summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/attotime.c312
-rw-r--r--src/emu/attotime.h212
-rw-r--r--src/emu/audio/generic.c162
-rw-r--r--src/emu/audio/generic.h61
-rw-r--r--src/emu/audit.c505
-rw-r--r--src/emu/audit.h90
-rw-r--r--src/emu/cheat.c11890
-rw-r--r--src/emu/cheat.h25
-rw-r--r--src/emu/clifront.c977
-rw-r--r--src/emu/clifront.h56
-rw-r--r--src/emu/config.c363
-rw-r--r--src/emu/config.h58
-rw-r--r--src/emu/cpu/adsp2100/2100dasm.c550
-rw-r--r--src/emu/cpu/adsp2100/2100ops.c2310
-rw-r--r--src/emu/cpu/adsp2100/adsp2100.c2612
-rw-r--r--src/emu/cpu/adsp2100/adsp2100.h164
-rw-r--r--src/emu/cpu/alph8201/8201dasm.c261
-rw-r--r--src/emu/cpu/alph8201/alph8201.c1013
-rw-r--r--src/emu/cpu/alph8201/alph8201.h72
-rw-r--r--src/emu/cpu/apexc/apexc.c922
-rw-r--r--src/emu/cpu/apexc/apexc.h38
-rw-r--r--src/emu/cpu/apexc/apexcdsm.c171
-rw-r--r--src/emu/cpu/arm/arm.c1599
-rw-r--r--src/emu/cpu/arm/arm.h32
-rw-r--r--src/emu/cpu/arm/armdasm.c393
-rw-r--r--src/emu/cpu/arm7/arm7.c464
-rw-r--r--src/emu/cpu/arm7/arm7.h41
-rw-r--r--src/emu/cpu/arm7/arm7core.c1681
-rw-r--r--src/emu/cpu/arm7/arm7core.h412
-rw-r--r--src/emu/cpu/arm7/arm7dasm.c1233
-rw-r--r--src/emu/cpu/arm7/arm7exec.c1334
-rw-r--r--src/emu/cpu/asap/asap.c1858
-rw-r--r--src/emu/cpu/asap/asap.h42
-rw-r--r--src/emu/cpu/asap/asapdasm.c148
-rw-r--r--src/emu/cpu/ccpu/ccpu.c809
-rw-r--r--src/emu/cpu/ccpu/ccpu.h57
-rw-r--r--src/emu/cpu/ccpu/ccpudasm.c327
-rw-r--r--src/emu/cpu/cdp1802/1802dasm.c173
-rw-r--r--src/emu/cpu/cdp1802/cdp1802.c1049
-rw-r--r--src/emu/cpu/cdp1802/cdp1802.h100
-rw-r--r--src/emu/cpu/cop400/410ops.c450
-rw-r--r--src/emu/cpu/cop400/420ops.c93
-rw-r--r--src/emu/cpu/cop400/cop400.h46
-rw-r--r--src/emu/cpu/cop400/cop410.c392
-rw-r--r--src/emu/cpu/cop400/cop410ds.c336
-rw-r--r--src/emu/cpu/cop400/cop420.c407
-rw-r--r--src/emu/cpu/cop400/cop420ds.c384
-rw-r--r--src/emu/cpu/cp1610/1610dasm.c1488
-rw-r--r--src/emu/cpu/cp1610/cp1610.c3525
-rw-r--r--src/emu/cpu/cp1610/cp1610.h49
-rw-r--r--src/emu/cpu/cpu.mak1689
-rw-r--r--src/emu/cpu/drcfe.c520
-rw-r--r--src/emu/cpu/drcfe.h188
-rw-r--r--src/emu/cpu/dsp32/dsp32.c952
-rw-r--r--src/emu/cpu/dsp32/dsp32.h84
-rw-r--r--src/emu/cpu/dsp32/dsp32dis.c693
-rw-r--r--src/emu/cpu/dsp32/dsp32ops.c2898
-rw-r--r--src/emu/cpu/dsp56k/dsp56dsm.c2210
-rw-r--r--src/emu/cpu/dsp56k/dsp56k.c1336
-rw-r--r--src/emu/cpu/dsp56k/dsp56k.h82
-rw-r--r--src/emu/cpu/dsp56k/dsp56ops.c2599
-rw-r--r--src/emu/cpu/e132xs/32xsdasm.c2135
-rw-r--r--src/emu/cpu/e132xs/e132xs.c5606
-rw-r--r--src/emu/cpu/e132xs/e132xs.h173
-rw-r--r--src/emu/cpu/f8/f3853.c152
-rw-r--r--src/emu/cpu/f8/f3853.h24
-rw-r--r--src/emu/cpu/f8/f8.c2223
-rw-r--r--src/emu/cpu/f8/f8.h55
-rw-r--r--src/emu/cpu/f8/f8dasm.c510
-rw-r--r--src/emu/cpu/g65816/g65816.c484
-rw-r--r--src/emu/cpu/g65816/g65816.h106
-rw-r--r--src/emu/cpu/g65816/g65816cm.h310
-rw-r--r--src/emu/cpu/g65816/g65816ds.c350
-rw-r--r--src/emu/cpu/g65816/g65816ds.h23
-rw-r--r--src/emu/cpu/g65816/g65816o0.c3
-rw-r--r--src/emu/cpu/g65816/g65816o1.c3
-rw-r--r--src/emu/cpu/g65816/g65816o2.c3
-rw-r--r--src/emu/cpu/g65816/g65816o3.c3
-rw-r--r--src/emu/cpu/g65816/g65816o4.c3
-rw-r--r--src/emu/cpu/g65816/g65816op.h2452
-rw-r--r--src/emu/cpu/h6280/6280dasm.c250
-rw-r--r--src/emu/cpu/h6280/h6280.c562
-rw-r--r--src/emu/cpu/h6280/h6280.h54
-rw-r--r--src/emu/cpu/h6280/h6280ops.h1379
-rw-r--r--src/emu/cpu/h6280/tblh6280.c344
-rw-r--r--src/emu/cpu/h83002/h83002.c3863
-rw-r--r--src/emu/cpu/h83002/h83002.h78
-rw-r--r--src/emu/cpu/h83002/h8disasm.c1230
-rw-r--r--src/emu/cpu/h83002/h8periph.c506
-rw-r--r--src/emu/cpu/h83002/h8priv.h44
-rw-r--r--src/emu/cpu/hd6309/6309dasm.c940
-rw-r--r--src/emu/cpu/hd6309/6309ops.c5599
-rw-r--r--src/emu/cpu/hd6309/6309tbl.c814
-rw-r--r--src/emu/cpu/hd6309/hd6309.c1340
-rw-r--r--src/emu/cpu/hd6309/hd6309.h52
-rw-r--r--src/emu/cpu/i386/cycles.h666
-rw-r--r--src/emu/cpu/i386/i386.c1421
-rw-r--r--src/emu/cpu/i386/i386.h898
-rw-r--r--src/emu/cpu/i386/i386dasm.c2125
-rw-r--r--src/emu/cpu/i386/i386intf.h11
-rw-r--r--src/emu/cpu/i386/i386op16.c3156
-rw-r--r--src/emu/cpu/i386/i386op32.c2974
-rw-r--r--src/emu/cpu/i386/i386ops.c2306
-rw-r--r--src/emu/cpu/i386/i386ops.h369
-rw-r--r--src/emu/cpu/i386/i486ops.c368
-rw-r--r--src/emu/cpu/i386/pentops.c53
-rw-r--r--src/emu/cpu/i386/x87ops.c352
-rw-r--r--src/emu/cpu/i8039/8039dasm.c302
-rw-r--r--src/emu/cpu/i8039/i8039.c949
-rw-r--r--src/emu/cpu/i8039/i8039.h175
-rw-r--r--src/emu/cpu/i8051/8051dasm.c1034
-rw-r--r--src/emu/cpu/i8051/i8051.c2583
-rw-r--r--src/emu/cpu/i8051/i8051.h157
-rw-r--r--src/emu/cpu/i8051/i8051ops.c960
-rw-r--r--src/emu/cpu/i8085/8085dasm.c581
-rw-r--r--src/emu/cpu/i8085/i8085.c1759
-rw-r--r--src/emu/cpu/i8085/i8085.h57
-rw-r--r--src/emu/cpu/i8085/i8085cpu.h181
-rw-r--r--src/emu/cpu/i8085/i8085daa.h2050
-rw-r--r--src/emu/cpu/i86/ea.h58
-rw-r--r--src/emu/cpu/i86/host.h12
-rw-r--r--src/emu/cpu/i86/i186intf.h10
-rw-r--r--src/emu/cpu/i86/i188intf.h9
-rw-r--r--src/emu/cpu/i86/i286.c510
-rw-r--r--src/emu/cpu/i86/i286.h36
-rw-r--r--src/emu/cpu/i86/i286intf.h46
-rw-r--r--src/emu/cpu/i86/i86.c561
-rw-r--r--src/emu/cpu/i86/i86.h127
-rw-r--r--src/emu/cpu/i86/i86.txt111
-rw-r--r--src/emu/cpu/i86/i86intf.h30
-rw-r--r--src/emu/cpu/i86/i86mem.c110
-rw-r--r--src/emu/cpu/i86/i86mem.h14
-rw-r--r--src/emu/cpu/i86/i86time.c312
-rw-r--r--src/emu/cpu/i86/i88intf.h9
-rw-r--r--src/emu/cpu/i86/instr186.c165
-rw-r--r--src/emu/cpu/i86/instr186.h27
-rw-r--r--src/emu/cpu/i86/instr286.c308
-rw-r--r--src/emu/cpu/i86/instr286.h13
-rw-r--r--src/emu/cpu/i86/instr86.c3137
-rw-r--r--src/emu/cpu/i86/instr86.h237
-rw-r--r--src/emu/cpu/i86/instrv30.c1311
-rw-r--r--src/emu/cpu/i86/instrv30.h7
-rw-r--r--src/emu/cpu/i86/modrm.h118
-rw-r--r--src/emu/cpu/i86/table186.h525
-rw-r--r--src/emu/cpu/i86/table286.h531
-rw-r--r--src/emu/cpu/i86/table86.h525
-rw-r--r--src/emu/cpu/i86/tablev30.h528
-rw-r--r--src/emu/cpu/i86/v20intf.h11
-rw-r--r--src/emu/cpu/i86/v30.h23
-rw-r--r--src/emu/cpu/i86/v30intf.h9
-rw-r--r--src/emu/cpu/i86/v33intf.h10
-rw-r--r--src/emu/cpu/i8x41/8x41dasm.c523
-rw-r--r--src/emu/cpu/i8x41/i8x41.c2316
-rw-r--r--src/emu/cpu/i8x41/i8x41.h88
-rw-r--r--src/emu/cpu/i960/i960.c2225
-rw-r--r--src/emu/cpu/i960/i960.h64
-rw-r--r--src/emu/cpu/i960/i960dis.c291
-rw-r--r--src/emu/cpu/i960/i960dis.h15
-rw-r--r--src/emu/cpu/jaguar/jagdasm.c182
-rw-r--r--src/emu/cpu/jaguar/jaguar.c1761
-rw-r--r--src/emu/cpu/jaguar/jaguar.h107
-rw-r--r--src/emu/cpu/konami/knmidasm.c1874
-rw-r--r--src/emu/cpu/konami/konami.c651
-rw-r--r--src/emu/cpu/konami/konami.h58
-rw-r--r--src/emu/cpu/konami/konamops.c4361
-rw-r--r--src/emu/cpu/konami/konamtbl.c491
-rw-r--r--src/emu/cpu/lh5801/5801dasm.c729
-rw-r--r--src/emu/cpu/lh5801/5801tbl.c691
-rw-r--r--src/emu/cpu/lh5801/lh5801.c281
-rw-r--r--src/emu/cpu/lh5801/lh5801.h76
-rw-r--r--src/emu/cpu/m37710/m37710.c1284
-rw-r--r--src/emu/cpu/m37710/m37710.h123
-rw-r--r--src/emu/cpu/m37710/m37710cm.h318
-rw-r--r--src/emu/cpu/m37710/m37710o0.c3
-rw-r--r--src/emu/cpu/m37710/m37710o1.c3
-rw-r--r--src/emu/cpu/m37710/m37710o2.c3
-rw-r--r--src/emu/cpu/m37710/m37710o3.c3
-rw-r--r--src/emu/cpu/m37710/m37710op.h2959
-rw-r--r--src/emu/cpu/m37710/m7700ds.c614
-rw-r--r--src/emu/cpu/m37710/m7700ds.h19
-rw-r--r--src/emu/cpu/m6502/6502dasm.c788
-rw-r--r--src/emu/cpu/m6502/ill02.h278
-rw-r--r--src/emu/cpu/m6502/m4510.c540
-rw-r--r--src/emu/cpu/m6502/m4510.h48
-rw-r--r--src/emu/cpu/m6502/m6502.c1017
-rw-r--r--src/emu/cpu/m6502/m6502.h259
-rw-r--r--src/emu/cpu/m6502/m6502.txt163
-rw-r--r--src/emu/cpu/m6502/m6509.c413
-rw-r--r--src/emu/cpu/m6502/m6509.h43
-rw-r--r--src/emu/cpu/m6502/m65ce02.c389
-rw-r--r--src/emu/cpu/m6502/m65ce02.h57
-rw-r--r--src/emu/cpu/m6502/minc4510.h72
-rw-r--r--src/emu/cpu/m6502/mincce02.h71
-rw-r--r--src/emu/cpu/m6502/ops02.h803
-rw-r--r--src/emu/cpu/m6502/ops09.h217
-rw-r--r--src/emu/cpu/m6502/ops4510.h77
-rw-r--r--src/emu/cpu/m6502/opsc02.h353
-rw-r--r--src/emu/cpu/m6502/opsce02.h988
-rw-r--r--src/emu/cpu/m6502/opsn2a03.h40
-rw-r--r--src/emu/cpu/m6502/t6502.c360
-rw-r--r--src/emu/cpu/m6502/t6509.c352
-rw-r--r--src/emu/cpu/m6502/t6510.c27
-rw-r--r--src/emu/cpu/m6502/t65c02.c410
-rw-r--r--src/emu/cpu/m6502/t65ce02.c399
-rw-r--r--src/emu/cpu/m6502/t65sc02.c80
-rw-r--r--src/emu/cpu/m6502/tdeco16.c429
-rw-r--r--src/emu/cpu/m6502/tn2a03.c97
-rw-r--r--src/emu/cpu/m6800/6800dasm.c274
-rw-r--r--src/emu/cpu/m6800/6800ops.c2140
-rw-r--r--src/emu/cpu/m6800/6800tbl.c398
-rw-r--r--src/emu/cpu/m6800/m6800.c2850
-rw-r--r--src/emu/cpu/m6800/m6800.h223
-rw-r--r--src/emu/cpu/m68000/m68000.h162
-rw-r--r--src/emu/cpu/m68000/m68k.h379
-rw-r--r--src/emu/cpu/m68000/m68k_in.c10685
-rw-r--r--src/emu/cpu/m68000/m68kconf.h201
-rw-r--r--src/emu/cpu/m68000/m68kcpu.c1025
-rw-r--r--src/emu/cpu/m68000/m68kcpu.h2037
-rw-r--r--src/emu/cpu/m68000/m68kdasm.c3742
-rw-r--r--src/emu/cpu/m68000/m68kfpu.c828
-rw-r--r--src/emu/cpu/m68000/m68kmake.c1433
-rw-r--r--src/emu/cpu/m68000/m68kmame.c1291
-rw-r--r--src/emu/cpu/m68000/m68kmame.h182
-rw-r--r--src/emu/cpu/m6805/6805dasm.c211
-rw-r--r--src/emu/cpu/m6805/6805ops.c1822
-rw-r--r--src/emu/cpu/m6805/m6805.c1062
-rw-r--r--src/emu/cpu/m6805/m6805.h95
-rw-r--r--src/emu/cpu/m6809/6809dasm.c612
-rw-r--r--src/emu/cpu/m6809/6809ops.c2997
-rw-r--r--src/emu/cpu/m6809/6809tbl.c316
-rw-r--r--src/emu/cpu/m6809/m6809.c1232
-rw-r--r--src/emu/cpu/m6809/m6809.h50
-rw-r--r--src/emu/cpu/mb86233/mb86233.c1690
-rw-r--r--src/emu/cpu/mb86233/mb86233.h52
-rw-r--r--src/emu/cpu/mb86233/mb86233d.c774
-rw-r--r--src/emu/cpu/mb88xx/mb88dasm.c221
-rw-r--r--src/emu/cpu/mb88xx/mb88xx.c955
-rw-r--r--src/emu/cpu/mb88xx/mb88xx.h78
-rw-r--r--src/emu/cpu/mc68hc11/hc11dasm.c1297
-rw-r--r--src/emu/cpu/mc68hc11/hc11ops.c2201
-rw-r--r--src/emu/cpu/mc68hc11/hc11ops.h189
-rw-r--r--src/emu/cpu/mc68hc11/mc68hc11.c494
-rw-r--r--src/emu/cpu/mc68hc11/mc68hc11.h32
-rw-r--r--src/emu/cpu/minx/minx.c325
-rw-r--r--src/emu/cpu/minx/minx.h18
-rw-r--r--src/emu/cpu/minx/minxd.c465
-rw-r--r--src/emu/cpu/minx/minxfunc.h272
-rw-r--r--src/emu/cpu/minx/minxopce.h331
-rw-r--r--src/emu/cpu/minx/minxopcf.h330
-rw-r--r--src/emu/cpu/minx/minxops.h330
-rw-r--r--src/emu/cpu/mips/dismips.c326
-rw-r--r--src/emu/cpu/mips/dismips.mak2
-rw-r--r--src/emu/cpu/mips/mdrc64.c5731
-rw-r--r--src/emu/cpu/mips/mdrcold.c4883
-rw-r--r--src/emu/cpu/mips/mips3.c2478
-rw-r--r--src/emu/cpu/mips/mips3.h199
-rw-r--r--src/emu/cpu/mips/mips3com.c979
-rw-r--r--src/emu/cpu/mips/mips3com.h257
-rw-r--r--src/emu/cpu/mips/mips3drc.c1297
-rw-r--r--src/emu/cpu/mips/mips3dsm.c511
-rw-r--r--src/emu/cpu/mips/mips3fe.c721
-rw-r--r--src/emu/cpu/mips/mips3fe.h50
-rw-r--r--src/emu/cpu/mips/mipsdasm.c620
-rw-r--r--src/emu/cpu/mips/psx.c3645
-rw-r--r--src/emu/cpu/mips/psx.h206
-rw-r--r--src/emu/cpu/mips/r3000.c1379
-rw-r--r--src/emu/cpu/mips/r3000.h65
-rw-r--r--src/emu/cpu/mips/r3kdasm.c295
-rw-r--r--src/emu/cpu/nec/nec.c1533
-rw-r--r--src/emu/cpu/nec/nec.h370
-rw-r--r--src/emu/cpu/nec/necdasm.c1522
-rw-r--r--src/emu/cpu/nec/necea.h60
-rw-r--r--src/emu/cpu/nec/nechost.h12
-rw-r--r--src/emu/cpu/nec/necinstr.h507
-rw-r--r--src/emu/cpu/nec/necintrf.h18
-rw-r--r--src/emu/cpu/nec/necmodrm.h104
-rw-r--r--src/emu/cpu/pdp1/pdp1.c1893
-rw-r--r--src/emu/cpu/pdp1/pdp1.h81
-rw-r--r--src/emu/cpu/pdp1/pdp1dasm.c293
-rw-r--r--src/emu/cpu/pdp1/tx0.c1318
-rw-r--r--src/emu/cpu/pdp1/tx0.h50
-rw-r--r--src/emu/cpu/pdp1/tx0dasm.c122
-rw-r--r--src/emu/cpu/pic16c5x/16c5xdsm.c267
-rw-r--r--src/emu/cpu/pic16c5x/dis16c5x.c134
-rw-r--r--src/emu/cpu/pic16c5x/pic16c5x.c1334
-rw-r--r--src/emu/cpu/pic16c5x/pic16c5x.h137
-rw-r--r--src/emu/cpu/powerpc/drc_ops.c3802
-rw-r--r--src/emu/cpu/powerpc/drc_ops.h143
-rw-r--r--src/emu/cpu/powerpc/ppc.c1938
-rw-r--r--src/emu/cpu/powerpc/ppc.h367
-rw-r--r--src/emu/cpu/powerpc/ppc403.c964
-rw-r--r--src/emu/cpu/powerpc/ppc602.c293
-rw-r--r--src/emu/cpu/powerpc/ppc603.c300
-rw-r--r--src/emu/cpu/powerpc/ppc_dasm.c1166
-rw-r--r--src/emu/cpu/powerpc/ppc_mem.c436
-rw-r--r--src/emu/cpu/powerpc/ppc_ops.c2848
-rw-r--r--src/emu/cpu/powerpc/ppc_ops.h143
-rw-r--r--src/emu/cpu/powerpc/ppcdrc.c2302
-rw-r--r--src/emu/cpu/rsp/rsp.c3008
-rw-r--r--src/emu/cpu/rsp/rsp.h65
-rw-r--r--src/emu/cpu/rsp/rsp_dasm.c345
-rw-r--r--src/emu/cpu/s2650/2650dasm.c852
-rw-r--r--src/emu/cpu/s2650/s2650.c1619
-rw-r--r--src/emu/cpu/s2650/s2650.h30
-rw-r--r--src/emu/cpu/s2650/s2650cpu.h35
-rw-r--r--src/emu/cpu/saturn/sat.h22
-rw-r--r--src/emu/cpu/saturn/satops.c1209
-rw-r--r--src/emu/cpu/saturn/sattable.c921
-rw-r--r--src/emu/cpu/saturn/saturn.c422
-rw-r--r--src/emu/cpu/saturn/saturn.h68
-rw-r--r--src/emu/cpu/saturn/saturnds.c1454
-rw-r--r--src/emu/cpu/sc61860/readpc.c195
-rw-r--r--src/emu/cpu/sc61860/sc.h34
-rw-r--r--src/emu/cpu/sc61860/sc61860.c255
-rw-r--r--src/emu/cpu/sc61860/sc61860.h58
-rw-r--r--src/emu/cpu/sc61860/scdasm.c220
-rw-r--r--src/emu/cpu/sc61860/scops.c734
-rw-r--r--src/emu/cpu/sc61860/sctable.c144
-rw-r--r--src/emu/cpu/se3208/se3208.c1952
-rw-r--r--src/emu/cpu/se3208/se3208.h14
-rw-r--r--src/emu/cpu/se3208/se3208dis.c1413
-rw-r--r--src/emu/cpu/sh2/sh2.c3181
-rw-r--r--src/emu/cpu/sh2/sh2.h83
-rw-r--r--src/emu/cpu/sh2/sh2dasm.c602
-rw-r--r--src/emu/cpu/sh4/sh4.c4637
-rw-r--r--src/emu/cpu/sh4/sh4.h93
-rw-r--r--src/emu/cpu/sh4/sh4dasm.c792
-rw-r--r--src/emu/cpu/sh4/sh4regs.h157
-rw-r--r--src/emu/cpu/sharc/compute.c1338
-rw-r--r--src/emu/cpu/sharc/sharc.c1229
-rw-r--r--src/emu/cpu/sharc/sharc.h35
-rw-r--r--src/emu/cpu/sharc/sharcdma.c204
-rw-r--r--src/emu/cpu/sharc/sharcdsm.c1183
-rw-r--r--src/emu/cpu/sharc/sharcdsm.h77
-rw-r--r--src/emu/cpu/sharc/sharcmem.c202
-rw-r--r--src/emu/cpu/sharc/sharcops.c2758
-rw-r--r--src/emu/cpu/sharc/sharcops.h138
-rw-r--r--src/emu/cpu/sm8500/sm8500.c533
-rw-r--r--src/emu/cpu/sm8500/sm8500.h59
-rw-r--r--src/emu/cpu/sm8500/sm8500d.c581
-rw-r--r--src/emu/cpu/sm8500/sm85ops.h1686
-rw-r--r--src/emu/cpu/spc700/spc700.c1828
-rw-r--r--src/emu/cpu/spc700/spc700.h154
-rw-r--r--src/emu/cpu/spc700/spc700ds.c437
-rw-r--r--src/emu/cpu/spc700/spc700ds.h27
-rw-r--r--src/emu/cpu/ssp1610/ssp1610.c869
-rw-r--r--src/emu/cpu/ssp1610/ssp1610.h16
-rw-r--r--src/emu/cpu/ssp1610/ssp1610d.c532
-rw-r--r--src/emu/cpu/t11/t11.c540
-rw-r--r--src/emu/cpu/t11/t11.h50
-rw-r--r--src/emu/cpu/t11/t11dasm.c517
-rw-r--r--src/emu/cpu/t11/t11ops.c1400
-rw-r--r--src/emu/cpu/t11/t11table.c2409
-rw-r--r--src/emu/cpu/tlcs90/tlcs90.c2875
-rw-r--r--src/emu/cpu/tlcs90/tlcs90.h26
-rw-r--r--src/emu/cpu/tms32010/32010dsm.c349
-rw-r--r--src/emu/cpu/tms32010/dis32010.c136
-rw-r--r--src/emu/cpu/tms32010/tms32010.c982
-rw-r--r--src/emu/cpu/tms32010/tms32010.h140
-rw-r--r--src/emu/cpu/tms32025/32025dsm.c522
-rw-r--r--src/emu/cpu/tms32025/dis32025.c135
-rw-r--r--src/emu/cpu/tms32025/tms32025.c2477
-rw-r--r--src/emu/cpu/tms32025/tms32025.h78
-rw-r--r--src/emu/cpu/tms32031/32031ops.c6627
-rw-r--r--src/emu/cpu/tms32031/dis32031.c733
-rw-r--r--src/emu/cpu/tms32031/tms32031.c829
-rw-r--r--src/emu/cpu/tms32031/tms32031.h71
-rw-r--r--src/emu/cpu/tms32051/32051ops.c1961
-rw-r--r--src/emu/cpu/tms32051/32051ops.h251
-rw-r--r--src/emu/cpu/tms32051/dis32051.c643
-rw-r--r--src/emu/cpu/tms32051/tms32051.c723
-rw-r--r--src/emu/cpu/tms32051/tms32051.h12
-rw-r--r--src/emu/cpu/tms34010/34010dsm.c1760
-rw-r--r--src/emu/cpu/tms34010/34010fld.c683
-rw-r--r--src/emu/cpu/tms34010/34010gfx.c2032
-rw-r--r--src/emu/cpu/tms34010/34010ops.c2467
-rw-r--r--src/emu/cpu/tms34010/34010ops.h279
-rw-r--r--src/emu/cpu/tms34010/34010tbl.c1167
-rw-r--r--src/emu/cpu/tms34010/dis34010.c113
-rw-r--r--src/emu/cpu/tms34010/makefile6
-rw-r--r--src/emu/cpu/tms34010/tms34010.c1917
-rw-r--r--src/emu/cpu/tms34010/tms34010.h135
-rw-r--r--src/emu/cpu/tms7000/7000dasm.c445
-rw-r--r--src/emu/cpu/tms7000/tms7000.c744
-rw-r--r--src/emu/cpu/tms7000/tms7000.h55
-rw-r--r--src/emu/cpu/tms7000/tms70op.c3958
-rw-r--r--src/emu/cpu/tms7000/tms70tb.c124
-rw-r--r--src/emu/cpu/tms9900/9900dasm.c801
-rw-r--r--src/emu/cpu/tms9900/99xxcore.h4868
-rw-r--r--src/emu/cpu/tms9900/99xxstat.h483
-rw-r--r--src/emu/cpu/tms9900/ti990_10.c9
-rw-r--r--src/emu/cpu/tms9900/tms9900.c9
-rw-r--r--src/emu/cpu/tms9900/tms9900.h223
-rw-r--r--src/emu/cpu/tms9900/tms9980a.c9
-rw-r--r--src/emu/cpu/tms9900/tms9995.c9
-rw-r--r--src/emu/cpu/upd7810/7810dasm.c4059
-rw-r--r--src/emu/cpu/upd7810/7810ops.c9341
-rw-r--r--src/emu/cpu/upd7810/7810tbl.c3513
-rw-r--r--src/emu/cpu/upd7810/upd7810.c2019
-rw-r--r--src/emu/cpu/upd7810/upd7810.h157
-rw-r--r--src/emu/cpu/v30mz/necea.h60
-rw-r--r--src/emu/cpu/v30mz/nechost.h12
-rw-r--r--src/emu/cpu/v30mz/necinstr.h507
-rw-r--r--src/emu/cpu/v30mz/necintrf.h16
-rw-r--r--src/emu/cpu/v30mz/necmodrm.h104
-rw-r--r--src/emu/cpu/v30mz/v30mz.c1158
-rw-r--r--src/emu/cpu/v30mz/v30mz.h359
-rw-r--r--src/emu/cpu/v60/am.c102
-rw-r--r--src/emu/cpu/v60/am1.c1391
-rw-r--r--src/emu/cpu/v60/am2.c1256
-rw-r--r--src/emu/cpu/v60/am3.c887
-rw-r--r--src/emu/cpu/v60/op12.c2399
-rw-r--r--src/emu/cpu/v60/op2.c359
-rw-r--r--src/emu/cpu/v60/op3.c645
-rw-r--r--src/emu/cpu/v60/op4.c354
-rw-r--r--src/emu/cpu/v60/op5.c96
-rw-r--r--src/emu/cpu/v60/op6.c254
-rw-r--r--src/emu/cpu/v60/op7a.c1230
-rw-r--r--src/emu/cpu/v60/optable.c259
-rw-r--r--src/emu/cpu/v60/v60.c743
-rw-r--r--src/emu/cpu/v60/v60.h90
-rw-r--r--src/emu/cpu/v60/v60d.c1477
-rw-r--r--src/emu/cpu/v60/v60mem.c388
-rw-r--r--src/emu/cpu/v810/v810.c1240
-rw-r--r--src/emu/cpu/v810/v810.h128
-rw-r--r--src/emu/cpu/v810/v810dasm.c168
-rw-r--r--src/emu/cpu/x64drc.c629
-rw-r--r--src/emu/cpu/x64drc.h223
-rw-r--r--src/emu/cpu/x86drc.c767
-rw-r--r--src/emu/cpu/x86drc.h194
-rw-r--r--src/emu/cpu/x86emit.h2888
-rw-r--r--src/emu/cpu/x86log.c316
-rw-r--r--src/emu/cpu/x86log.h53
-rw-r--r--src/emu/cpu/z180/z180.c2643
-rw-r--r--src/emu/cpu/z180/z180.h135
-rw-r--r--src/emu/cpu/z180/z180cb.c293
-rw-r--r--src/emu/cpu/z180/z180daa.h2051
-rw-r--r--src/emu/cpu/z180/z180dasm.c555
-rw-r--r--src/emu/cpu/z180/z180dd.c296
-rw-r--r--src/emu/cpu/z180/z180ed.c297
-rw-r--r--src/emu/cpu/z180/z180fd.c291
-rw-r--r--src/emu/cpu/z180/z180op.c520
-rw-r--r--src/emu/cpu/z180/z180ops.h1197
-rw-r--r--src/emu/cpu/z180/z180tbl.h362
-rw-r--r--src/emu/cpu/z180/z180xy.c292
-rw-r--r--src/emu/cpu/z80/z80.c3818
-rw-r--r--src/emu/cpu/z80/z80.h38
-rw-r--r--src/emu/cpu/z80/z80daisy.c75
-rw-r--r--src/emu/cpu/z80/z80daisy.h36
-rw-r--r--src/emu/cpu/z80/z80dasm.c543
-rw-r--r--src/emu/cpu/z8000/8000dasm.c318
-rw-r--r--src/emu/cpu/z8000/makedab.c87
-rw-r--r--src/emu/cpu/z8000/z8000.c756
-rw-r--r--src/emu/cpu/z8000/z8000.h29
-rw-r--r--src/emu/cpu/z8000/z8000cpu.h196
-rw-r--r--src/emu/cpu/z8000/z8000dab.h275
-rw-r--r--src/emu/cpu/z8000/z8000ops.c6503
-rw-r--r--src/emu/cpu/z8000/z8000tbl.c596
-rw-r--r--src/emu/cpu/z80gb/opc_cb.h1440
-rw-r--r--src/emu/cpu/z80gb/opc_main.h1552
-rw-r--r--src/emu/cpu/z80gb/z80gb.c485
-rw-r--r--src/emu/cpu/z80gb/z80gb.h34
-rw-r--r--src/emu/cpu/z80gb/z80gbd.c288
-rw-r--r--src/emu/cpuexec.c1511
-rw-r--r--src/emu/cpuexec.h434
-rw-r--r--src/emu/cpuint.c390
-rw-r--r--src/emu/cpuint.h56
-rw-r--r--src/emu/cpuintrf.c1653
-rw-r--r--src/emu/cpuintrf.h516
-rw-r--r--src/emu/debug/debugcmd.c2200
-rw-r--r--src/emu/debug/debugcmd.h26
-rw-r--r--src/emu/debug/debugcmt.c570
-rw-r--r--src/emu/debug/debugcmt.h40
-rw-r--r--src/emu/debug/debugcon.c533
-rw-r--r--src/emu/debug/debugcon.h97
-rw-r--r--src/emu/debug/debugcpu.c2195
-rw-r--r--src/emu/debug/debugcpu.h231
-rw-r--r--src/emu/debug/debughlp.c1075
-rw-r--r--src/emu/debug/debughlp.h23
-rw-r--r--src/emu/debug/debugvw.c3187
-rw-r--r--src/emu/debug/debugvw.h228
-rw-r--r--src/emu/debug/express.c1953
-rw-r--r--src/emu/debug/express.h160
-rw-r--r--src/emu/debug/textbuf.c326
-rw-r--r--src/emu/debug/textbuf.h58
-rw-r--r--src/emu/debugger.h71
-rw-r--r--src/emu/drawgfx.c5859
-rw-r--r--src/emu/drawgfx.h331
-rw-r--r--src/emu/driver.c520
-rw-r--r--src/emu/driver.h587
-rw-r--r--src/emu/drivers/empty.c81
-rw-r--r--src/emu/eigccppc.h434
-rw-r--r--src/emu/eigccx86.h610
-rw-r--r--src/emu/eminline.h433
-rw-r--r--src/emu/emu.mak237
-rw-r--r--src/emu/emuopts.c226
-rw-r--r--src/emu/emuopts.h158
-rw-r--r--src/emu/emupal.c796
-rw-r--r--src/emu/emupal.h250
-rw-r--r--src/emu/fileio.c839
-rw-r--r--src/emu/fileio.h170
-rw-r--r--src/emu/hash.c713
-rw-r--r--src/emu/hash.h79
-rw-r--r--src/emu/info.c1009
-rw-r--r--src/emu/info.h22
-rw-r--r--src/emu/inptport.c3610
-rw-r--r--src/emu/inptport.h903
-rw-r--r--src/emu/input.c1603
-rw-r--r--src/emu/input.h555
-rw-r--r--src/emu/inputseq.c630
-rw-r--r--src/emu/inputseq.h177
-rw-r--r--src/emu/layout/dualhovu.lay72
-rw-r--r--src/emu/layout/dualhsxs.lay72
-rw-r--r--src/emu/layout/dualhuov.lay72
-rw-r--r--src/emu/layout/ho20ffff.lay18
-rw-r--r--src/emu/layout/ho2eff2e.lay18
-rw-r--r--src/emu/layout/ho4f893d.lay21
-rw-r--r--src/emu/layout/ho88ffff.lay18
-rw-r--r--src/emu/layout/hoa0a0ff.lay18
-rw-r--r--src/emu/layout/hoffe457.lay18
-rw-r--r--src/emu/layout/hoffff20.lay18
-rw-r--r--src/emu/layout/horizont.lay24
-rw-r--r--src/emu/layout/snap.lay50
-rw-r--r--src/emu/layout/triphsxs.lay62
-rw-r--r--src/emu/layout/vertical.lay24
-rw-r--r--src/emu/layout/voffff20.lay18
-rw-r--r--src/emu/machine/53c810.c896
-rw-r--r--src/emu/machine/53c810.h26
-rw-r--r--src/emu/machine/6522via.c1153
-rw-r--r--src/emu/machine/6522via.h195
-rw-r--r--src/emu/machine/6526cia.c782
-rw-r--r--src/emu/machine/6526cia.h58
-rw-r--r--src/emu/machine/6532riot.c373
-rw-r--r--src/emu/machine/6532riot.h87
-rw-r--r--src/emu/machine/6821pia.c1353
-rw-r--r--src/emu/machine/6821pia.h359
-rw-r--r--src/emu/machine/6840ptm.c703
-rw-r--r--src/emu/machine/6840ptm.h75
-rw-r--r--src/emu/machine/6850acia.c691
-rw-r--r--src/emu/machine/6850acia.h90
-rw-r--r--src/emu/machine/74123.c190
-rw-r--r--src/emu/machine/74123.h80
-rw-r--r--src/emu/machine/74148.c193
-rw-r--r--src/emu/machine/74148.h63
-rw-r--r--src/emu/machine/74153.c151
-rw-r--r--src/emu/machine/74153.h58
-rw-r--r--src/emu/machine/74181.c165
-rw-r--r--src/emu/machine/74181.h40
-rw-r--r--src/emu/machine/7474.c173
-rw-r--r--src/emu/machine/7474.h63
-rw-r--r--src/emu/machine/8042kbdc.c622
-rw-r--r--src/emu/machine/8042kbdc.h40
-rw-r--r--src/emu/machine/8237dma.c450
-rw-r--r--src/emu/machine/8237dma.h61
-rw-r--r--src/emu/machine/8255ppi.c589
-rw-r--r--src/emu/machine/8255ppi.h89
-rw-r--r--src/emu/machine/adc083x.c465
-rw-r--r--src/emu/machine/adc083x.h38
-rw-r--r--src/emu/machine/adc1213x.c251
-rw-r--r--src/emu/machine/adc1213x.h18
-rw-r--r--src/emu/machine/am53cf96.c279
-rw-r--r--src/emu/machine/am53cf96.h24
-rw-r--r--src/emu/machine/at28c16.c253
-rw-r--r--src/emu/machine/at28c16.h53
-rw-r--r--src/emu/machine/cr589.c152
-rw-r--r--src/emu/machine/cr589.h3
-rw-r--r--src/emu/machine/ds1302.c140
-rw-r--r--src/emu/machine/ds1302.h5
-rw-r--r--src/emu/machine/ds2401.c272
-rw-r--r--src/emu/machine/ds2401.h18
-rw-r--r--src/emu/machine/ds2404.c320
-rw-r--r--src/emu/machine/ds2404.h18
-rw-r--r--src/emu/machine/eeprom.c378
-rw-r--r--src/emu/machine/eeprom.h40
-rw-r--r--src/emu/machine/generic.c820
-rw-r--r--src/emu/machine/generic.h292
-rw-r--r--src/emu/machine/i2cmem.c438
-rw-r--r--src/emu/machine/i2cmem.h27
-rw-r--r--src/emu/machine/idectrl.c1793
-rw-r--r--src/emu/machine/idectrl.h37
-rw-r--r--src/emu/machine/intelfsh.c493
-rw-r--r--src/emu/machine/intelfsh.h23
-rw-r--r--src/emu/machine/laserdsc.c3361
-rw-r--r--src/emu/machine/laserdsc.h86
-rw-r--r--src/emu/machine/mb3773.c39
-rw-r--r--src/emu/machine/mb3773.h12
-rw-r--r--src/emu/machine/mb87078.c169
-rw-r--r--src/emu/machine/mb87078.h103
-rw-r--r--src/emu/machine/mc146818.c392
-rw-r--r--src/emu/machine/mc146818.h55
-rw-r--r--src/emu/machine/msm6242.c139
-rw-r--r--src/emu/machine/msm6242.h10
-rw-r--r--src/emu/machine/pc16552d.c433
-rw-r--r--src/emu/machine/pc16552d.h12
-rw-r--r--src/emu/machine/pci.c197
-rw-r--r--src/emu/machine/pci.h30
-rw-r--r--src/emu/machine/pd4990a.c352
-rw-r--r--src/emu/machine/pd4990a.h26
-rw-r--r--src/emu/machine/pic8259.c397
-rw-r--r--src/emu/machine/pic8259.h34
-rw-r--r--src/emu/machine/pit8253.c1216
-rw-r--r--src/emu/machine/pit8253.h62
-rw-r--r--src/emu/machine/roc10937.c407
-rw-r--r--src/emu/machine/roc10937.h34
-rw-r--r--src/emu/machine/rp5h01.c207
-rw-r--r--src/emu/machine/rp5h01.h29
-rw-r--r--src/emu/machine/rtc65271.c654
-rw-r--r--src/emu/machine/rtc65271.h9
-rw-r--r--src/emu/machine/scsi.c119
-rw-r--r--src/emu/machine/scsi.h104
-rw-r--r--src/emu/machine/scsicd.c768
-rw-r--r--src/emu/machine/scsicd.h17
-rw-r--r--src/emu/machine/scsidev.c155
-rw-r--r--src/emu/machine/scsidev.h15
-rw-r--r--src/emu/machine/scsihd.c311
-rw-r--r--src/emu/machine/scsihd.h16
-rw-r--r--src/emu/machine/smc91c9x.c564
-rw-r--r--src/emu/machine/smc91c9x.h22
-rw-r--r--src/emu/machine/timekpr.c483
-rw-r--r--src/emu/machine/timekpr.h35
-rw-r--r--src/emu/machine/tmp68301.c179
-rw-r--r--src/emu/machine/tmp68301.h16
-rw-r--r--src/emu/machine/upd4701.c307
-rw-r--r--src/emu/machine/upd4701.h27
-rw-r--r--src/emu/machine/wd33c93.c872
-rw-r--r--src/emu/machine/wd33c93.h26
-rw-r--r--src/emu/machine/x76f041.c623
-rw-r--r--src/emu/machine/x76f041.h22
-rw-r--r--src/emu/machine/x76f100.c497
-rw-r--r--src/emu/machine/x76f100.h22
-rw-r--r--src/emu/machine/z80ctc.c483
-rw-r--r--src/emu/machine/z80ctc.h91
-rw-r--r--src/emu/machine/z80pio.c537
-rw-r--r--src/emu/machine/z80pio.h92
-rw-r--r--src/emu/machine/z80sio.c805
-rw-r--r--src/emu/machine/z80sio.h81
-rw-r--r--src/emu/mame.c1889
-rw-r--r--src/emu/mame.h400
-rw-r--r--src/emu/mamecore.c17
-rw-r--r--src/emu/mamecore.h350
-rw-r--r--src/emu/memconv.h1020
-rw-r--r--src/emu/memory.c3422
-rw-r--r--src/emu/memory.h1166
-rw-r--r--src/emu/output.c406
-rw-r--r--src/emu/output.h97
-rw-r--r--src/emu/profiler.c205
-rw-r--r--src/emu/profiler.h86
-rw-r--r--src/emu/render.c2948
-rw-r--r--src/emu/render.h478
-rw-r--r--src/emu/rendersw.c1942
-rw-r--r--src/emu/rendfont.c853
-rw-r--r--src/emu/rendfont.h33
-rw-r--r--src/emu/rendlay.c2126
-rw-r--r--src/emu/rendlay.h218
-rw-r--r--src/emu/rendutil.c772
-rw-r--r--src/emu/rendutil.h204
-rw-r--r--src/emu/restrack.c368
-rw-r--r--src/emu/restrack.h90
-rw-r--r--src/emu/romload.c1169
-rw-r--r--src/emu/romload.h300
-rw-r--r--src/emu/sndintrf.c967
-rw-r--r--src/emu/sndintrf.h285
-rw-r--r--src/emu/sound.c955
-rw-r--r--src/emu/sound.h89
-rw-r--r--src/emu/sound/2151intf.c236
-rw-r--r--src/emu/sound/2151intf.h37
-rw-r--r--src/emu/sound/2203intf.c348
-rw-r--r--src/emu/sound/2203intf.h67
-rw-r--r--src/emu/sound/2413intf.c186
-rw-r--r--src/emu/sound/2413intf.h26
-rw-r--r--src/emu/sound/2608intf.c314
-rw-r--r--src/emu/sound/2608intf.h38
-rw-r--r--src/emu/sound/2610intf.c520
-rw-r--r--src/emu/sound/2610intf.h50
-rw-r--r--src/emu/sound/2612intf.c415
-rw-r--r--src/emu/sound/2612intf.h64
-rw-r--r--src/emu/sound/262intf.c189
-rw-r--r--src/emu/sound/262intf.h27
-rw-r--r--src/emu/sound/3812intf.c565
-rw-r--r--src/emu/sound/3812intf.h56
-rw-r--r--src/emu/sound/5110intf.c243
-rw-r--r--src/emu/sound/5110intf.h23
-rw-r--r--src/emu/sound/5220intf.c262
-rw-r--r--src/emu/sound/5220intf.h31
-rw-r--r--src/emu/sound/astrocde.c355
-rw-r--r--src/emu/sound/astrocde.h8
-rw-r--r--src/emu/sound/ay8910.c899
-rw-r--r--src/emu/sound/ay8910.h90
-rw-r--r--src/emu/sound/beep.c197
-rw-r--r--src/emu/sound/beep.h16
-rw-r--r--src/emu/sound/bsmt2000.c529
-rw-r--r--src/emu/sound/bsmt2000.h23
-rw-r--r--src/emu/sound/c140.c520
-rw-r--r--src/emu/sound/c140.h24
-rw-r--r--src/emu/sound/c352.c643
-rw-r--r--src/emu/sound/c352.h13
-rw-r--r--src/emu/sound/c6280.c370
-rw-r--r--src/emu/sound/c6280.h8
-rw-r--r--src/emu/sound/cdda.c332
-rw-r--r--src/emu/sound/cdda.h17
-rw-r--r--src/emu/sound/cdp1869.c201
-rw-r--r--src/emu/sound/cdp1869.h41
-rw-r--r--src/emu/sound/cem3394.c593
-rw-r--r--src/emu/sound/cem3394.h45
-rw-r--r--src/emu/sound/custom.c90
-rw-r--r--src/emu/sound/custom.h15
-rw-r--r--src/emu/sound/dac.c187
-rw-r--r--src/emu/sound/dac.h16
-rw-r--r--src/emu/sound/disc_dev.c1372
-rw-r--r--src/emu/sound/disc_flt.c1220
-rw-r--r--src/emu/sound/disc_inp.c261
-rw-r--r--src/emu/sound/disc_mth.c1968
-rw-r--r--src/emu/sound/disc_wav.c1707
-rw-r--r--src/emu/sound/discrete.c751
-rw-r--r--src/emu/sound/discrete.h3930
-rw-r--r--src/emu/sound/dmadac.c272
-rw-r--r--src/emu/sound/dmadac.h16
-rw-r--r--src/emu/sound/es5503.c551
-rw-r--r--src/emu/sound/es5503.h15
-rw-r--r--src/emu/sound/es5506.c2205
-rw-r--r--src/emu/sound/es5506.h53
-rw-r--r--src/emu/sound/es8712.c479
-rw-r--r--src/emu/sound/es8712.h30
-rw-r--r--src/emu/sound/filter.c233
-rw-r--r--src/emu/sound/filter.h112
-rw-r--r--src/emu/sound/flt_rc.c147
-rw-r--r--src/emu/sound/flt_rc.h59
-rw-r--r--src/emu/sound/flt_vol.c80
-rw-r--r--src/emu/sound/flt_vol.h6
-rw-r--r--src/emu/sound/fm.c4744
-rw-r--r--src/emu/sound/fm.h211
-rw-r--r--src/emu/sound/fmopl.c2625
-rw-r--r--src/emu/sound/fmopl.h111
-rw-r--r--src/emu/sound/gaelco.c377
-rw-r--r--src/emu/sound/gaelco.h13
-rw-r--r--src/emu/sound/hc55516.c246
-rw-r--r--src/emu/sound/hc55516.h31
-rw-r--r--src/emu/sound/ics2115.c578
-rw-r--r--src/emu/sound/ics2115.h12
-rw-r--r--src/emu/sound/iremga20.c304
-rw-r--r--src/emu/sound/iremga20.h16
-rw-r--r--src/emu/sound/k005289.c285
-rw-r--r--src/emu/sound/k005289.h16
-rw-r--r--src/emu/sound/k007232.c509
-rw-r--r--src/emu/sound/k007232.h32
-rw-r--r--src/emu/sound/k051649.c255
-rw-r--r--src/emu/sound/k051649.h11
-rw-r--r--src/emu/sound/k053260.c487
-rw-r--r--src/emu/sound/k053260.h24
-rw-r--r--src/emu/sound/k054539.c741
-rw-r--r--src/emu/sound/k054539.h43
-rw-r--r--src/emu/sound/msm5205.c330
-rw-r--r--src/emu/sound/msm5205.h36
-rw-r--r--src/emu/sound/msm5232.c803
-rw-r--r--src/emu/sound/msm5232.h12
-rw-r--r--src/emu/sound/multipcm.c551
-rw-r--r--src/emu/sound/multipcm.h17
-rw-r--r--src/emu/sound/n63701x.c193
-rw-r--r--src/emu/sound/n63701x.h12
-rw-r--r--src/emu/sound/namco.c927
-rw-r--r--src/emu/sound/namco.h32
-rw-r--r--src/emu/sound/namco52.c228
-rw-r--r--src/emu/sound/namco52.h32
-rw-r--r--src/emu/sound/namcona.c1329
-rw-r--r--src/emu/sound/namcona.h10
-rw-r--r--src/emu/sound/nes_apu.c789
-rw-r--r--src/emu/sound/nes_apu.h46
-rw-r--r--src/emu/sound/nes_defs.h205
-rw-r--r--src/emu/sound/okim6295.c676
-rw-r--r--src/emu/sound/okim6295.h65
-rw-r--r--src/emu/sound/pokey.c1599
-rw-r--r--src/emu/sound/pokey.h105
-rw-r--r--src/emu/sound/pokey.txt319
-rw-r--r--src/emu/sound/psx.c695
-rw-r--r--src/emu/sound/psx.h27
-rw-r--r--src/emu/sound/qsound.c411
-rw-r--r--src/emu/sound/qsound.h21
-rw-r--r--src/emu/sound/rf5c400.c581
-rw-r--r--src/emu/sound/rf5c400.h13
-rw-r--r--src/emu/sound/rf5c68.c260
-rw-r--r--src/emu/sound/rf5c68.h15
-rw-r--r--src/emu/sound/s14001a.c548
-rw-r--r--src/emu/sound/s14001a.h16
-rw-r--r--src/emu/sound/saa1099.c519
-rw-r--r--src/emu/sound/saa1099.h18
-rw-r--r--src/emu/sound/samples.c612
-rw-r--r--src/emu/sound/samples.h50
-rw-r--r--src/emu/sound/scsp.c1567
-rw-r--r--src/emu/sound/scsp.h28
-rw-r--r--src/emu/sound/scspdsp.c319
-rw-r--r--src/emu/sound/scspdsp.h37
-rw-r--r--src/emu/sound/scsplfo.c157
-rw-r--r--src/emu/sound/segapcm.c160
-rw-r--r--src/emu/sound/segapcm.h24
-rw-r--r--src/emu/sound/sid.c364
-rw-r--r--src/emu/sound/sid.h74
-rw-r--r--src/emu/sound/sid6581.c144
-rw-r--r--src/emu/sound/sid6581.h32
-rw-r--r--src/emu/sound/side6581.h124
-rw-r--r--src/emu/sound/sidenvel.c590
-rw-r--r--src/emu/sound/sidenvel.h32
-rw-r--r--src/emu/sound/sidvoice.c819
-rw-r--r--src/emu/sound/sidvoice.h117
-rw-r--r--src/emu/sound/sidw6581.h1051
-rw-r--r--src/emu/sound/sidw8580.h1395
-rw-r--r--src/emu/sound/sn76477.c2512
-rw-r--r--src/emu/sound/sn76477.h124
-rw-r--r--src/emu/sound/sn76496.c456
-rw-r--r--src/emu/sound/sn76496.h10
-rw-r--r--src/emu/sound/sound.mak717
-rw-r--r--src/emu/sound/sp0250.c257
-rw-r--r--src/emu/sound/sp0250.h10
-rw-r--r--src/emu/sound/sp0256.c1383
-rw-r--r--src/emu/sound/sp0256.h37
-rw-r--r--src/emu/sound/speaker.c104
-rw-r--r--src/emu/sound/speaker.h29
-rw-r--r--src/emu/sound/st0016.c180
-rw-r--r--src/emu/sound/st0016.h14
-rw-r--r--src/emu/sound/tiaintf.c85
-rw-r--r--src/emu/sound/tiaintf.h8
-rw-r--r--src/emu/sound/tiasound.c596
-rw-r--r--src/emu/sound/tiasound.h44
-rw-r--r--src/emu/sound/tms3615.c125
-rw-r--r--src/emu/sound/tms3615.h9
-rw-r--r--src/emu/sound/tms36xx.c565
-rw-r--r--src/emu/sound/tms36xx.h25
-rw-r--r--src/emu/sound/tms5110.c731
-rw-r--r--src/emu/sound/tms5110.h32
-rw-r--r--src/emu/sound/tms5110r.c136
-rw-r--r--src/emu/sound/tms5220.c1140
-rw-r--r--src/emu/sound/tms5220.h32
-rw-r--r--src/emu/sound/tms5220.txt86
-rw-r--r--src/emu/sound/tms5220r.c107
-rw-r--r--src/emu/sound/upd7759.c801
-rw-r--r--src/emu/sound/upd7759.h31
-rw-r--r--src/emu/sound/vlm5030.c721
-rw-r--r--src/emu/sound/vlm5030.h25
-rw-r--r--src/emu/sound/votrax.c190
-rw-r--r--src/emu/sound/vrender0.c274
-rw-r--r--src/emu/sound/vrender0.h9
-rw-r--r--src/emu/sound/wave.c100
-rw-r--r--src/emu/sound/wave.h14
-rw-r--r--src/emu/sound/wavwrite.c207
-rw-r--r--src/emu/sound/wavwrite.h14
-rw-r--r--src/emu/sound/x1_010.c330
-rw-r--r--src/emu/sound/x1_010.h13
-rw-r--r--src/emu/sound/ym2151.c2505
-rw-r--r--src/emu/sound/ym2151.h86
-rw-r--r--src/emu/sound/ym2151.txt162
-rw-r--r--src/emu/sound/ym2413.c2122
-rw-r--r--src/emu/sound/ym2413.h42
-rw-r--r--src/emu/sound/ymdeltat.c652
-rw-r--r--src/emu/sound/ymdeltat.h82
-rw-r--r--src/emu/sound/ymf262.c2719
-rw-r--r--src/emu/sound/ymf262.h46
-rw-r--r--src/emu/sound/ymf271.c1833
-rw-r--r--src/emu/sound/ymf271.h17
-rw-r--r--src/emu/sound/ymf278b.c835
-rw-r--r--src/emu/sound/ymf278b.h29
-rw-r--r--src/emu/sound/ymz280b.c1125
-rw-r--r--src/emu/sound/ymz280b.h43
-rw-r--r--src/emu/state.c966
-rw-r--r--src/emu/state.h119
-rw-r--r--src/emu/streams.c881
-rw-r--r--src/emu/streams.h50
-rw-r--r--src/emu/tilemap.c2402
-rw-r--r--src/emu/tilemap.h635
-rw-r--r--src/emu/timer.c810
-rw-r--r--src/emu/timer.h185
-rw-r--r--src/emu/ui.c1961
-rw-r--r--src/emu/ui.h141
-rw-r--r--src/emu/uigfx.c1085
-rw-r--r--src/emu/uigfx.h31
-rw-r--r--src/emu/uimenu.c2612
-rw-r--r--src/emu/uimenu.h84
-rw-r--r--src/emu/uismall.pngbin0 -> 1488 bytes
-rw-r--r--src/emu/uitext.c356
-rw-r--r--src/emu/uitext.h233
-rw-r--r--src/emu/validity.c1449
-rw-r--r--src/emu/video.c2211
-rw-r--r--src/emu/video.h169
-rw-r--r--src/emu/video/cdp1869.c569
-rw-r--r--src/emu/video/cdp1869.h128
-rw-r--r--src/emu/video/crtc6845.c444
-rw-r--r--src/emu/video/crtc6845.h62
-rw-r--r--src/emu/video/generic.c1102
-rw-r--r--src/emu/video/generic.h229
-rw-r--r--src/emu/video/poly.c1410
-rw-r--r--src/emu/video/poly.h158
-rw-r--r--src/emu/video/resnet.c738
-rw-r--r--src/emu/video/resnet.h201
-rw-r--r--src/emu/video/rgbgen.h396
-rw-r--r--src/emu/video/rgbsse.h485
-rw-r--r--src/emu/video/rgbutil.h25
-rw-r--r--src/emu/video/rgbvmx.h545
-rw-r--r--src/emu/video/s2636.c300
-rw-r--r--src/emu/video/s2636.h18
-rw-r--r--src/emu/video/tlc34076.c262
-rw-r--r--src/emu/video/tlc34076.h19
-rw-r--r--src/emu/video/tms34061.c541
-rw-r--r--src/emu/video/tms34061.h70
-rw-r--r--src/emu/video/tms9928a.c809
-rw-r--r--src/emu/video/tms9928a.h88
-rw-r--r--src/emu/video/v9938.c2428
-rw-r--r--src/emu/video/v9938.h32
-rw-r--r--src/emu/video/v9938mod.c736
-rw-r--r--src/emu/video/vector.c315
-rw-r--r--src/emu/video/vector.h30
-rw-r--r--src/emu/video/vooddefs.h3632
-rw-r--r--src/emu/video/voodoo.c5742
-rw-r--r--src/emu/video/voodoo.h50
911 files changed, 609749 insertions, 0 deletions
diff --git a/src/emu/attotime.c b/src/emu/attotime.c
new file mode 100644
index 00000000000..41bde38fd47
--- /dev/null
+++ b/src/emu/attotime.c
@@ -0,0 +1,312 @@
+/***************************************************************************
+
+ attotime.c
+
+ Support functions for working with attotime data.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "mamecore.h"
+#include "attotime.h"
+#include "eminline.h"
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+const attotime attotime_zero = STATIC_ATTOTIME_IN_SEC(0);
+const attotime attotime_never = STATIC_ATTOTIME_IN_SEC(ATTOTIME_MAX_SECONDS);
+
+
+
+/***************************************************************************
+ CONVERSION HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ attotime_to_attoseconds - convert a attotime
+ to attoseconds, clamping to maximum positive/
+ negative values
+-------------------------------------------------*/
+
+attoseconds_t attotime_to_attoseconds(attotime _time)
+{
+ /* positive values between 0 and 1 second */
+ if (_time.seconds == 0)
+ return _time.attoseconds;
+
+ /* negative values between -1 and 0 seconds */
+ else if (_time.seconds == -1)
+ return _time.attoseconds - ATTOSECONDS_PER_SECOND;
+
+ /* out-of-range positive values */
+ else if (_time.seconds > 0)
+ return ATTOSECONDS_PER_SECOND;
+
+ /* out-of-range negative values */
+ else
+ return -ATTOSECONDS_PER_SECOND;
+}
+
+
+
+/***************************************************************************
+ CORE MATH FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ attotime_add - add two attotimes
+-------------------------------------------------*/
+
+attotime attotime_add(attotime _time1, attotime _time2)
+{
+ attotime result;
+
+ /* if one of the items is attotime_never, return attotime_never */
+ if (_time1.seconds >= ATTOTIME_MAX_SECONDS || _time2.seconds >= ATTOTIME_MAX_SECONDS)
+ return attotime_never;
+
+ /* add the seconds and attoseconds */
+ result.attoseconds = _time1.attoseconds + _time2.attoseconds;
+ result.seconds = _time1.seconds + _time2.seconds;
+
+ /* normalize and return */
+ if (result.attoseconds >= ATTOSECONDS_PER_SECOND)
+ {
+ result.attoseconds -= ATTOSECONDS_PER_SECOND;
+ result.seconds++;
+ }
+
+ /* overflow */
+ if (result.seconds >= ATTOTIME_MAX_SECONDS)
+ return attotime_never;
+ return result;
+}
+
+
+/*-------------------------------------------------
+ attotime_add_attoseconds - add attoseconds
+ to a attotime
+-------------------------------------------------*/
+
+attotime attotime_add_attoseconds(attotime _time1, attoseconds_t _attoseconds)
+{
+ attotime result;
+
+ /* if one of the items is attotime_never, return attotime_never */
+ if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
+ return attotime_never;
+
+ /* add the seconds and attoseconds */
+ result.attoseconds = _time1.attoseconds + _attoseconds;
+ result.seconds = _time1.seconds;
+
+ /* normalize and return */
+ if (result.attoseconds >= ATTOSECONDS_PER_SECOND)
+ {
+ result.attoseconds -= ATTOSECONDS_PER_SECOND;
+ result.seconds++;
+ }
+
+ /* overflow */
+ if (result.seconds >= ATTOTIME_MAX_SECONDS)
+ return attotime_never;
+ return result;
+}
+
+
+/*-------------------------------------------------
+ attotime_sub - subtract two attotimes
+-------------------------------------------------*/
+
+attotime attotime_sub(attotime _time1, attotime _time2)
+{
+ attotime result;
+
+ /* if time1 is attotime_never, return attotime_never */
+ if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
+ return attotime_never;
+
+ /* add the seconds and attoseconds */
+ result.attoseconds = _time1.attoseconds - _time2.attoseconds;
+ result.seconds = _time1.seconds - _time2.seconds;
+
+ /* normalize and return */
+ if (result.attoseconds < 0)
+ {
+ result.attoseconds += ATTOSECONDS_PER_SECOND;
+ result.seconds--;
+ }
+ return result;
+}
+
+
+/*-------------------------------------------------
+ attotime_sub_attoseconds - subtract
+ attoseconds from a attotime
+-------------------------------------------------*/
+
+attotime attotime_sub_attoseconds(attotime _time1, attoseconds_t _attoseconds)
+{
+ attotime result;
+
+ /* if time1 is attotime_never, return attotime_never */
+ if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
+ return attotime_never;
+
+ /* add the seconds and attoseconds */
+ result.attoseconds = _time1.attoseconds - _attoseconds;
+ result.seconds = _time1.seconds;
+
+ /* normalize and return */
+ if (result.attoseconds < 0)
+ {
+ result.attoseconds += ATTOSECONDS_PER_SECOND;
+ result.seconds--;
+ }
+ return result;
+}
+
+
+/*-------------------------------------------------
+ attotime_mul - multiply an attotime by
+ a constant
+-------------------------------------------------*/
+
+attotime attotime_mul(attotime _time1, UINT32 factor)
+{
+ INT32 attolo, attohi, reslo, reshi;
+ INT64 temp;
+
+ /* if one of the items is attotime_never, return attotime_never */
+ if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
+ return attotime_never;
+
+ /* 0 times anything is zero */
+ if (factor == 0)
+ return attotime_zero;
+
+ /* split attoseconds into upper and lower halves which fit into 32 bits */
+ attohi = div_64x32_rem(_time1.attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &attolo);
+
+ /* scale the lower half, then split into high/low parts */
+ temp = mul_32x32(attolo, factor);
+ temp = div_64x32_rem(temp, ATTOSECONDS_PER_SECOND_SQRT, &reslo);
+
+ /* scale the upper half, then split into high/low parts */
+ temp += mul_32x32(attohi, factor);
+ temp = div_64x32_rem(temp, ATTOSECONDS_PER_SECOND_SQRT, &reshi);
+
+ /* scale the seconds */
+ temp += mul_32x32(_time1.seconds, factor);
+ if (temp >= ATTOTIME_MAX_SECONDS)
+ return attotime_never;
+
+ /* build the result */
+ return attotime_make(temp, (attoseconds_t)reslo + mul_32x32(reshi, ATTOSECONDS_PER_SECOND_SQRT));
+}
+
+
+/*-------------------------------------------------
+ attotime_div - divide an attotime by
+ a constant
+-------------------------------------------------*/
+
+attotime attotime_div(attotime _time1, UINT32 factor)
+{
+ INT32 attolo, attohi, reshi, reslo, remainder;
+ attotime result;
+ INT64 temp;
+
+ /* if one of the items is attotime_never, return attotime_never */
+ if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
+ return attotime_never;
+
+ /* ignore divide by zero */
+ if (factor == 0)
+ return _time1;
+
+ /* split attoseconds into upper and lower halves which fit into 32 bits */
+ attohi = div_64x32_rem(_time1.attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &attolo);
+
+ /* divide the seconds and get the remainder */
+ result.seconds = div_64x32_rem(_time1.seconds, factor, &remainder);
+
+ /* combine the upper half of attoseconds with the remainder and divide that */
+ temp = (INT64)attohi + mul_32x32(remainder, ATTOSECONDS_PER_SECOND_SQRT);
+ reshi = div_64x32_rem(temp, factor, &remainder);
+
+ /* combine the lower half of attoseconds with the remainder and divide that */
+ temp = attolo + mul_32x32(remainder, ATTOSECONDS_PER_SECOND_SQRT);
+ reslo = div_64x32_rem(temp, factor, &remainder);
+
+ /* round based on the remainder */
+ result.attoseconds = (attoseconds_t)reslo + mul_32x32(reshi, ATTOSECONDS_PER_SECOND_SQRT);
+ if (remainder >= factor / 2)
+ if (++result.attoseconds >= ATTOSECONDS_PER_SECOND)
+ {
+ result.attoseconds = 0;
+ result.seconds++;
+ }
+ return result;
+}
+
+
+/*-------------------------------------------------
+ attotime_compare - compare two attotimes
+-------------------------------------------------*/
+
+int attotime_compare(attotime _time1, attotime _time2)
+{
+ if (_time1.seconds > _time2.seconds)
+ return 1;
+ if (_time1.seconds < _time2.seconds)
+ return -1;
+ if (_time1.attoseconds > _time2.attoseconds)
+ return 1;
+ if (_time1.attoseconds < _time2.attoseconds)
+ return -1;
+ return 0;
+}
+
+
+
+/***************************************************************************
+ MISC UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ attotime_compare - return a temporary
+ printable string describing an attotime
+-------------------------------------------------*/
+
+const char *attotime_string(attotime _time, int precision)
+{
+ static char buffers[8][30];
+ static int nextbuf;
+ char *buffer = &buffers[nextbuf++ % 8][0];
+
+ /* case 1: we want no precision; seconds only */
+ if (precision == 0)
+ sprintf(buffer, "%d", _time.seconds);
+
+ /* case 2: we want 9 or fewer digits of precision */
+ else if (precision <= 9)
+ {
+ INT32 upper = _time.attoseconds / ATTOSECONDS_PER_SECOND_SQRT;
+ sprintf(buffer, "%d.%0*d", _time.seconds, precision, upper);
+ }
+
+ /* case 3: more than 9 digits of precision */
+ else
+ {
+ INT32 lower;
+ INT32 upper = div_64x32_rem(_time.attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &lower);
+ sprintf(buffer, "%d.%09d%0*d", _time.seconds, upper, precision - 9, lower);
+ }
+ return buffer;
+}
diff --git a/src/emu/attotime.h b/src/emu/attotime.h
new file mode 100644
index 00000000000..8d7395b9d42
--- /dev/null
+++ b/src/emu/attotime.h
@@ -0,0 +1,212 @@
+/***************************************************************************
+
+ attotime.h
+
+ Support functions for working with attotime data.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Attotime is an attosecond-accurate timing system implemented as
+ 96-bit integers.
+
+ 1 second = 1e0 seconds
+ 1 millisecond = 1e-3 seconds
+ 1 microsecond = 1e-6 seconds
+ 1 nanosecond = 1e-9 seconds
+ 1 picosecond = 1e-12 seconds
+ 1 femtosecond = 1e-15 seconds
+ 1 attosecond = 1e-18 seconds
+
+ This may seem insanely accurate, but it has its uses when multiple
+ clocks in the system are run by independent crystals. It is also
+ useful to compute the attotime for something small, say 1 clock tick,
+ and still have it be accurate and useful for scaling.
+
+ Attotime consists of a 32-bit seconds count and a 64-bit attoseconds
+ count. Because the lower bits are kept as attoseconds and not as a
+ full 64-bit value, there is headroom to make some operations simpler.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __ATTOTIME_H__
+#define __ATTOTIME_H__
+
+#include "mamecore.h"
+#include <math.h>
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define ATTOSECONDS_PER_SECOND_SQRT ((attoseconds_t)1000000000)
+#define ATTOSECONDS_PER_SECOND (ATTOSECONDS_PER_SECOND_SQRT * ATTOSECONDS_PER_SECOND_SQRT)
+#define ATTOSECONDS_PER_MILLISECOND (ATTOSECONDS_PER_SECOND / 1000)
+#define ATTOSECONDS_PER_MICROSECOND (ATTOSECONDS_PER_SECOND / 1000000)
+#define ATTOSECONDS_PER_NANOSECOND (ATTOSECONDS_PER_SECOND / 1000000000)
+
+#define ATTOTIME_MAX_SECONDS ((seconds_t)1000000000)
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* convert between a double and attoseconds */
+#define ATTOSECONDS_TO_DOUBLE(x) ((double)(x) * 1e-18)
+#define DOUBLE_TO_ATTOSECONDS(x) ((attoseconds_t)((x) * 1e18))
+
+/* convert between hertz (as a double) and attoseconds */
+#define ATTOSECONDS_TO_HZ(x) ((double)ATTOSECONDS_PER_SECOND / (double)(x))
+#define HZ_TO_ATTOSECONDS(x) ((attoseconds_t)(ATTOSECONDS_PER_SECOND / (x)))
+
+/* macros for converting other seconds types to attoseconds */
+#define ATTOSECONDS_IN_SEC(x) ((x) * ATTOSECONDS_PER_SECOND)
+#define ATTOSECONDS_IN_MSEC(x) ((x) * ATTOSECONDS_PER_MILLISECOND)
+#define ATTOSECONDS_IN_USEC(x) ((x) * ATTOSECONDS_PER_MICROSECOND)
+#define ATTOSECONDS_IN_NSEC(x) ((x) * ATTOSECONDS_PER_NANOSECOND)
+
+/* macros for building attotimes from other types at runtime */
+#define ATTOTIME_IN_HZ(hz) attotime_make(0, HZ_TO_ATTOSECONDS(hz))
+#define ATTOTIME_IN_SEC(s) attotime_make((s) / 1, (s) % 1 /* mod here errors on doubles, which is intended */)
+#define ATTOTIME_IN_MSEC(ms) attotime_make((ms) / 1000, ATTOSECONDS_IN_MSEC((ms) % 1000))
+#define ATTOTIME_IN_USEC(us) attotime_make((us) / 1000000, ATTOSECONDS_IN_USEC((us) % 1000000))
+#define ATTOTIME_IN_NSEC(ns) attotime_make((ns) / 1000000000, ATTOSECONDS_IN_NSEC((ns) % 1000000000))
+
+/* macros for building attotimes from other types at compile time */
+#define STATIC_ATTOTIME_IN_HZ(hz) { 0, HZ_TO_ATTOSECONDS(hz) }
+#define STATIC_ATTOTIME_IN_SEC(s) { (s) / 1, (s) % 1 /* mod here errors on doubles, which is intended */ }
+#define STATIC_ATTOTIME_IN_MSEC(ms) { (ms) / 1000, ATTOSECONDS_IN_MSEC((ms) % 1000) }
+#define STATIC_ATTOTIME_IN_USEC(us) { (us) / 1000000, ATTOSECONDS_IN_USEC((us) % 1000000) }
+#define STATIC_ATTOTIME_IN_NSEC(ns) { (ns) / 1000000000, ATTOSECONDS_IN_NSEC((ns) % 1000000000) }
+
+
+#define USEC_TO_ATTOSECONDS(us) ((attoseconds_t)((us) * ATTOSECONDS_PER_MICROSECOND))
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* core components of the attotime structure */
+typedef INT64 attoseconds_t;
+typedef INT32 seconds_t;
+
+
+/* the attotime structure itself */
+typedef struct _attotime attotime;
+struct _attotime
+{
+ seconds_t seconds;
+ attoseconds_t attoseconds;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* constant times for zero and never */
+extern const attotime attotime_zero;
+extern const attotime attotime_never;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* ----- conversion helpers ----- */
+
+/* convert an attotime to attoseconds, clamping to maximum positive/negative values */
+attoseconds_t attotime_to_attoseconds(attotime _time);
+
+
+/* ----- core math functions ----- */
+
+/* add two attotimes */
+attotime attotime_add(attotime _time1, attotime _time2);
+
+/* add attoseconds to an attotime */
+attotime attotime_add_attoseconds(attotime _time1, attoseconds_t _attoseconds);
+
+/* subtract two attotimes */
+attotime attotime_sub(attotime _time1, attotime _time2);
+
+/* subtract attoseconds from an attotime */
+attotime attotime_sub_attoseconds(attotime _time1, attoseconds_t _attoseconds);
+
+/* multiply an attotime by a constant */
+attotime attotime_mul(attotime _time1, UINT32 factor);
+
+/* divide an attotime by a constant */
+attotime attotime_div(attotime _time1, UINT32 factor);
+
+/* compare two attotimes */
+int attotime_compare(attotime _time1, attotime _time2);
+
+
+/* ----- misc utilities ----- */
+
+/* return a temporary printable string describing an attotime */
+const char *attotime_string(attotime _time, int precision);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ attotime_make - assemble an attotime from
+ seconds and attoseconds components
+-------------------------------------------------*/
+
+INLINE attotime attotime_make(seconds_t _secs, attoseconds_t _subsecs)
+{
+ attotime result;
+ result.seconds = _secs;
+ result.attoseconds = _subsecs;
+ return result;
+}
+
+
+/*-------------------------------------------------
+ attotime_to_double - convert from attotime
+ to double
+-------------------------------------------------*/
+
+INLINE double attotime_to_double(attotime _time)
+{
+ return (double)_time.seconds + ATTOSECONDS_TO_DOUBLE(_time.attoseconds);
+}
+
+
+/*-------------------------------------------------
+ double_to_attotime - convert from double to
+ attotime
+-------------------------------------------------*/
+
+INLINE attotime double_to_attotime(double _time)
+{
+ attotime result;
+
+ /* set seconds to the integral part */
+ result.seconds = floor(_time);
+
+ /* set attoseconds to the fractional part */
+ _time -= (double)result.seconds;
+ result.attoseconds = DOUBLE_TO_ATTOSECONDS(_time);
+ return result;
+}
+
+
+#endif /* __ATTOTIME_H__ */
diff --git a/src/emu/audio/generic.c b/src/emu/audio/generic.c
new file mode 100644
index 00000000000..18c17e70e2c
--- /dev/null
+++ b/src/emu/audio/generic.c
@@ -0,0 +1,162 @@
+/***************************************************************************
+
+ generic.c
+
+ Generic simple sound functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "generic.h"
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static UINT16 latch_clear_value = 0x00;
+static UINT16 latched_value[4];
+static UINT8 latch_read[4];
+
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ generic_sound_init - initialize globals and
+ register for save states
+-------------------------------------------------*/
+
+int generic_sound_init(void)
+{
+ /* reset latches */
+ latch_clear_value = 0;
+ memset(latched_value, 0, sizeof(latched_value));
+ memset(latch_read, 0, sizeof(latch_read));
+
+ /* register globals with the save state system */
+ state_save_register_global_array(latched_value);
+ state_save_register_global_array(latch_read);
+
+ return 0;
+}
+
+
+
+/***************************************************************************
+
+ Many games use a master-slave CPU setup. Typically, the main CPU writes
+ a command to some register, and then writes to another register to trigger
+ an interrupt on the slave CPU (the interrupt might also be triggered by
+ the first write). The slave CPU, notified by the interrupt, goes and reads
+ the command.
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ latch_callback - time-delayed callback to
+ set a latch value
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( latch_callback )
+{
+ UINT16 value = param >> 8;
+ int which = param & 0xff;
+
+ /* if the latch hasn't been read and the value is changed, log a warning */
+ if (!latch_read[which] && latched_value[which] != value)
+ logerror("Warning: sound latch %d written before being read. Previous: %02x, new: %02x\n", which, latched_value[which], value);
+
+ /* store the new value and mark it not read */
+ latched_value[which] = value;
+ latch_read[which] = 0;
+}
+
+
+/*-------------------------------------------------
+ latch_w - handle a write to a given latch
+-------------------------------------------------*/
+
+INLINE void latch_w(int which, UINT16 value)
+{
+ timer_call_after_resynch(which | (value << 8), latch_callback);
+}
+
+
+/*-------------------------------------------------
+ latch_r - handle a read from a given latch
+-------------------------------------------------*/
+
+INLINE UINT16 latch_r(int which)
+{
+ latch_read[which] = 1;
+ return latched_value[which];
+}
+
+
+/*-------------------------------------------------
+ latch_clear - clear a given latch
+-------------------------------------------------*/
+
+INLINE void latch_clear(int which)
+{
+ latched_value[which] = latch_clear_value;
+}
+
+
+/*-------------------------------------------------
+ soundlatch_w - global write handlers for
+ writing to sound latches
+-------------------------------------------------*/
+
+WRITE8_HANDLER( soundlatch_w ) { latch_w(0, data); }
+WRITE16_HANDLER( soundlatch_word_w ) { latch_w(0, data); }
+WRITE8_HANDLER( soundlatch2_w ) { latch_w(1, data); }
+WRITE16_HANDLER( soundlatch2_word_w ) { latch_w(1, data); }
+WRITE8_HANDLER( soundlatch3_w ) { latch_w(2, data); }
+WRITE16_HANDLER( soundlatch3_word_w ) { latch_w(2, data); }
+WRITE8_HANDLER( soundlatch4_w ) { latch_w(3, data); }
+WRITE16_HANDLER( soundlatch4_word_w ) { latch_w(3, data); }
+
+
+/*-------------------------------------------------
+ soundlatch_r - global read handlers for
+ reading from sound latches
+-------------------------------------------------*/
+
+READ8_HANDLER( soundlatch_r ) { return latch_r(0); }
+READ16_HANDLER( soundlatch_word_r ) { return latch_r(0); }
+READ8_HANDLER( soundlatch2_r ) { return latch_r(1); }
+READ16_HANDLER( soundlatch2_word_r ) { return latch_r(1); }
+READ8_HANDLER( soundlatch3_r ) { return latch_r(2); }
+READ16_HANDLER( soundlatch3_word_r ) { return latch_r(2); }
+READ8_HANDLER( soundlatch4_r ) { return latch_r(3); }
+READ16_HANDLER( soundlatch4_word_r ) { return latch_r(3); }
+
+
+/*-------------------------------------------------
+ soundlatch_clear_w - global write handlers
+ for clearing sound latches
+-------------------------------------------------*/
+
+WRITE8_HANDLER( soundlatch_clear_w ) { latch_clear(0); }
+WRITE8_HANDLER( soundlatch2_clear_w ) { latch_clear(1); }
+WRITE8_HANDLER( soundlatch3_clear_w ) { latch_clear(2); }
+WRITE8_HANDLER( soundlatch4_clear_w ) { latch_clear(3); }
+
+
+/*-------------------------------------------------
+ soundlatch_setclearedvalue - set the "clear"
+ value for all sound latches
+-------------------------------------------------*/
+
+void soundlatch_setclearedvalue(int value)
+{
+ latch_clear_value = value;
+}
diff --git a/src/emu/audio/generic.h b/src/emu/audio/generic.h
new file mode 100644
index 00000000000..398b4bf06cd
--- /dev/null
+++ b/src/emu/audio/generic.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+
+ generic.h
+
+ Generic simple sound functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __SOUND_GENERIC_H__
+#define __SOUND_GENERIC_H__
+
+#include "memory.h"
+
+
+
+/***************************************************************************
+
+ Function prototypes
+
+***************************************************************************/
+
+int generic_sound_init(void);
+
+/* latch readers */
+READ8_HANDLER( soundlatch_r );
+READ8_HANDLER( soundlatch2_r );
+READ8_HANDLER( soundlatch3_r );
+READ8_HANDLER( soundlatch4_r );
+READ16_HANDLER( soundlatch_word_r );
+READ16_HANDLER( soundlatch2_word_r );
+READ16_HANDLER( soundlatch3_word_r );
+READ16_HANDLER( soundlatch4_word_r );
+
+/* latch writers */
+WRITE8_HANDLER( soundlatch_w );
+WRITE8_HANDLER( soundlatch2_w );
+WRITE8_HANDLER( soundlatch3_w );
+WRITE8_HANDLER( soundlatch4_w );
+WRITE16_HANDLER( soundlatch_word_w );
+WRITE16_HANDLER( soundlatch2_word_w );
+WRITE16_HANDLER( soundlatch3_word_w );
+WRITE16_HANDLER( soundlatch4_word_w );
+
+/* latch clearers */
+WRITE8_HANDLER( soundlatch_clear_w );
+WRITE8_HANDLER( soundlatch2_clear_w );
+WRITE8_HANDLER( soundlatch3_clear_w );
+WRITE8_HANDLER( soundlatch4_clear_w );
+
+/* If you're going to use soundlatchX_clear_w, and the cleared value is
+ something other than 0x00, use this function from machine_init. Note
+ that this one call effects all 4 latches */
+void soundlatch_setclearedvalue(int value);
+
+
+#endif /* __SOUND_GENERIC_H__ */
diff --git a/src/emu/audit.c b/src/emu/audit.c
new file mode 100644
index 00000000000..e72cf7604b5
--- /dev/null
+++ b/src/emu/audit.c
@@ -0,0 +1,505 @@
+/***************************************************************************
+
+ audit.c
+
+ ROM set auditing functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include <stdarg.h>
+#include "driver.h"
+#include "hash.h"
+#include "audit.h"
+#include "harddisk.h"
+#include "sound/samples.h"
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int audit_one_rom(core_options *options, const rom_entry *rom, const game_driver *gamedrv, UINT32 validation, audit_record *record);
+static int audit_one_disk(core_options *options, const rom_entry *rom, const game_driver *gamedrv, UINT32 validation, audit_record *record);
+static int rom_used_by_parent(const game_driver *gamedrv, const rom_entry *romentry, const game_driver **parent);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ set_status - shortcut for setting status and
+ substatus values
+-------------------------------------------------*/
+
+INLINE void set_status(audit_record *record, UINT8 status, UINT8 substatus)
+{
+ record->status = status;
+ record->substatus = substatus;
+}
+
+
+
+/***************************************************************************
+ CORE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ audit_images - validate the ROM and disk
+ images for a game
+-------------------------------------------------*/
+
+int audit_images(core_options *options, const game_driver *gamedrv, UINT32 validation, audit_record **audit)
+{
+ const rom_entry *region, *rom;
+ audit_record *record;
+ int foundany = FALSE;
+ int allshared = TRUE;
+ int records;
+
+ /* determine the number of records we will generate */
+ records = 0;
+ for (region = rom_first_region(gamedrv); region != NULL; region = rom_next_region(region))
+ for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom))
+ if (ROMREGION_ISROMDATA(region) || ROMREGION_ISDISKDATA(region))
+ {
+ if (allshared && !rom_used_by_parent(gamedrv, rom, NULL))
+ allshared = FALSE;
+ records++;
+ }
+
+ if (records > 0)
+ {
+ /* allocate memory for the records */
+ *audit = malloc_or_die(sizeof(**audit) * records);
+ memset(*audit, 0, sizeof(**audit) * records);
+ record = *audit;
+
+ /* iterate over regions and ROMs */
+ for (region = rom_first_region(gamedrv); region; region = rom_next_region(region))
+ for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ {
+ int shared = rom_used_by_parent(gamedrv, rom, NULL);
+
+ /* audit a file */
+ if (ROMREGION_ISROMDATA(region))
+ {
+ if (audit_one_rom(options, rom, gamedrv, validation, record++) && (!shared || allshared))
+ foundany = TRUE;
+ }
+
+ /* audit a disk */
+ else if (ROMREGION_ISDISKDATA(region))
+ {
+ if (audit_one_disk(options, rom, gamedrv, validation, record++) && (!shared || allshared))
+ foundany = TRUE;
+ }
+ }
+
+ /* if we found nothing, we don't have the set at all */
+ if (!foundany)
+ {
+ free(*audit);
+ *audit = NULL;
+ records = 0;
+ }
+ }
+ return records;
+}
+
+
+/*-------------------------------------------------
+ audit_samples - validate the samples for a
+ game
+-------------------------------------------------*/
+
+int audit_samples(core_options *options, const game_driver *gamedrv, audit_record **audit)
+{
+ machine_config config;
+ audit_record *record;
+ int sndnum, sampnum;
+ int records = 0;
+
+ /* count the number of sample records attached to this driver */
+ expand_machine_driver(gamedrv->drv, &config);
+#if HAS_SAMPLES
+ for (sndnum = 0; sndnum < ARRAY_LENGTH(config.sound); sndnum++)
+ if (config.sound[sndnum].type == SOUND_SAMPLES)
+ {
+ struct Samplesinterface *intf = (struct Samplesinterface *)config.sound[sndnum].config;
+
+ if (intf->samplenames != NULL)
+ {
+ /* iterate over samples in this entry */
+ for (sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++)
+ if (intf->samplenames[sampnum][0] != '*')
+ records++;
+ }
+ }
+#endif
+
+ /* if no records, just quit now */
+ if (records == 0)
+ return records;
+
+ /* allocate memory for the records */
+ *audit = malloc_or_die(sizeof(**audit) * records);
+ memset(*audit, 0, sizeof(**audit) * records);
+ record = *audit;
+
+ /* now iterate over sample entries */
+ for (sndnum = 0; sndnum < ARRAY_LENGTH(config.sound); sndnum++)
+ if (config.sound[sndnum].type == SOUND_SAMPLES)
+ {
+ struct Samplesinterface *intf = (struct Samplesinterface *)config.sound[sndnum].config;
+ const char *sharedname = NULL;
+
+ if (intf->samplenames != NULL)
+ {
+ /* iterate over samples in this entry */
+ for (sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++)
+ if (intf->samplenames[sampnum][0] == '*')
+ sharedname = &intf->samplenames[sampnum][1];
+ else
+ {
+ file_error filerr;
+ mame_file *file;
+ astring *fname;
+
+ /* attempt to access the file from the game driver name */
+ fname = astring_assemble_3(astring_alloc(), gamedrv->name, PATH_SEPARATOR, intf->samplenames[sampnum]);
+ filerr = mame_fopen_options(options, SEARCHPATH_SAMPLE, astring_c(fname), OPEN_FLAG_READ, &file);
+
+ /* attempt to access the file from the shared driver name */
+ if (filerr != FILERR_NONE && sharedname != NULL)
+ {
+ astring_assemble_3(fname, sharedname, PATH_SEPARATOR, intf->samplenames[sampnum]);
+ filerr = mame_fopen_options(options, SEARCHPATH_SAMPLE, astring_c(fname), OPEN_FLAG_READ, &file);
+ }
+ astring_free(fname);
+
+ /* fill in the record */
+ record->type = AUDIT_FILE_SAMPLE;
+ record->name = intf->samplenames[sampnum];
+ if (filerr == FILERR_NONE)
+ {
+ set_status(record++, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD);
+ mame_fclose(file);
+ }
+ else
+ set_status(record++, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND);
+ }
+ }
+ }
+
+ return records;
+}
+
+
+/*-------------------------------------------------
+ audit_summary - output a summary given a
+ list of audit records
+-------------------------------------------------*/
+
+int audit_summary(const game_driver *gamedrv, int count, const audit_record *records, int output)
+{
+ int overall_status = CORRECT;
+ int notfound = 0;
+ int recnum;
+
+ /* no count or records means not found */
+ if (count == 0 || records == NULL)
+ return NOTFOUND;
+
+ /* loop over records */
+ for (recnum = 0; recnum < count; recnum++)
+ {
+ const audit_record *record = &records[recnum];
+ int best_new_status = INCORRECT;
+
+ /* skip anything that's fine */
+ if (record->substatus == SUBSTATUS_GOOD)
+ continue;
+
+ /* count the number of missing items */
+ if (record->status == AUDIT_STATUS_NOT_FOUND)
+ notfound++;
+
+ /* output the game name, file name, and length (if applicable) */
+ if (output)
+ {
+ mame_printf_info("%-8s: %s", gamedrv->name, record->name);
+ if (record->explength > 0)
+ mame_printf_info(" (%d bytes)", record->explength);
+ mame_printf_info(" - ");
+ }
+
+ /* use the substatus for finer details */
+ switch (record->substatus)
+ {
+ case SUBSTATUS_GOOD_NEEDS_REDUMP:
+ if (output) mame_printf_info("NEEDS REDUMP\n");
+ best_new_status = BEST_AVAILABLE;
+ break;
+
+ case SUBSTATUS_FOUND_NODUMP:
+ if (output) mame_printf_info("NO GOOD DUMP KNOWN\n");
+ best_new_status = BEST_AVAILABLE;
+ break;
+
+ case SUBSTATUS_FOUND_BAD_CHECKSUM:
+ if (output)
+ {
+ char hashbuf[512];
+
+ mame_printf_info("INCORRECT CHECKSUM:\n");
+ hash_data_print(record->exphash, 0, hashbuf);
+ mame_printf_info("EXPECTED: %s\n", hashbuf);
+ hash_data_print(record->hash, 0, hashbuf);
+ mame_printf_info(" FOUND: %s\n", hashbuf);
+ }
+ break;
+
+ case SUBSTATUS_FOUND_WRONG_LENGTH:
+ if (output) mame_printf_info("INCORRECT LENGTH: %d bytes\n", record->length);
+ break;
+
+ case SUBSTATUS_NOT_FOUND:
+ if (output) mame_printf_info("NOT FOUND\n");
+ break;
+
+ case SUBSTATUS_NOT_FOUND_NODUMP:
+ if (output) mame_printf_info("NOT FOUND - NO GOOD DUMP KNOWN\n");
+ best_new_status = BEST_AVAILABLE;
+ break;
+
+ case SUBSTATUS_NOT_FOUND_OPTIONAL:
+ if (output) mame_printf_info("NOT FOUND BUT OPTIONAL\n");
+ best_new_status = BEST_AVAILABLE;
+ break;
+
+ case SUBSTATUS_NOT_FOUND_PARENT:
+ if (output) mame_printf_info("NOT FOUND (shared with parent)\n");
+ break;
+
+ case SUBSTATUS_NOT_FOUND_BIOS:
+ if (output) mame_printf_info("NOT FOUND (BIOS)\n");
+ break;
+ }
+
+ /* downgrade the overall status if necessary */
+ overall_status = MAX(overall_status, best_new_status);
+ }
+
+ return (notfound == count) ? NOTFOUND : overall_status;
+}
+
+
+
+/***************************************************************************
+ UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ audit_one_rom - validate a single ROM entry
+-------------------------------------------------*/
+
+static int audit_one_rom(core_options *options, const rom_entry *rom, const game_driver *gamedrv, UINT32 validation, audit_record *record)
+{
+ const game_driver *drv;
+ const rom_entry *chunk;
+ UINT32 crc = 0;
+ UINT8 crcs[4];
+ int has_crc;
+
+ /* fill in the record basics */
+ record->type = AUDIT_FILE_ROM;
+ record->name = ROM_GETNAME(rom);
+ record->exphash = ROM_GETHASHDATA(rom);
+
+ /* compute the expected length by summing the chunks */
+ for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk))
+ record->explength += ROM_GETLENGTH(chunk);
+
+ /* see if we have a CRC and extract it if so */
+ has_crc = hash_data_extract_binary_checksum(record->exphash, HASH_CRC, crcs);
+ if (has_crc)
+ crc = (crcs[0] << 24) | (crcs[1] << 16) | (crcs[2] << 8) | crcs[3];
+
+ /* find the file and checksum it, getting the file length along the way */
+ for (drv = gamedrv; drv != NULL; drv = driver_get_clone(drv))
+ {
+ file_error filerr;
+ mame_file *file;
+ astring *fname;
+
+ /* open the file if we can */
+ fname = astring_assemble_3(astring_alloc(), drv->name, PATH_SEPARATOR, ROM_GETNAME(rom));
+ if (has_crc)
+ filerr = mame_fopen_crc_options(options, SEARCHPATH_ROM, astring_c(fname), crc, OPEN_FLAG_READ, &file);
+ else
+ filerr = mame_fopen_options(options, SEARCHPATH_ROM, astring_c(fname), OPEN_FLAG_READ, &file);
+ astring_free(fname);
+
+ /* if we got it, extract the hash and length */
+ if (filerr == FILERR_NONE)
+ {
+ hash_data_copy(record->hash, mame_fhash(file, validation));
+ record->length = (UINT32)mame_fsize(file);
+ mame_fclose(file);
+ break;
+ }
+ }
+
+ /* if we failed to find the file, set the appropriate status */
+ if (drv == NULL)
+ {
+ const game_driver *parent;
+
+ /* no good dump */
+ if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP))
+ set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP);
+
+ /* optional ROM */
+ else if (ROM_ISOPTIONAL(rom))
+ set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_OPTIONAL);
+
+ /* not found and used by parent */
+ else if (rom_used_by_parent(gamedrv, rom, &parent))
+ set_status(record, AUDIT_STATUS_NOT_FOUND, (parent->flags & GAME_IS_BIOS_ROOT) ? SUBSTATUS_NOT_FOUND_BIOS : SUBSTATUS_NOT_FOUND_PARENT);
+
+ /* just plain old not found */
+ else
+ set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND);
+ }
+
+ /* if we did find the file, do additional verification */
+ else
+ {
+ /* length mismatch */
+ if (record->explength != record->length)
+ set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_WRONG_LENGTH);
+
+ /* found but needs a dump */
+ else if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP))
+ set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP);
+
+ /* incorrect hash */
+ else if (!hash_data_is_equal(record->exphash, record->hash, 0))
+ set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM);
+
+ /* correct hash but needs a redump */
+ else if (hash_data_has_info(record->exphash, HASH_INFO_BAD_DUMP))
+ set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP);
+
+ /* just plain old good */
+ else
+ set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD);
+ }
+
+ /* return TRUE if we found anything at all */
+ return (drv != NULL);
+}
+
+
+/*-------------------------------------------------
+ audit_one_disk - validate a single disk entry
+-------------------------------------------------*/
+
+static int audit_one_disk(core_options *options, const rom_entry *rom, const game_driver *gamedrv, UINT32 validation, audit_record *record)
+{
+ mame_file *source_file;
+ chd_file *source;
+ chd_error err;
+
+ /* fill in the record basics */
+ record->type = AUDIT_FILE_DISK;
+ record->name = ROM_GETNAME(rom);
+ record->exphash = ROM_GETHASHDATA(rom);
+
+ /* open the disk */
+ err = open_disk_image_options(options, gamedrv, rom, &source_file, &source);
+
+ /* if we failed, report the error */
+ if (err != CHDERR_NONE)
+ {
+ /* out of memory */
+ if (err == CHDERR_OUT_OF_MEMORY)
+ set_status(record, AUDIT_STATUS_ERROR, SUBSTATUS_ERROR);
+
+ /* not found but it's not good anyway */
+ else if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP))
+ set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP);
+
+ /* not found at all */
+ else
+ set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND);
+ }
+
+ /* if we succeeded, validate it */
+ else
+ {
+ static const UINT8 nullhash[HASH_BUF_SIZE] = { 0 };
+ chd_header header = *chd_get_header(source);
+
+ /* if there's an MD5 or SHA1 hash, add them to the output hash */
+ if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0)
+ hash_data_insert_binary_checksum(record->hash, HASH_MD5, header.md5);
+ if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0)
+ hash_data_insert_binary_checksum(record->hash, HASH_SHA1, header.sha1);
+
+ /* found but needs a dump */
+ if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP))
+ set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP);
+
+ /* incorrect hash */
+ else if (!hash_data_is_equal(record->exphash, record->hash, 0))
+ set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM);
+
+ /* just plain good */
+ else
+ set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD);
+
+ chd_close(source);
+ mame_fclose(source_file);
+ }
+
+ /* return TRUE if we found anything at all */
+ return (source != NULL);
+}
+
+
+/*-------------------------------------------------
+ rom_used_by_parent - determine if a given
+ ROM is also used by the parent
+-------------------------------------------------*/
+
+static int rom_used_by_parent(const game_driver *gamedrv, const rom_entry *romentry, const game_driver **parent)
+{
+ const char *hash = ROM_GETHASHDATA(romentry);
+ const game_driver *drv;
+
+ /* iterate up the parent chain */
+ for (drv = driver_get_clone(gamedrv); drv != NULL; drv = driver_get_clone(drv))
+ {
+ const rom_entry *region;
+ const rom_entry *rom;
+
+ /* see if the parent has the same ROM or not */
+ for (region = rom_first_region(drv); region; region = rom_next_region(region))
+ for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ if (hash_data_is_equal(ROM_GETHASHDATA(rom), hash, 0))
+ {
+ if (parent != NULL)
+ *parent = drv;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/src/emu/audit.h b/src/emu/audit.h
new file mode 100644
index 00000000000..b17ddecca68
--- /dev/null
+++ b/src/emu/audit.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+
+ audit.h
+
+ ROM, disk, and sample auditing functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __AUDIT_H__
+#define __AUDIT_H__
+
+#include "mamecore.h"
+#include "hash.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* hashes to use for validation */
+#define AUDIT_VALIDATE_FAST (HASH_CRC)
+#define AUDIT_VALIDATE_FULL (HASH_CRC | HASH_SHA)
+
+/* return values from audit_verify_roms and audit_verify_samples */
+#define CORRECT 0
+#define BEST_AVAILABLE 1
+#define INCORRECT 2
+#define NOTFOUND 3
+
+/* image types for audit_record.type */
+#define AUDIT_FILE_ROM 0
+#define AUDIT_FILE_DISK 1
+#define AUDIT_FILE_SAMPLE 2
+
+/* status values for audit_record.status */
+#define AUDIT_STATUS_GOOD 0
+#define AUDIT_STATUS_FOUND_INVALID 1
+#define AUDIT_STATUS_NOT_FOUND 2
+#define AUDIT_STATUS_ERROR 3
+
+/* substatus values for audit_record.substatus */
+#define SUBSTATUS_GOOD 0
+#define SUBSTATUS_GOOD_NEEDS_REDUMP 1
+#define SUBSTATUS_FOUND_NODUMP 2
+#define SUBSTATUS_FOUND_BAD_CHECKSUM 3
+#define SUBSTATUS_FOUND_WRONG_LENGTH 4
+#define SUBSTATUS_NOT_FOUND 5
+#define SUBSTATUS_NOT_FOUND_NODUMP 6
+#define SUBSTATUS_NOT_FOUND_OPTIONAL 7
+#define SUBSTATUS_NOT_FOUND_PARENT 8
+#define SUBSTATUS_NOT_FOUND_BIOS 9
+#define SUBSTATUS_ERROR 100
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _audit_record audit_record;
+struct _audit_record
+{
+ UINT8 type; /* type of item that was audited */
+ UINT8 status; /* status of audit on this item */
+ UINT8 substatus; /* finer-detail status */
+ const char * name; /* name of item */
+ UINT32 explength; /* expected length of item */
+ UINT32 length; /* actual length of item */
+ const char * exphash; /* expected hash data */
+ char hash[HASH_BUF_SIZE]; /* actual hash information */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+int audit_images(core_options *options, const game_driver *gamedrv, UINT32 validation, audit_record **audit);
+int audit_samples(core_options *options, const game_driver *gamedrv, audit_record **audit);
+int audit_summary(const game_driver *gamedrv, int count, const audit_record *records, int output);
+
+
+#endif /* __AUDIT_H__ */
diff --git a/src/emu/cheat.c b/src/emu/cheat.c
new file mode 100644
index 00000000000..9a423bbf480
--- /dev/null
+++ b/src/emu/cheat.c
@@ -0,0 +1,11890 @@
+/*********************************************************************
+
+ cheat.c
+
+ MAME cheat system.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "ui.h"
+#include "uimenu.h"
+#include "uitext.h"
+#include "machine/eeprom.h"
+#include "cheat.h"
+#include <ctype.h>
+#include <math.h>
+
+#ifdef MESS
+#include "cheatms.h"
+#endif
+
+#define OSD_READKEY_KLUDGE 1
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* easy bitfield extraction and setting, uses *_Shift, *_ShiftedMask, and *_Mask enums */
+#define EXTRACT_FIELD(data, name) (((data) >> k##name##_Shift) & k##name##_ShiftedMask)
+#define SET_FIELD(data, name, in) (data = (data & ~(k##name##_ShiftedMask << k##name##_Shift)) | (((in) & k##name##_ShiftedMask) << k##name##_Shift))
+#define TEST_FIELD(data, name) ((data) & k##name##_Mask)
+#define SET_MASK_FIELD(data, name) ((data) |= k##name##_Mask)
+#define CLEAR_MASK_FIELD(data, name) ((data) &= ~(k##name##_Mask))
+#define TOGGLE_MASK_FIELD(data, name) ((data) ^= k##name##_Mask)
+
+#define DEFINE_BITFIELD_ENUM(name, end, start) k##name##_Shift = (int)(end), \
+ k##name##_ShiftedMask = (int)(0xFFFFFFFF >> (32 - (start - end + 1))), \
+ k##name##_Mask = (int)(k##name##_ShiftedMask << k##name##_Shift)
+
+#define kRegionListLength (REGION_MAX - REGION_INVALID)
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define CHEAT_FILENAME_MAX_LEN 255
+
+/********** BIT FIELD **********/
+
+enum
+{
+ /* cheat code */
+ DEFINE_BITFIELD_ENUM(OneShot, 0, 0),
+ DEFINE_BITFIELD_ENUM(Type, 1, 2),
+ DEFINE_BITFIELD_ENUM(Operation, 3, 4),
+ DEFINE_BITFIELD_ENUM(TypeParameter, 5, 7),
+ DEFINE_BITFIELD_ENUM(UserSelectEnable, 8, 8),
+ DEFINE_BITFIELD_ENUM(UserSelectMinimumDisplay, 9, 9),
+ DEFINE_BITFIELD_ENUM(UserSelectMinimum, 10, 10),
+ DEFINE_BITFIELD_ENUM(UserSelectBCD, 11, 11),
+ DEFINE_BITFIELD_ENUM(Prefill, 12, 13),
+ DEFINE_BITFIELD_ENUM(RemoveFromList, 14, 14),
+ DEFINE_BITFIELD_ENUM(LinkExtension, 15, 15),
+ DEFINE_BITFIELD_ENUM(LinkEnable, 16, 16),
+ DEFINE_BITFIELD_ENUM(LinkCopyPreviousValue, 17, 17),
+ DEFINE_BITFIELD_ENUM(OperationParameter, 18, 18),
+ DEFINE_BITFIELD_ENUM(OperationExtend, 19, 19),
+ DEFINE_BITFIELD_ENUM(BytesUsed, 20, 21),
+ DEFINE_BITFIELD_ENUM(Endianness, 22, 22),
+ DEFINE_BITFIELD_ENUM(RestorePreviousValue, 23, 23),
+ DEFINE_BITFIELD_ENUM(LocationParameter, 24, 28),
+ DEFINE_BITFIELD_ENUM(LocationType, 29, 31),
+
+ /* watch (unused ?) */
+// DEFINE_BITFIELD_ENUM(Watch_AddValue, 0, 15),
+// DEFINE_BITFIELD_ENUM(Watch_Label, 16, 17),
+// DEFINE_BITFIELD_ENUM(Watch_DisplayType, 18, 19),
+
+ /* command */
+ DEFINE_BITFIELD_ENUM(AutoSaveEnabled, 0, 0),
+ DEFINE_BITFIELD_ENUM(SearchBox, 1, 2), // 0 = Minimum, 1 = Classic, 2 = Advanced
+ DEFINE_BITFIELD_ENUM(DontPrintNewLabels, 3, 3), // in options menu, it is reverted.
+ DEFINE_BITFIELD_ENUM(ActivationKeyMessage, 4, 4),
+ DEFINE_BITFIELD_ENUM(LoadOldFormat, 5, 5),
+ DEFINE_BITFIELD_ENUM(Debug, 6, 6)
+};
+
+/********** OPERATION **********/
+
+enum // types
+{
+ kType_NormalOrDelay = 0,
+ kType_WaitForModification,
+ kType_IgnoreIfDecrementing,
+ kType_Watch
+};
+
+enum // operations
+{
+ kOperation_WriteMask = 0,
+ kOperation_AddSubtract,
+ kOperation_ForceRange,
+ kOperation_SetOrClearBits,
+ kOperation_WriteMatch,
+ // kOperation_Unused5,
+ // kOperation_Unused6,
+ kOperation_None = 7
+};
+
+//enum // prefills (unused?)
+//{
+// kPrefill_Disable = 0,
+// kPrefill_UseFF,
+// kPrefill_Use00,
+// kPrefill_Use01
+//};
+
+enum // location types
+{
+ kLocation_Standard = 0,
+ kLocation_MemoryRegion,
+ kLocation_HandlerMemory,
+ kLocation_Custom,
+ kLocation_IndirectIndexed,
+ kLocation_ProgramSpace
+};
+
+enum // location parameters
+{
+ kCustomLocation_Comment = 0,
+ kCustomLocation_EEPROM,
+ kCustomLocation_Select,
+ kCustomLocation_AssignActivationKey,
+ kCustomLocation_Enable,
+ kCustomLocation_Overclock,
+ kCustomLocation_RefreshRate
+};
+
+enum // flags for action
+{
+ /* set for wait for modification or ignore if decrementing cheats when
+ the targeted value has changed
+ cleared after the operation is performed */
+ kActionFlag_WasModified = 1 << 0,
+
+ /* set for one shot cheats after the operation is performed */
+ kActionFlag_OperationDone = 1 << 1,
+
+ /* set if the extendData field is being used by something other than a mask value */
+ kActionFlag_IgnoreMask = 1 << 2,
+
+ /* set if the lastValue field contains valid data and can be restored if needed */
+ kActionFlag_LastValueGood = 1 << 3,
+
+ /* set after value changes from prefill value */
+ kActionFlag_PrefillDone = 1 << 4,
+
+ /* set after prefill value written */
+ kActionFlag_PrefillWritten = 1 << 5,
+
+ /* masks */
+ kActionFlag_StateMask = kActionFlag_OperationDone |
+ kActionFlag_LastValueGood |
+ kActionFlag_PrefillDone |
+ kActionFlag_PrefillWritten,
+ kActionFlag_InfoMask = kActionFlag_WasModified |
+ kActionFlag_IgnoreMask,
+ kActionFlag_PersistentMask = kActionFlag_LastValueGood
+};
+
+enum // flags for entry
+{
+ /* true when the cheat is active */
+ kCheatFlag_Active = 1 << 0,
+
+ /* true if the cheat is entirely one shot */
+ kCheatFlag_OneShot = 1 << 1,
+
+ /* true if the cheat will work with one shot in special case */
+ kCheatFlag_DoOneShot = 1 << 2,
+
+ /* true if the cheat is entirely null (ex. a comment) */
+ kCheatFlag_Null = 1 << 3,
+
+ /* true if the cheat contains a user-select element */
+ kCheatFlag_UserSelect = 1 << 4,
+
+ /* true if the cheat is a select cheat */
+ kCheatFlag_Select = 1 << 5,
+
+ /* true if the cheat has been assigned an 1st activation key */
+ kCheatFlag_HasActivationKey1 = 1 << 6,
+
+ /* true if the cheat has been assigned an 2nd activation key */
+ kCheatFlag_HasActivationKey2 = 1 << 7,
+
+ /* true if the activation key is being pressed */
+ kCheatFlag_ActivationKeyPressed = 1 << 8,
+
+ /* true if the cheat has been edited or is a new cheat */
+ kCheatFlag_Dirty = 1 << 9,
+
+ /* masks */
+ kCheatFlag_StateMask = kCheatFlag_Active |
+ kCheatFlag_DoOneShot,
+ kCheatFlag_InfoMask = kCheatFlag_OneShot |
+ kCheatFlag_DoOneShot |
+ kCheatFlag_Null |
+ kCheatFlag_UserSelect |
+ kCheatFlag_Select |
+ kCheatFlag_HasActivationKey1 |
+ kCheatFlag_HasActivationKey2 |
+ kCheatFlag_ActivationKeyPressed,
+ kCheatFlag_PersistentMask = kCheatFlag_Active |
+ kCheatFlag_DoOneShot |
+ kCheatFlag_HasActivationKey1 |
+ kCheatFlag_HasActivationKey2 |
+ kCheatFlag_ActivationKeyPressed |
+ kCheatFlag_Dirty
+};
+
+/********** WATCH **********/
+
+enum // types
+{
+ kWatchLabel_None = 0,
+ kWatchLabel_Address,
+ kWatchLabel_String,
+
+ kWatchLabel_MaxPlusOne
+};
+
+enum // display types
+{
+ kWatchDisplayType_Hex = 0,
+ kWatchDisplayType_Decimal,
+ kWatchDisplayType_Binary,
+ kWatchDisplayType_ASCII,
+
+ kWatchDisplayType_MaxPlusOne
+};
+
+/********** REGION **********/
+
+enum // flags
+{
+ /* true if enabled for search */
+ kRegionFlag_Enabled = 1 << 0
+
+ /* true if the memory region has no mapped memory and uses a memory handler (unused?) */
+// kRegionFlag_UsesHandler = 1 << 1
+};
+
+enum // types
+{
+ kRegionType_CPU = 0,
+ kRegionType_Memory
+};
+
+enum // default search regions
+{
+ kSearchSpeed_Fast = 0, // RAM + some banks
+ kSearchSpeed_Medium, // RAM + BANKx
+ kSearchSpeed_Slow, // all memory areas except ROM, NOP, and custom handlers
+ kSearchSpeed_VerySlow, // all memory areas except ROM and NOP
+ kSearchSpeed_AllMemory, // entire CPU address space
+
+ kSearchSpeed_Max = kSearchSpeed_AllMemory
+};
+
+/********** SEARCH **********/
+
+enum // operands
+{
+ kSearchOperand_Current = 0,
+ kSearchOperand_Previous,
+ kSearchOperand_First,
+ kSearchOperand_Value,
+
+ kSearchOperand_Max = kSearchOperand_Value
+};
+
+enum // bits
+{
+ kSearchSize_8Bit = 0,
+ kSearchSize_16Bit,
+ kSearchSize_24Bit,
+ kSearchSize_32Bit,
+ kSearchSize_1Bit,
+
+ kSearchSize_Max = kSearchSize_1Bit
+};
+
+enum // comparisons
+{
+ kSearchComparison_LessThan = 0,
+ kSearchComparison_GreaterThan,
+ kSearchComparison_EqualTo,
+ kSearchComparison_LessThanOrEqualTo,
+ kSearchComparison_GreaterThanOrEqualTo,
+ kSearchComparison_NotEqual,
+ kSearchComparison_IncreasedBy,
+ kSearchComparison_NearTo,
+
+ kSearchComparison_Max = kSearchComparison_NearTo
+};
+
+/********** OTHERS **********/
+
+enum
+{
+ kVerticalKeyRepeatRate = 8,
+ kHorizontalFastKeyRepeatRate = 5,
+ kHorizontalSlowKeyRepeatRate = 8
+};
+
+enum
+{
+ kSearchBox_Minimum = 0,
+ kSearchBox_Classic,
+ kSearchBox_Advanced
+};
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/********** ACTION **********/
+
+struct CheatAction
+{
+ UINT32 type;
+ UINT32 address;
+ UINT32 data;
+ UINT32 extendData;
+ UINT32 originalDataField;
+
+ INT32 frameTimer;
+ UINT32 lastValue;
+
+ UINT32 flags;
+
+ UINT8 ** cachedPointer;
+ UINT32 cachedOffset;
+
+ char * optionalName;
+};
+
+typedef struct CheatAction CheatAction;
+
+/********** ENTRY **********/
+
+struct CheatEntry
+{
+ char * name;
+ char * comment;
+
+ INT32 actionListLength;
+ CheatAction * actionList;
+
+ int activationKey1;
+ int activationKey2;
+
+ UINT32 flags;
+ int selection;
+};
+
+typedef struct CheatEntry CheatEntry;
+
+/********** WATCH **********/
+
+struct WatchInfo
+{
+ UINT32 address;
+ UINT8 cpu;
+ UINT8 numElements;
+ UINT8 elementBytes;
+ UINT8 labelType;
+ UINT8 displayType;
+ UINT8 skip;
+ UINT8 elementsPerLine;
+ INT8 addValue;
+ INT8 addressShift;
+ INT8 dataShift;
+ UINT32 xor;
+
+ UINT8 locationType;
+
+ float x, y;
+
+ CheatEntry * linkedCheat;
+
+ char label[256];
+};
+
+typedef struct WatchInfo WatchInfo;
+
+/********** REGION **********/
+
+struct SearchRegion
+{
+ UINT32 address;
+ UINT32 length;
+
+ UINT8 targetType;
+ UINT8 targetIdx;
+
+ UINT8 flags;
+
+ UINT8 * cachedPointer;
+ const address_map
+ * writeHandler;
+
+ UINT8 * first;
+ UINT8 * last;
+
+ UINT8 * status;
+
+ UINT8 * backupLast;
+ UINT8 * backupStatus;
+
+ char name[32]; // 12345678 - 12345678 BANK31
+
+ UINT32 numResults;
+ UINT32 oldNumResults;
+};
+
+typedef struct SearchRegion SearchRegion;
+
+/********** SEARCH **********/
+
+struct OldSearchOptions
+{
+ UINT8 status;
+ UINT8 energy;
+ UINT8 operand;
+ UINT32 value;
+ UINT32 delta;
+};
+
+typedef struct OldSearchOptions OldSearchOptions;
+
+struct SearchInfo
+{
+ INT32 regionListLength;
+ SearchRegion * regionList;
+
+ char * name;
+
+ INT8 bytes; // 0 = 1, 1 = 2, 2 = 3, 3 = 4, 4 = bit
+ UINT8 swap;
+ UINT8 sign;
+ INT8 lhs;
+ INT8 rhs;
+ INT8 comparison;
+
+ UINT8 targetType; // cpu/region
+ UINT8 targetIdx; // cpu or region index
+
+ UINT32 value;
+
+ UINT8 searchSpeed;
+
+ UINT32 numResults;
+ UINT32 oldNumResults;
+
+ INT32 currentRegionIdx;
+ INT32 currentResultsPage;
+
+ UINT8 backupValid;
+
+ OldSearchOptions oldOptions;
+};
+
+typedef struct SearchInfo SearchInfo;
+
+/********** CPU **********/
+
+struct CPUInfo
+{
+ UINT8 type;
+ UINT8 dataBits;
+ UINT8 addressBits;
+ UINT8 addressCharsNeeded;
+ UINT32 addressMask;
+ UINT8 endianness;
+ UINT8 addressShift;
+};
+
+typedef struct CPUInfo CPUInfo;
+
+/********** MENU **********/
+
+struct MenuStringList
+{
+ const char ** mainList; // editable menu item lists
+ const char ** subList;
+ char * flagList;
+
+ char ** mainStrings; // lists of useable strings
+ char ** subStrings;
+
+ char * buf; // string storage
+
+ UINT32 length; // number of menu items supported
+ UINT32 numStrings; // number of strings supported
+ UINT32 mainStringLength; // max length of main string
+ UINT32 subStringLength; // max length of sub string
+};
+
+typedef struct MenuStringList MenuStringList;
+
+struct MenuItemInfoStruct
+{
+ UINT32 subcheat;
+ UINT32 fieldType;
+ UINT32 extraData;
+};
+
+typedef struct MenuItemInfoStruct MenuItemInfoStruct;
+
+/***************************************************************************
+ EXPORTED VARIABLES
+***************************************************************************/
+
+static const char * cheatfile = NULL;
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static emu_timer * periodic_timer;
+
+static CheatEntry * cheatList = NULL;
+static INT32 cheatListLength = 0;
+
+static WatchInfo * watchList = NULL;
+static INT32 watchListLength = 0;
+
+static SearchInfo * searchList = NULL;
+static INT32 searchListLength = 0;
+static INT32 currentSearchIdx = 0;
+
+static CPUInfo cpuInfoList[MAX_CPU];
+static CPUInfo regionInfoList[kRegionListLength];
+
+//static int cheatEngineWasActive = 0;
+static int foundCheatDatabase = 0;
+static int cheatsDisabled = 0;
+static int watchesDisabled = 0;
+
+static int fullMenuPageHeight = 0;
+
+static char mainDatabaseName[CHEAT_FILENAME_MAX_LEN + 1];
+
+static MenuStringList menuStrings;
+
+static MenuItemInfoStruct * menuItemInfo;
+static INT32 menuItemInfoLength = 0;
+
+static UINT32 cheatOptions = 2;
+
+static const char * kCheatNameTemplates[] =
+{
+ "Infinite Credits",
+ "Infinite Time",
+ "Infinite Lives",
+ "Infinite Energy",
+ "Invincibility",
+ "Infinite Time PL1",
+ "Infinite Lives PL1",
+ "Infinite Energy PL1",
+ "Drain all Energy Now! PL1",
+ "Invincibility PL1",
+ "Infinite Time PL2",
+ "Infinite Lives PL2",
+ "Infinite Energy PL2",
+ "Drain all Energy Now! PL2",
+ "Invincibility PL2",
+ "Infinite Ammo",
+ "Infinite Bombs",
+ "Select starting level",
+ "Rapid Fire",
+ "Infinite Ammo PL1",
+ "Infinite Bombs PL1",
+ "Select Score PL1",
+ "Rapid Fire PL1",
+ "Infinite Ammo PL2",
+ "Infinite Bombs PL2",
+ "Select Score PL2",
+ "Rapid Fire PL2",
+ "Display the Correct Answer",
+ "Infinite ",
+ "Always have ",
+ "Get ",
+ "Lose ",
+ "Finish this ",
+ "---> <ENTER> To Edit <---",
+ "\0"
+};
+
+static CPUInfo rawCPUInfo =
+{
+ 0, // type
+ 8, // dataBits
+ 8, // addressBits
+ 1, // addressCharsNeeded
+ CPU_IS_BE // endianness
+};
+
+static const int kSearchByteIncrementTable[] =
+{
+ 1,
+ 2,
+ 3,
+ 4,
+ 1
+};
+
+static const int kSearchByteStep[] =
+{
+ 1,
+ 2,
+ 1,
+ 4,
+ 1
+};
+
+static const int kSearchByteDigitsTable[] =
+{
+ 2,
+ 4,
+ 6,
+ 8,
+ 1
+};
+
+static const int kSearchByteDecDigitsTable[] =
+{
+ 3,
+ 5,
+ 8,
+ 10,
+ 1
+};
+
+static const UINT32 kSearchByteMaskTable[] =
+{
+ 0x000000FF,
+ 0x0000FFFF,
+ 0x00FFFFFF,
+ 0xFFFFFFFF,
+ 0x00000001
+};
+
+static const UINT32 kSearchByteSignBitTable[] =
+{
+ 0x00000080,
+ 0x00008000,
+ 0x00800000,
+ 0x80000000,
+ 0x00000000
+};
+
+static const UINT32 kSearchByteUnsignedMaskTable[] =
+{
+ 0x0000007F,
+ 0x00007FFF,
+ 0x007FFFFF,
+ 0x7FFFFFFF,
+ 0x00000001
+};
+
+static const UINT32 kCheatSizeMaskTable[] =
+{
+ 0x000000FF,
+ 0x0000FFFF,
+ 0x00FFFFFF,
+ 0xFFFFFFFF
+};
+
+static const UINT32 kCheatSizeDigitsTable[] =
+{
+ 2,
+ 4,
+ 6,
+ 8
+};
+
+static const int kByteConversionTable[] =
+{
+ kSearchSize_8Bit,
+ kSearchSize_16Bit,
+ kSearchSize_24Bit,
+ kSearchSize_32Bit,
+ kSearchSize_32Bit
+};
+
+static const int kWatchSizeConversionTable[] =
+{
+ kSearchSize_8Bit,
+ kSearchSize_16Bit,
+ kSearchSize_24Bit,
+ kSearchSize_32Bit,
+ kSearchSize_8Bit
+};
+
+static const int kSearchOperandNeedsInit[] =
+{
+ 0,
+ 1,
+ 1,
+ 0
+};
+
+static const UINT32 kPrefillValueTable[] =
+{
+ 0x00,
+ 0xFF,
+ 0x00,
+ 0x01
+};
+
+static const char * kWatchLabelStringList[] =
+{
+ "None",
+ "Address",
+ "String"
+};
+
+static const char * kWatchDisplayTypeStringList[] =
+{
+ "Hex",
+ "Decimal",
+ "Binary",
+ "ASCII"
+};
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/********** MAIN **********/
+static TIMER_CALLBACK( cheat_periodic );
+static void cheat_exit(running_machine *machine);
+
+/********** SPECIAL KEY HANDLING **********/
+static int ShiftKeyPressed(void);
+static int ControlKeyPressed(void);
+static int AltKeyPressed(void);
+
+static int UIPressedRepeatThrottle(int code, int baseSpeed);
+
+/********** DIRECT KEY INPUT **********/
+static int ReadHexInput(void);
+
+static char * DoDynamicEditTextField(char * buf);
+static void DoStaticEditTextField(char * buf, int size);
+static UINT32 DoEditHexField(UINT32 data);
+static UINT32 DoEditHexFieldSigned(UINT32 data, UINT32 mask);
+static INT32 DoEditDecField(INT32 data, INT32 min, INT32 max);
+
+/********** VALUE SHIFT OR CONVERTION **********/
+static UINT32 DoShift(UINT32 input, INT8 shift);
+
+static UINT32 BCDToDecimal(UINT32 value);
+static UINT32 DecimalToBCD(UINT32 value);
+
+/********** STRINGS **********/
+static void RebuildStringTables(void);
+static void RequestStrings(UINT32 length, UINT32 numStrings, UINT32 mainStringLength, UINT32 subStringLength);
+static void InitStringTable(void);
+static void FreeStringTable(void);
+
+static char * CreateStringCopy(char * buf);
+
+/********** ADDITIONAL MENU FOR CHEAT **********/
+static INT32 UserSelectValueMenu(int selection, CheatEntry * entry);
+
+/********** CHEAT MENU **********/
+static int EnableDisableCheatMenu(int selection, int firstTime);
+static int AddEditCheatMenu(int selection);
+static int EditCheatMenu(CheatEntry * entry, int index, int selection);
+
+static int DoSearchMenuMinimum(int selection); // minimum mode
+static int DoSearchMenuClassic(int selection); // classic mode
+static int DoSearchMenu(int selection); // advanced mode
+static int SelectSearchRegions(int selection, SearchInfo * search);
+static int ViewSearchResults(int selection, int firstTime);
+
+static int ChooseWatch(int selection);
+static int EditWatch(WatchInfo * entry, int selection);
+
+static int SelectOptions(int selection);
+static int SelectSearch(int selection);
+
+/********** ENTRY LIST **********/
+static void ResizeCheatList(UINT32 newLength);
+static void ResizeCheatListNoDispose(UINT32 newLength);
+
+static void AddCheatBefore(UINT32 idx);
+static void DeleteCheatAt(UINT32 idx);
+
+static void DisposeCheat(CheatEntry * entry);
+static CheatEntry * GetNewCheat(void);
+
+/********** ACTION LIST **********/
+static void ResizeCheatActionList(CheatEntry * entry, UINT32 newLength);
+static void ResizeCheatActionListNoDispose(CheatEntry * entry, UINT32 newLength);
+
+static void AddActionBefore(CheatEntry * entry, UINT32 idx);
+static void DeleteActionAt(CheatEntry * entry, UINT32 idx);
+static void DisposeAction(CheatAction * action);
+
+/********** WATCH LIST **********/
+static void InitWatch(WatchInfo * info, UINT32 idx);
+static void ResizeWatchList(UINT32 newLength);
+static void ResizeWatchListNoDispose(UINT32 newLength);
+
+static void AddWatchBefore(UINT32 idx);
+static void DeleteWatchAt(UINT32 idx);
+static void DisposeWatch(WatchInfo * watch);
+static WatchInfo * GetUnusedWatch(void);
+
+static void AddCheatFromWatch(WatchInfo * watch);
+static void SetupCheatFromWatchAsWatch(CheatEntry * entry, WatchInfo * watch);
+
+/********** SEARCH LIST **********/
+static void ResizeSearchList(UINT32 newLength);
+static void ResizeSearchListNoDispose(UINT32 newLength);
+
+static void AddSearchBefore(UINT32 idx);
+static void DeleteSearchAt(UINT32 idx);
+
+static void InitSearch(SearchInfo * info);
+
+static void DisposeSearchRegions(SearchInfo * info);
+static void DisposeSearch(UINT32 idx);
+static SearchInfo * GetCurrentSearch(void);
+
+static void FillBufferFromRegion(SearchRegion * region, UINT8 * buf);
+static UINT32 ReadRegionData(SearchRegion * region, UINT32 offset, UINT8 size, UINT8 swap);
+
+static void BackupSearch(SearchInfo * info);
+static void RestoreSearchBackup(SearchInfo * info);
+static void BackupRegion(SearchRegion * region);
+static void RestoreRegionBackup(SearchRegion * region);
+static void SetSearchRegionDefaultName(SearchRegion * region);
+static void AllocateSearchRegions(SearchInfo * info);
+static void BuildSearchRegions(SearchInfo * info);
+
+/********** CODE LOADER **********/
+static int ConvertOldCode(int code, int cpu, int * data, int * extendData);
+static void HandleLocalCommandCheat(UINT32 type, UINT32 address, UINT32 data, UINT32 extendData, char * name, char * description);
+
+static void LoadCheatFile(char * fileName);
+static void LoadCheatDatabase(void);
+
+static void DisposeCheatDatabase(void);
+static void ReloadCheatDatabase(void);
+
+static void SaveCheat(CheatEntry * entry, int selection, int saveCode);
+static void DoAutoSaveCheats(void);
+
+/********** CODE ADDITION **********/
+static void AddCheatFromResult(SearchInfo * search, SearchRegion * region, UINT32 address);
+static void AddCheatFromFirstResult(SearchInfo * search);
+static void AddWatchFromResult(SearchInfo * search, SearchRegion * region, UINT32 address);
+
+/********** SEARCH **********/
+static UINT32 SearchSignExtend(SearchInfo * search, UINT32 value);
+static UINT32 ReadSearchOperand(UINT8 type, SearchInfo * search, SearchRegion * region, UINT32 address);
+static UINT32 ReadSearchOperandBit(UINT8 type, SearchInfo * search, SearchRegion * region, UINT32 address);
+static UINT8 DoSearchComparison(SearchInfo * search, UINT32 lhs, UINT32 rhs);
+static UINT32 DoSearchComparisonBit(SearchInfo * search, UINT32 lhs, UINT32 rhs);
+//static UINT8 IsRegionOffsetValid(SearchInfo * search, SearchRegion * region, UINT32 offset);
+
+#define IsRegionOffsetValid IsRegionOffsetValidBit
+
+static UINT8 IsRegionOffsetValidBit(SearchInfo * search, SearchRegion * region, UINT32 offset);
+static void InvalidateRegionOffset(SearchInfo * search, SearchRegion * region, UINT32 offset);
+static void InvalidateRegionOffsetBit(SearchInfo * search, SearchRegion * region, UINT32 offset, UINT32 invalidate);
+static void InvalidateEntireRegion(SearchInfo * search, SearchRegion * region);
+
+static void InitializeNewSearch(SearchInfo * search);
+static void UpdateSearch(SearchInfo * search);
+
+static void DoSearch(SearchInfo * search);
+
+/********** MEMORY ACCESSORS **********/
+static UINT8 ** LookupHandlerMemory(UINT8 cpu, UINT32 address, UINT32 * outRelativeAddress);
+
+static UINT32 DoCPURead(UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap);
+static UINT32 DoMemoryRead(UINT8 * buf, UINT32 address, UINT8 bytes, UINT8 swap, CPUInfo * info);
+static void DoCPUWrite(UINT32 data, UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap);
+static void DoMemoryWrite(UINT32 data, UINT8 * buf, UINT32 address, UINT8 bytes, UINT8 swap, CPUInfo * info);
+
+/********** CPU **********/
+static UINT8 CPUNeedsSwap(UINT8 cpu);
+static UINT8 RegionNeedsSwap(UINT8 region);
+
+static CPUInfo * GetCPUInfo(UINT8 cpu);
+static CPUInfo * GetRegionCPUInfo(UINT8 region);
+
+static UINT32 SwapAddress(UINT32 address, UINT8 dataSize, CPUInfo * info);
+
+static UINT32 ReadData(CheatAction * action);
+static void WriteData(CheatAction * action, UINT32 data);
+
+/********** WATCH **********/
+static void WatchCheatEntry(CheatEntry * entry, UINT8 associate);
+static void AddActionWatch(CheatAction * action, CheatEntry * entry);
+static void RemoveAssociatedWatches(CheatEntry * entry);
+
+static void ResetAction(CheatAction * action);
+static void ActivateCheat(CheatEntry * entry);
+static void DeactivateCheat(CheatEntry * entry);
+static void TempDeactivateCheat(CheatEntry * entry);
+
+static void cheat_periodicOperation(CheatAction * action);
+static void cheat_periodicAction(CheatAction * action);
+static void cheat_periodicEntry(CheatEntry * entry);
+
+static void UpdateAllCheatInfo(void);
+static void UpdateCheatInfo(CheatEntry * entry, UINT8 isLoadTime);
+
+static int IsAddressInRange(CheatAction * action, UINT32 length);
+
+static void BuildCPUInfoList(void);
+
+/*--------------------------------------------------------------
+ special key handler - check pressing shift, ctrl or alt key
+--------------------------------------------------------------*/
+
+static int ShiftKeyPressed(void)
+{
+ return (input_code_pressed(KEYCODE_LSHIFT) || input_code_pressed(KEYCODE_RSHIFT));
+}
+
+static int ControlKeyPressed(void)
+{
+ return (input_code_pressed(KEYCODE_LCONTROL) || input_code_pressed(KEYCODE_RCONTROL));
+}
+
+static int AltKeyPressed(void)
+{
+ return (input_code_pressed(KEYCODE_LALT) || input_code_pressed(KEYCODE_RALT));
+}
+
+/*---------------------------------------------------------------------------------------------------------------------
+ ReadKeyAsync - dirty hack until osd_readkey_unicode is supported in MAMEW re-implementation of osd_readkey_unicode
+---------------------------------------------------------------------------------------------------------------------*/
+
+#if 1
+
+#if OSD_READKEY_KLUDGE
+
+static int ReadKeyAsync(int flush)
+{
+ int code;
+
+ if(flush) // check key input
+ {
+ while(input_code_poll_switches(TRUE) != INPUT_CODE_INVALID) ;
+
+ return 0;
+ }
+
+ while(1) // check pressed key
+ {
+ code = input_code_poll_switches(FALSE);
+
+ if(code == INPUT_CODE_INVALID)
+ {
+ return 0;
+ }
+ else if((code >= KEYCODE_A) && (code <= KEYCODE_Z))
+ {
+ if(ShiftKeyPressed())
+ {
+ return 'A' + (code - KEYCODE_A);
+ }
+ else
+ {
+ return 'a' + (code - KEYCODE_A);
+ }
+ }
+ else if((code >= KEYCODE_0) && (code <= KEYCODE_9))
+ {
+ if(ShiftKeyPressed())
+ {
+ return ")!@#$%^&*("[code - KEYCODE_0];
+ }
+ else
+ {
+ return '0' + (code - KEYCODE_0);
+ }
+ }
+ else if((code >= KEYCODE_0_PAD) && (code <= KEYCODE_9_PAD))
+ {
+ return '0' + (code - KEYCODE_0_PAD);
+ }
+ else if(code == KEYCODE_TILDE)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '~';
+ }
+ else
+ {
+ return '`';
+ }
+ }
+ else if(code == KEYCODE_MINUS)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '_';
+ }
+ else
+ {
+ return '-';
+ }
+ }
+ else if(code == KEYCODE_EQUALS)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '+';
+ }
+ else
+ {
+ return '=';
+ }
+ }
+ else if(code == KEYCODE_BACKSPACE)
+ {
+ return 0x08;
+ }
+ else if(code == KEYCODE_OPENBRACE)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '{';
+ }
+ else
+ {
+ return '[';
+ }
+ }
+ else if(code == KEYCODE_CLOSEBRACE)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '}';
+ }
+ else
+ {
+ return ']';
+ }
+ }
+ else if(code == KEYCODE_COLON)
+ {
+ if(ShiftKeyPressed())
+ {
+ return ':';
+ }
+ else
+ {
+ return ';';
+ }
+ }
+ else if(code == KEYCODE_QUOTE)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '\"';
+ }
+ else
+ {
+ return '\'';
+ }
+ }
+ else if(code == KEYCODE_BACKSLASH)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '|';
+ }
+ else
+ {
+ return '\\';
+ }
+ }
+ else if(code == KEYCODE_COMMA)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '<';
+ }
+ else
+ {
+ return ',';
+ }
+ }
+ else if(code == KEYCODE_STOP)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '>';
+ }
+ else
+ {
+ return '.';
+ }
+ }
+ else if(code == KEYCODE_SLASH)
+ {
+ if(ShiftKeyPressed())
+ {
+ return '?';
+ }
+ else
+ {
+ return '/';
+ }
+ }
+ else if(code == KEYCODE_SLASH_PAD)
+ {
+ return '/';
+ }
+ else if(code == KEYCODE_ASTERISK)
+ {
+ return '*';
+ }
+ else if(code == KEYCODE_MINUS_PAD)
+ {
+ return '-';
+ }
+ else if(code == KEYCODE_PLUS_PAD)
+ {
+ return '+';
+ }
+ else if(code == KEYCODE_SPACE)
+ {
+ return ' ';
+ }
+ }
+}
+
+#define osd_readkey_unicode ReadKeyAsync
+
+#endif
+
+#endif
+
+/*-------------------------------------
+ old_style_menu - export menu items
+-------------------------------------*/
+
+static void old_style_menu(const char **items, const char **subitems, char *flag, int selected, int arrowize_subitem)
+{
+ static ui_menu_item item_list[1000];
+ int menu_items;
+
+ for (menu_items = 0; items[menu_items]; menu_items++)
+ {
+ item_list[menu_items].text = items[menu_items];
+ item_list[menu_items].subtext = subitems ? subitems[menu_items] : NULL;
+ item_list[menu_items].flags = 0;
+ if (flag && flag[menu_items])
+ item_list[menu_items].flags |= MENU_FLAG_INVERT;
+ if (menu_items == selected)
+ {
+ if (arrowize_subitem & 1)
+ item_list[menu_items].flags |= MENU_FLAG_LEFT_ARROW;
+ if (arrowize_subitem & 2)
+ item_list[menu_items].flags |= MENU_FLAG_RIGHT_ARROW;
+ }
+ }
+ ui_menu_draw(item_list, menu_items, selected, NULL);
+}
+
+/*-------------------------------------------------
+ UIPressedRepoeatThrottle - key repeat handling
+-------------------------------------------------*/
+
+static int UIPressedRepeatThrottle(int code, int baseSpeed)
+{
+ static int lastCode = -1;
+ static int lastSpeed = -1;
+ static int incrementTimer = 0;
+ int pressed = 0;
+
+ const int kDelayRampTimer = 10;
+
+ if(input_port_type_pressed(code, 0))
+ {
+ if(lastCode != code) // different key pressed
+ {
+ lastCode = code;
+ lastSpeed = baseSpeed;
+ incrementTimer = kDelayRampTimer * lastSpeed;
+ }
+ else // same key pressed
+ {
+ incrementTimer--;
+
+ if(incrementTimer <= 0)
+ {
+ incrementTimer = kDelayRampTimer * lastSpeed;
+
+ lastSpeed /= 2;
+
+ if(lastSpeed < 1)
+ lastSpeed = 1;
+
+ pressed = 1;
+ }
+ }
+ }
+ else
+ {
+ if(lastCode == code)
+ lastCode = -1;
+ }
+
+ return input_ui_pressed_repeat(code, lastSpeed);
+}
+
+/*---------------------------------
+ ReadHexInput - check hex input
+---------------------------------*/
+
+static int ReadHexInput(void)
+{
+ int i;
+
+ for(i = 0; i < 10; i++)
+ {
+ if(input_code_pressed_once(KEYCODE_0 + i))
+ return i;
+ }
+
+ for(i = 0; i < 10; i++)
+ {
+ if(input_code_pressed_once(KEYCODE_0_PAD + i))
+ return i;
+ }
+
+ for(i = 0; i < 6; i++)
+ {
+ if(input_code_pressed_once(KEYCODE_A + i))
+ return i + 10;
+ }
+
+ return -1;
+}
+
+/*-----------------------------------------------------------------
+ DoDynamicEditTextField - edit text field with direct key input
+-----------------------------------------------------------------*/
+
+static char * DoDynamicEditTextField(char * buf)
+{
+ char code = osd_readkey_unicode(0) & 0xFF;
+
+ if(code == 0x08)
+ {
+ /* ----- backspace ----- */
+ if(buf)
+ {
+ size_t length = strlen(buf);
+
+ if(length > 0)
+ {
+ buf[length - 1] = 0;
+
+ if(length > 1)
+ buf = realloc(buf, length);
+ else
+ {
+ free(buf);
+
+ buf = NULL;
+ }
+ }
+ }
+ }
+ else
+ {
+ if(isprint(code))
+ {
+ if(buf)
+ {
+ size_t length = strlen(buf);
+
+ buf = realloc(buf, length + 2);
+
+ buf[length] = code;
+ buf[length + 1] = 0;
+ }
+ else
+ {
+ buf = malloc(2);
+
+ buf[0] = code;
+ buf[1] = 0;
+ }
+ }
+ }
+
+ return buf;
+}
+
+/*------------------------
+ DoStaticEditTextField
+------------------------*/
+
+static void DoStaticEditTextField(char * buf, int size)
+{
+ char code = osd_readkey_unicode(0) & 0xFF;
+ size_t length;
+
+ if(!buf)
+ return;
+
+ length = strlen(buf);
+
+ if(code == 0x08)
+ {
+ if(length > 0)
+ {
+ buf[length - 1] = 0;
+ }
+ }
+ else if(isprint(code))
+ {
+ if(length + 1 < size)
+ {
+ buf[length] = code;
+ buf[length + 1] = 0;
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ DoEditHexField - edit hex field with direct key input (unsigned)
+------------------------------------------------------------------*/
+
+static UINT32 DoEditHexField(UINT32 data)
+{
+ INT8 key;
+
+ if(input_code_pressed_once(KEYCODE_BACKSPACE))
+ {
+ /* ----- backspace ----- */
+ data >>= 4;
+
+ return data;
+ }
+ else
+ {
+ if(input_ui_pressed(IPT_UI_CLEAR))
+ {
+ data = 0;
+
+ return data;
+ }
+ }
+
+ key = ReadHexInput();
+
+ if(key != -1)
+ {
+ data <<= 4;
+ data |= key;
+ }
+
+ return data;
+}
+
+/*-----------------------------------------------------------------------
+ DoEditHexFieldSigned - edit hex field with direct key input (signed)
+-----------------------------------------------------------------------*/
+
+static UINT32 DoEditHexFieldSigned(UINT32 data, UINT32 mask)
+{
+ INT8 key;
+ UINT32 isNegative = data & mask;
+
+ if(isNegative)
+ data |= mask;
+
+ key = ReadHexInput();
+
+ if(key != -1)
+ {
+ if(isNegative)
+ data = (~data) + 1;
+
+ data <<= 4;
+ data |= key;
+
+ if(isNegative)
+ data = (~data) + 1;
+ }
+ else
+ {
+ if(input_code_pressed_once(KEYCODE_MINUS))
+ data = (~data) + 1;
+ }
+
+ return data;
+}
+
+/*--------------------------------------------------------
+ DoEditDecField - edit dec field with direct key input
+--------------------------------------------------------*/
+
+static INT32 DoEditDecField(INT32 data, INT32 min, INT32 max)
+{
+ char code = osd_readkey_unicode(0) & 0xFF;
+
+ if((code >= '0') && (code <= '9'))
+ {
+ data *= 10;
+ data += (code - '0');
+ }
+ else
+ {
+ if(code == '-')
+ data = -data;
+ else
+ {
+ /* ----- backspace ----- */
+ if(code == 0x08)
+ data /= 10;
+ }
+ }
+
+ /* ----- adjust value ----- */
+ if(data < min)
+ data = min;
+ if(data > max)
+ data = max;
+
+ return data;
+}
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*---------------------------------------
+ cheat_init - initialize cheat system
+---------------------------------------*/
+
+void cheat_init(running_machine *machine)
+{
+ /* ----- initialize lists ----- */
+ cheatList = NULL;
+ cheatListLength = 0;
+
+ watchList = NULL;
+ watchListLength = 0;
+
+ searchList = NULL;
+ searchListLength = 0;
+
+#ifdef MESS
+ InitMessCheats();
+#endif
+
+ /* ----- initialize flags ----- */
+ currentSearchIdx = 0;
+ foundCheatDatabase = 0;
+ cheatsDisabled = 0;
+ watchesDisabled = 0;
+ cheatOptions = 2;
+
+ fullMenuPageHeight = floor(1.0f / ui_get_line_height()) - 1;
+
+ /* ----- initialize CPU info for cheat system ----- */
+ BuildCPUInfoList();
+
+ /* ----- load cheat database ----- */
+ LoadCheatDatabase();
+
+ ResizeSearchList(1);
+ ResizeWatchList(20);
+
+ /* ----- initialize search regions ----- */
+ BuildSearchRegions(GetCurrentSearch());
+ AllocateSearchRegions(GetCurrentSearch());
+
+ /* ----- initialize string table ----- */
+ InitStringTable();
+
+ periodic_timer = timer_alloc(cheat_periodic);
+ timer_adjust(periodic_timer, attotime_make(0, Machine->screen[0].refresh), 0, attotime_make(0, Machine->screen[0].refresh));
+
+ add_exit_callback(machine, cheat_exit);
+}
+
+/*---------------------------------
+ cheat_exit - free cheat system
+---------------------------------*/
+
+static void cheat_exit(running_machine *machine)
+{
+ int i;
+
+ /* ----- save all cheats automatically if needed ----- */
+ if(TEST_FIELD(cheatOptions, AutoSaveEnabled))
+ DoAutoSaveCheats();
+
+ /* ----- free database ----- */
+ DisposeCheatDatabase();
+
+ /* ----- free watch lists ----- */
+ if(watchList)
+ {
+ for(i = 0; i < watchListLength; i++)
+ DisposeWatch(&watchList[i]);
+
+ free(watchList);
+
+ watchList = NULL;
+ }
+
+ /* ----- free search lists ----- */
+ if(searchList)
+ {
+ for(i = 0; i < searchListLength; i++)
+ DisposeSearch(i);
+
+ free(searchList);
+
+ searchList = NULL;
+ }
+
+ /* ----- free string table ----- */
+ FreeStringTable();
+
+ free(menuItemInfo);
+ menuItemInfo = NULL;
+
+#ifdef MESS
+ StopMessCheats();
+#endif
+
+ /* ----- free flags ----- */
+ cheatListLength = 0;
+ watchListLength = 0;
+ searchListLength = 0;
+ currentSearchIdx = 0;
+// cheatEngineWasActive = 0;
+ foundCheatDatabase = 0;
+ cheatsDisabled = 0;
+ watchesDisabled = 0;
+ mainDatabaseName[0] = 0;
+ menuItemInfoLength = 0;
+ cheatOptions = 0;
+}
+
+/*-----------------------------------------------------
+ cheat_menu - management for the cheat general menu
+-----------------------------------------------------*/
+
+int cheat_menu(int selection)
+{
+ enum
+ {
+ kMenu_EnableDisable = 0,
+ kMenu_AddEdit,
+ kMenu_Search,
+ kMenu_ChooseWatch,
+ kMenu_ReloadDatabase,
+ kMenu_Options,
+ kMenu_Return,
+
+ kMenu_Max
+ };
+
+ ui_menu_item menu_item[kMenu_Max];
+
+ INT32 sel;
+ UINT8 total = 0;
+
+ static INT32 submenu_choice = 0;
+ static int firstEntry = 0;
+ static int lastPstn = 0;
+
+ /* ----- allocate memory for item list ----- */
+ memset(menu_item, 0, sizeof(menu_item));
+
+// cheatEngineWasActive = 1;
+
+ sel = lastPstn;
+
+ /********** SUB MENU **********/
+ if(submenu_choice)
+ {
+ switch(sel)
+ {
+ case kMenu_EnableDisable:
+ submenu_choice = EnableDisableCheatMenu(submenu_choice, firstEntry);
+ break;
+
+ case kMenu_AddEdit:
+ submenu_choice = AddEditCheatMenu(submenu_choice);
+ break;
+
+ case kMenu_Search:
+ switch(EXTRACT_FIELD(cheatOptions, SearchBox))
+ {
+ case kSearchBox_Minimum:
+ submenu_choice = DoSearchMenuMinimum(submenu_choice);
+ break;
+
+ case kSearchBox_Classic:
+ submenu_choice = DoSearchMenuClassic(submenu_choice);
+ break;
+
+ case kSearchBox_Advanced:
+ submenu_choice = DoSearchMenu(submenu_choice);
+ break;
+ }
+ break;
+
+ case kMenu_ChooseWatch:
+ submenu_choice = ChooseWatch(submenu_choice);
+ break;
+
+ case kMenu_Options:
+ submenu_choice = SelectOptions(submenu_choice);
+ break;
+ }
+
+ firstEntry = 0;
+
+ /* ----- quick menu switching ------ */
+ if(submenu_choice < 0)
+ {
+ switch(submenu_choice)
+ {
+ case -1:
+ lastPstn = kMenu_EnableDisable;
+ break;
+
+ case -2:
+ lastPstn = kMenu_AddEdit;
+ break;
+
+ case -3:
+ lastPstn = kMenu_Search;
+ break;
+
+ case -4:
+ lastPstn = kMenu_ChooseWatch;
+ break;
+
+ default:
+ ui_popup_time(1, "undefined menu switching : %x", submenu_choice);
+ }
+
+ submenu_choice = 1;
+ }
+
+ return sel + 1;
+ }
+
+ /********** MENU CONSTRUCION **********/
+ menu_item[total++].text = ui_getstring(UI_enablecheat); // Enable/Disable a Cheat
+
+ menu_item[total++].text = ui_getstring(UI_addeditcheat); // Add/Edit a Cheat
+
+ switch(EXTRACT_FIELD(cheatOptions, SearchBox)) // Search a Cheat
+ {
+ case kSearchBox_Minimum:
+ menu_item[total++].text = "Search a Cheat (Minimum Mode)";
+ break;
+
+ case kSearchBox_Classic:
+ menu_item[total++].text = "Search a Cheat (Classic Mode)";
+ break;
+
+ case kSearchBox_Advanced:
+ menu_item[total++].text = "Search a Cheat (Advanced Mode)";
+ break;
+ }
+
+ menu_item[total++].text = ui_getstring(UI_memorywatch); // Configure Watchpoints
+
+ menu_item[total++].text = ui_getstring(UI_reloaddatabase); // Reload Cheat Database
+
+ menu_item[total++].text = ui_getstring(UI_options); // Options
+
+ menu_item[total++].text = ui_getstring(UI_returntomain); // return to the MAME general menu
+
+ menu_item[total].text = NULL; // terminate array
+
+ /* ----- adjust cursor postion ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel > (total - 1))
+ sel = total - 1;
+
+ /* ----- print it ----- */
+ ui_menu_draw(menu_item, total, sel, NULL);
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ if(sel < (total - 1))
+ sel++;
+ else
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ if(sel > 0)
+ sel--;
+ else
+ sel = total - 1;
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ switch(sel)
+ {
+ case kMenu_Return:
+ submenu_choice = 0;
+ sel = -1;
+ lastPstn = 0; // if cursor is now on the return item, adjust cursor keeper
+ break;
+
+ case kMenu_ReloadDatabase:
+ ReloadCheatDatabase();
+ break;
+
+ default:
+ firstEntry = 1;
+ submenu_choice = 1;
+ break;
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_RELOAD_CHEAT))
+ ReloadCheatDatabase();
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ {
+ if(sel == kMenu_Return)
+ lastPstn = 0; // if cursor is now on the return item, adjust cursor keeper
+
+ sel = -1;
+ }
+
+ /* ----- keep current cursor position ----- */
+ if(sel >= 0)
+ lastPstn = sel;
+
+ return sel + 1;
+}
+
+/*----------
+ DoShift
+----------*/
+
+static UINT32 DoShift(UINT32 input, INT8 shift)
+{
+ if(shift > 0)
+ return input >> shift;
+ else
+ return input << -shift;
+}
+
+/*----------------------------------------
+ BCDToDecimal - convert a value to hex
+----------------------------------------*/
+
+static UINT32 BCDToDecimal(UINT32 value)
+{
+ UINT32 accumulator = 0;
+ UINT32 multiplier = 1;
+ int i;
+
+ for(i = 0; i < 8; i++)
+ {
+ accumulator += (value & 0xF) * multiplier;
+
+ multiplier *= 10;
+ value >>= 4;
+ }
+
+ return accumulator;
+}
+
+/*----------------------------------------
+ DecimalToBCD - convert a value to dec
+----------------------------------------*/
+
+static UINT32 DecimalToBCD(UINT32 value)
+{
+ UINT32 accumulator = 0;
+ UINT32 divisor = 10;
+ int i;
+
+ for(i = 0; i < 8; i++)
+ {
+ UINT32 temp;
+
+ temp = value % divisor;
+ value -= temp;
+ temp /= divisor / 10;
+
+ accumulator += temp << (i * 4);
+
+ divisor *= 10;
+ }
+
+ return accumulator;
+}
+
+/*----------------------
+ RebuildStringTables
+----------------------*/
+
+static void RebuildStringTables(void)
+{
+ UINT32 storageNeeded, i;
+ char * traverse;
+
+ storageNeeded = (menuStrings.mainStringLength + menuStrings.subStringLength) * menuStrings.numStrings;
+
+ menuStrings.mainList = (const char **) realloc((char *) menuStrings.mainList, sizeof(char *) * menuStrings.length);
+ menuStrings.subList = (const char **) realloc((char *) menuStrings.subList, sizeof(char *) * menuStrings.length);
+ menuStrings.flagList = realloc( menuStrings.flagList, sizeof(char) * menuStrings.length);
+ menuStrings.mainStrings = realloc( menuStrings.mainStrings, sizeof(char *) * menuStrings.numStrings);
+ menuStrings.subStrings = realloc( menuStrings.subStrings, sizeof(char *) * menuStrings.numStrings);
+ menuStrings.buf = realloc( menuStrings.buf, sizeof(char) * storageNeeded);
+
+ if( (!menuStrings.mainList && menuStrings.length) ||
+ (!menuStrings.subList && menuStrings.length) ||
+ (!menuStrings.flagList && menuStrings.length) ||
+ (!menuStrings.mainStrings && menuStrings.numStrings) ||
+ (!menuStrings.subStrings && menuStrings.numStrings) ||
+ (!menuStrings.buf && storageNeeded))
+ {
+ fatalerror( "cheat: memory allocation error\n"
+ " length = %.8X\n"
+ " numStrings = %.8X\n"
+ " mainStringLength = %.8X\n"
+ " subStringLength = %.8X\n"
+ "%p %p %p %p %p %p\n",
+ menuStrings.length,
+ menuStrings.numStrings,
+ menuStrings.mainStringLength,
+ menuStrings.subStringLength,
+
+ menuStrings.mainList,
+ menuStrings.subList,
+ menuStrings.flagList,
+ menuStrings.mainStrings,
+ menuStrings.subStrings,
+ menuStrings.buf);
+ }
+
+ traverse = menuStrings.buf;
+
+ for(i = 0; i < menuStrings.numStrings; i++)
+ {
+ menuStrings.mainStrings[i] = traverse;
+ traverse += menuStrings.mainStringLength;
+
+ menuStrings.subStrings[i] = traverse;
+ traverse += menuStrings.subStringLength;
+ }
+}
+
+/*-----------------------------------------------------------
+ RequestStrings - check list length and rebuild if needed
+-----------------------------------------------------------*/
+
+static void RequestStrings(UINT32 length, UINT32 numStrings, UINT32 mainStringLength, UINT32 subStringLength)
+{
+ UINT8 changed = 0;
+
+ if(menuStrings.length < length)
+ {
+ menuStrings.length = length;
+
+ changed = 1;
+ }
+
+ if(menuStrings.numStrings < numStrings)
+ {
+ menuStrings.numStrings = numStrings;
+
+ changed = 1;
+ }
+
+ if(menuStrings.mainStringLength < mainStringLength)
+ {
+ menuStrings.mainStringLength = mainStringLength;
+
+ changed = 1;
+ }
+
+ if(menuStrings.subStringLength < subStringLength)
+ {
+ menuStrings.subStringLength = subStringLength;
+
+ changed = 1;
+ }
+
+ if(changed)
+ RebuildStringTables();
+}
+
+/*------------------
+ InitStringTable
+------------------*/
+
+static void InitStringTable(void)
+{
+ memset(&menuStrings, 0, sizeof(MenuStringList));
+}
+
+/*------------------
+ FreeStringTable
+------------------*/
+
+static void FreeStringTable(void)
+{
+ free((char *)menuStrings.mainList);
+ free((char *)menuStrings.subList);
+ free(menuStrings.flagList);
+ free(menuStrings.mainStrings);
+ free(menuStrings.subStrings);
+ free(menuStrings.buf);
+
+ memset(&menuStrings, 0, sizeof(MenuStringList));
+}
+
+/*---------------------------------------------------------------------------
+ CreateStringCopy - copy stirng. It is only called on LoadCheatFile() now
+---------------------------------------------------------------------------*/
+
+static char * CreateStringCopy(char * buf)
+{
+ char * temp = NULL;
+
+ if(buf)
+ {
+ size_t length = strlen(buf) + 1;
+
+ temp = malloc(length);
+
+ if(temp)
+ memcpy(temp, buf, length);
+ }
+
+ return temp;
+}
+
+/*------------------------------------------------------------
+ UserSelectValueMenu - management for value-selection menu
+------------------------------------------------------------*/
+
+static INT32 UserSelectValueMenu(int selection, CheatEntry * entry)
+{
+ char buf[2048];
+ int sel;
+ CheatAction * action;
+ static INT32 value = -1;
+ static int firstTime = 1;
+ int delta = 0;
+ int displayValue;
+ int keyValue;
+ int forceUpdate = 0;
+
+ sel = selection - 1;
+
+ action = &entry->actionList[0];
+
+ /* ----- if we're just entering, save the value ----- */
+ if(firstTime)
+ {
+ UINT32 min = EXTRACT_FIELD(action->type, UserSelectMinimum);
+ UINT32 max = action->originalDataField + min;
+
+ value = ReadData(action);
+
+ /* ----- and check for valid BCD values ----- */
+ if(TEST_FIELD(action->type, UserSelectBCD))
+ {
+ value = BCDToDecimal(value);
+ value = DecimalToBCD(value);
+ }
+
+ if(value < min)
+ value = max;
+ if(value > max)
+ value = min;
+
+ action->data = value;
+ firstTime = 0;
+ }
+
+ displayValue = value;
+
+ /* ----- if the minimum display value is one, add one to the display value ----- */
+ if(TEST_FIELD(action->type, UserSelectMinimumDisplay))
+ {
+ if(TEST_FIELD(action->type, UserSelectBCD))
+ displayValue = BCDToDecimal(displayValue); // bcd -> dec
+
+ displayValue++;
+
+ if(TEST_FIELD(action->type, UserSelectBCD))
+ displayValue = DecimalToBCD(displayValue); // dec -> bcd
+ }
+
+ /* ----- print it ----- */
+ if(TEST_FIELD(action->type, UserSelectBCD))
+ sprintf(buf, "\t%s\n\t%.2X\n", ui_getstring(UI_search_select_value), displayValue);
+ else
+ sprintf(buf, "\t%s\n\t%.2X (%d)\n", ui_getstring(UI_search_select_value), displayValue, displayValue);
+
+ /* ----- create fake menu strings ----- */
+ strcat(buf, "\t");
+ strcat(buf, ui_getstring(UI_lefthilight));
+ strcat(buf, " ");
+ strcat(buf, ui_getstring(UI_OK));
+ strcat(buf, " ");
+ strcat(buf, ui_getstring(UI_righthilight));
+
+ /* ----- print it ----- */
+ ui_draw_message_window(buf);
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalFastKeyRepeatRate))
+ delta = -1;
+
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalFastKeyRepeatRate))
+ delta = 1;
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ /* ### redundant?? probably can be removed ### */
+ if(!firstTime)
+ {
+ int i;
+
+ /* ----- copy data field if copy previous value ----- */
+ for(i = 0; i < entry->actionListLength; i++)
+ {
+ CheatAction * traverse = &entry->actionList[i];
+
+ INT32 copyValue = value;
+
+ if(TEST_FIELD(traverse->type, LinkEnable) && TEST_FIELD(traverse->type, LinkCopyPreviousValue))
+ {
+ INT32 newData = traverse->originalDataField;
+
+ if(TEST_FIELD(traverse->type, UserSelectBCD))
+ {
+ copyValue = BCDToDecimal(value);
+ copyValue = DecimalToBCD(value);
+
+ newData = BCDToDecimal(newData);
+ newData = DecimalToBCD(newData);
+ }
+
+ copyValue += newData;
+
+ if(TEST_FIELD(traverse->type, UserSelectBCD))
+ {
+ copyValue = BCDToDecimal(copyValue);
+ copyValue = DecimalToBCD(copyValue);
+ }
+ }
+
+ if(!i || TEST_FIELD(traverse->type, LinkCopyPreviousValue))
+ traverse->data = copyValue;
+ }
+
+ ActivateCheat(entry);
+ }
+
+ firstTime = 1;
+ sel = -1;
+ }
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ {
+ firstTime = 1;
+ sel = -1;
+ }
+
+ /* ----- get other key inputs ----- */
+ keyValue = ReadHexInput();
+
+ /* ----- BCD check for input key ----- */
+ if((keyValue != -1) && TEST_FIELD(action->type, UserSelectBCD) && ((keyValue < 0 ) || (keyValue > 9)))
+ keyValue = -1;
+
+ /* ----- if we got a key ----- */
+ if(keyValue != -1)
+ {
+ /* ----- add it ----- */
+ value <<= 4;
+
+ switch(EXTRACT_FIELD(action->type, BytesUsed))
+ {
+ case 0: // 8 bit
+ value &= 0xF0;
+ break;
+ case 1: // 16 bit
+ value &= 0xFFF0;
+ break;
+ case 2: // 24 bit
+ value &= 0xFFFFF0;
+ break;
+ case 3: // 32 bit
+ value &= 0xFFFFFFF0;
+ break;
+ }
+
+ value |= keyValue & 0x0F;
+
+ delta = 0;
+ forceUpdate = 1;
+ }
+
+ /* ----- wrap-around with BCD stuff. ### this is a really bad way to do this ----- */
+ if(delta || forceUpdate)
+ {
+ INT32 min = EXTRACT_FIELD(action->type, UserSelectMinimum);
+ INT32 max = action->originalDataField + min;
+
+ if(TEST_FIELD(action->type, UserSelectBCD))
+ value = BCDToDecimal(value);
+
+ value += delta;
+
+ if(TEST_FIELD(action->type, UserSelectBCD))
+ value = DecimalToBCD(value);
+
+ if(value < min)
+ value = max;
+ if(value > max)
+ value = min;
+ }
+
+ return sel + 1;
+}
+
+/*-------------------------------------------------
+ CommentMenu - management comment for code menu
+-------------------------------------------------*/
+
+static INT32 CommentMenu(int selection, CheatEntry * entry)
+{
+ char buf[2048];
+ int sel;
+ const char * comment;
+
+ if(!entry)
+ return 0;
+
+ sel = selection - 1;
+
+ /********** MENU CONSTRUCTION **********/
+ if(entry->comment && entry->comment[0])
+ comment = entry->comment;
+ else
+ comment = "(none)";
+
+ sprintf(buf, "%s\n\t%s %s %s", comment, ui_getstring(UI_lefthilight), ui_getstring(UI_OK), ui_getstring(UI_righthilight));
+
+ /* ----- print it ----- */
+ ui_draw_message_window(buf);
+
+ /********** KEY HANDLING **********/
+ if(input_ui_pressed(IPT_UI_SELECT) || input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ return sel + 1;
+}
+
+/*--------------------------------------------------------------
+ EnableDisableCheatMenu - management for Enable/Disable menu
+--------------------------------------------------------------*/
+
+static int EnableDisableCheatMenu(int selection, int firstTime)
+{
+ INT32 sel;
+ static INT32 submenu_choice = 0;
+ static INT32 submenu_id = 0; // 0 = none, 1 = comment, 2 = value-selection, 3 = editCheat
+ const char ** menu_item;
+ const char ** menu_subitem;
+ char * flagBuf;
+ INT32 i;
+ INT32 total = 0;
+
+ CheatEntry * entry;
+
+ RequestStrings(cheatListLength + 5, 0, 0, 0);
+
+ menu_item = menuStrings.mainList;
+ menu_subitem = menuStrings.subList;
+ flagBuf = menuStrings.flagList;
+
+ sel = selection - 1;
+
+ /********** SUB MENU **********/
+ if(submenu_choice)
+ {
+ switch(submenu_id)
+ {
+ case 1:
+ submenu_choice = CommentMenu(submenu_choice, &cheatList[sel]);
+ break;
+
+ case 2:
+ submenu_choice = UserSelectValueMenu(submenu_choice, &cheatList[sel]);
+ break;
+
+ case 3:
+ submenu_choice = EditCheatMenu(&cheatList[sel], sel, submenu_choice);
+ break;
+
+ default:
+ submenu_choice = 0;
+ }
+
+ /* ----- meaningless ? because no longer return with sel = -1 (pressed UI_CONFIG in submenu) ----- */
+// if(submenu_choice == -1)
+// {
+// submenu_choice = 0;
+// sel = -2;
+// }
+
+ return sel + 1;
+ }
+
+ /********** MENU CONSTRUCTION **********/
+ for(i = 0; i < cheatListLength; i++)
+ {
+ CheatEntry * traverse = &cheatList[i];
+
+ /* ----- get code title ----- */
+ if(traverse->name)
+ menu_item[total] = traverse->name;
+ else
+ menu_item[total] = "null name";
+
+ menu_subitem[total] = NULL;
+
+ /* ----- get subitem ----- */
+ if(traverse->flags & kCheatFlag_Select) // label-selection gets sub-lebel name or "OFF"
+ {
+ /* ----- no "OFF" item if one shot ----- */
+ if((traverse->flags & kCheatFlag_OneShot) && !traverse->selection)
+ traverse->selection = 1; // adjust to 1st linked-code
+
+ /* ----- set sub-label name or "OFF" to subitem ----- */
+ if(traverse->selection && (traverse->selection < traverse->actionListLength))
+ menu_subitem[total] = traverse->actionList[traverse->selection].optionalName;
+ else
+ menu_subitem[total] = ui_getstring(UI_off);
+ }
+ else // others get "ON" or "OFF"
+ {
+ /* ----- add subitems for all cheats that are not comments ----- */
+ if(!(traverse->flags & kCheatFlag_Null))
+ {
+ if(traverse->flags & kCheatFlag_OneShot)
+ menu_subitem[total] = ui_getstring(UI_set);
+ else
+ {
+ if(traverse->flags & kCheatFlag_Active)
+ menu_subitem[total] = ui_getstring(UI_on);
+ else
+ menu_subitem[total] = ui_getstring(UI_off);
+ }
+ }
+ }
+
+ /* ----- get comment flag ----- */
+ if(traverse->comment && traverse->comment[0])
+ flagBuf[total++] = 1;
+ else
+ flagBuf[total++] = 0;
+ }
+
+ /* ----- if no code, set special message ----- */
+ if(cheatListLength == 0)
+ {
+ if(foundCheatDatabase) // the database found but no code
+ {
+ menu_item[total] = "there are no cheats for this game";
+ menu_subitem[total] = NULL;
+ flagBuf[total++] = 0;
+ }
+ else // the database itself not found
+ {
+ menu_item[total] = "cheat database not found";
+ menu_subitem[total] = NULL;
+ flagBuf[total++] = 0;
+
+ menu_item[total] = "unzip it and place it in the MAME directory";
+ menu_subitem[total] = NULL;
+ flagBuf[total++] = 0;
+ }
+ }
+
+ /* ----- set return item ----- */
+ menu_item[total] = ui_getstring(UI_returntoprior);
+ menu_subitem[total] = NULL;
+ flagBuf[total++] = 0;
+
+ menu_item[total] = 0; // terminate array
+ menu_subitem[total] = 0;
+ flagBuf[total] = 0;
+
+ /* ----- adjust cursor position ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel > (total - 1))
+ sel = total - 1;
+
+ /* ----- if cursor is on comment code, skip it ----- */
+ if(cheatListLength && firstTime)
+ {
+ while((sel < total - 1) && (cheatList[sel].flags & kCheatFlag_Null))
+ sel++;
+ }
+
+ /* ----- draw it ----- */
+ old_style_menu(menu_item, menu_subitem, flagBuf, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+
+ if(cheatListLength)
+ {
+ /* ----- if cursor is on comment code, skip it ----- */
+ for(i = 0; (i < fullMenuPageHeight / 2) && (sel < total - 1) && (cheatList[sel].flags & kCheatFlag_Null); i++)
+ sel++;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+ else
+ {
+ if(cheatListLength)
+ {
+ /* ----- if cursor is on comment code, skip it ----- */
+ for(i = 0; (i < fullMenuPageHeight / 2) && (sel != total - 1) && (cheatList[sel].flags & kCheatFlag_Null); i++)
+ {
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+ }
+ }
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+ }
+
+ if((sel >= 0) && (sel < cheatListLength))
+ entry = &cheatList[sel];
+ else
+ entry = NULL;
+
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate))
+ {
+ if((sel < (total - 1)) && entry)
+ {
+ if(entry->flags & kCheatFlag_Select) // label-selection
+ {
+ /* ----- move selection to unLinkExtension code or last linked-code ----- */
+ do{
+ entry->selection--;
+
+ if(entry->flags & kCheatFlag_OneShot)
+ {
+ if(entry->selection <= 0)
+ entry->selection = entry->actionListLength - 1; // first -> last
+
+ /* ----- no action when press arrow key ----- */
+ entry->flags &= ~kCheatFlag_DoOneShot;
+ }
+ else
+ {
+ if(entry->selection < 0)
+ entry->selection = entry->actionListLength - 1; // OFF -> last
+
+ if(entry->selection == 0)
+ DeactivateCheat(entry); // OFF
+ else
+ {
+ if(!TEST_FIELD(entry->actionList[entry->selection].type, LinkExtension))
+ ActivateCheat(entry); // ON
+ }
+ }
+ }while(entry->selection && TEST_FIELD(entry->actionList[entry->selection].type, LinkExtension));
+ }
+ else // others
+ {
+ if(!(entry->flags & kCheatFlag_Null) && !(entry->flags & kCheatFlag_OneShot))
+ {
+ int active = entry->flags & kCheatFlag_Active;
+
+ active ^= 0x01;
+
+ /* ----- get the user's selected value if needed ----- */
+ if((entry->flags & kCheatFlag_UserSelect) && active)
+ {
+ submenu_id = 2;
+ submenu_choice = 1;
+ }
+ else
+ {
+ if(active)
+ ActivateCheat(entry); // ON
+ else
+ DeactivateCheat(entry); // OFF
+ }
+ }
+ }
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalSlowKeyRepeatRate))
+ {
+ if((sel < (total - 1)) && entry)
+ {
+ if(entry->flags & kCheatFlag_Select) // label-selection
+ {
+ /* ----- move selection to unLinkExtension code or 1st code ----- */
+ do{
+ entry->selection++;
+
+ if(entry->flags & kCheatFlag_OneShot)
+ {
+ if(entry->selection >= entry->actionListLength)
+ {
+ entry->selection = 1; // last -> first
+
+ if(entry->selection >= entry->actionListLength)
+ entry->selection = 0;
+ }
+ /* ----- no action when press arrow key ----- */
+ entry->flags &= ~kCheatFlag_DoOneShot;
+ }
+ else // others
+ {
+ if(entry->selection >= entry->actionListLength)
+ {
+ entry->selection = 0; // last -> OFF
+
+ DeactivateCheat(entry); // OFF
+ }
+ else
+ {
+ if(!TEST_FIELD(entry->actionList[entry->selection].type, LinkExtension))
+ ActivateCheat(entry); // ON
+ }
+ }
+ }while(entry->selection && TEST_FIELD(entry->actionList[entry->selection].type, LinkExtension));
+ }
+ else
+ {
+ if(!(entry->flags & kCheatFlag_Null) && !(entry->flags & kCheatFlag_OneShot))
+ {
+ int active = entry->flags & kCheatFlag_Active;
+
+ active ^= 0x01; // toggle On and OFF
+
+ /* ----- get the user's selected value if needed ----- */
+ if((entry->flags & kCheatFlag_UserSelect) && active)
+ {
+ submenu_id = 2;
+ submenu_choice = 1;
+ }
+ else
+ {
+ if(active)
+ ActivateCheat(entry); // ON
+ else
+ DeactivateCheat(entry); // OFF
+ }
+ }
+ }
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ if(sel == (total - 1))
+ {
+ /* ----- return to prior menu ----- */
+ submenu_choice = 0;
+ sel = -1;
+ }
+ else
+ {
+ if((sel < (total - 1)) && entry)
+ {
+ if(ShiftKeyPressed())
+ {
+ if(entry->comment && entry->comment[0])
+ {
+ /* ----- display comment ------ */
+ submenu_id = 1;
+ submenu_choice = 1;
+ }
+ else
+ goto doActivate;
+ }
+ else
+ {
+ doActivate:
+
+ if(entry->flags & kCheatFlag_UserSelect)
+ {
+ /* ----- value-selection menu ----- */
+ submenu_id = 2;
+ submenu_choice = 1;
+ }
+ else
+ {
+ ActivateCheat(entry); // ON
+
+ /* ----- set do one shot flag if label-selection ----- */
+ if((entry->flags & kCheatFlag_Select) && (entry->flags & kCheatFlag_OneShot))
+ entry->flags |= kCheatFlag_DoOneShot;
+
+ /* ----- display one shot message if one shot ----- */
+ if(entry->flags & kCheatFlag_OneShot)
+ ui_popup_time(1, "%s activated", entry->name);
+ }
+ }
+ }
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_WATCH_VALUE))
+ WatchCheatEntry(entry, 0);
+
+ if(ShiftKeyPressed())
+ {
+ if(input_ui_pressed(IPT_UI_SAVE_CHEAT)) // shift + save = save all codes
+ {
+ for(i = 0; i < cheatListLength; i++)
+ SaveCheat(&cheatList[i], 0, 0);
+
+ ui_popup_time(1, "%d cheats saved", cheatListLength);
+ }
+
+ if(input_ui_pressed(IPT_UI_ADD_CHEAT)) // shift + add = add new emypty code
+ AddCheatBefore(sel);
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT)) // shift + delete = delete selected code
+ DeleteCheatAt(sel);
+ }
+ else
+ {
+ if(ControlKeyPressed())
+ {
+ if(input_ui_pressed(IPT_UI_SAVE_CHEAT)) // ctrl + save = save activation key
+ {
+ if((entry->flags & kCheatFlag_HasActivationKey1) || (entry->flags & kCheatFlag_HasActivationKey2))
+ {
+ SaveCheat(entry, sel, 1);
+
+ ui_popup_time(1, "activation key saved");
+ }
+ else
+ ui_popup_time(1, "no activation key");
+ }
+ }
+ else
+ {
+ if(input_ui_pressed(IPT_UI_SAVE_CHEAT))
+ SaveCheat(entry, 0, 0); // save current entry
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_EDIT_CHEAT) && entry) // edit selected code
+ {
+ submenu_id = 3;
+ submenu_choice = 1;
+ }
+
+ if(input_ui_pressed(IPT_UI_RELOAD_CHEAT))
+ ReloadCheatDatabase();
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_IN, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : enable/disable -> add/edit ----- */
+ sel = -3;
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_OUT, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : enable/disable -> watchpoint list ----- */
+ sel = -5;
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ return sel + 1;
+}
+
+/*--------------------------------------------------------
+ AddEditCheatMenu - management for Add/Edit cheat menu
+--------------------------------------------------------*/
+
+static int AddEditCheatMenu(int selection)
+{
+ INT32 sel;
+ static INT32 submenuChoice = 0;
+ static INT32 submenuCheat = 0;
+ const char ** menu_item;
+ INT32 i;
+ INT32 total = 0;
+ CheatEntry * entry;
+
+ sel = selection - 1;
+
+ RequestStrings(cheatListLength + 2, 0, 0, 0);
+
+ menu_item = menuStrings.mainList;
+
+ /********** SUB MENU **********/
+ if(submenuChoice)
+ {
+ submenuChoice = EditCheatMenu(&cheatList[submenuCheat], submenuCheat, submenuChoice);
+
+ /* ----- meaningless ? because no longer return with sel = -1 (pressed UI_CONFIG in submenu) ----- */
+// if(submenuChoice == -1)
+// {
+// submenuChoice = 0;
+// sel = -2;
+// }
+
+ return sel + 1;
+ }
+
+ /********** MENU CONSTRUCTION **********/
+ for(i = 0; i < cheatListLength; i++)
+ {
+ CheatEntry * traverse = &cheatList[i];
+
+ if(traverse->name)
+ menu_item[total++] = traverse->name; // code title
+ else
+ menu_item[total++] = "(none)";
+ }
+
+ menu_item[total++] = ui_getstring(UI_returntoprior); // return
+
+ menu_item[total] = NULL; // terminate array
+
+ /* ----- adjust current cursor position ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel >= total)
+ sel = total - 1;
+
+ /* ----- draw it ----- */
+ old_style_menu(menu_item, NULL, NULL, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+ }
+
+ if(sel < (total - 1))
+ entry = &cheatList[sel];
+ else
+ entry = NULL;
+
+ if(input_ui_pressed(IPT_UI_SAVE_CHEAT))
+ {
+ if(ShiftKeyPressed())
+ {
+ for(i = 0; i < cheatListLength; i++) // shift + save = save all codes
+ SaveCheat(&cheatList[i], 0, 0);
+
+ ui_popup_time(1, "%d cheats saved", cheatListLength);
+ }
+ else
+ {
+ if(ControlKeyPressed())
+ {
+ if((entry->flags & kCheatFlag_HasActivationKey1) || (entry->flags & kCheatFlag_HasActivationKey2))
+ {
+ SaveCheat(entry, sel, 1); // ctrl + save = save activation key
+
+ ui_popup_time(1, "activation key saved");
+ }
+ else
+ ui_popup_time(1, "no activation key");
+ }
+ else
+ SaveCheat(entry, 0, 0); // save current entry
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_ADD_CHEAT))
+ AddCheatBefore(sel); // insert empty code
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT))
+ DeleteCheatAt(sel); // delete selected code
+
+ if(input_ui_pressed(IPT_UI_WATCH_VALUE))
+ WatchCheatEntry(entry, 0); // watch selected code
+
+ if(input_ui_pressed(IPT_UI_EDIT_CHEAT)) // edit selected code
+ {
+ /* ----- if selected item is not return, go to edit menu ----- */
+ if(sel < (total - 1))
+ {
+ submenuCheat = sel;
+ submenuChoice = 1;
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ /* ----- if selected item is return, return previous menu ----- */
+ if(sel >= (total - 1))
+ {
+ submenuChoice = 0;
+ sel = -1;
+ }
+ /* ----- otherwise, go to edit menu (same as pressing edit key) ----- */
+ else
+ {
+ submenuCheat = sel;
+ submenuChoice = 1;
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_RELOAD_CHEAT))
+ ReloadCheatDatabase();
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_IN, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : add/edit -> search ----- */
+ sel = -4;
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_OUT, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : add/edit -> enable/disable ----- */
+ sel = -2;
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ return sel + 1;
+}
+
+/*------------------------------------------------
+ EditCheatMenu - management for edit code menu
+------------------------------------------------*/
+
+static int EditCheatMenu(CheatEntry * entry, int index, int selection)
+{
+ static const char * kTypeNames[] =
+ {
+ "Normal/Delay",
+ "Wait",
+ "Ignore Decrement",
+ "Watch",
+ "Comment",
+ "Select"
+ };
+
+ static const char * kNumbersTable[] =
+ {
+ "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"
+ };
+
+ static const char * kOperationNames[] =
+ {
+ "Write",
+ "Add/Subtract",
+ "Force Range",
+ "Set/Clear Bits",
+ "Write If Match",
+ "Unused (5)",
+ "Unused (6)",
+ "Null"
+ };
+
+ static const char * kAddSubtractNames[] =
+ {
+ "Add",
+ "Subtract"
+ };
+
+ static const char * kSetClearNames[] =
+ {
+ "Set",
+ "Clear"
+ };
+
+ static const char * kPrefillNames[] =
+ {
+ "None",
+ "FF",
+ "00",
+ "01"
+ };
+
+ static const char * kEndiannessNames[] =
+ {
+ "Normal",
+ "Swap"
+ };
+
+ static const char * kRegionNames[] =
+ {
+ "CPU1", "CPU2", "CPU3", "CPU4", "CPU5", "CPU6", "CPU7", "CPU8",
+ "GFX1", "GFX2", "GFX3", "GFX4", "GFX5", "GFX6", "GFX7", "GFX8",
+ "PROMS",
+ "SOUND1", "SOUND2", "SOUND3", "SOUND4", "SOUND5", "SOUND6", "SOUND7", "SOUND8",
+ "USER1", "USER2", "USER3", "USER4", "USER5", "USER6", "USER7", "USER8"
+ };
+
+ static const char * kLocationNames[] =
+ {
+ "Normal",
+ "Region",
+ "Mapped Memory",
+ "Custom",
+ "Relative Address",
+ "Program Space",
+ "Unused (6)",
+ "Unused (7)"
+ };
+
+ static const char * kCustomLocationNames[] =
+ {
+ "Comment",
+ "EEPROM",
+ "Select",
+ "Unused (3)", "Unused (4)", "Unused (5)", "Unused (6)", "Unused (7)",
+ "Unused (8)", "Unused (9)", "Unused (10)", "Unused (11)", "Unused (12)",
+ "Unused (13)", "Unused (14)", "Unused (15)", "Unused (16)", "Unused (17)",
+ "Unused (18)", "Unused (19)", "Unused (20)", "Unused (21)", "Unused (22)",
+ "Unused (23)", "Unused (24)", "Unused (25)", "Unused (26)", "Unused (27)",
+ "Unused (28)", "Unused (29)", "Unused (30)", "Unused (31)"
+ };
+
+ static const char * kSizeNames[] =
+ {
+ "8 Bit",
+ "16 Bit",
+ "24 Bit",
+ "32 Bit"
+ };
+
+ enum
+ {
+ kType_Name = 0, // text name
+ // NOTE: read from base cheat (for idx == 0)
+ kType_ExtendName, // text extraName
+ // NOTE: read from subcheat for (idx > 0) && (cheat[0].type == Select)
+ kType_Comment, // text comment
+ // NOTE: read from base cheat (for idx == 0)
+ kType_ActivationKey1, // key 1st activationKey
+ // NOTE: read from base cheat (for idx == 0)
+ kType_ActivationKey2, // key 2nd activationKey
+ // NOTE: read from base cheat (for idx == 0)
+ // if(idx > 0 && (cheat[0].type == Select))
+ kType_LinkExtension, // select LinkExtension Off - On
+ kType_Type, // select Type Normal/Delay - Wait - Ignore Decrement - Watch -
+ // Comment - Select
+ // NOTE: also uses location type field for comment and select
+ // if((Type != Comment) && (Type != Select))
+ // if(Type != Watch)
+ kType_OneShot, // select OneShot Off - On
+ kType_RestorePreviousValue,
+ // select RestorePreviousValue
+ // Off - On
+ // if((Type == Normal/Delay) || (Type == Wait))
+ kType_Delay, // value TypeParameter 0 - 7
+ // if(Type == Ignore Decrement)
+ kType_IgnoreDecrementBy,// value TypeParameter 0 - 7
+ // if(Type == Watch)
+ kType_WatchSize, // value Data 0x01 - 0xFF (stored as 0x00 - 0xFE)
+ // NOTE: value is packed in to 0x000000FF
+ kType_WatchSkip, // value Data 0x00 - 0xFF
+ // NOTE: value is packed in to 0x0000FF00
+ kType_WatchPerLine, // value Data 0x00 - 0xFF
+ // NOTE: value is packed in to 0x00FF0000
+ kType_WatchAddValue, // value Data -0x80 - 0x7F
+ // NOTE: value is packed in to 0xFF000000
+ kType_WatchFormat, // select TypeParameter Hex - Decimal - Binary - ASCII
+ // NOTE: value is packed in to 0x03
+ kType_WatchLabel, // select TypeParameter Off - On
+ // NOTE: value is packed in to 0x04
+ // and set operation to null
+ // else
+ kType_Operation, // select Operation Write - Add/Subtract - Force Range - Set/Clear Bits - Match to Write -
+ // Null
+ // if((Operation == Write) && (LocationType != Relative Address))
+ kType_WriteMask, // value extendData 0x00000000 - 0xFFFFFFFF
+ // if(Operation == Add/Subtract)
+ kType_AddSubtract, // select OperationParameter Add - Subtract
+ // if(LocationType != Relative Address)
+ // if(OperationParameter == Add)
+ kType_AddMaximum,
+ // value extendData 0x00000000 - 0xFFFFFFFF
+ // else
+ kType_SubtractMinimum,
+ // value extendData 0x00000000 - 0xFFFFFFFF
+ // if((Operation == Force Range) && (LocationType != Relative Address))
+ kType_RangeMinimum, // value extendData 0x00 - 0xFF / 0xFFFF
+ // NOTE: value is packed in to upper byte of extendData (as a word)
+ kType_RangeMaximum, // value extendData 0x00 - 0xFF / 0xFFFF
+ // NOTE: value is packed in to lower byte of extendData (as a word)
+ // if(Operation == Set/Clear)
+ kType_SetClear, // select OperationParameter Set - Clear
+ // if(Operation == Match to Write)
+ kType_WriteMatch, // value extendData 0x00000000 - 0xFFFFFFFF
+ // if((Operation != Null) || (Type == Watch))
+ // if(Type != Watch)
+ kType_Data,
+ kType_UserSelect, // select UserSelectEnable Off - On
+ // if(UserSelect == On)
+ kType_UserSelectMinimumDisp,
+ // value UserSelectMinimumDisplay
+ // 0 - 1
+ kType_UserSelectMinimum,
+ // value UserSelectMinimum 0 - 1
+ kType_UserSelectBCD,// select UserSelectBCD Off - On
+ kType_Prefill, // select UserSelectPrefill None - FF - 00 - 01
+ // if(idx > 0)
+ kType_CopyPrevious, // select LinkCopyPreviousValue
+ // Off - On
+ kType_ByteLength, // value BytesUsed 1 - 4
+ // if(bytesUsed > 0)
+ kType_Endianness, // select Endianness Normal - Swap
+ kType_LocationType, // select LocationType Normal - Region - Mapped Memory - EEPROM -
+ // Relative Address - Program Space
+ // NOTE: also uses LocationParameter for EEPROM type
+ // if((LocationType == Normal) || (LocationType == HandlerMemory) || (LocationType == ProgramSpace)
+ kType_CPU, // value LocationParameter 0 - 31
+ // if(LocationType == Region)
+ kType_Region, // select LocationParameter CPU1 - CPU2 - CPU3 - CPU4 - CPU5 - CPU6 - CPU7 -
+ // CPU8 - GFX1 - GFX2 - GFX3 - GFX4 - GFX5 - GFX6 -
+ // GFX7 - GFX8 - PROMS - SOUND1 - SOUND2 - SOUND3 -
+ // SOUND4 - SOUND5 - SOUND6 - SOUND7 - SOUND8 -
+ // USER1 - USER2 - USER3 - USER4 - USER5 - USER6 -
+ // USER7
+ // if(LocationType == RelativeAddress)
+ kType_PackedCPU, // value LocationParameter 0 - 7
+ // NOTE: packed in to upper three bits of LocationParameter
+ kType_PackedSize, // value LocationParameter 1 - 4
+ // NOTE: packed in to lower two bits of LocationParameter
+ kType_AddressIndex, // value extendData -0x80000000 - 0x7FFFFFFF
+ kType_Address,
+
+ kType_Return,
+ kType_Divider,
+
+ kType_Max
+ };
+
+ INT32 sel;
+ const char ** menuItem;
+ const char ** menuSubItem;
+ char * flagBuf;
+ char ** extendDataBuf; // FFFFFFFF (-80000000)
+ char ** addressBuf; // FFFFFFFF
+ char ** dataBuf; // 80000000 (-2147483648)
+ char ** watchSizeBuf; // FF
+ char ** watchSkipBuf; // FF
+ char ** watchPerLineBuf; // FF
+ char ** watchAddValueBuf; // FF
+ INT32 i;
+ INT32 total = 0;
+ MenuItemInfoStruct * info = NULL;
+ CheatAction * action = NULL;
+ UINT8 isSelect = 0;
+ static UINT8 editActive = 0;
+ UINT32 increment = 1;
+ UINT8 dirty = 0;
+ static INT32 currentNameTemplate = 0;
+
+ astring * temp_string_1 = astring_alloc();
+ astring * temp_string_2 = astring_alloc();
+
+ if(!entry)
+ return 0;
+
+ /********** MENU CONSTRUCTION **********/
+ if(menuItemInfoLength < (kType_Max * entry->actionListLength) + 2)
+ {
+ menuItemInfoLength = (kType_Max * entry->actionListLength) + 2;
+
+ menuItemInfo = realloc(menuItemInfo, menuItemInfoLength * sizeof(MenuItemInfoStruct));
+ }
+
+ RequestStrings((kType_Max * entry->actionListLength) + 2, 7 * entry->actionListLength, 24, 0);
+
+ menuItem = menuStrings.mainList;
+ menuSubItem = menuStrings.subList;
+ flagBuf = menuStrings.flagList;
+ extendDataBuf = &menuStrings.mainStrings[entry->actionListLength * 0];
+ addressBuf = &menuStrings.mainStrings[entry->actionListLength * 1];
+ dataBuf = &menuStrings.mainStrings[entry->actionListLength * 2];
+ watchSizeBuf = &menuStrings.mainStrings[entry->actionListLength * 3]; // these fields are wasteful
+ watchSkipBuf = &menuStrings.mainStrings[entry->actionListLength * 4]; // but the alternative is even more ugly
+ watchPerLineBuf = &menuStrings.mainStrings[entry->actionListLength * 5];
+ watchAddValueBuf = &menuStrings.mainStrings[entry->actionListLength * 6];
+
+ sel = selection - 1;
+
+ memset(flagBuf, 0, (kType_Max * entry->actionListLength) + 2);
+
+ /* ----- create menu items ----- */
+ for(i = 0; i < entry->actionListLength; i++)
+ {
+ CheatAction * traverse = &entry->actionList[i];
+
+ UINT32 type = EXTRACT_FIELD(traverse->type, Type);
+ UINT32 typeParameter = EXTRACT_FIELD(traverse->type, TypeParameter);
+ UINT32 operation = EXTRACT_FIELD(traverse->type, Operation) |
+ EXTRACT_FIELD(traverse->type, OperationExtend) << 2;
+ UINT32 operationParameter = EXTRACT_FIELD(traverse->type, OperationParameter);
+ UINT32 locationType = EXTRACT_FIELD(traverse->type, LocationType);
+ UINT32 locationParameter = EXTRACT_FIELD(traverse->type, LocationParameter);
+
+ UINT8 wasCommentOrSelect = 0;
+
+ if(isSelect)
+ {
+ /* ----- do extend name field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_ExtendName;
+ menuItem[total] = "Name";
+
+ if(traverse->optionalName)
+ menuSubItem[total++] = traverse->optionalName;
+ else
+ menuSubItem[total++] = "(none)";
+ }
+
+ /* ----- create items if 1st code ----- */
+ if(i == 0)
+ {
+ {
+ /* ----- do name field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Name;
+ menuItem[total] = "Name";
+
+ if(entry->name)
+ menuSubItem[total++] = entry->name;
+ else
+ menuSubItem[total++] = "(none)";
+ }
+
+ {
+ /* ----- do comment field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Comment;
+ menuItem[total] = "Comment";
+
+ if(entry->comment)
+ menuSubItem[total++] = entry->comment;
+ else
+ menuSubItem[total++] = "(none)";
+ }
+
+ {
+ /* ----- do 1st activation key field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_ActivationKey1;
+ menuItem[total] = "Activation Key (1st)";
+
+ if((entry->flags & kCheatFlag_HasActivationKey1))
+ menuSubItem[total++] = astring_c(input_code_name(temp_string_1, entry->activationKey1));
+ else
+ menuSubItem[total++] = "(none)";
+ }
+
+ {
+ /* ----- do 2nd activation key field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_ActivationKey2;
+ menuItem[total] = "Activation Key (2nd)";
+
+ if((entry->flags & kCheatFlag_HasActivationKey2))
+ menuSubItem[total++] = astring_c(input_code_name(temp_string_2, entry->activationKey2));
+ else
+ menuSubItem[total++] = "(none)";
+ }
+
+ /* ----- is this label-selection cheat ? ----- */
+ if((locationType == kLocation_Custom) && (locationParameter == kCustomLocation_Select))
+ isSelect = 1;
+ }
+
+ /* ----- create item if linked code on label-selection ----- */
+ if(i && isSelect)
+ {
+ /* ----- do link extension field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_LinkExtension;
+ menuItem[total] = "Link Extension";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(traverse->type, LinkExtension) ? UI_on : UI_off);
+ }
+
+ {
+ /* ----- do type field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Type;
+ menuItem[total] = "Type";
+
+ if(locationType == kLocation_Custom)
+ {
+ if(locationParameter == kCustomLocation_Comment)
+ {
+ /* ----- comment ----- */
+ wasCommentOrSelect = 1;
+
+ menuSubItem[total++] = kTypeNames[4];
+ }
+ else
+ {
+ if(locationParameter == kCustomLocation_Select)
+ {
+ /* ----- label-selection ----- */
+ wasCommentOrSelect = 1;
+
+ menuSubItem[total++] = kTypeNames[5];
+ }
+ else
+ menuSubItem[total++] = kTypeNames[type & 3];
+ }
+ }
+ else
+ menuSubItem[total++] = kTypeNames[type & 3];
+ }
+
+ /* ----- create items if not comment or label-selection ----- */
+ if(!wasCommentOrSelect)
+ {
+ if(type != kType_Watch)
+ {
+ {
+ /* ----- do one shot field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_OneShot;
+ menuItem[total] = "One Shot";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(traverse->type, OneShot) ? UI_on : UI_off);
+ }
+
+ {
+ /* ----- do restore previous value field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_RestorePreviousValue;
+ menuItem[total] = "Restore Previous Value";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(traverse->type, RestorePreviousValue) ? UI_on : UI_off);
+ }
+ }
+
+ if((type == kType_NormalOrDelay) || (type == kType_WaitForModification))
+ {
+ /* ----- do delay field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Delay;
+
+ if( TEST_FIELD(traverse->type, OneShot) && TEST_FIELD(traverse->type, RestorePreviousValue) &&
+ EXTRACT_FIELD(traverse->type, TypeParameter))
+ menuItem[total] = "Keep";
+ else
+ menuItem[total] = "Delay";
+
+ menuSubItem[total++] = kNumbersTable[typeParameter];
+ }
+
+ if(type == kType_IgnoreIfDecrementing)
+ {
+ /* ----- do ignore decrement by field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_IgnoreDecrementBy;
+ menuItem[total] = "Ignore Decrement By";
+ menuSubItem[total++] = kNumbersTable[typeParameter];
+ }
+
+ if(type == kType_Watch)
+ {
+ {
+ /* ----- do watch size field ----- */
+ sprintf(watchSizeBuf[i], "%d", (traverse->originalDataField & 0xFF) + 1);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_WatchSize;
+ menuItem[total] = "Watch Size";
+ menuSubItem[total++] = watchSizeBuf[i];
+ }
+
+ {
+ /* ----- do watch skip field ----- */
+ sprintf(watchSkipBuf[i], "%d", (traverse->data >> 8) & 0xFF);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_WatchSkip;
+ menuItem[total] = "Watch Skip";
+ menuSubItem[total++] = watchSkipBuf[i];
+ }
+
+ {
+ /* ----- do watch per line field ----- */
+ sprintf(watchPerLineBuf[i], "%d", (traverse->data >> 16) & 0xFF);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_WatchPerLine;
+ menuItem[total] = "Watch Per Line";
+ menuSubItem[total++] = watchPerLineBuf[i];
+ }
+
+ {
+ /* ----- do watch add value field ----- */
+ {
+ INT8 temp = (traverse->data >> 24) & 0xFF;
+
+ if(temp < 0)
+ sprintf(watchAddValueBuf[i], "-%.2X", -temp);
+ else
+ sprintf(watchAddValueBuf[i], "%.2X", temp);
+ }
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_WatchAddValue;
+ menuItem[total] = "Watch Add Value";
+ menuSubItem[total++] = watchAddValueBuf[i];
+ }
+
+ {
+ /* ----- do watch format field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_WatchFormat;
+ menuItem[total] = "Watch Format";
+ menuSubItem[total++] = kWatchDisplayTypeStringList[(typeParameter >> 0) & 0x03];
+ }
+
+ {
+ /* ----- do watch label field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_WatchLabel;
+ menuItem[total] = "Watch Label";
+ menuSubItem[total++] = ui_getstring(((typeParameter >> 2) & 0x01) ? UI_on : UI_off);
+ }
+ }
+ else
+ {
+ /* ----- do operation field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Operation;
+ menuItem[total] = "Operation";
+
+ if((locationType != kLocation_IndirectIndexed) && (operation == kOperation_SetOrClearBits))
+ {
+ /* ----- ignore Set/Clear Bit item if not relative address ----- */
+ operation = kOperation_WriteMask;
+
+ CLEAR_MASK_FIELD(traverse->type, OperationExtend);
+ SET_FIELD(traverse->type, Operation, operation);
+ }
+
+ menuSubItem[total++] = kOperationNames[operation];
+ }
+
+ if((operation == kOperation_WriteMask) && (locationType != kLocation_IndirectIndexed))
+ {
+ /* ----- do mask field ----- */
+ int numChars;
+
+ if(traverse->flags & kActionFlag_IgnoreMask)
+ {
+ menuItemInfo[total].extraData = 0xFFFFFFFF;
+ numChars = 8;
+ }
+ else
+ {
+ menuItemInfo[total].extraData = kCheatSizeMaskTable[EXTRACT_FIELD(traverse->type, BytesUsed)];
+ numChars = kCheatSizeDigitsTable[EXTRACT_FIELD(traverse->type, BytesUsed)];
+ }
+
+ sprintf(extendDataBuf[i], "%.*X", numChars, traverse->extendData);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_WriteMask;
+ menuItem[total] = "Mask";
+ menuSubItem[total++] = extendDataBuf[i];
+ }
+
+ if(operation == kOperation_AddSubtract)
+ {
+ {
+ /* ----- do add/subtract field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_AddSubtract;
+ menuItem[total] = "Add/Subtract";
+ menuSubItem[total++] = kAddSubtractNames[operationParameter];
+ }
+
+ if(locationType != kLocation_IndirectIndexed)
+ {
+ if(operationParameter)
+ {
+ /* ----- do subtract minimum field ----- */
+ sprintf(extendDataBuf[i], "%.8X", traverse->extendData);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_SubtractMinimum;
+ menuItem[total] = "Minimum Boundary";
+ menuSubItem[total++] = extendDataBuf[i];
+ }
+ else
+ {
+ /* ----- do add maximum field ----- */
+ sprintf(extendDataBuf[i], "%.8X", traverse->extendData);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_AddMaximum;
+ menuItem[total] = "Maximum Boundary";
+ menuSubItem[total++] = extendDataBuf[i];
+ }
+ }
+ }
+
+ if((operation == kOperation_ForceRange) && (locationType != kLocation_IndirectIndexed))
+ {
+ /* ----- do range minimum field ----- */
+ if(!EXTRACT_FIELD(traverse->type, BytesUsed))
+ sprintf(extendDataBuf[i], "%.2X", (traverse->extendData >> 8) & 0xFF);
+ else
+ sprintf(extendDataBuf[i], "%.4X", (traverse->extendData >> 16) & 0xFFFF);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_RangeMinimum;
+ menuItem[total] = "Range Minimum";
+ menuSubItem[total++] = extendDataBuf[i];
+
+ /* ----- do range maximum field ----- */
+ if(!EXTRACT_FIELD(traverse->type, BytesUsed))
+ {
+ sprintf(extendDataBuf[i] + 3, "%.2X", (traverse->extendData >> 0) & 0xFF);
+ menuSubItem[total] = extendDataBuf[i] + 3;
+ }
+ else
+ {
+ sprintf(extendDataBuf[i] + 7, "%.4X", (traverse->extendData >> 0) & 0xFFFF);
+ menuSubItem[total] = extendDataBuf[i] + 7;
+ }
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_RangeMaximum;
+ menuItem[total++] = "Range Maximum";
+ }
+
+ if(operation == kOperation_SetOrClearBits)
+ {
+ /* ----- do set/clear field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_SetClear;
+ menuItem[total] = "Set/Clear";
+ menuSubItem[total++] = kSetClearNames[operationParameter];
+ }
+
+ if(operation == kOperation_WriteMatch)
+ {
+ /* ----- do match value field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_WriteMatch;
+ menuItem[total] = "Match to Write";
+
+ {
+ int numChars;
+
+ if(traverse->flags & kActionFlag_IgnoreMask)
+ {
+ menuItemInfo[total].extraData = 0xFFFFFFFF;
+ numChars = 8;
+ }
+ else
+ {
+ menuItemInfo[total].extraData = kCheatSizeMaskTable[EXTRACT_FIELD(traverse->type, BytesUsed)];
+ numChars = kCheatSizeDigitsTable[EXTRACT_FIELD(traverse->type, BytesUsed)];
+ }
+
+ sprintf(extendDataBuf[i], "%.*X", numChars, traverse->extendData);
+ }
+
+ menuSubItem[total++] = extendDataBuf[i];
+ }
+
+ if((operation != kOperation_None) || (type == kType_Watch))
+ {
+ UINT32 userSelect = TEST_FIELD(entry->actionList[0].type, UserSelectEnable);
+ UINT32 bytesUsed = EXTRACT_FIELD(traverse->type, BytesUsed);
+
+ if(type != kType_Watch)
+ {
+ {
+ /* ----- do data field ----- */
+
+ sprintf(dataBuf[i], "%.*X (%d)", (int)kCheatSizeDigitsTable[bytesUsed], traverse->originalDataField, traverse->originalDataField);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Data;
+ menuItemInfo[total].extraData = kCheatSizeMaskTable[bytesUsed];
+ menuItem[total] = "Data";
+ menuSubItem[total++] = dataBuf[i];
+ }
+
+ if(!i)
+ {
+ /* ----- do user select field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_UserSelect;
+ menuItem[total] = "User Select";
+ menuSubItem[total++] = ui_getstring(userSelect ? UI_on : UI_off);
+ }
+
+ if(!i && userSelect)
+ {
+ {
+ /* ----- do user select minimum displayed value field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_UserSelectMinimumDisp;
+ menuItem[total] = "Minimum Displayed Value";
+ menuSubItem[total++] = kNumbersTable[EXTRACT_FIELD(traverse->type, UserSelectMinimumDisplay)];
+ }
+
+ {
+ /* ----- do user select minimum value field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_UserSelectMinimum;
+ menuItem[total] = "Minimum Value";
+ menuSubItem[total++] = kNumbersTable[EXTRACT_FIELD(traverse->type, UserSelectMinimum)];
+ }
+ }
+
+ if(userSelect)
+ {
+ /* ----- do user select BCD field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_UserSelectBCD;
+ menuItem[total] = "BCD";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(traverse->type, UserSelectBCD) ? UI_on : UI_off);
+ }
+
+ if(userSelect || isSelect)
+ {
+ /* ----- do prefill field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Prefill;
+ menuItem[total] = "Prefill";
+ menuSubItem[total++] = kPrefillNames[EXTRACT_FIELD(traverse->type, Prefill)];
+ }
+
+ if(i && userSelect)
+ {
+ /* ----- do copy previous value field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_CopyPrevious;
+ menuItem[total] = "Copy Previous Value";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(traverse->type, LinkCopyPreviousValue) ? UI_on : UI_off);
+ }
+ }
+
+ {
+ /* ----- do byte length field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_ByteLength;
+ menuItem[total] = "Byte Length";
+ menuSubItem[total++] = kSizeNames[bytesUsed];
+ }
+
+ if(bytesUsed > 0)
+ {
+ /* ----- do endianness field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Endianness;
+ menuItem[total] = "Endianness";
+ menuSubItem[total++] = kEndiannessNames[EXTRACT_FIELD(traverse->type, Endianness)];
+ }
+
+ {
+ /* ----- do location type field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_LocationType;
+ menuItem[total] = "Location";
+
+ if(locationType == kLocation_Custom)
+ menuSubItem[total++] = kCustomLocationNames[locationParameter];
+ else
+ menuSubItem[total++] = kLocationNames[locationType];
+ }
+
+ if( (locationType == kLocation_Standard) || (locationType == kLocation_HandlerMemory) ||
+ (locationType == kLocation_ProgramSpace))
+ {
+ /* ----- do cpu field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_CPU;
+ menuItem[total] = "CPU";
+ menuSubItem[total++] = kNumbersTable[locationParameter];
+ }
+
+ if(locationType == kLocation_MemoryRegion)
+ {
+ /* ----- do region field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Region;
+ menuItem[total] = "Region";
+ menuSubItem[total++] = kRegionNames[locationParameter];
+ }
+
+ if(locationType == kLocation_IndirectIndexed)
+ {
+ {
+ /* ----- do packed CPU field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_PackedCPU;
+ menuItem[total] = "CPU";
+ menuSubItem[total++] = kNumbersTable[(locationParameter >> 2) & 7];
+ }
+
+ {
+ /* ----- do packed size field ----- */
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_PackedSize;
+ menuItem[total] = "Address Size";
+ menuSubItem[total++] = kNumbersTable[(locationParameter & 3) + 1];
+ }
+
+ {
+ /* ----- do address index field ----- */
+
+ /* ---- swap if negative ----- */
+ if(traverse->extendData & 0x80000000)
+ {
+ int temp = traverse->extendData;
+
+ temp = -temp;
+
+ sprintf(extendDataBuf[i], "-%.8X", temp);
+ }
+ else
+ sprintf(extendDataBuf[i], "%.8X", traverse->extendData);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_AddressIndex;
+ menuItem[total] = "Address Index";
+ menuSubItem[total++] = extendDataBuf[i];
+ }
+ }
+
+ {
+ /* ----- do address field ----- */
+ int charsToPrint = 8;
+
+ switch(EXTRACT_FIELD(traverse->type, LocationType))
+ {
+ case kLocation_Standard:
+ case kLocation_HandlerMemory:
+ case kLocation_ProgramSpace:
+ {
+ CPUInfo * cpuInfo = &cpuInfoList[EXTRACT_FIELD(traverse->type, LocationParameter)];
+
+ charsToPrint = cpuInfo->addressCharsNeeded;
+ menuItemInfo[total].extraData = cpuInfo->addressMask;
+ }
+ break;
+
+ case kLocation_IndirectIndexed:
+ {
+ CPUInfo * cpuInfo = &cpuInfoList[(EXTRACT_FIELD(traverse->type, LocationParameter) >> 2) & 7];
+
+ charsToPrint = cpuInfo->addressCharsNeeded;
+ menuItemInfo[total].extraData = cpuInfo->addressMask;
+ }
+ break;
+
+ default:
+ menuItemInfo[total].extraData = 0xFFFFFFFF;
+ }
+
+ sprintf(addressBuf[i], "%.*X", charsToPrint, traverse->address);
+
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Address;
+ menuItem[total] = "Address";
+ menuSubItem[total++] = addressBuf[i];
+ }
+ }
+ }
+
+ if(i < (entry->actionListLength - 1))
+ {
+ menuItemInfo[total].subcheat = i;
+ menuItemInfo[total].fieldType = kType_Divider;
+ menuItem[total] = "==========";
+ menuSubItem[total++] = NULL;
+ }
+ }
+
+ menuItemInfo[total].subcheat = 0; // return
+ menuItemInfo[total].fieldType = kType_Return;
+ menuItem[total] = ui_getstring(UI_returntoprior);
+ menuSubItem[total++] = NULL;
+
+ menuItemInfo[total].subcheat = 0; // terminate arrey
+ menuItemInfo[total].fieldType = kType_Return;
+ menuItem[total] = NULL;
+ menuSubItem[total] = NULL;
+
+ /* ----- adjuste cursor position ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel >= total)
+ sel = total - 1;
+
+ info = &menuItemInfo[sel];
+ action = &entry->actionList[info->subcheat];
+
+ /* ----- higlighted sub-item if edit mode ----- */
+ if(editActive)
+ flagBuf[sel] = 1;
+
+ /* ---- draw it ----- */
+ old_style_menu(menuItem, menuSubItem, flagBuf, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(AltKeyPressed())
+ increment <<= 4;
+ if(ControlKeyPressed())
+ increment <<= 8;
+ if(ShiftKeyPressed())
+ increment <<= 16;
+
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate))
+ {
+ editActive = 0;
+ dirty = 1;
+
+ switch(info->fieldType)
+ {
+ case kType_Name:
+ currentNameTemplate--;
+
+ if(currentNameTemplate < 0)
+ {
+ currentNameTemplate = 0;
+
+ while(kCheatNameTemplates[currentNameTemplate + 1][0])
+ {
+ currentNameTemplate++;
+ }
+ }
+
+ entry->name = realloc(entry->name, strlen(kCheatNameTemplates[currentNameTemplate]) + 1);
+ strcpy(entry->name, kCheatNameTemplates[currentNameTemplate]);
+ break;
+/*
+ case kType_ActivationKey1:
+ case kType_ActivationKey2:
+ if(info->fieldType == kType_ActivationKey1)
+ {
+ entry->activationKey1--;
+
+ if(entry->activationKey1 < 0)
+ entry->activationKey1 = __code_max - 1;
+ if(entry->activationKey1 >= __code_max)
+ entry->activationKey1 = 0;
+
+ entry->flags |= kCheatFlag_HasActivationKey1;
+ }
+ else
+ {
+ entry->activationKey2--;
+
+ if(entry->activationKey2 < 0)
+ entry->activationKey2 = __code_max - 1;
+ if(entry->activationKey2 >= __code_max)
+ entry->activationKey2 = 0;
+
+ entry->flags |= kCheatFlag_HasActivationKey2;
+ }
+ break;
+*/
+ case kType_LinkExtension:
+ TOGGLE_MASK_FIELD(action->type, LinkExtension);
+ break;
+
+ case kType_Type:
+ {
+ UINT8 handled = 0;
+
+ CLEAR_MASK_FIELD(action->type, OperationExtend);
+
+ if(EXTRACT_FIELD(action->type, LocationType) == kLocation_Custom)
+ {
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ if(locationParameter == kCustomLocation_Comment)
+ {
+ SET_FIELD(action->type, LocationParameter, 0);
+ SET_FIELD(action->type, LocationType, kLocation_Standard);
+ SET_FIELD(action->type, Type, kType_Watch);
+ SET_FIELD(action->type, Operation, kOperation_None);
+ SET_MASK_FIELD(action->type, OperationExtend);
+
+ handled = 1;
+ }
+ else if(locationParameter == kCustomLocation_Select)
+ {
+ SET_FIELD(action->type, LocationParameter, kCustomLocation_Comment);
+ SET_FIELD(action->type, LocationType, kLocation_Custom);
+ SET_FIELD(action->type, Type, 0);
+
+ handled = 1;
+ }
+ }
+
+ if(!handled)
+ {
+ UINT32 type = EXTRACT_FIELD(action->type, Type);
+
+ if(type == kType_NormalOrDelay)
+ {
+ SET_FIELD(action->type, LocationParameter, kCustomLocation_Select);
+ SET_FIELD(action->type, LocationType, kLocation_Custom);
+ SET_FIELD(action->type, Type, 0);
+ }
+ else
+ {
+ SET_FIELD(action->type, Type, type - 1);
+ }
+ }
+ }
+ break;
+
+ case kType_OneShot:
+ TOGGLE_MASK_FIELD(action->type, OneShot);
+ break;
+
+ case kType_RestorePreviousValue:
+ TOGGLE_MASK_FIELD(action->type, RestorePreviousValue);
+ break;
+
+ case kType_Delay:
+ case kType_IgnoreDecrementBy:
+ {
+ UINT32 delay = (EXTRACT_FIELD(action->type, TypeParameter) - 1) & 7;
+
+ SET_FIELD(action->type, TypeParameter, delay);
+ }
+ break;
+
+ case kType_WatchSize:
+ action->originalDataField = (action->originalDataField & 0xFFFFFF00) | ((action->originalDataField - 0x00000001) & 0x000000FF);
+ action->data = action->originalDataField;
+ break;
+
+ case kType_WatchSkip:
+ action->originalDataField = (action->originalDataField & 0xFFFF00FF) | ((action->originalDataField - 0x00000100) & 0x0000FF00);
+ action->data = action->originalDataField;
+ break;
+
+ case kType_WatchPerLine:
+ action->originalDataField = (action->originalDataField & 0xFF00FFFF) | ((action->originalDataField - 0x00010000) & 0x00FF0000);
+ action->data = action->originalDataField;
+ break;
+
+ case kType_WatchAddValue:
+ action->originalDataField = (action->originalDataField & 0x00FFFFFF) | ((action->originalDataField - 0x01000000) & 0xFF000000);
+ action->data = action->originalDataField;
+ break;
+
+ case kType_WatchFormat:
+ {
+ UINT32 typeParameter = EXTRACT_FIELD(action->type, TypeParameter);
+
+ typeParameter = (typeParameter & 0xFFFFFFFC) | ((typeParameter - 0x00000001) & 0x0000003);
+ SET_FIELD(action->type, TypeParameter, typeParameter);
+ }
+ break;
+
+ case kType_WatchLabel:
+ SET_FIELD(action->type, TypeParameter, EXTRACT_FIELD(action->type, TypeParameter) ^ 0x00000004);
+ break;
+
+ case kType_Operation:
+ {
+ UINT32 operation = ((EXTRACT_FIELD(action->type, Operation) | EXTRACT_FIELD(action->type, OperationExtend) << 2) - 1) & 7;
+
+ if(operation == kOperation_None)
+ operation = kOperation_WriteMatch;
+
+ if( (operation == kOperation_SetOrClearBits) &&
+ !(EXTRACT_FIELD(action->type, LocationType) == kLocation_IndirectIndexed))
+ operation = (operation - 1) & 7;
+
+ if(operation >> 2)
+ SET_MASK_FIELD(action->type, OperationExtend);
+ else
+ CLEAR_MASK_FIELD(action->type, OperationExtend);
+
+ SET_FIELD(action->type, Operation, operation);
+ }
+ break;
+
+ case kType_WriteMask:
+ case kType_WriteMatch:
+ action->extendData -= increment;
+ action->extendData &= info->extraData;
+ break;
+
+ case kType_RangeMinimum:
+ if(!EXTRACT_FIELD(action->type, BytesUsed))
+ action->extendData = (action->extendData & 0xFFFF00FF) | ((action->extendData - 0x00000100) & 0x0000FF00);
+ else
+ action->extendData = (action->extendData & 0x0000FFFF) | ((action->extendData - 0x00010000) & 0xFFFF0000);
+ break;
+
+ case kType_RangeMaximum:
+ if(!EXTRACT_FIELD(action->type, BytesUsed))
+ action->extendData = (action->extendData & 0xFFFFFF00) | ((action->extendData - 0x00000001) & 0x000000FF);
+ else
+ action->extendData = (action->extendData & 0xFFFF0000) | ((action->extendData - 0x00000001) & 0x0000FFFF);
+ break;
+
+ case kType_AddressIndex:
+ case kType_SubtractMinimum:
+ case kType_AddMaximum:
+ action->extendData -= increment;
+ break;
+
+ case kType_AddSubtract:
+ case kType_SetClear:
+ TOGGLE_MASK_FIELD(action->type, OperationParameter);
+ break;
+
+ case kType_Data:
+ action->originalDataField -= increment;
+ action->originalDataField &= info->extraData;
+ action->data = action->originalDataField;
+ break;
+
+ case kType_UserSelect:
+ TOGGLE_MASK_FIELD(action->type, UserSelectEnable);
+ break;
+
+ case kType_UserSelectMinimumDisp:
+ TOGGLE_MASK_FIELD(action->type, UserSelectMinimumDisplay);
+ break;
+
+ case kType_UserSelectMinimum:
+ TOGGLE_MASK_FIELD(action->type, UserSelectMinimum);
+ break;
+
+ case kType_UserSelectBCD:
+ TOGGLE_MASK_FIELD(action->type, UserSelectBCD);
+ break;
+
+ case kType_Prefill:
+ {
+ UINT32 prefill = (EXTRACT_FIELD(action->type, Prefill) - 1) & 3;
+
+ SET_FIELD(action->type, Prefill, prefill);
+ }
+ break;
+
+ case kType_CopyPrevious:
+ TOGGLE_MASK_FIELD(action->type, LinkCopyPreviousValue);
+ break;
+
+ case kType_ByteLength:
+ {
+ UINT32 length = (EXTRACT_FIELD(action->type, BytesUsed) - 1) & 3;
+
+ SET_FIELD(action->type, BytesUsed, length);
+ }
+ break;
+
+ case kType_Endianness:
+ TOGGLE_MASK_FIELD(action->type, Endianness);
+ break;
+
+ case kType_LocationType:
+ {
+ UINT32 locationType = EXTRACT_FIELD(action->type, LocationType);
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ if(locationType == kLocation_Standard)
+ {
+ SET_FIELD(action->type, LocationType, kLocation_ProgramSpace);
+ SET_FIELD(action->type, LocationParameter, (locationParameter << 2) & 0x1C);
+ }
+ else if(locationType == kLocation_Custom)
+ {
+ SET_FIELD(action->type, LocationType, kLocation_HandlerMemory);
+ SET_FIELD(action->type, LocationParameter, 0);
+ }
+ else if(locationType == kLocation_IndirectIndexed)
+ {
+ SET_FIELD(action->type, LocationType, kLocation_Custom);
+ SET_FIELD(action->type, LocationParameter, kCustomLocation_EEPROM);
+ }
+ else
+ {
+ locationType--;
+
+ SET_FIELD(action->type, LocationType, locationType);
+ }
+ }
+ break;
+
+ case kType_CPU:
+ case kType_Region:
+ {
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ locationParameter = (locationParameter - 1) & 31;
+
+ SET_FIELD(action->type, LocationParameter, locationParameter);
+ }
+ break;
+
+ case kType_PackedCPU:
+ {
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ locationParameter = ((locationParameter - 0x04) & 0x1C) | (locationParameter & 0x03);
+
+ SET_FIELD(action->type, LocationParameter, locationParameter);
+ }
+ break;
+
+ case kType_PackedSize:
+ {
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ locationParameter = ((locationParameter - 0x01) & 0x03) | (locationParameter & 0x1C);
+
+ SET_FIELD(action->type, LocationParameter, locationParameter);
+ }
+ break;
+
+ case kType_Address:
+ action->address -= increment;
+ action->address &= info->extraData;
+ break;
+
+ case kType_Return:
+ case kType_Divider:
+ break;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalSlowKeyRepeatRate))
+ {
+ editActive = 0;
+ dirty = 1;
+
+ switch(info->fieldType)
+ {
+ case kType_Name:
+ currentNameTemplate++;
+
+ if((currentNameTemplate < 0) || !kCheatNameTemplates[currentNameTemplate][0])
+ {
+ currentNameTemplate = 0;
+ }
+
+ entry->name = realloc(entry->name, strlen(kCheatNameTemplates[currentNameTemplate]) + 1);
+ strcpy(entry->name, kCheatNameTemplates[currentNameTemplate]);
+ break;
+/*
+ case kType_ActivationKey1:
+ case kType_ActivationKey2:
+ if(info->fieldType == kType_ActivationKey1)
+ {
+ entry->activationKey1++;
+
+ if(entry->activationKey1 < 0)
+ entry->activationKey1 = __code_max - 1;
+ if(entry->activationKey1 >= __code_max)
+ entry->activationKey1 = 0;
+
+ entry->flags |= kCheatFlag_HasActivationKey1;
+ }
+ else
+ {
+ entry->activationKey2++;
+
+ if(entry->activationKey2 < 0)
+ entry->activationKey2 = __code_max - 1;
+ if(entry->activationKey2 >= __code_max)
+ entry->activationKey2 = 0;
+
+ entry->flags |= kCheatFlag_HasActivationKey2;
+ }
+ break;
+*/
+ case kType_LinkExtension:
+ TOGGLE_MASK_FIELD(action->type, LinkExtension);
+ break;
+
+ case kType_Type:
+ {
+ UINT8 handled = 0;
+
+ CLEAR_MASK_FIELD(action->type, OperationExtend);
+
+ if(EXTRACT_FIELD(action->type, LocationType) == kLocation_Custom)
+ {
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ if(locationParameter == kCustomLocation_Comment)
+ {
+ SET_FIELD(action->type, LocationParameter, kCustomLocation_Select);
+ SET_FIELD(action->type, LocationType, kLocation_Custom);
+ SET_FIELD(action->type, Type, 0);
+
+ handled = 1;
+ }
+ else if(locationParameter == kCustomLocation_Select)
+ {
+ SET_FIELD(action->type, LocationParameter, 0);
+ SET_FIELD(action->type, LocationType, kLocation_Standard);
+ SET_FIELD(action->type, Type, 0);
+
+ handled = 1;
+ }
+ }
+
+ if(!handled)
+ {
+ UINT32 type = EXTRACT_FIELD(action->type, Type);
+
+ if(type == kType_Watch)
+ {
+ SET_FIELD(action->type, LocationParameter, kCustomLocation_Comment);
+ SET_FIELD(action->type, LocationType, kLocation_Custom);
+ SET_FIELD(action->type, Type, 0);
+ }
+ else
+ {
+ SET_FIELD(action->type, Type, type + 1);
+
+ if((type + 1) == kType_Watch)
+ {
+ SET_FIELD(action->type, Operation, kOperation_None);
+ SET_MASK_FIELD(action->type, OperationExtend);
+ }
+ }
+ }
+ }
+ break;
+
+ case kType_OneShot:
+ TOGGLE_MASK_FIELD(action->type, OneShot);
+ break;
+
+ case kType_RestorePreviousValue:
+ TOGGLE_MASK_FIELD(action->type, RestorePreviousValue);
+ break;
+
+ case kType_Delay:
+ case kType_IgnoreDecrementBy:
+ {
+ UINT32 delay = (EXTRACT_FIELD(action->type, TypeParameter) + 1) & 7;
+
+ SET_FIELD(action->type, TypeParameter, delay);
+ }
+ break;
+
+ case kType_WatchSize:
+ action->originalDataField = (action->originalDataField & 0xFFFFFF00) | ((action->originalDataField + 0x00000001) & 0x000000FF);
+ action->data = action->originalDataField;
+ break;
+
+ case kType_WatchSkip:
+ action->originalDataField = (action->originalDataField & 0xFFFF00FF) | ((action->originalDataField + 0x00000100) & 0x0000FF00);
+ action->data = action->originalDataField;
+ break;
+
+ case kType_WatchPerLine:
+ action->originalDataField = (action->originalDataField & 0xFF00FFFF) | ((action->originalDataField + 0x00010000) & 0x00FF0000);
+ action->data = action->originalDataField;
+ break;
+
+ case kType_WatchAddValue:
+ action->originalDataField = (action->originalDataField & 0x00FFFFFF) | ((action->originalDataField + 0x01000000) & 0xFF000000);
+ action->data = action->originalDataField;
+ break;
+
+ case kType_WatchFormat:
+ {
+ UINT32 typeParameter = EXTRACT_FIELD(action->type, TypeParameter);
+
+ typeParameter = (typeParameter & 0xFFFFFFFC) | ((typeParameter + 0x00000001) & 0x0000003);
+ SET_FIELD(action->type, TypeParameter, typeParameter);
+ }
+ break;
+
+ case kType_WatchLabel:
+ SET_FIELD(action->type, TypeParameter, EXTRACT_FIELD(action->type, TypeParameter) ^ 0x00000004);
+ break;
+
+ case kType_Operation:
+ {
+ UINT32 operation = ((EXTRACT_FIELD(action->type, Operation) | EXTRACT_FIELD(action->type, OperationExtend) << 2) + 1) & 7;
+
+ if(operation > kOperation_WriteMatch)
+ operation = kOperation_WriteMask;
+
+ if( (operation == kOperation_SetOrClearBits) &&
+ !(EXTRACT_FIELD(action->type, LocationType) == kLocation_IndirectIndexed))
+ operation = (operation + 1) & 7;
+
+ if(operation >> 2)
+ SET_MASK_FIELD(action->type, OperationExtend);
+ else
+ CLEAR_MASK_FIELD(action->type, OperationExtend);
+
+ SET_FIELD(action->type, Operation, operation);
+ }
+ break;
+
+ case kType_WriteMask:
+ case kType_WriteMatch:
+ action->extendData += increment;
+ action->extendData &= info->extraData;
+ break;
+
+ case kType_RangeMinimum:
+ if(!EXTRACT_FIELD(action->type, BytesUsed))
+ action->extendData = (action->extendData & 0xFFFF00FF) | ((action->extendData + 0x00000100) & 0x0000FF00);
+ else
+ action->extendData = (action->extendData & 0x0000FFFF) | ((action->extendData + 0x00010000) & 0xFFFF0000);
+ break;
+
+ case kType_RangeMaximum:
+ if(!EXTRACT_FIELD(action->type, BytesUsed))
+ action->extendData = (action->extendData & 0xFFFFFF00) | ((action->extendData + 0x00000001) & 0x000000FF);
+ else
+ action->extendData = (action->extendData & 0xFFFF0000) | ((action->extendData + 0x00000001) & 0x0000FFFF);
+ break;
+
+ case kType_AddressIndex:
+ case kType_SubtractMinimum:
+ case kType_AddMaximum:
+ action->extendData += increment;
+ break;
+
+ case kType_AddSubtract:
+ case kType_SetClear:
+ TOGGLE_MASK_FIELD(action->type, OperationParameter);
+ break;
+
+ case kType_Data:
+ action->originalDataField += increment;
+ action->originalDataField &= info->extraData;
+ action->data = action->originalDataField;
+ break;
+
+ case kType_UserSelect:
+ TOGGLE_MASK_FIELD(action->type, UserSelectEnable);
+ break;
+
+ case kType_UserSelectMinimumDisp:
+ TOGGLE_MASK_FIELD(action->type, UserSelectMinimumDisplay);
+ break;
+
+ case kType_UserSelectMinimum:
+ TOGGLE_MASK_FIELD(action->type, UserSelectMinimum);
+ break;
+
+ case kType_UserSelectBCD:
+ TOGGLE_MASK_FIELD(action->type, UserSelectBCD);
+ break;
+
+ case kType_Prefill:
+ {
+ UINT32 prefill = (EXTRACT_FIELD(action->type, Prefill) + 1) & 3;
+
+ SET_FIELD(action->type, Prefill, prefill);
+ }
+ break;
+
+ case kType_CopyPrevious:
+ TOGGLE_MASK_FIELD(action->type, LinkCopyPreviousValue);
+ break;
+
+ case kType_ByteLength:
+ {
+ UINT32 length = (EXTRACT_FIELD(action->type, BytesUsed) + 1) & 3;
+
+ SET_FIELD(action->type, BytesUsed, length);
+ }
+ break;
+
+ case kType_Endianness:
+ TOGGLE_MASK_FIELD(action->type, Endianness);
+ break;
+
+ case kType_LocationType:
+ {
+ UINT32 locationType = EXTRACT_FIELD(action->type, LocationType);
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ if(locationType == kLocation_ProgramSpace)
+ {
+ SET_FIELD(action->type, LocationType, kLocation_Standard);
+ SET_FIELD(action->type, LocationParameter, (locationParameter >> 2) & 7);
+ }
+ else if(locationType == kLocation_Custom)
+ {
+ SET_FIELD(action->type, LocationType, kLocation_IndirectIndexed);
+ SET_FIELD(action->type, LocationParameter, 0);
+ }
+ else if(locationType == kLocation_HandlerMemory)
+ {
+ SET_FIELD(action->type, LocationType, kLocation_Custom);
+ SET_FIELD(action->type, LocationParameter, kCustomLocation_EEPROM);
+ }
+ else
+ {
+ locationType++;
+
+ SET_FIELD(action->type, LocationType, locationType);
+ }
+ }
+ break;
+
+ case kType_CPU:
+ case kType_Region:
+ {
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ locationParameter = (locationParameter + 1) & 31;
+
+ SET_FIELD(action->type, LocationParameter, locationParameter);
+ }
+ break;
+
+ case kType_PackedCPU:
+ {
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ locationParameter = ((locationParameter + 0x04) & 0x1C) | (locationParameter & 0x03);
+
+ SET_FIELD(action->type, LocationParameter, locationParameter);
+ }
+ break;
+
+ case kType_PackedSize:
+ {
+ UINT32 locationParameter = EXTRACT_FIELD(action->type, LocationParameter);
+
+ locationParameter = ((locationParameter + 0x01) & 0x03) | (locationParameter & 0x1C);
+
+ SET_FIELD(action->type, LocationParameter, locationParameter);
+ }
+ break;
+
+ case kType_Address:
+ action->address += increment;
+ action->address &= info->extraData;
+ break;
+
+ case kType_Return:
+ case kType_Divider:
+ break;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+
+ editActive = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+
+ editActive = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+
+ editActive = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+
+ editActive = 0;
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ if(editActive)
+ {
+ editActive = 0;
+ }
+ else
+ {
+ switch(info->fieldType)
+ {
+ case kType_Name:
+ case kType_ExtendName:
+ case kType_Comment:
+ case kType_ActivationKey1:
+ case kType_ActivationKey2:
+ case kType_WatchSize:
+ case kType_WatchSkip:
+ case kType_WatchPerLine:
+ case kType_WatchAddValue:
+ case kType_WriteMask:
+ case kType_AddMaximum:
+ case kType_SubtractMinimum:
+ case kType_RangeMinimum:
+ case kType_RangeMaximum:
+ case kType_WriteMatch:
+ case kType_Data:
+ case kType_Address:
+ osd_readkey_unicode(1);
+ dirty = 1;
+ editActive = 1;
+ break;
+
+ case kType_Return:
+ sel = -1;
+ break;
+ }
+ }
+ }
+
+ /********** EDIT MODE **********/
+ if(editActive)
+ {
+ /* ----- do edit text ----- */
+ dirty = 1;
+
+ switch(info->fieldType)
+ {
+ case kType_Name:
+ entry->name = DoDynamicEditTextField(entry->name);
+ break;
+
+ case kType_ExtendName:
+ action->optionalName = DoDynamicEditTextField(action->optionalName);
+ break;
+
+ case kType_Comment:
+ entry->comment = DoDynamicEditTextField(entry->comment);
+ break;
+
+ case kType_ActivationKey1:
+ case kType_ActivationKey2:
+ {
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ {
+ if(info->fieldType == kType_ActivationKey1)
+ {
+ entry->activationKey1 = 0;
+ entry->flags &= ~kCheatFlag_HasActivationKey1;
+ }
+ else
+ {
+ entry->activationKey2 = 0;
+ entry->flags &= ~kCheatFlag_HasActivationKey2;
+ }
+
+ editActive = 0;
+ }
+ else
+ {
+ int code = input_code_poll_switches(FALSE);
+
+ if(code == KEYCODE_ESC)
+ {
+ if(info->fieldType == kType_ActivationKey1)
+ {
+ entry->activationKey1 = 0;
+ entry->flags &= ~kCheatFlag_HasActivationKey1;
+ }
+ else
+ {
+ entry->activationKey2 = 0;
+ entry->flags &= ~kCheatFlag_HasActivationKey2;
+ }
+
+ editActive = 0;
+ }
+ else
+ {
+ if((code != INPUT_CODE_INVALID) && !input_ui_pressed(IPT_UI_SELECT))
+ {
+ if(info->fieldType == kType_ActivationKey1)
+ {
+ entry->activationKey1 = code;
+ entry->flags |= kCheatFlag_HasActivationKey1;
+ }
+ else
+ {
+ entry->activationKey2 = code;
+ entry->flags |= kCheatFlag_HasActivationKey2;
+ }
+
+ editActive = 0;
+ }
+ }
+ }
+ }
+ break;
+
+ case kType_WatchSize:
+ {
+ UINT32 temp = (action->originalDataField >> 0) & 0xFF;
+
+ temp++;
+ temp = DoEditHexField(temp) & 0xFF;
+ temp--;
+
+ action->originalDataField = (action->originalDataField & 0xFFFFFF00) | ((temp << 0) & 0x000000FF);
+ action->data = action->originalDataField;
+ }
+ break;
+
+ case kType_WatchSkip:
+ {
+ UINT32 temp = (action->originalDataField >> 8) & 0xFF;
+
+ temp = DoEditHexField(temp) & 0xFF;
+
+ action->originalDataField = (action->originalDataField & 0xFFFF00FF) | ((temp << 8) & 0x0000FF00);
+ action->data = action->originalDataField;
+ }
+ break;
+
+ case kType_WatchPerLine:
+ {
+ UINT32 temp = (action->originalDataField >> 16) & 0xFF;
+
+ temp = DoEditHexField(temp) & 0xFF;
+
+ action->originalDataField = (action->originalDataField & 0xFF00FFFF) | ((temp << 16) & 0x00FF0000);
+ action->data = action->originalDataField;
+ }
+ break;
+
+ case kType_WatchAddValue:
+ {
+ UINT32 temp = (action->originalDataField >> 24) & 0xFF;
+
+ temp = DoEditHexFieldSigned(temp, 0xFFFFFF80) & 0xFF;
+
+ action->originalDataField = (action->originalDataField & 0x00FFFFFF) | ((temp << 24) & 0xFF000000);
+ action->data = action->originalDataField;
+ }
+ break;
+
+ case kType_WriteMask:
+ action->extendData = DoEditHexField(action->extendData);
+ action->extendData &= info->extraData;
+ break;
+
+ case kType_AddMaximum:
+ case kType_SubtractMinimum:
+ case kType_WriteMatch:
+ action->extendData = DoEditHexField(action->extendData);
+ break;
+
+ case kType_RangeMinimum:
+ {
+ UINT32 temp;
+
+ if(!TEST_FIELD(action->type, BytesUsed))
+ {
+ temp = (action->extendData >> 8) & 0xFF;
+ temp = DoEditHexField(temp) & 0xFF;
+
+ action->extendData = (action->extendData & 0xFF) | ((temp << 8) & 0xFF00);
+ }
+ else
+ {
+ temp = (action->extendData >> 16) & 0xFFFF;
+ temp = DoEditHexField(temp) & 0xFFFF;
+
+ action->extendData = (action->extendData & 0x0000FFFF) | ((temp << 16) & 0xFFFF0000);
+ }
+ }
+ break;
+
+ case kType_RangeMaximum:
+ {
+ UINT32 temp;
+
+ if(!TEST_FIELD(action->type, BytesUsed))
+ {
+ temp = action->extendData & 0xFF;
+ temp = DoEditHexField(temp) & 0xFF;
+
+ action->extendData = (action->extendData & 0xFF00) | (temp & 0x00FF);
+ }
+ else
+ {
+ temp = action->extendData & 0xFFFF;
+ temp = DoEditHexField(temp) & 0xFFFF;
+
+ action->extendData = (action->extendData & 0xFFFF0000) | (temp & 0x0000FFFF);
+ }
+ }
+ break;
+
+ case kType_Data:
+ action->originalDataField = DoEditHexField(action->originalDataField);
+ action->originalDataField &= info->extraData;
+ action->data = action->originalDataField;
+ break;
+
+ case kType_Address:
+ action->address = DoEditHexField(action->address);
+ action->address &= info->extraData;
+ break;
+ }
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ editActive = 0;
+ }
+ else
+ {
+ if(input_ui_pressed(IPT_UI_SAVE_CHEAT))
+ {
+ if(ControlKeyPressed())
+ if((entry->flags & kCheatFlag_HasActivationKey1) || (entry->flags & kCheatFlag_HasActivationKey2))
+ {
+ SaveCheat(entry, index, 1); // save activation key
+
+ ui_popup_time(1, "activation key saved");
+ }
+ else
+ ui_popup_time(1, "no activation key");
+ else
+ SaveCheat(entry, 0, 0); // save current entry
+ }
+
+ if(input_ui_pressed(IPT_UI_WATCH_VALUE))
+ WatchCheatEntry(entry, 0);
+
+ if(input_ui_pressed(IPT_UI_ADD_CHEAT))
+ AddActionBefore(entry, info->subcheat);
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT))
+ {
+ if(!info->subcheat)
+ {
+ /* ----- if selected entry is master, delete current entry then return to previous menu ----- */
+ DeleteCheatAt(index);
+
+ return 0;
+ }
+ else
+ DeleteActionAt(entry, info->subcheat);
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ {
+ sel = -1;
+ editActive = 0;
+ }
+
+ if(sel == -1)
+ {
+ editActive = 0;
+ dirty = 1;
+ }
+
+ if(dirty)
+ {
+ UpdateCheatInfo(entry, 0);
+
+ entry->flags |= kCheatFlag_Dirty;
+ }
+
+ astring_free(temp_string_1);
+ astring_free(temp_string_2);
+
+ return sel + 1;
+}
+
+/*-----------------------------------------------------------
+ DoSearchMenuMinimum - management for minimum search menu
+-----------------------------------------------------------*/
+
+static int DoSearchMenuMinimum(int selection)
+{
+ /* main */
+ enum
+ {
+ kMenu_CPU = 0,
+ kMenu_SearchItem,
+
+ kMenu_Divider,
+
+ kMenu_Memory,
+ kMenu_ViewResult,
+ kMenu_RestoreSearch,
+
+ kMenu_Return,
+ };
+
+ /* search item */
+ enum
+ {
+ kItem_Value,
+ kItem_Timer,
+ kItem_Equal,
+ kItem_NotEqual,
+ kItem_Less,
+ kItem_Greater,
+
+ kItem_Max = kItem_Greater,
+ };
+
+ const char * menuItem[kMenu_Return + 2] = { 0 };
+ const char * menuSubItem[kMenu_Return + 2] = { 0 };
+
+ char valueBuffer[60];
+ char valueSignedBuffer[60];
+ char cpuBuffer[20];
+ char flagBuf[kMenu_Return + 2] = { 0 };
+
+ SearchInfo * search = GetCurrentSearch();
+
+ INT32 sel = selection - 1;
+ INT32 total = 0;
+ UINT8 doSearch = 0;
+
+ static INT8 searchItem = 0;
+ static INT8 submenuChoice = 0;
+ static UINT8 doneSaveMemory = 0;
+ static UINT8 firstEntry = 0;
+ static UINT8 editActive = 0;
+ static UINT8 posnKeep = kMenu_SearchItem;
+ static UINT32 increment = 1;
+
+ /********** SUB MENU **********/
+ if(submenuChoice)
+ {
+ switch(sel)
+ {
+ case kMenu_CPU:
+ submenuChoice = SelectSearchRegions(submenuChoice, GetCurrentSearch());
+ break;
+
+ case kMenu_ViewResult:
+ submenuChoice = ViewSearchResults(submenuChoice, firstEntry);
+ break;
+ }
+
+ firstEntry = 0;
+
+ posnKeep = sel;
+
+ /* ----- meaningless ? because no longer return with sel = -1 (pressed UI_CONFIG in submenu) ----- */
+// if(submenuChoice == -1)
+// submenuChoice = 0;
+
+ return sel + 1;
+ }
+
+ sel = posnKeep;
+
+ /* ----- unselectable comparison search item if no save ----- */
+ if(!doneSaveMemory)
+ searchItem = kItem_Value;
+
+ /********** MENU CONSTRUCTION **********/
+ sprintf(cpuBuffer, "%d", search->targetIdx); // CPU
+ menuItem[total] = ui_getstring(UI_cpu);
+ menuSubItem[total++] = cpuBuffer;
+
+ if(search->sign && (search->oldOptions.value & kSearchByteSignBitTable[search->bytes]))
+ {
+ UINT32 tempValue;
+
+ tempValue = ~search->oldOptions.value + 1;
+ tempValue &= kSearchByteUnsignedMaskTable[search->bytes];
+
+ sprintf(valueBuffer, "-%.*X (-%d)", kSearchByteDigitsTable[search->bytes], tempValue, tempValue);
+ }
+ else
+ sprintf(valueBuffer, "%.*X (%d)", kSearchByteDigitsTable[search->bytes],
+ search->oldOptions.value & kSearchByteMaskTable[search->bytes],
+ search->oldOptions.value & kSearchByteMaskTable[search->bytes]);
+
+ switch(searchItem)
+ {
+ case kItem_Value: // value
+ menuItem[total] = "Value";
+ menuSubItem[total++] = valueBuffer;
+ break;
+
+ case kItem_Timer:
+ menuItem[total] = "Timer (+ or -)"; // timer
+
+ /* ----- if memory has been saved, set sub-item for timer ----- */
+ if(doneSaveMemory)
+ {
+ if(search->oldOptions.delta & kSearchByteSignBitTable[search->bytes])
+ {
+ UINT32 tempValue;
+
+ tempValue = ~search->oldOptions.delta + 1;
+ tempValue &= kSearchByteUnsignedMaskTable[search->bytes];
+
+ sprintf(valueSignedBuffer, "-%.*X (-%d)", kSearchByteDigitsTable[search->bytes], tempValue, tempValue);
+ }
+ else
+ sprintf(valueSignedBuffer, "%.*X (%d)", kSearchByteDigitsTable[search->bytes],
+ search->oldOptions.delta & kSearchByteMaskTable[search->bytes],
+ search->oldOptions.delta & kSearchByteMaskTable[search->bytes]);
+
+ menuSubItem[total++] = valueSignedBuffer;
+ }
+ break;
+
+ case kItem_Equal:
+ menuItem[total] = "Comparison"; // equal
+ menuSubItem[total++] = "Equal";
+ break;
+
+ case kItem_NotEqual:
+ menuItem[total] = "Comparison"; // not equal
+ menuSubItem[total++] = "Not Equal";
+ break;
+
+ case kItem_Less:
+ menuItem[total] = "Comparison"; // less
+ menuSubItem[total++] = "Less";
+ break;
+
+ case kItem_Greater:
+ menuItem[total] = "Comparison"; // greater
+ menuSubItem[total++] = "Greater";
+ break;
+ }
+
+ menuItem[total] = "--------------------"; // divider
+ menuSubItem[total++] = NULL;
+
+ if(doneSaveMemory) // memory
+ menuItem[total] = "Initialize Memory";
+ else
+ menuItem[total] = "Save Memory";
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = ui_getstring(UI_viewresults); // view result
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = ui_getstring(UI_restoreresults); // restore result
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = ui_getstring(UI_returntoprior); // return
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = NULL; // terminate array
+ menuSubItem[total] = NULL;
+
+ /* ----- adjust current cursor position ----- */
+ if((sel < 0) || (sel >= total))
+ sel = kMenu_SearchItem;
+
+ /* ----- higlighted sub-item if edit mode ----- */
+ if(editActive)
+ flagBuf[sel] = 1;
+
+ /* ----- draw it ----- */
+ old_style_menu(menuItem, menuSubItem, flagBuf, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ if(editActive)
+ {
+ increment <<= 4;
+
+ switch(searchItem)
+ {
+ case kItem_Value:
+ search->oldOptions.value += increment;
+ search->oldOptions.value &= kSearchByteMaskTable[search->bytes];
+ break;
+
+ case kItem_Timer:
+ search->oldOptions.delta += increment;
+ search->oldOptions.delta &= kSearchByteMaskTable[search->bytes];
+ break;
+ }
+
+ increment >>= 4;
+ }
+ else
+ {
+ sel--;
+
+ /* ----- if divider, skip it ----- */
+ if(sel == kMenu_Divider)
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ if(editActive)
+ {
+ increment <<= 4;
+
+ switch(searchItem)
+ {
+ case kItem_Value:
+ search->oldOptions.value -= increment;
+ search->oldOptions.value &= kSearchByteMaskTable[search->bytes];
+ break;
+
+ case kItem_Timer:
+ search->oldOptions.delta -= increment;
+ search->oldOptions.delta &= kSearchByteMaskTable[search->bytes];
+ break;
+ }
+
+ increment >>= 4;
+ }
+ else
+ {
+ sel++;
+
+ /* ----- if divider, skip it ----- */
+ if(sel == kMenu_Divider)
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalFastKeyRepeatRate))
+ {
+ if(editActive)
+ {
+ switch(searchItem)
+ {
+ case kItem_Value:
+ search->oldOptions.value -= increment;
+ search->oldOptions.value &= kSearchByteMaskTable[search->bytes];
+ break;
+
+ case kItem_Timer:
+ search->oldOptions.delta -= increment;
+ search->oldOptions.delta &= kSearchByteMaskTable[search->bytes];
+ break;
+ }
+ }
+ else
+ {
+ switch(sel)
+ {
+ case kMenu_CPU:
+ if(search->targetIdx > 0)
+ {
+ search->targetIdx--;
+
+ BuildSearchRegions(search);
+ AllocateSearchRegions(search);
+
+ doneSaveMemory = 0;
+ }
+ break;
+
+ case kMenu_SearchItem:
+ if(doneSaveMemory)
+ searchItem--;
+
+ if(searchItem < 0)
+ searchItem = kItem_Max;
+ break;
+ }
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalFastKeyRepeatRate))
+ {
+ if(editActive)
+ {
+ switch(searchItem)
+ {
+ case kItem_Value:
+ search->oldOptions.value += increment;
+ search->oldOptions.value &= kSearchByteMaskTable[search->bytes];
+ break;
+
+ case kItem_Timer:
+ search->oldOptions.delta += increment;
+ search->oldOptions.delta &= kSearchByteMaskTable[search->bytes];
+ break;
+ }
+ }
+ else
+ {
+ switch(sel)
+ {
+ case kMenu_CPU:
+ if(search->targetIdx < cpu_gettotalcpu() - 1)
+ {
+ search->targetIdx++;
+
+ BuildSearchRegions(search);
+ AllocateSearchRegions(search);
+
+ doneSaveMemory = 0;
+ }
+ break;
+
+ case kMenu_SearchItem:
+ if(doneSaveMemory)
+ searchItem++;
+
+ if(searchItem > kItem_Max)
+ searchItem = kItem_Value;
+
+ break;
+ }
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ if(editActive)
+ {
+ switch(searchItem)
+ {
+ case kItem_Value:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kSearchOperand_Value;
+ search->comparison = kSearchComparison_EqualTo;
+ search->value = search->oldOptions.value;
+
+ doSearch = 1;
+ break;
+
+ case kItem_Timer:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kSearchOperand_Previous;
+ search->comparison = kSearchComparison_IncreasedBy;
+ search->value = search->oldOptions.delta;
+
+ doSearch = 1;
+ break;
+ }
+
+ /* ----- finish edit mode then do search ----- */
+ editActive = 0;
+ }
+ else
+ {
+ switch(sel)
+ {
+ case kMenu_CPU:
+ submenuChoice = 1; // go to region selection menu
+ break;
+
+ case kMenu_SearchItem:
+ {
+
+ switch(searchItem)
+ {
+ case kItem_Value:
+ case kItem_Timer:
+ editActive = 1;
+ break;
+
+ case kItem_Equal:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kSearchOperand_Previous;
+ search->comparison = kSearchComparison_EqualTo;
+
+ doSearch = 1;
+ break;
+
+ case kItem_NotEqual:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kSearchOperand_Previous;
+ search->comparison = kSearchComparison_NotEqual;
+
+ doSearch = 1;
+ break;
+
+ case kItem_Less:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kSearchOperand_Previous;
+ search->comparison = kSearchComparison_LessThan;
+
+ doSearch = 1;
+ break;
+
+ case kItem_Greater:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kSearchOperand_Previous;
+ search->comparison = kSearchComparison_GreaterThan;
+
+ doSearch = 1;
+ break;
+ }
+ }
+ break;
+
+ case kMenu_Memory: // save memory to search newly
+ doneSaveMemory = 0;
+
+ doSearch = 1;
+ break;
+
+ case kMenu_ViewResult:
+ if(search->regionListLength)
+ {
+ /* ----- go to result viewer ----- */
+ firstEntry = 1;
+ submenuChoice = 1;
+ }
+ else
+ /* ----- if no search region (eg, sms.c in HazeMD), don't open result viewer to avoid the crash ----- */
+ ui_popup_time(1, "no search regions");
+ break;
+
+ case kMenu_RestoreSearch:
+ RestoreSearchBackup(search);
+ break;
+
+ case kMenu_Return:
+ posnKeep = kMenu_SearchItem;
+ sel = -1;
+ break;
+ }
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_IN, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : search -> watchpoint list ----- */
+ sel = -5;
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_OUT, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : search -> add/edit ----- */
+ sel = -3;
+
+ /* ----- edit mode ON/OFF ----- */
+ if(input_ui_pressed(IPT_UI_EDIT_CHEAT))
+ {
+ if(editActive)
+ editActive = 0;
+ else
+ {
+ if((searchItem == kItem_Value) || (kItem_Timer))
+ editActive = 1;
+ }
+ }
+
+ /* ----- memory save ----- */
+ if(input_ui_pressed(IPT_UI_CLEAR))
+ {
+ doneSaveMemory = 0;
+
+ doSearch = 1;
+ }
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ {
+ if(editActive)
+ editActive = 0;
+ else
+ {
+ posnKeep = kMenu_Memory;
+ sel = -1;
+ }
+ }
+
+ /********** SEARCH **********/
+ if(doSearch)
+ {
+ if(!doneSaveMemory)
+ /* ----- initialize search ----- */
+ InitializeNewSearch(search);
+
+ if(((sel == kMenu_SearchItem) && (searchItem == kItem_Value)) || doneSaveMemory)
+ {
+ /* ----- do search ----- */
+ BackupSearch(search);
+
+ DoSearch(search);
+ }
+
+ UpdateSearch(search);
+
+ /* ----- display message ----- */
+ if(((sel == kMenu_SearchItem) && (searchItem == kItem_Value)) || doneSaveMemory)
+ popmessage("%d results found", search->numResults);
+ else
+ popmessage("saved all memory regions");
+
+ doneSaveMemory = 1;
+
+ if(search->numResults == 1)
+ {
+ AddCheatFromFirstResult(search);
+
+ popmessage("1 result found, added to list");
+ }
+ }
+
+ /********** EDIT **********/
+ if((sel == kMenu_SearchItem) && editActive)
+ {
+ if(searchItem == kItem_Value)
+ {
+ search->oldOptions.value = DoEditHexField(search->oldOptions.value);
+
+ search->oldOptions.value &= kSearchByteMaskTable[search->bytes];
+ }
+ else
+ {
+ if(searchItem == kItem_Timer)
+ {
+ search->oldOptions.delta = DoEditHexField(search->oldOptions.delta);
+
+ search->oldOptions.delta &= kSearchByteMaskTable[search->bytes];
+ }
+ }
+ }
+
+ if(sel >= 0)
+ posnKeep = sel;
+
+ return sel + 1;
+}
+
+/*-----------------------------------------------------------
+ DoSearchMenuClassic - management for classic search menu
+-----------------------------------------------------------*/
+
+static int DoSearchMenuClassic(int selection)
+{
+ static const char * energyStrings[] =
+ {
+ "Less",
+ "Greater",
+ "Less or Equal",
+ "Greater or Equal",
+ };
+
+ static const char * equalOrNotStrings[] =
+ {
+ "Equal",
+ "Not Equal",
+ };
+
+ static const char * operandStrings[] =
+ {
+ "Previous Data",
+ "First Data",
+ };
+
+ /* conversion table */
+ static const int kEnergyComparisonConversionTable[] =
+ {
+ kSearchComparison_LessThan,
+ kSearchComparison_GreaterThan,
+ kSearchComparison_LessThanOrEqualTo,
+ kSearchComparison_GreaterThanOrEqualTo
+ };
+
+ static const int kEqualOrNotConversionTable[] =
+ {
+ kSearchComparison_EqualTo,
+ kSearchComparison_NotEqual
+ };
+
+ static const int kOperandConversionTable[] =
+ {
+ kSearchOperand_Previous,
+ kSearchOperand_First
+ };
+
+ enum
+ {
+ kMenu_DoMemorySave = 0,
+
+ kMenu_Divider,
+
+ kMenu_CPU,
+ kMenu_ValueEqual,
+ kMenu_ValueNearTo,
+ kMenu_Time,
+ kMenu_Energy,
+ kMenu_Status,
+ kMenu_Operand,
+
+ kMenu_Divider2,
+
+ kMenu_ViewResult,
+ kMenu_RestoreSearch,
+
+ kMenu_Return,
+ };
+
+ enum
+ {
+ kEnergy_Less = 0,
+ kEnergy_Greater,
+ kEnergy_LessOrEqual,
+ kEnergy_GreaterOrEqual,
+ };
+
+ const char * menuItem[kMenu_Return + 2] = { 0 };
+ const char * menuSubItem[kMenu_Return + 2] = { 0 };
+
+ char valueBuffer[60];
+ char valueSignedBuffer[60];
+ char cpuBuffer[20];
+
+ SearchInfo * search = GetCurrentSearch();
+
+ INT32 sel = selection - 1;
+ INT32 total = 0;
+ UINT32 increment = 1;
+ UINT8 doSearch = 0;
+
+ static INT8 submenuChoice = 0;
+ static UINT8 doneSaveMemory = 0;
+ static UINT8 firstEntry = 0;
+ static int lastPos = 0;
+
+ sel = lastPos;
+
+ /********** SUB MENU **********/
+ if(submenuChoice)
+ {
+ switch(sel)
+ {
+ case kMenu_CPU:
+ submenuChoice = SelectSearchRegions(submenuChoice, GetCurrentSearch());
+ break;
+
+ case kMenu_ViewResult:
+ submenuChoice = ViewSearchResults(submenuChoice, firstEntry);
+ break;
+ }
+
+ firstEntry = 0;
+
+ /* ----- meaningless ? because no longer return with sel = -1 (pressed UI_CONFIG in submenu) ----- */
+// if(submenuChoice == -1)
+// submenuChoice = 0;
+
+ return sel + 1;
+ }
+
+ /********** MENU CONSTRUCTION **********/
+ if(!doneSaveMemory)
+ menuItem[total] = "Save Memory";
+ else
+ menuItem[total] = "Initialize Memory";
+
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = "--------------------";
+ menuSubItem[total++] = NULL;
+
+ sprintf(cpuBuffer, "%d", search->targetIdx);
+ menuItem[total] = ui_getstring(UI_cpu);
+ menuSubItem[total++] = cpuBuffer;
+
+ if(search->sign && (search->oldOptions.value & kSearchByteSignBitTable[search->bytes]))
+ {
+ UINT32 tempValue;
+
+ tempValue = ~search->oldOptions.value + 1;
+ tempValue &= kSearchByteUnsignedMaskTable[search->bytes];
+
+ sprintf(valueBuffer, "-%.*X (-%d)", kSearchByteDigitsTable[search->bytes], tempValue, tempValue);
+ }
+ else
+ sprintf(valueBuffer, "%.*X (%d)", kSearchByteDigitsTable[search->bytes], search->oldOptions.value & kSearchByteMaskTable[search->bytes], search->oldOptions.value & kSearchByteMaskTable[search->bytes]);
+
+ menuItem[total] = "Value (Equal)";
+
+ if(sel >= kMenu_ValueNearTo)
+ menuSubItem[total++] = " ";
+ else
+ menuSubItem[total++] = valueBuffer;
+
+ menuItem[total] = "Value (NearTo)";
+
+ if(sel >= kMenu_ValueNearTo)
+ menuSubItem[total++] = valueBuffer;
+ else
+ menuSubItem[total++] = " ";
+
+ menuItem[total] = "Timer (+ or -)";
+ menuSubItem[total++] = " ";
+
+ menuItem[total] = "Energy (Less or Greater)";
+ menuSubItem[total++] = " ";
+
+ menuItem[total] = "Status (Same or Different)";
+ menuSubItem[total++] = " ";
+
+ menuItem[total] = "Comparison Option";
+ menuSubItem[total++] = " ";
+
+ menuItem[total] = "--------------------";
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = ui_getstring(UI_viewresults); // view result
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = ui_getstring(UI_restoreresults); // restore result
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = ui_getstring(UI_returntoprior); // return
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = NULL; // terminate array
+ menuSubItem[total] = NULL;
+
+ /* ----- if memory has been saved, set sub-menu items ----- */
+ if(doneSaveMemory)
+ {
+ if(search->oldOptions.delta & kSearchByteSignBitTable[search->bytes])
+ {
+ UINT32 tempValue;
+
+ tempValue = ~search->oldOptions.delta + 1;
+ tempValue &= kSearchByteUnsignedMaskTable[search->bytes];
+
+ sprintf(valueSignedBuffer, "-%.*X (-%d)", kSearchByteDigitsTable[search->bytes], tempValue, tempValue);
+ }
+ else
+ sprintf(valueSignedBuffer, "%.*X (%d)", kSearchByteDigitsTable[search->bytes], search->oldOptions.delta & kSearchByteMaskTable[search->bytes], search->oldOptions.delta & kSearchByteMaskTable[search->bytes]);
+
+ menuSubItem[kMenu_Time] = valueSignedBuffer;
+ menuSubItem[kMenu_Energy] = energyStrings[search->oldOptions.energy];
+ menuSubItem[kMenu_Status] = equalOrNotStrings[search->oldOptions.status];
+ menuSubItem[kMenu_Operand] = operandStrings[search->oldOptions.operand];
+ }
+
+ /* ----- adjust current cursor position ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel >= total)
+ sel = total - 1;
+
+ /* ----- draw it ----- */
+ old_style_menu(menuItem, menuSubItem, 0, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(AltKeyPressed())
+ increment <<= 4;
+
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ /* ----- if divider, skip it ----- */
+ if((sel == kMenu_Divider) || (sel == kMenu_Divider2))
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ /* ----- if divider, skip it ----- */
+ if((sel == kMenu_Divider) || (sel == kMenu_Divider2))
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalFastKeyRepeatRate))
+ {
+ switch(sel)
+ {
+ case kMenu_CPU:
+ if(search->targetIdx > 0)
+ {
+ search->targetIdx--;
+
+ BuildSearchRegions(search);
+ AllocateSearchRegions(search);
+
+ doneSaveMemory = 0;
+ }
+ break;
+
+ case kMenu_ValueEqual:
+ case kMenu_ValueNearTo:
+ search->oldOptions.value -= increment;
+
+ search->oldOptions.value &= kSearchByteMaskTable[search->bytes];
+ break;
+
+ case kMenu_Time:
+ if(doneSaveMemory)
+ {
+ search->oldOptions.delta -= increment;
+
+ search->oldOptions.delta &= kSearchByteMaskTable[search->bytes];
+ }
+ break;
+
+ case kMenu_Energy:
+ if(doneSaveMemory)
+ {
+ if(search->oldOptions.energy < kEnergy_GreaterOrEqual)
+ search->oldOptions.energy++;
+ else
+ search->oldOptions.energy = kEnergy_Less;
+ }
+ break;
+
+ case kMenu_Status:
+ if(doneSaveMemory)
+ search->oldOptions.status ^= 1;
+ break;
+
+ case kMenu_Operand:
+ if(doneSaveMemory)
+ search->oldOptions.operand ^= 1;
+ break;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalFastKeyRepeatRate))
+ {
+ switch(sel)
+ {
+ case kMenu_CPU:
+ if(search->targetIdx < cpu_gettotalcpu() - 1)
+ {
+ search->targetIdx++;
+
+ BuildSearchRegions(search);
+ AllocateSearchRegions(search);
+
+ doneSaveMemory = 0;
+ }
+ break;
+
+ case kMenu_ValueEqual:
+ case kMenu_ValueNearTo:
+ search->oldOptions.value += increment;
+
+ search->oldOptions.value &= kSearchByteMaskTable[search->bytes];
+ break;
+
+ case kMenu_Time:
+ if(doneSaveMemory)
+ {
+ search->oldOptions.delta += increment;
+
+ search->oldOptions.delta &= kSearchByteMaskTable[search->bytes];
+ }
+ break;
+
+ case kMenu_Energy:
+ if(doneSaveMemory)
+ {
+ if(search->oldOptions.energy > kEnergy_Less)
+ search->oldOptions.energy--;
+ else
+ search->oldOptions.energy = kEnergy_GreaterOrEqual;
+ }
+ break;
+
+ case kMenu_Status:
+ if(doneSaveMemory)
+ search->oldOptions.status ^= 1;
+ break;
+
+ case kMenu_Operand:
+ if(doneSaveMemory)
+ search->oldOptions.operand ^= 1;
+ break;
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ switch(sel)
+ {
+ case kMenu_DoMemorySave: // save memory to search newly
+ doneSaveMemory = 0;
+
+ doSearch = 1;
+ break;
+
+ case kMenu_CPU:
+ submenuChoice = 1; // go to region selection menu
+ break;
+
+ case kMenu_ValueEqual:
+ case kMenu_ValueNearTo:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kSearchOperand_Value;
+
+ if(sel == kMenu_ValueEqual)
+ search->comparison = kSearchComparison_EqualTo; // search requested value
+ else
+ search->comparison = kSearchComparison_NearTo; // search requested and requested -1 value
+
+ search->value = search->oldOptions.value;
+
+ doSearch = 1;
+ break;
+
+ case kMenu_Time:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kOperandConversionTable[search->oldOptions.operand];
+ search->comparison = kSearchComparison_IncreasedBy;
+ search->value = search->oldOptions.delta;
+
+ doSearch = 1;
+ break;
+
+ case kMenu_Energy:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kOperandConversionTable[search->oldOptions.operand];
+ search->comparison = kEnergyComparisonConversionTable[search->oldOptions.energy];
+
+ doSearch = 1;
+ break;
+
+ case kMenu_Status:
+ search->bytes = kSearchSize_8Bit;
+ search->lhs = kSearchOperand_Current;
+ search->rhs = kOperandConversionTable[search->oldOptions.operand];
+ search->comparison = kEqualOrNotConversionTable[search->oldOptions.status];
+
+ doSearch = 1;
+ break;
+
+ case kMenu_ViewResult:
+ if(search->regionListLength)
+ {
+ /* ----- go to result viewer ----- */
+ firstEntry = 1;
+ submenuChoice = 1;
+ }
+ else
+ /* ----- if no search region (eg, sms.c in HazeMD), don't open result viewer to avoid the crash ----- */
+ ui_popup_time(1, "no search regions");
+ break;
+
+ case kMenu_RestoreSearch:
+ /* ----- restore previous results ----- */
+ RestoreSearchBackup(search);
+ break;
+
+ case kMenu_Return:
+ sel = -1;
+ lastPos = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_IN, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : search -> watchpoint list ----- */
+ sel = -5;
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_OUT, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : search -> add/edit ----- */
+ sel = -3;
+
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ {
+ /* ----- if cursor is now on the return item, adjust cursor keeper ----- */
+ if(sel == kMenu_Return)
+ lastPos = 0;
+
+ sel = -1;
+ }
+
+ if(doSearch)
+ {
+ if(!doneSaveMemory)
+ /* ----- initialize search ----- */
+ InitializeNewSearch(search);
+
+ if( (sel == kMenu_ValueEqual) || (sel == kMenu_ValueNearTo) || doneSaveMemory)
+ {
+ /* ----- do search ----- */
+ BackupSearch(search);
+
+ DoSearch(search);
+ }
+
+ UpdateSearch(search);
+
+ if( (sel == kMenu_ValueEqual) || (sel == kMenu_ValueNearTo) || doneSaveMemory)
+ popmessage("%d results found", search->numResults);
+ else
+ popmessage("saved all memory regions");
+
+ doneSaveMemory = 1;
+
+ if(search->numResults == 1)
+ {
+ AddCheatFromFirstResult(search);
+
+ popmessage("1 result found, added to list");
+ }
+ }
+
+ /* ----- edit a value if direct key input ----- */
+ if((sel == kMenu_ValueEqual) || (sel == kMenu_ValueNearTo))
+ {
+ search->oldOptions.value = DoEditHexField(search->oldOptions.value);
+
+ search->oldOptions.value &= kSearchByteMaskTable[search->bytes];
+ }
+ else
+ {
+ if(sel == kMenu_Time)
+ {
+ search->oldOptions.delta = DoEditHexField(search->oldOptions.delta);
+
+ search->oldOptions.delta &= kSearchByteMaskTable[search->bytes];
+ }
+ }
+
+ /* ----- keep current cursor position ----- */
+ if(sel >= 0)
+ lastPos = sel;
+
+ return sel + 1;
+}
+
+/*-----------------------------------------------------
+ DoSearchMenu - management for advanced search menu
+-----------------------------------------------------*/
+
+static int DoSearchMenu(int selection)
+{
+ /* menu stirngs */
+ static const char * kOperandNameTable[] =
+ {
+ "Current Data",
+ "Previous Data",
+ "First Data",
+ "Value"
+ };
+
+ static const char * kComparisonNameTable[] =
+ {
+ "Less",
+ "Greater",
+ "Equal",
+ "Less Or Equal",
+ "Greater Or Equal",
+ "Not Equal",
+ "Increased By Value",
+ "Near To"
+ };
+
+ static const char * kSearchByteNameTable[] =
+ {
+ "1",
+ "2",
+ "3",
+ "4",
+ "Bit"
+ };
+
+ enum
+ {
+ kMenu_LHS,
+ kMenu_Comparison,
+ kMenu_RHS,
+ kMenu_Value,
+
+ kMenu_Divider,
+
+ kMenu_Size,
+ kMenu_Swap,
+ kMenu_Sign,
+ kMenu_CPU,
+ kMenu_Name,
+
+ kMenu_Divider2,
+
+ kMenu_DoSearch,
+ kMenu_SaveMemory,
+
+ kMenu_Divider3,
+
+ kMenu_ViewResult,
+ kMenu_RestoreSearch,
+
+ kMenu_Return,
+
+ kMenu_Max
+ };
+
+ const char * menu_item[kMenu_Max + 2] = { 0 };
+ const char * menu_subitem[kMenu_Max + 2] = { 0 };
+
+ char valueBuffer[20];
+ char cpuBuffer[20];
+ char flagBuf[kMenu_Max + 2] = { 0 };
+
+ SearchInfo * search = GetCurrentSearch();
+
+ INT32 sel = selection - 1;
+ INT32 total = 0;
+ UINT32 increment = 1;
+
+ static INT8 submenuChoice = 0;
+ static UINT8 doneMemorySave = 0;
+ static UINT8 editActive = 0;
+ static UINT8 firstEntry = 0;
+ static int lastSel = 0;
+
+ sel = lastSel;
+
+ /********** SUB MENU **********/
+ if(submenuChoice)
+ {
+ switch(sel)
+ {
+ case kMenu_CPU:
+ submenuChoice = SelectSearchRegions(submenuChoice, GetCurrentSearch());
+ break;
+
+ case kMenu_ViewResult:
+ submenuChoice = ViewSearchResults(submenuChoice, firstEntry);
+ break;
+ }
+
+ firstEntry = 0;
+
+ /* ----- meaningless ? because no longer return with sel = -1 (pressed UI_CONFIG in submenu) ----- */
+// if(submenuChoice == -1)
+// submenuChoice = 0;
+
+ return sel + 1;
+ }
+
+ /********** MENU CONSTRUCION **********/
+ if((search->sign || search->comparison == kSearchComparison_IncreasedBy) && (search->value & kSearchByteSignBitTable[search->bytes]))
+ {
+ UINT32 tempValue;
+
+ tempValue = ~search->value + 1;
+ tempValue &= kSearchByteUnsignedMaskTable[search->bytes];
+
+ sprintf(valueBuffer, "-%.*X", kSearchByteDigitsTable[search->bytes], tempValue);
+ }
+ else
+ sprintf(valueBuffer, "%.*X", kSearchByteDigitsTable[search->bytes], search->value & kSearchByteMaskTable[search->bytes]);
+
+ if(TEST_FIELD(cheatOptions, DontPrintNewLabels))
+ {
+ menu_item[total] = kOperandNameTable[search->lhs];
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = kComparisonNameTable[search->comparison];
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = kOperandNameTable[search->rhs];
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = valueBuffer;
+ menu_subitem[total++] = NULL;
+ }
+ else
+ {
+ menu_item[total] = "LHS";
+ menu_subitem[total++] = kOperandNameTable[search->lhs];
+
+ menu_item[total] = "Comparison";
+ menu_subitem[total++] = kComparisonNameTable[search->comparison];
+
+ menu_item[total] = "RHS";
+ menu_subitem[total++] = kOperandNameTable[search->rhs];
+
+ menu_item[total] = "Value";
+ menu_subitem[total++] = valueBuffer;
+ }
+
+ menu_item[total] = "---";
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = "Size";
+ menu_subitem[total++] = kSearchByteNameTable[search->bytes];
+
+ menu_item[total] = "Swap";
+ menu_subitem[total++] = ui_getstring(search->swap ? UI_on : UI_off);
+
+ menu_item[total] = "Signed";
+ menu_subitem[total++] = ui_getstring(search->sign ? UI_on : UI_off);
+
+ sprintf(cpuBuffer, "%d", search->targetIdx);
+ menu_item[total] = "CPU";
+ menu_subitem[total++] = cpuBuffer;
+
+ menu_item[total] = "Name";
+ if(search->name)
+ menu_subitem[total++] = search->name;
+ else
+ menu_subitem[total++] = "(none)";
+
+ menu_item[total] = "---";
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = "Do Search";
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = "Save Memory";
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = "---";
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = ui_getstring(UI_viewresults); // view result
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = ui_getstring(UI_restoreresults); // restore result
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = ui_getstring(UI_returntoprior); // return
+ menu_subitem[total++] = NULL;
+
+ menu_item[total] = NULL; // terminate array
+ menu_subitem[total] = NULL;
+
+ /* ----- adjust current cursor position ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel >= total)
+ sel = total - 1;
+
+ /* ----- higlighted sub-item if edit mode ----- */
+ if(editActive)
+ flagBuf[sel] = 1;
+
+ /* ----- draw it ----- */
+ old_style_menu(menu_item, menu_subitem, flagBuf, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(AltKeyPressed())
+ increment <<= 4;
+ if(ControlKeyPressed())
+ increment <<= 8;
+ if(ShiftKeyPressed())
+ increment <<= 16;
+
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ /* ----- if divider, skip it ----- */
+ if((sel == kMenu_Divider) || (sel == kMenu_Divider2) || (sel == kMenu_Divider3))
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ /* ----- if divider, skip it ----- */
+ if((sel == kMenu_Divider) || (sel == kMenu_Divider2) || (sel == kMenu_Divider3))
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalFastKeyRepeatRate))
+ {
+ switch(sel)
+ {
+ case kMenu_Value:
+ search->value -= increment;
+
+ search->value &= kSearchByteMaskTable[search->bytes];
+ break;
+
+ case kMenu_LHS:
+ search->lhs--;
+
+ if(search->lhs < kSearchOperand_Current)
+ search->lhs = kSearchOperand_Max;
+ break;
+
+ case kMenu_RHS:
+ search->rhs--;
+
+ if(search->rhs < kSearchOperand_Current)
+ search->rhs = kSearchOperand_Max;
+ break;
+
+ case kMenu_Comparison:
+ search->comparison--;
+
+ if(search->comparison < kSearchComparison_LessThan)
+ search->comparison = kSearchComparison_Max;
+ break;
+
+ case kMenu_Size:
+ search->bytes--;
+
+ if(search->bytes < kSearchSize_8Bit)
+ search->bytes = kSearchSize_Max;
+ break;
+
+ case kMenu_Swap:
+ search->swap ^= 1;
+ break;
+
+ case kMenu_Sign:
+ search->sign ^= 1;
+ break;
+
+ case kMenu_CPU:
+ if(search->targetIdx > 0)
+ {
+ search->targetIdx--;
+
+ BuildSearchRegions(search);
+ AllocateSearchRegions(search);
+
+ doneMemorySave = 0;
+ }
+ break;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalFastKeyRepeatRate))
+ {
+ switch(sel)
+ {
+ case kMenu_Value:
+ search->value += increment;
+
+ search->value &= kSearchByteMaskTable[search->bytes];
+ break;
+
+ case kMenu_Size:
+ search->bytes++;
+
+ if(search->bytes > kSearchSize_Max)
+ search->bytes = kSearchSize_8Bit;
+ break;
+
+ case kMenu_LHS:
+ search->lhs++;
+
+ if(search->lhs > kSearchOperand_Max)
+ search->lhs = kSearchOperand_Current;
+ break;
+
+ case kMenu_RHS:
+ search->rhs++;
+
+ if(search->rhs > kSearchOperand_Max)
+ search->rhs = kSearchOperand_Current;
+ break;
+
+ case kMenu_Comparison:
+ search->comparison++;
+
+ if(search->comparison > kSearchComparison_Max)
+ search->comparison = kSearchComparison_LessThan;
+ break;
+
+ case kMenu_Swap:
+ search->swap ^= 1;
+ break;
+
+ case kMenu_Sign:
+ search->sign ^= 1;
+ break;
+
+ case kMenu_CPU:
+ if(search->targetIdx < cpu_gettotalcpu() - 1)
+ {
+ search->targetIdx++;
+
+ BuildSearchRegions(search);
+ AllocateSearchRegions(search);
+
+ doneMemorySave = 0;
+ }
+ break;
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ if(editActive)
+ editActive = 0;
+ else
+ {
+ switch(sel)
+ {
+ case kMenu_Value: // edit selected field
+ case kMenu_Name:
+ editActive = 1;
+ break;
+
+ case kMenu_CPU: // go to region selection menu
+ submenuChoice = 1;
+ break;
+
+ case kMenu_DoSearch:
+ if(!doneMemorySave)
+ /* ----- initialize search ----- */
+ InitializeNewSearch(search);
+
+ if((!kSearchOperandNeedsInit[search->lhs] && !kSearchOperandNeedsInit[search->rhs]) || doneMemorySave)
+ {
+ BackupSearch(search);
+
+ DoSearch(search);
+ }
+
+ UpdateSearch(search);
+
+ if((!kSearchOperandNeedsInit[search->lhs] && !kSearchOperandNeedsInit[search->rhs]) || doneMemorySave)
+ popmessage("%d results found", search->numResults);
+ else
+ popmessage("saved all memory regions");
+
+ doneMemorySave = 1;
+
+ if(search->numResults == 1)
+ {
+ AddCheatFromFirstResult(search);
+
+ popmessage("1 result found, added to list");
+ }
+ break;
+
+ case kMenu_SaveMemory:
+ InitializeNewSearch(search);
+
+ UpdateSearch(search);
+
+ popmessage("saved all memory regions");
+
+ doneMemorySave = 1;
+ break;
+
+ case kMenu_ViewResult:
+ if(search->regionListLength)
+ {
+ /* ----- go to result viewer ----- */
+ firstEntry = 1;
+ submenuChoice = 1;
+ }
+ else
+ /* ----- if no search region (eg, sms.c in HazeMD), don't open result viewer to avoid the crash ----- */
+ ui_popup_time(1, "no search regions");
+ break;
+
+ case kMenu_RestoreSearch:
+ /* ----- restore previous results ----- */
+ RestoreSearchBackup(search);
+ break;
+
+ case kMenu_Return:
+ submenuChoice = 0;
+ sel = -1;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ /* ----- edit selected field ----- */
+ if(editActive)
+ {
+ switch(sel)
+ {
+ case kMenu_Value:
+ search->value = DoEditHexField(search->value);
+
+ search->value &= kSearchByteMaskTable[search->bytes];
+ break;
+
+ case kMenu_Name:
+ search->name = DoDynamicEditTextField(search->name);
+ break;
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ /* ----- keep current cursor position ----- */
+ if(!(sel == -1))
+ lastSel = sel;
+
+ return sel + 1;
+}
+
+/*---------------------------------------------------------------------
+ SelectSearchRegions - management for search regions selection menu
+---------------------------------------------------------------------*/
+
+static int SelectSearchRegions(int selection, SearchInfo * search)
+{
+ static const char * kSearchSpeedList[] =
+ {
+ "Fast",
+ "Medium",
+ "Slow",
+ "Very Slow",
+ "All Memory"
+ };
+
+ INT32 sel;
+ const char ** menuItem;
+ const char ** menuSubItem;
+ INT32 i;
+ INT32 total = 0;
+ SearchRegion * region;
+
+ if(!search)
+ return 0;
+
+ sel = selection - 1;
+
+ RequestStrings(search->regionListLength + 3, 0, 0, 0);
+
+ /********** MENU CONSTRUCTION **********/
+ menuItem = menuStrings.mainList;
+ menuSubItem = menuStrings.subList;
+
+ for(i = 0; i < search->regionListLength; i++)
+ {
+ SearchRegion * traverse = &search->regionList[i];
+
+ menuItem[total] = traverse->name;
+ menuSubItem[total++] = ui_getstring((traverse->flags & kRegionFlag_Enabled) ? UI_on : UI_off);
+ }
+
+ menuItem[total] = "Search Speed";
+ menuSubItem[total++] = kSearchSpeedList[search->searchSpeed];
+
+ menuItem[total] = ui_getstring(UI_returntoprior); // return item
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = NULL; // terminate array
+ menuSubItem[total] = NULL;
+
+ /* ----- adjust current cursor positon ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel > (total - 1))
+ sel = total - 1;
+
+ if(sel < search->regionListLength)
+ region = &search->regionList[sel];
+ else
+ region = NULL;
+
+ /* ----- draw it ----- */
+ old_style_menu(menuItem, menuSubItem, NULL, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate))
+ {
+ if(sel < search->regionListLength)
+ {
+ search->regionList[sel].flags ^= kRegionFlag_Enabled;
+
+ AllocateSearchRegions(search);
+ }
+
+ if(sel == search->regionListLength) // set search speed
+ {
+ if(search->searchSpeed > kSearchSpeed_Fast)
+ search->searchSpeed--;
+ else
+ search->searchSpeed = kSearchSpeed_Max;
+
+ BuildSearchRegions(search);
+ AllocateSearchRegions(search);
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalSlowKeyRepeatRate))
+ {
+ if(sel < search->regionListLength)
+ {
+ search->regionList[sel].flags ^= kRegionFlag_Enabled;
+
+ AllocateSearchRegions(search);
+ }
+
+ if(sel == search->regionListLength) // set search speed
+ {
+ if(search->searchSpeed < kSearchSpeed_Max)
+ search->searchSpeed++;
+ else
+ search->searchSpeed = kSearchSpeed_Fast;
+
+ BuildSearchRegions(search);
+ AllocateSearchRegions(search);
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT))
+ {
+ if(ShiftKeyPressed()) // shift + delete = invalid region
+ {
+ if(region && search)
+ {
+ InvalidateEntireRegion(search, region);
+
+ ui_popup_time(1, "region invalidated - %d results remain", search->numResults);
+ }
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ if(sel >= total - 1)
+ sel = -1;
+ }
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ return sel + 1;
+}
+
+/*--------------------------------------------------------
+ ViewSearchResults - management for search result menu
+--------------------------------------------------------*/
+
+static int ViewSearchResults(int selection, int firstTime)
+{
+ enum
+ {
+ kMenu_Header = 0,
+ kMenu_FirstResult,
+
+ kMaxResultsPerPage = 100
+ };
+
+ const char ** menu_item;
+ char ** buf;
+ char * header;
+
+ SearchInfo * search = GetCurrentSearch();
+ SearchRegion * region;
+
+ INT32 sel;
+ INT32 total = 0;
+ INT32 numPages;
+ INT32 resultsPerPage;
+ INT32 i;
+ UINT32 traverse;
+ UINT8 hadResults = 0;
+ INT32 numToSkip;
+ UINT32 resultsFound = 0;
+ UINT32 selectedAddress = 0;
+ UINT32 selectedOffset = 0;
+ UINT8 selectedAddressGood = 0;
+ int goToNextPage = 0;
+ int goToPrevPage = 0;
+
+ RequestStrings(kMaxResultsPerPage + 3, kMaxResultsPerPage + 3, 80, 0);
+
+ menu_item = menuStrings.mainList;
+ buf = &menuStrings.mainStrings[1];
+ header = menuStrings.mainStrings[0];
+
+ sel = selection - 1;
+
+ /********** FIRST SETTING **********/
+ if(firstTime)
+ {
+ search->currentRegionIdx = 0;
+ search->currentResultsPage = 0;
+
+ /* ----- set current REGION for first display ----- */
+ for(traverse = 0; traverse < search->regionListLength; traverse++)
+ {
+ region = &search->regionList[traverse];
+
+ if(region->numResults)
+ {
+ search->currentRegionIdx = traverse;
+ break;
+ }
+ }
+ }
+
+ /* ----- adjust current REGION ----- */
+ if(search->currentRegionIdx >= search->regionListLength)
+ search->currentRegionIdx = search->regionListLength - 1;
+ if(search->currentRegionIdx < 0)
+ search->currentRegionIdx = 0;
+
+ region = &search->regionList[search->currentRegionIdx];
+
+ /* ----- set and adjust maximum displayable result in the PAGE ----- */
+ resultsPerPage = fullMenuPageHeight - 3;
+
+ if(resultsPerPage <= 0)
+ resultsPerPage = 1;
+ else if(resultsPerPage > kMaxResultsPerPage)
+ resultsPerPage = kMaxResultsPerPage;
+
+ /* ----- get the number of total page ----- */
+ if(region->flags & kRegionFlag_Enabled)
+ numPages = (region->numResults / kSearchByteStep[search->bytes] + resultsPerPage - 1) / resultsPerPage;
+ else
+ numPages = 0;
+
+ /* ----- adjust current PAGE ----- */
+ if(search->currentResultsPage >= numPages)
+ search->currentResultsPage = numPages - 1;
+ if(search->currentResultsPage < 0)
+ search->currentResultsPage = 0;
+
+ /* ----- set the number of undisplay result ----- */
+ numToSkip = resultsPerPage * search->currentResultsPage;
+
+ /********** MENU CONSTRUCTION **********/
+ /* ----- construct header item ----- */
+ sprintf(header, "%s %d/%d", region->name, search->currentResultsPage + 1, numPages);
+
+ menu_item[total++] = header;
+
+ traverse = 0;
+
+ if((region->length < kSearchByteIncrementTable[search->bytes]) || !(region->flags & kRegionFlag_Enabled))
+ ; // no results...
+ else
+ {
+ /* ----- construct result item ----- */
+ for(i = 0; (i < resultsPerPage) && (traverse < region->length) && (resultsFound < region->numResults);)
+ {
+ while(!IsRegionOffsetValid(search, region, traverse) && (traverse < region->length))
+ traverse += kSearchByteStep[search->bytes];
+
+ if(traverse < region->length)
+ {
+ if(numToSkip > 0)
+ numToSkip--;
+ else
+ {
+ if(total == sel)
+ {
+ selectedAddress = region->address + traverse;
+ selectedOffset = traverse;
+ selectedAddressGood = 1;
+ }
+
+ sprintf( buf[total],
+ "%.8X (%.*X %.*X %.*X)",
+ region->address + traverse,
+ kSearchByteDigitsTable[search->bytes],
+ ReadSearchOperand(kSearchOperand_First, search, region, region->address + traverse),
+ kSearchByteDigitsTable[search->bytes],
+ ReadSearchOperand(kSearchOperand_Previous, search, region, region->address + traverse),
+ kSearchByteDigitsTable[search->bytes],
+ ReadSearchOperand(kSearchOperand_Current, search, region, region->address + traverse));
+
+ menu_item[total] = buf[total];
+ total++;
+
+ i++;
+ }
+
+ traverse += kSearchByteStep[search->bytes];
+ resultsFound++;
+ hadResults = 1;
+ }
+ }
+ }
+
+ /* ----- set special message if empty REGION ----- */
+ if(!hadResults)
+ {
+ if(search->numResults)
+ menu_item[total++] = "no results for this region";
+ else
+ menu_item[total++] = "no results found";
+ }
+
+ menu_item[total++] = ui_getstring(UI_returntoprior); // return
+
+ menu_item[total] = NULL; // terminate array
+
+ /* ----- adjust current cursor position ----- */
+ if(sel <= kMenu_Header)
+ sel = kMenu_FirstResult;
+ if(sel > (total - 1) || !hadResults)
+ sel = total - 1;
+
+ /* ----- draw it ----- */
+ old_style_menu(menu_item, NULL, NULL, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ if(sel >= total)
+ sel = kMenu_FirstResult;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ if(sel < 1)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalFastKeyRepeatRate))
+ {
+ if(ShiftKeyPressed())
+ search->currentResultsPage = numPages - 1; // shift + right = go to last PAGE
+ else
+ {
+ if(ControlKeyPressed())
+ {
+ search->currentRegionIdx++; // ctrl + right = go to next REGION
+
+ if(search->currentRegionIdx >= search->regionListLength)
+ search->currentRegionIdx = 0;
+ }
+ else
+ goToNextPage = 1; // right = go to next PAGE
+ }
+
+ sel = kMenu_FirstResult;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalFastKeyRepeatRate))
+ {
+ if(ShiftKeyPressed())
+ search->currentResultsPage = 0; // shift + left = go to first PAGE
+ else
+ {
+ if(ControlKeyPressed())
+ {
+ search->currentRegionIdx--; // ctrl + left = go to previous REGION
+
+ if(search->currentRegionIdx < 0)
+ search->currentRegionIdx = search->regionListLength - 1;
+ }
+ else
+ goToPrevPage = 1; // left = go to previous PAGE
+ }
+
+ sel = kMenu_FirstResult;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kHorizontalFastKeyRepeatRate))
+ {
+ sel -=fullMenuPageHeight;
+
+ if(sel <= kMenu_Header)
+ sel = kMenu_FirstResult;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kHorizontalFastKeyRepeatRate))
+ {
+ sel +=fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+ }
+
+ if(input_code_pressed_once(KEYCODE_END))
+ search->currentResultsPage = numPages - 1; // go to last PAGE
+
+ if(input_code_pressed_once(KEYCODE_HOME))
+ search->currentResultsPage = 0; // go to first PAGE
+
+ if(UIPressedRepeatThrottle(IPT_UI_PREV_GROUP, kVerticalKeyRepeatRate))
+ {
+ search->currentRegionIdx--; // go to previous REGION
+
+ if(search->currentRegionIdx < 0)
+ search->currentRegionIdx = search->regionListLength - 1;
+
+ sel = kMenu_FirstResult;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_NEXT_GROUP, kVerticalKeyRepeatRate))
+ {
+ search->currentRegionIdx++; // go to next REGION
+
+ if(search->currentRegionIdx >= search->regionListLength)
+ search->currentRegionIdx = 0;
+
+ sel = kMenu_FirstResult;
+ }
+
+ if(goToNextPage)
+ {
+ search->currentResultsPage++;
+
+ /* ----- if current PAGE is the last, go to first PAGE in next REGION ----- */
+ if(search->currentResultsPage >= numPages)
+ {
+ search->currentResultsPage = 0;
+ search->currentRegionIdx++;
+
+ /* ----- if current REGION is the last, go to first REGION ----- */
+ if(search->currentRegionIdx >= search->regionListLength)
+ search->currentRegionIdx = 0;
+
+ /* ----- if next REGION is empty, search next "non-empty" REGION.
+ but incomplete because last REGION is displayed even if empty ----- */
+ for(traverse = search->currentRegionIdx; traverse < search->regionListLength; traverse++)
+ {
+ search->currentRegionIdx = traverse;
+
+ if(search->regionList[traverse].numResults)
+ break;
+ }
+ }
+
+ sel = kMenu_FirstResult;
+ }
+
+ if(goToPrevPage)
+ {
+ search->currentResultsPage--;
+
+ /* ----- if current PAGE is first, go to previous REGION ----- */
+ if(search->currentResultsPage < 0)
+ {
+ search->currentResultsPage = 0;
+ search->currentRegionIdx--;
+
+ /* ----- if current REGION is first, go to last REGION ----- */
+ if(search->currentRegionIdx < 0)
+ search->currentRegionIdx = search->regionListLength - 1;
+
+ /* ----- if previous REGION is empty, search previous "non-empty" REGION.
+ but incomplete because first REGION is displayed even if empty ----- */
+ for(i = search->currentRegionIdx; i >= 0; i--)
+ {
+ search->currentRegionIdx = i;
+
+ if(search->regionList[i].numResults)
+ break;
+ }
+
+ /* ----- go to last PAGE in previous REGION ----- */
+ {
+ /* ----- get the number of total page for previous REGION ----- */
+ SearchRegion * newRegion = &search->regionList[search->currentRegionIdx];
+ UINT32 nextNumPages = (newRegion->numResults / kSearchByteStep[search->bytes] + resultsPerPage - 1) / resultsPerPage;
+
+ if(nextNumPages <= 0)
+ nextNumPages = 1;
+
+ search->currentResultsPage = nextNumPages - 1;
+ }
+ }
+
+ sel = kMenu_FirstResult;
+ }
+
+ if(selectedAddressGood)
+ {
+ if(input_ui_pressed(IPT_UI_WATCH_VALUE))
+ AddWatchFromResult(search, region, selectedAddress); // watch selected result
+
+ if(input_ui_pressed(IPT_UI_ADD_CHEAT))
+ AddCheatFromResult(search, region, selectedAddress); // add selected result as new code to cheat list
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT))
+ {
+ InvalidateRegionOffset(search, region, selectedOffset); // delete selected result
+ search->numResults--;
+ region->numResults--;
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT))
+ {
+ if(ShiftKeyPressed())
+ {
+ if(region && search)
+ {
+ InvalidateEntireRegion(search, region); // invalidate all results in current REGION
+
+ ui_popup_time(1, "region invalidated - %d results remain", search->numResults);
+ }
+ }
+ }
+
+ if((input_ui_pressed(IPT_UI_SELECT) && (sel == total - 1)) || input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ return sel + 1;
+}
+
+/*----------------------------------------------------
+ ChooseWatch - management for watchpoint list menu
+----------------------------------------------------*/
+
+static int ChooseWatch(int selection)
+{
+ const char ** menuItem;
+ char ** buf;
+
+ WatchInfo * watch;
+
+ static INT32 submenuChoice = 0;
+ static INT32 submenuWatch = 0;
+ INT32 sel;
+ INT32 total = 0;
+ int i;
+
+ RequestStrings(watchListLength + 2, watchListLength, 30, 0);
+
+ menuItem = menuStrings.mainList;
+ buf = menuStrings.mainStrings;
+
+ sel = selection - 1;
+
+ /********** SUB MENU **********/
+ if(submenuChoice)
+ {
+ submenuChoice = EditWatch(&watchList[submenuWatch], submenuChoice);
+
+ /* ----- meaningless ? because no longer return with sel = -1 (pressed UI_CONFIG in submenu) ----- */
+// if(submenuChoice == -1)
+// {
+// submenuChoice = 0;
+// sel = -2;
+// }
+
+ return sel + 1;
+ }
+
+ /********** MENU CONSTRUCTION **********/
+ for(i = 0; i < watchListLength; i++)
+ {
+ WatchInfo * traverse = &watchList[i];
+
+ sprintf(buf[i], "%d:%.*X (%d)", traverse->cpu, cpuInfoList[traverse->cpu].addressCharsNeeded, traverse->address, traverse->numElements);
+
+ menuItem[total] = buf[i];
+ total++;
+ }
+
+ menuItem[total++] = ui_getstring(UI_returntoprior); // return
+
+ menuItem[total] = NULL; // terminate array
+
+ /* ----- adjust current cursor position ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel >= total)
+ sel = total - 1;
+
+ /* ----- draw it ----- */
+ old_style_menu(menuItem, NULL, NULL, sel, 0);
+
+ if(sel < watchListLength)
+ watch = &watchList[sel];
+ else
+ watch = NULL;
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+ }
+
+ if(ShiftKeyPressed())
+ {
+ if(input_ui_pressed(IPT_UI_ADD_CHEAT)) // shift + add = add new watchpoint
+ AddWatchBefore(sel);
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT)) // shift + delete = delete selected watchpoint
+ DeleteWatchAt(sel);
+ }
+ else
+ {
+ if(input_ui_pressed(IPT_UI_SAVE_CHEAT)) // save = save selected watchpoint as watchpoint code
+ {
+ if(watch)
+ {
+ CheatEntry entry;
+
+ memset(&entry, 0, sizeof(CheatEntry));
+
+ SetupCheatFromWatchAsWatch(&entry, watch);
+ SaveCheat(&entry, 0, 0);
+ DisposeCheat(&entry);
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_ADD_CHEAT))
+ {
+ if(watch)
+ {
+ if(ControlKeyPressed()) // ctrl + add = add selected watchpoing as watchpoint code to cheat list
+ {
+ CheatEntry * entry = GetNewCheat();
+
+ DisposeCheat(entry);
+ SetupCheatFromWatchAsWatch(entry, watch);
+ }
+ else
+ AddCheatFromWatch(watch); // add = add selected watchpoint as cheat code to cheat list
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT))
+ {
+ if(ControlKeyPressed())
+ {
+ for(i = 0; i < watchListLength; i++) // ctrl + delete = disable all watchpoints
+ watchList[i].numElements = 0;
+ }
+ else
+ {
+ if(watch) // delete = disable selected watchpoint
+ watch->numElements = 0;
+ }
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_EDIT_CHEAT)) // edit = edit selected watchpoint
+ {
+ if(sel < (total - 1))
+ {
+ submenuWatch = sel;
+ submenuChoice = 1;
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ if(sel == (total - 1)) // return previous menu
+ {
+ submenuChoice = 0;
+ sel = -1;
+ }
+ else
+ {
+ if(sel < (total - 1)) // edit selected watchpoint (same as edit key)
+ {
+ submenuWatch = sel;
+ submenuChoice = 1;
+ }
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_CLEAR))
+ {
+ /* ----- reset all watchpoints ----- */
+ for(i = 0; i < watchListLength; i++)
+ {
+ if(watch)
+ {
+ watchList[i].address = 0;
+ watchList[i].cpu = 0;
+ watchList[i].numElements = 0;
+ watchList[i].elementBytes = kWatchSizeConversionTable[0];
+ watchList[i].labelType = kWatchLabel_None;
+ watchList[i].displayType = kWatchDisplayType_Hex;
+ watchList[i].skip = 0;
+ watchList[i].elementsPerLine = 0;
+ watchList[i].addValue = 0;
+
+ watchList[i].linkedCheat = NULL;
+
+ watchList[i].label[0] = 0;
+ }
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_IN, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : watchpoint list -> enable/disable ----- */
+ sel = -2;
+
+ if(UIPressedRepeatThrottle(IPT_UI_ZOOM_OUT, kVerticalKeyRepeatRate))
+ /* ----- quick menu switch : watchpoint list -> search ----- */
+ sel = -4;
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ return sel + 1;
+}
+
+/*--------------------------------------------------
+ EditWatch - management for watchpoint edit menu
+--------------------------------------------------*/
+
+static int EditWatch(WatchInfo * entry, int selection)
+{
+ enum
+ {
+ kMenu_Address = 0,
+ kMenu_CPU,
+ kMenu_NumElements,
+ kMenu_ElementSize,
+ kMenu_LabelType,
+ kMenu_TextLabel,
+ kMenu_DisplayType,
+ kMenu_XPosition,
+ kMenu_YPosition,
+ kMenu_Skip,
+ kMenu_ElementsPerLine,
+ kMenu_AddValue,
+ kMenu_AddressShift,
+ kMenu_DataShift,
+ kMenu_XOR,
+
+ kMenu_Return
+ };
+
+ static const char * kWatchSizeStringList[] =
+ {
+ "8 Bit",
+ "16 Bit",
+ "24 Bit",
+ "32 Bit"
+ };
+
+ const char ** menuItem;
+ const char ** menuSubItem;
+ char ** buf;
+ char * flagBuf;
+
+ INT32 sel;
+ INT32 total = 0;
+ UINT32 increment = 1;
+ static UINT8 editActive = 0;
+
+ /* ----- if no watch entry, direct return ----- */
+ if(!entry)
+ return 0;
+
+ RequestStrings(kMenu_Return + 2, kMenu_Return, 0, 20);
+
+ menuItem = menuStrings.mainList;
+ menuSubItem = menuStrings.subList;
+ buf = menuStrings.subStrings;
+ flagBuf = menuStrings.flagList;
+
+ memset(flagBuf, 0, kMenu_Return + 2);
+
+ sel = selection - 1;
+
+ /********** MENU CONSTRUCTION **********/
+ sprintf(buf[total], "%.*X", cpuInfoList[entry->cpu].addressCharsNeeded, entry->address >> entry->addressShift);
+ menuItem[total] = "Address";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ sprintf(buf[total], "%d", entry->cpu);
+ menuItem[total] = "CPU";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ sprintf(buf[total], "%d", entry->numElements);
+ menuItem[total] = "Length";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ menuItem[total] = "Element Size";
+ menuSubItem[total++] = kWatchSizeStringList[entry->elementBytes];
+
+ menuItem[total] = "Label Type";
+ menuSubItem[total++] = kWatchLabelStringList[entry->labelType];
+
+ menuItem[total] = "Text Label";
+ if(entry->label[0])
+ menuSubItem[total++] = entry->label;
+ else
+ menuSubItem[total++] = "(none)";
+
+ menuItem[total] = "Display Type";
+ menuSubItem[total++] = kWatchDisplayTypeStringList[entry->displayType];
+
+ sprintf(buf[total], "%f", entry->x);
+ menuItem[total] = "X";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ sprintf(buf[total], "%f", entry->y);
+ menuItem[total] = "Y";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ sprintf(buf[total], "%d", entry->skip);
+ menuItem[total] = "Skip Bytes";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ sprintf(buf[total], "%d", entry->elementsPerLine);
+ menuItem[total] = "Elements Per Line";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ if(entry->addValue < 0)
+ sprintf(buf[total], "-%.2X", -entry->addValue);
+ else
+ sprintf(buf[total], "%.2X", entry->addValue);
+
+ menuItem[total] = "Add Value";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ sprintf(buf[total], "%d", entry->addressShift);
+ menuItem[total] = "Address Shift";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ sprintf(buf[total], "%d", entry->dataShift);
+ menuItem[total] = "Data Shift";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ sprintf(buf[total], "%.*X", kSearchByteDigitsTable[kWatchSizeConversionTable[entry->elementBytes]], entry->xor);
+ menuItem[total] = "XOR";
+ menuSubItem[total] = buf[total];
+ total++;
+
+ menuItem[total] = ui_getstring(UI_returntoprior); // return
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = NULL; // terminate array
+ menuSubItem[total] = NULL;
+
+ /* ----- adjust current cursor position ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel >= total)
+ sel = total - 1;
+
+ /* ----- higlighted sub-item if edit mode ----- */
+ if(editActive)
+ flagBuf[sel] = 1;
+
+ /* ----- draw it ----- */
+ old_style_menu(menuItem, menuSubItem, flagBuf, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(AltKeyPressed())
+ increment <<= 4;
+ if(ControlKeyPressed())
+ increment <<= 8;
+ if(ShiftKeyPressed())
+ increment <<= 16;
+
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate))
+ {
+ editActive = 0;
+
+ switch(sel)
+ {
+ case kMenu_Address:
+ entry->address = DoShift(entry->address, entry->addressShift);
+ entry->address -= increment;
+ entry->address = DoShift(entry->address, -entry->addressShift);
+
+ if(entry->locationType != kLocation_MemoryRegion)
+ entry->address &= cpuInfoList[entry->cpu].addressMask;
+
+ break;
+
+ case kMenu_CPU:
+ entry->cpu--;
+
+ if(entry->cpu >= cpu_gettotalcpu())
+ entry->cpu = cpu_gettotalcpu() - 1;
+
+ entry->address &= cpuInfoList[entry->cpu].addressMask;
+ break;
+
+ case kMenu_NumElements:
+ if(entry->numElements > 0)
+ entry->numElements--;
+ else
+ entry->numElements = 0;
+ break;
+
+ case kMenu_ElementSize:
+ if(entry->elementBytes > 0)
+ entry->elementBytes--;
+ else
+ entry->elementBytes = 0;
+
+ entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]];
+ break;
+
+ case kMenu_LabelType:
+ if(entry->labelType > 0)
+ entry->labelType--;
+ else
+ entry->labelType = 0;
+ break;
+
+ case kMenu_TextLabel:
+ break;
+
+ case kMenu_DisplayType:
+ if(entry->displayType > 0)
+ entry->displayType--;
+ else
+ entry->displayType = 0;
+ break;
+
+ case kMenu_XPosition:
+ entry->x -= 0.01;
+ break;
+
+ case kMenu_YPosition:
+ entry->y -= 0.01;
+ break;
+
+ case kMenu_Skip:
+ if(entry->skip > 0)
+ entry->skip--;
+ break;
+
+ case kMenu_ElementsPerLine:
+ if(entry->elementsPerLine > 0)
+ entry->elementsPerLine--;
+ break;
+
+ case kMenu_AddValue:
+ entry->addValue = (entry->addValue - 1) & 0xFF;
+ break;
+
+ case kMenu_AddressShift:
+ if(entry->addressShift > -31)
+ entry->addressShift--;
+ else
+ entry->addressShift = 31;
+ break;
+
+ case kMenu_DataShift:
+ if(entry->dataShift > -31)
+ entry->dataShift--;
+ else
+ entry->dataShift = 31;
+ break;
+
+ case kMenu_XOR:
+ entry->xor -= increment;
+ entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]];
+ break;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalSlowKeyRepeatRate))
+ {
+ editActive = 0;
+
+ switch(sel)
+ {
+ case kMenu_Address:
+ entry->address = DoShift(entry->address, entry->addressShift);
+ entry->address += increment;
+ entry->address = DoShift(entry->address, -entry->addressShift);
+ entry->address &= cpuInfoList[entry->cpu].addressMask;
+ break;
+
+ case kMenu_CPU:
+ entry->cpu++;
+
+ if(entry->cpu >= cpu_gettotalcpu())
+ entry->cpu = 0;
+
+ entry->address &= cpuInfoList[entry->cpu].addressMask;
+ break;
+
+ case kMenu_NumElements:
+ entry->numElements++;
+ break;
+
+ case kMenu_ElementSize:
+ if(entry->elementBytes < kSearchSize_32Bit)
+ entry->elementBytes++;
+ else
+ entry->elementBytes = kSearchSize_32Bit;
+
+ entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]];
+ break;
+
+ case kMenu_LabelType:
+ if(entry->labelType < kWatchLabel_MaxPlusOne - 1)
+ entry->labelType++;
+ else
+ entry->labelType = kWatchLabel_MaxPlusOne - 1;
+ break;
+
+ case kMenu_TextLabel:
+ break;
+
+ case kMenu_DisplayType:
+ if(entry->displayType < kWatchDisplayType_MaxPlusOne - 1)
+ entry->displayType++;
+ else
+ entry->displayType = kWatchDisplayType_MaxPlusOne - 1;
+ break;
+
+ case kMenu_XPosition:
+ entry->x += 0.01;
+ break;
+
+ case kMenu_YPosition:
+ entry->y += 0.01;
+ break;
+
+ case kMenu_Skip:
+ entry->skip++;
+ break;
+
+ case kMenu_ElementsPerLine:
+ entry->elementsPerLine++;
+ break;
+
+ case kMenu_AddValue:
+ entry->addValue = (entry->addValue + 1) & 0xFF;
+ break;
+
+ case kMenu_AddressShift:
+ if(entry->addressShift < 31)
+ entry->addressShift++;
+ else
+ entry->addressShift = -31;
+ break;
+
+ case kMenu_DataShift:
+ if(entry->dataShift < 31)
+ entry->dataShift++;
+ else
+ entry->dataShift = -31;
+ break;
+
+ case kMenu_XOR:
+ entry->xor += increment;
+ entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]];
+ break;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+
+ editActive = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+
+ editActive = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+
+ editActive = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+
+ editActive = 0;
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ if(editActive)
+ editActive = 0;
+ else
+ {
+ switch(sel)
+ {
+ case kMenu_Return:
+ sel = -1;
+ break;
+
+ case kMenu_Address:
+ case kMenu_CPU:
+ case kMenu_NumElements:
+ case kMenu_TextLabel:
+ case kMenu_XPosition:
+ case kMenu_YPosition:
+ case kMenu_AddValue:
+ case kMenu_AddressShift:
+ case kMenu_DataShift:
+ case kMenu_XOR:
+ osd_readkey_unicode(1);
+ editActive = 1;
+ }
+ }
+ }
+
+ if(editActive)
+ {
+ switch(sel)
+ {
+ case kMenu_Address:
+ entry->address = DoShift(entry->address, entry->addressShift);
+ entry->address = DoEditHexField(entry->address);
+ entry->address = DoShift(entry->address, -entry->addressShift);
+ entry->address &= cpuInfoList[entry->cpu].addressMask;
+ break;
+
+ case kMenu_CPU:
+ entry->cpu = DoEditDecField(entry->cpu, 0, cpu_gettotalcpu() - 1);
+ entry->address &= cpuInfoList[entry->cpu].addressMask;
+ break;
+
+ case kMenu_NumElements:
+ entry->numElements = DoEditDecField(entry->numElements, 0, 99);
+ break;
+
+ case kMenu_TextLabel:
+ DoStaticEditTextField(entry->label, 255);
+ break;
+
+ case kMenu_XPosition:
+ entry->x = DoEditDecField(entry->x, -1000, 1000);
+ break;
+
+ case kMenu_YPosition:
+ entry->y = DoEditDecField(entry->y, -1000, 1000);
+ break;
+
+ case kMenu_AddValue:
+ entry->addValue = DoEditHexFieldSigned(entry->addValue, 0xFFFFFF80) & 0xFF;
+ break;
+
+ case kMenu_AddressShift:
+ entry->addressShift = DoEditDecField(entry->addressShift, -31, 31);
+ break;
+
+ case kMenu_DataShift:
+ entry->dataShift = DoEditDecField(entry->dataShift, -31, 31);
+ break;
+
+ case kMenu_XOR:
+ entry->xor = DoEditHexField(entry->xor);
+ entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]];
+ break;
+ }
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ editActive = 0;
+ }
+ else
+ {
+ if(input_ui_pressed(IPT_UI_ADD_CHEAT))
+ AddCheatFromWatch(entry);
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT))
+ entry->numElements = 0;
+
+ if(input_ui_pressed(IPT_UI_SAVE_CHEAT))
+ {
+ CheatEntry tempEntry;
+
+ memset(&tempEntry, 0, sizeof(CheatEntry));
+
+ SetupCheatFromWatchAsWatch(&tempEntry, entry);
+ SaveCheat(&tempEntry, 0, 0);
+ DisposeCheat(&tempEntry);
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ return sel + 1;
+}
+
+/*----------------------------------------------
+ SelectOptions - management for options menu
+----------------------------------------------*/
+
+static int SelectOptions(int selection)
+{
+ enum
+ {
+ kMenu_SelectSearch = 0,
+ kMenu_SearchDialogStyle,
+ kMenu_ShowSearchLabels,
+ kMenu_AutoSaveCheats,
+ kMenu_ShowActivationKeyMessage,
+ kMenu_LoadOldFormat,
+ kMenu_Debug,
+ kMenu_Return,
+
+ kMenu_Max
+ };
+
+ INT32 sel;
+ static INT32 submenuChoice = 0;
+ const char * menuItem[kMenu_Max + 1];
+ const char * menuSubItem[kMenu_Max + 1];
+ int total = 0;
+
+ sel = selection - 1;
+
+ /********** SUB MENU **********/
+ if(submenuChoice)
+ {
+ switch(sel)
+ {
+ case kMenu_SelectSearch:
+ submenuChoice = SelectSearch(submenuChoice);
+ break;
+
+ default:
+ submenuChoice = 0;
+ sel = -1;
+ break;
+ }
+
+ if(submenuChoice == -1)
+ submenuChoice = 0;
+
+ return sel + 1;
+ }
+
+ /********** MENU CONSTRUCTION **********/
+ menuItem[total] = "Select Search";
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = "Search Dialog Style";
+ switch(EXTRACT_FIELD(cheatOptions, SearchBox))
+ {
+ case kSearchBox_Minimum:
+ menuSubItem[total++] = "Minimum";
+ break;
+
+ case kSearchBox_Classic:
+ menuSubItem[total++] = "Classic";
+ break;
+
+ case kSearchBox_Advanced:
+ menuSubItem[total++] = "Advanced";
+ break;
+ }
+
+ menuItem[total] = "Show Search Labels";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(cheatOptions, DontPrintNewLabels) ? UI_off : UI_on);
+
+ menuItem[total] = "Auto Save Cheats";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(cheatOptions, AutoSaveEnabled) ? UI_on : UI_off);
+
+ menuItem[total] = "Show Activation Key Message";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(cheatOptions, ActivationKeyMessage) ? UI_on : UI_off);
+
+ menuItem[total] = "Load Old Format Code";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(cheatOptions, LoadOldFormat) ? UI_on : UI_off);
+
+ menuItem[total] = "Debug";
+ menuSubItem[total++] = ui_getstring(TEST_FIELD(cheatOptions, Debug) ? UI_on : UI_off);
+
+ menuItem[total] = ui_getstring(UI_returntoprior); // return
+ menuSubItem[total++] = NULL;
+
+ menuItem[total] = NULL; // terminate array
+ menuSubItem[total] = NULL;
+
+ /* ----- draw it ----- */
+ old_style_menu(menuItem, menuSubItem, NULL, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalSlowKeyRepeatRate))
+ {
+ switch(sel)
+ {
+ case kMenu_SearchDialogStyle:
+ {
+ UINT8 length = (EXTRACT_FIELD(cheatOptions, SearchBox) + 1) & 3;
+
+ if(length > kSearchBox_Advanced)
+ length = kSearchBox_Minimum;
+
+ SET_FIELD(cheatOptions, SearchBox, length);
+ }
+ break;
+
+ case kMenu_ShowSearchLabels:
+ TOGGLE_MASK_FIELD(cheatOptions, DontPrintNewLabels);
+ break;
+
+ case kMenu_AutoSaveCheats:
+ TOGGLE_MASK_FIELD(cheatOptions, AutoSaveEnabled);
+ break;
+
+ case kMenu_ShowActivationKeyMessage:
+ TOGGLE_MASK_FIELD(cheatOptions, ActivationKeyMessage);
+ break;
+
+ case kMenu_LoadOldFormat:
+ TOGGLE_MASK_FIELD(cheatOptions, LoadOldFormat);
+ break;
+
+ case kMenu_Debug:
+ TOGGLE_MASK_FIELD(cheatOptions, Debug);
+ break;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate))
+ {
+ switch(sel)
+ {
+ case kMenu_SearchDialogStyle:
+ {
+ UINT8 length = (EXTRACT_FIELD(cheatOptions, SearchBox) - 1) & 3;
+
+ if(length > kSearchBox_Advanced)
+ length = kSearchBox_Advanced;
+
+ SET_FIELD(cheatOptions, SearchBox, length);
+ }
+ break;
+
+ case kMenu_ShowSearchLabels:
+ TOGGLE_MASK_FIELD(cheatOptions, DontPrintNewLabels);
+ break;
+
+ case kMenu_AutoSaveCheats:
+ TOGGLE_MASK_FIELD(cheatOptions, AutoSaveEnabled);
+ break;
+
+ case kMenu_ShowActivationKeyMessage:
+ TOGGLE_MASK_FIELD(cheatOptions, ActivationKeyMessage);
+ break;
+
+ case kMenu_LoadOldFormat:
+ TOGGLE_MASK_FIELD(cheatOptions, LoadOldFormat);
+ break;
+
+ case kMenu_Debug:
+ TOGGLE_MASK_FIELD(cheatOptions, Debug);
+ break;
+ }
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ if(sel < (kMenu_Max - 1))
+ sel++;
+ else
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ if(sel > 0)
+ sel--;
+ else
+ sel = kMenu_Max - 1;
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ switch(sel)
+ {
+ case kMenu_Return:
+ submenuChoice = 0;
+ sel = -1;
+ break;
+
+ case kMenu_SelectSearch:
+ submenuChoice = 1;
+ break;
+ }
+ }
+
+ if(input_ui_pressed(IPT_UI_SAVE_CHEAT))
+ {
+ SaveCheat(NULL, 0, 2);
+
+ ui_popup_time(1, "command code saved");
+ }
+
+ if(input_ui_pressed(IPT_UI_RELOAD_CHEAT))
+ ReloadCheatDatabase();
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ return sel + 1;
+}
+
+/*------------------------------------------------------
+ SelectSearch - management for search selection menu
+------------------------------------------------------*/
+
+static int SelectSearch(int selection)
+{
+ INT32 sel;
+ const char ** menuItem;
+ char ** buf;
+ INT32 i;
+ INT32 total = 0;
+
+ sel = selection - 1;
+
+ RequestStrings(searchListLength + 2, searchListLength, 300, 0);
+
+ menuItem = menuStrings.mainList;
+ buf = menuStrings.mainStrings;
+
+ /********** MENU CONSTRUCTION **********/
+ for(i = 0; i < searchListLength; i++)
+ {
+ SearchInfo * info = &searchList[i];
+
+ if(i == currentSearchIdx)
+ {
+ if(info->name)
+ sprintf(buf[total], "[#%d: %s]", i, info->name);
+ else
+ sprintf(buf[total], "[#%d]", i);
+ }
+ else
+ {
+ if(info->name)
+ sprintf(buf[total], "#%d: %s", i, info->name);
+ else
+ sprintf(buf[total], "#%d", i);
+ }
+
+ menuItem[total] = buf[total];
+ total++;
+ }
+
+ menuItem[total++] = ui_getstring(UI_returntoprior); // return
+
+ menuItem[total] = NULL; // terminate array
+
+ /* ----- adjust current cursor position ----- */
+ if(sel < 0)
+ sel = 0;
+ if(sel > (total - 1))
+ sel = total - 1;
+
+ /* ----- draw it ----- */
+ old_style_menu(menuItem, NULL, NULL, sel, 0);
+
+ /********** KEY HANDLING **********/
+ if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel++;
+
+ if(sel >= total)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
+ {
+ sel--;
+
+ if(sel < 0)
+ sel = total - 1;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_UP, kVerticalKeyRepeatRate))
+ {
+ sel -= fullMenuPageHeight;
+
+ if(sel < 0)
+ sel = 0;
+ }
+
+ if(UIPressedRepeatThrottle(IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate))
+ {
+ sel += fullMenuPageHeight;
+
+ if(sel >= total)
+ sel = total - 1;
+ }
+
+ if(input_ui_pressed(IPT_UI_ADD_CHEAT))
+ {
+ AddSearchBefore(sel);
+
+ BuildSearchRegions(&searchList[sel]);
+ AllocateSearchRegions(&searchList[sel]);
+ }
+
+ if(input_ui_pressed(IPT_UI_DELETE_CHEAT))
+ {
+ if(searchListLength > 1)
+ DeleteSearchAt(sel);
+ }
+
+ if(input_ui_pressed(IPT_UI_EDIT_CHEAT))
+ {
+ if(sel < total - 1)
+ currentSearchIdx = sel;
+ }
+
+ if(input_ui_pressed(IPT_UI_SELECT))
+ {
+ if(sel >= total - 1)
+ sel = -1;
+ else
+ currentSearchIdx = sel;
+ }
+
+ if(input_ui_pressed(IPT_UI_CANCEL))
+ sel = -1;
+
+ return sel + 1;
+}
+
+/*------------------
+ cheate_periodic
+------------------*/
+
+static TIMER_CALLBACK( cheat_periodic )
+{
+ int i;
+
+ if(input_ui_pressed(IPT_UI_TOGGLE_CHEAT))
+ {
+ if(ShiftKeyPressed())
+ {
+ /* ------ toggle watchpoint display if shift + toggle cheat ----- */
+ watchesDisabled ^= 1;
+
+ ui_popup_time(1, "%s %s", ui_getstring(UI_watchpoints), watchesDisabled ? ui_getstring (UI_off) : ui_getstring (UI_on));
+ }
+ else
+ {
+ /* ------ toggle cheat ----- */
+ cheatsDisabled ^= 1;
+
+ ui_popup_time(1, "%s %s", ui_getstring(UI_cheats), cheatsDisabled ? ui_getstring (UI_off) : ui_getstring (UI_on));
+
+ if(cheatsDisabled)
+ {
+ for(i = 0; i < cheatListLength; i++)
+ TempDeactivateCheat(&cheatList[i]);
+ }
+ }
+ }
+
+ if(cheatsDisabled)
+ return;
+
+ for(i = 0; i < cheatListLength; i++)
+ cheat_periodicEntry(&cheatList[i]);
+}
+
+/*--------------
+ PrintBinary
+--------------*/
+
+static UINT32 PrintBinary(char * buf, UINT32 data, UINT32 mask)
+{
+ UINT32 traverse = 0x80000000;
+ UINT32 written = 0;
+
+ while(traverse)
+ {
+ if(mask & traverse)
+ {
+ *buf++ = (data & traverse) ? '1' : '0';
+ written++;
+ }
+
+ traverse >>= 1;
+ }
+
+ *buf++ = 0;
+
+ return written;
+}
+
+/*-------------
+ PrintASCII
+-------------*/
+
+static UINT32 PrintASCII(char * buf, UINT32 data, UINT8 size)
+{
+ switch(size)
+ {
+ case kSearchSize_8Bit:
+ case kSearchSize_1Bit:
+ default:
+ buf[0] = (data >> 0) & 0xFF;
+ buf[1] = 0;
+
+ return 1;
+
+ case kSearchSize_16Bit:
+ buf[0] = (data >> 8) & 0xFF;
+ buf[1] = (data >> 0) & 0xFF;
+ buf[2] = 0;
+
+ return 2;
+
+ case kSearchSize_24Bit:
+ buf[0] = (data >> 16)& 0xFF;
+ buf[1] = (data >> 8) & 0xFF;
+ buf[2] = (data >> 0) & 0xFF;
+ buf[3] = 0;
+
+ return 3;
+
+ case kSearchSize_32Bit:
+ buf[0] = (data >> 24) & 0xFF;
+ buf[1] = (data >> 16) & 0xFF;
+ buf[2] = (data >> 8) & 0xFF;
+ buf[3] = (data >> 0) & 0xFF;
+ buf[4] = 0;
+
+ return 4;
+ }
+
+ buf[0] = 0;
+ return 0;
+}
+
+/*---------------------------------------------
+ cheat_display_watches - display watchpoint
+---------------------------------------------*/
+
+void cheat_display_watches(void)
+{
+ int i;
+
+ if(watchesDisabled)
+ return;
+
+ for(i = 0; i < watchListLength; i++)
+ {
+ int j;
+ WatchInfo * info = &watchList[i];
+ char buf[1024];
+ UINT32 address = info->address;
+ int xOffset = 0, yOffset = 0;
+ int numChars;
+ int lineElements = 0;
+
+ /* ----- if the length of the watchpoint is not 0, display it ----- */
+ if(info->numElements)
+ {
+ /* ----- label display ----- */
+ switch(info->labelType)
+ {
+ case kWatchLabel_Address:
+ numChars = sprintf(buf, "%.8X: ", info->address);
+
+ ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y);
+ xOffset += numChars;
+ break;
+
+ case kWatchLabel_String:
+ numChars = sprintf(buf, "%s: ", info->label);
+
+ ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y);
+ xOffset += numChars;
+ break;
+ }
+
+ /* ----- value display ----- */
+ for(j = 0; j < info->numElements; j++)
+ {
+ UINT32 data = 0;
+
+ switch(info->locationType)
+ {
+ case kLocation_Standard:
+ data = (DoCPURead(info->cpu, address, kSearchByteIncrementTable[info->elementBytes], CPUNeedsSwap(info->cpu)) + info->addValue) &
+ kSearchByteMaskTable[info->elementBytes];
+ break;
+
+ case kLocation_MemoryRegion:
+ {
+ int region = REGION_CPU1 + info->cpu;
+ UINT8 * buf = memory_region(region);
+
+ data = DoMemoryRead(buf, address, kSearchByteIncrementTable[info->elementBytes], RegionNeedsSwap(region) + info->addValue, GetRegionCPUInfo(region)) &
+ kSearchByteMaskTable[info->elementBytes];
+ }
+ break;
+
+ case kLocation_IndirectIndexed:
+ return; // under construction...
+
+ case kLocation_ProgramSpace:
+ {
+ UINT8 * buf;
+
+ memory_set_opbase(address);
+
+ buf = memory_get_op_ptr(info->cpu, address, 0);
+
+ buf -= address;
+
+ if(buf)
+ data = DoMemoryRead(buf, address, kSearchByteIncrementTable[info->elementBytes], CPUNeedsSwap(info->cpu) + info->addValue, GetCPUInfo(info->cpu)) &
+ kSearchByteMaskTable[info->elementBytes];
+ }
+ break;
+
+ default:
+ logerror("invalid location type : %x\n", info->locationType);
+ return;
+
+ }
+
+ data = DoShift(data, info->dataShift);
+ data ^= info->xor;
+
+ if( (lineElements >= info->elementsPerLine) && info->elementsPerLine)
+ {
+ lineElements = 0;
+
+ xOffset = 0;
+ yOffset++;
+ }
+
+ switch(info->displayType)
+ {
+ case kWatchDisplayType_Hex:
+ numChars = sprintf(buf, "%.*X", kSearchByteDigitsTable[info->elementBytes], data);
+
+ ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y);
+ xOffset += numChars;
+ xOffset++;
+ break;
+
+ case kWatchDisplayType_Decimal:
+ numChars = sprintf(buf, "%.*d", kSearchByteDecDigitsTable[info->elementBytes], data);
+
+ ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y);
+ xOffset += numChars;
+ xOffset++;
+ break;
+
+ case kWatchDisplayType_Binary:
+ numChars = PrintBinary(buf, data, kSearchByteMaskTable[info->elementBytes]);
+
+ ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y);
+ xOffset += numChars;
+ xOffset++;
+ break;
+
+ case kWatchDisplayType_ASCII:
+ numChars = PrintASCII(buf, data, info->elementBytes);
+
+ ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y);
+ xOffset += numChars;
+ break;
+ }
+
+ address += kSearchByteIncrementTable[info->elementBytes] + info->skip;
+ lineElements++;
+ }
+ }
+ }
+}
+
+/*------------------
+ ResizeCheatList
+------------------*/
+
+static void ResizeCheatList(UINT32 newLength)
+{
+ if(newLength != cheatListLength)
+ {
+ if(newLength < cheatListLength)
+ {
+ int i;
+
+ for(i = newLength; i < cheatListLength; i++)
+ DisposeCheat(&cheatList[i]);
+ }
+
+ cheatList = realloc(cheatList, newLength * sizeof(CheatEntry));
+
+ if(!cheatList && (newLength != 0))
+ {
+ logerror("ResizeCheatList: out of memory resizing cheat list\n");
+ ui_popup_time(2, "out of memory while loading cheat database");
+
+ cheatListLength = 0;
+
+ return;
+ }
+
+ if(newLength > cheatListLength)
+ {
+ int i;
+
+ memset(&cheatList[cheatListLength], 0, (newLength - cheatListLength) * sizeof(CheatEntry));
+
+ for(i = cheatListLength; i < newLength; i++)
+ cheatList[i].flags |= kCheatFlag_Dirty;
+ }
+
+ cheatListLength = newLength;
+ }
+}
+
+/*---------------------------
+ ResizeCheatListNoDispose
+---------------------------*/
+
+static void ResizeCheatListNoDispose(UINT32 newLength)
+{
+ if(newLength != cheatListLength)
+ {
+ cheatList = realloc(cheatList, newLength * sizeof(CheatEntry));
+
+ if(!cheatList && (newLength != 0))
+ {
+ logerror("ResizeCheatListNoDispose: out of memory resizing cheat list\n");
+ ui_popup_time(2, "out of memory while loading cheat database");
+
+ cheatListLength = 0;
+
+ return;
+ }
+
+ if(newLength > cheatListLength)
+ {
+ int i;
+
+ memset(&cheatList[cheatListLength], 0, (newLength - cheatListLength) * sizeof(CheatEntry));
+
+ for(i = cheatListLength; i < newLength; i++)
+ cheatList[i].flags |= kCheatFlag_Dirty;
+ }
+
+ cheatListLength = newLength;
+ }
+}
+
+/*---------------------------------------------------------------
+ AddCheatBefore - insert new cheat entry before selected code
+---------------------------------------------------------------*/
+
+static void AddCheatBefore(UINT32 idx)
+{
+ /* ----- memory reallocation ----- */
+ ResizeCheatList(cheatListLength + 1);
+
+ if(idx < (cheatListLength - 1))
+ memmove(&cheatList[idx + 1], &cheatList[idx], sizeof(CheatEntry) * (cheatListLength - 1 - idx));
+
+ if(idx >= cheatListLength)
+ idx = cheatListLength - 1;
+
+ /* ----- insert new entry ----- */
+ memset(&cheatList[idx], 0, sizeof(CheatEntry));
+
+ cheatList[idx].flags |= kCheatFlag_Dirty;
+
+ ResizeCheatActionList(&cheatList[idx], 1);
+}
+
+/*----------------
+ DeleteCheatAt
+----------------*/
+
+static void DeleteCheatAt(UINT32 idx)
+{
+ if(idx >= cheatListLength)
+ return;
+
+ DisposeCheat(&cheatList[idx]);
+
+ if(idx < (cheatListLength - 1))
+ {
+ memmove(&cheatList[idx], &cheatList[idx + 1], sizeof(CheatEntry) * (cheatListLength - 1 - idx));
+ }
+
+ ResizeCheatListNoDispose(cheatListLength - 1);
+}
+
+/*------------------------------------------------
+ DisposeCheat - free memory for selected entry
+------------------------------------------------*/
+
+static void DisposeCheat(CheatEntry * entry)
+{
+ if(entry)
+ {
+ int i;
+
+ free(entry->name);
+ free(entry->comment);
+
+ for(i = 0; i < entry->actionListLength; i++)
+ {
+ CheatAction * action = &entry->actionList[i];
+
+ DisposeAction(action);
+ }
+
+ free(entry->actionList);
+
+ memset(entry, 0, sizeof(CheatEntry));
+ }
+}
+
+/*------------------------------------
+ GetNewCheat - get new cheat entry
+------------------------------------*/
+
+static CheatEntry * GetNewCheat(void)
+{
+ /* ----- insert new cheat entry ----- */
+ AddCheatBefore(cheatListLength);
+
+ /* ----- return inserted entry ----- */
+ return &cheatList[cheatListLength - 1];
+}
+
+/*------------------------
+ ResizeCheatActionList
+------------------------*/
+
+static void ResizeCheatActionList(CheatEntry * entry, UINT32 newLength)
+{
+ if(newLength != entry->actionListLength)
+ {
+ if(newLength < entry->actionListLength)
+ {
+ int i;
+
+ for(i = newLength; i < entry->actionListLength; i++)
+ DisposeAction(&entry->actionList[i]);
+ }
+
+ entry->actionList = realloc(entry->actionList, newLength * sizeof(CheatAction));
+ if(!entry->actionList && (newLength != 0))
+ {
+ logerror("ResizeCheatActionList: out of memory resizing cheat action list\n");
+ ui_popup_time(2, "out of memory while loading cheat database");
+
+ entry->actionListLength = 0;
+
+ return;
+ }
+
+ if(newLength > entry->actionListLength)
+ {
+ memset(&entry->actionList[entry->actionListLength], 0, (newLength - entry->actionListLength) * sizeof(CheatAction));
+ }
+
+ entry->actionListLength = newLength;
+ }
+}
+
+/*---------------------------------
+ ResizeCheatActionListNoDispose
+---------------------------------*/
+
+static void ResizeCheatActionListNoDispose(CheatEntry * entry, UINT32 newLength)
+{
+ if(newLength != entry->actionListLength)
+ {
+ entry->actionList = realloc(entry->actionList, newLength * sizeof(CheatAction));
+ if(!entry->actionList && (newLength != 0))
+ {
+ logerror("ResizeCheatActionList: out of memory resizing cheat action list\n");
+ ui_popup_time(2, "out of memory while loading cheat database");
+
+ entry->actionListLength = 0;
+
+ return;
+ }
+
+ if(newLength > entry->actionListLength)
+ {
+ memset(&entry->actionList[entry->actionListLength], 0, (newLength - entry->actionListLength) * sizeof(CheatAction));
+ }
+
+ entry->actionListLength = newLength;
+ }
+}
+
+/*------------------
+ AddActionBefore
+------------------*/
+
+static void AddActionBefore(CheatEntry * entry, UINT32 idx)
+{
+ ResizeCheatActionList(entry, entry->actionListLength + 1);
+
+ if(idx < (entry->actionListLength - 1))
+ memmove(&entry->actionList[idx + 1], &entry->actionList[idx], sizeof(CheatAction) * (entry->actionListLength - 1 - idx));
+
+ if(idx >= entry->actionListLength)
+ idx = entry->actionListLength - 1;
+
+ memset(&entry->actionList[idx], 0, sizeof(CheatAction));
+}
+
+/*-----------------
+ DeleteActionAt
+-----------------*/
+
+static void DeleteActionAt(CheatEntry * entry, UINT32 idx)
+{
+ if(idx >= entry->actionListLength)
+ return;
+
+ DisposeAction(&entry->actionList[idx]);
+
+ if(idx < (entry->actionListLength - 1))
+ memmove(&entry->actionList[idx], &entry->actionList[idx + 1], sizeof(CheatAction) * (entry->actionListLength - 1 - idx));
+
+ ResizeCheatActionListNoDispose(entry, entry->actionListLength - 1);
+}
+
+/*----------------
+ DisposeAction
+----------------*/
+
+static void DisposeAction(CheatAction * action)
+{
+ if(action)
+ {
+ free(action->optionalName);
+
+ memset(action, 0, sizeof(CheatAction));
+ }
+}
+
+/*----------------------------------------------------
+ InitWatch - initialize y-position for watchpoints
+----------------------------------------------------*/
+
+static void InitWatch(WatchInfo * info, UINT32 idx)
+{
+ if(idx > 0)
+ /* ----- set 2nd or later y-position ----- */
+ info->y = watchList[idx - 1].y + ui_get_line_height();
+ else
+ /* ----- set 1st y-position (always Y=0) ----- */
+ info->y = 0;
+}
+
+/*------------------
+ ResizeWatchList
+------------------*/
+
+static void ResizeWatchList(UINT32 newLength)
+{
+ if(newLength != watchListLength)
+ {
+ if(newLength < watchListLength)
+ {
+ int i;
+
+ for(i = newLength; i < watchListLength; i++)
+ DisposeWatch(&watchList[i]);
+ }
+
+ watchList = realloc(watchList, newLength * sizeof(WatchInfo));
+ if(!watchList && (newLength != 0))
+ {
+ logerror("ResizeWatchList: out of memory resizing watch list\n");
+ ui_popup_time(2, "out of memory while adding watch");
+
+ watchListLength = 0;
+
+ return;
+ }
+
+ if(newLength > watchListLength)
+ {
+ int i;
+
+ memset(&watchList[watchListLength], 0, (newLength - watchListLength) * sizeof(WatchInfo));
+
+ for(i = watchListLength; i < newLength; i++)
+ InitWatch(&watchList[i], i);
+ }
+
+ watchListLength = newLength;
+ }
+}
+
+/*---------------------------
+ ResizeWatchListNoDispose
+---------------------------*/
+
+static void ResizeWatchListNoDispose(UINT32 newLength)
+{
+ if(newLength != watchListLength)
+ {
+ watchList = realloc(watchList, newLength * sizeof(WatchInfo));
+ if(!watchList && (newLength != 0))
+ {
+ logerror("ResizeWatchList: out of memory resizing watch list\n");
+ ui_popup_time(2, "out of memory while adding watch");
+
+ watchListLength = 0;
+
+ return;
+ }
+
+ if(newLength > watchListLength)
+ {
+ int i;
+
+ memset(&watchList[watchListLength], 0, (newLength - watchListLength) * sizeof(WatchInfo));
+
+ for(i = watchListLength; i < newLength; i++)
+ InitWatch(&watchList[i], i);
+ }
+
+ watchListLength = newLength;
+ }
+}
+
+/*-----------------
+ AddWatchBefore
+-----------------*/
+
+static void AddWatchBefore(UINT32 idx)
+{
+ ResizeWatchList(watchListLength + 1);
+
+ if(idx < (watchListLength - 1))
+ memmove(&watchList[idx + 1], &watchList[idx], sizeof(WatchInfo) * (watchListLength - 1 - idx));
+
+ if(idx >= watchListLength)
+ idx = watchListLength - 1;
+
+ memset(&watchList[idx], 0, sizeof(WatchInfo));
+
+ InitWatch(&watchList[idx], idx);
+}
+
+/*----------------
+ DeleteWatchAt
+----------------*/
+
+static void DeleteWatchAt(UINT32 idx)
+{
+ if(idx >= watchListLength)
+ return;
+
+ DisposeWatch(&watchList[idx]);
+
+ if(idx < (watchListLength - 1))
+ memmove(&watchList[idx], &watchList[idx + 1], sizeof(WatchInfo) * (watchListLength - 1 - idx));
+
+ ResizeWatchListNoDispose(watchListLength - 1);
+}
+
+/*---------------
+ DisposeWatch
+---------------*/
+
+static void DisposeWatch(WatchInfo * watch)
+{
+ if(watch)
+ memset(watch, 0, sizeof(WatchInfo));
+}
+
+/*----------------------------------------------------------
+ GetUnusedWatch - search unused watchpoint and return it
+----------------------------------------------------------*/
+
+static WatchInfo * GetUnusedWatch(void)
+{
+ int i;
+ WatchInfo * info;
+ WatchInfo * theWatch = NULL;
+
+ /* ----- search unused watchpoint ----- */
+ for(i = 0; i < watchListLength; i++)
+ {
+ info = &watchList[i];
+
+ if(info->numElements == 0)
+ {
+ theWatch = info;
+ break;
+ }
+ }
+
+ /* ----- if unused watchpoint is not found, insert new watchpoint as unused ----- */
+ if(!theWatch)
+ {
+ AddWatchBefore(watchListLength);
+
+ theWatch = &watchList[watchListLength - 1];
+ }
+
+ /* ----- return unused watchpoint ----- */
+ return theWatch;
+}
+
+/*----------------------------------------------------------------------------
+ AddCheatFromWatch - add new cheat code from watchpoint list to cheat list
+----------------------------------------------------------------------------*/
+
+static void AddCheatFromWatch(WatchInfo * watch)
+{
+ if(watch)
+ {
+ CheatEntry * entry = GetNewCheat();
+ CheatAction * action = &entry->actionList[0];
+ char tempString[1024];
+ int tempStringLength;
+ UINT32 data = DoCPURead(watch->cpu, watch->address, kSearchByteIncrementTable[watch->elementBytes], 0);
+
+ tempStringLength = sprintf(tempString, "%.8X (%d) = %.*X", watch->address, watch->cpu, kSearchByteDigitsTable[watch->elementBytes], data);
+
+ entry->name = realloc(entry->name, tempStringLength + 1);
+ memcpy(entry->name, tempString, tempStringLength + 1);
+
+ SET_FIELD(action->type, LocationParameter, watch->cpu);
+ SET_FIELD(action->type, BytesUsed, kSearchByteIncrementTable[watch->elementBytes] - 1);
+ action->address = watch->address;
+ action->data = data;
+ action->extendData = 0xFFFFFFFF;
+ action->originalDataField = data;
+
+ UpdateCheatInfo(entry, 0);
+ }
+}
+
+/*-------------------------------------------------------------------------------------
+ SetupCheatFromWatchAsWatch - add new watch code from watchpoint list to cheat list
+-------------------------------------------------------------------------------------*/
+
+static void SetupCheatFromWatchAsWatch(CheatEntry * entry, WatchInfo * watch)
+{
+ if(watch && entry && watch->numElements)
+ {
+ CheatAction * action;
+ char tempString[1024];
+ size_t tempStringLength;
+
+ DisposeCheat(entry);
+ ResizeCheatActionList(entry, 1);
+
+ action = &entry->actionList[0];
+
+ tempStringLength = sprintf(tempString, "Watch %.8X (%d)", watch->address, watch->cpu);
+
+ entry->name = realloc(entry->name, tempStringLength + 1);
+ memcpy(entry->name, tempString, tempStringLength + 1);
+
+ action->type = 0;
+ SET_FIELD(action->type, LocationParameter, watch->cpu);
+ SET_FIELD(action->type, Type, kType_Watch);
+ SET_FIELD(action->type, BytesUsed, kSearchByteIncrementTable[watch->elementBytes] - 1);
+ SET_FIELD(action->type, TypeParameter, watch->displayType | ((watch->labelType == kWatchLabel_String) ? 0x04 : 0));
+
+ action->address = watch->address;
+ action->data = ((watch->numElements - 1) & 0xFF) |
+ ((watch->skip & 0xFF) << 8) |
+ ((watch->elementsPerLine & 0xFF) << 16) |
+ ((watch->addValue & 0xFF) << 24);
+ action->originalDataField = action->data;
+ action->extendData = 0xFFFFFFFF;
+
+ tempStringLength = strlen(watch->label);
+ entry->comment = realloc(entry->comment, tempStringLength + 1);
+ memcpy(entry->comment, watch->label, tempStringLength + 1);
+
+ UpdateCheatInfo(entry, 0);
+ }
+}
+
+/*-------------------
+ ResizeSearchList
+-------------------*/
+
+static void ResizeSearchList(UINT32 newLength)
+{
+ if(newLength != searchListLength)
+ {
+ if(newLength < searchListLength)
+ {
+ int i;
+
+ for(i = newLength; i < searchListLength; i++)
+ DisposeSearch(i);
+ }
+
+ searchList = realloc(searchList, newLength * sizeof(SearchInfo));
+ if(!searchList && (newLength != 0))
+ {
+ logerror("ResizeSearchList: out of memory resizing search list\n");
+ ui_popup_time(2, "out of memory while adding search");
+
+ searchListLength = 0;
+
+ return;
+ }
+
+ if(newLength > searchListLength)
+ {
+ int i;
+
+ memset(&searchList[searchListLength], 0, (newLength - searchListLength) * sizeof(SearchInfo));
+
+ for(i = searchListLength; i < newLength; i++)
+ {
+ InitSearch(&searchList[i]);
+ }
+ }
+
+ searchListLength = newLength;
+ }
+}
+
+/*----------------------------
+ ResizeSearchListNoDispose
+----------------------------*/
+
+static void ResizeSearchListNoDispose(UINT32 newLength)
+{
+ if(newLength != searchListLength)
+ {
+ searchList = realloc(searchList, newLength * sizeof(SearchInfo));
+ if(!searchList && (newLength != 0))
+ {
+ logerror("ResizeSearchList: out of memory resizing search list\n");
+ ui_popup_time(2, "out of memory while adding search");
+
+ searchListLength = 0;
+
+ return;
+ }
+
+ if(newLength > searchListLength)
+ {
+ memset(&searchList[searchListLength], 0, (newLength - searchListLength) * sizeof(SearchInfo));
+ }
+
+ searchListLength = newLength;
+ }
+}
+
+/*------------------
+ AddSearchBefore
+------------------*/
+
+static void AddSearchBefore(UINT32 idx)
+{
+ ResizeSearchListNoDispose(searchListLength + 1);
+
+ if(idx < (searchListLength - 1))
+ memmove(&searchList[idx + 1], &searchList[idx], sizeof(SearchInfo) * (searchListLength - 1 - idx));
+
+ if(idx >= searchListLength)
+ idx = searchListLength - 1;
+
+ memset(&searchList[idx], 0, sizeof(SearchInfo));
+ InitSearch(&searchList[idx]);
+}
+
+/*-----------------
+ DeleteSearchAt
+-----------------*/
+
+static void DeleteSearchAt(UINT32 idx)
+{
+ if(idx >= searchListLength)
+ return;
+
+ DisposeSearch(idx);
+
+ if(idx < (searchListLength - 1))
+ {
+ memmove(&searchList[idx], &searchList[idx + 1], sizeof(SearchInfo) * (searchListLength - 1 - idx));
+ }
+
+ ResizeSearchListNoDispose(searchListLength - 1);
+}
+
+/*--------------------------------------
+ InitSearch - initialize search info
+--------------------------------------*/
+
+static void InitSearch(SearchInfo * info)
+{
+ if(info)
+ {
+ info->searchSpeed = kSearchSpeed_Medium;
+ }
+}
+
+/*-----------------------
+ DisposeSearchRegions
+-----------------------*/
+
+static void DisposeSearchRegions(SearchInfo * info)
+{
+ if(info->regionList)
+ {
+ int i;
+
+ for(i = 0; i < info->regionListLength; i++)
+ {
+ SearchRegion * region = &info->regionList[i];
+
+ free(region->first);
+ free(region->last);
+ free(region->status);
+ free(region->backupLast);
+ free(region->backupStatus);
+ }
+
+ free(info->regionList);
+
+ info->regionList = NULL;
+ }
+
+ info->regionListLength = 0;
+}
+
+/*------------------
+ DisposeSearch
+ ----------------*/
+
+static void DisposeSearch(UINT32 idx)
+{
+ SearchInfo * info;
+
+ if(idx >= searchListLength)
+ return;
+
+ info = &searchList[idx];
+
+ DisposeSearchRegions(info);
+
+ free(info->name);
+ info->name = NULL;
+}
+
+/*----------------------------------------
+ GetCurrentSearch - return search info
+----------------------------------------*/
+
+static SearchInfo * GetCurrentSearch(void)
+{
+ if(currentSearchIdx >= searchListLength)
+ currentSearchIdx = searchListLength - 1;
+ if(currentSearchIdx < 0)
+ currentSearchIdx = 0;
+
+ return &searchList[currentSearchIdx];
+}
+
+/*-------------------------------------------------------
+ FillBufferFromRegion - set a data into search region
+-------------------------------------------------------*/
+
+static void FillBufferFromRegion(SearchRegion * region, UINT8 * buf)
+{
+ UINT32 offset;
+
+ /* ### optimize if needed ### */
+ for(offset = 0; offset < region->length; offset++)
+ buf[offset] = ReadRegionData(region, offset, 1, 0);
+}
+
+/*-------------------------------------------------------
+ ReadRegionData - read a data from region when search
+-------------------------------------------------------*/
+
+static UINT32 ReadRegionData(SearchRegion * region, UINT32 offset, UINT8 size, UINT8 swap)
+{
+ UINT32 address = region->address + offset;
+
+ switch(region->targetType)
+ {
+ case kRegionType_CPU:
+ return DoCPURead(region->targetIdx, address, size, CPUNeedsSwap(region->targetIdx) ^ swap);
+
+ case kRegionType_Memory:
+ if(region->cachedPointer)
+ return DoMemoryRead(region->cachedPointer, address, size, swap, &rawCPUInfo);
+ else
+ return 0;
+ }
+
+ return 0;
+}
+/*-----------------------------------------------
+ BackupSearch - back up current search region
+-----------------------------------------------*/
+
+static void BackupSearch(SearchInfo * info)
+{
+ int i;
+
+ for(i = 0; i < info->regionListLength; i++)
+ BackupRegion(&info->regionList[i]);
+
+ info->oldNumResults = info->numResults;
+ info->backupValid = 1;
+}
+
+/*-------------------------------------------------------
+ RestoreSearchBackup - restore previous search region
+-------------------------------------------------------*/
+
+static void RestoreSearchBackup(SearchInfo * info)
+{
+ int i;
+
+ if(info && info->backupValid)
+ {
+ for(i = 0; i < info->regionListLength; i++)
+ RestoreRegionBackup(&info->regionList[i]);
+
+ info->numResults = info->oldNumResults;
+ info->backupValid = 0;
+
+ ui_popup_time(1, "values restored");
+ }
+ else
+ ui_popup_time(1, "there are no old values");
+}
+
+/*------------------------------------------------
+ BackupRegion - back up current search results
+------------------------------------------------*/
+
+static void BackupRegion(SearchRegion * region)
+{
+ if(region->flags & kRegionFlag_Enabled)
+ {
+ memcpy(region->backupLast, region->last, region->length);
+ memcpy(region->backupStatus, region->status, region->length);
+ region->oldNumResults = region->numResults;
+ }
+}
+
+/*--------------------------------------------------------
+ RestoreSearchBackup - restore previous search results
+--------------------------------------------------------*/
+
+static void RestoreRegionBackup(SearchRegion * region)
+{
+ if(region->flags & kRegionFlag_Enabled)
+ {
+ memcpy(region->last, region->backupLast, region->length);
+ memcpy(region->status, region->backupStatus, region->length);
+ region->numResults = region->oldNumResults;
+ }
+}
+
+/*-----------------------------------------------------------
+ DefaultEnableRegion - get default regions you can search
+-----------------------------------------------------------*/
+
+static UINT8 DefaultEnableRegion(SearchRegion * region, SearchInfo * info)
+{
+ write8_handler handler = region->writeHandler->write.handler8;
+ FPTR handlerAddress = (FPTR)handler;
+
+ switch(info->searchSpeed)
+ {
+ case kSearchSpeed_Fast:
+
+#if HAS_SH2
+ if(Machine->drv->cpu[0].type == CPU_SH2)
+ {
+ if( (info->targetType == kRegionType_CPU) && (info->targetIdx == 0) && (region->address == 0x06000000))
+ return 1;
+
+ return 0;
+ }
+#endif
+
+ if( (handler == MWA8_RAM) && (!region->writeHandler->base))
+ return 1;
+
+#ifndef MESS
+
+ {
+ /* ----- for neogeo, search bank one ----- */
+ if( (!strcmp(Machine->gamedrv->parent, "neogeo")) && (info->targetType == kRegionType_CPU) &&
+ (info->targetIdx == 0) && (handler == MWA8_BANK1))
+ return 1;
+ }
+
+#endif
+
+#if HAS_TMS34010
+
+ /* ----- for exterminator, search bank one ----- */
+ if( (Machine->drv->cpu[1].type == CPU_TMS34010) && (info->targetType == kRegionType_CPU) &&
+ (info->targetIdx == 1) && (handler == MWA8_BANK1))
+ return 1;
+
+ /* ----- for smashtv, search bank two ----- */
+ if( (Machine->drv->cpu[0].type == CPU_TMS34010) && (info->targetType == kRegionType_CPU) &&
+ (info->targetIdx == 0) && (handler == MWA8_BANK2))
+ return 1;
+
+#endif
+ return 0;
+
+ case kSearchSpeed_Medium:
+ if( (handlerAddress >= ((FPTR)MWA8_BANK1)) && (handlerAddress <= ((FPTR)MWA8_BANK24)))
+ return 1;
+
+ if(handler == MWA8_RAM)
+ return 1;
+
+ return 0;
+
+ case kSearchSpeed_Slow:
+ if( (handler == MWA8_NOP) || (handler == MWA8_ROM))
+ return 0;
+
+ if( (handlerAddress > STATIC_COUNT) && (!region->writeHandler->base))
+ return 0;
+
+ return 1;
+
+ case kSearchSpeed_VerySlow:
+ if( (handler == MWA8_NOP) || (handler == MWA8_ROM))
+ return 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*-----------------------------
+ SetSearchRegionDefaultName
+-----------------------------*/
+
+static void SetSearchRegionDefaultName(SearchRegion * region)
+{
+ switch(region->targetType)
+ {
+ case kRegionType_CPU:
+ {
+ char desc[16];
+
+ if(region->writeHandler)
+ {
+ genf * handler = region->writeHandler->write.handler;
+ FPTR handlerAddress = (FPTR)handler;
+
+ if( (handlerAddress >= ((FPTR)MWA8_BANK1)) && (handlerAddress <= ((FPTR)MWA8_BANK24)))
+ sprintf(desc, "BANK%.2d", (int)(handlerAddress - (FPTR)MWA8_BANK1) + 1);
+ else
+ {
+ switch(handlerAddress)
+ {
+ case (FPTR)MWA8_NOP: strcpy(desc, "NOP "); break;
+ case (FPTR)MWA8_RAM: strcpy(desc, "RAM "); break;
+ case (FPTR)MWA8_ROM: strcpy(desc, "ROM "); break;
+ default: strcpy(desc, "CUSTOM"); break;
+ }
+ }
+ }
+ else
+ sprintf(desc, "CPU%.2d ", region->targetIdx);
+
+ sprintf(region->name, "%.*X-%.*X %s",
+ cpuInfoList[region->targetIdx].addressCharsNeeded,
+ region->address,
+ cpuInfoList[region->targetIdx].addressCharsNeeded,
+ region->address + region->length - 1,
+ desc);
+ }
+ break;
+
+ case kRegionType_Memory:
+ sprintf(region->name, "%.8X-%.8X MEMORY", region->address, region->address + region->length - 1);
+ break;
+
+ default:
+ sprintf(region->name, "UNKNOWN");
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------------------------
+ AllocateSearchRegions - free memory for search region then realloc if searchable
+-----------------------------------------------------------------------------------*/
+
+static void AllocateSearchRegions(SearchInfo * info)
+{
+ int i;
+
+ info->backupValid = 0;
+ info->numResults = 0;
+
+ for(i = 0; i < info->regionListLength; i++)
+ {
+ SearchRegion * region;
+
+ region = &info->regionList[i];
+
+ region->numResults = 0;
+
+ free(region->first);
+ free(region->last);
+ free(region->status);
+ free(region->backupLast);
+ free(region->backupStatus);
+
+ if(region->flags & kRegionFlag_Enabled)
+ {
+ region->first = malloc(region->length);
+ region->last = malloc(region->length);
+ region->status = malloc(region->length);
+ region->backupLast = malloc(region->length);
+ region->backupStatus = malloc(region->length);
+
+ if(!region->first || !region->last || !region->status || !region->backupLast || !region->backupStatus)
+ {
+ free(region->first);
+ free(region->last);
+ free(region->status);
+ free(region->backupLast);
+ free(region->backupStatus);
+
+ region->first = NULL;
+ region->last = NULL;
+ region->status = NULL;
+ region->backupLast = NULL;
+ region->backupStatus = NULL;
+
+ region->flags &= ~kRegionFlag_Enabled;
+ }
+ }
+ else
+ {
+ region->first = NULL;
+ region->last = NULL;
+ region->status = NULL;
+ region->backupLast = NULL;
+ region->backupStatus = NULL;
+ }
+ }
+}
+
+/*---------------------
+ BuildSearchRegions
+---------------------*/
+
+static void BuildSearchRegions(SearchInfo * info)
+{
+ info->comparison = kSearchComparison_EqualTo;
+
+ DisposeSearchRegions(info);
+
+ switch(info->targetType)
+ {
+ case kRegionType_CPU:
+ {
+ if(info->searchSpeed == kSearchSpeed_AllMemory)
+ {
+ UINT32 length = cpuInfoList[info->targetIdx].addressMask + 1;
+ SearchRegion * region;
+
+ info->regionList = calloc(sizeof(SearchRegion), 1);
+ info->regionListLength = 1;
+ region = info->regionList;
+
+ region->address = 0;
+ region->length = length;
+
+ region->targetIdx = info->targetIdx;
+ region->targetType = info->targetType;
+ region->writeHandler = NULL;
+
+ region->first = NULL;
+ region->last = NULL;
+ region->status = NULL;
+
+ region->backupLast = NULL;
+ region->backupStatus = NULL;
+
+ region->flags = kRegionFlag_Enabled;
+
+ SetSearchRegionDefaultName(region);
+ }
+ else
+ {
+ if(info->targetIdx < cpu_gettotalcpu())
+ {
+ const address_map * map = NULL;
+ SearchRegion * traverse;
+ int count = 0;
+
+ map = memory_get_map(info->targetIdx, ADDRESS_SPACE_PROGRAM);
+
+ while(!IS_AMENTRY_END(map))
+ {
+ if(!IS_AMENTRY_EXTENDED(map) && map->write.handler)
+ count++;
+
+ map++;
+ }
+
+ info->regionList = calloc(sizeof(SearchRegion), count);
+ info->regionListLength = count;
+ traverse = info->regionList;
+
+ map = memory_get_map(info->targetIdx, ADDRESS_SPACE_PROGRAM);
+
+ while(!IS_AMENTRY_END(map))
+ {
+ if(!IS_AMENTRY_EXTENDED(map) && map->write.handler)
+ {
+ UINT32 length = (map->end - map->start) + 1;
+
+ traverse->address = map->start;
+ traverse->length = length;
+
+ traverse->targetIdx = info->targetIdx;
+ traverse->targetType = info->targetType;
+ traverse->writeHandler = map;
+
+ traverse->first = NULL;
+ traverse->last = NULL;
+ traverse->status = NULL;
+
+ traverse->backupLast = NULL;
+ traverse->backupStatus = NULL;
+
+ traverse->flags = DefaultEnableRegion(traverse, info) ? kRegionFlag_Enabled : 0;
+
+ SetSearchRegionDefaultName(traverse);
+
+ traverse++;
+ }
+
+ map++;
+ }
+ }
+ }
+ }
+ break;
+
+ case kRegionType_Memory:
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------
+ ConvertOldCode - convert old format code to new when load database
+---------------------------------------------------------------------*/
+
+static int ConvertOldCode(int code, int cpu, int * data, int * extendData)
+{
+ enum
+ {
+ kCustomField_None = 0,
+ kCustomField_DontApplyCPUField = 1 << 0,
+ kCustomField_SetBit = 1 << 1,
+ kCustomField_ClearBit = 1 << 2,
+ kCustomField_SubtractOne = 1 << 3,
+
+ kCustomField_BitMask = kCustomField_SetBit |
+ kCustomField_ClearBit,
+ kCustomField_End = 0xFF
+ };
+
+ struct ConversionTable
+ {
+ int oldCode;
+ UINT32 newCode;
+ UINT8 customField;
+ };
+
+ static struct ConversionTable kConversionTable[] =
+ {
+ { 0, 0x00000000, kCustomField_None },
+ { 1, 0x00000001, kCustomField_None },
+ { 2, 0x00000020, kCustomField_None },
+ { 3, 0x00000040, kCustomField_None },
+ { 4, 0x000000A0, kCustomField_None },
+ { 5, 0x00000022, kCustomField_None },
+ { 6, 0x00000042, kCustomField_None },
+ { 7, 0x000000A2, kCustomField_None },
+ { 8, 0x00000024, kCustomField_None },
+ { 9, 0x00000044, kCustomField_None },
+ { 10, 0x00000064, kCustomField_None },
+ { 11, 0x00000084, kCustomField_None },
+ { 15, 0x00000023, kCustomField_None },
+ { 16, 0x00000043, kCustomField_None },
+ { 17, 0x000000A3, kCustomField_None },
+ { 20, 0x00000000, kCustomField_SetBit },
+ { 21, 0x00000001, kCustomField_SetBit },
+ { 22, 0x00000020, kCustomField_SetBit },
+ { 23, 0x00000040, kCustomField_SetBit },
+ { 24, 0x000000A0, kCustomField_SetBit },
+ { 40, 0x00000000, kCustomField_ClearBit },
+ { 41, 0x00000001, kCustomField_ClearBit },
+ { 42, 0x00000020, kCustomField_ClearBit },
+ { 43, 0x00000040, kCustomField_ClearBit },
+ { 44, 0x000000A0, kCustomField_ClearBit },
+ { 60, 0x00000103, kCustomField_None },
+ { 61, 0x00000303, kCustomField_None },
+ { 62, 0x00000503, kCustomField_SubtractOne },
+ { 63, 0x00000903, kCustomField_None },
+ { 64, 0x00000B03, kCustomField_None },
+ { 65, 0x00000D03, kCustomField_SubtractOne },
+ { 70, 0x00000101, kCustomField_None },
+ { 71, 0x00000301, kCustomField_None },
+ { 72, 0x00000501, kCustomField_SubtractOne },
+ { 73, 0x00000901, kCustomField_None },
+ { 74, 0x00000B01, kCustomField_None },
+ { 75, 0x00000D01, kCustomField_SubtractOne },
+ { 80, 0x00000102, kCustomField_None },
+ { 81, 0x00000302, kCustomField_None },
+ { 82, 0x00000502, kCustomField_SubtractOne },
+ { 83, 0x00000902, kCustomField_None },
+ { 84, 0x00000B02, kCustomField_None },
+ { 85, 0x00000D02, kCustomField_SubtractOne },
+ { 90, 0x00000100, kCustomField_None },
+ { 91, 0x00000300, kCustomField_None },
+ { 92, 0x00000500, kCustomField_SubtractOne },
+ { 93, 0x00000900, kCustomField_None },
+ { 94, 0x00000B00, kCustomField_None },
+ { 95, 0x00000D00, kCustomField_SubtractOne },
+ { 100, 0x20800000, kCustomField_None },
+ { 101, 0x20000001, kCustomField_None },
+ { 102, 0x20800000, kCustomField_None },
+ { 103, 0x20000001, kCustomField_None },
+ { 110, 0x40800000, kCustomField_None },
+ { 111, 0x40000001, kCustomField_None },
+ { 112, 0x40800000, kCustomField_None },
+ { 113, 0x40000001, kCustomField_None },
+ { 120, 0x63000001, kCustomField_None },
+ { 121, 0x63000001, kCustomField_DontApplyCPUField | kCustomField_SetBit },
+ { 122, 0x63000001, kCustomField_DontApplyCPUField | kCustomField_ClearBit },
+ { 998, 0x00000006, kCustomField_None },
+ { 999, 0x60000000, kCustomField_DontApplyCPUField },
+ { -1, 0x00000000, kCustomField_End }
+ };
+
+ struct ConversionTable * traverse = kConversionTable;
+ UINT32 newCode;
+ UINT8 linkCheat = 0;
+
+ /* ----- convert link cheats ----- */
+ if((code >= 500) && (code <= 699))
+ {
+ linkCheat = 1;
+ code -= 500;
+ }
+
+ /* ----- look up code ----- */
+ while(traverse->oldCode >= 0)
+ {
+ if(code == traverse->oldCode)
+ goto foundCode;
+ traverse++;
+ }
+
+ logerror("ConvertOldCode: %d not found\n", code);
+
+ /* ----- not found ----- */
+ *extendData = 0;
+ return 0;
+
+ /* ----- found ----- */
+ foundCode:
+
+ newCode = traverse->newCode;
+
+ /* ----- add in the CPU field ----- */
+ if(!(traverse->customField & kCustomField_DontApplyCPUField))
+ newCode = (newCode & ~0x1F000000) | ((cpu << 24) & 0x1F000000);
+
+ /* ----- hack-ish, subtract one from data field for x5 user select ----- */
+ if(traverse->customField & kCustomField_SubtractOne)
+ (*data)--; // yaay for C operator precedence
+
+ /* ----- set up the extend data ----- */
+ if(traverse->customField & kCustomField_BitMask)
+ *extendData = *data;
+ else
+ *extendData = 0xFFFFFFFF;
+
+ if(traverse->customField & kCustomField_ClearBit)
+ *data = 0;
+
+ if(linkCheat)
+ SET_MASK_FIELD(newCode, LinkEnable);
+
+ return newCode;
+}
+
+/*--------------------------------------------------------------------------------
+ HandleLocalCommandCheat - get special code which is not added into cheat list
+--------------------------------------------------------------------------------*/
+
+static void HandleLocalCommandCheat(UINT32 type, UINT32 address, UINT32 data, UINT32 extendData, char * name, char * description)
+{
+ switch(EXTRACT_FIELD(type, LocationType))
+ {
+ case kLocation_Custom:
+ switch(EXTRACT_FIELD(type, LocationParameter))
+ {
+ /* ----- activation key ----- */
+ case kCustomLocation_AssignActivationKey:
+ {
+ if(address < cheatListLength)
+ {
+ CheatEntry * entry = &cheatList[address];
+
+ if(!TEST_FIELD(type, OneShot))
+ {
+ /* ----- 1st activation key ----- */
+ entry->activationKey1 = data;
+ entry->flags |= kCheatFlag_HasActivationKey1;
+ }
+ else
+ {
+ /* ----- 2nd activation key ----- */
+ entry->activationKey2 = data;
+ entry->flags |= kCheatFlag_HasActivationKey2;
+ }
+ }
+ }
+ break;
+
+ /* ----- pre-enable ----- */
+ case kCustomLocation_Enable:
+ {
+ if(address < cheatListLength)
+ {
+ CheatEntry * entry = &cheatList[address];
+
+ ActivateCheat(entry);
+ }
+ }
+ break;
+
+ /* ----- over-clock ----- */
+ case kCustomLocation_Overclock:
+ {
+ if(address < cpu_gettotalcpu())
+ {
+ double overclock = data;
+
+ overclock /= 65536.0;
+
+ cpunum_set_clockscale(address, overclock);
+ }
+ }
+ break;
+
+ /* ----- refresh rate ----- */
+ case kCustomLocation_RefreshRate:
+ {
+ screen_state *state = &Machine->screen[0];
+ double refresh = data;
+
+ refresh /= 65536.0;
+
+ video_screen_configure(0, state->width, state->height, &state->visarea, HZ_TO_ATTOSECONDS(refresh));
+ }
+ break;
+ }
+ break;
+ }
+}
+
+/*------------------------------------------------
+ LoadCheatFile - load cheat code from database
+------------------------------------------------*/
+
+static void LoadCheatFile(char * fileName)
+{
+ mame_file * theFile;
+ file_error filerr;
+ char formatString[256];
+ char oldFormatString[256];
+ char buf[2048];
+ int recordNames = 0;
+
+ /* ----- open the database ----- */
+ filerr = mame_fopen(SEARCHPATH_CHEAT, fileName, OPEN_FLAG_READ, &theFile);
+
+ if(filerr != FILERR_NONE)
+ return;
+
+ foundCheatDatabase = 1;
+
+ /* ----- make the format strings ----- */
+#ifdef MESS
+ sprintf(formatString, ":%s:%s", Machine->gamedrv->name, "%x:%x:%x:%x:%x:%[^:\n\r]:%[^:\n\r]");
+ sprintf(oldFormatString, "%s:%s", Machine->gamedrv->name, "%x:%d:%x:%x:%d:%[^:\n\r]:%[^:\n\r]");
+#else
+ sprintf(formatString, ":%s:%s", Machine->gamedrv->name, "%x:%x:%x:%x:%[^:\n\r]:%[^:\n\r]");
+ sprintf(oldFormatString, "%s:%s", Machine->gamedrv->name, "%d:%x:%x:%d:%[^:\n\r]:%[^:\n\r]");
+#endif
+
+ /* ----- get a line from database ----- */
+ while(mame_fgets(buf, 2048, theFile))
+ {
+ int type;
+ int address;
+ int data;
+ int extendData;
+ char name[256];
+ char description[256];
+#ifdef MESS
+ int crc;
+#endif
+
+ int argumentsMatched;
+ UINT32 command;
+
+ CheatEntry * entry;
+ CheatAction * action;
+
+ /* ----- get command line ----- */
+ argumentsMatched = sscanf(buf, ":_command:%8X", &command);
+
+ if(argumentsMatched == 1)
+ {
+ /* ----- set cheatOptions from command line ----- */
+ cheatOptions = command;
+
+ continue;
+ }
+
+ /* ----- get cheat code ----- */
+ name[0] = 0;
+ description[0] = 0;
+
+#ifdef MESS
+ argumentsMatched = sscanf(buf, formatString, &crc, &type, &address, &data, &extendData, name, description);
+#else
+ argumentsMatched = sscanf(buf, formatString, &type, &address, &data, &extendData, name, description);
+#endif
+
+#ifdef MESS
+ if(argumentsMatched < 5)
+#else
+ if(argumentsMatched < 4)
+#endif
+ {
+ int oldCPU;
+ int oldCode;
+
+#ifdef MESS
+ argumentsMatched = sscanf(buf, oldFormatString, &crc, &oldCPU, &address, &data, &oldCode, name, description);
+
+ if(argumentsMatched < 5)
+#else
+ argumentsMatched = sscanf(buf, oldFormatString, &oldCPU, &address, &data, &oldCode, name, description);
+
+ if(argumentsMatched < 4)
+#endif
+ /* ----- if it is not a cheat code, continue ----- */
+ continue;
+ else
+ {
+#ifdef MESS
+ if(!MatchesCRCTable(crc))
+ continue;
+#endif
+ /* ----- convert the old code to the new format ----- */
+ if(TEST_FIELD(cheatOptions, LoadOldFormat))
+ type = ConvertOldCode(oldCode, oldCPU, &data, &extendData);
+// continue;
+ }
+ }
+ else
+ {
+#ifdef MESS
+ if(!MatchesCRCTable(crc))
+ continue;
+#endif
+ }
+
+ //logerror("cheat: processing %s\n", buf);
+
+ if(TEST_FIELD(type, RemoveFromList))
+ {
+ //logerror("cheat: cheat line removed\n", buf);
+
+ HandleLocalCommandCheat(type, address, data, extendData, name, description);
+ }
+ else
+ {
+ if(TEST_FIELD(type, LinkEnable))
+ {
+ /* ----- if 1st code is the link code, it is invalid ----- */
+ if(cheatListLength == 0)
+ {
+ logerror("LoadCheatFile: first cheat found was link cheat; bailing\n");
+
+ goto bail;
+ }
+
+ //logerror("cheat: doing link cheat\n");
+
+ entry = &cheatList[cheatListLength - 1];
+ }
+ else
+ {
+ /* ----- go to the next cheat entry ----- */
+ ResizeCheatList(cheatListLength + 1);
+
+ //logerror("cheat: doing normal cheat\n");
+
+ if(cheatListLength == 0)
+ {
+ logerror("LoadCheatFile: cheat list resize failed; bailing\n");
+
+ goto bail;
+ }
+
+ entry = &cheatList[cheatListLength - 1];
+
+ /* ----- copy the code name ----- */
+ entry->name = CreateStringCopy(name);
+
+ /* ----- copy the description if we got it ----- */
+ if(argumentsMatched == 6)
+ entry->comment = CreateStringCopy(description);
+
+ recordNames = 0;
+
+ /* ----- try to copy the label if label-selection ------ */
+ if( (EXTRACT_FIELD(type, LocationType) == kLocation_Custom) &&
+ (EXTRACT_FIELD(type, LocationParameter) == kCustomLocation_Select))
+ recordNames = 1;
+ }
+
+ ResizeCheatActionList(&cheatList[cheatListLength - 1], entry->actionListLength + 1);
+
+ if(entry->actionListLength == 0)
+ {
+ logerror("LoadCheatFile: action list resize failed; bailing\n");
+
+ goto bail;
+ }
+
+ action = &entry->actionList[entry->actionListLength - 1];
+
+ action->type = type;
+ action->address = address;
+ action->data = data;
+ action->originalDataField = data;
+ action->extendData = extendData;
+
+ /* ----- copy the label if label-selection ------ */
+ if(recordNames)
+ action->optionalName = CreateStringCopy(name);
+ }
+ }
+
+ bail:
+
+ /* ----- close the database ----- */
+ mame_fclose(theFile);
+}
+
+/*---------------------------------------------------------
+ LoadCheatDatabase - get the database name then load it
+---------------------------------------------------------*/
+
+static void LoadCheatDatabase(void)
+{
+ char buf[4096];
+ const char * inTraverse;
+ char * outTraverse;
+ char * mainTraverse;
+ int first = 1;
+ char data;
+
+ cheatfile = options_get_string(mame_options(), OPTION_CHEAT_FILE);
+
+ /* ----- set default database name as "cheat.dat" ----- */
+ if (cheatfile[0] == 0)
+ cheatfile = "cheat.dat";
+
+ inTraverse = cheatfile;
+ outTraverse = buf;
+ mainTraverse = mainDatabaseName;
+
+ buf[0] = 0;
+
+ /* ----- get database name ----- */
+ do
+ {
+ data = *inTraverse;
+
+ /* ----- check separator or line end ----- */
+ if((data == ';') || (data == 0))
+ {
+ *outTraverse++ = 0;
+
+ if(first)
+ *mainTraverse++ = 0;
+
+ if(buf[0])
+ {
+ /* ----- load database based on the name we gotten ----- */
+ LoadCheatFile(buf);
+
+ outTraverse =buf;
+ buf[0] = 0;
+ first = 0;
+ }
+ }
+ else
+ {
+ *outTraverse++ = data;
+
+ if(first)
+ *mainTraverse++ = data;
+ }
+
+ inTraverse++;
+ }
+ while(data);
+
+ UpdateAllCheatInfo();
+}
+
+/*-----------------------------------------------------------------------------------------
+ DisposeCheatDatabase - deactivate all cheats when reload database or exit cheat system
+-----------------------------------------------------------------------------------------*/
+
+static void DisposeCheatDatabase(void)
+{
+ int i;
+
+ /* ----- first, turn all cheats "OFF" ----- */
+ for(i = 0; i < cheatListLength; i++)
+ TempDeactivateCheat(&cheatList[i]);
+
+ /* ----- next, free memory for all cheat entries ----- */
+ if(cheatList)
+ {
+ for(i = 0; i < cheatListLength; i++)
+ DisposeCheat(&cheatList[i]);
+
+ free(cheatList);
+
+ cheatList = NULL;
+ cheatListLength = 0;
+ }
+}
+
+/*-------------------------------------------------------------------------
+ ReloadCheatDatabase - reload cheat database directly on the cheat menu
+-------------------------------------------------------------------------*/
+
+static void ReloadCheatDatabase(void)
+{
+ DisposeCheatDatabase();
+ LoadCheatDatabase();
+
+ ui_popup_time(1, "Cheat Database reloaded");
+}
+
+/*---------------------------------------------------------------
+ SaveCheat - save a code (normal code, activation key, option)
+---------------------------------------------------------------*/
+
+static void SaveCheat(CheatEntry * entry, int selection, int saveCode)
+{
+ enum{
+ normalCode = 0,
+ activationKey,
+ command,
+ };
+
+ mame_file * theFile;
+ file_error filerr;
+ UINT32 i;
+ char buf[4096];
+
+ /* ----- check selected entry ----- */
+ if((saveCode == normalCode) || (saveCode == activationKey))
+ {
+ if(!entry || !entry->actionList)
+ return;
+
+ if((saveCode == activationKey) && (entry->flags & kCheatFlag_Select) && !entry->actionListLength)
+ return;
+ }
+
+ /* ----- open the database ----- */
+ filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE, &theFile);
+
+ /* ----- if fails to create, no save ----- */
+ if(!theFile)
+ return;
+ if (filerr != FILERR_NONE)
+ {
+ filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile);
+
+ /* ----- if fails to create, no save ----- */
+ if(filerr != FILERR_NONE)
+ return;
+ }
+
+ mame_fseek(theFile, 0, SEEK_END);
+
+ switch(saveCode)
+ {
+ case normalCode:
+ for(i = 0; i < entry->actionListLength; i++)
+ {
+ CheatAction * action = &entry->actionList[i];
+ char * name = entry->name;
+ UINT32 type = action->type;
+ char * bufTraverse = buf;
+ int addressLength = 8;
+
+ /* ----- set link enable and label if label-selection ----- */
+ if(i)
+ {
+ SET_MASK_FIELD(type, LinkEnable);
+
+ if(entry->flags & kCheatFlag_Select)
+ name = action->optionalName;
+ }
+
+ /* ----- get address length for current CPU ----- */
+ switch(EXTRACT_FIELD(type, LocationType))
+ {
+ case kLocation_Standard:
+ case kLocation_HandlerMemory:
+ case kLocation_ProgramSpace:
+ addressLength = cpuInfoList[EXTRACT_FIELD(type, LocationParameter)].addressCharsNeeded;
+ break;
+
+ case kLocation_IndirectIndexed:
+ addressLength = cpuInfoList[(EXTRACT_FIELD(type, LocationParameter) >> 2) & 0x7].addressCharsNeeded;
+ break;
+
+ case kLocation_MemoryRegion:
+ {
+ int idx = EXTRACT_FIELD(type, LocationParameter) + REGION_CPU1 - REGION_INVALID;
+
+ if(idx < kRegionListLength)
+ addressLength = regionInfoList[idx].addressCharsNeeded;
+ }
+ break;
+ }
+#ifdef MESS
+ bufTraverse += sprintf(bufTraverse, ":%s:%.8X:%.8X:%.*X:%.8X:%.8X", Machine->gamedrv->name, thisGameCRC, type, addressLength, action->address, action->originalDataField, action->extendData);
+#else
+ bufTraverse += sprintf(bufTraverse, ":%s:%.8X:%.*X:%.8X:%.8X", Machine->gamedrv->name, type, addressLength, action->address, action->originalDataField, action->extendData);
+#endif
+ /* ----- set description and comment ----- */
+ if(name)
+ {
+ bufTraverse += sprintf(bufTraverse, ":%s", name);
+
+ if(!i && (entry->comment))
+ bufTraverse += sprintf(bufTraverse, ":%s", entry->comment);
+ }
+ else
+ {
+ if(!i && (entry->comment))
+ bufTraverse += sprintf(bufTraverse, ":(none):%s", entry->comment);
+ }
+
+ bufTraverse += sprintf(bufTraverse, "\n");
+
+ /* ----- write the normal cheat code ----- */
+ mame_fwrite(theFile, buf, (UINT32)strlen(buf));
+ }
+ break;
+
+ case activationKey:
+ for(i = 0; i < 2; i++)
+ {
+ char * bufTraverse = buf;
+ int addressLength;
+
+ /* ----- if not find 1st activation key at saving 1st key, try to save 2nd key ----- */
+ if(!i && !(entry->flags & kCheatFlag_HasActivationKey1))
+ continue;
+
+ /* ----- if not find 2nd key after 1st key saved, finish ------ */
+ if(i && !(entry->flags & kCheatFlag_HasActivationKey2))
+ break;
+
+ /* ----- get address length for current CPU ----- */
+ if(!(entry->flags & kCheatFlag_Select))
+ addressLength = cpuInfoList[EXTRACT_FIELD(entry->actionList[0].type, LocationParameter)].addressCharsNeeded;
+ else
+ addressLength = cpuInfoList[EXTRACT_FIELD(entry->actionList[1].type, LocationParameter)].addressCharsNeeded;
+#ifdef MESS
+ if(!i)
+ bufTraverse += sprintf(bufTraverse, ":%s:%.8X:63004000:%.*X:%.8X:00000000", Machine->gamedrv->name, thisGameCRC, addressLength, selection, entry->activationKey1);
+ else
+ bufTraverse += sprintf(bufTraverse, ":%s:%.8X:63004001:%.*X:%.8X:00000000", Machine->gamedrv->name, thisGameCRC, addressLength, selection, entry->activationKey2);
+#else
+ if(!i)
+ bufTraverse += sprintf(bufTraverse, ":%s:63004000:%.*X:%.8X:00000000", Machine->gamedrv->name, addressLength, selection, entry->activationKey1);
+ else
+ bufTraverse += sprintf(bufTraverse, ":%s:63004001:%.*X:%.8X:00000000", Machine->gamedrv->name, addressLength, selection, entry->activationKey2);
+#endif
+ /* ----- set description and button index ----- */
+ if(!i)
+ {
+ /* ----- 1st key ----- */
+ astring *name = input_code_name(astring_alloc(), entry->activationKey1);
+ if (entry->name)
+ bufTraverse += sprintf(bufTraverse, ":1st Activation Key for %s (%s)\n", entry->name, astring_c(name));
+ else
+ bufTraverse += sprintf(bufTraverse, ":1st Activation Key (%s)\n", astring_c(name));
+ astring_free(name);
+ }
+ else
+ {
+ /* ----- 2nd key ----- */
+ astring *name = input_code_name(astring_alloc(), entry->activationKey2);
+ if (entry->name)
+ bufTraverse += sprintf(bufTraverse, ":2nd Activation Key for %s (%s)\n", entry->name, astring_c(name));
+ else
+ bufTraverse += sprintf(bufTraverse, ":2nd Activation Key (%s)\n", astring_c(name));
+ astring_free(name);
+ }
+
+ /* ----- write the activation key code ----- */
+ mame_fwrite(theFile, buf, (UINT32)strlen(buf));
+ }
+ break;
+
+ case command:
+ sprintf(buf, ":_command:%.8X\n", cheatOptions);
+
+ /* ----- write the command code ----- */
+ mame_fwrite(theFile, buf, (UINT32)strlen(buf));
+ break;
+
+ default:
+ break;
+ }
+
+ /* ----- close the database ----- */
+ mame_fclose(theFile);
+
+ /* ----- clear dirty flag ----- */
+ if((saveCode == normalCode) || (saveCode == activationKey))
+ entry->flags &= ~kCheatFlag_Dirty;
+}
+
+/*--------------------------------------------------------------------------
+ DoAutoSaveCheat - save normal code automatically when exit cheat system
+--------------------------------------------------------------------------*/
+
+static void DoAutoSaveCheats(void)
+{
+ int i;
+
+ for(i = 0; i < cheatListLength; i++)
+ {
+ CheatEntry * entry = &cheatList[i];
+
+ if(entry->flags & kCheatFlag_Dirty)
+ SaveCheat(entry, 0, 0);
+ }
+}
+
+/*-------------------------------------------------------------------
+ AddCheatFromResult - add a code from result viewer to cheat list
+-------------------------------------------------------------------*/
+
+static void AddCheatFromResult(SearchInfo * search, SearchRegion * region, UINT32 address)
+{
+ if(region->targetType == kRegionType_CPU)
+ {
+ CheatEntry * entry = GetNewCheat();
+ CheatAction * action = &entry->actionList[0];
+ char tempString[1024];
+ int tempStringLength;
+ UINT32 data = ReadSearchOperand(kSearchOperand_First, search, region, address);
+
+ tempStringLength = sprintf(tempString, "%.8X (%d) = %.*X", address, region->targetIdx, kSearchByteDigitsTable[search->bytes], data);
+
+ entry->name = realloc(entry->name, tempStringLength + 1);
+ memcpy(entry->name, tempString, tempStringLength + 1);
+
+ SET_FIELD(action->type, LocationParameter, region->targetIdx);
+ SET_FIELD(action->type, BytesUsed, kSearchByteIncrementTable[search->bytes] - 1);
+ action->address = address;
+ action->data = data;
+ action->extendData = 0xFFFFFFFF;
+ action->originalDataField = data;
+
+ UpdateCheatInfo(entry, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------------------------
+ AddCheatFromFirstResult - add a code from search box to cheat list if found result is one
+--------------------------------------------------------------------------------------------*/
+
+static void AddCheatFromFirstResult(SearchInfo * search)
+{
+ int i;
+
+ for(i = 0; i < search->regionListLength; i++)
+ {
+ SearchRegion * region = &search->regionList[i];
+
+ if(region->numResults)
+ {
+ UINT32 traverse;
+
+ for(traverse = 0; traverse < region->length; traverse++)
+ {
+ UINT32 address = region->address + traverse;
+
+ if(IsRegionOffsetValid(search, region, traverse))
+ {
+ AddCheatFromResult(search, region, address);
+
+ return;
+ }
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------
+ AddWatchFromResult - add a watch code from result viewer to cheat list
+-------------------------------------------------------------------------*/
+
+static void AddWatchFromResult(SearchInfo * search, SearchRegion * region, UINT32 address)
+{
+ if(region->targetType == kRegionType_CPU)
+ {
+ WatchInfo * info = GetUnusedWatch();
+
+ info->address = address;
+ info->cpu = region->targetIdx;
+ info->numElements = 1;
+ info->elementBytes = kWatchSizeConversionTable[search->bytes];
+ info->labelType = kWatchLabel_None;
+ info->displayType = kWatchDisplayType_Hex;
+ info->skip = 0;
+ info->elementsPerLine = 0;
+ info->addValue = 0;
+
+ info->linkedCheat = NULL;
+
+ info->label[0] = 0;
+ }
+}
+
+/*--------------------
+ SearchSignExtend
+--------------------*/
+
+static UINT32 SearchSignExtend(SearchInfo * search, UINT32 value)
+{
+ if(search->sign)
+ {
+ if(value & kSearchByteSignBitTable[search->bytes])
+ value |= ~kSearchByteUnsignedMaskTable[search->bytes];
+ }
+
+ return value;
+}
+
+/*-------------------------------------------------------------------
+ ReadSearchOperand - read a data from search region and return it
+-------------------------------------------------------------------*/
+
+static UINT32 ReadSearchOperand(UINT8 type, SearchInfo * search, SearchRegion * region, UINT32 address)
+{
+ UINT32 value = 0;
+
+ switch(type)
+ {
+ case kSearchOperand_Current:
+ value = ReadRegionData(region, address - region->address, kSearchByteIncrementTable[search->bytes], search->swap);
+ break;
+
+ case kSearchOperand_Previous:
+ value = DoMemoryRead(region->last, address - region->address, kSearchByteIncrementTable[search->bytes], search->swap, NULL);
+ break;
+
+ case kSearchOperand_First:
+ value = DoMemoryRead(region->first, address - region->address, kSearchByteIncrementTable[search->bytes], search->swap, NULL);
+ break;
+
+ case kSearchOperand_Value:
+ value = search->value;
+ break;
+ }
+
+ value = SearchSignExtend(search, value);
+
+ return value;
+}
+
+/*------------------------------------------------------------------------------------------
+ ReadSearchOperandBit - read a bit data from search region and return it when bit search
+------------------------------------------------------------------------------------------*/
+
+static UINT32 ReadSearchOperandBit(UINT8 type, SearchInfo * search, SearchRegion * region, UINT32 address)
+{
+ UINT32 value = 0;
+
+ switch(type)
+ {
+ case kSearchOperand_Current:
+ value = ReadRegionData(region, address - region->address, kSearchByteIncrementTable[search->bytes], search->swap);
+ break;
+
+ case kSearchOperand_Previous:
+ value = DoMemoryRead(region->last, address - region->address, kSearchByteIncrementTable[search->bytes], search->swap, NULL);
+ break;
+
+ case kSearchOperand_First:
+ value = DoMemoryRead(region->first, address - region->address, kSearchByteIncrementTable[search->bytes], search->swap, NULL);
+ break;
+
+ case kSearchOperand_Value:
+ if(search->value)
+ value = 0xFFFFFFFF;
+ else
+ value = 0x00000000;
+ break;
+ }
+
+ value = SearchSignExtend(search, value);
+
+ return value;
+}
+
+/*----------------------------------------------------------
+ DoSearchComparison - compare data and return it matched
+----------------------------------------------------------*/
+
+static UINT8 DoSearchComparison(SearchInfo * search, UINT32 lhs, UINT32 rhs)
+{
+ INT32 svalue;
+
+ if(search->sign)
+ {
+ /* ----- signed ----- */
+ INT32 slhs = lhs;
+ INT32 srhs = rhs;
+
+ switch(search->comparison)
+ {
+ case kSearchComparison_LessThan:
+ return slhs < srhs;
+
+ case kSearchComparison_GreaterThan:
+ return slhs > srhs;
+
+ case kSearchComparison_EqualTo:
+ return slhs == srhs;
+
+ case kSearchComparison_LessThanOrEqualTo:
+ return slhs <= srhs;
+
+ case kSearchComparison_GreaterThanOrEqualTo:
+ return slhs >= srhs;
+
+ case kSearchComparison_NotEqual:
+ return slhs != srhs;
+
+ case kSearchComparison_IncreasedBy:
+ svalue = search->value;
+ if(search->value & kSearchByteSignBitTable[search->bytes])
+ svalue |= ~kSearchByteUnsignedMaskTable[search->bytes];
+
+ return slhs == (srhs + svalue);
+
+ case kSearchComparison_NearTo:
+ return (slhs == srhs) || ((slhs + 1) == srhs);
+ }
+ }
+ else
+ {
+ /* ----- unsigned ----- */
+ switch(search->comparison)
+ {
+ case kSearchComparison_LessThan:
+ return lhs < rhs;
+
+ case kSearchComparison_GreaterThan:
+ return lhs > rhs;
+
+ case kSearchComparison_EqualTo:
+ return lhs == rhs;
+
+ case kSearchComparison_LessThanOrEqualTo:
+ return lhs <= rhs;
+
+ case kSearchComparison_GreaterThanOrEqualTo:
+ return lhs >= rhs;
+
+ case kSearchComparison_NotEqual:
+ return lhs != rhs;
+
+ case kSearchComparison_IncreasedBy:
+ svalue = search->value;
+ if(search->value & kSearchByteSignBitTable[search->bytes])
+ svalue |= ~kSearchByteUnsignedMaskTable[search->bytes];
+
+ return lhs == (rhs + svalue);
+
+ case kSearchComparison_NearTo:
+ return (lhs == rhs) || ((lhs + 1) == rhs);
+ }
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------
+ DoSearchComparisonBit - compare bit data and return it matched
+-----------------------------------------------------------------*/
+
+static UINT32 DoSearchComparisonBit(SearchInfo * search, UINT32 lhs, UINT32 rhs)
+{
+ switch(search->comparison)
+ {
+ case kSearchComparison_LessThan:
+ case kSearchComparison_NotEqual:
+ case kSearchComparison_GreaterThan:
+ case kSearchComparison_LessThanOrEqualTo:
+ case kSearchComparison_GreaterThanOrEqualTo:
+ case kSearchComparison_IncreasedBy:
+ return lhs ^ rhs;
+
+ case kSearchComparison_EqualTo:
+ case kSearchComparison_NearTo:
+ return ~(lhs ^ rhs);
+ }
+
+ return 0;
+}
+
+/*----------------------
+ IsRegionOffsetValid
+----------------------*/
+
+/*
+static UINT8 IsRegionOffsetValid(SearchInfo * search, SearchRegion * region, UINT32 offset)
+{
+ switch(kSearchByteIncrementTable[search->bytes])
+ {
+ case 1:
+ return *((UINT8 *)&region->status[offset]) == 0xFF;
+ break;
+
+ case 2:
+ return *((UINT16 *)&region->status[offset]) == 0xFFFF;
+ break;
+
+ case 4:
+ return *((UINT32 *)&region->status[offset]) == 0xFFFFFFFF;
+ break;
+ }
+
+ return 0;
+}
+*/
+
+/*----------------------------------------------------------
+ IsRegionOffsetValidBit - check selected offset is valid
+----------------------------------------------------------*/
+
+static UINT8 IsRegionOffsetValidBit(SearchInfo * search, SearchRegion * region, UINT32 offset)
+{
+ switch(kSearchByteStep[search->bytes])
+ {
+ case 1:
+ return *((UINT8 *)&region->status[offset]) != 0;
+ break;
+
+ case 2:
+ return *((UINT16 *)&region->status[offset]) != 0;
+ break;
+
+ case 3:
+ return ((*((UINT16 *)&region->status[offset]) != 0) | (*((UINT8 *)&region->status[offset+2]) != 0));
+ break;
+
+ case 4:
+ return *((UINT32 *)&region->status[offset]) != 0;
+ break;
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------
+ InvalidateRegionOffset - remove unmatched offset after search
+----------------------------------------------------------------*/
+
+static void InvalidateRegionOffset(SearchInfo * search, SearchRegion * region, UINT32 offset)
+{
+ switch(kSearchByteStep[search->bytes])
+ {
+ case 1:
+ *((UINT8 *)&region->status[offset]) = 0;
+ break;
+
+ case 2:
+ *((UINT16 *)&region->status[offset]) = 0;
+ break;
+
+ case 3:
+ *((UINT16 *)&region->status[offset]) = 0;
+ *((UINT8 *)&region->status[offset+2]) = 0;
+ break;
+
+ case 4:
+ *((UINT32 *)&region->status[offset]) = 0;
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ InvalidateRegionOffsetBit - remove unmatched offset after bit search
+-----------------------------------------------------------------------*/
+
+static void InvalidateRegionOffsetBit(SearchInfo * search, SearchRegion * region, UINT32 offset, UINT32 invalidate)
+{
+ switch(kSearchByteStep[search->bytes])
+ {
+ case 1:
+ *((UINT8 *)&region->status[offset]) &= ~invalidate;
+ break;
+
+ case 2:
+ *((UINT16 *)&region->status[offset]) &= ~invalidate;
+ break;
+
+ case 3:
+ *((UINT16 *)&region->status[offset]) &= ~invalidate;
+ *((UINT8 *)&region->status[offset+2]) &= ~invalidate;
+ break;
+
+ case 4:
+ *((UINT32 *)&region->status[offset]) &= ~invalidate;
+ break;
+ }
+}
+
+/*--------------------------------------------------------------
+ InvalidateEntireRegions - invalidate selected search region
+--------------------------------------------------------------*/
+
+static void InvalidateEntireRegion(SearchInfo * search, SearchRegion * region)
+{
+ memset(region->status, 0, region->length);
+
+ search->numResults -= region->numResults;
+ region->numResults = 0;
+}
+
+/*-------------------------------------------------------------------
+ InitializeNewSearch - initialize search region to start a search
+-------------------------------------------------------------------*/
+
+static void InitializeNewSearch(SearchInfo * search)
+{
+ int i;
+
+ search->numResults = 0;
+
+ for(i = 0; i < search->regionListLength; i++)
+ {
+ SearchRegion * region = &search->regionList[i];
+
+ if(region->flags & kRegionFlag_Enabled)
+ {
+ region->numResults = 0;
+
+ memset(region->status, 0xFF, region->length);
+
+ FillBufferFromRegion(region, region->first);
+
+ memcpy(region->last, region->first, region->length);
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+ UpdateSearch - updata a data in search region after initialize or search
+---------------------------------------------------------------------------*/
+
+static void UpdateSearch(SearchInfo * search)
+{
+ int i;
+
+ for(i = 0; i < search->regionListLength; i++)
+ {
+ SearchRegion * region = &search->regionList[i];
+
+ if(region->flags & kRegionFlag_Enabled)
+ FillBufferFromRegion(region, region->last);
+ }
+}
+
+/*-------------------------------------
+ DoSearch - management for a search
+-------------------------------------*/
+
+static void DoSearch(SearchInfo * search)
+{
+ int i, j;
+
+ search->numResults = 0;
+
+ if(search->bytes == kSearchSize_1Bit)
+ {
+ /* ----- bit search ----- */
+ for(i = 0; i < search->regionListLength; i++)
+ {
+ SearchRegion * region = &search->regionList[i];
+ UINT32 lastAddress = region->length - kSearchByteIncrementTable[search->bytes] + 1;
+ UINT32 increment = kSearchByteStep[search->bytes];
+
+ region->numResults = 0;
+
+ if((region->length < kSearchByteIncrementTable[search->bytes]) || !region->flags & kRegionFlag_Enabled)
+ continue;
+
+ for(j = 0; j < lastAddress; j += increment)
+ {
+ UINT32 address;
+ UINT32 lhs, rhs;
+
+ address = region->address + j;
+
+ if(IsRegionOffsetValidBit(search, region, j))
+ {
+ UINT32 validBits;
+
+ lhs = ReadSearchOperandBit(search->lhs, search, region, address);
+ rhs = ReadSearchOperandBit(search->rhs, search, region, address);
+
+ /* ----- do search ----- */
+ validBits = DoSearchComparisonBit(search, lhs, rhs);
+
+ InvalidateRegionOffsetBit(search, region, j, ~validBits);
+
+ if(IsRegionOffsetValidBit(search, region, j))
+ {
+ search->numResults++;
+ region->numResults++;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* ----- normal search ----- */
+ for(i = 0; i < search->regionListLength; i++)
+ {
+ SearchRegion * region = &search->regionList[i];
+ UINT32 lastAddress = region->length - kSearchByteIncrementTable[search->bytes] + 1;
+ UINT32 increment = kSearchByteStep[search->bytes];
+
+ region->numResults = 0;
+
+ if((region->length < kSearchByteIncrementTable[search->bytes]) || !region->flags & kRegionFlag_Enabled)
+ continue;
+
+ for(j = 0; j < lastAddress; j += increment)
+ {
+ UINT32 address;
+ UINT32 lhs, rhs;
+
+ address = region->address + j;
+
+ if(IsRegionOffsetValid(search, region, j))
+ {
+ lhs = ReadSearchOperand(search->lhs, search, region, address);
+ rhs = ReadSearchOperand(search->rhs, search, region, address);
+
+ /* ----- do search ----- */
+ if(!DoSearchComparison(search, lhs, rhs))
+ /* ----- unmatched ----- */
+ InvalidateRegionOffset(search, region, j);
+ else
+ {
+ /* ----- matched ----- */
+ search->numResults++;
+ region->numResults++;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*----------------------
+ LookupHandlerMemory
+----------------------*/
+
+static UINT8 ** LookupHandlerMemory(UINT8 cpu, UINT32 address, UINT32 * outRelativeAddress)
+{
+ const address_map * map = memory_get_map(cpu, ADDRESS_SPACE_PROGRAM);
+
+ while(!IS_AMENTRY_END(map))
+ {
+ if(!IS_AMENTRY_EXTENDED(map) && map->write.handler)
+ {
+ if((address >= map->start) && (address <= map->end))
+ {
+ if(outRelativeAddress)
+ *outRelativeAddress = address - map->start;
+
+ return (UINT8 **)map->base;
+ }
+ }
+
+ map++;
+ }
+
+ return NULL;
+}
+
+/*------------------------------------------
+ DoCPURead - read a data from RAM region
+------------------------------------------*/
+
+static UINT32 DoCPURead(UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap)
+{
+ switch(bytes)
+ {
+ case 1:
+ return (cpunum_read_byte(cpu, address + 0) << 0);
+
+ case 2:
+ if(swap)
+ return (cpunum_read_byte(cpu, address + 0) << 0) | (cpunum_read_byte(cpu, address + 1) << 8);
+ else
+ return (cpunum_read_byte(cpu, address + 0) << 8) | (cpunum_read_byte(cpu, address + 1) << 0);
+ break;
+
+ case 3:
+ if(swap)
+ return (cpunum_read_byte(cpu, address + 0) << 0) | (cpunum_read_byte(cpu, address + 1) << 8) |
+ (cpunum_read_byte(cpu, address + 2) << 16);
+ else
+ return (cpunum_read_byte(cpu, address + 0) << 16) | (cpunum_read_byte(cpu, address + 1) << 8) |
+ (cpunum_read_byte(cpu, address + 2) << 0);
+ break;
+
+ case 4:
+ if(swap)
+ return (cpunum_read_byte(cpu, address + 0) << 0) | (cpunum_read_byte(cpu, address + 1) << 8) |
+ (cpunum_read_byte(cpu, address + 2) << 16) | (cpunum_read_byte(cpu, address + 3) << 24);
+ else
+ return (cpunum_read_byte(cpu, address + 0) << 24) | (cpunum_read_byte(cpu, address + 1) << 16) |
+ (cpunum_read_byte(cpu, address + 2) << 8) | (cpunum_read_byte(cpu, address + 3) << 0);
+ break;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------
+ DoMemoryRead - read a data from ROM or User region
+-----------------------------------------------------*/
+
+static UINT32 DoMemoryRead(UINT8 * buf, UINT32 address, UINT8 bytes, UINT8 swap, CPUInfo * info)
+{
+ UINT32 data = 0;
+
+ if(!info)
+ {
+ switch(bytes)
+ {
+ case 1:
+ data = buf[address];
+ break;
+
+ case 2:
+ data = *((UINT16 *)&buf[address]);
+
+ if(swap)
+ data = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+ break;
+
+ case 4:
+ data = *((UINT32 *)&buf[address]);
+
+ if(swap)
+ data = ((data >> 24) & 0x000000FF) | ((data >> 8) & 0x0000FF00) |
+ ((data << 8) & 0x00FF0000) | ((data << 24) & 0xFF000000);
+ break;
+
+ default:
+ info = &rawCPUInfo;
+ goto generic;
+ }
+
+ return data;
+ }
+
+generic:
+
+ if(swap)
+ {
+ UINT32 i;
+
+ for(i = 0; i < bytes; i++)
+ data |= buf[SwapAddress(address + i, bytes, info)] << (i * 8);
+ }
+ else
+ {
+ UINT32 i;
+
+ for(i = 0; i < bytes; i++)
+ data |= buf[SwapAddress(address + i, bytes, info)] << ((bytes - i - 1) * 8);
+ }
+
+ return data;
+}
+
+/*--------------------------------------------
+ DoCPUWrite - write a data into RAM region
+--------------------------------------------*/
+
+static void DoCPUWrite(UINT32 data, UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap)
+{
+ switch(bytes)
+ {
+ case 1:
+ cpunum_write_byte(cpu, address + 0, data & 0xFF);
+ break;
+
+ case 2:
+ if(swap)
+ {
+ cpunum_write_byte(cpu, address + 0, (data >> 0) & 0xFF);
+ cpunum_write_byte(cpu, address + 1, (data >> 8) & 0xFF);
+ }
+ else
+ {
+ cpunum_write_byte(cpu, address + 0, (data >> 8) & 0xFF);
+ cpunum_write_byte(cpu, address + 1, (data >> 0) & 0xFF);
+ }
+ break;
+
+ case 3:
+ if(swap)
+ {
+ cpunum_write_byte(cpu, address + 0, (data >> 0) & 0xFF);
+ cpunum_write_byte(cpu, address + 1, (data >> 8) & 0xFF);
+ cpunum_write_byte(cpu, address + 2, (data >> 16) & 0xFF);
+ }
+ else
+ {
+ cpunum_write_byte(cpu, address + 0, (data >> 16) & 0xFF);
+ cpunum_write_byte(cpu, address + 1, (data >> 8) & 0xFF);
+ cpunum_write_byte(cpu, address + 2, (data >> 0) & 0xFF);
+ }
+ break;
+
+ case 4:
+ if(swap)
+ {
+ cpunum_write_byte(cpu, address + 0, (data >> 0) & 0xFF);
+ cpunum_write_byte(cpu, address + 1, (data >> 8) & 0xFF);
+ cpunum_write_byte(cpu, address + 2, (data >> 16) & 0xFF);
+ cpunum_write_byte(cpu, address + 3, (data >> 24) & 0xFF);
+ }
+ else
+ {
+ cpunum_write_byte(cpu, address + 0, (data >> 24) & 0xFF);
+ cpunum_write_byte(cpu, address + 1, (data >> 16) & 0xFF);
+ cpunum_write_byte(cpu, address + 2, (data >> 8) & 0xFF);
+ cpunum_write_byte(cpu, address + 3, (data >> 0) & 0xFF);
+ }
+ break;
+
+ default:
+ logerror("DoCPUWrite: bad size (%d)\n", bytes);
+ break;
+ }
+}
+
+/*-------------------------------------------------------
+ DoMemoryWrite - write a data into ROM or User region
+-------------------------------------------------------*/
+
+static void DoMemoryWrite(UINT32 data, UINT8 * buf, UINT32 address, UINT8 bytes, UINT8 swap, CPUInfo * info)
+{
+ if(!info)
+ {
+ switch(bytes)
+ {
+ case 1:
+ buf[address] = data;
+ break;
+
+ case 2:
+ if(swap)
+ data = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+
+ *((UINT16 *)&buf[address]) = data;
+ break;
+
+ case 4:
+ if(swap)
+ data = ((data >> 24) & 0x000000FF) | ((data >> 8) & 0x0000FF00) |
+ ((data << 8) & 0x00FF0000) | ((data << 24) & 0xFF000000);
+
+ *((UINT32 *)&buf[address]) = data;
+ break;
+
+ default:
+ info = &rawCPUInfo;
+ goto generic;
+ }
+
+ return;
+ }
+
+generic:
+
+ if(swap)
+ {
+ UINT32 i;
+
+ for(i = 0; i < bytes; i++)
+ buf[SwapAddress(address + i, bytes, info)] = data >> (i * 8);
+ }
+ else
+ {
+ UINT32 i;
+
+ for(i = 0; i < bytes; i++)
+ buf[SwapAddress(address + i, bytes, info)] = data >> ((bytes - i - 1) * 8);
+ }
+}
+
+/*--------------------------------
+ CPUNeedsSwap - endian checker
+--------------------------------*/
+
+static UINT8 CPUNeedsSwap(UINT8 cpu)
+{
+ return cpuInfoList[cpu].endianness ^ 1;
+}
+
+/*-----------------------------------
+ RegionNeedsSwap - endian checker
+-----------------------------------*/
+
+static UINT8 RegionNeedsSwap(UINT8 region)
+{
+ CPUInfo * temp = GetRegionCPUInfo(region);
+
+ if(temp)
+ return temp->endianness ^ 1;
+
+ return 0;
+}
+
+/*----------------------------------------------------
+ GetCPUInfo - return CPU info for standard region
+----------------------------------------------------*/
+
+static CPUInfo * GetCPUInfo(UINT8 cpu)
+{
+ return &cpuInfoList[cpu];
+}
+
+/*-------------------------------------------------
+ GetRegionCPUInfo - return CPU info for regions
+-------------------------------------------------*/
+
+static CPUInfo * GetRegionCPUInfo(UINT8 region)
+{
+ if((region >= REGION_INVALID) && (region < REGION_MAX))
+ return &regionInfoList[region - REGION_INVALID];
+
+ return NULL;
+}
+
+/*--------------
+ SwapAddress
+--------------*/
+
+static UINT32 SwapAddress(UINT32 address, UINT8 dataSize, CPUInfo * info)
+{
+ switch(info->dataBits)
+ {
+ case 16:
+ if(info->endianness == CPU_IS_BE)
+ return BYTE_XOR_BE(address);
+ else
+ return BYTE_XOR_LE(address);
+
+ case 32:
+ if(info->endianness == CPU_IS_BE)
+ return BYTE4_XOR_BE(address);
+ else
+ return BYTE4_XOR_LE(address);
+ }
+
+ return address;
+}
+
+/*------------------------------------
+ ReadData - read a data per region
+------------------------------------*/
+
+static UINT32 ReadData(CheatAction * action)
+{
+ UINT8 parameter = EXTRACT_FIELD(action->type, LocationParameter);
+ UINT8 bytes = EXTRACT_FIELD(action->type, BytesUsed) + 1;
+ UINT8 swapBytes = EXTRACT_FIELD(action->type, Endianness);
+
+ switch(EXTRACT_FIELD(action->type, LocationType))
+ {
+ case kLocation_Standard:
+ return DoCPURead(parameter, action->address, bytes, CPUNeedsSwap(parameter) ^ swapBytes);
+ break;
+
+ case kLocation_MemoryRegion:
+ {
+ int region = REGION_CPU1 + parameter;
+ UINT8 * buf = memory_region(region);
+
+ if(buf)
+ {
+ if(TEST_FIELD(cheatOptions, Debug))
+ {
+ if(ControlKeyPressed())
+ ui_popup_time(1, "MR : %x : %p", region, buf);
+ }
+
+ if(IsAddressInRange(action, memory_region_length(region)))
+ return DoMemoryRead(buf, action->address, bytes, RegionNeedsSwap(region) ^ swapBytes, GetRegionCPUInfo(region));
+ }
+ }
+ break;
+
+ case kLocation_HandlerMemory:
+ {
+ UINT32 relativeAddress;
+ UINT8 ** buf;
+
+ if(!action->cachedPointer)
+ action->cachedPointer = LookupHandlerMemory(parameter, action->address, &action->cachedOffset);
+
+ buf = action->cachedPointer;
+ relativeAddress = action->cachedOffset;
+
+ if(buf && *buf)
+ return DoMemoryRead(*buf, relativeAddress, bytes, CPUNeedsSwap(parameter) ^ swapBytes, GetCPUInfo(parameter));
+ }
+ break;
+
+ case kLocation_IndirectIndexed:
+ {
+ UINT32 address;
+ INT32 offset = action->extendData;
+ UINT8 cpu = (parameter >> 2) & 0x7;
+ UINT8 addressBytes = (parameter & 0x3) + 1;
+ CPUInfo * info = GetCPUInfo(cpu);
+
+ address = DoCPURead(cpu, action->address, addressBytes, CPUNeedsSwap(cpu) ^ swapBytes);
+
+ if(info)
+ address = DoShift(address, info->addressShift);
+
+ if(address)
+ {
+ address += offset;
+
+ return DoCPURead(cpu, address, bytes, CPUNeedsSwap(cpu) ^ swapBytes);
+ }
+ }
+ break;
+
+ case kLocation_ProgramSpace:
+ {
+ UINT8 * buf;
+
+ memory_set_opbase(action->address);
+
+ buf = memory_get_op_ptr(parameter, action->address, 0);
+
+ buf -= action->address;
+
+ if(buf)
+ {
+ if(TEST_FIELD(cheatOptions, Debug))
+ {
+ if(ControlKeyPressed())
+ ui_popup_time(1,"PG : %x : %p", parameter, buf);
+ }
+
+ return DoMemoryRead(buf, action->address, bytes, CPUNeedsSwap(parameter) ^ swapBytes, GetCPUInfo(parameter));
+ }
+ }
+ break;
+
+ case kLocation_Custom:
+ {
+ switch(parameter)
+ {
+ case kCustomLocation_Comment:
+ break;
+
+ case kCustomLocation_EEPROM:
+ {
+ int length;
+ UINT8 * buf;
+
+ buf = EEPROM_get_data_pointer(&length);
+
+ if(IsAddressInRange(action, length))
+ return DoMemoryRead(buf, action->address, bytes, swapBytes, &rawCPUInfo);
+ }
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------
+ WriteData - write a data per region
+--------------------------------------*/
+
+static void WriteData(CheatAction * action, UINT32 data)
+{
+ UINT8 parameter = EXTRACT_FIELD(action->type, LocationParameter);
+ UINT8 bytes = EXTRACT_FIELD(action->type, BytesUsed) + 1;
+ UINT8 swapBytes = EXTRACT_FIELD(action->type, Endianness);
+
+ switch(EXTRACT_FIELD(action->type, LocationType))
+ {
+ case kLocation_Standard:
+ DoCPUWrite(data, parameter, action->address, bytes, CPUNeedsSwap(parameter) ^ swapBytes);
+
+ break;
+
+ case kLocation_MemoryRegion:
+ {
+ int region = REGION_CPU1 + parameter;
+ UINT8 * buf = memory_region(region);
+
+ if(buf)
+ {
+ if(IsAddressInRange(action, memory_region_length(region)))
+ DoMemoryWrite(data, buf, action->address, bytes, RegionNeedsSwap(region) ^ swapBytes, GetRegionCPUInfo(region));
+ }
+ }
+ break;
+
+ case kLocation_HandlerMemory:
+ {
+ UINT32 relativeAddress;
+ UINT8 ** buf;
+
+ if(!action->cachedPointer)
+ {
+ action->cachedPointer = LookupHandlerMemory(parameter, action->address, &action->cachedOffset);
+ }
+
+ buf = action->cachedPointer;
+ relativeAddress = action->cachedOffset;
+
+ if(buf && *buf)
+ DoMemoryWrite(data, *buf, relativeAddress, bytes, CPUNeedsSwap(parameter) ^ swapBytes, GetCPUInfo(parameter));
+ }
+ break;
+
+ case kLocation_IndirectIndexed:
+ {
+ UINT32 address;
+ INT32 offset = action->extendData;
+ UINT8 cpu = (parameter >> 2) & 0x7;
+ UINT8 addressBytes = (parameter & 0x3) + 1;
+ CPUInfo * info = GetCPUInfo(cpu);
+
+ address = DoCPURead(cpu, action->address, addressBytes, CPUNeedsSwap(cpu) ^ swapBytes);
+
+ if(info)
+ address = DoShift(address, info->addressShift);
+
+ if(address)
+ {
+ address += offset;
+
+ DoCPUWrite(data, cpu, address, bytes, CPUNeedsSwap(cpu) ^ swapBytes);
+ }
+ }
+ break;
+
+ case kLocation_ProgramSpace:
+ {
+ UINT8 * buf;
+
+ memory_set_opbase(action->address);
+
+ buf = memory_get_op_ptr(parameter, action->address, 0);
+
+ buf -= action->address;
+
+ if(buf)
+ DoMemoryWrite(data, buf, action->address, bytes, CPUNeedsSwap(parameter) ^ swapBytes, GetCPUInfo(parameter));
+ }
+ break;
+
+ case kLocation_Custom:
+ {
+ switch(parameter)
+ {
+ case kCustomLocation_Comment:
+ break;
+
+ case kCustomLocation_EEPROM:
+ {
+ int length;
+ UINT8 * buf;
+
+ buf = EEPROM_get_data_pointer(&length);
+
+ if(IsAddressInRange(action, length))
+ DoMemoryWrite(data, buf, action->address, bytes, swapBytes, &rawCPUInfo);
+ }
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*-----------------------------------------------------
+ WatchCheatEntry - set watchpoint from action entry
+-----------------------------------------------------*/
+
+static void WatchCheatEntry(CheatEntry * entry, UINT8 associate)
+{
+ UINT32 i, j;
+ CheatEntry * associateEntry = NULL;
+
+ if(associate)
+ associateEntry = entry;
+
+ if(!entry)
+ return;
+
+ for(i = 0; i < entry->actionListLength; i++)
+ {
+ if(!i)
+ /* ----- first action entry ----- */
+ AddActionWatch(&entry->actionList[i], associateEntry);
+ else
+ {
+ /* ----- 2nd or later action entry ----- */
+ UINT8 sameAddress = 0;
+
+ for(j = 0; j < i; j++)
+ {
+ /* ----- if we find the same address action entry, skip it ----- */
+ if(entry->actionList[j].address == entry->actionList[i].address)
+ sameAddress = 1;
+ }
+
+ if(!sameAddress)
+ AddActionWatch(&entry->actionList[i], associateEntry);
+ }
+ }
+}
+
+/*--------------------------------------------------
+ AddActionWatch - add watchpoint into watch list
+--------------------------------------------------*/
+
+static void AddActionWatch(CheatAction * action, CheatEntry * entry)
+{
+ if( (EXTRACT_FIELD(action->type, LocationType) == kLocation_Standard) ||
+ (EXTRACT_FIELD(action->type, LocationType) == kLocation_MemoryRegion) ||
+ (EXTRACT_FIELD(action->type, LocationType) == kLocation_IndirectIndexed) ||
+ (EXTRACT_FIELD(action->type, LocationType) == kLocation_ProgramSpace))
+
+ {
+ WatchInfo * info = GetUnusedWatch();
+
+ info->address = action->address;
+ info->cpu = EXTRACT_FIELD(action->type, LocationParameter);
+ info->displayType = kWatchDisplayType_Hex;
+ info->elementBytes = kByteConversionTable[EXTRACT_FIELD(action->type, BytesUsed)];
+ info->label[0] = 0;
+ info->labelType = kWatchLabel_None;
+ info->linkedCheat = entry;
+ info->numElements = 1;
+ info->skip = 0;
+
+ info->locationType = EXTRACT_FIELD(action->type, LocationType);
+
+ if(EXTRACT_FIELD(action->type, Type) == kType_Watch)
+ {
+ /* ----- set watchpoint from watch code ----- */
+ UINT32 typeParameter = EXTRACT_FIELD(action->type, TypeParameter);
+
+ info->numElements = (action->data & 0xFF) + 1;
+
+ info->skip = (action->data >> 8) & 0xFF;
+ info->elementsPerLine = (action->data >> 16) & 0xFF;
+ info->addValue = (action->data >> 24) & 0xFF;
+
+ if(info->addValue & 0x80)
+ info->addValue |= ~0xFF;
+
+ if(action->extendData != 0xFFFFFFFF)
+ {
+ /* ### fix me... ### */
+ info->x = (float)((action->extendData >> 16) & 0xFFFF)/100;
+ info->y = (float)((action->extendData >> 0) & 0xFFFF)/100;
+ }
+
+ /* ----- if label is needed, copy the description from comment field ----- */
+ if((typeParameter & 0x04) && (entry->comment) && (strlen(entry->comment) < 256))
+ {
+ info->labelType = kWatchLabel_String;
+ strcpy(info->label, entry->comment);
+ }
+
+ info->displayType = typeParameter & 0x03;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------
+ RemoveAssociatedWatches - remove watchpoint when CODE is "OFF"
+-----------------------------------------------------------------*/
+
+static void RemoveAssociatedWatches(CheatEntry * entry)
+{
+ int i;
+
+ for(i = watchListLength - 1; i >= 0; i--)
+ {
+ WatchInfo * info = &watchList[i];
+
+ if(info->linkedCheat == entry)
+ DeleteWatchAt(i);
+ }
+}
+
+/*----------------------------------------------------------------------
+ ResetAction - back up data and set action flags when turn CODE "ON"
+----------------------------------------------------------------------*/
+
+static void ResetAction(CheatAction * action)
+{
+ action->frameTimer = 0;
+
+ /* ----- backup value ----- */
+ if(!(action->flags & kActionFlag_LastValueGood))
+ action->lastValue = ReadData(action);
+
+ action->flags &= ~kActionFlag_StateMask;
+ action->flags |= kActionFlag_LastValueGood;
+}
+
+/*-------------------------------------------------------------------------------------
+ ActivateCheat - reset action entry and set activate entry flag when turn CODE "ON"
+-------------------------------------------------------------------------------------*/
+
+static void ActivateCheat(CheatEntry * entry)
+{
+ int i;
+
+ for(i = 0; i < entry->actionListLength; i++)
+ {
+ CheatAction * action = &entry->actionList[i];
+
+ ResetAction(action);
+
+ /* ----- if watchpoint code, add watchpoint ----- */
+ if(EXTRACT_FIELD(action->type, Type) == kType_Watch)
+ AddActionWatch(action, entry);
+ }
+
+ entry->flags |= kCheatFlag_Active;
+}
+
+/*--------------------------------------------------------------------------------------
+ DeactivateCheat - restore previous value and remove watchpoint when turn CODE "OFF"
+--------------------------------------------------------------------------------------*/
+
+static void DeactivateCheat(CheatEntry * entry)
+{
+ int i;
+
+ for(i = 0; i < entry->actionListLength; i++)
+ {
+ CheatAction * action = &entry->actionList[i];
+
+ /* ----- restore previous value and clear backup flag if needed ----- */
+ if(EXTRACT_FIELD(action->type, RestorePreviousValue) && (action->flags & kActionFlag_LastValueGood))
+ {
+ WriteData(action, action->lastValue);
+
+ action->flags &= ~kActionFlag_LastValueGood;
+ }
+ }
+
+ /* ----- remove watchpoint ----- */
+ RemoveAssociatedWatches(entry);
+
+ entry->flags &= ~kCheatFlag_StateMask;
+}
+
+/*--------------------------------------------------------------------
+ TempDeactivateCheat - restore previous value when turn CHEAT "OFF"
+--------------------------------------------------------------------*/
+
+static void TempDeactivateCheat(CheatEntry * entry)
+{
+ if(entry->flags & kCheatFlag_Active)
+ {
+ int i;
+
+ for(i = 0; i < entry->actionListLength; i++)
+ {
+ CheatAction * action = &entry->actionList[i];
+
+ /* ----- restore previous value if needed ----- */
+ if(EXTRACT_FIELD(action->type, RestorePreviousValue) && (action->flags & kActionFlag_LastValueGood))
+ WriteData(action, action->lastValue);
+ }
+ }
+}
+
+/*------------------------------------------------------------
+ cheat_periodicOperation - management for cheat operations
+------------------------------------------------------------*/
+
+static void cheat_periodicOperation(CheatAction * action)
+{
+ UINT8 operation = EXTRACT_FIELD(action->type, Operation) | (EXTRACT_FIELD(action->type, OperationExtend) << 2);
+
+ switch(operation)
+ {
+ case kOperation_WriteMask:
+ {
+ UINT32 temp;
+
+ if(action->flags & kActionFlag_IgnoreMask)
+ WriteData(action, action->data);
+ else
+ {
+ temp = ReadData(action);
+
+ temp = (action->data & action->extendData) | (temp & ~action->extendData);
+
+ WriteData(action, temp);
+ }
+ }
+ break;
+
+ case kOperation_AddSubtract:
+ {
+ INT32 temp, bound;
+
+ /* ----- if extend data field is invalid, direct return ----- */
+ //if(action->flags & kActionFlag_IgnoreMask)
+ return;
+
+ temp = ReadData(action);
+
+ /* ----- OperationParameter field stores add/subtract ----- */
+ if(TEST_FIELD(action->type, OperationParameter))
+ {
+ /* ----- subtract ----- */
+ bound = action->extendData + action->data;
+
+ if(temp > bound)
+ temp -= action->data;
+ }
+ else
+ {
+ /* ----- add ----- */
+ bound = action->extendData - action->data;
+
+ if(temp < bound)
+ temp += action->data;
+ }
+
+ WriteData(action, temp);
+ }
+ break;
+
+ case kOperation_ForceRange:
+ {
+ UINT32 temp;
+
+ /* ----- if extend data field is invalid, direct return ----- */
+ if(action->flags & kActionFlag_IgnoreMask)
+ return;
+
+ temp = ReadData(action);
+
+ if(!TEST_FIELD(action->type, BytesUsed))
+ {
+ /* ----- 8 bit ----- */
+ if( (temp < ((action->extendData >> 8) & 0xFF)) || (temp > ((action->extendData >> 0) & 0xFF)))
+ {
+ temp = action->data;
+
+ WriteData(action, temp);
+ }
+ }
+ else
+ {
+ /* ----- 16 bit (or 24, 32 bit) ----- */
+ if( (temp < ((action->extendData >> 16) & 0xFFFF)) || (temp > ((action->extendData >> 0) & 0xFFFF)))
+ {
+ temp = action->data;
+
+ WriteData(action, temp);
+ }
+ }
+ }
+ break;
+
+ case kOperation_SetOrClearBits:
+ {
+ UINT32 temp;
+
+ temp = ReadData(action);
+
+ if(TEST_FIELD(action->type, OperationParameter))
+ /* ----- clear bit ----- */
+ temp &= ~action->data;
+ else
+ /* ----- set bit ----- */
+ temp |= action->data;
+
+ WriteData(action, temp);
+ }
+ break;
+
+ case kOperation_WriteMatch:
+ {
+ UINT32 temp;
+
+ /* ----- if extend data field is invalid, direct return ----- */
+ if(action->flags & kActionFlag_IgnoreMask)
+ return;
+
+ temp = ReadData(action);
+
+ /* ----- if current value matches appointed value, write ----- */
+ if(temp == action->extendData)
+ {
+ temp = action->data;
+
+ WriteData(action, temp);
+ }
+ }
+ break;
+
+ case kOperation_None:
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------
+ cheat_periodicAction - management for cheat actions
+------------------------------------------------------*/
+
+static void cheat_periodicAction(CheatAction * action)
+{
+ UINT8 parameter = EXTRACT_FIELD(action->type, TypeParameter);
+
+ /* ----- if operation is done in case of one shot, no action ----- */
+ if(action->flags & kActionFlag_OperationDone)
+ return;
+
+ if(TEST_FIELD(action->type, Prefill) && (!(action->flags & kActionFlag_PrefillDone)))
+ {
+ /* ----- pre-fill ----- */
+ UINT32 prefillValue = kPrefillValueTable[EXTRACT_FIELD(action->type, Prefill)];
+
+ if(!(action->flags & kActionFlag_PrefillWritten))
+ {
+ /* ----- set pre-fill value ---- */
+ WriteData(action, prefillValue);
+
+ action->flags |= kActionFlag_PrefillWritten;
+
+ return;
+ }
+ else
+ {
+ /* ----- if value is changed, try to write new value ----- */
+ if(ReadData(action) == prefillValue)
+ return;
+
+ action->flags |= kActionFlag_PrefillDone;
+ }
+ }
+
+ switch(EXTRACT_FIELD(action->type, Type))
+ {
+ case kType_NormalOrDelay:
+ {
+ if(TEST_FIELD(action->type, OneShot) && TEST_FIELD(action->type, RestorePreviousValue) && parameter)
+ {
+ /* ----- keep if one shot + restore prevous value + delay !=0 ----- */
+ cheat_periodicOperation(action);
+
+ if(action->frameTimer >= (parameter * ATTOSECONDS_TO_HZ(Machine->screen[0].refresh)))
+ {
+ action->frameTimer = 0;
+
+ action->flags |= kActionFlag_OperationDone;
+ }
+ else
+ action->frameTimer++;
+ }
+ else
+ {
+ /* ----- otherwise, delay ----- */
+ if(action->frameTimer >= (parameter * ATTOSECONDS_TO_HZ(Machine->screen[0].refresh)))
+ {
+ action->frameTimer = 0;
+
+ cheat_periodicOperation(action);
+
+ if(TEST_FIELD(action->type, OneShot))
+ action->flags |= kActionFlag_OperationDone;
+ }
+ else
+ action->frameTimer++;
+ }
+ }
+ break;
+
+ case kType_WaitForModification:
+ {
+ if(action->flags & kActionFlag_WasModified)
+ {
+ if(action->frameTimer <= 0)
+ {
+ cheat_periodicOperation(action);
+
+ action->flags &= ~kActionFlag_WasModified;
+
+ if(TEST_FIELD(action->type, OneShot))
+ action->flags |= kActionFlag_OperationDone;
+ }
+ else
+ action->frameTimer--;
+
+ action->lastValue = ReadData(action);
+ }
+ else
+ {
+ UINT32 currentValue = ReadData(action);
+
+ if(currentValue != action->lastValue)
+ {
+ action->frameTimer = parameter * ATTOSECONDS_TO_HZ(Machine->screen[0].refresh);
+
+ action->flags |= kActionFlag_WasModified;
+ }
+
+ action->lastValue = currentValue;
+ }
+ }
+ break;
+
+ case kType_IgnoreIfDecrementing:
+ {
+ UINT32 currentValue = ReadData(action);
+
+ /* ### is "NotEqual" correct ? "LessOrEqual" seems to be good... ### */
+ if(currentValue != (action->lastValue - parameter))
+ {
+ cheat_periodicOperation(action);
+
+ if(TEST_FIELD(action->type, OneShot))
+ action->flags |= kActionFlag_OperationDone;
+ }
+
+ action->lastValue = currentValue;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*-----------------------------------------------------
+ cheat_periodicEntry - management for cheat entries
+-----------------------------------------------------*/
+
+static void cheat_periodicEntry(CheatEntry * entry)
+{
+ int i;
+
+ /* ----- special handling for label-selection ----- */
+ if(entry->flags & kCheatFlag_Select)
+ {
+ /* ----- special handling for activation key ----- */
+ if((entry->flags & kCheatFlag_HasActivationKey1) || (entry->flags & kCheatFlag_HasActivationKey2))
+ {
+ if(input_code_pressed(entry->activationKey1) || input_code_pressed(entry->activationKey2))
+ {
+ if(!(entry->flags & kCheatFlag_ActivationKeyPressed))
+ {
+ /* ----- move current position until find OFF or no link extension code ----- */
+ do{
+ /* ----- 1st activation key pressed ----- */
+ if(input_code_pressed(entry->activationKey1))
+ {
+ entry->selection++;
+
+ if(entry->flags & kCheatFlag_OneShot)
+ {
+ if(entry->selection >= entry->actionListLength)
+ {
+ entry->selection = 1;
+
+ if(entry->selection >= entry->actionListLength)
+ entry->selection = 0;
+ }
+
+ if(!TEST_FIELD(entry->actionList[entry->selection].type, LinkExtension))
+ {
+ ActivateCheat(entry);
+
+ entry->flags |= kCheatFlag_DoOneShot;
+ }
+ }
+ else
+ {
+ if(entry->selection >= entry->actionListLength)
+ {
+ entry->selection = 0;
+
+ DeactivateCheat(entry);
+ }
+ else
+ {
+ if(!TEST_FIELD(entry->actionList[entry->selection].type, LinkExtension))
+ ActivateCheat(entry);
+ }
+ }
+ }
+ /* ----- 2nd activation key pressed ----- */
+ else
+ {
+ entry->selection--;
+
+ if(entry->flags & kCheatFlag_OneShot)
+ {
+ if(entry->selection <= 0)
+ entry->selection = entry->actionListLength - 1;
+
+ if(!TEST_FIELD(entry->actionList[entry->selection].type, LinkExtension))
+ {
+ ActivateCheat(entry);
+
+ entry->flags |= kCheatFlag_DoOneShot;
+ }
+ }
+ else
+ {
+ if(!entry->selection)
+ DeactivateCheat(entry);
+ else
+ {
+ if(entry->selection < 0)
+ entry->selection = entry->actionListLength - 1;
+
+ if(!TEST_FIELD(entry->actionList[entry->selection].type, LinkExtension))
+ ActivateCheat(entry);
+ }
+ }
+ }
+ }while(entry->selection && TEST_FIELD(entry->actionList[entry->selection].type, LinkExtension));
+
+ /* ----- display selected label name if needed ----- */
+ if(TEST_FIELD(cheatOptions, ActivationKeyMessage))
+ {
+ if(!entry->selection)
+ ui_popup_time(1,"%s disabled", entry->name);
+ else
+ ui_popup_time(1,"%s : %s selected", entry->name, entry->actionList[entry->selection].optionalName);
+ }
+
+ entry->flags |= kCheatFlag_ActivationKeyPressed; // set flag
+ }
+ }
+ else
+ entry->flags &= ~kCheatFlag_ActivationKeyPressed; // clear flag
+ }
+
+ /* ----- if a subcheat is selected, handle it ----- */
+ if(entry->selection)
+ {
+ i = entry->selection;
+
+ do{
+ if(!(entry->flags & kCheatFlag_OneShot) || (entry->flags & kCheatFlag_DoOneShot))
+ cheat_periodicAction(&entry->actionList[i]);
+
+ i++;
+
+ /* ----- if illegal index, finish ----- */
+ if(i >= entry->actionListLength)
+ break;
+
+ /* ----- if next code has link extension, handle it too ----- */
+ }while(TEST_FIELD(entry->actionList[i].type, LinkExtension));
+ }
+ }
+ else
+ {
+ /* ----- NOTE : activatinon key for value-selection is disabled -----*/
+ if(((entry->flags & kCheatFlag_HasActivationKey1) || (entry->flags & kCheatFlag_HasActivationKey2)) &&
+ !(entry->flags & kCheatFlag_UserSelect))
+ {
+ /* ----- special handling for activation key ----- */
+ if(input_code_pressed(entry->activationKey1) || input_code_pressed(entry->activationKey2))
+ {
+ if(!(entry->flags & kCheatFlag_ActivationKeyPressed))
+ {
+ if(entry->flags & kCheatFlag_OneShot)
+ {
+ ActivateCheat(entry);
+
+ /* ----- display description for one shot if needed ----- */
+ if(TEST_FIELD(cheatOptions, ActivationKeyMessage))
+ ui_popup_time(1,"set %s", entry->name);
+ }
+ else
+ {
+ if(entry->flags & kCheatFlag_Active)
+ {
+ DeactivateCheat(entry);
+
+ /* ----- display description for OFF if needed ----- */
+ if(TEST_FIELD(cheatOptions, ActivationKeyMessage))
+ ui_popup_time(1,"%s disabled", entry->name);
+ }
+ else
+ {
+ ActivateCheat(entry);
+
+ /* ----- display description for ON if needed ----- */
+ if(TEST_FIELD(cheatOptions, ActivationKeyMessage))
+ ui_popup_time(1,"%s enabled", entry->name);
+ }
+ }
+
+ entry->flags |= kCheatFlag_ActivationKeyPressed;
+ }
+ }
+ else
+ entry->flags &= ~kCheatFlag_ActivationKeyPressed;
+ }
+
+ if(!(entry->flags & kCheatFlag_Active))
+ return;
+
+ /* ----- update all actions ----- */
+ for(i = 0; i < entry->actionListLength; i++)
+ cheat_periodicAction(&entry->actionList[i]);
+
+ /* ----- if all actions are done, deactivate the cheat if oneshot entry ----- */
+ {
+ UINT8 done = 1;
+
+ for(i = 0 ; (i < entry->actionListLength && done) ; i++)
+ if(!(entry->actionList[i].flags & kActionFlag_OperationDone))
+ done = 0;
+
+ if(done)
+ DeactivateCheat(entry);
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ UpdateAllCheatInfo - update all cheat info when database loaded
+------------------------------------------------------------------*/
+
+static void UpdateAllCheatInfo(void)
+{
+ int i;
+
+ for(i = 0; i < cheatListLength; i++)
+ UpdateCheatInfo(&cheatList[i], 1);
+}
+
+/*--------------------------------------------------
+ UpdateCheatInfo - update entry, action and flag
+--------------------------------------------------*/
+
+static void UpdateCheatInfo(CheatEntry * entry, UINT8 isLoadTime)
+{
+ int isOneShot = 1;
+ int isNull = 1;
+ int flags = 0;
+ int i;
+
+ flags = entry->flags & kCheatFlag_PersistentMask;
+
+ /* ---- is it label-selection ? ----- */
+ if( (EXTRACT_FIELD(entry->actionList[0].type, LocationType) == kLocation_Custom) &&
+ (EXTRACT_FIELD(entry->actionList[0].type, LocationParameter) == kCustomLocation_Select))
+ flags |= kCheatFlag_Select;
+
+ for(i = 0; i < entry->actionListLength; i++)
+ {
+ CheatAction * action = &entry->actionList[i];
+
+ int isActionNull = 0;
+ UINT32 size;
+ UINT32 operation;
+ UINT32 actionFlags = action->flags & kActionFlag_PersistentMask;
+
+ size = EXTRACT_FIELD(action->type, BytesUsed);
+
+ operation = EXTRACT_FIELD(action->type, Operation) | EXTRACT_FIELD(action->type, OperationExtend) << 2;
+
+ /* ---- is it comment ? ----- */
+ if( (EXTRACT_FIELD(action->type, LocationType) == kLocation_Custom) &&
+ (EXTRACT_FIELD(action->type, LocationParameter) == kCustomLocation_Comment))
+ isActionNull = 1;
+ else
+ isNull = 0;
+
+ /* ---- is it one shot ? ----- */
+ if(!TEST_FIELD(action->type, OneShot))
+ isOneShot = 0;
+
+ /* ---- is it value-selection ? ----- */
+ if(TEST_FIELD(action->type, UserSelectEnable))
+ flags |= kCheatFlag_UserSelect;
+
+ /* ---- is it relative address ? ----- */
+ if(EXTRACT_FIELD(action->type, LocationType) == kLocation_IndirectIndexed)
+ actionFlags |= kActionFlag_IgnoreMask;
+ else
+ {
+ if(isLoadTime)
+ {
+ /* ----- check for mask == 0 and fix when database loaded ----- */
+ if((operation == kOperation_WriteMask) && (action->extendData == 0))
+ action->extendData = ~0;
+ }
+ }
+
+ action->flags = actionFlags;
+ }
+
+ /* ---- set one shot flag ----- */
+ if(isOneShot)
+ flags |= kCheatFlag_OneShot;
+
+ /* ---- set null flag ----- */
+ if(isNull)
+ flags |= kCheatFlag_Null;
+
+ entry->flags = (flags & kCheatFlag_InfoMask) | (entry->flags & ~kCheatFlag_InfoMask);
+
+ if(isLoadTime)
+ entry->flags &= ~kCheatFlag_Dirty;
+}
+
+/*--------------------------------------------------------------------------------
+ IsAddressInRange - check an address is in range (1 = in range, 0 = out range)
+--------------------------------------------------------------------------------*/
+
+static int IsAddressInRange(CheatAction * action, UINT32 length)
+{
+ UINT8 bytes = EXTRACT_FIELD(action->type, BytesUsed) + 1;
+
+ return ((action->address + bytes) <= length);
+}
+
+/*---------------------------------------------------------------
+ BuildCPUInfoList - get CPU info when initialize cheat system
+---------------------------------------------------------------*/
+
+static void BuildCPUInfoList(void)
+{
+ int i;
+
+ /* ----- do regions ----- */
+ {
+ const rom_entry * traverse = rom_first_region(Machine->gamedrv);
+
+ memset(regionInfoList, 0, sizeof(CPUInfo) * kRegionListLength);
+
+ while(traverse)
+ {
+ if(ROMENTRY_ISREGION(traverse))
+ {
+ UINT8 regionType = ROMREGION_GETTYPE(traverse);
+
+ /* ----- non-cpu region ? ----- */
+ if((regionType >= REGION_GFX1) && (regionType <= REGION_USER8))
+ {
+ CPUInfo * info = &regionInfoList[regionType - REGION_INVALID];
+ UINT32 length = memory_region_length(regionType);
+ int bitState = 0;
+
+ info->type = regionType;
+ info->dataBits = ROMREGION_GETWIDTH(traverse);
+
+ info->addressBits = 0;
+ info->addressMask = length;
+
+ /* ----- build address mask ----- */
+ for(i = 0; i < 32; i++)
+ {
+ UINT32 mask = 1 << (31 - i);
+
+ if(bitState)
+ info->addressMask |= mask;
+ else
+ {
+ if(info->addressMask & mask)
+ {
+ info->addressBits = 32 - i;
+ bitState = 1;
+ }
+ }
+ }
+
+ info->addressCharsNeeded = info->addressBits >> 2;
+
+ if(info->addressBits & 3)
+ info->addressCharsNeeded++;
+
+ info->endianness = ROMREGION_ISBIGENDIAN(traverse);
+ }
+ }
+
+ traverse = rom_next_region(traverse);
+ }
+ }
+
+ /* ----- do CPUs ----- */
+ {
+ memset(cpuInfoList, 0, sizeof(CPUInfo) * MAX_CPU);
+
+ for(i = 0; i < cpu_gettotalcpu(); i++)
+ {
+ CPUInfo * info = &cpuInfoList[i];
+ CPUInfo * regionInfo = &regionInfoList[REGION_CPU1 + i - REGION_INVALID];
+
+ cpu_type type = Machine->drv->cpu[i].type;
+
+ info->type = type;
+ info->dataBits = cputype_databus_width(type, ADDRESS_SPACE_PROGRAM);
+ info->addressBits = cputype_addrbus_width(type, ADDRESS_SPACE_PROGRAM);
+ info->addressMask = 0xFFFFFFFF >> (32 - cputype_addrbus_width(type, ADDRESS_SPACE_PROGRAM));
+
+ info->addressCharsNeeded = info->addressBits >> 2;
+ if(info->addressBits & 0x3)
+ info->addressCharsNeeded++;
+
+ info->endianness = (cputype_endianness(type) == CPU_IS_BE);
+
+ switch(type)
+ {
+#if HAS_TMS34010
+ case CPU_TMS34010:
+ info->addressShift = 3;
+ break;
+#endif
+#if HAS_TMS34020
+ case CPU_TMS34020:
+ info->addressShift = 3;
+ break;
+#endif
+ default:
+ info->addressShift = 0;
+ break;
+ }
+
+ /* ----- copy to region list ----- */
+ memcpy(regionInfo, info, sizeof(CPUInfo));
+ }
+ }
+}
+
diff --git a/src/emu/cheat.h b/src/emu/cheat.h
new file mode 100644
index 00000000000..566742c69f3
--- /dev/null
+++ b/src/emu/cheat.h
@@ -0,0 +1,25 @@
+/*********************************************************************
+
+ cheat.h
+
+ Cheat system.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __CHEAT_H__
+#define __CHEAT_H__
+
+#include "mamecore.h"
+
+void cheat_init(running_machine *machine);
+
+int cheat_menu(int selection);
+
+void cheat_display_watches(void);
+
+#endif /* __CHEAT_H__ */
diff --git a/src/emu/clifront.c b/src/emu/clifront.c
new file mode 100644
index 00000000000..ad7c39a74d2
--- /dev/null
+++ b/src/emu/clifront.c
@@ -0,0 +1,977 @@
+/***************************************************************************
+
+ clifront.c
+
+ Command-line interface frontend for MAME.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "emuopts.h"
+#include "clifront.h"
+#include "hash.h"
+#include "jedparse.h"
+#include "audit.h"
+#include "info.h"
+#include "unzip.h"
+#include "romload.h"
+#include "sound/samples.h"
+
+#include <ctype.h>
+
+#ifdef MESS
+#include "climess.h"
+#endif /* MESS */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _romident_status romident_status;
+struct _romident_status
+{
+ int total; /* total files processed */
+ int matches; /* number of matches found */
+ int nonroms; /* number of non-ROM files found */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int execute_simple_commands(core_options *options, const char *exename);
+static int execute_commands(core_options *options, const char *exename, const game_driver *driver);
+static void display_help(void);
+
+/* informational functions */
+static int info_verifyroms(core_options *options, const char *gamename);
+static int info_verifysamples(core_options *options, const char *gamename);
+static int info_romident(core_options *options, const char *gamename);
+
+/* utilities */
+static void romident(const char *filename, romident_status *status);
+static void identify_file(const char *name, romident_status *status);
+static void identify_data(const char *name, const UINT8 *data, int length, romident_status *status);
+static void match_roms(const char *hash, int length, int *found);
+
+
+
+/***************************************************************************
+ COMMAND-LINE OPTIONS
+***************************************************************************/
+
+const options_entry cli_options[] =
+{
+ /* core commands */
+ { NULL, NULL, OPTION_HEADER, "CORE COMMANDS" },
+ { "help;h;?", "0", OPTION_COMMAND, "show help message" },
+ { "validate;valid", "0", OPTION_COMMAND, "perform driver validation on all game drivers" },
+
+ /* configuration commands */
+ { NULL, NULL, OPTION_HEADER, "CONFIGURATION COMMANDS" },
+ { "createconfig;cc", "0", OPTION_COMMAND, "create the default configuration file" },
+ { "showconfig;sc", "0", OPTION_COMMAND, "display running parameters" },
+ { "showusage;su", "0", OPTION_COMMAND, "show this help" },
+
+ /* frontend commands */
+ { NULL, NULL, OPTION_HEADER, "FRONTEND COMMANDS" },
+ { "listxml;lx", "0", OPTION_COMMAND, "all available info on driver in XML format" },
+ { "listfull;ll", "0", OPTION_COMMAND, "short name, full name" },
+ { "listsource;ls", "0", OPTION_COMMAND, "driver sourcefile" },
+ { "listclones;lc", "0", OPTION_COMMAND, "show clones" },
+ { "listcrc", "0", OPTION_COMMAND, "CRC-32s" },
+ { "listroms", "0", OPTION_COMMAND, "list required roms for a driver" },
+ { "listsamples", "0", OPTION_COMMAND, "list optional samples for a driver" },
+ { "verifyroms", "0", OPTION_COMMAND, "report romsets that have problems" },
+ { "verifysamples", "0", OPTION_COMMAND, "report samplesets that have problems" },
+ { "romident", "0", OPTION_COMMAND, "compare files with known MAME roms" },
+#ifdef MESS
+ { "listdevices", "0", OPTION_COMMAND, "list available devices" },
+#endif
+
+ { NULL }
+};
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ cli_execute - execute a game via the standard
+ command line interface
+-------------------------------------------------*/
+
+int cli_execute(int argc, char **argv, const options_entry *osd_options)
+{
+ core_options *options;
+ astring *gamename = astring_alloc();
+ astring *exename = astring_alloc();
+ const game_driver *driver;
+ int result;
+
+ /* initialize the options manager and add the CLI-specific options */
+ options = mame_options_init(osd_options);
+ options_add_entries(options, cli_options);
+
+ /* parse the command line first; if we fail here, we're screwed */
+ if (options_parse_command_line(options, argc, argv, OPTION_PRIORITY_CMDLINE))
+ {
+ result = MAMERR_INVALID_CONFIG;
+ goto error;
+ }
+
+ /* parse the simple commmands before we go any further */
+ core_filename_extract_base(exename, argv[0], TRUE);
+ result = execute_simple_commands(options, astring_c(exename));
+ if (result != -1)
+ goto error;
+
+ /* find out what game we might be referring to */
+ core_filename_extract_base(gamename, options_get_string(options, OPTION_GAMENAME), TRUE);
+ driver = driver_get_name(astring_c(gamename));
+
+ /* execute any commands specified */
+ result = execute_commands(options, astring_c(exename), driver);
+ if (result != -1)
+ goto error;
+
+ /* if we don't have a valid driver selected, offer some suggestions */
+ if (astring_len(gamename) > 0 && driver == NULL)
+ {
+ const game_driver *matches[10];
+ int drvnum;
+
+ /* get the top 10 approximate matches */
+ driver_list_get_approx_matches(drivers, astring_c(gamename), ARRAY_LENGTH(matches), matches);
+
+ /* print them out */
+ fprintf(stderr, "\n\"%s\" approximately matches the following\n"
+ "supported " GAMESNOUN " (best match first):\n\n", astring_c(gamename));
+ for (drvnum = 0; drvnum < ARRAY_LENGTH(matches); drvnum++)
+ if (matches[drvnum] != NULL)
+ fprintf(stderr, "%-10s%s\n", matches[drvnum]->name, matches[drvnum]->description);
+
+ /* exit with an error */
+ result = MAMERR_NO_SUCH_GAME;
+ goto error;
+ }
+
+ /* run the game */
+ result = mame_execute(options);
+
+error:
+ /* free our options and exit */
+ options_free(options);
+ astring_free(gamename);
+ astring_free(exename);
+ return result;
+}
+
+
+/*-------------------------------------------------
+ help_output - output callback for printing
+ requested help information
+-------------------------------------------------*/
+
+static void help_output(const char *s)
+{
+ mame_printf_info("%s", s);
+}
+
+
+/*-------------------------------------------------
+ execute_simple_commands - execute basic
+ commands that don't require any context
+-------------------------------------------------*/
+
+static int execute_simple_commands(core_options *options, const char *exename)
+{
+ /* help? */
+ if (options_get_bool(options, CLIOPTION_HELP))
+ {
+ display_help();
+ return MAMERR_NONE;
+ }
+
+ /* showusage? */
+ if (options_get_bool(options, CLIOPTION_SHOWUSAGE))
+ {
+ mame_printf_info("Usage: %s [%s] [options]\n\nOptions:\n", exename, GAMENOUN);
+ options_output_help(options, help_output);
+ return MAMERR_NONE;
+ }
+
+ /* validate? */
+ if (options_get_bool(options, CLIOPTION_VALIDATE))
+ {
+ extern int mame_validitychecks(const game_driver *driver);
+ return mame_validitychecks(NULL);
+ }
+
+ return -1;
+}
+
+
+/*-------------------------------------------------
+ execute_commands - execute various frontend
+ commands
+-------------------------------------------------*/
+
+static int execute_commands(core_options *options, const char *exename, const game_driver *driver)
+{
+ static const struct
+ {
+ const char *option;
+ int (*function)(core_options *options, const char *gamename);
+ } info_commands[] =
+ {
+ { CLIOPTION_LISTXML, cli_info_listxml },
+ { CLIOPTION_LISTFULL, cli_info_listfull },
+ { CLIOPTION_LISTSOURCE, cli_info_listsource },
+ { CLIOPTION_LISTCLONES, cli_info_listclones },
+ { CLIOPTION_LISTCRC, cli_info_listcrc },
+#ifdef MESS
+ { CLIOPTION_LISTDEVICES, info_listdevices },
+#endif
+ { CLIOPTION_LISTROMS, cli_info_listroms },
+ { CLIOPTION_LISTSAMPLES, cli_info_listsamples },
+ { CLIOPTION_VERIFYROMS, info_verifyroms },
+ { CLIOPTION_VERIFYSAMPLES, info_verifysamples },
+ { CLIOPTION_ROMIDENT, info_romident }
+ };
+ int i;
+
+ /* createconfig? */
+ if (options_get_bool(options, CLIOPTION_CREATECONFIG))
+ {
+ file_error filerr;
+ mame_file *file;
+
+ /* parse any relevant INI files before proceeding */
+ mame_parse_ini_files(options, driver);
+
+ /* make the output filename */
+ filerr = mame_fopen_options(options, NULL, CONFIGNAME ".ini", OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
+
+ /* error if unable to create the file */
+ if (filerr != FILERR_NONE)
+ {
+ fprintf(stderr, "Unable to create file " CONFIGNAME ".ini\n");
+ return MAMERR_FATALERROR;
+ }
+
+ /* output the configuration and exit cleanly */
+ options_output_ini_file(options, mame_core_file(file));
+ mame_fclose(file);
+ return MAMERR_NONE;
+ }
+
+ /* showconfig? */
+ if (options_get_bool(options, CLIOPTION_SHOWCONFIG))
+ {
+ /* parse any relevant INI files before proceeding */
+ mame_parse_ini_files(options, driver);
+ options_output_ini_stdfile(options, stdout);
+ return MAMERR_NONE;
+ }
+
+ /* informational commands? */
+ for (i = 0; i < ARRAY_LENGTH(info_commands); i++)
+ if (options_get_bool(options, info_commands[i].option))
+ {
+ const char *gamename = options_get_string(options, OPTION_GAMENAME);
+
+ /* parse any relevant INI files before proceeding */
+ mame_parse_ini_files(options, driver);
+ return (*info_commands[i].function)(options, (gamename[0] == 0) ? "*" : gamename);
+ }
+
+ return -1;
+}
+
+
+/*-------------------------------------------------
+ display_help - display help to standard
+ output
+-------------------------------------------------*/
+
+static void display_help(void)
+{
+#ifndef MESS
+ mame_printf_info("M.A.M.E. v%s - Multiple Arcade Machine Emulator\n"
+ "Copyright (C) 1997-2007 by Nicola Salmoria and the MAME Team\n\n", build_version);
+ mame_printf_info("%s\n", mame_disclaimer);
+ mame_printf_info("Usage: MAME gamename [options]\n\n"
+ " MAME -showusage for a brief list of options\n"
+ " MAME -showconfig for a list of configuration options\n"
+ " MAME -createconfig to create a " CONFIGNAME ".ini\n\n"
+ "For usage instructions, please consult the file windows.txt\n");
+#else
+ mess_display_help();
+#endif
+}
+
+
+
+/***************************************************************************
+ INFORMATIONAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ cli_info_listxml - output the XML data for one
+ or more games
+-------------------------------------------------*/
+
+int cli_info_listxml(core_options *options, const char *gamename)
+{
+ /* since print_mame_xml expands the machine driver, we need to set things up */
+ init_resource_tracking();
+ cpuintrf_init(NULL);
+ sndintrf_init(NULL);
+
+ print_mame_xml(stdout, drivers, gamename);
+
+ /* clean up our tracked resources */
+ exit_resource_tracking();
+ return MAMERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ cli_info_listfull - output the name and description
+ of one or more games
+-------------------------------------------------*/
+
+int cli_info_listfull(core_options *options, const char *gamename)
+{
+ int drvindex, count = 0;
+
+ /* iterate over drivers */
+ for (drvindex = 0; drivers[drvindex]; drvindex++)
+ if ((drivers[drvindex]->flags & GAME_NO_STANDALONE) == 0 && mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
+ {
+ /* print the header on the first one */
+ if (count == 0)
+ mame_printf_info("Name: Description:\n");
+
+ /* output the remaining information */
+ mame_printf_info("%-10s\"%s\"\n", drivers[drvindex]->name, drivers[drvindex]->description);
+ count++;
+ }
+
+ /* return an error if none found */
+ return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME;
+}
+
+
+/*-------------------------------------------------
+ cli_info_listsource - output the name and source
+ filename of one or more games
+-------------------------------------------------*/
+
+int cli_info_listsource(core_options *options, const char *gamename)
+{
+ astring *filename = astring_alloc();
+ int drvindex, count = 0;
+
+ /* iterate over drivers */
+ for (drvindex = 0; drivers[drvindex]; drvindex++)
+ if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
+ {
+ /* output the remaining information */
+ mame_printf_info("%-8s %s\n", drivers[drvindex]->name, astring_c(core_filename_extract_base(filename, drivers[drvindex]->source_file, FALSE)));
+ count++;
+ }
+
+ /* return an error if none found */
+ astring_free(filename);
+ return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME;
+}
+
+
+/*-------------------------------------------------
+ cli_info_listclones - output the name and source
+ filename of one or more games
+-------------------------------------------------*/
+
+int cli_info_listclones(core_options *options, const char *gamename)
+{
+ int drvindex, count = 0;
+
+ /* iterate over drivers */
+ for (drvindex = 0; drivers[drvindex]; drvindex++)
+ {
+ const game_driver *clone_of = driver_get_clone(drivers[drvindex]);
+
+ /* if we are a clone, and either our name matches the gamename, or the clone's name matches, display us */
+ if (clone_of != NULL && (clone_of->flags & GAME_IS_BIOS_ROOT) == 0)
+ if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0 || mame_strwildcmp(gamename, clone_of->name) == 0)
+ {
+ /* print the header on the first one */
+ if (count == 0)
+ mame_printf_info("Name: Clone of:\n");
+
+ /* output the remaining information */
+ mame_printf_info("%-8s %-8s\n", drivers[drvindex]->name, clone_of->name);
+ count++;
+ }
+ }
+
+ /* return an error if none found */
+ return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME;
+}
+
+
+/*-------------------------------------------------
+ cli_info_listcrc - output the CRC and name of
+ all ROMs referenced by MAME
+-------------------------------------------------*/
+
+int cli_info_listcrc(core_options *options, const char *gamename)
+{
+ int drvindex, count = 0;
+
+ /* iterate over drivers */
+ for (drvindex = 0; drivers[drvindex]; drvindex++)
+ if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
+ {
+ const rom_entry *region, *rom;
+
+ /* iterate over regions, and then ROMs within the region */
+ for (region = rom_first_region(drivers[drvindex]); region; region = rom_next_region(region))
+ for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ {
+ char hashbuf[HASH_BUF_SIZE];
+
+ /* if we have a CRC, display it */
+ if (hash_data_extract_printable_checksum(ROM_GETHASHDATA(rom), HASH_CRC, hashbuf))
+ mame_printf_info("%s %-12s %s\n", hashbuf, ROM_GETNAME(rom), drivers[drvindex]->description);
+ }
+
+ count++;
+ }
+
+ /* return an error if none found */
+ return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME;
+}
+
+
+/*-------------------------------------------------
+ cli_info_listroms - output the list of ROMs
+ referenced by a given game or set of games
+-------------------------------------------------*/
+
+int cli_info_listroms(core_options *options, const char *gamename)
+{
+ int drvindex, count = 0;
+
+ /* iterate over drivers */
+ for (drvindex = 0; drivers[drvindex]; drvindex++)
+ if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
+ {
+ const rom_entry *region, *rom, *chunk;
+
+ /* print the header */
+ if (count > 0)
+ mame_printf_info("\n");
+ mame_printf_info("This is the list of the ROMs required for driver \"%s\".\n"
+ "Name Size Checksum\n", drivers[drvindex]->name);
+
+ /* iterate over regions and then ROMs within the region */
+ for (region = drivers[drvindex]->rom; region; region = rom_next_region(region))
+ for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ {
+ const char *name = ROM_GETNAME(rom);
+ const char* hash = ROM_GETHASHDATA(rom);
+ char hashbuf[HASH_BUF_SIZE];
+ int length = -1;
+
+ /* accumulate the total length of all chunks */
+ if (ROMREGION_ISROMDATA(region))
+ {
+ length = 0;
+ for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk))
+ length += ROM_GETLENGTH(chunk);
+ }
+
+ /* start with the name */
+ mame_printf_info("%-12s ", name);
+
+ /* output the length next */
+ if (length >= 0)
+ mame_printf_info("%7d", length);
+ else
+ mame_printf_info(" ");
+
+ /* output the hash data */
+ if (!hash_data_has_info(hash, HASH_INFO_NO_DUMP))
+ {
+ if (hash_data_has_info(hash, HASH_INFO_BAD_DUMP))
+ mame_printf_info(" BAD");
+
+ hash_data_print(hash, 0, hashbuf);
+ mame_printf_info(" %s", hashbuf);
+ }
+ else
+ mame_printf_info(" NO GOOD DUMP KNOWN");
+
+ /* end with a CR */
+ mame_printf_info("\n");
+ }
+
+ count++;
+ }
+
+ return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME;
+}
+
+
+/*-------------------------------------------------
+ cli_info_listsamples - output the list of samples
+ referenced by a given game or set of games
+-------------------------------------------------*/
+
+int cli_info_listsamples(core_options *options, const char *gamename)
+{
+ int count = 0;
+
+#if (HAS_SAMPLES)
+ int drvindex;
+
+ /* since we expand the machine driver, we need to set things up */
+ init_resource_tracking();
+ cpuintrf_init(NULL);
+ sndintrf_init(NULL);
+
+ /* iterate over drivers */
+ for (drvindex = 0; drivers[drvindex]; drvindex++)
+ if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
+ {
+ machine_config drv;
+ int sndnum;
+
+ /* expand the machine driver */
+ expand_machine_driver(drivers[drvindex]->drv, &drv);
+
+ /* find samples interfaces */
+ for (sndnum = 0; sndnum < MAX_SOUND && drv.sound[sndnum].type != SOUND_DUMMY; sndnum++)
+ if (drv.sound[sndnum].type == SOUND_SAMPLES)
+ {
+ const char **samplenames = ((struct Samplesinterface *)drv.sound[sndnum].config)->samplenames;
+ int sampnum;
+
+ /* if the list is legit, walk it and print the sample info */
+ if (samplenames != NULL)
+ for (sampnum = 0; samplenames[sampnum] != NULL; sampnum++)
+ mame_printf_info("%s\n", samplenames[sampnum]);
+ }
+
+ count++;
+ }
+
+ /* clean up our tracked resources */
+ exit_resource_tracking();
+#else
+ mame_printf_error("Samples not supported in this build\n");
+#endif
+
+ return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME;
+}
+
+
+/*-------------------------------------------------
+ info_verifyroms - verify the ROM sets of
+ one or more games
+-------------------------------------------------*/
+
+static int info_verifyroms(core_options *options, const char *gamename)
+{
+ int correct = 0;
+ int incorrect = 0;
+ int notfound = 0;
+ int drvindex;
+
+ /* iterate over drivers */
+ for (drvindex = 0; drivers[drvindex]; drvindex++)
+ if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
+ {
+ audit_record *audit;
+ int audit_records;
+ int res;
+
+ /* audit the ROMs in this set */
+ audit_records = audit_images(options, drivers[drvindex], AUDIT_VALIDATE_FAST, &audit);
+ res = audit_summary(drivers[drvindex], audit_records, audit, TRUE);
+ if (audit_records > 0)
+ free(audit);
+
+ /* if not found, count that and leave it at that */
+ if (res == NOTFOUND)
+ notfound++;
+
+ /* else display information about what we discovered */
+ else
+ {
+ const game_driver *clone_of;
+
+ /* output the name of the driver and its clone */
+ mame_printf_info("romset %s ", drivers[drvindex]->name);
+ clone_of = driver_get_clone(drivers[drvindex]);
+ if (clone_of != NULL)
+ mame_printf_info("[%s] ", clone_of->name);
+
+ /* switch off of the result */
+ switch (res)
+ {
+ case INCORRECT:
+ mame_printf_info("is bad\n");
+ incorrect++;
+ break;
+
+ case CORRECT:
+ mame_printf_info("is good\n");
+ correct++;
+ break;
+
+ case BEST_AVAILABLE:
+ mame_printf_info("is best available\n");
+ correct++;
+ break;
+ }
+ }
+ }
+
+ /* clear out any cached files */
+ zip_file_cache_clear();
+
+ /* if we didn't get anything at all, display a generic end message */
+ if (correct + incorrect == 0)
+ {
+ if (notfound > 0)
+ mame_printf_info("romset \"%s\" not found!\n", gamename);
+ else
+ mame_printf_info("romset \"%s\" not supported!\n", gamename);
+ return MAMERR_NO_SUCH_GAME;
+ }
+
+ /* otherwise, print a summary */
+ else
+ {
+ mame_printf_info("%d romsets found, %d were OK.\n", correct + incorrect, correct);
+ return (incorrect > 0) ? MAMERR_MISSING_FILES : MAMERR_NONE;
+ }
+}
+
+
+/*-------------------------------------------------
+ info_verifysamples - verify the sample sets of
+ one or more games
+-------------------------------------------------*/
+
+static int info_verifysamples(core_options *options, const char *gamename)
+{
+ int correct = 0;
+ int incorrect = 0;
+ int notfound = 0;
+ int drvindex;
+
+ /* now iterate over drivers */
+ for (drvindex = 0; drivers[drvindex]; drvindex++)
+ if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
+ {
+ audit_record *audit;
+ int audit_records;
+ int res;
+
+ /* audit the samples in this set */
+ audit_records = audit_samples(options, drivers[drvindex], &audit);
+ res = audit_summary(drivers[drvindex], audit_records, audit, TRUE);
+ if (audit_records > 0)
+ free(audit);
+ else
+ continue;
+
+ /* if not found, count that and leave it at that */
+ if (res == NOTFOUND)
+ notfound++;
+
+ /* else display information about what we discovered */
+ else
+ {
+ mame_printf_info("sampleset %s ", drivers[drvindex]->name);
+
+ /* switch off of the result */
+ switch (res)
+ {
+ case INCORRECT:
+ mame_printf_info("is bad\n");
+ incorrect++;
+ break;
+
+ case CORRECT:
+ mame_printf_info("is good\n");
+ correct++;
+ break;
+
+ case BEST_AVAILABLE:
+ mame_printf_info("is best available\n");
+ correct++;
+ break;
+ }
+ }
+ }
+
+ /* if we didn't get anything at all, display a generic end message */
+ if (correct + incorrect == 0)
+ {
+ if (notfound > 0)
+ mame_printf_error("sampleset \"%s\" not found!\n", gamename);
+ else
+ mame_printf_error("sampleset \"%s\" not supported!\n", gamename);
+ return MAMERR_NO_SUCH_GAME;
+ }
+
+ /* otherwise, print a summary */
+ else
+ {
+ mame_printf_info("%d samplesets found, %d were OK.\n", correct + incorrect, correct);
+ return (incorrect > 0) ? MAMERR_MISSING_FILES : MAMERR_NONE;
+ }
+}
+
+
+/*-------------------------------------------------
+ info_romident - identify ROMs by looking for
+ matches in our internal database
+-------------------------------------------------*/
+
+static int info_romident(core_options *options, const char *gamename)
+{
+ romident_status status;
+
+ /* a NULL gamename is a fatal error */
+ if (gamename == NULL)
+ return MAMERR_FATALERROR;
+
+ /* do the identification */
+ romident(gamename, &status);
+
+ /* clear out any cached files */
+ zip_file_cache_clear();
+
+ /* return the appropriate error code */
+ if (status.matches == status.total)
+ return MAMERR_NONE;
+ else if (status.matches == status.total - status.nonroms)
+ return MAMERR_IDENT_NONROMS;
+ else if (status.matches > 0)
+ return MAMERR_IDENT_PARTIAL;
+ else
+ return MAMERR_IDENT_NONE;
+}
+
+
+
+/***************************************************************************
+ UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ romident - identify files
+-------------------------------------------------*/
+
+static void romident(const char *filename, romident_status *status)
+{
+ osd_directory *directory;
+
+ /* reset the status */
+ memset(status, 0, sizeof(*status));
+
+ /* first try to open as a directory */
+ directory = osd_opendir(filename);
+ if (directory != NULL)
+ {
+ const osd_directory_entry *entry;
+
+ /* iterate over all files in the directory */
+ while ((entry = osd_readdir(directory)) != NULL)
+ if (entry->type == ENTTYPE_FILE)
+ {
+ astring *curfile = astring_assemble_3(astring_alloc(), filename, PATH_SEPARATOR, entry->name);
+ identify_file(astring_c(curfile), status);
+ astring_free(curfile);
+ }
+ osd_closedir(directory);
+ }
+
+ /* if that failed, and the filename ends with .zip, identify as a ZIP file */
+ else if (core_filename_ends_with(filename, ".zip"))
+ {
+ /* first attempt to examine it as a valid ZIP file */
+ zip_file *zip = NULL;
+ zip_error ziperr = zip_file_open(filename, &zip);
+ if (ziperr == ZIPERR_NONE && zip != NULL)
+ {
+ const zip_file_header *entry;
+
+ /* loop over entries in the ZIP, skipping empty files and directories */
+ for (entry = zip_file_first_file(zip); entry; entry = zip_file_next_file(zip))
+ if (entry->uncompressed_length != 0)
+ {
+ UINT8 *data = (UINT8 *)malloc(entry->uncompressed_length);
+ if (data != NULL)
+ {
+ /* decompress data into RAM and identify it */
+ ziperr = zip_file_decompress(zip, data, entry->uncompressed_length);
+ if (ziperr == ZIPERR_NONE)
+ identify_data(entry->filename, data, entry->uncompressed_length, status);
+ free(data);
+ }
+ }
+
+ /* close up */
+ zip_file_close(zip);
+ }
+ }
+
+ /* otherwise, identify as a raw file */
+ else
+ identify_file(filename, status);
+}
+
+
+/*-------------------------------------------------
+ identify_file - identify a file; if it is a
+ ZIP file, scan it and identify all enclosed
+ files
+-------------------------------------------------*/
+
+static void identify_file(const char *name, romident_status *status)
+{
+ file_error filerr;
+ osd_file *file;
+ UINT64 length;
+
+ /* open for read and process if it opens and has a valid length */
+ filerr = osd_open(name, OPEN_FLAG_READ, &file, &length);
+ if (filerr == FILERR_NONE && length > 0 && (UINT32)length == length)
+ {
+ UINT8 *data = (UINT8 *)malloc(length);
+ if (data != NULL)
+ {
+ UINT32 bytes;
+
+ /* read file data into RAM and identify it */
+ filerr = osd_read(file, data, 0, length, &bytes);
+ if (filerr == FILERR_NONE)
+ identify_data(name, data, bytes, status);
+ free(data);
+ }
+ osd_close(file);
+ }
+}
+
+
+/*-------------------------------------------------
+ identify_data - identify a buffer full of
+ data; if it comes from a .JED file, parse the
+ fusemap into raw data first
+-------------------------------------------------*/
+
+static void identify_data(const char *name, const UINT8 *data, int length, romident_status *status)
+{
+ char hash[HASH_BUF_SIZE];
+ UINT8 *tempjed = NULL;
+ astring *basename;
+ int found = 0;
+ jed_data jed;
+
+ /* if this is a '.jed' file, process it into raw bits first */
+ if (core_filename_ends_with(name, ".jed") && jed_parse(data, length, &jed) == JEDERR_NONE)
+ {
+ /* now determine the new data length and allocate temporary memory for it */
+ length = jedbin_output(&jed, NULL, 0);
+ tempjed = malloc(length);
+ if (tempjed == NULL)
+ return;
+
+ /* create a binary output of the JED data and use that instead */
+ jedbin_output(&jed, tempjed, length);
+ data = tempjed;
+ }
+
+ /* compute the hash of the data */
+ hash_data_clear(hash);
+ hash_compute(hash, data, length, HASH_SHA1 | HASH_CRC);
+
+ /* output the name */
+ status->total++;
+ basename = core_filename_extract_base(astring_alloc(), name, FALSE);
+ mame_printf_info("%-20s", astring_c(basename));
+ astring_free(basename);
+
+ /* see if we can find a match in the ROMs */
+ match_roms(hash, length, &found);
+
+ /* if we didn't find it, try to guess what it might be */
+ if (found == 0)
+ {
+ /* if not a power of 2, assume it is a non-ROM file */
+ if ((length & (length - 1)) != 0)
+ {
+ mame_printf_info("NOT A ROM\n");
+ status->nonroms++;
+ }
+
+ /* otherwise, it's just not a match */
+ else
+ mame_printf_info("NO MATCH\n");
+ }
+
+ /* if we did find it, count it as a match */
+ else
+ status->matches++;
+
+ /* free any temporary JED data */
+ if (tempjed != NULL)
+ free(tempjed);
+}
+
+
+/*-------------------------------------------------
+ match_roms - scan for a matching ROM by hash
+-------------------------------------------------*/
+
+static void match_roms(const char *hash, int length, int *found)
+{
+ int drvindex;
+
+ /* iterate over drivers */
+ for (drvindex = 0; drivers[drvindex]; drvindex++)
+ {
+ const rom_entry *region, *rom;
+
+ /* iterate over regions and files within the region */
+ for (region = rom_first_region(drivers[drvindex]); region; region = rom_next_region(region))
+ for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ if (hash_data_is_equal(hash, ROM_GETHASHDATA(rom), 0))
+ {
+ int baddump = hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_BAD_DUMP);
+
+ /* output information about the match */
+ if (*found != 0)
+ mame_printf_info(" ");
+ mame_printf_info("= %s%-20s %s\n", baddump ? "(BAD) " : "", ROM_GETNAME(rom), drivers[drvindex]->description);
+ (*found)++;
+ }
+ }
+}
diff --git a/src/emu/clifront.h b/src/emu/clifront.h
new file mode 100644
index 00000000000..4278a315325
--- /dev/null
+++ b/src/emu/clifront.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+
+ clifront.h
+
+ Command-line interface frontend for MAME.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CLIFRONT_H__
+#define __CLIFRONT_H__
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define CLIOPTION_CREATECONFIG "createconfig"
+#define CLIOPTION_SHOWCONFIG "showconfig"
+#define CLIOPTION_SHOWUSAGE "showusage"
+#define CLIOPTION_VALIDATE "validate"
+#define CLIOPTION_HELP "help"
+#define CLIOPTION_LISTXML "listxml"
+#define CLIOPTION_LISTFULL "listfull"
+#define CLIOPTION_LISTSOURCE "listsource"
+#define CLIOPTION_LISTCLONES "listclones"
+#define CLIOPTION_LISTCRC "listcrc"
+#define CLIOPTION_LISTDEVICES "listdevices"
+#define CLIOPTION_LISTROMS "listroms"
+#define CLIOPTION_LISTSAMPLES "listsamples"
+#define CLIOPTION_VERIFYROMS "verifyroms"
+#define CLIOPTION_VERIFYSAMPLES "verifysamples"
+#define CLIOPTION_ROMIDENT "romident"
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+int cli_execute(int argc, char **argv, const options_entry *osd_options);
+
+/* informational functions */
+int cli_info_listxml(core_options *options, const char *gamename);
+int cli_info_listfull(core_options *options, const char *gamename);
+int cli_info_listsource(core_options *options, const char *gamename);
+int cli_info_listclones(core_options *options, const char *gamename);
+int cli_info_listcrc(core_options *options, const char *gamename);
+int cli_info_listroms(core_options *options, const char *gamename);
+int cli_info_listsamples(core_options *options, const char *gamename);
+
+#endif /* __CLIFRONT_H__ */
diff --git a/src/emu/config.c b/src/emu/config.c
new file mode 100644
index 00000000000..7c014fef188
--- /dev/null
+++ b/src/emu/config.c
@@ -0,0 +1,363 @@
+/***************************************************************************
+
+ config.c
+
+ Configuration file I/O.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "config.h"
+#include "xmlfile.h"
+
+
+#define DEBUG_CONFIG 0
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define CONFIG_VERSION 10
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _config_type config_type;
+struct _config_type
+{
+ struct _config_type * next; /* next in line */
+ const char * name; /* node name */
+ config_callback load; /* load callback */
+ config_callback save; /* save callback */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static config_type *typelist;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int config_load_xml(mame_file *file, int type);
+static int config_save_xml(mame_file *file, int type);
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*************************************
+ *
+ * Reset the configuration callbacks
+ *
+ *************************************/
+
+void config_init(running_machine *machine)
+{
+ typelist = NULL;
+
+#ifdef MESS
+ mess_config_init(machine);
+#endif
+}
+
+
+
+/*************************************
+ *
+ * Register to be involved in config
+ * save/load
+ *
+ *************************************/
+
+void config_register(const char *nodename, config_callback load, config_callback save)
+{
+ config_type *newtype;
+ config_type **ptype;
+
+ /* allocate a new type */
+ newtype = auto_malloc(sizeof(*newtype));
+ newtype->next = NULL;
+ newtype->name = nodename;
+ newtype->load = load;
+ newtype->save = save;
+
+ /* add us to the end */
+ for (ptype = &typelist; *ptype; ptype = &(*ptype)->next) ;
+ *ptype = newtype;
+}
+
+
+
+/*************************************
+ *
+ * Settings save/load frontend
+ *
+ *************************************/
+
+int config_load_settings(void)
+{
+ const char *controller = options_get_string(mame_options(), OPTION_CTRLR);
+ file_error filerr;
+ config_type *type;
+ mame_file *file;
+ int loaded = 0;
+ astring *fname;
+
+ /* loop over all registrants and call their init function */
+ for (type = typelist; type; type = type->next)
+ (*type->load)(CONFIG_TYPE_INIT, NULL);
+
+ /* now load the controller file */
+ if (controller[0] != 0)
+ {
+ /* open the config file */
+ fname = astring_assemble_2(astring_alloc(), controller, ".cfg");
+ filerr = mame_fopen(SEARCHPATH_CTRLR, astring_c(fname), OPEN_FLAG_READ, &file);
+ astring_free(fname);
+
+ if (filerr != FILERR_NONE)
+ fatalerror("Could not load controller file %s.cfg", controller);
+
+ /* load the XML */
+ if (!config_load_xml(file, CONFIG_TYPE_CONTROLLER))
+ fatalerror("Could not load controller file %s.cfg", controller);
+ mame_fclose(file);
+ }
+
+ /* next load the defaults file */
+ filerr = mame_fopen(SEARCHPATH_CONFIG, "default.cfg", OPEN_FLAG_READ, &file);
+ if (filerr == FILERR_NONE)
+ {
+ config_load_xml(file, CONFIG_TYPE_DEFAULT);
+ mame_fclose(file);
+ }
+
+ /* finally, load the game-specific file */
+ fname = astring_assemble_2(astring_alloc(), Machine->basename, ".cfg");
+ filerr = mame_fopen(SEARCHPATH_CONFIG, astring_c(fname), OPEN_FLAG_READ, &file);
+ astring_free(fname);
+
+ if (filerr == FILERR_NONE)
+ {
+ loaded = config_load_xml(file, CONFIG_TYPE_GAME);
+ mame_fclose(file);
+ }
+
+ /* loop over all registrants and call their final function */
+ for (type = typelist; type; type = type->next)
+ (*type->load)(CONFIG_TYPE_FINAL, NULL);
+
+ /* if we didn't find a saved config, return 0 so the main core knows that it */
+ /* is the first time the game is run and it should diplay the disclaimer. */
+ return loaded;
+}
+
+
+void config_save_settings(void)
+{
+ file_error filerr;
+ config_type *type;
+ mame_file *file;
+ astring *fname;
+
+ /* loop over all registrants and call their init function */
+ for (type = typelist; type; type = type->next)
+ (*type->save)(CONFIG_TYPE_INIT, NULL);
+
+ /* save the defaults file */
+ filerr = mame_fopen(SEARCHPATH_CONFIG, "default.cfg", OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
+ if (filerr == FILERR_NONE)
+ {
+ config_save_xml(file, CONFIG_TYPE_DEFAULT);
+ mame_fclose(file);
+ }
+
+ /* finally, save the game-specific file */
+ fname = astring_assemble_2(astring_alloc(), Machine->basename, ".cfg");
+ filerr = mame_fopen(SEARCHPATH_CONFIG, astring_c(fname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
+ astring_free(fname);
+
+ if (filerr == FILERR_NONE)
+ {
+ config_save_xml(file, CONFIG_TYPE_GAME);
+ mame_fclose(file);
+ }
+
+ /* loop over all registrants and call their final function */
+ for (type = typelist; type; type = type->next)
+ (*type->save)(CONFIG_TYPE_FINAL, NULL);
+}
+
+
+
+/*************************************
+ *
+ * XML file load
+ *
+ *************************************/
+
+static int config_load_xml(mame_file *file, int which_type)
+{
+ xml_data_node *root, *confignode, *systemnode;
+ config_type *type;
+ const char *srcfile;
+ int version, count;
+
+ /* read the file */
+ root = xml_file_read(mame_core_file(file), NULL);
+ if (!root)
+ goto error;
+
+ /* find the config node */
+ confignode = xml_get_sibling(root->child, "mameconfig");
+ if (!confignode)
+ goto error;
+
+ /* validate the config data version */
+ version = xml_get_attribute_int(confignode, "version", 0);
+ if (version != CONFIG_VERSION)
+ goto error;
+
+ /* strip off all the path crap from the source filename */
+ srcfile = strrchr(Machine->gamedrv->source_file, '/');
+ if (!srcfile)
+ srcfile = strrchr(Machine->gamedrv->source_file, '\\');
+ if (!srcfile)
+ srcfile = strrchr(Machine->gamedrv->source_file, ':');
+ if (!srcfile)
+ srcfile = Machine->gamedrv->source_file;
+ else
+ srcfile++;
+
+ /* loop over all system nodes in the file */
+ count = 0;
+ for (systemnode = xml_get_sibling(confignode->child, "system"); systemnode; systemnode = xml_get_sibling(systemnode->next, "system"))
+ {
+ /* look up the name of the system here; skip if none */
+ const char *name = xml_get_attribute_string(systemnode, "name", "");
+
+ /* based on the file type, determine whether we have a match */
+ switch (which_type)
+ {
+ case CONFIG_TYPE_GAME:
+ /* only match on the specific game name */
+ if (strcmp(name, Machine->gamedrv->name) != 0)
+ continue;
+ break;
+
+ case CONFIG_TYPE_DEFAULT:
+ /* only match on default */
+ if (strcmp(name, "default") != 0)
+ continue;
+ break;
+
+ case CONFIG_TYPE_CONTROLLER:
+ {
+ const game_driver *clone_of;
+ /* match on: default, game name, source file name, parent name, grandparent name */
+ if (strcmp(name, "default") != 0 &&
+ strcmp(name, Machine->gamedrv->name) != 0 &&
+ strcmp(name, srcfile) != 0 &&
+ ((clone_of = driver_get_clone(Machine->gamedrv)) == NULL || strcmp(name, clone_of->name) != 0) &&
+ (clone_of == NULL || ((clone_of = driver_get_clone(clone_of)) == NULL) || strcmp(name, clone_of->name) != 0))
+ continue;
+ break;
+ }
+ }
+
+ /* log that we are processing this entry */
+ if (DEBUG_CONFIG)
+ mame_printf_debug("Entry: %s -- processing\n", name);
+
+ /* loop over all registrants and call their load function */
+ for (type = typelist; type; type = type->next)
+ (*type->load)(which_type, xml_get_sibling(systemnode->child, type->name));
+ count++;
+ }
+
+ /* error if this isn't a valid game match */
+ if (count == 0)
+ goto error;
+
+ /* free the parser */
+ xml_file_free(root);
+ return 1;
+
+error:
+ if (root)
+ xml_file_free(root);
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * XML file save
+ *
+ *************************************/
+
+static int config_save_xml(mame_file *file, int which_type)
+{
+ xml_data_node *root = xml_file_create();
+ xml_data_node *confignode, *systemnode;
+ config_type *type;
+
+ /* if we don't have a root, bail */
+ if (!root)
+ return 0;
+
+ /* create a config node */
+ confignode = xml_add_child(root, "mameconfig", NULL);
+ if (!confignode)
+ goto error;
+ xml_set_attribute_int(confignode, "version", CONFIG_VERSION);
+
+ /* create a system node */
+ systemnode = xml_add_child(confignode, "system", NULL);
+ if (!systemnode)
+ goto error;
+ xml_set_attribute(systemnode, "name", (which_type == CONFIG_TYPE_DEFAULT) ? "default" : Machine->gamedrv->name);
+
+ /* create the input node and write it out */
+ /* loop over all registrants and call their save function */
+ for (type = typelist; type; type = type->next)
+ {
+ xml_data_node *curnode = xml_add_child(systemnode, type->name, NULL);
+ if (!curnode)
+ goto error;
+ (*type->save)(which_type, curnode);
+
+ /* if nothing was added, just nuke the node */
+ if (!curnode->value && !curnode->child)
+ xml_delete_node(curnode);
+ }
+
+ /* flush the file */
+ xml_file_write(root, mame_core_file(file));
+
+ /* free and get out of here */
+ xml_file_free(root);
+ return 1;
+
+error:
+ xml_file_free(root);
+ return 0;
+}
diff --git a/src/emu/config.h b/src/emu/config.h
new file mode 100644
index 00000000000..31411684419
--- /dev/null
+++ b/src/emu/config.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+
+ config.h
+
+ Wrappers for handling MAME configuration files
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+#include "mame.h"
+#include "input.h"
+#include "xmlfile.h"
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define CONFIG_TYPE_INIT 0 /* opportunity to initialize things first */
+#define CONFIG_TYPE_CONTROLLER 1 /* loading from controller file */
+#define CONFIG_TYPE_DEFAULT 2 /* loading from default.cfg */
+#define CONFIG_TYPE_GAME 3 /* loading from game.cfg */
+#define CONFIG_TYPE_FINAL 4 /* opportunity to finish initialization */
+
+
+
+/*************************************
+ *
+ * Type definitions
+ *
+ *************************************/
+
+typedef void (*config_callback)(int config_type, xml_data_node *parentnode);
+
+
+
+/*************************************
+ *
+ * Function prototypes
+ *
+ *************************************/
+
+void config_init(running_machine *machine);
+void config_register(const char *nodename, config_callback load, config_callback save);
+int config_load_settings(void);
+void config_save_settings(void);
+
+#endif /* __CONFIG_H__ */
diff --git a/src/emu/cpu/adsp2100/2100dasm.c b/src/emu/cpu/adsp2100/2100dasm.c
new file mode 100644
index 00000000000..74bcc73c621
--- /dev/null
+++ b/src/emu/cpu/adsp2100/2100dasm.c
@@ -0,0 +1,550 @@
+#include "adsp2100.h"
+
+static const char *flag_change[] = { "", "TOGGLE %s ", "RESET %s ", "SET %s " };
+static const char *mode_change[] = { "", "", "DIS %s ", "ENA %s " };
+
+static const char *alu_xop[] = { "AX0", "AX1", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" };
+static const char *alu_yop[] = { "AY0", "AY1", "AF", "0" };
+static const char *alu_dst[] = { "AR", "AF", "NONE" };
+
+static const char *mac_xop[] = { "MX0", "MX1", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" };
+static const char *mac_yop[] = { "MY0", "MY1", "MF", "0" };
+static const char *mac_dst[] = { "MR", "MF" };
+
+static const char *shift_xop[] = { "SI", "??", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" };
+
+static const char *reg_grp[][16] =
+{
+ { "AX0", "AX1", "MX0", "MX1", "AY0", "AY1", "MY0", "MY1", "SI", "SE", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" },
+ { "I0", "I1", "I2", "I3", "M0", "M1", "M2", "M3", "L0", "L1", "L2", "L3", "??", "??", "??", "??" },
+ { "I4", "I5", "I6", "I7", "M4", "M5", "M6", "M7", "L4", "L5", "L6", "L7", "??", "??", "??", "??" },
+ { "ASTAT", "MSTAT", "SSTAT", "IMASK", "ICNTL", "CNTR", "SB", "PX", "RX0", "TX0", "RX1", "TX1", "IFC", "OWRCNTR", "??", "??" }
+};
+static const char *dual_xreg[] = { "AX0", "AX1", "MX0", "MX1" };
+static const char *dual_yreg[] = { "AY0", "AY1", "MY0", "MY1" };
+
+static const char *condition[] =
+{
+ "IF EQ ",
+ "IF NE ",
+ "IF GT ",
+ "IF LE ",
+ "IF LT ",
+ "IF GE ",
+ "IF AV ",
+ "IF NOT AV ",
+ "IF AC ",
+ "IF NOT AC ",
+ "IF NEG ",
+ "IF POS ",
+ "IF MV ",
+ "IF NOT MV ",
+ "IF NOT CE ",
+ ""
+};
+
+static const char *do_condition[] =
+{
+ "NE",
+ "EQ",
+ "LE",
+ "GT",
+ "GE",
+ "LT",
+ "NOT AV",
+ "AV",
+ "NOT AC",
+ "AC",
+ "POS",
+ "NEG",
+ "NOT MV",
+ "MV",
+ "CE",
+ "FOREVER"
+};
+
+static const char *alumac_op[][2] =
+{
+ { "", "" },
+ { "%s = %s * %s (RND)", "%s = %s * %s (RND)" },
+ { "%s = MR + %s * %s (RND)", "%s = MR + %s * %s (RND)" },
+ { "%s = MR - %s * %s (RND)", "%s = MR - %s * %s (RND)" },
+ { "%s = %s * %s (SS)", "%s = 0" },
+ { "%s = %s * %s (SU)", "%s = %s * %s (SU)" },
+ { "%s = %s * %s (US)", "%s = %s * %s (US)" },
+ { "%s = %s * %s (UU)", "%s = %s * %s (UU)" },
+ { "%s = MR + %s * %s (SS)", "%s = MR + %s * %s (SS)" },
+ { "%s = MR + %s * %s (SU)", "%s = MR + %s * %s (SU)" },
+ { "%s = MR + %s * %s (US)", "%s = MR + %s * %s (US)" },
+ { "%s = MR + %s * %s (UU)", "%s = MR + %s * %s (UU)" },
+ { "%s = MR - %s * %s (SS)", "%s = MR - %s * %s (SS)" },
+ { "%s = MR - %s * %s (SS)", "%s = MR - %s * %s (SS)" },
+ { "%s = MR - %s * %s (US)", "%s = MR - %s * %s (US)" },
+ { "%s = MR - %s * %s (UU)", "%s = MR - %s * %s (UU)" },
+
+ { "!%s = %s", "%s = 0" },
+ { "!%s = %s + 1", "%s = 1" },
+ { "%s = %s + %s + C", "%s = %s + %s + C" },
+ { "%s = %s + %s", "%s = %s" },
+ { "!%s = NOT %s", "!%s = NOT %s" },
+ { "!%s = -%s", "!%s = -%s" },
+ { "%s = %s - %s + C - 1", "%s = %s + C - 1" },
+ { "%s = %s - %s", "%s = %s - %s" },
+ { "!%s = %s - 1", "%s = -1" },
+ { "!%s = %s - %s", "%s = -%s" },
+ { "!%s = %s - %s + C - 1", "%s = -%s + C - 1" },
+ { "%s = NOT %s", "%s = NOT %s" },
+ { "%s = %s AND %s", "%s = %s AND %s" },
+ { "%s = %s OR %s", "%s = %s OR %s" },
+ { "%s = %s XOR %s", "%s = %s XOR %s" },
+ { "%s = ABS %s", "%s = ABS %s" }
+};
+
+static const char *shift_op[] =
+{
+ "SR = LSHIFT %s (HI)",
+ "SR = SR OR LSHIFT %s (HI)",
+ "SR = LSHIFT %s (LO)",
+ "SR = SR OR LSHIFT %s (LO)",
+ "SR = ASHIFT %s (HI)",
+ "SR = SR OR ASHIFT %s (HI)",
+ "SR = ASHIFT %s (LO)",
+ "SR = SR OR ASHIFT %s (LO)",
+ "SR = NORM %s (HI)",
+ "SR = SR OR NORM %s (HI)",
+ "SR = NORM %s (LO)",
+ "SR = SR OR NORM %s (LO)",
+ "SE = EXP %s (HI)",
+ "SE = EXP %s (HIX)",
+ "SE = EXP %s (LO)",
+ "SB = EXPADJ %s",
+};
+
+static const char *shift_by_op[] =
+{
+ "SR = LSHIFT %s BY %d (HI)",
+ "SR = SR OR LSHIFT %s BY %d (HI)",
+ "SR = LSHIFT %s BY %d (LO)",
+ "SR = SR OR LSHIFT %s BY %d (LO)",
+ "SR = ASHIFT %s BY %d (HI)",
+ "SR = SR OR ASHIFT %s BY %d (HI)",
+ "SR = ASHIFT %s BY %d (LO)",
+ "SR = SR OR ASHIFT %s BY %d (LO)",
+ "???",
+ "???",
+ "???",
+ "???",
+ "???",
+ "???",
+ "???",
+ "???"
+};
+
+static const char *constants[] =
+{
+ "$0001",
+ "$FFFE",
+ "$0002",
+ "$FFFD",
+ "$0004",
+ "$FFFB",
+ "$0008",
+ "$FFF7",
+ "$0010",
+ "$FFEF",
+ "$0020",
+ "$FFDF",
+ "$0040",
+ "$FFBF",
+ "$0080",
+ "$FF7F",
+ "$0100",
+ "$FEFF",
+ "$0200",
+ "$FDFF",
+ "$0400",
+ "$FBFF",
+ "$0800",
+ "$F7FF",
+ "$1000",
+ "$EFFF",
+ "$2000",
+ "$DFFF",
+ "$4000",
+ "$BFFF",
+ "$8000",
+ "$7FFF"
+};
+
+
+
+
+static int alumac(char *buffer, int dest, int op)
+{
+ int opindex = (op >> 13) & 31;
+ const char *xop, *yop, *dst, *opstring;
+
+ if (opindex & 16)
+ {
+ xop = alu_xop[(op >> 8) & 7];
+ yop = alu_yop[(op >> 11) & 3];
+ dst = alu_dst[dest];
+ }
+ else
+ {
+ xop = mac_xop[(op >> 8) & 7];
+ yop = mac_yop[(op >> 11) & 3];
+ dst = mac_dst[dest];
+ }
+ opstring = alumac_op[opindex][((op >> 11) & 3) == 3];
+ if (opstring[0] == '!')
+ return sprintf(buffer, opstring + 1, dst, yop, xop);
+ else
+ return sprintf(buffer, opstring, dst, xop, yop);
+}
+
+
+static int aluconst(char *buffer, int dest, int op)
+{
+ int opindex = (op >> 13) & 31;
+ const char *xop, *dst, *cval, *opstring;
+
+ if (opindex & 16)
+ {
+ xop = alu_xop[(op >> 8) & 7];
+ cval = constants[((op >> 5) & 0x07) | ((op >> 8) & 0x18)];
+ dst = alu_dst[dest];
+ }
+ else
+ {
+ xop = mac_xop[(op >> 8) & 7];
+ cval = xop;
+ dst = mac_dst[dest];
+ }
+ opstring = alumac_op[opindex][((op >> 11) & 3) == 3];
+ if (opstring[0] == '!')
+ return sprintf(buffer, opstring + 1, dst, cval, xop);
+ else
+ return sprintf(buffer, opstring, dst, xop, cval);
+}
+
+
+/* execute instructions on this CPU until icount expires */
+offs_t adsp2100_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ unsigned int op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16);
+ unsigned dasmflags = 0;
+ int temp;
+
+ switch ((op >> 16) & 0xff)
+ {
+ case 0x00:
+ /* 00000000 00000000 00000000 NOP */
+ sprintf(buffer, "%s", "NOP");
+ break;
+ case 0x01:
+ /* 00000000 0xxxxxxx xxxxxxxx dst = IO(x) */
+ /* 00000000 1xxxxxxx xxxxxxxx IO(x) = dst */
+ /* ADSP-218x only */
+ if ((op & 0x008000) == 0x000000)
+ buffer += sprintf(buffer, "%s = IO($%X)", reg_grp[0][op & 15], (op >> 4) & 0x7ff);
+ else
+ buffer += sprintf(buffer, "IO($%X) = %s", (op >> 4) & 0x7ff, reg_grp[0][op & 15]);
+ break;
+ case 0x02:
+ /* 00000010 0000xxxx xxxxxxxx modify flag out */
+ if ((op & 0x00f000) == 0x000000)
+ {
+ buffer += sprintf(buffer, "%s", condition[op & 15]);
+ buffer += sprintf(buffer, flag_change[(op >> 4) & 3], "FLAG_OUT");
+ buffer += sprintf(buffer, flag_change[(op >> 6) & 3], "FL0");
+ buffer += sprintf(buffer, flag_change[(op >> 8) & 3], "FL1");
+ buffer += sprintf(buffer, flag_change[(op >> 10) & 3], "FL2");
+ }
+ /* 00000010 10000000 00000000 idle */
+ /* 00000010 10000000 0000xxxx idle (n) */
+ else if ((op & 0x00fff0) == 0x008000)
+ {
+ }
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x03:
+ /* 00000011 xxxxxxxx xxxxxxxx call or jump on flag in */
+ if (op & 2)
+ buffer += sprintf(buffer, "%s", "IF FLAG_IN ");
+ else
+ buffer += sprintf(buffer, "%s", "IF NOT FLAG_IN ");
+ if (op & 1)
+ {
+ buffer += sprintf(buffer, "%s", "CALL ");
+ dasmflags = DASMFLAG_STEP_OVER;
+ }
+ else
+ buffer += sprintf(buffer, "%s", "JUMP ");
+ temp = ((op >> 4) & 0x0fff) | ((op << 10) & 0x3000);
+ buffer += sprintf(buffer, "$%04X", temp);
+ break;
+ case 0x04:
+ /* 00000100 00000000 000xxxxx stack control */
+ if ((op & 0x00ffe0) == 0x000000)
+ {
+ if (op & 0x000010)
+ {
+ buffer += sprintf(buffer, "%s", "POP PC ");
+ dasmflags = DASMFLAG_STEP_OUT;
+ }
+ if (op & 0x000008) buffer += sprintf(buffer, "%s", "POP LOOP ");
+ if (op & 0x000004) buffer += sprintf(buffer, "%s", "POP CNTR ");
+ if ((op & 0x000003) == 0x000002) buffer += sprintf(buffer, "%s", "PUSH STAT ");
+ else if ((op & 0x000003) == 0x000003) buffer += sprintf(buffer, "%s", "POP STAT ");
+ }
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x05:
+ /* 00000101 00000000 00000000 saturate MR */
+ if ((op & 0x00ffff) == 0x000000)
+ buffer += sprintf(buffer, "%s", "IF MV SAT MR");
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x06:
+ /* 00000110 000xxxxx 00000000 DIVS */
+ if ((op & 0x00e0ff) == 0x000000)
+ buffer += sprintf(buffer, "DIVS %s,%s", alu_yop[(op >> 11) & 3], alu_xop[(op >> 8) & 7]);
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x07:
+ /* 00000111 00010xxx 00000000 DIVQ */
+ if ((op & 0x00f8ff) == 0x001000)
+ buffer += sprintf(buffer, "DIVQ %s", alu_xop[(op >> 8) & 7]);
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x08:
+ /* 00001000 00000000 0000xxxx reserved */
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x09:
+ /* 00001001 00000000 000xxxxx modify address register */
+ if ((op & 0x00ffe0) == 0x000000)
+ {
+ temp = (op >> 2) & 4;
+ buffer += sprintf(buffer, "MODIFY (I%d,M%d)", temp + ((op >> 2) & 3), temp + (op & 3));
+ }
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x0a:
+ /* 00001010 00000000 0000xxxx conditional return */
+ if ((op & 0x00ffe0) == 0x000000)
+ {
+ buffer += sprintf(buffer, "%s", condition[op & 15]);
+ if (op & 0x000010)
+ buffer += sprintf(buffer, "%s", "RTI");
+ else
+ buffer += sprintf(buffer, "%s", "RTS");
+ dasmflags = DASMFLAG_STEP_OUT;
+ }
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x0b:
+ /* 00001011 00000000 xx00xxxx conditional jump (indirect address) */
+ if ((op & 0x00ff00) == 0x000000)
+ {
+ buffer += sprintf(buffer, "%s", condition[op & 15]);
+ if (op & 0x000010)
+ {
+ buffer += sprintf(buffer, "CALL (I%d)", 4 + ((op >> 6) & 3));
+ dasmflags = DASMFLAG_STEP_OVER;
+ }
+ else
+ buffer += sprintf(buffer, "JUMP (I%d)", 4 + ((op >> 6) & 3));
+ }
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x0c:
+ /* 00001100 xxxxxxxx xxxxxxxx mode control */
+ buffer += sprintf(buffer, mode_change[(op >> 4) & 3], "SEC_REG");
+ buffer += sprintf(buffer, mode_change[(op >> 6) & 3], "BIT_REV");
+ buffer += sprintf(buffer, mode_change[(op >> 8) & 3], "AV_LATCH");
+ buffer += sprintf(buffer, mode_change[(op >> 10) & 3], "AR_SAT");
+ buffer += sprintf(buffer, mode_change[(op >> 12) & 3], "M_MODE");
+ buffer += sprintf(buffer, mode_change[(op >> 14) & 3], "TIMER");
+ buffer += sprintf(buffer, mode_change[(op >> 2) & 3], "G_MODE");
+ break;
+ case 0x0d:
+ /* 00001101 0000xxxx xxxxxxxx internal data move */
+ if ((op & 0x00f000) == 0x000000)
+ buffer += sprintf(buffer, "%s = %s", reg_grp[(op >> 10) & 3][(op >> 4) & 15], reg_grp[(op >> 8) & 3][op & 15]);
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x0e:
+ /* 00001110 0xxxxxxx xxxxxxxx conditional shift */
+ if ((op & 0x0080f0) == 0x000000)
+ {
+ buffer += sprintf(buffer, "%s", condition[op & 15]);
+ buffer += sprintf(buffer, shift_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7]);
+ }
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x0f:
+ /* 00001111 0xxxxxxx xxxxxxxx shift immediate */
+ if ((op & 0x008000) == 0x000000)
+ buffer += sprintf(buffer, shift_by_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7], (signed char)op);
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x10:
+ /* 00010000 0xxxxxxx xxxxxxxx shift with internal data register move */
+ if ((op & 0x008000) == 0x000000)
+ {
+ buffer += sprintf(buffer, shift_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7]);
+ buffer += sprintf(buffer, ", %s = %s", reg_grp[0][(op >> 4) & 15], reg_grp[0][op & 15]);
+ }
+ else
+ buffer += sprintf(buffer, "??? (%06X)", op);
+ break;
+ case 0x11:
+ /* 00010001 0xxxxxxx xxxxxxxx shift with pgm memory read/write */
+ buffer += sprintf(buffer, shift_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7]);
+ if (op & 0x008000)
+ buffer += sprintf(buffer, ", PM(I%d,M%d) = %s", 4 + ((op >> 2) & 3), 4 + (op & 3), reg_grp[0][(op >> 4) & 15]);
+ else
+ buffer += sprintf(buffer, ", %s = PM(I%d,M%d)", reg_grp[0][(op >> 4) & 15], 4 + ((op >> 2) & 3), 4 + (op & 3));
+ break;
+ case 0x12: case 0x13:
+ /* 0001001x 0xxxxxxx xxxxxxxx shift with data memory read/write */
+ buffer += sprintf(buffer, shift_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7]);
+ temp = (op >> 14) & 4;
+ if (op & 0x008000)
+ buffer += sprintf(buffer, ", DM(I%d,M%d) = %s", temp + ((op >> 2) & 3), temp + (op & 3), reg_grp[0][(op >> 4) & 15]);
+ else
+ buffer += sprintf(buffer, ", %s = DM(I%d,M%d)", reg_grp[0][(op >> 4) & 15], temp + ((op >> 2) & 3), temp + (op & 3));
+ break;
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ /* 000101xx xxxxxxxx xxxxxxxx do until */
+ buffer += sprintf(buffer, "DO $%04X UNTIL %s", (op >> 4) & 0x3fff, do_condition[op & 15]);
+ break;
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ /* 00011xxx xxxxxxxx xxxxxxxx conditional jump (immediate addr) */
+ if (op & 0x040000)
+ {
+ buffer += sprintf(buffer, "%sCALL $%04X", condition[op & 15], (op >> 4) & 0x3fff);
+ dasmflags = DASMFLAG_STEP_OVER;
+ }
+ else
+ buffer += sprintf(buffer, "%sJUMP $%04X", condition[op & 15], (op >> 4) & 0x3fff);
+ break;
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+ /* 00100xxx xxxxxxxx xxxxxxxx conditional ALU/MAC */
+ buffer += sprintf(buffer, "%s", condition[op & 15]);
+ if (!(op & 0x10))
+ buffer += alumac(buffer, (op >> 18) & 1, op);
+ else
+ {
+ /* ADSP-218x only */
+ buffer += aluconst(buffer, (op >> 18) & 1, op);
+ }
+ break;
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ /* 00101xxx xxxxxxxx xxxxxxxx ALU/MAC with internal data register move */
+ if ((op & 0x0600ff) == 0x0200aa)
+ {
+ /* ADSP-218x only */
+ buffer += alumac(buffer, 2, op);
+ }
+ else
+ {
+ if ((op & 0x03e000) != 0)
+ {
+ buffer += alumac(buffer, (op >> 18) & 1, op);
+ buffer += sprintf(buffer, ", ");
+ }
+ buffer += sprintf(buffer, "%s = %s", reg_grp[0][(op >> 4) & 15], reg_grp[0][op & 15]);
+ }
+ break;
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ /* 0011xxxx xxxxxxxx xxxxxxxx load non-data register immediate */
+ buffer += sprintf(buffer, "%s = $%04X", reg_grp[(op >> 18) & 3][op & 15], (op >> 4) & 0x3fff);
+ break;
+ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
+ case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+ /* 0100xxxx xxxxxxxx xxxxxxxx load data register immediate */
+ buffer += sprintf(buffer, "%s = $%04X", reg_grp[0][op & 15], (op >> 4) & 0xffff);
+ break;
+ case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
+ case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
+ /* 0101xxxx xxxxxxxx xxxxxxxx ALU/MAC with pgm memory read/write */
+ if ((op & 0x03e000) != 0)
+ {
+ buffer += alumac(buffer, (op >> 18) & 1, op);
+ buffer += sprintf(buffer, ", ");
+ }
+ if (op & 0x080000)
+ buffer += sprintf(buffer, "PM(I%d,M%d) = %s", 4 + ((op >> 2) & 3), 4 + (op & 3), reg_grp[0][(op >> 4) & 15]);
+ else
+ buffer += sprintf(buffer, "%s = PM(I%d,M%d)", reg_grp[0][(op >> 4) & 15], 4 + ((op >> 2) & 3), 4 + (op & 3));
+ break;
+ case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
+ case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+ case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+ /* 011xxxxx xxxxxxxx xxxxxxxx ALU/MAC with data memory read/write */
+ if ((op & 0x03e000) != 0)
+ {
+ buffer += alumac(buffer, (op >> 18) & 1, op);
+ buffer += sprintf(buffer, ", ");
+ }
+ temp = (op >> 18) & 4;
+ if (op & 0x080000)
+ buffer += sprintf(buffer, "DM(I%d,M%d) = %s", temp + ((op >> 2) & 3), temp + (op & 3), reg_grp[0][(op >> 4) & 15]);
+ else
+ buffer += sprintf(buffer, "%s = DM(I%d,M%d)", reg_grp[0][(op >> 4) & 15], temp + ((op >> 2) & 3), temp + (op & 3));
+ break;
+ case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
+ case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
+ case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
+ case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
+ /* 100xxxxx xxxxxxxx xxxxxxxx read/write data memory (immediate addr) */
+ if (op & 0x100000)
+ buffer += sprintf(buffer, "DM($%04X) = %s", (op >> 4) & 0x3fff, reg_grp[(op >> 18) & 3][op & 15]);
+ else
+ buffer += sprintf(buffer, "%s = DM($%04X)", reg_grp[(op >> 18) & 3][op & 15], (op >> 4) & 0x3fff);
+ break;
+ case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
+ case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ /* 101xxxxx xxxxxxxx xxxxxxxx data memory write (immediate) */
+ temp = (op >> 18) & 4;
+ buffer += sprintf(buffer, "DM(I%d,M%d) = $%04X", temp + ((op >> 2) & 3), temp + (op & 3), (op >> 4) & 0xffff);
+ break;
+ case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
+ case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+ case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
+ case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
+ case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
+ case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
+ /* 11xxxxxx xxxxxxxx xxxxxxxx ALU/MAC with data & pgm memory read */
+ if ((op & 0x03e000) != 0)
+ {
+ buffer += alumac(buffer, 0, op);
+ buffer += sprintf(buffer, ", ");
+ }
+ buffer += sprintf(buffer, "%s = DM(I%d,M%d), %s = PM(I%d,M%d)", dual_xreg[(op >> 18) & 3], (op >> 2) & 3, op & 3,
+ dual_yreg[(op >> 20) & 3], 4 + ((op >> 6) & 3), 4 + ((op >> 4) & 3));
+ break;
+ }
+
+ return 1 | dasmflags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/adsp2100/2100ops.c b/src/emu/cpu/adsp2100/2100ops.c
new file mode 100644
index 00000000000..22e1e2b8cd7
--- /dev/null
+++ b/src/emu/cpu/adsp2100/2100ops.c
@@ -0,0 +1,2310 @@
+/*===========================================================================
+ ASTAT -- ALU/MAC status register
+===========================================================================*/
+
+/* flag definitions */
+#define SSFLAG 0x80
+#define MVFLAG 0x40
+#define QFLAG 0x20
+#define SFLAG 0x10
+#define CFLAG 0x08
+#define VFLAG 0x04
+#define NFLAG 0x02
+#define ZFLAG 0x01
+
+/* extracts flags */
+#define GET_SS (adsp2100.astat & SSFLAG)
+#define GET_MV (adsp2100.astat & MVFLAG)
+#define GET_Q (adsp2100.astat & QFLAG)
+#define GET_S (adsp2100.astat & SFLAG)
+#define GET_C (adsp2100.astat & CFLAG)
+#define GET_V (adsp2100.astat & VFLAG)
+#define GET_N (adsp2100.astat & NFLAG)
+#define GET_Z (adsp2100.astat & ZFLAG)
+
+/* clears flags */
+#define CLR_SS (adsp2100.astat &= ~SSFLAG)
+#define CLR_MV (adsp2100.astat &= ~MVFLAG)
+#define CLR_Q (adsp2100.astat &= ~QFLAG)
+#define CLR_S (adsp2100.astat &= ~SFLAG)
+#define CLR_C (adsp2100.astat &= ~CFLAG)
+#define CLR_V (adsp2100.astat &= ~VFLAG)
+#define CLR_N (adsp2100.astat &= ~NFLAG)
+#define CLR_Z (adsp2100.astat &= ~ZFLAG)
+
+/* sets flags */
+#define SET_SS (adsp2100.astat |= SSFLAG)
+#define SET_MV (adsp2100.astat |= MVFLAG)
+#define SET_Q (adsp2100.astat |= QFLAG)
+#define SET_S (adsp2100.astat |= SFLAG)
+#define SET_C (adsp2100.astat |= CFLAG)
+#define SET_V (adsp2100.astat |= VFLAG)
+#define SET_Z (adsp2100.astat |= ZFLAG)
+#define SET_N (adsp2100.astat |= NFLAG)
+
+/* flag clearing; must be done before setting */
+#define CLR_FLAGS (adsp2100.astat &= adsp2100.astat_clear)
+
+/* compute flags */
+#define CALC_Z(r) (adsp2100.astat |= ((r & 0xffff) == 0))
+#define CALC_N(r) (adsp2100.astat |= (r >> 14) & 0x02)
+#define CALC_V(s,d,r) (adsp2100.astat |= ((s ^ d ^ r ^ (r >> 1)) >> 13) & 0x04)
+#define CALC_C(r) (adsp2100.astat |= (r >> 13) & 0x08)
+#define CALC_C_SUB(r) (adsp2100.astat |= (~r >> 13) & 0x08)
+#define CALC_NZ(r) CLR_FLAGS; CALC_N(r); CALC_Z(r)
+#define CALC_NZV(s,d,r) CLR_FLAGS; CALC_N(r); CALC_Z(r); CALC_V(s,d,r)
+#define CALC_NZVC(s,d,r) CLR_FLAGS; CALC_N(r); CALC_Z(r); CALC_V(s,d,r); CALC_C(r)
+#define CALC_NZVC_SUB(s,d,r) CLR_FLAGS; CALC_N(r); CALC_Z(r); CALC_V(s,d,r); CALC_C_SUB(r)
+
+/* ADSP-218x constants */
+static const INT32 constants[] =
+{
+ 0x0001, 0xfffe, 0x0002, 0xfffd, 0x0004, 0xfffb, 0x0008, 0xfff7,
+ 0x0010, 0xffef, 0x0020, 0xffdf, 0x0040, 0xffbf, 0x0080, 0xff7f,
+ 0x0100, 0xfeff, 0x0200, 0xfdff, 0x0400, 0xfbff, 0x0800, 0xf7ff,
+ 0x1000, 0xefff, 0x2000, 0xdfff, 0x4000, 0xbfff, 0x8000, 0x7fff
+};
+
+
+
+/*===========================================================================
+ MSTAT -- ALU/MAC control register
+===========================================================================*/
+
+/* flag definitions */
+#define MSTAT_BANK 0x01 /* register bank select */
+#define MSTAT_REVERSE 0x02 /* bit-reverse addressing enable (DAG1) */
+#define MSTAT_STICKYV 0x04 /* sticky ALU overflow enable */
+#define MSTAT_SATURATE 0x08 /* AR saturation mode enable */
+#define MSTAT_INTEGER 0x10 /* MAC result placement; 0=fractional, 1=integer */
+#define MSTAT_TIMER 0x20 /* timer enable */
+#define MSTAT_GOMODE 0x40 /* go mode enable */
+
+/* you must call this in order to change MSTAT */
+INLINE void set_mstat(int new_value)
+{
+ if ((new_value ^ adsp2100.mstat) & MSTAT_BANK)
+ {
+ ADSPCORE temp = adsp2100.core;
+ adsp2100.core = adsp2100.alt;
+ adsp2100.alt = temp;
+ }
+ if ((new_value ^ adsp2100.mstat) & MSTAT_TIMER)
+ if (adsp2100.timer_callback)
+ (*adsp2100.timer_callback)((new_value & MSTAT_TIMER) != 0);
+ if (new_value & MSTAT_STICKYV)
+ adsp2100.astat_clear = ~(CFLAG | NFLAG | ZFLAG);
+ else
+ adsp2100.astat_clear = ~(CFLAG | VFLAG | NFLAG | ZFLAG);
+ adsp2100.mstat = new_value;
+}
+
+
+/*===========================================================================
+ SSTAT -- stack status register
+===========================================================================*/
+
+/* flag definitions */
+#define PC_EMPTY 0x01 /* PC stack empty */
+#define PC_OVER 0x02 /* PC stack overflow */
+#define COUNT_EMPTY 0x04 /* count stack empty */
+#define COUNT_OVER 0x08 /* count stack overflow */
+#define STATUS_EMPTY 0x10 /* status stack empty */
+#define STATUS_OVER 0x20 /* status stack overflow */
+#define LOOP_EMPTY 0x40 /* loop stack empty */
+#define LOOP_OVER 0x80 /* loop stack overflow */
+
+
+
+/*===========================================================================
+ PC stack handlers
+===========================================================================*/
+
+INLINE UINT32 pc_stack_top(void)
+{
+ if (adsp2100.pc_sp > 0)
+ return adsp2100.pc_stack[adsp2100.pc_sp - 1];
+ else
+ return adsp2100.pc_stack[0];
+}
+
+INLINE void set_pc_stack_top(UINT32 top)
+{
+ if (adsp2100.pc_sp > 0)
+ adsp2100.pc_stack[adsp2100.pc_sp - 1] = top;
+ else
+ adsp2100.pc_stack[0] = top;
+}
+
+INLINE void pc_stack_push(void)
+{
+ if (adsp2100.pc_sp < PC_STACK_DEPTH)
+ {
+ adsp2100.pc_stack[adsp2100.pc_sp] = adsp2100.pc;
+ adsp2100.pc_sp++;
+ adsp2100.sstat &= ~PC_EMPTY;
+ }
+ else
+ adsp2100.sstat |= PC_OVER;
+}
+
+INLINE void pc_stack_push_val(UINT32 val)
+{
+ if (adsp2100.pc_sp < PC_STACK_DEPTH)
+ {
+ adsp2100.pc_stack[adsp2100.pc_sp] = val;
+ adsp2100.pc_sp++;
+ adsp2100.sstat &= ~PC_EMPTY;
+ }
+ else
+ adsp2100.sstat |= PC_OVER;
+}
+
+INLINE void pc_stack_pop(void)
+{
+ if (adsp2100.pc_sp > 0)
+ {
+ adsp2100.pc_sp--;
+ if (adsp2100.pc_sp == 0)
+ adsp2100.sstat |= PC_EMPTY;
+ }
+ adsp2100.pc = adsp2100.pc_stack[adsp2100.pc_sp];
+ CHANGEPC();
+}
+
+INLINE UINT32 pc_stack_pop_val(void)
+{
+ if (adsp2100.pc_sp > 0)
+ {
+ adsp2100.pc_sp--;
+ if (adsp2100.pc_sp == 0)
+ adsp2100.sstat |= PC_EMPTY;
+ }
+ return adsp2100.pc_stack[adsp2100.pc_sp];
+}
+
+
+/*===========================================================================
+ CNTR stack handlers
+===========================================================================*/
+
+INLINE UINT32 cntr_stack_top(void)
+{
+ if (adsp2100.cntr_sp > 0)
+ return adsp2100.cntr_stack[adsp2100.cntr_sp - 1];
+ else
+ return adsp2100.cntr_stack[0];
+}
+
+INLINE void cntr_stack_push(void)
+{
+ if (adsp2100.cntr_sp < CNTR_STACK_DEPTH)
+ {
+ adsp2100.cntr_stack[adsp2100.cntr_sp] = adsp2100.cntr;
+ adsp2100.cntr_sp++;
+ adsp2100.sstat &= ~COUNT_EMPTY;
+ }
+ else
+ adsp2100.sstat |= COUNT_OVER;
+}
+
+INLINE void cntr_stack_pop(void)
+{
+ if (adsp2100.cntr_sp > 0)
+ {
+ adsp2100.cntr_sp--;
+ if (adsp2100.cntr_sp == 0)
+ adsp2100.sstat |= COUNT_EMPTY;
+ }
+ adsp2100.cntr = adsp2100.cntr_stack[adsp2100.cntr_sp];
+}
+
+
+/*===========================================================================
+ LOOP stack handlers
+===========================================================================*/
+
+INLINE UINT32 loop_stack_top(void)
+{
+ if (adsp2100.loop_sp > 0)
+ return adsp2100.loop_stack[adsp2100.loop_sp - 1];
+ else
+ return adsp2100.loop_stack[0];
+}
+
+INLINE void loop_stack_push(UINT32 value)
+{
+ if (adsp2100.loop_sp < LOOP_STACK_DEPTH)
+ {
+ adsp2100.loop_stack[adsp2100.loop_sp] = value;
+ adsp2100.loop_sp++;
+ adsp2100.loop = value >> 4;
+ adsp2100.loop_condition = value & 15;
+ adsp2100.sstat &= ~LOOP_EMPTY;
+ }
+ else
+ adsp2100.sstat |= LOOP_OVER;
+}
+
+INLINE void loop_stack_pop(void)
+{
+ if (adsp2100.loop_sp > 0)
+ {
+ adsp2100.loop_sp--;
+ if (adsp2100.loop_sp == 0)
+ {
+ adsp2100.loop = 0xffff;
+ adsp2100.loop_condition = 0;
+ adsp2100.sstat |= LOOP_EMPTY;
+ }
+ else
+ {
+ adsp2100.loop = adsp2100.loop_stack[adsp2100.loop_sp -1] >> 4;
+ adsp2100.loop_condition = adsp2100.loop_stack[adsp2100.loop_sp - 1] & 15;
+ }
+ }
+}
+
+
+/*===========================================================================
+ STAT stack handlers
+===========================================================================*/
+
+INLINE void stat_stack_push(void)
+{
+ if (adsp2100.stat_sp < STAT_STACK_DEPTH)
+ {
+ adsp2100.stat_stack[adsp2100.stat_sp][0] = adsp2100.mstat;
+ adsp2100.stat_stack[adsp2100.stat_sp][1] = adsp2100.imask;
+ adsp2100.stat_stack[adsp2100.stat_sp][2] = adsp2100.astat;
+ adsp2100.stat_sp++;
+ adsp2100.sstat &= ~STATUS_EMPTY;
+ }
+ else
+ adsp2100.sstat |= STATUS_OVER;
+}
+
+INLINE void stat_stack_pop(void)
+{
+ if (adsp2100.stat_sp > 0)
+ {
+ adsp2100.stat_sp--;
+ if (adsp2100.stat_sp == 0)
+ adsp2100.sstat |= STATUS_EMPTY;
+ }
+ set_mstat(adsp2100.stat_stack[adsp2100.stat_sp][0]);
+ adsp2100.imask = adsp2100.stat_stack[adsp2100.stat_sp][1];
+ adsp2100.astat = adsp2100.stat_stack[adsp2100.stat_sp][2];
+ check_irqs();
+}
+
+
+
+/*===========================================================================
+ condition code checking
+===========================================================================*/
+
+INLINE int CONDITION(int c)
+{
+ if (c != 14)
+ return condition_table[((c) << 8) | adsp2100.astat];
+ else if ((INT32)--adsp2100.cntr > 0)
+ return 1;
+ else
+ {
+ cntr_stack_pop();
+ return 0;
+ }
+}
+
+
+
+/*===========================================================================
+ register writing
+===========================================================================*/
+
+static void wr_inval(INT32 val) { logerror( "ADSP %04x: Writing to an invalid register!\n", adsp2100.ppc ); }
+static void wr_ax0(INT32 val) { adsp2100.core.ax0.s = val; }
+static void wr_ax1(INT32 val) { adsp2100.core.ax1.s = val; }
+static void wr_mx0(INT32 val) { adsp2100.core.mx0.s = val; }
+static void wr_mx1(INT32 val) { adsp2100.core.mx1.s = val; }
+static void wr_ay0(INT32 val) { adsp2100.core.ay0.s = val; }
+static void wr_ay1(INT32 val) { adsp2100.core.ay1.s = val; }
+static void wr_my0(INT32 val) { adsp2100.core.my0.s = val; }
+static void wr_my1(INT32 val) { adsp2100.core.my1.s = val; }
+static void wr_si(INT32 val) { adsp2100.core.si.s = val; }
+static void wr_se(INT32 val) { adsp2100.core.se.s = (INT8)val; }
+static void wr_ar(INT32 val) { adsp2100.core.ar.s = val; }
+static void wr_mr0(INT32 val) { adsp2100.core.mr.mrx.mr0.s = val; }
+static void wr_mr1(INT32 val) { adsp2100.core.mr.mrx.mr1.s = val; adsp2100.core.mr.mrx.mr2.s = (INT16)val >> 15; }
+static void wr_mr2(INT32 val) { adsp2100.core.mr.mrx.mr2.s = (INT8)val; }
+static void wr_sr0(INT32 val) { adsp2100.core.sr.srx.sr0.s = val; }
+static void wr_sr1(INT32 val) { adsp2100.core.sr.srx.sr1.s = val; }
+static void wr_i0(INT32 val) { adsp2100.i[0] = val & 0x3fff; adsp2100.base[0] = val & adsp2100.lmask[0]; }
+static void wr_i1(INT32 val) { adsp2100.i[1] = val & 0x3fff; adsp2100.base[1] = val & adsp2100.lmask[1]; }
+static void wr_i2(INT32 val) { adsp2100.i[2] = val & 0x3fff; adsp2100.base[2] = val & adsp2100.lmask[2]; }
+static void wr_i3(INT32 val) { adsp2100.i[3] = val & 0x3fff; adsp2100.base[3] = val & adsp2100.lmask[3]; }
+static void wr_i4(INT32 val) { adsp2100.i[4] = val & 0x3fff; adsp2100.base[4] = val & adsp2100.lmask[4]; }
+static void wr_i5(INT32 val) { adsp2100.i[5] = val & 0x3fff; adsp2100.base[5] = val & adsp2100.lmask[5]; }
+static void wr_i6(INT32 val) { adsp2100.i[6] = val & 0x3fff; adsp2100.base[6] = val & adsp2100.lmask[6]; }
+static void wr_i7(INT32 val) { adsp2100.i[7] = val & 0x3fff; adsp2100.base[7] = val & adsp2100.lmask[7]; }
+static void wr_m0(INT32 val) { adsp2100.m[0] = (INT32)(val << 18) >> 18; }
+static void wr_m1(INT32 val) { adsp2100.m[1] = (INT32)(val << 18) >> 18; }
+static void wr_m2(INT32 val) { adsp2100.m[2] = (INT32)(val << 18) >> 18; }
+static void wr_m3(INT32 val) { adsp2100.m[3] = (INT32)(val << 18) >> 18; }
+static void wr_m4(INT32 val) { adsp2100.m[4] = (INT32)(val << 18) >> 18; }
+static void wr_m5(INT32 val) { adsp2100.m[5] = (INT32)(val << 18) >> 18; }
+static void wr_m6(INT32 val) { adsp2100.m[6] = (INT32)(val << 18) >> 18; }
+static void wr_m7(INT32 val) { adsp2100.m[7] = (INT32)(val << 18) >> 18; }
+static void wr_l0(INT32 val) { adsp2100.l[0] = val & 0x3fff; adsp2100.lmask[0] = mask_table[val & 0x3fff]; adsp2100.base[0] = adsp2100.i[0] & adsp2100.lmask[0]; }
+static void wr_l1(INT32 val) { adsp2100.l[1] = val & 0x3fff; adsp2100.lmask[1] = mask_table[val & 0x3fff]; adsp2100.base[1] = adsp2100.i[1] & adsp2100.lmask[1]; }
+static void wr_l2(INT32 val) { adsp2100.l[2] = val & 0x3fff; adsp2100.lmask[2] = mask_table[val & 0x3fff]; adsp2100.base[2] = adsp2100.i[2] & adsp2100.lmask[2]; }
+static void wr_l3(INT32 val) { adsp2100.l[3] = val & 0x3fff; adsp2100.lmask[3] = mask_table[val & 0x3fff]; adsp2100.base[3] = adsp2100.i[3] & adsp2100.lmask[3]; }
+static void wr_l4(INT32 val) { adsp2100.l[4] = val & 0x3fff; adsp2100.lmask[4] = mask_table[val & 0x3fff]; adsp2100.base[4] = adsp2100.i[4] & adsp2100.lmask[4]; }
+static void wr_l5(INT32 val) { adsp2100.l[5] = val & 0x3fff; adsp2100.lmask[5] = mask_table[val & 0x3fff]; adsp2100.base[5] = adsp2100.i[5] & adsp2100.lmask[5]; }
+static void wr_l6(INT32 val) { adsp2100.l[6] = val & 0x3fff; adsp2100.lmask[6] = mask_table[val & 0x3fff]; adsp2100.base[6] = adsp2100.i[6] & adsp2100.lmask[6]; }
+static void wr_l7(INT32 val) { adsp2100.l[7] = val & 0x3fff; adsp2100.lmask[7] = mask_table[val & 0x3fff]; adsp2100.base[7] = adsp2100.i[7] & adsp2100.lmask[7]; }
+static void wr_astat(INT32 val) { adsp2100.astat = val & 0x00ff; }
+static void wr_mstat(INT32 val) { set_mstat(val & mstat_mask); }
+static void wr_sstat(INT32 val) { adsp2100.sstat = val & 0x00ff; }
+static void wr_imask(INT32 val) { adsp2100.imask = val & imask_mask; check_irqs(); }
+static void wr_icntl(INT32 val) { adsp2100.icntl = val & 0x001f; check_irqs(); }
+static void wr_cntr(INT32 val) { cntr_stack_push(); adsp2100.cntr = val & 0x3fff; }
+static void wr_sb(INT32 val) { adsp2100.core.sb.s = (INT32)(val << 27) >> 27; }
+static void wr_px(INT32 val) { adsp2100.px = val; }
+static void wr_ifc(INT32 val)
+{
+ adsp2100.ifc = val;
+#if (HAS_ADSP2181)
+ if (chip_type >= CHIP_TYPE_ADSP2181)
+ {
+ /* clear timer */
+ if (val & 0x0002) adsp2100.irq_latch[ADSP2181_IRQ0] = 0;
+ if (val & 0x0004) adsp2100.irq_latch[ADSP2181_IRQ1] = 0;
+ /* clear BDMA */
+ if (val & 0x0010) adsp2100.irq_latch[ADSP2181_IRQE] = 0;
+ if (val & 0x0020) adsp2100.irq_latch[ADSP2181_SPORT0_RX] = 0;
+ if (val & 0x0040) adsp2100.irq_latch[ADSP2181_SPORT0_TX] = 0;
+ if (val & 0x0080) adsp2100.irq_latch[ADSP2181_IRQ2] = 0;
+ /* force timer */
+ if (val & 0x0200) adsp2100.irq_latch[ADSP2181_IRQ0] = 1;
+ if (val & 0x0400) adsp2100.irq_latch[ADSP2181_IRQ1] = 1;
+ /* force BDMA */
+ if (val & 0x1000) adsp2100.irq_latch[ADSP2181_IRQE] = 1;
+ if (val & 0x2000) adsp2100.irq_latch[ADSP2181_SPORT0_RX] = 1;
+ if (val & 0x4000) adsp2100.irq_latch[ADSP2181_SPORT0_TX] = 1;
+ if (val & 0x8000) adsp2100.irq_latch[ADSP2181_IRQ2] = 1;
+ }
+ else
+#endif
+ {
+ /* clear timer */
+ if (val & 0x002) adsp2100.irq_latch[ADSP2101_IRQ0] = 0;
+ if (val & 0x004) adsp2100.irq_latch[ADSP2101_IRQ1] = 0;
+ if (val & 0x008) adsp2100.irq_latch[ADSP2101_SPORT0_RX] = 0;
+ if (val & 0x010) adsp2100.irq_latch[ADSP2101_SPORT0_TX] = 0;
+ if (val & 0x020) adsp2100.irq_latch[ADSP2101_IRQ2] = 0;
+ /* set timer */
+ if (val & 0x080) adsp2100.irq_latch[ADSP2101_IRQ0] = 1;
+ if (val & 0x100) adsp2100.irq_latch[ADSP2101_IRQ1] = 1;
+ if (val & 0x200) adsp2100.irq_latch[ADSP2101_SPORT0_RX] = 1;
+ if (val & 0x400) adsp2100.irq_latch[ADSP2101_SPORT0_TX] = 1;
+ if (val & 0x800) adsp2100.irq_latch[ADSP2101_IRQ2] = 1;
+ }
+ check_irqs();
+}
+static void wr_tx0(INT32 val) { if (adsp2100.sport_tx_callback) (*adsp2100.sport_tx_callback)(0, val); }
+static void wr_tx1(INT32 val) { if (adsp2100.sport_tx_callback) (*adsp2100.sport_tx_callback)(1, val); }
+static void wr_owrctr(INT32 val) { adsp2100.cntr = val & 0x3fff; }
+static void wr_topstack(INT32 val) { pc_stack_push_val(val & 0x3fff); }
+
+#define WRITE_REG(grp,reg,val) ((*wr_reg[grp][reg])(val))
+
+static void (*wr_reg[4][16])(INT32) =
+{
+ {
+ wr_ax0, wr_ax1, wr_mx0, wr_mx1, wr_ay0, wr_ay1, wr_my0, wr_my1,
+ wr_si, wr_se, wr_ar, wr_mr0, wr_mr1, wr_mr2, wr_sr0, wr_sr1
+ },
+ {
+ wr_i0, wr_i1, wr_i2, wr_i3, wr_m0, wr_m1, wr_m2, wr_m3,
+ wr_l0, wr_l1, wr_l2, wr_l3, wr_inval, wr_inval, wr_inval, wr_inval
+ },
+ {
+ wr_i4, wr_i5, wr_i6, wr_i7, wr_m4, wr_m5, wr_m6, wr_m7,
+ wr_l4, wr_l5, wr_l6, wr_l7, wr_inval, wr_inval, wr_inval, wr_inval
+ },
+ {
+ wr_astat, wr_mstat, wr_inval, wr_imask, wr_icntl, wr_cntr, wr_sb, wr_px,
+ wr_inval, wr_tx0, wr_inval, wr_tx1, wr_ifc, wr_owrctr, wr_inval, wr_topstack
+ }
+};
+
+
+
+/*===========================================================================
+ register reading
+===========================================================================*/
+
+static INT32 rd_inval(void) { logerror( "ADSP %04x: Writing to an invalid register!\n", adsp2100.ppc ); return 0; }
+static INT32 rd_ax0(void) { return adsp2100.core.ax0.s; }
+static INT32 rd_ax1(void) { return adsp2100.core.ax1.s; }
+static INT32 rd_mx0(void) { return adsp2100.core.mx0.s; }
+static INT32 rd_mx1(void) { return adsp2100.core.mx1.s; }
+static INT32 rd_ay0(void) { return adsp2100.core.ay0.s; }
+static INT32 rd_ay1(void) { return adsp2100.core.ay1.s; }
+static INT32 rd_my0(void) { return adsp2100.core.my0.s; }
+static INT32 rd_my1(void) { return adsp2100.core.my1.s; }
+static INT32 rd_si(void) { return adsp2100.core.si.s; }
+static INT32 rd_se(void) { return adsp2100.core.se.s; }
+static INT32 rd_ar(void) { return adsp2100.core.ar.s; }
+static INT32 rd_mr0(void) { return adsp2100.core.mr.mrx.mr0.s; }
+static INT32 rd_mr1(void) { return adsp2100.core.mr.mrx.mr1.s; }
+static INT32 rd_mr2(void) { return adsp2100.core.mr.mrx.mr2.s; }
+static INT32 rd_sr0(void) { return adsp2100.core.sr.srx.sr0.s; }
+static INT32 rd_sr1(void) { return adsp2100.core.sr.srx.sr1.s; }
+static INT32 rd_i0(void) { return adsp2100.i[0]; }
+static INT32 rd_i1(void) { return adsp2100.i[1]; }
+static INT32 rd_i2(void) { return adsp2100.i[2]; }
+static INT32 rd_i3(void) { return adsp2100.i[3]; }
+static INT32 rd_i4(void) { return adsp2100.i[4]; }
+static INT32 rd_i5(void) { return adsp2100.i[5]; }
+static INT32 rd_i6(void) { return adsp2100.i[6]; }
+static INT32 rd_i7(void) { return adsp2100.i[7]; }
+static INT32 rd_m0(void) { return adsp2100.m[0]; }
+static INT32 rd_m1(void) { return adsp2100.m[1]; }
+static INT32 rd_m2(void) { return adsp2100.m[2]; }
+static INT32 rd_m3(void) { return adsp2100.m[3]; }
+static INT32 rd_m4(void) { return adsp2100.m[4]; }
+static INT32 rd_m5(void) { return adsp2100.m[5]; }
+static INT32 rd_m6(void) { return adsp2100.m[6]; }
+static INT32 rd_m7(void) { return adsp2100.m[7]; }
+static INT32 rd_l0(void) { return adsp2100.l[0]; }
+static INT32 rd_l1(void) { return adsp2100.l[1]; }
+static INT32 rd_l2(void) { return adsp2100.l[2]; }
+static INT32 rd_l3(void) { return adsp2100.l[3]; }
+static INT32 rd_l4(void) { return adsp2100.l[4]; }
+static INT32 rd_l5(void) { return adsp2100.l[5]; }
+static INT32 rd_l6(void) { return adsp2100.l[6]; }
+static INT32 rd_l7(void) { return adsp2100.l[7]; }
+static INT32 rd_astat(void) { return adsp2100.astat; }
+static INT32 rd_mstat(void) { return adsp2100.mstat; }
+static INT32 rd_sstat(void) { return adsp2100.sstat; }
+static INT32 rd_imask(void) { return adsp2100.imask; }
+static INT32 rd_icntl(void) { return adsp2100.icntl; }
+static INT32 rd_cntr(void) { return adsp2100.cntr; }
+static INT32 rd_sb(void) { return adsp2100.core.sb.s; }
+static INT32 rd_px(void) { return adsp2100.px; }
+static INT32 rd_rx0(void) { if (adsp2100.sport_rx_callback) return (*adsp2100.sport_rx_callback)(0); else return 0; }
+static INT32 rd_rx1(void) { if (adsp2100.sport_rx_callback) return (*adsp2100.sport_rx_callback)(1); else return 0; }
+static INT32 rd_stacktop(void) { return pc_stack_pop_val(); }
+
+#define READ_REG(grp,reg) ((*rd_reg[grp][reg])())
+
+static INT32 (*rd_reg[4][16])(void) =
+{
+ {
+ rd_ax0, rd_ax1, rd_mx0, rd_mx1, rd_ay0, rd_ay1, rd_my0, rd_my1,
+ rd_si, rd_se, rd_ar, rd_mr0, rd_mr1, rd_mr2, rd_sr0, rd_sr1
+ },
+ {
+ rd_i0, rd_i1, rd_i2, rd_i3, rd_m0, rd_m1, rd_m2, rd_m3,
+ rd_l0, rd_l1, rd_l2, rd_l3, rd_inval, rd_inval, rd_inval, rd_inval
+ },
+ {
+ rd_i4, rd_i5, rd_i6, rd_i7, rd_m4, rd_m5, rd_m6, rd_m7,
+ rd_l4, rd_l5, rd_l6, rd_l7, rd_inval, rd_inval, rd_inval, rd_inval
+ },
+ {
+ rd_astat, rd_mstat, rd_sstat, rd_imask, rd_icntl, rd_cntr, rd_sb, rd_px,
+ rd_rx0, rd_inval, rd_rx1, rd_inval, rd_inval, rd_inval, rd_inval, rd_stacktop
+ }
+};
+
+
+
+/*===========================================================================
+ Modulus addressing logic
+===========================================================================*/
+
+INLINE void modify_address(UINT32 ireg, UINT32 mreg)
+{
+ UINT32 base = adsp2100.base[ireg];
+ UINT32 i = adsp2100.i[ireg];
+ UINT32 l = adsp2100.l[ireg];
+
+ i += adsp2100.m[mreg];
+ if (i < base) i += l;
+ else if (i >= base + l) i -= l;
+ adsp2100.i[ireg] = i;
+}
+
+
+
+/*===========================================================================
+ Data memory accessors
+===========================================================================*/
+
+INLINE void data_write_dag1(UINT32 op, INT32 val)
+{
+ UINT32 ireg = (op >> 2) & 3;
+ UINT32 mreg = op & 3;
+ UINT32 base = adsp2100.base[ireg];
+ UINT32 i = adsp2100.i[ireg];
+ UINT32 l = adsp2100.l[ireg];
+
+ if ( adsp2100.mstat & MSTAT_REVERSE )
+ {
+ UINT32 ir = reverse_table[ i & 0x3fff ];
+ WWORD_DATA(ir, val);
+ }
+ else
+ WWORD_DATA(i, val);
+
+ i += adsp2100.m[mreg];
+ if (i < base) i += l;
+ else if (i >= base + l) i -= l;
+ adsp2100.i[ireg] = i;
+}
+
+
+INLINE UINT32 data_read_dag1(UINT32 op)
+{
+ UINT32 ireg = (op >> 2) & 3;
+ UINT32 mreg = op & 3;
+ UINT32 base = adsp2100.base[ireg];
+ UINT32 i = adsp2100.i[ireg];
+ UINT32 l = adsp2100.l[ireg];
+ UINT32 res;
+
+ if (adsp2100.mstat & MSTAT_REVERSE)
+ {
+ UINT32 ir = reverse_table[i & 0x3fff];
+ res = RWORD_DATA(ir);
+ }
+ else
+ res = RWORD_DATA(i);
+
+ i += adsp2100.m[mreg];
+ if (i < base) i += l;
+ else if (i >= base + l) i -= l;
+ adsp2100.i[ireg] = i;
+
+ return res;
+}
+
+INLINE void data_write_dag2(UINT32 op, INT32 val)
+{
+ UINT32 ireg = 4 + ((op >> 2) & 3);
+ UINT32 mreg = 4 + (op & 3);
+ UINT32 base = adsp2100.base[ireg];
+ UINT32 i = adsp2100.i[ireg];
+ UINT32 l = adsp2100.l[ireg];
+
+ WWORD_DATA(i, val);
+
+ i += adsp2100.m[mreg];
+ if (i < base) i += l;
+ else if (i >= base + l) i -= l;
+ adsp2100.i[ireg] = i;
+}
+
+
+INLINE UINT32 data_read_dag2(UINT32 op)
+{
+ UINT32 ireg = 4 + ((op >> 2) & 3);
+ UINT32 mreg = 4 + (op & 3);
+ UINT32 base = adsp2100.base[ireg];
+ UINT32 i = adsp2100.i[ireg];
+ UINT32 l = adsp2100.l[ireg];
+
+ UINT32 res = RWORD_DATA(i);
+
+ i += adsp2100.m[mreg];
+ if (i < base) i += l;
+ else if (i >= base + l) i -= l;
+ adsp2100.i[ireg] = i;
+
+ return res;
+}
+
+/*===========================================================================
+ Program memory accessors
+===========================================================================*/
+
+INLINE void pgm_write_dag2(UINT32 op, INT32 val)
+{
+ UINT32 ireg = 4 + ((op >> 2) & 3);
+ UINT32 mreg = 4 + (op & 3);
+ UINT32 base = adsp2100.base[ireg];
+ UINT32 i = adsp2100.i[ireg];
+ UINT32 l = adsp2100.l[ireg];
+
+ WWORD_PGM(i, (val << 8) | adsp2100.px);
+
+ i += adsp2100.m[mreg];
+ if (i < base) i += l;
+ else if (i >= base + l) i -= l;
+ adsp2100.i[ireg] = i;
+}
+
+
+INLINE UINT32 pgm_read_dag2(UINT32 op)
+{
+ UINT32 ireg = 4 + ((op >> 2) & 3);
+ UINT32 mreg = 4 + (op & 3);
+ UINT32 base = adsp2100.base[ireg];
+ UINT32 i = adsp2100.i[ireg];
+ UINT32 l = adsp2100.l[ireg];
+ UINT32 res;
+
+ res = RWORD_PGM(i);
+ adsp2100.px = res;
+ res >>= 8;
+
+ i += adsp2100.m[mreg];
+ if (i < base) i += l;
+ else if (i >= base + l) i -= l;
+ adsp2100.i[ireg] = i;
+
+ return res;
+}
+
+
+
+/*===========================================================================
+ ALU register reading
+===========================================================================*/
+
+#define ALU_GETXREG_UNSIGNED(x) (*(UINT16 *)alu_xregs[x])
+#define ALU_GETXREG_SIGNED(x) (*( INT16 *)alu_xregs[x])
+#define ALU_GETYREG_UNSIGNED(y) (*(UINT16 *)alu_yregs[y])
+#define ALU_GETYREG_SIGNED(y) (*( INT16 *)alu_yregs[y])
+
+static const void *alu_xregs[8] =
+{
+ &adsp2100.core.ax0,
+ &adsp2100.core.ax1,
+ &adsp2100.core.ar,
+ &adsp2100.core.mr.mrx.mr0,
+ &adsp2100.core.mr.mrx.mr1,
+ &adsp2100.core.mr.mrx.mr2,
+ &adsp2100.core.sr.srx.sr0,
+ &adsp2100.core.sr.srx.sr1
+};
+
+static const void *alu_yregs[4] =
+{
+ &adsp2100.core.ay0,
+ &adsp2100.core.ay1,
+ &adsp2100.core.af,
+ &adsp2100.core.zero
+};
+
+
+
+/*===========================================================================
+ MAC register reading
+===========================================================================*/
+
+#define MAC_GETXREG_UNSIGNED(x) (*(UINT16 *)mac_xregs[x])
+#define MAC_GETXREG_SIGNED(x) (*( INT16 *)mac_xregs[x])
+#define MAC_GETYREG_UNSIGNED(y) (*(UINT16 *)mac_yregs[y])
+#define MAC_GETYREG_SIGNED(y) (*( INT16 *)mac_yregs[y])
+
+static const void *mac_xregs[8] =
+{
+ &adsp2100.core.mx0,
+ &adsp2100.core.mx1,
+ &adsp2100.core.ar,
+ &adsp2100.core.mr.mrx.mr0,
+ &adsp2100.core.mr.mrx.mr1,
+ &adsp2100.core.mr.mrx.mr2,
+ &adsp2100.core.sr.srx.sr0,
+ &adsp2100.core.sr.srx.sr1
+};
+
+static const void *mac_yregs[4] =
+{
+ &adsp2100.core.my0,
+ &adsp2100.core.my1,
+ &adsp2100.core.mf,
+ &adsp2100.core.zero
+};
+
+
+
+/*===========================================================================
+ SHIFT register reading
+===========================================================================*/
+
+#define SHIFT_GETXREG_UNSIGNED(x) (*(UINT16 *)shift_xregs[x])
+#define SHIFT_GETXREG_SIGNED(x) (*( INT16 *)shift_xregs[x])
+
+static const void *shift_xregs[8] =
+{
+ &adsp2100.core.si,
+ &adsp2100.core.si,
+ &adsp2100.core.ar,
+ &adsp2100.core.mr.mrx.mr0,
+ &adsp2100.core.mr.mrx.mr1,
+ &adsp2100.core.mr.mrx.mr2,
+ &adsp2100.core.sr.srx.sr0,
+ &adsp2100.core.sr.srx.sr1
+};
+
+
+
+/*===========================================================================
+ ALU operations (result in AR)
+===========================================================================*/
+
+static void alu_op_ar(int op)
+{
+ INT32 xop = (op >> 8) & 7;
+ INT32 yop = (op >> 11) & 3;
+ INT32 res;
+
+ switch (op & (15<<13)) /*JB*/
+ {
+ case 0x00<<13:
+ /* Y Clear when y = 0 */
+ res = ALU_GETYREG_UNSIGNED(yop);
+ CALC_NZ(res);
+ break;
+ case 0x01<<13:
+ /* Y + 1 PASS 1 when y = 0 */
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop + 1;
+ CALC_NZ(res);
+ if (yop == 0x7fff) SET_V;
+ else if (yop == 0xffff) SET_C;
+ break;
+ case 0x02<<13:
+ /* X + Y + C */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ yop += GET_C >> 3;
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x03<<13:
+ /* X + Y X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x04<<13:
+ /* NOT Y */
+ res = ALU_GETYREG_UNSIGNED(yop) ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x05<<13:
+ /* -Y */
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = -yop;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ if (yop == 0x0000) SET_C;
+ break;
+ case 0x06<<13:
+ /* X - Y + C - 1 X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop - yop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x07<<13:
+ /* X - Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop - yop;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x08<<13:
+ /* Y - 1 PASS -1 when y = 0 */
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop - 1;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ else if (yop == 0x0000) SET_C;
+ break;
+ case 0x09<<13:
+ /* Y - X -X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop - xop;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0a<<13:
+ /* Y - X + C - 1 -X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop - xop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0b<<13:
+ /* NOT X */
+ res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x0c<<13:
+ /* X AND Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop & yop;
+ CALC_NZ(res);
+ break;
+ case 0x0d<<13:
+ /* X OR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop | yop;
+ CALC_NZ(res);
+ break;
+ case 0x0e<<13:
+ /* X XOR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop ^ yop;
+ CALC_NZ(res);
+ break;
+ case 0x0f<<13:
+ /* ABS X */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = (xop & 0x8000) ? -xop : xop;
+ if (xop == 0) SET_Z;
+ if (xop == 0x8000) SET_N, SET_V;
+ CLR_S;
+ if (xop & 0x8000) SET_S;
+ break;
+ default:
+ res = 0; /* just to keep the compiler happy */
+ break;
+ }
+
+ /* saturate */
+ if ((adsp2100.mstat & MSTAT_SATURATE) && GET_V) res = GET_C ? -32768 : 32767;
+
+ /* set the final value */
+ adsp2100.core.ar.u = res;
+}
+
+
+
+/*===========================================================================
+ ALU operations (result in AR, constant yop)
+===========================================================================*/
+
+static void alu_op_ar_const(int op)
+{
+ INT32 xop = (op >> 8) & 7;
+ INT32 yop = constants[((op >> 5) & 0x07) | ((op >> 8) & 0x18)];
+ INT32 res;
+
+ switch (op & (15<<13)) /*JB*/
+ {
+ case 0x00<<13:
+ /* Y Clear when y = 0 */
+ res = yop;
+ CALC_NZ(res);
+ break;
+ case 0x01<<13:
+ /* Y + 1 PASS 1 when y = 0 */
+ res = yop + 1;
+ CALC_NZ(res);
+ if (yop == 0x7fff) SET_V;
+ else if (yop == 0xffff) SET_C;
+ break;
+ case 0x02<<13:
+ /* X + Y + C */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop += GET_C >> 3;
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x03<<13:
+ /* X + Y X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x04<<13:
+ /* NOT Y */
+ res = yop ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x05<<13:
+ /* -Y */
+ res = -yop;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ if (yop == 0x0000) SET_C;
+ break;
+ case 0x06<<13:
+ /* X - Y + C - 1 X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop - yop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x07<<13:
+ /* X - Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop - yop;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x08<<13:
+ /* Y - 1 PASS -1 when y = 0 */
+ res = yop - 1;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ else if (yop == 0x0000) SET_C;
+ break;
+ case 0x09<<13:
+ /* Y - X -X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = yop - xop;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0a<<13:
+ /* Y - X + C - 1 -X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = yop - xop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0b<<13:
+ /* NOT X */
+ res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x0c<<13:
+ /* X AND Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop & yop;
+ CALC_NZ(res);
+ break;
+ case 0x0d<<13:
+ /* X OR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop | yop;
+ CALC_NZ(res);
+ break;
+ case 0x0e<<13:
+ /* X XOR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop ^ yop;
+ CALC_NZ(res);
+ break;
+ case 0x0f<<13:
+ /* ABS X */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = (xop & 0x8000) ? -xop : xop;
+ if (xop == 0) SET_Z;
+ if (xop == 0x8000) SET_N, SET_V;
+ CLR_S;
+ if (xop & 0x8000) SET_S;
+ break;
+ default:
+ res = 0; /* just to keep the compiler happy */
+ break;
+ }
+
+ /* saturate */
+ if ((adsp2100.mstat & MSTAT_SATURATE) && GET_V) res = GET_C ? -32768 : 32767;
+
+ /* set the final value */
+ adsp2100.core.ar.u = res;
+}
+
+
+
+/*===========================================================================
+ ALU operations (result in AF)
+===========================================================================*/
+
+static void alu_op_af(int op)
+{
+ INT32 xop = (op >> 8) & 7;
+ INT32 yop = (op >> 11) & 3;
+ INT32 res;
+
+ switch (op & (15<<13)) /*JB*/
+ {
+ case 0x00<<13:
+ /* Y Clear when y = 0 */
+ res = ALU_GETYREG_UNSIGNED(yop);
+ CALC_NZ(res);
+ break;
+ case 0x01<<13:
+ /* Y + 1 PASS 1 when y = 0 */
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop + 1;
+ CALC_NZ(res);
+ if (yop == 0x7fff) SET_V;
+ else if (yop == 0xffff) SET_C;
+ break;
+ case 0x02<<13:
+ /* X + Y + C */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ yop += GET_C >> 3;
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x03<<13:
+ /* X + Y X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x04<<13:
+ /* NOT Y */
+ res = ALU_GETYREG_UNSIGNED(yop) ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x05<<13:
+ /* -Y */
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = -yop;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ if (yop == 0x0000) SET_C;
+ break;
+ case 0x06<<13:
+ /* X - Y + C - 1 X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop - yop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x07<<13:
+ /* X - Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop - yop;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x08<<13:
+ /* Y - 1 PASS -1 when y = 0 */
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop - 1;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ else if (yop == 0x0000) SET_C;
+ break;
+ case 0x09<<13:
+ /* Y - X -X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop - xop;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0a<<13:
+ /* Y - X + C - 1 -X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop - xop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0b<<13:
+ /* NOT X */
+ res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x0c<<13:
+ /* X AND Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop & yop;
+ CALC_NZ(res);
+ break;
+ case 0x0d<<13:
+ /* X OR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop | yop;
+ CALC_NZ(res);
+ break;
+ case 0x0e<<13:
+ /* X XOR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop ^ yop;
+ CALC_NZ(res);
+ break;
+ case 0x0f<<13:
+ /* ABS X */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = (xop & 0x8000) ? -xop : xop;
+ if (xop == 0) SET_Z;
+ if (xop == 0x8000) SET_N, SET_V;
+ CLR_S;
+ if (xop & 0x8000) SET_S;
+ break;
+ default:
+ res = 0; /* just to keep the compiler happy */
+ break;
+ }
+
+ /* set the final value */
+ adsp2100.core.af.u = res;
+}
+
+
+
+/*===========================================================================
+ ALU operations (result in AF, constant yop)
+===========================================================================*/
+
+static void alu_op_af_const(int op)
+{
+ INT32 xop = (op >> 8) & 7;
+ INT32 yop = constants[((op >> 5) & 0x07) | ((op >> 8) & 0x18)];
+ INT32 res;
+
+ switch (op & (15<<13)) /*JB*/
+ {
+ case 0x00<<13:
+ /* Y Clear when y = 0 */
+ res = yop;
+ CALC_NZ(res);
+ break;
+ case 0x01<<13:
+ /* Y + 1 PASS 1 when y = 0 */
+ res = yop + 1;
+ CALC_NZ(res);
+ if (yop == 0x7fff) SET_V;
+ else if (yop == 0xffff) SET_C;
+ break;
+ case 0x02<<13:
+ /* X + Y + C */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop += GET_C >> 3;
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x03<<13:
+ /* X + Y X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x04<<13:
+ /* NOT Y */
+ res = yop ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x05<<13:
+ /* -Y */
+ res = -yop;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ if (yop == 0x0000) SET_C;
+ break;
+ case 0x06<<13:
+ /* X - Y + C - 1 X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop - yop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x07<<13:
+ /* X - Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop - yop;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x08<<13:
+ /* Y - 1 PASS -1 when y = 0 */
+ res = yop - 1;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ else if (yop == 0x0000) SET_C;
+ break;
+ case 0x09<<13:
+ /* Y - X -X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = yop - xop;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0a<<13:
+ /* Y - X + C - 1 -X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = yop - xop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0b<<13:
+ /* NOT X */
+ res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x0c<<13:
+ /* X AND Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop & yop;
+ CALC_NZ(res);
+ break;
+ case 0x0d<<13:
+ /* X OR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop | yop;
+ CALC_NZ(res);
+ break;
+ case 0x0e<<13:
+ /* X XOR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = xop ^ yop;
+ CALC_NZ(res);
+ break;
+ case 0x0f<<13:
+ /* ABS X */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = (xop & 0x8000) ? -xop : xop;
+ if (xop == 0) SET_Z;
+ if (xop == 0x8000) SET_N, SET_V;
+ CLR_S;
+ if (xop & 0x8000) SET_S;
+ break;
+ default:
+ res = 0; /* just to keep the compiler happy */
+ break;
+ }
+
+ /* set the final value */
+ adsp2100.core.af.u = res;
+}
+
+
+
+/*===========================================================================
+ ALU operations (no result)
+===========================================================================*/
+
+static void alu_op_none(int op)
+{
+ INT32 xop = (op >> 8) & 7;
+ INT32 yop = (op >> 11) & 3;
+ INT32 res;
+
+ switch (op & (15<<13)) /*JB*/
+ {
+ case 0x00<<13:
+ /* Y Clear when y = 0 */
+ res = ALU_GETYREG_UNSIGNED(yop);
+ CALC_NZ(res);
+ break;
+ case 0x01<<13:
+ /* Y + 1 PASS 1 when y = 0 */
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop + 1;
+ CALC_NZ(res);
+ if (yop == 0x7fff) SET_V;
+ else if (yop == 0xffff) SET_C;
+ break;
+ case 0x02<<13:
+ /* X + Y + C */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ yop += GET_C >> 3;
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x03<<13:
+ /* X + Y X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop + yop;
+ CALC_NZVC(xop, yop, res);
+ break;
+ case 0x04<<13:
+ /* NOT Y */
+ res = ALU_GETYREG_UNSIGNED(yop) ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x05<<13:
+ /* -Y */
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = -yop;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ if (yop == 0x0000) SET_C;
+ break;
+ case 0x06<<13:
+ /* X - Y + C - 1 X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop - yop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x07<<13:
+ /* X - Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop - yop;
+ CALC_NZVC_SUB(xop, yop, res);
+ break;
+ case 0x08<<13:
+ /* Y - 1 PASS -1 when y = 0 */
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop - 1;
+ CALC_NZ(res);
+ if (yop == 0x8000) SET_V;
+ else if (yop == 0x0000) SET_C;
+ break;
+ case 0x09<<13:
+ /* Y - X -X when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop - xop;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0a<<13:
+ /* Y - X + C - 1 -X + C - 1 when y = 0 */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = yop - xop + (GET_C >> 3) - 1;
+ CALC_NZVC_SUB(yop, xop, res);
+ break;
+ case 0x0b<<13:
+ /* NOT X */
+ res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff;
+ CALC_NZ(res);
+ break;
+ case 0x0c<<13:
+ /* X AND Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop & yop;
+ CALC_NZ(res);
+ break;
+ case 0x0d<<13:
+ /* X OR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop | yop;
+ CALC_NZ(res);
+ break;
+ case 0x0e<<13:
+ /* X XOR Y */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+ res = xop ^ yop;
+ CALC_NZ(res);
+ break;
+ case 0x0f<<13:
+ /* ABS X */
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ res = (xop & 0x8000) ? -xop : xop;
+ if (xop == 0) SET_Z;
+ if (xop == 0x8000) SET_N, SET_V;
+ CLR_S;
+ if (xop & 0x8000) SET_S;
+ break;
+ }
+}
+
+
+
+/*===========================================================================
+ MAC operations (result in MR)
+===========================================================================*/
+
+static void mac_op_mr(int op)
+{
+ INT8 shift = ((adsp2100.mstat & MSTAT_INTEGER) >> 4) ^ 1;
+ INT32 xop = (op >> 8) & 7;
+ INT32 yop = (op >> 11) & 3;
+ INT32 temp;
+ INT64 res;
+
+ switch (op & (15<<13)) /*JB*/
+ {
+ case 0x00<<13:
+ /* no-op */
+ return;
+ case 0x01<<13:
+ /* X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x02<<13:
+ /* MR + X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x03<<13:
+ /* MR - X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x04<<13:
+ /* X * Y (SS) Clear when y = 0 */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x05<<13:
+ /* X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x06<<13:
+ /* X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x07<<13:
+ /* X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x08<<13:
+ /* MR + X * Y (SS) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x09<<13:
+ /* MR + X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0a<<13:
+ /* MR + X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0b<<13:
+ /* MR + X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0c<<13:
+ /* MR - X * Y (SS) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0d<<13:
+ /* MR - X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0e<<13:
+ /* MR - X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0f<<13:
+ /* MR - X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ default:
+ res = 0; /* just to keep the compiler happy */
+ break;
+ }
+
+ /* set the final value */
+ temp = (res >> 31) & 0x1ff;
+ CLR_MV;
+ if (temp != 0x000 && temp != 0x1ff) SET_MV;
+ adsp2100.core.mr.mr = res;
+}
+
+
+
+/*===========================================================================
+ MAC operations (result in MR, yop == xop)
+===========================================================================*/
+
+static void mac_op_mr_xop(int op)
+{
+ INT8 shift = ((adsp2100.mstat & MSTAT_INTEGER) >> 4) ^ 1;
+ INT32 xop = (op >> 8) & 7;
+ INT32 temp;
+ INT64 res;
+
+ switch (op & (15<<13)) /*JB*/
+ {
+ case 0x00<<13:
+ /* no-op */
+ return;
+ case 0x01<<13:
+ /* X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x02<<13:
+ /* MR + X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x03<<13:
+ /* MR - X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x04<<13:
+ /* X * Y (SS) Clear when y = 0 */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x05<<13:
+ /* X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x06<<13:
+ /* X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x07<<13:
+ /* X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x08<<13:
+ /* MR + X * Y (SS) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x09<<13:
+ /* MR + X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0a<<13:
+ /* MR + X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0b<<13:
+ /* MR + X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0c<<13:
+ /* MR - X * Y (SS) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0d<<13:
+ /* MR - X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0e<<13:
+ /* MR - X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0f<<13:
+ /* MR - X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ default:
+ res = 0; /* just to keep the compiler happy */
+ break;
+ }
+
+ /* set the final value */
+ temp = (res >> 31) & 0x1ff;
+ CLR_MV;
+ if (temp != 0x000 && temp != 0x1ff) SET_MV;
+ adsp2100.core.mr.mr = res;
+}
+
+
+
+/*===========================================================================
+ MAC operations (result in MF)
+===========================================================================*/
+
+static void mac_op_mf(int op)
+{
+ INT8 shift = ((adsp2100.mstat & MSTAT_INTEGER) >> 4) ^ 1;
+ INT32 xop = (op >> 8) & 7;
+ INT32 yop = (op >> 11) & 3;
+ INT32 temp;
+ INT64 res;
+
+ switch (op & (15<<13)) /*JB*/
+ {
+ case 0x00<<13:
+ /* no-op */
+ return;
+ case 0x01<<13:
+ /* X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x02<<13:
+ /* MR + X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x03<<13:
+ /* MR - X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x04<<13:
+ /* X * Y (SS) Clear when y = 0 */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x05<<13:
+ /* X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x06<<13:
+ /* X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x07<<13:
+ /* X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x08<<13:
+ /* MR + X * Y (SS) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x09<<13:
+ /* MR + X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0a<<13:
+ /* MR + X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0b<<13:
+ /* MR + X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0c<<13:
+ /* MR - X * Y (SS) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0d<<13:
+ /* MR - X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0e<<13:
+ /* MR - X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_SIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0f<<13:
+ /* MR - X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ yop = MAC_GETYREG_UNSIGNED(yop);
+ temp = (xop * yop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ default:
+ res = 0; /* just to keep the compiler happy */
+ break;
+ }
+
+ /* set the final value */
+ adsp2100.core.mf.u = (UINT32)res >> 16;
+}
+
+
+
+/*===========================================================================
+ MAC operations (result in MF, yop == xop)
+===========================================================================*/
+
+static void mac_op_mf_xop(int op)
+{
+ INT8 shift = ((adsp2100.mstat & MSTAT_INTEGER) >> 4) ^ 1;
+ INT32 xop = (op >> 8) & 7;
+ INT32 temp;
+ INT64 res;
+
+ switch (op & (15<<13)) /*JB*/
+ {
+ case 0x00<<13:
+ /* no-op */
+ return;
+ case 0x01<<13:
+ /* X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x02<<13:
+ /* MR + X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x03<<13:
+ /* MR - X * Y (RND) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+#if 0
+ if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
+ else res += (res & 0x8000) << 1;
+#else
+ temp &= 0xffff;
+ res += 0x8000;
+ if ( temp == 0x8000 )
+ res &= ~((UINT64)0x10000);
+#endif
+ break;
+ case 0x04<<13:
+ /* X * Y (SS) Clear when y = 0 */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x05<<13:
+ /* X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x06<<13:
+ /* X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x07<<13:
+ /* X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = (INT64)temp;
+ break;
+ case 0x08<<13:
+ /* MR + X * Y (SS) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x09<<13:
+ /* MR + X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0a<<13:
+ /* MR + X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0b<<13:
+ /* MR + X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr + (INT64)temp;
+ break;
+ case 0x0c<<13:
+ /* MR - X * Y (SS) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0d<<13:
+ /* MR - X * Y (SU) */
+ xop = MAC_GETXREG_SIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0e<<13:
+ /* MR - X * Y (US) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ case 0x0f<<13:
+ /* MR - X * Y (UU) */
+ xop = MAC_GETXREG_UNSIGNED(xop);
+ temp = (xop * xop) << shift;
+ res = adsp2100.core.mr.mr - (INT64)temp;
+ break;
+ default:
+ res = 0; /* just to keep the compiler happy */
+ break;
+ }
+
+ /* set the final value */
+ adsp2100.core.mf.u = (UINT32)res >> 16;
+}
+
+
+
+/*===========================================================================
+ SHIFT operations (result in SR/SE/SB)
+===========================================================================*/
+
+static void shift_op(int op)
+{
+ INT8 sc = adsp2100.core.se.s;
+ INT32 xop = (op >> 8) & 7;
+ UINT32 res;
+
+ switch (op & (15<<11)) /*JB*/
+ {
+ case 0x00<<11:
+ /* LSHIFT (HI) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop) << 16;
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0;
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x01<<11:
+ /* LSHIFT (HI, OR) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop) << 16;
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0;
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x02<<11:
+ /* LSHIFT (LO) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : 0;
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x03<<11:
+ /* LSHIFT (LO, OR) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : 0;
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x04<<11:
+ /* ASHIFT (HI) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x05<<11:
+ /* ASHIFT (HI, OR) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x06<<11:
+ /* ASHIFT (LO) */
+ xop = SHIFT_GETXREG_SIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x07<<11:
+ /* ASHIFT (LO, OR) */
+ xop = SHIFT_GETXREG_SIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x08<<11:
+ /* NORM (HI) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ if (sc > 0)
+ {
+ xop = ((UINT32)xop >> 1) | ((adsp2100.astat & CFLAG) << 28);
+ res = xop >> (sc - 1);
+ }
+ else res = (sc > -32) ? (xop << -sc) : 0;
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x09<<11:
+ /* NORM (HI, OR) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ if (sc > 0)
+ {
+ xop = ((UINT32)xop >> 1) | ((adsp2100.astat & CFLAG) << 28);
+ res = xop >> (sc - 1);
+ }
+ else res = (sc > -32) ? (xop << -sc) : 0;
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x0a<<11:
+ /* NORM (LO) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0;
+ else res = (sc > -32) ? (xop << -sc) : 0;
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x0b<<11:
+ /* NORM (LO, OR) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0;
+ else res = (sc > -32) ? (xop << -sc) : 0;
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x0c<<11:
+ /* EXP (HI) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ res = 0;
+ if (xop < 0)
+ {
+ SET_SS;
+ while ((xop & 0x40000000) != 0) res++, xop <<= 1;
+ }
+ else
+ {
+ CLR_SS;
+ xop |= 0x8000;
+ while ((xop & 0x40000000) == 0) res++, xop <<= 1;
+ }
+ adsp2100.core.se.s = -res;
+ break;
+ case 0x0d<<11:
+ /* EXP (HIX) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ if (GET_V)
+ {
+ adsp2100.core.se.s = 1;
+ if (xop < 0) CLR_SS;
+ else SET_SS;
+ }
+ else
+ {
+ res = 0;
+ if (xop < 0)
+ {
+ SET_SS;
+ while ((xop & 0x40000000) != 0) res++, xop <<= 1;
+ }
+ else
+ {
+ CLR_SS;
+ xop |= 0x8000;
+ while ((xop & 0x40000000) == 0) res++, xop <<= 1;
+ }
+ adsp2100.core.se.s = -res;
+ }
+ break;
+ case 0x0e<<11:
+ /* EXP (LO) */
+ if (adsp2100.core.se.s == -15)
+ {
+ xop = SHIFT_GETXREG_SIGNED(xop);
+ res = 15;
+ if (GET_SS)
+ while ((xop & 0x8000) != 0) res++, xop <<= 1;
+ else
+ {
+ xop = (xop << 1) | 1;
+ while ((xop & 0x10000) == 0) res++, xop <<= 1;
+ }
+ adsp2100.core.se.s = -res;
+ }
+ break;
+ case 0x0f<<11:
+ /* EXPADJ */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ res = 0;
+ if (xop < 0)
+ while ((xop & 0x40000000) != 0) res++, xop <<= 1;
+ else
+ {
+ xop |= 0x8000;
+ while ((xop & 0x40000000) == 0) res++, xop <<= 1;
+ }
+ if (res < -adsp2100.core.sb.s)
+ adsp2100.core.sb.s = -res;
+ break;
+ }
+}
+
+
+
+/*===========================================================================
+ Immediate SHIFT operations (result in SR/SE/SB)
+===========================================================================*/
+
+static void shift_op_imm(int op)
+{
+ INT8 sc = (INT8)op;
+ INT32 xop = (op >> 8) & 7;
+ UINT32 res;
+
+ switch (op & (15<<11)) /*JB*/
+ {
+ case 0x00<<11:
+ /* LSHIFT (HI) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop) << 16;
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0;
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x01<<11:
+ /* LSHIFT (HI, OR) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop) << 16;
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0;
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x02<<11:
+ /* LSHIFT (LO) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : 0;
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x03<<11:
+ /* LSHIFT (LO, OR) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : 0;
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x04<<11:
+ /* ASHIFT (HI) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x05<<11:
+ /* ASHIFT (HI, OR) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x06<<11:
+ /* ASHIFT (LO) */
+ xop = SHIFT_GETXREG_SIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x07<<11:
+ /* ASHIFT (LO, OR) */
+ xop = SHIFT_GETXREG_SIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
+ else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x08<<11:
+ /* NORM (HI) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ if (sc > 0)
+ {
+ xop = ((UINT32)xop >> 1) | ((adsp2100.astat & CFLAG) << 28);
+ res = xop >> (sc - 1);
+ }
+ else res = (sc > -32) ? (xop << -sc) : 0;
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x09<<11:
+ /* NORM (HI, OR) */
+ xop = SHIFT_GETXREG_SIGNED(xop) << 16;
+ if (sc > 0)
+ {
+ xop = ((UINT32)xop >> 1) | ((adsp2100.astat & CFLAG) << 28);
+ res = xop >> (sc - 1);
+ }
+ else res = (sc > -32) ? (xop << -sc) : 0;
+ adsp2100.core.sr.sr |= res;
+ break;
+ case 0x0a<<11:
+ /* NORM (LO) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0;
+ else res = (sc > -32) ? (xop << -sc) : 0;
+ adsp2100.core.sr.sr = res;
+ break;
+ case 0x0b<<11:
+ /* NORM (LO, OR) */
+ xop = SHIFT_GETXREG_UNSIGNED(xop);
+ if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0;
+ else res = (sc > -32) ? (xop << -sc) : 0;
+ adsp2100.core.sr.sr |= res;
+ break;
+ }
+}
diff --git a/src/emu/cpu/adsp2100/adsp2100.c b/src/emu/cpu/adsp2100/adsp2100.c
new file mode 100644
index 00000000000..ee80da32cff
--- /dev/null
+++ b/src/emu/cpu/adsp2100/adsp2100.c
@@ -0,0 +1,2612 @@
+/***************************************************************************
+
+ ADSP2100.c
+ Core implementation for the portable Analog ADSP-2100 emulator.
+ Written by Aaron Giles
+
+****************************************************************************
+
+ For ADSP-2101, ADSP-2111
+ ------------------------
+
+ MMAP = 0 MMAP = 1
+
+ Automatic boot loading No auto boot loading
+
+ Program Space: Program Space:
+ 0000-07ff = 2k Internal RAM (booted) 0000-37ff = 14k External access
+ 0800-3fff = 14k External access 3800-3fff = 2k Internal RAM
+
+ Data Space: Data Space:
+ 0000-03ff = 1k External DWAIT0 0000-03ff = 1k External DWAIT0
+ 0400-07ff = 1k External DWAIT1 0400-07ff = 1k External DWAIT1
+ 0800-2fff = 10k External DWAIT2 0800-2fff = 10k External DWAIT2
+ 3000-33ff = 1k External DWAIT3 3000-33ff = 1k External DWAIT3
+ 3400-37ff = 1k External DWAIT4 3400-37ff = 1k External DWAIT4
+ 3800-3bff = 1k Internal RAM 3800-3bff = 1k Internal RAM
+ 3c00-3fff = 1k Internal Control regs 3c00-3fff = 1k Internal Control regs
+
+
+ For ADSP-2105, ADSP-2115, ADSP-2104
+ -----------------------------------
+
+ MMAP = 0 MMAP = 1
+
+ Automatic boot loading No auto boot loading
+
+ Program Space: Program Space:
+ 0000-03ff = 1k Internal RAM (booted) 0000-37ff = 14k External access
+ 0400-07ff = 1k Reserved 3800-3bff = 1k Internal RAM
+ 0800-3fff = 14k External access 3c00-3fff = 1k Reserved
+
+ Data Space: Data Space:
+ 0000-03ff = 1k External DWAIT0 0000-03ff = 1k External DWAIT0
+ 0400-07ff = 1k External DWAIT1 0400-07ff = 1k External DWAIT1
+ 0800-2fff = 10k External DWAIT2 0800-2fff = 10k External DWAIT2
+ 3000-33ff = 1k External DWAIT3 3000-33ff = 1k External DWAIT3
+ 3400-37ff = 1k External DWAIT4 3400-37ff = 1k External DWAIT4
+ 3800-39ff = 512 Internal RAM 3800-39ff = 512 Internal RAM
+ 3a00-3bff = 512 Reserved 3a00-3bff = 512 Reserved
+ 3c00-3fff = 1k Internal Control regs 3c00-3fff = 1k Internal Control regs
+
+
+ For ADSP-2181
+ -------------
+
+ MMAP = 0 MMAP = 1
+
+ Program Space: Program Space:
+ 0000-1fff = 8k Internal RAM 0000-1fff = 8k External access
+ 2000-3fff = 8k Internal RAM or Overlay 2000-3fff = 8k Internal
+
+ Data Space: Data Space:
+ 0000-1fff = 8k Internal RAM or Overlay 0000-1fff = 8k Internal RAM or Overlay
+ 2000-3fdf = 8k-32 Internal RAM 2000-3fdf = 8k-32 Internal RAM
+ 3fe0-3fff = 32 Internal Control regs 3fe0-3fff = 32 Internal Control regs
+
+ I/O Space: I/O Space:
+ 0000-01ff = 512 External IOWAIT0 0000-01ff = 512 External IOWAIT0
+ 0200-03ff = 512 External IOWAIT1 0200-03ff = 512 External IOWAIT1
+ 0400-05ff = 512 External IOWAIT2 0400-05ff = 512 External IOWAIT2
+ 0600-07ff = 512 External IOWAIT3 0600-07ff = 512 External IOWAIT3
+
+***************************************************************************/
+
+#include "debugger.h"
+#include "adsp2100.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define TRACK_HOTSPOTS 0
+
+/* stack depths */
+#define PC_STACK_DEPTH 16
+#define CNTR_STACK_DEPTH 4
+#define STAT_STACK_DEPTH 4
+#define LOOP_STACK_DEPTH 4
+
+/* chip types */
+#define CHIP_TYPE_ADSP2100 0
+#define CHIP_TYPE_ADSP2101 1
+#define CHIP_TYPE_ADSP2104 2
+#define CHIP_TYPE_ADSP2105 3
+#define CHIP_TYPE_ADSP2115 4
+#define CHIP_TYPE_ADSP2181 5
+
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+/* 16-bit registers that can be loaded signed or unsigned */
+typedef union
+{
+ UINT16 u;
+ INT16 s;
+} ADSPREG16;
+
+
+/* the SHIFT result register is 32 bits */
+typedef union
+{
+#ifdef LSB_FIRST
+ struct { ADSPREG16 sr0, sr1; } srx;
+#else
+ struct { ADSPREG16 sr1, sr0; } srx;
+#endif
+ UINT32 sr;
+} SHIFTRESULT;
+
+
+/* the MAC result register is 40 bits */
+typedef union
+{
+#ifdef LSB_FIRST
+ struct { ADSPREG16 mr0, mr1, mr2, mrzero; } mrx;
+ struct { UINT32 mr0, mr1; } mry;
+#else
+ struct { ADSPREG16 mrzero, mr2, mr1, mr0; } mrx;
+ struct { UINT32 mr1, mr0; } mry;
+#endif
+ UINT64 mr;
+} MACRESULT;
+
+/* there are two banks of "core" registers */
+typedef struct ADSPCORE
+{
+ /* ALU registers */
+ ADSPREG16 ax0, ax1;
+ ADSPREG16 ay0, ay1;
+ ADSPREG16 ar;
+ ADSPREG16 af;
+
+ /* MAC registers */
+ ADSPREG16 mx0, mx1;
+ ADSPREG16 my0, my1;
+ MACRESULT mr;
+ ADSPREG16 mf;
+
+ /* SHIFT registers */
+ ADSPREG16 si;
+ ADSPREG16 se;
+ ADSPREG16 sb;
+ SHIFTRESULT sr;
+
+ /* dummy registers */
+ ADSPREG16 zero;
+} ADSPCORE;
+
+
+/* ADSP-2100 Registers */
+typedef struct
+{
+ /* Core registers, 2 banks */
+ ADSPCORE core;
+ ADSPCORE alt;
+
+ /* Memory addressing registers */
+ UINT32 i[8];
+ INT32 m[8];
+ UINT32 l[8];
+ UINT32 lmask[8];
+ UINT32 base[8];
+ UINT8 px;
+
+ /* other CPU registers */
+ UINT32 pc;
+ UINT32 ppc;
+ UINT32 loop;
+ UINT32 loop_condition;
+ UINT32 cntr;
+
+ /* status registers */
+ UINT32 astat;
+ UINT32 sstat;
+ UINT32 mstat;
+ UINT32 astat_clear;
+ UINT32 idle;
+
+ /* stacks */
+ UINT32 loop_stack[LOOP_STACK_DEPTH];
+ UINT32 cntr_stack[CNTR_STACK_DEPTH];
+ UINT32 pc_stack[PC_STACK_DEPTH];
+ UINT16 stat_stack[STAT_STACK_DEPTH][3];
+ INT32 pc_sp;
+ INT32 cntr_sp;
+ INT32 stat_sp;
+ INT32 loop_sp;
+
+ /* external I/O */
+ UINT8 flagout;
+ UINT8 flagin;
+ UINT8 fl0;
+ UINT8 fl1;
+ UINT8 fl2;
+ UINT16 idma_addr;
+ UINT16 idma_cache;
+ UINT8 idma_offs;
+
+ /* interrupt handling */
+ UINT16 imask;
+ UINT8 icntl;
+ UINT16 ifc;
+ UINT8 irq_state[9];
+ UINT8 irq_latch[9];
+ INT32 interrupt_cycles;
+ int (*irq_callback)(int irqline);
+
+ /* other callbacks */
+ RX_CALLBACK sport_rx_callback;
+ TX_CALLBACK sport_tx_callback;
+ ADSP2100_TIMER_CALLBACK timer_callback;
+} adsp2100_Regs;
+
+
+
+/***************************************************************************
+ PUBLIC GLOBAL VARIABLES
+***************************************************************************/
+
+static int adsp2100_icount;
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static adsp2100_Regs adsp2100;
+
+static int chip_type = CHIP_TYPE_ADSP2100;
+static int mstat_mask;
+static int imask_mask;
+
+static UINT16 *reverse_table = 0;
+static UINT16 *mask_table = 0;
+static UINT8 *condition_table = 0;
+
+#if TRACK_HOTSPOTS
+static UINT32 pcbucket[0x4000];
+#endif
+
+
+/***************************************************************************
+ PRIVATE FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int create_tables(void);
+static void check_irqs(void);
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+INLINE UINT16 RWORD_DATA(UINT32 addr)
+{
+ return data_read_word_16le(addr << 1);
+}
+
+INLINE void WWORD_DATA(UINT32 addr, UINT16 data)
+{
+ data_write_word_16le(addr << 1, data);
+}
+
+INLINE UINT16 RWORD_IO(UINT32 addr)
+{
+ return io_read_word_16le(addr << 1);
+}
+
+INLINE void WWORD_IO(UINT32 addr, UINT16 data)
+{
+ io_write_word_16le(addr << 1, data);
+}
+
+INLINE UINT32 RWORD_PGM(UINT32 addr)
+{
+ return program_read_dword_32le(addr << 2);
+}
+
+INLINE void WWORD_PGM(UINT32 addr, UINT32 data)
+{
+ program_write_dword_32le(addr << 2, data & 0xffffff);
+}
+
+#define ROPCODE() cpu_readop32(adsp2100.pc << 2)
+
+#define CHANGEPC() change_pc(adsp2100.pc << 2)
+
+
+/***************************************************************************
+ OTHER INLINES
+***************************************************************************/
+
+#if (HAS_ADSP2100)
+INLINE void set_core_2100(void)
+{
+ chip_type = CHIP_TYPE_ADSP2100;
+ mstat_mask = 0x0f;
+ imask_mask = 0x0f;
+}
+#endif
+
+#if (HAS_ADSP2101)
+INLINE void set_core_2101(void)
+{
+ chip_type = CHIP_TYPE_ADSP2101;
+ mstat_mask = 0x7f;
+ imask_mask = 0x3f;
+}
+#endif
+
+#if (HAS_ADSP2104)
+INLINE void set_core_2104(void)
+{
+ chip_type = CHIP_TYPE_ADSP2104;
+ mstat_mask = 0x7f;
+ imask_mask = 0x3f;
+}
+#endif
+
+#if (HAS_ADSP2105)
+INLINE void set_core_2105(void)
+{
+ chip_type = CHIP_TYPE_ADSP2105;
+ mstat_mask = 0x7f;
+ imask_mask = 0x3f;
+}
+#endif
+
+#if (HAS_ADSP2115)
+INLINE void set_core_2115(void)
+{
+ chip_type = CHIP_TYPE_ADSP2115;
+ mstat_mask = 0x7f;
+ imask_mask = 0x3f;
+}
+#endif
+
+#if (HAS_ADSP2181)
+INLINE void set_core_2181(void)
+{
+ chip_type = CHIP_TYPE_ADSP2181;
+ mstat_mask = 0x7f;
+ imask_mask = 0x3ff;
+}
+#endif
+
+
+/***************************************************************************
+ IMPORT CORE UTILITIES
+***************************************************************************/
+
+#include "2100ops.c"
+
+
+
+/***************************************************************************
+ IRQ HANDLING
+***************************************************************************/
+
+INLINE int adsp2100_generate_irq(int which)
+{
+ /* skip if masked */
+ if (!(adsp2100.imask & (1 << which)))
+ return 0;
+
+ /* clear the latch */
+ adsp2100.irq_latch[which] = 0;
+
+ /* push the PC and the status */
+ pc_stack_push();
+ stat_stack_push();
+
+ /* vector to location & stop idling */
+ adsp2100.pc = which;
+ CHANGEPC();
+ adsp2100.idle = 0;
+
+ /* mask other interrupts based on the nesting bit */
+ if (adsp2100.icntl & 0x10) adsp2100.imask &= ~((2 << which) - 1);
+ else adsp2100.imask &= ~0xf;
+
+ return 1;
+}
+
+
+INLINE int adsp2101_generate_irq(int which, int indx)
+{
+ /* skip if masked */
+ if (!(adsp2100.imask & (0x20 >> indx)))
+ return 0;
+
+ /* clear the latch */
+ adsp2100.irq_latch[which] = 0;
+
+ /* push the PC and the status */
+ pc_stack_push();
+ stat_stack_push();
+
+ /* vector to location & stop idling */
+ adsp2100.pc = 0x04 + indx * 4;
+ CHANGEPC();
+ adsp2100.idle = 0;
+
+ /* mask other interrupts based on the nesting bit */
+ if (adsp2100.icntl & 0x10) adsp2100.imask &= ~(0x3f >> indx);
+ else adsp2100.imask &= ~0x3f;
+
+ return 1;
+}
+
+
+INLINE int adsp2181_generate_irq(int which, int indx)
+{
+ /* skip if masked */
+ if (!(adsp2100.imask & (0x200 >> indx)))
+ return 0;
+
+ /* clear the latch */
+ adsp2100.irq_latch[which] = 0;
+
+ /* push the PC and the status */
+ pc_stack_push();
+ stat_stack_push();
+
+ /* vector to location & stop idling */
+ adsp2100.pc = 0x04 + indx * 4;
+ CHANGEPC();
+ adsp2100.idle = 0;
+
+ /* mask other interrupts based on the nesting bit */
+ if (adsp2100.icntl & 0x10) adsp2100.imask &= ~(0x3ff >> indx);
+ else adsp2100.imask &= ~0x3ff;
+
+ return 1;
+}
+
+
+static void check_irqs(void)
+{
+ UINT8 check;
+
+#if (HAS_ADSP2181)
+ if (chip_type >= CHIP_TYPE_ADSP2181)
+ {
+ /* check IRQ2 */
+ check = (adsp2100.icntl & 4) ? adsp2100.irq_latch[ADSP2181_IRQ2] : adsp2100.irq_state[ADSP2181_IRQ2];
+ if (check && adsp2181_generate_irq(ADSP2181_IRQ2, 0))
+ return;
+
+ /* check IRQL1 */
+ check = adsp2100.irq_state[ADSP2181_IRQL1];
+ if (check && adsp2181_generate_irq(ADSP2181_IRQL1, 1))
+ return;
+
+ /* check IRQL2 */
+ check = adsp2100.irq_state[ADSP2181_IRQL2];
+ if (check && adsp2181_generate_irq(ADSP2181_IRQL2, 2))
+ return;
+
+ /* check SPORT0 transmit */
+ check = adsp2100.irq_latch[ADSP2181_SPORT0_TX];
+ if (check && adsp2181_generate_irq(ADSP2181_SPORT0_TX, 3))
+ return;
+
+ /* check SPORT0 receive */
+ check = adsp2100.irq_latch[ADSP2181_SPORT0_RX];
+ if (check && adsp2181_generate_irq(ADSP2181_SPORT0_RX, 4))
+ return;
+
+ /* check IRQE */
+ check = adsp2100.irq_latch[ADSP2181_IRQE];
+ if (check && adsp2181_generate_irq(ADSP2181_IRQE, 5))
+ return;
+
+ /* check BDMA interrupt */
+
+ /* check IRQ1/SPORT1 transmit */
+ check = (adsp2100.icntl & 2) ? adsp2100.irq_latch[ADSP2181_IRQ1] : adsp2100.irq_state[ADSP2181_IRQ1];
+ if (check && adsp2181_generate_irq(ADSP2181_IRQ1, 7))
+ return;
+
+ /* check IRQ0/SPORT1 receive */
+ check = (adsp2100.icntl & 1) ? adsp2100.irq_latch[ADSP2181_IRQ0] : adsp2100.irq_state[ADSP2181_IRQ0];
+ if (check && adsp2181_generate_irq(ADSP2181_IRQ0, 8))
+ return;
+
+ /* check timer */
+ check = adsp2100.irq_latch[ADSP2181_TIMER];
+ if (check && adsp2181_generate_irq(ADSP2181_TIMER, 9))
+ return;
+ }
+ else
+#endif
+ if (chip_type >= CHIP_TYPE_ADSP2101)
+ {
+ /* check IRQ2 */
+ check = (adsp2100.icntl & 4) ? adsp2100.irq_latch[ADSP2101_IRQ2] : adsp2100.irq_state[ADSP2101_IRQ2];
+ if (check && adsp2101_generate_irq(ADSP2101_IRQ2, 0))
+ return;
+
+ /* check SPORT0 transmit */
+ check = adsp2100.irq_latch[ADSP2101_SPORT0_TX];
+ if (check && adsp2101_generate_irq(ADSP2101_SPORT0_TX, 1))
+ return;
+
+ /* check SPORT0 receive */
+ check = adsp2100.irq_latch[ADSP2101_SPORT0_RX];
+ if (check && adsp2101_generate_irq(ADSP2101_SPORT0_RX, 2))
+ return;
+
+ /* check IRQ1/SPORT1 transmit */
+ check = (adsp2100.icntl & 2) ? adsp2100.irq_latch[ADSP2101_IRQ1] : adsp2100.irq_state[ADSP2101_IRQ1];
+ if (check && adsp2101_generate_irq(ADSP2101_IRQ1, 3))
+ return;
+
+ /* check IRQ0/SPORT1 receive */
+ check = (adsp2100.icntl & 1) ? adsp2100.irq_latch[ADSP2101_IRQ0] : adsp2100.irq_state[ADSP2101_IRQ0];
+ if (check && adsp2101_generate_irq(ADSP2101_IRQ0, 4))
+ return;
+
+ /* check timer */
+ check = adsp2100.irq_latch[ADSP2101_TIMER];
+ if (check && adsp2101_generate_irq(ADSP2101_TIMER, 5))
+ return;
+ }
+ else
+ {
+ /* check IRQ3 */
+ check = (adsp2100.icntl & 8) ? adsp2100.irq_latch[ADSP2100_IRQ3] : adsp2100.irq_state[ADSP2100_IRQ3];
+ if (check && adsp2100_generate_irq(ADSP2100_IRQ3))
+ return;
+
+ /* check IRQ2 */
+ check = (adsp2100.icntl & 4) ? adsp2100.irq_latch[ADSP2100_IRQ2] : adsp2100.irq_state[ADSP2100_IRQ2];
+ if (check && adsp2100_generate_irq(ADSP2100_IRQ2))
+ return;
+
+ /* check IRQ1 */
+ check = (adsp2100.icntl & 2) ? adsp2100.irq_latch[ADSP2100_IRQ1] : adsp2100.irq_state[ADSP2100_IRQ1];
+ if (check && adsp2100_generate_irq(ADSP2100_IRQ1))
+ return;
+
+ /* check IRQ0 */
+ check = (adsp2100.icntl & 1) ? adsp2100.irq_latch[ADSP2100_IRQ0] : adsp2100.irq_state[ADSP2100_IRQ0];
+ if (check && adsp2100_generate_irq(ADSP2100_IRQ0))
+ return;
+ }
+}
+
+
+static void set_irq_line(int irqline, int state)
+{
+ /* update the latched state */
+ if (state != CLEAR_LINE && adsp2100.irq_state[irqline] == CLEAR_LINE)
+ adsp2100.irq_latch[irqline] = 1;
+
+ /* update the absolute state */
+ adsp2100.irq_state[irqline] = state;
+
+ /* check for IRQs */
+ if (state != CLEAR_LINE)
+ check_irqs();
+}
+
+
+
+/***************************************************************************
+ CONTEXT SWITCHING
+***************************************************************************/
+
+static void adsp2100_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(adsp2100_Regs *)dst = adsp2100;
+}
+
+
+#if (HAS_ADSP2100)
+static void adsp2100_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ {
+ adsp2100 = *(adsp2100_Regs *)src;
+ CHANGEPC();
+ }
+
+ /* reset the chip type */
+ set_core_2100();
+
+ /* check for IRQs */
+ check_irqs();
+}
+#endif
+
+
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+static void adsp2100_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ /* create the tables */
+ if (!create_tables())
+ fatalerror("creating adsp2100 tables failed");
+
+ /* set the IRQ callback */
+ adsp2100.irq_callback = irqcallback;
+
+ /* "core" */
+ state_save_register_item("adsp2100", index, adsp2100.core.ax0.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.ax1.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.ay0.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.ay1.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.ar.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.af.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.mx0.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.mx1.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.my0.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.my1.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.mr.mr);
+ state_save_register_item("adsp2100", index, adsp2100.core.mf.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.si.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.se.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.sb.u);
+ state_save_register_item("adsp2100", index, adsp2100.core.sr.sr);
+ state_save_register_item("adsp2100", index, adsp2100.core.zero.u);
+
+ /* "alt" */
+ state_save_register_item("adsp2100", index, adsp2100.alt.ax0.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.ax1.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.ay0.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.ay1.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.ar.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.af.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.mx0.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.mx1.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.my0.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.my1.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.mr.mr);
+ state_save_register_item("adsp2100", index, adsp2100.alt.mf.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.si.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.se.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.sb.u);
+ state_save_register_item("adsp2100", index, adsp2100.alt.sr.sr);
+ state_save_register_item("adsp2100", index, adsp2100.alt.zero.u);
+
+ state_save_register_item_array("adsp2100", index, adsp2100.i);
+ state_save_register_item_array("adsp2100", index, adsp2100.m);
+ state_save_register_item_array("adsp2100", index, adsp2100.l);
+ state_save_register_item_array("adsp2100", index, adsp2100.lmask);
+ state_save_register_item_array("adsp2100", index, adsp2100.base);
+ state_save_register_item("adsp2100", index, adsp2100.px);
+
+ state_save_register_item("adsp2100", index, adsp2100.pc);
+ state_save_register_item("adsp2100", index, adsp2100.ppc);
+ state_save_register_item("adsp2100", index, adsp2100.loop);
+ state_save_register_item("adsp2100", index, adsp2100.loop_condition);
+ state_save_register_item("adsp2100", index, adsp2100.cntr);
+ state_save_register_item("adsp2100", index, adsp2100.astat);
+ state_save_register_item("adsp2100", index, adsp2100.sstat);
+ state_save_register_item("adsp2100", index, adsp2100.mstat);
+ state_save_register_item("adsp2100", index, adsp2100.astat_clear);
+ state_save_register_item("adsp2100", index, adsp2100.idle);
+
+ state_save_register_item_array("adsp2100", index, adsp2100.loop_stack);
+ state_save_register_item_array("adsp2100", index, adsp2100.cntr_stack);
+ state_save_register_item_array("adsp2100", index, adsp2100.pc_stack);
+ state_save_register_item_2d_array("adsp2100", index, adsp2100.stat_stack);
+
+ state_save_register_item("adsp2100", index, adsp2100.pc_sp);
+ state_save_register_item("adsp2100", index, adsp2100.cntr_sp);
+ state_save_register_item("adsp2100", index, adsp2100.stat_sp);
+ state_save_register_item("adsp2100", index, adsp2100.loop_sp);
+
+ state_save_register_item("adsp2100", index, adsp2100.flagout);
+ state_save_register_item("adsp2100", index, adsp2100.flagin);
+ state_save_register_item("adsp2100", index, adsp2100.fl0);
+ state_save_register_item("adsp2100", index, adsp2100.fl1);
+ state_save_register_item("adsp2100", index, adsp2100.fl2);
+
+ state_save_register_item("adsp2100", index, adsp2100.idma_addr);
+ state_save_register_item("adsp2100", index, adsp2100.idma_cache);
+ state_save_register_item("adsp2100", index, adsp2100.idma_offs);
+
+ state_save_register_item("adsp2100", index, adsp2100.imask);
+ state_save_register_item("adsp2100", index, adsp2100.icntl);
+ state_save_register_item("adsp2100", index, adsp2100.ifc);
+
+ state_save_register_item_array("adsp2100", index, adsp2100.irq_state);
+ state_save_register_item_array("adsp2100", index, adsp2100.irq_latch);
+ state_save_register_item("adsp2100", index, adsp2100.interrupt_cycles);
+}
+
+
+static void adsp2100_reset(void)
+{
+ int irq;
+
+ /* ensure that zero is zero */
+ adsp2100.core.zero.u = adsp2100.alt.zero.u = 0;
+
+ /* recompute the memory registers with their current values */
+ wr_l0(adsp2100.l[0]); wr_i0(adsp2100.i[0]);
+ wr_l1(adsp2100.l[1]); wr_i1(adsp2100.i[1]);
+ wr_l2(adsp2100.l[2]); wr_i2(adsp2100.i[2]);
+ wr_l3(adsp2100.l[3]); wr_i3(adsp2100.i[3]);
+ wr_l4(adsp2100.l[4]); wr_i4(adsp2100.i[4]);
+ wr_l5(adsp2100.l[5]); wr_i5(adsp2100.i[5]);
+ wr_l6(adsp2100.l[6]); wr_i6(adsp2100.i[6]);
+ wr_l7(adsp2100.l[7]); wr_i7(adsp2100.i[7]);
+
+ /* reset PC and loops */
+ switch (chip_type)
+ {
+ case CHIP_TYPE_ADSP2100:
+ adsp2100.pc = 4;
+ break;
+
+ case CHIP_TYPE_ADSP2101:
+ case CHIP_TYPE_ADSP2104:
+ case CHIP_TYPE_ADSP2105:
+ case CHIP_TYPE_ADSP2115:
+ case CHIP_TYPE_ADSP2181:
+ adsp2100.pc = 0;
+ break;
+
+ default:
+ logerror( "ADSP2100 core: Unknown chip type!. Defaulting to ADSP2100.\n" );
+ adsp2100.pc = 4;
+ chip_type = CHIP_TYPE_ADSP2100;
+ break;
+ }
+ CHANGEPC();
+
+ adsp2100.ppc = -1;
+ adsp2100.loop = 0xffff;
+ adsp2100.loop_condition = 0;
+
+ /* reset status registers */
+ adsp2100.astat_clear = ~(CFLAG | VFLAG | NFLAG | ZFLAG);
+ adsp2100.mstat = 0;
+ adsp2100.sstat = 0x55;
+ adsp2100.idle = 0;
+
+ /* reset stacks */
+ adsp2100.pc_sp = 0;
+ adsp2100.cntr_sp = 0;
+ adsp2100.stat_sp = 0;
+ adsp2100.loop_sp = 0;
+
+ /* reset external I/O */
+ adsp2100.flagout = 0;
+ adsp2100.flagin = 0;
+ adsp2100.fl0 = 0;
+ adsp2100.fl1 = 0;
+ adsp2100.fl2 = 0;
+
+ /* reset interrupts */
+ adsp2100.imask = 0;
+ for (irq = 0; irq < 8; irq++)
+ adsp2100.irq_state[irq] = adsp2100.irq_latch[irq] = CLEAR_LINE;
+ adsp2100.interrupt_cycles = 0;
+}
+
+
+static int create_tables(void)
+{
+ int i;
+
+ /* allocate the tables */
+ if (!reverse_table)
+ reverse_table = (UINT16 *)malloc(0x4000 * sizeof(UINT16));
+ if (!mask_table)
+ mask_table = (UINT16 *)malloc(0x4000 * sizeof(UINT16));
+ if (!condition_table)
+ condition_table = (UINT8 *)malloc(0x1000 * sizeof(UINT8));
+
+ /* handle errors */
+ if (!reverse_table || !mask_table || !condition_table)
+ return 0;
+
+ /* initialize the bit reversing table */
+ for (i = 0; i < 0x4000; i++)
+ {
+ UINT16 data = 0;
+
+ data |= (i >> 13) & 0x0001;
+ data |= (i >> 11) & 0x0002;
+ data |= (i >> 9) & 0x0004;
+ data |= (i >> 7) & 0x0008;
+ data |= (i >> 5) & 0x0010;
+ data |= (i >> 3) & 0x0020;
+ data |= (i >> 1) & 0x0040;
+ data |= (i << 1) & 0x0080;
+ data |= (i << 3) & 0x0100;
+ data |= (i << 5) & 0x0200;
+ data |= (i << 7) & 0x0400;
+ data |= (i << 9) & 0x0800;
+ data |= (i << 11) & 0x1000;
+ data |= (i << 13) & 0x2000;
+
+ reverse_table[i] = data;
+ }
+
+ /* initialize the mask table */
+ for (i = 0; i < 0x4000; i++)
+ {
+ if (i > 0x2000) mask_table[i] = 0x0000;
+ else if (i > 0x1000) mask_table[i] = 0x2000;
+ else if (i > 0x0800) mask_table[i] = 0x3000;
+ else if (i > 0x0400) mask_table[i] = 0x3800;
+ else if (i > 0x0200) mask_table[i] = 0x3c00;
+ else if (i > 0x0100) mask_table[i] = 0x3e00;
+ else if (i > 0x0080) mask_table[i] = 0x3f00;
+ else if (i > 0x0040) mask_table[i] = 0x3f80;
+ else if (i > 0x0020) mask_table[i] = 0x3fc0;
+ else if (i > 0x0010) mask_table[i] = 0x3fe0;
+ else if (i > 0x0008) mask_table[i] = 0x3ff0;
+ else if (i > 0x0004) mask_table[i] = 0x3ff8;
+ else if (i > 0x0002) mask_table[i] = 0x3ffc;
+ else if (i > 0x0001) mask_table[i] = 0x3ffe;
+ else mask_table[i] = 0x3fff;
+ }
+
+ /* initialize the condition table */
+ for (i = 0; i < 0x100; i++)
+ {
+ int az = ((i & ZFLAG) != 0);
+ int an = ((i & NFLAG) != 0);
+ int av = ((i & VFLAG) != 0);
+ int ac = ((i & CFLAG) != 0);
+ int mv = ((i & MVFLAG) != 0);
+ int as = ((i & SFLAG) != 0);
+
+ condition_table[i | 0x000] = az;
+ condition_table[i | 0x100] = !az;
+ condition_table[i | 0x200] = !((an ^ av) | az);
+ condition_table[i | 0x300] = (an ^ av) | az;
+ condition_table[i | 0x400] = an ^ av;
+ condition_table[i | 0x500] = !(an ^ av);
+ condition_table[i | 0x600] = av;
+ condition_table[i | 0x700] = !av;
+ condition_table[i | 0x800] = ac;
+ condition_table[i | 0x900] = !ac;
+ condition_table[i | 0xa00] = as;
+ condition_table[i | 0xb00] = !as;
+ condition_table[i | 0xc00] = mv;
+ condition_table[i | 0xd00] = !mv;
+ condition_table[i | 0xf00] = 1;
+ }
+ return 1;
+}
+
+
+static void adsp2100_exit(void)
+{
+ if (reverse_table)
+ free(reverse_table);
+ reverse_table = NULL;
+
+ if (mask_table)
+ free(mask_table);
+ mask_table = NULL;
+
+ if (condition_table)
+ free(condition_table);
+ condition_table = NULL;
+
+#if TRACK_HOTSPOTS
+ {
+ FILE *log = fopen("adsp.hot", "w");
+ while (1)
+ {
+ int maxindex = 0, i;
+ for (i = 1; i < 0x4000; i++)
+ if (pcbucket[i] > pcbucket[maxindex])
+ maxindex = i;
+ if (pcbucket[maxindex] == 0)
+ break;
+ fprintf(log, "PC=%04X (%10d hits)\n", maxindex, pcbucket[maxindex]);
+ pcbucket[maxindex] = 0;
+ }
+ fclose(log);
+ }
+#endif
+
+}
+
+
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+/* execute instructions on this CPU until icount expires */
+static int adsp2100_execute(int cycles)
+{
+ /* reset the core */
+ set_mstat(adsp2100.mstat);
+
+ /* count cycles and interrupt cycles */
+ adsp2100_icount = cycles;
+ adsp2100_icount -= adsp2100.interrupt_cycles;
+ adsp2100.interrupt_cycles = 0;
+
+ CHANGEPC();
+
+ /* core execution loop */
+ do
+ {
+ UINT32 op, temp;
+
+ /* debugging */
+ adsp2100.ppc = adsp2100.pc; /* copy PC to previous PC */
+ CALL_MAME_DEBUG;
+
+#if TRACK_HOTSPOTS
+ pcbucket[adsp2100.pc & 0x3fff]++;
+#endif
+
+ /* instruction fetch */
+ op = ROPCODE();
+
+ /* advance to the next instruction */
+ if (adsp2100.pc != adsp2100.loop)
+ adsp2100.pc++;
+
+ /* handle looping */
+ else
+ {
+ /* condition not met, keep looping */
+ if (CONDITION(adsp2100.loop_condition))
+ adsp2100.pc = pc_stack_top();
+
+ /* condition met; pop the PC and loop stacks and fall through */
+ else
+ {
+ loop_stack_pop();
+ pc_stack_pop_val();
+ adsp2100.pc++;
+ }
+ }
+
+ /* parse the instruction */
+ switch (op >> 16)
+ {
+ case 0x00:
+ /* 00000000 00000000 00000000 NOP */
+ break;
+ case 0x01:
+ /* 00000000 0xxxxxxx xxxxxxxx dst = IO(x) */
+ /* 00000000 1xxxxxxx xxxxxxxx IO(x) = dst */
+ /* ADSP-218x only */
+ if (chip_type >= CHIP_TYPE_ADSP2181)
+ {
+ if ((op & 0x008000) == 0x000000)
+ WRITE_REG(0, op & 15, RWORD_IO((op >> 4) & 0x7ff));
+ else
+ WWORD_IO((op >> 4) & 0x7ff, READ_REG(0, op & 15));
+ }
+ break;
+ case 0x02:
+ /* 00000010 0000xxxx xxxxxxxx modify flag out */
+ /* 00000010 10000000 00000000 idle */
+ /* 00000010 10000000 0000xxxx idle (n) */
+ if (op & 0x008000)
+ {
+ adsp2100.idle = 1;
+ adsp2100_icount = 0;
+ }
+ else
+ {
+ if (CONDITION(op & 15))
+ {
+ if (op & 0x020) adsp2100.flagout = 0;
+ if (op & 0x010) adsp2100.flagout ^= 1;
+ if (chip_type >= CHIP_TYPE_ADSP2101)
+ {
+ if (op & 0x080) adsp2100.fl0 = 0;
+ if (op & 0x040) adsp2100.fl0 ^= 1;
+ if (op & 0x200) adsp2100.fl1 = 0;
+ if (op & 0x100) adsp2100.fl1 ^= 1;
+ if (op & 0x800) adsp2100.fl2 = 0;
+ if (op & 0x400) adsp2100.fl2 ^= 1;
+ }
+ }
+ }
+ break;
+ case 0x03:
+ /* 00000011 xxxxxxxx xxxxxxxx call or jump on flag in */
+ if (op & 0x000002)
+ {
+ if (adsp2100.flagin)
+ {
+ if (op & 0x000001)
+ pc_stack_push();
+ adsp2100.pc = ((op >> 4) & 0x0fff) | ((op << 10) & 0x3000);
+ CHANGEPC();
+ }
+ }
+ else
+ {
+ if (!adsp2100.flagin)
+ {
+ if (op & 0x000001)
+ pc_stack_push();
+ adsp2100.pc = ((op >> 4) & 0x0fff) | ((op << 10) & 0x3000);
+ CHANGEPC();
+ }
+ }
+ break;
+ case 0x04:
+ /* 00000100 00000000 000xxxxx stack control */
+ if (op & 0x000010) pc_stack_pop_val();
+ if (op & 0x000008) loop_stack_pop();
+ if (op & 0x000004) cntr_stack_pop();
+ if (op & 0x000002)
+ {
+ if (op & 0x000001) stat_stack_pop();
+ else stat_stack_push();
+ }
+ break;
+ case 0x05:
+ /* 00000101 00000000 00000000 saturate MR */
+ if (GET_MV)
+ {
+ if (adsp2100.core.mr.mrx.mr2.u & 0x80)
+ adsp2100.core.mr.mrx.mr2.u = 0xffff, adsp2100.core.mr.mrx.mr1.u = 0x8000, adsp2100.core.mr.mrx.mr0.u = 0x0000;
+ else
+ adsp2100.core.mr.mrx.mr2.u = 0x0000, adsp2100.core.mr.mrx.mr1.u = 0x7fff, adsp2100.core.mr.mrx.mr0.u = 0xffff;
+ }
+ break;
+ case 0x06:
+ /* 00000110 000xxxxx 00000000 DIVS */
+ {
+ int xop = (op >> 8) & 7;
+ int yop = (op >> 11) & 3;
+
+ xop = ALU_GETXREG_UNSIGNED(xop);
+ yop = ALU_GETYREG_UNSIGNED(yop);
+
+ temp = xop ^ yop;
+ adsp2100.astat = (adsp2100.astat & ~QFLAG) | ((temp >> 10) & QFLAG);
+ adsp2100.core.af.u = (yop << 1) | (adsp2100.core.ay0.u >> 15);
+ adsp2100.core.ay0.u = (adsp2100.core.ay0.u << 1) | (temp >> 15);
+ }
+ break;
+ case 0x07:
+ /* 00000111 00010xxx 00000000 DIVQ */
+ {
+ int xop = (op >> 8) & 7;
+ int res;
+
+ xop = ALU_GETXREG_UNSIGNED(xop);
+
+ if (GET_Q)
+ res = adsp2100.core.af.u + xop;
+ else
+ res = adsp2100.core.af.u - xop;
+
+ temp = res ^ xop;
+ adsp2100.astat = (adsp2100.astat & ~QFLAG) | ((temp >> 10) & QFLAG);
+ adsp2100.core.af.u = (res << 1) | (adsp2100.core.ay0.u >> 15);
+ adsp2100.core.ay0.u = (adsp2100.core.ay0.u << 1) | ((~temp >> 15) & 0x0001);
+ }
+ break;
+ case 0x08:
+ /* 00001000 00000000 0000xxxx reserved */
+ break;
+ case 0x09:
+ /* 00001001 00000000 000xxxxx modify address register */
+ temp = (op >> 2) & 4;
+ modify_address(temp + ((op >> 2) & 3), temp + (op & 3));
+ break;
+ case 0x0a:
+ /* 00001010 00000000 000xxxxx conditional return */
+ if (CONDITION(op & 15))
+ {
+ pc_stack_pop();
+
+ /* RTI case */
+ if (op & 0x000010)
+ stat_stack_pop();
+ }
+ break;
+ case 0x0b:
+ /* 00001011 00000000 xxxxxxxx conditional jump (indirect address) */
+ if (CONDITION(op & 15))
+ {
+ if (op & 0x000010)
+ pc_stack_push();
+ adsp2100.pc = adsp2100.i[4 + ((op >> 6) & 3)] & 0x3fff;
+ CHANGEPC();
+ }
+ break;
+ case 0x0c:
+ /* 00001100 xxxxxxxx xxxxxxxx mode control */
+ temp = adsp2100.mstat;
+ if (chip_type >= CHIP_TYPE_ADSP2101)
+ {
+ if (op & 0x000008) temp = (temp & ~MSTAT_GOMODE) | ((op << 5) & MSTAT_GOMODE);
+ if (op & 0x002000) temp = (temp & ~MSTAT_INTEGER) | ((op >> 8) & MSTAT_INTEGER);
+ if (op & 0x008000) temp = (temp & ~MSTAT_TIMER) | ((op >> 9) & MSTAT_TIMER);
+ }
+ if (op & 0x000020) temp = (temp & ~MSTAT_BANK) | ((op >> 4) & MSTAT_BANK);
+ if (op & 0x000080) temp = (temp & ~MSTAT_REVERSE) | ((op >> 5) & MSTAT_REVERSE);
+ if (op & 0x000200) temp = (temp & ~MSTAT_STICKYV) | ((op >> 6) & MSTAT_STICKYV);
+ if (op & 0x000800) temp = (temp & ~MSTAT_SATURATE) | ((op >> 7) & MSTAT_SATURATE);
+ set_mstat(temp);
+ break;
+ case 0x0d:
+ /* 00001101 0000xxxx xxxxxxxx internal data move */
+ WRITE_REG((op >> 10) & 3, (op >> 4) & 15, READ_REG((op >> 8) & 3, op & 15));
+ break;
+ case 0x0e:
+ /* 00001110 0xxxxxxx xxxxxxxx conditional shift */
+ if (CONDITION(op & 15)) shift_op(op);
+ break;
+ case 0x0f:
+ /* 00001111 0xxxxxxx xxxxxxxx shift immediate */
+ shift_op_imm(op);
+ break;
+ case 0x10:
+ /* 00010000 0xxxxxxx xxxxxxxx shift with internal data register move */
+ shift_op(op);
+ temp = READ_REG(0, op & 15);
+ WRITE_REG(0, (op >> 4) & 15, temp);
+ break;
+ case 0x11:
+ /* 00010001 xxxxxxxx xxxxxxxx shift with pgm memory read/write */
+ if (op & 0x8000)
+ {
+ pgm_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ shift_op(op);
+ }
+ else
+ {
+ shift_op(op);
+ WRITE_REG(0, (op >> 4) & 15, pgm_read_dag2(op));
+ }
+ break;
+ case 0x12:
+ /* 00010010 xxxxxxxx xxxxxxxx shift with data memory read/write DAG1 */
+ if (op & 0x8000)
+ {
+ data_write_dag1(op, READ_REG(0, (op >> 4) & 15));
+ shift_op(op);
+ }
+ else
+ {
+ shift_op(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag1(op));
+ }
+ break;
+ case 0x13:
+ /* 00010011 xxxxxxxx xxxxxxxx shift with data memory read/write DAG2 */
+ if (op & 0x8000)
+ {
+ data_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ shift_op(op);
+ }
+ else
+ {
+ shift_op(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag2(op));
+ }
+ break;
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ /* 000101xx xxxxxxxx xxxxxxxx do until */
+ loop_stack_push(op & 0x3ffff);
+ pc_stack_push();
+ break;
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ /* 000110xx xxxxxxxx xxxxxxxx conditional jump (immediate addr) */
+ if (CONDITION(op & 15))
+ {
+ adsp2100.pc = (op >> 4) & 0x3fff;
+ CHANGEPC();
+ }
+ /* check for a busy loop */
+ if (adsp2100.pc == adsp2100.ppc)
+ adsp2100_icount = 0;
+ break;
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ /* 000111xx xxxxxxxx xxxxxxxx conditional call (immediate addr) */
+ if (CONDITION(op & 15))
+ {
+ pc_stack_push();
+ adsp2100.pc = (op >> 4) & 0x3fff;
+ CHANGEPC();
+ }
+ break;
+ case 0x20: case 0x21:
+ /* 0010000x xxxxxxxx xxxxxxxx conditional MAC to MR */
+ if (CONDITION(op & 15))
+ {
+ if (chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x0018f0) == 0x000010)
+ mac_op_mr_xop(op);
+ else
+ mac_op_mr(op);
+ }
+ break;
+ case 0x22: case 0x23:
+ /* 0010001x xxxxxxxx xxxxxxxx conditional ALU to AR */
+ if (CONDITION(op & 15))
+ {
+ if (chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x000010) == 0x000010)
+ alu_op_ar_const(op);
+ else
+ alu_op_ar(op);
+ }
+ break;
+ case 0x24: case 0x25:
+ /* 0010010x xxxxxxxx xxxxxxxx conditional MAC to MF */
+ if (CONDITION(op & 15))
+ {
+ if (chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x0018f0) == 0x000010)
+ mac_op_mf_xop(op);
+ else
+ mac_op_mf(op);
+ }
+ break;
+ case 0x26: case 0x27:
+ /* 0010011x xxxxxxxx xxxxxxxx conditional ALU to AF */
+ if (CONDITION(op & 15))
+ {
+ if (chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x000010) == 0x000010)
+ alu_op_af_const(op);
+ else
+ alu_op_af(op);
+ }
+ break;
+ case 0x28: case 0x29:
+ /* 0010100x xxxxxxxx xxxxxxxx MAC to MR with internal data register move */
+ temp = READ_REG(0, op & 15);
+ mac_op_mr(op);
+ WRITE_REG(0, (op >> 4) & 15, temp);
+ break;
+ case 0x2a: case 0x2b:
+ /* 0010101x xxxxxxxx xxxxxxxx ALU to AR with internal data register move */
+ if (chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x0000ff) == 0x0000aa)
+ alu_op_none(op);
+ else
+ {
+ temp = READ_REG(0, op & 15);
+ alu_op_ar(op);
+ WRITE_REG(0, (op >> 4) & 15, temp);
+ }
+ break;
+ case 0x2c: case 0x2d:
+ /* 0010110x xxxxxxxx xxxxxxxx MAC to MF with internal data register move */
+ temp = READ_REG(0, op & 15);
+ mac_op_mf(op);
+ WRITE_REG(0, (op >> 4) & 15, temp);
+ break;
+ case 0x2e: case 0x2f:
+ /* 0010111x xxxxxxxx xxxxxxxx ALU to AF with internal data register move */
+ temp = READ_REG(0, op & 15);
+ alu_op_af(op);
+ WRITE_REG(0, (op >> 4) & 15, temp);
+ break;
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ /* 001100xx xxxxxxxx xxxxxxxx load non-data register immediate (group 0) */
+ WRITE_REG(0, op & 15, (INT32)(op << 14) >> 18);
+ break;
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ /* 001101xx xxxxxxxx xxxxxxxx load non-data register immediate (group 1) */
+ WRITE_REG(1, op & 15, (INT32)(op << 14) >> 18);
+ break;
+ case 0x38: case 0x39: case 0x3a: case 0x3b:
+ /* 001110xx xxxxxxxx xxxxxxxx load non-data register immediate (group 2) */
+ WRITE_REG(2, op & 15, (INT32)(op << 14) >> 18);
+ break;
+ case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ /* 001111xx xxxxxxxx xxxxxxxx load non-data register immediate (group 3) */
+ WRITE_REG(3, op & 15, (INT32)(op << 14) >> 18);
+ break;
+ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
+ case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+ /* 0100xxxx xxxxxxxx xxxxxxxx load data register immediate */
+ WRITE_REG(0, op & 15, (op >> 4) & 0xffff);
+ break;
+ case 0x50: case 0x51:
+ /* 0101000x xxxxxxxx xxxxxxxx MAC to MR with pgm memory read */
+ mac_op_mr(op);
+ WRITE_REG(0, (op >> 4) & 15, pgm_read_dag2(op));
+ break;
+ case 0x52: case 0x53:
+ /* 0101001x xxxxxxxx xxxxxxxx ALU to AR with pgm memory read */
+ alu_op_ar(op);
+ WRITE_REG(0, (op >> 4) & 15, pgm_read_dag2(op));
+ break;
+ case 0x54: case 0x55:
+ /* 0101010x xxxxxxxx xxxxxxxx MAC to MF with pgm memory read */
+ mac_op_mf(op);
+ WRITE_REG(0, (op >> 4) & 15, pgm_read_dag2(op));
+ break;
+ case 0x56: case 0x57:
+ /* 0101011x xxxxxxxx xxxxxxxx ALU to AF with pgm memory read */
+ alu_op_af(op);
+ WRITE_REG(0, (op >> 4) & 15, pgm_read_dag2(op));
+ break;
+ case 0x58: case 0x59:
+ /* 0101100x xxxxxxxx xxxxxxxx MAC to MR with pgm memory write */
+ pgm_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ mac_op_mr(op);
+ break;
+ case 0x5a: case 0x5b:
+ /* 0101101x xxxxxxxx xxxxxxxx ALU to AR with pgm memory write */
+ pgm_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ alu_op_ar(op);
+ break;
+ case 0x5c: case 0x5d:
+ /* 0101110x xxxxxxxx xxxxxxxx ALU to MR with pgm memory write */
+ pgm_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ mac_op_mf(op);
+ break;
+ case 0x5e: case 0x5f:
+ /* 0101111x xxxxxxxx xxxxxxxx ALU to MF with pgm memory write */
+ pgm_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ alu_op_af(op);
+ break;
+ case 0x60: case 0x61:
+ /* 0110000x xxxxxxxx xxxxxxxx MAC to MR with data memory read DAG1 */
+ mac_op_mr(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag1(op));
+ break;
+ case 0x62: case 0x63:
+ /* 0110001x xxxxxxxx xxxxxxxx ALU to AR with data memory read DAG1 */
+ alu_op_ar(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag1(op));
+ break;
+ case 0x64: case 0x65:
+ /* 0110010x xxxxxxxx xxxxxxxx MAC to MF with data memory read DAG1 */
+ mac_op_mf(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag1(op));
+ break;
+ case 0x66: case 0x67:
+ /* 0110011x xxxxxxxx xxxxxxxx ALU to AF with data memory read DAG1 */
+ alu_op_af(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag1(op));
+ break;
+ case 0x68: case 0x69:
+ /* 0110100x xxxxxxxx xxxxxxxx MAC to MR with data memory write DAG1 */
+ data_write_dag1(op, READ_REG(0, (op >> 4) & 15));
+ mac_op_mr(op);
+ break;
+ case 0x6a: case 0x6b:
+ /* 0110101x xxxxxxxx xxxxxxxx ALU to AR with data memory write DAG1 */
+ data_write_dag1(op, READ_REG(0, (op >> 4) & 15));
+ alu_op_ar(op);
+ break;
+ case 0x6c: case 0x6d:
+ /* 0111110x xxxxxxxx xxxxxxxx MAC to MF with data memory write DAG1 */
+ data_write_dag1(op, READ_REG(0, (op >> 4) & 15));
+ mac_op_mf(op);
+ break;
+ case 0x6e: case 0x6f:
+ /* 0111111x xxxxxxxx xxxxxxxx ALU to AF with data memory write DAG1 */
+ data_write_dag1(op, READ_REG(0, (op >> 4) & 15));
+ alu_op_af(op);
+ break;
+ case 0x70: case 0x71:
+ /* 0111000x xxxxxxxx xxxxxxxx MAC to MR with data memory read DAG2 */
+ mac_op_mr(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag2(op));
+ break;
+ case 0x72: case 0x73:
+ /* 0111001x xxxxxxxx xxxxxxxx ALU to AR with data memory read DAG2 */
+ alu_op_ar(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag2(op));
+ break;
+ case 0x74: case 0x75:
+ /* 0111010x xxxxxxxx xxxxxxxx MAC to MF with data memory read DAG2 */
+ mac_op_mf(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag2(op));
+ break;
+ case 0x76: case 0x77:
+ /* 0111011x xxxxxxxx xxxxxxxx ALU to AF with data memory read DAG2 */
+ alu_op_af(op);
+ WRITE_REG(0, (op >> 4) & 15, data_read_dag2(op));
+ break;
+ case 0x78: case 0x79:
+ /* 0111100x xxxxxxxx xxxxxxxx MAC to MR with data memory write DAG2 */
+ data_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ mac_op_mr(op);
+ break;
+ case 0x7a: case 0x7b:
+ /* 0111101x xxxxxxxx xxxxxxxx ALU to AR with data memory write DAG2 */
+ data_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ alu_op_ar(op);
+ break;
+ case 0x7c: case 0x7d:
+ /* 0111110x xxxxxxxx xxxxxxxx MAC to MF with data memory write DAG2 */
+ data_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ mac_op_mf(op);
+ break;
+ case 0x7e: case 0x7f:
+ /* 0111111x xxxxxxxx xxxxxxxx ALU to AF with data memory write DAG2 */
+ data_write_dag2(op, READ_REG(0, (op >> 4) & 15));
+ alu_op_af(op);
+ break;
+ case 0x80: case 0x81: case 0x82: case 0x83:
+ /* 100000xx xxxxxxxx xxxxxxxx read data memory (immediate addr) to reg group 0 */
+ WRITE_REG(0, op & 15, RWORD_DATA((op >> 4) & 0x3fff));
+ break;
+ case 0x84: case 0x85: case 0x86: case 0x87:
+ /* 100001xx xxxxxxxx xxxxxxxx read data memory (immediate addr) to reg group 1 */
+ WRITE_REG(1, op & 15, RWORD_DATA((op >> 4) & 0x3fff));
+ break;
+ case 0x88: case 0x89: case 0x8a: case 0x8b:
+ /* 100010xx xxxxxxxx xxxxxxxx read data memory (immediate addr) to reg group 2 */
+ WRITE_REG(2, op & 15, RWORD_DATA((op >> 4) & 0x3fff));
+ break;
+ case 0x8c: case 0x8d: case 0x8e: case 0x8f:
+ /* 100011xx xxxxxxxx xxxxxxxx read data memory (immediate addr) to reg group 3 */
+ WRITE_REG(3, op & 15, RWORD_DATA((op >> 4) & 0x3fff));
+ break;
+ case 0x90: case 0x91: case 0x92: case 0x93:
+ /* 1001xxxx xxxxxxxx xxxxxxxx write data memory (immediate addr) from reg group 0 */
+ WWORD_DATA((op >> 4) & 0x3fff, READ_REG(0, op & 15));
+ break;
+ case 0x94: case 0x95: case 0x96: case 0x97:
+ /* 1001xxxx xxxxxxxx xxxxxxxx write data memory (immediate addr) from reg group 1 */
+ WWORD_DATA((op >> 4) & 0x3fff, READ_REG(1, op & 15));
+ break;
+ case 0x98: case 0x99: case 0x9a: case 0x9b:
+ /* 1001xxxx xxxxxxxx xxxxxxxx write data memory (immediate addr) from reg group 2 */
+ WWORD_DATA((op >> 4) & 0x3fff, READ_REG(2, op & 15));
+ break;
+ case 0x9c: case 0x9d: case 0x9e: case 0x9f:
+ /* 1001xxxx xxxxxxxx xxxxxxxx write data memory (immediate addr) from reg group 3 */
+ WWORD_DATA((op >> 4) & 0x3fff, READ_REG(3, op & 15));
+ break;
+ case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
+ case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ /* 1010xxxx xxxxxxxx xxxxxxxx data memory write (immediate) DAG1 */
+ data_write_dag1(op, (op >> 4) & 0xffff);
+ break;
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ /* 1011xxxx xxxxxxxx xxxxxxxx data memory write (immediate) DAG2 */
+ data_write_dag2(op, (op >> 4) & 0xffff);
+ break;
+ case 0xc0: case 0xc1:
+ /* 1100000x xxxxxxxx xxxxxxxx MAC to MR with data read to AX0 & pgm read to AY0 */
+ mac_op_mr(op);
+ adsp2100.core.ax0.u = data_read_dag1(op);
+ adsp2100.core.ay0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xc2: case 0xc3:
+ /* 1100001x xxxxxxxx xxxxxxxx ALU to AR with data read to AX0 & pgm read to AY0 */
+ alu_op_ar(op);
+ adsp2100.core.ax0.u = data_read_dag1(op);
+ adsp2100.core.ay0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xc4: case 0xc5:
+ /* 1100010x xxxxxxxx xxxxxxxx MAC to MR with data read to AX1 & pgm read to AY0 */
+ mac_op_mr(op);
+ adsp2100.core.ax1.u = data_read_dag1(op);
+ adsp2100.core.ay0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xc6: case 0xc7:
+ /* 1100011x xxxxxxxx xxxxxxxx ALU to AR with data read to AX1 & pgm read to AY0 */
+ alu_op_ar(op);
+ adsp2100.core.ax1.u = data_read_dag1(op);
+ adsp2100.core.ay0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xc8: case 0xc9:
+ /* 1100100x xxxxxxxx xxxxxxxx MAC to MR with data read to MX0 & pgm read to AY0 */
+ mac_op_mr(op);
+ adsp2100.core.mx0.u = data_read_dag1(op);
+ adsp2100.core.ay0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xca: case 0xcb:
+ /* 1100101x xxxxxxxx xxxxxxxx ALU to AR with data read to MX0 & pgm read to AY0 */
+ alu_op_ar(op);
+ adsp2100.core.mx0.u = data_read_dag1(op);
+ adsp2100.core.ay0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xcc: case 0xcd:
+ /* 1100110x xxxxxxxx xxxxxxxx MAC to MR with data read to MX1 & pgm read to AY0 */
+ mac_op_mr(op);
+ adsp2100.core.mx1.u = data_read_dag1(op);
+ adsp2100.core.ay0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xce: case 0xcf:
+ /* 1100111x xxxxxxxx xxxxxxxx ALU to AR with data read to MX1 & pgm read to AY0 */
+ alu_op_ar(op);
+ adsp2100.core.mx1.u = data_read_dag1(op);
+ adsp2100.core.ay0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xd0: case 0xd1:
+ /* 1101000x xxxxxxxx xxxxxxxx MAC to MR with data read to AX0 & pgm read to AY1 */
+ mac_op_mr(op);
+ adsp2100.core.ax0.u = data_read_dag1(op);
+ adsp2100.core.ay1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xd2: case 0xd3:
+ /* 1101001x xxxxxxxx xxxxxxxx ALU to AR with data read to AX0 & pgm read to AY1 */
+ alu_op_ar(op);
+ adsp2100.core.ax0.u = data_read_dag1(op);
+ adsp2100.core.ay1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xd4: case 0xd5:
+ /* 1101010x xxxxxxxx xxxxxxxx MAC to MR with data read to AX1 & pgm read to AY1 */
+ mac_op_mr(op);
+ adsp2100.core.ax1.u = data_read_dag1(op);
+ adsp2100.core.ay1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xd6: case 0xd7:
+ /* 1101011x xxxxxxxx xxxxxxxx ALU to AR with data read to AX1 & pgm read to AY1 */
+ alu_op_ar(op);
+ adsp2100.core.ax1.u = data_read_dag1(op);
+ adsp2100.core.ay1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xd8: case 0xd9:
+ /* 1101100x xxxxxxxx xxxxxxxx MAC to MR with data read to MX0 & pgm read to AY1 */
+ mac_op_mr(op);
+ adsp2100.core.mx0.u = data_read_dag1(op);
+ adsp2100.core.ay1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xda: case 0xdb:
+ /* 1101101x xxxxxxxx xxxxxxxx ALU to AR with data read to MX0 & pgm read to AY1 */
+ alu_op_ar(op);
+ adsp2100.core.mx0.u = data_read_dag1(op);
+ adsp2100.core.ay1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xdc: case 0xdd:
+ /* 1101110x xxxxxxxx xxxxxxxx MAC to MR with data read to MX1 & pgm read to AY1 */
+ mac_op_mr(op);
+ adsp2100.core.mx1.u = data_read_dag1(op);
+ adsp2100.core.ay1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xde: case 0xdf:
+ /* 1101111x xxxxxxxx xxxxxxxx ALU to AR with data read to MX1 & pgm read to AY1 */
+ alu_op_ar(op);
+ adsp2100.core.mx1.u = data_read_dag1(op);
+ adsp2100.core.ay1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xe0: case 0xe1:
+ /* 1110000x xxxxxxxx xxxxxxxx MAC to MR with data read to AX0 & pgm read to MY0 */
+ mac_op_mr(op);
+ adsp2100.core.ax0.u = data_read_dag1(op);
+ adsp2100.core.my0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xe2: case 0xe3:
+ /* 1110001x xxxxxxxx xxxxxxxx ALU to AR with data read to AX0 & pgm read to MY0 */
+ alu_op_ar(op);
+ adsp2100.core.ax0.u = data_read_dag1(op);
+ adsp2100.core.my0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xe4: case 0xe5:
+ /* 1110010x xxxxxxxx xxxxxxxx MAC to MR with data read to AX1 & pgm read to MY0 */
+ mac_op_mr(op);
+ adsp2100.core.ax1.u = data_read_dag1(op);
+ adsp2100.core.my0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xe6: case 0xe7:
+ /* 1110011x xxxxxxxx xxxxxxxx ALU to AR with data read to AX1 & pgm read to MY0 */
+ alu_op_ar(op);
+ adsp2100.core.ax1.u = data_read_dag1(op);
+ adsp2100.core.my0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xe8: case 0xe9:
+ /* 1110100x xxxxxxxx xxxxxxxx MAC to MR with data read to MX0 & pgm read to MY0 */
+ mac_op_mr(op);
+ adsp2100.core.mx0.u = data_read_dag1(op);
+ adsp2100.core.my0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xea: case 0xeb:
+ /* 1110101x xxxxxxxx xxxxxxxx ALU to AR with data read to MX0 & pgm read to MY0 */
+ alu_op_ar(op);
+ adsp2100.core.mx0.u = data_read_dag1(op);
+ adsp2100.core.my0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xec: case 0xed:
+ /* 1110110x xxxxxxxx xxxxxxxx MAC to MR with data read to MX1 & pgm read to MY0 */
+ mac_op_mr(op);
+ adsp2100.core.mx1.u = data_read_dag1(op);
+ adsp2100.core.my0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xee: case 0xef:
+ /* 1110111x xxxxxxxx xxxxxxxx ALU to AR with data read to MX1 & pgm read to MY0 */
+ alu_op_ar(op);
+ adsp2100.core.mx1.u = data_read_dag1(op);
+ adsp2100.core.my0.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xf0: case 0xf1:
+ /* 1111000x xxxxxxxx xxxxxxxx MAC to MR with data read to AX0 & pgm read to MY1 */
+ mac_op_mr(op);
+ adsp2100.core.ax0.u = data_read_dag1(op);
+ adsp2100.core.my1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xf2: case 0xf3:
+ /* 1111001x xxxxxxxx xxxxxxxx ALU to AR with data read to AX0 & pgm read to MY1 */
+ alu_op_ar(op);
+ adsp2100.core.ax0.u = data_read_dag1(op);
+ adsp2100.core.my1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xf4: case 0xf5:
+ /* 1111010x xxxxxxxx xxxxxxxx MAC to MR with data read to AX1 & pgm read to MY1 */
+ mac_op_mr(op);
+ adsp2100.core.ax1.u = data_read_dag1(op);
+ adsp2100.core.my1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xf6: case 0xf7:
+ /* 1111011x xxxxxxxx xxxxxxxx ALU to AR with data read to AX1 & pgm read to MY1 */
+ alu_op_ar(op);
+ adsp2100.core.ax1.u = data_read_dag1(op);
+ adsp2100.core.my1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xf8: case 0xf9:
+ /* 1111100x xxxxxxxx xxxxxxxx MAC to MR with data read to MX0 & pgm read to MY1 */
+ mac_op_mr(op);
+ adsp2100.core.mx0.u = data_read_dag1(op);
+ adsp2100.core.my1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xfa: case 0xfb:
+ /* 1111101x xxxxxxxx xxxxxxxx ALU to AR with data read to MX0 & pgm read to MY1 */
+ alu_op_ar(op);
+ adsp2100.core.mx0.u = data_read_dag1(op);
+ adsp2100.core.my1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xfc: case 0xfd:
+ /* 1111110x xxxxxxxx xxxxxxxx MAC to MR with data read to MX1 & pgm read to MY1 */
+ mac_op_mr(op);
+ adsp2100.core.mx1.u = data_read_dag1(op);
+ adsp2100.core.my1.u = pgm_read_dag2(op >> 4);
+ break;
+ case 0xfe: case 0xff:
+ /* 1111111x xxxxxxxx xxxxxxxx ALU to AR with data read to MX1 & pgm read to MY1 */
+ alu_op_ar(op);
+ adsp2100.core.mx1.u = data_read_dag1(op);
+ adsp2100.core.my1.u = pgm_read_dag2(op >> 4);
+ break;
+ }
+
+ adsp2100_icount--;
+
+ } while (adsp2100_icount > 0);
+
+ adsp2100_icount -= adsp2100.interrupt_cycles;
+ adsp2100.interrupt_cycles = 0;
+
+ return cycles - adsp2100_icount;
+}
+
+
+
+/***************************************************************************
+ DEBUGGER DEFINITIONS
+***************************************************************************/
+
+#ifdef MAME_DEBUG
+extern offs_t adsp2100_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void adsp21xx_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ADSP2100_PC: adsp2100.pc = info->i; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_AX0: wr_ax0(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AX1: wr_ax1(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AY0: wr_ay0(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AY1: wr_ay1(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AR: wr_ar(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AF: adsp2100.core.af.u = info->i; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_MX0: wr_mx0(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MX1: wr_mx1(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MY0: wr_my0(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MY1: wr_my1(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR0: wr_mr0(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR1: wr_mr1(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR2: wr_mr2(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MF: adsp2100.core.mf.u = info->i; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_SI: wr_si(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SE: wr_se(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SB: wr_sb(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SR0: wr_sr0(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SR1: wr_sr1(info->i); break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_AX0_SEC: adsp2100.alt.ax0.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AX1_SEC: adsp2100.alt.ax1.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AY0_SEC: adsp2100.alt.ay0.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AY1_SEC: adsp2100.alt.ay1.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AR_SEC: adsp2100.alt.ar.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AF_SEC: adsp2100.alt.af.u = info->i; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_MX0_SEC: adsp2100.alt.mx0.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MX1_SEC: adsp2100.alt.mx1.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MY0_SEC: adsp2100.alt.my0.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MY1_SEC: adsp2100.alt.my1.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR0_SEC: adsp2100.alt.mr.mrx.mr0.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR1_SEC: adsp2100.alt.mr.mrx.mr1.s = info->i; adsp2100.alt.mr.mrx.mr2.s = (INT16)info->i >> 15; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR2_SEC: adsp2100.alt.mr.mrx.mr2.s = (INT8)info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MF_SEC: adsp2100.alt.mf.u = info->i; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_SI_SEC: adsp2100.alt.si.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SE_SEC: adsp2100.alt.se.s = (INT8)info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SB_SEC: adsp2100.alt.sb.s = (INT32)(info->i << 27) >> 27; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SR0_SEC: adsp2100.alt.sr.srx.sr0.s = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SR1_SEC: adsp2100.alt.sr.srx.sr1.s = info->i; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_I0: wr_i0(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I1: wr_i1(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I2: wr_i2(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I3: wr_i3(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I4: wr_i4(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I5: wr_i5(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I6: wr_i6(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I7: wr_i7(info->i); break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_L0: wr_l0(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L1: wr_l1(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L2: wr_l2(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L3: wr_l3(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L4: wr_l4(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L5: wr_l5(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L6: wr_l6(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L7: wr_l7(info->i); break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_M0: wr_m0(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M1: wr_m1(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M2: wr_m2(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M3: wr_m3(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M4: wr_m4(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M5: wr_m5(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M6: wr_m6(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M7: wr_m7(info->i); break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_PX: wr_px(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_CNTR: adsp2100.cntr = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_ASTAT: wr_astat(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SSTAT: wr_sstat(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MSTAT: wr_mstat(info->i); break;
+
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + ADSP2100_PCSP: adsp2100.pc_sp = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_CNTRSP: adsp2100.cntr_sp = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_STATSP: adsp2100.stat_sp = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_LOOPSP: adsp2100.loop_sp = info->i; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_IMASK: wr_imask(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_ICNTL: wr_icntl(info->i); break;
+ case CPUINFO_INT_REGISTER + ADSP2100_IRQSTATE0: adsp2100.irq_state[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_IRQSTATE1: adsp2100.irq_state[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_IRQSTATE2: adsp2100.irq_state[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_IRQSTATE3: adsp2100.irq_state[3] = info->i; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_FLAGIN: adsp2100.flagin = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_FLAGOUT: adsp2100.flagout = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_FL0: adsp2100.fl0 = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_FL1: adsp2100.fl1 = info->i; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_FL2: adsp2100.fl2 = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void adsp21xx_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(adsp2100); break;
+ case CPUINFO_INT_INPUT_LINES: /* set per CPU */ break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 14; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -2; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 14; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = adsp2100.ppc; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ADSP2100_PC: info->i = adsp2100.pc; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_AX0: info->i = adsp2100.core.ax0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AX1: info->i = adsp2100.core.ax1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AY0: info->i = adsp2100.core.ay0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AY1: info->i = adsp2100.core.ay1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AR: info->i = adsp2100.core.ar.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AF: info->i = adsp2100.core.af.u; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_MX0: info->i = adsp2100.core.mx0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MX1: info->i = adsp2100.core.mx1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MY0: info->i = adsp2100.core.my0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MY1: info->i = adsp2100.core.my1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR0: info->i = adsp2100.core.mr.mrx.mr0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR1: info->i = adsp2100.core.mr.mrx.mr1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR2: info->i = adsp2100.core.mr.mrx.mr2.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MF: info->i = adsp2100.core.mf.u; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_SI: info->i = adsp2100.core.si.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SE: info->i = adsp2100.core.se.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SB: info->i = adsp2100.core.sb.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SR0: info->i = adsp2100.core.sr.srx.sr0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SR1: info->i = adsp2100.core.sr.srx.sr1.u; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_AX0_SEC: info->i = adsp2100.alt.ax0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AX1_SEC: info->i = adsp2100.alt.ax1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AY0_SEC: info->i = adsp2100.alt.ay0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AY1_SEC: info->i = adsp2100.alt.ay1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AR_SEC: info->i = adsp2100.alt.ar.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_AF_SEC: info->i = adsp2100.alt.af.u; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_MX0_SEC: info->i = adsp2100.alt.mx0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MX1_SEC: info->i = adsp2100.alt.mx1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MY0_SEC: info->i = adsp2100.alt.my0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MY1_SEC: info->i = adsp2100.alt.my1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR0_SEC: info->i = adsp2100.alt.mr.mrx.mr0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR1_SEC: info->i = adsp2100.alt.mr.mrx.mr1.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MR2_SEC: info->i = adsp2100.alt.mr.mrx.mr2.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MF_SEC: info->i = adsp2100.alt.mf.u; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_SI_SEC: info->i = adsp2100.alt.si.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SE_SEC: info->i = adsp2100.alt.se.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SB_SEC: info->i = adsp2100.alt.sb.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SR0_SEC: info->i = adsp2100.alt.sr.srx.sr0.u; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SR1_SEC: info->i = adsp2100.alt.sr.srx.sr1.u; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_I0: info->i = adsp2100.i[0]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I1: info->i = adsp2100.i[1]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I2: info->i = adsp2100.i[2]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I3: info->i = adsp2100.i[3]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I4: info->i = adsp2100.i[4]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I5: info->i = adsp2100.i[5]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I6: info->i = adsp2100.i[6]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_I7: info->i = adsp2100.i[7]; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_L0: info->i = adsp2100.l[0]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L1: info->i = adsp2100.l[1]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L2: info->i = adsp2100.l[2]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L3: info->i = adsp2100.l[3]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L4: info->i = adsp2100.l[4]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L5: info->i = adsp2100.l[5]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L6: info->i = adsp2100.l[6]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_L7: info->i = adsp2100.l[7]; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_M0: info->i = adsp2100.m[0]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M1: info->i = adsp2100.m[1]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M2: info->i = adsp2100.m[2]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M3: info->i = adsp2100.m[3]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M4: info->i = adsp2100.m[4]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M5: info->i = adsp2100.m[5]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M6: info->i = adsp2100.m[6]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_M7: info->i = adsp2100.m[7]; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_PX: info->i = adsp2100.px; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_CNTR: info->i = adsp2100.cntr; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_ASTAT: info->i = adsp2100.astat; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_SSTAT: info->i = adsp2100.sstat; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_MSTAT: info->i = adsp2100.mstat; break;
+
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + ADSP2100_PCSP: info->i = adsp2100.pc_sp; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_CNTRSP: info->i = adsp2100.cntr_sp; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_STATSP: info->i = adsp2100.stat_sp; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_LOOPSP: info->i = adsp2100.loop_sp; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_IMASK: info->i = adsp2100.imask; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_ICNTL: info->i = adsp2100.icntl; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_IRQSTATE0: info->i = adsp2100.irq_state[0]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_IRQSTATE1: info->i = adsp2100.irq_state[1]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_IRQSTATE2: info->i = adsp2100.irq_state[2]; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_IRQSTATE3: info->i = adsp2100.irq_state[3]; break;
+
+ case CPUINFO_INT_REGISTER + ADSP2100_FLAGIN: info->i = adsp2100.flagin; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_FLAGOUT: info->i = adsp2100.flagout; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_FL0: info->i = adsp2100.fl0; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_FL1: info->i = adsp2100.fl1; break;
+ case CPUINFO_INT_REGISTER + ADSP2100_FL2: info->i = adsp2100.fl2; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: /* set per CPU */ break;
+ case CPUINFO_PTR_SET_CONTEXT: /* set per CPU */ break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = adsp2100_get_context; break;
+ case CPUINFO_PTR_INIT: info->init = adsp2100_init; break;
+ case CPUINFO_PTR_RESET: info->reset = adsp2100_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = adsp2100_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = adsp2100_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = adsp2100_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &adsp2100_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: /* set per CPU */ break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "ADSP21xx"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "2.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) Aaron Giles, 1999-2004"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ adsp2100.astat & 0x80 ? 'X':'.',
+ adsp2100.astat & 0x40 ? 'M':'.',
+ adsp2100.astat & 0x20 ? 'Q':'.',
+ adsp2100.astat & 0x10 ? 'S':'.',
+ adsp2100.astat & 0x08 ? 'C':'.',
+ adsp2100.astat & 0x04 ? 'V':'.',
+ adsp2100.astat & 0x02 ? 'N':'.',
+ adsp2100.astat & 0x01 ? 'Z':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_PC: sprintf(info->s, "PC: %04X", adsp2100.pc); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_AX0: sprintf(info->s, "AX0: %04X", adsp2100.core.ax0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AX1: sprintf(info->s, "AX1: %04X", adsp2100.core.ax1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AY0: sprintf(info->s, "AY0: %04X", adsp2100.core.ay0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AY1: sprintf(info->s, "AY1: %04X", adsp2100.core.ay1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AR: sprintf(info->s, "AR: %04X", adsp2100.core.ar.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AF: sprintf(info->s, "AF: %04X", adsp2100.core.af.u); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_MX0: sprintf(info->s, "MX0: %04X", adsp2100.core.mx0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MX1: sprintf(info->s, "MX1: %04X", adsp2100.core.mx1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MY0: sprintf(info->s, "MY0: %04X", adsp2100.core.my0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MY1: sprintf(info->s, "MY1: %04X", adsp2100.core.my1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MR0: sprintf(info->s, "MR0: %04X", adsp2100.core.mr.mrx.mr0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MR1: sprintf(info->s, "MR1: %04X", adsp2100.core.mr.mrx.mr1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MR2: sprintf(info->s, "MR2: %02X", adsp2100.core.mr.mrx.mr2.u & 0x00ff); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MF: sprintf(info->s, "MF: %04X", adsp2100.core.mf.u); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_SI: sprintf(info->s, "SI: %04X", adsp2100.core.si.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_SE: sprintf(info->s, "SE: %02X ", adsp2100.core.se.u & 0x00ff); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_SB: sprintf(info->s, "SB: %02X ", adsp2100.core.sb.u & 0x001f); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_SR0: sprintf(info->s, "SR0: %04X", adsp2100.core.sr.srx.sr0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_SR1: sprintf(info->s, "SR1: %04X", adsp2100.core.sr.srx.sr1.u); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_AX0_SEC: sprintf(info->s, "AX0_SEC: %04X", adsp2100.alt.ax0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AX1_SEC: sprintf(info->s, "AX1_SEC: %04X", adsp2100.alt.ax1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AY0_SEC: sprintf(info->s, "AY0_SEC: %04X", adsp2100.alt.ay0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AY1_SEC: sprintf(info->s, "AY1_SEC: %04X", adsp2100.alt.ay1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AR_SEC: sprintf(info->s, "AR_SEC: %04X", adsp2100.alt.ar.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_AF_SEC: sprintf(info->s, "AF_SEC: %04X", adsp2100.alt.af.u); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_MX0_SEC: sprintf(info->s, "MX0_SEC: %04X", adsp2100.alt.mx0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MX1_SEC: sprintf(info->s, "MX1_SEC: %04X", adsp2100.alt.mx1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MY0_SEC: sprintf(info->s, "MY0_SEC: %04X", adsp2100.alt.my0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MY1_SEC: sprintf(info->s, "MY1_SEC: %04X", adsp2100.alt.my1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MR0_SEC: sprintf(info->s, "MR0_SEC: %04X", adsp2100.alt.mr.mrx.mr0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MR1_SEC: sprintf(info->s, "MR1_SEC: %04X", adsp2100.alt.mr.mrx.mr1.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MR2_SEC: sprintf(info->s, "MR2_SEC: %02X", adsp2100.alt.mr.mrx.mr2.u & 0x00ff); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MF_SEC: sprintf(info->s, "MF_SEC: %04X", adsp2100.alt.mf.u); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_SI_SEC: sprintf(info->s, "SI_SEC: %04X", adsp2100.alt.si.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_SE_SEC: sprintf(info->s, "SE_SEC: %02X ", adsp2100.alt.se.u & 0x00ff); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_SB_SEC: sprintf(info->s, "SB_SEC: %02X ", adsp2100.alt.sb.u & 0x001f); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_SR0_SEC: sprintf(info->s, "SR0_SEC: %04X", adsp2100.alt.sr.srx.sr0.u); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_SR1_SEC: sprintf(info->s, "SR1_SEC: %04X", adsp2100.alt.sr.srx.sr1.u); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_I0: sprintf(info->s, "I0: %04X", adsp2100.i[0]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_I1: sprintf(info->s, "I1: %04X", adsp2100.i[1]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_I2: sprintf(info->s, "I2: %04X", adsp2100.i[2]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_I3: sprintf(info->s, "I3: %04X", adsp2100.i[3]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_I4: sprintf(info->s, "I4: %04X", adsp2100.i[4]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_I5: sprintf(info->s, "I5: %04X", adsp2100.i[5]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_I6: sprintf(info->s, "I6: %04X", adsp2100.i[6]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_I7: sprintf(info->s, "I7: %04X", adsp2100.i[7]); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_L0: sprintf(info->s, "L0: %04X", adsp2100.l[0]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_L1: sprintf(info->s, "L1: %04X", adsp2100.l[1]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_L2: sprintf(info->s, "L2: %04X", adsp2100.l[2]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_L3: sprintf(info->s, "L3: %04X", adsp2100.l[3]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_L4: sprintf(info->s, "L4: %04X", adsp2100.l[4]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_L5: sprintf(info->s, "L5: %04X", adsp2100.l[5]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_L6: sprintf(info->s, "L6: %04X", adsp2100.l[6]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_L7: sprintf(info->s, "L7: %04X", adsp2100.l[7]); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_M0: sprintf(info->s, "M0: %04X", adsp2100.m[0]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_M1: sprintf(info->s, "M1: %04X", adsp2100.m[1]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_M2: sprintf(info->s, "M2: %04X", adsp2100.m[2]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_M3: sprintf(info->s, "M3: %04X", adsp2100.m[3]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_M4: sprintf(info->s, "M4: %04X", adsp2100.m[4]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_M5: sprintf(info->s, "M5: %04X", adsp2100.m[5]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_M6: sprintf(info->s, "M6: %04X", adsp2100.m[6]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_M7: sprintf(info->s, "M7: %04X", adsp2100.m[7]); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_PX: sprintf(info->s, "PX: %02X ", adsp2100.px); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_CNTR: sprintf(info->s, "CNTR:%04X", adsp2100.cntr); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_ASTAT: sprintf(info->s, "ASTA:%02X ", adsp2100.astat); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_SSTAT: sprintf(info->s, "SSTA:%02X ", adsp2100.sstat); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_MSTAT: sprintf(info->s, "MSTA:%02X ", adsp2100.mstat); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_PCSP: sprintf(info->s, "PCSP:%02X ", adsp2100.pc_sp); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_CNTRSP: sprintf(info->s, "CTSP:%01X ", adsp2100.cntr_sp); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_STATSP: sprintf(info->s, "STSP:%01X ", adsp2100.stat_sp); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_LOOPSP: sprintf(info->s, "LPSP:%01X ", adsp2100.loop_sp); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_IMASK: sprintf(info->s, "IMSK:%03X ", adsp2100.imask); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_ICNTL: sprintf(info->s, "ICTL:%02X ", adsp2100.icntl); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_IRQSTATE0: sprintf(info->s, "IRQ0:%X ", adsp2100.irq_state[0]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_IRQSTATE1: sprintf(info->s, "IRQ1:%X ", adsp2100.irq_state[1]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_IRQSTATE2: sprintf(info->s, "IRQ2:%X ", adsp2100.irq_state[2]); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_IRQSTATE3: sprintf(info->s, "IRQ3:%X ", adsp2100.irq_state[3]); break;
+
+ case CPUINFO_STR_REGISTER + ADSP2100_FLAGIN: sprintf(info->s, "FI: %X ", adsp2100.flagin); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_FLAGOUT: sprintf(info->s, "FO: %X ", adsp2100.flagout); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_FL0: sprintf(info->s, "FL0: %X ", adsp2100.fl0); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_FL1: sprintf(info->s, "FL1: %X ", adsp2100.fl1); break;
+ case CPUINFO_STR_REGISTER + ADSP2100_FL2: sprintf(info->s, "FL2: %X ", adsp2100.fl2); break;
+ }
+}
+
+void adsp21xx_load_boot_data(UINT8 *srcdata, UINT32 *dstdata)
+{
+ /* see how many words we need to copy */
+ int pagelen = (srcdata[(3)] + 1) * 8;
+ int i;
+ for (i = 0; i < pagelen; i++)
+ {
+ UINT32 opcode = (srcdata[(i*4+0)] << 16) | (srcdata[(i*4+1)] << 8) | srcdata[(i*4+2)];
+ dstdata[i] = opcode;
+ }
+}
+
+#if (HAS_ADSP2100)
+/**************************************************************************
+ * ADSP2100 section
+ **************************************************************************/
+
+static void adsp2100_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + ADSP2100_IRQ0: set_irq_line(ADSP2100_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2100_IRQ1: set_irq_line(ADSP2100_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2100_IRQ2: set_irq_line(ADSP2100_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2100_IRQ3: set_irq_line(ADSP2100_IRQ3, info->i); break;
+
+ default:
+ adsp21xx_set_info(state, info);
+ break;
+ }
+}
+
+void adsp2100_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 4; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2100_IRQ0: info->i = adsp2100.irq_state[ADSP2100_IRQ0]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2100_IRQ1: info->i = adsp2100.irq_state[ADSP2100_IRQ1]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2100_IRQ2: info->i = adsp2100.irq_state[ADSP2100_IRQ2]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2100_IRQ3: info->i = adsp2100.irq_state[ADSP2100_IRQ3]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = adsp2100_set_info; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = adsp2100_set_context; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ADSP2100"); break;
+
+ default:
+ adsp21xx_get_info(state, info);
+ break;
+ }
+}
+#endif
+
+
+#if (HAS_ADSP2101)
+/**************************************************************************
+ * ADSP2101 section
+ **************************************************************************/
+
+static void adsp2101_reset(void)
+{
+ set_core_2101();
+ adsp2100_reset();
+}
+
+static void adsp2101_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ {
+ adsp2100 = *(adsp2100_Regs *)src;
+ CHANGEPC();
+ }
+
+ /* reset the chip type */
+ set_core_2101();
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+static void adsp2101_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_IRQ0: set_irq_line(ADSP2101_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_IRQ1: set_irq_line(ADSP2101_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_IRQ2: set_irq_line(ADSP2101_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_SPORT0_RX:set_irq_line(ADSP2101_SPORT0_RX, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_SPORT0_TX:set_irq_line(ADSP2101_SPORT0_TX, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_TIMER: set_irq_line(ADSP2101_TIMER, info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: adsp2100.sport_rx_callback = (RX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: adsp2100.sport_tx_callback = (TX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: adsp2100.timer_callback = (ADSP2100_TIMER_CALLBACK)info->f; break;
+
+ default:
+ adsp21xx_set_info(state, info);
+ break;
+ }
+}
+
+void adsp2101_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_IRQ0: info->i = adsp2100.irq_state[ADSP2101_IRQ0]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_IRQ1: info->i = adsp2100.irq_state[ADSP2101_IRQ1]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_IRQ2: info->i = adsp2100.irq_state[ADSP2101_IRQ2]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_SPORT0_RX:info->i = adsp2100.irq_state[ADSP2101_SPORT0_RX]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_SPORT0_TX:info->i = adsp2100.irq_state[ADSP2101_SPORT0_TX]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2101_TIMER: info->i = adsp2100.irq_state[ADSP2101_TIMER]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = adsp2101_set_info; break;
+ case CPUINFO_PTR_RESET: info->reset = adsp2101_reset; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = adsp2101_set_context; break;
+
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: info->f = (genf *)adsp2100.sport_rx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: info->f = (genf *)adsp2100.sport_tx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: info->f = (genf *)adsp2100.timer_callback; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ADSP2101"); break;
+
+ default:
+ adsp21xx_get_info(state, info);
+ break;
+ }
+}
+#endif
+
+
+#if (HAS_ADSP2104)
+/**************************************************************************
+ * ADSP2104 section
+ **************************************************************************/
+
+static void adsp2104_reset(void)
+{
+ set_core_2104();
+ adsp2100_reset();
+}
+
+static void adsp2104_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ {
+ adsp2100 = *(adsp2100_Regs *)src;
+ CHANGEPC();
+ }
+
+ /* reset the chip type */
+ set_core_2104();
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+void adsp2104_load_boot_data(UINT8 *srcdata, UINT32 *dstdata)
+{
+ adsp21xx_load_boot_data(srcdata, dstdata);
+}
+
+static void adsp2104_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_IRQ0: set_irq_line(ADSP2104_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_IRQ1: set_irq_line(ADSP2104_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_IRQ2: set_irq_line(ADSP2104_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_SPORT0_RX:set_irq_line(ADSP2104_SPORT0_RX, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_SPORT0_TX:set_irq_line(ADSP2104_SPORT0_TX, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_TIMER: set_irq_line(ADSP2104_TIMER, info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: adsp2100.sport_rx_callback = (RX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: adsp2100.sport_tx_callback = (TX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: adsp2100.timer_callback = (ADSP2100_TIMER_CALLBACK)info->f; break;
+
+ default:
+ adsp21xx_set_info(state, info);
+ break;
+ }
+}
+
+void adsp2104_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_IRQ0: info->i = adsp2100.irq_state[ADSP2104_IRQ0]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_IRQ1: info->i = adsp2100.irq_state[ADSP2104_IRQ1]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_IRQ2: info->i = adsp2100.irq_state[ADSP2104_IRQ2]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_SPORT0_RX:info->i = adsp2100.irq_state[ADSP2104_SPORT0_RX]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_SPORT0_TX:info->i = adsp2100.irq_state[ADSP2104_SPORT0_TX]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2104_TIMER: info->i = adsp2100.irq_state[ADSP2104_TIMER]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = adsp2104_set_info; break;
+ case CPUINFO_PTR_RESET: info->reset = adsp2104_reset; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = adsp2104_set_context; break;
+
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: info->f = (genf *)adsp2100.sport_rx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: info->f = (genf *)adsp2100.sport_tx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: info->f = (genf *)adsp2100.timer_callback; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ADSP2104"); break;
+
+ default:
+ adsp21xx_get_info(state, info);
+ break;
+ }
+}
+#endif
+
+
+#if (HAS_ADSP2105)
+/**************************************************************************
+ * ADSP2105 section
+ **************************************************************************/
+
+static void adsp2105_reset(void)
+{
+ set_core_2105();
+ adsp2100_reset();
+}
+
+static void adsp2105_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ {
+ adsp2100 = *(adsp2100_Regs *)src;
+ CHANGEPC();
+ }
+
+ /* reset the chip type */
+ set_core_2105();
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+void adsp2105_load_boot_data(UINT8 *srcdata, UINT32 *dstdata)
+{
+ adsp21xx_load_boot_data(srcdata, dstdata);
+}
+
+static void adsp2105_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + ADSP2105_IRQ0: set_irq_line(ADSP2105_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2105_IRQ1: set_irq_line(ADSP2105_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2105_IRQ2: set_irq_line(ADSP2105_IRQ2, info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: adsp2100.sport_rx_callback = (RX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: adsp2100.sport_tx_callback = (TX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: adsp2100.timer_callback = (ADSP2100_TIMER_CALLBACK)info->f; break;
+
+ default:
+ adsp21xx_set_info(state, info);
+ break;
+ }
+}
+
+void adsp2105_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2105_IRQ0: info->i = adsp2100.irq_state[ADSP2105_IRQ0]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2105_IRQ1: info->i = adsp2100.irq_state[ADSP2105_IRQ1]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2105_IRQ2: info->i = adsp2100.irq_state[ADSP2105_IRQ2]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = adsp2105_set_info; break;
+ case CPUINFO_PTR_RESET: info->reset = adsp2105_reset; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = adsp2105_set_context; break;
+
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: info->f = (genf *)adsp2100.sport_rx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: info->f = (genf *)adsp2100.sport_tx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: info->f = (genf *)adsp2100.timer_callback; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ADSP2105"); break;
+
+ default:
+ adsp21xx_get_info(state, info);
+ break;
+ }
+}
+#endif
+
+
+#if (HAS_ADSP2115)
+/**************************************************************************
+ * ADSP2115 section
+ **************************************************************************/
+
+static void adsp2115_reset(void)
+{
+ set_core_2115();
+ adsp2100_reset();
+}
+
+static void adsp2115_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ {
+ adsp2100 = *(adsp2100_Regs *)src;
+ CHANGEPC();
+ }
+
+ /* reset the chip type */
+ set_core_2115();
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+void adsp2115_load_boot_data(UINT8 *srcdata, UINT32 *dstdata)
+{
+ adsp21xx_load_boot_data(srcdata, dstdata);
+}
+
+static void adsp2115_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_IRQ0: set_irq_line(ADSP2115_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_IRQ1: set_irq_line(ADSP2115_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_IRQ2: set_irq_line(ADSP2115_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_SPORT0_RX:set_irq_line(ADSP2115_SPORT0_RX, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_SPORT0_TX:set_irq_line(ADSP2115_SPORT0_TX, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_TIMER: set_irq_line(ADSP2115_TIMER, info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: adsp2100.sport_rx_callback = (RX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: adsp2100.sport_tx_callback = (TX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: adsp2100.timer_callback = (ADSP2100_TIMER_CALLBACK)info->f; break;
+
+ default:
+ adsp21xx_set_info(state, info);
+ break;
+ }
+}
+
+void adsp2115_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 4; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_IRQ0: info->i = adsp2100.irq_state[ADSP2115_IRQ0]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_IRQ1: info->i = adsp2100.irq_state[ADSP2115_IRQ1]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_IRQ2: info->i = adsp2100.irq_state[ADSP2115_IRQ2]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_SPORT0_RX:info->i = adsp2100.irq_state[ADSP2115_SPORT0_RX]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_SPORT0_TX:info->i = adsp2100.irq_state[ADSP2115_SPORT0_TX]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2115_TIMER: info->i = adsp2100.irq_state[ADSP2115_TIMER]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = adsp2115_set_info; break;
+ case CPUINFO_PTR_RESET: info->reset = adsp2115_reset; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = adsp2115_set_context; break;
+
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: info->f = (genf *)adsp2100.sport_rx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: info->f = (genf *)adsp2100.sport_tx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: info->f = (genf *)adsp2100.timer_callback; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ADSP2115"); break;
+
+ default:
+ adsp21xx_get_info(state, info);
+ break;
+ }
+}
+#endif
+
+
+#if (HAS_ADSP2181)
+/**************************************************************************
+ * ADSP2181 section
+ **************************************************************************/
+
+static void adsp2181_reset(void)
+{
+ set_core_2181();
+ adsp2100_reset();
+}
+
+static void adsp2181_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ {
+ adsp2100 = *(adsp2100_Regs *)src;
+ CHANGEPC();
+ }
+
+ /* reset the chip type */
+ set_core_2181();
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+void adsp2181_load_boot_data(UINT8 *srcdata, UINT32 *dstdata)
+{
+ adsp21xx_load_boot_data(srcdata, dstdata);
+}
+
+static void adsp2181_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQ0: set_irq_line(ADSP2181_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQ1: set_irq_line(ADSP2181_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQ2: set_irq_line(ADSP2181_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_SPORT0_RX:set_irq_line(ADSP2181_SPORT0_RX, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_SPORT0_TX:set_irq_line(ADSP2181_SPORT0_TX, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_TIMER: set_irq_line(ADSP2181_TIMER, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQE: set_irq_line(ADSP2181_IRQE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQL1: set_irq_line(ADSP2181_IRQL1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQL2: set_irq_line(ADSP2181_IRQL2, info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: adsp2100.sport_rx_callback = (RX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: adsp2100.sport_tx_callback = (TX_CALLBACK)info->f; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: adsp2100.timer_callback = (ADSP2100_TIMER_CALLBACK)info->f; break;
+
+ default:
+ adsp21xx_set_info(state, info);
+ break;
+ }
+}
+
+void adsp2181_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 4; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQ0: info->i = adsp2100.irq_state[ADSP2181_IRQ0]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQ1: info->i = adsp2100.irq_state[ADSP2181_IRQ1]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQ2: info->i = adsp2100.irq_state[ADSP2181_IRQ2]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_SPORT0_RX:info->i = adsp2100.irq_state[ADSP2181_SPORT0_RX]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_SPORT0_TX:info->i = adsp2100.irq_state[ADSP2181_SPORT0_TX]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_TIMER: info->i = adsp2100.irq_state[ADSP2181_TIMER]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQE: info->i = adsp2100.irq_state[ADSP2181_IRQE]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQL1: info->i = adsp2100.irq_state[ADSP2181_IRQL1]; break;
+ case CPUINFO_INT_INPUT_STATE + ADSP2181_IRQL2: info->i = adsp2100.irq_state[ADSP2181_IRQL2]; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 11; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = -1; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = adsp2181_set_info; break;
+ case CPUINFO_PTR_RESET: info->reset = adsp2181_reset; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = adsp2181_set_context; break;
+
+ case CPUINFO_PTR_ADSP2100_RX_HANDLER: info->f = (genf *)adsp2100.sport_rx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TX_HANDLER: info->f = (genf *)adsp2100.sport_tx_callback; break;
+ case CPUINFO_PTR_ADSP2100_TIMER_HANDLER: info->f = (genf *)adsp2100.timer_callback; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ADSP2181"); break;
+
+ default:
+ adsp21xx_get_info(state, info);
+ break;
+ }
+}
+
+void adsp2181_idma_addr_w(UINT16 data)
+{
+ adsp2100.idma_addr = data;
+ adsp2100.idma_offs = 0;
+}
+
+UINT16 adsp2181_idma_addr_r(void)
+{
+ return adsp2100.idma_addr;
+}
+
+void adsp2181_idma_data_w(UINT16 data)
+{
+ /* program memory? */
+ if (!(adsp2100.idma_addr & 0x4000))
+ {
+ /* upper 16 bits */
+ if (adsp2100.idma_offs == 0)
+ {
+ adsp2100.idma_cache = data;
+ adsp2100.idma_offs = 1;
+ }
+
+ /* lower 8 bits */
+ else
+ {
+ WWORD_PGM(adsp2100.idma_addr++ & 0x3fff, (adsp2100.idma_cache << 8) | (data & 0xff));
+ adsp2100.idma_offs = 0;
+ }
+ }
+
+ /* data memory */
+ else
+ WWORD_DATA(adsp2100.idma_addr++ & 0x3fff, data);
+}
+
+UINT16 adsp2181_idma_data_r(void)
+{
+ UINT16 result = 0xffff;
+
+ /* program memory? */
+ if (!(adsp2100.idma_addr & 0x4000))
+ {
+ /* upper 16 bits */
+ if (adsp2100.idma_offs == 0)
+ {
+ result = RWORD_PGM(adsp2100.idma_addr & 0x3fff) >> 8;
+ adsp2100.idma_offs = 1;
+ }
+
+ /* lower 8 bits */
+ else
+ {
+ result = RWORD_PGM(adsp2100.idma_addr++ & 0x3fff) & 0xff;
+ adsp2100.idma_offs = 0;
+ }
+ }
+
+ /* data memory */
+ else
+ result = RWORD_DATA(adsp2100.idma_addr++ & 0x3fff);
+
+ return result;
+}
+
+#endif
diff --git a/src/emu/cpu/adsp2100/adsp2100.h b/src/emu/cpu/adsp2100/adsp2100.h
new file mode 100644
index 00000000000..e490388b43d
--- /dev/null
+++ b/src/emu/cpu/adsp2100/adsp2100.h
@@ -0,0 +1,164 @@
+/***************************************************************************
+
+ ADSP2100.h
+ Interface file for the portable Analog ADSP-2100 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#ifndef _ADSP2100_H
+#define _ADSP2100_H
+
+#include "cpuintrf.h"
+
+
+/***************************************************************************
+ GLOBAL CONSTANTS
+***************************************************************************/
+
+/* transmit and receive data callbacks types */
+typedef INT32 (*RX_CALLBACK)(int port);
+typedef void (*TX_CALLBACK)(int port, INT32 data);
+typedef void (*ADSP2100_TIMER_CALLBACK)(int enable);
+
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ ADSP2100_PC=1,
+ ADSP2100_AX0, ADSP2100_AX1, ADSP2100_AY0, ADSP2100_AY1, ADSP2100_AR, ADSP2100_AF,
+ ADSP2100_MX0, ADSP2100_MX1, ADSP2100_MY0, ADSP2100_MY1, ADSP2100_MR0, ADSP2100_MR1, ADSP2100_MR2, ADSP2100_MF,
+ ADSP2100_SI, ADSP2100_SE, ADSP2100_SB, ADSP2100_SR0, ADSP2100_SR1,
+ ADSP2100_I0, ADSP2100_I1, ADSP2100_I2, ADSP2100_I3, ADSP2100_I4, ADSP2100_I5, ADSP2100_I6, ADSP2100_I7,
+ ADSP2100_L0, ADSP2100_L1, ADSP2100_L2, ADSP2100_L3, ADSP2100_L4, ADSP2100_L5, ADSP2100_L6, ADSP2100_L7,
+ ADSP2100_M0, ADSP2100_M1, ADSP2100_M2, ADSP2100_M3, ADSP2100_M4, ADSP2100_M5, ADSP2100_M6, ADSP2100_M7,
+ ADSP2100_PX, ADSP2100_CNTR, ADSP2100_ASTAT, ADSP2100_SSTAT, ADSP2100_MSTAT,
+ ADSP2100_PCSP, ADSP2100_CNTRSP, ADSP2100_STATSP, ADSP2100_LOOPSP,
+ ADSP2100_IMASK, ADSP2100_ICNTL, ADSP2100_IRQSTATE0, ADSP2100_IRQSTATE1, ADSP2100_IRQSTATE2, ADSP2100_IRQSTATE3,
+ ADSP2100_FLAGIN, ADSP2100_FLAGOUT, ADSP2100_FL0, ADSP2100_FL1, ADSP2100_FL2,
+ ADSP2100_AX0_SEC, ADSP2100_AX1_SEC, ADSP2100_AY0_SEC, ADSP2100_AY1_SEC, ADSP2100_AR_SEC, ADSP2100_AF_SEC,
+ ADSP2100_MX0_SEC, ADSP2100_MX1_SEC, ADSP2100_MY0_SEC, ADSP2100_MY1_SEC, ADSP2100_MR0_SEC, ADSP2100_MR1_SEC, ADSP2100_MR2_SEC, ADSP2100_MF_SEC,
+ ADSP2100_SI_SEC, ADSP2100_SE_SEC, ADSP2100_SB_SEC, ADSP2100_SR0_SEC, ADSP2100_SR1_SEC
+};
+
+enum
+{
+ CPUINFO_PTR_ADSP2100_RX_HANDLER = CPUINFO_PTR_CPU_SPECIFIC,
+ CPUINFO_PTR_ADSP2100_TX_HANDLER,
+ CPUINFO_PTR_ADSP2100_TIMER_HANDLER
+};
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+#define ADSP2100_IRQ0 0 /* IRQ0 */
+#define ADSP2100_SPORT1_RX 0 /* SPORT1 receive IRQ */
+#define ADSP2100_IRQ1 1 /* IRQ1 */
+#define ADSP2100_SPORT1_TX 1 /* SPORT1 transmit IRQ */
+#define ADSP2100_IRQ2 2 /* IRQ2 */
+#define ADSP2100_IRQ3 3 /* IRQ3 */
+
+#if (HAS_ADSP2100)
+extern void adsp2100_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/**************************************************************************
+ * ADSP2101 section
+ **************************************************************************/
+
+#define ADSP2101_IRQ0 0 /* IRQ0 */
+#define ADSP2101_SPORT1_RX 0 /* SPORT1 receive IRQ */
+#define ADSP2101_IRQ1 1 /* IRQ1 */
+#define ADSP2101_SPORT1_TX 1 /* SPORT1 transmit IRQ */
+#define ADSP2101_IRQ2 2 /* IRQ2 */
+#define ADSP2101_SPORT0_RX 3 /* SPORT0 receive IRQ */
+#define ADSP2101_SPORT0_TX 4 /* SPORT0 transmit IRQ */
+#define ADSP2101_TIMER 5 /* internal timer IRQ */
+
+#if (HAS_ADSP2101)
+extern void adsp2101_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_ADSP2104)
+/**************************************************************************
+ * ADSP2104 section
+ **************************************************************************/
+
+#define ADSP2104_IRQ0 0 /* IRQ0 */
+#define ADSP2104_SPORT1_RX 0 /* SPORT1 receive IRQ */
+#define ADSP2104_IRQ1 1 /* IRQ1 */
+#define ADSP2104_SPORT1_TX 1 /* SPORT1 transmit IRQ */
+#define ADSP2104_IRQ2 2 /* IRQ2 */
+#define ADSP2104_SPORT0_RX 3 /* SPORT0 receive IRQ */
+#define ADSP2104_SPORT0_TX 4 /* SPORT0 transmit IRQ */
+#define ADSP2104_TIMER 5 /* internal timer IRQ */
+
+extern void adsp2104_get_info(UINT32 state, cpuinfo *info);
+extern void adsp2104_load_boot_data(UINT8 *srcdata, UINT32 *dstdata);
+#endif
+
+#if (HAS_ADSP2105)
+/**************************************************************************
+ * ADSP2105 section
+ **************************************************************************/
+
+#define ADSP2105_IRQ0 0 /* IRQ0 */
+#define ADSP2105_SPORT1_RX 0 /* SPORT1 receive IRQ */
+#define ADSP2105_IRQ1 1 /* IRQ1 */
+#define ADSP2105_SPORT1_TX 1 /* SPORT1 transmit IRQ */
+#define ADSP2105_IRQ2 2 /* IRQ2 */
+#define ADSP2105_TIMER 5 /* internal timer IRQ */
+
+extern void adsp2105_get_info(UINT32 state, cpuinfo *info);
+extern void adsp2105_load_boot_data(UINT8 *srcdata, UINT32 *dstdata);
+#endif
+
+#if (HAS_ADSP2115)
+/**************************************************************************
+ * ADSP2115 section
+ **************************************************************************/
+
+#define ADSP2115_IRQ0 0 /* IRQ0 */
+#define ADSP2115_SPORT1_RX 0 /* SPORT1 receive IRQ */
+#define ADSP2115_IRQ1 1 /* IRQ1 */
+#define ADSP2115_SPORT1_TX 1 /* SPORT1 transmit IRQ */
+#define ADSP2115_IRQ2 2 /* IRQ2 */
+#define ADSP2115_SPORT0_RX 3 /* SPORT0 receive IRQ */
+#define ADSP2115_SPORT0_TX 4 /* SPORT0 transmit IRQ */
+#define ADSP2115_TIMER 5 /* internal timer IRQ */
+
+extern void adsp2115_get_info(UINT32 state, cpuinfo *info);
+extern void adsp2115_load_boot_data(UINT8 *srcdata, UINT32 *dstdata);
+#endif
+
+#if (HAS_ADSP2181)
+/**************************************************************************
+ * ADSP2181 section
+ **************************************************************************/
+
+#define ADSP2181_IRQ0 0 /* IRQ0 */
+#define ADSP2181_SPORT1_RX 0 /* SPORT1 receive IRQ */
+#define ADSP2181_IRQ1 1 /* IRQ1 */
+#define ADSP2181_SPORT1_TX 1 /* SPORT1 transmit IRQ */
+#define ADSP2181_IRQ2 2 /* IRQ2 */
+#define ADSP2181_SPORT0_RX 3 /* SPORT0 receive IRQ */
+#define ADSP2181_SPORT0_TX 4 /* SPORT0 transmit IRQ */
+#define ADSP2181_TIMER 5 /* internal timer IRQ */
+#define ADSP2181_IRQE 6 /* IRQE */
+#define ADSP2181_IRQL1 7 /* IRQL1 */
+#define ADSP2181_IRQL2 8 /* IRQL2 */
+
+extern void adsp2181_get_info(UINT32 state, cpuinfo *info);
+extern void adsp2181_load_boot_data(UINT8 *srcdata, UINT32 *dstdata);
+extern void adsp2181_idma_addr_w(UINT16 data);
+extern UINT16 adsp2181_idma_addr_r(void);
+extern void adsp2181_idma_data_w(UINT16 data);
+extern UINT16 adsp2181_idma_data_r(void);
+#endif
+
+#endif /* _ADSP2100_H */
diff --git a/src/emu/cpu/alph8201/8201dasm.c b/src/emu/cpu/alph8201/8201dasm.c
new file mode 100644
index 00000000000..4555beac533
--- /dev/null
+++ b/src/emu/cpu/alph8201/8201dasm.c
@@ -0,0 +1,261 @@
+/****************************************************************************
+ Alpha 8201/8301 Disassembler
+
+ Copyright (C) 2006 Tatsuyuki Satoh
+ Originally written for the MAME project.
+
+****************************************************************************/
+
+#include <ctype.h>
+
+#include "cpuintrf.h"
+
+typedef unsigned char byte;
+
+#define FMT(a,b) a, b
+#define PTRS_PER_FORMAT 2
+
+static const char *Formats[] = {
+ FMT("0000_0000", "NOP"), // 00
+ FMT("0000_0001", "RRCA"), // 01
+ FMT("0000_0010", "RLCA"), // 02
+ FMT("0000_0011", "INC B"), // 03 : shougi $360 to $377
+ FMT("0000_0100", "DEC B"), // 04 : not found
+ FMT("0000_0101", "INC A"), // 05
+ FMT("0000_0110", "DEC A"), // 06
+ FMT("0000_0111", "CPL A"), // 07
+ FMT("0000_1aaa", "LD A,(IX0+%X)"),// 08-0F
+ FMT("0001_0aaa", "LD A,(IX1+%X)"),// 10-17
+ FMT("0001_1aaa", "LD (IX2+%X),A"),// 18-1F
+ FMT("0010_0xxx", "LD [IX0+%X],B"), // 20-27 : shougi $360 to $377
+ FMT("0010_1xxx", "ld [ix1+%X],b ?"),// 28-2f : not found
+ FMT("0011_0xxx", "ld b,[ix2+%X] ?"),// 30-37 : not found
+ FMT("0011_1aaa", "BIT R0.%d"), // 38-3f ZF = R0.a (bit test)
+ FMT("0100_aaa0", "LD A,R%X"), // 40-4E
+ FMT("0100_aaa1", "LD R%X,A"), // 41-4F
+ FMT("0101_aaa0", "ADD A,R%X"), // 50-5E
+ FMT("0101_aaa1", "SUB A,R%X"), // 51-5F
+ FMT("0110_aaa0", "AND A,R%X"), // 60-6E
+ FMT("0110_aaa1", "OR A,R%X"), // 61-6F
+ FMT("0111_aaaa", "ADD IX0,$%X"), // 70-7f
+ FMT("1000_aaaa", "ADD IX1,$%X"), // 80-8f
+ FMT("1001_aaaa", "ADD IX2,$%X"), // 90-9f
+ FMT("1010_0aaa", "LD RB,%X"), // A0-A7
+// FMT("1010_1xxx", "unknown"), // A8-AF : not found
+ FMT("1011_00aa", "LD MB,%X"), // B0-B3
+ FMT("1011_0100", "HALT"), // B4
+// FMT("1011_0101", "unknown"), // B5 : not found
+// FMT("1011_0110", "unknown"), // B6 : not found
+// FMT("1011_0111", "unknown"), // B7 : not found
+// FMT("1011_1xxx", "unknown"), // B8-BF : not found
+ FMT("1100_0000 I", "LD IX0,$%02X"),// C0
+ FMT("1100_0001 I", "LD IX1,$%02X"),// C1
+ FMT("1100_0010 I", "LD IX2,$%02X"),// C2
+ FMT("1100_0011 I", "LD A,$%02X"), // C3
+ FMT("1100_0100 I", "LD LP0,$%02X"),// C4
+ FMT("1100_0101 I", "LD LP1,$%02X"),// C5
+ FMT("1000_0110 I", "LD LP2,$%02X"),// C6
+ FMT("1100_0111 I", "LD B,$%02X"), // C7 : shougi.c : please check with real chip !
+ FMT("1100_1000 I", "ADD A,$%02X"), // C8
+ FMT("1100_1001 I", "SUB A,$%02X"), // C9
+ FMT("1100_1010 I", "AND A,$%02X"), // CA
+ FMT("1100_1011 I", "OR A,$%02X"), // CB
+ FMT("1100_1100 I", "DJNZ LP0,$%02X"),// CC
+ FMT("1100_1101 I", "DJNZ LP1,$%02X"),// CD
+ FMT("1100_1110 I", "DJNZ LP2,$%02X"),// CE
+ FMT("1100_1111 I", "JNZ $%02X"), // CF
+ FMT("1101_0000 I", "JC $%02X"), // D0
+ FMT("1101_0001 I", "JZ $%02X"), // D1
+ FMT("1101_0010 I", "J $%02X"), // D2
+ FMT("1101_0011 I", "unk $%02X"), // D3
+ FMT("1101_0100 I", "alu a,$%02X ?"), // D4 : 8031 , exctscc2 alu a,n ?
+ FMT("1101_0101 I", "alu a,$%02X ?"), // D5 : 8031 , exctscc2 alu a,n ?
+ FMT("1101_0110 I", "unk $%02X"), // D6
+ FMT("1101_0111 I", "unk $%02X"), // D7
+ FMT("1101_1000 I", "unk $%02X"), // D8
+ FMT("1101_1001 I", "unk $%02X"), // D9
+ FMT("1101_1010 I", "CMP A,$%02X"), // DA : 8301
+ FMT("1101_1011 I", "unk $%02X"), // DB
+ FMT("1101_1100 I", "unk $%02X"), // DC
+ FMT("1101_1101 I", "unk $%02X"), // DD
+ FMT("1101_1110 I", "unk $%02X"), // DE
+ FMT("1101_1111 I", "CALL $%02X"), // DF : 8301
+//
+ FMT("1110_0000", "DEC IX0"), // E0 : 8301
+// FMT("1110_0001", "unknown"), // E1
+// FMT("1110_0010", "unknown"), // E2
+ FMT("1110_0011", "ld a,b ?"), // E3 : 8301
+// FMT("1110_0100", "unknown"), // E4
+// FMT("1110_0101", "unknown"), // E5
+// FMT("1110_0110", "unknown"), // E6 : 8301
+// FMT("1110_0110", "unknown"), // E7
+ FMT("1110_1000", "LD IX0,A"), // E8 : 8301
+ FMT("1110_1001", "LD IX1,A ?"), // E9 : not found
+ FMT("1110_1010", "LD IX2,A"), // EA : 8301
+ FMT("1110_1011", "ld b,a ?"), // EB : 8301
+// FMT("1110_1100", "unknown"), // EC
+// FMT("1110_1100", "unknown"), // ED
+// FMT("1110_1110", "unknown"), // EE : 8301
+// FMT("1110_1111", "unknown"), // EF
+// FMT("1111_0000", "unknown"), // F0
+ FMT("1111_0001", "LD IX2,IX0"), // F1 : 8301
+// FMT("1111_0010", "unknown"), // F2 : 8301 , alu a,[IXR] ?
+// FMT("1111_0011", "unknown"), // F3
+// FMT("1111_0100", "unknown"), // F4
+// FMT("1111_0101", "unknown"), // F5
+ FMT("1111_0110", "alu ?,a"), // F6 : 8301 , exctsccr, alu ?,a
+// FMT("1111_0110", "unknown"), // F7
+ FMT("1111_1000", "alu a,?"), // F8 : 8301 , exctsccr, alu b,a ? : ZF check
+ FMT("1111_1001", "alu a,?"), // F9 : 8301 , exctsccr, alu a,?
+ FMT("1111_1010", "ADD A,CF"), // FA : 8301
+// FMT("1111_1011", "unknown"), // FB
+ FMT("1111_1100", "tst a ?"), // FC : 8301 , ZF = (A==0) ?
+ FMT("1111_1101", "CLR A"), // FD : 8301
+ FMT("1111_1110", "LD A,(IX0+A)"), // FE : 8301
+ FMT("1111_1111", "RET"), // FF : 8301
+ NULL
+};
+
+#define MAX_OPS (((sizeof(Formats) / sizeof(Formats[0])) - 1) / PTRS_PER_FORMAT)
+
+typedef struct opcode {
+ byte mask;
+ byte bits;
+ byte type;
+ byte pmask;
+ byte pdown;
+ const char *fmt;
+} AD8201Opcode;
+
+static AD8201Opcode Op[MAX_OPS+1];
+static int OpInizialized = 0;
+
+static void InitDasm8201(void)
+{
+ const char *p;
+ byte mask, bits;
+ int bit;
+ int i;
+ char chr , type;
+ int pmask , pdown;
+
+ for(i=0;(p=Formats[i*2])!=NULL;i++)
+ {
+ mask = 0;
+ bits = 0;
+ pmask = 0;
+ pdown = 0;
+ type = 0;
+ bit = 7;
+ while ( (chr=*p) && bit >= 0) {
+ p++;
+ switch (chr) {
+ case '1': bits |= 1<<bit;
+ case '0': mask |= 1<<bit; bit--; break;
+/*
+ case 'b':
+ type |= 0x80;
+*/
+ case 'a':
+ pmask |= 1<<bit;
+ pdown = bit;
+ case 'x':
+ bit --;
+ break;
+ case '_':
+ continue;
+ default:
+ fatalerror("Invalid instruction encoding '%s %s'\n", Formats[i*2],Formats[i*2+1]);
+ }
+ }
+ if (bit != -1 ) {
+ fatalerror("not enough bits in encoding '%s %s' %d\n", Formats[i*2],Formats[i*2+1],bit);
+ }
+
+ Op[i].mask = mask;
+ Op[i].bits = bits;
+ Op[i].pmask = pmask;
+ Op[i].pdown = pdown;
+ Op[i].fmt = Formats[i*2+1];
+ Op[i].type = type;
+
+ /* 2 byte code ? */
+ while (isspace(*p)) p++;
+ if( (*p) )
+ Op[i].type |= 0x10;
+ /* number of param */
+ if( (p=strchr(Op[i].fmt,'%'))!=NULL )
+ {
+ Op[i].type |= 0x01; /* single param */
+ if(strchr(p+1,'%') )
+ Op[i].type |= 0x02; /* double param */
+ }
+ }
+
+ OpInizialized = 1;
+}
+
+offs_t ALPHA8201_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ offs_t dasmflags = 0;
+ int i;
+ int op;
+ int cnt = 1;
+ int code , disp;
+
+ if (!OpInizialized) InitDasm8201();
+
+ code = oprom[0];
+ op = -1; /* no matching opcode */
+ for ( i = 0; i < MAX_OPS; i++)
+ {
+ if( (code & Op[i].mask) == Op[i].bits )
+ {
+ if (op != -1)
+ {
+ fprintf(stderr, "Error: opcode %02X matches %d (%s) and %d (%s)\n",
+ code,i,Op[i].fmt,op,Op[op].fmt);
+ }
+ op = i;
+ }
+ }
+
+ if (op == -1)
+ {
+ sprintf(buffer,"db %2.2x",code);
+ return cnt;
+ }
+
+ if (Op[op].type & 0x10)
+ {
+ disp = opram[1];
+ cnt++;
+ }
+ else
+ {
+ disp = (code & Op[op].pmask) >> Op[op].pdown;
+ }
+
+ if (Op[op].type & 0x02)
+ sprintf(buffer, Op[op].fmt,disp,disp);
+ else if (Op[op].type & 0x01)
+ sprintf(buffer, Op[op].fmt,disp);
+ else
+ sprintf(buffer, "%s",Op[op].fmt);
+
+ switch (code)
+ {
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xdf:
+ dasmflags = DASMFLAG_STEP_OVER;
+ break;
+
+ case 0xff:
+ dasmflags = DASMFLAG_STEP_OUT;
+ break;
+ }
+
+ return cnt | dasmflags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/alph8201/alph8201.c b/src/emu/cpu/alph8201/alph8201.c
new file mode 100644
index 00000000000..53b8db87c9a
--- /dev/null
+++ b/src/emu/cpu/alph8201/alph8201.c
@@ -0,0 +1,1013 @@
+/****************************************************************************
+ Alpha8201 Emulator
+
+ Copyright (C) 2006 Tatsuyuki Satoh
+ Originally written for the MAME project.
+
+ Notes :
+
+ tested with champbas.c , talbot.c , shougi.c
+
+ This MCU looks too slow speed,
+ but fast execution don't work to champbb2, champbbj, talbot.
+
+ some unknown instruction are not emulation (used by shougi).
+
+ Because there was no information, opcode-syntax was created.
+
+ TODO:
+ verify with real chip or analyze more.
+ -call/ret stack point (8301).
+ -A lot of 8301 opcode.
+ -memory address 000 specification
+ -memory address 001 bit 7-5 specification
+ -write value after HALT operation to ODD of vector memory.
+ -operation cycle(execution speed).
+ History:
+
+060327:
+ IXR changes to Breg.
+ The addition of Memory Access of Breg and IX0
+
+060326:
+ Added ALPHA 8301 I/F and emulation
+
+060324:
+ Archtectore Created by compare code no-MCU Z80 code and MCU version code.
+ and check talbot and shougi.c.
+
+****************************************************************************/
+
+/****************************************************************************
+
+-----------------------
+package / pin assign
+-----------------------
+ALPHA 8201 DIP 42
+
+ 1 -WR (or -RD)
+ 2-4 : ? NC
+ 5-7 : ? GND to shougi , NC to champbas
+ 8-14: ? NC
+ 15 : RESET
+ 16 : GND
+ 17 : CLK (champbas=768KHz)
+ 18 : ? NC
+ 19-21: to VCC
+ 22-25: DB4-DB7
+ 26-29: DB0-DB3
+ 30 : HALT (input)
+ 31 : ? NC
+ 32-35: A4-A7
+ 36-39: A0-A3
+ 40-41: A8-A9
+ 42 : -RD (or -WR)
+
+ALPHA 8301 seems to be 8201 upper compatibility IC.
+The package of ALPHA8301 is unknown.
+
+-----------------------
+Register Set
+-----------------------
+
+PC : 10bit Program Pointer
+ A lower 8bits are loaded from the immidate.
+ A higher 2bits are loaded from the MB register.
+
+MB : 2bit memory bank register, load PC[9:8] after branch
+ load high to higher 2bit of PC after branch.
+
+RB : 3bit register bank select register
+
+R0-R7 : internal? RAM register 8bitx8 (x8 bank)
+
+A : 8bit
+
+IX0/1 : memory indirect 'read' access pointer
+
+IX2 : memory indirect 'write' access pointer
+
+RXB : unknown , looks index register
+
+LP0/1/2 : loop count register used by DJNZ operation
+
+CF : carry flag
+ZF : zero flag
+
+-----------------------
+Memoy Space
+-----------------------
+
+000 : unknown ...
+001 : bit4..0 = pointer of current entry , bit7..6 = unknown
+002-003 : entrypoint1 vector
+004-005 : entrypoint2 vector
+006-007 : entrypoint3 vector
+008-009 : entrypoint4 vector
+00A-00B : entrypoint5 vector
+00C-00D : entrypoint6 vector
+00E-00F : entrypoint7 vector
+010-011 : entrypoint8 vector
+012-013 : entrypoint9 vector
+014-015 : entrypoint10 vector
+016-017 : entrypoint11 vector
+018-019 : entrypoint12 vector
+01A-01B : entrypoint13 vector
+01C-01D : entrypoint14 vector
+01E-01F : entrypoint15 vector
+020-0FF : bank 0, program / data memory
+100-1FF : bank 1, program / data memory
+200-2FF : bank 2, program / data memory
+300-3FF : bank 3, program / data memory
+
+The even address is the lower byte of the entry address.
+The odd-address of entry point is a MB and status.
+ Bit 0 and 1 are a memory bank.
+ Bit 2 is HALT.At the time of set, it doesn't execute entry address.
+ After EXIT operation, Bit2 is set.
+
+-----------------------
+Timming
+-----------------------
+
+****************************************************************************/
+
+#include "debugger.h"
+#include "alph8201.h"
+
+/* instruction cycle count */
+#define C1 16
+#define C2 32
+
+/* debug option */
+#define TRACE_PC 0
+#define SHOW_ENTRY_POINT 0
+#define SHOW_MESSAGE_CONSOLE 0
+
+/* MAME is unnecessary */
+#define HANDLE_HALT_LINE 0
+
+#define M_RDMEM(A) ALPHA8201_RDMEM(A)
+#define M_WRMEM(A,V) ALPHA8201_WRMEM(A,V)
+#define M_RDOP(A) ALPHA8201_RDOP(A)
+#define M_RDOP_ARG(A) ALPHA8201_RDOP_ARG(A)
+
+typedef struct
+{
+ UINT8 RAM[8*8]; /* internal GP register 8 * 8bank */
+ unsigned PREVPC;
+ PAIR retptr; /* for 8301, return address stack of CALL */
+ PAIR pc; /* 2bit+8bit program counter */
+ UINT8 regPtr; /* RB register base */
+ UINT8 mb; /* MB memory bank reg. latch after Branch */
+ UINT8 cf; /* C flag */
+ UINT8 zf; /* Z flag */
+//
+ PAIR ix0; /* 8bit memory read index reg. */
+ PAIR ix1; /* 8bitmemory read index reg. */
+ PAIR ix2; /* 8bitmemory write index reg. */
+ UINT8 lp0; /* 8bit loop reg. */
+ UINT8 lp1; /* 8bit loop reg. */
+ UINT8 lp2; /* 8bit loop reg. */
+ UINT8 A; /* 8bit accumerator */
+ UINT8 B; /* 8bit regiser */
+//
+#if HANDLE_HALT_LINE
+ UINT8 halt; /* halt input line */
+#endif
+} ALPHA8201_Regs;
+
+/* The opcode table now is a combination of cycle counts and function pointers */
+typedef struct {
+ unsigned cycles;
+ void (*function) (void);
+} s_opcode;
+
+static ALPHA8201_Regs R;
+int ALPHA8201_ICount;
+static int inst_cycles;
+
+#define intRAM R.RAM
+#define regPTR R.regPtr
+
+#define PC R.pc.w.l
+#define PCL R.pc.b.l
+#define R0 intRAM[regPTR ]
+#define R1 intRAM[regPTR+1]
+#define R2 intRAM[regPTR+2]
+#define R3 intRAM[regPTR+3]
+#define R4 intRAM[regPTR+4]
+#define R5 intRAM[regPTR+5]
+#define R6 intRAM[regPTR+6]
+#define R7 intRAM[regPTR+7]
+#define ZF R.zf
+#define CF R.cf
+#define IX0 R.ix0.b.l
+#define IX1 R.ix1.b.l
+#define IX2 R.ix2.b.l
+#define BIX0 R.ix0.w.l
+#define BIX1 R.ix1.w.l
+#define BIX2 R.ix2.w.l
+#define LP0 R.lp0
+#define LP1 R.lp1
+#define LP2 R.lp2
+
+/* Get next opcode argument and increment program counter */
+INLINE unsigned M_RDMEM_OPCODE (void)
+{
+ unsigned retval;
+ retval=M_RDOP_ARG(PC);
+ PCL++;
+ return retval;
+}
+
+INLINE void M_ADD(UINT8 dat)
+{
+ UINT16 temp = R.A + dat;
+ R.A = temp & 0xff;
+ ZF = (R.A==0);
+ CF = temp>>8;
+}
+
+INLINE void M_SUB(UINT8 dat)
+{
+ CF = (R.A<dat);
+ R.A -= dat;
+ ZF = (R.A==0);
+}
+
+INLINE void M_ADDB(UINT8 dat)
+{
+ UINT16 temp = R.B + dat;
+ R.B = temp & 0xff;
+ ZF = (R.B==0);
+ CF = temp>>8;
+}
+
+INLINE void M_SUBB(UINT8 dat)
+{
+ CF = (R.B<dat);
+ R.B -= dat;
+ ZF = (R.B==0);
+}
+
+INLINE void M_AND(UINT8 dat)
+{
+ R.A &= dat;
+ ZF = (R.A==0);
+ CF = 0;
+}
+
+INLINE void M_OR(UINT8 dat)
+{
+ R.A |= dat;
+ ZF = (R.A==0);
+ CF = 0;
+}
+
+INLINE void M_JMP(UINT8 dat)
+{
+ PCL = dat;
+ /* update pc page */
+ R.pc.b.h = R.ix0.b.h = R.ix1.b.h = R.ix2.b.h = R.mb & 3;
+ change_pc(PC);
+}
+
+INLINE void M_UNDEFINED(void)
+{
+ logerror("ALPHA8201: PC = %03x, Unimplemented opcode = %02x\n", PC-1, M_RDMEM(PC-1));
+#if SHOW_MESSAGE_CONSOLE
+ mame_printf_debug("ALPHA8201: PC = %03x, Unimplemented opcode = %02x\n", PC-1, M_RDMEM(PC-1));
+#endif
+}
+
+INLINE void M_UNDEFINED2(void)
+{
+ UINT8 op = M_RDOP(PC-1);
+ UINT8 imm = M_RDMEM_OPCODE();
+ logerror("ALPHA8201: PC = %03x, Unimplemented opcode = %02x,%02x\n", PC-2, op,imm);
+#if SHOW_MESSAGE_CONSOLE
+ mame_printf_debug("ALPHA8201: PC = %03x, Unimplemented opcode = %02x,%02x\n", PC-2, op,imm);
+#endif
+}
+
+static void undefined(void) { M_UNDEFINED(); }
+static void undefined2(void) { M_UNDEFINED2(); }
+
+static void need_verify(const char *s)
+{
+ UINT8 op = M_RDOP(PC-1);
+ logerror("ALPHA8201: PC = %03x, unknown opcode = %02x is '%s' ??\n",PC-1, op,s);
+#if SHOW_MESSAGE_CONSOLE
+ mame_printf_debug("ALPHA8201: PC = %03x, unknown opcode = %02x is '%s' ??\n",PC-1, op,s);
+#endif
+}
+
+static void nop(void) { }
+static void rlca(void) { CF = (R.A>>7)&1; R.A = (R.A<<1) | (R.A>>7); ZF = (R.A==0); }
+static void rrca(void) { CF = R.A &1; R.A = (R.A>>1) | (R.A<<7); ZF = (R.A==0); }
+static void inc_b(void) { M_ADDB(1); }
+static void dec_b(void) { M_SUBB(1); };
+static void inc_a(void) { M_ADD(1); }
+static void dec_a(void) { M_SUB(1); }
+static void cpl(void) { R.A = R.A^0xff; ZF = (R.A==0); };
+
+static void ld_a_ix0_0(void) { R.A = M_RDMEM(BIX0+0); }
+static void ld_a_ix0_1(void) { R.A = M_RDMEM(BIX0+1); }
+static void ld_a_ix0_2(void) { R.A = M_RDMEM(BIX0+2); }
+static void ld_a_ix0_3(void) { R.A = M_RDMEM(BIX0+3); }
+static void ld_a_ix0_4(void) { R.A = M_RDMEM(BIX0+4); }
+static void ld_a_ix0_5(void) { R.A = M_RDMEM(BIX0+5); }
+static void ld_a_ix0_6(void) { R.A = M_RDMEM(BIX0+6); }
+static void ld_a_ix0_7(void) { R.A = M_RDMEM(BIX0+7); }
+
+static void ld_a_ix1_0(void) { R.A = M_RDMEM(BIX1+0); }
+static void ld_a_ix1_1(void) { R.A = M_RDMEM(BIX1+1); }
+static void ld_a_ix1_2(void) { R.A = M_RDMEM(BIX1+2); }
+static void ld_a_ix1_3(void) { R.A = M_RDMEM(BIX1+3); }
+static void ld_a_ix1_4(void) { R.A = M_RDMEM(BIX1+4); }
+static void ld_a_ix1_5(void) { R.A = M_RDMEM(BIX1+5); }
+static void ld_a_ix1_6(void) { R.A = M_RDMEM(BIX1+6); }
+static void ld_a_ix1_7(void) { R.A = M_RDMEM(BIX1+7); }
+
+static void ld_ix2_0_a(void) { M_WRMEM(BIX2+0,R.A); }
+static void ld_ix2_1_a(void) { M_WRMEM(BIX2+1,R.A); }
+static void ld_ix2_2_a(void) { M_WRMEM(BIX2+2,R.A); }
+static void ld_ix2_3_a(void) { M_WRMEM(BIX2+3,R.A); }
+static void ld_ix2_4_a(void) { M_WRMEM(BIX2+4,R.A); }
+static void ld_ix2_5_a(void) { M_WRMEM(BIX2+5,R.A); }
+static void ld_ix2_6_a(void) { M_WRMEM(BIX2+6,R.A); }
+static void ld_ix2_7_a(void) { M_WRMEM(BIX2+7,R.A); }
+
+static void ld_ix0_0_b(void) { M_WRMEM(BIX0+0,R.B); }
+static void ld_ix0_1_b(void) { M_WRMEM(BIX0+0,R.B); }
+static void ld_ix0_2_b(void) { M_WRMEM(BIX0+0,R.B); }
+static void ld_ix0_3_b(void) { M_WRMEM(BIX0+0,R.B); }
+static void ld_ix0_4_b(void) { M_WRMEM(BIX0+0,R.B); }
+static void ld_ix0_5_b(void) { M_WRMEM(BIX0+0,R.B); }
+static void ld_ix0_6_b(void) { M_WRMEM(BIX0+0,R.B); }
+static void ld_ix0_7_b(void) { M_WRMEM(BIX0+0,R.B); }
+
+static void ld_ix1_0_b(void) { M_WRMEM(BIX1+0,R.B); need_verify("LD (IX1+0),B"); }
+static void ld_ix1_1_b(void) { M_WRMEM(BIX1+1,R.B); need_verify("LD (IX1+1),B"); }
+static void ld_ix1_2_b(void) { M_WRMEM(BIX1+2,R.B); need_verify("LD (IX1+2),B"); }
+static void ld_ix1_3_b(void) { M_WRMEM(BIX1+3,R.B); need_verify("LD (IX1+3),B"); }
+static void ld_ix1_4_b(void) { M_WRMEM(BIX1+4,R.B); need_verify("LD (IX1+4),B"); }
+static void ld_ix1_5_b(void) { M_WRMEM(BIX1+5,R.B); need_verify("LD (IX1+5),B"); }
+static void ld_ix1_6_b(void) { M_WRMEM(BIX1+6,R.B); need_verify("LD (IX1+6),B"); }
+static void ld_ix1_7_b(void) { M_WRMEM(BIX1+7,R.B); need_verify("LD (IX1+7),B"); }
+
+static void ld_b_ix2_0(void) { R.B = M_RDMEM(BIX2+0); need_verify("LD B,(IX2+0)"); }
+static void ld_b_ix2_1(void) { R.B = M_RDMEM(BIX2+1); need_verify("LD B,(IX2+1)"); }
+static void ld_b_ix2_2(void) { R.B = M_RDMEM(BIX2+2); need_verify("LD B,(IX2+2)"); }
+static void ld_b_ix2_3(void) { R.B = M_RDMEM(BIX2+3); need_verify("LD B,(IX2+3)"); }
+static void ld_b_ix2_4(void) { R.B = M_RDMEM(BIX2+4); need_verify("LD B,(IX2+4)"); }
+static void ld_b_ix2_5(void) { R.B = M_RDMEM(BIX2+5); need_verify("LD B,(IX2+5)"); }
+static void ld_b_ix2_6(void) { R.B = M_RDMEM(BIX2+6); need_verify("LD B,(IX2+6)"); }
+static void ld_b_ix2_7(void) { R.B = M_RDMEM(BIX2+7); need_verify("LD B,(IX2+7)"); }
+
+static void bit_r0_0(void) { R.zf = R0&(1<<0)?0:1; }
+static void bit_r0_1(void) { R.zf = R0&(1<<1)?0:1; }
+static void bit_r0_2(void) { R.zf = R0&(1<<2)?0:1; }
+static void bit_r0_3(void) { R.zf = R0&(1<<3)?0:1; }
+static void bit_r0_4(void) { R.zf = R0&(1<<4)?0:1; }
+static void bit_r0_5(void) { R.zf = R0&(1<<5)?0:1; }
+static void bit_r0_6(void) { R.zf = R0&(1<<6)?0:1; }
+static void bit_r0_7(void) { R.zf = R0&(1<<7)?0:1; }
+
+static void ld_a_n(void) { R.A = M_RDMEM_OPCODE(); }
+static void ld_a_r0(void) { R.A = R0; }
+static void ld_a_r1(void) { R.A = R1; }
+static void ld_a_r2(void) { R.A = R2; }
+static void ld_a_r3(void) { R.A = R3; }
+static void ld_a_r4(void) { R.A = R4; }
+static void ld_a_r5(void) { R.A = R5; }
+static void ld_a_r6(void) { R.A = R6; }
+static void ld_a_r7(void) { R.A = R7; }
+
+static void ld_r0_a(void) { R0 = R.A; }
+static void ld_r1_a(void) { R1 = R.A; }
+static void ld_r2_a(void) { R2 = R.A; }
+static void ld_r3_a(void) { R3 = R.A; }
+static void ld_r4_a(void) { R4 = R.A; }
+static void ld_r5_a(void) { R5 = R.A; }
+static void ld_r6_a(void) { R6 = R.A; }
+static void ld_r7_a(void) { R7 = R.A; }
+
+static void add_a_n(void) { M_ADD(M_RDMEM_OPCODE()); }
+static void add_a_r0(void) { M_ADD(R0); }
+static void add_a_r1(void) { M_ADD(R1); }
+static void add_a_r2(void) { M_ADD(R2); }
+static void add_a_r3(void) { M_ADD(R3); }
+static void add_a_r4(void) { M_ADD(R4); }
+static void add_a_r5(void) { M_ADD(R5); }
+static void add_a_r6(void) { M_ADD(R6); }
+static void add_a_r7(void) { M_ADD(R7); }
+
+static void sub_a_n(void) { M_SUB(M_RDMEM_OPCODE()); }
+static void sub_a_r0(void) { M_SUB(R0); }
+static void sub_a_r1(void) { M_SUB(R1); }
+static void sub_a_r2(void) { M_SUB(R2); }
+static void sub_a_r3(void) { M_SUB(R3); }
+static void sub_a_r4(void) { M_SUB(R4); }
+static void sub_a_r5(void) { M_SUB(R5); }
+static void sub_a_r6(void) { M_SUB(R6); }
+static void sub_a_r7(void) { M_SUB(R7); }
+
+static void and_a_n(void) { M_AND(M_RDMEM_OPCODE()); }
+static void and_a_r0(void) { M_AND(R0); }
+static void and_a_r1(void) { M_AND(R1); }
+static void and_a_r2(void) { M_AND(R2); }
+static void and_a_r3(void) { M_AND(R3); }
+static void and_a_r4(void) { M_AND(R4); }
+static void and_a_r5(void) { M_AND(R5); }
+static void and_a_r6(void) { M_AND(R6); }
+static void and_a_r7(void) { M_AND(R7); }
+
+static void or_a_n(void) { M_OR(M_RDMEM_OPCODE()); }
+static void or_a_r0(void) { M_OR(R0); }
+static void or_a_r1(void) { M_OR(R1); }
+static void or_a_r2(void) { M_OR(R2); }
+static void or_a_r3(void) { M_OR(R3); }
+static void or_a_r4(void) { M_OR(R4); }
+static void or_a_r5(void) { M_OR(R5); }
+static void or_a_r6(void) { M_OR(R6); }
+static void or_a_r7(void) { M_OR(R7); }
+
+static void add_ix0_0(void) {}
+static void add_ix0_1(void) { IX0 += 1; }
+static void add_ix0_2(void) { IX0 += 2; }
+static void add_ix0_3(void) { IX0 += 3; }
+static void add_ix0_4(void) { IX0 += 4; }
+static void add_ix0_5(void) { IX0 += 5; }
+static void add_ix0_6(void) { IX0 += 6; }
+static void add_ix0_7(void) { IX0 += 7; }
+static void add_ix0_8(void) { IX0 += 8; }
+static void add_ix0_9(void) { IX0 += 9; }
+static void add_ix0_a(void) { IX0 += 10; }
+static void add_ix0_b(void) { IX0 += 11; }
+static void add_ix0_c(void) { IX0 += 12; }
+static void add_ix0_d(void) { IX0 += 13; }
+static void add_ix0_e(void) { IX0 += 14; }
+static void add_ix0_f(void) { IX0 += 15; }
+
+static void add_ix1_0(void) {}
+static void add_ix1_1(void) { IX1 += 1; }
+static void add_ix1_2(void) { IX1 += 2; }
+static void add_ix1_3(void) { IX1 += 3; }
+static void add_ix1_4(void) { IX1 += 4; }
+static void add_ix1_5(void) { IX1 += 5; }
+static void add_ix1_6(void) { IX1 += 6; }
+static void add_ix1_7(void) { IX1 += 7; }
+static void add_ix1_8(void) { IX1 += 8; }
+static void add_ix1_9(void) { IX1 += 9; }
+static void add_ix1_a(void) { IX1 += 10; }
+static void add_ix1_b(void) { IX1 += 11; }
+static void add_ix1_c(void) { IX1 += 12; }
+static void add_ix1_d(void) { IX1 += 13; }
+static void add_ix1_e(void) { IX1 += 14; }
+static void add_ix1_f(void) { IX1 += 15; }
+
+static void add_ix2_0(void) {}
+static void add_ix2_1(void) { IX2 += 1; }
+static void add_ix2_2(void) { IX2 += 2; }
+static void add_ix2_3(void) { IX2 += 3; }
+static void add_ix2_4(void) { IX2 += 4; }
+static void add_ix2_5(void) { IX2 += 5; }
+static void add_ix2_6(void) { IX2 += 6; }
+static void add_ix2_7(void) { IX2 += 7; }
+static void add_ix2_8(void) { IX2 += 8; }
+static void add_ix2_9(void) { IX2 += 9; }
+static void add_ix2_a(void) { IX2 += 10; }
+static void add_ix2_b(void) { IX2 += 11; }
+static void add_ix2_c(void) { IX2 += 12; }
+static void add_ix2_d(void) { IX2 += 13; }
+static void add_ix2_e(void) { IX2 += 14; }
+static void add_ix2_f(void) { IX2 += 15; }
+
+static void ld_base_0(void) { regPTR = 0<<3; }
+static void ld_base_1(void) { regPTR = 1<<3; }
+static void ld_base_2(void) { regPTR = 2<<3; }
+static void ld_base_3(void) { regPTR = 3<<3; }
+static void ld_base_4(void) { regPTR = 4<<3; }
+static void ld_base_5(void) { regPTR = 5<<3; }
+static void ld_base_6(void) { regPTR = 6<<3; }
+static void ld_base_7(void) { regPTR = 7<<3; }
+
+static void ld_bank_0(void) { R.mb = 0; }
+static void ld_bank_1(void) { R.mb = 1; }
+static void ld_bank_2(void) { R.mb = 2; }
+static void ld_bank_3(void) { R.mb = 3; }
+
+static void halt(void)
+{
+ UINT8 pcptr = M_RDMEM(0x001) & 0x1f;
+ M_WRMEM(pcptr,0x08); /* mark entry point ODD to HALT */
+ R.mb |= 0x08; /* mark internal HALT state */
+}
+
+static void ld_ix0_n(void) { IX0 = M_RDMEM_OPCODE(); }
+static void ld_ix1_n(void) { IX1 = M_RDMEM_OPCODE(); }
+static void ld_ix2_n(void) { IX2 = M_RDMEM_OPCODE(); }
+static void ld_lp0_n(void) { LP0 = M_RDMEM_OPCODE(); }
+static void ld_lp1_n(void) { LP1 = M_RDMEM_OPCODE(); }
+static void ld_lp2_n(void) { LP2 = M_RDMEM_OPCODE(); }
+static void ld_b_n(void) { R.B = M_RDMEM_OPCODE(); }
+
+static void djnz_lp0(void) { UINT8 i=M_RDMEM_OPCODE(); LP0--; if (LP0 != 0) M_JMP(i); }
+static void djnz_lp1(void) { UINT8 i=M_RDMEM_OPCODE(); LP1--; if (LP1 != 0) M_JMP(i); }
+static void djnz_lp2(void) { UINT8 i=M_RDMEM_OPCODE(); LP2--; if (LP2 != 0) M_JMP(i); }
+static void jnz(void) { UINT8 i=M_RDMEM_OPCODE(); if (!R.zf) M_JMP(i); }
+static void jc(void) { UINT8 i=M_RDMEM_OPCODE(); if ( R.cf) M_JMP(i); }
+static void jz(void) { UINT8 i=M_RDMEM_OPCODE(); if ( R.zf) M_JMP(i); }
+static void jmp(void) { M_JMP( M_RDMEM_OPCODE() ); }
+
+#if (HAS_ALPHA8201)
+static const s_opcode opcode_8201[256]=
+{
+ {C1, nop },{C1,rrca },{C1, rlca },{C1,inc_b },{C1, dec_b },{C1, inc_a },{C1, dec_a },{C1, cpl },
+ {C2,ld_a_ix0_0 },{C2,ld_a_ix0_1},{C2, ld_a_ix0_2},{C2,ld_a_ix0_3},{C2,ld_a_ix0_4},{C2,ld_a_ix0_5},{C2,ld_a_ix0_6},{C2,ld_a_ix0_7},
+ {C2,ld_a_ix1_0 },{C2,ld_a_ix1_1},{C2, ld_a_ix1_2},{C2,ld_a_ix1_3},{C2,ld_a_ix1_4},{C2,ld_a_ix1_5},{C2,ld_a_ix1_6},{C2,ld_a_ix1_7},
+ {C2,ld_ix2_0_a },{C2,ld_ix2_1_a},{C2, ld_ix2_2_a},{C2,ld_ix2_3_a},{C2,ld_ix2_4_a},{C2,ld_ix2_5_a},{C2,ld_ix2_6_a},{C2,ld_ix2_7_a},
+/* 20 */
+ {C2,ld_ix0_0_b },{C2,ld_ix0_1_b},{C2, ld_ix0_2_b},{C2,ld_ix0_3_b},{C2,ld_ix0_4_b},{C2,ld_ix0_5_b},{C2,ld_ix0_6_b},{C2,ld_ix0_7_b},
+ {C2,ld_ix1_0_b },{C2,ld_ix1_1_b},{C2, ld_ix1_2_b},{C2,ld_ix1_3_b},{C2,ld_ix1_4_b},{C2,ld_ix1_5_b},{C2,ld_ix1_6_b},{C2,ld_ix1_7_b},
+ {C2,ld_b_ix2_0 },{C2,ld_b_ix2_1},{C2, ld_b_ix2_2},{C2,ld_b_ix2_3},{C2,ld_b_ix2_4},{C2,ld_b_ix2_5},{C2,ld_b_ix2_6},{C2,ld_b_ix2_7},
+ {C2,bit_r0_0 },{C2,bit_r0_1 },{C2, bit_r0_2 },{C2, bit_r0_3 },{C2, bit_r0_4 },{C2, bit_r0_5 },{C2, bit_r0_6 },{C2, bit_r0_7 },
+/* 40 : 8201 */
+ {C2, ld_a_r0 },{C2, ld_r0_a },{C2, ld_a_r1 },{C2, ld_r1_a },{C2, ld_a_r2 },{C2, ld_r2_a },{C2, ld_a_r3 },{C2, ld_r3_a },
+ {C2, ld_a_r4 },{C2, ld_r4_a },{C2, ld_a_r5 },{C2, ld_r5_a },{C2, ld_a_r6 },{C2, ld_r6_a },{C2, ld_a_r7 },{C2, ld_r7_a },
+ {C1, add_a_r0 },{C1, sub_a_r0 },{C1, add_a_r1 },{C1, sub_a_r1 },{C1, add_a_r2 },{C1, sub_a_r2 },{C1, add_a_r3 },{C1, sub_a_r3 },
+ {C1, add_a_r4 },{C1, sub_a_r4 },{C1, add_a_r5 },{C1, sub_a_r5 },{C1, add_a_r6 },{C1, sub_a_r6 },{C1, add_a_r7 },{C1, sub_a_r7 },
+ {C1, and_a_r0 },{C1, or_a_r0 },{C1, and_a_r1 },{C1, or_a_r1 },{C1, and_a_r2 },{C1, or_a_r2 },{C1, and_a_r3 },{C1, or_a_r3 },
+ {C1, and_a_r4 },{C1, or_a_r4 },{C1, and_a_r5 },{C1, or_a_r5 },{C1, and_a_r6 },{C1, or_a_r6 },{C1, and_a_r7 },{C1, or_a_r7 },
+ {C1, add_ix0_0 },{C1, add_ix0_1},{C1, add_ix0_2},{C1, add_ix0_3},{C1, add_ix0_4},{C1, add_ix0_5},{C1, add_ix0_6},{C1, add_ix0_7},
+ {C1, add_ix0_8 },{C1, add_ix0_9},{C1, add_ix0_a},{C1, add_ix0_b},{C1, add_ix0_c},{C1, add_ix0_d},{C1, add_ix0_e},{C1, add_ix0_f},
+/* 80 : 8201 */
+ {C1, add_ix1_0 },{C1, add_ix1_1},{C1, add_ix1_2},{C1, add_ix1_3},{C1, add_ix1_4},{C1, add_ix1_5},{C1, add_ix1_6},{C1, add_ix1_7},
+ {C1, add_ix1_8 },{C1, add_ix1_9},{C1, add_ix1_a},{C1, add_ix1_b},{C1, add_ix1_c},{C1, add_ix1_d},{C1, add_ix1_e},{C1, add_ix1_f},
+ {C1, add_ix2_0 },{C1, add_ix2_1},{C1, add_ix2_2},{C1, add_ix2_3},{C1, add_ix2_4},{C1, add_ix2_5},{C1, add_ix2_6},{C1, add_ix2_7},
+ {C1, add_ix2_8 },{C1, add_ix2_9},{C1, add_ix2_a},{C1, add_ix2_b},{C1, add_ix2_c},{C1, add_ix2_d},{C1, add_ix2_e},{C1, add_ix2_f},
+ {C1, ld_base_0 },{C1, ld_base_1},{C1, ld_base_2},{C1, ld_base_3},{C1, ld_base_4},{C1, ld_base_5},{C1, ld_base_6},{C1, ld_base_7},
+ {C1, undefined },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},
+ {C1, ld_bank_0 },{C1, ld_bank_1},{C1, ld_bank_2},{C1, ld_bank_3},{C2, halt },{C1, undefined},{C1, undefined},{C1, undefined},
+ {C1, undefined },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},
+/* c0 : 8201 */
+ {C2, ld_ix0_n },{C2, ld_ix1_n },{C2, ld_ix2_n },{C2, ld_a_n },{C2, ld_lp0_n },{C2, ld_lp1_n },{C2, ld_lp2_n },{C2, ld_b_n },
+ {C2, add_a_n },{C2, sub_a_n },{C2, and_a_n },{C2, or_a_n },{C2, djnz_lp0 },{C2, djnz_lp1 },{C2, djnz_lp2 },{C2, jnz },
+ {C2, jc },{C2, jz },{C2, jmp },{C2,undefined2},{C2,undefined2},{C2,undefined2},{C2,undefined2},{C2, undefined2},
+ {C2, undefined2 },{C2,undefined2},{C2,undefined2},{C2,undefined2},{C2,undefined2},{C2,undefined2},{C2,undefined2},{C2, undefined2},
+/* E0 : 8201*/
+ {C1, undefined },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},
+ {C1, undefined },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},
+ {C1, undefined },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},
+ {C1, undefined },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined }
+};
+#endif
+
+#if (HAS_ALPHA8301)
+
+/* ALPHA 8301 : added instruction */
+static void dec_ix0(void) { IX0--; } /* OK */
+
+static void ld_a_b(void) { R.A = R.B; }
+static void ld_b_a(void) { R.B = R.A; }
+
+static void ld_ix0_a(void) { IX0 = R.A; } /* maybe OK */
+static void ld_ix1_a(void) { IX1 = R.A; need_verify("LD IX1,A"); } /* not found */
+static void ld_ix2_a(void) { IX2 = R.A; } /* maybe OK */
+
+static void ld_ix2_ix0(void) { IX2 = IX0; } /* OK */
+
+/* used by exctscc2 initialize routine */
+/* A=2 , D5 01 , D4 00 -> R=5 */
+/* A=5 , D4 01 -> R=2 */
+/*
+300: DA 02 CMP A,$02 ; A is 2
+302: CF 00 JNZ $00
+304: A7 LD RB,7
+305: 41 LD R0,A
+306: 4F LD R7,A
+307: D5 01 --------------
+309: D4 00 --------------
+30B: DA 05 CMP A,$05 ; A must be set 5
+30D: CF 00 JNZ $00
+30F: D4 01 --------------
+311: DA 02 CMP A,$02 ; A must be set 5
+313: CF 00 JNZ $00
+315: FD clr a ?
+*/
+static void op_d4(void) { undefined2(); }
+static void op_d5(void) { undefined2(); }
+
+/* used by exctsccr/exctscc2 ROM check sum routine (382-3cf) */
+/* ZF = 0 in op_f8 are patch for bypass exctsccr and exctscc2 check sum error */
+static void op_f6(void) { logerror("ALPHA-8301 Unknown OP-code PC = %03x, opcode = 0xf6: alu ?,a ??\n",PC-1); }
+static void op_f8(void) { ZF = 1; logerror("ALPHA-8301 Unknown OP-code PC = %03x, opcode = 0xf8: alu ?,a ??\n",PC-1); }
+static void op_f9(void) { logerror("ALPHA-8301 Unknown OP-code PC = %03x, opcode = 0xf9: alu a,? ??\n",PC-1); }
+
+static void add_a_cf(void) { R.A += CF; CF = 0; ZF = (R.A==0); } /* OK */
+static void tst_a(void) { ZF = (R.A==0); } /* maybe OK */
+static void clr_a(void) { R.A = 0; ZF = (R.A==0); } /* maybe OK */
+static void cmp_a_n(void) { UINT8 i=M_RDMEM_OPCODE(); ZF = (R.A==i); CF = (R.A<i); }
+static void call(void) { UINT8 i=M_RDMEM_OPCODE(); R.retptr.w.l = PC; M_JMP(i); }; /* OK , but stack is unknown */
+static void ld_a_ix0_a(void) { R.A = M_RDMEM(BIX0+R.A); } /* maybe OK */
+static void ret(void) { R.mb = R.retptr.b.h; M_JMP( R.retptr.b.l ); }; /* OK , but stack is unknown */
+
+static const s_opcode opcode_8301[256]=
+{
+ {C1, nop },{C1,rrca },{C1, rlca },{C1,inc_b },{C1, dec_b },{C1, inc_a },{C1, dec_a },{C1, cpl },
+ {C2,ld_a_ix0_0 },{C2,ld_a_ix0_1},{C2, ld_a_ix0_2},{C2,ld_a_ix0_3},{C2,ld_a_ix0_4},{C2,ld_a_ix0_5},{C2,ld_a_ix0_6},{C2,ld_a_ix0_7},
+ {C2,ld_a_ix1_0 },{C2,ld_a_ix1_1},{C2, ld_a_ix1_2},{C2,ld_a_ix1_3},{C2,ld_a_ix1_4},{C2,ld_a_ix1_5},{C2,ld_a_ix1_6},{C2,ld_a_ix1_7},
+ {C2,ld_ix2_0_a },{C2,ld_ix2_1_a},{C2, ld_ix2_2_a},{C2,ld_ix2_3_a},{C2,ld_ix2_4_a},{C2,ld_ix2_5_a},{C2,ld_ix2_6_a},{C2,ld_ix2_7_a},
+/* 20 : 8301 */
+ {C2,ld_ix0_0_b },{C2,ld_ix0_1_b},{C2, ld_ix0_2_b},{C2,ld_ix0_3_b},{C2,ld_ix0_4_b},{C2,ld_ix0_5_b},{C2,ld_ix0_6_b},{C2,ld_ix0_7_b},
+ {C2,ld_ix1_0_b },{C2,ld_ix1_1_b},{C2, ld_ix1_2_b},{C2,ld_ix1_3_b},{C2,ld_ix1_4_b},{C2,ld_ix1_5_b},{C2,ld_ix1_6_b},{C2,ld_ix1_7_b},
+ {C2,ld_b_ix2_0 },{C2,ld_b_ix2_1},{C2, ld_b_ix2_2},{C2,ld_b_ix2_3},{C2,ld_b_ix2_4},{C2,ld_b_ix2_5},{C2,ld_b_ix2_6},{C2,ld_b_ix2_7},
+ {C2,bit_r0_0 },{C2,bit_r0_1 },{C2, bit_r0_2 },{C2, bit_r0_3 },{C2, bit_r0_4 },{C2, bit_r0_5 },{C2, bit_r0_6 },{C2, bit_r0_7 },
+/* 40 : 8301 */
+ {C2, ld_a_r0 },{C2, ld_r0_a },{C2, ld_a_r1 },{C2, ld_r1_a },{C2, ld_a_r2 },{C2, ld_r2_a },{C2, ld_a_r3 },{C2, ld_r3_a },
+ {C2, ld_a_r4 },{C2, ld_r4_a },{C2, ld_a_r5 },{C2, ld_r5_a },{C2, ld_a_r6 },{C2, ld_r6_a },{C2, ld_a_r7 },{C2, ld_r7_a },
+ {C1, add_a_r0 },{C1, sub_a_r0 },{C1, add_a_r1 },{C1, sub_a_r1 },{C1, add_a_r2 },{C1, sub_a_r2 },{C1, add_a_r3 },{C1, sub_a_r3 },
+ {C1, add_a_r4 },{C1, sub_a_r4 },{C1, add_a_r5 },{C1, sub_a_r5 },{C1, add_a_r6 },{C1, sub_a_r6 },{C1, add_a_r7 },{C1, sub_a_r7 },
+/* 60 : 8301 */
+ {C1, and_a_r0 },{C1, or_a_r0 },{C1, and_a_r1 },{C1, or_a_r1 },{C1, and_a_r2 },{C1, or_a_r2 },{C1, and_a_r3 },{C1, or_a_r3 },
+ {C1, and_a_r4 },{C1, or_a_r4 },{C1, and_a_r5 },{C1, or_a_r5 },{C1, and_a_r6 },{C1, or_a_r6 },{C1, and_a_r7 },{C1, or_a_r7 },
+ {C1, add_ix0_0 },{C1, add_ix0_1},{C1, add_ix0_2},{C1, add_ix0_3},{C1, add_ix0_4},{C1, add_ix0_5},{C1, add_ix0_6},{C1, add_ix0_7},
+ {C1, add_ix0_8 },{C1, add_ix0_9},{C1, add_ix0_a},{C1, add_ix0_b},{C1, add_ix0_c},{C1, add_ix0_d},{C1, add_ix0_e},{C1, add_ix0_f},
+/* 80 : 8301 */
+ {C1, add_ix1_0 },{C1, add_ix1_1},{C1, add_ix1_2},{C1, add_ix1_3},{C1, add_ix1_4},{C1, add_ix1_5},{C1, add_ix1_6},{C1, add_ix1_7},
+ {C1, add_ix1_8 },{C1, add_ix1_9},{C1, add_ix1_a},{C1, add_ix1_b},{C1, add_ix1_c},{C1, add_ix1_d},{C1, add_ix1_e},{C1, add_ix1_f},
+ {C1, add_ix2_0 },{C1, add_ix2_1},{C1, add_ix2_2},{C1, add_ix2_3},{C1, add_ix2_4},{C1, add_ix2_5},{C1, add_ix2_6},{C1, add_ix2_7},
+ {C1, add_ix2_8 },{C1, add_ix2_9},{C1, add_ix2_a},{C1, add_ix2_b},{C1, add_ix2_c},{C1, add_ix2_d},{C1, add_ix2_e},{C1, add_ix2_f},
+/* A0 : 8301 */
+ {C1, ld_base_0 },{C1, ld_base_1},{C1, ld_base_2},{C1, ld_base_3},{C1, ld_base_4},{C1, ld_base_5},{C1, ld_base_6},{C1, ld_base_7},
+ {C1, undefined },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},
+ {C1, ld_bank_0 },{C1, ld_bank_1},{C1, ld_bank_2},{C1, ld_bank_3},{C2, halt },{C1, undefined},{C1, undefined},{C1, undefined},
+ {C1, undefined },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},
+/* c0 : 8301 */
+ {C2, ld_ix0_n },{C2, ld_ix1_n },{C2, ld_ix2_n },{C2, ld_a_n },{C2, ld_lp0_n },{C2, ld_lp1_n },{C2, ld_lp2_n },{C2, ld_b_n },
+ {C2, add_a_n },{C2, sub_a_n },{C2, and_a_n },{C2, or_a_n },{C2, djnz_lp0 },{C2, djnz_lp1 },{C2, djnz_lp2 },{C2, jnz },
+ {C2, jc },{C2, jz },{C2, jmp },{C2,undefined2},{C2, op_d4 },{C2, op_d5 },{C2,undefined2},{C2, undefined2},
+ {C2, undefined2 },{C2,undefined2},{C2,cmp_a_n },{C2,undefined2},{C2,undefined2},{C2,undefined2},{C2,undefined2},{C2, call},
+/* E0 : 8301 */
+ {C1, dec_ix0 },{C1, undefined},{C1, undefined},{C1, ld_a_b },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},
+ {C1, ld_ix0_a },{C1, ld_ix1_a },{C1, ld_ix2_a },{C1, ld_b_a },{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},
+ {C1, undefined },{C1,ld_ix2_ix0},{C1, undefined},{C1, undefined},{C1, undefined},{C1, undefined},{C1, op_f6 },{C1, undefined},
+ {C1, op_f8 },{C1, op_f9 },{C1, add_a_cf },{C1, undefined},{C1, tst_a },{C1, clr_a },{C1,ld_a_ix0_a},{C1, ret }
+};
+#endif
+
+/****************************************************************************
+ * Initialize emulation
+ ****************************************************************************/
+static void ALPHA8201_init (int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ state_save_register_item_array("ALPHA8201", index, R.RAM);
+ state_save_register_item("ALPHA8201", index, R.PREVPC);
+ state_save_register_item("ALPHA8201", index, PC);
+ state_save_register_item("ALPHA8201", index, regPTR);
+ state_save_register_item("ALPHA8201", index, R.zf);
+ state_save_register_item("ALPHA8201", index, R.cf);
+ state_save_register_item("ALPHA8201", index, R.mb);
+#if HANDLE_HALT_LINE
+ state_save_register_item("ALPHA8201", index, R.halt);
+#endif
+ state_save_register_item("ALPHA8201", index, IX0);
+ state_save_register_item("ALPHA8201", index, IX1);
+ state_save_register_item("ALPHA8201", index, IX2);
+ state_save_register_item("ALPHA8201", index, LP0);
+ state_save_register_item("ALPHA8201", index, LP1);
+ state_save_register_item("ALPHA8201", index, LP2);
+ state_save_register_item("ALPHA8201", index, R.A);
+ state_save_register_item("ALPHA8201", index, R.B);
+}
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+static void ALPHA8201_reset (void)
+{
+ PC = 0;
+ regPTR = 0;
+ ZF = 0;
+ CF = 0;
+ R.mb = 0;
+ BIX0 = 0;
+ BIX1 = 0;
+ BIX2 = 0;
+ LP0 = 0;
+ LP1 = 0;
+ LP2 = 0;
+ R.A = 0;
+ R.B = 0;
+#if HANDLE_HALT_LINE
+ R.halt = 0;
+#endif
+/* memset(R.RAM, 0, sizeof(R.RAM)); */
+}
+
+/****************************************************************************
+ * Shut down CPU emulation
+ ****************************************************************************/
+static void ALPHA8201_exit (void)
+{
+ /* nothing to do ? */
+}
+
+/****************************************************************************
+ * Execute cycles CPU cycles. Return number of cycles really executed
+ ****************************************************************************/
+
+static int alpha8xxx_execute(const s_opcode *op_map,int cycles)
+{
+ unsigned opcode;
+ UINT8 pcptr;
+
+ ALPHA8201_ICount = cycles;
+
+#if HANDLE_HALT_LINE
+ if(R.halt)
+ return cycles;
+#endif
+
+ /* setup address bank & fall safe */
+ R.ix0.b.h =
+ R.ix1.b.h =
+ R.ix2.b.h = (R.pc.b.h &= 3);
+
+ /* reset start hack */
+ if(PC<0x20)
+ R.mb |= 0x08;
+
+ do
+ {
+ if(R.mb & 0x08)
+ {
+ pcptr = M_RDMEM(0x001) & 0x1f; /* pointer of entry point */
+ ALPHA8201_ICount -= C1;
+
+ /* entry point scan phase */
+ if( (pcptr&1) == 0)
+ {
+ /* EVEN , get PC low */
+ R.pc.b.l = M_RDMEM(pcptr);
+//mame_printf_debug("ALPHA8201 load PCL ENTRY=%02X PCL=%02X\n",pcptr, R.pc.b.l);
+ ALPHA8201_ICount -= C1;
+ M_WRMEM(0x001,pcptr+1);
+ continue;
+ }
+
+ /* ODD , check HALT flag */
+ R.mb = M_RDMEM(pcptr) & (0x08|0x03);
+ ALPHA8201_ICount -= C1;
+
+ /* not entryaddress 000,001 */
+ if(pcptr<2) R.mb |= 0x08;
+
+ if(R.mb & 0x08)
+ {
+ /* HALTED current entry point . next one */
+ pcptr = (pcptr+1)&0x1f;
+ M_WRMEM(0x001,pcptr);
+ ALPHA8201_ICount -= C1;
+ continue;
+ }
+
+ /* goto run phase */
+ M_JMP(R.pc.b.l);
+
+#if SHOW_ENTRY_POINT
+logerror("ALPHA8201 START ENTRY=%02X PC=%03X\n",pcptr,PC);
+mame_printf_debug("ALPHA8201 START ENTRY=%02X PC=%03X\n",pcptr,PC);
+#endif
+ }
+
+ /* run */
+ R.PREVPC = PC;
+ CALL_MAME_DEBUG;
+ opcode =M_RDOP(PC);
+#if TRACE_PC
+mame_printf_debug("ALPHA8201: PC = %03x, opcode = %02x\n", PC, opcode);
+#endif
+ PCL++;
+ inst_cycles = op_map[opcode].cycles;
+ (*(op_map[opcode].function))();
+ ALPHA8201_ICount -= inst_cycles;
+ } while (ALPHA8201_ICount>0);
+
+ return cycles - ALPHA8201_ICount;
+}
+
+#if (HAS_ALPHA8201)
+static int ALPHA8201_execute(int cycles) { return alpha8xxx_execute(opcode_8201,cycles); }
+#endif
+
+#if (HAS_ALPHA8301)
+static int ALPHA8301_execute(int cycles) { return alpha8xxx_execute(opcode_8301,cycles); }
+#endif
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void ALPHA8201_get_context (void *dst)
+{
+ if( dst )
+ *(ALPHA8201_Regs*)dst = R;
+}
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void ALPHA8201_set_context (void *src)
+{
+ if( src )
+ R = *(ALPHA8201_Regs*)src;
+}
+
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+#if HANDLE_HALT_LINE
+static void set_irq_line(int irqline, int state)
+{
+ if(irqline == INPUT_LINE_HALT)
+ {
+ R.halt = (state==ASSERT_LINE) ? 1 : 0;
+/* mame_printf_debug("ALPHA8201 HALT %d\n",R.halt); */
+ change_pc(PC);
+ }
+}
+#endif
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void ALPHA8201_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+#if HANDLE_HALT_LINE
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_HALT: set_irq_line(INPUT_LINE_HALT, info->i); break;
+#endif
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ALPHA8201_PC: PC = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + ALPHA8201_SP: M_WRMEM(0x001,info->i); break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_RB: regPTR = (info->i & 7)<<3; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_MB: R.mb = info->i & 0x03; break;
+#if 0
+ case CPUINFO_INT_REGISTER + ALPHA8201_ZF: R.zf= info->i & 0x01; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_CF: R.cf= info->i & 0x01; break;
+#endif
+ case CPUINFO_INT_REGISTER + ALPHA8201_IX0: IX0 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_IX1: IX1 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_IX2: IX2 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_LP0: LP0 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_LP1: LP1 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_LP2: LP2 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_A: R.A = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_B: R.B = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R0: R0 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R1: R1 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R2: R2 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R3: R3 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R4: R4 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R5: R5 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R6: R6 = info->i; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R7: R7 = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+/* 8201 and 8301 */
+static void alpha8xxx_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(R); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 16; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 10; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 6; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+#if HANDLE_HALT_LINE
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_HALT: info->i = R.halt ? ASSERT_LINE : CLEAR_LINE; break;
+#endif
+ case CPUINFO_INT_PREVIOUSPC: info->i = R.PREVPC; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ALPHA8201_PC: info->i = PC & 0x3ff; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + ALPHA8201_SP: info->i = M_RDMEM(0x001); break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_RB: info->i = regPTR; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_MB: info->i = R.mb; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_ZF: info->i = ZF; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_CF: info->i = CF; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_IX0: info->i = IX0; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_IX1: info->i = IX1; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_IX2: info->i = IX2; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_LP0: info->i = LP0; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_LP1: info->i = LP1; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_LP2: info->i = LP2; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_A: info->i = R.A; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_B: info->i = R.B; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R0: info->i = R0; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R1: info->i = R1; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R2: info->i = R2; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R3: info->i = R3; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R4: info->i = R4; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R5: info->i = R5; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R6: info->i = R6; break;
+ case CPUINFO_INT_REGISTER + ALPHA8201_R7: info->i = R7; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ALPHA8201_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ALPHA8201_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ALPHA8201_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = ALPHA8201_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ALPHA8201_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ALPHA8201_exit; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ALPHA8201_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ALPHA8201_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "AlphaDenshi MCU"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.1"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2006 by Tatsuyuki Satoh"); break;
+ case CPUINFO_STR_FLAGS: sprintf(info->s, "%c%c", CF?'C':'.',ZF?'Z':'.'); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_PC: sprintf(info->s, "PC:%03X", PC); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_SP: sprintf(info->s, "SP:%02X", M_RDMEM(0x001) ); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_RB: sprintf(info->s, "RB:%02X", regPTR>>3); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_MB: sprintf(info->s, "MB:%X", R.mb); break;
+#if 0
+ case CPUINFO_STR_REGISTER + ALPHA8201_ZF: sprintf(info->s, "ZF:%X", R.zf); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_CF: sprintf(info->s, "CF:%X", R.cf); break;
+#endif
+ case CPUINFO_STR_REGISTER + ALPHA8201_IX0: sprintf(info->s, "IX0:%02X", IX0); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_IX1: sprintf(info->s, "IX1:%02X", IX1); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_IX2: sprintf(info->s, "IX2:%02X", IX2); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_LP0: sprintf(info->s, "LP0:%02X", LP0); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_LP1: sprintf(info->s, "LP1:%02X", LP1); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_LP2: sprintf(info->s, "LP2:%02X", LP2); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_A: sprintf(info->s, "A:%02X", R.A); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_B: sprintf(info->s, "B:%02X", R.B); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_R0: sprintf(info->s, "R0:%02X", R0); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_R1: sprintf(info->s, "R1:%02X", R1); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_R2: sprintf(info->s, "R2:%02X", R2); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_R3: sprintf(info->s, "R3:%02X", R3); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_R4: sprintf(info->s, "R4:%02X", R4); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_R5: sprintf(info->s, "R5:%02X", R5); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_R6: sprintf(info->s, "R6:%02X", R6); break;
+ case CPUINFO_STR_REGISTER + ALPHA8201_R7: sprintf(info->s, "R7:%02X", R7); break;
+ }
+}
+#if (HAS_ALPHA8201)
+void alpha8201_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_STR_NAME: strcpy(info->s, "ALPHA-8201"); break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ALPHA8201_execute; break;
+ default:
+ /* 8201 / 8301 */
+ alpha8xxx_get_info(state,info);
+ }
+}
+#endif
+
+#if (HAS_ALPHA8301)
+void alpha8301_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_STR_NAME: strcpy(info->s, "ALPHA-8301"); break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ALPHA8301_execute; break;
+ default:
+ /* 8201 / 8301 */
+ alpha8xxx_get_info(state,info);
+ }
+}
+#endif
diff --git a/src/emu/cpu/alph8201/alph8201.h b/src/emu/cpu/alph8201/alph8201.h
new file mode 100644
index 00000000000..0457ea42ac8
--- /dev/null
+++ b/src/emu/cpu/alph8201/alph8201.h
@@ -0,0 +1,72 @@
+ /**************************************************************************\
+ * Alpha8201 Emulator *
+ * *
+ * Copyright (C) 2006 Tatsuyuki Satoh *
+ * Originally written for the MAME project. *
+ * *
+ * *
+ \**************************************************************************/
+
+#ifndef _ALPH8202_H
+#define _ALPH8202_H
+
+#ifndef INLINE
+#define INLINE static inline
+#endif
+
+#include "cpuintrf.h"
+
+enum {
+ ALPHA8201_PC=1,
+ ALPHA8201_SP,
+ ALPHA8201_RB,
+ ALPHA8201_MB,
+//
+ ALPHA8201_CF,
+ ALPHA8201_ZF,
+//
+ ALPHA8201_IX0,
+ ALPHA8201_IX1,
+ ALPHA8201_IX2,
+ ALPHA8201_LP0,
+ ALPHA8201_LP1,
+ ALPHA8201_LP2,
+ ALPHA8201_A,
+ ALPHA8201_B,
+//
+ ALPHA8201_R0,ALPHA8201_R1,ALPHA8201_R2,ALPHA8201_R3,
+ ALPHA8201_R4,ALPHA8201_R5,ALPHA8201_R6,ALPHA8201_R7
+};
+
+extern void ALPHA8201_get_info(UINT32 state, cpuinfo *info);
+extern void ALPHA8301_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ * Read a UINT8 from given memory location
+ */
+#define ALPHA8201_RDMEM(A) ((unsigned)program_read_byte_8(A))
+
+/*
+ * Write a UINT8 to given memory location
+ */
+#define ALPHA8201_WRMEM(A,V) (program_write_byte_8(A,V))
+
+/*
+ * ALPHA8201_RDOP() is identical to ALPHA8201_RDMEM() except it is used for reading
+ * opcodes. In case of system with memory mapped I/O, this function can be
+ * used to greatly speed up emulation
+ */
+#define ALPHA8201_RDOP(A) ((unsigned)cpu_readop(A))
+
+/*
+ * ALPHA8201_RDOP_ARG() is identical to ALPHA8201_RDOP() except it is used for reading
+ * opcode arguments. This difference can be used to support systems that
+ * use different encoding mechanisms for opcodes and opcode arguments
+ */
+#define ALPHA8201_RDOP_ARG(A) ((unsigned)cpu_readop_arg(A))
+
+#ifdef MAME_DEBUG
+offs_t ALPHA8201_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _ALPHA8201_H */
diff --git a/src/emu/cpu/apexc/apexc.c b/src/emu/cpu/apexc/apexc.c
new file mode 100644
index 00000000000..ba683a7c2f1
--- /dev/null
+++ b/src/emu/cpu/apexc/apexc.c
@@ -0,0 +1,922 @@
+/*
+ cpu/apexc/apexc.c: APE(X)C CPU emulation
+
+ By Raphael Nabet
+
+ APE(X)C (All Purpose Electronic X-ray Computer) was a computer built by Andrew D. Booth
+ and others for the Birkbeck College, in London, which was used to compute cristal
+ structure using X-ray diffraction.
+
+ It was one of the APEC series of computer, which were simple electronic computers
+ built in the early 1950s for various British Universities. Known members of this series
+ are:
+ * APE(X)C: Birkbeck College, London (before 1953 (1951?))
+ * APE(N)C: Board of Mathematical Machines, Oslo
+ * APE(H)C: British Tabulating Machine Company
+ * APE(R)C: British Rayon Research Association
+ * UCC: University College, London (circa january 1956)
+ * MAC (Magnetic Automatic Calculator): "built by Wharf Engineering Laboratories"
+ (february 1955), which used some germanium diodes
+ * The HEC (built by the British Tabulating Machine Company), a commercial machine sold
+ in two models at least (HEC 2M and HEC 4) (before 1955)
+
+ References:
+ * Andrew D. Booth & Kathleen H. V. Booth: Automatic Digital Calculators, 2nd edition
+ (Buttersworth Scientific Publications, 1956) (referred to as 'Booth&Booth')
+ * Kathleen H. V. Booth: Programming for an Automatic Digital Calculator
+ (Buttersworth Scientific Publications, 1958) (referred to as 'Booth')
+ * Digital Engineering Newsletter vol 7 nb 1 p 60 and vol 8 nb 1 p 60-61 provided some
+ dates
+*/
+
+/*
+ Generals specs:
+ * 32-bit data word size (10-bit addresses): uses fixed-point, 2's complement arithmetic
+ * CPU has one accumulator (A) and one register (R), plus a Control Register (this is
+ what we would call an "instruction register" nowadays). No Program Counter, each
+ instruction contains the address of the next instruction (!).
+ * memory is composed of 256 (maximal value only found on the UCC - APE(X)C only has
+ 32 tracks) circular magnetic tracks of 32 words: only 32 tracks can
+ be accessed at a time (the 16 first ones, plus 16 others chosen by the programmer),
+ and the rotation rate is 3750rpm (62.5 rotations per second).
+ * two I/O units: tape reader and tape puncher. A teletyper was designed to read
+ specially-encoded punched tapes and print decoded text. (See /systems/apexc.c)
+ * machine code has 15 instructions (!), including add, substract, shift, multiply (!),
+ test and branch, input and punch. A so-called vector mode allow to repeat the same
+ operation 32 times with 32 successive memory locations. Note the lack of bitwise
+ and/or/xor (!) .
+ * 1 kIPS, although memory access times make this figure fairly theorical (drum rotation
+ time: 16ms, which would allow about 60IPS when no optimization is made)
+ * there is no indirect addressing whatever, although dynamic modification of opcodes (!)
+ allows to simulate it...
+ * a control panel allows operation and debugging of the machine. (See /systems/apexc.c)
+
+ Conventions:
+ Bits are numbered in big-endian order, starting with 1: bit #1 is the
+ MSBit, and bit #32 is the LSBit.
+
+ References:
+ * Andrew D. Booth & Kathleen H. V. Booth: Automatic Digital Calculators, 2nd edition
+ (Buttersworth Scientific Publications, 1956)
+ * Kathleen H. V. Booth: Programming for an Automatic Digital Calculator
+ (Buttersworth Scientific Publications, 1958)
+*/
+
+/*
+ Machine code (reference: Booth):
+
+ Format of a machine instruction:
+bits: 1-5 6-10 11-15 16-20 21-25 26-31 32
+field: X address X address Y address Y address Function C6 Vector
+ (track) (location) (track) (location)
+
+ Meaning of fields:
+ X: address of an operand, or immediate, or meaningless, depending on Function
+ (When X is meaningless, it should be a duplicate of Y. Maybe this is because
+ X is unintentionnally loaded into the memory address register, and if track # is
+ different, we add unneeded track switch delays (this theory is either wrong or
+ incomplete, since it cannot be true for B or X))
+ Y: address of the next instruction
+ Function: code for the actual instruction executed
+ C6: immediate value used by shift, multiply and store operations
+ Vector: repeat operation 32 times (on all 32 consecutive locations of a track,
+ starting with the location given by the X field)
+
+ Function code:
+ # Mnemonic C6 Description
+
+ 0 Stop
+
+ 2 I(y) Input. A 5-bit word is read from tape and loaded
+ into the 5 MSBits of R. (These bits of R must be
+ cleared initially.)
+
+ 4 P(y) Punch. The 5 MSBits of R are punched onto the
+ output tape.
+
+ 6 B<(x)>=(y) Branch. If A<0, next instruction is fetched from @x, whereas
+ if A>=0, next instruction is fetched from @y
+
+ 8 l (y) n Shift left: the 64 bits of A and R are rotated left n times.
+ n
+
+ 10 r (y) 64-n Shift right: the 64 bits of A and R are shifted right n times.
+ n The sign bit of A is duplicated.
+
+ 14 X (x)(y) 33-n Multiply the contents of *track* x by the last n digits of the
+ n number in R, sending the 32 MSBs to A and 31 LSBs to R
+
+ 16 +c(x)(y) A <- (x)
+
+ 18 -c(x)(y) A <- -(x)
+
+ 20 +(x)(y) A <- A+(x)
+
+ 22 -(x)(y) A <- A-(x)
+
+ 24 T(x)(y) R <- (x)
+
+ 26 R (x)(y) 32+n Store first or last bits of R into (x). The remaining bits of (x)
+ 1-n are unaffected. "The contents of R are filled with 0s or 1s
+ according as the original contents were positive or negative".
+ R (x)(y) n-1
+ n-32
+
+ 28 A (x)(y) 32+n Same as 26, except that source is A, and the contents of A are
+ 1-n not modified.
+
+ A (x)(y) n-1
+ n-32
+
+ 30 S(x)(y) Block Head switch. This enables the block of heads specified
+ in x to be loaded into the working store.
+
+ Note: Mnemonics use subscripts (!), which I tried to render the best I could. Also,
+ ">=" is actually one single character. Last, "1-n" and "n-32" in store mnemonics
+ are the actual sequences "1 *DASH* <number n>" and "<number n> *DASH* 32"
+ (these are NOT formulas with substract signs).
+
+ Note2: Short-hand notations: X stands for X , A for A , and R for R .
+ 32 1-32 1-32
+
+ Note3: Vectors instruction are notated with a subscript 'v' following the basic
+ mnemonic. For instance:
+
+ A (x)(y), + (x)(y)
+ v v
+
+ are the vector counterparts of A(x)(y) and +(x)(y).
+
+
+
+
+ Note that the code has been presented so far as it was in 1957. It appears that
+ it was somewhat different in 1953 (Booth&Booth):
+
+ Format of a machine instruction:
+ Format for r, l, A:
+bits: 1-9 10-15 16-17 18-21 22-30 31-32
+field: X address C6 spare Function Y address spare
+ Format for other instructions:
+bits: 1-9 10-17 18-21 22-30 31-32
+field: X address D Function Y address D (part 2)
+
+ Meaning of fields:
+ D (i.e. drum #): MSBs for the address of the X operand. I don't know whether this feature
+ was actually implemented, since it is said in Booth&Booth that the APE(X)C does
+ not use this feature (it had only one drum of 16 tracks at the time, hence the 9
+ address bits).
+
+ Function code:
+ # Mnemonic C6 Description
+
+ 1 A (x)(y) 32+n(?) record first bits of A in (x). The remaining bits of x
+ 1-n are unaffected.
+
+ 2 +c(x)(y) A <- (x)
+
+ 3 -c(x)(y) A <- -(x)
+
+ 4 +(x)(y) A <- A+(x)
+
+ 5 -(x)(y) A <- A-(x)
+
+ 6 T(x)(y) R <- (x)
+
+ 7 X (x)(y) Multiply the contents of (x) by the number in R,
+ sending the 32 MSBs to A and 31 LSBs to R
+
+ 8 r (y) 64-n(?) Shift right: the 64 bits of A and R are shifted right n times.
+ n The sign bit of A is duplicated.
+
+ 9 l (y) n(?) Shift left: the 64 bits of A and R are rotated left n times.
+ n
+
+ 10 R (x)(y) 32+n record R into (x).
+ 1-n "the contents of R are filled with 0s or 1s
+ according as the original contents were positive or negative".
+
+ 11 B<(x)>=(y) Branch. If A<0, next instruction is read from @x, whereas
+ if A>=0, next instruction is read from @y
+
+ 12 Print(y) Punch. Contents of A are printed.
+
+ 13 C(d+x) branch ("switch Control") to instruction located in position
+ (D:X)
+
+ 14 Stop
+
+ You will notice the absence of input instruction. It seems that program and data were
+ meant to be entered with a teletyper or a card reader located on the control panel.
+
+ I don't know whether this computer really was in operation with this code. Handle
+ these info with caution.
+*/
+
+/*
+ memory interface:
+
+ Data is exchanged on a 1-bit (!) data bus, 10-bit address bus.
+
+ While the bus is 1-bit wide, read/write operation can only be take place on word
+ (i.e. 32 bit) boundaries. However, it is possible to store only the n first bits or
+ n last bits of a word, leaving other bits in memory unaffected.
+
+ The LSBits are transferred first, since this enables to perform bit-per-bit add and
+ substract. Otherwise, the CPU would need an additionnal register to store the second
+ operand, and it would be probably slower, since the operation could only
+ take place after all the data has been transfered.
+
+ Memory operations are synchronous with 2 clocks found on the memory controller:
+ * word clock: a pulse on each word boundary (3750rpm*32 -> 2kHz)
+ * bit clock: a pulse when a bit is present on the bus (word clock * 32 -> 64kHz)
+
+ CPU operation is synchronous with these clocks, too. For instance, the AU does bit-per-bit
+ addition and substraction with a memory operand, synchronously with bit clock,
+ starting and stopping on word clock boundaries. Similar thing with a Fetch operation.
+
+ There is a 10-bit memory location (i.e. address) register on the memory controller.
+ It is loaded with the contents of X after when instruction fetch is complete, and
+ with the contents of Y when instruction execution is complete, so that the next fetch
+ can be executed correctly.
+*/
+
+/*
+ Instruction timings:
+
+
+ References: Booth p. 14 for the table below
+
+
+ Mnemonic delay in word clock cycles
+
+ I 32
+
+ P 32
+
+ B 0
+
+ l 1 if n>=32 (i.e. C6>=32) (see 4.)
+ n 2 if n<32 (i.e. C6<32)
+
+ r 1 if n<=32 (i.e. C6>=32) (see 4.)
+ n 2 if n>32 (i.e. C6<32)
+
+ X 32
+
+ +c, -c, +, -, T 0
+
+ R , R , A , A 1 (see 1. & 4.)
+ 1-n n-32 1-n n-32
+
+ track switch 6 (see 2.)
+
+ vector 12 (see 3.)
+
+
+ (S and stop are missing in the table)
+
+
+ Note that you must add the fetch delay (at least 1 cycle), and, when applicable, the
+ operand read/write delay (at least 1 cycle).
+
+
+ Notes:
+
+ 1. The delay is applied after the store is done (from the analysis of the example
+ in Booth p.52)
+
+ 2. I guess that the memory controller needs 6 cycles to stabilize whenever track
+ switching occurs, i.e. when X does not refer to the current track, and then when Y
+ does not refer to the same track as X. This matches various examples in Booth,
+ although it appears that this delay is not applied when X is not read (cf cross-track
+ B in Booth p. 49).
+ However, and here comes the wacky part, analysis of Booth p. 55 shows that
+ no additionnal delay is caused by an X instruction having its X operand
+ on another track. Maybe, just maybe, this is related to the fact that X does not
+ need to take the word count into account, any word in track is as good as any (yet,
+ this leaves the question of why this optimization could not be applied to vector
+ operations unanswered).
+
+ 3. This is an ambiguous statement. Analysis of Booth p. 55 shows that
+ an instance of an Av instruction with its destination on another track takes no more
+ than 45 cycles, as follow:
+ * 1 cycle for fetch
+ * 6-cycle delay (at most) before write starts (-> track switch)
+ * 32 memory cycles
+ * 6-cycle delay (at most) after write completion (-> track switch)
+ It appears that the delay associated with the vector mode is not distinguishable from
+ the delay caused by track switch and even the delay associated to the Av instruction.
+ Is there really a specific delay associated with the vector mode? To know this, we
+ would need to see a vector instruction on the same track as its operands, which is
+ unlikely to be seen (the only reasonnable application I can see is running a '+_v'
+ to compute the checksum of the current track).
+
+ 4. Example in Booth p. 76 ("20/4 A (27/27) (21/2)") seems to imply that
+ when doing a store with a destination on a track other than the track where next
+ instruction is located, the 1-cycle post-store delay is merged with the 6-cycle track
+ switch delay. (I assume this because there is lots of room on track 21, and if
+ the delays were not merged, it should be easy to move the instruction forward
+ to speed up loop execution time.
+ Similarly, example in Booth p. 49-50 ("4/24 l 32 (5/31)") seems to show that
+ a similar delay merge occurs when doing a shift with the next instruction located on
+ another track.
+*/
+
+#include "cpuintrf.h"
+#include "apexc.h"
+#include "debugger.h"
+
+typedef struct
+{
+ UINT32 a; /* accumulator */
+ UINT32 r; /* register */
+ UINT32 cr; /* control register (i.e. instruction register) */
+ int ml; /* memory location (current track in working store, and requested
+ word position within track) (10 bits) */
+ int working_store; /* current working store (group of 16 tracks) (1-15) */
+ int current_word; /* current word position within track (0-31) */
+
+ int running; /* 1 flag: */
+ /* running: flag implied by the existence of the stop instruction */
+} apexc_regs;
+
+static apexc_regs apexc;
+
+int apexc_ICount;
+
+/* decrement ICount by n */
+#define DELAY(n) {apexc_ICount -= (n); apexc.current_word = (apexc.current_word + (n)) & 0x1f;}
+
+
+/*
+ word accessor functions
+
+ take a 10-bit word address
+ 5 bits (MSBs): track address within working store
+ 5 bits (LSBs): word position within track
+
+ 'special' flag: if true, read first word found in track (used by X instruction only)
+
+ 'mask': one bit is set for each bit to write (used by store instructions)
+
+ memory latency delays are taken into account, but not track switching delays
+*/
+
+/* compute complete word address (i.e. translate a logical track address (expressed
+in current working store) to an absolute track address) */
+static int effective_address(int address)
+{
+ if (address & 0x200)
+ {
+ address = (address & 0x1FF) | (apexc.working_store) << 9;
+ }
+
+ return address;
+}
+
+/* read word */
+static UINT32 word_read(int address, int special)
+{
+ UINT32 result;
+
+ /* compute absolute track address */
+ address = effective_address(address);
+
+ if (special)
+ {
+ /* ignore word position in x - use current position instead */
+ address = (address & ~ 0x1f) | apexc.current_word;
+ }
+ else
+ {
+ /* wait for requested word to appear under the heads */
+ DELAY(((address /*& 0x1f*/) - apexc.current_word) & 0x1f);
+ }
+
+ /* read 32 bits */
+#if 0
+ /* note that the APEXC reads LSBits first */
+ result = 0;
+ for (i=0; i<31; i++)
+ {
+ /*if (mask & (1 << i))*/
+ result |= bit_read((address << 5) | i) << i;
+ }
+#else
+ result = apexc_readmem(address);
+#endif
+
+ /* read takes one memory cycle */
+ DELAY(1);
+
+ return result;
+}
+
+/* write word (or part of a word, according to mask) */
+static void word_write(int address, UINT32 data, UINT32 mask)
+{
+ /* compute absolute track address */
+ address = effective_address(address);
+
+ /* wait for requested word to appear under the heads */
+ DELAY(((address /*& 0x1f*/) - apexc.current_word) & 0x1f);
+
+ /* write 32 bits according to mask */
+#if 0
+ /* note that the APEXC reads LSBits first */
+ for (i=0; i<31; i++)
+ {
+ if (mask & (1 << i))
+ bit_write((address << 5) | i, (data >> i) & 1);
+ }
+#else
+ apexc_writemem_masked(address, data, mask);
+#endif
+
+ /* write takes one memory cycle (2, actually, but the 2nd cycle is taken into
+ account in execute) */
+ DELAY(1);
+}
+
+/*
+ I/O accessors
+
+ no address is used, these functions just punch or read 5 bits
+*/
+
+static int papertape_read(void)
+{
+ return io_read_byte_8(0) & 0x1f;
+}
+
+static void papertape_punch(int data)
+{
+ io_write_byte_8(0, data);
+}
+
+/*
+ now for emulation code
+*/
+
+/*
+ set the memory location (i.e. address) register, and compute the associated delay
+*/
+INLINE int load_ml(int address, int vector)
+{
+ int delay;
+
+ /* additionnal delay appears if we switch tracks */
+ if (((apexc.ml & 0x3E0) != (address & 0x3E0)) /*|| vector*/)
+ delay = 6; /* if tracks are different, delay to allow for track switching */
+ else
+ delay = 0; /* else, no problem */
+
+ apexc.ml = address; /* save ml */
+
+ return delay;
+}
+
+/*
+ execute one instruction
+
+ TODO:
+ * test!!!
+
+ NOTE:
+ * I do not know whether we should fetch instructions at the beginning or the end of the
+ instruction cycle. Either solution is roughly equivalent to the other, but changes
+ the control panel operation (and I know virtually nothing on the control panel).
+ Currently, I fetch each instruction right after executing the previous instruction, so that
+ the user may enter an instruction into the control register with the control panel, then
+ execute it.
+ This solution makes timing simulation much simpler, too.
+*/
+static void execute(void)
+{
+ int x, y, function, c6, vector; /* instruction fields */
+ int i = 0; /* misc counter */
+ int has_operand; /* true if instruction is an AU operation with an X operand */
+ static const char has_operand_table[32] = /* table for has_operand - one entry for each function code */
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0
+ };
+ int delay1; /* pre-operand-access delay */
+ int delay2; /* post-operation delay */
+ int delay3; /* pre-operand-fetch delay */
+
+ /* first isolate the instruction fields */
+ x = (apexc.cr >> 22) & 0x3FF;
+ y = (apexc.cr >> 12) & 0x3FF;
+ function = (apexc.cr >> 7) & 0x1F;
+ c6 = (apexc.cr >> 1) & 0x3F;
+ vector = apexc.cr & 1;
+
+ function &= 0x1E; /* this is a mere guess - the LSBit is reserved for future additions */
+
+ /* determinates if we need to read an operand*/
+ has_operand = has_operand_table[function];
+
+ if (has_operand)
+ {
+ /* load ml with X */
+ delay1 = load_ml(x, vector);
+ /* burn pre-operand-access delay if needed */
+ if (delay1)
+ {
+ DELAY(delay1);
+ }
+ }
+
+ delay2 = 0; /* default */
+
+ do
+ {
+ switch (function)
+ {
+ case 0:
+ /* stop */
+
+ apexc.running = FALSE;
+
+ /* BTW, I don't know whether stop loads y into ml or not, and whether
+ subsequent fetch is done */
+ break;
+
+ case 2:
+ /* I */
+ /* I do not know whether the CPU does an OR or whatever, but since docs say that
+ the 5 bits must be cleared initially, an OR kind of makes sense */
+ apexc.r |= papertape_read() << 27;
+ delay2 = 32; /* no idea whether this should be counted as an absolute delay
+ or as a value in delay2 */
+ break;
+
+ case 4:
+ /* P */
+ papertape_punch((apexc.r >> 27) & 0x1f);
+ delay2 = 32; /* no idea whether this should be counted as an absolute delay
+ or as a value in delay2 */
+ break;
+
+ case 6:
+ /* B<(x)>=(y) */
+ /* I have no idea what we should do if the vector bit is set */
+ if (apexc.a & 0x80000000UL)
+ {
+ /* load ml with X */
+ delay1 = load_ml(x, vector);
+ /* burn pre-fetch delay if needed */
+ if (delay1)
+ {
+ DELAY(delay1);
+ }
+ /* and do fetch at X */
+ goto special_fetch;
+ }
+ /* else, the instruction ends with a normal fetch */
+ break;
+
+ case 8:
+ /* l_n */
+ delay2 = (c6 & 0x20) ? 1 : 2; /* if more than 32 shifts, it takes more time */
+
+ /* Yes, this code is inefficient, but this must be the way the APEXC does it ;-) */
+ while (c6 != 0)
+ {
+ int shifted_bit = 0;
+
+ /* shift and increment c6 */
+ shifted_bit = apexc.r & 1;
+ apexc.r >>= 1;
+ if (apexc.a & 1)
+ apexc.r |= 0x80000000UL;
+ apexc.a >>= 1;
+ if (shifted_bit)
+ apexc.a |= 0x80000000UL;
+
+ c6 = (c6+1) & 0x3f;
+ }
+
+ break;
+
+ case 10:
+ /* r_n */
+ delay2 = (c6 & 0x20) ? 1 : 2; /* if more than 32 shifts, it takes more time */
+
+ /* Yes, this code is inefficient, but this must be the way the APEXC does it ;-) */
+ while (c6 != 0)
+ {
+ /* shift and increment c6 */
+ apexc.r >>= 1;
+ if (apexc.a & 1)
+ apexc.r |= 0x80000000UL;
+ apexc.a = ((INT32) apexc.a) >> 1;
+
+ c6 = (c6+1) & 0x3f;
+ }
+
+ break;
+
+ case 12:
+ /* unused function code. I assume this results into a NOP, for lack of any
+ specific info... */
+
+ break;
+
+ case 14:
+ /* X_n(x) */
+
+ /* Yes, this code is inefficient, but this must be the way the APEXC does it ;-) */
+ /* algorithm found in Booth&Booth, p. 45-48 */
+ {
+ int shifted_bit;
+
+ apexc.a = 0;
+ shifted_bit = 0;
+ while (1)
+ {
+ /* note we read word at current word position */
+ if (shifted_bit && ! (apexc.r & 1))
+ apexc.a += word_read(x, 1);
+ else if ((! shifted_bit) && (apexc.r & 1))
+ apexc.a -= word_read(x, 1);
+ else
+ /* Even if we do not read anything, the loop still takes 1 cycle of
+ the memory word clock. */
+ /* Anyway, maybe we still read the data even if we do not use it. */
+ DELAY(1);
+
+ /* exit if c6 reached 32 ("c6 & 0x20" is simpler to implement and
+ essentially equivalent, so this is most likely the actual implementation) */
+ if (c6 & 0x20)
+ break;
+
+ /* else increment c6 and shift */
+ c6 = (c6+1) & 0x3f;
+
+ /* shift */
+ shifted_bit = apexc.r & 1;
+ apexc.r >>= 1;
+ if (apexc.a & 1)
+ apexc.r |= 0x80000000UL;
+ apexc.a = ((INT32) apexc.a) >> 1;
+ }
+ }
+
+ //DELAY(32); /* mmmh... we have already counted 32 wait states */
+ /* actually, if (n < 32) (which is an untypical case), we do not have 32 wait
+ states. Question is: do we really have 32 wait states if (n < 32), or is
+ the timing table incomplete? */
+ break;
+
+ case 16:
+ /* +c(x) */
+ apexc.a = + word_read(apexc.ml, 0);
+ break;
+
+ case 18:
+ /* -c(x) */
+ apexc.a = - word_read(apexc.ml, 0);
+ break;
+
+ case 20:
+ /* +(x) */
+ apexc.a += word_read(apexc.ml, 0);
+ break;
+
+ case 22:
+ /* -(x) */
+ apexc.a -= word_read(apexc.ml, 0);
+ break;
+
+ case 24:
+ /* T(x) */
+ apexc.r = word_read(apexc.ml, 0);
+ break;
+
+ case 26:
+ /* R_(1-n)(x) & R_(n-32)(x) */
+
+ {
+ UINT32 mask;
+
+ if (c6 & 0x20)
+ mask = 0xFFFFFFFFUL << (64 - c6);
+ else
+ mask = 0xFFFFFFFFUL >> c6;
+
+ word_write(apexc.ml, apexc.r, mask);
+ }
+
+ apexc.r = (apexc.r & 0x80000000UL) ? 0xFFFFFFFFUL : 0;
+
+ delay2 = 1;
+ break;
+
+ case 28:
+ /* A_(1-n)(x) & A_(n-32)(x) */
+
+ {
+ UINT32 mask;
+
+ if (c6 & 0x20)
+ mask = 0xFFFFFFFFUL << (64 - c6);
+ else
+ mask = 0xFFFFFFFFUL >> c6;
+
+ word_write(apexc.ml, apexc.a, mask);
+ }
+
+ delay2 = 1;
+ break;
+
+ case 30:
+ /* S(x) */
+ apexc.working_store = (x >> 5) & 0xf; /* or is it (x >> 6)? */
+ DELAY(32); /* no idea what the value is... All I know is that it takes much
+ more time than track switching (which takes 6 cycles) */
+ break;
+ }
+ if (vector)
+ /* increment word position in vector operations */
+ apexc.ml = (apexc.ml & 0x3E0) | ((apexc.ml + 1) & 0x1F);
+ } while (vector && has_operand && (++i < 32)); /* iterate 32 times if vector bit is set */
+ /* the has_operand is a mere guess */
+
+ /* load ml with Y */
+ delay3 = load_ml(y, 0);
+
+ /* compute max(delay2, delay3) */
+ if (delay2 > delay3)
+ delay3 = delay2;
+
+ /* burn pre-fetch delay if needed */
+ if (delay3)
+ {
+ DELAY(delay3);
+ }
+
+ /* entry point after a successful Branch (which alters the normal instruction sequence,
+ in order not to load ml with Y) */
+special_fetch:
+
+ /* fetch current instruction into control register */
+ apexc.cr = word_read(apexc.ml, 0);
+}
+
+
+static void apexc_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+}
+
+static void apexc_reset(void)
+{
+ /* mmmh... I don't know what happens on reset with an actual APEXC. */
+
+ apexc.working_store = 1; /* mere guess */
+ apexc.current_word = 0; /* well, we do have to start somewhere... */
+
+ /* next two lines are just the product of my bold fantasy */
+ apexc.cr = 0; /* first instruction executed will be a stop */
+ apexc.running = TRUE; /* this causes the CPU to load the instruction at 0/0,
+ which enables easy booting (just press run on the panel) */
+}
+
+static void apexc_get_context(void *dst)
+{
+ if (dst)
+ * ((apexc_regs*) dst) = apexc;
+}
+
+static void apexc_set_context(void *src)
+{
+ if (src)
+ apexc = * ((apexc_regs*)src);
+}
+
+static int apexc_execute(int cycles)
+{
+ apexc_ICount = cycles;
+
+ do
+ {
+ CALL_MAME_DEBUG;
+
+ if (apexc.running)
+ execute();
+ else
+ {
+ DELAY(apexc_ICount); /* burn cycles once for all */
+ }
+ } while (apexc_ICount > 0);
+
+ return cycles - apexc_ICount;
+}
+
+static void apexc_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ /*case CPUINFO_INT_INPUT_STATE + ...:*/ /* no interrupts */
+
+ case CPUINFO_INT_PC:
+ /* keep address 9 LSBits - 10th bit depends on whether we are accessing the permanent
+ track group or a switchable one */
+ apexc.ml = info->i & 0x1ff;
+ if (info->i & 0x1e00)
+ { /* we are accessing a switchable track group */
+ apexc.ml |= 0x200; /* set 10th bit */
+
+ if (((info->i >> 9) & 0xf) != apexc.working_store)
+ { /* we need to do a store switch */
+ apexc.working_store = ((info->i >> 9) & 0xf);
+ }
+ }
+ break;
+
+ case CPUINFO_INT_SP: (void) info->i; /* no SP */ break;
+
+ case CPUINFO_INT_REGISTER + APEXC_CR: apexc.cr = info->i; break;
+ case CPUINFO_INT_REGISTER + APEXC_A: apexc.a = info->i; break;
+ case CPUINFO_INT_REGISTER + APEXC_R: apexc.r = info->i; break;
+ case CPUINFO_INT_REGISTER + APEXC_ML: apexc.ml = info->i & 0x3ff; break;
+ case CPUINFO_INT_REGISTER + APEXC_WS: apexc.working_store = info->i & 0xf; break;
+ case CPUINFO_INT_REGISTER + APEXC_STATE: apexc.running = info->i ? TRUE : FALSE; break;
+ }
+}
+
+void apexc_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(apexc); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; /*don't care*/ break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; /* IIRC */ break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 75; /* IIRC */ break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 15; /*13+2 ignored bits to make double word address*/ break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = /*5*/8; /* no I/O bus, but we use address 0 for punchtape I/O */ break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = /*0*/1; /*0 is quite enough but the MAME core does not understand*/ break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_SP: info->i = 0; /* no SP */ break;
+ case CPUINFO_INT_PC:
+ /* no PC - return memory location register instead, this should be
+ equivalent unless executed in the midst of an instruction */
+ info->i = effective_address(apexc.ml);
+ break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* no PC */ break;
+
+ /*case CPUINFO_INT_INPUT_STATE + ...:*/ /* no interrupts */
+
+ case CPUINFO_INT_REGISTER + APEXC_CR: info->i = apexc.cr; break;
+ case CPUINFO_INT_REGISTER + APEXC_A: info->i = apexc.a; break;
+ case CPUINFO_INT_REGISTER + APEXC_R: info->i = apexc.r; break;
+ case CPUINFO_INT_REGISTER + APEXC_ML: info->i = apexc.ml; break;
+ case CPUINFO_INT_REGISTER + APEXC_WS: info->i = apexc.working_store; break;
+ case CPUINFO_INT_REGISTER + APEXC_STATE: info->i = apexc.running; break;
+ case CPUINFO_INT_REGISTER + APEXC_ML_FULL: info->i = effective_address(apexc.ml); break;
+
+ case CPUINFO_PTR_SET_INFO: info->setinfo = apexc_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = apexc_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = apexc_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = apexc_init; break;
+ case CPUINFO_PTR_RESET: info->reset = apexc_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = apexc_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = apexc_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &apexc_ICount; break;
+
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "APEXC"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "APEC"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "Raphael Nabet"); break;
+
+ case CPUINFO_STR_FLAGS: sprintf(info->s = cpuintrf_temp_str(), "%c", (apexc.running) ? 'R' : 'S'); break;
+
+ case CPUINFO_STR_REGISTER + APEXC_CR: sprintf(info->s = cpuintrf_temp_str(), "CR:%08X", apexc.cr); break;
+ case CPUINFO_STR_REGISTER + APEXC_A: sprintf(info->s = cpuintrf_temp_str(), "A :%08X", apexc.a); break;
+ case CPUINFO_STR_REGISTER + APEXC_R: sprintf(info->s = cpuintrf_temp_str(), "R :%08X", apexc.r); break;
+ case CPUINFO_STR_REGISTER + APEXC_ML: sprintf(info->s = cpuintrf_temp_str(), "ML:%03X", apexc.ml); break;
+ case CPUINFO_STR_REGISTER + APEXC_WS: sprintf(info->s = cpuintrf_temp_str(), "WS:%01X", apexc.working_store); break;
+
+ case CPUINFO_STR_REGISTER + APEXC_STATE: sprintf(info->s = cpuintrf_temp_str(), "CPU state:%01X", apexc.running ? TRUE : FALSE); break;
+ }
+}
diff --git a/src/emu/cpu/apexc/apexc.h b/src/emu/cpu/apexc/apexc.h
new file mode 100644
index 00000000000..47bee1f9653
--- /dev/null
+++ b/src/emu/cpu/apexc/apexc.h
@@ -0,0 +1,38 @@
+/* register names for apexc_get_reg & apexc_set_reg */
+enum
+{
+ APEXC_CR =1, /* control register */
+ APEXC_A, /* acumulator */
+ APEXC_R, /* register */
+ APEXC_ML, /* memory location */
+ APEXC_WS, /* working store */
+ APEXC_STATE, /* whether CPU is running */
+
+ APEXC_ML_FULL /* read-only pseudo-register for exclusive use by the control panel code
+ in the apexc driver : enables it to get the complete address computed
+ from the contents of ML and WS */
+};
+
+extern int apexc_ICount;
+
+void apexc_get_info(UINT32 state, cpuinfo *info);
+
+#ifndef SUPPORT_ODD_WORD_SIZES
+#define apexc_readmem(address) program_read_dword_32be((address)<<2)
+#define apexc_writemem(address, data) program_write_dword_32be((address)<<2, (data))
+/* eewww ! - Fortunately, there is no memory mapped I/O, so we can simulate masked write
+without danger */
+#define apexc_writemem_masked(address, data, mask) \
+ apexc_writemem((address), (apexc_readmem(address) & ~(mask)) | ((data) & (mask)))
+#else
+#define apexc_readmem(address) cpu_readmem13_32(address)
+#define apexc_writemem(address, data) cpu_writemem13_32((address), (data))
+#define apexc_writemem_masked(address, data, mask) cpu_writemem13_32masked((address), (data), (mask))
+#endif
+
+#ifdef MAME_DEBUG
+unsigned apexc_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+#define apexc_readop(address) apexc_readmem(address)
+
diff --git a/src/emu/cpu/apexc/apexcdsm.c b/src/emu/cpu/apexc/apexcdsm.c
new file mode 100644
index 00000000000..a9b99c52927
--- /dev/null
+++ b/src/emu/cpu/apexc/apexcdsm.c
@@ -0,0 +1,171 @@
+/*
+ cpu/apexc/apexcsm.c : APE(X)C CPU disassembler
+
+ By Raphael Nabet
+
+ see cpu/apexc.c for background and tech info
+*/
+
+
+#include "cpuintrf.h"
+#include "debugger.h"
+
+#include "apexc.h"
+
+/*
+ Here is the format used for debugger output.
+
+ Since the only assembler for the APEXC that I know of uses numerical data
+ (yes, mnemonics are numbers), I do not know if there is an official way of writing
+ APEXC assembly on a text terminal. The format I chose is closely inspired by
+ the assembly format found in Booth, but was slightly adapted to accomodate
+ the lack of subscripts and of a 'greater or equal' character.
+
+ Printed format Name
+ 0 1 2
+ 012345678901234567890123456
+ Stop (##/##) one_address
+ I (##/##) one_address
+ P (##/##) one_address
+ B <(##/##) >=(##/##) branch
+ l (##) (##/##) shiftl
+ r (##) (##/##) shiftr
+ Illegal (##/##) one_address
+ X (##) (##) (##/##) multiply
+ X (##) (##/##) multiply
+ +c (##/##) (##/##) two_address
+ -c (##/##) (##/##) two_address
+ + (##/##) (##/##) two_address
+ - (##/##) (##/##) two_address
+ T (##/##) (##/##) two_address
+ R (1-##) (##/##) (##/##) store
+ R (##-32) (##/##) (##/##) store
+ R (##/##) (##/##) store
+ A (1-##) (##/##) (##/##) store
+ A (##-32) (##/##) (##/##) store
+ A (##/##) (##/##) store
+ S (##) (##/##) swap
+ +--------++--------++-----+
+ mnemonic X field Y field
+ field
+
+ For vector instructions, replace the first space on the right of the mnemonic
+ with a 'v'.
+*/
+typedef struct instr_desc
+{
+ const char *mnemonic;
+ enum {branch, shiftl, shiftr, multiply, store, swap, one_address, two_address} format; /* -> X and Y are format */
+} instr_desc;
+
+static const instr_desc instructions[16] =
+{
+ { "Stop", one_address }, { "I", one_address },
+ { "P", one_address }, { "B", branch },
+ { "l", shiftl }, { "r", shiftr },
+ { "Illegal",one_address }, { "X", multiply },
+ { "+c", two_address }, { "-c", two_address },
+ { "+", two_address }, { "-", two_address },
+ { "T", two_address }, { "R", store },
+ { "A", store }, { "S", swap }
+};
+
+unsigned apexc_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 instruction; /* 32-bit machine instruction */
+ int x, y, function, c6, vector; /* instruction fields */
+ int n; /* 'friendly', instruction-dependant interpretation of C6 */
+ const instr_desc *the_desc; /* pointer to the revelant entry in the instructions array */
+ char mnemonic[9]; /* storage for generated mnemonic */
+
+ /* read the instruction to disassemble */
+ instruction = *((UINT32 *) oprom);
+
+ /* isolate the instruction fields */
+ x = (instruction >> 22) & 0x3FF;
+ y = (instruction >> 12) & 0x3FF;
+ function = (instruction >> 7) & 0x1F;
+ c6 = (instruction >> 1) & 0x3F;
+ vector = instruction & 1;
+
+ /* get the revelant entry in instructions */
+ the_desc = & instructions[function >> 1];
+
+ /* generate mnemonic : append a 'v' to the basic mnemonic if it is a vector instruction */
+ sprintf(mnemonic, "%.*s%c", (int)sizeof(mnemonic)-2, the_desc->mnemonic, vector ? 'v' : ' ');
+
+ /* print mnemonic and n immediate */
+ switch (the_desc->format)
+ {
+ case one_address:
+ case two_address:
+ case branch:
+ case swap:
+ buffer += sprintf(buffer, "%-10s", mnemonic); /* 10 chars*/
+ break;
+
+ case shiftl:
+ case shiftr:
+ if (the_desc->format == shiftl)
+ n = c6;
+ else
+ n = 64-c6;
+ buffer += sprintf(buffer, "%-2s(%2d) ", mnemonic, n); /* 10 chars */
+ break;
+
+ case multiply:
+ n = 33-c6;
+ if (n == 32)
+ /* case "32" : do not show bit specifier */
+ buffer += sprintf(buffer, "%-10s", mnemonic); /* 10 chars */
+ else
+ buffer += sprintf(buffer, "%-2s(%2d) ", mnemonic, n); /* 10 chars */
+ break;
+
+ case store:
+ if (c6 == 0)
+ { /* case "1-32" : do not show bit specifier */
+ buffer += sprintf(buffer, "%-10s", mnemonic); /* 10 chars*/
+ }
+ else if (c6 & 0x20)
+ { /* case "1-n" */
+ n = c6-32;
+ buffer += sprintf(buffer, "%-2s (1-%02d) ", mnemonic, n); /* 10 chars */
+ }
+ else
+ { /* case "n-32" */
+ n = c6+1;
+ buffer += sprintf(buffer, "%-2s(%02d-32) ", mnemonic, n); /* 8 chars */
+ }
+ }
+
+ /* print X address */
+ switch (the_desc->format)
+ {
+ case branch:
+ buffer--; /* eat last char */
+ buffer += sprintf(buffer, "<(%02d/%02d) >=", (x >> 5) & 0x1f, x & 0x1f); /* 10+1 chars */
+ break;
+
+ case multiply:
+ case swap:
+ buffer += sprintf(buffer, "(%02d) ", (x >> 5) & 0x1f); /* 10 chars */
+ break;
+
+ case one_address:
+ case shiftl:
+ case shiftr:
+ buffer += sprintf(buffer, " "); /* 10 chars */
+ break;
+
+ case two_address:
+ case store:
+ buffer += sprintf(buffer, "(%02d/%02d) ", (x >> 5) & 0x1f, x & 0x1f); /* 10 chars */
+ break;
+ }
+
+ /* print Y address */
+ buffer += sprintf(buffer, "(%02d/%02d)", (y >> 5) & 0x1f, y & 0x1f); /* 7 chars */
+
+ return 4;
+}
diff --git a/src/emu/cpu/arm/arm.c b/src/emu/cpu/arm/arm.c
new file mode 100644
index 00000000000..162bf62db0e
--- /dev/null
+++ b/src/emu/cpu/arm/arm.c
@@ -0,0 +1,1599 @@
+/* arm.c
+
+ ARM 2/3/6 Emulation (26 bit address bus)
+
+ Todo:
+ Timing - Currently very approximated, nothing relies on proper timing so far.
+ IRQ timing not yet correct (again, nothing is affected by this so far).
+
+ Recent changes (2005):
+ Fixed software interrupts
+ Fixed various mode change bugs
+ Added preliminary co-processor support.
+
+ By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino
+
+*/
+
+#include "arm.h"
+#include "debugger.h"
+
+#define READ8(addr) cpu_read8(addr)
+#define WRITE8(addr,data) cpu_write8(addr,data)
+#define READ32(addr) cpu_read32(addr)
+#define WRITE32(addr,data) cpu_write32(addr,data)
+
+#define ARM_DEBUG_CORE 0
+#define ARM_DEBUG_COPRO 0
+
+enum
+{
+ eARM_MODE_USER = 0x0,
+ eARM_MODE_FIQ = 0x1,
+ eARM_MODE_IRQ = 0x2,
+ eARM_MODE_SVC = 0x3,
+
+ kNumModes
+};
+
+/* There are 27 32 bit processor registers */
+enum
+{
+ eR0=0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13, /* Stack Pointer */
+ eR14, /* Link Register (holds return address) */
+ eR15, /* Program Counter */
+
+ /* Fast Interrupt */
+ eR8_FIQ,eR9_FIQ,eR10_FIQ,eR11_FIQ,eR12_FIQ,eR13_FIQ,eR14_FIQ,
+
+ /* IRQ */
+ eR13_IRQ,eR14_IRQ,
+
+ /* Software Interrupt */
+ eR13_SVC,eR14_SVC,
+
+ kNumRegisters
+};
+
+/* 16 processor registers are visible at any given time,
+ * banked depending on processor mode.
+ */
+static const int sRegisterTable[kNumModes][16] =
+{
+ { /* USR */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13,eR14,
+ eR15
+ },
+ { /* FIQ */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8_FIQ,eR9_FIQ,eR10_FIQ,eR11_FIQ,eR12_FIQ,
+ eR13_FIQ,eR14_FIQ,
+ eR15
+ },
+ { /* IRQ */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13_IRQ,eR14_IRQ,
+ eR15
+ },
+ { /* SVC */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13_SVC,eR14_SVC,
+ eR15
+ }
+};
+
+#define N_BIT 31
+#define Z_BIT 30
+#define C_BIT 29
+#define V_BIT 28
+#define I_BIT 27
+#define F_BIT 26
+
+#define N_MASK ((UINT32)(1<<N_BIT)) /* Negative flag */
+#define Z_MASK ((UINT32)(1<<Z_BIT)) /* Zero flag */
+#define C_MASK ((UINT32)(1<<C_BIT)) /* Carry flag */
+#define V_MASK ((UINT32)(1<<V_BIT)) /* oVerflow flag */
+#define I_MASK ((UINT32)(1<<I_BIT)) /* Interrupt request disable */
+#define F_MASK ((UINT32)(1<<F_BIT)) /* Fast interrupt request disable */
+
+#define N_IS_SET(pc) ((pc) & N_MASK)
+#define Z_IS_SET(pc) ((pc) & Z_MASK)
+#define C_IS_SET(pc) ((pc) & C_MASK)
+#define V_IS_SET(pc) ((pc) & V_MASK)
+#define I_IS_SET(pc) ((pc) & I_MASK)
+#define F_IS_SET(pc) ((pc) & F_MASK)
+
+#define N_IS_CLEAR(pc) (!N_IS_SET(pc))
+#define Z_IS_CLEAR(pc) (!Z_IS_SET(pc))
+#define C_IS_CLEAR(pc) (!C_IS_SET(pc))
+#define V_IS_CLEAR(pc) (!V_IS_SET(pc))
+#define I_IS_CLEAR(pc) (!I_IS_SET(pc))
+#define F_IS_CLEAR(pc) (!F_IS_SET(pc))
+
+#define PSR_MASK ((UINT32) 0xf0000000u)
+#define IRQ_MASK ((UINT32) 0x0c000000u)
+#define ADDRESS_MASK ((UINT32) 0x03fffffcu)
+#define MODE_MASK ((UINT32) 0x00000003u)
+
+#define R15 arm.sArmRegister[eR15]
+#define MODE (R15&0x03)
+#define SIGN_BIT ((UINT32)(1<<31))
+#define SIGN_BITS_DIFFER(a,b) (((a)^(b)) >> 31)
+
+/* Deconstructing an instruction */
+
+#define INSN_COND ((UINT32) 0xf0000000u)
+#define INSN_SDT_L ((UINT32) 0x00100000u)
+#define INSN_SDT_W ((UINT32) 0x00200000u)
+#define INSN_SDT_B ((UINT32) 0x00400000u)
+#define INSN_SDT_U ((UINT32) 0x00800000u)
+#define INSN_SDT_P ((UINT32) 0x01000000u)
+#define INSN_BDT_L ((UINT32) 0x00100000u)
+#define INSN_BDT_W ((UINT32) 0x00200000u)
+#define INSN_BDT_S ((UINT32) 0x00400000u)
+#define INSN_BDT_U ((UINT32) 0x00800000u)
+#define INSN_BDT_P ((UINT32) 0x01000000u)
+#define INSN_BDT_REGS ((UINT32) 0x0000ffffu)
+#define INSN_SDT_IMM ((UINT32) 0x00000fffu)
+#define INSN_MUL_A ((UINT32) 0x00200000u)
+#define INSN_MUL_RM ((UINT32) 0x0000000fu)
+#define INSN_MUL_RS ((UINT32) 0x00000f00u)
+#define INSN_MUL_RN ((UINT32) 0x0000f000u)
+#define INSN_MUL_RD ((UINT32) 0x000f0000u)
+#define INSN_I ((UINT32) 0x02000000u)
+#define INSN_OPCODE ((UINT32) 0x01e00000u)
+#define INSN_S ((UINT32) 0x00100000u)
+#define INSN_BL ((UINT32) 0x01000000u)
+#define INSN_BRANCH ((UINT32) 0x00ffffffu)
+#define INSN_SWI ((UINT32) 0x00ffffffu)
+#define INSN_RN ((UINT32) 0x000f0000u)
+#define INSN_RD ((UINT32) 0x0000f000u)
+#define INSN_OP2 ((UINT32) 0x00000fffu)
+#define INSN_OP2_SHIFT ((UINT32) 0x00000f80u)
+#define INSN_OP2_SHIFT_TYPE ((UINT32) 0x00000070u)
+#define INSN_OP2_RM ((UINT32) 0x0000000fu)
+#define INSN_OP2_ROTATE ((UINT32) 0x00000f00u)
+#define INSN_OP2_IMM ((UINT32) 0x000000ffu)
+#define INSN_OP2_SHIFT_TYPE_SHIFT 4
+#define INSN_OP2_SHIFT_SHIFT 7
+#define INSN_OP2_ROTATE_SHIFT 8
+#define INSN_MUL_RS_SHIFT 8
+#define INSN_MUL_RN_SHIFT 12
+#define INSN_MUL_RD_SHIFT 16
+#define INSN_OPCODE_SHIFT 21
+#define INSN_RN_SHIFT 16
+#define INSN_RD_SHIFT 12
+#define INSN_COND_SHIFT 28
+
+#define S_CYCLE 1
+#define N_CYCLE 1
+#define I_CYCLE 1
+
+enum
+{
+ OPCODE_AND, /* 0000 */
+ OPCODE_EOR, /* 0001 */
+ OPCODE_SUB, /* 0010 */
+ OPCODE_RSB, /* 0011 */
+ OPCODE_ADD, /* 0100 */
+ OPCODE_ADC, /* 0101 */
+ OPCODE_SBC, /* 0110 */
+ OPCODE_RSC, /* 0111 */
+ OPCODE_TST, /* 1000 */
+ OPCODE_TEQ, /* 1001 */
+ OPCODE_CMP, /* 1010 */
+ OPCODE_CMN, /* 1011 */
+ OPCODE_ORR, /* 1100 */
+ OPCODE_MOV, /* 1101 */
+ OPCODE_BIC, /* 1110 */
+ OPCODE_MVN /* 1111 */
+};
+
+enum
+{
+ COND_EQ = 0, /* Z: equal */
+ COND_NE, /* ~Z: not equal */
+ COND_CS, COND_HS = 2, /* C: unsigned higher or same */
+ COND_CC, COND_LO = 3, /* ~C: unsigned lower */
+ COND_MI, /* N: negative */
+ COND_PL, /* ~N: positive or zero */
+ COND_VS, /* V: overflow */
+ COND_VC, /* ~V: no overflow */
+ COND_HI, /* C && ~Z: unsigned higher */
+ COND_LS, /* ~C || Z: unsigned lower or same */
+ COND_GE, /* N == V: greater or equal */
+ COND_LT, /* N != V: less than */
+ COND_GT, /* ~Z && (N == V): greater than */
+ COND_LE, /* Z || (N != V): less than or equal */
+ COND_AL, /* always */
+ COND_NV /* never */
+};
+
+#define LSL(v,s) ((v) << (s))
+#define LSR(v,s) ((v) >> (s))
+#define ROL(v,s) (LSL((v),(s)) | (LSR((v),32u - (s))))
+#define ROR(v,s) (LSR((v),(s)) | (LSL((v),32u - (s))))
+
+/* Private Data */
+
+/* sArmRegister defines the CPU state */
+typedef struct
+{
+ UINT32 sArmRegister[kNumRegisters];
+ UINT32 coproRegister[16];
+ UINT8 pendingIrq;
+ UINT8 pendingFiq;
+ int (*irq_callback)(int);
+} ARM_REGS;
+
+static ARM_REGS arm;
+
+static int arm_icount;
+
+/* Prototypes */
+static void HandleALU( UINT32 insn);
+static void HandleMul( UINT32 insn);
+static void HandleBranch( UINT32 insn);
+static void HandleMemSingle( UINT32 insn);
+static void HandleMemBlock( UINT32 insn);
+static void HandleCoPro( UINT32 insn);
+static UINT32 decodeShift( UINT32 insn, UINT32 *pCarry);
+static void arm_check_irq_state(void);
+
+/***************************************************************************/
+
+INLINE void cpu_write32( int addr, UINT32 data )
+{
+ /* Unaligned writes are treated as normal writes */
+ program_write_dword_32le(addr&ADDRESS_MASK,data);
+ if (ARM_DEBUG_CORE && addr&3) logerror("%08x: Unaligned write %08x\n",R15,addr);
+}
+
+INLINE void cpu_write8( int addr, UINT8 data )
+{
+ program_write_byte_32le(addr,data);
+}
+
+INLINE UINT32 cpu_read32( int addr )
+{
+ UINT32 result = program_read_dword_32le(addr&ADDRESS_MASK);
+
+ /* Unaligned reads rotate the word, they never combine words */
+ if (addr&3) {
+ if (ARM_DEBUG_CORE && addr&1)
+ logerror("%08x: Unaligned byte read %08x\n",R15,addr);
+
+ if ((addr&3)==1)
+ return ((result&0x000000ff)<<24)|((result&0xffffff00)>> 8);
+ if ((addr&3)==2)
+ return ((result&0x0000ffff)<<16)|((result&0xffff0000)>>16);
+ if ((addr&3)==3)
+ return ((result&0x00ffffff)<< 8)|((result&0xff000000)>>24);
+ }
+
+ return result;
+}
+
+INLINE UINT8 cpu_read8( int addr )
+{
+ return program_read_byte_32le(addr);
+}
+
+INLINE UINT32 GetRegister( int rIndex )
+{
+ return arm.sArmRegister[sRegisterTable[MODE][rIndex]];
+}
+
+INLINE void SetRegister( int rIndex, UINT32 value )
+{
+ arm.sArmRegister[sRegisterTable[MODE][rIndex]] = value;
+ if (rIndex == eR15)
+ change_pc(value & ADDRESS_MASK);
+}
+
+/***************************************************************************/
+
+static void arm_reset(void)
+{
+ int (*save_irqcallback)(int) = arm.irq_callback;
+ memset(&arm, 0, sizeof(arm));
+ arm.irq_callback = save_irqcallback;
+
+ /* start up in SVC mode with interrupts disabled. */
+ R15 = eARM_MODE_SVC|I_MASK|F_MASK;
+ change_pc(R15 & ADDRESS_MASK);
+}
+
+static void arm_exit(void)
+{
+ /* nothing to do here */
+}
+
+static int arm_execute( int cycles )
+{
+ UINT32 pc;
+ UINT32 insn;
+
+ arm_icount = cycles;
+ do
+ {
+ CALL_MAME_DEBUG;
+
+ /* load instruction */
+ pc = R15;
+ insn = cpu_readop32( pc & ADDRESS_MASK );
+
+ switch (insn >> INSN_COND_SHIFT)
+ {
+ case COND_EQ:
+ if (Z_IS_CLEAR(pc)) goto L_Next;
+ break;
+ case COND_NE:
+ if (Z_IS_SET(pc)) goto L_Next;
+ break;
+ case COND_CS:
+ if (C_IS_CLEAR(pc)) goto L_Next;
+ break;
+ case COND_CC:
+ if (C_IS_SET(pc)) goto L_Next;
+ break;
+ case COND_MI:
+ if (N_IS_CLEAR(pc)) goto L_Next;
+ break;
+ case COND_PL:
+ if (N_IS_SET(pc)) goto L_Next;
+ break;
+ case COND_VS:
+ if (V_IS_CLEAR(pc)) goto L_Next;
+ break;
+ case COND_VC:
+ if (V_IS_SET(pc)) goto L_Next;
+ break;
+ case COND_HI:
+ if (C_IS_CLEAR(pc) || Z_IS_SET(pc)) goto L_Next;
+ break;
+ case COND_LS:
+ if (C_IS_SET(pc) && Z_IS_CLEAR(pc)) goto L_Next;
+ break;
+ case COND_GE:
+ if (!(pc & N_MASK) != !(pc & V_MASK)) goto L_Next; /* Use x ^ (x >> ...) method */
+ break;
+ case COND_LT:
+ if (!(pc & N_MASK) == !(pc & V_MASK)) goto L_Next;
+ break;
+ case COND_GT:
+ if (Z_IS_SET(pc) || (!(pc & N_MASK) != !(pc & V_MASK))) goto L_Next;
+ break;
+ case COND_LE:
+ if (Z_IS_CLEAR(pc) && (!(pc & N_MASK) == !(pc & V_MASK))) goto L_Next;
+ break;
+ case COND_NV:
+ goto L_Next;
+ }
+ /* Condition satisfied, so decode the instruction */
+ if ((insn & 0x0fc000f0u) == 0x00000090u) /* Multiplication */
+ {
+ HandleMul(insn);
+ R15 += 4;
+ }
+ else if (!(insn & 0x0c000000u)) /* Data processing */
+ {
+ HandleALU(insn);
+ }
+ else if ((insn & 0x0c000000u) == 0x04000000u) /* Single data access */
+ {
+ HandleMemSingle(insn);
+ R15 += 4;
+ }
+ else if ((insn & 0x0e000000u) == 0x08000000u ) /* Block data access */
+ {
+ HandleMemBlock(insn);
+ R15 += 4;
+ }
+ else if ((insn & 0x0e000000u) == 0x0a000000u) /* Branch */
+ {
+ HandleBranch(insn);
+ }
+ else if ((insn & 0x0f000000u) == 0x0e000000u) /* Coprocessor */
+ {
+ HandleCoPro(insn);
+ R15 += 4;
+ }
+ else if ((insn & 0x0f000000u) == 0x0f000000u) /* Software interrupt */
+ {
+ pc=R15+4;
+ R15 = eARM_MODE_SVC; /* Set SVC mode so PC is saved to correct R14 bank */
+ SetRegister( 14, pc ); /* save PC */
+ R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x8|eARM_MODE_SVC|I_MASK|(pc&MODE_MASK);
+ change_pc(pc&ADDRESS_MASK);
+ arm_icount -= 2 * S_CYCLE + N_CYCLE;
+ }
+ else /* Undefined */
+ {
+ logerror("%08x: Undefined instruction\n",R15);
+ L_Next:
+ arm_icount -= S_CYCLE;
+ R15 += 4;
+ }
+
+ arm_check_irq_state();
+
+ } while( arm_icount > 0 );
+
+ return cycles - arm_icount;
+} /* arm_execute */
+
+
+static void arm_get_context(void *dst)
+{
+ if( dst )
+ {
+ memcpy( dst, &arm, sizeof(arm) );
+ }
+}
+
+static void arm_set_context(void *src)
+{
+ if (src)
+ {
+ memcpy( &arm, src, sizeof(arm) );
+ change_pc(R15 & ADDRESS_MASK);
+ }
+}
+
+static void arm_check_irq_state(void)
+{
+ UINT32 pc = R15+4; /* save old pc (already incremented in pipeline) */;
+
+ /* Exception priorities (from ARM6, not specifically ARM2/3):
+
+ Reset
+ Data abort
+ FIRQ
+ IRQ
+ Prefetch abort
+ Undefined instruction
+ */
+
+ if (arm.pendingFiq && (pc&F_MASK)==0) {
+ R15 = eARM_MODE_FIQ; /* Set FIQ mode so PC is saved to correct R14 bank */
+ SetRegister( 14, pc ); /* save PC */
+ R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x1c|eARM_MODE_FIQ|I_MASK|F_MASK; /* Mask both IRQ & FIRQ, set PC=0x1c */
+ change_pc(R15 & ADDRESS_MASK);
+ arm.pendingFiq=0;
+ return;
+ }
+
+ if (arm.pendingIrq && (pc&I_MASK)==0) {
+ R15 = eARM_MODE_IRQ; /* Set IRQ mode so PC is saved to correct R14 bank */
+ SetRegister( 14, pc ); /* save PC */
+ R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x18|eARM_MODE_IRQ|I_MASK|(pc&F_MASK); /* Mask only IRQ, set PC=0x18 */
+ change_pc(R15 & ADDRESS_MASK);
+ arm.pendingIrq=0;
+ return;
+ }
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ switch (irqline) {
+
+ case ARM_IRQ_LINE: /* IRQ */
+ if (state && (R15&0x3)!=eARM_MODE_IRQ) /* Don't allow nested IRQs */
+ arm.pendingIrq=1;
+ else
+ arm.pendingIrq=0;
+ break;
+
+ case ARM_FIRQ_LINE: /* FIRQ */
+ if (state && (R15&0x3)!=eARM_MODE_FIQ) /* Don't allow nested FIRQs */
+ arm.pendingFiq=1;
+ else
+ arm.pendingFiq=0;
+ break;
+ }
+
+ arm_check_irq_state();
+}
+
+#ifdef MAME_DEBUG
+static offs_t arm_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 opcode = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24);
+ return 4 | arm_disasm(buffer, pc, opcode);
+}
+#endif /* MAME_DEBUG */
+
+static void arm_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ arm.irq_callback = irqcallback;
+
+ state_save_register_item_array("arm", index, arm.sArmRegister);
+ state_save_register_item_array("arm", index, arm.coproRegister);
+ state_save_register_item("arm", index, arm.pendingIrq);
+ state_save_register_item("arm", index, arm.pendingFiq);
+}
+
+/***************************************************************************/
+
+static void HandleBranch( UINT32 insn )
+{
+ UINT32 off = (insn & INSN_BRANCH) << 2;
+
+ /* Save PC into LR if this is a branch with link */
+ if (insn & INSN_BL)
+ {
+ SetRegister(14,R15 + 4);
+ }
+
+ /* Sign-extend the 24-bit offset in our calculations */
+ if (off & 0x2000000u)
+ {
+ R15 -= ((~(off | 0xfc000000u)) + 1) - 8;
+ }
+ else
+ {
+ R15 += off + 8;
+ }
+ change_pc(R15 & ADDRESS_MASK);
+ arm_icount -= 2 * S_CYCLE + N_CYCLE;
+}
+
+static void HandleMemSingle( UINT32 insn )
+{
+ UINT32 rn, rnv, off, rd;
+
+ /* Fetch the offset */
+ if (insn & INSN_I)
+ {
+ off = decodeShift(insn, NULL);
+ }
+ else
+ {
+ off = insn & INSN_SDT_IMM;
+ }
+
+ /* Calculate Rn, accounting for PC */
+ rn = (insn & INSN_RN) >> INSN_RN_SHIFT;
+
+// if (rn==0xf) logerror("%08x: Source R15\n",R15);
+
+ if (insn & INSN_SDT_P)
+ {
+ /* Pre-indexed addressing */
+ if (insn & INSN_SDT_U)
+ {
+ rnv = (GetRegister(rn) + off);
+ }
+ else
+ {
+ rnv = (GetRegister(rn) - off);
+ }
+
+ if (insn & INSN_SDT_W)
+ {
+ SetRegister(rn,rnv);
+ if (ARM_DEBUG_CORE && rn == eR15)
+ logerror("writeback R15 %08x\n", R15);
+ }
+ else if (rn == eR15)
+ {
+ rnv = (rnv & ADDRESS_MASK) + 8;
+ }
+ }
+ else
+ {
+ /* Post-indexed addressing */
+ if (rn == eR15)
+ {
+ rnv = (R15 & ADDRESS_MASK) + 8;
+ }
+ else
+ {
+ rnv = GetRegister(rn);
+ }
+ }
+
+ /* Do the transfer */
+ rd = (insn & INSN_RD) >> INSN_RD_SHIFT;
+ if (insn & INSN_SDT_L)
+ {
+ /* Load */
+ arm_icount -= S_CYCLE + I_CYCLE + N_CYCLE;
+ if (insn & INSN_SDT_B)
+ {
+ if (ARM_DEBUG_CORE && rd == eR15)
+ logerror("read byte R15 %08x\n", R15);
+ SetRegister(rd,(UINT32) READ8(rnv));
+ }
+ else
+ {
+ if (rd == eR15)
+ {
+ R15 = (READ32(rnv) & ADDRESS_MASK) | (R15 & PSR_MASK) | (R15 & MODE_MASK);
+ change_pc(R15 & ADDRESS_MASK);
+
+ /*
+ The docs are explicit in that the bottom bits should be masked off
+ when writing to R15 in this way, however World Cup Volleyball 95 has
+ an example of an unaligned jump (bottom bits = 2) where execution
+ should definitely continue from the rounded up address.
+
+ In other cases, 4 is subracted from R15 here to account for pipelining.
+ */
+ if ((READ32(rnv)&3)==0)
+ R15 -= 4;
+
+ arm_icount -= S_CYCLE + N_CYCLE;
+ }
+ else
+ {
+ SetRegister(rd,READ32(rnv));
+ }
+ }
+ }
+ else
+ {
+ /* Store */
+ arm_icount -= 2 * N_CYCLE;
+ if (insn & INSN_SDT_B)
+ {
+ if (ARM_DEBUG_CORE && rd==eR15)
+ logerror("Wrote R15 in byte mode\n");
+
+ WRITE8(rnv, (UINT8) GetRegister(rd) & 0xffu);
+ }
+ else
+ {
+ if (ARM_DEBUG_CORE && rd==eR15)
+ logerror("Wrote R15 in 32bit mode\n");
+
+ WRITE32(rnv, rd == eR15 ? R15 + 8 : GetRegister(rd));
+ }
+ }
+
+ /* Do post-indexing writeback */
+ if (!(insn & INSN_SDT_P)/* && (insn&INSN_SDT_W)*/)
+ {
+ if (insn & INSN_SDT_U)
+ {
+ /* Writeback is applied in pipeline, before value is read from mem,
+ so writeback is effectively ignored */
+ if (rd==rn) {
+ SetRegister(rn,GetRegister(rd));
+ }
+ else {
+
+ if ((insn&INSN_SDT_W)!=0)
+ logerror("%08x: RegisterWritebackIncrement %d %d %d\n",R15,(insn & INSN_SDT_P)!=0,(insn&INSN_SDT_W)!=0,(insn & INSN_SDT_U)!=0);
+
+ SetRegister(rn,(rnv + off));
+ }
+ }
+ else
+ {
+ /* Writeback is applied in pipeline, before value is read from mem,
+ so writeback is effectively ignored */
+ if (rd==rn) {
+ SetRegister(rn,GetRegister(rd));
+ }
+ else {
+ SetRegister(rn,(rnv - off));
+
+ if ((insn&INSN_SDT_W)!=0)
+ logerror("%08x: RegisterWritebackDecrement %d %d %d\n",R15,(insn & INSN_SDT_P)!=0,(insn&INSN_SDT_W)!=0,(insn & INSN_SDT_U)!=0);
+ }
+ }
+ }
+} /* HandleMemSingle */
+
+#define IsNeg(i) ((i) >> 31)
+#define IsPos(i) ((~(i)) >> 31)
+
+/* Set NZCV flags for ADDS / SUBS */
+
+#define HandleALUAddFlags(rd, rn, op2) \
+ if (insn & INSN_S) \
+ R15 = \
+ ((R15 &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
+ | (((!SIGN_BITS_DIFFER(rn, op2)) && SIGN_BITS_DIFFER(rn, rd)) \
+ << V_BIT) \
+ | (((~(rn)) < (op2)) << C_BIT) \
+ | HandleALUNZFlags(rd)) \
+ + 4; \
+ else R15 += 4;
+
+#define HandleALUSubFlags(rd, rn, op2) \
+ if (insn & INSN_S) \
+ R15 = \
+ ((R15 &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
+ | ((SIGN_BITS_DIFFER(rn, op2) && SIGN_BITS_DIFFER(rn, rd)) \
+ << V_BIT) \
+ | (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \
+ | HandleALUNZFlags(rd)) \
+ + 4; \
+ else R15 += 4;
+
+/* Set NZC flags for logical operations. */
+
+#define HandleALUNZFlags(rd) \
+ (((rd) & SIGN_BIT) | ((!(rd)) << Z_BIT))
+
+#define HandleALULogicalFlags(rd, sc) \
+ if (insn & INSN_S) \
+ R15 = ((R15 &~ (N_MASK | Z_MASK | C_MASK)) \
+ | HandleALUNZFlags(rd) \
+ | (((sc) != 0) << C_BIT)) + 4; \
+ else R15 += 4;
+
+static void HandleALU( UINT32 insn )
+{
+ UINT32 op2, sc=0, rd, rn, opcode;
+ UINT32 by, rdn;
+
+ opcode = (insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT;
+ arm_icount -= S_CYCLE;
+
+ rd = 0;
+ rn = 0;
+
+ /* Construct Op2 */
+ if (insn & INSN_I)
+ {
+ /* Immediate constant */
+ by = (insn & INSN_OP2_ROTATE) >> INSN_OP2_ROTATE_SHIFT;
+ if (by)
+ {
+ op2 = ROR(insn & INSN_OP2_IMM, by << 1);
+ sc = op2 & SIGN_BIT;
+ }
+ else
+ {
+ op2 = insn & INSN_OP2;
+ sc = R15 & C_MASK;
+ }
+ }
+ else
+ {
+ op2 = decodeShift(insn, (insn & INSN_S) ? &sc : NULL);
+
+ if (!(insn & INSN_S))
+ sc=0;
+ }
+
+ /* Calculate Rn to account for pipelining */
+ if ((opcode & 0xd) != 0xd) /* No Rn in MOV */
+ {
+ if ((rn = (insn & INSN_RN) >> INSN_RN_SHIFT) == eR15)
+ {
+ if (ARM_DEBUG_CORE)
+ logerror("%08x: Pipelined R15 (Shift %d)\n",R15,(insn&INSN_I?8:insn&0x10u?12:12));
+
+ /* Docs strongly suggest the mode bits should be included here, but it breaks Captain
+ America, as it starts doing unaligned reads */
+ rn=(R15+8)&ADDRESS_MASK;
+ }
+ else
+ {
+ rn = GetRegister(rn);
+ }
+ }
+
+ /* Perform the operation */
+ switch ((insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT)
+ {
+ /* Arithmetic operations */
+ case OPCODE_SBC:
+ rd = (rn - op2 - (R15 & C_MASK ? 0 : 1));
+ HandleALUSubFlags(rd, rn, op2);
+ break;
+ case OPCODE_CMP:
+ case OPCODE_SUB:
+ rd = (rn - op2);
+ HandleALUSubFlags(rd, rn, op2);
+ break;
+ case OPCODE_RSC:
+ rd = (op2 - rn - (R15 & C_MASK ? 0 : 1));
+ HandleALUSubFlags(rd, op2, rn);
+ break;
+ case OPCODE_RSB:
+ rd = (op2 - rn);
+ HandleALUSubFlags(rd, op2, rn);
+ break;
+ case OPCODE_ADC:
+ rd = (rn + op2 + ((R15 & C_MASK) >> C_BIT));
+ HandleALUAddFlags(rd, rn, op2);
+ break;
+ case OPCODE_CMN:
+ case OPCODE_ADD:
+ rd = (rn + op2);
+ HandleALUAddFlags(rd, rn, op2);
+ break;
+
+ /* Logical operations */
+ case OPCODE_AND:
+ case OPCODE_TST:
+ rd = rn & op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_BIC:
+ rd = rn &~ op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_TEQ:
+ case OPCODE_EOR:
+ rd = rn ^ op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_ORR:
+ rd = rn | op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_MOV:
+ rd = op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_MVN:
+ rd = (~op2);
+ HandleALULogicalFlags(rd, sc);
+ break;
+ }
+
+ /* Put the result in its register if not a test */
+ rdn = (insn & INSN_RD) >> INSN_RD_SHIFT;
+ if ((opcode & 0xc) != 0x8)
+ {
+ if (rdn == eR15 && !(insn & INSN_S))
+ {
+ /* Merge the old NZCV flags into the new PC value */
+ R15 = (rd & ADDRESS_MASK) | (R15 & PSR_MASK) | (R15 & IRQ_MASK) | (R15&MODE_MASK);
+ change_pc(R15 & ADDRESS_MASK);
+ arm_icount -= S_CYCLE + N_CYCLE;
+ }
+ else
+ {
+ if (rdn==eR15)
+ {
+ /* S Flag is set - update PSR & mode if in non-user mode only */
+ if ((R15&MODE_MASK)!=0)
+ {
+ SetRegister(rdn,rd);
+ }
+ else
+ {
+ SetRegister(rdn,(rd&ADDRESS_MASK) | (rd&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK));
+ }
+ arm_icount -= S_CYCLE + N_CYCLE;
+ }
+ else
+ {
+ SetRegister(rdn,rd);
+ }
+ }
+ /* TST & TEQ can affect R15 (the condition code register) with the S bit set */
+ } else if (rdn==eR15) {
+ if (insn & INSN_S) {
+ if (ARM_DEBUG_CORE)
+ logerror("%08x: TST class on R15 s bit set\n",R15);
+
+ /* Dubious hack for 'TEQS R15, #$3', the docs suggest execution
+ should continue two instructions later (because pipelined R15
+ is read back as already being incremented), but it seems the
+ hardware should execute the instruction in the delay slot.
+ Simulate it by just setting the PC back to the previously
+ skipped instruction.
+
+ See Heavy Smash (Data East) at 0x1c4
+ */
+ if (insn==0xe33ff003)
+ rd-=4;
+
+ arm_icount -= S_CYCLE + N_CYCLE;
+ if ((R15&MODE_MASK)!=0)
+ {
+ SetRegister(15, rd);
+ }
+ else
+ {
+ SetRegister(15, (rd&ADDRESS_MASK) | (rd&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK));
+ }
+ } else {
+ if (ARM_DEBUG_CORE)
+ logerror("%08x: TST class on R15 no s bit set\n",R15);
+ }
+ }
+}
+
+static void HandleMul( UINT32 insn)
+{
+ UINT32 r;
+
+ arm_icount -= S_CYCLE + I_CYCLE;
+ /* should be:
+ Range of Rs Number of cycles
+
+ &0 -- &1 1S + 1I
+ &2 -- &7 1S + 2I
+ &8 -- &1F 1S + 3I
+ &20 -- &7F 1S + 4I
+ &80 -- &1FF 1S + 5I
+ &200 -- &7FF 1S + 6I
+ &800 -- &1FFF 1S + 7I
+ &2000 -- &7FFF 1S + 8I
+ &8000 -- &1FFFF 1S + 9I
+ &20000 -- &7FFFF 1S + 10I
+ &80000 -- &1FFFFF 1S + 11I
+ &200000 -- &7FFFFF 1S + 12I
+ &800000 -- &1FFFFFF 1S + 13I
+ &2000000 -- &7FFFFFF 1S + 14I
+ &8000000 -- &1FFFFFFF 1S + 15I
+ &20000000 -- &FFFFFFFF 1S + 16I
+ */
+
+ /* Do the basic multiply of Rm and Rs */
+ r = GetRegister( insn&INSN_MUL_RM ) *
+ GetRegister( (insn&INSN_MUL_RS)>>INSN_MUL_RS_SHIFT );
+
+ if (ARM_DEBUG_CORE && ((insn&INSN_MUL_RM)==0xf
+ || ((insn&INSN_MUL_RS)>>INSN_MUL_RS_SHIFT )==0xf
+ || ((insn&INSN_MUL_RN)>>INSN_MUL_RN_SHIFT)==0xf)
+ )
+ logerror("%08x: R15 used in mult\n",R15);
+
+ /* Add on Rn if this is a MLA */
+ if (insn & INSN_MUL_A)
+ {
+ r += GetRegister((insn&INSN_MUL_RN)>>INSN_MUL_RN_SHIFT);
+ }
+
+ /* Write the result */
+ SetRegister((insn&INSN_MUL_RD)>>INSN_MUL_RD_SHIFT,r);
+
+ /* Set N and Z if asked */
+ if( insn & INSN_S )
+ {
+ R15 = (R15 &~ (N_MASK | Z_MASK)) | HandleALUNZFlags(r);
+ }
+}
+
+static int loadInc ( UINT32 pat, UINT32 rbv, UINT32 s)
+{
+ int i,result;
+
+ result = 0;
+ for( i=0; i<16; i++ )
+ {
+ if( (pat>>i)&1 )
+ {
+ if (i==15) {
+ if (s) /* Pull full contents from stack */
+ SetRegister( 15, READ32(rbv+=4) );
+ else /* Pull only address, preserve mode & status flags */
+ SetRegister( 15, (R15&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK) | ((READ32(rbv+=4))&ADDRESS_MASK) );
+ } else
+ SetRegister( i, READ32(rbv+=4) );
+
+ result++;
+ }
+ }
+ return result;
+}
+
+static int loadDec( UINT32 pat, UINT32 rbv, UINT32 s, UINT32* deferredR15, int* defer)
+{
+ int i,result;
+
+ result = 0;
+ for( i=15; i>=0; i-- )
+ {
+ if( (pat>>i)&1 )
+ {
+ if (i==15) {
+ *defer=1;
+ if (s) /* Pull full contents from stack */
+ *deferredR15=READ32(rbv-=4);
+ else /* Pull only address, preserve mode & status flags */
+ *deferredR15=(R15&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK) | ((READ32(rbv-=4))&ADDRESS_MASK);
+ }
+ else
+ SetRegister( i, READ32(rbv -=4) );
+ result++;
+ }
+ }
+ return result;
+}
+
+static int storeInc( UINT32 pat, UINT32 rbv)
+{
+ int i,result;
+
+ result = 0;
+ for( i=0; i<16; i++ )
+ {
+ if( (pat>>i)&1 )
+ {
+ if (ARM_DEBUG_CORE && i==15) /* R15 is plus 12 from address of STM */
+ logerror("%08x: StoreInc on R15\n",R15);
+
+ WRITE32( rbv += 4, GetRegister(i) );
+ result++;
+ }
+ }
+ return result;
+} /* storeInc */
+
+static int storeDec( UINT32 pat, UINT32 rbv)
+{
+ int i,result;
+
+ result = 0;
+ for( i=15; i>=0; i-- )
+ {
+ if( (pat>>i)&1 )
+ {
+ if (ARM_DEBUG_CORE && i==15) /* R15 is plus 12 from address of STM */
+ logerror("%08x: StoreDec on R15\n",R15);
+
+ WRITE32( rbv -= 4, GetRegister(i) );
+ result++;
+ }
+ }
+ return result;
+} /* storeDec */
+
+static void HandleMemBlock( UINT32 insn)
+{
+ UINT32 rb = (insn & INSN_RN) >> INSN_RN_SHIFT;
+ UINT32 rbp = GetRegister(rb);
+ int result;
+
+ if (ARM_DEBUG_CORE && insn & INSN_BDT_S)
+ logerror("%08x: S Bit set in MEMBLOCK\n",R15);
+
+ if (insn & INSN_BDT_L)
+ {
+ /* Loading */
+ if (insn & INSN_BDT_U)
+ {
+ /* Incrementing */
+ if (!(insn & INSN_BDT_P)) rbp = rbp + (- 4);
+
+ result = loadInc( insn & 0xffff, rbp, insn&INSN_BDT_S );
+
+ if (insn & 0x8000) {
+ R15-=4;
+ arm_icount -= S_CYCLE + N_CYCLE;
+ }
+
+ if (insn & INSN_BDT_W)
+ {
+ /* Arm docs notes: The base register can always be loaded without any problems.
+ However, don't specify writeback if the base register is being loaded -
+ you can't end up with both a written-back value and a loaded value in the base register!
+
+ However - Fighter's History does exactly that at 0x121e4 (LDMUW [R13], { R13-R15 })!
+
+ This emulator implementation skips applying writeback in this case, which is confirmed
+ correct for this situation, but that is not necessarily true for all ARM hardware
+ implementations (the results are officially undefined).
+ */
+
+ if (ARM_DEBUG_CORE && rb==15)
+ logerror("%08x: Illegal LDRM writeback to r15\n",R15);
+
+ if ((insn&(1<<rb))==0)
+ SetRegister(rb,GetRegister(rb)+result*4);
+ else if (ARM_DEBUG_CORE)
+ logerror("%08x: Illegal LDRM writeback to base register (%d)\n",R15, rb);
+ }
+ }
+ else
+ {
+ UINT32 deferredR15=0;
+ int defer=0;
+
+ /* Decrementing */
+ if (!(insn & INSN_BDT_P))
+ {
+ rbp = rbp - (- 4);
+ }
+
+ result = loadDec( insn&0xffff, rbp, insn&INSN_BDT_S, &deferredR15, &defer );
+
+ if (insn & INSN_BDT_W)
+ {
+ if (rb==0xf)
+ logerror("%08x: Illegal LDRM writeback to r15\n",R15);
+ SetRegister(rb,GetRegister(rb)-result*4);
+ }
+
+ // If R15 is pulled from memory we defer setting it until after writeback
+ // is performed, else we may writeback to the wrong context (ie, the new
+ // context if the mode has changed as a result of the R15 read)
+ if (defer)
+ SetRegister(15, deferredR15);
+
+ if (insn & 0x8000) {
+ arm_icount -= S_CYCLE + N_CYCLE;
+ R15-=4;
+ }
+ }
+ arm_icount -= result * S_CYCLE + N_CYCLE + I_CYCLE;
+ } /* Loading */
+ else
+ {
+ /* Storing
+
+ ARM docs notes: Storing a list of registers including the base register using writeback
+ will write the value of the base register before writeback to memory only if the base
+ register is the first in the list. Otherwise, the value which is used is not defined.
+
+ */
+ if (insn & (1<<eR15))
+ {
+ if (ARM_DEBUG_CORE)
+ logerror("%08x: Writing R15 in strm\n",R15);
+
+ /* special case handling if writing to PC */
+ R15 += 12;
+ }
+ if (insn & INSN_BDT_U)
+ {
+ /* Incrementing */
+ if (!(insn & INSN_BDT_P))
+ {
+ rbp = rbp + (- 4);
+ }
+ result = storeInc( insn&0xffff, rbp );
+ if( insn & INSN_BDT_W )
+ {
+ SetRegister(rb,GetRegister(rb)+result*4);
+ }
+ }
+ else
+ {
+ /* Decrementing */
+ if (!(insn & INSN_BDT_P))
+ {
+ rbp = rbp - (- 4);
+ }
+ result = storeDec( insn&0xffff, rbp );
+ if( insn & INSN_BDT_W )
+ {
+ SetRegister(rb,GetRegister(rb)-result*4);
+ }
+ }
+ if( insn & (1<<eR15) )
+ R15 -= 12;
+
+ arm_icount -= (result - 1) * S_CYCLE + 2 * N_CYCLE;
+ }
+} /* HandleMemBlock */
+
+
+
+/* Decodes an Op2-style shifted-register form. If @carry@ is non-zero the
+ * shifter carry output will manifest itself as @*carry == 0@ for carry clear
+ * and @*carry != 0@ for carry set.
+ */
+static UINT32 decodeShift( UINT32 insn, UINT32 *pCarry)
+{
+ UINT32 k = (insn & INSN_OP2_SHIFT) >> INSN_OP2_SHIFT_SHIFT;
+ UINT32 rm = GetRegister( insn & INSN_OP2_RM );
+ UINT32 t = (insn & INSN_OP2_SHIFT_TYPE) >> INSN_OP2_SHIFT_TYPE_SHIFT;
+
+ if ((insn & INSN_OP2_RM)==0xf) {
+ /* If hardwired shift, then PC is 8 bytes ahead, else if register shift
+ is used, then 12 bytes - TODO?? */
+ rm+=8;
+ }
+
+ /* All shift types ending in 1 are Rk, not #k */
+ if( t & 1 )
+ {
+// logerror("%08x: RegShift %02x %02x\n",R15, k>>1,GetRegister(k >> 1));
+ if (ARM_DEBUG_CORE && (insn&0x80)==0x80)
+ logerror("%08x: RegShift ERROR (p36)\n",R15);
+
+ //see p35 for check on this
+ k = GetRegister(k >> 1)&0x1f;
+ arm_icount -= S_CYCLE;
+ if( k == 0 ) /* Register shift by 0 is a no-op */
+ {
+// logerror("%08x: NO-OP Regshift\n",R15);
+ if (pCarry) *pCarry = R15 & C_MASK;
+ return rm;
+ }
+ }
+ /* Decode the shift type and perform the shift */
+ switch (t >> 1)
+ {
+ case 0: /* LSL */
+ if (pCarry)
+ {
+ *pCarry = k ? (rm & (1 << (32 - k))) : (R15 & C_MASK);
+ }
+ return k ? LSL(rm, k) : rm;
+ break;
+
+ case 1: /* LSR */
+ if (k == 0 || k == 32)
+ {
+ if (pCarry) *pCarry = rm & SIGN_BIT;
+ return 0;
+ }
+ else if (k > 32)
+ {
+ if (pCarry) *pCarry = 0;
+ return 0;
+ }
+ else
+ {
+ if (pCarry) *pCarry = (rm & (1 << (k - 1)));
+ return LSR(rm, k);
+ }
+ break;
+
+ case 2: /* ASR */
+ if (k == 0 || k > 32)
+ k = 32;
+ if (pCarry) *pCarry = (rm & (1 << (k - 1)));
+ if (k >= 32)
+ return rm & SIGN_BIT ? 0xffffffffu : 0;
+ else
+ {
+ if (rm & SIGN_BIT)
+ return LSR(rm, k) | (0xffffffffu << (32 - k));
+ else
+ return LSR(rm, k);
+ }
+ break;
+
+ case 3: /* ROR and RRX */
+ if (k)
+ {
+ while (k > 32) k -= 32;
+ if (pCarry) *pCarry = rm & SIGN_BIT;
+ return ROR(rm, k);
+ }
+ else
+ {
+ if (pCarry) *pCarry = (rm & 1);
+ return LSR(rm, 1) | ((R15 & C_MASK) << 2);
+ }
+ break;
+ }
+
+ logerror("%08x: Decodeshift error\n",R15);
+ return 0;
+} /* decodeShift */
+
+
+static UINT32 BCDToDecimal(UINT32 value)
+{
+ UINT32 accumulator = 0;
+ UINT32 multiplier = 1;
+ int i;
+
+ for(i = 0; i < 8; i++)
+ {
+ accumulator += (value & 0xF) * multiplier;
+
+ multiplier *= 10;
+ value >>= 4;
+ }
+
+ return accumulator;
+}
+
+static UINT32 DecimalToBCD(UINT32 value)
+{
+ UINT32 accumulator = 0;
+ UINT32 divisor = 10;
+ int i;
+
+ for(i = 0; i < 8; i++)
+ {
+ UINT32 temp;
+
+ temp = value % divisor;
+ value -= temp;
+ temp /= divisor / 10;
+
+ accumulator += temp << (i * 4);
+
+ divisor *= 10;
+ }
+
+ return accumulator;
+}
+
+static void HandleCoPro( UINT32 insn)
+{
+ UINT32 rn=(insn>>12)&0xf;
+ UINT32 crn=(insn>>16)&0xf;
+
+ arm_icount -= S_CYCLE;
+
+ /* MRC - transfer copro register to main register */
+ if( (insn&0x0f100010)==0x0e100010 )
+ {
+ SetRegister(rn, arm.coproRegister[crn]);
+
+ if (ARM_DEBUG_COPRO)
+ logerror("%08x: Copro read CR%d (%08x) to R%d\n", R15, crn, arm.coproRegister[crn], rn);
+ }
+ /* MCR - transfer main register to copro register */
+ else if( (insn&0x0f100010)==0x0e000010 )
+ {
+ arm.coproRegister[crn]=GetRegister(rn);
+
+ /* Data East 156 copro specific - trigger BCD operation */
+ if (crn==2)
+ {
+ if (arm.coproRegister[crn]==0)
+ {
+ /* Unpack BCD */
+ int v0=BCDToDecimal(arm.coproRegister[0]);
+ int v1=BCDToDecimal(arm.coproRegister[1]);
+
+ /* Repack vcd */
+ arm.coproRegister[5]=DecimalToBCD(v0+v1);
+
+ if (ARM_DEBUG_COPRO)
+ logerror("Cmd: Add 0 + 1, result in 5 (%08x + %08x == %08x)\n", v0, v1, arm.coproRegister[5]);
+ }
+ else if (arm.coproRegister[crn]==1)
+ {
+ /* Unpack BCD */
+ int v0=BCDToDecimal(arm.coproRegister[0]);
+ int v1=BCDToDecimal(arm.coproRegister[1]);
+
+ /* Repack vcd */
+ arm.coproRegister[5]=DecimalToBCD(v0*v1);
+
+ if (ARM_DEBUG_COPRO)
+ logerror("Cmd: Multiply 0 * 1, result in 5 (%08x * %08x == %08x)\n", v0, v1, arm.coproRegister[5]);
+ }
+ else if (arm.coproRegister[crn]==3)
+ {
+ /* Unpack BCD */
+ int v0=BCDToDecimal(arm.coproRegister[0]);
+ int v1=BCDToDecimal(arm.coproRegister[1]);
+
+ /* Repack vcd */
+ arm.coproRegister[5]=DecimalToBCD(v0-v1);
+
+ if (ARM_DEBUG_COPRO)
+ logerror("Cmd: Sub 0 - 1, result in 5 (%08x - %08x == %08x)\n", v0, v1, arm.coproRegister[5]);
+ }
+ else
+ {
+ logerror("Unknown bcd copro command %08x\n", arm.coproRegister[crn]);
+ }
+ }
+
+ if (ARM_DEBUG_COPRO)
+ logerror("%08x: Copro write R%d (%08x) to CR%d\n", R15, rn, GetRegister(rn), crn);
+ }
+ /* CDP - perform copro operation */
+ else if( (insn&0x0f000010)==0x0e000000 )
+ {
+ /* Data East 156 copro specific divider - result in reg 3/4 */
+ if (arm.coproRegister[1])
+ {
+ arm.coproRegister[3]=arm.coproRegister[0] / arm.coproRegister[1];
+ arm.coproRegister[4]=arm.coproRegister[0] % arm.coproRegister[1];
+ }
+ else
+ {
+ /* Unverified */
+ arm.coproRegister[3]=0xffffffff;
+ arm.coproRegister[4]=0xffffffff;
+ }
+
+ if (ARM_DEBUG_COPRO)
+ logerror("%08x: Copro cdp (%08x) (3==> %08x, 4==> %08x)\n", R15, insn, arm.coproRegister[3], arm.coproRegister[4]);
+ }
+ else
+ {
+ logerror("%08x: Unimplemented copro instruction %08x\n", R15, insn);
+ }
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void arm_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + ARM_IRQ_LINE: set_irq_line(ARM_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ARM_FIRQ_LINE: set_irq_line(ARM_FIRQ_LINE, info->i); break;
+
+ case CPUINFO_INT_REGISTER + ARM32_R0: arm.sArmRegister[ 0]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R1: arm.sArmRegister[ 1]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R2: arm.sArmRegister[ 2]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R3: arm.sArmRegister[ 3]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R4: arm.sArmRegister[ 4]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R5: arm.sArmRegister[ 5]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R6: arm.sArmRegister[ 6]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R7: arm.sArmRegister[ 7]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R8: arm.sArmRegister[ 8]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R9: arm.sArmRegister[ 9]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R10: arm.sArmRegister[10]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R11: arm.sArmRegister[11]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R12: arm.sArmRegister[12]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R13: arm.sArmRegister[13]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R14: arm.sArmRegister[14]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_R15: arm.sArmRegister[15]= info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR8: arm.sArmRegister[eR8_FIQ] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR9: arm.sArmRegister[eR9_FIQ] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR10: arm.sArmRegister[eR10_FIQ] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR11: arm.sArmRegister[eR11_FIQ] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR12: arm.sArmRegister[eR12_FIQ] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR13: arm.sArmRegister[eR13_FIQ] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR14: arm.sArmRegister[eR14_FIQ] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_IR13: arm.sArmRegister[eR13_IRQ] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_IR14: arm.sArmRegister[eR14_IRQ] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_SR13: arm.sArmRegister[eR13_SVC] = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM32_SR14: arm.sArmRegister[eR14_SVC] = info->i; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ARM32_PC: R15 = (R15&~ADDRESS_MASK)|info->i; break;
+ case CPUINFO_INT_SP: SetRegister(13,info->i); break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void arm_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(arm); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 3; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 4; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 26; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + ARM_IRQ_LINE: info->i = arm.pendingIrq; break;
+ case CPUINFO_INT_INPUT_STATE + ARM_FIRQ_LINE: info->i = arm.pendingFiq; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* not implemented */ break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ARM32_PC: info->i = arm.sArmRegister[15]&ADDRESS_MASK; break;
+ case CPUINFO_INT_SP: info->i = GetRegister(13); break;
+
+ case CPUINFO_INT_REGISTER + ARM32_R0: info->i = arm.sArmRegister[ 0]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R1: info->i = arm.sArmRegister[ 1]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R2: info->i = arm.sArmRegister[ 2]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R3: info->i = arm.sArmRegister[ 3]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R4: info->i = arm.sArmRegister[ 4]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R5: info->i = arm.sArmRegister[ 5]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R6: info->i = arm.sArmRegister[ 6]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R7: info->i = arm.sArmRegister[ 7]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R8: info->i = arm.sArmRegister[ 8]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R9: info->i = arm.sArmRegister[ 9]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R10: info->i = arm.sArmRegister[10]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R11: info->i = arm.sArmRegister[11]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R12: info->i = arm.sArmRegister[12]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R13: info->i = arm.sArmRegister[13]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R14: info->i = arm.sArmRegister[14]; break;
+ case CPUINFO_INT_REGISTER + ARM32_R15: info->i = arm.sArmRegister[15]; break;
+
+ case CPUINFO_INT_REGISTER + ARM32_FR8: info->i = arm.sArmRegister[eR8_FIQ]; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR9: info->i = arm.sArmRegister[eR9_FIQ]; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR10: info->i = arm.sArmRegister[eR10_FIQ]; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR11: info->i = arm.sArmRegister[eR11_FIQ]; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR12: info->i = arm.sArmRegister[eR12_FIQ]; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR13: info->i = arm.sArmRegister[eR13_FIQ]; break;
+ case CPUINFO_INT_REGISTER + ARM32_FR14: info->i = arm.sArmRegister[eR14_FIQ]; break;
+ case CPUINFO_INT_REGISTER + ARM32_IR13: info->i = arm.sArmRegister[eR13_IRQ]; break;
+ case CPUINFO_INT_REGISTER + ARM32_IR14: info->i = arm.sArmRegister[eR14_IRQ]; break;
+ case CPUINFO_INT_REGISTER + ARM32_SR13: info->i = arm.sArmRegister[eR13_SVC]; break;
+ case CPUINFO_INT_REGISTER + ARM32_SR14: info->i = arm.sArmRegister[eR14_SVC]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = arm_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = arm_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = arm_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = arm_init; break;
+ case CPUINFO_PTR_RESET: info->reset = arm_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = arm_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = arm_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = arm_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &arm_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ARM"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Acorn Risc Machine"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.3"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 2002-2006 Bryan McPhail, bmcphail@tendril.co.uk"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c",
+ (arm.sArmRegister[15] & N_MASK) ? 'N' : '-',
+ (arm.sArmRegister[15] & Z_MASK) ? 'Z' : '-',
+ (arm.sArmRegister[15] & C_MASK) ? 'C' : '-',
+ (arm.sArmRegister[15] & V_MASK) ? 'V' : '-',
+ (arm.sArmRegister[15] & I_MASK) ? 'I' : '-',
+ (arm.sArmRegister[15] & F_MASK) ? 'F' : '-');
+ switch (arm.sArmRegister[15] & 3)
+ {
+ case 0:
+ strcat(info->s, " USER");
+ break;
+ case 1:
+ strcat(info->s, " FIRQ");
+ break;
+ case 2:
+ strcat(info->s, " IRQ ");
+ break;
+ default:
+ strcat(info->s, " SVC ");
+ break;
+ }
+ break;
+
+ case CPUINFO_STR_REGISTER + ARM32_PC: sprintf( info->s, "PC :%08x", arm.sArmRegister[15]&ADDRESS_MASK ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R0: sprintf( info->s, "R0 :%08x", arm.sArmRegister[ 0] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R1: sprintf( info->s, "R1 :%08x", arm.sArmRegister[ 1] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R2: sprintf( info->s, "R2 :%08x", arm.sArmRegister[ 2] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R3: sprintf( info->s, "R3 :%08x", arm.sArmRegister[ 3] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R4: sprintf( info->s, "R4 :%08x", arm.sArmRegister[ 4] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R5: sprintf( info->s, "R5 :%08x", arm.sArmRegister[ 5] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R6: sprintf( info->s, "R6 :%08x", arm.sArmRegister[ 6] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R7: sprintf( info->s, "R7 :%08x", arm.sArmRegister[ 7] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R8: sprintf( info->s, "R8 :%08x", arm.sArmRegister[ 8] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R9: sprintf( info->s, "R9 :%08x", arm.sArmRegister[ 9] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R10: sprintf( info->s, "R10 :%08x", arm.sArmRegister[10] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R11: sprintf( info->s, "R11 :%08x", arm.sArmRegister[11] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R12: sprintf( info->s, "R12 :%08x", arm.sArmRegister[12] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R13: sprintf( info->s, "R13 :%08x", arm.sArmRegister[13] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R14: sprintf( info->s, "R14 :%08x", arm.sArmRegister[14] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_R15: sprintf( info->s, "R15 :%08x", arm.sArmRegister[15] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_FR8: sprintf( info->s, "FR8 :%08x", arm.sArmRegister[eR8_FIQ] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_FR9: sprintf( info->s, "FR9 :%08x", arm.sArmRegister[eR9_FIQ] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_FR10: sprintf( info->s, "FR10:%08x", arm.sArmRegister[eR10_FIQ] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_FR11: sprintf( info->s, "FR11:%08x", arm.sArmRegister[eR11_FIQ]); break;
+ case CPUINFO_STR_REGISTER + ARM32_FR12: sprintf( info->s, "FR12:%08x", arm.sArmRegister[eR12_FIQ] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_FR13: sprintf( info->s, "FR13:%08x", arm.sArmRegister[eR13_FIQ] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_FR14: sprintf( info->s, "FR14:%08x", arm.sArmRegister[eR14_FIQ] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_IR13: sprintf( info->s, "IR13:%08x", arm.sArmRegister[eR13_IRQ] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_IR14: sprintf( info->s, "IR14:%08x", arm.sArmRegister[eR14_IRQ] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_SR13: sprintf( info->s, "SR13:%08x", arm.sArmRegister[eR13_SVC] ); break;
+ case CPUINFO_STR_REGISTER + ARM32_SR14: sprintf( info->s, "SR14:%08x", arm.sArmRegister[eR14_SVC] ); break;
+ }
+}
diff --git a/src/emu/cpu/arm/arm.h b/src/emu/cpu/arm/arm.h
new file mode 100644
index 00000000000..a7331cebf5a
--- /dev/null
+++ b/src/emu/cpu/arm/arm.h
@@ -0,0 +1,32 @@
+#ifndef ARM_H
+#define ARM_H
+
+#include "cpuintrf.h"
+
+/****************************************************************************************************
+ * INTERRUPT CONSTANTS
+ ***************************************************************************************************/
+
+#define ARM_IRQ_LINE 0
+#define ARM_FIRQ_LINE 1
+
+/****************************************************************************************************
+ * PUBLIC FUNCTIONS
+ ***************************************************************************************************/
+
+extern void arm_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern UINT32 arm_disasm( char *pBuf, UINT32 pc, UINT32 opcode );
+#endif
+
+enum
+{
+ ARM32_PC=0,
+ ARM32_R0, ARM32_R1, ARM32_R2, ARM32_R3, ARM32_R4, ARM32_R5, ARM32_R6, ARM32_R7,
+ ARM32_R8, ARM32_R9, ARM32_R10, ARM32_R11, ARM32_R12, ARM32_R13, ARM32_R14, ARM32_R15,
+ ARM32_FR8, ARM32_FR9, ARM32_FR10, ARM32_FR11, ARM32_FR12, ARM32_FR13, ARM32_FR14,
+ ARM32_IR13, ARM32_IR14, ARM32_SR13, ARM32_SR14
+};
+
+#endif /* ARM_H */
diff --git a/src/emu/cpu/arm/armdasm.c b/src/emu/cpu/arm/armdasm.c
new file mode 100644
index 00000000000..21ae9b57c57
--- /dev/null
+++ b/src/emu/cpu/arm/armdasm.c
@@ -0,0 +1,393 @@
+/*
+ ARM 2/3 disassembler
+
+ (c) 2002-2006 Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino
+*/
+
+#include "arm.h"
+
+static char *WriteImmediateOperand( char *pBuf, UINT32 opcode )
+{
+ /* rrrrbbbbbbbb */
+ UINT32 imm;
+ int r;
+
+ imm = opcode&0xff;
+ r = ((opcode>>8)&0xf)*2;
+ imm = (imm>>r)|(imm<<(32-r));
+ pBuf += sprintf( pBuf, ", #$%x", imm );
+ return pBuf;
+}
+
+static char *WriteDataProcessingOperand( char *pBuf, UINT32 opcode, int printOp0, int printOp1, int printOp2 )
+{
+ /* ccccctttmmmm */
+ static const char *pRegOp[4] = { "LSL","LSR","ASR","ROR" };
+
+ if (printOp0)
+ pBuf += sprintf(pBuf,"R%d, ", (opcode>>12)&0xf);
+ if (printOp1)
+ pBuf += sprintf(pBuf,"R%d, ", (opcode>>16)&0xf);
+
+ /* Immediate Op2 */
+ if( opcode&0x02000000 )
+ return WriteImmediateOperand(pBuf-2,opcode);
+
+ /* Register Op2 */
+ if (printOp2)
+ pBuf += sprintf(pBuf,"R%d, ", (opcode>>0)&0xf);
+
+ pBuf += sprintf(pBuf, "%s ", pRegOp[(opcode>>5)&3] );
+
+ if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */
+ {
+ pBuf += sprintf( pBuf, "R%d", (opcode>>8)&0xf );
+ }
+ else /* Shift amount immediate 5 bit unsigned integer */
+ {
+ int c=(opcode>>7)&0x1f;
+ if( c==0 ) c = 32;
+ pBuf += sprintf( pBuf, "#%d", c );
+ }
+ return pBuf;
+}
+
+static char *WriteRegisterOperand1( char *pBuf, UINT32 opcode )
+{
+ /* ccccctttmmmm */
+ static const char *pRegOp[4] = { "LSL","LSR","ASR","ROR" };
+
+ pBuf += sprintf(
+ pBuf,
+ ", R%d %s ", /* Operand 1 register, Operand 2 register, shift type */
+ (opcode>> 0)&0xf,
+ pRegOp[(opcode>>5)&3] );
+
+ if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */
+ {
+ pBuf += sprintf( pBuf, "R%d", (opcode>>7)&0xf );
+ }
+ else /* Shift amount immediate 5 bit unsigned integer */
+ {
+ int c=(opcode>>7)&0x1f;
+ if( c==0 ) c = 32;
+ pBuf += sprintf( pBuf, "#%d", c );
+ }
+ return pBuf;
+} /* WriteRegisterOperand */
+
+
+static char *WriteBranchAddress( char *pBuf, UINT32 pc, UINT32 opcode )
+{
+ opcode &= 0x00ffffff;
+ if( opcode&0x00800000 )
+ {
+ opcode |= 0xff000000; /* sign-extend */
+ }
+ pc += 8+4*opcode;
+ sprintf( pBuf, "$%x", pc );
+ return pBuf;
+} /* WriteBranchAddress */
+
+static char *WritePadding( char *pBuf, const char *pBuf0 )
+{
+ pBuf0 += 8;
+ while( pBuf<pBuf0 )
+ {
+ *pBuf++ = ' ';
+ }
+ return pBuf;
+}
+
+UINT32 arm_disasm( char *pBuf, UINT32 pc, UINT32 opcode )
+{
+ const char *pBuf0;
+
+ static const char *pConditionCodeTable[16] =
+ {
+ "EQ","NE","CS","CC",
+ "MI","PL","VS","VC",
+ "HI","LS","GE","LT",
+ "GT","LE","","NV"
+ };
+ static const char *pOperation[16] =
+ {
+ "AND","EOR","SUB","RSB",
+ "ADD","ADC","SBC","RSC",
+ "TST","TEQ","CMP","CMN",
+ "ORR","MOV","BIC","MVN"
+ };
+ const char *pConditionCode;
+ UINT32 dasmflags = 0;
+
+ pConditionCode= pConditionCodeTable[opcode>>28];
+ pBuf0 = pBuf;
+
+ if( (opcode&0x0fc000f0)==0x00000090u )
+ {
+ /* multiply */
+ /* xxxx0000 00ASdddd nnnnssss 1001mmmm */
+ if( opcode&0x00200000 )
+ {
+ pBuf += sprintf( pBuf, "MLA" );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "MUL" );
+ }
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+ if( opcode&0x00100000 )
+ {
+ *pBuf++ = 'S';
+ }
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+ pBuf += sprintf( pBuf,
+ "R%d, R%d, R%d",
+ (opcode>>16)&0xf,
+ (opcode&0xf),
+ (opcode>>8)&0xf );
+
+ if( opcode&0x00200000 )
+ {
+ pBuf += sprintf( pBuf, ", R%d", (opcode>>12)&0xf );
+ }
+ }
+ else if( (opcode&0x0c000000)==0 )
+ {
+ int op=(opcode>>21)&0xf;
+
+ /* Data Processing */
+ /* xxxx001a aaaSnnnn ddddrrrr bbbbbbbb */
+ /* xxxx000a aaaSnnnn ddddcccc ctttmmmm */
+
+ pBuf += sprintf(
+ pBuf, "%s%s",
+ pOperation[op],
+ pConditionCode );
+
+ if( (opcode&0x01000000) )
+ {
+ *pBuf++ = 'S';
+ }
+
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+ switch (op) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x0c:
+ case 0x0e:
+ WriteDataProcessingOperand(pBuf, opcode, 1, 1, 1);
+ break;
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ WriteDataProcessingOperand(pBuf, opcode, 0, 1, 1);
+ break;
+ case 0x0d:
+ /* look for mov pc,lr */
+ if (((opcode >> 12) & 0x0f) == 15 && ((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0)
+ dasmflags = DASMFLAG_STEP_OUT;
+ case 0x0f:
+ WriteDataProcessingOperand(pBuf, opcode, 1, 0, 1);
+ break;
+ }
+ }
+ else if( (opcode&0x0c000000)==0x04000000 )
+ {
+ /* Data Transfer */
+
+ /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate form */
+ /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form */
+ if( opcode&0x00100000 )
+ {
+ pBuf += sprintf( pBuf, "LDR" );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "STR" );
+ }
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+
+ if( opcode&0x00400000 )
+ {
+ pBuf += sprintf( pBuf, "B" );
+ }
+
+ if( opcode&0x00200000 )
+ {
+ /* writeback addr */
+ if( opcode&0x01000000 )
+ {
+ /* pre-indexed addressing */
+ pBuf += sprintf( pBuf, "!" );
+ }
+ else
+ {
+ /* post-indexed addressing */
+ pBuf += sprintf( pBuf, "T" );
+ }
+ }
+
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf( pBuf, "R%d, [R%d",
+ (opcode>>12)&0xf, (opcode>>16)&0xf );
+
+ if( opcode&0x02000000 )
+ {
+ /* register form */
+ pBuf = WriteRegisterOperand1( pBuf, opcode );
+ pBuf += sprintf( pBuf, "]" );
+ }
+ else
+ {
+ /* immediate form */
+ pBuf += sprintf( pBuf, "]" );
+ if( opcode&0x00800000 )
+ {
+ pBuf += sprintf( pBuf, ", #$%x", opcode&0xfff );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, ", -#$%x", opcode&0xfff );
+ }
+ }
+ }
+ else if( (opcode&0x0e000000) == 0x08000000 )
+ {
+ /* xxxx100P USWLnnnn llllllll llllllll */
+ /* Block Data Transfer */
+
+ if( opcode&0x00100000 )
+ {
+ pBuf += sprintf( pBuf, "LDM" );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "STM" );
+ }
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+
+ if( opcode&0x01000000 )
+ {
+ pBuf += sprintf( pBuf, "P" );
+ }
+ if( opcode&0x00800000 )
+ {
+ pBuf += sprintf( pBuf, "U" );
+ }
+ if( opcode&0x00400000 )
+ {
+ pBuf += sprintf( pBuf, "^" );
+ }
+ if( opcode&0x00200000 )
+ {
+ pBuf += sprintf( pBuf, "W" );
+ }
+
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf( pBuf, "[R%d], {",(opcode>>16)&0xf);
+
+ {
+ int j=0,last=0,found=0;
+ for (j=0; j<16; j++) {
+ if (opcode&(1<<j) && found==0) {
+ found=1;
+ last=j;
+ }
+ else if ((opcode&(1<<j))==0 && found) {
+ if (last==j-1)
+ pBuf += sprintf( pBuf, " R%d,",last);
+ else
+ pBuf += sprintf( pBuf, " R%d-R%d,",last,j-1);
+ found=0;
+ }
+ }
+ if (found && last==15)
+ pBuf += sprintf( pBuf, " R15,");
+ else if (found)
+ pBuf += sprintf( pBuf, " R%d-R%d,",last,15);
+ }
+
+ pBuf--;
+ pBuf += sprintf( pBuf, " }");
+ }
+ else if( (opcode&0x0e000000)==0x0a000000 )
+ {
+ /* branch instruction */
+ /* xxxx101L oooooooo oooooooo oooooooo */
+ if( opcode&0x01000000 )
+ {
+ pBuf += sprintf( pBuf, "BL" );
+ dasmflags = DASMFLAG_STEP_OVER;
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "B" );
+ }
+
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+ pBuf = WriteBranchAddress( pBuf, pc, opcode );
+ }
+ else if( (opcode&0x0f000000) == 0x0e000000 )
+ {
+ /* co-processor */
+ /* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MRC/MCR */
+ if( (opcode&0x0f100000)==0x0e100000 )
+ {
+ if( (opcode&0x0f100010)==0x0e100010 )
+ {
+ pBuf += sprintf( pBuf, "MRC" );
+ }
+ else if( (opcode&0x0f100010)==0x0e000010 )
+ {
+ pBuf += sprintf( pBuf, "MCR" );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "???" );
+ }
+
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf( pBuf, "R%d, CR%d {CRM%d, q%d}",(opcode>>12)&0xf, (opcode>>16)&0xf, (opcode>>0)&0xf, (opcode>>5)&0x7);
+ /* Nb: full form should be o, p, R, CR, CRM, q */
+ }
+ else if( (opcode&0x0f000010)==0x0e000000 )
+ {
+ pBuf += sprintf( pBuf, "CDP" );
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf( pBuf, "%08x", opcode );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "???" );
+ }
+ }
+ else if( (opcode&0x0f000000) == 0x0f000000 )
+ {
+ /* Software Interrupt */
+ pBuf += sprintf( pBuf, "SWI%s $%x",
+ pConditionCode,
+ opcode&0x00ffffff );
+ dasmflags = DASMFLAG_STEP_OVER;
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "Undefined" );
+ }
+
+ return dasmflags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/arm7/arm7.c b/src/emu/cpu/arm7/arm7.c
new file mode 100644
index 00000000000..fe73bcc87ae
--- /dev/null
+++ b/src/emu/cpu/arm7/arm7.c
@@ -0,0 +1,464 @@
+/*****************************************************************************
+ *
+ * arm7.c
+ * Portable ARM7TDMI CPU Emulator
+ *
+ * Copyright (c) 2004 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
+ * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
+ * #3) Thumb support by Ryan Holtz
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ * Notes:
+
+ ** This is a plain vanilla implementation of an ARM7 cpu which incorporates my ARM7 core.
+ It can be used as is, or used to demonstrate how to utilize the arm7 core to create a cpu
+ that uses the core, since there are numerous different mcu packages that incorporate an arm7 core.
+
+ See the notes in the arm7core.c file itself regarding issues/limitations of the arm7 core.
+ **
+*****************************************************************************/
+#include "arm7.h"
+#include "debugger.h"
+#include "arm7core.h" //include arm7 core
+
+/* Example for showing how Co-Proc functions work */
+#define TEST_COPROC_FUNCS 1
+
+/*prototypes*/
+#if TEST_COPROC_FUNCS
+static WRITE32_HANDLER(test_do_callback);
+static READ32_HANDLER(test_rt_r_callback);
+static WRITE32_HANDLER(test_rt_w_callback);
+static void test_dt_r_callback (UINT32 insn, UINT32* prn, UINT32 (*read32)(int addr));
+static void test_dt_w_callback (UINT32 insn, UINT32* prn, void (*write32)(int addr, UINT32 data));
+#ifdef MAME_DEBUG
+static char *Spec_RT( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0);
+static char *Spec_DT( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0);
+static char *Spec_DO( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0);
+#endif
+#endif
+
+/* Macros that can be re-defined for custom cpu implementations - The core expects these to be defined */
+/* In this case, we are using the default arm7 handlers (supplied by the core)
+ - but simply changes these and define your own if needed for cpu implementation specific needs */
+#define READ8(addr) arm7_cpu_read8(addr)
+#define WRITE8(addr,data) arm7_cpu_write8(addr,data)
+#define READ16(addr) arm7_cpu_read16(addr)
+#define WRITE16(addr,data) arm7_cpu_write16(addr,data)
+#define READ32(addr) arm7_cpu_read32(addr)
+#define WRITE32(addr,data) arm7_cpu_write32(addr,data)
+#define PTR_READ32 &arm7_cpu_read32
+#define PTR_WRITE32 &arm7_cpu_write32
+
+/* Macros that need to be defined according to the cpu implementation specific need */
+#define ARM7REG(reg) arm7.sArmRegister[reg]
+#define ARM7 arm7
+#define ARM7_ICOUNT arm7_icount
+
+/* CPU Registers */
+typedef struct
+{
+ ARM7CORE_REGS //these must be included in your cpu specific register implementation
+} ARM7_REGS;
+
+static ARM7_REGS arm7;
+static int ARM7_ICOUNT;
+
+/* include the arm7 core */
+#include "arm7core.c"
+
+/***************************************************************************
+ * CPU SPECIFIC IMPLEMENTATIONS
+ **************************************************************************/
+static void arm7_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ //must call core
+ arm7_core_init("arm7", index);
+
+ ARM7.irq_callback = irqcallback;
+
+#if TEST_COPROC_FUNCS
+ //setup co-proc callbacks example
+ arm7_coproc_do_callback = test_do_callback;
+ arm7_coproc_rt_r_callback = test_rt_r_callback;
+ arm7_coproc_rt_w_callback = test_rt_w_callback;
+ arm7_coproc_dt_r_callback = test_dt_r_callback;
+ arm7_coproc_dt_w_callback = test_dt_w_callback;
+#ifdef MAME_DEBUG
+ //setup dasm callbacks - direct method example
+ arm7_dasm_cop_dt_callback = Spec_DT;
+ arm7_dasm_cop_rt_callback = Spec_RT;
+ arm7_dasm_cop_do_callback = Spec_DO;
+#endif
+#endif
+
+ return;
+}
+
+static void arm7_reset(void)
+{
+ //must call core reset
+ arm7_core_reset();
+}
+
+static void arm7_exit(void)
+{
+ /* nothing to do here */
+}
+
+static int arm7_execute( int cycles )
+{
+/*include the arm7 core execute code*/
+#include "arm7exec.c"
+} /* arm7_execute */
+
+
+static void set_irq_line(int irqline, int state)
+{
+ //must call core
+ arm7_core_set_irq_line(irqline,state);
+}
+
+static void arm7_get_context(void *dst)
+{
+ if( dst )
+ {
+ memcpy( dst, &ARM7, sizeof(ARM7) );
+ }
+}
+
+static void arm7_set_context(void *src)
+{
+ if (src)
+ {
+ memcpy( &ARM7, src, sizeof(ARM7) );
+ }
+}
+
+#ifdef MAME_DEBUG
+static offs_t arm7_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ if( T_IS_SET(GET_CPSR) )
+ {
+ return thumb_disasm( buffer, pc, oprom[0] | (oprom[1] << 8)) | 2;
+ }
+ else
+ {
+ return arm7_disasm( buffer, pc, oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24)) | 4;
+ }
+}
+#endif /* MAME_DEBUG */
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void arm7_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+
+ /* interrupt lines/exceptions */
+ case CPUINFO_INT_INPUT_STATE + ARM7_IRQ_LINE: set_irq_line(ARM7_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ARM7_FIRQ_LINE: set_irq_line(ARM7_FIRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ARM7_ABORT_EXCEPTION: set_irq_line(ARM7_ABORT_EXCEPTION, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ARM7_ABORT_PREFETCH_EXCEPTION: set_irq_line(ARM7_ABORT_PREFETCH_EXCEPTION, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + ARM7_UNDEFINE_EXCEPTION: set_irq_line(ARM7_UNDEFINE_EXCEPTION, info->i); break;
+
+ /* registers shared by all operating modes */
+ case CPUINFO_INT_REGISTER + ARM7_R0: ARM7REG( 0) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R1: ARM7REG( 1) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R2: ARM7REG( 2) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R3: ARM7REG( 3) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R4: ARM7REG( 4) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R5: ARM7REG( 5) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R6: ARM7REG( 6) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R7: ARM7REG( 7) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R8: ARM7REG( 8) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R9: ARM7REG( 9) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R10: ARM7REG(10) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R11: ARM7REG(11) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R12: ARM7REG(12) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R13: ARM7REG(13) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R14: ARM7REG(14) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_R15: ARM7REG(15) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_CPSR: SET_CPSR(info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ARM7_PC: R15 = info->i; break;
+ case CPUINFO_INT_SP: SetRegister(13,info->i); break;
+
+ /* FIRQ Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_FR8: ARM7REG(eR8_FIQ) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_FR9: ARM7REG(eR9_FIQ) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_FR10: ARM7REG(eR10_FIQ) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_FR11: ARM7REG(eR11_FIQ) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_FR12: ARM7REG(eR12_FIQ) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_FR13: ARM7REG(eR13_FIQ) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_FR14: ARM7REG(eR14_FIQ) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_FSPSR: ARM7REG(eSPSR_FIQ) = info->i; break;
+
+ /* IRQ Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_IR13: ARM7REG(eR13_IRQ) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_IR14: ARM7REG(eR14_IRQ) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_ISPSR: ARM7REG(eSPSR_IRQ) = info->i; break;
+
+ /* Supervisor Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_SR13: ARM7REG(eR13_SVC) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_SR14: ARM7REG(eR14_SVC) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_SSPSR: ARM7REG(eSPSR_SVC) = info->i; break;
+
+ /* Abort Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_AR13: ARM7REG(eR13_ABT) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_AR14: ARM7REG(eR14_ABT) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_ASPSR: ARM7REG(eSPSR_ABT) = info->i; break;
+
+ /* Undefined Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_UR13: ARM7REG(eR13_UND) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_UR14: ARM7REG(eR14_UND) = info->i; break;
+ case CPUINFO_INT_REGISTER + ARM7_USPSR: ARM7REG(eSPSR_UND) = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void arm7_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* cpu implementation data */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ARM7); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = ARM7_NUM_LINES; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 3; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 4; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ /* interrupt lines/exceptions */
+ case CPUINFO_INT_INPUT_STATE + ARM7_IRQ_LINE: info->i = ARM7.pendingIrq; break;
+ case CPUINFO_INT_INPUT_STATE + ARM7_FIRQ_LINE: info->i = ARM7.pendingFiq; break;
+ case CPUINFO_INT_INPUT_STATE + ARM7_ABORT_EXCEPTION: info->i = ARM7.pendingAbtD; break;
+ case CPUINFO_INT_INPUT_STATE + ARM7_ABORT_PREFETCH_EXCEPTION: info->i = ARM7.pendingAbtP; break;
+ case CPUINFO_INT_INPUT_STATE + ARM7_UNDEFINE_EXCEPTION: info->i = ARM7.pendingUnd; break;
+
+ /* registers shared by all operating modes */
+ case CPUINFO_INT_REGISTER + ARM7_R0: info->i = ARM7REG( 0); break;
+ case CPUINFO_INT_REGISTER + ARM7_R1: info->i = ARM7REG( 1); break;
+ case CPUINFO_INT_REGISTER + ARM7_R2: info->i = ARM7REG( 2); break;
+ case CPUINFO_INT_REGISTER + ARM7_R3: info->i = ARM7REG( 3); break;
+ case CPUINFO_INT_REGISTER + ARM7_R4: info->i = ARM7REG( 4); break;
+ case CPUINFO_INT_REGISTER + ARM7_R5: info->i = ARM7REG( 5); break;
+ case CPUINFO_INT_REGISTER + ARM7_R6: info->i = ARM7REG( 6); break;
+ case CPUINFO_INT_REGISTER + ARM7_R7: info->i = ARM7REG( 7); break;
+ case CPUINFO_INT_REGISTER + ARM7_R8: info->i = ARM7REG( 8); break;
+ case CPUINFO_INT_REGISTER + ARM7_R9: info->i = ARM7REG( 9); break;
+ case CPUINFO_INT_REGISTER + ARM7_R10: info->i = ARM7REG(10); break;
+ case CPUINFO_INT_REGISTER + ARM7_R11: info->i = ARM7REG(11); break;
+ case CPUINFO_INT_REGISTER + ARM7_R12: info->i = ARM7REG(12); break;
+ case CPUINFO_INT_REGISTER + ARM7_R13: info->i = ARM7REG(13); break;
+ case CPUINFO_INT_REGISTER + ARM7_R14: info->i = ARM7REG(14); break;
+ case CPUINFO_INT_REGISTER + ARM7_R15: info->i = ARM7REG(15); break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* not implemented */ break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ARM7_PC: info->i = R15; break;
+ case CPUINFO_INT_SP: info->i = GetRegister(13); break;
+
+ /* FIRQ Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_FR8: info->i = ARM7REG(eR8_FIQ); break;
+ case CPUINFO_INT_REGISTER + ARM7_FR9: info->i = ARM7REG(eR9_FIQ); break;
+ case CPUINFO_INT_REGISTER + ARM7_FR10: info->i = ARM7REG(eR10_FIQ); break;
+ case CPUINFO_INT_REGISTER + ARM7_FR11: info->i = ARM7REG(eR11_FIQ); break;
+ case CPUINFO_INT_REGISTER + ARM7_FR12: info->i = ARM7REG(eR12_FIQ); break;
+ case CPUINFO_INT_REGISTER + ARM7_FR13: info->i = ARM7REG(eR13_FIQ); break;
+ case CPUINFO_INT_REGISTER + ARM7_FR14: info->i = ARM7REG(eR14_FIQ); break;
+ case CPUINFO_INT_REGISTER + ARM7_FSPSR: info->i = ARM7REG(eSPSR_FIQ); break;
+
+ /* IRQ Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_IR13: info->i = ARM7REG(eR13_IRQ); break;
+ case CPUINFO_INT_REGISTER + ARM7_IR14: info->i = ARM7REG(eR14_IRQ); break;
+ case CPUINFO_INT_REGISTER + ARM7_ISPSR: info->i = ARM7REG(eSPSR_IRQ); break;
+
+ /* Supervisor Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_SR13: info->i = ARM7REG(eR13_SVC); break;
+ case CPUINFO_INT_REGISTER + ARM7_SR14: info->i = ARM7REG(eR14_SVC); break;
+ case CPUINFO_INT_REGISTER + ARM7_SSPSR: info->i = ARM7REG(eSPSR_SVC); break;
+
+ /* Abort Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_AR13: info->i = ARM7REG(eR13_ABT); break;
+ case CPUINFO_INT_REGISTER + ARM7_AR14: info->i = ARM7REG(eR14_ABT); break;
+ case CPUINFO_INT_REGISTER + ARM7_ASPSR: info->i = ARM7REG(eSPSR_ABT); break;
+
+ /* Undefined Mode Shadowed Registers */
+ case CPUINFO_INT_REGISTER + ARM7_UR13: info->i = ARM7REG(eR13_UND); break;
+ case CPUINFO_INT_REGISTER + ARM7_UR14: info->i = ARM7REG(eR14_UND); break;
+ case CPUINFO_INT_REGISTER + ARM7_USPSR: info->i = ARM7REG(eSPSR_UND); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = arm7_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = arm7_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = arm7_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = arm7_init; break;
+ case CPUINFO_PTR_RESET: info->reset = arm7_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = arm7_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = arm7_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = arm7_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ARM7_ICOUNT; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ARM7"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Acorn Risc Machine"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.3"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 2004-2006 Steve Ellenoff, sellenoff@hotmail.com"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c %s",
+ (ARM7REG(eCPSR) & N_MASK) ? 'N' : '-',
+ (ARM7REG(eCPSR) & Z_MASK) ? 'Z' : '-',
+ (ARM7REG(eCPSR) & C_MASK) ? 'C' : '-',
+ (ARM7REG(eCPSR) & V_MASK) ? 'V' : '-',
+ (ARM7REG(eCPSR) & I_MASK) ? 'I' : '-',
+ (ARM7REG(eCPSR) & F_MASK) ? 'F' : '-',
+ (ARM7REG(eCPSR) & T_MASK) ? 'T' : '-',
+ GetModeText(ARM7REG(eCPSR)));
+ break;
+
+ /* registers shared by all operating modes */
+ case CPUINFO_STR_REGISTER + ARM7_PC: sprintf(info->s, "PC :%08x", R15 ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R0: sprintf(info->s, "R0 :%08x", ARM7REG( 0) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R1: sprintf(info->s, "R1 :%08x", ARM7REG( 1) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R2: sprintf(info->s, "R2 :%08x", ARM7REG( 2) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R3: sprintf(info->s, "R3 :%08x", ARM7REG( 3) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R4: sprintf(info->s, "R4 :%08x", ARM7REG( 4) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R5: sprintf(info->s, "R5 :%08x", ARM7REG( 5) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R6: sprintf(info->s, "R6 :%08x", ARM7REG( 6) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R7: sprintf(info->s, "R7 :%08x", ARM7REG( 7) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R8: sprintf(info->s, "R8 :%08x", ARM7REG( 8) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R9: sprintf(info->s, "R9 :%08x", ARM7REG( 9) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R10: sprintf(info->s, "R10 :%08x", ARM7REG(10) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R11: sprintf(info->s, "R11 :%08x", ARM7REG(11) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R12: sprintf(info->s, "R12 :%08x", ARM7REG(12) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R13: sprintf(info->s, "R13 :%08x", ARM7REG(13) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R14: sprintf(info->s, "R14 :%08x", ARM7REG(14) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_R15: sprintf(info->s, "R15 :%08x", ARM7REG(15) ); break;
+
+ /* FIRQ Mode Shadowed Registers */
+ case CPUINFO_STR_REGISTER + ARM7_FR8: sprintf(info->s, "FR8 :%08x", ARM7REG(eR8_FIQ) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_FR9: sprintf(info->s, "FR9 :%08x", ARM7REG(eR9_FIQ) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_FR10: sprintf(info->s, "FR10:%08x", ARM7REG(eR10_FIQ) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_FR11: sprintf(info->s, "FR11:%08x", ARM7REG(eR11_FIQ) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_FR12: sprintf(info->s, "FR12:%08x", ARM7REG(eR12_FIQ) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_FR13: sprintf(info->s, "FR13:%08x", ARM7REG(eR13_FIQ) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_FR14: sprintf(info->s, "FR14:%08x", ARM7REG(eR14_FIQ) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_FSPSR: sprintf(info->s, "FR16:%08x", ARM7REG(eSPSR_FIQ)); break;
+
+ /* IRQ Mode Shadowed Registers */
+ case CPUINFO_STR_REGISTER + ARM7_IR13: sprintf(info->s, "IR13:%08x", ARM7REG(eR13_IRQ) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_IR14: sprintf(info->s, "IR14:%08x", ARM7REG(eR14_IRQ) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_ISPSR: sprintf(info->s, "IR16:%08x", ARM7REG(eSPSR_IRQ)); break;
+
+ /* Supervisor Mode Shadowed Registers */
+ case CPUINFO_STR_REGISTER + ARM7_SR13: sprintf(info->s, "SR13:%08x", ARM7REG(eR13_SVC) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_SR14: sprintf(info->s, "SR14:%08x", ARM7REG(eR14_SVC) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_SSPSR: sprintf(info->s, "SR16:%08x", ARM7REG(eSPSR_SVC)); break;
+
+ /* Abort Mode Shadowed Registers */
+ case CPUINFO_STR_REGISTER + ARM7_AR13: sprintf(info->s, "AR13:%08x", ARM7REG(eR13_ABT) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_AR14: sprintf(info->s, "AR14:%08x", ARM7REG(eR14_ABT) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_ASPSR: sprintf(info->s, "AR16:%08x", ARM7REG(eSPSR_ABT)); break;
+
+ /* Undefined Mode Shadowed Registers */
+ case CPUINFO_STR_REGISTER + ARM7_UR13: sprintf(info->s, "UR13:%08x", ARM7REG(eR13_UND) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_UR14: sprintf(info->s, "UR14:%08x", ARM7REG(eR14_UND) ); break;
+ case CPUINFO_STR_REGISTER + ARM7_USPSR: sprintf(info->s, "UR16:%08x", ARM7REG(eSPSR_UND)); break;
+ }
+}
+
+/* TEST COPROC CALLBACK HANDLERS - Used for example on how to implement only */
+#if TEST_COPROC_FUNCS
+
+static WRITE32_HANDLER(test_do_callback)
+{
+ LOG(("test_do_callback opcode=%x, =%x\n",offset,data));
+}
+static READ32_HANDLER(test_rt_r_callback)
+{
+ UINT32 data=0;
+ LOG(("test_rt_r_callback opcode=%x\n",offset));
+ return data;
+}
+static WRITE32_HANDLER(test_rt_w_callback)
+{
+ LOG(("test_rt_w_callback opcode=%x, data from ARM7 register=%x\n",offset,data));
+}
+static void test_dt_r_callback (UINT32 insn, UINT32* prn, UINT32 (*read32)(int addr))
+{
+ LOG(("test_dt_r_callback: insn = %x\n",insn));
+}
+static void test_dt_w_callback (UINT32 insn, UINT32* prn, void (*write32)(int addr, UINT32 data))
+{
+ LOG(("test_dt_w_callback: opcode = %x\n",insn));
+}
+
+/* Custom Co-proc DASM handlers */
+#ifdef MAME_DEBUG
+static char *Spec_RT( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0)
+{
+ pBuf += sprintf( pBuf, "SPECRT");
+ return pBuf;
+}
+static char *Spec_DT( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0)
+{
+ pBuf += sprintf( pBuf, "SPECDT");
+ return pBuf;
+}
+static char *Spec_DO( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0)
+{
+ pBuf += sprintf( pBuf, "SPECDO");
+ return pBuf;
+}
+#endif
+#endif
+
diff --git a/src/emu/cpu/arm7/arm7.h b/src/emu/cpu/arm7/arm7.h
new file mode 100644
index 00000000000..dc920146133
--- /dev/null
+++ b/src/emu/cpu/arm7/arm7.h
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ *
+ * arm7.h
+ * Portable ARM7TDMI CPU Emulator
+ *
+ * Copyright (c) 2004 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
+ * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
+ *
+ *****************************************************************************
+
+ This file contains everything related to the arm7 cpu specific implementation.
+ Anything related to the arm7 core itself is defined in arm7core.h instead.
+
+ ******************************************************************************/
+
+#ifndef ARM7_H
+#define ARM7_H
+
+#include "cpuintrf.h"
+
+/****************************************************************************************************
+ * PUBLIC FUNCTIONS
+ ***************************************************************************************************/
+extern void arm7_get_info(UINT32 state, cpuinfo *info);
+
+#endif /* ARM7_H */
diff --git a/src/emu/cpu/arm7/arm7core.c b/src/emu/cpu/arm7/arm7core.c
new file mode 100644
index 00000000000..04e491c87cc
--- /dev/null
+++ b/src/emu/cpu/arm7/arm7core.c
@@ -0,0 +1,1681 @@
+/*****************************************************************************
+ *
+ * arm7core.c
+ * Portable ARM7TDMI Core Emulator
+ *
+ * Copyright (c) 2004 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
+ * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
+ * #3) Thumb support by Ryan Holtz
+ * #4) Additional Thumb support and bugfixes by R. Belmont
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ * Notes:
+
+ **This core comes from my AT91 cpu core contributed to PinMAME,
+ but with all the AT91 specific junk removed,
+ which leaves just the ARM7TDMI core itself. I further removed the CPU specific MAME stuff
+ so you just have the actual ARM7 core itself, since many cpu's incorporate an ARM7 core, but add on
+ many cpu specific functionality.
+
+ Therefore, to use the core, you simpy include this file along with the .h file into your own cpu specific
+ implementation, and therefore, this file shouldn't be compiled as part of your project directly.
+ Additionally, you will need to include arm7exec.c in your cpu's execute routine.
+
+ For better or for worse, the code itself is very much intact from it's arm 2/3/6 origins from
+ Bryan & Phil's work. I contemplated merging it in, but thought the fact that the CPSR is
+ no longer part of the PC was enough of a change to make it annoying to merge.
+ **
+
+ Coprocessor functions are heavily implementation specific, so callback handlers are used to allow the
+ implementation to handle the functionality. Custom DASM handlers are included as well to allow the DASM
+ output to be tailored to the co-proc implementation details.
+
+ Todo:
+ 26 bit compatibility mode not implemented.
+ Data Processing opcodes need cycle count adjustments (see page 194 of ARM7TDMI manual for instruction timing summary)
+ Multi-emulated cpu support untested, but probably will not work too well, as no effort was made to code for more than 1.
+ Could not find info on what the TEQP opcode is from page 44..
+ I have no idea if user bank switching is right, as I don't fully understand it's use.
+ Search for Todo: tags for remaining items not done.
+
+
+ Differences from Arm 2/3 (6 also?)
+ -Thumb instruction support
+ -Full 32 bit address support
+ -PC no longer contains CPSR information, CPSR is own register now
+ -New register SPSR to store previous contents of CPSR (this register is banked in many modes)
+ -New opcodes for CPSR transfer, Long Multiplication, Co-Processor support, and some others
+ -User Bank Mode transfer using certain flags which were previously unallowed (LDM/STM with S Bit & R15)
+ -New operation modes? (unconfirmed)
+
+ Based heavily on arm core from MAME 0.76:
+ *****************************************
+ ARM 2/3/6 Emulation
+
+ Todo:
+ Software interrupts unverified (nothing uses them so far, but they should be ok)
+ Timing - Currently very approximated, nothing relies on proper timing so far.
+ IRQ timing not yet correct (again, nothing is affected by this so far).
+
+ By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino
+*****************************************************************************/
+
+#include <stdarg.h>
+
+#define ARM7_DEBUG_CORE 0
+
+#if 0
+#define LOG(x) mame_printf_debug x
+#else
+#define LOG(x) logerror x
+#endif
+
+/* Prototypes */
+
+//SJE: should these be inline? or are they too big to see any benefit?
+
+static void HandleCoProcDO(UINT32 insn);
+static void HandleCoProcRT(UINT32 insn);
+static void HandleCoProcDT(UINT32 insn);
+static void HandleHalfWordDT(UINT32 insn);
+static void HandleSwap(UINT32 insn);
+static void HandlePSRTransfer( UINT32 insn );
+static void HandleALU( UINT32 insn);
+static void HandleMul( UINT32 insn);
+static void HandleUMulLong( UINT32 insn);
+static void HandleSMulLong( UINT32 insn);
+//static void HandleBranch( UINT32 insn);
+INLINE void HandleBranch( UINT32 insn); //pretty short, so inline should be ok
+static void HandleMemSingle( UINT32 insn);
+static void HandleMemBlock( UINT32 insn);
+static UINT32 decodeShift( UINT32 insn, UINT32 *pCarry);
+INLINE void SwitchMode( int );
+static void arm7_check_irq_state(void);
+
+INLINE void arm7_cpu_write32( int addr, UINT32 data );
+INLINE void arm7_cpu_write16( int addr, UINT16 data );
+INLINE void arm7_cpu_write8( int addr, UINT8 data );
+INLINE UINT32 arm7_cpu_read32( int addr );
+INLINE UINT16 arm7_cpu_read16( int addr );
+INLINE UINT8 arm7_cpu_read8( offs_t addr );
+
+/* Static Vars */
+//Note: for multi-cpu implementation, this approach won't work w/o modification
+WRITE32_HANDLER((*arm7_coproc_do_callback)); //holder for the co processor Data Operations Callback func.
+READ32_HANDLER((*arm7_coproc_rt_r_callback)); //holder for the co processor Register Transfer Read Callback func.
+WRITE32_HANDLER((*arm7_coproc_rt_w_callback)); //holder for the co processor Register Transfer Write Callback Callback func.
+//holder for the co processor Data Transfer Read & Write Callback funcs
+void (*arm7_coproc_dt_r_callback)(UINT32 insn, UINT32* prn, UINT32 (*read32)(int addr));
+void (*arm7_coproc_dt_w_callback)(UINT32 insn, UINT32* prn, void (*write32)(int addr, UINT32 data));
+
+#ifdef MAME_DEBUG
+//custom dasm callback handlers for co-processor instructions
+char *(*arm7_dasm_cop_dt_callback)( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0 );
+char *(*arm7_dasm_cop_rt_callback)( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0 );
+char *(*arm7_dasm_cop_do_callback)( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0 );
+#endif
+
+/***************************************************************************
+ * Default Memory Handlers
+ ***************************************************************************/
+INLINE void arm7_cpu_write32( int addr, UINT32 data )
+{
+ addr &= ~3;
+ program_write_dword_32le(addr,data);
+}
+
+
+INLINE void arm7_cpu_write16( int addr, UINT16 data )
+{
+ addr &= ~1;
+ program_write_word_32le(addr,data);
+}
+
+INLINE void arm7_cpu_write8( int addr, UINT8 data )
+{
+ program_write_byte_32le(addr,data);
+}
+
+INLINE UINT32 arm7_cpu_read32( int addr )
+{
+ UINT32 result;
+
+ if (addr&3)
+ {
+ result = program_read_dword_32le(addr);
+ result = ( result >> ( 8 * ( addr & 3 ) ) ) | ( result << ( 32 - ( 8 * ( addr & 3 ) ) ) );
+ }
+ else
+ {
+ result = program_read_dword_32le(addr);
+ }
+ return result;
+}
+
+INLINE UINT16 arm7_cpu_read16( int addr )
+{
+ UINT16 result;
+
+ result = program_read_word_32le(addr & ~1);
+
+ if (addr & 1)
+ {
+ result = ((result>>8) & 0xff) | ((result&0xff)<<8);
+ }
+
+ return result;
+}
+
+INLINE UINT8 arm7_cpu_read8( offs_t addr )
+{
+ //Handle through normal 8 bit handler ( for 32 bit cpu )
+ return program_read_byte_32le(addr);
+}
+
+/***************
+ * helper funcs
+ ***************/
+
+/* Set NZCV flags for ADDS / SUBS */
+#define HandleALUAddFlags(rd, rn, op2) \
+ if (insn & INSN_S) \
+ SET_CPSR( \
+ ((GET_CPSR &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
+ | (((!SIGN_BITS_DIFFER(rn, op2)) && SIGN_BITS_DIFFER(rn, rd)) \
+ << V_BIT) \
+ | (((~(rn)) < (op2)) << C_BIT) \
+ | HandleALUNZFlags(rd))); \
+ R15 += 4;
+
+#define HandleThumbALUAddFlags(rd, rn, op2) \
+ SET_CPSR( \
+ ((GET_CPSR &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
+ | (((!THUMB_SIGN_BITS_DIFFER(rn, op2)) && THUMB_SIGN_BITS_DIFFER(rn, rd)) \
+ << V_BIT) \
+ | (((~(rn)) < (op2)) << C_BIT) \
+ | HandleALUNZFlags(rd))); \
+ R15 += 2;
+
+#define IsNeg(i) ((i) >> 31)
+#define IsPos(i) ((~(i)) >> 31)
+
+#define HandleALUSubFlags(rd, rn, op2) \
+ if (insn & INSN_S) \
+ SET_CPSR( \
+ ((GET_CPSR &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
+ | ((SIGN_BITS_DIFFER(rn, op2) && SIGN_BITS_DIFFER(rn, rd)) \
+ << V_BIT) \
+ | (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \
+ | HandleALUNZFlags(rd))); \
+ R15 += 4;
+
+#define HandleThumbALUSubFlags(rd, rn, op2) \
+ SET_CPSR( \
+ ((GET_CPSR &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \
+ | ((THUMB_SIGN_BITS_DIFFER(rn, op2) && THUMB_SIGN_BITS_DIFFER(rn, rd)) \
+ << V_BIT) \
+ | (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \
+ | HandleALUNZFlags(rd))); \
+ R15 += 2;
+
+/* Set NZC flags for logical operations. */
+
+//This macro (which I didn't write) - doesn't make it obvious that the SIGN BIT = 31, just as the N Bit does,
+//therfore, N is set by default
+#define HandleALUNZFlags(rd) \
+ (((rd) & SIGN_BIT) | ((!(rd)) << Z_BIT))
+
+
+//Long ALU Functions use bit 63
+#define HandleLongALUNZFlags(rd) \
+ ((((rd) & ((UINT64)1<<63))>>32) | ((!(rd)) << Z_BIT))
+
+#define HandleALULogicalFlags(rd, sc) \
+ if (insn & INSN_S) \
+ SET_CPSR( ((GET_CPSR &~ (N_MASK | Z_MASK | C_MASK)) \
+ | HandleALUNZFlags(rd) \
+ | (((sc) != 0) << C_BIT)));\
+ R15 += 4;
+
+//convert cpsr mode num into to text
+static const char modetext[ARM7_NUM_MODES][5] = {
+ "USER","FIRQ","IRQ","SVC","ILL1","ILL2","ILL3","ABT",
+ "ILL4","ILL5","ILL6","UND","ILL7","ILL8","ILL9","SYS"
+};
+static const char* GetModeText( int cpsr )
+{
+ return modetext[cpsr & MODE_FLAG];
+}
+
+//used to be functions, but no longer a need, so we'll use define for better speed.
+#define GetRegister(rIndex) ARM7REG(sRegisterTable[GET_MODE][rIndex])
+#define SetRegister(rIndex,value) ARM7REG(sRegisterTable[GET_MODE][rIndex]) = value
+
+//I could prob. convert to macro, but Switchmode shouldn't occur that often in emulated code..
+INLINE void SwitchMode (int cpsr_mode_val)
+{
+ UINT32 cspr = GET_CPSR & ~MODE_FLAG;
+ SET_CPSR(cspr | cpsr_mode_val);
+}
+
+
+/* Decodes an Op2-style shifted-register form. If @carry@ is non-zero the
+ * shifter carry output will manifest itself as @*carry == 0@ for carry clear
+ * and @*carry != 0@ for carry set.
+
+ SJE: Rules:
+ IF RC = 256, Result = no shift.
+ LSL 0 = Result = RM, Carry = Old Contents of CPSR C Bit
+ LSL(0,31) = Result shifted, least significant bit is in carry out
+ LSL 32 = Result of 0, Carry = Bit 0 of RM
+ LSL >32 = Result of 0, Carry out 0
+ LSR 0 = LSR 32 (see below)
+ LSR 32 = Result of 0, Carry = Bit 31 of RM
+ LSR >32 = Result of 0, Carry out 0
+ ASR >=32 = ENTIRE Result = bit 31 of RM
+ ROR 32 = Result = RM, Carry = Bit 31 of RM
+ ROR >32 = Same result as ROR n-32 until amount in range of 1-32 then follow rules
+*/
+
+static UINT32 decodeShift( UINT32 insn, UINT32 *pCarry)
+{
+ UINT32 k = (insn & INSN_OP2_SHIFT) >> INSN_OP2_SHIFT_SHIFT; //Bits 11-7
+ UINT32 rm = GET_REGISTER( insn & INSN_OP2_RM );
+ UINT32 t = (insn & INSN_OP2_SHIFT_TYPE) >> INSN_OP2_SHIFT_TYPE_SHIFT;
+
+ if ((insn & INSN_OP2_RM)==0xf) {
+ rm+=8;
+ }
+
+ /* All shift types ending in 1 are Rk, not #k */
+ if( t & 1 )
+ {
+// LOG(("%08x: RegShift %02x %02x\n",R15, k>>1,GET_REGISTER(k >> 1)));
+ #if ARM7_DEBUG_CORE
+ if((insn&0x80)==0x80)
+ LOG(("%08x: RegShift ERROR (p36)\n",R15));
+ #endif
+
+ //see p35 for check on this
+ //k = GET_REGISTER(k >> 1)&0x1f;
+
+ //Keep only the bottom 8 bits for a Register Shift
+ k = GET_REGISTER(k >> 1)&0xff;
+
+ if( k == 0 ) /* Register shift by 0 is a no-op */
+ {
+// LOG(("%08x: NO-OP Regshift\n",R15));
+ if (pCarry) *pCarry = GET_CPSR & C_MASK;
+ return rm;
+ }
+ }
+ /* Decode the shift type and perform the shift */
+ switch (t >> 1)
+ {
+ case 0: /* LSL */
+ //LSL 32 = Result of 0, Carry = Bit 0 of RM
+ //LSL >32 = Result of 0, Carry out 0
+ if(k>=32)
+ {
+ if(pCarry) *pCarry = (k==32)?rm&1:0;
+ return 0;
+ }
+ else
+ {
+ if (pCarry)
+ {
+ //LSL 0 = Result = RM, Carry = Old Contents of CPSR C Bit
+ //LSL (0,31) = Result shifted, least significant bit is in carry out
+ *pCarry = k ? (rm & (1 << (32 - k))) : (GET_CPSR & C_MASK);
+ }
+ return k ? LSL(rm, k) : rm;
+ }
+ break;
+
+ case 1: /* LSR */
+ if (k == 0 || k == 32)
+ {
+ if (pCarry) *pCarry = rm & SIGN_BIT;
+ return 0;
+ }
+ else if (k > 32)
+ {
+ if (pCarry) *pCarry = 0;
+ return 0;
+ }
+ else
+ {
+ if (pCarry) *pCarry = (rm & (1 << (k - 1)));
+ return LSR(rm, k);
+ }
+ break;
+
+ case 2: /* ASR */
+ if (k == 0 || k > 32)
+ k = 32;
+
+ if (pCarry) *pCarry = (rm & (1 << (k - 1)));
+ if (k >= 32)
+ return rm & SIGN_BIT ? 0xffffffffu : 0;
+ else
+ {
+ if (rm & SIGN_BIT)
+ return LSR(rm, k) | (0xffffffffu << (32 - k));
+ else
+ return LSR(rm, k);
+ }
+ break;
+
+ case 3: /* ROR and RRX */
+ if (k)
+ {
+ while (k > 32) k -= 32;
+ if (pCarry) *pCarry = rm & SIGN_BIT;
+ return ROR(rm, k);
+ }
+ else
+ {
+ if (pCarry) *pCarry = (rm & 1);
+ return LSR(rm, 1) | ((GET_CPSR & C_MASK) << 2);
+ }
+ break;
+ }
+
+ LOG(("%08x: Decodeshift error\n",R15));
+ return 0;
+} /* decodeShift */
+
+
+static int loadInc ( UINT32 pat, UINT32 rbv, UINT32 s)
+{
+ int i,result;
+
+ result = 0;
+ for( i=0; i<16; i++ )
+ {
+ if( (pat>>i)&1 )
+ {
+ if (i==15) {
+ if (s) /* Pull full contents from stack */
+ SET_REGISTER( 15, READ32(rbv+=4) );
+ else /* Pull only address, preserve mode & status flags */
+ SET_REGISTER( 15, READ32(rbv+=4) );
+ } else
+ SET_REGISTER( i, READ32(rbv+=4) );
+
+ result++;
+ }
+ }
+ return result;
+}
+
+static int loadDec( UINT32 pat, UINT32 rbv, UINT32 s)
+{
+ int i,result;
+
+ result = 0;
+ for( i=15; i>=0; i-- )
+ {
+ if( (pat>>i)&1 )
+ {
+ if (i==15) {
+ if (s) /* Pull full contents from stack */
+ SET_REGISTER( 15, READ32(rbv-=4) );
+ else /* Pull only address, preserve mode & status flags */
+ SET_REGISTER( 15, READ32(rbv-=4) );
+ }
+ else
+ SET_REGISTER( i, READ32(rbv -=4) );
+ result++;
+ }
+ }
+ return result;
+}
+
+static int storeInc( UINT32 pat, UINT32 rbv)
+{
+ int i,result;
+
+ result = 0;
+ for( i=0; i<16; i++ )
+ {
+ if( (pat>>i)&1 )
+ {
+ #if ARM7_DEBUG_CORE
+ if(i==15) /* R15 is plus 12 from address of STM */
+ LOG(("%08x: StoreInc on R15\n",R15));
+ #endif
+ WRITE32( rbv += 4, GET_REGISTER(i) );
+ result++;
+ }
+ }
+ return result;
+} /* storeInc */
+
+static int storeDec( UINT32 pat, UINT32 rbv)
+{
+ int i,result;
+
+ result = 0;
+ for( i=15; i>=0; i-- )
+ {
+ if( (pat>>i)&1 )
+ {
+ #if ARM7_DEBUG_CORE
+ if(i==15) /* R15 is plus 12 from address of STM */
+ LOG(("%08x: StoreDec on R15\n",R15));
+ #endif
+ WRITE32( rbv -= 4, GET_REGISTER(i) );
+ result++;
+ }
+ }
+ return result;
+} /* storeDec */
+
+/***************************************************************************
+ * Main CPU Funcs
+ ***************************************************************************/
+
+//CPU INIT
+static void arm7_core_init(const char *cpuname, int index)
+{
+ state_save_register_item_array(cpuname, index, ARM7.sArmRegister);
+ state_save_register_item(cpuname, index, ARM7.pendingIrq);
+ state_save_register_item(cpuname, index, ARM7.pendingFiq);
+ state_save_register_item(cpuname, index, ARM7.pendingAbtD);
+ state_save_register_item(cpuname, index, ARM7.pendingAbtP);
+ state_save_register_item(cpuname, index, ARM7.pendingUnd);
+ state_save_register_item(cpuname, index, ARM7.pendingSwi);
+}
+
+//CPU RESET
+static void arm7_core_reset(void)
+{
+ int (*save_irqcallback)(int) = ARM7.irq_callback;
+ memset(&ARM7, 0, sizeof(ARM7));
+ ARM7.irq_callback = save_irqcallback;
+
+ /* start up in SVC mode with interrupts disabled. */
+ SwitchMode(eARM7_MODE_SVC);
+ SET_CPSR(GET_CPSR | I_MASK | F_MASK);
+ R15 = 0;
+ change_pc(R15);
+}
+
+//Execute used to be here.. moved to separate file (arm7exec.c) to be included by cpu cores separately
+
+//CPU CHECK IRQ STATE
+//Note: couldn't find any exact cycle counts for most of these exceptions
+static void arm7_check_irq_state(void)
+{
+ UINT32 cpsr = GET_CPSR; /* save current CPSR */
+ UINT32 pc = R15+4; /* save old pc (already incremented in pipeline) */;
+
+ /* Exception priorities:
+
+ Reset
+ Data abort
+ FIRQ
+ IRQ
+ Prefetch abort
+ Undefined instruction
+ Software Interrupt
+ */
+
+ //Data Abort
+ if (ARM7.pendingAbtD) {
+ SwitchMode(eARM7_MODE_ABT); /* Set ABT mode so PC is saved to correct R14 bank */
+ SET_REGISTER( 14, pc ); /* save PC to R14 */
+ SET_REGISTER( SPSR, cpsr ); /* Save current CPSR */
+ SET_CPSR(GET_CPSR & ~T_MASK);
+ R15 = 0x10; /* IRQ Vector address */
+ change_pc(R15);
+ ARM7.pendingAbtD = 0;
+ return;
+ }
+
+ //FIRQ
+ if (ARM7.pendingFiq && (cpsr & F_MASK)==0) {
+ SwitchMode(eARM7_MODE_FIQ); /* Set FIQ mode so PC is saved to correct R14 bank */
+ SET_REGISTER( 14, pc ); /* save PC to R14 */
+ SET_REGISTER( SPSR, cpsr ); /* Save current CPSR */
+ SET_CPSR(GET_CPSR | I_MASK | F_MASK); /* Mask both IRQ & FIRQ*/
+ SET_CPSR(GET_CPSR & ~T_MASK);
+ R15 = 0x1c; /* IRQ Vector address */
+ change_pc(R15);
+ return;
+ }
+
+ //IRQ
+ if (ARM7.pendingIrq && (cpsr & I_MASK)==0) {
+ SwitchMode(eARM7_MODE_IRQ); /* Set IRQ mode so PC is saved to correct R14 bank */
+ SET_REGISTER( 14, pc ); /* save PC to R14 */
+ SET_REGISTER( SPSR, cpsr ); /* Save current CPSR */
+ SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */
+ SET_CPSR(GET_CPSR & ~T_MASK);
+ R15 = 0x18; /* IRQ Vector address */
+ change_pc(R15);
+ return;
+ }
+
+ //Prefetch Abort
+ if (ARM7.pendingAbtP) {
+ SwitchMode(eARM7_MODE_ABT); /* Set ABT mode so PC is saved to correct R14 bank */
+ SET_REGISTER( 14, pc ); /* save PC to R14 */
+ SET_REGISTER( SPSR, cpsr ); /* Save current CPSR */
+ SET_CPSR(GET_CPSR & ~T_MASK);
+ R15 = 0x0c; /* IRQ Vector address */
+ change_pc(R15);
+ ARM7.pendingAbtP = 0;
+ return;
+ }
+
+ //Undefined instruction
+ if (ARM7.pendingUnd) {
+ SwitchMode(eARM7_MODE_UND); /* Set UND mode so PC is saved to correct R14 bank */
+ SET_REGISTER( 14, pc ); /* save PC to R14 */
+ SET_REGISTER( SPSR, cpsr ); /* Save current CPSR */
+ SET_CPSR(GET_CPSR & ~T_MASK);
+ R15 = 0x04; /* IRQ Vector address */
+ change_pc(R15);
+ ARM7.pendingUnd = 0;
+ return;
+ }
+
+ //Software Interrupt
+ if (ARM7.pendingSwi) {
+ SwitchMode(eARM7_MODE_SVC); /* Set SVC mode so PC is saved to correct R14 bank */
+ // compensate for prefetch (should this also be done for normal IRQ?)
+ if (T_IS_SET(GET_CPSR))
+ {
+ SET_REGISTER( 14, pc-2 ); /* save PC to R14 */
+ }
+ else
+ {
+ SET_REGISTER( 14, pc ); /* save PC to R14 */
+ }
+ SET_REGISTER( SPSR, cpsr ); /* Save current CPSR */
+ SET_CPSR(GET_CPSR & ~T_MASK); /* Go to ARM mode */
+ R15 = 0x08; /* Jump to the SWI vector */
+ change_pc(R15);
+ ARM7.pendingSwi = 0;
+ return;
+ }
+}
+
+//CPU - SET IRQ LINE
+static void arm7_core_set_irq_line(int irqline, int state)
+{
+ switch (irqline) {
+
+ case ARM7_IRQ_LINE: /* IRQ */
+ ARM7.pendingIrq= (state & 1);
+ break;
+
+ case ARM7_FIRQ_LINE: /* FIRQ */
+ ARM7.pendingFiq= (state & 1);
+ break;
+
+ case ARM7_ABORT_EXCEPTION:
+ ARM7.pendingAbtD= (state & 1);
+ break;
+ case ARM7_ABORT_PREFETCH_EXCEPTION:
+ ARM7.pendingAbtP= (state & 1);
+ break;
+
+ case ARM7_UNDEFINE_EXCEPTION:
+ ARM7.pendingUnd= (state & 1);
+ break;
+ }
+
+ ARM7_CHECKIRQ;
+}
+
+/***************************************************************************
+ * OPCODE HANDLING
+ ***************************************************************************/
+
+// Co-Processor Data Operation
+static void HandleCoProcDO(UINT32 insn)
+{
+ // This instruction simply instructs the co-processor to do something, no data is returned to ARM7 core
+ if(arm7_coproc_do_callback)
+ arm7_coproc_do_callback(insn,0,0); //simply pass entire opcode to callback - since data format is actually dependent on co-proc implementation
+ else
+ LOG(("%08x: Co-Processor Data Operation executed, but no callback defined!\n",R15));
+}
+
+//Co-Processor Register Transfer - To/From Arm to Co-Proc
+static void HandleCoProcRT(UINT32 insn)
+{
+
+ /* xxxx 1110 oooL nnnn dddd cccc ppp1 mmmm */
+
+ // Load (MRC) data from Co-Proc to ARM7 register
+ if( insn&0x00100000 ) //Bit 20 = Load or Store
+ {
+ if(arm7_coproc_rt_r_callback)
+ {
+ UINT32 res = arm7_coproc_rt_r_callback(insn,0); //RT Read handler must parse opcode & return appropriate result
+ SET_REGISTER((insn>>12)&0xf,res);
+ }
+ else
+ LOG(("%08x: Co-Processor Register Transfer executed, but no RT Read callback defined!\n",R15));
+ }
+ // Store (MCR) data from ARM7 to Co-Proc register
+ else
+ {
+ if(arm7_coproc_rt_r_callback)
+ arm7_coproc_rt_w_callback(insn,GET_REGISTER((insn>>12)&0xf),0);
+ else
+ LOG(("%08x: Co-Processor Register Transfer executed, but no RT Write callback defined!\n",R15));
+ }
+}
+
+/*Data Transfer - To/From Arm to Co-Proc
+ Loading or Storing, the co-proc function is responsible to read/write from the base register supplied + offset
+ 8 bit immediate value Base Offset address is << 2 to get the actual #
+
+ issues - #1 - the co-proc function, needs direct access to memory reads or writes (ie, so we must send a pointer to a func)
+ - #2 - the co-proc may adjust the base address (especially if it reads more than 1 word), so a pointer to the register must be used
+ but the old value of the register must be restored if write back is not set..
+ - #3 - when post incrementing is used, it's up to the co-proc func. to add the offset, since the transfer
+ address supplied in that case, is simply the base. I suppose this is irrelevant if write back not set
+ but if co-proc reads multiple address, it must handle the offset adjustment itself.
+*/
+//todo: test with valid instructions
+static void HandleCoProcDT(UINT32 insn)
+{
+ UINT32 rn = (insn>>16)&0xf;
+ UINT32 rnv = GET_REGISTER(rn); // Get Address Value stored from Rn
+ UINT32 ornv = rnv; // Keep value of Rn
+ UINT32 off = (insn&0xff)<<2; // Offset is << 2 according to manual
+ UINT32* prn = &ARM7REG(rn); // Pointer to our register, so it can be changed in the callback
+
+ //Pointers to read32/write32 functions
+ void (*write32)(int addr, UINT32 data);
+ UINT32 (*read32)(int addr);
+ write32 = PTR_WRITE32;
+ read32 = PTR_READ32;
+
+ #if ARM7_DEBUG_CORE
+ if(((insn>>16)&0xf)==15 && (insn & 0x200000))
+ LOG(("%08x: Illegal use of R15 as base for write back value!\n",R15));
+ #endif
+
+ //Pre-Increment base address (IF POST INCREMENT - CALL BACK FUNCTION MUST DO IT)
+ if(insn&0x1000000 && off)
+ {
+ //Up - Down bit
+ if(insn&0x800000)
+ rnv+=off;
+ else
+ rnv-=off;
+ }
+
+ // Load (LDC) data from ARM7 memory to Co-Proc memory
+ if( insn&0x00100000 )
+ {
+ if(arm7_coproc_dt_r_callback)
+ arm7_coproc_dt_r_callback(insn,prn,read32);
+ else
+ LOG(("%08x: Co-Processer Data Transfer executed, but no READ callback defined!\n",R15));
+ }
+ // Store (STC) data from Co-Proc to ARM7 memory
+ else
+ {
+ if(arm7_coproc_dt_w_callback)
+ arm7_coproc_dt_w_callback(insn,prn,write32);
+ else
+ LOG(("%08x: Co-Processer Data Transfer executed, but no WRITE callback defined!\n",R15));
+ }
+
+ //If writeback not used - ensure the original value of RN is restored in case co-proc callback changed value
+ if((insn & 0x200000)==0)
+ SET_REGISTER(rn,ornv);
+}
+
+static void HandleBranch( UINT32 insn )
+{
+ UINT32 off = (insn & INSN_BRANCH) << 2;
+
+ /* Save PC into LR if this is a branch with link */
+ if (insn & INSN_BL)
+ {
+ SET_REGISTER(14,R15 + 4);
+ }
+
+ /* Sign-extend the 24-bit offset in our calculations */
+ if (off & 0x2000000u)
+ {
+ R15 -= ((~(off | 0xfc000000u)) + 1) - 8;
+ }
+ else
+ {
+ R15 += off + 8;
+ }
+
+ change_pc(R15);
+}
+
+static void HandleMemSingle( UINT32 insn )
+{
+ UINT32 rn, rnv, off, rd;
+
+ /* Fetch the offset */
+ if (insn & INSN_I)
+ {
+ /* Register Shift */
+ off = decodeShift(insn, NULL);
+ }
+ else
+ {
+ /* Immediate Value */
+ off = insn & INSN_SDT_IMM;
+ }
+
+ /* Calculate Rn, accounting for PC */
+ rn = (insn & INSN_RN) >> INSN_RN_SHIFT;
+
+ if (insn & INSN_SDT_P)
+ {
+ /* Pre-indexed addressing */
+ if (insn & INSN_SDT_U)
+ {
+ rnv = (GET_REGISTER(rn) + off);
+ }
+ else
+ {
+ rnv = (GET_REGISTER(rn) - off);
+ }
+
+ if (insn & INSN_SDT_W)
+ {
+ SET_REGISTER(rn,rnv);
+
+ //check writeback???
+ }
+ else if (rn == eR15)
+ {
+ rnv = rnv + 8;
+ }
+ }
+ else
+ {
+ /* Post-indexed addressing */
+ if (rn == eR15)
+ {
+ rnv = R15 + 8;
+ }
+ else
+ {
+ rnv = GET_REGISTER(rn);
+ }
+ }
+
+ /* Do the transfer */
+ rd = (insn & INSN_RD) >> INSN_RD_SHIFT;
+ if (insn & INSN_SDT_L)
+ {
+ /* Load */
+ if (insn & INSN_SDT_B)
+ {
+ SET_REGISTER(rd,(UINT32) READ8(rnv));
+ }
+ else
+ {
+ if (rd == eR15)
+ {
+ R15 = READ32(rnv);
+ R15 -= 4;
+ change_pc(R15);
+ //LDR, PC takes 2S + 2N + 1I (5 total cycles)
+ ARM7_ICOUNT -= 2;
+ }
+ else
+ {
+ SET_REGISTER(rd,READ32(rnv));
+ }
+ }
+ }
+ else
+ {
+ /* Store */
+ if (insn & INSN_SDT_B)
+ {
+ #if ARM7_DEBUG_CORE
+ if(rd==eR15)
+ LOG(("Wrote R15 in byte mode\n"));
+ #endif
+
+ WRITE8(rnv, (UINT8) GET_REGISTER(rd) & 0xffu);
+ }
+ else
+ {
+ #if ARM7_DEBUG_CORE
+ if(rd==eR15)
+ LOG(("Wrote R15 in 32bit mode\n"));
+ #endif
+
+ //WRITE32(rnv, rd == eR15 ? R15 + 8 : GET_REGISTER(rd));
+ WRITE32(rnv, rd == eR15 ? R15 + 8 + 4 : GET_REGISTER(rd)); //manual says STR rd = PC, +12
+ }
+ //Store takes only 2 N Cycles, so add + 1
+ ARM7_ICOUNT += 1;
+ }
+
+ /* Do post-indexing writeback */
+ if (!(insn & INSN_SDT_P)/* && (insn&INSN_SDT_W)*/)
+ {
+ if (insn & INSN_SDT_U)
+ {
+ /* Writeback is applied in pipeline, before value is read from mem,
+ so writeback is effectively ignored */
+ if (rd==rn) {
+ SET_REGISTER(rn,GET_REGISTER(rd));
+ //todo: check for offs... ?
+ }
+ else {
+
+ if ((insn&INSN_SDT_W)!=0)
+ LOG(("%08x: RegisterWritebackIncrement %d %d %d\n",R15,(insn & INSN_SDT_P)!=0,(insn&INSN_SDT_W)!=0,(insn & INSN_SDT_U)!=0));
+
+ SET_REGISTER(rn,(rnv + off));
+ }
+ }
+ else
+ {
+ /* Writeback is applied in pipeline, before value is read from mem,
+ so writeback is effectively ignored */
+ if (rd==rn) {
+ SET_REGISTER(rn,GET_REGISTER(rd));
+ }
+ else {
+ SET_REGISTER(rn,(rnv - off));
+
+ if ((insn&INSN_SDT_W)!=0)
+ LOG(("%08x: RegisterWritebackDecrement %d %d %d\n",R15,(insn & INSN_SDT_P)!=0,(insn&INSN_SDT_W)!=0,(insn & INSN_SDT_U)!=0));
+ }
+ }
+ }
+
+// ARM7_CHECKIRQ
+
+} /* HandleMemSingle */
+
+static void HandleHalfWordDT(UINT32 insn)
+{
+ UINT32 rn, rnv, off, rd;
+
+ //Immediate or Register Offset?
+ if(insn & 0x400000) { //Bit 22 - 1 = immediate, 0 = register
+ //imm. value in high nibble (bits 8-11) and lo nibble (bit 0-3)
+ off = (((insn>>8)&0x0f)<<4) | (insn&0x0f);
+ }
+ else {
+ //register
+ off = GET_REGISTER(insn & 0x0f);
+ }
+
+ /* Calculate Rn, accounting for PC */
+ rn = (insn & INSN_RN) >> INSN_RN_SHIFT;
+
+ if (insn & INSN_SDT_P)
+ {
+ /* Pre-indexed addressing */
+ if (insn & INSN_SDT_U)
+ {
+ rnv = (GET_REGISTER(rn) + off);
+ }
+ else
+ {
+ rnv = (GET_REGISTER(rn) - off);
+ }
+
+ if (insn & INSN_SDT_W)
+ {
+ SET_REGISTER(rn,rnv);
+
+ //check writeback???
+ }
+ else if (rn == eR15)
+ {
+ rnv = (rnv) + 8;
+ }
+ }
+ else
+ {
+ /* Post-indexed addressing */
+ if (rn == eR15)
+ {
+ rnv = R15 + 8;
+ }
+ else
+ {
+ rnv = GET_REGISTER(rn);
+ }
+ }
+
+ /* Do the transfer */
+ rd = (insn & INSN_RD) >> INSN_RD_SHIFT;
+
+ /* Load */
+ if (insn & INSN_SDT_L)
+ {
+ //Signed?
+ if(insn & 0x40)
+ {
+ UINT32 newval = 0;
+
+ //Signed Half Word?
+ if(insn & 0x20) {
+ UINT16 signbyte,databyte;
+ databyte = READ16(rnv) & 0xFFFF;
+ signbyte = (databyte & 0x8000) ? 0xffff : 0;
+ newval = (UINT32)(signbyte<<16)|databyte;
+ }
+ //Signed Byte
+ else {
+ UINT8 databyte;
+ UINT32 signbyte;
+ databyte = READ8(rnv) & 0xff;
+ signbyte = (databyte & 0x80) ? 0xffffff : 0;
+ newval = (UINT32)(signbyte<<8)|databyte;
+ }
+
+ //PC?
+ if(rd == eR15)
+ {
+ R15 = newval + 8;
+ //LDR(H,SH,SB) PC takes 2S + 2N + 1I (5 total cycles)
+ ARM7_ICOUNT -= 2;
+
+ }
+ else
+ {
+ SET_REGISTER(rd,newval);
+ R15 += 4;
+ }
+ }
+ //Unsigned Half Word
+ else
+ {
+ if (rd == eR15)
+ {
+ R15 = READ16(rnv) + 8;
+ }
+ else
+ {
+ SET_REGISTER(rd,READ16(rnv));
+ R15 += 4;
+ }
+ }
+
+
+ }
+ /* Store */
+ else
+ {
+ //WRITE16(rnv, rd == eR15 ? R15 + 8 : GET_REGISTER(rd));
+ WRITE16(rnv, rd == eR15 ? R15 + 8 + 4 : GET_REGISTER(rd)); //manual says STR RD=PC, +12 of address
+ if(rn != eR15)
+ R15 += 4;
+ //STRH takes 2 cycles, so we add + 1
+ ARM7_ICOUNT += 1;
+ }
+
+
+
+ //SJE: No idea if this writeback code works or makes sense here..
+
+ /* Do post-indexing writeback */
+ if (!(insn & INSN_SDT_P)/* && (insn&INSN_SDT_W)*/)
+ {
+ if (insn & INSN_SDT_U)
+ {
+ /* Writeback is applied in pipeline, before value is read from mem,
+ so writeback is effectively ignored */
+ if (rd==rn) {
+ SET_REGISTER(rn,GET_REGISTER(rd));
+ //todo: check for offs... ?
+ }
+ else {
+
+ if ((insn&INSN_SDT_W)!=0)
+ LOG(("%08x: RegisterWritebackIncrement %d %d %d\n",R15,(insn & INSN_SDT_P)!=0,(insn&INSN_SDT_W)!=0,(insn & INSN_SDT_U)!=0));
+
+ SET_REGISTER(rn,(rnv + off));
+ }
+ }
+ else
+ {
+ /* Writeback is applied in pipeline, before value is read from mem,
+ so writeback is effectively ignored */
+ if (rd==rn) {
+ SET_REGISTER(rn,GET_REGISTER(rd));
+ }
+ else {
+ SET_REGISTER(rn,(rnv - off));
+
+ if ((insn&INSN_SDT_W)!=0)
+ LOG(("%08x: RegisterWritebackDecrement %d %d %d\n",R15,(insn & INSN_SDT_P)!=0,(insn&INSN_SDT_W)!=0,(insn & INSN_SDT_U)!=0));
+ }
+ }
+ }
+ change_pc(R15);
+}
+
+static void HandleSwap(UINT32 insn)
+{
+ UINT32 rn, rm, rd, tmp;
+
+ rn = GET_REGISTER((insn>>16)&0xf); // reg. w/read address
+ rm = GET_REGISTER(insn&0xf); // reg. w/write address
+ rd = (insn>>12)&0xf; // dest reg
+
+ #if ARM7_DEBUG_CORE
+ if(rn == 15 || rm == 15 || rd == 15)
+ LOG(("%08x: Illegal use of R15 in Swap Instruction\n",R15));
+ #endif
+
+ // can be byte or word
+ if(insn & 0x400000)
+ {
+ tmp = READ8(rn);
+ WRITE8(rn, rm);
+ SET_REGISTER(rd, tmp);
+ }
+ else
+ {
+ tmp = READ32(rn);
+ WRITE32(rn, rm);
+ SET_REGISTER(rd, tmp);
+ }
+
+ R15 += 4;
+ //Instruction takes 1S+2N+1I cycles - so we subtract one more..
+ ARM7_ICOUNT -=1;
+}
+
+static void HandlePSRTransfer( UINT32 insn )
+{
+ int reg = (insn & 0x400000) ? SPSR : eCPSR; //Either CPSR or SPSR
+ UINT32 newval, val = 0;
+ int oldmode = GET_CPSR & MODE_FLAG;
+
+ // get old value of CPSR/SPSR
+ newval = GET_REGISTER(reg);
+
+ //MSR ( bit 21 set ) - Copy value to CPSR/SPSR
+ if( (insn & 0x00200000) )
+ {
+ //MSR (register transfer)?
+ if(insn & 0x10000)
+ {
+ val = GET_REGISTER(insn & 0x0f);
+ }
+ //MSR (register or immediate transfer - flag bits only)
+ else
+ {
+ //Immediate Value?
+ if(insn & INSN_I) {
+ //Value can be specified for a Right Rotate, 2x the value specified.
+ int by = (insn & INSN_OP2_ROTATE) >> INSN_OP2_ROTATE_SHIFT;
+ if (by)
+ val = ROR(insn & INSN_OP2_IMM, by << 1);
+ else
+ val = insn & INSN_OP2_IMM;
+ }
+ //Value from Register
+ else
+ {
+ val = GET_REGISTER(insn & 0x0f);
+ }
+ }
+
+ // apply field code bits
+ if (reg == eCPSR)
+ {
+ if ((GET_CPSR & 0x1f) > 0x10)
+ {
+ if (insn & 0x00010000)
+ {
+ newval = (newval & 0xffffff00) | (val & 0xff);
+ }
+ if (insn & 0x00020000)
+ {
+ newval = (newval & 0xffff00ff) | (val & 0xff00);
+ }
+ if (insn & 0x00040000)
+ {
+ newval = (newval & 0xff00ffff) | (val & 0xff0000);
+ }
+ }
+
+ // status flags can be modified regardless of mode
+ if (insn & 0x00080000)
+ {
+ newval = (newval & 0x00ffffff) | (val & 0xff000000);
+ }
+ }
+ else // SPSR has stricter requirements
+ {
+ if (((GET_CPSR & 0x1f) > 0x10) && ((GET_CPSR & 0x1f) < 0x1f))
+ {
+ if (insn & 0x00010000)
+ {
+ newval = (newval & 0xffffff00) | (val & 0xff);
+ }
+ if (insn & 0x00020000)
+ {
+ newval = (newval & 0xffff00ff) | (val & 0xff00);
+ }
+ if (insn & 0x00040000)
+ {
+ newval = (newval & 0xff00ffff) | (val & 0xff0000);
+ }
+ if (insn & 0x00080000)
+ {
+ newval = (newval & 0x00ffffff) | (val & 0xff000000);
+ }
+ }
+ }
+
+ // force valid mode
+ newval |= 0x10;
+
+ //Update the Register
+ SET_REGISTER(reg, val);
+
+ //Switch to new mode if changed
+ if( (val & MODE_FLAG) != oldmode)
+ SwitchMode(GET_MODE);
+
+ }
+ //MRS ( bit 21 clear ) - Copy CPSR or SPSR to specified Register
+ else
+ {
+ SET_REGISTER( (insn>>12)& 0x0f ,GET_REGISTER(reg));
+ }
+}
+
+static void HandleALU( UINT32 insn )
+{
+ UINT32 op2, sc=0, rd, rn, opcode;
+ UINT32 by, rdn;
+ UINT32 oldR15 = R15;
+
+ opcode = (insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT;
+
+ rd = 0;
+ rn = 0;
+
+ /* --------------*/
+ /* Construct Op2 */
+ /* --------------*/
+
+ /* Immediate constant */
+ if (insn & INSN_I)
+ {
+ by = (insn & INSN_OP2_ROTATE) >> INSN_OP2_ROTATE_SHIFT;
+ if (by)
+ {
+ op2 = ROR(insn & INSN_OP2_IMM, by << 1);
+ sc = op2 & SIGN_BIT;
+ }
+ else
+ {
+ op2 = insn & INSN_OP2; //SJE: Shouldn't this be INSN_OP2_IMM?
+ sc = GET_CPSR & C_MASK;
+ }
+ }
+ /* Op2 = Register Value */
+ else
+ {
+ op2 = decodeShift(insn, (insn & INSN_S) ? &sc : NULL);
+
+ if (!(insn & INSN_S))
+ sc=0;
+ }
+
+ /* Calculate Rn to account for pipelining */
+ if ((opcode & 0xd) != 0xd) /* No Rn in MOV */
+ {
+ if ((rn = (insn & INSN_RN) >> INSN_RN_SHIFT) == eR15)
+ {
+ #if ARM7_DEBUG_CORE
+ LOG(("%08x: Pipelined R15 (Shift %d)\n",R15,(insn&INSN_I?8:insn&0x10u?12:12)));
+ #endif
+ rn=R15+8;
+ }
+ else
+ {
+ rn = GET_REGISTER(rn);
+ }
+ }
+
+ /* Perform the operation */
+
+ switch (opcode)
+ {
+ /* Arithmetic operations */
+ case OPCODE_SBC:
+ rd = (rn - op2 - (GET_CPSR & C_MASK ? 0 : 1));
+ HandleALUSubFlags(rd, rn, op2);
+ break;
+ case OPCODE_CMP:
+ case OPCODE_SUB:
+ rd = (rn - op2);
+ HandleALUSubFlags(rd, rn, op2);
+ break;
+ case OPCODE_RSC:
+ rd = (op2 - rn - (GET_CPSR & C_MASK ? 0 : 1));
+ HandleALUSubFlags(rd, op2, rn);
+ break;
+ case OPCODE_RSB:
+ rd = (op2 - rn);
+ HandleALUSubFlags(rd, op2, rn);
+ break;
+ case OPCODE_ADC:
+ rd = (rn + op2 + ((GET_CPSR & C_MASK) >> C_BIT));
+ HandleALUAddFlags(rd, rn, op2);
+ break;
+ case OPCODE_CMN:
+ case OPCODE_ADD:
+ rd = (rn + op2);
+ HandleALUAddFlags(rd, rn, op2);
+ break;
+
+ /* Logical operations */
+ case OPCODE_AND:
+ case OPCODE_TST:
+ rd = rn & op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_BIC:
+ rd = rn &~ op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_TEQ:
+ case OPCODE_EOR:
+ rd = rn ^ op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_ORR:
+ rd = rn | op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_MOV:
+ rd = op2;
+ HandleALULogicalFlags(rd, sc);
+ break;
+ case OPCODE_MVN:
+ rd = (~op2);
+ HandleALULogicalFlags(rd, sc);
+ break;
+ }
+
+ /* Put the result in its register if not one of the test only opcodes (TST,TEQ,CMP,CMN) */
+ rdn = (insn & INSN_RD) >> INSN_RD_SHIFT;
+ if ((opcode & 0xc) != 0x8)
+ {
+ //If Rd = R15, but S Flag not set, Result is placed in R15, but CPSR is not affected (page 44)
+ if (rdn == eR15 && !(insn & INSN_S))
+ {
+ R15 = rd;
+ }
+ else
+ {
+ //Rd = 15 and S Flag IS set, Result is placed in R15, and current mode SPSR moved to CPSR
+ if (rdn==eR15) {
+
+ //Update CPSR from SPSR
+ SET_CPSR(GET_REGISTER(SPSR));
+ SwitchMode(GET_MODE);
+
+ R15 = rd;
+
+ /* IRQ masks may have changed in this instruction */
+// ARM7_CHECKIRQ;
+ }
+ else
+ /* S Flag is set - Write results to register & update CPSR (which was already handled using HandleALU flag macros) */
+ SET_REGISTER(rdn,rd);
+ }
+ }
+ //SJE: Don't think this applies any more.. (see page 44 at bottom)
+ /* TST & TEQ can affect R15 (the condition code register) with the S bit set */
+ else if (rdn==eR15)
+ {
+ if (insn & INSN_S) {
+ #if ARM7_DEBUG_CORE
+ LOG(("%08x: TST class on R15 s bit set\n",R15));
+ #endif
+ R15 = rd;
+
+ /* IRQ masks may have changed in this instruction */
+// ARM7_CHECKIRQ;
+ }
+ else
+ {
+ #if ARM7_DEBUG_CORE
+ LOG(("%08x: TST class on R15 no s bit set\n",R15));
+ #endif
+ }
+ }
+
+ if (oldR15 != R15)
+ change_pc(R15);
+}
+
+static void HandleMul( UINT32 insn)
+{
+ UINT32 r;
+
+ /* Do the basic multiply of Rm and Rs */
+ r = GET_REGISTER( insn&INSN_MUL_RM ) *
+ GET_REGISTER( (insn&INSN_MUL_RS)>>INSN_MUL_RS_SHIFT );
+
+ #if ARM7_DEBUG_CORE
+ if(
+ ((insn&INSN_MUL_RM)==0xf) ||
+ (((insn&INSN_MUL_RS)>>INSN_MUL_RS_SHIFT )==0xf) ||
+ (((insn&INSN_MUL_RN)>>INSN_MUL_RN_SHIFT)==0xf)
+ )
+ LOG(("%08x: R15 used in mult\n",R15));
+ #endif
+
+ /* Add on Rn if this is a MLA */
+ if (insn & INSN_MUL_A)
+ {
+ r += GET_REGISTER((insn&INSN_MUL_RN)>>INSN_MUL_RN_SHIFT);
+ }
+
+ /* Write the result */
+ SET_REGISTER((insn&INSN_MUL_RD)>>INSN_MUL_RD_SHIFT,r);
+
+ /* Set N and Z if asked */
+ if( insn & INSN_S )
+ {
+ SET_CPSR ( (GET_CPSR &~ (N_MASK | Z_MASK)) | HandleALUNZFlags(r));
+ }
+}
+
+//todo: add proper cycle counts
+static void HandleSMulLong( UINT32 insn)
+{
+ INT32 rm, rs;
+ UINT32 rhi,rlo;
+ INT64 res=0;
+
+ rm = (INT32)GET_REGISTER(insn&0xf);
+ rs = (INT32)GET_REGISTER(((insn>>8)&0xf));
+ rhi = (insn>>16)&0xf;
+ rlo = (insn>>12)&0xf;
+
+ #if ARM7_DEBUG_CORE
+ if( ((insn&0xf) == 15) || (((insn>>8)&0xf) == 15) || (((insn>>16)&0xf) == 15) || (((insn>>12)&0xf) == 15)
+ LOG(("%08x: Illegal use of PC as a register in SMULL opcode\n",R15));
+ #endif
+
+ /* Perform the multiplication */
+ res = (INT64)rm * rs;
+
+ /* Add on Rn if this is a MLA */
+ if (insn & INSN_MUL_A)
+ {
+ INT64 acum = (INT64)((((INT64)(GET_REGISTER(rhi)))<<32) | GET_REGISTER(rlo));
+ res += acum;
+ }
+
+ /* Write the result (upper dword goes to RHi, lower to RLo) */
+ SET_REGISTER(rhi, res>>32);
+ SET_REGISTER(rlo, res & 0xFFFFFFFF);
+
+ /* Set N and Z if asked */
+ if( insn & INSN_S )
+ {
+ SET_CPSR ( (GET_CPSR &~ (N_MASK | Z_MASK)) | HandleLongALUNZFlags(res));
+ }
+}
+
+//todo: add proper cycle counts
+static void HandleUMulLong( UINT32 insn)
+{
+ UINT32 rm, rs;
+ UINT32 rhi,rlo;
+ UINT64 res=0;
+
+ rm = (INT32)GET_REGISTER(insn&0xf);
+ rs = (INT32)GET_REGISTER(((insn>>8)&0xf));
+ rhi = (insn>>16)&0xf;
+ rlo = (insn>>12)&0xf;
+
+ #if ARM7_DEBUG_CORE
+ if( ((insn&0xf) == 15) || (((insn>>8)&0xf) == 15) || (((insn>>16)&0xf) == 15) || (((insn>>12)&0xf) == 15)
+ LOG(("%08x: Illegal use of PC as a register in SMULL opcode\n",R15));
+ #endif
+
+ /* Perform the multiplication */
+ res = (UINT64)rm * rs;
+
+ /* Add on Rn if this is a MLA */
+ if (insn & INSN_MUL_A)
+ {
+ UINT64 acum = (UINT64)((((UINT64)(GET_REGISTER(rhi)))<<32) | GET_REGISTER(rlo));
+ res += acum;
+ }
+
+ /* Write the result (upper dword goes to RHi, lower to RLo) */
+ SET_REGISTER(rhi, res>>32);
+ SET_REGISTER(rlo, res & 0xFFFFFFFF);
+
+ /* Set N and Z if asked */
+ if( insn & INSN_S )
+ {
+ SET_CPSR ( (GET_CPSR &~ (N_MASK | Z_MASK)) | HandleLongALUNZFlags(res));
+ }
+}
+
+static void HandleMemBlock( UINT32 insn)
+{
+ UINT32 rb = (insn & INSN_RN) >> INSN_RN_SHIFT;
+ UINT32 rbp = GET_REGISTER(rb);
+ UINT32 oldR15 = R15;
+ int result;
+
+#if ARM7_DEBUG_CORE
+ if(rbp & 3)
+ LOG(("%08x: Unaligned Mem Transfer @ %08x\n",R15,rbp));
+#endif
+
+ //We will specify the cycle count for each case, so remove the -3 that occurs at the end
+ ARM7_ICOUNT +=3;
+
+ if (insn & INSN_BDT_L)
+ {
+ /* Loading */
+ if (insn & INSN_BDT_U)
+ {
+ /* Incrementing */
+ if (!(insn & INSN_BDT_P))
+ {
+ rbp = rbp + (- 4);
+ }
+
+ //S Flag Set, but R15 not in list = User Bank Transfer
+ if(insn & INSN_BDT_S && ((insn & 0x8000)==0))
+ {
+ //set to user mode - then do the transfer, and set back
+ int curmode = GET_MODE;
+ SwitchMode(eARM7_MODE_USER);
+ LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n",R15));
+ result = loadInc( insn & 0xffff, rbp, insn&INSN_BDT_S );
+ //todo - not sure if Writeback occurs on User registers also..
+ SwitchMode(curmode);
+ }
+ else
+ result = loadInc( insn & 0xffff, rbp, insn&INSN_BDT_S );
+
+ if (insn & INSN_BDT_W)
+ {
+ #if ARM7_DEBUG_CORE
+ if(rb==15)
+ LOG(("%08x: Illegal LDRM writeback to r15\n",R15));
+ #endif
+ SET_REGISTER(rb,GET_REGISTER(rb)+result*4);
+ }
+
+ //R15 included? (NOTE: CPSR restore must occur LAST otherwise wrong registers restored!)
+ if (insn & 0x8000) {
+ R15-=4; //SJE: I forget why i did this?
+ //S - Flag Set? Signals transfer of current mode SPSR->CPSR
+ if(insn & INSN_BDT_S) {
+ SET_CPSR(GET_REGISTER(SPSR));
+ SwitchMode(GET_MODE);
+ }
+ }
+ //LDM PC - takes 1 extra cycle
+ ARM7_ICOUNT -=1;
+ }
+ else
+ {
+ /* Decrementing */
+ if (!(insn & INSN_BDT_P))
+ {
+ rbp = rbp - (- 4);
+ }
+
+ //S Flag Set, but R15 not in list = User Bank Transfer
+ if(insn & INSN_BDT_S && ((insn & 0x8000)==0))
+ {
+ //set to user mode - then do the transfer, and set back
+ int curmode = GET_MODE;
+ SwitchMode(eARM7_MODE_USER);
+ LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n",R15));
+ result = loadDec( insn&0xffff, rbp, insn&INSN_BDT_S );
+ //todo - not sure if Writeback occurs on User registers also..
+ SwitchMode(curmode);
+ }
+ else
+ result = loadDec( insn&0xffff, rbp, insn&INSN_BDT_S );
+
+ if (insn & INSN_BDT_W)
+ {
+ if (rb==0xf)
+ LOG(("%08x: Illegal LDRM writeback to r15\n",R15));
+ SET_REGISTER(rb,GET_REGISTER(rb)-result*4);
+ }
+
+ //R15 included? (NOTE: CPSR restore must occur LAST otherwise wrong registers restored!)
+ if (insn & 0x8000) {
+ R15-=4; //SJE: I forget why i did this?
+ //S - Flag Set? Signals transfer of current mode SPSR->CPSR
+ if(insn & INSN_BDT_S) {
+ SET_CPSR(GET_REGISTER(SPSR));
+ SwitchMode(GET_MODE);
+ }
+ //LDM PC - takes 1 extra cycle
+ ARM7_ICOUNT -=1;
+ }
+
+ //LDM (NO PC) takes nS + 1n + 1I cycles (n = # of register transfers)
+ ARM7_ICOUNT -= (result+1+1);
+ }
+ } /* Loading */
+ else
+ {
+ /* Storing */
+ if (insn & (1<<eR15))
+ {
+ #if ARM7_DEBUG_CORE
+ LOG(("%08x: Writing R15 in strm\n",R15));
+ #endif
+ /* special case handling if writing to PC */
+ R15 += 12;
+ }
+ if (insn & INSN_BDT_U)
+ {
+ /* Incrementing */
+ if (!(insn & INSN_BDT_P))
+ {
+ rbp = rbp + (- 4);
+ }
+
+ //S Flag Set, but R15 not in list = User Bank Transfer
+ if(insn & INSN_BDT_S && ((insn & 0x8000)==0))
+ {
+ //todo: needs to be tested..
+
+ //set to user mode - then do the transfer, and set back
+ int curmode = GET_MODE;
+ SwitchMode(eARM7_MODE_USER);
+ LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n",R15));
+ result = storeInc( insn&0xffff, rbp );
+ //todo - not sure if Writeback occurs on User registers also..
+ SwitchMode(curmode);
+ }
+ else
+ result = storeInc( insn&0xffff, rbp );
+
+ if( insn & INSN_BDT_W )
+ {
+ SET_REGISTER(rb,GET_REGISTER(rb)+result*4);
+ }
+ }
+ else
+ {
+ /* Decrementing */
+ if (!(insn & INSN_BDT_P))
+ {
+ rbp = rbp - (- 4);
+ }
+
+ //S Flag Set, but R15 not in list = User Bank Transfer
+ if(insn & INSN_BDT_S && ((insn & 0x8000)==0))
+ {
+ //set to user mode - then do the transfer, and set back
+ int curmode = GET_MODE;
+ SwitchMode(eARM7_MODE_USER);
+ LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n",R15));
+ result = storeDec( insn&0xffff, rbp );
+ //todo - not sure if Writeback occurs on User registers also..
+ SwitchMode(curmode);
+ }
+ else
+ result = storeDec( insn&0xffff, rbp );
+
+ if( insn & INSN_BDT_W )
+ {
+ SET_REGISTER(rb,GET_REGISTER(rb)-result*4);
+ }
+ }
+ if( insn & (1<<eR15) )
+ R15 -= 12;
+
+ //STM takes (n+1)S+2N+1I cycles (n = # of register transfers)
+ ARM7_ICOUNT -= ((result+1)+2+1);
+ }
+
+ if (oldR15 != R15)
+ change_pc(R15);
+} /* HandleMemBlock */
+
+
diff --git a/src/emu/cpu/arm7/arm7core.h b/src/emu/cpu/arm7/arm7core.h
new file mode 100644
index 00000000000..54ccd49dab1
--- /dev/null
+++ b/src/emu/cpu/arm7/arm7core.h
@@ -0,0 +1,412 @@
+/*****************************************************************************
+ *
+ * arm7core.h
+ * Portable ARM7TDMI Core Emulator
+ *
+ * Copyright (c) 2004 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
+ * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
+ *
+ *****************************************************************************
+
+ This file contains everything related to the arm7 core itself, and is presumed
+ to be cpu implementation non-specific, ie, applies to only the core.
+
+ ******************************************************************************/
+
+
+
+#ifndef ARM7CORE_H
+#define ARM7CORE_H
+
+#include "cpuintrf.h"
+
+/****************************************************************************************************
+ * INTERRUPT LINES/EXCEPTIONS
+ ***************************************************************************************************/
+enum
+{
+ ARM7_IRQ_LINE=0, ARM7_FIRQ_LINE,
+ ARM7_ABORT_EXCEPTION, ARM7_ABORT_PREFETCH_EXCEPTION, ARM7_UNDEFINE_EXCEPTION,
+ ARM7_NUM_LINES
+};
+//Really there's only 1 ABORT Line.. and cpu decides whether it's during data fetch or prefetch, but we let the user specify
+
+/****************************************************************************************************
+ * ARM7 CORE REGISTERS
+ ***************************************************************************************************/
+enum
+{
+ ARM7_PC=0,
+ ARM7_R0, ARM7_R1, ARM7_R2, ARM7_R3, ARM7_R4, ARM7_R5, ARM7_R6, ARM7_R7,
+ ARM7_R8, ARM7_R9, ARM7_R10, ARM7_R11, ARM7_R12, ARM7_R13, ARM7_R14, ARM7_R15,
+ ARM7_FR8, ARM7_FR9, ARM7_FR10, ARM7_FR11, ARM7_FR12, ARM7_FR13, ARM7_FR14,
+ ARM7_IR13, ARM7_IR14, ARM7_SR13, ARM7_SR14, ARM7_FSPSR, ARM7_ISPSR, ARM7_SSPSR,
+ ARM7_CPSR, ARM7_AR13, ARM7_AR14, ARM7_ASPSR, ARM7_UR13, ARM7_UR14, ARM7_USPSR
+};
+
+#define ARM7CORE_REGS \
+ UINT32 sArmRegister[kNumRegisters]; \
+ UINT8 pendingIrq; \
+ UINT8 pendingFiq; \
+ UINT8 pendingAbtD; \
+ UINT8 pendingAbtP; \
+ UINT8 pendingUnd; \
+ UINT8 pendingSwi; \
+ int (*irq_callback)(int);
+
+
+/****************************************************************************************************
+ * VARIOUS INTERNAL STRUCS/DEFINES/ETC..
+ ***************************************************************************************************/
+// Mode values come from bit 4-0 of CPSR, but we are ignoring bit 4 here, since bit 4 always = 1 for valid modes
+enum
+{
+ eARM7_MODE_USER = 0x0, // Bit: 4-0 = 10000
+ eARM7_MODE_FIQ = 0x1, // Bit: 4-0 = 10001
+ eARM7_MODE_IRQ = 0x2, // Bit: 4-0 = 10010
+ eARM7_MODE_SVC = 0x3, // Bit: 4-0 = 10011
+ eARM7_MODE_ABT = 0x7, // Bit: 4-0 = 10111
+ eARM7_MODE_UND = 0xb, // Bit: 4-0 = 11011
+ eARM7_MODE_SYS = 0xf // Bit: 4-0 = 11111
+};
+
+#define ARM7_NUM_MODES 0x10
+
+/* There are 36 Unique - 32 bit processor registers */
+/* Each mode has 17 registers (except user & system, which have 16) */
+/* This is a list of each *unique* register */
+enum
+{
+ /* All modes have the following */
+ eR0=0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13, /* Stack Pointer */
+ eR14, /* Link Register (holds return address) */
+ eR15, /* Program Counter */
+ eCPSR, /* Current Status Program Register */
+
+ /* Fast Interrupt - Bank switched registers */
+ eR8_FIQ,eR9_FIQ,eR10_FIQ,eR11_FIQ,eR12_FIQ,eR13_FIQ,eR14_FIQ,eSPSR_FIQ,
+
+ /* IRQ - Bank switched registers*/
+ eR13_IRQ,eR14_IRQ,eSPSR_IRQ,
+
+ /* Supervisor/Service Mode - Bank switched registers*/
+ eR13_SVC,eR14_SVC,eSPSR_SVC,
+
+ /* Abort Mode - Bank switched registers*/
+ eR13_ABT,eR14_ABT,eSPSR_ABT,
+
+ /* Undefined Mode - Bank switched registers*/
+ eR13_UND,eR14_UND,eSPSR_UND,
+
+ kNumRegisters
+};
+
+static const int thumbCycles[256] =
+{
+// 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ 1, 1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 4
+ 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 5
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 6
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 7
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 8
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 9
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // a
+ 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, // b
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, // d
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // e
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // f
+};
+
+/* 17 processor registers are visible at any given time,
+ * banked depending on processor mode.
+ */
+static const int sRegisterTable[ARM7_NUM_MODES][18] =
+{
+ { /* USR */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13,eR14,
+ eR15,eCPSR //No SPSR in this mode
+ },
+ { /* FIQ */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8_FIQ,eR9_FIQ,eR10_FIQ,eR11_FIQ,eR12_FIQ,
+ eR13_FIQ,eR14_FIQ,
+ eR15,eCPSR,eSPSR_FIQ
+ },
+ { /* IRQ */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13_IRQ,eR14_IRQ,
+ eR15,eCPSR,eSPSR_IRQ
+ },
+ { /* SVC */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13_SVC,eR14_SVC,
+ eR15,eCPSR,eSPSR_SVC
+ },
+ {0},{0},{0}, //values for modes 4,5,6 are not valid
+ { /* ABT */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13_ABT,eR14_ABT,
+ eR15,eCPSR,eSPSR_ABT
+ },
+ {0},{0},{0}, //values for modes 8,9,a are not valid!
+ { /* UND */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13_UND,eR14_UND,
+ eR15,eCPSR,eSPSR_UND
+ },
+ {0},{0},{0}, //values for modes c,d,e are not valid!
+ { /* SYS */
+ eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7,
+ eR8,eR9,eR10,eR11,eR12,
+ eR13,eR14,
+ eR15,eCPSR //No SPSR in this mode
+ }
+};
+
+#define N_BIT 31
+#define Z_BIT 30
+#define C_BIT 29
+#define V_BIT 28
+#define I_BIT 7
+#define F_BIT 6
+#define T_BIT 5 //Thumb mode
+
+#define N_MASK ((UINT32)(1<<N_BIT)) /* Negative flag */
+#define Z_MASK ((UINT32)(1<<Z_BIT)) /* Zero flag */
+#define C_MASK ((UINT32)(1<<C_BIT)) /* Carry flag */
+#define V_MASK ((UINT32)(1<<V_BIT)) /* oVerflow flag */
+#define I_MASK ((UINT32)(1<<I_BIT)) /* Interrupt request disable */
+#define F_MASK ((UINT32)(1<<F_BIT)) /* Fast interrupt request disable */
+#define T_MASK ((UINT32)(1<<T_BIT)) /* Thumb Mode flag */
+
+#define N_IS_SET(pc) ((pc) & N_MASK)
+#define Z_IS_SET(pc) ((pc) & Z_MASK)
+#define C_IS_SET(pc) ((pc) & C_MASK)
+#define V_IS_SET(pc) ((pc) & V_MASK)
+#define I_IS_SET(pc) ((pc) & I_MASK)
+#define F_IS_SET(pc) ((pc) & F_MASK)
+#define T_IS_SET(pc) ((pc) & T_MASK)
+
+#define N_IS_CLEAR(pc) (!N_IS_SET(pc))
+#define Z_IS_CLEAR(pc) (!Z_IS_SET(pc))
+#define C_IS_CLEAR(pc) (!C_IS_SET(pc))
+#define V_IS_CLEAR(pc) (!V_IS_SET(pc))
+#define I_IS_CLEAR(pc) (!I_IS_SET(pc))
+#define F_IS_CLEAR(pc) (!F_IS_SET(pc))
+#define T_IS_CLEAR(pc) (!T_IS_SET(pc))
+
+/* Deconstructing an instruction */
+//todo: use these in all places (including dasm file)
+#define INSN_COND ((UINT32) 0xf0000000u)
+#define INSN_SDT_L ((UINT32) 0x00100000u)
+#define INSN_SDT_W ((UINT32) 0x00200000u)
+#define INSN_SDT_B ((UINT32) 0x00400000u)
+#define INSN_SDT_U ((UINT32) 0x00800000u)
+#define INSN_SDT_P ((UINT32) 0x01000000u)
+#define INSN_BDT_L ((UINT32) 0x00100000u)
+#define INSN_BDT_W ((UINT32) 0x00200000u)
+#define INSN_BDT_S ((UINT32) 0x00400000u)
+#define INSN_BDT_U ((UINT32) 0x00800000u)
+#define INSN_BDT_P ((UINT32) 0x01000000u)
+#define INSN_BDT_REGS ((UINT32) 0x0000ffffu)
+#define INSN_SDT_IMM ((UINT32) 0x00000fffu)
+#define INSN_MUL_A ((UINT32) 0x00200000u)
+#define INSN_MUL_RM ((UINT32) 0x0000000fu)
+#define INSN_MUL_RS ((UINT32) 0x00000f00u)
+#define INSN_MUL_RN ((UINT32) 0x0000f000u)
+#define INSN_MUL_RD ((UINT32) 0x000f0000u)
+#define INSN_I ((UINT32) 0x02000000u)
+#define INSN_OPCODE ((UINT32) 0x01e00000u)
+#define INSN_S ((UINT32) 0x00100000u)
+#define INSN_BL ((UINT32) 0x01000000u)
+#define INSN_BRANCH ((UINT32) 0x00ffffffu)
+#define INSN_SWI ((UINT32) 0x00ffffffu)
+#define INSN_RN ((UINT32) 0x000f0000u)
+#define INSN_RD ((UINT32) 0x0000f000u)
+#define INSN_OP2 ((UINT32) 0x00000fffu)
+#define INSN_OP2_SHIFT ((UINT32) 0x00000f80u)
+#define INSN_OP2_SHIFT_TYPE ((UINT32) 0x00000070u)
+#define INSN_OP2_RM ((UINT32) 0x0000000fu)
+#define INSN_OP2_ROTATE ((UINT32) 0x00000f00u)
+#define INSN_OP2_IMM ((UINT32) 0x000000ffu)
+#define INSN_OP2_SHIFT_TYPE_SHIFT 4
+#define INSN_OP2_SHIFT_SHIFT 7
+#define INSN_OP2_ROTATE_SHIFT 8
+#define INSN_MUL_RS_SHIFT 8
+#define INSN_MUL_RN_SHIFT 12
+#define INSN_MUL_RD_SHIFT 16
+#define INSN_OPCODE_SHIFT 21
+#define INSN_RN_SHIFT 16
+#define INSN_RD_SHIFT 12
+#define INSN_COND_SHIFT 28
+
+#define THUMB_INSN_TYPE ((UINT16) 0xf000)
+#define THUMB_COND_TYPE ((UINT16) 0x0f00)
+#define THUMB_GROUP4_TYPE ((UINT16) 0x0c00)
+#define THUMB_GROUP5_TYPE ((UINT16) 0x0e00)
+#define THUMB_GROUP5_RM ((UINT16) 0x01c0)
+#define THUMB_GROUP5_RN ((UINT16) 0x0038)
+#define THUMB_GROUP5_RD ((UINT16) 0x0007)
+#define THUMB_ADDSUB_RNIMM ((UINT16) 0x01c0)
+#define THUMB_ADDSUB_RS ((UINT16) 0x0038)
+#define THUMB_ADDSUB_RD ((UINT16) 0x0007)
+#define THUMB_INSN_ADDSUB ((UINT16) 0x0800)
+#define THUMB_INSN_CMP ((UINT16) 0x0800)
+#define THUMB_INSN_SUB ((UINT16) 0x0800)
+#define THUMB_INSN_IMM_RD ((UINT16) 0x0700)
+#define THUMB_INSN_IMM_S ((UINT16) 0x0080)
+#define THUMB_INSN_IMM ((UINT16) 0x00ff)
+#define THUMB_ADDSUB_TYPE ((UINT16) 0x0600)
+#define THUMB_HIREG_OP ((UINT16) 0x0300)
+#define THUMB_HIREG_H ((UINT16) 0x00c0)
+#define THUMB_HIREG_RS ((UINT16) 0x0038)
+#define THUMB_HIREG_RD ((UINT16) 0x0007)
+#define THUMB_STACKOP_TYPE ((UINT16) 0x0f00)
+#define THUMB_STACKOP_L ((UINT16) 0x0800)
+#define THUMB_STACKOP_RD ((UINT16) 0x0700)
+#define THUMB_ALUOP_TYPE ((UINT16) 0x03c0)
+#define THUMB_BLOP_LO ((UINT16) 0x0800)
+#define THUMB_BLOP_OFFS ((UINT16) 0x07ff)
+#define THUMB_SHIFT_R ((UINT16) 0x0800)
+#define THUMB_SHIFT_AMT ((UINT16) 0x07c0)
+#define THUMB_HALFOP_L ((UINT16) 0x0800)
+#define THUMB_HALFOP_OFFS ((UINT16) 0x07c0)
+#define THUMB_BRANCH_OFFS ((UINT16) 0x07ff)
+#define THUMB_LSOP_L ((UINT16) 0x0800)
+#define THUMB_LSOP_OFFS ((UINT16) 0x07c0)
+#define THUMB_MULTLS ((UINT16) 0x0800)
+#define THUMB_MULTLS_BASE ((UINT16) 0x0700)
+#define THUMB_RELADDR_SP ((UINT16) 0x0800)
+#define THUMB_RELADDR_RD ((UINT16) 0x0700)
+#define THUMB_INSN_TYPE_SHIFT 12
+#define THUMB_COND_TYPE_SHIFT 8
+#define THUMB_GROUP4_TYPE_SHIFT 10
+#define THUMB_GROUP5_TYPE_SHIFT 9
+#define THUMB_ADDSUB_TYPE_SHIFT 9
+#define THUMB_INSN_IMM_RD_SHIFT 8
+#define THUMB_STACKOP_TYPE_SHIFT 8
+#define THUMB_HIREG_OP_SHIFT 8
+#define THUMB_STACKOP_RD_SHIFT 8
+#define THUMB_MULTLS_BASE_SHIFT 8
+#define THUMB_RELADDR_RD_SHIFT 8
+#define THUMB_HIREG_H_SHIFT 6
+#define THUMB_HIREG_RS_SHIFT 3
+#define THUMB_ALUOP_TYPE_SHIFT 6
+#define THUMB_SHIFT_AMT_SHIFT 6
+#define THUMB_HALFOP_OFFS_SHIFT 6
+#define THUMB_LSOP_OFFS_SHIFT 6
+#define THUMB_GROUP5_RM_SHIFT 6
+#define THUMB_GROUP5_RN_SHIFT 3
+#define THUMB_GROUP5_RD_SHIFT 0
+#define THUMB_ADDSUB_RNIMM_SHIFT 6
+#define THUMB_ADDSUB_RS_SHIFT 3
+#define THUMB_ADDSUB_RD_SHIFT 0
+
+enum
+{
+ OPCODE_AND, /* 0000 */
+ OPCODE_EOR, /* 0001 */
+ OPCODE_SUB, /* 0010 */
+ OPCODE_RSB, /* 0011 */
+ OPCODE_ADD, /* 0100 */
+ OPCODE_ADC, /* 0101 */
+ OPCODE_SBC, /* 0110 */
+ OPCODE_RSC, /* 0111 */
+ OPCODE_TST, /* 1000 */
+ OPCODE_TEQ, /* 1001 */
+ OPCODE_CMP, /* 1010 */
+ OPCODE_CMN, /* 1011 */
+ OPCODE_ORR, /* 1100 */
+ OPCODE_MOV, /* 1101 */
+ OPCODE_BIC, /* 1110 */
+ OPCODE_MVN /* 1111 */
+};
+
+enum
+{
+ COND_EQ = 0, /* Z: equal */
+ COND_NE, /* ~Z: not equal */
+ COND_CS, COND_HS = 2, /* C: unsigned higher or same */
+ COND_CC, COND_LO = 3, /* ~C: unsigned lower */
+ COND_MI, /* N: negative */
+ COND_PL, /* ~N: positive or zero */
+ COND_VS, /* V: overflow */
+ COND_VC, /* ~V: no overflow */
+ COND_HI, /* C && ~Z: unsigned higher */
+ COND_LS, /* ~C || Z: unsigned lower or same */
+ COND_GE, /* N == V: greater or equal */
+ COND_LT, /* N != V: less than */
+ COND_GT, /* ~Z && (N == V): greater than */
+ COND_LE, /* Z || (N != V): less than or equal */
+ COND_AL, /* always */
+ COND_NV /* never */
+};
+
+#define LSL(v,s) ((v) << (s))
+#define LSR(v,s) ((v) >> (s))
+#define ROL(v,s) (LSL((v),(s)) | (LSR((v),32u - (s))))
+#define ROR(v,s) (LSR((v),(s)) | (LSL((v),32u - (s))))
+
+/* Convenience Macros */
+#define R15 ARM7REG(eR15)
+#define SPSR 17 //SPSR is always the 18th register in our 0 based array sRegisterTable[][18]
+#define GET_CPSR ARM7REG(eCPSR)
+#define SET_CPSR(v) (GET_CPSR = (v))
+#define MODE_FLAG 0xF //Mode bits are 4:0 of CPSR, but we ignore bit 4.
+#define GET_MODE (GET_CPSR & MODE_FLAG)
+#define SIGN_BIT ((UINT32)(1<<31))
+#define SIGN_BITS_DIFFER(a,b) (((a)^(b)) >> 31)
+/* I really don't know why these were set to 16-bit, the thumb registers are still 32-bit ... */
+#define THUMB_SIGN_BIT ((UINT32)(1<<31))
+#define THUMB_SIGN_BITS_DIFFER(a,b) (((a)^(b)) >> 31)
+
+/* At one point I thought these needed to be cpu implementation specific, but they don't.. */
+#define GET_REGISTER(reg) GetRegister(reg)
+#define SET_REGISTER(reg,val) SetRegister(reg,val)
+#define ARM7_CHECKIRQ arm7_check_irq_state()
+
+extern WRITE32_HANDLER((*arm7_coproc_do_callback));
+extern READ32_HANDLER((*arm7_coproc_rt_r_callback));
+extern WRITE32_HANDLER((*arm7_coproc_rt_w_callback));
+extern void (*arm7_coproc_dt_r_callback)(UINT32 insn, UINT32* prn, UINT32 (*read32)(int addr));
+extern void (*arm7_coproc_dt_w_callback)(UINT32 insn, UINT32* prn, void (*write32)(int addr, UINT32 data));
+
+#ifdef MAME_DEBUG
+extern UINT32 arm7_disasm( char *pBuf, UINT32 pc, UINT32 opcode );
+extern UINT32 thumb_disasm( char *pBuf, UINT32 pc, UINT16 opcode );
+
+extern char *(*arm7_dasm_cop_dt_callback)( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0 );
+extern char *(*arm7_dasm_cop_rt_callback)( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0 );
+extern char *(*arm7_dasm_cop_do_callback)( char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0 );
+#endif
+
+#endif /* ARM7CORE_H */
+
diff --git a/src/emu/cpu/arm7/arm7dasm.c b/src/emu/cpu/arm7/arm7dasm.c
new file mode 100644
index 00000000000..f3340afa148
--- /dev/null
+++ b/src/emu/cpu/arm7/arm7dasm.c
@@ -0,0 +1,1233 @@
+/*****************************************************************************
+ *
+ * arm7dasm.c
+ * Portable ARM7TDMI Core Emulator - Disassembler
+ *
+ * Copyright (c) 2004 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
+ * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
+ *
+ *****************************************************************************/
+/******************************************************************************
+ * Notes:
+ *
+ * Because Co-Processor functions are highly specialized to the actual co-proc
+ * implementation being used, I've setup callback handlers to allow for custom
+ * dasm display of the co-proc functions so that the implementation specific
+ * commands/interpretation can be used. If not used, the default handlers which
+ * implement the ARM7TDMI guideline format is used
+ ******************************************************************************/
+
+#include "arm7core.h"
+
+static char *WritePadding( char *pBuf, const char *pBuf0 )
+{
+ pBuf0 += 8;
+ while( pBuf<pBuf0 )
+ {
+ *pBuf++ = ' ';
+ }
+ return pBuf;
+}
+
+static char *DasmCoProc_RT( char *pBuf, UINT32 opcode, const char *pConditionCode, const char *pBuf0)
+{
+ /* co processor register transfer */
+ /* xxxx 1110 oooL nnnn dddd cccc ppp1 mmmm */
+ if( opcode&0x00100000 ) //Bit 20 = Load or Store
+ {
+ pBuf += sprintf( pBuf, "MRC" );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "MCR" );
+ }
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf( pBuf, "p%d, %d, R%d, c%d, c%d",
+ (opcode>>8)&0xf, (opcode>>21)&7, (opcode>>12)&0xf, (opcode>>16)&0xf, opcode&0xf );
+ if((opcode>>5)&7) pBuf += sprintf( pBuf, ", %d",(opcode>>5)&7);
+ return pBuf;
+}
+
+static char *DasmCoProc_DT( char *pBuf, UINT32 opcode, const char *pConditionCode, const char *pBuf0 )
+{
+ /* co processor data transfer */
+ /* xxxx 111P UNWL nnnn dddd pppp oooooooo */
+ //todo: test this on valid instructions
+
+ pBuf += sprintf(pBuf, "%s%s",(opcode&0x00100000)?"LDC":"STC",pConditionCode); //Bit 20 = 1 for Load, 0 for Store
+ //Long Operation
+ if(opcode & 0x400000) pBuf += sprintf(pBuf, "L");
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+ //P# & CD #
+ pBuf += sprintf(pBuf, "p%d, c%d, ",(opcode>>8)&0x0f,(opcode>>12)&0x0f);
+
+ //Base Register (Rn)
+ pBuf += sprintf(pBuf, "[R%d%s",(opcode>>16)&0x0f,(opcode&0x1000000)?"":"]"); //If Bit 24 = 1, Pre-increment, otherwise, Post increment so close brace
+
+ //immediate value ( 8 bit value is << 2 according to manual )
+ if(opcode & 0xff) pBuf += sprintf(pBuf, ",%s#$%x",(opcode&0x800000)?"":"-",(opcode & 0xff)<<2);
+
+ //Pre-Inc brace & Write back
+ pBuf += sprintf(pBuf, "%s%s",(opcode&0x1000000)?"]":"",(opcode&0x200000)?"{!}":"");
+ return pBuf;
+}
+
+static char *DasmCoProc_DO( char *pBuf, UINT32 opcode, const char *pConditionCode, const char *pBuf0 )
+{
+ /* co processor data operation */
+ /* xxxx 1110 oooo nnnn dddd cccc ppp0 mmmm */
+ pBuf += sprintf( pBuf, "CDP" );
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+ pBuf = WritePadding( pBuf, pBuf0 );
+ //p#,CPOpc,cd,cn,cm
+ pBuf += sprintf( pBuf, "p%d, %d, c%d, c%d, c%d",
+ (opcode>>8)&0xf, (opcode>>20)&0xf, (opcode>>12)&0xf, (opcode>>16)&0xf, opcode&0xf );
+ if((opcode>>5)&7) pBuf += sprintf( pBuf, ", %d",(opcode>>5)&7);
+ return pBuf;
+}
+
+static char *WriteImmediateOperand( char *pBuf, UINT32 opcode )
+{
+ /* rrrrbbbbbbbb */
+ UINT32 imm;
+ int r;
+
+ imm = opcode&0xff;
+ r = ((opcode>>8)&0xf)*2;
+ imm = (imm>>r)|(imm<<(32-r));
+ pBuf += sprintf( pBuf, ", #$%x", imm );
+ return pBuf;
+}
+
+static char *WriteDataProcessingOperand( char *pBuf, UINT32 opcode, int printOp0, int printOp1, int printOp2 )
+{
+ /* ccccctttmmmm */
+ static const char *pRegOp[4] = { "LSL","LSR","ASR","ROR" };
+
+ if (printOp0)
+ pBuf += sprintf(pBuf,"R%d, ", (opcode>>12)&0xf);
+ if (printOp1)
+ pBuf += sprintf(pBuf,"R%d, ", (opcode>>16)&0xf);
+
+ /* Immediate Op2 */
+ if( opcode&0x02000000 )
+ return WriteImmediateOperand(pBuf-2,opcode);
+
+ /* Register Op2 */
+ if (printOp2)
+//SJE: pBuf += sprintf(pBuf,"R%d, ", (opcode>>0)&0xf);
+ pBuf += sprintf(pBuf,"R%d ", (opcode>>0)&0xf);
+
+ //SJE: ignore if LSL#0 for register shift
+ if( ((opcode&0x2000000) == 0) && (((opcode>>4) & 0xff)==0) )
+ return pBuf;
+
+ pBuf += sprintf(pBuf, ",%s ", pRegOp[(opcode>>5)&3] );
+ //SJE: pBuf += sprintf(pBuf, "%s ", pRegOp[(opcode>>5)&3] );
+
+ if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */
+ {
+ pBuf += sprintf( pBuf, "R%d", (opcode>>8)&0xf );
+ }
+ else /* Shift amount immediate 5 bit unsigned integer */
+ {
+ int c=(opcode>>7)&0x1f;
+ if( c==0 ) c = 32;
+ pBuf += sprintf( pBuf, "#%d", c );
+ }
+ return pBuf;
+}
+
+static char *WriteRegisterOperand1( char *pBuf, UINT32 opcode )
+{
+ /* ccccctttmmmm */
+ static const char *pRegOp[4] = { "LSL","LSR","ASR","ROR" };
+
+ pBuf += sprintf(
+ pBuf,
+ ", R%d", /* Operand 1 register, Operand 2 register, shift type */
+ (opcode>> 0)&0xf);
+
+ //check for LSL 0
+ if( (((opcode>>5)&3)==0) && (((opcode>>7)&0xf)==0) )
+ return pBuf;
+ else
+ //Add rotation type
+ pBuf += sprintf(pBuf," %s ",pRegOp[(opcode>>5)&3]);
+
+ if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */
+ {
+ pBuf += sprintf( pBuf, "R%d", (opcode>>7)&0xf );
+ }
+ else /* Shift amount immediate 5 bit unsigned integer */
+ {
+ int c=(opcode>>7)&0x1f;
+ if( c==0 ) c = 32;
+ pBuf += sprintf( pBuf, "#%d", c );
+ }
+ return pBuf;
+} /* WriteRegisterOperand */
+
+
+static char *WriteBranchAddress( char *pBuf, UINT32 pc, UINT32 opcode )
+{
+ opcode &= 0x00ffffff;
+ if( opcode&0x00800000 )
+ {
+ opcode |= 0xff000000; /* sign-extend */
+ }
+ pc += 8+4*opcode;
+ sprintf( pBuf, "$%x", pc );
+ return pBuf;
+} /* WriteBranchAddress */
+
+UINT32 arm7_disasm( char *pBuf, UINT32 pc, UINT32 opcode )
+{
+ const char *pBuf0;
+
+ static const char *pConditionCodeTable[16] =
+ {
+ "EQ","NE","CS","CC",
+ "MI","PL","VS","VC",
+ "HI","LS","GE","LT",
+ "GT","LE","","NV"
+ };
+ static const char *pOperation[16] =
+ {
+ "AND","EOR","SUB","RSB",
+ "ADD","ADC","SBC","RSC",
+ "TST","TEQ","CMP","CMN",
+ "ORR","MOV","BIC","MVN"
+ };
+ const char *pConditionCode;
+ UINT32 dasmflags = 0;
+
+ pConditionCode= pConditionCodeTable[opcode>>28];
+ pBuf0 = pBuf;
+
+ if( (opcode&0x0ffffff0)==0x012fff10 ) { //bits 27-4 == 000100101111111111110001
+ /* Branch and Exchange (BX) */
+ pBuf += sprintf( pBuf, "B");
+ pBuf += sprintf( pBuf, "%sX", pConditionCode );
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf( pBuf, "R%d",(opcode&0xf));
+ if ((opcode & 0x0f) == 14)
+ dasmflags = DASMFLAG_STEP_OUT;
+ }
+ else if( (opcode&0x0e000000)==0 && (opcode&0x80) && (opcode&0x10) ) //bits 27-25 == 000, bit 7=1, bit 4=1
+ {
+ /* multiply or swap or half word data transfer */
+
+ if(opcode&0x60)
+ { //bits = 6-5 != 00
+ /* half word data transfer */
+ pBuf += sprintf(pBuf, "%s%s",(opcode&0x00100000)?"LDR":"STR",pConditionCode); //Bit 20 = 1 for Load, 0 for Store
+
+ //Signed? (if not, always unsigned half word)
+ if(opcode&0x40)
+ pBuf += sprintf(pBuf, "%s",(opcode&0x20)?"SH":"SB"); //Bit 5 = 1 for Half Word, 0 for Byte
+ else
+ pBuf += sprintf(pBuf, "H");
+
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+ //Dest Register
+ pBuf += sprintf(pBuf, "R%d, ",(opcode>>12)&0x0f);
+ //Base Register
+ pBuf += sprintf(pBuf, "[R%d%s",(opcode>>16)&0x0f,(opcode&0x1000000)?"":"]"); //If Bit 24 = 1, Pre-increment, otherwise, Post increment so close brace
+
+ //Immediate or Register Offset?
+ if(opcode&0x400000) { //Bit 22 - 1 = immediate, 0 = register
+ //immediate ( imm. value in high nibble (bits 8-11) and lo nibble (bit 0-3) )
+ pBuf += sprintf(pBuf, ",%s#$%x",(opcode&0x800000)?"":"-",( (((opcode>>8)&0x0f)<<4) | (opcode&0x0f)));
+ }
+ else {
+ //register
+ pBuf += sprintf(pBuf, ",%sR%d",(opcode&0x800000)?"":"-",(opcode & 0x0f));
+ }
+
+ //Pre-Inc brace & Write back
+ pBuf += sprintf(pBuf, "%s%s",(opcode&0x1000000)?"]":"",(opcode&0x200000)?"{!}":"");
+ }
+ else {
+ if(opcode&0x01000000) { //bit 24 = 1
+ /* swap */
+ //todo: Test on valid instructions
+ /* xxxx 0001 0B00 nnnn dddd 0000 1001 mmmm */
+ pBuf += sprintf( pBuf, "SWP" );
+ pBuf += sprintf( pBuf, "%s%s", pConditionCode, (opcode & 0x400000)?"B":"" ); //Bit 22 = Byte/Word selection
+ //Rd, Rm, [Rn]
+ pBuf += sprintf( pBuf, "R%d, R%d, [R%d]",
+ (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf );
+ }
+ else {
+ /* multiply or multiply long */
+
+ if( opcode&0x800000 ) //Bit 23 = 1 for Multiply Long
+ {
+ /* Multiply Long */
+ /* xxxx0001 UAShhhhllllnnnn1001mmmm */
+
+ /* Signed? */
+ if( opcode&0x00400000 )
+ pBuf += sprintf( pBuf, "S" );
+ else
+ pBuf += sprintf( pBuf, "U" );
+
+ /* Multiply & Accumulate? */
+ if( opcode&0x00200000 )
+ {
+ pBuf += sprintf( pBuf, "MLAL" );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "MULL" );
+ }
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+
+ /* Set Status Flags */
+ if( opcode&0x00100000 )
+ {
+ *pBuf++ = 'S';
+ }
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+ //Format is RLo,RHi,Rm,Rs
+ pBuf += sprintf( pBuf,
+ "R%d, R%d, R%d, R%d",
+ (opcode>>12)&0xf,
+ (opcode>>16)&0xf,
+ (opcode&0xf),
+ (opcode>>8)&0xf);
+ }
+ else
+ {
+ /* Multiply */
+ /* xxxx0000 00ASdddd nnnnssss 1001mmmm */
+
+ /* Multiply & Accumulate? */
+ if( opcode&0x00200000 )
+ {
+ pBuf += sprintf( pBuf, "MLA" );
+ }
+ /* Multiply */
+ else
+ {
+ pBuf += sprintf( pBuf, "MUL" );
+ }
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+ if( opcode&0x00100000 )
+ {
+ *pBuf++ = 'S';
+ }
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+ pBuf += sprintf( pBuf,
+ "R%d, R%d, R%d",
+ (opcode>>16)&0xf,
+ (opcode&0xf),
+ (opcode>>8)&0xf );
+
+ if( opcode&0x00200000 )
+ {
+ pBuf += sprintf( pBuf, ", R%d", (opcode>>12)&0xf );
+ }
+ }
+ }
+ }
+ }
+ else if( (opcode&0x0c000000)==0 ) //bits 27-26 == 00 - This check can only exist properly after Multiplication check above
+ {
+
+ /* Data Processing OR PSR Transfer */
+
+ //SJE: check for MRS & MSR ( S bit must be clear, and bit 24,23 = 10 )
+ if( ((opcode&0x00100000)==0) && ((opcode&0x01800000)==0x01000000) ) {
+ char strpsr[6];
+ sprintf(strpsr, "%s",(opcode&0x400000)?"SPSR":"CPSR");
+
+ //MSR ( bit 21 set )
+ if( (opcode&0x00200000) ) {
+ pBuf += sprintf(pBuf, "MSR%s",pConditionCode );
+ //Flag Bits Only? (Bit 16 Clear)
+ if( (opcode&0x10000)==0) pBuf += sprintf(pBuf, "F");
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf(pBuf, "%s,",strpsr);
+ WriteDataProcessingOperand(pBuf, opcode, (opcode&0x02000000)?1:0, 0, 1);
+ }
+ //MRS ( bit 21 clear )
+ else {
+ pBuf += sprintf(pBuf, "MRS%s",pConditionCode );
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf(pBuf, "R%d,",(opcode>>12)&0x0f);
+ pBuf += sprintf(pBuf, "%s",strpsr);
+ }
+ }
+ else {
+ /* Data Processing */
+ /* xxxx001a aaaSnnnn ddddrrrr bbbbbbbb */
+ /* xxxx000a aaaSnnnn ddddcccc ctttmmmm */
+ int op=(opcode>>21)&0xf;
+ pBuf += sprintf(
+ pBuf, "%s%s",
+ pOperation[op],
+ pConditionCode );
+
+ //SJE: corrected S-Bit bug here
+ //if( (opcode&0x01000000) )
+ if( (opcode&0x0100000) )
+ {
+ *pBuf++ = 'S';
+ }
+
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+ switch (op) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x0c:
+ case 0x0e:
+ WriteDataProcessingOperand(pBuf, opcode, 1, 1, 1);
+ break;
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ WriteDataProcessingOperand(pBuf, opcode, 0, 1, 1);
+ break;
+ case 0x0d:
+ /* look for mov pc,lr */
+ if (((opcode >> 12) & 0x0f) == 15 && ((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0)
+ dasmflags = DASMFLAG_STEP_OUT;
+ case 0x0f:
+ WriteDataProcessingOperand(pBuf, opcode, 1, 0, 1);
+ break;
+ }
+ }
+ }
+ else if( (opcode&0x0c000000)==0x04000000 ) //bits 27-26 == 01
+ {
+ UINT32 rn = 0;
+ UINT32 rnv = 0;
+
+ /* Data Transfer */
+
+ /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate form */
+ /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form */
+ if( opcode&0x00100000 )
+ {
+ pBuf += sprintf( pBuf, "LDR" );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "STR" );
+ }
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+
+ if( opcode&0x00400000 )
+ {
+ pBuf += sprintf( pBuf, "B" );
+ }
+
+ if( opcode&0x00200000 )
+ {
+ /* writeback addr */
+ if( opcode&0x01000000 )
+ {
+ /* pre-indexed addressing */
+ pBuf += sprintf( pBuf, "!" );
+ }
+ else
+ {
+ /* post-indexed addressing */
+ pBuf += sprintf( pBuf, "T" );
+ }
+ }
+
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf( pBuf, "R%d, [R%d",
+ (opcode>>12)&0xf, (opcode>>16)&0xf );
+
+ //grab value of pc if used as base register
+ rn = (opcode>>16)&0xf;
+ if(rn==15) rnv = pc+8;
+
+ if( opcode&0x02000000 )
+ {
+ /* register form */
+ pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"":"]" );
+ pBuf = WriteRegisterOperand1( pBuf, opcode );
+ pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"]":"" );
+ }
+ else
+ {
+ /* immediate form */
+ pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"":"]" );
+ //hide zero offsets
+ if(opcode&0xfff) {
+ if( opcode&0x00800000 )
+ {
+ pBuf += sprintf( pBuf, ", #$%x", opcode&0xfff );
+ rnv += (rnv)?opcode&0xfff:0;
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, ", -#$%x", opcode&0xfff );
+ rnv -= (rnv)?opcode&0xfff:0;
+ }
+ }
+ pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"]":"" );
+ //show where the read will occur if we found a value
+ if(rnv) pBuf += sprintf( pBuf, " (%x)",rnv);
+ }
+ }
+ else if( (opcode&0x0e000000) == 0x08000000 ) //bits 27-25 == 100
+ {
+ /* xxxx100P USWLnnnn llllllll llllllll */
+ /* Block Data Transfer */
+
+ if( opcode&0x00100000 )
+ {
+ pBuf += sprintf( pBuf, "LDM" );
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "STM" );
+ }
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+
+ if( opcode&0x01000000 )
+ {
+ pBuf += sprintf( pBuf, "P" );
+ }
+ if( opcode&0x00800000 )
+ {
+ pBuf += sprintf( pBuf, "U" );
+ }
+ if( opcode&0x00400000 )
+ {
+ pBuf += sprintf( pBuf, "^" );
+ }
+ if( opcode&0x00200000 )
+ {
+ pBuf += sprintf( pBuf, "W" );
+ }
+
+ pBuf = WritePadding( pBuf, pBuf0 );
+ pBuf += sprintf( pBuf, "[R%d], {",(opcode>>16)&0xf);
+
+ {
+ int j=0,last=0,found=0;
+ for (j=0; j<16; j++) {
+ if (opcode&(1<<j) && found==0) {
+ found=1;
+ last=j;
+ }
+ else if ((opcode&(1<<j))==0 && found) {
+ if (last==j-1)
+ pBuf += sprintf( pBuf, " R%d,",last);
+ else
+ pBuf += sprintf( pBuf, " R%d-R%d,",last,j-1);
+ found=0;
+ }
+ }
+ if (found && last==15)
+ pBuf += sprintf( pBuf, " R15,");
+ else if (found)
+ pBuf += sprintf( pBuf, " R%d-R%d,",last,15);
+ }
+
+ pBuf--;
+ pBuf += sprintf( pBuf, " }");
+ }
+ else if( (opcode&0x0e000000)==0x0a000000 ) //bits 27-25 == 101
+ {
+ /* branch instruction */
+ /* xxxx101L oooooooo oooooooo oooooooo */
+ if( opcode&0x01000000 )
+ {
+ pBuf += sprintf( pBuf, "BL" );
+ dasmflags = DASMFLAG_STEP_OVER;
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "B" );
+ }
+
+ pBuf += sprintf( pBuf, "%s", pConditionCode );
+
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+ pBuf = WriteBranchAddress( pBuf, pc, opcode );
+ }
+ else if( (opcode&0x0e000000)==0x0c000000 ) //bits 27-25 == 110
+ {
+ /* co processor data transfer */
+ if(arm7_dasm_cop_dt_callback)
+ arm7_dasm_cop_dt_callback(pBuf,opcode,(char*)pConditionCode,(char*)pBuf0);
+ else
+ DasmCoProc_DT(pBuf,opcode,(char*)pConditionCode,(char*)pBuf0);
+ }
+ else if( (opcode&0x0f000000)==0x0e000000 ) //bits 27-24 == 1110
+ {
+ /* co processor data operation or register transfer */
+
+ //Register Transfer
+ if(opcode&0x10)
+ {
+ if(arm7_dasm_cop_rt_callback)
+ arm7_dasm_cop_rt_callback(pBuf,opcode,(char*)pConditionCode,(char*)pBuf0);
+ else
+ DasmCoProc_RT(pBuf,opcode,pConditionCode,pBuf0);
+ }
+ //Data Op
+ else
+ {
+ if(arm7_dasm_cop_do_callback)
+ arm7_dasm_cop_do_callback(pBuf,opcode,(char*)pConditionCode,(char*)pBuf0);
+ else
+ DasmCoProc_DO(pBuf,opcode,pConditionCode,pBuf0);
+ }
+ }
+ else if( (opcode&0x0f000000) == 0x0f000000 ) //bits 27-24 == 1111
+ {
+ /* Software Interrupt */
+ pBuf += sprintf( pBuf, "SWI%s $%x",
+ pConditionCode,
+ opcode&0x00ffffff );
+ dasmflags = DASMFLAG_STEP_OVER;
+ }
+ else
+ {
+ pBuf += sprintf( pBuf, "Undefined" );
+ }
+ return dasmflags | DASMFLAG_SUPPORTED;
+}
+
+UINT32 thumb_disasm( char *pBuf, UINT32 pc, UINT16 opcode )
+{
+ const char *pBuf0;
+ UINT32 dasmflags = 0;
+
+// UINT32 readword;
+ UINT32 addr;
+ UINT32 rm, rn, rs, rd, op2, imm;//, rrs;
+ INT32 offs;
+
+ pBuf0 = pBuf;
+ pBuf = WritePadding( pBuf, pBuf0 );
+
+
+ switch( ( opcode & THUMB_INSN_TYPE ) >> THUMB_INSN_TYPE_SHIFT )
+ {
+ case 0x0: /* Logical shifting */
+ if( opcode & THUMB_SHIFT_R ) /* Shift right */
+ {
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ offs = ( opcode & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT;
+ pBuf += sprintf( pBuf, "LSR R%d, R%d, %d", rd, rs, offs);
+ }
+ else /* Shift left */
+ {
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ offs = ( opcode & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT;
+ pBuf += sprintf( pBuf, "LSL R%d, R%d, %d", rd, rs, offs);
+ }
+ break;
+ case 0x1: /* Arithmetic */
+ if( opcode & THUMB_INSN_ADDSUB )
+ {
+ switch( ( opcode & THUMB_ADDSUB_TYPE ) >> THUMB_ADDSUB_TYPE_SHIFT )
+ {
+ case 0x0: /* ADD Rd, Rs, Rn */
+ rn = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT;
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "ADD R%d, R%d, R%d", rd, rs, rn );
+ break;
+ case 0x1: /* SUB Rd, Rs, Rn */
+ rn = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT;
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "SUB R%d, R%d, R%d", rd, rs, rn );
+ break;
+ case 0x2: /* ADD Rd, Rs, #imm */
+ imm = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT;
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "ADD R%d, R%d, #%d", rd, rs, imm );
+ break;
+ case 0x3: /* SUB Rd, Rs, #imm */
+ imm = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT;
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "SUB R%d, R%d, #%d", rd, rs, imm );
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ }
+ else
+ {
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ offs = ( opcode & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT;
+ pBuf += sprintf( pBuf, "ASR R%d, R%d, %d", rd, rs, offs);
+ }
+ break;
+ case 0x2: /* CMP / MOV */
+ if( opcode & THUMB_INSN_CMP )
+ {
+ rn = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT;
+ op2 = ( opcode & THUMB_INSN_IMM );
+ pBuf += sprintf( pBuf, "CMP R%d, %02x", rn, op2 );
+ }
+ else
+ {
+ rd = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT;
+ op2 = ( opcode & THUMB_INSN_IMM );
+ pBuf += sprintf( pBuf, "MOV R%d, %02x", rd, op2 );
+ }
+ break;
+ case 0x3: /* ADD/SUB immediate */
+ if( opcode & THUMB_INSN_SUB ) /* SUB Rd, #Offset8 */
+ {
+ rn = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT;
+ op2 = ( opcode & THUMB_INSN_IMM );
+ pBuf += sprintf( pBuf, "SUB R%d, %02x", rn, op2 ); // fixed, rd -> rn
+ }
+ else /* ADD Rd, #Offset8 */
+ {
+ rn = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT;
+ op2 = opcode & THUMB_INSN_IMM;
+ pBuf += sprintf( pBuf, "ADD R%d, %02x", rn, op2 );
+ }
+ break;
+ case 0x4: /* Rd & Rm instructions */
+ switch( ( opcode & THUMB_GROUP4_TYPE ) >> THUMB_GROUP4_TYPE_SHIFT )
+ {
+ case 0x0:
+ switch( ( opcode & THUMB_ALUOP_TYPE ) >> THUMB_ALUOP_TYPE_SHIFT )
+ {
+ case 0x0: /* AND Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "AND R%d, R%d", rd, rs );
+ break;
+ case 0x1: /* EOR Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "EOR R%d, R%d", rd, rs );
+ break;
+ case 0x2: /* LSL Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "LSL R%d, R%d", rd, rs );
+ break;
+ case 0x3: /* LSR Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "LSR R%d, R%d", rd, rs );
+ break;
+ case 0x4: /* ASR Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "ASR R%d, R%d", rd, rs );
+ break;
+ case 0x5: /* ADC Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "ADC R%d, R%d", rd, rs );
+ break;
+ case 0x6: /* SBC Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "SBC R%d, R%d", rd, rs );
+ break;
+ case 0x7: /* ROR Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "ROR R%d, R%d", rd, rs );
+ break;
+ case 0x8: /* TST Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "TST R%d, R%d", rd, rs );
+ break;
+ case 0xa: /* CMP Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "CMP R%d, R%d", rd, rs );
+ break;
+ case 0xb: /* CMN Rd, Rs - check flags, add dasm */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "CMN R%d, R%d", rd, rs );
+ break;
+ case 0xc: /* ORR Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "ORR R%d, R%d", rd, rs );
+ break;
+ case 0xd: /* MUL Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "MUL R%d, R%d", rd, rs );
+ break;
+ case 0xe: /* MUL Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "BIC R%d, R%d", rd, rs );
+ break;
+ case 0xf: /* MVN Rd, Rs */
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "MVN R%d, R%d", rd, rs );
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ break;
+ case 0x1:
+ switch( ( opcode & THUMB_HIREG_OP ) >> THUMB_HIREG_OP_SHIFT )
+ {
+ case 0x0: /* ADD Rd, Rs */
+ rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = opcode & THUMB_HIREG_RD;
+ switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x1: /* ADD Rd, HRs */
+ pBuf += sprintf( pBuf, "ADD R%d, R%d", rd, rs + 8 );
+ break;
+ case 0x2: /* ADD HRd, Rs */
+ pBuf += sprintf( pBuf, "ADD R%d, R%d", rd + 8, rs );
+ break;
+ case 0x3: /* ADD HRd, HRs */
+ pBuf += sprintf( pBuf, "ADD R%d, R%d", rd + 8, rs + 8 );
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ break;
+ case 0x1: /* CMP */
+ switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x0: /* CMP Rd, Rs */
+ rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = opcode & THUMB_HIREG_RD;
+ pBuf += sprintf( pBuf, "CMP R%d, R%d", rd, rs );
+ break;
+ case 0x1: /* CMP Rd, HRs */
+ rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = opcode & THUMB_HIREG_RD;
+ pBuf += sprintf( pBuf, "CMP R%d, R%d", rd, rs + 8 );
+ break;
+ case 0x2: /* CMP Hd, Rs */
+ rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = opcode & THUMB_HIREG_RD;
+ pBuf += sprintf( pBuf, "CMP R%d, R%d", rd + 8, rs );
+ break;
+ case 0x3: /* CMP Hd, Hs */
+ rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = opcode & THUMB_HIREG_RD;
+ pBuf += sprintf( pBuf, "CMP R%d, R%d", rd + 8, rs + 8 );
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ break;
+ case 0x2: /* MOV */
+ switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x1:
+ rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = opcode & THUMB_HIREG_RD;
+ pBuf += sprintf( pBuf, "MOV R%d, R%d", rd, rs + 8 );
+ break;
+ case 0x2:
+ rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = opcode & THUMB_HIREG_RD;
+ pBuf += sprintf( pBuf, "MOV R%d, R%d", rd + 8, rs );
+ break;
+ case 0x3:
+ rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = opcode & THUMB_HIREG_RD;
+ pBuf += sprintf( pBuf, "MOV R%d, R%d", rd + 8, rs + 8 );
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ break;
+ case 0x3:
+ switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x0:
+ rd = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ pBuf += sprintf( pBuf, "BX R%d", rd );
+ break;
+ case 0x1:
+ rd = ( ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8;
+ pBuf += sprintf( pBuf, "BX R%d", rd );
+ if (rd == 14)
+ dasmflags = DASMFLAG_STEP_OUT;
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ break;
+ case 0x2:
+ case 0x3:
+ rd = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT;
+ addr = ( opcode & THUMB_INSN_IMM ) << 2;
+ pBuf += sprintf( pBuf, "LDR R%d, [PC, #%03x]", rd, addr );
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ break;
+ case 0x5: /* LDR* STR* */
+ switch( ( opcode & THUMB_GROUP5_TYPE ) >> THUMB_GROUP5_TYPE_SHIFT )
+ {
+ case 0x0: /* STR Rd, [Rn, Rm] */
+ rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ pBuf += sprintf( pBuf, "STR R%d, [R%d, R%d]", rd, rn, rm );
+ break;
+ case 0x1: /* STRH Rd, [Rn, Rm] */
+ rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ pBuf += sprintf( pBuf, "STRH R%d, [R%d, R%d]", rd, rn, rm );
+ break;
+ case 0x2: /* STRB Rd, [Rn, Rm] */ /* check */
+ rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ pBuf += sprintf( pBuf, "STRB R%d, [R%d, R%d]", rd, rn, rm );
+ break;
+ case 0x3: /* LDRSB Rd, [Rn, Rm] */
+ rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ pBuf += sprintf( pBuf, "LDRSB R%d, [R%d, R%d]", rd, rn, rm );
+ break;
+ case 0x4: /* LDR Rd, [Rn, Rm] */ /* check */
+ rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ pBuf += sprintf( pBuf, "LDR R%d, [R%d, R%d]", rd, rn, rm );
+ break;
+ case 0x5: /* LDRH Rd, [Rn, Rm] */
+ rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ pBuf += sprintf( pBuf, "LDRH R%d, [R%d, R%d]", rd, rn, rm );
+ break;
+
+ case 0x6: /* LDRB Rd, [Rn, Rm] */
+ rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ pBuf += sprintf( pBuf, "LDRB R%d, [R%d, R%d]", rd, rn, rm );
+ break;
+ case 0x7: /* LDSH Rd, [Rn, Rm] */
+ rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ pBuf += sprintf( pBuf, "LDSH R%d, [R%d, R%d]", rd, rn, rm );
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ break;
+ case 0x6: /* Word Store w/ Immediate Offset */
+ if( opcode & THUMB_LSOP_L ) /* Load */
+ {
+ rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = opcode & THUMB_ADDSUB_RD;
+ offs = ( ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2;
+ pBuf += sprintf( pBuf, "LDR R%d [R%d + #%02x]", rd, rn, offs );
+ }
+ else /* Store */
+ {
+ rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = opcode & THUMB_ADDSUB_RD;
+ offs = ( ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2;
+ pBuf += sprintf( pBuf, "STR R%d, [R%d + #%02x] ", rd, rn, offs );
+ }
+ break;
+ case 0x7: /* Byte Store w/ Immeidate Offset */
+ if( opcode & THUMB_LSOP_L ) /* Load */
+ {
+ rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = opcode & THUMB_ADDSUB_RD;
+ offs = ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT;
+ pBuf += sprintf( pBuf, "LDRB R%d, [R%d + #%02x]", rd, rn, offs );
+ }
+ else /* Store */
+ {
+ rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = opcode & THUMB_ADDSUB_RD;
+ offs = ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT;
+ pBuf += sprintf( pBuf, "STRB R%d, [R%d + #%02x] ", rd, rn, offs );
+ }
+ break;
+ case 0x8: /* Load/Store Halfword */
+ if( opcode & THUMB_HALFOP_L ) /* Load */
+ {
+ imm = ( opcode & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT;
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "LDRH R%d, [R%d, #%03x]", rd, rs, imm << 1 );
+ }
+ else /* Store */
+ {
+ imm = ( opcode & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT;
+ rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ pBuf += sprintf( pBuf, "STRH R%d, [R%d, #%03x]", rd, rs, imm << 1 );
+ }
+ break;
+ case 0x9: /* Stack-Relative Load/Store */
+ if( opcode & THUMB_STACKOP_L )
+ {
+ rd = ( opcode & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT;
+ offs = (UINT8)( opcode & THUMB_INSN_IMM );
+ pBuf += sprintf( pBuf, "LDR R%d, [SP, #%03x]", rd, offs << 2 );
+ }
+ else
+ {
+ rd = ( opcode & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT;
+ offs = (UINT8)( opcode & THUMB_INSN_IMM );
+ pBuf += sprintf( pBuf, "STR R%d, [SP, #%03x]", rd, offs << 2 );
+ }
+ break;
+ case 0xa: /* Get relative address */
+ if( opcode & THUMB_RELADDR_SP ) /* ADD Rd, SP, #nn */
+ {
+ rd = ( opcode & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT;
+ offs = (UINT8)( opcode & THUMB_INSN_IMM ) << 2;
+ pBuf += sprintf( pBuf, "ADD R%d, SP, #%03x", rd, offs );
+ }
+ else /* ADD Rd, PC, #nn */
+ {
+ rd = ( opcode & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT;
+ offs = (UINT8)( opcode & THUMB_INSN_IMM ) << 2;
+ pBuf += sprintf( pBuf, "ADD R%d, PC, #%03x", rd, offs );
+ }
+ break;
+ case 0xb: /* Stack-Related Opcodes */
+ switch( ( opcode & THUMB_STACKOP_TYPE ) >> THUMB_STACKOP_TYPE_SHIFT )
+ {
+ case 0x0: /* ADD SP, #imm */
+ addr = ( opcode & THUMB_INSN_IMM );
+ addr &= ~THUMB_INSN_IMM_S;
+ pBuf += sprintf( pBuf, "ADD SP, #");
+ if( opcode & THUMB_INSN_IMM_S )
+ {
+ pBuf += sprintf( pBuf, "-");
+ }
+ pBuf += sprintf( pBuf, "%03x", addr << 2);
+ break;
+ case 0x5: /* PUSH {Rlist}{LR} */
+ pBuf += sprintf( pBuf, "PUSH {LR, ");
+ for( offs = 7; offs >= 0; offs-- )
+ {
+ if( opcode & ( 1 << offs ) )
+ {
+ pBuf += sprintf( pBuf, "R%d, ", offs);
+ }
+ }
+ pBuf += sprintf( pBuf, "}");
+ break;
+ case 0x4: /* PUSH {Rlist} */
+ pBuf += sprintf( pBuf, "PUSH {");
+ for( offs = 7; offs >= 0; offs-- )
+ {
+ if( opcode & ( 1 << offs ) )
+ {
+ pBuf += sprintf( pBuf, "R%d, ", offs);
+ }
+ }
+ pBuf += sprintf( pBuf, "}");
+ break;
+ case 0xc: /* POP {Rlist} */
+ pBuf += sprintf( pBuf, "POP {");
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( opcode & ( 1 << offs ) )
+ {
+ pBuf += sprintf( pBuf, "R%d, ", offs);
+ }
+ }
+ pBuf += sprintf( pBuf, "}");
+ break;
+ case 0xd: /* POP {Rlist}{PC} */
+ pBuf += sprintf( pBuf, "POP {");
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( opcode & ( 1 << offs ) )
+ {
+ pBuf += sprintf( pBuf, "R%d, ", offs);
+ }
+ }
+ pBuf += sprintf( pBuf, "PC}");
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+ break;
+ case 0xc: /* Multiple Load/Store */
+ if( opcode & THUMB_MULTLS ) /* Load */
+ {
+ rd = ( opcode & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT;
+ pBuf += sprintf( pBuf, "LDMIA R%d!,{", rd);
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( opcode & ( 1 << offs ) )
+ {
+ pBuf += sprintf( pBuf, "R%d, ", offs);
+ }
+ }
+ pBuf += sprintf( pBuf, "}");
+ }
+ else /* Store */
+ {
+ rd = ( opcode & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT;
+ pBuf += sprintf( pBuf, "STMIA R%d!,{", rd);
+ for( offs = 7; offs >= 0; offs-- )
+ {
+ if( opcode & ( 1 << offs ) )
+ {
+ pBuf += sprintf( pBuf, "R%d, ", offs);
+ }
+ }
+ pBuf += sprintf( pBuf, "}");
+ }
+ break;
+ case 0xd: /* Conditional Branch */
+ offs = (INT8)( opcode & THUMB_INSN_IMM );
+ switch( ( opcode & THUMB_COND_TYPE ) >> THUMB_COND_TYPE_SHIFT )
+ {
+ case COND_EQ:
+ pBuf += sprintf( pBuf, "BEQ %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_NE:
+ pBuf += sprintf( pBuf, "BNE %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_CS:
+ pBuf += sprintf( pBuf, "BCS %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_CC:
+ pBuf += sprintf( pBuf, "BCC %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_MI:
+ pBuf += sprintf( pBuf, "BMI %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_PL:
+ pBuf += sprintf( pBuf, "BPL %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_VS:
+ pBuf += sprintf( pBuf, "BVS %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_VC:
+ pBuf += sprintf( pBuf, "BVC %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_HI:
+ pBuf += sprintf( pBuf, "BHI %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_LS:
+ pBuf += sprintf( pBuf, "BLS %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_GE:
+ pBuf += sprintf( pBuf, "BGE %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_LT:
+ pBuf += sprintf( pBuf, "BLT %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_GT:
+ pBuf += sprintf( pBuf, "BGT %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_LE:
+ pBuf += sprintf( pBuf, "BLE %08x (%02x)", pc + 4 + (offs << 1), offs << 1);
+ break;
+ case COND_AL:
+ pBuf += sprintf( pBuf, "INVALID");
+ break;
+ case COND_NV:
+ pBuf += sprintf( pBuf, "SWI %02x\n", opcode & 0xff);
+ break;
+ }
+ break;
+ case 0xe: /* B #offs */
+ offs = ( opcode & THUMB_BRANCH_OFFS ) << 1;
+ if( offs & 0x00000800 )
+ {
+ offs |= 0xfffff800;
+ }
+ pBuf += sprintf( pBuf, "B #%08x (%08x)", offs, pc + 4 + offs);
+ break;
+ case 0xf: /* BL */
+ if( opcode & THUMB_BLOP_LO )
+ {
+ pBuf += sprintf( pBuf, "BL (LO) %04x", ( opcode & THUMB_BLOP_OFFS ) << 1 );
+ dasmflags = DASMFLAG_STEP_OVER;
+ }
+ else
+ {
+ addr = ( opcode & THUMB_BLOP_OFFS ) << 12;
+ if( addr & ( 1 << 22 ) )
+ {
+ addr |= 0xff800000;
+ }
+ pBuf += sprintf( pBuf, "BL (HI) %04x", ( opcode & THUMB_BLOP_OFFS ) << 12 );
+ dasmflags = DASMFLAG_STEP_OVER;
+ }
+ break;
+ default:
+ sprintf( pBuf, "INVALID %04x", opcode);
+ break;
+ }
+
+ return dasmflags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/arm7/arm7exec.c b/src/emu/cpu/arm7/arm7exec.c
new file mode 100644
index 00000000000..9b9facf182c
--- /dev/null
+++ b/src/emu/cpu/arm7/arm7exec.c
@@ -0,0 +1,1334 @@
+/*****************************************************************************
+ *
+ * arm7exec.c
+ * Portable ARM7TDMI Core Emulator
+ *
+ * Copyright (c) 2004 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
+ * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ * Notes:
+ * This file contains the code to run during the CPU EXECUTE METHOD.
+ * It has been split into it's own file (from the arm7core.c) so it can be
+ * directly compiled into any cpu core that wishes to use it.
+ *
+ * It should be included as follows in your cpu core:
+ *
+ * int arm7_execute( int cycles )
+ * {
+ * #include "arm7exec.c"
+ * }
+ *
+*****************************************************************************/
+
+/* This implementation uses an improved switch() for hopefully faster opcode fetches compared to my last version
+.. though there's still room for improvement. */
+{
+ UINT32 pc;
+ UINT32 insn;
+
+ ARM7_ICOUNT = cycles;
+ do
+ {
+ CALL_MAME_DEBUG;
+
+ /* handle Thumb instructions if active */
+ if( T_IS_SET(GET_CPSR) )
+ {
+ UINT32 readword;
+ UINT32 addr;
+ UINT32 rm, rn, rs, rd, op2, imm, rrs, rrd;
+ INT32 offs;
+ pc = R15;
+
+ insn = cpu_readop16(pc & (~1));
+ ARM7_ICOUNT -= (3 - thumbCycles[insn >> 8]);
+ switch( ( insn & THUMB_INSN_TYPE ) >> THUMB_INSN_TYPE_SHIFT )
+ {
+ case 0x0: /* Logical shifting */
+ SET_CPSR(GET_CPSR &~ (N_MASK | Z_MASK));
+ if( insn & THUMB_SHIFT_R ) /* Shift right */
+ {
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rrs = GET_REGISTER(rs);
+ offs = ( insn & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT;
+ if( offs != 0 )
+ {
+ SET_REGISTER( rd, rrs >> offs );
+ if( rrs & ( 1 << (offs-1) ) )
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ }
+ else
+ {
+ SET_REGISTER( rd, 0 );
+ if( rrs & 0x80000000 )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ SET_CPSR(GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+ else /* Shift left */
+ {
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rrs = GET_REGISTER(rs);
+ offs = ( insn & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT;
+ if( offs != 0 )
+ {
+ SET_REGISTER( rd, rrs << offs );
+ if( rrs & ( 1 << ( 31 - ( offs - 1 ) ) ) )
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ }
+ else
+ {
+ SET_REGISTER( rd, rrs );
+ }
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+ break;
+ case 0x1: /* Arithmetic */
+ if( insn & THUMB_INSN_ADDSUB )
+ {
+ switch( ( insn & THUMB_ADDSUB_TYPE ) >> THUMB_ADDSUB_TYPE_SHIFT )
+ {
+ case 0x0: /* ADD Rd, Rs, Rn */
+ rn = GET_REGISTER( ( insn & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT );
+ rs = GET_REGISTER( ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT );
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_REGISTER( rd, rs + rn );
+ HandleThumbALUAddFlags( GET_REGISTER(rd), rs, rn );
+ break;
+ case 0x1: /* SUB Rd, Rs, Rn */
+ rn = GET_REGISTER( ( insn & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT );
+ rs = GET_REGISTER( ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT );
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_REGISTER( rd, rs - rn );
+ HandleThumbALUSubFlags( GET_REGISTER(rd), rs, rn );
+ break;
+ case 0x2: /* ADD Rd, Rs, #imm */
+ imm = ( insn & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT;
+ rs = GET_REGISTER( ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT );
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_REGISTER( rd, rs + imm );
+ HandleThumbALUAddFlags( GET_REGISTER(rd), rs, imm );
+ break;
+ case 0x3: /* SUB Rd, Rs, #imm */
+ imm = ( insn & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT;
+ rs = GET_REGISTER( ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT );
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_REGISTER( rd, rs - imm );
+ HandleThumbALUSubFlags( GET_REGISTER(rd), rs,imm );
+ break;
+ default:
+ fatalerror("%08x: G1 Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ }
+ else
+ {
+ /* ASR.. */
+ //if( insn & THUMB_SHIFT_R ) /* Shift right */
+ {
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rrs = GET_REGISTER(rs);
+ offs = ( insn & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT;
+ if( offs == 0 )
+ {
+ offs = 32;
+ }
+
+ if( offs >= 32 )
+ {
+ if( rrs >> 31 )
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ SET_REGISTER( rd, ( rrs & 0x80000000 ) ? 0xFFFFFFFF : 0x00000000 );
+ }
+ else
+ {
+ if( ( rrs >> ( offs - 1 ) ) & 1 )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ SET_REGISTER( rd, ( rrs & 0x80000000 ) ? ( ( 0xFFFFFFFF << ( 32 - offs ) ) | ( rrs >> offs ) ) : ( rrs >> offs ) );
+ }
+ SET_CPSR(GET_CPSR &~ (N_MASK | Z_MASK));
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+
+ }
+ break;
+ case 0x2: /* CMP / MOV */
+ if( insn & THUMB_INSN_CMP )
+ {
+ rn = GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT );
+ op2 = ( insn & THUMB_INSN_IMM );
+ rd = rn - op2;
+ HandleThumbALUSubFlags( rd, rn, op2 );
+ //mame_printf_debug("%08x: xxx Thumb instruction: CMP R%d (%08x), %02x (N=%d, Z=%d, C=%d, V=%d)\n", pc, ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT ), op2, N_IS_SET(GET_CPSR) ? 1 : 0, Z_IS_SET(GET_CPSR) ? 1 : 0, C_IS_SET(GET_CPSR) ? 1 : 0, V_IS_SET(GET_CPSR) ? 1 : 0);
+ }
+ else
+ {
+ rd = ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT;
+ op2 = ( insn & THUMB_INSN_IMM );
+ SET_REGISTER( rd, op2 );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+ break;
+ case 0x3: /* ADD/SUB immediate */
+ if( insn & THUMB_INSN_SUB ) /* SUB Rd, #Offset8 */
+ {
+ rn = GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT );
+ op2 = ( insn & THUMB_INSN_IMM );
+ //mame_printf_debug("%08x: Thumb instruction: SUB R%d, %02x\n", pc, ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, op2);
+ rd = rn - op2;
+ SET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, rd );
+ HandleThumbALUSubFlags( rd, rn, op2 );
+ }
+ else /* ADD Rd, #Offset8 */
+ {
+ rn = GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT );
+ op2 = insn & THUMB_INSN_IMM;
+ rd = rn + op2;
+ //mame_printf_debug("%08x: Thumb instruction: ADD R%d, %02x\n", pc, ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, op2);
+ SET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, rd );
+ HandleThumbALUAddFlags( rd, rn, op2 );
+ }
+ break;
+ case 0x4: /* Rd & Rm instructions */
+ switch( ( insn & THUMB_GROUP4_TYPE ) >> THUMB_GROUP4_TYPE_SHIFT )
+ {
+ case 0x0:
+ switch( ( insn & THUMB_ALUOP_TYPE ) >> THUMB_ALUOP_TYPE_SHIFT )
+ {
+ case 0x0: /* AND Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_REGISTER( rd, GET_REGISTER(rd) & GET_REGISTER(rs) );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x1: /* EOR Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_REGISTER( rd, GET_REGISTER(rd) ^ GET_REGISTER(rs) );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x2: /* LSL Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rrd = GET_REGISTER(rd);
+ offs = GET_REGISTER(rs) & 0x000000ff;
+ if (offs > 0)
+ {
+ if ( offs < 32 )
+ {
+ SET_REGISTER( rd, rrd << offs );
+ if( rrd & ( 1 << ( 31 - ( offs - 1 ) ) ) )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ else if( offs == 32 )
+ {
+ SET_REGISTER( rd, 0 );
+ if( rrd & 1 )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ else
+ {
+ SET_REGISTER( rd, 0 );
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x3: /* LSR Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rrd = GET_REGISTER(rd);
+ offs = GET_REGISTER(rs) & 0x000000ff;
+ if (offs > 0)
+ {
+ if( offs < 32 )
+ {
+ SET_REGISTER( rd, rrd >> offs );
+ if( rrd & ( 1 << ( offs - 1 ) ) )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ else if( offs == 32 )
+ {
+ SET_REGISTER( rd, 0 );
+ if( rrd & 0x80000000 )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ else
+ {
+ SET_REGISTER( rd, 0 );
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x4: /* ASR Rd, Rs */
+ {
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rrs = GET_REGISTER(rs)&0xff;
+ rrd = GET_REGISTER(rd);
+ if (rrs != 0)
+ {
+ if (rrs >= 32)
+ {
+ if (rrd>>31)
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ SET_REGISTER( rd, (GET_REGISTER(rd) & 0x80000000) ? 0xFFFFFFFF : 0x00000000 );
+ }
+ else
+ {
+ if ((rrd>>(rs-1))&1)
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ SET_REGISTER( rd, (rrd & 0x80000000) ? ((0xFFFFFFFF<<(32-rrs)) | (rrd>>rrs)) : (rrd>>rrs));
+ }
+ }
+ SET_CPSR(GET_CPSR &~ (N_MASK | Z_MASK));
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+ break;
+ case 0x5: /* ADC Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ op2=(GET_CPSR & C_MASK) ? 1 : 0;
+ rn=GET_REGISTER(rd) + GET_REGISTER(rs) + op2;
+ HandleThumbALUAddFlags( rn, GET_REGISTER(rd), ( GET_REGISTER(rs) ) ); //?
+ SET_REGISTER( rd, rn);
+ break;
+ case 0x6: /* SBC Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ op2=(GET_CPSR & C_MASK) ? 0 : 1;
+ rn=GET_REGISTER(rd) - GET_REGISTER(rs) - op2;
+ HandleThumbALUSubFlags( rn, GET_REGISTER(rd), ( GET_REGISTER(rs) ) ); //?
+ SET_REGISTER( rd, rn);
+ break;
+ case 0x7: /* ROR Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rrd = GET_REGISTER(rd);
+ imm = GET_REGISTER(rs) & 0x0000001f;
+ SET_REGISTER( rd, ( rrd >> imm ) | ( rrd << ( 32 - imm ) ) );
+ if( rrd & ( 1 << ( imm - 1 ) ) )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x8: /* TST Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) & GET_REGISTER(rs) ) );
+ R15 += 2;
+ break;
+ case 0x9: /* NEG Rd, Rs - todo: check me */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rrs = GET_REGISTER(rs);
+ rn = 0 - rrs;
+ SET_REGISTER( rd, rn );
+ HandleThumbALUSubFlags( GET_REGISTER(rd), 0, rrs );
+ break;
+ case 0xa: /* CMP Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rn = GET_REGISTER(rd) - GET_REGISTER(rs);
+ HandleThumbALUSubFlags( rn, GET_REGISTER(rd), GET_REGISTER(rs) );
+ break;
+ case 0xb: /* CMN Rd, Rs - check flags, add dasm */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rn = GET_REGISTER(rd) + GET_REGISTER(rs);
+ HandleThumbALUAddFlags( rn, GET_REGISTER(rd), GET_REGISTER(rs) );
+ break;
+ case 0xc: /* ORR Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_REGISTER( rd, GET_REGISTER(rd) | GET_REGISTER(rs) );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0xd: /* MUL Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ rn = GET_REGISTER(rd) * GET_REGISTER(rs);
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_REGISTER( rd, rn );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( rn ) );
+ R15 += 2;
+ break;
+ case 0xe: /* BIC Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_REGISTER( rd, GET_REGISTER(rd) & (~GET_REGISTER(rs)) );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0xf: /* MVN Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ op2 = GET_REGISTER(rs);
+ SET_REGISTER( rd, ~op2 );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ default:
+ fatalerror("%08x: G4-0 Undefined Thumb instruction: %04x %x\n", pc, insn, ( insn & THUMB_ALUOP_TYPE ) >> THUMB_ALUOP_TYPE_SHIFT);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0x1:
+ switch( ( insn & THUMB_HIREG_OP ) >> THUMB_HIREG_OP_SHIFT )
+ {
+ case 0x0: /* ADD Rd, Rs */
+ rs = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = insn & THUMB_HIREG_RD;
+ switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x1: /* ADD Rd, HRs */
+ SET_REGISTER( rd, GET_REGISTER(rd) + GET_REGISTER(rs+8) );
+ // emulate the effects of pre-fetch
+ if (rs == 7)
+ {
+ SET_REGISTER(rd, GET_REGISTER(rd) + 4);
+ }
+ break;
+ case 0x2: /* ADD HRd, Rs */
+ SET_REGISTER( rd+8, GET_REGISTER(rd+8) + GET_REGISTER(rs) );
+ if (rd == 7)
+ {
+ R15 += 2;
+ change_pc(R15);
+ }
+ break;
+ case 0x3: /* Add HRd, HRs */
+ SET_REGISTER( rd+8, GET_REGISTER(rd+8) + GET_REGISTER(rs+8) );
+ // emulate the effects of pre-fetch
+ if (rs == 7)
+ {
+ SET_REGISTER(rd+8, GET_REGISTER(rd+8) + 4);
+ }
+ if (rd == 7)
+ {
+ R15 += 2;
+ change_pc(R15);
+ }
+ break;
+ default:
+ fatalerror("%08x: G4-1-0 Undefined Thumb instruction: %04x %x\n", pc, insn, ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT );
+ break;
+ }
+ R15 += 2;
+ break;
+ case 0x1: /* CMP */
+ switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x0: /* CMP Rd, Rs */
+ rs = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) );
+ rd = GET_REGISTER( insn & THUMB_HIREG_RD );
+ rn = rd - rs;
+ HandleThumbALUSubFlags( rn, rd, rs );
+ break;
+ case 0x1: /* CMP Rd, Hs */
+ rs = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8 );
+ rd = GET_REGISTER( insn & THUMB_HIREG_RD );
+ rn = rd - rs;
+ HandleThumbALUSubFlags( rn, rd, rs );
+ break;
+ case 0x2: /* CMP Hd, Rs */
+ rs = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) );
+ rd = GET_REGISTER( (insn & THUMB_HIREG_RD) + 8 );
+ rn = rd - rs;
+ HandleThumbALUSubFlags( rn, rd, rs );
+ break;
+ case 0x3: /* CMP Hd, Hs */
+ rs = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8 );
+ rd = GET_REGISTER( (insn & THUMB_HIREG_RD) + 8 );
+ rn = rd - rs;
+ HandleThumbALUSubFlags( rn, rd, rs );
+ break;
+ default:
+ fatalerror("%08x: G4-1 Undefined Thumb instruction: %04x %x\n", pc, insn, ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0x2: /* MOV */
+ switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x1: // MOV Rd, Hs
+ rs = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = insn & THUMB_HIREG_RD;
+ if( rs == 7 )
+ {
+ SET_REGISTER( rd, GET_REGISTER(rs + 8) + 4 );
+ }
+ else
+ {
+ SET_REGISTER( rd, GET_REGISTER(rs + 8) );
+ }
+ R15 += 2;
+ break;
+ case 0x2: // MOV Hd, Rs
+ rs = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = insn & THUMB_HIREG_RD;
+ SET_REGISTER( rd + 8, GET_REGISTER(rs) );
+ if( rd != 7 )
+ {
+ R15 += 2;
+ }
+ else
+ {
+ R15 &= ~1;
+ change_pc(R15);
+ }
+ break;
+ case 0x3: // MOV Hd, Hs
+ rs = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ rd = insn & THUMB_HIREG_RD;
+ if (rs == 7)
+ {
+ SET_REGISTER( rd + 8, GET_REGISTER(rs+8)+4 );
+ }
+ else
+ {
+ SET_REGISTER( rd + 8, GET_REGISTER(rs+8) );
+ }
+ if( rd != 7 )
+ {
+ R15 += 2;
+ }
+
+ if( rd == 7 )
+ {
+ R15 &= ~1;
+ change_pc(R15);
+ }
+ break;
+ default:
+ fatalerror("%08x: G4-2 Undefined Thumb instruction: %04x (%x)\n", pc, insn, ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0x3:
+ switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x0:
+ rd = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
+ addr = GET_REGISTER(rd);
+ if( addr & 1 )
+ {
+ addr &= ~1;
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ T_MASK);
+ if( addr & 2 )
+ {
+ addr += 2;
+ }
+ }
+ R15 = addr;
+ break;
+ case 0x1:
+ addr = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8 );
+ if( ( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8 ) == 15 )
+ {
+ addr += 2;
+ }
+ if( addr & 1 )
+ {
+ addr &= ~1;
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ T_MASK);
+ if( addr & 2 )
+ {
+ addr += 2;
+ }
+ }
+ R15 = addr;
+ break;
+ default:
+ fatalerror("%08x: G4-3 Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ default:
+ fatalerror("%08x: G4-x Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0x2:
+ case 0x3:
+ readword = READ32( ( R15 & ~2 ) + 4 + ( ( insn & THUMB_INSN_IMM ) << 2 ) );
+ SET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, readword );
+ R15 += 2;
+ break;
+ default:
+ fatalerror("%08x: G4-y Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0x5: /* LDR* STR* */
+ switch( ( insn & THUMB_GROUP5_TYPE ) >> THUMB_GROUP5_TYPE_SHIFT )
+ {
+ case 0x0: /* STR Rd, [Rn, Rm] */
+ rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ addr = GET_REGISTER(rn) + GET_REGISTER(rm);
+ WRITE32( addr, GET_REGISTER(rd) );
+ R15 += 2;
+ break;
+ case 0x1: /* STRH Rd, [Rn, Rm] */
+ rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ addr = GET_REGISTER(rn) + GET_REGISTER(rm);
+ WRITE16( addr, GET_REGISTER(rd) );
+ R15 += 2;
+ break;
+ case 0x2: /* STRB Rd, [Rn, Rm] */
+ rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ addr = GET_REGISTER(rn) + GET_REGISTER(rm);
+ WRITE8( addr, GET_REGISTER(rd) );
+ R15 += 2;
+ break;
+ case 0x3: /* LDSB Rd, [Rn, Rm] todo, add dasm */
+ rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ addr = GET_REGISTER(rn) + GET_REGISTER(rm);
+ op2 = READ8( addr );
+ if( op2 & 0x00000080 )
+ {
+ op2 |= 0xffffff00;
+ }
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+ case 0x4: /* LDR Rd, [Rn, Rm] */
+ rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ addr = GET_REGISTER(rn) + GET_REGISTER(rm);
+ op2 = READ32( addr );
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+ case 0x5: /* LDRH Rd, [Rn, Rm] */
+ rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ addr = GET_REGISTER(rn) + GET_REGISTER(rm);
+ op2 = READ16( addr );
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+
+ case 0x6: /* LDRB Rd, [Rn, Rm] */
+ rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ addr = GET_REGISTER(rn) + GET_REGISTER(rm);
+ op2 = READ8( addr );
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+ case 0x7: /* LDSH Rd, [Rn, Rm] */
+ rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
+ rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
+ rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
+ addr = GET_REGISTER(rn) + GET_REGISTER(rm);
+ op2 = READ16( addr );
+ if( op2 & 0x00008000 )
+ {
+ op2 |= 0xffff0000;
+ }
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+ default:
+ fatalerror("%08x: G5 Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0x6: /* Word Store w/ Immediate Offset */
+ if( insn & THUMB_LSOP_L ) /* Load */
+ {
+ rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = insn & THUMB_ADDSUB_RD;
+ offs = ( ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2;
+ SET_REGISTER( rd, READ32(GET_REGISTER(rn) + offs) ); // fix
+ R15 += 2;
+ }
+ else /* Store */
+ {
+ rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = insn & THUMB_ADDSUB_RD;
+ offs = ( ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2;
+ WRITE32( GET_REGISTER(rn) + offs, GET_REGISTER(rd) );
+ R15 += 2;
+ }
+ break;
+ case 0x7: /* Byte Store w/ Immeidate Offset */
+ if( insn & THUMB_LSOP_L ) /* Load */
+ {
+ rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = insn & THUMB_ADDSUB_RD;
+ offs = ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT;
+ SET_REGISTER( rd, READ8( GET_REGISTER(rn) + offs ) );
+ R15 += 2;
+ }
+ else /* Store */
+ {
+ rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = insn & THUMB_ADDSUB_RD;
+ offs = ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT;
+ WRITE8( GET_REGISTER(rn) + offs, GET_REGISTER(rd) );
+ R15 += 2;
+ }
+ break;
+ case 0x8: /* Load/Store Halfword */
+ if( insn & THUMB_HALFOP_L ) /* Load */
+ {
+ imm = ( insn & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT;
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_REGISTER( rd, READ16( GET_REGISTER(rs) + ( imm << 1 ) ) );
+ R15 += 2;
+ }
+ else /* Store */
+ {
+ imm = ( insn & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT;
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ WRITE16( GET_REGISTER(rs) + ( imm << 1 ), GET_REGISTER(rd) );
+ R15 += 2;
+ }
+ break;
+ case 0x9: /* Stack-Relative Load/Store */
+ if( insn & THUMB_STACKOP_L )
+ {
+ rd = ( insn & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT;
+ offs = (UINT8)( insn & THUMB_INSN_IMM );
+ readword = READ32( GET_REGISTER(13) + ( (UINT32)offs << 2 ) );
+ SET_REGISTER( rd, readword );
+ R15 += 2;
+ }
+ else
+ {
+ rd = ( insn & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT;
+ offs = (UINT8)( insn & THUMB_INSN_IMM );
+ WRITE32( GET_REGISTER(13) + ( (UINT32)offs << 2 ), GET_REGISTER(rd) );
+ R15 += 2;
+ }
+ break;
+ case 0xa: /* Get relative address */
+ if( insn & THUMB_RELADDR_SP ) /* ADD Rd, SP, #nn */
+ {
+ rd = ( insn & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT;
+ offs = (UINT8)( insn & THUMB_INSN_IMM ) << 2;
+ SET_REGISTER( rd, GET_REGISTER(13) + offs );
+ R15 += 2;
+ }
+ else /* ADD Rd, PC, #nn */
+ {
+ rd = ( insn & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT;
+ offs = (UINT8)( insn & THUMB_INSN_IMM ) << 2;
+ SET_REGISTER( rd, ( ( R15 + 4 ) & ~2 ) + offs );
+ R15 += 2;
+ }
+ break;
+ case 0xb: /* Stack-Related Opcodes */
+ switch( ( insn & THUMB_STACKOP_TYPE ) >> THUMB_STACKOP_TYPE_SHIFT )
+ {
+ case 0x0: /* ADD SP, #imm */
+ addr = ( insn & THUMB_INSN_IMM );
+ addr &= ~THUMB_INSN_IMM_S;
+ SET_REGISTER( 13, GET_REGISTER(13) + ( ( insn & THUMB_INSN_IMM_S ) ? -( addr << 2 ) : ( addr << 2 ) ) );
+ R15 += 2;
+ break;
+ case 0x4: /* PUSH {Rlist} */
+ for( offs = 7; offs >= 0; offs-- )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( 13, GET_REGISTER(13) - 4 );
+ WRITE32( GET_REGISTER(13), GET_REGISTER(offs) );
+ }
+ }
+ R15 += 2;
+ break;
+ case 0x5: /* PUSH {Rlist}{LR} */
+ SET_REGISTER( 13, GET_REGISTER(13) - 4 );
+ WRITE32( GET_REGISTER(13), GET_REGISTER(14) );
+ for( offs = 7; offs >= 0; offs-- )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( 13, GET_REGISTER(13) - 4 );
+ WRITE32( GET_REGISTER(13), GET_REGISTER(offs) );
+ }
+ }
+ R15 += 2;
+ break;
+ case 0xc: /* POP {Rlist} */
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( offs, READ32( GET_REGISTER(13) ) );
+ SET_REGISTER( 13, GET_REGISTER(13) + 4 );
+ }
+ }
+ R15 += 2;
+ break;
+ case 0xd: /* POP {Rlist}{PC} */
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( offs, READ32( GET_REGISTER(13) ) );
+ SET_REGISTER( 13, GET_REGISTER(13) + 4 );
+ }
+ }
+ R15 = READ32( GET_REGISTER(13) ) & ~1;
+ SET_REGISTER( 13, GET_REGISTER(13) + 4 );
+ break;
+ default:
+ fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0xc: /* Multiple Load/Store */
+ if( insn & THUMB_MULTLS ) /* Load */
+ {
+ rd = ( insn & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT;
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( offs, READ32( (GET_REGISTER(rd)&0xfffffffc) ) );
+ SET_REGISTER( rd, GET_REGISTER(rd) + 4 );
+ }
+ }
+ R15 += 2;
+ }
+ else /* Store */
+ {
+ rd = ( insn & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT;
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ WRITE32( (GET_REGISTER(rd)&0xfffffffc), GET_REGISTER(offs) );
+ SET_REGISTER( rd, GET_REGISTER(rd) + 4 );
+ }
+ }
+ R15 += 2;
+ }
+ break;
+ case 0xd: /* Conditional Branch */
+ offs = (INT8)( insn & THUMB_INSN_IMM );
+ switch( ( insn & THUMB_COND_TYPE ) >> THUMB_COND_TYPE_SHIFT )
+ {
+ case COND_EQ:
+ if( Z_IS_SET(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_NE:
+ if( Z_IS_CLEAR(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_CS:
+ if( C_IS_SET(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_CC:
+ if( C_IS_CLEAR(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_MI:
+ if( N_IS_SET(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_PL:
+ if( N_IS_CLEAR(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_VS:
+ if( V_IS_SET(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_VC:
+ if( V_IS_CLEAR(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_HI:
+ if( C_IS_SET(GET_CPSR) && Z_IS_CLEAR(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_LS:
+ if( C_IS_CLEAR(GET_CPSR) || Z_IS_SET(GET_CPSR) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_GE:
+ if( !(GET_CPSR & N_MASK) == !(GET_CPSR & V_MASK) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_LT:
+ if( !(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_GT:
+ if( Z_IS_CLEAR(GET_CPSR) && ( !(GET_CPSR & N_MASK) == !(GET_CPSR & V_MASK) ) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_LE:
+ if( Z_IS_SET(GET_CPSR) || ( !(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK) ) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_AL:
+ fatalerror("%08x: Undefined Thumb instruction: %04x (ARM9 reserved)\n", pc, insn);
+ R15 += 2;
+ break;
+
+ case COND_NV: // SWI (this is sort of a "hole" in the opcode encoding)
+ ARM7.pendingSwi = 1;
+ ARM7_CHECKIRQ;
+ break;
+ }
+ break;
+ case 0xe: /* B #offs */
+ offs = ( insn & THUMB_BRANCH_OFFS ) << 1;
+ if( offs & 0x00000800 )
+ {
+ offs |= 0xfffff800;
+ }
+ R15 += 4 + offs;
+ break;
+ case 0xf: /* BL */
+ if( insn & THUMB_BLOP_LO )
+ {
+ addr = GET_REGISTER(14);
+ addr += ( insn & THUMB_BLOP_OFFS ) << 1;
+ SET_REGISTER( 14, ( R15 + 2 ) | 1 );
+ R15 = addr;
+ // R15 += 2;
+ }
+ else
+ {
+ addr = ( insn & THUMB_BLOP_OFFS ) << 12;
+ if( addr & ( 1 << 22 ) )
+ {
+ addr |= 0xff800000;
+ }
+ addr += R15 + 4;
+ SET_REGISTER( 14, addr );
+ R15 += 2;
+ }
+ break;
+ default:
+ fatalerror("%08x: Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ }
+ else
+ {
+
+ /* load 32 bit instruction */
+ pc = R15;
+ insn = cpu_readop32(pc);
+
+ /* process condition codes for this instruction */
+ switch (insn >> INSN_COND_SHIFT)
+ {
+ case COND_EQ:
+ if (Z_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_NE:
+ if (Z_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_CS:
+ if (C_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_CC:
+ if (C_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_MI:
+ if (N_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_PL:
+ if (N_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_VS:
+ if (V_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_VC:
+ if (V_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_HI:
+ if (C_IS_CLEAR(GET_CPSR) || Z_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_LS:
+ if (C_IS_SET(GET_CPSR) && Z_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_GE:
+ if (!(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK)) goto L_Next; /* Use x ^ (x >> ...) method */
+ break;
+ case COND_LT:
+ if (!(GET_CPSR & N_MASK) == !(GET_CPSR & V_MASK)) goto L_Next;
+ break;
+ case COND_GT:
+ if (Z_IS_SET(GET_CPSR) || (!(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK))) goto L_Next;
+ break;
+ case COND_LE:
+ if (Z_IS_CLEAR(GET_CPSR) && (!(GET_CPSR & N_MASK) == !(GET_CPSR & V_MASK))) goto L_Next;
+ break;
+ case COND_NV:
+ goto L_Next;
+ }
+ /*******************************************************************/
+ /* If we got here - condition satisfied, so decode the instruction */
+ /*******************************************************************/
+ switch( (insn & 0xF000000)>>24 )
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ /* Branch and Exchange (BX) */
+ if( (insn&0x0ffffff0)==0x012fff10 ) //bits 27-4 == 000100101111111111110001
+ {
+ R15 = GET_REGISTER(insn & 0x0f);
+ //If new PC address has A0 set, switch to Thumb mode
+ if(R15 & 1) {
+ SET_CPSR(GET_CPSR|T_MASK);
+ R15--;
+ }
+ }
+ else
+ /* Multiply OR Swap OR Half Word Data Transfer */
+ if( (insn & 0x0e000000)==0 && (insn & 0x80) && (insn & 0x10) ) //bits 27-25 == 000, bit 7=1, bit 4=1
+ {
+ /* Half Word Data Transfer */
+ if(insn & 0x60) //bits = 6-5 != 00
+ {
+ HandleHalfWordDT(insn);
+ }
+ else
+ /* Swap */
+ if(insn & 0x01000000) //bit 24 = 1
+ {
+ HandleSwap(insn);
+ }
+ /* Multiply Or Multiply Long */
+ else
+ {
+ /* multiply long */
+ if( insn&0x800000 ) //Bit 23 = 1 for Multiply Long
+ {
+ /* Signed? */
+ if( insn&0x00400000 )
+ HandleSMulLong(insn);
+ else
+ HandleUMulLong(insn);
+ }
+ /* multiply */
+ else
+ {
+ HandleMul(insn);
+ }
+ R15 += 4;
+ }
+ }
+ else
+ /* Data Processing OR PSR Transfer */
+ if( (insn & 0x0c000000) ==0 ) //bits 27-26 == 00 - This check can only exist properly after Multiplication check above
+ {
+ /* PSR Transfer (MRS & MSR) */
+ if( ((insn&0x0100000)==0) && ((insn&0x01800000)==0x01000000) ) //( S bit must be clear, and bit 24,23 = 10 )
+ {
+ HandlePSRTransfer(insn);
+ ARM7_ICOUNT += 2; //PSR only takes 1 - S Cycle, so we add + 2, since at end, we -3..
+ R15 += 4;
+ }
+ /* Data Processing */
+ else
+ {
+ HandleALU(insn);
+ }
+ }
+ break;
+ /* Data Transfer - Single Data Access */
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ HandleMemSingle(insn);
+ R15 += 4;
+ break;
+ /* Block Data Transfer/Access */
+ case 8:
+ case 9:
+ HandleMemBlock(insn);
+ R15 += 4;
+ break;
+ /* Branch or Branch & Link */
+ case 0xa:
+ case 0xb:
+ HandleBranch(insn);
+ break;
+ /* Co-Processor Data Transfer */
+ case 0xc:
+ case 0xd:
+ HandleCoProcDT(insn);
+ R15 += 4;
+ break;
+ /* Co-Processor Data Operation or Register Transfer */
+ case 0xe:
+ if(insn & 0x10)
+ HandleCoProcRT(insn);
+ else
+ HandleCoProcDO(insn);
+ R15 += 4;
+ break;
+ /* Software Interrupt */
+ case 0x0f:
+ ARM7.pendingSwi = 1;
+ ARM7_CHECKIRQ;
+ //couldn't find any cycle counts for SWI
+ break;
+ /* Undefined */
+ default:
+ ARM7.pendingSwi = 1;
+ ARM7_CHECKIRQ;
+ ARM7_ICOUNT -= 1; //undefined takes 4 cycles (page 77)
+ LOG(("%08x: Undefined instruction\n",pc-4));
+ L_Next:
+ R15 += 4;
+ ARM7_ICOUNT +=2; //Any unexecuted instruction only takes 1 cycle (page 193)
+ }
+ }
+
+ change_pc(R15);
+
+ ARM7_CHECKIRQ;
+
+ /* All instructions remove 3 cycles.. Others taking less / more will have adjusted this # prior to here */
+ ARM7_ICOUNT -= 3;
+ } while( ARM7_ICOUNT > 0 );
+
+ return cycles - ARM7_ICOUNT;
+}
+
diff --git a/src/emu/cpu/asap/asap.c b/src/emu/cpu/asap/asap.c
new file mode 100644
index 00000000000..91278197f75
--- /dev/null
+++ b/src/emu/cpu/asap/asap.c
@@ -0,0 +1,1858 @@
+/***************************************************************************
+
+ asap.c
+ Core implementation for the portable ASAP emulator.
+ ASAP = Atari Simplified Architecture Processor
+
+ Written by Aaron Giles
+ Special thanks to Mike Albaugh for clarification on a couple of fine points.
+
+***************************************************************************/
+
+#include "debugger.h"
+#include "asap.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define PS_CFLAG 0x00000001
+#define PS_VFLAG 0x00000002
+#define PS_ZFLAG 0x00000004
+#define PS_NFLAG 0x00000008
+#define PS_IFLAG 0x00000010
+#define PS_PFLAG 0x00000020
+
+#define EXCEPTION_RESET 0
+#define EXCEPTION_TRAP0 1
+#define EXCEPTION_TRAPF 2
+#define EXCEPTION_INTERRUPT 3
+
+
+#define REGBASE 0xffe0
+
+
+#define SET_C_ADD(a,b) (asap.cflag = (UINT32)(b) > (UINT32)(~(a)))
+#define SET_C_SUB(a,b) (asap.cflag = (UINT32)(b) <= (UINT32)(a))
+#define SET_V_ADD(r,a,b) (asap.vflag = ~((a) ^ (b)) & ((a) ^ (r)))
+#define SET_V_SUB(r,a,b) (asap.vflag = ((a) ^ (b)) & ((a) ^ (r)))
+#define SET_ZN(r) (asap.znflag = (r))
+#define SET_ZNCV_ADD(r,a,b) SET_ZN(r); SET_C_ADD(a,b); SET_V_ADD(r,a,b)
+#define SET_ZNCV_SUB(r,a,b) SET_ZN(r); SET_C_SUB(a,b); SET_V_SUB(r,a,b)
+
+#define SET_VFLAG(val) (asap.vflag = (val) << 31)
+#define SET_CFLAG(val) (asap.cflag = (val))
+
+#define GET_FLAGS(r) ((r)->cflag | \
+ (((r)->vflag >> 30) & PS_VFLAG) | \
+ (((r)->znflag == 0) << 2) | \
+ (((r)->znflag >> 28) & PS_NFLAG) | \
+ ((r)->iflag << 4) | \
+ ((r)->pflag << 5))
+
+#define SET_FLAGS(r,v) do { \
+ (r)->cflag = (v) & PS_CFLAG; \
+ (r)->vflag = ((v) & PS_VFLAG) << 30; \
+ (r)->znflag = ((v) & PS_ZFLAG) ? 0 : ((v) & PS_NFLAG) ? -1 : 1; \
+ (r)->iflag = ((v) & PS_IFLAG) >> 4; \
+ (r)->pflag = ((v) & PS_PFLAG) >> 5; \
+ } while (0);
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+/* ASAP Registers */
+typedef struct
+{
+ /* core registers */
+ UINT32 r[32];
+ UINT32 pc;
+
+ /* expanded flags */
+ UINT32 pflag;
+ UINT32 iflag;
+ UINT32 cflag;
+ UINT32 vflag;
+ UINT32 znflag;
+
+ /* internal stuff */
+ PAIR op;
+ UINT32 ppc;
+ UINT32 nextpc;
+ UINT8 irq_state;
+ int interrupt_cycles;
+ int (*irq_callback)(int irqline);
+} asap_regs;
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static asap_regs asap;
+
+static void (**opcode)(void);
+static UINT32 *src2val;
+
+static int asap_icount;
+
+
+
+/***************************************************************************
+ OPCODE TABLE
+***************************************************************************/
+
+static void noop(void);
+static void trap0(void);
+static void bsp(void);
+static void bmz(void);
+static void bgt(void);
+static void ble(void);
+static void bge(void);
+static void blt(void);
+static void bhi(void);
+static void bls(void);
+static void bcc(void);
+static void bcs(void);
+static void bpl(void);
+static void bmi(void);
+static void bne(void);
+static void beq(void);
+static void bvc(void);
+static void bvs(void);
+static void bsr(void);
+static void bsr_0(void);
+static void lea(void);
+static void lea_c(void);
+static void lea_c0(void);
+static void leah(void);
+static void leah_c(void);
+static void leah_c0(void);
+static void subr(void);
+static void subr_c(void);
+static void subr_c0(void);
+static void xor(void);
+static void xor_c(void);
+static void xor_c0(void);
+static void xorn(void);
+static void xorn_c(void);
+static void xorn_c0(void);
+static void add(void);
+static void add_c(void);
+static void add_c0(void);
+static void sub(void);
+static void sub_c(void);
+static void sub_c0(void);
+static void addc(void);
+static void addc_c(void);
+static void addc_c0(void);
+static void subc(void);
+static void subc_c(void);
+static void subc_c0(void);
+static void and(void);
+static void and_c(void);
+static void and_c0(void);
+static void andn(void);
+static void andn_c(void);
+static void andn_c0(void);
+static void or(void);
+static void or_c(void);
+static void or_c0(void);
+static void orn(void);
+static void orn_c(void);
+static void orn_c0(void);
+static void ld(void);
+static void ld_0(void);
+static void ld_c(void);
+static void ld_c0(void);
+static void ldh(void);
+static void ldh_0(void);
+static void ldh_c(void);
+static void ldh_c0(void);
+static void lduh(void);
+static void lduh_0(void);
+static void lduh_c(void);
+static void lduh_c0(void);
+static void sth(void);
+static void sth_0(void);
+static void sth_c(void);
+static void sth_c0(void);
+static void st(void);
+static void st_0(void);
+static void st_c(void);
+static void st_c0(void);
+static void ldb(void);
+static void ldb_0(void);
+static void ldb_c(void);
+static void ldb_c0(void);
+static void ldub(void);
+static void ldub_0(void);
+static void ldub_c(void);
+static void ldub_c0(void);
+static void stb(void);
+static void stb_0(void);
+static void stb_c(void);
+static void stb_c0(void);
+static void ashr(void);
+static void ashr_c(void);
+static void ashr_c0(void);
+static void lshr(void);
+static void lshr_c(void);
+static void lshr_c0(void);
+static void ashl(void);
+static void ashl_c(void);
+static void ashl_c0(void);
+static void rotl(void);
+static void rotl_c(void);
+static void rotl_c0(void);
+static void getps(void);
+static void putps(void);
+static void jsr(void);
+static void jsr_0(void);
+static void jsr_c(void);
+static void jsr_c0(void);
+static void trapf(void);
+
+static void (*opcodetable[32][4])(void) =
+{
+ { trap0, trap0, trap0, trap0 },
+ { NULL, NULL, NULL, NULL },
+ { bsr, bsr_0, bsr, bsr_0 },
+ { lea, noop, lea_c, lea_c0 },
+ { leah, noop, leah_c, leah_c0 },
+ { subr, noop, subr_c, subr_c0 },
+ { xor, noop, xor_c, xor_c0 },
+ { xorn, noop, xorn_c, xorn_c0 },
+ { add, noop, add_c, add_c0 },
+ { sub, noop, sub_c, sub_c0 },
+ { addc, noop, addc_c, addc_c0 },
+ { subc, noop, subc_c, subc_c0 },
+ { and, noop, and_c, and_c0 },
+ { andn, noop, andn_c, andn_c0 },
+ { or, noop, or_c, or_c0 },
+ { orn, noop, orn_c, orn_c0 },
+ { ld, ld_0, ld_c, ld_c0 },
+ { ldh, ldh_0, ldh_c, ldh_c0 },
+ { lduh, lduh_0, lduh_c, lduh_c0 },
+ { sth, sth_0, sth_c, sth_c0 },
+ { st, st_0, st_c, st_c0 },
+ { ldb, ldb_0, ldb_c, ldb_c0 },
+ { ldub, ldub_0, ldub_c, ldub_c0 },
+ { stb, stb_0, stb_c, stb_c0 },
+ { ashr, noop, ashr_c, ashr_c0 },
+ { lshr, noop, lshr_c, lshr_c0 },
+ { ashl, noop, ashl_c, ashl_c0 },
+ { rotl, noop, rotl_c, rotl_c0 },
+ { getps, noop, getps, noop },
+ { putps, putps, putps, putps },
+ { jsr, jsr_0, jsr_c, jsr_c0 },
+ { trapf, trapf, trapf, trapf }
+};
+
+static void (*conditiontable[16])(void) =
+{
+ bsp, bmz, bgt, ble, bge, blt, bhi, bls,
+ bcc, bcs, bpl, bmi, bne, beq, bvc, bvs
+};
+
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(pc) cpu_readop32(pc)
+#define UPDATEPC() change_pc(asap.pc)
+
+
+INLINE UINT8 READBYTE(offs_t address)
+{
+ /* no alignment issues with bytes */
+ return program_read_byte_32le(address);
+}
+
+INLINE UINT16 READWORD(offs_t address)
+{
+ /* aligned reads are easy */
+ if (!(address & 1))
+ return program_read_word_32le(address);
+
+ /* misaligned reads are tricky */
+ return program_read_dword_32le(address & ~3) >> (address & 3);
+}
+
+INLINE UINT32 READLONG(offs_t address)
+{
+ /* aligned reads are easy */
+ if (!(address & 3))
+ return program_read_dword_32le(address);
+
+ /* misaligned reads are tricky */
+ return program_read_dword_32le(address & ~3) >> (address & 3);
+}
+
+INLINE void WRITEBYTE(offs_t address, UINT8 data)
+{
+ /* no alignment issues with bytes */
+ program_write_byte_32le(address, data);
+}
+
+INLINE void WRITEWORD(offs_t address, UINT16 data)
+{
+ /* aligned writes are easy */
+ if (!(address & 1))
+ {
+ program_write_word_32le(address, data);
+ return;
+ }
+
+ /* misaligned writes are tricky */
+ if (!(address & 2))
+ {
+ program_write_byte_32le(address + 1, data);
+ program_write_byte_32le(address + 2, data >> 8);
+ }
+ else
+ program_write_byte_32le(address + 1, data);
+}
+
+INLINE void WRITELONG(offs_t address, UINT32 data)
+{
+ /* aligned writes are easy */
+ if (!(address & 3))
+ {
+ program_write_dword_32le(address, data);
+ return;
+ }
+
+ /* misaligned writes are tricky */
+ switch (address & 3)
+ {
+ case 1:
+ program_write_byte_32le(address, data);
+ program_write_word_32le(address + 1, data >> 8);
+ break;
+ case 2:
+ program_write_word_32le(address, data);
+ break;
+ case 3:
+ program_write_byte_32le(address, data);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ EXCEPTION HANDLING
+***************************************************************************/
+
+INLINE void generate_exception(int exception)
+{
+ asap.pflag = asap.iflag;
+ asap.iflag = 0;
+
+ src2val[REGBASE + 30] = asap.pc;
+ src2val[REGBASE + 31] = (asap.nextpc == ~0) ? asap.pc + 4 : asap.nextpc;
+
+ asap.pc = 0x40 * exception;
+ asap.nextpc = ~0;
+ UPDATEPC();
+
+ asap.interrupt_cycles++;
+}
+
+
+
+/***************************************************************************
+ IRQ HANDLING
+***************************************************************************/
+
+INLINE void check_irqs(void)
+{
+ if (asap.irq_state && asap.iflag)
+ {
+ generate_exception(EXCEPTION_INTERRUPT);
+ if (asap.irq_callback)
+ (*asap.irq_callback)(ASAP_IRQ0);
+ }
+}
+
+
+static void set_irq_line(int irqline, int state)
+{
+ asap.irq_state = (state != CLEAR_LINE);
+ check_irqs();
+}
+
+
+
+/***************************************************************************
+ CONTEXT SWITCHING
+***************************************************************************/
+
+static void asap_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ {
+ if (src2val)
+ memcpy(&asap.r[0], &src2val[REGBASE], 32 * sizeof(UINT32));
+ *(asap_regs *)dst = asap;
+ }
+}
+
+
+static void asap_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ {
+ asap = *(asap_regs *)src;
+ if (src2val)
+ memcpy(&src2val[REGBASE], &asap.r[0], 32 * sizeof(UINT32));
+ UPDATEPC();
+
+ /* check for IRQs */
+ check_irqs();
+ }
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+static void init_tables(void)
+{
+ /* allocate opcode table */
+ if (!opcode)
+ opcode = auto_malloc(32 * 32 * 2 * sizeof(void *));
+
+ /* fill opcode table */
+ if (opcode)
+ {
+ int op, dst, cond;
+
+ for (op = 0; op < 32; op++)
+ for (dst = 0; dst < 32; dst++)
+ for (cond = 0; cond < 2; cond++)
+ if (op == 1)
+ opcode[(op << 6) + (dst << 1) + cond] = conditiontable[dst & 15];
+ else if (cond && dst == 0)
+ opcode[(op << 6) + (dst << 1) + cond] = opcodetable[op][3];
+ else if (cond)
+ opcode[(op << 6) + (dst << 1) + cond] = opcodetable[op][2];
+ else if (dst == 0)
+ opcode[(op << 6) + (dst << 1) + cond] = opcodetable[op][1];
+ else
+ opcode[(op << 6) + (dst << 1) + cond] = opcodetable[op][0];
+ }
+
+ /* allocate src2 table */
+ if (!src2val)
+ src2val = auto_malloc(65536 * sizeof(UINT32));
+
+ /* fill scr2 table */
+ if (src2val)
+ {
+ int i;
+
+ for (i = 0; i < REGBASE; i++)
+ src2val[i] = i;
+ memcpy(&src2val[REGBASE], &asap.r[0], 32 * sizeof(UINT32));
+ }
+}
+
+static void asap_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ init_tables();
+ asap.irq_callback = irqcallback;
+}
+
+static void asap_reset(void)
+{
+ /* initialize the state */
+ src2val[REGBASE + 0] = 0;
+ asap.pc = 0;
+ asap.iflag = 0;
+
+ asap.ppc = 0;
+ asap.nextpc = ~0;
+ asap.irq_state = 0;
+ asap.interrupt_cycles = 0;
+ asap.irq_callback = NULL;
+
+ UPDATEPC();
+}
+
+
+static void asap_exit(void)
+{
+ opcode = NULL;
+ src2val = NULL;
+}
+
+
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+INLINE void fetch_instruction(void)
+{
+ /* debugging */
+ asap.ppc = asap.pc;
+ CALL_MAME_DEBUG;
+
+ /* instruction fetch */
+ asap.op.d = ROPCODE(asap.pc);
+ asap.pc += 4;
+}
+
+INLINE void execute_instruction(void)
+{
+ /* parse the instruction */
+ (*opcode[asap.op.d >> 21])();
+}
+
+static int asap_execute(int cycles)
+{
+ /* count cycles and interrupt cycles */
+ asap_icount = cycles;
+ asap_icount -= asap.interrupt_cycles;
+ asap.interrupt_cycles = 0;
+ UPDATEPC();
+
+ /* core execution loop */
+ do
+ {
+ /* fetch and execute the next instruction */
+ fetch_instruction();
+ execute_instruction();
+
+ /* fetch and execute the next instruction */
+ fetch_instruction();
+ execute_instruction();
+
+ /* fetch and execute the next instruction */
+ fetch_instruction();
+ execute_instruction();
+
+ /* fetch and execute the next instruction */
+ fetch_instruction();
+ execute_instruction();
+
+ asap_icount -= 4;
+
+ } while (asap_icount > 0);
+
+ /* eat any new interrupt cycles */
+ asap_icount -= asap.interrupt_cycles;
+ asap.interrupt_cycles = 0;
+ return cycles - asap_icount;
+}
+
+
+
+/***************************************************************************
+ DISASSEMBLY HOOK
+***************************************************************************/
+
+#ifdef MAME_DEBUG
+extern offs_t asap_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+
+
+/***************************************************************************
+ HELPER MACROS
+***************************************************************************/
+
+#define OPCODE (asap.op.d >> 27)
+#define DSTREG ((asap.op.d >> 22) & 31)
+#define DSTVAL src2val[REGBASE + DSTREG]
+#define SRC1REG ((asap.op.d >> 16) & 31)
+#define SRC1VAL src2val[REGBASE + SRC1REG]
+#define SRC2VAL src2val[asap.op.w.l]
+
+
+
+/***************************************************************************
+ OPCODES
+***************************************************************************/
+
+static void noop(void)
+{
+}
+
+/**************************** TRAP 0 ******************************/
+
+static void trap0(void)
+{
+ generate_exception(EXCEPTION_TRAP0);
+}
+
+/**************************** Bcc ******************************/
+
+static void bsp(void)
+{
+ if ((INT32)asap.znflag > 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bmz(void)
+{
+ if ((INT32)asap.znflag <= 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bgt(void)
+{
+ if (asap.znflag != 0 && (INT32)(asap.znflag ^ asap.vflag) >= 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void ble(void)
+{
+ if (asap.znflag == 0 || (INT32)(asap.znflag ^ asap.vflag) < 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bge(void)
+{
+ if ((INT32)(asap.znflag ^ asap.vflag) >= 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void blt(void)
+{
+ if ((INT32)(asap.znflag ^ asap.vflag) < 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bhi(void)
+{
+ if (asap.znflag != 0 && asap.cflag)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bls(void)
+{
+ if (asap.znflag == 0 || !asap.cflag)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bcc(void)
+{
+ if (!asap.cflag)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bcs(void)
+{
+ if (asap.cflag)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bpl(void)
+{
+ if ((INT32)asap.znflag >= 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bmi(void)
+{
+ if ((INT32)asap.znflag < 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bne(void)
+{
+ if (asap.znflag != 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void beq(void)
+{
+ if (asap.znflag == 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bvc(void)
+{
+ if ((INT32)asap.vflag >= 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+static void bvs(void)
+{
+ if ((INT32)asap.vflag < 0)
+ {
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+ }
+}
+
+/**************************** BSR ******************************/
+
+static void bsr(void)
+{
+ DSTVAL = asap.pc + 4;
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+}
+
+static void bsr_0(void)
+{
+ asap.nextpc = asap.ppc + ((INT32)(asap.op.d << 10) >> 8);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ /*UPDATEPC();*/
+
+ execute_instruction();
+ asap_icount--;
+}
+
+/**************************** LEA ******************************/
+
+static void lea(void)
+{
+ DSTVAL = SRC1VAL + (SRC2VAL << 2);
+}
+
+static void lea_c(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 + (src2 << 2);
+
+ SET_ZNCV_ADD(dst, src1, src2);
+ if (src1 & 0xc0000000)
+ SET_CFLAG(1);
+ if (((src1 ^ (src1 >> 1)) & 0x20000000) || (src1 ^ (src1 >> 2)) & 0x20000000)
+ SET_VFLAG(1);
+ DSTVAL = dst;
+}
+
+static void lea_c0(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 + (src2 << 2);
+
+ SET_ZNCV_ADD(dst, src1, src2);
+ if (src1 & 0xc0000000)
+ SET_CFLAG(1);
+ if (((src1 ^ (src1 >> 1)) & 0x20000000) || (src1 ^ (src1 >> 2)) & 0x20000000)
+ SET_VFLAG(1);
+}
+
+/**************************** LEAH ******************************/
+
+static void leah(void)
+{
+ DSTVAL = SRC1VAL + (SRC2VAL << 1);
+}
+
+static void leah_c(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 + (src2 << 1);
+
+ SET_ZNCV_ADD(dst, src1, src2);
+ if (src1 & 0x80000000)
+ SET_CFLAG(1);
+ if ((src1 ^ (src1 >> 1)) & 0x40000000)
+ SET_VFLAG(1);
+ DSTVAL = dst;
+}
+
+static void leah_c0(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 + (src2 << 1);
+
+ SET_ZNCV_ADD(dst, src1, src2);
+ if (src1 & 0x80000000)
+ SET_CFLAG(1);
+ if ((src1 ^ (src1 >> 1)) & 0x40000000)
+ SET_VFLAG(1);
+}
+
+/**************************** SUBR ******************************/
+
+static void subr(void)
+{
+ DSTVAL = SRC2VAL - SRC1VAL;
+}
+
+static void subr_c(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src2 - src1;
+
+ SET_ZNCV_SUB(dst, src2, src1);
+ DSTVAL = dst;
+}
+
+static void subr_c0(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src2 - src1;
+
+ SET_ZNCV_SUB(dst, src2, src1);
+}
+
+/**************************** XOR ******************************/
+
+static void xor(void)
+{
+ DSTVAL = SRC1VAL ^ SRC2VAL;
+}
+
+static void xor_c(void)
+{
+ UINT32 dst = SRC1VAL ^ SRC2VAL;
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void xor_c0(void)
+{
+ UINT32 dst = SRC1VAL ^ SRC2VAL;
+ SET_ZN(dst);
+}
+
+/**************************** XOR ******************************/
+
+static void xorn(void)
+{
+ DSTVAL = SRC1VAL ^ ~SRC2VAL;
+}
+
+static void xorn_c(void)
+{
+ UINT32 dst = SRC1VAL ^ ~SRC2VAL;
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void xorn_c0(void)
+{
+ UINT32 dst = SRC1VAL ^ ~SRC2VAL;
+ SET_ZN(dst);
+}
+
+/**************************** ADD ******************************/
+
+static void add(void)
+{
+ DSTVAL = SRC1VAL + SRC2VAL;
+}
+
+static void add_c(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 + src2;
+
+ SET_ZNCV_ADD(dst, src1, src2);
+ DSTVAL = dst;
+}
+
+static void add_c0(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 + src2;
+
+ SET_ZNCV_ADD(dst, src1, src2);
+}
+
+/**************************** ADD ******************************/
+
+static void sub(void)
+{
+ DSTVAL = SRC1VAL - SRC2VAL;
+}
+
+static void sub_c(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 - src2;
+
+ SET_ZNCV_SUB(dst, src1, src2);
+ DSTVAL = dst;
+}
+
+static void sub_c0(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 - src2;
+
+ SET_ZNCV_SUB(dst, src1, src2);
+}
+
+/**************************** ADDC ******************************/
+
+static void addc(void)
+{
+ DSTVAL = SRC1VAL + SRC2VAL + asap.cflag;
+}
+
+static void addc_c(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 + src2 + asap.cflag;
+
+ SET_ZNCV_ADD(dst, src1, src2);
+ DSTVAL = dst;
+}
+
+static void addc_c0(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 + src2 + asap.cflag;
+
+ SET_ZNCV_ADD(dst, src1, src2);
+}
+
+/**************************** SUBC ******************************/
+
+static void subc(void)
+{
+ DSTVAL = SRC1VAL - SRC2VAL - 1 + asap.cflag;
+}
+
+static void subc_c(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 - src2 - 1 + asap.cflag;
+
+ SET_ZNCV_SUB(dst, src1, src2);
+ DSTVAL = dst;
+}
+
+static void subc_c0(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL;
+ UINT32 dst = src1 - src2 - 1 + asap.cflag;
+
+ SET_ZNCV_SUB(dst, src1, src2);
+}
+
+/**************************** AND ******************************/
+
+static void and(void)
+{
+ DSTVAL = SRC1VAL & SRC2VAL;
+}
+
+static void and_c(void)
+{
+ UINT32 dst = SRC1VAL & SRC2VAL;
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void and_c0(void)
+{
+ UINT32 dst = SRC1VAL & SRC2VAL;
+ SET_ZN(dst);
+}
+
+/**************************** ANDN ******************************/
+
+static void andn(void)
+{
+ DSTVAL = SRC1VAL & ~SRC2VAL;
+}
+
+static void andn_c(void)
+{
+ UINT32 dst = SRC1VAL & ~SRC2VAL;
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void andn_c0(void)
+{
+ UINT32 dst = SRC1VAL & ~SRC2VAL;
+ SET_ZN(dst);
+}
+
+/**************************** OR ******************************/
+
+static void or(void)
+{
+ DSTVAL = SRC1VAL | SRC2VAL;
+}
+
+static void or_c(void)
+{
+ UINT32 dst = SRC1VAL | SRC2VAL;
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void or_c0(void)
+{
+ UINT32 dst = SRC1VAL | SRC2VAL;
+ SET_ZN(dst);
+}
+
+/**************************** ORN ******************************/
+
+static void orn(void)
+{
+ DSTVAL = SRC1VAL | ~SRC2VAL;
+}
+
+static void orn_c(void)
+{
+ UINT32 dst = SRC1VAL | ~SRC2VAL;
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void orn_c0(void)
+{
+ UINT32 dst = SRC1VAL | ~SRC2VAL;
+ SET_ZN(dst);
+}
+
+/**************************** LD ******************************/
+
+static void ld(void)
+{
+ DSTVAL = READLONG(SRC1VAL + (SRC2VAL << 2));
+}
+
+static void ld_0(void)
+{
+ READLONG(SRC1VAL + (SRC2VAL << 2));
+}
+
+static void ld_c(void)
+{
+ UINT32 dst = READLONG(SRC1VAL + (SRC2VAL << 2));
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void ld_c0(void)
+{
+ UINT32 dst = READLONG(SRC1VAL + (SRC2VAL << 2));
+ SET_ZN(dst);
+}
+
+/**************************** LDH ******************************/
+
+static void ldh(void)
+{
+ DSTVAL = (INT16)READWORD(SRC1VAL + (SRC2VAL << 1));
+}
+
+static void ldh_0(void)
+{
+ READWORD(SRC1VAL + (SRC2VAL << 1));
+}
+
+static void ldh_c(void)
+{
+ UINT32 dst = (INT16)READWORD(SRC1VAL + (SRC2VAL << 1));
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void ldh_c0(void)
+{
+ UINT32 dst = (INT16)READWORD(SRC1VAL + (SRC2VAL << 1));
+ SET_ZN(dst);
+}
+
+/**************************** LDUH ******************************/
+
+static void lduh(void)
+{
+ DSTVAL = READWORD(SRC1VAL + (SRC2VAL << 1));
+}
+
+static void lduh_0(void)
+{
+ READWORD(SRC1VAL + (SRC2VAL << 1));
+}
+
+static void lduh_c(void)
+{
+ UINT32 dst = READWORD(SRC1VAL + (SRC2VAL << 1));
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void lduh_c0(void)
+{
+ UINT32 dst = READWORD(SRC1VAL + (SRC2VAL << 1));
+ SET_ZN(dst);
+}
+
+/**************************** STH ******************************/
+
+static void sth(void)
+{
+ WRITEWORD(SRC1VAL + (SRC2VAL << 1), DSTVAL);
+}
+
+static void sth_0(void)
+{
+ WRITEWORD(SRC1VAL + (SRC2VAL << 1), 0);
+}
+
+static void sth_c(void)
+{
+ UINT32 dst = (UINT16)DSTVAL;
+ SET_ZN(dst);
+ WRITEWORD(SRC1VAL + (SRC2VAL << 1), dst);
+}
+
+static void sth_c0(void)
+{
+ SET_ZN(0);
+ WRITEWORD(SRC1VAL + (SRC2VAL << 1), 0);
+}
+
+/**************************** ST ******************************/
+
+static void st(void)
+{
+ WRITELONG(SRC1VAL + (SRC2VAL << 2), DSTVAL);
+}
+
+static void st_0(void)
+{
+ WRITELONG(SRC1VAL + (SRC2VAL << 2), 0);
+}
+
+static void st_c(void)
+{
+ UINT32 dst = DSTVAL;
+ SET_ZN(dst);
+ WRITELONG(SRC1VAL + (SRC2VAL << 2), dst);
+}
+
+static void st_c0(void)
+{
+ SET_ZN(0);
+ WRITELONG(SRC1VAL + (SRC2VAL << 2), 0);
+}
+
+/**************************** LDB ******************************/
+
+static void ldb(void)
+{
+ DSTVAL = (INT8)READBYTE(SRC1VAL + SRC2VAL);
+}
+
+static void ldb_0(void)
+{
+ READBYTE(SRC1VAL + SRC2VAL);
+}
+
+static void ldb_c(void)
+{
+ UINT32 dst = (INT8)READBYTE(SRC1VAL + SRC2VAL);
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void ldb_c0(void)
+{
+ UINT32 dst = (INT8)READBYTE(SRC1VAL + SRC2VAL);
+ SET_ZN(dst);
+}
+
+/**************************** LDUB ******************************/
+
+static void ldub(void)
+{
+ DSTVAL = READBYTE(SRC1VAL + SRC2VAL);
+}
+
+static void ldub_0(void)
+{
+ READBYTE(SRC1VAL + SRC2VAL);
+}
+
+static void ldub_c(void)
+{
+ UINT32 dst = READBYTE(SRC1VAL + SRC2VAL);
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void ldub_c0(void)
+{
+ UINT32 dst = READBYTE(SRC1VAL + SRC2VAL);
+ SET_ZN(dst);
+}
+
+/**************************** STB ******************************/
+
+static void stb(void)
+{
+ WRITEBYTE(SRC1VAL + SRC2VAL, DSTVAL);
+}
+
+static void stb_0(void)
+{
+ WRITEBYTE(SRC1VAL + SRC2VAL, 0);
+}
+
+static void stb_c(void)
+{
+ UINT32 dst = (UINT8)DSTVAL;
+ SET_ZN(dst);
+ WRITEBYTE(SRC1VAL + SRC2VAL, dst);
+}
+
+static void stb_c0(void)
+{
+ SET_ZN(0);
+ WRITEBYTE(SRC1VAL + SRC2VAL, 0);
+}
+
+/**************************** ASHR ******************************/
+
+static void ashr(void)
+{
+ UINT32 src2 = SRC2VAL;
+ DSTVAL = (src2 < 32) ? ((INT32)SRC1VAL >> src2) : ((INT32)SRC1VAL >> 31);
+}
+
+static void ashr_c(void)
+{
+ UINT32 src2 = SRC2VAL;
+ asap.cflag = 0;
+ if (src2 < 32)
+ {
+ UINT32 src1 = SRC1VAL;
+ UINT32 dst = (INT32)src1 >> src2;
+ SET_ZN(dst);
+ if (src2 != 0)
+ {
+ src1 = src1 << (32 - src2);
+ asap.cflag = src1 >> 31;
+ }
+ DSTVAL = dst;
+ }
+ else
+ {
+ UINT32 dst = (INT32)SRC1VAL >> 31;
+ SET_ZN(dst);
+ DSTVAL = dst;
+ }
+}
+
+static void ashr_c0(void)
+{
+ UINT32 src2 = SRC2VAL;
+ asap.cflag = 0;
+ if (src2 < 32)
+ {
+ UINT32 src1 = SRC1VAL;
+ UINT32 dst = (INT32)src1 >> src2;
+ SET_ZN(dst);
+ if (src2 != 0)
+ {
+ src1 = src1 << (32 - src2);
+ asap.cflag = src1 >> 31;
+ }
+ }
+ else
+ {
+ UINT32 dst = (INT32)SRC1VAL >> 31;
+ SET_ZN(dst);
+ }
+}
+
+/**************************** LSHR ******************************/
+
+static void lshr(void)
+{
+ UINT32 src2 = SRC2VAL;
+ DSTVAL = (src2 < 32) ? (SRC1VAL >> src2) : (SRC1VAL >> 31);
+}
+
+static void lshr_c(void)
+{
+ UINT32 src2 = SRC2VAL;
+ asap.cflag = 0;
+ if (src2 < 32)
+ {
+ UINT32 src1 = SRC1VAL;
+ UINT32 dst = src1 >> src2;
+ SET_ZN(dst);
+ if (src2 != 0)
+ {
+ src1 = src1 << (32 - src2);
+ asap.cflag = src1 >> 31;
+ }
+ DSTVAL = dst;
+ }
+ else
+ {
+ UINT32 dst = SRC1VAL >> 31;
+ SET_ZN(dst);
+ DSTVAL = dst;
+ }
+}
+
+static void lshr_c0(void)
+{
+ UINT32 src2 = SRC2VAL;
+ asap.cflag = 0;
+ if (src2 < 32)
+ {
+ UINT32 src1 = SRC1VAL;
+ UINT32 dst = src1 >> src2;
+ SET_ZN(dst);
+ if (src2 != 0)
+ {
+ src1 = src1 << (32 - src2);
+ asap.cflag = src1 >> 31;
+ }
+ }
+ else
+ {
+ SET_ZN(0);
+ DSTVAL = 0;
+ }
+}
+
+/**************************** ASHL ******************************/
+
+static void ashl(void)
+{
+ UINT32 src2 = SRC2VAL;
+ DSTVAL = (src2 < 32) ? (SRC1VAL << src2) : 0;
+}
+
+static void ashl_c(void)
+{
+ UINT32 src2 = SRC2VAL;
+ asap.cflag = asap.vflag = 0;
+ if (src2 < 32)
+ {
+ UINT32 src1 = SRC1VAL;
+ UINT32 dst = src1 << src2;
+ SET_ZN(dst);
+ if (src2 != 0)
+ {
+ src1 = (INT32)src1 >> (32 - src2);
+ asap.cflag = src1 & PS_CFLAG;
+ asap.vflag = (src1 != ((INT32)dst >> 31)) << 31;
+ }
+ DSTVAL = dst;
+ }
+ else
+ {
+ SET_ZN(0);
+ DSTVAL = 0;
+ }
+}
+
+static void ashl_c0(void)
+{
+ UINT32 src2 = SRC2VAL;
+ asap.cflag = asap.vflag = 0;
+ if (src2 < 32)
+ {
+ UINT32 src1 = SRC1VAL;
+ UINT32 dst = src1 << src2;
+ SET_ZN(dst);
+ if (src2 != 0)
+ {
+ src1 = (INT32)src1 >> (32 - src2);
+ asap.cflag = src1 & PS_CFLAG;
+ asap.vflag = (src1 != ((INT32)dst >> 31)) << 31;
+ }
+ }
+ else
+ SET_ZN(0);
+}
+
+/**************************** ROTL ******************************/
+
+static void rotl(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL & 31;
+ DSTVAL = (src1 << src2) | (src1 >> (32 - src2));
+}
+
+static void rotl_c(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL & 31;
+ UINT32 dst = (src1 << src2) | (src1 >> (32 - src2));
+ SET_ZN(dst);
+ DSTVAL = dst;
+}
+
+static void rotl_c0(void)
+{
+ UINT32 src1 = SRC1VAL;
+ UINT32 src2 = SRC2VAL & 31;
+ UINT32 dst = (src1 << src2) | (src1 >> (32 - src2));
+ SET_ZN(dst);
+}
+
+/**************************** GETPS ******************************/
+
+static void getps(void)
+{
+ DSTVAL = GET_FLAGS(&asap);
+}
+
+/**************************** PUTPS ******************************/
+
+static void putps(void)
+{
+ UINT32 src2 = SRC2VAL & 0x3f;
+ SET_FLAGS(&asap, src2);
+ check_irqs();
+}
+
+/**************************** JSR ******************************/
+
+static void jsr(void)
+{
+ DSTVAL = asap.pc + 4;
+ asap.nextpc = SRC1VAL + (SRC2VAL << 2);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ UPDATEPC();
+
+ execute_instruction();
+ asap_icount--;
+}
+
+static void jsr_0(void)
+{
+ asap.nextpc = SRC1VAL + (SRC2VAL << 2);
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ UPDATEPC();
+
+ execute_instruction();
+ asap_icount--;
+}
+
+static void jsr_c(void)
+{
+ DSTVAL = asap.pc + 4;
+ asap.nextpc = SRC1VAL + (SRC2VAL << 2);
+ asap.iflag = asap.pflag;
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ UPDATEPC();
+
+ execute_instruction();
+ asap_icount--;
+ check_irqs();
+}
+
+static void jsr_c0(void)
+{
+ asap.nextpc = SRC1VAL + (SRC2VAL << 2);
+ asap.iflag = asap.pflag;
+
+ fetch_instruction();
+ asap.pc = asap.nextpc;
+ asap.nextpc = ~0;
+ UPDATEPC();
+
+ execute_instruction();
+ asap_icount--;
+ check_irqs();
+}
+
+/**************************** TRAP F ******************************/
+
+static void trapf(void)
+{
+ generate_exception(EXCEPTION_TRAPF);
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void asap_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + ASAP_IRQ0: set_irq_line(ASAP_IRQ0, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ASAP_PC: asap.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_PS: SET_FLAGS(&asap, info->i); break;
+
+ case CPUINFO_INT_REGISTER + ASAP_R0: src2val[REGBASE + 0] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R1: src2val[REGBASE + 1] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R2: src2val[REGBASE + 2] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R3: src2val[REGBASE + 3] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R4: src2val[REGBASE + 4] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R5: src2val[REGBASE + 5] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R6: src2val[REGBASE + 6] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R7: src2val[REGBASE + 7] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R8: src2val[REGBASE + 8] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R9: src2val[REGBASE + 9] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R10: src2val[REGBASE + 10] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R11: src2val[REGBASE + 11] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R12: src2val[REGBASE + 12] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R13: src2val[REGBASE + 13] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R14: src2val[REGBASE + 14] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R15: src2val[REGBASE + 15] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R16: src2val[REGBASE + 16] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R17: src2val[REGBASE + 17] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R18: src2val[REGBASE + 18] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R19: src2val[REGBASE + 19] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R20: src2val[REGBASE + 20] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R21: src2val[REGBASE + 21] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R22: src2val[REGBASE + 22] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R23: src2val[REGBASE + 23] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R24: src2val[REGBASE + 24] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R25: src2val[REGBASE + 25] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R26: src2val[REGBASE + 26] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R27: src2val[REGBASE + 27] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R28: src2val[REGBASE + 28] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R29: src2val[REGBASE + 29] = info->i; break;
+ case CPUINFO_INT_REGISTER + ASAP_R30: src2val[REGBASE + 30] = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + ASAP_R31: src2val[REGBASE + 31] = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void asap_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(asap); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 12; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 2; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + ASAP_IRQ0: info->i = asap.irq_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = asap.ppc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + ASAP_PC: info->i = asap.pc; break;
+ case CPUINFO_INT_REGISTER + ASAP_PS: info->i = GET_FLAGS(&asap); break;
+
+ case CPUINFO_INT_REGISTER + ASAP_R0: info->i = src2val[REGBASE + 0]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R1: info->i = src2val[REGBASE + 1]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R2: info->i = src2val[REGBASE + 2]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R3: info->i = src2val[REGBASE + 3]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R4: info->i = src2val[REGBASE + 4]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R5: info->i = src2val[REGBASE + 5]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R6: info->i = src2val[REGBASE + 6]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R7: info->i = src2val[REGBASE + 7]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R8: info->i = src2val[REGBASE + 8]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R9: info->i = src2val[REGBASE + 9]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R10: info->i = src2val[REGBASE + 10]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R11: info->i = src2val[REGBASE + 11]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R12: info->i = src2val[REGBASE + 12]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R13: info->i = src2val[REGBASE + 13]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R14: info->i = src2val[REGBASE + 14]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R15: info->i = src2val[REGBASE + 15]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R16: info->i = src2val[REGBASE + 16]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R17: info->i = src2val[REGBASE + 17]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R18: info->i = src2val[REGBASE + 18]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R19: info->i = src2val[REGBASE + 19]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R20: info->i = src2val[REGBASE + 20]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R21: info->i = src2val[REGBASE + 21]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R22: info->i = src2val[REGBASE + 22]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R23: info->i = src2val[REGBASE + 23]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R24: info->i = src2val[REGBASE + 24]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R25: info->i = src2val[REGBASE + 25]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R26: info->i = src2val[REGBASE + 26]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R27: info->i = src2val[REGBASE + 27]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R28: info->i = src2val[REGBASE + 28]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R29: info->i = src2val[REGBASE + 29]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R30: info->i = src2val[REGBASE + 30]; break;
+ case CPUINFO_INT_REGISTER + ASAP_R31: info->i = src2val[REGBASE + 31]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = asap_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = asap_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = asap_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = asap_init; break;
+ case CPUINFO_PTR_RESET: info->reset = asap_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = asap_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = asap_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = asap_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &asap_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ASAP"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Atari ASAP"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) Aaron Giles 2000-2004"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + ASAP_PC: sprintf(info->s, "PC: %08X", asap.pc); break;
+ case CPUINFO_STR_REGISTER + ASAP_PS: sprintf(info->s, "PS: %08X", GET_FLAGS(&asap)); break;
+
+ case CPUINFO_STR_REGISTER + ASAP_R0: sprintf(info->s, "R0: %08X", asap.r[0]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R1: sprintf(info->s, "R1: %08X", asap.r[1]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R2: sprintf(info->s, "R2: %08X", asap.r[2]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R3: sprintf(info->s, "R3: %08X", asap.r[3]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R4: sprintf(info->s, "R4: %08X", asap.r[4]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R5: sprintf(info->s, "R5: %08X", asap.r[5]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R6: sprintf(info->s, "R6: %08X", asap.r[6]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R7: sprintf(info->s, "R7: %08X", asap.r[7]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R8: sprintf(info->s, "R8: %08X", asap.r[8]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R9: sprintf(info->s, "R9: %08X", asap.r[9]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R10: sprintf(info->s, "R10:%08X", asap.r[10]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R11: sprintf(info->s, "R11:%08X", asap.r[11]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R12: sprintf(info->s, "R12:%08X", asap.r[12]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R13: sprintf(info->s, "R13:%08X", asap.r[13]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R14: sprintf(info->s, "R14:%08X", asap.r[14]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R15: sprintf(info->s, "R15:%08X", asap.r[15]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R16: sprintf(info->s, "R16:%08X", asap.r[16]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R17: sprintf(info->s, "R17:%08X", asap.r[17]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R18: sprintf(info->s, "R18:%08X", asap.r[18]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R19: sprintf(info->s, "R19:%08X", asap.r[19]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R20: sprintf(info->s, "R20:%08X", asap.r[20]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R21: sprintf(info->s, "R21:%08X", asap.r[21]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R22: sprintf(info->s, "R22:%08X", asap.r[22]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R23: sprintf(info->s, "R23:%08X", asap.r[23]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R24: sprintf(info->s, "R24:%08X", asap.r[24]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R25: sprintf(info->s, "R25:%08X", asap.r[25]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R26: sprintf(info->s, "R26:%08X", asap.r[26]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R27: sprintf(info->s, "R27:%08X", asap.r[27]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R28: sprintf(info->s, "R28:%08X", asap.r[28]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R29: sprintf(info->s, "R29:%08X", asap.r[29]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R30: sprintf(info->s, "R30:%08X", asap.r[30]); break;
+ case CPUINFO_STR_REGISTER + ASAP_R31: sprintf(info->s, "R31:%08X", asap.r[31]); break;
+ }
+}
diff --git a/src/emu/cpu/asap/asap.h b/src/emu/cpu/asap/asap.h
new file mode 100644
index 00000000000..cecdc0034b7
--- /dev/null
+++ b/src/emu/cpu/asap/asap.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+
+ asap.h
+ Interface file for the portable Atari ASAP emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#ifndef _ASAP_H
+#define _ASAP_H
+
+#include "cpuintrf.h"
+
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ ASAP_PC=1,ASAP_PS,
+ ASAP_R0,ASAP_R1,ASAP_R2,ASAP_R3,ASAP_R4,ASAP_R5,ASAP_R6,ASAP_R7,
+ ASAP_R8,ASAP_R9,ASAP_R10,ASAP_R11,ASAP_R12,ASAP_R13,ASAP_R14,ASAP_R15,
+ ASAP_R16,ASAP_R17,ASAP_R18,ASAP_R19,ASAP_R20,ASAP_R21,ASAP_R22,ASAP_R23,
+ ASAP_R24,ASAP_R25,ASAP_R26,ASAP_R27,ASAP_R28,ASAP_R29,ASAP_R30,ASAP_R31
+};
+
+
+/***************************************************************************
+ INTERRUPT CONSTANTS
+***************************************************************************/
+
+#define ASAP_IRQ0 0 /* IRQ0 */
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+extern void asap_get_info(UINT32 state, cpuinfo *info);
+
+#endif /* _ASAP_H */
diff --git a/src/emu/cpu/asap/asapdasm.c b/src/emu/cpu/asap/asapdasm.c
new file mode 100644
index 00000000000..43f25e6fcea
--- /dev/null
+++ b/src/emu/cpu/asap/asapdasm.c
@@ -0,0 +1,148 @@
+/***************************************************************************
+
+ asapdasm.c
+ Disassembler for the portable ASAP emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#include "asap.h"
+
+
+static const char *reg[32] =
+{
+ "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+static const char *setcond[2] =
+{
+ " ", ".c"
+};
+
+static const char *condition[16] =
+{
+ "sp", "mz", "gt", "le", "ge", "lt", "hi", "ls", "cc", "cs", "pl", "mi", "ne", "eq", "vc", "vs"
+};
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(pc) cpu_readop32(pc)
+
+
+/***************************************************************************
+ CODE CODE
+***************************************************************************/
+
+INLINE char *src2(UINT32 op, int scale)
+{
+ static char temp[20];
+ if ((op & 0xffe0) == 0xffe0)
+ sprintf(temp, "%s", reg[op & 31]);
+ else
+ sprintf(temp, "$%x", (op & 0xffff) << scale);
+ return temp;
+}
+
+offs_t asap_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24);
+ int opcode = op >> 27;
+ int cond = (op >> 21) & 1;
+ int rdst = (op >> 22) & 31;
+ int rsrc1 = (op >> 16) & 31;
+ int rsrc2 = op & 0xffff;
+ int rsrc2_iszero = (!rsrc2 || rsrc2 == 0xffe0);
+ UINT32 flags = 0;
+
+ switch (opcode)
+ {
+ case 0x00: sprintf(buffer, "trap $00"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x01: sprintf(buffer, "b%s $%08x", condition[rdst & 15], pc + ((INT32)(op << 10) >> 8)); break;
+ case 0x02: if ((op & 0x003fffff) == 3)
+ {
+ UINT32 nextop = oprom[4] | (oprom[5] << 8) | (oprom[6] << 16) | (oprom[7] << 24);
+ if ((nextop >> 27) == 0x10 && ((nextop >> 22) & 31) == rdst && (nextop & 0xffff) == 0)
+ {
+ UINT32 nextnextop = oprom[8] | (oprom[9] << 8) | (oprom[10] << 16) | (oprom[11] << 24);
+ sprintf(buffer, "llit%s $%08x,%s", setcond[cond], nextnextop, reg[rdst]);
+ return 12 | DASMFLAG_STEP_OVER | DASMFLAG_SUPPORTED;
+ }
+ }
+ if (rdst)
+ {
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ sprintf(buffer, "bsr %s,$%08x", reg[rdst], pc + ((INT32)(op << 10) >> 8));
+ }
+ else
+ sprintf(buffer, "bra $%08x", pc + ((INT32)(op << 10) >> 8));
+ break;
+ case 0x03: sprintf(buffer, "lea%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break;
+ case 0x04: sprintf(buffer, "leah%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x05: sprintf(buffer, "subr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x06: sprintf(buffer, "xor%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x07: sprintf(buffer, "xorn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x08: if (!rsrc1 && !rdst && rsrc2_iszero)
+ sprintf(buffer, "nop");
+ else if (!rsrc1)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], src2(op,0), reg[rdst]);
+ else if (rsrc2_iszero)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], reg[rsrc1], reg[rdst]);
+ else
+ sprintf(buffer, "add%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x09: sprintf(buffer, "sub%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0a: sprintf(buffer, "addc%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0b: sprintf(buffer, "subc%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0c: sprintf(buffer, "and%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0d: sprintf(buffer, "andn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0e: if (!rsrc1 && !rdst && rsrc2_iszero)
+ sprintf(buffer, "nop");
+ else if (!rsrc1)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], src2(op,0), reg[rdst]);
+ else if (rsrc2_iszero)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], reg[rsrc1], reg[rdst]);
+ else
+ sprintf(buffer, "or%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0f: sprintf(buffer, "orn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x10: sprintf(buffer, "ld%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break;
+ case 0x11: sprintf(buffer, "ldh%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x12: sprintf(buffer, "lduh%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x13: sprintf(buffer, "sth%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x14: sprintf(buffer, "st%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break;
+ case 0x15: sprintf(buffer, "ldb%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x16: sprintf(buffer, "ldub%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x17: sprintf(buffer, "stb%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x18: sprintf(buffer, "ashr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x19: sprintf(buffer, "lshr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x1a: sprintf(buffer, "ashl%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x1b: sprintf(buffer, "rotl%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x1c: sprintf(buffer, "getps %s", reg[rdst]); break;
+ case 0x1d: sprintf(buffer, "putps %s", src2(op,0)); break;
+ case 0x1e: if (rdst && rsrc2_iszero)
+ {
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ sprintf(buffer, "jsr%s %s,%s", setcond[cond], reg[rdst], reg[rsrc1]);
+ }
+ else if (rdst)
+ {
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ sprintf(buffer, "jsr%s %s,%s[%s]", setcond[cond], reg[rdst], reg[rsrc1], src2(op,2));
+ }
+ else if (rsrc2_iszero)
+ {
+ if (rsrc1 == 28)
+ flags = DASMFLAG_STEP_OUT;
+ sprintf(buffer, "jmp%s %s", setcond[cond], reg[rsrc1]);
+ }
+ else
+ sprintf(buffer, "jmp%s %s[%s]", setcond[cond], reg[rsrc1], src2(op,2));
+ break;
+ case 0x1f: sprintf(buffer, "trap $1f"); flags = DASMFLAG_STEP_OVER; break;
+ }
+ return 4 | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/ccpu/ccpu.c b/src/emu/cpu/ccpu/ccpu.c
new file mode 100644
index 00000000000..dac8c199bf5
--- /dev/null
+++ b/src/emu/cpu/ccpu/ccpu.c
@@ -0,0 +1,809 @@
+/***************************************************************************
+
+ ccpu.c
+ Core implementation for the portable Cinematronics CPU emulator.
+
+ Written by Aaron Giles
+ Special thanks to Zonn Moore for his detailed documentation.
+
+***************************************************************************/
+
+#include "debugger.h"
+#include "ccpu.h"
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+typedef struct
+{
+ UINT16 PC;
+ UINT16 A;
+ UINT16 B;
+ UINT8 I;
+ UINT16 J;
+ UINT8 P;
+ UINT16 X;
+ UINT16 Y;
+ UINT16 T;
+ UINT16 *acc;
+
+ UINT16 a0flag, ncflag, cmpacc, cmpval;
+ UINT16 miflag, nextmiflag, nextnextmiflag;
+ UINT16 drflag;
+
+ UINT8 (*external_input)(void);
+ void (*vector_callback)(INT16 sx, INT16 sy, INT16 ex, INT16 ey, UINT8 shift);
+ UINT8 scrnum;
+} ccpuRegs;
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static ccpuRegs ccpu;
+static int ccpu_icount;
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define READOP(a) (cpu_readop(a))
+
+#define RDMEM(a) (data_read_word_16be((a) * 2) & 0xfff)
+#define WRMEM(a,v) (data_write_word_16be((a) * 2, (v)))
+
+#define READPORT(a) (io_read_byte_8(a))
+#define WRITEPORT(a,v) (io_write_byte_8((a), (v)))
+
+#define SET_A0() do { ccpu.a0flag = ccpu.A; } while (0)
+#define SET_CMP_VAL(x) do { ccpu.cmpacc = *ccpu.acc; ccpu.cmpval = (x) & 0xfff; } while (0)
+#define SET_NC(a) do { ccpu.ncflag = ~(a); } while (0)
+#define SET_MI(a) do { ccpu.nextnextmiflag = (a); } while (0)
+
+#define TEST_A0() (ccpu.a0flag & 1)
+#define TEST_NC() ((ccpu.ncflag >> 12) & 1)
+#define TEST_MI() ((ccpu.miflag >> 11) & 1)
+#define TEST_LT() (ccpu.cmpval < ccpu.cmpacc)
+#define TEST_EQ() (ccpu.cmpval == ccpu.cmpacc)
+#define TEST_DR() (ccpu.drflag != 0)
+
+#define NEXT_ACC_A() do { SET_MI(*ccpu.acc); ccpu.acc = &ccpu.A; } while (0)
+#define NEXT_ACC_B() do { SET_MI(*ccpu.acc); if (ccpu.acc == &ccpu.A) ccpu.acc = &ccpu.B; else ccpu.acc = &ccpu.A; } while (0)
+
+#define CYCLES(x) do { ccpu_icount -= (x); } while (0)
+
+#define STANDARD_ACC_OP(resexp,cmpval) \
+do { \
+ UINT16 result = resexp; \
+ SET_A0(); /* set the A0 bit based on the previous 'A' value */ \
+ SET_CMP_VAL(cmpval); /* set the compare values to the previous accumulator and the cmpval */ \
+ SET_NC(result); /* set the NC flag based on the unmasked result */ \
+ *ccpu.acc = result & 0xfff; /* store the low 12 bits of the new value */ \
+} while (0)
+
+
+
+/***************************************************************************
+ CONTEXT SWITCHING
+***************************************************************************/
+
+static void ccpu_get_context(void *dst)
+{
+ /* copy the context */
+ *(ccpuRegs *)dst = ccpu;
+}
+
+
+static void ccpu_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ ccpu = *(ccpuRegs *)src;
+ change_pc(ccpu.PC);
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+static UINT8 read_jmi(void)
+{
+ /* this routine is called when there is no external input */
+ /* and the JMI jumper is present */
+ return TEST_MI();
+}
+
+
+static void ccpu_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const struct CCPUConfig *config = _config;
+
+ /* copy input params */
+ ccpu.external_input = config->external_input ? config->external_input : read_jmi;
+ ccpu.vector_callback = config->vector_callback;
+
+ state_save_register_item("ccpu", clock, ccpu.PC);
+ state_save_register_item("ccpu", clock, ccpu.A);
+ state_save_register_item("ccpu", clock, ccpu.B);
+ state_save_register_item("ccpu", clock, ccpu.I);
+ state_save_register_item("ccpu", clock, ccpu.J);
+ state_save_register_item("ccpu", clock, ccpu.P);
+ state_save_register_item("ccpu", clock, ccpu.X);
+ state_save_register_item("ccpu", clock, ccpu.Y);
+ state_save_register_item("ccpu", clock, ccpu.T);
+ state_save_register_item("ccpu", clock, ccpu.scrnum);
+}
+
+
+static void ccpu_reset(void)
+{
+ /* zero registers */
+ ccpu.PC = 0;
+ ccpu.A = 0;
+ ccpu.B = 0;
+ ccpu.I = 0;
+ ccpu.J = 0;
+ ccpu.P = 0;
+ ccpu.X = 0;
+ ccpu.Y = 0;
+ ccpu.T = 0;
+ ccpu.acc = &ccpu.A;
+
+ /* zero flags */
+ ccpu.a0flag = 0;
+ ccpu.ncflag = 0;
+ ccpu.cmpacc = 0;
+ ccpu.cmpval = 1;
+ ccpu.miflag = ccpu.nextmiflag = ccpu.nextnextmiflag = 0;
+ ccpu.drflag = 0;
+}
+
+
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+static int ccpu_execute(int cycles)
+{
+ ccpu_icount = cycles;
+
+ while (ccpu_icount >= 0)
+ {
+ UINT16 tempval;
+ UINT8 opcode;
+
+ /* update the delayed MI flag */
+ ccpu.miflag = ccpu.nextmiflag;
+ ccpu.nextmiflag = ccpu.nextnextmiflag;
+
+ /* fetch the opcode */
+ CALL_MAME_DEBUG;
+ opcode = READOP(ccpu.PC++);
+
+ switch (opcode)
+ {
+ /* LDAI */
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ tempval = (opcode & 0x0f) << 8;
+ STANDARD_ACC_OP(tempval, tempval);
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* INP */
+ 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 (ccpu.acc == &ccpu.A)
+ tempval = READPORT(opcode & 0x0f) & 1;
+ else
+ tempval = READPORT(16 + (opcode & 0x07)) & 1;
+ STANDARD_ACC_OP(tempval, tempval);
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* A8I */
+ case 0x20:
+ tempval = READOP(ccpu.PC++);
+ STANDARD_ACC_OP(*ccpu.acc + tempval, tempval);
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* A4I */
+ case 0x21: case 0x22: case 0x23:
+ case 0x24: case 0x25: case 0x26: case 0x27:
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ tempval = opcode & 0x0f;
+ STANDARD_ACC_OP(*ccpu.acc + tempval, tempval);
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* S8I */
+ case 0x30:
+ tempval = READOP(ccpu.PC++);
+ STANDARD_ACC_OP(*ccpu.acc + (tempval ^ 0xfff) + 1, tempval);
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* S4I */
+ case 0x31: case 0x32: case 0x33:
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b:
+ case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ tempval = opcode & 0x0f;
+ STANDARD_ACC_OP(*ccpu.acc + (tempval ^ 0xfff) + 1, tempval);
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* LPAI */
+ case 0x40: case 0x41: case 0x42: case 0x43:
+ case 0x44: case 0x45: case 0x46: case 0x47:
+ case 0x48: case 0x49: case 0x4a: case 0x4b:
+ case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+ tempval = READOP(ccpu.PC++);
+ ccpu.J = (opcode & 0x0f) + (tempval & 0xf0) + ((tempval & 0x0f) << 8);
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* T4K */
+ case 0x50:
+ ccpu.PC = (ccpu.P << 12) + ccpu.J;
+ change_pc(ccpu.PC);
+ NEXT_ACC_B(); CYCLES(4);
+ break;
+
+ /* JMIB/JEHB */
+ case 0x51:
+ if ((*ccpu.external_input)()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_B(); CYCLES(2);
+ break;
+
+ /* JVNB */
+ case 0x52:
+ if (TEST_DR()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_B(); CYCLES(2);
+ break;
+
+ /* JLTB */
+ case 0x53:
+ if (TEST_LT()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_B(); CYCLES(2);
+ break;
+
+ /* JEQB */
+ case 0x54:
+ if (TEST_EQ()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_B(); CYCLES(2);
+ break;
+
+ /* JCZB */
+ case 0x55:
+ if (TEST_NC()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_B(); CYCLES(2);
+ break;
+
+ /* JOSB */
+ case 0x56:
+ if (TEST_A0()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_B(); CYCLES(2);
+ break;
+
+ /* SSA */
+ case 0x57:
+ NEXT_ACC_B(); CYCLES(2);
+ break;
+
+ /* JMP */
+ case 0x58:
+ ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J;
+ NEXT_ACC_A(); CYCLES(4);
+ break;
+
+ /* JMI/JEH */
+ case 0x59:
+ if ((*ccpu.external_input)()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* JVN */
+ case 0x5a:
+ if (TEST_DR()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* JLT */
+ case 0x5b:
+ if (TEST_LT()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* JEQ */
+ case 0x5c:
+ if (TEST_EQ()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* JCZ */
+ case 0x5d:
+ if (TEST_NC()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* JOS */
+ case 0x5e:
+ if (TEST_A0()) { ccpu.PC = ((ccpu.PC - 1) & 0xf000) + ccpu.J; CYCLES(2); }
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* NOP */
+ case 0x5f:
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* ADD */
+ case 0x60: case 0x61: case 0x62: case 0x63:
+ case 0x64: case 0x65: case 0x66: case 0x67:
+ case 0x68: case 0x69: case 0x6a: case 0x6b:
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+ ccpu.I = (ccpu.P << 4) + (opcode & 0x0f);
+ tempval = RDMEM(ccpu.I);
+ STANDARD_ACC_OP(*ccpu.acc + tempval, tempval);
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* SUB */
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b:
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+ ccpu.I = (ccpu.P << 4) + (opcode & 0x0f);
+ tempval = RDMEM(ccpu.I);
+ STANDARD_ACC_OP(*ccpu.acc + (tempval ^ 0xfff) + 1, tempval);
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* SETP */
+ case 0x80: case 0x81: case 0x82: case 0x83:
+ case 0x84: case 0x85: case 0x86: case 0x87:
+ case 0x88: case 0x89: case 0x8a: case 0x8b:
+ case 0x8c: case 0x8d: case 0x8e: case 0x8f:
+ ccpu.P = opcode & 0x0f;
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* OUT */
+ case 0x90: case 0x91: case 0x92: case 0x93:
+ case 0x94: case 0x95: case 0x96: case 0x97:
+ case 0x98: case 0x99: case 0x9a: case 0x9b:
+ case 0x9c: case 0x9d: case 0x9e: case 0x9f:
+ if (ccpu.acc == &ccpu.A)
+ WRITEPORT(opcode & 0x07, ~*ccpu.acc & 1);
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* LDA */
+ case 0xa0: case 0xa1: case 0xa2: case 0xa3:
+ case 0xa4: case 0xa5: case 0xa6: case 0xa7:
+ case 0xa8: case 0xa9: case 0xaa: case 0xab:
+ case 0xac: case 0xad: case 0xae: case 0xaf:
+ ccpu.I = (ccpu.P << 4) + (opcode & 0x0f);
+ tempval = RDMEM(ccpu.I);
+ STANDARD_ACC_OP(tempval, tempval);
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* TST */
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3:
+ case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ case 0xb8: case 0xb9: case 0xba: case 0xbb:
+ case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ ccpu.I = (ccpu.P << 4) + (opcode & 0x0f);
+ tempval = RDMEM(ccpu.I);
+ {
+ UINT16 result = *ccpu.acc + (tempval ^ 0xfff) + 1;
+ SET_A0();
+ SET_CMP_VAL(tempval);
+ SET_NC(result);
+ SET_MI(result);
+ }
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* WS */
+ case 0xc0: case 0xc1: case 0xc2: case 0xc3:
+ case 0xc4: case 0xc5: case 0xc6: case 0xc7:
+ case 0xc8: case 0xc9: case 0xca: case 0xcb:
+ case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ ccpu.I = (ccpu.P << 4) + (opcode & 0x0f);
+ ccpu.I = RDMEM(ccpu.I) & 0xff;
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* STA */
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3:
+ case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+ case 0xd8: case 0xd9: case 0xda: case 0xdb:
+ case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ ccpu.I = (ccpu.P << 4) + (opcode & 0x0f);
+ WRMEM(ccpu.I, *ccpu.acc);
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* DV */
+ case 0xe0:
+ {
+ INT16 stopX = (INT16)(ccpu.A << 4) >> 4;
+ INT16 stopY = (INT16)(ccpu.B << 4) >> 4;
+
+ stopX = ((INT16)(stopX - ccpu.X) >> ccpu.T) + ccpu.X;
+ stopY = ((INT16)(stopY - ccpu.Y) >> ccpu.T) + ccpu.Y;
+
+ (*ccpu.vector_callback)(ccpu.X, ccpu.Y, stopX, stopY, ccpu.T);
+
+ /* hack to make QB3 display semi-correctly during explosions */
+ ccpu.A = ccpu.X & 0xfff;
+ ccpu.B = ccpu.Y & 0xfff;
+ }
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* LPAP */
+ case 0xe1:
+ ccpu.J = RDMEM(ccpu.I);
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* WSP */
+ case 0xf1:
+ ccpu.I = RDMEM(ccpu.I) & 0xff;
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* LKP */
+ case 0xe2:
+ case 0xf2:
+ tempval = READOP(((ccpu.PC - 1) & 0xf000) + *ccpu.acc);
+ STANDARD_ACC_OP(tempval, tempval);
+ NEXT_ACC_A(); CYCLES(7);
+ ccpu.PC++;
+ break;
+
+ /* MUL */
+ case 0xe3:
+ case 0xf3:
+ tempval = RDMEM(ccpu.I);
+ SET_A0();
+ ccpu.cmpval = tempval & 0xfff;
+ if (ccpu.acc == &ccpu.A)
+ {
+ if (ccpu.A & 1)
+ {
+ UINT16 result;
+ ccpu.cmpacc = ccpu.B;
+ ccpu.A = (ccpu.A >> 1) | ((ccpu.B << 11) & 0x800);
+ ccpu.B = ((INT16)(ccpu.B << 4) >> 5) & 0xfff;
+ result = ccpu.B + tempval;
+ SET_NC(result);
+ SET_MI(result);
+ ccpu.B = result & 0xfff;
+ }
+ else
+ {
+ UINT16 result;
+ ccpu.cmpacc = ccpu.A;
+ result = ccpu.A + tempval;
+ ccpu.A = (ccpu.A >> 1) | ((ccpu.B << 11) & 0x800);
+ ccpu.B = ((INT16)(ccpu.B << 4) >> 5) & 0xfff;
+ SET_NC(result);
+ SET_MI(result);
+ }
+ }
+ else
+ {
+ UINT16 result;
+ ccpu.cmpacc = ccpu.B;
+ ccpu.B = ((INT16)(ccpu.B << 4) >> 5) & 0xfff;
+ result = ccpu.B + tempval;
+ SET_NC(result);
+ SET_MI(result);
+ if (ccpu.A & 1)
+ ccpu.B = result & 0xfff;
+ }
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* NV */
+ case 0xe4:
+ case 0xf4:
+ ccpu.T = 0;
+ while (((ccpu.A & 0xa00) == 0x000 || (ccpu.A & 0xa00) == 0xa00) &&
+ ((ccpu.B & 0xa00) == 0x000 || (ccpu.B & 0xa00) == 0xa00) &&
+ ccpu.T < 16)
+ {
+ ccpu.A = (ccpu.A << 1) & 0xfff;
+ ccpu.B = (ccpu.B << 1) & 0xfff;
+ ccpu.T++;
+ CYCLES(1);
+ }
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* FRM */
+ case 0xe5:
+ case 0xf5:
+/* FIXME: once vector game video system configuration is fixed,
+ remove section in brackets and uncomment line below.
+ Speed Freak should run nice and smooth, with no flickering. */
+{
+ attotime scantime, abstime;
+ extern emu_timer *refresh_timer;
+ scantime = timer_starttime(refresh_timer);
+ abstime = timer_get_time();
+ while (attotime_compare(abstime, scantime) >= 0)
+ scantime = attotime_add(scantime, video_screen_get_frame_period(ccpu.scrnum));
+ cpu_spinuntil_time(attotime_sub(scantime, abstime));
+}
+/* cpu_spinuntil_time(video_screen_get_time_until_pos(ccpu.scrnum, Machine->screen[ccpu.scrnum].visarea.max_y + 1, 0)); */
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* STAP */
+ case 0xe6:
+ case 0xf6:
+ WRMEM(ccpu.I, *ccpu.acc);
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* CST */
+ case 0xf7:
+ watchdog_reset();
+ /* ADDP */
+ case 0xe7:
+ tempval = RDMEM(ccpu.I);
+ STANDARD_ACC_OP(*ccpu.acc + tempval, tempval);
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* SUBP */
+ case 0xe8:
+ case 0xf8:
+ tempval = RDMEM(ccpu.I);
+ STANDARD_ACC_OP(*ccpu.acc + (tempval ^ 0xfff) + 1, tempval);
+ NEXT_ACC_A(); CYCLES(3);
+ break;
+
+ /* ANDP */
+ case 0xe9:
+ case 0xf9:
+ tempval = RDMEM(ccpu.I);
+ STANDARD_ACC_OP(*ccpu.acc & tempval, tempval);
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* LDAP */
+ case 0xea:
+ case 0xfa:
+ tempval = RDMEM(ccpu.I);
+ STANDARD_ACC_OP(tempval, tempval);
+ NEXT_ACC_A(); CYCLES(2);
+ break;
+
+ /* SHR */
+ case 0xeb:
+ case 0xfb:
+ tempval = ((ccpu.acc == &ccpu.A) ? (ccpu.A >> 1) : ((INT16)(ccpu.B << 4) >> 5)) & 0xfff;
+ tempval |= (*ccpu.acc + (0xb0b | (opcode & 0xf0))) & 0x1000;
+ STANDARD_ACC_OP(tempval, 0xb0b | (opcode & 0xf0));
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* SHL */
+ case 0xec:
+ case 0xfc:
+ tempval = (*ccpu.acc << 1) & 0xfff;
+ tempval |= (*ccpu.acc + (0xc0c | (opcode & 0xf0))) & 0x1000;
+ STANDARD_ACC_OP(tempval, 0xc0c | (opcode & 0xf0));
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* ASR */
+ case 0xed:
+ case 0xfd:
+ tempval = ((INT16)(*ccpu.acc << 4) >> 5) & 0xfff;
+ STANDARD_ACC_OP(tempval, 0xd0d | (opcode & 0xf0));
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* SHRB */
+ case 0xee:
+ case 0xfe:
+ if (ccpu.acc == &ccpu.A)
+ {
+ tempval = (ccpu.A >> 1) | ((ccpu.B << 11) & 0x800);
+ ccpu.B = ((INT16)(ccpu.B << 4) >> 5) & 0xfff;
+ }
+ else
+ tempval = ((INT16)(ccpu.B << 4) >> 5) & 0xfff;
+ tempval |= (*ccpu.acc + (0xe0e | (opcode & 0xf0))) & 0x1000;
+ STANDARD_ACC_OP(tempval, 0xe0e | (opcode & 0xf0));
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* SHLB */
+ case 0xef:
+ case 0xff:
+ if (ccpu.acc == &ccpu.A)
+ {
+ tempval = (ccpu.A << 1) & 0xfff;
+ ccpu.B = (ccpu.B << 1) & 0xfff;
+ }
+ else
+ tempval = (ccpu.B << 1) & 0xfff;
+ tempval |= (*ccpu.acc + (0xf0f | (opcode & 0xf0))) & 0x1000;
+ STANDARD_ACC_OP(tempval, 0xf0f | (opcode & 0xf0));
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+
+ /* IV */
+ case 0xf0:
+ ccpu.X = (INT16)(ccpu.A << 4) >> 4;
+ ccpu.Y = (INT16)(ccpu.B << 4) >> 4;
+ NEXT_ACC_A(); CYCLES(1);
+ break;
+ }
+ }
+
+ return cycles - ccpu_icount;
+}
+
+
+
+/***************************************************************************
+ INFORMATION SETTERS
+***************************************************************************/
+
+static void ccpu_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + CCPU_PC: ccpu.PC = info->i; break;
+ case CPUINFO_INT_REGISTER + CCPU_FLAGS:
+ ccpu.a0flag = (info->i & 0x01) ? 1 : 0;
+ ccpu.ncflag = (info->i & 0x02) ? 0x0000 : 0x1000;
+ ccpu.cmpacc = 1;
+ ccpu.cmpval = (info->i & 0x04) ? 0 : (info->i & 0x08) ? 1 : 2;
+ ccpu.miflag = (info->i & 0x10) ? 1 : 0;
+ ccpu.drflag = (info->i & 0x20) ? 1 : 0;
+ break;
+ case CPUINFO_INT_REGISTER + CCPU_A: ccpu.A = info->i & 0xfff; break;
+ case CPUINFO_INT_REGISTER + CCPU_B: ccpu.B = info->i & 0xfff; break;
+ case CPUINFO_INT_REGISTER + CCPU_I: ccpu.I = info->i & 0xff; break;
+ case CPUINFO_INT_REGISTER + CCPU_J: ccpu.J = info->i & 0xfff; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + CCPU_P: ccpu.P = info->i & 0x0f; break;
+ case CPUINFO_INT_REGISTER + CCPU_X: ccpu.X = info->i & 0xfff; break;
+ case CPUINFO_INT_REGISTER + CCPU_Y: ccpu.Y = info->i & 0xfff; break;
+ case CPUINFO_INT_REGISTER + CCPU_T: ccpu.T = info->i & 0xfff; break;
+ }
+}
+
+
+
+/***************************************************************************
+ INFORMATION GETTERS
+***************************************************************************/
+
+void ccpu_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ccpuRegs); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 15; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 5; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + CCPU_PC: info->i = ccpu.PC; break;
+ case CPUINFO_INT_REGISTER + CCPU_FLAGS: info->i = 0;
+ if (TEST_A0()) info->i |= 0x01;
+ if (TEST_NC()) info->i |= 0x02;
+ if (TEST_LT()) info->i |= 0x04;
+ if (TEST_EQ()) info->i |= 0x08;
+ if ((*ccpu.external_input)()) info->i |= 0x10;
+ if (TEST_DR()) info->i |= 0x20;
+ break;
+ case CPUINFO_INT_REGISTER + CCPU_A: info->i = ccpu.A; break;
+ case CPUINFO_INT_REGISTER + CCPU_B: info->i = ccpu.B; break;
+ case CPUINFO_INT_REGISTER + CCPU_I: info->i = ccpu.I; break;
+ case CPUINFO_INT_REGISTER + CCPU_J: info->i = ccpu.J; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + CCPU_P: info->i = ccpu.P; break;
+ case CPUINFO_INT_REGISTER + CCPU_X: info->i = ccpu.X; break;
+ case CPUINFO_INT_REGISTER + CCPU_Y: info->i = ccpu.Y; break;
+ case CPUINFO_INT_REGISTER + CCPU_T: info->i = ccpu.T; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ccpu_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ccpu_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ccpu_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = ccpu_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ccpu_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = NULL; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ccpu_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ccpu_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ccpu_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "CCPU"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Cinematronics CPU"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 2004 Aaron Giles & Zonn Moore"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c",
+ TEST_A0() ? '0' : 'o',
+ TEST_NC() ? 'N' : 'n',
+ TEST_LT() ? 'L' : 'l',
+ TEST_EQ() ? 'E' : 'e',
+ (*ccpu.external_input)() ? 'M' : 'm',
+ TEST_DR() ? 'D' : 'd');
+ break;
+
+ case CPUINFO_STR_REGISTER + CCPU_FLAGS:
+ sprintf(info->s, "FL:%c%c%c%c%c%c",
+ TEST_A0() ? '0' : 'o',
+ TEST_NC() ? 'N' : 'n',
+ TEST_LT() ? 'L' : 'l',
+ TEST_EQ() ? 'E' : 'e',
+ (*ccpu.external_input)() ? 'M' : 'm',
+ TEST_DR() ? 'D' : 'd');
+ break;
+
+ case CPUINFO_STR_REGISTER + CCPU_PC: sprintf(info->s, "PC:%04X", ccpu.PC); break;
+ case CPUINFO_STR_REGISTER + CCPU_A: sprintf(info->s, "A:%03X", ccpu.A); break;
+ case CPUINFO_STR_REGISTER + CCPU_B: sprintf(info->s, "B:%03X", ccpu.B); break;
+ case CPUINFO_STR_REGISTER + CCPU_I: sprintf(info->s, "I:%03X", ccpu.I); break;
+ case CPUINFO_STR_REGISTER + CCPU_J: sprintf(info->s, "J:%03X", ccpu.J); break;
+ case CPUINFO_STR_REGISTER + CCPU_P: sprintf(info->s, "P:%X", ccpu.P); break;
+ case CPUINFO_STR_REGISTER + CCPU_X: sprintf(info->s, "X:%03X", ccpu.X); break;
+ case CPUINFO_STR_REGISTER + CCPU_Y: sprintf(info->s, "Y:%03X", ccpu.Y); break;
+ case CPUINFO_STR_REGISTER + CCPU_T: sprintf(info->s, "T:%03X", ccpu.T); break;
+ }
+}
diff --git a/src/emu/cpu/ccpu/ccpu.h b/src/emu/cpu/ccpu/ccpu.h
new file mode 100644
index 00000000000..6b53f3e7545
--- /dev/null
+++ b/src/emu/cpu/ccpu/ccpu.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+
+ ccpu.h
+ Core implementation for the portable Cinematronics CPU emulator.
+
+ Written by Aaron Giles
+ Special thanks to Zonn Moore for his detailed documentation.
+
+***************************************************************************/
+
+#ifndef _CCPU_H_
+#define _CCPU_H_
+
+#include "cpuintrf.h"
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ CCPU_PC=1,
+ CCPU_FLAGS,
+ CCPU_A,
+ CCPU_B,
+ CCPU_I,
+ CCPU_J,
+ CCPU_P,
+ CCPU_X,
+ CCPU_Y,
+ CCPU_T
+};
+
+
+/***************************************************************************
+ CONFIG STRUCTURE
+***************************************************************************/
+
+struct CCPUConfig
+{
+ UINT8 (*external_input)(void); /* if NULL, assume JMI jumper is present */
+ void (*vector_callback)(INT16 sx, INT16 sy, INT16 ex, INT16 ey, UINT8 shift);
+ UINT8 scrnum;
+};
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+void ccpu_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+offs_t ccpu_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif
diff --git a/src/emu/cpu/ccpu/ccpudasm.c b/src/emu/cpu/ccpu/ccpudasm.c
new file mode 100644
index 00000000000..c51f2c7ca84
--- /dev/null
+++ b/src/emu/cpu/ccpu/ccpudasm.c
@@ -0,0 +1,327 @@
+/***************************************************************************
+
+ ccpudasm.c
+ Core implementation for the portable Cinematronics CPU disassembler.
+
+ Written by Aaron Giles
+ Special thanks to Zonn Moore for his detailed documentation.
+
+***************************************************************************/
+
+#include "ccpu.h"
+
+
+offs_t ccpu_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ unsigned startpc = pc;
+ UINT8 opcode = oprom[pc++ - startpc];
+ UINT8 tempval;
+
+ switch (opcode)
+ {
+ /* LDAI */
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(buffer, "LDAI $%X", opcode & 0x0f);
+ break;
+
+ /* INP */
+ 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:
+ sprintf(buffer, "INP $%X", opcode & 0x0f);
+ break;
+
+ /* A8I */
+ case 0x20:
+ sprintf(buffer, "A8I $%X", oprom[pc++ - startpc]);
+ break;
+
+ /* A4I */
+ case 0x21: case 0x22: case 0x23:
+ case 0x24: case 0x25: case 0x26: case 0x27:
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(buffer, "A4I $%X", opcode & 0x0f);
+ break;
+
+ /* S8I */
+ case 0x30:
+ sprintf(buffer, "S8I $%X", oprom[pc++ - startpc]);
+ break;
+
+ /* S4I */
+ case 0x31: case 0x32: case 0x33:
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b:
+ case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ sprintf(buffer, "S4I $%X", opcode & 0x0f);
+ break;
+
+ /* LPAI */
+ case 0x40: case 0x41: case 0x42: case 0x43:
+ case 0x44: case 0x45: case 0x46: case 0x47:
+ case 0x48: case 0x49: case 0x4a: case 0x4b:
+ case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+ tempval = oprom[pc++ - startpc];
+ sprintf(buffer, "LPAI $%03X", (opcode & 0x0f) + (tempval & 0xf0) + ((tempval & 0x0f) << 8));
+ break;
+
+ /* T4K */
+ case 0x50:
+ sprintf(buffer, "T4K");
+ break;
+
+ /* JMIB/JEHB */
+ case 0x51:
+ sprintf(buffer, "JMIB/JEHB");
+ break;
+
+ /* JVNB */
+ case 0x52:
+ sprintf(buffer, "JVNB");
+ break;
+
+ /* JLTB */
+ case 0x53:
+ sprintf(buffer, "JLTB");
+ break;
+
+ /* JEQB */
+ case 0x54:
+ sprintf(buffer, "JEQB");
+ break;
+
+ /* JCZB */
+ case 0x55:
+ sprintf(buffer, "JCZB");
+ break;
+
+ /* JOSB */
+ case 0x56:
+ sprintf(buffer, "JOSB");
+ break;
+
+ /* SSA */
+ case 0x57:
+ sprintf(buffer, "SSA");
+ break;
+
+ /* JMP */
+ case 0x58:
+ sprintf(buffer, "JMP");
+ break;
+
+ /* JMI/JEH */
+ case 0x59:
+ sprintf(buffer, "JMI/JEH");
+ break;
+
+ /* JVN */
+ case 0x5a:
+ sprintf(buffer, "JVN");
+ break;
+
+ /* JLT */
+ case 0x5b:
+ sprintf(buffer, "JLT");
+ break;
+
+ /* JEQ */
+ case 0x5c:
+ sprintf(buffer, "JEQ");
+ break;
+
+ /* JCZ */
+ case 0x5d:
+ sprintf(buffer, "JCZ");
+ break;
+
+ /* JOS */
+ case 0x5e:
+ sprintf(buffer, "JOS");
+ break;
+
+ /* NOP */
+ case 0x5f:
+ sprintf(buffer, "NOP");
+ break;
+
+ /* ADD */
+ case 0x60: case 0x61: case 0x62: case 0x63:
+ case 0x64: case 0x65: case 0x66: case 0x67:
+ case 0x68: case 0x69: case 0x6a: case 0x6b:
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+ sprintf(buffer, "ADD $%X", opcode & 0x0f);
+ break;
+
+ /* SUB n */
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b:
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+ sprintf(buffer, "SUB $%X", opcode & 0x0f);
+ break;
+
+ /* SETP n */
+ case 0x80: case 0x81: case 0x82: case 0x83:
+ case 0x84: case 0x85: case 0x86: case 0x87:
+ case 0x88: case 0x89: case 0x8a: case 0x8b:
+ case 0x8c: case 0x8d: case 0x8e: case 0x8f:
+ sprintf(buffer, "SETP $%X", opcode & 0x0f);
+ break;
+
+ /* OUT */
+ case 0x90: case 0x91: case 0x92: case 0x93:
+ case 0x94: case 0x95: case 0x96: case 0x97:
+ case 0x98: case 0x99: case 0x9a: case 0x9b:
+ case 0x9c: case 0x9d: case 0x9e: case 0x9f:
+ sprintf(buffer, "OUT $%X", opcode & 0x0f);
+ break;
+
+ /* LDA */
+ case 0xa0: case 0xa1: case 0xa2: case 0xa3:
+ case 0xa4: case 0xa5: case 0xa6: case 0xa7:
+ case 0xa8: case 0xa9: case 0xaa: case 0xab:
+ case 0xac: case 0xad: case 0xae: case 0xaf:
+ sprintf(buffer, "LDA $%X", opcode & 0x0f);
+ break;
+
+ /* CMP */
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3:
+ case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ case 0xb8: case 0xb9: case 0xba: case 0xbb:
+ case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ sprintf(buffer, "TST $%X", opcode & 0x0f);
+ break;
+
+ /* WS */
+ case 0xc0: case 0xc1: case 0xc2: case 0xc3:
+ case 0xc4: case 0xc5: case 0xc6: case 0xc7:
+ case 0xc8: case 0xc9: case 0xca: case 0xcb:
+ case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ sprintf(buffer, "WS $%X", opcode & 0x0f);
+ break;
+
+ /* STA n */
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3:
+ case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+ case 0xd8: case 0xd9: case 0xda: case 0xdb:
+ case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ sprintf(buffer, "STA $%X", opcode & 0x0f);
+ break;
+
+ /* DV */
+ case 0xe0:
+ sprintf(buffer, "DV");
+ break;
+
+ /* LPAP */
+ case 0xe1:
+ sprintf(buffer, "LPAP");
+ break;
+
+ /* WSP */
+ case 0xf1:
+ sprintf(buffer, "WSP");
+ break;
+
+ /* LKP */
+ case 0xe2:
+ case 0xf2:
+ sprintf(buffer, "LKP");
+ break;
+
+ /* MUL */
+ case 0xe3:
+ case 0xf3:
+ sprintf(buffer, "MUL");
+ break;
+
+ /* NV */
+ case 0xe4:
+ case 0xf4:
+ sprintf(buffer, "NV");
+ break;
+
+ /* FRM */
+ case 0xe5:
+ case 0xf5:
+ sprintf(buffer, "FRM");
+ break;
+
+ /* STAP */
+ case 0xe6:
+ case 0xf6:
+ sprintf(buffer, "STAP");
+ break;
+
+ /* CST */
+ case 0xf7:
+ sprintf(buffer, "CST");
+ break;
+
+ /* ADDP */
+ case 0xe7:
+ sprintf(buffer, "ADDP");
+ break;
+
+ /* SUBP */
+ case 0xe8:
+ case 0xf8:
+ sprintf(buffer, "SUBP");
+ break;
+
+ /* ANDP */
+ case 0xe9:
+ case 0xf9:
+ sprintf(buffer, "ANDP");
+ break;
+
+ /* LDAP */
+ case 0xea:
+ case 0xfa:
+ sprintf(buffer, "LDAP");
+ break;
+
+ /* SHR */
+ case 0xeb:
+ case 0xfb:
+ sprintf(buffer, "SHR");
+ break;
+
+ /* SHL */
+ case 0xec:
+ case 0xfc:
+ sprintf(buffer, "SHL");
+ break;
+
+ /* ASR */
+ case 0xed:
+ case 0xfd:
+ sprintf(buffer, "ASR");
+ break;
+
+ /* SHRB */
+ case 0xee:
+ case 0xfe:
+ sprintf(buffer, "SHRB");
+ break;
+
+ /* SHLB */
+ case 0xef:
+ case 0xff:
+ sprintf(buffer, "SHLB");
+ break;
+
+ /* IV */
+ case 0xf0:
+ sprintf(buffer, "IV");
+ break;
+ }
+
+ return (pc - startpc) | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/cdp1802/1802dasm.c b/src/emu/cpu/cdp1802/1802dasm.c
new file mode 100644
index 00000000000..b8c21f6e276
--- /dev/null
+++ b/src/emu/cpu/cdp1802/1802dasm.c
@@ -0,0 +1,173 @@
+/*****************************************************************************
+ *
+ * disasm.c
+ * portable cosmac cdp1802 emulator interface
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+
+#include "cdp1802.h"
+
+typedef enum {
+ Ill,
+ Imm,
+ Imp,
+ Imp2, // lownibble contains register number
+ Imp3, // bit 0,1,2 1..7 contains n0,n1,n2 level
+ Low, // only low byte of address specified
+ Abs
+} Adr;
+
+static const struct { const char *mnemonic; Adr adr; } table[]={
+ { "IDL", Imp }, { "LDN", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "INC", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "DEC", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+
+ { "BR", Low }, { "BQ", Low }, { "BZ", Low }, { "BDF", Low },
+ { "B1", Low }, { "B2", Low }, { "B3", Low }, { "B4", Low },
+ { "SKP", Low }, { "BNQ", Low }, { "BNZ", Low }, { "BNF", Low },
+ { "BN1", Low }, { "BN2", Low }, { "BN3", Low }, { "BN4", Low },
+
+ { "LDA", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "STR", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "IRX", Imp } ,{ "OUT", Imp3},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 } ,{ "INP", Imp3},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "RET", Imp }, { "DIS", Imp }, { "LDXA", Imp }, { "STXD", Imp },
+ { "ADC", Imp }, { "SDB", Imp }, { "SHRC", Imp }, { "SMB", Imp },
+ { "SAV", Imp }, { "MARK", Imp }, { "REQ", Imp }, { "SEQ", Imp },
+ { "ADCI", Imm }, { "SDBI", Imm }, { "SHLC", Imp }, { "SMBI", Imm },
+
+
+ { "GLO", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "GHI", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "PLO", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "PHI", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "LBR", Abs }, { "LBQ", Abs }, { "LBZ", Abs }, { "LBDF", Abs },
+ { "NOP", Imp }, { "LSNQ", Imp }, { "LSNZ", Imp }, { "LSNF", Imp },
+ { "LSKP", Imp }, { "LBNQ", Abs }, { "LBNZ", Abs }, { "LBNF", Abs },
+ { "LSIE", Imp }, { "LSQ", Imp }, { "LSZ", Imp }, { "LSDF", Imp },
+
+ { "SEP", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "SEX", Imp2},{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { "LDX", Imp }, { "OR", Imp }, { "AND", Imp }, { "XOR", Imp },
+ { "ADD", Imp }, { "SD", Imp }, { "SHR", Imp }, { "SM", Imp },
+ { "LDI", Imm }, { "ORI", Imm }, { "ANI", Imm }, { "XRI", Imm },
+ { "ADI", Imm }, { "SDI", Imm }, { "SHL", Imp }, { "SMI", Imm },
+
+};
+
+offs_t cdp1802_dasm(char *dst, offs_t oldpc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ int pc;
+ int oper;
+ UINT16 absolut;
+ oldpc&=0xffff;
+ pc=oldpc;
+ oper=oprom[pc++ - oldpc];
+
+ switch(oper&0xf0) {
+ case 0:
+ if (oper==0) {
+ sprintf(dst,"%-5s",table[oper].mnemonic);
+ } else {
+ sprintf(dst,"%-5sR%.1x",table[(oper&0xf0)|1].mnemonic, oper&0x0f);
+ }
+ break;
+ case 0xd0:
+ flags = DASMFLAG_STEP_OVER;
+ /* fall through */
+ case 0x10:
+ case 0x20:
+ case 0x40:
+ case 0x50:
+ case 0x80:
+ case 0x90:
+ case 0xa0:
+ case 0xb0:
+ case 0xe0:
+ sprintf(dst,"%-5sR%.1x",table[oper&0xf0].mnemonic, oper&0x0f);
+ break;
+ default:
+ switch(oper&0xf8) {
+ case 0x60:
+ if (oper==0x60) {
+ sprintf(dst,"%-5s",table[oper].mnemonic);
+ } else {
+ sprintf(dst,"%-5s%d",table[(oper&0xf8)|1].mnemonic, oper&0x7);
+ }
+ break;
+ case 0x68:
+ sprintf(dst,"%-5s%d",table[(oper&0xf8)|1].mnemonic, oper&0x7);
+ break;
+ default:
+ switch (table[oper].adr) {
+ case Imp:
+ sprintf(dst,"%-5s",table[oper].mnemonic);
+ if (oper == 0x70 || oper == 0x71)
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ case Imm:
+ sprintf(dst,"%-5s#%.2x",table[oper].mnemonic,oprom[pc++ - oldpc]);
+ break;
+ case Low:
+ absolut=oprom[pc++ - oldpc];
+ absolut|=pc&0xff00;
+ sprintf(dst,"%-5s%.4x",table[oper].mnemonic,absolut);
+ break;
+ case Abs:
+ absolut=oprom[pc++ - oldpc]<<8;
+ absolut|=oprom[pc++ - oldpc];
+ sprintf(dst,"%-5s%.4x",table[oper].mnemonic,absolut);
+ break;
+ default:
+ sprintf(dst,"%-5s%.2x","ill",oper);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return (pc-oldpc) | flags | DASMFLAG_SUPPORTED;
+}
+
diff --git a/src/emu/cpu/cdp1802/cdp1802.c b/src/emu/cpu/cdp1802/cdp1802.c
new file mode 100644
index 00000000000..d474b34e6a5
--- /dev/null
+++ b/src/emu/cpu/cdp1802/cdp1802.c
@@ -0,0 +1,1049 @@
+#include "driver.h"
+#include "state.h"
+#include "debugger.h"
+#include "cdp1802.h"
+
+typedef struct
+{
+ CDP1802_CONFIG *config;
+
+ UINT8 p, x, d, b, t;
+ UINT16 r[16];
+ UINT8 df, ie, q, n, i;
+
+ int state;
+ int prevmode, mode;
+ int irq, dmain, dmaout;
+ int ef;
+
+} CDP1802_Regs;
+
+#define M program_read_byte
+#define MW program_write_byte
+
+#define P cdp1802.p
+#define X cdp1802.x
+#define D cdp1802.d
+#define B cdp1802.b
+#define T cdp1802.t
+#define R cdp1802.r
+#define DF cdp1802.df
+#define IE cdp1802.ie
+#define Q cdp1802.q
+#define N cdp1802.n
+#define I cdp1802.i
+
+static int cdp1802_ICount;
+
+static CDP1802_Regs cdp1802;
+
+static void cdp1802_get_context (void *dst)
+{
+ *(CDP1802_Regs *)dst = cdp1802;
+}
+
+static void cdp1802_set_context (void *src)
+{
+ cdp1802 = *(CDP1802_Regs *)src;
+}
+
+static void cdp1802_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ cdp1802.config = (CDP1802_CONFIG *) config;
+
+ cdp1802.mode = CDP1802_MODE_RESET;
+ cdp1802.prevmode = cdp1802.mode;
+ cdp1802.irq = CLEAR_LINE;
+ cdp1802.dmain = CLEAR_LINE;
+ cdp1802.dmaout = CLEAR_LINE;
+
+ state_save_register_item("cdp1802", index, cdp1802.p);
+ state_save_register_item("cdp1802", index, cdp1802.x);
+ state_save_register_item("cdp1802", index, cdp1802.d);
+ state_save_register_item("cdp1802", index, cdp1802.b);
+ state_save_register_item("cdp1802", index, cdp1802.t);
+ state_save_register_item_array("cdp1802", index, cdp1802.r);
+ state_save_register_item("cdp1802", index, cdp1802.df);
+ state_save_register_item("cdp1802", index, cdp1802.ie);
+ state_save_register_item("cdp1802", index, cdp1802.q);
+ state_save_register_item("cdp1802", index, cdp1802.n);
+ state_save_register_item("cdp1802", index, cdp1802.i);
+ state_save_register_item("cdp1802", index, cdp1802.state);
+ state_save_register_item("cdp1802", index, cdp1802.prevmode);
+ state_save_register_item("cdp1802", index, cdp1802.mode);
+ state_save_register_item("cdp1802", index, cdp1802.irq);
+ state_save_register_item("cdp1802", index, cdp1802.dmain);
+ state_save_register_item("cdp1802", index, cdp1802.dmaout);
+ state_save_register_item("cdp1802", index, cdp1802.ef);
+}
+
+INLINE void cdp1802_add(int left, int right)
+{
+ int result = left + right;
+ D = result & 0xff;
+ DF = (result & 0x100) >> 8;
+}
+
+INLINE void cdp1802_add_carry(int left, int right)
+{
+ int result = left + right + DF;
+ D = result & 0xff;
+ DF = (result & 0x100) >> 8;
+}
+
+INLINE void cdp1802_sub(int left, int right)
+{
+ int result = left + (~right & 0xff) + 1;
+
+ D = result & 0xff;
+ DF = (result & 0x100) >> 8;
+}
+
+INLINE void cdp1802_sub_carry(int left, int right)
+{
+ int result = left + (~right & 0xff) + DF;
+
+ D = result & 0xff;
+ DF = (result & 0x100) >> 8;
+}
+
+INLINE void cdp1802_short_branch(int taken)
+{
+ if (taken)
+ {
+ R[P] = (R[P] & 0xff00) | cpu_readop(R[P]);
+ }
+ else
+ {
+ R[P] = R[P] + 1;
+ }
+}
+
+INLINE void cdp1802_long_branch(int taken)
+{
+ if (taken)
+ {
+ // S1#1
+
+ B = cpu_readop(R[P]);
+ R[P] = R[P] + 1;
+
+ // S1#2
+
+ R[P] = (B << 8) | cpu_readop(R[P]);
+ }
+ else
+ {
+ // S1#1
+
+ R[P] = R[P] + 1;
+
+ // S1#2
+
+ R[P] = R[P] + 1;
+ }
+}
+
+INLINE void cdp1802_long_skip(int taken)
+{
+ if (taken)
+ {
+ // S1#1
+
+ R[P] = R[P] + 1;
+
+ // S1#2
+
+ R[P] = R[P] + 1;
+ }
+}
+
+static void cdp1802_sample_ef(void)
+{
+ if (cdp1802.config->ef_r)
+ {
+ cdp1802.ef = cdp1802.config->ef_r() & 0x0f;
+ }
+ else
+ {
+ cdp1802.ef = 0x0f;
+ }
+}
+
+static void cdp1802_output_state_code(void)
+{
+ if (cdp1802.config->sc_w)
+ {
+ switch (cdp1802.state)
+ {
+ case CDP1802_STATE_0_FETCH:
+ cdp1802.config->sc_w(CDP1802_STATE_CODE_S0_FETCH);
+ break;
+
+ case CDP1802_STATE_1_EXECUTE:
+ cdp1802.config->sc_w(CDP1802_STATE_CODE_S1_EXECUTE);
+ break;
+
+ case CDP1802_STATE_2_DMA_IN:
+ case CDP1802_STATE_2_DMA_OUT:
+ cdp1802.config->sc_w(CDP1802_STATE_CODE_S2_DMA);
+ break;
+
+ case CDP1802_STATE_3_INT:
+ cdp1802.config->sc_w(CDP1802_STATE_CODE_S3_INTERRUPT);
+ break;
+ }
+ }
+}
+
+static void cdp1802_run(void)
+{
+ cdp1802_output_state_code();
+
+ switch (cdp1802.state)
+ {
+ case CDP1802_STATE_1_RESET:
+
+ I = 0;
+ N = 0;
+ Q = 0;
+ IE = 1;
+
+ cdp1802_ICount -= CDP1802_CYCLES_RESET;
+
+ CALL_MAME_DEBUG;
+
+ break;
+
+ case CDP1802_STATE_1_INIT:
+
+ X = 0;
+ P = 0;
+ R[0] = 0;
+
+ cdp1802_ICount -= CDP1802_CYCLES_INIT;
+
+ if (cdp1802.dmain)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_IN;
+ }
+ else if (cdp1802.dmaout)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_OUT;
+ }
+ else
+ {
+ cdp1802.state = CDP1802_STATE_0_FETCH;
+ }
+
+ CALL_MAME_DEBUG;
+
+ break;
+
+ case CDP1802_STATE_0_FETCH:
+ {
+ UINT8 opcode = cpu_readop(R[P]);
+
+ I = opcode >> 4;
+ N = opcode & 0x0f;
+ R[P] = R[P] + 1;
+
+ cdp1802_ICount -= CDP1802_CYCLES_FETCH;
+
+ cdp1802.state = CDP1802_STATE_1_EXECUTE;
+ }
+ break;
+
+ case CDP1802_STATE_1_EXECUTE:
+
+ cdp1802_sample_ef();
+
+ switch (I)
+ {
+ case 0:
+ if (N > 0)
+ {
+ D = M(R[N]);
+ }
+ break;
+
+ case 1:
+ R[N] = R[N] + 1;
+ break;
+
+ case 2:
+ R[N] = R[N] - 1;
+ break;
+
+ case 3:
+ switch (N)
+ {
+ case 0:
+ cdp1802_short_branch(1);
+ break;
+
+ case 1:
+ cdp1802_short_branch(Q == 1);
+ break;
+
+ case 2:
+ cdp1802_short_branch(D == 0);
+ break;
+
+ case 3:
+ cdp1802_short_branch(DF == 1);
+ break;
+
+ case 4:
+ cdp1802_short_branch((cdp1802.ef & EF1) ? 0 : 1);
+ break;
+
+ case 5:
+ cdp1802_short_branch((cdp1802.ef & EF2) ? 0 : 1);
+ break;
+
+ case 6:
+ cdp1802_short_branch((cdp1802.ef & EF3) ? 0 : 1);
+ break;
+
+ case 7:
+ cdp1802_short_branch((cdp1802.ef & EF4) ? 0 : 1);
+ break;
+
+ case 8:
+ cdp1802_short_branch(0);
+ break;
+
+ case 9:
+ cdp1802_short_branch(Q == 0);
+ break;
+
+ case 0xa:
+ cdp1802_short_branch(D != 0);
+ break;
+
+ case 0xb:
+ cdp1802_short_branch(DF == 0);
+ break;
+
+ case 0xc:
+ cdp1802_short_branch((cdp1802.ef & EF1) ? 1 : 0);
+ break;
+
+ case 0xd:
+ cdp1802_short_branch((cdp1802.ef & EF2) ? 1 : 0);
+ break;
+
+ case 0xe:
+ cdp1802_short_branch((cdp1802.ef & EF3) ? 1 : 0);
+ break;
+
+ case 0xf:
+ cdp1802_short_branch((cdp1802.ef & EF4) ? 1 : 0);
+ break;
+ }
+ break;
+
+ case 4:
+ D = M(R[N]);
+ R[N] = R[N] + 1;
+ break;
+
+ case 5:
+ MW(R[N], D);
+ break;
+
+ case 6:
+ switch (N)
+ {
+ case 0:
+ R[X] = R[X] + 1;
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ io_write_byte(N, M(R[X]));
+ R[X] = R[X] + 1;
+ break;
+
+ case 8:
+ /*
+
+ A note about INP 0 (0x68) from Tom Pittman's "A Short Course in Programming":
+
+ If you look carefully, you will notice that we never studied the opcode "68".
+ That's because it is not a defined 1802 instruction. It has the form of an INP
+ instruction, but 0 is not a defined input port, so if you execute it (try it!)
+ nothing is input. "Nothing" is the answer to a question; it is data, and something
+ will be put in the accumulator and memory (so now you know what the computer uses
+ to mean "nothing").
+
+ However, since the result of the "68" opcode is unpredictable, it should not be
+ used in your programs. In fact, "68" is the first byte of a series of additional
+ instructions for the 1804 and 1805 microprocessors.
+
+ http://www.ittybittycomputers.com/IttyBitty/ShortCor.htm
+
+ */
+ case 9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ {
+ UINT8 data = io_read_byte(N & 0x07);
+ MW(R[X], data);
+ D = data;
+ }
+ break;
+ }
+ break;
+
+ case 7:
+ switch (N)
+ {
+ case 0:
+ {
+ UINT8 data = M(R[X]);
+ R[X] = R[X] + 1;
+ P = data & 0xf;
+ X = data >> 4;
+ IE = 1;
+ }
+ break;
+
+ case 1:
+ {
+ UINT8 data = M(R[X]);
+ R[X] = R[X] + 1;
+ P = data & 0xf;
+ X = data >> 4;
+ IE = 0;
+ }
+ break;
+
+ case 2:
+ D = M(R[X]);
+ R[X] = R[X] + 1;
+ break;
+
+ case 3:
+ MW(R[X], D);
+ R[X] = R[X] - 1;
+ break;
+
+ case 4:
+ cdp1802_add_carry(M(R[X]), D);
+ break;
+
+ case 5:
+ cdp1802_sub_carry(M(R[X]), D);
+ break;
+
+ case 6:
+ {
+ int b = DF;
+ DF = D & 1;
+ D >>= 1;
+ if (b) D |= 0x80;
+ }
+ break;
+
+ case 7:
+ cdp1802_sub_carry(D, M(R[X]));
+ break;
+
+ case 8:
+ MW(R[X], T);
+ break;
+
+ case 9:
+ {
+ UINT8 result = (X << 4) | P;
+ T = result;
+ MW(R[2], result);
+ X = P;
+ R[2] = R[2] - 1;
+ }
+ break;
+
+ case 0xa:
+ Q = 0;
+
+ if (cdp1802.config->q_w)
+ {
+ cdp1802.config->q_w(Q);
+ }
+ break;
+
+ case 0xb:
+ Q = 1;
+
+ if (cdp1802.config->q_w)
+ {
+ cdp1802.config->q_w(Q);
+ }
+ break;
+
+ case 0xc:
+ cdp1802_add_carry(M(R[P]), D);
+ R[P] = R[P] + 1;
+ break;
+
+ case 0xd:
+ cdp1802_sub_carry(M(R[P]), D);
+ R[P] = R[P] + 1;
+ break;
+
+ case 0xe:
+ {
+ int b = DF;
+ DF = D & 0x80;
+ D <<= 1;
+ if (b) D |= 1;
+ }
+ break;
+
+ case 0xf:
+ cdp1802_sub_carry(D, M(R[P]));
+ R[P] = R[P] + 1;
+ break;
+ }
+ break;
+
+ case 8:
+ D = R[N] & 0xff;
+ break;
+
+ case 9:
+ D = (R[N] >> 8) & 0xff;
+ break;
+
+ case 0xa:
+ R[N] = (R[N] & 0xff00) | D;
+ break;
+
+ case 0xb:
+ R[N] = (D << 8) | (R[N] & 0xff);
+ break;
+
+ case 0xc:
+ cdp1802_output_state_code();
+
+ switch (N)
+ {
+ case 0:
+ cdp1802_long_branch(1);
+ break;
+
+ case 1:
+ cdp1802_long_branch(Q == 1);
+ break;
+
+ case 2:
+ cdp1802_long_branch(D == 0);
+ break;
+
+ case 3:
+ cdp1802_long_branch(DF == 1);
+ break;
+
+ case 4:
+ // NOP
+ break;
+
+ case 5:
+ cdp1802_long_skip(Q == 0);
+ break;
+
+ case 6:
+ cdp1802_long_skip(D != 0);
+ break;
+
+ case 7:
+ cdp1802_long_skip(DF == 0);
+ break;
+
+ case 8:
+ cdp1802_long_skip(1);
+ break;
+
+ case 9:
+ cdp1802_long_branch(Q == 0);
+ break;
+
+ case 0xa:
+ cdp1802_long_branch(D != 0);
+ break;
+
+ case 0xb:
+ cdp1802_long_branch(DF == 0);
+ break;
+
+ case 0xc:
+ cdp1802_long_skip(IE == 1);
+ break;
+
+ case 0xd:
+ cdp1802_long_skip(Q == 1);
+ break;
+
+ case 0xe:
+ cdp1802_long_skip(D == 0);
+ break;
+
+ case 0xf:
+ cdp1802_long_skip(DF == 1);
+ break;
+ }
+
+ cdp1802_ICount -= CDP1802_CYCLES_EXECUTE;
+ break;
+
+ case 0xd:
+ P = N;
+ break;
+
+ case 0xe:
+ X = N;
+ break;
+
+ case 0xf:
+ switch (N)
+ {
+ case 0:
+ D = M(R[X]);
+ break;
+
+ case 1:
+ D = M(R[X]) | D;
+ break;
+
+ case 2:
+ D = M(R[X]) & D;
+ break;
+
+ case 3:
+ D = M(R[X]) ^ D;
+ break;
+
+ case 4:
+ cdp1802_add(M(R[X]), D);
+ break;
+
+ case 5:
+ cdp1802_sub(M(R[X]), D);
+ break;
+
+ case 6:
+ DF = D & 0x01;
+ D = D >> 1;
+ break;
+
+ case 7:
+ cdp1802_sub(D, M(R[X]));
+ break;
+
+ case 8:
+ D = M(R[P]);
+ R[P] = R[P] + 1;
+ break;
+
+ case 9:
+ D = M(R[P]) | D;
+ R[P] = R[P] + 1;
+ break;
+
+ case 0xa:
+ D = M(R[P]) & D;
+ R[P] = R[P] + 1;
+ break;
+
+ case 0xb:
+ D = M(R[P]) ^ D;
+ R[P] = R[P] + 1;
+ break;
+
+ case 0xc:
+ cdp1802_add(M(R[P]), D);
+ R[P] = R[P] + 1;
+ break;
+
+ case 0xd:
+ cdp1802_sub(M(R[P]), D);
+ R[P] = R[P] + 1;
+ break;
+
+ case 0xe:
+ DF = (D & 0x80) >> 7;
+ D = D << 1;
+ break;
+
+ case 0xf:
+ cdp1802_sub(D, M(R[P]));
+ R[P] = R[P] + 1;
+ break;
+ }
+ break;
+ }
+
+ cdp1802_ICount -= CDP1802_CYCLES_EXECUTE;
+
+ if (cdp1802.dmain)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_IN;
+ }
+ else if (cdp1802.dmaout)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_OUT;
+ }
+ else if (IE && cdp1802.irq)
+ {
+ cdp1802.state = CDP1802_STATE_3_INT;
+ }
+ else if ((I > 0) || (N > 0)) // not idling
+ {
+ cdp1802.state = CDP1802_STATE_0_FETCH;
+ }
+
+ CALL_MAME_DEBUG;
+
+ break;
+
+ case CDP1802_STATE_2_DMA_IN:
+
+ if (cdp1802.config->dma_r)
+ {
+ MW(R[0], cdp1802.config->dma_r());
+ }
+
+ R[0] = R[0] + 1;
+
+ cdp1802_ICount -= CDP1802_CYCLES_DMA;
+
+ if (cdp1802.dmain)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_IN;
+ }
+ else if (cdp1802.dmaout)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_OUT;
+ }
+ else if (IE && cdp1802.irq)
+ {
+ cdp1802.state = CDP1802_STATE_3_INT;
+ }
+ else if (cdp1802.mode == CDP1802_MODE_LOAD)
+ {
+ cdp1802.state = CDP1802_STATE_1_EXECUTE;
+ }
+ else
+ {
+ cdp1802.state = CDP1802_STATE_0_FETCH;
+ }
+ break;
+
+ case CDP1802_STATE_2_DMA_OUT:
+
+ if (cdp1802.config->dma_w)
+ {
+ cdp1802.config->dma_w(M(R[0]));
+ }
+
+ R[0] = R[0] + 1;
+
+ cdp1802_ICount -= CDP1802_CYCLES_DMA;
+
+ if (cdp1802.dmain)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_IN;
+ }
+ else if (cdp1802.dmaout)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_OUT;
+ }
+ else if (IE && cdp1802.irq)
+ {
+ cdp1802.state = CDP1802_STATE_3_INT;
+ }
+ else
+ {
+ cdp1802.state = CDP1802_STATE_0_FETCH;
+ }
+ break;
+
+ case CDP1802_STATE_3_INT:
+
+ T = (X << 4) | P;
+ X = 2;
+ P = 1;
+ IE = 0;
+
+ cdp1802_ICount -= CDP1802_CYCLES_INTERRUPT;
+
+ if (cdp1802.dmain)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_IN;
+ }
+ else if (cdp1802.dmaout)
+ {
+ cdp1802.state = CDP1802_STATE_2_DMA_OUT;
+ }
+ else
+ {
+ cdp1802.state = CDP1802_STATE_0_FETCH;
+ }
+
+ CALL_MAME_DEBUG;
+
+ break;
+ }
+}
+
+static int cdp1802_execute(int cycles)
+{
+ cdp1802_ICount = cycles;
+
+ cdp1802.prevmode = cdp1802.mode;
+ cdp1802.mode = cdp1802.config->mode_r();
+
+ do
+ {
+ switch (cdp1802.mode)
+ {
+ case CDP1802_MODE_LOAD:
+ I = 0;
+ N = 0;
+ cdp1802.state = CDP1802_STATE_1_EXECUTE;
+ cdp1802_run();
+ break;
+
+ case CDP1802_MODE_RESET:
+ cdp1802.state = CDP1802_STATE_1_RESET;
+ cdp1802_run();
+ break;
+
+ case CDP1802_MODE_PAUSE:
+ cdp1802_ICount -= 1;
+ break;
+
+ case CDP1802_MODE_RUN:
+ switch (cdp1802.prevmode)
+ {
+ case CDP1802_MODE_LOAD:
+ // RUN mode cannot be initiated from LOAD mode
+ cdp1802.mode = CDP1802_MODE_LOAD;
+ break;
+
+ case CDP1802_MODE_RESET:
+ cdp1802.prevmode = CDP1802_MODE_RUN;
+ cdp1802.state = CDP1802_STATE_1_INIT;
+ cdp1802_run();
+ break;
+
+ case CDP1802_MODE_PAUSE:
+ cdp1802.prevmode = CDP1802_MODE_RUN;
+ cdp1802.state = CDP1802_STATE_0_FETCH;
+ cdp1802_run();
+ break;
+
+ case CDP1802_MODE_RUN:
+ cdp1802_run();
+ break;
+ }
+ break;
+ }
+ }
+ while (cdp1802_ICount > 0);
+
+ return cycles - cdp1802_ICount;
+}
+
+static void cdp1802_set_interrupt_line(int state)
+{
+ cdp1802.irq = state;
+}
+
+static void cdp1802_set_dmain_line(int state)
+{
+ cdp1802.dmain = state;
+}
+
+static void cdp1802_set_dmaout_line(int state)
+{
+ cdp1802.dmaout = state;
+}
+
+static void cdp1802_reset(void)
+{
+ cdp1802.mode = CDP1802_MODE_RESET;
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void cdp1802_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_INPUT_STATE + CDP1802_INPUT_LINE_INT: cdp1802_set_interrupt_line(info->i); break;
+ case CPUINFO_INT_INPUT_STATE + CDP1802_INPUT_LINE_DMAIN: cdp1802_set_dmain_line(info->i); break;
+ case CPUINFO_INT_INPUT_STATE + CDP1802_INPUT_LINE_DMAOUT: cdp1802_set_dmaout_line(info->i); break;
+
+ case CPUINFO_INT_REGISTER + CDP1802_P: cdp1802.p = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_X: cdp1802.x = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_T: cdp1802.t = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_D: cdp1802.d = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_B: cdp1802.b = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R0: cdp1802.r[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R1: cdp1802.r[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R2: cdp1802.r[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R3: cdp1802.r[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R4: cdp1802.r[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R5: cdp1802.r[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R6: cdp1802.r[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R7: cdp1802.r[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R8: cdp1802.r[8] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R9: cdp1802.r[9] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Ra: cdp1802.r[0xa] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Rb: cdp1802.r[0xb] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Rc: cdp1802.r[0xc] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Rd: cdp1802.r[0xd] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Re: cdp1802.r[0xe] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Rf: cdp1802.r[0xf] = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_DF: cdp1802.df = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_IE: cdp1802.ie = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Q: cdp1802.q = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_N: cdp1802.n = info->i; break;
+ case CPUINFO_INT_REGISTER + CDP1802_I: cdp1802.i = info->i; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + CDP1802_PC: cdp1802.r[cdp1802.p] = info->i; break;
+ }
+}
+
+/****************************************************************************
+ * Return a formatted string for a register
+ ****************************************************************************/
+void cdp1802_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(cdp1802); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = CDP1802_CYCLES_EXECUTE * 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = CDP1802_CYCLES_EXECUTE * 3; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 3; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + CDP1802_INPUT_LINE_INT: info->i = cdp1802.irq; break;
+ case CPUINFO_INT_INPUT_STATE + CDP1802_INPUT_LINE_DMAIN: info->i = cdp1802.dmain; break;
+ case CPUINFO_INT_INPUT_STATE + CDP1802_INPUT_LINE_DMAOUT: info->i = cdp1802.dmaout; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_SP: info->i = 0; break;
+ case CPUINFO_INT_REGISTER + CDP1802_P: info->i = cdp1802.p; break;
+ case CPUINFO_INT_REGISTER + CDP1802_X: info->i = cdp1802.x; break;
+ case CPUINFO_INT_REGISTER + CDP1802_T: info->i = cdp1802.t; break;
+ case CPUINFO_INT_REGISTER + CDP1802_D: info->i = cdp1802.d; break;
+ case CPUINFO_INT_REGISTER + CDP1802_B: info->i = cdp1802.b; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R0: info->i = cdp1802.r[0]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R1: info->i = cdp1802.r[1]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R2: info->i = cdp1802.r[2]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R3: info->i = cdp1802.r[3]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R4: info->i = cdp1802.r[4]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R5: info->i = cdp1802.r[5]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R6: info->i = cdp1802.r[6]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R7: info->i = cdp1802.r[7]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R8: info->i = cdp1802.r[8]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_R9: info->i = cdp1802.r[9]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Ra: info->i = cdp1802.r[0xa]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Rb: info->i = cdp1802.r[0xb]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Rc: info->i = cdp1802.r[0xc]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Rd: info->i = cdp1802.r[0xd]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Re: info->i = cdp1802.r[0xe]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Rf: info->i = cdp1802.r[0xf]; break;
+ case CPUINFO_INT_REGISTER + CDP1802_DF: info->i = cdp1802.df; break;
+ case CPUINFO_INT_REGISTER + CDP1802_IE: info->i = cdp1802.ie; break;
+ case CPUINFO_INT_REGISTER + CDP1802_Q: info->i = cdp1802.q; break;
+ case CPUINFO_INT_REGISTER + CDP1802_N: info->i = cdp1802.n; break;
+ case CPUINFO_INT_REGISTER + CDP1802_I: info->i = cdp1802.i; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + CDP1802_PC: info->i = cdp1802.r[cdp1802.p]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = cdp1802_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = cdp1802_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = cdp1802_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = cdp1802_init; break;
+ case CPUINFO_PTR_RESET: info->reset = cdp1802_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = cdp1802_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = cdp1802_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cdp1802_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "CDP1802"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "CDP1800"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2007 The MAME team"); break;
+
+ case CPUINFO_STR_REGISTER + CDP1802_PC: sprintf(info->s, "PC:%.4x", cdp1802.r[cdp1802.p]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R0: sprintf(info->s, "R0:%.4x", cdp1802.r[0]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R1: sprintf(info->s, "R1:%.4x", cdp1802.r[1]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R2: sprintf(info->s, "R2:%.4x", cdp1802.r[2]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R3: sprintf(info->s, "R3:%.4x", cdp1802.r[3]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R4: sprintf(info->s, "R4:%.4x", cdp1802.r[4]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R5: sprintf(info->s, "R5:%.4x", cdp1802.r[5]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R6: sprintf(info->s, "R6:%.4x", cdp1802.r[6]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R7: sprintf(info->s, "R7:%.4x", cdp1802.r[7]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R8: sprintf(info->s, "R8:%.4x", cdp1802.r[8]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_R9: sprintf(info->s, "R9:%.4x", cdp1802.r[9]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_Ra: sprintf(info->s, "Ra:%.4x", cdp1802.r[0xa]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_Rb: sprintf(info->s, "Rb:%.4x", cdp1802.r[0xb]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_Rc: sprintf(info->s, "Rc:%.4x", cdp1802.r[0xc]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_Rd: sprintf(info->s, "Rd:%.4x", cdp1802.r[0xd]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_Re: sprintf(info->s, "Re:%.4x", cdp1802.r[0xe]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_Rf: sprintf(info->s, "Rf:%.4x", cdp1802.r[0xf]); break;
+ case CPUINFO_STR_REGISTER + CDP1802_P: sprintf(info->s, "P:%x", cdp1802.p); break;
+ case CPUINFO_STR_REGISTER + CDP1802_X: sprintf(info->s, "X:%x", cdp1802.x); break;
+ case CPUINFO_STR_REGISTER + CDP1802_D: sprintf(info->s, "D:%.2x", cdp1802.d); break;
+ case CPUINFO_STR_REGISTER + CDP1802_B: sprintf(info->s, "B:%.2x", cdp1802.b); break;
+ case CPUINFO_STR_REGISTER + CDP1802_T: sprintf(info->s, "T:%.2x", cdp1802.t); break;
+ case CPUINFO_STR_REGISTER + CDP1802_DF: sprintf(info->s, "DF:%x", cdp1802.df); break;
+ case CPUINFO_STR_REGISTER + CDP1802_IE: sprintf(info->s, "IE:%x", cdp1802.ie); break;
+ case CPUINFO_STR_REGISTER + CDP1802_Q: sprintf(info->s, "Q:%x", cdp1802.q); break;
+ case CPUINFO_STR_REGISTER + CDP1802_N: sprintf(info->s, "N:%x", cdp1802.n); break;
+ case CPUINFO_STR_REGISTER + CDP1802_I: sprintf(info->s, "I:%x", cdp1802.i); break;
+ case CPUINFO_STR_FLAGS: sprintf(info->s,
+ "%s%s%s",
+ cdp1802.df ? "DF" : "..",
+ cdp1802.ie ? "IE" : "..",
+ cdp1802.q ? "Q" : "."); break;
+ }
+}
diff --git a/src/emu/cpu/cdp1802/cdp1802.h b/src/emu/cpu/cdp1802/cdp1802.h
new file mode 100644
index 00000000000..e53c0ba26f9
--- /dev/null
+++ b/src/emu/cpu/cdp1802/cdp1802.h
@@ -0,0 +1,100 @@
+#ifndef _CDP1802_H
+#define _CDP1802_H
+
+#include "cpuintrf.h"
+
+#define CDP1802_CYCLES_RESET 8
+#define CDP1802_CYCLES_INIT 8 // really 9, but needs to be 8 to synchronize cdp1861 video timings
+#define CDP1802_CYCLES_FETCH 8
+#define CDP1802_CYCLES_EXECUTE 8
+#define CDP1802_CYCLES_DMA 8
+#define CDP1802_CYCLES_INTERRUPT 8
+
+enum {
+ CDP1802_INPUT_LINE_INT,
+ CDP1802_INPUT_LINE_DMAIN,
+ CDP1802_INPUT_LINE_DMAOUT
+};
+
+enum {
+ EF1 = 0x01,
+ EF2 = 0x02,
+ EF3 = 0x04,
+ EF4 = 0x08
+};
+
+enum {
+ CDP1802_STATE_0_FETCH,
+ CDP1802_STATE_1_RESET,
+ CDP1802_STATE_1_INIT,
+ CDP1802_STATE_1_EXECUTE,
+ CDP1802_STATE_2_DMA_IN,
+ CDP1802_STATE_2_DMA_OUT,
+ CDP1802_STATE_3_INT
+};
+
+enum {
+ CDP1802_STATE_CODE_S0_FETCH,
+ CDP1802_STATE_CODE_S1_EXECUTE,
+ CDP1802_STATE_CODE_S2_DMA,
+ CDP1802_STATE_CODE_S3_INTERRUPT
+};
+
+enum {
+ CDP1802_MODE_LOAD,
+ CDP1802_MODE_RESET,
+ CDP1802_MODE_PAUSE,
+ CDP1802_MODE_RUN
+};
+
+// CDP1802 Registers
+
+enum {
+ CDP1802_PC = 1,
+ CDP1802_P, // Designates which register is Program Counter
+ CDP1802_X, // Designates which register is Data Pointer
+ CDP1802_D, // Data Register (Accumulator)
+ CDP1802_B, // Auxiliary Holding Register
+ CDP1802_T, // Holds old X, P after Interrupt (X is high nibble)
+
+ CDP1802_R0, // 1 of 16 Scratchpad Registers
+ CDP1802_R1,
+ CDP1802_R2,
+ CDP1802_R3,
+ CDP1802_R4,
+ CDP1802_R5,
+ CDP1802_R6,
+ CDP1802_R7,
+ CDP1802_R8,
+ CDP1802_R9,
+ CDP1802_Ra,
+ CDP1802_Rb,
+ CDP1802_Rc,
+ CDP1802_Rd,
+ CDP1802_Re,
+ CDP1802_Rf,
+
+ CDP1802_DF, // Data Flag (ALU Carry)
+ CDP1802_IE, // Interrupt Enable
+ CDP1802_Q, // Output Flip-Flop
+ CDP1802_N, // Holds Low-Order Instruction Digit
+ CDP1802_I, // Holds High-Order Instruction Digit
+};
+
+void cdp1802_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+offs_t cdp1802_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+typedef struct
+{
+ UINT8 (*mode_r)(void);
+ UINT8 (*ef_r)(void);
+ void (*sc_w)(int state);
+ void (*q_w)(int level);
+ UINT8 (*dma_r)(void);
+ void (*dma_w)(UINT8 data);
+} CDP1802_CONFIG;
+
+#endif
diff --git a/src/emu/cpu/cop400/410ops.c b/src/emu/cpu/cop400/410ops.c
new file mode 100644
index 00000000000..5155e03ce5b
--- /dev/null
+++ b/src/emu/cpu/cop400/410ops.c
@@ -0,0 +1,450 @@
+/**************************************************************************
+ * National Semiconductor COP410 Emulator *
+ * *
+ * Copyright (C) 2006 MAME Team *
+ **************************************************************************/
+
+#define ROM(A) cpu_readop(A)
+#define RAM_W(A,V) (data_write_byte_8(A,V))
+#define RAM_R(A) (data_read_byte_8(A))
+
+#define IN(A) io_read_byte_8(A)
+#define OUT(A,V) io_write_byte_8(A,V)
+
+#define A R.A
+#define B R.B
+#define C R.C
+#define G R.G
+#define Q R.Q
+#define EN R.EN
+#define SA R.SA
+#define SB R.SB
+#define SIO R.SIO
+#define SKL R.SKL
+#define PC R.PC
+#define prevPC R.PREVPC
+#define skip R.skip
+#define skipLBI R.skipLBI
+
+#define READ_M RAM_R(B)
+#define WRITE_M(VAL) RAM_W(B,VAL)
+
+#define IN_G() IN(COP400_PORT_G)
+#define IN_L() IN(COP400_PORT_L)
+#define OUT_G(A) OUT(COP400_PORT_G, (A) & R.G_mask)
+#define OUT_L(A) OUT(COP400_PORT_L, (A))
+#define OUT_D(A) OUT(COP400_PORT_D, (A) & R.D_mask)
+#define OUT_SK(A) OUT(COP400_PORT_SK,A)
+
+#ifndef PUSH
+#define PUSH(addr) { SB = SA; SA = addr; }
+#define POP() { PC = SA; SA = SB; }
+#endif
+
+INLINE void illegal(void)
+{
+ logerror("ICOP400: PC = %04x, Illegal opcode = %02x\n", PC-1, ROM(PC-1));
+}
+
+INLINE void WRITE_SK(UINT8 data)
+{
+ SKL = data;
+
+ if (EN & 0x01)
+ {
+ OUT_SK(SKL);
+ }
+ else
+ {
+ // NOT IMPLEMENTED
+ OUT_SK(SKL);
+ }
+}
+
+INLINE void WRITE_Q(UINT8 data)
+{
+ Q = data;
+
+ if (EN & 0x04)
+ {
+ OUT_L(Q);
+ }
+}
+
+INLINE void WRITE_G(UINT8 data)
+{
+ G = data;
+ OUT_G(G);
+}
+
+INLINE void add(void) { A = (A + RAM_R(B)) & 0x0F; }
+
+INLINE void asc(void)
+{
+ A = A + C + RAM_R(B);
+
+ if (A > 0xF)
+ {
+ C = 1;
+ skip = 1;
+ A &= 0xF;
+ }
+ else
+ {
+ C = 0;
+ }
+}
+
+INLINE void AISC(int y)
+{
+ A = A + y;
+
+ if (A > 0xF)
+ {
+ skip = 1;
+ A &= 0xF;
+ }
+}
+
+INLINE void aisc1(void) { AISC(0x1); }
+INLINE void aisc2(void) { AISC(0x2); }
+INLINE void aisc3(void) { AISC(0x3); }
+INLINE void aisc4(void) { AISC(0x4); }
+INLINE void aisc5(void) { AISC(0x5); }
+INLINE void aisc6(void) { AISC(0x6); }
+INLINE void aisc7(void) { AISC(0x7); }
+INLINE void aisc8(void) { AISC(0x8); }
+INLINE void aisc9(void) { AISC(0x9); }
+INLINE void aisc10(void) { AISC(0xA); }
+INLINE void aisc11(void) { AISC(0xB); }
+INLINE void aisc12(void) { AISC(0xC); }
+INLINE void aisc13(void) { AISC(0xD); }
+INLINE void aisc14(void) { AISC(0xE); }
+INLINE void aisc15(void) { AISC(0xF); }
+
+INLINE void cab(void) { B = (B & 0x30) | A; }
+
+INLINE void camq(void) { WRITE_Q((A << 4) | READ_M); }
+
+INLINE void cba(void) { A = B & 0xF; }
+
+INLINE void clra(void){ A = 0; }
+
+INLINE void comp(void) { A = A ^ 0xF; }
+
+INLINE void ing(void) { A = IN_G(); }
+
+INLINE void inl(void)
+{
+ UINT8 L = IN_L();
+ RAM_W(B, L >> 4);
+ A = L & 0xF;
+}
+
+INLINE void jid(void)
+{
+ UINT16 addr = (PC & 0x300) | (A << 4) | READ_M;
+ PC = (PC & 0x300) | ROM(addr);
+}
+
+INLINE void JMP(UINT8 a8)
+{
+ PC = (a8 << 8) | ROM(PC);
+}
+
+INLINE void jmp0(void) { JMP(0); }
+INLINE void jmp1(void) { JMP(1); }
+INLINE void jmp2(void) { JMP(2); }
+INLINE void jmp3(void) { JMP(3); }
+
+INLINE void jp(void)
+{
+ UINT8 op = ROM(prevPC);
+
+ if (((PC & 0x3E0) >= 0x80) && ((PC & 0x3E0) < 0x100)) //JP pages 2,3
+ {
+ PC = (UINT16)((PC & 0x380) | (op & 0x7F));
+ }
+ else
+ {
+ if ((op & 0xC0) == 0xC0) //JP other pages
+ {
+ PC = (UINT16)((PC & 0x3C0) | (op & 0x3F));
+ }
+ else //JSRP
+ {
+ PUSH((UINT16)(PC));
+ PC = (UINT16)(0x80 | (op & 0x3F));
+ }
+ }
+}
+
+INLINE void JSR(UINT8 a8)
+{
+ PUSH(PC + 1);
+ PC = (a8 << 8) | ROM(PC);
+}
+
+INLINE void jsr0(void) { JSR(0); }
+INLINE void jsr1(void) { JSR(1); }
+INLINE void jsr2(void) { JSR(2); }
+INLINE void jsr3(void) { JSR(3); }
+
+INLINE void LD(UINT8 r)
+{
+ A = RAM_R(B);
+ B = B ^ (r << 4);
+}
+
+INLINE void ld0(void) { LD(0); }
+INLINE void ld1(void) { LD(1); }
+INLINE void ld2(void) { LD(2); }
+INLINE void ld3(void) { LD(3); }
+
+INLINE void LBI(UINT8 r, UINT8 d)
+{
+ B = (r << 4) | d;
+ skipLBI = 1;
+}
+
+INLINE void lbi0_0(void) { LBI(0,0); }
+INLINE void lbi0_1(void) { LBI(0,1); }
+INLINE void lbi0_2(void) { LBI(0,2); }
+INLINE void lbi0_3(void) { LBI(0,3); }
+INLINE void lbi0_4(void) { LBI(0,4); }
+INLINE void lbi0_5(void) { LBI(0,5); }
+INLINE void lbi0_6(void) { LBI(0,6); }
+INLINE void lbi0_7(void) { LBI(0,7); }
+INLINE void lbi0_8(void) { LBI(0,8); }
+INLINE void lbi0_9(void) { LBI(0,9); }
+INLINE void lbi0_10(void) { LBI(0,10); }
+INLINE void lbi0_11(void) { LBI(0,11); }
+INLINE void lbi0_12(void) { LBI(0,12); }
+INLINE void lbi0_13(void) { LBI(0,13); }
+INLINE void lbi0_14(void) { LBI(0,14); }
+INLINE void lbi0_15(void) { LBI(0,15); }
+
+INLINE void lbi1_0(void) { LBI(1,0); }
+INLINE void lbi1_1(void) { LBI(1,1); }
+INLINE void lbi1_2(void) { LBI(1,2); }
+INLINE void lbi1_3(void) { LBI(1,3); }
+INLINE void lbi1_4(void) { LBI(1,4); }
+INLINE void lbi1_5(void) { LBI(1,5); }
+INLINE void lbi1_6(void) { LBI(1,6); }
+INLINE void lbi1_7(void) { LBI(1,7); }
+INLINE void lbi1_8(void) { LBI(1,8); }
+INLINE void lbi1_9(void) { LBI(1,9); }
+INLINE void lbi1_10(void) { LBI(1,10); }
+INLINE void lbi1_11(void) { LBI(1,11); }
+INLINE void lbi1_12(void) { LBI(1,12); }
+INLINE void lbi1_13(void) { LBI(1,13); }
+INLINE void lbi1_14(void) { LBI(1,14); }
+INLINE void lbi1_15(void) { LBI(1,15); }
+
+INLINE void lbi2_0(void) { LBI(2,0); }
+INLINE void lbi2_1(void) { LBI(2,1); }
+INLINE void lbi2_2(void) { LBI(2,2); }
+INLINE void lbi2_3(void) { LBI(2,3); }
+INLINE void lbi2_4(void) { LBI(2,4); }
+INLINE void lbi2_5(void) { LBI(2,5); }
+INLINE void lbi2_6(void) { LBI(2,6); }
+INLINE void lbi2_7(void) { LBI(2,7); }
+INLINE void lbi2_8(void) { LBI(2,8); }
+INLINE void lbi2_9(void) { LBI(2,9); }
+INLINE void lbi2_10(void) { LBI(2,10); }
+INLINE void lbi2_11(void) { LBI(2,11); }
+INLINE void lbi2_12(void) { LBI(2,12); }
+INLINE void lbi2_13(void) { LBI(2,13); }
+INLINE void lbi2_14(void) { LBI(2,14); }
+INLINE void lbi2_15(void) { LBI(2,15); }
+
+INLINE void lbi3_0(void) { LBI(3,0); }
+INLINE void lbi3_1(void) { LBI(3,1); }
+INLINE void lbi3_2(void) { LBI(3,2); }
+INLINE void lbi3_3(void) { LBI(3,3); }
+INLINE void lbi3_4(void) { LBI(3,4); }
+INLINE void lbi3_5(void) { LBI(3,5); }
+INLINE void lbi3_6(void) { LBI(3,6); }
+INLINE void lbi3_7(void) { LBI(3,7); }
+INLINE void lbi3_8(void) { LBI(3,8); }
+INLINE void lbi3_9(void) { LBI(3,9); }
+INLINE void lbi3_10(void) { LBI(3,10); }
+INLINE void lbi3_11(void) { LBI(3,11); }
+INLINE void lbi3_12(void) { LBI(3,12); }
+INLINE void lbi3_13(void) { LBI(3,13); }
+INLINE void lbi3_14(void) { LBI(3,14); }
+INLINE void lbi3_15(void) { LBI(3,15); }
+
+INLINE void LEI(UINT8 y)
+{
+ EN = y & 0x0f;
+
+ WRITE_Q(Q);
+}
+
+INLINE void lei0(void) { LEI(0); }
+INLINE void lei1(void) { LEI(1); }
+INLINE void lei2(void) { LEI(2); }
+INLINE void lei3(void) { LEI(3); }
+INLINE void lei4(void) { LEI(4); }
+INLINE void lei5(void) { LEI(5); }
+INLINE void lei6(void) { LEI(6); }
+INLINE void lei7(void) { LEI(7); }
+INLINE void lei8(void) { LEI(8); }
+INLINE void lei9(void) { LEI(9); }
+INLINE void lei10(void) { LEI(10); }
+INLINE void lei11(void) { LEI(11); }
+INLINE void lei12(void) { LEI(12); }
+INLINE void lei13(void) { LEI(13); }
+INLINE void lei14(void) { LEI(14); }
+INLINE void lei15(void) { LEI(15); }
+
+INLINE void lqid(void)
+{
+ PUSH(PC + 1);
+ PC = (UINT16)((PC & 0x300) | (A << 4) | READ_M);
+ WRITE_Q(ROM(PC));
+ POP();
+}
+
+INLINE void nop(void) { }
+
+INLINE void obd(void) { OUT_D(B); }
+
+INLINE void omg(void) { WRITE_G(RAM_R(B)); }
+
+INLINE void rc(void) { C = 0; }
+
+INLINE void ret(void) { POP(); }
+
+INLINE void retsk(void) { POP(); skip = 1; }
+
+INLINE void rmb0(void) { RAM_W(B, RAM_R(B) & 0xE); }
+INLINE void rmb1(void) { RAM_W(B, RAM_R(B) & 0xD); }
+INLINE void rmb2(void) { RAM_W(B, RAM_R(B) & 0xB); }
+INLINE void rmb3(void) { RAM_W(B, RAM_R(B) & 0x7); }
+
+INLINE void sc(void) { C = 1; }
+
+INLINE void skc(void) { if (C == 1) skip = 1; }
+
+INLINE void ske(void) { if (A == RAM_R(B)) skip = 1; }
+
+INLINE void skmbz0(void) { if ((RAM_R(B) & 0x01) == 0 ) skip = 1; }
+INLINE void skmbz1(void) { if ((RAM_R(B) & 0x02) == 0 ) skip = 1; }
+INLINE void skmbz2(void) { if ((RAM_R(B) & 0x04) == 0 ) skip = 1; }
+INLINE void skmbz3(void) { if ((RAM_R(B) & 0x08) == 0 ) skip = 1; }
+
+INLINE void skgbz0(void) { if ((IN_G() & 0x01) == 0) skip = 1; }
+INLINE void skgbz1(void) { if ((IN_G() & 0x02) == 0) skip = 1; }
+INLINE void skgbz2(void) { if ((IN_G() & 0x04) == 0) skip = 1; }
+INLINE void skgbz3(void) { if ((IN_G() & 0x08) == 0) skip = 1; }
+
+INLINE void skgz(void) { if (IN_G() == 0) skip = 1; }
+
+INLINE void smb0(void) { RAM_W(B, RAM_R(B) | 0x1); }
+INLINE void smb1(void) { RAM_W(B, RAM_R(B) | 0x2); }
+INLINE void smb2(void) { RAM_W(B, RAM_R(B) | 0x4); }
+INLINE void smb3(void) { RAM_W(B, RAM_R(B) | 0x8); }
+
+INLINE void STII(UINT8 y)
+{
+ UINT16 Bd;
+
+ RAM_W(B, y);
+ Bd = (B & 0x0f) + 1;
+ if (Bd > 15) Bd = 0;
+ B = (B & 0x30) + Bd;
+}
+
+INLINE void stii0(void) { STII(0x0); }
+INLINE void stii1(void) { STII(0x1); }
+INLINE void stii2(void) { STII(0x2); }
+INLINE void stii3(void) { STII(0x3); }
+
+INLINE void stii4(void) { STII(0x4); }
+INLINE void stii5(void) { STII(0x5); }
+INLINE void stii6(void) { STII(0x6); }
+INLINE void stii7(void) { STII(0x7); }
+
+INLINE void stii8(void) { STII(0x8); }
+INLINE void stii9(void) { STII(0x9); }
+INLINE void stii10(void) { STII(0xA); }
+INLINE void stii11(void) { STII(0xB); }
+
+INLINE void stii12(void) { STII(0xC); }
+INLINE void stii13(void) { STII(0xD); }
+INLINE void stii14(void) { STII(0xE); }
+INLINE void stii15(void) { STII(0xF); }
+
+INLINE void X(UINT8 r)
+{
+ UINT8 t = RAM_R(B);
+ RAM_W(B, A);
+ A = t;
+ B = B ^ (r << 4);
+}
+
+INLINE void x0(void) { X(0); }
+INLINE void x1(void) { X(1); }
+INLINE void x2(void) { X(2); }
+INLINE void x3(void) { X(3); }
+
+INLINE void xad(void)
+{
+ UINT8 addr = ROM(PC++) & 0x3f;
+ UINT8 t = A;
+ A = RAM_R(addr);
+ RAM_W(addr, t);
+}
+
+INLINE void xas(void)
+{
+ UINT8 t = SIO;
+ SIO = A;
+ A = t;
+
+ WRITE_SK(C);
+}
+
+INLINE void XDS(UINT8 r)
+{
+ UINT8 t, Bd, Br;
+
+ t = RAM_R(B);
+ RAM_W(B, A);
+ A = t;
+
+ Br = (UINT8)((B & 0x30) ^ (r << 4));
+ Bd = (UINT8)((B & 0x0F) - 1);
+ B = (UINT8)(Br | (Bd & 0x0F));
+
+ if (Bd == 0xFF) skip = 1;
+}
+
+INLINE void XIS(UINT8 r)
+{
+ UINT8 t, Bd, Br;
+
+ t = RAM_R(B);
+ RAM_W(B, A);
+ A = t;
+
+ Br = (UINT8)((B & 0x30) ^ (r << 4));
+ Bd = (UINT8)((B & 0x0F) + 1);
+ B = (UINT8)(Br | (Bd & 0x0F));
+
+ if (Bd == 0x10) skip = 1;
+}
+
+INLINE void xis0(void) { XIS(0); }
+INLINE void xis1(void) { XIS(1); }
+INLINE void xis2(void) { XIS(2); }
+INLINE void xis3(void) { XIS(3); }
+
+INLINE void xds0(void) { XDS(0); }
+INLINE void xds1(void) { XDS(1); }
+INLINE void xds2(void) { XDS(2); }
+INLINE void xds3(void) { XDS(3); }
+
+INLINE void xor(void) { A = RAM_R(B) ^ A; }
diff --git a/src/emu/cpu/cop400/420ops.c b/src/emu/cpu/cop400/420ops.c
new file mode 100644
index 00000000000..d5c47751a93
--- /dev/null
+++ b/src/emu/cpu/cop400/420ops.c
@@ -0,0 +1,93 @@
+/**************************************************************************
+ * National Semiconductor COP420 Emulator *
+ * *
+ * Copyright (C) 2006 MAME Team *
+ **************************************************************************/
+
+#define SC R.SC
+
+#define PUSH(addr) { SC = SB; SB = SA; SA = addr; }
+#define POP() { PC = SA; SA = SB; SB = SC; }
+
+#include "410ops.c"
+
+#define IN_IN() IN(COP400_PORT_IN)
+
+INLINE void adt(void) { A = (A + 10) & 0x0F; }
+
+INLINE void casc(void)
+{
+ A = (A ^ 0xF) + RAM_R(B) + C;
+
+ if (A > 0xF)
+ {
+ C = 1;
+ skip = 1;
+ A &= 0xF;
+ }
+ else
+ {
+ C = 0;
+ }
+}
+
+INLINE void cqma(void)
+{
+ WRITE_M(Q >> 4);
+ A = Q & 0xF;
+}
+
+INLINE void inil(void)
+{
+ // NOT IMPLEMENTED
+ A = IN_IN();
+}
+
+INLINE void cop421_inil(void)
+{
+ // NOT IMPLEMENTED
+}
+
+INLINE void inin(void) { A = IN_IN(); }
+
+INLINE void cop402m_inin(void) { A = IN_IN() | 0x02; }
+
+INLINE void ldd(void)
+{
+ A = RAM_R(ROM(PC++) & 0x3f);
+}
+
+INLINE void ogi0(void) { WRITE_G(0); }
+INLINE void ogi1(void) { WRITE_G(1); }
+INLINE void ogi2(void) { WRITE_G(2); }
+INLINE void ogi3(void) { WRITE_G(3); }
+INLINE void ogi4(void) { WRITE_G(4); }
+INLINE void ogi5(void) { WRITE_G(5); }
+INLINE void ogi6(void) { WRITE_G(6); }
+INLINE void ogi7(void) { WRITE_G(7); }
+INLINE void ogi8(void) { WRITE_G(8); }
+INLINE void ogi9(void) { WRITE_G(9); }
+INLINE void ogi10(void) { WRITE_G(10); }
+INLINE void ogi11(void) { WRITE_G(11); }
+INLINE void ogi12(void) { WRITE_G(12); }
+INLINE void ogi13(void) { WRITE_G(13); }
+INLINE void ogi14(void) { WRITE_G(14); }
+INLINE void ogi15(void) { WRITE_G(15); }
+
+INLINE void skt(void)
+{
+ if (R.timerlatch == 1)
+ {
+ R.timerlatch = 0;
+ skip = 1;
+ }
+}
+
+INLINE void xabr(void)
+{
+ UINT8 Br = A & 0x03;
+ UINT8 Bd = B & 0x0f;
+
+ A = (B & 0x30) >> 4;
+ B = (Br << 4) + Bd;
+}
diff --git a/src/emu/cpu/cop400/cop400.h b/src/emu/cpu/cop400/cop400.h
new file mode 100644
index 00000000000..56b1a6012d9
--- /dev/null
+++ b/src/emu/cpu/cop400/cop400.h
@@ -0,0 +1,46 @@
+/**************************************************************************
+ * National Semiconductor COP400 Emulator *
+ * *
+ * Copyright (C) 2006 MAME Team *
+ **************************************************************************/
+
+#ifndef _COP400_H
+#define _COP400_H
+
+#ifndef INLINE
+#define INLINE static inline
+#endif
+
+#define COP400_CLOCK_DIVIDER 4
+
+#define COP400_PORT_L 0x100
+#define COP400_PORT_G 0x101
+#define COP400_PORT_D 0x102
+#define COP400_PORT_IN 0x103
+#define COP400_PORT_SK 0x104
+#define COP400_PORT_SIO 0x105
+
+enum {
+ COP400_PC=1,
+ COP400_A,
+ COP400_B,
+ COP400_C,
+ COP400_G,
+ COP400_EN,
+ COP400_Q,
+ COP400_SA,
+ COP400_SB,
+ COP400_SC,
+ COP400_SIO,
+ COP400_SKL
+};
+
+extern void cop410_get_info(UINT32 state, cpuinfo *info);
+extern void cop420_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+offs_t cop410_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t cop420_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+#endif /* _COP400_H */
diff --git a/src/emu/cpu/cop400/cop410.c b/src/emu/cpu/cop400/cop410.c
new file mode 100644
index 00000000000..95c0e2e8bf5
--- /dev/null
+++ b/src/emu/cpu/cop400/cop410.c
@@ -0,0 +1,392 @@
+/**************************************************************************
+ * National Semiconductor COP410 Emulator *
+ * *
+ * Copyright (C) 2005 by Dan Boris *
+ **************************************************************************/
+
+/*
+
+ TODO:
+
+ - serial I/O
+
+*/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "cop400.h"
+
+/* The opcode table now is a combination of cycle counts and function pointers */
+typedef struct {
+ unsigned cycles;
+ void (*function) (void);
+} s_opcode;
+
+#define UINT1 UINT8
+#define UINT4 UINT8
+#define UINT6 UINT8
+#define UINT9 UINT16
+
+typedef struct
+{
+ UINT9 PC;
+ UINT9 PREVPC;
+ UINT4 A;
+ UINT6 B;
+ UINT1 C;
+ UINT4 EN;
+ UINT4 G;
+ UINT8 Q;
+ UINT9 SA, SB;
+ UINT4 SIO;
+ UINT1 SKL;
+ UINT8 skip, skipLBI;
+ UINT8 G_mask;
+ UINT8 D_mask;
+} COP410_Regs;
+
+static COP410_Regs R;
+static int cop410_ICount;
+
+static int InstLen[256];
+static int LBIops[256];
+
+#include "410ops.c"
+
+static s_opcode cop410_opcode_op33[256]=
+{
+ {1, illegal },{1, skgbz0 },{1, illegal },{1, skgbz2 },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, skgbz1 },{1, illegal },{1, skgbz3 },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, skgz },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, ing },{1, illegal },{1, illegal },{1, illegal },{1, inl },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, omg },{1, illegal },{1, camq },{1, illegal },{1, obd },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, lei0 },{1, lei1 },{1, lei2 },{1, lei3 },{1, lei4 },{1, lei5 },{1, lei6 },{1, lei7 },
+ {1, lei8 },{1, lei9 },{1, lei10 },{1, lei11 },{1, lei12 },{1, lei13 },{1, lei14 },{1, lei15 },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal }
+};
+
+static void cop410_op33(void)
+{
+ (*(cop410_opcode_op33[ROM(PC++)].function))();
+}
+
+static s_opcode cop410_opcode_main[256]=
+{
+ {1, clra },{1, skmbz0 },{1, xor },{1, skmbz2 },{1, xis0 },{1, ld0 },{1, x0 },{1, xds0 },
+ {1, lbi0_9 },{1, lbi0_10 },{1, lbi0_11 },{1, lbi0_12 },{1, lbi0_13 },{1, lbi0_14 },{1, lbi0_15 },{1, lbi0_0 },
+ {0, illegal },{1, skmbz1 },{0, illegal },{1, skmbz3 },{1, xis0 },{1, ld1 },{1, x1 },{1, xds1 },
+ {1, lbi1_9 },{1, lbi1_10 },{1, lbi1_11 },{1, lbi1_12 },{1, lbi1_13 },{1, lbi1_14 },{1, lbi1_15 },{1, lbi1_0 },
+ {1, skc },{1, ske },{1, sc },{2, xad },{1, xis2 },{1, ld2 },{1, x2 },{1, xds2 },
+ {1, lbi2_9 },{1, lbi2_10 },{1, lbi2_11 },{1, lbi2_12 },{1, lbi2_13 },{1, lbi2_14 },{1, lbi2_15 },{1, lbi2_0 },
+ {1, asc },{1, add },{1, rc },{2, cop410_op33 },{1, xis3 },{1, ld3 },{1, x3 },{1, xds3 },
+ {1, lbi3_9 },{1, lbi3_10 },{1, lbi3_11 },{1, lbi3_12 },{1, lbi3_13 },{1, lbi3_14 },{1, lbi3_15 },{1, lbi3_0 },
+ {1, comp },{0, illegal },{1, rmb2 },{1, rmb2 },{1, nop },{1, rmb1 },{1, smb2 },{1, smb1 },
+ {1, ret },{1, retsk },{0, illegal },{1, smb3 },{1, rmb0 },{1, smb0 },{1, cba },{1, xas },
+ {1, cab },{1, aisc1 },{1, aisc2 },{1, aisc3 },{1, aisc4 },{1, aisc5 },{1, aisc6 },{1, aisc7 },
+ {1, aisc8 },{1, aisc9 },{1, aisc10 },{1, aisc11 },{1, aisc12 },{1, aisc13 },{1, aisc14 },{1, aisc15 },
+ {2, jmp0 },{2, jmp1 },{0, illegal },{0, illegal },{0, illegal },{0, illegal },{0, illegal },{0, illegal },
+ {2, jsr0 },{2, jsr1 },{0, illegal },{0, illegal },{0, illegal },{0, illegal },{0, illegal },{0, illegal },
+ {1, stii0 },{1, stii1 },{1, stii2 },{1, stii3 },{1, stii4 },{1, stii5 },{1, stii6 },{1, stii7 },
+ {1, stii8 },{1, stii9 },{1, stii10 },{1, stii11 },{1, stii12 },{1, stii13 },{1, stii14 },{1, stii15 },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, lqid },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jid }
+};
+
+static ADDRESS_MAP_START( cop410_RAM, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x40) AM_RAM
+ADDRESS_MAP_END
+
+/****************************************************************************
+ * Initialize emulation
+ ****************************************************************************/
+static void cop410_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int i;
+
+ memset(&R, 0, sizeof(R));
+ R.G_mask = 0x0F;
+ R.D_mask = 0x0F;
+
+ for (i=0; i<256; i++) InstLen[i]=1;
+
+ InstLen[0x60] = InstLen[0x61] = InstLen[0x68] = InstLen[0x69] = InstLen[0x33] = InstLen[0x23] = 2;
+
+ for (i=0; i<256; i++) LBIops[i] = 0;
+ for (i=0x08; i<0x10; i++) LBIops[i] = 1;
+ for (i=0x18; i<0x20; i++) LBIops[i] = 1;
+ for (i=0x28; i<0x30; i++) LBIops[i] = 1;
+ for (i=0x38; i<0x40; i++) LBIops[i] = 1;
+
+ state_save_register_item("cop410", index, PC);
+ state_save_register_item("cop410", index, R.PREVPC);
+ state_save_register_item("cop410", index, A);
+ state_save_register_item("cop410", index, B);
+ state_save_register_item("cop410", index, C);
+ state_save_register_item("cop410", index, EN);
+ state_save_register_item("cop410", index, G);
+ state_save_register_item("cop410", index, Q);
+ state_save_register_item("cop410", index, SA);
+ state_save_register_item("cop410", index, SB);
+ state_save_register_item("cop410", index, SIO);
+ state_save_register_item("cop410", index, SKL);
+ state_save_register_item("cop410", index, skip);
+ state_save_register_item("cop410", index, skipLBI);
+ state_save_register_item("cop410", index, R.G_mask);
+ state_save_register_item("cop410", index, R.D_mask);
+}
+
+static void cop411_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ cop410_init(index, clock, config, irqcallback);
+
+ /* the COP411 is like the COP410, just with less output ports */
+ R.G_mask = 0x07;
+ R.D_mask = 0x03;
+}
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+static void cop410_reset(void)
+{
+ PC = 0;
+ A = 0;
+ B = 0;
+ C = 0;
+ OUT_D(0);
+ EN = 0;
+ WRITE_G(0);
+}
+
+/****************************************************************************
+ * Execute cycles CPU cycles. Return number of cycles really executed
+ ****************************************************************************/
+static int cop410_execute(int cycles)
+{
+ unsigned opcode;
+
+ cop410_ICount = cycles;
+
+ do
+ {
+ prevPC = PC;
+
+ CALL_MAME_DEBUG;
+
+ opcode = ROM(PC);
+
+ if (skipLBI == 1)
+ {
+ if (LBIops[opcode] == 0)
+ {
+ skipLBI = 0;
+ }
+ else {
+ cop410_ICount -=cop410_opcode_main[opcode].cycles;
+
+ PC += InstLen[opcode];
+ }
+ }
+
+ if (skipLBI == 0)
+ {
+ int inst_cycles = cop410_opcode_main[opcode].cycles;
+ PC++;
+ (*(cop410_opcode_main[opcode].function))();
+ cop410_ICount -= inst_cycles;
+
+ if (skip == 1) {
+ opcode=ROM(PC);
+ cop410_ICount -=cop410_opcode_main[opcode].cycles;
+ PC += InstLen[opcode];
+ skip = 0;
+ }
+ }
+ } while (cop410_ICount>0);
+
+
+ return cycles - cop410_ICount;
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void cop410_get_context (void *dst)
+{
+ if( dst )
+ *(COP410_Regs*)dst = R;
+}
+
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void cop410_set_context (void *src)
+{
+ if( src )
+ R = *(COP410_Regs*)src;
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void cop410_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + COP400_PC: PC = info->i; break;
+
+ case CPUINFO_INT_REGISTER + COP400_A: A = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_B: B = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_C: C = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_EN: EN = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_G: G = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_Q: Q = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_SA: SA = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_SB: SB = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_SIO: SIO = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_SKL: SKL = info->i; break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void cop410_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(R); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = COP400_CLOCK_DIVIDER; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 2; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 9; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; /* Really 6 */ break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 9; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = prevPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + COP400_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + COP400_A: info->i = A; break;
+ case CPUINFO_INT_REGISTER + COP400_B: info->i = B; break;
+ case CPUINFO_INT_REGISTER + COP400_C: info->i = C; break;
+ case CPUINFO_INT_REGISTER + COP400_EN: info->i = EN; break;
+ case CPUINFO_INT_REGISTER + COP400_G: info->i = G; break;
+ case CPUINFO_INT_REGISTER + COP400_Q: info->i = Q; break;
+ case CPUINFO_INT_REGISTER + COP400_SA: info->i = SA; break;
+ case CPUINFO_INT_REGISTER + COP400_SB: info->i = SB; break;
+ case CPUINFO_INT_REGISTER + COP400_SIO: info->i = SIO; break;
+ case CPUINFO_INT_REGISTER + COP400_SKL: info->i = SKL; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = cop410_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = cop410_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = cop410_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = cop410_init; break;
+ case CPUINFO_PTR_RESET: info->reset = cop410_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = cop410_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = cop410_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cop410_ICount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA:
+ info->internal_map = construct_map_cop410_RAM; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "COP410"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "National Semiconductor COP410"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2006 MAME Team"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, " ");
+ break;
+
+ case CPUINFO_STR_REGISTER + COP400_PC: sprintf(info->s, "PC:%04X", PC); break;
+ case CPUINFO_STR_REGISTER + COP400_A: sprintf(info->s, "A:%01X", A ); break;
+ case CPUINFO_STR_REGISTER + COP400_B: sprintf(info->s, "B:%02X", B ); break;
+ case CPUINFO_STR_REGISTER + COP400_C: sprintf(info->s, "C:%01X", C); break;
+ case CPUINFO_STR_REGISTER + COP400_EN: sprintf(info->s, "EN:%01X", EN); break;
+ case CPUINFO_STR_REGISTER + COP400_G: sprintf(info->s, "G:%01X", G); break;
+ case CPUINFO_STR_REGISTER + COP400_Q: sprintf(info->s, "Q:%02X", Q); break;
+ case CPUINFO_STR_REGISTER + COP400_SA: sprintf(info->s, "SA:%04X", SA); break;
+ case CPUINFO_STR_REGISTER + COP400_SB: sprintf(info->s, "SB:%04X", SB); break;
+ case CPUINFO_STR_REGISTER + COP400_SIO: sprintf(info->s, "SIO:%01X", SIO); break;
+ case CPUINFO_STR_REGISTER + COP400_SKL: sprintf(info->s, "SKL:%01X", SKL); break;
+ }
+}
+
+void cop411_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = cop411_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "COP411"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "National Semiconductor COP411"); break;
+
+ default: cop410_get_info(state, info); break;
+ }
+}
diff --git a/src/emu/cpu/cop400/cop410ds.c b/src/emu/cpu/cop400/cop410ds.c
new file mode 100644
index 00000000000..23c3af1a087
--- /dev/null
+++ b/src/emu/cpu/cop400/cop410ds.c
@@ -0,0 +1,336 @@
+/**************************************************************************
+ * National Semiconductor COP410 Emulator *
+ * *
+ * Copyright (C) 2006 MAME Team *
+ **************************************************************************/
+
+#include "cpuintrf.h"
+
+offs_t cop410_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int op;
+ int cnt = 1;
+ UINT16 addr;
+ UINT8 op2;
+ UINT32 flags = 0;
+
+ op = oprom[0];
+
+ if ((op >= 0x80 && op <= 0xBE) || (op >= 0xC0 && op <= 0xFE))
+ {
+ if ((pc & 0x3E0) >= 0x80 && (pc & 0x3E0) < 0x100) //JP pages 2,3
+ {
+ addr = (UINT16)((pc & 0x380) | (op & 0x7F));
+ sprintf(buffer,"JP %x",addr);
+ }
+ else
+ {
+ if ((op & 0xC0) == 0xC0) //JP other pages
+ {
+ addr = (UINT16)((pc & 0x3C0) | (op & 0x3F));
+ sprintf(buffer,"JP %x",addr);
+ }
+ else //JSRP
+ {
+ addr = (UINT16)(0x80 | (op & 0x3F));
+ sprintf(buffer,"JSRP %x",addr);
+ flags = DASMFLAG_STEP_OVER;
+ }
+ }
+ }
+ else if (op >= 0x08 && op <= 0x0F)
+ {
+ sprintf(buffer,"LBI 0,%u",((op & 0xF) + 1) & 0xF);
+ }
+ else if (op >= 0x18 && op <= 0x1F)
+ {
+ sprintf(buffer,"LBI 1,%u",((op & 0xF) + 1) & 0xF);
+ }
+ else if (op >= 0x28 && op <= 0x2F)
+ {
+ sprintf(buffer,"LBI 2,%u",((op & 0xF) + 1) & 0xF);
+ }
+ else if (op >= 0x38 && op <= 0x3F)
+ {
+ sprintf(buffer,"LBI 3,%u",((op & 0xF) + 1) & 0xF);
+ }
+ else if (op >= 0x51 && op <= 0x5F)
+ {
+ sprintf(buffer,"AISC %u",op & 0xF);
+ }
+ else if (op >= 0x60 && op <= 0x61)
+ {
+ addr = ((op & 0x01) << 8) | oprom[1];
+ sprintf(buffer,"JMP %x",addr);
+ cnt = 2;
+ }
+ else if (op >= 0x68 && op <= 0x69)
+ {
+ addr = ((op & 0x01) << 8) | oprom[1];
+ sprintf(buffer,"JSR %x",addr);
+ flags = DASMFLAG_STEP_OVER;
+ cnt = 2;
+ }
+ else if (op >= 0x70 && op <= 0x7F)
+ {
+ sprintf(buffer,"STII %u",op & 0xF);
+ }
+ else
+ {
+ switch (op)
+ {
+ case 0:
+ sprintf(buffer,"CLRA");
+ break;
+
+ case 1:
+ sprintf(buffer,"SKMBZ 0");
+ break;
+
+ case 2:
+ sprintf(buffer,"XOR");
+ break;
+
+ case 3:
+ sprintf(buffer,"SKMBZ 2");
+ break;
+
+ case 4:
+ sprintf(buffer,"XIS 0");
+ break;
+
+ case 5:
+ sprintf(buffer,"LD 0");
+ break;
+
+ case 6:
+ sprintf(buffer,"X 0");
+ break;
+
+ case 7:
+ sprintf(buffer,"XDS 0");
+ break;
+
+ case 0x11:
+ sprintf(buffer,"SKMBZ 1");
+ break;
+
+ case 0x13:
+ sprintf(buffer,"SKMBZ 3");
+ break;
+
+ case 0x14:
+ sprintf(buffer,"XIS 1");
+ break;
+
+ case 0x15:
+ sprintf(buffer,"LD 1");
+ break;
+
+ case 0x16:
+ sprintf(buffer,"X 1");
+ break;
+
+ case 0x17:
+ sprintf(buffer,"XDS 1");
+ break;
+
+ case 0x20:
+ sprintf(buffer,"SKC");
+ break;
+
+ case 0x21:
+ sprintf(buffer,"SKE");
+ break;
+
+ case 0x22:
+ sprintf(buffer,"SC");
+ break;
+
+ case 0x23:
+ addr = (UINT16)(oprom[1] & 0x3F);
+ sprintf(buffer,"XAD %x,%x",((addr & 0x30) >> 4),addr & 0x0F);
+ cnt = 2;
+ break;
+
+ case 0x24:
+ sprintf(buffer,"XIS 2");
+ break;
+
+ case 0x25:
+ sprintf(buffer,"LD 2");
+ break;
+
+ case 0x26:
+ sprintf(buffer,"X 2");
+ break;
+
+ case 0x27:
+ sprintf(buffer,"XDS 2");
+ break;
+
+ case 0x30:
+ sprintf(buffer,"ASC");
+ break;
+
+ case 0x31:
+ sprintf(buffer,"ADD");
+ break;
+
+ case 0x32:
+ sprintf(buffer,"RC");
+ break;
+
+ case 0x33:
+ op2 = oprom[1];
+ cnt = 2;
+
+ if (op2 >= 0x60 || op2 <= 0x6F)
+ {
+ sprintf(buffer,"LEI %x",op2 & 0xF);
+ }
+ else
+ {
+ switch (op2)
+ {
+ case 0x01:
+ sprintf(buffer,"SKGBZ 0");
+ break;
+
+ case 0x03:
+ sprintf(buffer,"SKGBZ 2");
+ break;
+
+ case 0x11:
+ sprintf(buffer,"SKGBZ 1");
+ break;
+
+ case 0x13:
+ sprintf(buffer,"SKGBZ 3");
+ break;
+
+ case 0x21:
+ sprintf(buffer,"SKGZ");
+ break;
+
+ case 0x2A:
+ sprintf(buffer,"ING");
+ break;
+
+ case 0x2E:
+ sprintf(buffer,"INL");
+ break;
+
+ case 0x3A:
+ sprintf(buffer,"OMG");
+ break;
+
+ case 0x3C:
+ sprintf(buffer,"CAMQ");
+ break;
+
+ case 0x3E:
+ sprintf(buffer,"OBD");
+ break;
+
+ default:
+ sprintf(buffer,"Invalid");
+ break;
+ }
+ break;
+ }
+
+ case 0x34:
+ sprintf(buffer,"XIS 3");
+ break;
+
+ case 0x35:
+ sprintf(buffer,"LD 3");
+ break;
+
+ case 0x36:
+ sprintf(buffer,"X 3");
+ break;
+
+ case 0x37:
+ sprintf(buffer,"XDS 3");
+ break;
+
+ case 0x40:
+ sprintf(buffer,"COMP");
+ break;
+
+ case 0x42:
+ sprintf(buffer,"RMB 2");
+ break;
+
+ case 0x43:
+ sprintf(buffer,"RMB 3");
+ break;
+
+ case 0x44:
+ sprintf(buffer,"NOP");
+ break;
+
+ case 0x45:
+ sprintf(buffer,"RMB 1");
+ break;
+
+ case 0x46:
+ sprintf(buffer,"SMB 2");
+ break;
+
+ case 0x47:
+ sprintf(buffer,"SMB 1");
+ break;
+
+ case 0x48:
+ sprintf(buffer,"RET");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ case 0x49:
+ sprintf(buffer,"RETSK");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ case 0x4B:
+ sprintf(buffer,"SMB 3");
+ break;
+
+ case 0x4C:
+ sprintf(buffer,"RMB 0");
+ break;
+
+ case 0x4D:
+ sprintf(buffer,"SMB 0");
+ break;
+
+ case 0x4E:
+ sprintf(buffer,"CBA");
+ break;
+
+ case 0x4F:
+ sprintf(buffer,"XAS");
+ break;
+
+ case 0x50:
+ sprintf(buffer,"CAB");
+ break;
+
+ case 0xBF:
+ sprintf(buffer,"LQID");
+ break;
+
+ case 0xFF:
+ sprintf(buffer,"JID");
+ break;
+
+ default:
+ sprintf(buffer,"Invalid");
+ break;
+ }
+ }
+
+ return cnt | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/cop400/cop420.c b/src/emu/cpu/cop400/cop420.c
new file mode 100644
index 00000000000..12f0d0d793f
--- /dev/null
+++ b/src/emu/cpu/cop400/cop420.c
@@ -0,0 +1,407 @@
+/**************************************************************************
+ * National Semiconductor COP420 Emulator *
+ * *
+ * Copyright (C) 2006 MAME Team *
+ **************************************************************************/
+
+/*
+
+ TODO:
+
+ - serial I/O
+ - interrupt
+
+*/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "cop400.h"
+
+/* The opcode table now is a combination of cycle counts and function pointers */
+typedef struct {
+ unsigned cycles;
+ void (*function) (void);
+} s_opcode;
+
+#define UINT1 UINT8
+#define UINT4 UINT8
+#define UINT6 UINT8
+#define UINT10 UINT16
+
+typedef struct
+{
+ UINT10 PC;
+ UINT10 PREVPC;
+ UINT4 A;
+ UINT6 B;
+ UINT1 C;
+ UINT4 EN;
+ UINT4 G;
+ UINT8 Q;
+ UINT10 SA, SB, SC;
+ UINT4 SIO;
+ UINT1 SKL;
+ UINT8 skip, skipLBI;
+ UINT1 timerlatch;
+ UINT16 counter;
+ UINT8 G_mask;
+ UINT8 D_mask;
+} COP420_Regs;
+
+static COP420_Regs R;
+static int cop420_ICount;
+
+static int InstLen[256];
+static int LBIops[256];
+static int LBIops33[256];
+
+#include "420ops.c"
+
+static s_opcode cop420_opcode_op33[256]=
+{
+ {1, inil },{1, skgbz0 },{1, illegal },{1, skgbz2 },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, skgbz1 },{1, illegal },{1, skgbz3 },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, skgz },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, inin },{1, illegal },{1, ing },{1, illegal },{1, cqma },{1, illegal },{1, inl },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, omg },{1, illegal },{1, camq },{1, illegal },{1, obd },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, ogi0 },{1, ogi1 },{1, ogi2 },{1, ogi3 },{1, ogi4 },{1, ogi5 },{1, ogi6 },{1, ogi7 },
+ {1, ogi8 },{1, ogi9 },{1, ogi10 },{1, ogi11 },{1, ogi12 },{1, ogi13 },{1, ogi14 },{1, ogi15 },
+ {1, lei0 },{1, lei1 },{1, lei2 },{1, lei3 },{1, lei4 },{1, lei5 },{1, lei6 },{1, lei7 },
+ {1, lei8 },{1, lei9 },{1, lei10 },{1, lei11 },{1, lei12 },{1, lei13 },{1, lei14 },{1, lei15 },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, lbi0_1 },{1, lbi0_2 },{1, lbi0_3 },{1, lbi0_4 },{1, lbi0_5 },{1, lbi0_6 },{1, lbi0_7 },
+ {1, lbi0_8 },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, lbi1_1 },{1, lbi1_2 },{1, lbi1_3 },{1, lbi1_4 },{1, lbi1_5 },{1, lbi1_6 },{1, lbi1_7 },
+ {1, lbi1_8 },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, lbi2_1 },{1, lbi2_2 },{1, lbi2_3 },{1, lbi2_4 },{1, lbi2_5 },{1, lbi2_6 },{1, lbi2_7 },
+ {1, lbi2_8 },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, lbi3_1 },{1, lbi3_2 },{1, lbi3_3 },{1, lbi3_4 },{1, lbi3_5 },{1, lbi3_6 },{1, lbi3_7 },
+ {1, lbi3_8 },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },
+ {1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal },{1, illegal }
+};
+
+static void cop420_op33(void)
+{
+ (*(cop420_opcode_op33[ROM(PC++)].function))();
+}
+
+static s_opcode cop420_opcode_main[256]=
+{
+ {1, clra },{1, skmbz0 },{1, xor },{1, skmbz2 },{1, xis0 },{1, ld0 },{1, x0 },{1, xds0 },
+ {1, lbi0_9 },{1, lbi0_10 },{1, lbi0_11 },{1, lbi0_12 },{1, lbi0_13 },{1, lbi0_14 },{1, lbi0_15 },{1, lbi0_0 },
+ {1, casc },{1, skmbz1 },{1, xabr },{1, skmbz3 },{1, xis0 },{1, ld1 },{1, x1 },{1, xds1 },
+ {1, lbi1_9 },{1, lbi1_10 },{1, lbi1_11 },{1, lbi1_12 },{1, lbi1_13 },{1, lbi1_14 },{1, lbi1_15 },{1, lbi1_0 },
+ {1, skc },{1, ske },{1, sc },{2, xad },{1, xis2 },{1, ld2 },{1, x2 },{1, xds2 },
+ {1, lbi2_9 },{1, lbi2_10 },{1, lbi2_11 },{1, lbi2_12 },{1, lbi2_13 },{1, lbi2_14 },{1, lbi2_15 },{1, lbi2_0 },
+ {1, asc },{1, add },{1, rc },{2, cop420_op33 },{1, xis3 },{1, ld3 },{1, x3 },{1, xds3 },
+ {1, lbi3_9 },{1, lbi3_10 },{1, lbi3_11 },{1, lbi3_12 },{1, lbi3_13 },{1, lbi3_14 },{1, lbi3_15 },{1, lbi3_0 },
+ {1, comp },{1, skt },{1, rmb2 },{1, rmb2 },{1, nop },{1, rmb1 },{1, smb2 },{1, smb1 },
+ {1, ret },{1, retsk },{1, adt },{1, smb3 },{1, rmb0 },{1, smb0 },{1, cba },{1, xas },
+ {1, cab },{1, aisc1 },{1, aisc2 },{1, aisc3 },{1, aisc4 },{1, aisc5 },{1, aisc6 },{1, aisc7 },
+ {1, aisc8 },{1, aisc9 },{1, aisc10 },{1, aisc11 },{1, aisc12 },{1, aisc13 },{1, aisc14 },{1, aisc15 },
+ {2, jmp0 },{2, jmp1 },{2, jmp2 },{2, jmp3 },{0, illegal },{0, illegal },{0, illegal },{0, illegal },
+ {2, jsr0 },{2, jsr1 },{2, jsr2 },{2, jsr3 },{0, illegal },{0, illegal },{0, illegal },{0, illegal },
+ {1, stii0 },{1, stii1 },{1, stii2 },{1, stii3 },{1, stii4 },{1, stii5 },{1, stii6 },{1, stii7 },
+ {1, stii8 },{1, stii9 },{1, stii10 },{1, stii11 },{1, stii12 },{1, stii13 },{1, stii14 },{1, stii15 },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{2, lqid },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },
+ {1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jp },{1, jid }
+};
+
+static ADDRESS_MAP_START( cop420_RAM, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x40) AM_RAM
+ADDRESS_MAP_END
+
+/****************************************************************************
+ * Initialize emulation
+ ****************************************************************************/
+static void cop420_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int i;
+
+ memset(&R, 0, sizeof(R));
+ R.G_mask = 0x0F;
+ R.D_mask = 0x0F;
+
+ R.counter = 0x00;
+
+ for (i=0; i<256; i++) InstLen[i]=1;
+
+ InstLen[0x60] = InstLen[0x61] = InstLen[0x62] = InstLen[0x63] =
+ InstLen[0x68] = InstLen[0x69] = InstLen[0x6a] = InstLen[0x6b] =
+ InstLen[0x33] = InstLen[0x23] = 2;
+
+ for (i=0; i<256; i++) LBIops[i] = 0;
+ for (i=0x08; i<0x10; i++) LBIops[i] = 1;
+ for (i=0x18; i<0x20; i++) LBIops[i] = 1;
+ for (i=0x28; i<0x30; i++) LBIops[i] = 1;
+ for (i=0x38; i<0x40; i++) LBIops[i] = 1;
+
+ for (i=0; i<256; i++) LBIops33[i] = 0;
+ for (i=0x81; i<0x89; i++) LBIops33[i] = 1;
+ for (i=0x91; i<0x99; i++) LBIops33[i] = 1;
+ for (i=0xa1; i<0xa9; i++) LBIops33[i] = 1;
+ for (i=0xb1; i<0xb9; i++) LBIops33[i] = 1;
+
+ state_save_register_item("cop420", index, PC);
+ state_save_register_item("cop420", index, R.PREVPC);
+ state_save_register_item("cop420", index, A);
+ state_save_register_item("cop420", index, B);
+ state_save_register_item("cop420", index, C);
+ state_save_register_item("cop420", index, EN);
+ state_save_register_item("cop420", index, G);
+ state_save_register_item("cop420", index, Q);
+ state_save_register_item("cop420", index, SA);
+ state_save_register_item("cop420", index, SB);
+ state_save_register_item("cop420", index, SC);
+ state_save_register_item("cop420", index, SIO);
+ state_save_register_item("cop420", index, SKL);
+ state_save_register_item("cop420", index, skip);
+ state_save_register_item("cop420", index, skipLBI);
+ state_save_register_item("cop420", index, R.timerlatch);
+ state_save_register_item("cop420", index, R.counter);
+ state_save_register_item("cop420", index, R.G_mask);
+ state_save_register_item("cop420", index, R.D_mask);
+}
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+static void cop420_reset(void)
+{
+ PC = 0;
+ A = 0;
+ B = 0;
+ C = 0;
+ OUT_D(0);
+ EN = 0;
+ WRITE_G(0);
+}
+
+/****************************************************************************
+ * Execute cycles CPU cycles. Return number of cycles really executed
+ ****************************************************************************/
+static int cop420_execute(int cycles)
+{
+ unsigned opcode;
+
+ cop420_ICount = cycles;
+
+ do
+ {
+ prevPC = PC;
+
+ CALL_MAME_DEBUG;
+
+ opcode = ROM(PC);
+
+ if (skipLBI == 1)
+ {
+ int is_lbi = 0;
+
+ if (opcode == 0x33)
+ {
+ is_lbi = LBIops33[ROM(PC+1)];
+ }
+ else
+ {
+ is_lbi = LBIops[opcode];
+ }
+
+ if (is_lbi == 0)
+ {
+ skipLBI = 0;
+ }
+ else {
+ cop420_ICount -= cop420_opcode_main[opcode].cycles;
+
+ PC += InstLen[opcode];
+ }
+ }
+
+ if (skipLBI == 0)
+ {
+ int inst_cycles = cop420_opcode_main[opcode].cycles;
+ PC++;
+ (*(cop420_opcode_main[opcode].function))();
+ cop420_ICount -= inst_cycles;
+
+ if (skip == 1) {
+ opcode=ROM(PC);
+ cop420_ICount -= cop420_opcode_main[opcode].cycles;
+ PC += InstLen[opcode];
+ skip = 0;
+ }
+ }
+
+ /* counter handling */
+ R.counter += cop420_opcode_main[opcode].cycles;
+ if (R.counter > 1024)
+ {
+ R.timerlatch = 1;
+ R.counter = 0;
+ }
+
+ } while (cop420_ICount > 0);
+
+ return cycles - cop420_ICount;
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void cop420_get_context (void *dst)
+{
+ if( dst )
+ *(COP420_Regs*)dst = R;
+}
+
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void cop420_set_context (void *src)
+{
+ if( src )
+ R = *(COP420_Regs*)src;
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void cop420_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + COP400_PC: PC = info->i; break;
+
+ case CPUINFO_INT_REGISTER + COP400_A: A = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_B: B = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_C: C = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_EN: EN = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_G: G = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_Q: Q = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_SA: SA = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_SB: SB = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_SC: SC = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_SIO: SIO = info->i; break;
+ case CPUINFO_INT_REGISTER + COP400_SKL: SKL = info->i; break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void cop420_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(R); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = COP400_CLOCK_DIVIDER; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 2; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 10; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; /* Really 6 */ break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 9; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = prevPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + COP400_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + COP400_A: info->i = A; break;
+ case CPUINFO_INT_REGISTER + COP400_B: info->i = B; break;
+ case CPUINFO_INT_REGISTER + COP400_C: info->i = C; break;
+ case CPUINFO_INT_REGISTER + COP400_EN: info->i = EN; break;
+ case CPUINFO_INT_REGISTER + COP400_G: info->i = G; break;
+ case CPUINFO_INT_REGISTER + COP400_Q: info->i = Q; break;
+ case CPUINFO_INT_REGISTER + COP400_SA: info->i = SA; break;
+ case CPUINFO_INT_REGISTER + COP400_SB: info->i = SB; break;
+ case CPUINFO_INT_REGISTER + COP400_SC: info->i = SC; break;
+ case CPUINFO_INT_REGISTER + COP400_SIO: info->i = SIO; break;
+ case CPUINFO_INT_REGISTER + COP400_SKL: info->i = SKL; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = cop420_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = cop420_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = cop420_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = cop420_init; break;
+ case CPUINFO_PTR_RESET: info->reset = cop420_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = cop420_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = cop420_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cop420_ICount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA:
+ info->internal_map = construct_map_cop420_RAM; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "COP420"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "National Semiconductor COP420"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2006 MAME Team"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, " ");
+ break;
+
+ case CPUINFO_STR_REGISTER + COP400_PC: sprintf(info->s, "PC:%04X", PC); break;
+ case CPUINFO_STR_REGISTER + COP400_A: sprintf(info->s, "A:%01X", A ); break;
+ case CPUINFO_STR_REGISTER + COP400_B: sprintf(info->s, "B:%02X", B ); break;
+ case CPUINFO_STR_REGISTER + COP400_C: sprintf(info->s, "C:%01X", C); break;
+ case CPUINFO_STR_REGISTER + COP400_EN: sprintf(info->s, "EN:%01X", EN); break;
+ case CPUINFO_STR_REGISTER + COP400_G: sprintf(info->s, "G:%01X", G); break;
+ case CPUINFO_STR_REGISTER + COP400_Q: sprintf(info->s, "Q:%02X", Q); break;
+ case CPUINFO_STR_REGISTER + COP400_SA: sprintf(info->s, "SA:%04X", SA); break;
+ case CPUINFO_STR_REGISTER + COP400_SB: sprintf(info->s, "SB:%04X", SB); break;
+ case CPUINFO_STR_REGISTER + COP400_SC: sprintf(info->s, "SC:%04X", SC); break;
+ case CPUINFO_STR_REGISTER + COP400_SIO: sprintf(info->s, "SIO:%01X", SIO); break;
+ case CPUINFO_STR_REGISTER + COP400_SKL: sprintf(info->s, "SKL:%01X", SKL); break;
+ }
+}
diff --git a/src/emu/cpu/cop400/cop420ds.c b/src/emu/cpu/cop400/cop420ds.c
new file mode 100644
index 00000000000..b977f838d0a
--- /dev/null
+++ b/src/emu/cpu/cop400/cop420ds.c
@@ -0,0 +1,384 @@
+/**************************************************************************
+ * National Semiconductor COP420 Emulator *
+ * *
+ * Copyright (C) 2006 MAME Team *
+ **************************************************************************/
+
+#include "cpuintrf.h"
+
+offs_t cop420_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int op;
+ int cnt = 1;
+ UINT16 addr;
+ UINT8 op2;
+ UINT32 flags = 0;
+
+ op = oprom[0];
+
+ if ((op >= 0x80 && op <= 0xBE) || (op >= 0xC0 && op <= 0xFE))
+ {
+ if ((pc & 0x3E0) >= 0x80 && (pc & 0x3E0) < 0x100) //JP pages 2,3
+ {
+ addr = (UINT16)((pc & 0x380) | (op & 0x7F));
+ sprintf(buffer,"JP %x",addr);
+ }
+ else
+ {
+ if ((op & 0xC0) == 0xC0) //JP other pages
+ {
+ addr = (UINT16)((pc & 0x3C0) | (op & 0x3F));
+ sprintf(buffer,"JP %x",addr);
+ }
+ else //JSRP
+ {
+ addr = (UINT16)(0x80 | (op & 0x3F));
+ sprintf(buffer,"JSRP %x",addr);
+ flags = DASMFLAG_STEP_OVER;
+ }
+ }
+ }
+ else if (op >= 0x08 && op <= 0x0F)
+ {
+ sprintf(buffer,"LBI 0,%u",((op & 0xF) + 1) & 0xF);
+ }
+ else if (op >= 0x18 && op <= 0x1F)
+ {
+ sprintf(buffer,"LBI 1,%u",((op & 0xF) + 1) & 0xF);
+ }
+ else if (op >= 0x28 && op <= 0x2F)
+ {
+ sprintf(buffer,"LBI 2,%u",((op & 0xF) + 1) & 0xF);
+ }
+ else if (op >= 0x38 && op <= 0x3F)
+ {
+ sprintf(buffer,"LBI 3,%u",((op & 0xF) + 1) & 0xF);
+ }
+ else if (op >= 0x51 && op <= 0x5F)
+ {
+ sprintf(buffer,"AISC %u",op & 0xF);
+ }
+ else if (op >= 0x60 && op <= 0x63)
+ {
+ addr = ((op & 0x03) << 8) | oprom[1];
+ sprintf(buffer,"JMP %x",addr);
+ cnt = 2;
+ }
+ else if (op >= 0x68 && op <= 0x6B)
+ {
+ addr = ((op & 0x03) << 8) | oprom[1];
+ sprintf(buffer,"JSR %x",addr);
+ flags = DASMFLAG_STEP_OVER;
+ cnt = 2;
+ }
+ else if (op >= 0x70 && op <= 0x7F)
+ {
+ sprintf(buffer,"STII %u",op & 0xF);
+ }
+ else
+ {
+ switch (op)
+ {
+ case 0:
+ sprintf(buffer,"CLRA");
+ break;
+
+ case 1:
+ sprintf(buffer,"SKMBZ 0");
+ break;
+
+ case 2:
+ sprintf(buffer,"XOR");
+ break;
+
+ case 3:
+ sprintf(buffer,"SKMBZ 2");
+ break;
+
+ case 4:
+ sprintf(buffer,"XIS 0");
+ break;
+
+ case 5:
+ sprintf(buffer,"LD 0");
+ break;
+
+ case 6:
+ sprintf(buffer,"X 0");
+ break;
+
+ case 7:
+ sprintf(buffer,"XDS 0");
+ break;
+
+ case 0x10:
+ sprintf(buffer,"CASC");
+ break;
+
+ case 0x11:
+ sprintf(buffer,"SKMBZ 1");
+ break;
+
+ case 0x12:
+ sprintf(buffer,"XABR");
+ break;
+
+ case 0x13:
+ sprintf(buffer,"SKMBZ 3");
+ break;
+
+ case 0x14:
+ sprintf(buffer,"XIS 1");
+ break;
+
+ case 0x15:
+ sprintf(buffer,"LD 1");
+ break;
+
+ case 0x16:
+ sprintf(buffer,"X 1");
+ break;
+
+ case 0x17:
+ sprintf(buffer,"XDS 1");
+ break;
+
+ case 0x20:
+ sprintf(buffer,"SKC");
+ break;
+
+ case 0x21:
+ sprintf(buffer,"SKE");
+ break;
+
+ case 0x22:
+ sprintf(buffer,"SC");
+ break;
+
+ case 0x23:
+ addr = (UINT16)(oprom[1] & 0x3F);
+ sprintf(buffer,"XAD %x,%x",((addr & 0x30) >> 4),addr & 0x0F);
+ cnt = 2;
+ break;
+
+ case 0x24:
+ sprintf(buffer,"XIS 2");
+ break;
+
+ case 0x25:
+ sprintf(buffer,"LD 2");
+ break;
+
+ case 0x26:
+ sprintf(buffer,"X 2");
+ break;
+
+ case 0x27:
+ sprintf(buffer,"XDS 2");
+ break;
+
+ case 0x30:
+ sprintf(buffer,"ASC");
+ break;
+
+ case 0x31:
+ sprintf(buffer,"ADD");
+ break;
+
+ case 0x32:
+ sprintf(buffer,"RC");
+ break;
+
+ case 0x33:
+ op2 = oprom[1];
+ cnt = 2;
+
+ if (op2 >= 0x50 && op2 <= 0x5F)
+ {
+ sprintf(buffer,"OGI %u",op2 & 0xF);
+ }
+ else if (op2 >= 0x60 && op2 <= 0x6F)
+ {
+ sprintf(buffer,"LEI %u",op2 & 0xF);
+ }
+ else if (op2 >= 0x81 && op2 <= 0x88)
+ {
+ sprintf(buffer,"LBI 0,%u",op2 & 0xF);
+ }
+ else if (op2 >= 0x91 && op2 <= 0x98)
+ {
+ sprintf(buffer,"LBI 1,%u",op2 & 0xF);
+ }
+ else if (op2 >= 0xA1 && op2 <= 0xA8)
+ {
+ sprintf(buffer,"LBI 2,%u",op2 & 0xF);
+ }
+ else if (op2 >= 0xB1 && op2 <= 0xB8)
+ {
+ sprintf(buffer,"LBI 3,%u",op2 & 0xF);
+ }
+ else
+ {
+ switch (op2)
+ {
+ case 0x00:
+ sprintf(buffer,"INIL");
+ break;
+
+ case 0x01:
+ sprintf(buffer,"SKGBZ 0");
+ break;
+
+ case 0x03:
+ sprintf(buffer,"SKGBZ 2");
+ break;
+
+ case 0x11:
+ sprintf(buffer,"SKGBZ 1");
+ break;
+
+ case 0x13:
+ sprintf(buffer,"SKGBZ 3");
+ break;
+
+ case 0x21:
+ sprintf(buffer,"SKGZ");
+ break;
+
+ case 0x28:
+ sprintf(buffer,"ININ");
+ break;
+
+ case 0x2A:
+ sprintf(buffer,"ING");
+ break;
+
+ case 0x2C:
+ sprintf(buffer,"COMA");
+ break;
+
+ case 0x2E:
+ sprintf(buffer,"INL");
+ break;
+
+ case 0x3A:
+ sprintf(buffer,"OMG");
+ break;
+
+ case 0x3C:
+ sprintf(buffer,"CAMQ");
+ break;
+
+ case 0x3E:
+ sprintf(buffer,"OBD");
+ break;
+
+ default:
+ sprintf(buffer,"Invalid");
+ break;
+ }
+ }
+ break;
+
+ case 0x34:
+ sprintf(buffer,"XIS 3");
+ break;
+
+ case 0x35:
+ sprintf(buffer,"LD 3");
+ break;
+
+ case 0x36:
+ sprintf(buffer,"X 3");
+ break;
+
+ case 0x37:
+ sprintf(buffer,"XDS 3");
+ break;
+
+ case 0x40:
+ sprintf(buffer,"COMP");
+ break;
+
+ case 0x41:
+ sprintf(buffer,"SKT");
+ break;
+
+ case 0x42:
+ sprintf(buffer,"RMB 2");
+ break;
+
+ case 0x43:
+ sprintf(buffer,"RMB 3");
+ break;
+
+ case 0x44:
+ sprintf(buffer,"NOP");
+ break;
+
+ case 0x45:
+ sprintf(buffer,"RMB 1");
+ break;
+
+ case 0x46:
+ sprintf(buffer,"SMB 2");
+ break;
+
+ case 0x47:
+ sprintf(buffer,"SMB 1");
+ break;
+
+ case 0x48:
+ sprintf(buffer,"RET");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ case 0x49:
+ sprintf(buffer,"RETSK");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ case 0x4A:
+ sprintf(buffer,"ADT");
+ break;
+
+ case 0x4B:
+ sprintf(buffer,"SMB 3");
+ break;
+
+ case 0x4C:
+ sprintf(buffer,"RMB 0");
+ break;
+
+ case 0x4D:
+ sprintf(buffer,"SMB 0");
+ break;
+
+ case 0x4E:
+ sprintf(buffer,"CBA");
+ break;
+
+ case 0x4F:
+ sprintf(buffer,"XAS");
+ break;
+
+ case 0x50:
+ sprintf(buffer,"CAB");
+ break;
+
+ case 0xBF:
+ sprintf(buffer,"LQID");
+ break;
+
+ case 0xFF:
+ sprintf(buffer,"JID");
+ break;
+
+ default:
+ sprintf(buffer,"Invalid");
+ break;
+ }
+ }
+
+ return cnt | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/cp1610/1610dasm.c b/src/emu/cpu/cp1610/1610dasm.c
new file mode 100644
index 00000000000..ce131b7f70d
--- /dev/null
+++ b/src/emu/cpu/cp1610/1610dasm.c
@@ -0,0 +1,1488 @@
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "cp1610.h"
+
+unsigned cp1610_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT16 op = oprom[0];
+ UINT16 subop;
+ UINT16 ea, ea1, ea2;
+ unsigned size = 1;
+// const char *sym, *sym2;
+
+ switch( op )
+ {
+ /* opcode bitmask */
+ case 0x00: /* 0 000 000 000 */
+// sym = set_ea_info( 0, 12, EA_UINT8, EA_ZPG_RD );
+ sprintf(buffer, "HLT");
+ break;
+ case 0x001: /* 0 000 000 001 */
+ subop = oprom[1];
+ switch (subop & 0x3f8)
+ {
+ case 0x280: /* 1 010 000 xxx */
+ case 0x288: /* 1 010 001 xxx */
+ case 0x290: /* 1 010 010 xxx */
+ case 0x298: /* 1 010 011 xxx */
+ case 0x2a0: /* 1 010 100 xxx */
+ case 0x2a8: /* 1 010 101 xxx */
+ case 0x2b0: /* 1 010 110 xxx */
+ sprintf(buffer,"MVI@ (R%01d), R%01d",(subop&0x38)>>3,subop&7);
+ size += 1;
+ break;
+ case 0x2b8: /* 1 010 111 xxx */
+ ea1 = oprom[2];
+ ea2 = oprom[3];
+ ea = ((ea2&0xff)<<8) | (ea1&0xff);
+ sprintf(buffer,"MVII #%04X, R%01d",ea,subop&7);
+ size += 3;
+ break;
+ case 0x2c0: /* 1 011 000 xxx */
+ case 0x2c8: /* 1 011 001 xxx */
+ case 0x2d0: /* 1 011 010 xxx */
+ case 0x2d8: /* 1 011 011 xxx */
+ case 0x2e0: /* 1 011 100 xxx */
+ case 0x2e8: /* 1 011 101 xxx */
+ case 0x2f0: /* 1 011 110 xxx */
+ sprintf(buffer,"ADD@ (R%01d), R%01d",(subop&0x38)>>3,subop&7);
+ size += 1;
+ break;
+ case 0x2f8: /* 1 011 111 xxx */
+ ea1 = oprom[2];
+ ea2 = oprom[3];
+ ea = ((ea2&0xff)<<8) | (ea1&0xff);
+ sprintf(buffer,"ADDI #%04X, R%01d",ea,subop&7);
+ size += 3;
+ break;
+ case 0x300: /* 1 100 000 xxx */
+ case 0x308: /* 1 100 001 xxx */
+ case 0x310: /* 1 100 010 xxx */
+ case 0x318: /* 1 100 011 xxx */
+ case 0x320: /* 1 100 100 xxx */
+ case 0x328: /* 1 100 101 xxx */
+ case 0x330: /* 1 100 110 xxx */
+ sprintf(buffer,"SUB@ (R%01d), R%01d",(subop&0x38)>>3,subop&7);
+ size += 1;
+ break;
+ case 0x338: /* 1 100 111 xxx */
+ ea1 = oprom[2];
+ ea2 = oprom[3];
+ ea = ((ea2&0xff)<<8) | (ea1&0xff);
+ sprintf(buffer,"SUBI #%04X, R%01d",ea,subop&7);
+ size += 3;
+ break;
+ case 0x340: /* 1 101 000 xxx */
+ case 0x348: /* 1 101 001 xxx */
+ case 0x350: /* 1 101 010 xxx */
+ case 0x358: /* 1 101 011 xxx */
+ case 0x360: /* 1 101 100 xxx */
+ case 0x368: /* 1 101 101 xxx */
+ case 0x370: /* 1 101 110 xxx */
+ sprintf(buffer,"CMP@ (R%01d), R%01d",(subop&0x38)>>3,subop&7);
+ size += 1;
+ break;
+ case 0x378: /* 1 101 111 xxx */
+ ea1 = oprom[2];
+ ea2 = oprom[3];
+ ea = ((ea2&0xff)<<8) | (ea1&0xff);
+ sprintf(buffer,"CMPI #%04X, R%01d",ea,subop&7);
+ size += 3;
+ break;
+ case 0x380: /* 1 110 000 xxx */
+ case 0x388: /* 1 110 001 xxx */
+ case 0x390: /* 1 110 010 xxx */
+ case 0x398: /* 1 110 011 xxx */
+ case 0x3a0: /* 1 110 100 xxx */
+ case 0x3a8: /* 1 110 101 xxx */
+ case 0x3b0: /* 1 110 110 xxx */
+ sprintf(buffer,"AND@ (R%01d), R%01d",(subop&0x38)>>3,subop&7);
+ size += 1;
+ break;
+ case 0x3b8: /* 1 110 111 xxx */
+ ea1 = oprom[2];
+ ea2 = oprom[3];
+ ea = ((ea2&0xff)<<8) | (ea1&0xff);
+ sprintf(buffer,"ANDI #%04X, R%01d",ea,subop&7);
+ size += 3;
+ break;
+ case 0x3c0: /* 1 111 000 xxx */
+ case 0x3c8: /* 1 111 001 xxx */
+ case 0x3d0: /* 1 111 010 xxx */
+ case 0x3d8: /* 1 111 011 xxx */
+ case 0x3e0: /* 1 111 100 xxx */
+ case 0x3e8: /* 1 111 101 xxx */
+ case 0x3f0: /* 1 111 110 xxx */
+ sprintf(buffer,"XOR@ (R%01d), R%01d",(subop&0x38)>>3,subop&7);
+ size += 1;
+ break;
+ case 0x3f8: /* 1 111 111 xxx */
+ ea1 = oprom[2];
+ ea2 = oprom[3];
+ ea = ((ea2&0xff)<<8) | (ea1&0xff);
+ sprintf(buffer,"XORI #%04X, R%01d",ea,subop&7);
+ size += 3;
+ break;
+ default:
+ size += 1;
+ sprintf(buffer, "SDBD ????");
+ }
+ break;
+ case 0x002: /* 0 000 000 010 */
+ sprintf(buffer, "EIS");
+ break;
+ case 0x003: /* 0 000 000 011 */
+ sprintf(buffer, "DIS");
+ break;
+ case 0x004: /* 0 000 000 100 */
+ size += 2;
+ ea1 = oprom[1];
+ ea2 = oprom[2];
+ ea = ((ea1<<8)&0xfc00) + (ea2&0x3ff);
+ if ((ea1&0x300) == 0x300)
+ {
+ //?? set direct address
+ switch(ea1 & 0x03)
+ {
+ case 0:
+ sprintf(buffer, "J %04X",ea);
+ break;
+ case 1:
+ sprintf(buffer, "JE %04X",ea);
+ break;
+ case 2:
+ sprintf(buffer, "JD %04X",ea);
+ break;
+ case 3:
+ sprintf(buffer, "????");
+ break;
+ }
+ }
+ else
+ {
+ //?? set R?, return address
+ switch(ea1 & 0x03)
+ {
+ case 0:
+ sprintf(buffer, "JSR R%01d,%04X",((ea1&0x300)>>8)+4,ea);
+ break;
+ case 1:
+ sprintf(buffer, "JSRE R%01d,%04X",((ea1&0x300)>>8)+4,ea);
+ break;
+ case 2:
+ sprintf(buffer, "JSRD R%01d,%04X",((ea1&0x300)>>8)+4,ea);
+ break;
+ case 3:
+ sprintf(buffer, "????");
+ break;
+ }
+ }
+ break;
+ case 0x005: /* 0 000 000 101 */
+ sprintf(buffer, "TCI");
+ break;
+ case 0x006: /* 0 000 000 110 */
+ sprintf(buffer, "CLRC");
+ break;
+ case 0x007: /* 0 000 000 111 */
+ sprintf(buffer, "SETC");
+ break;
+ case 0x008: /* 0 000 001 000 */
+ case 0x009: /* 0 000 001 001 */
+ case 0x00a: /* 0 000 001 010 */
+ case 0x00b: /* 0 000 001 011 */
+ case 0x00c: /* 0 000 001 100 */
+ case 0x00d: /* 0 000 001 101 */
+ case 0x00e: /* 0 000 001 110 */
+ case 0x00f: /* 0 000 001 111 */
+ sprintf(buffer, "INCR R%01d",op&0x7);
+ break;
+ case 0x010: /* 0 000 010 000 */
+ case 0x011: /* 0 000 010 001 */
+ case 0x012: /* 0 000 010 010 */
+ case 0x013: /* 0 000 010 011 */
+ case 0x014: /* 0 000 010 100 */
+ case 0x015: /* 0 000 010 101 */
+ case 0x016: /* 0 000 010 110 */
+ case 0x017: /* 0 000 010 111 */
+ sprintf(buffer, "DECR R%01d",op&0x7);
+ break;
+ case 0x018: /* 0 000 011 000 */
+ case 0x019: /* 0 000 011 001 */
+ case 0x01a: /* 0 000 011 010 */
+ case 0x01b: /* 0 000 011 011 */
+ case 0x01c: /* 0 000 011 100 */
+ case 0x01d: /* 0 000 011 101 */
+ case 0x01e: /* 0 000 011 110 */
+ case 0x01f: /* 0 000 011 111 */
+ sprintf(buffer, "COMR R%01d",op&0x7);
+ break;
+ case 0x020: /* 0 000 100 000 */
+ case 0x021: /* 0 000 100 001 */
+ case 0x022: /* 0 000 100 010 */
+ case 0x023: /* 0 000 100 011 */
+ case 0x024: /* 0 000 100 100 */
+ case 0x025: /* 0 000 100 101 */
+ case 0x026: /* 0 000 100 110 */
+ case 0x027: /* 0 000 100 111 */
+ sprintf(buffer, "NEGR R%01d",op&0x7);
+ break;
+ case 0x028: /* 0 000 101 000 */
+ case 0x029: /* 0 000 101 001 */
+ case 0x02a: /* 0 000 101 010 */
+ case 0x02b: /* 0 000 101 011 */
+ case 0x02c: /* 0 000 101 100 */
+ case 0x02d: /* 0 000 101 101 */
+ case 0x02e: /* 0 000 101 110 */
+ case 0x02f: /* 0 000 101 111 */
+ sprintf(buffer, "ADCR R%01d",op&0x7);
+ break;
+ case 0x030: /* 0 000 110 000 */
+ case 0x031: /* 0 000 110 001 */
+ case 0x032: /* 0 000 110 010 */
+ case 0x033: /* 0 000 110 011 */
+ sprintf(buffer, "GSWD R%01d",op&0x3);
+ break;
+ case 0x034: /* 0 000 110 100 */
+ case 0x035: /* 0 000 110 101 */
+ sprintf(buffer, "NOP (%01d)",op&0x1); //???
+ break;
+ case 0x036: /* 0 000 110 110 */
+ case 0x037: /* 0 000 110 111 */
+ sprintf(buffer, "SIN");
+ break;
+ case 0x038: /* 0 000 111 000 */
+ case 0x039: /* 0 000 111 001 */
+ case 0x03a: /* 0 000 111 010 */
+ case 0x03b: /* 0 000 111 011 */
+ case 0x03c: /* 0 000 111 100 */
+ case 0x03d: /* 0 000 111 101 */
+ case 0x03e: /* 0 000 111 110 */
+ case 0x03f: /* 0 000 111 111 */
+ sprintf(buffer, "RSWD R%01d",op&0x7);
+ break;
+ case 0x040: /* 0 001 000 000 */
+ case 0x041: /* 0 001 000 001 */
+ case 0x042: /* 0 001 000 010 */
+ case 0x043: /* 0 001 000 011 */
+ sprintf(buffer, "SWAP R%01d,1",op&0x3);
+ break;
+ case 0x044: /* 0 001 000 100 */
+ case 0x045: /* 0 001 000 101 */
+ case 0x046: /* 0 001 000 110 */
+ case 0x047: /* 0 001 000 111 */
+ sprintf(buffer, "SWAP R%01d,2",op&0x3);
+ break;
+ case 0x048: /* 0 001 001 000 */
+ case 0x049: /* 0 001 001 001 */
+ case 0x04a: /* 0 001 001 010 */
+ case 0x04b: /* 0 001 001 011 */
+ sprintf(buffer, "SLL R%01d,1",op&0x3);
+ break;
+ case 0x04c: /* 0 001 001 100 */
+ case 0x04d: /* 0 001 001 101 */
+ case 0x04e: /* 0 001 001 110 */
+ case 0x04f: /* 0 001 001 111 */
+ sprintf(buffer, "SLL R%01d,2",op&0x3);
+ break;
+ case 0x050: /* 0 001 010 000 */
+ case 0x051: /* 0 001 010 001 */
+ case 0x052: /* 0 001 010 010 */
+ case 0x053: /* 0 001 010 011 */
+ sprintf(buffer, "RLC R%01d,1",op&0x3);
+ break;
+ case 0x054: /* 0 001 010 100 */
+ case 0x055: /* 0 001 010 101 */
+ case 0x056: /* 0 001 010 110 */
+ case 0x057: /* 0 001 010 111 */
+ sprintf(buffer, "RLC R%01d,2",op&0x3);
+ break;
+ case 0x058: /* 0 001 011 000 */
+ case 0x059: /* 0 001 011 001 */
+ case 0x05a: /* 0 001 011 010 */
+ case 0x05b: /* 0 001 011 011 */
+ sprintf(buffer, "SLLC R%01d,1",op&0x3);
+ break;
+ case 0x05c: /* 0 001 011 100 */
+ case 0x05d: /* 0 001 011 101 */
+ case 0x05e: /* 0 001 011 110 */
+ case 0x05f: /* 0 001 011 111 */
+ sprintf(buffer, "SLLC R%01d,2",op&0x3);
+ break;
+ case 0x060: /* 0 001 100 000 */
+ case 0x061: /* 0 001 100 001 */
+ case 0x062: /* 0 001 100 010 */
+ case 0x063: /* 0 001 100 011 */
+ sprintf(buffer, "SLR R%01d,1",op&0x3);
+ break;
+ case 0x064: /* 0 001 100 100 */
+ case 0x065: /* 0 001 100 101 */
+ case 0x066: /* 0 001 100 110 */
+ case 0x067: /* 0 001 100 111 */
+ sprintf(buffer, "SLR R%01d,2",op&0x3);
+ break;
+ case 0x068: /* 0 001 101 000 */
+ case 0x069: /* 0 001 101 001 */
+ case 0x06a: /* 0 001 101 010 */
+ case 0x06b: /* 0 001 101 011 */
+ sprintf(buffer, "SAR R%01d,1",op&0x3);
+ break;
+ case 0x06c: /* 0 001 101 100 */
+ case 0x06d: /* 0 001 101 101 */
+ case 0x06e: /* 0 001 101 110 */
+ case 0x06f: /* 0 001 101 111 */
+ sprintf(buffer, "SAR R%01d,2",op&0x3);
+ break;
+ case 0x070: /* 0 001 110 000 */
+ case 0x071: /* 0 001 110 001 */
+ case 0x072: /* 0 001 110 010 */
+ case 0x073: /* 0 001 110 011 */
+ sprintf(buffer, "RRC R%01d,1",op&0x3);
+ break;
+ case 0x074: /* 0 001 110 100 */
+ case 0x075: /* 0 001 110 101 */
+ case 0x076: /* 0 001 110 110 */
+ case 0x077: /* 0 001 110 111 */
+ sprintf(buffer, "RRC R%01d,2",op&0x3);
+ break;
+ case 0x078: /* 0 001 111 000 */
+ case 0x079: /* 0 001 111 001 */
+ case 0x07a: /* 0 001 111 010 */
+ case 0x07b: /* 0 001 111 011 */
+ sprintf(buffer, "SARC R%01d,1",op&0x3);
+ break;
+ case 0x07c: /* 0 001 111 100 */
+ case 0x07d: /* 0 001 111 101 */
+ case 0x07e: /* 0 001 111 110 */
+ case 0x07f: /* 0 001 111 111 */
+ sprintf(buffer, "SARC R%01d,2",op&0x3);
+ break;
+ case 0x080: /* 0 010 000 000 */
+ case 0x089: /* 0 010 001 001 */
+ case 0x092: /* 0 010 010 010 */
+ case 0x09b: /* 0 010 011 011 */
+ case 0x0a4: /* 0 010 100 100 */
+ case 0x0ad: /* 0 010 101 101 */
+ case 0x0b6: /* 0 010 110 110 */
+ case 0x0bf: /* 0 010 111 111 */
+ sprintf(buffer, "TSTR R%01d",op&0x7);
+ break;
+ case 0x087: /* 0 010 000 111 */
+ case 0x08f: /* 0 010 001 111 */
+ case 0x097: /* 0 010 010 111 */
+ case 0x09f: /* 0 010 011 111 */
+ case 0x0a7: /* 0 010 100 111 */
+ case 0x0af: /* 0 010 101 111 */
+ case 0x0b7: /* 0 010 110 111 */
+ sprintf(buffer, "JR R%01d",(op&0x38)>>3);
+ break;
+ case 0x081: /* 0 010 000 001 */
+ case 0x082: /* 0 010 000 010 */
+ case 0x083: /* 0 010 000 011 */
+ case 0x084: /* 0 010 000 100 */
+ case 0x085: /* 0 010 000 101 */
+ case 0x086: /* 0 010 000 110 */
+ case 0x088: /* 0 010 001 000 */
+ case 0x08a: /* 0 010 001 010 */
+ case 0x08b: /* 0 010 001 011 */
+ case 0x08c: /* 0 010 001 100 */
+ case 0x08d: /* 0 010 001 101 */
+ case 0x08e: /* 0 010 001 110 */
+ case 0x090: /* 0 010 010 000 */
+ case 0x091: /* 0 010 010 001 */
+ case 0x093: /* 0 010 010 011 */
+ case 0x094: /* 0 010 010 100 */
+ case 0x095: /* 0 010 010 101 */
+ case 0x096: /* 0 010 010 110 */
+ case 0x098: /* 0 010 011 000 */
+ case 0x099: /* 0 010 011 001 */
+ case 0x09a: /* 0 010 011 010 */
+ case 0x09c: /* 0 010 011 100 */
+ case 0x09d: /* 0 010 011 101 */
+ case 0x09e: /* 0 010 011 110 */
+ case 0x0a0: /* 0 010 100 000 */
+ case 0x0a1: /* 0 010 100 001 */
+ case 0x0a2: /* 0 010 100 010 */
+ case 0x0a3: /* 0 010 100 011 */
+ case 0x0a5: /* 0 010 100 101 */
+ case 0x0a6: /* 0 010 100 110 */
+ case 0x0a8: /* 0 010 101 000 */
+ case 0x0a9: /* 0 010 101 001 */
+ case 0x0aa: /* 0 010 101 010 */
+ case 0x0ab: /* 0 010 101 011 */
+ case 0x0ac: /* 0 010 101 100 */
+ case 0x0ae: /* 0 010 101 110 */
+ case 0x0b0: /* 0 010 110 000 */
+ case 0x0b1: /* 0 010 110 001 */
+ case 0x0b2: /* 0 010 110 010 */
+ case 0x0b3: /* 0 010 110 011 */
+ case 0x0b4: /* 0 010 110 100 */
+ case 0x0b5: /* 0 010 110 101 */
+ case 0x0b8: /* 0 010 111 000 */
+ case 0x0b9: /* 0 010 111 001 */
+ case 0x0ba: /* 0 010 111 010 */
+ case 0x0bb: /* 0 010 111 011 */
+ case 0x0bc: /* 0 010 111 100 */
+ case 0x0bd: /* 0 010 111 101 */
+ case 0x0be: /* 0 010 111 110 */
+ sprintf(buffer, "MOVR R%01d,R%01d",(op&0x38)>>3,op&0x7);
+ break;
+ case 0x0c0: /* 0 011 000 000 */
+ case 0x0c1: /* 0 011 000 001 */
+ case 0x0c2: /* 0 011 000 010 */
+ case 0x0c3: /* 0 011 000 011 */
+ case 0x0c4: /* 0 011 000 100 */
+ case 0x0c5: /* 0 011 000 101 */
+ case 0x0c6: /* 0 011 000 110 */
+ case 0x0c7: /* 0 011 000 111 */
+ case 0x0c8: /* 0 011 001 000 */
+ case 0x0c9: /* 0 011 001 001 */
+ case 0x0ca: /* 0 011 001 010 */
+ case 0x0cb: /* 0 011 001 011 */
+ case 0x0cc: /* 0 011 001 100 */
+ case 0x0cd: /* 0 011 001 101 */
+ case 0x0ce: /* 0 011 001 110 */
+ case 0x0cf: /* 0 011 001 111 */
+ case 0x0d0: /* 0 011 010 000 */
+ case 0x0d1: /* 0 011 010 001 */
+ case 0x0d2: /* 0 011 010 010 */
+ case 0x0d3: /* 0 011 010 011 */
+ case 0x0d4: /* 0 011 010 100 */
+ case 0x0d5: /* 0 011 010 101 */
+ case 0x0d6: /* 0 011 010 110 */
+ case 0x0d7: /* 0 011 010 111 */
+ case 0x0d8: /* 0 011 011 000 */
+ case 0x0d9: /* 0 011 011 001 */
+ case 0x0da: /* 0 011 011 010 */
+ case 0x0db: /* 0 011 011 011 */
+ case 0x0dc: /* 0 011 011 100 */
+ case 0x0dd: /* 0 011 011 101 */
+ case 0x0de: /* 0 011 011 110 */
+ case 0x0df: /* 0 011 011 111 */
+ case 0x0e0: /* 0 011 100 000 */
+ case 0x0e1: /* 0 011 100 001 */
+ case 0x0e2: /* 0 011 100 010 */
+ case 0x0e3: /* 0 011 100 011 */
+ case 0x0e4: /* 0 011 100 100 */
+ case 0x0e5: /* 0 011 100 101 */
+ case 0x0e6: /* 0 011 100 110 */
+ case 0x0e7: /* 0 011 100 111 */
+ case 0x0e8: /* 0 011 101 000 */
+ case 0x0e9: /* 0 011 101 001 */
+ case 0x0ea: /* 0 011 101 010 */
+ case 0x0eb: /* 0 011 101 011 */
+ case 0x0ec: /* 0 011 101 100 */
+ case 0x0ed: /* 0 011 101 101 */
+ case 0x0ee: /* 0 011 101 110 */
+ case 0x0ef: /* 0 011 101 111 */
+ case 0x0f0: /* 0 011 110 000 */
+ case 0x0f1: /* 0 011 110 001 */
+ case 0x0f2: /* 0 011 110 010 */
+ case 0x0f3: /* 0 011 110 011 */
+ case 0x0f4: /* 0 011 110 100 */
+ case 0x0f5: /* 0 011 110 101 */
+ case 0x0f6: /* 0 011 110 110 */
+ case 0x0f7: /* 0 011 110 111 */
+ case 0x0f8: /* 0 011 111 000 */
+ case 0x0f9: /* 0 011 111 001 */
+ case 0x0fa: /* 0 011 111 010 */
+ case 0x0fb: /* 0 011 111 011 */
+ case 0x0fc: /* 0 011 111 100 */
+ case 0x0fd: /* 0 011 111 101 */
+ case 0x0fe: /* 0 011 111 110 */
+ case 0x0ff: /* 0 011 111 111 */
+ sprintf(buffer, "ADDR R%01d,R%01d",(op&0x38)>>3,op&7);
+ break;
+ case 0x100: /* 0 100 000 000 */
+ case 0x101: /* 0 100 000 001 */
+ case 0x102: /* 0 100 000 010 */
+ case 0x103: /* 0 100 000 011 */
+ case 0x104: /* 0 100 000 100 */
+ case 0x105: /* 0 100 000 101 */
+ case 0x106: /* 0 100 000 110 */
+ case 0x107: /* 0 100 000 111 */
+ case 0x108: /* 0 100 001 000 */
+ case 0x109: /* 0 100 001 001 */
+ case 0x10a: /* 0 100 001 010 */
+ case 0x10b: /* 0 100 001 011 */
+ case 0x10c: /* 0 100 001 100 */
+ case 0x10d: /* 0 100 001 101 */
+ case 0x10e: /* 0 100 001 110 */
+ case 0x10f: /* 0 100 001 111 */
+ case 0x110: /* 0 100 010 000 */
+ case 0x111: /* 0 100 010 001 */
+ case 0x112: /* 0 100 010 010 */
+ case 0x113: /* 0 100 010 011 */
+ case 0x114: /* 0 100 010 100 */
+ case 0x115: /* 0 100 010 101 */
+ case 0x116: /* 0 100 010 110 */
+ case 0x117: /* 0 100 010 111 */
+ case 0x118: /* 0 100 011 000 */
+ case 0x119: /* 0 100 011 001 */
+ case 0x11a: /* 0 100 011 010 */
+ case 0x11b: /* 0 100 011 011 */
+ case 0x11c: /* 0 100 011 100 */
+ case 0x11d: /* 0 100 011 101 */
+ case 0x11e: /* 0 100 011 110 */
+ case 0x11f: /* 0 100 011 111 */
+ case 0x120: /* 0 100 100 000 */
+ case 0x121: /* 0 100 100 001 */
+ case 0x122: /* 0 100 100 010 */
+ case 0x123: /* 0 100 100 011 */
+ case 0x124: /* 0 100 100 100 */
+ case 0x125: /* 0 100 100 101 */
+ case 0x126: /* 0 100 100 110 */
+ case 0x127: /* 0 100 100 111 */
+ case 0x128: /* 0 100 101 000 */
+ case 0x129: /* 0 100 101 001 */
+ case 0x12a: /* 0 100 101 010 */
+ case 0x12b: /* 0 100 101 011 */
+ case 0x12c: /* 0 100 101 100 */
+ case 0x12d: /* 0 100 101 101 */
+ case 0x12e: /* 0 100 101 110 */
+ case 0x12f: /* 0 100 101 111 */
+ case 0x130: /* 0 100 110 000 */
+ case 0x131: /* 0 100 110 001 */
+ case 0x132: /* 0 100 110 010 */
+ case 0x133: /* 0 100 110 011 */
+ case 0x134: /* 0 100 110 100 */
+ case 0x135: /* 0 100 110 101 */
+ case 0x136: /* 0 100 110 110 */
+ case 0x137: /* 0 100 110 111 */
+ case 0x138: /* 0 100 111 000 */
+ case 0x139: /* 0 100 111 001 */
+ case 0x13a: /* 0 100 111 010 */
+ case 0x13b: /* 0 100 111 011 */
+ case 0x13c: /* 0 100 111 100 */
+ case 0x13d: /* 0 100 111 101 */
+ case 0x13e: /* 0 100 111 110 */
+ case 0x13f: /* 0 100 111 111 */
+ sprintf(buffer, "SUBR R%01d,R%01d",(op&0x38)>>3,op&7);
+ break;
+ case 0x140: /* 0 101 000 000 */
+ case 0x141: /* 0 101 000 001 */
+ case 0x142: /* 0 101 000 010 */
+ case 0x143: /* 0 101 000 011 */
+ case 0x144: /* 0 101 000 100 */
+ case 0x145: /* 0 101 000 101 */
+ case 0x146: /* 0 101 000 110 */
+ case 0x147: /* 0 101 000 111 */
+ case 0x148: /* 0 101 001 000 */
+ case 0x149: /* 0 101 001 001 */
+ case 0x14a: /* 0 101 001 010 */
+ case 0x14b: /* 0 101 001 011 */
+ case 0x14c: /* 0 101 001 100 */
+ case 0x14d: /* 0 101 001 101 */
+ case 0x14e: /* 0 101 001 110 */
+ case 0x14f: /* 0 101 001 111 */
+ case 0x150: /* 0 101 010 000 */
+ case 0x151: /* 0 101 010 001 */
+ case 0x152: /* 0 101 010 010 */
+ case 0x153: /* 0 101 010 011 */
+ case 0x154: /* 0 101 010 100 */
+ case 0x155: /* 0 101 010 101 */
+ case 0x156: /* 0 101 010 110 */
+ case 0x157: /* 0 101 010 111 */
+ case 0x158: /* 0 101 011 000 */
+ case 0x159: /* 0 101 011 001 */
+ case 0x15a: /* 0 101 011 010 */
+ case 0x15b: /* 0 101 011 011 */
+ case 0x15c: /* 0 101 011 100 */
+ case 0x15d: /* 0 101 011 101 */
+ case 0x15e: /* 0 101 011 110 */
+ case 0x15f: /* 0 101 011 111 */
+ case 0x160: /* 0 101 100 000 */
+ case 0x161: /* 0 101 100 001 */
+ case 0x162: /* 0 101 100 010 */
+ case 0x163: /* 0 101 100 011 */
+ case 0x164: /* 0 101 100 100 */
+ case 0x165: /* 0 101 100 101 */
+ case 0x166: /* 0 101 100 110 */
+ case 0x167: /* 0 101 100 111 */
+ case 0x168: /* 0 101 101 000 */
+ case 0x169: /* 0 101 101 001 */
+ case 0x16a: /* 0 101 101 010 */
+ case 0x16b: /* 0 101 101 011 */
+ case 0x16c: /* 0 101 101 100 */
+ case 0x16d: /* 0 101 101 101 */
+ case 0x16e: /* 0 101 101 110 */
+ case 0x16f: /* 0 101 101 111 */
+ case 0x170: /* 0 101 110 000 */
+ case 0x171: /* 0 101 110 001 */
+ case 0x172: /* 0 101 110 010 */
+ case 0x173: /* 0 101 110 011 */
+ case 0x174: /* 0 101 110 100 */
+ case 0x175: /* 0 101 110 101 */
+ case 0x176: /* 0 101 110 110 */
+ case 0x177: /* 0 101 110 111 */
+ case 0x178: /* 0 101 111 000 */
+ case 0x179: /* 0 101 111 001 */
+ case 0x17a: /* 0 101 111 010 */
+ case 0x17b: /* 0 101 111 011 */
+ case 0x17c: /* 0 101 111 100 */
+ case 0x17d: /* 0 101 111 101 */
+ case 0x17e: /* 0 101 111 110 */
+ case 0x17f: /* 0 101 111 111 */
+ sprintf(buffer, "CMPR R%01d,R%01d",(op&0x38)>>3,op&7);
+ break;
+ case 0x180: /* 0 110 000 000 */
+ case 0x181: /* 0 110 000 001 */
+ case 0x182: /* 0 110 000 010 */
+ case 0x183: /* 0 110 000 011 */
+ case 0x184: /* 0 110 000 100 */
+ case 0x185: /* 0 110 000 101 */
+ case 0x186: /* 0 110 000 110 */
+ case 0x187: /* 0 110 000 111 */
+ case 0x188: /* 0 110 001 000 */
+ case 0x189: /* 0 110 001 001 */
+ case 0x18a: /* 0 110 001 010 */
+ case 0x18b: /* 0 110 001 011 */
+ case 0x18c: /* 0 110 001 100 */
+ case 0x18d: /* 0 110 001 101 */
+ case 0x18e: /* 0 110 001 110 */
+ case 0x18f: /* 0 110 001 111 */
+ case 0x190: /* 0 110 010 000 */
+ case 0x191: /* 0 110 010 001 */
+ case 0x192: /* 0 110 010 010 */
+ case 0x193: /* 0 110 010 011 */
+ case 0x194: /* 0 110 010 100 */
+ case 0x195: /* 0 110 010 101 */
+ case 0x196: /* 0 110 010 110 */
+ case 0x197: /* 0 110 010 111 */
+ case 0x198: /* 0 110 011 000 */
+ case 0x199: /* 0 110 011 001 */
+ case 0x19a: /* 0 110 011 010 */
+ case 0x19b: /* 0 110 011 011 */
+ case 0x19c: /* 0 110 011 100 */
+ case 0x19d: /* 0 110 011 101 */
+ case 0x19e: /* 0 110 011 110 */
+ case 0x19f: /* 0 110 011 111 */
+ case 0x1a0: /* 0 110 100 000 */
+ case 0x1a1: /* 0 110 100 001 */
+ case 0x1a2: /* 0 110 100 010 */
+ case 0x1a3: /* 0 110 100 011 */
+ case 0x1a4: /* 0 110 100 100 */
+ case 0x1a5: /* 0 110 100 101 */
+ case 0x1a6: /* 0 110 100 110 */
+ case 0x1a7: /* 0 110 100 111 */
+ case 0x1a8: /* 0 110 101 000 */
+ case 0x1a9: /* 0 110 101 001 */
+ case 0x1aa: /* 0 110 101 010 */
+ case 0x1ab: /* 0 110 101 011 */
+ case 0x1ac: /* 0 110 101 100 */
+ case 0x1ad: /* 0 110 101 101 */
+ case 0x1ae: /* 0 110 101 110 */
+ case 0x1af: /* 0 110 101 111 */
+ case 0x1b0: /* 0 110 110 000 */
+ case 0x1b1: /* 0 110 110 001 */
+ case 0x1b2: /* 0 110 110 010 */
+ case 0x1b3: /* 0 110 110 011 */
+ case 0x1b4: /* 0 110 110 100 */
+ case 0x1b5: /* 0 110 110 101 */
+ case 0x1b6: /* 0 110 110 110 */
+ case 0x1b7: /* 0 110 110 111 */
+ case 0x1b8: /* 0 110 111 000 */
+ case 0x1b9: /* 0 110 111 001 */
+ case 0x1ba: /* 0 110 111 010 */
+ case 0x1bb: /* 0 110 111 011 */
+ case 0x1bc: /* 0 110 111 100 */
+ case 0x1bd: /* 0 110 111 101 */
+ case 0x1be: /* 0 110 111 110 */
+ case 0x1bf: /* 0 110 111 111 */
+ sprintf(buffer, "ANDR R%01d,R%01d",(op&0x38)>>3,op&7);
+ break;
+ case 0x1c0: /* 0 111 000 000 */
+ case 0x1c9: /* 0 111 001 001 */
+ case 0x1d2: /* 0 111 010 010 */
+ case 0x1db: /* 0 111 011 011 */
+ case 0x1e4: /* 0 111 100 100 */
+ case 0x1ed: /* 0 111 101 101 */
+ case 0x1f6: /* 0 111 110 110 */
+ case 0x1ff: /* 0 111 111 111 */
+ sprintf(buffer, "CLRR R%01d",op&7);
+ break;
+ case 0x1c1: /* 0 111 000 001 */
+ case 0x1c2: /* 0 111 000 010 */
+ case 0x1c3: /* 0 111 000 011 */
+ case 0x1c4: /* 0 111 000 100 */
+ case 0x1c5: /* 0 111 000 101 */
+ case 0x1c6: /* 0 111 000 110 */
+ case 0x1c7: /* 0 111 000 111 */
+ case 0x1c8: /* 0 111 001 000 */
+ case 0x1ca: /* 0 111 001 010 */
+ case 0x1cb: /* 0 111 001 011 */
+ case 0x1cc: /* 0 111 001 100 */
+ case 0x1cd: /* 0 111 001 101 */
+ case 0x1ce: /* 0 111 001 110 */
+ case 0x1cf: /* 0 111 001 111 */
+ case 0x1d0: /* 0 111 010 000 */
+ case 0x1d1: /* 0 111 010 001 */
+ case 0x1d3: /* 0 111 010 011 */
+ case 0x1d4: /* 0 111 010 100 */
+ case 0x1d5: /* 0 111 010 101 */
+ case 0x1d6: /* 0 111 010 110 */
+ case 0x1d7: /* 0 111 010 111 */
+ case 0x1d8: /* 0 111 011 000 */
+ case 0x1d9: /* 0 111 011 001 */
+ case 0x1da: /* 0 111 011 010 */
+ case 0x1dc: /* 0 111 011 100 */
+ case 0x1dd: /* 0 111 011 101 */
+ case 0x1de: /* 0 111 011 110 */
+ case 0x1df: /* 0 111 011 111 */
+ case 0x1e0: /* 0 111 100 000 */
+ case 0x1e1: /* 0 111 100 001 */
+ case 0x1e2: /* 0 111 100 010 */
+ case 0x1e3: /* 0 111 100 011 */
+ case 0x1e5: /* 0 111 100 101 */
+ case 0x1e6: /* 0 111 100 110 */
+ case 0x1e7: /* 0 111 100 111 */
+ case 0x1e8: /* 0 111 101 000 */
+ case 0x1e9: /* 0 111 101 001 */
+ case 0x1ea: /* 0 111 101 010 */
+ case 0x1eb: /* 0 111 101 011 */
+ case 0x1ec: /* 0 111 101 100 */
+ case 0x1ee: /* 0 111 101 110 */
+ case 0x1ef: /* 0 111 101 111 */
+ case 0x1f0: /* 0 111 110 000 */
+ case 0x1f1: /* 0 111 110 001 */
+ case 0x1f2: /* 0 111 110 010 */
+ case 0x1f3: /* 0 111 110 011 */
+ case 0x1f4: /* 0 111 110 100 */
+ case 0x1f5: /* 0 111 110 101 */
+ case 0x1f7: /* 0 111 110 111 */
+ case 0x1f8: /* 0 111 111 000 */
+ case 0x1f9: /* 0 111 111 001 */
+ case 0x1fa: /* 0 111 111 010 */
+ case 0x1fb: /* 0 111 111 011 */
+ case 0x1fc: /* 0 111 111 100 */
+ case 0x1fd: /* 0 111 111 101 */
+ case 0x1fe: /* 0 111 111 110 */
+ sprintf(buffer, "XORR R%01d,R%01d",(op&0x38)>>3,op&7);
+ break;
+ case 0x200: /* 1 000 000 000 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "B %04X",pc+2+ea);
+ break;
+ case 0x201: /* 1 000 000 001 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BC %04X",pc+2+ea);
+ break;
+ case 0x202: /* 1 000 000 010 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BOV %04X",pc+2+ea);
+ break;
+ case 0x203: /* 1 000 000 011 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BPL %04X",pc+2+ea);
+ break;
+ case 0x204: /* 1 000 000 100 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BZE %04X",pc+2+ea);
+ break;
+ case 0x205: /* 1 000 000 101 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BLT %04X",pc+2+ea);
+ break;
+ case 0x206: /* 1 000 000 110 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BLE %04X",pc+2+ea);
+ break;
+ case 0x207: /* 1 000 000 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BUSC %04X",pc+2+ea);
+ break;
+ case 0x208: /* 1 000 001 000 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "NOPP %04X",pc+2+ea);
+ break;
+ case 0x209: /* 1 000 001 001 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BNC %04X",pc+2+ea);
+ break;
+ case 0x20a: /* 1 000 001 010 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BNOV %04X",pc+2+ea);
+ break;
+ case 0x20b: /* 1 000 001 011 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BMI %04X",pc+2+ea);
+ break;
+ case 0x20c: /* 1 000 001 100 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BNZE %04X",pc+2+ea);
+ break;
+ case 0x20d: /* 1 000 001 101 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BGE %04X",pc+2+ea);
+ break;
+ case 0x20e: /* 1 000 001 110 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BGT %04X",pc+2+ea);
+ break;
+ case 0x20f: /* 1 000 001 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BESC %04X",pc+2+ea);
+ break;
+ case 0x210: /* 1 000 010 000 */
+ case 0x211: /* 1 000 010 001 */
+ case 0x212: /* 1 000 010 010 */
+ case 0x213: /* 1 000 010 011 */
+ case 0x214: /* 1 000 010 100 */
+ case 0x215: /* 1 000 010 101 */
+ case 0x216: /* 1 000 010 110 */
+ case 0x217: /* 1 000 010 111 */
+ case 0x218: /* 1 000 011 000 */
+ case 0x219: /* 1 000 011 001 */
+ case 0x21a: /* 1 000 011 010 */
+ case 0x21b: /* 1 000 011 011 */
+ case 0x21c: /* 1 000 011 100 */
+ case 0x21d: /* 1 000 011 101 */
+ case 0x21e: /* 1 000 011 110 */
+ case 0x21f: /* 1 000 011 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BEXT %04X,%01X",pc+2+ea,op&0x0f);
+ break;
+ case 0x220: /* 1 000 100 000 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "B %04X",pc+1-ea);
+ break;
+ case 0x221: /* 1 000 100 001 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BC %04X",pc+1-ea);
+ break;
+ case 0x222: /* 1 000 100 010 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BOV %04X",pc+1-ea);
+ break;
+ case 0x223: /* 1 000 100 011 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BPL %04X",pc+1-ea);
+ break;
+ case 0x224: /* 1 000 100 100 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BZE %04X",pc+1-ea);
+ break;
+ case 0x225: /* 1 000 100 101 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BLT %04X",pc+1-ea);
+ break;
+ case 0x226: /* 1 000 100 110 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BLE %04X",pc+1-ea);
+ break;
+ case 0x227: /* 1 000 100 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BUSC %04X",pc+1-ea);
+ break;
+ case 0x228: /* 1 000 101 000 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "NOPP %04X",pc+1-ea);
+ break;
+ case 0x229: /* 1 000 101 001 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BNC %04X",pc+1-ea);
+ break;
+ case 0x22a: /* 1 000 101 010 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BNOV %04X",pc+1-ea);
+ break;
+ case 0x22b: /* 1 000 101 011 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BMI %04X",pc+1-ea);
+ break;
+ case 0x22c: /* 1 000 101 100 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BNZE %04X",pc+1-ea);
+ break;
+ case 0x22d: /* 1 000 101 101 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BGE %04X",pc+1-ea);
+ break;
+ case 0x22e: /* 1 000 101 110 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BGT %04X",pc+1-ea);
+ break;
+ case 0x22f: /* 1 000 101 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BESC %04X",pc+1-ea);
+ break;
+ case 0x230: /* 1 000 110 000 */
+ case 0x231: /* 1 000 110 001 */
+ case 0x232: /* 1 000 110 010 */
+ case 0x233: /* 1 000 110 011 */
+ case 0x234: /* 1 000 110 100 */
+ case 0x235: /* 1 000 110 101 */
+ case 0x236: /* 1 000 110 110 */
+ case 0x237: /* 1 000 110 111 */
+ case 0x238: /* 1 000 111 000 */
+ case 0x239: /* 1 000 111 001 */
+ case 0x23a: /* 1 000 111 010 */
+ case 0x23b: /* 1 000 111 011 */
+ case 0x23c: /* 1 000 111 100 */
+ case 0x23d: /* 1 000 111 101 */
+ case 0x23e: /* 1 000 111 110 */
+ case 0x23f: /* 1 000 111 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "BEXT %04X,%01X",pc+1-ea,op&0x0f);
+ break;
+ case 0x240: /* 1 001 000 000 */
+ case 0x241: /* 1 001 000 001 */
+ case 0x242: /* 1 001 000 010 */
+ case 0x243: /* 1 001 000 011 */
+ case 0x244: /* 1 001 000 100 */
+ case 0x245: /* 1 001 000 101 */
+ case 0x246: /* 1 001 000 110 */
+ case 0x247: /* 1 001 000 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "MVO R%01d,(%04X)",op&0x7,ea);
+ break;
+ case 0x248: /* 1 001 001 000 */
+ case 0x249: /* 1 001 001 001 */
+ case 0x24a: /* 1 001 001 010 */
+ case 0x24b: /* 1 001 001 011 */
+ case 0x24c: /* 1 001 001 100 */
+ case 0x24d: /* 1 001 001 101 */
+ case 0x24e: /* 1 001 001 110 */
+ case 0x24f: /* 1 001 001 111 */
+ case 0x250: /* 1 001 010 000 */
+ case 0x251: /* 1 001 010 001 */
+ case 0x252: /* 1 001 010 010 */
+ case 0x253: /* 1 001 010 011 */
+ case 0x254: /* 1 001 010 100 */
+ case 0x255: /* 1 001 010 101 */
+ case 0x256: /* 1 001 010 110 */
+ case 0x257: /* 1 001 010 111 */
+ case 0x258: /* 1 001 011 000 */
+ case 0x259: /* 1 001 011 001 */
+ case 0x25a: /* 1 001 011 010 */
+ case 0x25b: /* 1 001 011 011 */
+ case 0x25c: /* 1 001 011 100 */
+ case 0x25d: /* 1 001 011 101 */
+ case 0x25e: /* 1 001 011 110 */
+ case 0x25f: /* 1 001 011 111 */
+ case 0x260: /* 1 001 100 000 */
+ case 0x261: /* 1 001 100 001 */
+ case 0x262: /* 1 001 100 010 */
+ case 0x263: /* 1 001 100 011 */
+ case 0x264: /* 1 001 100 100 */
+ case 0x265: /* 1 001 100 101 */
+ case 0x266: /* 1 001 100 110 */
+ case 0x267: /* 1 001 100 111 */
+ case 0x268: /* 1 001 101 000 */
+ case 0x269: /* 1 001 101 001 */
+ case 0x26a: /* 1 001 101 010 */
+ case 0x26b: /* 1 001 101 011 */
+ case 0x26c: /* 1 001 101 100 */
+ case 0x26d: /* 1 001 101 101 */
+ case 0x26e: /* 1 001 101 110 */
+ case 0x26f: /* 1 001 101 111 */
+ sprintf(buffer, "MVO@ R%01d,(R%01d)",op&0x7,(op&0x38)>>3);
+ break;
+ case 0x270: /* 1 001 110 000 */
+ case 0x271: /* 1 001 110 001 */
+ case 0x272: /* 1 001 110 010 */
+ case 0x273: /* 1 001 110 011 */
+ case 0x274: /* 1 001 110 100 */
+ case 0x275: /* 1 001 110 101 */
+ case 0x276: /* 1 001 110 110 */
+ case 0x277: /* 1 001 110 111 */
+ sprintf(buffer, "PSHR R%01d",op&0x7);
+ break;
+ case 0x278: /* 1 001 111 000 */
+ case 0x279: /* 1 001 111 001 */
+ case 0x27a: /* 1 001 111 010 */
+ case 0x27b: /* 1 001 111 011 */
+ case 0x27c: /* 1 001 111 100 */
+ case 0x27d: /* 1 001 111 101 */
+ case 0x27e: /* 1 001 111 110 */
+ case 0x27f: /* 1 001 111 111 */
+ size += 1;
+ sprintf(buffer, "MVOI R%01d,(%04X)",op&0x7,pc+1);
+ break;
+ case 0x280: /* 1 010 000 000 */
+ case 0x281: /* 1 010 000 001 */
+ case 0x282: /* 1 010 000 010 */
+ case 0x283: /* 1 010 000 011 */
+ case 0x284: /* 1 010 000 100 */
+ case 0x285: /* 1 010 000 101 */
+ case 0x286: /* 1 010 000 110 */
+ case 0x287: /* 1 010 000 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "MVI (%04X),R%01d",ea,op&0x7);
+ break;
+ case 0x288: /* 1 010 001 000 */
+ case 0x289: /* 1 010 001 001 */
+ case 0x28a: /* 1 010 001 010 */
+ case 0x28b: /* 1 010 001 011 */
+ case 0x28c: /* 1 010 001 100 */
+ case 0x28d: /* 1 010 001 101 */
+ case 0x28e: /* 1 010 001 110 */
+ case 0x28f: /* 1 010 001 111 */
+ case 0x290: /* 1 010 010 000 */
+ case 0x291: /* 1 010 010 001 */
+ case 0x292: /* 1 010 010 010 */
+ case 0x293: /* 1 010 010 011 */
+ case 0x294: /* 1 010 010 100 */
+ case 0x295: /* 1 010 010 101 */
+ case 0x296: /* 1 010 010 110 */
+ case 0x297: /* 1 010 010 111 */
+ case 0x298: /* 1 010 011 000 */
+ case 0x299: /* 1 010 011 001 */
+ case 0x29a: /* 1 010 011 010 */
+ case 0x29b: /* 1 010 011 011 */
+ case 0x29c: /* 1 010 011 100 */
+ case 0x29d: /* 1 010 011 101 */
+ case 0x29e: /* 1 010 011 110 */
+ case 0x29f: /* 1 010 011 111 */
+ case 0x2a0: /* 1 010 100 000 */
+ case 0x2a1: /* 1 010 100 001 */
+ case 0x2a2: /* 1 010 100 010 */
+ case 0x2a3: /* 1 010 100 011 */
+ case 0x2a4: /* 1 010 100 100 */
+ case 0x2a5: /* 1 010 100 101 */
+ case 0x2a6: /* 1 010 100 110 */
+ case 0x2a7: /* 1 010 100 111 */
+ case 0x2a8: /* 1 010 101 000 */
+ case 0x2a9: /* 1 010 101 001 */
+ case 0x2aa: /* 1 010 101 010 */
+ case 0x2ab: /* 1 010 101 011 */
+ case 0x2ac: /* 1 010 101 100 */
+ case 0x2ad: /* 1 010 101 101 */
+ case 0x2ae: /* 1 010 101 110 */
+ case 0x2af: /* 1 010 101 111 */
+ sprintf(buffer, "MVI@ (R%01d),R%01d",(op&0x38)>>3,op&0x7);
+ break;
+ case 0x2b0: /* 1 010 110 000 */
+ case 0x2b1: /* 1 010 110 001 */
+ case 0x2b2: /* 1 010 110 010 */
+ case 0x2b3: /* 1 010 110 011 */
+ case 0x2b4: /* 1 010 110 100 */
+ case 0x2b5: /* 1 010 110 101 */
+ case 0x2b6: /* 1 010 110 110 */
+ case 0x2b7: /* 1 010 110 111 */
+ sprintf(buffer, "PULR R%01d",op&0x7);
+ break;
+ case 0x2b8: /* 1 010 111 000 */
+ case 0x2b9: /* 1 010 111 001 */
+ case 0x2ba: /* 1 010 111 010 */
+ case 0x2bb: /* 1 010 111 011 */
+ case 0x2bc: /* 1 010 111 100 */
+ case 0x2bd: /* 1 010 111 101 */
+ case 0x2be: /* 1 010 111 110 */
+ case 0x2bf: /* 1 010 111 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "MVII #%04X,R%01d",ea,op&0x7);
+ break;
+ case 0x2c0: /* 1 011 010 000 */
+ case 0x2c1: /* 1 011 010 001 */
+ case 0x2c2: /* 1 011 010 010 */
+ case 0x2c3: /* 1 011 010 011 */
+ case 0x2c4: /* 1 011 010 100 */
+ case 0x2c5: /* 1 011 010 101 */
+ case 0x2c6: /* 1 011 010 110 */
+ case 0x2c7: /* 1 011 010 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "ADD (%04X),R%01d",ea,op&0x7);
+ break;
+ case 0x2c8: /* 1 011 001 000 */
+ case 0x2c9: /* 1 011 001 001 */
+ case 0x2ca: /* 1 011 001 010 */
+ case 0x2cb: /* 1 011 001 011 */
+ case 0x2cc: /* 1 011 001 100 */
+ case 0x2cd: /* 1 011 001 101 */
+ case 0x2ce: /* 1 011 001 110 */
+ case 0x2cf: /* 1 011 001 111 */
+ case 0x2d0: /* 1 011 010 000 */
+ case 0x2d1: /* 1 011 010 001 */
+ case 0x2d2: /* 1 011 010 010 */
+ case 0x2d3: /* 1 011 010 011 */
+ case 0x2d4: /* 1 011 010 100 */
+ case 0x2d5: /* 1 011 010 101 */
+ case 0x2d6: /* 1 011 010 110 */
+ case 0x2d7: /* 1 011 010 111 */
+ case 0x2d8: /* 1 011 011 000 */
+ case 0x2d9: /* 1 011 011 001 */
+ case 0x2da: /* 1 011 011 010 */
+ case 0x2db: /* 1 011 011 011 */
+ case 0x2dc: /* 1 011 011 100 */
+ case 0x2dd: /* 1 011 011 101 */
+ case 0x2de: /* 1 011 011 110 */
+ case 0x2df: /* 1 011 011 111 */
+ case 0x2e0: /* 1 011 100 000 */
+ case 0x2e1: /* 1 011 100 001 */
+ case 0x2e2: /* 1 011 100 010 */
+ case 0x2e3: /* 1 011 100 011 */
+ case 0x2e4: /* 1 011 100 100 */
+ case 0x2e5: /* 1 011 100 101 */
+ case 0x2e6: /* 1 011 100 110 */
+ case 0x2e7: /* 1 011 100 111 */
+ case 0x2e8: /* 1 011 101 000 */
+ case 0x2e9: /* 1 011 101 001 */
+ case 0x2ea: /* 1 011 101 010 */
+ case 0x2eb: /* 1 011 101 011 */
+ case 0x2ec: /* 1 011 101 100 */
+ case 0x2ed: /* 1 011 101 101 */
+ case 0x2ee: /* 1 011 101 110 */
+ case 0x2ef: /* 1 011 101 111 */
+ case 0x2f0: /* 1 011 110 000 */
+ case 0x2f1: /* 1 011 110 001 */
+ case 0x2f2: /* 1 011 110 010 */
+ case 0x2f3: /* 1 011 110 011 */
+ case 0x2f4: /* 1 011 110 100 */
+ case 0x2f5: /* 1 011 110 101 */
+ case 0x2f6: /* 1 011 110 110 */
+ case 0x2f7: /* 1 011 110 111 */
+ sprintf(buffer, "ADD@ (R%01d),R%01d",(op&0x38)>>3,op&0x7);
+ break;
+ case 0x2f8: /* 1 011 111 000 */
+ case 0x2f9: /* 1 011 111 001 */
+ case 0x2fa: /* 1 011 111 010 */
+ case 0x2fb: /* 1 011 111 011 */
+ case 0x2fc: /* 1 011 111 100 */
+ case 0x2fd: /* 1 011 111 101 */
+ case 0x2fe: /* 1 011 111 110 */
+ case 0x2ff: /* 1 011 111 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "ADDI #%04X,R%01d",ea,op&0x7);
+ break;
+ case 0x300: /* 1 100 000 000 */
+ case 0x301: /* 1 100 000 001 */
+ case 0x302: /* 1 100 000 010 */
+ case 0x303: /* 1 100 000 011 */
+ case 0x304: /* 1 100 000 100 */
+ case 0x305: /* 1 100 000 101 */
+ case 0x306: /* 1 100 000 110 */
+ case 0x307: /* 1 100 000 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "SUB (%04X),R%01d",ea,op&0x7);
+ break;
+ case 0x308: /* 1 100 001 000 */
+ case 0x309: /* 1 100 001 001 */
+ case 0x30a: /* 1 100 001 010 */
+ case 0x30b: /* 1 100 001 011 */
+ case 0x30c: /* 1 100 001 100 */
+ case 0x30d: /* 1 100 001 101 */
+ case 0x30e: /* 1 100 001 110 */
+ case 0x30f: /* 1 100 001 111 */
+ case 0x310: /* 1 100 010 000 */
+ case 0x311: /* 1 100 010 001 */
+ case 0x312: /* 1 100 010 010 */
+ case 0x313: /* 1 100 010 011 */
+ case 0x314: /* 1 100 010 100 */
+ case 0x315: /* 1 100 010 101 */
+ case 0x316: /* 1 100 010 110 */
+ case 0x317: /* 1 100 010 111 */
+ case 0x318: /* 1 100 011 000 */
+ case 0x319: /* 1 100 011 001 */
+ case 0x31a: /* 1 100 011 010 */
+ case 0x31b: /* 1 100 011 011 */
+ case 0x31c: /* 1 100 011 100 */
+ case 0x31d: /* 1 100 011 101 */
+ case 0x31e: /* 1 100 011 110 */
+ case 0x31f: /* 1 100 011 111 */
+ case 0x320: /* 1 100 100 000 */
+ case 0x321: /* 1 100 100 001 */
+ case 0x322: /* 1 100 100 010 */
+ case 0x323: /* 1 100 100 011 */
+ case 0x324: /* 1 100 100 100 */
+ case 0x325: /* 1 100 100 101 */
+ case 0x326: /* 1 100 100 110 */
+ case 0x327: /* 1 100 100 111 */
+ case 0x328: /* 1 100 101 000 */
+ case 0x329: /* 1 100 101 001 */
+ case 0x32a: /* 1 100 101 010 */
+ case 0x32b: /* 1 100 101 011 */
+ case 0x32c: /* 1 100 101 100 */
+ case 0x32d: /* 1 100 101 101 */
+ case 0x32e: /* 1 100 101 110 */
+ case 0x32f: /* 1 100 101 111 */
+ case 0x330: /* 1 100 110 000 */
+ case 0x331: /* 1 100 110 001 */
+ case 0x332: /* 1 100 110 010 */
+ case 0x333: /* 1 100 110 011 */
+ case 0x334: /* 1 100 110 100 */
+ case 0x335: /* 1 100 110 101 */
+ case 0x336: /* 1 100 110 110 */
+ case 0x337: /* 1 100 110 111 */
+ sprintf(buffer, "SUB@ (R%01d),R%01d",(op&0x38)>>3,op&0x7);
+ break;
+ case 0x338: /* 1 100 111 000 */
+ case 0x339: /* 1 100 111 001 */
+ case 0x33a: /* 1 100 111 010 */
+ case 0x33b: /* 1 100 111 011 */
+ case 0x33c: /* 1 100 111 100 */
+ case 0x33d: /* 1 100 111 101 */
+ case 0x33e: /* 1 100 111 110 */
+ case 0x33f: /* 1 100 111 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "SUBI #%04X,R%01d",ea,op&0x7);
+ break;
+ case 0x340: /* 1 101 000 000 */
+ case 0x341: /* 1 101 000 001 */
+ case 0x342: /* 1 101 000 010 */
+ case 0x343: /* 1 101 000 011 */
+ case 0x344: /* 1 101 000 100 */
+ case 0x345: /* 1 101 000 101 */
+ case 0x346: /* 1 101 000 110 */
+ case 0x347: /* 1 101 000 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "CMP (%04X),R%01d",ea,op&0x7);
+ break;
+ case 0x348: /* 1 101 001 000 */
+ case 0x349: /* 1 101 001 001 */
+ case 0x34a: /* 1 101 001 010 */
+ case 0x34b: /* 1 101 001 011 */
+ case 0x34c: /* 1 101 001 100 */
+ case 0x34d: /* 1 101 001 101 */
+ case 0x34e: /* 1 101 001 110 */
+ case 0x34f: /* 1 101 001 111 */
+ case 0x350: /* 1 101 010 000 */
+ case 0x351: /* 1 101 010 001 */
+ case 0x352: /* 1 101 010 010 */
+ case 0x353: /* 1 101 010 011 */
+ case 0x354: /* 1 101 010 100 */
+ case 0x355: /* 1 101 010 101 */
+ case 0x356: /* 1 101 010 110 */
+ case 0x357: /* 1 101 010 111 */
+ case 0x358: /* 1 101 011 000 */
+ case 0x359: /* 1 101 011 001 */
+ case 0x35a: /* 1 101 011 010 */
+ case 0x35b: /* 1 101 011 011 */
+ case 0x35c: /* 1 101 011 100 */
+ case 0x35d: /* 1 101 011 101 */
+ case 0x35e: /* 1 101 011 110 */
+ case 0x35f: /* 1 101 011 111 */
+ case 0x360: /* 1 101 100 000 */
+ case 0x361: /* 1 101 100 001 */
+ case 0x362: /* 1 101 100 010 */
+ case 0x363: /* 1 101 100 011 */
+ case 0x364: /* 1 101 100 100 */
+ case 0x365: /* 1 101 100 101 */
+ case 0x366: /* 1 101 100 110 */
+ case 0x367: /* 1 101 100 111 */
+ case 0x368: /* 1 101 101 000 */
+ case 0x369: /* 1 101 101 001 */
+ case 0x36a: /* 1 101 101 010 */
+ case 0x36b: /* 1 101 101 011 */
+ case 0x36c: /* 1 101 101 100 */
+ case 0x36d: /* 1 101 101 101 */
+ case 0x36e: /* 1 101 101 110 */
+ case 0x36f: /* 1 101 101 111 */
+ case 0x370: /* 1 101 110 000 */
+ case 0x371: /* 1 101 110 001 */
+ case 0x372: /* 1 101 110 010 */
+ case 0x373: /* 1 101 110 011 */
+ case 0x374: /* 1 101 110 100 */
+ case 0x375: /* 1 101 110 101 */
+ case 0x376: /* 1 101 110 110 */
+ case 0x377: /* 1 101 110 111 */
+ sprintf(buffer, "CMP@ (R%01d),R%01d",(op&0x38)>>3,op&0x7);
+ break;
+ case 0x378: /* 1 101 111 000 */
+ case 0x379: /* 1 101 111 001 */
+ case 0x37a: /* 1 101 111 010 */
+ case 0x37b: /* 1 101 111 011 */
+ case 0x37c: /* 1 101 111 100 */
+ case 0x37d: /* 1 101 111 101 */
+ case 0x37e: /* 1 101 111 110 */
+ case 0x37f: /* 1 101 111 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "CMPI #%04X,R%01d",ea,op&0x7);
+ break;
+ case 0x380: /* 1 110 000 000 */
+ case 0x381: /* 1 110 000 001 */
+ case 0x382: /* 1 110 000 010 */
+ case 0x383: /* 1 110 000 011 */
+ case 0x384: /* 1 110 000 100 */
+ case 0x385: /* 1 110 000 101 */
+ case 0x386: /* 1 110 000 110 */
+ case 0x387: /* 1 110 000 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "AND (%04X),R%01d",ea,op&0x7);
+ break;
+ case 0x388: /* 1 110 001 000 */
+ case 0x389: /* 1 110 001 001 */
+ case 0x38a: /* 1 110 001 010 */
+ case 0x38b: /* 1 110 001 011 */
+ case 0x38c: /* 1 110 001 100 */
+ case 0x38d: /* 1 110 001 101 */
+ case 0x38e: /* 1 110 001 110 */
+ case 0x38f: /* 1 110 001 111 */
+ case 0x390: /* 1 110 010 000 */
+ case 0x391: /* 1 110 010 001 */
+ case 0x392: /* 1 110 010 010 */
+ case 0x393: /* 1 110 010 011 */
+ case 0x394: /* 1 110 010 100 */
+ case 0x395: /* 1 110 010 101 */
+ case 0x396: /* 1 110 010 110 */
+ case 0x397: /* 1 110 010 111 */
+ case 0x398: /* 1 110 011 000 */
+ case 0x399: /* 1 110 011 001 */
+ case 0x39a: /* 1 110 011 010 */
+ case 0x39b: /* 1 110 011 011 */
+ case 0x39c: /* 1 110 011 100 */
+ case 0x39d: /* 1 110 011 101 */
+ case 0x39e: /* 1 110 011 110 */
+ case 0x39f: /* 1 110 011 111 */
+ case 0x3a0: /* 1 110 100 000 */
+ case 0x3a1: /* 1 110 100 001 */
+ case 0x3a2: /* 1 110 100 010 */
+ case 0x3a3: /* 1 110 100 011 */
+ case 0x3a4: /* 1 110 100 100 */
+ case 0x3a5: /* 1 110 100 101 */
+ case 0x3a6: /* 1 110 100 110 */
+ case 0x3a7: /* 1 110 100 111 */
+ case 0x3a8: /* 1 110 101 000 */
+ case 0x3a9: /* 1 110 101 001 */
+ case 0x3aa: /* 1 110 101 010 */
+ case 0x3ab: /* 1 110 101 011 */
+ case 0x3ac: /* 1 110 101 100 */
+ case 0x3ad: /* 1 110 101 101 */
+ case 0x3ae: /* 1 110 101 110 */
+ case 0x3af: /* 1 110 101 111 */
+ case 0x3b0: /* 1 110 110 000 */
+ case 0x3b1: /* 1 110 110 001 */
+ case 0x3b2: /* 1 110 110 010 */
+ case 0x3b3: /* 1 110 110 011 */
+ case 0x3b4: /* 1 110 110 100 */
+ case 0x3b5: /* 1 110 110 101 */
+ case 0x3b6: /* 1 110 110 110 */
+ case 0x3b7: /* 1 110 110 111 */
+ sprintf(buffer, "AND@ (R%01d),R%01d",(op&0x38)>>3,op&0x7);
+ break;
+ case 0x3b8: /* 1 110 111 000 */
+ case 0x3b9: /* 1 110 111 001 */
+ case 0x3ba: /* 1 110 111 010 */
+ case 0x3bb: /* 1 110 111 011 */
+ case 0x3bc: /* 1 110 111 100 */
+ case 0x3bd: /* 1 110 111 101 */
+ case 0x3be: /* 1 110 111 110 */
+ case 0x3bf: /* 1 110 111 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "ANDI #%04X,R%01d",ea,op&0x7);
+ break;
+ case 0x3c0: /* 1 111 000 000 */
+ case 0x3c1: /* 1 111 000 001 */
+ case 0x3c2: /* 1 111 000 010 */
+ case 0x3c3: /* 1 111 000 011 */
+ case 0x3c4: /* 1 111 000 100 */
+ case 0x3c5: /* 1 111 000 101 */
+ case 0x3c6: /* 1 111 000 110 */
+ case 0x3c7: /* 1 111 000 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "XOR (%04X),R%01d",ea,op&0x7);
+ break;
+ case 0x3c8: /* 1 111 001 000 */
+ case 0x3c9: /* 1 111 001 001 */
+ case 0x3ca: /* 1 111 001 010 */
+ case 0x3cb: /* 1 111 001 011 */
+ case 0x3cc: /* 1 111 001 100 */
+ case 0x3cd: /* 1 111 001 101 */
+ case 0x3ce: /* 1 111 001 110 */
+ case 0x3cf: /* 1 111 001 111 */
+ case 0x3d0: /* 1 111 010 000 */
+ case 0x3d1: /* 1 111 010 001 */
+ case 0x3d2: /* 1 111 010 010 */
+ case 0x3d3: /* 1 111 010 011 */
+ case 0x3d4: /* 1 111 010 100 */
+ case 0x3d5: /* 1 111 010 101 */
+ case 0x3d6: /* 1 111 010 110 */
+ case 0x3d7: /* 1 111 010 111 */
+ case 0x3d8: /* 1 111 011 000 */
+ case 0x3d9: /* 1 111 011 001 */
+ case 0x3da: /* 1 111 011 010 */
+ case 0x3db: /* 1 111 011 011 */
+ case 0x3dc: /* 1 111 011 100 */
+ case 0x3dd: /* 1 111 011 101 */
+ case 0x3de: /* 1 111 011 110 */
+ case 0x3df: /* 1 111 011 111 */
+ case 0x3e0: /* 1 111 100 000 */
+ case 0x3e1: /* 1 111 100 001 */
+ case 0x3e2: /* 1 111 100 010 */
+ case 0x3e3: /* 1 111 100 011 */
+ case 0x3e4: /* 1 111 100 100 */
+ case 0x3e5: /* 1 111 100 101 */
+ case 0x3e6: /* 1 111 100 110 */
+ case 0x3e7: /* 1 111 100 111 */
+ case 0x3e8: /* 1 111 101 000 */
+ case 0x3e9: /* 1 111 101 001 */
+ case 0x3ea: /* 1 111 101 010 */
+ case 0x3eb: /* 1 111 101 011 */
+ case 0x3ec: /* 1 111 101 100 */
+ case 0x3ed: /* 1 111 101 101 */
+ case 0x3ee: /* 1 111 101 110 */
+ case 0x3ef: /* 1 111 101 111 */
+ case 0x3f0: /* 1 111 110 000 */
+ case 0x3f1: /* 1 111 110 001 */
+ case 0x3f2: /* 1 111 110 010 */
+ case 0x3f3: /* 1 111 110 011 */
+ case 0x3f4: /* 1 111 110 100 */
+ case 0x3f5: /* 1 111 110 101 */
+ case 0x3f6: /* 1 111 110 110 */
+ case 0x3f7: /* 1 111 110 111 */
+ sprintf(buffer, "XOR@ (R%01d),R%01d",(op&0x38)>>3,op&0x7);
+ break;
+ case 0x3f8: /* 1 111 111 000 */
+ case 0x3f9: /* 1 111 111 001 */
+ case 0x3fa: /* 1 111 111 010 */
+ case 0x3fb: /* 1 111 111 011 */
+ case 0x3fc: /* 1 111 111 100 */
+ case 0x3fd: /* 1 111 111 101 */
+ case 0x3fe: /* 1 111 111 110 */
+ case 0x3ff: /* 1 111 111 111 */
+ size += 1;
+ ea = oprom[1];
+ sprintf(buffer, "XORI #%04X,R%01d",ea,op&0x7);
+ break;
+ default:
+ sprintf(buffer, "????");
+ }
+
+ return size;
+}
diff --git a/src/emu/cpu/cp1610/cp1610.c b/src/emu/cpu/cp1610/cp1610.c
new file mode 100644
index 00000000000..4259b98fba9
--- /dev/null
+++ b/src/emu/cpu/cp1610/cp1610.c
@@ -0,0 +1,3525 @@
+/*****************************************************************************
+ *
+ * cp1610.c
+ * Portable CP1610 emulator (General Instrument CP1610)
+ *
+ * Copyright (c) 2004 Frank Palazzolo, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * palazzol@comcast.net
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on Juergen Buchmueller's F8 emulation,
+ * and the 'General Instruments CP1610' data sheets.
+ * Special thanks to Joe Zbiciak for his GPL'd CP1610 emulator
+ *
+ *****************************************************************************/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "cp1610.h"
+
+#define S 0x80
+#define Z 0x40
+#define OV 0x20
+#define C 0x10
+
+typedef struct {
+ UINT16 r[8]; /* registers */
+ UINT8 flags; /* flags */
+ int intr_enabled;
+ //int (*reset_callback)(void);
+ int (*irq_callback)(int irqline);
+ UINT16 intr_vector;
+ int reset_state;
+ int intr_state;
+ int intrm_state;
+ int reset_pending;
+ int intr_pending;
+ int intrm_pending;
+ int mask_interrupts;
+} cp1610_Regs;
+
+int cp1610_icount;
+
+static cp1610_Regs cp1610;
+
+/* clear all flags */
+#define CLR_SZOC \
+ cp1610.flags &= ~(S|Z|C|OV)
+
+/* clear sign and zero flags */
+#define CLR_SZ \
+ cp1610.flags &= ~(S|Z)
+
+/* clear sign,zero, and carry flags */
+#define CLR_SZC \
+ cp1610.flags &= ~(S|Z|C)
+
+/* set sign and zero flags */
+#define SET_SZ(n) \
+ if (n == 0) \
+ cp1610.flags |= Z; \
+ else \
+ if (n & 0x8000) \
+ cp1610.flags |= S
+
+/* set sign zero, and carry flags */
+#define SET_SZC(n,m) \
+ if (n == 0) \
+ cp1610.flags |= Z; \
+ else \
+ if (n & 0x8000) \
+ cp1610.flags |= S; \
+ if ((n + m) & 0x10000) \
+ cp1610.flags |= C
+
+/* set carry and overflow flags */
+#define SET_COV(n,m,qq) \
+ { unsigned int pp = n + m; \
+ if (pp & 0x10000) \
+ cp1610.flags |= C; \
+ if (qq) \
+ { \
+ if ((n^pp)&(~(m^n))&0x8000) \
+ cp1610.flags |= OV; \
+ if (m == 0x8000) \
+ cp1610.flags ^= OV; \
+ } \
+ else \
+ { \
+ if ((n^pp)&(~(m^n))&0x8000) \
+ cp1610.flags |= OV; \
+ } \
+ }
+
+#if 0
+ if ((n&0x7fff)+(m&0x7fff) > 0x7fff) \
+ { \
+ if (!(cp1610.flags & C))\
+ cp1610.flags |= OV; \
+ } \
+ else \
+ { \
+ if (cp1610.flags & C) \
+ cp1610.flags |= OV; \
+ }
+#endif
+
+/***********************************
+ * illegal opcodes
+ ***********************************/
+static void cp1610_illegal(void)
+{
+ logerror("cp1610 illegal opcode at 0x%04x\n", cp1610.r[7]);
+}
+
+/***************************************************
+ * S Z C OV 0 000 000 000
+ * - - - - HLT
+ ***************************************************/
+static void cp1610_hlt(void)
+{
+ /* TBD */
+ cp1610_icount -= 4;
+}
+
+/***************************************************
+ * S Z C OV 0 000 000 010
+ * - - - - EIS
+ ***************************************************/
+static void cp1610_eis(void)
+{
+ cp1610.mask_interrupts = 1;
+ cp1610.intr_enabled = 1;
+ cp1610_icount -= 4;
+}
+
+/***************************************************
+ * S Z C OV 0 000 000 011
+ * - - - - DIS
+ ***************************************************/
+static void cp1610_dis(void)
+{
+ cp1610.mask_interrupts = 1;
+ cp1610.intr_enabled = 0;
+ cp1610_icount -= 4;
+}
+
+/***************************************************
+ * S Z C OV 0 000 000 101
+ * - - - - TCI
+ ***************************************************/
+static void cp1610_tci(void)
+{
+ /* TBD */
+ cp1610.mask_interrupts = 1;
+ cp1610_icount -= 4;
+}
+
+/***************************************************
+ * S Z C OV 0 000 000 110
+ * - - 0 - CLRC
+ ***************************************************/
+static void cp1610_clrc(void)
+{
+ cp1610.mask_interrupts = 1;
+ cp1610.flags &= ~C;
+ cp1610_icount -= 4;
+}
+
+/***************************************************
+ * S Z C OV 0 000 000 111
+ * - - 1 - SETC
+ ***************************************************/
+static void cp1610_setc(void)
+{
+ cp1610.mask_interrupts = 1;
+ cp1610.flags |= C;
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 000 001 ddd
+ * x x - - INCR Rd
+ ***************************************************/
+static void cp1610_incr(int n)
+{
+ cp1610.r[n]++;
+ CLR_SZ;
+ SET_SZ(cp1610.r[n]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 000 010 ddd
+ * x x - - DECR Rd
+ ***************************************************/
+static void cp1610_decr(int n)
+{
+ cp1610.r[n]--;
+ CLR_SZ;
+ SET_SZ(cp1610.r[n]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 000 011 ddd
+ * x x - - COMR Rd
+ ***************************************************/
+static void cp1610_comr(int n)
+{
+ cp1610.r[n] ^= 0xffff;
+ CLR_SZ;
+ SET_SZ(cp1610.r[n]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 000 100 ddd
+ * x x x x NEGR Rd
+ ***************************************************/
+static void cp1610_negr(int n)
+{
+ UINT32 temp;
+ CLR_SZOC;
+ temp = (cp1610.r[n] ^ 0xffff) + 1;
+ SET_COV(0,temp,1);
+ cp1610.r[n] = temp&0xffff;
+ SET_SZ(cp1610.r[n]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 000 101 ddd
+ * x x x x ADCR Rd
+ ***************************************************/
+static void cp1610_adcr(int n)
+{
+ UINT16 offset = 0;
+ if (cp1610.flags & C)
+ offset = 1;
+ CLR_SZOC;
+ SET_COV(cp1610.r[n],offset,0);
+ cp1610.r[n] += offset;
+ SET_SZ(cp1610.r[n]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 000 110 0dd
+ * - - - - GSWD Rd
+ ***************************************************/
+static void cp1610_gswd(int n)
+{
+ cp1610.r[n] = (cp1610.flags << 8) + cp1610.flags;
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 000 110 10x
+ * - - - - NOP
+ ***************************************************/
+static void cp1610_nop(void)
+{
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 000 110 11x
+ * - - - - SIN
+ ***************************************************/
+static void cp1610_sin(void)
+{
+ /* TBD */
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 000 111 sss
+ * x x x x RSWD Rs
+ ***************************************************/
+static void cp1610_rswd(int n)
+{
+ cp1610.flags = cp1610.r[n];
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 001 000 0rr
+ * x x - - SWAP Rr,1
+ ***************************************************/
+static void cp1610_swap(int r)
+{
+ UINT8 temp;
+ cp1610.mask_interrupts = 1;
+ CLR_SZ;
+ temp = cp1610.r[r] >> 8;
+ cp1610.r[r] = (cp1610.r[r] << 8) | temp;
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 001 000 1rr
+ * x x - - SWAP Rr,2
+ ***************************************************/
+static void cp1610_dswap(int r)
+{
+ /* This instruction was not officially supported by GI */
+ UINT16 temp;
+ cp1610.mask_interrupts = 1;
+ CLR_SZ;
+ temp = cp1610.r[r] & 0xff;
+ cp1610.r[r] = (temp << 8) | temp;
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 0 001 001 0rr
+ * x x - - SLL Rr,1
+ ***************************************************/
+static void cp1610_sll_1(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZ;
+ cp1610.r[r] <<= 1;
+ SET_SZ(cp1610.r[r]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 001 001 1rr
+ * x x - - SLL Rr,2
+ ***************************************************/
+static void cp1610_sll_2(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZ;
+ cp1610.r[r] <<= 2;
+ SET_SZ(cp1610.r[r]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 0 001 010 0rr
+ * x x x - RLC Rr,1
+ ***************************************************/
+static void cp1610_rlc_1(int r)
+{
+ UINT16 offset = 0;
+ cp1610.mask_interrupts = 1;
+ if (cp1610.flags & C)
+ offset = 1;
+ CLR_SZC;
+ if (cp1610.r[r] & 0x8000)
+ cp1610.flags |= C;
+ cp1610.r[r] = (cp1610.r[r] << 1) + offset;
+ SET_SZ(cp1610.r[r]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 001 010 1rr
+ * x x x x RLC Rr,2
+ ***************************************************/
+static void cp1610_rlc_2(int r)
+{
+ UINT16 offset = 0;
+ cp1610.mask_interrupts = 1;
+ switch(cp1610.flags & (C | OV))
+ {
+ case 0:
+ offset = 0;
+ break;
+ case OV:
+ offset = 1;
+ break;
+ case C:
+ offset = 2;
+ break;
+ case (C | OV):
+ offset = 3;
+ break;
+ }
+
+ CLR_SZOC;
+ if (cp1610.r[r] & 0x8000)
+ cp1610.flags |= C;
+ if (cp1610.r[r] & 0x4000)
+ cp1610.flags |= OV;
+ cp1610.r[r] <<= 2;
+ cp1610.r[r] += offset;
+ SET_SZ(cp1610.r[r]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 0 001 011 0rr
+ * x x x - SLLC Rr,1
+ ***************************************************/
+static void cp1610_sllc_1(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZC;
+ if (cp1610.r[r] & 0x8000)
+ cp1610.flags |= C;
+ cp1610.r[r] <<= 1;
+ SET_SZ(cp1610.r[r]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 001 011 1rr
+ * x x x x SLLC Rr,2
+ ***************************************************/
+static void cp1610_sllc_2(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZOC;
+ if (cp1610.r[r] & 0x8000)
+ cp1610.flags |= C;
+ if (cp1610.r[r] & 0x4000)
+ cp1610.flags |= OV;
+ cp1610.r[r] <<= 2;
+ SET_SZ(cp1610.r[r]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 0 001 100 0rr
+ * x x - - SLR Rr,1
+ ***************************************************/
+static void cp1610_slr_1(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZ;
+ cp1610.r[r] >>= 1;
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 001 100 1rr
+ * x x - - SLR Rr,2
+ ***************************************************/
+static void cp1610_slr_2(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZ;
+ cp1610.r[r] >>= 2;
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 0 001 101 0rr
+ * x x - - SAR Rr,1
+ ***************************************************/
+static void cp1610_sar_1(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZ;
+ cp1610.r[r] = (UINT16)(((INT16)(cp1610.r[r])) >> 1);
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 001 101 1rr
+ * x x - - SAR Rr,2
+ ***************************************************/
+static void cp1610_sar_2(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZ;
+ cp1610.r[r] = (UINT16)(((INT16)(cp1610.r[r])) >> 2);
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 0 001 110 0rr
+ * x x x - RRC Rr,1
+ ***************************************************/
+static void cp1610_rrc_1(int r)
+{
+ UINT16 offset = 0;
+ cp1610.mask_interrupts = 1;
+ if (cp1610.flags & C)
+ offset = 0x8000;
+ CLR_SZC;
+ if (cp1610.r[r] & 1)
+ cp1610.flags |= C;
+ cp1610.r[r] >>= 1;
+ cp1610.r[r] += offset;
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 001 110 1rr
+ * x x x x RRC Rr,2
+ ***************************************************/
+static void cp1610_rrc_2(int r)
+{
+ UINT16 offset = 0;
+ cp1610.mask_interrupts = 1;
+ if (cp1610.flags & C)
+ offset |= 0x4000;
+ if (cp1610.flags & OV)
+ offset |= 0x8000;
+ CLR_SZOC;
+ if (cp1610.r[r] & 1)
+ cp1610.flags |= C;
+ if (cp1610.r[r] & 2)
+ cp1610.flags |= OV;
+ cp1610.r[r] >>= 2;
+ cp1610.r[r] += offset;
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 0 001 111 0rr
+ * x x x - SARC Rr,1
+ ***************************************************/
+static void cp1610_sarc_1(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZC;
+ if (cp1610.r[r] & 1)
+ cp1610.flags |= C;
+ cp1610.r[r] = (UINT16)(((INT16)cp1610.r[r]) >> 1);
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 001 111 1rr
+ * x x x x SARC Rr,2
+ ***************************************************/
+static void cp1610_sarc_2(int r)
+{
+ cp1610.mask_interrupts = 1;
+ CLR_SZOC;
+ if (cp1610.r[r] & 1)
+ cp1610.flags |= C;
+ if (cp1610.r[r] & 2)
+ cp1610.flags |= OV;
+ cp1610.r[r] = (UINT16)(((INT16)cp1610.r[r]) >> 2);
+ SET_SZ(cp1610.r[r]);
+ /* S flag is set on bit 7 not bit 15 */
+ cp1610.flags &= ~S;
+ if (cp1610.r[r] & 0x80)
+ cp1610.flags |= S;
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 010 sss sss
+ * x x - - TSTR Rs
+ ***************************************************/
+static void cp1610_tstr(int n)
+{
+ CLR_SZ;
+ SET_SZ(cp1610.r[n]);
+ cp1610_icount -= 6;
+ if (n > 5)
+ cp1610_icount -= 1;
+}
+
+/***************************************************
+ * S Z C OV 0 010 sss ddd (sss != ddd)
+ * x x - - MOVR Rs,Rd
+ ***************************************************/
+static void cp1610_movr(int s, int d)
+{
+ CLR_SZ;
+ cp1610.r[d] = cp1610.r[s];
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 6;
+ if (d > 5)
+ cp1610_icount -= 1;
+}
+
+/***************************************************
+ * S Z C OV 0 011 sss ddd
+ * x x x x ADDR Rs, Rd
+ ***************************************************/
+static void cp1610_addr(int s, int d)
+{
+ CLR_SZOC;
+ SET_COV(cp1610.r[s],cp1610.r[d],0);
+ cp1610.r[d] += cp1610.r[s];
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 100 sss ddd
+ * x x x x SUBR Rs, Rd
+ ***************************************************/
+static void cp1610_subr(int s, int d)
+{
+ CLR_SZOC;
+ SET_COV(cp1610.r[d],(UINT32)((cp1610.r[s]^0xffff)+1),1);
+ cp1610.r[d] -= cp1610.r[s];
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 101 sss ddd
+ * x x x x CMPR Rs, Rd
+ ***************************************************/
+static void cp1610_cmpr(int s, int d)
+{
+ UINT16 temp;
+ CLR_SZOC;
+ SET_COV(cp1610.r[d],(UINT32)((cp1610.r[s]^0xffff)+1),1);
+ temp = cp1610.r[d] - cp1610.r[s];
+ SET_SZ(temp);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 110 sss ddd
+ * x x - - ANDR Rs, Rd
+ ***************************************************/
+static void cp1610_andr(int s, int d)
+{
+ CLR_SZ;
+ cp1610.r[d] &= cp1610.r[s];
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 111 sss ddd (sss != ddd)
+ * x x - - XORR Rs, Rd
+ ***************************************************/
+static void cp1610_xorr(int s, int d)
+{
+ CLR_SZ;
+ cp1610.r[d] ^= cp1610.r[s];
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 0 111 ddd ddd
+ * x x - - CLRR Rd
+ ***************************************************/
+static void cp1610_clrr(int d)
+{
+ CLR_SZ;
+ cp1610.r[d] = 0;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 6;
+}
+
+/***************************************************
+ * S Z C OV 1 000 s00 000 p ppp ppp ppp ppp ppp
+ * - - - - B ADDR
+ ***************************************************/
+static void cp1610_b(int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+}
+
+/***************************************************
+ * S Z C OV 1 000 s01 000 p ppp ppp ppp ppp ppp
+ * - - - - NOPP
+ ***************************************************/
+static void cp1610_nopp(int dir)
+{
+ cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ cp1610_icount -= 7;
+}
+
+/***************************************************
+ * S Z C OV 1 000 s00 001 p ppp ppp ppp ppp ppp
+ * - - - - BC ADDR
+ ***************************************************/
+static void cp1610_bc(int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & C)
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s01 001 p ppp ppp ppp ppp ppp
+ * - - - - BNC ADDR
+ ***************************************************/
+static void cp1610_bnc(int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (!(cp1610.flags & C))
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s00 010 p ppp ppp ppp ppp ppp
+ * - - - - BOV ADDR
+ ***************************************************/
+static void cp1610_bov(int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & OV)
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s01 010 p ppp ppp ppp ppp ppp
+ * - - - - BNOV ADDR
+ ***************************************************/
+static void cp1610_bnov(int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (!(cp1610.flags & OV))
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s00 011 p ppp ppp ppp ppp ppp
+ * - - - - BPL ADDR
+ ***************************************************/
+static void cp1610_bpl(int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (!(cp1610.flags & S))
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s01 011 p ppp ppp ppp ppp ppp
+ * - - - - BMI ADDR
+ ***************************************************/
+static void cp1610_bmi(int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & S)
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s00 100 p ppp ppp ppp ppp ppp
+ * - - - - BZE ADDR
+ ***************************************************/
+static void cp1610_bze(int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & Z)
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s01 100 p ppp ppp ppp ppp ppp
+ * - - - - BNZE ADDR
+ ***************************************************/
+static void cp1610_bnze(int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (!(cp1610.flags & Z))
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s00 101 p ppp ppp ppp ppp ppp
+ * - - - - BLT ADDR
+ ***************************************************/
+static void cp1610_blt(int dir)
+{
+ int condition1 = 0;
+ int condition2 = 0;
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & S) condition1 = 1;
+ if (cp1610.flags & OV) condition2 = 1;
+ if (condition1 ^ condition2)
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s01 101 p ppp ppp ppp ppp ppp
+ * - - - - BGE ADDR
+ ***************************************************/
+static void cp1610_bge(int dir)
+{
+ int condition1 = 0;
+ int condition2 = 0;
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & S) condition1 = 1;
+ if (cp1610.flags & OV) condition2 = 1;
+ if (!(condition1 ^ condition2))
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s00 110 p ppp ppp ppp ppp ppp
+ * - - - - BLE ADDR
+ ***************************************************/
+static void cp1610_ble(int dir)
+{
+ int condition1 = 0;
+ int condition2 = 0;
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & S) condition1 = 1;
+ if (cp1610.flags & OV) condition2 = 1;
+ if ((cp1610.flags & Z) || (condition1 ^ condition2))
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s01 110 p ppp ppp ppp ppp ppp
+ * - - - - BGT ADDR
+ ***************************************************/
+static void cp1610_bgt(int dir)
+{
+ int condition1 = 0;
+ int condition2 = 0;
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & S) condition1 = 1;
+ if (cp1610.flags & OV) condition2 = 1;
+ if (!((cp1610.flags & Z) || (condition1 ^ condition2)))
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s00 111 p ppp ppp ppp ppp ppp
+ * - - - - BUSC ADDR
+ ***************************************************/
+static void cp1610_busc(int dir)
+{
+ int condition1 = 0;
+ int condition2 = 0;
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & C) condition1 = 1;
+ if (cp1610.flags & S) condition2 = 1;
+ if (condition1 ^ condition2)
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s01 111 p ppp ppp ppp ppp ppp
+ * - - - - BESC ADDR
+ ***************************************************/
+static void cp1610_besc(int dir)
+{
+ int condition1 = 0;
+ int condition2 = 0;
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ if (cp1610.flags & C) condition1 = 1;
+ if (cp1610.flags & S) condition2 = 1;
+ if (!(condition1 ^ condition2))
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 000 s1e e p ppp ppp ppp ppp ppp
+ * - - - - BEXT ADDR, eeee
+ ***************************************************/
+static void cp1610_bext(int ext, int dir)
+{
+ UINT16 offset = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ /* TBD */
+ if (0)
+ {
+ cp1610.r[7] += (offset ^ dir);
+ cp1610_icount -= 9;
+ }
+ else
+ {
+ cp1610_icount -= 7;
+ }
+}
+
+/***************************************************
+ * S Z C OV 1 001 000 sss a aaa aaa aaa aaa aaa
+ * - - - - MVO Rs, ADDR
+ ***************************************************/
+static void cp1610_mvo(int s)
+{
+ UINT16 addr;
+ cp1610.mask_interrupts = 1;
+ addr = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ cp1610_writemem16(addr,cp1610.r[s]);
+ cp1610_icount -= 11;
+}
+
+/***************************************************
+ * S Z C OV 1 001 mmm sss (mmm = 0xx)
+ * - - - - MVO@ Rs, Rm
+ ***************************************************/
+static void cp1610_mvoat(int s, int m)
+{
+ cp1610.mask_interrupts = 1;
+ cp1610_writemem16(cp1610.r[m],cp1610.r[s]);
+ cp1610_icount -= 9;
+}
+
+/***************************************************
+ * S Z C OV 1 001 mmm sss (m = 10x or 110)
+ * - - - - MVO@ Rs, Rm
+ ***************************************************/
+static void cp1610_mvoat_i(int s, int m)
+{
+ cp1610.mask_interrupts = 1;
+ cp1610_writemem16(cp1610.r[m],cp1610.r[s]);
+ cp1610.r[m]++;
+ cp1610_icount -= 9;
+}
+
+/***************************************************
+ * S Z C OV 1 001 111 sss I III III III III III
+ * - - - - MVOI Rs, II
+ ***************************************************/
+static void cp1610_mvoi(int s)
+{
+ cp1610.mask_interrupts = 1;
+ cp1610_writemem16(cp1610.r[7],cp1610.r[s]);
+ cp1610.r[7]++;
+ cp1610_icount -= 9;
+}
+
+/***************************************************
+ * S Z C OV 1 010 000 ddd a aaa aaa aaa aaa aaa
+ * - - - - MVI ADDR, Rd
+ ***************************************************/
+static void cp1610_mvi(int d)
+{
+ UINT16 addr = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ cp1610.r[d] = cp1610_readmem16(addr);
+ cp1610_icount -= 10;
+}
+
+/***************************************************
+ * S Z C OV 1 010 mmm ddd (mmm = 0xx)
+ * - - - - MVI@ Rm, Rd
+ ***************************************************/
+static void cp1610_mviat(int m, int d)
+{
+ cp1610.r[d] = cp1610_readmem16(cp1610.r[m]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 010 mmm ddd (mmm = 10x)
+ * - - - - MVI@ Rm, Rd
+ ***************************************************/
+static void cp1610_mviat_i(int m, int d)
+{
+ UINT16 temp = cp1610_readmem16(cp1610.r[m]);
+ cp1610.r[m]++;
+ cp1610.r[d] = temp;
+ cp1610_icount -= 8;
+
+ //cp1610.r[d] = cp1610_readmem16(cp1610.r[m]);
+ //cp1610.r[m]++;
+ //cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 010 110 ddd
+ * - - - - PULR Rd
+ ***************************************************/
+static void cp1610_pulr(int d)
+{
+ cp1610.r[6]--;
+ cp1610.r[d] = cp1610_readmem16(cp1610.r[6]);
+ cp1610_icount -= 11;
+}
+
+/***************************************************
+ * S Z C OV 1 010 111 ddd I III III III III III
+ * - - - - MVII II, Rd
+ ***************************************************/
+static void cp1610_mvii(int d)
+{
+ UINT16 temp = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ cp1610.r[d] = temp;
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 011 000 ddd a aaa aaa aaa aaa aaa
+ * x x x x ADD ADDR, Rd
+ ***************************************************/
+static void cp1610_add(int d)
+{
+ UINT16 addr = cp1610_readop(cp1610.r[7]);
+ UINT16 data = cp1610_readmem16(addr);
+ cp1610.r[7]++;
+ CLR_SZOC;
+ SET_COV(cp1610.r[d],data,0);
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 10;
+}
+
+/***************************************************
+ * S Z C OV 1 011 mmm ddd (mmm = 0xx)
+ * x x x x ADD@ Rm, Rd
+ ***************************************************/
+static void cp1610_addat(int m, int d)
+{
+ UINT16 data = cp1610_readmem16(cp1610.r[m]);
+ CLR_SZOC;
+ SET_COV(cp1610.r[d],data,0);
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 011 mmm ddd (mmm = 10x)
+ * x x x x ADD@ Rm, Rd
+ ***************************************************/
+static void cp1610_addat_i(int m, int d)
+{
+ UINT16 data = cp1610_readmem16(cp1610.r[m]);
+ cp1610.r[m]++;
+ CLR_SZOC;
+ SET_COV(cp1610.r[d],data,0);
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 011 mmm ddd (mmm = 110)
+ * x x x x ADD@ Rm, Rd
+ ***************************************************/
+static void cp1610_addat_d(int m, int d)
+{
+ UINT16 data;
+ cp1610.r[m]--;
+ data = cp1610_readmem16(cp1610.r[m]);
+ CLR_SZOC;
+ SET_COV(cp1610.r[d],data,0);
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 11;
+}
+
+/***************************************************
+ * S Z C OV 1 011 111 ddd I III III III III III
+ * x x x x ADDI II, Rd
+ ***************************************************/
+static void cp1610_addi(int d)
+{
+ UINT16 data;
+ data = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ CLR_SZOC;
+ SET_COV(cp1610.r[d],data,0);
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 100 000 ddd a aaa aaa aaa aaa aaa
+ * x x x x SUB ADDR, Rd
+ ***************************************************/
+static void cp1610_sub(int d)
+{
+ UINT16 addr = cp1610_readop(cp1610.r[7]);
+ UINT32 data = cp1610_readmem16(addr);
+ cp1610.r[7]++;
+ CLR_SZOC;
+ data = (data ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 10;
+}
+
+/***************************************************
+ * S Z C OV 1 100 mmm ddd (mmm = 0xx)
+ * x x x x SUB@ Rm, Rd
+ ***************************************************/
+static void cp1610_subat(int m, int d)
+{
+ UINT32 data = cp1610_readmem16(cp1610.r[m]);
+ CLR_SZOC;
+ data = (data ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 100 mmm ddd (mmm = 10x)
+ * x x x x SUB@ Rm, Rd
+ ***************************************************/
+static void cp1610_subat_i(int m, int d)
+{
+ UINT32 data = cp1610_readmem16(cp1610.r[m]);
+ cp1610.r[m]++;
+ CLR_SZOC;
+ data = (data ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 100 mmm ddd (mmm = 110)
+ * x x x x SUB@ Rm, Rd
+ ***************************************************/
+static void cp1610_subat_d(int m, int d)
+{
+ UINT32 data;
+ cp1610.r[m]--;
+ data = cp1610_readmem16(cp1610.r[m]);
+ CLR_SZOC;
+ data = (data ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 11;
+}
+
+/***************************************************
+ * S Z C OV 1 100 111 ddd I III III III III III
+ * x x x x SUBI II, Rd
+ ***************************************************/
+static void cp1610_subi(int d)
+{
+ UINT32 data;
+ data = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ data = (data ^ 0xffff) + 1;
+ CLR_SZOC;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ cp1610.r[d] += data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 101 000 ddd a aaa aaa aaa aaa aaa
+ * x x x x CMP ADDR, Rd
+ ***************************************************/
+static void cp1610_cmp(int d)
+{
+ UINT16 addr = cp1610_readop(cp1610.r[7]);
+ UINT32 data = cp1610_readmem16(addr);
+ UINT16 res;
+ cp1610.r[7]++;
+ CLR_SZOC;
+ data = (data ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ res = cp1610.r[d] + data;
+ SET_SZ(res);
+ cp1610_icount -= 10;
+}
+
+/***************************************************
+ * S Z C OV 1 101 mmm ddd (mmm = 0xx)
+ * x x x x CMP@ Rm, Rd
+ ***************************************************/
+static void cp1610_cmpat(int m, int d)
+{
+ UINT32 data = cp1610_readmem16(cp1610.r[m]);
+ UINT16 res;
+ CLR_SZOC;
+ data = (data ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ res = cp1610.r[d] + data;
+ SET_SZ(res);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 101 mmm ddd (mmm = 10x)
+ * x x x x CMP@ Rm, Rd
+ ***************************************************/
+static void cp1610_cmpat_i(int m, int d)
+{
+ UINT32 data = cp1610_readmem16(cp1610.r[m]);
+ UINT16 res;
+ cp1610.r[m]++;
+ CLR_SZOC;
+ data = (data ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ res = cp1610.r[d] + data;
+ SET_SZ(res);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 101 mmm ddd (mmm = 110)
+ * x x x x CMP@ Rm, Rd
+ ***************************************************/
+static void cp1610_cmpat_d(int m, int d)
+{
+ UINT32 data;
+ UINT16 res;
+ cp1610.r[m]--;
+ data = cp1610_readmem16(cp1610.r[m]);
+ CLR_SZOC;
+ data = (data ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ res = cp1610.r[d] + data;
+ SET_SZ(res);
+ cp1610_icount -= 11;
+}
+
+/***************************************************
+ * S Z C OV 1 101 111 ddd I III III III III III
+ * x x x x CMPI II, Rd
+ ***************************************************/
+static void cp1610_cmpi(int d)
+{
+ UINT32 data;
+ UINT16 res;
+ data = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ data = (data ^ 0xffff) + 1;
+ CLR_SZOC;
+ SET_COV(cp1610.r[d],data,1);
+ data &= 0xffff;
+ res = cp1610.r[d] + data;
+ SET_SZ(res);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 110 000 ddd a aaa aaa aaa aaa aaa
+ * x x - - AND ADDR, Rd
+ ***************************************************/
+static void cp1610_and(int d)
+{
+ UINT16 addr = cp1610_readop(cp1610.r[7]);
+ UINT16 data = cp1610_readmem16(addr);
+ cp1610.r[7]++;
+ CLR_SZ;
+ cp1610.r[d] &= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 10;
+}
+
+/***************************************************
+ * S Z C OV 1 110 mmm ddd (mmm = 0xx)
+ * x x - - AND@ Rm, Rd
+ ***************************************************/
+static void cp1610_andat(int m, int d)
+{
+ UINT16 data = cp1610_readmem16(cp1610.r[m]);
+ CLR_SZ;
+ cp1610.r[d] &= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 110 mmm ddd (mmm = 10x)
+ * x x - - AND@ Rm, Rd
+ ***************************************************/
+static void cp1610_andat_i(int m, int d)
+{
+ UINT16 data = cp1610_readmem16(cp1610.r[m]);
+ cp1610.r[m]++;
+ CLR_SZ;
+ cp1610.r[d] &= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 110 mmm ddd (mmm = 110)
+ * x x - - AND@ Rm, Rd
+ ***************************************************/
+static void cp1610_andat_d(int m, int d)
+{
+ UINT16 data;
+ cp1610.r[m]--;
+ data = cp1610_readmem16(cp1610.r[m]);
+ CLR_SZ;
+ cp1610.r[d] &= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 11;
+}
+
+/***************************************************
+ * S Z C OV 1 110 111 ddd I III III III III III
+ * x x - - AND II, Rd
+ ***************************************************/
+static void cp1610_andi(int d)
+{
+ UINT16 data;
+ data = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ CLR_SZ;
+ cp1610.r[d] &= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 111 000 ddd a aaa aaa aaa aaa aaa
+ * x x - - XOR ADDR, Rd
+ ***************************************************/
+static void cp1610_xor(int d)
+{
+ UINT16 addr = cp1610_readop(cp1610.r[7]);
+ UINT16 data = cp1610_readmem16(addr);
+ cp1610.r[7]++;
+ CLR_SZ;
+ cp1610.r[d] ^= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 10;
+}
+
+/***************************************************
+ * S Z C OV 1 111 mmm ddd (mmm = 0xx)
+ * x x - - XOR@ Rm, Rd
+ ***************************************************/
+static void cp1610_xorat(int m, int d)
+{
+ UINT16 data = cp1610_readmem16(cp1610.r[m]);
+ CLR_SZ;
+ cp1610.r[d] ^= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 111 mmm ddd (mmm = 10x)
+ * x x - - XOR@ Rm, Rd
+ ***************************************************/
+static void cp1610_xorat_i(int m, int d)
+{
+ UINT16 data = cp1610_readmem16(cp1610.r[m]);
+ cp1610.r[m]++;
+ CLR_SZ;
+ cp1610.r[d] ^= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+/***************************************************
+ * S Z C OV 1 111 mmm ddd (mmm = 110)
+ * x x - - XOR@ Rm, Rd
+ ***************************************************/
+static void cp1610_xorat_d(int m, int d)
+{
+ UINT16 data;
+ cp1610.r[m]--;
+ data = cp1610_readmem16(cp1610.r[m]);
+ CLR_SZ;
+ cp1610.r[d] ^= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 11;
+}
+
+/***************************************************
+ * S Z C OV 1 111 111 ddd I III III III III III
+ * x x - - XOR II, Rd
+ ***************************************************/
+static void cp1610_xori(int d)
+{
+ UINT16 data;
+ data = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+ CLR_SZ;
+ cp1610.r[d] ^= data;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 8;
+}
+
+void cp1610_reset(void)
+{
+ /* This is how we set the reset vector */
+ cpunum_set_input_line(cpu_getactivecpu(), CP1610_RESET, PULSE_LINE);
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 010 mmm ddd (mmm = 0xx)
+ * - - - - SDBD, MVI@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_mviat(int r, int d)
+{
+ cp1610.r[d] = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[d] |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 010 mmm ddd (mmm = 10x)
+ * - - - - SDBD, MVI@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_mviat_i(int r, int d)
+{
+ UINT16 temp;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]++;
+ cp1610.r[d] = temp;
+ temp = (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[r]++;
+ cp1610.r[d] |= temp;
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 010 mmm ddd (mmm = 101)
+ * - - - - SDBD, MVI@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_mviat_d(int r, int d)
+{
+ cp1610.r[r]--;
+ cp1610.r[d] = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]--;
+ cp1610.r[d] |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610_icount -= 17;
+}
+
+/************************************************************************
+ * S Z C OV 0x001 1 010 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU
+ * - - - - SDBD, MVII I-I, Rd
+ ************************************************************************/
+static void cp1610_sdbd_mvii(int d)
+{
+ UINT16 addr;
+ addr = cp1610_readop(cp1610.r[7]) & 0xff;
+ cp1610.r[7]++;
+ addr |= (cp1610_readop(cp1610.r[7]) << 8);
+ cp1610.r[7]++;
+ cp1610.r[d] = addr;
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 011 mmm ddd (mmm = 0xx)
+ * x x x x SDBD, ADD@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_addat(int r, int d)
+{
+ UINT16 temp;
+ CLR_SZOC;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ SET_COV(cp1610.r[d],temp,0);
+ cp1610.r[d] += temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 011 mmm ddd (mmm = 10x)
+ * x x x x SDBD, ADD@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_addat_i(int r, int d)
+{
+ UINT16 temp;
+ CLR_SZOC;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]++;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[r]++;
+ SET_COV(cp1610.r[d],temp,0);
+ cp1610.r[d] += temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 011 mmm ddd (mmm = 101)
+ * x x x x SDBD, ADD@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_addat_d(int r, int d)
+{
+ UINT16 temp;
+ CLR_SZOC;
+ cp1610.r[r]--;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]--;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ SET_COV(cp1610.r[d],temp,0);
+ cp1610.r[d] += temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 17;
+}
+
+/************************************************************************
+ * S Z C OV 0x001 1 011 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU
+ * x x x x SDBD, ADDI I-I, Rd
+ ************************************************************************/
+static void cp1610_sdbd_addi(int d)
+{
+ UINT16 addr;
+ UINT16 temp;
+ CLR_SZOC;
+ addr = cp1610_readop(cp1610.r[7]) & 0xff;
+ cp1610.r[7]++;
+ addr |= (cp1610_readop(cp1610.r[7]) << 8);
+ cp1610.r[7]++;
+ temp = addr;
+ SET_COV(cp1610.r[d],temp,0);
+ cp1610.r[d] += temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 100 mmm ddd (mmm = 0xx)
+ * x x x x SDBD, SUB@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_subat(int r, int d)
+{
+ UINT32 temp;
+ CLR_SZOC;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ temp = (temp ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],temp,1);
+ temp &= 0xffff;
+ cp1610.r[d] += temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 100 mmm ddd (mmm = 10x)
+ * x x x x SDBD, SUB@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_subat_i(int r, int d)
+{
+ UINT32 temp;
+ CLR_SZOC;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]++;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[r]++;
+ temp = (temp ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],temp,1);
+ temp &= 0xffff;
+ cp1610.r[d] += temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 100 mmm ddd (mmm = 101)
+ * x x x x SDBD, SUB@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_subat_d(int r, int d)
+{
+ UINT32 temp;
+ CLR_SZOC;
+ cp1610.r[r]--;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]--;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ temp = (temp ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],temp,1);
+ temp &= 0xffff;
+ cp1610.r[d] += temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 17;
+}
+
+/************************************************************************
+ * S Z C OV 0x001 1 100 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU
+ * x x x x SDBD, SUBI I-I, Rd
+ ************************************************************************/
+static void cp1610_sdbd_subi(int d)
+{
+ UINT16 addr;
+ UINT32 temp;
+ CLR_SZOC;
+ addr = cp1610_readop(cp1610.r[7]) & 0xff;
+ cp1610.r[7]++;
+ addr |= (cp1610_readop(cp1610.r[7]) << 8);
+ cp1610.r[7]++;
+ temp = addr;
+ temp = (temp ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],temp,1);
+ temp &= 0xffff;
+ cp1610.r[d] += temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 101 mmm ddd (mmm = 0xx)
+ * x x x x SDBD, CMP@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_cmpat(int r, int d)
+{
+ UINT32 temp;
+ UINT16 temp2;
+ CLR_SZOC;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ temp = (temp ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],temp,1);
+ temp &= 0xffff;
+ temp2 = cp1610.r[d] + temp;
+ SET_SZ(temp2);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 101 mmm ddd (mmm = 10x)
+ * x x x x SDBD, CMP@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_cmpat_i(int r, int d)
+{
+ UINT32 temp;
+ UINT16 temp2;
+ CLR_SZOC;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]++;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[r]++;
+ temp = (temp ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],temp,1);
+ temp &= 0xffff;
+ temp2 = cp1610.r[d] + temp;
+ SET_SZ(temp2);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 101 mmm ddd (mmm = 101)
+ * x x x x SDBD, CMP@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_cmpat_d(int r, int d)
+{
+ UINT32 temp;
+ UINT16 temp2;
+ CLR_SZOC;
+ cp1610.r[r]--;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]--;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ temp = (temp ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],temp,1);
+ temp &= 0xffff;
+ temp2 = cp1610.r[d] + temp;
+ SET_SZ(temp2);
+ cp1610_icount -= 17;
+}
+
+/************************************************************************
+ * S Z C OV 0x001 1 101 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU
+ * x x x x SDBD, CMPI I-I, Rd
+ ************************************************************************/
+static void cp1610_sdbd_cmpi(int d)
+{
+ UINT16 addr;
+ UINT32 temp;
+ UINT16 temp2;
+ CLR_SZOC;
+ addr = cp1610_readop(cp1610.r[7]) & 0xff;
+ cp1610.r[7]++;
+ addr |= (cp1610_readop(cp1610.r[7]) << 8);
+ cp1610.r[7]++;
+ temp = addr;
+ temp = (temp ^ 0xffff) + 1;
+ SET_COV(cp1610.r[d],temp,1);
+ temp &= 0xffff;
+ temp2 = cp1610.r[d] + temp;
+ SET_SZ(temp2);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 110 mmm ddd (mmm = 0xx)
+ * x x - - SDBD, AND@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_andat(int r, int d)
+{
+ UINT16 temp;
+ CLR_SZ;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[d] &= temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 110 mmm ddd (mmm = 10x)
+ * x x - - SDBD, AND@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_andat_i(int r, int d)
+{
+ UINT16 temp;
+ CLR_SZ;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]++;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[r]++;
+ cp1610.r[d] &= temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 110 mmm ddd (mmm = 101)
+ * x x - - SDBD, AND@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_andat_d(int r, int d)
+{
+ UINT16 temp;
+ CLR_SZ;
+ cp1610.r[r]--;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]--;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[d] &= temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 17;
+}
+
+/************************************************************************
+ * S Z C OV 0x001 1 110 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU
+ * x x - - SDBD, ANDI I-I, Rd
+ ************************************************************************/
+static void cp1610_sdbd_andi(int d)
+{
+ UINT16 addr;
+ CLR_SZ;
+ addr = cp1610_readop(cp1610.r[7]) & 0xff;
+ cp1610.r[7]++;
+ addr |= (cp1610_readop(cp1610.r[7]) << 8);
+ cp1610.r[7]++;
+ cp1610.r[d] &= addr;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 111 mmm ddd (mmm = 0xx)
+ * x x - - SDBD, XOR@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_xorat(int r, int d)
+{
+ UINT16 temp;
+ CLR_SZ;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[d] ^= temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 111 mmm ddd (mmm = 10x)
+ * x x - - SDBD, XOR@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_xorat_i(int r, int d)
+{
+ UINT16 temp;
+ CLR_SZ;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]++;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[r]++;
+ cp1610.r[d] ^= temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV 0x001 1 111 mmm ddd (mmm = 101)
+ * x x - - SDBD, XOR@ Rm, Rd
+ ***************************************************/
+static void cp1610_sdbd_xorat_d(int r, int d)
+{
+ UINT16 temp;
+ CLR_SZ;
+ cp1610.r[r]--;
+ temp = cp1610_readmem16(cp1610.r[r]) & 0xff;
+ cp1610.r[r]--;
+ temp |= (cp1610_readmem16(cp1610.r[r]) << 8);
+ cp1610.r[d] ^= temp;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 17;
+}
+
+/************************************************************************
+ * S Z C OV 0x001 1 111 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU
+ * x x - - SDBD, XORI I-I, Rd
+ ************************************************************************/
+static void cp1610_sdbd_xori(int d)
+{
+ UINT16 addr;
+ CLR_SZ;
+ addr = cp1610_readop(cp1610.r[7]) & 0xff;
+ cp1610.r[7]++;
+ addr |= (cp1610_readop(cp1610.r[7]) << 8);
+ cp1610.r[7]++;
+ cp1610.r[d] ^= addr;
+ SET_SZ(cp1610.r[d]);
+ cp1610_icount -= 14;
+}
+
+/***************************************************
+ * S Z C OV b baa aaa a00 x xxx xxa aaa aaa aaa
+ * - - - - JSR R1bb, ADDR
+ ***************************************************/
+static void cp1610_jsr(int r, UINT16 addr)
+{
+ cp1610.r[r] = cp1610.r[7];
+ cp1610.r[7] = addr;
+}
+
+/***************************************************
+ * S Z C OV b baa aaa a01 x xxx xxa aaa aaa aaa
+ * - - - - JSRE R1bb, ADDR
+ ***************************************************/
+static void cp1610_jsre(int r, UINT16 addr)
+{
+ cp1610.r[r] = cp1610.r[7];
+ cp1610.r[7] = addr;
+ cp1610.intr_enabled = 1;
+}
+
+/***************************************************
+ * S Z C OV b baa aaa a10 x xxx xxa aaa aaa aaa
+ * - - - - JSRD R1bb, ADDR
+ ***************************************************/
+static void cp1610_jsrd(int r, UINT16 addr)
+{
+ cp1610.r[r] = cp1610.r[7];
+ cp1610.r[7] = addr;
+ cp1610.intr_enabled = 0;
+}
+
+/***************************************************
+ * S Z C OV 1 1aa aaa a00 x xxx xxa aaa aaa aaa
+ * - - - - J ADDR
+ ***************************************************/
+static void cp1610_j(UINT16 addr)
+{
+ cp1610.r[7] = addr;
+}
+
+/***************************************************
+ * S Z C OV 1 1aa aaa a01 x xxx xxa aaa aaa aaa
+ * - - - - JE ADDR
+ ***************************************************/
+static void cp1610_je(UINT16 addr)
+{
+ cp1610.r[7] = addr;
+ cp1610.intr_enabled = 1;
+}
+
+/***************************************************
+ * S Z C OV 1 1aa aaa a10 x xxx xxa aaa aaa aaa
+ * - - - - JD ADDR
+ ***************************************************/
+static void cp1610_jd(UINT16 addr)
+{
+ cp1610.r[7] = addr;
+ cp1610.intr_enabled = 0;
+}
+
+static void cp1610_do_sdbd(void)
+{
+ UINT16 sdbdtype, dest;
+
+ /* Even though SDBD is uninterruptable, we don't need to set the mask bit,
+ * because we already treat the SDBD prefixed instructions as uninterruptable
+ */
+ //cp1610.mask_interrupts = 1;
+
+ sdbdtype = cp1610_readop(cp1610.r[7]);
+ dest = sdbdtype & 0x07;
+ cp1610.r[7]++;
+
+ switch (sdbdtype & 0x3f8)
+ {
+ case 0x240: /* Not supporting SDBD MVO@ or SDBD MVOI for now */
+ case 0x248:
+ case 0x250:
+ case 0x258:
+ case 0x260:
+ case 0x268:
+ case 0x270:
+ case 0x278: /* 1 001 xxx xxx */ cp1610_illegal(); break;
+
+ case 0x280: /* 1 010 000 xxx */ cp1610_sdbd_mviat(0,dest); break;
+ case 0x288: /* 1 010 001 xxx */ cp1610_sdbd_mviat(1,dest); break;
+ case 0x290: /* 1 010 010 xxx */ cp1610_sdbd_mviat(2,dest); break;
+ case 0x298: /* 1 010 011 xxx */ cp1610_sdbd_mviat(3,dest); break;
+ case 0x2a0: /* 1 010 100 xxx */ cp1610_sdbd_mviat_i(4,dest); break;
+ case 0x2a8: /* 1 010 101 xxx */ cp1610_sdbd_mviat_i(5,dest); break;
+ case 0x2b0: /* 1 010 110 xxx */ cp1610_sdbd_mviat_d(6,dest); break; /* ??? */
+ case 0x2b8: /* 1 010 111 xxx */ cp1610_sdbd_mvii(dest); break;
+
+ case 0x2c0: /* 1 011 000 xxx */ cp1610_sdbd_addat(0,dest); break;
+ case 0x2c8: /* 1 011 001 xxx */ cp1610_sdbd_addat(1,dest); break;
+ case 0x2d0: /* 1 011 010 xxx */ cp1610_sdbd_addat(2,dest); break;
+ case 0x2d8: /* 1 011 011 xxx */ cp1610_sdbd_addat(3,dest); break;
+ case 0x2e0: /* 1 011 100 xxx */ cp1610_sdbd_addat_i(4,dest); break;
+ case 0x2e8: /* 1 011 101 xxx */ cp1610_sdbd_addat_i(5,dest); break;
+ case 0x2f0: /* 1 011 110 xxx */ cp1610_sdbd_addat_d(6,dest); break; /* ??? */
+ case 0x2f8: /* 1 011 111 xxx */ cp1610_sdbd_addi(dest); break;
+
+ case 0x300: /* 1 100 000 xxx */ cp1610_sdbd_subat(0,dest); break;
+ case 0x308: /* 1 100 001 xxx */ cp1610_sdbd_subat(1,dest); break;
+ case 0x310: /* 1 100 010 xxx */ cp1610_sdbd_subat(2,dest); break;
+ case 0x318: /* 1 100 011 xxx */ cp1610_sdbd_subat(3,dest); break;
+ case 0x320: /* 1 100 100 xxx */ cp1610_sdbd_subat_i(4,dest); break;
+ case 0x328: /* 1 100 101 xxx */ cp1610_sdbd_subat_i(5,dest); break;
+ case 0x330: /* 1 100 110 xxx */ cp1610_sdbd_subat_d(6,dest); break; /* ??? */
+ case 0x338: /* 1 100 111 xxx */ cp1610_sdbd_subi(dest); break;
+
+ case 0x340: /* 1 101 000 xxx */ cp1610_sdbd_cmpat(0,dest); break;
+ case 0x348: /* 1 101 001 xxx */ cp1610_sdbd_cmpat(1,dest); break;
+ case 0x350: /* 1 101 010 xxx */ cp1610_sdbd_cmpat(2,dest); break;
+ case 0x358: /* 1 101 011 xxx */ cp1610_sdbd_cmpat(3,dest); break;
+ case 0x360: /* 1 101 100 xxx */ cp1610_sdbd_cmpat_i(4,dest); break;
+ case 0x368: /* 1 101 101 xxx */ cp1610_sdbd_cmpat_i(5,dest); break;
+ case 0x370: /* 1 101 110 xxx */ cp1610_sdbd_cmpat_d(6,dest); break; /* ??? */
+ case 0x378: /* 1 101 111 xxx */ cp1610_sdbd_cmpi(dest); break;
+
+ case 0x380: /* 1 110 000 xxx */ cp1610_sdbd_andat(0,dest); break;
+ case 0x388: /* 1 110 001 xxx */ cp1610_sdbd_andat(1,dest); break;
+ case 0x390: /* 1 110 010 xxx */ cp1610_sdbd_andat(2,dest); break;
+ case 0x398: /* 1 110 011 xxx */ cp1610_sdbd_andat(3,dest); break;
+ case 0x3a0: /* 1 110 100 xxx */ cp1610_sdbd_andat_i(4,dest); break;
+ case 0x3a8: /* 1 110 101 xxx */ cp1610_sdbd_andat_i(5,dest); break;
+ case 0x3b0: /* 1 110 110 xxx */ cp1610_sdbd_andat_d(6,dest); break; /* ??? */
+ case 0x3b8: /* 1 110 111 xxx */ cp1610_sdbd_andi(dest); break;
+
+ case 0x3c0: /* 1 110 000 xxx */ cp1610_sdbd_xorat(0,dest); break;
+ case 0x3c8: /* 1 110 001 xxx */ cp1610_sdbd_xorat(1,dest); break;
+ case 0x3d0: /* 1 110 010 xxx */ cp1610_sdbd_xorat(2,dest); break;
+ case 0x3d8: /* 1 110 011 xxx */ cp1610_sdbd_xorat(3,dest); break;
+ case 0x3e0: /* 1 110 100 xxx */ cp1610_sdbd_xorat_i(4,dest); break;
+ case 0x3e8: /* 1 110 101 xxx */ cp1610_sdbd_xorat_i(5,dest); break;
+ case 0x3f0: /* 1 110 110 xxx */ cp1610_sdbd_xorat_d(6,dest); break; /* ??? */
+ case 0x3f8: /* 1 110 111 xxx */ cp1610_sdbd_xori(dest); break;
+ default: cp1610_illegal(); break;
+ }
+}
+
+static void cp1610_do_jumps(void)
+{
+ UINT16 jumptype, arg1, arg2, addr;
+
+ arg1 = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+
+ arg2 = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+
+ /*logerror("jumps: pc = 0x%04x, arg1 = 0x%04x, arg2 = 0x%04x\n",cp1610.r[7]-1,arg1,arg2);*/
+ jumptype = arg1 & 0x303;
+ addr = ((arg1 & 0x0fc) << 8) | (arg2 & 0x3ff);
+
+ switch( jumptype )
+ {
+ case 0x000: /* 0 0xx xxx x00 */ cp1610_jsr(4,addr); break;
+ case 0x001: /* 0 0xx xxx x01 */ cp1610_jsre(4,addr); break;
+ case 0x002: /* 0 0xx xxx x10 */ cp1610_jsrd(4,addr); break;
+ case 0x003: /* 0 0xx xxx x11 */ cp1610_illegal(); break;
+
+ case 0x100: /* 0 1xx xxx x00 */ cp1610_jsr(5,addr); break;
+ case 0x101: /* 0 1xx xxx x01 */ cp1610_jsre(5,addr); break;
+ case 0x102: /* 0 1xx xxx x10 */ cp1610_jsrd(5,addr); break;
+ case 0x103: /* 0 1xx xxx x11 */ cp1610_illegal(); break;
+
+ case 0x200: /* 1 0xx xxx x00 */ cp1610_jsr(6,addr); break;
+ case 0x201: /* 1 0xx xxx x01 */ cp1610_jsre(6,addr); break;
+ case 0x202: /* 1 0xx xxx x10 */ cp1610_jsrd(6,addr); break;
+ case 0x203: /* 1 0xx xxx x11 */ cp1610_illegal(); break;
+
+ case 0x300: /* 1 1xx xxx x00 */ cp1610_j(addr); break;
+ case 0x301: /* 1 1xx xxx x01 */ cp1610_je(addr); break;
+ case 0x302: /* 1 1xx xxx x10 */ cp1610_jd(addr); break;
+ case 0x303: /* 1 1xx xxx x11 */ cp1610_illegal(); break;
+ }
+
+ cp1610_icount -= 12;
+}
+
+/* Execute cycles - returns number of cycles actually run */
+int cp1610_execute(int cycles)
+{
+ UINT16 opcode;
+
+ cp1610_icount = cycles;
+
+ do
+ {
+ CALL_MAME_DEBUG;
+
+ cp1610.mask_interrupts = 0;
+
+ opcode = cp1610_readop(cp1610.r[7]);
+ cp1610.r[7]++;
+#if 0
+ logerror("PC:0x%04x, opcode = 0x%03x, ",cp1610.r[7]-1,opcode);
+ logerror("R0:0x%04x, ",cp1610.r[0]);
+ logerror("R1:0x%04x, ",cp1610.r[1]);
+ logerror("R2:0x%04x, ",cp1610.r[2]);
+ logerror("R3:0x%04x, ",cp1610.r[3]);
+ logerror("R4:0x%04x, ",cp1610.r[4]);
+ logerror("R5:0x%04x, ",cp1610.r[5]);
+ logerror("R6:0x%04x\n",cp1610.r[6]);
+#endif
+
+ switch( opcode )
+ {
+ /* opcode bitmask */
+ case 0x000: /* 0 000 000 000 */ cp1610_hlt(); break; /* TBD */
+ case 0x001: /* 0 000 000 001 */ cp1610_do_sdbd(); break;
+ case 0x002: /* 0 000 000 010 */ cp1610_eis(); break; /* TBD */
+ case 0x003: /* 0 000 000 011 */ cp1610_dis(); break; /* TBD */
+ case 0x004: /* 0 000 000 100 */ cp1610_do_jumps(); break;
+ case 0x005: /* 0 000 000 101 */ cp1610_tci(); break; /* TBD */
+ case 0x006: /* 0 000 000 110 */ cp1610_clrc(); break;
+ case 0x007: /* 0 000 000 111 */ cp1610_setc(); break;
+
+ case 0x008: /* 0 000 001 000 */ cp1610_incr(0); break;
+ case 0x009: /* 0 000 001 001 */ cp1610_incr(1); break;
+ case 0x00a: /* 0 000 001 010 */ cp1610_incr(2); break;
+ case 0x00b: /* 0 000 001 011 */ cp1610_incr(3); break;
+ case 0x00c: /* 0 000 001 100 */ cp1610_incr(4); break;
+ case 0x00d: /* 0 000 001 101 */ cp1610_incr(5); break;
+ case 0x00e: /* 0 000 001 110 */ cp1610_incr(6); break;
+ case 0x00f: /* 0 000 001 111 */ cp1610_incr(7); break;
+
+ case 0x010: /* 0 000 010 000 */ cp1610_decr(0); break;
+ case 0x011: /* 0 000 010 001 */ cp1610_decr(1); break;
+ case 0x012: /* 0 000 010 010 */ cp1610_decr(2); break;
+ case 0x013: /* 0 000 010 011 */ cp1610_decr(3); break;
+ case 0x014: /* 0 000 010 100 */ cp1610_decr(4); break;
+ case 0x015: /* 0 000 010 101 */ cp1610_decr(5); break;
+ case 0x016: /* 0 000 010 110 */ cp1610_decr(6); break;
+ case 0x017: /* 0 000 010 111 */ cp1610_decr(7); break;
+
+ case 0x018: /* 0 000 011 000 */ cp1610_comr(0); break;
+ case 0x019: /* 0 000 011 001 */ cp1610_comr(1); break;
+ case 0x01a: /* 0 000 011 010 */ cp1610_comr(2); break;
+ case 0x01b: /* 0 000 011 011 */ cp1610_comr(3); break;
+ case 0x01c: /* 0 000 011 100 */ cp1610_comr(4); break;
+ case 0x01d: /* 0 000 011 101 */ cp1610_comr(5); break;
+ case 0x01e: /* 0 000 011 110 */ cp1610_comr(6); break;
+ case 0x01f: /* 0 000 011 111 */ cp1610_comr(7); break;
+
+ case 0x020: /* 0 000 100 000 */ cp1610_negr(0); break;
+ case 0x021: /* 0 000 100 001 */ cp1610_negr(1); break;
+ case 0x022: /* 0 000 100 010 */ cp1610_negr(2); break;
+ case 0x023: /* 0 000 100 011 */ cp1610_negr(3); break;
+ case 0x024: /* 0 000 100 100 */ cp1610_negr(4); break;
+ case 0x025: /* 0 000 100 101 */ cp1610_negr(5); break;
+ case 0x026: /* 0 000 100 110 */ cp1610_negr(6); break;
+ case 0x027: /* 0 000 100 111 */ cp1610_negr(7); break;
+
+ case 0x028: /* 0 000 101 000 */ cp1610_adcr(0); break;
+ case 0x029: /* 0 000 101 001 */ cp1610_adcr(1); break;
+ case 0x02a: /* 0 000 101 010 */ cp1610_adcr(2); break;
+ case 0x02b: /* 0 000 101 011 */ cp1610_adcr(3); break;
+ case 0x02c: /* 0 000 101 100 */ cp1610_adcr(4); break;
+ case 0x02d: /* 0 000 101 101 */ cp1610_adcr(5); break;
+ case 0x02e: /* 0 000 101 110 */ cp1610_adcr(6); break;
+ case 0x02f: /* 0 000 101 111 */ cp1610_adcr(7); break;
+
+ case 0x030: /* 0 000 110 000 */ cp1610_gswd(0); break;
+ case 0x031: /* 0 000 110 001 */ cp1610_gswd(1); break;
+ case 0x032: /* 0 000 110 010 */ cp1610_gswd(2); break;
+ case 0x033: /* 0 000 110 011 */ cp1610_gswd(3); break;
+ case 0x034: /* 0 000 110 100 */ cp1610_nop(); break;
+ case 0x035: /* 0 000 110 101 */ cp1610_nop(); break;
+ case 0x036: /* 0 000 110 110 */ cp1610_sin(); break; /* TBD */
+ case 0x037: /* 0 000 110 111 */ cp1610_sin(); break; /* TBD */
+
+ case 0x038: /* 0 000 111 000 */ cp1610_rswd(0); break;
+ case 0x039: /* 0 000 111 001 */ cp1610_rswd(1); break;
+ case 0x03a: /* 0 000 111 010 */ cp1610_rswd(2); break;
+ case 0x03b: /* 0 000 111 011 */ cp1610_rswd(3); break;
+ case 0x03c: /* 0 000 111 100 */ cp1610_rswd(4); break;
+ case 0x03d: /* 0 000 111 101 */ cp1610_rswd(5); break;
+ case 0x03e: /* 0 000 111 110 */ cp1610_rswd(6); break;
+ case 0x03f: /* 0 000 111 111 */ cp1610_rswd(7); break;
+
+ case 0x040: /* 0 001 000 000 */ cp1610_swap(0); break;
+ case 0x041: /* 0 001 000 001 */ cp1610_swap(1); break;
+ case 0x042: /* 0 001 000 010 */ cp1610_swap(2); break;
+ case 0x043: /* 0 001 000 011 */ cp1610_swap(3); break;
+ case 0x044: /* 0 001 000 100 */ cp1610_dswap(0); break;
+ case 0x045: /* 0 001 000 101 */ cp1610_dswap(1); break;
+ case 0x046: /* 0 001 000 110 */ cp1610_dswap(2); break;
+ case 0x047: /* 0 001 000 111 */ cp1610_dswap(3); break;
+
+ case 0x048: /* 0 001 001 000 */ cp1610_sll_1(0); break;
+ case 0x049: /* 0 001 001 001 */ cp1610_sll_1(1); break;
+ case 0x04a: /* 0 001 001 010 */ cp1610_sll_1(2); break;
+ case 0x04b: /* 0 001 001 011 */ cp1610_sll_1(3); break;
+ case 0x04c: /* 0 001 001 100 */ cp1610_sll_2(0); break;
+ case 0x04d: /* 0 001 001 101 */ cp1610_sll_2(1); break;
+ case 0x04e: /* 0 001 001 110 */ cp1610_sll_2(2); break;
+ case 0x04f: /* 0 001 001 111 */ cp1610_sll_2(3); break;
+
+ case 0x050: /* 0 001 010 000 */ cp1610_rlc_1(0); break;
+ case 0x051: /* 0 001 010 001 */ cp1610_rlc_1(1); break;
+ case 0x052: /* 0 001 010 010 */ cp1610_rlc_1(2); break;
+ case 0x053: /* 0 001 010 011 */ cp1610_rlc_1(3); break;
+ case 0x054: /* 0 001 010 100 */ cp1610_rlc_2(0); break;
+ case 0x055: /* 0 001 010 101 */ cp1610_rlc_2(1); break;
+ case 0x056: /* 0 001 010 110 */ cp1610_rlc_2(2); break;
+ case 0x057: /* 0 001 010 111 */ cp1610_rlc_2(3); break;
+
+ case 0x058: /* 0 001 011 000 */ cp1610_sllc_1(0); break;
+ case 0x059: /* 0 001 011 001 */ cp1610_sllc_1(1); break;
+ case 0x05a: /* 0 001 011 010 */ cp1610_sllc_1(2); break;
+ case 0x05b: /* 0 001 011 011 */ cp1610_sllc_1(3); break;
+ case 0x05c: /* 0 001 011 100 */ cp1610_sllc_2(0); break;
+ case 0x05d: /* 0 001 011 101 */ cp1610_sllc_2(1); break;
+ case 0x05e: /* 0 001 011 110 */ cp1610_sllc_2(2); break;
+ case 0x05f: /* 0 001 011 111 */ cp1610_sllc_2(3); break;
+
+ case 0x060: /* 0 001 100 000 */ cp1610_slr_1(0); break;
+ case 0x061: /* 0 001 100 001 */ cp1610_slr_1(1); break;
+ case 0x062: /* 0 001 100 010 */ cp1610_slr_1(2); break;
+ case 0x063: /* 0 001 100 011 */ cp1610_slr_1(3); break;
+ case 0x064: /* 0 001 100 100 */ cp1610_slr_2(0); break;
+ case 0x065: /* 0 001 100 101 */ cp1610_slr_2(1); break;
+ case 0x066: /* 0 001 100 110 */ cp1610_slr_2(2); break;
+ case 0x067: /* 0 001 100 111 */ cp1610_slr_2(3); break;
+
+ case 0x068: /* 0 001 101 000 */ cp1610_sar_1(0); break;
+ case 0x069: /* 0 001 101 001 */ cp1610_sar_1(1); break;
+ case 0x06a: /* 0 001 101 010 */ cp1610_sar_1(2); break;
+ case 0x06b: /* 0 001 101 011 */ cp1610_sar_1(3); break;
+ case 0x06c: /* 0 001 101 100 */ cp1610_sar_2(0); break;
+ case 0x06d: /* 0 001 101 101 */ cp1610_sar_2(1); break;
+ case 0x06e: /* 0 001 101 110 */ cp1610_sar_2(2); break;
+ case 0x06f: /* 0 001 101 111 */ cp1610_sar_2(3); break;
+
+ case 0x070: /* 0 001 110 000 */ cp1610_rrc_1(0); break;
+ case 0x071: /* 0 001 110 001 */ cp1610_rrc_1(1); break;
+ case 0x072: /* 0 001 110 010 */ cp1610_rrc_1(2); break;
+ case 0x073: /* 0 001 110 011 */ cp1610_rrc_1(3); break;
+ case 0x074: /* 0 001 110 100 */ cp1610_rrc_2(0); break;
+ case 0x075: /* 0 001 110 101 */ cp1610_rrc_2(1); break;
+ case 0x076: /* 0 001 110 110 */ cp1610_rrc_2(2); break;
+ case 0x077: /* 0 001 110 111 */ cp1610_rrc_2(3); break;
+
+ case 0x078: /* 0 001 111 000 */ cp1610_sarc_1(0); break;
+ case 0x079: /* 0 001 111 001 */ cp1610_sarc_1(1); break;
+ case 0x07a: /* 0 001 111 010 */ cp1610_sarc_1(2); break;
+ case 0x07b: /* 0 001 111 011 */ cp1610_sarc_1(3); break;
+ case 0x07c: /* 0 001 111 100 */ cp1610_sarc_2(0); break;
+ case 0x07d: /* 0 001 111 101 */ cp1610_sarc_2(1); break;
+ case 0x07e: /* 0 001 111 110 */ cp1610_sarc_2(2); break;
+ case 0x07f: /* 0 001 111 111 */ cp1610_sarc_2(3); break;
+
+ case 0x080: /* 0 010 000 000 */ cp1610_tstr(0); break;
+ case 0x081: /* 0 010 000 001 */ cp1610_movr(0,1); break;
+ case 0x082: /* 0 010 000 010 */ cp1610_movr(0,2); break;
+ case 0x083: /* 0 010 000 011 */ cp1610_movr(0,3); break;
+ case 0x084: /* 0 010 000 100 */ cp1610_movr(0,4); break;
+ case 0x085: /* 0 010 000 101 */ cp1610_movr(0,5); break;
+ case 0x086: /* 0 010 000 110 */ cp1610_movr(0,6); break;
+ case 0x087: /* 0 010 000 111 */ cp1610_movr(0,7); break; /* jr */
+
+ case 0x088: /* 0 010 001 000 */ cp1610_movr(1,0); break;
+ case 0x089: /* 0 010 001 001 */ cp1610_tstr(1); break;
+ case 0x08a: /* 0 010 001 010 */ cp1610_movr(1,2); break;
+ case 0x08b: /* 0 010 001 011 */ cp1610_movr(1,3); break;
+ case 0x08c: /* 0 010 001 100 */ cp1610_movr(1,4); break;
+ case 0x08d: /* 0 010 001 101 */ cp1610_movr(1,5); break;
+ case 0x08e: /* 0 010 001 110 */ cp1610_movr(1,6); break;
+ case 0x08f: /* 0 010 001 111 */ cp1610_movr(1,7); break; /* jr */
+
+ case 0x090: /* 0 010 010 000 */ cp1610_movr(2,0); break;
+ case 0x091: /* 0 010 010 001 */ cp1610_movr(2,1); break;
+ case 0x092: /* 0 010 010 010 */ cp1610_tstr(2); break;
+ case 0x093: /* 0 010 010 011 */ cp1610_movr(2,3); break;
+ case 0x094: /* 0 010 010 100 */ cp1610_movr(2,4); break;
+ case 0x095: /* 0 010 010 101 */ cp1610_movr(2,5); break;
+ case 0x096: /* 0 010 010 110 */ cp1610_movr(2,6); break;
+ case 0x097: /* 0 010 010 111 */ cp1610_movr(2,7); break; /* jr */
+
+ case 0x098: /* 0 010 011 000 */ cp1610_movr(3,0); break;
+ case 0x099: /* 0 010 011 001 */ cp1610_movr(3,1); break;
+ case 0x09a: /* 0 010 011 010 */ cp1610_movr(3,2); break;
+ case 0x09b: /* 0 010 011 011 */ cp1610_tstr(3); break;
+ case 0x09c: /* 0 010 011 100 */ cp1610_movr(3,4); break;
+ case 0x09d: /* 0 010 011 101 */ cp1610_movr(3,5); break;
+ case 0x09e: /* 0 010 011 110 */ cp1610_movr(3,6); break;
+ case 0x09f: /* 0 010 011 111 */ cp1610_movr(3,7); break; /* jr */
+
+ case 0x0a0: /* 0 010 100 000 */ cp1610_movr(4,0); break;
+ case 0x0a1: /* 0 010 100 001 */ cp1610_movr(4,1); break;
+ case 0x0a2: /* 0 010 100 010 */ cp1610_movr(4,2); break;
+ case 0x0a3: /* 0 010 100 011 */ cp1610_movr(4,3); break;
+ case 0x0a4: /* 0 010 100 100 */ cp1610_tstr(4); break;
+ case 0x0a5: /* 0 010 100 101 */ cp1610_movr(4,5); break;
+ case 0x0a6: /* 0 010 100 110 */ cp1610_movr(4,6); break;
+ case 0x0a7: /* 0 010 100 111 */ cp1610_movr(4,7); break; /* jr */
+
+ case 0x0a8: /* 0 010 101 000 */ cp1610_movr(5,0); break;
+ case 0x0a9: /* 0 010 101 001 */ cp1610_movr(5,1); break;
+ case 0x0aa: /* 0 010 101 010 */ cp1610_movr(5,2); break;
+ case 0x0ab: /* 0 010 101 011 */ cp1610_movr(5,3); break;
+ case 0x0ac: /* 0 010 101 100 */ cp1610_movr(5,4); break;
+ case 0x0ad: /* 0 010 101 101 */ cp1610_tstr(5); break;
+ case 0x0ae: /* 0 010 101 110 */ cp1610_movr(5,6); break;
+ case 0x0af: /* 0 010 101 111 */ cp1610_movr(5,7); break; /* jr */
+
+ case 0x0b0: /* 0 010 110 000 */ cp1610_movr(6,0); break;
+ case 0x0b1: /* 0 010 110 001 */ cp1610_movr(6,1); break;
+ case 0x0b2: /* 0 010 110 010 */ cp1610_movr(6,2); break;
+ case 0x0b3: /* 0 010 110 011 */ cp1610_movr(6,3); break;
+ case 0x0b4: /* 0 010 110 100 */ cp1610_movr(6,4); break;
+ case 0x0b5: /* 0 010 110 101 */ cp1610_movr(6,5); break;
+ case 0x0b6: /* 0 010 110 110 */ cp1610_tstr(6); break;
+ case 0x0b7: /* 0 010 110 111 */ cp1610_movr(6,7); break; /* jr */
+
+ case 0x0b8: /* 0 010 111 000 */ cp1610_movr(7,0); break;
+ case 0x0b9: /* 0 010 111 001 */ cp1610_movr(7,1); break;
+ case 0x0ba: /* 0 010 111 010 */ cp1610_movr(7,2); break;
+ case 0x0bb: /* 0 010 111 011 */ cp1610_movr(7,3); break;
+ case 0x0bc: /* 0 010 111 100 */ cp1610_movr(7,4); break;
+ case 0x0bd: /* 0 010 111 101 */ cp1610_movr(7,5); break;
+ case 0x0be: /* 0 010 111 110 */ cp1610_movr(7,6); break;
+ case 0x0bf: /* 0 010 111 111 */ cp1610_tstr(7); break;
+
+ case 0x0c0: /* 0 011 000 000 */ cp1610_addr(0,0); break;
+ case 0x0c1: /* 0 011 000 001 */ cp1610_addr(0,1); break;
+ case 0x0c2: /* 0 011 000 010 */ cp1610_addr(0,2); break;
+ case 0x0c3: /* 0 011 000 011 */ cp1610_addr(0,3); break;
+ case 0x0c4: /* 0 011 000 100 */ cp1610_addr(0,4); break;
+ case 0x0c5: /* 0 011 000 101 */ cp1610_addr(0,5); break;
+ case 0x0c6: /* 0 011 000 110 */ cp1610_addr(0,6); break;
+ case 0x0c7: /* 0 011 000 111 */ cp1610_addr(0,7); break;
+
+ case 0x0c8: /* 0 011 001 000 */ cp1610_addr(1,0); break;
+ case 0x0c9: /* 0 011 001 001 */ cp1610_addr(1,1); break;
+ case 0x0ca: /* 0 011 001 010 */ cp1610_addr(1,2); break;
+ case 0x0cb: /* 0 011 001 011 */ cp1610_addr(1,3); break;
+ case 0x0cc: /* 0 011 001 100 */ cp1610_addr(1,4); break;
+ case 0x0cd: /* 0 011 001 101 */ cp1610_addr(1,5); break;
+ case 0x0ce: /* 0 011 001 110 */ cp1610_addr(1,6); break;
+ case 0x0cf: /* 0 011 001 111 */ cp1610_addr(1,7); break;
+
+ case 0x0d0: /* 0 011 010 000 */ cp1610_addr(2,0); break;
+ case 0x0d1: /* 0 011 010 001 */ cp1610_addr(2,1); break;
+ case 0x0d2: /* 0 011 010 010 */ cp1610_addr(2,2); break;
+ case 0x0d3: /* 0 011 010 011 */ cp1610_addr(2,3); break;
+ case 0x0d4: /* 0 011 010 100 */ cp1610_addr(2,4); break;
+ case 0x0d5: /* 0 011 010 101 */ cp1610_addr(2,5); break;
+ case 0x0d6: /* 0 011 010 110 */ cp1610_addr(2,6); break;
+ case 0x0d7: /* 0 011 010 111 */ cp1610_addr(2,7); break;
+
+ case 0x0d8: /* 0 011 011 000 */ cp1610_addr(3,0); break;
+ case 0x0d9: /* 0 011 011 001 */ cp1610_addr(3,1); break;
+ case 0x0da: /* 0 011 011 010 */ cp1610_addr(3,2); break;
+ case 0x0db: /* 0 011 011 011 */ cp1610_addr(3,3); break;
+ case 0x0dc: /* 0 011 011 100 */ cp1610_addr(3,4); break;
+ case 0x0dd: /* 0 011 011 101 */ cp1610_addr(3,5); break;
+ case 0x0de: /* 0 011 011 110 */ cp1610_addr(3,6); break;
+ case 0x0df: /* 0 011 011 111 */ cp1610_addr(3,7); break;
+
+ case 0x0e0: /* 0 011 100 000 */ cp1610_addr(4,0); break;
+ case 0x0e1: /* 0 011 100 001 */ cp1610_addr(4,1); break;
+ case 0x0e2: /* 0 011 100 010 */ cp1610_addr(4,2); break;
+ case 0x0e3: /* 0 011 100 011 */ cp1610_addr(4,3); break;
+ case 0x0e4: /* 0 011 100 100 */ cp1610_addr(4,4); break;
+ case 0x0e5: /* 0 011 100 101 */ cp1610_addr(4,5); break;
+ case 0x0e6: /* 0 011 100 110 */ cp1610_addr(4,6); break;
+ case 0x0e7: /* 0 011 100 111 */ cp1610_addr(4,7); break;
+
+ case 0x0e8: /* 0 011 101 000 */ cp1610_addr(5,0); break;
+ case 0x0e9: /* 0 011 101 001 */ cp1610_addr(5,1); break;
+ case 0x0ea: /* 0 011 101 010 */ cp1610_addr(5,2); break;
+ case 0x0eb: /* 0 011 101 011 */ cp1610_addr(5,3); break;
+ case 0x0ec: /* 0 011 101 100 */ cp1610_addr(5,4); break;
+ case 0x0ed: /* 0 011 101 101 */ cp1610_addr(5,5); break;
+ case 0x0ee: /* 0 011 101 110 */ cp1610_addr(5,6); break;
+ case 0x0ef: /* 0 011 101 111 */ cp1610_addr(5,7); break;
+
+ case 0x0f0: /* 0 011 110 000 */ cp1610_addr(6,0); break;
+ case 0x0f1: /* 0 011 110 001 */ cp1610_addr(6,1); break;
+ case 0x0f2: /* 0 011 110 010 */ cp1610_addr(6,2); break;
+ case 0x0f3: /* 0 011 110 011 */ cp1610_addr(6,3); break;
+ case 0x0f4: /* 0 011 110 100 */ cp1610_addr(6,4); break;
+ case 0x0f5: /* 0 011 110 101 */ cp1610_addr(6,5); break;
+ case 0x0f6: /* 0 011 110 110 */ cp1610_addr(6,6); break;
+ case 0x0f7: /* 0 011 110 111 */ cp1610_addr(6,7); break;
+
+ case 0x0f8: /* 0 011 111 000 */ cp1610_addr(7,0); break;
+ case 0x0f9: /* 0 011 111 001 */ cp1610_addr(7,1); break;
+ case 0x0fa: /* 0 011 111 010 */ cp1610_addr(7,2); break;
+ case 0x0fb: /* 0 011 111 011 */ cp1610_addr(7,3); break;
+ case 0x0fc: /* 0 011 111 100 */ cp1610_addr(7,4); break;
+ case 0x0fd: /* 0 011 111 101 */ cp1610_addr(7,5); break;
+ case 0x0fe: /* 0 011 111 110 */ cp1610_addr(7,6); break;
+ case 0x0ff: /* 0 011 111 111 */ cp1610_addr(7,7); break;
+
+ case 0x100: /* 0 100 000 000 */ cp1610_subr(0,0); break;
+ case 0x101: /* 0 100 000 001 */ cp1610_subr(0,1); break;
+ case 0x102: /* 0 100 000 010 */ cp1610_subr(0,2); break;
+ case 0x103: /* 0 100 000 011 */ cp1610_subr(0,3); break;
+ case 0x104: /* 0 100 000 100 */ cp1610_subr(0,4); break;
+ case 0x105: /* 0 100 000 101 */ cp1610_subr(0,5); break;
+ case 0x106: /* 0 100 000 110 */ cp1610_subr(0,6); break;
+ case 0x107: /* 0 100 000 111 */ cp1610_subr(0,7); break;
+
+ case 0x108: /* 0 100 001 000 */ cp1610_subr(1,0); break;
+ case 0x109: /* 0 100 001 001 */ cp1610_subr(1,1); break;
+ case 0x10a: /* 0 100 001 010 */ cp1610_subr(1,2); break;
+ case 0x10b: /* 0 100 001 011 */ cp1610_subr(1,3); break;
+ case 0x10c: /* 0 100 001 100 */ cp1610_subr(1,4); break;
+ case 0x10d: /* 0 100 001 101 */ cp1610_subr(1,5); break;
+ case 0x10e: /* 0 100 001 110 */ cp1610_subr(1,6); break;
+ case 0x10f: /* 0 100 001 111 */ cp1610_subr(1,7); break;
+
+ case 0x110: /* 0 100 010 000 */ cp1610_subr(2,0); break;
+ case 0x111: /* 0 100 010 001 */ cp1610_subr(2,1); break;
+ case 0x112: /* 0 100 010 010 */ cp1610_subr(2,2); break;
+ case 0x113: /* 0 100 010 011 */ cp1610_subr(2,3); break;
+ case 0x114: /* 0 100 010 100 */ cp1610_subr(2,4); break;
+ case 0x115: /* 0 100 010 101 */ cp1610_subr(2,5); break;
+ case 0x116: /* 0 100 010 110 */ cp1610_subr(2,6); break;
+ case 0x117: /* 0 100 010 111 */ cp1610_subr(2,7); break;
+
+ case 0x118: /* 0 100 011 000 */ cp1610_subr(3,0); break;
+ case 0x119: /* 0 100 011 001 */ cp1610_subr(3,1); break;
+ case 0x11a: /* 0 100 011 010 */ cp1610_subr(3,2); break;
+ case 0x11b: /* 0 100 011 011 */ cp1610_subr(3,3); break;
+ case 0x11c: /* 0 100 011 100 */ cp1610_subr(3,4); break;
+ case 0x11d: /* 0 100 011 101 */ cp1610_subr(3,5); break;
+ case 0x11e: /* 0 100 011 110 */ cp1610_subr(3,6); break;
+ case 0x11f: /* 0 100 011 111 */ cp1610_subr(3,7); break;
+
+ case 0x120: /* 0 100 100 000 */ cp1610_subr(4,0); break;
+ case 0x121: /* 0 100 100 001 */ cp1610_subr(4,1); break;
+ case 0x122: /* 0 100 100 010 */ cp1610_subr(4,2); break;
+ case 0x123: /* 0 100 100 011 */ cp1610_subr(4,3); break;
+ case 0x124: /* 0 100 100 100 */ cp1610_subr(4,4); break;
+ case 0x125: /* 0 100 100 101 */ cp1610_subr(4,5); break;
+ case 0x126: /* 0 100 100 110 */ cp1610_subr(4,6); break;
+ case 0x127: /* 0 100 100 111 */ cp1610_subr(4,7); break;
+
+ case 0x128: /* 0 100 101 000 */ cp1610_subr(5,0); break;
+ case 0x129: /* 0 100 101 001 */ cp1610_subr(5,1); break;
+ case 0x12a: /* 0 100 101 010 */ cp1610_subr(5,2); break;
+ case 0x12b: /* 0 100 101 011 */ cp1610_subr(5,3); break;
+ case 0x12c: /* 0 100 101 100 */ cp1610_subr(5,4); break;
+ case 0x12d: /* 0 100 101 101 */ cp1610_subr(5,5); break;
+ case 0x12e: /* 0 100 101 110 */ cp1610_subr(5,6); break;
+ case 0x12f: /* 0 100 101 111 */ cp1610_subr(5,7); break;
+
+ case 0x130: /* 0 100 110 000 */ cp1610_subr(6,0); break;
+ case 0x131: /* 0 100 110 001 */ cp1610_subr(6,1); break;
+ case 0x132: /* 0 100 110 010 */ cp1610_subr(6,2); break;
+ case 0x133: /* 0 100 110 011 */ cp1610_subr(6,3); break;
+ case 0x134: /* 0 100 110 100 */ cp1610_subr(6,4); break;
+ case 0x135: /* 0 100 110 101 */ cp1610_subr(6,5); break;
+ case 0x136: /* 0 100 110 110 */ cp1610_subr(6,6); break;
+ case 0x137: /* 0 100 110 111 */ cp1610_subr(6,7); break;
+
+ case 0x138: /* 0 100 111 000 */ cp1610_subr(7,0); break;
+ case 0x139: /* 0 100 111 001 */ cp1610_subr(7,1); break;
+ case 0x13a: /* 0 100 111 010 */ cp1610_subr(7,2); break;
+ case 0x13b: /* 0 100 111 011 */ cp1610_subr(7,3); break;
+ case 0x13c: /* 0 100 111 100 */ cp1610_subr(7,4); break;
+ case 0x13d: /* 0 100 111 101 */ cp1610_subr(7,5); break;
+ case 0x13e: /* 0 100 111 110 */ cp1610_subr(7,6); break;
+ case 0x13f: /* 0 100 111 111 */ cp1610_subr(7,7); break;
+
+ case 0x140: /* 0 101 000 000 */ cp1610_cmpr(0,0); break;
+ case 0x141: /* 0 101 000 001 */ cp1610_cmpr(0,1); break;
+ case 0x142: /* 0 101 000 010 */ cp1610_cmpr(0,2); break;
+ case 0x143: /* 0 101 000 011 */ cp1610_cmpr(0,3); break;
+ case 0x144: /* 0 101 000 100 */ cp1610_cmpr(0,4); break;
+ case 0x145: /* 0 101 000 101 */ cp1610_cmpr(0,5); break;
+ case 0x146: /* 0 101 000 110 */ cp1610_cmpr(0,6); break;
+ case 0x147: /* 0 101 000 111 */ cp1610_cmpr(0,7); break;
+
+ case 0x148: /* 0 101 001 000 */ cp1610_cmpr(1,0); break;
+ case 0x149: /* 0 101 001 001 */ cp1610_cmpr(1,1); break;
+ case 0x14a: /* 0 101 001 010 */ cp1610_cmpr(1,2); break;
+ case 0x14b: /* 0 101 001 011 */ cp1610_cmpr(1,3); break;
+ case 0x14c: /* 0 101 001 100 */ cp1610_cmpr(1,4); break;
+ case 0x14d: /* 0 101 001 101 */ cp1610_cmpr(1,5); break;
+ case 0x14e: /* 0 101 001 110 */ cp1610_cmpr(1,6); break;
+ case 0x14f: /* 0 101 001 111 */ cp1610_cmpr(1,7); break;
+
+ case 0x150: /* 0 101 010 000 */ cp1610_cmpr(2,0); break;
+ case 0x151: /* 0 101 010 001 */ cp1610_cmpr(2,1); break;
+ case 0x152: /* 0 101 010 010 */ cp1610_cmpr(2,2); break;
+ case 0x153: /* 0 101 010 011 */ cp1610_cmpr(2,3); break;
+ case 0x154: /* 0 101 010 100 */ cp1610_cmpr(2,4); break;
+ case 0x155: /* 0 101 010 101 */ cp1610_cmpr(2,5); break;
+ case 0x156: /* 0 101 010 110 */ cp1610_cmpr(2,6); break;
+ case 0x157: /* 0 101 010 111 */ cp1610_cmpr(2,7); break;
+
+ case 0x158: /* 0 101 011 000 */ cp1610_cmpr(3,0); break;
+ case 0x159: /* 0 101 011 001 */ cp1610_cmpr(3,1); break;
+ case 0x15a: /* 0 101 011 010 */ cp1610_cmpr(3,2); break;
+ case 0x15b: /* 0 101 011 011 */ cp1610_cmpr(3,3); break;
+ case 0x15c: /* 0 101 011 100 */ cp1610_cmpr(3,4); break;
+ case 0x15d: /* 0 101 011 101 */ cp1610_cmpr(3,5); break;
+ case 0x15e: /* 0 101 011 110 */ cp1610_cmpr(3,6); break;
+ case 0x15f: /* 0 101 011 111 */ cp1610_cmpr(3,7); break;
+
+ case 0x160: /* 0 101 100 000 */ cp1610_cmpr(4,0); break;
+ case 0x161: /* 0 101 100 001 */ cp1610_cmpr(4,1); break;
+ case 0x162: /* 0 101 100 010 */ cp1610_cmpr(4,2); break;
+ case 0x163: /* 0 101 100 011 */ cp1610_cmpr(4,3); break;
+ case 0x164: /* 0 101 100 100 */ cp1610_cmpr(4,4); break;
+ case 0x165: /* 0 101 100 101 */ cp1610_cmpr(4,5); break;
+ case 0x166: /* 0 101 100 110 */ cp1610_cmpr(4,6); break;
+ case 0x167: /* 0 101 100 111 */ cp1610_cmpr(4,7); break;
+
+ case 0x168: /* 0 101 101 000 */ cp1610_cmpr(5,0); break;
+ case 0x169: /* 0 101 101 001 */ cp1610_cmpr(5,1); break;
+ case 0x16a: /* 0 101 101 010 */ cp1610_cmpr(5,2); break;
+ case 0x16b: /* 0 101 101 011 */ cp1610_cmpr(5,3); break;
+ case 0x16c: /* 0 101 101 100 */ cp1610_cmpr(5,4); break;
+ case 0x16d: /* 0 101 101 101 */ cp1610_cmpr(5,5); break;
+ case 0x16e: /* 0 101 101 110 */ cp1610_cmpr(5,6); break;
+ case 0x16f: /* 0 101 101 111 */ cp1610_cmpr(5,7); break;
+
+ case 0x170: /* 0 101 110 000 */ cp1610_cmpr(6,0); break;
+ case 0x171: /* 0 101 110 001 */ cp1610_cmpr(6,1); break;
+ case 0x172: /* 0 101 110 010 */ cp1610_cmpr(6,2); break;
+ case 0x173: /* 0 101 110 011 */ cp1610_cmpr(6,3); break;
+ case 0x174: /* 0 101 110 100 */ cp1610_cmpr(6,4); break;
+ case 0x175: /* 0 101 110 101 */ cp1610_cmpr(6,5); break;
+ case 0x176: /* 0 101 110 110 */ cp1610_cmpr(6,6); break;
+ case 0x177: /* 0 101 110 111 */ cp1610_cmpr(6,7); break;
+
+ case 0x178: /* 0 101 111 000 */ cp1610_cmpr(7,0); break;
+ case 0x179: /* 0 101 111 001 */ cp1610_cmpr(7,1); break;
+ case 0x17a: /* 0 101 111 010 */ cp1610_cmpr(7,2); break;
+ case 0x17b: /* 0 101 111 011 */ cp1610_cmpr(7,3); break;
+ case 0x17c: /* 0 101 111 100 */ cp1610_cmpr(7,4); break;
+ case 0x17d: /* 0 101 111 101 */ cp1610_cmpr(7,5); break;
+ case 0x17e: /* 0 101 111 110 */ cp1610_cmpr(7,6); break;
+ case 0x17f: /* 0 101 111 111 */ cp1610_cmpr(7,7); break;
+
+ case 0x180: /* 0 110 000 000 */ cp1610_andr(0,0); break;
+ case 0x181: /* 0 110 000 001 */ cp1610_andr(0,1); break;
+ case 0x182: /* 0 110 000 010 */ cp1610_andr(0,2); break;
+ case 0x183: /* 0 110 000 011 */ cp1610_andr(0,3); break;
+ case 0x184: /* 0 110 000 100 */ cp1610_andr(0,4); break;
+ case 0x185: /* 0 110 000 101 */ cp1610_andr(0,5); break;
+ case 0x186: /* 0 110 000 110 */ cp1610_andr(0,6); break;
+ case 0x187: /* 0 110 000 111 */ cp1610_andr(0,7); break;
+
+ case 0x188: /* 0 110 001 000 */ cp1610_andr(1,0); break;
+ case 0x189: /* 0 110 001 001 */ cp1610_andr(1,1); break;
+ case 0x18a: /* 0 110 001 010 */ cp1610_andr(1,2); break;
+ case 0x18b: /* 0 110 001 011 */ cp1610_andr(1,3); break;
+ case 0x18c: /* 0 110 001 100 */ cp1610_andr(1,4); break;
+ case 0x18d: /* 0 110 001 101 */ cp1610_andr(1,5); break;
+ case 0x18e: /* 0 110 001 110 */ cp1610_andr(1,6); break;
+ case 0x18f: /* 0 110 001 111 */ cp1610_andr(1,7); break;
+
+ case 0x190: /* 0 110 010 000 */ cp1610_andr(2,0); break;
+ case 0x191: /* 0 110 010 001 */ cp1610_andr(2,1); break;
+ case 0x192: /* 0 110 010 010 */ cp1610_andr(2,2); break;
+ case 0x193: /* 0 110 010 011 */ cp1610_andr(2,3); break;
+ case 0x194: /* 0 110 010 100 */ cp1610_andr(2,4); break;
+ case 0x195: /* 0 110 010 101 */ cp1610_andr(2,5); break;
+ case 0x196: /* 0 110 010 110 */ cp1610_andr(2,6); break;
+ case 0x197: /* 0 110 010 111 */ cp1610_andr(2,7); break;
+
+ case 0x198: /* 0 110 011 000 */ cp1610_andr(3,0); break;
+ case 0x199: /* 0 110 011 001 */ cp1610_andr(3,1); break;
+ case 0x19a: /* 0 110 011 010 */ cp1610_andr(3,2); break;
+ case 0x19b: /* 0 110 011 011 */ cp1610_andr(3,3); break;
+ case 0x19c: /* 0 110 011 100 */ cp1610_andr(3,4); break;
+ case 0x19d: /* 0 110 011 101 */ cp1610_andr(3,5); break;
+ case 0x19e: /* 0 110 011 110 */ cp1610_andr(3,6); break;
+ case 0x19f: /* 0 110 011 111 */ cp1610_andr(3,7); break;
+
+ case 0x1a0: /* 0 110 100 000 */ cp1610_andr(4,0); break;
+ case 0x1a1: /* 0 110 100 001 */ cp1610_andr(4,1); break;
+ case 0x1a2: /* 0 110 100 010 */ cp1610_andr(4,2); break;
+ case 0x1a3: /* 0 110 100 011 */ cp1610_andr(4,3); break;
+ case 0x1a4: /* 0 110 100 100 */ cp1610_andr(4,4); break;
+ case 0x1a5: /* 0 110 100 101 */ cp1610_andr(4,5); break;
+ case 0x1a6: /* 0 110 100 110 */ cp1610_andr(4,6); break;
+ case 0x1a7: /* 0 110 100 111 */ cp1610_andr(4,7); break;
+
+ case 0x1a8: /* 0 110 101 000 */ cp1610_andr(5,0); break;
+ case 0x1a9: /* 0 110 101 001 */ cp1610_andr(5,1); break;
+ case 0x1aa: /* 0 110 101 010 */ cp1610_andr(5,2); break;
+ case 0x1ab: /* 0 110 101 011 */ cp1610_andr(5,3); break;
+ case 0x1ac: /* 0 110 101 100 */ cp1610_andr(5,4); break;
+ case 0x1ad: /* 0 110 101 101 */ cp1610_andr(5,5); break;
+ case 0x1ae: /* 0 110 101 110 */ cp1610_andr(5,6); break;
+ case 0x1af: /* 0 110 101 111 */ cp1610_andr(5,7); break;
+
+ case 0x1b0: /* 0 110 110 000 */ cp1610_andr(6,0); break;
+ case 0x1b1: /* 0 110 110 001 */ cp1610_andr(6,1); break;
+ case 0x1b2: /* 0 110 110 010 */ cp1610_andr(6,2); break;
+ case 0x1b3: /* 0 110 110 011 */ cp1610_andr(6,3); break;
+ case 0x1b4: /* 0 110 110 100 */ cp1610_andr(6,4); break;
+ case 0x1b5: /* 0 110 110 101 */ cp1610_andr(6,5); break;
+ case 0x1b6: /* 0 110 110 110 */ cp1610_andr(6,6); break;
+ case 0x1b7: /* 0 110 110 111 */ cp1610_andr(6,7); break;
+
+ case 0x1b8: /* 0 110 111 000 */ cp1610_andr(7,0); break;
+ case 0x1b9: /* 0 110 111 001 */ cp1610_andr(7,1); break;
+ case 0x1ba: /* 0 110 111 010 */ cp1610_andr(7,2); break;
+ case 0x1bb: /* 0 110 111 011 */ cp1610_andr(7,3); break;
+ case 0x1bc: /* 0 110 111 100 */ cp1610_andr(7,4); break;
+ case 0x1bd: /* 0 110 111 101 */ cp1610_andr(7,5); break;
+ case 0x1be: /* 0 110 111 110 */ cp1610_andr(7,6); break;
+ case 0x1bf: /* 0 110 111 111 */ cp1610_andr(7,7); break;
+
+ case 0x1c0: /* 0 111 000 000 */ cp1610_clrr(0); break;
+ case 0x1c1: /* 0 111 000 001 */ cp1610_xorr(0,1); break;
+ case 0x1c2: /* 0 111 000 010 */ cp1610_xorr(0,2); break;
+ case 0x1c3: /* 0 111 000 011 */ cp1610_xorr(0,3); break;
+ case 0x1c4: /* 0 111 000 100 */ cp1610_xorr(0,4); break;
+ case 0x1c5: /* 0 111 000 101 */ cp1610_xorr(0,5); break;
+ case 0x1c6: /* 0 111 000 110 */ cp1610_xorr(0,6); break;
+ case 0x1c7: /* 0 111 000 111 */ cp1610_xorr(0,7); break;
+
+ case 0x1c8: /* 0 111 001 000 */ cp1610_xorr(1,0); break;
+ case 0x1c9: /* 0 111 001 001 */ cp1610_clrr(1); break;
+ case 0x1ca: /* 0 111 001 010 */ cp1610_xorr(1,2); break;
+ case 0x1cb: /* 0 111 001 011 */ cp1610_xorr(1,3); break;
+ case 0x1cc: /* 0 111 001 100 */ cp1610_xorr(1,4); break;
+ case 0x1cd: /* 0 111 001 101 */ cp1610_xorr(1,5); break;
+ case 0x1ce: /* 0 111 001 110 */ cp1610_xorr(1,6); break;
+ case 0x1cf: /* 0 111 001 111 */ cp1610_xorr(1,7); break;
+
+ case 0x1d0: /* 0 111 010 000 */ cp1610_xorr(2,0); break;
+ case 0x1d1: /* 0 111 010 001 */ cp1610_xorr(2,1); break;
+ case 0x1d2: /* 0 111 010 010 */ cp1610_clrr(2); break;
+ case 0x1d3: /* 0 111 010 011 */ cp1610_xorr(2,3); break;
+ case 0x1d4: /* 0 111 010 100 */ cp1610_xorr(2,4); break;
+ case 0x1d5: /* 0 111 010 101 */ cp1610_xorr(2,5); break;
+ case 0x1d6: /* 0 111 010 110 */ cp1610_xorr(2,6); break;
+ case 0x1d7: /* 0 111 010 111 */ cp1610_xorr(2,7); break;
+
+ case 0x1d8: /* 0 111 011 000 */ cp1610_xorr(3,0); break;
+ case 0x1d9: /* 0 111 011 001 */ cp1610_xorr(3,1); break;
+ case 0x1da: /* 0 111 011 010 */ cp1610_xorr(3,2); break;
+ case 0x1db: /* 0 111 011 011 */ cp1610_clrr(3); break;
+ case 0x1dc: /* 0 111 011 100 */ cp1610_xorr(3,4); break;
+ case 0x1dd: /* 0 111 011 101 */ cp1610_xorr(3,5); break;
+ case 0x1de: /* 0 111 011 110 */ cp1610_xorr(3,6); break;
+ case 0x1df: /* 0 111 011 111 */ cp1610_xorr(3,7); break;
+
+ case 0x1e0: /* 0 111 100 000 */ cp1610_xorr(4,0); break;
+ case 0x1e1: /* 0 111 100 001 */ cp1610_xorr(4,1); break;
+ case 0x1e2: /* 0 111 100 010 */ cp1610_xorr(4,2); break;
+ case 0x1e3: /* 0 111 100 011 */ cp1610_xorr(4,3); break;
+ case 0x1e4: /* 0 111 100 100 */ cp1610_clrr(4); break;
+ case 0x1e5: /* 0 111 100 101 */ cp1610_xorr(4,5); break;
+ case 0x1e6: /* 0 111 100 110 */ cp1610_xorr(4,6); break;
+ case 0x1e7: /* 0 111 100 111 */ cp1610_xorr(4,7); break;
+
+ case 0x1e8: /* 0 111 101 000 */ cp1610_xorr(5,0); break;
+ case 0x1e9: /* 0 111 101 001 */ cp1610_xorr(5,1); break;
+ case 0x1ea: /* 0 111 101 010 */ cp1610_xorr(5,2); break;
+ case 0x1eb: /* 0 111 101 011 */ cp1610_xorr(5,3); break;
+ case 0x1ec: /* 0 111 101 100 */ cp1610_xorr(5,4); break;
+ case 0x1ed: /* 0 111 101 101 */ cp1610_clrr(5); break;
+ case 0x1ee: /* 0 111 101 110 */ cp1610_xorr(5,6); break;
+ case 0x1ef: /* 0 111 101 111 */ cp1610_xorr(5,7); break;
+
+ case 0x1f0: /* 0 111 110 000 */ cp1610_xorr(6,0); break;
+ case 0x1f1: /* 0 111 110 001 */ cp1610_xorr(6,1); break;
+ case 0x1f2: /* 0 111 110 010 */ cp1610_xorr(6,2); break;
+ case 0x1f3: /* 0 111 110 011 */ cp1610_xorr(6,3); break;
+ case 0x1f4: /* 0 111 110 100 */ cp1610_xorr(6,4); break;
+ case 0x1f5: /* 0 111 110 101 */ cp1610_xorr(6,5); break;
+ case 0x1f6: /* 0 111 110 110 */ cp1610_clrr(6); break;
+ case 0x1f7: /* 0 111 110 111 */ cp1610_xorr(6,7); break;
+
+ case 0x1f8: /* 0 111 111 000 */ cp1610_xorr(7,0); break;
+ case 0x1f9: /* 0 111 111 001 */ cp1610_xorr(7,1); break;
+ case 0x1fa: /* 0 111 111 010 */ cp1610_xorr(7,2); break;
+ case 0x1fb: /* 0 111 111 011 */ cp1610_xorr(7,3); break;
+ case 0x1fc: /* 0 111 111 100 */ cp1610_xorr(7,4); break;
+ case 0x1fd: /* 0 111 111 101 */ cp1610_xorr(7,5); break;
+ case 0x1fe: /* 0 111 111 110 */ cp1610_xorr(7,6); break;
+ case 0x1ff: /* 0 110 111 111 */ cp1610_clrr(7); break;
+
+ case 0x200: /* 1 000 000 000 */ cp1610_b(0); break;
+ case 0x201: /* 1 000 000 001 */ cp1610_bc(0); break; /* aka BLGE */
+ case 0x202: /* 1 000 000 010 */ cp1610_bov(0); break;
+ case 0x203: /* 1 000 000 011 */ cp1610_bpl(0); break;
+ case 0x204: /* 1 000 000 100 */ cp1610_bze(0); break; /* aka BEQ */
+ case 0x205: /* 1 000 000 101 */ cp1610_blt(0); break;
+ case 0x206: /* 1 000 000 110 */ cp1610_ble(0); break;
+ case 0x207: /* 1 000 000 111 */ cp1610_busc(0); break;
+
+ case 0x208: /* 1 000 001 000 */ cp1610_nopp(0); break;
+ case 0x209: /* 1 000 001 001 */ cp1610_bnc(0); break; /* aka BLLT */
+ case 0x20a: /* 1 000 001 010 */ cp1610_bnov(0); break;
+ case 0x20b: /* 1 000 001 011 */ cp1610_bmi(0); break;
+ case 0x20c: /* 1 000 001 100 */ cp1610_bnze(0); break; /* aka BNEQ */
+ case 0x20d: /* 1 000 001 101 */ cp1610_bge(0); break;
+ case 0x20e: /* 1 000 001 110 */ cp1610_bgt(0); break;
+ case 0x20f: /* 1 000 001 111 */ cp1610_besc(0); break;
+
+ case 0x210: /* 1 000 010 000 */ cp1610_bext(0,0); break;
+ case 0x211: /* 1 000 010 001 */ cp1610_bext(1,0); break;
+ case 0x212: /* 1 000 010 010 */ cp1610_bext(2,0); break;
+ case 0x213: /* 1 000 010 011 */ cp1610_bext(3,0); break;
+ case 0x214: /* 1 000 010 100 */ cp1610_bext(4,0); break;
+ case 0x215: /* 1 000 010 101 */ cp1610_bext(5,0); break;
+ case 0x216: /* 1 000 010 110 */ cp1610_bext(6,0); break;
+ case 0x217: /* 1 000 010 111 */ cp1610_bext(7,0); break;
+
+ case 0x218: /* 1 000 011 000 */ cp1610_bext(8,0); break;
+ case 0x219: /* 1 000 011 001 */ cp1610_bext(9,0); break;
+ case 0x21a: /* 1 000 011 010 */ cp1610_bext(10,0); break;
+ case 0x21b: /* 1 000 011 011 */ cp1610_bext(11,0); break;
+ case 0x21c: /* 1 000 011 100 */ cp1610_bext(12,0); break;
+ case 0x21d: /* 1 000 011 101 */ cp1610_bext(13,0); break;
+ case 0x21e: /* 1 000 011 110 */ cp1610_bext(14,0); break;
+ case 0x21f: /* 1 000 011 111 */ cp1610_bext(15,0); break;
+
+ case 0x220: /* 1 000 100 000 */ cp1610_b(0xffff); break;
+ case 0x221: /* 1 000 100 001 */ cp1610_bc(0xffff); break; /* aka BLGE */
+ case 0x222: /* 1 000 100 010 */ cp1610_bov(0xffff); break;
+ case 0x223: /* 1 000 100 011 */ cp1610_bpl(0xffff); break;
+ case 0x224: /* 1 000 100 100 */ cp1610_bze(0xffff); break; /* aka BEQ */
+ case 0x225: /* 1 000 100 101 */ cp1610_blt(0xffff); break;
+ case 0x226: /* 1 000 100 110 */ cp1610_ble(0xffff); break;
+ case 0x227: /* 1 000 100 111 */ cp1610_busc(0xffff); break;
+
+ case 0x228: /* 1 000 101 000 */ cp1610_nopp(0xffff); break;
+ case 0x229: /* 1 000 101 001 */ cp1610_bnc(0xffff); break; /* aka BLLT */
+ case 0x22a: /* 1 000 101 010 */ cp1610_bnov(0xffff); break;
+ case 0x22b: /* 1 000 101 011 */ cp1610_bmi(0xffff); break;
+ case 0x22c: /* 1 000 101 100 */ cp1610_bnze(0xffff); break; /* aka BNEQ */
+ case 0x22d: /* 1 000 101 101 */ cp1610_bge(0xffff); break;
+ case 0x22e: /* 1 000 101 110 */ cp1610_bgt(0xffff); break;
+ case 0x22f: /* 1 000 101 111 */ cp1610_besc(0xffff); break;
+
+ case 0x230: /* 1 000 110 000 */ cp1610_bext(0,0xffff); break;
+ case 0x231: /* 1 000 110 001 */ cp1610_bext(1,0xffff); break;
+ case 0x232: /* 1 000 110 010 */ cp1610_bext(2,0xffff); break;
+ case 0x233: /* 1 000 110 011 */ cp1610_bext(3,0xffff); break;
+ case 0x234: /* 1 000 110 100 */ cp1610_bext(4,0xffff); break;
+ case 0x235: /* 1 000 110 101 */ cp1610_bext(5,0xffff); break;
+ case 0x236: /* 1 000 110 110 */ cp1610_bext(6,0xffff); break;
+ case 0x237: /* 1 000 110 111 */ cp1610_bext(7,0xffff); break;
+
+ case 0x238: /* 1 000 111 000 */ cp1610_bext(8,0xffff); break;
+ case 0x239: /* 1 000 111 001 */ cp1610_bext(9,0xffff); break;
+ case 0x23a: /* 1 000 111 010 */ cp1610_bext(10,0xffff); break;
+ case 0x23b: /* 1 000 111 011 */ cp1610_bext(11,0xffff); break;
+ case 0x23c: /* 1 000 111 100 */ cp1610_bext(12,0xffff); break;
+ case 0x23d: /* 1 000 111 101 */ cp1610_bext(13,0xffff); break;
+ case 0x23e: /* 1 000 111 110 */ cp1610_bext(14,0xffff); break;
+ case 0x23f: /* 1 000 111 111 */ cp1610_bext(15,0xffff); break;
+
+ case 0x240: /* 1 001 000 000 */ cp1610_mvo(0); break;
+ case 0x241: /* 1 001 000 001 */ cp1610_mvo(1); break;
+ case 0x242: /* 1 001 000 010 */ cp1610_mvo(2); break;
+ case 0x243: /* 1 001 000 011 */ cp1610_mvo(3); break;
+ case 0x244: /* 1 001 000 100 */ cp1610_mvo(4); break;
+ case 0x245: /* 1 001 000 101 */ cp1610_mvo(5); break;
+ case 0x246: /* 1 001 000 110 */ cp1610_mvo(6); break;
+ case 0x247: /* 1 001 000 111 */ cp1610_mvo(7); break;
+
+ case 0x248: /* 1 001 001 000 */ cp1610_mvoat(0,1); break;
+ case 0x249: /* 1 001 001 001 */ cp1610_mvoat(1,1); break;
+ case 0x24a: /* 1 001 001 010 */ cp1610_mvoat(2,1); break;
+ case 0x24b: /* 1 001 001 011 */ cp1610_mvoat(3,1); break;
+ case 0x24c: /* 1 001 001 100 */ cp1610_mvoat(4,1); break;
+ case 0x24d: /* 1 001 001 101 */ cp1610_mvoat(5,1); break;
+ case 0x24e: /* 1 001 001 110 */ cp1610_mvoat(6,1); break;
+ case 0x24f: /* 1 001 001 111 */ cp1610_mvoat(7,1); break;
+
+ case 0x250: /* 1 001 010 000 */ cp1610_mvoat(0,2); break;
+ case 0x251: /* 1 001 010 001 */ cp1610_mvoat(1,2); break;
+ case 0x252: /* 1 001 010 010 */ cp1610_mvoat(2,2); break;
+ case 0x253: /* 1 001 010 011 */ cp1610_mvoat(3,2); break;
+ case 0x254: /* 1 001 010 100 */ cp1610_mvoat(4,2); break;
+ case 0x255: /* 1 001 010 101 */ cp1610_mvoat(5,2); break;
+ case 0x256: /* 1 001 010 110 */ cp1610_mvoat(6,2); break;
+ case 0x257: /* 1 001 010 111 */ cp1610_mvoat(7,2); break;
+
+ case 0x258: /* 1 001 011 000 */ cp1610_mvoat(0,3); break;
+ case 0x259: /* 1 001 011 001 */ cp1610_mvoat(1,3); break;
+ case 0x25a: /* 1 001 011 010 */ cp1610_mvoat(2,3); break;
+ case 0x25b: /* 1 001 011 011 */ cp1610_mvoat(3,3); break;
+ case 0x25c: /* 1 001 011 100 */ cp1610_mvoat(4,3); break;
+ case 0x25d: /* 1 001 011 101 */ cp1610_mvoat(5,3); break;
+ case 0x25e: /* 1 001 011 110 */ cp1610_mvoat(6,3); break;
+ case 0x25f: /* 1 001 011 111 */ cp1610_mvoat(7,3); break;
+
+ case 0x260: /* 1 001 100 000 */ cp1610_mvoat_i(0,4); break;
+ case 0x261: /* 1 001 100 001 */ cp1610_mvoat_i(1,4); break;
+ case 0x262: /* 1 001 100 010 */ cp1610_mvoat_i(2,4); break;
+ case 0x263: /* 1 001 100 011 */ cp1610_mvoat_i(3,4); break;
+ case 0x264: /* 1 001 100 100 */ cp1610_mvoat_i(4,4); break;
+ case 0x265: /* 1 001 100 101 */ cp1610_mvoat_i(5,4); break;
+ case 0x266: /* 1 001 100 110 */ cp1610_mvoat_i(6,4); break;
+ case 0x267: /* 1 001 100 111 */ cp1610_mvoat_i(7,4); break;
+
+ case 0x268: /* 1 001 101 000 */ cp1610_mvoat_i(0,5); break;
+ case 0x269: /* 1 001 101 001 */ cp1610_mvoat_i(1,5); break;
+ case 0x26a: /* 1 001 101 010 */ cp1610_mvoat_i(2,5); break;
+ case 0x26b: /* 1 001 101 011 */ cp1610_mvoat_i(3,5); break;
+ case 0x26c: /* 1 001 101 100 */ cp1610_mvoat_i(4,5); break;
+ case 0x26d: /* 1 001 101 101 */ cp1610_mvoat_i(5,5); break;
+ case 0x26e: /* 1 001 101 110 */ cp1610_mvoat_i(6,5); break;
+ case 0x26f: /* 1 001 101 111 */ cp1610_mvoat_i(7,5); break;
+
+ case 0x270: /* 1 001 110 000 */ cp1610_mvoat_i(0,6); break; /* pshr */
+ case 0x271: /* 1 001 110 001 */ cp1610_mvoat_i(1,6); break; /* pshr */
+ case 0x272: /* 1 001 110 010 */ cp1610_mvoat_i(2,6); break; /* pshr */
+ case 0x273: /* 1 001 110 011 */ cp1610_mvoat_i(3,6); break; /* pshr */
+ case 0x274: /* 1 001 110 100 */ cp1610_mvoat_i(4,6); break; /* pshr */
+ case 0x275: /* 1 001 110 101 */ cp1610_mvoat_i(5,6); break; /* pshr */
+ case 0x276: /* 1 001 110 110 */ cp1610_mvoat_i(6,6); break; /* pshr */
+ case 0x277: /* 1 001 110 111 */ cp1610_mvoat_i(7,6); break; /* pshr */
+
+ case 0x278: /* 1 001 111 000 */ cp1610_mvoi(0); break;
+ case 0x279: /* 1 001 111 001 */ cp1610_mvoi(1); break;
+ case 0x27a: /* 1 001 111 010 */ cp1610_mvoi(2); break;
+ case 0x27b: /* 1 001 111 011 */ cp1610_mvoi(3); break;
+ case 0x27c: /* 1 001 111 100 */ cp1610_mvoi(4); break;
+ case 0x27d: /* 1 001 111 101 */ cp1610_mvoi(5); break;
+ case 0x27e: /* 1 001 111 110 */ cp1610_mvoi(6); break;
+ case 0x27f: /* 1 001 111 111 */ cp1610_mvoi(7); break;
+
+ case 0x280: /* 1 010 000 000 */ cp1610_mvi(0); break;
+ case 0x281: /* 1 010 000 001 */ cp1610_mvi(1); break;
+ case 0x282: /* 1 010 000 010 */ cp1610_mvi(2); break;
+ case 0x283: /* 1 010 000 011 */ cp1610_mvi(3); break;
+ case 0x284: /* 1 010 000 100 */ cp1610_mvi(4); break;
+ case 0x285: /* 1 010 000 101 */ cp1610_mvi(5); break;
+ case 0x286: /* 1 010 000 110 */ cp1610_mvi(6); break;
+ case 0x287: /* 1 010 000 111 */ cp1610_mvi(7); break;
+
+ case 0x288: /* 1 010 001 000 */ cp1610_mviat(1,0); break;
+ case 0x289: /* 1 010 001 001 */ cp1610_mviat(1,1); break;
+ case 0x28a: /* 1 010 001 010 */ cp1610_mviat(1,2); break;
+ case 0x28b: /* 1 010 001 011 */ cp1610_mviat(1,3); break;
+ case 0x28c: /* 1 010 001 100 */ cp1610_mviat(1,4); break;
+ case 0x28d: /* 1 010 001 101 */ cp1610_mviat(1,5); break;
+ case 0x28e: /* 1 010 001 110 */ cp1610_mviat(1,6); break;
+ case 0x28f: /* 1 010 001 111 */ cp1610_mviat(1,7); break;
+
+ case 0x290: /* 1 010 010 000 */ cp1610_mviat(2,0); break;
+ case 0x291: /* 1 010 010 001 */ cp1610_mviat(2,1); break;
+ case 0x292: /* 1 010 010 010 */ cp1610_mviat(2,2); break;
+ case 0x293: /* 1 010 010 011 */ cp1610_mviat(2,3); break;
+ case 0x294: /* 1 010 010 100 */ cp1610_mviat(2,4); break;
+ case 0x295: /* 1 010 010 101 */ cp1610_mviat(2,5); break;
+ case 0x296: /* 1 010 010 110 */ cp1610_mviat(2,6); break;
+ case 0x297: /* 1 010 010 111 */ cp1610_mviat(2,7); break;
+
+ case 0x298: /* 1 010 011 000 */ cp1610_mviat(3,0); break;
+ case 0x299: /* 1 010 011 001 */ cp1610_mviat(3,1); break;
+ case 0x29a: /* 1 010 011 010 */ cp1610_mviat(3,2); break;
+ case 0x29b: /* 1 010 011 011 */ cp1610_mviat(3,3); break;
+ case 0x29c: /* 1 010 011 100 */ cp1610_mviat(3,4); break;
+ case 0x29d: /* 1 010 011 101 */ cp1610_mviat(3,5); break;
+ case 0x29e: /* 1 010 011 110 */ cp1610_mviat(3,6); break;
+ case 0x29f: /* 1 010 011 111 */ cp1610_mviat(3,7); break;
+
+ case 0x2a0: /* 1 010 100 000 */ cp1610_mviat_i(4,0); break;
+ case 0x2a1: /* 1 010 100 001 */ cp1610_mviat_i(4,1); break;
+ case 0x2a2: /* 1 010 100 010 */ cp1610_mviat_i(4,2); break;
+ case 0x2a3: /* 1 010 100 011 */ cp1610_mviat_i(4,3); break;
+ case 0x2a4: /* 1 010 100 100 */ cp1610_mviat_i(4,4); break;
+ case 0x2a5: /* 1 010 100 101 */ cp1610_mviat_i(4,5); break;
+ case 0x2a6: /* 1 010 100 110 */ cp1610_mviat_i(4,6); break;
+ case 0x2a7: /* 1 010 100 111 */ cp1610_mviat_i(4,7); break;
+
+ case 0x2a8: /* 1 010 101 000 */ cp1610_mviat_i(5,0); break;
+ case 0x2a9: /* 1 010 101 001 */ cp1610_mviat_i(5,1); break;
+ case 0x2aa: /* 1 010 101 010 */ cp1610_mviat_i(5,2); break;
+ case 0x2ab: /* 1 010 101 011 */ cp1610_mviat_i(5,3); break;
+ case 0x2ac: /* 1 010 101 100 */ cp1610_mviat_i(5,4); break;
+ case 0x2ad: /* 1 010 101 101 */ cp1610_mviat_i(5,5); break;
+ case 0x2ae: /* 1 010 101 110 */ cp1610_mviat_i(5,6); break;
+ case 0x2af: /* 1 010 101 111 */ cp1610_mviat_i(5,7); break;
+
+ case 0x2b0: /* 1 010 110 000 */ cp1610_pulr(0); break;
+ case 0x2b1: /* 1 010 110 001 */ cp1610_pulr(1); break;
+ case 0x2b2: /* 1 010 110 010 */ cp1610_pulr(2); break;
+ case 0x2b3: /* 1 010 110 011 */ cp1610_pulr(3); break;
+ case 0x2b4: /* 1 010 110 100 */ cp1610_pulr(4); break;
+ case 0x2b5: /* 1 010 110 101 */ cp1610_pulr(5); break;
+ case 0x2b6: /* 1 010 110 110 */ cp1610_pulr(6); break;
+ case 0x2b7: /* 1 010 110 111 */ cp1610_pulr(7); break;
+
+ case 0x2b8: /* 1 010 111 000 */ cp1610_mvii(0); break;
+ case 0x2b9: /* 1 010 111 001 */ cp1610_mvii(1); break;
+ case 0x2ba: /* 1 010 111 010 */ cp1610_mvii(2); break;
+ case 0x2bb: /* 1 010 111 011 */ cp1610_mvii(3); break;
+ case 0x2bc: /* 1 010 111 100 */ cp1610_mvii(4); break;
+ case 0x2bd: /* 1 010 111 101 */ cp1610_mvii(5); break;
+ case 0x2be: /* 1 010 111 110 */ cp1610_mvii(6); break;
+ case 0x2bf: /* 1 010 111 111 */ cp1610_mvii(7); break;
+
+ case 0x2c0: /* 1 011 000 000 */ cp1610_add(0); break;
+ case 0x2c1: /* 1 011 000 001 */ cp1610_add(1); break;
+ case 0x2c2: /* 1 011 000 010 */ cp1610_add(2); break;
+ case 0x2c3: /* 1 011 000 011 */ cp1610_add(3); break;
+ case 0x2c4: /* 1 011 000 100 */ cp1610_add(4); break;
+ case 0x2c5: /* 1 011 000 101 */ cp1610_add(5); break;
+ case 0x2c6: /* 1 011 000 110 */ cp1610_add(6); break;
+ case 0x2c7: /* 1 011 000 111 */ cp1610_add(7); break;
+
+ case 0x2c8: /* 1 011 001 000 */ cp1610_addat(1,0); break;
+ case 0x2c9: /* 1 011 001 001 */ cp1610_addat(1,1); break;
+ case 0x2ca: /* 1 011 001 010 */ cp1610_addat(1,2); break;
+ case 0x2cb: /* 1 011 001 011 */ cp1610_addat(1,3); break;
+ case 0x2cc: /* 1 011 001 100 */ cp1610_addat(1,4); break;
+ case 0x2cd: /* 1 011 001 101 */ cp1610_addat(1,5); break;
+ case 0x2ce: /* 1 011 001 110 */ cp1610_addat(1,6); break;
+ case 0x2cf: /* 1 011 001 111 */ cp1610_addat(1,7); break;
+
+ case 0x2d0: /* 1 011 010 000 */ cp1610_addat(2,0); break;
+ case 0x2d1: /* 1 011 010 001 */ cp1610_addat(2,1); break;
+ case 0x2d2: /* 1 011 010 010 */ cp1610_addat(2,2); break;
+ case 0x2d3: /* 1 011 010 011 */ cp1610_addat(2,3); break;
+ case 0x2d4: /* 1 011 010 100 */ cp1610_addat(2,4); break;
+ case 0x2d5: /* 1 011 010 101 */ cp1610_addat(2,5); break;
+ case 0x2d6: /* 1 011 010 110 */ cp1610_addat(2,6); break;
+ case 0x2d7: /* 1 011 010 111 */ cp1610_addat(2,7); break;
+
+ case 0x2d8: /* 1 011 011 000 */ cp1610_addat(3,0); break;
+ case 0x2d9: /* 1 011 011 001 */ cp1610_addat(3,1); break;
+ case 0x2da: /* 1 011 011 010 */ cp1610_addat(3,2); break;
+ case 0x2db: /* 1 011 011 011 */ cp1610_addat(3,3); break;
+ case 0x2dc: /* 1 011 011 100 */ cp1610_addat(3,4); break;
+ case 0x2dd: /* 1 011 011 101 */ cp1610_addat(3,5); break;
+ case 0x2de: /* 1 011 011 110 */ cp1610_addat(3,6); break;
+ case 0x2df: /* 1 011 011 111 */ cp1610_addat(3,7); break;
+
+ case 0x2e0: /* 1 011 100 000 */ cp1610_addat_i(4,0); break;
+ case 0x2e1: /* 1 011 100 001 */ cp1610_addat_i(4,1); break;
+ case 0x2e2: /* 1 011 100 010 */ cp1610_addat_i(4,2); break;
+ case 0x2e3: /* 1 011 100 011 */ cp1610_addat_i(4,3); break;
+ case 0x2e4: /* 1 011 100 100 */ cp1610_addat_i(4,4); break;
+ case 0x2e5: /* 1 011 100 101 */ cp1610_addat_i(4,5); break;
+ case 0x2e6: /* 1 011 100 110 */ cp1610_addat_i(4,6); break;
+ case 0x2e7: /* 1 011 100 111 */ cp1610_addat_i(4,7); break;
+
+ case 0x2e8: /* 1 011 101 000 */ cp1610_addat_i(5,0); break;
+ case 0x2e9: /* 1 011 101 001 */ cp1610_addat_i(5,1); break;
+ case 0x2ea: /* 1 011 101 010 */ cp1610_addat_i(5,2); break;
+ case 0x2eb: /* 1 011 101 011 */ cp1610_addat_i(5,3); break;
+ case 0x2ec: /* 1 011 101 100 */ cp1610_addat_i(5,4); break;
+ case 0x2ed: /* 1 011 101 101 */ cp1610_addat_i(5,5); break;
+ case 0x2ee: /* 1 011 101 110 */ cp1610_addat_i(5,6); break;
+ case 0x2ef: /* 1 011 101 111 */ cp1610_addat_i(5,7); break;
+
+ case 0x2f0: /* 1 011 110 000 */ cp1610_addat_d(6,0); break;
+ case 0x2f1: /* 1 011 110 001 */ cp1610_addat_d(6,1); break;
+ case 0x2f2: /* 1 011 110 010 */ cp1610_addat_d(6,2); break;
+ case 0x2f3: /* 1 011 110 011 */ cp1610_addat_d(6,3); break;
+ case 0x2f4: /* 1 011 110 100 */ cp1610_addat_d(6,4); break;
+ case 0x2f5: /* 1 011 110 101 */ cp1610_addat_d(6,5); break;
+ case 0x2f6: /* 1 011 110 110 */ cp1610_addat_d(6,6); break;
+ case 0x2f7: /* 1 011 110 111 */ cp1610_addat_d(6,7); break;
+
+ case 0x2f8: /* 1 011 111 000 */ cp1610_addi(0); break;
+ case 0x2f9: /* 1 011 111 001 */ cp1610_addi(1); break;
+ case 0x2fa: /* 1 011 111 010 */ cp1610_addi(2); break;
+ case 0x2fb: /* 1 011 111 011 */ cp1610_addi(3); break;
+ case 0x2fc: /* 1 011 111 100 */ cp1610_addi(4); break;
+ case 0x2fd: /* 1 011 111 101 */ cp1610_addi(5); break;
+ case 0x2fe: /* 1 011 111 110 */ cp1610_addi(6); break;
+ case 0x2ff: /* 1 011 111 111 */ cp1610_addi(7); break;
+
+ case 0x300: /* 1 100 000 000 */ cp1610_sub(0); break;
+ case 0x301: /* 1 100 000 001 */ cp1610_sub(1); break;
+ case 0x302: /* 1 100 000 010 */ cp1610_sub(2); break;
+ case 0x303: /* 1 100 000 011 */ cp1610_sub(3); break;
+ case 0x304: /* 1 100 000 100 */ cp1610_sub(4); break;
+ case 0x305: /* 1 100 000 101 */ cp1610_sub(5); break;
+ case 0x306: /* 1 100 000 110 */ cp1610_sub(6); break;
+ case 0x307: /* 1 100 000 111 */ cp1610_sub(7); break;
+
+ case 0x308: /* 1 100 001 000 */ cp1610_subat(1,0); break;
+ case 0x309: /* 1 100 001 001 */ cp1610_subat(1,1); break;
+ case 0x30a: /* 1 100 001 010 */ cp1610_subat(1,2); break;
+ case 0x30b: /* 1 100 001 011 */ cp1610_subat(1,3); break;
+ case 0x30c: /* 1 100 001 100 */ cp1610_subat(1,4); break;
+ case 0x30d: /* 1 100 001 101 */ cp1610_subat(1,5); break;
+ case 0x30e: /* 1 100 001 110 */ cp1610_subat(1,6); break;
+ case 0x30f: /* 1 100 001 111 */ cp1610_subat(1,7); break;
+
+ case 0x310: /* 1 100 010 000 */ cp1610_subat(2,0); break;
+ case 0x311: /* 1 100 010 001 */ cp1610_subat(2,1); break;
+ case 0x312: /* 1 100 010 010 */ cp1610_subat(2,2); break;
+ case 0x313: /* 1 100 010 011 */ cp1610_subat(2,3); break;
+ case 0x314: /* 1 100 010 100 */ cp1610_subat(2,4); break;
+ case 0x315: /* 1 100 010 101 */ cp1610_subat(2,5); break;
+ case 0x316: /* 1 100 010 110 */ cp1610_subat(2,6); break;
+ case 0x317: /* 1 100 010 111 */ cp1610_subat(2,7); break;
+
+ case 0x318: /* 1 100 011 000 */ cp1610_subat(3,0); break;
+ case 0x319: /* 1 100 011 001 */ cp1610_subat(3,1); break;
+ case 0x31a: /* 1 100 011 010 */ cp1610_subat(3,2); break;
+ case 0x31b: /* 1 100 011 011 */ cp1610_subat(3,3); break;
+ case 0x31c: /* 1 100 011 100 */ cp1610_subat(3,4); break;
+ case 0x31d: /* 1 100 011 101 */ cp1610_subat(3,5); break;
+ case 0x31e: /* 1 100 011 110 */ cp1610_subat(3,6); break;
+ case 0x31f: /* 1 100 011 111 */ cp1610_subat(3,7); break;
+
+ case 0x320: /* 1 100 100 000 */ cp1610_subat_i(4,0); break;
+ case 0x321: /* 1 100 100 001 */ cp1610_subat_i(4,1); break;
+ case 0x322: /* 1 100 100 010 */ cp1610_subat_i(4,2); break;
+ case 0x323: /* 1 100 100 011 */ cp1610_subat_i(4,3); break;
+ case 0x324: /* 1 100 100 100 */ cp1610_subat_i(4,4); break;
+ case 0x325: /* 1 100 100 101 */ cp1610_subat_i(4,5); break;
+ case 0x326: /* 1 100 100 110 */ cp1610_subat_i(4,6); break;
+ case 0x327: /* 1 100 100 111 */ cp1610_subat_i(4,7); break;
+
+ case 0x328: /* 1 100 101 000 */ cp1610_subat_i(5,0); break;
+ case 0x329: /* 1 100 101 001 */ cp1610_subat_i(5,1); break;
+ case 0x32a: /* 1 100 101 010 */ cp1610_subat_i(5,2); break;
+ case 0x32b: /* 1 100 101 011 */ cp1610_subat_i(5,3); break;
+ case 0x32c: /* 1 100 101 100 */ cp1610_subat_i(5,4); break;
+ case 0x32d: /* 1 100 101 101 */ cp1610_subat_i(5,5); break;
+ case 0x32e: /* 1 100 101 110 */ cp1610_subat_i(5,6); break;
+ case 0x32f: /* 1 100 101 111 */ cp1610_subat_i(5,7); break;
+
+ case 0x330: /* 1 100 110 000 */ cp1610_subat_d(6,0); break;
+ case 0x331: /* 1 100 110 001 */ cp1610_subat_d(6,1); break;
+ case 0x332: /* 1 100 110 010 */ cp1610_subat_d(6,2); break;
+ case 0x333: /* 1 100 110 011 */ cp1610_subat_d(6,3); break;
+ case 0x334: /* 1 100 110 100 */ cp1610_subat_d(6,4); break;
+ case 0x335: /* 1 100 110 101 */ cp1610_subat_d(6,5); break;
+ case 0x336: /* 1 100 110 110 */ cp1610_subat_d(6,6); break;
+ case 0x337: /* 1 100 110 111 */ cp1610_subat_d(6,7); break;
+
+ case 0x338: /* 1 100 111 000 */ cp1610_subi(0); break;
+ case 0x339: /* 1 100 111 001 */ cp1610_subi(1); break;
+ case 0x33a: /* 1 100 111 010 */ cp1610_subi(2); break;
+ case 0x33b: /* 1 100 111 011 */ cp1610_subi(3); break;
+ case 0x33c: /* 1 100 111 100 */ cp1610_subi(4); break;
+ case 0x33d: /* 1 100 111 101 */ cp1610_subi(5); break;
+ case 0x33e: /* 1 100 111 110 */ cp1610_subi(6); break;
+ case 0x33f: /* 1 100 111 111 */ cp1610_subi(7); break;
+
+ case 0x340: /* 1 101 000 000 */ cp1610_cmp(0); break;
+ case 0x341: /* 1 101 000 001 */ cp1610_cmp(1); break;
+ case 0x342: /* 1 101 000 010 */ cp1610_cmp(2); break;
+ case 0x343: /* 1 101 000 011 */ cp1610_cmp(3); break;
+ case 0x344: /* 1 101 000 100 */ cp1610_cmp(4); break;
+ case 0x345: /* 1 101 000 101 */ cp1610_cmp(5); break;
+ case 0x346: /* 1 101 000 110 */ cp1610_cmp(6); break;
+ case 0x347: /* 1 101 000 111 */ cp1610_cmp(7); break;
+
+ case 0x348: /* 1 101 001 000 */ cp1610_cmpat(1,0); break;
+ case 0x349: /* 1 101 001 001 */ cp1610_cmpat(1,1); break;
+ case 0x34a: /* 1 101 001 010 */ cp1610_cmpat(1,2); break;
+ case 0x34b: /* 1 101 001 011 */ cp1610_cmpat(1,3); break;
+ case 0x34c: /* 1 101 001 100 */ cp1610_cmpat(1,4); break;
+ case 0x34d: /* 1 101 001 101 */ cp1610_cmpat(1,5); break;
+ case 0x34e: /* 1 101 001 110 */ cp1610_cmpat(1,6); break;
+ case 0x34f: /* 1 101 001 111 */ cp1610_cmpat(1,7); break;
+
+ case 0x350: /* 1 101 010 000 */ cp1610_cmpat(2,0); break;
+ case 0x351: /* 1 101 010 001 */ cp1610_cmpat(2,1); break;
+ case 0x352: /* 1 101 010 010 */ cp1610_cmpat(2,2); break;
+ case 0x353: /* 1 101 010 011 */ cp1610_cmpat(2,3); break;
+ case 0x354: /* 1 101 010 100 */ cp1610_cmpat(2,4); break;
+ case 0x355: /* 1 101 010 101 */ cp1610_cmpat(2,5); break;
+ case 0x356: /* 1 101 010 110 */ cp1610_cmpat(2,6); break;
+ case 0x357: /* 1 101 010 111 */ cp1610_cmpat(2,7); break;
+
+ case 0x358: /* 1 101 011 000 */ cp1610_cmpat(3,0); break;
+ case 0x359: /* 1 101 011 001 */ cp1610_cmpat(3,1); break;
+ case 0x35a: /* 1 101 011 010 */ cp1610_cmpat(3,2); break;
+ case 0x35b: /* 1 101 011 011 */ cp1610_cmpat(3,3); break;
+ case 0x35c: /* 1 101 011 100 */ cp1610_cmpat(3,4); break;
+ case 0x35d: /* 1 101 011 101 */ cp1610_cmpat(3,5); break;
+ case 0x35e: /* 1 101 011 110 */ cp1610_cmpat(3,6); break;
+ case 0x35f: /* 1 101 011 111 */ cp1610_cmpat(3,7); break;
+
+ case 0x360: /* 1 101 100 000 */ cp1610_cmpat_i(4,0); break;
+ case 0x361: /* 1 101 100 001 */ cp1610_cmpat_i(4,1); break;
+ case 0x362: /* 1 101 100 010 */ cp1610_cmpat_i(4,2); break;
+ case 0x363: /* 1 101 100 011 */ cp1610_cmpat_i(4,3); break;
+ case 0x364: /* 1 101 100 100 */ cp1610_cmpat_i(4,4); break;
+ case 0x365: /* 1 101 100 101 */ cp1610_cmpat_i(4,5); break;
+ case 0x366: /* 1 101 100 110 */ cp1610_cmpat_i(4,6); break;
+ case 0x367: /* 1 101 100 111 */ cp1610_cmpat_i(4,7); break;
+
+ case 0x368: /* 1 101 101 000 */ cp1610_cmpat_i(5,0); break;
+ case 0x369: /* 1 101 101 001 */ cp1610_cmpat_i(5,1); break;
+ case 0x36a: /* 1 101 101 010 */ cp1610_cmpat_i(5,2); break;
+ case 0x36b: /* 1 101 101 011 */ cp1610_cmpat_i(5,3); break;
+ case 0x36c: /* 1 101 101 100 */ cp1610_cmpat_i(5,4); break;
+ case 0x36d: /* 1 101 101 101 */ cp1610_cmpat_i(5,5); break;
+ case 0x36e: /* 1 101 101 110 */ cp1610_cmpat_i(5,6); break;
+ case 0x36f: /* 1 101 101 111 */ cp1610_cmpat_i(5,7); break;
+
+ case 0x370: /* 1 101 110 000 */ cp1610_cmpat_d(6,0); break;
+ case 0x371: /* 1 101 110 001 */ cp1610_cmpat_d(6,1); break;
+ case 0x372: /* 1 101 110 010 */ cp1610_cmpat_d(6,2); break;
+ case 0x373: /* 1 101 110 011 */ cp1610_cmpat_d(6,3); break;
+ case 0x374: /* 1 101 110 100 */ cp1610_cmpat_d(6,4); break;
+ case 0x375: /* 1 101 110 101 */ cp1610_cmpat_d(6,5); break;
+ case 0x376: /* 1 101 110 110 */ cp1610_cmpat_d(6,6); break;
+ case 0x377: /* 1 101 110 111 */ cp1610_cmpat_d(6,7); break;
+
+ case 0x378: /* 1 101 111 000 */ cp1610_cmpi(0); break;
+ case 0x379: /* 1 101 111 001 */ cp1610_cmpi(1); break;
+ case 0x37a: /* 1 101 111 010 */ cp1610_cmpi(2); break;
+ case 0x37b: /* 1 101 111 011 */ cp1610_cmpi(3); break;
+ case 0x37c: /* 1 101 111 100 */ cp1610_cmpi(4); break;
+ case 0x37d: /* 1 101 111 101 */ cp1610_cmpi(5); break;
+ case 0x37e: /* 1 101 111 110 */ cp1610_cmpi(6); break;
+ case 0x37f: /* 1 101 111 111 */ cp1610_cmpi(7); break;
+
+ case 0x380: /* 1 110 000 000 */ cp1610_and(0); break;
+ case 0x381: /* 1 110 000 001 */ cp1610_and(1); break;
+ case 0x382: /* 1 110 000 010 */ cp1610_and(2); break;
+ case 0x383: /* 1 110 000 011 */ cp1610_and(3); break;
+ case 0x384: /* 1 110 000 100 */ cp1610_and(4); break;
+ case 0x385: /* 1 110 000 101 */ cp1610_and(5); break;
+ case 0x386: /* 1 110 000 110 */ cp1610_and(6); break;
+ case 0x387: /* 1 110 000 111 */ cp1610_and(7); break;
+
+ case 0x388: /* 1 110 001 000 */ cp1610_andat(1,0); break;
+ case 0x389: /* 1 110 001 001 */ cp1610_andat(1,1); break;
+ case 0x38a: /* 1 110 001 010 */ cp1610_andat(1,2); break;
+ case 0x38b: /* 1 110 001 011 */ cp1610_andat(1,3); break;
+ case 0x38c: /* 1 110 001 100 */ cp1610_andat(1,4); break;
+ case 0x38d: /* 1 110 001 101 */ cp1610_andat(1,5); break;
+ case 0x38e: /* 1 110 001 110 */ cp1610_andat(1,6); break;
+ case 0x38f: /* 1 110 001 111 */ cp1610_andat(1,7); break;
+
+ case 0x390: /* 1 110 010 000 */ cp1610_andat(2,0); break;
+ case 0x391: /* 1 110 010 001 */ cp1610_andat(2,1); break;
+ case 0x392: /* 1 110 010 010 */ cp1610_andat(2,2); break;
+ case 0x393: /* 1 110 010 011 */ cp1610_andat(2,3); break;
+ case 0x394: /* 1 110 010 100 */ cp1610_andat(2,4); break;
+ case 0x395: /* 1 110 010 101 */ cp1610_andat(2,5); break;
+ case 0x396: /* 1 110 010 110 */ cp1610_andat(2,6); break;
+ case 0x397: /* 1 110 010 111 */ cp1610_andat(2,7); break;
+
+ case 0x398: /* 1 110 011 000 */ cp1610_andat(3,0); break;
+ case 0x399: /* 1 110 011 001 */ cp1610_andat(3,1); break;
+ case 0x39a: /* 1 110 011 010 */ cp1610_andat(3,2); break;
+ case 0x39b: /* 1 110 011 011 */ cp1610_andat(3,3); break;
+ case 0x39c: /* 1 110 011 100 */ cp1610_andat(3,4); break;
+ case 0x39d: /* 1 110 011 101 */ cp1610_andat(3,5); break;
+ case 0x39e: /* 1 110 011 110 */ cp1610_andat(3,6); break;
+ case 0x39f: /* 1 110 011 111 */ cp1610_andat(3,7); break;
+
+ case 0x3a0: /* 1 110 100 000 */ cp1610_andat_i(4,0); break;
+ case 0x3a1: /* 1 110 100 001 */ cp1610_andat_i(4,1); break;
+ case 0x3a2: /* 1 110 100 010 */ cp1610_andat_i(4,2); break;
+ case 0x3a3: /* 1 110 100 011 */ cp1610_andat_i(4,3); break;
+ case 0x3a4: /* 1 110 100 100 */ cp1610_andat_i(4,4); break;
+ case 0x3a5: /* 1 110 100 101 */ cp1610_andat_i(4,5); break;
+ case 0x3a6: /* 1 110 100 110 */ cp1610_andat_i(4,6); break;
+ case 0x3a7: /* 1 110 100 111 */ cp1610_andat_i(4,7); break;
+
+ case 0x3a8: /* 1 110 101 000 */ cp1610_andat_i(5,0); break;
+ case 0x3a9: /* 1 110 101 001 */ cp1610_andat_i(5,1); break;
+ case 0x3aa: /* 1 110 101 010 */ cp1610_andat_i(5,2); break;
+ case 0x3ab: /* 1 110 101 011 */ cp1610_andat_i(5,3); break;
+ case 0x3ac: /* 1 110 101 100 */ cp1610_andat_i(5,4); break;
+ case 0x3ad: /* 1 110 101 101 */ cp1610_andat_i(5,5); break;
+ case 0x3ae: /* 1 110 101 110 */ cp1610_andat_i(5,6); break;
+ case 0x3af: /* 1 110 101 111 */ cp1610_andat_i(5,7); break;
+
+ case 0x3b0: /* 1 110 110 000 */ cp1610_andat_d(6,0); break;
+ case 0x3b1: /* 1 110 110 001 */ cp1610_andat_d(6,1); break;
+ case 0x3b2: /* 1 110 110 010 */ cp1610_andat_d(6,2); break;
+ case 0x3b3: /* 1 110 110 011 */ cp1610_andat_d(6,3); break;
+ case 0x3b4: /* 1 110 110 100 */ cp1610_andat_d(6,4); break;
+ case 0x3b5: /* 1 110 110 101 */ cp1610_andat_d(6,5); break;
+ case 0x3b6: /* 1 110 110 110 */ cp1610_andat_d(6,6); break;
+ case 0x3b7: /* 1 110 110 111 */ cp1610_andat_d(6,7); break;
+
+ case 0x3b8: /* 1 110 111 000 */ cp1610_andi(0); break;
+ case 0x3b9: /* 1 110 111 001 */ cp1610_andi(1); break;
+ case 0x3ba: /* 1 110 111 010 */ cp1610_andi(2); break;
+ case 0x3bb: /* 1 110 111 011 */ cp1610_andi(3); break;
+ case 0x3bc: /* 1 110 111 100 */ cp1610_andi(4); break;
+ case 0x3bd: /* 1 110 111 101 */ cp1610_andi(5); break;
+ case 0x3be: /* 1 110 111 110 */ cp1610_andi(6); break;
+ case 0x3bf: /* 1 110 111 111 */ cp1610_andi(7); break;
+
+ case 0x3c0: /* 1 111 000 000 */ cp1610_xor(0); break;
+ case 0x3c1: /* 1 111 000 001 */ cp1610_xor(1); break;
+ case 0x3c2: /* 1 111 000 010 */ cp1610_xor(2); break;
+ case 0x3c3: /* 1 111 000 011 */ cp1610_xor(3); break;
+ case 0x3c4: /* 1 111 000 100 */ cp1610_xor(4); break;
+ case 0x3c5: /* 1 111 000 101 */ cp1610_xor(5); break;
+ case 0x3c6: /* 1 111 000 110 */ cp1610_xor(6); break;
+ case 0x3c7: /* 1 111 000 111 */ cp1610_xor(7); break;
+
+ case 0x3c8: /* 1 111 001 000 */ cp1610_xorat(1,0); break;
+ case 0x3c9: /* 1 111 001 001 */ cp1610_xorat(1,1); break;
+ case 0x3ca: /* 1 111 001 010 */ cp1610_xorat(1,2); break;
+ case 0x3cb: /* 1 111 001 011 */ cp1610_xorat(1,3); break;
+ case 0x3cc: /* 1 111 001 100 */ cp1610_xorat(1,4); break;
+ case 0x3cd: /* 1 111 001 101 */ cp1610_xorat(1,5); break;
+ case 0x3ce: /* 1 111 001 110 */ cp1610_xorat(1,6); break;
+ case 0x3cf: /* 1 111 001 111 */ cp1610_xorat(1,7); break;
+
+ case 0x3d0: /* 1 111 010 000 */ cp1610_xorat(2,0); break;
+ case 0x3d1: /* 1 111 010 001 */ cp1610_xorat(2,1); break;
+ case 0x3d2: /* 1 111 010 010 */ cp1610_xorat(2,2); break;
+ case 0x3d3: /* 1 111 010 011 */ cp1610_xorat(2,3); break;
+ case 0x3d4: /* 1 111 010 100 */ cp1610_xorat(2,4); break;
+ case 0x3d5: /* 1 111 010 101 */ cp1610_xorat(2,5); break;
+ case 0x3d6: /* 1 111 010 110 */ cp1610_xorat(2,6); break;
+ case 0x3d7: /* 1 111 010 111 */ cp1610_xorat(2,7); break;
+
+ case 0x3d8: /* 1 111 011 000 */ cp1610_xorat(3,0); break;
+ case 0x3d9: /* 1 111 011 001 */ cp1610_xorat(3,1); break;
+ case 0x3da: /* 1 111 011 010 */ cp1610_xorat(3,2); break;
+ case 0x3db: /* 1 111 011 011 */ cp1610_xorat(3,3); break;
+ case 0x3dc: /* 1 111 011 100 */ cp1610_xorat(3,4); break;
+ case 0x3dd: /* 1 111 011 101 */ cp1610_xorat(3,5); break;
+ case 0x3de: /* 1 111 011 110 */ cp1610_xorat(3,6); break;
+ case 0x3df: /* 1 111 011 111 */ cp1610_xorat(3,7); break;
+
+ case 0x3e0: /* 1 111 100 000 */ cp1610_xorat_i(4,0); break;
+ case 0x3e1: /* 1 111 100 001 */ cp1610_xorat_i(4,1); break;
+ case 0x3e2: /* 1 111 100 010 */ cp1610_xorat_i(4,2); break;
+ case 0x3e3: /* 1 111 100 011 */ cp1610_xorat_i(4,3); break;
+ case 0x3e4: /* 1 111 100 100 */ cp1610_xorat_i(4,4); break;
+ case 0x3e5: /* 1 111 100 101 */ cp1610_xorat_i(4,5); break;
+ case 0x3e6: /* 1 111 100 110 */ cp1610_xorat_i(4,6); break;
+ case 0x3e7: /* 1 111 100 111 */ cp1610_xorat_i(4,7); break;
+
+ case 0x3e8: /* 1 111 101 000 */ cp1610_xorat_i(5,0); break;
+ case 0x3e9: /* 1 111 101 001 */ cp1610_xorat_i(5,1); break;
+ case 0x3ea: /* 1 111 101 010 */ cp1610_xorat_i(5,2); break;
+ case 0x3eb: /* 1 111 101 011 */ cp1610_xorat_i(5,3); break;
+ case 0x3ec: /* 1 111 101 100 */ cp1610_xorat_i(5,4); break;
+ case 0x3ed: /* 1 111 101 101 */ cp1610_xorat_i(5,5); break;
+ case 0x3ee: /* 1 111 101 110 */ cp1610_xorat_i(5,6); break;
+ case 0x3ef: /* 1 111 101 111 */ cp1610_xorat_i(5,7); break;
+
+ case 0x3f0: /* 1 111 110 000 */ cp1610_xorat_d(6,0); break;
+ case 0x3f1: /* 1 111 110 001 */ cp1610_xorat_d(6,1); break;
+ case 0x3f2: /* 1 111 110 010 */ cp1610_xorat_d(6,2); break;
+ case 0x3f3: /* 1 111 110 011 */ cp1610_xorat_d(6,3); break;
+ case 0x3f4: /* 1 111 110 100 */ cp1610_xorat_d(6,4); break;
+ case 0x3f5: /* 1 111 110 101 */ cp1610_xorat_d(6,5); break;
+ case 0x3f6: /* 1 111 110 110 */ cp1610_xorat_d(6,6); break;
+ case 0x3f7: /* 1 111 110 111 */ cp1610_xorat_d(6,7); break;
+
+ case 0x3f8: /* 1 111 111 000 */ cp1610_xori(0); break;
+ case 0x3f9: /* 1 111 111 001 */ cp1610_xori(1); break;
+ case 0x3fa: /* 1 111 111 010 */ cp1610_xori(2); break;
+ case 0x3fb: /* 1 111 111 011 */ cp1610_xori(3); break;
+ case 0x3fc: /* 1 111 111 100 */ cp1610_xori(4); break;
+ case 0x3fd: /* 1 111 111 101 */ cp1610_xori(5); break;
+ case 0x3fe: /* 1 111 111 110 */ cp1610_xori(6); break;
+ case 0x3ff: /* 1 111 111 111 */ cp1610_xori(7); break;
+ }
+
+ if (cp1610.mask_interrupts == 0)
+ {
+ if (cp1610.intr_pending == 1)
+ {
+ /* PSHR R7 */
+ cp1610_writemem16(cp1610.r[6],cp1610.r[7]);
+ cp1610.r[6]++;
+ cp1610_icount -= 9;
+ cp1610.intr_pending = 0;
+ cp1610.r[7] = cp1610.irq_callback(CP1610_INT_INTR);
+ }
+ if ((cp1610.intrm_pending == 1) && (cp1610.intr_enabled))
+ {
+ /* PSHR R7 */
+ cp1610_writemem16(cp1610.r[6],cp1610.r[7]);
+ cp1610.r[6]++;
+ cp1610_icount -= 9;
+ cp1610.intrm_pending = 0;
+ cp1610.r[7] = cp1610.irq_callback(CP1610_INT_INTRM);
+ }
+ if (cp1610.reset_pending == 1)
+ {
+ cp1610.reset_pending = 0;
+ cp1610.r[7] = cp1610.irq_callback(CP1610_RESET);
+ }
+ }
+
+ } while( cp1610_icount > 0 );
+
+ return cycles - cp1610_icount;
+}
+
+static void cp1610_get_context (void *dst)
+{
+ if (dst)
+ *(cp1610_Regs *) dst = cp1610;
+}
+
+static void cp1610_set_context (void *src)
+{
+ if (src)
+ cp1610 = *(cp1610_Regs *) src;
+}
+
+void cp1610_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ cp1610.intr_enabled = 0;
+ cp1610.reset_pending = 0;
+ cp1610.intr_pending = 0;
+ cp1610.intrm_pending = 0;
+ cp1610.irq_callback = irqcallback;
+}
+
+static void cp1610_set_irq_line(UINT32 irqline, int state)
+{
+ switch(irqline)
+ {
+ case CP1610_INT_INTRM:
+ if (state == ASSERT_LINE)
+ cp1610.intrm_pending = 1;
+ cp1610.intrm_state = state;
+ break;
+ case CP1610_RESET:
+ if (state == ASSERT_LINE)
+ cp1610.reset_pending = 1;
+ cp1610.reset_state = state;
+ break;
+ case CP1610_INT_INTR:
+ if (state == ASSERT_LINE)
+ cp1610.intr_pending = 1;
+ cp1610.intr_state = state;
+ break;
+ }
+}
+
+static void cp1610_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_PREVIOUSPC: break; /* TODO? */
+ case CPUINFO_INT_INPUT_STATE + CP1610_INT_INTRM:
+ case CPUINFO_INT_INPUT_STATE + CP1610_RESET:
+ case CPUINFO_INT_INPUT_STATE + CP1610_INT_INTR:
+ cp1610_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); break;
+
+ case CPUINFO_INT_REGISTER + CP1610_R0: cp1610.r[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + CP1610_R1: cp1610.r[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + CP1610_R2: cp1610.r[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + CP1610_R3: cp1610.r[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + CP1610_R4: cp1610.r[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + CP1610_R5: cp1610.r[5] = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + CP1610_R6: cp1610.r[6] = info->i; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + CP1610_R7: cp1610.r[7] = info->i; break;
+ }
+ return;
+}
+
+void cp1610_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(cp1610_Regs); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 7; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* TODO??? */ break;
+
+ case CPUINFO_INT_INPUT_STATE + CP1610_INT_INTRM: info->i = cp1610.intrm_state; break;
+ case CPUINFO_INT_INPUT_STATE + CP1610_RESET: info->i = cp1610.reset_state; break;
+ case CPUINFO_INT_INPUT_STATE + CP1610_INT_INTR: info->i = cp1610.intr_state; break;
+
+ case CPUINFO_INT_REGISTER + CP1610_R0: info->i = cp1610.r[0]; break;
+ case CPUINFO_INT_REGISTER + CP1610_R1: info->i = cp1610.r[1]; break;
+ case CPUINFO_INT_REGISTER + CP1610_R2: info->i = cp1610.r[2]; break;
+ case CPUINFO_INT_REGISTER + CP1610_R3: info->i = cp1610.r[3]; break;
+ case CPUINFO_INT_REGISTER + CP1610_R4: info->i = cp1610.r[4]; break;
+ case CPUINFO_INT_REGISTER + CP1610_R5: info->i = cp1610.r[5]; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + CP1610_R6: info->i = cp1610.r[6]; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + CP1610_R7: info->i = cp1610.r[7]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = cp1610_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = cp1610_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = cp1610_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = cp1610_init; break;
+ case CPUINFO_PTR_RESET: info->reset = cp1610_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = cp1610_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = cp1610_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cp1610_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "CP1610"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), ""); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(),
+ "Copyright (c) 2004 Frank Palazzolo, all rights reserved.");
+ break;
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s = cpuintrf_temp_str(), "%c%c%c%c",
+ cp1610.flags & 0x80 ? 'S':'.',
+ cp1610.flags & 0x40 ? 'Z':'.',
+ cp1610.flags & 0x10 ? 'V':'.',
+ cp1610.flags & 0x10 ? 'C':'.');
+ break;
+ case CPUINFO_STR_REGISTER+CP1610_R0: sprintf(info->s = cpuintrf_temp_str(), "R0:%04X", cp1610.r[0]); break;
+ case CPUINFO_STR_REGISTER+CP1610_R1: sprintf(info->s = cpuintrf_temp_str(), "R1:%04X", cp1610.r[1]); break;
+ case CPUINFO_STR_REGISTER+CP1610_R2: sprintf(info->s = cpuintrf_temp_str(), "R2:%04X", cp1610.r[2]); break;
+ case CPUINFO_STR_REGISTER+CP1610_R3: sprintf(info->s = cpuintrf_temp_str(), "R3:%04X", cp1610.r[3]); break;
+ case CPUINFO_STR_REGISTER+CP1610_R4: sprintf(info->s = cpuintrf_temp_str(), "R4:%04X", cp1610.r[4]); break;
+ case CPUINFO_STR_REGISTER+CP1610_R5: sprintf(info->s = cpuintrf_temp_str(), "R5:%04X", cp1610.r[5]); break;
+ case CPUINFO_STR_REGISTER+CP1610_R6: sprintf(info->s = cpuintrf_temp_str(), "R6:%04X", cp1610.r[6]); break;
+ case CPUINFO_STR_REGISTER+CP1610_R7: sprintf(info->s = cpuintrf_temp_str(), "R7:%04X", cp1610.r[7]); break;
+ }
+
+ return;
+}
+
+
diff --git a/src/emu/cpu/cp1610/cp1610.h b/src/emu/cpu/cp1610/cp1610.h
new file mode 100644
index 00000000000..e7304dc51c8
--- /dev/null
+++ b/src/emu/cpu/cp1610/cp1610.h
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ *
+ * cp1610.h
+ * Portable General Instruments CP1610 emulator interface
+ *
+ * Copyright (c) 2004 Frank Palazzolo, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * palazzol@comcast.net
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#ifndef _CP1610_H
+#define _CP1610_H
+
+#include "cpuintrf.h"
+
+enum {
+ CP1610_R0=1, CP1610_R1, CP1610_R2, CP1610_R3,
+ CP1610_R4, CP1610_R5, CP1610_R6, CP1610_R7
+};
+
+#define CP1610_INT_NONE 0
+#define CP1610_INT_INTRM 1 /* Maskable */
+#define CP1610_RESET 2 /* Non-Maskable */
+#define CP1610_INT_INTR INPUT_LINE_NMI /* Non-Maskable */
+
+extern int cp1610_icount; /* cycle count */
+
+
+void cp1610_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+unsigned cp1610_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+// Temporary
+#define cp1610_readop(A) program_read_word_16be((A)<<1)
+#define cp1610_readmem16(A) program_read_word_16be((A)<<1)
+#define cp1610_writemem16(A,B) program_write_word_16be((A)<<1,B)
+
+#endif /* _CP1610_H */
diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak
new file mode 100644
index 00000000000..06c86237c95
--- /dev/null
+++ b/src/emu/cpu/cpu.mak
@@ -0,0 +1,1689 @@
+###########################################################################
+#
+# cpu.mak
+#
+# Rules for building CPU cores
+#
+# Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+# Visit http://mamedev.org for licensing and usage restrictions.
+#
+###########################################################################
+
+
+CPUSRC = $(EMUSRC)/cpu
+CPUOBJ = $(EMUOBJ)/cpu
+
+
+#-------------------------------------------------
+# Dynamic recompiler objects
+#-------------------------------------------------
+
+ifdef PTR64
+
+DRCOBJ = $(CPUOBJ)/x64drc.o $(CPUOBJ)/x86log.o $(CPUOBJ)/drcfe.o
+
+DRCDEPS = $(CPUSRC)/x86emit.h \
+ $(CPUSRC)/x64drc.c \
+ $(CPUSRC)/x64drc.h \
+
+$(DRCOBJ): $(DRCDEPS)
+
+else
+
+DRCOBJ = $(CPUOBJ)/x86drc.o $(CPUOBJ)/x86log.o $(CPUOBJ)/drcfe.o
+
+DRCDEPS = $(CPUSRC)/x86emit.h \
+ $(CPUSRC)/x86drc.c \
+ $(CPUSRC)/x86drc.h \
+
+$(DRCOBJ): $(DRCDEPS)
+
+endif
+
+
+#-------------------------------------------------
+# Acorn ARM series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_ARM=$(if $(filter ARM,$(CPUS)),1,0)
+CPUDEFS += -DHAS_ARM7=$(if $(filter ARM7,$(CPUS)),1,0)
+
+ifneq ($(filter ARM,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/arm
+CPUOBJS += $(CPUOBJ)/arm/arm.o
+DBGOBJS += $(CPUOBJ)/arm/armdasm.o
+endif
+
+ifneq ($(filter ARM7,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/arm7
+CPUOBJS += $(CPUOBJ)/arm7/arm7.o
+DBGOBJS += $(CPUOBJ)/arm7/arm7dasm.o
+endif
+
+$(CPUOBJ)/arm/arm.o: $(CPUSRC)/arm/arm.c \
+ $(CPUSRC)/arm/arm.h
+
+$(CPUOBJ)/arm7/arm7.o: $(CPUSRC)/arm7/arm7.c \
+ $(CPUSRC)/arm7/arm7.h \
+ $(CPUSRC)/arm7/arm7exec.c \
+ $(CPUSRC)/arm7/arm7core.c
+
+
+
+#-------------------------------------------------
+# Advanced Digital Chips SE3208
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_SE3208=$(if $(filter SE3208,$(CPUS)),1,0)
+
+ifneq ($(filter SE3208,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/se3208
+CPUOBJS += $(CPUOBJ)/se3208/se3208.o
+DBGOBJS += $(CPUOBJ)/se3208/se3208dis.o
+endif
+
+$(CPUOBJ)/se3208/se3208.o: $(CPUSRC)/se3208/se3208.c \
+ $(CPUSRC)/se3208/se3208.h
+
+
+
+#-------------------------------------------------
+# Alpha 8201
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_ALPHA8201=$(if $(filter ALPHA8201,$(CPUS)),1,0)
+CPUDEFS += -DHAS_ALPHA8301=$(if $(filter ALPHA8301,$(CPUS)),1,0)
+
+ifneq ($(filter ALPHA8201 ALPHA8301,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/alph8201
+CPUOBJS += $(CPUOBJ)/alph8201/alph8201.o
+DBGOBJS += $(CPUOBJ)/alph8201/8201dasm.o
+endif
+
+$(CPUOBJ)/alph8201/alph8201.o: $(CPUSRC)/alph8201/alph8201.c \
+ $(CPUSRC)/alph8201/alph8201.h
+
+
+
+#-------------------------------------------------
+# Analog Devices ADSP21xx series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_ADSP2100=$(if $(filter ADSP2100,$(CPUS)),1,0)
+CPUDEFS += -DHAS_ADSP2101=$(if $(filter ADSP2101,$(CPUS)),1,0)
+CPUDEFS += -DHAS_ADSP2104=$(if $(filter ADSP2104,$(CPUS)),1,0)
+CPUDEFS += -DHAS_ADSP2105=$(if $(filter ADSP2105,$(CPUS)),1,0)
+CPUDEFS += -DHAS_ADSP2115=$(if $(filter ADSP2115,$(CPUS)),1,0)
+CPUDEFS += -DHAS_ADSP2181=$(if $(filter ADSP2181,$(CPUS)),1,0)
+
+ifneq ($(filter ADSP2100 ADSP2101 ADSP2104 ADSP2105 ADSP2115 ADSP2181,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/adsp2100
+CPUOBJS += $(CPUOBJ)/adsp2100/adsp2100.o
+DBGOBJS += $(CPUOBJ)/adsp2100/2100dasm.o
+endif
+
+$(CPUOBJ)/adsp2100/adsp2100.o: $(CPUSRC)/adsp2100/adsp2100.c \
+ $(CPUSRC)/adsp2100/adsp2100.h \
+ $(CPUSRC)/adsp2100/2100ops.c
+
+
+
+#-------------------------------------------------
+# Analog Devices "Sharc" ADSP21062
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_ADSP21062=$(if $(filter ADSP21062,$(CPUS)),1,0)
+
+ifneq ($(filter ADSP21062,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/sharc
+CPUOBJS += $(CPUOBJ)/sharc/sharc.o
+DBGOBJS += $(CPUOBJ)/sharc/sharcdsm.o
+endif
+
+$(CPUOBJ)/sharc/sharc.o: $(CPUSRC)/sharc/sharc.c \
+ $(CPUSRC)/sharc/sharc.h \
+ $(CPUSRC)/sharc/sharcops.c \
+ $(CPUSRC)/sharc/sharcops.h \
+ $(CPUSRC)/sharc/sharcdsm.c \
+ $(CPUSRC)/sharc/sharcdsm.h \
+ $(CPUSRC)/sharc/compute.c \
+ $(CPUSRC)/sharc/sharcdma.c \
+ $(CPUSRC)/sharc/sharcmem.c
+
+
+
+#-------------------------------------------------
+# APEXC
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_APEXC=$(if $(filter APEXC,$(CPUS)),1,0)
+
+ifneq ($(filter APEXC,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/apexc
+CPUOBJS += $(CPUOBJ)/apexc/apexc.o
+DBGOBJS += $(CPUOBJ)/apexc/apexcdsm.o
+endif
+
+$(CPUOBJ)/apexc/apexc.o: $(CPUSRC)/apexc/apexc.c \
+ $(CPUSRC)/apexc/apexc.h
+
+
+
+#-------------------------------------------------
+# AT&T DSP32C
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_DSP32C=$(if $(filter DSP32C,$(CPUS)),1,0)
+
+ifneq ($(filter DSP32C,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/dsp32
+CPUOBJS += $(CPUOBJ)/dsp32/dsp32.o
+DBGOBJS += $(CPUOBJ)/dsp32/dsp32dis.o
+endif
+
+$(CPUOBJ)/dsp32/dsp32.o: $(CPUSRC)/dsp32/dsp32.c \
+ $(CPUSRC)/dsp32/dsp32.h
+
+
+
+#-------------------------------------------------
+# Atari custom RISC processor
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_ASAP=$(if $(filter ASAP,$(CPUS)),1,0)
+
+ifneq ($(filter ASAP,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/asap
+CPUOBJS += $(CPUOBJ)/asap/asap.o
+DBGOBJS += $(CPUOBJ)/asap/asapdasm.o
+endif
+
+$(CPUOBJ)/asap/asap.o: $(CPUSRC)/asap/asap.c \
+ $(CPUSRC)/asap/asap.h
+
+
+
+#-------------------------------------------------
+# Atari Jaguar custom DSPs
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_JAGUAR=$(if $(filter JAGUAR,$(CPUS)),1,0)
+
+ifneq ($(filter JAGUAR,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/jaguar
+CPUOBJS += $(CPUOBJ)/jaguar/jaguar.o
+DBGOBJS += $(CPUOBJ)/jaguar/jagdasm.o
+endif
+
+$(CPUOBJ)/jaguar/jaguar.o: $(CPUSRC)/jaguar/jaguar.c \
+ $(CPUSRC)/jaguar/jaguar.h
+
+
+
+#-------------------------------------------------
+# RCA CDP1802
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_CDP1802=$(if $(filter CDP1802,$(CPUS)),1,0)
+
+ifneq ($(filter CDP1802,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/cdp1802
+CPUOBJS += $(CPUOBJ)/cdp1802/cdp1802.o
+DBGOBJS += $(CPUOBJ)/cdp1802/1802dasm.o
+endif
+
+$(CPUOBJ)/cdp1802/cdp1802.o: $(CPUSRC)/cdp1802/cdp1802.c \
+ $(CPUSRC)/cdp1802/cdp1802.h
+
+
+
+#-------------------------------------------------
+# National Semiconductor COP4xx
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_COP410=$(if $(filter COP410,$(CPUS)),1,0)
+CPUDEFS += -DHAS_COP411=$(if $(filter COP411,$(CPUS)),1,0)
+CPUDEFS += -DHAS_COP420=$(if $(filter COP420,$(CPUS)),1,0)
+
+ifneq ($(filter COP410 COP411,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/cop400
+CPUOBJS += $(CPUOBJ)/cop400/cop410.o
+DBGOBJS += $(CPUOBJ)/cop400/cop410ds.o
+endif
+
+ifneq ($(filter COP420,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/cop400
+CPUOBJS += $(CPUOBJ)/cop400/cop420.o
+DBGOBJS += $(CPUOBJ)/cop400/cop420ds.o
+endif
+
+$(CPUOBJ)/cop400/cop410.o: $(CPUSRC)/cop400/cop410.c \
+ $(CPUSRC)/cop400/cop400.h \
+ $(CPUSRC)/cop400/410ops.c
+
+$(CPUOBJ)/cop400/cop420.o: $(CPUSRC)/cop400/cop420.c \
+ $(CPUSRC)/cop400/cop400.h \
+ $(CPUSRC)/cop400/410ops.c \
+ $(CPUSRC)/cop400/420ops.c
+
+
+
+#-------------------------------------------------
+# CP1610
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_CP1610=$(if $(filter CP1610,$(CPUS)),1,0)
+
+ifneq ($(filter CP1610,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/cp1610
+CPUOBJS += $(CPUOBJ)/cp1610/cp1610.o
+DBGOBJS += $(CPUOBJ)/cp1610/1610dasm.o
+endif
+
+$(CPUOBJ)/cp1610/cp1610.o: $(CPUSRC)/cp1610/cp1610.c \
+ $(CPUSRC)/cp1610/cp1610.h
+
+
+
+#-------------------------------------------------
+# Cinematronics vector "CPU"
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_CCPU=$(if $(filter CCPU,$(CPUS)),1,0)
+
+ifneq ($(filter CCPU,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/ccpu
+CPUOBJS += $(CPUOBJ)/ccpu/ccpu.o
+DBGOBJS += $(CPUOBJ)/ccpu/ccpudasm.o
+endif
+
+$(CPUOBJ)/ccpu/ccpu.o: $(CPUSRC)/ccpu/ccpu.c \
+ $(CPUSRC)/ccpu/ccpu.h
+
+
+
+#-------------------------------------------------
+# DEC T-11
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_T11=$(if $(filter T11,$(CPUS)),1,0)
+
+ifneq ($(filter T11,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/t11
+CPUOBJS += $(CPUOBJ)/t11/t11.o
+DBGOBJS += $(CPUOBJ)/t11/t11dasm.o
+endif
+
+$(CPUOBJ)/t11/t11.o: $(CPUSRC)/t11/t11.c \
+ $(CPUSRC)/t11/t11.h \
+ $(CPUSRC)/t11/t11ops.c \
+ $(CPUSRC)/t11/t11table.c
+
+
+
+#-------------------------------------------------
+# F8
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_F8=$(if $(filter F8,$(CPUS)),1,0)
+
+ifneq ($(filter F8,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/f8
+CPUOBJS += $(CPUOBJ)/f8/f8.o
+DBGOBJS += $(CPUOBJ)/f8/f8dasm.o
+endif
+
+$(CPUOBJ)/f8/f8.o: $(CPUSRC)/f8/f8.c \
+ $(CPUSRC)/f8/f8.h
+
+
+
+#-------------------------------------------------
+# G65816
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_G65816=$(if $(filter G65816,$(CPUS)),1,0)
+
+ifneq ($(filter G65816,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/g65816
+CPUOBJS += \
+ $(CPUOBJ)/g65816/g65816.o \
+ $(CPUOBJ)/g65816/g65816o0.o \
+ $(CPUOBJ)/g65816/g65816o1.o \
+ $(CPUOBJ)/g65816/g65816o2.o \
+ $(CPUOBJ)/g65816/g65816o3.o \
+ $(CPUOBJ)/g65816/g65816o4.o
+DBGOBJS += $(CPUOBJ)/g65816/g65816ds.o
+endif
+
+G65816DEPS = \
+ $(CPUSRC)/g65816/g65816.h \
+ $(CPUSRC)/g65816/g65816cm.h \
+ $(CPUSRC)/g65816/g65816op.h
+
+$(CPUOBJ)/g65816/g65816.o: $(CPUSRC)/g65816/g65816.c \
+ $(G65816DEPS)
+
+$(CPUOBJ)/g65816/g65816o0.o: $(CPUSRC)/g65816/g65816o0.c \
+ $(G65816DEPS)
+
+$(CPUOBJ)/g65816/g65816o1.o: $(CPUSRC)/g65816/g65816o1.c \
+ $(G65816DEPS)
+
+$(CPUOBJ)/g65816/g65816o2.o: $(CPUSRC)/g65816/g65816o2.c \
+ $(G65816DEPS)
+
+$(CPUOBJ)/g65816/g65816o3.o: $(CPUSRC)/g65816/g65816o3.c \
+ $(G65816DEPS)
+
+$(CPUOBJ)/g65816/g65816o4.o: $(CPUSRC)/g65816/g65816o4.c \
+ $(G65816DEPS)
+
+
+
+#-------------------------------------------------
+# Hitachi 6309
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_HD6309=$(if $(filter HD6309,$(CPUS)),1,0)
+
+ifneq ($(filter HD6309,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/hd6309
+CPUOBJS += $(CPUOBJ)/hd6309/hd6309.o
+DBGOBJS += $(CPUOBJ)/hd6309/6309dasm.o
+endif
+
+$(CPUOBJ)/hd6309/hd6309.o: $(CPUSRC)/hd6309/hd6309.c \
+ $(CPUSRC)/hd6309/hd6309.h \
+ $(CPUSRC)/hd6309/6309ops.c \
+ $(CPUSRC)/hd6309/6309tbl.c
+
+
+
+#-------------------------------------------------
+# Hitachi H8/3002
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_H83002=$(if $(filter H83002,$(CPUS)),1,0)
+
+ifneq ($(filter H83002,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/h83002
+CPUOBJS += $(CPUOBJ)/h83002/h83002.o $(CPUOBJ)/h83002/h8periph.o
+DBGOBJS += $(CPUOBJ)/h83002/h8disasm.o
+endif
+
+$(CPUOBJ)/h83002/h83002.o: $(CPUSRC)/h83002/h83002.c \
+ $(CPUSRC)/h83002/h83002.h \
+ $(CPUSRC)/h83002/h8priv.h
+
+$(CPUOBJ)/h83002/h8disasm.o: $(CPUSRC)/h83002/h8disasm.c
+
+$(CPUOBJ)/h83002/h8periph.o: $(CPUSRC)/h83002/h8periph.c \
+ $(CPUSRC)/h83002/h8priv.h
+
+
+
+#-------------------------------------------------
+# Hitachi SH2
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_SH2=$(if $(filter SH2,$(CPUS)),1,0)
+
+ifneq ($(filter SH2,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/sh2
+CPUOBJS += $(CPUOBJ)/sh2/sh2.o
+DBGOBJS += $(CPUOBJ)/sh2/sh2dasm.o
+endif
+
+$(CPUOBJ)/sh2/sh2.o: $(CPUSRC)/sh2/sh2.c \
+ $(CPUSRC)/sh2/sh2.h
+
+#-------------------------------------------------
+# Hitachi SH4
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_SH4=$(if $(filter SH4,$(CPUS)),1,0)
+
+ifneq ($(filter SH4,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/sh4
+CPUOBJS += $(CPUOBJ)/sh4/sh4.o
+DBGOBJS += $(CPUOBJ)/sh4/sh4dasm.o
+endif
+
+$(CPUOBJ)/sh4/sh4.o: $(CPUSRC)/sh4/sh4.c \
+ $(CPUSRC)/sh4/sh4.h
+
+#-------------------------------------------------
+# Hudsonsoft 6280
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_H6280=$(if $(filter H6280,$(CPUS)),1,0)
+
+ifneq ($(filter H6280,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/h6280
+CPUOBJS += $(CPUOBJ)/h6280/h6280.o
+DBGOBJS += $(CPUOBJ)/h6280/6280dasm.o
+endif
+
+$(CPUOBJ)/h6280/h6280.o: $(CPUSRC)/h6280/h6280.c \
+ $(CPUSRC)/h6280/h6280.h \
+ $(CPUSRC)/h6280/h6280ops.h \
+ $(CPUSRC)/h6280/tblh6280.c
+
+
+
+#-------------------------------------------------
+# Hyperstone E1 series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_E116T=$(if $(filter E116T,$(CPUS)),1,0)
+CPUDEFS += -DHAS_E116XT=$(if $(filter E116XT,$(CPUS)),1,0)
+CPUDEFS += -DHAS_E116XS=$(if $(filter E116XS,$(CPUS)),1,0)
+CPUDEFS += -DHAS_E116XSR=$(if $(filter E116XSR,$(CPUS)),1,0)
+CPUDEFS += -DHAS_E132N=$(if $(filter E132N,$(CPUS)),1,0)
+CPUDEFS += -DHAS_E132T=$(if $(filter E132T,$(CPUS)),1,0)
+CPUDEFS += -DHAS_E132XN=$(if $(filter E132XN,$(CPUS)),1,0)
+CPUDEFS += -DHAS_E132XT=$(if $(filter E132XT,$(CPUS)),1,0)
+CPUDEFS += -DHAS_E132XS=$(if $(filter E132XS,$(CPUS)),1,0)
+CPUDEFS += -DHAS_E132XSR=$(if $(filter E132XSR,$(CPUS)),1,0)
+CPUDEFS += -DHAS_GMS30C2116=$(if $(filter GMS30C2116,$(CPUS)),1,0)
+CPUDEFS += -DHAS_GMS30C2132=$(if $(filter GMS30C2132,$(CPUS)),1,0)
+CPUDEFS += -DHAS_GMS30C2216=$(if $(filter GMS30C2216,$(CPUS)),1,0)
+CPUDEFS += -DHAS_GMS30C2232=$(if $(filter GMS30C2232,$(CPUS)),1,0)
+
+ifneq ($(filter E116T E116XT E116XS E116XSR E132N E132T E132XN E132XT E132XS E132XSR GMS30C2116 GMS30C2132 GMS30C2216 GMS30C2232,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/e132xs
+CPUOBJS += $(CPUOBJ)/e132xs/e132xs.o
+DBGOBJS += $(CPUOBJ)/e132xs/32xsdasm.o
+endif
+
+$(CPUOBJ)/e132xs/e132xs.o: $(CPUSRC)/e132xs/e132xs.c \
+ $(CPUSRC)/e132xs/e132xs.h
+
+
+
+#-------------------------------------------------
+# Intel 8080/8085A
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_8080=$(if $(filter 8080,$(CPUS)),1,0)
+CPUDEFS += -DHAS_8085A=$(if $(filter 8085A,$(CPUS)),1,0)
+
+ifneq ($(filter 8080 8085A,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/i8085
+CPUOBJS += $(CPUOBJ)/i8085/i8085.o
+DBGOBJS += $(CPUOBJ)/i8085/8085dasm.o
+endif
+
+$(CPUOBJ)/i8085/i8085.o: $(CPUSRC)/i8085/i8085.c \
+ $(CPUSRC)/i8085/i8085.h \
+ $(CPUSRC)/i8085/i8085cpu.h \
+ $(CPUSRC)/i8085/i8085daa.h
+
+
+
+#-------------------------------------------------
+# Intel 8039 and derivatives
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_I8035=$(if $(filter I8035,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I8039=$(if $(filter I8039,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I8048=$(if $(filter I8048,$(CPUS)),1,0)
+CPUDEFS += -DHAS_N7751=$(if $(filter N7751,$(CPUS)),1,0)
+
+ifneq ($(filter I8035 I8039 I8048 N7751,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/i8039
+CPUOBJS += $(CPUOBJ)/i8039/i8039.o
+DBGOBJS += $(CPUOBJ)/i8039/8039dasm.o
+endif
+
+$(CPUOBJ)/i8039/i8039.o: $(CPUSRC)/i8039/i8039.c \
+ $(CPUSRC)/i8039/i8039.h
+
+
+
+#-------------------------------------------------
+# Intel 8x41
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_I8X41=$(if $(filter I8X41,$(CPUS)),1,0)
+
+ifneq ($(filter I8X41,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/i8x41
+CPUOBJS += $(CPUOBJ)/i8x41/i8x41.o
+DBGOBJS += $(CPUOBJ)/i8x41/8x41dasm.o
+endif
+
+$(CPUOBJ)/i8x41/i8x41.o: $(CPUSRC)/i8x41/i8x41.c \
+ $(CPUSRC)/i8x41/i8x41.h
+
+
+
+#-------------------------------------------------
+# Intel 8051 and derivatives
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_I8051=$(if $(filter I8051,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I8052=$(if $(filter I8052,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I8751=$(if $(filter I8751,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I8752=$(if $(filter I8752,$(CPUS)),1,0)
+
+ifneq ($(filter I8051 I8052 I8751 I8752,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/i8051
+CPUOBJS += $(CPUOBJ)/i8051/i8051.o
+DBGOBJS += $(CPUOBJ)/i8051/8051dasm.o
+endif
+
+$(CPUOBJ)/i8051/i8051.o: $(CPUSRC)/i8051/i8051.c \
+ $(CPUSRC)/i8051/i8051.h \
+ $(CPUSRC)/i8051/i8051ops.c
+
+
+
+#-------------------------------------------------
+# Intel 80x86 series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_I8086=$(if $(filter I8086,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I8088=$(if $(filter I8088,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I80186=$(if $(filter I80186,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I80188=$(if $(filter I80188,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I80286=$(if $(filter I80286,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I386=$(if $(filter I386,$(CPUS)),1,0)
+CPUDEFS += -DHAS_I486=$(if $(filter I486,$(CPUS)),1,0)
+CPUDEFS += -DHAS_PENTIUM=$(if $(filter PENTIUM,$(CPUS)),1,0)
+CPUDEFS += -DHAS_MEDIAGX=$(if $(filter MEDIAGX,$(CPUS)),1,0)
+
+ifneq ($(filter I8086 I8088 I80186 I80188,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/i86 $(CPUOBJ)/i386
+CPUOBJS += $(CPUOBJ)/i86/i86.o
+DBGOBJS += $(CPUOBJ)/i386/i386dasm.o
+endif
+
+
+ifneq ($(filter I80286,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/i86 $(CPUOBJ)/i386
+CPUOBJS += $(CPUOBJ)/i86/i286.o
+DBGOBJS += $(CPUOBJ)/i386/i386dasm.o
+endif
+
+
+ifneq ($(filter I386 I486 PENTIUM MEDIAGX,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/i386
+CPUOBJS += $(CPUOBJ)/i386/i386.o
+DBGOBJS += $(CPUOBJ)/i386/i386dasm.o
+endif
+
+I86DEPS = \
+ $(CPUSRC)/i86/i86.h \
+ $(CPUSRC)/i86/ea.h \
+ $(CPUSRC)/i86/host.h \
+ $(CPUSRC)/i86/modrm.h
+
+$(CPUOBJ)/i86/i86.o: $(CPUSRC)/i86/i86.c \
+ $(CPUSRC)/i86/instr86.c \
+ $(CPUSRC)/i86/instr186.c \
+ $(CPUSRC)/i86/i86intf.h \
+ $(CPUSRC)/i86/i186intf.h \
+ $(I86DEPS)
+
+$(CPUOBJ)/i86/i286.o: $(CPUSRC)/i86/i86.c \
+ $(CPUSRC)/i86/instr286.c \
+ $(CPUSRC)/i86/i286intf.h \
+ $(I86DEPS)
+
+$(CPUOBJ)/i386/i386.o: $(CPUSRC)/i386/i386.c \
+ $(CPUSRC)/i386/i386.h \
+ $(CPUSRC)/i386/i386intf.h \
+ $(CPUSRC)/i386/i386op16.c \
+ $(CPUSRC)/i386/i386op32.c \
+ $(CPUSRC)/i386/i386ops.c \
+ $(CPUSRC)/i386/i486ops.c \
+ $(CPUSRC)/i386/pentops.c \
+ $(CPUSRC)/i386/x87ops.c \
+ $(CPUSRC)/i386/i386ops.h \
+ $(CPUSRC)/i386/cycles.h
+
+
+
+#-------------------------------------------------
+# Intel i960
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_I960=$(if $(filter I960,$(CPUS)),1,0)
+
+ifneq ($(filter I960,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/i960
+CPUOBJS += $(CPUOBJ)/i960/i960.o
+DBGOBJS += $(CPUOBJ)/i960/i960dis.o
+endif
+
+$(CPUOBJ)/i960/i960.o: $(CPUSRC)/i960/i960.c \
+ $(CPUSRC)/i960/i960.h
+
+
+
+#-------------------------------------------------
+# Konami custom CPU (6809-based)
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_KONAMI=$(if $(filter KONAMI,$(CPUS)),1,0)
+
+ifneq ($(filter KONAMI,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/konami
+CPUOBJS += $(CPUOBJ)/konami/konami.o
+DBGOBJS += $(CPUOBJ)/konami/knmidasm.o
+endif
+
+$(CPUOBJ)/konami/konami.o: $(CPUSRC)/konami/konami.c \
+ $(CPUSRC)/konami/konami.h \
+ $(CPUSRC)/konami/konamops.c \
+ $(CPUSRC)/konami/konamtbl.c
+
+
+
+#-------------------------------------------------
+# LH5801
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_LH5801=$(if $(filter LH5801,$(CPUS)),1,0)
+
+ifneq ($(filter LH5801,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/lh5801
+CPUOBJS += $(CPUOBJ)/lh5801/lh5801.o
+DBGOBJS += $(CPUOBJ)/lh5801/5801dasm.o
+endif
+
+$(CPUOBJ)/lh5801/lh5801.o: $(CPUSRC)/lh5801/lh5801.c \
+ $(CPUSRC)/lh5801/5801tbl.c \
+ $(CPUSRC)/lh5801/lh5801.h
+
+
+
+#-------------------------------------------------
+# Fujitsu MB88xx
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_MB8841=$(if $(filter MB8841,$(CPUS)),1,0)
+CPUDEFS += -DHAS_MB8842=$(if $(filter MB8842,$(CPUS)),1,0)
+CPUDEFS += -DHAS_MB8843=$(if $(filter MB8843,$(CPUS)),1,0)
+CPUDEFS += -DHAS_MB8844=$(if $(filter MB8844,$(CPUS)),1,0)
+
+ifneq ($(filter MB8841 MB8842 MB8843 MB8844,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/mb88xx
+CPUOBJS += $(CPUOBJ)/mb88xx/mb88xx.o
+DBGOBJS += $(CPUOBJ)/mb88xx/mb88dasm.o
+endif
+
+$(CPUOBJ)/mb88xx/mb88xx.o: $(CPUSRC)/mb88xx/mb88xx.c \
+ $(CPUSRC)/mb88xx/mb88xx.h
+
+
+
+#-------------------------------------------------
+# Fujitsu MB86233
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_MB86233=$(if $(filter MB86233,$(CPUS)),1,0)
+
+ifneq ($(filter MB86233,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/mb86233
+CPUOBJS += $(CPUOBJ)/mb86233/mb86233.o
+DBGOBJS += $(CPUOBJ)/mb86233/mb86233d.o
+endif
+
+$(CPUOBJ)/mb86233/mb86233.o: $(CPUSRC)/mb86233/mb86233.c \
+ $(CPUSRC)/mb86233/mb86233.h
+
+
+
+#-------------------------------------------------
+# Microchip PIC16C5x
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_PIC16C54=$(if $(filter PIC16C54,$(CPUS)),1,0)
+CPUDEFS += -DHAS_PIC16C55=$(if $(filter PIC16C55,$(CPUS)),1,0)
+CPUDEFS += -DHAS_PIC16C56=$(if $(filter PIC16C56,$(CPUS)),1,0)
+CPUDEFS += -DHAS_PIC16C57=$(if $(filter PIC16C57,$(CPUS)),1,0)
+CPUDEFS += -DHAS_PIC16C58=$(if $(filter PIC16C58,$(CPUS)),1,0)
+
+ifneq ($(filter PIC16C54 PIC16C55 PIC16C56 PIC16C57 PIC16C58,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/pic16c5x
+CPUOBJS += $(CPUOBJ)/pic16c5x/pic16c5x.o
+DBGOBJS += $(CPUOBJ)/pic16c5x/16c5xdsm.o
+endif
+
+$(CPUOBJ)/pic16c5x/pic16c5x.o: $(CPUSRC)/pic16c5x/pic16c5x.c \
+ $(CPUSRC)/pic16c5x/pic16c5x.h
+
+
+
+#-------------------------------------------------
+# MIPS R3000 (MIPS I/II) series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_R3000=$(if $(filter R3000,$(CPUS)),1,0)
+
+ifneq ($(filter R3000,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/mips
+CPUOBJS += $(CPUOBJ)/mips/r3000.o
+DBGOBJS += $(CPUOBJ)/mips/r3kdasm.o
+endif
+
+$(CPUOBJ)/mips/r3000.o: $(CPUSRC)/mips/r3000.c \
+ $(CPUSRC)/mips/r3000.h
+
+
+
+#-------------------------------------------------
+# MIPS R4000 (MIPS III/IV) series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_R4600=$(if $(filter R4600,$(CPUS)),1,0)
+CPUDEFS += -DHAS_R4650=$(if $(filter R4650,$(CPUS)),1,0)
+CPUDEFS += -DHAS_R4700=$(if $(filter R4700,$(CPUS)),1,0)
+CPUDEFS += -DHAS_R5000=$(if $(filter R5000,$(CPUS)),1,0)
+CPUDEFS += -DHAS_QED5271=$(if $(filter QED5271,$(CPUS)),1,0)
+CPUDEFS += -DHAS_RM7000=$(if $(filter RM7000,$(CPUS)),1,0)
+
+ifneq ($(filter R4600 R4650 R4700 R5000 QED5271 RM7000,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/mips
+CPUOBJS += $(CPUOBJ)/mips/mips3com.o
+DBGOBJS += $(CPUOBJ)/mips/mips3dsm.o
+
+ifdef X86_MIPS3_DRC
+CPUOBJS += $(CPUOBJ)/mips/mips3drc.o $(CPUOBJ)/mips/mips3fe.o $(DRCOBJ)
+else
+CPUOBJS += $(CPUOBJ)/mips/mips3.o
+endif
+endif
+
+$(CPUOBJ)/mips/mips3.o: $(CPUSRC)/mips/mips3.c \
+ $(CPUSRC)/mips/mips3.h \
+ $(CPUSRC)/mips/mips3com.h
+
+$(CPUOBJ)/mips/mips3drc.o: $(CPUSRC)/mips/mips3drc.c \
+ $(CPUSRC)/mips/mdrcold.c \
+ $(CPUSRC)/mips/mdrc64.c \
+ $(CPUSRC)/mips/mips3.h \
+ $(CPUSRC)/mips/mips3com.h \
+ $(CPUSRC)/mips/mips3fe.h \
+ $(DRCDEPS)
+
+
+
+#-------------------------------------------------
+# Mitsubishi M37702 and M37710 (based on 65C816)
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_M37702=$(if $(filter M37702,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M37710=$(if $(filter M37710,$(CPUS)),1,0)
+
+ifneq ($(filter M37702 M37710,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/m37710
+CPUOBJS += \
+ $(CPUOBJ)/m37710/m37710.o \
+ $(CPUOBJ)/m37710/m37710o0.o \
+ $(CPUOBJ)/m37710/m37710o1.o \
+ $(CPUOBJ)/m37710/m37710o2.o \
+ $(CPUOBJ)/m37710/m37710o3.o
+DBGOBJS += $(CPUOBJ)/m37710/m7700ds.o
+endif
+
+M37710DEPS = \
+ $(CPUSRC)/m37710/m37710.h \
+ $(CPUSRC)/m37710/m37710op.h \
+ $(CPUSRC)/m37710/m7700ds.h
+
+$(CPUOBJ)/m37710/m37710.o: $(CPUSRC)/m37710/m37710.c \
+ $(M37710DEPS)
+
+$(CPUOBJ)/m37710/m37710o0.o: $(CPUSRC)/m37710/m37710o0.c \
+ $(M37710DEPS)
+
+$(CPUOBJ)/m37710/m37710o1.o: $(CPUSRC)/m37710/m37710o1.c \
+ $(M37710DEPS)
+
+$(CPUOBJ)/m37710/m37710o2.o: $(CPUSRC)/m37710/m37710o2.c \
+ $(M37710DEPS)
+
+$(CPUOBJ)/m37710/m37710o3.o: $(CPUSRC)/m37710/m37710o3.c \
+ $(M37710DEPS)
+
+$(CPUOBJ)/m37710/m7700ds.o: $(CPUSRC)/m37710/m7700ds.c \
+ $(CPUSRC)/m37710/m7700ds.h
+
+
+
+#-------------------------------------------------
+# Mostek 6502 and its many derivatives
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_M6502=$(if $(filter M6502,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M65C02=$(if $(filter M65C02,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M65SC02=$(if $(filter M65SC02,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M65CE02=$(if $(filter M65CE02,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M6509=$(if $(filter M6509,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M6510=$(if $(filter M6510 M6510T M7501 M8502,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M6510T=$(if $(filter M6510T,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M7501=$(if $(filter M7501,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M8502=$(if $(filter M8502,$(CPUS)),1,0)
+CPUDEFS += -DHAS_N2A03=$(if $(filter N2A03,$(CPUS)),1,0)
+CPUDEFS += -DHAS_DECO16=$(if $(filter DECO16,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M4510=$(if $(filter M4510,$(CPUS)),1,0)
+
+ifneq ($(filter M6502 M65C02 M65SC02 M6510 M6510T M7501 M8502 N2A03 DECO16,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/m6502
+CPUOBJS += $(CPUOBJ)/m6502/m6502.o
+DBGOBJS += $(CPUOBJ)/m6502/6502dasm.o
+endif
+
+ifneq ($(filter M65CE02,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/m6502
+CPUOBJS += $(CPUOBJ)/m6502/m65ce02.o
+DBGOBJS += $(CPUOBJ)/m6502/6502dasm.o
+endif
+
+ifneq ($(filter M6509,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/m6502
+CPUOBJS += $(CPUOBJ)/m6502/m6509.o
+DBGOBJS += $(CPUOBJ)/m6502/6502dasm.o
+endif
+
+ifneq ($(filter M4510,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/m6502
+CPUOBJS += $(CPUOBJ)/m6502/m4510.o
+DBGOBJS += $(CPUOBJ)/m6502/6502dasm.o
+endif
+
+$(CPUOBJ)/m6502/m6502.o: $(CPUSRC)/m6502/m6502.c \
+ $(CPUSRC)/m6502/m6502.h \
+ $(CPUSRC)/m6502/ops02.h \
+ $(CPUSRC)/m6502/t6502.c \
+ $(CPUSRC)/m6502/t65c02.c \
+ $(CPUSRC)/m6502/t65sc02.c \
+ $(CPUSRC)/m6502/t6510.c \
+ $(CPUSRC)/m6502/tdeco16.c
+
+$(CPUOBJ)/m6502/m65ce02.o: $(CPUSRC)/m6502/m65ce02.c \
+ $(CPUSRC)/m6502/m65ce02.h \
+ $(CPUSRC)/m6502/opsce02.h \
+ $(CPUSRC)/m6502/t65ce02.c
+
+$(CPUOBJ)/m6502/m6509.o: $(CPUSRC)/m6502/m6509.c \
+ $(CPUSRC)/m6502/m6509.h \
+ $(CPUSRC)/m6502/ops09.h \
+ $(CPUSRC)/m6502/t6509.c
+
+
+
+#-------------------------------------------------
+# Motorola 680x
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_M6800=$(if $(filter M6800,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M6801=$(if $(filter M6801,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M6802=$(if $(filter M6802,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M6803=$(if $(filter M6803,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M6808=$(if $(filter M6808,$(CPUS)),1,0)
+CPUDEFS += -DHAS_HD63701=$(if $(filter HD63701,$(CPUS)),1,0)
+CPUDEFS += -DHAS_NSC8105=$(if $(filter NSC8105,$(CPUS)),1,0)
+
+ifneq ($(filter M6800 M6801 M6802 M6803 M6808 HD63701 NSC8105,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/m6800
+CPUOBJS += $(CPUOBJ)/m6800/m6800.o
+DBGOBJS += $(CPUOBJ)/m6800/6800dasm.o
+endif
+
+$(CPUOBJ)/m6800/m6800.o: $(CPUSRC)/m6800/m6800.c \
+ $(CPUSRC)/m6800/m6800.h \
+ $(CPUSRC)/m6800/6800ops.c \
+ $(CPUSRC)/m6800/6800tbl.c
+
+
+
+#-------------------------------------------------
+# Motorola 6805
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_M6805=$(if $(filter M6805,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M68705=$(if $(filter M68705,$(CPUS)),1,0)
+CPUDEFS += -DHAS_HD63705=$(if $(filter HD63705,$(CPUS)),1,0)
+
+ifneq ($(filter M6805 M68705 HD63705,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/m6805
+CPUOBJS += $(CPUOBJ)/m6805/m6805.o
+DBGOBJS += $(CPUOBJ)/m6805/6805dasm.o
+endif
+
+$(CPUOBJ)/m6805/m6805.o: $(CPUSRC)/m6805/m6805.c \
+ $(CPUSRC)/m6805/m6805.h \
+ $(CPUSRC)/m6805/6805ops.c
+
+
+
+#-------------------------------------------------
+# Motorola 6809
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_M6809=$(if $(filter M6809,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M6809E=$(if $(filter M6809E,$(CPUS)),1,0)
+
+ifneq ($(filter M6809 M6809E,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/m6809
+CPUOBJS += $(CPUOBJ)/m6809/m6809.o
+DBGOBJS += $(CPUOBJ)/m6809/6809dasm.o
+endif
+
+$(CPUOBJ)/m6809/m6809.o: $(CPUSRC)/m6809/m6809.c \
+ $(CPUSRC)/m6809/m6809.h \
+ $(CPUSRC)/m6809/6809ops.c \
+ $(CPUSRC)/m6809/6809tbl.c
+
+
+
+#-------------------------------------------------
+# Motorola 68HC11
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_MC68HC11=$(if $(filter MC68HC11,$(CPUS)),1,0)
+
+ifneq ($(filter MC68HC11,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/mc68hc11
+CPUOBJS += $(CPUOBJ)/mc68hc11/mc68hc11.o
+DBGOBJS += $(CPUOBJ)/mc68hc11/hc11dasm.o
+endif
+
+$(CPUOBJ)/mc68hc11/mc68hc11.o: $(CPUSRC)/mc68hc11/mc68hc11.c \
+ $(CPUSRC)/mc68hc11/hc11dasm.c
+
+
+
+#-------------------------------------------------
+# Motorola 68000 series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_M68000=$(if $(filter M68000,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M68008=$(if $(filter M68008,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M68010=$(if $(filter M68010,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M68EC020=$(if $(filter M68EC020,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M68020=$(if $(filter M68020,$(CPUS)),1,0)
+CPUDEFS += -DHAS_M68040=$(if $(filter M68040,$(CPUS)),1,0)
+
+ifneq ($(filter M68000 M68008 M68010 M68EC020 M68020 M68040,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/m68000
+CPUOBJS += $(CPUOBJ)/m68000/m68kcpu.o $(CPUOBJ)/m68000/m68kmame.o $(CPUOBJ)/m68000/m68kops.o
+DBGOBJS += $(CPUOBJ)/m68000/m68kdasm.o
+endif
+
+# when we compile source files we need to include generated files from the OBJ directory
+$(CPUOBJ)/m68000/%.o: $(CPUSRC)/m68000/%.c
+ @echo Compiling $<...
+ $(CC) $(CDEFS) $(CFLAGS) -I$(CPUOBJ)/m68000 -c $< -o $@
+
+# when we compile generated files we need to include stuff from the src directory
+$(CPUOBJ)/m68000/%.o: $(CPUOBJ)/m68000/%.c
+ @echo Compiling $<...
+ $(CC) $(CDEFS) $(CFLAGS) -I$(CPUSRC)/m68000 -c $< -o $@
+
+# rule to generate the C files
+$(CPUOBJ)/m68000/m68kops.c: $(CPUOBJ)/m68000/m68kmake$(EXE) $(CPUSRC)/m68000/m68k_in.c
+ @echo Generating M68K source files...
+ $(CPUOBJ)/m68000/m68kmake$(EXE) $(CPUOBJ)/m68000 $(CPUSRC)/m68000/m68k_in.c
+
+# rule to build the generator
+$(CPUOBJ)/m68000/m68kmake$(EXE): $(CPUOBJ)/m68000/m68kmake.o $(LIBOCORE)
+ @echo Linking $@...
+ $(LD) $(LDFLAGS) $(OSDBGLDFLAGS) $^ $(LIBS) -o $@
+
+# rule to ensure we build the header before building the core CPU file
+$(CPUOBJ)/m68000/m68kcpu.o: $(CPUOBJ)/m68000/m68kops.c
+
+
+
+#-------------------------------------------------
+# Motorola/Freescale dsp56k
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_DSP56156=$(if $(filter DSP56156,$(CPUS)),1,0)
+
+ifneq ($(filter DSP56156,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/dsp56k
+CPUOBJS += $(CPUOBJ)/dsp56k/dsp56k.o
+DBGOBJS += $(CPUOBJ)/dsp56k/dsp56dsm.o
+endif
+
+$(CPUOBJ)/dsp56k/dsp56k.o: $(CPUSRC)/dsp56k/dsp56k.c \
+ $(CPUSRC)/dsp56k/dsp56ops.c \
+ $(CPUSRC)/dsp56k/dsp56k.h
+
+
+
+#-------------------------------------------------
+# PDP-1
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_PDP1=$(if $(filter PDP1,$(CPUS)),1,0)
+
+ifneq ($(filter PDP1,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/pdp1
+CPUOBJS += $(CPUOBJ)/pdp1/pdp1.o
+DBGOBJS += $(CPUOBJ)/pdp1/pdp1dasm.o
+endif
+
+$(CPUOBJ)/pdp1/pdp1.o: $(CPUSRC)/pdp1/pdp1.c \
+ $(CPUSRC)/pdp1/pdp1.h
+
+
+
+#-------------------------------------------------
+# Motorola PowerPC series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_PPC403=$(if $(filter PPC403,$(CPUS)),1,0)
+CPUDEFS += -DHAS_PPC601=$(if $(filter PPC601,$(CPUS)),1,0)
+CPUDEFS += -DHAS_PPC602=$(if $(filter PPC602,$(CPUS)),1,0)
+CPUDEFS += -DHAS_PPC603=$(if $(filter PPC603,$(CPUS)),1,0)
+CPUDEFS += -DHAS_MPC8240=$(if $(filter MPC8240,$(CPUS)),1,0)
+
+ifneq ($(filter PPC403 PPC601 PPC602 PPC603 MPC8240,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/powerpc
+DBGOBJS += $(CPUOBJ)/powerpc/ppc_dasm.o
+
+ifdef X86_PPC_DRC
+CPUOBJS += $(CPUOBJ)/powerpc/ppcdrc.o $(DRCOBJ)
+else
+CPUOBJS += $(CPUOBJ)/powerpc/ppc.o
+endif
+endif
+
+$(CPUOBJ)/powerpc/ppc.o: $(CPUSRC)/powerpc/ppc.c \
+ $(CPUSRC)/powerpc/ppc.h \
+ $(CPUSRC)/powerpc/ppc_ops.c \
+ $(CPUSRC)/powerpc/ppc_mem.c \
+ $(CPUSRC)/powerpc/ppc403.c \
+ $(CPUSRC)/powerpc/ppc602.c \
+ $(CPUSRC)/powerpc/ppc603.c
+
+$(CPUOBJ)/powerpc/ppcdrc.o: $(CPUSRC)/powerpc/ppcdrc.c \
+ $(CPUSRC)/powerpc/ppc.h \
+ $(CPUSRC)/powerpc/drc_ops.c \
+ $(CPUSRC)/powerpc/drc_ops.h \
+ $(CPUSRC)/powerpc/ppc_ops.c \
+ $(CPUSRC)/powerpc/ppc_mem.c \
+ $(CPUSRC)/powerpc/ppc403.c \
+ $(CPUSRC)/powerpc/ppc602.c \
+ $(CPUSRC)/powerpc/ppc603.c \
+ $(DRCDEPS)
+
+
+
+#-------------------------------------------------
+# NEC V-series Intel-compatible
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_V20=$(if $(filter V20,$(CPUS)),1,0)
+CPUDEFS += -DHAS_V25=$(if $(filter V25,$(CPUS)),1,0)
+CPUDEFS += -DHAS_V30=$(if $(filter V30,$(CPUS)),1,0)
+CPUDEFS += -DHAS_V30MZ=$(if $(filter V30MZ,$(CPUS)),1,0)
+CPUDEFS += -DHAS_V33=$(if $(filter V33,$(CPUS)),1,0)
+CPUDEFS += -DHAS_V35=$(if $(filter V35,$(CPUS)),1,0)
+
+ifneq ($(filter V20 V25 V30 V33 V35,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/nec
+CPUOBJS += $(CPUOBJ)/nec/nec.o
+DBGOBJS += $(CPUOBJ)/nec/necdasm.o
+endif
+
+ifneq ($(filter V30MZ,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/v30mz $(CPUOBJ)/nec
+CPUOBJS += $(CPUOBJ)/v30mz/v30mz.o
+DBGOBJS += $(CPUOBJ)/nec/necdasm.o
+endif
+
+$(CPUOBJ)/nec/nec.o: $(CPUSRC)/nec/nec.c \
+ $(CPUSRC)/nec/nec.h \
+ $(CPUSRC)/nec/necintrf.h \
+ $(CPUSRC)/nec/necea.h \
+ $(CPUSRC)/nec/nechost.h \
+ $(CPUSRC)/nec/necinstr.h \
+ $(CPUSRC)/nec/necmodrm.h
+
+$(CPUOBJ)/v30mz/v30mz.o: $(CPUSRC)/v30mz/v30mz.c \
+ $(CPUSRC)/v30mz/v30mz.h \
+ $(CPUSRC)/v30mz/necmodrm.h \
+ $(CPUSRC)/v30mz/necinstr.h \
+ $(CPUSRC)/v30mz/necea.h \
+ $(CPUSRC)/v30mz/nechost.h \
+ $(CPUSRC)/v30mz/necintrf.h
+
+
+
+#-------------------------------------------------
+# NEC V60/V70
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_V60=$(if $(filter V60,$(CPUS)),1,0)
+CPUDEFS += -DHAS_V70=$(if $(filter V70,$(CPUS)),1,0)
+
+ifneq ($(filter V60 V70,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/v60
+CPUOBJS += $(CPUOBJ)/v60/v60.o
+DBGOBJS += $(CPUOBJ)/v60/v60d.o
+endif
+
+$(CPUOBJ)/v60/v60.o: $(CPUSRC)/v60/am.c \
+ $(CPUSRC)/v60/am1.c \
+ $(CPUSRC)/v60/am2.c \
+ $(CPUSRC)/v60/am3.c \
+ $(CPUSRC)/v60/op12.c \
+ $(CPUSRC)/v60/op2.c \
+ $(CPUSRC)/v60/op3.c \
+ $(CPUSRC)/v60/op4.c \
+ $(CPUSRC)/v60/op5.c \
+ $(CPUSRC)/v60/op6.c \
+ $(CPUSRC)/v60/op7a.c \
+ $(CPUSRC)/v60/optable.c \
+ $(CPUSRC)/v60/v60.c \
+ $(CPUSRC)/v60/v60.h \
+ $(CPUSRC)/v60/v60d.c
+
+
+
+#-------------------------------------------------
+# NEC V810 (uPD70732)
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_V810=$(if $(filter V810,$(CPUS)),1,0)
+
+ifneq ($(filter V810,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/v810
+CPUOBJS += $(CPUOBJ)/v810/v810.o
+DBGOBJS += $(CPUOBJ)/v810/v810dasm.o
+endif
+
+$(CPUOBJ)/v810/v810.o: $(CPUSRC)/v810/v810.c \
+ $(CPUSRC)/v810/v810.h
+
+
+
+#-------------------------------------------------
+# NEC uPD7810 series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_UPD7810=$(if $(filter UPD7810,$(CPUS)),1,0)
+CPUDEFS += -DHAS_UPD7807=$(if $(filter UPD7807,$(CPUS)),1,0)
+
+ifneq ($(filter UPD7810 UPD7807,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/upd7810
+CPUOBJS += $(CPUOBJ)/upd7810/upd7810.o
+DBGOBJS += $(CPUOBJ)/upd7810/7810dasm.o
+endif
+
+$(CPUOBJ)/upd7810/upd7810.o: $(CPUSRC)/upd7810/upd7810.c \
+ $(CPUSRC)/upd7810/7810tbl.c \
+ $(CPUSRC)/upd7810/7810ops.c \
+ $(CPUSRC)/upd7810/upd7810.h
+
+
+
+#-------------------------------------------------
+# Nintendo/SGI RSP (R3000-based + vector processing)
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_RSP=$(if $(filter RSP,$(CPUS)),1,0)
+
+ifneq ($(filter RSP,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/rsp
+CPUOBJS += $(CPUOBJ)/rsp/rsp.o
+DBGOBJS += $(CPUOBJ)/rsp/rsp_dasm.o
+endif
+
+$(CPUOBJ)/rsp/rsp.o: $(CPUSRC)/rsp/rsp.c \
+ $(CPUSRC)/rsp/rsp.h
+
+
+
+#-------------------------------------------------
+# Saturn
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_SATURN=$(if $(filter SATURN,$(CPUS)),1,0)
+
+ifneq ($(filter SATURN,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/saturn
+CPUOBJS += $(CPUOBJ)/saturn/saturn.o
+DBGOBJS += $(CPUOBJ)/saturn/saturnds.o
+endif
+
+$(CPUOBJ)/saturn/saturn.o: $(CPUSRC)/saturn/saturn.c \
+ $(CPUSRC)/saturn/sattable.c \
+ $(CPUSRC)/saturn/satops.c \
+ $(CPUSRC)/saturn/saturn.h \
+ $(CPUSRC)/saturn/sat.h
+
+
+
+#-------------------------------------------------
+# Signetics 2650
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_S2650=$(if $(filter S2650,$(CPUS)),1,0)
+
+ifneq ($(filter S2650,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/s2650
+CPUOBJS += $(CPUOBJ)/s2650/s2650.o
+DBGOBJS += $(CPUOBJ)/s2650/2650dasm.o
+endif
+
+$(CPUOBJ)/s2650/s2650.o: $(CPUSRC)/s2650/s2650.c \
+ $(CPUSRC)/s2650/s2650.h \
+ $(CPUSRC)/s2650/s2650cpu.h
+
+
+
+#-------------------------------------------------
+# SC61860
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_SC61860=$(if $(filter SC61860,$(CPUS)),1,0)
+
+ifneq ($(filter SC61860,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/sc61860
+CPUOBJS += $(CPUOBJ)/sc61860/sc61860.o
+DBGOBJS += $(CPUOBJ)/sc61860/scdasm.o
+endif
+
+$(CPUOBJ)/sc61860/sc61860.o: $(CPUSRC)/sc61860/sc61860.h \
+ $(CPUSRC)/sc61860/sc.h \
+ $(CPUSRC)/sc61860/scops.c \
+ $(CPUSRC)/sc61860/sctable.c
+
+
+
+#-------------------------------------------------
+# SM8500
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_SM8500=$(if $(filter SM8500,$(CPUS)),1,0)
+
+ifneq ($(filter SM8500,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/sm8500
+CPUOBJS += $(CPUOBJ)/sm8500/sm8500.o
+DBGOBJS += $(CPUOBJ)/sm8500/sm8500d.o
+endif
+
+$(CPUOBJ)/sm8500/sm8500.o: $(CPUSRC)/sm8500/sm8500.c \
+ $(CPUSRC)/sm8500/sm8500.h \
+ $(CPUSRC)/sm8500/sm85ops.h
+
+
+
+#-------------------------------------------------
+# Sony/Nintendo SPC700
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_SPC700=$(if $(filter SPC700,$(CPUS)),1,0)
+
+ifneq ($(filter SPC700,$(CPUS)),)
+SPCD = cpu/spc700
+OBJDIRS += $(CPUOBJ)/spc700
+CPUOBJS += $(CPUOBJ)/spc700/spc700.o
+DBGOBJS += $(CPUOBJ)/spc700/spc700ds.o
+endif
+
+$(CPUOBJ)/spc700/spc700.o: $(CPUSRC)/spc700/spc700.c \
+ $(CPUSRC)/spc700/spc700.h
+
+
+
+#-------------------------------------------------
+# Sony PlayStation CPU (R3000-based + GTE)
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_PSXCPU=$(if $(filter PSXCPU,$(CPUS)),1,0)
+
+ifneq ($(filter PSXCPU,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/mips
+CPUOBJS += $(CPUOBJ)/mips/psx.o
+DBGOBJS += $(CPUOBJ)/mips/mipsdasm.o
+endif
+
+$(CPUOBJ)/mips/psx.o: $(CPUSRC)/mips/psx.c \
+ $(CPUSRC)/mips/psx.h
+
+
+
+#-------------------------------------------------
+# SSP1610
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_SSP1610=$(if $(filter SSP1610,$(CPUS)),1,0)
+
+ifneq ($(filter SSP1610,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/ssp1610
+CPUOBJS += $(CPUOBJ)/ssp1610/ssp1610.o
+DBGOBJS += $(CPUOBJ)/ssp1610/ssp1610d.o
+endif
+
+$(CPUOBJ)/ssp1610/ssp1610.o: $(CPUSRC)/ssp1610/ssp1610.c \
+ $(CPUSRC)/ssp1610/ssp1610.h
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS7000 series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_TMS7000=$(if $(filter TMS7000,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS7000_EXL=$(if $(filter TMS7000_EXL,$(CPUS)),1,0)
+
+ifneq ($(filter TMS7000 TMS7000_EXL,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms7000
+CPUOBJS += $(CPUOBJ)/tms7000/tms7000.o
+DBGOBJS += $(CPUOBJ)/tms7000/7000dasm.o
+endif
+
+$(CPUOBJ)/tms7000/tms7000.o: $(CPUSRC)/tms7000/tms7000.h \
+ $(CPUSRC)/tms7000/tms7000.c
+
+$(CPUOBJ)/tms7000/7000dasm.o: $(CPUSRC)/tms7000/tms7000.h \
+ $(CPUSRC)/tms7000/7000dasm.c
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS99xx series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_TMS9900=$(if $(filter TMS9900,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS9940=$(if $(filter TMS9940,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS9980=$(if $(filter TMS9980,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS9985=$(if $(filter TMS9985,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS9989=$(if $(filter TMS9989,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS9995=$(if $(filter TMS9995,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS99105A=$(if $(filter TMS99105A,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS99110A=$(if $(filter TMS99110A,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS99000=$(if $(filter TMS99000,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TI990_10=$(if $(filter TMS99010,$(CPUS)),1,0)
+
+ifneq ($(filter TMS9900 TMS9940 TMS99000,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms9900
+CPUOBJS += $(CPUOBJ)/tms9900/tms9900.o
+DBGOBJS += $(CPUOBJ)/tms9900/9900dasm.o
+endif
+
+ifneq ($(filter TMS9980 TMS9985 TMS9989,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms9900
+CPUOBJS += $(CPUOBJ)/tms9900/tms9980a.o
+DBGOBJS += $(CPUOBJ)/tms9900/9900dasm.o
+endif
+
+ifneq ($(filter TMS9995 TMS99105A TMS99110A,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms9900
+CPUOBJS += $(CPUOBJ)/tms9900/tms9995.o
+DBGOBJS += $(CPUOBJ)/tms9900/9900dasm.o
+endif
+
+ifneq ($(filter TMS99010,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms9900
+CPUOBJS += $(CPUOBJ)/tms9900/ti990_10.o
+DBGOBJS += $(CPUOBJ)/tms9900/9900dasm.o
+endif
+
+$(CPUOBJ)/tms9900/tms9900.o: $(CPUSRC)/tms9900/tms9900.c \
+ $(CPUSRC)/tms9900/tms9900.h \
+ $(CPUSRC)/tms9900/99xxcore.h \
+ $(CPUSRC)/tms9900/99xxstat.h
+
+$(CPUOBJ)/tms9900/tms9980a.o: $(CPUSRC)/tms9900/tms9980a.c \
+ $(CPUSRC)/tms9900/tms9900.h \
+ $(CPUSRC)/tms9900/99xxcore.h \
+ $(CPUSRC)/tms9900/99xxstat.h
+
+$(CPUOBJ)/tms9900/tms9995.o: $(CPUSRC)/tms9900/tms9995.c \
+ $(CPUSRC)/tms9900/tms9900.h \
+ $(CPUSRC)/tms9900/99xxcore.h \
+ $(CPUSRC)/tms9900/99xxstat.h
+
+$(CPUOBJ)/tms9900/ti990_10.o: $(CPUSRC)/tms9900/ti990_10.c \
+ $(CPUSRC)/tms9900/tms9900.h \
+ $(CPUSRC)/tms9900/99xxcore.h \
+ $(CPUSRC)/tms9900/99xxstat.h
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS340x0 graphics controllers
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_TMS34010=$(if $(filter TMS34010,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS34020=$(if $(filter TMS34020,$(CPUS)),1,0)
+
+ifneq ($(filter TMS34010 TMS34020,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms34010
+CPUOBJS += $(CPUOBJ)/tms34010/tms34010.o $(CPUOBJ)/tms34010/34010fld.o
+DBGOBJS += $(CPUOBJ)/tms34010/34010dsm.o
+endif
+
+$(CPUOBJ)/tms34010/34010fld.o: $(CPUSRC)/tms34010/34010fld.c
+
+$(CPUOBJ)/tms34010/tms34010.o: $(CPUSRC)/tms34010/tms34010.c \
+ $(CPUSRC)/tms34010/tms34010.h \
+ $(CPUSRC)/tms34010/34010ops.c \
+ $(CPUSRC)/tms34010/34010gfx.c \
+ $(CPUSRC)/tms34010/34010tbl.c
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS3201x DSP
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_TMS32010=$(if $(filter TMS32010,$(CPUS)),1,0)
+
+ifneq ($(filter TMS32010,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms32010
+CPUOBJS += $(CPUOBJ)/tms32010/tms32010.o
+DBGOBJS += $(CPUOBJ)/tms32010/32010dsm.o
+endif
+
+$(CPUOBJ)/tms32010/tms32010.o: $(CPUSRC)/tms32010/tms32010.c \
+ $(CPUSRC)/tms32010/tms32010.h
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS3202x DSP
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_TMS32025=$(if $(filter TMS32025,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS32026=$(if $(filter TMS32026,$(CPUS)),1,0)
+
+ifneq ($(filter TMS32025 TMS32026,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms32025
+CPUOBJS += $(CPUOBJ)/tms32025/tms32025.o
+DBGOBJS += $(CPUOBJ)/tms32025/32025dsm.o
+endif
+
+$(CPUOBJ)/tms32025/tms32025.o: $(CPUSRC)/tms32025/tms32025.c \
+ $(CPUSRC)/tms32025/tms32025.h
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS3203x DSP
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_TMS32031=$(if $(filter TMS32031,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TMS32032=$(if $(filter TMS32032,$(CPUS)),1,0)
+
+ifneq ($(filter TMS32031 TMS32032,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms32031
+CPUOBJS += $(CPUOBJ)/tms32031/tms32031.o
+DBGOBJS += $(CPUOBJ)/tms32031/dis32031.o
+endif
+
+$(CPUOBJ)/tms32031/tms32031.o: $(CPUSRC)/tms32031/tms32031.c \
+ $(CPUSRC)/tms32031/tms32031.h \
+ $(CPUSRC)/tms32031/32031ops.c
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS3205x DSP
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_TMS32051=$(if $(filter TMS32051,$(CPUS)),1,0)
+
+ifneq ($(filter TMS32051,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tms32051
+CPUOBJS += $(CPUOBJ)/tms32051/tms32051.o
+DBGOBJS += $(CPUOBJ)/tms32051/dis32051.o
+endif
+
+$(CPUOBJ)/tms32051/tms32051.o: $(CPUSRC)/tms32051/tms32051.c \
+ $(CPUSRC)/tms32051/tms32051.h
+
+
+
+#-------------------------------------------------
+# Toshiba TLCS-90 Series
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_TLCS90=$(if $(filter TLCS90,$(CPUS)),1,0)
+
+ifneq ($(filter TLCS90,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/tlcs90
+CPUOBJS += $(CPUOBJ)/tlcs90/tlcs90.o
+#DBGOBJS += $(CPUOBJ)/tlcs90/tlcs90.o
+endif
+
+$(CPUOBJ)/tlcs90/tlcs90.o: $(CPUSRC)/tlcs90/tlcs90.c \
+ $(CPUSRC)/tlcs90/tlcs90.h
+
+
+
+#-------------------------------------------------
+# TX0
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_TX0_64KW=$(if $(filter TX0,$(CPUS)),1,0)
+CPUDEFS += -DHAS_TX0_8KW=$(if $(filter TX0,$(CPUS)),1,0)
+
+ifneq ($(filter TX0,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/pdp1
+CPUOBJS += $(CPUOBJ)/pdp1/tx0.o
+DBGOBJS += $(CPUOBJ)/pdp1/tx0dasm.o
+endif
+
+$(CPUOBJ)/pdp1/tx0.o: $(CPUSRC)/pdp1/tx0.h \
+ $(CPUSRC)/pdp1/tx0.c
+
+$(CPUOBJ)/pdp1/tx0dasm.o: $(CPUSRC)/pdp1/tx0.h \
+ $(CPUSRC)/pdp1/tx0dasm.c
+
+
+
+#-------------------------------------------------
+# Zilog Z80
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_Z80=$(if $(filter Z80,$(CPUS)),1,0)
+
+ifneq ($(filter Z80,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/z80
+CPUOBJS += $(CPUOBJ)/z80/z80.o $(CPUOBJ)/z80/z80daisy.o
+DBGOBJS += $(CPUOBJ)/z80/z80dasm.o
+endif
+
+$(CPUOBJ)/z80/z80.o: $(CPUSRC)/z80/z80.c \
+ $(CPUSRC)/z80/z80.h
+
+
+
+#-------------------------------------------------
+# Zilog Z180
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_Z180=$(if $(filter Z180,$(CPUS)),1,0)
+
+ifneq ($(filter Z180,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/z180 $(CPUOBJ)/z80
+CPUOBJS += $(CPUOBJ)/z180/z180.o $(CPUOBJ)/z80/z80daisy.o
+DBGOBJS += $(CPUOBJ)/z180/z180dasm.o
+endif
+
+$(CPUOBJ)/z180/z180.o: $(CPUSRC)/z180/z180.c \
+ $(CPUSRC)/z180/z180.h \
+ $(CPUSRC)/z180/z180daa.h \
+ $(CPUSRC)/z180/z180op.c \
+ $(CPUSRC)/z180/z180ops.h \
+ $(CPUSRC)/z180/z180tbl.h \
+ $(CPUSRC)/z180/z180cb.c \
+ $(CPUSRC)/z180/z180dd.c \
+ $(CPUSRC)/z180/z180ed.c \
+ $(CPUSRC)/z180/z180fd.c \
+ $(CPUSRC)/z180/z180xy.c
+
+
+
+#-------------------------------------------------
+# Zilog Z8000
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_Z8000=$(if $(filter Z8000,$(CPUS)),1,0)
+
+ifneq ($(filter Z8000,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/z8000
+CPUOBJS += $(CPUOBJ)/z8000/z8000.o
+DBGOBJS += $(CPUOBJ)/z8000/8000dasm.o
+endif
+
+$(CPUOBJ)/z8000/z8000.o: $(CPUSRC)/z8000/z8000.c \
+ $(CPUSRC)/z8000/z8000.h \
+ $(CPUSRC)/z8000/z8000cpu.h \
+ $(CPUSRC)/z8000/z8000dab.h \
+ $(CPUSRC)/z8000/z8000ops.c \
+ $(CPUSRC)/z8000/z8000tbl.c
+
+
+
+#-------------------------------------------------
+# Game Boy Z-80
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_Z80GB=$(if $(filter Z80GB,$(CPUS)),1,0)
+
+ifneq ($(filter Z80GB,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/z80gb
+CPUOBJS += $(CPUOBJ)/z80gb/z80gb.o
+DBGOBJS += $(CPUOBJ)/z80gb/z80gbd.o
+endif
+
+$(CPUOBJ)/z80gb/z80gb.o: $(CPUSRC)/z80gb/z80gb.c \
+ $(CPUSRC)/z80gb/z80gb.h \
+ $(CPUSRC)/z80gb/opc_cb.h \
+ $(CPUSRC)/z80gb/opc_main.h
+
+#-------------------------------------------------
+# Nintendo Minx
+#-------------------------------------------------
+
+CPUDEFS += -DHAS_MINX=$(if $(filter MINX,$(CPUS)),1,0)
+
+ifneq ($(filter MINX,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/minx
+CPUOBJS += $(CPUOBJ)/minx/minx.o
+DBGOBJS += $(CPUOBJ)/minx/minxd.o
+endif
+
+$(CPUOBJ)/minx/minx.o: $(CPUSRC)/minx/minx.c \
+ $(CPUSRC)/minx/minx.h \
+ $(CPUSRC)/minx/minxd.c \
+ $(CPUSRC)/minx/minxopce.h \
+ $(CPUSRC)/minx/minxopcf.h \
+ $(CPUSRC)/minx/minxops.h \
+ $(CPUSRC)/minx/minxfunc.h
+
+
diff --git a/src/emu/cpu/drcfe.c b/src/emu/cpu/drcfe.c
new file mode 100644
index 00000000000..35c6472aa56
--- /dev/null
+++ b/src/emu/cpu/drcfe.c
@@ -0,0 +1,520 @@
+/***************************************************************************
+
+ drcfe.c
+
+ Generic dynamic recompiler frontend structures and utilities.
+
+ Copyright (c) 2007, Aaron Giles
+ Released for general use under the MAME license
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include <stddef.h>
+#include "cpuintrf.h"
+#include "drcfe.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_STACK_DEPTH 100
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* an entry that maps branches for our code walking */
+typedef struct _pc_stack_entry pc_stack_entry;
+struct _pc_stack_entry
+{
+ offs_t targetpc;
+ offs_t srcpc;
+};
+
+
+/* internal state */
+struct _drcfe_state
+{
+ /* configuration parameters */
+ UINT32 window_start; /* code window start offset = startpc - window_start */
+ UINT32 window_end; /* code window end offset = startpc + window_end */
+ UINT32 max_sequence; /* maximum instructions to include in a sequence */
+
+ drcfe_describe describe; /* callback to describe a single instruction */
+ void * param; /* parameter for the callback */
+
+ /* CPU parameters */
+ offs_t pageshift; /* shift to convert address to a page index */
+ cpufunc_translate translate; /* pointer to translation function */
+
+ /* opcode descriptor arrays */
+ opcode_desc * desc_live_list; /* head of list of live descriptions */
+ opcode_desc * desc_free_list; /* head of list of free descriptions */
+ opcode_desc ** desc_array; /* array of descriptions in PC order */
+ UINT32 desc_array_size; /* size of the array */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static opcode_desc *describe_one(drcfe_state *drcfe, offs_t curpc);
+static opcode_desc **build_sequence(drcfe_state *drcfe, opcode_desc **tailptr, int start, int end, UINT32 endflag);
+static void accumulate_live_info_forwards(opcode_desc *desc, UINT64 *gprread, UINT64 *gprwrite, UINT64 *fprread, UINT64 *fprwrite);
+static void accumulate_live_info_backwards(opcode_desc *desc, UINT64 *gprread, UINT64 *gprwrite, UINT64 *fprread, UINT64 *fprwrite);
+static void release_descriptions(drcfe_state *drcfe, opcode_desc *desc);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ desc_alloc - allocate a new opcode description
+-------------------------------------------------*/
+
+INLINE opcode_desc *desc_alloc(drcfe_state *drcfe)
+{
+ opcode_desc *desc = drcfe->desc_free_list;
+
+ /* pull a description off of the free list or allocate a new one */
+ if (desc != NULL)
+ drcfe->desc_free_list = desc->next;
+ else
+ desc = malloc_or_die(sizeof(*desc));
+ return desc;
+}
+
+
+/*-------------------------------------------------
+ desc_free - free an opcode description
+-------------------------------------------------*/
+
+INLINE void desc_free(drcfe_state *drcfe, opcode_desc *desc)
+{
+ /* just put ourselves on the free list */
+ desc->next = drcfe->desc_free_list;
+ drcfe->desc_free_list = desc;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ drcfe_init - initializate the drcfe state
+-------------------------------------------------*/
+
+drcfe_state *drcfe_init(const drcfe_config *config, void *param)
+{
+ drcfe_state *drcfe;
+
+ /* allocate some memory to hold the state */
+ drcfe = malloc_or_die(sizeof(*drcfe));
+ memset(drcfe, 0, sizeof(*drcfe));
+
+ /* allocate the description array */
+ drcfe->desc_array = malloc_or_die((config->window_end + config->window_start + 2) * sizeof(*drcfe->desc_array));
+ memset(drcfe->desc_array, 0, (config->window_end + config->window_start + 2) * sizeof(*drcfe->desc_array));
+
+ /* copy in configuration information */
+ drcfe->window_start = config->window_start;
+ drcfe->window_end = config->window_end;
+ drcfe->max_sequence = config->max_sequence;
+ drcfe->describe = config->describe;
+ drcfe->param = param;
+
+ /* initialize the state */
+ drcfe->pageshift = activecpu_page_shift(ADDRESS_SPACE_PROGRAM);
+ drcfe->translate = (cpufunc_translate)activecpu_get_info_fct(CPUINFO_PTR_TRANSLATE);
+
+ return drcfe;
+}
+
+
+/*-------------------------------------------------
+ drcfe_exit - clean up after ourselves
+-------------------------------------------------*/
+
+void drcfe_exit(drcfe_state *drcfe)
+{
+ /* release any descriptions we've accumulated */
+ release_descriptions(drcfe, drcfe->desc_live_list);
+
+ /* free our free list of descriptions */
+ while (drcfe->desc_free_list != NULL)
+ {
+ opcode_desc *freeme = drcfe->desc_free_list;
+ drcfe->desc_free_list = drcfe->desc_free_list->next;
+ free(freeme);
+ }
+
+ /* free the description array */
+ if (drcfe->desc_array != NULL)
+ free(drcfe->desc_array);
+
+ /* free the object itself */
+ free(drcfe);
+}
+
+
+/*-------------------------------------------------
+ drcfe_describe_code - describe a sequence of
+ code that falls within the configured window
+ relative to the specified startpc
+-------------------------------------------------*/
+
+const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc)
+{
+ offs_t minpc = startpc - drcfe->window_start;
+ offs_t maxpc = startpc + drcfe->window_end;
+ pc_stack_entry pcstack[MAX_STACK_DEPTH];
+ pc_stack_entry *pcstackptr = &pcstack[0];
+ opcode_desc **tailptr;
+
+ /* release any descriptions we've accumulated */
+ release_descriptions(drcfe, drcfe->desc_live_list);
+ drcfe->desc_live_list = NULL;
+
+ /* add the initial PC to the stack */
+ pcstackptr->srcpc = 0;
+ pcstackptr->targetpc = startpc;
+ pcstackptr++;
+
+ /* loop while we still have a stack */
+ while (pcstackptr != &pcstack[0])
+ {
+ pc_stack_entry *curstack = --pcstackptr;
+ opcode_desc *curdesc;
+ offs_t curpc;
+
+ /* if we've already hit this PC, just mark it a branch target and continue */
+ curdesc = drcfe->desc_array[curstack->targetpc - minpc];
+ if (curdesc != NULL)
+ {
+ curdesc->flags |= OPFLAG_IS_BRANCH_TARGET;
+
+ /* if the branch crosses a page boundary, mark the target as needing to revalidate */
+ if (drcfe->pageshift != 0 && ((curstack->srcpc ^ curdesc->pc) >> drcfe->pageshift) != 0)
+ curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
+
+ /* continue processing */
+ continue;
+ }
+
+ /* loop until we exit the block */
+ for (curpc = curstack->targetpc; curpc < maxpc && drcfe->desc_array[curpc - minpc] == NULL; curpc += drcfe->desc_array[curpc - minpc]->length)
+ {
+ /* allocate a new description and describe this instruction */
+ drcfe->desc_array[curpc - minpc] = curdesc = describe_one(drcfe, curpc);
+
+ /* stop if we hit a page fault */
+ if (curdesc->flags & OPFLAG_COMPILER_PAGE_FAULT)
+ break;
+
+ /* if we are the first instruction in the whole window, we must validate the TLB */
+ if (curpc == startpc && drcfe->pageshift != 0)
+ curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
+
+ /* first instruction in a sequence is always a branch target */
+ if (curpc == curstack->targetpc)
+ curdesc->flags |= OPFLAG_IS_BRANCH_TARGET;
+
+ /* if we are a branch within the block range, add the branch target to our stack */
+ if ((curdesc->flags & OPFLAG_IS_BRANCH) && curdesc->targetpc >= minpc && curdesc->targetpc < maxpc && pcstackptr < &pcstack[MAX_STACK_DEPTH])
+ {
+ curdesc->flags |= OPFLAG_INTRABLOCK_BRANCH;
+ pcstackptr->srcpc = curdesc->pc;
+ pcstackptr->targetpc = curdesc->targetpc;
+ pcstackptr++;
+ }
+
+ /* if we're done, we're done */
+ if (curdesc->flags & OPFLAG_END_SEQUENCE)
+ break;
+ }
+ }
+
+ /* now build the list of descriptions in order */
+ /* first from startpc -> maxpc, then from minpc -> startpc */
+ tailptr = build_sequence(drcfe, &drcfe->desc_live_list, startpc - minpc, maxpc - minpc, OPFLAG_REDISPATCH);
+ tailptr = build_sequence(drcfe, tailptr, minpc - minpc, startpc - minpc, OPFLAG_RETURN_TO_START);
+ return drcfe->desc_live_list;
+}
+
+
+
+/***************************************************************************
+ INTERNAL HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ describe_one - describe a single instruction,
+ recursively describing opcodes in delay
+ slots of branches as well
+-------------------------------------------------*/
+
+static opcode_desc *describe_one(drcfe_state *drcfe, offs_t curpc)
+{
+ opcode_desc *desc = desc_alloc(drcfe);
+
+ /* initialize the description */
+ memset(desc, 0, sizeof(*desc));
+ desc->pc = curpc;
+ desc->physpc = curpc;
+ desc->targetpc = BRANCH_TARGET_DYNAMIC;
+
+ /* compute the physical PC */
+ if (drcfe->translate != NULL && !(*drcfe->translate)(ADDRESS_SPACE_PROGRAM, &desc->physpc))
+ {
+ /* uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and */
+ /* mark as needing to validate; otherwise, just end the sequence here */
+ desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP;
+ return desc;
+ }
+
+ /* get a pointer to the physical address */
+ memory_set_opbase(desc->physpc);
+ desc->opptr.v = cpu_opptr(desc->physpc);
+ assert(desc->opptr.v != NULL);
+ if (desc->opptr.v == NULL)
+ {
+ /* address is unmapped; report it as such */
+ desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_UNMAPPED | OPFLAG_VIRTUAL_NOOP;
+ return desc;
+ }
+
+ /* call the callback to describe an instruction */
+ if (!(*drcfe->describe)(drcfe->param, desc))
+ {
+ desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_INVALID_OPCODE;
+ return desc;
+ }
+
+ /* validate the TLB if we are exactly at the start of a page, or if we cross a page boundary */
+ if (drcfe->pageshift != 0 && (((curpc - 1) ^ (curpc + desc->length - 1)) >> drcfe->pageshift) != 0)
+ desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
+
+ /* validate stuff */
+ assert(desc->length > 0);
+
+ /* if we are a branch with delay slots, recursively walk those */
+ if (desc->flags & OPFLAG_IS_BRANCH)
+ {
+ opcode_desc **tailptr = &desc->delay;
+ offs_t delaypc = curpc + desc->length;
+ UINT8 slotnum;
+
+ /* iterate over slots and describe them */
+ for (slotnum = 0; slotnum < desc->delayslots; slotnum++)
+ {
+ /* recursively describe the next instruction */
+ *tailptr = describe_one(drcfe, delaypc);
+ if (*tailptr == NULL)
+ break;
+
+ /* set the delay slot flag and a pointer back to the original branch */
+ (*tailptr)->flags |= OPFLAG_IN_DELAY_SLOT;
+ (*tailptr)->branch = desc;
+
+ /* stop if we hit a page fault */
+ if ((*tailptr)->flags & OPFLAG_COMPILER_PAGE_FAULT)
+ break;
+
+ /* otherwise, advance */
+ delaypc += (*tailptr)->length;
+ tailptr = &(*tailptr)->next;
+ }
+ }
+
+ return desc;
+}
+
+
+/*-------------------------------------------------
+ build_sequence - build an ordered sequence
+ of instructions
+-------------------------------------------------*/
+
+static opcode_desc **build_sequence(drcfe_state *drcfe, opcode_desc **tailptr, int start, int end, UINT32 endflag)
+{
+ UINT64 gprread = 0, gprwrite = 0;
+ UINT64 fprread = 0, fprwrite = 0;
+ int consecutive = 0;
+ int seqstart = -1;
+ int skipsleft = 0;
+ int descnum;
+
+ /* iterate in order from start to end, picking up all non-NULL instructions */
+ for (descnum = start; descnum < end; descnum++)
+ if (drcfe->desc_array[descnum] != NULL)
+ {
+ opcode_desc *curdesc = drcfe->desc_array[descnum];
+ opcode_desc *nextdesc = NULL;
+ int nextdescnum;
+ UINT8 skipnum;
+
+ /* determine the next instruction, taking skips into account */
+ nextdescnum = descnum + curdesc->length;
+ nextdesc = (nextdescnum < end) ? drcfe->desc_array[nextdescnum] : NULL;
+ for (skipnum = 0; skipnum < curdesc->skipslots && nextdesc != NULL; skipnum++)
+ {
+ nextdescnum = nextdescnum + nextdesc->length;
+ nextdesc = (nextdescnum < end) ? drcfe->desc_array[nextdescnum] : NULL;
+ }
+
+ /* start a new sequence if we aren't already in the middle of one */
+ if (seqstart == -1)
+ seqstart = descnum;
+
+ /* if we are the last instruction, indicate end-of-sequence and redispatch */
+ if (nextdesc == NULL)
+ curdesc->flags |= OPFLAG_END_SEQUENCE | endflag;
+
+ /* otherwise, do some analysis based on the next instruction */
+ else
+ {
+ opcode_desc *scandesc = NULL;
+ int scandescnum;
+
+ /* if there are instructions between us and the next instruction, we must end our sequence here */
+ for (scandescnum = descnum + 1; scandescnum < end; scandescnum++)
+ {
+ scandesc = drcfe->desc_array[scandescnum];
+ if (scandesc != NULL || scandesc == nextdesc)
+ break;
+ }
+ if (scandesc != nextdesc)
+ curdesc->flags |= OPFLAG_END_SEQUENCE;
+
+ /* if the next instruction is a branch target, mark this instruction as end of sequence */
+ if (nextdesc->flags & OPFLAG_IS_BRANCH_TARGET)
+ curdesc->flags |= OPFLAG_END_SEQUENCE;
+ }
+
+ /* if we exceed the maximum consecutive count, cut off the sequence */
+ if (++consecutive >= drcfe->max_sequence)
+ curdesc->flags |= OPFLAG_END_SEQUENCE;
+ if (curdesc->flags & OPFLAG_END_SEQUENCE)
+ consecutive = 0;
+
+ /* update register accumulators */
+ accumulate_live_info_forwards(curdesc, &gprread, &gprwrite, &fprread, &fprwrite);
+
+ /* if this is the end of a sequence, work backwards */
+ if (curdesc->flags & OPFLAG_END_SEQUENCE)
+ {
+ int backdesc;
+
+ /* loop until all the registers have been accounted for */
+ gprread = gprwrite = 0;
+ fprread = fprwrite = 0;
+ for (backdesc = descnum; backdesc != seqstart - 1; backdesc--)
+ if (drcfe->desc_array[backdesc] != NULL)
+ accumulate_live_info_backwards(drcfe->desc_array[backdesc], &gprread, &gprwrite, &fprread, &fprwrite);
+
+ /* reset the register states */
+ seqstart = -1;
+ gprread = gprwrite = 0;
+ fprread = fprwrite = 0;
+ }
+
+ /* if we have instructions remaining to be skipped, and this instruction is a branch target */
+ /* belay the skip order */
+ if (skipsleft > 0 && (curdesc->flags & OPFLAG_IS_BRANCH_TARGET))
+ skipsleft = 0;
+
+ /* if we're not getting skipped, add us to the end of the list and clear our array slot */
+ if (skipsleft == 0)
+ {
+ *tailptr = curdesc;
+ tailptr = &curdesc->next;
+ }
+ else
+ desc_free(drcfe, curdesc);
+
+ /* if the current instruction starts skipping, reset our skip count */
+ /* otherwise, just decrement */
+ if (curdesc->skipslots > 0)
+ skipsleft = curdesc->skipslots;
+ else if (skipsleft > 0)
+ skipsleft--;
+ }
+
+ /* zap the array */
+ memset(&drcfe->desc_array[start], 0, (end - start) * sizeof(drcfe->desc_array[0]));
+
+ /* return the final tailptr */
+ return tailptr;
+}
+
+
+/*-------------------------------------------------
+ accumulate_live_info_forwards - recursively
+ accumulate live register liveness information
+ walking in a forward direction
+-------------------------------------------------*/
+
+static void accumulate_live_info_forwards(opcode_desc *desc, UINT64 *gprread, UINT64 *gprwrite, UINT64 *fprread, UINT64 *fprwrite)
+{
+ /* set the initial information */
+ desc->gpr.liveread = (*gprread |= desc->gpr.used);
+ desc->gpr.livewrite = (*gprwrite |= desc->gpr.modified);
+ desc->fpr.liveread = (*fprread |= desc->fpr.used);
+ desc->fpr.livewrite = (*fprwrite |= desc->fpr.modified);
+
+ /* recursively handle delay slots */
+ if (desc->delay != NULL)
+ accumulate_live_info_forwards(desc->delay, gprread, gprwrite, fprread, fprwrite);
+}
+
+
+/*-------------------------------------------------
+ accumulate_live_info_backwards - recursively
+ accumulate live register liveness information
+ walking in a backwards direction
+-------------------------------------------------*/
+
+static void accumulate_live_info_backwards(opcode_desc *desc, UINT64 *gprread, UINT64 *gprwrite, UINT64 *fprread, UINT64 *fprwrite)
+{
+ /* recursively handle delay slots */
+ if (desc->delay != NULL)
+ accumulate_live_info_backwards(desc->delay, gprread, gprwrite, fprread, fprwrite);
+
+ /* accumulate the info from this instruction */
+ desc->gpr.liveread &= (*gprread |= desc->gpr.used);
+ desc->gpr.livewrite &= (*gprwrite |= desc->gpr.modified);
+ desc->fpr.liveread &= (*fprread |= desc->fpr.used);
+ desc->fpr.livewrite &= (*fprwrite |= desc->fpr.modified);
+}
+
+
+/*-------------------------------------------------
+ release_descriptions - release any
+ descriptions we've allocated back to the
+ free list
+------------------------------------------------*/
+
+static void release_descriptions(drcfe_state *drcfe, opcode_desc *desc)
+{
+ /* loop while we still have valid entries */
+ while (desc != NULL)
+ {
+ opcode_desc *freeme = desc;
+
+ /* recursively release delay slots */
+ if (desc->delay != NULL)
+ release_descriptions(drcfe, desc->delay);
+ desc = desc->next;
+ desc_free(drcfe, freeme);
+ }
+}
diff --git a/src/emu/cpu/drcfe.h b/src/emu/cpu/drcfe.h
new file mode 100644
index 00000000000..44661034251
--- /dev/null
+++ b/src/emu/cpu/drcfe.h
@@ -0,0 +1,188 @@
+/***************************************************************************
+
+ drcfe.h
+
+ Generic dynamic recompiler frontend structures and utilities.
+
+ Copyright (c) 2007, Aaron Giles
+ Released for general use under the MAME license
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Concepts:
+
+ Dynamic recompiling cores are generally broken into a platform-neutral
+ "frontend", which performs some level of analysis on the code, and a
+ platform-specific "backend", which generates the recompiled machine
+ code.
+
+ The frontend's job is generally to walk through the instruction stream,
+ identifying basic blocks, or "sequences" of code that can be compiled
+ and optimized as a unit. This scanning involves recursively walking
+ the instruction stream, following branches, etc., within a specific
+ "code window", relative to the current PC.
+
+ As the frontend walks through the code, it generates a list of opcode
+ "descriptions", one per visited opcode, providing information about
+ code flow, exception handling, and other characteristics. Once the
+ walkthrough is finished, these descriptions are assembled together into
+ a linked list and returned for further processing by the backend.
+
+***************************************************************************/
+
+#ifndef __DRCFE_H__
+#define __DRCFE_H__
+
+#ifdef PTR64
+#include "x64drc.h"
+#else
+#include "x86drc.h"
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* this defines a branch targetpc that is dynamic at runtime */
+#define BRANCH_TARGET_DYNAMIC (~0)
+
+
+/* opcode branch flags */
+#define OPFLAG_IS_UNCONDITIONAL_BRANCH 0x00000001 /* instruction is unconditional branch */
+#define OPFLAG_IS_CONDITIONAL_BRANCH 0x00000002 /* instruction is conditional branch */
+#define OPFLAG_IS_BRANCH (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH)
+#define OPFLAG_IS_BRANCH_TARGET 0x00000004 /* instruction is the target of a branch */
+#define OPFLAG_IN_DELAY_SLOT 0x00000008 /* instruction is in the delay slot of a branch */
+#define OPFLAG_INTRABLOCK_BRANCH 0x00000010 /* instruction branches within the block */
+
+/* opcode exception flags */
+#define OPFLAG_CAN_TRIGGER_SW_INT 0x00000020 /* instruction can trigger a software interrupt */
+#define OPFLAG_CAN_EXPOSE_EXTERNAL_INT 0x00000040 /* instruction can expose an external interrupt */
+#define OPFLAG_CAN_CAUSE_EXCEPTION 0x00000080 /* instruction may generate exception */
+#define OPFLAG_WILL_CAUSE_EXCEPTION 0x00000100 /* instruction will generate exception */
+
+/* opcode virtual->physical translation flags */
+#define OPFLAG_VALIDATE_TLB 0x00000200 /* instruction must validate TLB before execution */
+#define OPFLAG_MODIFIES_TRANSLATION 0x00000400 /* instruction modifies the TLB */
+#define OPFLAG_COMPILER_PAGE_FAULT 0x00000800 /* compiler hit a page fault when parsing */
+#define OPFLAG_COMPILER_UNMAPPED 0x00001000 /* compiler hit unmapped memory when parsing */
+
+/* opcode flags */
+#define OPFLAG_INVALID_OPCODE 0x00002000 /* instruction is invalid */
+#define OPFLAG_VIRTUAL_NOOP 0x00004000 /* instruction is a virtual no-op */
+
+/* opcode sequence flow flags */
+#define OPFLAG_REDISPATCH 0x00008000 /* instruction must redispatch after completion */
+#define OPFLAG_RETURN_TO_START 0x00010000 /* instruction must jump back to the beginning after completion */
+#define OPFLAG_END_SEQUENCE 0x00020000 /* this is the last instruction in a sequence */
+#define OPFLAG_CAN_CHANGE_MODES 0x00040000 /* instruction can change modes */
+
+/* execution semantics */
+#define OPFLAG_READS_MEMORY 0x00080000 /* instruction reads memory */
+#define OPFLAG_WRITES_MEMORY 0x00100000 /* instruction writes memory */
+#define OPFLAG_VARIABLE_SHIFT 0x00200000 /* instruction performs a variable count shift */
+#define OPFLAG_MULTIPLY_DIVIDE 0x00400000 /* instruction performs a multiply/divide */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* opaque internal state */
+typedef struct _drcfe_state drcfe_state;
+
+
+/* register information as bitmasks */
+typedef struct _drc_reginfo drc_reginfo;
+struct _drc_reginfo
+{
+ UINT64 used; /* bitmask of used registers */
+ UINT64 modified; /* bitmask of modified registers */
+ UINT64 constant; /* bitmask of constant registers */
+ UINT64 liveread; /* bitmask of registers that are live for reading */
+ UINT64 livewrite; /* bitmask of registers that are live for writing */
+};
+
+
+/* description of a given opcode */
+typedef struct _opcode_desc opcode_desc;
+struct _opcode_desc
+{
+ /* links to other descriptions */
+ opcode_desc * next; /* pointer to next description */
+ opcode_desc * branch; /* pointer back to branch description for delay slots */
+ opcode_desc * delay; /* pointer to delay slot description */
+
+ /* information about the current PC */
+ offs_t pc; /* PC of this opcode */
+ offs_t physpc; /* physical PC of this opcode */
+ offs_t targetpc; /* target PC if we are a branch, or BRANCH_TARGET_DYNAMIC */
+
+ /* pointer to the current opcode */
+ union
+ {
+ void * v;
+ UINT8 * b;
+ UINT16 * w;
+ UINT32 * l;
+ UINT64 * q;
+ } opptr; /* pointer to opcode memory */
+
+ /* information about this instruction's execution */
+ UINT8 length; /* length in bytes of this opcode */
+ UINT8 delayslots; /* number of delay slots (for branches) */
+ UINT8 skipslots; /* number of skip slots (for branches) */
+ UINT32 flags; /* OPFLAG_* opcode flags */
+ UINT32 cycles; /* number of cycles needed to execute */
+
+ /* register usage information */
+ drc_reginfo gpr; /* register info for GPRs */
+ drc_reginfo fpr; /* register info for FPRs */
+};
+
+
+/* callback function that is used to describe a single opcode */
+typedef int (*drcfe_describe)(void *param, opcode_desc *desc);
+
+
+/* description of a given opcode */
+typedef struct _drcfe_config drcfe_config;
+struct _drcfe_config
+{
+ UINT32 window_start; /* code window start offset = startpc - window_start */
+ UINT32 window_end; /* code window end offset = startpc + window_end */
+ UINT32 max_sequence; /* maximum instructions to include in a sequence */
+ drcfe_describe describe; /* callback to describe a single instruction */
+};
+
+/*
+ for each register:
+ callback to load
+ callback to store
+ pointer to memory
+ if (pointer != NULL)
+ - can return reference to memory for operations
+ else
+ - must always load/store from register
+*/
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* initializate the drcfe state */
+drcfe_state *drcfe_init(const drcfe_config *config, void *param);
+
+/* clean up after ourselves */
+void drcfe_exit(drcfe_state *drcfe);
+
+/* describe a sequence of code that falls within the configured window relative to the specified startpc */
+const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc);
+
+
+#endif
diff --git a/src/emu/cpu/dsp32/dsp32.c b/src/emu/cpu/dsp32/dsp32.c
new file mode 100644
index 00000000000..1c65533a8bd
--- /dev/null
+++ b/src/emu/cpu/dsp32/dsp32.c
@@ -0,0 +1,952 @@
+/***************************************************************************
+
+ dsp32.c
+ Core implementation for the portable DSP32 emulator.
+ Written by Aaron Giles
+
+****************************************************************************
+
+ Important note:
+
+ At this time, the emulator is rather incomplete. However, it is
+ sufficiently complete to run both Race Drivin' and Hard Drivin's
+ Airborne, which is all I was after.
+
+ Things that still need to be implemented:
+
+ * interrupts
+ * carry-reverse add operations
+ * do loops
+ * ieee/dsp conversions
+ * input/output conversion
+ * serial I/O
+
+ In addition, there are several optimizations enabled which make
+ assumptions about the code which may not be valid for other
+ applications. Check dsp32ops.c for details.
+
+***************************************************************************/
+
+#include <math.h>
+#include "debugger.h"
+#include "dsp32.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define DETECT_MISALIGNED_MEMORY 0
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* internal register numbering for PIO registers */
+#define PIO_PAR 0
+#define PIO_PDR 1
+#define PIO_EMR 2
+#define PIO_ESR 3
+#define PIO_PCR 4
+#define PIO_PIR 5
+#define PIO_PARE 6
+#define PIO_PDR2 7
+#define PIO_RESERVED 8
+
+#define UPPER (0x00ff << 8)
+#define LOWER (0xff00 << 8)
+
+/* bits in the PCR register */
+#define PCR_RESET 0x001
+#define PCR_REGMAP 0x002
+#define PCR_ENI 0x004
+#define PCR_DMA 0x008
+#define PCR_AUTO 0x010
+#define PCR_PDFs 0x020
+#define PCR_PIFs 0x040
+#define PCR_RES 0x080
+#define PCR_DMA32 0x100
+#define PCR_PIO16 0x200
+#define PCR_FLG 0x400
+
+/* internal flag bits */
+#define UFLAGBIT 1
+#define VFLAGBIT 2
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* register mapping */
+#define R0 r[0]
+#define R1 r[1]
+#define R2 r[2]
+#define R3 r[3]
+#define R4 r[4]
+#define R5 r[5]
+#define R6 r[6]
+#define R7 r[7]
+#define R8 r[8]
+#define R9 r[9]
+#define R10 r[10]
+#define R11 r[11]
+#define R12 r[12]
+#define R13 r[13]
+#define R14 r[14]
+#define PC r[15]
+#define R0_ALT r[16]
+#define R15 r[17]
+#define R16 r[18]
+#define R17 r[19]
+#define R18 r[20]
+#define R19 r[21]
+#define RMM r[22]
+#define RPP r[23]
+#define R20 r[24]
+#define R21 r[25]
+#define DAUC r[26]
+#define IOC r[27]
+#define R22 r[29]
+#define PCSH r[30]
+
+#define A0 a[0]
+#define A1 a[1]
+#define A2 a[2]
+#define A3 a[3]
+#define A_0 a[4]
+#define A_1 a[5]
+
+#define OP dsp32.op
+
+#define zFLAG ((dsp32.nzcflags & 0xffffff) == 0)
+#define nFLAG ((dsp32.nzcflags & 0x800000) != 0)
+#define cFLAG ((dsp32.nzcflags & 0x1000000) != 0)
+#define vFLAG ((dsp32.vflags & 0x800000) != 0)
+#define ZFLAG (dsp32.NZflags == 0)
+#define NFLAG (dsp32.NZflags < 0)
+#define UFLAG (dsp32.VUflags & UFLAGBIT)
+#define VFLAG (dsp32.VUflags & VFLAGBIT)
+
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+/* DSP32 Registers */
+typedef struct
+{
+ /* core registers */
+ UINT32 r[32];
+ UINT32 pin, pout;
+ UINT32 ivtp;
+ UINT32 nzcflags;
+ UINT32 vflags;
+
+ double a[6];
+ double NZflags;
+ UINT8 VUflags;
+
+ double abuf[4];
+ UINT8 abufreg[4];
+ UINT8 abufVUflags[4];
+ UINT8 abufNZflags[4];
+ int abufcycle[4];
+ int abuf_index;
+
+ INT32 mbufaddr[4];
+ UINT32 mbufdata[4];
+ int mbuf_index;
+
+ UINT16 par;
+ UINT8 pare;
+ UINT16 pdr;
+ UINT16 pdr2;
+ UINT16 pir;
+ UINT16 pcr;
+ UINT16 emr;
+ UINT8 esr;
+ UINT16 pcw;
+ UINT8 piop;
+
+ UINT32 ibuf;
+ UINT32 isr;
+ UINT32 obuf;
+ UINT32 osr;
+
+ /* internal stuff */
+ UINT8 lastpins;
+ UINT32 ppc;
+ UINT32 op;
+ int interrupt_cycles;
+ void (*output_pins_changed)(UINT32 pins);
+} dsp32_regs;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void dsp32c_reset(void);
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static dsp32_regs dsp32;
+static int dsp32_icount;
+
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(pc) cpu_readop32(pc)
+
+#define RBYTE(addr) program_read_byte_32le(addr)
+#define WBYTE(addr,data) program_write_byte_32le((addr), data)
+
+#if (!DETECT_MISALIGNED_MEMORY)
+
+#define RWORD(addr) program_read_word_32le(addr)
+#define WWORD(addr,data) program_write_word_32le((addr), data)
+#define RLONG(addr) program_read_dword_32le(addr)
+#define WLONG(addr,data) program_write_dword_32le((addr), data)
+
+#else
+
+INLINE UINT16 RWORD(offs_t addr)
+{
+ UINT16 data;
+ if (addr & 1) fprintf(stderr, "Unaligned word read @ %06X, PC=%06X\n", addr, dsp32.PC);
+ data = program_read_word_32le(addr);
+ return data;
+}
+
+INLINE UINT32 RLONG(offs_t addr)
+{
+ UINT32 data;
+ if (addr & 3) fprintf(stderr, "Unaligned long read @ %06X, PC=%06X\n", addr, dsp32.PC);
+ data = program_write_word_32le(addr);
+ return data;
+}
+
+INLINE void WWORD(offs_t addr, UINT16 data)
+{
+ if (addr & 1) fprintf(stderr, "Unaligned word write @ %06X, PC=%06X\n", addr, dsp32.PC);
+ program_read_dword_32le((addr), data);
+}
+
+INLINE void WLONG(offs_t addr, UINT32 data)
+{
+ if (addr & 3) fprintf(stderr, "Unaligned long write @ %06X, PC=%06X\n", addr, dsp32.PC);
+ program_write_dword_32le((addr), data);
+}
+
+#endif
+
+
+
+/***************************************************************************
+ EXECEPTION HANDLING
+***************************************************************************/
+
+INLINE void generate_exception(int exception)
+{
+}
+
+
+INLINE void invalid_instruction(UINT32 op)
+{
+}
+
+
+
+/***************************************************************************
+ IRQ HANDLING
+***************************************************************************/
+
+static void check_irqs(void)
+{
+ /* finish me! */
+}
+
+
+static void set_irq_line(int irqline, int state)
+{
+ /* finish me! */
+}
+
+
+
+/***************************************************************************
+ REGISTER HANDLING
+***************************************************************************/
+
+static void update_pcr(UINT16 newval)
+{
+ UINT16 oldval = dsp32.pcr;
+ dsp32.pcr = newval;
+
+ /* reset the chip if we get a reset */
+ if ((oldval & PCR_RESET) == 0 && (newval & PCR_RESET) != 0)
+ dsp32c_reset();
+
+ /* track the state of the output pins */
+ if (dsp32.output_pins_changed)
+ {
+ UINT16 newoutput = ((newval & (PCR_PIFs | PCR_ENI)) == (PCR_PIFs | PCR_ENI)) ? DSP32_OUTPUT_PIF : 0;
+ if (newoutput != dsp32.lastpins)
+ {
+ dsp32.lastpins = newoutput;
+ (*dsp32.output_pins_changed)(newoutput);
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ CONTEXT SWITCHING
+***************************************************************************/
+
+static void dsp32c_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(dsp32_regs *)dst = dsp32;
+}
+
+
+static void dsp32c_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ dsp32 = *(dsp32_regs *)src;
+ memory_set_opbase(dsp32.PC);
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+static void dsp32c_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const struct dsp32_config *config = _config;
+
+ /* copy in config data */
+ if (config)
+ dsp32.output_pins_changed = config->output_pins_changed;
+}
+
+
+static void dsp32c_reset(void)
+{
+ /* reset goes to 0 */
+ dsp32.PC = 0;
+ memory_set_opbase(dsp32.PC);
+
+ /* clear some registers */
+ dsp32.pcw &= 0x03ff;
+ update_pcr(dsp32.pcr & PCR_RESET);
+ dsp32.esr = 0;
+ dsp32.emr = 0xffff;
+
+ /* initialize fixed registers */
+ dsp32.R0 = dsp32.R0_ALT = 0;
+ dsp32.RMM = -1;
+ dsp32.RPP = 1;
+ dsp32.A_0 = 0.0;
+ dsp32.A_1 = 1.0;
+
+ /* init internal stuff */
+ dsp32.abufcycle[0] = dsp32.abufcycle[1] = dsp32.abufcycle[2] = dsp32.abufcycle[3] = 12345678;
+ dsp32.mbufaddr[0] = dsp32.mbufaddr[1] = dsp32.mbufaddr[2] = dsp32.mbufaddr[3] = 1;
+}
+
+
+static void dsp32c_exit(void)
+{
+}
+
+
+
+/***************************************************************************
+ CORE INCLUDE
+***************************************************************************/
+
+#include "dsp32ops.c"
+
+
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+static int dsp32c_execute(int cycles)
+{
+ /* skip if halted */
+ if ((dsp32.pcr & PCR_RESET) == 0)
+ return cycles;
+
+ /* count cycles and interrupt cycles */
+ dsp32_icount = cycles;
+ dsp32_icount -= dsp32.interrupt_cycles;
+ dsp32.interrupt_cycles = 0;
+
+ /* update buffered accumulator values */
+ dsp32.abufcycle[0] += dsp32_icount;
+ dsp32.abufcycle[1] += dsp32_icount;
+ dsp32.abufcycle[2] += dsp32_icount;
+ dsp32.abufcycle[3] += dsp32_icount;
+
+ while (dsp32_icount > 0)
+ execute_one();
+
+ dsp32_icount -= dsp32.interrupt_cycles;
+ dsp32.interrupt_cycles = 0;
+
+ /* normalize buffered accumulator values */
+ dsp32.abufcycle[0] -= dsp32_icount;
+ dsp32.abufcycle[1] -= dsp32_icount;
+ dsp32.abufcycle[2] -= dsp32_icount;
+ dsp32.abufcycle[3] -= dsp32_icount;
+
+ return cycles - dsp32_icount;
+}
+
+
+
+/***************************************************************************
+ DISASSEMBLY HOOK
+***************************************************************************/
+
+#ifdef MAME_DEBUG
+static offs_t dsp32c_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ extern unsigned dasm_dsp32(char *, unsigned, UINT32);
+ return dasm_dsp32(buffer, pc, oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24));
+}
+#endif /* MAME_DEBUG */
+
+
+
+/***************************************************************************
+ PARALLEL INTERFACE WRITES
+***************************************************************************/
+
+/* context finder */
+INLINE dsp32_regs *FINDCONTEXT(int cpu)
+{
+ dsp32_regs *context = cpunum_get_context_ptr(cpu);
+ if (!context)
+ context = &dsp32;
+ return context;
+}
+
+static UINT32 regmap[4][16] =
+{
+ { /* DSP32 compatible mode */
+ PIO_PAR|LOWER, PIO_PAR|UPPER, PIO_PDR|LOWER, PIO_PDR|UPPER,
+ PIO_EMR|LOWER, PIO_EMR|UPPER, PIO_ESR|LOWER, PIO_PCR|LOWER,
+ PIO_PIR|UPPER, PIO_PIR|UPPER, PIO_PIR|UPPER, PIO_PIR|UPPER,
+ PIO_PIR|UPPER, PIO_PIR|UPPER, PIO_PIR|UPPER, PIO_PIR|UPPER
+ },
+ { /* DSP32C 8-bit mode */
+ PIO_PAR|LOWER, PIO_PAR|UPPER, PIO_PDR|LOWER, PIO_PDR|UPPER,
+ PIO_EMR|LOWER, PIO_EMR|UPPER, PIO_ESR|LOWER, PIO_PCR|LOWER,
+ PIO_PIR|LOWER, PIO_PIR|UPPER, PIO_PCR|UPPER, PIO_PARE|LOWER,
+ PIO_PDR2|LOWER,PIO_PDR2|UPPER,PIO_RESERVED, PIO_RESERVED
+ },
+ { /* DSP32C illegal mode */
+ PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED,
+ PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED,
+ PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED,
+ PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED
+ },
+ { /* DSP32C 16-bit mode */
+ PIO_PAR, PIO_RESERVED, PIO_PDR, PIO_RESERVED,
+ PIO_EMR, PIO_RESERVED, PIO_ESR|LOWER, PIO_PCR,
+ PIO_PIR, PIO_RESERVED, PIO_RESERVED, PIO_PARE|LOWER,
+ PIO_PDR2, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED
+ }
+};
+
+
+
+/***************************************************************************
+ PARALLEL INTERFACE WRITES
+***************************************************************************/
+
+INLINE void dma_increment(void)
+{
+ if (dsp32.pcr & PCR_AUTO)
+ {
+ int amount = (dsp32.pcr & PCR_DMA32) ? 4 : 2;
+ dsp32.par += amount;
+ if (dsp32.par < amount)
+ dsp32.pare++;
+ }
+}
+
+
+INLINE void dma_load(void)
+{
+ /* only process if DMA is enabled */
+ if (dsp32.pcr & PCR_DMA)
+ {
+ UINT32 addr = dsp32.par | (dsp32.pare << 16);
+
+ /* 16-bit case */
+ if (!(dsp32.pcr & PCR_DMA32))
+ dsp32.pdr = RWORD(addr & 0xfffffe);
+
+ /* 32-bit case */
+ else
+ {
+ UINT32 temp = RLONG(addr & 0xfffffc);
+ dsp32.pdr = temp >> 16;
+ dsp32.pdr2 = temp & 0xffff;
+ }
+
+ /* set the PDF flag to indicate we have data ready */
+ update_pcr(dsp32.pcr | PCR_PDFs);
+ }
+}
+
+
+INLINE void dma_store(void)
+{
+ /* only process if DMA is enabled */
+ if (dsp32.pcr & PCR_DMA)
+ {
+ UINT32 addr = dsp32.par | (dsp32.pare << 16);
+
+ /* 16-bit case */
+ if (!(dsp32.pcr & PCR_DMA32))
+ WWORD(addr & 0xfffffe, dsp32.pdr);
+
+ /* 32-bit case */
+ else
+ WLONG(addr & 0xfffffc, (dsp32.pdr << 16) | dsp32.pdr2);
+
+ /* clear the PDF flag to indicate we have taken the data */
+ update_pcr(dsp32.pcr & ~PCR_PDFs);
+ }
+}
+
+
+void dsp32c_pio_w(int cpunum, int reg, int data)
+{
+ UINT16 mask;
+ UINT8 mode;
+
+ cpuintrf_push_context(cpunum);
+
+ /* look up register and mask */
+ mode = ((dsp32.pcr >> 8) & 2) | ((dsp32.pcr >> 1) & 1);
+ reg = regmap[mode][reg];
+ mask = reg >> 8;
+ if (mask == 0x00ff) data <<= 8;
+ data &= ~mask;
+ reg &= 0xff;
+
+ /* switch off the register */
+ switch (reg)
+ {
+ case PIO_PAR:
+ dsp32.par = (dsp32.par & mask) | data;
+
+ /* trigger a load on the upper half */
+ if (!(mask & 0xff00))
+ dma_load();
+ break;
+
+ case PIO_PARE:
+ dsp32.pare = (dsp32.pare & mask) | data;
+ break;
+
+ case PIO_PDR:
+ dsp32.pdr = (dsp32.pdr & mask) | data;
+
+ /* trigger a write and PDF setting on the upper half */
+ if (!(mask & 0xff00))
+ {
+ dma_store();
+ dma_increment();
+ }
+ break;
+
+ case PIO_PDR2:
+ dsp32.pdr2 = (dsp32.pdr2 & mask) | data;
+ break;
+
+ case PIO_EMR:
+ dsp32.emr = (dsp32.emr & mask) | data;
+ break;
+
+ case PIO_ESR:
+ dsp32.esr = (dsp32.esr & mask) | data;
+ break;
+
+ case PIO_PCR:
+ mask |= 0x0060;
+ data &= ~mask;
+ update_pcr((dsp32.pcr & mask) | data);
+ break;
+
+ case PIO_PIR:
+ dsp32.pir = (dsp32.pir & mask) | data;
+
+ /* set PIF on upper half */
+ if (!(mask & 0xff00))
+ update_pcr(dsp32.pcr | PCR_PIFs);
+ break;
+
+ /* error case */
+ default:
+ logerror("dsp32_pio_w called on invalid register %d\n", reg);
+ break;
+ }
+
+ cpuintrf_pop_context();
+}
+
+
+
+/***************************************************************************
+ PARALLEL INTERFACE READS
+***************************************************************************/
+
+int dsp32c_pio_r(int cpunum, int reg)
+{
+ UINT16 mask, result = 0xffff;
+ UINT8 mode, shift = 0;
+
+ cpuintrf_push_context(cpunum);
+
+ /* look up register and mask */
+ mode = ((dsp32.pcr >> 8) & 2) | ((dsp32.pcr >> 1) & 1);
+ reg = regmap[mode][reg];
+ mask = reg >> 8;
+ if (mask == 0x00ff) mask = 0xff00, shift = 8;
+ reg &= 0xff;
+
+ /* switch off the register */
+ switch (reg)
+ {
+ case PIO_PAR:
+ result = dsp32.par | 1;
+ break;
+
+ case PIO_PARE:
+ result = dsp32.pare;
+ break;
+
+ case PIO_PDR:
+ result = dsp32.pdr;
+
+ /* trigger an increment on the lower half */
+ if (shift != 8)
+ dma_increment();
+
+ /* trigger a fetch on the upper half */
+ if (!(mask & 0xff00))
+ dma_load();
+ break;
+
+ case PIO_PDR2:
+ result = dsp32.pdr2;
+ break;
+
+ case PIO_EMR:
+ result = dsp32.emr;
+ break;
+
+ case PIO_ESR:
+ result = dsp32.esr;
+ break;
+
+ case PIO_PCR:
+ result = dsp32.pcr;
+ break;
+
+ case PIO_PIR:
+ if (!(mask & 0xff00))
+ update_pcr(dsp32.pcr & ~PCR_PIFs); /* clear PIFs */
+ result = dsp32.pir;
+ break;
+
+ /* error case */
+ default:
+ logerror("dsp32_pio_w called on invalid register %d\n", reg);
+ break;
+ }
+
+ cpuintrf_pop_context();
+ return (result >> shift) & ~mask;
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void dsp32c_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + DSP32_IRQ0: set_irq_line(DSP32_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + DSP32_IRQ1: set_irq_line(DSP32_IRQ1, info->i); break;
+
+ /* CAU */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + DSP32_PC: dsp32.PC = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R0: dsp32.R0 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R1: dsp32.R1 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R2: dsp32.R2 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R3: dsp32.R3 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R4: dsp32.R4 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R5: dsp32.R5 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R6: dsp32.R6 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R7: dsp32.R7 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R8: dsp32.R8 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R9: dsp32.R9 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R10: dsp32.R10 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R11: dsp32.R11 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R12: dsp32.R12 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R13: dsp32.R13 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R14: dsp32.R14 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R15: dsp32.R15 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R16: dsp32.R16 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R17: dsp32.R17 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R18: dsp32.R18 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R19: dsp32.R19 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R20: dsp32.R20 = info->i & 0xffffff; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + DSP32_R21: dsp32.R21 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_R22: dsp32.R22 = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_PIN: dsp32.pin = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_POUT: dsp32.pout = info->i & 0xffffff; break;
+ case CPUINFO_INT_REGISTER + DSP32_IVTP: dsp32.ivtp = info->i & 0xffffff; break;
+
+ /* DAU */
+ case CPUINFO_INT_REGISTER + DSP32_A0: dsp32.A0 = info->i; /* fix me -- very wrong */ break;
+ case CPUINFO_INT_REGISTER + DSP32_A1: dsp32.A1 = info->i; /* fix me -- very wrong */ break;
+ case CPUINFO_INT_REGISTER + DSP32_A2: dsp32.A2 = info->i; /* fix me -- very wrong */ break;
+ case CPUINFO_INT_REGISTER + DSP32_A3: dsp32.A3 = info->i; /* fix me -- very wrong */ break;
+ case CPUINFO_INT_REGISTER + DSP32_DAUC: dsp32.DAUC = info->i; break;
+
+ /* PIO */
+ case CPUINFO_INT_REGISTER + DSP32_PAR: dsp32.par = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_PDR: dsp32.pdr = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_PIR: dsp32.pir = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_PCR: update_pcr(info->i & 0x3ff); break;
+ case CPUINFO_INT_REGISTER + DSP32_EMR: dsp32.emr = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_ESR: dsp32.esr = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_PCW: dsp32.pcw = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_PIOP: dsp32.piop = info->i; break;
+
+ /* SIO */
+ case CPUINFO_INT_REGISTER + DSP32_IBUF: dsp32.ibuf = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_ISR: dsp32.isr = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_OBUF: dsp32.obuf = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_OSR: dsp32.osr = info->i; break;
+ case CPUINFO_INT_REGISTER + DSP32_IOC: dsp32.IOC = info->i & 0xfffff; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void dsp32c_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(dsp32); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 4; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 4; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + DSP32_IRQ0: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + DSP32_IRQ1: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = dsp32.ppc; break;
+
+ /* CAU */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + DSP32_PC: info->i = dsp32.PC; break;
+ case CPUINFO_INT_REGISTER + DSP32_R0: info->i = dsp32.R0; break;
+ case CPUINFO_INT_REGISTER + DSP32_R1: info->i = dsp32.R1; break;
+ case CPUINFO_INT_REGISTER + DSP32_R2: info->i = dsp32.R2; break;
+ case CPUINFO_INT_REGISTER + DSP32_R3: info->i = dsp32.R3; break;
+ case CPUINFO_INT_REGISTER + DSP32_R4: info->i = dsp32.R4; break;
+ case CPUINFO_INT_REGISTER + DSP32_R5: info->i = dsp32.R5; break;
+ case CPUINFO_INT_REGISTER + DSP32_R6: info->i = dsp32.R6; break;
+ case CPUINFO_INT_REGISTER + DSP32_R7: info->i = dsp32.R7; break;
+ case CPUINFO_INT_REGISTER + DSP32_R8: info->i = dsp32.R8; break;
+ case CPUINFO_INT_REGISTER + DSP32_R9: info->i = dsp32.R9; break;
+ case CPUINFO_INT_REGISTER + DSP32_R10: info->i = dsp32.R10; break;
+ case CPUINFO_INT_REGISTER + DSP32_R11: info->i = dsp32.R11; break;
+ case CPUINFO_INT_REGISTER + DSP32_R12: info->i = dsp32.R12; break;
+ case CPUINFO_INT_REGISTER + DSP32_R13: info->i = dsp32.R13; break;
+ case CPUINFO_INT_REGISTER + DSP32_R14: info->i = dsp32.R14; break;
+ case CPUINFO_INT_REGISTER + DSP32_R15: info->i = dsp32.R15; break;
+ case CPUINFO_INT_REGISTER + DSP32_R16: info->i = dsp32.R16; break;
+ case CPUINFO_INT_REGISTER + DSP32_R17: info->i = dsp32.R17; break;
+ case CPUINFO_INT_REGISTER + DSP32_R18: info->i = dsp32.R18; break;
+ case CPUINFO_INT_REGISTER + DSP32_R19: info->i = dsp32.R19; break;
+ case CPUINFO_INT_REGISTER + DSP32_R20: info->i = dsp32.R20; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + DSP32_R21: info->i = dsp32.R21; break;
+ case CPUINFO_INT_REGISTER + DSP32_R22: info->i = dsp32.R22; break;
+ case CPUINFO_INT_REGISTER + DSP32_PIN: info->i = dsp32.pin; break;
+ case CPUINFO_INT_REGISTER + DSP32_POUT: info->i = dsp32.pout; break;
+ case CPUINFO_INT_REGISTER + DSP32_IVTP: info->i = dsp32.ivtp; break;
+
+ /* DAU */
+ case CPUINFO_INT_REGISTER + DSP32_A0: info->i = dsp32.A0; /* fix me -- very wrong */ break;
+ case CPUINFO_INT_REGISTER + DSP32_A1: info->i = dsp32.A1; /* fix me -- very wrong */ break;
+ case CPUINFO_INT_REGISTER + DSP32_A2: info->i = dsp32.A2; /* fix me -- very wrong */ break;
+ case CPUINFO_INT_REGISTER + DSP32_A3: info->i = dsp32.A3; /* fix me -- very wrong */ break;
+ case CPUINFO_INT_REGISTER + DSP32_DAUC: info->i = dsp32.DAUC; break;
+
+ /* PIO */
+ case CPUINFO_INT_REGISTER + DSP32_PAR: info->i = dsp32.par; break;
+ case CPUINFO_INT_REGISTER + DSP32_PDR: info->i = dsp32.pdr; break;
+ case CPUINFO_INT_REGISTER + DSP32_PIR: info->i = dsp32.pir; break;
+ case CPUINFO_INT_REGISTER + DSP32_PCR: info->i = dsp32.pcr; break;
+ case CPUINFO_INT_REGISTER + DSP32_EMR: info->i = dsp32.emr; break;
+ case CPUINFO_INT_REGISTER + DSP32_ESR: info->i = dsp32.esr; break;
+ case CPUINFO_INT_REGISTER + DSP32_PCW: info->i = dsp32.pcw; break;
+ case CPUINFO_INT_REGISTER + DSP32_PIOP: info->i = dsp32.piop; break;
+
+ /* SIO */
+ case CPUINFO_INT_REGISTER + DSP32_IBUF: info->i = dsp32.ibuf; break;
+ case CPUINFO_INT_REGISTER + DSP32_ISR: info->i = dsp32.isr; break;
+ case CPUINFO_INT_REGISTER + DSP32_OBUF: info->i = dsp32.obuf; break;
+ case CPUINFO_INT_REGISTER + DSP32_OSR: info->i = dsp32.osr; break;
+ case CPUINFO_INT_REGISTER + DSP32_IOC: info->i = dsp32.IOC; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = dsp32c_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = dsp32c_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = dsp32c_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = dsp32c_init; break;
+ case CPUINFO_PTR_RESET: info->reset = dsp32c_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = dsp32c_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = dsp32c_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = dsp32c_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &dsp32_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "DSP32C"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Lucent DSP32"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Aaron Giles"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ NFLAG ? 'N':'.',
+ ZFLAG ? 'Z':'.',
+ UFLAG ? 'U':'.',
+ VFLAG ? 'V':'.',
+ nFLAG ? 'n':'.',
+ zFLAG ? 'z':'.',
+ cFLAG ? 'c':'.',
+ vFLAG ? 'v':'.');
+ break;
+
+ /* CAU */
+ case CPUINFO_STR_REGISTER + DSP32_PC: sprintf(info->s, "PC: %06X", dsp32.PC); break;
+ case CPUINFO_STR_REGISTER + DSP32_R0: sprintf(info->s, "R0: %06X", dsp32.R0); break;
+ case CPUINFO_STR_REGISTER + DSP32_R1: sprintf(info->s, "R1: %06X", dsp32.R1); break;
+ case CPUINFO_STR_REGISTER + DSP32_R2: sprintf(info->s, "R2: %06X", dsp32.R2); break;
+ case CPUINFO_STR_REGISTER + DSP32_R3: sprintf(info->s, "R3: %06X", dsp32.R3); break;
+ case CPUINFO_STR_REGISTER + DSP32_R4: sprintf(info->s, "R4: %06X", dsp32.R4); break;
+ case CPUINFO_STR_REGISTER + DSP32_R5: sprintf(info->s, "R5: %06X", dsp32.R5); break;
+ case CPUINFO_STR_REGISTER + DSP32_R6: sprintf(info->s, "R6: %06X", dsp32.R6); break;
+ case CPUINFO_STR_REGISTER + DSP32_R7: sprintf(info->s, "R7: %06X", dsp32.R7); break;
+ case CPUINFO_STR_REGISTER + DSP32_R8: sprintf(info->s, "R8: %06X", dsp32.R8); break;
+ case CPUINFO_STR_REGISTER + DSP32_R9: sprintf(info->s, "R9: %06X", dsp32.R9); break;
+ case CPUINFO_STR_REGISTER + DSP32_R10: sprintf(info->s, "R10:%06X", dsp32.R10); break;
+ case CPUINFO_STR_REGISTER + DSP32_R11: sprintf(info->s, "R11:%06X", dsp32.R11); break;
+ case CPUINFO_STR_REGISTER + DSP32_R12: sprintf(info->s, "R12:%06X", dsp32.R12); break;
+ case CPUINFO_STR_REGISTER + DSP32_R13: sprintf(info->s, "R13:%06X", dsp32.R13); break;
+ case CPUINFO_STR_REGISTER + DSP32_R14: sprintf(info->s, "R14:%06X", dsp32.R14); break;
+ case CPUINFO_STR_REGISTER + DSP32_R15: sprintf(info->s, "R15:%06X", dsp32.R15); break;
+ case CPUINFO_STR_REGISTER + DSP32_R16: sprintf(info->s, "R16:%06X", dsp32.R16); break;
+ case CPUINFO_STR_REGISTER + DSP32_R17: sprintf(info->s, "R17:%06X", dsp32.R17); break;
+ case CPUINFO_STR_REGISTER + DSP32_R18: sprintf(info->s, "R18:%06X", dsp32.R18); break;
+ case CPUINFO_STR_REGISTER + DSP32_R19: sprintf(info->s, "R19:%06X", dsp32.R19); break;
+ case CPUINFO_STR_REGISTER + DSP32_R20: sprintf(info->s, "R20:%06X", dsp32.R20); break;
+ case CPUINFO_STR_REGISTER + DSP32_R21: sprintf(info->s, "R21:%06X", dsp32.R21); break;
+ case CPUINFO_STR_REGISTER + DSP32_R22: sprintf(info->s, "R22:%06X", dsp32.R22); break;
+ case CPUINFO_STR_REGISTER + DSP32_PIN: sprintf(info->s, "PIN:%06X", dsp32.pin); break;
+ case CPUINFO_STR_REGISTER + DSP32_POUT: sprintf(info->s, "POUT:%06X", dsp32.pout); break;
+ case CPUINFO_STR_REGISTER + DSP32_IVTP: sprintf(info->s, "IVTP:%06X", dsp32.ivtp); break;
+
+ /* DAU */
+ case CPUINFO_STR_REGISTER + DSP32_A0: sprintf(info->s, "A0:%8g", dsp32.A0); break;
+ case CPUINFO_STR_REGISTER + DSP32_A1: sprintf(info->s, "A1:%8g", dsp32.A1); break;
+ case CPUINFO_STR_REGISTER + DSP32_A2: sprintf(info->s, "A2:%8g", dsp32.A2); break;
+ case CPUINFO_STR_REGISTER + DSP32_A3: sprintf(info->s, "A3:%8g", dsp32.A3); break;
+ case CPUINFO_STR_REGISTER + DSP32_DAUC: sprintf(info->s, "DAUC:%02X", dsp32.DAUC); break;
+
+ /* PIO */
+ case CPUINFO_STR_REGISTER + DSP32_PAR: sprintf(info->s, "PAR:%08X", dsp32.par); break;
+ case CPUINFO_STR_REGISTER + DSP32_PDR: sprintf(info->s, "PDR:%08X", dsp32.pdr); break;
+ case CPUINFO_STR_REGISTER + DSP32_PIR: sprintf(info->s, "PIR:%04X", dsp32.pir); break;
+ case CPUINFO_STR_REGISTER + DSP32_PCR: sprintf(info->s, "PCR:%03X", dsp32.pcr); break;
+ case CPUINFO_STR_REGISTER + DSP32_EMR: sprintf(info->s, "EMR:%04X", dsp32.emr); break;
+ case CPUINFO_STR_REGISTER + DSP32_ESR: sprintf(info->s, "ESR:%02X", dsp32.esr); break;
+ case CPUINFO_STR_REGISTER + DSP32_PCW: sprintf(info->s, "PCW:%04X", dsp32.pcw); break;
+ case CPUINFO_STR_REGISTER + DSP32_PIOP: sprintf(info->s, "PIOP:%02X", dsp32.piop); break;
+
+ /* SIO */
+ case CPUINFO_STR_REGISTER + DSP32_IBUF: sprintf(info->s, "IBUF:%08X", dsp32.ibuf); break;
+ case CPUINFO_STR_REGISTER + DSP32_ISR: sprintf(info->s, "ISR:%08X", dsp32.isr); break;
+ case CPUINFO_STR_REGISTER + DSP32_OBUF: sprintf(info->s, "OBUF:%08X", dsp32.obuf); break;
+ case CPUINFO_STR_REGISTER + DSP32_OSR: sprintf(info->s, "OSR:%08X", dsp32.osr); break;
+ case CPUINFO_STR_REGISTER + DSP32_IOC: sprintf(info->s, "IOC:%05X", dsp32.IOC); break;
+ }
+}
diff --git a/src/emu/cpu/dsp32/dsp32.h b/src/emu/cpu/dsp32/dsp32.h
new file mode 100644
index 00000000000..7b2facfe16b
--- /dev/null
+++ b/src/emu/cpu/dsp32/dsp32.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+
+ dsp32.h
+ Interface file for the portable DSP32 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#ifndef _DSP32_H
+#define _DSP32_H
+
+#include "cpuintrf.h"
+
+
+
+/***************************************************************************
+ COMPILE-TIME DEFINITIONS
+***************************************************************************/
+
+
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ /* CAU */
+ DSP32_PC=1,
+ DSP32_R0,DSP32_R1,DSP32_R2,DSP32_R3,
+ DSP32_R4,DSP32_R5,DSP32_R6,DSP32_R7,
+ DSP32_R8,DSP32_R9,DSP32_R10,DSP32_R11,
+ DSP32_R12,DSP32_R13,DSP32_R14,DSP32_R15,
+ DSP32_R16,DSP32_R17,DSP32_R18,DSP32_R19,
+ DSP32_R20,DSP32_R21,DSP32_R22,
+ DSP32_PIN,DSP32_POUT,DSP32_IVTP,
+
+ /* DAU */
+ DSP32_A0,DSP32_A1,DSP32_A2,DSP32_A3,
+ DSP32_DAUC,
+
+ /* PIO */
+ DSP32_PAR,DSP32_PDR,DSP32_PIR,DSP32_PCR,
+ DSP32_EMR,DSP32_ESR,DSP32_PCW,DSP32_PIOP,
+
+ /* SIO */
+ DSP32_IBUF,DSP32_ISR,DSP32_OBUF,DSP32_OSR,
+ DSP32_IOC
+};
+
+
+
+/***************************************************************************
+ INTERRUPT CONSTANTS
+***************************************************************************/
+
+#define DSP32_IRQ0 0 /* IRQ0 */
+#define DSP32_IRQ1 1 /* IRQ1 */
+
+
+
+/***************************************************************************
+ CONFIGURATION
+***************************************************************************/
+
+#define DSP32_OUTPUT_PIF 0x01
+
+struct dsp32_config
+{
+ void (*output_pins_changed)(UINT32 pins); /* a change has occurred on an output pin */
+};
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+extern void dsp32c_get_info(UINT32 state, cpuinfo *info);
+
+extern void dsp32c_pio_w(int cpunum, int reg, int data);
+extern int dsp32c_pio_r(int cpunum, int reg);
+
+#endif /* _DSP32_H */
diff --git a/src/emu/cpu/dsp32/dsp32dis.c b/src/emu/cpu/dsp32/dsp32dis.c
new file mode 100644
index 00000000000..29eed18bf47
--- /dev/null
+++ b/src/emu/cpu/dsp32/dsp32dis.c
@@ -0,0 +1,693 @@
+/***************************************************************************
+
+ dsp32dis.c
+ Disassembler for the portable AT&T/Lucent DSP32C emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#include "dsp32.h"
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(pc) cpu_readop32(pc)
+
+#define ABS(x) (((x) >= 0) ? (x) : -(x))
+
+
+/***************************************************************************
+ CODE CODE
+***************************************************************************/
+
+static const char *sizesuffix[] = { "", "e" };
+static const char *unarysign[] = { "", "-" };
+static const char *sign[] = { "+", "-" };
+static const char *aMvals[] = { "a0", "a1", "a2", "a3", "0.0", "1.0", "Format 4", "Reserved" };
+static const char *memsuffix[] = { "h", "l", "", "e" };
+static const char *functable[] =
+{
+ "ic", "oc", "float", "int", "round", "ifalt", "ifaeq", "ifagt",
+ "reserved8", "reserved9", "float24", "int24", "ieee", "dsp", "seed", "reservedf"
+};
+static const char *condtable[] =
+{
+ "false", "true",
+ "pl", "mi",
+ "ne", "eq",
+ "vc", "vs",
+ "cc", "cs",
+ "ge", "lt",
+ "gt", "le",
+ "hi", "ls",
+ "auc", "aus",
+ "age", "alt",
+ "ane", "aeq",
+ "avc", "avs",
+ "agt", "ale",
+ "!resd", "resd",
+ "!rese", "rese",
+ "!resf", "resf",
+ "ibe", "ibf",
+ "obf", "obe",
+ "pde", "pdf",
+ "pie", "pif",
+ "syc", "sys",
+ "fbc", "fbs",
+ "ireq1_lo", "ireq1_hi",
+ "ireq2_lo", "ireq2_hi",
+ "!?18", "?18",
+ "!?19", "?19",
+ "!?1a", "?1a",
+ "!?1b", "?1b",
+ "!?1c", "?1c",
+ "!?1d", "?1d",
+ "!?1e", "?1e",
+ "!?1f", "?1f"
+};
+static const char *regname[] =
+{
+ "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc",
+ "0", "r15", "r16", "r17", "r18", "r19", "-1", "1",
+ "r20", "r21", "dauc", "ioc", "res1c", "r22", "pcsh", "res1f"
+};
+static const char *regnamee[] =
+{
+ "0", "r1e", "r2e", "r3e", "r4e", "r5e", "r6e", "r7e",
+ "r8e", "r9e", "r10e", "r11e", "r12e", "r13e", "r14e", "pce",
+ "0", "r15e", "r16e", "r17e", "r18e", "r19e", "--", "++",
+ "r20e", "r21e", "dauce", "ioce", "res1ce", "r22e", "pcshe", "res1fe"
+};
+
+static char tempbuf[10][40];
+
+INLINE char *signed_16bit_unary(INT16 val)
+{
+ static char temp[10];
+ if (val < 0)
+ sprintf(temp, "-$%x", -val);
+ else
+ sprintf(temp, "$%x", val);
+ return temp;
+}
+
+INLINE char *signed_16bit_sep(INT16 val)
+{
+ static char temp[10];
+ if (val < 0)
+ sprintf(temp, " - $%x", -val);
+ else
+ sprintf(temp, " + $%x", val);
+ return temp;
+}
+
+INLINE char *signed_16bit_sep_nospace(INT16 val)
+{
+ static char temp[10];
+ if (val < 0)
+ sprintf(temp, "-$%x", -val);
+ else
+ sprintf(temp, "+$%x", val);
+ return temp;
+}
+
+INLINE char *unsigned_16bit_size(INT16 val, UINT8 size)
+{
+ static char temp[10];
+ if (size)
+ sprintf(temp, "$%06x", (INT32)val & 0xffffff);
+ else
+ sprintf(temp, "$%04x", val & 0xffff);
+ return temp;
+}
+
+static UINT8 lastp;
+static const char *dasm_XYZ(UINT8 bits, char *buffer)
+{
+ UINT8 p = bits >> 3;
+ UINT8 i = bits & 7;
+
+ if (p)
+ {
+ if (p == 15) p = lastp; /* P=15 means Z inherits from Y, Y inherits from X */
+ lastp = p;
+ switch (i)
+ {
+ case 0: sprintf(buffer, "*r%d", p); break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5: sprintf(buffer, "*r%d++r%d", p, i + 14); break;
+ case 6: sprintf(buffer, "*r%d--", p); break;
+ case 7: sprintf(buffer, "*r%d++", p); break;
+ }
+ }
+ else
+ {
+ switch (i)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3: sprintf(buffer, "a%d", i); break;
+ case 4: sprintf(buffer, "ibuf"); break;
+ case 5: sprintf(buffer, "obuf"); break;
+ case 6: sprintf(buffer, "pdr"); break;
+ case 7: buffer[0] = 0; break;
+ }
+ }
+ return buffer;
+}
+
+
+static const char *dasm_PI(UINT16 bits, char *buffer)
+{
+ UINT8 p = bits >> 5;
+ UINT8 i = bits & 0x1f;
+
+ if (p)
+ {
+ switch (i)
+ {
+ case 0:
+ case 16: sprintf(buffer, "*%s", regname[p]); break;
+ case 22: sprintf(buffer, "*%s--", regname[p]); break;
+ case 23: sprintf(buffer, "*%s++", regname[p]); break;
+ default: sprintf(buffer, "*%s++%s", regname[p], regname[i]); break;
+ }
+ }
+ else
+ {
+ switch (i)
+ {
+ case 4: sprintf(buffer, "ibuf"); break;
+ case 5: sprintf(buffer, "obuf"); break;
+ case 6: sprintf(buffer, "pdr"); break;
+ case 14: sprintf(buffer, "piop"); break;
+ case 20: sprintf(buffer, "pdr2"); break;
+ case 22: sprintf(buffer, "pir"); break;
+ case 30: sprintf(buffer, "pcw"); break;
+ default: sprintf(buffer, "????"); break;
+ }
+ }
+ return buffer;
+}
+
+
+unsigned dasm_dsp32(char *buffer, unsigned pc, UINT32 op)
+{
+ UINT32 flags = 0;
+
+ switch (op >> 25)
+ {
+ /* DA format 1 */
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ {
+ const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]);
+ const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]);
+ const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]);
+ const char *aM = aMvals[(op >> 26) & 7];
+ UINT8 aN = (op >> 21) & 3;
+ if ((op & 0x7f) == 7)
+ {
+ if (aM[0] == '0')
+ sprintf(buffer, "a%d = %s%s", aN, unarysign[(op >> 24) & 1], Y);
+ else if (aM[0] == '1')
+ sprintf(buffer, "a%d = %s%s %s %s", aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], X);
+ else
+ sprintf(buffer, "a%d = %s%s %s %s * %s", aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], aM, X);
+ }
+ else
+ {
+ if (aM[0] == '0')
+ sprintf(buffer, "%s = a%d = %s%s", Z, aN, unarysign[(op >> 24) & 1], Y);
+ else if (aM[0] == '1')
+ sprintf(buffer, "%s = a%d = %s%s %s %s", Z, aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], X);
+ else
+ sprintf(buffer, "%s = a%d = %s%s %s %s * %s", Z, aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], aM, X);
+ }
+ break;
+ }
+
+ /* DA format 2 */
+ case 0x20: case 0x21: case 0x22: case 0x23:
+ case 0x24: case 0x25: case 0x26: case 0x27:
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ {
+ const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]);
+ const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]);
+ const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]);
+ const char *aM = aMvals[(op >> 26) & 7];
+ UINT8 aN = (op >> 21) & 3;
+
+ if ((op & 0x7f) == 7)
+ {
+ if (aM[0] == '0')
+ sprintf(buffer, "a%d = %s%s * %s", aN, unarysign[(op >> 23) & 1], Y, X);
+ else
+ sprintf(buffer, "a%d = %s%s %s %s * %s", aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Y, X);
+ }
+ else
+ {
+ if (aM[0] == '0')
+ sprintf(buffer, "a%d = %s(%s=%s) * %s", aN, unarysign[(op >> 23) & 1], Z, Y, X);
+ else
+ sprintf(buffer, "a%d = %s%s %s (%s=%s) * %s", aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Z, Y, X);
+ }
+ break;
+ }
+
+ /* DA format 3 */
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b:
+ {
+ const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]);
+ const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]);
+ const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]);
+ const char *aM = aMvals[(op >> 26) & 7];
+ UINT8 aN = (op >> 21) & 3;
+
+ if ((op & 0x7f) == 7)
+ {
+ if (aM[0] == '0')
+ sprintf(buffer, "a%d = %s%s * %s", aN, unarysign[(op >> 23) & 1], Y, X);
+ else
+ sprintf(buffer, "a%d = %s%s %s %s * %s", aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Y, X);
+ }
+ else
+ {
+ if (aM[0] == '0')
+ sprintf(buffer, "%s = a%d = %s%s * %s", Z, aN, unarysign[(op >> 23) & 1], Y, X);
+ else
+ sprintf(buffer, "%s = a%d = %s%s %s %s * %s", Z, aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Y, X);
+ }
+ break;
+ }
+
+ /* DA format 4 */
+ case 0x1c: case 0x1d:
+ {
+ const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]);
+ const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]);
+ const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]);
+ UINT8 aN = (op >> 21) & 3;
+
+ if ((op & 0x7f) == 7)
+ sprintf(buffer, "a%d = %s%s %s %s", aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], X);
+ else
+ sprintf(buffer, "a%d = %s(%s=%s) %s %s", aN, unarysign[(op >> 24) & 1], Z, Y, sign[(op >> 23) & 1], X);
+ break;
+ }
+
+ /* DA format 5 */
+ case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ if ((op & 0x7f) == 7)
+ sprintf(buffer, "a%d = %s(%s)",
+ (op >> 21) & 3, // aN
+ functable[(op >> 23) & 15], // G
+ dasm_XYZ((op >> 7) & 0x7f, tempbuf[0])); // Y
+ else
+ sprintf(buffer, "%s = a%d = %s(%s)",
+ dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]), // Z
+ (op >> 21) & 3, // aN
+ functable[(op >> 23) & 15], // G
+ dasm_XYZ((op >> 7) & 0x7f, tempbuf[0])); // Y
+ break;
+
+ /* CA formats 0/1 */
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ {
+ const char *rH = regname[(op >> 16) & 0x1f];
+ UINT8 C = (op >> 21) & 0x3f;
+ INT16 N = (INT16)op;
+
+ if (op == 0)
+ sprintf(buffer, "nop");
+ else if (C == 1 && N == 0 && ((op >> 16) & 0x1f) == 0x1e)
+ sprintf(buffer, "ireturn");
+ else if (C == 1)
+ {
+ if (((op >> 16) & 0x1f) == 15)
+ sprintf(buffer, "goto %s%s [%x]", rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff);
+ else if (N && rH[0] != '0')
+ sprintf(buffer, "goto %s%s", rH, signed_16bit_sep_nospace(N));
+ else if (N)
+ sprintf(buffer, "goto $%x", ((INT32)N & 0xffffff));
+ else
+ {
+ if (((op >> 16) & 0x1f) == 20)
+ flags = DASMFLAG_STEP_OUT;
+ sprintf(buffer, "goto %s", rH);
+ }
+ }
+ else
+ {
+ if (((op >> 16) & 0x1f) == 15)
+ sprintf(buffer, "if (%s) goto %s%s [%x]", condtable[C], rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff);
+ else if (N && rH[0] != '0')
+ sprintf(buffer, "if (%s) goto %s%s", condtable[C], rH, signed_16bit_sep_nospace(N));
+ else if (N)
+ sprintf(buffer, "if (%s) goto $%x", condtable[C], ((INT32)N & 0xffffff));
+ else
+ {
+ if (((op >> 16) & 0x1f) == 20)
+ flags = DASMFLAG_STEP_OUT;
+ sprintf(buffer, "if (%s) goto %s", condtable[C], rH);
+ }
+ }
+ break;
+ }
+
+ /* CA format 3a */
+ case 0x06: case 0x07:
+ {
+ const char *rH = regname[(op >> 16) & 0x1f];
+ const char *rM = regname[(op >> 21) & 0x1f];
+ INT16 N = (INT16)op;
+
+ if (((op >> 16) & 0x1f) == 15)
+ {
+ sprintf(buffer, "if (%s-- >= 0) goto %s%s [%x]", rM, rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff);
+ if (((pc + 8 + N) & 0xffffff) < pc)
+ flags = DASMFLAG_STEP_OVER;
+ }
+ else if (N && rH[0] != '0')
+ sprintf(buffer, "if (%s-- >= 0) goto %s%s", rM, rH, signed_16bit_sep_nospace(N));
+ else if (N)
+ {
+ sprintf(buffer, "if (%s-- >= 0) goto $%x", rM, ((INT32)N & 0xffffff));
+ if (((INT32)N & 0xffffff) < pc)
+ flags = DASMFLAG_STEP_OVER;
+ }
+ else
+ {
+ sprintf(buffer, "if (%s-- >= 0) goto %s", rM, rH);
+ if (((op >> 16) & 0x1f) == 20)
+ flags = DASMFLAG_STEP_OUT;
+ }
+ break;
+ }
+
+ /* CA format 3b/3c */
+ case 0x46:
+ if (((op >> 21) & 0x1f) == 0)
+ sprintf(buffer, "do %d,%d", (op >> 16) & 0x1f, op & 0x7ff);
+ else if (((op >> 21) & 0x1f) == 1)
+ sprintf(buffer, "do %d,%s", (op >> 16) & 0x1f, regname[op & 0x1f]);
+ break;
+
+ /* CA format 4 */
+ case 0x08: case 0x09:
+ {
+ const char *rH = regname[(op >> 16) & 0x1f];
+ const char *rM = regname[(op >> 21) & 0x1f];
+ INT16 N = (INT16)op;
+
+ if (((op >> 16) & 0x1f) == 15)
+ sprintf(buffer, "call %s%s (%s) [%x]", rH, signed_16bit_sep_nospace(N), rM, (pc + 8 + N) & 0xffffff);
+ else if (N && rH[0] != '0')
+ sprintf(buffer, "call %s%s (%s)", rH, signed_16bit_sep_nospace(N), rM);
+ else if (N)
+ sprintf(buffer, "call $%x (%s)", ((INT32)N & 0xffffff), rM);
+ else
+ sprintf(buffer, "call %s (%s)", rH, rM);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ break;
+ }
+
+ /* CA format 5a/5b */
+ case 0x0a: case 0x0b:
+ case 0x4a: case 0x4b:
+ {
+ const char *rD = regname[(op >> 21) & 0x1f];
+ const char *rH = regname[(op >> 16) & 0x1f];
+ const char *s = sizesuffix[(op >> 31) & 1];
+ INT16 N = (INT16)op;
+ if (N == 0)
+ sprintf(buffer, "%s%s = %s%s", rD, s, rH, s);
+ else if (rH[0] == '0')
+ sprintf(buffer, "%s%s = %s", rD, s, signed_16bit_unary(N));
+ else
+ sprintf(buffer, "%s%s = %s%s%s", rD, s, rH, s, signed_16bit_sep((INT16)op));
+ break;
+ }
+
+ /* CA format 6a/6b */
+ case 0x0c: case 0x4c:
+ {
+ const char *rD = regname[(op >> 16) & 0x1f];
+ const char *rS1 = regname[(op >> 5) & 0x1f];
+ const char *rS2 = regname[(op >> 0) & 0x1f];
+ const char *s = sizesuffix[(op >> 31) & 1];
+ UINT8 threeop = (op >> 11) & 1;
+ char condbuf[40] = { 0 };
+
+ if ((op >> 10) & 1)
+ sprintf(condbuf, "if (%s) ", condtable[(op >> 12) & 15]);
+
+ switch ((op >> 21) & 15)
+ {
+ /* add */
+ case 0:
+ if (threeop)
+ {
+ if (rS1[0] == '0' && rS2[0] == '0')
+ sprintf(buffer, "%s%s%s = 0", condbuf, rD, s);
+ else if (rS1[0] == '0')
+ sprintf(buffer, "%s%s%s = %s%s", condbuf, rD, s, rS2, s);
+ else if (rS2[0] == '0')
+ sprintf(buffer, "%s%s%s = %s%s", condbuf, rD, s, rS1, s);
+ else
+ sprintf(buffer, "%s%s%s = %s%s + %s%s", condbuf, rD, s, rS2, s, rS1, s);
+ }
+ else
+ {
+ if (rS1[0] == '0')
+ sprintf(buffer, "%s%s%s = %s%s", condbuf, rD, s, rD, s);
+ else
+ sprintf(buffer, "%s%s%s = %s%s + %s%s", condbuf, rD, s, rD, s, rS1, s);
+ }
+ break;
+
+ case 1:
+ sprintf(buffer, "%s%s%s = %s%s * 2", condbuf, rD, s, rS1, s);
+ break;
+
+ case 2:
+ if (threeop)
+ sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rS1, s, rS2, s);
+ else
+ sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rS1, s, rD, s);
+ break;
+
+ case 3:
+ if (threeop)
+ sprintf(buffer, "%s%s%s = %s%s # %s%s", condbuf, rD, s, rS2, s, rS1, s);
+ else
+ sprintf(buffer, "%s%s%s = %s%s # %s%s", condbuf, rD, s, rD, s, rS1, s);
+ break;
+
+ case 4:
+ if (threeop)
+ sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rS2, s, rS1, s);
+ else
+ sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rD, s, rS1, s);
+ break;
+
+ case 5:
+ sprintf(buffer, "%s%s%s = -%s%s", condbuf, rD, s, rS1, s);
+ break;
+
+ case 6:
+ if (threeop)
+ sprintf(buffer, "%s%s%s = %s%s &~ %s%s", condbuf, rD, s, rS2, s, rS1, s);
+ else
+ sprintf(buffer, "%s%s%s = %s%s &~ %s%s", condbuf, rD, s, rD, s, rS1, s);
+ break;
+
+ case 7:
+// if (threeop)
+// sprintf(buffer, "%s%s%s - %s%s", condbuf, rS2, s, rS1, s);
+// else
+ sprintf(buffer, "%s%s%s - %s%s", condbuf, rD, s, rS1, s);
+ break;
+
+ case 8:
+ if (threeop)
+ sprintf(buffer, "%s%s%s = %s%s ^ %s%s", condbuf, rD, s, rS2, s, rS1, s);
+ else
+ sprintf(buffer, "%s%s%s = %s%s ^ %s%s", condbuf, rD, s, rD, s, rS1, s);
+ break;
+
+ case 9:
+ sprintf(buffer, "%s%s%s = %s%s >>> 1", condbuf, rD, s, rS1, s);
+ break;
+
+ case 10:
+ if (threeop)
+ sprintf(buffer, "%s%s%s = %s%s | %s%s", condbuf, rD, s, rS2, s, rS1, s);
+ else
+ sprintf(buffer, "%s%s%s = %s%s | %s%s", condbuf, rD, s, rD, s, rS1, s);
+ break;
+
+ case 11:
+ sprintf(buffer, "%s%s%s = %s%s <<< 1", condbuf, rD, s, rS1, s);
+ break;
+
+ case 12:
+ sprintf(buffer, "%s%s%s = %s%s >> 1", condbuf, rD, s, rS1, s);
+ break;
+
+ case 13:
+ sprintf(buffer, "%s%s%s = %s%s / 2", condbuf, rD, s, rS1, s);
+ break;
+
+ case 14:
+ if (threeop)
+ sprintf(buffer, "%s%s%s = %s%s & %s%s", condbuf, rD, s, rS2, s, rS1, s);
+ else
+ sprintf(buffer, "%s%s%s = %s%s & %s%s", condbuf, rD, s, rD, s, rS1, s);
+ break;
+
+ case 15:
+// if (threeop)
+// sprintf(buffer, "%s%s%s & %s%s", condbuf, rS1, s, rS2, s);
+// else
+ sprintf(buffer, "%s%s%s & %s%s", condbuf, rD, s, rS1, s);
+ break;
+ }
+ break;
+ }
+
+ /* CA format 6c/6d */
+ case 0x0d: case 0x4d:
+ {
+ const char *rD = regname[(op >> 16) & 0x1f];
+ const char *s = sizesuffix[(op >> 31) & 1];
+ INT16 N = (INT16)op;
+
+ switch ((op >> 21) & 15)
+ {
+ case 0:
+ case 1:
+ case 5:
+ case 9:
+ case 11:
+ case 12:
+ case 13:
+ sprintf(buffer, "Unexpected: %08X", op);
+ break;
+
+ case 2:
+ sprintf(buffer, "%s%s = %s - %s%s", rD, s, signed_16bit_unary(N), rD, s);
+ break;
+
+ case 3:
+ sprintf(buffer, "%s%s = %s%s # %s", rD, s, rD, s, signed_16bit_unary(N));
+ break;
+
+ case 4:
+ sprintf(buffer, "%s%s = %s%s - %s", rD, s, rD, s, signed_16bit_unary(N));
+ break;
+
+ case 6:
+ sprintf(buffer, "%s%s = %s%s &~ %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1));
+ break;
+
+ case 7:
+ sprintf(buffer, "%s%s - %s", rD, s, signed_16bit_unary(N));
+ break;
+
+ case 8:
+ sprintf(buffer, "%s%s = %s%s ^ %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1));
+ break;
+
+ case 10:
+ sprintf(buffer, "%s%s = %s%s | %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1));
+ break;
+
+ case 14:
+ sprintf(buffer, "%s%s = %s%s & %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1));
+ break;
+
+ case 15:
+ sprintf(buffer, "%s%s & %s", rD, s, unsigned_16bit_size(N, (op >> 31) & 1));
+ break;
+ }
+ break;
+ }
+
+ /* CA format 7a */
+ case 0x0e:
+ if ((op >> 24) & 1)
+ sprintf(buffer, "*%08X = %s%s", (INT16)op, regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3]);
+ else
+ sprintf(buffer, "%s%s = *%08X", regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3], (INT16)op);
+ break;
+
+ /* CA format 7b */
+ case 0x0f:
+ if ((op >> 24) & 1)
+ sprintf(buffer, "%s = %s%s", dasm_PI(op & 0x3ff, tempbuf[0]), regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3]);
+ else
+ sprintf(buffer, "%s%s = %s", regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3], dasm_PI(op & 0x3ff, tempbuf[0]));
+ break;
+
+ /* CA format 8a */
+ case 0x50: case 0x51: case 0x52: case 0x53:
+ case 0x54: case 0x55: case 0x56: case 0x57:
+ case 0x58: case 0x59: case 0x5a: case 0x5b:
+ case 0x5c: case 0x5d: case 0x5e: case 0x5f:
+ {
+ INT32 N = (op & 0xffff) | ((INT32)((op & 0x1fe00000) << 3) >> 8);
+ const char *rH = regname[(op >> 16) & 0x1f];
+
+ if (((op >> 16) & 0x1f) == 15)
+ sprintf(buffer, "goto %s%s [%x]", rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff);
+ else if (N && rH[0] != '0')
+ sprintf(buffer, "goto %s%s", rH, signed_16bit_sep_nospace(N));
+ else if (N)
+ sprintf(buffer, "goto $%x", ((INT32)N & 0xffffff));
+ else
+ {
+ if (((op >> 16) & 0x1f) == 20)
+ flags = DASMFLAG_STEP_OUT;
+ sprintf(buffer, "goto %s", rH);
+ }
+ break;
+ }
+
+ /* CA format 8b */
+ case 0x60: case 0x61: case 0x62: case 0x63:
+ case 0x64: case 0x65: case 0x66: case 0x67:
+ case 0x68: case 0x69: case 0x6a: case 0x6b:
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+ {
+ INT32 immed = (op & 0xffff) | ((INT32)((op & 0x1fe00000) << 3) >> 8);
+ sprintf(buffer, "%s = $%x", regnamee[(op >> 16) & 0x1f], immed & 0xffffff);
+ break;
+ }
+
+ /* CA format 8c */
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b:
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+ {
+ INT32 N = (op & 0xffff) | ((INT32)((op & 0x1fe00000) << 3) >> 8);
+ const char *rM = regname[(op >> 16) & 0x1f];
+ sprintf(buffer, "call $%x (%s)", N & 0xffffff, rM);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ break;
+ }
+ }
+
+ return 4 | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/dsp32/dsp32ops.c b/src/emu/cpu/dsp32/dsp32ops.c
new file mode 100644
index 00000000000..fce00795ccb
--- /dev/null
+++ b/src/emu/cpu/dsp32/dsp32ops.c
@@ -0,0 +1,2898 @@
+/***************************************************************************
+
+ dsp32ops.c
+ Core implementation for the portable DSP32 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+
+
+/***************************************************************************
+ COMPILE-TIME OPTIONS
+***************************************************************************/
+
+/* these defined latencies are a pain to implement, but are necessary */
+#define EMULATE_MEMORY_LATENCY (1)
+#define EMULATE_MULTIPLIER_LATENCY (1)
+#define EMULATE_AFLAGS_LATENCY (1)
+
+/* these optimizations should have some effect, but they don't really, so */
+/* leave them off */
+#define IGNORE_DAU_UV_FLAGS (0)
+#define ASSUME_WRITEABLE (0)
+#define ASSUME_UNCONDITIONAL_CAU (0)
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define SET_V_16(a,b,r) dsp32.vflags = (((a) ^ (b) ^ (r) ^ ((r) >> 1)) << 8)
+#define SET_NZC_16(r) dsp32.nzcflags = ((r) << 8)
+#define SET_NZCV_16(a,b,r) SET_NZC_16(r); SET_V_16(a,b,r)
+#define SET_NZ00_16(r) dsp32.nzcflags = (((r) << 8) & 0xffffff); dsp32.vflags = 0
+
+#define SET_V_24(a,b,r) dsp32.vflags = ((a) ^ (b) ^ (r) ^ ((r) >> 1))
+#define SET_NZC_24(r) dsp32.nzcflags = (r)
+#define SET_NZCV_24(a,b,r) SET_NZC_24(r); SET_V_24(a,b,r)
+#define SET_NZ00_24(r) dsp32.nzcflags = ((r) & 0xffffff); dsp32.vflags = 0
+
+#define TRUNCATE24(a) ((a) & 0xffffff)
+#define EXTEND16_TO_24(a) TRUNCATE24((INT32)(INT16)(a))
+#define REG16(a) ((UINT16)dsp32.r[a])
+#define REG24(a) (dsp32.r[a])
+
+#define WRITEABLE_REGS (0x6f3efffe)
+#if ASSUME_WRITEABLE
+#define IS_WRITEABLE(r) (1)
+#else
+#define IS_WRITEABLE(r) (WRITEABLE_REGS & (1 << (r)))
+#endif
+
+#if ASSUME_UNCONDITIONAL_CAU
+#define CONDITION_IS_TRUE (1)
+#else
+#define CONDITION_IS_TRUE (!(OP & 0x400) || (condition((OP >> 12) & 15)))
+#endif
+
+#if EMULATE_MEMORY_LATENCY
+#define WWORD_DEFERRED(a,v) do { int bufidx = dsp32.mbuf_index & 3; dsp32.mbufaddr[bufidx] = -(a); dsp32.mbufdata[bufidx] = (v); } while (0)
+#define WLONG_DEFERRED(a,v) do { int bufidx = dsp32.mbuf_index & 3; dsp32.mbufaddr[bufidx] = (a); dsp32.mbufdata[bufidx] = (v); } while (0)
+#define PROCESS_DEFERRED_MEMORY() \
+ if (dsp32.mbufaddr[++dsp32.mbuf_index & 3] != 1) \
+ { \
+ int bufidx = dsp32.mbuf_index & 3; \
+ if (dsp32.mbufaddr[bufidx] >= 0) \
+ WLONG(dsp32.mbufaddr[bufidx], dsp32.mbufdata[bufidx]); \
+ else \
+ WWORD(-dsp32.mbufaddr[bufidx], dsp32.mbufdata[bufidx]); \
+ dsp32.mbufaddr[bufidx] = 1; \
+ }
+#else
+#define WWORD_DEFERRED(a,v) WWORD(a,v)
+#define WLONG_DEFERRED(a,v) WLONG(a,v)
+#define PROCESS_DEFERRED_MEMORY()
+#endif
+
+#if EMULATE_MULTIPLIER_LATENCY
+#define DEFERRED_MULTIPLIER(x) dau_get_amult(x)
+#else
+#define DEFERRED_MULTIPLIER(x) dsp32.a[x]
+#endif
+
+#if EMULATE_AFLAGS_LATENCY
+#define DEFERRED_NZFLAGS dau_get_anzflags()
+#define DEFERRED_VUFLAGS dau_get_avuflags()
+#else
+#define DEFERRED_NZFLAGS dsp32.NZflags
+#define DEFERRED_VUFLAGS dsp32.VUflags
+#endif
+
+
+
+/***************************************************************************
+ FORWARD DECLARATIONS
+***************************************************************************/
+
+extern void (*dsp32ops[])(void);
+
+
+
+/***************************************************************************
+ TYPEDEFS
+***************************************************************************/
+
+typedef union int_double
+{
+ double d;
+ UINT32 i[2];
+} int_double;
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static void illegal(void)
+{
+}
+
+
+static void unimplemented(void)
+{
+ fatalerror("Unimplemented op @ %06X: %08X (dis=%02X, tbl=%03X)", dsp32.PC - 4, OP, OP >> 25, OP >> 21);
+}
+
+
+INLINE void execute_one(void)
+{
+ PROCESS_DEFERRED_MEMORY();
+ CALL_MAME_DEBUG;
+ OP = ROPCODE(dsp32.PC);
+ dsp32_icount -= 4; /* 4 clocks per cycle */
+ dsp32.PC += 4;
+ if (OP)
+ (*dsp32ops[OP >> 21])();
+}
+
+
+
+/***************************************************************************
+ CAU HELPERS
+***************************************************************************/
+
+static UINT32 cau_read_pi_special(UINT8 i)
+{
+ switch (i)
+ {
+ case 4: return dsp32.ibuf;
+ case 5: return dsp32.obuf;
+ case 6: update_pcr(dsp32.pcr & ~PCR_PDFs); return dsp32.pdr;
+ case 14: return dsp32.piop;
+ case 20: return dsp32.pdr2;
+ case 22: update_pcr(dsp32.pcr & ~PCR_PIFs); return dsp32.pir;
+ case 30: return dsp32.pcw;
+ default: fprintf(stderr, "Unimplemented CAU PI read = %X\n", i);
+ }
+ return 0;
+}
+
+
+static void cau_write_pi_special(UINT8 i, UINT32 val)
+{
+ switch (i)
+ {
+ case 4: dsp32.ibuf = val; break;
+ case 5: dsp32.obuf = val; break;
+ case 6: dsp32.pdr = val; update_pcr(dsp32.pcr | PCR_PDFs); break;
+ case 14: dsp32.piop = val; break;
+ case 20: dsp32.pdr2 = val; break;
+ case 22: dsp32.pir = val; update_pcr(dsp32.pcr | PCR_PIFs); break;
+ case 30: dsp32.pcw = val; break;
+ default: fprintf(stderr, "Unimplemented CAU PI write = %X\n", i);
+ }
+}
+
+
+INLINE UINT8 cau_read_pi_1byte(int pi)
+{
+ int p = (pi >> 5) & 0x1f;
+ int i = (pi >> 0) & 0x1f;
+ if (p)
+ {
+ UINT32 result = RBYTE(dsp32.r[p]);
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i]);
+ return result;
+ }
+ else
+ return cau_read_pi_special(i);
+}
+
+
+INLINE UINT16 cau_read_pi_2byte(int pi)
+{
+ int p = (pi >> 5) & 0x1f;
+ int i = (pi >> 0) & 0x1f;
+ if (p)
+ {
+ UINT32 result = RWORD(dsp32.r[p]);
+ if (i < 22 || i > 23)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i] * 2);
+ return result;
+ }
+ else
+ return cau_read_pi_special(i);
+}
+
+
+INLINE UINT32 cau_read_pi_4byte(int pi)
+{
+ int p = (pi >> 5) & 0x1f;
+ int i = (pi >> 0) & 0x1f;
+ if (p)
+ {
+ UINT32 result = RLONG(dsp32.r[p]);
+ if (i < 22 || i > 23)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i] * 4);
+ return result;
+ }
+ else
+ return cau_read_pi_special(i);
+}
+
+
+INLINE void cau_write_pi_1byte(int pi, UINT8 val)
+{
+ int p = (pi >> 5) & 0x1f;
+ int i = (pi >> 0) & 0x1f;
+ if (p)
+ {
+ WBYTE(dsp32.r[p], val);
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i]);
+ }
+ else
+ cau_write_pi_special(i, val);
+}
+
+
+INLINE void cau_write_pi_2byte(int pi, UINT16 val)
+{
+ int p = (pi >> 5) & 0x1f;
+ int i = (pi >> 0) & 0x1f;
+ if (p)
+ {
+ WWORD(dsp32.r[p], val);
+ if (i < 22 || i > 23)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i] * 2);
+ }
+ else
+ cau_write_pi_special(i, val);
+}
+
+
+INLINE void cau_write_pi_4byte(int pi, UINT32 val)
+{
+ int p = (pi >> 5) & 0x1f;
+ int i = (pi >> 0) & 0x1f;
+ if (p)
+ {
+ WLONG(dsp32.r[p], (INT32)(val << 8) >> 8);
+ if (i < 22 || i > 23)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i] * 4);
+ }
+ else
+ cau_write_pi_special(i, val);
+}
+
+
+
+/***************************************************************************
+ DAU HELPERS
+***************************************************************************/
+
+INLINE double dau_get_amult(int aidx)
+{
+ int bufidx = (dsp32.abuf_index - 1) & 3;
+ double val = dsp32.a[aidx];
+ while (dsp32_icount >= dsp32.abufcycle[bufidx] - 2 * 4)
+ {
+ if (dsp32.abufreg[bufidx] == aidx)
+ val = dsp32.abuf[bufidx];
+ bufidx = (bufidx - 1) & 3;
+ }
+ return val;
+}
+
+
+INLINE double dau_get_anzflags(void)
+{
+ int bufidx = (dsp32.abuf_index - 1) & 3;
+ double nzflags = dsp32.NZflags;
+ while (dsp32_icount >= dsp32.abufcycle[bufidx] - 3 * 4)
+ {
+ nzflags = dsp32.abufNZflags[bufidx];
+ bufidx = (bufidx - 1) & 3;
+ }
+ return nzflags;
+}
+
+
+INLINE UINT8 dau_get_avuflags(void)
+{
+#if (!IGNORE_DAU_UV_FLAGS)
+ int bufidx = (dsp32.abuf_index - 1) & 3;
+ UINT8 vuflags = dsp32.VUflags;
+ while (dsp32_icount >= dsp32.abufcycle[bufidx] - 3 * 4)
+ {
+ vuflags = dsp32.abufVUflags[bufidx];
+ bufidx = (bufidx - 1) & 3;
+ }
+ return vuflags;
+#else
+ return 0;
+#endif
+}
+
+
+INLINE void remember_last_dau(int aidx)
+{
+#if (EMULATE_MULTIPLIER_LATENCY || EMULATE_AFLAGS_LATENCY)
+ int bufidx = dsp32.abuf_index++ & 3;
+ dsp32.abuf[bufidx] = dsp32.a[aidx];
+ dsp32.abufreg[bufidx] = aidx;
+ dsp32.abufNZflags[bufidx] = dsp32.NZflags;
+#if (!IGNORE_DAU_UV_FLAGS)
+ dsp32.abufVUflags[bufidx] = dsp32.VUflags;
+#endif
+ dsp32.abufcycle[bufidx] = dsp32_icount;
+#endif
+}
+
+
+INLINE void dau_set_val_noflags(int aidx, double res)
+{
+ remember_last_dau(aidx);
+ dsp32.a[aidx] = res;
+}
+
+
+INLINE void dau_set_val_flags(int aidx, double res)
+{
+ remember_last_dau(aidx);
+#if (!IGNORE_DAU_UV_FLAGS)
+{
+ double absres = (res < 0) ? -res : res;
+ dsp32.VUflags = 0;
+ if (absres < 5.87747e-39)
+ {
+ if (absres != 0)
+ dsp32.VUflags = UFLAGBIT;
+ res = 0.0;
+ }
+ else if (absres > 3.40282e38)
+ {
+ dsp32.VUflags = VFLAGBIT;
+// DEBUGGER_BREAK;
+// fprintf(stderr, "Result = %g\n", absres);
+ res = (res < 0) ? -3.40282e38 : 3.40282e38;
+ }
+}
+#endif
+ dsp32.NZflags = res;
+ dsp32.a[aidx] = res;
+}
+
+
+INLINE double dsp_to_double(UINT32 val)
+{
+ int_double id;
+
+ if (val == 0)
+ return 0;
+ else if ((INT32)val > 0)
+ {
+ int exponent = ((val & 0xff) - 128 + 1023) << 20;
+ id.i[BYTE_XOR_BE(0)] = exponent + (val >> 11);
+ id.i[BYTE_XOR_BE(1)] = (val << 21) & 0xe0000000;
+ }
+ else
+ {
+ int exponent = ((val & 0xff) - 128 + 1023) << 20;
+ val = -(val & 0xffffff00);
+ id.i[BYTE_XOR_BE(0)] = 0x80000000 + exponent + ((val >> 11) & 0x001fffff);
+ id.i[BYTE_XOR_BE(1)] = (val << 21) & 0xe0000000;
+ }
+ return id.d;
+}
+
+
+INLINE UINT32 double_to_dsp(double val)
+{
+ int mantissa, exponent;
+ int_double id;
+ id.d = val;
+ mantissa = ((id.i[BYTE_XOR_BE(0)] & 0x000fffff) << 11) | ((id.i[BYTE_XOR_BE(1)] & 0xe0000000) >> 21);
+ exponent = ((id.i[BYTE_XOR_BE(0)] & 0x7ff00000) >> 20) - 1023 + 128;
+ if (exponent < 0)
+ return 0x00000000;
+ else if (exponent > 255)
+ {
+// DEBUGGER_BREAK;
+// fprintf(stderr, "Exponent = %d\n", exponent);
+ return ((INT32)id.i[BYTE_XOR_BE(0)] >= 0) ? 0x7fffffff : 0x800000ff;
+ }
+ else if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0)
+ return exponent | mantissa;
+ else
+ {
+ mantissa = -mantissa;
+ if (mantissa == 0) { mantissa = 0x80000000; exponent--; }
+ return 0x80000000 | exponent | (mantissa & 0xffffff00);
+ }
+}
+
+
+static double dau_read_pi_special(int i)
+{
+ fatalerror("Unimplemented dau_read_pi_special(%d)", i);
+ return 0;
+}
+
+
+static void dau_write_pi_special(int i, double val)
+{
+ fatalerror("Unimplemented dau_write_pi_special(%d)", i);
+}
+
+
+static int lastp;
+
+INLINE double dau_read_pi_double_1st(int pi, int multiplier)
+{
+ int p = (pi >> 3) & 15;
+ int i = (pi >> 0) & 7;
+
+ lastp = p;
+ if (p)
+ {
+ UINT32 result = RLONG(dsp32.r[p]);
+ if (i < 6)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16] * 4);
+ return dsp_to_double(result);
+ }
+ else if (i < 4)
+ return multiplier ? DEFERRED_MULTIPLIER(i) : dsp32.a[i];
+ else
+ return dau_read_pi_special(i);
+}
+
+
+INLINE double dau_read_pi_double_2nd(int pi, int multiplier, double xval)
+{
+ int p = (pi >> 3) & 15;
+ int i = (pi >> 0) & 7;
+
+ if (p == 15) p = lastp; /* P=15 means Z inherits from Y, Y inherits from X */
+ lastp = p;
+ if (p)
+ {
+ UINT32 result;
+ result = RLONG(dsp32.r[p]);
+ if (i < 6)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16] * 4);
+ return dsp_to_double(result);
+ }
+ else if (i < 4)
+ return multiplier ? DEFERRED_MULTIPLIER(i) : dsp32.a[i];
+ else
+ return dau_read_pi_special(i);
+}
+
+
+INLINE UINT32 dau_read_pi_4bytes(int pi)
+{
+ int p = (pi >> 3) & 15;
+ int i = (pi >> 0) & 7;
+
+ lastp = p;
+ if (p)
+ {
+ UINT32 result = RLONG(dsp32.r[p]);
+ if (i < 6)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16] * 4);
+ return result;
+ }
+ else if (i < 4)
+ return double_to_dsp(dsp32.a[i]);
+ else
+ return dau_read_pi_special(i);
+}
+
+
+INLINE UINT16 dau_read_pi_2bytes(int pi)
+{
+ int p = (pi >> 3) & 15;
+ int i = (pi >> 0) & 7;
+
+ lastp = p;
+ if (p)
+ {
+ UINT32 result = RWORD(dsp32.r[p]);
+ if (i < 6)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16] * 2);
+ return result;
+ }
+ else if (i < 4)
+ return double_to_dsp(dsp32.a[i]);
+ else
+ return dau_read_pi_special(i);
+}
+
+
+INLINE void dau_write_pi_double(int pi, double val)
+{
+ int p = (pi >> 3) & 15;
+ int i = (pi >> 0) & 7;
+
+ if (p == 15) p = lastp; /* P=15 means Z inherits from Y, Y inherits from X */
+ if (p)
+ {
+ WLONG_DEFERRED(dsp32.r[p], double_to_dsp(val));
+ if (i < 6)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16] * 4);
+ }
+ else if (i < 4)
+ dau_set_val_noflags(i, val);
+ else
+ dau_write_pi_special(i, val);
+}
+
+
+INLINE void dau_write_pi_4bytes(int pi, UINT32 val)
+{
+ int p = (pi >> 3) & 15;
+ int i = (pi >> 0) & 7;
+
+ if (p == 15) p = lastp; /* P=15 means Z inherits from Y, Y inherits from X */
+ if (p)
+ {
+ lastp = p;
+ WLONG_DEFERRED(dsp32.r[p], val);
+ if (i < 6)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16] * 4);
+ }
+ else if (i < 4)
+ dau_set_val_noflags(i, dsp_to_double(val));
+ else
+ dau_write_pi_special(i, val);
+}
+
+
+INLINE void dau_write_pi_2bytes(int pi, UINT16 val)
+{
+ int p = (pi >> 3) & 15;
+ int i = (pi >> 0) & 7;
+
+ if (p == 15) p = lastp; /* P=15 means Z inherits from Y, Y inherits from X */
+ if (p)
+ {
+ lastp = p;
+ WWORD_DEFERRED(dsp32.r[p], val);
+ if (i < 6)
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16]);
+ else
+ dsp32.r[p] = TRUNCATE24(dsp32.r[p] + dsp32.r[i+16] * 2);
+ }
+ else if (i < 4)
+ dau_set_val_noflags(i, dsp_to_double(val << 16));
+ else
+ dau_write_pi_special(i, val);
+}
+
+
+
+/***************************************************************************
+ COMMON CONDITION ROUTINE
+***************************************************************************/
+
+#if (!ASSUME_UNCONDITIONAL_CAU)
+static int condition(int cond)
+{
+ switch (cond)
+ {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ return !nFLAG;
+ case 3:
+ return nFLAG;
+ case 4:
+ return !zFLAG;
+ case 5:
+ return zFLAG;
+ case 6:
+ return !vFLAG;
+ case 7:
+ return vFLAG;
+ case 8:
+ return !cFLAG;
+ case 9:
+ return cFLAG;
+ case 10:
+ return !(nFLAG ^ cFLAG);
+ case 11:
+ return (nFLAG ^ cFLAG);
+ case 12:
+ return !(zFLAG | (nFLAG ^ vFLAG));
+ case 13:
+ return (zFLAG | (nFLAG ^ vFLAG));
+ case 14:
+ return !(cFLAG | zFLAG);
+ case 15:
+ return (cFLAG | zFLAG);
+
+ case 16:
+ return !(DEFERRED_VUFLAGS & UFLAGBIT);
+ case 17:
+ return (DEFERRED_VUFLAGS & UFLAGBIT);
+ case 18:
+ return !(DEFERRED_NZFLAGS < 0);
+ case 19:
+ return (DEFERRED_NZFLAGS < 0);
+ case 20:
+ return !(DEFERRED_NZFLAGS == 0);
+ case 21:
+ return (DEFERRED_NZFLAGS == 0);
+ case 22:
+ return !(DEFERRED_VUFLAGS & VFLAGBIT);
+ case 23:
+ return (DEFERRED_VUFLAGS & VFLAGBIT);
+ case 24:
+ return !(DEFERRED_NZFLAGS <= 0);
+ case 25:
+ return (DEFERRED_NZFLAGS <= 0);
+
+ case 32: /* !ibf */
+ case 33: /* ibf */
+ case 34: /* !obe */
+ case 35: /* obe */
+ case 36: /* !pdf */
+ case 37: /* pdf */
+ case 38: /* !pif */
+ case 39: /* pif */
+ case 40: /* !sy */
+ case 41: /* sy */
+ case 42: /* !fb */
+ case 43: /* fb */
+ case 44: /* !ireq1 */
+ case 45: /* ireq1 */
+ case 46: /* !ireq2 */
+ case 47: /* ireq2 */
+ default:
+ fatalerror("Unimplemented condition: %X", cond);
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ CAU BRANCH INSTRUCTION IMPLEMENTATION
+***************************************************************************/
+
+static void nop(void)
+{
+ UINT32 op = OP;
+ if (op == 0)
+ return;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+
+}
+
+
+static void goto_t(void)
+{
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+}
+
+
+static void goto_pl(void)
+{
+ if (!nFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_mi(void)
+{
+ if (nFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_ne(void)
+{
+ if (!zFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_eq(void)
+{
+ if (zFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_vc(void)
+{
+ if (!vFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_vs(void)
+{
+ if (vFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_cc(void)
+{
+ if (!cFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_cs(void)
+{
+ if (cFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_ge(void)
+{
+ if (!(nFLAG ^ vFLAG))
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_lt(void)
+{
+ if (nFLAG ^ vFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_gt(void)
+{
+ if (!(zFLAG | (nFLAG ^ vFLAG)))
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_le(void)
+{
+ if (zFLAG | (nFLAG ^ vFLAG))
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_hi(void)
+{
+ if (!cFLAG && !zFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_ls(void)
+{
+ if (cFLAG || zFLAG)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_auc(void)
+{
+ if (!(DEFERRED_VUFLAGS & UFLAGBIT))
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_aus(void)
+{
+ if (DEFERRED_VUFLAGS & UFLAGBIT)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_age(void)
+{
+ if (DEFERRED_NZFLAGS >= 0)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_alt(void)
+{
+ if (DEFERRED_NZFLAGS < 0)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_ane(void)
+{
+ if (DEFERRED_NZFLAGS != 0)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_aeq(void)
+{
+ if (DEFERRED_NZFLAGS == 0)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_avc(void)
+{
+ if (!(DEFERRED_VUFLAGS & VFLAGBIT))
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_avs(void)
+{
+ if (DEFERRED_VUFLAGS & VFLAGBIT)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_agt(void)
+{
+ if (DEFERRED_NZFLAGS > 0)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_ale(void)
+{
+ if (DEFERRED_NZFLAGS <= 0)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void goto_ibe(void)
+{
+ unimplemented();
+}
+
+
+static void goto_ibf(void)
+{
+ unimplemented();
+}
+
+
+static void goto_obf(void)
+{
+ unimplemented();
+}
+
+
+static void goto_obe(void)
+{
+ unimplemented();
+}
+
+
+static void goto_pde(void)
+{
+ unimplemented();
+}
+
+
+static void goto_pdf(void)
+{
+ unimplemented();
+}
+
+
+static void goto_pie(void)
+{
+ unimplemented();
+}
+
+
+static void goto_pif(void)
+{
+ unimplemented();
+}
+
+
+static void goto_syc(void)
+{
+ unimplemented();
+}
+
+
+static void goto_sys(void)
+{
+ unimplemented();
+}
+
+
+static void goto_fbc(void)
+{
+ unimplemented();
+}
+
+
+static void goto_fbs(void)
+{
+ unimplemented();
+}
+
+
+static void goto_irq1lo(void)
+{
+ unimplemented();
+}
+
+
+static void goto_irq1hi(void)
+{
+ unimplemented();
+}
+
+
+static void goto_irq2lo(void)
+{
+ unimplemented();
+}
+
+
+static void goto_irq2hi(void)
+{
+ unimplemented();
+}
+
+
+static void dec_goto(void)
+{
+ int hr = (OP >> 21) & 0x1f;
+ int old = (INT16)dsp32.r[hr];
+ dsp32.r[hr] = EXTEND16_TO_24(dsp32.r[hr] - 1);
+ if (old >= 0)
+ {
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+ }
+}
+
+
+static void call(void)
+{
+ UINT32 op = OP;
+ int mr = (op >> 21) & 0x1f;
+ if (IS_WRITEABLE(mr))
+ dsp32.r[mr] = dsp32.PC + 4;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op);
+ memory_set_opbase(dsp32.PC);
+}
+
+
+static void goto24(void)
+{
+ UINT32 op = OP;
+ execute_one();
+ dsp32.PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (op & 0xffff) + ((op >> 5) & 0xff0000));
+ memory_set_opbase(dsp32.PC);
+}
+
+
+static void call24(void)
+{
+ UINT32 op = OP;
+ int mr = (op >> 16) & 0x1f;
+ if (IS_WRITEABLE(mr))
+ dsp32.r[mr] = dsp32.PC + 4;
+ execute_one();
+ dsp32.PC = (op & 0xffff) + ((op >> 5) & 0xff0000);
+ memory_set_opbase(dsp32.PC);
+}
+
+
+static void do_i(void)
+{
+ unimplemented();
+}
+
+
+static void do_r(void)
+{
+ unimplemented();
+}
+
+
+
+/***************************************************************************
+ CAU 16-BIT ARITHMETIC IMPLEMENTATION
+***************************************************************************/
+
+static void add_si(void)
+{
+ int dr = (OP >> 21) & 0x1f;
+ int hrval = REG16((OP >> 16) & 0x1f);
+ int res = hrval + (UINT16)OP;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZCV_16(hrval, OP, res);
+}
+
+
+static void add_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG16((OP >> 0) & 0x1f) : REG16(dr);
+ int res = s2rval + s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZCV_16(s1rval, s2rval, res);
+ }
+}
+
+
+static void mul2_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int res = s1rval * 2;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZCV_16(s1rval, 0, res);
+ }
+}
+
+
+static void subr_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG16((OP >> 0) & 0x1f) : REG16(dr);
+ int res = s1rval - s2rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZCV_16(s1rval, s2rval, res);
+ }
+}
+
+
+static void addr_ss(void)
+{
+ unimplemented();
+}
+
+
+static void sub_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG16((OP >> 0) & 0x1f) : REG16(dr);
+ int res = s2rval - s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZCV_16(s1rval, s2rval, res);
+ }
+}
+
+
+static void neg_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int res = -s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZCV_16(s1rval, 0, res);
+ }
+}
+
+
+static void andc_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG16((OP >> 0) & 0x1f) : REG16(dr);
+ int res = s2rval & ~s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZ00_16(res);
+ }
+}
+
+
+static void cmp_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int drval = REG16((OP >> 16) & 0x1f);
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int res = drval - s1rval;
+ SET_NZCV_16(drval, s1rval, res);
+ }
+}
+
+
+static void xor_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG16((OP >> 0) & 0x1f) : REG16(dr);
+ int res = s2rval ^ s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZ00_16(res);
+ }
+}
+
+
+static void rcr_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int res = ((dsp32.nzcflags >> 9) & 0x8000) | (s1rval >> 1);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ dsp32.nzcflags = ((res & 0xffff) << 8) | ((s1rval & 1) << 24);
+ dsp32.vflags = 0;
+ }
+}
+
+
+static void or_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG16((OP >> 0) & 0x1f) : REG16(dr);
+ int res = s2rval | s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZ00_16(res);
+ }
+}
+
+
+static void rcl_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int res = ((dsp32.nzcflags >> 24) & 0x0001) | (s1rval << 1);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ dsp32.nzcflags = ((res & 0xffff) << 8) | ((s1rval & 0x8000) << 9);
+ dsp32.vflags = 0;
+ }
+}
+
+
+static void shr_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int res = s1rval >> 1;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ dsp32.nzcflags = ((res & 0xffff) << 8) | ((s1rval & 1) << 24);
+ dsp32.vflags = 0;
+ }
+}
+
+
+static void div2_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int res = (s1rval & 0x8000) | (s1rval >> 1);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ dsp32.nzcflags = ((res & 0xffff) << 8) | ((s1rval & 1) << 24);
+ dsp32.vflags = 0;
+ }
+}
+
+
+static void and_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG16((OP >> 0) & 0x1f) : REG16(dr);
+ int res = s2rval & s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZ00_16(res);
+ }
+}
+
+
+static void test_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int drval = REG16((OP >> 16) & 0x1f);
+ int s1rval = REG16((OP >> 5) & 0x1f);
+ int res = drval & s1rval;
+ SET_NZ00_16(res);
+ }
+}
+
+
+static void add_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG16(dr);
+ int res = drval + (UINT16)OP;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZCV_16(drval, OP, res);
+}
+
+
+static void subr_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG16(dr);
+ int res = (UINT16)OP - drval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZCV_16(drval, OP, res);
+}
+
+
+static void addr_di(void)
+{
+ unimplemented();
+}
+
+
+static void sub_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG16(dr);
+ int res = drval - (UINT16)OP;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZCV_16(drval, OP, res);
+}
+
+
+static void andc_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG16(dr);
+ int res = drval & ~(UINT16)OP;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZ00_16(res);
+}
+
+
+static void cmp_di(void)
+{
+ int drval = REG16((OP >> 16) & 0x1f);
+ int res = drval - (UINT16)OP;
+ SET_NZCV_16(drval, OP, res);
+}
+
+
+static void xor_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG16(dr);
+ int res = drval ^ (UINT16)OP;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZ00_16(res);
+}
+
+
+static void or_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG16(dr);
+ int res = drval | (UINT16)OP;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZ00_16(res);
+}
+
+
+static void and_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG16(dr);
+ int res = drval & (UINT16)OP;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ SET_NZ00_16(res);
+}
+
+
+static void test_di(void)
+{
+ int drval = REG16((OP >> 16) & 0x1f);
+ int res = drval & (UINT16)OP;
+ SET_NZ00_16(res);
+}
+
+
+
+/***************************************************************************
+ CAU 24-BIT ARITHMETIC IMPLEMENTATION
+***************************************************************************/
+
+static void adde_si(void)
+{
+ int dr = (OP >> 21) & 0x1f;
+ int hrval = REG24((OP >> 16) & 0x1f);
+ int res = hrval + EXTEND16_TO_24(OP);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ SET_NZCV_24(hrval, OP << 8, res);
+}
+
+
+static void adde_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG24((OP >> 0) & 0x1f) : REG24(dr);
+ int res = s2rval + s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ SET_NZCV_24(s1rval, s2rval, res);
+ }
+}
+
+
+static void mul2e_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int res = s1rval * 2;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ SET_NZCV_24(s1rval, 0, res);
+ }
+}
+
+
+static void subre_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG24((OP >> 0) & 0x1f) : REG24(dr);
+ int res = s1rval - s2rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ SET_NZCV_24(s1rval, s2rval, res);
+ }
+}
+
+
+static void addre_ss(void)
+{
+ unimplemented();
+}
+
+
+static void sube_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG24((OP >> 0) & 0x1f) : REG24(dr);
+ int res = s2rval - s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ SET_NZCV_24(s1rval, s2rval, res);
+ }
+}
+
+
+static void nege_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int res = -s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ SET_NZCV_24(s1rval, 0, res);
+ }
+}
+
+
+static void andce_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG24((OP >> 0) & 0x1f) : REG24(dr);
+ int res = s2rval & ~s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ SET_NZ00_24(res);
+ }
+}
+
+
+static void cmpe_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int drval = REG24((OP >> 16) & 0x1f);
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int res = drval - s1rval;
+ SET_NZCV_24(drval, s1rval, res);
+ }
+}
+
+
+static void xore_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG24((OP >> 0) & 0x1f) : REG24(dr);
+ int res = s2rval ^ s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ SET_NZ00_24(res);
+ }
+}
+
+
+static void rcre_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int res = ((dsp32.nzcflags >> 1) & 0x800000) | (s1rval >> 1);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ dsp32.nzcflags = res | ((s1rval & 1) << 24);
+ dsp32.vflags = 0;
+ }
+}
+
+
+static void ore_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG24((OP >> 0) & 0x1f) : REG24(dr);
+ int res = s2rval | s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ SET_NZ00_24(res);
+ }
+}
+
+
+static void rcle_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int res = ((dsp32.nzcflags >> 24) & 0x000001) | (s1rval << 1);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ dsp32.nzcflags = res | ((s1rval & 0x800000) << 1);
+ dsp32.vflags = 0;
+ }
+}
+
+
+static void shre_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int res = s1rval >> 1;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ dsp32.nzcflags = res | ((s1rval & 1) << 24);
+ dsp32.vflags = 0;
+ }
+}
+
+
+static void div2e_s(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int res = (s1rval & 0x800000) | (s1rval >> 1);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ dsp32.nzcflags = res | ((s1rval & 1) << 24);
+ dsp32.vflags = 0;
+ }
+}
+
+
+static void ande_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int dr = (OP >> 16) & 0x1f;
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int s2rval = (OP & 0x800) ? REG24((OP >> 0) & 0x1f) : REG24(dr);
+ int res = s2rval & s1rval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ SET_NZ00_24(res);
+ }
+}
+
+
+static void teste_ss(void)
+{
+ if (CONDITION_IS_TRUE)
+ {
+ int drval = REG24((OP >> 16) & 0x1f);
+ int s1rval = REG24((OP >> 5) & 0x1f);
+ int res = drval & s1rval;
+ SET_NZ00_24(res);
+ }
+}
+
+
+static void adde_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG24(dr);
+ int res = drval + EXTEND16_TO_24(OP);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ SET_NZCV_24(drval, OP << 8, res);
+}
+
+
+static void subre_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG24(dr);
+ int res = EXTEND16_TO_24(OP) - drval;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ SET_NZCV_24(drval, OP << 8, res);
+}
+
+
+static void addre_di(void)
+{
+ unimplemented();
+}
+
+
+static void sube_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG24(dr);
+ int res = drval - EXTEND16_TO_24(OP);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = TRUNCATE24(res);
+ SET_NZCV_24(drval, OP << 8, res);
+}
+
+
+static void andce_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG24(dr);
+ int res = drval & ~EXTEND16_TO_24(OP);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ SET_NZ00_24(res);
+}
+
+
+static void cmpe_di(void)
+{
+ int drval = REG24((OP >> 16) & 0x1f);
+ int res = drval - EXTEND16_TO_24(OP);
+ SET_NZCV_24(drval, OP << 8, res);
+}
+
+
+static void xore_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG24(dr);
+ int res = drval ^ EXTEND16_TO_24(OP);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ SET_NZ00_24(res);
+}
+
+
+static void ore_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG24(dr);
+ int res = drval | EXTEND16_TO_24(OP);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ SET_NZ00_24(res);
+}
+
+
+static void ande_di(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ int drval = REG24(dr);
+ int res = drval & EXTEND16_TO_24(OP);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ SET_NZ00_24(res);
+}
+
+
+static void teste_di(void)
+{
+ int drval = REG24((OP >> 16) & 0x1f);
+ int res = drval & EXTEND16_TO_24(OP);
+ SET_NZ00_24(res);
+}
+
+
+
+/***************************************************************************
+ CAU LOAD/STORE IMPLEMENTATION
+***************************************************************************/
+
+static void load_hi(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ UINT32 res = RBYTE(EXTEND16_TO_24(OP));
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ dsp32.nzcflags = res << 8;
+ dsp32.vflags = 0;
+}
+
+
+static void load_li(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ UINT32 res = RBYTE(EXTEND16_TO_24(OP));
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ dsp32.nzcflags = res << 8;
+ dsp32.vflags = 0;
+}
+
+
+static void load_i(void)
+{
+ UINT32 res = RWORD(EXTEND16_TO_24(OP));
+ int dr = (OP >> 16) & 0x1f;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ dsp32.nzcflags = res << 8;
+ dsp32.vflags = 0;
+}
+
+
+static void load_ei(void)
+{
+ UINT32 res = TRUNCATE24(RLONG(EXTEND16_TO_24(OP)));
+ int dr = (OP >> 16) & 0x1f;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ dsp32.nzcflags = res;
+ dsp32.vflags = 0;
+}
+
+
+static void store_hi(void)
+{
+ WBYTE(EXTEND16_TO_24(OP), dsp32.r[(OP >> 16) & 0x1f] >> 8);
+}
+
+
+static void store_li(void)
+{
+ WBYTE(EXTEND16_TO_24(OP), dsp32.r[(OP >> 16) & 0x1f]);
+}
+
+
+static void store_i(void)
+{
+ WWORD(EXTEND16_TO_24(OP), REG16((OP >> 16) & 0x1f));
+}
+
+
+static void store_ei(void)
+{
+ WLONG(EXTEND16_TO_24(OP), (INT32)(REG24((OP >> 16) & 0x1f) << 8) >> 8);
+}
+
+
+static void load_hr(void)
+{
+ if (!(OP & 0x400))
+ {
+ int dr = (OP >> 16) & 0x1f;
+ UINT32 res = cau_read_pi_1byte(OP) << 8;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ dsp32.nzcflags = res << 8;
+ dsp32.vflags = 0;
+ }
+ else
+ unimplemented();
+}
+
+
+static void load_lr(void)
+{
+ if (!(OP & 0x400))
+ {
+ int dr = (OP >> 16) & 0x1f;
+ UINT32 res = cau_read_pi_1byte(OP);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ dsp32.nzcflags = res << 8;
+ dsp32.vflags = 0;
+ }
+ else
+ unimplemented();
+}
+
+
+static void load_r(void)
+{
+ if (!(OP & 0x400))
+ {
+ UINT32 res = cau_read_pi_2byte(OP);
+ int dr = (OP >> 16) & 0x1f;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = EXTEND16_TO_24(res);
+ dsp32.nzcflags = res << 8;
+ dsp32.vflags = 0;
+ }
+ else
+ unimplemented();
+}
+
+
+static void load_er(void)
+{
+ if (!(OP & 0x400))
+ {
+ UINT32 res = TRUNCATE24(cau_read_pi_4byte(OP));
+ int dr = (OP >> 16) & 0x1f;
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+ dsp32.nzcflags = res;
+ dsp32.vflags = 0;
+ }
+ else
+ unimplemented();
+}
+
+
+static void store_hr(void)
+{
+ if (!(OP & 0x400))
+ cau_write_pi_1byte(OP, dsp32.r[(OP >> 16) & 0x1f] >> 8);
+ else
+ unimplemented();
+}
+
+
+static void store_lr(void)
+{
+ if (!(OP & 0x400))
+ cau_write_pi_1byte(OP, dsp32.r[(OP >> 16) & 0x1f]);
+ else
+ unimplemented();
+}
+
+
+static void store_r(void)
+{
+ if (!(OP & 0x400))
+ cau_write_pi_2byte(OP, REG16((OP >> 16) & 0x1f));
+ else
+ unimplemented();
+}
+
+
+static void store_er(void)
+{
+ if (!(OP & 0x400))
+ cau_write_pi_4byte(OP, REG24((OP >> 16) & 0x1f));
+ else
+ unimplemented();
+}
+
+
+static void load24(void)
+{
+ int dr = (OP >> 16) & 0x1f;
+ UINT32 res = (OP & 0xffff) + ((OP >> 5) & 0xff0000);
+ if (IS_WRITEABLE(dr))
+ dsp32.r[dr] = res;
+}
+
+
+
+/***************************************************************************
+ DAU FORM 1 IMPLEMENTATION
+***************************************************************************/
+
+static void d1_aMpp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = yval + DEFERRED_MULTIPLIER((OP >> 26) & 7) * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d1_aMpm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = yval - DEFERRED_MULTIPLIER((OP >> 26) & 7) * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d1_aMmp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = -yval + DEFERRED_MULTIPLIER((OP >> 26) & 7) * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d1_aMmm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = -yval - DEFERRED_MULTIPLIER((OP >> 26) & 7) * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d1_0px(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = yval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+ (void)xval;
+}
+
+
+static void d1_0mx(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = -yval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+ (void)xval;
+}
+
+
+static void d1_1pp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = yval + xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d1_1pm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = yval - xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d1_1mp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = -yval + xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d1_1mm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = -yval - xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d1_aMppr(void)
+{
+ unimplemented();
+}
+
+
+static void d1_aMpmr(void)
+{
+ unimplemented();
+}
+
+
+static void d1_aMmpr(void)
+{
+ unimplemented();
+}
+
+
+static void d1_aMmmr(void)
+{
+ unimplemented();
+}
+
+
+
+/***************************************************************************
+ DAU FORM 2 IMPLEMENTATION
+***************************************************************************/
+
+static void d2_aMpp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 1, xval);
+ double res = dsp32.a[(OP >> 26) & 7] + yval * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, yval);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d2_aMpm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 1, xval);
+ double res = dsp32.a[(OP >> 26) & 7] - yval * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, yval);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d2_aMmp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 1, xval);
+ double res = -dsp32.a[(OP >> 26) & 7] + yval * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, yval);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d2_aMmm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 1, xval);
+ double res = -dsp32.a[(OP >> 26) & 7] - yval * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, yval);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d2_aMppr(void)
+{
+ unimplemented();
+}
+
+
+static void d2_aMpmr(void)
+{
+ unimplemented();
+}
+
+
+static void d2_aMmpr(void)
+{
+ unimplemented();
+}
+
+
+static void d2_aMmmr(void)
+{
+ unimplemented();
+}
+
+
+
+/***************************************************************************
+ DAU FORM 3 IMPLEMENTATION
+***************************************************************************/
+
+static void d3_aMpp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 1, xval);
+ double res = dsp32.a[(OP >> 26) & 7] + yval * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d3_aMpm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 1, xval);
+ double res = dsp32.a[(OP >> 26) & 7] - yval * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d3_aMmp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 1, xval);
+ double res = -dsp32.a[(OP >> 26) & 7] + yval * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d3_aMmm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 1, xval);
+ double res = -dsp32.a[(OP >> 26) & 7] - yval * xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d3_aMppr(void)
+{
+ unimplemented();
+}
+
+
+static void d3_aMpmr(void)
+{
+ unimplemented();
+}
+
+
+static void d3_aMmpr(void)
+{
+ unimplemented();
+}
+
+
+static void d3_aMmmr(void)
+{
+ unimplemented();
+}
+
+
+
+/***************************************************************************
+ DAU FORM 4 IMPLEMENTATION
+***************************************************************************/
+
+static void d4_pp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = yval + xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, yval);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d4_pm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = yval - xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, yval);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d4_mp(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = -yval + xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, yval);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d4_mm(void)
+{
+ double xval = dau_read_pi_double_1st(OP >> 14, 1);
+ double yval = dau_read_pi_double_2nd(OP >> 7, 0, xval);
+ double res = -yval - xval;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, yval);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d4_ppr(void)
+{
+ unimplemented();
+}
+
+
+static void d4_pmr(void)
+{
+ unimplemented();
+}
+
+
+static void d4_mpr(void)
+{
+ unimplemented();
+}
+
+
+static void d4_mmr(void)
+{
+ unimplemented();
+}
+
+
+
+/***************************************************************************
+ DAU FORM 5 IMPLEMENTATION
+***************************************************************************/
+
+static void d5_ic(void)
+{
+ unimplemented();
+}
+
+
+static void d5_oc(void)
+{
+ unimplemented();
+}
+
+
+static void d5_float(void)
+{
+ double res = (double)(INT16)dau_read_pi_2bytes(OP >> 7);
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d5_int(void)
+{
+ double val = dau_read_pi_double_1st(OP >> 7, 0);
+ int zpi = (OP >> 0) & 0x7f;
+ INT16 res;
+ if (!(dsp32.DAUC & 0x10)) val = floor(val + 0.5);
+ else val = ceil(val - 0.5);
+ res = (INT16)val;
+ if (zpi != 7)
+ dau_write_pi_2bytes(zpi, res);
+ dau_set_val_noflags((OP >> 21) & 3, dsp_to_double(res << 16));
+}
+
+
+static void d5_round(void)
+{
+ double res = (double)(float)dau_read_pi_double_1st(OP >> 7, 0);
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d5_ifalt(void)
+{
+ int ar = (OP >> 21) & 3;
+ double res = dsp32.a[ar];
+ int zpi = (OP >> 0) & 0x7f;
+ if (NFLAG)
+ res = dau_read_pi_double_1st(OP >> 7, 0);
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_noflags(ar, res);
+}
+
+
+static void d5_ifaeq(void)
+{
+ int ar = (OP >> 21) & 3;
+ double res = dsp32.a[ar];
+ int zpi = (OP >> 0) & 0x7f;
+ if (ZFLAG)
+ res = dau_read_pi_double_1st(OP >> 7, 0);
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_noflags(ar, res);
+}
+
+
+static void d5_ifagt(void)
+{
+ int ar = (OP >> 21) & 3;
+ double res = dsp32.a[ar];
+ int zpi = (OP >> 0) & 0x7f;
+ if (!NFLAG && !ZFLAG)
+ res = dau_read_pi_double_1st(OP >> 7, 0);
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_noflags(ar, res);
+}
+
+
+static void d5_float24(void)
+{
+ double res = (double)((INT32)(dau_read_pi_4bytes(OP >> 7) << 8) >> 8);
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_double(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, res);
+}
+
+
+static void d5_int24(void)
+{
+ double val = dau_read_pi_double_1st(OP >> 7, 0);
+ int zpi = (OP >> 0) & 0x7f;
+ INT32 res;
+ if (!(dsp32.DAUC & 0x10)) val = floor(val + 0.5);
+ else val = ceil(val - 0.5);
+ res = (INT32)val;
+ if (res > 0x7fffff) res = 0x7fffff;
+ else if (res < -0x800000) res = -0x800000;
+ if (zpi != 7)
+ dau_write_pi_4bytes(zpi, (INT32)(res << 8) >> 8);
+ dau_set_val_noflags((OP >> 21) & 3, dsp_to_double(res << 8));
+}
+
+
+static void d5_ieee(void)
+{
+ unimplemented();
+}
+
+
+static void d5_dsp(void)
+{
+ unimplemented();
+}
+
+
+static void d5_seed(void)
+{
+ UINT32 val = dau_read_pi_4bytes(OP >> 7);
+ INT32 res = val ^ 0x7fffffff;
+ int zpi = (OP >> 0) & 0x7f;
+ if (zpi != 7)
+ dau_write_pi_4bytes(zpi, res);
+ dau_set_val_flags((OP >> 21) & 3, dsp_to_double((INT32)res));
+}
+
+
+
+/***************************************************************************
+ FUNCTION TABLE
+***************************************************************************/
+
+void (*dsp32ops[])(void) =
+{
+ nop, goto_t, goto_pl, goto_mi, goto_ne, goto_eq, goto_vc, goto_vs, /* 00 */
+ goto_cc, goto_cs, goto_ge, goto_lt, goto_gt, goto_le, goto_hi, goto_ls,
+ goto_auc, goto_aus, goto_age, goto_alt, goto_ane, goto_aeq, goto_avc, goto_avs, /* 01 */
+ goto_agt, goto_ale, illegal, illegal, illegal, illegal, illegal, illegal,
+ goto_ibe, goto_ibf, goto_obf, goto_obe, goto_pde, goto_pdf, goto_pie, goto_pif, /* 02 */
+ goto_syc, goto_sys, goto_fbc, goto_fbs, goto_irq1lo,goto_irq1hi,goto_irq2lo,goto_irq2hi,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 03 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 04 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 05 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, /* 06 */
+ dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto,
+ dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, /* 07 */
+ dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto, dec_goto,
+
+ call, call, call, call, call, call, call, call, /* 08 */
+ call, call, call, call, call, call, call, call,
+ call, call, call, call, call, call, call, call, /* 09 */
+ call, call, call, call, call, call, call, call,
+ add_si, add_si, add_si, add_si, add_si, add_si, add_si, add_si, /* 0a */
+ add_si, add_si, add_si, add_si, add_si, add_si, add_si, add_si,
+ add_si, add_si, add_si, add_si, add_si, add_si, add_si, add_si, /* 0b */
+ add_si, add_si, add_si, add_si, add_si, add_si, add_si, add_si,
+
+ add_ss, mul2_s, subr_ss, addr_ss, sub_ss, neg_s, andc_ss, cmp_ss, /* 0c */
+ xor_ss, rcr_s, or_ss, rcl_s, shr_s, div2_s, and_ss, test_ss,
+ add_di, illegal, subr_di, addr_di, sub_di, illegal, andc_di, cmp_di, /* 0d */
+ xor_di, illegal, or_di, illegal, illegal, illegal, and_di, test_di,
+ load_hi, load_hi, load_li, load_li, load_i, load_i, load_ei, load_ei, /* 0e */
+ store_hi, store_hi, store_li, store_li, store_i, store_i, store_ei, store_ei,
+ load_hr, load_hr, load_lr, load_lr, load_r, load_r, load_er, load_er, /* 0f */
+ store_hr, store_hr, store_lr, store_lr, store_r, store_r, store_er, store_er,
+
+ d1_aMpp, d1_aMpp, d1_aMpp, d1_aMpp, d1_aMpm, d1_aMpm, d1_aMpm, d1_aMpm, /* 10 */
+ d1_aMmp, d1_aMmp, d1_aMmp, d1_aMmp, d1_aMmm, d1_aMmm, d1_aMmm, d1_aMmm,
+ d1_aMppr, d1_aMppr, d1_aMppr, d1_aMppr, d1_aMpmr, d1_aMpmr, d1_aMpmr, d1_aMpmr, /* 11 */
+ d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmmr, d1_aMmmr, d1_aMmmr, d1_aMmmr,
+ d1_aMpp, d1_aMpp, d1_aMpp, d1_aMpp, d1_aMpm, d1_aMpm, d1_aMpm, d1_aMpm, /* 12 */
+ d1_aMmp, d1_aMmp, d1_aMmp, d1_aMmp, d1_aMmm, d1_aMmm, d1_aMmm, d1_aMmm,
+ d1_aMppr, d1_aMppr, d1_aMppr, d1_aMppr, d1_aMpmr, d1_aMpmr, d1_aMpmr, d1_aMpmr, /* 13 */
+ d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmmr, d1_aMmmr, d1_aMmmr, d1_aMmmr,
+
+ d1_aMpp, d1_aMpp, d1_aMpp, d1_aMpp, d1_aMpm, d1_aMpm, d1_aMpm, d1_aMpm, /* 14 */
+ d1_aMmp, d1_aMmp, d1_aMmp, d1_aMmp, d1_aMmm, d1_aMmm, d1_aMmm, d1_aMmm,
+ d1_aMppr, d1_aMppr, d1_aMppr, d1_aMppr, d1_aMpmr, d1_aMpmr, d1_aMpmr, d1_aMpmr, /* 15 */
+ d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmmr, d1_aMmmr, d1_aMmmr, d1_aMmmr,
+ d1_aMpp, d1_aMpp, d1_aMpp, d1_aMpp, d1_aMpm, d1_aMpm, d1_aMpm, d1_aMpm, /* 16 */
+ d1_aMmp, d1_aMmp, d1_aMmp, d1_aMmp, d1_aMmm, d1_aMmm, d1_aMmm, d1_aMmm,
+ d1_aMppr, d1_aMppr, d1_aMppr, d1_aMppr, d1_aMpmr, d1_aMpmr, d1_aMpmr, d1_aMpmr, /* 17 */
+ d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmmr, d1_aMmmr, d1_aMmmr, d1_aMmmr,
+
+ d1_0px, d1_0px, d1_0px, d1_0px, d1_0px, d1_0px, d1_0px, d1_0px, /* 18 */
+ d1_0mx, d1_0mx, d1_0mx, d1_0mx, d1_0mx, d1_0mx, d1_0mx, d1_0mx,
+ d1_aMppr, d1_aMppr, d1_aMppr, d1_aMppr, d1_aMpmr, d1_aMpmr, d1_aMpmr, d1_aMpmr, /* 19 */
+ d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmmr, d1_aMmmr, d1_aMmmr, d1_aMmmr,
+ d1_1pp, d1_1pp, d1_1pp, d1_1pp, d1_1pm, d1_1pm, d1_1pm, d1_1pm, /* 1a */
+ d1_1mp, d1_1mp, d1_1mp, d1_1mp, d1_1mm, d1_1mm, d1_1mm, d1_1mm,
+ d1_aMppr, d1_aMppr, d1_aMppr, d1_aMppr, d1_aMpmr, d1_aMpmr, d1_aMpmr, d1_aMpmr, /* 1b */
+ d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmpr, d1_aMmmr, d1_aMmmr, d1_aMmmr, d1_aMmmr,
+
+ d4_pp, d4_pp, d4_pp, d4_pp, d4_pm, d4_pm, d4_pm, d4_pm, /* 1c */
+ d4_mp, d4_mp, d4_mp, d4_mp, d4_mm, d4_mm, d4_mm, d4_mm,
+ d4_ppr, d4_ppr, d4_ppr, d4_ppr, d4_pmr, d4_pmr, d4_pmr, d4_pmr, /* 1d */
+ d4_mpr, d4_mpr, d4_mpr, d4_mpr, d4_mmr, d4_mmr, d4_mmr, d4_mmr,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 1e */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 1f */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+
+ d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpm, d2_aMpm, d2_aMpm, d2_aMpm, /* 20 */
+ d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmm, d2_aMmm, d2_aMmm, d2_aMmm,
+ d2_aMppr, d2_aMppr, d2_aMppr, d2_aMppr, d2_aMpmr, d2_aMpmr, d2_aMpmr, d2_aMpmr, /* 21 */
+ d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmmr, d2_aMmmr, d2_aMmmr, d2_aMmmr,
+ d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpm, d2_aMpm, d2_aMpm, d2_aMpm, /* 22 */
+ d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmm, d2_aMmm, d2_aMmm, d2_aMmm,
+ d2_aMppr, d2_aMppr, d2_aMppr, d2_aMppr, d2_aMpmr, d2_aMpmr, d2_aMpmr, d2_aMpmr, /* 23 */
+ d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmmr, d2_aMmmr, d2_aMmmr, d2_aMmmr,
+
+ d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpm, d2_aMpm, d2_aMpm, d2_aMpm, /* 24 */
+ d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmm, d2_aMmm, d2_aMmm, d2_aMmm,
+ d2_aMppr, d2_aMppr, d2_aMppr, d2_aMppr, d2_aMpmr, d2_aMpmr, d2_aMpmr, d2_aMpmr, /* 25 */
+ d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmmr, d2_aMmmr, d2_aMmmr, d2_aMmmr,
+ d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpm, d2_aMpm, d2_aMpm, d2_aMpm, /* 26 */
+ d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmm, d2_aMmm, d2_aMmm, d2_aMmm,
+ d2_aMppr, d2_aMppr, d2_aMppr, d2_aMppr, d2_aMpmr, d2_aMpmr, d2_aMpmr, d2_aMpmr, /* 27 */
+ d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmmr, d2_aMmmr, d2_aMmmr, d2_aMmmr,
+
+ d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpm, d2_aMpm, d2_aMpm, d2_aMpm, /* 28 */
+ d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmm, d2_aMmm, d2_aMmm, d2_aMmm,
+ d2_aMppr, d2_aMppr, d2_aMppr, d2_aMppr, d2_aMpmr, d2_aMpmr, d2_aMpmr, d2_aMpmr, /* 29 */
+ d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmmr, d2_aMmmr, d2_aMmmr, d2_aMmmr,
+ d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpp, d2_aMpm, d2_aMpm, d2_aMpm, d2_aMpm, /* 2a */
+ d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmp, d2_aMmm, d2_aMmm, d2_aMmm, d2_aMmm,
+ d2_aMppr, d2_aMppr, d2_aMppr, d2_aMppr, d2_aMpmr, d2_aMpmr, d2_aMpmr, d2_aMpmr, /* 2b */
+ d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmpr, d2_aMmmr, d2_aMmmr, d2_aMmmr, d2_aMmmr,
+
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 2c */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 2d */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 2e */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 2f */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+
+ d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpm, d3_aMpm, d3_aMpm, d3_aMpm, /* 30 */
+ d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmm, d3_aMmm, d3_aMmm, d3_aMmm,
+ d3_aMppr, d3_aMppr, d3_aMppr, d3_aMppr, d3_aMpmr, d3_aMpmr, d3_aMpmr, d3_aMpmr, /* 31 */
+ d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmmr, d3_aMmmr, d3_aMmmr, d3_aMmmr,
+ d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpm, d3_aMpm, d3_aMpm, d3_aMpm, /* 32 */
+ d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmm, d3_aMmm, d3_aMmm, d3_aMmm,
+ d3_aMppr, d3_aMppr, d3_aMppr, d3_aMppr, d3_aMpmr, d3_aMpmr, d3_aMpmr, d3_aMpmr, /* 33 */
+ d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmmr, d3_aMmmr, d3_aMmmr, d3_aMmmr,
+
+ d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpm, d3_aMpm, d3_aMpm, d3_aMpm, /* 34 */
+ d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmm, d3_aMmm, d3_aMmm, d3_aMmm,
+ d3_aMppr, d3_aMppr, d3_aMppr, d3_aMppr, d3_aMpmr, d3_aMpmr, d3_aMpmr, d3_aMpmr, /* 35 */
+ d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmmr, d3_aMmmr, d3_aMmmr, d3_aMmmr,
+ d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpm, d3_aMpm, d3_aMpm, d3_aMpm, /* 36 */
+ d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmm, d3_aMmm, d3_aMmm, d3_aMmm,
+ d3_aMppr, d3_aMppr, d3_aMppr, d3_aMppr, d3_aMpmr, d3_aMpmr, d3_aMpmr, d3_aMpmr, /* 37 */
+ d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmmr, d3_aMmmr, d3_aMmmr, d3_aMmmr,
+
+ d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpm, d3_aMpm, d3_aMpm, d3_aMpm, /* 38 */
+ d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmm, d3_aMmm, d3_aMmm, d3_aMmm,
+ d3_aMppr, d3_aMppr, d3_aMppr, d3_aMppr, d3_aMpmr, d3_aMpmr, d3_aMpmr, d3_aMpmr, /* 39 */
+ d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmmr, d3_aMmmr, d3_aMmmr, d3_aMmmr,
+ d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpp, d3_aMpm, d3_aMpm, d3_aMpm, d3_aMpm, /* 3a */
+ d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmp, d3_aMmm, d3_aMmm, d3_aMmm, d3_aMmm,
+ d3_aMppr, d3_aMppr, d3_aMppr, d3_aMppr, d3_aMpmr, d3_aMpmr, d3_aMpmr, d3_aMpmr, /* 3b */
+ d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmpr, d3_aMmmr, d3_aMmmr, d3_aMmmr, d3_aMmmr,
+
+ d5_ic, d5_ic, d5_ic, d5_ic, d5_oc, d5_oc, d5_oc, d5_oc, /* 3c */
+ d5_float, d5_float, d5_float, d5_float, d5_int, d5_int, d5_int, d5_int,
+ d5_round, d5_round, d5_round, d5_round, d5_ifalt, d5_ifalt, d5_ifalt, d5_ifalt, /* 3d */
+ d5_ifaeq, d5_ifaeq, d5_ifaeq, d5_ifaeq, d5_ifagt, d5_ifagt, d5_ifagt, d5_ifagt,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 3e */
+ d5_float24, d5_float24, d5_float24, d5_float24, d5_int24, d5_int24, d5_int24, d5_int24,
+ d5_ieee, d5_ieee, d5_ieee, d5_ieee, d5_dsp, d5_dsp, d5_dsp, d5_dsp, /* 3f */
+ d5_seed, d5_seed, d5_seed, d5_seed, illegal, illegal, illegal, illegal,
+
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 40 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 41 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 42 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 43 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 44 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 45 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ do_i, do_r, illegal, illegal, illegal, illegal, illegal, illegal, /* 46 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 47 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 48 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 49 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, /* 4a */
+ adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, adde_si,
+ adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, /* 4b */
+ adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, adde_si, adde_si,
+
+ adde_ss, mul2e_s, subre_ss, addre_ss, sube_ss, nege_s, andce_ss, cmpe_ss, /* 4c */
+ xore_ss, rcre_s, ore_ss, rcle_s, shre_s, div2e_s, ande_ss, teste_ss,
+ adde_di, illegal, subre_di, addre_di, sube_di, illegal, andce_di, cmpe_di, /* 4d */
+ xore_di, illegal, ore_di, illegal, illegal, illegal, ande_di, teste_di,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 4e */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, /* 4f */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 50 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 51 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 52 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 53 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 54 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 55 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 56 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 57 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 58 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 59 */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 5a */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 5b */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 5c */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 5d */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 5e */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24, /* 5f */
+ goto24, goto24, goto24, goto24, goto24, goto24, goto24, goto24,
+
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 60 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 61 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 62 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 63 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 64 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 65 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 66 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 67 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 68 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 69 */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 6a */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 6b */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 6c */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 6d */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 6e */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+ load24, load24, load24, load24, load24, load24, load24, load24, /* 6f */
+ load24, load24, load24, load24, load24, load24, load24, load24,
+
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 70 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 71 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 72 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 73 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 74 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 75 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 76 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 77 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 78 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 79 */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 7a */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 7b */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 7c */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 7d */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 7e */
+ call24, call24, call24, call24, call24, call24, call24, call24,
+ call24, call24, call24, call24, call24, call24, call24, call24, /* 7f */
+ call24, call24, call24, call24, call24, call24, call24, call24
+};
+
+
+/*
+
+ Most common OPs in Race Drivin':
+
+301681217 - OP 0 - nop
+164890391 - OP 4A1 - adde_si
+99210113 - OP 661 - load24
+86010010 - OP F7 - load_er
+61148739 - OP 4D4 - sube_di
+52693763 - OP 180 - d1_0px
+41525754 - OP FF - store_er
+35033321 - OP 380 - d3_aMpp
+31621151 - OP 4C0 - adde_ss
+28076244 - OP 660 - load24
+19190505 - OP 4C1 - mul2e_s
+13270852 - OP F5 - load_r
+12535169 - OP 1A4 - d1_1pm
+12265141 - OP 4C4 - sube_ss
+10748211 - OP 4CD - div2e_s
+10493660 - OP FD - store_r
+ 9721263 - OP 189
+ 9415685 - OP 3C8
+ 9294148 - OP 3D5
+ 8887846 - OP 1A1
+ 8788648 - OP 381
+ 8185239 - OP 300
+ 7241256 - OP 383
+ 6877349 - OP 4A3
+ 6832295 - OP 181
+ 6601270 - OP 3E8
+ 6562483 - OP 4A4
+ 6553514 - OP 3C9
+ 6270430 - OP 280
+ 6041485 - OP 1A0
+ 5299529 - OP 304
+ 5110926 - OP 382
+ 4922253 - OP 363
+ 4603670 - OP 4D7
+ 4164327 - OP 4AE
+ 3980085 - OP 3EC
+ 3599198 - OP 3CC
+ 3543878 - OP 3D0
+ 3489158 - OP 4
+ 3463235 - OP 321
+ 3335995 - OP 3F9
+ 3001546 - OP 4CE
+ 2882940 - OP 129
+ 2882940 - OP 1A5
+ 2882940 - OP 342
+ 2841981 - OP 360
+ 2663417 - OP FB
+ 2059640 - OP 3ED
+ 1867166 - OP 1A8
+ 1830789 - OP 305
+ 1753312 - OP 301
+ 1726866 - OP 5
+ 1594991 - OP 12
+ 1571286 - OP 19
+ 1507644 - OP A2
+ 1418846 - OP 3CD
+ 1273134 - OP F3
+ 1177914 - OP 4C7
+ 1175720 - OP 188
+ 1091848 - OP 3E9
+ 1088206 - OP 6FF
+ 1088204 - OP 4CA
+ 1012639 - OP 101
+ 939617 - OP 4C5
+
+*/
diff --git a/src/emu/cpu/dsp56k/dsp56dsm.c b/src/emu/cpu/dsp56k/dsp56dsm.c
new file mode 100644
index 00000000000..a2f5c00b5b1
--- /dev/null
+++ b/src/emu/cpu/dsp56k/dsp56dsm.c
@@ -0,0 +1,2210 @@
+/***************************************************************************
+
+ dsp56kdasm.c
+ Disassembler for the portable Motorola/Freescale dsp56k emulator.
+ Written by Andrew Gardner
+
+***************************************************************************/
+
+#include "dsp56k.h"
+
+/* todo: fix the syntax for many opcodes to be true DSP56k assembly
+ *
+ *
+*/
+
+
+// Main opcode categories
+static unsigned DecodeDataALUOpcode(char *buffer, UINT16 op, unsigned pc, int parallelType) ;
+//static unsigned DecodeDXMDROpcode(char *buffer, UINT16 op, unsigned pc) ;
+static unsigned DecodeNPMOpcode(char *buffer, UINT16 op, unsigned pc, const UINT8 *oprom) ;
+static unsigned DecodeMisfitOpcode(char *buffer, UINT16 op, unsigned pc, const UINT8 *oprom) ;
+static unsigned DecodeSpecialOpcode(char *buffer, UINT16 op, unsigned pc, const UINT8 *oprom) ;
+
+
+// Parallel memory operation decoding
+static void AppendXMDM(char *buffer, UINT16 op) ;
+static void AppendXMDMSpecial(char *buffer, UINT16 op, char *working) ;
+static void AppendARU(char *buffer, UINT16 op) ;
+static void AppendRRDM(char *buffer, UINT16 op, char *working) ;
+
+//static void AppendDXMDR(char *buffer, UINT16 op) ;
+
+
+// Helper functions
+#define BITS(CUR,MASK) (Dsp56kOpMask(CUR,MASK))
+static UINT16 Dsp56kOpMask(UINT16 op, UINT16 mask) ;
+
+
+enum bbbType { BBB_UPPER, BBB_MIDDLE, BBB_LOWER } ;
+
+// Table decoder functions...
+static int DecodeBBBTable (UINT16 BBB ) ;
+static void DecodeccccTable (UINT16 cccc, char *mnemonic) ;
+static void DecodeDDDDDTable(UINT16 DDDDD, char *SD) ;
+static void DecodeDDTable (UINT16 DD, char *SD) ;
+//static void DecodeDDFTable (UINT16 DD, UINT16 F, char *S, char *D) ;
+static void DecodeEETable (UINT16 EE, char *D) ;
+static void DecodeFTable (UINT16 F, char *SD) ;
+static void Decodeh0hFTable (UINT16 h0h, UINT16 F, char *S, char *D) ;
+static void DecodeHHTable (UINT16 HH, char *SD) ;
+static void DecodeHHHTable (UINT16 HHH, char *SD) ;
+static void DecodeIIIITable (UINT16 IIII, char *S, char *D) ;
+static void DecodeJJJFTable (UINT16 JJJ, UINT16 F, char *S, char *D) ;
+static void DecodeJJFTable (UINT16 JJ, UINT16 F, char *S, char *D) ;
+//static void DecodeJFTable (UINT16 J, UINT16 F, char *S, char *D) ;
+//static void DecodekTable (UINT16 k, char *Dnot) ;
+//static void DecodekSignTable(UINT16 k, char *plusMinus) ;
+//static void DecodeKKKTable (UINT16 KKK, char *D1, char *D2) ;
+//static int DecodeNNTable (UINT16 NN) ;
+//static void DecodeQQFTable (UINT16 QQ, UINT16 F, char *S1, char *S2, char *D) ;
+static void DecodeQQFTableSp(UINT16 QQ, UINT16 F, char *S1, char *S2, char *D) ;
+//static void DecodeQQQFTable (UINT16 QQQ, UINT16 F, char *S1, char *S2, char *D) ;
+static int DecodeRRTable (UINT16 RR) ;
+static void DecodesTable (UINT16 s, char *arithmetic) ;
+//static void DecodessTable (UINT16 ss, char *arithmetic) ;
+//static void DecodeuuuuFTable(UINT16 uuuu, UINT16 F, char *arg, char *S, char *D) ;
+static void DecodeZTable (UINT16 Z, char *ea) ;
+
+
+static void AssembleeaFrommTable (UINT16 m, int n, char *ea) ;
+//static void AssembleeaFrommmTable(UINT16 mm, int n1, int n2, char *ea1, char *ea2) ;
+static void AssembleeaFromMMTable(UINT16 MM, int n, char *ea) ;
+static void AssembleeaFromtTable (UINT16 t, UINT16 val, char *ea) ;
+static void AssembleeaFromqTable (UINT16 q, int n, char *ea) ;
+static void AssembleeaFromzTable (UINT16 z, int n, char *ea) ;
+
+static void AssembleDFromPTable(UINT16 P, UINT16 ppppp, char *D) ;
+static void AssembleArgumentsFromWTable(UINT16 W, char *args, char ma, char *SD, char *ea) ;
+static void AssembleRegFromWTable(UINT16 W, char *args, char ma, char *SD, UINT8 xx) ;
+
+static void AssembleAddressFromIOShortAddress(UINT16 pp, char *ea) ;
+static void AssembleAddressFrom6BitSignedRelativeShortAddress(UINT16 srs, char *ea) ;
+
+// Main disassembly function
+offs_t dsp56k_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT16 op = oprom[0] | (oprom[1] << 8);
+ unsigned size = 0 ;
+
+ pc <<= 1 ;
+
+ if (BITS(op,0x8000)) // First, the parallel data move instructions
+ {
+ size = DecodeDataALUOpcode(buffer, op, pc, PARALLEL_TYPE_XMDM) ;
+ }
+ else if (BITS(op,0xf000) == 0x5)
+ {
+ size = DecodeDataALUOpcode(buffer, op, pc, PARALLEL_TYPE_XMDM_SPECIAL) ;
+ }
+ else if (BITS(op,0xff00) == 0x4a)
+ {
+ size = DecodeDataALUOpcode(buffer, op, pc, PARALLEL_TYPE_NODM) ;
+ }
+ else if (BITS(op,0xf000) == 0x04)
+ {
+ size = DecodeDataALUOpcode(buffer, op, pc, PARALLEL_TYPE_RRDM) ;
+ }
+ else if (BITS(op,0xf800) == 0x06)
+ {
+ size = DecodeDataALUOpcode(buffer, op, pc, PARALLEL_TYPE_ARU) ;
+ }
+
+ else if (BITS(op,0x4000))
+ {
+ // size = DecodeDXMDROpcode(buffer, op, pc) ;
+ sprintf(buffer, "unknown") ;
+ size = 1 ;
+ }
+ else if (BITS(op,0xf000) == 0x1)
+ {
+ size = DecodeNPMOpcode(buffer, op, pc, oprom) ;
+ }
+ else if (BITS(op,0x2000))
+ {
+ size = DecodeMisfitOpcode(buffer, op, pc, oprom) ;
+ }
+ else if (BITS(op,0xf000) == 0x0)
+ {
+ size = DecodeSpecialOpcode(buffer, op, pc, oprom) ;
+ }
+
+ if (size == 0)
+ {
+ sprintf(buffer, "unknown") ;
+ size = 1 ; // Just to get the debugger past the bad opcode
+ }
+
+ return size | DASMFLAG_SUPPORTED;
+}
+
+
+static unsigned DecodeDataALUOpcode(char *buffer, UINT16 op, unsigned pc, int parallelType)
+{
+ unsigned retSize = 0 ;
+
+ char S1[32] ;
+ char D[32] ;
+
+ switch(BITS(op,0x0070))
+ {
+ case 0x0:
+ if (BITS(op,0x0007) == 0x1)
+ {
+ // CLR - 1mRR HHHW 0000 F001
+ DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "clr %s", D) ;
+ retSize = 1 ;
+ }
+ else
+ {
+ // ADD - 1mRR HHHW 0000 FJJJ
+ DecodeJJJFTable(BITS(op,0x0007), BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "add %s,%s", S1, D) ;
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0x1:
+ if (BITS(op,0x000f) == 0x1)
+ {
+ // MOVE - 1mRR HHHW 0001 0001
+ // Funny operation :)
+ sprintf(buffer, "move ") ;
+ retSize = 1 ;
+ }
+ else
+ {
+ // TFR - 1mRR HHHW 0001 FJJJ
+ DecodeJJJFTable(BITS(op,0x0007), BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "tfr %s,%s", S1, D) ;
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0x2:
+ if (BITS(op,0x0007) == 0x0)
+ {
+ // RND - 1mRR HHHW 0010 F000
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "rnd %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0007) == 0x1)
+ {
+ // TST - 1mRR HHHW 0010 F001
+ DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "tst %s", D) ;
+ retSize = 1 ;
+ }
+ else if (BITS(op,0x0007) == 0x2)
+ {
+ // INC - 1mRR HHHW 0010 F010
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "inc %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0007) == 0x3)
+ {
+ // INC24 - 1mRR HHHW 0010 F011
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "inc24 %s", D) ;
+ retSize = 1 ;
+*/ }
+ else
+ {
+ // OR - 1mRR HHHW 0010 F1JJ
+ DecodeJJFTable(BITS(op,0x0003),BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "or %s,%s", S1, D) ;
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0x3:
+ if (BITS(op,0x0007) == 0x0)
+ {
+ // ASR - 1mRR HHHW 0011 F000
+ DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "asr %s", D) ;
+ retSize = 1 ;
+ }
+ else if (BITS(op,0x0007) == 0x1)
+ {
+/*
+ // ASL - 1mRR HHHW 0011 F001
+ DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "asl %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0007) == 0x2)
+ {
+ // LSR - 1mRR HHHW 0011 F010
+ DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "lsr %s", D) ;
+ retSize = 1 ;
+ }
+ else if (BITS(op,0x0007) == 0x3)
+ {
+/*
+ // LSL - 1mRR HHHW 0011 F011
+ DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "lsl %s", D) ;
+ retSize = 1 ;
+*/ }
+ else
+ {
+ // EOR - 1mRR HHHW 0011 F1JJ
+ DecodeJJFTable(BITS(op,0x0003),BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "eor %s,%s", S1, D) ;
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0x4:
+ if (BITS(op,0x0007) == 0x1)
+ {
+ // SUBL - 1mRR HHHW 0100 F001
+ // There's something strange about this opcode - there's only one option for F!
+/* if (!BITS(op,0x0008))
+ sprintf(buffer, "subl B,A") ;
+ else
+ sprintf(buffer, "subl (other!)") ;
+ retSize = 1 ;
+*/ }
+ else
+ {
+ // SUB - 1mRR HHHW 0100 FJJJ
+/* DecodeJJJFTable(BITS(op,0x0007), BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "sub %s,%s", S1, D) ;
+ retSize = 1 ;
+*/ }
+ break ;
+
+ case 0x5:
+ if (BITS(op,0x0007) == 0x1)
+ {
+ // CLR24 - 1mRR HHHW 0101 F001
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "clr24 %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0006) == 0x1)
+ {
+ // SBC - 1mRR HHHW 0101 F01J
+/* DecodeJFTable(BITS(op,0x0001), BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "sbc %s,%s", S1, D) ;
+ retSize = 1 ;
+*/ }
+ else
+ {
+ // CMP - 1mRR HHHW 0101 FJJJ
+ DecodeJJJFTable(BITS(op,0x0007), BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "cmp %s,%s", S1,D) ;
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0x6:
+ if (BITS(op,0x0007) == 0x0)
+ {
+ // NEG - 1mRR HHHW 0110 F000
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "neg %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0007) == 0x1)
+ {
+ // NOT - 1mRR HHHW 0110 F001
+ DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "not %s", D) ;
+ retSize = 1 ;
+ }
+ else if (BITS(op,0x0007) == 0x2)
+ {
+ // DEC - 1mRR HHHW 0110 F010
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "dec %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0007) == 0x3)
+ {
+ // DEC24 - 1mRR HHHW 0110 F011
+ DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "dec24 %s", D) ;
+ retSize = 1 ;
+ }
+ else
+ {
+ // AND - 1mRR HHHW 0110 F1JJ
+ DecodeJJFTable(BITS(op,0x0003),BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "and %s,%s", S1, D) ;
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0x7:
+ if (BITS(op,0x0007) == 0x1)
+ {
+ // ABS - 1mRR HHHW 0111 F001
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "abs %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0007) == 0x2)
+ {
+ // ROR - 1mRR HHHW 0111 F010
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "ror %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0007) == 0x3)
+ {
+ // ROL - 1mRR HHHW 0111 F011
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "rol %s", D) ;
+ retSize = 1 ;
+*/ }
+ else
+ {
+ // CMPM - 1mRR HHHW 0111 FJJJ
+/* DecodeJJJFTable(BITS(op,0x0007), BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "cmpm %s,%s", S1,D) ;
+ retSize = 1 ;
+*/ }
+
+ break ;
+ }
+
+/*
+ // Otherwise you're looking at a MPY/MAC operation...
+ if (BITS(op,0x0080)) // Maybe i should un-consolidate here?
+ {
+ DecodeQQQFTable(BITS(op,0x0007), BITS(op,0x0008), S1, S2, D) ;
+ DecodekSignTable(BITS(op,0x0040), sign) ;
+
+ switch(BITS(op,0x00b0))
+ {
+ // MPY - 1mRR HHHH 1k00 FQQQ
+ case 0x4: sprintf(buffer, "mpy (%s)%s,%s,%s", sign, S2, S1, D) ; break ;
+
+ // MPYR - 1mRR HHHH 1k01 FQQQ
+ case 0x5: sprintf(buffer, "mpyr (%s)%s,%s,%s", sign, S2, S1, D) ; break ;
+
+ // MAC - 1mRR HHHH 1k10 FQQQ
+ case 0x6: sprintf(buffer, "mac (%s)%s,%s,%s", sign, S2, S1, D) ; break ;
+
+ // MACR - 1mRR HHHH 1k11 FQQQ
+ case 0x7: sprintf(buffer, "macr (%s)%s,%s,%s", sign, S1, S2, D) ; break ;
+ // !! It's a little odd that macr is S1,S2 while everyone else is S2,S1 !!
+ }
+
+ retSize = 1 ;
+ }
+*/
+
+// mame_printf_debug("op : %04x parallelType : %d\n", op, parallelType) ;
+
+ switch (parallelType)
+ {
+ case PARALLEL_TYPE_XMDM:
+ AppendXMDM(buffer, op) ;
+ break ;
+
+ case PARALLEL_TYPE_XMDM_SPECIAL:
+ AppendXMDMSpecial(buffer, op, D) ;
+ break ;
+
+ case PARALLEL_TYPE_NODM:
+ // Do Nothing :)...
+ break ;
+
+ case PARALLEL_TYPE_ARU:
+ AppendARU(buffer, op) ;
+ break ;
+
+ case PARALLEL_TYPE_RRDM:
+ AppendRRDM(buffer, op, D) ;
+ break ;
+ }
+
+ return retSize ;
+}
+
+
+#ifdef UNUSED_FUNCTION
+static unsigned DecodeDXMDROpcode(char *buffer, UINT16 op, unsigned pc)
+{
+ unsigned retSize = 0 ;
+
+ char S1[32] ;
+ char S2[32] ;
+ char D[32] ;
+ char arg[32] ;
+
+ if (!BITS(op,0x0080))
+ {
+ if (BITS(op,0x0014) != 0x2)
+ {
+ // ADD - 011m mKKK 0rru Fuuu
+ // SUB - 011m mKKK 0rru Fuuu
+ DecodeuuuuFTable(BITS(op,0x0013), BITS(op,0x0008), arg, S1, D) ;
+ sprintf(buffer, "%s %s,%s", arg, S1, D) ;
+ retSize = 1 ;
+ }
+ else if (BITS(op,0x0014) == 0x2)
+ {
+ // TFR - 011m mKKK 0rr1 F0DD
+ DecodeDDFTable(BITS(op,0x0003), BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "tfr %s,%s", S1, D) ;
+ retSize = 1 ;
+
+ // MOVE - 011m mKKK 0rr1 0000
+ // !!! What? The opcode is .identical. to the TFR one. Wait, that makes sense, right?
+ }
+ }
+ else
+ {
+ switch (BITS(op,0x0014))
+ {
+ case 0x0:
+ // MPY - 011m mKKK 1xx0 F0QQ
+ // What the hell are those two x's : i bet they're supposed to be -'s?
+ DecodeQQFTable(BITS(op,0x0003), BITS(op,0x0008), S1, S2, D) ;
+ sprintf(buffer, "mpy %s,%s,%s", S1, S2, D) ;
+ retSize = 1 ;
+ break ;
+
+ case 0x1:
+ // MAC - 011m mKKK 1xx0 F1QQ
+ // What the hell are those two x's : i bet they're supposed to be -'s?
+ DecodeQQFTable(BITS(op,0x0003), BITS(op,0x0008), S1, S2, D) ;
+ sprintf(buffer, "mac %s,%s,%s", S1, S2, D) ;
+ retSize = 1 ;
+ break ;
+
+ case 0x2:
+ // MPYR - 011m mKKK 1--1 F0QQ
+ DecodeQQFTable(BITS(op,0x0003), BITS(op,0x0008), S1, S2, D) ;
+ sprintf(buffer, "mpyr %s,%s,%s", S1, S2, D) ;
+ retSize = 1 ;
+ break ;
+
+ case 0x3:
+ // MACR - 011m mKKK 1--1 F1QQ
+ DecodeQQFTable(BITS(op,0x0003), BITS(op,0x0008), S1, S2, D) ;
+ sprintf(buffer, "macr %s,%s,%s", S1, S2, D) ;
+ retSize = 1 ;
+ break ;
+ }
+ }
+
+ AppendDXMDR(buffer, op) ;
+
+ return retSize ;
+}
+#endif
+
+
+static unsigned DecodeNPMOpcode(char *buffer, UINT16 op, unsigned pc, const UINT8 *oprom)
+{
+ unsigned retSize = 0 ;
+
+ char S1[32] ;
+ char S2[32] ;
+ char SD[32] ;
+ char D[32] ;
+ char A[32] ;
+ char M[32] ;
+ char args[32] ;
+ int Rnum ;
+
+
+ if (BITS(op,0x0f00) == 0x4)
+ {
+ // Bitfield Immediate
+ int upperMiddleLower = -1 ;
+ UINT16 iVal = 0x0000 ;
+ UINT16 rVal = 0x0000 ;
+ char D[32] ;
+
+ UINT32 op2 = oprom[2] | (oprom[3] << 8);
+
+ // Decode the common parts
+ upperMiddleLower = DecodeBBBTable(BITS(op2,0xe000)) ;
+ iVal = BITS(op2,0x00ff) ;
+
+ switch(upperMiddleLower)
+ {
+ case BBB_UPPER: iVal <<= 8; break ;
+ case BBB_MIDDLE: iVal <<= 4; break ;
+ case BBB_LOWER: iVal <<= 0; break ;
+ }
+
+ switch(BITS(op,0x00e0))
+ {
+ case 0x6: case 0x7: case 0x2: case 0x3:
+ AssembleDFromPTable(BITS(op,0x0020), BITS(op,0x001f), D) ;
+ break ;
+
+ case 0x5: case 0x1:
+ // !! Probably want to combine this into something that returns a 'string'... !!
+ rVal = DecodeRRTable(BITS(op,0x0003)) ;
+ sprintf(D, "X:(R%d)", rVal) ;
+ break ;
+
+ case 0x4: case 0x0:
+ DecodeDDDDDTable(BITS(op,0x001f), D) ;
+ break ;
+ }
+
+ switch(BITS(op2,0x1f00))
+ {
+ // !!! retsize = 2 put here for debugging help - put it at the end eventually...
+ case 0x12: sprintf(buffer, "bfchg #%04x,%s", iVal, D) ; retSize = 2 ; break ;
+ case 0x04: sprintf(buffer, "bfclr #%04x,%s", iVal, D) ; retSize = 2 ; break ;
+ case 0x18: sprintf(buffer, "bfset #%04x,%s", iVal, D) ; retSize = 2 ; break ;
+// case 0x10: sprintf(buffer, "bftsth #%04x,%s", iVal, D) ; retSize = 2 ; break ;
+ case 0x00: sprintf(buffer, "bftstl #%04x,%s", iVal, D) ; retSize = 2 ; break ;
+ }
+
+ // uncomment me someday
+// retSize = 2 ;
+ }
+ else if (BITS(op,0x0f00) == 0x5)
+ {
+ switch(BITS(op,0x0074))
+ {
+ case 0x0:
+ if (BITS(op,0x0006) == 0x0)
+ {
+ // TFR(2) - 0001 0101 0000 F00J
+/* DecodeJFTable(BITS(op,0x0001),BITS(op,0x0008), D, S1) ;
+ sprintf(buffer, "tfr2 %s,%s", S1, D) ;
+ retSize = 1 ;
+*/ // !?! Documentation bug !?!
+ // !!! the source and destination are backwards for TFR(2), and no mention of it is made !!!
+ }
+ else if (BITS(op,0x0006) == 0x1)
+ {
+ // ADC - 0001 0101 0000 F01J
+/* DecodeJFTable(BITS(op,0x0001),BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "adc %s,%s", S1, D) ;
+ retSize = 1 ;
+*/ }
+ break ;
+
+ case 0x3:
+ // TST(2) - 0001 0101 0001 -1DD
+ DecodeDDTable(BITS(op,0x0003), S1) ;
+ sprintf(buffer, "tst(2) %s", S1) ;
+ retSize = 1 ;
+ break ;
+
+ case 0x4:
+ // NORM - 0001 0101 0010 F0RR
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ Rnum = DecodeRRTable(BITS(op,0x0003)) ;
+ sprintf(buffer, "norm %s,R%d", S1, Rnum) ;
+ retSize = 1 ;
+*/ break ;
+
+ case 0x6:
+ if (BITS(op,0x0003) == 0x0)
+ {
+ // ASR4 - 0001 0101 0011 F000
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "asr4 %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0003) == 0x1)
+ {
+ // ASL4 - 0001 0101 0011 F001
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "asl4 %s", D) ;
+ retSize = 1 ;
+*/ }
+ break ;
+
+ case 0x1: case 0x5: case 0x9: case 0xd:
+ // DIV - 0001 0101 0--0 F1DD
+/* DecodeDDFTable(BITS(op,0x0003), BITS(op,0x0008), S1, D) ;
+ sprintf(buffer, "div %s,%s", S1, D) ;
+ retSize = 1 ;
+*/ break ;
+
+ case 0xa:
+ if (BITS(op,0x0003) == 0x0)
+ {
+ // ZERO - 0001 0101 0101 F000
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "zero %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0003) == 0x2)
+ {
+ // EXT - 0001 0101 0101 F010
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "ext %s", D) ;
+ retSize = 1 ;
+*/ }
+ break ;
+
+ case 0xc:
+ if (BITS(op,0x0003) == 0x0)
+ {
+ // NEGC - 0001 0101 0110 F000
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "negc %s", D) ;
+ retSize = 1 ;
+*/ }
+ break ;
+
+ case 0xe:
+ if (BITS(op,0x0003) == 0x0)
+ {
+ // ASR16 - 0001 0101 0111 F000
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "asr16 %s", D) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x0003) == 0x1)
+ {
+ // SWAP - 0001 0101 0111 F001
+/* DecodeFTable(BITS(op,0x0008), D) ;
+ sprintf(buffer, "swap %s", D) ;
+ retSize = 1 ;
+*/ }
+ break ;
+ }
+
+ switch(BITS(op,0x00f0))
+ {
+ case 0x8:
+ // IMPY - 0001 0101 1000 FQQQ
+/* DecodeQQQFTable(BITS(op,0x0007), BITS(op,0x0008), S1, S2, D) ;
+ sprintf(buffer, "impy %s,%s,%s", S1, S2, D) ;
+ retSize = 1 ;
+*/ break ;
+ case 0xa:
+ // IMAC - 0001 0101 1010 FQQQ
+/* DecodeQQQFTable(BITS(op,0x0007), BITS(op,0x0008), S1, S2, D) ;
+ sprintf(buffer, "imac %s,%s,%s", S1, S2, D) ;
+ retSize = 1 ;
+*/ break ;
+ case 0x9: case 0xb:
+ // DMAC(ss,su,uu) - 0001 0101 10s1 FsQQ
+/* DecodessTable(BITS(op,0x0024), A) ;
+ DecodeQQFTableSp(BITS(op,0x0003), BITS(op,0x0008), S2, S1, D) ; // Special QQF
+ sprintf(buffer, "dmac(%s) %s,%s,%s", A, S1, S2, D) ;
+ retSize = 1 ;
+*/ break ;
+ case 0xc:
+ // MPY(su,uu) - 0001 0101 1100 FsQQ
+/* DecodesTable(BITS(op,0x0004), A) ;
+ DecodeQQFTableSp(BITS(op,0x0003), BITS(op,0x0008), S2, S1, D) ; // Special QQF
+ sprintf(buffer, "mpy(%s) %s,%s,%s", A, S1, S2, D) ;
+ retSize = 1 ;
+*/ break ;
+ case 0xe:
+ // MAC(su,uu) - 0001 0101 1110 FsQQ
+ DecodesTable(BITS(op,0x0004), A) ;
+ DecodeQQFTableSp(BITS(op,0x0003), BITS(op,0x0008), S2, S1, D) ; // Special QQF
+ sprintf(buffer, "mac(%s) %s,%s,%s", A, S1, S2, D) ;
+ retSize = 1 ;
+ break ;
+ }
+ }
+ else if ((BITS(op,0x0f00) == 0x6))
+ {
+/*
+ char S[32] ;
+
+ // MPY - 0001 0110 RRDD FQQQ
+ DecodekTable(BITS(op,0x0100), Dnot) ;
+ Rnum = DecodeRRTable(BITS(op,0x00c0)) ;
+ DecodeDDTable(BITS(op,0x0030), S) ;
+ DecodeQQQFTable(BITS(op,0x0007), BITS(op,0x0008), S1, S2, D) ;
+ sprintf(buffer, "mpy %s,%s,%s %s,(R%d)+N%d %s,%s", S1, S2, D, Dnot, Rnum, Rnum, S, Dnot) ;
+ // Strange, but not entirely out of the question - this 'k' parameter is hardcoded
+ // I cheat here and do the parallel memory data move above - this specific one is only used twice
+ retSize = 1 ;
+*/ }
+ else if ((BITS(op,0x0f00) == 0x7))
+ {
+/*
+ char S[32] ;
+
+ // MAC - 0001 0111 RRDD FQQQ
+ DecodekTable(BITS(op,0x0100), Dnot) ;
+ Rnum = DecodeRRTable(BITS(op,0x00c0)) ;
+ DecodeDDTable(BITS(op,0x0030), S) ;
+ DecodeQQQFTable(BITS(op,0x0007), BITS(op,0x0008), S1, S2, D) ;
+ sprintf(buffer, "mac %s,%s,%s %s,(R%d)+N%d %s,%s", S1, S2, D, Dnot, Rnum, Rnum, S, Dnot) ;
+ // Strange, but not entirely out of the question - this 'k' parameter is hardcoded
+ // I cheat here and do the parallel memory data move above - this specific one is only used twice
+ retSize = 1 ;
+*/ }
+ else if ((BITS(op,0x0800) == 0x1))
+ {
+ if (BITS(op,0x0600))
+ {
+ if (!BITS(op,0x0100))
+ {
+ // ANDI - 0001 1EE0 iiii iiii
+ DecodeEETable(BITS(op,0x0600), D) ;
+ sprintf(buffer, "and(i) #%02x,%s", BITS(op,0x00ff), D) ;
+ retSize = 1 ;
+ }
+ else
+ {
+ // ORI - 0001 1EE1 iiii iiii
+/* DecodeEETable(BITS(op,0x0600), D) ;
+ sprintf(buffer, "or(i) #%02x,%s", BITS(op,0x00ff), D) ;
+ retSize = 1 ;
+*/ }
+ }
+ else
+ {
+ if (!BITS(op,0x0020))
+ {
+ // MOVE(S) - 0001 100W HH0a aaaa
+/*
+ DecodeHHTable(BITS(op,0x00c0), SD) ;
+ sprintf(A, "X:%02x", BITS(op,0x001f)) ;
+ AssembleArgumentsFromWTable(BITS(op,0x0100), args, 'X', SD, A) ;
+ sprintf(buffer, "move(s) %s", args) ;
+ retSize = 1 ;
+*/ }
+ else
+ {
+ char fullAddy[128] ; // Convert Short Absolute Address to full 16-bit
+
+ // MOVE(P) - 0001 100W HH1p pppp
+ DecodeHHTable(BITS(op,0x00c0), SD) ;
+
+ AssembleAddressFromIOShortAddress(BITS(op,0x001f), fullAddy) ;
+
+ sprintf(A, "%02x (%s)", BITS(op,0x001f), fullAddy) ;
+ AssembleArgumentsFromWTable(BITS(op,0x0100), args, 'X', SD, A) ;
+ sprintf(buffer, "move(p) %s", args) ;
+ retSize = 1 ;
+ }
+ }
+ }
+ else if ((BITS(op,0x0c00) == 0x0))
+ {
+ // T.cc - 0001 00cc ccTT Fh0h
+ DecodeccccTable(BITS(op,0x03c0), M) ;
+ Rnum = DecodeRRTable(BITS(op,0x0030)) ;
+ Decodeh0hFTable(BITS(op,0x0007),BITS(op,0x0008), S1, D) ;
+ if (S1[0] == D[0] && D[0] == 'A')
+ sprintf(buffer, "t.%s %s,%s", M, S1, D) ;
+ else
+ sprintf(buffer, "t.%s %s,%s R0,R%d", M, S1, D, Rnum) ;
+ // !! Might not be right - gotta' double-check !!
+ retSize = 1 ;
+ }
+
+ return retSize ;
+}
+
+
+unsigned DecodeMisfitOpcode(char *buffer, UINT16 op, unsigned pc, const UINT8 *oprom)
+{
+ unsigned retSize = 0 ;
+
+ char S1[32] ;
+ char D1[32] ;
+ char SD[32] ;
+ char M[32] ;
+ char ea[32] ;
+ char args[32] ;
+ int Rnum ;
+
+ if (BITS(op,0x1000)== 0x0)
+ {
+ switch(BITS(op,0x0c00))
+ {
+ // MOVE(I) - 0010 00DD BBBB BBBB
+ case 0x0:
+ DecodeDDTable(BITS(op,0x0300), D1) ;
+ sprintf(buffer, "move(i) #%02x,%s", BITS(op,0x00ff), D1) ;
+ retSize = 1 ;
+ break ;
+
+ // TFR(3) - 0010 01mW RRDD FHHH
+ case 0x1:
+/* DecodeDDFTable(BITS(op,0x0030), BITS(op,0x0008), D1, S1) ; // Intentionally switched
+ DecodeHHHTable(BITS(op,0x0007), SD) ;
+ Rnum = DecodeRRTable(BITS(op,0x00c0)) ;
+ AssembleeaFrommTable(BITS(op,0x0200), Rnum, ea) ;
+ AssembleArgumentsFromWTable(BITS(op,0x0100), args, 'X', SD, ea) ;
+ sprintf(buffer, "tfr3 %s,%s %s", S1, D1, args) ;
+ retSize = 1 ;
+*/ break ;
+
+ // MOVE(C) - 0010 10dd dddD DDDD
+ case 0x2:
+ DecodeDDDDDTable(BITS(op,0x03e0), S1) ;
+ DecodeDDDDDTable(BITS(op,0x001f), D1) ;
+ sprintf(buffer, "move(c) %s,%s", S1, D1) ;
+ retSize = 1 ;
+ break ;
+
+ // B.cc - 0010 11cc ccee eeee
+ case 0x3:
+ DecodeccccTable(BITS(op,0x3c0), M) ;
+ AssembleAddressFrom6BitSignedRelativeShortAddress(BITS(op,0x003f), ea) ;
+ sprintf(buffer, "b.%s %s (%02x)", M, ea, BITS(op,0x003f)) ;
+ retSize = 1 ;
+ break ;
+ }
+ }
+ else
+ {
+ if (BITS(op,0x0010) == 0x0)
+ {
+ // MOVE(C) - 0011 1WDD DDD0 MMRR
+ DecodeDDDDDTable(BITS(op,0x03e0), SD) ;
+ Rnum = DecodeRRTable(BITS(op,0x0003)) ;
+ AssembleeaFromMMTable(BITS(op,0x000c), Rnum, ea) ;
+ AssembleArgumentsFromWTable(BITS(op,0x0400), args, 'X', SD, ea) ;
+ sprintf(buffer, "move(c) %s", args) ;
+ retSize = 1 ;
+ }
+ else
+ {
+ if (BITS(op,0x0004) == 0x0)
+ {
+ // MOVE(C) - 0011 1WDD DDD1 q0RR
+ DecodeDDDDDTable(BITS(op,0x03e0), SD) ;
+ Rnum = DecodeRRTable(BITS(op,0x0003)) ;
+ AssembleeaFromqTable(BITS(op,0x0008), Rnum, ea) ;
+ AssembleArgumentsFromWTable(BITS(op,0x0400), args, 'X', SD, ea) ;
+ sprintf(buffer, "move(c) %s", args) ;
+ retSize = 1 ;
+ }
+ else
+ {
+ switch(BITS(op,0x0006))
+ {
+ // MOVE(C) - 0011 1WDD DDD1 t10- xxxx xxxx xxxx xxxx
+ case 0x2:
+ DecodeDDDDDTable(BITS(op,0x03e0), SD) ;
+ AssembleeaFromtTable(BITS(op,0x0008), oprom[2] | (oprom[3] << 8), ea) ;
+ // !!! I'm pretty sure this is in the right order - same issue as the WTables !!!
+ if (BITS(op,0x0400)) // fixed - 02/03/05
+ sprintf(args, "%s,%s", ea, SD) ;
+ else
+ sprintf(args, "%s,%s", SD, ea) ;
+ sprintf(buffer, "move(c) %s", args) ;
+ retSize = 2 ;
+ break ;
+
+ // MOVE(C) - 0011 1WDD DDD1 Z11-
+ case 0x3:
+ DecodeDDDDDTable(BITS(op,0x03e0), SD) ;
+ DecodeZTable(BITS(op,0x0008), ea) ; // Fixed - 11/26/06
+ AssembleArgumentsFromWTable(BITS(op,0x0400), args, 'X', SD, ea) ;
+ sprintf(buffer, "move(c) %s", args) ;
+ retSize = 1 ;
+ break ;
+ }
+ }
+ }
+ }
+
+ return retSize ;
+}
+
+
+static unsigned DecodeSpecialOpcode(char *buffer, UINT16 op, unsigned pc, const UINT8 *oprom)
+{
+ unsigned retSize = 0 ;
+
+ char S1[32] ;
+ char SD[32] ;
+ char M[32] ;
+ char args[32] ;
+ char ea[32] ;
+ int Rnum ;
+
+ if (BITS(op,0x0ff0) == 0x0)
+ {
+ switch (BITS(op,0x000f))
+ {
+ // NOP - 0000 0000 0000 0000
+ case 0x0:
+ sprintf(buffer, "nop") ;
+ retSize = 1 ;
+ break ;
+
+ // Debug - 0000 0000 0000 0001
+ case 0x1:
+/* sprintf(buffer, "debug") ;
+ retSize = 1 ;
+*/ break ;
+
+ // DO FOREVER - 0000 0000 0000 0010 xxxx xxxx xxxx xxxx
+ case 0x2:
+ sprintf(buffer, "doForever %04x", oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+ break ;
+
+ // chkaau - 0000 0000 0000 0100
+ case 0x4:
+/* sprintf(buffer, "chkaau") ;
+ retSize = 1 ;
+*/ break ;
+
+ // SWI - 0000 0000 0000 0101
+ case 0x5:
+/* sprintf(buffer, "swi") ;
+ retSize = 1 ;
+*/ break ;
+
+ // RTS - 0000 0000 0000 0110
+ case 0x6:
+ sprintf(buffer, "rts") ;
+ retSize = 1 | DASMFLAG_STEP_OUT;
+ break ;
+
+ // RTI - 0000 0000 0000 0111
+ case 0x7:
+ sprintf(buffer, "rti") ;
+ retSize = 1 | DASMFLAG_STEP_OUT;
+ break ;
+
+ // RESET - 0000 0000 0000 1000
+ case 0x8:
+/* sprintf(buffer, "reset") ;
+ retSize = 1 ;
+*/ break ;
+
+ // Enddo - 0000 0000 0000 1001
+ case 0x9:
+/* sprintf(buffer, "endDo") ;
+ retSize = 1 ;
+*/ break ;
+
+ // STOP - 0000 0000 0000 1010
+ case 0xa:
+/* sprintf(buffer, "stop") ;
+ retSize = 1 ;
+*/ break ;
+
+ // WAIT - 0000 0000 0000 1011
+ case 0xb:
+/* sprintf(buffer, "wait") ;
+ retSize = 1 ;
+*/ break ;
+
+ // ILLEGAL - 0000 0000 0000 1111
+ case 0xf:
+/* sprintf(buffer, "illegal") ;
+ retSize = 1 ;
+*/ break ;
+
+ }
+ }
+ else if (BITS(op,0x0f00) == 0x0)
+ {
+ switch(BITS(op,0x00e0))
+ {
+ case 0x2:
+ // DEBUG.cc - 0000 0000 0101 cccc
+/* DecodeccccTable(BITS(op,0x000f), M) ;
+ sprintf(buffer, "debug.%s", M) ;
+ retSize = 1 ;
+*/ break ;
+
+ case 0x6:
+ // DO - 0000 0000 110- --RR xxxx xxxx xxxx xxxx
+/* Rnum = DecodeRRTable(BITS(op,0x0003)) ;
+ sprintf(buffer, "do X:(R%d),%02x", Rnum, oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+*/ break ;
+
+ case 0x7:
+ // REP - 0000 0000 111- --RR
+/* Rnum = DecodeRRTable(BITS(op,0x0003)) ;
+ sprintf(buffer, "rep X:(R%d)", Rnum) ;
+ retSize = 1 ;
+*/ break ;
+ }
+ }
+ else if (BITS(op,0x0f00) == 0x1)
+ {
+ if (BITS(op,0x00f0) == 0x1)
+ {
+ // BRK.cc - 0000 0001 0001 cccc
+/* DecodeccccTable(BITS(op,0x000f), M) ;
+ sprintf(buffer, "brk.%s", M) ;
+ retSize = 1 ;
+*/ }
+ else if (BITS(op,0x00f0) == 0x2)
+ {
+ switch(BITS(op,0x000c)) // Consolidation can happen here
+ {
+ // JSR - 0000 0001 0010 00RR
+ case 0x0:
+/* Rnum = DecodeRRTable(BITS(op,0x0003)) ;
+ sprintf(buffer, "jsr R%d", Rnum) ;
+ retSize = 1 ; // I think aaron guessed incorrectly? | DASMFLAG_STEP_OVER;
+*/ break ;
+
+ // JMP - 0000 0001 0010 01RR
+ case 0x1:
+ Rnum = DecodeRRTable(BITS(op,0x0003)) ;
+ sprintf(buffer, "jmp R%d", Rnum) ;
+ retSize = 1 ;
+ break ;
+
+ // BSR - 0000 0001 0010 10RR
+ case 0x2:
+/* Rnum = DecodeRRTable(BITS(op,0x0003)) ;
+ sprintf(buffer, "bsr R%d", Rnum) ;
+ retSize = 1 | DASMFLAG_STEP_OVER;
+*/ break ;
+
+ // BRA - 0000 0001 0010 11RR
+ case 0x3:
+/* Rnum = DecodeRRTable(BITS(op,0x0003)) ;
+ sprintf(buffer, "bra R%d", Rnum) ;
+ retSize = 1 ;
+*/ break ;
+ }
+ }
+ else if (BITS(op,0x00f0) == 0x3)
+ {
+ switch(BITS(op,0x000c))
+ {
+ // JSR - 0000 0001 0011 00-- xxxx xxxx xxxx xxxx
+ case 0x0:
+ sprintf(buffer, "jsr %04x", oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 | DASMFLAG_STEP_OVER;
+ break ;
+
+ // JMP - 0000 0001 0011 01-- xxxx xxxx xxxx xxxx
+ case 0x1:
+ sprintf(buffer, "jmp %04x", oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+ break ;
+
+ // BSR - 0000 0001 0011 10-- xxxx xxxx xxxx xxxx
+ case 0x2:
+ sprintf(buffer, "bsr %d (0x%04x)", oprom[2] | (oprom[3] << 8), oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 | DASMFLAG_STEP_OVER;
+ break ;
+
+ // BRA - 0000 0001 0011 11-- xxxx xxxx xxxx xxxx
+ case 0x3:
+/* sprintf(buffer, "bra %d (%04x)", oprom[2] | (oprom[3] << 8), oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+*/ break ;
+ }
+ }
+ else if (BITS(op,0x00f0) == 0x5)
+ {
+ // REP.cc - 0000 0001 0101 cccc
+/* DecodeccccTable(BITS(op,0x000f), M) ;
+ sprintf(buffer, "rep.%s", M) ;
+ retSize = 1 ;
+*/ // !!! Should I decode the next instruction and put it here ??? probably...
+ }
+ else if (BITS(op,0x0080) == 0x1)
+ {
+ // LEA - 0000 0001 10TT MMRR - 0000 0001 11NN MMRR
+/* Rnum = DecodeRRTable(BITS(op,0x0030)) ;
+ AssembleeaFromMMTable(BITS(op,0x000c), BITS(op,0x0003), ea) ;
+ if (BITS(op,0x0040))
+ sprintf(buffer, "lea %s,R%d", ea, Rnum) ;
+ else
+ sprintf(buffer, "lea %s,N%d", ea, Rnum) ;
+ retSize = 1 ;
+*/ }
+ }
+ else if (BITS(op,0x0e00) == 0x1)
+ {
+
+ if (BITS(op,0x0020) == 0x0)
+ {
+ // MOVE(M) - 0000 001W RR0M MHHH
+ Rnum = DecodeRRTable(BITS(op,0x00c0)) ;
+ DecodeHHHTable(BITS(op,0x0007), SD) ;
+ AssembleeaFromMMTable(BITS(op,0x0018), Rnum, ea) ;
+ AssembleArgumentsFromWTable(BITS(op,0x0100), args, 'P', SD, ea) ;
+ sprintf(buffer, "move(m) %s", args) ;
+ // !!! The docs list the read/write order backwards for all move(m)'s - crackbabies ???
+ retSize = 1 ;
+ }
+ else
+ {
+ // MOVE(M) - 0000 001W RR11 mmRR
+/* AssembleeaFrommmTable(BITS(op,0x000c), BITS(op,0x00c0), BITS(op,0x0003), ea, ea2) ;
+ sprintf(SD, "P:%s", ea) ;
+ AssembleArgumentsFromWTable(BITS(op,0x0100), args, 'X', SD, ea2) ;
+ // !!! The docs list the read/write order backwards for all move(m)'s - crackbabies ???
+ sprintf(buffer, "move(m) %s", args) ;
+ retSize = 1 ;
+*/ }
+ }
+ else if (BITS(op,0x0f00) == 0x4)
+ {
+ if (BITS(op,0x0020) == 0x0)
+ {
+ // DO - 0000 0100 000D DDDD xxxx xxxx xxxx xxxx
+ DecodeDDDDDTable(BITS(op,0x001f), S1) ;
+ sprintf(buffer, "do %s,%04x", S1, oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+ }
+ else
+ {
+ // REP - 0000 0100 001D DDDD
+ DecodeDDDDDTable(BITS(op,0x001f), S1) ;
+ sprintf(buffer, "rep %s", S1) ;
+ retSize = 1 ;
+ }
+ }
+ else if (BITS(op,0x0f00) == 0x5)
+ {
+ UINT8 B ;
+ UINT16 op2 = oprom[2] | (oprom[3] << 8) ;
+
+ if (BITS(op2,0xfe20) == 0x02)
+ {
+ // MOVE(M) - 0000 0101 BBBB BBBB | 0000 001W --0- -HHH
+ B = BITS(op,0x00ff) ;
+ DecodeHHHTable(BITS(op2,0x0007), SD) ;
+ AssembleRegFromWTable(BITS(op2,0x0100), args, 'P', SD, B) ;
+ sprintf(buffer, "move(m) %s", args) ;
+ // !!! The docs list the read/write order backwards for all move(m)'s - crackbabies ???
+ retSize = 2 ;
+ }
+ else if (BITS(op2,0xf810) == 0x0e)
+ {
+ // MOVE(C) - 0000 0101 BBBB BBBB | 0011 1WDD DDD0 ----
+/* B = BITS(op,0x00ff) ;
+ DecodeDDDDDTable(BITS(op2,0x03e0), SD) ;
+ AssembleRegFromWTable(BITS(op2,0x0400), args, 'X', SD, B) ;
+ sprintf(buffer, "move(c) %s", args) ;
+ retSize = 2 ;
+*/ }
+ else if (BITS(op2,0x00ff) == 0x11)
+ {
+ // MOVE - 0000 0101 BBBB BBBB | ---- HHHW 0001 0001
+/* B = BITS(op,0x00ff) ;
+ DecodeHHHTable(BITS(op2,0x0e00), SD) ;
+ AssembleRegFromWTable(BITS(op2,0x0100), args, 'X', SD, B) ;
+ sprintf(buffer, "move %s", args) ;
+ retSize = 2 ;
+*/ }
+ }
+ else if (BITS(op,0x0f00) == 0x6)
+ {
+ switch(BITS(op,0x0030))
+ {
+ case 0x0:
+ // JS.cc - 0000 0110 RR00 cccc
+/* DecodeccccTable(BITS(op,0x000f), M) ;
+ Rnum = DecodeRRTable(BITS(op,0x00c0)) ;
+ sprintf(buffer, "js.%s R%d\n", M, Rnum) ;
+ retSize = 1 ;
+*/ break ;
+
+ case 0x1:
+ // JS.cc - 0000 0110 --01 cccc xxxx xxxx xxxx xxxx
+/* DecodeccccTable(BITS(op,0x000f), M) ;
+ sprintf(buffer, "js.%s %04x", M, oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+*/ break ;
+
+ case 0x2:
+ // J.cc - 0000 0110 RR10 cccc
+/* DecodeccccTable(BITS(op,0x000f), M) ;
+ Rnum = DecodeRRTable(BITS(op,0x00c0)) ;
+ sprintf(buffer, "j.%s R%d", M, Rnum) ;
+ retSize = 1 ;
+*/ break ;
+
+ case 0x3:
+ // J.cc - 0000 0110 --11 cccc xxxx xxxx xxxx xxxx
+/* DecodeccccTable(BITS(op,0x000f), M) ;
+ sprintf(buffer, "j.%s %04x", M, oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+*/ break ;
+ }
+ }
+ else if (BITS(op,0x0f00) == 0x7)
+ {
+ switch(BITS(op,0x0030))
+ {
+ case 0x0:
+ // BS.cc - 0000 0111 RR00 cccc
+/* DecodeccccTable(BITS(op,0x000f), M) ;
+ Rnum = DecodeRRTable(BITS(op,0x00c0)) ;
+ sprintf(buffer, "bs.%s R%d\n", M, Rnum) ;
+ retSize = 1 ;
+*/ break ;
+
+ case 0x1:
+ // BS.cc - 0000 0111 --01 cccc xxxx xxxx xxxx xxxx
+ DecodeccccTable(BITS(op,0x000f), M) ;
+ sprintf(buffer, "bs.%s %d (0x%04x)", M, (INT16)(oprom[2] | (oprom[3] << 8)), oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+ break ;
+
+ case 0x2:
+ // B.cc - 0000 0111 RR10 cccc
+/* DecodeccccTable(BITS(op,0x000f), M) ;
+ Rnum = DecodeRRTable(BITS(op,0x00c0)) ;
+ sprintf(buffer, "b.%s R%d", M, Rnum) ;
+ retSize = 1 ;
+*/ break ;
+
+ case 0x3:
+ // B.cc - 0000 0111 --11 cccc xxxx xxxx xxxx xxxx
+ DecodeccccTable(BITS(op,0x000f), M) ;
+ sprintf(buffer, "b.%s %04x (%d)", M, oprom[2] | (oprom[3] << 8), oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+ break ;
+ }
+ }
+ else if (BITS(op,0x0800))
+ {
+ switch (BITS(op,0x0700))
+ {
+ // JSR - 0000 1010 AAAA AAAA
+ case 0x2:
+/* sprintf(buffer, "jsr %02x", BITS(op,0x00ff)) ;
+ retSize = 1 ;
+*/ break ;
+
+ // BRA - 0000 1011 aaaa aaaa
+ case 0x3:
+ sprintf(buffer, "bra %d (0x%02x)", (INT8)BITS(op,0x00ff), BITS(op,0x00ff)) ;
+ retSize = 1 ;
+ break ;
+
+ // MOVE(P) - 0000 110W RRmp pppp
+ case 0x4: case 0x5:
+ {
+ char fullAddy[128] ; // Convert Short Absolute Address to full 16-bit
+ Rnum = DecodeRRTable(BITS(op,0x00c0)) ;
+ AssembleeaFrommTable(BITS(op,0x0020), Rnum, ea) ;
+
+ AssembleAddressFromIOShortAddress(BITS(op,0x001f), fullAddy) ;
+
+ sprintf(SD, "X:%02x (%s)", BITS(op,0x001f), fullAddy) ;
+
+ // !! order (pretty sure pp is S/D in the docs) !!
+ AssembleArgumentsFromWTable(BITS(op,0x0100), args, 'X', SD, ea) ;
+ sprintf(buffer, "move(p) %s", args) ;
+ retSize = 1 ;
+ break ;
+ }
+
+ // DO - 0000 1110 iiii iiii xxxx xxxx xxxx xxxx
+ case 0x6:
+ sprintf(buffer, "do #%02x,%04x", BITS(op,0x00ff), oprom[2] | (oprom[3] << 8)) ;
+ retSize = 2 ;
+ break ;
+
+ // REP - 0000 1111 iiii iiii
+ case 0x7:
+ sprintf(buffer, "rep #%02x", BITS(op,0x00ff)) ;
+ retSize = 1 ;
+ break ;
+ }
+ }
+
+ return retSize ;
+}
+
+
+
+
+
+////////////////////////////////////////
+// PARALLEL MEMORY OPERATION DECODING //
+////////////////////////////////////////
+
+static void AppendXMDM(char *buffer, UINT16 op)
+{
+ int Rnum ;
+ char SD[32] ;
+ char ea[32] ;
+ char args[32] ;
+
+ // 1mRR HHHW ---- ----
+ Rnum = DecodeRRTable(BITS(op,0x3000)) ;
+ DecodeHHHTable(BITS(op,0x0e00), SD) ;
+ AssembleeaFrommTable(BITS(op,0x4000), Rnum, ea) ;
+ AssembleArgumentsFromWTable(BITS(op,0x0100), args, 'X', SD, ea) ;
+
+ strcat(buffer, " ") ;
+ strcat(buffer, args) ;
+}
+
+// !!! NOT FULLY IMPLEMENTED !!!
+static void AppendXMDMSpecial(char *buffer, UINT16 op, char *working)
+{
+ // This is actually a little tricky 'cuz X:(F1) comes from the 'Data ALU' operation...
+ // (page 326 of the family manual)
+
+ // !! Also, p326 mentions 'F1' is the upper word of the accumulator which is not used by the parallel data ALU operation
+ // (in case of no Data ALU operation, A1 is chosen as F)
+ // my question is : when is there .not. a Data ALU operation ??
+
+ char SD[32] ;
+ char args[32] ;
+ char dest[32] ;
+
+ if (working[0] == 'B')
+ sprintf(dest, "(A1)") ;
+ else if (working[0] == 'A')
+ sprintf(dest, "(B1)") ;
+ else
+ sprintf(dest, "(wtf)") ;
+
+ DecodeHHHTable(BITS(op,0x0e00), SD) ;
+ AssembleArgumentsFromWTable(BITS(op,0x0100), args, 'X', SD, dest) ;
+
+ strcat(buffer, " ") ;
+ strcat(buffer, args) ;
+}
+
+static void AppendARU(char *buffer, UINT16 op)
+{
+ char ea[32] ;
+ int rr = DecodeRRTable(BITS(op,0x0300)) ;
+
+ AssembleeaFromzTable(BITS(op,0x0400), rr, ea) ;
+
+ strcat(buffer, ea) ;
+}
+
+static void AppendRRDM(char *buffer, UINT16 op, char *working)
+{
+ char S[32], D[32] ;
+ char final[128] ;
+
+ DecodeIIIITable(BITS(op,0x0f00), S, D) ;
+
+ if (D[0] == '^')
+ {
+ if (working[0] == 'B')
+ sprintf(D, "A") ;
+ else if (working[0] == 'A')
+ sprintf(D, "B") ;
+ else
+ sprintf(D, "(wtf)") ;
+ }
+
+ if (S[0] == 'F')
+ {
+ sprintf(S, "%s", working) ;
+ }
+
+ sprintf(final, "%s,%s", S, D) ;
+
+ strcat(buffer, " ") ;
+ strcat(buffer, final) ;
+}
+
+#ifdef UNUSED_FUNCTION
+static void AppendDXMDR(char *buffer, UINT16 op)
+{
+ char D1[32] ;
+ char D2[32] ;
+ char ea1[32] ;
+ char ea2[32] ;
+ int Rnum ;
+
+ char temp[128] ;
+
+ // 011m mKKK -rr- ----
+ Rnum = BITS(op,0x0060) ;
+ DecodeKKKTable(BITS(op,0x0700), D1, D2) ;
+ AssembleeaFrommmTable(BITS(op,0x1800), Rnum, 3, ea1, ea2) ;
+
+ sprintf(temp, " X:%s,%s X:%s,%s", ea1, D1, ea2, D2) ;
+ strcat(buffer, temp) ;
+}
+#endif
+
+
+
+/////////////////////////////
+// TABLE DECODER FUNCTIONS //
+/////////////////////////////
+
+static int DecodeBBBTable(UINT16 BBB)
+{
+ switch(BBB)
+ {
+ case 0x4: return BBB_UPPER ; break ;
+ case 0x2: return BBB_MIDDLE ; break ;
+ case 0x1: return BBB_LOWER ; break ;
+ }
+
+ return BBB_LOWER ; // Not really safe...
+}
+
+static void DecodeccccTable(UINT16 cccc, char *mnemonic)
+{
+ switch (cccc)
+ {
+ case 0x0: sprintf(mnemonic, "cc(hs)") ; break ;
+ case 0x1: sprintf(mnemonic, "ge ") ; break ;
+ case 0x2: sprintf(mnemonic, "ne ") ; break ;
+ case 0x3: sprintf(mnemonic, "pl ") ; break ;
+ case 0x4: sprintf(mnemonic, "nn ") ; break ;
+ case 0x5: sprintf(mnemonic, "ec ") ; break ;
+ case 0x6: sprintf(mnemonic, "lc ") ; break ;
+ case 0x7: sprintf(mnemonic, "gt ") ; break ;
+ case 0x8: sprintf(mnemonic, "cs(lo)") ; break ;
+ case 0x9: sprintf(mnemonic, "lt ") ; break ;
+ case 0xa: sprintf(mnemonic, "eq ") ; break ;
+ case 0xb: sprintf(mnemonic, "mi ") ; break ;
+ case 0xc: sprintf(mnemonic, "nr ") ; break ;
+ case 0xd: sprintf(mnemonic, "es ") ; break ;
+ case 0xe: sprintf(mnemonic, "ls ") ; break ;
+ case 0xf: sprintf(mnemonic, "le ") ; break ;
+ }
+}
+
+static void DecodeDDDDDTable(UINT16 DDDDD, char *SD)
+{
+ switch(DDDDD)
+ {
+ case 0x00: sprintf(SD, "X0") ; break ;
+ case 0x01: sprintf(SD, "Y0") ; break ;
+ case 0x02: sprintf(SD, "X1") ; break ;
+ case 0x03: sprintf(SD, "Y1") ; break ;
+ case 0x04: sprintf(SD, "A") ; break ;
+ case 0x05: sprintf(SD, "B") ; break ;
+ case 0x06: sprintf(SD, "A0") ; break ;
+ case 0x07: sprintf(SD, "B0") ; break ;
+ case 0x08: sprintf(SD, "LC") ; break ;
+ case 0x09: sprintf(SD, "SR") ; break ;
+ case 0x0a: sprintf(SD, "OMR") ; break ;
+ case 0x0b: sprintf(SD, "SP") ; break ;
+ case 0x0c: sprintf(SD, "A1") ; break ;
+ case 0x0d: sprintf(SD, "B1") ; break ;
+ case 0x0e: sprintf(SD, "A2") ; break ;
+ case 0x0f: sprintf(SD, "B2") ; break ;
+
+ case 0x10: sprintf(SD, "R0") ; break ;
+ case 0x11: sprintf(SD, "R1") ; break ;
+ case 0x12: sprintf(SD, "R2") ; break ;
+ case 0x13: sprintf(SD, "R3") ; break ;
+ case 0x14: sprintf(SD, "M0") ; break ;
+ case 0x15: sprintf(SD, "M1") ; break ;
+ case 0x16: sprintf(SD, "M2") ; break ;
+ case 0x17: sprintf(SD, "M3") ; break ;
+ case 0x18: sprintf(SD, "SSH") ; break ;
+ case 0x19: sprintf(SD, "SSL") ; break ;
+ case 0x1a: sprintf(SD, "LA") ; break ;
+ //no 0x1b
+ case 0x1c: sprintf(SD, "N0") ; break ;
+ case 0x1d: sprintf(SD, "N1") ; break ;
+ case 0x1e: sprintf(SD, "N2") ; break ;
+ case 0x1f: sprintf(SD, "N3") ; break ;
+ }
+}
+
+static void DecodeDDTable(UINT16 DD, char *SD)
+{
+ switch (DD)
+ {
+ case 0x0: sprintf(SD, "X0") ; break ;
+ case 0x1: sprintf(SD, "Y0") ; break ;
+ case 0x2: sprintf(SD, "X1") ; break ;
+ case 0x3: sprintf(SD, "Y1") ; break ;
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+static void DecodeDDFTable(UINT16 DD, UINT16 F, char *S, char *D)
+{
+ UINT16 switchVal = (DD << 1) | F ;
+
+ switch (switchVal)
+ {
+ case 0x0: sprintf(S, "X0") ; sprintf(D, "A") ; break ;
+ case 0x1: sprintf(S, "X0") ; sprintf(D, "B") ; break ;
+ case 0x2: sprintf(S, "Y0") ; sprintf(D, "A") ; break ;
+ case 0x3: sprintf(S, "Y0") ; sprintf(D, "B") ; break ;
+ case 0x4: sprintf(S, "X1") ; sprintf(D, "A") ; break ;
+ case 0x5: sprintf(S, "X1") ; sprintf(D, "B") ; break ;
+ case 0x6: sprintf(S, "Y1") ; sprintf(D, "A") ; break ;
+ case 0x7: sprintf(S, "Y1") ; sprintf(D, "B") ; break ;
+ }
+}
+#endif
+
+static void DecodeEETable(UINT16 EE, char *D)
+{
+ switch(EE)
+ {
+ case 0x1: sprintf(D, "MR") ; break ;
+ case 0x3: sprintf(D, "CCR") ; break ;
+ case 0x2: sprintf(D, "OMR") ; break ;
+ }
+}
+
+static void DecodeFTable(UINT16 F, char *SD)
+{
+ switch(F)
+ {
+ case 0x0: sprintf(SD, "A") ; break ;
+ case 0x1: sprintf(SD, "B") ; break ;
+ }
+}
+
+static void Decodeh0hFTable(UINT16 h0h, UINT16 F, char *S, char *D)
+{
+ UINT16 switchVal = (h0h << 1) | F ;
+
+ switch (switchVal)
+ {
+ case 0x8: sprintf(S, "X0") ; sprintf(D, "A") ; break ;
+ case 0x9: sprintf(S, "X0") ; sprintf(D, "B") ; break ;
+ case 0xa: sprintf(S, "Y0") ; sprintf(D, "A") ; break ;
+ case 0xb: sprintf(S, "Y0") ; sprintf(D, "B") ; break ;
+ case 0x2: sprintf(S, "A") ; sprintf(D, "A") ; break ;
+ case 0x1: sprintf(S, "A") ; sprintf(D, "B") ; break ;
+ case 0x0: sprintf(S, "B") ; sprintf(D, "A") ; break ;
+ case 0x3: sprintf(S, "B") ; sprintf(D, "B") ; break ;
+ }
+}
+
+static void DecodeHHTable(UINT16 HH, char *SD)
+{
+ switch(HH)
+ {
+ case 0x0: sprintf(SD, "X0") ; break ;
+ case 0x1: sprintf(SD, "Y0") ; break ;
+ case 0x2: sprintf(SD, "A") ; break ;
+ case 0x3: sprintf(SD, "B") ; break ;
+ }
+}
+
+static void DecodeHHHTable(UINT16 HHH, char *SD)
+{
+ switch(HHH)
+ {
+ case 0x0: sprintf(SD, "X0") ; break ;
+ case 0x1: sprintf(SD, "Y0") ; break ;
+ case 0x2: sprintf(SD, "X1") ; break ;
+ case 0x3: sprintf(SD, "Y1") ; break ;
+ case 0x4: sprintf(SD, "A") ; break ;
+ case 0x5: sprintf(SD, "B") ; break ;
+ case 0x6: sprintf(SD, "A0") ; break ;
+ case 0x7: sprintf(SD, "B0") ; break ;
+ }
+}
+
+// I don't know if this is ever used?
+static void DecodeIIIITable(UINT16 IIII, char *S, char *D)
+{
+ switch(IIII)
+ {
+ case 0x0: sprintf(S, "X0") ; sprintf(D, "^F^") ; break ;
+ case 0x1: sprintf(S, "Y0") ; sprintf(D, "^F^") ; break ;
+ case 0x2: sprintf(S, "X1") ; sprintf(D, "^F^") ; break ;
+ case 0x3: sprintf(S, "Y1") ; sprintf(D, "^F^") ; break ;
+ case 0x4: sprintf(S, "A") ; sprintf(D, "X0") ; break ;
+ case 0x5: sprintf(S, "B") ; sprintf(D, "Y0") ; break ;
+ case 0x6: sprintf(S, "A0") ; sprintf(D, "X0") ; break ;
+ case 0x7: sprintf(S, "B0") ; sprintf(D, "Y0") ; break ;
+ case 0x8: sprintf(S, "F") ; sprintf(D, "^F^") ; break ;
+ case 0x9: sprintf(S, "F") ; sprintf(D, "^F^") ; break ;
+ case 0xc: sprintf(S, "A") ; sprintf(D, "X1") ; break ;
+ case 0xd: sprintf(S, "B") ; sprintf(D, "Y1") ; break ;
+ case 0xe: sprintf(S, "A0") ; sprintf(D, "X1") ; break ;
+ case 0xf: sprintf(S, "B0") ; sprintf(D, "Y1") ; break ;
+ }
+}
+
+static void DecodeJJJFTable(UINT16 JJJ, UINT16 F, char *S, char *D)
+{
+ UINT16 switchVal = (JJJ << 1) | F ;
+
+ switch(switchVal)
+ {
+ case 0x0: sprintf(S, "B") ; sprintf(D, "A") ; break ;
+ case 0x1: sprintf(S, "A") ; sprintf(D, "B") ; break ;
+ case 0x4: sprintf(S, "X") ; sprintf(D, "A") ; break ;
+ case 0x5: sprintf(S, "X") ; sprintf(D, "B") ; break ;
+ case 0x6: sprintf(S, "Y") ; sprintf(D, "A") ; break ;
+ case 0x7: sprintf(S, "Y") ; sprintf(D, "B") ; break ;
+ case 0x8: sprintf(S, "X0") ; sprintf(D, "A") ; break ;
+ case 0x9: sprintf(S, "X0") ; sprintf(D, "B") ; break ;
+ case 0xa: sprintf(S, "Y0") ; sprintf(D, "A") ; break ;
+ case 0xb: sprintf(S, "Y0") ; sprintf(D, "B") ; break ;
+ case 0xc: sprintf(S, "X1") ; sprintf(D, "A") ; break ;
+ case 0xd: sprintf(S, "X1") ; sprintf(D, "B") ; break ;
+ case 0xe: sprintf(S, "Y1") ; sprintf(D, "A") ; break ;
+ case 0xf: sprintf(S, "Y1") ; sprintf(D, "B") ; break ;
+ }
+}
+
+static void DecodeJJFTable(UINT16 JJ, UINT16 F, char *S, char *D)
+{
+ UINT16 switchVal = (JJ << 1) | F ;
+
+ switch (switchVal)
+ {
+ case 0x0: sprintf(S, "X0") ; sprintf(D, "A") ; break ;
+ case 0x1: sprintf(S, "X0") ; sprintf(D, "B") ; break ;
+ case 0x2: sprintf(S, "Y0") ; sprintf(D, "A") ; break ;
+ case 0x3: sprintf(S, "Y0") ; sprintf(D, "B") ; break ;
+ case 0x4: sprintf(S, "X1") ; sprintf(D, "A") ; break ;
+ case 0x5: sprintf(S, "X1") ; sprintf(D, "B") ; break ;
+ case 0x6: sprintf(S, "Y1") ; sprintf(D, "A") ; break ;
+ case 0x7: sprintf(S, "Y1") ; sprintf(D, "B") ; break ;
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+static void DecodeJFTable(UINT16 J, UINT16 F, char *S, char *D)
+{
+ UINT16 switchVal = (J << 1) | F ;
+
+ switch(switchVal)
+ {
+ case 0x0: sprintf(S, "X") ; sprintf(D, "A") ; break ;
+ case 0x1: sprintf(S, "X") ; sprintf(D, "B") ; break ;
+ case 0x2: sprintf(S, "Y") ; sprintf(D, "A") ; break ;
+ case 0x3: sprintf(S, "Y") ; sprintf(D, "B") ; break ;
+ }
+}
+
+static void DecodekTable(UINT16 k, char *Dnot)
+{
+ switch(k)
+ {
+ case 0x0: sprintf(Dnot, "B") ; break ;
+ case 0x1: sprintf(Dnot, "A") ; break ;
+ }
+}
+
+static void DecodekSignTable(UINT16 k, char *plusMinus)
+{
+ switch(k)
+ {
+ case 0x0: sprintf(plusMinus, "+") ; break ;
+ case 0x1: sprintf(plusMinus, "-") ; break ;
+ }
+}
+
+static void DecodeKKKTable (UINT16 KKK, char *D1, char *D2)
+{
+ switch(KKK)
+ {
+ case 0x0: sprintf(D1, "^F^") ; sprintf(D2, "X0") ; break ;
+ case 0x1: sprintf(D1, "Y0") ; sprintf(D2, "X0") ; break ;
+ case 0x2: sprintf(D1, "X1") ; sprintf(D2, "X0") ; break ;
+ case 0x3: sprintf(D1, "Y1") ; sprintf(D2, "X0") ; break ;
+ case 0x4: sprintf(D1, "X0") ; sprintf(D2, "X1") ; break ;
+ case 0x5: sprintf(D1, "Y0") ; sprintf(D2, "X1") ; break ;
+ case 0x6: sprintf(D1, "^F^") ; sprintf(D2, "Y0") ; break ;
+ case 0x7: sprintf(D1, "Y1") ; sprintf(D2, "X1") ; break ;
+ }
+}
+
+static int DecodeNNTable(UINT16 NN)
+{
+ return NN ;
+}
+
+static void DecodeQQFTable(UINT16 QQ, UINT16 F, char *S1, char *S2, char *D)
+{
+ UINT16 switchVal = (QQ << 1) | F ;
+
+ switch(switchVal)
+ {
+ case 0x0: sprintf(S1, "X0") ; sprintf(S2, "Y0") ; sprintf(D, "A") ; break ;
+ case 0x1: sprintf(S1, "X0") ; sprintf(S2, "Y0") ; sprintf(D, "B") ; break ;
+ case 0x2: sprintf(S1, "X0") ; sprintf(S2, "Y1") ; sprintf(D, "A") ; break ;
+ case 0x3: sprintf(S1, "X0") ; sprintf(S2, "Y1") ; sprintf(D, "B") ; break ;
+ case 0x4: sprintf(S1, "X1") ; sprintf(S2, "Y0") ; sprintf(D, "A") ; break ;
+ case 0x5: sprintf(S1, "X1") ; sprintf(S2, "Y0") ; sprintf(D, "B") ; break ;
+ case 0x6: sprintf(S1, "X1") ; sprintf(S2, "Y1") ; sprintf(D, "A") ; break ;
+ case 0x7: sprintf(S1, "X1") ; sprintf(S2, "Y1") ; sprintf(D, "B") ; break ;
+ }
+}
+#endif
+
+static void DecodeQQFTableSp(UINT16 QQ, UINT16 F, char *S1, char *S2, char *D)
+{
+ UINT16 switchVal = (QQ << 1) | F ;
+
+ switch(switchVal)
+ {
+ case 0x0: sprintf(S1, "Y0") ; sprintf(S2, "X0") ; sprintf(D, "A") ; break ;
+ case 0x1: sprintf(S1, "Y0") ; sprintf(S2, "X0") ; sprintf(D, "B") ; break ;
+ case 0x2: sprintf(S1, "Y1") ; sprintf(S2, "X0") ; sprintf(D, "A") ; break ;
+ case 0x3: sprintf(S1, "Y1") ; sprintf(S2, "X0") ; sprintf(D, "B") ; break ;
+ case 0x4: sprintf(S1, "X1") ; sprintf(S2, "Y0") ; sprintf(D, "A") ; break ;
+ case 0x5: sprintf(S1, "X1") ; sprintf(S2, "Y0") ; sprintf(D, "B") ; break ;
+ case 0x6: sprintf(S1, "X1") ; sprintf(S2, "Y1") ; sprintf(D, "A") ; break ;
+ case 0x7: sprintf(S1, "X1") ; sprintf(S2, "Y1") ; sprintf(D, "B") ; break ;
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+static void DecodeQQQFTable(UINT16 QQQ, UINT16 F, char *S1, char *S2, char *D)
+{
+ UINT16 switchVal = (QQQ << 1) | F ;
+
+ switch(switchVal)
+ {
+ case 0x0: sprintf(S1, "X0") ; sprintf(S2, "X0") ; sprintf(D, "A") ; break ;
+ case 0x1: sprintf(S1, "X0") ; sprintf(S2, "X0") ; sprintf(D, "B") ; break ;
+ case 0x2: sprintf(S1, "X1") ; sprintf(S2, "X0") ; sprintf(D, "A") ; break ;
+ case 0x3: sprintf(S1, "X1") ; sprintf(S2, "X0") ; sprintf(D, "B") ; break ;
+ case 0x4: sprintf(S1, "A1") ; sprintf(S2, "Y0") ; sprintf(D, "A") ; break ;
+ case 0x5: sprintf(S1, "A1") ; sprintf(S2, "Y0") ; sprintf(D, "B") ; break ;
+ case 0x6: sprintf(S1, "B1") ; sprintf(S2, "X0") ; sprintf(D, "A") ; break ;
+ case 0x7: sprintf(S1, "B1") ; sprintf(S2, "X0") ; sprintf(D, "B") ; break ;
+ case 0x8: sprintf(S1, "Y0") ; sprintf(S2, "X0") ; sprintf(D, "A") ; break ;
+ case 0x9: sprintf(S1, "Y0") ; sprintf(S2, "X0") ; sprintf(D, "B") ; break ;
+ case 0xa: sprintf(S1, "Y1") ; sprintf(S2, "X0") ; sprintf(D, "A") ; break ;
+ case 0xb: sprintf(S1, "Y1") ; sprintf(S2, "X0") ; sprintf(D, "B") ; break ;
+ case 0xc: sprintf(S1, "Y0") ; sprintf(S2, "X1") ; sprintf(D, "A") ; break ;
+ case 0xd: sprintf(S1, "Y0") ; sprintf(S2, "X1") ; sprintf(D, "B") ; break ;
+ case 0xe: sprintf(S1, "Y1") ; sprintf(S2, "X1") ; sprintf(D, "A") ; break ;
+ case 0xf: sprintf(S1, "Y1") ; sprintf(S2, "X1") ; sprintf(D, "B") ; break ;
+ }
+}
+#endif
+
+static int DecodeRRTable(UINT16 RR)
+{
+ return RR ;
+}
+
+static void DecodesTable(UINT16 s, char *arithmetic)
+{
+ switch(s)
+ {
+ case 0x0: sprintf(arithmetic, "su") ; break ;
+ case 0x1: sprintf(arithmetic, "uu") ; break ;
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+static void DecodessTable(UINT16 ss, char *arithmetic)
+{
+ switch(ss)
+ {
+ case 0x0: sprintf(arithmetic, "ss") ; break ;
+ case 0x1: sprintf(arithmetic, "ss") ; break ;
+ case 0x2: sprintf(arithmetic, "su") ; break ;
+ case 0x3: sprintf(arithmetic, "uu") ; break ;
+ }
+}
+
+static void DecodeuuuuFTable(UINT16 uuuu, UINT16 F, char *arg, char *S, char *D)
+{
+ UINT16 switchVal = (uuuu << 1) | F ;
+
+ switch(switchVal)
+ {
+ // The add and sub cases are piled on top of one another
+ case 0x00: sprintf(arg, "add") ; case 0x08: sprintf(arg, "sub") ; sprintf(S, "X0") ; sprintf(D, "A") ; break ;
+ case 0x01: sprintf(arg, "add") ; case 0x09: sprintf(arg, "sub") ; sprintf(S, "X0") ; sprintf(D, "B") ; break ;
+ case 0x02: sprintf(arg, "add") ; case 0x0a: sprintf(arg, "sub") ; sprintf(S, "Y0") ; sprintf(D, "A") ; break ;
+ case 0x03: sprintf(arg, "add") ; case 0x0b: sprintf(arg, "sub") ; sprintf(S, "Y0") ; sprintf(D, "B") ; break ;
+ case 0x04: sprintf(arg, "add") ; case 0x0c: sprintf(arg, "sub") ; sprintf(S, "X1") ; sprintf(D, "A") ; break ;
+ case 0x05: sprintf(arg, "add") ; case 0x0d: sprintf(arg, "sub") ; sprintf(S, "X1") ; sprintf(D, "B") ; break ;
+ case 0x06: sprintf(arg, "add") ; case 0x0e: sprintf(arg, "sub") ; sprintf(S, "Y1") ; sprintf(D, "A") ; break ;
+ case 0x07: sprintf(arg, "add") ; case 0x0f: sprintf(arg, "sub") ; sprintf(S, "Y1") ; sprintf(D, "B") ; break ;
+ case 0x18: sprintf(arg, "add") ; case 0x1a: sprintf(arg, "sub") ; sprintf(S, "B") ; sprintf(D, "A") ; break ;
+ case 0x19: sprintf(arg, "add") ; case 0x1b: sprintf(arg, "sub") ; sprintf(S, "A") ; sprintf(D, "B") ; break ;
+ }
+}
+#endif
+
+static void DecodeZTable(UINT16 Z, char *ea)
+{
+ // This is fixed as per the Family Manual addendum
+ switch(Z)
+ {
+ case 0x1: sprintf(ea, "(A1)") ; break ;
+ case 0x0: sprintf(ea, "(B1)") ; break ;
+ }
+}
+
+
+static void AssembleeaFrommTable(UINT16 m, int n, char *ea)
+{
+ switch(m)
+ {
+ case 0x0: sprintf(ea, "(R%d)+",n) ; break ;
+ case 0x1: sprintf(ea, "(R%d)+N%d", n, n) ; break ;
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+static void AssembleeaFrommmTable(UINT16 mm, int n1, int n2, char *ea1, char *ea2)
+{
+ switch(mm)
+ {
+ case 0x0: sprintf(ea1, "(R%d)+", n1) ;
+ sprintf(ea2, "(R%d)+", n2) ; break ;
+ case 0x1: sprintf(ea1, "(R%d)+", n1) ;
+ sprintf(ea2, "(R%d)+N%d", n2, n2) ; break ;
+ case 0x2: sprintf(ea1, "(R%d)+N%d", n1, n1) ;
+ sprintf(ea2, "(R%d)+", n2) ; break ;
+ case 0x3: sprintf(ea1, "(R%d)+N%d", n1, n1) ;
+ sprintf(ea2, "(R%d)+N%d", n2, n2) ; break ;
+ }
+}
+#endif
+
+static void AssembleeaFromMMTable(UINT16 MM, int n, char *ea)
+{
+ switch(MM)
+ {
+ case 0x0: sprintf(ea, "(R%d)", n) ; break ;
+ case 0x1: sprintf(ea, "(R%d)+", n) ; break ;
+ case 0x2: sprintf(ea, "(R%d)-", n) ; break ;
+ case 0x3: sprintf(ea, "(R%d)+N%d", n, n) ; break ;
+ }
+}
+
+static void AssembleeaFromqTable(UINT16 q, int n, char *ea)
+{
+ switch(q)
+ {
+ case 0x0: sprintf(ea, "(R%d+N%d)", n, n) ; break ;
+ case 0x1: sprintf(ea, "-(R%d)", n) ; break ;
+ }
+}
+
+static void AssembleeaFromtTable(UINT16 t, UINT16 val, char *ea)
+{
+ switch(t)
+ {
+ // !!! Looking at page 336 of UM, I'm not sure if 0 is X: or if 0 is just # !!!
+ case 0x0: sprintf(ea, "X:%04x", val) ; break ;
+ case 0x1: sprintf(ea, "#%04x", val) ; break ;
+ }
+}
+
+// Not sure if this one is even used?
+static void AssembleeaFromzTable(UINT16 z, int n, char *ea)
+{
+ switch(z)
+ {
+ case 0x0: sprintf(ea, "(R%d)-", n) ; break ;
+ case 0x1: sprintf(ea, "(R%d)+N%d", n, n) ; break ;
+ }
+}
+
+static void AssembleDFromPTable(UINT16 P, UINT16 ppppp, char *D)
+{
+ char fullAddy[128] ; // Convert Short Absolute Address to full 16-bit
+
+ switch(P)
+ {
+ case 0x0: sprintf(D, "X:%02x", ppppp) ; break ;
+ case 0x1:
+ AssembleAddressFromIOShortAddress(ppppp, fullAddy) ;
+ sprintf(D, "X:%02x (%s)", ppppp, fullAddy) ;
+ break ;
+ }
+}
+
+static void AssembleArgumentsFromWTable(UINT16 W, char *args, char ma, char *SD, char *ea)
+{
+ switch(W)
+ {
+ case 0x0: sprintf(args, "%s,%c:%s", SD, ma, ea) ; break ;
+ case 0x1: sprintf(args, "%c:%s,%s", ma, ea, SD) ; break ;
+ }
+}
+
+static void AssembleRegFromWTable(UINT16 W, char *args, char ma, char *SD, UINT8 xx)
+{
+ switch(W)
+ {
+ case 0x0: sprintf(args, "%s,%c:(R2+%02x)", SD, ma, xx) ; break ;
+ case 0x1: sprintf(args, "%c:(R2+%02x),%s", ma, xx, SD) ; break ;
+ }
+}
+
+static void AssembleAddressFromIOShortAddress(UINT16 pp, char *ea)
+{
+ UINT16 fullAddy = 0xffe0 ;
+ fullAddy |= pp ;
+
+ sprintf(ea, "%.04x", fullAddy) ;
+}
+
+static void AssembleAddressFrom6BitSignedRelativeShortAddress(UINT16 srs, char *ea)
+{
+ UINT16 fullAddy = srs ;
+ if (fullAddy & 0x0020) fullAddy |= 0xffc0 ;
+
+ sprintf(ea, "%d", (INT16)fullAddy) ;
+}
+
+
+
+//////////////////////
+// HELPER FUNCTIONS //
+//////////////////////
+
+static UINT16 Dsp56kOpMask(UINT16 cur, UINT16 mask)
+{
+ int i ;
+
+ UINT16 retVal = (cur & mask) ;
+ UINT16 temp = 0x0000 ;
+ int offsetCount = 0 ;
+
+ // Shift everything right, eliminating 'whitespace'...
+ for (i = 0; i < 16; i++)
+ {
+ if (mask & (0x1<<i)) // If mask bit is non-zero
+ {
+ temp |= (((retVal >> i) & 0x1) << offsetCount) ;
+ offsetCount++ ;
+ }
+ }
+
+ return temp ;
+}
+
+
+
+/*
+
+Data ALU Ops
+--------------------
+
+CLR X 1xxx xxxx 0000 x001
+ADD X 1xxx xxxx 0000 xxxx
+
+MOVE X 1xxx xxxx 0001 0001
+TFR X 1xxx xxxx 0001 xxxx
+
+RND X 1xxx xxxx 0010 x000
+TST X 1xxx xxxx 0010 x001
+INC X 1xxx xxxx 0010 x010
+INC24 X 1xxx xxxx 0010 x011
+OR X 1xxx xxxx 0010 x1xx
+
+ASR X 1xxx xxxx 0011 x000
+ASL X 1xxx xxxx 0011 x001
+LSR X 1xxx xxxx 0011 x010
+LSL X 1xxx xxxx 0011 x011
+EOR X 1xxx xxxx 0011 x1xx
+
+SUBL X 1xxx xxxx 0100 x001
+SUB X 1xxx xxxx 0100 xxxx
+
+CLR24 X 1xxx xxxx 0101 x001
+SBC X 1xxx xxxx 0101 x01x
+CMP X 1xxx xxxx 0101 xxxx
+
+NEG X 1xxx xxxx 0110 x000
+NOT X 1xxx xxxx 0110 x001
+DEC X 1xxx xxxx 0110 x010
+DEC24 X 1xxx xxxx 0110 x011
+AND X 1xxx xxxx 0110 x1xx
+
+ABS X 1xxx xxxx 0111 x001
+ROR X 1xxx xxxx 0111 x010
+ROL X 1xxx xxxx 0111 x011
+CMPM X 1xxx xxxx 0111 xxxx
+
+MPY X 1xxx xxxx 1x00 xxxx
+MPYR X 1xxx xxxx 1x01 xxxx
+MAC X 1xxx xxxx 1x10 xxxx
+MACR X 1xxx xxxx 1x11 xxxx
+
+
+VERY STRANGE XMDM! 0101 HHHW xxxx xxxx
+
+
+DXMDR
+-----------------
+
+ADD X 011x xxxx 0xxx xxxx
+SUB X 011x xxxx 0xxx xxxx
+TFR X 011x xxxx 0xx1 x0xx
+MOVE X 011x xxxx 0xx1 0000
+
+MPY X 011x xxxx 1xx0 x0xx
+MAC X 011x xxxx 1xx0 x1xx
+MPYR X 011x xxxx 1XX1 x0xx
+MACR X 011x xxxx 1XX1 x1xx
+
+
+BITFIELD
+-----------------
+
+BFTSTL X 0001 0100 000x xxxx . xxx0 0000 xxxx xxxx
+BFTSTH X 0001 0100 000x xxxx . xxx1 0000 xxxx xxxx
+BFTSTL X 0001 0100 001X XXxx . xxx0 0000 xxxx xxxx
+BFTSTH X 0001 0100 001X XXxx . xxx1 0000 xxxx xxxx
+BFTSTL X 0001 0100 01xx xxxx . xxx0 0000 xxxx xxxx
+BFTSTH X 0001 0100 01xx xxxx . xxx1 0000 xxxx xxxx
+BFCLR X 0001 0100 100x xxxx . xxx0 0100 xxxx xxxx
+BFCHG X 0001 0100 100x xxxx . xxx1 0010 xxxx xxxx
+BFSET X 0001 0100 100x xxxx . xxx1 1000 xxxx xxxx
+BFCLR X 0001 0100 101X XXxx . xxx0 0100 xxxx xxxx
+BFCHG X 0001 0100 101X XXxx . xxx1 0010 xxxx xxxx
+BFSET X 0001 0100 101X XXxx . xxx1 1000 xxxx xxxx
+BFCHG X 0001 0100 11xx xxxx . xxx1 0010 xxxx xxxx
+BFCLR X 0001 0100 11xx xxxx . xxx0 0100 xxxx xxxx
+BFSET X 0001 0100 11xx xxxx . xxx1 1000 xxxx xxxx
+
+
+NPM
+-----------------
+
+TFR2 X 0001 0101 0000 x00x
+ADC X 0001 0101 0000 x01x
+
+TST2 X 0001 0101 0001 X1xx
+
+NORM X 0001 0101 0010 x0xx
+
+ASR4 X 0001 0101 0011 x000
+ASL4 X 0001 0101 0011 x001
+
+DIV X 0001 0101 0XX0 x1xx
+
+ZERO X 0001 0101 0101 x000
+EXT X 0001 0101 0101 x010
+
+NEGC X 0001 0101 0110 x000
+
+ASR16 X 0001 0101 0111 x000
+SWAP X 0001 0101 0111 x001
+
+IMPY X 0001 0101 1000 xxxx
+IMAC X 0001 0101 1010 xxxx
+DMAC(ss,su,uu) X 0001 0101 10x1 xxxx
+MPY(su,uu) X 0001 0101 1100 xxxx
+MAC(su,uu) X 0001 0101 1110 xxxx
+
+
+XMDWRDM
+-----------------
+
+MPY X 0001 0110 xxxx xxxx
+MAC X 0001 0111 xxxx xxxx
+
+
+IMMEDIATE
+-----------------
+
+ANDI X 0001 1xx0 xxxx xxxx
+ORI X 0001 1xx1 xxxx xxxx
+
+
+SPECIAL
+-----------------
+
+MOVE(S) X 0001 100x xx0x xxxx
+MOVE(P) X 0001 100x xx1x xxxx
+
+-----------------
+
+Tcc X 0001 00xx xxxx xx0x
+
+-----------------
+
+MOVE(I) X 0010 00xx xxxx xxxx
+TFR3 X 0010 01xx xxxx xxxx
+MOVE(C) X 0010 10xx xxxx xxxx
+Bcc X 0010 11xx xxxx xxxx
+
+-----------------
+
+MOVE(C) X 0011 1xxx xxx0 xxxx
+MOVE(C) X 0011 1xxx xxx1 x0xx
+MOVE(C) X 0011 1xxx xxx1 x10X xxxx xxxx xxxx xxxx
+MOVE(C) X 0011 1xxx xxx1 x11X
+
+-----------------
+
+NOP X 0000 0000 0000 0000
+DEBUG X 0000 0000 0000 0001
+DO FOREVER X 0000 0000 0000 0010 xxxx xxxx xxxx xxxx
+CHKAAU X 0000 0000 0000 0100
+SWI X 0000 0000 0000 0101
+RTS X 0000 0000 0000 0110
+RTI X 0000 0000 0000 0111
+RESET X 0000 0000 0000 1000
+ENDDO X 0000 0000 0000 1001
+STOP X 0000 0000 0000 1010
+WAIT X 0000 0000 0000 1011
+ILLEGAL X 0000 0000 0000 1111
+
+DEBUGcc X 0000 0000 0101 xxxx
+DOLoop X 0000 0000 110X XXxx xxxx xxxx xxxx xxxx
+REP X 0000 0000 111X XXxx
+
+BRKcc X 0000 0001 0001 xxxx
+
+JSR X 0000 0001 0010 00xx
+JMP X 0000 0001 0010 01xx
+BSR X 0000 0001 0010 10xx
+BRA X 0000 0001 0010 11xx
+
+JSR X 0000 0001 0011 00XX xxxx xxxx xxxx xxxx
+JMP X 0000 0001 0011 01XX xxxx xxxx xxxx xxxx
+BSR X 0000 0001 0011 10XX xxxx xxxx xxxx xxxx
+BRA X 0000 0001 0011 11XX xxxx xxxx xxxx xxxx
+
+REPcc X 0000 0001 0101 xxxx
+
+LEA X 0000 0001 10xx xxxx
+LEA X 0000 0001 11xx xxxx
+
+-----------------
+
+MOVE(M) X 0000 001x xx0x xxxx
+MOVE(M) X 0000 001x xx11 xxxx
+
+-----------------
+
+DOLoop X 0000 0100 000x xxxx xxxx xxxx xxxx xxxx
+REP X 0000 0100 001x xxxx
+
+-----------------
+
+MOVE(M) X 0000 0101 xxxx xxxx 0000 001x XX0X Xxxx
+MOVE(C) X 0000 0101 xxxx xxxx 0011 1xxx xxx0 XXXX
+MOVE X 0000 0101 xxxx xxxx XXXX xxxx 0001 0001
+
+-----------------
+
+JScc X 0000 0110 xx00 xxxx
+JScc X 0000 0110 XX01 xxxx xxxx xxxx xxxx xxxx
+Jcc X 0000 0110 xx10 xxxx
+Jcc X 0000 0110 XX11 xxxx xxxx xxxx xxxx xxxx
+
+BScc X 0000 0111 xx00 xxxx
+BScc X 0000 0111 XX01 xxxx xxxx xxxx xxxx xxxx
+Bcc X 0000 0111 xx10 xxxx
+Bcc X 0000 0111 XX11 xxxx xxxx xxxx xxxx xxxx
+
+-----------------
+
+JSR X 0000 1010 xxxx xxxx
+BRA X 0000 1011 xxxx xxxx
+MOVE(P) X 0000 110x xxxx xxxx
+DOLoop X 0000 1110 xxxx xxxx xxxx xxxx xxxx xxxx
+REP X 0000 1111 xxxx xxxx
+
+*/
diff --git a/src/emu/cpu/dsp56k/dsp56k.c b/src/emu/cpu/dsp56k/dsp56k.c
new file mode 100644
index 00000000000..defd07f3124
--- /dev/null
+++ b/src/emu/cpu/dsp56k/dsp56k.c
@@ -0,0 +1,1336 @@
+/***************************************************************************
+
+ dsp56k.c
+ Core implementation for the portable DSP56k emulator.
+ Written by Andrew Gardner
+
+****************************************************************************
+
+ Note:
+
+ This CPU emulator is very much a work-in-progress. Thus far, it appears to be
+ complete enough to run the memory tests for Polygonet Commanders.
+
+ Some particularly WIP-like features of this core are as follows :
+ * I ask many questions about my code throughout the core
+ * The BITS(bits,op) macro is fine for a disassembler, but VERY slow for the
+ inner loops of an executing core. This will go away someday
+
+***************************************************************************/
+
+#include "debugger.h"
+#include "dsp56k.h"
+
+// #define PC_E000
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+// ??? Are there namespace collision issues with just defining something "PC" ???
+// ...doesn't seem like it, but one never knows...
+
+// Register macros
+#define PC dsp56k.pcuProgramCounter
+#define SR dsp56k.pcuStatus
+#define OMR dsp56k.pcuOperatingModeReg
+#define SP dsp56k.pcuStackPointer
+#define LA dsp56k.pcuLoopAddressReg
+#define LC dsp56k.pcuLoopCounter
+
+#define SSH dsp56k.pcuSystemStack[SP].w.h
+#define SSL dsp56k.pcuSystemStack[SP].w.l
+
+
+#define X dsp56k.aluDataRegs[0].d
+#define X1 dsp56k.aluDataRegs[0].w.h
+#define X0 dsp56k.aluDataRegs[0].w.l
+#define Y dsp56k.aluDataRegs[1].d
+#define Y1 dsp56k.aluDataRegs[1].w.h
+#define Y0 dsp56k.aluDataRegs[1].w.l
+
+#define A dsp56k.aluAccumRegs[0].lw
+#define A2 dsp56k.aluAccumRegs[0].b.h4
+#define A1 dsp56k.aluAccumRegs[0].w.h
+#define A0 dsp56k.aluAccumRegs[0].w.l
+#define B dsp56k.aluAccumRegs[1].lw
+#define B2 dsp56k.aluAccumRegs[1].b.h4
+#define B1 dsp56k.aluAccumRegs[1].w.h
+#define B0 dsp56k.aluAccumRegs[1].w.l
+
+#define R0 dsp56k.aguAddressRegs[0]
+#define R1 dsp56k.aguAddressRegs[1]
+#define R2 dsp56k.aguAddressRegs[2]
+#define R3 dsp56k.aguAddressRegs[3]
+
+#define N0 dsp56k.aguOffsetRegs[0]
+#define N1 dsp56k.aguOffsetRegs[1]
+#define N2 dsp56k.aguOffsetRegs[2]
+#define N3 dsp56k.aguOffsetRegs[3]
+
+#define M0 dsp56k.aguModifierRegs[0]
+#define M1 dsp56k.aguModifierRegs[1]
+#define M2 dsp56k.aguModifierRegs[2]
+#define M3 dsp56k.aguModifierRegs[3]
+
+#define TEMP dsp56k.aguTempReg
+#define STATUS dsp56k.aguStatusReg
+
+// The CPU Stack
+#define ST0 dsp56k.pcuSystemStack[0].d
+#define ST1 dsp56k.pcuSystemStack[1].d
+#define ST2 dsp56k.pcuSystemStack[2].d
+#define ST3 dsp56k.pcuSystemStack[3].d
+#define ST4 dsp56k.pcuSystemStack[4].d
+#define ST5 dsp56k.pcuSystemStack[5].d
+#define ST6 dsp56k.pcuSystemStack[6].d
+#define ST7 dsp56k.pcuSystemStack[7].d
+#define ST8 dsp56k.pcuSystemStack[8].d
+#define ST9 dsp56k.pcuSystemStack[9].d
+#define ST10 dsp56k.pcuSystemStack[10].d
+#define ST11 dsp56k.pcuSystemStack[11].d
+#define ST12 dsp56k.pcuSystemStack[12].d
+#define ST13 dsp56k.pcuSystemStack[13].d
+#define ST14 dsp56k.pcuSystemStack[14].d
+#define ST15 dsp56k.pcuSystemStack[15].d
+// !!! Is there really only 15 of them, or is there 16 ???
+
+// Other
+#define OP dsp56k.op
+
+
+// Peripheral RAM id's and addresses
+#define PBCa (0xffc0-0xffc0)
+#define PCCa (0xffc1-0xffc0)
+#define PBDDRa (0xffc2-0xffc0)
+#define PCDDRa (0xffc3-0xffc0)
+#define PBC (dsp56k_peripheral_ram[PBCa])
+#define PCC (dsp56k_peripheral_ram[PCCa])
+#define PBDDR (dsp56k_peripheral_ram[PBDDRa])
+#define PCDDR (dsp56k_peripheral_ram[PCDDRa])
+
+#define HCRa (0xffc4-0xffc0)
+#define HCR (dsp56k_peripheral_ram[HCRa])
+
+#define COCRa (0xffc8-0xffc0)
+#define COCR (dsp56k_peripheral_ram[COCR])
+
+#define CRASSI0a (0xffd0-0xffc0)
+#define CRBSSI0a (0xffd1-0xffc0)
+#define CRASSI0 (dsp56k_peripheral_ram[CRASSI0a])
+#define CRBSSI0 (dsp56k_peripheral_ram[CRBSSI0a])
+
+#define CRASSI1a (0xffd8-0xffc0)
+#define CRBSSI1a (0xffd9-0xffc0)
+#define CRASSI1 (dsp56k_peripheral_ram[CRASSI1a])
+#define CRBSSI1 (dsp56k_peripheral_ram[CRBSSI1a])
+
+#define PLCRa (0xffdc-0xffc0)
+#define PLCR (dsp56k_peripheral_ram[PLCRa])
+
+#define BCRa (0xffde-0xffc0)
+#define IPRa (0xffdf-0xffc0)
+#define BCR (dsp56k_peripheral_ram[BCRa])
+#define IPR (dsp56k_peripheral_ram[IPRa])
+
+#define PBDa (0xffe2-0xffc0)
+#define PCDa (0xffe3-0xffc0)
+#define HSRa (0xffe4-0xffc0)
+#define PBD (dsp56k_peripheral_ram[PBDa])
+#define PCD (dsp56k_peripheral_ram[PCDa])
+#define HSR (dsp56k_peripheral_ram[HSRa])
+
+#define HTXHRXa (0xffe5-0xffc0)
+#define HTXHRX (dsp56k_peripheral_ram[HTXHRXa])
+
+#define COSRa (0xffe8-0xffc0)
+#define CRXCTXa (0xffe9-0xffc0)
+#define COSR (dsp56k_peripheral_ram[COSRa])
+#define CRXCTX (dsp56k_peripheral_ram[CRXCTXa])
+
+#define TCRa (0xffec-0xffc0)
+#define TCTRa (0xffed-0xffc0)
+#define TCPRa (0xffee-0xffc0)
+#define TPRa (0xffef-0xffc0)
+#define TCR (dsp56k_peripheral_ram[TCRa])
+#define TCTR (dsp56k_peripheral_ram[TCTRa])
+#define TCPR (dsp56k_peripheral_ram[TCPRa])
+#define TPR (dsp56k_peripheral_ram[TPRa])
+
+#define TSRSSI0a (0xfff0-0xffc0)
+#define TRXSSI0a (0xfff1-0xffc0)
+#define RSMA0a (0xfff2-0xffc0)
+#define RSMB0a (0xfff3-0xffc0)
+#define TSMA0a (0xfff4-0xffc0)
+#define TSMB0a (0xfff5-0xffc0)
+#define TSRSSI0 (dsp56k_peripheral_ram[TSRSSI0a])
+#define TRXSSI0 (dsp56k_peripheral_ram[TRXSSI0a])
+#define RSMA0 (dsp56k_peripheral_ram[RSMA0a])
+#define RSMB0 (dsp56k_peripheral_ram[RSMB0a])
+#define TSMA0 (dsp56k_peripheral_ram[TSMA0a])
+#define TSMB0 (dsp56k_peripheral_ram[TSMB0a])
+
+#define TSRSSI1a (0xfff8-0xffc0)
+#define TRXSSI1a (0xfff9-0xffc0)
+#define RSMA1a (0xfffa-0xffc0)
+#define RSMB1a (0xfffb-0xffc0)
+#define TSMA1a (0xfffc-0xffc0)
+#define TSMB1a (0xfffd-0xffc0)
+#define TSRSSI1 (dsp56k_peripheral_ram[TSRSSI1a])
+#define TRXSSI1 (dsp56k_peripheral_ram[TRXSSI1a])
+#define RSMA1 (dsp56k_peripheral_ram[RSMA1a])
+#define RSMB1 (dsp56k_peripheral_ram[RSMB1a])
+#define TSMA1 (dsp56k_peripheral_ram[TSMA1a])
+#define TSMB1 (dsp56k_peripheral_ram[TSMB1a])
+
+
+
+// Status Register Bits
+#define lfBIT ((SR & 0x8000) != 0)
+#define fvBIT ((SR & 0x4000) != 0)
+#define s1BIT ((SR & 0x0800) != 0)
+#define s0BIT ((SR & 0x0400) != 0)
+#define i1BIT ((SR & 0x0200) != 0)
+#define i0BIT ((SR & 0x0100) != 0)
+#define sBIT ((SR & 0x0080) != 0)
+#define lBIT ((SR & 0x0040) != 0)
+#define eBIT ((SR & 0x0020) != 0)
+#define uBIT ((SR & 0x0010) != 0)
+#define nBIT ((SR & 0x0008) != 0)
+#define zBIT ((SR & 0x0004) != 0)
+#define vBIT ((SR & 0x0002) != 0)
+#define cBIT ((SR & 0x0001) != 0)
+
+#define CLEAR_lfBIT() (SR &= (~0x8000))
+#define CLEAR_fvBIT() (SR &= (~0x4000))
+#define CLEAR_s1BIT() (SR &= (~0x0800))
+#define CLEAR_s0BIT() (SR &= (~0x0400))
+#define CLEAR_i1BIT() (SR &= (~0x0200))
+#define CLEAR_i0BIT() (SR &= (~0x0100))
+#define CLEAR_sBIT() (SR &= (~0x0080))
+#define CLEAR_lBIT() (SR &= (~0x0040))
+#define CLEAR_eBIT() (SR &= (~0x0020))
+#define CLEAR_uBIT() (SR &= (~0x0010))
+#define CLEAR_nBIT() (SR &= (~0x0008))
+#define CLEAR_zBIT() (SR &= (~0x0004))
+#define CLEAR_vBIT() (SR &= (~0x0002))
+#define CLEAR_cBIT() (SR &= (~0x0001))
+
+#define SET_lfBIT() (SR |= 0x8000)
+#define SET_fvBIT() (SR |= 0x4000)
+#define SET_s1BIT() (SR |= 0x0800)
+#define SET_s0BIT() (SR |= 0x0400)
+#define SET_i1BIT() (SR |= 0x0200)
+#define SET_i0BIT() (SR |= 0x0100)
+#define SET_sBIT() (SR |= 0x0080)
+#define SET_lBIT() (SR |= 0x0040)
+#define SET_eBIT() (SR |= 0x0020)
+#define SET_uBIT() (SR |= 0x0010)
+#define SET_nBIT() (SR |= 0x0008)
+#define SET_zBIT() (SR |= 0x0004)
+#define SET_vBIT() (SR |= 0x0002)
+#define SET_cBIT() (SR |= 0x0001)
+
+
+
+// Stack Pointer Bits
+#define ufBIT ((SP & 0x20) != 0)
+#define seBIT ((SP & 0x10) != 0)
+
+#define CLEAR_ufBIT() (SP &= (~0x20))
+#define CLEAR_seBIT() (SP &= (~0x10))
+
+#define SET_ufBIT() (SP |= 0x20)
+#define SET_seBIT() (SP |= 0x10)
+
+
+
+// Operating Mode Register Bits
+#define cdBIT ((OMR & 0x80) != 0)
+#define sdBIT ((OMR & 0x40) != 0)
+#define rBIT ((OMR & 0x20) != 0)
+#define saBIT ((OMR & 0x10) != 0)
+#define mcBIT ((OMR & 0x04) != 0)
+#define mbBIT ((OMR & 0x02) != 0)
+#define maBIT ((OMR & 0x01) != 0)
+
+#define CLEAR_cdBIT() (OMR &= (~0x80))
+#define CLEAR_sdBIT() (OMR &= (~0x40))
+#define CLEAR_rBIT() (OMR &= (~0x20))
+#define CLEAR_saBIT() (OMR &= (~0x10))
+#define CLEAR_mcBIT() (OMR &= (~0x04))
+#define CLEAR_mbBIT() (OMR &= (~0x02))
+#define CLEAR_maBIT() (OMR &= (~0x01))
+
+#define SET_cdBIT() (OMR |= 0x80)
+#define SET_sdBIT() (OMR |= 0x40)
+#define SET_rBIT() (OMR |= 0x20)
+#define SET_saBIT() (OMR |= 0x10)
+#define SET_mcBIT() (OMR |= 0x04)
+#define SET_mbBIT() (OMR |= 0x02)
+#define SET_maBIT() (OMR |= 0x01)
+
+
+// Interrupt Priority Register Bits
+#define tl1BIT ((IPR & 0x8000) != 0)
+#define tl0BIT ((IPR & 0x4000) != 0)
+#define s1l1BIT ((IPR & 0x2000) != 0)
+#define s1l0BIT ((IPR & 0x1000) != 0)
+#define s0l1BIT ((IPR & 0x0800) != 0)
+#define s0l0BIT ((IPR & 0x0400) != 0)
+#define hl1BIT ((IPR & 0x0200) != 0)
+#define hl0BIT ((IPR & 0x0100) != 0)
+#define cl1BIT ((IPR & 0x0080) != 0)
+#define cl0BIT ((IPR & 0x0040) != 0)
+#define ibl2BIT ((IPR & 0x0020) != 0)
+#define ibl1BIT ((IPR & 0x0010) != 0)
+#define ibl0BIT ((IPR & 0x0008) != 0)
+#define ial2BIT ((IPR & 0x0004) != 0)
+#define ial1BIT ((IPR & 0x0002) != 0)
+#define ial0BIT ((IPR & 0x0001) != 0)
+
+#define CLEAR_tl1BIT() (IPR &= (~0x8000))
+#define CLEAR_tl0BIT() (IPR &= (~0x4000))
+#define CLEAR_s1l1BIT() (IPR &= (~0x2000))
+#define CLEAR_s1l0BIT() (IPR &= (~0x1000))
+#define CLEAR_s0l1BIT() (IPR &= (~0x0800))
+#define CLEAR_s0l0BIT() (IPR &= (~0x0400))
+#define CLEAR_hl1BIT() (IPR &= (~0x0200))
+#define CLEAR_hl0BIT() (IPR &= (~0x0100))
+#define CLEAR_cl1BIT() (IPR &= (~0x0080))
+#define CLEAR_cl0BIT() (IPR &= (~0x0040))
+#define CLEAR_ibl2BIT() (IPR &= (~0x0020))
+#define CLEAR_ibl1BIT() (IPR &= (~0x0010))
+#define CLEAR_ibl0BIT() (IPR &= (~0x0008))
+#define CLEAR_ial2BIT() (IPR &= (~0x0004))
+#define CLEAR_ial1BIT() (IPR &= (~0x0002))
+#define CLEAR_ial0BIT() (IPR &= (~0x0001))
+
+#define SET_tl1BIT() (IPR |= 0x8000)
+#define SET_tl0BIT() (IPR |= 0x4000)
+#define SET_s1l1BIT() (IPR |= 0x2000)
+#define SET_s1l0BIT() (IPR |= 0x1000)
+#define SET_s0l1BIT() (IPR |= 0x0800)
+#define SET_s0l0BIT() (IPR |= 0x0400)
+#define SET_hl1BIT() (IPR |= 0x0200)
+#define SET_hl0BIT() (IPR |= 0x0100)
+#define SET_cl1BIT() (IPR |= 0x0080)
+#define SET_cl0BIT() (IPR |= 0x0040)
+#define SET_ibl2BIT() (IPR |= 0x0020)
+#define SET_ibl1BIT() (IPR |= 0x0010)
+#define SET_ibl0BIT() (IPR |= 0x0008)
+#define SET_ial2BIT() (IPR |= 0x0004)
+#define SET_ial1BIT() (IPR |= 0x0002)
+#define SET_ial0BIT() (IPR |= 0x0001)
+
+
+
+// Bus Control Register Bits
+#define rhBIT ((BCR & 0x8000) != 0)
+#define bsBIT ((BCR & 0x4000) != 0)
+
+#define CLEAR_rhBIT() (BCR &= (~0x8000))
+#define CLEAR_bsBIT() (BCR &= (~0x4000))
+
+#define SET_rhBIT() (BCR |= 0x8000)
+#define SET_bsBIT() (BCR |= 0x4000)
+
+
+
+// Port B Control Register Bits
+#define bcBIT ((PBC & 0x0001) != 0)
+
+#define CLEAR_bcBIT() (PBC &= (~0x0001))
+
+#define SET_bcBIT() (PBC |= 0x0001)
+
+
+
+// HOST INTERFACE (dsp56k side)
+// Read/Write Host Control Register Bits
+#define hf3BIT ((HCR & 0x0010) != 0)
+#define hf2BIT ((HCR & 0x0008) != 0)
+#define hcieBIT ((HCR & 0x0004) != 0)
+#define htieBIT ((HCR & 0x0002) != 0)
+#define hrieBIT ((HCR & 0x0001) != 0)
+
+#define CLEAR_hf3BIT() (HCR &= (~0x0010))
+#define CLEAR_hf2BIT() (HCR &= (~0x0008))
+#define CLEAR_hcieBIT() (HCR &= (~0x0004))
+#define CLEAR_htieBIT() (HCR &= (~0x0002))
+#define CLEAR_hrieBIT() (HCR &= (~0x0001))
+
+#define SET_hf3BIT() (HCR |= 0x0010)
+#define SET_hf2BIT() (HCR |= 0x0008)
+#define SET_hcieBIT() (HCR |= 0x0004)
+#define SET_htieBIT() (HCR |= 0x0002)
+#define SET_hrieBIT() (HCR |= 0x0001)
+
+
+
+// Read-only Host Status Register Bits
+#define dmaBIT ((HSR & 0x0080) != 0)
+#define hf1BIT ((HSR & 0x0010) != 0)
+#define hf0BIT ((HSR & 0x0008) != 0)
+#define hcpBIT ((HSR & 0x0004) != 0)
+#define htdeBIT ((HSR & 0x0002) != 0)
+#define hrdfBIT ((HSR & 0x0001) != 0)
+
+#define CLEAR_dmaBIT() (HSR &= (~0x0080))
+#define CLEAR_hf1BIT() (HSR &= (~0x0010))
+#define CLEAR_hf0BIT() (HSR &= (~0x0008))
+#define CLEAR_hcpBIT() (HSR &= (~0x0004))
+#define CLEAR_htdeBIT() (HSR &= (~0x0002))
+#define CLEAR_hrdfBIT() (HSR &= (~0x0001))
+
+#define SET_dmaBIT() (HSR |= 0x0080)
+#define SET_hf1BIT() (HSR |= 0x0010)
+#define SET_hf0BIT() (HSR |= 0x0008)
+#define SET_hcpBIT() (HSR |= 0x0004)
+#define SET_htdeBIT() (HSR |= 0x0002)
+#define SET_hrdfBIT() (HSR |= 0x0001)
+
+
+
+// HOST INTERFACE (host side)
+// Interrupt Control Register Bits
+#define x_initBIT ((dsp56k.HI.ICR & 0x0080) != 0)
+#define x_hm1BIT ((dsp56k.HI.ICR & 0x0040) != 0)
+#define x_hm0BIT ((dsp56k.HI.ICR & 0x0020) != 0)
+#define x_hf1BIT ((dsp56k.HI.ICR & 0x0010) != 0)
+#define x_hf0BIT ((dsp56k.HI.ICR & 0x0008) != 0)
+#define x_treqBIT ((dsp56k.HI.ICR & 0x0002) != 0)
+#define x_rreqBIT ((dsp56k.HI.ICR & 0x0001) != 0)
+
+#define CLEAR_x_initBIT() (dsp56k.HI.ICR &= (~0x0080))
+#define CLEAR_x_hm1BIT() (dsp56k.HI.ICR &= (~0x0040))
+#define CLEAR_x_hm0BIT() (dsp56k.HI.ICR &= (~0x0020))
+#define CLEAR_x_hf1BIT() (dsp56k.HI.ICR &= (~0x0010))
+#define CLEAR_x_hf0BIT() (dsp56k.HI.ICR &= (~0x0008))
+#define CLEAR_x_treqBIT() (dsp56k.HI.ICR &= (~0x0002))
+#define CLEAR_x_rreqBIT() (dsp56k.HI.ICR &= (~0x0001))
+
+#define SET_x_initBIT() (dsp56k.HI.ICR |= 0x0080)
+#define SET_x_hm1BIT() (dsp56k.HI.ICR |= 0x0040)
+#define SET_x_hm0BIT() (dsp56k.HI.ICR |= 0x0020)
+#define SET_x_hf1BIT() (dsp56k.HI.ICR |= 0x0010)
+#define SET_x_hf0BIT() (dsp56k.HI.ICR |= 0x0008)
+#define SET_x_treqBIT() (dsp56k.HI.ICR |= 0x0002)
+#define SET_x_rreqBIT() (dsp56k.HI.ICR |= 0x0001)
+
+
+
+// Command Vector Register Bit
+#define x_hcBIT ((dsp56k.HI.CVR & 0x0080) != 0)
+
+#define CLEAR_x_hcBIT() (dsp56k.HI.CVR &= (~0x0080))
+
+#define SET_x_hcBIT() (dsp56k.HI.CVR |= 0x0080)
+
+
+
+// Interrupt Status Register Bits
+#define x_hreqBIT ((dsp56k.HI.ISR & 0x0080) != 0)
+#define x_dmaBIT ((dsp56k.HI.ISR & 0x0040) != 0)
+#define x_hf3BIT ((dsp56k.HI.ISR & 0x0010) != 0)
+#define x_hf2BIT ((dsp56k.HI.ISR & 0x0008) != 0)
+#define x_trdyBIT ((dsp56k.HI.ISR & 0x0004) != 0)
+#define x_txdeBIT ((dsp56k.HI.ISR & 0x0002) != 0)
+#define x_rxdfBIT ((dsp56k.HI.ISR & 0x0001) != 0)
+
+#define CLEAR_x_hreqBIT() (dsp56k.HI.ISR &= (~0x0080))
+#define CLEAR_x_dmaBIT() (dsp56k.HI.ISR &= (~0x0040))
+#define CLEAR_x_hf3BIT() (dsp56k.HI.ISR &= (~0x0010))
+#define CLEAR_x_hf2BIT() (dsp56k.HI.ISR &= (~0x0008))
+#define CLEAR_x_trdyBIT() (dsp56k.HI.ISR &= (~0x0004))
+#define CLEAR_x_txdeBIT() (dsp56k.HI.ISR &= (~0x0002))
+#define CLEAR_x_rxdfBIT() (dsp56k.HI.ISR &= (~0x0001))
+
+#define SET_x_hreqBIT() (dsp56k.HI.ISR |= 0x0080)
+#define SET_x_dmaBIT() (dsp56k.HI.ISR |= 0x0040)
+#define SET_x_hf3BIT() (dsp56k.HI.ISR |= 0x0010)
+#define SET_x_hf2BIT() (dsp56k.HI.ISR |= 0x0008)
+#define SET_x_trdyBIT() (dsp56k.HI.ISR |= 0x0004)
+#define SET_x_txdeBIT() (dsp56k.HI.ISR |= 0x0002)
+#define SET_x_rxdfBIT() (dsp56k.HI.ISR |= 0x0001)
+
+
+
+// Interrupt Vector Register Bits
+#define x_iv7BIT ((dsp56k.HI.IVR & 0x0080) != 0)
+#define x_iv6BIT ((dsp56k.HI.IVR & 0x0040) != 0)
+#define x_iv5BIT ((dsp56k.HI.IVR & 0x0020) != 0)
+#define x_iv4BIT ((dsp56k.HI.IVR & 0x0010) != 0)
+#define x_iv3BIT ((dsp56k.HI.IVR & 0x0008) != 0)
+#define x_iv2BIT ((dsp56k.HI.IVR & 0x0004) != 0)
+#define x_iv1BIT ((dsp56k.HI.IVR & 0x0002) != 0)
+#define x_iv0BIT ((dsp56k.HI.IVR & 0x0001) != 0)
+
+#define CLEAR_x_iv7BIT() (dsp56k.HI.IVR &= (~0x0080))
+#define CLEAR_x_iv6BIT() (dsp56k.HI.IVR &= (~0x0040))
+#define CLEAR_x_iv5BIT() (dsp56k.HI.IVR &= (~0x0020))
+#define CLEAR_x_iv4BIT() (dsp56k.HI.IVR &= (~0x0010))
+#define CLEAR_x_iv3BIT() (dsp56k.HI.IVR &= (~0x0008))
+#define CLEAR_x_iv2BIT() (dsp56k.HI.IVR &= (~0x0004))
+#define CLEAR_x_iv1BIT() (dsp56k.HI.IVR &= (~0x0002))
+#define CLEAR_x_iv0BIT() (dsp56k.HI.IVR &= (~0x0001))
+
+#define SET_x_iv7BIT() (dsp56k.HI.IVR | 0x0080)
+#define SET_x_iv6BIT() (dsp56k.HI.IVR | 0x0040)
+#define SET_x_iv5BIT() (dsp56k.HI.IVR | 0x0020)
+#define SET_x_iv4BIT() (dsp56k.HI.IVR | 0x0010)
+#define SET_x_iv3BIT() (dsp56k.HI.IVR | 0x0008)
+#define SET_x_iv2BIT() (dsp56k.HI.IVR | 0x0004)
+#define SET_x_iv1BIT() (dsp56k.HI.IVR | 0x0002)
+#define SET_x_iv0BIT() (dsp56k.HI.IVR | 0x0001)
+
+
+
+
+
+// IRQ Interfaces
+#define LINE_MODA (dsp56k.irq_modA)
+#define LINE_MODB (dsp56k.irq_modB)
+#define LINE_MODC (dsp56k.irq_modC)
+#define LINE_RESET (dsp56k.irq_reset)
+
+
+
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+// DSP56156 Host Interface - page 94 of DSP56156UM
+typedef struct
+{
+ // DSP56156 SIDE
+ // Three words in the DSP processor?s address space
+ // UINT8 HCR $FFC4
+ // UINT8 HSR $FFE4
+ // UINT16 HTX $FFE5 - same as below
+ // UINT16 HRX $FFE5 - same as above
+
+ // HOST SIDE
+ // The HI appears as a memory mapped peripheral, occupying 8 bytes in the host processor?s address space
+ UINT8 TXHRXH, TXLRXL;
+
+ UINT8 ICR;
+ UINT8 CVR;
+ UINT8 ISR;
+ UINT8 IVR;
+
+ // control lines available to the host
+ UINT8 HA0, HA1, HA2;
+ UINT8 hatHRW;
+ UINT8 hatHEN;
+ UINT8 hatHREQ;
+ UINT8 hatHACK;
+
+} dsp56k_host_interface;
+
+
+// DSP56156 Registers - sizes specific to chip
+typedef struct
+{
+ // See section 1-22 in DSP56156UM.pdf for scrutinization...
+
+ // PCU Registers
+ UINT16 pcuProgramCounter; // PC
+ UINT16 pcuStatus; // MR,CCR / SR
+ UINT16 pcuLoopCounter; // LC
+ UINT16 pcuLoopAddressReg; // LA
+ UINT8 pcuStackPointer; // SP
+ UINT8 pcuOperatingModeReg; // OMR
+ PAIR pcuSystemStack[16]; // SSH,SSL (*15)
+
+ // ALU Registers
+ PAIR aluDataRegs[2]; // X1,X0 & Y1,Y0
+ PAIR64 aluAccumRegs[2]; // A2,A1,A0 & B2,B1,B0
+
+ // AGU Registers
+ UINT16 aguAddressRegs[4]; // R0,R1,R2,R3
+ UINT16 aguOffsetRegs[4]; // N0,N1,N2,N3
+ UINT16 aguModifierRegs[4]; // M0,M1,M2,M3
+ UINT16 aguTempReg; // TEMP
+ UINT8 aguStatusReg; // Status
+
+
+ // IRQ lines
+ UINT8 irq_modA; // aka IRQA - can be defined edge or level sensitive (though i'm not sure how)
+ UINT8 irq_modB; // aka IRQA - can be defined edge or level sensitive (though i'm not sure how)
+ UINT8 irq_modC; // just modC :)
+ UINT8 irq_reset; // Always level-sensitive
+
+ int (*irq_callback)(int irqline);
+
+ // Internal Stuff
+ UINT32 ppc; // Previous PC - for debugger
+ UINT16 op; // Current opcode
+ int interrupt_cycles;
+
+ int repFlag; // Knowing if we're in a 'repeat' state (dunno how the processor does this)
+ UINT32 repAddr; // The address of the instruction to repeat...
+
+ // Interfaces - ports B and C *can* be these if everything's setup right.
+ dsp56k_host_interface HI;
+
+ const void * config;
+
+} dsp56k_regs;
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void dsp56k_reset(void);
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static dsp56k_regs dsp56k;
+static int dsp56k_icount;
+
+static UINT16 hack_memory_offset = 0;
+static UINT16 *dsp56k_peripheral_ram;
+static UINT16 *dsp56k_program_ram;
+
+/***************************************************************************
+ IRQ HANDLING
+***************************************************************************/
+
+static void check_irqs(void)
+{
+
+}
+
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == 3)
+ {
+ LINE_RESET = state;
+
+ if(LINE_RESET != CLEAR_LINE)
+ {
+ int irq_vector = (*dsp56k.irq_callback)(3);
+
+ PC = irq_vector;
+
+ LINE_RESET = CLEAR_LINE;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ CONTEXT SWITCHING
+***************************************************************************/
+
+static void dsp56k_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(dsp56k_regs *)dst = dsp56k;
+}
+
+
+static void dsp56k_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ dsp56k = *(dsp56k_regs *)src;
+ memory_set_opbase(PC);
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+static void dsp56k_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ dsp56k.config = _config;
+ dsp56k.irq_callback = irqcallback;
+}
+
+
+static void dsp56k_reset_HI(void)
+{
+ dsp56k.HI.CVR = 0x16; // clears HC and sets HL
+}
+
+// Page 101 (7-25) in the Family Manual
+static void dsp56k_reset(void)
+{
+ if (dsp56k.config == NULL)
+ {
+ memory_set_opbase(PC);
+
+ // Handle internal stuff
+ dsp56k.interrupt_cycles = 0;
+
+
+ // Internal peripheral devices are reset, and pins revert to general I/O pins
+
+ // Modifier registers are set
+ M0 = M1 = M2 = M3 = 0xffff;
+
+ // BCR is set - the really slow bootup mode & the Bus State status bit high (0x4xxx)
+ //BCR = 0x43ff;
+
+ // Stack pointer is cleared
+ SP = 0x00; // The docs say nothing about ufBIT & seBIT, but this should be right
+
+ // Documentation says 'MR' is setup, but it really means 'SR' is setup
+ SR = 0x0300; // Only the Interrupt mask bits of the Status Register are set upon reset
+
+
+ // !!! GO THROUGH AND GET ALL THESE RIGHT SOMEDAY !!!
+ HSR = 0x0000;
+ SET_htdeBIT();
+
+ dsp56k_reset_HI();
+
+ OMR = 0x00; // All is cleared, except for the IRQ lines below
+ IPR = 0x00;
+
+ dsp56k.repFlag = 0; // Certainly not repeating to start
+ dsp56k.repAddr = 0x0000; // Reset the address too...
+
+ // Manipulate everything you need to for the ports (!! maybe these will be callbacks someday !!)...
+ data_write_word_16le(0xffc0, 0x0000); // Sets Port B Control Register to general I/O
+ data_write_word_16le(0xffc2, 0x0000); // Sets Port B Data Direction Register as input
+ data_write_word_16le(0xffc1, 0x0000); // Sets Port C Control Register to general I/O
+ data_write_word_16le(0xffc3, 0x0000); // Sets Port C Data Direction Register as input
+
+ // Now that we're leaving, set ma, mb, and mc from MODA, MODB, and MODC lines
+ // I believe polygonet sets everyone to mode 0... The following reflects this...
+ CLEAR_maBIT();
+ CLEAR_mbBIT();
+
+ // switch bootup sequence based on chip operating mode
+ switch((mbBIT << 1) | maBIT)
+ {
+ // [Special Bootstrap 1] Bootstrap from an external byte-wide memory located at P:$c000
+ case 0x0:
+ PC = 0x0000; // 0x0030; // 0x0032; // 0x002e; // 0x0000; // 0x002c;
+ break;
+
+ // [Special Bootstrap 2] Bootstrap from the Host port or SSI0
+ case 0x1:
+ PC = 0x0000;
+ break;
+
+ // [Normal Expanded] Internal PRAM enabled; External reset at P:$e000
+ case 0x2:
+ PC = 0xe000;
+ break;
+
+ // [Development Expanded] Int. program memory disabled; Ext. reset at P:$0000
+ case 0x3:
+ PC = 0x0000;
+ break;
+ }
+ }
+ else
+ {
+ PC = *((UINT16*)dsp56k.config);
+ }
+}
+
+
+static void dsp56k_exit(void)
+{
+}
+
+
+
+/***************************************************************************
+ CORE INCLUDE
+***************************************************************************/
+
+#define ROPCODE(pc) cpu_readop16(pc)
+
+#include "dsp56ops.c"
+
+
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+static int dsp56k_execute(int cycles)
+{
+ /* skip if halted */
+ if (LINE_RESET)
+ return cycles;
+
+ dsp56k_icount = cycles;
+ dsp56k_icount -= dsp56k.interrupt_cycles;
+ dsp56k.interrupt_cycles = 0;
+
+ while(dsp56k_icount > 0)
+ execute_one();
+
+ dsp56k_icount -= dsp56k.interrupt_cycles;
+ dsp56k.interrupt_cycles = 0;
+
+ return cycles - dsp56k_icount;
+}
+
+
+
+/***************************************************************************
+ DISASSEMBLY HOOK
+***************************************************************************/
+
+extern offs_t dsp56k_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+
+
+
+/****************************************************************************
+ * Internal Memory Handlers
+ ****************************************************************************/
+
+static READ16_HANDLER( peripheral_register_r )
+{
+// logerror("peripheral_register_r 0x%x\n", offset+0xffc0);
+
+ switch (offset)
+ {
+ case HCRa: //ffc4
+ return HCR;
+ break;
+
+ case HSRa: //ffe4
+ return HSR;
+ break;
+
+ case HTXHRXa: //ffe5
+ // The HRX register contains valid data when the HRDF bit is set.
+// if (hrdfBIT)
+ return HTXHRX;
+
+ // Reading HRX clears HRDF.
+ CLEAR_hrdfBIT();
+
+ // The DSP may program the HRIE bit to cause a Host Receive Data interrupt when HRDF is set.
+
+ return 0x0000;
+ break;
+ }
+
+ return dsp56k_peripheral_ram[offset];
+}
+
+static WRITE16_HANDLER( peripheral_register_w )
+{
+ COMBINE_DATA(&dsp56k_peripheral_ram[offset]);
+
+ logerror("peripheral_register_w 0x%x 0x%x (@%x)\n", offset+0xffc0, data, PC);
+
+ switch (offset)
+ {
+ case HCRa: //ffc4
+ // The HCR register occupies the low order byte of the internal data bus -
+ // the high order portion is zero-filled.
+
+ // Changing HF2 will change the Host Flag 2 (HF2) bit of the Interrupt Status
+ // Register ISR on the host processor side of the host interface.
+ if (hf2BIT)
+ SET_x_hf2BIT();
+ else
+ CLEAR_x_hf2BIT();
+
+ // Changing HF3 will change the Host Flag 3 (HF3) bit of the Interrupt Status
+ // Register ISR on the host processor side of the host interface.
+ if (hf3BIT)
+ {
+ SET_x_hf3BIT();
+ }
+ else
+ CLEAR_x_hf3BIT();
+
+ break;
+
+ case HSRa: //ffe4
+ /* READ ONLY */
+ break;
+
+ case HTXHRXa: //ffe5
+
+ // ??? Can you write here even if you don't have the requirements?
+
+ // Writing the HTX register clears HTDE (HSR bit 1)
+ CLEAR_htdeBIT();
+
+ // The DSP may program the HTIE (HCR bit 1) bit to cause a Host Transmit Data
+ // interrupt when HTDE is set
+
+ // The HTX register is transferred as 16-bit data to the Receive Byte Registers
+ // RXH:RXL if both the HTDE (HSR bit 1) bit and the Receive Data Full,
+ // RXDF (ISR bit 0), status bit are cleared
+// printf("%d %d %x\n", htdeBIT, x_rxdfBIT, dsp56k_peripheral_ram[offset]);
+ if ( !htdeBIT && !x_rxdfBIT )
+ {
+ dsp56k.HI.TXHRXH = (HTXHRX & 0xff00) >> 8;
+ dsp56k.HI.TXLRXL = (HTXHRX & 0x00ff);
+
+ // This transfer operation sets RXDF (ISR bit 0) and HTDE (HSR bit 1).
+ SET_x_rxdfBIT();
+ }
+ break;
+ }
+}
+
+UINT16 dsp56k_get_peripheral_memory(UINT16 addr)
+{
+ if (addr >= 0xffc0) // && addr <= 0xffff
+ {
+ return dsp56k_peripheral_ram[addr-0xffc0];
+ }
+ else
+ {
+ logerror("DSP56k - Peripheral memory requested does not exist\n");
+ return 0x00;
+ }
+}
+
+/****************************************************************************
+ * Internal Memory Maps
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( dsp56156_program_memory, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x0000, 0x07ff) AM_RAM AM_BASE(&dsp56k_program_ram)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( dsp56156_x_data_memory, ADDRESS_SPACE_DATA, 16 )
+ AM_RANGE(0x0000, 0x07ff) AM_RAM
+ AM_RANGE(0xffc0, 0xffff) AM_READWRITE(peripheral_register_r, peripheral_register_w) AM_BASE(&dsp56k_peripheral_ram)
+ADDRESS_MAP_END
+
+
+/**************************************************************************
+ * Host Interface (HI) functionality.
+ **************************************************************************/
+
+void dsp56k_host_interface_write(UINT8 addr, UINT8 data)
+{
+ switch (addr)
+ {
+ case 0x0: // ICR
+ dsp56k.HI.ICR = data;
+
+ // Changing HF0 also changes the Host Flag bit 0 (HF0) of the Host Status register HSR on the DSP side of the HI.
+ if (x_hf0BIT) SET_hf0BIT();
+ if (x_hf1BIT) SET_hf1BIT();
+
+ break;
+
+ case 0x1: // CVR
+ dsp56k.HI.CVR = data;
+
+ // Normally the host processor sets HC=1 to request the host command
+ // exception from the DSP.
+ if (dsp56k.HI.CVR & 0x80)
+ {
+ // Setting HC (bit 0x80) causes HCP (Host Command Pending) to be set in the HSR register. The host
+ // can write HC and HV in the same write cycle if desired. HC is cleared by DSP reset.
+ SET_hcpBIT();
+
+ // reset the pc to the proper address
+ logerror("RESET (%04x) sent\n", (dsp56k.HI.CVR & 0x1f) << 1);
+ PC = (dsp56k.HI.CVR & 0x1f) << 1;
+
+ // When the host command exception is taken by the DSP, the HC
+ // bit is cleared by the HI hardware.
+ CLEAR_x_hcBIT();
+ }
+ break;
+
+ case 0x2: break; // ISR - read only
+
+ case 0x3: // IVR
+ // 68000 series communication
+ break;
+
+ case 0x4: break; // Unused
+ case 0x5: break; // Unused
+
+ case 0x6: // TXH/RXH
+
+ // Data may be written into the Transmit Byte Registers when the
+ // Transmit Data Register Empty TXDE bit is set.
+ if (!x_txdeBIT)
+ {
+ dsp56k.HI.TXHRXH = data;
+ }
+
+ break;
+
+ case 0x7: // TXL/RXL
+
+ // Data may be written into the Transmit Byte Registers when the
+ // Transmit Data Register Empty TXDE bit is set.
+ if (!x_txdeBIT)
+ dsp56k.HI.TXLRXL = data;
+
+ // writing the Transmit Low register TXL clears the TXDE bit
+ CLEAR_x_txdeBIT();
+
+
+ // The Transmit Byte Registers TXH:TXL are transferred as 16-bit data to the Host Receive
+ // Data Register HRX when both TXDE bit and the Host Receive Data Full, HRDF, bit are
+ // cleared.
+ if (!x_txdeBIT && !hrdfBIT)
+ {
+ HTXHRX = ( ((UINT16)dsp56k.HI.TXHRXH) << 8 ) | (UINT16)dsp56k.HI.TXLRXL;
+
+ // !!! Hack !!! Move it straight to program memory...
+ dsp56k_program_ram[hack_memory_offset] = HTXHRX;
+ logerror("Wrote memoryOffset[%d] : %04x\n", hack_memory_offset, dsp56k_program_ram[hack_memory_offset]);
+ hack_memory_offset++;
+
+ // This transfer operation sets TXDE and HRDF.
+// SET_x_txdeBIT();
+// SET_hrdfBIT();
+ }
+ break;
+ }
+}
+
+static int memtest3_hack=0;
+
+UINT8 dsp56k_host_interface_read(UINT8 addr)
+{
+ UINT8 retVal = 0x00;
+
+ switch(addr)
+ {
+ case 0x00: // ICR
+ retVal = dsp56k.HI.ICR;
+ break;
+
+ case 0x01: // CVR
+ retVal = dsp56k.HI.CVR;
+ break;
+
+ case 0x02: // ISR
+ retVal = dsp56k.HI.ISR;
+
+ /* We may need some *VERY* tight synchro at the end of the 3rd memory test in order to get this going right */
+ if ( (PC <= 0x125) && (PC >= 0x123) )
+ {
+ /* Maybe this isn't needed? */
+ if (!memtest3_hack)
+ {
+ cpu_boost_interleave(attotime_zero, ATTOTIME_IN_USEC(100));
+ memtest3_hack++;
+ }
+ }
+ break;
+
+ case 0x03: // IVR
+ retVal = dsp56k.HI.IVR;
+ break;
+
+ case 0x04: break; // Unused
+ case 0x05: break; // Unused
+
+ case 0x06: // RXH/TXH
+ retVal = dsp56k.HI.TXHRXH;
+ break;
+
+ case 0x07: // RXL/TXL
+ retVal = dsp56k.HI.TXLRXL;
+
+ // RXDF is cleared when the Receive Data Low (RXL) register is read by the host processor.
+ CLEAR_x_rxdfBIT();
+ SET_htdeBIT(); // !!! seems right ???
+ break;
+ }
+
+ return retVal;
+}
+
+/* HACK ! (maybe ;) */
+void dsp56k_reset_dma_offset(void)
+{
+ hack_memory_offset = 0;
+}
+
+/**************************************************************************
+ * Generic set_info/get_info
+ **************************************************************************/
+
+static void dsp56k_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_INPUT_STATE + DSP56K_IRQ_MODA: set_irq_line(DSP56K_IRQ_MODA, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + DSP56K_IRQ_MODB: set_irq_line(DSP56K_IRQ_MODB, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + DSP56K_IRQ_MODC: set_irq_line(DSP56K_IRQ_MODC, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + DSP56K_IRQ_RESET: set_irq_line(DSP56K_IRQ_RESET, info->i); break;
+
+
+ // !! It might be interesting to use this section as something which masks out the unecessary bits in each register !!
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + DSP56K_PC: PC = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_SR: SR = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_LC: LC = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_LA: LA = info->i & 0xffff; break;
+ case CPUINFO_INT_SP: // !!! I think this is correct !!!
+ case CPUINFO_INT_REGISTER + DSP56K_SP: SP = info->i & 0xff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_OMR: OMR = info->i & 0xff; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_X: X = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_Y: Y = info->i & 0xffffffff; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_A: A = info->i & (UINT64)U64(0xffffffffffffffff); break; // could benefit from a better mask?
+ case CPUINFO_INT_REGISTER + DSP56K_B: B = info->i & (UINT64)U64(0xffffffffffffffff); break; // could benefit from a better mask?
+
+ case CPUINFO_INT_REGISTER + DSP56K_R0: R0 = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_R1: R1 = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_R2: R2 = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_R3: R3 = info->i & 0xffff; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_N0: N0 = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_N1: N1 = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_N2: N2 = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_N3: N3 = info->i & 0xffff; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_M0: M0 = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_M1: M1 = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_M2: M2 = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_M3: M3 = info->i & 0xffff; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_TEMP: TEMP = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_STATUS: STATUS = info->i & 0xff; break;
+
+ // The CPU stack...
+ case CPUINFO_INT_REGISTER + DSP56K_ST0: ST0 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST1: ST1 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST2: ST2 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST3: ST3 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST4: ST4 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST5: ST5 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST6: ST6 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST7: ST7 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST8: ST8 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST9: ST9 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST10: ST10 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST11: ST11 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST12: ST12 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST13: ST13 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST14: ST14 = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST15: ST15 = info->i & 0xffffffff; break;
+ }
+}
+
+
+void dsp56k_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ // --- the following bits of info are returned as 64-bit signed integers ---
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(dsp56k); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 4; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; // ?
+ case CPUINFO_INT_MAX_CYCLES: info->i = 8; break; // ?
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; // I think this is the ffc0-fff0 part of data memory?
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; //
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break; //
+
+ case CPUINFO_INT_INPUT_STATE + DSP56K_IRQ_MODA: info->i = LINE_MODA; break;
+ case CPUINFO_INT_INPUT_STATE + DSP56K_IRQ_MODB: info->i = LINE_MODB; break;
+ case CPUINFO_INT_INPUT_STATE + DSP56K_IRQ_MODC: info->i = LINE_MODC; break;
+ case CPUINFO_INT_INPUT_STATE + DSP56K_IRQ_RESET: info->i = LINE_RESET; break; // Is reset a special case?
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = dsp56k.ppc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + DSP56K_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + DSP56K_SR: info->i = SR; break;
+ case CPUINFO_INT_REGISTER + DSP56K_LC: info->i = LC; break;
+ case CPUINFO_INT_REGISTER + DSP56K_LA: info->i = LA; break;
+ case CPUINFO_INT_SP: // !!! I think this is correct !!!
+ case CPUINFO_INT_REGISTER + DSP56K_SP: info->i = SP; break;
+ case CPUINFO_INT_REGISTER + DSP56K_OMR: info->i = OMR; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_X: info->i = X; break;
+ case CPUINFO_INT_REGISTER + DSP56K_Y: info->i = Y; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_A: info->i = A; break;
+ case CPUINFO_INT_REGISTER + DSP56K_B: info->i = B; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_R0: info->i = R0; break;
+ case CPUINFO_INT_REGISTER + DSP56K_R1: info->i = R1; break;
+ case CPUINFO_INT_REGISTER + DSP56K_R2: info->i = R2; break;
+ case CPUINFO_INT_REGISTER + DSP56K_R3: info->i = R3; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_N0: info->i = N0; break;
+ case CPUINFO_INT_REGISTER + DSP56K_N1: info->i = N1; break;
+ case CPUINFO_INT_REGISTER + DSP56K_N2: info->i = N2; break;
+ case CPUINFO_INT_REGISTER + DSP56K_N3: info->i = N3; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_M0: info->i = M0; break;
+ case CPUINFO_INT_REGISTER + DSP56K_M1: info->i = M1; break;
+ case CPUINFO_INT_REGISTER + DSP56K_M2: info->i = M2; break;
+ case CPUINFO_INT_REGISTER + DSP56K_M3: info->i = M3; break;
+
+ case CPUINFO_INT_REGISTER + DSP56K_TEMP: info->i = TEMP; break;
+ case CPUINFO_INT_REGISTER + DSP56K_STATUS: info->i = STATUS; break;
+
+ // The CPU stack
+ case CPUINFO_INT_REGISTER + DSP56K_ST0: info->i = ST0; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST1: info->i = ST1; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST2: info->i = ST2; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST3: info->i = ST3; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST4: info->i = ST4; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST5: info->i = ST5; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST6: info->i = ST6; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST7: info->i = ST7; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST8: info->i = ST8; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST9: info->i = ST9; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST10: info->i = ST10; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST11: info->i = ST11; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST12: info->i = ST12; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST13: info->i = ST13; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST14: info->i = ST14; break;
+ case CPUINFO_INT_REGISTER + DSP56K_ST15: info->i = ST15; break;
+
+
+
+ // --- the following bits of info are returned as pointers to data or functions ---
+ case CPUINFO_PTR_SET_INFO: info->setinfo = dsp56k_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = dsp56k_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = dsp56k_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = dsp56k_init; break;
+ case CPUINFO_PTR_RESET: info->reset = dsp56k_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = dsp56k_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = dsp56k_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = dsp56k_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &dsp56k_icount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA:
+ info->internal_map = construct_map_dsp56156_x_data_memory; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM:
+ info->internal_map = construct_map_dsp56156_program_memory; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO:
+ info->internal_map = 0; break;
+
+
+ // --- the following bits of info are returned as NULL-terminated strings ---
+ case CPUINFO_STR_NAME: strcpy(info->s, "DSP56156"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola DSP56156"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.1"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Andrew Gardner"); break;
+
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s %s%s %s%s%s%s%s%s%s",
+ lfBIT ? "L":".",
+ fvBIT ? "F":".",
+ s1BIT ? "S":".",
+ s0BIT ? "S":".",
+ i1BIT ? "I":".",
+ i0BIT ? "I":".",
+ sBIT ? "S":".",
+ lBIT ? "L":".",
+ eBIT ? "E":".",
+ uBIT ? "U":".",
+ nBIT ? "N":".",
+ zBIT ? "Z":".",
+ vBIT ? "V":".",
+ cBIT ? "C":".",
+ ufBIT ? "U":".",
+ seBIT ? "S":".",
+ cdBIT ? "C":".",
+ sdBIT ? "S":".",
+ rBIT ? "R":".",
+ saBIT ? "S":".",
+ mcBIT ? "M":".",
+ mbBIT ? "M":".",
+ maBIT ? "M":".");
+
+ break;
+
+
+ case CPUINFO_STR_REGISTER + DSP56K_PC: sprintf(info->s, "PC : %04x", PC); break;
+ case CPUINFO_STR_REGISTER + DSP56K_SR: sprintf(info->s, "SR : %04x", SR); break;
+ case CPUINFO_STR_REGISTER + DSP56K_LC: sprintf(info->s, "LC : %04x", LC); break;
+ case CPUINFO_STR_REGISTER + DSP56K_LA: sprintf(info->s, "LA : %04x", LA); break;
+ case CPUINFO_STR_REGISTER + DSP56K_SP: sprintf(info->s, "SP : %02x", SP); break;
+ case CPUINFO_STR_REGISTER + DSP56K_OMR: sprintf(info->s, "OMR: %02x", OMR); break;
+
+ case CPUINFO_STR_REGISTER + DSP56K_X: sprintf(info->s, "X : %04x %04x", X1, X0); break;
+ case CPUINFO_STR_REGISTER + DSP56K_Y: sprintf(info->s, "Y : %04x %04x", Y1, Y0); break;
+
+ // !! This is silly - it gives me a warning if I try to print an unsigned long with %08x
+ // (and thus won't compile) - any suggestions? Maybe we change it to a series of UINT16's or something?
+ case CPUINFO_STR_REGISTER + DSP56K_A: sprintf(info->s, "A : %02x %04x %04x", A2,A1,A0); break;
+ case CPUINFO_STR_REGISTER + DSP56K_B: sprintf(info->s, "B : %02x %04x %04x", B2,B1,B0); break;
+
+ case CPUINFO_STR_REGISTER + DSP56K_R0: sprintf(info->s, "R0 : %04x", R0); break;
+ case CPUINFO_STR_REGISTER + DSP56K_R1: sprintf(info->s, "R1 : %04x", R1); break;
+ case CPUINFO_STR_REGISTER + DSP56K_R2: sprintf(info->s, "R2 : %04x", R2); break;
+ case CPUINFO_STR_REGISTER + DSP56K_R3: sprintf(info->s, "R3 : %04x", R3); break;
+
+ case CPUINFO_STR_REGISTER + DSP56K_N0: sprintf(info->s, "N0 : %04x", N0); break;
+ case CPUINFO_STR_REGISTER + DSP56K_N1: sprintf(info->s, "N1 : %04x", N1); break;
+ case CPUINFO_STR_REGISTER + DSP56K_N2: sprintf(info->s, "N2 : %04x", N2); break;
+ case CPUINFO_STR_REGISTER + DSP56K_N3: sprintf(info->s, "N3 : %04x", N3); break;
+
+ case CPUINFO_STR_REGISTER + DSP56K_M0: sprintf(info->s, "M0 : %04x", M0); break;
+ case CPUINFO_STR_REGISTER + DSP56K_M1: sprintf(info->s, "M1 : %04x", M1); break;
+ case CPUINFO_STR_REGISTER + DSP56K_M2: sprintf(info->s, "M2 : %04x", M2); break;
+ case CPUINFO_STR_REGISTER + DSP56K_M3: sprintf(info->s, "M3 : %04x", M3); break;
+
+ case CPUINFO_STR_REGISTER + DSP56K_TEMP: sprintf(info->s, "TMP: %04x", TEMP); break;
+ case CPUINFO_STR_REGISTER + DSP56K_STATUS: sprintf(info->s, "STS: %02x", STATUS); break;
+
+
+ // The CPU stack
+ case CPUINFO_STR_REGISTER + DSP56K_ST0: sprintf(info->s, "ST0 : %08x", ST0); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST1: sprintf(info->s, "ST1 : %08x", ST1); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST2: sprintf(info->s, "ST2 : %08x", ST2); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST3: sprintf(info->s, "ST3 : %08x", ST3); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST4: sprintf(info->s, "ST4 : %08x", ST4); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST5: sprintf(info->s, "ST5 : %08x", ST5); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST6: sprintf(info->s, "ST6 : %08x", ST6); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST7: sprintf(info->s, "ST7 : %08x", ST7); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST8: sprintf(info->s, "ST8 : %08x", ST8); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST9: sprintf(info->s, "ST9 : %08x", ST9); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST10: sprintf(info->s, "ST10: %08x", ST10); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST11: sprintf(info->s, "ST11: %08x", ST11); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST12: sprintf(info->s, "ST12: %08x", ST12); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST13: sprintf(info->s, "ST13: %08x", ST13); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST14: sprintf(info->s, "ST14: %08x", ST14); break;
+ case CPUINFO_STR_REGISTER + DSP56K_ST15: sprintf(info->s, "ST15: %08x", ST15); break;
+ }
+}
diff --git a/src/emu/cpu/dsp56k/dsp56k.h b/src/emu/cpu/dsp56k/dsp56k.h
new file mode 100644
index 00000000000..b2f88e18502
--- /dev/null
+++ b/src/emu/cpu/dsp56k/dsp56k.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+
+ dsp56k.h
+ Interface file for the portable Motorola/Freescale DSP56k emulator.
+ Written by Andrew Gardner
+
+***************************************************************************/
+
+
+#ifndef _DSP56K_H
+#define _DSP56K_H
+
+#include "cpuintrf.h"
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+// IRQ Lines
+// MODA and MODB are also known as IRQA and IRQB
+#define DSP56K_IRQ_MODA 0
+#define DSP56K_IRQ_MODB 1
+#define DSP56K_IRQ_MODC 2
+#define DSP56K_IRQ_RESET 3
+
+enum
+{
+ // PCU
+ DSP56K_PC=1,
+ DSP56K_SR,
+ DSP56K_LC,
+ DSP56K_LA,
+ DSP56K_SP,
+ DSP56K_OMR,
+
+ // ALU
+ DSP56K_X, DSP56K_Y,
+ DSP56K_A, DSP56K_B,
+
+ // AGU
+ DSP56K_R0,DSP56K_R1,DSP56K_R2,DSP56K_R3,DSP56K_R4,DSP56K_R5,DSP56K_R6,DSP56K_R7,
+ DSP56K_N0,DSP56K_N1,DSP56K_N2,DSP56K_N3,DSP56K_N4,DSP56K_N5,DSP56K_N6,DSP56K_N7,
+ DSP56K_M0,DSP56K_M1,DSP56K_M2,DSP56K_M3,DSP56K_M4,DSP56K_M5,DSP56K_M6,DSP56K_M7,
+ DSP56K_TEMP,
+ DSP56K_STATUS,
+
+ // CPU STACK
+ DSP56K_ST0,
+ DSP56K_ST1,
+ DSP56K_ST2,
+ DSP56K_ST3,
+ DSP56K_ST4,
+ DSP56K_ST5,
+ DSP56K_ST6,
+ DSP56K_ST7,
+ DSP56K_ST8,
+ DSP56K_ST9,
+ DSP56K_ST10,
+ DSP56K_ST11,
+ DSP56K_ST12,
+ DSP56K_ST13,
+ DSP56K_ST14,
+ DSP56K_ST15
+};
+
+
+
+extern void dsp56k_get_info(UINT32 state, cpuinfo *info) ;
+
+void dsp56k_host_interface_write(UINT8 addr, UINT8 data);
+UINT8 dsp56k_host_interface_read(UINT8 addr);
+
+void dsp56k_reset_dma_offset(void);
+
+UINT16 dsp56k_get_peripheral_memory(UINT16 addr);
+
+
+// For Debugger and opcodes
+enum parallelMoveType { PARALLEL_TYPE_XMDM, PARALLEL_TYPE_XMDM_SPECIAL, PARALLEL_TYPE_NODM, PARALLEL_TYPE_ARU, PARALLEL_TYPE_RRDM } ;
+
+
+#endif // _DSP56K_H
diff --git a/src/emu/cpu/dsp56k/dsp56ops.c b/src/emu/cpu/dsp56k/dsp56ops.c
new file mode 100644
index 00000000000..a6907f20b58
--- /dev/null
+++ b/src/emu/cpu/dsp56k/dsp56ops.c
@@ -0,0 +1,2599 @@
+/***************************************************************************
+
+ dsp56kops.c
+ Core implementation for the portable Motorola/Freescale DSP56k emulator.
+ Written by Andrew Gardner
+
+***************************************************************************/
+
+// Helper functions and macros
+#define BITS(CUR,MASK) (Dsp56kOpMask(CUR,MASK))
+static UINT16 Dsp56kOpMask(UINT16 op, UINT16 mask) ;
+
+enum dataType { DT_BYTE, DT_WORD, DT_DOUBLE_WORD, DT_LONG_WORD } ;
+
+// This function's areguments are written source->destination to fall in line with the processor's paradigm...
+static void SetDestinationValue(void *sourcePointer, unsigned char sourceType,
+ void *destinationPointer, unsigned char destinationType) ;
+
+static void SetDataMemoryValue (void *sourcePointer, unsigned char sourceType, UINT32 destinationAddr) ;
+static void SetProgramMemoryValue(void *sourcePointer, unsigned char sourceType, UINT32 destinationAddr) ;
+
+
+// Main opcode categories
+static unsigned ExecuteDataALUOpcode(int parallelType) ;
+static unsigned ExecuteDXMDROpcode(void) ;
+static unsigned ExecuteNPMOpcode(void) ;
+static unsigned ExecuteMisfitOpcode(void) ;
+static unsigned ExecuteSpecialOpcode(void) ;
+
+
+// Actual opcode implementations
+
+// Data ALU Ops
+static int ClrOperation(void **wd, UINT64 *pa) ;
+static int AddOperation(void **wd, UINT64 *pa) ;
+static int NotOperation(void **wd, UINT64 *pa) ;
+static int LsrOperation(void **wd, UINT64 *pa) ;
+static int AsrOperation(void **wd, UINT64 *pa) ;
+static int TfrDataALUOperation(void **wd, UINT64 *pa) ;
+static int EorOperation(void **wd, UINT64 *pa) ;
+static int CmpOperation(void **wd, UINT64 *pa) ;
+static int Dec24Operation(void **wd, UINT64 *pa) ;
+static int AndOperation(void **wd, UINT64 *pa) ;
+static int OrOperation(void **wd, UINT64 *pa) ;
+static int TstOperation(void **wd, UINT64 *pa) ;
+
+static int MoveCOperation(void) ;
+static int MoveMOperation(void) ;
+static int MoveIOperation(void) ;
+static int MovePOperation(void) ;
+
+static int AndiOperation(void) ;
+//static int OriOperation(void) ;
+
+static int BitfieldOperation(void) ;
+static int JmpOperation(void) ;
+static int BsrOperation(void) ;
+static int JsrOperation(void) ;
+static int DoOperation(void) ;
+static int TccOperation(void) ;
+static int BraOperation(void) ;
+static int BsccOperation(void) ;
+static int BccOperation(void) ;
+static int Tst2Operation(void) ;
+static int MACsuuuOperation(void) ;
+static int RepOperation(void) ;
+
+static void EndOfLoopProcessing(void) ;
+static void EndOfRepProcessing(void) ;
+
+// Parallel memory data moves
+static void XMDMOperation(UINT16 parameters, void *working, UINT64 *pa) ;
+static void XMDMSpecialOperation(UINT16 parameters, void *working) ;
+static void ARUOperation(UINT16 parameters) ;
+static void RRDMOperation(UINT16 parameters, void *working, UINT64 *pa) ;
+
+// For decoding the different types of tables...
+static void *DecodeDDDDDTable(UINT16 DDDDD, unsigned char *dt) ;
+static void *DecodeRRTable(UINT16 RR, unsigned char *dt) ;
+static void *DecodeDDTable(UINT16 DD, unsigned char *dt) ;
+static void *DecodeHHHTable(UINT16 HHH, unsigned char *dt) ;
+static void *DecodeHHTable(UINT16 HH, unsigned char *dt) ;
+static void *DecodeZTable(UINT16 Z, unsigned char *dt) ;
+static UINT16 DecodeBBBBitMask(UINT16 BBB, UINT16 *iVal) ;
+static int DecodeccccTable(UINT16 cccc) ;
+static void Decodeh0hFTable(UINT16 h0h, UINT16 F, void **source, unsigned char *st, void **dest, unsigned char *dt) ;
+static void *DecodeFTable(UINT16 F, unsigned char *dt) ;
+static void DecodeJJJFTable(UINT16 JJJ, UINT16 F, void **source, unsigned char *st, void **dest, unsigned char *dt) ;
+static void DecodeJJFTable(UINT16 JJ, UINT16 F, void **source, unsigned char *st, void **dest, unsigned char *dt) ;
+static void DecodeQQFTableSp(UINT16 QQ, UINT16 F, void **S1, void **S2, void **D) ;
+static void DecodeIIIITable(UINT16 IIII, void **source, unsigned char *st, void **dest, unsigned char *dt, void *working) ;
+
+static void ExecuteMMTable(int x, UINT16 MM) ;
+static void ExecutemTable(int x, UINT16 m) ;
+static void ExecutezTable(int x, UINT16 z) ;
+static UINT16 ExecuteqTable(int x, UINT16 q) ;
+
+static UINT16 AssembleDFromPTable(UINT16 P, UINT16 ppppp) ;
+
+static UINT16 AssembleAddressFromIOShortAddress(UINT16 pp) ;
+static UINT16 AssembleAddressFrom6BitSignedRelativeShortAddress(UINT16 srs) ;
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+#ifdef UNUSED_FUNCTION
+static void unimplemented(void)
+{
+ fatalerror("Unimplemented OP @ %04X: %04X", PC-2, OP) ;
+}
+#endif
+
+
+static void execute_one(void)
+{
+ unsigned size = 666 ;
+
+ CALL_MAME_DEBUG;
+ OP = ROPCODE(PC<<1);
+
+ if (BITS(OP,0x8000)) // First, the parallel data move instructions
+ {
+ size = ExecuteDataALUOpcode(PARALLEL_TYPE_XMDM) ;
+ }
+ else if (BITS(OP,0xf000) == 0x5)
+ {
+ size = ExecuteDataALUOpcode(PARALLEL_TYPE_XMDM_SPECIAL) ;
+ }
+ else if (BITS(OP,0xff00) == 0x4a)
+ {
+ size = ExecuteDataALUOpcode(PARALLEL_TYPE_NODM) ;
+ }
+ else if (BITS(OP,0xf000) == 0x04)
+ {
+ size = ExecuteDataALUOpcode(PARALLEL_TYPE_RRDM) ;
+ }
+ else if (BITS(OP,0xf800) == 0x06)
+ {
+ size = ExecuteDataALUOpcode(PARALLEL_TYPE_ARU) ;
+ }
+
+
+ else if (BITS(OP,0x4000))
+ {
+ size = ExecuteDXMDROpcode() ;
+ }
+ else if (BITS(OP,0xf000) == 0x1)
+ {
+ size = ExecuteNPMOpcode() ;
+ }
+ else if (BITS(OP,0x2000))
+ {
+ size = ExecuteMisfitOpcode() ;
+ }
+ else if (BITS(OP,0xf000) == 0x0)
+ {
+ size = ExecuteSpecialOpcode();
+ }
+
+ if (size == 666)
+ {
+ mame_printf_debug("unimplemented at %04x\n", PC) ;
+ size = 1 ; // Just to get the debugger past the bad opcode
+ }
+
+
+ PC += size ;
+ change_pc(PC) ;
+
+ // Loop processing
+ if (lfBIT)
+ {
+ if (PC == LA)
+ {
+ // You're on the last instruction of the loop...
+ if (LC != 1) // Strange, the == 1 thing...
+ {
+ LC-- ;
+ PC = SSH ;
+ change_pc(PC) ;
+ }
+ else
+ {
+ EndOfLoopProcessing() ;
+ }
+ }
+ }
+
+ // Rep processing
+ if (dsp56k.repFlag)
+ {
+ if (PC == dsp56k.repAddr)
+ {
+ if (LC != 1)
+ {
+ LC-- ;
+ PC -= size ; // Eh, seems reasonable :)
+ change_pc(PC) ;
+ }
+ else
+ {
+ EndOfRepProcessing() ;
+ }
+ }
+ }
+
+ dsp56k_icount -= 4; /* Temporarily hard-coded at 4 clocks per opcode */
+}
+
+
+static unsigned ExecuteDataALUOpcode(int parallelType)
+{
+ unsigned retSize = 666 ;
+
+ void *workingDest = 0x00 ;
+
+ // Whenever an instruction uses an accumulator as both a destination operand for a Data ALU operation and
+ // as a source for a parallel move operation, the parallel move operation will use the value in the accumulator
+ // prior to execution of any Data ALU operation.
+ UINT64 previousAccum = 0 ;
+
+ switch(BITS(OP,0x0070))
+ {
+
+ case 0x0:
+ if (BITS(OP,0x0007) == 0x1)
+ {
+ // CLR - 1mRR HHHW 0000 F001
+ retSize = ClrOperation(&workingDest, &previousAccum) ;
+ }
+ else
+ {
+ // ADD - 1mRR HHHW 0000 FJJJ
+ retSize = AddOperation(&workingDest, &previousAccum) ;
+ }
+ break ;
+
+ case 0x1:
+ if (BITS(OP,0x000f) == 0x1)
+ {
+ // MOVE - 1mRR HHHW 0001 0001
+ retSize = 1 ;
+ }
+ else
+ {
+ // TFR - 1mRR HHHW 0001 FJJJ
+ retSize = TfrDataALUOperation(&workingDest, &previousAccum) ;
+ }
+ break ;
+
+ case 0x2:
+ if (BITS(OP,0x0007) == 0x0)
+ {
+ // RND - 1mRR HHHW 0010 F000
+ }
+ else if (BITS(OP,0x0007) == 0x1)
+ {
+ // TST - 1mRR HHHW 0010 F001
+ retSize = TstOperation(&workingDest, &previousAccum);
+ }
+ else if (BITS(OP,0x0007) == 0x2)
+ {
+ // INC - 1mRR HHHW 0010 F010
+ }
+ else if (BITS(OP,0x0007) == 0x3)
+ {
+ // INC24 - 1mRR HHHW 0010 F011
+ }
+ else
+ {
+ // OR - 1mRR HHHW 0010 F1JJ
+ retSize = OrOperation(&workingDest, &previousAccum) ;
+ }
+ break ;
+
+ case 0x3:
+ if (BITS(OP,0x0007) == 0x0)
+ {
+ // ASR - 1mRR HHHW 0011 F000
+ retSize = AsrOperation(&workingDest, &previousAccum) ;
+ }
+ else if (BITS(OP,0x0007) == 0x1)
+ {
+ // ASL - 1mRR HHHW 0011 F001
+ }
+ else if (BITS(OP,0x0007) == 0x2)
+ {
+ // LSR - 1mRR HHHW 0011 F010
+ retSize = LsrOperation(&workingDest, &previousAccum) ;
+ }
+ else if (BITS(OP,0x0007) == 0x3)
+ {
+ // LSL - 1mRR HHHW 0011 F011
+ }
+ else
+ {
+ // EOR - 1mRR HHHW 0011 F1JJ
+ retSize = EorOperation(&workingDest, &previousAccum) ;
+ }
+ break ;
+/*
+ case 0x4:
+ if (BITS(op,0x0007) == 0x1)
+ {
+ // SUBL - 1mRR HHHW 0100 F001
+ }
+ else
+ {
+ // SUB - 1mRR HHHW 0100 FJJJ
+ }
+ break ;
+*/
+ case 0x5:
+ if (BITS(OP,0x0007) == 0x1)
+ {
+ // CLR24 - 1mRR HHHW 0101 F001
+ }
+ else if (BITS(OP,0x0006) == 0x1)
+ {
+ // SBC - 1mRR HHHW 0101 F01J
+ }
+ else
+ {
+ // CMP - 1mRR HHHW 0101 FJJJ
+ retSize = CmpOperation(&workingDest, &previousAccum) ;
+ }
+ break ;
+
+ case 0x6:
+ if (BITS(OP,0x0007) == 0x0)
+ {
+ // NEG - 1mRR HHHW 0110 F000
+ }
+ else if (BITS(OP,0x0007) == 0x1)
+ {
+ // NOT - 1mRR HHHW 0110 F001
+ retSize = NotOperation(&workingDest, &previousAccum) ;
+ }
+ else if (BITS(OP,0x0007) == 0x2)
+ {
+ // DEC - 1mRR HHHW 0110 F010
+ }
+ else if (BITS(OP,0x0007) == 0x3)
+ {
+ // DEC24 - 1mRR HHHW 0110 F011
+ retSize = Dec24Operation(&workingDest, &previousAccum) ;
+ }
+ else
+ {
+ // AND - 1mRR HHHW 0110 F1JJ
+ retSize = AndOperation(&workingDest, &previousAccum) ;
+ }
+ break ;
+/*
+ case 0x7:
+ if (BITS(op,0x0007) == 0x1)
+ {
+ // ABS - 1mRR HHHW 0111 F001
+ }
+ if (BITS(op,0x0007) == 0x2)
+ {
+ // ROR - 1mRR HHHW 0111 F010
+ }
+ if (BITS(op,0x0007) == 0x3)
+ {
+ // ROL - 1mRR HHHW 0111 F011
+ }
+ else
+ {
+ // CMPM - 1mRR HHHW 0111 FJJJ
+ }
+
+ break ;
+*/
+ }
+
+/*
+ // Otherwise you're looking at a MPY/MAC operation...
+ if (BITS(op,0x0080)) // Maybe i should un-consolidate here?
+ {
+ DecodeQQQFTable(BITS(op,0x0007), BITS(op,0x0008), S1, S2, D) ;
+ DecodekSignTable(BITS(op,0x0040), sign) ;
+
+ switch(BITS(op,0x00b0))
+ {
+ // MPY - 1mRR HHHH 1k00 FQQQ
+ case 0x4: sprintf(buffer, "mpy (%s)%s,%s,%s", sign, S2, S1, D) ; break ;
+
+ // MPYR - 1mRR HHHH 1k01 FQQQ
+ case 0x5: sprintf(buffer, "mpyr (%s)%s,%s,%s", sign, S2, S1, D) ; break ;
+
+ // MAC - 1mRR HHHH 1k10 FQQQ
+ case 0x6: sprintf(buffer, "mac (%s)%s,%s,%s", sign, S2, S1, D) ; break ;
+
+ // MACR - 1mRR HHHH 1k11 FQQQ
+ case 0x7: sprintf(buffer, "macr (%s)%s,%s,%s", sign, S1, S2, D) ; break ;
+ // !! It's a little odd that macr is S1,S2 while everyone else is S2,S1 !!
+ }
+
+ retSize = 1 ;
+ }
+*/
+
+ // Do the parallel move parallel'y :)
+ // Someday we may have to check against the special cases to throw exceptions !!
+ switch (parallelType)
+ {
+ case PARALLEL_TYPE_XMDM:
+ XMDMOperation(BITS(OP,0xff00), workingDest, &previousAccum) ;
+ break ;
+
+ case PARALLEL_TYPE_RRDM:
+ RRDMOperation(BITS(OP,0xff00), workingDest, &previousAccum) ;
+ break ;
+
+ case PARALLEL_TYPE_XMDM_SPECIAL:
+ // pa is not needed because the XMDM dest is always the .opposite. of the regular dest.
+ XMDMSpecialOperation(BITS(OP,0xff00), workingDest) ;
+ break ;
+
+ case PARALLEL_TYPE_NODM:
+ // do nothing
+ break ;
+
+ case PARALLEL_TYPE_ARU:
+ ARUOperation(BITS(OP,0xff00)) ;
+ break ;
+ }
+
+ return retSize ;
+}
+
+static unsigned ExecuteDXMDROpcode(void)
+{
+ unsigned retSize = 666 ;
+
+ return retSize ;
+}
+
+static unsigned ExecuteNPMOpcode(void)
+{
+ unsigned retSize = 666 ;
+
+ if (BITS(OP,0x0f00) == 0x4)
+ {
+ retSize = BitfieldOperation() ;
+ }
+ else if (BITS(OP,0x0f00) == 0x5)
+ {
+ switch(BITS(OP,0x0074))
+ {
+ case 0x0:
+ if (BITS(OP,0x0006) == 0x0)
+ {
+ // TFR(2) - 0001 0101 0000 F00J
+ retSize = 1 ;
+ }
+ else if (BITS(OP,0x0006) == 0x1)
+ {
+ // ADC - 0001 0101 0000 F01J
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0x3:
+ // TST(2) - 0001 0101 0001 -1DD
+ retSize = Tst2Operation() ; break ;
+
+ case 0x4:
+ // NORM - 0001 0101 0010 F0RR
+ retSize = 1 ; break ;
+
+ case 0x6:
+ if (BITS(OP,0x0003) == 0x0)
+ {
+ // ASR4 - 0001 0101 0011 F000
+ retSize = 1 ;
+ }
+ else if (BITS(OP,0x0003) == 0x1)
+ {
+ // ASL4 - 0001 0101 0011 F001
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0x1: case 0x5: case 0x9: case 0xd:
+ // DIV - 0001 0101 0--0 F1DD
+ retSize = 1 ; break ;
+
+ case 0xa:
+ if (BITS(OP,0x0003) == 0x0)
+ {
+ // ZERO - 0001 0101 0101 F000
+ retSize = 1 ;
+ }
+ else if (BITS(OP,0x0003) == 0x2)
+ {
+ // EXT - 0001 0101 0101 F010
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0xc:
+ if (BITS(OP,0x0003) == 0x0)
+ {
+ // NEGC - 0001 0101 0110 F000
+ retSize = 1 ;
+ }
+ break ;
+
+ case 0xe:
+ if (BITS(OP,0x0003) == 0x0)
+ {
+ // ASR16 - 0001 0101 0111 F000
+ retSize = 1 ;
+ }
+ else if (BITS(OP,0x0003) == 0x1)
+ {
+ // SWAP - 0001 0101 0111 F001
+ retSize = 1 ;
+ }
+ break ;
+ }
+
+ switch(BITS(OP,0x00f0))
+ {
+ case 0x8:
+ // IMPY - 0001 0101 1000 FQQQ
+ retSize = 1 ; break ;
+ case 0xa:
+ // IMAC - 0001 0101 1010 FQQQ
+ retSize = 1 ; break ;
+ case 0x9: case 0xb:
+ // DMAC(ss,su,uu) - 0001 0101 10s1 FsQQ
+ retSize = 1 ; break ;
+ case 0xc:
+ // MPY(su,uu) - 0001 0101 1100 FsQQ
+ retSize = 1 ; break ;
+ case 0xe:
+ // MAC(su,uu) - 0001 0101 1110 FsQQ
+ retSize = MACsuuuOperation() ; break ;
+ }
+ }
+ else if ((BITS(OP,0x0f00) == 0x6))
+ {
+ retSize = 1 ;
+ }
+ else if ((BITS(OP,0x0f00) == 0x7))
+ {
+ retSize = 1 ;
+ }
+ else if ((BITS(OP,0x0800) == 0x1))
+ {
+ if (BITS(OP,0x0600))
+ {
+ if (!BITS(OP,0x0100))
+ {
+ // ANDI - 0001 1EE0 iiii iiii
+ retSize = AndiOperation() ;
+ }
+ else
+ {
+ // ORI - 0001 1EE1 iiii iiii
+ }
+ }
+ else
+ {
+ if (!BITS(OP,0x0020))
+ {
+ // MOVE(S) - 0001 100W HH0a aaaa
+ }
+ else
+ {
+ // MOVE(P) - 0001 100W HH1p pppp
+ retSize = MovePOperation() ;
+ }
+ }
+ }
+ else if ((BITS(OP,0x0c00) == 0x0))
+ {
+ retSize = TccOperation() ;
+ }
+
+ return retSize ;
+}
+
+static unsigned ExecuteMisfitOpcode(void)
+{
+ unsigned retSize = 666 ;
+
+ if (BITS(OP,0x1000)== 0x0)
+ {
+ switch(BITS(OP,0x0c00))
+ {
+ // MOVE(I) - 0010 00DD BBBB BBBB
+ case 0x0:
+ retSize = MoveIOperation() ;
+ break ;
+
+/*
+ case 0x1:
+ // TFR(3) - 0010 01mW RRDD FHHH
+ break ;
+*/
+ case 0x2:
+ // MOVE(C) - 0010 10dd dddD DDDD
+ retSize = MoveCOperation() ;
+ break ;
+
+ case 0x3:
+ // B.cc - 0010 11cc ccee eeee
+ retSize = BccOperation() ;
+ break ;
+ }
+ }
+ else
+ {
+ // MOVE(C) - 0011 1WDD DDD0 MMRR
+ // MOVE(C) - 0011 1WDD DDD1 q0RR
+ // MOVE(C) - 0011 1WDD DDD1 t10- xxxx xxxx xxxx xxxx
+ // MOVE(C) - 0011 1WDD DDD1 Z11-
+ retSize = MoveCOperation() ;
+ }
+
+ return retSize ;
+}
+
+static unsigned ExecuteSpecialOpcode(void)
+{
+ unsigned retSize = 666 ;
+
+ if (BITS(OP,0x0ff0) == 0x0)
+ {
+ switch (BITS(OP,0x000f))
+ {
+ // NOP - 0000 0000 0000 0000
+ case 0x0:
+ retSize = 1 ;
+ break ;
+
+ // DO FOREVER - 0000 0000 0000 0010 xxxx xxxx xxxx xxxx
+ case 0x2:
+ // !!! IMPLEMENT ME NEXT;
+ retSize = 0;
+ break;
+
+ // RTS - 0000 0000 0000 0110
+ case 0x6:
+ PC = SSH ;
+ SR = SSL ;
+ SP-- ;
+ retSize = 0 ;
+ change_pc(PC) ;
+ break ;
+
+ // RTI - 0000 0000 0000 0111
+ case 0x7:
+ PC = SSH;
+ SR = SSL;
+ SP--;
+ retSize = 0;
+ change_pc(PC);
+ break;
+ }
+ }
+ else if (BITS(OP,0x0f00) == 0x0)
+ {
+ retSize = 1 ;
+ }
+ else if (BITS(OP,0x0f00) == 0x1)
+ {
+ if (BITS(OP,0x00f0) == 0x1)
+ {
+ retSize = 1 ;
+ }
+ else if (BITS(OP,0x00f0) == 0x2)
+ {
+ switch(BITS(OP,0x000c)) // Consolidation can happen here
+ {
+ // JSR - 0000 0001 0010 00RR
+ // JMP - 0000 0001 0010 01RR
+ case 0x1: retSize = JmpOperation(); break;
+ // BSR - 0000 0001 0010 10RR
+ // BRA - 0000 0001 0010 11RR
+ default: retSize = 1;
+ }
+ }
+ else if (BITS(OP,0x00f0) == 0x3)
+ {
+ switch(BITS(OP,0x000c))
+ {
+ // JSR - 0000 0001 0011 00-- xxxx xxxx xxxx xxxx
+ case 0x0: retSize = JsrOperation() ; break ;
+ // JMP - 0000 0001 0011 01-- xxxx xxxx xxxx xxxx
+ case 0x1: retSize = JmpOperation() ; break ;
+ // BSR - 0000 0001 0011 10-- xxxx xxxx xxxx xxxx
+ case 0x2: retSize = BsrOperation() ; break ;
+ }
+ }
+ else if (BITS(OP,0x00f0) == 0x5)
+ {
+ retSize = 1 ;
+ }
+ else if (BITS(OP,0x0080) == 0x1)
+ {
+ retSize = 1 ;
+ }
+ }
+ else if (BITS(OP,0x0e00) == 0x1)
+ {
+ if (BITS(OP,0x0020) == 0x0)
+ {
+ // MOVE(M) - 0000 001W RR0M MHHH
+ retSize = MoveMOperation() ;
+ }
+ }
+ else if (BITS(OP,0x0f00) == 0x4)
+ {
+ if (BITS(OP,0x0020) == 0x0)
+ {
+ // DO - 0000 0100 000D DDDD xxxx xxxx xxxx xxxx
+ retSize = DoOperation() ;
+ }
+ else
+ {
+ // REP - 0000 0100 001D DDDD
+ retSize = RepOperation() ;
+ }
+ }
+ else if (BITS(OP,0x0f00) == 0x5)
+ {
+ UINT16 op2 = ROPCODE((PC<<1)+2) ;
+
+ if (BITS(op2,0xfe20) == 0x02)
+ {
+ // MOVE(M) - 0000 0101 BBBB BBBB | 0000 001W --0- -HHH
+ retSize = MoveMOperation() ;
+ }
+ else if (BITS(op2,0xf810) == 0x0e)
+ {
+ // MOVE(C) - 0000 0101 BBBB BBBB | 0011 1WDD DDD0 ----
+ }
+ else if (BITS(op2,0x00ff) == 0x11)
+ {
+ // MOVE - 0000 0101 BBBB BBBB | ---- HHHW 0001 0001
+ }
+ }
+ else if (BITS(OP,0x0f00) == 0x6)
+ {
+ retSize = 1 ;
+ }
+ else if (BITS(OP,0x0f00) == 0x7)
+ {
+ switch(BITS(OP,0x0030))
+ {
+ // BS.cc - 0000 0111 RR00 cccc
+ case 0x0: retSize = 1 ; break ;
+
+ // BS.cc - 0000 0111 --01 cccc xxxx xxxx xxxx xxxx
+ case 0x1: retSize = BsccOperation() ; break ;
+
+ // B.cc - 0000 0111 RR10 cccc
+ case 0x2: retSize = 1 ; break ;
+
+ // B.cc - 0000 0111 --11 cccc xxxx xxxx xxxx xxxx
+ case 0x3: retSize = BccOperation() ; break ;
+ }
+ }
+ else if (BITS(OP,0x0800))
+ {
+ switch (BITS(OP,0x0700))
+ {
+ // BRA - 0000 1011 aaaa aaaa
+ case 0x3: retSize = BraOperation() ; break ;
+
+ // MOVE(P) - 0000 110W RRmp pppp
+ case 0x4: case 0x5: retSize = MovePOperation() ; break ;
+
+ // DO - 0000 1110 iiii iiii xxxx xxxx xxxx xxxx
+ case 0x6: retSize = DoOperation() ; break ;
+
+ // REP - 0000 1111 iiii iiii
+ case 0x7: retSize = RepOperation() ; break ;
+ }
+ }
+
+ return retSize ;
+}
+
+/*
+IMPLEMENTATIONS
+*/
+
+static int BitfieldOperation(void)
+{
+ int retSize = 0 ;
+
+ // BITFIELD OPERATIONS
+ // ONLY PARTIALLY IMPLEMENTED !!!
+
+ // Get the next part of the opcode...
+ UINT16 op2 = ROPCODE((PC<<1)+2) ;
+
+ unsigned char dt = 0x00 ;
+ void *destinationReg = 0x00 ;
+ void *rReg = 0x00 ;
+
+ UINT16 destAddr = 0x00 ;
+
+ UINT16 opVal ;
+
+ // Get the universal immediate value and its proper mask...
+ UINT16 iVal = op2 & 0x00ff ;
+ DecodeBBBBitMask(BITS(op2,0xe000), &iVal) ;
+
+ // Figure out where data you'll be dealing with comes from...
+ switch(BITS(OP,0x00e0))
+ {
+ case 0x6: case 0x7: case 0x2: case 0x3:
+ destAddr = AssembleDFromPTable(BITS(OP,0x0020), BITS(OP,0x001f)) ;
+ break ;
+
+ case 0x5: case 0x1:
+ rReg = DecodeRRTable(BITS(OP,0x0003), &dt) ;
+ destAddr = *((UINT16*)rReg) ;
+ break ;
+
+ case 0x4: case 0x0:
+ destinationReg = DecodeDDDDDTable(BITS(OP,0x001f), &dt) ;
+ break ;
+ }
+
+ // Grab the value to operate on...
+ if (destinationReg)
+ {
+ if (dt == DT_LONG_WORD)
+ opVal = (*((PAIR64*)destinationReg)).w.h ;
+ else
+ opVal = *((UINT16*)destinationReg) ;
+ }
+ else
+ opVal = data_read_word_16le(destAddr<<1) ;
+
+ // Do the necessary bitfield operation...
+ switch(BITS(op2,0x1f00))
+ {
+ // bfchg
+ case 0x12:
+ if ((iVal & opVal) == iVal) SET_cBIT() ; // test
+ else CLEAR_cBIT() ;
+
+ opVal ^= iVal ; // and change
+ break ;
+
+ // bfclr
+ case 0x04:
+ opVal &= (~iVal) ;
+ break ;
+
+ // bfset
+ case 0x18:
+ opVal |= iVal ;
+ break ;
+
+ // bfsth
+ case 0x10:
+ mame_printf_debug("BFSTH - not here yet") ;
+ break ;
+
+ // bftstl
+ case 0x00:
+ if ((iVal & opVal) == 0) SET_cBIT() ;
+ else CLEAR_cBIT() ;
+ retSize = 2; return retSize; /* It's just a test - no need to go on */
+ break ;
+ }
+
+ // Put the data back where it belongs
+ // !!! When setting A and B, I'm pretty sure if it's supposed to pass through the normal 'setDestValue' pipe but not entirely !!!
+ // (in other words, does clearing ff.ffff.ffff with 001c really result in ff.ffe3.0000 or ff.ffe3.ffff) ???
+ if (destinationReg)
+ SetDestinationValue(&opVal, DT_WORD, destinationReg, dt) ;
+ else
+ SetDataMemoryValue(&opVal, DT_WORD, destAddr<<1) ;
+
+ retSize = 2 ;
+ return retSize ;
+}
+
+static int MoveCOperation(void)
+{
+ int retSize = 0 ;
+
+ unsigned char W = 0x00 ;
+
+ unsigned char sdt = 0x00 ;
+ void *SD ;
+
+ // ONLY PARTIALLY IMPLEMENTED !!!
+
+ SD = DecodeDDDDDTable(BITS(OP,0x03e0), &sdt) ;
+ W = BITS(OP,0x0400) ;
+
+ if (BITS(OP,0x1000))
+ {
+ // Single source/destination move(c)
+ if (!BITS(OP,0x0010))
+ {
+ // MM in move(c)
+
+ // Get the r register...
+ unsigned char rt = 0x00 ;
+ void *R ;
+
+ R = DecodeRRTable(BITS(OP,0x0003), &rt) ;
+
+ if (W)
+ {
+ // !!! does this work ???
+ UINT16 data = data_read_word_16le((*((UINT16*)R))<<1) ;
+ SetDestinationValue(&data, DT_WORD, SD, sdt) ;
+ }
+ else
+ {
+ SetDataMemoryValue(SD, sdt, (*((UINT16*)R))<<1) ;
+ }
+
+ ExecuteMMTable(BITS(OP,0x0003), BITS(OP,0x000c)) ;
+ retSize = 1 ;
+ }
+ else
+ {
+ if (!BITS(OP,0x0004))
+ {
+ // q in move(c)
+
+ // Figure out the true addr...
+ UINT16 addr = ExecuteqTable(BITS(OP,0x0003), BITS(OP,0x0008));
+
+ if (W)
+ {
+ // !!! does this work ???
+ UINT16 data = data_read_word_16le(addr<<1) ;
+ SetDestinationValue(&data, DT_WORD, SD, sdt) ;
+ }
+ else
+ {
+ SetDataMemoryValue(SD, sdt, addr<<1);
+ }
+
+ retSize = 1 ;
+ }
+ else
+ {
+ if (BITS(OP,0x0002))
+ {
+ // Z in move(c)
+ unsigned char rt = 0x00;
+ void *Z;
+
+ Z = DecodeZTable(BITS(OP,0x0008), &rt);
+
+ if (W)
+ {
+ // Unimplemented
+ retSize = 666 ;
+ }
+ else
+ {
+ SetDataMemoryValue(SD, sdt, (*((UINT16*)Z))<<1);
+ retSize = 1;
+ }
+ }
+ else
+ {
+ // 2-word move(c)
+ UINT16 nextWord = ROPCODE((PC<<1)+2) ;
+
+ if (BITS(OP,0x0008))
+ {
+ // #xxxx - value read directly out of the opcode
+ SetDestinationValue(&nextWord, DT_WORD, SD, sdt) ;
+ }
+ else
+ {
+ // X:xxxx = value resides in X memory...
+ if (W)
+ {
+ // Read from X-data memory...
+ // !!! Does this work ???
+ UINT16 data = data_read_word_16le(nextWord<<1) ;
+ SetDestinationValue(&data, DT_WORD, SD, sdt) ;
+ }
+ else
+ {
+ // Write to X-data memory...
+ SetDataMemoryValue(SD, sdt, nextWord<<1) ;
+ }
+ }
+
+ retSize = 2 ;
+ }
+ }
+ }
+ }
+ else if (BITS(OP,0x2000))
+ {
+ // Source and Destination explicit
+ unsigned char dt = 0x00 ;
+ void *D ;
+
+ D = DecodeDDDDDTable(BITS(OP,0x001f), &dt) ;
+ SetDestinationValue(SD, sdt, D, dt) ;
+
+ retSize = 1 ;
+ }
+ else
+ {
+ // Double source/destination move(c)
+
+ retSize = 666 ;
+ }
+
+ return retSize ;
+}
+
+static int MoveMOperation(void)
+{
+ int retSize = 0 ;
+
+ // ONLY PARTIALLY IMPLEMENTED !!!
+
+ if (BITS(OP,0x0400))
+ {
+ // The double word MoveM operation...
+ UINT16 nextWord = ROPCODE((PC<<1)+2) ;
+
+ UINT8 increment = BITS(OP,0x00ff) ;
+
+ int W = BITS(nextWord, 0x0100) ;
+
+ unsigned char sdt = 0x00 ;
+ void *sdReg = 0x00 ;
+ sdReg = DecodeHHHTable(BITS(nextWord,0x0007), &sdt) ;
+
+ if (W)
+ {
+ // Read from Program Memory...
+ UINT16 data = program_read_word_16le((R2<<1)+(increment<<1)) ;
+ SetDestinationValue(&data, DT_WORD, sdReg, sdt) ;
+ }
+ else
+ {
+ // Write to Program Memory...
+ // !!! Does this work ???
+ // SetMemoryValue(sdReg, sdt, ((R2<<1)+(increment<<1))) ;
+ }
+
+ retSize = 2 ;
+ }
+ else
+ {
+ // The single word MoveM operation...
+
+ // Decode which way the data is going...
+ int W = BITS(OP,0x0100) ;
+
+ // Decode which R Register we're working with...
+ unsigned char rt = 0x00 ;
+ void *rReg = 0x00 ;
+ rReg = DecodeRRTable(BITS(OP,0x00c0), &rt) ;
+
+ if (BITS(OP,0x0020))
+ {
+ // R and R operation
+ retSize = 666 ;
+ }
+ else
+ {
+ // R and SD operation
+ // Decode the SD register...
+ unsigned char sdt = 0x00 ;
+ void *sdReg = 0x00 ;
+ sdReg = DecodeHHHTable(BITS(OP,0x0007), &sdt) ;
+
+ if (W)
+ {
+ // Read from Program Memory...
+ UINT16 data = program_read_word_16le( (*((UINT16*)rReg)) << 1 ) ;
+ SetDestinationValue(&data, DT_WORD, sdReg, sdt) ;
+ }
+ else
+ {
+ // Write to Program Memory...
+ SetProgramMemoryValue(sdReg, sdt, (*((UINT16*)rReg)) << 1 ) ;
+ }
+
+ // Execute the increment part of the opcode...
+ ExecuteMMTable(BITS(OP,0x00c0), BITS(OP,0x0018)) ;
+
+ retSize = 1 ;
+ }
+ }
+
+ return retSize ;
+}
+
+static int MoveIOperation(void)
+{
+ int retSize = 1 ;
+
+ // The 8-bit signed immediate operand is stored in the low byte of destination
+ // register D after having been sign extended.
+
+ INT8 immediateVal = OP & 0x00ff ;
+ UINT16 immediateWord ;
+
+ unsigned char dt = 0x00 ;
+ void *destinationReg = 0x00 ;
+
+ destinationReg = DecodeDDTable(BITS(OP,0x0300), &dt) ;
+
+ // Sign extend the immediate value...
+ // !!! On Intel architecture this works correctly, does it work everywhere ???
+ immediateWord = (INT16)immediateVal ;
+
+ SetDestinationValue(&immediateWord, DT_WORD, destinationReg, dt) ;
+
+ return retSize ;
+}
+
+static int MovePOperation(void)
+{
+ int retSize = 1 ;
+
+ if (BITS(OP,0x1000))
+ {
+ // X:<pp> and SD
+ UINT16 pp ;
+ UINT16 W ;
+
+ unsigned char sdt = 0x00 ;
+ void *SD = 0x00 ;
+
+ SD = DecodeHHTable(BITS(OP,0x00c0), &sdt) ;
+
+ pp = BITS(OP,0x001f) ;
+ pp = AssembleAddressFromIOShortAddress(pp) ;
+
+ W = BITS(OP,0x0100) ;
+
+ if (W)
+ {
+ UINT16 data = data_read_word_16le(pp<<1) ;
+ SetDestinationValue(&data, DT_WORD, SD, sdt) ;
+ }
+ else
+ {
+ SetDataMemoryValue(SD, sdt, pp<<1) ;
+ }
+ }
+ else
+ {
+ // X:<Rx> and X:<pp>
+ UINT16 pp ;
+ UINT16 W ;
+
+ unsigned char sdrt = 0x00 ;
+ void *sdrReg = 0x00 ;
+ sdrReg = DecodeRRTable(BITS(OP,0x00c0), &sdrt) ;
+
+ pp = BITS(OP,0x001f) ;
+ pp = AssembleAddressFromIOShortAddress(pp) ;
+
+ W = BITS(OP,0x0100) ;
+
+ // A little different than most W if's - opposite read and write thingies...
+ if (W)
+ {
+ UINT16 data = data_read_word_16le( (*((UINT16*)sdrReg))<<1 ) ; // read the word out
+ SetDataMemoryValue(&data, DT_WORD, pp<<1) ;
+ }
+ else
+ {
+ mame_printf_debug("NOTHING HERE (yet)\n") ;
+ }
+
+ // Postincrement
+ ExecutemTable(BITS(OP,0x00c0), BITS(OP,0x0020)) ;
+ }
+
+ return retSize ;
+}
+
+
+static int JmpOperation(void)
+{
+ int retSize = 0 ;
+
+ dsp56k.ppc = PC;
+
+ if (BITS(OP,0x0010))
+ {
+ PC = (ROPCODE((PC<<1)+2)) ; // Can this offset by 2 bytes be handled better? Say, for example, by moving "1 word"?
+ change_pc(PC) ;
+ }
+ else
+ {
+ unsigned char rt = 0x00 ;
+ void *R = 0x00 ;
+
+ R = DecodeRRTable(BITS(OP,0x0003), &rt);
+
+ PC = *((UINT16*)R);
+ change_pc(PC);
+ }
+
+ retSize = 0 ; // Jump with no offset.
+
+ return retSize ;
+}
+
+static int BsrOperation(void)
+{
+ int retSize = 0 ;
+
+ INT16 branchOffset = (ROPCODE((PC<<1)+2)) ; // Can this offset by 2 bytes be handled better? Say, for example, by moving "1 word"?
+
+ // "The PC Contains the address of the next instruction"
+ PC += 2 ;
+ dsp56k.ppc = PC ;
+
+ // Push the PC to the stack...
+ SP++ ; // !!! I'm not so sure about this 'pre-increment'
+ // The reason it might be there is that SSH and SSL are supposed to point to the top of the
+ // stack (and the docs seem to imply this behaviour). But it wastes the first stack entry ???
+ // !!! I think i've read somewhere that PC == 1 when the stack is empty ???
+ // !!! I also .know. there are only 15 stack entries - could this be why ???
+ SSH = PC ;
+ SSL = SR ;
+
+ PC += branchOffset ;
+
+ retSize = 0 ; // Branch and then no offset.
+
+ change_pc(PC) ;
+
+ return retSize ;
+}
+
+static int JsrOperation(void)
+{
+ int retSize = 0;
+
+ // Handle other JSR types!
+ INT16 branchOffset = (ROPCODE((PC<<1)+2)) ; // Can this offset by 2 bytes be handled better? Say, for example, by moving "1 word"?
+
+ // The docs say nothing of this, but I swear it *must* be true
+ PC += 2 ;
+ dsp56k.ppc = PC ;
+
+ // See bsr operation
+ SP++;
+ SSH = PC;
+ SSL = SR;
+
+ PC = branchOffset;
+
+ return retSize;
+}
+
+static int BraOperation(void)
+{
+ int retSize = 0 ;
+
+ // Branch to the location in program memory at location PC+displacement.
+ INT16 branchOffset = 0x00;
+
+ if (BITS(OP,0x0800))
+ {
+ // 8 bit immediate (relative) offset
+ branchOffset = (INT8)BITS(OP,0x00ff) ;
+
+ // "The PC Contains the address of the next instruction"
+ PC += 1 ;
+ }
+ else if (BITS(OP,0x0010))
+ {
+ // 16 bit immediate (relative) offset
+ retSize = 666 ;
+ }
+ else if (!BITS(OP,0x0010))
+ {
+ // 16 bit Rx offset
+ retSize = 666 ;
+ }
+
+ dsp56k.ppc = PC ;
+ PC += branchOffset ;
+
+ change_pc(PC) ;
+
+ return retSize ;
+}
+
+
+static int DoOperation(void)
+{
+ int retSize = 0 ;
+
+ UINT16 offset ;
+
+ // First instruction cycle
+ SP++ ;
+ SSH = LA ;
+ SSL = LC ;
+
+ if (BITS(OP,0x0800))
+ {
+ // #xx,expr
+ LC = BITS(OP,0x00ff) ;
+ retSize = 2 ;
+ }
+ else if (BITS(OP,0x0400))
+ {
+ // S,expr
+ unsigned char sdt = 0x00 ;
+ void *SD ;
+
+ // !!! Watch out for the special cases (FamilyManual page 276) !!!
+ SD = DecodeDDDDDTable(BITS(OP,0x001f), &sdt) ;
+ SetDestinationValue(SD, sdt, &LC, DT_WORD) ;
+ retSize = 2 ;
+ }
+ else
+ {
+ // X:(Rn),expr
+ retSize = 666 ;
+ }
+
+
+ // Second instruction cycle
+ SP++ ;
+ SSH = PC+2 ; // The value in the Program Counter (PC) register pushed onto the system stack is the address of the first instruction following the DO instruction
+ SSL = SR ;
+
+ offset = 0x00 ; // The offset is the same for all DO instructions...
+ offset = (ROPCODE((PC<<1)+2)) ;
+ offset += PC+2 ;
+ LA = offset ;
+
+
+ // Third instruction cycle
+ SET_lfBIT() ;
+
+ return retSize ;
+}
+
+static void EndOfLoopProcessing(void)
+{
+ SR = SSL ;
+ SP-- ;
+ LA = SSH ;
+ LC = SSL ;
+ SP-- ;
+}
+
+static int Dec24Operation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ UINT64 decMe ;
+
+ unsigned char drt = 0x00 ;
+ void *D = 0x00 ;
+ D = DecodeFTable(BITS(OP,0x0008), &drt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value
+
+ // !! I wonder if this should be a signed int instead !!
+ decMe = (*((UINT64*)D) & (UINT64)U64(0xffffff0000)) >> 16 ;
+ decMe-- ;
+ decMe &= (UINT64)U64(0x0000000000ffffff) ; // For wraparound - Make sure no bits get set improperly in A/B
+
+// UINT8 carryBit = (*((UINT64*)D) & 0x0000008000000000) >> 39 ; // For determinating carry status...
+
+ *((UINT64*)D) &= (UINT64)U64(0x000000000000ffff) ; // Prepare the destination to be set...
+ *((UINT64*)D) |= (decMe << 16) ; // Set the top 24 bits accordingly...
+
+ // Carry flag (C) - HACK
+// if (decMe == 0x0000000000ff7fff)
+// SET_cBIT() ;
+// else
+// CLEAR_cBIT() ;
+
+ // Carry flag (C)
+// UINT8 postCarryBit = (*((UINT64*)D) & 0x0000008000000000) >> 39 ;
+// if (postCarryBit != carryBit) SET_cBIT() ;
+// else CLEAR_cBIT() ;
+
+ *wd = D ;
+
+/*
+ UINT32 decMe = ((*((PAIR64*)D)).b.h4 << 16) | (*((PAIR64*)D)).w.h ;
+
+ int fflag = 0 ;
+ if (decMe == 0x00007fff) fflag = 1 ;
+
+ if (fflag) mame_printf_debug("%08x\n", decMe) ;
+
+ decMe-- ;
+
+ if (fflag) mame_printf_debug("%08x\n", decMe) ;
+
+ decMe &= 0x00ffffff ;
+
+ if (fflag) mame_printf_debug("%08x\n", decMe) ;
+
+ UINT8 carryBit = ((*((PAIR64*)D)).b.h4 & 0x80) >> 7 ;
+
+ (*((PAIR64*)D)).b.h4 = (decMe & 0x00ff0000) >> 16 ;
+ (*((PAIR64*)D)).w.h = (decMe & 0x0000ffff) ;
+
+ if (fflag) mame_printf_debug("%2x\n", (*((PAIR64*)D)).b.h4) ;
+ if (fflag) mame_printf_debug("%4x\n", (*((PAIR64*)D)).w.h) ;
+
+ // Carry flag (C)
+ UINT8 postCarryBit = ((*((PAIR64*)D)).b.h4 & 0x80) >> 7 ;
+ if (postCarryBit != carryBit) SET_cBIT() ;
+ else CLEAR_cBIT() ;
+
+ *wd = D ;
+*/
+ return retSize ;
+}
+
+static int AddOperation(void **wd, UINT64 *pa)
+{
+ UINT64 addVal = 0x00;
+
+ unsigned char st = 0x00, dt = 0x00 ;
+ void *S = 0x00, *D = 0x00;
+
+ DecodeJJJFTable(BITS(OP,0x0007),BITS(OP,0x0008), &S, &st, &D, &dt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value
+
+ switch(st)
+ {
+ case DT_WORD: addVal = (UINT64)*((UINT16*)S) << 16 ; break ;
+ case DT_DOUBLE_WORD: addVal = (UINT64)*((UINT32*)S) ; break ;
+ case DT_LONG_WORD: addVal = (UINT64)*((UINT64*)S) ; break ;
+ }
+
+ *((UINT64*)D) += addVal ;
+
+ *wd = D ;
+
+ return 1 ;
+}
+
+static int LsrOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ UINT16 result ;
+
+ unsigned char dt = 0x00 ;
+ void *D = 0x00 ;
+
+ D = DecodeFTable(BITS(OP,0x0008), &dt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value
+
+ // !!! Make sure to hold the MS bit and shift the LS bit properly !!!
+
+ result = (*((PAIR64*)D)).w.h >> 1 ;
+ (*((PAIR64*)D)).w.h = result ;
+
+ *wd = D ;
+ return retSize ;
+}
+
+static int AsrOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ unsigned char dt = 0x00 ;
+ void *D = 0x00 ;
+
+ D = DecodeFTable(BITS(OP,0x0008), &dt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value
+
+ // !!! Make sure to hold the MS bit and shift the LS bit properly !!!
+
+ *((UINT64*)D) = (*((UINT64*)D)) >> 1 ;
+
+ *wd = D ;
+ return retSize ;
+}
+
+static int NotOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ unsigned char dt = 0x00 ;
+ void *D = 0x00 ;
+
+ D = DecodeFTable(BITS(OP,0x0008), &dt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value
+
+ (*((PAIR64*)D)).w.h ^= 0xffff ;
+
+ *wd = D ;
+ return retSize ;
+}
+
+
+static int EorOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ UINT16 result ;
+
+ unsigned char st = 0x00, dt = 0x00 ;
+ void *S = 0x00, *D = 0x00;
+
+ DecodeJJFTable(BITS(OP,0x0003),BITS(OP,0x0008), &S, &st, &D, &dt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value
+
+ // This operation does an XOR of a word of S with A1/B1...
+ result = *((UINT16*)S) ^ (*((PAIR64*)D)).w.h ;
+ (*((PAIR64*)D)).w.h = result ;
+
+ *wd = D ;
+ return retSize ;
+}
+
+static int TfrDataALUOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ unsigned char st = 0x00, dt = 0x00 ;
+ void *S = 0x00, *D = 0x00;
+
+ DecodeJJJFTable(BITS(OP,0x0007),BITS(OP,0x0008), &S, &st, &D, &dt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value
+
+ SetDestinationValue(S, st, D, dt) ;
+
+ *wd = D ;
+ return retSize ;
+}
+
+static int AndOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ UINT16 result ;
+
+ unsigned char st = 0x00, dt = 0x00 ;
+ void *S = 0x00, *D = 0x00;
+
+ DecodeJJFTable(BITS(OP,0x0003),BITS(OP,0x0008), &S, &st, &D, &dt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value
+
+ // This operation does an AND of a word of S with A1/B1...
+ result = *((UINT16*)S) & (*((PAIR64*)D)).w.h ;
+ (*((PAIR64*)D)).w.h = result ;
+
+ *wd = D ;
+ return retSize ;
+}
+
+static int OrOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ UINT16 result ;
+
+ unsigned char st = 0x00, dt = 0x00 ;
+ void *S = 0x00, *D = 0x00;
+
+ DecodeJJFTable(BITS(OP,0x0003),BITS(OP,0x0008), &S, &st, &D, &dt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value
+
+ // This operation does an OR of a word of S with A1/B1...
+ result = *((UINT16*)S) | (*((PAIR64*)D)).w.h ;
+ (*((PAIR64*)D)).w.h = result ;
+
+ *wd = D ;
+ return retSize ;
+}
+
+
+static int TccOperation(void)
+{
+ int retSize = 1 ;
+
+ int transfer = DecodeccccTable(BITS(OP,0x03c0)) ;
+
+ // !!! WARNING === TESTING !!!
+ // transfer = 1 ;
+
+ if (transfer)
+ {
+ unsigned char st = 0x00, dt = 0x00 ;
+ void *S = 0x00, *D = 0x00;
+
+ unsigned char drt = 0x00 ;
+ void *destinationReg = 0x00 ;
+
+ Decodeh0hFTable(BITS(OP,0x0007),BITS(OP,0x0008), &S, &st, &D, &dt) ;
+
+ SetDestinationValue(S, st, D, dt) ;
+
+ // !!! What's up with that A,A* thing in the docs? Does that mean "do not transfer R0 to Rn ???
+ destinationReg = DecodeRRTable(BITS(OP,0x0030), &drt) ; // Actually a TT table, but it's the same
+
+ SetDestinationValue(&R0, DT_WORD, destinationReg, drt) ;
+ }
+
+ // Otherwise it's a NOP
+
+ return retSize ;
+}
+
+static int ClrOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ UINT64 clearValue = 0 ;
+
+ unsigned char drt = 0x00 ;
+ void *destinationReg = 0x00 ;
+
+ destinationReg = DecodeFTable(BITS(OP,0x0008), &drt) ;
+
+ *pa = *((UINT64*)destinationReg) ; // backup the previous value
+
+ SetDestinationValue(&clearValue, DT_LONG_WORD, destinationReg, drt) ;
+
+ *wd = destinationReg ;
+ return retSize ;
+}
+
+static int TstOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ unsigned char drt = 0x00 ;
+ void *destinationReg = 0x00 ;
+ destinationReg = DecodeFTable(BITS(OP,0x0008), &drt) ;
+
+ // S - "computed according to the standard definition (section A.4)"
+ // L - can't be done until after data move
+ // E - set if signed integer portion is in use
+ // U - set according to the standard definition of the U bit
+ // N - set if bit 39 is set
+ if (*((UINT64*)destinationReg) & (UINT64)U64(0x8000000000)) SET_nBIT();
+ else CLEAR_nBIT();
+
+ // Z - set if == 0
+ if (*((UINT64*)destinationReg) == 0) SET_zBIT();
+ else CLEAR_zBIT();
+
+ // V&C - always cleared
+ CLEAR_vBIT();
+ CLEAR_cBIT();
+
+ *pa = *((UINT64*)destinationReg) ; // backup the previous value (no change here)
+ *wd = destinationReg;
+
+ return retSize ;
+}
+
+static int AndiOperation(void)
+{
+ int retSize = 1 ;
+
+ UINT16 andMe = BITS(OP,0x00ff) ;
+
+ // Because I don't have a good way to access MR and CCR right now, i'm going to
+ // hard-code decoding EE here and in the OriOperation as well...
+ switch(BITS(OP,0x0600))
+ {
+ // MR
+ case 0x01:
+ SR &= ((andMe << 8) | 0x00ff) ;
+ break ;
+
+ // CCR
+ case 0x03:
+ SR &= ((andMe) | 0xff00) ;
+ break ;
+
+ // OMR
+ case 0x02:
+ OMR &= (UINT8)(andMe) ;
+ break ;
+
+ default:
+ fatalerror("DSP56k - BAD EE value in andi operation") ;
+ }
+
+
+ return retSize ;
+}
+
+#ifdef UNUSED_FUNCTION
+// !!! NOT IMPLEMENTED YET - JUST PUT HERE TO BE NEXT TO ANDI SOMEDAY !!!
+static int OriOperation(void)
+{
+ int retSize = 1 ;
+
+ return retSize ;
+}
+#endif
+
+static int CmpOperation(void **wd, UINT64 *pa)
+{
+ int retSize = 1 ;
+
+ UINT64 cmpVal ;
+ UINT64 result ;
+
+ unsigned char st = 0x00, dt = 0x00 ;
+ void *S = 0x00, *D = 0x00;
+
+ DecodeJJJFTable(BITS(OP,0x0007),BITS(OP,0x0008), &S, &st, &D, &dt) ;
+
+ *pa = *((UINT64*)D) ; // backup the previous value - not necessary for cmp :)
+
+ switch(st)
+ {
+ default:
+ case DT_WORD: cmpVal = (UINT64)*((UINT16*)S) ; break ;
+ case DT_DOUBLE_WORD: cmpVal = (UINT64)*((UINT32*)S) ; break ;
+ case DT_LONG_WORD: cmpVal = (UINT64)*((UINT64*)S) ; break ;
+ }
+
+ result = *((UINT64*)D) - cmpVal ;
+
+ if (result == 0)
+ SET_zBIT() ;
+ else
+ CLEAR_zBIT() ;
+
+ *wd = D ;
+ return retSize ;
+}
+
+static int BsccOperation(void)
+{
+ int retSize = 0 ;
+
+ // Decode the condition
+ int transfer = DecodeccccTable(BITS(OP,0x000f)) ;
+
+ // TESTING !!!
+ // transfer = 0 ;
+
+ // 1 or 2 word operation...
+ if (transfer)
+ {
+ if (BITS(OP,0x0010))
+ {
+ // 2 word immediate offset...
+ INT16 branchOffset = (INT16)ROPCODE((PC<<1)+2) ;
+
+ // "The PC Contains the address of the next instruction"
+ PC += 2 ;
+ dsp56k.ppc = PC ;
+
+ SP++ ;
+ SSH = PC ;
+ SSL = SR ;
+
+ PC += branchOffset ;
+
+ change_pc(PC) ;
+ }
+ else
+ {
+ // 1 word Rx offset...
+ }
+
+ retSize = 0 ;
+ }
+ else
+ {
+ if (BITS(OP,0x0010))
+ retSize = 2 ;
+ else
+ retSize = 1 ;
+ }
+
+ return retSize ;
+}
+
+static int BccOperation(void)
+{
+ int retSize = 0 ;
+
+ if (!BITS(OP,0x2000))
+ {
+ int branch = DecodeccccTable(BITS(OP,0x000f)) ;
+
+ if (branch)
+ {
+ if (BITS(OP,0x0010))
+ {
+ // B.cc xxxx
+ INT16 op2 = ROPCODE((PC<<1)+2) ;
+
+ // The PC contains the address of the next instruction
+ PC += 2 ;
+ dsp56k.ppc = PC ;
+ PC += op2 ;
+
+ change_pc(PC) ;
+ }
+ else
+ {
+ // B.cc Rn
+ }
+ }
+ else
+ {
+ if (BITS(OP,0x0010))
+ retSize = 2 ;
+ else
+ retSize = 1 ;
+ }
+ }
+ else
+ {
+ // B.cc aa
+ int branch = DecodeccccTable(BITS(OP,0x03c0)) ;
+
+ if (branch)
+ {
+ INT16 offset = (INT16)AssembleAddressFrom6BitSignedRelativeShortAddress(BITS(OP,0x003f)) ;
+
+ PC += 1 ;
+ dsp56k.ppc = PC ;
+ PC += offset ;
+
+ change_pc(PC) ;
+ }
+ else
+ {
+ retSize = 1 ;
+ }
+ }
+
+ return retSize ;
+}
+
+static int Tst2Operation(void)
+{
+ int retSize = 1 ;
+
+ unsigned char dt = 0x00 ;
+ void *destinationReg = 0x00 ;
+
+ destinationReg = DecodeDDTable(BITS(OP,0x0003), &dt) ;
+
+ // unnormalized
+
+ // negative
+ // bit 31 of A or B ???
+
+ // zero
+ if ( (*((UINT16*)destinationReg)) == 0)
+ SET_zBIT() ;
+ else
+ CLEAR_zBIT() ;
+
+ // always clear C flag
+ CLEAR_cBIT() ;
+
+ return retSize ;
+}
+
+static int MACsuuuOperation(void)
+{
+ int retSize = 1 ;
+
+ INT64 result = 0 ;
+
+ int s ;
+ void *S1 = 0x00, *S2 = 0x00, *D = 0x00 ;
+
+ DecodeQQFTableSp(BITS(OP,0x0003), BITS(OP,0x0008), &S1, &S2, &D) ;
+
+ s = BITS(OP,0x0004) ;
+
+ // !!! There is no way this is right - wtf is EXT:MSP:LSP format ???
+ if (!s)
+ {
+ // su
+ result = ( (INT32)(*((UINT16*)S1)) * (UINT32)(*((UINT16*)S2)) ) << 1 ;
+ }
+ else
+ {
+ // uu
+ result = ( (UINT32)(*((UINT16*)S1)) * (UINT32)(*((UINT16*)S2)) ) << 1 ;
+ }
+
+ (*((UINT64*)D)) += result ;
+
+ return retSize ;
+}
+
+static int RepOperation(void)
+{
+ int retSize = 1 ;
+
+ UINT16 count = 0x0000 ;
+
+ if (BITS(OP,0x0f00) == 0xf)
+ {
+ // immediate
+ count = BITS(OP,0x00ff) ;
+ }
+ else if (BITS(OP,0x0f00) == 0x4)
+ {
+ // SD
+ unsigned char st = 0x00 ;
+ void *S ;
+
+ S = DecodeDDDDDTable(BITS(OP,0x001f), &st) ;
+ SetDestinationValue(S, st, &count, DT_WORD);
+ }
+ else
+ {
+ // X:(Rn)
+ }
+
+ TEMP = LC ;
+ LC = count ;
+
+ dsp56k.repFlag = 1 ;
+ dsp56k.repAddr = PC + (retSize<<1) ;
+
+ return retSize ;
+}
+
+static void EndOfRepProcessing(void)
+{
+ LC = TEMP ;
+
+ dsp56k.repFlag = 0 ;
+ dsp56k.repAddr = 0x0000 ;
+}
+
+
+/*
+DECODERS
+*/
+static void *DecodeDDDDDTable(UINT16 DDDDD, unsigned char *dt)
+{
+ void *retAddress = 0x00 ;
+
+ switch(DDDDD)
+ {
+ case 0x00: retAddress = &X0 ; *dt = DT_WORD ; break ;
+ case 0x01: retAddress = &Y0 ; *dt = DT_WORD ; break ;
+ case 0x02: retAddress = &X1 ; *dt = DT_WORD ; break ;
+ case 0x03: retAddress = &Y1 ; *dt = DT_WORD ; break ;
+ case 0x04: retAddress = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x05: retAddress = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x06: retAddress = &A0 ; *dt = DT_WORD ; break ;
+ case 0x07: retAddress = &B0 ; *dt = DT_WORD ; break ;
+ case 0x08: retAddress = &LC ; *dt = DT_WORD ; break ;
+ case 0x09: retAddress = &SR ; *dt = DT_WORD ; break ;
+ case 0x0a: retAddress = &OMR ; *dt = DT_BYTE ; break ;
+ case 0x0b: retAddress = &SP ; *dt = DT_BYTE ; break ;
+ case 0x0c: retAddress = &A1 ; *dt = DT_WORD ; break ;
+ case 0x0d: retAddress = &B1 ; *dt = DT_WORD ; break ;
+ case 0x0e: retAddress = &A2 ; *dt = DT_BYTE ; break ;
+ case 0x0f: retAddress = &B2 ; *dt = DT_BYTE ; break ;
+
+ case 0x10: retAddress = &R0 ; *dt = DT_WORD ; break ;
+ case 0x11: retAddress = &R1 ; *dt = DT_WORD ; break ;
+ case 0x12: retAddress = &R2 ; *dt = DT_WORD ; break ;
+ case 0x13: retAddress = &R3 ; *dt = DT_WORD ; break ;
+ case 0x14: retAddress = &M0 ; *dt = DT_WORD ; break ;
+ case 0x15: retAddress = &M1 ; *dt = DT_WORD ; break ;
+ case 0x16: retAddress = &M2 ; *dt = DT_WORD ; break ;
+ case 0x17: retAddress = &M3 ; *dt = DT_WORD ; break ;
+ case 0x18: retAddress = &SSH ; *dt = DT_WORD ; break ;
+ case 0x19: retAddress = &SSL ; *dt = DT_WORD ; break ;
+ case 0x1a: retAddress = &LA ; *dt = DT_WORD ; break ;
+ //no 0x1b
+ case 0x1c: retAddress = &N0 ; *dt = DT_WORD ; break ;
+ case 0x1d: retAddress = &N1 ; *dt = DT_WORD ; break ;
+ case 0x1e: retAddress = &N2 ; *dt = DT_WORD ; break ;
+ case 0x1f: retAddress = &N3 ; *dt = DT_WORD ; break ;
+ }
+
+ return retAddress ;
+}
+
+static void *DecodeRRTable(UINT16 RR, unsigned char *dt)
+{
+ void *retAddress = 0x00 ;
+
+ switch(RR)
+ {
+ case 0x00: retAddress = &R0 ; *dt = DT_WORD ; break ;
+ case 0x01: retAddress = &R1 ; *dt = DT_WORD ; break ;
+ case 0x02: retAddress = &R2 ; *dt = DT_WORD ; break ;
+ case 0x03: retAddress = &R3 ; *dt = DT_WORD ; break ;
+ }
+
+ return retAddress ;
+}
+
+static void *DecodeDDTable(UINT16 DD, unsigned char *dt)
+{
+ void *retAddress = 0x00 ;
+
+ switch(DD)
+ {
+ case 0x00: retAddress = &X0 ; *dt = DT_WORD ; break ;
+ case 0x01: retAddress = &Y0 ; *dt = DT_WORD ; break ;
+ case 0x02: retAddress = &X1 ; *dt = DT_WORD ; break ;
+ case 0x03: retAddress = &Y1 ; *dt = DT_WORD ; break ;
+ }
+
+ return retAddress ;
+}
+
+static void *DecodeHHHTable(UINT16 HHH, unsigned char *dt)
+{
+ void *retAddress = 0x00 ;
+
+ switch(HHH)
+ {
+ case 0x0: retAddress = &X0 ; *dt = DT_WORD ; break ;
+ case 0x1: retAddress = &Y0 ; *dt = DT_WORD ; break ;
+ case 0x2: retAddress = &X1 ; *dt = DT_WORD ; break ;
+ case 0x3: retAddress = &Y1 ; *dt = DT_WORD ; break ;
+ case 0x4: retAddress = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x5: retAddress = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x6: retAddress = &A0 ; *dt = DT_WORD ; break ;
+ case 0x7: retAddress = &B0 ; *dt = DT_WORD ; break ;
+ }
+
+ return retAddress ;
+}
+
+static void *DecodeHHTable(UINT16 HH, unsigned char *dt)
+{
+ void *retAddress = 0x00 ;
+
+ switch(HH)
+ {
+ case 0x0: retAddress = &X0 ; *dt = DT_WORD ; break ;
+ case 0x1: retAddress = &Y0 ; *dt = DT_WORD ; break ;
+ case 0x2: retAddress = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x3: retAddress = &B ; *dt = DT_LONG_WORD ; break ;
+ }
+
+ return retAddress ;
+}
+
+static void *DecodeZTable(UINT16 Z, unsigned char *dt)
+{
+ void *retAddress = 0x00 ;
+
+ switch(Z)
+ {
+ // Fixed as per the Family Manual addendum
+ case 0x01: retAddress = &A1 ; *dt = DT_WORD ; break ;
+ case 0x00: retAddress = &B1 ; *dt = DT_WORD ; break ;
+ }
+
+ return retAddress ;
+}
+
+
+static UINT16 DecodeBBBBitMask(UINT16 BBB, UINT16 *iVal)
+{
+ UINT16 retVal = 0x00 ;
+
+ switch(BBB)
+ {
+ case 0x4: retVal = 0xff00 ; *iVal <<= 8 ; break ;
+ case 0x2: retVal = 0x0ff0 ; *iVal <<= 4 ; break ;
+ case 0x1: retVal = 0x00ff ; *iVal <<= 0 ; break ;
+ }
+
+ return retVal ;
+}
+
+static void ExecuteMMTable(int x, UINT16 MM)
+{
+ UINT16 *rX = 0x00 ;
+ UINT16 *nX = 0x00 ;
+
+ switch(x)
+ {
+ case 0x0: rX = &R0 ; nX = &N0 ; break ;
+ case 0x1: rX = &R1 ; nX = &N1 ; break ;
+ case 0x2: rX = &R2 ; nX = &N2 ; break ;
+ case 0x3: rX = &R3 ; nX = &N3 ; break ;
+ }
+
+ switch(MM)
+ {
+ case 0x0: /* do nothing */ break ;
+ case 0x1: (*rX)++ ; break ;
+ case 0x2: (*rX)-- ; break ;
+ case 0x3: (*rX) = (*rX)+(*nX) ; break ;
+ }
+}
+
+static void ExecutemTable(int x, UINT16 m)
+{
+ UINT16 *rX = 0x00 ;
+ UINT16 *nX = 0x00 ;
+
+ switch(x)
+ {
+ case 0x0: rX = &R0 ; nX = &N0 ; break ;
+ case 0x1: rX = &R1 ; nX = &N1 ; break ;
+ case 0x2: rX = &R2 ; nX = &N2 ; break ;
+ case 0x3: rX = &R3 ; nX = &N3 ; break ;
+ }
+
+ switch(m)
+ {
+ case 0x0: (*rX)++ ; break ;
+ case 0x1: (*rX) = (*rX)+(*nX) ; break ;
+ }
+}
+
+static void ExecutezTable(int x, UINT16 z)
+{
+ UINT16 *rX = 0x00 ;
+ UINT16 *nX = 0x00 ;
+
+ switch(x)
+ {
+ case 0x0: rX = &R0 ; nX = &N0 ; break ;
+ case 0x1: rX = &R1 ; nX = &N1 ; break ;
+ case 0x2: rX = &R2 ; nX = &N2 ; break ;
+ case 0x3: rX = &R3 ; nX = &N3 ; break ;
+ }
+
+ if (!z)
+ {
+ (*rX)-- ;
+ }
+ else
+ {
+ (*rX) = (*rX)+(*nX) ;
+ }
+}
+
+// Returns R address
+static UINT16 ExecuteqTable(int x, UINT16 q)
+{
+ UINT16 *rX = 0x00 ;
+ UINT16 *nX = 0x00 ;
+
+ switch(x)
+ {
+ case 0x0: rX = &R0 ; nX = &N0 ; break ;
+ case 0x1: rX = &R1 ; nX = &N1 ; break ;
+ case 0x2: rX = &R2 ; nX = &N2 ; break ;
+ case 0x3: rX = &R3 ; nX = &N3 ; break ;
+ }
+
+ switch(q)
+ {
+ case 0x0: /* No permanent changes */ ; return (*rX)+(*nX); break;
+ case 0x1: (*rX)--; return (*rX); break; // This one is special - it's a *PRE-decrement*!
+ }
+
+ exit(1);
+ return 0x00;
+}
+
+static UINT16 AssembleDFromPTable(UINT16 P, UINT16 ppppp)
+{
+ UINT16 destAddr = 0x00 ;
+
+ switch (P)
+ {
+ case 0x0: destAddr = ppppp ; break ;
+ case 0x1: destAddr = AssembleAddressFromIOShortAddress(ppppp) ; break ;
+ }
+
+ return destAddr ;
+}
+
+
+static UINT16 AssembleAddressFromIOShortAddress(UINT16 pp)
+{
+ UINT16 fullAddy = 0xffe0 ;
+ fullAddy |= pp ;
+ return fullAddy ;
+}
+
+static UINT16 AssembleAddressFrom6BitSignedRelativeShortAddress(UINT16 srs)
+{
+ UINT16 fullAddy = srs ;
+ if (fullAddy & 0x0020) fullAddy |= 0xffc0 ;
+
+ return fullAddy ;
+}
+
+static int DecodeccccTable(UINT16 cccc)
+{
+ int retVal = 0 ;
+
+ // !!! go back and check me again someday - potential bugs !!!
+ switch (cccc)
+ {
+ // Arranged according to mnemonic table - not decoding table...
+ case 0x0: if( cBIT == 0) retVal = 1 ; break ; // cc(hs)
+ case 0x8: if( cBIT == 1) retVal = 1 ; break ; // cs(lo)
+ case 0x5: if( eBIT == 0) retVal = 1 ; break ; // ec
+ case 0xa: if( zBIT == 1) retVal = 1 ; break ; // eq
+ case 0xd: if( eBIT == 1) retVal = 1 ; break ; // es
+ case 0x1: if((nBIT ^ vBIT) == 0) retVal = 1 ; break ; // ge
+ case 0x7: if((zBIT + (nBIT ^ vBIT)) == 0) retVal = 1 ; break ; // gt
+ case 0x6: if( lBIT == 0) retVal = 1 ; break ; // lc
+ case 0xf: if((zBIT + (nBIT ^ vBIT)) == 1) retVal = 1 ; break ; // le
+ case 0xe: if( lBIT == 1) retVal = 1 ; break ; // ls
+ case 0x9: if((nBIT ^ vBIT) == 1) retVal = 1 ; break ; // lt
+ case 0xb: if( nBIT == 1) retVal = 1 ; break ; // mi
+ case 0x2: if( zBIT == 0) retVal = 1 ; break ; // ne
+ case 0xc: if((zBIT + ((!uBIT) & (!eBIT))) == 1) retVal = 1 ; break ; // nr
+ case 0x3: if( nBIT == 0) retVal = 1 ; break ; // pl
+ case 0x4: if((zBIT + ((!uBIT) & (!eBIT))) == 0) retVal = 1 ; break ; // nn
+ }
+
+ return retVal ;
+}
+
+static void Decodeh0hFTable(UINT16 h0h, UINT16 F,
+ void **source, unsigned char *st,
+ void **dest, unsigned char *dt)
+{
+ UINT16 switchVal = (h0h << 1) | F ;
+
+ switch (switchVal)
+ {
+ case 0x8: *source = &X0 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x9: *source = &X0 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0xa: *source = &Y0 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0xb: *source = &Y0 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x2: *source = &A ; *st = DT_LONG_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x1: *source = &A ; *st = DT_LONG_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x0: *source = &B ; *st = DT_LONG_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x3: *source = &B ; *st = DT_LONG_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ }
+}
+
+static void *DecodeFTable(UINT16 F, unsigned char *dt)
+{
+ void *retAddress = 0x00 ;
+
+ switch(F)
+ {
+ case 0x0: retAddress = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x1: retAddress = &B ; *dt = DT_LONG_WORD ; break ;
+ }
+
+ return retAddress ;
+}
+
+static void DecodeJJJFTable(UINT16 JJJ, UINT16 F,
+ void **source, unsigned char *st,
+ void **dest, unsigned char *dt)
+{
+ UINT16 switchVal = (JJJ << 1) | F ;
+
+ switch(switchVal)
+ {
+ case 0x0: *source = &B ; *st = DT_LONG_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x1: *source = &A ; *st = DT_LONG_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x4: *source = &X ; *st = DT_DOUBLE_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x5: *source = &X ; *st = DT_DOUBLE_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x6: *source = &Y ; *st = DT_DOUBLE_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x7: *source = &Y ; *st = DT_DOUBLE_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x8: *source = &X0 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x9: *source = &X0 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0xa: *source = &Y0 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0xb: *source = &Y0 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0xc: *source = &X1 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0xd: *source = &X1 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0xe: *source = &Y1 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0xf: *source = &Y1 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ }
+}
+
+static void DecodeJJFTable(UINT16 JJ, UINT16 F,
+ void **source, unsigned char *st,
+ void **dest, unsigned char *dt)
+{
+ UINT16 switchVal = (JJ << 1) | F ;
+
+ switch (switchVal)
+ {
+ case 0x0: *source = &X0 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x1: *source = &X0 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x2: *source = &Y0 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x3: *source = &Y0 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x4: *source = &X1 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x5: *source = &X1 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ case 0x6: *source = &Y1 ; *st = DT_WORD ; *dest = &A ; *dt = DT_LONG_WORD ; break ;
+ case 0x7: *source = &Y1 ; *st = DT_WORD ; *dest = &B ; *dt = DT_LONG_WORD ; break ;
+ }
+}
+
+// Types not necessary - we know what we are...
+static void DecodeQQFTableSp(UINT16 QQ, UINT16 F, void **S1, void **S2, void **D)
+{
+ UINT16 switchVal = (QQ << 1) | F ;
+
+ switch(switchVal)
+ {
+ case 0x0: *S1 = &Y0 ; *S2 = &X0 ; *D = &A ; break ;
+ case 0x1: *S1 = &Y0 ; *S2 = &X0 ; *D = &B ; break ;
+ case 0x2: *S1 = &Y1 ; *S2 = &X0 ; *D = &A ; break ;
+ case 0x3: *S1 = &Y1 ; *S2 = &X0 ; *D = &B ; break ;
+ case 0x4: *S1 = &X1 ; *S2 = &Y0 ; *D = &A ; break ;
+ case 0x5: *S1 = &X1 ; *S2 = &Y0 ; *D = &B ; break ;
+ case 0x6: *S1 = &X1 ; *S2 = &Y1 ; *D = &A ; break ;
+ case 0x7: *S1 = &X1 ; *S2 = &Y1 ; *D = &B ; break ;
+ }
+}
+
+static void DecodeIIIITable(UINT16 IIII,
+ void **source, unsigned char *st,
+ void **dest, unsigned char *dt,
+ void *working)
+{
+ void *opposite = 0x00 ;
+
+ if (working == &A) opposite = &B ;
+ else opposite = &A ;
+
+ switch(IIII)
+ {
+ case 0x0: *source = &X0 ; *st = DT_WORD ; *dest = opposite ; *dt = DT_LONG_WORD ; break ;
+ case 0x1: *source = &Y0 ; *st = DT_WORD ; *dest = opposite ; *dt = DT_LONG_WORD ; break ;
+ case 0x2: *source = &X1 ; *st = DT_WORD ; *dest = opposite ; *dt = DT_LONG_WORD ; break ;
+ case 0x3: *source = &Y1 ; *st = DT_WORD ; *dest = opposite ; *dt = DT_LONG_WORD ; break ;
+ case 0x4: *source = &A ; *st = DT_LONG_WORD ; *dest = &X0 ; *dt = DT_WORD ; break ;
+ case 0x5: *source = &B ; *st = DT_LONG_WORD ; *dest = &Y0 ; *dt = DT_WORD ; break ;
+ case 0x6: *source = &A0 ; *st = DT_WORD ; *dest = &X0 ; *dt = DT_WORD ; break ;
+ case 0x7: *source = &B0 ; *st = DT_WORD ; *dest = &Y0 ; *dt = DT_WORD ; break ;
+ case 0x8: *source = working ; *st = DT_LONG_WORD ; *dest = opposite ; *dt = DT_LONG_WORD ; break ;
+ case 0x9: *source = working ; *st = DT_LONG_WORD ; *dest = opposite ; *dt = DT_LONG_WORD ; break ;
+ case 0xc: *source = &A ; *st = DT_LONG_WORD ; *dest = &X1 ; *dt = DT_WORD ; break ;
+ case 0xd: *source = &B ; *st = DT_LONG_WORD ; *dest = &Y1 ; *dt = DT_WORD ; break ;
+ case 0xe: *source = &A0 ; *st = DT_WORD ; *dest = &X1 ; *dt = DT_WORD ; break ;
+ case 0xf: *source = &B0 ; *st = DT_WORD ; *dest = &Y1 ; *dt = DT_WORD ; break ;
+ }
+}
+
+/*
+MEMORY OPS
+*/
+
+static void XMDMOperation(UINT16 parameters, void *working, UINT64 *pa)
+{
+ UINT16 W ;
+ unsigned char rdt = 0x00 ;
+ void *R = 0x00 ;
+
+ unsigned char sdt = 0x00 ;
+ void *SD = 0x00 ;
+
+ // Get the source
+ SD = DecodeHHHTable(BITS(parameters,0x000e), &sdt) ;
+
+ // Get the destination
+ R = DecodeRRTable(BITS(parameters,0x0030), &rdt) ;
+
+ // Move the data
+ W = BITS(parameters,0x0001) ;
+
+ if (W)
+ {
+ // from X:<ea> to SD...
+ // !!! TODO : Fill in similar comments for other "if (W)'s" !!!
+ UINT16 data = data_read_word_16le((*((UINT16*)R))<<1) ; // read the word out
+ SetDestinationValue(&data, DT_WORD, SD, sdt) ;
+ }
+ else
+ {
+ // from SD to X:<ea>...
+
+ // If the source is the same as the ALU destination, use the Previous Accumulator value
+ if (working == SD)
+ {
+ // the value before the ALU operation was executed...
+ SetDataMemoryValue(pa, DT_LONG_WORD, (*((UINT16*)R))<<1) ;
+ }
+ else
+ {
+ // Expected memory move
+ SetDataMemoryValue(SD, sdt, (*((UINT16*)R))<<1) ;
+ }
+ }
+
+ // Postincrement
+ ExecutemTable(BITS(parameters,0x0030), BITS(parameters,0x0040)) ;
+}
+
+static void RRDMOperation(UINT16 parameters, void *working, UINT64 *pa)
+{
+ unsigned char st = 0x00, dt = 0x00 ;
+ void *S = 0x00, *D = 0x00;
+
+ DecodeIIIITable(BITS(parameters,0x000f), &S, &st, &D, &dt, working) ;
+
+ // If the source is what we're working with, use the old value
+ if (S == working)
+ SetDestinationValue(pa, DT_LONG_WORD, D, dt) ;
+ else
+ SetDestinationValue(S, st, D, dt) ;
+}
+
+
+static void XMDMSpecialOperation(UINT16 parameters, void *working)
+{
+ UINT16 W ;
+ UINT16 *dest = 0x00 ;
+
+ // Get the source/destination
+ unsigned char sdt = 0x00 ;
+ void *SD = 0x00 ;
+ SD = DecodeHHHTable(BITS(parameters,0x000e), &sdt) ;
+
+ // Get the opposite A/B depending on what was used before
+ if (working == &A)
+ dest = &B1 ;
+ else if (working == &B)
+ dest = &A1 ;
+ else
+ {
+ mame_printf_debug("WTF MF\n") ;
+ return ;
+ }
+
+ // Move the data
+ W = BITS(parameters,0x0001) ;
+
+ if (W)
+ {
+ // from X:<ea> to SD...
+ // !!! DOES THIS WORK ???
+ UINT16 data = data_read_word_16le((*dest)<<1) ; // read the word out
+ SetDestinationValue(&data, DT_WORD, SD, sdt) ;
+ }
+ else
+ {
+ // Normal memory move
+ SetDataMemoryValue(SD, sdt, (*dest)<<1) ;
+ }
+}
+
+static void ARUOperation(UINT16 parameters)
+{
+ ExecutezTable(BITS(parameters, 0x0003), BITS(parameters, 0x0004)) ;
+}
+
+
+/*
+HELPERS
+*/
+static UINT16 Dsp56kOpMask(UINT16 cur, UINT16 mask)
+{
+ int i ;
+
+ UINT16 retVal = (cur & mask) ;
+ UINT16 temp = 0x0000 ;
+ int offsetCount = 0 ;
+
+ // Shift everything right, eliminating 'whitespace'...
+ for (i = 0; i < 16; i++)
+ {
+ if (mask & (0x1<<i)) // If mask bit is non-zero
+ {
+ temp |= (((retVal >> i) & 0x1) << offsetCount) ;
+ offsetCount++ ;
+ }
+ }
+
+ return temp ;
+}
+
+
+static void SetDestinationValue(void *sourcePointer, unsigned char sourceType,
+ void *destinationPointer, unsigned char destinationType)
+{
+ UINT64 destinationValue = 0 ;
+
+ switch(destinationType)
+ {
+ case DT_BYTE:
+ switch(sourceType)
+ {
+ case DT_BYTE: *((UINT8*)destinationPointer) = *((UINT8*) sourcePointer) ; break ;
+ case DT_WORD: *((UINT8*)destinationPointer) = *((UINT16*)sourcePointer) ; break ;
+ case DT_DOUBLE_WORD: *((UINT8*)destinationPointer) = *((UINT32*)sourcePointer) ; break ;
+ case DT_LONG_WORD: *((UINT8*)destinationPointer) = *((UINT64*)sourcePointer) ; break ;
+ }
+ break ;
+
+ case DT_WORD:
+ switch(sourceType)
+ {
+ case DT_BYTE: *((UINT16*)destinationPointer) = *((UINT8*) sourcePointer) ; break ;
+ case DT_WORD: *((UINT16*)destinationPointer) = *((UINT16*)sourcePointer) ; break ;
+ case DT_DOUBLE_WORD: *((UINT16*)destinationPointer) = *((UINT32*)sourcePointer) ; break ;
+ // !!! This one is interesting too - shifter limiter action !!!
+ case DT_LONG_WORD: *((UINT16*)destinationPointer) = *((UINT64*)sourcePointer) ; break ;
+ }
+ break ;
+
+ case DT_DOUBLE_WORD:
+ switch(sourceType)
+ {
+ case DT_BYTE: *((UINT32*)destinationPointer) = *((UINT8*) sourcePointer) ; break ;
+ case DT_WORD: *((UINT32*)destinationPointer) = *((UINT16*)sourcePointer) ; break ;
+ case DT_DOUBLE_WORD: *((UINT32*)destinationPointer) = *((UINT32*)sourcePointer) ; break ;
+ case DT_LONG_WORD: *((UINT32*)destinationPointer) = *((UINT64*)sourcePointer) ; break ;
+ }
+ break ;
+
+ case DT_LONG_WORD:
+ switch(sourceType)
+ {
+ case DT_BYTE: *((UINT64*)destinationPointer) = *((UINT8*) sourcePointer) ; break ;
+
+ // !!! sign extending works on intel, others ???
+ // !!! Need to check the shift limiter here too !!!
+ case DT_WORD: destinationValue = (*((INT16*)sourcePointer)) << 16 ; // Insure sign extending
+ destinationValue &= (UINT64)U64(0x000000ffffff0000) ;
+ *((UINT64*)destinationPointer) = destinationValue ; break ;
+
+ case DT_DOUBLE_WORD: *((UINT64*)destinationPointer) = *((UINT32*)sourcePointer) ; break ;
+ case DT_LONG_WORD: *((UINT64*)destinationPointer) = *((UINT64*)sourcePointer) ; break ;
+ }
+ break ;
+ }
+}
+
+// !! redundant functions (data and memory) can be handled with function pointers !!
+static void SetDataMemoryValue(void *sourcePointer, unsigned char sourceType, UINT32 destinationAddr)
+{
+ // mame_printf_debug("%d %x\n", sourceType, destinationAddr) ;
+
+ // I wonder if this is how this should be done???
+ switch(sourceType)
+ {
+ case DT_BYTE: data_write_word_16le(destinationAddr, (UINT16)( (*((UINT8*) sourcePointer) & 0xff) ) ) ; break ;
+ case DT_WORD: data_write_word_16le(destinationAddr, (UINT16)( (*((UINT16*)sourcePointer) & 0xffff) ) ) ; break ;
+ case DT_DOUBLE_WORD: data_write_word_16le(destinationAddr, (UINT16)( (*((UINT32*)sourcePointer) & 0x0000ffff) ) ) ; break ;
+
+ // !!! Is this universal ???
+ // !!! Forget not, yon shift-limiter !!!
+ case DT_LONG_WORD: data_write_word_16le(destinationAddr, (UINT16)( ((*((UINT64*)sourcePointer)) & (UINT64)U64(0x00000000ffff0000)) >> 16) ) ; break ;
+ }
+}
+
+static void SetProgramMemoryValue(void *sourcePointer, unsigned char sourceType, UINT32 destinationAddr)
+{
+ // I wonder if this is how this should be done???
+ switch(sourceType)
+ {
+ case DT_BYTE: program_write_word_16le(destinationAddr, (UINT16)( (*((UINT8*) sourcePointer) & 0xff) ) ) ; break ;
+ case DT_WORD: program_write_word_16le(destinationAddr, (UINT16)( (*((UINT16*)sourcePointer) & 0xffff) ) ) ; break ;
+ case DT_DOUBLE_WORD: program_write_word_16le(destinationAddr, (UINT16)( (*((UINT32*)sourcePointer) & 0x0000ffff) ) ) ; break ;
+
+ // !!! Is this universal ???
+ // !!! Forget not, yon shift-limiter !!!
+ case DT_LONG_WORD: program_write_word_16le(destinationAddr, (UINT16)( ((*((UINT64*)sourcePointer)) & (UINT64)U64(0x00000000ffff0000)) >> 16) ) ; break ;
+ }
+}
+
diff --git a/src/emu/cpu/e132xs/32xsdasm.c b/src/emu/cpu/e132xs/32xsdasm.c
new file mode 100644
index 00000000000..fc5a373f13d
--- /dev/null
+++ b/src/emu/cpu/e132xs/32xsdasm.c
@@ -0,0 +1,2135 @@
+/*
+
+ Hyperstone disassembler
+ written by Pierpaolo Prazzoli
+
+*/
+
+#include <math.h>
+#include "debugger.h"
+#include "e132xs.h"
+
+static const char *L_REG[] =
+{
+ "L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9",
+ "L10", "L11", "L12", "L13", "L14", "L15", "L16", "L17", "L18", "L19",
+ "L20", "L21", "L22", "L23", "L24", "L25", "L26", "L27", "L28", "L29",
+ "L30", "L31", "L32", "L33", "L34", "L35", "L36", "L37", "L38", "L39",
+ "L40", "L41", "L42", "L43", "L44", "L45", "L46", "L47", "L48", "L49",
+ "L50", "L51", "L52", "L53", "L54", "L55", "L56", "L57", "L58", "L59",
+ "L60", "L61", "L62", "L63"
+};
+
+static const char *G_REG[] =
+{
+ "PC", "SR", "FER", "G03", "G04", "G05", "G06", "G07", "G08", "G09",
+ "G10", "G11", "G12", "G13", "G14", "G15", "G16", "G17", "SP", "UB",
+ "BCR", "TPR", "TCR", "TR", "WCR", "ISR", "FCR", "MCR", "G28", "G29",
+ "G30", "G31"
+};
+
+static const char *SETxx[] =
+{
+ "SETADR", "Reserved", "SET1", "SET0", "SETLE", "SETGT", "SETLT", "SETGE",
+ "SETSE", "SETHT", "SETST", "SETHE", "SETE", "SETNE", "SETV", "SETNV",
+ "Reserved", "Reserved", "SET1M", "Reserved", "SETLEM", "SETGTM", "SETLTM", "SETGEM",
+ "SETSEM", "SETTHM", "SETSTM", "SETHEM", "SETEM", "SETNEM", "SETVM", "SETNVM"
+};
+
+#define DESTCODE(op) ((op & 0x00f0) >> 4)
+#define SOURCECODE(op) (op & 0x000f)
+
+#define SOURCEBIT(op) ((op & 0x100) >> 8)
+#define DESTBIT(op) ((op & 0x200) >> 9)
+
+#define N_VALUE(op) ((((op & 0x100) >> 8) << 4 ) | (op & 0x0f))
+
+static int size, global_fp;
+
+static offs_t base_pc;
+static const UINT8 *base_oprom;
+#define READ_OP_DASM(p) ((base_oprom[(p) - base_pc] << 8) | base_oprom[(p) + 1 - base_pc])
+
+
+static void LL_format(char *source, char *dest, UINT16 op)
+{
+ strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]);
+ strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]);
+}
+
+static void LR_format(char *source, char *dest, UINT16 op)
+{
+ if( SOURCEBIT(op) )
+ {
+ strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(source, G_REG[SOURCECODE(op)]);
+ }
+
+ strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]);
+}
+
+static void RR_format(char *source, char *dest, UINT16 op, unsigned h_flag)
+{
+ if( SOURCEBIT(op) )
+ {
+ strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(source, G_REG[SOURCECODE(op) + h_flag * 16]);
+ }
+
+ if( DESTBIT(op) )
+ {
+ strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(dest, G_REG[DESTCODE(op) + h_flag * 16]);
+ }
+}
+
+static UINT32 LRconst_format(char *source, char *dest, UINT16 op, unsigned *pc)
+{
+ UINT16 next_op;
+ UINT32 const_val;
+
+ if( SOURCEBIT(op) )
+ {
+ strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(source, G_REG[SOURCECODE(op)]);
+ }
+
+ strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]);
+
+ size = 4;
+
+ *pc += 2;
+ next_op = READ_OP_DASM(*pc);
+
+ if( E_BIT(next_op) )
+ {
+ UINT16 next_op2;
+
+ size = 6;
+
+ *pc += 2;
+ next_op2 = READ_OP_DASM(*pc);
+ const_val = next_op2;
+ const_val |= ((next_op & 0x3fff) << 16 );
+
+ if( S_BIT_CONST(next_op) )
+ {
+ const_val |= 0xc0000000;
+ }
+ }
+ else
+ {
+ const_val = next_op & 0x3fff;
+
+ if( S_BIT_CONST(next_op) )
+ {
+ const_val |= 0xffffc000;
+ }
+ }
+
+ return const_val;
+}
+
+static UINT32 RRconst_format(char *source, char *dest, UINT16 op, unsigned *pc)
+{
+ UINT16 next_op;
+ UINT32 const_val;
+
+ if( SOURCEBIT(op) )
+ {
+ strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(source, G_REG[SOURCECODE(op)]);
+ }
+
+ if( DESTBIT(op) )
+ {
+ strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(dest, G_REG[DESTCODE(op)]);
+ }
+
+ size = 4;
+
+ *pc += 2;
+ next_op = READ_OP_DASM(*pc);
+
+ if( E_BIT(next_op) )
+ {
+ UINT16 next_op2;
+
+ size = 6;
+
+ *pc += 2;
+ next_op2 = READ_OP_DASM(*pc);
+ const_val = next_op2;
+ const_val |= ((next_op & 0x3fff) << 16 );
+
+ if( S_BIT_CONST(next_op) )
+ {
+ const_val |= 0xc0000000;
+ }
+ }
+ else
+ {
+ const_val = next_op & 0x3fff;
+
+ if( S_BIT_CONST(next_op) )
+ {
+ const_val |= 0xffffc000;
+ }
+ }
+
+ return const_val;
+}
+
+static INT32 Rimm_format(char *dest, UINT16 op, unsigned *pc, unsigned h_flag)
+{
+ UINT16 imm1, imm2;
+ INT32 ret;
+
+ int n = N_VALUE(op);
+
+ if( DESTBIT(op) )
+ {
+ strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(dest, G_REG[DESTCODE(op) + h_flag * 16]);
+ }
+
+ switch( n )
+ {
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
+ case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16:
+ return n;
+
+ case 17:
+ *pc += 2;
+ imm1 = READ_OP_DASM(*pc);
+ *pc += 2;
+ imm2 = READ_OP_DASM(*pc);
+ ret = (imm1 << 16) | imm2;
+
+ size = 6;
+ return ret;
+
+
+ case 18:
+ *pc += 2;
+ ret = READ_OP_DASM(*pc);
+
+ size = 4;
+ return ret;
+
+ case 19:
+ *pc += 2;
+ ret = (INT32) (0xffff0000 | READ_OP_DASM(*pc));
+
+ size = 4;
+ return ret;
+
+ case 20:
+ return 32; //bit 5 = 1, others = 0
+
+ case 21:
+ return 64; //bit 6 = 1, others = 0
+
+ case 22:
+ return 128; //bit 7 = 1, others = 0
+
+ case 23:
+ return 0x80000000; //bit 31 = 1, others = 0 (2 at the power of 31)
+
+ case 24:
+ return -8;
+
+ case 25:
+ return -7;
+
+ case 26:
+ return -6;
+
+ case 27:
+ return -5;
+
+ case 28:
+ return -4;
+
+ case 29:
+ return -3;
+
+ case 30:
+ return -2;
+
+ case 31:
+ return -1;
+
+ default:
+ return 0; //should never goes here
+ }
+}
+
+static UINT8 Ln_format(char *dest, UINT16 op)
+{
+ strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]);
+
+ return N_VALUE(op);
+}
+
+static UINT8 Rn_format(char *dest, UINT16 op)
+{
+ if( DESTBIT(op) )
+ {
+ strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(dest, G_REG[DESTCODE(op)]);
+ }
+
+ return N_VALUE(op);
+}
+
+static INT32 PCrel_format(UINT16 op, unsigned pc)
+{
+ INT32 ret;
+
+ if( op & 0x80 ) //bit 7 = 1
+ {
+ UINT16 next;
+
+ size = 4;
+
+ pc += 2;
+
+ next = READ_OP_DASM(pc);
+
+ ret = (op & 0x7f) << 16;
+
+ ret |= (next & 0xfffe);
+
+ if( next & 1 )
+ ret |= 0xff800000; //ok?
+ }
+ else
+ {
+ ret = op & 0x7e;
+
+ if( op & 1 )
+ ret |= 0xffffff80; //ok?
+ }
+
+ return (pc + ret);
+}
+
+static UINT32 RRdis_format(char *source, char *dest, UINT16 op, UINT16 next_op, unsigned pc)
+{
+ UINT32 ret;
+
+ if( SOURCEBIT(op) )
+ {
+ strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(source, G_REG[SOURCECODE(op)]);
+ }
+
+ if( DESTBIT(op) )
+ {
+ strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]);
+ }
+ else
+ {
+ strcpy(dest, G_REG[DESTCODE(op)]);
+ }
+
+ if( E_BIT(next_op) )
+ {
+ UINT16 next;
+
+ size = 6;
+
+ next = READ_OP_DASM(pc + 4);
+
+ ret = next;
+ ret |= ( ( next_op & 0xfff ) << 16 );
+
+ if( S_BIT_CONST(next_op) )
+ {
+ ret |= 0xf0000000;
+ }
+ }
+ else
+ {
+ ret = next_op & 0xfff;
+ if( S_BIT_CONST(next_op) )
+ {
+ ret |= 0xfffff000;
+ }
+ }
+
+ return ret;
+}
+
+unsigned dasm_hyperstone(char *buffer, unsigned pc, const UINT8 *oprom, unsigned h_flag, int private_fp)
+{
+ UINT16 op = 0;
+ UINT8 op_num;
+
+ UINT8 source_code, dest_code, source_bit, dest_bit;
+
+ char source[5] = "\0", dest[5] = "\0";
+ UINT32 flags = 0;
+
+ base_pc = pc;
+ base_oprom = oprom;
+
+ op = READ_OP_DASM(pc);
+
+ size = 2;
+
+ source_code = SOURCECODE(op);
+ dest_code = DESTCODE(op);
+ source_bit = SOURCEBIT(op);
+ dest_bit = DESTBIT(op);
+
+ global_fp = private_fp;
+
+ op_num = (op & 0xff00) >> 8;
+
+ switch( op_num )
+ {
+ // CHK - CHKZ - NOP
+ case 0x00: case 0x01: case 0x02: case 0x03:
+
+ if( source_bit && dest_bit && source_code == 0 && dest_code == 0 )
+ {
+ sprintf(buffer, "NOP");
+ }
+ else
+ {
+ RR_format(source, dest, op, 0);
+
+ if( !source_bit && source_code == SR_REGISTER )
+ {
+ sprintf(buffer, "CHKZ %s, 0", dest);
+ }
+ else
+ {
+ sprintf(buffer, "CHK %s, %s", dest, source);
+ }
+ }
+
+ break;
+
+ // MOVD - RET
+ case 0x04: case 0x05: case 0x06: case 0x07:
+
+ RR_format(source, dest, op, 0);
+
+ if( dest_code == PC_REGISTER && !dest_bit )
+ {
+ global_fp = 0;
+ RR_format(source, dest, op, 0);
+ sprintf(buffer, "RET PC, %s", source);
+ flags = DASMFLAG_STEP_OUT;
+ }
+ else if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "MOVD %s, 0", dest);
+ }
+ else
+ {
+ sprintf(buffer, "MOVD %s, %s", dest, source);
+ }
+
+ break;
+
+ // DIVU
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+
+ RR_format(source, dest, op, 0);
+ sprintf(buffer, "DIVU %s, %s", dest, source);
+
+ break;
+
+ // DIVS
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+
+ RR_format(source, dest, op, 0);
+ sprintf(buffer, "DIVS %s, %s", dest, source);
+
+ break;
+
+ // XMx - XXx
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ {
+ int xcode;
+
+ RR_format(source, dest, op, 0);
+
+ size = 4;
+
+ pc += 2;
+ op = READ_OP_DASM(pc);
+
+ xcode = X_CODE(op);
+
+ if( xcode < 4 )
+ {
+ UINT16 lim;
+
+ if( E_BIT(op) )
+ {
+ UINT16 next_op;
+
+ size = 6;
+
+ pc += 2;
+ next_op = READ_OP_DASM(pc);
+
+ lim = ((op & 0xfff) << 16) | next_op;
+ }
+ else
+ {
+ lim = op & 0xfff;
+ }
+
+ sprintf(buffer, "XM%x %s, %s, $%x", (UINT8)(float) pow(2, xcode), dest, source, lim);
+
+ }
+ else
+ {
+ sprintf(buffer, "XX%x %s, %s, 0", (UINT8)(float) pow(2, (xcode - 4)), dest, source);
+ }
+
+ break;
+ }
+
+ // MASK
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ {
+ UINT32 const_val = RRconst_format(source, dest, op, &pc);
+
+ sprintf(buffer, "MASK %s, %s, $%x", dest, source, const_val);
+
+ break;
+ }
+
+ // SUM
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ {
+ UINT32 const_val = RRconst_format(source, dest, op, &pc);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "SUM %s, C, $%x", dest, const_val);
+ }
+ else
+ {
+ sprintf(buffer, "SUM %s, %s, $%x", dest, source, const_val);
+ }
+
+ break;
+ }
+
+ // SUMS
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ {
+ UINT32 const_val = RRconst_format(source, dest, op, &pc);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "SUMS %s, C, $%x", dest, const_val);
+ }
+ else
+ {
+ sprintf(buffer, "SUMS %s, %s, $%x", dest, source, const_val);
+ }
+
+ break;
+ }
+
+ // CMP
+ case 0x20: case 0x21: case 0x22: case 0x23:
+
+ RR_format(source, dest, op, 0);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "CMP %s, C", dest);
+ }
+ else
+ {
+ sprintf(buffer, "CMP %s, %s", dest, source);
+ }
+
+ break;
+
+ // MOV
+ case 0x24: case 0x25: case 0x26: case 0x27:
+
+ RR_format(source, dest, op, h_flag);
+ sprintf(buffer, "MOV %s, %s", dest, source);
+
+ break;
+
+ // ADD
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+
+ RR_format(source, dest, op, 0);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "ADD %s, C", dest);
+ }
+ else
+ {
+ sprintf(buffer, "ADD %s, %s", dest, source);
+ }
+
+ break;
+
+ // ADDS
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+
+ RR_format(source, dest, op, 0);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "ADDS %s, C", dest);
+ }
+ else
+ {
+ sprintf(buffer, "ADDS %s, %s", dest, source);
+ }
+
+ break;
+
+ // CMPB
+ case 0x30: case 0x31: case 0x32: case 0x33:
+
+ RR_format(source, dest, op, 0);
+ sprintf(buffer, "CMPB %s, %s", dest, source);
+
+ break;
+
+ // ANDN
+ case 0x34: case 0x35: case 0x36: case 0x37:
+
+ RR_format(source, dest, op, 0);
+ sprintf(buffer, "ANDN %s, %s", dest, source);
+
+ break;
+
+ // OR
+ case 0x38: case 0x39: case 0x3a: case 0x3b:
+
+ RR_format(source, dest, op, 0);
+ sprintf(buffer, "OR %s, %s", dest, source);
+
+ break;
+
+ // XOR
+ case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+
+ RR_format(source, dest, op, 0);
+ sprintf(buffer, "XOR %s, %s", dest, source);
+
+ break;
+
+ // SUBC
+ case 0x40: case 0x41: case 0x42: case 0x43:
+
+ RR_format(source, dest, op, 0);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "SUBC %s, C", dest);
+ }
+ else
+ {
+ sprintf(buffer, "SUBC %s, %s", dest, source);
+ }
+
+ break;
+
+ // NOT
+ case 0x44: case 0x45: case 0x46: case 0x47:
+
+ RR_format(source, dest, op, 0);
+
+ sprintf(buffer, "NOT %s, %s", dest, source);
+
+ break;
+
+ // SUB
+ case 0x48: case 0x49: case 0x4a: case 0x4b:
+
+ RR_format(source, dest, op, 0);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "SUB %s, C", dest);
+ }
+ else
+ {
+ sprintf(buffer, "SUB %s, %s", dest, source);
+ }
+
+ break;
+
+ // SUBS
+ case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+
+ RR_format(source, dest, op, 0);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "SUBS %s, C", dest);
+ }
+ else
+ {
+ sprintf(buffer, "SUBS %s, %s", dest, source);
+ }
+
+ break;
+
+ // ADDC
+ case 0x50: case 0x51: case 0x52: case 0x53:
+
+ RR_format(source, dest, op, 0);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "ADDC %s, C", dest);
+ }
+ else
+ {
+ sprintf(buffer, "ADDC %s, %s", dest, source);
+ }
+
+ break;
+
+ // AND
+ case 0x54: case 0x55: case 0x56: case 0x57:
+
+ RR_format(source, dest, op, 0);
+ sprintf(buffer, "AND %s, %s", dest, source);
+
+ break;
+
+ // NEG
+ case 0x58: case 0x59: case 0x5a: case 0x5b:
+
+ RR_format(source, dest, op, 0);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "NEG %s, C", dest);
+ }
+ else
+ {
+ sprintf(buffer, "NEG %s, %s", dest, source);
+ }
+
+ break;
+
+ // NEGS
+ case 0x5c: case 0x5d: case 0x5e: case 0x5f:
+
+ RR_format(source, dest, op, 0);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "NEGS %s, C", dest);
+ }
+ else
+ {
+ sprintf(buffer, "NEGS %s, %s", dest, source);
+ }
+
+ break;
+
+ // CMPI
+ case 0x60: case 0x61: case 0x62: case 0x63:
+ {
+ UINT32 imm = Rimm_format(dest, op, &pc, 0);
+
+ sprintf(buffer, "CMPI %s, $%x", dest, imm);
+
+ break;
+ }
+
+ // MOVI
+ case 0x64: case 0x65: case 0x66: case 0x67:
+ {
+ UINT32 imm = Rimm_format(dest, op, &pc, h_flag);
+
+ sprintf(buffer, "MOVI %s, $%x", dest, imm);
+
+ break;
+ }
+
+ // ADDI
+ case 0x68: case 0x69: case 0x6a: case 0x6b:
+ {
+ UINT32 imm = Rimm_format(dest, op, &pc, 0);
+
+ if( !N_VALUE(op) )
+ {
+ sprintf(buffer, "ADDI %s, CZ", dest);
+ }
+ else
+ {
+ sprintf(buffer, "ADDI %s, $%x", dest, imm);
+ }
+
+ break;
+ }
+
+ // ADDSI
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+ {
+ UINT32 imm = Rimm_format(dest, op, &pc, 0);
+
+ if( !N_VALUE(op) )
+ {
+ sprintf(buffer, "ADDSI %s, CZ", dest);
+ }
+ else
+ {
+ sprintf(buffer, "ADDSI %s, $%x", dest, imm);
+ }
+
+ break;
+ }
+
+ // CMPBI
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ {
+ UINT32 imm = Rimm_format(dest, op, &pc, 0);
+
+ if( !N_VALUE(op) )
+ {
+ sprintf(buffer, "CMPBI %s, ANYBZ", dest);
+ }
+ else
+ {
+ if( N_VALUE(op) == 31 )
+ imm = 0x7fffffff; //bit 31 = 0, others = 1
+
+ sprintf(buffer, "CMPBI %s, $%x", dest, imm);
+ }
+
+ break;
+ }
+
+ // ANDNI
+ case 0x74: case 0x75: case 0x76: case 0x77:
+ {
+ UINT32 imm = Rimm_format(dest, op, &pc, 0);
+
+ if( N_VALUE(op) == 31 )
+ imm = 0x7fffffff; //bit 31 = 0, others = 1
+
+ sprintf(buffer, "ANDNI %s, $%x", dest, imm);
+
+ break;
+ }
+
+ // ORI
+ case 0x78: case 0x79: case 0x7a: case 0x7b:
+ {
+ UINT32 imm = Rimm_format(dest, op, &pc, 0);
+
+ sprintf(buffer, "ORI %s, $%x", dest, imm);
+
+ break;
+ }
+
+ // XORI
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+ {
+ UINT32 imm = Rimm_format(dest, op, &pc, 0);
+
+ sprintf(buffer, "XORI %s, $%x", dest, imm);
+
+ break;
+ }
+
+ // SHRDI
+ case 0x80: case 0x81:
+ {
+ UINT8 n = Ln_format(dest, op);
+
+ sprintf(buffer, "SHRDI %s, $%x", dest, n);
+
+ break;
+ }
+
+ // SHRD
+ case 0x82:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "SHRD %s, %s", dest, source);
+
+ break;
+
+ // SHR
+ case 0x83:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "SHR %s, %s", dest, source);
+
+ break;
+
+ // SARDI
+ case 0x84: case 0x85:
+ {
+ UINT8 n = Ln_format(dest, op);
+
+ sprintf(buffer, "SARDI %s, $%x", dest, n);
+
+ break;
+ }
+
+ // SARD
+ case 0x86:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "SARD %s, %s", dest, source);
+
+ break;
+
+ // SAR
+ case 0x87:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "SAR %s, %s", dest, source);
+
+ break;
+
+ // SHLDI
+ case 0x88: case 0x89:
+ {
+ UINT8 n = Ln_format(dest, op);
+
+ sprintf(buffer, "SHLDI %s, $%x", dest, n);
+
+ break;
+ }
+
+ // SHLD
+ case 0x8a:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "SHLD %s, %s", dest, source);
+
+ break;
+
+ // SHL
+ case 0x8b:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "SHL %s, %s", dest, source);
+
+ break;
+
+ // RESERVED
+ case 0x8c: case 0x8d:
+ case 0xac: case 0xad: case 0xae: case 0xaf:
+
+ sprintf(buffer, "Reserved");
+
+ break;
+
+ // TESTLZ
+ case 0x8e:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "TESTLZ %s, %s", dest, source);
+
+ break;
+
+ // ROL
+ case 0x8f:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "ROL %s, %s", dest, source);
+
+ break;
+
+ // LDxx.D/A/IOD/IOA
+ case 0x90: case 0x91: case 0x92: case 0x93:
+ {
+ UINT16 next_op = READ_OP_DASM(pc + 2);
+ UINT32 dis = RRdis_format(source, dest, op, next_op, pc);
+
+ if( size == 2 )
+ size = 4;
+
+ if( dest_code == SR_REGISTER && !dest_bit )
+ {
+ switch( DD( next_op ) )
+ {
+ case 0:
+ // LDBS.A
+ sprintf(buffer, "LDBS.A 0, %s, $%x", source, dis);
+ break;
+
+ case 1:
+ // LDBU.A
+ sprintf(buffer, "LDBU.A 0, %s, $%x", source, dis);
+ break;
+
+ case 2:
+ // LDHS.A
+ if( dis & 1 )
+ {
+ sprintf(buffer, "LDHS.A 0, %s, $%x", source, dis & ~1);
+ }
+ // LDHU.A
+ else
+ {
+ sprintf(buffer, "LDHU.A 0, %s, $%x", source, dis & ~1);
+ }
+
+ break;
+
+ case 3:
+ // LDD.IOA
+ if( (dis & 3) == 3 )
+ {
+ sprintf(buffer, "LDD.IOA 0, %s, $%x", source, dis & ~3);
+ }
+ // LDW.IOA
+ else if( (dis & 3) == 2 )
+ {
+ sprintf(buffer, "LDW.IOA 0, %s, $%x", source, dis & ~3);
+ }
+ // LDD.A
+ else if( (dis & 3) == 1 )
+ {
+ sprintf(buffer, "LDD.A 0, %s, $%x", source, dis & ~1);
+ }
+ // LDW.A
+ else
+ {
+ sprintf(buffer, "LDW.A 0, %s, $%x", source, dis & ~1);
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ switch( DD( next_op ) )
+ {
+ case 0:
+ // LDBS.D
+ sprintf(buffer, "LDBS.D %s, %s, $%x", dest, source, dis);
+ break;
+
+ case 1:
+ // LDBU.D
+ sprintf(buffer, "LDBU.D %s, %s, $%x", dest, source, dis);
+ break;
+
+ case 2:
+ // LDHS.D
+ if( dis & 1 )
+ {
+ sprintf(buffer, "LDHS.D %s, %s, $%x", dest, source, dis & ~1);
+ }
+ // LDHU.D
+ else
+ {
+ sprintf(buffer, "LDHU.D %s, %s, $%x", dest, source, dis & ~1);
+ }
+ break;
+
+ case 3:
+ // LDD.IOD
+ if( (dis & 3) == 3 )
+ {
+ sprintf(buffer, "LDD.IOD %s, %s, $%x", dest, source, dis & ~3);
+ }
+ // LDW.IOD
+ else if( (dis & 3) == 2 )
+ {
+ sprintf(buffer, "LDW.IOD %s, %s, $%x", dest, source, dis & ~3);
+ }
+ // LDD.D
+ else if( (dis & 3) == 1 )
+ {
+ sprintf(buffer, "LDD.D %s, %s, $%x", dest, source, dis & ~1);
+ }
+ // LDW.D
+ else
+ {
+ sprintf(buffer, "LDW.D %s, %s, $%x", dest, source, dis & ~1);
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ // LDxx.N/S
+ case 0x94: case 0x95: case 0x96: case 0x97:
+ {
+ UINT16 next_op = READ_OP_DASM(pc + 2);
+ UINT32 dis = RRdis_format(source, dest, op, next_op, pc);
+
+ if( size == 2 )
+ size = 4;
+
+ if( (dest_code == PC_REGISTER && !dest_bit) || (dest_code == SR_REGISTER && !dest_bit) )
+ {
+ sprintf(buffer, "Reserved");
+ break;
+ }
+
+ switch( DD( next_op ) )
+ {
+ case 0:
+ // LDBS.N
+ sprintf(buffer, "LDBS.N %s, %s, $%x", dest, source, dis);
+ break;
+
+ case 1:
+ // LDBU.N
+ sprintf(buffer, "LDBU.N %s, %s, $%x", dest, source, dis);
+ break;
+
+ case 2:
+ // LDHS.N
+ if( dis & 1 )
+ {
+ sprintf(buffer, "LDHS.N %s, %s, $%x", dest, source, dis & ~1);
+ }
+ // LDHU.N
+ else
+ {
+ sprintf(buffer, "LDHU.N %s, %s, $%x", dest, source, dis & ~1);
+ }
+
+ break;
+
+ case 3:
+ // LDW.S
+ if( (dis & 3) == 3 )
+ {
+ sprintf(buffer, "LDW.S %s, %s, $%x", dest, source, dis & ~3);
+ }
+ // Reserved
+ else if( (dis & 3) == 2 )
+ {
+ sprintf(buffer, "Reserved");
+ }
+ // LDD.N
+ else if( (dis & 3) == 1 )
+ {
+ sprintf(buffer, "LDD.N %s, %s, $%x", dest, source, dis & ~1);
+ }
+ // LDW.N
+ else
+ {
+ sprintf(buffer, "LDW.N %s, %s, $%x", dest, source, dis & ~1);
+ }
+
+ break;
+ }
+
+ break;
+ }
+
+ // STxx.D/A/IOD/IOA
+ case 0x98: case 0x99: case 0x9a: case 0x9b:
+ {
+ UINT16 next_op = READ_OP_DASM(pc + 2);
+ UINT32 dis = RRdis_format(source, dest, op, next_op, pc);
+
+ if( size == 2 )
+ size = 4;
+
+ if( source_code == SR_REGISTER && !source_bit )
+ strcpy(source,"0");
+
+ if( dest_code == SR_REGISTER && !dest_bit )
+ {
+ switch( DD( next_op ) )
+ {
+ case 0:
+ // STBS.A
+ sprintf(buffer, "STBS.A 0, %s, $%x", source, dis);
+ break;
+
+ case 1:
+ // STBU.A
+ sprintf(buffer, "STBU.A 0, %s, $%x", source, dis);
+ break;
+
+ case 2:
+ // STHS.A
+ if( dis & 1 )
+ {
+ sprintf(buffer, "STHS.A 0, %s, $%x", source, dis & ~1);
+ }
+ // STHU.A
+ else
+ {
+ sprintf(buffer, "STHU.A 0, %s, $%x", source, dis & ~1);
+ }
+
+ break;
+
+ case 3:
+ // STD.IOA
+ if( (dis & 3) == 3 )
+ {
+ sprintf(buffer, "STD.IOA 0, %s, $%x", source, dis & ~3);
+ }
+ // STW.IOA
+ else if( (dis & 3) == 2 )
+ {
+ sprintf(buffer, "STW.IOA 0, %s, $%x", source, dis & ~3);
+ }
+ // STD.A
+ else if( (dis & 3) == 1 )
+ {
+ sprintf(buffer, "STD.A 0, %s, $%x", source, dis & ~1);
+ }
+ // STW.A
+ else
+ {
+ sprintf(buffer, "STW.A 0, %s, $%x", source, dis & ~1);
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ switch( DD( next_op ) )
+ {
+ case 0:
+ // STBS.D
+ sprintf(buffer, "STBS.D %s, %s, $%x", dest, source, dis);
+ break;
+
+ case 1:
+ // STBU.D
+ sprintf(buffer, "STBU.D %s, %s, $%x", dest, source, dis);
+ break;
+
+ case 2:
+ // STHS.D
+ if( dis & 1 )
+ {
+ sprintf(buffer, "STHS.D %s, %s, $%x", dest, source, dis & ~1);
+ }
+ // STHU.D
+ else
+ {
+ sprintf(buffer, "STHU.D %s, %s, $%x", dest, source, dis & ~1);
+ }
+ break;
+
+ case 3:
+ // STD.IOD
+ if( (dis & 3) == 3 )
+ {
+ sprintf(buffer, "STD.IOD %s, %s, $%x", dest, source, dis & ~3);
+ }
+ // STW.IOD
+ else if( (dis & 3) == 2 )
+ {
+ sprintf(buffer, "STW.IOD %s, %s, $%x", dest, source, dis & ~3);
+ }
+ // STD.D
+ else if( (dis & 3) == 1 )
+ {
+ sprintf(buffer, "STD.D %s, %s, $%x", dest, source, dis & ~1);
+ }
+ // STW.D
+ else
+ {
+ sprintf(buffer, "STW.D %s, %s, $%x", dest, source, dis & ~1);
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ // STxx.N/S
+ case 0x9c: case 0x9d: case 0x9e: case 0x9f:
+ {
+ UINT16 next_op = READ_OP_DASM(pc + 2);
+ UINT32 dis = RRdis_format(source, dest, op, next_op, pc);
+
+ if( size == 2 )
+ size = 4;
+
+ if( source_code == SR_REGISTER && !source_bit )
+ strcpy(source,"0");
+
+ if( (dest_code == PC_REGISTER && !dest_bit) || (dest_code == SR_REGISTER && !dest_bit) )
+ {
+ sprintf(buffer, "Reserved");
+ break;
+ }
+
+ switch( DD( next_op ) )
+ {
+ case 0:
+ // STBS.N
+ sprintf(buffer, "STBS.N %s, %s, $%x", dest, source, dis);
+ break;
+
+ case 1:
+ // STBU.N
+ sprintf(buffer, "STBU.N %s, %s, $%x", dest, source, dis);
+ break;
+
+ case 2:
+ // STHS.N
+ if( dis & 1 )
+ {
+ sprintf(buffer, "STHS.N %s, %s, $%x", dest, source, dis & ~1);
+ }
+ // STHU.N
+ else
+ {
+ sprintf(buffer, "STHU.N %s, %s, $%x", dest, source, dis & ~1);
+ }
+
+ break;
+
+ case 3:
+ // STW.S
+ if( (dis & 3) == 3 )
+ {
+ sprintf(buffer, "STW.S %s, %s, $%x", dest, source, dis & ~3);
+ }
+ // Reserved
+ else if( (dis & 3) == 2 )
+ {
+ sprintf(buffer, "Reserved");
+ }
+ // STD.N
+ else if( (dis & 3) == 1 )
+ {
+ sprintf(buffer, "STD.N %s, %s, $%x", dest, source, dis & ~1);
+ }
+ // STW.N
+ else
+ {
+ sprintf(buffer, "STW.N %s, %s, $%x", dest, source, dis & ~1);
+ }
+
+ break;
+ }
+
+ break;
+ }
+
+ // SHRI
+ case 0xa0: case 0xa1: case 0xa2: case 0xa3:
+ {
+ UINT8 n = Rn_format(dest, op);
+
+ sprintf(buffer, "SHRI %s, $%x", dest, n);
+
+ break;
+ }
+
+ // SARI
+ case 0xa4: case 0xa5: case 0xa6: case 0xa7:
+ {
+ UINT8 n = Rn_format(dest, op);
+
+ sprintf(buffer, "SARI %s, $%x", dest, n);
+
+ break;
+ }
+
+ // SHLI
+ case 0xa8: case 0xa9: case 0xaa: case 0xab:
+ {
+ UINT8 n = Rn_format(dest, op);
+
+ sprintf(buffer, "SHLI %s, $%x", dest, n);
+
+ break;
+ }
+
+ // MULU
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3:
+
+ RR_format(source, dest, op, 0);
+
+ sprintf(buffer, "MULU %s, %s", dest, source);
+
+ break;
+
+ // MULS
+ case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+
+ RR_format(source, dest, op, 0);
+
+ sprintf(buffer, "MULS %s, %s", dest, source);
+
+ break;
+
+ // SETxx - SETADR - FETCH
+ case 0xb8: case 0xb9: case 0xba: case 0xbb:
+ {
+ UINT8 n = Rn_format(dest, op);
+
+ if( dest_code == PC_REGISTER && !dest_bit )
+ {
+ sprintf(buffer, "Illegal PC: $%x OP: $%x", pc, op);
+ }
+ else if( dest_code == SR_REGISTER && !dest_bit )
+ {
+ sprintf(buffer, "FETCH $%x", (n / 2) + 1);
+ }
+ else
+ {
+ sprintf(buffer, "%s %s", SETxx[n], dest);
+ }
+
+ break;
+ }
+
+ // MUL
+ case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+
+ RR_format(source, dest, op, 0);
+
+ sprintf(buffer, "MUL %s, %s", dest, source);
+
+ break;
+
+ // FADD
+ case 0xc0:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FADD %s, %s", dest, source);
+
+ break;
+
+ // FADDD
+ case 0xc1:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FADDD %s, %s", dest, source);
+
+ break;
+
+ // FSUB
+ case 0xc2:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FSUB %s, %s", dest, source);
+
+ break;
+
+ // FSUBD
+ case 0xc3:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FSUBD %s, %s", dest, source);
+
+ break;
+
+ // FMUL
+ case 0xc4:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FMUL %s, %s", dest, source);
+
+ break;
+
+ // FMULD
+ case 0xc5:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FMULD %s, %s", dest, source);
+
+ break;
+
+ // FDIV
+ case 0xc6:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FDIV %s, %s", dest, source);
+
+ break;
+
+ // FDIVD
+ case 0xc7:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FDIVD %s, %s", dest, source);
+
+ break;
+
+ // FCMP
+ case 0xc8:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FCMP %s, %s", dest, source);
+
+ break;
+
+ // FCMPD
+ case 0xc9:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FCMPD %s, %s", dest, source);
+
+ break;
+
+ // FCMPU
+ case 0xca:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FCMPU %s, %s", dest, source);
+
+ break;
+
+ // FCMPUD
+ case 0xcb:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FCMPUD %s, %s", dest, source);
+
+ break;
+
+ // FCVT
+ case 0xcc:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FCVT %s, %s", dest, source);
+
+ break;
+
+ // FCVTD
+ case 0xcd:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FCVTD %s, %s", dest, source);
+
+ break;
+
+ // EXTEND
+ case 0xce:
+ {
+ UINT16 extended_op;
+
+ LL_format(source, dest, op);
+
+ pc += 2;
+ extended_op = READ_OP_DASM(pc);
+
+ size = 4;
+
+ switch( extended_op )
+ {
+ case 0x100:
+ case EMUL:
+ sprintf(buffer, "EMUL %s, %s", dest, source);
+ break;
+
+ case EMULU:
+ sprintf(buffer, "EMULU %s, %s", dest, source);
+ break;
+
+ case EMULS:
+ sprintf(buffer, "EMULS %s, %s", dest, source);
+ break;
+
+ case EMAC:
+ sprintf(buffer, "EMAC %s, %s", dest, source);
+ break;
+
+ case EMACD:
+ sprintf(buffer, "EMACD %s, %s", dest, source);
+ break;
+
+ case EMSUB:
+ sprintf(buffer, "EMSUB %s, %s", dest, source);
+ break;
+
+ case EMSUBD:
+ sprintf(buffer, "EMSUBD %s, %s", dest, source);
+ break;
+
+ case EHMAC:
+ sprintf(buffer, "EHMAC %s, %s", dest, source);
+ break;
+
+ case EHMACD:
+ sprintf(buffer, "EHMACD %s, %s", dest, source);
+ break;
+
+ case EHCMULD:
+ sprintf(buffer, "EHCMULD %s, %s", dest, source);
+ break;
+
+ case EHCMACD:
+ sprintf(buffer, "EHCMACD %s, %s", dest, source);
+ break;
+
+ case EHCSUMD:
+ sprintf(buffer, "EHCSUMD %s, %s", dest, source);
+ break;
+
+ case EHCFFTD:
+ sprintf(buffer, "EHCFFTD %s, %s", dest, source);
+ break;
+
+ case EHCFFTSD:
+ sprintf(buffer, "EHCFFTSD %s, %s", dest, source);
+ break;
+
+ default:
+ sprintf(buffer, "Ext. OP $%x", extended_op);
+ logerror(buffer, "Illegal Extended Opcode: %x\n", extended_op);
+ break;
+ }
+
+ break;
+ }
+
+ // DO
+ case 0xcf:
+
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "DO %s, %s", dest, source);
+
+ break;
+
+ // LDW.R
+ case 0xd0: case 0xd1:
+
+ LR_format(source, dest, op);
+
+ sprintf(buffer, "LDW.R %s, %s", dest, source);
+
+ break;
+
+ // LDD.R
+ case 0xd2: case 0xd3:
+
+ LR_format(source, dest, op);
+
+ sprintf(buffer, "LDD.R %s, %s", dest, source);
+
+ break;
+
+ // LDW.P
+ case 0xd4: case 0xd5:
+
+ LR_format(source, dest, op);
+
+ sprintf(buffer, "LDW.P %s, %s", dest, source);
+
+ break;
+
+ // LDD.P
+ case 0xd6: case 0xd7:
+
+ LR_format(source, dest, op);
+
+ sprintf(buffer, "LDD.P %s, %s", dest, source);
+
+ break;
+
+ // STW.R
+ case 0xd8: case 0xd9:
+
+ LR_format(source, dest, op);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ strcpy(source,"0");
+
+ sprintf(buffer, "STW.R %s, %s", dest, source);
+
+ break;
+
+ // STD.R
+ case 0xda: case 0xdb:
+
+ LR_format(source, dest, op);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ strcpy(source,"0");
+
+ sprintf(buffer, "STD.R %s, %s", dest, source);
+
+ break;
+
+ // STW.P
+ case 0xdc: case 0xdd:
+
+ LR_format(source, dest, op);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ strcpy(source,"0");
+
+ sprintf(buffer, "STW.P %s, %s", dest, source);
+
+ break;
+
+ // STD.P
+ case 0xde: case 0xdf:
+
+ LR_format(source, dest, op);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ strcpy(source,"0");
+
+ sprintf(buffer, "STD.P %s, %s", dest, source);
+
+ break;
+
+ // DBV
+ case 0xe0:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBV $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBNV
+ case 0xe1:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBNV $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBE
+ case 0xe2:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBE $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBNE
+ case 0xe3:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBNE $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBC
+ case 0xe4:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBC $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBNC
+ case 0xe5:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBNC $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBSE
+ case 0xe6:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBSE $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBHT
+ case 0xe7:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBHT $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBN
+ case 0xe8:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBN $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBNN
+ case 0xe9:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBNN $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBLE
+ case 0xea:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBLE $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBGT
+ case 0xeb:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBGT $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // DBR
+ case 0xec:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "DBR $%x", rel);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+
+ break;
+ }
+
+ // FRAME
+ case 0xed:
+
+ global_fp = 0;
+ LL_format(source, dest, op);
+
+ sprintf(buffer, "FRAME %s, %s", dest, source);
+
+ break;
+
+ // CALL
+ case 0xee: case 0xef:
+ {
+ UINT32 const_val = LRconst_format(source, dest, op, &pc);
+
+ if( source_code == SR_REGISTER && !source_bit )
+ {
+ sprintf(buffer, "CALL %s, 0, $%x", dest, const_val);
+ flags = DASMFLAG_STEP_OVER;
+ }
+ else
+ {
+ sprintf(buffer, "CALL %s, %s, $%x", dest, source, const_val);
+ flags = DASMFLAG_STEP_OVER;
+ }
+
+ break;
+ }
+
+ // BV
+ case 0xf0:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BV $%x", rel);
+
+ break;
+ }
+
+ // BNV
+ case 0xf1:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BNV $%x", rel);
+
+ break;
+ }
+
+ // BE
+ case 0xf2:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BE $%x", rel);
+
+ break;
+ }
+
+ // BNE
+ case 0xf3:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BNE $%x", rel);
+
+ break;
+ }
+
+ // BC
+ case 0xf4:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BC $%x", rel);
+
+ break;
+ }
+
+ // BNC
+ case 0xf5:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BNC $%x", rel);
+
+ break;
+ }
+
+ // BSE
+ case 0xf6:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BSE $%x", rel);
+
+ break;
+ }
+
+ // BHT
+ case 0xf7:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BHT $%x", rel);
+
+ break;
+ }
+
+ // BN
+ case 0xf8:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BN $%x", rel);
+
+ break;
+ }
+
+ // BNN
+ case 0xf9:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BNN $%x", rel);
+
+ break;
+ }
+
+ // BLE
+ case 0xfa:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BLE $%x", rel);
+
+ break;
+ }
+
+ // BGT
+ case 0xfb:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BGT $%x", rel);
+
+ break;
+ }
+
+ // BR
+ case 0xfc:
+ {
+ INT32 rel = PCrel_format(op, pc) + 2;
+
+ sprintf(buffer, "BR $%x", rel);
+
+ break;
+ }
+
+ // TRAPxx - TRAP
+ case 0xfd: case 0xfe: case 0xff:
+ {
+ UINT8 code = ((op & 0x300) >> 6) | (op & 0x03);
+ UINT8 trapno = (op & 0xfc) >> 2;
+
+ switch( code )
+ {
+ case TRAPLE:
+ sprintf(buffer, "TRAPLE %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPGT:
+ sprintf(buffer, "TRAPGT %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPLT:
+ sprintf(buffer, "TRAPLT %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPGE:
+ sprintf(buffer, "TRAPGE %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPSE:
+ sprintf(buffer, "TRAPSE %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPHT:
+ sprintf(buffer, "TRAPHT %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPST:
+ sprintf(buffer, "TRAPST %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPHE:
+ sprintf(buffer, "TRAPHE %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPE:
+ sprintf(buffer, "TRAPE %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPNE:
+ sprintf(buffer, "TRAPNE %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAPV:
+ sprintf(buffer, "TRAPV %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+
+ case TRAP:
+ sprintf(buffer, "TRAP %d", trapno);
+ flags = DASMFLAG_STEP_OVER;
+
+ break;
+ }
+
+ break;
+ }
+ }
+
+ return size | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/e132xs/e132xs.c b/src/emu/cpu/e132xs/e132xs.c
new file mode 100644
index 00000000000..022ebd372eb
--- /dev/null
+++ b/src/emu/cpu/e132xs/e132xs.c
@@ -0,0 +1,5606 @@
+/********************************************************************
+ Hyperstone cpu emulator
+ written by Pierpaolo Prazzoli
+
+ All the types are compatible, but they have different IRAM size and cycles
+
+ Hyperstone models:
+
+ 16 bits
+ - E1-16T
+ - E1-16XT
+ - E1-16XS
+ - E1-16XSR
+
+ 32bits
+ - E1-32N or E1-32T
+ - E1-32XN or E1-32XT
+ - E1-32XS
+ - E1-32XSR
+
+ Hynix models:
+
+ 16 bits
+ - GMS30C2116
+ - GMS30C2216
+
+ 32bits
+ - GMS30C2132
+ - GMS30C2232
+
+ TODO:
+ - some wrong cycle counts
+
+ CHANGELOG:
+
+ Pierpaolo Prazzoli
+ - Fixed LDxx.N/P/S opcodes not to increment the destination register when
+ it's the same as the source or "next source" one.
+
+ Pierpaolo Prazzoli
+ - Removed nested delays
+ - Added better delay branch support
+ - Fixed PC seen by a delay instruction, because a delay instruction
+ should use the delayed PC (thus allowing the execution of software
+ opcodes too)
+
+ Tomasz Slanina
+ - Fixed delayed branching for delay instructions longer than 2 bytes
+
+ Pierpaolo Prazzoli
+ - Added and fixed Timer without hack
+
+ Tomasz Slanina
+ - Fixed MULU/MULS
+ - Fixed Carry in ADDC/SUBC
+
+ Pierpaolo Prazzoli
+ - Fixed software opcodes used as delay instructions
+ - Added nested delays
+
+ Tomasz Slanina
+ - Added "undefined" C flag to shift left instructions
+
+ Pierpaolo Prazzoli
+ - Added interrupts-block for delay instructions
+ - Fixed get_emu_code_addr
+ - Added LDW.S and STW.S instructions
+ - Fixed floating point opcodes
+
+ Tomasz Slanina
+ - interrputs after call and before frame are prohibited now
+ - emulation of FCR register
+ - Floating point opcodes (preliminary)
+ - Fixed stack addressing in RET/FRAME opcodes
+ - Fixed bug in SET_RS macro
+ - Fixed bug in return opcode (S flag)
+ - Added C/N flags calculation in add/adc/addi/adds/addsi and some shift opcodes
+ - Added writeback to ROL
+ - Fixed ROL/SAR/SARD/SHR/SHRD/SHL/SHLD opcode decoding (Local/Global regs)
+ - Fixed I and T flag in RET opcode
+ - Fixed XX/XM opcodes
+ - Fixed MOV opcode, when RD = PC
+ - Fixed execute_trap()
+ - Fixed ST opcodes, when when RS = SR
+ - Added interrupts
+ - Fixed I/O addressing
+
+ Pierpaolo Prazzoli
+ - Fixed fetch
+ - Fixed decode of hyperstone_xm opcode
+ - Fixed 7 bits difference number in FRAME / RET instructions
+ - Some debbugger fixes
+ - Added generic registers decode function
+ - Some other little fixes.
+
+ MooglyGuy 29/03/2004
+ - Changed MOVI to use unsigned values instead of signed, correcting
+ an ugly glitch when loading 32-bit immediates.
+ Pierpaolo Prazzoli
+ - Same fix in get_const
+
+ MooglyGuy - 02/27/04
+ - Fixed delayed branching
+ - const_val for CALL should always have bit 0 clear
+
+ Pierpaolo Prazzoli - 02/25/04
+ - Fixed some wrong addresses to address local registers instead of memory
+ - Fixed FRAME and RET instruction
+ - Added preliminary I/O space
+ - Fixed some load / store instructions
+
+ Pierpaolo Prazzoli - 02/20/04
+ - Added execute_exception function
+ - Added FL == 0 always interpreted as 16
+
+ Pierpaolo Prazzoli - 02/19/04
+ - Changed the reset to use the execute_trap(reset) which should be right to set
+ the initiale state of the cpu
+ - Added Trace exception
+ - Set of T flag in RET instruction
+ - Set I flag in interrupts entries and resetted by a RET instruction
+ - Added correct set instruction for SR
+
+ Pierpaolo Prazzoli - 10/26/03
+ - Changed get_lrconst to get_const and changed it to use the removed GET_CONST_RR
+ macro.
+ - Removed the High flag used in some opcodes, it should be used only in
+ MOV and MOVI instruction.
+ - Fixed MOV and MOVI instruction.
+ - Set to 1 FP is SR register at reset.
+ (From the doc: A Call, Trap or Software instruction increments the FP and sets FL
+ to 6, thus creating a new stack frame with the length of 6 registers).
+
+ MooglyGuy - 10/25/03
+ - Fixed CALL enough that it at least jumps to the right address, no word
+ yet as to whether or not it's working enough to return.
+ - Added get_lrconst() to get the const value for the CALL operand, since
+ apparently using immediate_value() was wrong. The code is ugly, but it
+ works properly. Vampire 1/2 now gets far enough to try to test its RAM.
+ - Just from looking at it, CALL apparently doesn't frame properly. I'm not
+ sure about FRAME, but perhaps it doesn't work properly - I'm not entirely
+ positive. The return address when vamphalf's memory check routine is
+ called at FFFFFD7E is stored in register L8, and then the RET instruction
+ at the end of the routine uses L1 as the return address, so that might
+ provide some clues as to how it works.
+ - I'd almost be willing to bet money that there's no framing at all since
+ the values in L0 - L15 as displayed by the debugger would change during a
+ CALL or FRAME operation. I'll look when I'm in the mood.
+ - The mood struck me, and I took a look at SET_L_REG and GET_L_REG.
+ Apparently no matter what the current frame pointer is they'll always use
+ local_regs[0] through local_regs[15].
+
+ MooglyGuy - 08/20/03
+ - Added H flag support for MOV and MOVI
+ - Changed init routine to set S flag on boot. Apparently the CPU defaults to
+ supervisor mode as opposed to user mode when it powers on, as shown by the
+ vamphalf power-on routines. Makes sense, too, since if the machine booted
+ in user mode, it would be impossible to get into supervisor mode.
+
+ Pierpaolo Prazzoli - 08/19/03
+ - Added check for D_BIT and S_BIT where PC or SR must or must not be denoted.
+ (movd, divu, divs, ldxx1, ldxx2, stxx1, stxx2, mulu, muls, set, mul
+ call, chk)
+
+ MooglyGuy - 08/17/03
+ - Working on support for H flag, nothing quite done yet
+ - Added trap Range Error for CHK PC, PC
+ - Fixed relative jumps, they have to be taken from the opcode following the
+ jump minstead of the jump opcode itself.
+
+ Pierpaolo Prazzoli - 08/17/03
+ - Fixed get_pcrel() when OP & 0x80 is set.
+ - Decremented PC by 2 also in MOV, ADD, ADDI, SUM, SUB and added the check if
+ D_BIT is not set. (when pc is changed they are implicit branch)
+
+ MooglyGuy - 08/17/03
+ - Implemented a crude hack to set FL in the SR to 6, since according to the docs
+ that's supposed to happen each time a trap occurs, apparently including when
+ the processor starts up. The 3rd opcode executed in vamphalf checks to see if
+ the FL flag in SR 6, so it's apparently the "correct" behaviour despite the
+ docs not saying anything on it. If FL is not 6, the branch falls through and
+ encounters a CHK PC, L2, which at that point will always throw a range trap.
+ The range trap vector contains 00000000 (CHK PC, PC), which according to the
+ docs will always throw a range trap (which would effectively lock the system).
+ This revealed a bug: CHK PC, PC apparently does not throw a range trap, which
+ needs to be fixed. Now that the "correct" behaviour is hacked in with the FL
+ flags, it reveals yet another bug in that the branch is interpreted as being
+ +0x8700. This means that the PC then wraps around to 000082B0, give or take
+ a few bytes. While it does indeed branch to valid code, I highly doubt that
+ this is the desired effect. Check for signed/unsigned relative branch, maybe?
+
+ MooglyGuy - 08/16/03
+ - Fixed the debugger at least somewhat so that it displays hex instead of decimal,
+ and so that it disassembles opcodes properly.
+ - Fixed hyperstone_execute() to increment PC *after* executing the opcode instead of
+ before. This is probably why vamphalf was booting to fffffff8, but executing at
+ fffffffa instead.
+ - Changed execute_trap to decrement PC by 2 so that the next opcode isn't skipped
+ after a trap
+ - Changed execute_br to decrement PC by 2 so that the next opcode isn't skipped
+ after a branch
+ - Changed hyperstone_movi to decrement PC by 2 when G0 (PC) is modified so that the
+ next opcode isn't skipped after a branch
+ - Changed hyperstone_movi to default to a UINT32 being moved into the register
+ as opposed to a UINT8. This is wrong, the bit width is quite likely to be
+ dependent on the n field in the Rimm instruction type. However, vamphalf uses
+ MOVI G0,[FFFF]FBAC (n=$13) since there's apparently no absolute branch opcode.
+ What kind of CPU is this that it doesn't have an absolute jump in its branch
+ instructions and you have to use an immediate MOV to do an abs. jump!?
+ - Replaced usage of logerror() with smf's verboselog()
+
+*********************************************************************/
+
+#include "debugger.h"
+#include "e132xs.h"
+#include "osd_cpu.h"
+
+static UINT8 (*hyp_cpu_read_byte)(offs_t address);
+static UINT16 (*hyp_cpu_read_half_word)(offs_t address);
+static UINT32 (*hyp_cpu_read_word)(offs_t address);
+static UINT32 (*hyp_cpu_read_io_word)(offs_t address);
+static void (*hyp_cpu_write_byte)(offs_t address, UINT8 data);
+static void (*hyp_cpu_write_half_word)(offs_t address, UINT16 data);
+static void (*hyp_cpu_write_word)(offs_t address, UINT32 data);
+static void (*hyp_cpu_write_io_word)(offs_t address, UINT32 data);
+int hyp_type_16bit;
+
+// set C in adds/addsi/subs/sums
+#define SETCARRYS 0
+#define MISSIONCRAFT_FLAGS 1
+
+static int hyperstone_ICount;
+
+static void hyperstone_chk(void);
+static void hyperstone_movd(void);
+static void hyperstone_divu(void);
+static void hyperstone_divs(void);
+static void hyperstone_xm(void);
+static void hyperstone_mask(void);
+static void hyperstone_sum(void);
+static void hyperstone_sums(void);
+static void hyperstone_cmp(void);
+static void hyperstone_mov(void);
+static void hyperstone_add(void);
+static void hyperstone_adds(void);
+static void hyperstone_cmpb(void);
+static void hyperstone_andn(void);
+static void hyperstone_or(void);
+static void hyperstone_xor(void);
+static void hyperstone_subc(void);
+static void hyperstone_not(void);
+static void hyperstone_sub(void);
+static void hyperstone_subs(void);
+static void hyperstone_addc(void);
+static void hyperstone_and(void);
+static void hyperstone_neg(void);
+static void hyperstone_negs(void);
+static void hyperstone_cmpi(void);
+static void hyperstone_movi(void);
+static void hyperstone_addi(void);
+static void hyperstone_addsi(void);
+static void hyperstone_cmpbi(void);
+static void hyperstone_andni(void);
+static void hyperstone_ori(void);
+static void hyperstone_xori(void);
+static void hyperstone_shrdi(void);
+static void hyperstone_shrd(void);
+static void hyperstone_shr(void);
+static void hyperstone_sardi(void);
+static void hyperstone_sard(void);
+static void hyperstone_sar(void);
+static void hyperstone_shldi(void);
+static void hyperstone_shld(void);
+static void hyperstone_shl(void);
+static void reserved(void);
+static void hyperstone_testlz(void);
+static void hyperstone_rol(void);
+static void hyperstone_ldxx1(void);
+static void hyperstone_ldxx2(void);
+static void hyperstone_stxx1(void);
+static void hyperstone_stxx2(void);
+static void hyperstone_shri(void);
+static void hyperstone_sari(void);
+static void hyperstone_shli(void);
+static void hyperstone_mulu(void);
+static void hyperstone_muls(void);
+static void hyperstone_set(void);
+static void hyperstone_mul(void);
+static void hyperstone_fadd(void);
+static void hyperstone_faddd(void);
+static void hyperstone_fsub(void);
+static void hyperstone_fsubd(void);
+static void hyperstone_fmul(void);
+static void hyperstone_fmuld(void);
+static void hyperstone_fdiv(void);
+static void hyperstone_fdivd(void);
+static void hyperstone_fcmp(void);
+static void hyperstone_fcmpd(void);
+static void hyperstone_fcmpu(void);
+static void hyperstone_fcmpud(void);
+static void hyperstone_fcvt(void);
+static void hyperstone_fcvtd(void);
+static void hyperstone_extend(void);
+static void hyperstone_do(void);
+static void hyperstone_ldwr(void);
+static void hyperstone_lddr(void);
+static void hyperstone_ldwp(void);
+static void hyperstone_lddp(void);
+static void hyperstone_stwr(void);
+static void hyperstone_stdr(void);
+static void hyperstone_stwp(void);
+static void hyperstone_stdp(void);
+static void hyperstone_dbv(void);
+static void hyperstone_dbnv(void);
+static void hyperstone_dbe(void);
+static void hyperstone_dbne(void);
+static void hyperstone_dbc(void);
+static void hyperstone_dbnc(void);
+static void hyperstone_dbse(void);
+static void hyperstone_dbht(void);
+static void hyperstone_dbn(void);
+static void hyperstone_dbnn(void);
+static void hyperstone_dble(void);
+static void hyperstone_dbgt(void);
+static void hyperstone_dbr(void);
+static void hyperstone_frame(void);
+static void hyperstone_call(void);
+static void hyperstone_bv(void);
+static void hyperstone_bnv(void);
+static void hyperstone_be(void);
+static void hyperstone_bne(void);
+static void hyperstone_bc(void);
+static void hyperstone_bnc(void);
+static void hyperstone_bse(void);
+static void hyperstone_bht(void);
+static void hyperstone_bn(void);
+static void hyperstone_bnn(void);
+static void hyperstone_ble(void);
+static void hyperstone_bgt(void);
+static void hyperstone_br(void);
+static void hyperstone_trap(void);
+
+/* Registers */
+
+enum
+{
+ E132XS_PC = 1,
+ E132XS_SR,
+ E132XS_FER,
+ E132XS_G3,
+ E132XS_G4,
+ E132XS_G5,
+ E132XS_G6,
+ E132XS_G7,
+ E132XS_G8,
+ E132XS_G9,
+ E132XS_G10,
+ E132XS_G11,
+ E132XS_G12,
+ E132XS_G13,
+ E132XS_G14,
+ E132XS_G15,
+ E132XS_G16,
+ E132XS_G17,
+ E132XS_SP,
+ E132XS_UB,
+ E132XS_BCR,
+ E132XS_TPR,
+ E132XS_TCR,
+ E132XS_TR,
+ E132XS_WCR,
+ E132XS_ISR,
+ E132XS_FCR,
+ E132XS_MCR,
+ E132XS_G28,
+ E132XS_G29,
+ E132XS_G30,
+ E132XS_G31,
+ E132XS_CL0, E132XS_CL1, E132XS_CL2, E132XS_CL3,
+ E132XS_CL4, E132XS_CL5, E132XS_CL6, E132XS_CL7,
+ E132XS_CL8, E132XS_CL9, E132XS_CL10,E132XS_CL11,
+ E132XS_CL12,E132XS_CL13,E132XS_CL14,E132XS_CL15,
+ E132XS_L0, E132XS_L1, E132XS_L2, E132XS_L3,
+ E132XS_L4, E132XS_L5, E132XS_L6, E132XS_L7,
+ E132XS_L8, E132XS_L9, E132XS_L10, E132XS_L11,
+ E132XS_L12, E132XS_L13, E132XS_L14, E132XS_L15,
+ E132XS_L16, E132XS_L17, E132XS_L18, E132XS_L19,
+ E132XS_L20, E132XS_L21, E132XS_L22, E132XS_L23,
+ E132XS_L24, E132XS_L25, E132XS_L26, E132XS_L27,
+ E132XS_L28, E132XS_L29, E132XS_L30, E132XS_L31,
+ E132XS_L32, E132XS_L33, E132XS_L34, E132XS_L35,
+ E132XS_L36, E132XS_L37, E132XS_L38, E132XS_L39,
+ E132XS_L40, E132XS_L41, E132XS_L42, E132XS_L43,
+ E132XS_L44, E132XS_L45, E132XS_L46, E132XS_L47,
+ E132XS_L48, E132XS_L49, E132XS_L50, E132XS_L51,
+ E132XS_L52, E132XS_L53, E132XS_L54, E132XS_L55,
+ E132XS_L56, E132XS_L57, E132XS_L58, E132XS_L59,
+ E132XS_L60, E132XS_L61, E132XS_L62, E132XS_L63
+};
+
+
+/* Delay information */
+struct _delay
+{
+ INT32 delay_cmd;
+ UINT32 delay_pc;
+};
+
+/* Internal registers */
+typedef struct
+{
+ UINT32 global_regs[32];
+ UINT32 local_regs[64];
+
+ /* internal stuff */
+ UINT32 ppc; // previous pc
+ UINT16 op; // opcode
+ UINT32 trap_entry; // entry point to get trap address
+
+ UINT8 n;
+ INT32 delay_timer;
+ int timer_clocks;
+
+ struct _delay delay;
+
+ int (*irq_callback)(int irqline);
+
+ INT32 h_clear;
+ INT32 instruction_length;
+ INT32 intblock;
+
+} hyperstone_regs;
+
+static hyperstone_regs hyperstone;
+
+static struct regs_decode
+{
+ UINT8 src, dst; // destination and source register code
+ UINT32 src_value; // current source register value
+ UINT32 next_src_value; // current next source register value
+ UINT32 dst_value; // current destination register value
+ UINT32 next_dst_value; // current next destination register value
+ UINT8 sub_type; // sub type opcode (for DD and X_CODE bits)
+ union
+ {
+ UINT32 u;
+ INT32 s;
+ } extra; // extra value such as immediate value, const, pcrel, ...
+ void (*set_src_register)(UINT8 reg, UINT32 data); // set local / global source register
+ void (*set_dst_register)(UINT8 reg, UINT32 data); // set local / global destination register
+ UINT8 src_is_pc;
+ UINT8 dst_is_pc;
+ UINT8 src_is_sr;
+ UINT8 dst_is_sr;
+ UINT8 same_src_dst;
+ UINT8 same_src_dstf;
+ UINT8 same_srcf_dst;
+} current_regs;
+
+#define SREG current_regs.src_value
+#define SREGF current_regs.next_src_value
+#define DREG current_regs.dst_value
+#define DREGF current_regs.next_dst_value
+#define EXTRA_U current_regs.extra.u
+#define EXTRA_S current_regs.extra.s
+
+#define SET_SREG( _data_ ) (*current_regs.set_src_register)(current_regs.src, _data_)
+#define SET_SREGF( _data_ ) (*current_regs.set_src_register)(current_regs.src + 1, _data_)
+#define SET_DREG( _data_ ) (*current_regs.set_dst_register)(current_regs.dst, _data_)
+#define SET_DREGF( _data_ ) (*current_regs.set_dst_register)(current_regs.dst + 1, _data_)
+
+#define SRC_IS_PC current_regs.src_is_pc
+#define DST_IS_PC current_regs.dst_is_pc
+#define SRC_IS_SR current_regs.src_is_sr
+#define DST_IS_SR current_regs.dst_is_sr
+#define SAME_SRC_DST current_regs.same_src_dst
+#define SAME_SRC_DSTF current_regs.same_src_dstf
+#define SAME_SRCF_DST current_regs.same_srcf_dst
+
+#if (HAS_E116T || HAS_E116XT || HAS_E116XS || HAS_E116XSR || HAS_GMS30C2116 || HAS_GMS30C2216)
+static UINT32 program_read_dword_16be(offs_t address)
+{
+ return (program_read_word_16be(address & ~1) << 16) | program_read_word_16be((address & ~1) + 2);
+}
+
+static void program_write_dword_16be(offs_t address, UINT32 data)
+{
+ program_write_word_16be(address & ~1, (data & 0xffff0000)>>16);
+ program_write_word_16be((address & ~1)+2, data & 0xffff);
+}
+
+static UINT32 io_read_dword_16be(offs_t address)
+{
+ return (io_read_word_16be(address & ~1)<< 16) | io_read_word_16be((address & ~1) + 2);
+}
+
+static void io_write_dword_16be(offs_t address, UINT32 data)
+{
+ io_write_word_16be(address & ~1, (data & 0xffff0000)>>16);
+ io_write_word_16be((address & ~1)+2, data & 0xffff);
+}
+#endif
+
+
+/* Opcodes table */
+static void (*hyperstone_op[0x100])(void) = {
+ hyperstone_chk, hyperstone_chk, hyperstone_chk, hyperstone_chk, /* CHK - CHKZ - NOP */
+ hyperstone_movd, hyperstone_movd, hyperstone_movd, hyperstone_movd, /* MOVD - RET */
+ hyperstone_divu, hyperstone_divu, hyperstone_divu, hyperstone_divu, /* DIVU */
+ hyperstone_divs, hyperstone_divs, hyperstone_divs, hyperstone_divs, /* DIVS */
+ hyperstone_xm, hyperstone_xm, hyperstone_xm, hyperstone_xm, /* XMx - XXx */
+ hyperstone_mask, hyperstone_mask, hyperstone_mask, hyperstone_mask, /* MASK */
+ hyperstone_sum, hyperstone_sum, hyperstone_sum, hyperstone_sum, /* SUM */
+ hyperstone_sums, hyperstone_sums, hyperstone_sums, hyperstone_sums, /* SUMS */
+ hyperstone_cmp, hyperstone_cmp, hyperstone_cmp, hyperstone_cmp, /* CMP */
+ hyperstone_mov, hyperstone_mov, hyperstone_mov, hyperstone_mov, /* MOV */
+ hyperstone_add, hyperstone_add, hyperstone_add, hyperstone_add, /* ADD */
+ hyperstone_adds, hyperstone_adds, hyperstone_adds, hyperstone_adds, /* ADDS */
+ hyperstone_cmpb, hyperstone_cmpb, hyperstone_cmpb, hyperstone_cmpb, /* CMPB */
+ hyperstone_andn, hyperstone_andn, hyperstone_andn, hyperstone_andn, /* ANDN */
+ hyperstone_or, hyperstone_or, hyperstone_or, hyperstone_or, /* OR */
+ hyperstone_xor, hyperstone_xor, hyperstone_xor, hyperstone_xor, /* XOR */
+ hyperstone_subc, hyperstone_subc, hyperstone_subc, hyperstone_subc, /* SUBC */
+ hyperstone_not, hyperstone_not, hyperstone_not, hyperstone_not, /* NOT */
+ hyperstone_sub, hyperstone_sub, hyperstone_sub, hyperstone_sub, /* SUB */
+ hyperstone_subs, hyperstone_subs, hyperstone_subs, hyperstone_subs, /* SUBS */
+ hyperstone_addc, hyperstone_addc, hyperstone_addc, hyperstone_addc, /* ADDC */
+ hyperstone_and, hyperstone_and, hyperstone_and, hyperstone_and, /* AND */
+ hyperstone_neg, hyperstone_neg, hyperstone_neg, hyperstone_neg, /* NEG */
+ hyperstone_negs, hyperstone_negs, hyperstone_negs, hyperstone_negs, /* NEGS */
+ hyperstone_cmpi, hyperstone_cmpi, hyperstone_cmpi, hyperstone_cmpi, /* CMPI */
+ hyperstone_movi, hyperstone_movi, hyperstone_movi, hyperstone_movi, /* MOVI */
+ hyperstone_addi, hyperstone_addi, hyperstone_addi, hyperstone_addi, /* ADDI */
+ hyperstone_addsi,hyperstone_addsi,hyperstone_addsi, hyperstone_addsi, /* ADDSI */
+ hyperstone_cmpbi,hyperstone_cmpbi,hyperstone_cmpbi, hyperstone_cmpbi, /* CMPBI */
+ hyperstone_andni,hyperstone_andni,hyperstone_andni, hyperstone_andni, /* ANDNI */
+ hyperstone_ori, hyperstone_ori, hyperstone_ori, hyperstone_ori, /* ORI */
+ hyperstone_xori, hyperstone_xori, hyperstone_xori, hyperstone_xori, /* XORI */
+ hyperstone_shrdi,hyperstone_shrdi,hyperstone_shrd, hyperstone_shr, /* SHRDI, SHRD, SHR */
+ hyperstone_sardi,hyperstone_sardi,hyperstone_sard, hyperstone_sar, /* SARDI, SARD, SAR */
+ hyperstone_shldi,hyperstone_shldi,hyperstone_shld, hyperstone_shl, /* SHLDI, SHLD, SHL */
+ reserved, reserved, hyperstone_testlz,hyperstone_rol, /* RESERVED, TESTLZ, ROL */
+ hyperstone_ldxx1,hyperstone_ldxx1,hyperstone_ldxx1, hyperstone_ldxx1, /* LDxx.D/A/IOD/IOA */
+ hyperstone_ldxx2,hyperstone_ldxx2,hyperstone_ldxx2, hyperstone_ldxx2, /* LDxx.N/S */
+ hyperstone_stxx1,hyperstone_stxx1,hyperstone_stxx1, hyperstone_stxx1, /* STxx.D/A/IOD/IOA */
+ hyperstone_stxx2,hyperstone_stxx2,hyperstone_stxx2, hyperstone_stxx2, /* STxx.N/S */
+ hyperstone_shri, hyperstone_shri, hyperstone_shri, hyperstone_shri, /* SHRI */
+ hyperstone_sari, hyperstone_sari, hyperstone_sari, hyperstone_sari, /* SARI */
+ hyperstone_shli, hyperstone_shli, hyperstone_shli, hyperstone_shli, /* SHLI */
+ reserved, reserved, reserved, reserved, /* RESERVED */
+ hyperstone_mulu, hyperstone_mulu, hyperstone_mulu, hyperstone_mulu, /* MULU */
+ hyperstone_muls, hyperstone_muls, hyperstone_muls, hyperstone_muls, /* MULS */
+ hyperstone_set, hyperstone_set, hyperstone_set, hyperstone_set, /* SETxx - SETADR - FETCH */
+ hyperstone_mul, hyperstone_mul, hyperstone_mul, hyperstone_mul, /* MUL */
+ hyperstone_fadd, hyperstone_faddd,hyperstone_fsub, hyperstone_fsubd, /* FADD, FADDD, FSUB, FSUBD */
+ hyperstone_fmul, hyperstone_fmuld,hyperstone_fdiv, hyperstone_fdivd, /* FMUL, FMULD, FDIV, FDIVD */
+ hyperstone_fcmp, hyperstone_fcmpd,hyperstone_fcmpu, hyperstone_fcmpud, /* FCMP, FCMPD, FCMPU, FCMPUD */
+ hyperstone_fcvt, hyperstone_fcvtd,hyperstone_extend,hyperstone_do, /* FCVT, FCVTD, EXTEND, DO */
+ hyperstone_ldwr, hyperstone_ldwr, hyperstone_lddr, hyperstone_lddr, /* LDW.R, LDD.R */
+ hyperstone_ldwp, hyperstone_ldwp, hyperstone_lddp, hyperstone_lddp, /* LDW.P, LDD.P */
+ hyperstone_stwr, hyperstone_stwr, hyperstone_stdr, hyperstone_stdr, /* STW.R, STD.R */
+ hyperstone_stwp, hyperstone_stwp, hyperstone_stdp, hyperstone_stdp, /* STW.P, STD.P */
+ hyperstone_dbv, hyperstone_dbnv, hyperstone_dbe, hyperstone_dbne, /* DBV, DBNV, DBE, DBNE */
+ hyperstone_dbc, hyperstone_dbnc, hyperstone_dbse, hyperstone_dbht, /* DBC, DBNC, DBSE, DBHT */
+ hyperstone_dbn, hyperstone_dbnn, hyperstone_dble, hyperstone_dbgt, /* DBN, DBNN, DBLE, DBGT */
+ hyperstone_dbr, hyperstone_frame,hyperstone_call, hyperstone_call, /* DBR, FRAME, CALL */
+ hyperstone_bv, hyperstone_bnv, hyperstone_be, hyperstone_bne, /* BV, BNV, BE, BNE */
+ hyperstone_bc, hyperstone_bnc, hyperstone_bse, hyperstone_bht, /* BC, BNC, BSE, BHT */
+ hyperstone_bn, hyperstone_bnn, hyperstone_ble, hyperstone_bgt, /* BN, BNN, BLE, BGT */
+ hyperstone_br, hyperstone_trap, hyperstone_trap, hyperstone_trap /* BR, TRAPxx - TRAP */
+};
+
+// 4Kb IRAM (On-Chip Memory)
+#if (HAS_E116T || HAS_GMS30C2116)
+
+static ADDRESS_MAP_START( e116_4k_iram_map, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0xc0000000, 0xc0000fff) AM_RAM AM_MIRROR(0x1ffff000)
+ADDRESS_MAP_END
+
+#endif
+
+#if (HAS_E132N || HAS_E132T || HAS_GMS30C2132)
+
+static ADDRESS_MAP_START( e132_4k_iram_map, ADDRESS_SPACE_PROGRAM, 32 )
+ AM_RANGE(0xc0000000, 0xc0000fff) AM_RAM AM_MIRROR(0x1ffff000)
+ADDRESS_MAP_END
+
+#endif
+
+// 8Kb IRAM (On-Chip Memory)
+
+#if (HAS_E116XT || HAS_GMS30C2216)
+
+static ADDRESS_MAP_START( e116_8k_iram_map, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0xc0000000, 0xc0001fff) AM_RAM AM_MIRROR(0x1fffe000)
+ADDRESS_MAP_END
+
+#endif
+
+#if (HAS_E132XN || HAS_E132XT || HAS_GMS30C2232)
+
+static ADDRESS_MAP_START( e132_8k_iram_map, ADDRESS_SPACE_PROGRAM, 32 )
+ AM_RANGE(0xc0000000, 0xc0001fff) AM_RAM AM_MIRROR(0x1fffe000)
+ADDRESS_MAP_END
+
+#endif
+
+// 16Kb IRAM (On-Chip Memory)
+
+#if (HAS_E116XS || HAS_E116XSR)
+
+static ADDRESS_MAP_START( e116_16k_iram_map, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0xc0000000, 0xc0003fff) AM_RAM AM_MIRROR(0x1fffc000)
+ADDRESS_MAP_END
+
+#endif
+
+#if (HAS_E132XS || HAS_E132XSR)
+
+static ADDRESS_MAP_START( e132_16k_iram_map, ADDRESS_SPACE_PROGRAM, 32 )
+ AM_RANGE(0xc0000000, 0xc0003fff) AM_RAM AM_MIRROR(0x1fffc000)
+ADDRESS_MAP_END
+
+#endif
+
+/* Return the entry point for a determinated trap */
+static UINT32 get_trap_addr(UINT8 trapno)
+{
+ UINT32 addr;
+ if( hyperstone.trap_entry == 0xffffff00 ) /* @ MEM3 */
+ {
+ addr = trapno * 4;
+ }
+ else
+ {
+ addr = (63 - trapno) * 4;
+ }
+ addr |= hyperstone.trap_entry;
+
+ return addr;
+}
+
+/* Return the entry point for a determinated emulated code (the one for "extend" opcode is reserved) */
+static UINT32 get_emu_code_addr(UINT8 num) /* num is OP */
+{
+ UINT32 addr;
+ if( hyperstone.trap_entry == 0xffffff00 ) /* @ MEM3 */
+ {
+ addr = (hyperstone.trap_entry - 0x100) | ((num & 0xf) << 4);
+ }
+ else
+ {
+ addr = hyperstone.trap_entry | (0x10c | ((0xcf - num) << 4));
+ }
+ return addr;
+}
+
+static void hyperstone_set_trap_entry(int which)
+{
+ switch( which )
+ {
+ case E132XS_ENTRY_MEM0:
+ hyperstone.trap_entry = 0x00000000;
+ break;
+
+ case E132XS_ENTRY_MEM1:
+ hyperstone.trap_entry = 0x40000000;
+ break;
+
+ case E132XS_ENTRY_MEM2:
+ hyperstone.trap_entry = 0x80000000;
+ break;
+
+ case E132XS_ENTRY_MEM3:
+ hyperstone.trap_entry = 0xffffff00;
+ break;
+
+ case E132XS_ENTRY_IRAM:
+ hyperstone.trap_entry = 0xc0000000;
+ break;
+
+ default:
+ logerror("Set entry point to a reserved value: %d\n", which);
+ break;
+ }
+}
+
+#define OP hyperstone.op
+
+#define PPC hyperstone.ppc //previous pc
+#define PC hyperstone.global_regs[0] //Program Counter
+#define SR hyperstone.global_regs[1] //Status Register
+#define FER hyperstone.global_regs[2] //Floating-Point Exception Register
+// 03 - 15 General Purpose Registers
+// 16 - 17 Reserved
+#define SP hyperstone.global_regs[18] //Stack Pointer
+#define UB hyperstone.global_regs[19] //Upper Stack Bound
+#define BCR hyperstone.global_regs[20] //Bus Control Register
+#define TPR hyperstone.global_regs[21] //Timer Prescaler Register
+#define TCR hyperstone.global_regs[22] //Timer Compare Register
+#define TR hyperstone.global_regs[23] //Timer Register
+#define WCR hyperstone.global_regs[24] //Watchdog Compare Register
+#define ISR hyperstone.global_regs[25] //Input Status Register
+#define FCR hyperstone.global_regs[26] //Function Control Register
+#define MCR hyperstone.global_regs[27] //Memory Control Register
+// 28 - 31 Reserved
+
+/* SR flags */
+#define GET_C ( SR & 0x00000001) // bit 0 //CARRY
+#define GET_Z ((SR & 0x00000002)>>1) // bit 1 //ZERO
+#define GET_N ((SR & 0x00000004)>>2) // bit 2 //NEGATIVE
+#define GET_V ((SR & 0x00000008)>>3) // bit 3 //OVERFLOW
+#define GET_M ((SR & 0x00000010)>>4) // bit 4 //CACHE-MODE
+#define GET_H ((SR & 0x00000020)>>5) // bit 5 //HIGHGLOBAL
+// bit 6 RESERVED (always 0)
+#define GET_I ((SR & 0x00000080)>>7) // bit 7 //INTERRUPT-MODE
+#define GET_FTE ((SR & 0x00001f00)>>8) // bits 12 - 8 //Floating-Point Trap Enable
+#define GET_FRM ((SR & 0x00006000)>>13) // bits 14 - 13 //Floating-Point Rounding Mode
+#define GET_L ((SR & 0x00008000)>>15) // bit 15 //INTERRUPT-LOCK
+#define GET_T ((SR & 0x00010000)>>16) // bit 16 //TRACE-MODE
+#define GET_P ((SR & 0x00020000)>>17) // bit 17 //TRACE PENDING
+#define GET_S ((SR & 0x00040000)>>18) // bit 18 //SUPERVISOR STATE
+#define GET_ILC ((SR & 0x00180000)>>19) // bits 20 - 19 //INSTRUCTION-LENGTH
+/* if FL is zero it is always interpreted as 16 */
+#define GET_FL ((SR & 0x01e00000) ? ((SR & 0x01e00000)>>21) : 16) // bits 24 - 21 //FRAME LENGTH
+#define GET_FP ((SR & 0xfe000000)>>25) // bits 31 - 25 //FRAME POINTER
+
+#define SET_C(val) (SR = (SR & ~0x00000001) | (val))
+#define SET_Z(val) (SR = (SR & ~0x00000002) | ((val) << 1))
+#define SET_N(val) (SR = (SR & ~0x00000004) | ((val) << 2))
+#define SET_V(val) (SR = (SR & ~0x00000008) | ((val) << 3))
+#define SET_M(val) (SR = (SR & ~0x00000010) | ((val) << 4))
+#define SET_H(val) (SR = (SR & ~0x00000020) | ((val) << 5))
+#define SET_I(val) (SR = (SR & ~0x00000080) | ((val) << 7))
+#define SET_FTE(val) (SR = (SR & ~0x00001f00) | ((val) << 8))
+#define SET_FRM(val) (SR = (SR & ~0x00006000) | ((val) << 13))
+#define SET_L(val) (SR = (SR & ~0x00008000) | ((val) << 15))
+#define SET_T(val) (SR = (SR & ~0x00010000) | ((val) << 16))
+#define SET_P(val) (SR = (SR & ~0x00020000) | ((val) << 17))
+#define SET_S(val) (SR = (SR & ~0x00040000) | ((val) << 18))
+#define SET_ILC(val) (SR = (SR & ~0x00180000) | ((val) << 19))
+#define SET_FL(val) (SR = (SR & ~0x01e00000) | ((val) << 21))
+#define SET_FP(val) (SR = (SR & ~0xfe000000) | ((val) << 25))
+
+#define SET_PC(val) PC = ((val) & 0xfffffffe) //PC(0) = 0
+#define SET_SP(val) SP = ((val) & 0xfffffffc) //SP(0) = SP(1) = 0
+#define SET_UB(val) UB = ((val) & 0xfffffffc) //UB(0) = UB(1) = 0
+
+#define SET_LOW_SR(val) (SR = (SR & 0xffff0000) | ((val) & 0x0000ffff)) // when SR is addressed, only low 16 bits can be changed
+
+
+#define CHECK_C(x) (SR = (SR & ~0x00000001) | (((x) & (((UINT64)1) << 32)) ? 1 : 0 ))
+#define CHECK_VADD(x,y,z) (SR = (SR & ~0x00000008) | ((((x) ^ (z)) & ((y) ^ (z)) & 0x80000000) ? 8: 0))
+#define CHECK_VADD3(x,y,w,z) (SR = (SR & ~0x00000008) | ((((x) ^ (z)) & ((y) ^ (z)) & ((w) ^ (z)) & 0x80000000) ? 8: 0))
+#define CHECK_VSUB(x,y,z) (SR = (SR & ~0x00000008) | ((((z) ^ (y)) & ((y) ^ (x)) & 0x80000000) ? 8: 0))
+
+
+/* FER flags */
+#define GET_ACCRUED (FER & 0x0000001f) //bits 4 - 0 //Floating-Point Accrued Exceptions
+#define GET_ACTUAL (FER & 0x00001f00) //bits 12 - 8 //Floating-Point Actual Exceptions
+//other bits are reversed, in particular 7 - 5 for the operating system.
+//the user program can only changes the above 2 flags
+
+static UINT32 get_global_register(UINT8 code)
+{
+/*
+ if( code >= 16 )
+ {
+ switch( code )
+ {
+ case 16:
+ case 17:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ mame_printf_debug("read _Reserved_ Global Register %d @ %08X\n",code,PC);
+ break;
+
+ case BCR_REGISTER:
+ mame_printf_debug("read write-only BCR register @ %08X\n",PC);
+ return 0;
+
+ case TPR_REGISTER:
+ mame_printf_debug("read write-only TPR register @ %08X\n",PC);
+ return 0;
+
+ case FCR_REGISTER:
+ mame_printf_debug("read write-only FCR register @ %08X\n",PC);
+ return 0;
+
+ case MCR_REGISTER:
+ mame_printf_debug("read write-only MCR register @ %08X\n",PC);
+ return 0;
+ }
+ }
+*/
+ return hyperstone.global_regs[code];
+}
+
+static void set_global_register(UINT8 code, UINT32 val)
+{
+ //TODO: add correct FER set instruction
+
+ if( code == PC_REGISTER )
+ {
+ SET_PC(val);
+ change_pc(PC);
+ }
+ else if( code == SR_REGISTER )
+ {
+ SET_LOW_SR(val); // only a RET instruction can change the full content of SR
+
+ SR &= ~0x40; //reserved bit 6 always zero
+ }
+ else
+ {
+ if( code != ISR_REGISTER )
+ hyperstone.global_regs[code] = val;
+ else
+ logerror("Written to ISR register. PC = %08X\n", PC);
+
+ //are these set only when privilege bit is set?
+ if( code >= 16 )
+ {
+ switch( code )
+ {
+ case 18:
+ SET_SP(val);
+ break;
+
+ case 19:
+ SET_UB(val);
+ break;
+/*
+ case ISR_REGISTER:
+ mame_printf_debug("written %08X to read-only ISR register\n",val);
+ break;
+
+ case 22:
+// mame_printf_debug("written %08X to TCR register\n",val);
+ break;
+
+ case 23:
+// mame_printf_debug("written %08X to TR register\n",val);
+ break;
+
+ case 24:
+// mame_printf_debug("written %08X to WCR register\n",val);
+ break;
+
+ case 16:
+ case 17:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ mame_printf_debug("written %08X to _Reserved_ Global Register %d\n",val,code);
+ break;
+
+ case BCR_REGISTER:
+ break;
+*/
+ case TPR_REGISTER:
+
+ hyperstone.n = (val & 0xff0000) >> 16;
+
+ if(!(val & 0x80000000)) /* change immediately */
+ {
+ hyperstone.delay_timer = 0;
+ hyperstone.timer_clocks = hyperstone.n + 2;
+ }
+ else
+ {
+ hyperstone.delay_timer = 1;
+ }
+
+ break;
+/*
+ case FCR_REGISTER:
+ switch((val & 0x3000)>>12)
+ {
+ case 0:
+ mame_printf_debug("IO3 interrupt mode\n");
+ break;
+ case 1:
+ mame_printf_debug("IO3 timing mode\n");
+ break;
+ case 2:
+ mame_printf_debug("watchdog mode\n");
+ break;
+ case 3:
+ // IO3 standard mode
+ break;
+ }
+ break;
+*/
+ case MCR_REGISTER:
+ // bits 14..12 EntryTableMap
+ hyperstone_set_trap_entry((val & 0x7000) >> 12);
+
+ break;
+ }
+ }
+ }
+}
+
+static void set_local_register(UINT8 code, UINT32 val)
+{
+ UINT8 new_code = (code + GET_FP) % 64;
+
+ hyperstone.local_regs[new_code] = val;
+}
+
+#define GET_ABS_L_REG(code) hyperstone.local_regs[code]
+#define SET_L_REG(code, val) set_local_register(code, val)
+#define SET_ABS_L_REG(code, val) hyperstone.local_regs[code] = val
+#define GET_G_REG(code) get_global_register(code)
+#define SET_G_REG(code, val) set_global_register(code, val)
+
+#define S_BIT ((OP & 0x100) >> 8)
+#define N_BIT S_BIT
+#define D_BIT ((OP & 0x200) >> 9)
+#define N_VALUE ((N_BIT << 4) | (OP & 0x0f))
+#define DST_CODE ((OP & 0xf0) >> 4)
+#define SRC_CODE (OP & 0x0f)
+#define SIGN_BIT(val) ((val & 0x80000000) >> 31)
+
+#define LOCAL 1
+
+static void decode_source(int local, int hflag)
+{
+ if(local)
+ {
+ UINT8 code = current_regs.src;
+ current_regs.set_src_register = set_local_register;
+ code = (current_regs.src + GET_FP) % 64; // registers offset by frame pointer
+ SREG = hyperstone.local_regs[code];
+ code = (current_regs.src + 1 + GET_FP) % 64;
+ SREGF = hyperstone.local_regs[code];
+ }
+ else
+ {
+ current_regs.set_src_register = set_global_register;
+
+ if(hflag)
+ current_regs.src += hflag * 16;
+
+ SREG = hyperstone.global_regs[current_regs.src];
+
+ /* bound safe */
+ if(current_regs.src != 15 && current_regs.src != 31)
+ SREGF = hyperstone.global_regs[current_regs.src + 1];
+
+ if(current_regs.src == PC_REGISTER)
+ SRC_IS_PC = 1;
+ else if(current_regs.src == SR_REGISTER)
+ SRC_IS_SR = 1;
+ else if( current_regs.src == BCR_REGISTER || current_regs.src == TPR_REGISTER ||
+ current_regs.src == FCR_REGISTER || current_regs.src == MCR_REGISTER )
+ {
+ SREG = 0; // write-only registers
+ }
+ else if( current_regs.src == ISR_REGISTER )
+ mame_printf_debug("read src ISR. PC = %08X\n",PPC);
+ }
+}
+
+static void decode_dest(int local, int hflag)
+{
+ if(local)
+ {
+ UINT8 code = current_regs.dst;
+ current_regs.set_dst_register = set_local_register;
+ code = (current_regs.dst + GET_FP) % 64; // registers offset by frame pointer
+ DREG = hyperstone.local_regs[code];
+ code = (current_regs.dst + 1 + GET_FP) % 64;
+ DREGF = hyperstone.local_regs[code];
+ }
+ else
+ {
+ current_regs.set_dst_register = set_global_register;
+
+ if(hflag)
+ current_regs.dst += hflag * 16;
+
+ DREG = hyperstone.global_regs[current_regs.dst];
+
+ /* bound safe */
+ if(current_regs.dst != 15 && current_regs.dst != 31)
+ DREGF = hyperstone.global_regs[current_regs.dst + 1];
+
+ if(current_regs.dst == PC_REGISTER)
+ DST_IS_PC = 1;
+ else if(current_regs.dst == SR_REGISTER)
+ DST_IS_SR = 1;
+ else if( current_regs.src == ISR_REGISTER )
+ mame_printf_debug("read dst ISR. PC = %08X\n",PPC);
+ }
+}
+
+INLINE void decode_RR(void)
+{
+ current_regs.src = SRC_CODE;
+ current_regs.dst = DST_CODE;
+ decode_source(S_BIT, 0);
+ decode_dest(D_BIT, 0);
+
+ if( SRC_CODE == DST_CODE && S_BIT == D_BIT )
+ SAME_SRC_DST = 1;
+
+ if( S_BIT == LOCAL && D_BIT == LOCAL )
+ {
+ if( SRC_CODE == ((DST_CODE + 1) % 64) )
+ SAME_SRC_DSTF = 1;
+
+ if( ((SRC_CODE + 1) % 64) == DST_CODE )
+ SAME_SRCF_DST = 1;
+ }
+ else if( S_BIT == 0 && D_BIT == 0 )
+ {
+ if( SRC_CODE == (DST_CODE + 1) )
+ SAME_SRC_DSTF = 1;
+
+ if( (SRC_CODE + 1) == DST_CODE )
+ SAME_SRCF_DST = 1;
+ }
+}
+
+INLINE void decode_LL(void)
+{
+ current_regs.src = SRC_CODE;
+ current_regs.dst = DST_CODE;
+ decode_source(LOCAL, 0);
+ decode_dest(LOCAL, 0);
+
+ if( SRC_CODE == DST_CODE )
+ SAME_SRC_DST = 1;
+
+ if( SRC_CODE == ((DST_CODE + 1) % 64) )
+ SAME_SRC_DSTF = 1;
+}
+
+INLINE void decode_LR(void)
+{
+ current_regs.src = SRC_CODE;
+ current_regs.dst = DST_CODE;
+ decode_source(S_BIT, 0);
+ decode_dest(LOCAL, 0);
+
+ if( ((SRC_CODE + 1) % 64) == DST_CODE && S_BIT == LOCAL )
+ SAME_SRCF_DST = 1;
+}
+
+INLINE void check_delay_PC(void)
+{
+ // if PC is used in a delay instruction, the delayed PC should be used
+ if( hyperstone.delay.delay_cmd == DELAY_EXECUTE )
+ {
+ PC = hyperstone.delay.delay_pc;
+ hyperstone.delay.delay_cmd = NO_DELAY;
+ }
+}
+
+INLINE void decode_immediate(void)
+{
+ switch( N_VALUE )
+ {
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
+ case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16:
+ EXTRA_U = N_VALUE;
+ break;
+
+ case 17:
+ hyperstone.instruction_length = 3;
+ EXTRA_U = (READ_OP(PC) << 16) | READ_OP(PC + 2);
+ PC += 4;
+ break;
+
+ case 18:
+ hyperstone.instruction_length = 2;
+ EXTRA_U = READ_OP(PC);
+ PC += 2;
+ break;
+
+ case 19:
+ hyperstone.instruction_length = 2;
+ EXTRA_U = 0xffff0000 | READ_OP(PC);
+ PC += 2;
+ break;
+
+ case 20:
+ EXTRA_U = 32; // bit 5 = 1, others = 0
+ break;
+
+ case 21:
+ EXTRA_U = 64; // bit 6 = 1, others = 0
+ break;
+
+ case 22:
+ EXTRA_U = 128; // bit 7 = 1, others = 0
+ break;
+
+ case 23:
+ EXTRA_U = 0x80000000; // bit 31 = 1, others = 0 (2 at the power of 31)
+ break;
+
+ case 24:
+ EXTRA_U = -8;
+ break;
+
+ case 25:
+ EXTRA_U = -7;
+ break;
+
+ case 26:
+ EXTRA_U = -6;
+ break;
+
+ case 27:
+ EXTRA_U = -5;
+ break;
+
+ case 28:
+ EXTRA_U = -4;
+ break;
+
+ case 29:
+ EXTRA_U = -3;
+ break;
+
+ case 30:
+ EXTRA_U = -2;
+ break;
+
+ case 31:
+ EXTRA_U = -1;
+ break;
+ }
+}
+
+INLINE void decode_const(void)
+{
+ UINT16 imm_1 = READ_OP(PC);
+
+ PC += 2;
+ hyperstone.instruction_length = 2;
+
+ if( E_BIT(imm_1) )
+ {
+ UINT16 imm_2 = READ_OP(PC);
+
+ PC += 2;
+ hyperstone.instruction_length = 3;
+
+ EXTRA_S = imm_2;
+ EXTRA_S |= ((imm_1 & 0x3fff) << 16);
+
+ if( S_BIT_CONST(imm_1) )
+ {
+ EXTRA_S |= 0xc0000000;
+ }
+ }
+ else
+ {
+ EXTRA_S = imm_1 & 0x3fff;
+
+ if( S_BIT_CONST(imm_1) )
+ {
+ EXTRA_S |= 0xffffc000;
+ }
+ }
+}
+
+INLINE void decode_pcrel(void)
+{
+ if( OP & 0x80 )
+ {
+ UINT16 next = READ_OP(PC);
+
+ PC += 2;
+ hyperstone.instruction_length = 2;
+
+ EXTRA_S = (OP & 0x7f) << 16;
+ EXTRA_S |= (next & 0xfffe);
+
+ if( next & 1 )
+ EXTRA_S |= 0xff800000;
+ }
+ else
+ {
+ EXTRA_S = OP & 0x7e;
+
+ if( OP & 1 )
+ EXTRA_S |= 0xffffff80;
+ }
+}
+
+INLINE void decode_dis(void)
+{
+ UINT16 next_1 = READ_OP(PC);
+
+ PC += 2;
+ hyperstone.instruction_length = 2;
+
+ current_regs.sub_type = DD(next_1);
+
+ if( E_BIT(next_1) )
+ {
+ UINT16 next_2 = READ_OP(PC);
+
+ PC += 2;
+ hyperstone.instruction_length = 3;
+
+ EXTRA_S = next_2;
+ EXTRA_S |= ((next_1 & 0xfff) << 16);
+
+ if( S_BIT_CONST(next_1) )
+ {
+ EXTRA_S |= 0xf0000000;
+ }
+ }
+ else
+ {
+ EXTRA_S = next_1 & 0xfff;
+
+ if( S_BIT_CONST(next_1) )
+ {
+ EXTRA_S |= 0xfffff000;
+ }
+ }
+}
+
+INLINE void decode_lim(void)
+{
+ UINT32 next = READ_OP(PC);
+ PC += 2;
+ hyperstone.instruction_length = 2;
+
+ current_regs.sub_type = X_CODE(next);
+
+ if( E_BIT(next) )
+ {
+ EXTRA_U = ((next & 0xfff) << 16) | READ_OP(PC);
+ PC += 2;
+ hyperstone.instruction_length = 3;
+ }
+ else
+ {
+ EXTRA_U = next & 0xfff;
+ }
+}
+
+/* used in the jumptable */
+INLINE void RRdecode(void)
+{
+ check_delay_PC();
+ decode_RR();
+}
+
+INLINE void RRlimdecode(void)
+{
+ decode_lim();
+ check_delay_PC();
+ decode_RR();
+}
+
+INLINE void RRconstdecode(void)
+{
+ decode_const();
+ check_delay_PC();
+ decode_RR();
+}
+
+INLINE void RRdisdecode(void)
+{
+ decode_dis();
+ check_delay_PC();
+ decode_RR();
+}
+
+INLINE void RRdecodewithHflag(void)
+{
+ check_delay_PC();
+ current_regs.src = SRC_CODE;
+ current_regs.dst = DST_CODE;
+ decode_source(S_BIT, GET_H);
+ decode_dest(D_BIT, GET_H);
+
+ if(GET_H)
+ if(S_BIT == 0 && D_BIT == 0)
+ popmessage("MOV with hflag and 2 GRegs! PC = %08X\n",PPC);
+}
+
+INLINE void Rimmdecode(void)
+{
+ decode_immediate();
+ check_delay_PC();
+ current_regs.dst = DST_CODE;
+ decode_dest(D_BIT, 0);
+}
+
+INLINE void Rndecode(void)
+{
+ check_delay_PC();
+ current_regs.dst = DST_CODE;
+ decode_dest(D_BIT, 0);
+}
+
+INLINE void RimmdecodewithHflag(void)
+{
+ decode_immediate();
+ check_delay_PC();
+ current_regs.dst = DST_CODE;
+ decode_dest(D_BIT, GET_H);
+}
+
+INLINE void Lndecode(void)
+{
+ check_delay_PC();
+ current_regs.dst = DST_CODE;
+ decode_dest(LOCAL, 0);
+}
+
+INLINE void LLdecode(void)
+{
+ check_delay_PC();
+ decode_LL();
+}
+
+INLINE void LLextdecode(void)
+{
+ hyperstone.instruction_length = 2;
+ EXTRA_U = READ_OP(PC);
+ PC += 2;
+ check_delay_PC();
+ decode_LL();
+}
+
+INLINE void LRdecode(void)
+{
+ check_delay_PC();
+ decode_LR();
+}
+
+INLINE void LRconstdecode(void)
+{
+ decode_const();
+ check_delay_PC();
+ decode_LR();
+}
+
+INLINE void PCreldecode(void)
+{
+ decode_pcrel();
+ check_delay_PC();
+}
+
+INLINE void PCadrdecode(void)
+{
+ check_delay_PC();
+}
+
+INLINE void no_decode(void)
+{
+
+}
+
+
+/* Decode helper table */
+static void (*hyperstone_decode[0x100])(void) = {
+/*00*/ RRdecode, RRdecode, RRdecode, RRdecode, /* CHK - CHKZ - NOP */
+/*04*/ RRdecode, RRdecode, RRdecode, RRdecode, /* MOVD - RET */
+/*08*/ RRdecode, RRdecode, RRdecode, RRdecode, /* DIVU */
+/*0c*/ RRdecode, RRdecode, RRdecode, RRdecode, /* DIVS */
+/*10*/ RRlimdecode, RRlimdecode, RRlimdecode, RRlimdecode, /* XMx - XXx */
+/*14*/ RRconstdecode, RRconstdecode, RRconstdecode, RRconstdecode, /* MASK */
+/*18*/ RRconstdecode, RRconstdecode, RRconstdecode, RRconstdecode, /* SUM */
+/*1c*/ RRconstdecode, RRconstdecode, RRconstdecode, RRconstdecode, /* SUMS */
+/*20*/ RRdecode, RRdecode, RRdecode, RRdecode, /* CMP */
+/*24*/ RRdecodewithHflag, RRdecodewithHflag, RRdecodewithHflag, RRdecodewithHflag, /* MOV */
+/*28*/ RRdecode, RRdecode, RRdecode, RRdecode, /* ADD */
+/*2c*/ RRdecode, RRdecode, RRdecode, RRdecode, /* ADDS */
+/*30*/ RRdecode, RRdecode, RRdecode, RRdecode, /* CMPB */
+/*34*/ RRdecode, RRdecode, RRdecode, RRdecode, /* ANDN */
+/*38*/ RRdecode, RRdecode, RRdecode, RRdecode, /* OR */
+/*3c*/ RRdecode, RRdecode, RRdecode, RRdecode, /* XOR */
+/*40*/ RRdecode, RRdecode, RRdecode, RRdecode, /* SUBC */
+/*44*/ RRdecode, RRdecode, RRdecode, RRdecode, /* NOT */
+/*48*/ RRdecode, RRdecode, RRdecode, RRdecode, /* SUB */
+/*4c*/ RRdecode, RRdecode, RRdecode, RRdecode, /* SUBS */
+/*50*/ RRdecode, RRdecode, RRdecode, RRdecode, /* ADDC */
+/*54*/ RRdecode, RRdecode, RRdecode, RRdecode, /* AND */
+/*58*/ RRdecode, RRdecode, RRdecode, RRdecode, /* NEG */
+/*5c*/ RRdecode, RRdecode, RRdecode, RRdecode, /* NEGS */
+/*60*/ Rimmdecode, Rimmdecode, Rimmdecode, Rimmdecode, /* CMPI */
+/*64*/ RimmdecodewithHflag, RimmdecodewithHflag, RimmdecodewithHflag, RimmdecodewithHflag, /* MOVI */
+/*68*/ Rimmdecode, Rimmdecode, Rimmdecode, Rimmdecode, /* ADDI */
+/*6c*/ Rimmdecode, Rimmdecode, Rimmdecode, Rimmdecode, /* ADDSI */
+/*70*/ Rimmdecode, Rimmdecode, Rimmdecode, Rimmdecode, /* CMPBI */
+/*74*/ Rimmdecode, Rimmdecode, Rimmdecode, Rimmdecode, /* ANDNI */
+/*78*/ Rimmdecode, Rimmdecode, Rimmdecode, Rimmdecode, /* ORI */
+/*7c*/ Rimmdecode, Rimmdecode, Rimmdecode, Rimmdecode, /* XORI */
+/*80*/ Lndecode, Lndecode, LLdecode, LLdecode, /* SHRDI, SHRD, SHR */
+/*84*/ Lndecode, Lndecode, LLdecode, LLdecode, /* SARDI, SARD, SAR */
+/*88*/ Lndecode, Lndecode, LLdecode, LLdecode, /* SHLDI, SHLD, SHL */
+/*8c*/ no_decode, no_decode, LLdecode, LLdecode, /* RESERVED, TESTLZ, ROL */
+/*90*/ RRdisdecode, RRdisdecode, RRdisdecode, RRdisdecode, /* LDxx.D/A/IOD/IOA */
+/*94*/ RRdisdecode, RRdisdecode, RRdisdecode, RRdisdecode, /* LDxx.N/S */
+/*98*/ RRdisdecode, RRdisdecode, RRdisdecode, RRdisdecode, /* STxx.D/A/IOD/IOA */
+/*9c*/ RRdisdecode, RRdisdecode, RRdisdecode, RRdisdecode, /* STxx.N/S */
+/*a0*/ Rndecode, Rndecode, Rndecode, Rndecode, /* SHRI */
+/*a4*/ Rndecode, Rndecode, Rndecode, Rndecode, /* SARI */
+/*a8*/ Rndecode, Rndecode, Rndecode, Rndecode, /* SHLI */
+/*ac*/ no_decode, no_decode, no_decode, no_decode, /* RESERVED */
+/*b0*/ RRdecode, RRdecode, RRdecode, RRdecode, /* MULU */
+/*b4*/ RRdecode, RRdecode, RRdecode, RRdecode, /* MULS */
+/*b8*/ Rndecode, Rndecode, Rndecode, Rndecode, /* SETxx - SETADR - FETCH */
+/*bc*/ RRdecode, RRdecode, RRdecode, RRdecode, /* MUL */
+/*c0*/ LLdecode, LLdecode, LLdecode, LLdecode, /* FADD, FADDD, FSUB, FSUBD */
+/*c4*/ LLdecode, LLdecode, LLdecode, LLdecode, /* FMUL, FMULD, FDIV, FDIVD */
+/*c8*/ LLdecode, LLdecode, LLdecode, LLdecode, /* FCMP, FCMPD, FCMPU, FCMPUD */
+/*cc*/ LLdecode, LLdecode, LLextdecode, LLdecode, /* FCVT, FCVTD, EXTEND, DO */
+/*d0*/ LRdecode, LRdecode, LRdecode, LRdecode, /* LDW.R, LDD.R */
+/*d4*/ LRdecode, LRdecode, LRdecode, LRdecode, /* LDW.P, LDD.P */
+/*d8*/ LRdecode, LRdecode, LRdecode, LRdecode, /* STW.R, STD.R */
+/*dc*/ LRdecode, LRdecode, LRdecode, LRdecode, /* STW.P, STD.P */
+/*e0*/ PCreldecode, PCreldecode, PCreldecode, PCreldecode, /* DBV, DBNV, DBE, DBNE */
+/*e4*/ PCreldecode, PCreldecode, PCreldecode, PCreldecode, /* DBC, DBNC, DBSE, DBHT */
+/*e8*/ PCreldecode, PCreldecode, PCreldecode, PCreldecode, /* DBN, DBNN, DBLE, DBGT */
+/*ec*/ PCreldecode, LLdecode, LRconstdecode, LRconstdecode, /* DBR, FRAME, CALL */
+/*f0*/ PCreldecode, PCreldecode, PCreldecode, PCreldecode, /* BV, BNV, BE, BNE */
+/*f4*/ PCreldecode, PCreldecode, PCreldecode, PCreldecode, /* BC, BNC, BSE, BHT */
+/*f8*/ PCreldecode, PCreldecode, PCreldecode, PCreldecode, /* BN, BNN, BLE, BGT */
+/*fc*/ PCreldecode, PCadrdecode, PCadrdecode, PCadrdecode /* BR, TRAPxx - TRAP */
+};
+
+INLINE void execute_br(void)
+{
+ PPC = PC;
+ PC += EXTRA_S;
+ change_pc(PC);
+ SET_M(0);
+
+ hyperstone_ICount -= 2;
+}
+
+INLINE void execute_dbr(void)
+{
+ hyperstone.delay.delay_cmd = DELAY_TAKEN;
+ hyperstone.delay.delay_pc = PC + EXTRA_S;
+
+ hyperstone.intblock = 3;
+}
+
+
+static void execute_trap(UINT32 addr)
+{
+ UINT8 reg;
+ UINT32 oldSR;
+ reg = GET_FP + GET_FL;
+
+ SET_ILC(hyperstone.instruction_length & 3);
+
+ oldSR = SR;
+
+ SET_FL(6);
+ SET_FP(reg);
+
+ SET_L_REG(0, (PC & 0xfffffffe) | GET_S);
+ SET_L_REG(1, oldSR);
+
+ SET_M(0);
+ SET_T(0);
+ SET_L(1);
+ SET_S(1);
+
+ PPC = PC;
+ PC = addr;
+ change_pc(PC);
+
+ hyperstone_ICount -= 2;
+}
+
+
+static void execute_int(UINT32 addr)
+{
+ UINT8 reg;
+ UINT32 oldSR;
+ reg = GET_FP + GET_FL;
+
+ SET_ILC(hyperstone.instruction_length & 3);
+
+ oldSR = SR;
+
+ SET_FL(2);
+ SET_FP(reg);
+
+ SET_L_REG(0, (PC & 0xfffffffe) | GET_S);
+ SET_L_REG(1, oldSR);
+
+ SET_M(0);
+ SET_T(0);
+ SET_L(1);
+ SET_S(1);
+ SET_I(1);
+
+ PPC = PC;
+ PC = addr;
+ change_pc(PC);
+
+ hyperstone_ICount -= 2;
+}
+
+/* TODO: mask Parity Error and Extended Overflow exceptions */
+static void execute_exception(UINT32 addr)
+{
+ UINT8 reg;
+ UINT32 oldSR;
+ reg = GET_FP + GET_FL;
+
+ SET_ILC(hyperstone.instruction_length & 3);
+
+ oldSR = SR;
+
+ SET_FP(reg);
+ SET_FL(2);
+
+ SET_L_REG(0, (PC & 0xfffffffe) | GET_S);
+ SET_L_REG(1, oldSR);
+
+ SET_M(0);
+ SET_T(0);
+ SET_L(1);
+ SET_S(1);
+
+ PPC = PC;
+ PC = addr;
+ change_pc(PC);
+
+ mame_printf_debug("EXCEPTION! PPC = %08X PC = %08X\n",PPC-2,PC-2);
+ hyperstone_ICount -= 2;
+}
+
+static void execute_software(void)
+{
+ UINT8 reg;
+ UINT32 oldSR;
+ UINT32 addr;
+ UINT32 stack_of_dst;
+
+ SET_ILC(1);
+
+ addr = get_emu_code_addr((OP & 0xff00) >> 8);
+ reg = GET_FP + GET_FL;
+
+ //since it's sure the register is in the register part of the stack,
+ //set the stack address to a value above the highest address
+ //that can be set by a following frame instruction
+ stack_of_dst = (SP & ~0xff) + 64*4 + (((GET_FP + current_regs.dst) % 64) * 4); //converted to 32bits offset
+
+ oldSR = SR;
+
+ SET_FL(6);
+ SET_FP(reg);
+
+ SET_L_REG(0, stack_of_dst);
+ SET_L_REG(1, SREG);
+ SET_L_REG(2, SREGF);
+ SET_L_REG(3, (PC & 0xfffffffe) | GET_S);
+ SET_L_REG(4, oldSR);
+
+ SET_M(0);
+ SET_T(0);
+ SET_L(1);
+
+ PPC = PC;
+ PC = addr;
+ change_pc(PC);
+}
+
+
+/*
+ IRQ lines :
+ 0 - IO2 (trap 48)
+ 1 - IO1 (trap 49)
+ 2 - INT4 (trap 50)
+ 3 - INT3 (trap 51)
+ 4 - INT2 (trap 52)
+ 5 - INT1 (trap 53)
+ 6 - IO3 (trap 54)
+ 7 - TIMER (trap 55)
+*/
+static void set_irq_line(int irqline, int state)
+{
+ /* Interrupt-Lock flag isn't set */
+
+ if(hyperstone.intblock)
+ return;
+
+ if( !GET_L && state )
+ {
+ int execint=0;
+ switch(irqline)
+ {
+ case 0: if( (FCR&(1<<6)) && (!(FCR&(1<<4))) ) execint=1; // IO2
+ break;
+ case 1: if( (FCR&(1<<2)) && (!(FCR&(1<<0))) ) execint=1; // IO1
+ break;
+ case 2: if( !(FCR&(1<<31)) ) execint=1; // int 4
+ break;
+ case 3: if( !(FCR&(1<<30)) ) execint=1; // int 3
+ break;
+ case 4: if( !(FCR&(1<<29)) ) execint=1; // int 2
+ break;
+ case 5: if( !(FCR&(1<<28)) ) execint=1; // int 1
+ break;
+ case 6: if( (FCR&(1<<10)) && (!(FCR&(1<<8))) ) execint=1; // IO3
+ break;
+ case 7: if( !(FCR&(1<<23)) ) execint=1; // timer
+ break;
+ }
+/*
+ if( (FCR&(1<<6)) && (!(FCR&(1<<4))) ) mame_printf_debug("IO2 en\n"); // IO2
+
+ if( (FCR&(1<<2)) && (!(FCR&(1<<0))) ) mame_printf_debug("IO1 en\n"); // IO1
+
+ if( !(FCR&(1<<31)) ) mame_printf_debug("int4 en\n"); // int 4
+
+ if( !(FCR&(1<<30)) ) mame_printf_debug("int3 en\n"); // int 3
+
+ if( !(FCR&(1<<29)) ) mame_printf_debug("int2 en\n"); // int 2
+
+ if( !(FCR&(1<<28)) ) mame_printf_debug("int1 en\n"); // int 1
+
+ if( (FCR&(1<<10)) && (!(FCR&(1<<8))) ) mame_printf_debug("IO3 en\n"); // IO3
+
+ // if( !(FCR&(1<<23)) ) mame_printf_debug("timer irq!\n"); // timer
+*/
+ if(execint)
+ {
+ execute_int(get_trap_addr(irqline + 48));
+ (*hyperstone.irq_callback)(irqline);
+ }
+ }
+}
+
+static void hyperstone_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ state_save_register_item_array("E132XS", index, hyperstone.global_regs);
+ state_save_register_item_array("E132XS", index, hyperstone.local_regs);
+ state_save_register_item("E132XS", index, hyperstone.ppc);
+ state_save_register_item("E132XS", index, hyperstone.trap_entry);
+ state_save_register_item("E132XS", index, hyperstone.delay.delay_pc);
+ state_save_register_item("E132XS", index, hyperstone.op);
+ state_save_register_item("E132XS", index, hyperstone.n);
+ state_save_register_item("E132XS", index, hyperstone.h_clear);
+ state_save_register_item("E132XS", index, hyperstone.instruction_length);
+ state_save_register_item("E132XS", index, hyperstone.intblock);
+ state_save_register_item("E132XS", index, hyperstone.delay_timer);
+ state_save_register_item("E132XS", index, hyperstone.delay.delay_cmd);
+ state_save_register_item("E132XS", index, hyperstone.timer_clocks);
+
+ hyperstone.irq_callback = irqcallback;
+}
+
+#if (HAS_E116T || HAS_E116XT || HAS_E116XS || HAS_E116XSR || HAS_GMS30C2116 || HAS_GMS30C2216)
+static void e116_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ hyp_cpu_read_byte = program_read_byte_16be;
+ hyp_cpu_read_half_word = program_read_word_16be;
+ hyp_cpu_read_word = program_read_dword_16be;
+ hyp_cpu_read_io_word = io_read_dword_16be;
+
+ hyp_cpu_write_byte = program_write_byte_16be;
+ hyp_cpu_write_half_word = program_write_word_16be;
+ hyp_cpu_write_word = program_write_dword_16be;
+ hyp_cpu_write_io_word = io_write_dword_16be;
+
+ hyp_type_16bit = 1;
+
+ hyperstone_init(index, clock, config, irqcallback);
+}
+#endif
+
+#if (HAS_E132N || HAS_E132T || HAS_E132XN || HAS_E132XT || HAS_E132XS || HAS_E132XSR || HAS_GMS30C2132 || HAS_GMS30C2232)
+static void e132_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ hyp_cpu_read_byte = program_read_byte_32be;
+ hyp_cpu_read_half_word = program_read_word_32be;
+ hyp_cpu_read_word = program_read_dword_32be;
+ hyp_cpu_read_io_word = io_read_dword_32be;
+
+ hyp_cpu_write_byte = program_write_byte_32be;
+ hyp_cpu_write_half_word = program_write_word_32be;
+ hyp_cpu_write_word = program_write_dword_32be;
+ hyp_cpu_write_io_word = io_write_dword_32be;
+
+ hyp_type_16bit = 0;
+
+ hyperstone_init(index, clock, config, irqcallback);
+}
+#endif
+
+static void hyperstone_reset(void)
+{
+ //TODO: Add different reset initializations for BCR, MCR, FCR, TPR
+
+ int (*save_irqcallback)(int);
+
+ save_irqcallback = hyperstone.irq_callback;
+ memset(&hyperstone, 0, sizeof(hyperstone_regs));
+ hyperstone.irq_callback = save_irqcallback;
+
+ hyperstone.h_clear = 0;
+ hyperstone.instruction_length = 0;
+
+ hyperstone_set_trap_entry(E132XS_ENTRY_MEM3); /* default entry point @ MEM3 */
+
+ set_global_register(BCR_REGISTER, ~0);
+ set_global_register(MCR_REGISTER, ~0);
+ set_global_register(FCR_REGISTER, ~0);
+ set_global_register(TPR_REGISTER, 0xc000000);
+
+ PC = get_trap_addr(RESET);
+ change_pc(PC);
+
+ SET_FP(0);
+ SET_FL(2);
+
+ SET_M(0);
+ SET_T(0);
+ SET_L(1);
+ SET_S(1);
+
+ SET_L_REG(0, (PC & 0xfffffffe) | GET_S);
+ SET_L_REG(1, SR);
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_exit(void)
+{
+ // nothing to do
+}
+
+/* Handle the timer, increasing its value after "timer_clocks" clocks and returning the new icount base that needs to be used for the next check */
+static int handle_timers(int current_icount, int previous_icount)
+{
+ int diff = previous_icount - current_icount;
+ int new_icount_base;
+
+ if(diff >= hyperstone.timer_clocks)
+ {
+ TR++; // wrap around to 0 modulo 32 bits
+
+ if( hyperstone.delay_timer )
+ {
+ hyperstone.delay_timer = 0;
+ hyperstone.timer_clocks = hyperstone.n + 2;
+ }
+
+ new_icount_base = current_icount + (diff - hyperstone.timer_clocks);
+ }
+ else
+ {
+ new_icount_base = previous_icount;
+ }
+
+ if(!hyperstone.intblock)
+ {
+ if( !((TR - TCR) & 0x80000000) )
+ {
+ /* generate a timer interrupt */
+ set_irq_line(7, PULSE_LINE);
+ }
+ }
+
+ return new_icount_base;
+}
+
+static int hyperstone_execute(int cycles)
+{
+ int old_icount = cycles;
+ hyperstone_ICount = cycles;
+
+ do
+ {
+ PPC = PC; /* copy PC to previous PC */
+
+ CALL_MAME_DEBUG;
+
+ OP = READ_OP(PC);
+
+ PC += 2;
+
+ if(GET_H)
+ {
+ hyperstone.h_clear = 1;
+ }
+
+ hyperstone.instruction_length = 1;
+
+ /* clear 'current regs / flags' */
+ current_regs.src = 0;
+ current_regs.dst = 0;
+ current_regs.src_value = 0;
+ current_regs.next_src_value = 0;
+ current_regs.dst_value = 0;
+ current_regs.next_dst_value = 0;
+ current_regs.sub_type = 0;
+ current_regs.extra.u = 0;
+ current_regs.extra.s = 0;
+ current_regs.set_src_register = NULL;
+ current_regs.set_dst_register = NULL;
+ current_regs.src_is_pc = 0;
+ current_regs.dst_is_pc = 0;
+ current_regs.src_is_sr = 0;
+ current_regs.dst_is_sr = 0;
+ current_regs.same_src_dst = 0;
+ current_regs.same_src_dstf = 0;
+ current_regs.same_srcf_dst = 0;
+
+ /* decode current opcode details into current regs */
+ hyperstone_decode[(OP & 0xff00) >> 8]();
+
+ /* execute opcode */
+ hyperstone_op[(OP & 0xff00) >> 8]();
+
+ SET_ILC(hyperstone.instruction_length & 3);
+
+ old_icount = handle_timers(hyperstone_ICount, old_icount);
+
+ if(hyperstone.h_clear)
+ {
+ SET_H(0);
+ hyperstone.h_clear = 0;
+ }
+
+ if( GET_T && GET_P && hyperstone.delay.delay_cmd == NO_DELAY ) /* Not in a Delayed Branch instructions */
+ {
+ UINT32 addr = get_trap_addr(TRACE_EXCEPTION);
+ execute_exception(addr);
+ }
+
+ if( hyperstone.delay.delay_cmd == DELAY_TAKEN )
+ {
+ hyperstone.delay.delay_cmd = DELAY_EXECUTE;
+ }
+
+ if(hyperstone.intblock > 0)
+ {
+ hyperstone.intblock--;
+ }
+
+ } while( hyperstone_ICount > 0 );
+
+ return cycles - hyperstone_ICount;
+}
+
+static void hyperstone_get_context(void *regs)
+{
+ /* copy the context */
+ if( regs )
+ *(hyperstone_regs *)regs = hyperstone;
+}
+
+static void hyperstone_set_context(void *regs)
+{
+ /* copy the context */
+ if (regs)
+ hyperstone = *(hyperstone_regs *)regs;
+}
+
+#ifdef MAME_DEBUG
+static offs_t hyperstone_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return dasm_hyperstone( buffer, pc, oprom, GET_H, GET_FP );
+}
+#endif /* MAME_DEBUG */
+
+/* Opcodes */
+
+static void hyperstone_chk(void)
+{
+ UINT32 addr = get_trap_addr(RANGE_ERROR);
+
+ if( SRC_IS_SR )
+ {
+ if( DREG == 0 )
+ execute_exception(addr);
+ }
+ else
+ {
+ if( SRC_IS_PC )
+ {
+ if( DREG >= SREG )
+ execute_exception(addr);
+ }
+ else
+ {
+ if( DREG > SREG )
+ execute_exception(addr);
+ }
+ }
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_movd(void)
+{
+ if( DST_IS_PC ) // Rd denotes PC
+ {
+ // RET instruction
+
+ UINT8 old_s, old_l;
+ INT8 difference; // really it's 7 bits
+
+ if( SRC_IS_PC || SRC_IS_SR )
+ {
+ logerror("Denoted PC or SR in RET instruction. PC = %08X\n", PC);
+ }
+ else
+ {
+ old_s = GET_S;
+ old_l = GET_L;
+ PPC = PC;
+
+ PC = SET_PC(SREG);
+ change_pc(PC);
+ SR = (SREGF & 0xffe00000) | ((SREG & 0x01) << 18 ) | (SREGF & 0x3ffff);
+
+ hyperstone.instruction_length = 0; // undefined
+
+ if( (!old_s && GET_S) || (!GET_S && !old_l && GET_L))
+ {
+ UINT32 addr = get_trap_addr(PRIVILEGE_ERROR);
+ execute_exception(addr);
+ }
+
+ difference = GET_FP - ((SP & 0x1fc) >> 2);
+
+ /* convert to 8 bits */
+ if(difference > 63)
+ difference = (INT8)(difference|0x80);
+ else if( difference < -64 )
+ difference = difference & 0x7f;
+
+ if( difference < 0 ) //else it's finished
+ {
+ do
+ {
+ SP -= 4;
+ SET_ABS_L_REG(((SP & 0xfc) >> 2), READ_W(SP));
+ difference++;
+
+ } while(difference != 0);
+ }
+ }
+
+ //TODO: no 1!
+ hyperstone_ICount -= 1;
+ }
+ else if( SRC_IS_SR ) // Rd doesn't denote PC and Rs denotes SR
+ {
+ SET_DREG(0);
+ SET_DREGF(0);
+ SET_Z(1);
+ SET_N(0);
+
+ hyperstone_ICount -= 2;
+ }
+ else // Rd doesn't denote PC and Rs doesn't denote SR
+ {
+ UINT64 tmp;
+
+ SET_DREG(SREG);
+ SET_DREGF(SREGF);
+
+ tmp = COMBINE_U64_U32_U32(SREG, SREGF);
+ SET_Z( tmp == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(SREG) );
+
+ hyperstone_ICount -= 2;
+ }
+}
+
+static void hyperstone_divu(void)
+{
+ if( SAME_SRC_DST || SAME_SRC_DSTF )
+ {
+ logerror("Denoted the same register code in hyperstone_divu instruction. PC = %08X\n", PC);
+ }
+ else
+ {
+ if( SRC_IS_PC || SRC_IS_SR )
+ {
+ logerror("Denoted PC or SR as source register in hyperstone_divu instruction. PC = %08X\n", PC);
+ }
+ else
+ {
+ UINT64 dividend;
+
+ dividend = COMBINE_U64_U32_U32(DREG, DREGF);
+
+ if( SREG == 0 )
+ {
+ //Rd//Rdf -> undefined
+ //Z -> undefined
+ //N -> undefined
+ UINT32 addr;
+ SET_V(1);
+ addr = get_trap_addr(RANGE_ERROR);
+ execute_exception(addr);
+ }
+ else
+ {
+ UINT32 quotient, remainder;
+
+ /* TODO: add quotient overflow */
+ quotient = dividend / SREG;
+ remainder = dividend % SREG;
+
+ SET_DREG(remainder);
+ SET_DREGF(quotient);
+
+ SET_Z( quotient == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(quotient) );
+ SET_V(0);
+ }
+ }
+ }
+
+ hyperstone_ICount -= 36;
+}
+
+static void hyperstone_divs(void)
+{
+ if( SAME_SRC_DST || SAME_SRC_DSTF )
+ {
+ logerror("Denoted the same register code in hyperstone_divs instruction. PC = %08X\n", PC);
+ }
+ else
+ {
+ if( SRC_IS_PC || SRC_IS_SR )
+ {
+ logerror("Denoted PC or SR as source register in hyperstone_divs instruction. PC = %08X\n", PC);
+ }
+ else
+ {
+ INT64 dividend;
+
+ dividend = (INT64) COMBINE_64_32_32(DREG, DREGF);
+
+ if( SREG == 0 || (DREG & 0x80000000) )
+ {
+ //Rd//Rdf -> undefined
+ //Z -> undefined
+ //N -> undefined
+ UINT32 addr;
+ SET_V(1);
+ addr = get_trap_addr(RANGE_ERROR);
+ execute_exception(addr);
+ }
+ else
+ {
+ INT32 quotient, remainder;
+
+ /* TODO: add quotient overflow */
+ quotient = dividend / ((INT32)(SREG));
+ remainder = dividend % ((INT32)(SREG));
+
+ SET_DREG(remainder);
+ SET_DREGF(quotient);
+
+ SET_Z( quotient == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(quotient) );
+ SET_V(0);
+ }
+ }
+ }
+
+ hyperstone_ICount -= 36;
+}
+
+static void hyperstone_xm(void)
+{
+ if( SRC_IS_SR || DST_IS_SR || DST_IS_PC )
+ {
+ logerror("Denoted PC or SR in hyperstone_xm. PC = %08X\n", PC);
+ }
+ else
+ {
+ switch( current_regs.sub_type ) // x_code
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ if( !SRC_IS_PC && (SREG > EXTRA_U) )
+ {
+ UINT32 addr = get_trap_addr(RANGE_ERROR);
+ execute_exception(addr);
+ }
+ else if( SRC_IS_PC && (SREG >= EXTRA_U) )
+ {
+ UINT32 addr = get_trap_addr(RANGE_ERROR);
+ execute_exception(addr);
+ }
+ else
+ {
+ SREG <<= current_regs.sub_type;
+ }
+
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ current_regs.sub_type -= 4;
+ SREG <<= current_regs.sub_type;
+
+ break;
+ }
+
+ SET_DREG(SREG);
+ }
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_mask(void)
+{
+ DREG = SREG & EXTRA_U;
+
+ SET_DREG(DREG);
+ SET_Z( DREG == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_sum(void)
+{
+ UINT64 tmp;
+
+ if( SRC_IS_SR )
+ SREG = GET_C;
+
+ tmp = (UINT64)(SREG) + (UINT64)(EXTRA_U);
+ CHECK_C(tmp);
+ CHECK_VADD(SREG,EXTRA_U,tmp);
+
+ DREG = SREG + EXTRA_U;
+
+ SET_DREG(DREG);
+
+ if( DST_IS_PC )
+ SET_M(0);
+
+ SET_Z( DREG == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(DREG) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_sums(void)
+{
+ INT32 res;
+ INT64 tmp;
+
+ if( SRC_IS_SR )
+ SREG = GET_C;
+
+ tmp = (INT64)((INT32)(SREG)) + (INT64)(EXTRA_S);
+ CHECK_VADD(SREG,EXTRA_S,tmp);
+
+//#if SETCARRYS
+// CHECK_C(tmp);
+//#endif
+
+ res = (INT32)(SREG) + EXTRA_S;
+
+ SET_DREG(res);
+
+ SET_Z( res == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(res) );
+
+ hyperstone_ICount -= 1;
+
+ if( GET_V && !SRC_IS_SR )
+ {
+ UINT32 addr = get_trap_addr(RANGE_ERROR);
+ execute_exception(addr);
+ }
+}
+
+static void hyperstone_cmp(void)
+{
+ UINT64 tmp;
+
+ if( SRC_IS_SR )
+ SREG = GET_C;
+
+ if( DREG == SREG )
+ SET_Z(1);
+ else
+ SET_Z(0);
+
+ if( (INT32) DREG < (INT32) SREG )
+ SET_N(1);
+ else
+ SET_N(0);
+
+ tmp = (UINT64)(DREG) - (UINT64)(SREG);
+ CHECK_VSUB(SREG,DREG,tmp);
+
+ if( DREG < SREG )
+ SET_C(1);
+ else
+ SET_C(0);
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_mov(void)
+{
+ if( !GET_S && current_regs.dst >= 16 )
+ {
+ UINT32 addr = get_trap_addr(PRIVILEGE_ERROR);
+ execute_exception(addr);
+ }
+
+ SET_DREG(SREG);
+
+ if( DST_IS_PC )
+ SET_M(0);
+
+ SET_Z( SREG == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(SREG) );
+
+ hyperstone_ICount -= 1;
+}
+
+
+static void hyperstone_add(void)
+{
+ UINT64 tmp;
+
+ if( SRC_IS_SR )
+ SREG = GET_C;
+
+ tmp = (UINT64)(SREG) + (UINT64)(DREG);
+ CHECK_C(tmp);
+ CHECK_VADD(SREG,DREG,tmp);
+
+ DREG = SREG + DREG;
+ SET_DREG(DREG);
+
+ if( DST_IS_PC )
+ SET_M(0);
+
+ SET_Z( DREG == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(DREG) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_adds(void)
+{
+ INT32 res;
+ INT64 tmp;
+
+ if( SRC_IS_SR )
+ SREG = GET_C;
+
+ tmp = (INT64)((INT32)(SREG)) + (INT64)((INT32)(DREG));
+
+ CHECK_VADD(SREG,DREG,tmp);
+
+//#if SETCARRYS
+// CHECK_C(tmp);
+//#endif
+
+ res = (INT32)(SREG) + (INT32)(DREG);
+
+ SET_DREG(res);
+ SET_Z( res == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(res) );
+
+ hyperstone_ICount -= 1;
+
+ if( GET_V )
+ {
+ UINT32 addr = get_trap_addr(RANGE_ERROR);
+ execute_exception(addr);
+ }
+}
+
+static void hyperstone_cmpb(void)
+{
+ SET_Z( (DREG & SREG) == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_andn(void)
+{
+ DREG = DREG & ~SREG;
+
+ SET_DREG(DREG);
+ SET_Z( DREG == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_or(void)
+{
+ DREG = DREG | SREG;
+
+ SET_DREG(DREG);
+ SET_Z( DREG == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_xor(void)
+{
+ DREG = DREG ^ SREG;
+
+ SET_DREG(DREG);
+ SET_Z( DREG == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_subc(void)
+{
+ UINT64 tmp;
+
+ if( SRC_IS_SR )
+ {
+ tmp = (UINT64)(DREG) - (UINT64)(GET_C);
+ CHECK_VSUB(GET_C,DREG,tmp);
+ }
+ else
+ {
+ tmp = (UINT64)(DREG) - ((UINT64)(SREG) + (UINT64)(GET_C));
+ //CHECK!
+ CHECK_VSUB(SREG + GET_C,DREG,tmp);
+ }
+
+
+ if( SRC_IS_SR )
+ {
+ DREG = DREG - GET_C;
+ }
+ else
+ {
+ DREG = DREG - (SREG + GET_C);
+ }
+
+ CHECK_C(tmp);
+
+ SET_DREG(DREG);
+
+ SET_Z( GET_Z & (DREG == 0 ? 1 : 0) );
+ SET_N( SIGN_BIT(DREG) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_not(void)
+{
+ SET_DREG(~SREG);
+ SET_Z( ~SREG == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_sub(void)
+{
+ UINT64 tmp;
+
+ if( SRC_IS_SR )
+ SREG = GET_C;
+
+ tmp = (UINT64)(DREG) - (UINT64)(SREG);
+ CHECK_C(tmp);
+ CHECK_VSUB(SREG,DREG,tmp);
+
+ DREG = DREG - SREG;
+ SET_DREG(DREG);
+
+ if( DST_IS_PC )
+ SET_M(0);
+
+ SET_Z( DREG == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(DREG) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_subs(void)
+{
+ INT32 res;
+ INT64 tmp;
+
+ if( SRC_IS_SR )
+ SREG = GET_C;
+
+ tmp = (INT64)((INT32)(DREG)) - (INT64)((INT32)(SREG));
+
+//#ifdef SETCARRYS
+// CHECK_C(tmp);
+//#endif
+
+ CHECK_VSUB(SREG,DREG,tmp);
+
+ res = (INT32)(DREG) - (INT32)(SREG);
+
+ SET_DREG(res);
+
+ SET_Z( res == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(res) );
+
+ hyperstone_ICount -= 1;
+
+ if( GET_V )
+ {
+ UINT32 addr = get_trap_addr(RANGE_ERROR);
+ execute_exception(addr);
+ }
+}
+
+static void hyperstone_addc(void)
+{
+ UINT64 tmp;
+
+ if( SRC_IS_SR )
+ {
+ tmp = (UINT64)(DREG) + (UINT64)(GET_C);
+ CHECK_VADD(DREG,GET_C,tmp);
+ }
+ else
+ {
+ tmp = (UINT64)(SREG) + (UINT64)(DREG) + (UINT64)(GET_C);
+
+ //CHECK!
+ //CHECK_VADD1: V = (DREG == 0x7FFF) && (C == 1);
+ //OVERFLOW = CHECK_VADD1(DREG, C, DREG+C) | CHECK_VADD(SREG, DREG+C, SREG+DREG+C)
+ /* check if DREG + GET_C overflows */
+// if( (DREG == 0x7FFFFFFF) && (GET_C == 1) )
+// SET_V(1);
+// else
+// CHECK_VADD(SREG,DREG + GET_C,tmp);
+
+ CHECK_VADD3(SREG,DREG,GET_C,tmp);
+ }
+
+
+
+ if( SRC_IS_SR )
+ DREG = DREG + GET_C;
+ else
+ DREG = SREG + DREG + GET_C;
+
+ CHECK_C(tmp);
+
+ SET_DREG(DREG);
+ SET_Z( GET_Z & (DREG == 0 ? 1 : 0) );
+ SET_N( SIGN_BIT(DREG) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_and(void)
+{
+ DREG = DREG & SREG;
+
+ SET_DREG(DREG);
+ SET_Z( DREG == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_neg(void)
+{
+ UINT64 tmp;
+
+ if( SRC_IS_SR )
+ SREG = GET_C;
+
+ tmp = -(UINT64)(SREG);
+ CHECK_C(tmp);
+ CHECK_VSUB(SREG,0,tmp);
+
+ DREG = -SREG;
+
+ SET_DREG(DREG);
+
+ SET_Z( DREG == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(DREG) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_negs(void)
+{
+ INT32 res;
+ INT64 tmp;
+
+ if( SRC_IS_SR )
+ SREG = GET_C;
+
+ tmp = -(INT64)((INT32)(SREG));
+ CHECK_VSUB(SREG,0,tmp);
+
+//#if SETCARRYS
+// CHECK_C(tmp);
+//#endif
+
+ res = -(INT32)(SREG);
+
+ SET_DREG(res);
+
+ SET_Z( res == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(res) );
+
+
+ hyperstone_ICount -= 1;
+
+ if( GET_V && !SRC_IS_SR ) //trap doesn't occur when source is SR
+ {
+ UINT32 addr = get_trap_addr(RANGE_ERROR);
+ execute_exception(addr);
+ }
+}
+
+static void hyperstone_cmpi(void)
+{
+ UINT64 tmp;
+
+ tmp = (UINT64)(DREG) - (UINT64)(EXTRA_U);
+ CHECK_VSUB(EXTRA_U,DREG,tmp);
+
+ if( DREG == EXTRA_U )
+ SET_Z(1);
+ else
+ SET_Z(0);
+
+ if( (INT32) DREG < (INT32) EXTRA_U )
+ SET_N(1);
+ else
+ SET_N(0);
+
+ if( DREG < EXTRA_U )
+ SET_C(1);
+ else
+ SET_C(0);
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_movi(void)
+{
+ if( !GET_S && current_regs.dst >= 16 )
+ {
+ UINT32 addr = get_trap_addr(PRIVILEGE_ERROR);
+ execute_exception(addr);
+ }
+
+ SET_DREG(EXTRA_U);
+
+ if( DST_IS_PC )
+ SET_M(0);
+
+ SET_Z( EXTRA_U == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(EXTRA_U) );
+
+#if MISSIONCRAFT_FLAGS
+ SET_V(0); // or V undefined ?
+#endif
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_addi(void)
+{
+ UINT32 imm;
+ UINT64 tmp;
+
+ if( N_VALUE )
+ imm = EXTRA_U;
+ else
+ imm = GET_C & ((GET_Z == 0 ? 1 : 0) | (DREG & 0x01));
+
+
+ tmp = (UINT64)(imm) + (UINT64)(DREG);
+ CHECK_C(tmp);
+ CHECK_VADD(imm,DREG,tmp);
+
+ DREG = imm + DREG;
+ SET_DREG(DREG);
+
+ if( DST_IS_PC )
+ SET_M(0);
+
+ SET_Z( DREG == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(DREG) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_addsi(void)
+{
+ INT32 imm, res;
+ INT64 tmp;
+
+ if( N_VALUE )
+ imm = EXTRA_S;
+ else
+ imm = GET_C & ((GET_Z == 0 ? 1 : 0) | (DREG & 0x01));
+
+ tmp = (INT64)(imm) + (INT64)((INT32)(DREG));
+ CHECK_VADD(imm,DREG,tmp);
+
+//#if SETCARRYS
+// CHECK_C(tmp);
+//#endif
+
+ res = imm + (INT32)(DREG);
+
+ SET_DREG(res);
+
+ SET_Z( res == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(res) );
+
+ hyperstone_ICount -= 1;
+
+ if( GET_V )
+ {
+ UINT32 addr = get_trap_addr(RANGE_ERROR);
+ execute_exception(addr);
+ }
+}
+
+static void hyperstone_cmpbi(void)
+{
+ UINT32 imm;
+
+ if( N_VALUE )
+ {
+ if( N_VALUE == 31 )
+ {
+ imm = 0x7fffffff; // bit 31 = 0, others = 1
+ }
+ else
+ {
+ imm = EXTRA_U;
+ }
+
+ SET_Z( (DREG & imm) == 0 ? 1 : 0 );
+ }
+ else
+ {
+ if( (DREG & 0xff000000) == 0 || (DREG & 0x00ff0000) == 0 ||
+ (DREG & 0x0000ff00) == 0 || (DREG & 0x000000ff) == 0 )
+ SET_Z(1);
+ else
+ SET_Z(0);
+ }
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_andni(void)
+{
+ UINT32 imm;
+
+ if( N_VALUE == 31 )
+ imm = 0x7fffffff; // bit 31 = 0, others = 1
+ else
+ imm = EXTRA_U;
+
+ DREG = DREG & ~imm;
+
+ SET_DREG(DREG);
+ SET_Z( DREG == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_ori(void)
+{
+ DREG = DREG | EXTRA_U;
+
+ SET_DREG(DREG);
+ SET_Z( DREG == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_xori(void)
+{
+ DREG = DREG ^ EXTRA_U;
+
+ SET_DREG(DREG);
+ SET_Z( DREG == 0 ? 1 : 0 );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_shrdi(void)
+{
+ UINT32 low_order, high_order;
+ UINT64 val;
+
+ high_order = DREG;
+ low_order = DREGF;
+
+ val = COMBINE_U64_U32_U32(high_order, low_order);
+
+ if( N_VALUE )
+ SET_C((val >> (N_VALUE - 1)) & 1);
+ else
+ SET_C(0);
+
+ val >>= N_VALUE;
+
+ high_order = HI32_32_64(val);
+ low_order = LO32_32_64(val);
+
+ SET_DREG(high_order);
+ SET_DREGF(low_order);
+ SET_Z( val == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(high_order) );
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_shrd(void)
+{
+ UINT32 low_order, high_order;
+ UINT64 val;
+ UINT8 n = SREG & 0x1f;
+
+ // result undefined if Ls denotes the same register as Ld or Ldf
+ if( SAME_SRC_DST || SAME_SRC_DSTF )
+ {
+ logerror("Denoted same registers in hyperstone_shrd. PC = %08X\n", PC);
+ }
+ else
+ {
+ high_order = DREG;
+ low_order = DREGF;
+
+ val = COMBINE_U64_U32_U32(high_order, low_order);
+
+ if( n )
+ SET_C((val >> (n - 1)) & 1);
+ else
+ SET_C(0);
+
+ val >>= n;
+
+ high_order = HI32_32_64(val);
+ low_order = LO32_32_64(val);
+
+ SET_DREG(high_order);
+ SET_DREGF(low_order);
+
+ SET_Z( val == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(high_order) );
+ }
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_shr(void)
+{
+ UINT32 ret;
+ UINT8 n;
+
+ n = SREG & 0x1f;
+ ret = DREG;
+
+ if( n )
+ SET_C((ret >> (n - 1)) & 1);
+ else
+ SET_C(0);
+
+ ret >>= n;
+
+ SET_DREG(ret);
+ SET_Z( ret == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(ret) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_sardi(void)
+{
+ UINT32 low_order, high_order;
+ UINT64 val;
+ UINT8 sign_bit;
+
+ high_order = DREG;
+ low_order = DREGF;
+
+ val = COMBINE_64_32_32(high_order, low_order);
+
+ if( N_VALUE )
+ SET_C((val >> (N_VALUE - 1)) & 1);
+ else
+ SET_C(0);
+
+ sign_bit = val >> 63;
+ val >>= N_VALUE;
+
+ if( sign_bit )
+ {
+ int i;
+ for( i = 0; i < N_VALUE; i++ )
+ {
+ val |= (U64(0x8000000000000000) >> i);
+ }
+ }
+
+ high_order = val >> 32;
+ low_order = val & 0xffffffff;
+
+ SET_DREG(high_order);
+ SET_DREGF(low_order);
+
+ SET_Z( val == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(high_order) );
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_sard(void)
+{
+ UINT32 low_order, high_order;
+ UINT64 val;
+ UINT8 n, sign_bit;
+
+ n = SREG & 0x1f;
+
+ // result undefined if Ls denotes the same register as Ld or Ldf
+ if( SAME_SRC_DST || SAME_SRC_DSTF )
+ {
+ logerror("Denoted same registers in hyperstone_sard. PC = %08X\n", PC);
+ }
+ else
+ {
+ high_order = DREG;
+ low_order = DREGF;
+
+ val = COMBINE_64_32_32(high_order, low_order);
+
+ if( n )
+ SET_C((val >> (n - 1)) & 1);
+ else
+ SET_C(0);
+
+ sign_bit = val >> 63;
+
+ val >>= n;
+
+ if( sign_bit )
+ {
+ int i;
+ for( i = 0; i < n; i++ )
+ {
+ val |= (U64(0x8000000000000000) >> i);
+ }
+ }
+
+ high_order = val >> 32;
+ low_order = val & 0xffffffff;
+
+ SET_DREG(high_order);
+ SET_DREGF(low_order);
+ SET_Z( val == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(high_order) );
+ }
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_sar(void)
+{
+ UINT32 ret;
+ UINT8 n, sign_bit;
+
+ n = SREG & 0x1f;
+ ret = DREG;
+ sign_bit = (ret & 0x80000000) >> 31;
+
+ if( n )
+ SET_C((ret >> (n - 1)) & 1);
+ else
+ SET_C(0);
+
+ ret >>= n;
+
+ if( sign_bit )
+ {
+ int i;
+ for( i = 0; i < n; i++ )
+ {
+ ret |= (0x80000000 >> i);
+ }
+ }
+
+ SET_DREG(ret);
+ SET_Z( ret == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(ret) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_shldi(void)
+{
+ UINT32 low_order, high_order, tmp;
+ UINT64 val, mask;
+
+ high_order = DREG;
+ low_order = DREGF;
+
+ val = COMBINE_U64_U32_U32(high_order, low_order);
+ SET_C( (N_VALUE)?(((val<<(N_VALUE-1))&U64(0x8000000000000000))?1:0):0);
+ mask = ((((UINT64)1) << (32 - N_VALUE)) - 1) ^ 0xffffffff;
+ tmp = high_order << N_VALUE;
+
+ if( ((high_order & mask) && (!(tmp & 0x80000000))) ||
+ (((high_order & mask) ^ mask) && (tmp & 0x80000000)) )
+ SET_V(1);
+ else
+ SET_V(0);
+
+ val <<= N_VALUE;
+
+ high_order = HI32_32_64(val);
+ low_order = LO32_32_64(val);
+
+ SET_DREG(high_order);
+ SET_DREGF(low_order);
+
+ SET_Z( val == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(high_order) );
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_shld(void)
+{
+ UINT32 low_order, high_order, tmp, n;
+ UINT64 val, mask;
+
+ n = SREG & 0x1f;
+
+ // result undefined if Ls denotes the same register as Ld or Ldf
+ if( SAME_SRC_DST || SAME_SRC_DSTF )
+ {
+ logerror("Denoted same registers in hyperstone_shld. PC = %08X\n", PC);
+ }
+ else
+ {
+ high_order = DREG;
+ low_order = DREGF;
+
+ mask = ((((UINT64)1) << (32 - n)) - 1) ^ 0xffffffff;
+
+ val = COMBINE_U64_U32_U32(high_order, low_order);
+ SET_C( (n)?(((val<<(n-1))&U64(0x8000000000000000))?1:0):0);
+ tmp = high_order << n;
+
+ if( ((high_order & mask) && (!(tmp & 0x80000000))) ||
+ (((high_order & mask) ^ mask) && (tmp & 0x80000000)) )
+ SET_V(1);
+ else
+ SET_V(0);
+
+ val <<= n;
+
+ high_order = HI32_32_64(val);
+ low_order = LO32_32_64(val);
+
+ SET_DREG(high_order);
+ SET_DREGF(low_order);
+
+ SET_Z( val == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(high_order) );
+ }
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_shl(void)
+{
+ UINT32 base, ret, n;
+ UINT64 mask;
+
+ n = SREG & 0x1f;
+ base = DREG;
+ mask = ((((UINT64)1) << (32 - n)) - 1) ^ 0xffffffff;
+ SET_C( (n)?(((base<<(n-1))&0x80000000)?1:0):0);
+ ret = base << n;
+
+ if( ((base & mask) && (!(ret & 0x80000000))) ||
+ (((base & mask) ^ mask) && (ret & 0x80000000)) )
+ SET_V(1);
+ else
+ SET_V(0);
+
+ SET_DREG(ret);
+ SET_Z( ret == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(ret) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void reserved(void)
+{
+ logerror("Executed Reserved opcode. PC = %08X OP = %04X\n", PC, OP);
+}
+
+static void hyperstone_testlz(void)
+{
+ UINT8 zeros = 0;
+ UINT32 mask;
+
+ for( mask = 0x80000000; ; mask >>= 1 )
+ {
+ if( SREG & mask )
+ break;
+ else
+ zeros++;
+
+ if( zeros == 32 )
+ break;
+ }
+
+ SET_DREG(zeros);
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_rol(void)
+{
+ UINT32 val, base;
+ UINT8 n;
+ UINT64 mask;
+
+ n = SREG & 0x1f;
+
+ val = base = DREG;
+
+ mask = ((((UINT64)1) << (32 - n)) - 1) ^ 0xffffffff;
+
+ while( n > 0 )
+ {
+ val = (val << 1) | ((val & 0x80000000) >> 31);
+ n--;
+ }
+
+#ifdef MISSIONCRAFT_FLAGS
+
+ if( ((base & mask) && (!(val & 0x80000000))) ||
+ (((base & mask) ^ mask) && (val & 0x80000000)) )
+ SET_V(1);
+ else
+ SET_V(0);
+
+#endif
+
+ SET_DREG(val);
+
+ SET_Z( val == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(val) );
+
+ hyperstone_ICount -= 1;
+}
+
+//TODO: add trap error
+static void hyperstone_ldxx1(void)
+{
+ UINT32 load;
+
+ if( DST_IS_SR )
+ {
+ switch( current_regs.sub_type )
+ {
+ case 0: // LDBS.A
+
+ load = READ_B(EXTRA_S);
+ load |= (load & 0x80) ? 0xffffff00 : 0;
+ SET_SREG(load);
+
+ break;
+
+ case 1: // LDBU.A
+
+ load = READ_B(EXTRA_S);
+ SET_SREG(load);
+
+ break;
+
+ case 2:
+
+ load = READ_HW(EXTRA_S & ~1);
+
+ if( EXTRA_S & 1 ) // LDHS.A
+ {
+ load |= (load & 0x8000) ? 0xffff0000 : 0;
+ }
+ /*
+ else // LDHU.A
+ {
+ // nothing more
+ }
+ */
+
+ SET_SREG(load);
+
+ break;
+
+ case 3:
+
+ if( (EXTRA_S & 3) == 3 ) // LDD.IOA
+ {
+ load = IO_READ_W(EXTRA_S & ~3);
+ SET_SREG(load);
+
+ load = IO_READ_W((EXTRA_S & ~3) + 4);
+ SET_SREGF(load);
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else if( (EXTRA_S & 3) == 2 ) // LDW.IOA
+ {
+ load = IO_READ_W(EXTRA_S & ~3);
+ SET_SREG(load);
+ }
+ else if( (EXTRA_S & 3) == 1 ) // LDD.A
+ {
+ load = READ_W(EXTRA_S & ~1);
+ SET_SREG(load);
+
+ load = READ_W((EXTRA_S & ~1) + 4);
+ SET_SREGF(load);
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else // LDW.A
+ {
+ load = READ_W(EXTRA_S & ~1);
+ SET_SREG(load);
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ switch( current_regs.sub_type )
+ {
+ case 0: // LDBS.D
+
+ load = READ_B(DREG + EXTRA_S);
+ load |= (load & 0x80) ? 0xffffff00 : 0;
+ SET_SREG(load);
+
+ break;
+
+ case 1: // LDBU.D
+
+ load = READ_B(DREG + EXTRA_S);
+ SET_SREG(load);
+
+ break;
+
+ case 2:
+
+ load = READ_HW(DREG + (EXTRA_S & ~1));
+
+ if( EXTRA_S & 1 ) // LDHS.D
+ {
+ load |= (load & 0x8000) ? 0xffff0000 : 0;
+ }
+ /*
+ else // LDHU.D
+ {
+ // nothing more
+ }
+ */
+
+ SET_SREG(load);
+
+ break;
+
+ case 3:
+
+ if( (EXTRA_S & 3) == 3 ) // LDD.IOD
+ {
+ load = IO_READ_W(DREG + (EXTRA_S & ~3));
+ SET_SREG(load);
+
+ load = IO_READ_W(DREG + (EXTRA_S & ~3) + 4);
+ SET_SREGF(load);
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else if( (EXTRA_S & 3) == 2 ) // LDW.IOD
+ {
+ load = IO_READ_W(DREG + (EXTRA_S & ~3));
+ SET_SREG(load);
+ }
+ else if( (EXTRA_S & 3) == 1 ) // LDD.D
+ {
+ load = READ_W(DREG + (EXTRA_S & ~1));
+ SET_SREG(load);
+
+ load = READ_W(DREG + (EXTRA_S & ~1) + 4);
+ SET_SREGF(load);
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else // LDW.D
+ {
+ load = READ_W(DREG + (EXTRA_S & ~1));
+ SET_SREG(load);
+ }
+
+ break;
+ }
+ }
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_ldxx2(void)
+{
+ UINT32 load;
+
+ if( DST_IS_PC || DST_IS_SR )
+ {
+ logerror("Denoted PC or SR in hyperstone_ldxx2. PC = %08X\n", PC);
+ }
+ else
+ {
+ switch( current_regs.sub_type )
+ {
+ case 0: // LDBS.N
+
+ if(SAME_SRC_DST)
+ popmessage("LDBS.N denoted same regs @ %08X",PPC);
+
+ load = READ_B(DREG);
+ load |= (load & 0x80) ? 0xffffff00 : 0;
+ SET_SREG(load);
+
+ if(!SAME_SRC_DST)
+ SET_DREG(DREG + EXTRA_S);
+
+ break;
+
+ case 1: // LDBU.N
+
+ if(SAME_SRC_DST)
+ popmessage("LDBU.N denoted same regs @ %08X",PPC);
+
+ load = READ_B(DREG);
+ SET_SREG(load);
+
+ if(!SAME_SRC_DST)
+ SET_DREG(DREG + EXTRA_S);
+
+ break;
+
+ case 2:
+
+ load = READ_HW(DREG);
+
+ if( EXTRA_S & 1 ) // LDHS.N
+ {
+ load |= (load & 0x8000) ? 0xffff0000 : 0;
+
+ if(SAME_SRC_DST)
+ popmessage("LDHS.N denoted same regs @ %08X",PPC);
+ }
+ /*
+ else // LDHU.N
+ {
+ // nothing more
+ }
+ */
+
+ SET_SREG(load);
+
+ if(!SAME_SRC_DST)
+ SET_DREG(DREG + (EXTRA_S & ~1));
+
+ break;
+
+ case 3:
+
+ if( (EXTRA_S & 3) == 3 ) // LDW.S
+ {
+ if(SAME_SRC_DST)
+ popmessage("LDW.S denoted same regs @ %08X",PPC);
+
+ if(DREG < SP)
+ SET_SREG(READ_W(DREG));
+ else
+ SET_SREG(GET_ABS_L_REG((DREG & 0xfc) >> 2));
+
+ if(!SAME_SRC_DST)
+ SET_DREG(DREG + (EXTRA_S & ~3));
+
+ hyperstone_ICount -= 2; // extra cycles
+ }
+ else if( (EXTRA_S & 3) == 2 ) // Reserved
+ {
+ logerror("Executed Reserved instruction in hyperstone_ldxx2. PC = %08X\n", PC);
+ }
+ else if( (EXTRA_S & 3) == 1 ) // LDD.N
+ {
+ if(SAME_SRC_DST || SAME_SRCF_DST)
+ popmessage("LDD.N denoted same regs @ %08X",PPC);
+
+ load = READ_W(DREG);
+ SET_SREG(load);
+
+ load = READ_W(DREG + 4);
+ SET_SREGF(load);
+
+ if(!SAME_SRC_DST && !SAME_SRCF_DST)
+ SET_DREG(DREG + (EXTRA_S & ~1));
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else // LDW.N
+ {
+ if(SAME_SRC_DST)
+ popmessage("LDW.N denoted same regs @ %08X",PPC);
+
+ load = READ_W(DREG);
+ SET_SREG(load);
+
+ if(!SAME_SRC_DST)
+ SET_DREG(DREG + (EXTRA_S & ~1));
+ }
+
+ break;
+ }
+ }
+
+ hyperstone_ICount -= 1;
+}
+
+//TODO: add trap error
+static void hyperstone_stxx1(void)
+{
+ if( SRC_IS_SR )
+ SREG = SREGF = 0;
+
+ if( DST_IS_SR )
+ {
+ switch( current_regs.sub_type )
+ {
+ case 0: // STBS.A
+
+ /* TODO: missing trap on range error */
+ WRITE_B(EXTRA_S, SREG & 0xff);
+
+ break;
+
+ case 1: // STBU.A
+
+ WRITE_B(EXTRA_S, SREG & 0xff);
+
+ break;
+
+ case 2:
+
+ WRITE_HW(EXTRA_S & ~1, SREG & 0xffff);
+
+ /*
+ if( EXTRA_S & 1 ) // STHS.A
+ {
+ // TODO: missing trap on range error
+ }
+ else // STHU.A
+ {
+ // nothing more
+ }
+ */
+
+ break;
+
+ case 3:
+
+ if( (EXTRA_S & 3) == 3 ) // STD.IOA
+ {
+ IO_WRITE_W(EXTRA_S & ~3, SREG);
+ IO_WRITE_W((EXTRA_S & ~3) + 4, SREGF);
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else if( (EXTRA_S & 3) == 2 ) // STW.IOA
+ {
+ IO_WRITE_W(EXTRA_S & ~3, SREG);
+ }
+ else if( (EXTRA_S & 3) == 1 ) // STD.A
+ {
+ WRITE_W(EXTRA_S & ~1, SREG);
+ WRITE_W((EXTRA_S & ~1) + 4, SREGF);
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else // STW.A
+ {
+ WRITE_W(EXTRA_S & ~1, SREG);
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ switch( current_regs.sub_type )
+ {
+ case 0: // STBS.D
+
+ /* TODO: missing trap on range error */
+ WRITE_B(DREG + EXTRA_S, SREG & 0xff);
+
+ break;
+
+ case 1: // STBU.D
+
+ WRITE_B(DREG + EXTRA_S, SREG & 0xff);
+
+ break;
+
+ case 2:
+
+ WRITE_HW(DREG + (EXTRA_S & ~1), SREG & 0xffff);
+
+ /*
+ if( EXTRA_S & 1 ) // STHS.D
+ {
+ // TODO: missing trap on range error
+ }
+ else // STHU.D
+ {
+ // nothing more
+ }
+ */
+
+ break;
+
+ case 3:
+
+ if( (EXTRA_S & 3) == 3 ) // STD.IOD
+ {
+ IO_WRITE_W(DREG + (EXTRA_S & ~3), SREG);
+ IO_WRITE_W(DREG + (EXTRA_S & ~3) + 4, SREGF);
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else if( (EXTRA_S & 3) == 2 ) // STW.IOD
+ {
+ IO_WRITE_W(DREG + (EXTRA_S & ~3), SREG);
+ }
+ else if( (EXTRA_S & 3) == 1 ) // STD.D
+ {
+ WRITE_W(DREG + (EXTRA_S & ~1), SREG);
+ WRITE_W(DREG + (EXTRA_S & ~1) + 4, SREGF);
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else // STW.D
+ {
+ WRITE_W(DREG + (EXTRA_S & ~1), SREG);
+ }
+
+ break;
+ }
+ }
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_stxx2(void)
+{
+ if( SRC_IS_SR )
+ SREG = SREGF = 0;
+
+ if( DST_IS_PC || DST_IS_SR )
+ {
+ logerror("Denoted PC or SR in hyperstone_stxx2. PC = %08X\n", PC);
+ }
+ else
+ {
+ switch( current_regs.sub_type )
+ {
+ case 0: // STBS.N
+
+ /* TODO: missing trap on range error */
+ WRITE_B(DREG, SREG & 0xff);
+ SET_DREG(DREG + EXTRA_S);
+
+ break;
+
+ case 1: // STBU.N
+
+ WRITE_B(DREG, SREG & 0xff);
+ SET_DREG(DREG + EXTRA_S);
+
+ break;
+
+ case 2:
+
+ WRITE_HW(DREG, SREG & 0xffff);
+ SET_DREG(DREG + (EXTRA_S & ~1));
+
+ /*
+ if( EXTRA_S & 1 ) // STHS.N
+ {
+ // TODO: missing trap on range error
+ }
+ else // STHU.N
+ {
+ // nothing more
+ }
+ */
+
+ break;
+
+ case 3:
+
+ if( (EXTRA_S & 3) == 3 ) // STW.S
+ {
+ if(DREG < SP)
+ WRITE_W(DREG, SREG);
+ else
+ {
+ if(((DREG & 0xfc) >> 2) == ((current_regs.src + GET_FP) % 64) && S_BIT == LOCAL)
+ popmessage("STW.S denoted the same local register @ %08X\n",PPC);
+
+ SET_ABS_L_REG((DREG & 0xfc) >> 2,SREG);
+ }
+
+ SET_DREG(DREG + (EXTRA_S & ~3));
+
+ hyperstone_ICount -= 2; // extra cycles
+
+ }
+ else if( (EXTRA_S & 3) == 2 ) // Reserved
+ {
+ logerror("Executed Reserved instruction in hyperstone_stxx2. PC = %08X\n", PC);
+ }
+ else if( (EXTRA_S & 3) == 1 ) // STD.N
+ {
+ WRITE_W(DREG, SREG);
+ SET_DREG(DREG + (EXTRA_S & ~1));
+
+ if( SAME_SRCF_DST )
+ WRITE_W(DREG + 4, SREGF + (EXTRA_S & ~1)); // because DREG == SREGF and DREG has been incremented
+ else
+ WRITE_W(DREG + 4, SREGF);
+
+ hyperstone_ICount -= 1; // extra cycle
+ }
+ else // STW.N
+ {
+ WRITE_W(DREG, SREG);
+ SET_DREG(DREG + (EXTRA_S & ~1));
+ }
+
+ break;
+ }
+ }
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_shri(void)
+{
+ UINT32 val;
+
+ val = DREG;
+
+ if( N_VALUE )
+ SET_C((val >> (N_VALUE - 1)) & 1);
+ else
+ SET_C(0);
+
+ val >>= N_VALUE;
+
+ SET_DREG(val);
+ SET_Z( val == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(val) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_sari(void)
+{
+ UINT32 val;
+ UINT8 sign_bit;
+
+ val = DREG;
+ sign_bit = (val & 0x80000000) >> 31;
+
+ if( N_VALUE )
+ SET_C((val >> (N_VALUE - 1)) & 1);
+ else
+ SET_C(0);
+
+ val >>= N_VALUE;
+
+ if( sign_bit )
+ {
+ int i;
+ for( i = 0; i < N_VALUE; i++ )
+ {
+ val |= (0x80000000 >> i);
+ }
+ }
+
+ SET_DREG(val);
+ SET_Z( val == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(val) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_shli(void)
+{
+ UINT32 val, val2;
+ UINT64 mask;
+
+ val = DREG;
+ SET_C( (N_VALUE)?(((val<<(N_VALUE-1))&0x80000000)?1:0):0);
+ mask = ((((UINT64)1) << (32 - N_VALUE)) - 1) ^ 0xffffffff;
+ val2 = val << N_VALUE;
+
+ if( ((val & mask) && (!(val2 & 0x80000000))) ||
+ (((val & mask) ^ mask) && (val2 & 0x80000000)) )
+ SET_V(1);
+ else
+ SET_V(0);
+
+ SET_DREG(val2);
+ SET_Z( val2 == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(val2) );
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_mulu(void)
+{
+ UINT32 low_order, high_order;
+ UINT64 double_word;
+
+ // PC or SR aren't denoted, else result is undefined
+ if( SRC_IS_PC || SRC_IS_SR || DST_IS_PC || DST_IS_SR )
+ {
+ logerror("Denoted PC or SR in hyperstone_mulu instruction. PC = %08X\n", PC);
+ }
+ else
+ {
+ double_word = (UINT64)SREG *(UINT64)DREG;
+
+ low_order = double_word & 0xffffffff;
+ high_order = double_word >> 32;
+
+ SET_DREG(high_order);
+ SET_DREGF(low_order);
+
+ SET_Z( double_word == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(high_order) );
+ }
+
+ if(SREG <= 0xffff && DREG <= 0xffff)
+ hyperstone_ICount -= 4;
+ else
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_muls(void)
+{
+ UINT32 low_order, high_order;
+ INT64 double_word;
+
+ // PC or SR aren't denoted, else result is undefined
+ if( SRC_IS_PC || SRC_IS_SR || DST_IS_PC || DST_IS_SR )
+ {
+ logerror("Denoted PC or SR in hyperstone_muls instruction. PC = %08X\n", PC);
+ }
+ else
+ {
+ double_word = (INT64)(INT32)(SREG) * (INT64)(INT32)(DREG);
+ low_order = double_word & 0xffffffff;
+ high_order = double_word >> 32;
+
+ SET_DREG(high_order);
+ SET_DREGF(low_order);
+
+ SET_Z( double_word == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(high_order) );
+ }
+
+ if((SREG >= 0xffff8000 && SREG <= 0x7fff) && (DREG >= 0xffff8000 && DREG <= 0x7fff))
+ hyperstone_ICount -= 4;
+ else
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_set(void)
+{
+ int n = N_VALUE;
+
+ if( DST_IS_PC )
+ {
+ logerror("Denoted PC in hyperstone_set. PC = %08X\n", PC);
+ }
+ else if( DST_IS_SR )
+ {
+ //TODO: add fetch opcode when there's the pipeline
+
+ //TODO: no 1!
+ hyperstone_ICount -= 1;
+ }
+ else
+ {
+ switch( n )
+ {
+ // SETADR
+ case 0:
+ {
+ UINT32 val;
+ val = (SP & 0xfffffe00) | (GET_FP << 2);
+
+ //plus carry into bit 9
+ val += (( (SP & 0x100) && (SIGN_BIT(SR) == 0) ) ? 1 : 0);
+
+ SET_DREG(val);
+
+ break;
+ }
+ // Reserved
+ case 1:
+ case 16:
+ case 17:
+ case 19:
+ logerror("Used reserved N value (%d) in hyperstone_set. PC = %08X\n", n, PC);
+ break;
+
+ // SETxx
+ case 2:
+ SET_DREG(1);
+ break;
+
+ case 3:
+ SET_DREG(0);
+ break;
+
+ case 4:
+ if( GET_N || GET_Z )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 5:
+ if( !GET_N && !GET_Z )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 6:
+ if( GET_N )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 7:
+ if( !GET_N )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 8:
+ if( GET_C || GET_Z )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 9:
+ if( !GET_C && !GET_Z )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 10:
+ if( GET_C )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 11:
+ if( !GET_C )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 12:
+ if( GET_Z )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 13:
+ if( !GET_Z )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 14:
+ if( GET_V )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 15:
+ if( !GET_V )
+ {
+ SET_DREG(1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 18:
+ SET_DREG(-1);
+ break;
+
+ case 20:
+ if( GET_N || GET_Z )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 21:
+ if( !GET_N && !GET_Z )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 22:
+ if( GET_N )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 23:
+ if( !GET_N )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 24:
+ if( GET_C || GET_Z )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 25:
+ if( !GET_C && !GET_Z )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 26:
+ if( GET_C )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 27:
+ if( !GET_C )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 28:
+ if( GET_Z )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 29:
+ if( !GET_Z )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 30:
+ if( GET_V )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+
+ case 31:
+ if( !GET_V )
+ {
+ SET_DREG(-1);
+ }
+ else
+ {
+ SET_DREG(0);
+ }
+
+ break;
+ }
+
+ hyperstone_ICount -= 1;
+ }
+}
+
+static void hyperstone_mul(void)
+{
+ UINT32 single_word;
+
+ // PC or SR aren't denoted, else result is undefined
+ if( SRC_IS_PC || SRC_IS_SR || DST_IS_PC || DST_IS_SR )
+ {
+ logerror("Denoted PC or SR in hyperstone_mul instruction. PC = %08X\n", PC);
+ }
+ else
+ {
+ single_word = (SREG * DREG);// & 0xffffffff; // only the low-order word is taken
+
+ SET_DREG(single_word);
+
+ SET_Z( single_word == 0 ? 1 : 0 );
+ SET_N( SIGN_BIT(single_word) );
+ }
+
+ if((SREG >= 0xffff8000 && SREG <= 0x7fff) && (DREG >= 0xffff8000 && DREG <= 0x7fff))
+ hyperstone_ICount -= 3;
+ else
+ hyperstone_ICount -= 5;
+}
+
+static void hyperstone_fadd(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_faddd(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fsub(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fsubd(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fmul(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fmuld(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fdiv(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fdivd(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fcmp(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fcmpd(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fcmpu(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fcmpud(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fcvt(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_fcvtd(void)
+{
+ execute_software();
+ hyperstone_ICount -= 6;
+}
+
+static void hyperstone_extend(void)
+{
+ //TODO: add locks, overflow error and other things
+ UINT32 vals, vald;
+
+ vals = SREG;
+ vald = DREG;
+
+ switch( EXTRA_U ) // extended opcode
+ {
+ // signed or unsigned multiplication, single word product
+ case EMUL:
+ case 0x100: // used in "N" type cpu
+ {
+ UINT32 result;
+
+ result = vals * vald;
+ SET_G_REG(15, result);
+
+ break;
+ }
+ // unsigned multiplication, double word product
+ case EMULU:
+ {
+ UINT64 result;
+
+ result = (UINT64)vals * (UINT64)vald;
+ vals = result >> 32;
+ vald = result & 0xffffffff;
+ SET_G_REG(14, vals);
+ SET_G_REG(15, vald);
+
+ break;
+ }
+ // signed multiplication, double word product
+ case EMULS:
+ {
+ INT64 result;
+
+ result = (INT64)(INT32)(vals) * (INT64)(INT32)(vald);
+ vals = result >> 32;
+ vald = result & 0xffffffff;
+ SET_G_REG(14, vals);
+ SET_G_REG(15, vald);
+
+ break;
+ }
+ // signed multiply/add, single word product sum
+ case EMAC:
+ {
+ INT32 result;
+
+ result = (INT32)GET_G_REG(15) + ((INT32)(vals) * (INT32)(vald));
+ SET_G_REG(15, result);
+
+ break;
+ }
+ // signed multiply/add, double word product sum
+ case EMACD:
+ {
+ INT64 result;
+
+ result = (INT64)COMBINE_64_32_32(GET_G_REG(14), GET_G_REG(15)) + (INT64)((INT64)(INT32)(vals) * (INT64)(INT32)(vald));
+
+ vals = result >> 32;
+ vald = result & 0xffffffff;
+ SET_G_REG(14, vals);
+ SET_G_REG(15, vald);
+
+ break;
+ }
+ // signed multiply/substract, single word product difference
+ case EMSUB:
+ {
+ INT32 result;
+
+ result = (INT32)GET_G_REG(15) - ((INT32)(vals) * (INT32)(vald));
+ SET_G_REG(15, result);
+
+ break;
+ }
+ // signed multiply/substract, double word product difference
+ case EMSUBD:
+ {
+ INT64 result;
+
+ result = (INT64)COMBINE_64_32_32(GET_G_REG(14), GET_G_REG(15)) - (INT64)((INT64)(INT32)(vals) * (INT64)(INT32)(vald));
+
+ vals = result >> 32;
+ vald = result & 0xffffffff;
+ SET_G_REG(14, vals);
+ SET_G_REG(15, vald);
+
+ break;
+ }
+ // signed half-word multiply/add, single word product sum
+ case EHMAC:
+ {
+ INT32 result;
+
+ result = (INT32)GET_G_REG(15) + ((INT32)((vald & 0xffff0000) >> 16) * (INT32)((vals & 0xffff0000) >> 16)) + ((INT32)(vald & 0xffff) * (INT32)(vals & 0xffff));
+ SET_G_REG(15, result);
+
+ break;
+ }
+ // signed half-word multiply/add, double word product sum
+ case EHMACD:
+ {
+ INT64 result;
+
+ result = (INT64)COMBINE_64_32_32(GET_G_REG(14), GET_G_REG(15)) + (INT64)((INT64)(INT32)((vald & 0xffff0000) >> 16) * (INT64)(INT32)((vals & 0xffff0000) >> 16)) + ((INT64)(INT32)(vald & 0xffff) * (INT64)(INT32)(vals & 0xffff));
+
+ vals = result >> 32;
+ vald = result & 0xffffffff;
+ SET_G_REG(14, vals);
+ SET_G_REG(15, vald);
+
+ break;
+ }
+ // half-word complex multiply
+ case EHCMULD:
+ {
+ UINT32 result;
+
+ result = (((vald & 0xffff0000) >> 16) * ((vals & 0xffff0000) >> 16)) - ((vald & 0xffff) * (vals & 0xffff));
+ SET_G_REG(14, result);
+
+ result = (((vald & 0xffff0000) >> 16) * (vals & 0xffff)) + ((vald & 0xffff) * ((vals & 0xffff0000) >> 16));
+ SET_G_REG(15, result);
+
+ break;
+ }
+ // half-word complex multiply/add
+ case EHCMACD:
+ {
+ UINT32 result;
+
+ result = GET_G_REG(14) + (((vald & 0xffff0000) >> 16) * ((vals & 0xffff0000) >> 16)) - ((vald & 0xffff) * (vals & 0xffff));
+ SET_G_REG(14, result);
+
+ result = GET_G_REG(15) + (((vald & 0xffff0000) >> 16) * (vals & 0xffff)) + ((vald & 0xffff) * ((vals & 0xffff0000) >> 16));
+ SET_G_REG(15, result);
+
+ break;
+ }
+ // half-word (complex) add/substract
+ // Ls is not used and should denote the same register as Ld
+ case EHCSUMD:
+ {
+ UINT32 result;
+
+ result = ((((vals & 0xffff0000) >> 16) + GET_G_REG(14)) << 16) & 0xffff0000;
+ result |= ((vals & 0xffff) + GET_G_REG(15)) & 0xffff;
+ SET_G_REG(14, result);
+
+ result = ((((vals & 0xffff0000) >> 16) - GET_G_REG(14)) << 16) & 0xffff0000;
+ result |= ((vals & 0xffff) - GET_G_REG(15)) & 0xffff;
+ SET_G_REG(15, result);
+
+ break;
+ }
+ // half-word (complex) add/substract with fixed point adjustment
+ // Ls is not used and should denote the same register as Ld
+ case EHCFFTD:
+ {
+ UINT32 result;
+
+ result = ((((vals & 0xffff0000) >> 16) + (GET_G_REG(14) >> 15)) << 16) & 0xffff0000;
+ result |= ((vals & 0xffff) + (GET_G_REG(15) >> 15)) & 0xffff;
+ SET_G_REG(14, result);
+
+ result = ((((vals & 0xffff0000) >> 16) - (GET_G_REG(14) >> 15)) << 16) & 0xffff0000;
+ result |= ((vals & 0xffff) - (GET_G_REG(15) >> 15)) & 0xffff;
+ SET_G_REG(15, result);
+
+ break;
+ }
+ // half-word (complex) add/substract with fixed point adjustment and shift
+ // Ls is not used and should denote the same register as Ld
+ case EHCFFTSD:
+ {
+ UINT32 result;
+
+ result = (((((vals & 0xffff0000) >> 16) + (GET_G_REG(14) >> 15)) >> 1) << 16) & 0xffff0000;
+ result |= ((((vals & 0xffff) + (GET_G_REG(15) >> 15)) >> 1) & 0xffff);
+ SET_G_REG(14, result);
+
+ result = (((((vals & 0xffff0000) >> 16) - (GET_G_REG(14) >> 15)) >> 1) << 16) & 0xffff0000;
+ result |= ((((vals & 0xffff) - (GET_G_REG(15) >> 15)) >> 1) & 0xffff);
+ SET_G_REG(15, result);
+
+ break;
+ }
+ default:
+ logerror("Executed Illegal extended opcode (%X). PC = %08X\n", EXTRA_U, PC);
+ break;
+ }
+
+ hyperstone_ICount -= 1; //TODO: with the latency it can change
+}
+
+static void hyperstone_do(void)
+{
+ fatalerror("Executed hyperstone_do instruction. PC = %08X", PPC);
+}
+
+static void hyperstone_ldwr(void)
+{
+ SET_SREG(READ_W(DREG));
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_lddr(void)
+{
+ SET_SREG(READ_W(DREG));
+ SET_SREGF(READ_W(DREG + 4));
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_ldwp(void)
+{
+ SET_SREG(READ_W(DREG));
+
+ // post increment the destination register if it's different from the source one
+ // (needed by Hidden Catch)
+ if(!(current_regs.src == current_regs.dst && S_BIT == LOCAL))
+ SET_DREG(DREG + 4);
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_lddp(void)
+{
+ SET_SREG(READ_W(DREG));
+ SET_SREGF(READ_W(DREG + 4));
+
+ // post increment the destination register if it's different from the source one
+ // and from the "next source" one
+ if(!(current_regs.src == current_regs.dst && S_BIT == LOCAL) && !SAME_SRCF_DST )
+ {
+ SET_DREG(DREG + 8);
+ }
+ else
+ {
+ popmessage("LDD.P denoted same regs @ %08X",PPC);
+ }
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_stwr(void)
+{
+ if( SRC_IS_SR )
+ SREG = 0;
+
+ WRITE_W(DREG, SREG);
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_stdr(void)
+{
+ if( SRC_IS_SR )
+ SREG = SREGF = 0;
+
+ WRITE_W(DREG, SREG);
+ WRITE_W(DREG + 4, SREGF);
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_stwp(void)
+{
+ if( SRC_IS_SR )
+ SREG = 0;
+
+ WRITE_W(DREG, SREG);
+ SET_DREG(DREG + 4);
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_stdp(void)
+{
+ if( SRC_IS_SR )
+ SREG = SREGF = 0;
+
+ WRITE_W(DREG, SREG);
+ SET_DREG(DREG + 8);
+
+ if( SAME_SRCF_DST )
+ WRITE_W(DREG + 4, SREGF + 8); // because DREG == SREGF and DREG has been incremented
+ else
+ WRITE_W(DREG + 4, SREGF);
+
+ hyperstone_ICount -= 2;
+}
+
+static void hyperstone_dbv(void)
+{
+ if( GET_V )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbnv(void)
+{
+ if( !GET_V )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbe(void) //or DBZ
+{
+ if( GET_Z )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbne(void) //or DBNZ
+{
+ if( !GET_Z )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbc(void) //or DBST
+{
+ if( GET_C )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbnc(void) //or DBHE
+{
+ if( !GET_C )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbse(void)
+{
+ if( GET_C || GET_Z )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbht(void)
+{
+ if( !GET_C && !GET_Z )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbn(void) //or DBLT
+{
+ if( GET_N )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbnn(void) //or DBGE
+{
+ if( !GET_N )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dble(void)
+{
+ if( GET_N || GET_Z )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbgt(void)
+{
+ if( !GET_N && !GET_Z )
+ execute_dbr();
+
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_dbr(void)
+{
+ execute_dbr();
+}
+
+static void hyperstone_frame(void)
+{
+ INT8 difference; // really it's 7 bits
+ UINT8 realfp = GET_FP - SRC_CODE;
+
+ SET_FP(realfp);
+ SET_FL(DST_CODE);
+ SET_M(0);
+
+ difference = ((SP & 0x1fc) >> 2) + (64 - 10) - (realfp + GET_FL);
+
+ /* convert to 8 bits */
+ if(difference > 63)
+ difference = (INT8)(difference|0x80);
+ else if( difference < -64 )
+ difference = difference & 0x7f;
+
+ if( difference < 0 ) // else it's finished
+ {
+ UINT8 tmp_flag;
+
+ tmp_flag = ( SP >= UB ? 1 : 0 );
+
+ do
+ {
+ WRITE_W(SP, GET_ABS_L_REG((SP & 0xfc) >> 2));
+ SP += 4;
+ difference++;
+
+ } while(difference != 0);
+
+ if( tmp_flag )
+ {
+ UINT32 addr = get_trap_addr(FRAME_ERROR);
+ execute_exception(addr);
+ }
+ }
+
+ //TODO: no 1!
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_call(void)
+{
+ if( SRC_IS_SR )
+ SREG = 0;
+
+ if( !DST_CODE )
+ current_regs.dst = 16;
+
+ EXTRA_S = (EXTRA_S & ~1) + SREG;
+
+ SET_ILC(hyperstone.instruction_length & 3);
+
+ SET_DREG((PC & 0xfffffffe) | GET_S);
+ SET_DREGF(SR);
+
+ SET_FP(GET_FP + current_regs.dst);
+
+ SET_FL(6); //default value for call
+ SET_M(0);
+
+ PPC = PC;
+ PC = EXTRA_S; // const value
+ change_pc(PC);
+
+ hyperstone.intblock = 2;
+
+ //TODO: add interrupt locks, errors, ....
+
+ //TODO: no 1!
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bv(void)
+{
+ if( GET_V )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bnv(void)
+{
+ if( !GET_V )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_be(void) //or BZ
+{
+ if( GET_Z )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bne(void) //or BNZ
+{
+ if( !GET_Z )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bc(void) //or BST
+{
+ if( GET_C )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bnc(void) //or BHE
+{
+ if( !GET_C )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bse(void)
+{
+ if( GET_C || GET_Z )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bht(void)
+{
+ if( !GET_C && !GET_Z )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bn(void) //or BLT
+{
+ if( GET_N )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bnn(void) //or BGE
+{
+ if( !GET_N )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_ble(void)
+{
+ if( GET_N || GET_Z )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_bgt(void)
+{
+ if( !GET_N && !GET_Z )
+ execute_br();
+ else
+ hyperstone_ICount -= 1;
+}
+
+static void hyperstone_br(void)
+{
+ execute_br();
+}
+
+static void hyperstone_trap(void)
+{
+ UINT8 code, trapno;
+ UINT32 addr;
+
+ trapno = (OP & 0xfc) >> 2;
+
+ addr = get_trap_addr(trapno);
+ code = ((OP & 0x300) >> 6) | (OP & 0x03);
+
+ switch( code )
+ {
+ case TRAPLE:
+ if( GET_N || GET_Z )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPGT:
+ if( !GET_N && !GET_Z )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPLT:
+ if( GET_N )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPGE:
+ if( !GET_N )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPSE:
+ if( GET_C || GET_Z )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPHT:
+ if( !GET_C && !GET_Z )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPST:
+ if( GET_C )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPHE:
+ if( !GET_C )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPE:
+ if( GET_Z )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPNE:
+ if( !GET_Z )
+ execute_trap(addr);
+
+ break;
+
+ case TRAPV:
+ if( GET_V )
+ execute_trap(addr);
+
+ break;
+
+ case TRAP:
+ execute_trap(addr);
+
+ break;
+ }
+
+ hyperstone_ICount -= 1;
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void hyperstone_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + E132XS_PC: PC = info->i; change_pc(PC); break;
+ case CPUINFO_INT_REGISTER + E132XS_SR: SR = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_FER: FER = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G3: hyperstone.global_regs[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G4: hyperstone.global_regs[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G5: hyperstone.global_regs[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G6: hyperstone.global_regs[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G7: hyperstone.global_regs[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G8: hyperstone.global_regs[8] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G9: hyperstone.global_regs[9] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G10: hyperstone.global_regs[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G11: hyperstone.global_regs[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G12: hyperstone.global_regs[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G13: hyperstone.global_regs[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G14: hyperstone.global_regs[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G15: hyperstone.global_regs[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G16: hyperstone.global_regs[16] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G17: hyperstone.global_regs[17] = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + E132XS_SP: SP = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_UB: UB = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_BCR: BCR = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_TPR: TPR = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_TCR: TCR = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_TR: TR = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_WCR: WCR = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_ISR: ISR = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_FCR: FCR = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_MCR: MCR = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G28: hyperstone.global_regs[28] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G29: hyperstone.global_regs[29] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G30: hyperstone.global_regs[30] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_G31: hyperstone.global_regs[31] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL0: hyperstone.local_regs[(0 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL1: hyperstone.local_regs[(1 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL2: hyperstone.local_regs[(2 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL3: hyperstone.local_regs[(3 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL4: hyperstone.local_regs[(4 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL5: hyperstone.local_regs[(5 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL6: hyperstone.local_regs[(6 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL7: hyperstone.local_regs[(7 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL8: hyperstone.local_regs[(8 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL9: hyperstone.local_regs[(9 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL10: hyperstone.local_regs[(10 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL11: hyperstone.local_regs[(11 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL12: hyperstone.local_regs[(12 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL13: hyperstone.local_regs[(13 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL14: hyperstone.local_regs[(14 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL15: hyperstone.local_regs[(15 + GET_FP) % 64] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L0: hyperstone.local_regs[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L1: hyperstone.local_regs[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L2: hyperstone.local_regs[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L3: hyperstone.local_regs[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L4: hyperstone.local_regs[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L5: hyperstone.local_regs[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L6: hyperstone.local_regs[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L7: hyperstone.local_regs[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L8: hyperstone.local_regs[8] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L9: hyperstone.local_regs[9] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L10: hyperstone.local_regs[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L11: hyperstone.local_regs[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L12: hyperstone.local_regs[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L13: hyperstone.local_regs[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L14: hyperstone.local_regs[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L15: hyperstone.local_regs[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L16: hyperstone.local_regs[16] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L17: hyperstone.local_regs[17] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L18: hyperstone.local_regs[18] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L19: hyperstone.local_regs[19] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L20: hyperstone.local_regs[20] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L21: hyperstone.local_regs[21] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L22: hyperstone.local_regs[22] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L23: hyperstone.local_regs[23] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L24: hyperstone.local_regs[24] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L25: hyperstone.local_regs[25] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L26: hyperstone.local_regs[26] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L27: hyperstone.local_regs[27] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L28: hyperstone.local_regs[28] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L29: hyperstone.local_regs[29] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L30: hyperstone.local_regs[30] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L31: hyperstone.local_regs[31] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L32: hyperstone.local_regs[32] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L33: hyperstone.local_regs[33] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L34: hyperstone.local_regs[34] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L35: hyperstone.local_regs[35] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L36: hyperstone.local_regs[36] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L37: hyperstone.local_regs[37] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L38: hyperstone.local_regs[38] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L39: hyperstone.local_regs[39] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L40: hyperstone.local_regs[40] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L41: hyperstone.local_regs[41] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L42: hyperstone.local_regs[42] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L43: hyperstone.local_regs[43] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L44: hyperstone.local_regs[44] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L45: hyperstone.local_regs[45] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L46: hyperstone.local_regs[46] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L47: hyperstone.local_regs[47] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L48: hyperstone.local_regs[48] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L49: hyperstone.local_regs[49] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L50: hyperstone.local_regs[50] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L51: hyperstone.local_regs[51] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L52: hyperstone.local_regs[52] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L53: hyperstone.local_regs[53] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L54: hyperstone.local_regs[54] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L55: hyperstone.local_regs[55] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L56: hyperstone.local_regs[56] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L57: hyperstone.local_regs[57] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L58: hyperstone.local_regs[58] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L59: hyperstone.local_regs[59] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L60: hyperstone.local_regs[60] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L61: hyperstone.local_regs[61] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L62: hyperstone.local_regs[62] = info->i; break;
+ case CPUINFO_INT_REGISTER + E132XS_L63: hyperstone.local_regs[63] = info->i; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 2: set_irq_line(2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 3: set_irq_line(3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 4: set_irq_line(4, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 5: set_irq_line(5, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 6: set_irq_line(6, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 7: set_irq_line(7, info->i); break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void hyperstone_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(hyperstone_regs); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 8; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 36; break;
+
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 15; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: /* not implemented */ break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + E132XS_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + E132XS_SR: info->i = SR; break;
+ case CPUINFO_INT_REGISTER + E132XS_FER: info->i = FER; break;
+ case CPUINFO_INT_REGISTER + E132XS_G3: info->i = hyperstone.global_regs[3]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G4: info->i = hyperstone.global_regs[4]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G5: info->i = hyperstone.global_regs[5]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G6: info->i = hyperstone.global_regs[6]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G7: info->i = hyperstone.global_regs[7]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G8: info->i = hyperstone.global_regs[8]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G9: info->i = hyperstone.global_regs[9]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G10: info->i = hyperstone.global_regs[10]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G11: info->i = hyperstone.global_regs[11]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G12: info->i = hyperstone.global_regs[12]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G13: info->i = hyperstone.global_regs[13]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G14: info->i = hyperstone.global_regs[14]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G15: info->i = hyperstone.global_regs[15]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G16: info->i = hyperstone.global_regs[16]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G17: info->i = hyperstone.global_regs[17]; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + E132XS_SP: info->i = SP; break;
+ case CPUINFO_INT_REGISTER + E132XS_UB: info->i = UB; break;
+ case CPUINFO_INT_REGISTER + E132XS_BCR: info->i = BCR; break;
+ case CPUINFO_INT_REGISTER + E132XS_TPR: info->i = TPR; break;
+ case CPUINFO_INT_REGISTER + E132XS_TCR: info->i = TCR; break;
+ case CPUINFO_INT_REGISTER + E132XS_TR: info->i = TR; break;
+ case CPUINFO_INT_REGISTER + E132XS_WCR: info->i = WCR; break;
+ case CPUINFO_INT_REGISTER + E132XS_ISR: info->i = ISR; break;
+ case CPUINFO_INT_REGISTER + E132XS_FCR: info->i = FCR; break;
+ case CPUINFO_INT_REGISTER + E132XS_MCR: info->i = MCR; break;
+ case CPUINFO_INT_REGISTER + E132XS_G28: info->i = hyperstone.global_regs[28]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G29: info->i = hyperstone.global_regs[29]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G30: info->i = hyperstone.global_regs[30]; break;
+ case CPUINFO_INT_REGISTER + E132XS_G31: info->i = hyperstone.global_regs[31]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL0: info->i = hyperstone.local_regs[(0 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL1: info->i = hyperstone.local_regs[(1 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL2: info->i = hyperstone.local_regs[(2 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL3: info->i = hyperstone.local_regs[(3 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL4: info->i = hyperstone.local_regs[(4 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL5: info->i = hyperstone.local_regs[(5 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL6: info->i = hyperstone.local_regs[(6 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL7: info->i = hyperstone.local_regs[(7 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL8: info->i = hyperstone.local_regs[(8 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL9: info->i = hyperstone.local_regs[(9 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL10: info->i = hyperstone.local_regs[(10 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL11: info->i = hyperstone.local_regs[(11 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL12: info->i = hyperstone.local_regs[(12 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL13: info->i = hyperstone.local_regs[(13 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL14: info->i = hyperstone.local_regs[(14 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_CL15: info->i = hyperstone.local_regs[(15 + GET_FP) % 64]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L0: info->i = hyperstone.local_regs[0]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L1: info->i = hyperstone.local_regs[1]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L2: info->i = hyperstone.local_regs[2]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L3: info->i = hyperstone.local_regs[3]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L4: info->i = hyperstone.local_regs[4]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L5: info->i = hyperstone.local_regs[5]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L6: info->i = hyperstone.local_regs[6]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L7: info->i = hyperstone.local_regs[7]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L8: info->i = hyperstone.local_regs[8]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L9: info->i = hyperstone.local_regs[9]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L10: info->i = hyperstone.local_regs[10]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L11: info->i = hyperstone.local_regs[11]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L12: info->i = hyperstone.local_regs[12]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L13: info->i = hyperstone.local_regs[13]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L14: info->i = hyperstone.local_regs[14]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L15: info->i = hyperstone.local_regs[15]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L16: info->i = hyperstone.local_regs[16]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L17: info->i = hyperstone.local_regs[17]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L18: info->i = hyperstone.local_regs[18]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L19: info->i = hyperstone.local_regs[19]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L20: info->i = hyperstone.local_regs[20]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L21: info->i = hyperstone.local_regs[21]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L22: info->i = hyperstone.local_regs[22]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L23: info->i = hyperstone.local_regs[23]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L24: info->i = hyperstone.local_regs[24]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L25: info->i = hyperstone.local_regs[25]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L26: info->i = hyperstone.local_regs[26]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L27: info->i = hyperstone.local_regs[27]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L28: info->i = hyperstone.local_regs[28]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L29: info->i = hyperstone.local_regs[29]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L30: info->i = hyperstone.local_regs[30]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L31: info->i = hyperstone.local_regs[31]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L32: info->i = hyperstone.local_regs[32]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L33: info->i = hyperstone.local_regs[33]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L34: info->i = hyperstone.local_regs[34]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L35: info->i = hyperstone.local_regs[35]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L36: info->i = hyperstone.local_regs[36]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L37: info->i = hyperstone.local_regs[37]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L38: info->i = hyperstone.local_regs[38]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L39: info->i = hyperstone.local_regs[39]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L40: info->i = hyperstone.local_regs[40]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L41: info->i = hyperstone.local_regs[41]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L42: info->i = hyperstone.local_regs[42]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L43: info->i = hyperstone.local_regs[43]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L44: info->i = hyperstone.local_regs[44]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L45: info->i = hyperstone.local_regs[45]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L46: info->i = hyperstone.local_regs[46]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L47: info->i = hyperstone.local_regs[47]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L48: info->i = hyperstone.local_regs[48]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L49: info->i = hyperstone.local_regs[49]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L50: info->i = hyperstone.local_regs[50]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L51: info->i = hyperstone.local_regs[51]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L52: info->i = hyperstone.local_regs[52]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L53: info->i = hyperstone.local_regs[53]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L54: info->i = hyperstone.local_regs[54]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L55: info->i = hyperstone.local_regs[55]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L56: info->i = hyperstone.local_regs[56]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L57: info->i = hyperstone.local_regs[57]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L58: info->i = hyperstone.local_regs[58]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L59: info->i = hyperstone.local_regs[59]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L60: info->i = hyperstone.local_regs[60]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L61: info->i = hyperstone.local_regs[61]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L62: info->i = hyperstone.local_regs[62]; break;
+ case CPUINFO_INT_REGISTER + E132XS_L63: info->i = hyperstone.local_regs[63]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = hyperstone_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = hyperstone_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = hyperstone_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = hyperstone_init; break;
+ case CPUINFO_PTR_RESET: info->reset = hyperstone_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = hyperstone_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = hyperstone_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = hyperstone_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &hyperstone_ICount; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO: info->internal_map = 0; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Hyperstone CPU"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.9"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Pierpaolo Prazzoli and Ryan Holtz"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c FTE:%X FRM:%X ILC:%d FL:%d FP:%d",
+ GET_S ? 'S':'.',
+ GET_P ? 'P':'.',
+ GET_T ? 'T':'.',
+ GET_L ? 'L':'.',
+ GET_I ? 'I':'.',
+ hyperstone.global_regs[1] & 0x00040 ? '?':'.',
+ GET_H ? 'H':'.',
+ GET_M ? 'M':'.',
+ GET_V ? 'V':'.',
+ GET_N ? 'N':'.',
+ GET_Z ? 'Z':'.',
+ GET_C ? 'C':'.',
+ GET_FTE,
+ GET_FRM,
+ GET_ILC,
+ GET_FL,
+ GET_FP);
+ break;
+
+ case CPUINFO_STR_REGISTER + E132XS_PC: sprintf(info->s, "PC :%08X", hyperstone.global_regs[0]); break;
+ case CPUINFO_STR_REGISTER + E132XS_SR: sprintf(info->s, "SR :%08X", hyperstone.global_regs[1]); break;
+ case CPUINFO_STR_REGISTER + E132XS_FER: sprintf(info->s, "FER :%08X", hyperstone.global_regs[2]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G3: sprintf(info->s, "G3 :%08X", hyperstone.global_regs[3]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G4: sprintf(info->s, "G4 :%08X", hyperstone.global_regs[4]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G5: sprintf(info->s, "G5 :%08X", hyperstone.global_regs[5]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G6: sprintf(info->s, "G6 :%08X", hyperstone.global_regs[6]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G7: sprintf(info->s, "G7 :%08X", hyperstone.global_regs[7]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G8: sprintf(info->s, "G8 :%08X", hyperstone.global_regs[8]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G9: sprintf(info->s, "G9 :%08X", hyperstone.global_regs[9]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G10: sprintf(info->s, "G10 :%08X", hyperstone.global_regs[10]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G11: sprintf(info->s, "G11 :%08X", hyperstone.global_regs[11]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G12: sprintf(info->s, "G12 :%08X", hyperstone.global_regs[12]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G13: sprintf(info->s, "G13 :%08X", hyperstone.global_regs[13]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G14: sprintf(info->s, "G14 :%08X", hyperstone.global_regs[14]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G15: sprintf(info->s, "G15 :%08X", hyperstone.global_regs[15]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G16: sprintf(info->s, "G16 :%08X", hyperstone.global_regs[16]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G17: sprintf(info->s, "G17 :%08X", hyperstone.global_regs[17]); break;
+ case CPUINFO_STR_REGISTER + E132XS_SP: sprintf(info->s, "SP :%08X", hyperstone.global_regs[18]); break;
+ case CPUINFO_STR_REGISTER + E132XS_UB: sprintf(info->s, "UB :%08X", hyperstone.global_regs[19]); break;
+ case CPUINFO_STR_REGISTER + E132XS_BCR: sprintf(info->s, "BCR :%08X", hyperstone.global_regs[20]); break;
+ case CPUINFO_STR_REGISTER + E132XS_TPR: sprintf(info->s, "TPR :%08X", hyperstone.global_regs[21]); break;
+ case CPUINFO_STR_REGISTER + E132XS_TCR: sprintf(info->s, "TCR :%08X", hyperstone.global_regs[22]); break;
+ case CPUINFO_STR_REGISTER + E132XS_TR: sprintf(info->s, "TR :%08X", hyperstone.global_regs[23]); break;
+ case CPUINFO_STR_REGISTER + E132XS_WCR: sprintf(info->s, "WCR :%08X", hyperstone.global_regs[24]); break;
+ case CPUINFO_STR_REGISTER + E132XS_ISR: sprintf(info->s, "ISR :%08X", hyperstone.global_regs[25]); break;
+ case CPUINFO_STR_REGISTER + E132XS_FCR: sprintf(info->s, "FCR :%08X", hyperstone.global_regs[26]); break;
+ case CPUINFO_STR_REGISTER + E132XS_MCR: sprintf(info->s, "MCR :%08X", hyperstone.global_regs[27]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G28: sprintf(info->s, "G28 :%08X", hyperstone.global_regs[28]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G29: sprintf(info->s, "G29 :%08X", hyperstone.global_regs[29]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G30: sprintf(info->s, "G30 :%08X", hyperstone.global_regs[30]); break;
+ case CPUINFO_STR_REGISTER + E132XS_G31: sprintf(info->s, "G31 :%08X", hyperstone.global_regs[31]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL0: sprintf(info->s, "CL0 :%08X", hyperstone.local_regs[(0 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL1: sprintf(info->s, "CL1 :%08X", hyperstone.local_regs[(1 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL2: sprintf(info->s, "CL2 :%08X", hyperstone.local_regs[(2 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL3: sprintf(info->s, "CL3 :%08X", hyperstone.local_regs[(3 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL4: sprintf(info->s, "CL4 :%08X", hyperstone.local_regs[(4 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL5: sprintf(info->s, "CL5 :%08X", hyperstone.local_regs[(5 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL6: sprintf(info->s, "CL6 :%08X", hyperstone.local_regs[(6 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL7: sprintf(info->s, "CL7 :%08X", hyperstone.local_regs[(7 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL8: sprintf(info->s, "CL8 :%08X", hyperstone.local_regs[(8 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL9: sprintf(info->s, "CL9 :%08X", hyperstone.local_regs[(9 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL10: sprintf(info->s, "CL10:%08X", hyperstone.local_regs[(10 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL11: sprintf(info->s, "CL11:%08X", hyperstone.local_regs[(11 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL12: sprintf(info->s, "CL12:%08X", hyperstone.local_regs[(12 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL13: sprintf(info->s, "CL13:%08X", hyperstone.local_regs[(13 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL14: sprintf(info->s, "CL14:%08X", hyperstone.local_regs[(14 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_CL15: sprintf(info->s, "CL15:%08X", hyperstone.local_regs[(15 + GET_FP) % 64]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L0: sprintf(info->s, "L0 :%08X", hyperstone.local_regs[0]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L1: sprintf(info->s, "L1 :%08X", hyperstone.local_regs[1]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L2: sprintf(info->s, "L2 :%08X", hyperstone.local_regs[2]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L3: sprintf(info->s, "L3 :%08X", hyperstone.local_regs[3]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L4: sprintf(info->s, "L4 :%08X", hyperstone.local_regs[4]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L5: sprintf(info->s, "L5 :%08X", hyperstone.local_regs[5]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L6: sprintf(info->s, "L6 :%08X", hyperstone.local_regs[6]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L7: sprintf(info->s, "L7 :%08X", hyperstone.local_regs[7]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L8: sprintf(info->s, "L8 :%08X", hyperstone.local_regs[8]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L9: sprintf(info->s, "L9 :%08X", hyperstone.local_regs[9]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L10: sprintf(info->s, "L10 :%08X", hyperstone.local_regs[10]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L11: sprintf(info->s, "L11 :%08X", hyperstone.local_regs[11]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L12: sprintf(info->s, "L12 :%08X", hyperstone.local_regs[12]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L13: sprintf(info->s, "L13 :%08X", hyperstone.local_regs[13]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L14: sprintf(info->s, "L14 :%08X", hyperstone.local_regs[14]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L15: sprintf(info->s, "L15 :%08X", hyperstone.local_regs[15]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L16: sprintf(info->s, "L16 :%08X", hyperstone.local_regs[16]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L17: sprintf(info->s, "L17 :%08X", hyperstone.local_regs[17]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L18: sprintf(info->s, "L18 :%08X", hyperstone.local_regs[18]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L19: sprintf(info->s, "L19 :%08X", hyperstone.local_regs[19]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L20: sprintf(info->s, "L20 :%08X", hyperstone.local_regs[20]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L21: sprintf(info->s, "L21 :%08X", hyperstone.local_regs[21]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L22: sprintf(info->s, "L22 :%08X", hyperstone.local_regs[22]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L23: sprintf(info->s, "L23 :%08X", hyperstone.local_regs[23]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L24: sprintf(info->s, "L24 :%08X", hyperstone.local_regs[24]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L25: sprintf(info->s, "L25 :%08X", hyperstone.local_regs[25]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L26: sprintf(info->s, "L26 :%08X", hyperstone.local_regs[26]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L27: sprintf(info->s, "L27 :%08X", hyperstone.local_regs[27]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L28: sprintf(info->s, "L28 :%08X", hyperstone.local_regs[28]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L29: sprintf(info->s, "L29 :%08X", hyperstone.local_regs[29]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L30: sprintf(info->s, "L30 :%08X", hyperstone.local_regs[30]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L31: sprintf(info->s, "L31 :%08X", hyperstone.local_regs[31]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L32: sprintf(info->s, "L32 :%08X", hyperstone.local_regs[32]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L33: sprintf(info->s, "L33 :%08X", hyperstone.local_regs[33]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L34: sprintf(info->s, "L34 :%08X", hyperstone.local_regs[34]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L35: sprintf(info->s, "L35 :%08X", hyperstone.local_regs[35]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L36: sprintf(info->s, "L36 :%08X", hyperstone.local_regs[36]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L37: sprintf(info->s, "L37 :%08X", hyperstone.local_regs[37]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L38: sprintf(info->s, "L38 :%08X", hyperstone.local_regs[38]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L39: sprintf(info->s, "L39 :%08X", hyperstone.local_regs[39]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L40: sprintf(info->s, "L40 :%08X", hyperstone.local_regs[40]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L41: sprintf(info->s, "L41 :%08X", hyperstone.local_regs[41]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L42: sprintf(info->s, "L42 :%08X", hyperstone.local_regs[42]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L43: sprintf(info->s, "L43 :%08X", hyperstone.local_regs[43]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L44: sprintf(info->s, "L44 :%08X", hyperstone.local_regs[44]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L45: sprintf(info->s, "L45 :%08X", hyperstone.local_regs[45]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L46: sprintf(info->s, "L46 :%08X", hyperstone.local_regs[46]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L47: sprintf(info->s, "L47 :%08X", hyperstone.local_regs[47]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L48: sprintf(info->s, "L48 :%08X", hyperstone.local_regs[48]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L49: sprintf(info->s, "L49 :%08X", hyperstone.local_regs[49]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L50: sprintf(info->s, "L50 :%08X", hyperstone.local_regs[50]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L51: sprintf(info->s, "L51 :%08X", hyperstone.local_regs[51]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L52: sprintf(info->s, "L52 :%08X", hyperstone.local_regs[52]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L53: sprintf(info->s, "L53 :%08X", hyperstone.local_regs[53]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L54: sprintf(info->s, "L54 :%08X", hyperstone.local_regs[54]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L55: sprintf(info->s, "L55 :%08X", hyperstone.local_regs[55]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L56: sprintf(info->s, "L56 :%08X", hyperstone.local_regs[56]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L57: sprintf(info->s, "L57 :%08X", hyperstone.local_regs[57]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L58: sprintf(info->s, "L58 :%08X", hyperstone.local_regs[58]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L59: sprintf(info->s, "L59 :%08X", hyperstone.local_regs[59]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L60: sprintf(info->s, "L60 :%08X", hyperstone.local_regs[60]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L61: sprintf(info->s, "L61 :%08X", hyperstone.local_regs[61]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L62: sprintf(info->s, "L62 :%08X", hyperstone.local_regs[62]); break;
+ case CPUINFO_STR_REGISTER + E132XS_L63: sprintf(info->s, "L63 :%08X", hyperstone.local_regs[63]); break;
+ }
+}
+
+
+#if (HAS_E116T)
+void e116t_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e116_4k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e116_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-16T"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_E116XT)
+void e116xt_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e116_8k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e116_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-16XT"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_E116XS)
+void e116xs_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e116_16k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e116_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-16XS"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_E116XSR)
+void e116xsr_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e116_16k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e116_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-16XSR"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_E132N)
+void e132n_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e132_4k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e132_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-32N"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_E132T)
+void e132t_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e132_4k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e132_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-32T"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_E132XN)
+void e132xn_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e132_8k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e132_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-32XN"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_E132XT)
+void e132xt_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e132_8k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e132_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-32XT"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_E132XS)
+void e132xs_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e132_16k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e132_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-32XS"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_E132XSR)
+void e132xsr_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e132_16k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e132_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "E1-32XSR"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_GMS30C2116)
+void gms30c2116_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e116_4k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e116_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "GMS30C2116"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_GMS30C2132)
+void gms30c2132_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e132_4k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e132_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "GMS30C2132"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_GMS30C2216)
+void gms30c2216_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e116_8k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e116_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "GMS30C2216"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
+
+#if (HAS_GMS30C2232)
+void gms30c2232_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_e132_8k_iram_map; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = e132_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "GMS30C2232"); break;
+
+ default:
+ hyperstone_get_info(state, info);
+ }
+}
+#endif
diff --git a/src/emu/cpu/e132xs/e132xs.h b/src/emu/cpu/e132xs/e132xs.h
new file mode 100644
index 00000000000..ed9a899a504
--- /dev/null
+++ b/src/emu/cpu/e132xs/e132xs.h
@@ -0,0 +1,173 @@
+#ifndef E132XS_H
+#define E132XS_H
+
+#include "cpuintrf.h"
+
+/* Functions */
+
+#if (HAS_E116T)
+void e116t_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_E116XT)
+void e116xt_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_E116XS)
+void e116xs_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_E116XSR)
+void e116xsr_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_E132N)
+void e132n_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_E132T)
+void e132t_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_E132XN)
+void e132xn_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_E132XT)
+void e132xt_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_E132XS)
+void e132xs_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_E132XSR)
+void e132xsr_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_GMS30C2116)
+void gms30c2116_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_GMS30C2132)
+void gms30c2132_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_GMS30C2216)
+void gms30c2216_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_GMS30C2232)
+void gms30c2232_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#ifdef MAME_DEBUG
+extern unsigned dasm_hyperstone(char *buffer, unsigned pc, const UINT8 *oprom, unsigned h_flag, int private_fp);
+#endif
+
+extern int hyp_type_16bit;
+
+/* Memory access */
+/* read byte */
+#define READ_B(addr) ((*hyp_cpu_read_byte)(addr))
+/* read half-word */
+#define READ_HW(addr) ((*hyp_cpu_read_half_word)((addr) & ~1))
+/* read word */
+#define READ_W(addr) ((*hyp_cpu_read_word)((addr) & ~3))
+
+/* write byte */
+#define WRITE_B(addr, data) ((*hyp_cpu_write_byte)(addr, data))
+/* write half-word */
+#define WRITE_HW(addr, data) ((*hyp_cpu_write_half_word)((addr) & ~1, data))
+/* write word */
+#define WRITE_W(addr, data) ((*hyp_cpu_write_word)((addr) & ~3, data))
+
+
+/* I/O access */
+/* read word */
+#define IO_READ_W(addr) ((*hyp_cpu_read_io_word)(((addr) >> 11) & 0x7ffc))
+/* write word */
+#define IO_WRITE_W(addr, data) ((*hyp_cpu_write_io_word)(((addr) >> 11) & 0x7ffc, data))
+
+
+#define READ_OP(addr) (cpu_readop16(hyp_type_16bit ? addr: WORD_XOR_BE(addr)))
+
+
+/* Registers Number */
+#define PC_REGISTER 0
+#define SR_REGISTER 1
+#define BCR_REGISTER 20
+#define TPR_REGISTER 21
+#define ISR_REGISTER 25
+#define FCR_REGISTER 26
+#define MCR_REGISTER 27
+
+#define X_CODE(val) ((val & 0x7000) >> 12)
+#define E_BIT(val) ((val & 0x8000) >> 15)
+#define S_BIT_CONST(val) ((val & 0x4000) >> 14)
+#define DD(val) ((val & 0x3000) >> 12)
+
+
+/* Extended DSP instructions */
+#define EMUL 0x102
+#define EMULU 0x104
+#define EMULS 0x106
+#define EMAC 0x10a
+#define EMACD 0x10e
+#define EMSUB 0x11a
+#define EMSUBD 0x11e
+#define EHMAC 0x02a
+#define EHMACD 0x02e
+#define EHCMULD 0x046
+#define EHCMACD 0x04e
+#define EHCSUMD 0x086
+#define EHCFFTD 0x096
+#define EHCFFTSD 0x296
+
+/* Delay values */
+#define NO_DELAY 0
+#define DELAY_EXECUTE 1
+#define DELAY_TAKEN 2
+
+/* Trap numbers */
+#define IO2 48
+#define IO1 49
+#define INT4 50
+#define INT3 51
+#define INT2 52
+#define INT1 53
+#define IO3 54
+#define TIMER 55
+#define RESERVED1 56
+#define TRACE_EXCEPTION 57
+#define PARITY_ERROR 58
+#define EXTENDED_OVERFLOW 59
+#define RANGE_ERROR 60
+#define PRIVILEGE_ERROR RANGE_ERROR
+#define FRAME_ERROR RANGE_ERROR
+#define RESERVED2 61
+#define RESET 62 // reserved if not mapped @ MEM3
+#define ERROR_ENTRY 63 // for instruction code of all ones
+
+/* Traps code */
+#define TRAPLE 4
+#define TRAPGT 5
+#define TRAPLT 6
+#define TRAPGE 7
+#define TRAPSE 8
+#define TRAPHT 9
+#define TRAPST 10
+#define TRAPHE 11
+#define TRAPE 12
+#define TRAPNE 13
+#define TRAPV 14
+#define TRAP 15
+
+/* Entry point to get trap locations or emulated code associated */
+#define E132XS_ENTRY_MEM0 0
+#define E132XS_ENTRY_MEM1 1
+#define E132XS_ENTRY_MEM2 2
+#define E132XS_ENTRY_IRAM 3
+#define E132XS_ENTRY_MEM3 7
+
+#endif /* E132XS_H */
diff --git a/src/emu/cpu/f8/f3853.c b/src/emu/cpu/f8/f3853.c
new file mode 100644
index 00000000000..4aa0d9dc908
--- /dev/null
+++ b/src/emu/cpu/f8/f3853.c
@@ -0,0 +1,152 @@
+/*
+ fairchild f3853 smi static ram interface
+ with integrated interrupt controller and timer
+
+ databook found at www.freetradezone.com
+*/
+
+#include "f3853.h"
+
+/*
+ the smi does not have DC0 and DC1, only DC0
+ it is not reacting to the cpus DC0/DC1 swap instruction
+ --> might lead to 2 devices having reacting to the same DC0 address
+ and placing their bytes to the databus!
+*/
+
+/*
+ 8 bit shift register
+ feedback in0 = not ( (out3 xor out4) xor (out5 xor out7) )
+ interrupt at 0xfe
+ 0xff stops register (0xfe never reached!)
+*/
+static UINT8 f3853_value_to_cycle[0x100];
+
+static struct {
+ F3853_CONFIG config;
+
+ UINT8 high,low; // bit 7 set to 0 for timer interrupt, to 1 for external interrupt
+ int external_enable;
+ int timer_enable;
+
+ int request_flipflop;
+
+ int priority_line; /* inverted level*/
+ int external_interrupt_line;/* inverted level */
+
+ emu_timer *timer;
+} f3853= { { 0 } };
+#define INTERRUPT_VECTOR(external) (external?f3853.low|(f3853.high<<8)|0x80 \
+ :(f3853.low|(f3853.high<<8))&~0x80)
+
+static void f3853_set_interrupt_request_line(void)
+{
+ if (!f3853.config.interrupt_request)
+ return;
+
+ if (f3853.external_enable&&!f3853.priority_line)
+ f3853.config.interrupt_request(INTERRUPT_VECTOR(TRUE), TRUE);
+ else if (f3853.timer_enable&&!f3853.priority_line&&f3853.request_flipflop)
+ f3853.config.interrupt_request(INTERRUPT_VECTOR(FALSE), TRUE);
+ else
+ f3853.config.interrupt_request(0, FALSE);
+}
+
+static TIMER_CALLBACK( f3853_timer_callback );
+
+static void f3853_timer_start(UINT8 value)
+{
+ attotime period = (value != 0xff) ? attotime_mul(ATTOTIME_IN_HZ(f3853.config.frequency), f3853_value_to_cycle[value]*31) : attotime_never;
+
+ timer_adjust(f3853.timer, period, 0, attotime_never);
+}
+
+static TIMER_CALLBACK( f3853_timer_callback )
+{
+ if (f3853.timer_enable)
+ {
+ f3853.request_flipflop = TRUE;
+ f3853_set_interrupt_request_line();
+ }
+ f3853_timer_start(0xfe);
+}
+
+
+void f3853_init(F3853_CONFIG *config)
+{
+ UINT8 reg=0xfe;
+ int i;
+
+ for (i=254/*known to get 0xfe after 255 cycles*/; i>=0; i--)
+ {
+ int o7=reg&0x80?TRUE:FALSE, o5=reg&0x20?TRUE:FALSE,
+ o4=reg&0x10?TRUE:FALSE, o3=reg&8?TRUE:FALSE;
+ f3853_value_to_cycle[reg]=i;
+ reg<<=1;
+ if (!((o7!=o5)!=(o4!=o3))) reg|=1;
+ }
+
+ f3853.config=*config;
+
+ f3853.priority_line=FALSE;
+ f3853.external_interrupt_line=TRUE;
+ f3853.timer = timer_alloc(f3853_timer_callback);
+}
+
+void f3853_reset(void)
+{
+ // registers indeterminate
+}
+
+void f3853_set_external_interrupt_in_line(int level)
+{
+ if (f3853.external_interrupt_line&&!level&& f3853.external_enable)
+ f3853.request_flipflop = TRUE;
+ f3853.external_interrupt_line = level;
+ f3853_set_interrupt_request_line();
+}
+
+void f3853_set_priority_in_line(int level)
+{
+ f3853.priority_line=level;
+ f3853_set_interrupt_request_line();
+}
+
+ READ8_HANDLER(f3853_r)
+{
+ UINT8 data=0;
+ switch (offset) {
+ case 0:
+ data=f3853.high;
+ break;
+ case 1:
+ data=f3853.low;
+ break;
+ case 2: // interrupt control; not readable
+ case 3: // timer; not readable
+ break;
+ }
+ return data;
+}
+
+WRITE8_HANDLER(f3853_w)
+{
+ switch (offset) {
+ case 0:
+ f3853.high=data;
+ break;
+ case 1:
+ f3853.low=data;
+ break;
+ case 2: //interrupt control
+ f3853.external_enable = ((data&3)==1);
+ f3853.timer_enable = ((data&3)==3);
+ f3853_set_interrupt_request_line();
+ break;
+ case 3: //timer
+ f3853.request_flipflop=FALSE;
+ f3853_set_interrupt_request_line();
+ f3853_timer_start(data);
+ break;
+ }
+}
diff --git a/src/emu/cpu/f8/f3853.h b/src/emu/cpu/f8/f3853.h
new file mode 100644
index 00000000000..ba1b6e4273f
--- /dev/null
+++ b/src/emu/cpu/f8/f3853.h
@@ -0,0 +1,24 @@
+/*
+ fairchild f3853 static ram interface smi
+ with integrated interrupt controller and timer
+
+ timer shift register basically the same as in f3851!
+*/
+
+#include "cpuintrf.h"
+
+typedef struct {
+ int frequency;
+ void (*interrupt_request)(UINT16 addr, int level);
+} F3853_CONFIG;
+
+void f3853_init(F3853_CONFIG *config);
+void f3853_reset(void);
+
+// ports 0x0c - 0x0f
+ READ8_HANDLER(f3853_r);
+WRITE8_HANDLER(f3853_w);
+
+void f3853_set_external_interrupt_in_line(int level);
+void f3853_set_priority_in_line(int level);
+
diff --git a/src/emu/cpu/f8/f8.c b/src/emu/cpu/f8/f8.c
new file mode 100644
index 00000000000..6e3ea1ec9ef
--- /dev/null
+++ b/src/emu/cpu/f8/f8.c
@@ -0,0 +1,2223 @@
+/*****************************************************************************
+ *
+ * f8.c
+ * Portable F8 emulator (Fairchild 3850)
+ *
+ * Copyright (c) 2000 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on Frank Palazzolo's F8 emulation in a standalone
+ * Fairchild Channel F emulator and the 'Fairchild F3850 CPU' data sheets.
+ *
+ *****************************************************************************/
+
+/* PeT 25.June 2001
+ added interrupt functionality
+ */
+
+#include <stdio.h>
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "f8.h"
+
+#define S 0x01
+#define C 0x02
+#define Z 0x04
+#define O 0x08
+#define I 0x10
+
+#define cS 4
+#define cL 6
+
+typedef struct {
+ UINT16 pc0; /* program counter 0 */
+ UINT16 pc1; /* program counter 1 */
+ UINT16 dc0; /* data counter 0 */
+ UINT16 dc1; /* data counter 1 */
+ UINT8 a; /* accumulator */
+ UINT8 w; /* processor status */
+ UINT8 is; /* scratchpad pointer */
+ UINT8 dbus; /* data bus value */
+ UINT16 io; /* last I/O address */
+ UINT16 irq_vector;
+ int (*irq_callback)(int irqline);
+ UINT8 r[64]; /* scratchpad RAM */
+ int irq_request;
+} f8_Regs;
+
+int f8_icount;
+
+static f8_Regs f8;
+
+/* timer shifter polynome values (will be used for timer interrupts) */
+static UINT8 timer_shifter[256];
+
+/* clear all flags */
+#define CLR_OZCS \
+ f8.w &= ~(O|Z|C|S)
+
+/* set sign and zero flags (note: the S flag is complementary) */
+#define SET_SZ(n) \
+ if (n == 0) \
+ f8.w |= Z | S; \
+ else \
+ if (n < 128) \
+ f8.w |= S
+
+/* set overflow and carry flags */
+#define SET_OC(n,m) \
+ if (n + m > 255) \
+ f8.w |= C; \
+ if ((n&127)+(m&127) > 127) \
+ { \
+ if (!(f8.w & C)) \
+ f8.w |= O; \
+ } \
+ else \
+ { \
+ if (f8.w & C) \
+ f8.w |= O; \
+ }
+
+/******************************************************************************
+ * ROMC (ROM cycles)
+ * This is what the Fairchild F8 CPUs use instead of an address bus
+ * There are 5 control lines and each combination of those lines has
+ * a special meaning. The devices attached to those control lines all
+ * have their own program counters (PC0 and PC1) and at least one
+ * data counter (DC0).
+ * Currently the emulation does not handle distinct PCs and DCs, but
+ * only one instance inside the CPU context.
+ ******************************************************************************/
+static void ROMC_00(int insttim) /* SKR - added parameter to tell if */
+ /* it is long or short based on inst */
+{
+ /*
+ * Instruction Fetch. The device whose address space includes the
+ * contents of the PC0 register must place on the data bus the op
+ * code addressed by PC0; then all devices increment the contents
+ * of PC0.
+ */
+
+ f8.dbus = cpu_readop(f8.pc0);
+ f8.pc0 += 1;
+ f8_icount -= insttim; /* SKR - ROMC00 is usually short, not short+long, */
+ /* but DS is long */
+}
+
+static void ROMC_01(void)
+{
+ /*
+ * The device whose address space includes the contents of the PC0
+ * register must place on the data bus the contents of the memory
+ * location addressed by PC0; then all devices add the 8-bit value
+ * on the data bus as signed binary number to PC0.
+ */
+ f8.dbus = cpu_readop_arg(f8.pc0);
+ f8.pc0 += (INT8)f8.dbus;
+ f8_icount -= cL;
+}
+
+static void ROMC_02(void)
+{
+ /*
+ * The device whose DC0 addresses a memory word within the address
+ * space of that device must place on the data bus the contents of
+ * the memory location addressed by DC0; then all devices increment
+ * DC0.
+ */
+ f8.dbus = program_read_byte_8(f8.dc0);
+ f8.dc0 += 1;
+ f8_icount -= cL;
+}
+
+static void ROMC_03(int insttim) /* SKR - added parameter to tell if */
+{ /* it is long or short based on inst */
+ /*
+ * Similiar to 0x00, except that it is used for immediate operands
+ * fetches (using PC0) instead of instruction fetches.
+ */
+ f8.dbus = f8.io = cpu_readop_arg(f8.pc0);
+ f8.pc0 += 1;
+ f8_icount -= insttim;
+}
+
+static void ROMC_04(void)
+{
+ /*
+ * Copy the contents of PC1 into PC0
+ */
+ f8.pc0 = f8.pc1;
+ f8_icount -= cS;
+}
+
+static void ROMC_05(void)
+{
+ /*
+ * Store the data bus contents into the memory location pointed
+ * to by DC0; increment DC0.
+ */
+ program_write_byte_8(f8.dc0, f8.dbus);
+ f8.dc0 += 1;
+ f8_icount -= cL;
+}
+
+static void ROMC_06(void)
+{
+ /*
+ * Place the high order byte of DC0 on the data bus.
+ */
+ f8.dbus = f8.dc0 >> 8;
+ f8_icount -= cL;
+}
+
+static void ROMC_07(void)
+{
+ /*
+ * Place the high order byte of PC1 on the data bus.
+ */
+ f8.dbus = f8.pc1 >> 8;
+ f8_icount -= cL;
+}
+
+static void ROMC_08(void)
+{
+ /*
+ * All devices copy the contents of PC0 into PC1. The CPU outputs
+ * zero on the data bus in this ROMC state. Load the data bus into
+ * both halves of PC0, thus clearing the register.
+ */
+ f8.pc1 = f8.pc0;
+ f8.dbus = 0;
+ f8.pc0 = 0;
+ f8_icount -= cL;
+}
+
+static void ROMC_09(void)
+{
+ /*
+ * The device whose address space includes the contents of the DC0
+ * register must place the low order byte of DC0 onto the data bus.
+ */
+ f8.dbus = f8.dc0 & 0xff;
+ f8_icount -= cL;
+}
+
+static void ROMC_0A(void)
+{
+ /*
+ * All devices add the 8-bit value on the data bus, treated as
+ * signed binary number, to the data counter.
+ */
+ f8.dc0 += (INT8)f8.dbus;
+ f8_icount -= cL;
+}
+
+static void ROMC_0B(void)
+{
+ /*
+ * The device whose address space includes the value in PC1
+ * must place the low order byte of PC1 onto the data bus.
+ */
+ f8.dbus = f8.pc1 & 0xff;
+ f8_icount -= cL;
+}
+
+static void ROMC_0C(void)
+{
+ /*
+ * The device whose address space includes the contents of the PC0
+ * register must place the contents of the memory word addressed
+ * by PC0 into the data bus; then all devices move the value that
+ * has just been placed on the data bus into the low order byte of PC0.
+ */
+ f8.dbus = cpu_readop_arg(f8.pc0);
+ f8.pc0 = (f8.pc0 & 0xff00) | f8.dbus;
+ f8_icount -= cL;
+}
+
+static void ROMC_0D(void)
+{
+ /*
+ * All devices store in PC1 the current contents of PC0, incremented
+ * by 1; PC0 is unaltered.
+ */
+ f8.pc1 = f8.pc0 + 1;
+ f8_icount -= cS;
+}
+
+static void ROMC_0E(void)
+{
+ /*
+ * The device whose address space includes the contents of the PC0
+ * register must place the word addressed by PC0 into the data bus.
+ * The value on the data bus is then moved to the low order byte
+ * of DC0 by all devices.
+ */
+ f8.dbus = cpu_readop_arg(f8.pc0);
+ f8.dc0 = (f8.dc0 & 0xff00) | f8.dbus;
+ f8_icount -= cL;
+}
+
+static void ROMC_0F(void)
+{
+ /*
+ * The interrupting device with highest priority must place the
+ * low order byte of the interrupt vector on the data bus.
+ * All devices must copy the contents of PC0 into PC1. All devices
+ * must move the contents of the data bus into the low order
+ * byte of PC0.
+ */
+ f8.irq_vector = (*f8.irq_callback)(0);
+ f8.dbus = f8.irq_vector & 0x00ff;
+ f8.pc1 = f8.pc0;
+ f8.pc0 = (f8.pc0 & 0xff00) | f8.dbus;
+ f8_icount -= cL;
+}
+
+#if 0
+static void ROMC_10(void)
+{
+ /*
+ * Inhibit any modification to the interrupt priority logic.
+ */
+ f8.w |= 0x20; /* ???? */
+ f8_icount -= cL;
+}
+#endif
+
+static void ROMC_11(void)
+{
+ /*
+ * The device whose address space includes the contents of PC0
+ * must place the contents of the addressed memory word on the
+ * data bus. All devices must then move the contents of the
+ * data bus to the upper byte of DC0.
+ */
+ f8.dbus = cpu_readop_arg(f8.pc0);
+ f8.dc0 = (f8.dc0 & 0x00ff) | (f8.dbus << 8);
+ f8_icount -= cL;
+}
+
+static void ROMC_12(void)
+{
+ /*
+ * All devices copy the contents of PC0 into PC1. All devices then
+ * move the contents of the data bus into the low order byte of PC0.
+ */
+ f8.pc1 = f8.pc0;
+ f8.pc0 = (f8.pc0 & 0xff00) | f8.dbus;
+ f8_icount -= cL;
+}
+
+static void ROMC_13(void)
+{
+ /*
+ * The interrupting device with highest priority must move the high
+ * order half of the interrupt vector onto the data bus. All devices
+ * must then move the contents of the data bus into the high order
+ * byte of PC0. The interrupting device resets its interrupt circuitry
+ * (so that it is no longer requesting CPU servicing and can respond
+ * to another interrupt).
+ */
+ f8.dbus = f8.irq_vector >> 8;
+ f8.pc0 = (f8.pc0 & 0x00ff) | (f8.dbus << 8);
+ f8.w&=~I;
+ f8_icount -= cL;
+}
+
+static void ROMC_14(void)
+{
+ /*
+ * All devices move the contents of the data bus into the high
+ * order byte of PC0.
+ */
+ f8.pc0 = (f8.pc0 & 0x00ff) | (f8.dbus << 8);
+ f8_icount -= cL;
+}
+
+static void ROMC_15(void)
+{
+ /*
+ * All devices move the contents of the data bus into the high
+ * order byte of PC1.
+ */
+ f8.pc1 = (f8.pc1 & 0x00ff) | (f8.dbus << 8);
+ f8_icount -= cL;
+}
+
+static void ROMC_16(void)
+{
+ /*
+ * All devices move the contents of the data bus into the high
+ * order byte of DC0.
+ */
+ f8.dc0 = (f8.dc0 & 0x00ff) | (f8.dbus << 8);
+ f8_icount -= cL;
+}
+
+static void ROMC_17(void)
+{
+ /*
+ * All devices move the contents of the data bus into the low
+ * order byte of PC0.
+ */
+ f8.pc0 = (f8.pc0 & 0xff00) | f8.dbus;
+ f8_icount -= cL;
+}
+
+static void ROMC_18(void)
+{
+ /*
+ * All devices move the contents of the data bus into the low
+ * order byte of PC1.
+ */
+ f8.pc1 = (f8.pc1 & 0xff00) | f8.dbus;
+ f8_icount -= cL;
+}
+
+static void ROMC_19(void)
+{
+ /*
+ * All devices move the contents of the data bus into the low
+ * order byte of DC0.
+ */
+ f8.dc0 = (f8.dc0 & 0xff00) | f8.dbus;
+ f8_icount -= cL;
+}
+
+static void ROMC_1A(void)
+{
+ /*
+ * During the prior cycle, an I/O port timer or interrupt control
+ * register was addressed; the device containing the addressed port
+ * must place the contents of the data bus into the address port.
+ */
+ io_write_byte_8(f8.io, f8.dbus);
+ f8_icount -= cL;
+}
+
+static void ROMC_1B(void)
+{
+ /*
+ * During the prior cycle, the data bus specified the address of an
+ * I/O port. The device containing the addressed I/O port must place
+ * the contents of the I/O port on the data bus. (Note that the
+ * contents of timer and interrupt control registers cannot be read
+ * back onto the data bus).
+ */
+ f8.dbus = io_read_byte_8(f8.io);
+ f8_icount -= cL;
+}
+
+static void ROMC_1C(int insttim) /* SKR - added parameter to tell if */
+ /* it is long or short based on inst */
+{
+ /*
+ * None.
+ */
+ f8_icount -= insttim;
+}
+
+static void ROMC_1D(void)
+{
+ /*
+ * Devices with DC0 and DC1 registers must switch registers.
+ * Devices without a DC1 register perform no operation.
+ */
+ UINT16 tmp = f8.dc0;
+ f8.dc0 = f8.dc1;
+ f8.dc1 = tmp;
+ f8_icount -= cS;
+}
+
+#if 0
+static void ROMC_1E(void)
+{
+ /*
+ * The devices whose address space includes the contents of PC0
+ * must place the low order byte of PC0 onto the data bus.
+ */
+ f8.dbus = f8.pc0 & 0xff;
+ f8_icount -= cL;
+}
+
+static void ROMC_1F(void)
+{
+ /*
+ * The devices whose address space includes the contents of PC0
+ * must place the high order byte of PC0 onto the data bus.
+ */
+ f8.dbus = (f8.pc0 >> 8) & 0xff;
+ f8_icount -= cL;
+}
+#endif
+
+/***********************************
+ * illegal opcodes
+ ***********************************/
+static void illegal(void)
+{
+ logerror("f8 illegal opcode at 0x%04x: %02x\n", f8.pc0, f8.dbus);
+}
+
+/***************************************************
+ * O Z C S 0000 0000
+ * - - - - LR A,KU
+ ***************************************************/
+static void f8_lr_a_ku(void)
+{
+ f8.a = f8.r[12];
+}
+
+/***************************************************
+ * O Z C S 0000 0001
+ * - - - - LR A,KL
+ ***************************************************/
+static void f8_lr_a_kl(void)
+{
+ f8.a = f8.r[13];
+}
+
+/***************************************************
+ * O Z C S 0000 0010
+ * - - - - LR A,QU
+ ***************************************************/
+static void f8_lr_a_qu(void)
+{
+ f8.a = f8.r[14];
+}
+
+/***************************************************
+ * O Z C S 0000 0011
+ * - - - - LR A,QL
+ ***************************************************/
+static void f8_lr_a_ql(void)
+{
+ f8.a = f8.r[15];
+}
+
+/***************************************************
+ * O Z C S 0000 0100
+ * - - - - LR KU,A
+ ***************************************************/
+static void f8_lr_ku_a(void)
+{
+ f8.r[12] = f8.a;
+}
+
+/***************************************************
+ * O Z C S 0000 0101
+ * - - - - LR KL,A
+ ***************************************************/
+static void f8_lr_kl_a(void)
+{
+ f8.r[13] = f8.a;
+}
+
+/***************************************************
+ * O Z C S 0000 0110
+ * - - - - LR QU,A
+ ***************************************************/
+static void f8_lr_qu_a(void)
+{
+ f8.r[14] = f8.a;
+}
+
+/***************************************************
+ * O Z C S 0000 0111
+ * - - - - LR QL,A
+ ***************************************************/
+static void f8_lr_ql_a(void)
+{
+ f8.r[15] = f8.a;
+}
+
+/***************************************************
+ * O Z C S 0000 1000
+ * - - - - LR K,P
+ ***************************************************/
+static void f8_lr_k_p(void)
+{
+ ROMC_07();
+ f8.r[12] = f8.dbus;
+ ROMC_0B();
+ f8.r[13] = f8.dbus;
+}
+
+/***************************************************
+ * O Z C S 0000 1001
+ * - - - - LR P,K
+ ***************************************************/
+static void f8_lr_p_k(void)
+{
+ f8.dbus = f8.r[12];
+ ROMC_15();
+ f8.dbus = f8.r[13];
+ ROMC_18();
+}
+
+/***************************************************
+ * O Z C S 0000 1010
+ * - - - - LR A,IS
+ ***************************************************/
+static void f8_lr_a_is(void)
+{
+ f8.a = f8.is;
+}
+
+/***************************************************
+ * O Z C S 0000 1011
+ * - - - - LR IS,A
+ ***************************************************/
+static void f8_lr_is_a(void)
+{
+ f8.is = f8.a & 0x3f;
+}
+
+/***************************************************
+ * O Z C S 0000 1100
+ * - - - - PK
+ ***************************************************/
+static void f8_pk(void)
+{
+ f8.dbus = f8.r[13];
+ ROMC_12();
+ f8.dbus = f8.r[12];
+ ROMC_14();
+}
+
+/***************************************************
+ * O Z C S 0000 1101
+ * - - - - LR P0,Q
+ ***************************************************/
+static void f8_lr_p0_q(void)
+{
+ f8.dbus = f8.r[15];
+ ROMC_17();
+ f8.dbus = f8.r[14];
+ ROMC_14();
+}
+
+/***************************************************
+ * O Z C S 0000 1110
+ * - - - - LR Q,DC
+ ***************************************************/
+static void f8_lr_q_dc(void)
+{
+ ROMC_06();
+ f8.r[14] = f8.dbus;
+ ROMC_09();
+ f8.r[15] = f8.dbus;
+}
+
+/***************************************************
+ * O Z C S 0000 1111
+ * - - - - LR DC,Q
+ ***************************************************/
+static void f8_lr_dc_q(void)
+{
+ f8.dbus = f8.r[14];
+ ROMC_16();
+ f8.dbus = f8.r[15];
+ ROMC_19();
+}
+
+/***************************************************
+ * O Z C S 0001 0000
+ * - - - - LR DC,H
+ ***************************************************/
+static void f8_lr_dc_h(void)
+{
+ f8.dbus = f8.r[10];
+ ROMC_16();
+ f8.dbus = f8.r[11];
+ ROMC_19();
+}
+
+/***************************************************
+ * O Z C S 0001 0001
+ * - - - - LR H,DC
+ ***************************************************/
+static void f8_lr_h_dc(void)
+{
+ ROMC_06();
+ f8.r[10] = f8.dbus;
+ ROMC_09();
+ f8.r[11] = f8.dbus;
+}
+
+/***************************************************
+ * O Z C S 0001 0010
+ * 0 x 0 1 SR 1
+ ***************************************************/
+static void f8_sr_1(void)
+{
+ f8.a >>= 1;
+ CLR_OZCS;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0001 0011
+ * 0 x 0 x SL 1
+ ***************************************************/
+static void f8_sl_1(void)
+{
+ f8.a <<= 1;
+ CLR_OZCS;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0001 0100
+ * 0 x 0 1 SR 4
+ ***************************************************/
+static void f8_sr_4(void)
+{
+ f8.a >>= 4;
+ CLR_OZCS;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0001 0101
+ * 0 x 0 x SL 4
+ ***************************************************/
+static void f8_sl_4(void)
+{
+ f8.a <<= 4;
+ CLR_OZCS;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0001 0110
+ * - - - - LM
+ ***************************************************/
+static void f8_lm(void)
+{
+ ROMC_02();
+ f8.a = f8.dbus;
+}
+
+/***************************************************
+ * O Z C S 0001 0111
+ * - - - - ST
+ ***************************************************/
+static void f8_st(void)
+{
+ f8.dbus = f8.a;
+ ROMC_05();
+}
+
+/***************************************************
+ * O Z C S 0001 1000
+ * 0 x 0 x COM
+ ***************************************************/
+static void f8_com(void)
+{
+ f8.a = ~f8.a;
+ CLR_OZCS;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0001 1001
+ * x x x x LNK
+ ***************************************************/
+static void f8_lnk(void)
+{
+ if (f8.w & C)
+ {
+ CLR_OZCS;
+ SET_OC(f8.a,1);
+ f8.a += 1;
+ }
+ else
+ {
+ CLR_OZCS;
+ }
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0001 1010
+ * DI
+ ***************************************************/
+static void f8_di(void)
+{
+ ROMC_1C(cS);
+ f8.w &= ~I;
+}
+
+/***************************************************
+ * O Z C S 0001 1011
+ * EI
+ ***************************************************/
+static void f8_ei(void)
+{
+ ROMC_1C(cS);
+ f8.w |= I;
+}
+
+/***************************************************
+ * O Z C S 0001 1100
+ * POP
+ ***************************************************/
+static void f8_pop(void)
+{
+ ROMC_04();
+}
+
+/***************************************************
+ * O Z C S 0001 1101
+ * x x x x LR W,J
+ ***************************************************/
+static void f8_lr_w_j(void)
+{
+ ROMC_1C(cS);
+ f8.w = f8.r[9];
+}
+
+/***************************************************
+ * O Z C S 0001 1110
+ * - - - - LR J,W
+ ***************************************************/
+static void f8_lr_j_w(void)
+{
+ f8.r[9] = f8.w;
+}
+
+/***************************************************
+ * O Z C S 0001 1111
+ * x x x x INC
+ ***************************************************/
+static void f8_inc(void)
+{
+ CLR_OZCS;
+ SET_OC(f8.a,1);
+ f8.a += 1;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0010 0000 aaaa aaaa
+ * - - - - LI aa
+ ***************************************************/
+static void f8_li(void)
+{
+ ROMC_03(cL);
+ f8.a = f8.dbus;
+}
+
+/***************************************************
+ * O Z C S 0010 0001 aaaa aaaa
+ * 0 x 0 x NI aa
+ ***************************************************/
+static void f8_ni(void)
+{
+ ROMC_03(cL);
+ CLR_OZCS;
+ f8.a &= f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0010 0010 aaaa aaaa
+ * 0 x 0 x OI aa
+ ***************************************************/
+static void f8_oi(void)
+{
+ ROMC_03(cL);
+ CLR_OZCS;
+ f8.a |= f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0010 0011 aaaa aaaa
+ * 0 x 0 x XI aa
+ ***************************************************/
+static void f8_xi(void)
+{
+ ROMC_03(cL);
+ CLR_OZCS;
+ f8.a ^= f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0010 0100 aaaa aaaa
+ * x x x x AI aa
+ ***************************************************/
+static void f8_ai(void)
+{
+ ROMC_03(cL);
+ CLR_OZCS;
+ SET_OC(f8.a,f8.dbus);
+ f8.a += f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0010 0101 aaaa aaaa
+ * x x x x CI aa
+ ***************************************************/
+static void f8_ci(void)
+{
+ UINT16 tmp = ((UINT8)~f8.a) + 1;
+ ROMC_03(cL);
+ CLR_OZCS;
+ SET_OC(tmp,f8.dbus);
+ tmp += f8.dbus;
+ SET_SZ((UINT8)tmp);
+}
+
+/***************************************************
+ * O Z C S 0010 0110 aaaa aaaa
+ * 0 x 0 x IN aa
+ ***************************************************/
+static void f8_in(void)
+{
+ ROMC_03(cL);
+ CLR_OZCS;
+ ROMC_1B();
+ f8.a = f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 0010 0111 aaaa aaaa
+ * - - - - OUT aa
+ ***************************************************/
+static void f8_out(void)
+{
+ ROMC_03(cL);
+ f8.dbus = f8.a;
+ ROMC_1A();
+}
+
+/***************************************************
+ * O Z C S 0010 1000 iiii iiii jjjj jjjj
+ * - - - - PI iijj
+ ***************************************************/
+static void f8_pi(void)
+{
+ ROMC_03(cL);
+ f8.a = f8.dbus;
+ ROMC_0D();
+ ROMC_0C();
+ f8.dbus = f8.a;
+ ROMC_14();
+}
+
+/***************************************************
+ * O Z C S 0010 1001 iiii iiii jjjj jjjj
+ * - - - - JMP iijj
+ ***************************************************/
+static void f8_jmp(void)
+{
+ ROMC_03(cL);
+ f8.a = f8.dbus;
+ ROMC_0C();
+ f8.dbus = f8.a;
+ ROMC_14();
+}
+
+/***************************************************
+ * O Z C S 0010 1010 iiii iiii jjjj jjjj
+ * - - - - DCI iijj
+ ***************************************************/
+static void f8_dci(void)
+{
+ ROMC_11();
+ ROMC_03(cS);
+ ROMC_0E();
+ ROMC_03(cS);
+}
+
+/***************************************************
+ * O Z C S 0010 1011
+ * - - - - NOP
+ ***************************************************/
+static void f8_nop(void)
+{
+}
+
+/***************************************************
+ * O Z C S 0010 1100
+ * - - - - XDC
+ ***************************************************/
+static void f8_xdc(void)
+{
+ ROMC_1D();
+}
+
+/***************************************************
+ * O Z C S 0011 rrrr
+ * x x x x DS r
+ ***************************************************/
+static void f8_ds_r(int r)
+{
+ CLR_OZCS;
+ SET_OC(f8.r[r], 0xff);
+ f8.r[r] = f8.r[r] + 0xff;
+ SET_SZ(f8.r[r]);
+}
+
+/***************************************************
+ * O Z C S 0011 1100
+ * x x x x DS ISAR
+ ***************************************************/
+static void f8_ds_isar(void)
+{
+ CLR_OZCS;
+ SET_OC(f8.r[f8.is], 0xff);
+ f8.r[f8.is] = f8.r[f8.is] + 0xff;
+ SET_SZ(f8.r[f8.is]);
+}
+
+/***************************************************
+ * O Z C S 0011 1101
+ * x x x x DS ISAR++
+ ***************************************************/
+static void f8_ds_isar_i(void)
+{
+ CLR_OZCS;
+ SET_OC(f8.r[f8.is], 0xff);
+ f8.r[f8.is] = f8.r[f8.is] + 0xff;
+ SET_SZ(f8.r[f8.is]);
+ f8.is = (f8.is & 0x38) | ((f8.is + 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 0011 1110
+ * x x x x DS ISAR--
+ ***************************************************/
+static void f8_ds_isar_d(void)
+{
+ CLR_OZCS;
+ SET_OC(f8.r[f8.is], 0xff);
+ f8.r[f8.is] = f8.r[f8.is] + 0xff;
+ SET_SZ(f8.r[f8.is]);
+ f8.is = (f8.is & 0x38) | ((f8.is - 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 0100 rrrr
+ * - - - - LR A,r
+ ***************************************************/
+static void f8_lr_a_r(int r)
+{
+ f8.a = f8.r[r];
+}
+
+/***************************************************
+ * O Z C S 0100 1100
+ * - - - - LR A,ISAR
+ ***************************************************/
+static void f8_lr_a_isar(void)
+{
+ f8.a = f8.r[f8.is];
+}
+
+/***************************************************
+ * O Z C S 0100 1101
+ * - - - - LR A,ISAR++
+ ***************************************************/
+static void f8_lr_a_isar_i(void)
+{
+ f8.a = f8.r[f8.is];
+ f8.is = (f8.is & 0x38) | ((f8.is + 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 0100 1110
+ * - - - - LR A,ISAR--
+ ***************************************************/
+static void f8_lr_a_isar_d(void)
+{
+ f8.a = f8.r[f8.is];
+ f8.is = (f8.is & 0x38) | ((f8.is - 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 0101 rrrr
+ * - - - - LR r,A
+ ***************************************************/
+static void f8_lr_r_a(int r)
+{
+ f8.r[r] = f8.a;
+}
+
+/***************************************************
+ * O Z C S 0101 1100
+ * - - - - LR ISAR,A
+ ***************************************************/
+static void f8_lr_isar_a(void)
+{
+ f8.r[f8.is] = f8.a;
+}
+
+/***************************************************
+ * O Z C S 0101 1101
+ * - - - - LR ISAR++,A
+ ***************************************************/
+static void f8_lr_isar_i_a(void)
+{
+ f8.r[f8.is] = f8.a;
+ f8.is = (f8.is & 0x38) | ((f8.is + 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 0101 1110
+ * - - - - LR ISAR--,A
+ ***************************************************/
+static void f8_lr_isar_d_a(void)
+{
+ f8.r[f8.is] = f8.a;
+ f8.is = (f8.is & 0x38) | ((f8.is - 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 0110 0eee
+ * - - - - LISU e
+ ***************************************************/
+static void f8_lisu(int e)
+{
+ f8.is = (f8.is & 0x07) | e;
+}
+
+/***************************************************
+ * O Z C S 0110 1eee
+ * - - - - LISL e
+ ***************************************************/
+static void f8_lisl(int e)
+{
+ f8.is = (f8.is & 0x38) | e;
+}
+
+/***************************************************
+ * O Z C S 0111 iiii
+ * - - - - LIS i
+ ***************************************************/
+static void f8_lis(int i)
+{
+ f8.a = i;
+}
+
+/***************************************************
+ * O Z C S 1000 0eee aaaa aaaa
+ * BT e,aa
+ ***************************************************/
+static void f8_bt(int e)
+{
+ ROMC_1C(cS);
+ if (f8.w & e)
+ ROMC_01(); /* take the relative branch */
+ else
+ ROMC_03(cS); /* just read the argument on the data bus */
+}
+
+/***************************************************
+ * O Z C S 1000 1000
+ * x x x x AM
+ ***************************************************/
+static void f8_am(void)
+{
+ ROMC_02();
+ CLR_OZCS;
+ SET_OC(f8.a, f8.dbus);
+ f8.a += f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1000 1001
+ * x x x x AMD
+ ***************************************************/
+static void f8_amd(void)
+{
+ UINT8 tmp = f8.a - 0x66, adj = 0x00;
+ int sum;
+ ROMC_02();
+ sum = (tmp & 0x0f) + (f8.dbus & 0x0f);
+ if (sum > 0x09)
+ adj += 0x06;
+ sum = tmp + f8.dbus + adj;
+ if (sum > 0x99)
+ adj += 0x60;
+ tmp += adj;
+ CLR_OZCS;
+ SET_OC(tmp,f8.dbus);
+ f8.a = tmp + f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1000 1010
+ * 0 x 0 x NM
+ ***************************************************/
+static void f8_nm(void)
+{
+ ROMC_02();
+ CLR_OZCS;
+ f8.a &= f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1000 1011
+ * 0 x 0 x OM
+ ***************************************************/
+static void f8_om(void)
+{
+ ROMC_02();
+ CLR_OZCS;
+ f8.a |= f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1000 1100
+ * 0 x 0 x XM
+ ***************************************************/
+static void f8_xm(void)
+{
+ ROMC_02();
+ CLR_OZCS;
+ f8.a ^= f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1000 1101
+ * 0 x 0 x CM
+ ***************************************************/
+static void f8_cm(void) /* SKR changed to match f8_ci() */
+{
+ UINT16 tmp = ((UINT8)~f8.a) + 1;
+ ROMC_02();
+ CLR_OZCS;
+ SET_OC(tmp,f8.dbus);
+ tmp += f8.dbus;
+ SET_SZ((UINT8)tmp);
+}
+
+/***************************************************
+ * O Z C S 1000 1110
+ * - - - - ADC
+ ***************************************************/
+static void f8_adc(void)
+{
+ f8.dbus = f8.a;
+ ROMC_0A(); /* add data bus value to DC0 */
+}
+
+/***************************************************
+ * O Z C S 1000 1111
+ * - - - - BR7
+ ***************************************************/
+static void f8_br7(void)
+{
+ if ((f8.is & 7) == 7)
+ ROMC_03(cS); /* just read the argument on the data bus */
+ else
+ ROMC_01(); /* take the relative branch */
+}
+
+/***************************************************
+ * O Z C S 1001 tttt aaaa aaaa
+ * - - - - BF t,aa
+ ***************************************************/
+static void f8_bf(int t)
+{
+ ROMC_1C(cS);
+ if (f8.w & t)
+ ROMC_03(cS); /* just read the argument on the data bus */
+ else
+ ROMC_01(); /* take the relative branch */
+}
+
+/***************************************************
+ * O Z C S 1010 000n
+ * 0 x 0 x INS n (n = 0-1)
+ ***************************************************/
+static void f8_ins_0(int n)
+{
+ ROMC_1C(cS);
+ CLR_OZCS;
+ f8.a = io_read_byte_8(n);
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1010 nnnn
+ * 0 x 0 x INS n (n = 4-F)
+ ***************************************************/
+static void f8_ins_1(int n)
+{
+ ROMC_1C(cL);
+ f8.io = n;
+ ROMC_1B();
+ CLR_OZCS;
+ f8.a = f8.dbus;
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1011 000n
+ * - - - - OUTS n (n = 0-1)
+ ***************************************************/
+static void f8_outs_0(int n)
+{
+ ROMC_1C(cS);
+ io_write_byte_8(n, f8.a);
+}
+
+/***************************************************
+ * O Z C S 1011 nnnn
+ * - - - - OUTS n (n = 4-F)
+ ***************************************************/
+static void f8_outs_1(int n)
+{
+ ROMC_1C(cL);
+ f8.io = n;
+ f8.dbus = f8.a;
+ ROMC_1A();
+}
+
+/***************************************************
+ * O Z C S 1100 rrrr
+ * x x x x AS r
+ ***************************************************/
+static void f8_as(int r)
+{
+ CLR_OZCS;
+ SET_OC(f8.a, f8.r[r]);
+ f8.a += f8.r[r];
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1100 1100
+ * x x x x AS ISAR
+ ***************************************************/
+static void f8_as_isar(void)
+{
+ CLR_OZCS;
+ SET_OC(f8.a, f8.r[f8.is]);
+ f8.a += f8.r[f8.is];
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1100 1101
+ * x x x x AS ISAR++
+ ***************************************************/
+static void f8_as_isar_i(void)
+{
+ CLR_OZCS;
+ SET_OC(f8.a, f8.r[f8.is]);
+ f8.a += f8.r[f8.is];
+ SET_SZ(f8.a);
+ f8.is = (f8.is & 0x38) | ((f8.is + 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 1100 1110
+ * x x x x AS ISAR--
+ ***************************************************/
+static void f8_as_isar_d(void)
+{
+ CLR_OZCS;
+ SET_OC(f8.a, f8.r[f8.is]);
+ f8.a += f8.r[f8.is];
+ SET_SZ(f8.a);
+ f8.is = (f8.is & 0x38) | ((f8.is - 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 1101 rrrr
+ * x x x x ASD r
+ ***************************************************/
+static void f8_asd(int r)
+{
+ UINT8 tmp = f8.a - 0x66, adj = 0x00;
+ int sum;
+ ROMC_1C(cS);
+ sum = (tmp & 0x0f) + (f8.r[r] & 0x0f);
+ if (sum > 0x09)
+ adj += 0x06;
+ sum = tmp + f8.r[r] + adj;
+ if (sum > 0x99)
+ adj += 0x60;
+ tmp += adj;
+ CLR_OZCS;
+ SET_OC(tmp, f8.r[r]);
+ f8.a = tmp + f8.r[r];
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1101 1100
+ * x x x x ASD ISAR
+ ***************************************************/
+static void f8_asd_isar(void)
+{
+ UINT8 tmp = f8.a - 0x66, adj = 0x00;
+ int sum;
+ ROMC_1C(cS);
+ sum = (tmp & 0x0f) + (f8.r[f8.is] & 0x0f);
+ if (sum > 0x09)
+ adj += 0x06;
+ sum = tmp + f8.r[f8.is] + adj;
+ if (sum > 0x99)
+ adj += 0x60;
+ tmp += adj;
+ CLR_OZCS;
+ SET_OC(tmp, f8.r[f8.is]);
+ f8.a = tmp + f8.r[f8.is];
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1101 1101
+ * x x x x ASD ISAR++
+ ***************************************************/
+static void f8_asd_isar_i(void)
+{
+ UINT8 tmp = f8.a - 0x66, adj = 0x00;
+ int sum;
+ ROMC_1C(cS);
+ sum = (tmp & 0x0f) + (f8.r[f8.is] & 0x0f);
+ if (sum > 0x09)
+ adj += 0x06;
+ sum = tmp + f8.r[f8.is] + adj;
+ if (sum > 0x99)
+ adj += 0x60;
+ tmp += adj;
+ CLR_OZCS;
+ SET_OC(tmp, f8.r[f8.is]);
+ f8.a = tmp + f8.r[f8.is];
+ SET_SZ(f8.a);
+ f8.is = (f8.is & 0x38) | ((f8.is + 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 1101 1110
+ * x x x x ASD ISAR--
+ ***************************************************/
+static void f8_asd_isar_d(void)
+{
+ UINT8 tmp = f8.a - 0x66, adj = 0x00;
+ int sum;
+ ROMC_1C(cS);
+ sum = (tmp & 0x0f) + (f8.r[f8.is] & 0x0f);
+ if (sum > 0x09)
+ adj += 0x06;
+ sum = tmp + f8.r[f8.is] + adj;
+ if (sum > 0x99)
+ adj += 0x60;
+ tmp += adj;
+ CLR_OZCS;
+ SET_OC(tmp, f8.r[f8.is]);
+ f8.a = tmp + f8.r[f8.is];
+ SET_SZ(f8.a);
+ f8.is = (f8.is & 0x38) | ((f8.is - 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 1110 rrrr
+ * 0 x 0 x XS r
+ ***************************************************/
+static void f8_xs(int r)
+{
+ CLR_OZCS;
+ f8.a ^= f8.r[r];
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1110 1100
+ * 0 x 0 x XS ISAR
+ ***************************************************/
+static void f8_xs_isar(void)
+{
+ CLR_OZCS;
+ f8.a ^= f8.r[f8.is];
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1110 1101
+ * 0 x 0 x XS ISAR++
+ ***************************************************/
+static void f8_xs_isar_i(void)
+{
+ CLR_OZCS;
+ f8.a ^= f8.r[f8.is];
+ SET_SZ(f8.a);
+ f8.is = (f8.is & 0x38) | ((f8.is + 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 1110 1110
+ * 0 x 0 x XS ISAR--
+ ***************************************************/
+static void f8_xs_isar_d(void)
+{
+ CLR_OZCS;
+ f8.a ^= f8.r[f8.is];
+ SET_SZ(f8.a);
+ f8.is = (f8.is & 0x38) | ((f8.is - 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 1111 rrrr
+ * 0 x 0 x NS r
+ ***************************************************/
+static void f8_ns(int r)
+{
+ CLR_OZCS;
+ f8.a &= f8.r[r];
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1111 1100
+ * 0 x 0 x NS ISAR
+ ***************************************************/
+static void f8_ns_isar(void)
+{
+ CLR_OZCS;
+ f8.a &= f8.r[f8.is];
+ SET_SZ(f8.a);
+}
+
+/***************************************************
+ * O Z C S 1111 1101
+ * 0 x 0 x NS ISAR++
+ ***************************************************/
+static void f8_ns_isar_i(void)
+{
+ CLR_OZCS;
+ f8.a &= f8.r[f8.is];
+ SET_SZ(f8.a);
+ f8.is = (f8.is & 0x38) | ((f8.is + 1) & 0x07);
+}
+
+/***************************************************
+ * O Z C S 1111 1110
+ * 0 x 0 x NS ISAR--
+ ***************************************************/
+static void f8_ns_isar_d(void)
+{
+ CLR_OZCS;
+ f8.a &= f8.r[f8.is];
+ SET_SZ(f8.a);
+ f8.is = (f8.is & 0x38) | ((f8.is - 1) & 0x07);
+}
+
+void f8_reset(void)
+{
+ UINT8 data;
+ int i;
+ int (*old_callback)(int);
+
+ old_callback = f8.irq_callback;
+ memset(&f8, 0, sizeof(f8_Regs));
+ f8.irq_callback = old_callback;
+ f8.w&=~I;
+
+ /* save PC0 to PC1 and reset PC0 */
+ ROMC_08();
+ /* fetch the first opcode */
+ ROMC_00(cS);
+
+ /* initialize the timer shift register
+ * this is an 8 bit polynome counter which can be loaded parallel
+ * with 0xff the outputs never change and thus the timer is disabled.
+ * with 0xfe the shifter starts cycling through 255 states until it
+ * reaches 0xfe again (and then issues an interrupt).
+ * the counter output values are not sequential, but go like this:
+ * 0xfe, 0xfd, 0xfb, 0xf7, 0xee, 0xdc ... etc. :-)
+ * We have to build a lookup table to tell how many cycles a write
+
+ */
+ data = 0xfe; /* initial value */
+ for (i = 0; i < 256; i++)
+ {
+ timer_shifter[i] = data;
+ if ( (((data >> 3) ^ (data >> 4)) ^
+ ((data >> 5) ^ (data >> 7))) & 1 )
+ data <<= 1;
+ else
+ data = (data << 1) | 1;
+ }
+}
+
+/* Execute cycles - returns number of cycles actually run */
+int f8_execute(int cycles)
+{
+ f8_icount = cycles;
+
+ do
+ {
+ UINT8 op=f8.dbus;
+ CALL_MAME_DEBUG;
+
+ switch( op )
+ {
+ /* opcode bitmask */
+ case 0x00: /* 0000 0000 */ f8_lr_a_ku(); break;
+ case 0x01: /* 0000 0001 */ f8_lr_a_kl(); break;
+ case 0x02: /* 0000 0010 */ f8_lr_a_qu(); break;
+ case 0x03: /* 0000 0011 */ f8_lr_a_ql(); break;
+ case 0x04: /* 0000 0100 */ f8_lr_ku_a(); break;
+ case 0x05: /* 0000 0101 */ f8_lr_kl_a(); break;
+ case 0x06: /* 0000 0110 */ f8_lr_qu_a(); break;
+ case 0x07: /* 0000 0111 */ f8_lr_ql_a(); break;
+ case 0x08: /* 0000 1000 */ f8_lr_k_p(); break;
+ case 0x09: /* 0000 1001 */ f8_lr_p_k(); break;
+ case 0x0a: /* 0000 1010 */ f8_lr_a_is(); break;
+ case 0x0b: /* 0000 1011 */ f8_lr_is_a(); break;
+ case 0x0c: /* 0000 1100 */ f8_pk(); break;
+ case 0x0d: /* 0000 1101 */ f8_lr_p0_q(); break;
+ case 0x0e: /* 0000 1110 */ f8_lr_q_dc(); break;
+ case 0x0f: /* 0000 1111 */ f8_lr_dc_q(); break;
+
+ case 0x10: /* 0001 0000 */ f8_lr_dc_h(); break;
+ case 0x11: /* 0001 0001 */ f8_lr_h_dc(); break;
+ case 0x12: /* 0001 0010 */ f8_sr_1(); break;
+ case 0x13: /* 0001 0011 */ f8_sl_1(); break;
+ case 0x14: /* 0001 0100 */ f8_sr_4(); break;
+ case 0x15: /* 0001 0101 */ f8_sl_4(); break;
+ case 0x16: /* 0001 0110 */ f8_lm(); break;
+ case 0x17: /* 0001 0111 */ f8_st(); break;
+ case 0x18: /* 0001 1000 */ f8_com(); break;
+ case 0x19: /* 0001 1001 */ f8_lnk(); break;
+ case 0x1a: /* 0001 1010 */ f8_di(); break;
+ case 0x1b: /* 0001 1011 */ f8_ei(); break;
+ case 0x1c: /* 0001 1100 */ f8_pop(); break;
+ case 0x1d: /* 0001 1101 */ f8_lr_w_j(); break;
+ case 0x1e: /* 0001 1110 */ f8_lr_j_w(); break;
+ case 0x1f: /* 0001 1111 */ f8_inc(); break;
+
+ case 0x20: /* 0010 0000 */ f8_li(); break;
+ case 0x21: /* 0010 0001 */ f8_ni(); break;
+ case 0x22: /* 0010 0010 */ f8_oi(); break;
+ case 0x23: /* 0010 0011 */ f8_xi(); break;
+ case 0x24: /* 0010 0100 */ f8_ai(); break;
+ case 0x25: /* 0010 0101 */ f8_ci(); break;
+ case 0x26: /* 0010 0110 */ f8_in(); break;
+ case 0x27: /* 0010 0111 */ f8_out(); break;
+ case 0x28: /* 0010 1000 */ f8_pi(); break;
+ case 0x29: /* 0010 1001 */ f8_jmp(); break;
+ case 0x2a: /* 0010 1010 */ f8_dci(); break;
+ case 0x2b: /* 0010 1011 */ f8_nop(); break;
+ case 0x2c: /* 0010 1100 */ f8_xdc(); break;
+ case 0x2d: /* 0010 1101 */ illegal(); break;
+ case 0x2e: /* 0010 1110 */ illegal(); break;
+ case 0x2f: /* 0010 1111 */ illegal(); break;
+
+ case 0x30: /* 0011 0000 */ f8_ds_r( 0); break;
+ case 0x31: /* 0011 0001 */ f8_ds_r( 1); break;
+ case 0x32: /* 0011 0010 */ f8_ds_r( 2); break;
+ case 0x33: /* 0011 0011 */ f8_ds_r( 3); break;
+ case 0x34: /* 0011 0100 */ f8_ds_r( 4); break;
+ case 0x35: /* 0011 0101 */ f8_ds_r( 5); break;
+ case 0x36: /* 0011 0110 */ f8_ds_r( 6); break;
+ case 0x37: /* 0011 0111 */ f8_ds_r( 7); break;
+ case 0x38: /* 0011 1000 */ f8_ds_r( 8); break;
+ case 0x39: /* 0011 1001 */ f8_ds_r( 9); break;
+ case 0x3a: /* 0011 1010 */ f8_ds_r(10); break;
+ case 0x3b: /* 0011 1011 */ f8_ds_r(11); break;
+ case 0x3c: /* 0011 1100 */ f8_ds_isar(); break;
+ case 0x3d: /* 0011 1101 */ f8_ds_isar_i(); break;
+ case 0x3e: /* 0011 1110 */ f8_ds_isar_d(); break;
+ case 0x3f: /* 0011 1111 */ illegal(); break;
+
+ case 0x40: /* 0100 0000 */ f8_lr_a_r( 0); break;
+ case 0x41: /* 0100 0001 */ f8_lr_a_r( 1); break;
+ case 0x42: /* 0100 0010 */ f8_lr_a_r( 2); break;
+ case 0x43: /* 0100 0011 */ f8_lr_a_r( 3); break;
+ case 0x44: /* 0100 0100 */ f8_lr_a_r( 4); break;
+ case 0x45: /* 0100 0101 */ f8_lr_a_r( 5); break;
+ case 0x46: /* 0100 0110 */ f8_lr_a_r( 6); break;
+ case 0x47: /* 0100 0111 */ f8_lr_a_r( 7); break;
+ case 0x48: /* 0100 1000 */ f8_lr_a_r( 8); break;
+ case 0x49: /* 0100 1001 */ f8_lr_a_r( 9); break;
+ case 0x4a: /* 0100 1010 */ f8_lr_a_r(10); break;
+ case 0x4b: /* 0100 1011 */ f8_lr_a_r(11); break;
+ case 0x4c: /* 0100 1100 */ f8_lr_a_isar(); break;
+ case 0x4d: /* 0100 1101 */ f8_lr_a_isar_i(); break;
+ case 0x4e: /* 0100 1110 */ f8_lr_a_isar_d(); break;
+ case 0x4f: /* 0100 1111 */ illegal(); break;
+
+ case 0x50: /* 0101 0000 */ f8_lr_r_a( 0); break;
+ case 0x51: /* 0101 0001 */ f8_lr_r_a( 1); break;
+ case 0x52: /* 0101 0010 */ f8_lr_r_a( 2); break;
+ case 0x53: /* 0101 0011 */ f8_lr_r_a( 3); break;
+ case 0x54: /* 0101 0100 */ f8_lr_r_a( 4); break;
+ case 0x55: /* 0101 0101 */ f8_lr_r_a( 5); break;
+ case 0x56: /* 0101 0110 */ f8_lr_r_a( 6); break;
+ case 0x57: /* 0101 0111 */ f8_lr_r_a( 7); break;
+ case 0x58: /* 0101 1000 */ f8_lr_r_a( 8); break;
+ case 0x59: /* 0101 1001 */ f8_lr_r_a( 9); break;
+ case 0x5a: /* 0101 1010 */ f8_lr_r_a(10); break;
+ case 0x5b: /* 0101 1011 */ f8_lr_r_a(11); break;
+ case 0x5c: /* 0101 1100 */ f8_lr_isar_a(); break;
+ case 0x5d: /* 0101 1101 */ f8_lr_isar_i_a(); break;
+ case 0x5e: /* 0101 1110 */ f8_lr_isar_d_a(); break;
+ case 0x5f: /* 0101 1111 */ illegal(); break;
+
+ case 0x60: /* 0110 0000 */ f8_lisu(0x00); break;
+ case 0x61: /* 0110 0001 */ f8_lisu(0x08); break;
+ case 0x62: /* 0110 0010 */ f8_lisu(0x10); break;
+ case 0x63: /* 0110 0011 */ f8_lisu(0x18); break;
+ case 0x64: /* 0110 0100 */ f8_lisu(0x20); break;
+ case 0x65: /* 0110 0101 */ f8_lisu(0x28); break;
+ case 0x66: /* 0110 0110 */ f8_lisu(0x30); break;
+ case 0x67: /* 0110 0111 */ f8_lisu(0x38); break;
+ case 0x68: /* 0110 1000 */ f8_lisl(0x00); break;
+ case 0x69: /* 0110 1001 */ f8_lisl(0x01); break;
+ case 0x6a: /* 0110 1010 */ f8_lisl(0x02); break;
+ case 0x6b: /* 0110 1011 */ f8_lisl(0x03); break;
+ case 0x6c: /* 0110 1100 */ f8_lisl(0x04); break;
+ case 0x6d: /* 0110 1101 */ f8_lisl(0x05); break;
+ case 0x6e: /* 0110 1110 */ f8_lisl(0x06); break;
+ case 0x6f: /* 0110 1111 */ f8_lisl(0x07); break;
+
+ case 0x70: /* 0111 0000 */ f8_lis(0x0); break;
+ case 0x71: /* 0111 0001 */ f8_lis(0x1); break;
+ case 0x72: /* 0111 0010 */ f8_lis(0x2); break;
+ case 0x73: /* 0111 0011 */ f8_lis(0x3); break;
+ case 0x74: /* 0111 0100 */ f8_lis(0x4); break;
+ case 0x75: /* 0111 0101 */ f8_lis(0x5); break;
+ case 0x76: /* 0111 0110 */ f8_lis(0x6); break;
+ case 0x77: /* 0111 0111 */ f8_lis(0x7); break;
+ case 0x78: /* 0111 1000 */ f8_lis(0x8); break;
+ case 0x79: /* 0111 1001 */ f8_lis(0x9); break;
+ case 0x7a: /* 0111 1010 */ f8_lis(0xa); break;
+ case 0x7b: /* 0111 1011 */ f8_lis(0xb); break;
+ case 0x7c: /* 0111 1100 */ f8_lis(0xc); break;
+ case 0x7d: /* 0111 1101 */ f8_lis(0xd); break;
+ case 0x7e: /* 0111 1110 */ f8_lis(0xe); break;
+ case 0x7f: /* 0111 1111 */ f8_lis(0xf); break;
+
+ case 0x80: /* 1000 0000 */ f8_bt(0); break;
+ case 0x81: /* 1000 0001 */ f8_bt(1); break;
+ case 0x82: /* 1000 0010 */ f8_bt(2); break;
+ case 0x83: /* 1000 0011 */ f8_bt(3); break;
+ case 0x84: /* 1000 0100 */ f8_bt(4); break;
+ case 0x85: /* 1000 0101 */ f8_bt(5); break;
+ case 0x86: /* 1000 0110 */ f8_bt(6); break;
+ case 0x87: /* 1000 0111 */ f8_bt(7); break;
+ case 0x88: /* 1000 1000 */ f8_am(); break;
+ case 0x89: /* 1000 1001 */ f8_amd(); break;
+ case 0x8a: /* 1000 1010 */ f8_nm(); break;
+ case 0x8b: /* 1000 1011 */ f8_om(); break;
+ case 0x8c: /* 1000 1100 */ f8_xm(); break;
+ case 0x8d: /* 1000 1101 */ f8_cm(); break;
+ case 0x8e: /* 1000 1110 */ f8_adc(); break;
+ case 0x8f: /* 1000 1111 */ f8_br7(); break;
+
+ case 0x90: /* 1001 0000 */ f8_bf(0x0); break;
+ case 0x91: /* 1001 0001 */ f8_bf(0x1); break;
+ case 0x92: /* 1001 0010 */ f8_bf(0x2); break;
+ case 0x93: /* 1001 0011 */ f8_bf(0x3); break;
+ case 0x94: /* 1001 0100 */ f8_bf(0x4); break;
+ case 0x95: /* 1001 0101 */ f8_bf(0x5); break;
+ case 0x96: /* 1001 0110 */ f8_bf(0x6); break;
+ case 0x97: /* 1001 0111 */ f8_bf(0x7); break;
+ case 0x98: /* 1001 1000 */ f8_bf(0x8); break;
+ case 0x99: /* 1001 1001 */ f8_bf(0x9); break;
+ case 0x9a: /* 1001 1010 */ f8_bf(0xa); break;
+ case 0x9b: /* 1001 1011 */ f8_bf(0xb); break;
+ case 0x9c: /* 1001 1100 */ f8_bf(0xc); break;
+ case 0x9d: /* 1001 1101 */ f8_bf(0xd); break;
+ case 0x9e: /* 1001 1110 */ f8_bf(0xe); break;
+ case 0x9f: /* 1001 1111 */ f8_bf(0xf); break;
+
+ case 0xa0: /* 1010 0000 */ f8_ins_0(0x0); break;
+ case 0xa1: /* 1010 0001 */ f8_ins_0(0x1); break;
+ case 0xa2: /* 1010 0010 */ illegal(); break;
+ case 0xa3: /* 1010 0011 */ illegal(); break;
+ case 0xa4: /* 1010 0100 */ f8_ins_1(0x4); break;
+ case 0xa5: /* 1010 0101 */ f8_ins_1(0x5); break;
+ case 0xa6: /* 1010 0110 */ f8_ins_1(0x6); break;
+ case 0xa7: /* 1010 0111 */ f8_ins_1(0x7); break;
+ case 0xa8: /* 1010 1000 */ f8_ins_1(0x8); break;
+ case 0xa9: /* 1010 1001 */ f8_ins_1(0x9); break;
+ case 0xaa: /* 1010 1010 */ f8_ins_1(0xa); break;
+ case 0xab: /* 1010 1011 */ f8_ins_1(0xb); break;
+ case 0xac: /* 1010 1100 */ f8_ins_1(0xc); break;
+ case 0xad: /* 1010 1101 */ f8_ins_1(0xd); break;
+ case 0xae: /* 1010 1110 */ f8_ins_1(0xe); break;
+ case 0xaf: /* 1010 1111 */ f8_ins_1(0xf); break;
+
+ case 0xb0: /* 1011 0000 */ f8_outs_0(0x0); break;
+ case 0xb1: /* 1011 0001 */ f8_outs_0(0x1); break;
+ case 0xb2: /* 1011 0010 */ illegal(); break;
+ case 0xb3: /* 1011 0011 */ illegal(); break;
+ case 0xb4: /* 1011 0100 */ f8_outs_1(0x4); break;
+ case 0xb5: /* 1011 0101 */ f8_outs_1(0x5); break;
+ case 0xb6: /* 1011 0110 */ f8_outs_1(0x6); break;
+ case 0xb7: /* 1011 0111 */ f8_outs_1(0x7); break;
+ case 0xb8: /* 1011 1000 */ f8_outs_1(0x8); break;
+ case 0xb9: /* 1011 1001 */ f8_outs_1(0x9); break;
+ case 0xba: /* 1011 1010 */ f8_outs_1(0xa); break;
+ case 0xbb: /* 1011 1011 */ f8_outs_1(0xb); break;
+ case 0xbc: /* 1011 1100 */ f8_outs_1(0xc); break;
+ case 0xbd: /* 1011 1101 */ f8_outs_1(0xd); break;
+ case 0xbe: /* 1011 1110 */ f8_outs_1(0xe); break;
+ case 0xbf: /* 1011 1111 */ f8_outs_1(0xf); break;
+
+ case 0xc0: /* 1100 0000 */ f8_as(0x0); break;
+ case 0xc1: /* 1100 0001 */ f8_as(0x1); break;
+ case 0xc2: /* 1100 0010 */ f8_as(0x2); break;
+ case 0xc3: /* 1100 0011 */ f8_as(0x3); break;
+ case 0xc4: /* 1100 0100 */ f8_as(0x4); break;
+ case 0xc5: /* 1100 0101 */ f8_as(0x5); break;
+ case 0xc6: /* 1100 0110 */ f8_as(0x6); break;
+ case 0xc7: /* 1100 0111 */ f8_as(0x7); break;
+ case 0xc8: /* 1100 1000 */ f8_as(0x8); break;
+ case 0xc9: /* 1100 1001 */ f8_as(0x9); break;
+ case 0xca: /* 1100 1010 */ f8_as(0xa); break;
+ case 0xcb: /* 1100 1011 */ f8_as(0xb); break;
+ case 0xcc: /* 1100 1100 */ f8_as_isar(); break;
+ case 0xcd: /* 1100 1101 */ f8_as_isar_i(); break;
+ case 0xce: /* 1100 1110 */ f8_as_isar_d(); break;
+ case 0xcf: /* 1100 1111 */ illegal(); break;
+
+ case 0xd0: /* 1101 0000 */ f8_asd(0x0); break;
+ case 0xd1: /* 1101 0001 */ f8_asd(0x1); break;
+ case 0xd2: /* 1101 0010 */ f8_asd(0x2); break;
+ case 0xd3: /* 1101 0011 */ f8_asd(0x3); break;
+ case 0xd4: /* 1101 0100 */ f8_asd(0x4); break;
+ case 0xd5: /* 1101 0101 */ f8_asd(0x5); break;
+ case 0xd6: /* 1101 0110 */ f8_asd(0x6); break;
+ case 0xd7: /* 1101 0111 */ f8_asd(0x7); break;
+ case 0xd8: /* 1101 1000 */ f8_asd(0x8); break;
+ case 0xd9: /* 1101 1001 */ f8_asd(0x9); break;
+ case 0xda: /* 1101 1010 */ f8_asd(0xa); break;
+ case 0xdb: /* 1101 1011 */ f8_asd(0xb); break;
+ case 0xdc: /* 1101 1100 */ f8_asd_isar(); break;
+ case 0xdd: /* 1101 1101 */ f8_asd_isar_i(); break;
+ case 0xde: /* 1101 1110 */ f8_asd_isar_d(); break;
+ case 0xdf: /* 1101 1111 */ illegal(); break;
+
+ case 0xe0: /* 1110 0000 */ f8_xs(0x0); break;
+ case 0xe1: /* 1110 0001 */ f8_xs(0x1); break;
+ case 0xe2: /* 1110 0010 */ f8_xs(0x2); break;
+ case 0xe3: /* 1110 0011 */ f8_xs(0x3); break;
+ case 0xe4: /* 1110 0100 */ f8_xs(0x4); break;
+ case 0xe5: /* 1110 0101 */ f8_xs(0x5); break;
+ case 0xe6: /* 1110 0110 */ f8_xs(0x6); break;
+ case 0xe7: /* 1110 0111 */ f8_xs(0x7); break;
+ case 0xe8: /* 1110 1000 */ f8_xs(0x8); break;
+ case 0xe9: /* 1110 1001 */ f8_xs(0x9); break;
+ case 0xea: /* 1110 1010 */ f8_xs(0xa); break;
+ case 0xeb: /* 1110 1011 */ f8_xs(0xb); break;
+ case 0xec: /* 1110 1100 */ f8_xs_isar(); break;
+ case 0xed: /* 1110 1101 */ f8_xs_isar_i(); break;
+ case 0xee: /* 1110 1110 */ f8_xs_isar_d(); break;
+ case 0xef: /* 1110 1111 */ illegal(); break;
+
+ case 0xf0: /* 1111 0000 */ f8_ns(0x0); break;
+ case 0xf1: /* 1111 0001 */ f8_ns(0x1); break;
+ case 0xf2: /* 1111 0010 */ f8_ns(0x2); break;
+ case 0xf3: /* 1111 0011 */ f8_ns(0x3); break;
+ case 0xf4: /* 1111 0100 */ f8_ns(0x4); break;
+ case 0xf5: /* 1111 0101 */ f8_ns(0x5); break;
+ case 0xf6: /* 1111 0110 */ f8_ns(0x6); break;
+ case 0xf7: /* 1111 0111 */ f8_ns(0x7); break;
+ case 0xf8: /* 1111 1000 */ f8_ns(0x8); break;
+ case 0xf9: /* 1111 1001 */ f8_ns(0x9); break;
+ case 0xfa: /* 1111 1010 */ f8_ns(0xa); break;
+ case 0xfb: /* 1111 1011 */ f8_ns(0xb); break;
+ case 0xfc: /* 1111 1100 */ f8_ns_isar(); break;
+ case 0xfd: /* 1111 1101 */ f8_ns_isar_i(); break;
+ case 0xfe: /* 1111 1110 */ f8_ns_isar_d(); break;
+ case 0xff: /* 1111 1111 */ illegal(); break;
+ }
+ switch (op) {
+ case 0x0d:case 0x1b:case 0x1c:case 0x1d:
+ case 0x27:case 0x28:case 0x29:
+ case 0xb4:case 0xb5:case 0xb6:case 0xb7:
+ case 0xb8:case 0xb9:case 0xba:case 0xbb:
+ case 0xbc:case 0xbd:case 0xbe:case 0xbf:
+ ROMC_00(cS);
+ break;
+ default:
+ if (f8.w&I && f8.irq_request) {
+ ROMC_1C(cL);
+ ROMC_0F();
+ ROMC_13();
+ }
+ if((op>=0x30)&&(op<=0x3f)) /* SKR - DS is a long cycle inst */
+ ROMC_00(cL);
+ else
+ ROMC_00(cS);
+ break;
+ }
+
+ } while( f8_icount > 0 );
+
+ return cycles - f8_icount;
+}
+
+static void f8_get_context (void *dst)
+{
+ if (dst)
+ *(f8_Regs *) dst = f8;
+}
+
+static void f8_set_context (void *src)
+{
+ if (src)
+ f8 = *(f8_Regs *) src;
+}
+
+#ifdef MAME_DEBUG
+unsigned f8_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+static void f8_init (int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ f8.irq_callback = irqcallback;
+}
+
+static void f8_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_SP: f8.pc1 = info->i; break;
+ case CPUINFO_INT_PC:
+ f8.pc0 = info->i;
+ f8.dbus = cpu_readop(f8.pc0);
+ f8.pc0 += 1;
+ break;
+ case CPUINFO_INT_PREVIOUSPC: break; /* TODO? */
+ case CPUINFO_INT_INPUT_STATE: f8.irq_request = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_PC0:
+ f8.pc0 = info->i;
+ f8.dbus = cpu_readop(f8.pc0);
+ f8.pc0 += 1;
+ break;
+ case CPUINFO_INT_REGISTER + F8_PC1: f8.pc1 = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_DC0: f8.dc0 = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_DC1: f8.dc1 = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_W: f8.w = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_A: f8.a = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_IS: f8.is = info->i & 0x3f; break;
+ case CPUINFO_INT_REGISTER + F8_J: f8.r[ 9] = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_HU: f8.r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_HL: f8.r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_KU: f8.r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_KL: f8.r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_QU: f8.r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + F8_QL: f8.r[15] = info->i; break;
+
+ case CPUINFO_INT_REGISTER + F8_R0:
+ case CPUINFO_INT_REGISTER + F8_R1:
+ case CPUINFO_INT_REGISTER + F8_R2:
+ case CPUINFO_INT_REGISTER + F8_R3:
+ case CPUINFO_INT_REGISTER + F8_R4:
+ case CPUINFO_INT_REGISTER + F8_R5:
+ case CPUINFO_INT_REGISTER + F8_R6:
+ case CPUINFO_INT_REGISTER + F8_R7:
+ case CPUINFO_INT_REGISTER + F8_R8:
+ f8.r[state - (CPUINFO_INT_REGISTER + F8_R0)]=info->i;
+ break;
+
+ case CPUINFO_INT_REGISTER + F8_R16:
+ case CPUINFO_INT_REGISTER + F8_R17:
+ case CPUINFO_INT_REGISTER + F8_R18:
+ case CPUINFO_INT_REGISTER + F8_R19:
+ case CPUINFO_INT_REGISTER + F8_R20:
+ case CPUINFO_INT_REGISTER + F8_R21:
+ case CPUINFO_INT_REGISTER + F8_R22:
+ case CPUINFO_INT_REGISTER + F8_R23:
+ case CPUINFO_INT_REGISTER + F8_R24:
+ case CPUINFO_INT_REGISTER + F8_R25:
+ case CPUINFO_INT_REGISTER + F8_R26:
+ case CPUINFO_INT_REGISTER + F8_R27:
+ case CPUINFO_INT_REGISTER + F8_R28:
+ case CPUINFO_INT_REGISTER + F8_R29:
+ case CPUINFO_INT_REGISTER + F8_R30:
+ case CPUINFO_INT_REGISTER + F8_R31:
+ case CPUINFO_INT_REGISTER + F8_R32:
+ case CPUINFO_INT_REGISTER + F8_R33:
+ case CPUINFO_INT_REGISTER + F8_R34:
+ case CPUINFO_INT_REGISTER + F8_R35:
+ case CPUINFO_INT_REGISTER + F8_R36:
+ case CPUINFO_INT_REGISTER + F8_R37:
+ case CPUINFO_INT_REGISTER + F8_R38:
+ case CPUINFO_INT_REGISTER + F8_R39:
+ case CPUINFO_INT_REGISTER + F8_R40:
+ case CPUINFO_INT_REGISTER + F8_R41:
+ case CPUINFO_INT_REGISTER + F8_R42:
+ case CPUINFO_INT_REGISTER + F8_R43:
+ case CPUINFO_INT_REGISTER + F8_R44:
+ case CPUINFO_INT_REGISTER + F8_R45:
+ case CPUINFO_INT_REGISTER + F8_R46:
+ case CPUINFO_INT_REGISTER + F8_R47:
+ case CPUINFO_INT_REGISTER + F8_R48:
+ case CPUINFO_INT_REGISTER + F8_R49:
+ case CPUINFO_INT_REGISTER + F8_R50:
+ case CPUINFO_INT_REGISTER + F8_R51:
+ case CPUINFO_INT_REGISTER + F8_R52:
+ case CPUINFO_INT_REGISTER + F8_R53:
+ case CPUINFO_INT_REGISTER + F8_R54:
+ case CPUINFO_INT_REGISTER + F8_R55:
+ case CPUINFO_INT_REGISTER + F8_R56:
+ case CPUINFO_INT_REGISTER + F8_R57:
+ case CPUINFO_INT_REGISTER + F8_R58:
+ case CPUINFO_INT_REGISTER + F8_R59:
+ case CPUINFO_INT_REGISTER + F8_R60:
+ case CPUINFO_INT_REGISTER + F8_R61:
+ case CPUINFO_INT_REGISTER + F8_R62:
+ case CPUINFO_INT_REGISTER + F8_R63:
+ f8.r[state - (CPUINFO_INT_REGISTER + F8_R16) + 16]=info->i;
+ break;
+ }
+ return;
+}
+
+void f8_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(f8_Regs); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 7; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_SP: info->i = f8.pc1; break;
+ case CPUINFO_INT_PC: info->i = (f8.pc0 - 1) & 0xffff; break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* TODO??? */ break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = f8.irq_request; break;
+
+ case CPUINFO_INT_REGISTER + F8_PC0: info->i = (f8.pc0 - 1) & 0xffff; break;
+ case CPUINFO_INT_REGISTER + F8_PC1: info->i = f8.pc1; break;
+ case CPUINFO_INT_REGISTER + F8_DC0: info->i = f8.dc0; break;
+ case CPUINFO_INT_REGISTER + F8_DC1: info->i = f8.dc1; break;
+ case CPUINFO_INT_REGISTER + F8_W: info->i = f8.w; break;
+ case CPUINFO_INT_REGISTER + F8_A: info->i = f8.a; break;
+ case CPUINFO_INT_REGISTER + F8_IS: info->i = f8.is; break;
+ case CPUINFO_INT_REGISTER + F8_J: info->i = f8.r[ 9]; break;
+ case CPUINFO_INT_REGISTER + F8_HU: info->i = f8.r[10]; break;
+ case CPUINFO_INT_REGISTER + F8_HL: info->i = f8.r[11]; break;
+ case CPUINFO_INT_REGISTER + F8_KU: info->i = f8.r[12]; break;
+ case CPUINFO_INT_REGISTER + F8_KL: info->i = f8.r[13]; break;
+ case CPUINFO_INT_REGISTER + F8_QU: info->i = f8.r[14]; break;
+ case CPUINFO_INT_REGISTER + F8_QL: info->i = f8.r[15]; break;
+
+ case CPUINFO_INT_REGISTER + F8_R0:
+ case CPUINFO_INT_REGISTER + F8_R1:
+ case CPUINFO_INT_REGISTER + F8_R2:
+ case CPUINFO_INT_REGISTER + F8_R3:
+ case CPUINFO_INT_REGISTER + F8_R4:
+ case CPUINFO_INT_REGISTER + F8_R5:
+ case CPUINFO_INT_REGISTER + F8_R6:
+ case CPUINFO_INT_REGISTER + F8_R7:
+ case CPUINFO_INT_REGISTER + F8_R8:
+ info->i = f8.r[state - (CPUINFO_INT_REGISTER + F8_R0)]; break;
+
+
+ case CPUINFO_INT_REGISTER + F8_R16:
+ case CPUINFO_INT_REGISTER + F8_R17:
+ case CPUINFO_INT_REGISTER + F8_R18:
+ case CPUINFO_INT_REGISTER + F8_R19:
+ case CPUINFO_INT_REGISTER + F8_R20:
+ case CPUINFO_INT_REGISTER + F8_R21:
+ case CPUINFO_INT_REGISTER + F8_R22:
+ case CPUINFO_INT_REGISTER + F8_R23:
+ case CPUINFO_INT_REGISTER + F8_R24:
+ case CPUINFO_INT_REGISTER + F8_R25:
+ case CPUINFO_INT_REGISTER + F8_R26:
+ case CPUINFO_INT_REGISTER + F8_R27:
+ case CPUINFO_INT_REGISTER + F8_R28:
+ case CPUINFO_INT_REGISTER + F8_R29:
+ case CPUINFO_INT_REGISTER + F8_R30:
+ case CPUINFO_INT_REGISTER + F8_R31:
+ case CPUINFO_INT_REGISTER + F8_R32:
+ case CPUINFO_INT_REGISTER + F8_R33:
+ case CPUINFO_INT_REGISTER + F8_R34:
+ case CPUINFO_INT_REGISTER + F8_R35:
+ case CPUINFO_INT_REGISTER + F8_R36:
+ case CPUINFO_INT_REGISTER + F8_R37:
+ case CPUINFO_INT_REGISTER + F8_R38:
+ case CPUINFO_INT_REGISTER + F8_R39:
+ case CPUINFO_INT_REGISTER + F8_R40:
+ case CPUINFO_INT_REGISTER + F8_R41:
+ case CPUINFO_INT_REGISTER + F8_R42:
+ case CPUINFO_INT_REGISTER + F8_R43:
+ case CPUINFO_INT_REGISTER + F8_R44:
+ case CPUINFO_INT_REGISTER + F8_R45:
+ case CPUINFO_INT_REGISTER + F8_R46:
+ case CPUINFO_INT_REGISTER + F8_R47:
+ case CPUINFO_INT_REGISTER + F8_R48:
+ case CPUINFO_INT_REGISTER + F8_R49:
+ case CPUINFO_INT_REGISTER + F8_R50:
+ case CPUINFO_INT_REGISTER + F8_R51:
+ case CPUINFO_INT_REGISTER + F8_R52:
+ case CPUINFO_INT_REGISTER + F8_R53:
+ case CPUINFO_INT_REGISTER + F8_R54:
+ case CPUINFO_INT_REGISTER + F8_R55:
+ case CPUINFO_INT_REGISTER + F8_R56:
+ case CPUINFO_INT_REGISTER + F8_R57:
+ case CPUINFO_INT_REGISTER + F8_R58:
+ case CPUINFO_INT_REGISTER + F8_R59:
+ case CPUINFO_INT_REGISTER + F8_R60:
+ case CPUINFO_INT_REGISTER + F8_R61:
+ case CPUINFO_INT_REGISTER + F8_R62:
+ case CPUINFO_INT_REGISTER + F8_R63:
+ info->i = f8.r[state - (CPUINFO_INT_REGISTER + F8_R16) + 16]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = f8_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = f8_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = f8_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = f8_init; break;
+ case CPUINFO_PTR_RESET: info->reset = f8_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = f8_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = f8_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &f8_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "F8"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "Fairchild F8"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(),
+ "Copyright (c) 2000 Juergen Buchmueller, all rights reserved.");
+ break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s = cpuintrf_temp_str(), "%c%c%c%c%c",
+ f8.w & 0x10 ? 'I':'.',
+ f8.w & 0x08 ? 'O':'.',
+ f8.w & 0x04 ? 'Z':'.',
+ f8.w & 0x02 ? 'C':'.',
+ f8.w & 0x01 ? 'S':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER+F8_PC0:sprintf(info->s = cpuintrf_temp_str(), "PC0:%04X", ((f8.pc0) - 1) & 0xffff); break;
+ case CPUINFO_STR_REGISTER+F8_PC1:sprintf(info->s = cpuintrf_temp_str(), "PC1:%04X", f8.pc1); break;
+ case CPUINFO_STR_REGISTER+F8_DC0:sprintf(info->s = cpuintrf_temp_str(), "DC0:%04X", f8.dc0); break;
+ case CPUINFO_STR_REGISTER+F8_DC1:sprintf(info->s = cpuintrf_temp_str(), "DC1:%04X", f8.dc1); break;
+ case CPUINFO_STR_REGISTER+F8_W: sprintf(info->s = cpuintrf_temp_str(), "W :%02X", f8.w); break;
+ case CPUINFO_STR_REGISTER+F8_A: sprintf(info->s = cpuintrf_temp_str(), "A :%02X", f8.a); break;
+ case CPUINFO_STR_REGISTER+F8_IS: sprintf(info->s = cpuintrf_temp_str(), "IS :%02X", f8.is); break;
+ case CPUINFO_STR_REGISTER+F8_J: sprintf(info->s = cpuintrf_temp_str(), "J :%02X", f8.r[9]); break;
+ case CPUINFO_STR_REGISTER+F8_HU: sprintf(info->s = cpuintrf_temp_str(), "HU :%02X", f8.r[10]); break;
+ case CPUINFO_STR_REGISTER+F8_HL: sprintf(info->s = cpuintrf_temp_str(), "HL :%02X", f8.r[11]); break;
+ case CPUINFO_STR_REGISTER+F8_KU: sprintf(info->s = cpuintrf_temp_str(), "KU :%02X", f8.r[12]); break;
+ case CPUINFO_STR_REGISTER+F8_KL: sprintf(info->s = cpuintrf_temp_str(), "KL :%02X", f8.r[13]); break;
+ case CPUINFO_STR_REGISTER+F8_QU: sprintf(info->s = cpuintrf_temp_str(), "QU :%02X", f8.r[14]); break;
+ case CPUINFO_STR_REGISTER+F8_QL: sprintf(info->s = cpuintrf_temp_str(), "QL :%02X", f8.r[15]); break;
+ case CPUINFO_STR_REGISTER+F8_R0: sprintf(info->s = cpuintrf_temp_str(), "R0 :%02X", f8.r[0]); break;
+ case CPUINFO_STR_REGISTER+F8_R1: sprintf(info->s = cpuintrf_temp_str(), "R1 :%02X", f8.r[1]); break;
+ case CPUINFO_STR_REGISTER+F8_R2: sprintf(info->s = cpuintrf_temp_str(), "R2 :%02X", f8.r[2]); break;
+ case CPUINFO_STR_REGISTER+F8_R3: sprintf(info->s = cpuintrf_temp_str(), "R3 :%02X", f8.r[3]); break;
+ case CPUINFO_STR_REGISTER+F8_R4: sprintf(info->s = cpuintrf_temp_str(), "R4 :%02X", f8.r[4]); break;
+ case CPUINFO_STR_REGISTER+F8_R5: sprintf(info->s = cpuintrf_temp_str(), "R5 :%02X", f8.r[5]); break;
+ case CPUINFO_STR_REGISTER+F8_R6: sprintf(info->s = cpuintrf_temp_str(), "R6 :%02X", f8.r[6]); break;
+ case CPUINFO_STR_REGISTER+F8_R7: sprintf(info->s = cpuintrf_temp_str(), "R7 :%02X", f8.r[7]); break;
+ case CPUINFO_STR_REGISTER+F8_R8: sprintf(info->s = cpuintrf_temp_str(), "R8 :%02X", f8.r[8]); break;
+ case CPUINFO_STR_REGISTER+F8_R16: sprintf(info->s = cpuintrf_temp_str(), "R16 :%02X", f8.r[16]); break;
+ case CPUINFO_STR_REGISTER+F8_R17: sprintf(info->s = cpuintrf_temp_str(), "R17 :%02X", f8.r[17]); break;
+ case CPUINFO_STR_REGISTER+F8_R18: sprintf(info->s = cpuintrf_temp_str(), "R18 :%02X", f8.r[18]); break;
+ case CPUINFO_STR_REGISTER+F8_R19: sprintf(info->s = cpuintrf_temp_str(), "R19 :%02X", f8.r[19]); break;
+ case CPUINFO_STR_REGISTER+F8_R20: sprintf(info->s = cpuintrf_temp_str(), "R20 :%02X", f8.r[20]); break;
+ case CPUINFO_STR_REGISTER+F8_R21: sprintf(info->s = cpuintrf_temp_str(), "R21 :%02X", f8.r[21]); break;
+ case CPUINFO_STR_REGISTER+F8_R22: sprintf(info->s = cpuintrf_temp_str(), "R22 :%02X", f8.r[22]); break;
+ case CPUINFO_STR_REGISTER+F8_R23: sprintf(info->s = cpuintrf_temp_str(), "R23 :%02X", f8.r[23]); break;
+ case CPUINFO_STR_REGISTER+F8_R24: sprintf(info->s = cpuintrf_temp_str(), "R24 :%02X", f8.r[24]); break;
+ case CPUINFO_STR_REGISTER+F8_R25: sprintf(info->s = cpuintrf_temp_str(), "R25 :%02X", f8.r[25]); break;
+ case CPUINFO_STR_REGISTER+F8_R26: sprintf(info->s = cpuintrf_temp_str(), "R26 :%02X", f8.r[26]); break;
+ case CPUINFO_STR_REGISTER+F8_R27: sprintf(info->s = cpuintrf_temp_str(), "R27 :%02X", f8.r[27]); break;
+ case CPUINFO_STR_REGISTER+F8_R28: sprintf(info->s = cpuintrf_temp_str(), "R28 :%02X", f8.r[28]); break;
+ case CPUINFO_STR_REGISTER+F8_R29: sprintf(info->s = cpuintrf_temp_str(), "R29 :%02X", f8.r[29]); break;
+ case CPUINFO_STR_REGISTER+F8_R30: sprintf(info->s = cpuintrf_temp_str(), "R30 :%02X", f8.r[30]); break;
+ case CPUINFO_STR_REGISTER+F8_R31: sprintf(info->s = cpuintrf_temp_str(), "R31 :%02X", f8.r[31]); break;
+ case CPUINFO_STR_REGISTER+F8_R32: sprintf(info->s = cpuintrf_temp_str(), "R32 :%02X", f8.r[32]); break;
+ case CPUINFO_STR_REGISTER+F8_R33: sprintf(info->s = cpuintrf_temp_str(), "R33 :%02X", f8.r[33]); break;
+ case CPUINFO_STR_REGISTER+F8_R34: sprintf(info->s = cpuintrf_temp_str(), "R34 :%02X", f8.r[34]); break;
+ case CPUINFO_STR_REGISTER+F8_R35: sprintf(info->s = cpuintrf_temp_str(), "R35 :%02X", f8.r[35]); break;
+ case CPUINFO_STR_REGISTER+F8_R36: sprintf(info->s = cpuintrf_temp_str(), "R36 :%02X", f8.r[36]); break;
+ case CPUINFO_STR_REGISTER+F8_R37: sprintf(info->s = cpuintrf_temp_str(), "R37 :%02X", f8.r[37]); break;
+ case CPUINFO_STR_REGISTER+F8_R38: sprintf(info->s = cpuintrf_temp_str(), "R38 :%02X", f8.r[38]); break;
+ case CPUINFO_STR_REGISTER+F8_R39: sprintf(info->s = cpuintrf_temp_str(), "R39 :%02X", f8.r[39]); break;
+ case CPUINFO_STR_REGISTER+F8_R40: sprintf(info->s = cpuintrf_temp_str(), "R40 :%02X", f8.r[40]); break;
+ case CPUINFO_STR_REGISTER+F8_R41: sprintf(info->s = cpuintrf_temp_str(), "R41 :%02X", f8.r[41]); break;
+ case CPUINFO_STR_REGISTER+F8_R42: sprintf(info->s = cpuintrf_temp_str(), "R42 :%02X", f8.r[42]); break;
+ case CPUINFO_STR_REGISTER+F8_R43: sprintf(info->s = cpuintrf_temp_str(), "R43 :%02X", f8.r[43]); break;
+ case CPUINFO_STR_REGISTER+F8_R44: sprintf(info->s = cpuintrf_temp_str(), "R44 :%02X", f8.r[44]); break;
+ case CPUINFO_STR_REGISTER+F8_R45: sprintf(info->s = cpuintrf_temp_str(), "R45 :%02X", f8.r[45]); break;
+ case CPUINFO_STR_REGISTER+F8_R46: sprintf(info->s = cpuintrf_temp_str(), "R46 :%02X", f8.r[46]); break;
+ case CPUINFO_STR_REGISTER+F8_R47: sprintf(info->s = cpuintrf_temp_str(), "R47 :%02X", f8.r[47]); break;
+ case CPUINFO_STR_REGISTER+F8_R48: sprintf(info->s = cpuintrf_temp_str(), "R48 :%02X", f8.r[48]); break;
+ case CPUINFO_STR_REGISTER+F8_R49: sprintf(info->s = cpuintrf_temp_str(), "R49 :%02X", f8.r[49]); break;
+ case CPUINFO_STR_REGISTER+F8_R50: sprintf(info->s = cpuintrf_temp_str(), "R50 :%02X", f8.r[50]); break;
+ case CPUINFO_STR_REGISTER+F8_R51: sprintf(info->s = cpuintrf_temp_str(), "R51 :%02X", f8.r[51]); break;
+ case CPUINFO_STR_REGISTER+F8_R52: sprintf(info->s = cpuintrf_temp_str(), "R52 :%02X", f8.r[52]); break;
+ case CPUINFO_STR_REGISTER+F8_R53: sprintf(info->s = cpuintrf_temp_str(), "R53 :%02X", f8.r[53]); break;
+ case CPUINFO_STR_REGISTER+F8_R54: sprintf(info->s = cpuintrf_temp_str(), "R54 :%02X", f8.r[54]); break;
+ case CPUINFO_STR_REGISTER+F8_R55: sprintf(info->s = cpuintrf_temp_str(), "R55 :%02X", f8.r[55]); break;
+ case CPUINFO_STR_REGISTER+F8_R56: sprintf(info->s = cpuintrf_temp_str(), "R56 :%02X", f8.r[56]); break;
+ case CPUINFO_STR_REGISTER+F8_R57: sprintf(info->s = cpuintrf_temp_str(), "R57 :%02X", f8.r[57]); break;
+ case CPUINFO_STR_REGISTER+F8_R58: sprintf(info->s = cpuintrf_temp_str(), "R58 :%02X", f8.r[58]); break;
+ case CPUINFO_STR_REGISTER+F8_R59: sprintf(info->s = cpuintrf_temp_str(), "R59 :%02X", f8.r[59]); break;
+ case CPUINFO_STR_REGISTER+F8_R60: sprintf(info->s = cpuintrf_temp_str(), "R60 :%02X", f8.r[60]); break;
+ case CPUINFO_STR_REGISTER+F8_R61: sprintf(info->s = cpuintrf_temp_str(), "R61 :%02X", f8.r[61]); break;
+ case CPUINFO_STR_REGISTER+F8_R62: sprintf(info->s = cpuintrf_temp_str(), "R62 :%02X", f8.r[62]); break;
+ case CPUINFO_STR_REGISTER+F8_R63: sprintf(info->s = cpuintrf_temp_str(), "R63 :%02X", f8.r[63]); break;
+
+ }
+
+ return;
+}
+
+
+
+
+
+
diff --git a/src/emu/cpu/f8/f8.h b/src/emu/cpu/f8/f8.h
new file mode 100644
index 00000000000..b8530386663
--- /dev/null
+++ b/src/emu/cpu/f8/f8.h
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ *
+ * f8.h
+ * Portable Fairchild F8 emulator interface
+ *
+ * Copyright (c) 2000 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#ifndef _F8_H
+#define _F8_H
+
+#include "cpuintrf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ F8_PC0=1, F8_PC1, F8_DC0, F8_DC1, F8_W, F8_A, F8_IS,
+ F8_J, F8_HU, F8_HL, F8_KU, F8_KL, F8_QU, F8_QL,
+
+ F8_R0, F8_R1, F8_R2, F8_R3, F8_R4, F8_R5, F8_R6, F8_R7, F8_R8,
+ F8_R16, F8_R17, F8_R18, F8_R19, F8_R20, F8_R21, F8_R22, F8_R23,
+ F8_R24, F8_R25, F8_R26, F8_R27, F8_R28, F8_R29, F8_R30, F8_R31,
+ F8_R32, F8_R33, F8_R34, F8_R35, F8_R36, F8_R37, F8_R38, F8_R39,
+ F8_R40, F8_R41, F8_R42, F8_R43, F8_R44, F8_R45, F8_R46, F8_R47,
+ F8_R48, F8_R49, F8_R50, F8_R51, F8_R52, F8_R53, F8_R54, F8_R55,
+ F8_R56, F8_R57, F8_R58, F8_R59, F8_R60, F8_R61, F8_R62, F8_R63
+};
+
+#define F8_INT_NONE 0
+#define F8_INT_INTR 1
+
+void f8_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _F8_H */
+
+
diff --git a/src/emu/cpu/f8/f8dasm.c b/src/emu/cpu/f8/f8dasm.c
new file mode 100644
index 00000000000..c8f1f4ae8b7
--- /dev/null
+++ b/src/emu/cpu/f8/f8dasm.c
@@ -0,0 +1,510 @@
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "f8.h"
+
+static const char *rname[16] = {
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "J", "HU", "HL", "KU", "KL", "QU", "QL"
+};
+
+unsigned f8_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ unsigned size = 0;
+ UINT8 op = oprom[size++];
+
+ switch( op )
+ {
+ /* opcode bitmask */
+ case 0x00: /* 0000 0000 */
+ sprintf(buffer, "LR A,KU");
+ break;
+ case 0x01: /* 0000 0001 */
+ sprintf(buffer, "LR A,KL");
+ break;
+ case 0x02: /* 0000 0010 */
+ sprintf(buffer, "LR A,QU");
+ break;
+ case 0x03: /* 0000 0011 */
+ sprintf(buffer, "LR A,QL");
+ break;
+ case 0x04: /* 0000 0100 */
+ sprintf(buffer, "LR KU,A");
+ break;
+ case 0x05: /* 0000 0101 */
+ sprintf(buffer, "LR KL,A");
+ break;
+ case 0x06: /* 0000 0110 */
+ sprintf(buffer, "LR QU,A");
+ break;
+ case 0x07: /* 0000 0111 */
+ sprintf(buffer, "LR QL,A");
+ break;
+
+ case 0x08: /* 0000 1000 */
+ sprintf(buffer, "LR K,P");
+ break;
+ case 0x09: /* 0000 1001 */
+ sprintf(buffer, "LR P,K");
+ break;
+ case 0x0a: /* 0000 1010 */
+ sprintf(buffer, "LR A,IS");
+ break;
+ case 0x0b: /* 0000 1011 */
+ sprintf(buffer, "LR IS,A");
+ break;
+
+ case 0x0c: /* 0000 1100 */
+ sprintf(buffer, "PK") ;
+ break;
+ case 0x0d: /* 0000 1101 */
+ sprintf(buffer, "LR P0,Q");
+ break;
+ case 0x0e: /* 0000 1110 */
+ sprintf(buffer, "LR Q,DC");
+ break;
+ case 0x0f: /* 0000 1111 */
+ sprintf(buffer, "LR DC,Q");
+ break;
+ case 0x10: /* 0001 0000 */
+ sprintf(buffer, "LR DC,H");
+ break;
+ case 0x11: /* 0001 0001 */
+ sprintf(buffer, "LR H,DC");
+ break;
+ case 0x12: /* 0001 0010 */
+ sprintf(buffer, "SR 1");
+ break;
+ case 0x13: /* 0001 0011 */
+ sprintf(buffer, "SL 1");
+ break;
+ case 0x14: /* 0001 0100 */
+ sprintf(buffer, "SR 4");
+ break;
+ case 0x15: /* 0001 0101 */
+ sprintf(buffer, "SL 4");
+ break;
+ case 0x16: /* 0001 0110 */
+ sprintf(buffer, "LM") ;
+ break;
+ case 0x17: /* 0001 0111 */
+ sprintf(buffer, "ST");
+ break;
+ case 0x18: /* 0001 1000 */
+ sprintf(buffer, "COM");
+ break;
+ case 0x19: /* 0001 1001 */
+ sprintf(buffer, "LNK");
+ break;
+ case 0x1a: /* 0001 1010 */
+ sprintf(buffer, "DI");
+ break;
+ case 0x1b: /* 0001 1011 */
+ sprintf(buffer, "EI");
+ break;
+ case 0x1c: /* 0001 1100 */
+ sprintf(buffer, "POP");
+ break;
+ case 0x1d: /* 0001 1101 */
+ sprintf(buffer, "LR W,J");
+ break;
+ case 0x1e: /* 0001 1110 */
+ sprintf(buffer, "LR J,W");
+ break;
+ case 0x1f: /* 0001 1111 */
+ sprintf(buffer, "INC");
+ break;
+ case 0x20: /* 0010 0000 */
+ sprintf(buffer, "LI $%02X", oprom[size++]);
+ break;
+ case 0x21: /* 0010 0001 */
+ sprintf(buffer, "NI $%02X", oprom[size++]);
+ break;
+ case 0x22: /* 0010 0010 */
+ sprintf(buffer, "OI $%02X", oprom[size++]);
+ break;
+ case 0x23: /* 0010 0011 */
+ sprintf(buffer, "XI $%02X", oprom[size++]);
+ break;
+ case 0x24: /* 0010 0100 */
+ sprintf(buffer, "AI $%02X", oprom[size++]);
+ break;
+ case 0x25: /* 0010 0101 */
+ sprintf(buffer, "CI $%02X", oprom[size++]);
+ break;
+ case 0x26: /* 0010 0110 */
+ sprintf(buffer, "IN $%02X", oprom[size++]);
+ break;
+ case 0x27: /* 0010 0111 */
+ sprintf(buffer, "OUT $%02X", oprom[size++]);
+ break;
+ case 0x28: /* 0010 1000 */
+ sprintf(buffer, "PI $%02X$%02X", oprom[size + 0], oprom[size + 1]);
+ size += 2;
+ break;
+ case 0x29: /* 0010 1001 */
+ sprintf(buffer, "JMP $%02X$%02X", oprom[size + 0], oprom[size + 1]);
+ size += 2;
+ break;
+ case 0x2a: /* 0010 1010 */
+ sprintf(buffer, "DCI $%02X$%02X", oprom[size + 0], oprom[size + 1]);
+ size += 2;
+ break;
+ case 0x2b: /* 0010 1011 */
+ sprintf(buffer, "NOP");
+ break;
+ case 0x2c: /* 0010 1100 */
+ sprintf(buffer, "XDC");
+ break;
+ case 0x2d: /* 0010 1101 */
+ case 0x2e: /* 0010 1110 */
+ case 0x2f: /* 0010 1111 */
+ sprintf(buffer, "??? $%02X",op);
+ break;
+
+ case 0x30: /* 0011 0000 */
+ case 0x31: /* 0011 0001 */
+ case 0x32: /* 0011 0010 */
+ case 0x33: /* 0011 0011 */
+ case 0x34: /* 0011 0100 */
+ case 0x35: /* 0011 0101 */
+ case 0x36: /* 0011 0110 */
+ case 0x37: /* 0011 0111 */
+ case 0x38: /* 0011 1000 */
+ case 0x39: /* 0011 1001 */
+ case 0x3a: /* 0011 1010 */
+ case 0x3b: /* 0011 1011 */
+ sprintf(buffer, "DS %s",rname[op & 15]);
+ break;
+ case 0x3c: /* 0011 1100 */
+ sprintf(buffer, "DS (IS)");
+ break;
+ case 0x3d: /* 0011 1101 */
+ sprintf(buffer, "DS (IS++)");
+ break;
+ case 0x3e: /* 0011 1110 */
+ sprintf(buffer, "DS (IS--)");
+ break;
+ case 0x3f: /* 0011 1111 */
+ sprintf(buffer, "??? $%02X",op);
+ break;
+
+ case 0x40: /* 0100 0000 */
+ case 0x41: /* 0100 0001 */
+ case 0x42: /* 0100 0010 */
+ case 0x43: /* 0100 0011 */
+ case 0x44: /* 0100 0100 */
+ case 0x45: /* 0100 0101 */
+ case 0x46: /* 0100 0110 */
+ case 0x47: /* 0100 0111 */
+ case 0x48: /* 0100 1000 */
+ case 0x49: /* 0100 1001 */
+ case 0x4a: /* 0100 1010 */
+ case 0x4b: /* 0100 1011 */
+ sprintf(buffer, "LR A,%s",rname[op & 15]);
+ break;
+ case 0x4c: /* 0100 1100 */
+ sprintf(buffer, "LR A,(IS)");
+ break;
+ case 0x4d: /* 0100 1101 */
+ sprintf(buffer, "LR A,(IS++)");
+ break;
+ case 0x4e: /* 0100 1110 */
+ sprintf(buffer, "LR A,(IS--)");
+ break;
+ case 0x4f: /* 0100 1111 */
+ sprintf(buffer, "??? $%02X",op);
+ break;
+
+ case 0x50: /* 0101 0000 */
+ case 0x51: /* 0101 0001 */
+ case 0x52: /* 0101 0010 */
+ case 0x53: /* 0101 0011 */
+ case 0x54: /* 0101 0100 */
+ case 0x55: /* 0101 0101 */
+ case 0x56: /* 0101 0110 */
+ case 0x57: /* 0101 0111 */
+ case 0x58: /* 0101 1000 */
+ case 0x59: /* 0101 1001 */
+ case 0x5a: /* 0101 1010 */
+ case 0x5b: /* 0101 1011 */
+ sprintf(buffer, "LR %s,A",rname[op & 15]);
+ break;
+ case 0x5c: /* 0101 1100 */
+ sprintf(buffer, "LR (IS),A");
+ break;
+ case 0x5d: /* 0101 1101 */
+ sprintf(buffer, "LR (IS++),A");
+ break;
+ case 0x5e: /* 0101 1110 */
+ sprintf(buffer, "LR (IS--),A");
+ break;
+ case 0x5f: /* 0101 1111 */
+ sprintf(buffer, "??? $%02X",op);
+ break;
+
+ case 0x60: /* 0110 0000 */
+ case 0x61: /* 0110 0001 */
+ case 0x62: /* 0110 0010 */
+ case 0x63: /* 0110 0011 */
+ case 0x64: /* 0110 0100 */
+ case 0x65: /* 0110 0101 */
+ case 0x66: /* 0110 0110 */
+ case 0x67: /* 0110 0111 */
+ sprintf(buffer, "LISU $%02X", op & 0x07);
+ break;
+ case 0x68: /* 0110 1000 */
+ case 0x69: /* 0110 1001 */
+ case 0x6a: /* 0110 1010 */
+ case 0x6b: /* 0110 1011 */
+ case 0x6c: /* 0110 1100 */
+ case 0x6d: /* 0110 1101 */
+ case 0x6e: /* 0110 1110 */
+ case 0x6f: /* 0110 1111 */
+ sprintf(buffer, "LISL $%02X", op & 0x07);
+ break;
+
+ case 0x70: /* 0111 0000 */
+ case 0x71: /* 0111 0001 */
+ case 0x72: /* 0111 0010 */
+ case 0x73: /* 0111 0011 */
+ case 0x74: /* 0111 0100 */
+ case 0x75: /* 0111 0101 */
+ case 0x76: /* 0111 0110 */
+ case 0x77: /* 0111 0111 */
+ case 0x78: /* 0111 1000 */
+ case 0x79: /* 0111 1001 */
+ case 0x7a: /* 0111 1010 */
+ case 0x7b: /* 0111 1011 */
+ case 0x7c: /* 0111 1100 */
+ case 0x7d: /* 0111 1101 */
+ case 0x7e: /* 0111 1110 */
+ case 0x7f: /* 0111 1111 */
+ sprintf(buffer, "LIS $%02X", op & 0x0f);
+ break;
+
+ case 0x80: /* 1000 0000 */
+ case 0x81: /* 1000 0001 */
+ case 0x82: /* 1000 0010 */
+ case 0x83: /* 1000 0011 */
+ case 0x84: /* 1000 0100 */
+ case 0x85: /* 1000 0101 */
+ case 0x86: /* 1000 0110 */
+ case 0x87: /* 1000 0111 */
+ sprintf(buffer, "BT $%02X,$%04X", oprom[size + 0], pc + (INT8)oprom[size + 1]);
+ size += 2;
+ break;
+
+ case 0x88: /* 1000 1000 */
+ sprintf(buffer, "AM");
+ break;
+
+ case 0x89: /* 1000 1001 */
+ sprintf(buffer, "AMD");
+ break;
+
+ case 0x8a: /* 1000 1010 */
+ sprintf(buffer, "NM");
+ break;
+
+ case 0x8b: /* 1000 1011 */
+ sprintf(buffer, "OM");
+ break;
+
+ case 0x8c: /* 1000 1100 */
+ sprintf(buffer, "XM");
+ break;
+
+ case 0x8d: /* 1000 1101 */
+ sprintf(buffer, "CM");
+ break;
+
+ case 0x8e: /* 1000 1110 */
+ sprintf(buffer, "ADC");
+ break;
+
+ case 0x8f: /* 1000 1111 */
+ sprintf(buffer, "BR7 $%04X", pc + (INT8)oprom[size++]);
+ break;
+
+ case 0x90: /* 1001 0000 */
+ case 0x91: /* 1001 0001 */
+ case 0x92: /* 1001 0010 */
+ case 0x93: /* 1001 0011 */
+ case 0x94: /* 1001 0100 */
+ case 0x95: /* 1001 0101 */
+ case 0x96: /* 1001 0110 */
+ case 0x97: /* 1001 0111 */
+ case 0x98: /* 1001 1000 */
+ case 0x99: /* 1001 1001 */
+ case 0x9a: /* 1001 1010 */
+ case 0x9b: /* 1001 1011 */
+ case 0x9c: /* 1001 1100 */
+ case 0x9d: /* 1001 1101 */
+ case 0x9e: /* 1001 1110 */
+ case 0x9f: /* 1001 1111 */
+ sprintf(buffer, "BF $%02X,$%04X", op & 0x0f, pc + (INT8)oprom[size++]);
+ break;
+
+ case 0xa0: /* 1010 0000 */
+ case 0xa1: /* 1010 0001 */
+ sprintf(buffer, "INS $%02X", (unsigned) (INT8) (op & 0x0F));
+ break;
+
+ case 0xa2: /* 1010 0010 */
+ case 0xa3: /* 1010 0011 */
+ sprintf(buffer, "??? $%02X\n", op);
+ break;
+
+ case 0xa4: /* 1010 0100 */
+ case 0xa5: /* 1010 0101 */
+ case 0xa6: /* 1010 0110 */
+ case 0xa7: /* 1010 0111 */
+ case 0xa8: /* 1010 1000 */
+ case 0xa9: /* 1010 1001 */
+ case 0xaa: /* 1010 1010 */
+ case 0xab: /* 1010 1011 */
+ case 0xac: /* 1010 1100 */
+ case 0xad: /* 1010 1101 */
+ case 0xae: /* 1010 1110 */
+ case 0xaf: /* 1010 1111 */
+ sprintf(buffer, "INS $%02X", (INT8) op & 0x0f);
+ break;
+
+ case 0xb0: /* 1011 0000 */
+ case 0xb1: /* 1011 0001 */
+ sprintf(buffer, "OUTS $%02X", (INT8) op & 0x0f);
+ break;
+
+ case 0xb2: /* 1011 0010 */
+ case 0xb3: /* 1011 0011 */
+ sprintf(buffer, "??? $%02X\n", op);
+ break;
+
+ case 0xb4: /* 1011 0100 */
+ case 0xb5: /* 1011 0101 */
+ case 0xb6: /* 1011 0110 */
+ case 0xb7: /* 1011 0111 */
+ case 0xb8: /* 1011 1000 */
+ case 0xb9: /* 1011 1001 */
+ case 0xba: /* 1011 1010 */
+ case 0xbb: /* 1011 1011 */
+ case 0xbc: /* 1011 1100 */
+ case 0xbd: /* 1011 1101 */
+ case 0xbe: /* 1011 1110 */
+ case 0xbf: /* 1011 1111 */
+ sprintf(buffer, "OUTS $%02X", (unsigned) (INT8) op & 0x0f);
+ break;
+
+ case 0xc0: /* 1100 0000 */
+ case 0xc1: /* 1100 0001 */
+ case 0xc2: /* 1100 0010 */
+ case 0xc3: /* 1100 0011 */
+ case 0xc4: /* 1100 0100 */
+ case 0xc5: /* 1100 0101 */
+ case 0xc6: /* 1100 0110 */
+ case 0xc7: /* 1100 0111 */
+ case 0xc8: /* 1100 1000 */
+ case 0xc9: /* 1100 1001 */
+ case 0xca: /* 1100 1010 */
+ case 0xcb: /* 1100 1011 */
+ sprintf(buffer, "AS %s", rname[op & 15]);
+ break;
+ case 0xcc: /* 1100 1100 */
+ sprintf(buffer, "AS (IS)");
+ break;
+ case 0xcd: /* 1100 1101 */
+ sprintf(buffer, "AS (IS++)");
+ break;
+ case 0xce: /* 1100 1110 */
+ sprintf(buffer, "AS (IS--)");
+ break;
+ case 0xcf: /* 1100 1111 */
+ sprintf(buffer, "??? $%02X\n", op);
+ break;
+
+ case 0xd0: /* 1101 0000 */
+ case 0xd1: /* 1101 0001 */
+ case 0xd2: /* 1101 0010 */
+ case 0xd3: /* 1101 0011 */
+ case 0xd4: /* 1101 0100 */
+ case 0xd5: /* 1101 0101 */
+ case 0xd6: /* 1101 0110 */
+ case 0xd7: /* 1101 0111 */
+ case 0xd8: /* 1101 1000 */
+ case 0xd9: /* 1101 1001 */
+ case 0xda: /* 1101 1010 */
+ case 0xdb: /* 1101 1011 */
+ sprintf(buffer, "ASD %s", rname[op & 15]);
+ break;
+ case 0xdc: /* 1101 1100 */
+ sprintf(buffer, "ASD (IS)");
+ break;
+ case 0xdd: /* 1101 1101 */
+ sprintf(buffer, "ASD (IS++)");
+ break;
+ case 0xde: /* 1101 1110 */
+ sprintf(buffer, "ASD (IS--)");
+ break;
+ case 0xdf: /* 1101 1111 */
+ sprintf(buffer, "??? $%02X\n", op);
+ break;
+
+ case 0xe0: /* 1110 0000 */
+ case 0xe1: /* 1110 0001 */
+ case 0xe2: /* 1110 0010 */
+ case 0xe3: /* 1110 0011 */
+ case 0xe4: /* 1110 0100 */
+ case 0xe5: /* 1110 0101 */
+ case 0xe6: /* 1110 0110 */
+ case 0xe7: /* 1110 0111 */
+ case 0xe8: /* 1110 1000 */
+ case 0xe9: /* 1110 1001 */
+ case 0xea: /* 1110 1010 */
+ case 0xeb: /* 1110 1011 */
+ sprintf(buffer, "XS %s", rname[op & 15]);
+ break;
+ case 0xec: /* 1110 1100 */
+ sprintf(buffer, "XS (IS)");
+ break;
+ case 0xed: /* 1110 1101 */
+ sprintf(buffer, "XS (IS++)");
+ break;
+ case 0xee: /* 1110 1110 */
+ sprintf(buffer, "XS (IS--)");
+ break;
+ case 0xef: /* 1110 1111 */
+ sprintf(buffer, "??? $%02X\n", op);
+ break;
+
+
+ case 0xf0: /* 1111 0000 */
+ case 0xf1: /* 1111 0001 */
+ case 0xf2: /* 1111 0010 */
+ case 0xf3: /* 1111 0011 */
+ case 0xf4: /* 1111 0100 */
+ case 0xf5: /* 1111 0101 */
+ case 0xf6: /* 1111 0110 */
+ case 0xf7: /* 1111 0111 */
+ case 0xf8: /* 1111 1000 */
+ case 0xf9: /* 1111 1001 */
+ case 0xfa: /* 1111 1010 */
+ case 0xfb: /* 1111 1011 */
+ sprintf(buffer, "NS %s", rname[op & 15]);
+ break;
+ case 0xfc: /* 1111 1100 */
+ sprintf(buffer, "NS (IS)");
+ break;
+ case 0xfd: /* 1111 1101 */
+ sprintf(buffer, "NS (IS++)");
+ break;
+ case 0xfe: /* 1111 1110 */
+ sprintf(buffer, "NS (IS--)");
+ break;
+ case 0xff: /* 1111 1111 */
+ sprintf(buffer, "??? $%02X\n", op);
+ break;
+ }
+
+ return size;
+}
+
diff --git a/src/emu/cpu/g65816/g65816.c b/src/emu/cpu/g65816/g65816.c
new file mode 100644
index 00000000000..4503eb91cac
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816.c
@@ -0,0 +1,484 @@
+/* ======================================================================== */
+/* =============================== COPYRIGHT ============================== */
+/* ======================================================================== */
+/*
+
+G65C816 CPU Emulator V0.93
+
+Copyright (c) 2000 Karl Stenerud
+All rights reserved.
+
+Permission is granted to use this source code for non-commercial purposes.
+To use this code for commercial purposes, you must get permission from the
+author (Karl Stenerud) at karl@higashiyama-unet.ocn.ne.jp.
+
+
+*/
+/* ======================================================================== */
+/* ================================= NOTES ================================ */
+/* ======================================================================== */
+/*
+
+Changes:
+ 0.94 (2007-06-14):
+ Zsolt Vasvari
+ - Removed unneccessary checks from MVP and MVN
+
+ 0.93 (2003-07-05):
+ Angelo Salese <lordkale@libero.it>
+ - Fixed the BCD conversion when using the Decimal Flag in ADC and SBC.
+ - Removed the two conversion tables for ADC and SBC as they aren't
+ needed anymore.
+
+ 0.92 (2000-05-28):
+ Lee Hammerton <lee-hammerton@hammerhead.ltd.uk>
+ - Fixed debugger bug that caused D to be misrepresented.
+ - Fixed MVN and MVP (they were reversed)
+
+ 0.91 (2000-05-22):
+ Lee Hammerton <lee-hammerton@hammerhead.ltd.uk>
+ - Fixed reset vector fetch to be little endian
+ - Fixed disassembler call bug
+ - Fixed C flag in SBC (should be inverted before operation)
+ - Fixed JSR to stack PC-1 and RTS to pull PC and add 1
+
+ Karl Stenerud <karl@higashiyama-unet.ocn.ne.jp>
+ - Added correct timing for absolute indexed operations
+ - SBC: fixed corruption of interim values
+
+ 0.90 (2000-05-17):
+ Karl Stenerud <karl@higashiyama-unet.ocn.ne.jp>
+ - first public release
+
+
+Note on timings:
+ - For instructions that write to memory (ASL, ASR, LSL, ROL, ROR, DEC,
+ INC, STA, STZ), the absolute indexed addressing mode takes 1 extra
+ cycle to complete.
+ - The spec says fc (JMP axi) is 6 cyles, but elsewhere says 8 cycles
+ (which is what it should be)
+
+
+TODO general:
+ - WAI will not stop if RDY is held high.
+
+ - RDY internally held low when WAI executed and returned to hi when RES,
+ ABORT, NMI, or IRQ asserted.
+
+ - ABORT will terminate WAI instruction but wil not restart the processor
+
+ - If interrupt occurs after ABORT of WAI, processor returns to WAI
+ instruction.
+
+ - Add one cycle when indexing across page boundary and E=1 except for STA
+ and STZ instructions.
+
+ - Add 1 cycle if branch is taken. In Emulation (E= 1 ) mode only --add 1
+ cycle if the branch is taken and crosses a page boundary.
+
+ - Add 1 cycle in Emulation mode (E=1) for (dir),y; abs,x; and abs,y
+ addressing modes.
+
+*/
+/* ======================================================================== */
+/* ================================= DATA ================================= */
+/* ======================================================================== */
+
+#include "g65816cm.h"
+
+/* Our CPU structure */
+g65816i_cpu_struct g65816i_cpu = {0};
+
+int g65816_ICount = 0;
+
+/* Temporary Variables */
+uint g65816i_source;
+uint g65816i_destination;
+
+static int g65816_readop(UINT32 offset, int size, UINT64 *value)
+{
+ *value = g65816_read_8_immediate(offset);
+
+ return 1;
+}
+
+extern void (*g65816i_opcodes_M0X0[])(void);
+extern uint g65816i_get_reg_M0X0(int regnum);
+extern void g65816i_set_reg_M0X0(int regnum, uint val);
+extern void g65816i_set_line_M0X0(int line, int state);
+extern int g65816i_execute_M0X0(int cycles);
+
+extern void (*g65816i_opcodes_M0X1[])(void);
+extern uint g65816i_get_reg_M0X1(int regnum);
+extern void g65816i_set_reg_M0X1(int regnum, uint val);
+extern void g65816i_set_line_M0X1(int line, int state);
+extern int g65816i_execute_M0X1(int cycles);
+
+extern void (*g65816i_opcodes_M1X0[])(void);
+extern uint g65816i_get_reg_M1X0(int regnum);
+extern void g65816i_set_reg_M1X0(int regnum, uint val);
+extern void g65816i_set_line_M1X0(int line, int state);
+extern int g65816i_execute_M1X0(int cycles);
+
+extern void (*g65816i_opcodes_M1X1[])(void);
+extern uint g65816i_get_reg_M1X1(int regnum);
+extern void g65816i_set_reg_M1X1(int regnum, uint val);
+extern void g65816i_set_line_M1X1(int line, int state);
+extern int g65816i_execute_M1X1(int cycles);
+
+extern void (*g65816i_opcodes_E[])(void);
+extern uint g65816i_get_reg_E(int regnum);
+extern void g65816i_set_reg_E(int regnum, uint val);
+extern void g65816i_set_line_E(int line, int state);
+extern int g65816i_execute_E(int cycles);
+
+void (**g65816i_opcodes[5])(void) =
+{
+ g65816i_opcodes_M0X0,
+ g65816i_opcodes_M0X1,
+ g65816i_opcodes_M1X0,
+ g65816i_opcodes_M1X1,
+ g65816i_opcodes_E
+};
+
+uint (*g65816i_get_reg[5])(int regnum) =
+{
+ g65816i_get_reg_M0X0,
+ g65816i_get_reg_M0X1,
+ g65816i_get_reg_M1X0,
+ g65816i_get_reg_M1X1,
+ g65816i_get_reg_E
+};
+
+void (*g65816i_set_reg[5])(int regnum, uint val) =
+{
+ g65816i_set_reg_M0X0,
+ g65816i_set_reg_M0X1,
+ g65816i_set_reg_M1X0,
+ g65816i_set_reg_M1X1,
+ g65816i_set_reg_E
+};
+
+void (*g65816i_set_line[5])(int line, int state) =
+{
+ g65816i_set_line_M0X0,
+ g65816i_set_line_M0X1,
+ g65816i_set_line_M1X0,
+ g65816i_set_line_M1X1,
+ g65816i_set_line_E
+};
+
+int (*g65816i_execute[5])(int cycles) =
+{
+ g65816i_execute_M0X0,
+ g65816i_execute_M0X1,
+ g65816i_execute_M1X0,
+ g65816i_execute_M1X1,
+ g65816i_execute_E
+};
+
+/* ======================================================================== */
+/* ================================= API ================================== */
+/* ======================================================================== */
+
+
+static void g65816_reset(void)
+{
+ /* Start the CPU */
+ CPU_STOPPED = 0;
+
+ /* Put into emulation mode */
+ REGISTER_D = 0;
+ REGISTER_PB = 0;
+ REGISTER_DB = 0;
+ REGISTER_S = (REGISTER_S & 0xff) | 0x100;
+ REGISTER_X &= 0xff;
+ REGISTER_Y &= 0xff;
+ if(!FLAG_M)
+ {
+ REGISTER_B = REGISTER_A & 0xff00;
+ REGISTER_A &= 0xff;
+ }
+ FLAG_E = EFLAG_SET;
+ FLAG_M = MFLAG_SET;
+ FLAG_X = XFLAG_SET;
+
+ /* Clear D and set I */
+ FLAG_D = DFLAG_CLEAR;
+ FLAG_I = IFLAG_SET;
+
+ /* Clear all pending interrupts (should we really do this?) */
+ LINE_IRQ = 0;
+ LINE_NMI = 0;
+ IRQ_DELAY = 0;
+
+ /* Set the function tables to emulation mode */
+ g65816i_set_execution_mode(EXECUTION_MODE_E);
+
+ /* 6502 expects these, but its not in the 65816 spec */
+ FLAG_Z = ZFLAG_CLEAR;
+ REGISTER_S = 0x1ff;
+
+ /* Fetch the reset vector */
+ REGISTER_PC = g65816_read_8(VECTOR_RESET) | (g65816_read_8(VECTOR_RESET+1)<<8);
+ g65816i_jumping(REGISTER_PB | REGISTER_PC);
+}
+
+/* Exit and clean up */
+static void g65816_exit(void)
+{
+ /* nothing to do yet */
+}
+
+/* Execute some instructions */
+static int g65816_execute(int cycles)
+{
+ return FTABLE_EXECUTE(cycles);
+}
+
+
+/* Get the current CPU context */
+static void g65816_get_context(void *dst_context)
+{
+ if(dst_context)
+ *(g65816i_cpu_struct*)dst_context = g65816i_cpu;
+}
+
+/* Set the current CPU context */
+static void g65816_set_context(void *src_context)
+{
+ if(src_context)
+ {
+ g65816i_cpu = *(g65816i_cpu_struct*)src_context;
+ g65816i_jumping(REGISTER_PB | REGISTER_PC);
+ }
+}
+
+/* Get the current Program Counter */
+static unsigned g65816_get_pc(void)
+{
+ return REGISTER_PB | REGISTER_PC;
+}
+
+/* Set the Program Counter */
+static void g65816_set_pc(unsigned val)
+{
+ REGISTER_PC = MAKE_UINT_16(val);
+ REGISTER_PB = (val >> 16) & 0xFF;
+ g65816_jumping(REGISTER_PB | REGISTER_PC);
+}
+
+/* Get the current Stack Pointer */
+static unsigned g65816_get_sp(void)
+{
+ return REGISTER_S;
+}
+
+/* Set the Stack Pointer */
+static void g65816_set_sp(unsigned val)
+{
+ REGISTER_S = FLAG_E ? MAKE_UINT_8(val) | 0x100 : MAKE_UINT_16(val);
+}
+
+/* Get a register */
+static unsigned g65816_get_reg(int regnum)
+{
+ /* Set the function tables to emulation mode if the FTABLE is NULL */
+ if( FTABLE_GET_REG == NULL )
+ g65816i_set_execution_mode(EXECUTION_MODE_E);
+
+ return FTABLE_GET_REG(regnum);
+}
+
+/* Set a register */
+static void g65816_set_reg(int regnum, unsigned value)
+{
+ FTABLE_SET_REG(regnum, value);
+}
+
+/* Set an interrupt line */
+static void g65816_set_irq_line(int line, int state)
+{
+ FTABLE_SET_LINE(line, state);
+}
+
+/* Set the callback that is called when servicing an interrupt */
+static void g65816_set_irq_callback(int (*callback)(int))
+{
+ INT_ACK = callback;
+}
+
+
+/* Disassemble an instruction */
+#ifdef MAME_DEBUG
+#include "g65816ds.h"
+
+static offs_t g65816_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return g65816_disassemble(buffer, (pc & 0x00ffff), (pc & 0xff0000) >> 16, oprom, FLAG_M, FLAG_X);
+}
+#endif /* MAME_DEBUG */
+
+
+
+static void g65816_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ g65816_set_irq_callback(irqcallback);
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void g65816_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_IRQ: g65816_set_irq_line(G65816_LINE_IRQ, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_NMI: g65816_set_irq_line(G65816_LINE_NMI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_ABORT: g65816_set_irq_line(G65816_LINE_ABORT, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_SO: g65816_set_irq_line(G65816_LINE_SO, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_RDY: g65816_set_irq_line(G65816_LINE_RDY, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_RESET: g65816_set_irq_line(G65816_LINE_RESET, info->i); break;
+
+ case CPUINFO_INT_PC: g65816_set_pc(info->i); break;
+ case CPUINFO_INT_SP: g65816_set_sp(info->i); break;
+
+ case CPUINFO_INT_REGISTER + G65816_PC: g65816_set_reg(G65816_PC, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_S: g65816_set_reg(G65816_S, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_P: g65816_set_reg(G65816_P, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_A: g65816_set_reg(G65816_A, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_X: g65816_set_reg(G65816_X, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_Y: g65816_set_reg(G65816_Y, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_PB: g65816_set_reg(G65816_PB, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_DB: g65816_set_reg(G65816_DB, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_D: g65816_set_reg(G65816_D, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_E: g65816_set_reg(G65816_E, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_NMI_STATE: g65816_set_reg(G65816_NMI_STATE, info->i); break;
+ case CPUINFO_INT_REGISTER + G65816_IRQ_STATE: g65816_set_reg(G65816_IRQ_STATE, info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_G65816_READVECTOR_CALLBACK: READ_VECTOR = (read8_handler) info->f; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void g65816_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(g65816i_cpu); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 20; /* rough guess */ break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_IRQ: info->i = LINE_IRQ; break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_NMI: info->i = LINE_NMI; break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_ABORT: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_SO: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_RDY: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + G65816_LINE_RESET: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not supported */ break;
+
+ case CPUINFO_INT_PC: info->i = g65816_get_pc(); break;
+ case CPUINFO_INT_SP: info->i = g65816_get_sp(); break;
+
+ case CPUINFO_INT_REGISTER + G65816_PC: info->i = g65816_get_pc(); break;
+ case CPUINFO_INT_REGISTER + G65816_S: info->i = g65816_get_reg(G65816_S); break;
+ case CPUINFO_INT_REGISTER + G65816_P: info->i = g65816_get_reg(G65816_P); break;
+ case CPUINFO_INT_REGISTER + G65816_A: info->i = g65816_get_reg(G65816_A); break;
+ case CPUINFO_INT_REGISTER + G65816_X: info->i = g65816_get_reg(G65816_X); break;
+ case CPUINFO_INT_REGISTER + G65816_Y: info->i = g65816_get_reg(G65816_Y); break;
+ case CPUINFO_INT_REGISTER + G65816_PB: info->i = g65816_get_reg(G65816_PB); break;
+ case CPUINFO_INT_REGISTER + G65816_DB: info->i = g65816_get_reg(G65816_DB); break;
+ case CPUINFO_INT_REGISTER + G65816_D: info->i = g65816_get_reg(G65816_D); break;
+ case CPUINFO_INT_REGISTER + G65816_E: info->i = g65816_get_reg(G65816_E); break;
+ case CPUINFO_INT_REGISTER + G65816_NMI_STATE: info->i = g65816_get_reg(G65816_NMI_STATE); break;
+ case CPUINFO_INT_REGISTER + G65816_IRQ_STATE: info->i = g65816_get_reg(G65816_IRQ_STATE); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = g65816_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = g65816_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = g65816_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = g65816_init; break;
+ case CPUINFO_PTR_RESET: info->reset = g65816_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = g65816_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = g65816_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = g65816_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &g65816_ICount; break;
+ case CPUINFO_PTR_G65816_READVECTOR_CALLBACK: info->f = (genf *) READ_VECTOR; break;
+
+ case CPUINFO_PTR_READOP: info->readop = g65816_readop; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "G65C816"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "6500"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.94"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2000 Karl Stenerud, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ g65816i_cpu.flag_n & NFLAG_SET ? 'N':'.',
+ g65816i_cpu.flag_v & VFLAG_SET ? 'V':'.',
+ g65816i_cpu.flag_m & MFLAG_SET ? 'M':'.',
+ g65816i_cpu.flag_x & XFLAG_SET ? 'X':'.',
+ g65816i_cpu.flag_d & DFLAG_SET ? 'D':'.',
+ g65816i_cpu.flag_i & IFLAG_SET ? 'I':'.',
+ g65816i_cpu.flag_z == 0 ? 'Z':'.',
+ g65816i_cpu.flag_c & CFLAG_SET ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + G65816_PC: sprintf(info->s, "PC:%06X", g65816_get_pc()); break;
+ case CPUINFO_STR_REGISTER + G65816_PB: sprintf(info->s, "PB:%02X", g65816i_cpu.pb>>16); break;
+ case CPUINFO_STR_REGISTER + G65816_DB: sprintf(info->s, "DB:%02X", g65816i_cpu.db>>16); break;
+ case CPUINFO_STR_REGISTER + G65816_D: sprintf(info->s, "D:%04X", g65816i_cpu.d); break;
+ case CPUINFO_STR_REGISTER + G65816_S: sprintf(info->s, "S:%04X", g65816i_cpu.s); break;
+ case CPUINFO_STR_REGISTER + G65816_P: sprintf(info->s, "P:%02X",
+ (g65816i_cpu.flag_n&0x80) |
+ ((g65816i_cpu.flag_v>>1)&0x40) |
+ g65816i_cpu.flag_m |
+ g65816i_cpu.flag_x |
+ g65816i_cpu.flag_d |
+ g65816i_cpu.flag_i |
+ ((!g65816i_cpu.flag_z)<<1) |
+ ((g65816i_cpu.flag_c>>8)&1)); break;
+ case CPUINFO_STR_REGISTER + G65816_E: sprintf(info->s, "E:%d", g65816i_cpu.flag_e); break;
+ case CPUINFO_STR_REGISTER + G65816_A: sprintf(info->s, "A:%04X", g65816i_cpu.a | g65816i_cpu.b); break;
+ case CPUINFO_STR_REGISTER + G65816_X: sprintf(info->s, "X:%04X", g65816i_cpu.x); break;
+ case CPUINFO_STR_REGISTER + G65816_Y: sprintf(info->s, "Y:%04X", g65816i_cpu.y); break;
+ case CPUINFO_STR_REGISTER + G65816_NMI_STATE: sprintf(info->s, "NMI:%X", g65816i_cpu.line_nmi); break;
+ case CPUINFO_STR_REGISTER + G65816_IRQ_STATE: sprintf(info->s, "IRQ:%X", g65816i_cpu.line_irq); break;
+ }
+}
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
diff --git a/src/emu/cpu/g65816/g65816.h b/src/emu/cpu/g65816/g65816.h
new file mode 100644
index 00000000000..02c181c5255
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816.h
@@ -0,0 +1,106 @@
+#ifndef HEADER__G65816
+#define HEADER__G65816
+
+/* ======================================================================== */
+/* =============================== COPYRIGHT ============================== */
+/* ======================================================================== */
+/*
+
+G65C816 CPU Emulator V0.92
+
+Copyright (c) 2000 Karl Stenerud
+All rights reserved.
+
+Permission is granted to use this source code for non-commercial purposes.
+To use this code for commercial purposes, you must get permission from the
+author (Karl Stenerud) at karl@higashiyama-unet.ocn.ne.jp.
+
+
+*/
+/* ======================================================================== */
+/* ============================= Configuration ============================ */
+/* ======================================================================== */
+
+/* GTE Microcircuits G65816 */
+
+/* ======================================================================== */
+/* =============================== DEFINES ================================ */
+/* ======================================================================== */
+
+/* Interrupt lines - used with g65816_set_irq_line() */
+enum
+{
+ G65816_LINE_NONE,
+ G65816_LINE_IRQ,
+ G65816_LINE_NMI,
+ G65816_LINE_ABORT,
+ G65816_LINE_SO,
+ G65816_LINE_RDY,
+ G65816_LINE_RESET
+};
+
+#define G65816_INT_NONE G65816_LINE_NONE
+#define G65816_INT_IRQ G65816_LINE_IRQ
+#define G65816_INT_NMI G65816_LINE_NMI
+
+
+/* Registers - used by g65816_set_reg() and g65816_get_reg() */
+enum
+{
+ G65816_PC=1, G65816_S, G65816_P, G65816_A, G65816_X, G65816_Y,
+ G65816_PB, G65816_DB, G65816_D, G65816_E,
+ G65816_NMI_STATE, G65816_IRQ_STATE
+};
+
+
+
+/* ======================================================================== */
+/* =================== Functions Implemented by the Host ================== */
+/* ======================================================================== */
+
+/* Read data from RAM */
+unsigned int g65816_read_8(unsigned int address);
+
+/* Read data from ROM */
+unsigned int g65816_read_8_immediate(unsigned int address);
+
+/* Write data to RAM */
+void g65816_write_8(unsigned int address, unsigned int value);
+
+/* Notification of PC changes */
+void g65816_jumping(unsigned int new_pc);
+void g65816_branching(unsigned int new_pc);
+
+
+
+/* ======================================================================== */
+/* ================================= MAME ================================= */
+/* ======================================================================== */
+
+#include "cpuintrf.h"
+#include "debugger.h"
+
+enum
+{
+ CPUINFO_PTR_G65816_READVECTOR_CALLBACK = CPUINFO_PTR_CPU_SPECIFIC
+};
+
+/* Main interface function */
+void g65816_get_info(UINT32 state, cpuinfo *info);
+
+#undef G65816_CALL_DEBUGGER
+#define G65816_CALL_DEBUGGER CALL_MAME_DEBUG
+
+#define g65816_read_8(addr) program_read_byte_8(addr)
+#define g65816_write_8(addr,data) program_write_byte_8(addr,data)
+#define g65816_read_8_immediate(A) program_read_byte_8(A)
+#define g65816_jumping(A) change_pc(A)
+#define g65816_branching(A)
+
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+#endif /* HEADER__G65816 */
diff --git a/src/emu/cpu/g65816/g65816cm.h b/src/emu/cpu/g65816/g65816cm.h
new file mode 100644
index 00000000000..0b9dda5e88e
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816cm.h
@@ -0,0 +1,310 @@
+#ifndef HEADER__G65816CM
+#define HEADER__G65816CM
+
+#define g65816i_branching(A)
+#define g65816i_jumping(A)
+
+
+/* ======================================================================== */
+/* ================================ INCLUDES ============================== */
+/* ======================================================================== */
+
+#include <limits.h>
+#include "g65816.h"
+#include <stdio.h>
+
+
+/* ======================================================================== */
+/* ================================ GENERAL =============================== */
+/* ======================================================================== */
+
+/* Fallback on static if we don't have inline */
+#ifndef INLINE
+#define INLINE static
+#endif
+
+/* This should be set to the default size of your processor (min 16 bit) */
+#undef uint
+#define uint unsigned int
+
+#undef uint8
+#define uint8 unsigned char
+
+#undef int8
+
+/* Allow for architectures that don't have 8-bit sizes */
+#if UCHAR_MAX == 0xff
+#define int8 char
+#define MAKE_INT_8(A) (int8)((A)&0xff)
+#else
+#define int8 int
+INLINE int MAKE_INT_8(int A) {return (A & 0x80) ? A | ~0xff : A & 0xff;}
+#endif /* UCHAR_MAX == 0xff */
+
+#define MAKE_UINT_8(A) ((A)&0xff)
+#define MAKE_UINT_16(A) ((A)&0xffff)
+#define MAKE_UINT_24(A) ((A)&0xffffff)
+
+/* Bits */
+#define BIT_0 0x01
+#define BIT_1 0x02
+#define BIT_2 0x04
+#define BIT_3 0x08
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+
+
+/* ======================================================================== */
+/* ================================== CPU ================================= */
+/* ======================================================================== */
+
+/* CPU Structure */
+typedef struct
+{
+ uint a; /* Accumulator */
+ uint b; /* holds high byte of accumulator */
+ uint x; /* Index Register X */
+ uint y; /* Index Register Y */
+ uint s; /* Stack Pointer */
+ uint pc; /* Program Counter */
+ uint ppc; /* Previous Program Counter */
+ uint pb; /* Program Bank (shifted left 16) */
+ uint db; /* Data Bank (shifted left 16) */
+ uint d; /* Direct Register */
+ uint flag_e; /* Emulation Mode Flag */
+ uint flag_m; /* Memory/Accumulator Select Flag */
+ uint flag_x; /* Index Select Flag */
+ uint flag_n; /* Negative Flag */
+ uint flag_v; /* Overflow Flag */
+ uint flag_d; /* Decimal Mode Flag */
+ uint flag_i; /* Interrupt Mask Flag */
+ uint flag_z; /* Zero Flag (inverted) */
+ uint flag_c; /* Carry Flag */
+ uint line_irq; /* Status of the IRQ line */
+ uint line_nmi; /* Status of the NMI line */
+ uint ir; /* Instruction Register */
+ uint irq_delay; /* delay 1 instruction before checking irq */
+ int (*int_ack)(int); /* Interrupt Acknowledge */
+ read8_handler read_vector; /* Read vector override */
+ uint stopped; /* Sets how the CPU is stopped */
+ void (**opcodes)(void);
+ uint (*get_reg)(int regnum);
+ void (*set_reg)(int regnum, uint val);
+ void (*set_line)(int line, int state);
+ int (*execute)(int cycles);
+} g65816i_cpu_struct;
+
+extern g65816i_cpu_struct g65816i_cpu;
+extern int g65816_ICount;
+extern uint g65816i_source;
+extern uint g65816i_destination;
+
+extern void (**g65816i_opcodes[])(void);
+extern uint (*g65816i_get_reg[])(int regnum);
+extern void (*g65816i_set_reg[])(int regnum, uint val);
+extern void (*g65816i_set_line[])(int line, int state);
+extern int (*g65816i_execute[])(int cycles);
+
+#define REGISTER_A g65816i_cpu.a /* Accumulator */
+#define REGISTER_B g65816i_cpu.b /* Accumulator hi byte */
+#define REGISTER_X g65816i_cpu.x /* Index X Register */
+#define REGISTER_Y g65816i_cpu.y /* Index Y Register */
+#define REGISTER_S g65816i_cpu.s /* Stack Pointer */
+#define REGISTER_PC g65816i_cpu.pc /* Program Counter */
+#define REGISTER_PPC g65816i_cpu.ppc /* Previous Program Counter */
+#define REGISTER_PB g65816i_cpu.pb /* Program Bank */
+#define REGISTER_DB g65816i_cpu.db /* Data Bank */
+#define REGISTER_D g65816i_cpu.d /* Direct Register */
+#define FLAG_E g65816i_cpu.flag_e /* Emulation Mode Flag */
+#define FLAG_M g65816i_cpu.flag_m /* Memory/Accumulator Select Flag */
+#define FLAG_X g65816i_cpu.flag_x /* Index Select Flag */
+#define FLAG_N g65816i_cpu.flag_n /* Negative Flag */
+#define FLAG_V g65816i_cpu.flag_v /* Overflow Flag */
+#define FLAG_D g65816i_cpu.flag_d /* Decimal Mode Flag */
+#define FLAG_I g65816i_cpu.flag_i /* Interrupt Mask Flag */
+#define FLAG_Z g65816i_cpu.flag_z /* Zero Flag (inverted) */
+#define FLAG_C g65816i_cpu.flag_c /* Carry Flag */
+#define LINE_IRQ g65816i_cpu.line_irq /* Status of the IRQ line */
+#define LINE_NMI g65816i_cpu.line_nmi /* Status of the NMI line */
+#define REGISTER_IR g65816i_cpu.ir /* Instruction Register */
+#define INT_ACK g65816i_cpu.int_ack /* Interrupt Acknowledge function pointer */
+#define READ_VECTOR g65816i_cpu.read_vector /* Vector reading override */
+#define CLOCKS g65816_ICount /* Clock cycles remaining */
+#define IRQ_DELAY g65816i_cpu.irq_delay /* Delay 1 instruction before checking IRQ */
+#define CPU_STOPPED g65816i_cpu.stopped /* Stopped status of the CPU */
+
+#define FTABLE_OPCODES g65816i_cpu.opcodes
+#define FTABLE_GET_REG g65816i_cpu.get_reg
+#define FTABLE_SET_REG g65816i_cpu.set_reg
+#define FTABLE_SET_LINE g65816i_cpu.set_line
+#define FTABLE_EXECUTE g65816i_cpu.execute
+
+#define SRC g65816i_source /* Source Operand */
+#define DST g65816i_destination /* Destination Operand */
+
+#define STOP_LEVEL_WAI 1
+#define STOP_LEVEL_STOP 2
+
+#define EXECUTION_MODE_M0X0 0
+#define EXECUTION_MODE_M0X1 1
+#define EXECUTION_MODE_M1X0 2
+#define EXECUTION_MODE_M1X1 3
+#define EXECUTION_MODE_E 4
+
+INLINE void g65816i_set_execution_mode(uint mode)
+{
+ FTABLE_OPCODES = g65816i_opcodes[mode];
+ FTABLE_GET_REG = g65816i_get_reg[mode];
+ FTABLE_SET_REG = g65816i_set_reg[mode];
+ FTABLE_SET_LINE = g65816i_set_line[mode];
+ FTABLE_EXECUTE = g65816i_execute[mode];
+}
+
+
+
+#define VECTOR_RESET 0xfffc /* Reset */
+#define VECTOR_IRQ_E 0xfffe /* Interrupt Request */
+#define VECTOR_NMI_E 0xfffa /* Non-Maskable Interrupt */
+#define VECTOR_ABORT_E 0xfff8 /* ABORT asserted */
+#define VECTOR_BRK_E 0xfffe /* Break Instruction */
+#define VECTOR_COP_E 0xfff4 /* Coprocessor instruction */
+
+#define VECTOR_IRQ_N 0xffee /* Interrupt Request */
+#define VECTOR_NMI_N 0xffea /* Non-Maskable Interrupt */
+#define VECTOR_ABORT_N 0xffe8 /* ABORT asserted */
+#define VECTOR_BRK_N 0xffe6 /* Break Instruction */
+#define VECTOR_COP_N 0xffe4 /* Coprocessor instruction */
+
+
+/* ======================================================================== */
+/* ================================= CLOCK ================================ */
+/* ======================================================================== */
+
+#define CLK_OP 1
+#define CLK_R8 1
+#define CLK_R16 2
+#define CLK_R24 3
+#define CLK_W8 1
+#define CLK_W16 2
+#define CLK_W24 3
+#define CLK_RMW8 3
+#define CLK_RMW16 5
+
+#define CLK_IMPLIED 1
+#define CLK_IMPLIED 1
+#define CLK_RELATIVE_8 1
+#define CLK_RELATIVE_16 2
+#define CLK_IMM 0
+#define CLK_AI 4
+#define CLK_AXI 4
+#define CLK_A 2
+#define CLK_AL 3
+#define CLK_ALX 3
+#define CLK_AX 2
+#define CLK_AY 2
+#define CLK_D 1
+#define CLK_DI 3
+#define CLK_DIY 3
+#define CLK_DLI 4
+#define CLK_DLIY 4
+#define CLK_DX 2
+#define CLK_DXI 4
+#define CLK_DY 2
+#define CLK_S 2
+#define CLK_SIY 5
+
+/* AX and AY addressing modes take 1 extra cycle when writing */
+#define CLK_W_IMM 0
+#define CLK_W_AI 4
+#define CLK_W_AXI 4
+#define CLK_W_A 2
+#define CLK_W_AL 3
+#define CLK_W_ALX 3
+#define CLK_W_AX 3
+#define CLK_W_AY 3
+#define CLK_W_D 1
+#define CLK_W_DI 3
+#define CLK_W_DIY 3
+#define CLK_W_DLI 4
+#define CLK_W_DLIY 4
+#define CLK_W_DX 2
+#define CLK_W_DXI 4
+#define CLK_W_DY 2
+#define CLK_W_S 2
+#define CLK_W_SIY 5
+
+#define CLK(A) CLOCKS -= (A)
+#define USE_ALL_CLKS() CLOCKS = 0
+
+
+/* ======================================================================== */
+/* ============================ STATUS REGISTER =========================== */
+/* ======================================================================== */
+
+/* Flag positions in Processor Status Register */
+/* common */
+#define FLAGPOS_N BIT_7 /* Negative */
+#define FLAGPOS_V BIT_6 /* Overflow */
+#define FLAGPOS_D BIT_3 /* Decimal Mode */
+#define FLAGPOS_I BIT_2 /* Interrupt Mask */
+#define FLAGPOS_Z BIT_1 /* Zero */
+#define FLAGPOS_C BIT_0 /* Carry */
+/* emulation */
+#define FLAGPOS_R BIT_5 /* Reserved */
+#define FLAGPOS_B BIT_4 /* BRK Instruction */
+/* native */
+#define FLAGPOS_M BIT_5 /* Mem/Reg Select */
+#define FLAGPOS_X BIT_4 /* Index Select */
+
+#define EFLAG_SET 1
+#define EFLAG_CLEAR 0
+#define MFLAG_SET FLAGPOS_M
+#define MFLAG_CLEAR 0
+#define XFLAG_SET FLAGPOS_X
+#define XFLAG_CLEAR 0
+#define NFLAG_SET 0x80
+#define NFLAG_CLEAR 0
+#define VFLAG_SET 0x80
+#define VFLAG_CLEAR 0
+#define DFLAG_SET FLAGPOS_D
+#define DFLAG_CLEAR 0
+#define IFLAG_SET FLAGPOS_I
+#define IFLAG_CLEAR 0
+#define BFLAG_SET FLAGPOS_B
+#define BFLAG_CLEAR 0
+#define ZFLAG_SET 0
+#define ZFLAG_CLEAR 1
+#define CFLAG_SET 0x100
+#define CFLAG_CLEAR 0
+
+/* Codition code tests */
+#define COND_CC() (!(FLAG_C&0x100)) /* Carry Clear */
+#define COND_CS() (FLAG_C&0x100) /* Carry Set */
+#define COND_EQ() (!FLAG_Z) /* Equal */
+#define COND_NE() FLAG_Z /* Not Equal */
+#define COND_MI() (FLAG_N&0x80) /* Minus */
+#define COND_PL() (!(FLAG_N&0x80)) /* Plus */
+#define COND_VC() (!(FLAG_V&0x80)) /* Overflow Clear */
+#define COND_VS() (FLAG_V&0x80) /* Overflow Set */
+
+/* Set Overflow flag in math operations */
+#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R))
+#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8)
+#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D))
+#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8)
+
+#define CFLAG_8(A) (A)
+#define CFLAG_16(A) ((A)>>8)
+#define NFLAG_8(A) (A)
+#define NFLAG_16(A) ((A)>>8)
+
+#define CFLAG_AS_1() ((FLAG_C>>8)&1)
+
+
+
+/* ======================================================================== */
+/* ================================== CPU ================================= */
+/* ======================================================================== */
+#endif /* HEADER__G65816CM */
diff --git a/src/emu/cpu/g65816/g65816ds.c b/src/emu/cpu/g65816/g65816ds.c
new file mode 100644
index 00000000000..ad3570043d9
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816ds.c
@@ -0,0 +1,350 @@
+/* ======================================================================== */
+/* =============================== COPYRIGHT ============================== */
+/* ======================================================================== */
+/*
+
+G65C816 CPU Emulator V0.90
+
+Copyright (c) 2000 Karl Stenerud
+All rights reserved.
+
+Permission is granted to use this source code for non-commercial purposes.
+To use this code for commercial purposes, you must get permission from the
+author (Karl Stenerud) at karl@higashiyama-unet.ocn.ne.jp.
+
+
+*/
+
+
+#include "cpuintrf.h"
+#include "g65816ds.h"
+
+#ifdef SEC
+#undef SEC
+#endif
+
+#define ADDRESS_65816(A) ((A)&0xffffff)
+#ifndef INLINE
+#define INLINE static
+#endif
+
+
+typedef struct
+{
+ unsigned char name;
+ unsigned char flag;
+ unsigned char ea;
+} opcode_struct;
+
+enum
+{
+ IMP , ACC , RELB, RELW, IMM , A , AI , AL , ALX , AX , AXI ,
+ AY , D , DI , DIY , DLI , DLIY, DX , DXI , DY , S , SIY ,
+ SIG /*, MVN , MVP , PEA , PEI , PER */
+};
+
+enum
+{
+ I, /* ignore */
+ M, /* check m bit */
+ X /* check x bit */
+};
+
+enum
+{
+ ADC , AND , ASL , BCC , BCS , BEQ , BIT , BMI , BNE , BPL , BRA ,
+ BRK , BRL , BVC , BVS , CLC , CLD , CLI , CLV , CMP , COP , CPX ,
+ CPY , DEA , DEC , DEX , DEY , EOR , INA , INC , INX , INY , JML ,
+ JMP , JSL , JSR , LDA , LDX , LDY , LSR , MVN , MVP , NOP , ORA ,
+ PEA , PEI , PER , PHA , PHB , PHD , PHK , PHP , PHX , PHY , PLA ,
+ PLB , PLD , PLP , PLX , PLY , REP , ROL , ROR , RTI , RTL , RTS ,
+ SBC , SEC , SED , SEI , SEP , STA , STP , STX , STY , STZ , TAX ,
+ TAY , TCS , TCD , TDC , TRB , TSB , TSC , TSX , TXA , TXS , TXY ,
+ TYA , TYX , WAI , WDM , XBA , XCE
+};
+
+static const char* g_opnames[] =
+{
+ "ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI", "BNE", "BPL", "BRA",
+ "BRK", "BRL", "BVC", "BVS", "CLC", "CLD", "CLI", "CLV", "CMP", "COP", "CPX",
+ "CPY", "DEA", "DEC", "DEX", "DEY", "EOR", "INA", "INC", "INX", "INY", "JML",
+ "JMP", "JSL", "JSR", "LDA", "LDX", "LDY", "LSR", "MVN", "MVP", "NOP", "ORA",
+ "PEA", "PEI", "PER", "PHA", "PHB", "PHD", "PHK", "PHP", "PHX", "PHY", "PLA",
+ "PLB", "PLD", "PLP", "PLX", "PLY", "REP", "ROL", "ROR", "RTI", "RTL", "RTS",
+ "SBC", "SEC", "SED", "SEI", "SEP", "STA", "STP", "STX", "STY", "STZ", "TAX",
+ "TAY", "TCS", "TCD", "TDC", "TRB", "TSB", "TSC", "TSX", "TXA", "TXS", "TXY",
+ "TYA", "TYX", "WAI", "WDM", "XBA", "XCE"
+};
+
+static const opcode_struct g_opcodes[256] =
+{
+ {BRK, I, SIG }, {ORA, M, DXI }, {COP, I, SIG }, {ORA, M, S },
+ {TSB, M, D }, {ORA, M, D }, {ASL, M, D }, {ORA, M, DLI },
+ {PHP, I, IMP }, {ORA, M, IMM }, {ASL, M, ACC }, {PHD, I, IMP },
+ {TSB, M, A }, {ORA, M, A }, {ASL, M, A }, {ORA, M, AL },
+ {BPL, I, RELB}, {ORA, M, DIY }, {ORA, M, DI }, {ORA, M, SIY },
+ {TRB, M, D }, {ORA, M, DX }, {ASL, M, DX }, {ORA, M, DLIY},
+ {CLC, I, IMP }, {ORA, M, AY }, {INA, I, IMP }, {TCS, I, IMP },
+ {TRB, M, A }, {ORA, M, AX }, {ASL, M, AX }, {ORA, M, ALX },
+ {JSR, I, A }, {AND, M, DXI }, {JSL, I, AL }, {AND, M, S },
+ {BIT, M, D }, {AND, M, D }, {ROL, M, D }, {AND, M, DLI },
+ {PLP, I, IMP }, {AND, M, IMM }, {ROL, M, ACC }, {PLD, I, IMP },
+ {BIT, M, A }, {AND, M, A }, {ROL, M, A }, {AND, M, AL },
+ {BMI, I, RELB}, {AND, M, DIY }, {AND, M, DI }, {AND, M, SIY },
+ {BIT, M, DX }, {AND, M, DX }, {ROL, M, DX }, {AND, M, DLIY},
+ {SEC, I, IMP }, {AND, M, AY }, {DEA, I, IMP }, {TSC, I, IMP },
+ {BIT, M, AX }, {AND, M, AX }, {ROL, M, AX }, {AND, M, ALX },
+ {RTI, I, IMP }, {EOR, M, DXI }, {WDM, I, IMP }, {EOR, M, S },
+ {MVP, I, MVP }, {EOR, M, D }, {LSR, M, D }, {EOR, M, DLI },
+ {PHA, I, IMP }, {EOR, M, IMM }, {LSR, M, ACC }, {PHK, I, IMP },
+ {JMP, I, A }, {EOR, M, A }, {LSR, M, A }, {EOR, M, AL },
+ {BVC, I, RELB}, {EOR, M, DIY }, {EOR, M, DI }, {EOR, M, SIY },
+ {MVN, I, MVN }, {EOR, M, DX }, {LSR, M, DX }, {EOR, M, DLIY},
+ {CLI, I, IMP }, {EOR, M, AY }, {PHY, I, IMP }, {TCD, I, IMP },
+ {JMP, I, AL }, {EOR, M, AX }, {LSR, M, AX }, {EOR, M, ALX },
+ {RTS, I, IMP }, {ADC, M, DXI }, {PER, I, PER }, {ADC, M, S },
+ {STZ, M, D }, {ADC, M, D }, {ROR, M, D }, {ADC, M, DLI },
+ {PLA, I, IMP }, {ADC, M, IMM }, {ROR, M, ACC }, {RTL, I, IMP },
+ {JMP, I, AI }, {ADC, M, A }, {ROR, M, A }, {ADC, M, AL },
+ {BVS, I, RELB}, {ADC, M, DIY }, {ADC, M, DI }, {ADC, M, SIY },
+ {STZ, M, DX }, {ADC, M, DX }, {ROR, M, DX }, {ADC, M, DLIY},
+ {SEI, I, IMP }, {ADC, M, AY }, {PLY, I, IMP }, {TDC, I, IMP },
+ {JMP, I, AXI }, {ADC, M, AX }, {ROR, M, AX }, {ADC, M, ALX },
+ {BRA, I, RELB}, {STA, M, DXI }, {BRL, I, RELW}, {STA, M, S },
+ {STY, X, D }, {STA, M, D }, {STX, X, D }, {STA, M, DLI },
+ {DEY, I, IMP }, {BIT, M, IMM }, {TXA, I, IMP }, {PHB, I, IMP },
+ {STY, X, A }, {STA, M, A }, {STX, X, A }, {STA, M, AL },
+ {BCC, I, RELB}, {STA, M, DIY }, {STA, M, DI }, {STA, M, SIY },
+ {STY, X, DX }, {STA, M, DX }, {STX, X, DY }, {STA, M, DLIY},
+ {TYA, I, IMP }, {STA, M, AY }, {TXS, I, IMP }, {TXY, I, IMP },
+ {STZ, M, A }, {STA, M, AX }, {STZ, M, AX }, {STA, M, ALX },
+ {LDY, X, IMM }, {LDA, M, DXI }, {LDX, X, IMM }, {LDA, M, S },
+ {LDY, X, D }, {LDA, M, D }, {LDX, X, D }, {LDA, M, DLI },
+ {TAY, I, IMP }, {LDA, M, IMM }, {TAX, I, IMP }, {PLB, I, IMP },
+ {LDY, X, A }, {LDA, M, A }, {LDX, X, A }, {LDA, M, AL },
+ {BCS, I, RELB}, {LDA, M, DIY }, {LDA, M, DI }, {LDA, M, SIY },
+ {LDY, X, DX }, {LDA, M, DX }, {LDX, X, DY }, {LDA, M, DLIY},
+ {CLV, I, IMP }, {LDA, M, AY }, {TSX, I, IMP }, {TYX, I, IMP },
+ {LDY, X, AX }, {LDA, M, AX }, {LDX, X, AY }, {LDA, M, ALX },
+ {CPY, X, IMM }, {CMP, M, DXI }, {REP, I, IMM }, {CMP, M, S },
+ {CPY, X, D }, {CMP, M, D }, {DEC, M, D }, {CMP, M, DLI },
+ {INY, I, IMP }, {CMP, M, IMM }, {DEX, I, IMP }, {WAI, I, IMP },
+ {CPY, X, A }, {CMP, M, A }, {DEC, M, A }, {CMP, M, AL },
+ {BNE, I, RELB}, {CMP, M, DIY }, {CMP, M, DI }, {CMP, M, SIY },
+ {PEI, I, PEI }, {CMP, M, DX }, {DEC, M, DX }, {CMP, M, DLIY},
+ {CLD, I, IMP }, {CMP, M, AY }, {PHX, I, IMP }, {STP, I, IMP },
+ {JML, I, AI }, {CMP, M, AX }, {DEC, M, AX }, {CMP, M, ALX },
+ {CPX, X, IMM }, {SBC, M, DXI }, {SEP, I, IMM }, {SBC, M, S },
+ {CPX, X, D }, {SBC, M, D }, {INC, M, D }, {SBC, M, DLI },
+ {INX, M, IMP }, {SBC, M, IMM }, {NOP, I, IMP }, {XBA, I, IMP },
+ {CPX, X, A }, {SBC, M, A }, {INC, M, A }, {SBC, M, AL },
+ {BEQ, I, RELB}, {SBC, M, DIY }, {SBC, M, DI }, {SBC, M, SIY },
+ {PEA, I, PEA }, {SBC, M, DX }, {INC, M, DX }, {SBC, M, DLIY},
+ {SED, I, IMP }, {SBC, M, AY }, {PLX, I, IMP }, {XCE, I, IMP },
+ {JSR, I, AXI }, {SBC, M, AX }, {INC, M, AX }, {SBC, M, ALX }
+};
+
+static const UINT8 *base_oprom;
+static UINT32 base_pc;
+
+INLINE unsigned int read_8(unsigned int address)
+{
+ address = ADDRESS_65816(address);
+ return base_oprom[address - base_pc];
+}
+
+INLINE unsigned int read_16(unsigned int address)
+{
+ unsigned int val = read_8(address);
+ return val | (read_8(address+1)<<8);
+}
+
+INLINE unsigned int read_24(unsigned int address)
+{
+ unsigned int val = read_8(address);
+ val |= (read_8(address+1)<<8);
+ return val | (read_8(address+2)<<16);
+}
+
+INLINE char* int_8_str(unsigned int val)
+{
+ static char str[20];
+
+ val &= 0xff;
+
+ if(val & 0x80)
+ sprintf(str, "-$%x", (0-val) & 0x7f);
+ else
+ sprintf(str, "$%x", val & 0x7f);
+
+ return str;
+}
+
+INLINE char* int_16_str(unsigned int val)
+{
+ static char str[20];
+
+ val &= 0xffff;
+
+ if(val & 0x8000)
+ sprintf(str, "-$%x", (0-val) & 0x7fff);
+ else
+ sprintf(str, "$%x", val & 0x7fff);
+
+ return str;
+}
+
+
+unsigned g65816_disassemble(char* buff, unsigned int pc, unsigned int pb, const UINT8 *oprom, int m_flag, int x_flag)
+{
+ unsigned int instruction;
+ const opcode_struct* opcode;
+ char* ptr;
+ int var;
+ int length = 1;
+ unsigned int address;
+ unsigned dasm_flags;
+
+ pb <<= 16;
+ address = pc | pb;
+
+ base_oprom = oprom;
+ base_pc = address;
+
+ instruction = read_8(address);
+ opcode = g_opcodes + instruction;
+
+ strcpy(buff, g_opnames[opcode->name]);
+ ptr = buff + strlen(buff);
+
+ switch(opcode->name)
+ {
+ case JSR:
+ case JSL:
+ dasm_flags = DASMFLAG_STEP_OVER;
+ break;
+
+ case RTI:
+ case RTL:
+ case RTS:
+ dasm_flags = DASMFLAG_STEP_OUT;
+ break;
+
+ default:
+ dasm_flags = 0;
+ break;
+ }
+
+ switch(opcode->ea)
+ {
+ case IMP :
+ break;
+ case ACC :
+ sprintf(ptr, "A");
+ break;
+ case RELB:
+ var = (INT8) read_8(address+1);
+ length++;
+ sprintf(ptr, " %06x (%s)", pb | ((pc + length + var)&0xffff), int_8_str(var));
+ break;
+ case RELW:
+ case PER :
+ var = read_16(address+1);
+ sprintf(ptr, " %06x (%s)", pb | ((pc + 1 + var)&0xffff), int_16_str(var));
+ length += 2;
+ break;
+ case IMM :
+ if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag))
+ {
+ sprintf(ptr, " #$%04x", read_16(address+1));
+ length += 2;
+ }
+ else
+ {
+ sprintf(ptr, " #$%02x", read_8(address+1));
+ length++;
+ }
+ break;
+ case A :
+ case PEA :
+ sprintf(ptr, " $%04x", read_16(address+1));
+ length += 2;
+ break;
+ case AI :
+ sprintf(ptr, " ($%04x)", read_16(address+1));
+ length += 2;
+ break;
+ case AL :
+ sprintf(ptr, " $%06x", read_24(address+1));
+ length += 3;
+ break;
+ case ALX :
+ sprintf(ptr, " $%06x,X", read_24(address+1));
+ length += 3;
+ break;
+ case AX :
+ sprintf(ptr, " $%04x,X", read_16(address+1));
+ length += 2;
+ break;
+ case AXI :
+ sprintf(ptr, " ($%04x,X)", read_16(address+1));
+ length += 2;
+ break;
+ case AY :
+ sprintf(ptr, " $%04x,Y", read_16(address+1));
+ length += 2;
+ break;
+ case D :
+ sprintf(ptr, " $%02x", read_8(address+1));
+ length++;
+ break;
+ case DI :
+ case PEI :
+ sprintf(ptr, " ($%02x)", read_8(address+1));
+ length++;
+ break;
+ case DIY :
+ sprintf(ptr, " ($%02x),Y", read_8(address+1));
+ length++;
+ break;
+ case DLI :
+ sprintf(ptr, " [$%02x]", read_8(address+1));
+ length++;
+ break;
+ case DLIY:
+ sprintf(ptr, " [$%02x],Y", read_8(address+1));
+ length++;
+ break;
+ case DX :
+ sprintf(ptr, " $%02x,X", read_8(address+1));
+ length++;
+ break;
+ case DXI :
+ sprintf(ptr, " ($%02x,X)", read_8(address+1));
+ length++;
+ break;
+ case DY :
+ sprintf(ptr, " $%02x,Y", read_8(address+1));
+ length++;
+ break;
+ case S :
+ sprintf(ptr, " %s,S", int_8_str(read_8(address+1)));
+ length++;
+ break;
+ case SIY :
+ sprintf(ptr, " (%s,S),Y", int_8_str(read_8(address+1)));
+ length++;
+ break;
+ case SIG :
+ sprintf(ptr, " #$%02x", read_8(address+1));
+ length++;
+ break;
+ case MVN :
+ case MVP :
+ sprintf(ptr, " $%02x, $%02x", read_8(address+2), read_8(address+1));
+ length += 2;
+ break;
+ }
+
+ return length | DASMFLAG_SUPPORTED | dasm_flags;
+}
diff --git a/src/emu/cpu/g65816/g65816ds.h b/src/emu/cpu/g65816/g65816ds.h
new file mode 100644
index 00000000000..53646475549
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816ds.h
@@ -0,0 +1,23 @@
+#ifndef HEADER__G65816DS
+#define HEADER__G65816DS
+/* ======================================================================== */
+/* =============================== COPYRIGHT ============================== */
+/* ======================================================================== */
+/*
+
+G65C816 CPU Emulator V0.92
+
+Copyright (c) 2000 Karl Stenerud
+All rights reserved.
+
+Permission is granted to use this source code for non-commercial purposes.
+To use this code for commercial purposes, you must get permission from the
+author (Karl Stenerud) at karl@higashiyama-unet.ocn.ne.jp.
+
+
+*/
+
+unsigned g65816_disassemble(char* buff, unsigned int pc, unsigned int pb, const UINT8 *oprom, int m_flag, int x_flag);
+
+
+#endif /* HEADER__G65816DS */
diff --git a/src/emu/cpu/g65816/g65816o0.c b/src/emu/cpu/g65816/g65816o0.c
new file mode 100644
index 00000000000..0a6782c9ec4
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816o0.c
@@ -0,0 +1,3 @@
+#include "g65816cm.h"
+#define EXECUTION_MODE EXECUTION_MODE_M0X0
+#include "g65816op.h"
diff --git a/src/emu/cpu/g65816/g65816o1.c b/src/emu/cpu/g65816/g65816o1.c
new file mode 100644
index 00000000000..1fe601fdc30
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816o1.c
@@ -0,0 +1,3 @@
+#include "g65816cm.h"
+#define EXECUTION_MODE EXECUTION_MODE_M0X1
+#include "g65816op.h"
diff --git a/src/emu/cpu/g65816/g65816o2.c b/src/emu/cpu/g65816/g65816o2.c
new file mode 100644
index 00000000000..171a45cb430
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816o2.c
@@ -0,0 +1,3 @@
+#include "g65816cm.h"
+#define EXECUTION_MODE EXECUTION_MODE_M1X0
+#include "g65816op.h"
diff --git a/src/emu/cpu/g65816/g65816o3.c b/src/emu/cpu/g65816/g65816o3.c
new file mode 100644
index 00000000000..43835320642
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816o3.c
@@ -0,0 +1,3 @@
+#include "g65816cm.h"
+#define EXECUTION_MODE EXECUTION_MODE_M1X1
+#include "g65816op.h"
diff --git a/src/emu/cpu/g65816/g65816o4.c b/src/emu/cpu/g65816/g65816o4.c
new file mode 100644
index 00000000000..5ba25617158
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816o4.c
@@ -0,0 +1,3 @@
+#include "g65816cm.h"
+#define EXECUTION_MODE EXECUTION_MODE_E
+#include "g65816op.h"
diff --git a/src/emu/cpu/g65816/g65816op.h b/src/emu/cpu/g65816/g65816op.h
new file mode 100644
index 00000000000..2e3ce3b8f8d
--- /dev/null
+++ b/src/emu/cpu/g65816/g65816op.h
@@ -0,0 +1,2452 @@
+/* ======================================================================== */
+/* ============================= CONFIGURATION ============================ */
+/* ======================================================================== */
+
+#undef FLAG_SET_E
+#undef FLAG_SET_M
+#undef FLAG_SET_X
+#if EXECUTION_MODE == EXECUTION_MODE_E
+#define FLAG_SET_E 1
+#define FLAG_SET_M 1
+#define FLAG_SET_X 1
+#elif EXECUTION_MODE == EXECUTION_MODE_M0X0
+#define FLAG_SET_E 0
+#define FLAG_SET_M 0
+#define FLAG_SET_X 0
+#elif EXECUTION_MODE == EXECUTION_MODE_M0X1
+#define FLAG_SET_E 0
+#define FLAG_SET_M 0
+#define FLAG_SET_X 1
+#elif EXECUTION_MODE == EXECUTION_MODE_M1X0
+#define FLAG_SET_E 0
+#define FLAG_SET_M 1
+#define FLAG_SET_X 0
+#elif EXECUTION_MODE == EXECUTION_MODE_M1X1
+#define FLAG_SET_E 0
+#define FLAG_SET_M 1
+#define FLAG_SET_X 1
+#endif
+
+#undef VECTOR_IRQ
+#undef VECTOR_NMI
+#undef VECTOR_ABORT
+#undef VECTOR_BRK
+#undef VECTOR_COP
+
+#if FLAG_SET_E
+#define VECTOR_IRQ VECTOR_IRQ_E
+#define VECTOR_NMI VECTOR_NMI_E
+#define VECTOR_ABORT VECTOR_ABORT_E
+#define VECTOR_BRK VECTOR_BRK_E
+#define VECTOR_COP VECTOR_COP_E
+#else /* FLAG_SET_E */
+#define VECTOR_IRQ VECTOR_IRQ_N
+#define VECTOR_NMI VECTOR_NMI_N
+#define VECTOR_ABORT VECTOR_ABORT_N
+#define VECTOR_BRK VECTOR_BRK_N
+#define VECTOR_COP VECTOR_COP_N
+#endif
+
+
+
+/* ======================================================================== */
+/* ================================= MEMORY =============================== */
+/* ======================================================================== */
+
+#define ADDRESS_65816(A) ((A)&0x00ffffff)
+
+INLINE uint g65816i_read_8_normal(uint address)
+{
+ address = ADDRESS_65816(address);
+ return g65816_read_8(address);
+}
+
+INLINE uint g65816i_read_8_immediate(uint address)
+{
+ address = ADDRESS_65816(address);
+ return g65816_read_8_immediate(address);
+}
+
+INLINE uint g65816i_read_8_direct(uint address)
+{
+#if FLAG_SET_E
+ /* force address into zero page */
+ address = REGISTER_D + MAKE_UINT_8(address - REGISTER_D);
+#else
+ address = ADDRESS_65816(address);
+#endif
+ return g65816_read_8(address);
+}
+
+INLINE uint g65816i_read_8_vector(uint address)
+{
+ if (READ_VECTOR)
+ return READ_VECTOR(address);
+ else
+ return g65816i_read_8_normal(address);
+}
+
+INLINE void g65816i_write_8_normal(uint address, uint value)
+{
+ address = ADDRESS_65816(address);
+ g65816_write_8(address, MAKE_UINT_8(value));
+}
+
+INLINE void g65816i_write_8_direct(uint address, uint value)
+{
+#if FLAG_SET_E
+ /* force address into zero page */
+ address = REGISTER_D + MAKE_UINT_8(address - REGISTER_D);
+#else
+ address = ADDRESS_65816(address);
+#endif
+ g65816_write_8(address, MAKE_UINT_8(value));
+}
+
+INLINE uint g65816i_read_16_normal(uint address)
+{
+ return g65816i_read_8_normal(address) |
+ (g65816i_read_8_normal(address+1)<<8);
+}
+
+INLINE uint g65816i_read_16_immediate(uint address)
+{
+ return g65816i_read_8_immediate(address) |
+ (g65816i_read_8_immediate(address+1)<<8);
+}
+
+INLINE uint g65816i_read_16_direct(uint address)
+{
+ return g65816i_read_8_direct(address) |
+ (g65816i_read_8_direct(address+1)<<8);
+}
+
+INLINE uint g65816i_read_16_vector(uint address)
+{
+ return g65816i_read_8_vector(address) |
+ (g65816i_read_8_vector(address+1)<<8);
+}
+
+INLINE void g65816i_write_16_normal(uint address, uint value)
+{
+ g65816i_write_8_normal(address, value&0xff);
+ g65816i_write_8_normal(address+1, value>>8);
+}
+
+INLINE void g65816i_write_16_direct(uint address, uint value)
+{
+ g65816i_write_8_direct(address, value&0xff);
+ g65816i_write_8_direct(address+1, value>>8);
+}
+
+INLINE uint g65816i_read_24_normal(uint address)
+{
+ return g65816i_read_8_normal(address) |
+ (g65816i_read_8_normal(address+1)<<8) |
+ (g65816i_read_8_normal(address+2)<<16);
+}
+
+INLINE uint g65816i_read_24_immediate(uint address)
+{
+ return g65816i_read_8_immediate(address) |
+ (g65816i_read_8_immediate(address+1)<<8) |
+ (g65816i_read_8_immediate(address+2)<<16);
+}
+
+INLINE uint g65816i_read_24_direct(uint address)
+{
+ return g65816i_read_8_direct(address) |
+ (g65816i_read_8_direct(address+1)<<8) |
+ (g65816i_read_8_direct(address+2)<<16);
+}
+
+
+
+/* ======================================================================== */
+/* ================================= STACK ================================ */
+/* ======================================================================== */
+
+INLINE void g65816i_push_8(uint value)
+{
+ g65816i_write_8_normal(REGISTER_S, value);
+#if FLAG_SET_E
+ REGISTER_S = MAKE_UINT_8(REGISTER_S-1) | 0x100;
+#else
+ REGISTER_S = MAKE_UINT_16(REGISTER_S-1);
+#endif
+}
+
+INLINE uint g65816i_pull_8(void)
+{
+#if FLAG_SET_E
+ REGISTER_S = MAKE_UINT_8(REGISTER_S+1) | 0x100;
+#else
+ REGISTER_S = MAKE_UINT_16(REGISTER_S+1);
+#endif
+ return g65816i_read_8_normal(REGISTER_S);
+}
+
+INLINE void g65816i_push_16(uint value)
+{
+ g65816i_push_8(value>>8);
+ g65816i_push_8(value&0xff);
+}
+
+INLINE uint g65816i_pull_16(void)
+{
+ uint res = g65816i_pull_8();
+ return res | (g65816i_pull_8() << 8);
+}
+
+INLINE void g65816i_push_24(uint value)
+{
+ g65816i_push_8(value>>16);
+ g65816i_push_8((value>>8)&0xff);
+ g65816i_push_8(value&0xff);
+}
+
+INLINE uint g65816i_pull_24(void)
+{
+ uint res = g65816i_pull_8();
+ res |= g65816i_pull_8() << 8;
+ return res | (g65816i_pull_8() << 16);
+}
+
+
+/* ======================================================================== */
+/* ============================ PROGRAM COUNTER =========================== */
+/* ======================================================================== */
+
+INLINE void g65816i_jump_16(uint address)
+{
+ REGISTER_PC = MAKE_UINT_16(address);
+ g65816i_jumping(REGISTER_PC);
+}
+
+INLINE void g65816i_jump_24(uint address)
+{
+ REGISTER_PB = address&0xff0000;
+ REGISTER_PC = MAKE_UINT_16(address);
+ g65816i_jumping(REGISTER_PC);
+}
+
+INLINE void g65816i_branch_8(uint offset)
+{
+#if FLAG_SET_E
+ uint old_pc = REGISTER_PC;
+ REGISTER_PC = MAKE_UINT_16(REGISTER_PC + MAKE_INT_8(offset));
+ if((REGISTER_PC^old_pc)&0xff00)
+ CLK(1);
+#else
+ REGISTER_PC = MAKE_UINT_16(REGISTER_PC + MAKE_INT_8(offset));
+#endif
+ g65816i_branching(REGISTER_PC);
+}
+
+INLINE void g65816i_branch_16(uint offset)
+{
+ REGISTER_PC = MAKE_UINT_16(REGISTER_PC + offset);
+ g65816i_branching(REGISTER_PC);
+}
+
+
+/* ======================================================================== */
+/* ============================ STATUS REGISTER =========================== */
+/* ======================================================================== */
+
+#if !FLAG_SET_E
+INLINE void g65816i_set_flag_mx(uint value)
+{
+#if FLAG_SET_M
+ if(!(value & FLAGPOS_M))
+ {
+ REGISTER_A |= REGISTER_B;
+ REGISTER_B = 0;
+ FLAG_M = MFLAG_CLEAR;
+ }
+#else
+ if(value & FLAGPOS_M)
+ {
+ REGISTER_B = REGISTER_A & 0xff00;
+ REGISTER_A = MAKE_UINT_8(REGISTER_A);
+ FLAG_M = MFLAG_SET;
+ }
+#endif
+#if FLAG_SET_X
+ if(!(value & FLAGPOS_X))
+ {
+ FLAG_X = XFLAG_CLEAR;
+ }
+#else
+ if(value & FLAGPOS_X)
+ {
+ REGISTER_X = MAKE_UINT_8(REGISTER_X);
+ REGISTER_Y = MAKE_UINT_8(REGISTER_Y);
+ FLAG_X = XFLAG_SET;
+ }
+#endif
+ g65816i_set_execution_mode((FLAG_M>>4) | (FLAG_X>>4));
+}
+#endif
+
+INLINE void g65816i_set_flag_e(uint value)
+{
+#if FLAG_SET_E
+ if(!value)
+ {
+ FLAG_E = EFLAG_CLEAR;
+ g65816i_set_execution_mode(EXECUTION_MODE_M1X1);
+ }
+#else
+ if(value)
+ {
+#if !FLAG_SET_M
+ REGISTER_B = REGISTER_A & 0xff00;
+ REGISTER_A &= 0x00ff;
+ FLAG_M = MFLAG_SET;
+#endif
+#if !FLAG_SET_X
+ REGISTER_X = MAKE_UINT_8(REGISTER_X);
+ REGISTER_Y = MAKE_UINT_8(REGISTER_Y);
+ FLAG_X = XFLAG_SET;
+#endif
+ REGISTER_S = MAKE_UINT_8(REGISTER_S) | 0x100;
+ FLAG_E = EFLAG_SET;
+ g65816i_set_execution_mode(EXECUTION_MODE_E);
+ }
+#endif
+}
+
+//INLINE void g65816i_check_maskable_interrupt(void);
+
+INLINE void g65816i_set_flag_i(uint value)
+{
+ value &= FLAGPOS_I;
+ if(!FLAG_I || value)
+ {
+ FLAG_I = value;
+ return;
+ }
+ FLAG_I = value;
+// g65816i_check_maskable_interrupt();
+}
+
+
+
+
+/* Get the Processor Status Register */
+INLINE uint g65816i_get_reg_p(void)
+{
+ return (FLAG_N&0x80) |
+ ((FLAG_V>>1)&0x40) |
+ FLAG_M |
+ FLAG_X |
+ FLAG_D |
+ FLAG_I |
+ ((!FLAG_Z)<<1) |
+ ((FLAG_C>>8)&1);
+}
+
+INLINE void g65816i_set_reg_p(uint value)
+{
+#if FLAG_SET_E
+ FLAG_N = value;
+ FLAG_V = value << 1;
+ FLAG_D = value & FLAGPOS_D;
+ FLAG_Z = !(value & FLAGPOS_Z);
+ FLAG_C = value << 8;
+ g65816i_set_flag_i(value);
+#else
+ FLAG_N = value;
+ FLAG_V = value << 1;
+ FLAG_D = value & FLAGPOS_D;
+ FLAG_Z = !(value & FLAGPOS_Z);
+ FLAG_C = value << 8;
+ g65816i_set_flag_mx(value);
+ g65816i_set_flag_i(value);
+#endif
+}
+
+
+/* ======================================================================== */
+/* =============================== INTERRUPTS ============================= */
+/* ======================================================================== */
+
+INLINE void g65816i_interrupt_hardware(uint vector)
+{
+#if FLAG_SET_E
+ CLK(7);
+ g65816i_push_16(REGISTER_PC);
+ g65816i_push_8(g65816i_get_reg_p() & ~FLAGPOS_B);
+ FLAG_D = DFLAG_CLEAR;
+ g65816i_set_flag_i(IFLAG_SET);
+ REGISTER_PB = 0;
+ g65816i_jump_16(g65816i_read_16_vector(vector));
+ if(INT_ACK) INT_ACK(0);
+#else
+ CLK(8);
+ g65816i_push_8(REGISTER_PB>>16);
+ g65816i_push_16(REGISTER_PC);
+ g65816i_push_8(g65816i_get_reg_p());
+ FLAG_D = DFLAG_CLEAR;
+ g65816i_set_flag_i(IFLAG_SET);
+ REGISTER_PB = 0;
+ g65816i_jump_16(g65816i_read_16_vector(vector));
+ if(INT_ACK) INT_ACK(0);
+#endif
+}
+
+INLINE void g65816i_interrupt_software(uint vector)
+{
+#if FLAG_SET_E
+ CLK(7);
+ g65816i_push_16(REGISTER_PC);
+ g65816i_push_8(g65816i_get_reg_p());
+ FLAG_D = DFLAG_CLEAR;
+ g65816i_set_flag_i(IFLAG_SET);
+ REGISTER_PB = 0;
+ g65816i_jump_16(g65816i_read_16_normal(vector));
+#else
+ CLK(8);
+ g65816i_push_8(REGISTER_PB>>16);
+ g65816i_push_16(REGISTER_PC);
+ g65816i_push_8(g65816i_get_reg_p());
+ FLAG_D = DFLAG_CLEAR;
+ g65816i_set_flag_i(IFLAG_SET);
+ REGISTER_PB = 0;
+ g65816i_jump_16(g65816i_read_16_normal(vector));
+#endif
+}
+
+INLINE void g65816i_interrupt_nmi(void)
+{
+#if FLAG_SET_E
+ CLK(7);
+ g65816i_push_16(REGISTER_PC);
+ g65816i_push_8(g65816i_get_reg_p() & ~FLAGPOS_B);
+ FLAG_D = DFLAG_CLEAR;
+ REGISTER_PB = 0;
+ g65816i_jump_16(g65816i_read_16_normal(VECTOR_NMI));
+#else
+ CLK(8);
+ g65816i_push_8(REGISTER_PB>>16);
+ g65816i_push_16(REGISTER_PC);
+ g65816i_push_8(g65816i_get_reg_p());
+ FLAG_D = DFLAG_CLEAR;
+ REGISTER_PB = 0;
+ g65816i_jump_16(g65816i_read_16_normal(VECTOR_NMI));
+#endif
+}
+
+
+INLINE void g65816i_check_maskable_interrupt(void)
+{
+ if(!(CPU_STOPPED & STOP_LEVEL_STOP) && LINE_IRQ && !FLAG_I)
+ {
+ g65816i_interrupt_hardware(VECTOR_IRQ);
+ CPU_STOPPED &= ~STOP_LEVEL_WAI;
+ LINE_IRQ=0;
+ }
+}
+
+
+/* ======================================================================== */
+/* ========================== EFFECTIVE ADDRESSES ========================= */
+/* ======================================================================== */
+
+/* Effective-address based memory access macros */
+#define read_8_NORM(A) g65816i_read_8_normal(A)
+#define read_8_IMM(A) g65816i_read_8_immediate(A)
+#define read_8_D(A) g65816i_read_8_direct(A)
+#define read_8_A(A) g65816i_read_8_normal(A)
+#define read_8_AL(A) g65816i_read_8_normal(A)
+#define read_8_DX(A) g65816i_read_8_direct(A)
+#define read_8_DY(A) g65816i_read_8_direct(A)
+#define read_8_AX(A) g65816i_read_8_normal(A)
+#define read_8_ALX(A) g65816i_read_8_normal(A)
+#define read_8_AY(A) g65816i_read_8_normal(A)
+#define read_8_DI(A) g65816i_read_8_normal(A)
+#define read_8_DLI(A) g65816i_read_8_normal(A)
+#define read_8_AI(A) g65816i_read_8_normal(A)
+#define read_8_ALI(A) g65816i_read_8_normal(A)
+#define read_8_DXI(A) g65816i_read_8_normal(A)
+#define read_8_DIY(A) g65816i_read_8_normal(A)
+#define read_8_DLIY(A) g65816i_read_8_normal(A)
+#define read_8_AXI(A) g65816i_read_8_normal(A)
+#define read_8_S(A) g65816i_read_8_normal(A)
+#define read_8_SIY(A) g65816i_read_8_normal(A)
+
+#define read_16_NORM(A) g65816i_read_16_normal(A)
+#define read_16_IMM(A) g65816i_read_16_immediate(A)
+#define read_16_D(A) g65816i_read_16_direct(A)
+#define read_16_A(A) g65816i_read_16_normal(A)
+#define read_16_AL(A) g65816i_read_16_normal(A)
+#define read_16_DX(A) g65816i_read_16_direct(A)
+#define read_16_DY(A) g65816i_read_16_direct(A)
+#define read_16_AX(A) g65816i_read_16_normal(A)
+#define read_16_ALX(A) g65816i_read_16_normal(A)
+#define read_16_AY(A) g65816i_read_16_normal(A)
+#define read_16_DI(A) g65816i_read_16_normal(A)
+#define read_16_DLI(A) g65816i_read_16_normal(A)
+#define read_16_AI(A) g65816i_read_16_normal(A)
+#define read_16_ALI(A) g65816i_read_16_normal(A)
+#define read_16_DXI(A) g65816i_read_16_normal(A)
+#define read_16_DIY(A) g65816i_read_16_normal(A)
+#define read_16_DLIY(A) g65816i_read_16_normal(A)
+#define read_16_AXI(A) g65816i_read_16_normal(A)
+#define read_16_S(A) g65816i_read_16_normal(A)
+#define read_16_SIY(A) g65816i_read_16_normal(A)
+
+#define read_24_NORM(A) g65816i_read_24_normal(A)
+#define read_24_IMM(A) g65816i_read_24_immediate(A)
+#define read_24_D(A) g65816i_read_24_direct(A)
+#define read_24_A(A) g65816i_read_24_normal(A)
+#define read_24_AL(A) g65816i_read_24_normal(A)
+#define read_24_DX(A) g65816i_read_24_direct(A)
+#define read_24_DY(A) g65816i_read_24_direct(A)
+#define read_24_AX(A) g65816i_read_24_normal(A)
+#define read_24_ALX(A) g65816i_read_24_normal(A)
+#define read_24_AY(A) g65816i_read_24_normal(A)
+#define read_24_DI(A) g65816i_read_24_normal(A)
+#define read_24_DLI(A) g65816i_read_24_normal(A)
+#define read_24_AI(A) g65816i_read_24_normal(A)
+#define read_24_ALI(A) g65816i_read_24_normal(A)
+#define read_24_DXI(A) g65816i_read_24_normal(A)
+#define read_24_DIY(A) g65816i_read_24_normal(A)
+#define read_24_DLIY(A) g65816i_read_24_normal(A)
+#define read_24_AXI(A) g65816i_read_24_normal(A)
+#define read_24_S(A) g65816i_read_24_normal(A)
+#define read_24_SIY(A) g65816i_read_24_normal(A)
+
+#define write_8_NORM(A, V) g65816i_write_8_normal(A, V)
+#define write_8_D(A, V) g65816i_write_8_direct(A, V)
+#define write_8_A(A, V) g65816i_write_8_normal(A, V)
+#define write_8_AL(A, V) g65816i_write_8_normal(A, V)
+#define write_8_DX(A, V) g65816i_write_8_direct(A, V)
+#define write_8_DY(A, V) g65816i_write_8_direct(A, V)
+#define write_8_AX(A, V) g65816i_write_8_normal(A, V)
+#define write_8_ALX(A, V) g65816i_write_8_normal(A, V)
+#define write_8_AY(A, V) g65816i_write_8_normal(A, V)
+#define write_8_DI(A, V) g65816i_write_8_normal(A, V)
+#define write_8_DLI(A, V) g65816i_write_8_normal(A, V)
+#define write_8_AI(A, V) g65816i_write_8_normal(A, V)
+#define write_8_ALI(A, V) g65816i_write_8_normal(A, V)
+#define write_8_DXI(A, V) g65816i_write_8_normal(A, V)
+#define write_8_DIY(A, V) g65816i_write_8_normal(A, V)
+#define write_8_DLIY(A, V) g65816i_write_8_normal(A, V)
+#define write_8_AXI(A, V) g65816i_write_8_normal(A, V)
+#define write_8_S(A, V) g65816i_write_8_normal(A, V)
+#define write_8_SIY(A, V) g65816i_write_8_normal(A, V)
+
+#define write_16_NORM(A, V) g65816i_write_16_normal(A, V)
+#define write_16_D(A, V) g65816i_write_16_direct(A, V)
+#define write_16_A(A, V) g65816i_write_16_normal(A, V)
+#define write_16_AL(A, V) g65816i_write_16_normal(A, V)
+#define write_16_DX(A, V) g65816i_write_16_direct(A, V)
+#define write_16_DY(A, V) g65816i_write_16_direct(A, V)
+#define write_16_AX(A, V) g65816i_write_16_normal(A, V)
+#define write_16_ALX(A, V) g65816i_write_16_normal(A, V)
+#define write_16_AY(A, V) g65816i_write_16_normal(A, V)
+#define write_16_DI(A, V) g65816i_write_16_normal(A, V)
+#define write_16_DLI(A, V) g65816i_write_16_normal(A, V)
+#define write_16_AI(A, V) g65816i_write_16_normal(A, V)
+#define write_16_ALI(A, V) g65816i_write_16_normal(A, V)
+#define write_16_DXI(A, V) g65816i_write_16_normal(A, V)
+#define write_16_DIY(A, V) g65816i_write_16_normal(A, V)
+#define write_16_DLIY(A, V) g65816i_write_16_normal(A, V)
+#define write_16_AXI(A, V) g65816i_write_16_normal(A, V)
+#define write_16_S(A, V) g65816i_write_16_normal(A, V)
+#define write_16_SIY(A, V) g65816i_write_16_normal(A, V)
+
+
+#define OPER_8_IMM() read_8_IMM(EA_IMM8())
+#define OPER_8_D() read_8_D(EA_D())
+#define OPER_8_A() read_8_A(EA_A())
+#define OPER_8_AL() read_8_AL(EA_AL())
+#define OPER_8_DX() read_8_DX(EA_DX())
+#define OPER_8_DY() read_8_DY(EA_DY())
+#define OPER_8_AX() read_8_AX(EA_AX())
+#define OPER_8_ALX() read_8_ALX(EA_ALX())
+#define OPER_8_AY() read_8_AY(EA_AY())
+#define OPER_8_DI() read_8_DI(EA_DI())
+#define OPER_8_DLI() read_8_DLI(EA_DLI())
+#define OPER_8_AI() read_8_AI(EA_AI())
+#define OPER_8_ALI() read_8_ALI(EA_ALI())
+#define OPER_8_DXI() read_8_DXI(EA_DXI())
+#define OPER_8_DIY() read_8_DIY(EA_DIY())
+#define OPER_8_DLIY() read_8_DLIY(EA_DLIY())
+#define OPER_8_AXI() read_8_AXI(EA_AXI())
+#define OPER_8_S() read_8_S(EA_S())
+#define OPER_8_SIY() read_8_SIY(EA_SIY())
+
+#define OPER_16_IMM() read_16_IMM(EA_IMM16())
+#define OPER_16_D() read_16_D(EA_D())
+#define OPER_16_A() read_16_A(EA_A())
+#define OPER_16_AL() read_16_AL(EA_AL())
+#define OPER_16_DX() read_16_DX(EA_DX())
+#define OPER_16_DY() read_16_DY(EA_DY())
+#define OPER_16_AX() read_16_AX(EA_AX())
+#define OPER_16_ALX() read_16_ALX(EA_ALX())
+#define OPER_16_AY() read_16_AY(EA_AY())
+#define OPER_16_DI() read_16_DI(EA_DI())
+#define OPER_16_DLI() read_16_DLI(EA_DLI())
+#define OPER_16_AI() read_16_AI(EA_AI())
+#define OPER_16_ALI() read_16_ALI(EA_ALI())
+#define OPER_16_DXI() read_16_DXI(EA_DXI())
+#define OPER_16_DIY() read_16_DIY(EA_DIY())
+#define OPER_16_DLIY() read_16_DLIY(EA_DLIY())
+#define OPER_16_AXI() read_16_AXI(EA_AXI())
+#define OPER_16_S() read_16_S(EA_S())
+#define OPER_16_SIY() read_16_SIY(EA_SIY())
+
+#define OPER_24_IMM() read_24_IMM(EA_IMM24())
+#define OPER_24_D() read_24_D(EA_D())
+#define OPER_24_A() read_24_A(EA_A())
+#define OPER_24_AL() read_24_AL(EA_AL())
+#define OPER_24_DX() read_24_DX(EA_DX())
+#define OPER_24_DY() read_24_DY(EA_DY())
+#define OPER_24_AX() read_24_AX(EA_AX())
+#define OPER_24_ALX() read_24_ALX(EA_ALX())
+#define OPER_24_AY() read_24_AY(EA_AY())
+#define OPER_24_DI() read_24_DI(EA_DI())
+#define OPER_24_DLI() read_24_DLI(EA_DLI())
+#define OPER_24_AI() read_24_AI(EA_AI())
+#define OPER_24_ALI() read_24_ALI(EA_ALI())
+#define OPER_24_DXI() read_24_DXI(EA_DXI())
+#define OPER_24_DIY() read_24_DIY(EA_DIY())
+#define OPER_24_DLIY() read_24_DLIY(EA_DLIY())
+#define OPER_24_AXI() read_24_AXI(EA_AXI())
+#define OPER_24_S() read_24_S(EA_S())
+#define OPER_24_SIY() read_24_SIY(EA_SIY())
+
+INLINE uint EA_IMM8(void) {REGISTER_PC += 1; return REGISTER_PB | MAKE_UINT_16(REGISTER_PC-1);}
+INLINE uint EA_IMM16(void) {REGISTER_PC += 2; return REGISTER_PB | MAKE_UINT_16(REGISTER_PC-2);}
+INLINE uint EA_IMM24(void) {REGISTER_PC += 3; return REGISTER_PB | MAKE_UINT_16(REGISTER_PC-3);}
+INLINE uint EA_D(void) {if(MAKE_UINT_8(REGISTER_D)) CLK(1); return MAKE_UINT_16(REGISTER_D + OPER_8_IMM());}
+INLINE uint EA_A(void) {return REGISTER_DB | OPER_16_IMM();}
+INLINE uint EA_AL(void) {return OPER_24_IMM();}
+INLINE uint EA_DX(void) {return MAKE_UINT_16(REGISTER_D + OPER_8_IMM() + REGISTER_X);}
+INLINE uint EA_DY(void) {return MAKE_UINT_16(REGISTER_D + OPER_8_IMM() + REGISTER_Y);}
+INLINE uint EA_AX(void) {uint tmp = EA_A(); if((tmp^(tmp+REGISTER_X))&0xff00) CLK(1); return tmp + REGISTER_X;}
+INLINE uint EA_ALX(void) {return EA_AL() + REGISTER_X;}
+INLINE uint EA_AY(void) {uint tmp = EA_A(); if((tmp^(tmp+REGISTER_X))&0xff00) CLK(1); return tmp + REGISTER_Y;}
+INLINE uint EA_DI(void) {return REGISTER_DB | OPER_16_D();}
+INLINE uint EA_DLI(void) {return OPER_24_D();}
+INLINE uint EA_AI(void) {return read_16_A(OPER_16_IMM());}
+INLINE uint EA_ALI(void) {return OPER_24_A();}
+INLINE uint EA_DXI(void) {return REGISTER_DB | OPER_16_DX();}
+INLINE uint EA_DIY(void) {uint tmp = REGISTER_DB | OPER_16_D(); if((tmp^(tmp+REGISTER_X))&0xff00) CLK(1); return tmp + REGISTER_Y;}
+INLINE uint EA_DLIY(void) {return OPER_24_D() + REGISTER_Y;}
+INLINE uint EA_AXI(void) {return read_16_AXI(MAKE_UINT_16(OPER_16_IMM() + REGISTER_X));}
+INLINE uint EA_S(void) {return MAKE_UINT_16(REGISTER_S + OPER_8_IMM());}
+INLINE uint EA_SIY(void) {return MAKE_UINT_16(read_16_SIY(REGISTER_S + OPER_8_IMM()) + REGISTER_Y) | REGISTER_DB;}
+
+
+
+/* ======================================================================== */
+/* =========================== OPERATION MACROS =========================== */
+/* ======================================================================== */
+
+/* M6502 Add With Carry */
+#undef OP_ADC
+#if FLAG_SET_M
+#define OP_ADC(MODE) \
+ { \
+ unsigned tmp16; \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ SRC = OPER_8_##MODE(); \
+ if(FLAG_D) \
+ { \
+ unsigned tmp1, tmp2, tmpA, tmpB; \
+ tmp1 = REGISTER_A & 0x0F; \
+ tmp2 = (REGISTER_A >> 4) & 0x0F; \
+ tmpA = SRC&0x0F; \
+ tmpB = (SRC >> 4) & 0x0F; \
+ tmp1 = tmp1 + tmpA + CFLAG_AS_1(); \
+ tmp2 = tmp2 + tmpB; \
+ FLAG_C = CFLAG_CLEAR; \
+ if(tmp1 > 0x09) \
+ { \
+ tmp2++; \
+ tmp1 = ((tmp1 + 6) & 0x0F); \
+ } \
+ if(tmp2 > 0x09) \
+ { \
+ tmp2=((tmp2 + 6) & 0x0F); \
+ FLAG_C = CFLAG_SET; \
+ } \
+ tmp16 = tmp1 | (tmp2 << 4); \
+ FLAG_V = VFLAG_ADD_8(SRC, REGISTER_A, tmp16); \
+ } \
+ else \
+ { \
+ FLAG_C = tmp16 = REGISTER_A + SRC + CFLAG_AS_1(); \
+ FLAG_V = VFLAG_ADD_8(SRC, REGISTER_A, FLAG_C); \
+ } \
+ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(tmp16); \
+ }
+
+#else
+#define OP_ADC(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ SRC = OPER_16_##MODE(); \
+ if(!FLAG_D) \
+ { \
+ FLAG_C = REGISTER_A + SRC + CFLAG_AS_1(); \
+ FLAG_V = VFLAG_ADD_16(SRC, REGISTER_A, FLAG_C); \
+ FLAG_Z = REGISTER_A = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(REGISTER_A); \
+ FLAG_C = CFLAG_16(FLAG_C); \
+ BREAKOUT; \
+ } \
+ else \
+ { \
+ unsigned tmp16; \
+ unsigned tmp1,tmp2,tmp3, tmp4, tmpA, tmpB, tmpC, tmpD; \
+ tmp1 = REGISTER_A & 0x0F; \
+ tmp2 = (REGISTER_A >> 4) & 0x0F; \
+ tmp3 = (REGISTER_A >> 8) & 0x0F; \
+ tmp4 = (REGISTER_A >> 12) & 0x0F; \
+ tmpA = SRC & 0x0F; \
+ tmpB = (SRC >> 4) & 0x0F; \
+ tmpC = (SRC >> 8) & 0x0F; \
+ tmpD = (SRC >> 12) & 0x0F; \
+ tmp1 = tmp1 + tmpA + CFLAG_AS_1(); \
+ tmp2 = tmp2 + tmpB; \
+ tmp3 = tmp3 + tmpC; \
+ tmp4 = tmp4 + tmpD; \
+ FLAG_C = CFLAG_CLEAR; \
+ if(tmp1 > 9) \
+ { \
+ tmp2++; \
+ tmp1 = ((tmp1 + 6) & 0x0F); \
+ } \
+ if(tmp2 > 9) \
+ { \
+ tmp3++; \
+ tmp2 = ((tmp2 + 6) & 0x0F); \
+ } \
+ if(tmp3 > 9) \
+ { \
+ tmp4++; \
+ tmp3 = ((tmp3 + 6) & 0x0F); \
+ } \
+ if(tmp4 > 9) \
+ { \
+ FLAG_C = CFLAG_SET; \
+ tmp4 = ((tmp4 + 6) & 0x0F); \
+ } \
+ tmp16 = tmp1 | (tmp2 << 4) | (tmp3 << 8) | (tmp4 << 12); \
+ FLAG_V = VFLAG_ADD_16(SRC, REGISTER_A, tmp16); \
+ FLAG_Z = REGISTER_A = MAKE_UINT_16(tmp16); \
+ FLAG_N = NFLAG_16(REGISTER_A); \
+ }
+
+#endif
+
+
+/* M6502 Logical AND with accumulator */
+#undef OP_AND
+#if FLAG_SET_M
+#define OP_AND(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REGISTER_A &= OPER_8_##MODE()
+#else
+#define OP_AND(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REGISTER_A &= OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REGISTER_A)
+#endif
+
+/* M6502 Arithmetic Shift Left accumulator */
+#undef OP_ASL
+#if FLAG_SET_M
+#define OP_ASL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = REGISTER_A << 1; \
+ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(FLAG_C)
+#else
+#define OP_ASL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = REGISTER_A << 1; \
+ FLAG_Z = REGISTER_A = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C)
+#endif
+
+/* M6502 Arithmetic Shift Left operand */
+#undef OP_ASLM
+#if FLAG_SET_M
+#define OP_ASLM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_C = read_8_##MODE(DST) << 1; \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_ASLM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_C = read_16_##MODE(DST) << 1; \
+ FLAG_Z = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M6502 Branch on Condition Code */
+#undef OP_BCC
+#define OP_BCC(COND) \
+ DST = OPER_8_IMM(); \
+ if(COND) \
+ { \
+ CLK(CLK_OP + CLK_RELATIVE_8 + 1); \
+ g65816i_branch_8(DST); \
+ BREAKOUT; \
+ } \
+ CLK(CLK_OP + CLK_RELATIVE_8); \
+
+/* M6502 Set flags according to bits */
+#undef OP_BIT
+#if FLAG_SET_M
+#define OP_BIT(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = OPER_8_##MODE(); \
+ FLAG_Z = FLAG_N & REGISTER_A; \
+ FLAG_V = FLAG_N << 1
+#else
+#define OP_BIT(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_N = OPER_16_##MODE(); \
+ FLAG_Z = FLAG_N & REGISTER_A; \
+ FLAG_N = NFLAG_16(FLAG_N); \
+ FLAG_V = FLAG_N << 1
+#endif
+
+/* G65816 Set flags according to bits (immediate addressing mode) */
+#undef OP_BITI
+#if FLAG_SET_M
+#define OP_BITI() \
+ CLK(CLK_OP + CLK_R8 + CLK_IMM); \
+ FLAG_Z = REGISTER_A & OPER_8_IMM()
+#else
+#define OP_BITI() \
+ CLK(CLK_OP + CLK_R16 + CLK_IMM); \
+ FLAG_Z = REGISTER_A & OPER_16_IMM()
+#endif
+
+/* M6502 Cause a Break interrupt */
+#undef OP_BRK
+#define OP_BRK() \
+ REGISTER_PC++; \
+ g65816i_interrupt_software(VECTOR_BRK)
+
+/* G65816 Branch Always */
+#undef OP_BRA
+#define OP_BRA() \
+ CLK(CLK_OP + CLK_IMPLIED + CLK_RELATIVE_8); \
+ g65816i_branch_8(OPER_8_IMM())
+
+/* G65816 Branch Always Long */
+#undef OP_BRL
+#define OP_BRL() \
+ CLK(CLK_OP + CLK_IMPLIED + CLK_RELATIVE_16); \
+ g65816i_branch_16(OPER_16_IMM())
+
+/* M6502 Clear Carry flag */
+#undef OP_CLC
+#define OP_CLC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = CFLAG_CLEAR
+
+/* M6502 Clear Decimal flag */
+#undef OP_CLD
+#define OP_CLD() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_D = DFLAG_CLEAR
+
+/* M6502 Clear Interrupt Mask flag */
+#undef OP_CLI
+#define OP_CLI() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ g65816i_set_flag_i(IFLAG_CLEAR)
+
+/* M6502 Clear oVerflow flag */
+#undef OP_CLV
+#define OP_CLV() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_V = VFLAG_CLEAR
+
+/* M6502 Compare operand to accumulator */
+/* Unusual behavior: C flag is inverted */
+#undef OP_CMP
+#if FLAG_SET_M
+#define OP_CMP(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_C = REGISTER_A - OPER_8_##MODE(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ FLAG_C ^= CFLAG_SET
+#else
+#define OP_CMP(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_C = REGISTER_A - OPER_16_##MODE(); \
+ FLAG_Z = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = ~CFLAG_16(FLAG_C)
+#endif
+
+/* M6502 Compare operand to index register */
+/* Unusual behavior: C flag is inverted */
+#undef OP_CMPX
+#if FLAG_SET_X
+#define OP_CMPX(REG, MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_C = REG - OPER_8_##MODE(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ FLAG_C ^= CFLAG_SET
+#else
+#define OP_CMPX(REG, MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_C = REG - OPER_16_##MODE(); \
+ FLAG_Z = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = ~CFLAG_16(FLAG_C)
+#endif
+
+/* G65816 Coprocessor operation */
+#undef OP_COP
+#define OP_COP() \
+ REGISTER_PC++; \
+ g65816i_interrupt_software(VECTOR_COP)
+
+/* M6502 Decrement accumulator */
+#undef OP_DEC
+#if FLAG_SET_M
+#define OP_DEC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(REGISTER_A - 1)
+#else
+#define OP_DEC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_A = MAKE_UINT_16(REGISTER_A - 1); \
+ FLAG_N = NFLAG_16(REGISTER_A)
+#endif
+
+/* M6502 Decrement operand */
+#undef OP_DECM
+#if FLAG_SET_M
+#define OP_DECM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(read_8_##MODE(DST) - 1); \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_DECM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = MAKE_UINT_16(read_16_##MODE(DST) - 1); \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M6502 Decrement index register */
+#undef OP_DECX
+#if FLAG_SET_X
+#define OP_DECX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REG = MAKE_UINT_8(REG - 1)
+#else
+#define OP_DECX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = MAKE_UINT_16(REG - 1); \
+ FLAG_N = NFLAG_16(REG)
+#endif
+
+/* M6502 Exclusive Or operand to accumulator */
+#undef OP_EOR
+#if FLAG_SET_M
+#define OP_EOR(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REGISTER_A ^= OPER_8_##MODE()
+#else
+#define OP_EOR(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REGISTER_A ^= OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REGISTER_A)
+#endif
+
+/* M6502 Increment accumulator */
+#undef OP_INC
+#if FLAG_SET_M
+#define OP_INC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(REGISTER_A + 1)
+#else
+#define OP_INC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_A = MAKE_UINT_16(REGISTER_A + 1); \
+ FLAG_N = NFLAG_16(REGISTER_A)
+#endif
+
+/* M6502 Increment operand */
+#undef OP_INCM
+#if FLAG_SET_M
+#define OP_INCM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(read_8_##MODE(DST) + 1); \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_INCM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = MAKE_UINT_16(read_16_##MODE(DST) + 1); \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M6502 Increment index register */
+#undef OP_INCX
+#if FLAG_SET_X
+#define OP_INCX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REG = MAKE_UINT_8(REG + 1)
+#else
+#define OP_INCX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = MAKE_UINT_16(REG + 1); \
+ FLAG_N = NFLAG_16(REG)
+#endif
+
+/* G65816 Jump Long */
+#undef OP_JMLAI
+#define OP_JMLAI() \
+ CLK(CLK_OP + CLK_AI + 1); \
+ g65816i_jump_24(read_24_A(OPER_16_IMM()))
+
+/* M6502 Jump */
+#undef OP_JMP
+#define OP_JMP(MODE) \
+ CLK(CLK_OP + CLK_##MODE); \
+ g65816i_jump_16(EA_##MODE())
+
+/* M6502 Jump absolute indexed indirect */
+#undef OP_JMPAXI
+#define OP_JMPAXI() \
+ CLK(CLK_OP + CLK_AXI); \
+ g65816i_jump_16(read_16_AXI(REGISTER_PB | (MAKE_UINT_16(OPER_16_IMM() + REGISTER_X))))
+
+/* G65816 Jump absolute long */
+#undef OP_JMPAL
+#define OP_JMPAL() \
+ CLK(CLK_OP + CLK_AL); \
+ g65816i_jump_24(EA_AL())
+
+/* G65816 Jump to Subroutine Long */
+/* Unusual behavior: stacks PC-1 */
+#undef OP_JSL
+#define OP_JSL(MODE) \
+ CLK(CLK_OP + CLK_W24 + CLK_##MODE + 1); \
+ DST = EA_##MODE(); \
+ g65816i_push_8(REGISTER_PB>>16); \
+ g65816i_push_16(REGISTER_PC-1); \
+ g65816i_jump_24(DST)
+
+/* M6502 Jump to Subroutine */
+/* Unusual behavior: stacks PC-1 */
+#undef OP_JSR
+#define OP_JSR(MODE) \
+ CLK(CLK_OP + CLK_W16 + CLK_##MODE); \
+ DST = EA_##MODE(); \
+ g65816i_push_16(REGISTER_PC-1); \
+ g65816i_jump_16(DST)
+
+/* M6502 Jump to Subroutine */
+/* Unusual behavior: stacks PC-1 */
+#undef OP_JSRAXI
+#define OP_JSRAXI() \
+ CLK(CLK_OP + CLK_W16 + CLK_AXI); \
+ DST = read_16_AXI(REGISTER_PB | (MAKE_UINT_16(OPER_16_IMM() + REGISTER_X))); \
+ g65816i_push_16(REGISTER_PC-1); \
+ g65816i_jump_16(DST)
+
+/* M6502 Load accumulator with operand */
+#undef OP_LDA
+#if FLAG_SET_M
+#define OP_LDA(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REGISTER_A = OPER_8_##MODE()
+#else
+#define OP_LDA(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REGISTER_A = OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REGISTER_A)
+#endif
+
+/* M6502 Load index register with operand */
+#undef OP_LDX
+#if FLAG_SET_X
+#define OP_LDX(REG, MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG = OPER_8_##MODE()
+#else
+#define OP_LDX(REG, MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG = OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG)
+#endif
+
+/* M6502 Logical Shift Right accumulator */
+#undef OP_LSR
+#if FLAG_SET_M
+#define OP_LSR() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = 0; \
+ FLAG_C = REGISTER_A << 8; \
+ FLAG_Z = REGISTER_A >>= 1
+#else
+#define OP_LSR() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = 0; \
+ FLAG_C = REGISTER_A << 8; \
+ FLAG_Z = REGISTER_A >>= 1
+#endif
+
+/* M6502 Logical Shift Right operand */
+#undef OP_LSRM
+#if FLAG_SET_M
+#define OP_LSRM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_N = 0; \
+ FLAG_Z = read_8_##MODE(DST); \
+ FLAG_C = FLAG_Z << 8; \
+ FLAG_Z >>= 1; \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_LSRM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_N = 0; \
+ FLAG_Z = read_16_##MODE(DST); \
+ FLAG_C = FLAG_Z << 8; \
+ FLAG_Z >>= 1; \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* G65816 Move Block Negative */
+#undef OP_MVN
+#if FLAG_SET_M
+#if FLAG_SET_X
+#define OP_MVN() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REGISTER_DB = DST; \
+ CLK(7); \
+ write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \
+ REGISTER_X = MAKE_UINT_8(REGISTER_X+1); \
+ REGISTER_Y = MAKE_UINT_8(REGISTER_Y+1); \
+ REGISTER_A--; \
+ if ((REGISTER_A&0xff) != 0xff) \
+ {\
+ REGISTER_PC -= 3; \
+ }\
+ else \
+ { \
+ REGISTER_B -= 0x100;\
+ if ((REGISTER_B & 0xff00) != 0xff00)\
+ { \
+ REGISTER_PC -= 3;\
+ } \
+ }
+#else
+#define OP_MVN() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REGISTER_DB = DST; \
+ CLK(7); \
+ write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \
+ REGISTER_X = MAKE_UINT_16(REGISTER_X+1); \
+ REGISTER_Y = MAKE_UINT_16(REGISTER_Y+1); \
+ REGISTER_A--; \
+ if ((REGISTER_A&0xff) != 0xff) \
+ {\
+ REGISTER_PC -= 3; \
+ }\
+ else \
+ { \
+ REGISTER_B -= 0x100;\
+ if ((REGISTER_B & 0xff00) != 0xff00)\
+ { \
+ REGISTER_PC -= 3;\
+ } \
+ }
+#endif
+#else
+#if FLAG_SET_X
+#define OP_MVN() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REGISTER_DB = DST; \
+ REGISTER_A |= REGISTER_B; \
+ CLK(7); \
+ write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \
+ REGISTER_X = MAKE_UINT_8(REGISTER_X+1); \
+ REGISTER_Y = MAKE_UINT_8(REGISTER_Y+1); \
+ REGISTER_A--; \
+ if ((REGISTER_A&0xffff) != 0xffff) \
+ {\
+ REGISTER_PC -= 3; \
+ }
+#else
+#define OP_MVN() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REGISTER_DB = DST; \
+ REGISTER_A |= REGISTER_B; \
+ CLK(7); \
+ write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \
+ REGISTER_X = MAKE_UINT_16(REGISTER_X+1); \
+ REGISTER_Y = MAKE_UINT_16(REGISTER_Y+1); \
+ REGISTER_A--; \
+ if ((REGISTER_A&0xffff) != 0xffff) \
+ {\
+ REGISTER_PC -= 3; \
+ }
+#endif
+#endif
+
+/* G65816 Move Block Positive */
+#undef OP_MVP
+#if FLAG_SET_M
+#if FLAG_SET_X
+#define OP_MVP() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REGISTER_DB = DST; \
+ CLK(7); \
+ write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \
+ REGISTER_X = MAKE_UINT_8(REGISTER_X-1); \
+ REGISTER_Y = MAKE_UINT_8(REGISTER_Y-1); \
+ REGISTER_A--; \
+ if ((REGISTER_A&0xff) != 0xff) \
+ {\
+ REGISTER_PC -= 3; \
+ }\
+ else \
+ { \
+ REGISTER_B -= 0x100;\
+ if ((REGISTER_B & 0xff00) != 0xff00)\
+ { \
+ REGISTER_PC -= 3;\
+ } \
+ }
+#else
+#define OP_MVP() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REGISTER_DB = DST; \
+ CLK(7); \
+ write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \
+ REGISTER_X = MAKE_UINT_16(REGISTER_X-1); \
+ REGISTER_Y = MAKE_UINT_16(REGISTER_Y-1); \
+ REGISTER_A--; \
+ if ((REGISTER_A&0xff) != 0xff) \
+ {\
+ REGISTER_PC -= 3; \
+ }\
+ else \
+ { \
+ REGISTER_B -= 0x100;\
+ if ((REGISTER_B & 0xff00) != 0xff00)\
+ { \
+ REGISTER_PC -= 3;\
+ } \
+ }
+#endif
+#else
+#if FLAG_SET_X
+#define OP_MVP() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REGISTER_DB = DST; \
+ REGISTER_A |= REGISTER_B; \
+ CLK(7); \
+ write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \
+ REGISTER_X = MAKE_UINT_8(REGISTER_X-1); \
+ REGISTER_Y = MAKE_UINT_8(REGISTER_Y-1); \
+ REGISTER_A--; \
+ if ((REGISTER_A&0xffff) != 0xffff) \
+ {\
+ REGISTER_PC -= 3; \
+ }
+#else
+#define OP_MVP() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REGISTER_DB = DST; \
+ REGISTER_A |= REGISTER_B; \
+ CLK(7); \
+ write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \
+ REGISTER_X = MAKE_UINT_16(REGISTER_X-1); \
+ REGISTER_Y = MAKE_UINT_16(REGISTER_Y-1); \
+ REGISTER_A--; \
+ if ((REGISTER_A&0xffff) != 0xffff) \
+ {\
+ REGISTER_PC -= 3; \
+ }
+#endif
+#endif
+
+/* M6502 No Operation */
+#undef OP_NOP
+#define OP_NOP() \
+ CLK(CLK_OP + CLK_IMPLIED)
+
+/* M6502 Logical OR operand to accumulator */
+#undef OP_ORA
+#if FLAG_SET_M
+#define OP_ORA(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REGISTER_A |= OPER_8_ ## MODE()
+#else
+#define OP_ORA(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REGISTER_A |= OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REGISTER_A)
+#endif
+
+/* G65816 Push Effective Address */
+#undef OP_PEA
+#define OP_PEA() \
+ CLK(CLK_OP + CLK_R16 + CLK_W16); \
+ g65816i_push_16(OPER_16_IMM())
+
+/* G65816 Push Effective Indirect Address */
+#undef OP_PEI
+#define OP_PEI() \
+ CLK(CLK_OP + CLK_R16 + CLK_W16 + CLK_D); \
+ g65816i_push_16(EA_DI())
+
+/* G65816 Push Effective PC-Relative Address */
+#undef OP_PER
+#define OP_PER() \
+ CLK(CLK_OP + CLK_R16 + CLK_W16 + 1); \
+ SRC = OPER_16_IMM(); \
+ g65816i_push_16(REGISTER_PC + SRC)
+
+/* M6502 Push accumulator to the stack */
+#undef OP_PHA
+#if FLAG_SET_M
+#define OP_PHA() \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ g65816i_push_8(REGISTER_A)
+#else
+#define OP_PHA() \
+ CLK(CLK_OP + CLK_W16 + 1); \
+ g65816i_push_16(REGISTER_A)
+#endif
+
+/* M6502 Push index register to the stack */
+#undef OP_PHX
+#if FLAG_SET_X
+#define OP_PHX(REG) \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ g65816i_push_8(REG)
+#else
+#define OP_PHX(REG) \
+ CLK(CLK_OP + CLK_W16 + 1); \
+ g65816i_push_16(REG)
+#endif
+
+/* G65816 Push data bank register */
+#undef OP_PHB
+#define OP_PHB() \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ g65816i_push_8(REGISTER_DB>>16)
+
+/* G65816 Push direct register */
+#undef OP_PHD
+#define OP_PHD() \
+ CLK(CLK_OP + CLK_W16 + 1); \
+ g65816i_push_16(REGISTER_D)
+
+/* G65816 Push program bank register */
+#undef OP_PHK
+#define OP_PHK() \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ g65816i_push_8(REGISTER_PB>>16)
+
+/* M6502 Push the Processor Status Register to the stack */
+#undef OP_PHP
+#define OP_PHP() \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ g65816i_push_8(g65816i_get_reg_p())
+
+/* M6502 Pull accumulator from the stack */
+#undef OP_PLA
+#if FLAG_SET_M
+#define OP_PLA() \
+ CLK(CLK_OP + CLK_R8 + 2); \
+ FLAG_N = FLAG_Z = REGISTER_A = g65816i_pull_8()
+#else
+#define OP_PLA() \
+ CLK(CLK_OP + CLK_R16 + 2); \
+ FLAG_Z = REGISTER_A = g65816i_pull_16(); \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M6502 Pull index register from the stack */
+#undef OP_PLX
+#if FLAG_SET_X
+#define OP_PLX(REG) \
+ CLK(CLK_OP + CLK_R8 + 2); \
+ FLAG_N = FLAG_Z = REG = g65816i_pull_8()
+#else
+#define OP_PLX(REG) \
+ CLK(CLK_OP + CLK_R16 + 2); \
+ FLAG_Z = REG = g65816i_pull_16(); \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* G65816 Pull data bank register */
+#undef OP_PLB
+#define OP_PLB() \
+ CLK(CLK_OP + CLK_R8 + 2); \
+ FLAG_N = FLAG_Z = g65816i_pull_8(); \
+ REGISTER_DB = FLAG_Z << 16
+
+/* G65816 Pull direct register */
+#undef OP_PLD
+#define OP_PLD() \
+ CLK(CLK_OP + CLK_R16 + 2); \
+ FLAG_Z = REGISTER_D = g65816i_pull_16(); \
+ FLAG_N = NFLAG_16(FLAG_Z)
+
+/* M6502 Pull the Processor Status Register from the stack */
+#undef OP_PLP
+#define OP_PLP() \
+ CLK(CLK_OP + CLK_R8 + 2); \
+ g65816i_set_reg_p(g65816i_pull_8())
+
+/* G65816 Reset Program status word */
+#undef OP_REP
+#define OP_REP() \
+ CLK(CLK_OP + CLK_R8 + 1); \
+ g65816i_set_reg_p(g65816i_get_reg_p() & ~OPER_8_IMM())
+
+/* M6502 Rotate Left the accumulator */
+#undef OP_ROL
+#if FLAG_SET_M
+#define OP_ROL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = (REGISTER_A<<1) | CFLAG_AS_1(); \
+ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(FLAG_C)
+#else
+#define OP_ROL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = (REGISTER_A<<1) | CFLAG_AS_1(); \
+ FLAG_Z = REGISTER_A = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C)
+#endif
+
+/* M6502 Rotate Left an operand */
+#undef OP_ROLM
+#if FLAG_SET_M
+#define OP_ROLM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_C = (read_8_##MODE(DST)<<1) | CFLAG_AS_1(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_ROLM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_C = (read_16_##MODE(DST)<<1) | CFLAG_AS_1(); \
+ FLAG_Z = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M6502 Rotate Right the accumulator */
+#undef OP_ROR
+#if FLAG_SET_M
+#define OP_ROR() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REGISTER_A |= FLAG_C & 0x100; \
+ FLAG_C = REGISTER_A << 8; \
+ FLAG_N = FLAG_Z = REGISTER_A >>= 1
+#else
+#define OP_ROR() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REGISTER_A |= (FLAG_C<<8) & 0x10000; \
+ FLAG_C = REGISTER_A << 8; \
+ FLAG_Z = REGISTER_A >>= 1; \
+ FLAG_N = NFLAG_16(REGISTER_A)
+#endif
+
+/* M6502 Rotate Right an operand */
+#undef OP_RORM
+#if FLAG_SET_M
+#define OP_RORM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = read_8_##MODE(DST) | (FLAG_C & 0x100); \
+ FLAG_C = FLAG_Z << 8; \
+ FLAG_N = FLAG_Z >>= 1; \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_RORM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = read_16_##MODE(DST) | ((FLAG_C<<8) & 0x10000); \
+ FLAG_C = FLAG_Z << 8; \
+ FLAG_Z >>= 1; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M6502 Return from Interrupt */
+#undef OP_RTI
+#if FLAG_SET_E
+#define OP_RTI() \
+ CLK(7); \
+ g65816i_set_reg_p(g65816i_pull_8()); \
+ g65816i_jump_16(g65816i_pull_16())
+#else
+#define OP_RTI() \
+ CLK(8); \
+ g65816i_set_reg_p(g65816i_pull_8()); \
+ g65816i_jump_16(g65816i_pull_16()); \
+ REGISTER_PB = g65816i_pull_8() << 16
+#endif
+
+/* G65816 Return from Subroutine Long */
+/* Unusual behavior: Gets PC and increments */
+#undef OP_RTL
+#define OP_RTL() \
+ CLK(6); \
+ g65816i_jump_24(g65816i_pull_24()+1)
+
+/* M6502 Return from Subroutine */
+/* Unusual behavior: Gets PC and increments */
+#undef OP_RTS
+#define OP_RTS() \
+ CLK(6); \
+ g65816i_jump_16(g65816i_pull_16()+1)
+
+/* M6502 Subtract with Carry */
+/* Unusual behavior: C flag is inverted */
+#undef OP_SBC
+#if FLAG_SET_M
+#define OP_SBC(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ SRC = OPER_8_##MODE(); \
+ FLAG_C = ~FLAG_C; \
+ if(!FLAG_D) \
+ { \
+ FLAG_C = REGISTER_A - SRC - CFLAG_AS_1(); \
+ FLAG_V = VFLAG_SUB_8(SRC, REGISTER_A, FLAG_C); \
+ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(FLAG_C); \
+ FLAG_C = ~FLAG_C; \
+ BREAKOUT; \
+ } \
+ else \
+ { \
+ unsigned tmp16; \
+ signed tmp1, tmp2, tmpA, tmpB; \
+ DST = CFLAG_AS_1(); \
+ tmp1 = REGISTER_A & 0x0F; \
+ tmp2 = (REGISTER_A >> 4) & 0x0F; \
+ tmpA = SRC&0x0F; \
+ tmpB = (SRC >> 4) & 0x0F; \
+ tmp1 = tmp1 - tmpA - DST; \
+ tmp2 = tmp2 - tmpB; \
+ FLAG_C = CFLAG_CLEAR; \
+ if(tmp1 < 0) \
+ tmp2--; \
+ if((tmp1 > 0x09) || (tmp1 < 0 )) \
+ { \
+ tmp1 = ((tmp1 + 10) & 0x0F); \
+ } \
+ if(!(tmp2 < 0)) \
+ FLAG_C = CFLAG_SET; \
+ if((tmp2 > 0x09) || (tmp2 < 0)) \
+ { \
+ tmp2=((tmp2 + 10) & 0x0F); \
+ } \
+ tmp16 = tmp1 | (tmp2 << 4); \
+ FLAG_V = VFLAG_SUB_8(SRC, REGISTER_A, tmp16); \
+ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(tmp16); \
+ }
+#else
+#define OP_SBC(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ SRC = OPER_16_##MODE(); \
+ FLAG_C = ~FLAG_C; \
+ if(!FLAG_D) \
+ { \
+ FLAG_C = REGISTER_A - SRC - CFLAG_AS_1(); \
+ FLAG_V = VFLAG_SUB_16(SRC, REGISTER_A, FLAG_C); \
+ FLAG_Z = REGISTER_A = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(REGISTER_A); \
+ FLAG_C = ~CFLAG_16(FLAG_C); \
+ BREAKOUT; \
+ } \
+ else \
+ { \
+ unsigned tmp16; \
+ signed tmp1,tmp2,tmp3, tmp4, tmpA, tmpB, tmpC, tmpD; \
+ DST = CFLAG_AS_1(); \
+ tmp1 = REGISTER_A & 0x0F; \
+ tmp2 = (REGISTER_A >> 4) & 0x0F; \
+ tmp3 = (REGISTER_A >> 8) & 0x0F; \
+ tmp4 = (REGISTER_A >> 12) & 0x0F; \
+ tmpA = SRC & 0x0F; \
+ tmpB = (SRC >> 4) & 0x0F; \
+ tmpC = (SRC >> 8) & 0x0F; \
+ tmpD = (SRC >> 12) & 0x0F; \
+ tmp1 = tmp1 - tmpA - CFLAG_AS_1(); \
+ tmp2 = tmp2 - tmpB; \
+ tmp3 = tmp3 - tmpC; \
+ tmp4 = tmp4 - tmpD; \
+ FLAG_C = CFLAG_CLEAR; \
+ if(tmp1 < 0) \
+ tmp2--; \
+ if((tmp1 > 0x09) || (tmp1 < 0 )) \
+ { \
+ tmp1 = ((tmp1 + 10) & 0x0F); \
+ } \
+ if(tmp2 < 0) \
+ tmp3--; \
+ if((tmp2 > 0x09) || (tmp2 < 0)) \
+ { \
+ tmp2=((tmp2 + 10) & 0x0F); \
+ } \
+ if(tmp3 < 0) \
+ tmp4--; \
+ if((tmp3 > 0x09) || (tmp3 < 0 )) \
+ { \
+ tmp3 = ((tmp3 + 10) & 0x0F); \
+ } \
+ if(!(tmp4 < 0)) \
+ FLAG_C = CFLAG_SET; \
+ if((tmp4 > 0x09) || (tmp4 < 0)) \
+ { \
+ tmp4=((tmp4 + 10) & 0x0F); \
+ } \
+ tmp16 = tmp1 | (tmp2 << 4) | (tmp3 << 8) | (tmp4 << 12); \
+ FLAG_V = VFLAG_SUB_16(SRC, REGISTER_A, tmp16); \
+ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_16(tmp16); \
+ }
+#endif
+
+
+/* M6502 Set Carry flag */
+#undef OP_SEC
+#define OP_SEC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = CFLAG_SET
+
+/* M6502 Set Decimal flag */
+#undef OP_SED
+#define OP_SED() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_D = DFLAG_SET
+
+/* M6502 Set Interrupt Mask flag */
+#undef OP_SEI
+#define OP_SEI() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ g65816i_set_flag_i(IFLAG_SET)
+
+/* G65816 Set Program status word */
+#undef OP_SEP
+#define OP_SEP() \
+ CLK(CLK_OP + CLK_R8 + 1); \
+ g65816i_set_reg_p(g65816i_get_reg_p() | OPER_8_IMM())
+
+/* M6502 Store accumulator to memory */
+#undef OP_STA
+#if FLAG_SET_M
+#define OP_STA(MODE) \
+ CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \
+ write_8_##MODE(EA_##MODE(), REGISTER_A)
+#else
+#define OP_STA(MODE) \
+ CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \
+ write_16_##MODE(EA_##MODE(), REGISTER_A)
+#endif
+
+/* M6502 Store index register to memory */
+#undef OP_STX
+#if FLAG_SET_X
+#define OP_STX(REG, MODE) \
+ CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \
+ write_8_##MODE(EA_##MODE(), REG)
+#else
+#define OP_STX(REG, MODE) \
+ CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \
+ write_16_##MODE(EA_##MODE(), REG)
+#endif
+
+/* M6502 Store zero to memory */
+#undef OP_STZ
+#if FLAG_SET_M
+#define OP_STZ(MODE) \
+ CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \
+ write_8_##MODE(EA_##MODE(), 0)
+#else
+#define OP_STZ(MODE) \
+ CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \
+ write_16_##MODE(EA_##MODE(), 0)
+#endif
+
+/* G65816 Stop the clock */
+#undef OP_STP
+#define OP_STP() \
+ USE_ALL_CLKS(); \
+ CPU_STOPPED |= STOP_LEVEL_STOP
+
+/* M6502 Transfer accumulator to index */
+#undef OP_TAX
+#if FLAG_SET_M
+#if FLAG_SET_X
+#define OP_TAX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = REGISTER_A; \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else /* FLAG_SET_X */
+#define OP_TAX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = REGISTER_B | REGISTER_A; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif /* FLAG_SET_X */
+#else /* FLAG_SET_M */
+#if FLAG_SET_X
+#define OP_TAX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = MAKE_UINT_8(REGISTER_A); \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else /* FLAG_SET_X */
+#define OP_TAX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = REGISTER_A; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif /* FLAG_SET_X */
+#endif /* FLAG_SET_M */
+
+
+/* M6502 Transfer index to accumulator */
+#undef OP_TXA
+#if FLAG_SET_M
+#define OP_TXA(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_A = MAKE_UINT_8(REG); \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_TXA(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_A = REG; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* G65816 Transfer C to direct register */
+#undef OP_TCD
+#if FLAG_SET_M
+#define OP_TCD() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_D = REGISTER_A | REGISTER_B; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#else
+#define OP_TCD() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_D = REGISTER_A; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* G65816 Transfer direct register to C */
+#undef OP_TDC
+#if FLAG_SET_M
+#define OP_TDC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_D; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ REGISTER_A = MAKE_UINT_8(REGISTER_D); \
+ REGISTER_B = REGISTER_D & 0xff00
+#else
+#define OP_TDC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_A = REGISTER_D; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* G65816 Transfer C to stack pointer */
+#undef OP_TCS
+#if FLAG_SET_E
+#define OP_TCS() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REGISTER_S = MAKE_UINT_8(REGISTER_A) | 0x100
+#else
+#define OP_TCS() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REGISTER_S = REGISTER_A | REGISTER_B
+#endif
+
+/* G65816 Transfer stack pointer to C */
+#undef OP_TSC
+#if FLAG_SET_M
+#define OP_TSC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_S; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ REGISTER_A = MAKE_UINT_8(REGISTER_S); \
+ REGISTER_B = REGISTER_S & 0xff00
+#else
+#define OP_TSC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_A = REGISTER_S; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M6502 Transfer stack pointer to X */
+#undef OP_TSX
+#if FLAG_SET_X
+#define OP_TSX() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_X = MAKE_UINT_8(REGISTER_S); \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_TSX() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_X = REGISTER_S; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M6502 Transfer X to stack pointer */
+#undef OP_TXS
+#if FLAG_SET_E
+#define OP_TXS() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REGISTER_S = MAKE_UINT_8(REGISTER_X) | 0x100
+#else
+#define OP_TXS() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REGISTER_S = REGISTER_X
+#endif
+
+/* G65816 Transfer X to Y */
+#undef OP_TXY
+#if FLAG_SET_X
+#define OP_TXY() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_Y = REGISTER_X; \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_TXY() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_Y = REGISTER_X; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* G65816 Transfer Y to X */
+#undef OP_TYX
+#if FLAG_SET_X
+#define OP_TYX() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_X = REGISTER_Y; \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_TYX() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_X = REGISTER_Y; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* G65816 Test and reset bit */
+#undef OP_TRB
+#if FLAG_SET_M
+#define OP_TRB(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = read_8_##MODE(DST); \
+ write_8_##MODE(DST, FLAG_Z & ~REGISTER_A); \
+ FLAG_Z &= REGISTER_A
+#else
+#define OP_TRB(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = read_16_##MODE(DST); \
+ write_16_##MODE(DST, FLAG_Z & ~REGISTER_A); \
+ FLAG_Z &= REGISTER_A
+#endif
+
+/* G65816 Test and set bit */
+#undef OP_TSB
+#if FLAG_SET_M
+#define OP_TSB(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = read_8_##MODE(DST); \
+ write_8_##MODE(DST, FLAG_Z | REGISTER_A); \
+ FLAG_Z &= REGISTER_A
+#else
+#define OP_TSB(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = read_16_##MODE(DST); \
+ write_16_##MODE(DST, FLAG_Z | REGISTER_A); \
+ FLAG_Z &= REGISTER_A
+#endif
+
+/* G65816 Wait for interrupt */
+#undef OP_WAI
+#define OP_WAI() \
+ USE_ALL_CLKS(); \
+ CPU_STOPPED |= STOP_LEVEL_WAI
+
+/* G65816 William D. Mensch, JR. (65816 designer) - future expansion */
+#undef OP_WDM
+#define OP_WDM() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REGISTER_PC++
+
+/* G65816 Exchange accum high and low bytes */
+#undef OP_XBA
+#if FLAG_SET_M
+#define OP_XBA() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REGISTER_B>>8; \
+ REGISTER_B = REGISTER_A<<8; \
+ REGISTER_A = FLAG_Z; \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_XBA() \
+ CLK(CLK_OP + CLK_IMPLIED + 1); \
+ FLAG_Z = REGISTER_A >> 8; \
+ REGISTER_A = MAKE_UINT_16(REGISTER_A<<8) | FLAG_Z; \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#endif
+
+/* G65816 Exchange carry and emulation bits */
+#undef OP_XCE
+#define OP_XCE() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ SRC = CFLAG_AS_1(); \
+ FLAG_C = FLAG_E<<8; \
+ g65816i_set_flag_e(SRC)
+
+
+
+
+/* ======================================================================== */
+/* ======================== OPCODE & FUNCTION TABLES ====================== */
+/* ======================================================================== */
+
+#undef OP
+#undef O
+#undef TABLE_OPCODES
+#undef TABLE_FUNCTION
+
+#if FLAG_SET_E
+#define OP(CODE, OPERATION) static void g65816i_ ## CODE ## _E(void) {OPERATION;}
+#define O(CODE) g65816i_ ## CODE ## _E
+#define TABLE_OPCODES void (*g65816i_opcodes_E[256])(void)
+#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816i_ ## NAME ## _E ARGS
+
+#else
+
+#if !FLAG_SET_M && !FLAG_SET_X
+#define OP(CODE, OPERATION) static void g65816i_ ## CODE ## _M0X0(void) {OPERATION;}
+#define O(CODE) g65816i_ ## CODE ## _M0X0
+#define TABLE_OPCODES void (*g65816i_opcodes_M0X0[256])(void)
+#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816i_ ## NAME ## _M0X0 ARGS
+
+#elif !FLAG_SET_M && FLAG_SET_X
+
+#define OP(CODE, OPERATION) static void g65816i_ ## CODE ## _M0X1(void) {OPERATION;}
+#define O(CODE) g65816i_ ## CODE ## _M0X1
+#define TABLE_OPCODES void (*g65816i_opcodes_M0X1[256])(void)
+#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816i_ ## NAME ## _M0X1 ARGS
+
+#elif FLAG_SET_M && !FLAG_SET_X
+
+#define OP(CODE, OPERATION) static void g65816i_ ## CODE ## _M1X0(void) {OPERATION;}
+#define O(CODE) g65816i_ ## CODE ## _M1X0
+#define TABLE_OPCODES void (*g65816i_opcodes_M1X0[256])(void)
+#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816i_ ## NAME ## _M1X0 ARGS
+
+#elif FLAG_SET_M && FLAG_SET_X
+
+#define OP(CODE, OPERATION) static void g65816i_ ## CODE ## _M1X1(void) {OPERATION;}
+#define O(CODE) g65816i_ ## CODE ## _M1X1
+#define TABLE_OPCODES void (*g65816i_opcodes_M1X1[256])(void)
+#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816i_ ## NAME ## _M1X1 ARGS
+
+#endif
+#endif
+#define BREAKOUT return
+
+
+
+/* OP FUNCTION Comment */
+OP(00, OP_BRK ( ) ) /* BRK */
+OP(01, OP_ORA ( DXI ) ) /* ORA dxi */
+OP(02, OP_COP ( ) ) /* COP (G) */
+OP(03, OP_ORA ( S ) ) /* ORA s (G) */
+OP(04, OP_TSB ( D ) ) /* TSB d (C) */
+OP(05, OP_ORA ( D ) ) /* ORA d */
+OP(06, OP_ASLM ( D ) ) /* ASL d */
+OP(07, OP_ORA ( DLI ) ) /* ORA dli (G) */
+OP(08, OP_PHP ( ) ) /* PHP */
+OP(09, OP_ORA ( IMM ) ) /* ORA imm */
+OP(0a, OP_ASL ( ) ) /* ASL acc */
+OP(0b, OP_PHD ( ) ) /* PHD (G) */
+OP(0c, OP_TSB ( A ) ) /* TSB a (C) */
+OP(0d, OP_ORA ( A ) ) /* ORA a */
+OP(0e, OP_ASLM ( A ) ) /* ASL a */
+OP(0f, OP_ORA ( AL ) ) /* ORA al (G) */
+OP(10, OP_BCC ( COND_PL() ) ) /* BPL */
+OP(11, OP_ORA ( DIY ) ) /* ORA diy */
+OP(12, OP_ORA ( DI ) ) /* ORA di (C) */
+OP(13, OP_ORA ( SIY ) ) /* ORA siy (G) */
+OP(14, OP_TRB ( D ) ) /* TRB d (C) */
+OP(15, OP_ORA ( DX ) ) /* ORA dx */
+OP(16, OP_ASLM ( DX ) ) /* ASL dx */
+OP(17, OP_ORA ( DLIY ) ) /* ORA dliy(C) */
+OP(18, OP_CLC ( ) ) /* CLC */
+OP(19, OP_ORA ( AY ) ) /* ORA ay */
+OP(1a, OP_INC ( ) ) /* INA (C) */
+OP(1b, OP_TCS ( ) ) /* TCS (G) */
+OP(1c, OP_TRB ( A ) ) /* TRB a (C) */
+OP(1d, OP_ORA ( AX ) ) /* ORA ax */
+OP(1e, OP_ASLM ( AX ) ) /* ASL ax */
+OP(1f, OP_ORA ( ALX ) ) /* ORA alx (G) */
+OP(20, OP_JSR ( A ) ) /* JSR a */
+OP(21, OP_AND ( DXI ) ) /* AND dxi */
+OP(22, OP_JSL ( AL ) ) /* JSL al (G) */
+OP(23, OP_AND ( S ) ) /* AND s (G) */
+OP(24, OP_BIT ( D ) ) /* BIT d */
+OP(25, OP_AND ( D ) ) /* AND d */
+OP(26, OP_ROLM ( D ) ) /* ROL d */
+OP(27, OP_AND ( DLI ) ) /* AND dli (G) */
+OP(28, OP_PLP ( ) ) /* PLP */
+OP(29, OP_AND ( IMM ) ) /* AND imm */
+OP(2a, OP_ROL ( ) ) /* ROL acc */
+OP(2b, OP_PLD ( ) ) /* PLD (G) */
+OP(2c, OP_BIT ( A ) ) /* BIT a */
+OP(2d, OP_AND ( A ) ) /* AND a */
+OP(2e, OP_ROLM ( A ) ) /* ROL a */
+OP(2f, OP_AND ( AL ) ) /* AND al (G) */
+OP(30, OP_BCC ( COND_MI() ) ) /* BMI */
+OP(31, OP_AND ( DIY ) ) /* AND diy */
+OP(32, OP_AND ( DI ) ) /* AND di (C) */
+OP(33, OP_AND ( SIY ) ) /* AND siy */
+OP(34, OP_BIT ( DX ) ) /* BIT dx (C) */
+OP(35, OP_AND ( DX ) ) /* AND dx */
+OP(36, OP_ROLM ( DX ) ) /* ROL dx */
+OP(37, OP_AND ( DLIY ) ) /* AND dliy(G) */
+OP(38, OP_SEC ( ) ) /* SEC */
+OP(39, OP_AND ( AY ) ) /* AND ay */
+OP(3a, OP_DEC ( ) ) /* DEA (C) */
+OP(3b, OP_TSC ( ) ) /* TSC (G) */
+OP(3c, OP_BIT ( AX ) ) /* BIT abx (C) */
+OP(3d, OP_AND ( AX ) ) /* AND ax */
+OP(3e, OP_ROLM ( AX ) ) /* ROL ax */
+OP(3f, OP_AND ( ALX ) ) /* AND alx (G) */
+OP(40, OP_RTI ( ) ) /* RTI */
+OP(41, OP_EOR ( DXI ) ) /* EOR dxi */
+OP(42, OP_WDM ( ) ) /* WDM */
+OP(43, OP_EOR ( S ) ) /* EOR s (G) */
+OP(44, OP_MVP ( ) ) /* MVP (G) */
+OP(45, OP_EOR ( D ) ) /* EOR d */
+OP(46, OP_LSRM ( D ) ) /* LSR d */
+OP(47, OP_EOR ( DLI ) ) /* EOR dli (G) */
+OP(48, OP_PHA ( ) ) /* PHA */
+OP(49, OP_EOR ( IMM ) ) /* EOR imm */
+OP(4a, OP_LSR ( ) ) /* LSR acc */
+OP(4b, OP_PHK ( ) ) /* PHK (G) */
+OP(4c, OP_JMP ( A ) ) /* JMP a */
+OP(4d, OP_EOR ( A ) ) /* EOR a */
+OP(4e, OP_LSRM ( A ) ) /* LSR a */
+OP(4f, OP_EOR ( AL ) ) /* EOR al (G) */
+OP(50, OP_BCC ( COND_VC() ) ) /* BVC */
+OP(51, OP_EOR ( DIY ) ) /* EOR diy */
+OP(52, OP_EOR ( DI ) ) /* EOR di (C) */
+OP(53, OP_EOR ( SIY ) ) /* EOR siy (G) */
+OP(54, OP_MVN ( ) ) /* MVN (G) */
+OP(55, OP_EOR ( DX ) ) /* EOR dx */
+OP(56, OP_LSRM ( DX ) ) /* LSR dx */
+OP(57, OP_EOR ( DLIY ) ) /* EOR dliy(G) */
+OP(58, OP_CLI ( ) ) /* CLI */
+OP(59, OP_EOR ( AY ) ) /* EOR ay */
+OP(5a, OP_PHX ( REGISTER_Y ) ) /* PHY (C) */
+OP(5b, OP_TCD ( ) ) /* TCD (G) */
+OP(5c, OP_JMPAL( ) ) /* JMP al (G) */
+OP(5d, OP_EOR ( AX ) ) /* EOR ax */
+OP(5e, OP_LSRM ( AX ) ) /* LSR ax */
+OP(5f, OP_EOR ( ALX ) ) /* EOR alx (G) */
+OP(60, OP_RTS ( ) ) /* RTS */
+OP(61, OP_ADC ( DXI ) ) /* ADC dxi */
+OP(62, OP_PER ( ) ) /* PER (G) */
+OP(63, OP_ADC ( S ) ) /* ADC s (G) */
+OP(64, OP_STZ ( D ) ) /* STZ d (C) */
+OP(65, OP_ADC ( D ) ) /* ADC d */
+OP(66, OP_RORM ( D ) ) /* ROR d */
+OP(67, OP_ADC ( DLI ) ) /* ADC dli (G) */
+OP(68, OP_PLA ( ) ) /* PLA */
+OP(69, OP_ADC ( IMM ) ) /* ADC imm */
+OP(6a, OP_ROR ( ) ) /* ROR acc */
+OP(6b, OP_RTL ( ) ) /* RTL (G) */
+OP(6c, OP_JMP ( AI ) ) /* JMP ai */
+OP(6d, OP_ADC ( A ) ) /* ADC a */
+OP(6e, OP_RORM ( A ) ) /* ROR a */
+OP(6f, OP_ADC ( AL ) ) /* ADC al (G) */
+OP(70, OP_BCC ( COND_VS() ) ) /* BVS */
+OP(71, OP_ADC ( DIY ) ) /* ADC diy */
+OP(72, OP_ADC ( DI ) ) /* ADC di (G) */
+OP(73, OP_ADC ( SIY ) ) /* ADC siy (G) */
+OP(74, OP_STZ ( DX ) ) /* STZ dx (C) */
+OP(75, OP_ADC ( DX ) ) /* ADC dx */
+OP(76, OP_RORM ( DX ) ) /* ROR dx */
+OP(77, OP_ADC ( DLIY ) ) /* ADC dliy(G) */
+OP(78, OP_SEI ( ) ) /* SEI */
+OP(79, OP_ADC ( AY ) ) /* ADC ay */
+OP(7a, OP_PLX ( REGISTER_Y ) ) /* PLY (C) */
+OP(7b, OP_TDC ( ) ) /* TDC (G) */
+OP(7c, OP_JMPAXI( ) ) /* JMP axi (C) */
+OP(7d, OP_ADC ( AX ) ) /* ADC ax */
+OP(7e, OP_RORM ( AX ) ) /* ROR ax */
+OP(7f, OP_ADC ( ALX ) ) /* ADC alx (G) */
+OP(80, OP_BRA ( ) ) /* BRA (C) */
+OP(81, OP_STA ( DXI ) ) /* STA dxi */
+OP(82, OP_BRL ( ) ) /* BRL (G) */
+OP(83, OP_STA ( S ) ) /* STA s (G) */
+OP(84, OP_STX ( REGISTER_Y, D ) ) /* STY d */
+OP(85, OP_STA ( D ) ) /* STA d */
+OP(86, OP_STX ( REGISTER_X, D ) ) /* STX d */
+OP(87, OP_STA ( DLI ) ) /* STA dli (G) */
+OP(88, OP_DECX ( REGISTER_Y ) ) /* DEY */
+OP(89, OP_BITI ( ) ) /* BIT imm (C) */
+OP(8a, OP_TXA ( REGISTER_X ) ) /* TXA */
+OP(8b, OP_PHB ( ) ) /* PHB (G) */
+OP(8c, OP_STX ( REGISTER_Y, A ) ) /* STY a */
+OP(8d, OP_STA ( A ) ) /* STA a */
+OP(8e, OP_STX ( REGISTER_X, A ) ) /* STX a */
+OP(8f, OP_STA ( AL ) ) /* STA al (G) */
+OP(90, OP_BCC ( COND_CC() ) ) /* BCC */
+OP(91, OP_STA ( DIY ) ) /* STA diy */
+OP(92, OP_STA ( DI ) ) /* STA di (C) */
+OP(93, OP_STA ( SIY ) ) /* STA siy (G) */
+OP(94, OP_STX ( REGISTER_Y, DX ) ) /* STY dx */
+OP(95, OP_STA ( DX ) ) /* STA dx */
+OP(96, OP_STX ( REGISTER_X, DY ) ) /* STX dy */
+OP(97, OP_STA ( DLIY ) ) /* STA dliy(G) */
+OP(98, OP_TXA ( REGISTER_Y ) ) /* TYA */
+OP(99, OP_STA ( AY ) ) /* STA ay */
+OP(9a, OP_TXS ( ) ) /* TXS */
+OP(9b, OP_TXY ( ) ) /* TXY (G) */
+OP(9c, OP_STZ ( A ) ) /* STZ a (C) */
+OP(9d, OP_STA ( AX ) ) /* STA ax */
+OP(9e, OP_STZ ( AX ) ) /* STZ ax (C) */
+OP(9f, OP_STA ( ALX ) ) /* STA alx (G) */
+OP(a0, OP_LDX ( REGISTER_Y, IMM ) ) /* LDY imm */
+OP(a1, OP_LDA ( DXI ) ) /* LDA dxi */
+OP(a2, OP_LDX ( REGISTER_X, IMM ) ) /* LDX imm */
+OP(a3, OP_LDA ( S ) ) /* LDA s (G) */
+OP(a4, OP_LDX ( REGISTER_Y, D ) ) /* LDY d */
+OP(a5, OP_LDA ( D ) ) /* LDA d */
+OP(a6, OP_LDX ( REGISTER_X, D ) ) /* LDX d */
+OP(a7, OP_LDA ( DLI ) ) /* LDA dli (G) */
+OP(a8, OP_TAX ( REGISTER_Y ) ) /* TAY */
+OP(a9, OP_LDA ( IMM ) ) /* LDA imm */
+OP(aa, OP_TAX ( REGISTER_X ) ) /* TAX */
+OP(ab, OP_PLB ( ) ) /* PLB (G) */
+OP(ac, OP_LDX ( REGISTER_Y, A ) ) /* LDY a */
+OP(ad, OP_LDA ( A ) ) /* LDA a */
+OP(ae, OP_LDX ( REGISTER_X, A ) ) /* LDX a */
+OP(af, OP_LDA ( AL ) ) /* LDA al (G) */
+OP(b0, OP_BCC ( COND_CS() ) ) /* BCS */
+OP(b1, OP_LDA ( DIY ) ) /* LDA diy */
+OP(b2, OP_LDA ( DI ) ) /* LDA di (C) */
+OP(b3, OP_LDA ( SIY ) ) /* LDA siy (G) */
+OP(b4, OP_LDX ( REGISTER_Y, DX ) ) /* LDY dx */
+OP(b5, OP_LDA ( DX ) ) /* LDA dx */
+OP(b6, OP_LDX ( REGISTER_X, DY ) ) /* LDX dy */
+OP(b7, OP_LDA ( DLIY ) ) /* LDA dliy(G) */
+OP(b8, OP_CLV ( ) ) /* CLV */
+OP(b9, OP_LDA ( AY ) ) /* LDA ay */
+OP(ba, OP_TSX ( ) ) /* TSX */
+OP(bb, OP_TYX ( ) ) /* TYX (G) */
+OP(bc, OP_LDX ( REGISTER_Y, AX ) ) /* LDY ax */
+OP(bd, OP_LDA ( AX ) ) /* LDA ax */
+OP(be, OP_LDX ( REGISTER_X, AY ) ) /* LDX ay */
+OP(bf, OP_LDA ( ALX ) ) /* LDA alx (G) */
+OP(c0, OP_CMPX ( REGISTER_Y, IMM ) ) /* CPY imm */
+OP(c1, OP_CMP ( DXI ) ) /* CMP dxi */
+OP(c2, OP_REP ( ) ) /* REP (G) */
+OP(c3, OP_CMP ( S ) ) /* CMP s (G) */
+OP(c4, OP_CMPX ( REGISTER_Y, D ) ) /* CPY d */
+OP(c5, OP_CMP ( D ) ) /* CMP d */
+OP(c6, OP_DECM ( D ) ) /* DEC d */
+OP(c7, OP_CMP ( DLI ) ) /* CMP dli (G) */
+OP(c8, OP_INCX ( REGISTER_Y ) ) /* INY */
+OP(c9, OP_CMP ( IMM ) ) /* CMP imm */
+OP(ca, OP_DECX ( REGISTER_X ) ) /* DEX */
+OP(cb, OP_WAI ( ) ) /* WAI (G) */
+OP(cc, OP_CMPX ( REGISTER_Y, A ) ) /* CPY a */
+OP(cd, OP_CMP ( A ) ) /* CMP a */
+OP(ce, OP_DECM ( A ) ) /* DEC a */
+OP(cf, OP_CMP ( AL ) ) /* CMP al (G) */
+OP(d0, OP_BCC ( COND_NE() ) ) /* BNE */
+OP(d1, OP_CMP ( DIY ) ) /* CMP diy */
+OP(d2, OP_CMP ( DI ) ) /* CMP di (C) */
+OP(d3, OP_CMP ( SIY ) ) /* CMP siy (G) */
+OP(d4, OP_PEI ( ) ) /* PEI (G) */
+OP(d5, OP_CMP ( DX ) ) /* CMP dx */
+OP(d6, OP_DECM ( DX ) ) /* DEC dx */
+OP(d7, OP_CMP ( DLIY ) ) /* CMP dliy(G) */
+OP(d8, OP_CLD ( ) ) /* CLD */
+OP(d9, OP_CMP ( AY ) ) /* CMP ay */
+OP(da, OP_PHX ( REGISTER_X ) ) /* PHX (C) */
+OP(db, OP_STP ( ) ) /* STP (G) */
+OP(dc, OP_JMLAI( ) ) /* JML ai (G) */
+OP(dd, OP_CMP ( AX ) ) /* CMP ax */
+OP(de, OP_DECM ( AX ) ) /* DEC ax */
+OP(df, OP_CMP ( ALX ) ) /* CMP alx (G) */
+OP(e0, OP_CMPX ( REGISTER_X, IMM ) ) /* CPX imm */
+OP(e1, OP_SBC ( DXI ) ) /* SBC dxi */
+OP(e2, OP_SEP ( ) ) /* SEP imm (G) */
+OP(e3, OP_SBC ( S ) ) /* SBC s (G) */
+OP(e4, OP_CMPX ( REGISTER_X, D ) ) /* CPX d */
+OP(e5, OP_SBC ( D ) ) /* SBC d */
+OP(e6, OP_INCM ( D ) ) /* INC d */
+OP(e7, OP_SBC ( DLI ) ) /* SBC dli (G) */
+OP(e8, OP_INCX ( REGISTER_X ) ) /* INX */
+OP(e9, OP_SBC ( IMM ) ) /* SBC imm */
+OP(ea, OP_NOP ( ) ) /* NOP */
+OP(eb, OP_XBA ( ) ) /* XBA (G) */
+OP(ec, OP_CMPX ( REGISTER_X, A ) ) /* CPX a */
+OP(ed, OP_SBC ( A ) ) /* SBC a */
+OP(ee, OP_INCM ( A ) ) /* INC a */
+OP(ef, OP_SBC ( AL ) ) /* SBC al (G) */
+OP(f0, OP_BCC ( COND_EQ() ) ) /* BEQ */
+OP(f1, OP_SBC ( DIY ) ) /* SBC diy */
+OP(f2, OP_SBC ( DI ) ) /* SBC di (C) */
+OP(f3, OP_SBC ( SIY ) ) /* SBC siy (G) */
+OP(f4, OP_PEA ( ) ) /* PEA (G) */
+OP(f5, OP_SBC ( DX ) ) /* SBC dx */
+OP(f6, OP_INCM ( DX ) ) /* INC dx */
+OP(f7, OP_SBC ( DLIY ) ) /* SBC dliy(G) */
+OP(f8, OP_SED ( ) ) /* SED */
+OP(f9, OP_SBC ( AY ) ) /* SBC ay */
+OP(fa, OP_PLX ( REGISTER_X ) ) /* PLX (C) */
+OP(fb, OP_XCE ( ) ) /* XCE (G) */
+OP(fc, OP_JSRAXI( ) ) /* JSR axi (G) */
+OP(fd, OP_SBC ( AX ) ) /* SBC ax */
+OP(fe, OP_INCM ( AX ) ) /* INC ax */
+OP(ff, OP_SBC ( ALX ) ) /* SBC alx (G) */
+
+
+
+TABLE_OPCODES =
+{
+ O(00),O(01),O(02),O(03),O(04),O(05),O(06),O(07),
+ O(08),O(09),O(0a),O(0b),O(0c),O(0d),O(0e),O(0f),
+ O(10),O(11),O(12),O(13),O(14),O(15),O(16),O(17),
+ O(18),O(19),O(1a),O(1b),O(1c),O(1d),O(1e),O(1f),
+ O(20),O(21),O(22),O(23),O(24),O(25),O(26),O(27),
+ O(28),O(29),O(2a),O(2b),O(2c),O(2d),O(2e),O(2f),
+ O(30),O(31),O(32),O(33),O(34),O(35),O(36),O(37),
+ O(38),O(39),O(3a),O(3b),O(3c),O(3d),O(3e),O(3f),
+ O(40),O(41),O(42),O(43),O(44),O(45),O(46),O(47),
+ O(48),O(49),O(4a),O(4b),O(4c),O(4d),O(4e),O(4f),
+ O(50),O(51),O(52),O(53),O(54),O(55),O(56),O(57),
+ O(58),O(59),O(5a),O(5b),O(5c),O(5d),O(5e),O(5f),
+ O(60),O(61),O(62),O(63),O(64),O(65),O(66),O(67),
+ O(68),O(69),O(6a),O(6b),O(6c),O(6d),O(6e),O(6f),
+ O(70),O(71),O(72),O(73),O(74),O(75),O(76),O(77),
+ O(78),O(79),O(7a),O(7b),O(7c),O(7d),O(7e),O(7f),
+ O(80),O(81),O(82),O(83),O(84),O(85),O(86),O(87),
+ O(88),O(89),O(8a),O(8b),O(8c),O(8d),O(8e),O(8f),
+ O(90),O(91),O(92),O(93),O(94),O(95),O(96),O(97),
+ O(98),O(99),O(9a),O(9b),O(9c),O(9d),O(9e),O(9f),
+ O(a0),O(a1),O(a2),O(a3),O(a4),O(a5),O(a6),O(a7),
+ O(a8),O(a9),O(aa),O(ab),O(ac),O(ad),O(ae),O(af),
+ O(b0),O(b1),O(b2),O(b3),O(b4),O(b5),O(b6),O(b7),
+ O(b8),O(b9),O(ba),O(bb),O(bc),O(bd),O(be),O(bf),
+ O(c0),O(c1),O(c2),O(c3),O(c4),O(c5),O(c6),O(c7),
+ O(c8),O(c9),O(ca),O(cb),O(cc),O(cd),O(ce),O(cf),
+ O(d0),O(d1),O(d2),O(d3),O(d4),O(d5),O(d6),O(d7),
+ O(d8),O(d9),O(da),O(db),O(dc),O(dd),O(de),O(df),
+ O(e0),O(e1),O(e2),O(e3),O(e4),O(e5),O(e6),O(e7),
+ O(e8),O(e9),O(ea),O(eb),O(ec),O(ed),O(ee),O(ef),
+ O(f0),O(f1),O(f2),O(f3),O(f4),O(f5),O(f6),O(f7),
+ O(f8),O(f9),O(fa),O(fb),O(fc),O(fd),O(fe),O(ff)
+};
+
+
+
+/* Assert or clear a line on the CPU */
+TABLE_FUNCTION(void, set_line, (int line, int state))
+{
+ switch(line)
+ {
+ case G65816_LINE_IRQ:
+ switch(state)
+ {
+ case CLEAR_LINE:
+ LINE_IRQ = 0;
+ return;
+ case ASSERT_LINE:
+ case HOLD_LINE:
+ LINE_IRQ = 1;
+ }
+ if(FLAG_I)
+ {
+ if(CPU_STOPPED & STOP_LEVEL_WAI)
+ {
+ CPU_STOPPED &= ~STOP_LEVEL_WAI;
+ }
+ return;
+ }
+ return;
+ case G65816_LINE_NMI:
+ if(state == CLEAR_LINE)
+ {
+ LINE_NMI = 0;
+ return;
+ }
+ if(!LINE_NMI)
+ {
+ LINE_NMI = state != PULSE_LINE;
+ CPU_STOPPED &= ~STOP_LEVEL_WAI;
+ if(!CPU_STOPPED)
+ g65816i_interrupt_nmi();
+ }
+ return;
+ case G65816_LINE_SO:
+ FLAG_V = VFLAG_SET;
+ break;
+ case G65816_LINE_RESET:
+ case G65816_LINE_ABORT:
+ case G65816_LINE_RDY:
+ return;
+ }
+
+ LINE_IRQ=1;
+}
+
+
+
+/* Get a register from the CPU core */
+TABLE_FUNCTION(uint, get_reg, (int regnum))
+{
+ switch(regnum)
+ {
+ case G65816_A: return REGISTER_B | REGISTER_A;
+ case G65816_X: return REGISTER_X;
+ case G65816_Y: return REGISTER_Y;
+ case REG_SP: return REGISTER_S;
+ case G65816_S: return REGISTER_S;
+ case REG_PC: return REGISTER_PC;
+ case G65816_PC: return REGISTER_PC;
+ case G65816_PB: return REGISTER_PB >> 16;
+ case G65816_DB: return REGISTER_DB >> 16;
+ case G65816_D: return REGISTER_D;
+ case G65816_P: return g65816i_get_reg_p();
+ case G65816_NMI_STATE: return LINE_NMI;
+ case G65816_IRQ_STATE: return LINE_IRQ;
+ case REG_PREVIOUSPC: return REGISTER_PPC;
+ }
+ return 0;
+}
+
+
+
+TABLE_FUNCTION(void, set_reg, (int regnum, uint val))
+{
+ switch(regnum)
+ {
+ case REG_PC: case G65816_PC: REGISTER_PC = MAKE_UINT_16(val); break;
+#if FLAG_SET_E
+ case REG_SP: case G65816_S: REGISTER_S = MAKE_UINT_8(val) | 0x100; break;
+#else
+ case REG_SP: case G65816_S: REGISTER_S = MAKE_UINT_16(val); break;
+#endif
+ case G65816_P: g65816i_set_reg_p(val); break;
+#if FLAG_SET_M
+ case G65816_A: REGISTER_A = MAKE_UINT_8(val); REGISTER_B = val&0xff00; break;
+#else
+ case G65816_A: REGISTER_A = MAKE_UINT_16(val); break;
+#endif
+#if FLAG_SET_X
+ case G65816_X: REGISTER_X = MAKE_UINT_8(val); break;
+ case G65816_Y: REGISTER_Y = MAKE_UINT_8(val); break;
+#else
+ case G65816_X: REGISTER_X = MAKE_UINT_16(val); break;
+ case G65816_Y: REGISTER_Y = MAKE_UINT_16(val); break;
+#endif
+ case G65816_DB: REGISTER_DB = MAKE_UINT_8(val); break;
+ case G65816_PB: REGISTER_PB = MAKE_UINT_8(val); break;
+ case G65816_NMI_STATE: FTABLE_SET_LINE(G65816_LINE_NMI, val == 0 ? CLEAR_LINE : ASSERT_LINE); break;
+ case G65816_IRQ_STATE: FTABLE_SET_LINE(G65816_LINE_IRQ, val == 0 ? CLEAR_LINE : ASSERT_LINE); break;
+ }
+}
+
+
+
+INLINE int g65816i_correct_mode(void)
+{
+#if EXECUTION_MODE == EXECUTION_MODE_E
+ return (FLAG_E == EFLAG_SET);
+#elif EXECUTION_MODE == EXECUTION_MODE_M0X0
+ return (FLAG_E == EFLAG_CLEAR) && (FLAG_M == MFLAG_CLEAR) && (FLAG_X == XFLAG_CLEAR);
+#elif EXECUTION_MODE == EXECUTION_MODE_M0X1
+ return (FLAG_E == EFLAG_CLEAR) && (FLAG_M == MFLAG_CLEAR) && (FLAG_X == XFLAG_SET);
+#elif EXECUTION_MODE == EXECUTION_MODE_M1X0
+ return (FLAG_E == EFLAG_CLEAR) && (FLAG_M == MFLAG_SET) && (FLAG_X == XFLAG_CLEAR);
+#elif EXECUTION_MODE == EXECUTION_MODE_M1X1
+ return (FLAG_E == EFLAG_CLEAR) && (FLAG_M == MFLAG_SET) && (FLAG_X == XFLAG_SET);
+#else
+#error Invalid EXECUTION_MODE
+#endif
+}
+
+
+
+TABLE_FUNCTION(int, execute, (int clocks))
+{
+ // do a check here also in case we're in STOP_WAI mode - this'll clear it when the IRQ happens
+ g65816i_check_maskable_interrupt();
+
+ if (!CPU_STOPPED)
+ {
+ CLOCKS = clocks;
+ do
+ {
+ /* Note that I'm doing a per-instruction interrupt
+ * check until this core is working well enough
+ * to start trying fancy stuff.
+ */
+ g65816i_check_maskable_interrupt();
+
+ REGISTER_PPC = REGISTER_PC;
+ G65816_CALL_DEBUGGER;
+
+ REGISTER_PC++;
+ REGISTER_IR = read_8_IMM(REGISTER_PB | REGISTER_PPC);
+ FTABLE_OPCODES[REGISTER_IR]();
+ } while((CLOCKS > 0) && g65816i_correct_mode());
+ return clocks - CLOCKS;
+ }
+ return clocks;
+}
+
+
+/* ======================================================================== */
+/* ================================== EOF ================================= */
+/* ======================================================================== */
diff --git a/src/emu/cpu/h6280/6280dasm.c b/src/emu/cpu/h6280/6280dasm.c
new file mode 100644
index 00000000000..e70d808e683
--- /dev/null
+++ b/src/emu/cpu/h6280/6280dasm.c
@@ -0,0 +1,250 @@
+/*****************************************************************************
+
+ 6280dasm.c Hudsonsoft Hu6280 (HuC6280/Hu6280a) disassembler
+
+ Copyright (c) 1999, 2000 Bryan McPhail, mish@tendril.co.uk
+
+ This source code is based (with permission!) on the 6502 emulator by
+ Juergen Buchmueller. It is released as part of the Mame emulator project.
+ Let me know if you intend to use this code in any other project.
+
+
+ Notes relating to Mame:
+
+ The dasm window shows 'real' memory, as executed by the cpu
+ The data windows show 'physical' memory, as defined in the memory map
+
+******************************************************************************/
+
+#include "cpuintrf.h"
+
+extern UINT8 H6280_debug_mmr[8];
+
+#define RDOP(addr) (oprom[addr - pc])
+#define RDBYTE(addr) (opram[addr - pc])
+#define RDWORD(addr) (opram[addr - pc] | ( oprom[(addr) + 1 - pc] << 8 ))
+
+enum addr_mode {
+ _non=0, /* no additional arguments */
+ _acc, /* accumulator */
+ _imp, /* implicit */
+ _imm, /* immediate */
+ _abs, /* absolute */
+ _zpg, /* zero page */
+ _zpx, /* zero page + X */
+ _zpy, /* zero page + Y */
+ _zpi, /* zero page indirect */
+ _abx, /* absolute + X */
+ _aby, /* absolute + Y */
+ _rel, /* relative */
+ _idx, /* zero page pre indexed */
+ _idy, /* zero page post indexed */
+ _ind, /* indirect */
+ _iax, /* indirect + X */
+ _blk, /* block */
+ _zrl, /* zero page relative */
+ _imz, /* immediate, zero page */
+ _izx, /* immediate, zero page + X */
+ _ima, /* immediate, absolute */
+ _imx /* immediate, absolute + X */
+};
+
+enum opcodes {
+
+ /* 6502 opcodes */
+ _adc=0,_and, _asl, _bcc, _bcs, _beq, _bit, _bmi,
+ _bne, _bpl, _brk, _bvc, _bvs, _clc, _cld, _cli,
+ _clv, _cmp, _cpx, _cpy, _dec, _dex, _dey, _eor,
+ _inc, _inx, _iny, _jmp, _jsr, _lda, _ldx, _ldy,
+ _lsr, _nop, _ora, _pha, _php, _pla, _plp, _rol,
+ _ror, _rti, _rts, _sbc, _sec, _sed, _sei, _sta,
+ _stx, _sty, _tax, _tay, _tsx, _txa, _txs, _tya,
+ _ill,
+
+ /* Hu6280 extensions */
+ _bra, _stz, _trb, _tsb, _dea, _ina, _sax, _bsr,
+ _phx, _phy, _plx, _ply, _csh, _csl, _tam, _tma,
+ _cla, _cly, _clx, _st0, _st1, _st2, _tst, _set,
+ _tdd, _tia, _tii, _tin, _tai, _say, _sxy,
+
+ _sm0, _sm1, _sm2, _sm3, _sm4, _sm5, _sm6, _sm7,
+ _rm0, _rm1, _rm2, _rm3, _rm4, _rm5, _rm6, _rm7,
+
+ _bs0, _bs1, _bs2, _bs3, _bs4, _bs5, _bs6, _bs7,
+ _br0, _br1, _br2, _br3, _br4, _br5, _br6, _br7
+
+};
+
+
+static const char *token[]=
+{
+ /* 6502 opcodes */
+ "adc", "and", "asl", "bcc", "bcs", "beq", "bit", "bmi",
+ "bne", "bpl", "brk", "bvc", "bvs", "clc", "cld", "cli",
+ "clv", "cmp", "cpx", "cpy", "dec", "dex", "dey", "eor",
+ "inc", "inx", "iny", "jmp", "jsr", "lda", "ldx", "ldy",
+ "lsr", "nop", "ora", "pha", "php", "pla", "plp", "rol",
+ "ror", "rti", "rts", "sbc", "sec", "sed", "sei", "sta",
+ "stx", "sty", "tax", "tay", "tsx", "txa", "txs", "tya",
+ "ill",
+
+ /* Hu6280 extensions */
+ "bra", "stz", "trb", "tsb", "dea", "ina", "sax", "bsr",
+ "phx", "phy", "plx", "ply", "csh", "csl", "tam", "tma",
+ "cla", "cly", "clx", "st0", "st1", "st2", "tst", "set",
+ "tdd", "tia", "tii", "tin", "tai", "say", "sxy",
+
+ "smb0", "smb1", "smb2", "smb3", "smb4", "smb5", "smb6", "smb7",
+ "rmb0", "rmb1", "rmb2", "rmb3", "rmb4", "rmb5", "rmb6", "rmb7",
+
+ "bbs0", "bbs1", "bbs2", "bbs3", "bbs4", "bbs5", "bbs6", "bbs7",
+ "bbr0", "bbr1", "bbr2", "bbr3", "bbr4", "bbr5", "bbr6", "bbr7"
+};
+
+static const unsigned char op6280[512]=
+{
+ _brk,_imp, _ora,_idx, _sxy,_imp, _st0,_imm, _tsb,_zpg, _ora,_zpg, _asl,_zpg, _rm0,_zpg, /* 00 */
+ _php,_imp, _ora,_imm, _asl,_acc, _ill,_non, _tsb,_abs, _ora,_abs, _asl,_abs, _br0,_zrl,
+ _bpl,_rel, _ora,_idy, _ora,_zpi, _st1,_imm, _trb,_zpg, _ora,_zpx, _asl,_zpx, _rm1,_zpg, /* 10 */
+ _clc,_imp, _ora,_aby, _ina,_imp, _ill,_non, _trb,_abs, _ora,_abx, _asl,_abx, _br1,_zrl,
+ _jsr,_abs, _and,_idx, _sax,_imp, _st2,_imm, _bit,_zpg, _and,_zpg, _rol,_zpg, _rm2,_zpg, /* 20 */
+ _plp,_imp, _and,_imm, _rol,_acc, _ill,_non, _bit,_abs, _and,_abs, _rol,_abs, _br2,_zrl,
+ _bmi,_rel, _and,_idy, _and,_zpi, _ill,_non, _bit,_zpx, _and,_zpx, _rol,_zpx, _rm3,_zpg, /* 30 */
+ _sec,_imp, _and,_aby, _dea,_imp, _ill,_non, _bit,_abx, _and,_abx, _rol,_abx, _br3,_zrl,
+ _rti,_imp, _eor,_idx, _say,_imp, _tma,_imm, _bsr,_rel, _eor,_zpg, _lsr,_zpg, _rm4,_zpg, /* 40 */
+ _pha,_imp, _eor,_imm, _lsr,_acc, _ill,_non, _jmp,_abs, _eor,_abs, _lsr,_abs, _br4,_zrl,
+ _bvc,_rel, _eor,_idy, _eor,_zpi, _tam,_imm, _csl,_imp, _eor,_zpx, _lsr,_zpx, _rm5,_zpg, /* 50 */
+ _cli,_imp, _eor,_aby, _phy,_imp, _ill,_non, _ill,_non, _eor,_abx, _lsr,_abx, _br5,_zrl,
+ _rts,_imp, _adc,_idx, _cla,_imp, _ill,_non, _stz,_zpg, _adc,_zpg, _ror,_zpg, _rm6,_zpg, /* 60 */
+ _pla,_imp, _adc,_imm, _ror,_acc, _ill,_non, _jmp,_ind, _adc,_abs, _ror,_abs, _br6,_zrl,
+ _bvs,_rel, _adc,_idy, _adc,_zpi, _tii,_blk, _stz,_zpx, _adc,_zpx, _ror,_zpx, _rm7,_zpg, /* 70 */
+ _sei,_imp, _adc,_aby, _ply,_imp, _ill,_non, _jmp,_iax, _adc,_abx, _ror,_abx, _br7,_zrl,
+ _bra,_rel, _sta,_idx, _clx,_imp, _tst,_imz, _sty,_zpg, _sta,_zpg, _stx,_zpg, _sm0,_zpg, /* 80 */
+ _dey,_imp, _bit,_imm, _txa,_imp, _ill,_non, _sty,_abs, _sta,_abs, _stx,_abs, _bs0,_zrl,
+ _bcc,_rel, _sta,_idy, _sta,_zpi, _tst,_ima, _sty,_zpx, _sta,_zpx, _stx,_zpy, _sm1,_zpg, /* 90 */
+ _tya,_imp, _sta,_aby, _txs,_imp, _ill,_non, _stz,_abs, _sta,_abx, _stz,_abx, _bs1,_zrl,
+ _ldy,_imm, _lda,_idx, _ldx,_imm, _tst,_izx, _ldy,_zpg, _lda,_zpg, _ldx,_zpg, _sm2,_zpg, /* a0 */
+ _tay,_imp, _lda,_imm, _tax,_imp, _ill,_non, _ldy,_abs, _lda,_abs, _ldx,_abs, _bs2,_zrl,
+ _bcs,_rel, _lda,_idy, _lda,_zpi, _tst,_imx, _ldy,_zpx, _lda,_zpx, _ldx,_zpy, _sm3,_zpg, /* b0 */
+ _clv,_imp, _lda,_aby, _tsx,_imp, _ill,_non, _ldy,_abx, _lda,_abx, _ldx,_aby, _bs3,_zrl,
+ _cpy,_imm, _cmp,_idx, _cly,_imp, _tdd,_blk, _cpy,_zpg, _cmp,_zpg, _dec,_zpg, _sm4,_zpg, /* c0 */
+ _iny,_imp, _cmp,_imm, _dex,_imp, _ill,_non, _cpy,_abs, _cmp,_abs, _dec,_abs, _bs4,_zrl,
+ _bne,_rel, _cmp,_idy, _cmp,_zpi, _tin,_blk, _csh,_imp, _cmp,_zpx, _dec,_zpx, _sm5,_zpg, /* d0 */
+ _cld,_imp, _cmp,_aby, _phx,_imp, _ill,_non, _ill,_non, _cmp,_abx, _dec,_abx, _bs5,_zrl,
+ _cpx,_imm, _sbc,_idx, _ill,_non, _tia,_blk, _cpx,_zpg, _sbc,_zpg, _inc,_zpg, _sm6,_zpg, /* e0 */
+ _inx,_imp, _sbc,_imm, _nop,_imp, _ill,_non, _cpx,_abs, _sbc,_abs, _inc,_abs, _bs6,_zrl,
+ _beq,_rel, _sbc,_idy, _sbc,_zpi, _tai,_blk, _set,_imp, _sbc,_zpx, _inc,_zpx, _sm7,_zpg, /* f0 */
+ _sed,_imp, _sbc,_aby, _plx,_imp, _ill,_non, _ill,_non, _sbc,_abx, _inc,_abx, _bs7,_zrl
+};
+
+/*****************************************************************************
+ * Disassemble a single command and return the number of bytes it uses.
+ *****************************************************************************/
+offs_t h6280_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ int PC, OP, opc, arg;
+
+ PC = pc;
+ OP = RDOP(PC);
+ OP = OP << 1;
+ PC++;
+
+ opc = op6280[OP];
+ arg = op6280[OP+1];
+
+ if (opc == _jsr || opc == _bsr)
+ flags = DASMFLAG_STEP_OVER;
+ else if (opc == _rts)
+ flags = DASMFLAG_STEP_OUT;
+
+ switch(arg)
+ {
+ case _acc:
+ sprintf(buffer,"%-5sa", token[opc]);
+ break;
+ case _imp:
+ sprintf(buffer,"%s", token[opc]);
+ break;
+ case _rel:
+ sprintf(buffer,"%-5s$%04X", token[opc], (PC + 1 + (signed char)RDBYTE(PC)) & 0xffff);
+ PC+=1;
+ break;
+ case _imm:
+ sprintf(buffer,"%-5s#$%02X", token[opc], RDBYTE(PC));
+ PC+=1;
+ break;
+ case _zpg:
+ sprintf(buffer,"%-5s$%02X", token[opc], RDBYTE(PC));
+ PC+=1;
+ break;
+ case _zpx:
+ sprintf(buffer,"%-5s$%02X,x", token[opc], RDBYTE(PC));
+ PC+=1;
+ break;
+ case _zpy:
+ sprintf(buffer,"%-5s$%02X,y", token[opc], RDBYTE(PC));
+ PC+=1;
+ break;
+ case _idx:
+ sprintf(buffer,"%-5s($%02X,x)", token[opc], RDBYTE(PC));
+ PC+=1;
+ break;
+ case _idy:
+ sprintf(buffer,"%-5s($%02X),y", token[opc], RDBYTE(PC));
+ PC+=1;
+ break;
+ case _zpi:
+ sprintf(buffer,"%-5s($%02X)", token[opc], RDBYTE(PC));
+ PC+=1;
+ break;
+ case _abs:
+ sprintf(buffer,"%-5s$%04X", token[opc], RDWORD(PC));
+ PC+=2;
+ break;
+ case _abx:
+ sprintf(buffer,"%-5s$%04X,x", token[opc], RDWORD(PC));
+ PC+=2;
+ break;
+ case _aby:
+ sprintf(buffer,"%-5s$%04X,y", token[opc], RDWORD(PC));
+ PC+=2;
+ break;
+ case _ind:
+ sprintf(buffer,"%-5s($%04X)", token[opc], RDWORD(PC));
+ PC+=2;
+ break;
+ case _iax:
+ sprintf(buffer,"%-5s($%04X),X", token[opc], RDWORD(PC));
+ PC+=2;
+ break;
+ case _blk:
+ sprintf(buffer,"%-5s$%04X $%04X $%04X", token[opc], RDWORD(PC), RDWORD(PC+2), RDWORD(PC+4));
+ PC+=6;
+ break;
+ case _zrl:
+ sprintf(buffer,"%-5s$%02X $%04X", token[opc], RDBYTE(PC), (PC + 2 + (signed char)RDBYTE(PC+1)) & 0xffff);
+ PC+=2;
+ break;
+ case _imz:
+ sprintf(buffer,"%-5s#$%02X $%02X", token[opc], RDBYTE(PC), RDBYTE(PC+1));
+ PC+=2;
+ break;
+ case _izx:
+ sprintf(buffer,"%-5s#$%02X $%02X,x", token[opc], RDBYTE(PC), RDBYTE(PC+1));
+ PC+=2;
+ break;
+ case _ima:
+ sprintf(buffer,"%-5s#$%02X $%04X", token[opc], RDBYTE(PC), RDWORD(PC+1));
+ PC+=3;
+ break;
+ case _imx:
+ sprintf(buffer,"%-5s#$%02X $%04X,x", token[opc], RDBYTE(PC), RDWORD(PC+1));
+ PC+=3;
+ break;
+
+ default:
+ sprintf(buffer,"%-5s$%02X", token[opc], OP >> 1);
+ }
+ return (PC - pc) | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/h6280/h6280.c b/src/emu/cpu/h6280/h6280.c
new file mode 100644
index 00000000000..99e98e64992
--- /dev/null
+++ b/src/emu/cpu/h6280/h6280.c
@@ -0,0 +1,562 @@
+/*****************************************************************************
+
+ h6280.c - Portable HuC6280 emulator
+
+ Copyright (c) 1999, 2000 Bryan McPhail, mish@tendril.co.uk
+
+ This source code is based (with permission!) on the 6502 emulator by
+ Juergen Buchmueller. It is released as part of the Mame emulator project.
+ Let me know if you intend to use this code in any other project.
+
+
+ NOTICE:
+
+ This code is around 99% complete! Several things are unimplemented,
+ some due to lack of time, some due to lack of documentation, mainly
+ due to lack of programs using these features.
+
+ csh, csl opcodes are not supported.
+
+ I am unsure if flag B is set upon execution of rti.
+
+ Cycle counts should be quite accurate.
+
+
+ Changelog, version 1.02:
+ JMP + indirect X (0x7c) opcode fixed.
+ SMB + RMB opcodes fixed in disassembler.
+ change_pc function calls removed.
+ TSB & TRB now set flags properly.
+ BIT opcode altered.
+
+ Changelog, version 1.03:
+ Swapped IRQ mask for IRQ1 & IRQ2 (thanks Yasuhiro)
+
+ Changelog, version 1.04, 28/9/99-22/10/99:
+ Adjusted RTI (thanks Karl)
+ TST opcodes fixed in disassembler (missing break statements in a case!).
+ TST behaviour fixed.
+ SMB/RMB/BBS/BBR fixed in disassembler.
+
+ Changelog, version 1.05, 8/12/99-16/12/99:
+ Added CAB's timer implementation (note: irq ack & timer reload are changed).
+ Fixed STA IDX.
+ Fixed B flag setting on BRK.
+ Assumed CSH & CSL to take 2 cycles each.
+
+ Todo: Performance could be improved by precalculating timer fire position.
+
+ Changelog, version 1.06, 4/5/00 - last opcode bug found?
+ JMP indirect was doing a EAL++; instead of EAD++; - Obviously causing
+ a corrupt read when L = 0xff! This fixes Bloody Wolf and Trio The Punch!
+
+ Changelog, version 1.07, 3/9/00:
+ Changed timer to be single shot - fixes Crude Buster music in level 1.
+
+ Changelog, version 1.08, 8/11/05: (Charles MacDonald)
+
+ Changed timer implementation, no longer single shot and reading the
+ timer registers returns the count only. Fixes the following:
+ - Mesopotamia: Music tempo & in-game timer
+ - Dragon Saber: DDA effects
+ - Magical Chase: Music tempo and speed regulation
+ - Cadash: Allows the first level to start
+ - Turrican: Allows the game to start
+
+ Changed PLX and PLY to set NZ flags. Fixes:
+ - Afterburner: Graphics unpacking
+ - Aoi Blink: Collision detection with background
+
+ Fixed the decimal version of ADC/SBC to *not* update the V flag,
+ only the binary ones do.
+
+ Fixed B flag handling so it is always set outside of an interrupt;
+ even after being set by PLP and RTI.
+
+ Fixed P state after reset to set I and B, leaving T, D cleared and
+ NVZC randomized (cleared in this case).
+
+ Fixed interrupt processing order (Timer has highest priority followed
+ by IRQ1 and finally IRQ2).
+
+ Changelog, version 1.09, 1/07/06: (Rob Bohms)
+
+ Added emulation of the T flag, fixes PCE Ankuku Densetsu title screen
+
+ Changelog, version 1.10, 5/09/07: (Wilbert Pol)
+
+ - Taking of interrupts is delayed to respect a pending instruction already
+ in the instruction pipeline; fixes After Burner.
+ - Added 1 cycle for decimal mode ADC and SBC instructions.
+ - Changed cycle counts for CSH and CSL instructions to 3.
+ - Added T flag support to the SBC instruction.
+ - Fixed ADC T flag to set the Z flag based on the value read.
+ - Added 3 cycle penalty to ADC, AND, EOR, ORA, and SBC instructions
+ when the T flag is set.
+ - Fixed cycle count and support for 65536 byte blocks for the TAI, TDD,
+ TIA, TII, and TIN instructions.
+ - Fixed RDWORD macro in the disassembler.
+ - Fixed setting of N and V flags in the TST instructions.
+ - Removed unneeded debug_mmr code.
+ - Fixed TSB and TRB instructions.
+ - Added 1 delay when accessing the VDC or VCE areas.
+ - Implemented low and high speed cpu modes.
+
+ Changelog, version 1.11, 18/09/07: (Wilbert Pol)
+
+ - Improvements to the handling of taking of delayed interrupts.
+
+******************************************************************************/
+#include "debugger.h"
+#include "h6280.h"
+
+static int h6280_ICount = 0;
+
+/****************************************************************************
+ * The 6280 registers.
+ ****************************************************************************/
+typedef struct
+{
+ PAIR ppc; /* previous program counter */
+ PAIR pc; /* program counter */
+ PAIR sp; /* stack pointer (always 100 - 1FF) */
+ PAIR zp; /* zero page address */
+ PAIR ea; /* effective address */
+ UINT8 a; /* Accumulator */
+ UINT8 x; /* X index register */
+ UINT8 y; /* Y index register */
+ UINT8 p; /* Processor status */
+ UINT8 mmr[8]; /* Hu6280 memory mapper registers */
+ UINT8 irq_mask; /* interrupt enable/disable */
+ UINT8 timer_status; /* timer status */
+ UINT8 timer_ack; /* timer acknowledge */
+ UINT8 clocks_per_cycle; /* 3 = low speed mode, 1 = high speed mode */
+ INT32 timer_value; /* timer interrupt */
+ INT32 timer_load; /* reload value */
+ UINT8 nmi_state;
+ UINT8 irq_state[3];
+ UINT8 irq_pending;
+ int (*irq_callback)(int irqline);
+
+#if LAZY_FLAGS
+ INT32 NZ; /* last value (lazy N and Z flag) */
+#endif
+ UINT8 io_buffer; /* last value written to the PSG, timer, and interrupt pages */
+} h6280_Regs;
+
+static h6280_Regs h6280;
+
+static void set_irq_line(int irqline, int state);
+
+/* include the macros */
+#include "h6280ops.h"
+
+/* include the opcode macros, functions and function pointer tables */
+#include "tblh6280.c"
+
+/*****************************************************************************/
+static void h6280_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ state_save_register_item("h6280", index, h6280.ppc.w.l);
+ state_save_register_item("h6280", index, h6280.pc.w.l);
+ state_save_register_item("h6280", index, h6280.sp.w.l);
+ state_save_register_item("h6280", index, h6280.zp.w.l);
+ state_save_register_item("h6280", index, h6280.ea.w.l);
+ state_save_register_item("h6280", index, h6280.a);
+ state_save_register_item("h6280", index, h6280.x);
+ state_save_register_item("h6280", index, h6280.y);
+ state_save_register_item("h6280", index, h6280.p);
+ state_save_register_item_array("h6280", index, h6280.mmr);
+ state_save_register_item("h6280", index, h6280.irq_mask);
+ state_save_register_item("h6280", index, h6280.timer_status);
+ state_save_register_item("h6280", index, h6280.timer_ack);
+ state_save_register_item("h6280", index, h6280.clocks_per_cycle);
+ state_save_register_item("h6280", index, h6280.timer_value);
+ state_save_register_item("h6280", index, h6280.timer_load);
+ state_save_register_item("h6280", index, h6280.nmi_state);
+ state_save_register_item("h6280", index, h6280.irq_state[0]);
+ state_save_register_item("h6280", index, h6280.irq_state[1]);
+ state_save_register_item("h6280", index, h6280.irq_state[2]);
+ state_save_register_item("h6280", index, h6280.irq_pending);
+
+ #if LAZY_FLAGS
+ state_save_register_item("h6280", index, h6280.NZ);
+ #endif
+ state_save_register_item("h6280", index, h6280.io_buffer);
+
+ h6280.irq_callback = irqcallback;
+}
+
+static void h6280_reset(void)
+{
+ int (*save_irqcallback)(int);
+ int i;
+
+ /* wipe out the h6280 structure */
+ save_irqcallback = h6280.irq_callback;
+ memset(&h6280, 0, sizeof(h6280_Regs));
+ h6280.irq_callback = save_irqcallback;
+
+ /* set I and B flags */
+ P = _fI | _fB;
+
+ /* stack starts at 0x01ff */
+ h6280.sp.d = 0x1ff;
+
+ /* read the reset vector into PC */
+ PCL = RDMEM(H6280_RESET_VEC);
+ PCH = RDMEM((H6280_RESET_VEC+1));
+ CHANGE_PC;
+
+ /* CPU starts in low speed mode */
+ h6280.clocks_per_cycle = 3;
+
+ /* timer off by default */
+ h6280.timer_status=0;
+
+ /* clear pending interrupts */
+ for (i = 0; i < 3; i++)
+ h6280.irq_state[i] = CLEAR_LINE;
+ h6280.nmi_state = CLEAR_LINE;
+
+ h6280.irq_pending = 0;
+}
+
+static void h6280_exit(void)
+{
+ /* nothing */
+}
+
+static int h6280_execute(int cycles)
+{
+ int in;
+ h6280_ICount = cycles;
+
+ if ( h6280.irq_pending == 2 ) {
+ h6280.irq_pending--;
+ }
+
+ /* Execute instructions */
+ do
+ {
+ if ((h6280.ppc.w.l ^ h6280.pc.w.l) & 0xe000)
+ CHANGE_PC;
+ h6280.ppc = h6280.pc;
+
+ CALL_MAME_DEBUG;
+
+ /* Execute 1 instruction */
+ in=RDOP();
+ PCW++;
+ insnh6280[in]();
+
+ if ( h6280.irq_pending ) {
+ if ( h6280.irq_pending == 1 ) {
+ if ( !(P & _fI) ) {
+ h6280.irq_pending--;
+ CHECK_AND_TAKE_IRQ_LINES;
+ }
+ } else {
+ h6280.irq_pending--;
+ }
+ }
+
+ /* Check internal timer */
+ if(h6280.timer_status)
+ {
+ if(h6280.timer_value<=0)
+ {
+ if ( ! h6280.irq_pending )
+ h6280.irq_pending = 1;
+ while( h6280.timer_value <= 0 )
+ h6280.timer_value += h6280.timer_load;
+ set_irq_line(2,ASSERT_LINE);
+ }
+ }
+ } while (h6280_ICount > 0);
+
+ return cycles - h6280_ICount;
+}
+
+static void h6280_get_context (void *dst)
+{
+ if( dst )
+ *(h6280_Regs*)dst = h6280;
+}
+
+static void h6280_set_context (void *src)
+{
+ if( src )
+ h6280 = *(h6280_Regs*)src;
+ CHANGE_PC;
+}
+
+
+/*****************************************************************************/
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if ( state != ASSERT_LINE ) return;
+ h6280.nmi_state = state;
+ CHECK_IRQ_LINES;
+ }
+ else if (irqline < 3)
+ {
+ /* If the state has not changed, just return */
+ if ( h6280.irq_state[irqline] == state )
+ return;
+
+ h6280.irq_state[irqline] = state;
+
+ CHECK_IRQ_LINES;
+ }
+}
+
+
+
+/*****************************************************************************/
+
+READ8_HANDLER( H6280_irq_status_r )
+{
+ int status;
+
+ switch (offset&3)
+ {
+ default:return h6280.io_buffer;break;
+ case 3:
+ {
+ status=0;
+ if(h6280.irq_state[1]!=CLEAR_LINE) status|=1; /* IRQ 2 */
+ if(h6280.irq_state[0]!=CLEAR_LINE) status|=2; /* IRQ 1 */
+ if(h6280.irq_state[2]!=CLEAR_LINE) status|=4; /* TIMER */
+ return status|(h6280.io_buffer&(~H6280_IRQ_MASK));break;
+ }
+ case 2: return h6280.irq_mask|(h6280.io_buffer&(~H6280_IRQ_MASK));break;
+ }
+}
+
+WRITE8_HANDLER( H6280_irq_status_w )
+{
+ h6280.io_buffer=data;
+ switch (offset&3)
+ {
+ default:h6280.io_buffer=data;break;
+ case 2: /* Write irq mask */
+ h6280.irq_mask=data&0x7;
+ CHECK_IRQ_LINES;
+ break;
+
+ case 3: /* Timer irq ack */
+ set_irq_line(2,CLEAR_LINE);
+ break;
+ }
+}
+
+READ8_HANDLER( H6280_timer_r )
+{
+ /* only returns countdown */
+ return ((h6280.timer_value/1024)&0x7F)|(h6280.io_buffer&0x80);
+}
+
+WRITE8_HANDLER( H6280_timer_w )
+{
+ h6280.io_buffer=data;
+ switch (offset) {
+ case 0: /* Counter preload */
+ h6280.timer_load=h6280.timer_value=((data&127)+1)*1024;
+ return;
+
+ case 1: /* Counter enable */
+ if(data&1)
+ { /* stop -> start causes reload */
+ if(h6280.timer_status==0) h6280.timer_value=h6280.timer_load;
+ }
+ h6280.timer_status=data&1;
+ return;
+ }
+}
+
+static int h6280_translate(int space, offs_t *addr)
+{
+ if (space == ADDRESS_SPACE_PROGRAM)
+ *addr = TRANSLATED(*addr);
+ return 1;
+}
+
+UINT8 h6280io_get_buffer()
+{
+ return h6280.io_buffer;
+}
+void h6280io_set_buffer(UINT8 data)
+{
+ h6280.io_buffer=data;
+}
+
+
+/*****************************************************************************/
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void h6280_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 2: set_irq_line(2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI:set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + H6280_PC: PCW = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + H6280_S: S = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_P: P = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_A: A = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_X: X = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_Y: Y = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_IRQ_MASK: h6280.irq_mask = info->i; CHECK_IRQ_LINES; break;
+ case CPUINFO_INT_REGISTER + H6280_TIMER_STATE: h6280.timer_status = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_NMI_STATE: set_irq_line( INPUT_LINE_NMI, info->i ); break;
+ case CPUINFO_INT_REGISTER + H6280_IRQ1_STATE: set_irq_line( 0, info->i ); break;
+ case CPUINFO_INT_REGISTER + H6280_IRQ2_STATE: set_irq_line( 1, info->i ); break;
+ case CPUINFO_INT_REGISTER + H6280_IRQT_STATE: set_irq_line( 2, info->i ); break;
+#ifdef MAME_DEBUG
+ case CPUINFO_INT_REGISTER + H6280_M1: h6280.mmr[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_M2: h6280.mmr[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_M3: h6280.mmr[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_M4: h6280.mmr[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_M5: h6280.mmr[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_M6: h6280.mmr[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_M7: h6280.mmr[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + H6280_M8: h6280.mmr[7] = info->i; break;
+#endif
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void h6280_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(h6280); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 7; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 17 + 6*65536; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 21; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 2; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = h6280.irq_state[0]; break;
+ case CPUINFO_INT_INPUT_STATE + 1: info->i = h6280.irq_state[1]; break;
+ case CPUINFO_INT_INPUT_STATE + 2: info->i = h6280.irq_state[2]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = h6280.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = h6280.ppc.d; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + H6280_PC: info->i = PCD; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + H6280_S: info->i = S; break;
+ case CPUINFO_INT_REGISTER + H6280_P: info->i = P; break;
+ case CPUINFO_INT_REGISTER + H6280_A: info->i = A; break;
+ case CPUINFO_INT_REGISTER + H6280_X: info->i = X; break;
+ case CPUINFO_INT_REGISTER + H6280_Y: info->i = Y; break;
+ case CPUINFO_INT_REGISTER + H6280_IRQ_MASK: info->i = h6280.irq_mask; break;
+ case CPUINFO_INT_REGISTER + H6280_TIMER_STATE: info->i = h6280.timer_status; break;
+ case CPUINFO_INT_REGISTER + H6280_NMI_STATE: info->i = h6280.nmi_state; break;
+ case CPUINFO_INT_REGISTER + H6280_IRQ1_STATE: info->i = h6280.irq_state[0]; break;
+ case CPUINFO_INT_REGISTER + H6280_IRQ2_STATE: info->i = h6280.irq_state[1]; break;
+ case CPUINFO_INT_REGISTER + H6280_IRQT_STATE: info->i = h6280.irq_state[2]; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_INT_REGISTER + H6280_M1: info->i = h6280.mmr[0]; break;
+ case CPUINFO_INT_REGISTER + H6280_M2: info->i = h6280.mmr[1]; break;
+ case CPUINFO_INT_REGISTER + H6280_M3: info->i = h6280.mmr[2]; break;
+ case CPUINFO_INT_REGISTER + H6280_M4: info->i = h6280.mmr[3]; break;
+ case CPUINFO_INT_REGISTER + H6280_M5: info->i = h6280.mmr[4]; break;
+ case CPUINFO_INT_REGISTER + H6280_M6: info->i = h6280.mmr[5]; break;
+ case CPUINFO_INT_REGISTER + H6280_M7: info->i = h6280.mmr[6]; break;
+ case CPUINFO_INT_REGISTER + H6280_M8: info->i = h6280.mmr[7]; break;
+#endif
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = h6280_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = h6280_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = h6280_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = h6280_init; break;
+ case CPUINFO_PTR_RESET: info->reset = h6280_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = h6280_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = h6280_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = h6280_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &h6280_ICount; break;
+ case CPUINFO_PTR_TRANSLATE: info->translate = h6280_translate; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "HuC6280"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Hudsonsoft 6280"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.11"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 1999, 2000 Bryan McPhail, mish@tendril.co.uk"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ h6280.p & 0x80 ? 'N':'.',
+ h6280.p & 0x40 ? 'V':'.',
+ h6280.p & 0x20 ? 'R':'.',
+ h6280.p & 0x10 ? 'B':'.',
+ h6280.p & 0x08 ? 'D':'.',
+ h6280.p & 0x04 ? 'I':'.',
+ h6280.p & 0x02 ? 'Z':'.',
+ h6280.p & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + H6280_PC: sprintf(info->s, "PC:%04X", h6280.pc.d); break;
+ case CPUINFO_STR_REGISTER + H6280_S: sprintf(info->s, "S:%02X", h6280.sp.b.l); break;
+ case CPUINFO_STR_REGISTER + H6280_P: sprintf(info->s, "P:%02X", h6280.p); break;
+ case CPUINFO_STR_REGISTER + H6280_A: sprintf(info->s, "A:%02X", h6280.a); break;
+ case CPUINFO_STR_REGISTER + H6280_X: sprintf(info->s, "X:%02X", h6280.x); break;
+ case CPUINFO_STR_REGISTER + H6280_Y: sprintf(info->s, "Y:%02X", h6280.y); break;
+ case CPUINFO_STR_REGISTER + H6280_IRQ_MASK: sprintf(info->s, "IM:%02X", h6280.irq_mask); break;
+ case CPUINFO_STR_REGISTER + H6280_TIMER_STATE: sprintf(info->s, "TMR:%02X", h6280.timer_status); break;
+ case CPUINFO_STR_REGISTER + H6280_NMI_STATE: sprintf(info->s, "NMI:%X", h6280.nmi_state); break;
+ case CPUINFO_STR_REGISTER + H6280_IRQ1_STATE: sprintf(info->s, "IRQ1:%X", h6280.irq_state[0]); break;
+ case CPUINFO_STR_REGISTER + H6280_IRQ2_STATE: sprintf(info->s, "IRQ2:%X", h6280.irq_state[1]); break;
+ case CPUINFO_STR_REGISTER + H6280_IRQT_STATE: sprintf(info->s, "IRQT:%X", h6280.irq_state[2]); break;
+#ifdef MAME_DEBUG
+ case CPUINFO_STR_REGISTER + H6280_M1: sprintf(info->s, "M1:%02X", h6280.mmr[0]); break;
+ case CPUINFO_STR_REGISTER + H6280_M2: sprintf(info->s, "M2:%02X", h6280.mmr[1]); break;
+ case CPUINFO_STR_REGISTER + H6280_M3: sprintf(info->s, "M3:%02X", h6280.mmr[2]); break;
+ case CPUINFO_STR_REGISTER + H6280_M4: sprintf(info->s, "M4:%02X", h6280.mmr[3]); break;
+ case CPUINFO_STR_REGISTER + H6280_M5: sprintf(info->s, "M5:%02X", h6280.mmr[4]); break;
+ case CPUINFO_STR_REGISTER + H6280_M6: sprintf(info->s, "M6:%02X", h6280.mmr[5]); break;
+ case CPUINFO_STR_REGISTER + H6280_M7: sprintf(info->s, "M7:%02X", h6280.mmr[6]); break;
+ case CPUINFO_STR_REGISTER + H6280_M8: sprintf(info->s, "M8:%02X", h6280.mmr[7]); break;
+#endif
+ }
+}
diff --git a/src/emu/cpu/h6280/h6280.h b/src/emu/cpu/h6280/h6280.h
new file mode 100644
index 00000000000..a1cd235a7d5
--- /dev/null
+++ b/src/emu/cpu/h6280/h6280.h
@@ -0,0 +1,54 @@
+/*****************************************************************************
+
+ h6280.h Portable Hu6280 emulator interface
+
+ Copyright (c) 1999 Bryan McPhail, mish@tendril.co.uk
+
+ This source code is based (with permission!) on the 6502 emulator by
+ Juergen Buchmueller. It is released as part of the Mame emulator project.
+ Let me know if you intend to use this code in any other project.
+
+******************************************************************************/
+
+#ifndef _H6280_H
+#define _H6280_H
+
+#include "cpuintrf.h"
+
+enum {
+ H6280_PC=1, H6280_S, H6280_P, H6280_A, H6280_X, H6280_Y,
+ H6280_IRQ_MASK, H6280_TIMER_STATE,
+ H6280_NMI_STATE, H6280_IRQ1_STATE, H6280_IRQ2_STATE, H6280_IRQT_STATE
+#ifdef MAME_DEBUG
+ ,
+ H6280_M1, H6280_M2, H6280_M3, H6280_M4,
+ H6280_M5, H6280_M6, H6280_M7, H6280_M8
+#endif
+};
+
+#define LAZY_FLAGS 0
+
+#define H6280_RESET_VEC 0xfffe
+#define H6280_NMI_VEC 0xfffc
+#define H6280_TIMER_VEC 0xfffa
+#define H6280_IRQ1_VEC 0xfff8
+#define H6280_IRQ2_VEC 0xfff6 /* Aka BRK vector */
+
+void h6280_get_info(UINT32 state, cpuinfo *info);
+
+
+READ8_HANDLER( H6280_irq_status_r );
+WRITE8_HANDLER( H6280_irq_status_w );
+
+READ8_HANDLER( H6280_timer_r );
+WRITE8_HANDLER( H6280_timer_w );
+
+/* functions for use by the PSG and joypad port only! */
+UINT8 h6280io_get_buffer(void);
+void h6280io_set_buffer(UINT8);
+
+#ifdef MAME_DEBUG
+offs_t h6280_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _H6280_H */
diff --git a/src/emu/cpu/h6280/h6280ops.h b/src/emu/cpu/h6280/h6280ops.h
new file mode 100644
index 00000000000..087698f88c7
--- /dev/null
+++ b/src/emu/cpu/h6280/h6280ops.h
@@ -0,0 +1,1379 @@
+/*****************************************************************************
+
+ h6280ops.h - Addressing modes and opcode macros for the Hu6820 cpu
+
+ Copyright (c) 1999 Bryan McPhail, mish@tendril.co.uk
+
+ This source code is based (with permission!) on the 6502 emulator by
+ Juergen Buchmueller. It is released as part of the Mame emulator project.
+ Let me know if you intend to use this code in any other project.
+
+******************************************************************************/
+
+/* 6280 flags */
+#define _fC 0x01
+#define _fZ 0x02
+#define _fI 0x04
+#define _fD 0x08
+#define _fB 0x10
+#define _fT 0x20
+#define _fV 0x40
+#define _fN 0x80
+
+/* some shortcuts for improved readability */
+#define A h6280.a
+#define X h6280.x
+#define Y h6280.y
+#define P h6280.p
+#define S h6280.sp.b.l
+
+#define TRANSLATED(addr) ((h6280.mmr[(addr)>>13] << 13) | ((addr)&0x1fff))
+#define CHANGE_PC do { offs_t temp = TRANSLATED(PCW); change_pc(temp); } while (0)
+#define H6280_CYCLES(cyc) \
+ { \
+ h6280_ICount -= ((cyc) * h6280.clocks_per_cycle); \
+ h6280.timer_value -= ((cyc) * h6280.clocks_per_cycle); \
+ }
+
+#if LAZY_FLAGS
+
+#define NZ h6280.NZ
+#define SET_NZ(n) \
+ P &= ~_fT; \
+ NZ = ((n & _fN) << 8) | n
+
+#else
+
+#define SET_NZ(n) \
+ P = (P & ~(_fN|_fT|_fZ)) | \
+ (n & _fN) | \
+ ((n == 0) ? _fZ : 0)
+
+#endif
+
+#define EAL h6280.ea.b.l
+#define EAH h6280.ea.b.h
+#define EAW h6280.ea.w.l
+#define EAD h6280.ea.d
+
+#define ZPL h6280.zp.b.l
+#define ZPH h6280.zp.b.h
+#define ZPW h6280.zp.w.l
+#define ZPD h6280.zp.d
+
+#define PCL h6280.pc.b.l
+#define PCH h6280.pc.b.h
+#define PCW h6280.pc.w.l
+#define PCD h6280.pc.d
+
+#define CLEAR_T \
+ P &= ~_fT;
+
+#define DO_INTERRUPT(vector) \
+{ \
+ H6280_CYCLES(7); /* 7 cycles for an int */ \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ COMPOSE_P(0,_fB); \
+ PUSH(P); \
+ P = (P & ~_fD) | _fI; /* knock out D and set I flag */ \
+ PCL = RDMEM(vector); \
+ PCH = RDMEM((vector+1)); \
+ CHANGE_PC; \
+}
+
+#define CHECK_AND_TAKE_IRQ_LINES \
+ if ( h6280.nmi_state != CLEAR_LINE ) { \
+ h6280.nmi_state = CLEAR_LINE; \
+ DO_INTERRUPT(H6280_NMI_VEC); \
+ } \
+ else if( !(P & _fI) ) \
+ { \
+ if ( h6280.irq_state[2] != CLEAR_LINE && \
+ !(h6280.irq_mask & 0x4) ) \
+ { \
+ DO_INTERRUPT(H6280_TIMER_VEC); \
+ } else \
+ if ( h6280.irq_state[0] != CLEAR_LINE && \
+ !(h6280.irq_mask & 0x2) ) \
+ { \
+ DO_INTERRUPT(H6280_IRQ1_VEC); \
+ (*h6280.irq_callback)(0); \
+ } else \
+ if ( h6280.irq_state[1] != CLEAR_LINE && \
+ !(h6280.irq_mask & 0x1) ) \
+ { \
+ DO_INTERRUPT(H6280_IRQ2_VEC); \
+ (*h6280.irq_callback)(1); \
+ } \
+ }
+
+#define CHECK_IRQ_LINES \
+ if ( ! h6280.irq_pending ) \
+ h6280.irq_pending = 2;
+
+/***************************************************************
+ * CHECK_VDC_VCE_PENALTY
+ * The CPU inserts 1 clock delay when accessing the VDC or VCE
+ * area.
+ ***************************************************************/
+#define CHECK_VDC_VCE_PENALTY(addr) \
+ if ( ( TRANSLATED(addr) & 0x1FF800 ) == 0x1FE000 ) { \
+ H6280_CYCLES(1); \
+ }
+
+/***************************************************************
+ * RDMEM read memory
+ ***************************************************************/
+INLINE UINT8 RDMEM(offs_t addr) {
+ CHECK_VDC_VCE_PENALTY(addr);
+ return program_read_byte_8(TRANSLATED(addr));
+}
+
+/***************************************************************
+ * WRMEM write memory
+ ***************************************************************/
+INLINE void WRMEM(offs_t addr, UINT8 data) {
+ CHECK_VDC_VCE_PENALTY(addr);
+ program_write_byte_8(TRANSLATED(addr),data);
+}
+
+/***************************************************************
+ * RDMEMZ read memory - zero page
+ ***************************************************************/
+#define RDMEMZ(addr) \
+ program_read_byte_8( (h6280.mmr[1] << 13) | ((addr)&0x1fff));
+
+/***************************************************************
+ * WRMEMZ write memory - zero page
+ ***************************************************************/
+#define WRMEMZ(addr,data) \
+ program_write_byte_8( (h6280.mmr[1] << 13) | ((addr)&0x1fff),data);
+
+/***************************************************************
+ * RDMEMW read word from memory
+ ***************************************************************/
+#define RDMEMW(addr) \
+ program_read_byte_8(TRANSLATED(addr)) \
+| ( program_read_byte_8(TRANSLATED(addr+1)) << 8 )
+
+/***************************************************************
+ * RDZPWORD read a word from a zero page address
+ ***************************************************************/
+#define RDZPWORD(addr) \
+ ((addr&0xff)==0xff) ? \
+ program_read_byte_8( (h6280.mmr[1] << 13) | ((addr)&0x1fff)) \
+ +(program_read_byte_8( (h6280.mmr[1] << 13) | ((addr-0xff)&0x1fff))<<8) : \
+ program_read_byte_8( (h6280.mmr[1] << 13) | ((addr)&0x1fff)) \
+ +(program_read_byte_8( (h6280.mmr[1] << 13) | ((addr+1)&0x1fff))<<8)
+
+
+/***************************************************************
+ * push a register onto the stack
+ ***************************************************************/
+#define PUSH(Rg) program_write_byte_8( (h6280.mmr[1] << 13) | h6280.sp.d,Rg); S--
+
+/***************************************************************
+ * pull a register from the stack
+ ***************************************************************/
+#define PULL(Rg) S++; Rg = program_read_byte_8( (h6280.mmr[1] << 13) | h6280.sp.d)
+
+/***************************************************************
+ * RDOP read an opcode
+ ***************************************************************/
+#define RDOP() \
+ cpu_readop(TRANSLATED(PCW))
+
+/***************************************************************
+ * RDOPARG read an opcode argument
+ ***************************************************************/
+#define RDOPARG() \
+ cpu_readop_arg(TRANSLATED(PCW))
+
+/***************************************************************
+ * BRA branch relative
+ ***************************************************************/
+#define BRA(cond) \
+ CLEAR_T; \
+ if (cond) \
+ { \
+ H6280_CYCLES(4); \
+ tmp = RDOPARG(); \
+ PCW++; \
+ EAW = PCW + (signed char)tmp; \
+ PCD = EAD; \
+ CHANGE_PC; \
+ } \
+ else \
+ { \
+ PCW++; \
+ H6280_CYCLES(2); \
+ }
+
+/***************************************************************
+ *
+ * Helper macros to build the effective address
+ *
+ ***************************************************************/
+
+/***************************************************************
+ * EA = zero page address
+ ***************************************************************/
+#define EA_ZPG \
+ ZPL = RDOPARG(); \
+ PCW++; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page address - T flag
+ ***************************************************************/
+#define EA_TFLG \
+ ZPL = X; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page address + X
+ ***************************************************************/
+#define EA_ZPX \
+ ZPL = RDOPARG() + X; \
+ PCW++; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page address + Y
+ ***************************************************************/
+#define EA_ZPY \
+ ZPL = RDOPARG() + Y; \
+ PCW++; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = absolute address
+ ***************************************************************/
+#define EA_ABS \
+ EAL = RDOPARG(); \
+ PCW++; \
+ EAH = RDOPARG(); \
+ PCW++
+
+/***************************************************************
+ * EA = absolute address + X
+ ***************************************************************/
+#define EA_ABX \
+ EA_ABS; \
+ EAW += X
+
+/***************************************************************
+ * EA = absolute address + Y
+ ***************************************************************/
+#define EA_ABY \
+ EA_ABS; \
+ EAW += Y
+
+/***************************************************************
+ * EA = zero page indirect (65c02 pre indexed w/o X)
+ ***************************************************************/
+#define EA_ZPI \
+ ZPL = RDOPARG(); \
+ PCW++; \
+ EAD = RDZPWORD(ZPD)
+
+/***************************************************************
+ * EA = zero page + X indirect (pre indexed)
+ ***************************************************************/
+#define EA_IDX \
+ ZPL = RDOPARG() + X; \
+ PCW++; \
+ EAD = RDZPWORD(ZPD);
+
+/***************************************************************
+ * EA = zero page indirect + Y (post indexed)
+ ***************************************************************/
+#define EA_IDY \
+ ZPL = RDOPARG(); \
+ PCW++; \
+ EAD = RDZPWORD(ZPD); \
+ EAW += Y
+
+/***************************************************************
+ * EA = indirect (only used by JMP)
+ ***************************************************************/
+#define EA_IND \
+ EA_ABS; \
+ tmp = RDMEM(EAD); \
+ EAD++; \
+ EAH = RDMEM(EAD); \
+ EAL = tmp
+
+/***************************************************************
+ * EA = indirect plus x (only used by JMP)
+ ***************************************************************/
+#define EA_IAX \
+ EA_ABS; \
+ EAD+=X; \
+ tmp = RDMEM(EAD); \
+ EAD++; \
+ EAH = RDMEM(EAD); \
+ EAL = tmp
+
+/* read a value into tmp */
+#define RD_IMM tmp = RDOPARG(); PCW++
+#define RD_IMM2 tmp2 = RDOPARG(); PCW++
+#define RD_ACC tmp = A
+#define RD_ZPG EA_ZPG; tmp = RDMEMZ(EAD)
+#define RD_ZPX EA_ZPX; tmp = RDMEMZ(EAD)
+#define RD_ZPY EA_ZPY; tmp = RDMEMZ(EAD)
+#define RD_ABS EA_ABS; tmp = RDMEM(EAD)
+#define RD_ABX EA_ABX; tmp = RDMEM(EAD)
+#define RD_ABY EA_ABY; tmp = RDMEM(EAD)
+#define RD_ZPI EA_ZPI; tmp = RDMEM(EAD)
+#define RD_IDX EA_IDX; tmp = RDMEM(EAD)
+#define RD_IDY EA_IDY; tmp = RDMEM(EAD)
+#define RD_TFL EA_TFLG; tflagtemp = RDMEMZ(EAD)
+
+/* write a value from tmp */
+#define WR_ZPG EA_ZPG; WRMEMZ(EAD, tmp)
+#define WR_ZPX EA_ZPX; WRMEMZ(EAD, tmp)
+#define WR_ZPY EA_ZPY; WRMEMZ(EAD, tmp)
+#define WR_ABS EA_ABS; WRMEM(EAD, tmp)
+#define WR_ABX EA_ABX; WRMEM(EAD, tmp)
+#define WR_ABY EA_ABY; WRMEM(EAD, tmp)
+#define WR_ZPI EA_ZPI; WRMEM(EAD, tmp)
+#define WR_IDX EA_IDX; WRMEM(EAD, tmp)
+#define WR_IDY EA_IDY; WRMEM(EAD, tmp)
+
+/* write back a value from tmp to the last EA */
+#define WB_ACC A = (UINT8)tmp;
+#define WB_EA WRMEM(EAD, tmp)
+#define WB_EAZ WRMEMZ(EAD, tmp)
+#define WB_TFL WRMEMZ(EAD, tflagtemp)
+
+/***************************************************************
+ *
+ * Macros to emulate the 6280 opcodes
+ *
+ ***************************************************************/
+
+/***************************************************************
+ * compose the real flag register by
+ * including N and Z and set any
+ * SET and clear any CLR bits also
+ ***************************************************************/
+#if LAZY_FLAGS
+
+#define COMPOSE_P(SET,CLR) \
+ P = (P & ~(_fN | _fZ | CLR)) | \
+ (NZ >> 8) | \
+ ((NZ & 0xff) ? 0 : _fZ) | \
+ SET
+
+#else
+
+#define COMPOSE_P(SET,CLR) \
+ P = (P & ~CLR) | SET
+
+#endif
+
+/* 6280 ********************************************************
+ * ADC Add with carry
+ ***************************************************************/
+#define TADC \
+ { \
+ int tflagtemp; \
+ CLEAR_T; \
+ RD_TFL; \
+ if (P & _fD) \
+ { \
+ int c = (P & _fC); \
+ int lo = (tflagtemp & 0x0f) + (tmp & 0x0f) + c; \
+ int hi = (tflagtemp & 0xf0) + (tmp & 0xf0); \
+ P &= ~_fC; \
+ if (lo > 0x09) \
+ { \
+ hi += 0x10; \
+ lo += 0x06; \
+ } \
+ if (hi > 0x90) \
+ hi += 0x60; \
+ if (hi & 0xff00) \
+ P |= _fC; \
+ tflagtemp = (lo & 0x0f) + (hi & 0xf0); \
+ H6280_CYCLES(1); \
+ } \
+ else \
+ { \
+ int c = (P & _fC); \
+ int sum = tflagtemp + tmp + c; \
+ P &= ~(_fV | _fC); \
+ if (~(tflagtemp^tmp) & (tflagtemp^sum) & _fN) \
+ P |= _fV; \
+ if (sum & 0xff00) \
+ P |= _fC; \
+ tflagtemp = (UINT8) sum; \
+ } \
+ SET_NZ(tflagtemp); \
+ WB_TFL; \
+ H6280_CYCLES(3); \
+ }
+
+
+#define ADC \
+ if(P & _fT) \
+ TADC \
+ else { \
+ if (P & _fD) \
+ { \
+ int c = (P & _fC); \
+ int lo = (A & 0x0f) + (tmp & 0x0f) + c; \
+ int hi = (A & 0xf0) + (tmp & 0xf0); \
+ P &= ~_fC; \
+ if (lo > 0x09) \
+ { \
+ hi += 0x10; \
+ lo += 0x06; \
+ } \
+ if (hi > 0x90) \
+ hi += 0x60; \
+ if (hi & 0xff00) \
+ P |= _fC; \
+ A = (lo & 0x0f) + (hi & 0xf0); \
+ H6280_CYCLES(1); \
+ } \
+ else \
+ { \
+ int c = (P & _fC); \
+ int sum = A + tmp + c; \
+ P &= ~(_fV | _fC); \
+ if (~(A^tmp) & (A^sum) & _fN) \
+ P |= _fV; \
+ if (sum & 0xff00) \
+ P |= _fC; \
+ A = (UINT8) sum; \
+ } \
+ SET_NZ(A); \
+ }
+
+/* 6280 ********************************************************
+ * AND Logical and
+ ***************************************************************/
+#define TAND \
+ { \
+ int tflagtemp; \
+ CLEAR_T; \
+ RD_TFL; \
+ tflagtemp = (UINT8)(tflagtemp & tmp); \
+ WB_TFL; \
+ SET_NZ(tflagtemp); \
+ H6280_CYCLES(3); \
+ }
+
+#define AND \
+ if(P & _fT) \
+ TAND \
+ else { \
+ A = (UINT8)(A & tmp); \
+ SET_NZ(A); \
+ }
+
+/* 6280 ********************************************************
+ * ASL Arithmetic shift left
+ ***************************************************************/
+#define ASL \
+ CLEAR_T; \
+ P = (P & ~_fC) | ((tmp >> 7) & _fC); \
+ tmp = (UINT8)(tmp << 1); \
+ SET_NZ(tmp)
+
+/* 6280 ********************************************************
+ * BBR Branch if bit is reset
+ ***************************************************************/
+#define BBR(bit) \
+ BRA(!(tmp & (1<<bit)))
+
+/* 6280 ********************************************************
+ * BBS Branch if bit is set
+ ***************************************************************/
+#define BBS(bit) \
+ BRA(tmp & (1<<bit))
+
+/* 6280 ********************************************************
+ * BCC Branch if carry clear
+ ***************************************************************/
+#define BCC BRA(!(P & _fC))
+
+/* 6280 ********************************************************
+ * BCS Branch if carry set
+ ***************************************************************/
+#define BCS BRA(P & _fC)
+
+/* 6280 ********************************************************
+ * BEQ Branch if equal
+ ***************************************************************/
+#if LAZY_FLAGS
+#define BEQ BRA(!(NZ & 0xff))
+#else
+#define BEQ BRA(P & _fZ)
+#endif
+
+/* 6280 ********************************************************
+ * BIT Bit test
+ ***************************************************************/
+#undef BIT
+#define BIT \
+ P = (P & ~(_fN|_fV|_fT|_fZ)) \
+ | ((tmp&0x80) ? _fN:0) \
+ | ((tmp&0x40) ? _fV:0) \
+ | ((tmp&A) ? 0:_fZ)
+
+/* 6280 ********************************************************
+ * BMI Branch if minus
+ ***************************************************************/
+#if LAZY_FLAGS
+#define BMI BRA(NZ & 0x8000)
+#else
+#define BMI BRA(P & _fN)
+#endif
+
+/* 6280 ********************************************************
+ * BNE Branch if not equal
+ ***************************************************************/
+#if LAZY_FLAGS
+#define BNE BRA(NZ & 0xff)
+#else
+#define BNE BRA(!(P & _fZ))
+#endif
+
+/* 6280 ********************************************************
+ * BPL Branch if plus
+ ***************************************************************/
+#if LAZY_FLAGS
+#define BPL BRA(!(NZ & 0x8000))
+#else
+#define BPL BRA(!(P & _fN))
+#endif
+
+/* 6280 ********************************************************
+ * BRK Break
+ * increment PC, push PC hi, PC lo, flags (with B bit set),
+ * set I flag, reset D flag and jump via IRQ vector
+ ***************************************************************/
+#define BRK \
+ logerror("BRK %04x\n",activecpu_get_pc()); \
+ CLEAR_T; \
+ PCW++; \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ PUSH(P); \
+ P = (P & ~_fD) | _fI; \
+ PCL = RDMEM(H6280_IRQ2_VEC); \
+ PCH = RDMEM(H6280_IRQ2_VEC+1); \
+ CHANGE_PC
+
+/* 6280 ********************************************************
+ * BSR Branch to subroutine
+ ***************************************************************/
+#define BSR \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ H6280_CYCLES(4); /* 4 cycles here, 4 in BRA */ \
+ BRA(1)
+
+/* 6280 ********************************************************
+ * BVC Branch if overflow clear
+ ***************************************************************/
+#define BVC BRA(!(P & _fV))
+
+/* 6280 ********************************************************
+ * BVS Branch if overflow set
+ ***************************************************************/
+#define BVS BRA(P & _fV)
+
+/* 6280 ********************************************************
+ * CLA Clear accumulator
+ ***************************************************************/
+#define CLA \
+ CLEAR_T; \
+ A = 0
+
+/* 6280 ********************************************************
+ * CLC Clear carry flag
+ ***************************************************************/
+#define CLC \
+ CLEAR_T; \
+ P &= ~_fC
+
+/* 6280 ********************************************************
+ * CLD Clear decimal flag
+ ***************************************************************/
+#define CLD \
+ CLEAR_T; \
+ P &= ~_fD
+
+/* 6280 ********************************************************
+ * CLI Clear interrupt flag
+ ***************************************************************/
+#define CLI \
+ CLEAR_T; \
+ if( P & _fI ) \
+ { \
+ P &= ~_fI; \
+ CHECK_IRQ_LINES; \
+ }
+
+
+/* 6280 ********************************************************
+ * CLV Clear overflow flag
+ ***************************************************************/
+#define CLV \
+ CLEAR_T; \
+ P &= ~_fV
+
+/* 6280 ********************************************************
+ * CLX Clear index X
+ ***************************************************************/
+#define CLX \
+ CLEAR_T; \
+ X = 0
+
+/* 6280 ********************************************************
+ * CLY Clear index Y
+ ***************************************************************/
+#define CLY \
+ CLEAR_T; \
+ Y = 0
+
+/* 6280 ********************************************************
+ * CMP Compare accumulator
+ ***************************************************************/
+#define CMP \
+ CLEAR_T; \
+ P &= ~_fC; \
+ if (A >= tmp) \
+ P |= _fC; \
+ SET_NZ((UINT8)(A - tmp))
+
+/* 6280 ********************************************************
+ * CPX Compare index X
+ ***************************************************************/
+#define CPX \
+ CLEAR_T; \
+ P &= ~_fC; \
+ if (X >= tmp) \
+ P |= _fC; \
+ SET_NZ((UINT8)(X - tmp))
+
+/* 6280 ********************************************************
+ * CPY Compare index Y
+ ***************************************************************/
+#define CPY \
+ CLEAR_T; \
+ P &= ~_fC; \
+ if (Y >= tmp) \
+ P |= _fC; \
+ SET_NZ((UINT8)(Y - tmp))
+
+/* 6280 ********************************************************
+ * DEA Decrement accumulator
+ ***************************************************************/
+#define DEA \
+ CLEAR_T; \
+ A = (UINT8)--A; \
+ SET_NZ(A)
+
+/* 6280 ********************************************************
+ * DEC Decrement memory
+ ***************************************************************/
+#define DEC \
+ CLEAR_T; \
+ tmp = (UINT8)(tmp-1); \
+ SET_NZ(tmp)
+
+/* 6280 ********************************************************
+ * DEX Decrement index X
+ ***************************************************************/
+#define DEX \
+ CLEAR_T; \
+ X = (UINT8)--X; \
+ SET_NZ(X)
+
+/* 6280 ********************************************************
+ * DEY Decrement index Y
+ ***************************************************************/
+#define DEY \
+ CLEAR_T; \
+ Y = (UINT8)--Y; \
+ SET_NZ(Y)
+
+/* 6280 ********************************************************
+ * EOR Logical exclusive or
+ ***************************************************************/
+#define TEOR \
+ { \
+ int tflagtemp; \
+ CLEAR_T; \
+ RD_TFL; \
+ tflagtemp = (UINT8)(tflagtemp ^ tmp); \
+ WB_TFL; \
+ SET_NZ(tflagtemp); \
+ H6280_CYCLES(3); \
+ }
+
+#define EOR \
+ if(P & _fT) \
+ TEOR \
+ else { \
+ A = (UINT8)(A ^ tmp); \
+ SET_NZ(A); \
+ }
+
+/* 6280 ********************************************************
+ * INA Increment accumulator
+ ***************************************************************/
+#define INA \
+ CLEAR_T; \
+ A = (UINT8)++A; \
+ SET_NZ(A)
+
+/* 6280 ********************************************************
+ * INC Increment memory
+ ***************************************************************/
+#define INC \
+ CLEAR_T; \
+ tmp = (UINT8)(tmp+1); \
+ SET_NZ(tmp)
+
+/* 6280 ********************************************************
+ * INX Increment index X
+ ***************************************************************/
+#define INX \
+ CLEAR_T; \
+ X = (UINT8)++X; \
+ SET_NZ(X)
+
+/* 6280 ********************************************************
+ * INY Increment index Y
+ ***************************************************************/
+#define INY \
+ CLEAR_T; \
+ Y = (UINT8)++Y; \
+ SET_NZ(Y)
+
+/* 6280 ********************************************************
+ * JMP Jump to address
+ * set PC to the effective address
+ ***************************************************************/
+#define JMP \
+ CLEAR_T; \
+ PCD = EAD; \
+ CHANGE_PC
+
+/* 6280 ********************************************************
+ * JSR Jump to subroutine
+ * decrement PC (sic!) push PC hi, push PC lo and set
+ * PC to the effective address
+ ***************************************************************/
+#define JSR \
+ CLEAR_T; \
+ PCW--; \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ PCD = EAD; \
+ CHANGE_PC
+
+/* 6280 ********************************************************
+ * LDA Load accumulator
+ ***************************************************************/
+#define LDA \
+ CLEAR_T; \
+ A = (UINT8)tmp; \
+ SET_NZ(A)
+
+/* 6280 ********************************************************
+ * LDX Load index X
+ ***************************************************************/
+#define LDX \
+ CLEAR_T; \
+ X = (UINT8)tmp; \
+ SET_NZ(X)
+
+/* 6280 ********************************************************
+ * LDY Load index Y
+ ***************************************************************/
+#define LDY \
+ CLEAR_T; \
+ Y = (UINT8)tmp; \
+ SET_NZ(Y)
+
+/* 6280 ********************************************************
+ * LSR Logic shift right
+ * 0 -> [7][6][5][4][3][2][1][0] -> C
+ ***************************************************************/
+#define LSR \
+ CLEAR_T; \
+ P = (P & ~_fC) | (tmp & _fC); \
+ tmp = (UINT8)tmp >> 1; \
+ SET_NZ(tmp)
+
+/* 6280 ********************************************************
+ * NOP No operation
+ ***************************************************************/
+#define NOP CLEAR_T;
+
+/* 6280 ********************************************************
+ * ORA Logical inclusive or
+ ***************************************************************/
+
+#define TORA \
+ { \
+ int tflagtemp; \
+ CLEAR_T; \
+ RD_TFL; \
+ tflagtemp = (UINT8)(tflagtemp | tmp); \
+ WB_TFL; \
+ SET_NZ(tflagtemp); \
+ H6280_CYCLES(3); \
+ }
+
+#define ORA \
+ if(P & _fT) \
+ TORA \
+ else { \
+ A = (UINT8)(A | tmp); \
+ SET_NZ(A); \
+ }
+
+/* 6280 ********************************************************
+ * PHA Push accumulator
+ ***************************************************************/
+#define PHA \
+ CLEAR_T; \
+ PUSH(A)
+
+/* 6280 ********************************************************
+ * PHP Push processor status (flags)
+ ***************************************************************/
+#define PHP \
+ CLEAR_T; \
+ COMPOSE_P(0,0); \
+ PUSH(P)
+
+/* 6280 ********************************************************
+ * PHX Push index X
+ ***************************************************************/
+#define PHX \
+ CLEAR_T; \
+ PUSH(X)
+
+/* 6280 ********************************************************
+ * PHY Push index Y
+ ***************************************************************/
+#define PHY \
+ CLEAR_T; \
+ PUSH(Y)
+
+/* 6280 ********************************************************
+ * PLA Pull accumulator
+ ***************************************************************/
+#define PLA \
+ CLEAR_T; \
+ PULL(A); \
+ SET_NZ(A)
+
+/* 6280 ********************************************************
+ * PLP Pull processor status (flags)
+ ***************************************************************/
+#if LAZY_FLAGS
+
+#define PLP \
+ PULL(P); \
+ P |= _fB; \
+ NZ = ((P & _fN) << 8) | \
+ ((P & _fZ) ^ _fZ); \
+ CHECK_IRQ_LINES
+
+#else
+
+#define PLP \
+ PULL(P); \
+ P |= _fB; \
+ CHECK_IRQ_LINES
+#endif
+
+/* 6280 ********************************************************
+ * PLX Pull index X
+ ***************************************************************/
+#define PLX \
+ CLEAR_T; \
+ PULL(X); \
+ SET_NZ(X)
+
+/* 6280 ********************************************************
+ * PLY Pull index Y
+ ***************************************************************/
+#define PLY \
+ CLEAR_T; \
+ PULL(Y); \
+ SET_NZ(Y)
+
+/* 6280 ********************************************************
+ * RMB Reset memory bit
+ ***************************************************************/
+#define RMB(bit) \
+ CLEAR_T; \
+ tmp &= ~(1<<bit)
+
+/* 6280 ********************************************************
+ * ROL Rotate left
+ * new C <- [7][6][5][4][3][2][1][0] <- C
+ ***************************************************************/
+#define ROL \
+ CLEAR_T; \
+ tmp = (tmp << 1) | (P & _fC); \
+ P = (P & ~_fC) | ((tmp >> 8) & _fC); \
+ tmp = (UINT8)tmp; \
+ SET_NZ(tmp)
+
+/* 6280 ********************************************************
+ * ROR Rotate right
+ * C -> [7][6][5][4][3][2][1][0] -> new C
+ ***************************************************************/
+#define ROR \
+ CLEAR_T; \
+ tmp |= (P & _fC) << 8; \
+ P = (P & ~_fC) | (tmp & _fC); \
+ tmp = (UINT8)(tmp >> 1); \
+ SET_NZ(tmp)
+
+/* 6280 ********************************************************
+ * RTI Return from interrupt
+ * pull flags, pull PC lo, pull PC hi and increment PC
+ ***************************************************************/
+#if LAZY_FLAGS
+
+#define RTI \
+ PULL(P); \
+ P |= _fB; \
+ NZ = ((P & _fN) << 8) | \
+ ((P & _fZ) ^ _fZ); \
+ PULL(PCL); \
+ PULL(PCH); \
+ CHANGE_PC; \
+ CHECK_IRQ_LINES
+#else
+
+#define RTI \
+ PULL(P); \
+ P |= _fB; \
+ PULL(PCL); \
+ PULL(PCH); \
+ CHANGE_PC; \
+ CHECK_IRQ_LINES
+#endif
+
+/* 6280 ********************************************************
+ * RTS Return from subroutine
+ * pull PC lo, PC hi and increment PC
+ ***************************************************************/
+#define RTS \
+ CLEAR_T; \
+ PULL(PCL); \
+ PULL(PCH); \
+ PCW++; \
+ CHANGE_PC
+
+/* 6280 ********************************************************
+ * SAX Swap accumulator and index X
+ ***************************************************************/
+#define SAX \
+ CLEAR_T; \
+ tmp = X; \
+ X = A; \
+ A = tmp
+
+/* 6280 ********************************************************
+ * SAY Swap accumulator and index Y
+ ***************************************************************/
+#define SAY \
+ CLEAR_T; \
+ tmp = Y; \
+ Y = A; \
+ A = tmp
+
+/* 6280 ********************************************************
+ * SBC Subtract with carry
+ ***************************************************************/
+#define TSBC \
+ { \
+ int tflagtemp; \
+ CLEAR_T; \
+ RD_TFL; \
+ if (P & _fD) \
+ { \
+ int c = (P & _fC) ^ _fC; \
+ int sum = tflagtemp - tmp -c; \
+ int lo = (tflagtemp & 0x0f) - (tmp & 0x0f) - c; \
+ int hi = (tflagtemp & 0xf0) - (tmp & 0xf0); \
+ P &= ~_fC; \
+ if (lo & 0xf0) \
+ lo -= 6; \
+ if (lo & 0x80) \
+ hi -= 0x10; \
+ if (hi & 0x0f00) \
+ hi -= 0x60; \
+ if ((sum & 0xff00) == 0) \
+ P |= _fC; \
+ tflagtemp = (lo & 0x0f) + (hi & 0xf0); \
+ H6280_CYCLES(1); \
+ } \
+ else \
+ { \
+ int c = (P & _fC) ^ _fC; \
+ int sum = tflagtemp - tmp - c; \
+ P &= ~(_fV | _fC); \
+ if ((tflagtemp^tmp) & (tflagtemp^sum) & _fN) \
+ P |= _fV; \
+ if ((sum & 0xff00) == 0) \
+ P |= _fC; \
+ tflagtemp = (UINT8) sum; \
+ } \
+ SET_NZ(tflagtemp); \
+ WB_TFL; \
+ H6280_CYCLES(3); \
+ }
+
+#define SBC \
+ if(P & _fT) \
+ TSBC \
+ else { \
+ if (P & _fD) \
+ { \
+ int c = (P & _fC) ^ _fC; \
+ int sum = A - tmp - c; \
+ int lo = (A & 0x0f) - (tmp & 0x0f) - c; \
+ int hi = (A & 0xf0) - (tmp & 0xf0); \
+ P &= ~_fC; \
+ if (lo & 0xf0) \
+ lo -= 6; \
+ if (lo & 0x80) \
+ hi -= 0x10; \
+ if (hi & 0x0f00) \
+ hi -= 0x60; \
+ if ((sum & 0xff00) == 0) \
+ P |= _fC; \
+ A = (lo & 0x0f) + (hi & 0xf0); \
+ H6280_CYCLES(1); \
+ } \
+ else \
+ { \
+ int c = (P & _fC) ^ _fC; \
+ int sum = A - tmp - c; \
+ P &= ~(_fV | _fC); \
+ if ((A^tmp) & (A^sum) & _fN) \
+ P |= _fV; \
+ if ((sum & 0xff00) == 0) \
+ P |= _fC; \
+ A = (UINT8) sum; \
+ } \
+ SET_NZ(A); \
+ }
+
+/* 6280 ********************************************************
+ * SEC Set carry flag
+ ***************************************************************/
+#define SEC \
+ CLEAR_T; \
+ P |= _fC
+
+/* 6280 ********************************************************
+ * SED Set decimal flag
+ ***************************************************************/
+#define SED \
+ CLEAR_T; \
+ P |= _fD
+
+/* 6280 ********************************************************
+ * SEI Set interrupt flag
+ ***************************************************************/
+#define SEI \
+ CLEAR_T; \
+ P |= _fI
+
+/* 6280 ********************************************************
+ * SET Set t flag
+ ***************************************************************/
+#define SET \
+ P |= _fT; \
+ logerror("%04x: WARNING H6280 SET\n",activecpu_get_pc())
+
+/* 6280 ********************************************************
+ * SMB Set memory bit
+ ***************************************************************/
+#define SMB(bit) \
+ CLEAR_T; \
+ tmp |= (1<<bit)
+
+/* 6280 ********************************************************
+ * ST0 Store at hardware address 0
+ ***************************************************************/
+#define ST0 \
+ CLEAR_T; \
+ io_write_byte_8(0x0000,tmp)
+
+/* 6280 ********************************************************
+ * ST1 Store at hardware address 2
+ ***************************************************************/
+#define ST1 \
+ CLEAR_T; \
+ io_write_byte_8(0x0002,tmp)
+
+/* 6280 ********************************************************
+ * ST2 Store at hardware address 3
+ ***************************************************************/
+#define ST2 \
+ CLEAR_T; \
+ io_write_byte_8(0x0003,tmp)
+
+/* 6280 ********************************************************
+ * STA Store accumulator
+ ***************************************************************/
+#define STA \
+ CLEAR_T; \
+ tmp = A
+
+/* 6280 ********************************************************
+ * STX Store index X
+ ***************************************************************/
+#define STX \
+ CLEAR_T; \
+ tmp = X
+
+/* 6280 ********************************************************
+ * STY Store index Y
+ ***************************************************************/
+#define STY \
+ CLEAR_T; \
+ tmp = Y
+
+/* 6280 ********************************************************
+ * STZ Store zero
+ ***************************************************************/
+#define STZ \
+ CLEAR_T; \
+ tmp = 0
+
+/* H6280 *******************************************************
+ * SXY Swap index X and index Y
+ ***************************************************************/
+#define SXY \
+ CLEAR_T; \
+ tmp = X; \
+ X = Y; \
+ Y = tmp
+
+/* H6280 *******************************************************
+ * TAI Transfer Alternate Increment
+ ***************************************************************/
+#define TAI \
+ CLEAR_T; \
+ from=RDMEMW(PCW); \
+ to =RDMEMW(PCW+2); \
+ length=RDMEMW(PCW+4); \
+ PCW+=6; \
+ alternate=0; \
+ if (!length) length = 0x10000; \
+ H6280_CYCLES( ((6 * length) + 17) ); \
+ while ((length--) != 0) { \
+ WRMEM(to,RDMEM(from+alternate)); \
+ to++; \
+ alternate ^= 1; \
+ }
+
+/* H6280 *******************************************************
+ * TAM Transfer accumulator to memory mapper register(s)
+ ***************************************************************/
+#define TAM \
+ CLEAR_T; \
+ if (tmp&0x01) h6280.mmr[0] = A; \
+ if (tmp&0x02) h6280.mmr[1] = A; \
+ if (tmp&0x04) h6280.mmr[2] = A; \
+ if (tmp&0x08) h6280.mmr[3] = A; \
+ if (tmp&0x10) h6280.mmr[4] = A; \
+ if (tmp&0x20) h6280.mmr[5] = A; \
+ if (tmp&0x40) h6280.mmr[6] = A; \
+ if (tmp&0x80) h6280.mmr[7] = A; \
+ CHANGE_PC
+
+/* 6280 ********************************************************
+ * TAX Transfer accumulator to index X
+ ***************************************************************/
+#define TAX \
+ CLEAR_T; \
+ X = A; \
+ SET_NZ(X)
+
+/* 6280 ********************************************************
+ * TAY Transfer accumulator to index Y
+ ***************************************************************/
+#define TAY \
+ CLEAR_T; \
+ Y = A; \
+ SET_NZ(Y)
+
+/* 6280 ********************************************************
+ * TDD Transfer Decrement Decrement
+ ***************************************************************/
+#define TDD \
+ CLEAR_T; \
+ from=RDMEMW(PCW); \
+ to =RDMEMW(PCW+2); \
+ length=RDMEMW(PCW+4); \
+ PCW+=6; \
+ if (!length) length = 0x10000; \
+ H6280_CYCLES( ((6 * length) + 17) ); \
+ while ((length--) != 0) { \
+ WRMEM(to,RDMEM(from)); \
+ to--; \
+ from--; \
+ }
+
+/* 6280 ********************************************************
+ * TIA Transfer Increment Alternate
+ ***************************************************************/
+#define TIA \
+ CLEAR_T; \
+ from=RDMEMW(PCW); \
+ to =RDMEMW(PCW+2); \
+ length=RDMEMW(PCW+4); \
+ PCW+=6; \
+ alternate=0; \
+ if (!length) length = 0x10000; \
+ H6280_CYCLES( ((6 * length) + 17) ); \
+ while ((length--) != 0) { \
+ WRMEM(to+alternate,RDMEM(from)); \
+ from++; \
+ alternate ^= 1; \
+ }
+
+/* 6280 ********************************************************
+ * TII Transfer Increment Increment
+ ***************************************************************/
+#define TII \
+ CLEAR_T; \
+ from=RDMEMW(PCW); \
+ to =RDMEMW(PCW+2); \
+ length=RDMEMW(PCW+4); \
+ PCW+=6; \
+ if (!length) length = 0x10000; \
+ H6280_CYCLES( ((6 * length) + 17) ); \
+ while ((length--) != 0) { \
+ WRMEM(to,RDMEM(from)); \
+ to++; \
+ from++; \
+ }
+
+/* 6280 ********************************************************
+ * TIN Transfer block, source increments every loop
+ ***************************************************************/
+#define TIN \
+ CLEAR_T; \
+ from=RDMEMW(PCW); \
+ to =RDMEMW(PCW+2); \
+ length=RDMEMW(PCW+4); \
+ PCW+=6; \
+ if (!length) length = 0x10000; \
+ H6280_CYCLES( ((6 * length) + 17) ); \
+ while ((length--) != 0) { \
+ WRMEM(to,RDMEM(from)); \
+ from++; \
+ }
+
+/* 6280 ********************************************************
+ * TMA Transfer memory mapper register(s) to accumulator
+ * the highest bit set in tmp is the one that counts
+ ***************************************************************/
+#define TMA \
+ CLEAR_T; \
+ if (tmp&0x01) A = h6280.mmr[0]; \
+ if (tmp&0x02) A = h6280.mmr[1]; \
+ if (tmp&0x04) A = h6280.mmr[2]; \
+ if (tmp&0x08) A = h6280.mmr[3]; \
+ if (tmp&0x10) A = h6280.mmr[4]; \
+ if (tmp&0x20) A = h6280.mmr[5]; \
+ if (tmp&0x40) A = h6280.mmr[6]; \
+ if (tmp&0x80) A = h6280.mmr[7]
+
+/* 6280 ********************************************************
+ * TRB Test and reset bits
+ ***************************************************************/
+#define TRB \
+ CLEAR_T; \
+ P = (P & ~(_fN|_fV|_fT|_fZ)) \
+ | ((tmp&0x80) ? _fN:0) \
+ | ((tmp&0x40) ? _fV:0) \
+ | ((tmp&~A) ? 0:_fZ); \
+ tmp &= ~A
+
+/* 6280 ********************************************************
+ * TSB Test and set bits
+ ***************************************************************/
+#define TSB \
+ CLEAR_T; \
+ P = (P & ~(_fN|_fV|_fT|_fZ)) \
+ | ((tmp&0x80) ? _fN:0) \
+ | ((tmp&0x40) ? _fV:0) \
+ | ((tmp|A) ? 0:_fZ); \
+ tmp |= A
+
+/* 6280 ********************************************************
+ * TSX Transfer stack LSB to index X
+ ***************************************************************/
+#define TSX \
+ CLEAR_T; \
+ X = S; \
+ SET_NZ(X)
+
+/* 6280 ********************************************************
+ * TST
+ ***************************************************************/
+#define TST \
+ P = (P & ~(_fN|_fV|_fT|_fZ)) \
+ | ((tmp&0x80) ? _fN:0) \
+ | ((tmp&0x40) ? _fV:0) \
+ | ((tmp&tmp2) ? 0:_fZ)
+
+/* 6280 ********************************************************
+ * TXA Transfer index X to accumulator
+ ***************************************************************/
+#define TXA \
+ CLEAR_T; \
+ A = X; \
+ SET_NZ(A)
+
+/* 6280 ********************************************************
+ * TXS Transfer index X to stack LSB
+ * no flags changed (sic!)
+ ***************************************************************/
+#define TXS \
+ CLEAR_T; \
+ S = X
+
+/* 6280 ********************************************************
+ * TYA Transfer index Y to accumulator
+ ***************************************************************/
+#define TYA \
+ CLEAR_T; \
+ A = Y; \
+ SET_NZ(A)
+
+/* 6280 ********************************************************
+ * CSH Set CPU in high speed mode
+ ***************************************************************/
+#define CSH \
+ h6280.clocks_per_cycle = 1;
+
+/* 6280 ********************************************************
+ * CSL Set CPU in low speed mode
+ ***************************************************************/
+#define CSL \
+ h6280.clocks_per_cycle = 3;
+
diff --git a/src/emu/cpu/h6280/tblh6280.c b/src/emu/cpu/h6280/tblh6280.c
new file mode 100644
index 00000000000..1cd317e5a03
--- /dev/null
+++ b/src/emu/cpu/h6280/tblh6280.c
@@ -0,0 +1,344 @@
+/*****************************************************************************
+
+ tblh6280.c
+
+ Copyright (c) 1999 Bryan McPhail, mish@tendril.co.uk
+
+ This source code is based (with permission!) on the 6502 emulator by
+ Juergen Buchmueller. It is released as part of the Mame emulator project.
+ Let me know if you intend to use this code in any other project.
+
+******************************************************************************/
+
+#undef OP
+#define OP(nnn) INLINE void h6280##nnn(void)
+
+/*****************************************************************************
+ *****************************************************************************
+ *
+ * Hu6280 opcodes
+ *
+ *****************************************************************************
+ * op temp cycles rdmem opc wrmem ******************/
+OP(_000) { H6280_CYCLES(8); BRK; } // 8 BRK
+OP(_020) { H6280_CYCLES(7); EA_ABS; JSR; } // 7 JSR ABS
+OP(_040) { H6280_CYCLES(7); RTI; } // 7 RTI
+OP(_060) { H6280_CYCLES(7); RTS; } // 7 RTS
+OP(_080) { int tmp; BRA(1); } // 4 BRA REL
+OP(_0a0) { int tmp; H6280_CYCLES(2); RD_IMM; LDY; } // 2 LDY IMM
+OP(_0c0) { int tmp; H6280_CYCLES(2); RD_IMM; CPY; } // 2 CPY IMM
+OP(_0e0) { int tmp; H6280_CYCLES(2); RD_IMM; CPX; } // 2 CPX IMM
+
+OP(_010) { int tmp; BPL; } // 2/4 BPL REL
+OP(_030) { int tmp; BMI; } // 2/4 BMI REL
+OP(_050) { int tmp; BVC; } // 2/4 BVC REL
+OP(_070) { int tmp; BVS; } // 2/4 BVS REL
+OP(_090) { int tmp; BCC; } // 2/4 BCC REL
+OP(_0b0) { int tmp; BCS; } // 2/4 BCS REL
+OP(_0d0) { int tmp; BNE; } // 2/4 BNE REL
+OP(_0f0) { int tmp; BEQ; } // 2/4 BEQ REL
+
+OP(_001) { int tmp; H6280_CYCLES(7); RD_IDX; ORA; } // 7 ORA IDX
+OP(_021) { int tmp; H6280_CYCLES(7); RD_IDX; AND; } // 7 AND IDX
+OP(_041) { int tmp; H6280_CYCLES(7); RD_IDX; EOR; } // 7 EOR IDX
+OP(_061) { int tmp; H6280_CYCLES(7); RD_IDX; ADC; } // 7 ADC IDX
+OP(_081) { int tmp; H6280_CYCLES(7); STA; WR_IDX; } // 7 STA IDX
+OP(_0a1) { int tmp; H6280_CYCLES(7); RD_IDX; LDA; } // 7 LDA IDX
+OP(_0c1) { int tmp; H6280_CYCLES(7); RD_IDX; CMP; } // 7 CMP IDX
+OP(_0e1) { int tmp; H6280_CYCLES(7); RD_IDX; SBC; } // 7 SBC IDX
+
+OP(_011) { int tmp; H6280_CYCLES(7); RD_IDY; ORA; } // 7 ORA IDY
+OP(_031) { int tmp; H6280_CYCLES(7); RD_IDY; AND; } // 7 AND IDY
+OP(_051) { int tmp; H6280_CYCLES(7); RD_IDY; EOR; } // 7 EOR IDY
+OP(_071) { int tmp; H6280_CYCLES(7); RD_IDY; ADC; } // 7 ADC AZP
+OP(_091) { int tmp; H6280_CYCLES(7); STA; WR_IDY; } // 7 STA IDY
+OP(_0b1) { int tmp; H6280_CYCLES(7); RD_IDY; LDA; } // 7 LDA IDY
+OP(_0d1) { int tmp; H6280_CYCLES(7); RD_IDY; CMP; } // 7 CMP IDY
+OP(_0f1) { int tmp; H6280_CYCLES(7); RD_IDY; SBC; } // 7 SBC IDY
+
+OP(_002) { int tmp; H6280_CYCLES(3); SXY; } // 3 SXY
+OP(_022) { int tmp; H6280_CYCLES(3); SAX; } // 3 SAX
+OP(_042) { int tmp; H6280_CYCLES(3); SAY; } // 3 SAY
+OP(_062) { H6280_CYCLES(2); CLA; } // 2 CLA
+OP(_082) { H6280_CYCLES(2); CLX; } // 2 CLX
+OP(_0a2) { int tmp; H6280_CYCLES(2); RD_IMM; LDX; } // 2 LDX IMM
+OP(_0c2) { H6280_CYCLES(2); CLY; } // 2 CLY
+OP(_0e2) { H6280_CYCLES(2); NOP; } // 2 NOP
+
+OP(_012) { int tmp; H6280_CYCLES(7); RD_ZPI; ORA; } // 7 ORA ZPI
+OP(_032) { int tmp; H6280_CYCLES(7); RD_ZPI; AND; } // 7 AND ZPI
+OP(_052) { int tmp; H6280_CYCLES(7); RD_ZPI; EOR; } // 7 EOR ZPI
+OP(_072) { int tmp; H6280_CYCLES(7); RD_ZPI; ADC; } // 7 ADC ZPI
+OP(_092) { int tmp; H6280_CYCLES(7); STA; WR_ZPI; } // 7 STA ZPI
+OP(_0b2) { int tmp; H6280_CYCLES(7); RD_ZPI; LDA; } // 7 LDA ZPI
+OP(_0d2) { int tmp; H6280_CYCLES(7); RD_ZPI; CMP; } // 7 CMP ZPI
+OP(_0f2) { int tmp; H6280_CYCLES(7); RD_ZPI; SBC; } // 7 SBC ZPI
+
+OP(_003) { int tmp; H6280_CYCLES(5); RD_IMM; ST0; } // 4 + 1 penalty cycle ST0 IMM
+OP(_023) { int tmp; H6280_CYCLES(5); RD_IMM; ST2; } // 4 + 1 penalty cycle ST2 IMM
+OP(_043) { int tmp; H6280_CYCLES(4); RD_IMM; TMA; } // 4 TMA
+OP(_063) { H6280_CYCLES(4); NOP; } // 2 NOP
+OP(_083) { int tmp,tmp2; H6280_CYCLES(7); RD_IMM2; RD_ZPG; TST; } // 7 TST IMM,ZPG
+OP(_0a3) { int tmp,tmp2; H6280_CYCLES(7); RD_IMM2; RD_ZPX; TST; } // 7 TST IMM,ZPX
+OP(_0c3) { int to,from,length; TDD; } // 6*l+17 TDD XFER
+OP(_0e3) { int to,from,length,alternate; TIA; } // 6*l+17 TIA XFER
+
+OP(_013) { int tmp; H6280_CYCLES(5); RD_IMM; ST1; } // 4 + 1 penalty cycle ST1
+OP(_033) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_053) { int tmp; H6280_CYCLES(5); RD_IMM; TAM; } // 5 TAM IMM
+OP(_073) { int to,from,length; TII; } // 6*l+17 TII XFER
+OP(_093) { int tmp,tmp2; H6280_CYCLES(8); RD_IMM2; RD_ABS; TST; } // 8 TST IMM,ABS
+OP(_0b3) { int tmp,tmp2; H6280_CYCLES(8); RD_IMM2; RD_ABX; TST; } // 8 TST IMM,ABX
+OP(_0d3) { int to,from,length; TIN; } // 6*l+17 TIN XFER
+OP(_0f3) { int to,from,length,alternate; TAI; } // 6*l+17 TAI XFER
+
+OP(_004) { int tmp; H6280_CYCLES(6); RD_ZPG; TSB; WB_EAZ; } // 6 TSB ZPG
+OP(_024) { int tmp; H6280_CYCLES(4); RD_ZPG; BIT; } // 4 BIT ZPG
+OP(_044) { int tmp; BSR; } // 8 BSR REL
+OP(_064) { int tmp; H6280_CYCLES(4); STZ; WR_ZPG; } // 4 STZ ZPG
+OP(_084) { int tmp; H6280_CYCLES(4); STY; WR_ZPG; } // 4 STY ZPG
+OP(_0a4) { int tmp; H6280_CYCLES(4); RD_ZPG; LDY; } // 4 LDY ZPG
+OP(_0c4) { int tmp; H6280_CYCLES(4); RD_ZPG; CPY; } // 4 CPY ZPG
+OP(_0e4) { int tmp; H6280_CYCLES(4); RD_ZPG; CPX; } // 4 CPX ZPG
+
+OP(_014) { int tmp; H6280_CYCLES(6); RD_ZPG; TRB; WB_EAZ; } // 6 TRB ZPG
+OP(_034) { int tmp; H6280_CYCLES(4); RD_ZPX; BIT; } // 4 BIT ZPX
+OP(_054) { H6280_CYCLES(3); CSL; } // 3 CSL
+OP(_074) { int tmp; H6280_CYCLES(4); STZ; WR_ZPX; } // 4 STZ ZPX
+OP(_094) { int tmp; H6280_CYCLES(4); STY; WR_ZPX; } // 4 STY ZPX
+OP(_0b4) { int tmp; H6280_CYCLES(4); RD_ZPX; LDY; } // 4 LDY ZPX
+OP(_0d4) { H6280_CYCLES(3); CSH; } // 3 CSH
+OP(_0f4) { H6280_CYCLES(2); SET; } // 2 SET
+
+OP(_005) { int tmp; H6280_CYCLES(4); RD_ZPG; ORA; } // 4 ORA ZPG
+OP(_025) { int tmp; H6280_CYCLES(4); RD_ZPG; AND; } // 4 AND ZPG
+OP(_045) { int tmp; H6280_CYCLES(4); RD_ZPG; EOR; } // 4 EOR ZPG
+OP(_065) { int tmp; H6280_CYCLES(4); RD_ZPG; ADC; } // 4 ADC ZPG
+OP(_085) { int tmp; H6280_CYCLES(4); STA; WR_ZPG; } // 4 STA ZPG
+OP(_0a5) { int tmp; H6280_CYCLES(4); RD_ZPG; LDA; } // 4 LDA ZPG
+OP(_0c5) { int tmp; H6280_CYCLES(4); RD_ZPG; CMP; } // 4 CMP ZPG
+OP(_0e5) { int tmp; H6280_CYCLES(4); RD_ZPG; SBC; } // 4 SBC ZPG
+
+OP(_015) { int tmp; H6280_CYCLES(4); RD_ZPX; ORA; } // 4 ORA ZPX
+OP(_035) { int tmp; H6280_CYCLES(4); RD_ZPX; AND; } // 4 AND ZPX
+OP(_055) { int tmp; H6280_CYCLES(4); RD_ZPX; EOR; } // 4 EOR ZPX
+OP(_075) { int tmp; H6280_CYCLES(4); RD_ZPX; ADC; } // 4 ADC ZPX
+OP(_095) { int tmp; H6280_CYCLES(4); STA; WR_ZPX; } // 4 STA ZPX
+OP(_0b5) { int tmp; H6280_CYCLES(4); RD_ZPX; LDA; } // 4 LDA ZPX
+OP(_0d5) { int tmp; H6280_CYCLES(4); RD_ZPX; CMP; } // 4 CMP ZPX
+OP(_0f5) { int tmp; H6280_CYCLES(4); RD_ZPX; SBC; } // 4 SBC ZPX
+
+OP(_006) { int tmp; H6280_CYCLES(6); RD_ZPG; ASL; WB_EAZ; } // 6 ASL ZPG
+OP(_026) { int tmp; H6280_CYCLES(6); RD_ZPG; ROL; WB_EAZ; } // 6 ROL ZPG
+OP(_046) { int tmp; H6280_CYCLES(6); RD_ZPG; LSR; WB_EAZ; } // 6 LSR ZPG
+OP(_066) { int tmp; H6280_CYCLES(6); RD_ZPG; ROR; WB_EAZ; } // 6 ROR ZPG
+OP(_086) { int tmp; H6280_CYCLES(4); STX; WR_ZPG; } // 4 STX ZPG
+OP(_0a6) { int tmp; H6280_CYCLES(4); RD_ZPG; LDX; } // 4 LDX ZPG
+OP(_0c6) { int tmp; H6280_CYCLES(6); RD_ZPG; DEC; WB_EAZ; } // 6 DEC ZPG
+OP(_0e6) { int tmp; H6280_CYCLES(6); RD_ZPG; INC; WB_EAZ; } // 6 INC ZPG
+
+OP(_016) { int tmp; H6280_CYCLES(6); RD_ZPX; ASL; WB_EAZ } // 6 ASL ZPX
+OP(_036) { int tmp; H6280_CYCLES(6); RD_ZPX; ROL; WB_EAZ } // 6 ROL ZPX
+OP(_056) { int tmp; H6280_CYCLES(6); RD_ZPX; LSR; WB_EAZ } // 6 LSR ZPX
+OP(_076) { int tmp; H6280_CYCLES(6); RD_ZPX; ROR; WB_EAZ } // 6 ROR ZPX
+OP(_096) { int tmp; H6280_CYCLES(4); STX; WR_ZPY; } // 4 STX ZPY
+OP(_0b6) { int tmp; H6280_CYCLES(4); RD_ZPY; LDX; } // 4 LDX ZPY
+OP(_0d6) { int tmp; H6280_CYCLES(6); RD_ZPX; DEC; WB_EAZ; } // 6 DEC ZPX
+OP(_0f6) { int tmp; H6280_CYCLES(6); RD_ZPX; INC; WB_EAZ; } // 6 INC ZPX
+
+OP(_007) { int tmp; H6280_CYCLES(7); RD_ZPG; RMB(0);WB_EAZ;} // 7 RMB0 ZPG
+OP(_027) { int tmp; H6280_CYCLES(7); RD_ZPG; RMB(2);WB_EAZ;} // 7 RMB2 ZPG
+OP(_047) { int tmp; H6280_CYCLES(7); RD_ZPG; RMB(4);WB_EAZ;} // 7 RMB4 ZPG
+OP(_067) { int tmp; H6280_CYCLES(7); RD_ZPG; RMB(6);WB_EAZ;} // 7 RMB6 ZPG
+OP(_087) { int tmp; H6280_CYCLES(7); RD_ZPG; SMB(0);WB_EAZ;} // 7 SMB0 ZPG
+OP(_0a7) { int tmp; H6280_CYCLES(7); RD_ZPG; SMB(2);WB_EAZ;} // 7 SMB2 ZPG
+OP(_0c7) { int tmp; H6280_CYCLES(7); RD_ZPG; SMB(4);WB_EAZ;} // 7 SMB4 ZPG
+OP(_0e7) { int tmp; H6280_CYCLES(7); RD_ZPG; SMB(6);WB_EAZ;} // 7 SMB6 ZPG
+
+OP(_017) { int tmp; H6280_CYCLES(7); RD_ZPG; RMB(1);WB_EAZ;} // 7 RMB1 ZPG
+OP(_037) { int tmp; H6280_CYCLES(7); RD_ZPG; RMB(3);WB_EAZ;} // 7 RMB3 ZPG
+OP(_057) { int tmp; H6280_CYCLES(7); RD_ZPG; RMB(5);WB_EAZ;} // 7 RMB5 ZPG
+OP(_077) { int tmp; H6280_CYCLES(7); RD_ZPG; RMB(7);WB_EAZ;} // 7 RMB7 ZPG
+OP(_097) { int tmp; H6280_CYCLES(7); RD_ZPG; SMB(1);WB_EAZ;} // 7 SMB1 ZPG
+OP(_0b7) { int tmp; H6280_CYCLES(7); RD_ZPG; SMB(3);WB_EAZ;} // 7 SMB3 ZPG
+OP(_0d7) { int tmp; H6280_CYCLES(7); RD_ZPG; SMB(5);WB_EAZ;} // 7 SMB5 ZPG
+OP(_0f7) { int tmp; H6280_CYCLES(7); RD_ZPG; SMB(7);WB_EAZ;} // 7 SMB7 ZPG
+
+OP(_008) { H6280_CYCLES(3); PHP; } // 3 PHP
+OP(_028) { H6280_CYCLES(4); PLP; } // 4 PLP
+OP(_048) { H6280_CYCLES(3); PHA; } // 3 PHA
+OP(_068) { H6280_CYCLES(4); PLA; } // 4 PLA
+OP(_088) { H6280_CYCLES(2); DEY; } // 2 DEY
+OP(_0a8) { H6280_CYCLES(2); TAY; } // 2 TAY
+OP(_0c8) { H6280_CYCLES(2); INY; } // 2 INY
+OP(_0e8) { H6280_CYCLES(2); INX; } // 2 INX
+
+OP(_018) { H6280_CYCLES(2); CLC; } // 2 CLC
+OP(_038) { H6280_CYCLES(2); SEC; } // 2 SEC
+OP(_058) { H6280_CYCLES(2); CLI; } // 2 CLI
+OP(_078) { H6280_CYCLES(2); SEI; } // 2 SEI
+OP(_098) { H6280_CYCLES(2); TYA; } // 2 TYA
+OP(_0b8) { H6280_CYCLES(2); CLV; } // 2 CLV
+OP(_0d8) { H6280_CYCLES(2); CLD; } // 2 CLD
+OP(_0f8) { H6280_CYCLES(2); SED; } // 2 SED
+
+OP(_009) { int tmp; H6280_CYCLES(2); RD_IMM; ORA; } // 2 ORA IMM
+OP(_029) { int tmp; H6280_CYCLES(2); RD_IMM; AND; } // 2 AND IMM
+OP(_049) { int tmp; H6280_CYCLES(2); RD_IMM; EOR; } // 2 EOR IMM
+OP(_069) { int tmp; H6280_CYCLES(2); RD_IMM; ADC; } // 2 ADC IMM
+OP(_089) { int tmp; H6280_CYCLES(2); RD_IMM; BIT; } // 2 BIT IMM
+OP(_0a9) { int tmp; H6280_CYCLES(2); RD_IMM; LDA; } // 2 LDA IMM
+OP(_0c9) { int tmp; H6280_CYCLES(2); RD_IMM; CMP; } // 2 CMP IMM
+OP(_0e9) { int tmp; H6280_CYCLES(2); RD_IMM; SBC; } // 2 SBC IMM
+
+OP(_019) { int tmp; H6280_CYCLES(5); RD_ABY; ORA; } // 5 ORA ABY
+OP(_039) { int tmp; H6280_CYCLES(5); RD_ABY; AND; } // 5 AND ABY
+OP(_059) { int tmp; H6280_CYCLES(5); RD_ABY; EOR; } // 5 EOR ABY
+OP(_079) { int tmp; H6280_CYCLES(5); RD_ABY; ADC; } // 5 ADC ABY
+OP(_099) { int tmp; H6280_CYCLES(5); STA; WR_ABY; } // 5 STA ABY
+OP(_0b9) { int tmp; H6280_CYCLES(5); RD_ABY; LDA; } // 5 LDA ABY
+OP(_0d9) { int tmp; H6280_CYCLES(5); RD_ABY; CMP; } // 5 CMP ABY
+OP(_0f9) { int tmp; H6280_CYCLES(5); RD_ABY; SBC; } // 5 SBC ABY
+
+OP(_00a) { int tmp; H6280_CYCLES(2); RD_ACC; ASL; WB_ACC; } // 2 ASL A
+OP(_02a) { int tmp; H6280_CYCLES(2); RD_ACC; ROL; WB_ACC; } // 2 ROL A
+OP(_04a) { int tmp; H6280_CYCLES(2); RD_ACC; LSR; WB_ACC; } // 2 LSR A
+OP(_06a) { int tmp; H6280_CYCLES(2); RD_ACC; ROR; WB_ACC; } // 2 ROR A
+OP(_08a) { H6280_CYCLES(2); TXA; } // 2 TXA
+OP(_0aa) { H6280_CYCLES(2); TAX; } // 2 TAX
+OP(_0ca) { H6280_CYCLES(2); DEX; } // 2 DEX
+OP(_0ea) { H6280_CYCLES(2); NOP; } // 2 NOP
+
+OP(_01a) { H6280_CYCLES(2); INA; } // 2 INC A
+OP(_03a) { H6280_CYCLES(2); DEA; } // 2 DEC A
+OP(_05a) { H6280_CYCLES(3); PHY; } // 3 PHY
+OP(_07a) { H6280_CYCLES(4); PLY; } // 4 PLY
+OP(_09a) { H6280_CYCLES(2); TXS; } // 2 TXS
+OP(_0ba) { H6280_CYCLES(2); TSX; } // 2 TSX
+OP(_0da) { H6280_CYCLES(3); PHX; } // 3 PHX
+OP(_0fa) { H6280_CYCLES(4); PLX; } // 4 PLX
+
+OP(_00b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_02b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_04b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_06b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_08b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_0ab) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_0cb) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_0eb) { H6280_CYCLES(2); NOP; } // 2 NOP
+
+OP(_01b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_03b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_05b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_07b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_09b) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_0bb) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_0db) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_0fb) { H6280_CYCLES(2); NOP; } // 2 NOP
+
+OP(_00c) { int tmp; H6280_CYCLES(7); RD_ABS; TSB; WB_EA; } // 7 TSB ABS
+OP(_02c) { int tmp; H6280_CYCLES(5); RD_ABS; BIT; } // 5 BIT ABS
+OP(_04c) { H6280_CYCLES(4); EA_ABS; JMP; } // 4 JMP ABS
+OP(_06c) { int tmp; H6280_CYCLES(7); EA_IND; JMP; } // 7 JMP IND
+OP(_08c) { int tmp; H6280_CYCLES(5); STY; WR_ABS; } // 5 STY ABS
+OP(_0ac) { int tmp; H6280_CYCLES(5); RD_ABS; LDY; } // 5 LDY ABS
+OP(_0cc) { int tmp; H6280_CYCLES(5); RD_ABS; CPY; } // 5 CPY ABS
+OP(_0ec) { int tmp; H6280_CYCLES(5); RD_ABS; CPX; } // 5 CPX ABS
+
+OP(_01c) { int tmp; H6280_CYCLES(7); RD_ABS; TRB; WB_EA; } // 7 TRB ABS
+OP(_03c) { int tmp; H6280_CYCLES(5); RD_ABX; BIT; } // 5 BIT ABX
+OP(_05c) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_07c) { int tmp; H6280_CYCLES(7); EA_IAX; JMP; } // 7 JMP IAX
+OP(_09c) { int tmp; H6280_CYCLES(5); STZ; WR_ABS; } // 5 STZ ABS
+OP(_0bc) { int tmp; H6280_CYCLES(5); RD_ABX; LDY; } // 5 LDY ABX
+OP(_0dc) { H6280_CYCLES(2); NOP; } // 2 NOP
+OP(_0fc) { H6280_CYCLES(2); NOP; } // 2 NOP
+
+OP(_00d) { int tmp; H6280_CYCLES(5); RD_ABS; ORA; } // 5 ORA ABS
+OP(_02d) { int tmp; H6280_CYCLES(5); RD_ABS; AND; } // 5 AND ABS
+OP(_04d) { int tmp; H6280_CYCLES(5); RD_ABS; EOR; } // 5 EOR ABS
+OP(_06d) { int tmp; H6280_CYCLES(5); RD_ABS; ADC; } // 5 ADC ABS
+OP(_08d) { int tmp; H6280_CYCLES(5); STA; WR_ABS; } // 5 STA ABS
+OP(_0ad) { int tmp; H6280_CYCLES(5); RD_ABS; LDA; } // 5 LDA ABS
+OP(_0cd) { int tmp; H6280_CYCLES(5); RD_ABS; CMP; } // 5 CMP ABS
+OP(_0ed) { int tmp; H6280_CYCLES(5); RD_ABS; SBC; } // 5 SBC ABS
+
+OP(_01d) { int tmp; H6280_CYCLES(5); RD_ABX; ORA; } // 5 ORA ABX
+OP(_03d) { int tmp; H6280_CYCLES(5); RD_ABX; AND; } // 5 AND ABX
+OP(_05d) { int tmp; H6280_CYCLES(5); RD_ABX; EOR; } // 5 EOR ABX
+OP(_07d) { int tmp; H6280_CYCLES(5); RD_ABX; ADC; } // 5 ADC ABX
+OP(_09d) { int tmp; H6280_CYCLES(5); STA; WR_ABX; } // 5 STA ABX
+OP(_0bd) { int tmp; H6280_CYCLES(5); RD_ABX; LDA; } // 5 LDA ABX
+OP(_0dd) { int tmp; H6280_CYCLES(5); RD_ABX; CMP; } // 5 CMP ABX
+OP(_0fd) { int tmp; H6280_CYCLES(5); RD_ABX; SBC; } // 5 SBC ABX
+
+OP(_00e) { int tmp; H6280_CYCLES(7); RD_ABS; ASL; WB_EA; } // 7 ASL ABS
+OP(_02e) { int tmp; H6280_CYCLES(7); RD_ABS; ROL; WB_EA; } // 7 ROL ABS
+OP(_04e) { int tmp; H6280_CYCLES(7); RD_ABS; LSR; WB_EA; } // 7 LSR ABS
+OP(_06e) { int tmp; H6280_CYCLES(7); RD_ABS; ROR; WB_EA; } // 7 ROR ABS
+OP(_08e) { int tmp; H6280_CYCLES(5); STX; WR_ABS; } // 5 STX ABS
+OP(_0ae) { int tmp; H6280_CYCLES(5); RD_ABS; LDX; } // 5 LDX ABS
+OP(_0ce) { int tmp; H6280_CYCLES(7); RD_ABS; DEC; WB_EA; } // 7 DEC ABS
+OP(_0ee) { int tmp; H6280_CYCLES(7); RD_ABS; INC; WB_EA; } // 7 INC ABS
+
+OP(_01e) { int tmp; H6280_CYCLES(7); RD_ABX; ASL; WB_EA; } // 7 ASL ABX
+OP(_03e) { int tmp; H6280_CYCLES(7); RD_ABX; ROL; WB_EA; } // 7 ROL ABX
+OP(_05e) { int tmp; H6280_CYCLES(7); RD_ABX; LSR; WB_EA; } // 7 LSR ABX
+OP(_07e) { int tmp; H6280_CYCLES(7); RD_ABX; ROR; WB_EA; } // 7 ROR ABX
+OP(_09e) { int tmp; H6280_CYCLES(5); STZ; WR_ABX; } // 5 STZ ABX
+OP(_0be) { int tmp; H6280_CYCLES(5); RD_ABY; LDX; } // 5 LDX ABY
+OP(_0de) { int tmp; H6280_CYCLES(7); RD_ABX; DEC; WB_EA; } // 7 DEC ABX
+OP(_0fe) { int tmp; H6280_CYCLES(7); RD_ABX; INC; WB_EA; } // 7 INC ABX
+
+OP(_00f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBR(0); } // 6/8 BBR0 ZPG,REL
+OP(_02f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBR(2); } // 6/8 BBR2 ZPG,REL
+OP(_04f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBR(4); } // 6/8 BBR4 ZPG,REL
+OP(_06f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBR(6); } // 6/8 BBR6 ZPG,REL
+OP(_08f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBS(0); } // 6/8 BBS0 ZPG,REL
+OP(_0af) { int tmp; H6280_CYCLES(4); RD_ZPG; BBS(2); } // 6/8 BBS2 ZPG,REL
+OP(_0cf) { int tmp; H6280_CYCLES(4); RD_ZPG; BBS(4); } // 6/8 BBS4 ZPG,REL
+OP(_0ef) { int tmp; H6280_CYCLES(4); RD_ZPG; BBS(6); } // 6/8 BBS6 ZPG,REL
+
+OP(_01f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBR(1); } // 6/8 BBR1 ZPG,REL
+OP(_03f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBR(3); } // 6/8 BBR3 ZPG,REL
+OP(_05f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBR(5); } // 6/8 BBR5 ZPG,REL
+OP(_07f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBR(7); } // 6/8 BBR7 ZPG,REL
+OP(_09f) { int tmp; H6280_CYCLES(4); RD_ZPG; BBS(1); } // 6/8 BBS1 ZPG,REL
+OP(_0bf) { int tmp; H6280_CYCLES(4); RD_ZPG; BBS(3); } // 6/8 BBS3 ZPG,REL
+OP(_0df) { int tmp; H6280_CYCLES(4); RD_ZPG; BBS(5); } // 6/8 BBS5 ZPG,REL
+OP(_0ff) { int tmp; H6280_CYCLES(4); RD_ZPG; BBS(7); } // 6/8 BBS7 ZPG,REL
+
+static void (*insnh6280[0x100])(void) = {
+ h6280_000,h6280_001,h6280_002,h6280_003,h6280_004,h6280_005,h6280_006,h6280_007,
+ h6280_008,h6280_009,h6280_00a,h6280_00b,h6280_00c,h6280_00d,h6280_00e,h6280_00f,
+ h6280_010,h6280_011,h6280_012,h6280_013,h6280_014,h6280_015,h6280_016,h6280_017,
+ h6280_018,h6280_019,h6280_01a,h6280_01b,h6280_01c,h6280_01d,h6280_01e,h6280_01f,
+ h6280_020,h6280_021,h6280_022,h6280_023,h6280_024,h6280_025,h6280_026,h6280_027,
+ h6280_028,h6280_029,h6280_02a,h6280_02b,h6280_02c,h6280_02d,h6280_02e,h6280_02f,
+ h6280_030,h6280_031,h6280_032,h6280_033,h6280_034,h6280_035,h6280_036,h6280_037,
+ h6280_038,h6280_039,h6280_03a,h6280_03b,h6280_03c,h6280_03d,h6280_03e,h6280_03f,
+ h6280_040,h6280_041,h6280_042,h6280_043,h6280_044,h6280_045,h6280_046,h6280_047,
+ h6280_048,h6280_049,h6280_04a,h6280_04b,h6280_04c,h6280_04d,h6280_04e,h6280_04f,
+ h6280_050,h6280_051,h6280_052,h6280_053,h6280_054,h6280_055,h6280_056,h6280_057,
+ h6280_058,h6280_059,h6280_05a,h6280_05b,h6280_05c,h6280_05d,h6280_05e,h6280_05f,
+ h6280_060,h6280_061,h6280_062,h6280_063,h6280_064,h6280_065,h6280_066,h6280_067,
+ h6280_068,h6280_069,h6280_06a,h6280_06b,h6280_06c,h6280_06d,h6280_06e,h6280_06f,
+ h6280_070,h6280_071,h6280_072,h6280_073,h6280_074,h6280_075,h6280_076,h6280_077,
+ h6280_078,h6280_079,h6280_07a,h6280_07b,h6280_07c,h6280_07d,h6280_07e,h6280_07f,
+ h6280_080,h6280_081,h6280_082,h6280_083,h6280_084,h6280_085,h6280_086,h6280_087,
+ h6280_088,h6280_089,h6280_08a,h6280_08b,h6280_08c,h6280_08d,h6280_08e,h6280_08f,
+ h6280_090,h6280_091,h6280_092,h6280_093,h6280_094,h6280_095,h6280_096,h6280_097,
+ h6280_098,h6280_099,h6280_09a,h6280_09b,h6280_09c,h6280_09d,h6280_09e,h6280_09f,
+ h6280_0a0,h6280_0a1,h6280_0a2,h6280_0a3,h6280_0a4,h6280_0a5,h6280_0a6,h6280_0a7,
+ h6280_0a8,h6280_0a9,h6280_0aa,h6280_0ab,h6280_0ac,h6280_0ad,h6280_0ae,h6280_0af,
+ h6280_0b0,h6280_0b1,h6280_0b2,h6280_0b3,h6280_0b4,h6280_0b5,h6280_0b6,h6280_0b7,
+ h6280_0b8,h6280_0b9,h6280_0ba,h6280_0bb,h6280_0bc,h6280_0bd,h6280_0be,h6280_0bf,
+ h6280_0c0,h6280_0c1,h6280_0c2,h6280_0c3,h6280_0c4,h6280_0c5,h6280_0c6,h6280_0c7,
+ h6280_0c8,h6280_0c9,h6280_0ca,h6280_0cb,h6280_0cc,h6280_0cd,h6280_0ce,h6280_0cf,
+ h6280_0d0,h6280_0d1,h6280_0d2,h6280_0d3,h6280_0d4,h6280_0d5,h6280_0d6,h6280_0d7,
+ h6280_0d8,h6280_0d9,h6280_0da,h6280_0db,h6280_0dc,h6280_0dd,h6280_0de,h6280_0df,
+ h6280_0e0,h6280_0e1,h6280_0e2,h6280_0e3,h6280_0e4,h6280_0e5,h6280_0e6,h6280_0e7,
+ h6280_0e8,h6280_0e9,h6280_0ea,h6280_0eb,h6280_0ec,h6280_0ed,h6280_0ee,h6280_0ef,
+ h6280_0f0,h6280_0f1,h6280_0f2,h6280_0f3,h6280_0f4,h6280_0f5,h6280_0f6,h6280_0f7,
+ h6280_0f8,h6280_0f9,h6280_0fa,h6280_0fb,h6280_0fc,h6280_0fd,h6280_0fe,h6280_0ff
+};
diff --git a/src/emu/cpu/h83002/h83002.c b/src/emu/cpu/h83002/h83002.c
new file mode 100644
index 00000000000..b0e01bfc0ff
--- /dev/null
+++ b/src/emu/cpu/h83002/h83002.c
@@ -0,0 +1,3863 @@
+/***************************************************************************
+
+ h83002.c: Hitachi H8/3002 microcontroller emulator
+
+ Original by The_Author & DynaChicken for the ZiNc emulator.
+
+ Rewrite for MAME by R. Belmont, including...
+ - Changed types to MAME standards
+ - Added MAME cpuintrf glue
+ - Put all per-CPU state in a struct
+ - Fixed ADD flag calcs
+ - Added support for all 8 flag bits
+ - Added cycle timing (probably not right yet)
+ - Fixed and optimized interrupt handling
+ - Optimized main execution loop
+ - Added new opcodes for ND-1 and System 23 BIOS programs
+ - Improved I/O and timer support
+ - Fixed major error in 7Cxx/7Dxx series bit opcodes where the wrong
+ instructions were being picked.
+
+ TS 20060412 Added exts.l, sub.l, divxs.w (buggy), jsr @reg, rotxl.l reg, mov.l @(adr, reg), reg
+
+ Note: The H8/3000 series is normally back-compatible to the 8-bit H8/300,
+ but the 3002 does not include "emulation mode" - it always runs in full
+ 16/32-bit ("advanced") mode. So this core is not suitable for general
+ H8/300 emulation.
+
+****************************************************************************/
+
+#include "debugger.h"
+#include "h83002.h"
+#include "h8priv.h"
+
+#define H8_SP (7)
+
+#define h8_mem_read8(x) program_read_byte_16be(x)
+#define h8_mem_read16(x) program_read_word_16be(x)
+#define h8_mem_write8(x, y) program_write_byte_16be(x, y)
+#define h8_mem_write16(x, y) program_write_word_16be(x, y)
+
+// timing macros
+// note: we assume a system 12 - type setup where external access is 3+1 states
+// timing will be off somewhat for other configurations.
+#define H8_IFETCH_TIMING(x) h8_cyccnt -= (x) * 4;
+#define H8_BRANCH_TIMING(x) h8_cyccnt -= (x) * 4;
+#define H8_STACK_TIMING(x) h8_cyccnt -= (x) * 4;
+#define H8_BYTE_TIMING(x, adr) if (address24 >= 0xffff10) h8_cyccnt -= (x) * 3; else h8_cyccnt -= (x) * 4;
+#define H8_WORD_TIMING(x, adr) if (address24 >= 0xffff10) h8_cyccnt -= (x) * 3; else h8_cyccnt -= (x) * 4;
+#define H8_IOP_TIMING(x) h8_cyccnt -= (x);
+
+extern UINT8 h8_register_read8(UINT32 address);
+extern void h8_register_write8(UINT32 address, UINT8 val);
+
+INLINE UINT32 h8_mem_read32(offs_t address)
+{
+ UINT32 result = program_read_word_16be(address) << 16;
+ return result | program_read_word_16be(address + 2);
+}
+
+INLINE void h8_mem_write32(offs_t address, UINT32 data)
+{
+ program_write_word_16be(address, data >> 16);
+ program_write_word_16be(address + 2, data);
+}
+
+
+h83002_state h8;
+
+static INT32 h8_cyccnt;
+
+static UINT32 udata32, address24;
+static INT32 sdata32;
+static UINT16 udata16, ext16;
+static INT16 sdata16;
+static UINT8 udata8;
+static INT8 sdata8;
+static UINT8 srcreg, dstreg;
+
+/* internal functions */
+
+static void h8_check_irqs(void);
+
+static void h8_group0(UINT16 opcode);
+static void h8_group1(UINT16 opcode);
+static void h8_group5(UINT16 opcode);
+static void h8_group6(UINT16 opcode);
+static void h8_group7(UINT16 opcode);
+
+static int h8_branch(UINT8 condition);
+
+static UINT8 h8_mov8(UINT8 src);
+static UINT16 h8_mov16(UINT16 src);
+static UINT32 h8_mov32(UINT32 src);
+
+static UINT8 h8_add8(UINT8 src, UINT8 dst);
+static UINT16 h8_add16(UINT16 src, UINT16 dst);
+static UINT32 h8_add32(UINT32 src, UINT32 dst);
+
+static UINT8 h8_sub8(UINT8 src, UINT8 dst);
+static UINT16 h8_sub16(UINT16 src, UINT16 dst);
+static UINT32 h8_sub32(UINT32 src, UINT32 dst);
+
+static UINT8 h8_addx8(UINT8 src, UINT8 dst);
+
+static void h8_cmp8(UINT8 src, UINT8 dst);
+static void h8_cmp16(UINT16 src, UINT16 dst);
+static void h8_cmp32(UINT32 src, UINT32 dst);
+static UINT8 h8_subx8(UINT8 src, UINT8 dst);
+
+static UINT8 h8_or8(UINT8 src, UINT8 dst);
+static UINT16 h8_or16(UINT16 src, UINT16 dst);
+
+static UINT8 h8_xor8(UINT8 src, UINT8 dst);
+static UINT16 h8_xor16(UINT16 src, UINT16 dst);
+static UINT32 h8_xor32(UINT32 src, UINT32 dst);
+
+static UINT8 h8_and8(UINT8 src, UINT8 dst);
+static UINT16 h8_and16(UINT16 src, UINT16 dst);
+static UINT32 h8_and32(UINT32 src, UINT32 dst);
+
+static INT8 h8_neg8(INT8 src);
+static INT16 h8_neg16(INT16 src);
+
+static UINT16 h8_divxu8 (UINT16 dst, UINT8 src);
+static UINT32 h8_divxu16(UINT32 dst, UINT16 src);
+
+static UINT8 h8_not8(UINT8 src);
+static UINT16 h8_not16(UINT16 src);
+
+static UINT8 h8_rotl8(UINT8 src);
+static UINT16 h8_rotl16(UINT16 src);
+
+static UINT8 h8_rotxl8(UINT8 src);
+static UINT16 h8_rotxl16(UINT16 src);
+static UINT32 h8_rotxl32(UINT32 src);
+
+static UINT8 h8_rotxr8(UINT8 src);
+static UINT16 h8_rotxr16(UINT16 src);
+
+static UINT8 h8_shll8(UINT8 src);
+static UINT16 h8_shll16(UINT16 src);
+static UINT32 h8_shll32(UINT32 src);
+
+static UINT8 h8_shlr8(UINT8 src);
+static UINT16 h8_shlr16(UINT16 src);
+static UINT32 h8_shlr32(UINT32 src);
+
+static INT8 h8_shal8(INT8 src);
+static INT16 h8_shal16(INT16 src);
+
+static INT8 h8_shar8(INT8 src);
+static INT16 h8_shar16(INT16 src);
+static INT32 h8_shar32(INT32 src);
+
+static UINT8 h8_dec8(UINT8 src);
+static UINT16 h8_dec16(UINT16 src);
+static UINT32 h8_dec32(UINT32 src);
+
+static UINT8 h8_inc8(UINT8 src);
+static UINT16 h8_inc16(UINT16 src);
+static UINT32 h8_inc32(UINT32 src);
+
+//static UINT8 h8_bnot8(UINT8 src, UINT8 dst);
+static UINT8 h8_bst8(UINT8 src, UINT8 dst);
+static UINT8 h8_bist8(UINT8 src, UINT8 dst);
+static UINT8 h8_bset8(UINT8 src, UINT8 dst);
+static UINT8 h8_bclr8(UINT8 src, UINT8 dst);
+static void h8_btst8(UINT8 src, UINT8 dst);
+static void h8_bld8(UINT8 src, UINT8 dst); // loads to carry
+static void h8_bor8(UINT8 src, UINT8 dst); // result in carry
+//static void h8_bxor8(UINT8 src, UINT8 dst);
+
+static INT32 h8_mulxs16(INT16 src, INT16 dst);
+static UINT32 h8_divxs16(INT16 src, INT32 dst);
+
+/* implementation */
+
+#ifdef MAME_DEBUG
+extern offs_t h8_disasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+void h8_3002_InterruptRequest(UINT8 source)
+{
+ if(source>31)
+ {
+ h8.h8_IRQrequestH |= (1<<(source-32));
+ }
+ else
+ {
+ h8.h8_IRQrequestL |= (1<<source);
+ }
+}
+
+
+static UINT8 h8_get_ccr(void)
+{
+ h8.ccr = 0;
+ if(h8.h8nflag)h8.ccr |= NFLAG;
+ if(h8.h8zflag)h8.ccr |= ZFLAG;
+ if(h8.h8vflag)h8.ccr |= VFLAG;
+ if(h8.h8cflag)h8.ccr |= CFLAG;
+ if(h8.h8uflag)h8.ccr |= UFLAG;
+ if(h8.h8hflag)h8.ccr |= HFLAG;
+ if(h8.h8uiflag)h8.ccr |= UIFLAG;
+ if(h8.h8iflag)h8.ccr |= IFLAG;
+ return h8.ccr;
+}
+
+static char *h8_get_ccr_str(void)
+{
+ static char res[8];
+
+ memset(res, 0, 8);
+ if(h8.h8iflag) strcat(res, "I"); else strcat(res, "i");
+ if(h8.h8uiflag)strcat(res, "U"); else strcat(res, "u");
+ if(h8.h8hflag) strcat(res, "H"); else strcat(res, "h");
+ if(h8.h8uflag) strcat(res, "U"); else strcat(res, "u");
+ if(h8.h8nflag) strcat(res, "N"); else strcat(res, "n");
+ if(h8.h8zflag) strcat(res, "Z"); else strcat(res, "z");
+ if(h8.h8vflag) strcat(res, "V"); else strcat(res, "v");
+ if(h8.h8cflag) strcat(res, "C"); else strcat(res, "c");
+
+ return res;
+}
+
+static void h8_set_ccr(UINT8 data)
+{
+ h8.ccr = data;
+
+ h8.h8nflag = 0;
+ h8.h8zflag = 0;
+ h8.h8vflag = 0;
+ h8.h8cflag = 0;
+ h8.h8hflag = 0;
+ h8.h8iflag = 0;
+ h8.h8uflag = 0;
+ h8.h8uiflag = 0;
+
+ if(h8.ccr & NFLAG) h8.h8nflag = 1;
+ if(h8.ccr & ZFLAG) h8.h8zflag = 1;
+ if(h8.ccr & VFLAG) h8.h8vflag = 1;
+ if(h8.ccr & CFLAG) h8.h8cflag = 1;
+ if(h8.ccr & HFLAG) h8.h8hflag = 1;
+ if(h8.ccr & UFLAG) h8.h8uflag = 1;
+ if(h8.ccr & UIFLAG) h8.h8uiflag = 1;
+ if(h8.ccr & IFLAG) h8.h8iflag = 1;
+
+ h8_check_irqs();
+}
+
+static INT16 h8_getreg16(UINT8 reg)
+{
+ if(reg > 7)
+ {
+ return h8.regs[reg-8]>>16;
+ }
+ else
+ {
+ return h8.regs[reg];
+ }
+}
+
+static void h8_setreg16(UINT8 reg, UINT16 data)
+{
+ if(reg > 7)
+ {
+ h8.regs[reg-8] &= 0xffff;
+ h8.regs[reg-8] |= data<<16;
+ }
+ else
+ {
+ h8.regs[reg] &= 0xffff0000;
+ h8.regs[reg] |= data;
+ }
+}
+
+static UINT8 h8_getreg8(UINT8 reg)
+{
+ if(reg > 7)
+ {
+ return h8.regs[reg-8];
+ }
+ else
+ {
+ return h8.regs[reg]>>8;
+ }
+}
+
+static void h8_setreg8(UINT8 reg, UINT8 data)
+{
+ if(reg > 7)
+ {
+ h8.regs[reg-8] &= 0xffffff00;
+ h8.regs[reg-8] |= data;
+ }
+ else
+ {
+ h8.regs[reg] &= 0xffff00ff;
+ h8.regs[reg] |= data<<8;
+ }
+}
+
+static UINT32 h8_getreg32(UINT8 reg)
+{
+ return h8.regs[reg];
+}
+
+static void h8_setreg32(UINT8 reg, UINT32 data)
+{
+ h8.regs[reg] = data;
+}
+
+static void h8_onstateload(void)
+{
+ h8_set_ccr(h8.ccr);
+}
+
+static void h8_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ memset(&h8, 0, sizeof(h8));
+ h8.h8iflag = 1;
+
+ h8.irq_cb = irqcallback;
+
+ state_save_register_item("H8/3002", index, h8.h8err);
+ state_save_register_item_array("H8/3002", index, h8.regs);
+ state_save_register_item("H8/3002", index, h8.pc);
+ state_save_register_item("H8/3002", index, h8.ppc);
+ state_save_register_item("H8/3002", index, h8.h8_IRQrequestH);
+ state_save_register_item("H8/3002", index, h8.h8_IRQrequestL);
+ state_save_register_item("H8/3002", index, h8.ccr);
+
+ state_save_register_item_array("H8/3002", index, h8.per_regs);
+ state_save_register_item("H8/3002", index, h8.h8TSTR);
+ state_save_register_item("H8/3002", index, h8.h8TCNT0);
+ state_save_register_item("H8/3002", index, h8.h8TCNT1);
+ state_save_register_item("H8/3002", index, h8.h8TCNT2);
+ state_save_register_item("H8/3002", index, h8.h8TCNT3);
+ state_save_register_item("H8/3002", index, h8.h8TCNT4);
+
+ state_save_register_func_postload(h8_onstateload);
+
+ h8_itu_init();
+}
+
+static void h8_reset(void)
+{
+ h8.h8err = 0;
+ h8.pc = h8_mem_read32(0) & 0xffffff;
+ change_pc(h8.pc);
+
+ // disable timers
+ h8.h8TSTR = 0;
+
+ h8_itu_reset();
+}
+
+static void h8_GenException(UINT8 vectornr)
+{
+ // push PC on stack
+ // extended mode stack push!
+ h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
+ h8_mem_write32(h8_getreg32(H8_SP), h8.pc);
+ // push ccr
+ h8_setreg32(H8_SP, h8_getreg32(H8_SP)-2);
+ h8_mem_write16(h8_getreg32(H8_SP), h8_get_ccr());
+
+ // generate address from vector
+ h8_set_ccr(h8_get_ccr() | 0x80);
+ h8.pc = h8_mem_read32(vectornr * 4) & 0xffffff;
+ change_pc(h8.pc);
+
+ // I couldn't find timing info for exceptions, so this is a guess (based on JSR/BSR)
+ H8_IFETCH_TIMING(2);
+ H8_STACK_TIMING(2);
+}
+
+static int h8_get_priority(UINT8 bit)
+{
+ int res = 0;
+ switch(bit)
+ {
+ case 12: // IRQ0
+ if (h8.per_regs[0xF8]&0x80) res = 1; break;
+ case 13: // IRQ1
+ if (h8.per_regs[0xF8]&0x40) res = 1; break;
+ case 14: // IRQ2
+ case 15: // IRQ3
+ if (h8.per_regs[0xF8]&0x20) res = 1; break;
+ case 16: // IRQ4
+ case 17: // IRQ5
+ if (h8.per_regs[0xF8]&0x10) res = 1; break;
+ }
+ return res;
+}
+
+static void h8_check_irqs(void)
+{
+ int lv = -1;
+ if (h8.h8iflag == 0)
+ {
+ lv = 0;
+ }
+ else
+ {
+ if ((h8.per_regs[0xF2]&0x08)/*SYSCR*/ == 0)
+ {
+ if (h8.h8uiflag == 0)
+ lv = 1;
+ }
+ }
+
+ // any interrupts wanted and can accept ?
+ if(((h8.h8_IRQrequestH != 0) || (h8.h8_IRQrequestL != 0)) && (lv >= 0))
+ {
+ UINT8 bit, source;
+ // which one ?
+ for(bit = 0, source = 0xff; source == 0xff && bit < 32; bit++)
+ {
+ if( h8.h8_IRQrequestL & (1<<bit) )
+ {
+ if (h8_get_priority(bit) >= lv)
+ {
+ // mask off
+ h8.h8_IRQrequestL &= ~(1<<bit);
+ source = bit;
+ }
+ }
+ }
+ // which one ?
+ for(bit = 0; source == 0xff && bit < 32; bit++)
+ {
+ if( h8.h8_IRQrequestH & (1<<bit) )
+ {
+ if (h8_get_priority(bit + 32) >= lv)
+ {
+ // mask off
+ h8.h8_IRQrequestH &= ~(1<<bit);
+ source = bit + 32;
+ }
+ }
+ }
+
+ // call the MAME callback if it's one of the 6
+ // external IRQs
+ if (source >= 12 && source <= 17)
+ {
+ (*h8.irq_cb)(source - 12 + H8_IRQ0);
+ }
+
+ if (source != 0xff)
+ h8_GenException(source);
+ }
+}
+
+static int h8_execute(int cycles)
+{
+ UINT16 opcode=0;
+
+ h8_cyccnt = cycles;
+
+ h8_check_irqs();
+
+ while ((h8_cyccnt > 0) && (!h8.h8err))
+ {
+ h8.ppc = h8.pc;
+
+#ifdef MAME_DEBUG
+ CALL_MAME_DEBUG;
+#endif
+ opcode = cpu_readop16(h8.pc);
+// mame_printf_debug("[%06x]: %04x => %x\n", h8.pc, opcode, (opcode>>12)&0xf);
+ h8.pc += 2;
+
+ switch((opcode>>12) & 0xf)
+ {
+ case 0x0:
+ h8_group0(opcode);
+ break;
+ case 0x1:
+ h8_group1(opcode);
+ break;
+ case 0x2:
+ // mov.b @xx:8, Rd (abs)
+ dstreg = (opcode>>8) & 0xf;
+ udata8 = h8_mem_read8(0xffff00+(opcode & 0xff));
+ h8_mov8(udata8); // flags calculation, dont care about others
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x3: // pass
+ // mov.b Rs, @xx:8 (abs)
+ srcreg = (opcode>>8) & 0xf;
+ udata8 = h8_getreg8(srcreg);
+ h8_mov8(udata8); // flags calculation, dont care about others
+ h8_mem_write8(0xffff00+(opcode & 0xff), udata8);
+ H8_IFETCH_TIMING(1);
+ H8_BYTE_TIMING(1, 0xffff00+(opcode & 0xff));
+ break;
+ case 0x4:
+ // bcc @xx:8
+ sdata8 = (opcode & 0xff);
+ if( h8_branch((opcode >> 8) & 0xf) == 1)h8.pc += sdata8;
+ change_pc(h8.pc);
+ break;
+ case 0x5:
+ h8_group5(opcode);
+ break;
+ case 0x6:
+ h8_group6(opcode);
+ break;
+ case 0x7:
+ h8_group7(opcode);
+ break;
+ case 0x8:
+ // add.b #xx:8, Rd
+ dstreg = (opcode>>8) & 0xf;
+ udata8 = h8_add8(opcode & 0xff, h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1)
+ break;
+ case 0x9:
+ // addx.b #xx:8, Rd
+ dstreg = (opcode>>8) & 0xf;
+ udata8 = h8_addx8(opcode & 0xff, h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1)
+ break;
+ case 0xa:
+ // cmp.b #xx:8, Rd
+ dstreg = (opcode>>8) & 0xf;
+ h8_cmp8(opcode & 0xff, h8_getreg8(dstreg));
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xb:
+ // subx.b #xx:8, Rd
+ dstreg = (opcode>>8) & 0xf;
+ udata8 = h8_subx8(opcode & 0xff, h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xc:
+ // or.b #xx:8, Rd
+ dstreg = (opcode>>8) & 0xf;
+ udata8 = h8_or8(opcode & 0xff, h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xd:
+ // xor.b #xx:8, Rd
+ dstreg = (opcode>>8) & 0xf;
+ udata8 = h8_xor8(opcode & 0xff, h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xe: // pass
+ // and.b #xx:8, Rd
+ dstreg = (opcode>>8) & 0xf;
+ udata8 = h8_and8(opcode & 0xff, h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1)
+ break;
+ case 0xf: // pass
+ // mov.b #xx:8, Rd
+ dstreg = (opcode>>8) & 0xf;
+ udata8 = h8_mov8(opcode & 0xff);
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ }
+ }
+
+ if (h8.h8err)
+ {
+ fatalerror("H8/3002: Unknown opcode (PC=%x) %x", h8.ppc, opcode);
+
+ }
+
+ return cycles - h8_cyccnt;
+}
+
+static void h8_group0(UINT16 opcode)
+{
+ switch((opcode>>8)&0xf)
+ {
+ case 0:
+ // nop
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x1:
+ // 010x where x should always be 0!
+ if((opcode & 0xf) != 0)
+ {
+ h8.h8err = 1;
+ break;
+ }
+ switch((opcode>>4) & 0xf)
+ {
+ // 0100 mov.l prefix
+ case 0xf: // and.l Rn, Rn
+ ext16 = h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ if (ext16 & 0x88)
+ {
+ h8.h8err = 1;
+ }
+ else
+ {
+ switch((ext16>>8)&0xff)
+ {
+ case 0x65:
+ dstreg = ext16 & 0x7;
+ udata32 = h8_xor32(h8_getreg32((ext16>>4) & 0x7), h8_getreg32(dstreg));
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(2);
+ break;
+ case 0x66:
+ dstreg = ext16 & 0x7;
+ udata32 = h8_and32(h8_getreg32((ext16>>4) & 0x7), h8_getreg32(dstreg));
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(2);
+ break;
+ default:
+ h8.h8err = 1;
+ break;
+ }
+ }
+ break;
+
+ case 0:
+ ext16 = h8_mem_read16(h8.pc);
+ h8.pc+=2;
+ switch((ext16 >> 8) & 0xff)
+ {
+ case 0x69:
+ if((ext16 & 0x80) == 0x80)
+ {
+ // mov.l rx, @rx
+ udata32 = h8_mov32(h8_getreg32(ext16 & 7));
+ h8_mem_write32(h8_getreg32((ext16 >> 4) & 7), udata32);
+ H8_IFETCH_TIMING(2);
+ H8_WORD_TIMING(2, h8_getreg32((ext16 >> 4) & 7));
+ }
+ else
+ {
+ // mov.l @rx, rx
+ udata32 = h8_mem_read32(h8_getreg32( (ext16 >> 4) &7));
+ h8_mov32(udata32);
+ h8_setreg32(ext16 & 7, udata32);
+ H8_IFETCH_TIMING(2);
+ H8_WORD_TIMING(2, h8_getreg32( (ext16 >> 4) &7));
+ }
+ break;
+ case 0x6b:
+ // mov.l rx, @xx / mov.l @xx, rx
+ switch((ext16 >> 4)&0xf)
+ {
+ case 0x2:
+ // mov.l @aa:24, erx
+ address24=h8_mem_read32(h8.pc);
+ h8.pc += 4;
+ udata32=h8_mem_read32(address24);
+ h8_mov32(udata32); // flags only
+ h8_setreg32(ext16 & 0x7, udata32);
+ H8_IFETCH_TIMING(4);
+ H8_WORD_TIMING(2, address24);
+ break;
+ case 0xa:
+ // mov.l erx, @aa:24
+ address24=h8_mem_read32(h8.pc);
+ h8.pc += 4;
+ udata32=h8_getreg32(ext16 & 0x7);
+ h8_mov32(udata32); // flags only
+ h8_mem_write32(address24, udata32);
+ H8_IFETCH_TIMING(4);
+ H8_WORD_TIMING(2, address24);
+ break;
+ default:
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0x6d:
+ if(ext16 & 0x80)
+ {
+ // mov.l rs, @-erd
+ srcreg = (ext16>>4)&7;
+ h8_setreg32(srcreg, h8_getreg32(srcreg)-4);
+ address24 = h8_getreg32(srcreg) & 0xffffff;
+ udata32 = h8_getreg32(ext16 & 0x7);
+ h8_mem_write32(address24, udata32);
+ H8_IFETCH_TIMING(2);
+ H8_WORD_TIMING(2, address24);
+ H8_IOP_TIMING(2);
+ }
+ else
+ {
+ // mov.l @ers+, rd
+ srcreg = (ext16 >>4)&7;
+ address24 = h8_getreg32(srcreg) & 0xffffff;
+ h8_setreg32(srcreg, h8_getreg32(srcreg)+4);
+ udata32 = h8_mem_read32(address24);
+ h8_setreg32(ext16 & 0x7, udata32);
+ H8_IFETCH_TIMING(2);
+ H8_WORD_TIMING(2, address24);
+ H8_IOP_TIMING(2);
+ }
+ h8_mov32(udata32);
+ break;
+ case 0x6f:
+ // mov.l @(displ16 + Rs), rd
+ sdata16=h8_mem_read16(h8.pc); // sign extend displacements !
+ h8.pc += 2;
+ address24 = (h8_getreg32((ext16 >> 4)&7)) & 0xffffff;
+ address24 += sdata16;
+ H8_IFETCH_TIMING(3);
+ H8_WORD_TIMING(2, address24);
+ if(ext16 & 0x80)
+ {
+ udata32 = h8_getreg32(ext16 & 0x7);
+ h8_mem_write32(address24, udata32);
+ }
+ else
+ {
+ udata32 = h8_mem_read32(address24);
+ h8_setreg32(ext16 & 0x7, udata32);
+ }
+ h8_mov32(udata32);
+ break;
+ case 0x78:
+ // prefix for
+ // mov.l (@aa:x, rx), Rx
+ //00000A10 010078606B2600201AC2 MOV.L @($00201AC2,ER6),ER6
+ // mov.l @(displ24 + Rs), rd
+ srcreg = (ext16 >> 4) & 7;
+
+ // 6b20
+ udata16 = h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ dstreg = udata16 & 7;
+
+ address24 = h8_mem_read32(h8.pc);
+ h8.pc += 4;
+ address24 += h8_getreg32(srcreg);
+ address24 &= 0xffffff;
+
+ if ( (ext16 & 0x80) && ((udata16 & ~7) == 0x6ba0) )
+ {
+ udata32 = h8_getreg32(dstreg);
+ h8_mem_write32(address24, udata32);
+ }
+ else if ( (!(ext16 & 0x80)) && ((udata16 & ~7) == 0x6b20) )
+ {
+ udata32 = h8_mem_read32(address24);
+ h8_setreg32(dstreg, udata32);
+ }
+ else
+ {
+ h8.h8err = 1;
+ }
+
+ h8_mov32(udata32);
+
+ H8_IFETCH_TIMING(5);
+ H8_WORD_TIMING(2, address24);
+
+ break;
+ default:
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0xc:
+ // mulxs
+ ext16 = h8_mem_read16(h8.pc);
+ h8.pc+=2;
+ if(((ext16>>8) & 0xf) == 0)
+ {
+ h8.h8err = 1;
+ }
+ else if(((ext16>>8) & 0xf) == 2)
+ {
+ sdata32 = h8_getreg32(ext16 & 0x7);
+ sdata16 = h8_getreg16((ext16>>4) & 0xf);
+ sdata32 = h8_mulxs16(sdata16, sdata32);
+ h8_setreg32(ext16 & 0x7, sdata32);
+ H8_IFETCH_TIMING(2);
+ H8_IOP_TIMING(20);
+ }
+ else
+ {
+ logerror("H8/3002: Unk. group 0 mulxs %x\n", opcode);
+ h8.h8err = 1;
+ }
+ break;
+
+ case 0xd:
+ //divxs - probbaly buggy (flags?)
+ ext16 = h8_mem_read16(h8.pc);
+ h8.pc+=2;
+ if(((ext16>>8) & 0xf) == 0)
+ {
+ h8.h8err = 1;
+ }
+ else if(((ext16>>8) & 0xf) == 3)
+ {
+ sdata32 = h8_getreg32(ext16 & 0x7);
+ sdata16 = h8_getreg16((ext16>>4) & 0xf);
+ sdata32 = h8_divxs16(sdata16, sdata32);
+ h8_setreg32(ext16 & 0x7, sdata32);
+ H8_IFETCH_TIMING(2);
+ H8_IOP_TIMING(20);
+ }
+ else
+ {
+ h8.h8err = 1;
+ }
+
+
+ break;
+
+ default:
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0x2:
+ // stc ccr, rd
+ if(((opcode>>4) & 0xf) == 0)
+ {
+ h8_setreg8(opcode & 0xf, h8_get_ccr());
+ H8_IFETCH_TIMING(1);
+ }
+ else
+ {
+ logerror("H8/3002: Unk. group 0 2 %x\n", opcode);
+ h8.h8err = 1;
+ }
+ break;
+ case 0x3:
+ // ldc rd, ccr
+ if(((opcode>>4) & 0xf) == 0)
+ {
+ udata8 = h8_getreg8(opcode & 0xf);
+ h8_set_ccr(udata8);
+ H8_IFETCH_TIMING(1);
+ }
+ else
+ {
+ logerror("H8/3002: Unk. group 0 3 %x\n", opcode);
+ h8.h8err = 1;
+ }
+ break;
+ case 0x4: // pass
+ // orc
+ udata8 = h8_or8(opcode & 0xff, h8_get_ccr());
+ h8_set_ccr(udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x6:
+ // andc
+ udata8 = h8_and8(opcode & 0xff, h8_get_ccr());
+ h8_set_ccr(udata8);
+ H8_IFETCH_TIMING(1)
+ break;
+ // ldc
+ case 0x8:
+ // add.b rx, ry
+ dstreg = opcode & 0xf;
+ udata8 = h8_add8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1)
+ break;
+ // add.w rx, ry
+ case 0x9:
+ dstreg = opcode & 0xf;
+ udata16 = h8_add16(h8_getreg16((opcode>>4) &0xf), h8_getreg16(dstreg));
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1)
+ break;
+ // inc.b rx
+ case 0xA:
+ if(opcode&0x80)
+ {
+ if(opcode & 0x8)
+ {
+ logerror("H8/3002: Unk. group 0 a %x\n", opcode);
+ h8.h8err = 1;
+ }
+ else
+ {
+ dstreg = opcode & 0x7;
+ udata32 = h8_add32(h8_getreg32((opcode>>4) &0x7), h8_getreg32(dstreg));
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1)
+ }
+ }
+ else
+ {
+ if(opcode & 0xf0)
+ {
+ logerror("H8/3002: Unk. group 0 a2 %x\n", opcode);
+ h8.h8err =1;
+ }
+ else
+ {
+ dstreg = opcode & 0xf;
+ udata8 = h8_inc8(h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ }
+ }
+ break;
+ case 0xb:
+ switch((opcode>>4)& 0xf)
+ {
+ case 0:
+ if(opcode & 8)
+ {
+ h8.h8err = 1;
+ }
+ else
+ {
+ dstreg = opcode & 7;
+ udata32 = h8_getreg32(dstreg) + 1;
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1)
+ }
+ break;
+ case 5:
+ dstreg = opcode & 0xf;
+ udata16 = h8_inc16(h8_getreg16(dstreg));
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 7:
+ dstreg = opcode & 0x7;
+ udata32 = h8_inc32(h8_getreg32(dstreg));
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 8:
+ if(opcode & 8)
+ {
+ h8.h8err = 1;
+ }
+ else
+ {
+ dstreg = opcode & 7;
+ udata32 = h8_getreg32(dstreg) + 2;
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1)
+ }
+ break;
+ case 9:
+ if(opcode & 8)
+ {
+ h8.h8err = 1;
+ }
+ else
+ {
+ dstreg = opcode & 7;
+ udata32 = h8_getreg32(dstreg) + 4;
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1)
+ }
+ break;
+ case 0xd:
+ dstreg = opcode & 0xf;
+ udata16 = h8_inc16(h8_getreg16(dstreg));
+ if(h8.h8vflag)
+ {
+ udata16 = h8_inc16(udata16); // slow and easy
+ h8.h8vflag = 1;
+ }
+ else
+ udata16 = h8_inc16(udata16); // slow and easy
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xf:
+ dstreg = opcode & 0x7;
+ udata32 = h8_inc32(h8_getreg32(dstreg));
+ if(h8.h8vflag)
+ {
+ udata32 = h8_inc32(udata32); // slow and easy
+ h8.h8vflag = 1;
+ }
+ else
+ udata32 = h8_inc32(udata32); // slow and easy
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+ default:
+ logerror("H8/3002: Unk. group 0 b %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ // mov.b rx, ry
+ case 0xc: // pass
+ dstreg = opcode & 0xf;
+ udata8 = h8_mov8(h8_getreg8((opcode>>4) &0xf));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xd:
+ // mov.w rx, ry
+ dstreg = opcode & 0xf;
+ udata16 = h8_mov16(h8_getreg16((opcode>>4) &0xf));
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xf:
+ if(opcode & 0x80)
+ {
+ if(opcode & 8)
+ {
+ logerror("H8/3002: Unk. group 0 f %x\n", opcode);
+ h8.h8err = 1;
+ }
+ else
+ {
+ dstreg = opcode & 0x7;
+ udata32 = h8_mov32(h8_getreg32((opcode>>4) &0x7));
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1);
+ }
+ }
+ else
+ {
+ h8.h8err = 1;
+ logerror("H8/3002: Unk. group 0 f2 %x\n", opcode);
+ if((opcode & 0xf0) !=0)
+ {
+ h8.h8err = 1;
+ }
+ else
+ {
+ h8.h8err = 1;
+ }
+ }
+ break;
+ default:
+ logerror("H8/3002: Unk. group 0 tdef %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+}
+
+static void h8_group1(UINT16 opcode)
+{
+ switch((opcode>>8)&0xf)
+ {
+ case 0x0:
+ switch((opcode>>4)&0xf)
+ {
+ case 0x0:
+ // shll.b Rx
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_shll8(udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x1:
+ // shll.w Rx
+ udata16 = h8_getreg16(opcode & 0xf);
+ udata16 = h8_shll16(udata16);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x3:
+ // shal.l Rx
+ udata32 = h8_getreg32(opcode & 0x7);
+ udata32 = h8_shll32(udata32);
+ h8_setreg32(opcode & 0x7, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+
+ case 0x8:
+ // shal.b Rx
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_shal8(udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ // shal.w Rx
+ case 0x9:
+ udata16 = h8_getreg16(opcode & 0xf);
+ udata16 = h8_shal16(udata16);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+
+ default:
+ logerror("H8/3002: Unk. group 1 0 %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0x1:
+ switch((opcode>>4)&0xf)
+ {
+ case 0x0:
+ // shlr.b rx
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_shlr8(udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x1:
+ // shlr.w rx
+ udata16 = h8_getreg16(opcode & 0xf);
+ udata16 = h8_shlr16(udata16);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ // shlr.l rx
+ case 0x3:
+ udata32 = h8_getreg32(opcode & 0x7);
+ udata32 = h8_shlr32(udata32);
+ h8_setreg32(opcode & 0x7, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x8:
+ // shar.b rx
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_shar8(udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x9:
+ // shar.w rx
+ udata16 = h8_getreg16(opcode & 0xf);
+ udata16 = h8_shar16(udata16);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xb:
+ // shar.l rx
+ udata32 = h8_getreg32(opcode & 0x7);
+ udata32 = h8_shar32(udata32);
+ h8_setreg32(opcode & 0x7, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+ default:
+ logerror("H8/3002: Unk. group 1 1 %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0x2:
+ switch((opcode>>4)&0xf)
+ {
+ case 0x0:
+ // rotxl.b Rx
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_rotxl8(udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x1:
+ // rotxl.w Rx
+ udata16 = h8_getreg16(opcode & 0xf);
+ udata16 = h8_rotxl16(udata16);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+
+ case 0x3:
+ // rotxl.l Rx
+ udata32 = h8_getreg32(opcode & 0x7);
+ udata32 = h8_rotxl32(udata32);
+ h8_setreg32(opcode & 0xf, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+
+ case 0x8:
+ // rotl.b Rx
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_rotl8(udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x9:
+ // rotl.w Rx
+ udata16 = h8_getreg16(opcode & 0xf);
+ udata16 = h8_rotl16(udata16);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ // rotl.l Rx
+ default:
+ logerror("H8/3002: Unk. group 1 2 %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0x3:
+ switch((opcode>>4)&0xf)
+ {
+ case 0x0:
+ // rotxr.b Rx
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_rotxr8(udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x1:
+ // rotxr.w Rx
+ udata16 = h8_getreg16(opcode & 0xf);
+ udata16 = h8_rotxr16(udata16);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ default:
+ logerror("H8/3002: Unk. group 1 3 %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0x4:
+ // or.b rs, rd
+ dstreg = opcode & 0xf;
+ udata8 = h8_or8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x5:
+ // xor.b rs, rd
+ dstreg = opcode & 0xf;
+ udata8 = h8_xor8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x6:
+ // and.b rs, rd
+ dstreg = opcode & 0xf;
+ udata8 = h8_and8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1)
+ break;
+ // not
+ case 0x7:
+ switch((opcode>>4)&0xf)
+ {
+ case 0x0:
+ // not.b Rx
+ dstreg = opcode & 0xf;
+ udata8 = h8_not8(h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x1:
+ // not.w Rx
+ dstreg = opcode & 0xf;
+ udata16 = h8_not16(h8_getreg16(dstreg));
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+
+ case 0x5:
+ // extu.w Rx
+ dstreg = opcode & 0xf;
+ udata16 = h8_getreg16(dstreg) & 0x00ff;
+ h8_setreg16(dstreg, udata16);
+ h8.h8nflag = 0;
+ h8.h8vflag = 0;
+ h8.h8zflag = ((udata16 == 0) ? 1 : 0);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x7:
+ // extu.l Rx
+ dstreg = opcode & 0x7;
+ udata32 = h8_getreg32(dstreg) & 0x0000ffff;
+ h8_setreg32(dstreg, udata32);
+ h8.h8nflag = 0;
+ h8.h8vflag = 0;
+ h8.h8zflag = ((udata32 == 0) ? 1 : 0);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x8:
+ // neg.b Rx
+ //sprintf(output, "%4.4x neg.b %s", opcode, reg_names8[opcode & 0xf]);
+ dstreg = opcode & 0xf;
+ sdata8 = h8_neg8(h8_getreg8(dstreg));
+ h8_setreg8(dstreg, sdata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x9:
+ // neg.w Rx
+ //sprintf(output, "%4.4x neg.w %s", opcode, reg_names16[opcode & 0xf]);
+ dstreg = opcode & 0xf;
+ sdata16 = h8_neg16(h8_getreg16(dstreg));
+ h8_setreg16(dstreg, sdata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xf:
+ // exts.l Rx
+ dstreg = opcode & 0xf;
+ udata32=h8_getreg32(dstreg)&0xffff;
+ if(udata32&0x8000)
+ {
+ udata32|=0xffff0000;
+ }
+ h8_setreg32(dstreg, udata32);
+
+ h8.h8vflag = 0;
+ h8.h8nflag = (udata32 & 0xffff0000) ? 1 : 0;
+ h8.h8zflag = (udata32) ? 0 : 1;
+
+ H8_IFETCH_TIMING(1);
+ break;
+
+ default:
+ logerror("H8/3002: Unk. group 1 7-9 %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0x8:
+ // sub.b rs, rd
+ dstreg = opcode & 0xf;
+ udata8 = h8_sub8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x9:
+ // sub.w rs, rd
+ dstreg = opcode & 0xf;
+ udata16 = h8_sub16(h8_getreg16((opcode>>4) &0xf), h8_getreg16(dstreg));
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ // sub.b rx
+ case 0xA:
+ if(opcode&0x80)
+ {
+ //logerror("H8/3002: Unk. group 1 A %x\n", opcode);
+
+ // sub.l rs,rd
+ dstreg = opcode & 0x7;
+ udata32=h8_sub32(h8_getreg32((opcode>>4) &0x7), h8_getreg32(dstreg));
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(2);
+ break;
+
+ }
+ else
+ {
+ if(opcode & 0xf0)
+ {
+ logerror("H8/3002: Unk. group A2 0 %x\n", opcode);
+ h8.h8err = 1;
+ }
+ else
+ {
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_dec8(udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ }
+ }
+ break;
+ //
+ case 0xb:
+ switch((opcode>>4)& 0xf)
+ {
+ case 0: // subs.l #1, rN (decrement without touching flags)
+ dstreg = opcode & 0x7;
+ udata32 = h8_getreg32(dstreg);
+ udata32--;
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 5: // dec.w #1, rN
+ dstreg = opcode & 0xf;
+ udata16 = h8_dec16(h8_getreg16(dstreg));
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 7: // dec.l #1, rN
+ dstreg = opcode & 0x7;
+ udata32 = h8_dec32(h8_getreg32(dstreg));
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 8: // subs.l #2, rN (decrement without touching flags)
+ dstreg = opcode & 0x7;
+ udata32 = h8_getreg32(dstreg);
+ udata32-=2;
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 9: // subs.l #4, rN (decrement without touching flags)
+ dstreg = opcode & 0x7;
+ udata32 = h8_getreg32(dstreg);
+ udata32-=4;
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xd: // dec.w #2, rN
+ dstreg = opcode & 0xf;
+ udata16 = h8_dec16(h8_getreg16(dstreg));
+ if (h8.h8vflag)
+ {
+ udata16 = h8_dec16(udata16);
+ h8.h8vflag = 1;
+ }
+ else
+ udata16 = h8_dec16(udata16);
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xf: // dec.l #2, rN
+ dstreg = opcode & 0x7;
+ udata32 = h8_dec32(h8_getreg32(dstreg));
+ if (h8.h8vflag)
+ {
+ udata32 = h8_dec32(udata32);
+ h8.h8vflag = 1;
+ }
+ else
+ udata32 = h8_dec32(udata32);
+ h8_setreg32(dstreg, udata32);
+ H8_IFETCH_TIMING(1);
+ break;
+
+ default:
+ logerror("H8/3002: Unk. group 1 B %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0xc:
+ // cmp.b rs, rd
+ h8_cmp8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(opcode & 0xf));
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xd:
+ // cmp.w rx, ry
+ h8_cmp16(h8_getreg16((opcode>>4) &0xf), h8_getreg16(opcode & 0xf));
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xe:
+ // subx.b rx, ry
+ dstreg = opcode & 0xf;
+ udata8 = h8_subx8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
+ h8_setreg8(dstreg, udata8);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0xf:
+ if(opcode & 0x80)
+ {
+ if(opcode & 8)
+ {
+ logerror("H8/3002: Unk. group 1 f %x\n", opcode);
+ h8.h8err = 1;
+ }
+ else
+ {
+ h8_cmp32(h8_getreg32((opcode>>4) & 0x7), h8_getreg32(opcode & 0x7));
+ H8_IFETCH_TIMING(1);
+ }
+ }
+ else
+ {
+ logerror("H8/3002: Unk. group 1 f2 %x\n", opcode);
+ h8.h8err = 1;
+ }
+ break;
+ default:
+ logerror("H8/3002: Unk. group 1 def %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+}
+
+
+static void h8_group5(UINT16 opcode)
+{
+ switch((opcode>>8)&0xf)
+ {
+ case 0x0:
+ // mulxu.b
+ udata8 = h8_getreg8((opcode>>4)&0xf);
+ udata16 = h8_getreg16(opcode & 0xf);
+ udata16 &= 0xff;
+ udata16 = udata16*udata8;
+ // no flags modified!
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ H8_IOP_TIMING(12);
+ break;
+ case 0x1:
+ // divxu.b
+ udata8 = h8_getreg8((opcode>>4)&0xf);
+ udata16 = h8_getreg16(opcode & 0x0f);
+ udata16 = h8_divxu8(udata16,udata8);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ H8_IOP_TIMING(12);
+ break;
+ case 0x2:
+ // mulxu.w
+ udata16 = h8_getreg16((opcode>>4)&0xf);
+ udata32 = h8_getreg32(opcode & 7);
+ udata32 &= 0xffff;
+ udata32 = udata32*udata16;
+ // no flags modified!
+ h8_setreg32(opcode & 7, udata32);
+ H8_IFETCH_TIMING(1);
+ H8_IOP_TIMING(20);
+ break;
+ case 0x3:
+ // divxu.w
+ udata16 = h8_getreg16((opcode>>4)&0xf);
+ udata32 = h8_getreg32(opcode & 7);
+ udata32 = h8_divxu16(udata32,udata16);
+ h8_setreg32(opcode & 7, udata32);
+ H8_IFETCH_TIMING(1);
+ H8_IOP_TIMING(20);
+ break;
+ case 0x4:
+ if(opcode == 0x5470)
+ {
+ // rts
+ udata32 = h8_mem_read32(h8_getreg32(H8_SP));
+ h8_setreg32(H8_SP, h8_getreg32(H8_SP)+4);
+ // extended mode
+ h8.pc = udata32;
+ change_pc(h8.pc);
+ H8_IFETCH_TIMING(2);
+ H8_STACK_TIMING(2);
+ H8_IOP_TIMING(2);
+ }
+ else
+ {
+ logerror("H8/3002: Unk. group 5 1 %x\n", opcode);
+ h8.h8err = 1;
+ }
+ break;
+ case 0x5:
+ // bsr 8
+ sdata8 = opcode & 0xff;
+ // extended mode stack push!
+ h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
+ h8_mem_write32(h8_getreg32(H8_SP), h8.pc);
+ h8.pc = h8.pc + sdata8;
+ change_pc(h8.pc);
+ H8_IFETCH_TIMING(2); H8_STACK_TIMING(2);
+ break;
+ case 0x6:
+ // rte
+ if(opcode == 0x5670)
+ {
+ // restore CCR
+ udata16 = h8_mem_read16(h8_getreg32(H8_SP));
+ h8_setreg32(H8_SP, h8_getreg32(H8_SP)+2);
+ // extended mode restore PC
+ udata32 = h8_mem_read32(h8_getreg32(H8_SP));
+ h8_setreg32(H8_SP, h8_getreg32(H8_SP)+4);
+ // extended mode
+ h8.pc = udata32;
+ change_pc(h8.pc);
+ // must do this last, because set_ccr() does a check_irq()
+ h8_set_ccr((UINT8)udata16);
+ H8_IFETCH_TIMING(2);
+ H8_STACK_TIMING(2);
+ H8_IOP_TIMING(2);
+ }
+ else
+ {
+ logerror("H8/3002: Unk. group 5 6 %x\n", opcode);
+ h8.h8err = 1;
+ }
+ break;
+ // trapa
+ case 0x7:
+ logerror("H8/3002: Unk. group 5 7 %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ case 0x8:
+ // bcc @xx:16
+ if(opcode & 0xf)
+ {
+ logerror("H8/3002: Unk. group 5 8 %x\n", opcode);
+ h8.h8err = 1;
+ }
+ else
+ {
+ sdata16 = h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ if( h8_branch((opcode >> 4) & 0xf) == 1)h8.pc += sdata16;
+ change_pc(h8.pc);
+ H8_IOP_TIMING(2)
+ }
+ break;
+ case 0x9:
+ // jmp @erd
+ address24 = h8_getreg32((opcode>>4)&7);
+ address24 &= 0xffffff;
+ h8.pc = address24;
+ change_pc(h8.pc);
+ H8_IFETCH_TIMING(2);
+ break;
+ // jmp @aa:24
+ case 0xa:
+ address24=h8_mem_read32(h8.pc-2);
+ address24 &= 0xffffff;
+ h8.pc = address24;
+ change_pc(h8.pc);
+ H8_IFETCH_TIMING(2);
+ H8_IOP_TIMING(2);
+ break;
+ // jmp @aa:8
+ case 0xc:
+ if(opcode & 0xff)
+ {
+ logerror("H8/3002: Unk. group 5 c %x\n", opcode);
+ h8.h8err = 1;
+ }
+ else
+ {
+ // bsr d:16
+ sdata16=h8_mem_read16(h8.pc);
+ h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
+ h8_mem_write32(h8_getreg32(H8_SP), h8.pc+2);
+ h8.pc += sdata16 + 2;
+ change_pc(h8.pc);
+ H8_IFETCH_TIMING(2); H8_STACK_TIMING(2); H8_IOP_TIMING(2);
+ }
+ break;
+ case 0xd:
+ // jsr @reg
+ address24=h8_getreg32((opcode>>4)&7);
+ address24 &= 0xffffff;
+ // extended mode stack push!
+ h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
+ h8_mem_write32(h8_getreg32(H8_SP), h8.pc);
+ h8.pc = address24;
+ change_pc(h8.pc);
+ H8_STACK_TIMING(2);
+ H8_IOP_TIMING(2);
+ break;
+ case 0xe:
+ // jsr @aa:24
+ address24=h8_mem_read32(h8.pc-2);
+ address24 &= 0xffffff;
+ // extended mode stack push!
+ h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
+ h8_mem_write32(h8_getreg32(H8_SP), h8.pc+2);
+ h8.pc = address24;
+ change_pc(h8.pc);
+ H8_IFETCH_TIMING(2);
+ H8_STACK_TIMING(2);
+ H8_IOP_TIMING(2);
+ break;
+ // jsr @aa:8
+ default:
+ logerror("H8/3002: Unk. group 5 def %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+}
+
+static void h8_group6(UINT16 opcode)
+{
+ switch((opcode>>8)&0xf)
+ {
+ case 0:case 1:case 2:case 3:
+ {
+ UINT8 bitnr;
+
+ dstreg = opcode & 0xf;
+ udata8 = h8_getreg8(dstreg);
+ bitnr = h8_getreg8((opcode>>4)& 0xf)&7;
+
+ switch((opcode>>8)&0xf)
+ {
+ case 0: udata8 = h8_bset8(bitnr, udata8); h8_setreg8(dstreg, udata8); H8_IFETCH_TIMING(1); break;
+ case 2: udata8 = h8_bclr8(bitnr, udata8); h8_setreg8(dstreg, udata8); H8_IFETCH_TIMING(1); break;
+ case 3: h8_btst8(bitnr, udata8); H8_IFETCH_TIMING(1); break;
+ default:
+ logerror("H8/3002: Unk. group 6 def 0-3-0 %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ }
+ break;
+ case 0x4:
+ // or.w rs, rd
+ dstreg = opcode & 0xf;
+ udata16 = h8_getreg16(dstreg);
+ udata16 = h8_or16(h8_getreg16((opcode>>4) & 0xf), udata16);
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x5:
+ // xor.w rs, rd
+ dstreg = opcode & 0xf;
+ udata16 = h8_getreg16(dstreg);
+ udata16 = h8_xor16(h8_getreg16((opcode>>4) & 0xf), udata16);
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1);
+ break;
+ case 0x6:
+ // and.w rs, rd
+ dstreg = opcode & 0xf;
+ udata16 = h8_getreg16(dstreg);
+ udata16 = h8_and16(h8_getreg16((opcode>>4) & 0xf), udata16);
+ h8_setreg16(dstreg, udata16);
+ H8_IFETCH_TIMING(1)
+ break;
+ case 0x7:
+ // bst/bist #imm, rd
+ if(opcode & 0x80)
+ {
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_bist8((opcode>>4) & 7, udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ }
+ else
+ {
+ udata8 = h8_getreg8(opcode & 0xf);
+ udata8 = h8_bst8((opcode>>4) & 7, udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ }
+ break;
+ case 0x8:
+ if(opcode & 0x80)
+ {
+ // mov.b rx, @rx
+ udata8 = h8_getreg8(opcode & 0xf);
+ address24 = h8_getreg32((opcode>>4)&7) & 0xffffff;
+ h8_mov8(udata8);
+ h8_mem_write8(address24, udata8);
+ H8_IFETCH_TIMING(1);
+ H8_BYTE_TIMING(1, address24);
+ }
+ else
+ {
+ // mov.b @rx, rx
+ address24 = h8_getreg32((opcode>>4)&7) & 0xffffff;
+ udata8 = h8_mem_read8(address24);
+ h8_mov8(udata8);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ H8_BYTE_TIMING(1, address24);
+ }
+ break;
+ case 0x9:
+ if(opcode & 0x80)
+ {
+ // mov.w rx, @rx
+ address24 = h8_getreg32((opcode>>4)&7) & 0xffffff;
+ udata16 = h8_getreg16(opcode & 0xf);
+ h8_mov16(udata16);
+ h8_mem_write16(address24, udata16);
+ H8_IFETCH_TIMING(1);
+ H8_WORD_TIMING(1, address24);
+ }
+ else
+ {
+ // mov.w @rx, rx
+ address24 = h8_getreg32((opcode>>4)&7) & 0xffffff;
+ udata16 = h8_mem_read16(address24);
+ h8_mov16(udata16);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ H8_WORD_TIMING(1, address24);
+ }
+ break;
+ case 0xa:
+ // mov.b rx, @xx
+ switch((opcode>>4)&0xf)
+ {
+ case 0x0:
+ sdata16=h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ address24 = sdata16 & 0xffffff;
+ udata8=h8_mem_read8(address24);
+ h8_mov8(udata8); // flags only
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ H8_BYTE_TIMING(1, address24);
+ break;
+ case 0x2:
+ address24=h8_mem_read32(h8.pc);
+ h8.pc += 4;
+ udata8=h8_mem_read8(address24);
+ h8_mov8(udata8); // flags only
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(2);
+ H8_BYTE_TIMING(1, address24);
+ break;
+ case 0x8:
+ sdata16=h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ address24 = sdata16 & 0xffffff;
+ udata8=h8_getreg8(opcode & 0xf);
+ h8_mov8(udata8); // flags only
+ h8_mem_write8(address24, udata8);
+ H8_IFETCH_TIMING(3);
+ H8_BYTE_TIMING(1, address24);
+ break;
+ case 0xa: // pass
+ address24=h8_mem_read32(h8.pc);
+ h8.pc += 4;
+ udata8=h8_getreg8(opcode & 0xf);
+ h8_mov8(udata8); // flags only
+ h8_mem_write8(address24, udata8);
+ H8_IFETCH_TIMING(3);
+ H8_BYTE_TIMING(1, address24);
+ break;
+ default:
+ logerror("H8/3002: Unk. group 6 a %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0xb:
+ // mov.w rx, @xx / mov.w @xx, rx
+ switch((opcode>>4)&0xf)
+ {
+ case 0x0:
+ sdata16=h8_mem_read16(h8.pc);
+ address24 = sdata16;
+ address24 &= 0xffffff;
+ h8.pc += 2;
+ udata16=h8_mem_read16(address24);
+ h8_mov16(udata16); // flags only
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(2);
+ H8_WORD_TIMING(1, address24);
+ break;
+ case 0x2:
+ address24=h8_mem_read32(h8.pc);
+ h8.pc += 4;
+ udata16=h8_mem_read16(address24);
+ h8_mov16(udata16); // flags only
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(4);
+ H8_WORD_TIMING(1, address24);
+ break;
+ case 0x8:
+ sdata16=h8_mem_read16(h8.pc);
+ address24 = sdata16;
+ address24 &= 0xffffff;
+ h8.pc += 2;
+ udata16=h8_getreg16(opcode & 0xf);
+ h8_mov16(udata16); // flags only
+ h8_mem_write16(address24, udata16);
+ H8_IFETCH_TIMING(2);
+ H8_WORD_TIMING(1, address24);
+ break;
+ case 0xa: // pass
+ address24=h8_mem_read32(h8.pc);
+ h8.pc += 4;
+ udata16=h8_getreg16(opcode & 0xf);
+ h8_mov16(udata16); // flags only
+ h8_mem_write16(address24, udata16);
+ H8_IFETCH_TIMING(4);
+ H8_WORD_TIMING(1, address24);
+ break;
+ default:
+ logerror("H8/3002: Unk. group 6b %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ break;
+ case 0xc:
+ if(opcode & 0x80)
+ {
+ // mov.b rx, @-erx
+ srcreg = (opcode>>4)&7;
+ h8_setreg32(srcreg, h8_getreg32(srcreg)-1);
+ address24 = h8_getreg32(srcreg) & 0xffffff;
+ udata8 = h8_getreg8(opcode & 0xf);
+ h8_mem_write8(address24, udata8);
+ H8_IFETCH_TIMING(1);
+ H8_BYTE_TIMING(1, address24);
+ H8_IOP_TIMING(2);
+ }
+ else
+ {
+ // mov.b @erx+,rx
+ srcreg = (opcode>>4)&7;
+ address24 = h8_getreg32(srcreg) & 0xffffff;
+ h8_setreg32(srcreg, h8_getreg32(srcreg)+1);
+ udata8 = h8_mem_read8(address24);
+ h8_setreg8(opcode & 0xf, udata8);
+ H8_IFETCH_TIMING(1);
+ H8_BYTE_TIMING(1, address24);
+ H8_IOP_TIMING(2);
+ }
+ h8_mov8(udata8);
+ break;
+ case 0xd:
+ if(opcode & 0x80)
+ {
+ // mov.w rs, @-erd
+ srcreg = (opcode>>4)&7;
+ h8_setreg32(srcreg, h8_getreg32(srcreg)-2);
+ address24 = h8_getreg32(srcreg) & 0xffffff;
+ udata16 = h8_getreg16(opcode & 0xf);
+ h8_mem_write16(address24, udata16);
+ H8_IFETCH_TIMING(1);
+ H8_WORD_TIMING(1, address24);
+ H8_IOP_TIMING(2);
+ }
+ else
+ {
+ // mov.w @ers+, rd
+ srcreg = (opcode>>4)&7;
+ address24 = h8_getreg32(srcreg) & 0xffffff;
+ h8_setreg32(srcreg, h8_getreg32(srcreg)+2);
+ udata16 = h8_mem_read16(address24);
+ h8_setreg16(opcode & 0xf, udata16);
+ H8_IFETCH_TIMING(1);
+ H8_BYTE_TIMING(1, address24);
+ H8_IOP_TIMING(2);
+ }
+ h8_mov16(udata16);
+ break;
+ case 0xe: // pass
+ // mov.b @(displ16 + Rs), rd
+ sdata16=h8_mem_read16(h8.pc); // sign extend displacements !
+ h8.pc += 2;
+ address24 = (h8_getreg32((opcode>>4)&7)) & 0xffffff;
+ address24 += sdata16;
+ if(opcode & 0x80)
+ {
+ udata8 = h8_getreg8(opcode & 0xf);
+ h8_mem_write8(address24, udata8);
+ }
+ else
+ {
+ udata8 = h8_mem_read8(address24);
+ h8_setreg8(opcode & 0xf, udata8);
+ }
+ h8_mov8(udata8);
+ H8_IFETCH_TIMING(2);
+ H8_BYTE_TIMING(1, address24);
+ break;
+ case 0xf:
+ // mov.w @(displ16 + Rs), rd
+ sdata16=h8_mem_read16(h8.pc); // sign extend displacements !
+ h8.pc += 2;
+ address24 = (h8_getreg32((opcode>>4)&7)) & 0xffffff;
+ address24 += sdata16;
+ if(opcode & 0x80)
+ {
+ udata16 = h8_getreg16(opcode & 0xf);
+ h8_mem_write16(address24, udata16);
+ }
+ else
+ {
+ udata16 = h8_mem_read16(address24);
+ h8_setreg16(opcode & 0xf, udata16);
+ }
+ h8_mov16(udata16);
+ H8_IFETCH_TIMING(2);
+ H8_WORD_TIMING(1, address24);
+ break;
+ default:
+ logerror("H8/3002: Unk. group 6 def %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+}
+
+static void h8_group7(UINT16 opcode)
+{
+ switch((opcode>>8)&0xf)
+ {
+ case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:
+ {
+ UINT8 bitnr;
+
+ dstreg = opcode & 0xf;
+ udata8 = h8_getreg8(dstreg);
+ bitnr = (opcode>>4)&7;
+
+ if(((opcode>>4)&0x8) == 0)
+ {
+ switch((opcode>>8)&7)
+ {
+ case 0: udata8 = h8_bset8(bitnr, udata8); h8_setreg8(dstreg, udata8); H8_IFETCH_TIMING(1); break;
+ case 2: udata8 = h8_bclr8(bitnr, udata8); h8_setreg8(dstreg, udata8);H8_IFETCH_TIMING(1);break;
+ case 3: h8_btst8(bitnr, udata8); H8_IFETCH_TIMING(1); break;
+ case 7: h8_bld8(bitnr, udata8); H8_IFETCH_TIMING(1); break;
+ default:
+ logerror("H8/3002: Unk. group 7 0-7 def %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ }
+ else
+ {
+ switch((opcode>>8)&7)
+ {
+ default:
+ logerror("H8/3002: Unk. group 7 0-7-1 def %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ }
+ }
+ break;
+ case 0x8:
+ ext16 = h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ udata32 = h8_mem_read32(h8.pc);
+ h8.pc += 4;
+
+ if(((ext16>>8) & 0xf) == 0xa)
+ {
+ if(((ext16>>4) & 0xf) == 0xa)
+ {
+ udata8 = h8_getreg8(ext16 & 0xf);
+ h8_mov8(udata8); // update flags !
+ udata32 += h8_getreg32((opcode >> 4) & 7);
+ h8_mem_write8(udata32, udata8);
+ }
+ else
+ {
+ udata32 += h8_getreg32((opcode >> 4) & 7);
+ udata8 = h8_mem_read8(udata32);
+ h8_mov8(udata8); // update flags !
+ h8_setreg8(ext16 & 0xf, udata8);
+ }
+ H8_BYTE_TIMING(1, udata32);
+ H8_IFETCH_TIMING(4);
+ }
+ else if ((ext16 & 0xfff0) == 0x6b20) // mov.w @(24-bit direct, rN), rM
+ {
+ udata32 += h8_getreg32((opcode >> 4) & 7);
+ udata16 = h8_mem_read16(udata32);
+ h8_setreg16(ext16 & 0xf, udata16);
+ h8_mov16(udata16); // update flags !
+ H8_WORD_TIMING(1, udata32);
+ H8_IFETCH_TIMING(4);
+ }
+ else if ((ext16 & 0xfff0) == 0x6ba0) // mov.w rM, @(24-bit direct, rN)
+ {
+ udata32 += h8_getreg32((opcode >> 4) & 7);
+ udata16 = h8_getreg16(ext16 & 0xf);
+ h8_mem_write16(udata32, udata16);
+ h8_mov16(udata16); // update flags !
+ H8_WORD_TIMING(1, udata32);
+ H8_IFETCH_TIMING(4);
+ }
+ else
+ {
+ logerror("H8/3002: Unk. group 7 8 %x\n", opcode);
+ h8.h8err = 1;
+ }
+ break;
+
+
+ // xxx.w #aa:16, rd
+ case 0x9:
+ if( ((opcode>>4) & 0xf) > 0x6)
+ {
+ logerror("H8/3002: Unk. group 7 9 %x\n", opcode);
+ h8.h8err = 1;
+ }
+ else
+ {
+ UINT16 dst16;
+ udata16 = h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ dstreg = opcode&0xf;
+ dst16 = h8_getreg16(dstreg);
+
+ switch((opcode>>4)&7)
+ {
+ case 0: dst16 = h8_mov16(udata16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2);break;
+ case 1: dst16 = h8_add16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
+ case 2: h8_cmp16(udata16, dst16); H8_IFETCH_TIMING(2); break;
+ case 3: dst16 = h8_sub16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
+ case 4: dst16 = h8_or16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
+ case 5: dst16 = h8_xor16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
+ case 6: dst16 = h8_and16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
+ default:
+ logerror("H8/3002: Unk. group 7 9 %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ }
+ break;
+ // xxx.l #aa:32, erd
+ case 0xa:
+ if( (((opcode>>4) & 0xf) > 0x6) || (opcode & 0x8))
+ {
+ logerror("H8/3002: Unk. group 7 a %x\n", opcode);
+ h8.h8err = 1;
+ }
+ else
+ {
+ UINT32 dst32;
+ udata32 = h8_mem_read32(h8.pc);
+ dstreg = opcode&0x7;
+ h8.pc +=4;
+ dst32 = h8_getreg32(dstreg);
+
+ switch((opcode>>4)&7)
+ {
+ case 0: dst32 = h8_mov32(udata32); h8_setreg32(dstreg, dst32); H8_IFETCH_TIMING(3); break;
+ case 1: dst32 = h8_add32(udata32, dst32); h8_setreg32(dstreg, dst32); H8_IFETCH_TIMING(3); break;
+ case 2: h8_cmp32(udata32, dst32); H8_IFETCH_TIMING(3); break;
+ case 6: dst32 = h8_and32(udata32, dst32); h8_setreg32(dstreg, dst32); H8_IFETCH_TIMING(3); break;
+ default:
+ logerror("H8/3002: Unk. group 7 a2 %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+ }
+ break;
+ // eepmov
+ case 0xb:
+ if ((opcode & 0xff) == 0xd4)
+ {
+ UINT16 cnt = h8_getreg16(4);
+
+ H8_IFETCH_TIMING(1);
+ H8_BYTE_TIMING((2*cnt)+2, h8.regs[5]);
+
+ // eepmov.w
+ while (cnt > 0)
+ {
+ h8_mem_write8(h8.regs[6], h8_mem_read8(h8.regs[5]));
+ h8.regs[5]++;
+ h8.regs[6]++;
+ cnt--;
+ }
+ h8_setreg16(4, 0);
+ h8.pc += 2;
+ }
+ else
+ {
+ logerror("H8/3002: Unk. eepmov form\n");
+ h8.h8err = 1;
+ }
+ break;
+ // bxx.b #xx:3, @rd
+ case 0xc:
+ {
+ UINT8 bitnr;
+
+ address24 = h8_getreg32((opcode>>4) & 0x7);
+ udata8 = h8_mem_read8(address24);
+ H8_BYTE_TIMING(1, address24);
+
+ ext16 = h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ H8_IFETCH_TIMING(2);
+
+ switch(ext16>>8)
+ {
+ // BTST Rn,@ERd
+ case 0x63:
+ srcreg = (ext16>>4)&0xf;
+ bitnr = h8_getreg8(srcreg)&7;
+ h8_btst8(bitnr, udata8);
+ break;
+ // btst.b #imm, @Rn
+ case 0x73:
+ bitnr = (ext16>>4)&7;
+ h8_btst8(bitnr, udata8);
+ break;
+ default:
+ h8.h8err=1;
+ }
+ }
+ break;
+ case 0xd:
+ {
+ UINT8 bitnr;
+ sdata16 = h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ address24 = h8_getreg32((opcode>>4) & 0x7);
+ udata8 = h8_mem_read8(address24);
+ bitnr = (sdata16>>4)&7;
+
+ if(((sdata16>>4)&0x8) == 0)
+ {
+ switch ((sdata16>>8)&0xff)
+ {
+ // bset.b #imm, @Rn
+ case 0x70: udata8 = h8_bset8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24); break;
+ // bclr.b #imm, @Rn
+ case 0x72: udata8 = h8_bclr8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24); break;
+ default:
+ h8.h8err=1;
+ logerror("H8/3002: Unk. group 7 cd-1 %x (%x)\n", opcode, (sdata16>>4)&7);
+ break;
+ }
+ }
+ else
+ {
+ switch ((sdata16>>8)&7)
+ {
+ default:
+ h8.h8err=1;
+ logerror("H8/3002: Unk. group 7 cd-2 %x %x\n", opcode, sdata16);
+ break;
+ }
+ }
+ }
+ break;
+ // bxxx.b #imm, @aa:8
+ case 0xe:
+ case 0xf:
+ {
+ UINT8 bitnr=0;
+ ext16 = h8_mem_read16(h8.pc);
+ h8.pc += 2;
+ address24 = 0xffff00 + (opcode & 0xff);
+ udata8 = h8_mem_read8(address24);
+
+ switch((ext16>>8)&0xff)
+ {
+ case 0x30:
+ case 0x60:
+ bitnr = (ext16>>4)&7;
+ udata8 = h8_bset8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
+ break;
+ case 0x70:
+ bitnr = (ext16>>4)&7;
+ if(ext16&0x80) h8.h8err = 1;
+ udata8 = h8_bset8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
+ break;
+ case 0x32:
+ case 0x62:
+ bitnr = h8_getreg8((ext16>>4)&0xf)&7;
+ udata8 = h8_bclr8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
+ break;
+ case 0x72:
+ bitnr = (ext16>>4)&7;
+ if(ext16&0x80) h8.h8err = 1;
+ udata8 = h8_bclr8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
+ break;
+ case 0x63:
+ bitnr = h8_getreg8((ext16>>4)&0xf)&7;
+ h8_btst8(bitnr, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(1, address24);
+ break;
+ case 0x73:
+ bitnr = (ext16>>4)&7;
+ if(ext16&0x80) h8.h8err = 1;
+ h8_btst8(bitnr, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(1, address24);
+ break;
+ case 0x74:
+ bitnr = (ext16>>4)&7;
+ if(ext16&0x80)
+ {
+ // bior
+ h8.h8err = 1;
+ }
+ else
+ {
+ h8_bor8(bitnr, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(1, address24);
+ }
+ break;
+ case 0x67:
+ bitnr = (ext16>>4)&7;
+ if(ext16&0x80)
+ {
+ // bist
+ h8.h8err = 1;
+ }
+ else
+ {
+ h8_bst8(bitnr, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
+ }
+ break;
+ case 0x77:
+ bitnr = (ext16>>4)&7;
+ if(ext16&0x80)
+ {
+ // bild
+ h8.h8err = 1;
+ }
+ else
+ {
+ h8_bld8(bitnr, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
+ }
+ break;
+ default:
+ h8.h8err = 1;
+ break;
+ }
+ if(h8.h8err)
+ logerror("H8/3002: Unk. group 7 e %x\n", opcode);
+ }
+ break;
+ default:
+ logerror("H8/3002: Unk. group 7 def %x\n", opcode);
+ h8.h8err = 1;
+ break;
+ }
+}
+
+
+static UINT8 h8_mov8(UINT8 src)
+{
+ // N and Z modified
+ h8.h8nflag = (src>>7) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(src==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return src;
+}
+
+static UINT16 h8_mov16(UINT16 src)
+{
+ // N and Z modified
+ h8.h8nflag = (src>>15) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(src==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+ return src;
+}
+
+static UINT32 h8_mov32(UINT32 src)
+{
+ // N and Z modified
+ h8.h8nflag = (src>>31) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(src==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return src;
+}
+
+static UINT8 h8_sub8(UINT8 src, UINT8 dst)
+{
+ UINT16 res;
+
+ res = (UINT16)dst - src;
+ // H,N,Z,V,C modified
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = (((src^dst) & (res^dst))>>7) & 1;
+ h8.h8cflag = (res >> 8) & 1;
+
+ // zflag
+ if((res&0xff)==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;
+
+ return res;
+}
+
+static UINT16 h8_sub16(UINT16 src, UINT16 dst)
+{
+ UINT32 res;
+
+ res = (UINT32)dst - src;
+ // H,N,Z,V,C modified
+ h8.h8nflag = (res>>15) & 1;
+ h8.h8vflag = (((src^dst) & (res^dst))>>15) & 1;
+ h8.h8cflag = (res >> 16) & 1;
+ // h8.h8hflag = (res>>28) & 1;
+
+ // zflag
+ if((res&0xffff)==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ h8.h8hflag = ((src^dst^res) & 0x1000) ? 1 : 0;
+
+ return res;
+}
+
+static UINT32 h8_sub32(UINT32 src, UINT32 dst)
+{
+ UINT64 res;
+
+ res = (UINT64)dst - src;
+ // H,N,Z,V,C modified
+ h8.h8nflag = (res>>31) & 1;
+ h8.h8vflag = (((src^dst) & (res^dst))>>31) & 1;
+ h8.h8cflag = (res >> 32) & 1;
+ // h8.h8hflag = (res>>28) & 1;
+
+ // zflag
+ if((res&0xffffffff)==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ h8.h8hflag = ((src^dst^res) & 0x10000000) ? 1 : 0;
+
+ return res;
+}
+
+
+
+
+static UINT8 h8_add8(UINT8 src, UINT8 dst)
+{
+ UINT16 res;
+
+ res = (UINT16)src + dst;
+ // H,N,Z,V,C modified
+ h8.h8nflag = (res & 0x80) ? 1 : 0;
+ h8.h8vflag = ((src^res) & (dst^res) & 0x80) ? 1 : 0;
+ h8.h8cflag = (res & 0x100) ? 1 : 0;
+ h8.h8zflag = (res & 0xff) ? 0 : 1;
+ h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;
+
+ return (UINT8)res;
+}
+
+static UINT16 h8_add16(UINT16 src, UINT16 dst)
+{
+ UINT32 res;
+
+ res = (UINT32)src + dst;
+ // H,N,Z,V,C modified
+ h8.h8nflag = (res & 0x8000) ? 1 : 0;
+ h8.h8vflag = ((src^res) & (dst^res) & 0x8000) ? 1 : 0;
+ h8.h8cflag = (res & 0x10000) ? 1 : 0;
+ h8.h8zflag = (res & 0xffff) ? 0 : 1;
+ h8.h8hflag = ((src^dst^res) & 0x1000) ? 1 : 0;
+
+ return res;
+}
+
+static UINT32 h8_add32(UINT32 src, UINT32 dst)
+{
+ UINT64 res;
+
+ res = (UINT64)src + dst;
+ // H,N,Z,V,C modified
+ h8.h8nflag = (res & 0x80000000) ? 1 : 0;
+ h8.h8vflag = (((src^res) & (dst^res)) & 0x80000000) ? 1 : 0;
+ h8.h8cflag = ((res) & (((UINT64)1) << 32)) ? 1 : 0;
+ h8.h8zflag = (res & 0xffffffff) ? 0 : 1;
+ h8.h8hflag = ((src^dst^res) & 0x10000000) ? 1 : 0;
+
+ return res;
+}
+
+
+static UINT8 h8_addx8(UINT8 src, UINT8 dst)
+{
+ UINT16 res;
+
+ res = (UINT16)src + dst + h8.h8cflag;
+ // H,N,Z,V,C modified
+ h8.h8nflag = (res & 0x80) ? 1 : 0;
+ h8.h8vflag = ((src^res) & (dst^res) & 0x80) ? 1 : 0;
+ h8.h8cflag = (res >> 8) & 1;
+ h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;
+ h8.h8zflag = (res & 0xff) ? 0 : h8.h8zflag;
+
+ return (UINT8)res;
+}
+
+static void h8_cmp8(UINT8 src, UINT8 dst)
+{
+ UINT16 res = (UINT16)dst - src;
+
+ h8.h8cflag = (res & 0x100) ? 1 : 0;
+ h8.h8vflag = (((dst) ^ (src)) & ((dst) ^ (res)) & 0x80) ? 1 : 0;
+ h8.h8zflag = ((res & 0xff) == 0) ? 1 : 0;
+ h8.h8nflag = (res & 0x80) ? 1 : 0;
+ h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;
+}
+
+static void h8_cmp16(UINT16 src, UINT16 dst)
+{
+ UINT32 res = (UINT32)dst - src;
+
+ h8.h8cflag = (res & 0x10000) ? 1 : 0;
+ h8.h8vflag = (((dst) ^ (src)) & ((dst) ^ (res)) & 0x8000) ? 1 : 0;
+ h8.h8zflag = ((res & 0xffff) == 0) ? 1 : 0;
+ h8.h8nflag = (res & 0x8000) ? 1 : 0;
+ h8.h8hflag = ((src^dst^res) & 0x1000) ? 1 : 0;
+}
+
+static void h8_cmp32(UINT32 src, UINT32 dst)
+{
+ UINT64 res = (UINT64)dst - src;
+
+ h8.h8cflag = (res & (UINT64)U64(0x100000000)) ? 1 : 0;
+ h8.h8vflag = (((dst) ^ (src)) & ((dst) ^ (res)) & 0x80000000) ? 1 : 0;
+ h8.h8zflag = ((res & 0xffffffff) == 0) ? 1 : 0;
+ h8.h8nflag = (res & 0x80000000) ? 1 : 0;
+ h8.h8hflag = ((src^dst^res) & 0x10000000) ? 1 : 0;
+}
+
+
+static UINT8 h8_subx8(UINT8 src, UINT8 dst)
+{
+ UINT16 res;
+
+ res = (UINT16)dst - src - (h8.h8cflag) ? 1 : 0;
+ // H,N,Z,V,C modified
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = (((src^dst) & (res^dst))>>7) & 1;
+ h8.h8cflag = (res >> 8) & 1;
+
+ // zflag
+ if((res&0xff)==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;
+
+ return res;
+}
+
+static UINT8 h8_or8(UINT8 src, UINT8 dst)
+{
+ UINT8 res;
+ res = src | dst;
+
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_or16(UINT16 src, UINT16 dst)
+{
+ UINT16 res;
+ res = src | dst;
+
+ h8.h8nflag = (res>>15) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT8 h8_xor8(UINT8 src, UINT8 dst)
+{
+ UINT8 res;
+ res = src ^ dst;
+
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_xor16(UINT16 src, UINT16 dst)
+{
+ UINT16 res;
+ res = src ^ dst;
+
+ h8.h8nflag = (res>>15) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT32 h8_xor32(UINT32 src, UINT32 dst)
+{
+ UINT32 res;
+ res = src ^ dst;
+
+ h8.h8nflag = (res>>31) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT8 h8_and8(UINT8 src, UINT8 dst)
+{
+ UINT8 res;
+
+ res = src & dst;
+ // N and Z modified
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_and16(UINT16 src, UINT16 dst)
+{
+ UINT16 res;
+
+ res = src & dst;
+ // N and Z modified
+ h8.h8nflag = (res>>15) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT32 h8_and32(UINT32 src, UINT32 dst)
+{
+ UINT32 res;
+
+ res = src & dst;
+ // N and Z modified
+ h8.h8nflag = (res>>31) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static void h8_btst8(UINT8 bit, UINT8 dst)
+{
+ // test single bit and update Z flag
+ if( (dst & (1<<bit)) == 0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+}
+
+static void h8_bld8(UINT8 bit, UINT8 dst)
+{
+ // load bit to carry
+ h8.h8cflag = (dst >> bit) & 1;
+}
+
+#ifdef UNUSED_FUNCTION
+static UINT8 h8_bnot8(UINT8 src, UINT8 dst)
+{
+ UINT8 res;
+
+ // invert single bit, no effect on C flag
+ res = dst ^ (1<<src);
+
+ return res;
+}
+#endif
+
+static UINT8 h8_bst8(UINT8 src, UINT8 dst)
+{
+ UINT8 res;
+
+ // store carry flag in bit position
+ if(h8.h8cflag == 1)
+ {
+ res = dst | (1<<src);
+ }
+ else
+ {
+ res = dst & ~(1<<src); // mask off
+ }
+ return res;
+}
+
+static UINT8 h8_bist8(UINT8 src, UINT8 dst)
+{
+ UINT8 res;
+
+ // store inverse of carry flag in bit position
+ if(h8.h8cflag == 0)
+ {
+ res = dst | (1<<src);
+ }
+ else
+ {
+ res = dst & ~(1<<src); // mask off
+ }
+ return res;
+}
+
+static UINT8 h8_bset8(UINT8 src, UINT8 dst)
+{
+ // pass
+ UINT8 res;
+ res = dst | (1<<src);
+ return res;
+}
+
+// does not affect result, res in C flag only
+static void h8_bor8(UINT8 src, UINT8 dst)
+{
+ // pass
+ UINT8 res;
+
+ res = dst & (1<<src);
+ h8.h8cflag |= res ? 1 : 0;
+}
+
+#ifdef UNUSED_FUNCTION
+static void h8_bxor8(UINT8 src, UINT8 dst)
+{
+ dst >>= src;
+ dst &= 0x1;
+ h8.h8cflag ^= dst;
+}
+#endif
+
+static UINT8 h8_bclr8(UINT8 src, UINT8 dst)
+{
+ // pass
+ UINT8 res;
+ res = dst & ~(1<<src);
+ return res;
+}
+
+static INT8 h8_neg8(INT8 src)
+{
+ INT8 res;
+
+ if((UINT8)src == 0x80)
+ {
+ // overflow !
+ h8.h8vflag = 1;
+ res = 0x80;
+ }
+ else
+ {
+ h8.h8vflag = 0;
+ res = 0-src;
+ }
+
+ // N and Z modified
+ h8.h8nflag = (res>>7) & 1;
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ h8.h8hflag = ((src|res)&0x08) ? 1 : 0;
+ h8.h8cflag = ((src|res)&0x80) ? 1 : 0;
+
+ return res;
+}
+
+static INT16 h8_neg16(INT16 src)
+{
+ INT16 res;
+
+ if((UINT16)src == 0x8000)
+ {
+ // overflow !
+ h8.h8vflag = 1;
+ res = 0x8000;
+ }
+ else
+ {
+ h8.h8vflag = 0;
+ res = 0-src;
+ }
+
+ // N and Z modified
+ h8.h8nflag = (res>>15) & 1;
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ h8.h8hflag = ((src|res)&0x0800) ? 1 : 0;
+ h8.h8cflag = ((src|res)&0x8000) ? 1 : 0;
+
+ return res;
+}
+
+static UINT8 h8_not8(UINT8 src)
+{
+ UINT8 res;
+
+ res = ~src;
+
+ // N and Z modified
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_not16(UINT16 src)
+{
+ UINT16 res;
+
+ res = ~src;
+
+ // N and Z modified
+ h8.h8nflag = (res>>15) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT8 h8_rotxr8(UINT8 src)
+{
+ UINT8 res;
+
+ // rotate through carry right
+ res = src>>1;
+ if(h8.h8cflag)res |= 0x80; // put cflag in upper bit
+ h8.h8cflag = src & 1;
+
+ // N and Z modified
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_rotxr16(UINT16 src)
+{
+ UINT16 res;
+
+ // rotate through carry right
+ res = src>>1;
+ if(h8.h8cflag)res |= 0x8000; // put cflag in upper bit
+ h8.h8cflag = src & 1;
+
+ // N and Z modified
+ h8.h8nflag = (res>>15) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT8 h8_rotxl8(UINT8 src)
+{
+ UINT8 res;
+
+ // rotate through carry
+ res = src<<1;
+ res |= (h8.h8cflag & 1);
+ h8.h8cflag = (src>>7) & 1;
+
+ // N and Z modified
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_rotxl16(UINT16 src)
+{
+ UINT16 res;
+
+ // rotate through carry
+ res = src<<1;
+ res |= (h8.h8cflag & 1);
+ h8.h8cflag = (src>>15) & 1;
+
+ // N and Z modified
+ h8.h8nflag = (res>>15) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT32 h8_rotxl32(UINT32 src)
+{
+ UINT32 res;
+
+ // rotate through carry
+ res = src<<1;
+ res |= (h8.h8cflag & 1);
+ h8.h8cflag = (src>>31) & 1;
+
+ // N and Z modified
+ h8.h8nflag = (res>>31) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+
+static UINT8 h8_rotl8(UINT8 src)
+{
+ UINT8 res;
+
+ // rotate
+ res = src<<1;
+ h8.h8cflag = (src>>7) & 1;
+ res |= (h8.h8cflag & 1);
+
+ // N and Z modified
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_rotl16(UINT16 src)
+{
+ UINT16 res;
+
+ // rotate
+ res = src<<1;
+ h8.h8cflag = (src>>15) & 1;
+ res |= (h8.h8cflag & 1);
+
+ // N and Z modified
+ h8.h8nflag = (res>>15) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT8 h8_shll8(UINT8 src)
+{
+ UINT8 res;
+ h8.h8cflag = (src>>7) & 1;
+ res = src<<1;
+ // N and Z modified
+ h8.h8nflag = (res>>7) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_shll16(UINT16 src)
+{
+ UINT16 res;
+ h8.h8cflag = (src>>15) & 1;
+ res = src<<1;
+ // N and Z modified
+ h8.h8nflag = (res>>15) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT32 h8_shll32(UINT32 src)
+{
+ UINT32 res;
+ h8.h8cflag = (src>>31) & 1;
+ res = src<<1;
+ // N and Z modified
+ h8.h8nflag = (res>>31) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT8 h8_shlr8(UINT8 src)
+{
+ UINT8 res;
+ h8.h8cflag = src&1;
+ res = src>>1;
+ // N and Z modified
+ h8.h8nflag = 0;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_shlr16(UINT16 src)
+{
+ UINT16 res;
+ h8.h8cflag = src&1;
+ res = src>>1;
+ // N and Z modified
+ h8.h8nflag = 0;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT32 h8_shlr32(UINT32 src)
+{
+ UINT32 res;
+ h8.h8cflag = src&1;
+ res = src>>1;
+
+ // N and Z modified, V always cleared
+ h8.h8nflag = 0;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static INT8 h8_shar8(INT8 src)
+{
+ INT8 res;
+ h8.h8cflag = src&1;
+ res = (src>>1)|(src&0x80);
+ // N and Z modified
+ h8.h8nflag = (res>>7)&1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static INT16 h8_shar16(INT16 src)
+{
+ INT16 res;
+ h8.h8cflag = src&1;
+ res = (src>>1)|(src&0x8000);
+ // N and Z modified
+ h8.h8nflag = (res>>15)&1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static INT32 h8_shar32(INT32 src)
+{
+ INT32 res;
+
+ h8.h8cflag = src&1;
+ res = (src>>1)|(src&0x80000000);
+ // N and Z modified
+ h8.h8nflag = (res>>31) & 1;
+ h8.h8vflag = 0;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static INT8 h8_shal8(INT8 src)
+{
+ INT8 res;
+
+ h8.h8cflag = (src>>7)&1;
+ res = src<<1;
+ // N and Z modified
+ h8.h8nflag = (res>>7)&1;
+ h8.h8vflag = (((src>>7)&(~src>>6)) | ((~src>>7)&(~src>>6)))&1;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static INT16 h8_shal16(INT16 src)
+{
+ INT16 res;
+
+ h8.h8cflag = (src>>15)&1;
+ res = src<<1;
+ // N and Z modified
+ h8.h8nflag = (res>>15)&1;
+ h8.h8vflag = (((src>>15)&(~src>>14)) | ((~src>>15)&(~src>>14)))&1;
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT8 h8_dec8(UINT8 src)
+{
+ UINT8 res;
+
+ res = src - 1;
+ // N and Z modified
+ h8.h8nflag = (res>>7)&1;
+ if(src == 0x80)
+ {
+ h8.h8vflag = 1;
+ }
+ else
+ {
+ h8.h8vflag = 0;
+ }
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_dec16(UINT16 src)
+{
+ UINT16 res;
+
+ res = src - 1;
+ // N and Z modified
+ h8.h8nflag = (res>>15)&1;
+ if(src == 0x8000)
+ {
+ h8.h8vflag = 1;
+ }
+ else
+ {
+ h8.h8vflag = 0;
+ }
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT32 h8_dec32(UINT32 src)
+{
+ UINT32 res;
+
+ res = src - 1;
+ // N and Z modified
+ h8.h8nflag = (res>>31)&1;
+ if(src == 0x80000000)
+ {
+ h8.h8vflag = 1;
+ }
+ else
+ {
+ h8.h8vflag = 0;
+ }
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT8 h8_inc8(UINT8 src)
+{
+ UINT8 res;
+
+ res = src + 1;
+ // N and Z modified
+ h8.h8nflag = (res>>7)&1;
+ if(src == 0x7f)
+ {
+ h8.h8vflag = 1;
+ }
+ else
+ {
+ h8.h8vflag = 0;
+ }
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT16 h8_inc16(UINT16 src)
+{
+ UINT16 res;
+
+ res = src + 1;
+ // N and Z modified
+ h8.h8nflag = (res>>15)&1;
+ if(src == 0x7fff)
+ {
+ h8.h8vflag = 1;
+ }
+ else
+ {
+ h8.h8vflag = 0;
+ }
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static UINT32 h8_inc32(UINT32 src)
+{
+ UINT32 res;
+
+ res = src + 1;
+ // N and Z modified
+ h8.h8nflag = (res>>31)&1;
+ if(src == 0x7fffffff)
+ {
+ h8.h8vflag = 1;
+ }
+ else
+ {
+ h8.h8vflag = 0;
+ }
+
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+
+ return res;
+}
+
+static INT32 h8_mulxs16(INT16 src, INT16 dst)
+{
+ INT32 res;
+
+ res = (INT32)src * dst;
+
+ // N and Z modified
+ h8.h8nflag = (res>>31)&1;
+ // zflag
+ if(res==0)
+ {
+ h8.h8zflag = 1;
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ }
+ return res;
+}
+
+static UINT32 h8_divxs16(INT16 src, INT32 dst)
+{
+ // NOT tested !
+ UINT32 res,r1,r2;
+ INT16 remainder, quotient;
+
+ if(src!=0)
+ {
+ quotient = dst/src;
+ h8.h8zflag = 0;
+ }
+ else
+ {
+ quotient = 0;
+ h8.h8zflag = 1;
+ }
+ remainder = dst%src;
+
+ r1=*(&quotient);
+ r2=*(&remainder);
+ res=(r2<<16)|r1;
+
+ h8.h8nflag = (quotient<0)?1:0;
+
+ return res;
+
+}
+
+static UINT16 h8_divxu8(UINT16 dst, UINT8 src)
+{
+ UINT8 remainder, quotient;
+ UINT16 res = 0;
+ // N and Z modified
+ h8.h8nflag = (src>>7)&1;
+ // zflag
+ if(src==0)
+ {
+ h8.h8zflag = 1;
+ // dont do anything on division by zero !
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ quotient = dst / src;
+ remainder = dst % src;
+ res = (remainder << 8) | quotient;
+ }
+ return res;
+}
+
+static UINT32 h8_divxu16(UINT32 dst, UINT16 src)
+{
+ UINT16 remainder, quotient;
+ UINT32 res = 0;
+ // N and Z modified
+ h8.h8nflag = (src>>15)&1;
+ // zflag
+ if(src==0)
+ {
+ h8.h8zflag = 1;
+ // dont do anything on division by zero !
+ }
+ else
+ {
+ h8.h8zflag = 0;
+ quotient = dst / src;
+ remainder = dst % src;
+ res = (remainder << 16) | quotient;
+ }
+ return res;
+}
+
+// input: branch condition
+// output: 1 if condition met, 0 if not condition met
+static int h8_branch(UINT8 condition)
+{
+ int taken = 0;
+
+ // a branch always eats 2 ifetch states, regardless of if it's taken
+ H8_IFETCH_TIMING(2)
+
+ switch(condition)
+ {
+ case 0: // bt
+ taken = 1;
+ break;
+ case 1: // bf
+ break;
+ case 2: // bhi (C | Z) == 0)
+ if((h8.h8cflag | h8.h8zflag) == 0)taken = 1;
+ break;
+ case 3: // bls
+ if((h8.h8cflag | h8.h8zflag) == 1)taken = 1;
+ break;
+ case 4: // bcc C = 0
+ if(h8.h8cflag == 0)taken = 1;
+ break;
+ case 5: // bcs C = 1
+ if(h8.h8cflag == 1)taken = 1;
+ break;
+ case 6: // bne Z = 0
+ if(h8.h8zflag == 0)taken = 1;
+ break;
+ case 7: // beq Z = 1
+ if(h8.h8zflag == 1)taken = 1;
+ break;
+ case 8: // bvc V = 0
+ h8.h8err = 1;
+ if(h8.h8vflag == 0)taken = 1;
+ break;
+ case 9: // bvs V = 1
+ h8.h8err = 1;
+ if(h8.h8vflag == 1)taken = 1;
+ break;
+ case 0xa: // bpl N = 0
+ if(h8.h8nflag == 0)taken = 1;
+ break;
+ case 0xb: // bmi N = 1
+ if(h8.h8nflag == 1)taken = 1;
+ break;
+ case 0xc: // bge (N ^ V) = 0
+ if((h8.h8nflag ^ h8.h8vflag) == 0)taken = 1;
+ break;
+ case 0xd: // blt (N ^ V) = 1
+ if((h8.h8nflag ^ h8.h8vflag) == 1)taken = 1;
+ break;
+ case 0xe: // bgt (Z | (N ^ V)) = 0
+ if((h8.h8zflag | (h8.h8nflag ^ h8.h8vflag)) == 0)taken = 1;
+ break;
+ case 0xf: // ble (Z | (N ^ V)) = 1
+ if((h8.h8zflag | (h8.h8nflag ^ h8.h8vflag)) == 1)taken = 1;
+ break;
+ }
+ return taken;
+}
+
+// MAME interface stuff
+
+static void h8_get_context(void *context)
+{
+ *(h83002_state *)context = h8;
+}
+
+static void h8_set_context(void *context)
+{
+ h8 = *(h83002_state *)context;
+}
+
+static void h8_set_info(UINT32 state, cpuinfo *info)
+{
+ switch(state) {
+ case CPUINFO_INT_PC: h8.pc = info->i; change_pc(h8.pc); break;
+ case CPUINFO_INT_REGISTER + H8_PC: h8.pc = info->i; change_pc(h8.pc); break;
+ case CPUINFO_INT_REGISTER + H8_CCR: h8_set_ccr(info->i); break;
+
+ case CPUINFO_INT_REGISTER + H8_E0: h8.regs[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + H8_E1: h8.regs[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + H8_E2: h8.regs[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + H8_E3: h8.regs[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + H8_E4: h8.regs[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + H8_E5: h8.regs[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + H8_E6: h8.regs[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + H8_E7: h8.regs[7] = info->i; break;
+
+ case CPUINFO_INT_INPUT_STATE + H8_IRQ0: if (info->i) h8_3002_InterruptRequest(12); break;
+ case CPUINFO_INT_INPUT_STATE + H8_IRQ1: if (info->i) h8_3002_InterruptRequest(13); break;
+ case CPUINFO_INT_INPUT_STATE + H8_IRQ2: if (info->i) h8_3002_InterruptRequest(14); break;
+ case CPUINFO_INT_INPUT_STATE + H8_IRQ3: if (info->i) h8_3002_InterruptRequest(15); break;
+ case CPUINFO_INT_INPUT_STATE + H8_IRQ4: if (info->i) h8_3002_InterruptRequest(16); break;
+ case CPUINFO_INT_INPUT_STATE + H8_IRQ5: if (info->i) h8_3002_InterruptRequest(17); break;
+
+ default:
+ fatalerror("h8_set_info unknown request %x", state);
+ break;
+ }
+}
+
+static READ16_HANDLER( h8_itu_r )
+{
+ if (mem_mask == 0)
+ {
+ // 16-bit read
+ return h8_register_read8(offset*2 + 0xffff10)<<8 | h8_register_read8((offset*2) + 1 + 0xffff10);
+ }
+ else if (mem_mask == 0xff)
+ {
+ return h8_register_read8(offset*2 + 0xffff10)<<8;
+ }
+ else if (mem_mask == 0xff00)
+ {
+ return h8_register_read8((offset*2) + 1 + 0xffff10);
+ }
+
+ return 0;
+}
+
+static WRITE16_HANDLER( h8_itu_w )
+{
+ if (mem_mask == 0)
+ {
+ // 16-bit write
+ h8_register_write8(offset*2 + 0xffff10, data>>8);
+ h8_register_write8((offset*2) + 1 + 0xffff10, data&0xff);
+ }
+ else if (mem_mask == 0xff)
+ {
+ h8_register_write8(offset*2 + 0xffff10, data>>8);
+ }
+ else if (mem_mask == 0xff00)
+ {
+ h8_register_write8((offset*2) + 1 + 0xffff10, data&0xff);
+ }
+}
+
+// On-board RAM and peripherals
+static ADDRESS_MAP_START( h8_internal_map, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0xfffd10, 0xffff0f) AM_RAM
+ AM_RANGE(0xffff10, 0xffffff) AM_READWRITE( h8_itu_r, h8_itu_w )
+ADDRESS_MAP_END
+
+void h8_3002_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state) {
+ // Interface functions and variables
+ case CPUINFO_PTR_SET_INFO: info->setinfo = h8_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = h8_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext= h8_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = h8_init; break;
+ case CPUINFO_PTR_RESET: info->reset = h8_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = 0; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = h8_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = 0; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = h8_disasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &h8_cyccnt; break;
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(h83002_state); break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 10; break;
+
+ // Bus sizes
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ // Internal maps
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_h8_internal_map; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO: info->internal_map = 0; break;
+
+ // CPU misc parameters
+ case CPUINFO_STR_NAME: strcpy(info->s, "H8/3002"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_FLAGS: strcpy(info->s, h8_get_ccr_str()); break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 16; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = -1; break;
+
+ // CPU main state
+ case CPUINFO_INT_PC: info->i = h8.pc; break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = h8.ppc; break;
+
+ case CPUINFO_INT_REGISTER + H8_PC: info->i = h8.pc; break;
+ case CPUINFO_INT_REGISTER + H8_CCR: info->i = h8_get_ccr(); break;
+
+ case CPUINFO_INT_REGISTER + H8_E0: info->i = h8.regs[0]; break;
+ case CPUINFO_INT_REGISTER + H8_E1: info->i = h8.regs[1]; break;
+ case CPUINFO_INT_REGISTER + H8_E2: info->i = h8.regs[2]; break;
+ case CPUINFO_INT_REGISTER + H8_E3: info->i = h8.regs[3]; break;
+ case CPUINFO_INT_REGISTER + H8_E4: info->i = h8.regs[4]; break;
+ case CPUINFO_INT_REGISTER + H8_E5: info->i = h8.regs[5]; break;
+ case CPUINFO_INT_REGISTER + H8_E6: info->i = h8.regs[6]; break;
+ case CPUINFO_INT_REGISTER + H8_E7: info->i = h8.regs[7]; break;
+
+ // CPU debug stuff
+ case CPUINFO_STR_REGISTER + H8_PC: sprintf(info->s, "PC :%08x", h8.pc); break;
+ case CPUINFO_STR_REGISTER + H8_CCR: sprintf(info->s, "CCR :%08x", h8_get_ccr()); break;
+
+ case CPUINFO_STR_REGISTER + H8_E0: sprintf(info->s, "ER0 :%08x", h8.regs[0]); break;
+ case CPUINFO_STR_REGISTER + H8_E1: sprintf(info->s, "ER1 :%08x", h8.regs[1]); break;
+ case CPUINFO_STR_REGISTER + H8_E2: sprintf(info->s, "ER2 :%08x", h8.regs[2]); break;
+ case CPUINFO_STR_REGISTER + H8_E3: sprintf(info->s, "ER3 :%08x", h8.regs[3]); break;
+ case CPUINFO_STR_REGISTER + H8_E4: sprintf(info->s, "ER4 :%08x", h8.regs[4]); break;
+ case CPUINFO_STR_REGISTER + H8_E5: sprintf(info->s, "ER5 :%08x", h8.regs[5]); break;
+ case CPUINFO_STR_REGISTER + H8_E6: sprintf(info->s, "ER6 :%08x", h8.regs[6]); break;
+ case CPUINFO_STR_REGISTER + H8_E7: sprintf(info->s, " SP :%08x", h8.regs[7]); break;
+ }
+}
diff --git a/src/emu/cpu/h83002/h83002.h b/src/emu/cpu/h83002/h83002.h
new file mode 100644
index 00000000000..480b14a46fa
--- /dev/null
+++ b/src/emu/cpu/h83002/h83002.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+
+ h83002.h : Public constants and function defs for the H8/3002 emulator.
+
+****************************************************************************/
+
+#ifndef _H83002_H_
+#define _H83002_H_
+
+#include "cpuintrf.h"
+
+#define IFLAG 0x80
+#define UIFLAG 0x40
+#define HFLAG 0x20
+#define UFLAG 0x10
+#define NFLAG 0x08
+#define ZFLAG 0x04
+#define VFLAG 0x02
+#define CFLAG 0x01
+
+enum
+{
+ H8_E0 = 1,
+ H8_E1,
+ H8_E2,
+ H8_E3,
+ H8_E4,
+ H8_E5,
+ H8_E6,
+ H8_E7,
+
+ H8_PC,
+ H8_CCR
+};
+
+// external interrupt lines
+enum
+{
+ H8_IRQ0 = 0,
+ H8_IRQ1,
+ H8_IRQ2,
+ H8_IRQ3,
+ H8_IRQ4,
+ H8_IRQ5
+};
+
+// I/O ports
+enum
+{
+ // digital I/O ports
+ H8_PORT4 = 0, // 0
+ H8_PORT6, // 1
+ H8_PORT7, // 2
+ H8_PORT8, // 3
+ H8_PORT9, // 4
+ H8_PORTA, // 5
+ H8_PORTB, // 6
+
+ // analog inputs
+ H8_ADC_0_H = 0x10,
+ H8_ADC_0_L,
+ H8_ADC_1_H,
+ H8_ADC_1_L,
+ H8_ADC_2_H,
+ H8_ADC_2_L,
+ H8_ADC_3_H,
+ H8_ADC_3_L,
+
+ // serial ports
+ H8_SERIAL_A = 0x20,
+ H8_SERIAL_B
+};
+
+void h8_3002_get_info(UINT32 state, cpuinfo *info);
+
+void h8_3002_InterruptRequest(UINT8 source);
+
+#endif
diff --git a/src/emu/cpu/h83002/h8disasm.c b/src/emu/cpu/h83002/h8disasm.c
new file mode 100644
index 00000000000..d4cbabf523f
--- /dev/null
+++ b/src/emu/cpu/h83002/h8disasm.c
@@ -0,0 +1,1230 @@
+/***************************************************************************
+
+ h8disasm.c: Hitachi H8/3000 series disassembler
+
+ Original by The_Author & DynaChicken for the ZiNc emulator.
+
+ MAME version, portability cleanups, and bugfixes by R. Belmont
+
+****************************************************************************/
+
+#include "debugger.h"
+#include "h83002.h"
+
+static const char *bit_instr[8] = {"bset", "bnot", "bclr", "btst", "bor", "bxor", "band", "bld"};
+static const char *bit_instr2[8] = {"bset", "bnot", "bclr", "btst", "bior", "bixor", "biand", "bild"};
+static const char *imm32l_instr[8] = {"mov", "add", "cmp", "sub", "or", "xor", "and", "?"};
+static const char *branch_instr[16] = {"bt", "bf", "bhi", "bls", "bcc", "bcs", "bne", "beq", "bvc", "bvs", "bpl", "bmi", "bge", "blt", "bgt", "ble"};
+static const char *reg_names32[8] = {"ER0", "ER1", "ER2", "ER3", "ER4", "ER5", "ER6", "SP"};
+static const char *reg_names16[16] = {"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7"};
+static const char *reg_names8[16] = {"R0H", "R1H", "R2H", "R3H", "R4H", "R5H", "R6H", "R7H","R0L", "R1L", "R2L", "R3L", "R4L", "R5L", "R6L", "R7L"};
+
+static UINT32 h8disasm_0(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom);
+static UINT32 h8disasm_1(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom);
+static UINT32 h8disasm_5(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom);
+static UINT32 h8disasm_6(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom);
+static UINT32 h8disasm_7(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom);
+
+#define h8_mem_read16(x) ((oprom[x] << 8) | oprom[(x) + 1])
+#define h8_mem_read32(x) ((oprom[x] << 24) | (oprom[(x) + 1] << 16) | (oprom[(x) + 2] << 8) | oprom[(x) + 3])
+
+offs_t h8_disasm(char *output, offs_t address, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 size = 0;
+ UINT16 opcode;
+
+ opcode = h8_mem_read16(0);
+
+ switch((opcode>>12) & 0xf)
+ {
+ case 0x0:
+ size = h8disasm_0(address, opcode, output, oprom);
+ break;
+ case 0x1:
+ size = h8disasm_1(address, opcode, output, oprom);
+ break;
+ // mov.b @xx:8, Rd (abs)
+ case 0x2:
+ sprintf(output, "%4.4x mov.b @%8.8x, %s", opcode, 0xffff00 | (opcode & 0xff), reg_names8[(opcode>>8) & 0xf]);
+ size = 2;
+ break;
+ // mov.b Rs, @xx:8 (abs)
+ case 0x3:
+ sprintf(output, "%4.4x mov.b %s, @%8.8x", opcode, reg_names8[(opcode>>8) & 0xf], 0xfffff00 | (opcode & 0xff));
+ size = 2;
+ break;
+ // bcc @xx:8
+ case 0x4:
+ address += 2;
+ sprintf(output, "%4.4x %s %8.8x", opcode, branch_instr[(opcode >> 8) & 0xf], address + (INT8)(opcode &0xff));
+ size = 2;
+ break;
+ // group 5
+ case 0x5:
+ size = h8disasm_5(address, opcode, output, oprom);
+ break;
+ case 0x6:
+ size = h8disasm_6(address, opcode, output, oprom);
+ break;
+ case 0x7:
+ size = h8disasm_7(address, opcode, output, oprom);
+ break;
+ case 0x8:
+ // add.b #xx:8, Rd
+ sprintf(output, "%4.4x add.b #%2.2x, %s", opcode, opcode & 0xff, reg_names8[(opcode>>8) & 0xf]);
+ size = 2;
+ break;
+ case 0x9:
+ // addx.b #xx:8, Rd
+ sprintf(output, "%4.4x addx.b #%2.2x, %s", opcode, opcode & 0xff, reg_names8[(opcode>>8) & 0xf]);
+ size = 2;
+ break;
+ case 0xa:
+ // cmp.b #xx:8, Rd
+ sprintf(output, "%4.4x cmp.b #%2.2x, %s", opcode, opcode & 0xff, reg_names8[(opcode>>8) & 0xf]);
+ size = 2;
+ break;
+ case 0xb:
+ // subx.b #xx:8, Rd
+ sprintf(output, "%4.4x subx.b #%2.2x, %s", opcode, opcode & 0xff, reg_names8[(opcode>>8) & 0xf]);
+ size = 2;
+ break;
+ case 0xc:
+ // or.b #xx:8, Rd
+ sprintf(output, "%4.4x or.b #%2.2x, %s", opcode, opcode & 0xff, reg_names8[(opcode>>8) & 0xf]);
+ size = 2;
+ break;
+ case 0xd:
+ // xor.b #xx:8, Rd
+ sprintf(output, "%4.4x xor.b #%2.2x, %s", opcode, opcode & 0xff, reg_names8[(opcode>>8) & 0xf]);
+ size = 2;
+ break;
+ case 0xe:
+ // and.b #xx:8, Rd
+ sprintf(output, "%4.4x and.b #%2.2x, %s", opcode, opcode & 0xff, reg_names8[(opcode>>8) & 0xf]);
+ size = 2;
+ break;
+ // mov.b #xx:8, Rd
+ case 0xf:
+ sprintf(output, "%4.4x mov.b #%2.2x, %s", opcode, opcode & 0xff, reg_names8[(opcode>>8) & 0xf]);
+ size = 2;
+ break;
+ default:
+ sprintf(output, "%4.4x", opcode);
+ size = 2;
+ break;
+ }
+
+ return size | DASMFLAG_SUPPORTED;
+}
+
+static UINT32 h8disasm_0(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom)
+{
+ UINT32 size = 2;
+ UINT16 data16;
+ INT16 sdata16;
+ INT32 sdata32;
+ UINT16 ext16;
+
+ switch((opcode>>8)&0xf)
+ {
+ // nop
+ case 0:
+ sprintf(output, "%4.4x nop", opcode);
+ size = 2;
+ break;
+ case 0x1:
+ // 010x where x should always be 0!
+ if((opcode & 0xf) != 0)
+ {
+ sprintf(output, "%4.4x default", opcode);
+ break;
+ }
+ switch((opcode>>4) & 0xf)
+ {
+ // 0100 mov.l prefix
+ case 0:
+ data16 = h8_mem_read16(2);
+ switch((data16>>8) & 0xff)
+ {
+ case 0x69:
+ // mov.l @rx, rx
+ if((data16 & 0x80) == 0x80)
+ {
+ sprintf(output, "%4.4x mov.l %s, @%s", opcode, reg_names32[data16&7], reg_names32[(data16>>4)&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.l @%s, %s", opcode, reg_names32[(data16>>4)&7], reg_names32[data16&7]);
+ }
+ size = 4;
+ break;
+ case 0x6b:
+ // mov.l @aa:x, Rx
+ // 24 bit abs ?
+ if((data16 & 0x20 )==0x20)
+ {
+ sdata32 = h8_mem_read32(4);
+ sdata32 &= 0xffffff;
+ size = 8;
+ }
+ else
+ {
+ sdata16 = h8_mem_read16(4);
+ sdata32 = sdata16;
+ size = 6;
+ }
+ if((data16 & 0x80) == 0x80)
+ {
+ sprintf(output, "%4.4x %x mov.l %s, @%x", opcode, data16, reg_names32[data16&7], sdata32);
+ }
+ else
+ {
+ sprintf(output, "%4.4x %x mov.l @%x, %s", opcode, data16, sdata32, reg_names32[data16&7]);
+ }
+ break;
+ case 0x6d:
+ // mov.l @(Ers+), rd
+ if((data16 & 0x80) == 0x80)
+ {
+ sprintf(output, "%4.4x mov.l %s, @-%s", opcode, reg_names32[data16 & 0x7], reg_names32[(data16>>4)&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.l @%s+, %s", opcode, reg_names32[(data16>>4)&7], reg_names32[data16 & 0x7]);
+ }
+ size = 4;
+ break;
+ case 0x6f:
+ // mov.l @(displ16 + Rs), rd
+ sdata16=h8_mem_read16(4);
+ if((data16 & 0x80) == 0x80)
+ {
+ sprintf(output, "%4.4x mov.l %s,@(%x, %s)", opcode, reg_names32[data16 &0x7], sdata16, reg_names32[(data16>>4)&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.l @(%x, %s), %s", opcode, sdata16, reg_names32[(data16>>4)&7], reg_names32[data16 &0x7]);
+ }
+ size = 6;
+ break;
+ case 0x78:
+ // mov.l @(displ24 + Rs), rd
+ size = 10;
+ ext16 = h8_mem_read16(4);
+ sdata32 = h8_mem_read32(6) & 0xffffff;
+ if ( (data16 & 0x80) && ((ext16 & ~7) == 0x6ba0) )
+ {
+ sprintf(output, "%4.4x mov.l %s,@(%x, %s)", opcode, reg_names32[ext16&7], sdata32, reg_names32[(data16>>4)&7]);
+ }
+ else if ( (!(data16 & 0x80)) && ((ext16 & ~7) == 0x6b20) )
+ {
+ sprintf(output, "%4.4x mov.l @(%x, %s), %s", opcode, sdata32, reg_names32[(data16>>4)&7], reg_names32[ext16&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x ? %x", opcode, data16);
+ }
+ break;
+
+ default:
+ sprintf(output, "%4.4x ? %x", opcode, data16);
+ break;
+ }
+ break;
+ // ldc
+ case 0x4:
+ break;
+ // sleep
+ case 0x8:
+ sprintf(output, "%4.4x sleep", opcode);
+ size = 2;
+ break;
+ // mulxs
+ case 0xc:
+ break;
+ // divxs
+ case 0xd:
+ break;
+ // 01f0 and.l prefix
+ case 0xf:
+ // and.l rs, rd
+ data16 = h8_mem_read16(2);
+ sprintf(output, "%4.4x and.l %s, %s", opcode, reg_names16[(data16>>4) & 0x7], reg_names16[data16 & 0x7]);
+ size = 2;
+ break;
+ default:
+ sprintf(output, "%4.4x default", opcode);
+ break;
+ }
+ break;
+ // stc ccr, rd
+ case 0x2:
+ if(((opcode>>4) & 0xf) == 0)
+ {
+ sprintf(output, "%4.4x stc ccr, %s", opcode, reg_names8[opcode & 0xf]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x default", opcode);
+ }
+ size = 2;
+ break;
+ // ldc rd, ccr
+ case 0x3:
+ if(((opcode>>4) & 0xf) == 0)
+ {
+ sprintf(output, "%4.4x ldc %s, ccr", opcode, reg_names8[opcode & 0xf]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x default", opcode);
+ }
+ size = 2;
+ break;
+ // orc
+ case 0x4:
+ sprintf(output, "%4.4x orc #%2.2x, ccr", opcode, opcode & 0xff);
+ size = 2;
+ break;
+ // xorc
+ case 0x5:
+ sprintf(output, "%4.4x xorc #%2.2x, ccr", opcode, opcode & 0xff);
+ size = 2;
+ break;
+ // andc
+ case 0x6:
+ sprintf(output, "%4.4x andc #%2.2x, ccr", opcode, opcode & 0xff);
+ size = 2;
+ break;
+ // ldc
+ case 0x7:
+ sprintf(output, "%4.4x ldc #%2.2x, ccr", opcode, opcode & 0xff);
+ size = 2;
+ break;
+ // add.b rx, ry
+ case 0x8:
+ sprintf(output, "%4.4x add.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // add.w rx, ry
+ case 0x9:
+ sprintf(output, "%4.4x add.w %s, %s", opcode, reg_names16[(opcode>>4) & 0xf], reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // inc.b rx
+ case 0xA:
+ if(opcode&0x80)
+ {
+ if(opcode & 0x8)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x add.l %s, %s", opcode, reg_names32[(opcode>>4) & 7], reg_names32[opcode & 7]);
+ }
+ }
+ else
+ {
+ if(opcode & 0xf0)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x inc.b %s", opcode, reg_names8[(opcode & 0xf)]);
+ }
+ }
+ size = 2;
+ break;
+ //
+ case 0xb:
+ switch((opcode>>4)& 0xf)
+ {
+ case 0:
+ sprintf(output, "%4.4x adds.l #1, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ case 5:
+ sprintf(output, "%4.4x inc.w #1, %s", opcode, reg_names16[opcode & 0xf]);
+ break;
+ case 7:
+ sprintf(output, "%4.4x inc.l #1, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ case 8:
+ sprintf(output, "%4.4x adds.l #2, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ case 9:
+ sprintf(output, "%4.4x adds.l #3, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ case 0xd:
+ sprintf(output, "%4.4x inc.w #2, %s", opcode, reg_names16[opcode & 0xf]);
+ break;
+ case 0xf:
+ sprintf(output, "%4.4x inc.l #2, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ default:
+ sprintf(output, "%4.4x illegal", opcode);
+ break;
+ }
+ size = 2;
+ break;
+ // mov.b rx, ry
+ case 0xc:
+ sprintf(output, "%4.4x mov.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // mov.w rx, ry
+ case 0xd:
+ sprintf(output, "%4.4x mov.w %s, %s", opcode, reg_names16[(opcode>>4) & 0xf], reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // addx.b rx, ry
+ case 0xe:
+ sprintf(output, "%4.4x addx.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ case 0xf:
+ if(opcode & 0x80)
+ {
+ if(opcode & 8)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.l %s, %s", opcode, reg_names32[(opcode>>4) & 0x7], reg_names32[opcode & 0x7]);
+ }
+ }
+ else
+ {
+ if((opcode & 0xf0) !=0)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x daa.b %s", opcode, reg_names8[opcode & 0xf]);
+ }
+ }
+ size = 2;
+ break;
+ default:
+ sprintf(output, "%4.4x default", opcode);
+ break;
+ }
+ return size;
+}
+
+static UINT32 h8disasm_1(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom)
+{
+ UINT32 size = 2; //, mode8;
+ switch((opcode>>8)&0xf)
+ {
+ case 0x0:
+ switch((opcode>>4)&0xf)
+ {
+ // shll.b Rx
+ case 0x0:
+ sprintf(output, "%4.4x shll.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // shll.w Rx
+ case 0x1:
+ sprintf(output, "%4.4x shll.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // shll.l Rx
+ case 0x3:
+ sprintf(output, "%4.4x shll.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ // shal.b Rx
+ case 0x8:
+ sprintf(output, "%4.4x shal.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // shal.w Rx
+ case 0x9:
+ sprintf(output, "%4.4x shal.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // shal.l Rx
+ case 0xb:
+ sprintf(output, "%4.4x shal.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ default:
+ sprintf(output, "%4.4x default", opcode);
+ size = 2;
+ break;
+ }
+ break;
+
+ case 0x1:
+ switch((opcode>>4)&0xf)
+ {
+ // shlr.b rx
+ case 0x0:
+ sprintf(output, "%4.4x shlr.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // shlr.w rx
+ case 0x1:
+ sprintf(output, "%4.4x shlr.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // shlr.l rx
+ case 0x3:
+ sprintf(output, "%4.4x shlr.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ // shar.b rx
+ case 0x8:
+ sprintf(output, "%4.4x shar.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // shar.w rx
+ case 0x9:
+ sprintf(output, "%4.4x shar.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // shar.l rx
+ case 0xb:
+ sprintf(output, "%4.4x shar.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ default:
+ sprintf(output, "%4.4x illegal ", opcode);
+ size = 2;
+ break;
+ }
+ break;
+ case 0x2:
+ switch((opcode>>4)&0xf)
+ {
+ // rotxl.b Rx
+ case 0x0:
+ sprintf(output, "%4.4x rotxl.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // rotxl.w Rx
+ case 0x1:
+ sprintf(output, "%4.4x rotxl.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // rotxl.l Rx
+ case 0x3:
+ sprintf(output, "%4.4x rotxl.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ // rotl.b Rx
+ case 0x8:
+ sprintf(output, "%4.4x rotl.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // rotl.w Rx
+ case 0x9:
+ sprintf(output, "%4.4x rotl.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // rotl.l Rx
+ case 0xb:
+ sprintf(output, "%4.4x rotl.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ default:
+ sprintf(output, "%4.4x ? ", opcode);
+ size = 2;
+ break;
+ }
+ break;
+ case 0x3:
+ switch((opcode>>4)&0xf)
+ {
+ // rotxr.b Rx
+ case 0x0:
+ sprintf(output, "%4.4x rotxr.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // rotxr.w Rx
+ case 0x1:
+ sprintf(output, "%4.4x rotxr.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // rotxr.l Rx
+ case 0x3:
+ sprintf(output, "%4.4x rotxr.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ // rotr.b Rx
+ case 0x8:
+ sprintf(output, "%4.4x rotr.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // rotr.w Rx
+ case 0x9:
+ sprintf(output, "%4.4x rotr.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // rotr.l Rx
+ case 0xb:
+ sprintf(output, "%4.4x rotr.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ default:
+ sprintf(output, "%4.4x ? ", opcode);
+ size = 2;
+ break;
+ }
+ break;
+ // or.b rs, rd
+ case 0x4:
+ sprintf(output, "%4.4x or.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // xor.b rs, rd
+ case 0x5:
+ sprintf(output, "%4.4x xor.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // and.b rs, rd
+ case 0x6:
+ sprintf(output, "%4.4x and.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // not
+ case 0x7:
+ switch((opcode>>4)&0xf)
+ {
+ // not.b Rx
+ case 0x0:
+ sprintf(output, "%4.4x not.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // not.w Rx
+ case 0x1:
+ sprintf(output, "%4.4x not.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // not.l Rx
+ case 0x3:
+ sprintf(output, "%4.4x not.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ // extu.b Rx
+ case 0x4:
+ sprintf(output, "%4.4x extu.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // extu.w Rx
+ case 0x5:
+ sprintf(output, "%4.4x extu.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // extu.l Rx
+ case 0x7:
+ sprintf(output, "%4.4x extu.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ // neg.b Rx
+ case 0x8:
+ sprintf(output, "%4.4x neg.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // neg.w Rx
+ case 0x9:
+ sprintf(output, "%4.4x neg.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // neg.l Rx
+ case 0xb:
+ sprintf(output, "%4.4x neg.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ // exts.b Rx
+ case 0xc:
+ sprintf(output, "%4.4x exts.b %s", opcode, reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // exts.w Rx
+ case 0xd:
+ sprintf(output, "%4.4x exts.w %s", opcode, reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // exts.l Rx
+ case 0xf:
+ sprintf(output, "%4.4x exts.l %s", opcode, reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ default:
+ sprintf(output, "%4.4x default ", opcode);
+ size = 2;
+ break;
+ }
+ break;
+ // sub.b rs, rd
+ case 0x8:
+ sprintf(output, "%4.4x sub.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // sub.w rs, rd
+ case 0x9:
+ sprintf(output, "%4.4x sub.w %s, %s", opcode, reg_names16[(opcode>>4) & 0xf], reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // sub.b rx
+ case 0xA:
+ if(opcode&0x80)
+ {
+ if(opcode & 0x8)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x sub.l %s, %s", opcode, reg_names32[(opcode>>4) & 7], reg_names32[opcode & 7]);
+ }
+ }
+ else
+ {
+ if(opcode & 0xf0)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x dec.b %s", opcode, reg_names8[(opcode & 0xf)]);
+ }
+ }
+ size = 2;
+ break;
+ //
+ case 0xb:
+ switch((opcode>>4)& 0xf)
+ {
+ case 0:
+ sprintf(output, "%4.4x subs.l #1, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ case 5:
+ sprintf(output, "%4.4x dec.w #1, %s", opcode, reg_names16[opcode & 0xf]);
+ break;
+ case 7:
+ sprintf(output, "%4.4x dec.l #1, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ case 8:
+ sprintf(output, "%4.4x subs.l #2, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ case 9:
+ sprintf(output, "%4.4x subs.l #4, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ case 0xd:
+ sprintf(output, "%4.4x dec.w #2, %s", opcode, reg_names16[opcode & 0xf]);
+ break;
+ case 0xf:
+ sprintf(output, "%4.4x dec.l #2, %s", opcode, reg_names32[opcode & 0x7]);
+ break;
+ default:
+ sprintf(output, "%4.4x ?", opcode);
+ break;
+ }
+ size = 2;
+ break;
+ // cmp.b rs, rd
+ case 0xc:
+ sprintf(output, "%4.4x cmp.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // cmp.w rx, ry
+ case 0xd:
+ sprintf(output, "%4.4x cmp.w %s, %s", opcode, reg_names16[(opcode>>4) & 0xf], reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // subx.b rx, ry
+ case 0xe:
+ sprintf(output, "%4.4x subx.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ case 0xf:
+ if(opcode & 0x80)
+ {
+ if(opcode & 8)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x cmp.l %s, %s", opcode, reg_names32[(opcode>>4) & 0x7], reg_names32[opcode & 0x7]);
+ }
+ }
+ else
+ {
+ if((opcode & 0xf0) !=0)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x das.b %s", opcode, reg_names8[opcode & 0xf]);
+ }
+ }
+ size = 2;
+ break;
+ default:
+ sprintf(output, "%4.4x default", opcode);
+ break;
+ }
+
+ return size;
+}
+
+static UINT32 h8disasm_5(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom)
+{
+ UINT32 size = 2;
+ UINT32 data32;
+ INT16 data16;
+
+ switch((opcode>>8)&0xf)
+ {
+ // mulxu.b
+ case 0x0:
+ sprintf(output, "%4.4x mulxu.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // divxu.b
+ case 0x1:
+ sprintf(output, "%4.4x divxu.b %s, %s", opcode, reg_names8[(opcode>>4) & 0xf], reg_names8[opcode & 0xf]);
+ size = 2;
+ break;
+ // mulxu.w
+ case 0x2:
+ sprintf(output, "%4.4x mulxu.w %s, %s", opcode, reg_names16[(opcode>>4) & 0xf], reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ // divxu.w
+ case 0x3:
+ sprintf(output, "%4.4x divxu.w %s, %s", opcode, reg_names16[(opcode>>4) & 0xf], reg_names32[opcode & 7]);
+ size = 2;
+ break;
+ // rts
+ case 0x4:
+ if(opcode == 0x5470)
+ {
+ sprintf(output, "%4.4x rts", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x default", opcode);
+ }
+ size = 2 | DASMFLAG_STEP_OUT;
+ break;
+ // bsr 8
+ case 0x5:
+ sprintf(output, "%4.4x bsr %x", opcode, address+2 + ((INT8)opcode& 0xff));
+ size = 2 | DASMFLAG_STEP_OVER;
+ break;
+ // rte
+ case 0x6:
+ if(opcode == 0x5670)
+ {
+ sprintf(output, "%4.4x rte", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x default", opcode);
+ }
+ size = 2 | DASMFLAG_STEP_OUT;
+ break;
+ // trapa
+ case 0x7:
+ if(opcode & 0xcf)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ }
+ else
+ {
+ sprintf(output, "%4.4x trapa #%x", opcode, (opcode >> 4) & 3);
+ }
+ size = 2 | DASMFLAG_STEP_OVER;
+ break;
+ // bcc 16
+ case 0x8:
+ if(opcode & 0xf)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ size = 2;
+ }
+ else
+ {
+ data16 = h8_mem_read16(2);
+ address += 4;
+ sprintf(output, "%4.4x %s %8.8x", opcode, branch_instr[(opcode >> 4) & 0xf], address + (INT16)(data16));
+ size = 4;
+ }
+ break;
+ // jmp @erd
+ case 0x9:
+ sprintf(output, "%4.4x jmp @%s", opcode, reg_names32[(opcode>>4) &7]);
+ size = 2;
+ break;
+ // jmp @aa:24
+ case 0xa:
+ data32=h8_mem_read32(0);
+ sprintf(output, "%4.4x jmp %8.8x", opcode, (data32& 0xffffff));
+ size = 4;
+ break;
+ // jmp @aa:8
+ case 0xb:
+ sprintf(output, "%4.4x jmp %8.8x", opcode, (opcode & 0xff));
+ size = 2;
+ break;
+ // bsr @aa:16
+ case 0xc:
+ if(opcode & 0xff)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ size = 2;
+ }
+ else
+ {
+ data16=h8_mem_read16(2);
+ sprintf(output, "%4.4x bsr %8.8x", opcode, data16+address+4);
+ size = 4 | DASMFLAG_STEP_OVER;
+ }
+ break;
+ // jsr @erd
+ case 0xd:
+ sprintf(output, "%4.4x jsr @%s", opcode, reg_names32[(opcode>>4) &7]);
+ size = 2 | DASMFLAG_STEP_OVER;
+ break;
+ // jsr @aa:24
+ case 0xe:
+ data32=h8_mem_read32(0);
+ sprintf(output, "%4.4x jsr %8.8x", opcode, (data32& 0xffffff));
+ size = 4 | DASMFLAG_STEP_OVER;
+ break;
+ // jsr @aa:8
+ case 0xf:
+ sprintf(output, "%4.4x jsr %8.8x", opcode, (opcode & 0xff));
+ size = 2 | DASMFLAG_STEP_OVER;
+ break;
+ default:
+ sprintf(output, "%4.4x default", opcode);
+ break;
+ }
+ return size;
+}
+
+static UINT32 h8disasm_6(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom)
+{
+ UINT32 size = 2;
+ UINT32 data32;
+ INT16 data16;
+
+ switch((opcode>>8)&0xf)
+ {
+ case 0:case 1:case 2:case 3:
+ if(((opcode>>4)&0x8) == 0)
+ {
+ sprintf(output, "%4.4x %s.b %s, %s", opcode, bit_instr[(opcode>>8)&7], reg_names8[(opcode>>4)&0xf], reg_names8[(opcode & 0xf)]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x %s.b %s, %s", opcode, bit_instr2[(opcode>>8)&7], reg_names8[(opcode>>4)&0xf], reg_names8[(opcode & 0xf)]);
+ }
+ size = 2;
+ break;
+ // or.w rs, rd
+ case 0x4:
+ sprintf(output, "%4.4x or.w %s, %s", opcode, reg_names16[(opcode>>4) & 0xf], reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // xor.w rs, rd
+ case 0x5:
+ sprintf(output, "%4.4x xor.w %s, %s", opcode, reg_names16[(opcode>>4) & 0xf], reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // and.w rs, rd
+ case 0x6:
+ sprintf(output, "%4.4x and.w %s, %s", opcode, reg_names16[(opcode>>4) & 0xf], reg_names16[opcode & 0xf]);
+ size = 2;
+ break;
+ // bst/bist #imm, rd
+ case 0x7:
+ if(opcode & 0x80)
+ {
+ sprintf(output, "%4.4x bist.b #%1.1x, %s", opcode, (opcode>>4)&7, reg_names8[(opcode & 0xf)]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x bst.b #%1.1x, %s", opcode, (opcode>>4)&7, reg_names8[(opcode & 0xf)]);
+ }
+ size = 2;
+ break;
+ case 0x8:
+ if(opcode & 0x80)
+ {
+ sprintf(output, "%4.4x mov.b %s, @%s", opcode, reg_names8[opcode & 0xf], reg_names32[(opcode >> 4) & 7]);
+ size = 2;
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.b @%s, %s", opcode, reg_names32[(opcode >> 4) & 7], reg_names8[opcode & 0xf]);
+ size = 2;
+ }
+ break;
+ case 0x9:
+ if(opcode & 0x80)
+ {
+ sprintf(output, "%4.4x mov.w %s, @%s", opcode, reg_names16[opcode & 0xf], reg_names32[(opcode >> 4) & 7]);
+ size = 2;
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.w @%s, %s", opcode, reg_names32[(opcode >> 4) & 7], reg_names16[opcode & 0xf]);
+ size = 2;
+ }
+ break;
+ case 0xa:
+ // mov.b rx, @xx
+ switch((opcode>>4)&0xf)
+ {
+ case 0x0:
+ data16=h8_mem_read16(2);
+ sprintf(output, "%4.4x mov.b @%x, %s", opcode, data16, reg_names8[opcode & 0xf]);
+ size = 4;
+ break;
+ case 0x2:
+ data32=h8_mem_read32(2);
+ sprintf(output, "%4.4x mov.b @%8.8x, %s", opcode, data32, reg_names8[opcode & 0xf]);
+ size = 6;
+ break;
+ case 0x8:
+ data16=h8_mem_read16(2);
+ sprintf(output, "%4.4x mov.b %s, @%8.8x", opcode, reg_names8[opcode & 0xf], data16);
+ size = 4;
+ break;
+ case 0xa:
+ data32=h8_mem_read32(2);
+ sprintf(output, "%4.4x mov.b %s, @%8.8x", opcode, reg_names8[opcode & 0xf], data32);
+ size = 6;
+ break;
+ default:
+ sprintf(output, "%4.4x 0x6a ? ", opcode);
+ size = 2;
+ break;
+ }
+ break;
+ case 0xb:
+ // mov.w rx, @xx
+ switch((opcode>>4)&0xf)
+ {
+ case 0x0:
+ data16=h8_mem_read16(2);
+ sprintf(output, "%4.4x mov.w @%8.8x, %s", opcode, data16, reg_names16[opcode & 0xf]);
+ size = 4;
+ break;
+ case 0x2:
+ data32=h8_mem_read32(2);
+ sprintf(output, "%4.4x mov.w @%8.8x, %s", opcode, data32, reg_names16[opcode & 0xf]);
+ size = 6;
+ break;
+ case 0x8:
+ data16=h8_mem_read16(2);
+ sprintf(output, "%4.4x mov.w %s, @%8.8x", opcode, reg_names16[opcode & 0xf], data16);
+ size = 4;
+ break;
+ case 0xa:
+ data32=h8_mem_read32(2);
+ sprintf(output, "%4.4x mov.w %s, @%8.8x", opcode, reg_names16[opcode & 0xf], data32);
+ size = 6;
+ break;
+ default:
+ sprintf(output, "%4.4x 0x6b ? ", opcode);
+ size = 2;
+ break;
+ }
+ break;
+ case 0xc:
+ // mov.b @erx+,rx / mov.b @-erx, rx
+ if(opcode & 0x80)
+ {
+ sprintf(output, "%4.4x mov.b %s, @(-%s)", opcode, reg_names8[opcode &0xf], reg_names32[(opcode>>4)&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.b @(%s+), %s", opcode, reg_names32[(opcode>>4)&7], reg_names8[opcode &0xf]);
+ }
+ size = 2;
+ break;
+ case 0xd:
+ // mov.w @ers+, rd / mov.w rs, @-erd
+ if(opcode & 0x80)
+ {
+ sprintf(output, "%4.4x mov.w %s, @-%s", opcode, reg_names16[opcode&0xf], reg_names32[(opcode>>4)&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.w @%s+, %s", opcode, reg_names32[(opcode>>4)&7], reg_names16[opcode & 0xf]);
+ }
+ size = 2;
+ break;
+ case 0xe:
+ // mov.b @(displ16 + Rs), rd
+ data16=h8_mem_read16(2);
+ if(opcode & 0x80)
+ {
+ sprintf(output, "%4.4x mov.b %s,@(%x, %s)", opcode, reg_names8[opcode &0xf], data16, reg_names32[(opcode>>4)&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.b @(%x, %s), %s", opcode, data16, reg_names32[(opcode>>4)&7], reg_names8[opcode &0xf]);
+ }
+ size = 4;
+ break;
+ case 0xf:
+ // mov.w @(displ16 + Rs), rd
+ data16=h8_mem_read16(2);
+ if(opcode & 0x80)
+ {
+ sprintf(output, "%4.4x mov.w %s,@(%x, %s)", opcode, reg_names16[opcode &0xf], data16, reg_names32[(opcode>>4)&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.w @(%x, %s), %s", opcode, data16, reg_names32[(opcode>>4)&7], reg_names16[opcode &0xf]);
+ }
+ size = 4;
+ break;
+ default:
+ sprintf(output, "%4.4x default", opcode);
+ break;
+ }
+ return size;
+}
+
+static UINT32 h8disasm_7(UINT32 address, UINT32 opcode, char *output, const UINT8 *oprom)
+{
+ UINT32 size = 2;
+ UINT32 data32;
+ UINT16 data16;
+
+ switch((opcode>>8)&0xf)
+ {
+ case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:
+ if(((opcode>>4)&0x8) == 0)
+ {
+ sprintf(output, "%4.4x %s.b #%1.1x, %s", opcode, bit_instr[(opcode>>8)&7], (opcode>>4)&7, reg_names8[(opcode & 0xf)]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x %s.b #%1.1x, %s", opcode, bit_instr2[(opcode>>8)&7], (opcode>>4)&7, reg_names8[(opcode & 0xf)]);
+ }
+ size = 2;
+ break;
+ case 0x8:
+ data16 = h8_mem_read16(2);
+ data32 = h8_mem_read32(4);
+ if(((data16>>8) & 0xf) == 0xa)
+ {
+ if(((data16>>4) & 0xf) == 0xa)
+ {
+ sprintf(output, "%4.4x mov.b %s, @(%x, %s)", opcode, reg_names8[(data16 & 0xf)], data32, reg_names32[(opcode>>4)&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.b @(%x, %s), %s", opcode, data32, reg_names32[(opcode>>4) & 7], reg_names8[(data16 & 0xf)]);
+ }
+ }
+ else
+ {
+ if(((data16>>4) & 0xf) == 0xa)
+ {
+ sprintf(output, "%4.4x mov.w %s, @(%x, %s)", opcode, reg_names16[(data16 & 0xf)], data32, reg_names32[(opcode>>4)&7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x mov.w @(%x, %s), %s", opcode, data32, reg_names32[(opcode>>4) & 7], reg_names16[(data16 & 0xf)]);
+ }
+ }
+ size = 8;
+ break;
+ // xxx.w #aa:16, rd
+ case 0x9:
+ if( ((opcode>>4) & 0xf) > 0x6)
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ size = 2;
+ }
+ else
+ {
+ data16 = h8_mem_read16(2);
+ sprintf(output, "%4.4x %s.w #%x, %s", opcode, imm32l_instr[(opcode>>4)&7], data16, reg_names16[opcode&0xf]);
+ size = 4;
+ }
+ break;
+ // xxx.l #aa:32, erd
+ case 0xa:
+ if( (((opcode>>4) & 0xf) > 0x6) || (opcode & 0x8))
+ {
+ sprintf(output, "%4.4x illegal", opcode);
+ size = 2;
+ }
+ else
+ {
+ data32 = h8_mem_read32(2);
+ sprintf(output, "%4.4x %s.l #%x, %s", opcode, imm32l_instr[(opcode>>4)&7], data32, reg_names32[opcode&0x7]);
+ size = 6;
+ }
+ break;
+ // eepmov
+ case 0xb:
+ switch (opcode & 0x00ff)
+ {
+ case 0x5c:
+ sprintf(output, "%4.4x eepmov.b", opcode);
+ break;
+ case 0xd4:
+ sprintf(output, "%4.4x eepmov.w", opcode);
+ break;
+ default:
+ sprintf(output, "%4.4x eepmov UNK!", opcode);
+ break;
+ }
+ size = 4;
+ break;
+ // bxx.b #xx:3, @rd
+ case 0xc:
+ case 0xd:
+ data16 = h8_mem_read16(2);
+ if(((data16>>4)&0x8) == 0)
+ {
+ sprintf(output, "%4.4x %s.b #%1.1x, @%s", opcode, bit_instr[(data16>>8)&7], (data16>>4)&7, reg_names32[(opcode>>4) & 0x7]);
+ }
+ else
+ {
+ sprintf(output, "%4.4x %s.b #%1.1x, @%s", opcode, bit_instr2[(opcode>>4)&7], (data16>>4)&7, reg_names32[(opcode>>4) & 0x7]);
+ }
+ size = 4;
+ break;
+ // bxx.b #imm, @aa:8
+ case 0xe:
+ case 0xf:
+ data16 = h8_mem_read16(2);
+ if(((data16>>4)&0x8) == 0)
+ {
+ sprintf(output, "%4.4x %4.4x %s.b #%1.1x, @%x", opcode, data16, bit_instr[(data16>>8)&7], (data16>>4)&7, 0xffffff00 + (opcode & 0xff));
+ }
+ else
+ {
+ sprintf(output, "%4.4x %4.4x %s.b #%1.1x, @%x", opcode, data16, bit_instr2[(data16>>8)&7], (data16>>4)&7, 0xffffff00 + (opcode & 0xff));
+ }
+ size = 4;
+ break;
+ default:
+ sprintf(output, "%4.4x default", opcode);
+ break;
+ }
+ return size;
+}
+
+
diff --git a/src/emu/cpu/h83002/h8periph.c b/src/emu/cpu/h83002/h8periph.c
new file mode 100644
index 00000000000..d410759830a
--- /dev/null
+++ b/src/emu/cpu/h83002/h8periph.c
@@ -0,0 +1,506 @@
+/***************************************************************************
+
+ h8periph.c: Implementation of Hitachi H8/3002 on-board MCU functions.
+
+ Original by The_Author & DynaChicken for the ZiNc emulator.
+
+ Rewritten for MAME to use MAME timers and other facilities by R. Belmont
+
+****************************************************************************/
+
+#include "debugger.h"
+#include "h83002.h"
+#include "h8priv.h"
+
+#define H8_REG_START (0x00ffff10)
+
+// timer registers
+#define TSTR (0x60)
+#define TIER0 (0x66)
+#define TIER1 (0x70)
+#define TIER2 (0x7a)
+#define TIER3 (0x84)
+#define TIER4 (0x94)
+#define TSR0 (0x67)
+#define TSR1 (0x71)
+#define TSR2 (0x7b)
+#define TSR3 (0x85)
+#define TSR4 (0x95)
+#define TCR0 (0x64)
+#define TCR1 (0x6e)
+#define TCR2 (0x78)
+#define TCR3 (0x82)
+#define TCR4 (0x92)
+
+static TIMER_CALLBACK( h8itu_timer_0_cb )
+{
+ timer_adjust(h8.timer[0], attotime_never, 0, attotime_zero);
+ h8.h8TCNT0 = 0;
+ h8.per_regs[TSR0] |= 4;
+ // interrupt on overflow ?
+ if(h8.per_regs[TIER0] & 4)
+ {
+ h8_3002_InterruptRequest(26);
+ }
+}
+
+static TIMER_CALLBACK( h8itu_timer_1_cb )
+{
+ timer_adjust(h8.timer[1], attotime_never, 0, attotime_zero);
+ h8.h8TCNT1 = 0;
+ h8.per_regs[TSR1] |= 4;
+ // interrupt on overflow ?
+ if(h8.per_regs[TIER1] & 4)
+ {
+ h8_3002_InterruptRequest(30);
+ }
+}
+
+static TIMER_CALLBACK( h8itu_timer_2_cb )
+{
+ timer_adjust(h8.timer[2], attotime_never, 0, attotime_zero);
+ h8.h8TCNT2 = 0;
+ h8.per_regs[TSR2] |= 4;
+ // interrupt on overflow ?
+ if(h8.per_regs[TIER2] & 4)
+ {
+ h8_3002_InterruptRequest(34);
+ }
+}
+
+static TIMER_CALLBACK( h8itu_timer_3_cb )
+{
+ timer_adjust(h8.timer[3], attotime_never, 0, attotime_zero);
+ h8.h8TCNT3 = 0;
+ h8.per_regs[TSR3] |= 4;
+ // interrupt on overflow ?
+ if(h8.per_regs[TIER3] & 4)
+ {
+ h8_3002_InterruptRequest(38);
+ }
+}
+
+static TIMER_CALLBACK( h8itu_timer_4_cb )
+{
+ timer_adjust(h8.timer[4], attotime_never, 0, attotime_zero);
+ h8.h8TCNT4 = 0;
+ h8.per_regs[TSR4] |= 4;
+ // interrupt on overflow ?
+ if(h8.per_regs[TIER4] & 4)
+ {
+ h8_3002_InterruptRequest(42);
+ }
+}
+
+static void h8_itu_refresh_timer(int tnum)
+{
+ int ourTCR = 0;
+ int ourTVAL = 0;
+ attotime period;
+ static const int tscales[4] = { 1, 2, 4, 8 };
+
+ switch (tnum)
+ {
+ case 0:
+ ourTCR = h8.per_regs[TCR0];
+ ourTVAL = h8.h8TCNT0;
+ break;
+ case 1:
+ ourTCR = h8.per_regs[TCR1];
+ ourTVAL = h8.h8TCNT1;
+ break;
+ case 2:
+ ourTCR = h8.per_regs[TCR2];
+ ourTVAL = h8.h8TCNT2;
+ break;
+ case 3:
+ ourTCR = h8.per_regs[TCR3];
+ ourTVAL = h8.h8TCNT3;
+ break;
+ case 4:
+ ourTCR = h8.per_regs[TCR4];
+ ourTVAL = h8.h8TCNT4;
+ break;
+ }
+
+ period = attotime_mul(ATTOTIME_IN_HZ(cpunum_get_clock(h8.cpu_number)), tscales[ourTCR & 3] * (65536 - ourTVAL));
+
+ if (ourTCR & 4)
+ {
+ logerror("H8/3002: Timer %d is using an external clock. Unsupported!\n", tnum);
+ }
+
+ timer_adjust(h8.timer[tnum], period, 0, attotime_zero);
+}
+
+static void h8_itu_sync_timers(int tnum)
+{
+ int ourTCR = 0;
+ attotime cycle_time, cur;
+ UINT16 ratio;
+ static const int tscales[4] = { 1, 2, 4, 8 };
+
+ switch (tnum)
+ {
+ case 0:
+ ourTCR = h8.per_regs[TCR0];
+ break;
+ case 1:
+ ourTCR = h8.per_regs[TCR1];
+ break;
+ case 2:
+ ourTCR = h8.per_regs[TCR2];
+ break;
+ case 3:
+ ourTCR = h8.per_regs[TCR3];
+ break;
+ case 4:
+ ourTCR = h8.per_regs[TCR4];
+ break;
+ }
+
+ // get the time per unit
+ cycle_time = attotime_mul(ATTOTIME_IN_HZ(cpunum_get_clock(h8.cpu_number)), tscales[ourTCR & 3]);
+ cur = timer_timeelapsed(h8.timer[tnum]);
+
+ ratio = attotime_to_double(cur) / attotime_to_double(cycle_time);
+
+ switch (tnum)
+ {
+ case 0:
+ h8.h8TCNT0 = ratio;
+ break;
+ case 1:
+ h8.h8TCNT1 = ratio;
+ break;
+ case 2:
+ h8.h8TCNT2 = ratio;
+ break;
+ case 3:
+ h8.h8TCNT3 = ratio;
+ break;
+ case 4:
+ h8.h8TCNT4 = ratio;
+ break;
+ }
+}
+
+UINT8 h8_itu_read8(UINT8 reg)
+{
+ UINT8 val;
+
+ switch(reg)
+ {
+ case 0x60:
+ val = h8.h8TSTR;
+ break;
+ case 0x68:
+ h8_itu_sync_timers(0);
+ val = h8.h8TCNT0>>8;
+ break;
+ case 0x69:
+ h8_itu_sync_timers(0);
+ val = h8.h8TCNT0&0xff;
+ break;
+ case 0x72:
+ h8_itu_sync_timers(1);
+ val = h8.h8TCNT1>>8;
+ break;
+ case 0x73:
+ h8_itu_sync_timers(1);
+ val = h8.h8TCNT1&0xff;
+ break;
+ case 0x7c:
+ h8_itu_sync_timers(2);
+ val = h8.h8TCNT2>>8;
+ break;
+ case 0x7d:
+ h8_itu_sync_timers(2);
+ val = h8.h8TCNT2&0xff;
+ break;
+ case 0x86:
+ h8_itu_sync_timers(3);
+ val = h8.h8TCNT3>>8;
+ break;
+ case 0x87:
+ h8_itu_sync_timers(3);
+ val = h8.h8TCNT3&0xff;
+ break;
+ default:
+ val = h8.per_regs[reg];
+ break;
+ }
+
+
+ return val;
+}
+
+void h8_itu_write8(UINT8 reg, UINT8 val)
+{
+ h8.per_regs[reg] = val;
+ switch(reg)
+ {
+ case 0x60:
+ if ((val & 1) && !(h8.h8TSTR & 1))
+ {
+ h8_itu_refresh_timer(0);
+ }
+ if ((val & 2) && !(h8.h8TSTR & 2))
+ {
+ h8_itu_refresh_timer(1);
+ }
+ if ((val & 4) && !(h8.h8TSTR & 4))
+ {
+ h8_itu_refresh_timer(2);
+ }
+ if ((val & 8) && !(h8.h8TSTR & 8))
+ {
+ h8_itu_refresh_timer(3);
+ }
+ if ((val & 0x10) && !(h8.h8TSTR & 0x10))
+ {
+ h8_itu_refresh_timer(4);
+ }
+ h8.h8TSTR = val;
+ break;
+ case 0x68:
+ h8.h8TCNT0 = (val<<8) | (h8.h8TCNT0 & 0xff);
+ if (h8.h8TSTR & 1)
+ {
+ h8_itu_refresh_timer(0);
+ }
+ break;
+ case 0x69:
+ h8.h8TCNT0 = (val) | (h8.h8TCNT0 & 0xff00);
+ if (h8.h8TSTR & 1)
+ {
+ h8_itu_refresh_timer(0);
+ }
+ break;
+ case 0x72:
+ h8.h8TCNT1 = (val<<8) | (h8.h8TCNT1 & 0xff);
+ if (h8.h8TSTR & 2)
+ {
+ h8_itu_refresh_timer(1);
+ }
+ break;
+ case 0x73:
+ h8.h8TCNT1 = (val) | (h8.h8TCNT1 & 0xff00);
+ if (h8.h8TSTR & 2)
+ {
+ h8_itu_refresh_timer(1);
+ }
+ break;
+ case 0x7c:
+ h8.h8TCNT2 = (val<<8) | (h8.h8TCNT2 & 0xff);
+ if (h8.h8TSTR & 4)
+ {
+ h8_itu_refresh_timer(2);
+ }
+ break;
+ case 0x7d:
+ h8.h8TCNT2 = (val) | (h8.h8TCNT2 & 0xff00);
+ if (h8.h8TSTR & 4)
+ {
+ h8_itu_refresh_timer(2);
+ }
+ break;
+ case 0x86:
+ h8.h8TCNT3 = (val<<8) | (h8.h8TCNT3 & 0xff);
+ if (h8.h8TSTR & 8)
+ {
+ h8_itu_refresh_timer(3);
+ }
+ break;
+ case 0x87:
+ h8.h8TCNT3 = (val) | (h8.h8TCNT3 & 0xff00);
+ if (h8.h8TSTR & 8)
+ {
+ h8_itu_refresh_timer(3);
+ }
+ break;
+ case 0x96:
+ h8.h8TCNT4 = (val<<8) | (h8.h8TCNT4 & 0xff);
+ if (h8.h8TSTR & 0x10)
+ {
+ h8_itu_refresh_timer(4);
+ }
+ break;
+ case 0x97:
+ h8.h8TCNT4 = (val) | (h8.h8TCNT4 & 0xff00);
+ if (h8.h8TSTR & 0x10)
+ {
+ h8_itu_refresh_timer(4);
+ }
+ break;
+ default:
+ val = 0;
+ break;
+ }
+}
+
+UINT8 h8_debugger_itu_read8(UINT8 reg)
+{
+ UINT8 val;
+ val = 0;
+ return val;
+}
+
+
+UINT8 h8_register_read8(UINT32 address)
+{
+ UINT8 val;
+ UINT8 reg;
+
+ address &= 0xffffff;
+
+ reg = address & 0xff;
+
+ if(reg >= 0x60 && reg <= 0x9f)
+ {
+ return h8_itu_read8(reg);
+ }
+ else
+ {
+ switch(reg)
+ {
+ case 0xb4: // serial port A status
+ val = h8.per_regs[reg];
+ val |= 0xc4; // transmit finished, receive ready, no errors
+ break;
+ case 0xb5: // serial port A receive
+ val = io_read_byte(H8_SERIAL_A);
+ break;
+ case 0xbc: // serial port B status
+ val = h8.per_regs[reg];
+ val |= 0xc4; // transmit finished, receive ready, no errors
+ break;
+ case 0xbd: // serial port B receive
+ val = io_read_byte(H8_SERIAL_B);
+ break;
+ case 0xe0:
+ val = io_read_byte_8(H8_ADC_0_H);
+ break;
+ case 0xe1:
+ val = io_read_byte_8(H8_ADC_0_L);
+ break;
+ case 0xe2:
+ val = io_read_byte_8(H8_ADC_1_H);
+ break;
+ case 0xe3:
+ val = io_read_byte_8(H8_ADC_1_L);
+ break;
+ case 0xe4:
+ val = io_read_byte_8(H8_ADC_2_H);
+ break;
+ case 0xe5:
+ val = io_read_byte_8(H8_ADC_2_L);
+ break;
+ case 0xe6:
+ val = io_read_byte_8(H8_ADC_3_H);
+ break;
+ case 0xe7:
+ val = io_read_byte_8(H8_ADC_3_L);
+ break;
+ case 0xe8: // adc status
+ val = 0x80;
+ break;
+ case 0xc7: // port 4 data
+ val = io_read_byte_8(H8_PORT4);
+ break;
+ case 0xcb: // port 6 data
+ val = io_read_byte_8(H8_PORT6);
+ break;
+ case 0xce: // port 7 data
+ val = io_read_byte_8(H8_PORT7);
+ break;
+ case 0xcf: // port 8 data
+ val = io_read_byte_8(H8_PORT8);
+ break;
+ case 0xd2: // port 9 data
+ val = io_read_byte_8(H8_PORT9);
+ break;
+ case 0xd3: // port a data
+ val = io_read_byte_8(H8_PORTA);
+ break;
+ case 0xd6: // port b data
+ val = io_read_byte_8(H8_PORTB);
+ break;
+ default:
+ val = h8.per_regs[reg];
+ break;
+ }
+ }
+
+ return val;
+}
+
+void h8_register_write8(UINT32 address, UINT8 val)
+{
+ UINT8 reg;
+
+ address &= 0xffffff;
+
+ reg = address & 0xff;
+
+ if(reg >= 0x60 && reg <= 0x9f)
+ {
+ h8_itu_write8(reg, val);
+ }
+
+ switch (reg)
+ {
+ case 0xb3:
+ io_write_byte(H8_SERIAL_A, val);
+ break;
+ case 0xbb:
+ io_write_byte(H8_SERIAL_B, val);
+ break;
+ case 0xc7:
+ io_write_byte_8(H8_PORT4, val);
+ break;
+ case 0xcb: // port 6 data
+ io_write_byte_8(H8_PORT6, val);
+ break;
+ case 0xce: // port 7 data
+ io_write_byte_8(H8_PORT7, val);
+ break;
+ case 0xcf: // port 8 data
+ io_write_byte_8(H8_PORT8, val);
+ break;
+ case 0xd2: // port 9 data
+ io_write_byte_8(H8_PORT9, val);
+ break;
+ case 0xd3: // port a data
+ io_write_byte_8(H8_PORTA, val);
+ break;
+ case 0xd6: // port b data
+ io_write_byte_8(H8_PORTB, val);
+ break;
+ }
+
+ h8.per_regs[reg] = val;
+}
+
+void h8_itu_init(void)
+{
+ h8.timer[0] = timer_alloc(h8itu_timer_0_cb);
+ h8.timer[1] = timer_alloc(h8itu_timer_1_cb);
+ h8.timer[2] = timer_alloc(h8itu_timer_2_cb);
+ h8.timer[3] = timer_alloc(h8itu_timer_3_cb);
+ h8.timer[4] = timer_alloc(h8itu_timer_4_cb);
+
+ h8_itu_reset();
+
+ h8.cpu_number = cpu_getactivecpu();
+}
+
+void h8_itu_reset(void)
+{
+ // stop all the timers
+ timer_adjust(h8.timer[0], attotime_never, 0, attotime_zero);
+ timer_adjust(h8.timer[1], attotime_never, 0, attotime_zero);
+ timer_adjust(h8.timer[2], attotime_never, 0, attotime_zero);
+ timer_adjust(h8.timer[3], attotime_never, 0, attotime_zero);
+ timer_adjust(h8.timer[4], attotime_never, 0, attotime_zero);
+}
diff --git a/src/emu/cpu/h83002/h8priv.h b/src/emu/cpu/h83002/h8priv.h
new file mode 100644
index 00000000000..fa73d5c2633
--- /dev/null
+++ b/src/emu/cpu/h83002/h8priv.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+
+ h8priv.h : Private constants and other definitions for the H8/3002 emulator.
+
+****************************************************************************/
+
+#ifndef _H8PRIV_H_
+#define _H8PRIV_H_
+
+typedef struct
+{
+ // main CPU stuff
+ UINT32 h8err;
+ UINT32 regs[8];
+ UINT32 pc, ppc;
+ UINT32 h8_IRQrequestH, h8_IRQrequestL;
+
+ UINT8 ccr;
+ UINT8 h8nflag, h8vflag, h8cflag, h8zflag, h8iflag, h8hflag;
+ UINT8 h8uflag, h8uiflag;
+
+ int (*irq_cb)(int);
+
+ // H8/3002 onboard peripherals stuff
+
+ UINT8 per_regs[256];
+
+ UINT16 h8TCNT0, h8TCNT1, h8TCNT2, h8TCNT3, h8TCNT4;
+ UINT8 h8TSTR;
+
+ emu_timer *timer[5];
+
+ int cpu_number;
+
+} h83002_state;
+
+extern h83002_state h8;
+
+void h8_itu_init(void);
+void h8_itu_reset(void);
+UINT8 h8_itu_read8(UINT8 reg);
+void h8_itu_write8(UINT8 reg, UINT8 val);
+
+#endif
diff --git a/src/emu/cpu/hd6309/6309dasm.c b/src/emu/cpu/hd6309/6309dasm.c
new file mode 100644
index 00000000000..13579e86a90
--- /dev/null
+++ b/src/emu/cpu/hd6309/6309dasm.c
@@ -0,0 +1,940 @@
+/*****************************************************************************
+
+ 6309dasm.c - a 6309 opcode disassembler
+ Version 1.0 5-AUG-2000
+ Copyright 2000 Tim Lindner
+
+ Based on:
+ 6809dasm.c - a 6809 opcode disassembler
+ Version 1.4 1-MAR-95
+ Copyright 1995 Sean Riddle
+
+ Thanks to Franklin Bowen for bug fixes, ideas
+
+ Freely distributable on any medium given all copyrights are retained
+ by the author and no charge greater than $7.00 is made for obtaining
+ this software
+
+ Please send all bug reports, update ideas and data files to:
+ tlindner@ix.netcom.com
+
+*****************************************************************************/
+
+#include "debugger.h"
+#include "hd6309.h"
+
+// Opcode structure
+typedef struct
+{
+ UINT8 opcode; // 8-bit opcode value
+ UINT8 length; // Opcode length in bytes
+ char name[6]; // Opcode name
+ UINT8 mode; // Addressing mode
+ unsigned flags; // Disassembly flags
+} opcodeinfo;
+
+enum hd6309_addressing_modes
+{
+ INH, // Inherent
+ DIR, // Direct
+ DIR_IM, // Direct in memory (6309 only)
+ IND, // Indexed
+ REL, // Relative (8 bit)
+ LREL, // Long relative (16 bit)
+ EXT, // Extended
+ IMM, // Immediate
+ IMM_RR, // Register-to-register
+ IMM_BW, // Bitwise operations (6309 only)
+ IMM_TFM, // Transfer from memory (6309 only)
+ PG1, // Switch to page 1 opcodes
+ PG2 // Switch to page 2 opcodes
+};
+
+// Page 0 opcodes (single byte)
+static const opcodeinfo hd6309_pg0opcodes[] =
+{
+ { 0x00, 2, "NEG", DIR },
+ { 0x01, 3, "OIM", DIR_IM },
+ { 0x02, 3, "AIM", DIR_IM },
+ { 0x03, 2, "COM", DIR },
+ { 0x04, 2, "LSR", DIR },
+ { 0x05, 3, "EIM", DIR_IM },
+ { 0x06, 2, "ROR", DIR },
+ { 0x07, 2, "ASR", DIR },
+ { 0x08, 2, "ASL", DIR },
+ { 0x09, 2, "ROL", DIR },
+ { 0x0A, 2, "DEC", DIR },
+ { 0x0B, 3, "TIM", DIR_IM },
+ { 0x0C, 2, "INC", DIR },
+ { 0x0D, 2, "TST", DIR },
+ { 0x0E, 2, "JMP", DIR },
+ { 0x0F, 2, "CLR", DIR },
+
+ { 0x10, 1, "page1", PG1 },
+ { 0x11, 1, "page2", PG2 },
+ { 0x12, 1, "NOP", INH },
+ { 0x13, 1, "SYNC", INH },
+ { 0x14, 1, "SEXW", INH },
+ { 0x16, 3, "LBRA", LREL },
+ { 0x17, 3, "LBSR", LREL , DASMFLAG_STEP_OVER },
+ { 0x19, 1, "DAA", INH },
+ { 0x1A, 2, "ORCC", IMM },
+ { 0x1C, 2, "ANDCC", IMM },
+ { 0x1D, 1, "SEX", INH },
+ { 0x1E, 2, "EXG", IMM_RR },
+ { 0x1F, 2, "TFR", IMM_RR },
+
+ { 0x20, 2, "BRA", REL },
+ { 0x21, 2, "BRN", REL },
+ { 0x22, 2, "BHI", REL },
+ { 0x23, 2, "BLS", REL },
+ { 0x24, 2, "BCC", REL },
+ { 0x25, 2, "BCS", REL },
+ { 0x26, 2, "BNE", REL },
+ { 0x27, 2, "BEQ", REL },
+ { 0x28, 2, "BVC", REL },
+ { 0x29, 2, "BVS", REL },
+ { 0x2A, 2, "BPL", REL },
+ { 0x2B, 2, "BMI", REL },
+ { 0x2C, 2, "BGE", REL },
+ { 0x2D, 2, "BLT", REL },
+ { 0x2E, 2, "BGT", REL },
+ { 0x2F, 2, "BLE", REL },
+
+ { 0x30, 2, "LEAX", IND },
+ { 0x31, 2, "LEAY", IND },
+ { 0x32, 2, "LEAS", IND },
+ { 0x33, 2, "LEAU", IND },
+ { 0x34, 2, "PSHS", INH },
+ { 0x35, 2, "PULS", INH },
+ { 0x36, 2, "PSHU", INH },
+ { 0x37, 2, "PULU", INH },
+ { 0x39, 1, "RTS", INH },
+ { 0x3A, 1, "ABX", INH },
+ { 0x3B, 1, "RTI", INH },
+ { 0x3C, 2, "CWAI", IMM },
+ { 0x3D, 1, "MUL", INH },
+ { 0x3F, 1, "SWI", INH },
+
+ { 0x40, 1, "NEGA", INH },
+ { 0x43, 1, "COMA", INH },
+ { 0x44, 1, "LSRA", INH },
+ { 0x46, 1, "RORA", INH },
+ { 0x47, 1, "ASRA", INH },
+ { 0x48, 1, "ASLA", INH },
+ { 0x49, 1, "ROLA", INH },
+ { 0x4A, 1, "DECA", INH },
+ { 0x4C, 1, "INCA", INH },
+ { 0x4D, 1, "TSTA", INH },
+ { 0x4F, 1, "CLRA", INH },
+
+ { 0x50, 1, "NEGB", INH },
+ { 0x53, 1, "COMB", INH },
+ { 0x54, 1, "LSRB", INH },
+ { 0x56, 1, "RORB", INH },
+ { 0x57, 1, "ASRB", INH },
+ { 0x58, 1, "ASLB", INH },
+ { 0x59, 1, "ROLB", INH },
+ { 0x5A, 1, "DECB", INH },
+ { 0x5C, 1, "INCB", INH },
+ { 0x5D, 1, "TSTB", INH },
+ { 0x5F, 1, "CLRB", INH },
+
+ { 0x60, 2, "NEG", IND },
+ { 0x61, 3, "OIM", IND },
+ { 0x62, 3, "AIM", IND },
+ { 0x63, 2, "COM", IND },
+ { 0x64, 2, "LSR", IND },
+ { 0x65, 3, "EIM", IND },
+ { 0x66, 2, "ROR", IND },
+ { 0x67, 2, "ASR", IND },
+ { 0x68, 2, "ASL", IND },
+ { 0x69, 2, "ROL", IND },
+ { 0x6A, 2, "DEC", IND },
+ { 0x6B, 3, "TIM", IND },
+ { 0x6C, 2, "INC", IND },
+ { 0x6D, 2, "TST", IND },
+ { 0x6E, 2, "JMP", IND },
+ { 0x6F, 2, "CLR", IND },
+
+ { 0x70, 3, "NEG", EXT },
+ { 0x71, 4, "OIM", EXT },
+ { 0x72, 4, "AIM", EXT },
+ { 0x73, 3, "COM", EXT },
+ { 0x74, 3, "LSR", EXT },
+ { 0x75, 4, "EIM", EXT },
+ { 0x76, 3, "ROR", EXT },
+ { 0x77, 3, "ASR", EXT },
+ { 0x78, 3, "ASL", EXT },
+ { 0x79, 3, "ROL", EXT },
+ { 0x7A, 3, "DEC", EXT },
+ { 0x7B, 4, "TIM", EXT },
+ { 0x7C, 3, "INC", EXT },
+ { 0x7D, 3, "TST", EXT },
+ { 0x7E, 3, "JMP", EXT },
+ { 0x7F, 3, "CLR", EXT },
+
+ { 0x80, 2, "SUBA", IMM },
+ { 0x81, 2, "CMPA", IMM },
+ { 0x82, 2, "SBCA", IMM },
+ { 0x83, 3, "SUBD", IMM },
+ { 0x84, 2, "ANDA", IMM },
+ { 0x85, 2, "BITA", IMM },
+ { 0x86, 2, "LDA", IMM },
+ { 0x88, 2, "EORA", IMM },
+ { 0x89, 2, "ADCA", IMM },
+ { 0x8A, 2, "ORA", IMM },
+ { 0x8B, 2, "ADDA", IMM },
+ { 0x8C, 3, "CMPX", IMM },
+ { 0x8D, 2, "BSR", REL , DASMFLAG_STEP_OVER },
+ { 0x8E, 3, "LDX", IMM },
+
+ { 0x90, 2, "SUBA", DIR },
+ { 0x91, 2, "CMPA", DIR },
+ { 0x92, 2, "SBCA", DIR },
+ { 0x93, 2, "SUBD", DIR },
+ { 0x94, 2, "ANDA", DIR },
+ { 0x95, 2, "BITA", DIR },
+ { 0x96, 2, "LDA", DIR },
+ { 0x97, 2, "STA", DIR },
+ { 0x98, 2, "EORA", DIR },
+ { 0x99, 2, "ADCA", DIR },
+ { 0x9A, 2, "ORA", DIR },
+ { 0x9B, 2, "ADDA", DIR },
+ { 0x9C, 2, "CMPX", DIR },
+ { 0x9D, 2, "JSR", DIR , DASMFLAG_STEP_OVER },
+ { 0x9E, 2, "LDX", DIR },
+ { 0x9F, 2, "STX", DIR },
+
+ { 0xA0, 2, "SUBA", IND },
+ { 0xA1, 2, "CMPA", IND },
+ { 0xA2, 2, "SBCA", IND },
+ { 0xA3, 2, "SUBD", IND },
+ { 0xA4, 2, "ANDA", IND },
+ { 0xA5, 2, "BITA", IND },
+ { 0xA6, 2, "LDA", IND },
+ { 0xA7, 2, "STA", IND },
+ { 0xA8, 2, "EORA", IND },
+ { 0xA9, 2, "ADCA", IND },
+ { 0xAA, 2, "ORA", IND },
+ { 0xAB, 2, "ADDA", IND },
+ { 0xAC, 2, "CMPX", IND },
+ { 0xAD, 2, "JSR", IND , DASMFLAG_STEP_OVER },
+ { 0xAE, 2, "LDX", IND },
+ { 0xAF, 2, "STX", IND },
+
+ { 0xB0, 3, "SUBA", EXT },
+ { 0xB1, 3, "CMPA", EXT },
+ { 0xB2, 3, "SBCA", EXT },
+ { 0xB3, 3, "SUBD", EXT },
+ { 0xB4, 3, "ANDA", EXT },
+ { 0xB5, 3, "BITA", EXT },
+ { 0xB6, 3, "LDA", EXT },
+ { 0xB7, 3, "STA", EXT },
+ { 0xB8, 3, "EORA", EXT },
+ { 0xB9, 3, "ADCA", EXT },
+ { 0xBA, 3, "ORA", EXT },
+ { 0xBB, 3, "ADDA", EXT },
+ { 0xBC, 3, "CMPX", EXT },
+ { 0xBD, 3, "JSR", EXT , DASMFLAG_STEP_OVER },
+ { 0xBE, 3, "LDX", EXT },
+ { 0xBF, 3, "STX", EXT },
+
+ { 0xC0, 2, "SUBB", IMM },
+ { 0xC1, 2, "CMPB", IMM },
+ { 0xC2, 2, "SBCB", IMM },
+ { 0xC3, 3, "ADDD", IMM },
+ { 0xC4, 2, "ANDB", IMM },
+ { 0xC5, 2, "BITB", IMM },
+ { 0xC6, 2, "LDB", IMM },
+ { 0xC8, 2, "EORB", IMM },
+ { 0xC9, 2, "ADCB", IMM },
+ { 0xCA, 2, "ORB", IMM },
+ { 0xCB, 2, "ADDB", IMM },
+ { 0xCC, 3, "LDD", IMM },
+ { 0xCD, 5, "LDQ", IMM },
+ { 0xCE, 3, "LDU", IMM },
+
+ { 0xD0, 2, "SUBB", DIR },
+ { 0xD1, 2, "CMPB", DIR },
+ { 0xD2, 2, "SBCB", DIR },
+ { 0xD3, 2, "ADDD", DIR },
+ { 0xD4, 2, "ANDB", DIR },
+ { 0xD5, 2, "BITB", DIR },
+ { 0xD6, 2, "LDB", DIR },
+ { 0xD7, 2, "STB", DIR },
+ { 0xD8, 2, "EORB", DIR },
+ { 0xD9, 2, "ADCB", DIR },
+ { 0xDA, 2, "ORB", DIR },
+ { 0xDB, 2, "ADDB", DIR },
+ { 0xDC, 2, "LDD", DIR },
+ { 0xDD, 2, "STD", DIR },
+ { 0xDE, 2, "LDU", DIR },
+ { 0xDF, 2, "STU", DIR },
+
+ { 0xE0, 2, "SUBB", IND },
+ { 0xE1, 2, "CMPB", IND },
+ { 0xE2, 2, "SBCB", IND },
+ { 0xE3, 2, "ADDD", IND },
+ { 0xE4, 2, "ANDB", IND },
+ { 0xE5, 2, "BITB", IND },
+ { 0xE6, 2, "LDB", IND },
+ { 0xE7, 2, "STB", IND },
+ { 0xE8, 2, "EORB", IND },
+ { 0xE9, 2, "ADCB", IND },
+ { 0xEA, 2, "ORB", IND },
+ { 0xEB, 2, "ADDB", IND },
+ { 0xEC, 2, "LDD", IND },
+ { 0xED, 2, "STD", IND },
+ { 0xEE, 2, "LDU", IND },
+ { 0xEF, 2, "STU", IND },
+
+ { 0xF0, 3, "SUBB", EXT },
+ { 0xF1, 3, "CMPB", EXT },
+ { 0xF2, 3, "SBCB", EXT },
+ { 0xF3, 3, "ADDD", EXT },
+ { 0xF4, 3, "ANDB", EXT },
+ { 0xF5, 3, "BITB", EXT },
+ { 0xF6, 3, "LDB", EXT },
+ { 0xF7, 3, "STB", EXT },
+ { 0xF8, 3, "EORB", EXT },
+ { 0xF9, 3, "ADCB", EXT },
+ { 0xFA, 3, "ORB", EXT },
+ { 0xFB, 3, "ADDB", EXT },
+ { 0xFC, 3, "LDD", EXT },
+ { 0xFD, 3, "STD", EXT },
+ { 0xFE, 3, "LDU", EXT },
+ { 0xFF, 3, "STU", EXT }
+};
+
+// Page 1 opcodes (0x10 0x..)
+static const opcodeinfo hd6309_pg1opcodes[] =
+{
+ { 0x21, 4, "LBRN", LREL },
+ { 0x22, 4, "LBHI", LREL },
+ { 0x23, 4, "LBLS", LREL },
+ { 0x24, 4, "LBCC", LREL },
+ { 0x25, 4, "LBCS", LREL },
+ { 0x26, 4, "LBNE", LREL },
+ { 0x27, 4, "LBEQ", LREL },
+ { 0x28, 4, "LBVC", LREL },
+ { 0x29, 4, "LBVS", LREL },
+ { 0x2A, 4, "LBPL", LREL },
+ { 0x2B, 4, "LBMI", LREL },
+ { 0x2C, 4, "LBGE", LREL },
+ { 0x2D, 4, "LBLT", LREL },
+ { 0x2E, 4, "LBGT", LREL },
+ { 0x2F, 4, "LBLE", LREL },
+
+ { 0x30, 3, "ADDR", IMM_RR },
+ { 0x31, 3, "ADCR", IMM_RR },
+ { 0x32, 3, "SUBR", IMM_RR },
+ { 0x33, 3, "SBCR", IMM_RR },
+ { 0x34, 3, "ANDR", IMM_RR },
+ { 0x35, 3, "ORR", IMM_RR },
+ { 0x36, 3, "EORR", IMM_RR },
+ { 0x37, 3, "CMPR", IMM_RR },
+
+ { 0x38, 2, "PSHSW", INH },
+ { 0x39, 2, "PULSW", INH },
+ { 0x3A, 2, "PSHUW", INH },
+ { 0x3B, 2, "PULUW", INH },
+
+ { 0x3F, 2, "SWI2", INH },
+
+ { 0x40, 2, "NEGD", INH },
+ { 0x43, 2, "COMD", INH },
+ { 0x44, 2, "LSRD", INH },
+ { 0x46, 2, "RORD", INH },
+ { 0x47, 2, "ASRD", INH },
+ { 0x48, 2, "ASLD", INH },
+ { 0x49, 2, "ROLD", INH },
+
+ { 0x4A, 2, "DECD", INH },
+ { 0x4C, 2, "INCD", INH },
+ { 0x4D, 2, "TSTD", INH },
+ { 0x4f, 2, "CLRD", INH },
+
+ { 0x53, 2, "COMW", INH },
+ { 0x54, 2, "LSRW", INH },
+ { 0x56, 2, "RORW", INH },
+ { 0x59, 2, "ROLW", INH },
+ { 0x5A, 2, "DECW", INH },
+ { 0x5C, 2, "INCW", INH },
+ { 0x5D, 2, "TSTW", INH },
+ { 0x5F, 2, "CLRW", INH },
+ { 0x80, 4, "SUBW", IMM },
+ { 0x81, 4, "CMPW", IMM },
+ { 0x82, 4, "SBCD", IMM },
+
+ { 0x83, 4, "CMPD", IMM },
+
+ { 0x84, 4, "ANDD", IMM },
+ { 0x85, 4, "BITD", IMM },
+ { 0x86, 4, "LDW", IMM },
+ { 0x88, 4, "EORD", IMM },
+ { 0x89, 4, "ADCD", IMM },
+ { 0x8A, 4, "ORD", IMM },
+ { 0x8B, 4, "ADDW", IMM },
+
+ { 0x8C, 4, "CMPY", IMM },
+ { 0x8E, 4, "LDY", IMM },
+
+ { 0x90, 3, "SUBW", DIR },
+ { 0x91, 3, "CMPW", DIR },
+ { 0x92, 3, "SBCD", DIR },
+
+ { 0x93, 3, "CMPD", DIR },
+
+ { 0x94, 3, "ANDD", DIR },
+ { 0x95, 3, "BITD", DIR },
+ { 0x96, 3, "LDW", DIR },
+ { 0x97, 3, "STW", DIR },
+ { 0x98, 3, "EORD", DIR },
+ { 0x99, 3, "ADCD", DIR },
+ { 0x9A, 3, "ORD", DIR },
+ { 0x9B, 3, "ADDW", DIR },
+
+ { 0x9C, 3, "CMPY", DIR },
+ { 0x9E, 3, "LDY", DIR },
+ { 0x9F, 3, "STY", DIR },
+
+ { 0xA0, 3, "SUBW", IND },
+ { 0xA1, 3, "CMPW", IND },
+ { 0xA2, 3, "SBCD", IND },
+
+ { 0xA3, 3, "CMPD", IND },
+
+ { 0xA4, 3, "ANDD", IND },
+ { 0xA5, 3, "BITD", IND },
+
+ { 0xA6, 3, "LDW", IND },
+ { 0xA7, 3, "STW", IND },
+ { 0xA8, 3, "EORD", IND },
+ { 0xA9, 3, "ADCD", IND },
+ { 0xAA, 3, "ORD", IND },
+ { 0xAB, 3, "ADDW", IND },
+
+ { 0xAC, 3, "CMPY", IND },
+ { 0xAE, 3, "LDY", IND },
+ { 0xAF, 3, "STY", IND },
+
+ { 0xB0, 4, "SUBW", EXT },
+ { 0xB1, 4, "CMPW", EXT },
+ { 0xB2, 4, "SBCD", EXT },
+
+ { 0xB3, 4, "CMPD", EXT },
+
+ { 0xB4, 4, "ANDD", EXT },
+ { 0xB5, 4, "BITD", EXT },
+ { 0xB6, 4, "LDW", EXT },
+ { 0xB7, 4, "STW", EXT },
+ { 0xB8, 4, "EORD", EXT },
+ { 0xB9, 4, "ADCD", EXT },
+ { 0xBA, 4, "ORD", EXT },
+ { 0xBB, 4, "ADDW", EXT },
+
+ { 0xBC, 4, "CMPY", EXT },
+ { 0xBE, 4, "LDY", EXT },
+ { 0xBF, 4, "STY", EXT },
+ { 0xCE, 4, "LDS", IMM },
+
+ { 0xDC, 3, "LDQ", DIR },
+ { 0xDD, 3, "STQ", DIR },
+
+ { 0xDE, 3, "LDS", DIR },
+ { 0xDF, 3, "STS", DIR },
+
+ { 0xEC, 3, "LDQ", IND },
+ { 0xED, 3, "STQ", IND },
+ { 0xEE, 3, "LDS", IND },
+
+ { 0xEE, 3, "LDS", IND },
+ { 0xEF, 3, "STS", IND },
+
+ { 0xFC, 4, "LDQ", EXT },
+ { 0xFD, 4, "STQ", EXT },
+
+ { 0xFE, 4, "LDS", EXT },
+ { 0xFF, 4, "STS", EXT }
+};
+
+// Page 2 opcodes (0x11 0x..)
+static const opcodeinfo hd6309_pg2opcodes[] =
+{
+ { 0x30, 4, "BAND", IMM_BW },
+ { 0x31, 4, "BIAND", IMM_BW },
+ { 0x32, 4, "BOR", IMM_BW },
+ { 0x33, 4, "BIOR", IMM_BW },
+ { 0x34, 4, "BEOR", IMM_BW },
+ { 0x35, 4, "BIEOR", IMM_BW },
+
+ { 0x36, 4, "LDBT", IMM_BW },
+ { 0x37, 4, "STBT", IMM_BW },
+
+ { 0x38, 3, "TFM", IMM_TFM },
+ { 0x39, 3, "TFM", IMM_TFM },
+ { 0x3A, 3, "TFM", IMM_TFM },
+ { 0x3B, 3, "TFM", IMM_TFM },
+
+ { 0x3C, 3, "BITMD", IMM },
+ { 0x3D, 3, "LDMD", IMM },
+
+ { 0x3F, 2, "SWI3", INH },
+
+ { 0x43, 2, "COME", INH },
+ { 0x4A, 2, "DECE", INH },
+ { 0x4C, 2, "INCE", INH },
+ { 0x4D, 2, "TSTE", INH },
+ { 0x4F, 2, "CLRE", INH },
+ { 0x53, 2, "COMF", INH },
+ { 0x5A, 2, "DECF", INH },
+ { 0x5C, 2, "INCF", INH },
+ { 0x5D, 2, "TSTF", INH },
+ { 0x5F, 2, "CLRF", INH },
+
+ { 0x80, 3, "SUBE", IMM },
+ { 0x81, 3, "CMPE", IMM },
+
+ { 0x83, 4, "CMPU", IMM },
+
+ { 0x86, 3, "LDE", IMM },
+ { 0x8b, 3, "ADDE", IMM },
+
+ { 0x8C, 4, "CMPS", IMM },
+
+ { 0x8D, 3, "DIVD", IMM },
+ { 0x8E, 4, "DIVQ", IMM },
+ { 0x8F, 4, "MULD", IMM },
+ { 0x90, 3, "SUBE", DIR },
+ { 0x91, 3, "CMPE", DIR },
+
+ { 0x93, 3, "CMPU", DIR },
+
+ { 0x96, 3, "LDE", DIR },
+ { 0x97, 3, "STE", DIR },
+ { 0x9B, 3, "ADDE", DIR },
+
+ { 0x9C, 3, "CMPS", DIR },
+
+ { 0x9D, 3, "DIVD", DIR },
+ { 0x9E, 3, "DIVQ", DIR },
+ { 0x9F, 3, "MULD", DIR },
+
+ { 0xA0, 3, "SUBE", IND },
+ { 0xA1, 3, "CMPE", IND },
+
+ { 0xA3, 3, "CMPU", IND },
+
+ { 0xA6, 3, "LDE", IND },
+ { 0xA7, 3, "STE", IND },
+ { 0xAB, 3, "ADDE", IND },
+
+ { 0xAC, 3, "CMPS", IND },
+
+ { 0xAD, 3, "DIVD", IND },
+ { 0xAE, 3, "DIVQ", IND },
+ { 0xAF, 3, "MULD", IND },
+ { 0xB0, 4, "SUBE", EXT },
+ { 0xB1, 4, "CMPE", EXT },
+
+ { 0xB3, 4, "CMPU", EXT },
+
+ { 0xB6, 4, "LDE", EXT },
+ { 0xB7, 4, "STE", EXT },
+
+ { 0xBB, 4, "ADDE", EXT },
+ { 0xBC, 4, "CMPS", EXT },
+
+ { 0xBD, 4, "DIVD", EXT },
+ { 0xBE, 4, "DIVQ", EXT },
+ { 0xBF, 4, "MULD", EXT },
+
+ { 0xC0, 3, "SUBF", IMM },
+ { 0xC1, 3, "CMPF", IMM },
+ { 0xC6, 3, "LDF", IMM },
+ { 0xCB, 3, "ADDF", IMM },
+
+ { 0xD0, 3, "SUBF", DIR },
+ { 0xD1, 3, "CMPF", DIR },
+ { 0xD6, 3, "LDF", DIR },
+ { 0xD7, 3, "STF", DIR },
+ { 0xDB, 3, "ADDF", DIR },
+
+ { 0xE0, 3, "SUBF", IND },
+ { 0xE1, 3, "CMPF", IND },
+ { 0xE6, 3, "LDF", IND },
+ { 0xE7, 3, "STF", IND },
+ { 0xEB, 3, "ADDF", IND },
+
+ { 0xF0, 4, "SUBF", EXT },
+ { 0xF1, 4, "CMPF", EXT },
+ { 0xF6, 4, "LDF", EXT },
+ { 0xF7, 4, "STF", EXT },
+ { 0xFB, 4, "ADDF", EXT }
+};
+
+static const opcodeinfo *hd6309_pgpointers[3] =
+{
+ hd6309_pg0opcodes, hd6309_pg1opcodes, hd6309_pg2opcodes
+};
+
+static const int hd6309_numops[3] =
+{
+ sizeof(hd6309_pg0opcodes) / sizeof(hd6309_pg0opcodes[0]),
+ sizeof(hd6309_pg1opcodes) / sizeof(hd6309_pg1opcodes[0]),
+ sizeof(hd6309_pg2opcodes) / sizeof(hd6309_pg2opcodes[0])
+};
+
+static const char *hd6309_regs[5] = { "X", "Y", "U", "S", "PC" };
+
+static const char *hd6309_btwregs[5] = { "CC", "A", "B", "inv" };
+
+static const char *hd6309_teregs[16] =
+{
+ "D", "X", "Y", "U", "S", "PC", "W", "V",
+ "A", "B", "CC", "DP", "0", "0", "E", "F"
+};
+
+static const char *hd6309_tfmregs[16] = {
+ "D", "X", "Y", "U", "S", "inv", "inv", "inv",
+ "inv", "inv", "inv", "inv", "inv", "inv", "inv", "inv"
+};
+
+static const char *tfm_s[] = { "%s+,%s+", "%s-,%s-", "%s+,%s", "%s,%s+" };
+
+offs_t hd6309_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT8 opcode, mode, pb, pbm, reg;
+ const UINT8 *operandarray;
+ unsigned int ea, flags;
+ int numoperands, offset, indirect;
+
+ int i, p = 0, page = 0, opcode_found = FALSE;
+
+ do
+ {
+ opcode = oprom[p++];
+ for (i = 0; i < hd6309_numops[page]; i++)
+ if (hd6309_pgpointers[page][i].opcode == opcode)
+ break;
+
+ if (i < hd6309_numops[page])
+ opcode_found = TRUE;
+ else
+ {
+ strcpy(buffer, "Illegal Opcode");
+ return p | DASMFLAG_SUPPORTED;
+ }
+
+ if (hd6309_pgpointers[page][i].mode >= PG1)
+ {
+ page = hd6309_pgpointers[page][i].mode - PG1 + 1;
+ opcode_found = FALSE;
+ }
+ } while (!opcode_found);
+
+ if (page == 0)
+ numoperands = hd6309_pgpointers[page][i].length - 1;
+ else
+ numoperands = hd6309_pgpointers[page][i].length - 2;
+
+ operandarray = &opram[p];
+ p += numoperands;
+ pc += p;
+ mode = hd6309_pgpointers[page][i].mode;
+ flags = hd6309_pgpointers[page][i].flags;
+
+ buffer += sprintf(buffer, "%-6s", hd6309_pgpointers[page][i].name);
+
+ switch (mode)
+ {
+ case INH:
+ switch (opcode)
+ {
+ case 0x34: // PSHS
+ case 0x36: // PSHU
+ pb = operandarray[0];
+ if (pb & 0x80)
+ buffer += sprintf(buffer, "PC");
+ if (pb & 0x40)
+ buffer += sprintf(buffer, "%s%s", (pb&0x80)?",":"", (opcode==0x34)?"U":"S");
+ if (pb & 0x20)
+ buffer += sprintf(buffer, "%sY", (pb&0xc0)?",":"");
+ if (pb & 0x10)
+ buffer += sprintf(buffer, "%sX", (pb&0xe0)?",":"");
+ if (pb & 0x08)
+ buffer += sprintf(buffer, "%sDP", (pb&0xf0)?",":"");
+ if (pb & 0x04)
+ buffer += sprintf(buffer, "%sB", (pb&0xf8)?",":"");
+ if (pb & 0x02)
+ buffer += sprintf(buffer, "%sA", (pb&0xfc)?",":"");
+ if (pb & 0x01)
+ buffer += sprintf(buffer, "%sCC", (pb&0xfe)?",":"");
+ break;
+ case 0x35: // PULS
+ case 0x37: // PULU
+ pb = operandarray[0];
+ if (pb & 0x01)
+ buffer += sprintf(buffer, "CC");
+ if (pb & 0x02)
+ buffer += sprintf(buffer, "%sA", (pb&0x01)?",":"");
+ if (pb & 0x04)
+ buffer += sprintf(buffer, "%sB", (pb&0x03)?",":"");
+ if (pb & 0x08)
+ buffer += sprintf(buffer, "%sDP", (pb&0x07)?",":"");
+ if (pb & 0x10)
+ buffer += sprintf(buffer, "%sX", (pb&0x0f)?",":"");
+ if (pb & 0x20)
+ buffer += sprintf(buffer, "%sY", (pb&0x1f)?",":"");
+ if (pb & 0x40)
+ buffer += sprintf(buffer, "%s%s", (pb&0x3f)?",":"", (opcode==0x35)?"U":"S");
+ if (pb & 0x80)
+ buffer += sprintf(buffer, "%sPC ; (PUL? PC=RTS)", (pb&0x7f)?",":"");
+ break;
+ default:
+ // No operands
+ break;
+ }
+ break;
+
+ case DIR:
+ ea = operandarray[0];
+ buffer += sprintf(buffer, "$%02X", ea);
+ break;
+
+ case DIR_IM:
+ buffer += sprintf(buffer, "#$%02X,", operandarray[0]);
+ buffer += sprintf(buffer, "$%02X", operandarray[1]);
+ break;
+
+ case REL:
+ offset = (INT8)operandarray[0];
+ buffer += sprintf(buffer, "$%04X", (pc + offset) & 0xffff);
+ break;
+
+ case LREL:
+ offset = (INT16)((operandarray[0] << 8) + operandarray[1]);
+ buffer += sprintf(buffer, "$%04X", (pc + offset) & 0xffff);
+ break;
+
+ case EXT:
+ if (numoperands == 3)
+ {
+ pb = operandarray[0];
+ ea = (operandarray[1] << 8) + operandarray[2];
+ buffer += sprintf(buffer, "#$%02X,$%04X", pb, ea);
+ }
+ else
+ if (numoperands == 2)
+ {
+ ea = (operandarray[0] << 8) + operandarray[1];
+ buffer += sprintf(buffer, "$%04X", ea);
+ }
+ break;
+
+ case IND:
+ if (numoperands == 2)
+ {
+ buffer += sprintf(buffer, "#$%02X,", operandarray[0]);
+ pb = operandarray[1];
+ }
+ else
+ {
+ pb = operandarray[0];
+ }
+
+ reg = (pb >> 5) & 3;
+ pbm = pb & 0x8f;
+ indirect = ((pb & 0x90) == 0x90 )? TRUE : FALSE;
+
+ // open brackets if indirect
+ if (indirect && pbm != 0x82)
+ buffer += sprintf(buffer, "[");
+
+ switch (pbm)
+ {
+ case 0x80: // ,R+ or operations relative to W
+ if (indirect)
+ {
+ switch (reg)
+ {
+ case 0x00:
+ buffer += sprintf(buffer, ",W");
+ break;
+ case 0x01:
+ offset = (INT16)((opram[p+0] << 8) + opram[p+1]);
+ p += 2;
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%04X,W", (offset < 0) ? -offset : offset);
+ break;
+ case 0x02:
+ buffer += sprintf(buffer, ",W++");
+ break;
+ case 0x03:
+ buffer += sprintf(buffer, ",--W");
+ break;
+ }
+ }
+ else
+ buffer += sprintf(buffer, ",%s+", hd6309_regs[reg]);
+ break;
+
+ case 0x81: // ,R++
+ buffer += sprintf(buffer, ",%s++", hd6309_regs[reg]);
+ break;
+
+ case 0x82: // ,-R
+ if (indirect)
+ strcpy(buffer, "Illegal Postbyte");
+ else
+ buffer += sprintf(buffer, ",-%s", hd6309_regs[reg]);
+ break;
+
+ case 0x83: // ,--R
+ buffer += sprintf(buffer, ",--%s", hd6309_regs[reg]);
+ break;
+
+ case 0x84: // ,R
+ buffer += sprintf(buffer, ",%s", hd6309_regs[reg]);
+ break;
+
+ case 0x85: // (+/- B),R
+ buffer += sprintf(buffer, "B,%s", hd6309_regs[reg]);
+ break;
+
+ case 0x86: // (+/- A),R
+ buffer += sprintf(buffer, "A,%s", hd6309_regs[reg]);
+ break;
+
+ case 0x87: // (+/- E),R
+ buffer += sprintf(buffer, "E,%s", hd6309_regs[reg]);
+ break;
+
+ case 0x88: // (+/- 7 bit offset),R
+ offset = (INT8)opram[p++];
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%02X,", (offset < 0) ? -offset : offset);
+ buffer += sprintf(buffer, "%s", hd6309_regs[reg]);
+ break;
+
+ case 0x89: // (+/- 15 bit offset),R
+ offset = (INT16)((opram[p+0] << 8) + opram[p+1]);
+ p += 2;
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%04X,", (offset < 0) ? -offset : offset);
+ buffer += sprintf(buffer, "%s", hd6309_regs[reg]);
+ break;
+
+ case 0x8a: // (+/- F),R
+ buffer += sprintf(buffer, "F,%s", hd6309_regs[reg]);
+ break;
+
+ case 0x8b: // (+/- D),R
+ buffer += sprintf(buffer, "D,%s", hd6309_regs[reg]);
+ break;
+
+ case 0x8c: // (+/- 7 bit offset),PC
+ offset = (INT8)opram[p++];
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%02X,PC", (offset < 0) ? -offset : offset);
+ break;
+
+ case 0x8d: // (+/- 15 bit offset),PC
+ offset = (INT16)((opram[p+0] << 8) + opram[p+1]);
+ p += 2;
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%04X,PC", (offset < 0) ? -offset : offset);
+ break;
+
+ case 0x8e: // (+/- W),R
+ buffer += sprintf(buffer, "W,%s", hd6309_regs[reg]);
+ break;
+
+ case 0x8f: // address or operations relative to W
+ if (indirect)
+ {
+ ea = (UINT16)((opram[p+0] << 8) + opram[p+1]);
+ p += 2;
+ buffer += sprintf(buffer, "$%04X", ea);
+ break;
+ }
+ else
+ {
+ switch (reg)
+ {
+ case 0x00:
+ buffer += sprintf(buffer, ",W");
+ break;
+ case 0x01:
+ offset = (INT16)((opram[p+0] << 8) + opram[p+1]);
+ p += 2;
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%04X,W", (offset < 0) ? -offset : offset);
+ break;
+ case 0x02:
+ buffer += sprintf(buffer, ",W++");
+ break;
+ case 0x03:
+ buffer += sprintf(buffer, ",--W");
+ break;
+ }
+ }
+ break;
+
+ default: // (+/- 4 bit offset),R
+ offset = pb & 0x1f;
+ if (offset > 15)
+ offset = offset - 32;
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%X,", (offset < 0) ? -offset : offset);
+ buffer += sprintf(buffer, "%s", hd6309_regs[reg]);
+ break;
+ }
+
+ // close brackets if indirect
+ if (indirect && pbm != 0x82)
+ buffer += sprintf(buffer, "]");
+ break;
+
+ case IMM:
+ if (numoperands == 4)
+ {
+ ea = (operandarray[0] << 24) + (operandarray[1] << 16) + (operandarray[2] << 8) + operandarray[3];
+ buffer += sprintf(buffer, "#$%08X", ea);
+ }
+ else
+ if (numoperands == 2)
+ {
+ ea = (operandarray[0] << 8) + operandarray[1];
+ buffer += sprintf(buffer, "#$%04X", ea);
+ }
+ else
+ if (numoperands == 1)
+ {
+ ea = operandarray[0];
+ buffer += sprintf(buffer, "#$%02X", ea);
+ }
+ break;
+
+ case IMM_RR:
+ pb = operandarray[0];
+ buffer += sprintf(buffer, "%s,%s", hd6309_teregs[(pb >> 4) & 0xf], hd6309_teregs[pb & 0xf]);
+ break;
+
+ case IMM_BW:
+ pb = operandarray[0];
+ buffer += sprintf(buffer, "%s,", hd6309_btwregs[((pb & 0xc0) >> 6)]);
+ buffer += sprintf(buffer, "%d,", (pb & 0x38) >> 3);
+ buffer += sprintf(buffer, "%d,", (pb & 0x07));
+ buffer += sprintf(buffer, "$%02X", operandarray[1]);
+ break;
+
+ case IMM_TFM:
+ pb = operandarray[0];
+ buffer += sprintf(buffer, tfm_s[opcode & 0x07], hd6309_tfmregs[(pb >> 4) & 0xf], hd6309_tfmregs[pb & 0xf]);
+ break;
+ }
+
+ return p | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/hd6309/6309ops.c b/src/emu/cpu/hd6309/6309ops.c
new file mode 100644
index 00000000000..ed3e6098584
--- /dev/null
+++ b/src/emu/cpu/hd6309/6309ops.c
@@ -0,0 +1,5599 @@
+/*
+
+HNZVC
+
+? = undefined
+* = affected
+- = unaffected
+0 = cleared
+1 = set
+# = CCr directly affected by instruction
+@ = special - carry set if bit 7 is set
+
+*/
+
+INLINE void illegal( void )
+{
+ LOG(("HD6309: illegal opcode at %04x\nVectoring to [$fff0]\n",PC));
+
+ CC |= CC_E;
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+
+ if ( MD & MD_EM )
+ {
+ PUSHBYTE(F);
+ PUSHBYTE(E);
+ hd6309_ICount -= 2;
+ }
+
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+
+ PCD = RM16(0xfff0);
+ CHANGE_PC;
+}
+
+static void IIError(void)
+{
+ SEII; // Set illegal Instruction Flag
+ illegal(); // Vector to Trap handler
+}
+
+static void DZError(void)
+{
+ SEDZ; // Set Division by Zero Flag
+ illegal(); // Vector to Trap handler
+}
+
+/* $00 NEG direct ?**** */
+INLINE void neg_di( void )
+{
+ UINT16 r,t;
+ DIRBYTE(t);
+ r = -t;
+ CLR_NZVC;
+ SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $01 OIM direct ?**** */
+INLINE void oim_di( void )
+{
+ UINT8 r,t,im;
+ IMMBYTE(im);
+ DIRBYTE(t);
+ r = im | t;
+ CLR_NZV;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $02 AIM direct */
+INLINE void aim_di( void )
+{
+ UINT8 r,t,im;
+ IMMBYTE(im);
+ DIRBYTE(t);
+ r = im & t;
+ CLR_NZV;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $03 COM direct -**01 */
+INLINE void com_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ t = ~t;
+ CLR_NZV;
+ SET_NZ8(t);
+ SEC;
+ WM(EAD,t);
+}
+
+/* $04 LSR direct -0*-* */
+INLINE void lsr_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t >>= 1;
+ SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $05 EIM direct */
+INLINE void eim_di( void )
+{
+ UINT8 r,t,im;
+ IMMBYTE(im);
+ DIRBYTE(t);
+ r = im ^ t;
+ CLR_NZV;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $06 ROR direct -**-* */
+INLINE void ror_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r= (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (t & CC_C);
+ r |= t>>1;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $07 ASR direct ?**-* */
+INLINE void asr_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t = (t & 0x80) | (t >> 1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $08 ASL direct ?**** */
+INLINE void asl_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $09 ROL direct -**** */
+INLINE void rol_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = (CC & CC_C) | (t << 1);
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $0A DEC direct -***- */
+INLINE void dec_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ --t;
+ CLR_NZV;
+ SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $0B TIM direct */
+INLINE void tim_di( void )
+{
+ UINT8 r,t,im;
+ IMMBYTE(im);
+ DIRBYTE(t);
+ r = im & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $OC INC direct -***- */
+INLINE void inc_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ ++t;
+ CLR_NZV;
+ SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $OD TST direct -**0- */
+INLINE void tst_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZV;
+ SET_NZ8(t);
+}
+
+/* $0E JMP direct ----- */
+INLINE void jmp_di( void )
+{
+ DIRECT;
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $0F CLR direct -0100 */
+INLINE void clr_di( void )
+{
+ UINT32 dummy;
+ DIRECT;
+ dummy = RM(EAD);
+ WM(EAD,0);
+ CLR_NZVC;
+ SEZ;
+}
+
+/* $10 FLAG */
+
+/* $11 FLAG */
+
+/* $12 NOP inherent ----- */
+INLINE void nop( void )
+{
+ ;
+}
+
+/* $13 SYNC inherent ----- */
+INLINE void sync( void )
+{
+ /* SYNC stops processing instructions until an interrupt request happens. */
+ /* This doesn't require the corresponding interrupt to be enabled: if it */
+ /* is disabled, execution continues with the next instruction. */
+ hd6309.int_state |= HD6309_SYNC; /* HJB 990227 */
+ CHECK_IRQ_LINES();
+ /* if HD6309_SYNC has not been cleared by CHECK_IRQ_LINES(),
+ * stop execution until the interrupt lines change. */
+ if( hd6309.int_state & HD6309_SYNC )
+ if (hd6309_ICount > 0) hd6309_ICount = 0;
+}
+
+/* $14 sexw inherent */
+INLINE void sexw( void )
+{
+ PAIR q;
+ q.d = SIGNED_16(W);
+ D = q.w.h;
+ W = q.w.l;
+ CLR_NZ;
+ SET_N16(D);
+ SET_Z(q.d);
+}
+
+/* $15 ILLEGAL */
+
+/* $16 LBRA relative ----- */
+INLINE void lbra( void )
+{
+ IMMWORD(ea);
+ PC += EA;
+ CHANGE_PC;
+
+ if ( EA == 0xfffd ) /* EHC 980508 speed up busy loop */
+ if ( hd6309_ICount > 0)
+ hd6309_ICount = 0;
+}
+
+/* $17 LBSR relative ----- */
+INLINE void lbsr( void )
+{
+ IMMWORD(ea);
+ PUSHWORD(pPC);
+ PC += EA;
+ CHANGE_PC;
+}
+
+/* $18 ILLEGAL */
+
+/* $19 DAA inherent (A) -**0* */
+INLINE void daa( void )
+{
+ UINT8 msn, lsn;
+ UINT16 t, cf = 0;
+ msn = A & 0xf0; lsn = A & 0x0f;
+ if( lsn>0x09 || CC & CC_H) cf |= 0x06;
+ if( msn>0x80 && lsn>0x09 ) cf |= 0x60;
+ if( msn>0x90 || CC & CC_C) cf |= 0x60;
+ t = cf + A;
+ CLR_NZV; /* keep carry from previous operation */
+ SET_NZ8((UINT8)t); SET_C8(t);
+ A = t;
+}
+
+/* $1A ORCC immediate ##### */
+INLINE void orcc( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ CC |= t;
+ CHECK_IRQ_LINES(); /* HJB 990116 */
+}
+
+/* $1B ILLEGAL */
+
+/* $1C ANDCC immediate ##### */
+INLINE void andcc( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ CC &= t;
+ CHECK_IRQ_LINES(); /* HJB 990116 */
+}
+
+/* $1D SEX inherent -**0- */
+INLINE void sex( void )
+{
+ UINT16 t;
+ t = SIGNED(B);
+ D = t;
+ CLR_NZ;
+ SET_NZ16(t);
+}
+
+INLINE void exg( void )
+{
+ UINT16 t1,t2;
+ UINT8 tb;
+ int promote = FALSE;
+
+ IMMBYTE(tb);
+ if( (tb^(tb>>4)) & 0x08 ) /* HJB 990225: mixed 8/16 bit case? */
+ {
+ promote = TRUE;
+ }
+
+ switch(tb>>4) {
+ case 0: t1 = D; break;
+ case 1: t1 = X; break;
+ case 2: t1 = Y; break;
+ case 3: t1 = U; break;
+ case 4: t1 = S; break;
+ case 5: t1 = PC; break;
+ case 6: t1 = W; break;
+ case 7: t1 = V; break;
+ case 8: t1 = (promote ? A + ((A) << 8) : A); break;
+ case 9: t1 = (promote ? B + ((B) << 8) : B); break;
+ case 10: t1 = (promote ? CC + ((CC) << 8) : CC); break;
+ case 11: t1 = (promote ? DP + ((DP) << 8) : DP); break;
+ case 12: t1 = 0; break;
+ case 13: t1 = 0; break;
+ case 14: t1 = (promote ? E + ((E) << 8) : E); break;
+ default: t1 = (promote ? F + ((F) << 8) : F); break;
+ }
+ switch(tb&15) {
+ case 0: t2 = D; break;
+ case 1: t2 = X; break;
+ case 2: t2 = Y; break;
+ case 3: t2 = U; break;
+ case 4: t2 = S; break;
+ case 5: t2 = PC; break;
+ case 6: t2 = W; break;
+ case 7: t2 = V; break;
+ case 8: t2 = (promote ? A + ((A) << 8) : A); break;
+ case 9: t2 = (promote ? B + ((B) << 8) : B); break;
+ case 10: t2 = (promote ? CC + ((CC) << 8) : CC); break;
+ case 11: t2 = (promote ? DP + ((DP) << 8) : DP); break;
+ case 12: t2 = 0; break;
+ case 13: t2 = 0; break;
+ case 14: t2 = (promote ? E + ((E) << 8) : E); break;
+ default: t2 = (promote ? F + ((F) << 8) : F); break;
+ }
+
+ switch(tb>>4) {
+ case 0: D = t2; break;
+ case 1: X = t2; break;
+ case 2: Y = t2; break;
+ case 3: U = t2; break;
+ case 4: S = t2; break;
+ case 5: PC = t2; CHANGE_PC; break;
+ case 6: W = t2; break;
+ case 7: V = t2; break;
+ case 8: A = (promote ? t2 >> 8 : t2); break;
+ case 9: B = (promote ? t2 & 0xff : t2); break;
+ case 10: CC = (promote ? t2 & 0xff : t2); break;
+ case 11: DP = (promote ? t2 >> 8 : t2); break;
+ case 12: /* 0 = t2 */ break;
+ case 13: /* 0 = t2 */ break;
+ case 14: E = (promote ? t2 >> 8 : t2); break;
+ case 15: F = (promote ? t2 & 0xff : t2); break;
+ }
+ switch(tb&15) {
+ case 0: D = t1; break;
+ case 1: X = t1; break;
+ case 2: Y = t1; break;
+ case 3: U = t1; break;
+ case 4: S = t1; break;
+ case 5: PC = t1; CHANGE_PC; break;
+ case 6: W = t1; break;
+ case 7: V = t1; break;
+ case 8: A = (promote ? t1 >> 8 : t1); break;
+ case 9: B = (promote ? t1 & 0xff : t1); break;
+ case 10: CC = (promote ? t1 & 0xff : t1); break;
+ case 11: DP = (promote ? t1 >> 8 : t1); break;
+ case 12: /* 0 = t1 */ break;
+ case 13: /* 0 = t1 */ break;
+ case 14: E = (promote ? t1 >> 8 : t1); break;
+ case 15: F = (promote ? t1 & 0xff : t1); break;
+ }
+}
+
+/* $1F TFR inherent ----- */
+INLINE void tfr( void )
+{
+ UINT8 tb;
+ UINT16 t;
+ int promote = FALSE;
+
+ IMMBYTE(tb);
+ if( (tb^(tb>>4)) & 0x08 )
+ {
+ promote = TRUE;
+ }
+
+ switch(tb>>4) {
+ case 0: t = D; break;
+ case 1: t = X; break;
+ case 2: t = Y; break;
+ case 3: t = U; break;
+ case 4: t = S; break;
+ case 5: t = PC; break;
+ case 6: t = W; break;
+ case 7: t = V; break;
+ case 8: t = (promote ? A + ((A) << 8) : A); break;
+ case 9: t = (promote ? B + ((B) << 8) : B); break;
+ case 10: t = (promote ? CC + ((CC) << 8) : CC); break;
+ case 11: t = (promote ? DP + ((DP) << 8) : DP); break;
+ case 12: t = 0; break;
+ case 13: t = 0; break;
+ case 14: t = (promote ? E + ((E) << 8) : E); break;
+ default: t = (promote ? F + ((F) << 8) : F); break;
+ }
+
+ switch(tb&15) {
+ case 0: D = t; break;
+ case 1: X = t; break;
+ case 2: Y = t; break;
+ case 3: U = t; break;
+ case 4: S = t; break;
+ case 5: PC = t; CHANGE_PC; break;
+ case 6: W = t; break;
+ case 7: V = t; break;
+ case 8: A = (promote ? t >> 8 : t); break;
+ case 9: B = (promote ? t & 0xff : t); break;
+ case 10: CC = (promote ? t & 0xff : t); break;
+ case 11: DP = (promote ? t >> 8 : t); break;
+ case 12: /* 0 = t */ break;
+ case 13: /* 0 = t */ break;
+ case 14: E = (promote ? t >> 8 : t); break;
+ case 15: F = (promote ? t & 0xff : t); break;
+ }
+}
+
+/* $20 BRA relative ----- */
+INLINE void bra( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ PC += SIGNED(t);
+ CHANGE_PC;
+ /* JB 970823 - speed up busy loops */
+ if( t == 0xfe )
+ if( hd6309_ICount > 0 ) hd6309_ICount = 0;
+}
+
+/* $21 BRN relative ----- */
+INLINE void brn( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+}
+
+/* $1021 LBRN relative ----- */
+INLINE void lbrn( void )
+{
+ IMMWORD(ea);
+}
+
+/* $22 BHI relative ----- */
+INLINE void bhi( void )
+{
+ BRANCH( !(CC & (CC_Z|CC_C)) );
+}
+
+/* $1022 LBHI relative ----- */
+INLINE void lbhi( void )
+{
+ LBRANCH( !(CC & (CC_Z|CC_C)) );
+}
+
+/* $23 BLS relative ----- */
+INLINE void bls( void )
+{
+ BRANCH( (CC & (CC_Z|CC_C)) );
+}
+
+/* $1023 LBLS relative ----- */
+INLINE void lbls( void )
+{
+ LBRANCH( (CC&(CC_Z|CC_C)) );
+}
+
+/* $24 BCC relative ----- */
+INLINE void bcc( void )
+{
+ BRANCH( !(CC&CC_C) );
+}
+
+/* $1024 LBCC relative ----- */
+INLINE void lbcc( void )
+{
+ LBRANCH( !(CC&CC_C) );
+}
+
+/* $25 BCS relative ----- */
+INLINE void bcs( void )
+{
+ BRANCH( (CC&CC_C) );
+}
+
+/* $1025 LBCS relative ----- */
+INLINE void lbcs( void )
+{
+ LBRANCH( (CC&CC_C) );
+}
+
+/* $26 BNE relative ----- */
+INLINE void bne( void )
+{
+ BRANCH( !(CC&CC_Z) );
+}
+
+/* $1026 LBNE relative ----- */
+INLINE void lbne( void )
+{
+ LBRANCH( !(CC&CC_Z) );
+}
+
+/* $27 BEQ relative ----- */
+INLINE void beq( void )
+{
+ BRANCH( (CC&CC_Z) );
+}
+
+/* $1027 LBEQ relative ----- */
+INLINE void lbeq( void )
+{
+ LBRANCH( (CC&CC_Z) );
+}
+
+/* $28 BVC relative ----- */
+INLINE void bvc( void )
+{
+ BRANCH( !(CC&CC_V) );
+}
+
+/* $1028 LBVC relative ----- */
+INLINE void lbvc( void )
+{
+ LBRANCH( !(CC&CC_V) );
+}
+
+/* $29 BVS relative ----- */
+INLINE void bvs( void )
+{
+ BRANCH( (CC&CC_V) );
+}
+
+/* $1029 LBVS relative ----- */
+INLINE void lbvs( void )
+{
+ LBRANCH( (CC&CC_V) );
+}
+
+/* $2A BPL relative ----- */
+INLINE void bpl( void )
+{
+ BRANCH( !(CC&CC_N) );
+}
+
+/* $102A LBPL relative ----- */
+INLINE void lbpl( void )
+{
+ LBRANCH( !(CC&CC_N) );
+}
+
+/* $2B BMI relative ----- */
+INLINE void bmi( void )
+{
+ BRANCH( (CC&CC_N) );
+}
+
+/* $102B LBMI relative ----- */
+INLINE void lbmi( void )
+{
+ LBRANCH( (CC&CC_N) );
+}
+
+/* $2C BGE relative ----- */
+INLINE void bge( void )
+{
+ BRANCH( !NXORV );
+}
+
+/* $102C LBGE relative ----- */
+INLINE void lbge( void )
+{
+ LBRANCH( !NXORV );
+}
+
+/* $2D BLT relative ----- */
+INLINE void blt( void )
+{
+ BRANCH( NXORV );
+}
+
+/* $102D LBLT relative ----- */
+INLINE void lblt( void )
+{
+ LBRANCH( NXORV );
+}
+
+/* $2E BGT relative ----- */
+INLINE void bgt( void )
+{
+ BRANCH( !(NXORV || (CC&CC_Z)) );
+}
+
+/* $102E LBGT relative ----- */
+INLINE void lbgt( void )
+{
+ LBRANCH( !(NXORV || (CC&CC_Z)) );
+}
+
+/* $2F BLE relative ----- */
+INLINE void ble( void )
+{
+ BRANCH( (NXORV || (CC&CC_Z)) );
+}
+
+/* $102F LBLE relative ----- */
+INLINE void lble( void )
+{
+ LBRANCH( (NXORV || (CC&CC_Z)) );
+}
+
+#define REGREG_PREAMBLE \
+ IMMBYTE(tb); \
+ if( (tb^(tb>>4)) & 0x08 ) \
+ {promote = TRUE;} \
+ switch(tb>>4) { \
+ case 0: src16Reg = &D; large = TRUE; break; \
+ case 1: src16Reg = &X; large = TRUE; break; \
+ case 2: src16Reg = &Y; large = TRUE; break; \
+ case 3: src16Reg = &U; large = TRUE; break; \
+ case 4: src16Reg = &S; large = TRUE; break; \
+ case 5: src16Reg = &PC; large = TRUE; break; \
+ case 6: src16Reg = &W; large = TRUE; break; \
+ case 7: src16Reg = &V; large = TRUE; break; \
+ case 8: if (promote) src16Reg = &D; else src8Reg = &A; break; \
+ case 9: if (promote) src16Reg = &D; else src8Reg = &B; break; \
+ case 10: if (promote) src16Reg = &z16; else src8Reg = &CC; break; \
+ case 11: if (promote) src16Reg = &z16; else src8Reg = &DP; break; \
+ case 12: if (promote) src16Reg = &z16; else src8Reg = &z8; break; \
+ case 13: if (promote) src16Reg = &z16; else src8Reg = &z8; break; \
+ case 14: if (promote) src16Reg = &W; else src8Reg = &E; break; \
+ default: if (promote) src16Reg = &W; else src8Reg = &F; break; \
+ } \
+ switch(tb&15) { \
+ case 0: dst16Reg = &D; large = TRUE; break; \
+ case 1: dst16Reg = &X; large = TRUE; break; \
+ case 2: dst16Reg = &Y; large = TRUE; break; \
+ case 3: dst16Reg = &U; large = TRUE; break; \
+ case 4: dst16Reg = &S; large = TRUE; break; \
+ case 5: dst16Reg = &PC; large = TRUE; break; \
+ case 6: dst16Reg = &W; large = TRUE; break; \
+ case 7: dst16Reg = &V; large = TRUE; break; \
+ case 8: if (promote) dst16Reg = &D; else dst8Reg = &A; break; \
+ case 9: if (promote) dst16Reg = &D; else dst8Reg = &B; break; \
+ case 10: if (promote) dst16Reg = &z16; else dst8Reg = &CC; break; \
+ case 11: if (promote) dst16Reg = &z16; else dst8Reg = &DP; break; \
+ case 12: if (promote) dst16Reg = &z16; else dst8Reg = &z8; break; \
+ case 13: if (promote) dst16Reg = &z16; else dst8Reg = &z8; break; \
+ case 14: if (promote) dst16Reg = &W; else dst8Reg = &E; break; \
+ default: if (promote) dst16Reg = &W; else dst8Reg = &F; break; \
+ } \
+
+/* $1030 addr_r r1 + r2 -> r2 */
+
+INLINE void addr_r( void )
+{
+ UINT8 tb, z8 = 0;
+ UINT16 z16 = 0, r8;
+ UINT32 r16;
+ UINT8 *src8Reg = NULL, *dst8Reg = NULL;
+ UINT16 *src16Reg = NULL, *dst16Reg = NULL;
+ int promote = FALSE, large = FALSE;
+
+ REGREG_PREAMBLE;
+
+ if ( large )
+ {
+ r16 = *src16Reg + *dst16Reg;
+ CLR_NZVC;
+ *dst16Reg = r16;
+ SET_FLAGS16(*src16Reg,*dst16Reg,r16);
+
+ if ( (tb&15) == 5 )
+ {
+ CHANGE_PC;
+ }
+ }
+ else
+ {
+ r8 = *src8Reg + *dst8Reg;
+ CLR_NZVC;
+ /* SET_H(*src8Reg,*src8Reg,r8);*/ /*Experimentation prooved this not to be the case */
+ *dst8Reg = r8;
+ SET_FLAGS8(*src8Reg,*dst8Reg,r8);
+ }
+}
+
+INLINE void adcr( void )
+{
+ UINT8 tb, z8 = 0;
+ UINT16 z16 = 0, r8;
+ UINT32 r16;
+ UINT8 *src8Reg = NULL, *dst8Reg = NULL;
+ UINT16 *src16Reg = NULL, *dst16Reg = NULL;
+ int promote = FALSE, large = FALSE;
+
+ REGREG_PREAMBLE;
+
+ if ( large )
+ {
+ r16 = *src16Reg + *dst16Reg + (CC & CC_C);
+ CLR_NZVC;
+ *dst16Reg = r16;
+ SET_FLAGS16(*src16Reg,*dst16Reg,r16);
+
+ if ( (tb&15) == 5 )
+ {
+ CHANGE_PC;
+ }
+ }
+ else
+ {
+ r8 = *src8Reg + *dst8Reg + (CC & CC_C);
+ CLR_NZVC;
+ /* SET_H(*src8Reg,*src8Reg,r8);*/ /*Experimentation prooved this not to be the case */
+ *dst8Reg = r8;
+ SET_FLAGS8(*src8Reg,*dst8Reg,r8);
+ }
+}
+
+/* $1032 SUBR r1 - r2 -> r2 */
+INLINE void subr( void )
+{
+ UINT8 tb, z8 = 0;
+ UINT16 z16 = 0, r8;
+ UINT32 r16;
+ UINT8 *src8Reg = NULL, *dst8Reg = NULL;
+ UINT16 *src16Reg = NULL, *dst16Reg = NULL;
+ int promote = FALSE, large = FALSE;
+
+ REGREG_PREAMBLE;
+
+ if ( large )
+ {
+ r16 = (UINT32)*dst16Reg - (UINT32)*src16Reg;
+ CLR_NZVC;
+ *dst16Reg = r16;
+ SET_FLAGS16((UINT32)*dst16Reg,(UINT32)*src16Reg,r16);
+
+ if ( (tb&15) == 5 )
+ {
+ CHANGE_PC;
+ }
+ }
+ else
+ {
+ r8 = *dst8Reg - *src8Reg;
+ CLR_NZVC;
+ *dst8Reg = r8;
+ SET_FLAGS8(*dst8Reg,*src8Reg,r8);
+ }
+}
+
+/* $1033 SBCR r1 - r2 - C -> r2 */
+INLINE void sbcr( void )
+{
+ UINT8 tb, z8 = 0;
+ UINT16 z16 = 0, r8;
+ UINT32 r16;
+ UINT8 *src8Reg = NULL, *dst8Reg = NULL;
+ UINT16 *src16Reg = NULL, *dst16Reg = NULL;
+ int promote = FALSE, large = FALSE;
+
+ REGREG_PREAMBLE;
+
+ if ( large )
+ {
+ r16 = (UINT32)*dst16Reg - (UINT32)*src16Reg - (CC & CC_C);
+ CLR_NZVC;
+ *dst16Reg = r16;
+ SET_FLAGS16((UINT32)*dst16Reg,(UINT32)*src16Reg,r16);
+
+ if ( (tb&15) == 5 )
+ {
+ CHANGE_PC;
+ }
+ }
+ else
+ {
+ r8 = *dst8Reg - *src8Reg - (CC & CC_C);
+ CLR_NZVC;
+ *dst8Reg = r8;
+ SET_FLAGS8(*dst8Reg,*src8Reg,r8);
+ }
+}
+
+/* $1034 ANDR r1 & r2 -> r2 */
+INLINE void andr( void )
+{
+ UINT8 tb, z8 = 0;
+ UINT16 z16 = 0, r8;
+ UINT32 r16;
+ UINT8 *src8Reg = NULL, *dst8Reg = NULL;
+ UINT16 *src16Reg = NULL, *dst16Reg = NULL;
+ int promote = FALSE, large = FALSE;
+
+ REGREG_PREAMBLE;
+
+ if ( large )
+ {
+ r16 = *src16Reg & *dst16Reg;
+ CLR_NZV;
+ *dst16Reg = r16;
+ SET_NZ16(r16);
+
+ if ( (tb&15) == 5 )
+ {
+ CHANGE_PC;
+ }
+ }
+ else
+ {
+ r8 = *src8Reg & *dst8Reg;
+ CLR_NZV;
+ *dst8Reg = r8;
+ SET_NZ8(r8);
+ }
+}
+
+/* $1035 ORR r1 | r2 -> r2 */
+INLINE void orr( void )
+{
+ UINT8 tb, z8 = 0;
+ UINT16 z16 = 0, r8;
+ UINT32 r16;
+ UINT8 *src8Reg = NULL, *dst8Reg = NULL;
+ UINT16 *src16Reg = NULL, *dst16Reg = NULL;
+ int promote = FALSE, large = FALSE;
+
+ REGREG_PREAMBLE;
+
+ if ( large )
+ {
+ r16 = *src16Reg | *dst16Reg;
+ CLR_NZV;
+ *dst16Reg = r16;
+ SET_NZ16(r16);
+
+ if ( (tb&15) == 5 )
+ {
+ CHANGE_PC;
+ }
+ }
+ else
+ {
+ r8 = *src8Reg | *dst8Reg;
+ CLR_NZV;
+ *dst8Reg = r8;
+ SET_NZ8(r8);
+ }
+}
+
+/* $1036 EORR r1 ^ r2 -> r2 */
+INLINE void eorr( void )
+{
+ UINT8 tb, z8 = 0;
+ UINT16 z16 = 0, r8;
+ UINT32 r16;
+ UINT8 *src8Reg = NULL, *dst8Reg = NULL;
+ UINT16 *src16Reg = NULL, *dst16Reg = NULL;
+ int promote = FALSE, large = FALSE;
+
+ REGREG_PREAMBLE;
+
+ if ( large )
+ {
+ r16 = *src16Reg ^ *dst16Reg;
+ CLR_NZV;
+ *dst16Reg = r16;
+ SET_NZ16(r16);
+
+ if ( (tb&15) == 5 )
+ {
+ CHANGE_PC;
+ }
+ }
+ else
+ {
+ r8 = *src8Reg ^ *dst8Reg;
+ CLR_NZV;
+ *dst8Reg = r8;
+ SET_NZ8(r8);
+ }
+}
+
+/* $1037 CMPR r1 - r2 */
+INLINE void cmpr( void )
+{
+ UINT8 tb, z8 = 0;
+ UINT16 z16 = 0, r8;
+ UINT32 r16;
+ UINT8 *src8Reg = NULL, *dst8Reg = NULL;
+ UINT16 *src16Reg = NULL, *dst16Reg = NULL;
+ int promote = FALSE, large = FALSE;
+
+ REGREG_PREAMBLE;
+
+ if ( large )
+ {
+ r16 = (UINT32)*dst16Reg - (UINT32)*src16Reg;
+ CLR_NZVC;
+ SET_FLAGS16((UINT32)*dst16Reg,(UINT32)*src16Reg,r16);
+ }
+ else
+ {
+ r8 = *dst8Reg - *src8Reg;
+ CLR_NZVC;
+ SET_FLAGS8(*dst8Reg,*src8Reg,r8);
+ }
+}
+
+/* $1138 TFM R0+,R1+ */
+INLINE void tfmpp( void )
+{
+ UINT8 tb, srcValue = 0;
+
+ IMMBYTE(tb);
+
+ if ( W != 0 )
+ {
+ switch(tb>>4) {
+ case 0: srcValue = RM(D++); break;
+ case 1: srcValue = RM(X++); break;
+ case 2: srcValue = RM(Y++); break;
+ case 3: srcValue = RM(U++); break;
+ case 4: srcValue = RM(S++); break;
+ default: IIError(); return; break; /* reg PC thru F */
+ }
+
+ switch(tb&15) {
+ case 0: WM(D++, srcValue); break;
+ case 1: WM(X++, srcValue); break;
+ case 2: WM(Y++, srcValue); break;
+ case 3: WM(U++, srcValue); break;
+ case 4: WM(S++, srcValue); break;
+ default: IIError(); return; break; /* reg PC thru F */
+ }
+
+ PCD = PCD - 3;
+ CHANGE_PC;
+ W--;
+ }
+ else
+ hd6309_ICount -= 6; /* Needs six aditional cycles to get the 6+3n */
+}
+
+/* $1139 TFM R0-,R1- */
+INLINE void tfmmm( void )
+{
+ UINT8 tb, srcValue = 0;
+
+ IMMBYTE(tb);
+
+ if ( W != 0 )
+ {
+ switch(tb>>4) {
+ case 0: srcValue = RM(D--); break;
+ case 1: srcValue = RM(X--); break;
+ case 2: srcValue = RM(Y--); break;
+ case 3: srcValue = RM(U--); break;
+ case 4: srcValue = RM(S--); break;
+ default: IIError(); return; break; /* reg PC thru F */
+ }
+
+ switch(tb&15) {
+ case 0: WM(D--, srcValue); break;
+ case 1: WM(X--, srcValue); break;
+ case 2: WM(Y--, srcValue); break;
+ case 3: WM(U--, srcValue); break;
+ case 4: WM(S--, srcValue); break;
+ default: IIError(); return; break; /* reg PC thru F */
+ }
+
+ PCD = PCD - 3;
+ CHANGE_PC;
+ W--;
+ }
+ else
+ hd6309_ICount -= 6; /* Needs six aditional cycles to get the 6+3n */
+}
+
+/* $113A TFM R0+,R1 */
+INLINE void tfmpc( void )
+{
+ UINT8 tb, srcValue = 0;
+
+ IMMBYTE(tb);
+
+ if ( W != 0 )
+ {
+ switch(tb>>4) {
+ case 0: srcValue = RM(D++); break;
+ case 1: srcValue = RM(X++); break;
+ case 2: srcValue = RM(Y++); break;
+ case 3: srcValue = RM(U++); break;
+ case 4: srcValue = RM(S++); break;
+ default: IIError(); return; break; /* reg PC thru F */
+ }
+
+ switch(tb&15) {
+ case 0: WM(D, srcValue); break;
+ case 1: WM(X, srcValue); break;
+ case 2: WM(Y, srcValue); break;
+ case 3: WM(U, srcValue); break;
+ case 4: WM(S, srcValue); break;
+ default: IIError(); return; break; /* reg PC thru F */
+ }
+
+ PCD = PCD - 3;
+ CHANGE_PC;
+ W--;
+ }
+ else
+ hd6309_ICount -= 6; /* Needs six aditional cycles to get the 6+3n */
+}
+
+/* $113B TFM R0,R1+ */
+INLINE void tfmcp( void )
+{
+ UINT8 tb, srcValue = 0;
+
+ IMMBYTE(tb);
+
+ if ( W != 0 )
+ {
+ switch(tb>>4) {
+ case 0: srcValue = RM(D); break;
+ case 1: srcValue = RM(X); break;
+ case 2: srcValue = RM(Y); break;
+ case 3: srcValue = RM(U); break;
+ case 4: srcValue = RM(S); break;
+ default: IIError(); return; break; /* reg PC thru F */
+ }
+
+ switch(tb&15) {
+ case 0: WM(D++, srcValue); break;
+ case 1: WM(X++, srcValue); break;
+ case 2: WM(Y++, srcValue); break;
+ case 3: WM(U++, srcValue); break;
+ case 4: WM(S++, srcValue); break;
+ default: IIError(); return; break; /* reg PC thru F */
+ }
+
+ PCD = PCD - 3;
+ CHANGE_PC;
+ W--;
+ }
+ else
+ hd6309_ICount -= 6; /* Needs six aditional cycles to get the 6+3n */
+}
+
+/* $30 LEAX indexed --*-- */
+INLINE void leax( void )
+{
+ fetch_effective_address();
+ X = EA;
+ CLR_Z;
+ SET_Z(X);
+}
+
+/* $31 LEAY indexed --*-- */
+INLINE void leay( void )
+{
+ fetch_effective_address();
+ Y = EA;
+ CLR_Z;
+ SET_Z(Y);
+}
+
+/* $32 LEAS indexed ----- */
+INLINE void leas( void )
+{
+ fetch_effective_address();
+ S = EA;
+ hd6309.int_state |= HD6309_LDS;
+}
+
+/* $33 LEAU indexed ----- */
+INLINE void leau( void )
+{
+ fetch_effective_address();
+ U = EA;
+}
+
+/* $34 PSHS inherent ----- */
+INLINE void pshs( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x80 ) { PUSHWORD(pPC); hd6309_ICount -= 2; }
+ if( t&0x40 ) { PUSHWORD(pU); hd6309_ICount -= 2; }
+ if( t&0x20 ) { PUSHWORD(pY); hd6309_ICount -= 2; }
+ if( t&0x10 ) { PUSHWORD(pX); hd6309_ICount -= 2; }
+ if( t&0x08 ) { PUSHBYTE(DP); hd6309_ICount -= 1; }
+ if( t&0x04 ) { PUSHBYTE(B); hd6309_ICount -= 1; }
+ if( t&0x02 ) { PUSHBYTE(A); hd6309_ICount -= 1; }
+ if( t&0x01 ) { PUSHBYTE(CC); hd6309_ICount -= 1; }
+}
+
+/* $1038 PSHSW inherent ----- */
+INLINE void pshsw( void )
+{
+ PUSHWORD(pW);
+}
+
+/* $103a PSHUW inherent ----- */
+INLINE void pshuw( void )
+{
+ PSHUWORD(pW);
+}
+
+/* $35 PULS inherent ----- */
+INLINE void puls( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x01 ) { PULLBYTE(CC); hd6309_ICount -= 1; }
+ if( t&0x02 ) { PULLBYTE(A); hd6309_ICount -= 1; }
+ if( t&0x04 ) { PULLBYTE(B); hd6309_ICount -= 1; }
+ if( t&0x08 ) { PULLBYTE(DP); hd6309_ICount -= 1; }
+ if( t&0x10 ) { PULLWORD(XD); hd6309_ICount -= 2; }
+ if( t&0x20 ) { PULLWORD(YD); hd6309_ICount -= 2; }
+ if( t&0x40 ) { PULLWORD(UD); hd6309_ICount -= 2; }
+ if( t&0x80 ) { PULLWORD(PCD); CHANGE_PC; hd6309_ICount -= 2; }
+
+ /* HJB 990225: moved check after all PULLs */
+ if( t&0x01 ) { CHECK_IRQ_LINES(); }
+}
+
+/* $1039 PULSW inherent ----- */
+INLINE void pulsw( void )
+{
+ PULLWORD(W);
+}
+
+/* $103b PULUW inherent ----- */
+INLINE void puluw( void )
+{
+ PULUWORD(W);
+}
+
+/* $36 PSHU inherent ----- */
+INLINE void pshu( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x80 ) { PSHUWORD(pPC); hd6309_ICount -= 2; }
+ if( t&0x40 ) { PSHUWORD(pS); hd6309_ICount -= 2; }
+ if( t&0x20 ) { PSHUWORD(pY); hd6309_ICount -= 2; }
+ if( t&0x10 ) { PSHUWORD(pX); hd6309_ICount -= 2; }
+ if( t&0x08 ) { PSHUBYTE(DP); hd6309_ICount -= 1; }
+ if( t&0x04 ) { PSHUBYTE(B); hd6309_ICount -= 1; }
+ if( t&0x02 ) { PSHUBYTE(A); hd6309_ICount -= 1; }
+ if( t&0x01 ) { PSHUBYTE(CC); hd6309_ICount -= 1; }
+}
+
+/* 37 PULU inherent ----- */
+INLINE void pulu( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x01 ) { PULUBYTE(CC); hd6309_ICount -= 1; }
+ if( t&0x02 ) { PULUBYTE(A); hd6309_ICount -= 1; }
+ if( t&0x04 ) { PULUBYTE(B); hd6309_ICount -= 1; }
+ if( t&0x08 ) { PULUBYTE(DP); hd6309_ICount -= 1; }
+ if( t&0x10 ) { PULUWORD(XD); hd6309_ICount -= 2; }
+ if( t&0x20 ) { PULUWORD(YD); hd6309_ICount -= 2; }
+ if( t&0x40 ) { PULUWORD(SD); hd6309_ICount -= 2; }
+ if( t&0x80 ) { PULUWORD(PCD); CHANGE_PC; hd6309_ICount -= 2; }
+
+ /* HJB 990225: moved check after all PULLs */
+ if( t&0x01 ) { CHECK_IRQ_LINES(); }
+}
+
+/* $38 ILLEGAL */
+
+/* $39 RTS inherent ----- */
+INLINE void rts( void )
+{
+ PULLWORD(PCD);
+ CHANGE_PC;
+}
+
+/* $3A ABX inherent ----- */
+INLINE void abx( void )
+{
+ X += B;
+}
+
+/* $3B RTI inherent ##### */
+INLINE void rti( void )
+{
+ UINT8 t;
+ PULLBYTE(CC);
+ t = CC & CC_E; /* HJB 990225: entire state saved? */
+ if(t)
+ {
+ hd6309_ICount -= 9;
+ PULLBYTE(A);
+ PULLBYTE(B);
+ if ( MD & MD_EM )
+ {
+ PULLBYTE(E);
+ PULLBYTE(F);
+ hd6309_ICount -= 2;
+ }
+ PULLBYTE(DP);
+ PULLWORD(XD);
+ PULLWORD(YD);
+ PULLWORD(UD);
+ }
+ PULLWORD(PCD);
+ CHANGE_PC;
+ CHECK_IRQ_LINES(); /* HJB 990116 */
+}
+
+/* $3C CWAI inherent ----1 */
+INLINE void cwai( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ CC &= t;
+ /*
+ * CWAI stacks the entire machine state on the hardware stack,
+ * then waits for an interrupt; when the interrupt is taken
+ * later, the state is *not* saved again after CWAI.
+ */
+ CC |= CC_E; /* HJB 990225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ if ( MD & MD_EM )
+ {
+ PUSHBYTE(E);
+ PUSHBYTE(F);
+ }
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ hd6309.int_state |= HD6309_CWAI; /* HJB 990228 */
+ CHECK_IRQ_LINES(); /* HJB 990116 */
+ if( hd6309.int_state & HD6309_CWAI )
+ if( hd6309_ICount > 0 )
+ hd6309_ICount = 0;
+}
+
+/* $3D MUL inherent --*-@ */
+INLINE void mul( void )
+{
+ UINT16 t;
+ t = A * B;
+ CLR_ZC; SET_Z16(t); if(t&0x80) SEC;
+ D = t;
+}
+
+/* $3E ILLEGAL */
+
+/* $3F SWI (SWI2 SWI3) absolute indirect ----- */
+INLINE void swi( void )
+{
+ CC |= CC_E; /* HJB 980225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ if ( MD & MD_EM )
+ {
+ PUSHBYTE(F);
+ PUSHBYTE(E);
+ }
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */
+ PCD=RM16(0xfffa);
+ CHANGE_PC;
+}
+
+/* $1130 BAND */
+
+#define decodePB_tReg(n) (((n) >> 6) & 0x03)
+#define decodePB_src(n) (((n) >> 3) & 0x07)
+#define decodePB_dst(n) (((n) >> 0) & 0x07)
+
+static UINT8 dummy_byte;
+static unsigned char *regTable[4] = { &(CC), &(A), &(B), &dummy_byte };
+
+static const UINT8 bitTable[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+
+INLINE void band( void )
+{
+ UINT8 pb;
+ UINT16 db;
+
+ IMMBYTE(pb);
+
+ DIRBYTE(db);
+
+ if ( ( *(regTable[decodePB_tReg(pb)]) & bitTable[decodePB_dst(pb)] ) && ( db & bitTable[decodePB_src(pb)] ))
+ *(regTable[decodePB_tReg(pb)]) |= bitTable[decodePB_dst(pb)];
+ else
+ *(regTable[decodePB_tReg(pb)]) &= (~bitTable[decodePB_dst(pb)]);
+}
+
+/* $1131 BIAND */
+
+INLINE void biand( void )
+{
+ UINT8 pb;
+ UINT16 db;
+
+ IMMBYTE(pb);
+
+ DIRBYTE(db);
+
+ if ( ( *(regTable[decodePB_tReg(pb)]) & bitTable[decodePB_dst(pb)] ) && ( (~db) & bitTable[decodePB_src(pb)] ))
+ *(regTable[decodePB_tReg(pb)]) |= bitTable[decodePB_dst(pb)];
+ else
+ *(regTable[decodePB_tReg(pb)]) &= (~bitTable[decodePB_dst(pb)]);
+}
+
+/* $1132 BOR */
+
+INLINE void bor( void )
+{
+ UINT8 pb;
+ UINT16 db;
+
+ IMMBYTE(pb);
+
+ DIRBYTE(db);
+
+ if ( ( *(regTable[decodePB_tReg(pb)]) & bitTable[decodePB_dst(pb)] ) || ( db & bitTable[decodePB_src(pb)] ))
+ *(regTable[decodePB_tReg(pb)]) |= bitTable[decodePB_dst(pb)];
+ else
+ *(regTable[decodePB_tReg(pb)]) &= (~bitTable[decodePB_dst(pb)]);
+}
+
+/* $1133 BIOR */
+
+INLINE void bior( void )
+{
+ UINT8 pb;
+ UINT16 db;
+
+ IMMBYTE(pb);
+
+ DIRBYTE(db);
+
+ if ( ( *(regTable[decodePB_tReg(pb)]) & bitTable[decodePB_dst(pb)] ) || ( (~db) & bitTable[decodePB_src(pb)] ))
+ *(regTable[decodePB_tReg(pb)]) |= bitTable[decodePB_dst(pb)];
+ else
+ *(regTable[decodePB_tReg(pb)]) &= (~bitTable[decodePB_dst(pb)]);
+}
+
+/* $1134 BEOR */
+
+INLINE void beor( void )
+{
+ UINT8 pb;
+ UINT16 db;
+ UINT8 tReg, tMem;
+
+ IMMBYTE(pb);
+
+ DIRBYTE(db);
+
+ tReg = *(regTable[decodePB_tReg(pb)]) & bitTable[decodePB_dst(pb)];
+ tMem = db & bitTable[decodePB_src(pb)];
+
+ if ( (tReg || tMem ) && !(tReg && tMem) )
+ *(regTable[decodePB_tReg(pb)]) |= bitTable[decodePB_dst(pb)];
+ else
+ *(regTable[decodePB_tReg(pb)]) &= (~bitTable[decodePB_dst(pb)]);
+}
+
+/* $1135 BIEOR */
+
+INLINE void bieor( void )
+{
+ UINT8 pb;
+ UINT16 db;
+ UINT8 tReg, tMem;
+
+ IMMBYTE(pb);
+
+ DIRBYTE(db);
+
+ tReg = *(regTable[decodePB_tReg(pb)]) & bitTable[decodePB_dst(pb)];
+ tMem = (~db) & bitTable[decodePB_src(pb)];
+
+ if ( (tReg || tMem ) && !(tReg && tMem) )
+ *(regTable[decodePB_tReg(pb)]) |= bitTable[decodePB_dst(pb)];
+ else
+ *(regTable[decodePB_tReg(pb)]) &= (~bitTable[decodePB_dst(pb)]);
+}
+
+/* $1133 LDBT */
+
+INLINE void ldbt( void )
+{
+ UINT8 pb;
+ UINT16 db;
+
+ IMMBYTE(pb);
+
+ DIRBYTE(db);
+
+ if ( ( db & bitTable[decodePB_src(pb)] ) )
+ *(regTable[decodePB_tReg(pb)]) |= bitTable[decodePB_dst(pb)];
+ else
+ *(regTable[decodePB_tReg(pb)]) &= (~bitTable[decodePB_dst(pb)]);
+}
+
+/* $1134 STBT */
+
+INLINE void stbt( void )
+{
+ UINT8 pb;
+ UINT16 db;
+
+ IMMBYTE(pb);
+
+ DIRBYTE(db);
+
+ if ( ( *(regTable[decodePB_tReg(pb)]) & bitTable[decodePB_dst(pb)] ) )
+ WM( EAD, db | bitTable[decodePB_src(pb)] );
+ else
+ WM( EAD, db & (~bitTable[decodePB_src(pb)]) );
+}
+
+/* $103F SWI2 absolute indirect ----- */
+INLINE void swi2( void )
+{
+ CC |= CC_E; /* HJB 980225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ if ( MD & MD_EM )
+ {
+ PUSHBYTE(F);
+ PUSHBYTE(E);
+ }
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ PCD = RM16(0xfff4);
+ CHANGE_PC;
+}
+
+/* $113F SWI3 absolute indirect ----- */
+INLINE void swi3( void )
+{
+ CC |= CC_E; /* HJB 980225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ if ( MD & MD_EM )
+ {
+ PUSHBYTE(F);
+ PUSHBYTE(E);
+ }
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ PCD = RM16(0xfff2);
+ CHANGE_PC;
+}
+
+/* $40 NEGA inherent ?**** */
+INLINE void nega( void )
+{
+ UINT16 r;
+ r = -A;
+ CLR_NZVC;
+ SET_FLAGS8(0,A,r);
+ A = r;
+}
+
+/* $41 ILLEGAL */
+
+/* $42 ILLEGAL */
+
+/* $43 COMA inherent -**01 */
+INLINE void coma( void )
+{
+ A = ~A;
+ CLR_NZV;
+ SET_NZ8(A);
+ SEC;
+}
+
+/* $44 LSRA inherent -0*-* */
+INLINE void lsra( void )
+{
+ CLR_NZC;
+ CC |= (A & CC_C);
+ A >>= 1;
+ SET_Z8(A);
+}
+
+/* $45 ILLEGAL */
+
+/* $46 RORA inherent -**-* */
+INLINE void rora( void )
+{
+ UINT8 r;
+ r = (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (A & CC_C);
+ r |= A >> 1;
+ SET_NZ8(r);
+ A = r;
+}
+
+/* $47 ASRA inherent ?**-* */
+INLINE void asra( void )
+{
+ CLR_NZC;
+ CC |= (A & CC_C);
+ A = (A & 0x80) | (A >> 1);
+ SET_NZ8(A);
+}
+
+/* $48 ASLA inherent ?**** */
+INLINE void asla( void )
+{
+ UINT16 r;
+ r = A << 1;
+ CLR_NZVC;
+ SET_FLAGS8(A,A,r);
+ A = r;
+}
+
+/* $49 ROLA inherent -**** */
+INLINE void rola( void )
+{
+ UINT16 t,r;
+ t = A;
+ r = (CC & CC_C) | (t<<1);
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ A = r;
+}
+
+/* $4A DECA inherent -***- */
+INLINE void deca( void )
+{
+ --A;
+ CLR_NZV;
+ SET_FLAGS8D(A);
+}
+
+/* $4B ILLEGAL */
+
+/* $4C INCA inherent -***- */
+INLINE void inca( void )
+{
+ ++A;
+ CLR_NZV;
+ SET_FLAGS8I(A);
+}
+
+/* $4D TSTA inherent -**0- */
+INLINE void tsta( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $4E ILLEGAL */
+
+/* $4F CLRA inherent -0100 */
+INLINE void clra( void )
+{
+ A = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $50 NEGB inherent ?**** */
+INLINE void negb( void )
+{
+ UINT16 r;
+ r = -B;
+ CLR_NZVC;
+ SET_FLAGS8(0,B,r);
+ B = r;
+}
+
+/* $1040 NEGD inherent ?**** */
+INLINE void negd( void )
+{
+ UINT32 r;
+ r = -D;
+ CLR_NZVC;
+ SET_FLAGS16(0,D,r);
+ D = r;
+}
+
+/* $51 ILLEGAL */
+
+/* $52 ILLEGAL */
+
+/* $53 COMB inherent -**01 */
+INLINE void comb( void )
+{
+ B = ~B;
+ CLR_NZV;
+ SET_NZ8(B);
+ SEC;
+}
+
+/* $1143 COME inherent -**01 */
+INLINE void come( void )
+{
+ E = ~E;
+ CLR_NZV;
+ SET_NZ8(E);
+ SEC;
+}
+
+/* $1153 COMF inherent -**01 */
+INLINE void comf( void )
+{
+ F = ~F;
+ CLR_NZV;
+ SET_NZ8(F);
+ SEC;
+}
+
+/* $1043 COMD inherent -**01 */
+INLINE void comd( void )
+{
+ D = ~D;
+ CLR_NZV;
+ SET_NZ16(D);
+ SEC;
+}
+
+/* $1053 COMW inherent -**01 */
+INLINE void comw( void )
+{
+ W = ~W;
+ CLR_NZV;
+ SET_NZ16(W);
+ SEC;
+}
+
+/* $54 LSRB inherent -0*-* */
+INLINE void lsrb( void )
+{
+ CLR_NZC;
+ CC |= (B & CC_C);
+ B >>= 1;
+ SET_Z8(B);
+}
+
+/* $1044 LSRD inherent -0*-* */
+INLINE void lsrd( void )
+{
+ CLR_NZC;
+ CC |= (B & CC_C);
+ D >>= 1;
+ SET_Z16(D);
+}
+
+/* $1054 LSRW inherent -0*-* */
+INLINE void lsrw( void )
+{
+ CLR_NZC;
+ CC |= (F & CC_C);
+ W >>= 1;
+ SET_Z16(W);
+}
+
+/* $55 ILLEGAL */
+
+/* $56 RORB inherent -**-* */
+INLINE void rorb( void )
+{
+ UINT8 r;
+ r = (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (B & CC_C);
+ r |= B >> 1;
+ SET_NZ8(r);
+ B = r;
+}
+
+/* $1046 RORD inherent -**-* */
+INLINE void rord( void )
+{
+ UINT16 r;
+ r = (CC & CC_C) << 15;
+ CLR_NZC;
+ CC |= (D & CC_C);
+ r |= D >> 1;
+ SET_NZ16(r);
+ D = r;
+}
+
+/* $1056 RORW inherent -**-* */
+INLINE void rorw( void )
+{
+ UINT16 r;
+ r = (CC & CC_C) << 15;
+ CLR_NZC;
+ CC |= (W & CC_C);
+ r |= W >> 1;
+ SET_NZ16(r);
+ W = r;
+}
+
+/* $57 ASRB inherent ?**-* */
+INLINE void asrb( void )
+{
+ CLR_NZC;
+ CC |= (B & CC_C);
+ B= (B & 0x80) | (B >> 1);
+ SET_NZ8(B);
+}
+
+/* $1047 ASRD inherent ?**-* */
+INLINE void asrd( void )
+{
+ CLR_NZC;
+ CC |= (D & CC_C);
+ D= (D & 0x8000) | (D >> 1);
+ SET_NZ16(D);
+}
+
+/* $58 ASLB inherent ?**** */
+INLINE void aslb( void )
+{
+ UINT16 r;
+ r = B << 1;
+ CLR_NZVC;
+ SET_FLAGS8(B,B,r);
+ B = r;
+}
+
+/* $1048 ASLD inherent ?**** */
+INLINE void asld( void )
+{
+ UINT32 r;
+ r = D << 1;
+ CLR_NZVC;
+ SET_FLAGS16(D,D,r);
+ D = r;
+}
+
+/* $59 ROLB inherent -**** */
+INLINE void rolb( void )
+{
+ UINT16 t,r;
+ t = B;
+ r = CC & CC_C;
+ r |= t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ B = r;
+}
+
+/* $1049 ROLD inherent -**** */
+INLINE void rold( void )
+{
+ UINT32 t,r;
+ t = D;
+ r = CC & CC_C;
+ r |= t << 1;
+ CLR_NZVC;
+ SET_FLAGS16(t,t,r);
+ D = r;
+}
+
+/* $1059 ROLW inherent -**** */
+INLINE void rolw( void )
+{
+ UINT32 t,r;
+ t = W;
+ r = CC & CC_C;
+ r |= t << 1;
+ CLR_NZVC;
+ SET_FLAGS16(t,t,r);
+ W = r;
+}
+
+/* $5A DECB inherent -***- */
+INLINE void decb( void )
+{
+ --B;
+ CLR_NZV;
+ SET_FLAGS8D(B);
+}
+
+/* $114a DECE inherent -***- */
+INLINE void dece( void )
+{
+ --E;
+ CLR_NZV;
+ SET_FLAGS8D(E);
+}
+
+/* $115a DECF inherent -***- */
+INLINE void decf( void )
+{
+ --F;
+ CLR_NZV;
+ SET_FLAGS8D(F);
+}
+
+/* $104a DECD inherent -***- */
+INLINE void decd( void )
+{
+ UINT32 r;
+ r = D - 1;
+ CLR_NZVC;
+ SET_FLAGS16(D,D,r)
+ D = r;
+}
+
+/* $105a DECW inherent -***- */
+INLINE void decw( void )
+{
+ UINT32 r;
+ r = W - 1;
+ CLR_NZVC;
+ SET_FLAGS16(W,W,r)
+ W = r;
+}
+
+/* $5B ILLEGAL */
+
+/* $5C INCB inherent -***- */
+INLINE void incb( void )
+{
+ ++B;
+ CLR_NZV;
+ SET_FLAGS8I(B);
+}
+
+/* $114c INCE inherent -***- */
+INLINE void ince( void )
+{
+ ++E;
+ CLR_NZV;
+ SET_FLAGS8I(E);
+}
+
+/* $115c INCF inherent -***- */
+INLINE void incf( void )
+{
+ ++F;
+ CLR_NZV;
+ SET_FLAGS8I(F);
+}
+
+/* $104c INCD inherent -***- */
+INLINE void incd( void )
+{
+ UINT32 r;
+ r = D + 1;
+ CLR_NZVC;
+ SET_FLAGS16(D,D,r)
+ D = r;
+}
+
+/* $105c INCW inherent -***- */
+INLINE void incw( void )
+{
+ UINT32 r;
+ r = W + 1;
+ CLR_NZVC;
+ SET_FLAGS16(W,W,r)
+ W = r;
+}
+
+/* $5D TSTB inherent -**0- */
+INLINE void tstb( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $104d TSTD inherent -**0- */
+INLINE void tstd( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $105d TSTW inherent -**0- */
+INLINE void tstw( void )
+{
+ CLR_NZV;
+ SET_NZ16(W);
+}
+
+/* $114d TSTE inherent -**0- */
+INLINE void tste( void )
+{
+ CLR_NZV;
+ SET_NZ8(E);
+}
+
+/* $115d TSTF inherent -**0- */
+INLINE void tstf( void )
+{
+ CLR_NZV;
+ SET_NZ8(F);
+}
+
+/* $5E ILLEGAL */
+
+/* $5F CLRB inherent -0100 */
+INLINE void clrb( void )
+{
+ B = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $104f CLRD inherent -0100 */
+INLINE void clrd( void )
+{
+ D = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $114f CLRE inherent -0100 */
+INLINE void clre( void )
+{
+ E = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $115f CLRF inherent -0100 */
+INLINE void clrf( void )
+{
+ F = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $105f CLRW inherent -0100 */
+INLINE void clrw( void )
+{
+ W = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $60 NEG indexed ?**** */
+INLINE void neg_ix( void )
+{
+ UINT16 r,t;
+ fetch_effective_address();
+ t = RM(EAD);
+ r=-t;
+ CLR_NZVC;
+ SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $61 OIM indexed */
+INLINE void oim_ix( void )
+{
+ UINT8 r,im;
+ IMMBYTE(im);
+ fetch_effective_address();
+ r = im | RM(EAD);
+ CLR_NZV;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $62 AIM indexed */
+INLINE void aim_ix( void )
+{
+ UINT8 r,im;
+ IMMBYTE(im);
+ fetch_effective_address();
+ r = im & RM(EAD);
+ CLR_NZV;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $63 COM indexed -**01 */
+INLINE void com_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t = ~RM(EAD);
+ CLR_NZV;
+ SET_NZ8(t);
+ SEC;
+ WM(EAD,t);
+}
+
+/* $64 LSR indexed -0*-* */
+INLINE void lsr_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t=RM(EAD);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t>>=1; SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $65 EIM indexed */
+INLINE void eim_ix( void )
+{
+ UINT8 r,im;
+ IMMBYTE(im);
+ fetch_effective_address();
+ r = im ^ RM(EAD);
+ CLR_NZV;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+/* $66 ROR indexed -**-* */
+INLINE void ror_ix( void )
+{
+ UINT8 t,r;
+ fetch_effective_address();
+ t=RM(EAD);
+ r = (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (t & CC_C);
+ r |= t>>1; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $67 ASR indexed ?**-* */
+INLINE void asr_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t=RM(EAD);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t=(t&0x80)|(t>>1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $68 ASL indexed ?**** */
+INLINE void asl_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t=RM(EAD);
+ r = t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $69 ROL indexed -**** */
+INLINE void rol_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t=RM(EAD);
+ r = CC & CC_C;
+ r |= t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $6A DEC indexed -***- */
+INLINE void dec_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t = RM(EAD) - 1;
+ CLR_NZV; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $6B TIM indexed */
+INLINE void tim_ix( void )
+{
+ UINT8 r,im,m;
+ IMMBYTE(im);
+ fetch_effective_address();
+ m = RM(EAD);
+ r = im & m;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $6C INC indexed -***- */
+INLINE void inc_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t = RM(EAD) + 1;
+ CLR_NZV; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $6D TST indexed -**0- */
+INLINE void tst_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(t);
+}
+
+/* $6E JMP indexed ----- */
+INLINE void jmp_ix( void )
+{
+ fetch_effective_address();
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $6F CLR indexed -0100 */
+INLINE void clr_ix( void )
+{
+ UINT32 dummy;
+ fetch_effective_address();
+ dummy = RM(EAD);
+ WM(EAD,0);
+ CLR_NZVC; SEZ;
+}
+
+/* $70 NEG extended ?**** */
+INLINE void neg_ex( void )
+{
+ UINT16 r,t;
+ EXTBYTE(t); r=-t;
+ CLR_NZVC; SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $71 OIM extended */
+INLINE void oim_ex( void )
+{
+ UINT8 r,t,im;
+ IMMBYTE(im);
+ EXTBYTE(t);
+ r = im | t;
+ CLR_NZV;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $72 AIM extended */
+INLINE void aim_ex( void )
+{
+ UINT8 r,t,im;
+ IMMBYTE(im);
+ EXTBYTE(t);
+ r = im & t;
+ CLR_NZV;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $73 COM extended -**01 */
+INLINE void com_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); t = ~t;
+ CLR_NZV; SET_NZ8(t); SEC;
+ WM(EAD,t);
+}
+
+/* $74 LSR extended -0*-* */
+INLINE void lsr_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZC; CC |= (t & CC_C);
+ t>>=1; SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $75 EIM extended */
+INLINE void eim_ex( void )
+{
+ UINT8 r,t,im;
+ IMMBYTE(im);
+ EXTBYTE(t);
+ r = im ^ t;
+ CLR_NZV;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $76 ROR extended -**-* */
+INLINE void ror_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t); r=(CC & CC_C) << 7;
+ CLR_NZC; CC |= (t & CC_C);
+ r |= t>>1; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $77 ASR extended ?**-* */
+INLINE void asr_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZC; CC |= (t & CC_C);
+ t=(t&0x80)|(t>>1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $78 ASL extended ?**** */
+INLINE void asl_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r=t<<1;
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $79 ROL extended -**** */
+INLINE void rol_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = (CC & CC_C) | (t << 1);
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $7A DEC extended -***- */
+INLINE void dec_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); --t;
+ CLR_NZV; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $7B TIM extended */
+INLINE void tim_ex( void )
+{
+ UINT8 r,t,im;
+ IMMBYTE(im);
+ EXTBYTE(t);
+ r = im & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $7C INC extended -***- */
+INLINE void inc_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); ++t;
+ CLR_NZV; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $7D TST extended -**0- */
+INLINE void tst_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZV; SET_NZ8(t);
+}
+
+/* $7E JMP extended ----- */
+INLINE void jmp_ex( void )
+{
+ EXTENDED;
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $7F CLR extended -0100 */
+INLINE void clr_ex( void )
+{
+ UINT32 dummy;
+ EXTENDED;
+ dummy = RM(EAD);
+ WM(EAD,0);
+ CLR_NZVC; SEZ;
+}
+
+/* $80 SUBA immediate ?**** */
+INLINE void suba_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $81 CMPA immediate ?**** */
+INLINE void cmpa_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $82 SBCA immediate ?**** */
+INLINE void sbca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $83 SUBD (CMPD CMPU) immediate -**** */
+INLINE void subd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $1080 SUBW immediate -**** */
+INLINE void subw_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = W;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ W = r;
+}
+
+/* $1083 CMPD immediate -**** */
+INLINE void cmpd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $1081 CMPW immediate -**** */
+INLINE void cmpw_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = W;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $1183 CMPU immediate -**** */
+INLINE void cmpu_im( void )
+{
+ UINT32 r, d;
+ PAIR b;
+ IMMWORD(b);
+ d = U;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $84 ANDA immediate -**0- */
+INLINE void anda_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A &= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $85 BITA immediate -**0- */
+INLINE void bita_im( void )
+{
+ UINT8 t,r;
+ IMMBYTE(t);
+ r = A & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $86 LDA immediate -**0- */
+INLINE void lda_im( void )
+{
+ IMMBYTE(A);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $88 EORA immediate -**0- */
+INLINE void eora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A ^= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $89 ADCA immediate ***** */
+INLINE void adca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $8A ORA immediate -**0- */
+INLINE void ora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A |= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $8B ADDA immediate ***** */
+INLINE void adda_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $8C CMPX (CMPY CMPS) immediate -**** */
+INLINE void cmpx_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $108C CMPY immediate -**** */
+INLINE void cmpy_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $118C CMPS immediate -**** */
+INLINE void cmps_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $8D BSR ----- */
+INLINE void bsr( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ PUSHWORD(pPC);
+ PC += SIGNED(t);
+ CHANGE_PC;
+}
+
+/* $8E LDX (LDY) immediate -**0- */
+INLINE void ldx_im( void )
+{
+ IMMWORD(pX);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $CD LDQ immediate -**0- */
+INLINE void ldq_im( void )
+{
+ PAIR q;
+
+ IMMLONG(q);
+ D = q.w.h;
+ W = q.w.l;
+ CLR_NZV;
+ SET_N8(A);
+ SET_Z(q.d);
+}
+
+/* $108E LDY immediate -**0- */
+INLINE void ldy_im( void )
+{
+ IMMWORD(pY);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $118f MULD immediate */
+INLINE void muld_im( void )
+{
+ PAIR t, q;
+
+ IMMWORD( t );
+ q.d = (INT16) D * (INT16)t.w.l;
+ D = q.w.h;
+ W = q.w.l;
+ CLR_NZVC;
+ SET_NZ16(D);
+}
+
+/* $118d DIVD immediate */
+INLINE void divd_im( void )
+{
+ UINT8 t;
+ INT16 v, oldD;
+
+ IMMBYTE( t );
+
+ if( t != 0 )
+ {
+ oldD = D;
+ v = (INT16) D / (INT8) t;
+ A = (INT16) D % (INT8) t;
+ B = v;
+
+ CLR_NZVC;
+ SET_NZ8(B);
+
+ if( B & 0x01 )
+ SEC;
+
+ if( (INT16)D < 0 )
+ SEN;
+
+ if ( (v > 127) || (v < -128) ) /* soft overflow */
+ {
+ SEV;
+
+ if( (v > 255) || (v < -256) ) /* hard overflow - division is aborted */
+ {
+ SET_NZ16( oldD );
+ D = abs( oldD );
+ }
+ }
+ }
+ else
+ {
+ hd6309_ICount -= 8;
+ DZError();
+ }
+}
+
+/* $118e DIVQ immediate */
+INLINE void divq_im( void )
+{
+ PAIR t,q, oldQ;
+ INT32 v;
+
+ IMMWORD( t );
+
+ q.w.h = D;
+ q.w.l = W;
+
+ if( t.w.l != 0 )
+ {
+ oldQ = q;
+
+ v = (INT32) q.d / (INT16) t.w.l;
+ D = (INT32) q.d % (INT16) t.w.l;
+ W = v;
+
+ CLR_NZVC;
+ SET_NZ16(W);
+
+ if( W & 0x0001 )
+ SEC;
+
+ if ( (v > 32768) || (v < -35767) ) /* soft overflow */
+ {
+ SEV;
+
+ if( (v > 65536 ) || (v < -65535 ) ) /* hard overflow - division is aborted */
+ {
+ if( (INT32)oldQ.d < 0 )
+ SEN;
+ else if( oldQ.d == 0 )
+ SEZ;
+
+ t.w.l = abs( t.w.l );
+ D = oldQ.w.h;
+ W = oldQ.w.l;
+ }
+ }
+ }
+ else
+ DZError();
+}
+
+/* $90 SUBA direct ?**** */
+INLINE void suba_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $91 CMPA direct ?**** */
+INLINE void cmpa_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $92 SBCA direct ?**** */
+INLINE void sbca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $93 SUBD (CMPD CMPU) direct -**** */
+INLINE void subd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $1090 SUBW direct -**** */
+INLINE void subw_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = W;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ W = r;
+}
+
+/* $1093 CMPD direct -**** */
+INLINE void cmpd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $1091 CMPW direct -**** */
+INLINE void cmpw_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = W;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $1193 CMPU direct -**** */
+INLINE void cmpu_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = U;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(U,b.d,r);
+}
+
+/* $94 ANDA direct -**0- */
+INLINE void anda_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A &= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $95 BITA direct -**0- */
+INLINE void bita_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r = A & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $96 LDA direct -**0- */
+INLINE void lda_di( void )
+{
+ DIRBYTE(A);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $97 STA direct -**0- */
+INLINE void sta_di( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+ DIRECT;
+ WM(EAD,A);
+}
+
+/* $98 EORA direct -**0- */
+INLINE void eora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A ^= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $99 ADCA direct ***** */
+INLINE void adca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $9A ORA direct -**0- */
+INLINE void ora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A |= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $9B ADDA direct ***** */
+INLINE void adda_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $9C CMPX (CMPY CMPS) direct -**** */
+INLINE void cmpx_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $109C CMPY direct -**** */
+INLINE void cmpy_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $119C CMPS direct -**** */
+INLINE void cmps_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $9D JSR direct ----- */
+INLINE void jsr_di( void )
+{
+ DIRECT;
+ PUSHWORD(pPC);
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $9E LDX (LDY) direct -**0- */
+INLINE void ldx_di( void )
+{
+ DIRWORD(pX);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $119f MULD direct -**0- */
+INLINE void muld_di( void )
+{
+ PAIR t,q;
+
+ DIRWORD(t);
+ q.d = (INT16) D * (INT16)t.w.l;
+
+ D = q.w.h;
+ W = q.w.l;
+ CLR_NZVC;
+ SET_NZ16(D);
+}
+
+/* $119d DIVD direct -**0- */
+INLINE void divd_di( void )
+{
+ UINT8 t;
+ INT16 v, oldD;
+
+ DIRBYTE(t);
+
+ if( t != 0 )
+ {
+ oldD = D;
+ v = (INT16) D / (INT8) t;
+ A = (INT16) D % (INT8) t;
+ B = v;
+
+ CLR_NZVC;
+ SET_NZ8(B);
+
+ if( B & 0x01 )
+ SEC;
+
+ if( (INT16)D < 0 )
+ SEN;
+
+ if ( (v > 127) || (v < -128) ) /* soft overflow */
+ {
+ SEV;
+
+ if( (v > 255) || (v < -256) ) /* hard overflow - division is aborted */
+ {
+ SET_NZ16( oldD );
+ D = abs( oldD );
+ }
+ }
+ }
+ else
+ {
+ hd6309_ICount -= 8;
+ DZError();
+ }
+}
+
+/* $119e DIVQ direct -**0- */
+INLINE void divq_di( void )
+{
+ PAIR t,q, oldQ;
+ INT32 v;
+
+ DIRWORD(t);
+
+ q.w.h = D;
+ q.w.l = W;
+
+ if( t.w.l != 0 )
+ {
+ oldQ = q;
+
+ v = (INT32) q.d / (INT16) t.w.l;
+ D = (INT32) q.d % (INT16) t.w.l;
+ W = v;
+
+ CLR_NZVC;
+ SET_NZ16(W);
+
+ if( W & 0x0001 )
+ SEC;
+
+ if ( (v > 32767) || (v < -32768) ) /* soft overflow */
+ {
+ SEV;
+
+ if( (v > 65535 ) || (v < -65536 ) ) /* hard overflow - division is aborted */
+ {
+ if( (INT32)oldQ.d < 0 )
+ SEN;
+ else if( oldQ.d == 0 )
+ SEZ;
+
+ t.w.l = abs( t.w.l );
+ D = oldQ.w.h;
+ W = oldQ.w.l;
+ }
+ }
+ }
+ else
+ DZError();
+}
+/* $10dc LDQ direct -**0- */
+INLINE void ldq_di( void )
+{
+ PAIR q;
+
+ DIRLONG(q);
+ D = q.w.h;
+ W = q.w.l;
+ CLR_NZV;
+ SET_N8(A);
+ SET_Z(q.d);
+}
+
+/* $109E LDY direct -**0- */
+INLINE void ldy_di( void )
+{
+ DIRWORD(pY);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $9F STX (STY) direct -**0- */
+INLINE void stx_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ DIRECT;
+ WM16(EAD,&pX);
+}
+
+/* $10dd STQ direct -**0- */
+INLINE void stq_di( void )
+{
+ PAIR q;
+
+ q.w.h = D;
+ q.w.l = W;
+ DIRECT;
+ WM32(EAD,&q);
+ CLR_NZV;
+ SET_N8(A);
+ SET_Z(q.d);
+}
+
+/* $109F STY direct -**0- */
+INLINE void sty_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(Y);
+ DIRECT;
+ WM16(EAD,&pY);
+}
+
+/* $a0 SUBA indexed ?**** */
+INLINE void suba_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a1 CMPA indexed ?**** */
+INLINE void cmpa_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $a2 SBCA indexed ?**** */
+INLINE void sbca_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a3 SUBD (CMPD CMPU) indexed -**** */
+INLINE void subd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $10a0 SUBW indexed -**** */
+INLINE void subw_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = W;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ W = r;
+}
+
+/* $10a3 CMPD indexed -**** */
+INLINE void cmpd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $10a1 CMPW indexed -**** */
+INLINE void cmpw_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = W;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11a3 CMPU indexed -**** */
+INLINE void cmpu_ix( void )
+{
+ UINT32 r;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ r = U - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(U,b.d,r);
+}
+
+/* $a4 ANDA indexed -**0- */
+INLINE void anda_ix( void )
+{
+ fetch_effective_address();
+ A &= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $a5 BITA indexed -**0- */
+INLINE void bita_ix( void )
+{
+ UINT8 r;
+ fetch_effective_address();
+ r = A & RM(EAD);
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $a6 LDA indexed -**0- */
+INLINE void lda_ix( void )
+{
+ fetch_effective_address();
+ A = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $a7 STA indexed -**0- */
+INLINE void sta_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ8(A);
+ WM(EAD,A);
+}
+
+/* $a8 EORA indexed -**0- */
+INLINE void eora_ix( void )
+{
+ fetch_effective_address();
+ A ^= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $a9 ADCA indexed ***** */
+INLINE void adca_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $aA ORA indexed -**0- */
+INLINE void ora_ix( void )
+{
+ fetch_effective_address();
+ A |= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $aB ADDA indexed ***** */
+INLINE void adda_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $aC CMPX (CMPY CMPS) indexed -**** */
+INLINE void cmpx_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $10aC CMPY indexed -**** */
+INLINE void cmpy_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11aC CMPS indexed -**** */
+INLINE void cmps_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $aD JSR indexed ----- */
+INLINE void jsr_ix( void )
+{
+ fetch_effective_address();
+ PUSHWORD(pPC);
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $aE LDX (LDY) indexed -**0- */
+INLINE void ldx_ix( void )
+{
+ fetch_effective_address();
+ X=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $11af MULD indexed -**0- */
+INLINE void muld_ix( void )
+{
+ PAIR q;
+ UINT16 t;
+
+ fetch_effective_address();
+ t=RM16(EAD);
+ q.d = (INT16) D * (INT16)t;
+
+ D = q.w.h;
+ W = q.w.l;
+ CLR_NZVC;
+ SET_NZ16(D);
+}
+
+/* $11ad DIVD indexed -**0- */
+INLINE void divd_ix( void )
+{
+ UINT8 t;
+ INT16 v, oldD;
+
+ fetch_effective_address();
+ t=RM(EAD);
+
+ if( t != 0 )
+ {
+ oldD = D;
+ v = (INT16) D / (INT8) t;
+ A = (INT16) D % (INT8) t;
+ B = v;
+
+ CLR_NZVC;
+ SET_NZ8(B);
+
+ if( B & 0x01 )
+ SEC;
+
+ if( (INT16)D < 0 )
+ SEN;
+
+ if ( (v > 127) || (v < -128) ) /* soft overflow */
+ {
+ SEV;
+
+ if( (v > 255) || (v < -256) ) /* hard overflow - division is aborted */
+ {
+ SET_NZ16( oldD );
+ D = abs( oldD );
+ }
+ }
+ }
+ else
+ {
+ hd6309_ICount -= 8;
+ DZError();
+ }
+}
+
+/* $11ae DIVQ indexed -**0- */
+INLINE void divq_ix( void )
+{
+ PAIR t,q, oldQ;
+ INT32 v;
+
+ fetch_effective_address();
+ t.w.l=RM16(EAD);
+
+ q.w.h = D;
+ q.w.l = W;
+
+ if( t.w.l != 0 )
+ {
+ oldQ = q;
+
+ v = (INT32) q.d / (INT16) t.w.l;
+ D = (INT32) q.d % (INT16) t.w.l;
+ W = v;
+
+ CLR_NZVC;
+ SET_NZ16(W);
+
+ if( W & 0x0001 )
+ SEC;
+
+ if ( (v > 32767) || (v < -32768) ) /* soft overflow */
+ {
+ SEV;
+
+ if( (v > 65535 ) || (v < -65536 ) ) /* hard overflow - division is aborted */
+ {
+ if( (INT32)oldQ.d < 0 )
+ SEN;
+ else if( oldQ.d == 0 )
+ SEZ;
+
+ t.w.l = abs( t.w.l );
+ D = oldQ.w.h;
+ W = oldQ.w.l;
+ }
+ }
+ }
+ else
+ DZError();
+}
+
+/* $10ec LDQ indexed -**0- */
+INLINE void ldq_ix( void )
+{
+ PAIR q;
+
+ fetch_effective_address();
+ q.d=RM32(EAD);
+ D = q.w.h;
+ W = q.w.l;
+ CLR_NZV;
+ SET_N8(A);
+ SET_Z(q.d);
+}
+
+/* $10aE LDY indexed -**0- */
+INLINE void ldy_ix( void )
+{
+ fetch_effective_address();
+ Y=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $aF STX (STY) indexed -**0- */
+INLINE void stx_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(X);
+ WM16(EAD,&pX);
+}
+
+/* $10ed STQ indexed -**0- */
+INLINE void stq_ix( void )
+{
+ PAIR q;
+
+ q.w.h = D;
+ q.w.l = W;
+ fetch_effective_address();
+ WM32(EAD,&q);
+ CLR_NZV;
+ SET_N8(A);
+ SET_Z(q.d);
+}
+
+/* $10aF STY indexed -**0- */
+INLINE void sty_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(Y);
+ WM16(EAD,&pY);
+}
+
+/* $b0 SUBA extended ?**** */
+INLINE void suba_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b1 CMPA extended ?**** */
+INLINE void cmpa_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $b2 SBCA extended ?**** */
+INLINE void sbca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b3 SUBD (CMPD CMPU) extended -**** */
+INLINE void subd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $10b0 SUBW extended -**** */
+INLINE void subw_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = W;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ W = r;
+}
+
+/* $10b3 CMPD extended -**** */
+INLINE void cmpd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $10b1 CMPW extended -**** */
+INLINE void cmpw_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = W;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11b3 CMPU extended -**** */
+INLINE void cmpu_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = U;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $b4 ANDA extended -**0- */
+INLINE void anda_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A &= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $b5 BITA extended -**0- */
+INLINE void bita_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t);
+ r = A & t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $b6 LDA extended -**0- */
+INLINE void lda_ex( void )
+{
+ EXTBYTE(A);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $b7 STA extended -**0- */
+INLINE void sta_ex( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+ EXTENDED;
+ WM(EAD,A);
+}
+
+/* $b8 EORA extended -**0- */
+INLINE void eora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A ^= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $b9 ADCA extended ***** */
+INLINE void adca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $bA ORA extended -**0- */
+INLINE void ora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A |= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $bB ADDA extended ***** */
+INLINE void adda_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $bC CMPX (CMPY CMPS) extended -**** */
+INLINE void cmpx_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $10bC CMPY extended -**** */
+INLINE void cmpy_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11bC CMPS extended -**** */
+INLINE void cmps_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $bD JSR extended ----- */
+INLINE void jsr_ex( void )
+{
+ EXTENDED;
+ PUSHWORD(pPC);
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $bE LDX (LDY) extended -**0- */
+INLINE void ldx_ex( void )
+{
+ EXTWORD(pX);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $11bf MULD extended -**0- */
+INLINE void muld_ex( void )
+{
+ PAIR t, q;
+
+ EXTWORD(t);
+ q.d = (INT16) D * (INT16)t.w.l;
+
+ D = q.w.h;
+ W = q.w.l;
+ CLR_NZVC;
+ SET_NZ16(D);
+}
+
+/* $11bd DIVD extended -**0- */
+INLINE void divd_ex( void )
+{
+ UINT8 t;
+ INT16 v, oldD;
+
+ EXTBYTE(t);
+
+ if( t != 0 )
+ {
+ oldD = D;
+ v = (INT16) D / (INT8) t;
+ A = (INT16) D % (INT8) t;
+ B = v;
+
+ CLR_NZVC;
+ SET_NZ8(B);
+
+ if( B & 0x01 )
+ SEC;
+
+ if( (INT16)D < 0 )
+ SEN;
+
+ if ( (v > 127) || (v < -128) ) /* soft overflow */
+ {
+ SEV;
+
+ if( (v > 255) || (v < -256) ) /* hard overflow - division is aborted */
+ {
+ SET_NZ16( oldD );
+ D = abs( oldD );
+ }
+ }
+ }
+ else
+ {
+ hd6309_ICount -= 8;
+ DZError();
+ }
+}
+
+/* $11be DIVQ extended -**0- */
+INLINE void divq_ex( void )
+{
+ PAIR t,q, oldQ;
+ INT32 v;
+
+ EXTWORD(t);
+
+ q.w.h = D;
+ q.w.l = W;
+
+ if( t.w.l != 0 )
+ {
+ oldQ = q;
+
+ v = (INT32) q.d / (INT16) t.w.l;
+ D = (INT32) q.d % (INT16) t.w.l;
+ W = v;
+
+ CLR_NZVC;
+ SET_NZ16(W);
+
+ if( W & 0x0001 )
+ SEC;
+
+ if ( (v > 32767) || (v < -32768) ) /* soft overflow */
+ {
+ SEV;
+
+ if( (v > 65535 ) || (v < -65536 ) ) /* hard overflow - division is aborted */
+ {
+ if( (INT32)oldQ.d < 0 )
+ SEN;
+ else if( oldQ.d == 0 )
+ SEZ;
+
+ t.w.l = abs( t.w.l );
+ D = oldQ.w.h;
+ W = oldQ.w.l;
+ }
+ }
+ }
+ else
+ DZError();
+}
+
+/* $10fc LDQ extended -**0- */
+INLINE void ldq_ex( void )
+{
+ PAIR q;
+
+ EXTLONG(q);
+ D = q.w.h;
+ W = q.w.l;
+ CLR_NZV;
+ SET_N8(A);
+ SET_Z(q.d);
+}
+
+/* $10bE LDY extended -**0- */
+INLINE void ldy_ex( void )
+{
+ EXTWORD(pY);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $bF STX (STY) extended -**0- */
+INLINE void stx_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ EXTENDED;
+ WM16(EAD,&pX);
+}
+
+/* $10fd STQ extended -**0- */
+INLINE void stq_ex( void )
+{
+ PAIR q;
+
+ q.w.h = D;
+ q.w.l = W;
+ EXTENDED;
+ WM32(EAD,&q);
+ CLR_NZV;
+ SET_N8(A);
+ SET_Z(q.d);
+}
+
+/* $10bF STY extended -**0- */
+INLINE void sty_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(Y);
+ EXTENDED;
+ WM16(EAD,&pY);
+}
+
+/* $c0 SUBB immediate ?**** */
+INLINE void subb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $1180 SUBE immediate ?**** */
+INLINE void sube_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = E - t;
+ CLR_NZVC;
+ SET_FLAGS8(E,t,r);
+ E = r;
+}
+
+/* $11C0 SUBF immediate ?**** */
+INLINE void subf_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = F - t;
+ CLR_NZVC;
+ SET_FLAGS8(F,t,r);
+ F = r;
+}
+
+/* $c1 CMPB immediate ?**** */
+INLINE void cmpb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B - t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+}
+
+/* $1181 CMPE immediate ?**** */
+INLINE void cmpe_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = E - t;
+ CLR_NZVC; SET_FLAGS8(E,t,r);
+}
+
+/* $11C1 CMPF immediate ?**** */
+INLINE void cmpf_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = F - t;
+ CLR_NZVC; SET_FLAGS8(F,t,r);
+}
+
+/* $c2 SBCB immediate ?**** */
+INLINE void sbcb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $1082 SBCD immediate ?**** */
+INLINE void sbcd_im( void )
+{
+ PAIR t;
+ UINT32 r;
+ IMMWORD(t);
+ r = D - t.w.l - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS16(D,t.w.l,r);
+ D = r;
+}
+
+/* $c3 ADDD immediate -**** */
+INLINE void addd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $108b ADDW immediate -**** */
+INLINE void addw_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = W;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ W = r;
+}
+
+/* $118b ADDE immediate -**** */
+INLINE void adde_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = E + t;
+ CLR_HNZVC;
+ SET_FLAGS8(E,t,r);
+ SET_H(E,t,r);
+ E = r;
+}
+
+/* $11Cb ADDF immediate -**** */
+INLINE void addf_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = F + t;
+ CLR_HNZVC;
+ SET_FLAGS8(F,t,r);
+ SET_H(F,t,r);
+ F = r;
+}
+
+/* $c4 ANDB immediate -**0- */
+INLINE void andb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $1084 ANDD immediate -**0- */
+INLINE void andd_im( void )
+{
+ PAIR t;
+ IMMWORD(t);
+ D &= t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $c5 BITB immediate -**0- */
+INLINE void bitb_im( void )
+{
+ UINT8 t,r;
+ IMMBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $1085 BITD immediate -**0- */
+INLINE void bitd_im( void )
+{
+ PAIR t;
+ UINT16 r;
+ IMMWORD(t);
+ r = B & t.w.l;
+ CLR_NZV;
+ SET_NZ16(r);
+}
+
+/* $113c BITMD immediate -**0- */
+INLINE void bitmd_im( void )
+{
+ /*
+ The following is from Darren A.
+
+ The Z flag is the only condition code that should be affected by BITMD.
+ For example, when the "Divide-By-Zero" flag (bit 7) is set, BITMD should
+ not set the N flag. It should also NOT clear the V flag (unlike the other
+ BIT instructions).
+
+ His comments come from experimentation and differ from Chris Burke
+ */
+
+ UINT8 t,r;
+ IMMBYTE(t);
+ r = MD & t;
+ CLR_Z;
+ SET_Z8(r);
+
+ MD &= ~(r & 0xc0); /* clear the tested high bits */
+
+}
+
+/* $c6 LDB immediate -**0- */
+INLINE void ldb_im( void )
+{
+ IMMBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $113d LDMD immediate -**0- */
+INLINE void ldmd_im( void )
+{
+ IMMBYTE(MD);
+ UpdateState();
+}
+
+/* $1186 LDE immediate -**0- */
+INLINE void lde_im( void )
+{
+ IMMBYTE(E);
+ CLR_NZV;
+ SET_NZ8(E);
+}
+
+/* $11C6 LDF immediate -**0- */
+INLINE void ldf_im( void )
+{
+ IMMBYTE(F);
+ CLR_NZV;
+ SET_NZ8(F);
+}
+
+/* $c8 EORB immediate -**0- */
+INLINE void eorb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ B ^= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $1088 EORD immediate -**0- */
+INLINE void eord_im( void )
+{
+ PAIR t;
+ IMMWORD(t);
+ D ^= t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $c9 ADCB immediate ***** */
+INLINE void adcb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $1089 ADCD immediate ***** */
+INLINE void adcd_im( void )
+{
+ PAIR t;
+ UINT32 r;
+ IMMWORD(t);
+ r = D + t.w.l + (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS16(D,t.w.l,r);
+ D = r;
+}
+
+/* $cA ORB immediate -**0- */
+INLINE void orb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ B |= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $108a ORD immediate -**0- */
+INLINE void ord_im( void )
+{
+ PAIR t;
+ IMMWORD(t);
+ D |= t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $cB ADDB immediate ***** */
+INLINE void addb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $cC LDD immediate -**0- */
+INLINE void ldd_im( void )
+{
+ PAIR t;
+
+ IMMWORD(t);
+ D=t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $1086 LDW immediate -**0- */
+INLINE void ldw_im( void )
+{
+ PAIR t;
+ IMMWORD(t);
+ W=t.w.l;
+ CLR_NZV;
+ SET_NZ16(W);
+}
+
+/* $cE LDU (LDS) immediate -**0- */
+INLINE void ldu_im( void )
+{
+ IMMWORD(pU);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10cE LDS immediate -**0- */
+INLINE void lds_im( void )
+{
+ IMMWORD(pS);
+ CLR_NZV;
+ SET_NZ16(S);
+ hd6309.int_state |= HD6309_LDS;
+}
+
+/* $d0 SUBB direct ?**** */
+INLINE void subb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $1190 SUBE direct ?**** */
+INLINE void sube_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = E - t;
+ CLR_NZVC;
+ SET_FLAGS8(E,t,r);
+ E = r;
+}
+
+/* $11d0 SUBF direct ?**** */
+INLINE void subf_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = F - t;
+ CLR_NZVC;
+ SET_FLAGS8(F,t,r);
+ F = r;
+}
+
+/* $d1 CMPB direct ?**** */
+INLINE void cmpb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+}
+
+/* $1191 CMPE direct ?**** */
+INLINE void cmpe_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = E - t;
+ CLR_NZVC;
+ SET_FLAGS8(E,t,r);
+}
+
+/* $11D1 CMPF direct ?**** */
+INLINE void cmpf_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = F - t;
+ CLR_NZVC;
+ SET_FLAGS8(F,t,r);
+}
+
+/* $d2 SBCB direct ?**** */
+INLINE void sbcb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $1092 SBCD direct ?**** */
+INLINE void sbcd_di( void )
+{
+ PAIR t;
+ UINT32 r;
+ DIRWORD(t);
+ r = D - t.w.l - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS16(D,t.w.l,r);
+ D = r;
+}
+
+/* $d3 ADDD direct -**** */
+INLINE void addd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $109b ADDW direct -**** */
+INLINE void addw_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = W;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ W = r;
+}
+
+/* $119b ADDE direct -**** */
+INLINE void adde_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = E + t;
+ CLR_HNZVC;
+ SET_FLAGS8(E,t,r);
+ SET_H(E,t,r);
+ E = r;
+}
+
+/* $11db ADDF direct -**** */
+INLINE void addf_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = F + t;
+ CLR_HNZVC;
+ SET_FLAGS8(F,t,r);
+ SET_H(F,t,r);
+ F = r;
+}
+
+/* $d4 ANDB direct -**0- */
+INLINE void andb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $1094 ANDD direct -**0- */
+INLINE void andd_di( void )
+{
+ PAIR t;
+ DIRWORD(t);
+ D &= t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $d5 BITB direct -**0- */
+INLINE void bitb_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $1095 BITD direct -**0- */
+INLINE void bitd_di( void )
+{
+ PAIR t;
+ UINT16 r;
+ DIRWORD(t);
+ r = B & t.w.l;
+ CLR_NZV;
+ SET_NZ16(r);
+}
+
+/* $d6 LDB direct -**0- */
+INLINE void ldb_di( void )
+{
+ DIRBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $1196 LDE direct -**0- */
+INLINE void lde_di( void )
+{
+ DIRBYTE(E);
+ CLR_NZV;
+ SET_NZ8(E);
+}
+
+/* $11d6 LDF direct -**0- */
+INLINE void ldf_di( void )
+{
+ DIRBYTE(F);
+ CLR_NZV;
+ SET_NZ8(F);
+}
+
+/* $d7 STB direct -**0- */
+INLINE void stb_di( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+ DIRECT;
+ WM(EAD,B);
+}
+
+/* $1197 STE direct -**0- */
+INLINE void ste_di( void )
+{
+ CLR_NZV;
+ SET_NZ8(E);
+ DIRECT;
+ WM(EAD,E);
+}
+
+/* $11D7 STF direct -**0- */
+INLINE void stf_di( void )
+{
+ CLR_NZV;
+ SET_NZ8(F);
+ DIRECT;
+ WM(EAD,F);
+}
+
+/* $d8 EORB direct -**0- */
+INLINE void eorb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ B ^= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $1098 EORD direct -**0- */
+INLINE void eord_di( void )
+{
+ PAIR t;
+ DIRWORD(t);
+ D ^= t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $d9 ADCB direct ***** */
+INLINE void adcb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $1099 adcd direct ***** */
+INLINE void adcd_di( void )
+{
+ UINT32 r;
+ PAIR t;
+
+ DIRWORD(t);
+ r = D + t.w.l + (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS16(D,t.w.l,r);
+ D = r;
+}
+
+/* $dA ORB direct -**0- */
+INLINE void orb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ B |= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $109a ORD direct -**0- */
+INLINE void ord_di( void )
+{
+ PAIR t;
+ DIRWORD(t);
+ D |= t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $dB ADDB direct ***** */
+INLINE void addb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $dC LDD direct -**0- */
+INLINE void ldd_di( void )
+{
+ PAIR t;
+ DIRWORD(t);
+ D=t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $1096 LDW direct -**0- */
+INLINE void ldw_di( void )
+{
+ PAIR t;
+ DIRWORD(t);
+ W=t.w.l;
+ CLR_NZV;
+ SET_NZ16(W);
+}
+
+/* $dD STD direct -**0- */
+INLINE void std_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+ DIRECT;
+ WM16(EAD,&pD);
+}
+
+/* $1097 STW direct -**0- */
+INLINE void stw_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(W);
+ DIRECT;
+ WM16(EAD,&pW);
+}
+
+/* $dE LDU (LDS) direct -**0- */
+INLINE void ldu_di( void )
+{
+ DIRWORD(pU);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10dE LDS direct -**0- */
+INLINE void lds_di( void )
+{
+ DIRWORD(pS);
+ CLR_NZV;
+ SET_NZ16(S);
+ hd6309.int_state |= HD6309_LDS;
+}
+
+/* $dF STU (STS) direct -**0- */
+INLINE void stu_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(U);
+ DIRECT;
+ WM16(EAD,&pU);
+}
+
+/* $10dF STS direct -**0- */
+INLINE void sts_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ DIRECT;
+ WM16(EAD,&pS);
+}
+
+/* $e0 SUBB indexed ?**** */
+INLINE void subb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $11a0 SUBE indexed ?**** */
+INLINE void sube_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = E - t;
+ CLR_NZVC;
+ SET_FLAGS8(E,t,r);
+ E = r;
+}
+
+/* $11e0 SUBF indexed ?**** */
+INLINE void subf_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = F - t;
+ CLR_NZVC;
+ SET_FLAGS8(F,t,r);
+ F = r;
+}
+
+/* $e1 CMPB indexed ?**** */
+INLINE void cmpb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+}
+
+/* $11a1 CMPE indexed ?**** */
+INLINE void cmpe_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = E - t;
+ CLR_NZVC;
+ SET_FLAGS8(E,t,r);
+}
+
+/* $11e1 CMPF indexed ?**** */
+INLINE void cmpf_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = F - t;
+ CLR_NZVC;
+ SET_FLAGS8(F,t,r);
+}
+
+/* $e2 SBCB indexed ?**** */
+INLINE void sbcb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $10a2 SBCD indexed ?**** */
+INLINE void sbcd_ix( void )
+{
+ UINT32 t,r;
+ fetch_effective_address();
+ t = RM16(EAD);
+ r = D - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS16(D,t,r);
+ D = r;
+}
+
+/* $e3 ADDD indexed -**** */
+INLINE void addd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $10ab ADDW indexed -**** */
+INLINE void addw_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = W;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ W = r;
+}
+
+/* $11ab ADDE indexed -**** */
+INLINE void adde_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = E + t;
+ CLR_HNZVC;
+ SET_FLAGS8(E,t,r);
+ SET_H(E,t,r);
+ E = r;
+}
+
+/* $11eb ADDF indexed -**** */
+INLINE void addf_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = F + t;
+ CLR_HNZVC;
+ SET_FLAGS8(F,t,r);
+ SET_H(F,t,r);
+ F = r;
+}
+
+/* $e4 ANDB indexed -**0- */
+INLINE void andb_ix( void )
+{
+ fetch_effective_address();
+ B &= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $10a4 ANDD indexed -**0- */
+INLINE void andd_ix( void )
+{
+ fetch_effective_address();
+ D &= RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $e5 BITB indexed -**0- */
+INLINE void bitb_ix( void )
+{
+ UINT8 r;
+ fetch_effective_address();
+ r = B & RM(EAD);
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $10a5 BITD indexed -**0- */
+INLINE void bitd_ix( void )
+{
+ UINT16 r;
+ fetch_effective_address();
+ r = D & RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(r);
+}
+
+/* $e6 LDB indexed -**0- */
+INLINE void ldb_ix( void )
+{
+ fetch_effective_address();
+ B = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $11a6 LDE indexed -**0- */
+INLINE void lde_ix( void )
+{
+ fetch_effective_address();
+ E = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(E);
+}
+
+/* $11e6 LDF indexed -**0- */
+INLINE void ldf_ix( void )
+{
+ fetch_effective_address();
+ F = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(F);
+}
+
+/* $e7 STB indexed -**0- */
+INLINE void stb_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ8(B);
+ WM(EAD,B);
+}
+
+/* $11a7 STE indexed -**0- */
+INLINE void ste_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ8(E);
+ WM(EAD,E);
+}
+
+/* $11e7 STF indexed -**0- */
+INLINE void stf_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ8(F);
+ WM(EAD,F);
+}
+
+/* $e8 EORB indexed -**0- */
+INLINE void eorb_ix( void )
+{
+ fetch_effective_address();
+ B ^= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $10a8 EORD indexed -**0- */
+INLINE void eord_ix( void )
+{
+ fetch_effective_address();
+ D ^= RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $e9 ADCB indexed ***** */
+INLINE void adcb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $10a9 ADCD indexed ***** */
+INLINE void adcd_ix( void )
+{
+ UINT32 r;
+ PAIR t;
+ fetch_effective_address();
+ t.d = RM16(EAD);
+ r = D + t.d + (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS16(D,t.d,r);
+ D = r;
+}
+
+/* $eA ORB indexed -**0- */
+INLINE void orb_ix( void )
+{
+ fetch_effective_address();
+ B |= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $10aa ORD indexed -**0- */
+INLINE void ord_ix( void )
+{
+ fetch_effective_address();
+ D |= RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $eB ADDB indexed ***** */
+INLINE void addb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $eC LDD indexed -**0- */
+INLINE void ldd_ix( void )
+{
+ fetch_effective_address();
+ D=RM16(EAD);
+ CLR_NZV; SET_NZ16(D);
+}
+
+/* $10a6 LDW indexed -**0- */
+INLINE void ldw_ix( void )
+{
+ fetch_effective_address();
+ W=RM16(EAD);
+ CLR_NZV; SET_NZ16(W);
+}
+
+/* $eD STD indexed -**0- */
+INLINE void std_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(D);
+ WM16(EAD,&pD);
+}
+
+/* $10a7 STW indexed -**0- */
+INLINE void stw_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(W);
+ WM16(EAD,&pW);
+}
+
+/* $eE LDU (LDS) indexed -**0- */
+INLINE void ldu_ix( void )
+{
+ fetch_effective_address();
+ U=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10eE LDS indexed -**0- */
+INLINE void lds_ix( void )
+{
+ fetch_effective_address();
+ S=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(S);
+ hd6309.int_state |= HD6309_LDS;
+}
+
+/* $eF STU (STS) indexed -**0- */
+INLINE void stu_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(U);
+ WM16(EAD,&pU);
+}
+
+/* $10eF STS indexed -**0- */
+INLINE void sts_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(S);
+ WM16(EAD,&pS);
+}
+
+/* $f0 SUBB extended ?**** */
+INLINE void subb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $11b0 SUBE extended ?**** */
+INLINE void sube_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = E - t;
+ CLR_NZVC;
+ SET_FLAGS8(E,t,r);
+ E = r;
+}
+
+/* $11f0 SUBF extended ?**** */
+INLINE void subf_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = F - t;
+ CLR_NZVC;
+ SET_FLAGS8(F,t,r);
+ F = r;
+}
+
+/* $f1 CMPB extended ?**** */
+INLINE void cmpb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+}
+
+/* $11b1 CMPE extended ?**** */
+INLINE void cmpe_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = E - t;
+ CLR_NZVC;
+ SET_FLAGS8(E,t,r);
+}
+
+/* $11f1 CMPF extended ?**** */
+INLINE void cmpf_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = F - t;
+ CLR_NZVC;
+ SET_FLAGS8(F,t,r);
+}
+
+/* $f2 SBCB extended ?**** */
+INLINE void sbcb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $10b2 SBCD extended ?**** */
+INLINE void sbcd_ex( void )
+{
+ PAIR t = {{0,}};
+ UINT32 r;
+
+ EXTWORD(t);
+ r = D - t.w.l - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS16(D,t.w.l,r);
+ D = r;
+}
+
+/* $f3 ADDD extended -**** */
+INLINE void addd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $10bb ADDW extended -**** */
+INLINE void addw_ex( void )
+{
+ UINT32 r,d;
+ PAIR b = {{0,}};
+ EXTWORD(b);
+ d = W;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ W = r;
+}
+
+/* $11bb ADDE extended -**** */
+INLINE void adde_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = E + t;
+ CLR_HNZVC;
+ SET_FLAGS8(E,t,r);
+ SET_H(E,t,r);
+ E = r;
+}
+
+/* $11fb ADDF extended -**** */
+INLINE void addf_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = F + t;
+ CLR_HNZVC;
+ SET_FLAGS8(F,t,r);
+ SET_H(F,t,r);
+ F = r;
+}
+
+/* $f4 ANDB extended -**0- */
+INLINE void andb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $10b4 ANDD extended -**0- */
+INLINE void andd_ex( void )
+{
+ PAIR t = {{0,}};
+ EXTWORD(t);
+ D &= t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $f5 BITB extended -**0- */
+INLINE void bitb_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $10b5 BITD extended -**0- */
+INLINE void bitd_ex( void )
+{
+ PAIR t = {{0,}};
+ UINT8 r;
+ EXTWORD(t);
+ r = B & t.w.l;
+ CLR_NZV;
+ SET_NZ16(r);
+}
+
+/* $f6 LDB extended -**0- */
+INLINE void ldb_ex( void )
+{
+ EXTBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $11b6 LDE extended -**0- */
+INLINE void lde_ex( void )
+{
+ EXTBYTE(E);
+ CLR_NZV;
+ SET_NZ8(E);
+}
+
+/* $11f6 LDF extended -**0- */
+INLINE void ldf_ex( void )
+{
+ EXTBYTE(F);
+ CLR_NZV;
+ SET_NZ8(F);
+}
+
+/* $f7 STB extended -**0- */
+INLINE void stb_ex( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+ EXTENDED;
+ WM(EAD,B);
+}
+
+/* $11b7 STE extended -**0- */
+INLINE void ste_ex( void )
+{
+ CLR_NZV;
+ SET_NZ8(E);
+ EXTENDED;
+ WM(EAD,E);
+}
+
+/* $11f7 STF extended -**0- */
+INLINE void stf_ex( void )
+{
+ CLR_NZV;
+ SET_NZ8(F);
+ EXTENDED;
+ WM(EAD,F);
+}
+
+/* $f8 EORB extended -**0- */
+INLINE void eorb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B ^= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $10b8 EORD extended -**0- */
+INLINE void eord_ex( void )
+{
+ PAIR t = {{0,}};
+ EXTWORD(t);
+ D ^= t.w.l;
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $f9 ADCB extended ***** */
+INLINE void adcb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $10b9 ADCD extended ***** */
+INLINE void adcd_ex( void )
+{
+ UINT32 r;
+ PAIR t;
+ EXTWORD(t);
+ r = D + t.w.l + (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS16(D,t.w.l,r);
+ D = r;
+}
+
+/* $fA ORB extended -**0- */
+INLINE void orb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B |= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $10ba ORD extended -**0- */
+INLINE void ord_ex( void )
+{
+ PAIR t = {{0,}};
+ EXTWORD(t);
+ D |= t.w.l;
+ CLR_NZV;
+ SET_NZ8(D);
+}
+
+/* $fB ADDB extended ***** */
+INLINE void addb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $fC LDD extended -**0- */
+INLINE void ldd_ex( void )
+{
+ EXTWORD(pD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $10b6 LDW extended -**0- */
+INLINE void ldw_ex( void )
+{
+ EXTWORD(pW);
+ CLR_NZV;
+ SET_NZ16(W);
+}
+
+/* $fD STD extended -**0- */
+INLINE void std_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+ EXTENDED;
+ WM16(EAD,&pD);
+}
+
+/* $10b7 STW extended -**0- */
+INLINE void stw_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(W);
+ EXTENDED;
+ WM16(EAD,&pW);
+}
+
+/* $fE LDU (LDS) extended -**0- */
+INLINE void ldu_ex( void )
+{
+ EXTWORD(pU);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10fE LDS extended -**0- */
+INLINE void lds_ex( void )
+{
+ EXTWORD(pS);
+ CLR_NZV;
+ SET_NZ16(S);
+ hd6309.int_state |= HD6309_LDS;
+}
+
+/* $fF STU (STS) extended -**0- */
+INLINE void stu_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(U);
+ EXTENDED;
+ WM16(EAD,&pU);
+}
+
+/* $10fF STS extended -**0- */
+INLINE void sts_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ EXTENDED;
+ WM16(EAD,&pS);
+}
+
+/* $10xx opcodes */
+INLINE void pref10( void )
+{
+ UINT8 ireg2 = ROP(PCD);
+ PC++;
+
+#ifdef BIG_SWITCH
+ switch( ireg2 )
+ {
+ case 0x21: lbrn(); break;
+ case 0x22: lbhi(); break;
+ case 0x23: lbls(); break;
+ case 0x24: lbcc(); break;
+ case 0x25: lbcs(); break;
+ case 0x26: lbne(); break;
+ case 0x27: lbeq(); break;
+ case 0x28: lbvc(); break;
+ case 0x29: lbvs(); break;
+ case 0x2a: lbpl(); break;
+ case 0x2b: lbmi(); break;
+ case 0x2c: lbge(); break;
+ case 0x2d: lblt(); break;
+ case 0x2e: lbgt(); break;
+ case 0x2f: lble(); break;
+
+ case 0x30: addr_r(); break;
+ case 0x31: adcr(); break;
+ case 0x32: subr(); break;
+ case 0x33: sbcr(); break;
+ case 0x34: andr(); break;
+ case 0x35: orr(); break;
+ case 0x36: eorr(); break;
+ case 0x37: cmpr(); break;
+ case 0x38: pshsw(); break;
+ case 0x39: pulsw(); break;
+ case 0x3a: pshuw(); break;
+ case 0x3b: puluw(); break;
+ case 0x3f: swi2(); break;
+
+ case 0x40: negd(); break;
+ case 0x43: comd(); break;
+ case 0x44: lsrd(); break;
+ case 0x46: rord(); break;
+ case 0x47: asrd(); break;
+ case 0x48: asld(); break;
+ case 0x49: rold(); break;
+ case 0x4a: decd(); break;
+ case 0x4c: incd(); break;
+ case 0x4d: tstd(); break;
+ case 0x4f: clrd(); break;
+
+ case 0x53: comw(); break;
+ case 0x54: lsrw(); break;
+ case 0x56: rorw(); break;
+ case 0x59: rolw(); break;
+ case 0x5a: decw(); break;
+ case 0x5c: incw(); break;
+ case 0x5d: tstw(); break;
+ case 0x5f: clrw(); break;
+
+ case 0x80: subw_im(); break;
+ case 0x81: cmpw_im(); break;
+ case 0x82: sbcd_im(); break;
+ case 0x83: cmpd_im(); break;
+ case 0x84: andd_im(); break;
+ case 0x85: bitd_im(); break;
+ case 0x86: ldw_im(); break;
+ case 0x88: eord_im(); break;
+ case 0x89: adcd_im(); break;
+ case 0x8a: ord_im(); break;
+ case 0x8b: addw_im(); break;
+ case 0x8c: cmpy_im(); break;
+ case 0x8e: ldy_im(); break;
+
+ case 0x90: subw_di(); break;
+ case 0x91: cmpw_di(); break;
+ case 0x92: sbcd_di(); break;
+ case 0x93: cmpd_di(); break;
+ case 0x94: andd_di(); break;
+ case 0x95: bitd_di(); break;
+ case 0x96: ldw_di(); break;
+ case 0x97: stw_di(); break;
+ case 0x98: eord_di(); break;
+ case 0x99: adcd_di(); break;
+ case 0x9a: ord_di(); break;
+ case 0x9b: addw_di(); break;
+ case 0x9c: cmpy_di(); break;
+ case 0x9e: ldy_di(); break;
+ case 0x9f: sty_di(); break;
+
+ case 0xa0: subw_ix(); break;
+ case 0xa1: cmpw_ix(); break;
+ case 0xa2: sbcd_ix(); break;
+ case 0xa3: cmpd_ix(); break;
+ case 0xa4: andd_ix(); break;
+ case 0xa5: bitd_ix(); break;
+ case 0xa6: ldw_ix(); break;
+ case 0xa7: stw_ix(); break;
+ case 0xa8: eord_ix(); break;
+ case 0xa9: adcd_ix(); break;
+ case 0xaa: ord_ix(); break;
+ case 0xab: addw_ix(); break;
+ case 0xac: cmpy_ix(); break;
+ case 0xae: ldy_ix(); break;
+ case 0xaf: sty_ix(); break;
+
+ case 0xb0: subw_ex(); break;
+ case 0xb1: cmpw_ex(); break;
+ case 0xb2: sbcd_ex(); break;
+ case 0xb3: cmpd_ex(); break;
+ case 0xb4: andd_ex(); break;
+ case 0xb5: bitd_ex(); break;
+ case 0xb6: ldw_ex(); break;
+ case 0xb7: stw_ex(); break;
+ case 0xb8: eord_ex(); break;
+ case 0xb9: adcd_ex(); break;
+ case 0xba: ord_ex(); break;
+ case 0xbb: addw_ex(); break;
+ case 0xbc: cmpy_ex(); break;
+ case 0xbe: ldy_ex(); break;
+ case 0xbf: sty_ex(); break;
+
+ case 0xce: lds_im(); break;
+
+ case 0xdc: ldq_di(); break;
+ case 0xdd: stq_di(); break;
+ case 0xde: lds_di(); break;
+ case 0xdf: sts_di(); break;
+
+ case 0xec: ldq_ix(); break;
+ case 0xed: stq_ix(); break;
+ case 0xee: lds_ix(); break;
+ case 0xef: sts_ix(); break;
+
+ case 0xfc: ldq_ex(); break;
+ case 0xfd: stq_ex(); break;
+ case 0xfe: lds_ex(); break;
+ case 0xff: sts_ex(); break;
+
+ default: IIError(); break;
+ }
+#else
+
+ (*hd6309_page01[ireg2])();
+
+#endif /* BIG_SWITCH */
+
+ hd6309_ICount -= cycle_counts_page01[ireg2];
+}
+
+/* $11xx opcodes */
+INLINE void pref11( void )
+{
+ UINT8 ireg2 = ROP(PCD);
+ PC++;
+
+#ifdef BIG_SWITCH
+ switch( ireg2 )
+ {
+ case 0x30: band(); break;
+ case 0x31: biand(); break;
+ case 0x32: bor(); break;
+ case 0x33: bior(); break;
+ case 0x34: beor(); break;
+ case 0x35: bieor(); break;
+ case 0x36: ldbt(); break;
+ case 0x37: stbt(); break;
+ case 0x38: tfmpp(); break; /* Timing for TFM is actually 6+3n. */
+ case 0x39: tfmmm(); break; /* To avoid saving the state, I decided */
+ case 0x3a: tfmpc(); break; /* to push the initial 6 cycles to the end */
+ case 0x3b: tfmcp(); break; /* We will soon see how this fairs! */
+ case 0x3c: bitmd_im(); break;
+ case 0x3d: ldmd_im(); break;
+ case 0x3f: swi3(); break;
+
+ case 0x43: come(); break;
+ case 0x4a: dece(); break;
+ case 0x4c: ince(); break;
+ case 0x4d: tste(); break;
+ case 0x4f: clre(); break;
+
+ case 0x53: comf(); break;
+ case 0x5a: decf(); break;
+ case 0x5c: incf(); break;
+ case 0x5d: tstf(); break;
+ case 0x5f: clrf(); break;
+
+ case 0x80: sube_im(); break;
+ case 0x81: cmpe_im(); break;
+ case 0x83: cmpu_im(); break;
+ case 0x86: lde_im(); break;
+ case 0x8b: adde_im(); break;
+ case 0x8c: cmps_im(); break;
+ case 0x8d: divd_im(); break;
+ case 0x8e: divq_im(); break;
+ case 0x8f: muld_im(); break;
+
+ case 0x90: sube_di(); break;
+ case 0x91: cmpe_di(); break;
+ case 0x93: cmpu_di(); break;
+ case 0x96: lde_di(); break;
+ case 0x97: ste_di(); break;
+ case 0x9b: adde_di(); break;
+ case 0x9c: cmps_di(); break;
+ case 0x9d: divd_di(); break;
+ case 0x9e: divq_di(); break;
+ case 0x9f: muld_di(); break;
+
+ case 0xa0: sube_ix(); break;
+ case 0xa1: cmpe_ix(); break;
+ case 0xa3: cmpu_ix(); break;
+ case 0xa6: lde_ix(); break;
+ case 0xa7: ste_ix(); break;
+ case 0xab: adde_ix(); break;
+ case 0xac: cmps_ix(); break;
+ case 0xad: divd_ix(); break;
+ case 0xae: divq_ix(); break;
+ case 0xaf: muld_ix(); break;
+
+ case 0xb0: sube_ex(); break;
+ case 0xb1: cmpe_ex(); break;
+ case 0xb3: cmpu_ex(); break;
+ case 0xb6: lde_ex(); break;
+ case 0xb7: ste_ex(); break;
+ case 0xbb: adde_ex(); break;
+ case 0xbc: cmps_ex(); break;
+ case 0xbd: divd_ex(); break;
+ case 0xbe: divq_ex(); break;
+ case 0xbf: muld_ex(); break;
+
+ case 0xc0: subf_im(); break;
+ case 0xc1: cmpf_im(); break;
+ case 0xc6: ldf_im(); break;
+ case 0xcb: addf_im(); break;
+
+ case 0xd0: subf_di(); break;
+ case 0xd1: cmpf_di(); break;
+ case 0xd6: ldf_di(); break;
+ case 0xd7: stf_di(); break;
+ case 0xdb: addf_di(); break;
+
+ case 0xe0: subf_ix(); break;
+ case 0xe1: cmpf_ix(); break;
+ case 0xe6: ldf_ix(); break;
+ case 0xe7: stf_ix(); break;
+ case 0xeb: addf_ix(); break;
+
+ case 0xf0: subf_ex(); break;
+ case 0xf1: cmpf_ex(); break;
+ case 0xf6: ldf_ex(); break;
+ case 0xf7: stf_ex(); break;
+ case 0xfb: addf_ex(); break;
+
+ default: IIError(); break;
+ }
+#else
+
+ (*hd6309_page11[ireg2])();
+
+#endif /* BIG_SWITCH */
+ hd6309_ICount -= cycle_counts_page11[ireg2];
+}
+
diff --git a/src/emu/cpu/hd6309/6309tbl.c b/src/emu/cpu/hd6309/6309tbl.c
new file mode 100644
index 00000000000..2c0d78815a8
--- /dev/null
+++ b/src/emu/cpu/hd6309/6309tbl.c
@@ -0,0 +1,814 @@
+INLINE void illegal( void );
+INLINE void neg_di( void );
+INLINE void oim_di( void );
+INLINE void aim_di( void );
+INLINE void com_di( void );
+INLINE void lsr_di( void );
+INLINE void eim_di( void );
+INLINE void ror_di( void );
+INLINE void asr_di( void );
+INLINE void asl_di( void );
+INLINE void rol_di( void );
+INLINE void dec_di( void );
+INLINE void tim_di( void );
+INLINE void inc_di( void );
+INLINE void tst_di( void );
+INLINE void jmp_di( void );
+INLINE void clr_di( void );
+INLINE void nop( void );
+INLINE void sync( void );
+INLINE void sexw( void );
+INLINE void lbra( void );
+INLINE void lbsr( void );
+INLINE void daa( void );
+INLINE void daa( void );
+INLINE void orcc( void );
+INLINE void andcc( void );
+INLINE void sex( void );
+INLINE void exg( void );
+INLINE void tfr( void );
+INLINE void bra( void );
+INLINE void brn( void );
+INLINE void lbrn( void );
+INLINE void bhi( void );
+INLINE void lbhi( void );
+INLINE void bls( void );
+INLINE void lbls( void );
+INLINE void bcc( void );
+INLINE void lbcc( void );
+INLINE void bcs( void );
+INLINE void lbcs( void );
+INLINE void bne( void );
+INLINE void lbne( void );
+INLINE void beq( void );
+INLINE void lbeq( void );
+INLINE void bvc( void );
+INLINE void lbvc( void );
+INLINE void bvs( void );
+INLINE void lbvs( void );
+INLINE void bpl( void );
+INLINE void lbpl( void );
+INLINE void bmi( void );
+INLINE void lbmi( void );
+INLINE void bge( void );
+INLINE void lbge( void );
+INLINE void blt( void );
+INLINE void lblt( void );
+INLINE void bgt( void );
+INLINE void lbgt( void );
+INLINE void ble( void );
+INLINE void lble( void );
+INLINE void addr_r( void );
+INLINE void adcr( void );
+INLINE void subr( void );
+INLINE void sbcr( void );
+INLINE void andr( void );
+INLINE void orr( void );
+INLINE void eorr( void );
+INLINE void cmpr( void );
+INLINE void tfmpp( void );
+INLINE void tfmmm( void );
+INLINE void tfmpc( void );
+INLINE void tfmcp( void );
+INLINE void bitmd_im( void );
+INLINE void leax( void );
+INLINE void leay( void );
+INLINE void leas( void );
+INLINE void leau( void );
+INLINE void pshs( void );
+INLINE void ldmd_im( void );
+INLINE void pshsw( void );
+INLINE void pshuw( void );
+INLINE void puls( void );
+INLINE void pulsw( void );
+INLINE void puluw( void );
+INLINE void pshu( void );
+INLINE void pulu( void );
+INLINE void rts( void );
+INLINE void abx( void );
+INLINE void rti( void );
+INLINE void cwai( void );
+INLINE void bitd_di( void );
+INLINE void bitd_ix( void );
+INLINE void bitd_ex( void );
+INLINE void mul( void );
+INLINE void swi( void );
+INLINE void band( void );
+INLINE void bitd_im( void );
+INLINE void biand( void );
+INLINE void bor( void );
+INLINE void bior( void );
+INLINE void beor( void );
+INLINE void bieor( void );
+INLINE void ldbt( void );
+INLINE void stbt( void );
+INLINE void swi2( void );
+INLINE void swi3( void );
+INLINE void nega( void );
+INLINE void coma( void );
+INLINE void lsra( void );
+INLINE void rora( void );
+INLINE void asra( void );
+INLINE void asla( void );
+INLINE void rola( void );
+INLINE void deca( void );
+INLINE void inca( void );
+INLINE void tsta( void );
+INLINE void clra( void );
+INLINE void negb( void );
+INLINE void negd( void );
+INLINE void comb( void );
+INLINE void come( void );
+INLINE void comf( void );
+INLINE void comd( void );
+INLINE void comw( void );
+INLINE void lsrb( void );
+INLINE void lsrd( void );
+INLINE void lsrw( void );
+INLINE void rorb( void );
+INLINE void rord( void );
+INLINE void rorw( void );
+INLINE void asrb( void );
+INLINE void asrd( void );
+INLINE void aslb( void );
+INLINE void asld( void );
+INLINE void rolb( void );
+INLINE void rold( void );
+INLINE void rolw( void );
+INLINE void decb( void );
+INLINE void dece( void );
+INLINE void decf( void );
+INLINE void decd( void );
+INLINE void decw( void );
+INLINE void incb( void );
+INLINE void ince( void );
+INLINE void incf( void );
+INLINE void incd( void );
+INLINE void incw( void );
+INLINE void tstb( void );
+INLINE void tstd( void );
+INLINE void tstw( void );
+INLINE void tste( void );
+INLINE void tstf( void );
+INLINE void clrb( void );
+INLINE void clrd( void );
+INLINE void clre( void );
+INLINE void clrf( void );
+INLINE void clrw( void );
+INLINE void neg_ix( void );
+INLINE void oim_ix( void );
+INLINE void aim_ix( void );
+INLINE void com_ix( void );
+INLINE void lsr_ix( void );
+INLINE void eim_ix( void );
+INLINE void ror_ix( void );
+INLINE void asr_ix( void );
+INLINE void asl_ix( void );
+INLINE void rol_ix( void );
+INLINE void dec_ix( void );
+INLINE void tim_ix( void );
+INLINE void inc_ix( void );
+INLINE void tst_ix( void );
+INLINE void jmp_ix( void );
+INLINE void clr_ix( void );
+INLINE void neg_ex( void );
+INLINE void oim_ex( void );
+INLINE void aim_ex( void );
+INLINE void com_ex( void );
+INLINE void lsr_ex( void );
+INLINE void eim_ex( void );
+INLINE void ror_ex( void );
+INLINE void asr_ex( void );
+INLINE void asl_ex( void );
+INLINE void rol_ex( void );
+INLINE void dec_ex( void );
+INLINE void tim_ex( void );
+INLINE void inc_ex( void );
+INLINE void tst_ex( void );
+INLINE void jmp_ex( void );
+INLINE void clr_ex( void );
+INLINE void suba_im( void );
+INLINE void cmpa_im( void );
+INLINE void sbca_im( void );
+INLINE void subd_im( void );
+INLINE void subw_im( void );
+INLINE void cmpd_im( void );
+INLINE void cmpw_im( void );
+INLINE void cmpu_im( void );
+INLINE void anda_im( void );
+INLINE void bita_im( void );
+INLINE void lda_im( void );
+INLINE void eora_im( void );
+INLINE void adca_im( void );
+INLINE void ora_im( void );
+INLINE void adda_im( void );
+INLINE void cmpx_im( void );
+INLINE void cmpy_im( void );
+INLINE void cmps_im( void );
+INLINE void bsr( void );
+INLINE void ldx_im( void );
+INLINE void ldq_im( void );
+INLINE void ldy_im( void );
+INLINE void suba_di( void );
+INLINE void cmpa_di( void );
+INLINE void sbca_di( void );
+INLINE void subd_di( void );
+INLINE void subw_di( void );
+INLINE void cmpd_di( void );
+INLINE void cmpw_di( void );
+INLINE void cmpu_di( void );
+INLINE void anda_di( void );
+INLINE void bita_di( void );
+INLINE void lda_di( void );
+INLINE void sta_di( void );
+INLINE void eora_di( void );
+INLINE void adca_di( void );
+INLINE void ora_di( void );
+INLINE void adda_di( void );
+INLINE void cmpx_di( void );
+INLINE void cmpy_di( void );
+INLINE void cmps_di( void );
+INLINE void jsr_di( void );
+INLINE void ldx_di( void );
+INLINE void muld_di( void );
+INLINE void divd_im( void );
+INLINE void divq_im( void );
+INLINE void muld_im( void );
+INLINE void divd_di( void );
+INLINE void divq_di( void );
+INLINE void ldq_di( void );
+INLINE void ldy_di( void );
+INLINE void stx_di( void );
+INLINE void stq_di( void );
+INLINE void sty_di( void );
+INLINE void suba_ix( void );
+INLINE void cmpa_ix( void );
+INLINE void sbca_ix( void );
+INLINE void subd_ix( void );
+INLINE void subw_ix( void );
+INLINE void cmpd_ix( void );
+INLINE void cmpw_ix( void );
+INLINE void cmpu_ix( void );
+INLINE void anda_ix( void );
+INLINE void bita_ix( void );
+INLINE void lda_ix( void );
+INLINE void sta_ix( void );
+INLINE void eora_ix( void );
+INLINE void adca_ix( void );
+INLINE void ora_ix( void );
+INLINE void adda_ix( void );
+INLINE void cmpx_ix( void );
+INLINE void cmpy_ix( void );
+INLINE void cmps_ix( void );
+INLINE void jsr_ix( void );
+INLINE void ldx_ix( void );
+INLINE void muld_ix( void );
+INLINE void divd_ix( void );
+INLINE void divq_ix( void );
+INLINE void ldq_ix( void );
+INLINE void ldy_ix( void );
+INLINE void stx_ix( void );
+INLINE void stq_ix( void );
+INLINE void sty_ix( void );
+INLINE void suba_ex( void );
+INLINE void cmpa_ex( void );
+INLINE void sbca_ex( void );
+INLINE void subd_ex( void );
+INLINE void subw_ex( void );
+INLINE void cmpd_ex( void );
+INLINE void cmpw_ex( void );
+INLINE void cmpu_ex( void );
+INLINE void anda_ex( void );
+INLINE void bita_ex( void );
+INLINE void lda_ex( void );
+INLINE void sta_ex( void );
+INLINE void eora_ex( void );
+INLINE void adca_ex( void );
+INLINE void ora_ex( void );
+INLINE void adda_ex( void );
+INLINE void cmpx_ex( void );
+INLINE void cmpy_ex( void );
+INLINE void cmps_ex( void );
+INLINE void jsr_ex( void );
+INLINE void ldx_ex( void );
+INLINE void muld_ex( void );
+INLINE void divd_ex( void );
+INLINE void divq_ex( void );
+INLINE void ldq_ex( void );
+INLINE void ldy_ex( void );
+INLINE void stx_ex( void );
+INLINE void stq_ex( void );
+INLINE void sty_ex( void );
+INLINE void subb_im( void );
+INLINE void sube_im( void );
+INLINE void subf_im( void );
+INLINE void cmpb_im( void );
+INLINE void cmpe_im( void );
+INLINE void cmpf_im( void );
+INLINE void sbcb_im( void );
+INLINE void sbcd_im( void );
+INLINE void addd_im( void );
+INLINE void addw_im( void );
+INLINE void adde_im( void );
+INLINE void addf_im( void );
+INLINE void andb_im( void );
+INLINE void andd_im( void );
+INLINE void bitb_im( void );
+INLINE void ldb_im( void );
+INLINE void lde_im( void );
+INLINE void ldf_im( void );
+INLINE void eorb_im( void );
+INLINE void eord_im( void );
+INLINE void adcb_im( void );
+INLINE void adcd_im( void );
+INLINE void orb_im( void );
+INLINE void ord_im( void );
+INLINE void addb_im( void );
+INLINE void ldd_im( void );
+INLINE void ldw_im( void );
+INLINE void ldu_im( void );
+INLINE void lds_im( void );
+INLINE void subb_di( void );
+INLINE void sube_di( void );
+INLINE void subf_di( void );
+INLINE void cmpb_di( void );
+INLINE void cmpe_di( void );
+INLINE void cmpf_di( void );
+INLINE void sbcb_di( void );
+INLINE void sbcd_di( void );
+INLINE void addd_di( void );
+INLINE void addw_di( void );
+INLINE void adde_di( void );
+INLINE void addf_di( void );
+INLINE void andb_di( void );
+INLINE void andd_di( void );
+INLINE void bitb_di( void );
+INLINE void ldb_di( void );
+INLINE void lde_di( void );
+INLINE void ldf_di( void );
+INLINE void stb_di( void );
+INLINE void ste_di( void );
+INLINE void stf_di( void );
+INLINE void eorb_di( void );
+INLINE void eord_di( void );
+INLINE void adcb_di( void );
+INLINE void adcd_di( void );
+INLINE void orb_di( void );
+INLINE void ord_di( void );
+INLINE void addb_di( void );
+INLINE void ldd_di( void );
+INLINE void ldw_di( void );
+INLINE void std_di( void );
+INLINE void stw_di( void );
+INLINE void ldu_di( void );
+INLINE void lds_di( void );
+INLINE void stu_di( void );
+INLINE void sts_di( void );
+INLINE void subb_ix( void );
+INLINE void sube_ix( void );
+INLINE void subf_ix( void );
+INLINE void cmpb_ix( void );
+INLINE void cmpe_ix( void );
+INLINE void cmpf_ix( void );
+INLINE void sbcb_ix( void );
+INLINE void sbcd_ix( void );
+INLINE void addd_ix( void );
+INLINE void addw_ix( void );
+INLINE void adde_ix( void );
+INLINE void addf_ix( void );
+INLINE void andb_ix( void );
+INLINE void andd_ix( void );
+INLINE void bitb_ix( void );
+INLINE void ldb_ix( void );
+INLINE void lde_ix( void );
+INLINE void ldf_ix( void );
+INLINE void stb_ix( void );
+INLINE void ste_ix( void );
+INLINE void stf_ix( void );
+INLINE void eorb_ix( void );
+INLINE void eord_ix( void );
+INLINE void adcb_ix( void );
+INLINE void adcd_ix( void );
+INLINE void orb_ix( void );
+INLINE void ord_ix( void );
+INLINE void addb_ix( void );
+INLINE void ldd_ix( void );
+INLINE void ldw_ix( void );
+INLINE void std_ix( void );
+INLINE void stw_ix( void );
+INLINE void ldu_ix( void );
+INLINE void lds_ix( void );
+INLINE void stu_ix( void );
+INLINE void sts_ix( void );
+INLINE void subb_ex( void );
+INLINE void sube_ex( void );
+INLINE void subf_ex( void );
+INLINE void cmpb_ex( void );
+INLINE void cmpe_ex( void );
+INLINE void cmpf_ex( void );
+INLINE void sbcb_ex( void );
+INLINE void sbcd_ex( void );
+INLINE void addd_ex( void );
+INLINE void addw_ex( void );
+INLINE void adde_ex( void );
+INLINE void addf_ex( void );
+INLINE void andb_ex( void );
+INLINE void andd_ex( void );
+INLINE void bitb_ex( void );
+INLINE void ldb_ex( void );
+INLINE void lde_ex( void );
+INLINE void ldf_ex( void );
+INLINE void stb_ex( void );
+INLINE void ste_ex( void );
+INLINE void stf_ex( void );
+INLINE void eorb_ex( void );
+INLINE void eord_ex( void );
+INLINE void adcb_ex( void );
+INLINE void adcd_ex( void );
+INLINE void orb_ex( void );
+INLINE void ord_ex( void );
+INLINE void addb_ex( void );
+INLINE void ldd_ex( void );
+INLINE void ldw_ex( void );
+INLINE void std_ex( void );
+INLINE void stw_ex( void );
+INLINE void ldu_ex( void );
+INLINE void lds_ex( void );
+INLINE void stu_ex( void );
+INLINE void sts_ex( void );
+INLINE void pref10( void );
+INLINE void pref11( void );
+
+static UINT8 flags8i[256]= /* increment */
+{
+CC_Z,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+CC_N|CC_V,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N
+};
+static UINT8 flags8d[256]= /* decrement */
+{
+CC_Z,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,CC_V,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N
+};
+
+static UINT8 index_cycle_em[256] = { /* Index Loopup cycle counts, emulated 6809 */
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7, 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+
+/* 0x0X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x1X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x2X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x4X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x6X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x8X */ 2, 3, 2, 3, 0, 1, 1, 1, 1, 4, 1, 4, 1, 5, 4, 0,
+/* 0x9X */ 3, 6, 20, 6, 3, 4, 4, 4, 4, 7, 4, 7, 4, 8, 7, 5,
+/* 0xAX */ 2, 3, 2, 3, 0, 1, 1, 1, 1, 4, 1, 4, 1, 5, 4, 5,
+/* 0xBX */ 5, 6, 20, 6, 3, 4, 4, 4, 4, 7, 4, 7, 4, 8, 7, 20,
+/* 0xCX */ 2, 3, 2, 3, 0, 1, 1, 1, 1, 4, 1, 4, 1, 5, 4, 3,
+/* 0xDX */ 4, 6, 20, 6, 3, 4, 4, 4, 4, 7, 4, 7, 4, 8, 7, 20,
+/* 0xEX */ 2, 3, 2, 3, 0, 1, 1, 1, 1, 4, 1, 4, 1, 5, 4, 3,
+/* 0xFX */ 4, 6, 20, 6, 3, 4, 4, 4, 4, 7, 4, 7, 4, 8, 7, 20
+};
+
+static UINT8 index_cycle_na[256] = { /* Index Loopup cycle counts,
+native 6309 */
+/* X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, XA, XB, XC, XD, XE, XF */
+
+/* 0x0X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x1X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x2X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x4X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x6X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x8X */ 1, 2, 1, 2, 0, 1, 1, 1, 1, 3, 1, 2, 1, 3, 1, 0,
+/* 0x9X */ 3, 5, 19, 5, 3, 4, 4, 4, 4, 7, 4, 5, 4, 6, 4, 5,
+/* 0xAX */ 1, 2, 1, 2, 0, 1, 1, 1, 1, 3, 1, 2, 1, 3, 1, 2,
+/* 0xBX */ 5, 5, 19, 5, 3, 4, 4, 4, 4, 7, 4, 5, 4, 6, 4, 19,
+/* 0xCX */ 1, 2, 1, 2, 0, 1, 1, 1, 1, 3, 1, 2, 1, 3, 1, 1,
+/* 0xDX */ 4, 5, 19, 5, 3, 4, 4, 4, 4, 7, 4, 5, 4, 6, 4, 19,
+/* 0xEX */ 1, 2, 1, 2, 0, 1, 1, 1, 1, 3, 1, 2, 1, 3, 1, 1,
+/* 0xFX */ 4, 5, 19, 5, 3, 4, 4, 4, 4, 7, 4, 5, 4, 6, 4, 19
+};
+
+#define IIP0 19 /* Illegal instruction cycle count page 0 */
+#define IIP1 20 /* Illegal instruction cycle count page 01 & 11 */
+
+static UINT8 ccounts_page0_em[256] = /* Cycle Counts Page zero, Emulated 6809 */
+{
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7, 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+/* 0x0X */ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 6,
+/* 0x1X */ 0, 0, 2, 4, 4, IIP0, 5, 9, IIP0, 2, 3, IIP0, 3, 2, 8, 6,
+/* 0x2X */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+/* 0x3X */ 4, 4, 4, 4, 5, 5, 5, 5, IIP0, 5, 3, 6, 20, 11, IIP0, 19,
+/* 0x4X */ 2, IIP0, IIP0, 2, 2, IIP0, 2, 2, 2, 2, 2, IIP0, 2, 2, IIP0, 2,
+/* 0x5X */ 2, IIP0, IIP0, 2, 2, IIP0, 2, 2, 2, 2, 2, IIP0, 2, 2, IIP0, 2,
+/* 0x6X */ 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 3, 6,
+/* 0x7X */ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 4, 7,
+/* 0x8X */ 2, 2, 2, 4, 2, 2, 2, IIP0, 2, 2, 2, 2, 4, 7, 3, IIP0,
+/* 0x9X */ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 7, 5, 5,
+/* 0xAX */ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 7, 5, 5,
+/* 0xBX */ 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 5, 7, 8, 6, 6,
+/* 0xCX */ 2, 2, 2, 4, 2, 2, 2, IIP0, 2, 2, 2, 2, 3, 5, 3, IIP0,
+/* 0xDX */ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+/* 0xEX */ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+/* 0xFX */ 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6
+};
+
+static UINT8 ccounts_page0_na[256] = /* Cycle Counts Page zero, Native 6309 */
+{
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7, 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+/* 0x0X */ 5, 6, 6, 5, 5, 6, 5, 5, 5, 5, 5, 6, 5, 4, 2, 5,
+/* 0x1X */ 0, 0, 1, 4, 4, IIP0, 4, 7, IIP0, 1, 2, IIP0, 3, 1, 5, 4,
+/* 0x2X */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+/* 0x3X */ 4, 4, 4, 4, 4, 4, 4, 4, IIP0, 4, 1, 6, 22, 10, IIP0, 21,
+/* 0x4X */ 1, IIP0, IIP0, 1, 1, IIP0, 1, 1, 1, 1, 1, IIP0, 1, 1, IIP0, 1,
+/* 0x5X */ 1, IIP0, IIP0, 1, 1, IIP0, 1, 1, 1, 1, 1, IIP0, 1, 1, IIP0, 1,
+/* 0x6X */ 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 5, 3, 6,
+/* 0x7X */ 6, 7, 7, 6, 6, 7, 6, 6, 6, 6, 6, 5, 6, 5, 3, 6,
+/* 0x8X */ 2, 2, 2, 3, 2, 2, 2, IIP0, 2, 2, 2, 2, 3, 6, 3, IIP0,
+/* 0x9X */ 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 6, 4, 4,
+/* 0xAX */ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 5, 5,
+/* 0xBX */ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 7, 5, 5,
+/* 0xCX */ 2, 2, 2, 3, 2, 2, 2, IIP0, 2, 2, 2, 2, 3, 5, 3, IIP0,
+/* 0xDX */ 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+/* 0xEX */ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+/* 0xFX */ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5
+};
+
+static UINT8 ccounts_page01_em[256] = /* Cycle Counts Page 01, Emulated 6809 */
+{
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7, 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+/* 0x0X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x1X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x2X */ IIP1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+/* 0x3X */ 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, IIP1, IIP1, IIP1, 20,
+/* 0x4X */ 2, IIP1,IIP1, 2, 2, IIP1, 2, 2, 2, 2, 2, IIP1, 2, 2, IIP1, 2,
+/* 0x5X */ IIP1, IIP1, IIP1, 3, 3, IIP1, 3, IIP1, IIP1, 3, 3, IIP1, 3, 3, IIP1, 3,
+/* 0x6X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x7X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x8X */ 5, 5, 5, 5, 5, 5, 4, IIP1, 5, 5, 5, 5, 5, IIP1, 4, IIP1,
+/* 0x9X */ 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 7, 7, IIP1, 6, 6,
+/* 0xAX */ 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 7, 7, IIP1, 6, 6,
+/* 0xBX */ 8, 8, 8, 8, 8, 8, 7, 7, 8, 8, 8, 8, 8, IIP1, 7, 7,
+/* 0xCX */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 4, IIP1,
+/* 0xDX */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 8, 8, 6, 6,
+/* 0xEX */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 8, 8, 6, 6,
+/* 0xFX */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 9, 9, 7, 7
+};
+
+static UINT8 ccounts_page01_na[256] = /* Cycle Counts Page 01, Native 6309 */
+{
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7, 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+/* 0x0X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x1X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x2X */ IIP1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+/* 0x3X */ 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, IIP1, IIP1, IIP1, 22,
+/* 0x4X */ 1, IIP1, IIP1, 1, 1, IIP1, 1, 1, 1, 1, 1, IIP1, 1, 1, IIP1, 1,
+/* 0x5X */ IIP1, IIP1, IIP1, 2, 2, IIP1, 2, IIP1, IIP1, 2, 2, IIP1, 2, 2, IIP1, 1,
+/* 0x6X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x7X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x8X */ 4, 4, 4, 4, 4, 4, 4, IIP1, 4, 4, 4, 4, 4, IIP1, 4, IIP1,
+/* 0x9X */ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, IIP1, 5, 5,
+/* 0xAX */ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, IIP1, 6, 6,
+/* 0xBX */ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, IIP1, 6, 6,
+/* 0xCX */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 4, IIP1,
+/* 0xDX */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 7, 7, 5, 5,
+/* 0xEX */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 8, 8, 6, 6,
+/* 0xFX */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 8, 8, 6, 6
+};
+
+static UINT8 ccounts_page11_em[256] = /* Cycle Counts Page 11, Emulated 6809 */
+{
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7, 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+/* 0x0X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x1X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x2X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x3X */ 7, 7, 7, 7, 7, 7, 7, 8, 3, 3, 3, 3, 4, 5, IIP1, 20,
+/* 0x4X */ IIP1, IIP1, IIP1, 2, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 2, IIP1, 2, 2, IIP1, 2,
+/* 0x5X */ IIP1, IIP1, IIP1, 2, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 2, IIP1, 2, 2, IIP1, 2,
+/* 0x6X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x7X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x8X */ 3, 3, IIP1, 5, IIP1, IIP1, 3, IIP1, IIP1, IIP1, IIP1, 3, 5, 25, 34, 28,
+/* 0x9X */ 5, 5, IIP1, 7, IIP1, IIP1, 5, 5, IIP1, IIP1, IIP1, 5, 7, 27, 36, 30,
+/* 0xAX */ 5, 5, IIP1, 7, IIP1, IIP1, 5, 5, IIP1, IIP1, IIP1, 5, 7, 27, 36, 30,
+/* 0xBX */ 6, 6, IIP1, 8, IIP1, IIP1, 6, 6, IIP1, IIP1, IIP1, 6, 8, 28, 37, 31,
+/* 0xCX */ 3, 3, IIP1, IIP1, IIP1, IIP1, 3, IIP1, IIP1, IIP1, IIP1, 3, IIP1, IIP1, IIP1, IIP1,
+/* 0xDX */ 5, 5, IIP1, IIP1, IIP1, IIP1, 5, 5, IIP1, IIP1, IIP1, 5, IIP1, IIP1, IIP1, IIP1,
+/* 0xEX */ 5, 5, IIP1, IIP1, IIP1, IIP1, 5, 5, IIP1, IIP1, IIP1, 5, IIP1, IIP1, IIP1, IIP1,
+/* 0xFX */ 6, 6, IIP1, IIP1, IIP1, IIP1, 6, 6, IIP1, IIP1, IIP1, 6, IIP1, IIP1, IIP1, IIP1
+};
+
+static UINT8 ccounts_page11_na[256] = /* Cycle Counts Page 11, Native 6309 */
+{
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7, 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+/* 0x0X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x1X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x2X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x3X */ 6, 6, 6, 6, 6, 6, 6, 7, 3, 3, 3, 3, 4, 5, IIP1, 22,
+/* 0x4X */ IIP1, IIP1, IIP1, 2, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 2, IIP1, 2, 2, IIP1, 2,
+/* 0x5X */ IIP1, IIP1, IIP1, 2, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, 2, IIP1, 2, 2, IIP1, 2,
+/* 0x6X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x7X */ IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1, IIP1,
+/* 0x8X */ 3, 3, IIP1, 4, IIP1, IIP1, 3, IIP1, IIP1, IIP1, IIP1, 3, 4, 25, 34, 28,
+/* 0x9X */ 4, 4, IIP1, 5, IIP1, IIP1, 4, 4, IIP1, IIP1, IIP1, 4, 5, 26, 35, 29,
+/* 0xAX */ 5, 5, IIP1, 6, IIP1, IIP1, 5, 5, IIP1, IIP1, IIP1, 5, 6, 27, 36, 30,
+/* 0xBX */ 5, 5, IIP1, 6, IIP1, IIP1, 5, 5, IIP1, IIP1, IIP1, 5, 6, 27, 36, 30,
+/* 0xCX */ 3, 3, IIP1, IIP1, IIP1, IIP1, 3, IIP1, IIP1, IIP1, IIP1, 3, IIP1, IIP1, IIP1, IIP1,
+/* 0xDX */ 4, 4, IIP1, IIP1, IIP1, IIP1, 4, 4, IIP1, IIP1, IIP1, 4, IIP1, IIP1, IIP1, IIP1,
+/* 0xEX */ 5, 5, IIP1, IIP1, IIP1, IIP1, 5, 5, IIP1, IIP1, IIP1, 5, IIP1, IIP1, IIP1, IIP1,
+/* 0xFX */ 5, 5, IIP1, IIP1, IIP1, IIP1, 5, 5, IIP1, IIP1, IIP1, 5, IIP1, IIP1, IIP1, IIP1
+};
+
+#ifndef BIG_SWITCH
+
+static void (*hd6309_main[0x100])(void) = {
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7,
+ 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+
+/* 0x0X */ neg_di, oim_di, aim_di, com_di, lsr_di, eim_di, ror_di, asr_di,
+ asl_di, rol_di, dec_di, tim_di, inc_di, tst_di, jmp_di, clr_di,
+
+/* 0x1X */ pref10, pref11, nop, sync, sexw, IIError, lbra, lbsr,
+ IIError, daa, orcc, IIError, andcc, sex, exg, tfr,
+
+/* 0x2X */ bra, brn, bhi, bls, bcc, bcs, bne, beq,
+ bvc, bvs, bpl, bmi, bge, blt, bgt, ble,
+
+/* 0x3X */ leax, leay, leas, leau, pshs, puls, pshu, pulu,
+ IIError, rts, abx, rti, cwai, mul, IIError, swi,
+
+/* 0x4X */ nega, IIError, IIError, coma, lsra, IIError, rora, asra,
+ asla, rola, deca, IIError, inca, tsta, IIError, clra,
+
+/* 0x5X */ negb, IIError, IIError, comb, lsrb, IIError, rorb, asrb,
+ aslb, rolb, decb, IIError, incb, tstb, IIError, clrb,
+
+/* 0x6X */ neg_ix, oim_ix, aim_ix, com_ix, lsr_ix, eim_ix, ror_ix, asr_ix,
+ asl_ix, rol_ix, dec_ix, tim_ix, inc_ix, tst_ix, jmp_ix, clr_ix,
+
+/* 0x7X */ neg_ex, oim_ex, aim_ex, com_ex, lsr_ex, eim_ex, ror_ex, asr_ex,
+ asl_ex, rol_ex, dec_ex, tim_ex, inc_ex, tst_ex, jmp_ex, clr_ex,
+
+/* 0x8X */ suba_im, cmpa_im, sbca_im, subd_im, anda_im, bita_im, lda_im, IIError,
+ eora_im, adca_im, ora_im, adda_im, cmpx_im, bsr, ldx_im, IIError,
+
+/* 0x9X */ suba_di, cmpa_di, sbca_di, subd_di, anda_di, bita_di, lda_di, sta_di,
+ eora_di, adca_di, ora_di, adda_di, cmpx_di, jsr_di, ldx_di, stx_di,
+
+/* 0xAX */ suba_ix, cmpa_ix, sbca_ix, subd_ix, anda_ix, bita_ix, lda_ix, sta_ix,
+ eora_ix, adca_ix, ora_ix, adda_ix, cmpx_ix, jsr_ix, ldx_ix, stx_ix,
+
+/* 0xBX */ suba_ex, cmpa_ex, sbca_ex, subd_ex, anda_ex, bita_ex, lda_ex, sta_ex,
+ eora_ex, adca_ex, ora_ex, adda_ex, cmpx_ex, jsr_ex, ldx_ex, stx_ex,
+
+/* 0xCX */ subb_im, cmpb_im, sbcb_im, addd_im, andb_im, bitb_im, ldb_im, IIError,
+ eorb_im, adcb_im, orb_im, addb_im, ldd_im, ldq_im, ldu_im, IIError,
+
+/* 0xDX */ subb_di, cmpb_di, sbcb_di, addd_di, andb_di, bitb_di, ldb_di, stb_di,
+ eorb_di, adcb_di, orb_di, addb_di, ldd_di, std_di, ldu_di, stu_di,
+
+/* 0xEX */ subb_ix, cmpb_ix, sbcb_ix, addd_ix, andb_ix, bitb_ix, ldb_ix, stb_ix,
+ eorb_ix, adcb_ix, orb_ix, addb_ix, ldd_ix, std_ix, ldu_ix, stu_ix,
+
+/* 0xFX */ subb_ex, cmpb_ex, sbcb_ex, addd_ex, andb_ex, bitb_ex, ldb_ex, stb_ex,
+ eorb_ex, adcb_ex, orb_ex, addb_ex, ldd_ex, std_ex, ldu_ex, stu_ex
+};
+
+static void (*hd6309_page01[0x100])(void) = {
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7,
+ 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+
+/* 0x0X */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+
+/* 0x1X */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+
+/* 0x2X */ IIError, lbrn, lbhi, lbls, lbcc, lbcs, lbne, lbeq,
+ lbvc, lbvs, lbpl, lbmi, lbge, lblt, lbgt, lble,
+
+/* 0x3X */ addr_r, adcr, subr, sbcr, andr, orr, eorr, cmpr,
+ pshsw, pulsw, pshuw, puluw, IIError, IIError, IIError, swi2,
+
+/* 0x4X */ negd, IIError, IIError, comd, lsrd, IIError, rord, asrd,
+ asld, rold, decd, IIError, incd, tstd, IIError, clrd,
+
+/* 0x5X */ IIError, IIError, IIError, comw, lsrw, IIError, rorw, IIError,
+ IIError, rolw, decw, IIError, incw, tstw, IIError, clrw,
+
+/* 0x6X */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+
+/* 0x7X */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+
+/* 0x8X */ subw_im, cmpw_im, sbcd_im, cmpd_im, andd_im, bitd_im, ldw_im, IIError,
+ eord_im, adcd_im, ord_im, addw_im, cmpy_im, IIError, ldy_im, IIError,
+
+/* 0x9X */ subw_di, cmpw_di, sbcd_di, cmpd_di, andd_di, bitd_di, ldw_di, stw_di,
+ eord_di, adcd_di, ord_di, addw_di, cmpy_di, IIError, ldy_di, sty_di,
+
+/* 0xAX */ subw_ix, cmpw_ix, sbcd_ix, cmpd_ix, andd_ix, bitd_ix, ldw_ix, stw_ix,
+ eord_ix, adcd_ix, ord_ix, addw_ix, cmpy_ix, IIError, ldy_ix, sty_ix,
+
+/* 0xBX */ subw_ex, cmpw_ex, sbcd_ex, cmpd_ex, andd_ex, bitd_ex, ldw_ex, stw_ex,
+ eord_ex, adcd_ex, ord_ex, addw_ex, cmpy_ex, IIError, ldy_ex, sty_ex,
+
+/* 0xCX */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, lds_im, IIError,
+
+/* 0xDX */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, ldq_di, stq_di, lds_di, sts_di,
+
+/* 0xEX */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, ldq_ix, stq_ix, lds_ix, sts_ix,
+
+/* 0xFX */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, ldq_ex, stq_ex, lds_ex, sts_ex
+};
+static void (*hd6309_page11[0x100])(void) = {
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7,
+ 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+
+/* 0x0X */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+
+/* 0x1X */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+
+/* 0x2X */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+
+/* 0x3X */ band, biand, bor, bior, beor, bieor, ldbt, stbt,
+ tfmpp, tfmmm, tfmpc, tfmcp, bitmd_im,ldmd_im, IIError, swi3,
+
+/* 0x4X */ IIError, IIError, IIError, come, IIError, IIError, IIError, IIError,
+ IIError, IIError, dece, IIError, ince, tste, IIError, clre,
+
+/* 0x5X */ IIError, IIError, IIError, comf, IIError, IIError, IIError, IIError,
+ IIError, IIError, decf, IIError, incf, tstf, IIError, clrf,
+
+/* 0x6X */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+
+/* 0x7X */ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+ IIError, IIError, IIError, IIError, IIError, IIError, IIError, IIError,
+
+/* 0x8X */ sube_im, cmpe_im, IIError, cmpu_im, IIError, IIError, lde_im, IIError,
+ IIError, IIError, IIError, adde_im, cmps_im, divd_im, divq_im, muld_im,
+
+/* 0x9X */ sube_di, cmpe_di, IIError, cmpu_di, IIError, IIError, lde_di, ste_di,
+ IIError, IIError, IIError, adde_di, cmps_di, divd_di, divq_di, muld_di,
+
+/* 0xAX */ sube_ix, cmpe_ix, IIError, cmpu_ix, IIError, IIError, lde_ix, ste_ix,
+ IIError, IIError, IIError, adde_ix, cmps_ix, divd_ix, divq_ix, muld_ix,
+
+/* 0xBX */ sube_ex, cmpe_ex, IIError, cmpu_ex, IIError, IIError, lde_ex, ste_ex,
+ IIError, IIError, IIError, adde_ex, cmps_ex, divd_ex, divq_ex, muld_ex,
+
+/* 0xCX */ subf_im, cmpf_im, IIError, IIError, IIError, IIError, ldf_im, IIError,
+ IIError, IIError, IIError, addf_im, IIError, IIError, IIError, IIError,
+
+/* 0xDX */ subf_di, cmpf_di, IIError, IIError, IIError, IIError, ldf_di, stf_di,
+ IIError, IIError, IIError, addf_di, IIError, IIError, IIError, IIError,
+
+/* 0xEX */ subf_ix, cmpf_ix, IIError, IIError, IIError, IIError, ldf_ix, stf_ix,
+ IIError, IIError, IIError, addf_ix, IIError, IIError, IIError, IIError,
+
+/* 0xFX */ subf_ex, cmpf_ex, IIError, IIError, IIError, IIError, ldf_ex, stf_ex,
+ IIError, IIError, IIError, addf_ex, IIError, IIError, IIError, IIError
+
+};
+
+#endif /* BIG_SWITCH */
diff --git a/src/emu/cpu/hd6309/hd6309.c b/src/emu/cpu/hd6309/hd6309.c
new file mode 100644
index 00000000000..97bc972fbf2
--- /dev/null
+++ b/src/emu/cpu/hd6309/hd6309.c
@@ -0,0 +1,1340 @@
+/*** hd6309: Portable 6309 emulator ******************************************
+
+ Copyright (C) John Butler 1997
+ Copyright (C) Tim Lindner 2000
+
+ References:
+
+ HD63B09EP Technical Refrence Guide, by Chet Simpson with addition
+ by Alan Dekok
+ 6809 Simulator V09, By L.C. Benschop, Eidnhoven The Netherlands.
+
+ m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from
+ the 6809 Simulator V09)
+
+ 6809 Microcomputer Programming & Interfacing with Experiments"
+ by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc.
+
+ System dependencies: UINT16 must be 16 bit unsigned int
+ UINT8 must be 8 bit unsigned int
+ UINT32 must be more than 16 bits
+ arrays up to 65536 bytes must be supported
+ machine must be twos complement
+
+ History:
+070614 ZV:
+ Fixed N flag setting in DIV overflow
+
+991026 HJB:
+ Fixed missing calls to cpu_changepc() for the TFR and EXG ocpodes.
+ Replaced m6809_slapstic checks by a macro (CHANGE_PC). ESB still
+ needs the tweaks.
+
+991024 HJB:
+ Tried to improve speed: Using bit7 of cycles1/2 as flag for multi
+ byte opcodes is gone, those opcodes now call fetch_effective_address().
+ Got rid of the slow/fast flags for stack (S and U) memory accesses.
+ Minor changes to use 32 bit values as arguments to memory functions
+ and added defines for that purpose (e.g. X = 16bit XD = 32bit).
+
+990312 HJB:
+ Added bugfixes according to Aaron's findings.
+ Reset only sets CC_II and CC_IF, DP to zero and PC from reset vector.
+990311 HJB:
+ Added _info functions. Now uses static m6808_Regs struct instead
+ of single statics. Changed the 16 bit registers to use the generic
+ PAIR union. Registers defined using macros. Split the core into
+ four execution loops for M6802, M6803, M6808 and HD63701.
+ TST, TSTA and TSTB opcodes reset carry flag.
+ Modified the read/write stack handlers to push LSB first then MSB
+ and pull MSB first then LSB.
+
+990228 HJB:
+ Changed the interrupt handling again. Now interrupts are taken
+ either right at the moment the lines are asserted or whenever
+ an interrupt is enabled and the corresponding line is still
+ asserted. That way the pending_interrupts checks are not
+ needed anymore. However, the CWAI and SYNC flags still need
+ some flags, so I changed the name to 'int_state'.
+ This core also has the code for the old interrupt system removed.
+
+990225 HJB:
+ Cleaned up the code here and there, added some comments.
+ Slightly changed the SAR opcodes (similiar to other CPU cores).
+ Added symbolic names for the flag bits.
+ Changed the way CWAI/Interrupt() handle CPU state saving.
+ A new flag M6809_STATE in pending_interrupts is used to determine
+ if a state save is needed on interrupt entry or already done by CWAI.
+ Added M6809_IRQ_LINE and M6809_FIRQ_LINE defines to m6809.h
+ Moved the internal interrupt_pending flags from m6809.h to m6809.c
+ Changed CWAI cycles2[0x3c] to be 2 (plus all or at least 19 if
+ CWAI actually pushes the entire state).
+ Implemented undocumented TFR/EXG for undefined source and mixed 8/16
+ bit transfers (they should transfer/exchange the constant $ff).
+ Removed unused jmp/jsr _slap functions from 6809ops.c,
+ m6809_slapstick check moved into the opcode functions.
+
+000809 TJL:
+ Started converting m6809 into hd6309
+
+001217 TJL:
+ Finished:
+ All opcodes
+ Dual Timing
+ To Do:
+ Verify new DIV opcodes.
+
+070805 TJL:
+ Fixed ADDR and ADCR opcodes not to clear the H condition code. Fixed ANDR,
+ EORR, ORR, ADDR, ADCR, SBCR, and SUBR to evaluate condition codes after
+ the destination register was set. Fixed BITMD opcode to only effect the Z
+ condition code. Fixed BITMD opcode to clear only tested flags. Fixed EXG
+ and TFR register promotion and demotion. Fixed illegal instruction handler
+ to not set I and F condition codes. Credit to Darren Atkinson for the
+ discovery of these bugs.
+
+090907 TJL:
+ The SEXW instruction is clearing the Overflow flag (V). It should not do
+ that. When an invalid source or destination register is specified for
+ the TFM instructions, real hardware invokes the Illegal Instruction
+ trap, whereas the emulator simply ignores the instruction. Credit to
+ Darren Atkinson for the discovery of these bugs.
+
+*****************************************************************************/
+
+#include "debugger.h"
+#include "hd6309.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+#ifndef true
+#define true 1
+#endif
+
+#ifndef false
+#define false 0
+#endif
+
+#ifdef MAME_DEBUG
+extern offs_t hd6309_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+/*#define BIG_SWITCH*/
+
+static void CHECK_IRQ_LINES( void );
+static void IIError(void);
+static void DZError(void);
+
+INLINE void fetch_effective_address( void );
+
+/* 6309 Registers */
+typedef struct
+{
+ PAIR pc; /* Program counter */
+ PAIR ppc; /* Previous program counter */
+ PAIR d,w; /* Accumlator d and w (ab = d, ef = w, abef = q) */
+ PAIR dp; /* Direct Page register (page in MSB) */
+ PAIR u, s; /* Stack pointers */
+ PAIR x, y; /* Index registers */
+ PAIR v; /* New 6309 register */
+ UINT8 cc;
+ UINT8 md; /* Special mode register */
+ UINT8 ireg; /* First opcode */
+ UINT8 irq_state[2];
+ int extra_cycles; /* cycles used up by interrupts */
+ int (*irq_callback)(int irqline);
+ UINT8 int_state; /* SYNC and CWAI flags */
+ UINT8 nmi_state;
+} hd6309_Regs;
+
+/* flag bits in the cc register */
+#define CC_C 0x01 /* Carry */
+#define CC_V 0x02 /* Overflow */
+#define CC_Z 0x04 /* Zero */
+#define CC_N 0x08 /* Negative */
+#define CC_II 0x10 /* Inhibit IRQ */
+#define CC_H 0x20 /* Half (auxiliary) carry */
+#define CC_IF 0x40 /* Inhibit FIRQ */
+#define CC_E 0x80 /* entire state pushed */
+
+/* flag bits in the md register */
+#define MD_EM 0x01 /* Execution mode */
+#define MD_FM 0x02 /* FIRQ mode */
+#define MD_II 0x40 /* Illegal instruction */
+#define MD_DZ 0x80 /* Division by zero */
+
+/* 6309 registers */
+static hd6309_Regs hd6309;
+int hd6309_slapstic = 0;
+
+#define pPPC hd6309.ppc
+#define pPC hd6309.pc
+#define pU hd6309.u
+#define pS hd6309.s
+#define pX hd6309.x
+#define pY hd6309.y
+#define pV hd6309.v
+/*#define pQ hd6309.q*/
+#define pD hd6309.d
+#define pW hd6309.w
+#define pZ hd6309.z
+
+#define PPC hd6309.ppc.w.l
+#define PC hd6309.pc.w.l
+#define PCD hd6309.pc.d
+#define U hd6309.u.w.l
+#define UD hd6309.u.d
+#define S hd6309.s.w.l
+#define SD hd6309.s.d
+#define X hd6309.x.w.l
+#define XD hd6309.x.d
+#define Y hd6309.y.w.l
+#define YD hd6309.y.d
+#define V hd6309.v.w.l
+#define VD hd6309.v.d
+#define D hd6309.d.w.l
+#define A hd6309.d.b.h
+#define B hd6309.d.b.l
+#define W hd6309.w.w.l
+#define E hd6309.w.b.h
+#define F hd6309.w.b.l
+#define DP hd6309.dp.b.h
+#define DPD hd6309.dp.d
+#define CC hd6309.cc
+#define MD hd6309.md
+
+static PAIR ea; /* effective address */
+#define EA ea.w.l
+#define EAD ea.d
+
+#define CHANGE_PC change_pc(PCD)
+#if 0
+#define CHANGE_PC { \
+ if( hd6309_slapstic ) \
+ cpu_setOPbase16(PCD); \
+ else \
+ change_pc(PCD); \
+ }
+#endif
+
+#define HD6309_CWAI 8 /* set when CWAI is waiting for an interrupt */
+#define HD6309_SYNC 16 /* set when SYNC is waiting for an interrupt */
+#define HD6309_LDS 32 /* set when LDS occured at least once */
+
+/* public globals */
+static int hd6309_ICount;
+
+/* these are re-defined in hd6309.h TO RAM, ROM or functions in cpuintrf.c */
+#define RM(mAddr) HD6309_RDMEM(mAddr)
+#define WM(mAddr,Value) HD6309_WRMEM(mAddr,Value)
+#define ROP(mAddr) HD6309_RDOP(mAddr)
+#define ROP_ARG(mAddr) HD6309_RDOP_ARG(mAddr)
+
+/* macros to access memory */
+#define IMMBYTE(b) b = ROP_ARG(PCD); PC++
+#define IMMWORD(w) w.d = (ROP_ARG(PCD)<<8) | ROP_ARG((PCD+1)&0xffff); PC+=2
+#define IMMLONG(w) w.d = (ROP_ARG(PCD)<<24) + (ROP_ARG(PCD+1)<<16) + (ROP_ARG(PCD+2)<<8) + (ROP_ARG(PCD+3)); PC+=4
+
+#define PUSHBYTE(b) --S; WM(SD,b)
+#define PUSHWORD(w) --S; WM(SD,w.b.l); --S; WM(SD,w.b.h)
+#define PULLBYTE(b) b = RM(SD); S++
+#define PULLWORD(w) w = RM(SD)<<8; S++; w |= RM(SD); S++
+
+#define PSHUBYTE(b) --U; WM(UD,b);
+#define PSHUWORD(w) --U; WM(UD,w.b.l); --U; WM(UD,w.b.h)
+#define PULUBYTE(b) b = RM(UD); U++
+#define PULUWORD(w) w = RM(UD)<<8; U++; w |= RM(UD); U++
+
+#define CLR_HNZVC CC&=~(CC_H|CC_N|CC_Z|CC_V|CC_C)
+#define CLR_NZV CC&=~(CC_N|CC_Z|CC_V)
+#define CLR_NZ CC&=~(CC_N|CC_Z)
+#define CLR_HNZC CC&=~(CC_H|CC_N|CC_Z|CC_C)
+#define CLR_NZVC CC&=~(CC_N|CC_Z|CC_V|CC_C)
+#define CLR_Z CC&=~(CC_Z)
+#define CLR_N CC&=~(CC_N)
+#define CLR_NZC CC&=~(CC_N|CC_Z|CC_C)
+#define CLR_ZC CC&=~(CC_Z|CC_C)
+
+/* macros for CC -- CC bits affected should be reset before calling */
+#define SET_Z(a) if(!a)SEZ
+#define SET_Z8(a) SET_Z((UINT8)a)
+#define SET_Z16(a) SET_Z((UINT16)a)
+#define SET_N8(a) CC|=((a&0x80)>>4)
+#define SET_N16(a) CC|=((a&0x8000)>>12)
+#define SET_N32(a) CC|=((a&0x8000)>>20)
+#define SET_H(a,b,r) CC|=(((a^b^r)&0x10)<<1)
+#define SET_C8(a) CC|=((a&0x100)>>8)
+#define SET_C16(a) CC|=((a&0x10000)>>16)
+#define SET_V8(a,b,r) CC|=(((a^b^r^(r>>1))&0x80)>>6)
+#define SET_V16(a,b,r) CC|=(((a^b^r^(r>>1))&0x8000)>>14)
+
+#define SET_FLAGS8I(a) {CC|=flags8i[(a)&0xff];}
+#define SET_FLAGS8D(a) {CC|=flags8d[(a)&0xff];}
+
+static UINT8 *cycle_counts_page0;
+static UINT8 *cycle_counts_page01;
+static UINT8 *cycle_counts_page11;
+static UINT8 *index_cycle;
+
+/* combos */
+#define SET_NZ8(a) {SET_N8(a);SET_Z(a);}
+#define SET_NZ16(a) {SET_N16(a);SET_Z(a);}
+#define SET_FLAGS8(a,b,r) {SET_N8(r);SET_Z8(r);SET_V8(a,b,r);SET_C8(r);}
+#define SET_FLAGS16(a,b,r) {SET_N16(r);SET_Z16(r);SET_V16(a,b,r);SET_C16(r);}
+
+#define NXORV ((CC&CC_N)^((CC&CC_V)<<2))
+
+/* for treating an unsigned byte as a signed word */
+#define SIGNED(b) ((UINT16)(b&0x80?b|0xff00:b))
+/* for treating an unsigned short as a signed long */
+#define SIGNED_16(b) ((UINT32)(b&0x8000?b|0xffff0000:b))
+
+/* macros for addressing modes (postbytes have their own code) */
+#define DIRECT EAD = DPD; IMMBYTE(ea.b.l)
+#define IMM8 EAD = PCD; PC++
+#define IMM16 EAD = PCD; PC+=2
+#define EXTENDED IMMWORD(ea)
+
+/* macros to set status flags */
+#define SEC CC|=CC_C
+#define CLC CC&=~CC_C
+#define SEZ CC|=CC_Z
+#define CLZ CC&=~CC_Z
+#define SEN CC|=CC_N
+#define CLN CC&=~CC_N
+#define SEV CC|=CC_V
+#define CLV CC&=~CC_V
+#define SEH CC|=CC_H
+#define CLH CC&=~CC_H
+
+/* Macros to set mode flags */
+#define SEDZ MD|=MD_DZ
+#define CLDZ MD&=~MD_DZ
+#define SEII MD|=MD_II
+#define CLII MD&=~MD_II
+#define SEFM MD|=MD_FM
+#define CLFM MD&=~MD_FM
+#define SEEM MD|=MD_EM
+#define CLEM MD&=~MD_EM
+
+/* macros for convenience */
+#define DIRBYTE(b) {DIRECT;b=RM(EAD);}
+#define DIRWORD(w) {DIRECT;w.d=RM16(EAD);}
+#define DIRLONG(lng) {DIRECT;lng.w.h=RM16(EAD);lng.w.l=RM16(EAD+2);}
+#define EXTBYTE(b) {EXTENDED;b=RM(EAD);}
+#define EXTWORD(w) {EXTENDED;w.d=RM16(EAD);}
+#define EXTLONG(lng) {EXTENDED;lng.w.h=RM16(EAD);lng.w.l=RM16(EAD+2);}
+
+/* includes the static function prototypes and other tables */
+#include "6309tbl.c"
+
+/* macros for branch instructions */
+#define BRANCH(f) { \
+ UINT8 t; \
+ IMMBYTE(t); \
+ if( f ) \
+ { \
+ PC += SIGNED(t); \
+ CHANGE_PC; \
+ } \
+}
+
+#define LBRANCH(f) { \
+ PAIR t; \
+ IMMWORD(t); \
+ if( f ) \
+ { \
+ if( !(MD & MD_EM) ) \
+ hd6309_ICount -= 1; \
+ PC += t.w.l; \
+ CHANGE_PC; \
+ } \
+}
+
+INLINE UINT32 RM16( UINT32 mAddr );
+INLINE UINT32 RM16( UINT32 mAddr )
+{
+ UINT32 result = RM(mAddr) << 8;
+ return result | RM((mAddr+1)&0xffff);
+}
+
+INLINE UINT32 RM32( UINT32 mAddr );
+INLINE UINT32 RM32( UINT32 mAddr )
+{
+ UINT32 result = RM(mAddr) << 24;
+ result += RM(mAddr+1) << 16;
+ result += RM(mAddr+2) << 8;
+ result += RM(mAddr+3);
+ return result;
+}
+
+INLINE void WM16( UINT32 mAddr, PAIR *p );
+INLINE void WM16( UINT32 mAddr, PAIR *p )
+{
+ WM( mAddr, p->b.h );
+ WM( (mAddr+1)&0xffff, p->b.l );
+}
+
+INLINE void WM32( UINT32 mAddr, PAIR *p );
+INLINE void WM32( UINT32 mAddr, PAIR *p )
+{
+ WM( mAddr, p->b.h3 );
+ WM( (mAddr+1)&0xffff, p->b.h2 );
+ WM( (mAddr+2)&0xffff, p->b.h );
+ WM( (mAddr+3)&0xffff, p->b.l );
+}
+
+static void UpdateState( void )
+{
+ if ( hd6309.md & MD_EM )
+ {
+ cycle_counts_page0 = ccounts_page0_na;
+ cycle_counts_page01 = ccounts_page01_na;
+ cycle_counts_page11 = ccounts_page11_na;
+ index_cycle = index_cycle_na;
+ }
+ else
+ {
+ cycle_counts_page0 = ccounts_page0_em;
+ cycle_counts_page01 = ccounts_page01_em;
+ cycle_counts_page11 = ccounts_page11_em;
+ index_cycle = index_cycle_em;
+ }
+}
+
+static void CHECK_IRQ_LINES( void )
+{
+ if( hd6309.irq_state[HD6309_IRQ_LINE] != CLEAR_LINE ||
+ hd6309.irq_state[HD6309_FIRQ_LINE] != CLEAR_LINE )
+ hd6309.int_state &= ~HD6309_SYNC; /* clear SYNC flag */
+ if( hd6309.irq_state[HD6309_FIRQ_LINE]!=CLEAR_LINE && !(CC & CC_IF))
+ {
+ /* fast IRQ */
+ /* HJB 990225: state already saved by CWAI? */
+ if( hd6309.int_state & HD6309_CWAI )
+ {
+ hd6309.int_state &= ~HD6309_CWAI;
+ hd6309.extra_cycles += 7; /* subtract +7 cycles */
+ }
+ else
+ {
+ if ( MD & MD_FM )
+ {
+ CC |= CC_E; /* save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ if ( MD & MD_EM )
+ {
+ PUSHBYTE(F);
+ PUSHBYTE(E);
+ hd6309.extra_cycles += 2; /* subtract +2 cycles */
+ }
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ hd6309.extra_cycles += 19; /* subtract +19 cycles */
+ }
+ else
+ {
+ CC &= ~CC_E; /* save 'short' state */
+ PUSHWORD(pPC);
+ PUSHBYTE(CC);
+ hd6309.extra_cycles += 10; /* subtract +10 cycles */
+ }
+ }
+ CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */
+ PCD=RM16(0xfff6);
+ CHANGE_PC;
+ (void)(*hd6309.irq_callback)(HD6309_FIRQ_LINE);
+ }
+ else
+ if( hd6309.irq_state[HD6309_IRQ_LINE]!=CLEAR_LINE && !(CC & CC_II) )
+ {
+ /* standard IRQ */
+ /* HJB 990225: state already saved by CWAI? */
+ if( hd6309.int_state & HD6309_CWAI )
+ {
+ hd6309.int_state &= ~HD6309_CWAI; /* clear CWAI flag */
+ hd6309.extra_cycles += 7; /* subtract +7 cycles */
+ }
+ else
+ {
+ CC |= CC_E; /* save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ if ( MD & MD_EM )
+ {
+ PUSHBYTE(F);
+ PUSHBYTE(E);
+ hd6309.extra_cycles += 2; /* subtract +2 cycles */
+ }
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ hd6309.extra_cycles += 19; /* subtract +19 cycles */
+ }
+ CC |= CC_II; /* inhibit IRQ */
+ PCD=RM16(0xfff8);
+ CHANGE_PC;
+ (void)(*hd6309.irq_callback)(HD6309_IRQ_LINE);
+ }
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void hd6309_get_context(void *dst)
+{
+ if( dst )
+ *(hd6309_Regs*)dst = hd6309;
+}
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void hd6309_set_context(void *src)
+{
+ if( src )
+ hd6309 = *(hd6309_Regs*)src;
+ CHANGE_PC;
+
+ CHECK_IRQ_LINES();
+ UpdateState();
+}
+
+
+static void hd6309_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ hd6309.irq_callback = irqcallback;
+
+ state_save_register_item("hd6309", index, PC);
+ state_save_register_item("hd6309", index, U);
+ state_save_register_item("hd6309", index, S);
+ state_save_register_item("hd6309", index, X);
+ state_save_register_item("hd6309", index, Y);
+ state_save_register_item("hd6309", index, V);
+ state_save_register_item("hd6309", index, DP);
+ state_save_register_item("hd6309", index, CC);
+ state_save_register_item("hd6309", index, MD);
+ state_save_register_func_postload( UpdateState );
+ state_save_register_item("hd6309", index, hd6309.int_state);
+ state_save_register_item("hd6309", index, hd6309.nmi_state);
+ state_save_register_item("hd6309", index, hd6309.irq_state[0]);
+ state_save_register_item("hd6309", index, hd6309.irq_state[1]);
+}
+
+/****************************************************************************/
+/* Reset registers to their initial values */
+/****************************************************************************/
+static void hd6309_reset(void)
+{
+ hd6309.int_state = 0;
+ hd6309.nmi_state = CLEAR_LINE;
+ hd6309.irq_state[0] = CLEAR_LINE;
+ hd6309.irq_state[0] = CLEAR_LINE;
+
+ DPD = 0; /* Reset direct page register */
+
+ MD = 0; /* Mode register gets reset */
+ CC |= CC_II; /* IRQ disabled */
+ CC |= CC_IF; /* FIRQ disabled */
+
+ PCD = RM16(0xfffe);
+ CHANGE_PC;
+ UpdateState();
+}
+
+void hd6309_exit(void)
+{
+ /* nothing to do ? */
+}
+
+/* Generate interrupts */
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (hd6309.nmi_state == state) return;
+ hd6309.nmi_state = state;
+ LOG(("HD6309#%d set_irq_line (NMI) %d (PC=%4.4X)\n", cpu_getactivecpu(), state, pPC));
+ if( state == CLEAR_LINE ) return;
+
+ /* if the stack was not yet initialized */
+ if( !(hd6309.int_state & HD6309_LDS) ) return;
+
+ hd6309.int_state &= ~HD6309_SYNC;
+ /* HJB 990225: state already saved by CWAI? */
+ if( hd6309.int_state & HD6309_CWAI )
+ {
+ hd6309.int_state &= ~HD6309_CWAI;
+ hd6309.extra_cycles += 7; /* subtract +7 cycles next time */
+ }
+ else
+ {
+ CC |= CC_E; /* save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ if ( MD & MD_EM )
+ {
+ PUSHBYTE(F);
+ PUSHBYTE(E);
+ hd6309.extra_cycles += 2; /* subtract +2 cycles */
+ }
+
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ hd6309.extra_cycles += 19; /* subtract +19 cycles next time */
+ }
+ CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */
+ PCD = RM16(0xfffc);
+ CHANGE_PC;
+ }
+ else if (irqline < 2)
+ {
+ LOG(("HD6309#%d set_irq_line %d, %d (PC=%4.4X)\n", cpu_getactivecpu(), irqline, state, pPC));
+ hd6309.irq_state[irqline] = state;
+ if (state == CLEAR_LINE) return;
+ CHECK_IRQ_LINES();
+ }
+}
+
+/* includes the actual opcode implementations */
+#include "6309ops.c"
+
+/* execute instructions on this CPU until icount expires */
+static int hd6309_execute(int cycles) /* NS 970908 */
+{
+ hd6309_ICount = cycles - hd6309.extra_cycles;
+ hd6309.extra_cycles = 0;
+
+ if (hd6309.int_state & (HD6309_CWAI | HD6309_SYNC))
+ {
+ CALL_MAME_DEBUG;
+ hd6309_ICount = 0;
+ }
+ else
+ {
+ do
+ {
+ pPPC = pPC;
+
+ CALL_MAME_DEBUG;
+
+ hd6309.ireg = ROP(PCD);
+ PC++;
+
+#ifdef BIG_SWITCH
+ switch( hd6309.ireg )
+ {
+ case 0x00: neg_di(); break;
+ case 0x01: oim_di(); break;
+ case 0x02: aim_di(); break;
+ case 0x03: com_di(); break;
+ case 0x04: lsr_di(); break;
+ case 0x05: eim_di(); break;
+ case 0x06: ror_di(); break;
+ case 0x07: asr_di(); break;
+ case 0x08: asl_di(); break;
+ case 0x09: rol_di(); break;
+ case 0x0a: dec_di(); break;
+ case 0x0b: tim_di(); break;
+ case 0x0c: inc_di(); break;
+ case 0x0d: tst_di(); break;
+ case 0x0e: jmp_di(); break;
+ case 0x0f: clr_di(); break;
+ case 0x10: pref10(); break;
+ case 0x11: pref11(); break;
+ case 0x12: nop(); break;
+ case 0x13: sync(); break;
+ case 0x14: sexw(); break;
+ case 0x15: IIError(); break;
+ case 0x16: lbra(); break;
+ case 0x17: lbsr(); break;
+ case 0x18: IIError(); break;
+ case 0x19: daa(); break;
+ case 0x1a: orcc(); break;
+ case 0x1b: IIError(); break;
+ case 0x1c: andcc(); break;
+ case 0x1d: sex(); break;
+ case 0x1e: exg(); break;
+ case 0x1f: tfr(); break;
+ case 0x20: bra(); break;
+ case 0x21: brn(); break;
+ case 0x22: bhi(); break;
+ case 0x23: bls(); break;
+ case 0x24: bcc(); break;
+ case 0x25: bcs(); break;
+ case 0x26: bne(); break;
+ case 0x27: beq(); break;
+ case 0x28: bvc(); break;
+ case 0x29: bvs(); break;
+ case 0x2a: bpl(); break;
+ case 0x2b: bmi(); break;
+ case 0x2c: bge(); break;
+ case 0x2d: blt(); break;
+ case 0x2e: bgt(); break;
+ case 0x2f: ble(); break;
+ case 0x30: leax(); break;
+ case 0x31: leay(); break;
+ case 0x32: leas(); break;
+ case 0x33: leau(); break;
+ case 0x34: pshs(); break;
+ case 0x35: puls(); break;
+ case 0x36: pshu(); break;
+ case 0x37: pulu(); break;
+ case 0x38: IIError(); break;
+ case 0x39: rts(); break;
+ case 0x3a: abx(); break;
+ case 0x3b: rti(); break;
+ case 0x3c: cwai(); break;
+ case 0x3d: mul(); break;
+ case 0x3e: IIError(); break;
+ case 0x3f: swi(); break;
+ case 0x40: nega(); break;
+ case 0x41: IIError(); break;
+ case 0x42: IIError(); break;
+ case 0x43: coma(); break;
+ case 0x44: lsra(); break;
+ case 0x45: IIError(); break;
+ case 0x46: rora(); break;
+ case 0x47: asra(); break;
+ case 0x48: asla(); break;
+ case 0x49: rola(); break;
+ case 0x4a: deca(); break;
+ case 0x4b: IIError(); break;
+ case 0x4c: inca(); break;
+ case 0x4d: tsta(); break;
+ case 0x4e: IIError(); break;
+ case 0x4f: clra(); break;
+ case 0x50: negb(); break;
+ case 0x51: IIError(); break;
+ case 0x52: IIError(); break;
+ case 0x53: comb(); break;
+ case 0x54: lsrb(); break;
+ case 0x55: IIError(); break;
+ case 0x56: rorb(); break;
+ case 0x57: asrb(); break;
+ case 0x58: aslb(); break;
+ case 0x59: rolb(); break;
+ case 0x5a: decb(); break;
+ case 0x5b: IIError(); break;
+ case 0x5c: incb(); break;
+ case 0x5d: tstb(); break;
+ case 0x5e: IIError(); break;
+ case 0x5f: clrb(); break;
+ case 0x60: neg_ix(); break;
+ case 0x61: oim_ix(); break;
+ case 0x62: aim_ix(); break;
+ case 0x63: com_ix(); break;
+ case 0x64: lsr_ix(); break;
+ case 0x65: eim_ix(); break;
+ case 0x66: ror_ix(); break;
+ case 0x67: asr_ix(); break;
+ case 0x68: asl_ix(); break;
+ case 0x69: rol_ix(); break;
+ case 0x6a: dec_ix(); break;
+ case 0x6b: tim_ix(); break;
+ case 0x6c: inc_ix(); break;
+ case 0x6d: tst_ix(); break;
+ case 0x6e: jmp_ix(); break;
+ case 0x6f: clr_ix(); break;
+ case 0x70: neg_ex(); break;
+ case 0x71: oim_ex(); break;
+ case 0x72: aim_ex(); break;
+ case 0x73: com_ex(); break;
+ case 0x74: lsr_ex(); break;
+ case 0x75: eim_ex(); break;
+ case 0x76: ror_ex(); break;
+ case 0x77: asr_ex(); break;
+ case 0x78: asl_ex(); break;
+ case 0x79: rol_ex(); break;
+ case 0x7a: dec_ex(); break;
+ case 0x7b: tim_ex(); break;
+ case 0x7c: inc_ex(); break;
+ case 0x7d: tst_ex(); break;
+ case 0x7e: jmp_ex(); break;
+ case 0x7f: clr_ex(); break;
+ case 0x80: suba_im(); break;
+ case 0x81: cmpa_im(); break;
+ case 0x82: sbca_im(); break;
+ case 0x83: subd_im(); break;
+ case 0x84: anda_im(); break;
+ case 0x85: bita_im(); break;
+ case 0x86: lda_im(); break;
+ case 0x87: IIError(); break;
+ case 0x88: eora_im(); break;
+ case 0x89: adca_im(); break;
+ case 0x8a: ora_im(); break;
+ case 0x8b: adda_im(); break;
+ case 0x8c: cmpx_im(); break;
+ case 0x8d: bsr(); break;
+ case 0x8e: ldx_im(); break;
+ case 0x8f: IIError(); break;
+ case 0x90: suba_di(); break;
+ case 0x91: cmpa_di(); break;
+ case 0x92: sbca_di(); break;
+ case 0x93: subd_di(); break;
+ case 0x94: anda_di(); break;
+ case 0x95: bita_di(); break;
+ case 0x96: lda_di(); break;
+ case 0x97: sta_di(); break;
+ case 0x98: eora_di(); break;
+ case 0x99: adca_di(); break;
+ case 0x9a: ora_di(); break;
+ case 0x9b: adda_di(); break;
+ case 0x9c: cmpx_di(); break;
+ case 0x9d: jsr_di(); break;
+ case 0x9e: ldx_di(); break;
+ case 0x9f: stx_di(); break;
+ case 0xa0: suba_ix(); break;
+ case 0xa1: cmpa_ix(); break;
+ case 0xa2: sbca_ix(); break;
+ case 0xa3: subd_ix(); break;
+ case 0xa4: anda_ix(); break;
+ case 0xa5: bita_ix(); break;
+ case 0xa6: lda_ix(); break;
+ case 0xa7: sta_ix(); break;
+ case 0xa8: eora_ix(); break;
+ case 0xa9: adca_ix(); break;
+ case 0xaa: ora_ix(); break;
+ case 0xab: adda_ix(); break;
+ case 0xac: cmpx_ix(); break;
+ case 0xad: jsr_ix(); break;
+ case 0xae: ldx_ix(); break;
+ case 0xaf: stx_ix(); break;
+ case 0xb0: suba_ex(); break;
+ case 0xb1: cmpa_ex(); break;
+ case 0xb2: sbca_ex(); break;
+ case 0xb3: subd_ex(); break;
+ case 0xb4: anda_ex(); break;
+ case 0xb5: bita_ex(); break;
+ case 0xb6: lda_ex(); break;
+ case 0xb7: sta_ex(); break;
+ case 0xb8: eora_ex(); break;
+ case 0xb9: adca_ex(); break;
+ case 0xba: ora_ex(); break;
+ case 0xbb: adda_ex(); break;
+ case 0xbc: cmpx_ex(); break;
+ case 0xbd: jsr_ex(); break;
+ case 0xbe: ldx_ex(); break;
+ case 0xbf: stx_ex(); break;
+ case 0xc0: subb_im(); break;
+ case 0xc1: cmpb_im(); break;
+ case 0xc2: sbcb_im(); break;
+ case 0xc3: addd_im(); break;
+ case 0xc4: andb_im(); break;
+ case 0xc5: bitb_im(); break;
+ case 0xc6: ldb_im(); break;
+ case 0xc7: IIError(); break;
+ case 0xc8: eorb_im(); break;
+ case 0xc9: adcb_im(); break;
+ case 0xca: orb_im(); break;
+ case 0xcb: addb_im(); break;
+ case 0xcc: ldd_im(); break;
+ case 0xcd: ldq_im(); break; /* in m6809 was std_im */
+ case 0xce: ldu_im(); break;
+ case 0xcf: IIError(); break;
+ case 0xd0: subb_di(); break;
+ case 0xd1: cmpb_di(); break;
+ case 0xd2: sbcb_di(); break;
+ case 0xd3: addd_di(); break;
+ case 0xd4: andb_di(); break;
+ case 0xd5: bitb_di(); break;
+ case 0xd6: ldb_di(); break;
+ case 0xd7: stb_di(); break;
+ case 0xd8: eorb_di(); break;
+ case 0xd9: adcb_di(); break;
+ case 0xda: orb_di(); break;
+ case 0xdb: addb_di(); break;
+ case 0xdc: ldd_di(); break;
+ case 0xdd: std_di(); break;
+ case 0xde: ldu_di(); break;
+ case 0xdf: stu_di(); break;
+ case 0xe0: subb_ix(); break;
+ case 0xe1: cmpb_ix(); break;
+ case 0xe2: sbcb_ix(); break;
+ case 0xe3: addd_ix(); break;
+ case 0xe4: andb_ix(); break;
+ case 0xe5: bitb_ix(); break;
+ case 0xe6: ldb_ix(); break;
+ case 0xe7: stb_ix(); break;
+ case 0xe8: eorb_ix(); break;
+ case 0xe9: adcb_ix(); break;
+ case 0xea: orb_ix(); break;
+ case 0xeb: addb_ix(); break;
+ case 0xec: ldd_ix(); break;
+ case 0xed: std_ix(); break;
+ case 0xee: ldu_ix(); break;
+ case 0xef: stu_ix(); break;
+ case 0xf0: subb_ex(); break;
+ case 0xf1: cmpb_ex(); break;
+ case 0xf2: sbcb_ex(); break;
+ case 0xf3: addd_ex(); break;
+ case 0xf4: andb_ex(); break;
+ case 0xf5: bitb_ex(); break;
+ case 0xf6: ldb_ex(); break;
+ case 0xf7: stb_ex(); break;
+ case 0xf8: eorb_ex(); break;
+ case 0xf9: adcb_ex(); break;
+ case 0xfa: orb_ex(); break;
+ case 0xfb: addb_ex(); break;
+ case 0xfc: ldd_ex(); break;
+ case 0xfd: std_ex(); break;
+ case 0xfe: ldu_ex(); break;
+ case 0xff: stu_ex(); break;
+ }
+#else
+ (*hd6309_main[hd6309.ireg])();
+#endif /* BIG_SWITCH */
+
+ hd6309_ICount -= cycle_counts_page0[hd6309.ireg];
+
+ } while( hd6309_ICount > 0 );
+
+ hd6309_ICount -= hd6309.extra_cycles;
+ hd6309.extra_cycles = 0;
+ }
+
+ return cycles - hd6309_ICount; /* NS 970908 */
+}
+
+INLINE void fetch_effective_address( void )
+{
+ UINT8 postbyte = ROP_ARG(PCD);
+ PC++;
+
+ switch(postbyte)
+ {
+ case 0x00: EA=X; break;
+ case 0x01: EA=X+1; break;
+ case 0x02: EA=X+2; break;
+ case 0x03: EA=X+3; break;
+ case 0x04: EA=X+4; break;
+ case 0x05: EA=X+5; break;
+ case 0x06: EA=X+6; break;
+ case 0x07: EA=X+7; break;
+ case 0x08: EA=X+8; break;
+ case 0x09: EA=X+9; break;
+ case 0x0a: EA=X+10; break;
+ case 0x0b: EA=X+11; break;
+ case 0x0c: EA=X+12; break;
+ case 0x0d: EA=X+13; break;
+ case 0x0e: EA=X+14; break;
+ case 0x0f: EA=X+15; break;
+
+ case 0x10: EA=X-16; break;
+ case 0x11: EA=X-15; break;
+ case 0x12: EA=X-14; break;
+ case 0x13: EA=X-13; break;
+ case 0x14: EA=X-12; break;
+ case 0x15: EA=X-11; break;
+ case 0x16: EA=X-10; break;
+ case 0x17: EA=X-9; break;
+ case 0x18: EA=X-8; break;
+ case 0x19: EA=X-7; break;
+ case 0x1a: EA=X-6; break;
+ case 0x1b: EA=X-5; break;
+ case 0x1c: EA=X-4; break;
+ case 0x1d: EA=X-3; break;
+ case 0x1e: EA=X-2; break;
+ case 0x1f: EA=X-1; break;
+
+ case 0x20: EA=Y; break;
+ case 0x21: EA=Y+1; break;
+ case 0x22: EA=Y+2; break;
+ case 0x23: EA=Y+3; break;
+ case 0x24: EA=Y+4; break;
+ case 0x25: EA=Y+5; break;
+ case 0x26: EA=Y+6; break;
+ case 0x27: EA=Y+7; break;
+ case 0x28: EA=Y+8; break;
+ case 0x29: EA=Y+9; break;
+ case 0x2a: EA=Y+10; break;
+ case 0x2b: EA=Y+11; break;
+ case 0x2c: EA=Y+12; break;
+ case 0x2d: EA=Y+13; break;
+ case 0x2e: EA=Y+14; break;
+ case 0x2f: EA=Y+15; break;
+
+ case 0x30: EA=Y-16; break;
+ case 0x31: EA=Y-15; break;
+ case 0x32: EA=Y-14; break;
+ case 0x33: EA=Y-13; break;
+ case 0x34: EA=Y-12; break;
+ case 0x35: EA=Y-11; break;
+ case 0x36: EA=Y-10; break;
+ case 0x37: EA=Y-9; break;
+ case 0x38: EA=Y-8; break;
+ case 0x39: EA=Y-7; break;
+ case 0x3a: EA=Y-6; break;
+ case 0x3b: EA=Y-5; break;
+ case 0x3c: EA=Y-4; break;
+ case 0x3d: EA=Y-3; break;
+ case 0x3e: EA=Y-2; break;
+ case 0x3f: EA=Y-1; break;
+
+ case 0x40: EA=U; break;
+ case 0x41: EA=U+1; break;
+ case 0x42: EA=U+2; break;
+ case 0x43: EA=U+3; break;
+ case 0x44: EA=U+4; break;
+ case 0x45: EA=U+5; break;
+ case 0x46: EA=U+6; break;
+ case 0x47: EA=U+7; break;
+ case 0x48: EA=U+8; break;
+ case 0x49: EA=U+9; break;
+ case 0x4a: EA=U+10; break;
+ case 0x4b: EA=U+11; break;
+ case 0x4c: EA=U+12; break;
+ case 0x4d: EA=U+13; break;
+ case 0x4e: EA=U+14; break;
+ case 0x4f: EA=U+15; break;
+
+ case 0x50: EA=U-16; break;
+ case 0x51: EA=U-15; break;
+ case 0x52: EA=U-14; break;
+ case 0x53: EA=U-13; break;
+ case 0x54: EA=U-12; break;
+ case 0x55: EA=U-11; break;
+ case 0x56: EA=U-10; break;
+ case 0x57: EA=U-9; break;
+ case 0x58: EA=U-8; break;
+ case 0x59: EA=U-7; break;
+ case 0x5a: EA=U-6; break;
+ case 0x5b: EA=U-5; break;
+ case 0x5c: EA=U-4; break;
+ case 0x5d: EA=U-3; break;
+ case 0x5e: EA=U-2; break;
+ case 0x5f: EA=U-1; break;
+
+ case 0x60: EA=S; break;
+ case 0x61: EA=S+1; break;
+ case 0x62: EA=S+2; break;
+ case 0x63: EA=S+3; break;
+ case 0x64: EA=S+4; break;
+ case 0x65: EA=S+5; break;
+ case 0x66: EA=S+6; break;
+ case 0x67: EA=S+7; break;
+ case 0x68: EA=S+8; break;
+ case 0x69: EA=S+9; break;
+ case 0x6a: EA=S+10; break;
+ case 0x6b: EA=S+11; break;
+ case 0x6c: EA=S+12; break;
+ case 0x6d: EA=S+13; break;
+ case 0x6e: EA=S+14; break;
+ case 0x6f: EA=S+15; break;
+
+ case 0x70: EA=S-16; break;
+ case 0x71: EA=S-15; break;
+ case 0x72: EA=S-14; break;
+ case 0x73: EA=S-13; break;
+ case 0x74: EA=S-12; break;
+ case 0x75: EA=S-11; break;
+ case 0x76: EA=S-10; break;
+ case 0x77: EA=S-9; break;
+ case 0x78: EA=S-8; break;
+ case 0x79: EA=S-7; break;
+ case 0x7a: EA=S-6; break;
+ case 0x7b: EA=S-5; break;
+ case 0x7c: EA=S-4; break;
+ case 0x7d: EA=S-3; break;
+ case 0x7e: EA=S-2; break;
+ case 0x7f: EA=S-1; break;
+
+ case 0x80: EA=X; X++; break;
+ case 0x81: EA=X; X+=2; break;
+ case 0x82: X--; EA=X; break;
+ case 0x83: X-=2; EA=X; break;
+ case 0x84: EA=X; break;
+ case 0x85: EA=X+SIGNED(B); break;
+ case 0x86: EA=X+SIGNED(A); break;
+ case 0x87: EA=X+SIGNED(E); break;
+ case 0x88: IMMBYTE(EA); EA=X+SIGNED(EA); break;
+ case 0x89: IMMWORD(ea); EA+=X; break;
+ case 0x8a: EA=X+SIGNED(F); break;
+ case 0x8b: EA=X+D; break;
+ case 0x8c: IMMBYTE(EA); EA=PC+SIGNED(EA); break;
+ case 0x8d: IMMWORD(ea); EA+=PC; break;
+ case 0x8e: EA=X+W; break;
+ case 0x8f: EA=W; break;
+
+ case 0x90: EA=W; EAD=RM16(EAD); break;
+ case 0x91: EA=X; X+=2; EAD=RM16(EAD); break;
+ case 0x92: IIError(); break;
+ case 0x93: X-=2; EA=X; EAD=RM16(EAD); break;
+ case 0x94: EA=X; EAD=RM16(EAD); break;
+ case 0x95: EA=X+SIGNED(B); EAD=RM16(EAD); break;
+ case 0x96: EA=X+SIGNED(A); EAD=RM16(EAD); break;
+ case 0x97: EA=X+SIGNED(E); EAD=RM16(EAD); break;
+ case 0x98: IMMBYTE(EA); EA=X+SIGNED(EA); EAD=RM16(EAD); break;
+ case 0x99: IMMWORD(ea); EA+=X; EAD=RM16(EAD); break;
+ case 0x9a: EA=X+SIGNED(F); EAD=RM16(EAD); break;
+ case 0x9b: EA=X+D; EAD=RM16(EAD); break;
+ case 0x9c: IMMBYTE(EA); EA=PC+SIGNED(EA); EAD=RM16(EAD); break;
+ case 0x9d: IMMWORD(ea); EA+=PC; EAD=RM16(EAD); break;
+ case 0x9e: EA=X+W; EAD=RM16(EAD); break;
+ case 0x9f: IMMWORD(ea); EAD=RM16(EAD); break;
+
+ case 0xa0: EA=Y; Y++; break;
+ case 0xa1: EA=Y; Y+=2; break;
+ case 0xa2: Y--; EA=Y; break;
+ case 0xa3: Y-=2; EA=Y; break;
+ case 0xa4: EA=Y; break;
+ case 0xa5: EA=Y+SIGNED(B); break;
+ case 0xa6: EA=Y+SIGNED(A); break;
+ case 0xa7: EA=Y+SIGNED(E); break;
+ case 0xa8: IMMBYTE(EA); EA=Y+SIGNED(EA); break;
+ case 0xa9: IMMWORD(ea); EA+=Y; break;
+ case 0xaa: EA=Y+SIGNED(F); break;
+ case 0xab: EA=Y+D; break;
+ case 0xac: IMMBYTE(EA); EA=PC+SIGNED(EA); break;
+ case 0xad: IMMWORD(ea); EA+=PC; break;
+ case 0xae: EA=Y+W; break;
+ case 0xaf: IMMWORD(ea); EA+=W; break;
+
+ case 0xb0: IMMWORD(ea); EA+=W; EAD=RM16(EAD); break;
+ case 0xb1: EA=Y; Y+=2; EAD=RM16(EAD); break;
+ case 0xb2: IIError(); break;
+ case 0xb3: Y-=2; EA=Y; EAD=RM16(EAD); break;
+ case 0xb4: EA=Y; EAD=RM16(EAD); break;
+ case 0xb5: EA=Y+SIGNED(B); EAD=RM16(EAD); break;
+ case 0xb6: EA=Y+SIGNED(A); EAD=RM16(EAD); break;
+ case 0xb7: EA=Y+SIGNED(E); EAD=RM16(EAD); break;
+ case 0xb8: IMMBYTE(EA); EA=Y+SIGNED(EA); EAD=RM16(EAD); break;
+ case 0xb9: IMMWORD(ea); EA+=Y; EAD=RM16(EAD); break;
+ case 0xba: EA=Y+SIGNED(F); EAD=RM16(EAD); break;
+ case 0xbb: EA=Y+D; EAD=RM16(EAD); break;
+ case 0xbc: IMMBYTE(EA); EA=PC+SIGNED(EA); EAD=RM16(EAD); break;
+ case 0xbd: IMMWORD(ea); EA+=PC; EAD=RM16(EAD); break;
+ case 0xbe: EA=Y+W; EAD=RM16(EAD); break;
+ case 0xbf: IIError(); break;
+
+ case 0xc0: EA=U; U++; break;
+ case 0xc1: EA=U; U+=2; break;
+ case 0xc2: U--; EA=U; break;
+ case 0xc3: U-=2; EA=U; break;
+ case 0xc4: EA=U; break;
+ case 0xc5: EA=U+SIGNED(B); break;
+ case 0xc6: EA=U+SIGNED(A); break;
+ case 0xc7: EA=U+SIGNED(E); break;
+ case 0xc8: IMMBYTE(EA); EA=U+SIGNED(EA); break;
+ case 0xc9: IMMWORD(ea); EA+=U; break;
+ case 0xca: EA=U+SIGNED(F); break;
+ case 0xcb: EA=U+D; break;
+ case 0xcc: IMMBYTE(EA); EA=PC+SIGNED(EA); break;
+ case 0xcd: IMMWORD(ea); EA+=PC; break;
+ case 0xce: EA=U+W; break;
+ case 0xcf: EA=W; W+=2; break;
+
+ case 0xd0: EA=W; W+=2; EAD=RM16(EAD); break;
+ case 0xd1: EA=U; U+=2; EAD=RM16(EAD); break;
+ case 0xd2: IIError(); break;
+ case 0xd3: U-=2; EA=U; EAD=RM16(EAD); break;
+ case 0xd4: EA=U; EAD=RM16(EAD); break;
+ case 0xd5: EA=U+SIGNED(B); EAD=RM16(EAD); break;
+ case 0xd6: EA=U+SIGNED(A); EAD=RM16(EAD); break;
+ case 0xd7: EA=U+SIGNED(E); EAD=RM16(EAD); break;
+ case 0xd8: IMMBYTE(EA); EA=U+SIGNED(EA); EAD=RM16(EAD); break;
+ case 0xd9: IMMWORD(ea); EA+=U; EAD=RM16(EAD); break;
+ case 0xda: EA=U+SIGNED(F); EAD=RM16(EAD); break;
+ case 0xdb: EA=U+D; EAD=RM16(EAD); break;
+ case 0xdc: IMMBYTE(EA); EA=PC+SIGNED(EA); EAD=RM16(EAD); break;
+ case 0xdd: IMMWORD(ea); EA+=PC; EAD=RM16(EAD); break;
+ case 0xde: EA=U+W; EAD=RM16(EAD); break;
+ case 0xdf: IIError(); break;
+
+ case 0xe0: EA=S; S++; break;
+ case 0xe1: EA=S; S+=2; break;
+ case 0xe2: S--; EA=S; break;
+ case 0xe3: S-=2; EA=S; break;
+ case 0xe4: EA=S; break;
+ case 0xe5: EA=S+SIGNED(B); break;
+ case 0xe6: EA=S+SIGNED(A); break;
+ case 0xe7: EA=S+SIGNED(E); break;
+ case 0xe8: IMMBYTE(EA); EA=S+SIGNED(EA); break;
+ case 0xe9: IMMWORD(ea); EA+=S; break;
+ case 0xea: EA=S+SIGNED(F); break;
+ case 0xeb: EA=S+D; break;
+ case 0xec: IMMBYTE(EA); EA=PC+SIGNED(EA); break;
+ case 0xed: IMMWORD(ea); EA+=PC; break;
+ case 0xee: EA=S+W; break;
+ case 0xef: W-=2; EA=W; break;
+
+ case 0xf0: W-=2; EA=W; EAD=RM16(EAD); break;
+ case 0xf1: EA=S; S+=2; EAD=RM16(EAD); break;
+ case 0xf2: IIError(); break;
+ case 0xf3: S-=2; EA=S; EAD=RM16(EAD); break;
+ case 0xf4: EA=S; EAD=RM16(EAD); break;
+ case 0xf5: EA=S+SIGNED(B); EAD=RM16(EAD); break;
+ case 0xf6: EA=S+SIGNED(A); EAD=RM16(EAD); break;
+ case 0xf7: EA=S+SIGNED(E); EAD=RM16(EAD); break;
+ case 0xf8: IMMBYTE(EA); EA=S+SIGNED(EA); EAD=RM16(EAD); break;
+ case 0xf9: IMMWORD(ea); EA+=S; EAD=RM16(EAD); break;
+ case 0xfa: EA=S+SIGNED(F); EAD=RM16(EAD); break;
+ case 0xfb: EA=S+D; EAD=RM16(EAD); break;
+ case 0xfc: IMMBYTE(EA); EA=PC+SIGNED(EA); EAD=RM16(EAD); break;
+ case 0xfd: IMMWORD(ea); EA+=PC; EAD=RM16(EAD); break;
+ case 0xfe: EA=S+W; EAD=RM16(EAD); break;
+ case 0xff: IIError(); break;
+ }
+
+ hd6309_ICount -= index_cycle[postbyte];
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void hd6309_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + HD6309_IRQ_LINE: set_irq_line(HD6309_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + HD6309_FIRQ_LINE:set_irq_line(HD6309_FIRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + HD6309_PC: PC = info->i; CHANGE_PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + HD6309_S: S = info->i; break;
+ case CPUINFO_INT_REGISTER + HD6309_CC: CC = info->i; CHECK_IRQ_LINES(); break;
+ case CPUINFO_INT_REGISTER + HD6309_MD: MD = info->i; UpdateState(); break;
+ case CPUINFO_INT_REGISTER + HD6309_U: U = info->i; break;
+ case CPUINFO_INT_REGISTER + HD6309_A: A = info->i; break;
+ case CPUINFO_INT_REGISTER + HD6309_B: B = info->i; break;
+ case CPUINFO_INT_REGISTER + HD6309_E: E = info->i; break;
+ case CPUINFO_INT_REGISTER + HD6309_F: F = info->i; break;
+ case CPUINFO_INT_REGISTER + HD6309_X: X = info->i; break;
+ case CPUINFO_INT_REGISTER + HD6309_Y: Y = info->i; break;
+ case CPUINFO_INT_REGISTER + HD6309_V: V = info->i; break;
+ case CPUINFO_INT_REGISTER + HD6309_DP: DP = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void hd6309_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(hd6309); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 20; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + HD6309_IRQ_LINE: info->i = hd6309.irq_state[HD6309_IRQ_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + HD6309_FIRQ_LINE:info->i = hd6309.irq_state[HD6309_FIRQ_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = hd6309.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + HD6309_PC: info->i = PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + HD6309_S: info->i = S; break;
+ case CPUINFO_INT_REGISTER + HD6309_CC: info->i = CC; break;
+ case CPUINFO_INT_REGISTER + HD6309_MD: info->i = MD; break;
+ case CPUINFO_INT_REGISTER + HD6309_U: info->i = U; break;
+ case CPUINFO_INT_REGISTER + HD6309_A: info->i = A; break;
+ case CPUINFO_INT_REGISTER + HD6309_B: info->i = B; break;
+ case CPUINFO_INT_REGISTER + HD6309_E: info->i = E; break;
+ case CPUINFO_INT_REGISTER + HD6309_F: info->i = F; break;
+ case CPUINFO_INT_REGISTER + HD6309_X: info->i = X; break;
+ case CPUINFO_INT_REGISTER + HD6309_Y: info->i = Y; break;
+ case CPUINFO_INT_REGISTER + HD6309_V: info->i = V; break;
+ case CPUINFO_INT_REGISTER + HD6309_DP: info->i = DP; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = hd6309_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = hd6309_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = hd6309_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = hd6309_init; break;
+ case CPUINFO_PTR_RESET: info->reset = hd6309_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = hd6309_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = hd6309_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = hd6309_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &hd6309_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "HD6309"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Hitachi 6309"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.01"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) John Butler 1997 and Tim Lindner 2000"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c (MD:%c%c%c%c)",
+ hd6309.cc & 0x80 ? 'E':'.',
+ hd6309.cc & 0x40 ? 'F':'.',
+ hd6309.cc & 0x20 ? 'H':'.',
+ hd6309.cc & 0x10 ? 'I':'.',
+ hd6309.cc & 0x08 ? 'N':'.',
+ hd6309.cc & 0x04 ? 'Z':'.',
+ hd6309.cc & 0x02 ? 'V':'.',
+ hd6309.cc & 0x01 ? 'C':'.',
+
+ hd6309.md & 0x80 ? 'E':'e',
+ hd6309.md & 0x40 ? 'F':'f',
+ hd6309.md & 0x02 ? 'I':'i',
+ hd6309.md & 0x01 ? 'Z':'z');
+ break;
+
+ case CPUINFO_STR_REGISTER + HD6309_PC: sprintf(info->s, "PC:%04X", hd6309.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + HD6309_S: sprintf(info->s, "S:%04X", hd6309.s.w.l); break;
+ case CPUINFO_STR_REGISTER + HD6309_CC: sprintf(info->s, "CC:%02X", hd6309.cc); break;
+ case CPUINFO_STR_REGISTER + HD6309_MD: sprintf(info->s, "MD:%02X", hd6309.md); break;
+ case CPUINFO_STR_REGISTER + HD6309_U: sprintf(info->s, "U:%04X", hd6309.u.w.l); break;
+ case CPUINFO_STR_REGISTER + HD6309_A: sprintf(info->s, "A:%02X", hd6309.d.b.h); break;
+ case CPUINFO_STR_REGISTER + HD6309_B: sprintf(info->s, "B:%02X", hd6309.d.b.l); break;
+ case CPUINFO_STR_REGISTER + HD6309_E: sprintf(info->s, "E:%02X", hd6309.w.b.h); break;
+ case CPUINFO_STR_REGISTER + HD6309_F: sprintf(info->s, "F:%02X", hd6309.w.b.l); break;
+ case CPUINFO_STR_REGISTER + HD6309_X: sprintf(info->s, "X:%04X", hd6309.x.w.l); break;
+ case CPUINFO_STR_REGISTER + HD6309_Y: sprintf(info->s, "Y:%04X", hd6309.y.w.l); break;
+ case CPUINFO_STR_REGISTER + HD6309_V: sprintf(info->s, "V:%04X", hd6309.v.w.l); break;
+ case CPUINFO_STR_REGISTER + HD6309_DP: sprintf(info->s, "DP:%02X", hd6309.dp.b.h); break;
+ }
+}
diff --git a/src/emu/cpu/hd6309/hd6309.h b/src/emu/cpu/hd6309/hd6309.h
new file mode 100644
index 00000000000..f4db2ad368c
--- /dev/null
+++ b/src/emu/cpu/hd6309/hd6309.h
@@ -0,0 +1,52 @@
+/*** hd6309: Portable 6309 emulator ******************************************/
+
+#ifndef _HD6309_H
+#define _HD6309_H
+
+#include "cpuintrf.h"
+
+enum {
+ HD6309_PC=1, HD6309_S, HD6309_CC ,HD6309_A, HD6309_B, HD6309_U, HD6309_X, HD6309_Y, HD6309_DP,
+ HD6309_E, HD6309_F, HD6309_V, HD6309_MD };
+
+#define HD6309_IRQ_LINE 0 /* IRQ line number */
+#define HD6309_FIRQ_LINE 1 /* FIRQ line number */
+
+
+/* PUBLIC FUNCTIONS */
+void hd6309_get_info(UINT32 state, cpuinfo *info);
+
+/****************************************************************************/
+/* Read a byte from given memory location */
+/****************************************************************************/
+/* ASG 971005 -- changed to program_read_byte_8/cpu_writemem16 */
+#define HD6309_RDMEM(Addr) ((unsigned)program_read_byte_8(Addr))
+
+/****************************************************************************/
+/* Write a byte to given memory location */
+/****************************************************************************/
+#define HD6309_WRMEM(Addr,Value) (program_write_byte_8(Addr,Value))
+
+/****************************************************************************/
+/* Z80_RDOP() is identical to Z80_RDMEM() except it is used for reading */
+/* opcodes. In case of system with memory mapped I/O, this function can be */
+/* used to greatly speed up emulation */
+/****************************************************************************/
+#define HD6309_RDOP(Addr) ((unsigned)cpu_readop(Addr))
+
+/****************************************************************************/
+/* Z80_RDOP_ARG() is identical to Z80_RDOP() except it is used for reading */
+/* opcode arguments. This difference can be used to support systems that */
+/* use different encoding mechanisms for opcodes and opcode arguments */
+/****************************************************************************/
+#define HD6309_RDOP_ARG(Addr) ((unsigned)cpu_readop_arg(Addr))
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE (!FALSE)
+#endif
+
+#endif /* _HD6309_H */
+
diff --git a/src/emu/cpu/i386/cycles.h b/src/emu/cpu/i386/cycles.h
new file mode 100644
index 00000000000..1d7681e5f47
--- /dev/null
+++ b/src/emu/cpu/i386/cycles.h
@@ -0,0 +1,666 @@
+typedef enum {
+ CYCLES_MOV_REG_REG,
+ CYCLES_MOV_REG_MEM,
+ CYCLES_MOV_MEM_REG,
+ CYCLES_MOV_IMM_REG,
+ CYCLES_MOV_IMM_MEM,
+ CYCLES_MOV_ACC_MEM,
+ CYCLES_MOV_MEM_ACC,
+ CYCLES_MOV_REG_SREG,
+ CYCLES_MOV_MEM_SREG,
+ CYCLES_MOV_SREG_REG,
+ CYCLES_MOV_SREG_MEM,
+ CYCLES_MOVSX_REG_REG,
+ CYCLES_MOVSX_MEM_REG,
+ CYCLES_MOVZX_REG_REG,
+ CYCLES_MOVZX_MEM_REG,
+ CYCLES_PUSH_RM,
+ CYCLES_PUSH_REG_SHORT,
+ CYCLES_PUSH_SREG,
+ CYCLES_PUSH_IMM,
+ CYCLES_PUSHA,
+ CYCLES_POP_RM,
+ CYCLES_POP_REG_SHORT,
+ CYCLES_POP_SREG,
+ CYCLES_POPA,
+ CYCLES_XCHG_REG_REG,
+ CYCLES_XCHG_REG_MEM,
+ CYCLES_IN,
+ CYCLES_IN_VAR,
+ CYCLES_OUT,
+ CYCLES_OUT_VAR,
+ CYCLES_LEA,
+ CYCLES_LDS,
+ CYCLES_LES,
+ CYCLES_LFS,
+ CYCLES_LGS,
+ CYCLES_LSS,
+ CYCLES_CLC,
+ CYCLES_CLD,
+ CYCLES_CLI,
+ CYCLES_CLTS,
+ CYCLES_CMC,
+ CYCLES_LAHF,
+ CYCLES_POPF,
+ CYCLES_PUSHF,
+ CYCLES_SAHF,
+ CYCLES_STC,
+ CYCLES_STD,
+ CYCLES_STI,
+ CYCLES_ALU_REG_REG,
+ CYCLES_ALU_REG_MEM,
+ CYCLES_ALU_MEM_REG,
+ CYCLES_ALU_IMM_REG,
+ CYCLES_ALU_IMM_MEM,
+ CYCLES_ALU_IMM_ACC,
+ CYCLES_INC_REG,
+ CYCLES_INC_MEM,
+ CYCLES_DEC_REG,
+ CYCLES_DEC_MEM,
+ CYCLES_CMP_REG_REG,
+ CYCLES_CMP_REG_MEM,
+ CYCLES_CMP_MEM_REG,
+ CYCLES_CMP_IMM_REG,
+ CYCLES_CMP_IMM_MEM,
+ CYCLES_CMP_IMM_ACC,
+ CYCLES_TEST_REG_REG,
+ CYCLES_TEST_REG_MEM,
+ CYCLES_TEST_IMM_REG,
+ CYCLES_TEST_IMM_MEM,
+ CYCLES_TEST_IMM_ACC,
+ CYCLES_NEG_REG,
+ CYCLES_NEG_MEM,
+ CYCLES_AAA,
+ CYCLES_AAS,
+ CYCLES_DAA,
+ CYCLES_DAS,
+ CYCLES_MUL8_ACC_REG,
+ CYCLES_MUL8_ACC_MEM,
+ CYCLES_MUL16_ACC_REG,
+ CYCLES_MUL16_ACC_MEM,
+ CYCLES_MUL32_ACC_REG,
+ CYCLES_MUL32_ACC_MEM,
+ CYCLES_IMUL8_ACC_REG,
+ CYCLES_IMUL8_ACC_MEM,
+ CYCLES_IMUL16_ACC_REG,
+ CYCLES_IMUL16_ACC_MEM,
+ CYCLES_IMUL32_ACC_REG,
+ CYCLES_IMUL32_ACC_MEM,
+ CYCLES_IMUL8_REG_REG,
+ CYCLES_IMUL8_REG_MEM,
+ CYCLES_IMUL16_REG_REG,
+ CYCLES_IMUL16_REG_MEM,
+ CYCLES_IMUL32_REG_REG,
+ CYCLES_IMUL32_REG_MEM,
+ CYCLES_IMUL16_REG_IMM_REG,
+ CYCLES_IMUL16_MEM_IMM_REG,
+ CYCLES_IMUL32_REG_IMM_REG,
+ CYCLES_IMUL32_MEM_IMM_REG,
+ CYCLES_DIV8_ACC_REG,
+ CYCLES_DIV8_ACC_MEM,
+ CYCLES_DIV16_ACC_REG,
+ CYCLES_DIV16_ACC_MEM,
+ CYCLES_DIV32_ACC_REG,
+ CYCLES_DIV32_ACC_MEM,
+ CYCLES_IDIV8_ACC_REG,
+ CYCLES_IDIV8_ACC_MEM,
+ CYCLES_IDIV16_ACC_REG,
+ CYCLES_IDIV16_ACC_MEM,
+ CYCLES_IDIV32_ACC_REG,
+ CYCLES_IDIV32_ACC_MEM,
+ CYCLES_AAD,
+ CYCLES_AAM,
+ CYCLES_CBW,
+ CYCLES_CWD,
+ CYCLES_ROTATE_REG,
+ CYCLES_ROTATE_MEM,
+ CYCLES_ROTATE_CARRY_REG,
+ CYCLES_ROTATE_CARRY_MEM,
+ CYCLES_SHLD_REG,
+ CYCLES_SHLD_MEM,
+ CYCLES_SHRD_REG,
+ CYCLES_SHRD_MEM,
+ CYCLES_NOT_REG,
+ CYCLES_NOT_MEM,
+ CYCLES_CMPS,
+ CYCLES_INS,
+ CYCLES_LODS,
+ CYCLES_MOVS,
+ CYCLES_OUTS,
+ CYCLES_SCAS,
+ CYCLES_STOS,
+ CYCLES_XLAT,
+ CYCLES_REP_CMPS_BASE,
+ CYCLES_REP_INS_BASE,
+ CYCLES_REP_LODS_BASE,
+ CYCLES_REP_MOVS_BASE,
+ CYCLES_REP_OUTS_BASE,
+ CYCLES_REP_SCAS_BASE,
+ CYCLES_REP_STOS_BASE,
+ CYCLES_REP_CMPS,
+ CYCLES_REP_INS,
+ CYCLES_REP_LODS,
+ CYCLES_REP_MOVS,
+ CYCLES_REP_OUTS,
+ CYCLES_REP_SCAS,
+ CYCLES_REP_STOS,
+ CYCLES_BSF_BASE,
+ CYCLES_BSF,
+ CYCLES_BSR_BASE,
+ CYCLES_BSR,
+ CYCLES_BT_IMM_REG,
+ CYCLES_BT_IMM_MEM,
+ CYCLES_BT_REG_REG,
+ CYCLES_BT_REG_MEM,
+ CYCLES_BTC_IMM_REG,
+ CYCLES_BTC_IMM_MEM,
+ CYCLES_BTC_REG_REG,
+ CYCLES_BTC_REG_MEM,
+ CYCLES_BTR_IMM_REG,
+ CYCLES_BTR_IMM_MEM,
+ CYCLES_BTR_REG_REG,
+ CYCLES_BTR_REG_MEM,
+ CYCLES_BTS_IMM_REG,
+ CYCLES_BTS_IMM_MEM,
+ CYCLES_BTS_REG_REG,
+ CYCLES_BTS_REG_MEM,
+ CYCLES_CALL, // E8
+ CYCLES_CALL_REG, // FF /2
+ CYCLES_CALL_MEM, // FF /2
+ CYCLES_CALL_INTERSEG, // 9A
+ CYCLES_CALL_REG_INTERSEG, // FF /3
+ CYCLES_CALL_MEM_INTERSEG, // FF /3
+ CYCLES_JMP_SHORT, // EB
+ CYCLES_JMP, // E9
+ CYCLES_JMP_REG, // FF /4
+ CYCLES_JMP_MEM, // FF /4
+ CYCLES_JMP_INTERSEG, // EA
+ CYCLES_JMP_REG_INTERSEG, // FF /5
+ CYCLES_JMP_MEM_INTERSEG, // FF /5
+ CYCLES_RET, // C3
+ CYCLES_RET_IMM, // C2
+ CYCLES_RET_INTERSEG, // CB
+ CYCLES_RET_IMM_INTERSEG, // CA
+ CYCLES_JCC_DISP8,
+ CYCLES_JCC_FULL_DISP,
+ CYCLES_JCC_DISP8_NOBRANCH,
+ CYCLES_JCC_FULL_DISP_NOBRANCH,
+ CYCLES_JCXZ,
+ CYCLES_JCXZ_NOBRANCH,
+ CYCLES_LOOP,
+ CYCLES_LOOPZ,
+ CYCLES_LOOPNZ,
+ CYCLES_SETCC_REG,
+ CYCLES_SETCC_MEM,
+ CYCLES_ENTER,
+ CYCLES_LEAVE,
+ CYCLES_INT,
+ CYCLES_INT3,
+ CYCLES_INTO_OF1,
+ CYCLES_INTO_OF0,
+ CYCLES_BOUND_IN_RANGE,
+ CYCLES_BOUND_OUT_RANGE,
+ CYCLES_IRET,
+ CYCLES_HLT,
+ CYCLES_MOV_REG_CR0,
+ CYCLES_MOV_REG_CR2,
+ CYCLES_MOV_REG_CR3,
+ CYCLES_MOV_CR_REG,
+ CYCLES_MOV_REG_DR0_3,
+ CYCLES_MOV_REG_DR6_7,
+ CYCLES_MOV_DR6_7_REG,
+ CYCLES_MOV_DR0_3_REG,
+ CYCLES_MOV_REG_TR6_7,
+ CYCLES_MOV_TR6_7_REG,
+ CYCLES_NOP,
+ CYCLES_WAIT,
+ CYCLES_ARPL_REG,
+ CYCLES_ARPL_MEM,
+ CYCLES_LAR_REG,
+ CYCLES_LAR_MEM,
+ CYCLES_LGDT,
+ CYCLES_LIDT,
+ CYCLES_LLDT_REG,
+ CYCLES_LLDT_MEM,
+ CYCLES_LMSW_REG,
+ CYCLES_LMSW_MEM,
+ CYCLES_LSL_REG,
+ CYCLES_LSL_MEM,
+ CYCLES_LTR_REG,
+ CYCLES_LTR_MEM,
+ CYCLES_SGDT,
+ CYCLES_SIDT,
+ CYCLES_SLDT_REG,
+ CYCLES_SLDT_MEM,
+ CYCLES_SMSW_REG,
+ CYCLES_SMSW_MEM,
+ CYCLES_STR_REG,
+ CYCLES_STR_MEM,
+ CYCLES_VERR_REG,
+ CYCLES_VERR_MEM,
+ CYCLES_VERW_REG,
+ CYCLES_VERW_MEM,
+ CYCLES_LOCK,
+
+ CYCLES_BSWAP,
+ CYCLES_CMPXCHG8B,
+ CYCLES_CMPXCHG,
+ CYCLES_CPUID,
+ CYCLES_CPUID_EAX1,
+ CYCLES_INVD,
+ CYCLES_XADD,
+ CYCLES_RDTSC,
+ CYCLES_RSM,
+ CYCLES_RDMSR,
+
+ CYCLES_FABS,
+ CYCLES_FADD,
+ CYCLES_FBLD,
+ CYCLES_FBSTP,
+ CYCLES_FCHS,
+ CYCLES_FCLEX,
+ CYCLES_FCOM,
+ CYCLES_FCOS,
+ CYCLES_FDECSTP,
+ CYCLES_FDISI,
+ CYCLES_FDIV,
+ CYCLES_FDIVR,
+ CYCLES_FENI,
+ CYCLES_FFREE,
+ CYCLES_FIADD,
+ CYCLES_FICOM,
+ CYCLES_FIDIV,
+ CYCLES_FILD,
+ CYCLES_FIMUL,
+ CYCLES_FINCSTP,
+ CYCLES_FINIT,
+ CYCLES_FIST,
+ CYCLES_FISUB,
+ CYCLES_FLD,
+ CYCLES_FLDZ,
+ CYCLES_FLD1,
+ CYCLES_FLDL2E,
+ CYCLES_FLDL2T,
+ CYCLES_FLDLG2,
+ CYCLES_FLDLN2,
+ CYCLES_FLDPI,
+ CYCLES_FLDCW,
+ CYCLES_FLDENV,
+ CYCLES_FMUL,
+ CYCLES_FNOP,
+ CYCLES_FPATAN,
+ CYCLES_FPREM,
+ CYCLES_FPREM1,
+ CYCLES_FPTAN,
+ CYCLES_FRNDINT,
+ CYCLES_FRSTOR,
+ CYCLES_FSAVE,
+ CYCLES_FSCALE,
+ CYCLES_FSETPM,
+ CYCLES_FSIN,
+ CYCLES_FSINCOS,
+ CYCLES_FSQRT,
+ CYCLES_FST,
+ CYCLES_FSTCW,
+ CYCLES_FSTENV,
+ CYCLES_FSTSW,
+ CYCLES_FSUB,
+ CYCLES_FSUBR,
+ CYCLES_FTST,
+ CYCLES_FUCOM,
+ CYCLES_FXAM,
+ CYCLES_FXCH,
+ CYCLES_FXTRACT,
+ CYCLES_FYL2X,
+ CYCLES_FYL2XPI,
+ CYCLES_CMPXCHG_REG_REG_T,
+ CYCLES_CMPXCHG_REG_REG_F,
+ CYCLES_CMPXCHG_REG_MEM_T,
+ CYCLES_CMPXCHG_REG_MEM_F,
+ CYCLES_XADD_REG_REG,
+ CYCLES_XADD_REG_MEM,
+
+ CYCLES_NUM_OPCODES
+} X86_CYCLES;
+
+
+#define X86_NUM_CPUS 4
+#define CPU_CYCLES_I386 0
+#define CPU_CYCLES_I486 1
+#define CPU_CYCLES_PENTIUM 2
+#define CPU_CYCLES_MEDIAGX 3
+
+
+typedef struct
+{
+ X86_CYCLES op;
+ UINT8 cpu_cycles[X86_NUM_CPUS][2];
+} X86_CYCLE_TABLE;
+
+static X86_CYCLE_TABLE x86_cycle_table[] =
+{
+ // opcode rm/pmode
+ // i386 i486 pentium mediagx
+ { CYCLES_MOV_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_MOV_REG_MEM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_MOV_MEM_REG, { { 4, 4 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_MOV_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_MOV_IMM_MEM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_MOV_ACC_MEM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_MOV_MEM_ACC, { { 4, 4 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_MOV_REG_SREG, { { 2, 18 }, { 3, 3 }, { 2, 2 }, { 1, 6 } } },
+ { CYCLES_MOV_MEM_SREG, { { 5, 19 }, { 9, 9 }, { 3, 3 }, { 1, 6 } } },
+ { CYCLES_MOV_SREG_REG, { { 2, 2 }, { 3, 3 }, { 1, 1 }, { 1, 6 } } },
+ { CYCLES_MOV_SREG_MEM, { { 2, 2 }, { 3, 3 }, { 1, 1 }, { 1, 6 } } },
+ { CYCLES_MOVSX_REG_REG, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_MOVSX_MEM_REG, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_MOVZX_REG_REG, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_MOVZX_MEM_REG, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_PUSH_RM, { { 5, 5 }, { 4, 4 }, { 2, 2 }, { 3, 3 } } },
+ { CYCLES_PUSH_REG_SHORT, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_PUSH_SREG, { { 2, 2 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_PUSH_IMM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_PUSHA, { { 18, 18 }, { 11, 11 }, { 5, 5 }, { 11, 11 } } },
+ { CYCLES_POP_RM, { { 5, 5 }, { 4, 4 }, { 3, 3 }, { 4, 4 } } },
+ { CYCLES_POP_REG_SHORT, { { 4, 4 }, { 4, 4 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_POP_SREG, { { 7, 21 }, { 3, 3 }, { 3, 3 }, { 1, 6 } } },
+ { CYCLES_POPA, { { 24, 24 }, { 9, 9 }, { 5, 5 }, { 9, 9 } } },
+ { CYCLES_XCHG_REG_REG, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_XCHG_REG_MEM, { { 5, 5 }, { 5, 5 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_IN, { { 12, 26 }, { 14, 27 }, { 7, 19 }, { 8, 8 } } },
+ { CYCLES_IN_VAR, { { 13, 27 }, { 14, 27 }, { 7, 19 }, { 8, 8 } } },
+ { CYCLES_OUT, { { 10, 24 }, { 16, 29 }, { 12, 24 }, { 14, 14 } } },
+ { CYCLES_OUT_VAR, { { 11, 25 }, { 16, 29 }, { 12, 24 }, { 14, 14 } } },
+ { CYCLES_LEA, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_LDS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } },
+ { CYCLES_LES, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } },
+ { CYCLES_LFS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } },
+ { CYCLES_LGS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } },
+ { CYCLES_LSS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 10 } } },
+ { CYCLES_CLC, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_CLD, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 4, 4 } } },
+ { CYCLES_CLI, { { 8, 8 }, { 5, 5 }, { 7, 7 }, { 6, 6 } } },
+ { CYCLES_CLTS, { { 6, 6 }, { 7, 7 }, { 10, 10 }, { 7, 7 } } },
+ { CYCLES_CMC, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 3, 3 } } },
+ { CYCLES_LAHF, { { 2, 2 }, { 3, 3 }, { 2, 2 }, { 2, 2 } } },
+ { CYCLES_POPF, { { 5, 5 }, { 9, 9 }, { 6, 6 }, { 8, 8 } } },
+ { CYCLES_PUSHF, { { 4, 4 }, { 4, 4 }, { 9, 9 }, { 2, 2 } } },
+ { CYCLES_SAHF, { { 3, 3 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_STC, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_STD, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 4, 4 } } },
+ { CYCLES_STI, { { 8, 8 }, { 5, 5 }, { 7, 7 }, { 6, 6 } } },
+ { CYCLES_ALU_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_ALU_REG_MEM, { { 7, 7 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_ALU_MEM_REG, { { 6, 6 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_ALU_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_ALU_IMM_MEM, { { 7, 7 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_ALU_IMM_ACC, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_INC_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_INC_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_DEC_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_DEC_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_CMP_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_CMP_REG_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_CMP_MEM_REG, { { 6, 6 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_CMP_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_CMP_IMM_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_CMP_IMM_ACC, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_TEST_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_TEST_REG_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_TEST_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_TEST_IMM_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_TEST_IMM_ACC, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_NEG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_NEG_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_AAA, { { 4, 4 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } },
+ { CYCLES_AAS, { { 4, 4 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } },
+ { CYCLES_DAA, { { 4, 4 }, { 2, 2 }, { 3, 3 }, { 2, 2 } } },
+ { CYCLES_DAS, { { 4, 4 }, { 2, 2 }, { 3, 3 }, { 2, 2 } } },
+ { CYCLES_MUL8_ACC_REG, { { 17, 17 }, { 13, 13 }, { 11, 11 }, { 4, 4 } } },
+ { CYCLES_MUL8_ACC_MEM, { { 20, 20 }, { 13, 13 }, { 11, 11 }, { 4, 4 } } },
+ { CYCLES_MUL16_ACC_REG, { { 25, 25 }, { 13, 13 }, { 11, 11 }, { 5, 5 } } },
+ { CYCLES_MUL16_ACC_MEM, { { 28, 28 }, { 13, 13 }, { 11, 11 }, { 5, 5 } } },
+ { CYCLES_MUL32_ACC_REG, { { 41, 41 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } },
+ { CYCLES_MUL32_ACC_MEM, { { 44, 44 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } },
+ { CYCLES_IMUL8_ACC_REG, { { 17, 17 }, { 18, 18 }, { 11, 11 }, { 4, 4 } } },
+ { CYCLES_IMUL8_ACC_MEM, { { 20, 20 }, { 18, 18 }, { 11, 11 }, { 4, 4 } } },
+ { CYCLES_IMUL16_ACC_REG, { { 25, 25 }, { 26, 26 }, { 11, 11 }, { 5, 5 } } },
+ { CYCLES_IMUL16_ACC_MEM, { { 28, 28 }, { 26, 26 }, { 11, 11 }, { 5, 5 } } },
+ { CYCLES_IMUL32_ACC_REG, { { 41, 41 }, { 42, 42 }, { 10, 10 }, { 15, 15 } } },
+ { CYCLES_IMUL32_ACC_MEM, { { 44, 44 }, { 42, 42 }, { 10, 10 }, { 15, 15 } } },
+ { CYCLES_IMUL8_REG_REG, { { 17, 17 }, { 13, 13 }, { 10, 10 }, { 4, 4 } } },
+ { CYCLES_IMUL8_REG_MEM, { { 20, 20 }, { 13, 13 }, { 10, 10 }, { 4, 4 } } },
+ { CYCLES_IMUL16_REG_REG, { { 25, 25 }, { 13, 13 }, { 10, 10 }, { 5, 5 } } },
+ { CYCLES_IMUL16_REG_MEM, { { 28, 28 }, { 13, 13 }, { 10, 10 }, { 5, 5 } } },
+ { CYCLES_IMUL32_REG_REG, { { 41, 41 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } },
+ { CYCLES_IMUL32_REG_MEM, { { 44, 44 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } },
+ { CYCLES_IMUL16_REG_IMM_REG,{ { 26, 26 }, { 26, 26 }, { 10, 10 }, { 6, 6 } } },
+ { CYCLES_IMUL16_MEM_IMM_REG,{ { 27, 27 }, { 26, 26 }, { 10, 10 }, { 6, 6 } } },
+ { CYCLES_IMUL32_REG_IMM_REG,{ { 42, 42 }, { 42, 42 }, { 10, 10 }, { 16, 16 } } },
+ { CYCLES_IMUL32_MEM_IMM_REG,{ { 43, 43 }, { 42, 42 }, { 10, 10 }, { 16, 16 } } },
+ { CYCLES_DIV8_ACC_REG, { { 14, 14 }, { 16, 16 }, { 17, 17 }, { 20, 20 } } },
+ { CYCLES_DIV8_ACC_MEM, { { 17, 17 }, { 16, 16 }, { 17, 17 }, { 20, 20 } } },
+ { CYCLES_DIV16_ACC_REG, { { 22, 22 }, { 24, 24 }, { 25, 25 }, { 29, 29 } } },
+ { CYCLES_DIV16_ACC_MEM, { { 25, 25 }, { 24, 24 }, { 25, 25 }, { 29, 29 } } },
+ { CYCLES_DIV32_ACC_REG, { { 38, 38 }, { 40, 40 }, { 41, 41 }, { 45, 45 } } },
+ { CYCLES_DIV32_ACC_MEM, { { 41, 41 }, { 40, 40 }, { 41, 41 }, { 45, 45 } } },
+ { CYCLES_IDIV8_ACC_REG, { { 19, 19 }, { 19, 19 }, { 22, 22 }, { 20, 20 } } },
+ { CYCLES_IDIV8_ACC_MEM, { { 22, 22 }, { 20, 20 }, { 22, 22 }, { 20, 20 } } },
+ { CYCLES_IDIV16_ACC_REG, { { 27, 27 }, { 27, 27 }, { 30, 30 }, { 29, 29 } } },
+ { CYCLES_IDIV16_ACC_MEM, { { 30, 30 }, { 28, 28 }, { 30, 30 }, { 29, 29 } } },
+ { CYCLES_IDIV32_ACC_REG, { { 43, 43 }, { 43, 43 }, { 46, 46 }, { 45, 45 } } },
+ { CYCLES_IDIV32_ACC_MEM, { { 46, 46 }, { 44, 44 }, { 46, 46 }, { 45, 45 } } },
+ { CYCLES_AAD, { { 19, 19 }, { 14, 14 }, { 10, 10 }, { 7, 7 } } },
+ { CYCLES_AAM, { { 17, 17 }, { 15, 15 }, { 18, 18 }, { 19, 19 } } },
+ { CYCLES_CBW, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } },
+ { CYCLES_CWD, { { 2, 2 }, { 3, 3 }, { 2, 2 }, { 2, 2 } } },
+ { CYCLES_ROTATE_REG, { { 3, 3 }, { 3, 3 }, { 1, 1 }, { 2, 2 } } },
+ { CYCLES_ROTATE_MEM, { { 7, 7 }, { 4, 4 }, { 3, 3 }, { 2, 2 } } },
+ { CYCLES_ROTATE_CARRY_REG, { { 9, 9 }, { 8, 8 }, { 7, 7 }, { 8, 8 } } },
+ { CYCLES_ROTATE_CARRY_MEM, { { 10, 10 }, { 9, 9 }, { 8, 8 }, { 8, 8 } } },
+ { CYCLES_SHLD_REG, { { 3, 3 }, { 2, 2 }, { 4, 4 }, { 3, 3 } } },
+ { CYCLES_SHLD_MEM, { { 7, 7 }, { 3, 3 }, { 4, 4 }, { 6, 6 } } },
+ { CYCLES_SHRD_REG, { { 3, 3 }, { 2, 2 }, { 4, 4 }, { 3, 3 } } },
+ { CYCLES_SHRD_MEM, { { 7, 7 }, { 3, 3 }, { 4, 4 }, { 6, 6 } } },
+ { CYCLES_NOT_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_NOT_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_CMPS, { { 10, 10 }, { 8, 8 }, { 5, 5 }, { 6, 6 } } },
+ { CYCLES_INS, { { 15, 29 }, { 17, 30 }, { 9, 22 }, { 11, 11 } } },
+ { CYCLES_LODS, { { 5, 5 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
+ { CYCLES_MOVS, { { 8, 8 }, { 7, 7 }, { 4, 4 }, { 6, 6 } } },
+ { CYCLES_OUTS, { { 14, 28 }, { 17, 30 }, { 13, 25 }, { 15, 15 } } },
+ { CYCLES_SCAS, { { 8, 8 }, { 6, 6 }, { 4, 4 }, { 2, 2 } } },
+ { CYCLES_STOS, { { 5, 5 }, { 5, 5 }, { 3, 3 }, { 2, 2 } } },
+ { CYCLES_XLAT, { { 5, 5 }, { 4, 4 }, { 4, 4 }, { 5, 5 } } },
+ { CYCLES_REP_CMPS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 11, 11 } } },
+ { CYCLES_REP_INS_BASE, { { 14, 8 }, { 0, 0 }, { 0, 0 }, { 17, 17 } } },
+ { CYCLES_REP_LODS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 9, 9 } } },
+ { CYCLES_REP_MOVS_BASE, { { 8, 8 }, { 0, 0 }, { 0, 0 }, { 12, 12 } } },
+ { CYCLES_REP_OUTS_BASE, { { 12, 6 }, { 0, 0 }, { 0, 0 }, { 24, 24 } } },
+ { CYCLES_REP_SCAS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 9, 9 } } },
+ { CYCLES_REP_STOS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 9, 9 } } },
+ { CYCLES_REP_CMPS, { { 5, 5 }, { 8, 8 }, { 5, 5 }, { 4, 4 } } },
+ { CYCLES_REP_INS, { { 14, 8 }, { 17, 30 }, { 9, 22 }, { 4, 4 } } },
+ { CYCLES_REP_LODS, { { 5, 5 }, { 5, 5 }, { 2, 2 }, { 2, 2 } } },
+ { CYCLES_REP_MOVS, { { 8, 8 }, { 7, 7 }, { 4, 4 }, { 2, 2 } } },
+ { CYCLES_REP_OUTS, { { 12, 6 }, { 17, 30 }, { 13, 25 }, { 4, 4 } } },
+ { CYCLES_REP_SCAS, { { 5, 5 }, { 6, 6 }, { 4, 4 }, { 3, 3 } } },
+ { CYCLES_REP_STOS, { { 5, 5 }, { 5, 5 }, { 3, 3 }, { 2, 2 } } },
+ { CYCLES_BSF_BASE, { { 11, 11 }, { 6, 6 }, { 6, 6 }, { 4, 4 } } },
+ { CYCLES_BSF, { { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_BSR_BASE, { { 9, 9 }, { 6, 6 }, { 7, 7 }, { 4, 4 } } },
+ { CYCLES_BSR, { { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_BT_IMM_REG, { { 3, 3 }, { 3, 3 }, { 4, 4 }, { 1, 1 } } },
+ { CYCLES_BT_IMM_MEM, { { 6, 6 }, { 6, 6 }, { 4, 4 }, { 1, 1 } } },
+ { CYCLES_BT_REG_REG, { { 3, 3 }, { 3, 3 }, { 4, 4 }, { 1, 1 } } },
+ { CYCLES_BT_REG_MEM, { { 12, 12 }, { 12, 12 }, { 9, 9 }, { 7, 7 } } },
+ { CYCLES_BTC_IMM_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
+ { CYCLES_BTC_IMM_MEM, { { 8, 8 }, { 8, 8 }, { 8, 8 }, { 2, 2 } } },
+ { CYCLES_BTC_REG_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
+ { CYCLES_BTC_REG_MEM, { { 13, 13 }, { 13, 13 }, { 13, 13 }, { 8, 8 } } },
+ { CYCLES_BTR_IMM_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
+ { CYCLES_BTR_IMM_MEM, { { 8, 8 }, { 8, 8 }, { 8, 8 }, { 2, 2 } } },
+ { CYCLES_BTR_REG_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
+ { CYCLES_BTR_REG_MEM, { { 13, 13 }, { 13, 13 }, { 13, 13 }, { 8, 8 } } },
+ { CYCLES_BTS_IMM_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
+ { CYCLES_BTS_IMM_MEM, { { 8, 8 }, { 8, 8 }, { 8, 8 }, { 2, 2 } } },
+ { CYCLES_BTS_REG_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
+ { CYCLES_BTS_REG_MEM, { { 13, 13 }, { 13, 13 }, { 13, 13 }, { 8, 8 } } },
+ { CYCLES_CALL, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 3, 3 } } },
+ { CYCLES_CALL_REG, { { 7, 7 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
+ { CYCLES_CALL_MEM, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 4, 4 } } },
+ { CYCLES_CALL_INTERSEG, { { 17, 34 }, { 18, 20 }, { 4, 13 }, { 9, 14 } } },
+ { CYCLES_CALL_REG_INTERSEG, { { 22, 38 }, { 17, 20 }, { 4, 14 }, { 11, 15 } } },
+ { CYCLES_CALL_MEM_INTERSEG, { { 22, 38 }, { 17, 20 }, { 4, 14 }, { 11, 15 } } },
+ { CYCLES_JMP_SHORT, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_JMP, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_JMP_REG, { { 7, 7 }, { 5, 5 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_JMP_MEM, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
+ { CYCLES_JMP_INTERSEG, { { 12, 27 }, { 17, 19 }, { 3, 3 }, { 8, 12 } } },
+ { CYCLES_JMP_REG_INTERSEG, { { 17, 31 }, { 13, 18 }, { 4, 4 }, { 10, 10 } } },
+ { CYCLES_JMP_MEM_INTERSEG, { { 17, 31 }, { 13, 18 }, { 4, 4 }, { 10, 13 } } },
+ { CYCLES_RET, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
+ { CYCLES_RET_IMM, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
+ { CYCLES_RET_INTERSEG, { { 18, 32 }, { 13, 13 }, { 4, 4 }, { 10, 13 } } },
+ { CYCLES_RET_IMM_INTERSEG, { { 18, 32 }, { 14, 14 }, { 4, 4 }, { 10, 13 } } },
+ { CYCLES_JCC_DISP8, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_JCC_FULL_DISP, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_JCC_DISP8_NOBRANCH,{ { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_JCC_FULL_DISP_NOBRANCH,{ { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_JCXZ, { { 9, 9 }, { 1, 1 }, { 1, 1 }, { 2, 2 } } },
+ { CYCLES_JCXZ_NOBRANCH, { { 5, 5 }, { 1, 1 }, { 1, 1 }, { 2, 2 } } },
+ { CYCLES_LOOP, { { 11, 11 }, { 6, 6 }, { 5, 5 }, { 2, 2 } } },
+ { CYCLES_LOOPZ, { { 11, 11 }, { 9, 9 }, { 8, 8 }, { 2, 2 } } },
+ { CYCLES_LOOPNZ, { { 11, 11 }, { 9, 9 }, { 8, 8 }, { 2, 2 } } },
+ { CYCLES_SETCC_REG, { { 4, 4 }, { 3, 3 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_SETCC_MEM, { { 5, 5 }, { 4, 4 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_ENTER, { { 10, 10 }, { 14, 14 }, { 11, 11 }, { 13, 13 } } },
+ { CYCLES_LEAVE, { { 4, 4 }, { 5, 5 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_INT, { { 37, 37 }, { 30, 30 }, { 16, 16 }, { 19, 19 } } },
+ { CYCLES_INT3, { { 33, 33 }, { 26, 26 }, { 13, 13 }, { 19, 19 } } },
+ { CYCLES_INTO_OF1, { { 35, 35 }, { 28, 28 }, { 13, 13 }, { 19, 19 } } },
+ { CYCLES_INTO_OF0, { { 3, 3 }, { 3, 3 }, { 4, 4 }, { 4, 4 } } },
+ { CYCLES_BOUND_IN_RANGE, { { 10, 10 }, { 7, 7 }, { 8, 8 }, { 7, 7 } } },
+ { CYCLES_BOUND_OUT_RANGE, { { 44, 44 }, { 7, 7 }, { 8, 8 }, { 8, 8 } } },
+ { CYCLES_IRET, { { 22, 22 }, { 15, 15 }, { 8, 8 }, { 13, 13 } } },
+ { CYCLES_HLT, { { 5, 5 }, { 4, 4 }, { 4, 4 }, { 10, 10 } } },
+ { CYCLES_MOV_REG_CR0, { { 11, 11 }, { 16, 16 }, { 16, 16 }, { 20, 18 } } },
+ { CYCLES_MOV_REG_CR2, { { 4, 4 }, { 4, 4 }, { 4, 4 }, { 5, 5 } } },
+ { CYCLES_MOV_REG_CR3, { { 5, 5 }, { 4, 4 }, { 4, 4 }, { 5, 6 } } },
+ { CYCLES_MOV_CR_REG, { { 6, 6 }, { 4, 4 }, { 4, 4 }, { 6, 6 } } },
+ { CYCLES_MOV_REG_DR0_3, { { 22, 22 }, { 10, 10 }, { 10, 10 }, { 10, 10 } } },
+ { CYCLES_MOV_REG_DR6_7, { { 16, 16 }, { 10, 10 }, { 10, 10 }, { 10, 10 } } },
+ { CYCLES_MOV_DR6_7_REG, { { 14, 14 }, { 11, 11 }, { 11, 11 }, { 9, 9 } } },
+ { CYCLES_MOV_DR0_3_REG, { { 22, 22 }, { 11, 11 }, { 11, 11 }, { 9, 9 } } },
+ { CYCLES_MOV_REG_TR6_7, { { 12, 12 }, { 4, 4 }, { 4, 4 }, { 11, 11 } } },
+ { CYCLES_MOV_TR6_7_REG, { { 12, 12 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } },
+ { CYCLES_NOP, { { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_WAIT, { { 7, 7 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_ARPL_REG, { { 0, 20 }, { 0, 9 }, { 0, 7 }, { 0, 9 } } },
+ { CYCLES_ARPL_MEM, { { 0, 21 }, { 0, 9 }, { 0, 7 }, { 0, 9 } } },
+ { CYCLES_LAR_REG, { { 0, 15 }, { 11, 11 }, { 8, 8 }, { 0, 9 } } },
+ { CYCLES_LAR_MEM, { { 0, 16 }, { 11, 11 }, { 8, 8 }, { 0, 9 } } },
+ { CYCLES_LGDT, { { 11, 11 }, { 11, 11 }, { 6, 6 }, { 10, 10 } } },
+ { CYCLES_LIDT, { { 11, 11 }, { 11, 11 }, { 6, 6 }, { 10, 10 } } },
+ { CYCLES_LLDT_REG, { { 0, 20 }, { 11, 11 }, { 9, 9 }, { 0, 8 } } },
+ { CYCLES_LLDT_MEM, { { 0, 24 }, { 11, 11 }, { 9, 9 }, { 0, 8 } } },
+ { CYCLES_LMSW_REG, { { 11, 11 }, { 13, 13 }, { 8, 8 }, { 11, 11 } } },
+ { CYCLES_LMSW_MEM, { { 14, 14 }, { 13, 13 }, { 8, 8 }, { 11, 11 } } },
+ { CYCLES_LSL_REG, { { 0, 21 }, { 10, 10 }, { 8, 8 }, { 0, 9 } } },
+ { CYCLES_LSL_MEM, { { 0, 22 }, { 10, 10 }, { 8, 8 }, { 0, 9 } } },
+ { CYCLES_LTR_REG, { { 0, 23 }, { 20, 20 }, { 10, 10 }, { 0, 9 } } },
+ { CYCLES_LTR_MEM, { { 0, 27 }, { 20, 20 }, { 10, 10 }, { 0, 9 } } },
+ { CYCLES_SGDT, { { 9, 9 }, { 10, 10 }, { 4, 4 }, { 6, 6 } } },
+ { CYCLES_SIDT, { { 9, 9 }, { 10, 10 }, { 4, 4 }, { 6, 6 } } },
+ { CYCLES_SLDT_REG, { { 0, 2 }, { 2, 2 }, { 2, 2 }, { 0, 1 } } },
+ { CYCLES_SLDT_MEM, { { 0, 2 }, { 3, 3 }, { 2, 2 }, { 0, 1 } } },
+ { CYCLES_SMSW_REG, { { 2, 2 }, { 2, 2 }, { 4, 4 }, { 4, 4 } } },
+ { CYCLES_SMSW_MEM, { { 2, 2 }, { 3, 3 }, { 4, 4 }, { 4, 4 } } },
+ { CYCLES_STR_REG, { { 0, 2 }, { 2, 2 }, { 2, 2 }, { 0, 3 } } },
+ { CYCLES_STR_MEM, { { 0, 2 }, { 3, 3 }, { 2, 2 }, { 0, 3 } } },
+ { CYCLES_VERR_REG, { { 0, 10 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } },
+ { CYCLES_VERR_MEM, { { 0, 11 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } },
+ { CYCLES_VERW_REG, { { 0, 15 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } },
+ { CYCLES_VERW_MEM, { { 0, 16 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } },
+ { CYCLES_LOCK, { { 0, 0 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
+
+ // i486+
+ { CYCLES_BSWAP, { { 0, 0 }, { 1, 1 }, { 1, 1 }, { 6, 6 } } },
+ { CYCLES_CMPXCHG, { { 0, 0 }, { 6, 6 }, { 5, 5 }, { 6, 6 } } },
+ { CYCLES_INVD, { { 0, 0 }, { 4, 4 }, { 15, 15 }, { 20, 20 } } },
+ { CYCLES_XADD, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 2, 2 } } },
+
+ // Pentium+
+ { CYCLES_CMPXCHG8B, { { 0, 0 }, { 0, 0 }, { 10, 10 }, { 6, 6 } } },
+ { CYCLES_CPUID, { { 0, 0 }, { 0, 0 }, { 14, 14 }, { 12, 12 } } },
+ { CYCLES_CPUID_EAX1, { { 0, 0 }, { 0, 0 }, { 14, 14 }, { 12, 12 } } },
+ { CYCLES_RDTSC, { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 1, 1 } } },
+ { CYCLES_RSM, { { 0, 0 }, { 0, 0 }, { 82, 82 }, { 57, 57 } } },
+ { CYCLES_RDMSR, { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 1, 1 } } },
+
+ // FPU
+ { CYCLES_FABS, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FADD, { { 0, 0 }, { 8, 8 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_FBLD, { { 0, 0 }, { 70, 70 }, { 48, 48 }, { 1, 1 } } },
+ { CYCLES_FBSTP, { { 0, 0 }, {172,172 }, {148,148 }, { 1, 1 } } },
+ { CYCLES_FCHS, { { 0, 0 }, { 6, 6 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FCLEX, { { 0, 0 }, { 7, 7 }, { 9, 9 }, { 1, 1 } } },
+ { CYCLES_FCOM, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 1, 1 } } },
+ { CYCLES_FCOS, { { 0, 0 }, {255,255 }, {124,124 }, { 1, 1 } } },
+ { CYCLES_FDECSTP, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FDISI, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FDIV, { { 0, 0 }, { 73, 73 }, { 39, 39 }, { 1, 1 } } },
+ { CYCLES_FDIVR, { { 0, 0 }, { 73, 73 }, { 39, 39 }, { 1, 1 } } },
+ { CYCLES_FENI, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FFREE, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FIADD, { { 0, 0 }, { 20, 20 }, { 7, 7 }, { 1, 1 } } },
+ { CYCLES_FICOM, { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 1, 1 } } },
+ { CYCLES_FIDIV, { { 0, 0 }, { 85, 85 }, { 42, 42 }, { 1, 1 } } },
+ { CYCLES_FILD, { { 0, 0 }, { 13, 13 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_FIMUL, { { 0, 0 }, { 23, 23 }, { 7, 7 }, { 1, 1 } } },
+ { CYCLES_FINCSTP, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FINIT, { { 0, 0 }, { 17, 17 }, { 16, 16 }, { 1, 1 } } },
+ { CYCLES_FIST, { { 0, 0 }, { 29, 29 }, { 6, 6 }, { 1, 1 } } },
+ { CYCLES_FISUB, { { 0, 0 }, { 20, 20 }, { 7, 7 }, { 1, 1 } } },
+ { CYCLES_FLD, { { 0, 0 }, { 4, 4 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FLDZ, { { 0, 0 }, { 4, 4 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_FLD1, { { 0, 0 }, { 4, 4 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_FLDL2E, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
+ { CYCLES_FLDL2T, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
+ { CYCLES_FLDLG2, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
+ { CYCLES_FLDLN2, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
+ { CYCLES_FLDPI, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
+ { CYCLES_FLDCW, { { 0, 0 }, { 4, 4 }, { 7, 7 }, { 1, 1 } } },
+ { CYCLES_FLDENV, { { 0, 0 }, { 44, 44 }, { 37, 37 }, { 1, 1 } } },
+ { CYCLES_FMUL, { { 0, 0 }, { 16, 16 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_FNOP, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FPATAN, { { 0, 0 }, {218,218 }, {173,173 }, { 1, 1 } } },
+ { CYCLES_FPREM, { { 0, 0 }, { 70, 70 }, { 16, 16 }, { 1, 1 } } },
+ { CYCLES_FPREM1, { { 0, 0 }, { 72, 72 }, { 20, 20 }, { 1, 1 } } },
+ { CYCLES_FPTAN, { { 0, 0 }, {200,200 }, {173,173 }, { 1, 1 } } },
+ { CYCLES_FRNDINT, { { 0, 0 }, { 21, 21 }, { 9, 9 }, { 1, 1 } } },
+ { CYCLES_FRSTOR, { { 0, 0 }, {131,131 }, { 75, 75 }, { 1, 1 } } },
+ { CYCLES_FSAVE, { { 0, 0 }, {154,154 }, {127,127 }, { 1, 1 } } },
+ { CYCLES_FSCALE, { { 0, 0 }, { 30, 30 }, { 20, 20 }, { 1, 1 } } },
+ { CYCLES_FSETPM, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FSIN, { { 0, 0 }, {255,255 }, {126,126 }, { 1, 1 } } },
+ { CYCLES_FSINCOS, { { 0, 0 }, {255,255 }, {137,137 }, { 1, 1 } } },
+ { CYCLES_FSQRT, { { 0, 0 }, { 83, 83 }, { 70, 70 }, { 1, 1 } } },
+ { CYCLES_FST, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FSTCW, { { 0, 0 }, { 3, 3 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_FSTENV, { { 0, 0 }, { 67, 67 }, { 48, 48 }, { 1, 1 } } },
+ { CYCLES_FSTSW, { { 0, 0 }, { 3, 3 }, { 2, 2 }, { 1, 1 } } },
+ { CYCLES_FSUB, { { 0, 0 }, { 8, 8 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_FSUBR, { { 0, 0 }, { 8, 8 }, { 3, 3 }, { 1, 1 } } },
+ { CYCLES_FTST, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 1, 1 } } },
+ { CYCLES_FUCOM, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 1, 1 } } },
+ { CYCLES_FXAM, { { 0, 0 }, { 8, 8 }, { 21, 21 }, { 1, 1 } } },
+ { CYCLES_FXCH, { { 0, 0 }, { 4, 4 }, { 1, 1 }, { 1, 1 } } },
+ { CYCLES_FXTRACT, { { 0, 0 }, { 16, 16 }, { 13, 13 }, { 1, 1 } } },
+ { CYCLES_FYL2X, { { 0, 0 }, {196,196 }, {111,111 }, { 1, 1 } } },
+ { CYCLES_FYL2XPI, { { 0, 0 }, {171,171 }, {103,103 }, { 1, 1 } } },
+ { CYCLES_CMPXCHG_REG_REG_T, { { 0, 0 }, { 6, 6 }, { 6, 6 }, { 6, 6 } } },
+ { CYCLES_CMPXCHG_REG_REG_F, { { 0, 0 }, { 9, 9 }, { 9, 9 }, { 9, 9 } } },
+ { CYCLES_CMPXCHG_REG_MEM_T, { { 0, 0 }, { 7, 7 }, { 7, 7 }, { 7, 7 } } },
+ { CYCLES_CMPXCHG_REG_MEM_F, { { 0, 0 }, { 10, 10 }, { 10, 10 }, { 10, 10 } } },
+};
diff --git a/src/emu/cpu/i386/i386.c b/src/emu/cpu/i386/i386.c
new file mode 100644
index 00000000000..e1cc92645fa
--- /dev/null
+++ b/src/emu/cpu/i386/i386.c
@@ -0,0 +1,1421 @@
+/*
+ Intel 386 emulator
+
+ Written by Ville Linde
+
+ Currently supports:
+ Intel 386
+ Intel 486
+ Intel Pentium
+ Cyrix MediaGX
+*/
+
+#include "debugger.h"
+#include "i386.h"
+#include "i386intf.h"
+
+#ifdef MAME_DEBUG
+#include "debug/debugcpu.h"
+#endif
+
+int i386_parity_table[256];
+MODRM_TABLE i386_MODRM_table[256];
+
+/*************************************************************************/
+
+#define INT_DEBUG 1
+
+static void i386_load_protected_mode_segment( I386_SREG *seg )
+{
+ UINT32 v1,v2;
+ UINT32 base, limit;
+ int entry;
+
+ if ( seg->selector & 0x4 )
+ {
+ base = I.ldtr.base;
+ limit = I.ldtr.limit;
+ } else {
+ base = I.gdtr.base;
+ limit = I.gdtr.limit;
+ }
+
+ if (limit == 0 || seg->selector + 7 > limit)
+ return;
+ entry = seg->selector & ~0x7;
+
+ v1 = READ32( base + entry );
+ v2 = READ32( base + entry + 4 );
+
+ seg->flags = (v2 >> 8) & 0xf0ff;
+ seg->base = (v2 & 0xff000000) | ((v2 & 0xff) << 16) | ((v1 >> 16) & 0xffff);
+ seg->limit = (v2 & 0xf0000) | (v1 & 0xffff);
+ if (seg->flags & 0x8000)
+ seg->limit = (seg->limit << 12) | 0xfff;
+ seg->d = (seg->flags & 0x4000) ? 1 : 0;
+}
+
+void i386_load_segment_descriptor( int segment )
+{
+ if (PROTECTED_MODE)
+ {
+ if (!V8086_MODE)
+ i386_load_protected_mode_segment( &I.sreg[segment] );
+ else
+ {
+ I.sreg[segment].base = I.sreg[segment].selector << 4;
+ I.sreg[segment].limit = 0xffff;
+ I.sreg[segment].flags = (segment == CS) ? 0x009a : 0x0092;
+ }
+ }
+ else
+ {
+ I.sreg[segment].base = I.sreg[segment].selector << 4;
+
+ if( segment == CS && !I.performed_intersegment_jump )
+ I.sreg[segment].base |= 0xfff00000;
+ }
+}
+
+static UINT32 get_flags(void)
+{
+ UINT32 f = 0x2;
+ f |= I.CF;
+ f |= I.PF << 2;
+ f |= I.AF << 4;
+ f |= I.ZF << 6;
+ f |= I.SF << 7;
+ f |= I.TF << 8;
+ f |= I.IF << 9;
+ f |= I.DF << 10;
+ f |= I.OF << 11;
+ return (I.eflags & 0xFFFF0000) | (f & 0xFFFF);
+}
+
+static void set_flags( UINT32 f )
+{
+ I.CF = (f & 0x1) ? 1 : 0;
+ I.PF = (f & 0x4) ? 1 : 0;
+ I.AF = (f & 0x10) ? 1 : 0;
+ I.ZF = (f & 0x40) ? 1 : 0;
+ I.SF = (f & 0x80) ? 1 : 0;
+ I.TF = (f & 0x100) ? 1 : 0;
+ I.IF = (f & 0x200) ? 1 : 0;
+ I.DF = (f & 0x400) ? 1 : 0;
+ I.OF = (f & 0x800) ? 1 : 0;
+}
+
+static void sib_byte(UINT8 mod, UINT32* out_ea, UINT8* out_segment)
+{
+ UINT32 ea = 0;
+ UINT8 segment = 0;
+ UINT8 scale, i, base;
+ UINT8 sib = FETCH();
+ scale = (sib >> 6) & 0x3;
+ i = (sib >> 3) & 0x7;
+ base = sib & 0x7;
+
+ switch( base )
+ {
+ case 0: ea = REG32(EAX); segment = DS; break;
+ case 1: ea = REG32(ECX); segment = DS; break;
+ case 2: ea = REG32(EDX); segment = DS; break;
+ case 3: ea = REG32(EBX); segment = DS; break;
+ case 4: ea = REG32(ESP); segment = SS; break;
+ case 5:
+ if( mod == 0 ) {
+ ea = FETCH32();
+ segment = DS;
+ } else if( mod == 1 ) {
+ ea = REG32(EBP);
+ segment = SS;
+ } else if( mod == 2 ) {
+ ea = REG32(EBP);
+ segment = SS;
+ }
+ break;
+ case 6: ea = REG32(ESI); segment = DS; break;
+ case 7: ea = REG32(EDI); segment = DS; break;
+ }
+ switch( i )
+ {
+ case 0: ea += REG32(EAX) * (1 << scale); break;
+ case 1: ea += REG32(ECX) * (1 << scale); break;
+ case 2: ea += REG32(EDX) * (1 << scale); break;
+ case 3: ea += REG32(EBX) * (1 << scale); break;
+ case 4: break;
+ case 5: ea += REG32(EBP) * (1 << scale); break;
+ case 6: ea += REG32(ESI) * (1 << scale); break;
+ case 7: ea += REG32(EDI) * (1 << scale); break;
+ }
+ *out_ea = ea;
+ *out_segment = segment;
+}
+
+static void modrm_to_EA(UINT8 mod_rm, UINT32* out_ea, UINT8* out_segment)
+{
+ INT8 disp8;
+ INT16 disp16;
+ INT32 disp32;
+ UINT8 mod = (mod_rm >> 6) & 0x3;
+ UINT8 rm = mod_rm & 0x7;
+ UINT32 ea;
+ UINT8 segment;
+
+ if( mod_rm >= 0xc0 )
+ fatalerror("i386: Called modrm_to_EA with modrm value %02X !",mod_rm);
+
+ if( I.address_size ) {
+ switch( rm )
+ {
+ default:
+ case 0: ea = REG32(EAX); segment = DS; break;
+ case 1: ea = REG32(ECX); segment = DS; break;
+ case 2: ea = REG32(EDX); segment = DS; break;
+ case 3: ea = REG32(EBX); segment = DS; break;
+ case 4: sib_byte( mod, &ea, &segment ); break;
+ case 5:
+ if( mod == 0 ) {
+ ea = FETCH32(); segment = DS;
+ } else {
+ ea = REG32(EBP); segment = SS;
+ }
+ break;
+ case 6: ea = REG32(ESI); segment = DS; break;
+ case 7: ea = REG32(EDI); segment = DS; break;
+ }
+ if( mod == 1 ) {
+ disp8 = FETCH();
+ ea += (INT32)disp8;
+ } else if( mod == 2 ) {
+ disp32 = FETCH32();
+ ea += disp32;
+ }
+
+ if( I.segment_prefix )
+ segment = I.segment_override;
+
+ *out_ea = ea;
+ *out_segment = segment;
+
+ } else {
+ switch( rm )
+ {
+ default:
+ case 0: ea = REG16(BX) + REG16(SI); segment = DS; break;
+ case 1: ea = REG16(BX) + REG16(DI); segment = DS; break;
+ case 2: ea = REG16(BP) + REG16(SI); segment = SS; break;
+ case 3: ea = REG16(BP) + REG16(DI); segment = SS; break;
+ case 4: ea = REG16(SI); segment = DS; break;
+ case 5: ea = REG16(DI); segment = DS; break;
+ case 6:
+ if( mod == 0 ) {
+ ea = FETCH16(); segment = DS;
+ } else {
+ ea = REG16(BP); segment = SS;
+ }
+ break;
+ case 7: ea = REG16(BX); segment = DS; break;
+ }
+ if( mod == 1 ) {
+ disp8 = FETCH();
+ ea += (INT32)disp8;
+ } else if( mod == 2 ) {
+ disp16 = FETCH16();
+ ea += (INT32)disp16;
+ }
+
+ if( I.segment_prefix )
+ segment = I.segment_override;
+
+ *out_ea = ea & 0xffff;
+ *out_segment = segment;
+ }
+}
+
+static UINT32 GetNonTranslatedEA(UINT8 modrm)
+{
+ UINT8 segment;
+ UINT32 ea;
+ modrm_to_EA( modrm, &ea, &segment );
+ return ea;
+}
+
+static UINT32 GetEA(UINT8 modrm)
+{
+ UINT8 segment;
+ UINT32 ea;
+ modrm_to_EA( modrm, &ea, &segment );
+ return i386_translate( segment, ea );
+}
+
+static void i386_trap(int irq, int irq_gate)
+{
+ /* I386 Interrupts/Traps/Faults:
+ *
+ * 0x00 Divide by zero
+ * 0x01 Debug exception
+ * 0x02 NMI
+ * 0x03 Int3
+ * 0x04 Overflow
+ * 0x05 Array bounds check
+ * 0x06 Illegal Opcode
+ * 0x07 FPU not available
+ * 0x08 Double fault
+ * 0x09 Coprocessor segment overrun
+ * 0x0a Invalid task state
+ * 0x0b Segment not present
+ * 0x0c Stack exception
+ * 0x0d General Protection Fault
+ * 0x0e Page fault
+ * 0x0f Reserved
+ * 0x10 Coprocessor error
+ */
+ UINT32 v1, v2;
+ UINT32 offset;
+ UINT16 segment;
+ int entry = irq * (I.sreg[CS].d ? 8 : 4);
+
+ /* Check if IRQ is out of IDTR's bounds */
+ if( entry > I.idtr.limit ) {
+ fatalerror("I386 Interrupt: IRQ out of IDTR bounds (IRQ: %d, IDTR Limit: %d)", irq, I.idtr.limit);
+ }
+
+ if( !I.sreg[CS].d )
+ {
+ /* 16-bit */
+ PUSH16( get_flags() & 0xffff );
+ PUSH16( I.sreg[CS].selector );
+ PUSH16( I.eip );
+
+ I.sreg[CS].selector = READ16( I.idtr.base + entry + 2 );
+ I.eip = READ16( I.idtr.base + entry );
+
+ /* Interrupts that vector through either interrupt gates or trap gates cause TF */
+ /* (the trap flag) to be reset after the current value of TF is saved on the stack as part of EFLAGS. */
+ I.TF = 0;
+
+ if (irq_gate)
+ {
+ I.IF = 0;
+ }
+
+ }
+ else
+ {
+ int type;
+ /* 32-bit */
+ PUSH32( get_flags() & 0x00fcffff );
+ PUSH32( I.sreg[CS].selector );
+ PUSH32( I.eip );
+
+ v1 = READ32( I.idtr.base + entry );
+ v2 = READ32( I.idtr.base + entry + 4 );
+ offset = (v2 & 0xffff0000) | (v1 & 0xffff);
+ segment = (v1 >> 16) & 0xffff;
+ type = (v2>>8) & 0x1F;
+
+ I.sreg[CS].selector = segment;
+ I.eip = offset;
+
+ /* Interrupts that vector through either interrupt gates or trap gates cause TF */
+ /* (the trap flag) to be reset after the current value of TF is saved on the stack as part of EFLAGS. */
+ if ((type == 14) || (type==15))
+ I.TF = 0;
+
+ if (type == 14)
+ {
+ I.IF = 0;
+ }
+
+ }
+
+ i386_load_segment_descriptor(CS);
+ CHANGE_PC(I.eip);
+
+}
+
+static void i386_check_irq_line(void)
+{
+ /* Check if the interrupts are enabled */
+ if ( (I.irq_state) && I.IF )
+ {
+ I.cycles -= 2;
+ i386_trap(I.irq_callback(0), 1);
+ }
+}
+
+#include "cycles.h"
+
+static UINT8 *cycle_table_rm[X86_NUM_CPUS];
+static UINT8 *cycle_table_pm[X86_NUM_CPUS];
+
+#define CYCLES_NUM(x) (I.cycles -= (x))
+
+INLINE void CYCLES(int x)
+{
+ if (PROTECTED_MODE)
+ {
+ I.cycles -= I.cycle_table_pm[x];
+ }
+ else
+ {
+ I.cycles -= I.cycle_table_rm[x];
+ }
+}
+
+INLINE void CYCLES_RM(int modrm, int r, int m)
+{
+ if (modrm >= 0xc0)
+ {
+ if (PROTECTED_MODE)
+ {
+ I.cycles -= I.cycle_table_pm[r];
+ }
+ else
+ {
+ I.cycles -= I.cycle_table_rm[r];
+ }
+ }
+ else
+ {
+ if (PROTECTED_MODE)
+ {
+ I.cycles -= I.cycle_table_pm[m];
+ }
+ else
+ {
+ I.cycles -= I.cycle_table_rm[m];
+ }
+ }
+}
+
+static void build_cycle_table(void)
+{
+ int i, j;
+ for (j=0; j < X86_NUM_CPUS; j++)
+ {
+ cycle_table_rm[j] = auto_malloc(sizeof(UINT8) * CYCLES_NUM_OPCODES);
+ cycle_table_pm[j] = auto_malloc(sizeof(UINT8) * CYCLES_NUM_OPCODES);
+
+ for (i=0; i < sizeof(x86_cycle_table)/sizeof(X86_CYCLE_TABLE); i++)
+ {
+ int opcode = x86_cycle_table[i].op;
+ cycle_table_rm[j][opcode] = x86_cycle_table[i].cpu_cycles[j][0];
+ cycle_table_pm[j][opcode] = x86_cycle_table[i].cpu_cycles[j][1];
+ }
+ }
+}
+
+/* Forward declarations */
+static void I386OP(decode_opcode)(void);
+static void I386OP(decode_two_byte)(void);
+
+
+
+#include "i386ops.c"
+#include "i386op16.c"
+#include "i386op32.c"
+#include "i486ops.c"
+#include "pentops.c"
+#include "x87ops.c"
+#include "i386ops.h"
+
+static void I386OP(decode_opcode)(void)
+{
+ I.opcode = FETCH();
+ if( I.operand_size )
+ I.opcode_table1_32[I.opcode]();
+ else
+ I.opcode_table1_16[I.opcode]();
+}
+
+/* Two-byte opcode prefix */
+static void I386OP(decode_two_byte)(void)
+{
+ I.opcode = FETCH();
+ if( I.operand_size )
+ I.opcode_table2_32[I.opcode]();
+ else
+ I.opcode_table2_16[I.opcode]();
+}
+
+/*************************************************************************/
+
+#ifdef MAME_DEBUG
+
+static UINT64 i386_debug_segbase(UINT32 ref, UINT32 params, UINT64 *param)
+{
+ UINT32 result;
+ I386_SREG seg;
+
+ if (PROTECTED_MODE)
+ {
+ memset(&seg, 0, sizeof(seg));
+ seg.selector = (UINT16) param[0];
+ i386_load_protected_mode_segment(&seg);
+ result = seg.base;
+ }
+ else
+ {
+ result = param[0] << 4;
+ }
+ return result;
+}
+
+static UINT64 i386_debug_seglimit(UINT32 ref, UINT32 params, UINT64 *param)
+{
+ UINT32 result = 0;
+ I386_SREG seg;
+
+ if (PROTECTED_MODE)
+ {
+ memset(&seg, 0, sizeof(seg));
+ seg.selector = (UINT16) param[0];
+ i386_load_protected_mode_segment(&seg);
+ result = seg.limit;
+ }
+ return result;
+}
+
+static void i386_debug_setup(void)
+{
+ symtable_add_function(global_symtable, "segbase", 0, 1, 1, i386_debug_segbase);
+ symtable_add_function(global_symtable, "seglimit", 0, 1, 1, i386_debug_seglimit);
+}
+
+#endif /* defined(MAME_DEBUG) */
+
+/*************************************************************************/
+
+static void i386_postload(void)
+{
+ int i;
+ for (i = 0; i < 6; i++)
+ i386_load_segment_descriptor(i);
+ CHANGE_PC(I.eip);
+}
+
+void i386_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int i, j;
+ static const int regs8[8] = {AL,CL,DL,BL,AH,CH,DH,BH};
+ static const int regs16[8] = {AX,CX,DX,BX,SP,BP,SI,DI};
+ static const int regs32[8] = {EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI};
+ static const char state_type[] = "I386";
+
+ build_cycle_table();
+
+ for( i=0; i < 256; i++ ) {
+ int c=0;
+ for( j=0; j < 8; j++ ) {
+ if( i & (1 << j) )
+ c++;
+ }
+ i386_parity_table[i] = ~(c & 0x1) & 0x1;
+ }
+
+ for( i=0; i < 256; i++ ) {
+ i386_MODRM_table[i].reg.b = regs8[(i >> 3) & 0x7];
+ i386_MODRM_table[i].reg.w = regs16[(i >> 3) & 0x7];
+ i386_MODRM_table[i].reg.d = regs32[(i >> 3) & 0x7];
+
+ i386_MODRM_table[i].rm.b = regs8[i & 0x7];
+ i386_MODRM_table[i].rm.w = regs16[i & 0x7];
+ i386_MODRM_table[i].rm.d = regs32[i & 0x7];
+ }
+
+ I.irq_callback = irqcallback;
+
+ state_save_register_item_array(state_type, index, I.reg.d);
+ state_save_register_item(state_type, index, I.sreg[ES].selector);
+ state_save_register_item(state_type, index, I.sreg[ES].base);
+ state_save_register_item(state_type, index, I.sreg[ES].limit);
+ state_save_register_item(state_type, index, I.sreg[ES].flags);
+ state_save_register_item(state_type, index, I.sreg[CS].selector);
+ state_save_register_item(state_type, index, I.sreg[CS].base);
+ state_save_register_item(state_type, index, I.sreg[CS].limit);
+ state_save_register_item(state_type, index, I.sreg[CS].flags);
+ state_save_register_item(state_type, index, I.sreg[SS].selector);
+ state_save_register_item(state_type, index, I.sreg[SS].base);
+ state_save_register_item(state_type, index, I.sreg[SS].limit);
+ state_save_register_item(state_type, index, I.sreg[SS].flags);
+ state_save_register_item(state_type, index, I.sreg[DS].selector);
+ state_save_register_item(state_type, index, I.sreg[DS].base);
+ state_save_register_item(state_type, index, I.sreg[DS].limit);
+ state_save_register_item(state_type, index, I.sreg[DS].flags);
+ state_save_register_item(state_type, index, I.sreg[FS].selector);
+ state_save_register_item(state_type, index, I.sreg[FS].base);
+ state_save_register_item(state_type, index, I.sreg[FS].limit);
+ state_save_register_item(state_type, index, I.sreg[FS].flags);
+ state_save_register_item(state_type, index, I.sreg[GS].selector);
+ state_save_register_item(state_type, index, I.sreg[GS].base);
+ state_save_register_item(state_type, index, I.sreg[GS].limit);
+ state_save_register_item(state_type, index, I.sreg[GS].flags);
+ state_save_register_item(state_type, index, I.eip);
+ state_save_register_item(state_type, index, I.prev_eip);
+ state_save_register_item(state_type, index, I.CF);
+ state_save_register_item(state_type, index, I.DF);
+ state_save_register_item(state_type, index, I.SF);
+ state_save_register_item(state_type, index, I.OF);
+ state_save_register_item(state_type, index, I.ZF);
+ state_save_register_item(state_type, index, I.PF);
+ state_save_register_item(state_type, index, I.AF);
+ state_save_register_item(state_type, index, I.IF);
+ state_save_register_item(state_type, index, I.TF);
+ state_save_register_item_array(state_type, index, I.cr);
+ state_save_register_item_array(state_type, index, I.dr);
+ state_save_register_item_array(state_type, index, I.tr);
+ state_save_register_item(state_type, index, I.idtr.base);
+ state_save_register_item(state_type, index, I.idtr.limit);
+ state_save_register_item(state_type, index, I.gdtr.base);
+ state_save_register_item(state_type, index, I.gdtr.limit);
+ state_save_register_item(state_type, index, I.task.base);
+ state_save_register_item(state_type, index, I.task.segment);
+ state_save_register_item(state_type, index, I.task.limit);
+ state_save_register_item(state_type, index, I.task.flags);
+ state_save_register_item(state_type, index, I.ldtr.base);
+ state_save_register_item(state_type, index, I.ldtr.segment);
+ state_save_register_item(state_type, index, I.ldtr.limit);
+ state_save_register_item(state_type, index, I.ldtr.flags);
+ state_save_register_item(state_type, index, I.irq_state);
+ state_save_register_item(state_type, index, I.performed_intersegment_jump);
+ state_save_register_func_postload(i386_postload);
+}
+
+static void build_opcode_table(UINT32 features)
+{
+ int i;
+ for (i=0; i < 256; i++)
+ {
+ I.opcode_table1_16[i] = I386OP(invalid);
+ I.opcode_table1_32[i] = I386OP(invalid);
+ I.opcode_table2_16[i] = I386OP(invalid);
+ I.opcode_table2_32[i] = I386OP(invalid);
+ }
+
+ for (i=0; i < sizeof(x86_opcode_table)/sizeof(X86_OPCODE); i++)
+ {
+ const X86_OPCODE *op = &x86_opcode_table[i];
+
+ if ((op->flags & features))
+ {
+ if (op->flags & OP_2BYTE)
+ {
+ I.opcode_table2_32[op->opcode] = op->handler32;
+ I.opcode_table2_16[op->opcode] = op->handler16;
+ }
+ else
+ {
+ I.opcode_table1_32[op->opcode] = op->handler32;
+ I.opcode_table1_16[op->opcode] = op->handler16;
+ }
+ }
+ }
+}
+
+void i386_reset(void)
+{
+ int (*save_irqcallback)(int);
+
+ save_irqcallback = I.irq_callback;
+ memset( &I, 0, sizeof(I386_REGS) );
+ I.irq_callback = save_irqcallback;
+
+ I.sreg[CS].selector = 0xf000;
+ I.sreg[CS].base = 0xffff0000;
+ I.sreg[CS].limit = 0xffff;
+
+ I.sreg[DS].base = I.sreg[ES].base = I.sreg[FS].base = I.sreg[GS].base = I.sreg[SS].base = 0x00000000;
+ I.sreg[DS].limit = I.sreg[ES].limit = I.sreg[FS].limit = I.sreg[GS].limit = I.sreg[SS].limit = 0xffff;
+ I.sreg[DS].flags = I.sreg[ES].flags = I.sreg[FS].flags = I.sreg[GS].flags = I.sreg[SS].flags = 0x0092;
+
+ I.idtr.base = 0;
+ I.idtr.limit = 0x3ff;
+
+ I.a20_mask = ~0;
+
+ I.cr[0] = 0;
+ I.eflags = 0;
+ I.eip = 0xfff0;
+
+ REG32(EAX) = 0x0308; // Intel 386, stepping D1
+ REG32(EDX) = 0;
+
+ build_opcode_table(OP_I386);
+ I.cycle_table_rm = cycle_table_rm[CPU_CYCLES_I386];
+ I.cycle_table_pm = cycle_table_pm[CPU_CYCLES_I386];
+
+ CHANGE_PC(I.eip);
+}
+
+static void i386_get_context(void *dst)
+{
+ if(dst) {
+ *(I386_REGS *)dst = I;
+ }
+}
+
+static void i386_set_context(void *src)
+{
+ if(src) {
+ I = *(I386_REGS *)src;
+ }
+
+ CHANGE_PC(I.eip);
+}
+
+static void i386_set_irq_line(int irqline, int state)
+{
+ if (state != CLEAR_LINE && I.halted)
+ {
+ I.halted = 0;
+ }
+
+ if ( irqline == INPUT_LINE_NMI )
+ {
+ /* NMI (I do not think that this is 100% right) */
+ if ( state )
+ i386_trap(2, 1);
+ }
+ else
+ {
+ I.irq_state = state;
+ }
+}
+
+static void i386_set_a20_line(int state)
+{
+ if (state)
+ {
+ I.a20_mask = ~0;
+ }
+ else
+ {
+ I.a20_mask = ~(1 << 20);
+ }
+}
+
+int i386_execute(int num_cycles)
+{
+ I.cycles = num_cycles;
+ I.base_cycles = num_cycles;
+ CHANGE_PC(I.eip);
+
+ if (I.halted)
+ {
+ I.tsc += num_cycles;
+ return num_cycles;
+ }
+
+ while( I.cycles > 0 )
+ {
+ I.operand_size = I.sreg[CS].d;
+ I.address_size = I.sreg[CS].d;
+
+ I.segment_prefix = 0;
+ I.prev_eip = I.eip;
+
+ CALL_MAME_DEBUG;
+
+ i386_check_irq_line();
+ I386OP(decode_opcode)();
+ }
+ I.tsc += (num_cycles - I.cycles);
+
+ return num_cycles - I.cycles;
+}
+
+/*************************************************************************/
+
+static int translate_address_cb(int space, offs_t *addr)
+{
+ int result = 1;
+ if (space == ADDRESS_SPACE_PROGRAM)
+ {
+ if (I.cr[0] & 0x80000000)
+ result = translate_address(addr);
+ *addr &= I.a20_mask;
+ }
+ return result;
+}
+
+#ifdef MAME_DEBUG
+static offs_t i386_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return i386_dasm_one(buffer, pc, oprom, I.sreg[CS].d ? 32 : 16);
+}
+#endif /* MAME_DEBUG */
+
+static void i386_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state == CPUINFO_INT_INPUT_STATE+INPUT_LINE_A20)
+ {
+ i386_set_a20_line(info->i);
+ return;
+ }
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + MAX_INPUT_LINES)
+ {
+ i386_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I386_PC: I.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_EIP: I.eip = info->i; CHANGE_PC(I.eip); break;
+ case CPUINFO_INT_REGISTER + I386_AL: REG8(AL) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_AH: REG8(AH) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_BL: REG8(BL) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_BH: REG8(BH) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_CL: REG8(CL) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_CH: REG8(CH) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DL: REG8(DL) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DH: REG8(DH) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_AX: REG16(AX) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_BX: REG16(BX) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_CX: REG16(CX) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DX: REG16(DX) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_SI: REG16(SI) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DI: REG16(DI) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_BP: REG16(BP) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_SP: REG16(SP) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_IP: I.eip = (I.eip & ~0xFFFF) | (info->i & 0xFFFF); CHANGE_PC(I.eip); break;
+ case CPUINFO_INT_REGISTER + I386_EAX: REG32(EAX) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_EBX: REG32(EBX) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_ECX: REG32(ECX) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_EDX: REG32(EDX) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_EBP: REG32(EBP) = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + I386_ESP: REG32(ESP) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_ESI: REG32(ESI) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_EDI: REG32(EDI) = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_EFLAGS: I.eflags = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_CS: I.sreg[CS].selector = info->i & 0xffff; i386_load_segment_descriptor(CS); break;
+ case CPUINFO_INT_REGISTER + I386_CS_BASE: I.sreg[CS].base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_CS_LIMIT: I.sreg[CS].limit = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_CS_FLAGS: I.sreg[CS].flags = info->i & 0xf0ff; break;
+ case CPUINFO_INT_REGISTER + I386_SS: I.sreg[SS].selector = info->i & 0xffff; i386_load_segment_descriptor(SS); break;
+ case CPUINFO_INT_REGISTER + I386_SS_BASE: I.sreg[SS].base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_SS_LIMIT: I.sreg[SS].limit = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_SS_FLAGS: I.sreg[SS].flags = info->i & 0xf0ff; break;
+ case CPUINFO_INT_REGISTER + I386_DS: I.sreg[DS].selector = info->i & 0xffff; i386_load_segment_descriptor(DS); break;
+ case CPUINFO_INT_REGISTER + I386_DS_BASE: I.sreg[DS].base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DS_LIMIT: I.sreg[DS].limit = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DS_FLAGS: I.sreg[DS].flags = info->i & 0xf0ff; break;
+ case CPUINFO_INT_REGISTER + I386_ES: I.sreg[ES].selector = info->i & 0xffff; i386_load_segment_descriptor(ES); break;
+ case CPUINFO_INT_REGISTER + I386_ES_BASE: I.sreg[ES].base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_ES_LIMIT: I.sreg[ES].limit = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_ES_FLAGS: I.sreg[ES].flags = info->i & 0xf0ff; break;
+ case CPUINFO_INT_REGISTER + I386_FS: I.sreg[FS].selector = info->i & 0xffff; i386_load_segment_descriptor(FS); break;
+ case CPUINFO_INT_REGISTER + I386_FS_BASE: I.sreg[FS].base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_FS_LIMIT: I.sreg[FS].limit = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_FS_FLAGS: I.sreg[FS].flags = info->i & 0xf0ff; break;
+ case CPUINFO_INT_REGISTER + I386_GS: I.sreg[GS].selector = info->i & 0xffff; i386_load_segment_descriptor(GS); break;
+ case CPUINFO_INT_REGISTER + I386_GS_BASE: I.sreg[GS].base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_GS_LIMIT: I.sreg[GS].limit = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_GS_FLAGS: I.sreg[GS].flags = info->i & 0xf0ff; break;
+ case CPUINFO_INT_REGISTER + I386_CR0: I.cr[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_CR1: I.cr[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_CR2: I.cr[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_CR3: I.cr[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DR0: I.dr[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DR1: I.dr[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DR2: I.dr[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DR3: I.dr[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DR4: I.dr[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DR5: I.dr[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DR6: I.dr[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_DR7: I.dr[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_TR6: I.tr[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_TR7: I.tr[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_GDTR_BASE: I.gdtr.base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_GDTR_LIMIT: I.gdtr.limit = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + I386_IDTR_BASE: I.idtr.base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_IDTR_LIMIT: I.idtr.limit = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + I386_TR: I.task.segment = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + I386_TR_BASE: I.task.base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_TR_LIMIT: I.task.limit = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_TR_FLAGS: I.task.flags = info->i & 0xf0ff; break;
+ case CPUINFO_INT_REGISTER + I386_LDTR: I.ldtr.segment = info->i & 0xffff; break;
+ case CPUINFO_INT_REGISTER + I386_LDTR_BASE: I.ldtr.base = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_LDTR_LIMIT: I.ldtr.limit = info->i; break;
+ case CPUINFO_INT_REGISTER + I386_LDTR_FLAGS: I.ldtr.flags = info->i & 0xf0ff; break;
+ }
+}
+
+void i386_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(I386_REGS); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 32; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 15; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 12; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I386_PC: info->i = I.pc; break;
+ case CPUINFO_INT_REGISTER + I386_EIP: info->i = I.eip; break;
+ case CPUINFO_INT_REGISTER + I386_AL: info->i = REG8(AL); break;
+ case CPUINFO_INT_REGISTER + I386_AH: info->i = REG8(AH); break;
+ case CPUINFO_INT_REGISTER + I386_BL: info->i = REG8(BL); break;
+ case CPUINFO_INT_REGISTER + I386_BH: info->i = REG8(BH); break;
+ case CPUINFO_INT_REGISTER + I386_CL: info->i = REG8(CL); break;
+ case CPUINFO_INT_REGISTER + I386_CH: info->i = REG8(CH); break;
+ case CPUINFO_INT_REGISTER + I386_DL: info->i = REG8(DL); break;
+ case CPUINFO_INT_REGISTER + I386_DH: info->i = REG8(DH); break;
+ case CPUINFO_INT_REGISTER + I386_AX: info->i = REG16(AX); break;
+ case CPUINFO_INT_REGISTER + I386_BX: info->i = REG16(BX); break;
+ case CPUINFO_INT_REGISTER + I386_CX: info->i = REG16(CX); break;
+ case CPUINFO_INT_REGISTER + I386_DX: info->i = REG16(DX); break;
+ case CPUINFO_INT_REGISTER + I386_SI: info->i = REG16(SI); break;
+ case CPUINFO_INT_REGISTER + I386_DI: info->i = REG16(DI); break;
+ case CPUINFO_INT_REGISTER + I386_BP: info->i = REG16(BP); break;
+ case CPUINFO_INT_REGISTER + I386_SP: info->i = REG16(SP); break;
+ case CPUINFO_INT_REGISTER + I386_IP: info->i = I.eip & 0xFFFF; break;
+ case CPUINFO_INT_REGISTER + I386_EAX: info->i = REG32(EAX); break;
+ case CPUINFO_INT_REGISTER + I386_EBX: info->i = REG32(EBX); break;
+ case CPUINFO_INT_REGISTER + I386_ECX: info->i = REG32(ECX); break;
+ case CPUINFO_INT_REGISTER + I386_EDX: info->i = REG32(EDX); break;
+ case CPUINFO_INT_REGISTER + I386_EBP: info->i = REG32(EBP); break;
+ case CPUINFO_INT_REGISTER + I386_ESP: info->i = REG32(ESP); break;
+ case CPUINFO_INT_REGISTER + I386_ESI: info->i = REG32(ESI); break;
+ case CPUINFO_INT_REGISTER + I386_EDI: info->i = REG32(EDI); break;
+ case CPUINFO_INT_REGISTER + I386_EFLAGS: info->i = I.eflags; break;
+ case CPUINFO_INT_REGISTER + I386_CS: info->i = I.sreg[CS].selector; break;
+ case CPUINFO_INT_REGISTER + I386_CS_BASE: info->i = I.sreg[CS].base; break;
+ case CPUINFO_INT_REGISTER + I386_CS_LIMIT: info->i = I.sreg[CS].limit; break;
+ case CPUINFO_INT_REGISTER + I386_CS_FLAGS: info->i = I.sreg[CS].flags; break;
+ case CPUINFO_INT_REGISTER + I386_SS: info->i = I.sreg[SS].selector; break;
+ case CPUINFO_INT_REGISTER + I386_SS_BASE: info->i = I.sreg[SS].base; break;
+ case CPUINFO_INT_REGISTER + I386_SS_LIMIT: info->i = I.sreg[SS].limit; break;
+ case CPUINFO_INT_REGISTER + I386_SS_FLAGS: info->i = I.sreg[SS].flags; break;
+ case CPUINFO_INT_REGISTER + I386_DS: info->i = I.sreg[DS].selector; break;
+ case CPUINFO_INT_REGISTER + I386_DS_BASE: info->i = I.sreg[DS].base; break;
+ case CPUINFO_INT_REGISTER + I386_DS_LIMIT: info->i = I.sreg[DS].limit; break;
+ case CPUINFO_INT_REGISTER + I386_DS_FLAGS: info->i = I.sreg[DS].flags; break;
+ case CPUINFO_INT_REGISTER + I386_ES: info->i = I.sreg[ES].selector; break;
+ case CPUINFO_INT_REGISTER + I386_ES_BASE: info->i = I.sreg[ES].base; break;
+ case CPUINFO_INT_REGISTER + I386_ES_LIMIT: info->i = I.sreg[ES].limit; break;
+ case CPUINFO_INT_REGISTER + I386_ES_FLAGS: info->i = I.sreg[ES].flags; break;
+ case CPUINFO_INT_REGISTER + I386_FS: info->i = I.sreg[FS].selector; break;
+ case CPUINFO_INT_REGISTER + I386_FS_BASE: info->i = I.sreg[FS].base; break;
+ case CPUINFO_INT_REGISTER + I386_FS_LIMIT: info->i = I.sreg[FS].limit; break;
+ case CPUINFO_INT_REGISTER + I386_FS_FLAGS: info->i = I.sreg[FS].flags; break;
+ case CPUINFO_INT_REGISTER + I386_GS: info->i = I.sreg[GS].selector; break;
+ case CPUINFO_INT_REGISTER + I386_GS_BASE: info->i = I.sreg[GS].base; break;
+ case CPUINFO_INT_REGISTER + I386_GS_LIMIT: info->i = I.sreg[GS].limit; break;
+ case CPUINFO_INT_REGISTER + I386_GS_FLAGS: info->i = I.sreg[GS].flags; break;
+ case CPUINFO_INT_REGISTER + I386_CR0: info->i = I.cr[0]; break;
+ case CPUINFO_INT_REGISTER + I386_CR1: info->i = I.cr[1]; break;
+ case CPUINFO_INT_REGISTER + I386_CR2: info->i = I.cr[2]; break;
+ case CPUINFO_INT_REGISTER + I386_CR3: info->i = I.cr[3]; break;
+ case CPUINFO_INT_REGISTER + I386_DR0: info->i = I.dr[0]; break;
+ case CPUINFO_INT_REGISTER + I386_DR1: info->i = I.dr[1]; break;
+ case CPUINFO_INT_REGISTER + I386_DR2: info->i = I.dr[2]; break;
+ case CPUINFO_INT_REGISTER + I386_DR3: info->i = I.dr[3]; break;
+ case CPUINFO_INT_REGISTER + I386_DR4: info->i = I.dr[4]; break;
+ case CPUINFO_INT_REGISTER + I386_DR5: info->i = I.dr[5]; break;
+ case CPUINFO_INT_REGISTER + I386_DR6: info->i = I.dr[6]; break;
+ case CPUINFO_INT_REGISTER + I386_DR7: info->i = I.dr[7]; break;
+ case CPUINFO_INT_REGISTER + I386_TR6: info->i = I.tr[6]; break;
+ case CPUINFO_INT_REGISTER + I386_TR7: info->i = I.tr[7]; break;
+ case CPUINFO_INT_REGISTER + I386_GDTR_BASE: info->i = I.gdtr.base; break;
+ case CPUINFO_INT_REGISTER + I386_GDTR_LIMIT: info->i = I.gdtr.limit; break;
+ case CPUINFO_INT_REGISTER + I386_IDTR_BASE: info->i = I.idtr.base; break;
+ case CPUINFO_INT_REGISTER + I386_IDTR_LIMIT: info->i = I.idtr.limit; break;
+ case CPUINFO_INT_REGISTER + I386_TR: info->i = I.task.segment; break;
+ case CPUINFO_INT_REGISTER + I386_TR_BASE: info->i = I.task.base; break;
+ case CPUINFO_INT_REGISTER + I386_TR_LIMIT: info->i = I.task.limit; break;
+ case CPUINFO_INT_REGISTER + I386_TR_FLAGS: info->i = I.task.flags; break;
+ case CPUINFO_INT_REGISTER + I386_LDTR: info->i = I.ldtr.segment; break;
+ case CPUINFO_INT_REGISTER + I386_LDTR_BASE: info->i = I.ldtr.base; break;
+ case CPUINFO_INT_REGISTER + I386_LDTR_LIMIT: info->i = I.ldtr.limit; break;
+ case CPUINFO_INT_REGISTER + I386_LDTR_FLAGS: info->i = I.ldtr.flags; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i386_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i386_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i386_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i386_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i386_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i386_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &I.cycles; break;
+ case CPUINFO_PTR_TRANSLATE: info->translate = translate_address_cb; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = i386_dasm; break;
+ case CPUINFO_PTR_DEBUG_SETUP_COMMANDS: info->setup_commands = i386_debug_setup; break;
+#endif
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "I386"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel 386"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2003-2004 Ville Linde"); break;
+
+ case CPUINFO_STR_FLAGS: sprintf(info->s, "%08X", get_flags()); break;
+
+ case CPUINFO_STR_REGISTER + I386_PC: sprintf(info->s, "PC: %08X", I.pc); break;
+ case CPUINFO_STR_REGISTER + I386_EIP: sprintf(info->s, "EIP: %08X", I.eip); break;
+ case CPUINFO_STR_REGISTER + I386_AL: sprintf(info->s, "~AL: %02X", REG8(AL)); break;
+ case CPUINFO_STR_REGISTER + I386_AH: sprintf(info->s, "~AH: %02X", REG8(AH)); break;
+ case CPUINFO_STR_REGISTER + I386_BL: sprintf(info->s, "~BL: %02X", REG8(BL)); break;
+ case CPUINFO_STR_REGISTER + I386_BH: sprintf(info->s, "~BH: %02X", REG8(BH)); break;
+ case CPUINFO_STR_REGISTER + I386_CL: sprintf(info->s, "~CL: %02X", REG8(CL)); break;
+ case CPUINFO_STR_REGISTER + I386_CH: sprintf(info->s, "~CH: %02X", REG8(CH)); break;
+ case CPUINFO_STR_REGISTER + I386_DL: sprintf(info->s, "~DL: %02X", REG8(DL)); break;
+ case CPUINFO_STR_REGISTER + I386_DH: sprintf(info->s, "~DH: %02X", REG8(DH)); break;
+ case CPUINFO_STR_REGISTER + I386_AX: sprintf(info->s, "~AX: %04X", REG16(AX)); break;
+ case CPUINFO_STR_REGISTER + I386_BX: sprintf(info->s, "~BX: %04X", REG16(BX)); break;
+ case CPUINFO_STR_REGISTER + I386_CX: sprintf(info->s, "~CX: %04X", REG16(CX)); break;
+ case CPUINFO_STR_REGISTER + I386_DX: sprintf(info->s, "~DX: %04X", REG16(DX)); break;
+ case CPUINFO_STR_REGISTER + I386_SI: sprintf(info->s, "~SI: %04X", REG16(SI)); break;
+ case CPUINFO_STR_REGISTER + I386_DI: sprintf(info->s, "~DI: %04X", REG16(DI)); break;
+ case CPUINFO_STR_REGISTER + I386_BP: sprintf(info->s, "~BP: %04X", REG16(BP)); break;
+ case CPUINFO_STR_REGISTER + I386_SP: sprintf(info->s, "~SP: %04X", REG16(SP)); break;
+ case CPUINFO_STR_REGISTER + I386_IP: sprintf(info->s, "~IP: %04X", I.eip & 0xFFFF); break;
+ case CPUINFO_STR_REGISTER + I386_EAX: sprintf(info->s, "EAX: %08X", I.reg.d[EAX]); break;
+ case CPUINFO_STR_REGISTER + I386_EBX: sprintf(info->s, "EBX: %08X", I.reg.d[EBX]); break;
+ case CPUINFO_STR_REGISTER + I386_ECX: sprintf(info->s, "ECX: %08X", I.reg.d[ECX]); break;
+ case CPUINFO_STR_REGISTER + I386_EDX: sprintf(info->s, "EDX: %08X", I.reg.d[EDX]); break;
+ case CPUINFO_STR_REGISTER + I386_EBP: sprintf(info->s, "EBP: %08X", I.reg.d[EBP]); break;
+ case CPUINFO_STR_REGISTER + I386_ESP: sprintf(info->s, "ESP: %08X", I.reg.d[ESP]); break;
+ case CPUINFO_STR_REGISTER + I386_ESI: sprintf(info->s, "ESI: %08X", I.reg.d[ESI]); break;
+ case CPUINFO_STR_REGISTER + I386_EDI: sprintf(info->s, "EDI: %08X", I.reg.d[EDI]); break;
+ case CPUINFO_STR_REGISTER + I386_EFLAGS: sprintf(info->s, "EFLAGS: %08X", I.eflags); break;
+ case CPUINFO_STR_REGISTER + I386_CS: sprintf(info->s, "CS: %04X", I.sreg[CS].selector); break;
+ case CPUINFO_STR_REGISTER + I386_CS_BASE: sprintf(info->s, "CSBASE: %08X", I.sreg[CS].base); break;
+ case CPUINFO_STR_REGISTER + I386_CS_LIMIT: sprintf(info->s, "CSLIMIT: %08X", I.sreg[CS].limit); break;
+ case CPUINFO_STR_REGISTER + I386_CS_FLAGS: sprintf(info->s, "CSFLAGS: %04X", I.sreg[CS].flags); break;
+ case CPUINFO_STR_REGISTER + I386_SS: sprintf(info->s, "SS: %04X", I.sreg[SS].selector); break;
+ case CPUINFO_STR_REGISTER + I386_SS_BASE: sprintf(info->s, "SSBASE: %08X", I.sreg[SS].base); break;
+ case CPUINFO_STR_REGISTER + I386_SS_LIMIT: sprintf(info->s, "SSLIMIT: %08X", I.sreg[SS].limit); break;
+ case CPUINFO_STR_REGISTER + I386_SS_FLAGS: sprintf(info->s, "SSFLAGS: %04X", I.sreg[SS].flags); break;
+ case CPUINFO_STR_REGISTER + I386_DS: sprintf(info->s, "DS: %04X", I.sreg[DS].selector); break;
+ case CPUINFO_STR_REGISTER + I386_DS_BASE: sprintf(info->s, "DSBASE: %08X", I.sreg[DS].base); break;
+ case CPUINFO_STR_REGISTER + I386_DS_LIMIT: sprintf(info->s, "DSLIMIT: %08X", I.sreg[DS].limit); break;
+ case CPUINFO_STR_REGISTER + I386_DS_FLAGS: sprintf(info->s, "DSFLAGS: %04X", I.sreg[DS].flags); break;
+ case CPUINFO_STR_REGISTER + I386_ES: sprintf(info->s, "ES: %04X", I.sreg[ES].selector); break;
+ case CPUINFO_STR_REGISTER + I386_ES_BASE: sprintf(info->s, "ESBASE: %08X", I.sreg[ES].base); break;
+ case CPUINFO_STR_REGISTER + I386_ES_LIMIT: sprintf(info->s, "ESLIMIT: %08X", I.sreg[ES].limit); break;
+ case CPUINFO_STR_REGISTER + I386_ES_FLAGS: sprintf(info->s, "ESFLAGS: %04X", I.sreg[ES].flags); break;
+ case CPUINFO_STR_REGISTER + I386_FS: sprintf(info->s, "FS: %04X", I.sreg[FS].selector); break;
+ case CPUINFO_STR_REGISTER + I386_FS_BASE: sprintf(info->s, "FSBASE: %08X", I.sreg[FS].base); break;
+ case CPUINFO_STR_REGISTER + I386_FS_LIMIT: sprintf(info->s, "FSLIMIT: %08X", I.sreg[FS].limit); break;
+ case CPUINFO_STR_REGISTER + I386_FS_FLAGS: sprintf(info->s, "FSFLAGS: %04X", I.sreg[FS].flags); break;
+ case CPUINFO_STR_REGISTER + I386_GS: sprintf(info->s, "GS: %04X", I.sreg[GS].selector); break;
+ case CPUINFO_STR_REGISTER + I386_GS_BASE: sprintf(info->s, "GSBASE: %08X", I.sreg[GS].base); break;
+ case CPUINFO_STR_REGISTER + I386_GS_LIMIT: sprintf(info->s, "GSLIMIT: %08X", I.sreg[GS].limit); break;
+ case CPUINFO_STR_REGISTER + I386_GS_FLAGS: sprintf(info->s, "GSFLAGS: %04X", I.sreg[GS].flags); break;
+ case CPUINFO_STR_REGISTER + I386_CR0: sprintf(info->s, "CR0: %08X", I.cr[0]); break;
+ case CPUINFO_STR_REGISTER + I386_CR1: sprintf(info->s, "CR1: %08X", I.cr[1]); break;
+ case CPUINFO_STR_REGISTER + I386_CR2: sprintf(info->s, "CR2: %08X", I.cr[2]); break;
+ case CPUINFO_STR_REGISTER + I386_CR3: sprintf(info->s, "CR3: %08X", I.cr[3]); break;
+ case CPUINFO_STR_REGISTER + I386_DR0: sprintf(info->s, "DR0: %08X", I.dr[0]); break;
+ case CPUINFO_STR_REGISTER + I386_DR1: sprintf(info->s, "DR1: %08X", I.dr[1]); break;
+ case CPUINFO_STR_REGISTER + I386_DR2: sprintf(info->s, "DR2: %08X", I.dr[2]); break;
+ case CPUINFO_STR_REGISTER + I386_DR3: sprintf(info->s, "DR3: %08X", I.dr[3]); break;
+ case CPUINFO_STR_REGISTER + I386_DR4: sprintf(info->s, "DR4: %08X", I.dr[4]); break;
+ case CPUINFO_STR_REGISTER + I386_DR5: sprintf(info->s, "DR5: %08X", I.dr[5]); break;
+ case CPUINFO_STR_REGISTER + I386_DR6: sprintf(info->s, "DR6: %08X", I.dr[6]); break;
+ case CPUINFO_STR_REGISTER + I386_DR7: sprintf(info->s, "DR7: %08X", I.dr[7]); break;
+ case CPUINFO_STR_REGISTER + I386_TR6: sprintf(info->s, "TR6: %08X", I.tr[6]); break;
+ case CPUINFO_STR_REGISTER + I386_TR7: sprintf(info->s, "TR7: %08X", I.tr[7]); break;
+ case CPUINFO_STR_REGISTER + I386_GDTR_BASE: sprintf(info->s, "GDTRBASE: %08X", I.gdtr.base); break;
+ case CPUINFO_STR_REGISTER + I386_GDTR_LIMIT: sprintf(info->s, "GDTRLIMIT: %04X", I.gdtr.limit); break;
+ case CPUINFO_STR_REGISTER + I386_IDTR_BASE: sprintf(info->s, "IDTRBASE: %08X", I.idtr.base); break;
+ case CPUINFO_STR_REGISTER + I386_IDTR_LIMIT: sprintf(info->s, "IDTRLIMIT: %04X", I.idtr.limit); break;
+ case CPUINFO_STR_REGISTER + I386_LDTR: sprintf(info->s, "LDTR: %04X", I.ldtr.segment); break;
+ case CPUINFO_STR_REGISTER + I386_LDTR_BASE: sprintf(info->s, "LDTRBASE: %08X", I.ldtr.base); break;
+ case CPUINFO_STR_REGISTER + I386_LDTR_LIMIT: sprintf(info->s, "LDTRLIMIT: %08X", I.ldtr.limit); break;
+ case CPUINFO_STR_REGISTER + I386_LDTR_FLAGS: sprintf(info->s, "LDTRFLAGS: %04X", I.ldtr.flags); break;
+ case CPUINFO_STR_REGISTER + I386_TR: sprintf(info->s, "TR: %04X", I.task.segment); break;
+ case CPUINFO_STR_REGISTER + I386_TR_BASE: sprintf(info->s, "TRBASE: %08X", I.task.base); break;
+ case CPUINFO_STR_REGISTER + I386_TR_LIMIT: sprintf(info->s, "TRLIMIT: %08X", I.task.limit); break;
+ case CPUINFO_STR_REGISTER + I386_TR_FLAGS: sprintf(info->s, "TRFLAGS: %04X", I.task.flags); break;
+ }
+}
+
+/*****************************************************************************/
+/* Intel 486 */
+
+#if (HAS_I486)
+
+void i486_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ i386_init(index, clock, config, irqcallback);
+}
+
+static void i486_reset(void)
+{
+ int (*save_irqcallback)(int);
+
+ save_irqcallback = I.irq_callback;
+ memset( &I, 0, sizeof(I386_REGS) );
+ I.irq_callback = save_irqcallback;
+ I.sreg[CS].selector = 0xf000;
+ I.sreg[CS].base = 0xffff0000;
+ I.sreg[CS].limit = 0xffff;
+ I.sreg[CS].flags = 0x009b;
+
+ I.sreg[DS].base = I.sreg[ES].base = I.sreg[FS].base = I.sreg[GS].base = I.sreg[SS].base = 0x00000000;
+ I.sreg[DS].limit = I.sreg[ES].limit = I.sreg[FS].limit = I.sreg[GS].limit = I.sreg[SS].limit = 0xffff;
+ I.sreg[DS].flags = I.sreg[ES].flags = I.sreg[FS].flags = I.sreg[GS].flags = I.sreg[SS].flags = 0x0092;
+
+ I.idtr.base = 0;
+ I.idtr.limit = 0x3ff;
+
+ I.a20_mask = ~0;
+
+ I.cr[0] = 0;
+ I.eflags = 0;
+ I.eip = 0xfff0;
+
+ REG32(EAX) = 0x0308; // Intel 386, stepping D1
+ REG32(EDX) = 0;
+
+ build_opcode_table(OP_I386 | OP_FPU | OP_I486);
+ I.cycle_table_rm = cycle_table_rm[CPU_CYCLES_I486];
+ I.cycle_table_pm = cycle_table_pm[CPU_CYCLES_I486];
+
+ CHANGE_PC(I.eip);
+}
+
+static void i486_exit(void)
+{
+}
+
+static void i486_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_REGISTER + X87_CTRL: I.fpu_control_word = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_STATUS: I.fpu_status_word = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST0: ST(0).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST1: ST(1).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST2: ST(2).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST3: ST(3).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST4: ST(4).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST5: ST(5).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST6: ST(6).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST7: ST(7).f = info->i; break;
+
+ default: i386_set_info(state, info); break;
+ }
+}
+
+void i486_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i486_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = i486_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i486_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i486_exit; break;
+
+ case CPUINFO_INT_REGISTER + X87_CTRL: info->i = I.fpu_control_word; break;
+ case CPUINFO_INT_REGISTER + X87_STATUS: info->i = I.fpu_status_word; break;
+ case CPUINFO_INT_REGISTER + X87_ST0: info->i = ST(0).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST1: info->i = ST(1).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST2: info->i = ST(2).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST3: info->i = ST(3).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST4: info->i = ST(4).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST5: info->i = ST(5).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST6: info->i = ST(6).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST7: info->i = ST(7).f; break;
+
+ case CPUINFO_STR_NAME: strcpy(info->s, "I486"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel 486"); break;
+ case CPUINFO_STR_REGISTER + X87_CTRL: sprintf(info->s, "FPU_CW: %04X", I.fpu_control_word); break;
+ case CPUINFO_STR_REGISTER + X87_STATUS: sprintf(info->s, "FPU_SW: %04X", I.fpu_status_word); break;
+ case CPUINFO_STR_REGISTER + X87_ST0: sprintf(info->s, "ST0: %f", ST(0).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST1: sprintf(info->s, "ST1: %f", ST(1).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST2: sprintf(info->s, "ST2: %f", ST(2).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST3: sprintf(info->s, "ST3: %f", ST(3).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST4: sprintf(info->s, "ST4: %f", ST(4).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST5: sprintf(info->s, "ST5: %f", ST(5).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST6: sprintf(info->s, "ST6: %f", ST(6).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST7: sprintf(info->s, "ST7: %f", ST(7).f); break;
+
+ default: i386_get_info(state, info); break;
+ }
+}
+#endif
+
+/*****************************************************************************/
+/* Pentium */
+
+#if (HAS_PENTIUM)
+
+void pentium_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ i386_init(index, clock, config, irqcallback);
+}
+
+static void pentium_reset(void)
+{
+ int (*save_irqcallback)(int);
+
+ save_irqcallback = I.irq_callback;
+ memset( &I, 0, sizeof(I386_REGS) );
+ I.irq_callback = save_irqcallback;
+ I.sreg[CS].selector = 0xf000;
+ I.sreg[CS].base = 0xffff0000;
+ I.sreg[CS].limit = 0xffff;
+ I.sreg[CS].flags = 0x009b;
+
+ I.sreg[DS].base = I.sreg[ES].base = I.sreg[FS].base = I.sreg[GS].base = I.sreg[SS].base = 0x00000000;
+ I.sreg[DS].limit = I.sreg[ES].limit = I.sreg[FS].limit = I.sreg[GS].limit = I.sreg[SS].limit = 0xffff;
+ I.sreg[DS].flags = I.sreg[ES].flags = I.sreg[FS].flags = I.sreg[GS].flags = I.sreg[SS].flags = 0x0092;
+
+ I.idtr.base = 0;
+ I.idtr.limit = 0x3ff;
+
+ I.a20_mask = ~0;
+
+ I.cr[0] = 0;
+ I.eflags = 0;
+ I.eip = 0xfff0;
+
+ REG32(EAX) = 0x0308; // Intel 386, stepping D1
+ REG32(EDX) = 0;
+
+ build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM);
+ I.cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM];
+ I.cycle_table_pm = cycle_table_pm[CPU_CYCLES_PENTIUM];
+
+ I.cpuid_id0 = 0x756e6547; // Genu
+ I.cpuid_id1 = 0x49656e69; // ineI
+ I.cpuid_id2 = 0x6c65746e; // ntel
+
+ I.cpuid_max_input_value_eax = 0x01;
+
+ // [11:8] Family
+ // [ 7:4] Model
+ // [ 3:0] Stepping ID
+ // Family 5 (Pentium), Model 2 (75 - 200MHz), Stepping 1
+ I.cpu_version = (5 << 8) | (2 << 4) | (1);
+
+ // [ 0:0] FPU on chip
+ // [ 2:2] I/O breakpoints
+ // [ 4:4] Time Stamp Counter
+ // [ 5:5] Pentium CPU style model specific registers
+ // [ 7:7] Machine Check Exception
+ // [ 8:8] CMPXCHG8B instruction
+ I.feature_flags = 0x00000000;
+
+ CHANGE_PC(I.eip);
+}
+
+static void pentium_exit(void)
+{
+}
+
+static void pentium_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_REGISTER + X87_CTRL: I.fpu_control_word = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_STATUS: I.fpu_status_word = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST0: ST(0).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST1: ST(1).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST2: ST(2).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST3: ST(3).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST4: ST(4).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST5: ST(5).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST6: ST(6).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST7: ST(7).f = info->i; break;
+
+ default: i386_set_info(state, info); break;
+ }
+}
+
+void pentium_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_PTR_SET_INFO: info->setinfo = pentium_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = pentium_init; break;
+ case CPUINFO_PTR_RESET: info->reset = pentium_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = pentium_exit; break;
+
+ case CPUINFO_INT_REGISTER + X87_CTRL: info->i = I.fpu_control_word; break;
+ case CPUINFO_INT_REGISTER + X87_STATUS: info->i = I.fpu_status_word; break;
+ case CPUINFO_INT_REGISTER + X87_ST0: info->i = ST(0).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST1: info->i = ST(1).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST2: info->i = ST(2).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST3: info->i = ST(3).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST4: info->i = ST(4).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST5: info->i = ST(5).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST6: info->i = ST(6).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST7: info->i = ST(7).f; break;
+
+ case CPUINFO_STR_NAME: strcpy(info->s, "PENTIUM"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel Pentium"); break;
+ case CPUINFO_STR_REGISTER + X87_CTRL: sprintf(info->s, "FPU_CW: %04X", I.fpu_control_word); break;
+ case CPUINFO_STR_REGISTER + X87_STATUS: sprintf(info->s, "FPU_SW: %04X", I.fpu_status_word); break;
+ case CPUINFO_STR_REGISTER + X87_ST0: sprintf(info->s, "ST0: %f", ST(0).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST1: sprintf(info->s, "ST1: %f", ST(1).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST2: sprintf(info->s, "ST2: %f", ST(2).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST3: sprintf(info->s, "ST3: %f", ST(3).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST4: sprintf(info->s, "ST4: %f", ST(4).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST5: sprintf(info->s, "ST5: %f", ST(5).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST6: sprintf(info->s, "ST6: %f", ST(6).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST7: sprintf(info->s, "ST7: %f", ST(7).f); break;
+
+ default: i386_get_info(state, info); break;
+ }
+}
+#endif
+
+/*****************************************************************************/
+/* Cyrix MediaGX */
+
+#if (HAS_MEDIAGX)
+
+void mediagx_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ i386_init(index, clock, config, irqcallback);
+}
+
+static void mediagx_reset(void)
+{
+ int (*save_irqcallback)(int);
+
+ save_irqcallback = I.irq_callback;
+ memset( &I, 0, sizeof(I386_REGS) );
+ I.irq_callback = save_irqcallback;
+ I.sreg[CS].selector = 0xf000;
+ I.sreg[CS].base = 0xffff0000;
+ I.sreg[CS].limit = 0xffff;
+ I.sreg[CS].flags = 0x009b;
+
+ I.sreg[DS].base = I.sreg[ES].base = I.sreg[FS].base = I.sreg[GS].base = I.sreg[SS].base = 0x00000000;
+ I.sreg[DS].limit = I.sreg[ES].limit = I.sreg[FS].limit = I.sreg[GS].limit = I.sreg[SS].limit = 0xffff;
+ I.sreg[DS].flags = I.sreg[ES].flags = I.sreg[FS].flags = I.sreg[GS].flags = I.sreg[SS].flags = 0x0092;
+
+ I.idtr.base = 0;
+ I.idtr.limit = 0x3ff;
+
+ I.a20_mask = ~0;
+
+ I.cr[0] = 0;
+ I.eflags = 0;
+ I.eip = 0xfff0;
+
+ REG32(EAX) = 0x0308; // Intel 386, stepping D1
+ REG32(EDX) = 0;
+
+ build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_CYRIX);
+ I.cycle_table_rm = cycle_table_rm[CPU_CYCLES_MEDIAGX];
+ I.cycle_table_pm = cycle_table_pm[CPU_CYCLES_MEDIAGX];
+
+ I.cpuid_id0 = 0x69727943; // Cyri
+ I.cpuid_id1 = 0x736e4978; // xIns
+ I.cpuid_id2 = 0x6d616574; // tead
+
+ I.cpuid_max_input_value_eax = 0x01;
+
+ // [11:8] Family
+ // [ 7:4] Model
+ // [ 3:0] Stepping ID
+ // Family 4, Model 4 (MediaGX)
+ I.cpu_version = (4 << 8) | (4 << 4) | (1);
+
+ // [ 0:0] FPU on chip
+ // [ 2:2] I/O breakpoints
+ // [ 4:4] Time Stamp Counter
+ // [ 5:5] Pentium CPU style model specific registers
+ // [ 7:7] Machine Check Exception
+ // [ 8:8] CMPXCHG8B instruction
+ I.feature_flags = 0x00000001;
+
+ CHANGE_PC(I.eip);
+}
+
+static void mediagx_exit(void)
+{
+}
+
+static void mediagx_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_REGISTER + X87_CTRL: I.fpu_control_word = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_STATUS: I.fpu_status_word = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST0: ST(0).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST1: ST(1).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST2: ST(2).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST3: ST(3).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST4: ST(4).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST5: ST(5).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST6: ST(6).f = info->i; break;
+ case CPUINFO_INT_REGISTER + X87_ST7: ST(7).f = info->i; break;
+
+ default: i386_set_info(state, info); break;
+ }
+}
+
+void mediagx_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mediagx_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = mediagx_init; break;
+ case CPUINFO_PTR_RESET: info->reset = mediagx_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = mediagx_exit; break;
+
+ case CPUINFO_INT_REGISTER + X87_CTRL: info->i = I.fpu_control_word; break;
+ case CPUINFO_INT_REGISTER + X87_STATUS: info->i = I.fpu_status_word; break;
+ case CPUINFO_INT_REGISTER + X87_ST0: info->i = ST(0).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST1: info->i = ST(1).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST2: info->i = ST(2).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST3: info->i = ST(3).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST4: info->i = ST(4).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST5: info->i = ST(5).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST6: info->i = ST(6).f; break;
+ case CPUINFO_INT_REGISTER + X87_ST7: info->i = ST(7).f; break;
+
+ case CPUINFO_STR_NAME: strcpy(info->s, "MEDIAGX"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Cyrix MediaGX"); break;
+ case CPUINFO_STR_REGISTER + X87_CTRL: sprintf(info->s, "FPU_CW: %04X", I.fpu_control_word); break;
+ case CPUINFO_STR_REGISTER + X87_STATUS: sprintf(info->s, "FPU_SW: %04X", I.fpu_status_word); break;
+ case CPUINFO_STR_REGISTER + X87_ST0: sprintf(info->s, "ST0: %f", ST(0).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST1: sprintf(info->s, "ST1: %f", ST(1).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST2: sprintf(info->s, "ST2: %f", ST(2).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST3: sprintf(info->s, "ST3: %f", ST(3).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST4: sprintf(info->s, "ST4: %f", ST(4).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST5: sprintf(info->s, "ST5: %f", ST(5).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST6: sprintf(info->s, "ST6: %f", ST(6).f); break;
+ case CPUINFO_STR_REGISTER + X87_ST7: sprintf(info->s, "ST7: %f", ST(7).f); break;
+
+ default: i386_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/i386/i386.h b/src/emu/cpu/i386/i386.h
new file mode 100644
index 00000000000..0c4efc670a3
--- /dev/null
+++ b/src/emu/cpu/i386/i386.h
@@ -0,0 +1,898 @@
+#ifndef __I386_H_
+#define __I386_H_
+
+#include "cpuintrf.h"
+
+#define I386OP(XX) i386_##XX
+#define I486OP(XX) i486_##XX
+#define PENTIUMOP(XX) pentium_##XX
+#define MMXOP(XX) mmx_##XX
+
+#define INPUT_LINE_A20 1
+
+#ifdef MAME_DEBUG
+extern int i386_dasm_one(char *buffer, UINT32 pc, const UINT8 *oprom, int mode);
+#endif
+
+typedef enum { ES, CS, SS, DS, FS, GS } SREGS;
+
+#ifdef LSB_FIRST
+typedef enum {
+ AL = 0,
+ AH = 1,
+ CL = 4,
+ CH = 5,
+ DL = 8,
+ DH = 9,
+ BL = 12,
+ BH = 13
+} BREGS;
+#else
+typedef enum {
+ AL = 3,
+ AH = 2,
+ CL = 7,
+ CH = 6,
+ DL = 11,
+ DH = 10,
+ BL = 15,
+ BH = 14
+} BREGS;
+#endif
+
+#ifdef LSB_FIRST
+typedef enum {
+ AX = 0,
+ CX = 2,
+ DX = 4,
+ BX = 6,
+ SP = 8,
+ BP = 10,
+ SI = 12,
+ DI = 14
+} WREGS;
+#else
+typedef enum {
+ AX = 1,
+ CX = 3,
+ DX = 5,
+ BX = 7,
+ SP = 9,
+ BP = 11,
+ SI = 13,
+ DI = 15
+} WREGS;
+#endif
+
+typedef enum { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI } DREGS;
+
+enum
+{
+ I386_PC = 0,
+
+ /* 8-bit registers */
+ I386_AL,
+ I386_AH,
+ I386_BL,
+ I386_BH,
+ I386_CL,
+ I386_CH,
+ I386_DL,
+ I386_DH,
+
+ /* 16-bit registers */
+ I386_AX,
+ I386_BX,
+ I386_CX,
+ I386_DX,
+ I386_BP,
+ I386_SP,
+ I386_SI,
+ I386_DI,
+ I386_IP,
+
+ /* 32-bit registers */
+ I386_EAX,
+ I386_ECX,
+ I386_EDX,
+ I386_EBX,
+ I386_EBP,
+ I386_ESP,
+ I386_ESI,
+ I386_EDI,
+ I386_EIP,
+
+ /* segment registers */
+ I386_CS,
+ I386_CS_BASE,
+ I386_CS_LIMIT,
+ I386_CS_FLAGS,
+ I386_SS,
+ I386_SS_BASE,
+ I386_SS_LIMIT,
+ I386_SS_FLAGS,
+ I386_DS,
+ I386_DS_BASE,
+ I386_DS_LIMIT,
+ I386_DS_FLAGS,
+ I386_ES,
+ I386_ES_BASE,
+ I386_ES_LIMIT,
+ I386_ES_FLAGS,
+ I386_FS,
+ I386_FS_BASE,
+ I386_FS_LIMIT,
+ I386_FS_FLAGS,
+ I386_GS,
+ I386_GS_BASE,
+ I386_GS_LIMIT,
+ I386_GS_FLAGS,
+
+ /* other */
+ I386_EFLAGS,
+
+ I386_CR0,
+ I386_CR1,
+ I386_CR2,
+ I386_CR3,
+
+ I386_DR0,
+ I386_DR1,
+ I386_DR2,
+ I386_DR3,
+ I386_DR4,
+ I386_DR5,
+ I386_DR6,
+ I386_DR7,
+
+ I386_TR6,
+ I386_TR7,
+
+ I386_GDTR_BASE,
+ I386_GDTR_LIMIT,
+ I386_IDTR_BASE,
+ I386_IDTR_LIMIT,
+ I386_TR,
+ I386_TR_BASE,
+ I386_TR_LIMIT,
+ I386_TR_FLAGS,
+ I386_LDTR,
+ I386_LDTR_BASE,
+ I386_LDTR_LIMIT,
+ I386_LDTR_FLAGS,
+
+ X87_CTRL,
+ X87_STATUS,
+ X87_ST0,
+ X87_ST1,
+ X87_ST2,
+ X87_ST3,
+ X87_ST4,
+ X87_ST5,
+ X87_ST6,
+ X87_ST7,
+};
+
+typedef struct {
+ UINT16 selector;
+ UINT16 flags;
+ UINT32 base;
+ UINT32 limit;
+ int d; // Operand size
+} I386_SREG;
+
+typedef struct {
+ UINT32 base;
+ UINT16 limit;
+} I386_SYS_TABLE;
+
+typedef struct {
+ UINT16 segment;
+ UINT16 flags;
+ UINT32 base;
+ UINT32 limit;
+} I386_SEG_DESC;
+
+typedef union {
+ UINT32 d[8];
+ UINT16 w[16];
+ UINT8 b[32];
+} I386_GPR;
+
+typedef union {
+ UINT64 i;
+ double f;
+} X87_REG;
+
+typedef struct {
+ I386_GPR reg;
+ I386_SREG sreg[6];
+ UINT32 eip;
+ UINT32 pc;
+ UINT32 prev_eip;
+ UINT32 eflags;
+ UINT8 CF;
+ UINT8 DF;
+ UINT8 SF;
+ UINT8 OF;
+ UINT8 ZF;
+ UINT8 PF;
+ UINT8 AF;
+ UINT8 IF;
+ UINT8 TF;
+
+ UINT8 performed_intersegment_jump;
+
+ UINT32 cr[4]; // Control registers
+ UINT32 dr[8]; // Debug registers
+ UINT32 tr[8]; // Test registers
+
+ I386_SYS_TABLE gdtr; // Global Descriptor Table Register
+ I386_SYS_TABLE idtr; // Interrupt Descriptor Table Register
+ I386_SEG_DESC task; // Task register
+ I386_SEG_DESC ldtr; // Local Descriptor Table Register
+
+ int halted;
+
+ int operand_size;
+ int address_size;
+
+ int segment_prefix;
+ int segment_override;
+
+ int cycles;
+ int base_cycles;
+ UINT8 opcode;
+
+ UINT8 irq_state;
+ int (*irq_callback)(int);
+ UINT32 a20_mask;
+
+ int cpuid_max_input_value_eax;
+ UINT32 cpuid_id0, cpuid_id1, cpuid_id2;
+ UINT32 cpu_version;
+ UINT32 feature_flags;
+ UINT64 tsc;
+
+ // FPU
+ X87_REG fpu_reg[8];
+ UINT16 fpu_control_word;
+ UINT16 fpu_status_word;
+ UINT16 fpu_tag_word;
+ UINT64 fpu_data_ptr;
+ UINT64 fpu_inst_ptr;
+ UINT16 fpu_opcode;
+ int fpu_top;
+
+ void (*opcode_table1_16[256])(void);
+ void (*opcode_table1_32[256])(void);
+ void (*opcode_table2_16[256])(void);
+ void (*opcode_table2_32[256])(void);
+
+ UINT8 *cycle_table_pm;
+ UINT8 *cycle_table_rm;
+} I386_REGS;
+
+
+static I386_REGS I;
+
+
+extern int i386_parity_table[256];
+
+#define PROTECTED_MODE (I.cr[0] & 0x1)
+#define STACK_32BIT (I.sreg[SS].d)
+#define V8086_MODE (I.eflags & 0x00020000)
+
+#define SetOF_Add32(r,s,d) (I.OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80000000) ? 1: 0)
+#define SetOF_Add16(r,s,d) (I.OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x8000) ? 1 : 0)
+#define SetOF_Add8(r,s,d) (I.OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80) ? 1 : 0)
+
+#define SetOF_Sub32(r,s,d) (I.OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x80000000) ? 1 : 0)
+#define SetOF_Sub16(r,s,d) (I.OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? 1 : 0)
+#define SetOF_Sub8(r,s,d) (I.OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? 1 : 0)
+
+#define SetCF8(x) {I.CF = ((x) & 0x100) ? 1 : 0; }
+#define SetCF16(x) {I.CF = ((x) & 0x10000) ? 1 : 0; }
+#define SetCF32(x) {I.CF = ((x) & (((UINT64)1) << 32)) ? 1 : 0; }
+
+#define SetSF(x) (I.SF = (x))
+#define SetZF(x) (I.ZF = (x))
+#define SetAF(x,y,z) (I.AF = (((x) ^ ((y) ^ (z))) & 0x10) ? 1 : 0)
+#define SetPF(x) (I.PF = i386_parity_table[(x) & 0xFF])
+
+#define SetSZPF8(x) {I.ZF = ((UINT8)(x)==0); I.SF = ((x)&0x80) ? 1 : 0; I.PF = i386_parity_table[x & 0xFF]; }
+#define SetSZPF16(x) {I.ZF = ((UINT16)(x)==0); I.SF = ((x)&0x8000) ? 1 : 0; I.PF = i386_parity_table[x & 0xFF]; }
+#define SetSZPF32(x) {I.ZF = ((UINT32)(x)==0); I.SF = ((x)&0x80000000) ? 1 : 0; I.PF = i386_parity_table[x & 0xFF]; }
+
+/***********************************************************************************/
+
+typedef struct {
+ struct {
+ int b;
+ int w;
+ int d;
+ } reg;
+ struct {
+ int b;
+ int w;
+ int d;
+ } rm;
+} MODRM_TABLE;
+
+extern MODRM_TABLE i386_MODRM_table[256];
+
+#define REG8(x) (I.reg.b[x])
+#define REG16(x) (I.reg.w[x])
+#define REG32(x) (I.reg.d[x])
+
+#define LOAD_REG8(x) (REG8(i386_MODRM_table[x].reg.b))
+#define LOAD_REG16(x) (REG16(i386_MODRM_table[x].reg.w))
+#define LOAD_REG32(x) (REG32(i386_MODRM_table[x].reg.d))
+#define LOAD_RM8(x) (REG8(i386_MODRM_table[x].rm.b))
+#define LOAD_RM16(x) (REG16(i386_MODRM_table[x].rm.w))
+#define LOAD_RM32(x) (REG32(i386_MODRM_table[x].rm.d))
+
+#define STORE_REG8(x, value) (REG8(i386_MODRM_table[x].reg.b) = value)
+#define STORE_REG16(x, value) (REG16(i386_MODRM_table[x].reg.w) = value)
+#define STORE_REG32(x, value) (REG32(i386_MODRM_table[x].reg.d) = value)
+#define STORE_RM8(x, value) (REG8(i386_MODRM_table[x].rm.b) = value)
+#define STORE_RM16(x, value) (REG16(i386_MODRM_table[x].rm.w) = value)
+#define STORE_RM32(x, value) (REG32(i386_MODRM_table[x].rm.d) = value)
+
+/***********************************************************************************/
+
+INLINE UINT32 i386_translate(int segment, UINT32 ip)
+{
+ // TODO: segment limit
+ return I.sreg[segment].base + ip;
+}
+
+INLINE int translate_address(UINT32 *address)
+{
+ UINT32 a = *address;
+ UINT32 pdbr = I.cr[3] & 0xfffff000;
+ UINT32 directory = (a >> 22) & 0x3ff;
+ UINT32 table = (a >> 12) & 0x3ff;
+ UINT32 offset = a & 0xfff;
+
+ // TODO: 4MB pages
+ UINT32 page_dir = program_read_dword_32le(pdbr + directory * 4);
+ UINT32 page_entry = program_read_dword_32le((page_dir & 0xfffff000) + (table * 4));
+
+ *address = (page_entry & 0xfffff000) | offset;
+ return 1;
+}
+
+INLINE void CHANGE_PC(UINT32 pc)
+{
+ UINT32 address;
+ I.pc = i386_translate( CS, pc );
+
+ address = I.pc;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ change_pc(address & I.a20_mask);
+}
+
+INLINE void NEAR_BRANCH(INT32 offs)
+{
+ UINT32 address;
+ /* TODO: limit */
+ I.eip += offs;
+ I.pc += offs;
+
+ address = I.pc;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ change_pc(address & I.a20_mask);
+}
+
+INLINE UINT8 FETCH(void)
+{
+ UINT8 value;
+ UINT32 address = I.pc;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ value = cpu_readop(address & I.a20_mask);
+ I.eip++;
+ I.pc++;
+ return value;
+}
+INLINE UINT16 FETCH16(void)
+{
+ UINT16 value;
+ UINT32 address = I.pc;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ if( address & 0x1 ) { /* Unaligned read */
+ address &= I.a20_mask;
+ value = (cpu_readop(address+0) << 0) |
+ (cpu_readop(address+1) << 8);
+ } else {
+ address &= I.a20_mask;
+ value = cpu_readop16(address);
+ }
+ I.eip += 2;
+ I.pc += 2;
+ return value;
+}
+INLINE UINT32 FETCH32(void)
+{
+ UINT32 value;
+ UINT32 address = I.pc;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ if( I.pc & 0x3 ) { /* Unaligned read */
+ address &= I.a20_mask;
+ value = (cpu_readop(address+0) << 0) |
+ (cpu_readop(address+1) << 8) |
+ (cpu_readop(address+2) << 16) |
+ (cpu_readop(address+3) << 24);
+ } else {
+ address &= I.a20_mask;
+ value = cpu_readop32(address);
+ }
+ I.eip += 4;
+ I.pc += 4;
+ return value;
+}
+
+INLINE UINT8 READ8(UINT32 ea)
+{
+ UINT32 address = ea;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ address &= I.a20_mask;
+ return program_read_byte_32le(address);
+}
+INLINE UINT16 READ16(UINT32 ea)
+{
+ UINT16 value;
+ UINT32 address = ea;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ address &= I.a20_mask;
+ if( ea & 0x1 ) { /* Unaligned read */
+ value = (program_read_byte_32le( address+0 ) << 0) |
+ (program_read_byte_32le( address+1 ) << 8);
+ } else {
+ value = program_read_word_32le( address );
+ }
+ return value;
+}
+INLINE UINT32 READ32(UINT32 ea)
+{
+ UINT32 value;
+ UINT32 address = ea;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ address &= I.a20_mask;
+ if( ea & 0x3 ) { /* Unaligned read */
+ value = (program_read_byte_32le( address+0 ) << 0) |
+ (program_read_byte_32le( address+1 ) << 8) |
+ (program_read_byte_32le( address+2 ) << 16) |
+ (program_read_byte_32le( address+3 ) << 24);
+ } else {
+ value = program_read_dword_32le( address );
+ }
+ return value;
+}
+
+INLINE UINT64 READ64(UINT32 ea)
+{
+ UINT64 value;
+ UINT32 address = ea;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ address &= I.a20_mask;
+ if( ea & 0x7 ) { /* Unaligned read */
+ value = (((UINT64) program_read_byte_32le( address+0 )) << 0) |
+ (((UINT64) program_read_byte_32le( address+1 )) << 8) |
+ (((UINT64) program_read_byte_32le( address+2 )) << 16) |
+ (((UINT64) program_read_byte_32le( address+3 )) << 24) |
+ (((UINT64) program_read_byte_32le( address+4 )) << 32) |
+ (((UINT64) program_read_byte_32le( address+5 )) << 40) |
+ (((UINT64) program_read_byte_32le( address+6 )) << 48) |
+ (((UINT64) program_read_byte_32le( address+7 )) << 56);
+ } else {
+ value = (((UINT64) program_read_dword_32le( address+0 )) << 0) |
+ (((UINT64) program_read_dword_32le( address+4 )) << 32);
+ }
+ return value;
+}
+
+INLINE void WRITE8(UINT32 ea, UINT8 value)
+{
+ UINT32 address = ea;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ address &= I.a20_mask;
+ program_write_byte_32le(address, value);
+}
+INLINE void WRITE16(UINT32 ea, UINT16 value)
+{
+ UINT32 address = ea;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ address &= I.a20_mask;
+ if( ea & 0x1 ) { /* Unaligned write */
+ program_write_byte_32le( address+0, value & 0xff );
+ program_write_byte_32le( address+1, (value >> 8) & 0xff );
+ } else {
+ program_write_word_32le(address, value);
+ }
+}
+INLINE void WRITE32(UINT32 ea, UINT32 value)
+{
+ UINT32 address = ea;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ ea &= I.a20_mask;
+ if( ea & 0x3 ) { /* Unaligned write */
+ program_write_byte_32le( address+0, value & 0xff );
+ program_write_byte_32le( address+1, (value >> 8) & 0xff );
+ program_write_byte_32le( address+2, (value >> 16) & 0xff );
+ program_write_byte_32le( address+3, (value >> 24) & 0xff );
+ } else {
+ program_write_dword_32le(address, value);
+ }
+}
+
+INLINE void WRITE64(UINT32 ea, UINT64 value)
+{
+ UINT32 address = ea;
+
+ if (I.cr[0] & 0x80000000) // page translation enabled
+ {
+ translate_address(&address);
+ }
+
+ ea &= I.a20_mask;
+ if( ea & 0x7 ) { /* Unaligned write */
+ program_write_byte_32le( address+0, value & 0xff );
+ program_write_byte_32le( address+1, (value >> 8) & 0xff );
+ program_write_byte_32le( address+2, (value >> 16) & 0xff );
+ program_write_byte_32le( address+3, (value >> 24) & 0xff );
+ program_write_byte_32le( address+4, (value >> 32) & 0xff );
+ program_write_byte_32le( address+5, (value >> 40) & 0xff );
+ program_write_byte_32le( address+6, (value >> 48) & 0xff );
+ program_write_byte_32le( address+7, (value >> 56) & 0xff );
+ } else {
+ program_write_dword_32le(address+0, value & 0xffffffff);
+ program_write_dword_32le(address+4, (value >> 32) & 0xffffffff);
+ }
+}
+
+/***********************************************************************************/
+
+INLINE UINT8 OR8(UINT8 dst, UINT8 src)
+{
+ UINT8 res = dst | src;
+ I.CF = I.OF = 0;
+ SetSZPF8(res);
+ return res;
+}
+INLINE UINT16 OR16(UINT16 dst, UINT16 src)
+{
+ UINT16 res = dst | src;
+ I.CF = I.OF = 0;
+ SetSZPF16(res);
+ return res;
+}
+INLINE UINT32 OR32(UINT32 dst, UINT32 src)
+{
+ UINT32 res = dst | src;
+ I.CF = I.OF = 0;
+ SetSZPF32(res);
+ return res;
+}
+
+INLINE UINT8 AND8(UINT8 dst, UINT8 src)
+{
+ UINT8 res = dst & src;
+ I.CF = I.OF = 0;
+ SetSZPF8(res);
+ return res;
+}
+INLINE UINT16 AND16(UINT16 dst, UINT16 src)
+{
+ UINT16 res = dst & src;
+ I.CF = I.OF = 0;
+ SetSZPF16(res);
+ return res;
+}
+INLINE UINT32 AND32(UINT32 dst, UINT32 src)
+{
+ UINT32 res = dst & src;
+ I.CF = I.OF = 0;
+ SetSZPF32(res);
+ return res;
+}
+
+INLINE UINT8 XOR8(UINT8 dst, UINT8 src)
+{
+ UINT8 res = dst ^ src;
+ I.CF = I.OF = 0;
+ SetSZPF8(res);
+ return res;
+}
+INLINE UINT16 XOR16(UINT16 dst, UINT16 src)
+{
+ UINT16 res = dst ^ src;
+ I.CF = I.OF = 0;
+ SetSZPF16(res);
+ return res;
+}
+INLINE UINT32 XOR32(UINT32 dst, UINT32 src)
+{
+ UINT32 res = dst ^ src;
+ I.CF = I.OF = 0;
+ SetSZPF32(res);
+ return res;
+}
+
+INLINE UINT8 SUB8(UINT8 dst, UINT8 src)
+{
+ UINT16 res = (UINT16)dst - (UINT16)src;
+ SetCF8(res);
+ SetOF_Sub8(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF8(res);
+ return (UINT8)res;
+}
+INLINE UINT16 SUB16(UINT16 dst, UINT16 src)
+{
+ UINT32 res = (UINT32)dst - (UINT32)src;
+ SetCF16(res);
+ SetOF_Sub16(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF16(res);
+ return (UINT16)res;
+}
+INLINE UINT32 SUB32(UINT32 dst, UINT32 src)
+{
+ UINT64 res = (UINT64)dst - (UINT64)src;
+ SetCF32(res);
+ SetOF_Sub32(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF32(res);
+ return (UINT32)res;
+}
+
+INLINE UINT8 ADD8(UINT8 dst, UINT8 src)
+{
+ UINT16 res = (UINT16)dst + (UINT16)src;
+ SetCF8(res);
+ SetOF_Add8(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF8(res);
+ return (UINT8)res;
+}
+INLINE UINT16 ADD16(UINT16 dst, UINT16 src)
+{
+ UINT32 res = (UINT32)dst + (UINT32)src;
+ SetCF16(res);
+ SetOF_Add16(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF16(res);
+ return (UINT16)res;
+}
+INLINE UINT32 ADD32(UINT32 dst, UINT32 src)
+{
+ UINT64 res = (UINT64)dst + (UINT64)src;
+ SetCF32(res);
+ SetOF_Add32(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF32(res);
+ return (UINT32)res;
+}
+
+INLINE UINT8 INC8(UINT8 dst)
+{
+ UINT16 res = (UINT16)dst + 1;
+ SetOF_Add8(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF8(res);
+ return (UINT8)res;
+}
+INLINE UINT16 INC16(UINT16 dst)
+{
+ UINT32 res = (UINT32)dst + 1;
+ SetOF_Add16(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF16(res);
+ return (UINT16)res;
+}
+INLINE UINT32 INC32(UINT32 dst)
+{
+ UINT64 res = (UINT64)dst + 1;
+ SetOF_Add32(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF32(res);
+ return (UINT32)res;
+}
+
+INLINE UINT8 DEC8(UINT8 dst)
+{
+ UINT16 res = (UINT16)dst - 1;
+ SetOF_Sub8(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF8(res);
+ return (UINT8)res;
+}
+INLINE UINT16 DEC16(UINT16 dst)
+{
+ UINT32 res = (UINT32)dst - 1;
+ SetOF_Sub16(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF16(res);
+ return (UINT16)res;
+}
+INLINE UINT32 DEC32(UINT32 dst)
+{
+ UINT64 res = (UINT64)dst - 1;
+ SetOF_Sub32(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF32(res);
+ return (UINT32)res;
+}
+
+
+
+INLINE void PUSH16(UINT16 value)
+{
+ UINT32 ea;
+ if( STACK_32BIT ) {
+ REG32(ESP) -= 2;
+ ea = i386_translate( SS, REG32(ESP) );
+ WRITE16( ea, value );
+ } else {
+ REG16(SP) -= 2;
+ ea = i386_translate( SS, REG16(SP) );
+ WRITE16( ea, value );
+ }
+}
+INLINE void PUSH32(UINT32 value)
+{
+ UINT32 ea;
+ if( STACK_32BIT ) {
+ REG32(ESP) -= 4;
+ ea = i386_translate( SS, REG32(ESP) );
+ WRITE32( ea, value );
+ } else {
+ REG16(SP) -= 4;
+ ea = i386_translate( SS, REG16(SP) );
+ WRITE32( ea, value );
+ }
+}
+INLINE void PUSH8(UINT8 value)
+{
+ if( I.operand_size ) {
+ PUSH32((INT32)(INT8)value);
+ } else {
+ PUSH16((INT16)(INT8)value);
+ }
+}
+
+INLINE UINT8 POP8(void)
+{
+ UINT8 value;
+ UINT32 ea;
+ if( STACK_32BIT ) {
+ ea = i386_translate( SS, REG32(ESP) );
+ value = READ8( ea );
+ REG32(ESP) += 1;
+ } else {
+ ea = i386_translate( SS, REG16(SP) );
+ value = READ8( ea );
+ REG16(SP) += 1;
+ }
+ return value;
+}
+INLINE UINT16 POP16(void)
+{
+ UINT16 value;
+ UINT32 ea;
+ if( STACK_32BIT ) {
+ ea = i386_translate( SS, REG32(ESP) );
+ value = READ16( ea );
+ REG32(ESP) += 2;
+ } else {
+ ea = i386_translate( SS, REG16(SP) );
+ value = READ16( ea );
+ REG16(SP) += 2;
+ }
+ return value;
+}
+INLINE UINT32 POP32(void)
+{
+ UINT32 value;
+ UINT32 ea;
+ if( STACK_32BIT ) {
+ ea = i386_translate( SS, REG32(ESP) );
+ value = READ32( ea );
+ REG32(ESP) += 4;
+ } else {
+ ea = i386_translate( SS, REG16(SP) );
+ value = READ32( ea );
+ REG16(SP) += 4;
+ }
+ return value;
+}
+
+INLINE void BUMP_SI(int adjustment)
+{
+ if ( I.address_size )
+ REG32(ESI) += ((I.DF) ? -adjustment : +adjustment);
+ else
+ REG16(SI) += ((I.DF) ? -adjustment : +adjustment);
+}
+
+INLINE void BUMP_DI(int adjustment)
+{
+ if ( I.address_size )
+ REG32(EDI) += ((I.DF) ? -adjustment : +adjustment);
+ else
+ REG16(DI) += ((I.DF) ? -adjustment : +adjustment);
+}
+
+
+
+/***********************************************************************************/
+
+#define READPORT8(port) (io_read_byte_32le(port))
+#define READPORT16(port) (io_read_word_32le(port))
+#define READPORT32(port) (io_read_dword_32le(port))
+#define WRITEPORT8(port, value) (io_write_byte_32le(port, value))
+#define WRITEPORT16(port, value) (io_write_word_32le(port, value))
+#define WRITEPORT32(port, value) (io_write_dword_32le(port, value))
+
+#endif
diff --git a/src/emu/cpu/i386/i386dasm.c b/src/emu/cpu/i386/i386dasm.c
new file mode 100644
index 00000000000..8d88f34bbd2
--- /dev/null
+++ b/src/emu/cpu/i386/i386dasm.c
@@ -0,0 +1,2125 @@
+/*
+ i386 Disassembler
+
+ Written by Ville Linde
+*/
+
+#include "cpuintrf.h"
+
+enum {
+ PARAM_REG = 1, /* 16 or 32-bit register */
+ PARAM_REG8, /* 8-bit register */
+ PARAM_REG16, /* 16-bit register */
+ PARAM_REG32, /* 32-bit register */
+ PARAM_REG3264, /* 32-bit or 64-bit register */
+ PARAM_REG2_32, /* 32-bit register */
+ PARAM_MMX, /* MMX register */
+ PARAM_XMM, /* XMM register */
+ PARAM_RM, /* 16 or 32-bit memory or register */
+ PARAM_RM8, /* 8-bit memory or register */
+ PARAM_RM16, /* 16-bit memory or register */
+ PARAM_RM32, /* 32-bit memory or register */
+ PARAM_RMPTR, /* 16 or 32-bit memory or register */
+ PARAM_RMPTR8, /* 8-bit memory or register */
+ PARAM_RMPTR16, /* 16-bit memory or register */
+ PARAM_RMPTR32, /* 32-bit memory or register */
+ PARAM_RMXMM, /* 32 or 64-bit memory or register */
+ PARAM_REGORXMM, /* 32 or 64-bit register or XMM register */
+ PARAM_M64, /* 64-bit memory */
+ PARAM_M64PTR, /* 64-bit memory */
+ PARAM_MMXM, /* 64-bit memory or MMX register */
+ PARAM_XMMM, /* 128-bit memory or XMM register */
+ PARAM_I4, /* 4-bit signed immediate */
+ PARAM_I8, /* 8-bit signed immediate */
+ PARAM_I16, /* 16-bit signed immediate */
+ PARAM_UI8, /* 8-bit unsigned immediate */
+ PARAM_UI16, /* 16-bit unsigned immediate */
+ PARAM_IMM, /* 16 or 32-bit immediate */
+ PARAM_IMM64, /* 16, 32 or 64-bit immediate */
+ PARAM_ADDR, /* 16:16 or 16:32 address */
+ PARAM_REL, /* 16 or 32-bit PC-relative displacement */
+ PARAM_REL8, /* 8-bit PC-relative displacement */
+ PARAM_MEM_OFFS_B, /* 8-bit mem offset */
+ PARAM_MEM_OFFS_V, /* 16 or 32-bit mem offset */
+ PARAM_SREG, /* segment register */
+ PARAM_CREG, /* control register */
+ PARAM_DREG, /* debug register */
+ PARAM_TREG, /* test register */
+ PARAM_1, /* used by shift/rotate instructions */
+ PARAM_AL,
+ PARAM_CL,
+ PARAM_DL,
+ PARAM_BL,
+ PARAM_AH,
+ PARAM_CH,
+ PARAM_DH,
+ PARAM_BH,
+ PARAM_DX,
+ PARAM_EAX, /* EAX or AX */
+ PARAM_ECX, /* ECX or CX */
+ PARAM_EDX, /* EDX or DX */
+ PARAM_EBX, /* EBX or BX */
+ PARAM_ESP, /* ESP or SP */
+ PARAM_EBP, /* EBP or BP */
+ PARAM_ESI, /* ESI or SI */
+ PARAM_EDI, /* EDI or DI */
+};
+
+enum
+{
+ MODRM = 1,
+ GROUP,
+ FPU,
+ OP_SIZE,
+ ADDR_SIZE,
+ TWO_BYTE,
+ PREFIX,
+ SEG_CS,
+ SEG_DS,
+ SEG_ES,
+ SEG_FS,
+ SEG_GS,
+ SEG_SS,
+ ISREX
+};
+
+#define FLAGS_MASK 0x0ff
+#define VAR_NAME 0x100
+#define VAR_NAME4 0x200
+#define ALWAYS64 0x400
+#define SPECIAL64 0x800
+#define SPECIAL64_ENT(x) (SPECIAL64 | ((x) << 24))
+
+typedef struct {
+ const char *mnemonic;
+ UINT32 flags;
+ UINT32 param1;
+ UINT32 param2;
+ UINT32 param3;
+ offs_t dasm_flags;
+} I386_OPCODE;
+
+typedef struct {
+ char mnemonic[32];
+ const I386_OPCODE *opcode;
+} GROUP_OP;
+
+static const UINT8 *opcode_ptr;
+static const UINT8 *opcode_ptr_base;
+
+static const I386_OPCODE i386_opcode_table1[256] =
+{
+ // 0x00
+ {"add", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"add", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"add", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"add", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"add", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"add", 0, PARAM_EAX, PARAM_IMM, 0 },
+ {"push es", 0, 0, 0, 0 },
+ {"pop es", 0, 0, 0, 0 },
+ {"or", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"or", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"or", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"or", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"or", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"or", 0, PARAM_EAX, PARAM_IMM, 0 },
+ {"push cs", 0, 0, 0, 0 },
+ {"two_byte", TWO_BYTE, 0, 0, 0 },
+ // 0x10
+ {"adc", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"adc", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"adc", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"adc", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"adc", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"adc", 0, PARAM_EAX, PARAM_IMM, 0 },
+ {"push ss", 0, 0, 0, 0 },
+ {"pop ss", 0, 0, 0, 0 },
+ {"sbb", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"sbb", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"sbb", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"sbb", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"sbb", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"sbb", 0, PARAM_EAX, PARAM_IMM, 0 },
+ {"push ds", 0, 0, 0, 0 },
+ {"pop ds", 0, 0, 0, 0 },
+ // 0x20
+ {"and", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"and", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"and", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"and", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"and", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"and", 0, PARAM_EAX, PARAM_IMM, 0 },
+ {"seg_es", SEG_ES, 0, 0, 0 },
+ {"daa", 0, 0, 0, 0 },
+ {"sub", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"sub", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"sub", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"sub", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"sub", 0, PARAM_AL, PARAM_I8, 0 },
+ {"sub", 0, PARAM_EAX, PARAM_IMM, 0 },
+ {"seg_cs", SEG_CS, 0, 0, 0 },
+ {"das", 0, 0, 0, 0 },
+ // 0x30
+ {"xor", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"xor", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"xor", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"xor", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"xor", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"xor", 0, PARAM_EAX, PARAM_IMM, 0 },
+ {"seg_ss", SEG_SS, 0, 0, 0 },
+ {"aaa", 0, 0, 0, 0 },
+ {"cmp", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"cmp", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"cmp", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"cmp", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmp", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"cmp", 0, PARAM_EAX, PARAM_IMM, 0 },
+ {"seg_ds", SEG_DS, 0, 0, 0 },
+ {"aas", 0, 0, 0, 0 },
+ // 0x40
+ {"inc", ISREX, PARAM_EAX, 0, 0 },
+ {"inc", ISREX, PARAM_ECX, 0, 0 },
+ {"inc", ISREX, PARAM_EDX, 0, 0 },
+ {"inc", ISREX, PARAM_EBX, 0, 0 },
+ {"inc", ISREX, PARAM_ESP, 0, 0 },
+ {"inc", ISREX, PARAM_EBP, 0, 0 },
+ {"inc", ISREX, PARAM_ESI, 0, 0 },
+ {"inc", ISREX, PARAM_EDI, 0, 0 },
+ {"dec", ISREX, PARAM_EAX, 0, 0 },
+ {"dec", ISREX, PARAM_ECX, 0, 0 },
+ {"dec", ISREX, PARAM_EDX, 0, 0 },
+ {"dec", ISREX, PARAM_EBX, 0, 0 },
+ {"dec", ISREX, PARAM_ESP, 0, 0 },
+ {"dec", ISREX, PARAM_EBP, 0, 0 },
+ {"dec", ISREX, PARAM_ESI, 0, 0 },
+ {"dec", ISREX, PARAM_EDI, 0, 0 },
+ // 0x50
+ {"push", ALWAYS64, PARAM_EAX, 0, 0 },
+ {"push", ALWAYS64, PARAM_ECX, 0, 0 },
+ {"push", ALWAYS64, PARAM_EDX, 0, 0 },
+ {"push", ALWAYS64, PARAM_EBX, 0, 0 },
+ {"push", ALWAYS64, PARAM_ESP, 0, 0 },
+ {"push", ALWAYS64, PARAM_EBP, 0, 0 },
+ {"push", ALWAYS64, PARAM_ESI, 0, 0 },
+ {"push", ALWAYS64, PARAM_EDI, 0, 0 },
+ {"pop", ALWAYS64, PARAM_EAX, 0, 0 },
+ {"pop", ALWAYS64, PARAM_ECX, 0, 0 },
+ {"pop", ALWAYS64, PARAM_EDX, 0, 0 },
+ {"pop", ALWAYS64, PARAM_EBX, 0, 0 },
+ {"pop", ALWAYS64, PARAM_ESP, 0, 0 },
+ {"pop", ALWAYS64, PARAM_EBP, 0, 0 },
+ {"pop", ALWAYS64, PARAM_ESI, 0, 0 },
+ {"pop", ALWAYS64, PARAM_EDI, 0, 0 },
+ // 0x60
+ {"pusha\0pushad\0<invalid>",VAR_NAME,0, 0, 0 },
+ {"popa\0popad\0<invalid>", VAR_NAME,0, 0, 0 },
+ {"bound", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"arpl", MODRM | SPECIAL64_ENT(0),PARAM_RM, PARAM_REG16, 0 },
+ {"seg_fs", SEG_FS, 0, 0, 0 },
+ {"seg_gs", SEG_GS, 0, 0, 0 },
+ {"op_size", OP_SIZE, 0, 0, 0 },
+ {"addr_size", ADDR_SIZE, 0, 0, 0 },
+ {"push", 0, PARAM_IMM, 0, 0 },
+ {"imul", MODRM, PARAM_REG, PARAM_RM, PARAM_IMM },
+ {"push", 0, PARAM_I8, 0, 0 },
+ {"imul", MODRM, PARAM_REG, PARAM_RM, PARAM_I8 },
+ {"insb", 0, 0, 0, 0 },
+ {"insw\0insd\0insd",VAR_NAME, 0, 0, 0 },
+ {"outsb", 0, 0, 0, 0 },
+ {"outsw\0outsd\0outsd",VAR_NAME, 0, 0, 0 },
+ // 0x70
+ {"jo", 0, PARAM_REL8, 0, 0 },
+ {"jno", 0, PARAM_REL8, 0, 0 },
+ {"jb", 0, PARAM_REL8, 0, 0 },
+ {"jae", 0, PARAM_REL8, 0, 0 },
+ {"je", 0, PARAM_REL8, 0, 0 },
+ {"jne", 0, PARAM_REL8, 0, 0 },
+ {"jbe", 0, PARAM_REL8, 0, 0 },
+ {"ja", 0, PARAM_REL8, 0, 0 },
+ {"js", 0, PARAM_REL8, 0, 0 },
+ {"jns", 0, PARAM_REL8, 0, 0 },
+ {"jp", 0, PARAM_REL8, 0, 0 },
+ {"jnp", 0, PARAM_REL8, 0, 0 },
+ {"jl", 0, PARAM_REL8, 0, 0 },
+ {"jge", 0, PARAM_REL8, 0, 0 },
+ {"jle", 0, PARAM_REL8, 0, 0 },
+ {"jg", 0, PARAM_REL8, 0, 0 },
+ // 0x80
+ {"group80", GROUP, 0, 0, 0 },
+ {"group81", GROUP, 0, 0, 0 },
+ {"group80", GROUP, 0, 0, 0 },
+ {"group83", GROUP, 0, 0, 0 },
+ {"test", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"test", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"xchg", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"xchg", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"mov", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"mov", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"mov", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"mov", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"mov", MODRM, PARAM_RM, PARAM_SREG, 0 },
+ {"lea", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"mov", MODRM, PARAM_SREG, PARAM_RM, 0 },
+ {"pop", MODRM, PARAM_RM, 0, 0 },
+ // 0x90
+ {"nop", 0, 0, 0, 0 },
+ {"xchg", 0, PARAM_EAX, PARAM_ECX, 0 },
+ {"xchg", 0, PARAM_EAX, PARAM_EDX, 0 },
+ {"xchg", 0, PARAM_EAX, PARAM_EBX, 0 },
+ {"xchg", 0, PARAM_EAX, PARAM_ESP, 0 },
+ {"xchg", 0, PARAM_EAX, PARAM_EBP, 0 },
+ {"xchg", 0, PARAM_EAX, PARAM_ESI, 0 },
+ {"xchg", 0, PARAM_EAX, PARAM_EDI, 0 },
+ {"cbw\0cwde\0cdqe", VAR_NAME, 0, 0, 0 },
+ {"cwd\0cdq\0cqo", VAR_NAME, 0, 0, 0 },
+ {"call", ALWAYS64, PARAM_ADDR, 0, 0, DASMFLAG_STEP_OVER},
+ {"wait", 0, 0, 0, 0 },
+ {"pushf\0pushfd\0pushfq",VAR_NAME, 0, 0, 0 },
+ {"popf\0popfd\0popfq",VAR_NAME, 0, 0, 0 },
+ {"sahf", 0, 0, 0, 0 },
+ {"lahf", 0, 0, 0, 0 },
+ // 0xa0
+ {"mov", 0, PARAM_AL, PARAM_MEM_OFFS_V, 0 },
+ {"mov", 0, PARAM_EAX, PARAM_MEM_OFFS_V, 0 },
+ {"mov", 0, PARAM_MEM_OFFS_V, PARAM_AL, 0 },
+ {"mov", 0, PARAM_MEM_OFFS_V, PARAM_EAX, 0 },
+ {"movsb", 0, 0, 0, 0 },
+ {"movsw\0movsd\0movsq",VAR_NAME, 0, 0, 0 },
+ {"cmpsb", 0, 0, 0, 0 },
+ {"cmpsw\0cmpsd\0cmpsq",VAR_NAME, 0, 0, 0 },
+ {"test", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"test", 0, PARAM_EAX, PARAM_IMM, 0 },
+ {"stosb", 0, 0, 0, 0 },
+ {"stosw\0stosd\0stosq",VAR_NAME, 0, 0, 0 },
+ {"lodsb", 0, 0, 0, 0 },
+ {"lodsw\0lodsd\0lodsq",VAR_NAME, 0, 0, 0 },
+ {"scasb", 0, 0, 0, 0 },
+ {"scasw\0scasd\0scasq",VAR_NAME, 0, 0, 0 },
+ // 0xb0
+ {"mov", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_CL, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_DL, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_BL, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_AH, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_CH, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_DH, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_BH, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_EAX, PARAM_IMM64, 0 },
+ {"mov", 0, PARAM_ECX, PARAM_IMM64, 0 },
+ {"mov", 0, PARAM_EDX, PARAM_IMM64, 0 },
+ {"mov", 0, PARAM_EBX, PARAM_IMM64, 0 },
+ {"mov", 0, PARAM_ESP, PARAM_IMM64, 0 },
+ {"mov", 0, PARAM_EBP, PARAM_IMM64, 0 },
+ {"mov", 0, PARAM_ESI, PARAM_IMM64, 0 },
+ {"mov", 0, PARAM_EDI, PARAM_IMM64, 0 },
+ // 0xc0
+ {"groupC0", GROUP, 0, 0, 0 },
+ {"groupC1", GROUP, 0, 0, 0 },
+ {"ret", 0, PARAM_I16, 0, 0, DASMFLAG_STEP_OUT},
+ {"ret", 0, 0, 0, 0, DASMFLAG_STEP_OUT},
+ {"les", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"lds", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"mov", MODRM, PARAM_RMPTR8, PARAM_UI8, 0 },
+ {"mov", MODRM, PARAM_RMPTR, PARAM_IMM, 0 },
+ {"enter", 0, PARAM_I16, PARAM_UI8, 0 },
+ {"leave", 0, 0, 0, 0 },
+ {"retf", 0, PARAM_I16, 0, 0, DASMFLAG_STEP_OUT},
+ {"retf", 0, 0, 0, 0, DASMFLAG_STEP_OUT},
+ {"int 3", 0, 0, 0, 0, DASMFLAG_STEP_OVER},
+ {"int", 0, PARAM_UI8, 0, 0, DASMFLAG_STEP_OVER},
+ {"into", 0, 0, 0, 0 },
+ {"iret", 0, 0, 0, 0, DASMFLAG_STEP_OUT},
+ // 0xd0
+ {"groupD0", GROUP, 0, 0, 0 },
+ {"groupD1", GROUP, 0, 0, 0 },
+ {"groupD2", GROUP, 0, 0, 0 },
+ {"groupD3", GROUP, 0, 0, 0 },
+ {"aam", 0, PARAM_I8, 0, 0 },
+ {"aad", 0, PARAM_I8, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"xlat", 0, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ // 0xe0
+ {"loopne", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER},
+ {"loopz", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER},
+ {"loop", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER},
+ {"jcxz\0jecxz\0jrcxz",VAR_NAME, PARAM_REL8, 0, 0 },
+ {"in", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"in", 0, PARAM_EAX, PARAM_UI8, 0 },
+ {"out", 0, PARAM_UI8, PARAM_AL, 0 },
+ {"out", 0, PARAM_UI8, PARAM_EAX, 0 },
+ {"call", 0, PARAM_REL, 0, 0, DASMFLAG_STEP_OVER},
+ {"jmp", 0, PARAM_REL, 0, 0 },
+ {"jmp", 0, PARAM_ADDR, 0, 0 },
+ {"jmp", 0, PARAM_REL8, 0, 0 },
+ {"in", 0, PARAM_AL, PARAM_DX, 0 },
+ {"in", 0, PARAM_EAX, PARAM_DX, 0 },
+ {"out", 0, PARAM_DX, PARAM_AL, 0 },
+ {"out", 0, PARAM_DX, PARAM_EAX, 0 },
+ // 0xf0
+ {"lock", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"repne", PREFIX, 0, 0, 0 },
+ {"rep", PREFIX, 0, 0, 0 },
+ {"hlt", 0, 0, 0, 0 },
+ {"cmc", 0, 0, 0, 0 },
+ {"groupF6", GROUP, 0, 0, 0 },
+ {"groupF7", GROUP, 0, 0, 0 },
+ {"clc", 0, 0, 0, 0 },
+ {"stc", 0, 0, 0, 0 },
+ {"cli", 0, 0, 0, 0 },
+ {"sti", 0, 0, 0, 0 },
+ {"cld", 0, 0, 0, 0 },
+ {"std", 0, 0, 0, 0 },
+ {"groupFE", GROUP, 0, 0, 0 },
+ {"groupFF", GROUP, 0, 0, 0 }
+};
+
+static const I386_OPCODE x64_opcode_alt[] =
+{
+ {"movsxd", MODRM | ALWAYS64,PARAM_REG, PARAM_RMPTR32, 0 },
+};
+
+static const I386_OPCODE i386_opcode_table2[256] =
+{
+ // 0x00
+ {"group0F00", GROUP, 0, 0, 0 },
+ {"group0F01", GROUP, 0, 0, 0 },
+ {"lar", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"lsl", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"syscall", 0, 0, 0, 0 },
+ {"clts", 0, 0, 0, 0 },
+ {"sysret", 0, 0, 0, 0 },
+ {"invd", 0, 0, 0, 0 },
+ {"wbinvd", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"ud2", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ // 0x10
+ {"movups\0"
+ "movupd\0"
+ "movsd\0"
+ "movss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"movups\0"
+ "movupd\0"
+ "movsd\0"
+ "movss", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 },
+ {"movlps\0"
+ "movlpd\0"
+ "movddup\0"
+ "movsldup", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"movlps\0"
+ "movlpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 },
+ {"unpcklps\0"
+ "unpcklpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"unpckhps\0"
+ "unpckhpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"movhps\0"
+ "movhpd\0"
+ "???\0"
+ "movshdup", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 },
+ {"movhps\0"
+ "movhpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"group0F18", GROUP, 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 },
+ // 0x20
+ {"mov", MODRM, PARAM_REG2_32, PARAM_CREG, 0 },
+ {"mov", MODRM, PARAM_REG2_32, PARAM_DREG, 0 },
+ {"mov", MODRM, PARAM_CREG, PARAM_REG2_32, 0 },
+ {"mov", MODRM, PARAM_DREG, PARAM_REG2_32, 0 },
+ {"mov", MODRM, PARAM_REG2_32, PARAM_TREG, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"mov", MODRM, PARAM_TREG, PARAM_REG2_32, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"movaps\0"
+ "movapd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"movaps\0"
+ "movapd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 },
+ {"cvtpi2ps\0"
+ "cvtpi2pd\0"
+ "cvtsi2sd\0"
+ "cvtsi2ss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_RMXMM, 0 },
+ {"movntps\0"
+ "movntpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 },
+ {"cvttps2pi\0"
+ "cvttpd2pi\0"
+ "cvttsd2si\0"
+ "cvttss2si", MODRM|VAR_NAME4,PARAM_REGORXMM, PARAM_XMMM, 0 },
+ {"cvtps2pi\0"
+ "cvtpd2pi\0"
+ "cvtsd2si\0"
+ "cvtss2si", MODRM|VAR_NAME4,PARAM_REGORXMM, PARAM_XMMM, 0 },
+ {"ucomiss\0"
+ "ucomisd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"comiss\0"
+ "comisd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ // 0x30
+ {"wrmsr", 0, 0, 0, 0 },
+ {"rdtsc", 0, 0, 0, 0 },
+ {"rdmsr", 0, 0, 0, 0 },
+ {"rdpmc", 0, 0, 0, 0 },
+ {"sysenter", 0, 0, 0, 0 },
+ {"sysexit", 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 },
+ // 0x40
+ {"cmovo", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovno", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovb", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovae", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmove", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovne", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovbe", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmova", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovs", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovns", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovpe", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovpo", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovl", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovge", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovle", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"cmovg", MODRM, PARAM_REG, PARAM_RM, 0 },
+ // 0x50
+ {"movmskps\0"
+ "movmskpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_REG3264, PARAM_XMMM, 0 },
+ {"sqrtps\0"
+ "sqrtpd\0"
+ "sqrtsd\0"
+ "sqrtss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"rsqrtps\0"
+ "???\0"
+ "???\0"
+ "rsqrtss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"rcpps\0"
+ "???\0"
+ "???\0"
+ "rcpss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"andps\0"
+ "andpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"andnps\0"
+ "andnpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"orps\0"
+ "orpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"xorps\0"
+ "xorpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"addps\0"
+ "addpd\0"
+ "addsd\0"
+ "addss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"mulps\0"
+ "mulpd\0"
+ "mulsd\0"
+ "mulss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"cvtps2pd\0"
+ "cvtpd2ps\0"
+ "cvtsd2ss\0"
+ "cvtss2sd", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"cvtdq2ps\0"
+ "cvtps2dq\0"
+ "???\0"
+ "cvttps2dq", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"subps\0"
+ "subpd\0"
+ "subsd\0"
+ "subss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"minps\0"
+ "minpd\0"
+ "minsd\0"
+ "minss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"divps\0"
+ "divpd\0"
+ "divsd\0"
+ "divss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"maxps\0"
+ "maxpd\0"
+ "maxsd\0"
+ "maxss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ // 0x60
+ {"punpcklbw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"punpcklwd", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"punpckldq", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"packsswb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pcmpgtb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pcmpgtw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pcmpgtd", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"packuswb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"punpckhbw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"punpckhwd", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"punpckhdq", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"packssdw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"punpcklqdq", MODRM, PARAM_XMM, PARAM_XMMM, 0 },
+ {"punpckhqdq", MODRM, PARAM_XMM, PARAM_XMMM, 0 },
+ {"movd", MODRM, PARAM_MMX, PARAM_RM, 0 },
+ {"movq\0"
+ "movdqa\0"
+ "???\0"
+ "movdqu", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 },
+ // 0x70
+ {"pshufw\0"
+ "pshufd\0"
+ "pshuflw\0"
+ "pshufhw", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, PARAM_I8 },
+ {"group0F71", GROUP, 0, 0, 0 },
+ {"group0F72", GROUP, 0, 0, 0 },
+ {"group0F73", GROUP, 0, 0, 0 },
+ {"pcmpeqb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pcmpeqw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pcmpeqd", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"emms", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???\0"
+ "haddpd\0"
+ "haddps\0"
+ "???", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 },
+ {"???\0"
+ "hsubpd\0"
+ "hsubps\0"
+ "???", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 },
+ {"movd\0"
+ "movd\0"
+ "???\0"
+ "movq", MODRM|VAR_NAME4,PARAM_RM, PARAM_MMX, 0 },
+ {"movq\0"
+ "movdqa\0"
+ "???\0"
+ "movdqu", MODRM|VAR_NAME4,PARAM_MMXM, PARAM_MMX, 0 },
+ // 0x80
+ {"jo", 0, PARAM_REL, 0, 0 },
+ {"jno", 0, PARAM_REL, 0, 0 },
+ {"jb", 0, PARAM_REL, 0, 0 },
+ {"jae", 0, PARAM_REL, 0, 0 },
+ {"je", 0, PARAM_REL, 0, 0 },
+ {"jne", 0, PARAM_REL, 0, 0 },
+ {"jbe", 0, PARAM_REL, 0, 0 },
+ {"ja", 0, PARAM_REL, 0, 0 },
+ {"js", 0, PARAM_REL, 0, 0 },
+ {"jns", 0, PARAM_REL, 0, 0 },
+ {"jp", 0, PARAM_REL, 0, 0 },
+ {"jnp", 0, PARAM_REL, 0, 0 },
+ {"jl", 0, PARAM_REL, 0, 0 },
+ {"jge", 0, PARAM_REL, 0, 0 },
+ {"jle", 0, PARAM_REL, 0, 0 },
+ {"jg", 0, PARAM_REL, 0, 0 },
+ // 0x90
+ {"seto", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setno", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setb", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setae", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"sete", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setne", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setbe", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"seta", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"sets", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setns", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setp", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setnp", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setl", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setge", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setle", MODRM, PARAM_RMPTR8, 0, 0 },
+ {"setg", MODRM, PARAM_RMPTR8, 0, 0 },
+ // 0xa0
+ {"push fs", 0, 0, 0, 0 },
+ {"pop fs", 0, 0, 0, 0 },
+ {"cpuid", 0, 0, 0, 0 },
+ {"bt", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"shld", MODRM, PARAM_RM, PARAM_REG, PARAM_I8 },
+ {"shld", MODRM, PARAM_RM, PARAM_REG, PARAM_CL },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"push gs", 0, 0, 0, 0 },
+ {"pop gs", 0, 0, 0, 0 },
+ {"rsm", 0, 0, 0, 0 },
+ {"bts", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"shrd", MODRM, PARAM_RM, PARAM_REG, PARAM_I8 },
+ {"shrd", MODRM, PARAM_RM, PARAM_REG, PARAM_CL },
+ {"group0FAE", GROUP, 0, 0, 0 },
+ {"imul", MODRM, PARAM_REG, PARAM_RM, 0 },
+ // 0xb0
+ {"cmpxchg", MODRM, PARAM_RM8, PARAM_REG, 0 },
+ {"cmpxchg", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"lss", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"btr", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"lfs", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"lgs", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"movzx", MODRM, PARAM_REG, PARAM_RMPTR8, 0 },
+ {"movzx", MODRM, PARAM_REG, PARAM_RMPTR16, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"group0FBA", GROUP, 0, 0, 0 },
+ {"btc", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"bsf", MODRM, PARAM_REG, PARAM_RM, 0 },
+ {"bsr", MODRM, PARAM_REG, PARAM_RM, 0, DASMFLAG_STEP_OVER},
+ {"movsx", MODRM, PARAM_REG, PARAM_RMPTR8, 0 },
+ {"movsx", MODRM, PARAM_REG, PARAM_RMPTR16, 0 },
+ // 0xc0
+ {"xadd", MODRM, PARAM_RM8, PARAM_REG, 0 },
+ {"xadd", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"cmpps\0"
+ "cmppd\0"
+ "cmpsd\0"
+ "cmpss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"movnti", MODRM, PARAM_RM, PARAM_REG, 0 },
+ {"pinsrw", MODRM, PARAM_MMX, PARAM_MMXM, PARAM_I8 },
+ {"pextrw", MODRM, PARAM_MMX, PARAM_MMXM, PARAM_I8 },
+ {"shufps\0"
+ "shufpd\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, PARAM_I8 },
+ {"cmpxchg8b", MODRM, PARAM_M64PTR, 0, 0 },
+ {"bswap", 0, PARAM_EAX, 0, 0 },
+ {"bswap", 0, PARAM_ECX, 0, 0 },
+ {"bswap", 0, PARAM_EDX, 0, 0 },
+ {"bswap", 0, PARAM_EBX, 0, 0 },
+ {"bswap", 0, PARAM_ESP, 0, 0 },
+ {"bswap", 0, PARAM_EBP, 0, 0 },
+ {"bswap", 0, PARAM_ESI, 0, 0 },
+ {"bswap", 0, PARAM_EDI, 0, 0 },
+ // 0xd0
+ {"addsubpd\0"
+ "???\0"
+ "addsubps\0"
+ "???\0", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"psrlw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psrld", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psrlq", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"paddq", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pmullw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"movq\0"
+ "???\0"
+ "movdq2q\0"
+ "movq2dq", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 },
+ {"pmovmskb", MODRM, PARAM_REG3264, PARAM_MMXM, 0 },
+ {"psubusb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psubusw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pminub", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pand", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"paddub", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"padduw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pmaxub", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pandn", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ // 0xe0
+ {"pavgb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psraw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psrad", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pavgw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pmulhuw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pmulhw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"???\0"
+ "cvttpd2dq\0"
+ "cvtpd2dq\0"
+ "cvtdq2pd", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"movntq", MODRM, PARAM_M64, PARAM_MMX, 0 },
+ {"psubsb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psubsw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pminsw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"por", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"paddsb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"paddsw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pmaxsw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pxor", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ // 0xf0
+ {"???\0"
+ "???\0"
+ "lddqu\0"
+ "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 },
+ {"psllw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pslld", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psllq", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pmuludq", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"pmaddwd", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psadbw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"maskmovq\0"
+ "maskmovdqu\0"
+ "???\0"
+ "???", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 },
+ {"psubb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psubw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psubd", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"psubq", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"paddb", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"paddw", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"paddd", MODRM, PARAM_MMX, PARAM_MMXM, 0 },
+ {"???", 0, 0, 0, 0 }
+};
+
+static const I386_OPCODE group80_table[8] =
+{
+ {"add", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"or", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"adc", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"sbb", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"and", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"sub", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"xor", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"cmp", 0, PARAM_RMPTR8, PARAM_I8, 0 }
+};
+
+static const I386_OPCODE group81_table[8] =
+{
+ {"add", 0, PARAM_RMPTR, PARAM_IMM, 0 },
+ {"or", 0, PARAM_RMPTR, PARAM_IMM, 0 },
+ {"adc", 0, PARAM_RMPTR, PARAM_IMM, 0 },
+ {"sbb", 0, PARAM_RMPTR, PARAM_IMM, 0 },
+ {"and", 0, PARAM_RMPTR, PARAM_IMM, 0 },
+ {"sub", 0, PARAM_RMPTR, PARAM_IMM, 0 },
+ {"xor", 0, PARAM_RMPTR, PARAM_IMM, 0 },
+ {"cmp", 0, PARAM_RMPTR, PARAM_IMM, 0 }
+};
+
+static const I386_OPCODE group83_table[8] =
+{
+ {"add", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"or", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"adc", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"sbb", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"and", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"sub", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"xor", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"cmp", 0, PARAM_RMPTR, PARAM_I8, 0 }
+};
+
+static const I386_OPCODE groupC0_table[8] =
+{
+ {"rol", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"ror", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"rcl", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"rcr", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"shl", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"shr", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"sal", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"sar", 0, PARAM_RMPTR8, PARAM_I8, 0 }
+};
+
+static const I386_OPCODE groupC1_table[8] =
+{
+ {"rol", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"ror", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"rcl", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"rcr", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"shl", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"shr", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"sal", 0, PARAM_RMPTR, PARAM_I8, 0 },
+ {"sar", 0, PARAM_RMPTR, PARAM_I8, 0 }
+};
+
+static const I386_OPCODE groupD0_table[8] =
+{
+ {"rol", 0, PARAM_RMPTR8, PARAM_1, 0 },
+ {"ror", 0, PARAM_RMPTR8, PARAM_1, 0 },
+ {"rcl", 0, PARAM_RMPTR8, PARAM_1, 0 },
+ {"rcr", 0, PARAM_RMPTR8, PARAM_1, 0 },
+ {"shl", 0, PARAM_RMPTR8, PARAM_1, 0 },
+ {"shr", 0, PARAM_RMPTR8, PARAM_1, 0 },
+ {"sal", 0, PARAM_RMPTR8, PARAM_1, 0 },
+ {"sar", 0, PARAM_RMPTR8, PARAM_1, 0 }
+};
+
+static const I386_OPCODE groupD1_table[8] =
+{
+ {"rol", 0, PARAM_RMPTR, PARAM_1, 0 },
+ {"ror", 0, PARAM_RMPTR, PARAM_1, 0 },
+ {"rcl", 0, PARAM_RMPTR, PARAM_1, 0 },
+ {"rcr", 0, PARAM_RMPTR, PARAM_1, 0 },
+ {"shl", 0, PARAM_RMPTR, PARAM_1, 0 },
+ {"shr", 0, PARAM_RMPTR, PARAM_1, 0 },
+ {"sal", 0, PARAM_RMPTR, PARAM_1, 0 },
+ {"sar", 0, PARAM_RMPTR, PARAM_1, 0 }
+};
+
+static const I386_OPCODE groupD2_table[8] =
+{
+ {"rol", 0, PARAM_RMPTR8, PARAM_CL, 0 },
+ {"ror", 0, PARAM_RMPTR8, PARAM_CL, 0 },
+ {"rcl", 0, PARAM_RMPTR8, PARAM_CL, 0 },
+ {"rcr", 0, PARAM_RMPTR8, PARAM_CL, 0 },
+ {"shl", 0, PARAM_RMPTR8, PARAM_CL, 0 },
+ {"shr", 0, PARAM_RMPTR8, PARAM_CL, 0 },
+ {"sal", 0, PARAM_RMPTR8, PARAM_CL, 0 },
+ {"sar", 0, PARAM_RMPTR8, PARAM_CL, 0 }
+};
+
+static const I386_OPCODE groupD3_table[8] =
+{
+ {"rol", 0, PARAM_RMPTR, PARAM_CL, 0 },
+ {"ror", 0, PARAM_RMPTR, PARAM_CL, 0 },
+ {"rcl", 0, PARAM_RMPTR, PARAM_CL, 0 },
+ {"rcr", 0, PARAM_RMPTR, PARAM_CL, 0 },
+ {"shl", 0, PARAM_RMPTR, PARAM_CL, 0 },
+ {"shr", 0, PARAM_RMPTR, PARAM_CL, 0 },
+ {"sal", 0, PARAM_RMPTR, PARAM_CL, 0 },
+ {"sar", 0, PARAM_RMPTR, PARAM_CL, 0 }
+};
+
+static const I386_OPCODE groupF6_table[8] =
+{
+ {"test", 0, PARAM_RMPTR8, PARAM_I8, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"not", 0, PARAM_RMPTR8, 0, 0 },
+ {"neg", 0, PARAM_RMPTR8, 0, 0 },
+ {"mul", 0, PARAM_RMPTR8, 0, 0 },
+ {"imul", 0, PARAM_RMPTR8, 0, 0 },
+ {"div", 0, PARAM_RMPTR8, 0, 0 },
+ {"idiv", 0, PARAM_RMPTR8, 0, 0 }
+};
+
+static const I386_OPCODE groupF7_table[8] =
+{
+ {"test", 0, PARAM_RMPTR, PARAM_IMM, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"not", 0, PARAM_RMPTR, 0, 0 },
+ {"neg", 0, PARAM_RMPTR, 0, 0 },
+ {"mul", 0, PARAM_RMPTR, 0, 0 },
+ {"imul", 0, PARAM_RMPTR, 0, 0 },
+ {"div", 0, PARAM_RMPTR, 0, 0 },
+ {"idiv", 0, PARAM_RMPTR, 0, 0 }
+};
+
+static const I386_OPCODE groupFE_table[8] =
+{
+ {"inc", 0, PARAM_RMPTR8, 0, 0 },
+ {"dec", 0, PARAM_RMPTR8, 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 I386_OPCODE groupFF_table[8] =
+{
+ {"inc", 0, PARAM_RMPTR, 0, 0 },
+ {"dec", 0, PARAM_RMPTR, 0, 0 },
+ {"call", ALWAYS64, PARAM_RMPTR, 0, 0, DASMFLAG_STEP_OVER},
+ {"call far ptr ",0, PARAM_RM, 0, 0, DASMFLAG_STEP_OVER},
+ {"jmp", ALWAYS64, PARAM_RMPTR, 0, 0 },
+ {"jmp far ptr ",0, PARAM_RM, 0, 0 },
+ {"push", 0, PARAM_RMPTR, 0, 0 },
+ {"???", 0, 0, 0, 0 }
+};
+
+static const I386_OPCODE group0F00_table[8] =
+{
+ {"sldt", 0, PARAM_RM, 0, 0 },
+ {"str", 0, PARAM_RM, 0, 0 },
+ {"lldt", 0, PARAM_RM, 0, 0 },
+ {"ltr", 0, PARAM_RM, 0, 0 },
+ {"verr", 0, PARAM_RM, 0, 0 },
+ {"verw", 0, PARAM_RM, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 }
+};
+
+static const I386_OPCODE group0F01_table[8] =
+{
+ {"sgdt", 0, PARAM_RM, 0, 0 },
+ {"sidt", 0, PARAM_RM, 0, 0 },
+ {"lgdt", 0, PARAM_RM, 0, 0 },
+ {"lidt", 0, PARAM_RM, 0, 0 },
+ {"smsw", 0, PARAM_RM, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"lmsw", 0, PARAM_RM, 0, 0 },
+ {"invlpg", 0, PARAM_RM, 0, 0 }
+};
+
+static const I386_OPCODE group0F18_table[8] =
+{
+ {"prefetchnta", 0, PARAM_RM8, 0, 0 },
+ {"prefetch0", 0, PARAM_RM8, 0, 0 },
+ {"prefetch1", 0, PARAM_RM8, 0, 0 },
+ {"prefetch2", 0, PARAM_RM8, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 }
+};
+
+static const I386_OPCODE group0F71_table[8] =
+{
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"psrlw", 0, PARAM_MMX, PARAM_I8, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"psraw", 0, PARAM_MMX, PARAM_I8, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"psllw", 0, PARAM_MMX, PARAM_I8, 0 },
+ {"???", 0, 0, 0, 0 }
+};
+
+static const I386_OPCODE group0F72_table[8] =
+{
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"psrld", 0, PARAM_MMX, PARAM_I8, 0 },
+ {"psrldq", 0, PARAM_MMX, PARAM_I8, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"pslld", 0, PARAM_MMX, PARAM_I8, 0 },
+ {"pslldq", 0, PARAM_MMX, PARAM_I8, 0 },
+};
+
+static const I386_OPCODE group0F73_table[8] =
+{
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"psrlq", 0, PARAM_MMX, PARAM_I8, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"psraq", 0, PARAM_MMX, PARAM_I8, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"psllq", 0, PARAM_MMX, PARAM_I8, 0 },
+ {"???", 0, 0, 0, 0 }
+};
+
+static const I386_OPCODE group0FAE_table[8] =
+{
+ {"fxsave", 0, PARAM_RM, 0, 0 },
+ {"fxrstor", 0, PARAM_RM, 0, 0 },
+ {"ldmxcsr", 0, PARAM_RM, 0, 0 },
+ {"stmxscr", 0, PARAM_RM, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"lfence", 0, 0, 0, 0 },
+ {"mfence", 0, 0, 0, 0 },
+ {"sfence", 0, 0, 0, 0 }
+};
+
+
+static const I386_OPCODE group0FBA_table[8] =
+{
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"bt", 0, PARAM_RM, PARAM_I8, 0 },
+ {"bts", 0, PARAM_RM, PARAM_I8, 0 },
+ {"btr", 0, PARAM_RM, PARAM_I8, 0 },
+ {"btc", 0, PARAM_RM, PARAM_I8, 0 }
+};
+
+static const GROUP_OP group_op_table[] =
+{
+ { "group80", group80_table },
+ { "group81", group81_table },
+ { "group83", group83_table },
+ { "groupC0", groupC0_table },
+ { "groupC1", groupC1_table },
+ { "groupD0", groupD0_table },
+ { "groupD1", groupD1_table },
+ { "groupD2", groupD2_table },
+ { "groupD3", groupD3_table },
+ { "groupF6", groupF6_table },
+ { "groupF7", groupF7_table },
+ { "groupFE", groupFE_table },
+ { "groupFF", groupFF_table },
+ { "group0F00", group0F00_table },
+ { "group0F01", group0F01_table },
+ { "group0F18", group0F18_table },
+ { "group0F71", group0F71_table },
+ { "group0F72", group0F72_table },
+ { "group0F73", group0F73_table },
+ { "group0FAE", group0FAE_table },
+ { "group0FBA", group0FBA_table }
+};
+
+
+
+static const char *i386_reg[3][16] =
+{
+ {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w","r11w","r12w","r13w","r14w","r15w"},
+ {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d","r11d","r12d","r13d","r14d","r15d"},
+ {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}
+};
+
+static const char *i386_reg8[8] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
+static const char *i386_reg8rex[16] = {"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"};
+static const char *i386_sreg[8] = {"es", "cs", "ss", "ds", "fs", "gs", "???", "???"};
+
+static int address_size;
+static int operand_size;
+static UINT32 pc;
+static UINT8 modrm;
+static UINT32 segment;
+static offs_t dasm_flags;
+static char modrm_string[256];
+static UINT8 rex, regex, sibex, rmex;
+static UINT8 pre0f;
+static UINT8 curmode;
+
+#define MODRM_REG1 ((modrm >> 3) & 0x7)
+#define MODRM_REG2 (modrm & 0x7)
+
+INLINE UINT8 FETCH(void)
+{
+ if ((opcode_ptr - opcode_ptr_base) + 1 > 15)
+ return 0xff;
+ pc++;
+ return *opcode_ptr++;
+}
+
+INLINE UINT16 FETCH16(void)
+{
+ UINT16 d;
+ if ((opcode_ptr - opcode_ptr_base) + 2 > 15)
+ return 0xffff;
+ d = opcode_ptr[0] | (opcode_ptr[1] << 8);
+ opcode_ptr += 2;
+ pc += 2;
+ return d;
+}
+
+INLINE UINT32 FETCH32(void)
+{
+ UINT32 d;
+ if ((opcode_ptr - opcode_ptr_base) + 4 > 15)
+ return 0xffffffff;
+ d = opcode_ptr[0] | (opcode_ptr[1] << 8) | (opcode_ptr[2] << 16) | (opcode_ptr[3] << 24);
+ opcode_ptr += 4;
+ pc += 4;
+ return d;
+}
+
+INLINE UINT8 FETCHD(void)
+{
+ if ((opcode_ptr - opcode_ptr_base) + 1 > 15)
+ return 0xff;
+ pc++;
+ return *opcode_ptr++;
+}
+
+INLINE UINT16 FETCHD16(void)
+{
+ UINT16 d;
+ if ((opcode_ptr - opcode_ptr_base) + 2 > 15)
+ return 0xffff;
+ d = opcode_ptr[0] | (opcode_ptr[1] << 8);
+ opcode_ptr += 2;
+ pc += 2;
+ return d;
+}
+
+INLINE UINT32 FETCHD32(void)
+{
+ UINT32 d;
+ if ((opcode_ptr - opcode_ptr_base) + 4 > 15)
+ return 0xffffffff;
+ d = opcode_ptr[0] | (opcode_ptr[1] << 8) | (opcode_ptr[2] << 16) | (opcode_ptr[3] << 24);
+ opcode_ptr += 4;
+ pc += 4;
+ return d;
+}
+
+static char *hexstring(UINT32 value, int digits)
+{
+ static char buffer[20];
+ buffer[0] = '0';
+ if (digits)
+ sprintf(&buffer[1], "%0*Xh", digits, value);
+ else
+ sprintf(&buffer[1], "%Xh", value);
+ return (buffer[1] >= '0' && buffer[1] <= '9') ? &buffer[1] : &buffer[0];
+}
+
+static char *hexstring64(UINT32 lo, UINT32 hi)
+{
+ static char buffer[40];
+ buffer[0] = '0';
+ if (hi != 0)
+ sprintf(&buffer[1], "%X%08Xh", hi, lo);
+ else
+ sprintf(&buffer[1], "%Xh", lo);
+ return (buffer[1] >= '0' && buffer[1] <= '9') ? &buffer[1] : &buffer[0];
+}
+
+static char *shexstring(UINT32 value, int digits, int always)
+{
+ static char buffer[20];
+ if (value >= 0x80000000)
+ sprintf(buffer, "-%s", hexstring(-value, digits));
+ else if (always)
+ sprintf(buffer, "+%s", hexstring(value, digits));
+ else
+ return hexstring(value, digits);
+ return buffer;
+}
+
+static char* handle_sib_byte( char* s, UINT8 mod )
+{
+ UINT32 i32;
+ UINT8 scale, i, base;
+ UINT8 sib = FETCHD();
+
+ scale = (sib >> 6) & 0x3;
+ i = ((sib >> 3) & 0x7) | sibex;
+ base = (sib & 0x7) | rmex;
+
+ if (base == 5 && mod == 0) {
+ i32 = FETCH32();
+ s += sprintf( s, "%s", hexstring(i32, 0) );
+ } else if (base != 5 || mod != 3)
+ s += sprintf( s, "%s", i386_reg[address_size][base] );
+
+ if ( i != 4 ) {
+ s += sprintf( s, "+%s", i386_reg[address_size][i] );
+ if (scale)
+ s += sprintf( s, "*%d", 1 << scale );
+ }
+ return s;
+}
+
+static void handle_modrm(char* s)
+{
+ INT8 disp8;
+ INT16 disp16;
+ INT32 disp32;
+ UINT8 mod, rm;
+
+ modrm = FETCHD();
+ mod = (modrm >> 6) & 0x3;
+ rm = (modrm & 0x7) | rmex;
+
+ if( modrm >= 0xc0 )
+ return;
+
+ switch(segment)
+ {
+ case SEG_CS: s += sprintf( s, "cs:" ); break;
+ case SEG_DS: s += sprintf( s, "ds:" ); break;
+ case SEG_ES: s += sprintf( s, "es:" ); break;
+ case SEG_FS: s += sprintf( s, "fs:" ); break;
+ case SEG_GS: s += sprintf( s, "gs:" ); break;
+ case SEG_SS: s += sprintf( s, "ss:" ); break;
+ }
+
+ s += sprintf( s, "[" );
+ if( address_size == 2 ) {
+ if ((rm & 7) == 4)
+ s = handle_sib_byte( s, mod );
+ else if ((rm & 7) == 5 && mod == 0) {
+ disp32 = FETCHD32();
+ s += sprintf( s, "rip%s", shexstring(disp32, 0, TRUE) );
+ } else
+ s += sprintf( s, "%s", i386_reg[2][rm]);
+ if( mod == 1 ) {
+ disp8 = FETCHD();
+ if (disp8 != 0)
+ s += sprintf( s, "%s", shexstring((INT32)disp8, 0, TRUE) );
+ } else if( mod == 2 ) {
+ disp32 = FETCHD32();
+ if (disp32 != 0)
+ s += sprintf( s, "%s", shexstring(disp32, 0, TRUE) );
+ }
+ } else if (address_size == 1) {
+ if ((rm & 7) == 4)
+ s = handle_sib_byte( s, mod );
+ else if ((rm & 7) == 5 && mod == 0) {
+ disp32 = FETCHD32();
+ if (curmode == 64)
+ s += sprintf( s, "eip%s", shexstring(disp32, 0, TRUE) );
+ else
+ s += sprintf( s, "%s", hexstring(disp32, 0) );
+ } else
+ s += sprintf( s, "%s", i386_reg[1][rm]);
+ if( mod == 1 ) {
+ disp8 = FETCHD();
+ if (disp8 != 0)
+ s += sprintf( s, "%s", shexstring((INT32)disp8, 0, TRUE) );
+ } else if( mod == 2 ) {
+ disp32 = FETCHD32();
+ if (disp32 != 0)
+ s += sprintf( s, "%s", shexstring(disp32, 0, TRUE) );
+ }
+ } else {
+ switch( rm )
+ {
+ case 0: s += sprintf( s, "bx+si" ); break;
+ case 1: s += sprintf( s, "bx+di" ); break;
+ case 2: s += sprintf( s, "bx+si" ); break;
+ case 3: s += sprintf( s, "bx+di" ); break;
+ case 4: s += sprintf( s, "si" ); break;
+ case 5: s += sprintf( s, "di" ); break;
+ case 6:
+ if( mod == 0 ) {
+ disp16 = FETCHD16();
+ s += sprintf( s, "%s", hexstring((unsigned) (UINT16) disp16, 0) );
+ } else {
+ s += sprintf( s, "bp" );
+ }
+ break;
+ case 7: s += sprintf( s, "bx" ); break;
+ }
+ if( mod == 1 ) {
+ disp8 = FETCHD();
+ if (disp8 != 0)
+ s += sprintf( s, "%s", shexstring((INT32)disp8, 0, TRUE) );
+ } else if( mod == 2 ) {
+ disp16 = FETCHD16();
+ if (disp16 != 0)
+ s += sprintf( s, "%s", shexstring((INT32)disp16, 0, TRUE) );
+ }
+ }
+ s += sprintf( s, "]" );
+}
+
+static char* handle_param(char* s, UINT32 param)
+{
+ UINT8 i8;
+ UINT16 i16;
+ UINT32 i32;
+ UINT16 ptr;
+ UINT32 addr;
+ INT8 d8;
+ INT16 d16;
+ INT32 d32;
+
+ switch(param)
+ {
+ case PARAM_REG:
+ s += sprintf( s, "%s", i386_reg[operand_size][MODRM_REG1 | regex] );
+ break;
+
+ case PARAM_REG8:
+ s += sprintf( s, "%s", (rex ? i386_reg8rex : i386_reg8)[MODRM_REG1 | regex] );
+ break;
+
+ case PARAM_REG16:
+ s += sprintf( s, "%s", i386_reg[0][MODRM_REG1 | regex] );
+ break;
+
+ case PARAM_REG32:
+ s += sprintf( s, "%s", i386_reg[1][MODRM_REG1 | regex] );
+ break;
+
+ case PARAM_REG3264:
+ s += sprintf( s, "%s", i386_reg[(operand_size == 2) ? 2 : 1][MODRM_REG1 | regex] );
+ break;
+
+ case PARAM_MMX:
+ if (pre0f == 0x66 || pre0f == 0xf2 || pre0f == 0xf3)
+ s += sprintf( s, "xmm%d", MODRM_REG1 | regex );
+ else
+ s += sprintf( s, "mm%d", MODRM_REG1 | regex );
+ break;
+
+ case PARAM_XMM:
+ s += sprintf( s, "xmm%d", MODRM_REG1 | regex );
+ break;
+
+ case PARAM_REGORXMM:
+ if (pre0f != 0xf2 && pre0f != 0xf3)
+ s += sprintf( s, "xmm%d", MODRM_REG1 | regex );
+ else
+ s += sprintf( s, "%s", i386_reg[(operand_size == 2) ? 2 : 1][MODRM_REG1 | regex] );
+ break;
+
+ case PARAM_REG2_32:
+ s += sprintf( s, "%s", i386_reg[1][MODRM_REG2 | rmex] );
+ break;
+
+ case PARAM_RM:
+ case PARAM_RMPTR:
+ if( modrm >= 0xc0 ) {
+ s += sprintf( s, "%s", i386_reg[operand_size][MODRM_REG2 | rmex] );
+ } else {
+ if (param == PARAM_RMPTR)
+ {
+ if( operand_size == 2 )
+ s += sprintf( s, "qword ptr " );
+ else if (operand_size == 1)
+ s += sprintf( s, "dword ptr " );
+ else
+ s += sprintf( s, "word ptr " );
+ }
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_RM8:
+ case PARAM_RMPTR8:
+ if( modrm >= 0xc0 ) {
+ s += sprintf( s, "%s", (rex ? i386_reg8rex : i386_reg8)[MODRM_REG2 | rmex] );
+ } else {
+ if (param == PARAM_RMPTR8)
+ s += sprintf( s, "byte ptr " );
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_RM16:
+ case PARAM_RMPTR16:
+ if( modrm >= 0xc0 ) {
+ s += sprintf( s, "%s", i386_reg[0][MODRM_REG2 | rmex] );
+ } else {
+ if (param == PARAM_RMPTR16)
+ s += sprintf( s, "word ptr " );
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_RM32:
+ case PARAM_RMPTR32:
+ if( modrm >= 0xc0 ) {
+ s += sprintf( s, "%s", i386_reg[1][MODRM_REG2 | rmex] );
+ } else {
+ if (param == PARAM_RMPTR32)
+ s += sprintf( s, "dword ptr " );
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_RMXMM:
+ if( modrm >= 0xc0 ) {
+ if (pre0f != 0xf2 && pre0f != 0xf3)
+ s += sprintf( s, "xmm%d", MODRM_REG2 | rmex );
+ else
+ s += sprintf( s, "%s", i386_reg[(operand_size == 2) ? 2 : 1][MODRM_REG2 | rmex] );
+ } else {
+ if (param == PARAM_RMPTR32)
+ s += sprintf( s, "dword ptr " );
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_M64:
+ case PARAM_M64PTR:
+ if( modrm >= 0xc0 ) {
+ s += sprintf( s, "???" );
+ } else {
+ if (param == PARAM_M64PTR)
+ s += sprintf( s, "qword ptr " );
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_MMXM:
+ if( modrm >= 0xc0 ) {
+ if (pre0f == 0x66 || pre0f == 0xf2 || pre0f == 0xf3)
+ s += sprintf( s, "xmm%d", MODRM_REG2 | rmex );
+ else
+ s += sprintf( s, "mm%d", MODRM_REG2 | rmex );
+ } else {
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_XMMM:
+ if( modrm >= 0xc0 ) {
+ s += sprintf( s, "xmm%d", MODRM_REG2 | rmex );
+ } else {
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_I4:
+ i8 = FETCHD();
+ s += sprintf( s, "%d", i8 & 0x0f );
+ break;
+
+ case PARAM_I8:
+ i8 = FETCHD();
+ s += sprintf( s, "%s", shexstring((INT8)i8, 0, FALSE) );
+ break;
+
+ case PARAM_I16:
+ i16 = FETCHD16();
+ s += sprintf( s, "%s", shexstring((INT16)i16, 0, FALSE) );
+ break;
+
+ case PARAM_UI8:
+ i8 = FETCHD();
+ s += sprintf( s, "%s", shexstring((UINT8)i8, 0, FALSE) );
+ break;
+
+ case PARAM_UI16:
+ i16 = FETCHD16();
+ s += sprintf( s, "%s", shexstring((UINT16)i16, 0, FALSE) );
+ break;
+
+ case PARAM_IMM64:
+ if (operand_size == 2) {
+ UINT32 lo32 = FETCHD32();
+ i32 = FETCHD32();
+ s += sprintf( s, "%s", hexstring64(lo32, i32) );
+ } else if( operand_size ) {
+ i32 = FETCHD32();
+ s += sprintf( s, "%s", hexstring(i32, 0) );
+ } else {
+ i16 = FETCHD16();
+ s += sprintf( s, "%s", hexstring(i16, 0) );
+ }
+ break;
+
+ case PARAM_IMM:
+ if( operand_size ) {
+ i32 = FETCHD32();
+ s += sprintf( s, "%s", hexstring(i32, 0) );
+ } else {
+ i16 = FETCHD16();
+ s += sprintf( s, "%s", hexstring(i16, 0) );
+ }
+ break;
+
+ case PARAM_ADDR:
+ if( operand_size ) {
+ addr = FETCHD32();
+ ptr = FETCHD16();
+ s += sprintf( s, "%s:", hexstring(ptr, 4) );
+ s += sprintf( s, "%s", hexstring(addr, 0) );
+ } else {
+ addr = FETCHD16();
+ ptr = FETCHD16();
+ s += sprintf( s, "%s:", hexstring(ptr, 4) );
+ s += sprintf( s, "%s", hexstring(addr, 0) );
+ }
+ break;
+
+ case PARAM_REL:
+ if( operand_size ) {
+ d32 = FETCHD32();
+ s += sprintf( s, "%s", hexstring(pc + d32, 0) );
+ } else {
+ /* make sure to keep the relative offset within the segment */
+ d16 = FETCHD16();
+ s += sprintf( s, "%s", hexstring((pc & 0xFFFF0000) | ((pc + d16) & 0x0000FFFF), 0) );
+ }
+ break;
+
+ case PARAM_REL8:
+ d8 = FETCHD();
+ s += sprintf( s, "%s", hexstring(pc + d8, 0) );
+ break;
+
+ case PARAM_MEM_OFFS_B:
+ d8 = FETCHD();
+ s += sprintf( s, "[%s]", hexstring(d8, 0) );
+ break;
+
+ case PARAM_MEM_OFFS_V:
+ if( address_size ) {
+ d32 = FETCHD32();
+ s += sprintf( s, "[%s]", hexstring(d32, 0) );
+ } else {
+ d32 = FETCHD16();
+ s += sprintf( s, "[%s]", hexstring(d32, 0) );
+ }
+ break;
+
+ case PARAM_SREG:
+ s += sprintf( s, "%s", i386_sreg[MODRM_REG1] );
+ break;
+
+ case PARAM_CREG:
+ s += sprintf( s, "cr%d", MODRM_REG1 | regex );
+ break;
+
+ case PARAM_TREG:
+ s += sprintf( s, "tr%d", MODRM_REG1 | regex );
+ break;
+
+ case PARAM_1:
+ s += sprintf( s, "1" );
+ break;
+
+ case PARAM_DX:
+ s += sprintf( s, "dx" );
+ break;
+
+ case PARAM_AL: s += sprintf( s, "al" ); break;
+ case PARAM_CL: s += sprintf( s, "cl" ); break;
+ case PARAM_DL: s += sprintf( s, "dl" ); break;
+ case PARAM_BL: s += sprintf( s, "bl" ); break;
+ case PARAM_AH: s += sprintf( s, "ah" ); break;
+ case PARAM_CH: s += sprintf( s, "ch" ); break;
+ case PARAM_DH: s += sprintf( s, "dh" ); break;
+ case PARAM_BH: s += sprintf( s, "bh" ); break;
+
+ case PARAM_EAX: s += sprintf( s, "%s", i386_reg[operand_size][0 | rmex] ); break;
+ case PARAM_ECX: s += sprintf( s, "%s", i386_reg[operand_size][1 | rmex] ); break;
+ case PARAM_EDX: s += sprintf( s, "%s", i386_reg[operand_size][2 | rmex] ); break;
+ case PARAM_EBX: s += sprintf( s, "%s", i386_reg[operand_size][3 | rmex] ); break;
+ case PARAM_ESP: s += sprintf( s, "%s", i386_reg[operand_size][4 | rmex] ); break;
+ case PARAM_EBP: s += sprintf( s, "%s", i386_reg[operand_size][5 | rmex] ); break;
+ case PARAM_ESI: s += sprintf( s, "%s", i386_reg[operand_size][6 | rmex] ); break;
+ case PARAM_EDI: s += sprintf( s, "%s", i386_reg[operand_size][7 | rmex] ); break;
+ }
+ return s;
+}
+
+static void handle_fpu(char *s, UINT8 op1, UINT8 op2)
+{
+ switch (op1 & 0x7)
+ {
+ case 0: // Group D8
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fadd dword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "fmul dword ptr %s", modrm_string); break;
+ case 2: sprintf(s, "fcom dword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fcomp dword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fsub dword ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fsubr dword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fdiv dword ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fdivr dword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fadd st(0),st(%d)", op2 & 0x7); break;
+ case 1: sprintf(s, "fcom st(0),st(%d)", op2 & 0x7); break;
+ case 2: sprintf(s, "fsub st(0),st(%d)", op2 & 0x7); break;
+ case 3: sprintf(s, "fdiv st(0),st(%d)", op2 & 0x7); break;
+ case 4: sprintf(s, "fmul st(0),st(%d)", op2 & 0x7); break;
+ case 5: sprintf(s, "fcomp st(0),st(%d)", op2 & 0x7); break;
+ case 6: sprintf(s, "fsubr st(0),st(%d)", op2 & 0x7); break;
+ case 7: sprintf(s, "fdivr st(0),st(%d)", op2 & 0x7); break;
+ }
+ }
+ break;
+ }
+
+ case 1: // Group D9
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fld dword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "??? (FPU)"); break;
+ case 2: sprintf(s, "fst dword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fstp dword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fldenv word ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fldcw word ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fstenv word ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fstcw word ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "fld st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fxch st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x10: sprintf(s, "fnop"); break;
+ case 0x20: sprintf(s, "fchs"); break;
+ case 0x21: sprintf(s, "fabs"); break;
+ case 0x24: sprintf(s, "ftst"); break;
+ case 0x25: sprintf(s, "fxam"); break;
+ case 0x28: sprintf(s, "fld1"); break;
+ case 0x29: sprintf(s, "fldl2t"); break;
+ case 0x2a: sprintf(s, "fldl2e"); break;
+ case 0x2b: sprintf(s, "fldpi"); break;
+ case 0x2c: sprintf(s, "fldlg2"); break;
+ case 0x2d: sprintf(s, "fldln2"); break;
+ case 0x2e: sprintf(s, "fldz"); break;
+ case 0x30: sprintf(s, "f2xm1"); break;
+ case 0x31: sprintf(s, "fyl2x"); break;
+ case 0x32: sprintf(s, "fptan"); break;
+ case 0x33: sprintf(s, "fpatan"); break;
+ case 0x34: sprintf(s, "fxtract"); break;
+ case 0x35: sprintf(s, "fprem1"); break;
+ case 0x36: sprintf(s, "fdecstp"); break;
+ case 0x37: sprintf(s, "fincstp"); break;
+ case 0x38: sprintf(s, "fprem"); break;
+ case 0x39: sprintf(s, "fyl2xp1"); break;
+ case 0x3a: sprintf(s, "fsqrt"); break;
+ case 0x3b: sprintf(s, "fsincos"); break;
+ case 0x3c: sprintf(s, "frndint"); break;
+ case 0x3d: sprintf(s, "fscale"); break;
+ case 0x3e: sprintf(s, "fsin"); break;
+ case 0x3f: sprintf(s, "fcos"); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 2: // Group DA
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fiadd dword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "fimul dword ptr %s", modrm_string); break;
+ case 2: sprintf(s, "ficom dword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "ficomp dword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fisub dword ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fisubr dword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fidiv dword ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fidivr dword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "fcmovb st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fcmove st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ sprintf(s, "fcmovbe st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ sprintf(s, "fcmovu st(0),st(%d)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+
+ }
+ }
+ break;
+ }
+
+ case 3: // Group DB
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fild dword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "??? (FPU)"); break;
+ case 2: sprintf(s, "fist dword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fistp dword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "??? (FPU)"); break;
+ case 5: sprintf(s, "fld tword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "??? (FPU)"); break;
+ case 7: sprintf(s, "fstp tword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "fcmovnb st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fcmovne st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ sprintf(s, "fcmovnbe st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ sprintf(s, "fcmovnu st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x22: sprintf(s, "fclex"); break;
+ case 0x23: sprintf(s, "finit"); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fucomi st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ sprintf(s, "fcomi st(0),st(%d)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 4: // Group DC
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fadd qword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "fmul qword ptr %s", modrm_string); break;
+ case 2: sprintf(s, "fcom qword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fcomp qword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fsub qword ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fsubr qword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fdiv qword ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fdivr qword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "fadd st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fmul st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+ sprintf(s, "fsubr st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fsub st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ sprintf(s, "fdivr st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ sprintf(s, "fdiv st(%d),st(0)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 5: // Group DD
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fld qword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "??? (FPU)"); break;
+ case 2: sprintf(s, "fst qword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fstp qword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "frstor %s", modrm_string); break;
+ case 5: sprintf(s, "??? (FPU)"); break;
+ case 6: sprintf(s, "fsave %s", modrm_string); break;
+ case 7: sprintf(s, "fstsw word ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "ffree st(%d)", op2 & 0x7); break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ sprintf(s, "fst st(%d)", op2 & 0x7); break;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ sprintf(s, "fstp st(%d)", op2 & 0x7); break;
+
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+ sprintf(s, "fucom st(%d), st(0)", op2 & 0x7); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fucomp st(%d)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 6: // Group DE
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fiadd word ptr %s", modrm_string); break;
+ case 1: sprintf(s, "fimul word ptr %s", modrm_string); break;
+ case 2: sprintf(s, "ficom word ptr %s", modrm_string); break;
+ case 3: sprintf(s, "ficomp word ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fisub word ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fisubr word ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fidiv word ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fidivr word ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "faddp st(%d)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fmulp st(%d)", op2 & 0x7); break;
+
+ case 0x19: sprintf(s, "fcompp"); break;
+
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+ sprintf(s, "fsubrp st(%d)", op2 & 0x7); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fsubp st(%d)", op2 & 0x7); break;
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ sprintf(s, "fdivrp st(%d), st(0)", op2 & 0x7); break;
+
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ sprintf(s, "fdivp st(%d)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 7: // Group DF
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fild word ptr %s", modrm_string); break;
+ case 1: sprintf(s, "??? (FPU)"); break;
+ case 2: sprintf(s, "fist word ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fistp word ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fbld %s", modrm_string); break;
+ case 5: sprintf(s, "fild qword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fbstp %s", modrm_string); break;
+ case 7: sprintf(s, "fistp qword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x20: sprintf(s, "fstsw ax"); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fucomip st(%d)", op2 & 0x7); break;
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ sprintf(s, "fcomip st(%d),st(0)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void decode_opcode(char *s, const I386_OPCODE *op, UINT8 op1)
+{
+ int i;
+ UINT8 op2;
+
+ if (op->flags & SPECIAL64)
+ op = &x64_opcode_alt[op->flags >> 24];
+
+ switch( op->flags & FLAGS_MASK )
+ {
+ case ISREX:
+ if (curmode == 64)
+ {
+ rex = op1;
+ operand_size = (op1 & 8) ? 2 : 1;
+ regex = (op1 << 1) & 8;
+ sibex = (op1 << 2) & 8;
+ rmex = (op1 << 3) & 8;
+ op2 = FETCH();
+ decode_opcode( s, &i386_opcode_table1[op2], op1 );
+ return;
+ }
+ break;
+
+ case OP_SIZE:
+ rex = regex = sibex = rmex = 0;
+ if (operand_size < 2)
+ operand_size ^= 1;
+ op2 = FETCH();
+ decode_opcode( s, &i386_opcode_table1[op2], op2 );
+ return;
+
+ case ADDR_SIZE:
+ rex = regex = sibex = rmex = 0;
+ if (curmode != 64)
+ address_size ^= 1;
+ else
+ address_size ^= 3;
+ op2 = FETCH();
+ decode_opcode( s, &i386_opcode_table1[op2], op2 );
+ return;
+
+ case TWO_BYTE:
+ if (&opcode_ptr[-2] >= opcode_ptr_base)
+ pre0f = opcode_ptr[-2];
+ op2 = FETCHD();
+ decode_opcode( s, &i386_opcode_table2[op2], op1 );
+ return;
+
+ case SEG_CS:
+ case SEG_DS:
+ case SEG_ES:
+ case SEG_FS:
+ case SEG_GS:
+ case SEG_SS:
+ rex = regex = sibex = rmex = 0;
+ segment = op->flags;
+ op2 = FETCH();
+ decode_opcode( s, &i386_opcode_table1[op2], op2 );
+ return;
+
+ case PREFIX:
+ op2 = FETCH();
+ if (op2 != 0x0f)
+ s += sprintf( s, "%-7s ", op->mnemonic );
+ decode_opcode( s, &i386_opcode_table1[op2], op2 );
+ return;
+
+ case GROUP:
+ handle_modrm( modrm_string );
+ for( i=0; i < ARRAY_LENGTH(group_op_table); i++ ) {
+ if( mame_stricmp(op->mnemonic, group_op_table[i].mnemonic) == 0 ) {
+ decode_opcode( s, &group_op_table[i].opcode[MODRM_REG1], op1 );
+ return;
+ }
+ }
+ goto handle_unknown;
+
+ case FPU:
+ op2 = FETCHD();
+ handle_fpu( s, op1, op2);
+ return;
+
+ case MODRM:
+ handle_modrm( modrm_string );
+ break;
+ }
+
+ if ((op->flags & ALWAYS64) && curmode == 64)
+ operand_size = 2;
+
+ if ((op->flags & VAR_NAME) && operand_size > 0)
+ {
+ const char *mnemonic = op->mnemonic + strlen(op->mnemonic) + 1;
+ if (operand_size == 2)
+ mnemonic += strlen(mnemonic) + 1;
+ s += sprintf( s, "%-7s ", mnemonic );
+ }
+ else if (op->flags & VAR_NAME4)
+ {
+ const char *mnemonic = op->mnemonic;
+ int which = (pre0f == 0xf3) ? 3 : (pre0f == 0xf2) ? 2 : (pre0f == 0x66) ? 1 : 0;
+ while (which--)
+ mnemonic += strlen(mnemonic) + 1;
+ s += sprintf( s, "%-7s ", mnemonic );
+ }
+ else
+ s += sprintf( s, "%-7s ", op->mnemonic );
+ dasm_flags = op->dasm_flags;
+
+ if( op->param1 != 0 ) {
+ s = handle_param( s, op->param1 );
+ }
+
+ if( op->param2 != 0 ) {
+ s += sprintf( s, "," );
+ s = handle_param( s, op->param2 );
+ }
+
+ if( op->param3 != 0 ) {
+ s += sprintf( s, "," );
+ s = handle_param( s, op->param3 );
+ }
+ return;
+
+handle_unknown:
+ sprintf(s, "???");
+}
+
+int i386_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom, int mode)
+{
+ UINT8 op;
+
+ opcode_ptr = opcode_ptr_base = oprom;
+ address_size = (mode == 16) ? 0 : (mode == 32) ? 1 : 2;
+ operand_size = (mode == 16) ? 0 : 1;
+ pc = eip;
+ dasm_flags = 0;
+ segment = 0;
+ curmode = mode;
+ pre0f = 0;
+ rex = regex = sibex = rmex = 0;
+
+ op = FETCH();
+
+ decode_opcode( buffer, &i386_opcode_table1[op], op );
+ return (pc-eip) | dasm_flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/i386/i386intf.h b/src/emu/cpu/i386/i386intf.h
new file mode 100644
index 00000000000..d8af4a27bd4
--- /dev/null
+++ b/src/emu/cpu/i386/i386intf.h
@@ -0,0 +1,11 @@
+#ifndef __I386INTF_H
+#define __I386INTF_H
+
+#include "cpuintrf.h"
+
+void i386_get_info(UINT32, cpuinfo*);
+void i486_get_info(UINT32, cpuinfo*);
+void pentium_get_info(UINT32, cpuinfo*);
+void mediagx_get_info(UINT32, cpuinfo*);
+
+#endif /* __I386INTF_H */
diff --git a/src/emu/cpu/i386/i386op16.c b/src/emu/cpu/i386/i386op16.c
new file mode 100644
index 00000000000..7eb7deffa4a
--- /dev/null
+++ b/src/emu/cpu/i386/i386op16.c
@@ -0,0 +1,3156 @@
+static UINT16 I386OP(shift_rotate16)(UINT8 modrm, UINT32 value, UINT8 shift)
+{
+ UINT16 src = value;
+ UINT16 dst = value;
+
+ if( shift == 0 ) {
+ CYCLES_RM(modrm, 3, 7);
+ } else if( shift == 1 ) {
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* ROL rm16, 1 */
+ I.CF = (src & 0x8000) ? 1 : 0;
+ dst = (src << 1) + I.CF;
+ I.OF = ((src ^ dst) & 0x8000) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 1: /* ROR rm16, 1 */
+ I.CF = (src & 0x1) ? 1 : 0;
+ dst = (I.CF << 15) | (src >> 1);
+ I.OF = ((src ^ dst) & 0x8000) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 2: /* RCL rm16, 1 */
+ dst = (src << 1) + I.CF;
+ I.CF = (src & 0x8000) ? 1 : 0;
+ I.OF = ((src ^ dst) & 0x8000) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 3: /* RCR rm16, 1 */
+ dst = (I.CF << 15) | (src >> 1);
+ I.CF = src & 0x1;
+ I.OF = ((src ^ dst) & 0x8000) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 4: /* SHL/SAL rm16, 1 */
+ case 6:
+ dst = src << 1;
+ I.CF = (src & 0x8000) ? 1 : 0;
+ I.OF = (((I.CF << 15) ^ dst) & 0x8000) ? 1 : 0;
+ SetSZPF16(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 5: /* SHR rm16, 1 */
+ dst = src >> 1;
+ I.CF = src & 0x1;
+ I.OF = (dst & 0x8000) ? 1 : 0;
+ SetSZPF16(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 7: /* SAR rm16, 1 */
+ dst = (INT16)(src) >> 1;
+ I.CF = src & 0x1;
+ I.OF = 0;
+ SetSZPF16(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ }
+ } else {
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* ROL rm16, i8 */
+ dst = ((src & ((UINT16)0xffff >> shift)) << shift) |
+ ((src & ((UINT16)0xffff << (16-shift))) >> (16-shift));
+ I.CF = (src >> (16-shift)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 1: /* ROR rm16, i8 */
+ dst = ((src & ((UINT16)0xffff << shift)) >> shift) |
+ ((src & ((UINT16)0xffff >> (16-shift))) << (16-shift));
+ I.CF = (src >> (shift-1)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 2: /* RCL rm16, i8 */
+ dst = ((src & ((UINT16)0xffff >> shift)) << shift) |
+ ((src & ((UINT16)0xffff << (17-shift))) >> (17-shift)) |
+ (I.CF << (shift-1));
+ I.CF = (src >> (16-shift)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 3: /* RCR rm16, i8 */
+ dst = ((src & ((UINT16)0xffff << shift)) >> shift) |
+ ((src & ((UINT16)0xffff >> (16-shift))) << (17-shift)) |
+ (I.CF << (16-shift));
+ I.CF = (src >> (shift-1)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 4: /* SHL/SAL rm16, i8 */
+ case 6:
+ dst = src << shift;
+ I.CF = (src & (1 << (16-shift))) ? 1 : 0;
+ SetSZPF16(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 5: /* SHR rm16, i8 */
+ dst = src >> shift;
+ I.CF = (src & (1 << (shift-1))) ? 1 : 0;
+ SetSZPF16(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 7: /* SAR rm16, i8 */
+ dst = (INT16)src >> shift;
+ I.CF = (src & (1 << (shift-1))) ? 1 : 0;
+ SetSZPF16(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ }
+
+ }
+ return dst;
+}
+
+
+
+static void I386OP(adc_rm16_r16)(void) // Opcode 0x11
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm);
+ dst = LOAD_RM16(modrm);
+ src = ADD16(src, I.CF);
+ dst = ADD16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm);
+ dst = READ16(ea);
+ src = ADD16(src, I.CF);
+ dst = ADD16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(adc_r16_rm16)(void) // Opcode 0x13
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ dst = LOAD_REG16(modrm);
+ src = ADD16(src, I.CF);
+ dst = ADD16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ dst = LOAD_REG16(modrm);
+ src = ADD16(src, I.CF);
+ dst = ADD16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(adc_ax_i16)(void) // Opcode 0x15
+{
+ UINT16 src, dst;
+ src = FETCH16();
+ dst = REG16(AX);
+ src = ADD16(src, I.CF);
+ dst = ADD16(dst, src);
+ REG16(AX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(add_rm16_r16)(void) // Opcode 0x01
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm);
+ dst = LOAD_RM16(modrm);
+ dst = ADD16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm);
+ dst = READ16(ea);
+ dst = ADD16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(add_r16_rm16)(void) // Opcode 0x03
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ dst = LOAD_REG16(modrm);
+ dst = ADD16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ dst = LOAD_REG16(modrm);
+ dst = ADD16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(add_ax_i16)(void) // Opcode 0x05
+{
+ UINT16 src, dst;
+ src = FETCH16();
+ dst = REG16(AX);
+ dst = ADD16(dst, src);
+ REG16(AX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(and_rm16_r16)(void) // Opcode 0x21
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm);
+ dst = LOAD_RM16(modrm);
+ dst = AND16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm);
+ dst = READ16(ea);
+ dst = AND16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(and_r16_rm16)(void) // Opcode 0x23
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ dst = LOAD_REG16(modrm);
+ dst = AND16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ dst = LOAD_REG16(modrm);
+ dst = AND16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(and_ax_i16)(void) // Opcode 0x25
+{
+ UINT16 src, dst;
+ src = FETCH16();
+ dst = REG16(AX);
+ dst = AND16(dst, src);
+ REG16(AX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(bsf_r16_rm16)(void) // Opcode 0x0f bc
+{
+ UINT16 src, dst, temp;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ }
+
+ dst = 0;
+
+ if( src == 0 ) {
+ I.ZF = 1;
+ } else {
+ I.ZF = 0;
+ temp = 0;
+ while( (src & (1 << temp)) == 0 ) {
+ temp++;
+ dst = temp;
+ CYCLES(CYCLES_BSF);
+ }
+ }
+ CYCLES(CYCLES_BSF_BASE);
+ STORE_REG16(modrm, dst);
+}
+
+static void I386OP(bsr_r16_rm16)(void) // Opcode 0x0f bd
+{
+ UINT16 src, dst, temp;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ }
+
+ dst = 0;
+
+ if( src == 0 ) {
+ I.ZF = 1;
+ } else {
+ I.ZF = 0;
+ temp = 15;
+ while( (src & (1 << temp)) == 0 ) {
+ temp--;
+ dst = temp;
+ CYCLES(CYCLES_BSR);
+ }
+ }
+ CYCLES(CYCLES_BSR_BASE);
+ STORE_REG16(modrm, dst);
+}
+
+
+static void I386OP(bt_rm16_r16)(void) // Opcode 0x0f a3
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 bit = LOAD_REG16(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+
+ CYCLES(CYCLES_BT_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 bit = LOAD_REG16(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+
+ CYCLES(CYCLES_BT_REG_MEM);
+ }
+}
+
+static void I386OP(btc_rm16_r16)(void) // Opcode 0x0f bb
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 bit = LOAD_REG16(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst ^= (1 << bit);
+
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_BTC_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 bit = LOAD_REG16(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst ^= (1 << bit);
+
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_BTC_REG_MEM);
+ }
+}
+
+static void I386OP(btr_rm16_r16)(void) // Opcode 0x0f b3
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 bit = LOAD_REG16(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst &= ~(1 << bit);
+
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_BTR_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 bit = LOAD_REG16(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst &= ~(1 << bit);
+
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_BTR_REG_MEM);
+ }
+}
+
+static void I386OP(bts_rm16_r16)(void) // Opcode 0x0f ab
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 bit = LOAD_REG16(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst |= (1 << bit);
+
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_BTS_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 bit = LOAD_REG16(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst |= (1 << bit);
+
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_BTS_REG_MEM);
+ }
+}
+
+static void I386OP(call_abs16)(void) // Opcode 0x9a
+{
+ UINT16 offset = FETCH16();
+ UINT16 ptr = FETCH16();
+
+ if( PROTECTED_MODE ) {
+ /* TODO */
+ fatalerror("i386: call_abs16 in protected mode unimplemented");
+ } else {
+ if (I.sreg[CS].d)
+ {
+ PUSH32( I.sreg[CS].selector );
+ PUSH32( I.eip );
+ }
+ else
+ {
+ PUSH16( I.sreg[CS].selector );
+ PUSH16( I.eip );
+ }
+ I.sreg[CS].selector = ptr;
+ I.eip = offset;
+ i386_load_segment_descriptor(CS);
+ }
+ CYCLES(CYCLES_CALL_INTERSEG); /* TODO: Timing = 17 + m */
+ CHANGE_PC(I.eip);
+}
+
+static void I386OP(call_rel16)(void) // Opcode 0xe8
+{
+ INT16 disp = FETCH16();
+
+ PUSH16( I.eip );
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_CALL); /* TODO: Timing = 7 + m */
+}
+
+static void I386OP(cbw)(void) // Opcode 0x98
+{
+ REG16(AX) = (INT16)((INT8)REG8(AL));
+ CYCLES(CYCLES_CBW);
+}
+
+static void I386OP(cmp_rm16_r16)(void) // Opcode 0x39
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm);
+ dst = LOAD_RM16(modrm);
+ SUB16(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm);
+ dst = READ16(ea);
+ SUB16(dst, src);
+ CYCLES(CYCLES_CMP_REG_MEM);
+ }
+}
+
+static void I386OP(cmp_r16_rm16)(void) // Opcode 0x3b
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ dst = LOAD_REG16(modrm);
+ SUB16(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ dst = LOAD_REG16(modrm);
+ SUB16(dst, src);
+ CYCLES(CYCLES_CMP_MEM_REG);
+ }
+}
+
+static void I386OP(cmp_ax_i16)(void) // Opcode 0x3d
+{
+ UINT16 src, dst;
+ src = FETCH16();
+ dst = REG16(AX);
+ SUB16(dst, src);
+ CYCLES(CYCLES_CMP_IMM_ACC);
+}
+
+static void I386OP(cmpsw)(void) // Opcode 0xa7
+{
+ UINT32 eas, ead;
+ UINT16 src, dst;
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.address_size ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.address_size ? REG32(ESI) : REG16(SI) );
+ }
+ ead = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ src = READ16(eas);
+ dst = READ16(ead);
+ SUB16(dst, src);
+ BUMP_SI(2);
+ BUMP_DI(2);
+ CYCLES(CYCLES_CMPS);
+}
+
+static void I386OP(cwd)(void) // Opcode 0x99
+{
+ if( REG16(AX) & 0x8000 ) {
+ REG16(DX) = 0xffff;
+ } else {
+ REG16(DX) = 0x0000;
+ }
+ CYCLES(CYCLES_CWD);
+}
+
+static void I386OP(dec_ax)(void) // Opcode 0x48
+{
+ REG16(AX) = DEC16( REG16(AX) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_cx)(void) // Opcode 0x49
+{
+ REG16(CX) = DEC16( REG16(CX) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_dx)(void) // Opcode 0x4a
+{
+ REG16(DX) = DEC16( REG16(DX) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_bx)(void) // Opcode 0x4b
+{
+ REG16(BX) = DEC16( REG16(BX) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_sp)(void) // Opcode 0x4c
+{
+ REG16(SP) = DEC16( REG16(SP) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_bp)(void) // Opcode 0x4d
+{
+ REG16(BP) = DEC16( REG16(BP) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_si)(void) // Opcode 0x4e
+{
+ REG16(SI) = DEC16( REG16(SI) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_di)(void) // Opcode 0x4f
+{
+ REG16(DI) = DEC16( REG16(DI) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(imul_r16_rm16)(void) // Opcode 0x0f af
+{
+ UINT8 modrm = FETCH();
+ INT32 result;
+ INT32 src, dst;
+ if( modrm >= 0xc0 ) {
+ src = (INT32)(INT16)LOAD_RM16(modrm);
+ CYCLES(CYCLES_IMUL16_REG_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = (INT32)(INT16)READ16(ea);
+ CYCLES(CYCLES_IMUL16_REG_MEM); /* TODO: Correct multiply timing */
+ }
+
+ dst = (INT32)(INT16)LOAD_REG16(modrm);
+ result = src * dst;
+
+ STORE_REG16(modrm, (UINT16)result);
+
+ I.CF = I.OF = !(result == (INT32)(INT16)result);
+}
+
+static void I386OP(imul_r16_rm16_i16)(void) // Opcode 0x69
+{
+ UINT8 modrm = FETCH();
+ INT32 result;
+ INT32 src, dst;
+ if( modrm >= 0xc0 ) {
+ dst = (INT32)(INT16)LOAD_RM16(modrm);
+ CYCLES(CYCLES_IMUL16_REG_IMM_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = (INT32)(INT16)READ16(ea);
+ CYCLES(CYCLES_IMUL16_MEM_IMM_REG); /* TODO: Correct multiply timing */
+ }
+
+ src = (INT32)(INT16)FETCH16();
+ result = src * dst;
+
+ STORE_REG16(modrm, (UINT16)result);
+
+ I.CF = I.OF = !(result == (INT32)(INT16)result);
+}
+
+static void I386OP(imul_r16_rm16_i8)(void) // Opcode 0x6b
+{
+ UINT8 modrm = FETCH();
+ INT32 result;
+ INT32 src, dst;
+ if( modrm >= 0xc0 ) {
+ dst = (INT32)(INT16)LOAD_RM16(modrm);
+ CYCLES(CYCLES_IMUL16_REG_IMM_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = (INT32)(INT16)READ16(ea);
+ CYCLES(CYCLES_IMUL16_MEM_IMM_REG); /* TODO: Correct multiply timing */
+ }
+
+ src = (INT32)(INT8)FETCH();
+ result = src * dst;
+
+ STORE_REG16(modrm, (UINT16)result);
+
+ I.CF = I.OF = !(result == (INT32)(INT16)result);
+}
+
+static void I386OP(in_ax_i8)(void) // Opcode 0xe5
+{
+ UINT16 port = FETCH();
+ UINT16 data = READPORT16(port);
+ REG16(AX) = data;
+ CYCLES(CYCLES_IN_VAR);
+}
+
+static void I386OP(in_ax_dx)(void) // Opcode 0xed
+{
+ UINT16 port = REG16(DX);
+ UINT16 data = READPORT16(port);
+ REG16(AX) = data;
+ CYCLES(CYCLES_IN);
+}
+
+static void I386OP(inc_ax)(void) // Opcode 0x40
+{
+ REG16(AX) = INC16( REG16(AX) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_cx)(void) // Opcode 0x41
+{
+ REG16(CX) = INC16( REG16(CX) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_dx)(void) // Opcode 0x42
+{
+ REG16(DX) = INC16( REG16(DX) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_bx)(void) // Opcode 0x43
+{
+ REG16(BX) = INC16( REG16(BX) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_sp)(void) // Opcode 0x44
+{
+ REG16(SP) = INC16( REG16(SP) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_bp)(void) // Opcode 0x45
+{
+ REG16(BP) = INC16( REG16(BP) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_si)(void) // Opcode 0x46
+{
+ REG16(SI) = INC16( REG16(SI) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_di)(void) // Opcode 0x47
+{
+ REG16(DI) = INC16( REG16(DI) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(iret16)(void) // Opcode 0xcf
+{
+ if( PROTECTED_MODE ) {
+ /* TODO: Virtual 8086-mode */
+ /* TODO: Nested task */
+ /* TODO: #SS(0) exception */
+ /* TODO: All the protection-related stuff... */
+ I.eip = POP16();
+ I.sreg[CS].selector = POP16();
+ set_flags( POP16() );
+ i386_load_segment_descriptor(CS);
+ CHANGE_PC(I.eip);
+ } else {
+ /* TODO: #SS(0) exception */
+ /* TODO: #GP(0) exception */
+ I.eip = POP16();
+ I.sreg[CS].selector = POP16();
+ set_flags( POP16() );
+ i386_load_segment_descriptor(CS);
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_IRET);
+}
+
+static void I386OP(ja_rel16)(void) // Opcode 0x0f 87
+{
+ INT16 disp = FETCH16();
+ if( I.CF == 0 && I.ZF == 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jbe_rel16)(void) // Opcode 0x0f 86
+{
+ INT16 disp = FETCH16();
+ if( I.CF != 0 || I.ZF != 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jc_rel16)(void) // Opcode 0x0f 82
+{
+ INT16 disp = FETCH16();
+ if( I.CF != 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jg_rel16)(void) // Opcode 0x0f 8f
+{
+ INT16 disp = FETCH16();
+ if( I.ZF == 0 && (I.SF == I.OF) ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jge_rel16)(void) // Opcode 0x0f 8d
+{
+ INT16 disp = FETCH16();
+ if( (I.SF == I.OF) ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jl_rel16)(void) // Opcode 0x0f 8c
+{
+ INT16 disp = FETCH16();
+ if( (I.SF != I.OF) ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jle_rel16)(void) // Opcode 0x0f 8e
+{
+ INT16 disp = FETCH16();
+ if( I.ZF != 0 || (I.SF != I.OF) ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jnc_rel16)(void) // Opcode 0x0f 83
+{
+ INT16 disp = FETCH16();
+ if( I.CF == 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jno_rel16)(void) // Opcode 0x0f 81
+{
+ INT16 disp = FETCH16();
+ if( I.OF == 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jnp_rel16)(void) // Opcode 0x0f 8b
+{
+ INT16 disp = FETCH16();
+ if( I.PF == 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jns_rel16)(void) // Opcode 0x0f 89
+{
+ INT16 disp = FETCH16();
+ if( I.SF == 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jnz_rel16)(void) // Opcode 0x0f 85
+{
+ INT16 disp = FETCH16();
+ if( I.ZF == 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jo_rel16)(void) // Opcode 0x0f 80
+{
+ INT16 disp = FETCH16();
+ if( I.OF != 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jp_rel16)(void) // Opcode 0x0f 8a
+{
+ INT16 disp = FETCH16();
+ if( I.PF != 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(js_rel16)(void) // Opcode 0x0f 88
+{
+ INT16 disp = FETCH16();
+ if( I.SF != 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jz_rel16)(void) // Opcode 0x0f 84
+{
+ INT16 disp = FETCH16();
+ if( I.ZF != 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jcxz16)(void) // Opcode 0xe3
+{
+ INT8 disp = FETCH();
+ if( REG16(CX) == 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCXZ); /* TODO: Timing = 9 + m */
+ } else {
+ CYCLES(CYCLES_JCXZ_NOBRANCH);
+ }
+}
+
+static void I386OP(jmp_rel16)(void) // Opcode 0xe9
+{
+ INT16 disp = FETCH16();
+
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JMP); /* TODO: Timing = 7 + m */
+}
+
+static void I386OP(jmp_abs16)(void) // Opcode 0xea
+{
+ UINT16 address = FETCH16();
+ UINT16 segment = FETCH16();
+
+ if( PROTECTED_MODE ) {
+ /* TODO: #GP */
+ /* TODO: access rights, etc. */
+ I.eip = address;
+ I.sreg[CS].selector = segment;
+ I.performed_intersegment_jump = 1;
+ i386_load_segment_descriptor(CS);
+ CHANGE_PC(I.eip);
+ } else {
+ I.eip = address;
+ I.sreg[CS].selector = segment;
+ I.performed_intersegment_jump = 1;
+ i386_load_segment_descriptor(CS);
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_JMP_INTERSEG);
+}
+
+static void I386OP(lea16)(void) // Opcode 0x8d
+{
+ UINT8 modrm = FETCH();
+ UINT32 ea = GetNonTranslatedEA(modrm);
+ STORE_REG16(modrm, ea);
+ CYCLES(CYCLES_LEA);
+}
+
+static void I386OP(leave16)(void) // Opcode 0xc9
+{
+ REG16(SP) = REG16(BP);
+ REG16(BP) = POP16();
+ CYCLES(CYCLES_LEAVE);
+}
+
+static void I386OP(lodsw)(void) // Opcode 0xad
+{
+ UINT32 eas;
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.address_size ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.address_size ? REG32(ESI) : REG16(SI) );
+ }
+ REG16(AX) = READ16(eas);
+ BUMP_SI(2);
+ CYCLES(CYCLES_LODS);
+}
+
+static void I386OP(loop16)(void) // Opcode 0xe2
+{
+ INT8 disp = FETCH();
+ REG16(CX)--;
+ if( REG16(CX) != 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_LOOP); /* TODO: Timing = 11 + m */
+}
+
+static void I386OP(loopne16)(void) // Opcode 0xe0
+{
+ INT8 disp = FETCH();
+ REG16(CX)--;
+ if( REG16(CX) != 0 && I.ZF == 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_LOOPNZ); /* TODO: Timing = 11 + m */
+}
+
+static void I386OP(loopz16)(void) // Opcode 0xe1
+{
+ INT8 disp = FETCH();
+ REG16(CX)--;
+ if( REG16(CX) != 0 && I.ZF != 0 ) {
+ if (I.sreg[CS].d)
+ {
+ I.eip += disp;
+ }
+ else
+ {
+ I.eip = (I.eip + disp) & 0xffff;
+ }
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_LOOPZ); /* TODO: Timing = 11 + m */
+}
+
+static void I386OP(mov_rm16_r16)(void) // Opcode 0x89
+{
+ UINT16 src;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm);
+ STORE_RM16(modrm, src);
+ CYCLES(CYCLES_MOV_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm);
+ WRITE16(ea, src);
+ CYCLES(CYCLES_MOV_REG_MEM);
+ }
+}
+
+static void I386OP(mov_r16_rm16)(void) // Opcode 0x8b
+{
+ UINT16 src;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ STORE_REG16(modrm, src);
+ CYCLES(CYCLES_MOV_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ STORE_REG16(modrm, src);
+ CYCLES(CYCLES_MOV_MEM_REG);
+ }
+}
+
+static void I386OP(mov_rm16_i16)(void) // Opcode 0xc7
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 value = FETCH16();
+ STORE_RM16(modrm, value);
+ CYCLES(CYCLES_MOV_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 value = FETCH16();
+ WRITE16(ea, value);
+ CYCLES(CYCLES_MOV_IMM_MEM);
+ }
+}
+
+static void I386OP(mov_ax_m16)(void) // Opcode 0xa1
+{
+ UINT32 offset, ea;
+ if( I.address_size ) {
+ offset = FETCH32();
+ } else {
+ offset = FETCH16();
+ }
+ /* TODO: Not sure if this is correct... */
+ if( I.segment_prefix ) {
+ ea = i386_translate( I.segment_override, offset );
+ } else {
+ ea = i386_translate( DS, offset );
+ }
+ REG16(AX) = READ16(ea);
+ CYCLES(CYCLES_MOV_MEM_ACC);
+}
+
+static void I386OP(mov_m16_ax)(void) // Opcode 0xa3
+{
+ UINT32 offset, ea;
+ if( I.address_size ) {
+ offset = FETCH32();
+ } else {
+ offset = FETCH16();
+ }
+ /* TODO: Not sure if this is correct... */
+ if( I.segment_prefix ) {
+ ea = i386_translate( I.segment_override, offset );
+ } else {
+ ea = i386_translate( DS, offset );
+ }
+ WRITE16( ea, REG16(AX) );
+ CYCLES(CYCLES_MOV_ACC_MEM);
+}
+
+static void I386OP(mov_ax_i16)(void) // Opcode 0xb8
+{
+ REG16(AX) = FETCH16();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_cx_i16)(void) // Opcode 0xb9
+{
+ REG16(CX) = FETCH16();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_dx_i16)(void) // Opcode 0xba
+{
+ REG16(DX) = FETCH16();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_bx_i16)(void) // Opcode 0xbb
+{
+ REG16(BX) = FETCH16();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_sp_i16)(void) // Opcode 0xbc
+{
+ REG16(SP) = FETCH16();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_bp_i16)(void) // Opcode 0xbd
+{
+ REG16(BP) = FETCH16();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_si_i16)(void) // Opcode 0xbe
+{
+ REG16(SI) = FETCH16();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_di_i16)(void) // Opcode 0xbf
+{
+ REG16(DI) = FETCH16();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(movsw)(void) // Opcode 0xa5
+{
+ UINT32 eas, ead;
+ UINT16 v;
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.address_size ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.address_size ? REG32(ESI) : REG16(SI) );
+ }
+ ead = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ v = READ16(eas);
+ WRITE16(ead, v);
+ BUMP_SI(2);
+ BUMP_DI(2);
+ CYCLES(CYCLES_MOVS);
+}
+
+static void I386OP(movsx_r16_rm8)(void) // Opcode 0x0f be
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ INT16 src = (INT8)LOAD_RM8(modrm);
+ STORE_REG16(modrm, src);
+ CYCLES(CYCLES_MOVSX_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ INT16 src = (INT8)READ8(ea);
+ STORE_REG16(modrm, src);
+ CYCLES(CYCLES_MOVSX_MEM_REG);
+ }
+}
+
+static void I386OP(movzx_r16_rm8)(void) // Opcode 0x0f b6
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 src = (UINT8)LOAD_RM8(modrm);
+ STORE_REG16(modrm, src);
+ CYCLES(CYCLES_MOVZX_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 src = (UINT8)READ8(ea);
+ STORE_REG16(modrm, src);
+ CYCLES(CYCLES_MOVZX_MEM_REG);
+ }
+}
+
+static void I386OP(or_rm16_r16)(void) // Opcode 0x09
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm);
+ dst = LOAD_RM16(modrm);
+ dst = OR16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm);
+ dst = READ16(ea);
+ dst = OR16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(or_r16_rm16)(void) // Opcode 0x0b
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ dst = LOAD_REG16(modrm);
+ dst = OR16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ dst = LOAD_REG16(modrm);
+ dst = OR16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(or_ax_i16)(void) // Opcode 0x0d
+{
+ UINT16 src, dst;
+ src = FETCH16();
+ dst = REG16(AX);
+ dst = OR16(dst, src);
+ REG16(AX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(out_ax_i8)(void) // Opcode 0xe7
+{
+ UINT16 port = FETCH();
+ UINT16 data = REG16(AX);
+ WRITEPORT16(port, data);
+ CYCLES(CYCLES_OUT_VAR);
+}
+
+static void I386OP(out_ax_dx)(void) // Opcode 0xef
+{
+ UINT16 port = REG16(DX);
+ UINT16 data = REG16(AX);
+ WRITEPORT16(port, data);
+ CYCLES(CYCLES_OUT);
+}
+
+static void I386OP(pop_ax)(void) // Opcode 0x58
+{
+ REG16(AX) = POP16();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_cx)(void) // Opcode 0x59
+{
+ REG16(CX) = POP16();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_dx)(void) // Opcode 0x5a
+{
+ REG16(DX) = POP16();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_bx)(void) // Opcode 0x5b
+{
+ REG16(BX) = POP16();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_sp)(void) // Opcode 0x5c
+{
+ REG16(SP) = POP16();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_bp)(void) // Opcode 0x5d
+{
+ REG16(BP) = POP16();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_si)(void) // Opcode 0x5e
+{
+ REG16(SI) = POP16();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_di)(void) // Opcode 0x5f
+{
+ REG16(DI) = POP16();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_ds16)(void) // Opcode 0x1f
+{
+ I.sreg[DS].selector = POP16();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(DS);
+ } else {
+ i386_load_segment_descriptor(DS);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_es16)(void) // Opcode 0x07
+{
+ I.sreg[ES].selector = POP16();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(ES);
+ } else {
+ i386_load_segment_descriptor(ES);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_fs16)(void) // Opcode 0x0f a1
+{
+ I.sreg[FS].selector = POP16();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(FS);
+ } else {
+ i386_load_segment_descriptor(FS);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_gs16)(void) // Opcode 0x0f a9
+{
+ I.sreg[GS].selector = POP16();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(GS);
+ } else {
+ i386_load_segment_descriptor(GS);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_ss16)(void) // Opcode 0x17
+{
+ I.sreg[SS].selector = POP16();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(SS);
+ } else {
+ i386_load_segment_descriptor(SS);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_rm16)(void) // Opcode 0x8f
+{
+ UINT8 modrm = FETCH();
+ UINT16 value = POP16();
+
+ if( modrm >= 0xc0 ) {
+ STORE_RM16(modrm, value);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE16(ea, value);
+ }
+ CYCLES(CYCLES_POP_RM);
+}
+
+static void I386OP(popa)(void) // Opcode 0x61
+{
+ REG16(DI) = POP16();
+ REG16(SI) = POP16();
+ REG16(BP) = POP16();
+ REG16(SP) += 2;
+ REG16(BX) = POP16();
+ REG16(DX) = POP16();
+ REG16(CX) = POP16();
+ REG16(AX) = POP16();
+ CYCLES(CYCLES_POPA);
+}
+
+static void I386OP(popf)(void) // Opcode 0x9d
+{
+ UINT16 value = POP16();
+ set_flags(value);
+ CYCLES(CYCLES_POPF);
+}
+
+static void I386OP(push_ax)(void) // Opcode 0x50
+{
+ PUSH16( REG16(AX) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_cx)(void) // Opcode 0x51
+{
+ PUSH16( REG16(CX) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_dx)(void) // Opcode 0x52
+{
+ PUSH16( REG16(DX) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_bx)(void) // Opcode 0x53
+{
+ PUSH16( REG16(BX) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_sp)(void) // Opcode 0x54
+{
+ PUSH16( REG16(SP) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_bp)(void) // Opcode 0x55
+{
+ PUSH16( REG16(BP) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_si)(void) // Opcode 0x56
+{
+ PUSH16( REG16(SI) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_di)(void) // Opcode 0x57
+{
+ PUSH16( REG16(DI) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_cs16)(void) // Opcode 0x0e
+{
+ PUSH16( I.sreg[CS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_ds16)(void) // Opcode 0x1e
+{
+ PUSH16( I.sreg[DS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_es16)(void) // Opcode 0x06
+{
+ PUSH16( I.sreg[ES].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_fs16)(void) // Opcode 0x0f a0
+{
+ PUSH16( I.sreg[FS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_gs16)(void) // Opcode 0x0f a8
+{
+ PUSH16( I.sreg[GS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_ss16)(void) // Opcode 0x16
+{
+ PUSH16( I.sreg[SS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_i16)(void) // Opcode 0x68
+{
+ UINT16 value = FETCH16();
+ PUSH16(value);
+ CYCLES(CYCLES_PUSH_IMM);
+}
+
+static void I386OP(pusha)(void) // Opcode 0x60
+{
+ UINT16 temp = REG16(SP);
+ PUSH16( REG16(AX) );
+ PUSH16( REG16(CX) );
+ PUSH16( REG16(DX) );
+ PUSH16( REG16(BX) );
+ PUSH16( temp );
+ PUSH16( REG16(BP) );
+ PUSH16( REG16(SI) );
+ PUSH16( REG16(DI) );
+ CYCLES(CYCLES_PUSHA);
+}
+
+static void I386OP(pushf)(void) // Opcode 0x9c
+{
+ PUSH16( get_flags() & 0xffff );
+ CYCLES(CYCLES_PUSHF);
+}
+
+static void I386OP(ret_near16_i16)(void) // Opcode 0xc2
+{
+ INT16 disp = FETCH16();
+ I.eip = POP16();
+ REG16(SP) += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_RET_IMM); /* TODO: Timing = 10 + m */
+}
+
+static void I386OP(ret_near16)(void) // Opcode 0xc3
+{
+ I.eip = POP16();
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_RET); /* TODO: Timing = 10 + m */
+}
+
+static void I386OP(sbb_rm16_r16)(void) // Opcode 0x19
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm) + I.CF;
+ dst = LOAD_RM16(modrm);
+ dst = SUB16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm) + I.CF;
+ dst = READ16(ea);
+ dst = SUB16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(sbb_r16_rm16)(void) // Opcode 0x1b
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm) + I.CF;
+ dst = LOAD_REG16(modrm);
+ dst = SUB16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea) + I.CF;
+ dst = LOAD_REG16(modrm);
+ dst = SUB16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(sbb_ax_i16)(void) // Opcode 0x1d
+{
+ UINT16 src, dst;
+ src = FETCH16() + I.CF;
+ dst = REG16(AX);
+ dst = SUB16(dst, src);
+ REG16(AX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(scasw)(void) // Opcode 0xaf
+{
+ UINT32 eas;
+ UINT16 src, dst;
+ eas = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ src = READ16(eas);
+ dst = REG16(AX);
+ SUB16(dst, src);
+ BUMP_DI(2);
+ CYCLES(CYCLES_SCAS);
+}
+
+static void I386OP(shld16_i8)(void) // Opcode 0x0f a4
+{
+ /* TODO: Correct flags */
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 upper = LOAD_REG16(modrm);
+ UINT8 shift = FETCH();
+ if( shift > 31 || shift == 0 ) {
+
+ } else if( shift > 15 ) {
+ I.CF = (dst & (1 << (16-shift))) ? 1 : 0;
+ dst = (upper << (shift-16)) | (upper >> (32-shift));
+ SetSZPF16(dst);
+ } else {
+ I.CF = (dst & (1 << (16-shift))) ? 1 : 0;
+ dst = (dst << shift) | (upper >> (16-shift));
+ SetSZPF16(dst);
+ }
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_SHLD_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 upper = LOAD_REG16(modrm);
+ UINT8 shift = FETCH();
+ if( shift > 31 || shift == 0 ) {
+
+ } else if( shift > 15 ) {
+ I.CF = (dst & (1 << (16-shift))) ? 1 : 0;
+ dst = (upper << (shift-16)) | (upper >> (32-shift));
+ SetSZPF16(dst);
+ } else {
+ I.CF = (dst & (1 << (16-shift))) ? 1 : 0;
+ dst = (dst << shift) | (upper >> (16-shift));
+ SetSZPF16(dst);
+ }
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_SHLD_MEM);
+ }
+}
+
+static void I386OP(shld16_cl)(void) // Opcode 0x0f a5
+{
+ /* TODO: Correct flags */
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 upper = LOAD_REG16(modrm);
+ UINT8 shift = REG8(CL);
+ if( shift > 31 || shift == 0 ) {
+
+ } else if( shift > 15 ) {
+ I.CF = (dst & (1 << (16-shift))) ? 1 : 0;
+ dst = (upper << (shift-16)) | (upper >> (32-shift));
+ SetSZPF16(dst);
+ } else {
+ I.CF = (dst & (1 << (16-shift))) ? 1 : 0;
+ dst = (dst << shift) | (upper >> (16-shift));
+ SetSZPF16(dst);
+ }
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_SHLD_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 upper = LOAD_REG16(modrm);
+ UINT8 shift = REG8(CL);
+ if( shift > 31 || shift == 0 ) {
+
+ } else if( shift > 15 ) {
+ I.CF = (dst & (1 << (16-shift))) ? 1 : 0;
+ dst = (upper << (shift-16)) | (upper >> (32-shift));
+ SetSZPF16(dst);
+ } else {
+ I.CF = (dst & (1 << (16-shift))) ? 1 : 0;
+ dst = (dst << shift) | (upper >> (16-shift));
+ SetSZPF16(dst);
+ }
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_SHLD_MEM);
+ }
+}
+
+static void I386OP(shrd16_i8)(void) // Opcode 0x0f ac
+{
+ /* TODO: Correct flags */
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 upper = LOAD_REG16(modrm);
+ UINT8 shift = FETCH();
+ if( shift > 15 || shift == 0) {
+
+ } else {
+ I.CF = (dst & (1 << (shift-1))) ? 1 : 0;
+ dst = (dst >> shift) | (upper << (16-shift));
+ SetSZPF16(dst);
+ }
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_SHRD_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 upper = LOAD_REG16(modrm);
+ UINT8 shift = FETCH();
+ if( shift > 15 || shift == 0) {
+
+ } else {
+ I.CF = (dst & (1 << (shift-1))) ? 1 : 0;
+ dst = (dst >> shift) | (upper << (16-shift));
+ SetSZPF16(dst);
+ }
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_SHRD_MEM);
+ }
+}
+
+static void I386OP(shrd16_cl)(void) // Opcode 0x0f ad
+{
+ /* TODO: Correct flags */
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 upper = LOAD_REG16(modrm);
+ UINT8 shift = REG8(CL);
+ if( shift > 15 || shift == 0) {
+
+ } else {
+ I.CF = (dst & (1 << (shift-1))) ? 1 : 0;
+ dst = (dst >> shift) | (upper << (16-shift));
+ SetSZPF16(dst);
+ }
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_SHRD_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 upper = LOAD_REG16(modrm);
+ UINT8 shift = REG8(CL);
+ if( shift > 15 || shift == 0) {
+
+ } else {
+ I.CF = (dst & (1 << (shift-1))) ? 1 : 0;
+ dst = (dst >> shift) | (upper << (16-shift));
+ SetSZPF16(dst);
+ }
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_SHRD_MEM);
+ }
+}
+
+static void I386OP(stosw)(void) // Opcode 0xab
+{
+ UINT32 ead;
+ ead = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ WRITE16(ead, REG16(AX));
+ BUMP_DI(2);
+ CYCLES(CYCLES_STOS);
+}
+
+static void I386OP(sub_rm16_r16)(void) // Opcode 0x29
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm);
+ dst = LOAD_RM16(modrm);
+ dst = SUB16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm);
+ dst = READ16(ea);
+ dst = SUB16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(sub_r16_rm16)(void) // Opcode 0x2b
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ dst = LOAD_REG16(modrm);
+ dst = SUB16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ dst = LOAD_REG16(modrm);
+ dst = SUB16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(sub_ax_i16)(void) // Opcode 0x2d
+{
+ UINT16 src, dst;
+ src = FETCH16();
+ dst = REG16(AX);
+ dst = SUB16(dst, src);
+ REG16(AX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(test_ax_i16)(void) // Opcode 0xa9
+{
+ UINT16 src = FETCH16();
+ UINT16 dst = REG16(AX);
+ dst = src & dst;
+ SetSZPF16(dst);
+ I.CF = 0;
+ I.OF = 0;
+ CYCLES(CYCLES_TEST_IMM_ACC);
+}
+
+static void I386OP(test_rm16_r16)(void) // Opcode 0x85
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm);
+ dst = LOAD_RM16(modrm);
+ dst = src & dst;
+ SetSZPF16(dst);
+ I.CF = 0;
+ I.OF = 0;
+ CYCLES(CYCLES_TEST_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm);
+ dst = READ16(ea);
+ dst = src & dst;
+ SetSZPF16(dst);
+ I.CF = 0;
+ I.OF = 0;
+ CYCLES(CYCLES_TEST_REG_MEM);
+ }
+}
+
+static void I386OP(xchg_ax_cx)(void) // Opcode 0x91
+{
+ UINT16 temp;
+ temp = REG16(AX);
+ REG16(AX) = REG16(CX);
+ REG16(CX) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_ax_dx)(void) // Opcode 0x92
+{
+ UINT16 temp;
+ temp = REG16(AX);
+ REG16(AX) = REG16(DX);
+ REG16(DX) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_ax_bx)(void) // Opcode 0x93
+{
+ UINT16 temp;
+ temp = REG16(AX);
+ REG16(AX) = REG16(BX);
+ REG16(BX) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_ax_sp)(void) // Opcode 0x94
+{
+ UINT16 temp;
+ temp = REG16(AX);
+ REG16(AX) = REG16(SP);
+ REG16(SP) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_ax_bp)(void) // Opcode 0x95
+{
+ UINT16 temp;
+ temp = REG16(AX);
+ REG16(AX) = REG16(BP);
+ REG16(BP) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_ax_si)(void) // Opcode 0x96
+{
+ UINT16 temp;
+ temp = REG16(AX);
+ REG16(AX) = REG16(SI);
+ REG16(SI) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_ax_di)(void) // Opcode 0x97
+{
+ UINT16 temp;
+ temp = REG16(AX);
+ REG16(AX) = REG16(DI);
+ REG16(DI) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_r16_rm16)(void) // Opcode 0x87
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 src = LOAD_RM16(modrm);
+ UINT16 dst = LOAD_REG16(modrm);
+ STORE_REG16(modrm, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_XCHG_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 src = READ16(ea);
+ UINT16 dst = LOAD_REG16(modrm);
+ STORE_REG16(modrm, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_XCHG_REG_MEM);
+ }
+}
+
+static void I386OP(xor_rm16_r16)(void) // Opcode 0x31
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG16(modrm);
+ dst = LOAD_RM16(modrm);
+ dst = XOR16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG16(modrm);
+ dst = READ16(ea);
+ dst = XOR16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(xor_r16_rm16)(void) // Opcode 0x33
+{
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ dst = LOAD_REG16(modrm);
+ dst = XOR16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ dst = LOAD_REG16(modrm);
+ dst = XOR16(dst, src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(xor_ax_i16)(void) // Opcode 0x35
+{
+ UINT16 src, dst;
+ src = FETCH16();
+ dst = REG16(AX);
+ dst = XOR16(dst, src);
+ REG16(AX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+
+
+static void I386OP(group81_16)(void) // Opcode 0x81
+{
+ UINT32 ea;
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: // ADD Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = FETCH16();
+ dst = ADD16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = FETCH16();
+ dst = ADD16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 1: // OR Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = FETCH16();
+ dst = OR16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = FETCH16();
+ dst = OR16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 2: // ADC Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = FETCH16();
+ src = ADD16(src, I.CF);
+ dst = ADD16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = FETCH16();
+ src = ADD16(src, I.CF);
+ dst = ADD16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 3: // SBB Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = FETCH16() + I.CF;
+ dst = SUB16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = FETCH16() + I.CF;
+ dst = SUB16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 4: // AND Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = FETCH16();
+ dst = AND16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = FETCH16();
+ dst = AND16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 5: // SUB Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = FETCH16();
+ dst = SUB16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = FETCH16();
+ dst = SUB16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 6: // XOR Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = FETCH16();
+ dst = XOR16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = FETCH16();
+ dst = XOR16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 7: // CMP Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = FETCH16();
+ SUB16(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = FETCH16();
+ SUB16(dst, src);
+ CYCLES(CYCLES_CMP_REG_MEM);
+ }
+ break;
+ }
+}
+
+static void I386OP(group83_16)(void) // Opcode 0x83
+{
+ UINT32 ea;
+ UINT16 src, dst;
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: // ADD Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = ADD16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = ADD16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 1: // OR Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = OR16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = OR16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 2: // ADC Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ src = ADD16(src, I.CF);
+ dst = ADD16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ src = ADD16(src, I.CF);
+ dst = ADD16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 3: // SBB Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = ((UINT16)(INT16)(INT8)FETCH()) + I.CF;
+ dst = SUB16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = ((UINT16)(INT16)(INT8)FETCH()) + I.CF;
+ dst = SUB16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 4: // AND Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = AND16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = AND16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 5: // SUB Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = SUB16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = SUB16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 6: // XOR Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = XOR16(dst, src);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ dst = XOR16(dst, src);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 7: // CMP Rm16, i16
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ SUB16(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ16(ea);
+ src = (UINT16)(INT16)(INT8)FETCH();
+ SUB16(dst, src);
+ CYCLES(CYCLES_CMP_REG_MEM);
+ }
+ break;
+ }
+}
+
+static void I386OP(groupC1_16)(void) // Opcode 0xc1
+{
+ UINT16 dst;
+ UINT8 modrm = FETCH();
+ UINT8 shift;
+
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ shift = FETCH() & 0x1f;
+ dst = i386_shift_rotate16(modrm, dst, shift);
+ STORE_RM16(modrm, dst);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = READ16(ea);
+ shift = FETCH() & 0x1f;
+ dst = i386_shift_rotate16(modrm, dst, shift);
+ WRITE16(ea, dst);
+ }
+}
+
+static void I386OP(groupD1_16)(void) // Opcode 0xd1
+{
+ UINT16 dst;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ dst = i386_shift_rotate16(modrm, dst, 1);
+ STORE_RM16(modrm, dst);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = READ16(ea);
+ dst = i386_shift_rotate16(modrm, dst, 1);
+ WRITE16(ea, dst);
+ }
+}
+
+static void I386OP(groupD3_16)(void) // Opcode 0xd3
+{
+ UINT16 dst;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM16(modrm);
+ dst = i386_shift_rotate16(modrm, dst, REG8(CL));
+ STORE_RM16(modrm, dst);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = READ16(ea);
+ dst = i386_shift_rotate16(modrm, dst, REG8(CL));
+ WRITE16(ea, dst);
+ }
+}
+
+static void I386OP(groupF7_16)(void) // Opcode 0xf7
+{
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* TEST Rm16, i16 */
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 src = FETCH16();
+ dst &= src;
+ I.CF = I.OF = I.AF = 0;
+ SetSZPF16(dst);
+ CYCLES(CYCLES_TEST_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 src = FETCH16();
+ dst &= src;
+ I.CF = I.OF = I.AF = 0;
+ SetSZPF16(dst);
+ CYCLES(CYCLES_TEST_IMM_MEM);
+ }
+ break;
+ case 2: /* NOT Rm16 */
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ dst = ~dst;
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_NOT_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ dst = ~dst;
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_NOT_MEM);
+ }
+ break;
+ case 3: /* NEG Rm16 */
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ dst = SUB16( 0, dst );
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_NEG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ dst = SUB16( 0, dst );
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_NEG_MEM);
+ }
+ break;
+ case 4: /* MUL AX, Rm16 */
+ {
+ UINT32 result;
+ UINT16 src, dst;
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ CYCLES(CYCLES_MUL16_ACC_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ CYCLES(CYCLES_MUL16_ACC_MEM); /* TODO: Correct multiply timing */
+ }
+
+ dst = REG16(AX);
+ result = (UINT32)src * (UINT32)dst;
+ REG16(DX) = (UINT16)(result >> 16);
+ REG16(AX) = (UINT16)result;
+
+ I.CF = I.OF = (REG16(DX) != 0);
+ }
+ break;
+ case 5: /* IMUL AX, Rm16 */
+ {
+ INT32 result;
+ INT32 src, dst;
+ if( modrm >= 0xc0 ) {
+ src = (INT32)(INT16)LOAD_RM16(modrm);
+ CYCLES(CYCLES_IMUL16_ACC_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = (INT32)(INT16)READ16(ea);
+ CYCLES(CYCLES_IMUL16_ACC_MEM); /* TODO: Correct multiply timing */
+ }
+
+ dst = (INT32)(INT16)REG16(AX);
+ result = src * dst;
+
+ REG16(DX) = (UINT16)(result >> 16);
+ REG16(AX) = (UINT16)result;
+
+ I.CF = I.OF = !(result == (INT32)(INT16)result);
+ }
+ break;
+ case 6: /* DIV AX, Rm16 */
+ {
+ UINT32 quotient, remainder, result;
+ UINT16 src;
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ CYCLES(CYCLES_DIV16_ACC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ CYCLES(CYCLES_DIV16_ACC_MEM);
+ }
+
+ quotient = ((UINT32)(REG16(DX)) << 16) | (UINT32)(REG16(AX));
+ if( src ) {
+ remainder = quotient % (UINT32)src;
+ result = quotient / (UINT32)src;
+ if( result > 0xffff ) {
+ /* TODO: Divide error */
+ } else {
+ REG16(DX) = (UINT16)remainder;
+ REG16(AX) = (UINT16)result;
+ }
+ } else {
+ /* TODO: Divide by zero */
+ }
+ }
+ break;
+ case 7: /* IDIV AX, Rm16 */
+ {
+ INT32 quotient, remainder, result;
+ UINT16 src;
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM16(modrm);
+ CYCLES(CYCLES_IDIV16_ACC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ16(ea);
+ CYCLES(CYCLES_IDIV16_ACC_MEM);
+ }
+
+ quotient = (((INT32)REG16(DX)) << 16) | ((UINT32)REG16(AX));
+ if( src ) {
+ remainder = quotient % (INT32)(INT16)src;
+ result = quotient / (INT32)(INT16)src;
+ if( result > 0xffff ) {
+ /* TODO: Divide error */
+ } else {
+ REG16(DX) = (UINT16)remainder;
+ REG16(AX) = (UINT16)result;
+ }
+ } else {
+ /* TODO: Divide by zero */
+ }
+ }
+ break;
+ }
+}
+
+static void I386OP(groupFF_16)(void) // Opcode 0xff
+{
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* INC Rm16 */
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ dst = INC16(dst);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_INC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ dst = INC16(dst);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_INC_MEM);
+ }
+ break;
+ case 1: /* DEC Rm16 */
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ dst = DEC16(dst);
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_DEC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ dst = DEC16(dst);
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_DEC_MEM);
+ }
+ break;
+ case 2: /* CALL Rm16 */
+ {
+ UINT16 address;
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ CYCLES(CYCLES_CALL_REG); /* TODO: Timing = 7 + m */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ address = READ16(ea);
+ CYCLES(CYCLES_CALL_MEM); /* TODO: Timing = 10 + m */
+ }
+ PUSH16( I.eip );
+ I.eip = address;
+ CHANGE_PC(I.eip);
+ }
+ break;
+ case 3: /* CALL FAR Rm16 */
+ {
+ UINT16 address, selector;
+ if( modrm >= 0xc0 ) {
+ fatalerror("NYI");
+ } else {
+ UINT32 ea = GetEA(modrm);
+ address = READ16(ea + 0);
+ selector = READ16(ea + 2);
+ CYCLES(CYCLES_CALL_MEM_INTERSEG); /* TODO: Timing = 10 + m */
+ }
+ PUSH16( I.sreg[CS].selector );
+ PUSH16( I.eip );
+ I.sreg[CS].selector = selector;
+ I.performed_intersegment_jump = 1;
+ i386_load_segment_descriptor( CS );
+ I.eip = address;
+ CHANGE_PC(I.eip);
+ }
+ break;
+ case 4: /* JMP Rm16 */
+ {
+ UINT16 address;
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ CYCLES(CYCLES_JMP_REG); /* TODO: Timing = 7 + m */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ address = READ16(ea);
+ CYCLES(CYCLES_JMP_MEM); /* TODO: Timing = 10 + m */
+ }
+ I.eip = address;
+ CHANGE_PC(I.eip);
+ }
+ break;
+ case 5: /* JMP FAR Rm16 */
+ {
+ UINT16 address, selector;
+ if( modrm >= 0xc0 ) {
+ fatalerror("NYI");
+ } else {
+ UINT32 ea = GetEA(modrm);
+ address = READ16(ea + 0);
+ selector = READ16(ea + 2);
+ CYCLES(CYCLES_JMP_MEM_INTERSEG); /* TODO: Timing = 10 + m */
+ }
+ I.sreg[CS].selector = selector;
+ I.performed_intersegment_jump = 1;
+ i386_load_segment_descriptor( CS );
+ I.eip = address;
+ CHANGE_PC(I.eip);
+ }
+ break;
+ case 6: /* PUSH Rm16 */
+ {
+ UINT16 value;
+ if( modrm >= 0xc0 ) {
+ value = LOAD_RM16(modrm);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ value = READ16(ea);
+ }
+ PUSH16(value);
+ CYCLES(CYCLES_PUSH_RM);
+ }
+ break;
+ case 7:
+ I386OP(invalid)();
+ break;
+ default:
+ fatalerror("i386: groupFF_16 /%d unimplemented", (modrm >> 3) & 0x7);
+ break;
+ }
+}
+
+static void I386OP(group0F00_16)(void) // Opcode 0x0f 00
+{
+ UINT32 address, ea;
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 2: /* LLDT */
+ if ( PROTECTED_MODE && !V8086_MODE )
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ CYCLES(CYCLES_LLDT_REG);
+ } else {
+ ea = GetEA(modrm);
+ CYCLES(CYCLES_LLDT_MEM);
+ }
+ I.ldtr.segment = READ16(ea);
+ }
+ else
+ {
+ i386_trap(6, 0);
+ }
+ break;
+
+ case 3: /* LTR */
+ if ( PROTECTED_MODE && !V8086_MODE )
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ CYCLES(CYCLES_LTR_REG);
+ } else {
+ ea = GetEA(modrm);
+ CYCLES(CYCLES_LTR_MEM);
+ }
+ I.task.segment = READ16(ea);
+ }
+ else
+ {
+ i386_trap(6, 0);
+ }
+ break;
+
+ default:
+ fatalerror("i386: group0F00_16 /%d unimplemented", (modrm >> 3) & 0x7);
+ break;
+ }
+}
+
+static void I386OP(group0F01_16)(void) // Opcode 0x0f 01
+{
+ UINT8 modrm = FETCH();
+ UINT16 address;
+ UINT32 ea;
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* SGDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ WRITE16(ea, I.gdtr.limit);
+ WRITE32(ea + 2, I.gdtr.base & 0xffffff);
+ CYCLES(CYCLES_SGDT);
+ break;
+ }
+ case 1: /* SIDT */
+ {
+ if (modrm >= 0xc0)
+ {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ }
+ else
+ {
+ ea = GetEA(modrm);
+ }
+ WRITE16(ea, I.idtr.limit);
+ WRITE32(ea + 2, I.idtr.base & 0xffffff);
+ CYCLES(CYCLES_SIDT);
+ break;
+ }
+ case 2: /* LGDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ I.gdtr.limit = READ16(ea);
+ I.gdtr.base = READ32(ea + 2) & 0xffffff;
+ CYCLES(CYCLES_LGDT);
+ break;
+ }
+ case 3: /* LIDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ I.idtr.limit = READ16(ea);
+ I.idtr.base = READ32(ea + 2) & 0xffffff;
+ CYCLES(CYCLES_LIDT);
+ break;
+ }
+ case 4: /* SMSW */
+ {
+ if( modrm >= 0xc0 ) {
+ STORE_RM16(modrm, I.cr[0]);
+ CYCLES(CYCLES_SMSW_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE16(ea, I.cr[0]);
+ CYCLES(CYCLES_SMSW_MEM);
+ }
+ break;
+ }
+ case 6: /* LMSW */
+ {
+ // TODO: Check for protection fault
+ UINT8 b;
+ if( modrm >= 0xc0 ) {
+ b = LOAD_RM8(modrm);
+ CYCLES(CYCLES_LMSW_REG);
+ } else {
+ ea = GetEA(modrm);
+ CYCLES(CYCLES_LMSW_MEM);
+ b = READ8(ea);
+ }
+ I.cr[0] &= ~0x03;
+ I.cr[0] |= b & 0x03;
+ break;
+ }
+ default:
+ fatalerror("i386: unimplemented opcode 0x0f 01 /%d at %08X", (modrm >> 3) & 0x7, I.eip - 2);
+ break;
+ }
+}
+
+static void I386OP(group0FBA_16)(void) // Opcode 0x0f ba
+{
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 4: /* BT Rm16, i8 */
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+
+ CYCLES(CYCLES_BT_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+
+ CYCLES(CYCLES_BT_IMM_MEM);
+ }
+ break;
+ case 5: /* BTS Rm16, i8 */
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst |= (1 << bit);
+
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_BTS_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst |= (1 << bit);
+
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_BTS_IMM_MEM);
+ }
+ break;
+ case 6: /* BTR Rm16, i8 */
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst &= ~(1 << bit);
+
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_BTR_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst &= ~(1 << bit);
+
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_BTR_IMM_MEM);
+ }
+ break;
+ case 7: /* BTC Rm16, i8 */
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst ^= (1 << bit);
+
+ STORE_RM16(modrm, dst);
+ CYCLES(CYCLES_BTC_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst ^= (1 << bit);
+
+ WRITE16(ea, dst);
+ CYCLES(CYCLES_BTC_IMM_MEM);
+ }
+ break;
+ default:
+ fatalerror("i386: group0FBA_16 /%d unknown", (modrm >> 3) & 0x7);
+ break;
+ }
+}
+
+static void I386OP(bound_r16_m16_m16)(void) // Opcode 0x62
+{
+ UINT8 modrm;
+ INT16 val, low, high;
+
+ modrm = FETCH();
+
+ if (modrm >= 0xc0)
+ {
+ low = high = LOAD_RM16(modrm);
+ }
+ else
+ {
+ UINT32 ea = GetEA(modrm);
+ low = READ16(ea + 0);
+ high = READ16(ea + 2);
+ }
+ val = LOAD_REG16(modrm);
+
+ if ((val < low) || (val > high))
+ {
+ CYCLES(CYCLES_BOUND_OUT_RANGE);
+ i386_trap(5, 0);
+ }
+ else
+ {
+ CYCLES(CYCLES_BOUND_IN_RANGE);
+ }
+}
+
+static void I386OP(retf16)(void) // Opcode 0xcb
+{
+ I.eip = POP16();
+ I.sreg[CS].selector = POP16();
+ i386_load_segment_descriptor( CS );
+ CHANGE_PC(I.eip);
+
+ CYCLES(CYCLES_RET_INTERSEG);
+}
+
+static void I386OP(retf_i16)(void) // Opcode 0xca
+{
+ UINT16 count = FETCH16();
+
+ I.eip = POP16();
+ I.sreg[CS].selector = POP16();
+ i386_load_segment_descriptor( CS );
+ CHANGE_PC(I.eip);
+
+ REG16(SP) += count;
+ CYCLES(CYCLES_RET_IMM_INTERSEG);
+}
+
+static void I386OP(xlat16)(void) // Opcode 0xd7
+{
+ UINT32 ea;
+ if( I.segment_prefix ) {
+ ea = i386_translate( I.segment_override, REG16(BX) + REG8(AL) );
+ } else {
+ ea = i386_translate( DS, REG16(BX) + REG8(AL) );
+ }
+ REG8(AL) = READ8(ea);
+ CYCLES(CYCLES_XLAT);
+}
+
+static void I386OP(load_far_pointer16)(int s)
+{
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ fatalerror("NYI");
+ } else {
+ UINT32 ea = GetEA(modrm);
+ STORE_REG16(modrm, READ16(ea + 0));
+ I.sreg[s].selector = READ16(ea + 2);
+ i386_load_segment_descriptor( s );
+ }
+}
+
+static void I386OP(lds16)(void) // Opcode 0xc5
+{
+ I386OP(load_far_pointer16)(DS);
+ CYCLES(CYCLES_LDS);
+}
+
+static void I386OP(lss16)(void) // Opcode 0x0f 0xb2
+{
+ I386OP(load_far_pointer16)(SS);
+ CYCLES(CYCLES_LSS);
+}
+
+static void I386OP(les16)(void) // Opcode 0xc4
+{
+ I386OP(load_far_pointer16)(ES);
+ CYCLES(CYCLES_LES);
+}
+
+static void I386OP(lfs16)(void) // Opcode 0x0f 0xb4
+{
+ I386OP(load_far_pointer16)(FS);
+ CYCLES(CYCLES_LFS);
+}
+
+static void I386OP(lgs16)(void) // Opcode 0x0f 0xb5
+{
+ I386OP(load_far_pointer16)(GS);
+ CYCLES(CYCLES_LGS);
+}
+
diff --git a/src/emu/cpu/i386/i386op32.c b/src/emu/cpu/i386/i386op32.c
new file mode 100644
index 00000000000..a5eee962959
--- /dev/null
+++ b/src/emu/cpu/i386/i386op32.c
@@ -0,0 +1,2974 @@
+static UINT32 I386OP(shift_rotate32)(UINT8 modrm, UINT32 value, UINT8 shift)
+{
+ UINT32 dst, src;
+ dst = value;
+ src = value;
+
+ if( shift == 0 ) {
+ CYCLES_RM(modrm, 3, 7);
+ } else if( shift == 1 ) {
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* ROL rm32, 1 */
+ I.CF = (src & 0x80000000) ? 1 : 0;
+ dst = (src << 1) + I.CF;
+ I.OF = ((src ^ dst) & 0x80000000) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 1: /* ROR rm32, 1 */
+ I.CF = (src & 0x1) ? 1 : 0;
+ dst = (I.CF << 31) | (src >> 1);
+ I.OF = ((src ^ dst) & 0x80000000) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 2: /* RCL rm32, 1 */
+ dst = (src << 1) + I.CF;
+ I.CF = (src & 0x80000000) ? 1 : 0;
+ I.OF = ((src ^ dst) & 0x80000000) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 3: /* RCR rm32, 1 */
+ dst = (I.CF << 31) | (src >> 1);
+ I.CF = src & 0x1;
+ I.OF = ((src ^ dst) & 0x80000000) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 4: /* SHL/SAL rm32, 1 */
+ case 6:
+ dst = src << 1;
+ I.CF = (src & 0x80000000) ? 1 : 0;
+ I.OF = (((I.CF << 31) ^ dst) & 0x80000000) ? 1 : 0;
+ SetSZPF32(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 5: /* SHR rm32, 1 */
+ dst = src >> 1;
+ I.CF = src & 0x1;
+ I.OF = (src & 0x80000000) ? 1 : 0;
+ SetSZPF32(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 7: /* SAR rm32, 1 */
+ dst = (INT32)(src) >> 1;
+ I.CF = src & 0x1;
+ I.OF = 0;
+ SetSZPF32(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ }
+
+ } else {
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* ROL rm32, i8 */
+ dst = ((src & ((UINT32)0xffffffff >> shift)) << shift) |
+ ((src & ((UINT32)0xffffffff << (32-shift))) >> (32-shift));
+ I.CF = (src >> (32-shift)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 1: /* ROR rm32, i8 */
+ dst = ((src & ((UINT32)0xffffffff << shift)) >> shift) |
+ ((src & ((UINT32)0xffffffff >> (32-shift))) << (32-shift));
+ I.CF = (src >> (shift-1)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 2: /* RCL rm32, i8 */
+ dst = ((src & ((UINT32)0xffffffff >> shift)) << shift) |
+ ((src & ((UINT32)0xffffffff << (33-shift))) >> (33-shift)) |
+ (I.CF << (shift-1));
+ I.CF = (src >> (32-shift)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 3: /* RCR rm32, i8 */
+ dst = ((src & ((UINT32)0xffffffff << shift)) >> shift) |
+ ((src & ((UINT32)0xffffffff >> (32-shift))) << (33-shift)) |
+ (I.CF << (32-shift));
+ I.CF = (src >> (shift-1)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 4: /* SHL/SAL rm32, i8 */
+ case 6:
+ dst = src << shift;
+ I.CF = (src & (1 << (32-shift))) ? 1 : 0;
+ SetSZPF32(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 5: /* SHR rm32, i8 */
+ dst = src >> shift;
+ I.CF = (src & (1 << (shift-1))) ? 1 : 0;
+ SetSZPF32(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 7: /* SAR rm32, i8 */
+ dst = (INT32)src >> shift;
+ I.CF = (src & (1 << (shift-1))) ? 1 : 0;
+ SetSZPF32(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ }
+
+ }
+ return dst;
+}
+
+
+
+static void I386OP(adc_rm32_r32)(void) // Opcode 0x11
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm);
+ dst = LOAD_RM32(modrm);
+ src = ADD32(src, I.CF);
+ dst = ADD32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm);
+ dst = READ32(ea);
+ src = ADD32(src, I.CF);
+ dst = ADD32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(adc_r32_rm32)(void) // Opcode 0x13
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ dst = LOAD_REG32(modrm);
+ src = ADD32(src, I.CF);
+ dst = ADD32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ dst = LOAD_REG32(modrm);
+ src = ADD32(src, I.CF);
+ dst = ADD32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(adc_eax_i32)(void) // Opcode 0x15
+{
+ UINT32 src, dst;
+ src = FETCH32();
+ dst = REG32(EAX);
+ src = ADD32(src, I.CF);
+ dst = ADD32(dst, src);
+ REG32(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(add_rm32_r32)(void) // Opcode 0x01
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm);
+ dst = LOAD_RM32(modrm);
+ dst = ADD32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm);
+ dst = READ32(ea);
+ dst = ADD32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(add_r32_rm32)(void) // Opcode 0x03
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ dst = LOAD_REG32(modrm);
+ dst = ADD32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ dst = LOAD_REG32(modrm);
+ dst = ADD32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(add_eax_i32)(void) // Opcode 0x05
+{
+ UINT32 src, dst;
+ src = FETCH32();
+ dst = REG32(EAX);
+ dst = ADD32(dst, src);
+ REG32(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(and_rm32_r32)(void) // Opcode 0x21
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm);
+ dst = LOAD_RM32(modrm);
+ dst = AND32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm);
+ dst = READ32(ea);
+ dst = AND32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(and_r32_rm32)(void) // Opcode 0x23
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ dst = LOAD_REG32(modrm);
+ dst = AND32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ dst = LOAD_REG32(modrm);
+ dst = AND32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(and_eax_i32)(void) // Opcode 0x25
+{
+ UINT32 src, dst;
+ src = FETCH32();
+ dst = REG32(EAX);
+ dst = AND32(dst, src);
+ REG32(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(bsf_r32_rm32)(void) // Opcode 0x0f bc
+{
+ UINT32 src, dst, temp;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ }
+
+ dst = 0;
+
+ if( src == 0 ) {
+ I.ZF = 1;
+ } else {
+ I.ZF = 0;
+ temp = 0;
+ while( (src & (1 << temp)) == 0 ) {
+ temp++;
+ dst = temp;
+ CYCLES(CYCLES_BSF);
+ }
+ }
+ CYCLES(CYCLES_BSF_BASE);
+ STORE_REG32(modrm, dst);
+}
+
+static void I386OP(bsr_r32_rm32)(void) // Opcode 0x0f bd
+{
+ UINT32 src, dst, temp;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ }
+
+ dst = 0;
+
+ if( src == 0 ) {
+ I.ZF = 1;
+ } else {
+ I.ZF = 0;
+ temp = 31;
+ while( (src & (1 << temp)) == 0 ) {
+ temp--;
+ dst = temp;
+ CYCLES(CYCLES_BSR);
+ }
+ }
+ CYCLES(CYCLES_BSR_BASE);
+ STORE_REG32(modrm, dst);
+}
+
+static void I386OP(bt_rm32_r32)(void) // Opcode 0x0f a3
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 bit = LOAD_REG32(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+
+ CYCLES(CYCLES_BT_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 bit = LOAD_REG32(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+
+ CYCLES(CYCLES_BT_REG_MEM);
+ }
+}
+
+static void I386OP(btc_rm32_r32)(void) // Opcode 0x0f bb
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 bit = LOAD_REG32(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst ^= (1 << bit);
+
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_BTC_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 bit = LOAD_REG32(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst ^= (1 << bit);
+
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_BTC_REG_MEM);
+ }
+}
+
+static void I386OP(btr_rm32_r32)(void) // Opcode 0x0f b3
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 bit = LOAD_REG32(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst &= ~(1 << bit);
+
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_BTR_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 bit = LOAD_REG32(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst &= ~(1 << bit);
+
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_BTR_REG_MEM);
+ }
+}
+
+static void I386OP(bts_rm32_r32)(void) // Opcode 0x0f ab
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 bit = LOAD_REG32(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst |= (1 << bit);
+
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_BTS_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 bit = LOAD_REG32(modrm);
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst |= (1 << bit);
+
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_BTS_REG_MEM);
+ }
+}
+
+static void I386OP(call_abs32)(void) // Opcode 0x9a
+{
+ UINT32 offset = FETCH32();
+ UINT16 ptr = FETCH16();
+
+ if( PROTECTED_MODE ) {
+ /* TODO */
+ fatalerror("i386: call_abs32 in protected mode unimplemented");
+ } else {
+ PUSH32( I.sreg[CS].selector );
+ PUSH32( I.eip );
+ I.sreg[CS].selector = ptr;
+ I.eip = offset;
+ i386_load_segment_descriptor(CS);
+ }
+ CYCLES(CYCLES_CALL_INTERSEG);
+ CHANGE_PC(I.eip);
+}
+
+static void I386OP(call_rel32)(void) // Opcode 0xe8
+{
+ INT32 disp = FETCH32();
+
+ PUSH32( I.eip );
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_CALL); /* TODO: Timing = 7 + m */
+}
+
+static void I386OP(cdq)(void) // Opcode 0x99
+{
+ if( REG32(EAX) & 0x80000000 ) {
+ REG32(EDX) = 0xffffffff;
+ } else {
+ REG32(EDX) = 0x00000000;
+ }
+ CYCLES(CYCLES_CWD);
+}
+
+static void I386OP(cmp_rm32_r32)(void) // Opcode 0x39
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm);
+ dst = LOAD_RM32(modrm);
+ SUB32(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm);
+ dst = READ32(ea);
+ SUB32(dst, src);
+ CYCLES(CYCLES_CMP_REG_MEM);
+ }
+}
+
+static void I386OP(cmp_r32_rm32)(void) // Opcode 0x3b
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ dst = LOAD_REG32(modrm);
+ SUB32(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ dst = LOAD_REG32(modrm);
+ SUB32(dst, src);
+ CYCLES(CYCLES_CMP_MEM_REG);
+ }
+}
+
+static void I386OP(cmp_eax_i32)(void) // Opcode 0x3d
+{
+ UINT32 src, dst;
+ src = FETCH32();
+ dst = REG32(EAX);
+ SUB32(dst, src);
+ CYCLES(CYCLES_CMP_IMM_ACC);
+}
+
+static void I386OP(cmpsd)(void) // Opcode 0xa7
+{
+ UINT32 eas, ead, src, dst;
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.address_size ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.address_size ? REG32(ESI) : REG16(SI) );
+ }
+ ead = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ src = READ32(eas);
+ dst = READ32(ead);
+ SUB32(dst, src);
+ BUMP_SI(4);
+ BUMP_DI(4);
+ CYCLES(CYCLES_CMPS);
+}
+
+static void I386OP(cwde)(void) // Opcode 0x98
+{
+ REG32(EAX) = (INT32)((INT16)REG16(AX));
+ CYCLES(CYCLES_CBW);
+}
+
+static void I386OP(dec_eax)(void) // Opcode 0x48
+{
+ REG32(EAX) = DEC32( REG32(EAX) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_ecx)(void) // Opcode 0x49
+{
+ REG32(ECX) = DEC32( REG32(ECX) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_edx)(void) // Opcode 0x4a
+{
+ REG32(EDX) = DEC32( REG32(EDX) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_ebx)(void) // Opcode 0x4b
+{
+ REG32(EBX) = DEC32( REG32(EBX) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_esp)(void) // Opcode 0x4c
+{
+ REG32(ESP) = DEC32( REG32(ESP) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_ebp)(void) // Opcode 0x4d
+{
+ REG32(EBP) = DEC32( REG32(EBP) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_esi)(void) // Opcode 0x4e
+{
+ REG32(ESI) = DEC32( REG32(ESI) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(dec_edi)(void) // Opcode 0x4f
+{
+ REG32(EDI) = DEC32( REG32(EDI) );
+ CYCLES(CYCLES_DEC_REG);
+}
+
+static void I386OP(imul_r32_rm32)(void) // Opcode 0x0f af
+{
+ UINT8 modrm = FETCH();
+ INT64 result;
+ INT64 src, dst;
+ if( modrm >= 0xc0 ) {
+ src = (INT64)(INT32)LOAD_RM32(modrm);
+ CYCLES(CYCLES_IMUL32_REG_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = (INT64)(INT32)READ32(ea);
+ CYCLES(CYCLES_IMUL32_REG_REG); /* TODO: Correct multiply timing */
+ }
+
+ dst = (INT64)(INT32)LOAD_REG32(modrm);
+ result = src * dst;
+
+ STORE_REG32(modrm, (UINT32)result);
+
+ I.CF = I.OF = !(result == (INT64)(INT32)result);
+}
+
+static void I386OP(imul_r32_rm32_i32)(void) // Opcode 0x69
+{
+ UINT8 modrm = FETCH();
+ INT64 result;
+ INT64 src, dst;
+ if( modrm >= 0xc0 ) {
+ dst = (INT64)(INT32)LOAD_RM32(modrm);
+ CYCLES(CYCLES_IMUL32_REG_IMM_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = (INT64)(INT32)READ32(ea);
+ CYCLES(CYCLES_IMUL32_MEM_IMM_REG); /* TODO: Correct multiply timing */
+ }
+
+ src = (INT64)(INT32)FETCH32();
+ result = src * dst;
+
+ STORE_REG32(modrm, (UINT32)result);
+
+ I.CF = I.OF = !(result == (INT64)(INT32)result);
+}
+
+static void I386OP(imul_r32_rm32_i8)(void) // Opcode 0x6b
+{
+ UINT8 modrm = FETCH();
+ INT64 result;
+ INT64 src, dst;
+ if( modrm >= 0xc0 ) {
+ dst = (INT64)(INT32)LOAD_RM32(modrm);
+ CYCLES(CYCLES_IMUL32_REG_IMM_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = (INT64)(INT32)READ32(ea);
+ CYCLES(CYCLES_IMUL32_MEM_IMM_REG); /* TODO: Correct multiply timing */
+ }
+
+ src = (INT64)(INT8)FETCH();
+ result = src * dst;
+
+ STORE_REG32(modrm, (UINT32)result);
+
+ I.CF = I.OF = !(result == (INT64)(INT32)result);
+}
+
+static void I386OP(in_eax_i8)(void) // Opcode 0xe5
+{
+ UINT16 port = FETCH();
+ UINT32 data = READPORT32(port);
+ REG32(EAX) = data;
+ CYCLES(CYCLES_IN_VAR);
+}
+
+static void I386OP(in_eax_dx)(void) // Opcode 0xed
+{
+ UINT16 port = REG16(DX);
+ UINT32 data = READPORT32(port);
+ REG32(EAX) = data;
+ CYCLES(CYCLES_IN);
+}
+
+static void I386OP(inc_eax)(void) // Opcode 0x40
+{
+ REG32(EAX) = INC32( REG32(EAX) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_ecx)(void) // Opcode 0x41
+{
+ REG32(ECX) = INC32( REG32(ECX) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_edx)(void) // Opcode 0x42
+{
+ REG32(EDX) = INC32( REG32(EDX) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_ebx)(void) // Opcode 0x43
+{
+ REG32(EBX) = INC32( REG32(EBX) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_esp)(void) // Opcode 0x44
+{
+ REG32(ESP) = INC32( REG32(ESP) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_ebp)(void) // Opcode 0x45
+{
+ REG32(EBP) = INC32( REG32(EBP) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_esi)(void) // Opcode 0x46
+{
+ REG32(ESI) = INC32( REG32(ESI) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(inc_edi)(void) // Opcode 0x47
+{
+ REG32(EDI) = INC32( REG32(EDI) );
+ CYCLES(CYCLES_INC_REG);
+}
+
+static void I386OP(iret32)(void) // Opcode 0xcf
+{
+ if( PROTECTED_MODE ) {
+ /* TODO: Virtual 8086-mode */
+ /* TODO: Nested task */
+ /* TODO: #SS(0) exception */
+ /* TODO: All the protection-related stuff... */
+ I.eip = POP32();
+ I.sreg[CS].selector = POP32() & 0xffff;
+ set_flags( POP32() );
+ i386_load_segment_descriptor(CS);
+ CHANGE_PC(I.eip);
+ } else {
+ /* TODO: #SS(0) exception */
+ /* TODO: #GP(0) exception */
+ I.eip = POP32();
+ I.sreg[CS].selector = POP32() & 0xffff;
+ set_flags( POP32() );
+ i386_load_segment_descriptor(CS);
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_IRET);
+}
+
+static void I386OP(ja_rel32)(void) // Opcode 0x0f 87
+{
+ INT32 disp = FETCH32();
+ if( I.CF == 0 && I.ZF == 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jbe_rel32)(void) // Opcode 0x0f 86
+{
+ INT32 disp = FETCH32();
+ if( I.CF != 0 || I.ZF != 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jc_rel32)(void) // Opcode 0x0f 82
+{
+ INT32 disp = FETCH32();
+ if( I.CF != 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jg_rel32)(void) // Opcode 0x0f 8f
+{
+ INT32 disp = FETCH32();
+ if( I.ZF == 0 && (I.SF == I.OF) ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jge_rel32)(void) // Opcode 0x0f 8d
+{
+ INT32 disp = FETCH32();
+ if( (I.SF == I.OF) ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jl_rel32)(void) // Opcode 0x0f 8c
+{
+ INT32 disp = FETCH32();
+ if( (I.SF != I.OF) ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jle_rel32)(void) // Opcode 0x0f 8e
+{
+ INT32 disp = FETCH32();
+ if( I.ZF != 0 || (I.SF != I.OF) ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jnc_rel32)(void) // Opcode 0x0f 83
+{
+ INT32 disp = FETCH32();
+ if( I.CF == 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jno_rel32)(void) // Opcode 0x0f 81
+{
+ INT32 disp = FETCH32();
+ if( I.OF == 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jnp_rel32)(void) // Opcode 0x0f 8b
+{
+ INT32 disp = FETCH32();
+ if( I.PF == 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jns_rel32)(void) // Opcode 0x0f 89
+{
+ INT32 disp = FETCH32();
+ if( I.SF == 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jnz_rel32)(void) // Opcode 0x0f 85
+{
+ INT32 disp = FETCH32();
+ if( I.ZF == 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jo_rel32)(void) // Opcode 0x0f 80
+{
+ INT32 disp = FETCH32();
+ if( I.OF != 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jp_rel32)(void) // Opcode 0x0f 8a
+{
+ INT32 disp = FETCH32();
+ if( I.PF != 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(js_rel32)(void) // Opcode 0x0f 88
+{
+ INT32 disp = FETCH32();
+ if( I.SF != 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jz_rel32)(void) // Opcode 0x0f 84
+{
+ INT32 disp = FETCH32();
+ if( I.ZF != 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH);
+ }
+}
+
+static void I386OP(jcxz32)(void) // Opcode 0xe3
+{
+ INT8 disp = FETCH();
+ if( REG32(ECX) == 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JCXZ); /* TODO: Timing = 9 + m */
+ } else {
+ CYCLES(CYCLES_JCXZ_NOBRANCH);
+ }
+}
+
+static void I386OP(jmp_rel32)(void) // Opcode 0xe9
+{
+ UINT32 disp = FETCH32();
+ /* TODO: Segment limit */
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_JMP); /* TODO: Timing = 7 + m */
+}
+
+static void I386OP(jmp_abs32)(void) // Opcode 0xea
+{
+ UINT32 address = FETCH32();
+ UINT16 segment = FETCH16();
+
+ if( PROTECTED_MODE ) {
+ /* TODO: #GP */
+ /* TODO: access rights, etc. */
+ I.eip = address;
+ I.sreg[CS].selector = segment;
+ i386_load_segment_descriptor(CS);
+ CHANGE_PC(I.eip);
+ } else {
+ I.eip = address;
+ I.sreg[CS].selector = segment;
+ i386_load_segment_descriptor(CS);
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_JMP_INTERSEG);
+}
+
+static void I386OP(lea32)(void) // Opcode 0x8d
+{
+ UINT8 modrm = FETCH();
+ UINT32 ea = GetNonTranslatedEA(modrm);
+ if (!I.address_size)
+ {
+ ea &= 0xffff;
+ }
+ STORE_REG32(modrm, ea);
+ CYCLES(CYCLES_LEA);
+}
+
+static void I386OP(leave32)(void) // Opcode 0xc9
+{
+ REG32(ESP) = REG32(EBP);
+ REG32(EBP) = POP32();
+ CYCLES(CYCLES_LEAVE);
+}
+
+static void I386OP(lodsd)(void) // Opcode 0xad
+{
+ UINT32 eas;
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.address_size ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.address_size ? REG32(ESI) : REG16(SI) );
+ }
+ REG32(EAX) = READ32(eas);
+ BUMP_SI(4);
+ CYCLES(CYCLES_LODS);
+}
+
+static void I386OP(loop32)(void) // Opcode 0xe2
+{
+ INT8 disp = FETCH();
+ REG32(ECX)--;
+ if( REG32(ECX) != 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_LOOP); /* TODO: Timing = 11 + m */
+}
+
+static void I386OP(loopne32)(void) // Opcode 0xe0
+{
+ INT8 disp = FETCH();
+ REG32(ECX)--;
+ if( REG32(ECX) != 0 && I.ZF == 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_LOOPNZ); /* TODO: Timing = 11 + m */
+}
+
+static void I386OP(loopz32)(void) // Opcode 0xe1
+{
+ INT8 disp = FETCH();
+ REG32(ECX)--;
+ if( REG32(ECX) != 0 && I.ZF != 0 ) {
+ I.eip += disp;
+ CHANGE_PC(I.eip);
+ }
+ CYCLES(CYCLES_LOOPZ); /* TODO: Timing = 11 + m */
+}
+
+static void I386OP(mov_rm32_r32)(void) // Opcode 0x89
+{
+ UINT32 src;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm);
+ STORE_RM32(modrm, src);
+ CYCLES(CYCLES_MOV_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm);
+ WRITE32(ea, src);
+ CYCLES(CYCLES_MOV_REG_MEM);
+ }
+}
+
+static void I386OP(mov_r32_rm32)(void) // Opcode 0x8b
+{
+ UINT32 src;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOV_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOV_MEM_REG);
+ }
+}
+
+static void I386OP(mov_rm32_i32)(void) // Opcode 0xc7
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 value = FETCH32();
+ STORE_RM32(modrm, value);
+ CYCLES(CYCLES_MOV_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 value = FETCH32();
+ WRITE32(ea, value);
+ CYCLES(CYCLES_MOV_IMM_MEM);
+ }
+}
+
+static void I386OP(mov_eax_m32)(void) // Opcode 0xa1
+{
+ UINT32 offset, ea;
+ if( I.address_size ) {
+ offset = FETCH32();
+ } else {
+ offset = FETCH16();
+ }
+ if( I.segment_prefix ) {
+ ea = i386_translate( I.segment_override, offset );
+ } else {
+ ea = i386_translate( DS, offset );
+ }
+ REG32(EAX) = READ32(ea);
+ CYCLES(CYCLES_MOV_MEM_ACC);
+}
+
+static void I386OP(mov_m32_eax)(void) // Opcode 0xa3
+{
+ UINT32 offset, ea;
+ if( I.address_size ) {
+ offset = FETCH32();
+ } else {
+ offset = FETCH16();
+ }
+ if( I.segment_prefix ) {
+ ea = i386_translate( I.segment_override, offset );
+ } else {
+ ea = i386_translate( DS, offset );
+ }
+ WRITE32( ea, REG32(EAX) );
+ CYCLES(CYCLES_MOV_ACC_MEM);
+}
+
+static void I386OP(mov_eax_i32)(void) // Opcode 0xb8
+{
+ REG32(EAX) = FETCH32();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_ecx_i32)(void) // Opcode 0xb9
+{
+ REG32(ECX) = FETCH32();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_edx_i32)(void) // Opcode 0xba
+{
+ REG32(EDX) = FETCH32();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_ebx_i32)(void) // Opcode 0xbb
+{
+ REG32(EBX) = FETCH32();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_esp_i32)(void) // Opcode 0xbc
+{
+ REG32(ESP) = FETCH32();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_ebp_i32)(void) // Opcode 0xbd
+{
+ REG32(EBP) = FETCH32();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_esi_i32)(void) // Opcode 0xbe
+{
+ REG32(ESI) = FETCH32();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_edi_i32)(void) // Opcode 0xbf
+{
+ REG32(EDI) = FETCH32();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(movsd)(void) // Opcode 0xa5
+{
+ UINT32 eas, ead, v;
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.address_size ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.address_size ? REG32(ESI) : REG16(SI) );
+ }
+ ead = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ v = READ32(eas);
+ WRITE32(ead, v);
+ BUMP_SI(4);
+ BUMP_DI(4);
+ CYCLES(CYCLES_MOVS);
+}
+
+static void I386OP(movsx_r32_rm8)(void) // Opcode 0x0f be
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ INT32 src = (INT8)LOAD_RM8(modrm);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOVSX_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ INT32 src = (INT8)READ8(ea);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOVSX_MEM_REG);
+ }
+}
+
+static void I386OP(movsx_r32_rm16)(void) // Opcode 0x0f bf
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ INT32 src = (INT16)LOAD_RM16(modrm);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOVSX_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ INT32 src = (INT16)READ16(ea);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOVSX_MEM_REG);
+ }
+}
+
+static void I386OP(movzx_r32_rm8)(void) // Opcode 0x0f b6
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 src = (UINT8)LOAD_RM8(modrm);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOVZX_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 src = (UINT8)READ8(ea);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOVZX_MEM_REG);
+ }
+}
+
+static void I386OP(movzx_r32_rm16)(void) // Opcode 0x0f b7
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 src = (UINT16)LOAD_RM16(modrm);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOVZX_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 src = (UINT16)READ16(ea);
+ STORE_REG32(modrm, src);
+ CYCLES(CYCLES_MOVZX_MEM_REG);
+ }
+}
+
+static void I386OP(or_rm32_r32)(void) // Opcode 0x09
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm);
+ dst = LOAD_RM32(modrm);
+ dst = OR32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm);
+ dst = READ32(ea);
+ dst = OR32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(or_r32_rm32)(void) // Opcode 0x0b
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ dst = LOAD_REG32(modrm);
+ dst = OR32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ dst = LOAD_REG32(modrm);
+ dst = OR32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(or_eax_i32)(void) // Opcode 0x0d
+{
+ UINT32 src, dst;
+ src = FETCH32();
+ dst = REG32(EAX);
+ dst = OR32(dst, src);
+ REG32(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(out_eax_i8)(void) // Opcode 0xe7
+{
+ UINT16 port = FETCH();
+ UINT32 data = REG32(EAX);
+ WRITEPORT32(port, data);
+ CYCLES(CYCLES_OUT_VAR);
+}
+
+static void I386OP(out_eax_dx)(void) // Opcode 0xef
+{
+ UINT16 port = REG16(DX);
+ UINT32 data = REG32(EAX);
+ WRITEPORT32(port, data);
+ CYCLES(CYCLES_OUT);
+}
+
+static void I386OP(pop_eax)(void) // Opcode 0x58
+{
+ REG32(EAX) = POP32();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_ecx)(void) // Opcode 0x59
+{
+ REG32(ECX) = POP32();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_edx)(void) // Opcode 0x5a
+{
+ REG32(EDX) = POP32();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_ebx)(void) // Opcode 0x5b
+{
+ REG32(EBX) = POP32();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_esp)(void) // Opcode 0x5c
+{
+ REG32(ESP) = POP32();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_ebp)(void) // Opcode 0x5d
+{
+ REG32(EBP) = POP32();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_esi)(void) // Opcode 0x5e
+{
+ REG32(ESI) = POP32();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_edi)(void) // Opcode 0x5f
+{
+ REG32(EDI) = POP32();
+ CYCLES(CYCLES_POP_REG_SHORT);
+}
+
+static void I386OP(pop_ds32)(void) // Opcode 0x1f
+{
+ I.sreg[DS].selector = POP32();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(DS);
+ } else {
+ i386_load_segment_descriptor(DS);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_es32)(void) // Opcode 0x07
+{
+ I.sreg[ES].selector = POP32();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(ES);
+ } else {
+ i386_load_segment_descriptor(ES);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_fs32)(void) // Opcode 0x0f a1
+{
+ I.sreg[FS].selector = POP32();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(FS);
+ } else {
+ i386_load_segment_descriptor(FS);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_gs32)(void) // Opcode 0x0f a9
+{
+ I.sreg[GS].selector = POP32();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(GS);
+ } else {
+ i386_load_segment_descriptor(GS);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_ss32)(void) // Opcode 0x17
+{
+ I.sreg[SS].selector = POP32();
+ if( PROTECTED_MODE ) {
+ i386_load_segment_descriptor(SS);
+ } else {
+ i386_load_segment_descriptor(SS);
+ }
+ CYCLES(CYCLES_POP_SREG);
+}
+
+static void I386OP(pop_rm32)(void) // Opcode 0x8f
+{
+ UINT8 modrm = FETCH();
+ UINT32 value = POP32();
+
+ if( modrm >= 0xc0 ) {
+ STORE_RM32(modrm, value);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE32(ea, value);
+ }
+ CYCLES(CYCLES_POP_RM);
+}
+
+static void I386OP(popad)(void) // Opcode 0x61
+{
+ REG32(EDI) = POP32();
+ REG32(ESI) = POP32();
+ REG32(EBP) = POP32();
+ REG32(ESP) += 4;
+ REG32(EBX) = POP32();
+ REG32(EDX) = POP32();
+ REG32(ECX) = POP32();
+ REG32(EAX) = POP32();
+ CYCLES(CYCLES_POPA);
+}
+
+static void I386OP(popfd)(void) // Opcode 0x9d
+{
+ UINT32 value = POP32();
+ set_flags(value);
+ CYCLES(CYCLES_POPF);
+}
+
+static void I386OP(push_eax)(void) // Opcode 0x50
+{
+ PUSH32( REG32(EAX) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_ecx)(void) // Opcode 0x51
+{
+ PUSH32( REG32(ECX) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_edx)(void) // Opcode 0x52
+{
+ PUSH32( REG32(EDX) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_ebx)(void) // Opcode 0x53
+{
+ PUSH32( REG32(EBX) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_esp)(void) // Opcode 0x54
+{
+ PUSH32( REG32(ESP) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_ebp)(void) // Opcode 0x55
+{
+ PUSH32( REG32(EBP) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_esi)(void) // Opcode 0x56
+{
+ PUSH32( REG32(ESI) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_edi)(void) // Opcode 0x57
+{
+ PUSH32( REG32(EDI) );
+ CYCLES(CYCLES_PUSH_REG_SHORT);
+}
+
+static void I386OP(push_cs32)(void) // Opcode 0x0e
+{
+ PUSH32( I.sreg[CS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_ds32)(void) // Opcode 0x1e
+{
+ PUSH32( I.sreg[DS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_es32)(void) // Opcode 0x06
+{
+ PUSH32( I.sreg[ES].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_fs32)(void) // Opcode 0x0f a0
+{
+ PUSH32( I.sreg[FS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_gs32)(void) // Opcode 0x0f a8
+{
+ PUSH32( I.sreg[GS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_ss32)(void) // Opcode 0x16
+{
+ PUSH32( I.sreg[SS].selector );
+ CYCLES(CYCLES_PUSH_SREG);
+}
+
+static void I386OP(push_i32)(void) // Opcode 0x68
+{
+ UINT32 value = FETCH32();
+ PUSH32(value);
+ CYCLES(CYCLES_PUSH_IMM);
+}
+
+static void I386OP(pushad)(void) // Opcode 0x60
+{
+ UINT32 temp = REG32(ESP);
+ PUSH32( REG32(EAX) );
+ PUSH32( REG32(ECX) );
+ PUSH32( REG32(EDX) );
+ PUSH32( REG32(EBX) );
+ PUSH32( temp );
+ PUSH32( REG32(EBP) );
+ PUSH32( REG32(ESI) );
+ PUSH32( REG32(EDI) );
+ CYCLES(CYCLES_PUSHA);
+}
+
+static void I386OP(pushfd)(void) // Opcode 0x9c
+{
+ PUSH32( get_flags() & 0x00fcffff );
+ CYCLES(CYCLES_PUSHF);
+}
+
+static void I386OP(ret_near32_i16)(void) // Opcode 0xc2
+{
+ INT16 disp = FETCH16();
+ I.eip = POP32();
+ REG32(ESP) += disp;
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_RET_IMM); /* TODO: Timing = 10 + m */
+}
+
+static void I386OP(ret_near32)(void) // Opcode 0xc3
+{
+ I.eip = POP32();
+ CHANGE_PC(I.eip);
+ CYCLES(CYCLES_RET); /* TODO: Timing = 10 + m */
+}
+
+static void I386OP(sbb_rm32_r32)(void) // Opcode 0x19
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm) + I.CF;
+ dst = LOAD_RM32(modrm);
+ dst = SUB32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm) + I.CF;
+ dst = READ32(ea);
+ dst = SUB32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(sbb_r32_rm32)(void) // Opcode 0x1b
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm) + I.CF;
+ dst = LOAD_REG32(modrm);
+ dst = SUB32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea) + I.CF;
+ dst = LOAD_REG32(modrm);
+ dst = SUB32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(sbb_eax_i32)(void) // Opcode 0x1d
+{
+ UINT32 src, dst;
+ src = FETCH32() + I.CF;
+ dst = REG32(EAX);
+ dst = SUB32(dst, src);
+ REG32(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(scasd)(void) // Opcode 0xaf
+{
+ UINT32 eas, src, dst;
+ eas = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ src = READ32(eas);
+ dst = REG32(EAX);
+ SUB32(dst, src);
+ BUMP_DI(4);
+ CYCLES(CYCLES_SCAS);
+}
+
+static void I386OP(shld32_i8)(void) // Opcode 0x0f a4
+{
+ /* TODO: Correct flags */
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 upper = LOAD_REG32(modrm);
+ UINT8 shift = FETCH();
+ if( shift > 31 || shift == 0 ) {
+
+ } else {
+ I.CF = (dst & (1 << (32-shift))) ? 1 : 0;
+ dst = (dst << shift) | (upper >> (32-shift));
+ SetSZPF32(dst);
+ }
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_SHLD_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 upper = LOAD_REG32(modrm);
+ UINT8 shift = FETCH();
+ if( shift > 31 || shift == 0 ) {
+
+ } else {
+ I.CF = (dst & (1 << (32-shift))) ? 1 : 0;
+ dst = (dst << shift) | (upper >> (32-shift));
+ SetSZPF32(dst);
+ }
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_SHLD_MEM);
+ }
+}
+
+static void I386OP(shld32_cl)(void) // Opcode 0x0f a5
+{
+ /* TODO: Correct flags */
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 upper = LOAD_REG32(modrm);
+ UINT8 shift = REG8(CL);
+ if( shift > 31 || shift == 0 ) {
+
+ } else {
+ I.CF = (dst & (1 << (32-shift))) ? 1 : 0;
+ dst = (dst << shift) | (upper >> (32-shift));
+ SetSZPF32(dst);
+ }
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_SHLD_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 upper = LOAD_REG32(modrm);
+ UINT8 shift = REG8(CL);
+ if( shift > 31 || shift == 0 ) {
+
+ } else {
+ I.CF = (dst & (1 << (32-shift))) ? 1 : 0;
+ dst = (dst << shift) | (upper >> (32-shift));
+ SetSZPF32(dst);
+ }
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_SHLD_MEM);
+ }
+}
+
+static void I386OP(shrd32_i8)(void) // Opcode 0x0f ac
+{
+ /* TODO: Correct flags */
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 upper = LOAD_REG32(modrm);
+ UINT8 shift = FETCH();
+ if( shift > 31 || shift == 0 ) {
+
+ } else {
+ I.CF = (dst & (1 << (shift-1))) ? 1 : 0;
+ dst = (dst >> shift) | (upper << (32-shift));
+ SetSZPF32(dst);
+ }
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_SHRD_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 upper = LOAD_REG32(modrm);
+ UINT8 shift = FETCH();
+ if( shift > 31 || shift == 0 ) {
+
+ } else {
+ I.CF = (dst & (1 << (shift-1))) ? 1 : 0;
+ dst = (dst >> shift) | (upper << (32-shift));
+ SetSZPF32(dst);
+ }
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_SHRD_MEM);
+ }
+}
+
+static void I386OP(shrd32_cl)(void) // Opcode 0x0f ad
+{
+ /* TODO: Correct flags */
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 upper = LOAD_REG32(modrm);
+ UINT8 shift = REG8(CL);
+ if( shift > 31 || shift == 0 ) {
+
+ } else {
+ I.CF = (dst & (1 << (shift-1))) ? 1 : 0;
+ dst = (dst >> shift) | (upper << (32-shift));
+ SetSZPF32(dst);
+ }
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_SHRD_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 upper = LOAD_REG32(modrm);
+ UINT8 shift = REG8(CL);
+ if( shift > 31 || shift == 0 ) {
+
+ } else {
+ I.CF = (dst & (1 << (shift-1))) ? 1 : 0;
+ dst = (dst >> shift) | (upper << (32-shift));
+ SetSZPF32(dst);
+ }
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_SHRD_MEM);
+ }
+}
+
+static void I386OP(stosd)(void) // Opcode 0xab
+{
+ UINT32 eas = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ WRITE32(eas, REG32(EAX));
+ BUMP_DI(4);
+ CYCLES(CYCLES_STOS);
+}
+
+static void I386OP(sub_rm32_r32)(void) // Opcode 0x29
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm);
+ dst = LOAD_RM32(modrm);
+ dst = SUB32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm);
+ dst = READ32(ea);
+ dst = SUB32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(sub_r32_rm32)(void) // Opcode 0x2b
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ dst = LOAD_REG32(modrm);
+ dst = SUB32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ dst = LOAD_REG32(modrm);
+ dst = SUB32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(sub_eax_i32)(void) // Opcode 0x2d
+{
+ UINT32 src, dst;
+ src = FETCH32();
+ dst = REG32(EAX);
+ dst = SUB32(dst, src);
+ REG32(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(test_eax_i32)(void) // Opcode 0xa9
+{
+ UINT32 src = FETCH32();
+ UINT32 dst = REG32(EAX);
+ dst = src & dst;
+ SetSZPF32(dst);
+ I.CF = 0;
+ I.OF = 0;
+ CYCLES(CYCLES_TEST_IMM_ACC);
+}
+
+static void I386OP(test_rm32_r32)(void) // Opcode 0x85
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm);
+ dst = LOAD_RM32(modrm);
+ dst = src & dst;
+ SetSZPF32(dst);
+ I.CF = 0;
+ I.OF = 0;
+ CYCLES(CYCLES_TEST_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm);
+ dst = READ32(ea);
+ dst = src & dst;
+ SetSZPF32(dst);
+ I.CF = 0;
+ I.OF = 0;
+ CYCLES(CYCLES_TEST_REG_MEM);
+ }
+}
+
+static void I386OP(xchg_eax_ecx)(void) // Opcode 0x91
+{
+ UINT32 temp;
+ temp = REG32(EAX);
+ REG32(EAX) = REG32(ECX);
+ REG32(ECX) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_eax_edx)(void) // Opcode 0x92
+{
+ UINT32 temp;
+ temp = REG32(EAX);
+ REG32(EAX) = REG32(EDX);
+ REG32(EDX) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_eax_ebx)(void) // Opcode 0x93
+{
+ UINT32 temp;
+ temp = REG32(EAX);
+ REG32(EAX) = REG32(EBX);
+ REG32(EBX) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_eax_esp)(void) // Opcode 0x94
+{
+ UINT32 temp;
+ temp = REG32(EAX);
+ REG32(EAX) = REG32(ESP);
+ REG32(ESP) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_eax_ebp)(void) // Opcode 0x95
+{
+ UINT32 temp;
+ temp = REG32(EAX);
+ REG32(EAX) = REG32(EBP);
+ REG32(EBP) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_eax_esi)(void) // Opcode 0x96
+{
+ UINT32 temp;
+ temp = REG32(EAX);
+ REG32(EAX) = REG32(ESI);
+ REG32(ESI) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_eax_edi)(void) // Opcode 0x97
+{
+ UINT32 temp;
+ temp = REG32(EAX);
+ REG32(EAX) = REG32(EDI);
+ REG32(EDI) = temp;
+ CYCLES(CYCLES_XCHG_REG_REG);
+}
+
+static void I386OP(xchg_r32_rm32)(void) // Opcode 0x87
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 src = LOAD_RM32(modrm);
+ UINT32 dst = LOAD_REG32(modrm);
+ STORE_REG32(modrm, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_XCHG_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 src = READ32(ea);
+ UINT32 dst = LOAD_REG32(modrm);
+ STORE_REG32(modrm, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_XCHG_REG_MEM);
+ }
+}
+
+static void I386OP(xor_rm32_r32)(void) // Opcode 0x31
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG32(modrm);
+ dst = LOAD_RM32(modrm);
+ dst = XOR32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG32(modrm);
+ dst = READ32(ea);
+ dst = XOR32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(xor_r32_rm32)(void) // Opcode 0x33
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ dst = LOAD_REG32(modrm);
+ dst = XOR32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ dst = LOAD_REG32(modrm);
+ dst = XOR32(dst, src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(xor_eax_i32)(void) // Opcode 0x35
+{
+ UINT32 src, dst;
+ src = FETCH32();
+ dst = REG32(EAX);
+ dst = XOR32(dst, src);
+ REG32(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+
+
+static void I386OP(group81_32)(void) // Opcode 0x81
+{
+ UINT32 ea;
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: // ADD Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = FETCH32();
+ dst = ADD32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = FETCH32();
+ dst = ADD32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 1: // OR Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = FETCH32();
+ dst = OR32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = FETCH32();
+ dst = OR32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 2: // ADC Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = FETCH32();
+ src = ADD32(src, I.CF);
+ dst = ADD32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = FETCH32();
+ src = ADD32(src, I.CF);
+ dst = ADD32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 3: // SBB Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = FETCH32() + I.CF;
+ dst = SUB32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = FETCH32() + I.CF;
+ dst = SUB32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 4: // AND Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = FETCH32();
+ dst = AND32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = FETCH32();
+ dst = AND32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 5: // SUB Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = FETCH32();
+ dst = SUB32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = FETCH32();
+ dst = SUB32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 6: // XOR Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = FETCH32();
+ dst = XOR32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = FETCH32();
+ dst = XOR32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 7: // CMP Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = FETCH32();
+ SUB32(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = FETCH32();
+ SUB32(dst, src);
+ CYCLES(CYCLES_CMP_REG_MEM);
+ }
+ break;
+ }
+}
+
+static void I386OP(group83_32)(void) // Opcode 0x83
+{
+ UINT32 ea;
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: // ADD Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = ADD32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = ADD32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 1: // OR Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = OR32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = OR32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 2: // ADC Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ src = ADD32(src, I.CF);
+ dst = ADD32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ src = ADD32(src, I.CF);
+ dst = ADD32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 3: // SBB Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = ((UINT32)(INT32)(INT8)FETCH()) + I.CF;
+ dst = SUB32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = ((UINT32)(INT32)(INT8)FETCH()) + I.CF;
+ dst = SUB32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 4: // AND Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = AND32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = AND32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 5: // SUB Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = SUB32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = SUB32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 6: // XOR Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = XOR32(dst, src);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ dst = XOR32(dst, src);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 7: // CMP Rm32, i32
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ SUB32(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ32(ea);
+ src = (UINT32)(INT32)(INT8)FETCH();
+ SUB32(dst, src);
+ CYCLES(CYCLES_CMP_REG_MEM);
+ }
+ break;
+ }
+}
+
+static void I386OP(groupC1_32)(void) // Opcode 0xc1
+{
+ UINT32 dst;
+ UINT8 modrm = FETCH();
+ UINT8 shift;
+
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ shift = FETCH() & 0x1f;
+ dst = i386_shift_rotate32(modrm, dst, shift);
+ STORE_RM32(modrm, dst);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = READ32(ea);
+ shift = FETCH() & 0x1f;
+ dst = i386_shift_rotate32(modrm, dst, shift);
+ WRITE32(ea, dst);
+ }
+}
+
+static void I386OP(groupD1_32)(void) // Opcode 0xd1
+{
+ UINT32 dst;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ dst = i386_shift_rotate32(modrm, dst, 1);
+ STORE_RM32(modrm, dst);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = READ32(ea);
+ dst = i386_shift_rotate32(modrm, dst, 1);
+ WRITE32(ea, dst);
+ }
+}
+
+static void I386OP(groupD3_32)(void) // Opcode 0xd3
+{
+ UINT32 dst;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM32(modrm);
+ dst = i386_shift_rotate32(modrm, dst, REG8(CL));
+ STORE_RM32(modrm, dst);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = READ32(ea);
+ dst = i386_shift_rotate32(modrm, dst, REG8(CL));
+ WRITE32(ea, dst);
+ }
+}
+
+static void I386OP(groupF7_32)(void) // Opcode 0xf7
+{
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* TEST Rm32, i32 */
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 src = FETCH32();
+ dst &= src;
+ I.CF = I.OF = I.AF = 0;
+ SetSZPF32(dst);
+ CYCLES(CYCLES_TEST_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 src = FETCH32();
+ dst &= src;
+ I.CF = I.OF = I.AF = 0;
+ SetSZPF32(dst);
+ CYCLES(CYCLES_TEST_IMM_MEM);
+ }
+ break;
+ case 2: /* NOT Rm32 */
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ dst = ~dst;
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_NOT_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ dst = ~dst;
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_NOT_MEM);
+ }
+ break;
+ case 3: /* NEG Rm32 */
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ dst = SUB32( 0, dst );
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_NEG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ dst = SUB32( 0, dst );
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_NEG_MEM);
+ }
+ break;
+ case 4: /* MUL EAX, Rm32 */
+ {
+ UINT64 result;
+ UINT32 src, dst;
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ CYCLES(CYCLES_MUL32_ACC_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ CYCLES(CYCLES_MUL32_ACC_MEM); /* TODO: Correct multiply timing */
+ }
+
+ dst = REG32(EAX);
+ result = (UINT64)src * (UINT64)dst;
+ REG32(EDX) = (UINT32)(result >> 32);
+ REG32(EAX) = (UINT32)result;
+
+ I.CF = I.OF = (REG32(EDX) != 0);
+ }
+ break;
+ case 5: /* IMUL EAX, Rm32 */
+ {
+ INT64 result;
+ INT64 src, dst;
+ if( modrm >= 0xc0 ) {
+ src = (INT64)(INT32)LOAD_RM32(modrm);
+ CYCLES(CYCLES_IMUL32_ACC_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = (INT64)(INT32)READ32(ea);
+ CYCLES(CYCLES_IMUL32_ACC_MEM); /* TODO: Correct multiply timing */
+ }
+
+ dst = (INT64)(INT32)REG32(EAX);
+ result = src * dst;
+
+ REG32(EDX) = (UINT32)(result >> 32);
+ REG32(EAX) = (UINT32)result;
+
+ I.CF = I.OF = !(result == (INT64)(INT32)result);
+ }
+ break;
+ case 6: /* DIV EAX, Rm32 */
+ {
+ UINT64 quotient, remainder, result;
+ UINT32 src;
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ CYCLES(CYCLES_DIV32_ACC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ CYCLES(CYCLES_DIV32_ACC_MEM);
+ }
+
+ quotient = ((UINT64)(REG32(EDX)) << 32) | (UINT64)(REG32(EAX));
+ if( src ) {
+ remainder = quotient % (UINT64)src;
+ result = quotient / (UINT64)src;
+ if( result > 0xffffffff ) {
+ /* TODO: Divide error */
+ } else {
+ REG32(EDX) = (UINT32)remainder;
+ REG32(EAX) = (UINT32)result;
+ }
+ } else {
+ /* TODO: Divide by zero */
+ }
+ }
+ break;
+ case 7: /* IDIV EAX, Rm32 */
+ {
+ INT64 quotient, remainder, result;
+ UINT32 src;
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM32(modrm);
+ CYCLES(CYCLES_IDIV32_ACC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ32(ea);
+ CYCLES(CYCLES_IDIV32_ACC_MEM);
+ }
+
+ quotient = (((INT64)REG32(EDX)) << 32) | ((UINT64)REG32(EAX));
+ if( src ) {
+ remainder = quotient % (INT64)(INT32)src;
+ result = quotient / (INT64)(INT32)src;
+ if( result > 0xffffffff ) {
+ /* TODO: Divide error */
+ } else {
+ REG32(EDX) = (UINT32)remainder;
+ REG32(EAX) = (UINT32)result;
+ }
+ } else {
+ /* TODO: Divide by zero */
+ }
+ }
+ break;
+ }
+}
+
+static void I386OP(groupFF_32)(void) // Opcode 0xff
+{
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* INC Rm32 */
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ dst = INC32(dst);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_INC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ dst = INC32(dst);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_INC_MEM);
+ }
+ break;
+ case 1: /* DEC Rm32 */
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ dst = DEC32(dst);
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_DEC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ dst = DEC32(dst);
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_DEC_MEM);
+ }
+ break;
+ case 2: /* CALL Rm32 */
+ {
+ UINT32 address;
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ CYCLES(CYCLES_CALL_REG); /* TODO: Timing = 7 + m */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ address = READ32(ea);
+ CYCLES(CYCLES_CALL_MEM); /* TODO: Timing = 10 + m */
+ }
+ PUSH32( I.eip );
+ I.eip = address;
+ CHANGE_PC(I.eip);
+ }
+ break;
+ case 3: /* CALL FAR Rm32 */
+ {
+ UINT16 selector;
+ UINT32 address;
+ if( modrm >= 0xc0 ) {
+ fatalerror("NYI");
+ } else {
+ UINT32 ea = GetEA(modrm);
+ address = READ32(ea + 0);
+ selector = READ16(ea + 4);
+ CYCLES(CYCLES_CALL_MEM_INTERSEG); /* TODO: Timing = 10 + m */
+ }
+ PUSH32( I.sreg[CS].selector );
+ PUSH32( I.eip );
+ I.sreg[CS].selector = selector;
+ I.performed_intersegment_jump = 1;
+ i386_load_segment_descriptor( CS );
+ I.eip = address;
+ CHANGE_PC(I.eip);
+ }
+ break;
+ case 4: /* JMP Rm32 */
+ {
+ UINT32 address;
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ CYCLES(CYCLES_JMP_REG); /* TODO: Timing = 7 + m */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ address = READ32(ea);
+ CYCLES(CYCLES_JMP_MEM); /* TODO: Timing = 10 + m */
+ }
+ I.eip = address;
+ CHANGE_PC(I.eip);
+ }
+ break;
+ case 5: /* JMP FAR Rm32 */
+ {
+ UINT16 selector;
+ UINT32 address;
+ if( modrm >= 0xc0 ) {
+ fatalerror("NYI");
+ } else {
+ UINT32 ea = GetEA(modrm);
+ address = READ32(ea + 0);
+ selector = READ16(ea + 4);
+ CYCLES(CYCLES_JMP_MEM_INTERSEG); /* TODO: Timing = 10 + m */
+ }
+ I.sreg[CS].selector = selector;
+ I.performed_intersegment_jump = 1;
+ i386_load_segment_descriptor( CS );
+ I.eip = address;
+ CHANGE_PC(I.eip);
+ }
+ break;
+ case 6: /* PUSH Rm32 */
+ {
+ UINT32 value;
+ if( modrm >= 0xc0 ) {
+ value = LOAD_RM32(modrm);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ value = READ32(ea);
+ }
+ PUSH32(value);
+ CYCLES(CYCLES_PUSH_RM);
+ }
+ break;
+ default:
+ fatalerror("i386: groupFF_32 /%d unimplemented at %08X", (modrm >> 3) & 0x7, I.pc-2);
+ break;
+ }
+}
+
+static void I386OP(group0F00_32)(void) // Opcode 0x0f 00
+{
+ UINT32 address, ea;
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 2: /* LLDT */
+ if ( PROTECTED_MODE && !V8086_MODE )
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ CYCLES(CYCLES_LLDT_REG);
+ } else {
+ ea = GetEA(modrm);
+ CYCLES(CYCLES_LLDT_MEM);
+ }
+ I.ldtr.segment = READ32(ea);
+ }
+ else
+ {
+ i386_trap(6, 0);
+ }
+ break;
+
+ case 3: /* LTR */
+ if ( PROTECTED_MODE && !V8086_MODE )
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ CYCLES(CYCLES_LTR_REG);
+ } else {
+ ea = GetEA(modrm);
+ CYCLES(CYCLES_LTR_MEM);
+ }
+ I.task.segment = READ32(ea);
+ }
+ else
+ {
+ i386_trap(6, 0);
+ }
+ break;
+
+ default:
+ fatalerror("i386: group0F00_32 /%d unimplemented", (modrm >> 3) & 0x7);
+ break;
+ }
+}
+
+static void I386OP(group0F01_32)(void) // Opcode 0x0f 01
+{
+ UINT8 modrm = FETCH();
+ UINT32 address, ea;
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* SGDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ WRITE16(ea, I.gdtr.limit);
+ WRITE32(ea + 2, I.gdtr.base);
+ CYCLES(CYCLES_SGDT);
+ break;
+ }
+ case 1: /* SIDT */
+ {
+ if (modrm >= 0xc0)
+ {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ }
+ else
+ {
+ ea = GetEA(modrm);
+ }
+ WRITE16(ea, I.idtr.limit);
+ WRITE32(ea + 2, I.idtr.base);
+ CYCLES(CYCLES_SIDT);
+ break;
+ }
+ case 2: /* LGDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ I.gdtr.limit = READ16(ea);
+ I.gdtr.base = READ32(ea + 2);
+ CYCLES(CYCLES_LGDT);
+ break;
+ }
+ case 3: /* LIDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ I.idtr.limit = READ16(ea);
+ I.idtr.base = READ32(ea + 2);
+ CYCLES(CYCLES_LIDT);
+ break;
+ }
+ default:
+ fatalerror("i386: unimplemented opcode 0x0f 01 /%d at %08X", (modrm >> 3) & 0x7, I.eip - 2);
+ break;
+ }
+}
+
+static void I386OP(group0FBA_32)(void) // Opcode 0x0f ba
+{
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 4: /* BT Rm32, i8 */
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+
+ CYCLES(CYCLES_BT_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+
+ CYCLES(CYCLES_BT_IMM_MEM);
+ }
+ break;
+ case 5: /* BTS Rm32, i8 */
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst |= (1 << bit);
+
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_BTS_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst |= (1 << bit);
+
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_BTS_IMM_MEM);
+ }
+ break;
+ case 6: /* BTR Rm32, i8 */
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst &= ~(1 << bit);
+
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_BTR_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst &= ~(1 << bit);
+
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_BTR_IMM_MEM);
+ }
+ break;
+ case 7: /* BTC Rm32, i8 */
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst ^= (1 << bit);
+
+ STORE_RM32(modrm, dst);
+ CYCLES(CYCLES_BTC_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT8 bit = FETCH();
+
+ if( dst & (1 << bit) )
+ I.CF = 1;
+ else
+ I.CF = 0;
+ dst ^= (1 << bit);
+
+ WRITE32(ea, dst);
+ CYCLES(CYCLES_BTC_IMM_MEM);
+ }
+ break;
+ default:
+ fatalerror("i386: group0FBA_32 /%d unknown", (modrm >> 3) & 0x7);
+ break;
+ }
+}
+
+static void I386OP(bound_r32_m32_m32)(void) // Opcode 0x62
+{
+ UINT8 modrm;
+ INT32 val, low, high;
+
+ modrm = FETCH();
+
+ if (modrm >= 0xc0)
+ {
+ low = high = LOAD_RM32(modrm);
+ }
+ else
+ {
+ UINT32 ea = GetEA(modrm);
+ low = READ32(ea + 0);
+ high = READ32(ea + 4);
+ }
+ val = LOAD_REG32(modrm);
+
+ if ((val < low) || (val > high))
+ {
+ CYCLES(CYCLES_BOUND_OUT_RANGE);
+ i386_trap(5, 0);
+ }
+ else
+ {
+ CYCLES(CYCLES_BOUND_IN_RANGE);
+ }
+}
+
+static void I386OP(retf32)(void) // Opcode 0xcb
+{
+ I.eip = POP32();
+ I.sreg[CS].selector = POP32();
+ i386_load_segment_descriptor( CS );
+ CHANGE_PC(I.eip);
+
+ CYCLES(CYCLES_RET_INTERSEG);
+}
+
+static void I386OP(retf_i32)(void) // Opcode 0xca
+{
+ UINT16 count = FETCH16();
+
+ I.eip = POP32();
+ I.sreg[CS].selector = POP32();
+ i386_load_segment_descriptor( CS );
+ CHANGE_PC(I.eip);
+
+ REG32(ESP) += count;
+ CYCLES(CYCLES_RET_IMM_INTERSEG);
+}
+
+static void I386OP(xlat32)(void) // Opcode 0xd7
+{
+ UINT32 ea;
+ if( I.segment_prefix ) {
+ ea = i386_translate( I.segment_override, REG32(EBX) + REG8(AL) );
+ } else {
+ ea = i386_translate( DS, REG32(EBX) + REG8(AL) );
+ }
+ REG8(AL) = READ8(ea);
+ CYCLES(CYCLES_XLAT);
+}
+
+static void I386OP(load_far_pointer32)(int s)
+{
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ fatalerror("NYI");
+ } else {
+ UINT32 ea = GetEA(modrm);
+ STORE_REG32(modrm, READ32(ea + 0));
+ I.sreg[s].selector = READ16(ea + 4);
+ i386_load_segment_descriptor( s );
+ }
+}
+
+static void I386OP(lds32)(void) // Opcode 0xc5
+{
+ I386OP(load_far_pointer32)(DS);
+ CYCLES(CYCLES_LDS);
+}
+
+static void I386OP(lss32)(void) // Opcode 0x0f 0xb2
+{
+ I386OP(load_far_pointer32)(SS);
+ CYCLES(CYCLES_LSS);
+}
+
+static void I386OP(les32)(void) // Opcode 0xc4
+{
+ I386OP(load_far_pointer16)(ES);
+ CYCLES(CYCLES_LES);
+}
+
+static void I386OP(lfs32)(void) // Opcode 0x0f 0xb4
+{
+ I386OP(load_far_pointer16)(FS);
+ CYCLES(CYCLES_LFS);
+}
+
+static void I386OP(lgs32)(void) // Opcode 0x0f 0xb5
+{
+ I386OP(load_far_pointer32)(GS);
+ CYCLES(CYCLES_LGS);
+}
diff --git a/src/emu/cpu/i386/i386ops.c b/src/emu/cpu/i386/i386ops.c
new file mode 100644
index 00000000000..8a98897e91f
--- /dev/null
+++ b/src/emu/cpu/i386/i386ops.c
@@ -0,0 +1,2306 @@
+static UINT8 I386OP(shift_rotate8)(UINT8 modrm, UINT32 value, UINT8 shift)
+{
+ UINT8 src = value;
+ UINT8 dst = value;
+
+ if( shift == 0 ) {
+ CYCLES_RM(modrm, 3, 7);
+ } else if( shift == 1 ) {
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* ROL rm8, 1 */
+ I.CF = (src & 0x80) ? 1 : 0;
+ dst = (src << 1) + I.CF;
+ I.OF = ((src ^ dst) & 0x80) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 1: /* ROR rm8, 1 */
+ I.CF = (src & 0x1) ? 1 : 0;
+ dst = (I.CF << 7) | (src >> 1);
+ I.OF = ((src ^ dst) & 0x80) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 2: /* RCL rm8, 1 */
+ dst = (src << 1) + I.CF;
+ I.CF = (src & 0x80) ? 1 : 0;
+ I.OF = ((src ^ dst) & 0x80) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 3: /* RCR rm8, 1 */
+ dst = (I.CF << 7) | (src >> 1);
+ I.CF = src & 0x1;
+ I.OF = ((src ^ dst) & 0x80) ? 1 : 0;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 4: /* SHL/SAL rm8, 1 */
+ case 6:
+ dst = src << 1;
+ I.CF = (src & 0x80) ? 1 : 0;
+ I.OF = (((I.CF << 7) ^ dst) & 0x80) ? 1 : 0;
+ SetSZPF8(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 5: /* SHR rm8, 1 */
+ dst = src >> 1;
+ I.CF = src & 0x1;
+ I.OF = (dst & 0x80) ? 1 : 0;
+ SetSZPF8(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 7: /* SAR rm8, 1 */
+ dst = (INT8)(src) >> 1;
+ I.CF = src & 0x1;
+ I.OF = 0;
+ SetSZPF8(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ }
+
+ } else {
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* ROL rm8, i8 */
+ dst = ((src & ((UINT8)0xff >> shift)) << shift) |
+ ((src & ((UINT8)0xff << (8-shift))) >> (8-shift));
+ I.CF = (src >> (8-shift)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 1: /* ROR rm8, i8 */
+ dst = ((src & ((UINT8)0xff << shift)) >> shift) |
+ ((src & ((UINT8)0xff >> (8-shift))) << (8-shift));
+ I.CF = (src >> (shift-1)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 2: /* RCL rm8, i8 */
+ dst = ((src & ((UINT8)0xff >> shift)) << shift) |
+ ((src & ((UINT8)0xff << (9-shift))) >> (9-shift)) |
+ (I.CF << (shift-1));
+ I.CF = (src >> (8-shift)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 3: /* RCR rm8, i8 */
+ dst = ((src & ((UINT8)0xff << shift)) >> shift) |
+ ((src & ((UINT8)0xff >> (8-shift))) << (9-shift)) |
+ (I.CF << (8-shift));
+ I.CF = (src >> (shift-1)) & 0x1;
+ CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
+ break;
+ case 4: /* SHL/SAL rm8, i8 */
+ case 6:
+ dst = src << shift;
+ I.CF = (src & (1 << (8-shift))) ? 1 : 0;
+ SetSZPF8(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 5: /* SHR rm8, i8 */
+ dst = src >> shift;
+ I.CF = (src & (1 << (shift-1))) ? 1 : 0;
+ SetSZPF8(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ case 7: /* SAR rm8, i8 */
+ dst = (INT8)src >> shift;
+ I.CF = (src & (1 << (shift-1))) ? 1 : 0;
+ SetSZPF8(dst);
+ CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
+ break;
+ }
+ }
+
+ return dst;
+}
+
+
+
+static void I386OP(adc_rm8_r8)(void) // Opcode 0x10
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm);
+ dst = LOAD_RM8(modrm);
+ src = ADD8(src, I.CF);
+ dst = ADD8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm);
+ dst = READ8(ea);
+ src = ADD8(src, I.CF);
+ dst = ADD8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(adc_r8_rm8)(void) // Opcode 0x12
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ dst = LOAD_REG8(modrm);
+ src = ADD8(src, I.CF);
+ dst = ADD8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ dst = LOAD_REG8(modrm);
+ src = ADD8(src, I.CF);
+ dst = ADD8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(adc_al_i8)(void) // Opcode 0x14
+{
+ UINT8 src, dst;
+ src = FETCH();
+ dst = REG8(AL);
+ src = ADD8(src, I.CF);
+ dst = ADD8(dst, src);
+ REG8(AL) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(add_rm8_r8)(void) // Opcode 0x00
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm);
+ dst = LOAD_RM8(modrm);
+ dst = ADD8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm);
+ dst = READ8(ea);
+ dst = ADD8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(add_r8_rm8)(void) // Opcode 0x02
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ dst = LOAD_REG8(modrm);
+ dst = ADD8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ dst = LOAD_REG8(modrm);
+ dst = ADD8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(add_al_i8)(void) // Opcode 0x04
+{
+ UINT8 src, dst;
+ src = FETCH();
+ dst = REG8(AL);
+ dst = ADD8(dst, src);
+ REG8(AL) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(and_rm8_r8)(void) // Opcode 0x20
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm);
+ dst = LOAD_RM8(modrm);
+ dst = AND8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm);
+ dst = READ8(ea);
+ dst = AND8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(and_r8_rm8)(void) // Opcode 0x22
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ dst = LOAD_REG8(modrm);
+ dst = AND8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ dst = LOAD_REG8(modrm);
+ dst = AND8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(and_al_i8)(void) // Opcode 0x24
+{
+ UINT8 src, dst;
+ src = FETCH();
+ dst = REG8(AL);
+ dst = AND8(dst, src);
+ REG8(AL) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(clc)(void) // Opcode 0xf8
+{
+ I.CF = 0;
+ CYCLES(CYCLES_CLC);
+}
+
+static void I386OP(cld)(void) // Opcode 0xfc
+{
+ I.DF = 0;
+ CYCLES(CYCLES_CLD);
+}
+
+static void I386OP(cli)(void) // Opcode 0xfa
+{
+ I.IF = 0;
+ CYCLES(CYCLES_CLI);
+}
+
+static void I386OP(cmc)(void) // Opcode 0xf5
+{
+ I.CF ^= 1;
+ CYCLES(CYCLES_CMC);
+}
+
+static void I386OP(cmp_rm8_r8)(void) // Opcode 0x38
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm);
+ dst = LOAD_RM8(modrm);
+ SUB8(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm);
+ dst = READ8(ea);
+ SUB8(dst, src);
+ CYCLES(CYCLES_CMP_REG_MEM);
+ }
+}
+
+static void I386OP(cmp_r8_rm8)(void) // Opcode 0x3a
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ dst = LOAD_REG8(modrm);
+ SUB8(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ dst = LOAD_REG8(modrm);
+ SUB8(dst, src);
+ CYCLES(CYCLES_CMP_MEM_REG);
+ }
+}
+
+static void I386OP(cmp_al_i8)(void) // Opcode 0x3c
+{
+ UINT8 src, dst;
+ src = FETCH();
+ dst = REG8(AL);
+ SUB8(dst, src);
+ CYCLES(CYCLES_CMP_IMM_ACC);
+}
+
+static void I386OP(cmpsb)(void) // Opcode 0xa6
+{
+ UINT32 eas, ead;
+ UINT8 src, dst;
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.address_size ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.address_size ? REG32(ESI) : REG16(SI) );
+ }
+ ead = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ src = READ8(eas);
+ dst = READ8(ead);
+ SUB8(dst, src);
+ BUMP_SI(1);
+ BUMP_DI(1);
+ CYCLES(CYCLES_CMPS);
+}
+
+static void I386OP(in_al_i8)(void) // Opcode 0xe4
+{
+ UINT16 port = FETCH();
+ UINT8 data = READPORT8(port);
+ REG8(AL) = data;
+ CYCLES(CYCLES_IN_VAR);
+}
+
+static void I386OP(in_al_dx)(void) // Opcode 0xec
+{
+ UINT16 port = REG16(DX);
+ UINT8 data = READPORT8(port);
+ REG8(AL) = data;
+ CYCLES(CYCLES_IN);
+}
+
+static void I386OP(ja_rel8)(void) // Opcode 0x77
+{
+ INT8 disp = FETCH();
+ if( I.CF == 0 && I.ZF == 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jbe_rel8)(void) // Opcode 0x76
+{
+ INT8 disp = FETCH();
+ if( I.CF != 0 || I.ZF != 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jc_rel8)(void) // Opcode 0x72
+{
+ INT8 disp = FETCH();
+ if( I.CF != 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jg_rel8)(void) // Opcode 0x7f
+{
+ INT8 disp = FETCH();
+ if( I.ZF == 0 && (I.SF == I.OF) ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jge_rel8)(void) // Opcode 0x7d
+{
+ INT8 disp = FETCH();
+ if( (I.SF == I.OF) ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jl_rel8)(void) // Opcode 0x7c
+{
+ INT8 disp = FETCH();
+ if( (I.SF != I.OF) ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jle_rel8)(void) // Opcode 0x7e
+{
+ INT8 disp = FETCH();
+ if( I.ZF != 0 || (I.SF != I.OF) ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jnc_rel8)(void) // Opcode 0x73
+{
+ INT8 disp = FETCH();
+ if( I.CF == 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jno_rel8)(void) // Opcode 0x71
+{
+ INT8 disp = FETCH();
+ if( I.OF == 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jnp_rel8)(void) // Opcode 0x7b
+{
+ INT8 disp = FETCH();
+ if( I.PF == 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jns_rel8)(void) // Opcode 0x79
+{
+ INT8 disp = FETCH();
+ if( I.SF == 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jnz_rel8)(void) // Opcode 0x75
+{
+ INT8 disp = FETCH();
+ if( I.ZF == 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jo_rel8)(void) // Opcode 0x70
+{
+ INT8 disp = FETCH();
+ if( I.OF != 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jp_rel8)(void) // Opcode 0x7a
+{
+ INT8 disp = FETCH();
+ if( I.PF != 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(js_rel8)(void) // Opcode 0x78
+{
+ INT8 disp = FETCH();
+ if( I.SF != 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jz_rel8)(void) // Opcode 0x74
+{
+ INT8 disp = FETCH();
+ if( I.ZF != 0 ) {
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */
+ } else {
+ CYCLES(CYCLES_JCC_DISP8_NOBRANCH);
+ }
+}
+
+static void I386OP(jmp_rel8)(void) // Opcode 0xeb
+{
+ INT8 disp = FETCH();
+ NEAR_BRANCH(disp);
+ CYCLES(CYCLES_JMP_SHORT); /* TODO: Timing = 7 + m */
+}
+
+static void I386OP(lahf)(void) // Opcode 0x9f
+{
+ REG8(AH) = get_flags() & 0xd7;
+ CYCLES(CYCLES_LAHF);
+}
+
+static void I386OP(lodsb)(void) // Opcode 0xac
+{
+ UINT32 eas;
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.address_size ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.address_size ? REG32(ESI) : REG16(SI) );
+ }
+ REG8(AL) = READ8(eas);
+ BUMP_SI(1);
+ CYCLES(CYCLES_LODS);
+}
+
+static void I386OP(mov_rm8_r8)(void) // Opcode 0x88
+{
+ UINT8 src;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm);
+ STORE_RM8(modrm, src);
+ CYCLES(CYCLES_MOV_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm);
+ WRITE8(ea, src);
+ CYCLES(CYCLES_MOV_REG_MEM);
+ }
+}
+
+static void I386OP(mov_r8_rm8)(void) // Opcode 0x8a
+{
+ UINT8 src;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ STORE_REG8(modrm, src);
+ CYCLES(CYCLES_MOV_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ STORE_REG8(modrm, src);
+ CYCLES(CYCLES_MOV_MEM_REG);
+ }
+}
+
+static void I386OP(mov_rm8_i8)(void) // Opcode 0xc6
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT8 value = FETCH();
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_MOV_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT8 value = FETCH();
+ WRITE8(ea, value);
+ CYCLES(CYCLES_MOV_IMM_MEM);
+ }
+}
+
+static void I386OP(mov_r32_cr)(void) // Opcode 0x0f 20
+{
+ UINT8 modrm = FETCH();
+ UINT8 cr = (modrm >> 3) & 0x7;
+
+ STORE_RM32(modrm, I.cr[cr]);
+ CYCLES(CYCLES_MOV_CR_REG);
+}
+
+static void I386OP(mov_r32_dr)(void) // Opcode 0x0f 21
+{
+ UINT8 modrm = FETCH();
+ UINT8 dr = (modrm >> 3) & 0x7;
+
+ STORE_RM32(modrm, I.dr[dr]);
+ switch(dr)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ CYCLES(CYCLES_MOV_REG_DR0_3);
+ break;
+ case 6:
+ case 7:
+ CYCLES(CYCLES_MOV_REG_DR6_7);
+ break;
+ }
+}
+
+static void I386OP(mov_cr_r32)(void) // Opcode 0x0f 22
+{
+ UINT8 modrm = FETCH();
+ UINT8 cr = (modrm >> 3) & 0x7;
+
+ I.cr[cr] = LOAD_RM32(modrm);
+ switch(cr)
+ {
+ case 0: CYCLES(CYCLES_MOV_REG_CR0); break;
+ case 2: CYCLES(CYCLES_MOV_REG_CR2); break;
+ case 3: CYCLES(CYCLES_MOV_REG_CR3); break;
+ default:
+ fatalerror("i386: mov_cr_r32 CR%d !", cr);
+ break;
+ }
+}
+
+static void I386OP(mov_dr_r32)(void) // Opcode 0x0f 23
+{
+ UINT8 modrm = FETCH();
+ UINT8 dr = (modrm >> 3) & 0x7;
+
+ I.dr[dr] = LOAD_RM32(modrm);
+ switch(dr)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ CYCLES(CYCLES_MOV_DR0_3_REG);
+ break;
+ case 6:
+ case 7:
+ CYCLES(CYCLES_MOV_DR6_7_REG);
+ break;
+ default:
+ fatalerror("i386: mov_dr_r32 DR%d !", dr);
+ break;
+ }
+}
+
+static void I386OP(mov_al_m8)(void) // Opcode 0xa0
+{
+ UINT32 offset, ea;
+ if( I.address_size ) {
+ offset = FETCH32();
+ } else {
+ offset = FETCH16();
+ }
+ /* TODO: Not sure if this is correct... */
+ if( I.segment_prefix ) {
+ ea = i386_translate( I.segment_override, offset );
+ } else {
+ ea = i386_translate( DS, offset );
+ }
+ REG8(AL) = READ8(ea);
+ CYCLES(CYCLES_MOV_IMM_MEM);
+}
+
+static void I386OP(mov_m8_al)(void) // Opcode 0xa2
+{
+ UINT32 offset, ea;
+ if( I.address_size ) {
+ offset = FETCH32();
+ } else {
+ offset = FETCH16();
+ }
+ /* TODO: Not sure if this is correct... */
+ if( I.segment_prefix ) {
+ ea = i386_translate( I.segment_override, offset );
+ } else {
+ ea = i386_translate( DS, offset );
+ }
+ WRITE8( ea, REG8(AL) );
+ CYCLES(CYCLES_MOV_MEM_ACC);
+}
+
+static void I386OP(mov_rm16_sreg)(void) // Opcode 0x8c
+{
+ UINT8 modrm = FETCH();
+ int s = (modrm >> 3) & 0x7;
+
+ if( modrm >= 0xc0 ) {
+ STORE_RM16(modrm, I.sreg[s].selector);
+ CYCLES(CYCLES_MOV_SREG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE16(ea, I.sreg[s].selector);
+ CYCLES(CYCLES_MOV_SREG_MEM);
+ }
+}
+
+static void I386OP(mov_sreg_rm16)(void) // Opcode 0x8e
+{
+ UINT16 selector;
+ UINT8 modrm = FETCH();
+ int s = (modrm >> 3) & 0x7;
+
+ if( modrm >= 0xc0 ) {
+ selector = LOAD_RM16(modrm);
+ CYCLES(CYCLES_MOV_REG_SREG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ selector = READ16(ea);
+ CYCLES(CYCLES_MOV_MEM_SREG);
+ }
+ I.sreg[s].selector = selector;
+ i386_load_segment_descriptor( s );
+}
+
+static void I386OP(mov_al_i8)(void) // Opcode 0xb0
+{
+ REG8(AL) = FETCH();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_cl_i8)(void) // Opcode 0xb1
+{
+ REG8(CL) = FETCH();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_dl_i8)(void) // Opcode 0xb2
+{
+ REG8(DL) = FETCH();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_bl_i8)(void) // Opcode 0xb3
+{
+ REG8(BL) = FETCH();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_ah_i8)(void) // Opcode 0xb4
+{
+ REG8(AH) = FETCH();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_ch_i8)(void) // Opcode 0xb5
+{
+ REG8(CH) = FETCH();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_dh_i8)(void) // Opcode 0xb6
+{
+ REG8(DH) = FETCH();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(mov_bh_i8)(void) // Opcode 0xb7
+{
+ REG8(BH) = FETCH();
+ CYCLES(CYCLES_MOV_IMM_REG);
+}
+
+static void I386OP(movsb)(void) // Opcode 0xa4
+{
+ UINT32 eas, ead;
+ UINT8 v;
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.address_size ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.address_size ? REG32(ESI) : REG16(SI) );
+ }
+ ead = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ v = READ8(eas);
+ WRITE8(ead, v);
+ BUMP_SI(1);
+ BUMP_DI(1);
+ CYCLES(CYCLES_MOVS);
+}
+
+static void I386OP(or_rm8_r8)(void) // Opcode 0x08
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm);
+ dst = LOAD_RM8(modrm);
+ dst = OR8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm);
+ dst = READ8(ea);
+ dst = OR8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(or_r8_rm8)(void) // Opcode 0x0a
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ dst = LOAD_REG8(modrm);
+ dst = OR8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ dst = LOAD_REG8(modrm);
+ dst = OR8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(or_al_i8)(void) // Opcode 0x0c
+{
+ UINT8 src, dst;
+ src = FETCH();
+ dst = REG8(AL);
+ dst = OR8(dst, src);
+ REG8(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(out_al_i8)(void) // Opcode 0xe6
+{
+ UINT16 port = FETCH();
+ UINT8 data = REG8(AL);
+ WRITEPORT8(port, data);
+ CYCLES(CYCLES_OUT_VAR);
+}
+
+static void I386OP(out_al_dx)(void) // Opcode 0xee
+{
+ UINT16 port = REG16(DX);
+ UINT8 data = REG8(AL);
+ WRITEPORT8(port, data);
+ CYCLES(CYCLES_OUT);
+}
+
+static void I386OP(push_i8)(void) // Opcode 0x6a
+{
+ UINT8 value = FETCH();
+ PUSH8(value);
+ CYCLES(CYCLES_PUSH_IMM);
+}
+
+static void I386OP(ins_generic)(int size)
+{
+ UINT32 ead;
+ UINT8 vb;
+ UINT16 vw;
+ UINT32 vd;
+
+ ead = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+
+ switch(size) {
+ case 1:
+ vb = READPORT8(REG16(DX));
+ WRITE8(ead, vb);
+ break;
+ case 2:
+ vw = READPORT16(REG16(DX));
+ WRITE16(ead, vw);
+ break;
+ case 4:
+ vd = READPORT32(REG16(DX));
+ WRITE32(ead, vd);
+ break;
+ }
+
+ REG32(EDI) += ((I.DF) ? -1 : 1) * size;
+ CYCLES(CYCLES_INS); // TODO: Confirm this value
+}
+
+static void I386OP(insb)(void) // Opcode 0x6c
+{
+ I386OP(ins_generic)(1);
+}
+
+static void I386OP(insw)(void) // Opcode 0x6d
+{
+ I386OP(ins_generic)(2);
+}
+
+static void I386OP(insd)(void) // Opcode 0x6d
+{
+ I386OP(ins_generic)(4);
+}
+
+static void I386OP(outs_generic)(int size)
+{
+ UINT32 eas;
+ UINT8 vb;
+ UINT16 vw;
+ UINT32 vd;
+
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, REG32(ESI) );
+ } else {
+ eas = i386_translate( DS, REG32(ESI) );
+ }
+
+ switch(size) {
+ case 1:
+ vb = READ8(eas);
+ WRITEPORT8(REG16(DX), vb);
+ break;
+ case 2:
+ vw = READ16(eas);
+ WRITEPORT16(REG16(DX), vw);
+ break;
+ case 4:
+ vd = READ32(eas);
+ WRITEPORT32(REG16(DX), vd);
+ break;
+ }
+
+ REG32(ESI) += ((I.DF) ? -1 : 1) * size;
+ CYCLES(CYCLES_OUTS); // TODO: Confirm this value
+}
+
+static void I386OP(outsb)(void) // Opcode 0x6e
+{
+ I386OP(outs_generic)(1);
+}
+
+static void I386OP(outsw)(void) // Opcode 0x6f
+{
+ I386OP(outs_generic)(2);
+}
+
+static void I386OP(outsd)(void) // Opcode 0x6f
+{
+ I386OP(outs_generic)(4);
+}
+
+static void I386OP(repeat)(int invert_flag)
+{
+ UINT32 repeated_eip = I.eip;
+ UINT32 repeated_pc = I.pc;
+ UINT8 opcode = FETCH();
+ UINT32 eas, ead;
+ UINT32 count;
+ INT32 cycle_base = 0, cycle_adjustment = 0;
+ UINT8 *flag = NULL;
+
+ if( I.segment_prefix ) {
+ eas = i386_translate( I.segment_override, I.sreg[CS].d ? REG32(ESI) : REG16(SI) );
+ } else {
+ eas = i386_translate( DS, I.sreg[CS].d ? REG32(ESI) : REG16(SI) );
+ }
+ ead = i386_translate( ES, I.sreg[CS].d ? REG32(EDI) : REG16(DI) );
+
+ if( opcode == 0x66 ) {
+ I.operand_size ^= 1;
+ repeated_eip = I.eip;
+ repeated_pc = I.pc;
+ opcode = FETCH();
+ }
+ if( opcode == 0x67 ) {
+ I.address_size ^= 1;
+ repeated_eip = I.eip;
+ repeated_pc = I.pc;
+ opcode = FETCH();
+ }
+
+ switch(opcode)
+ {
+ case 0x6c:
+ case 0x6d:
+ /* INSB, INSW, INSD */
+ // TODO: cycle count
+ cycle_base = 8;
+ cycle_adjustment = -4;
+ flag = NULL;
+ break;
+
+ case 0x6e:
+ case 0x6f:
+ /* OUTSB, OUTSW, OUTSD */
+ // TODO: cycle count
+ cycle_base = 8;
+ cycle_adjustment = -4;
+ flag = NULL;
+ break;
+
+ case 0xa4:
+ case 0xa5:
+ /* MOVSB, MOVSW, MOVSD */
+ cycle_base = 8;
+ cycle_adjustment = -4;
+ flag = NULL;
+ break;
+
+ case 0xa6:
+ case 0xa7:
+ /* CMPSB, CMPSW, CMPSD */
+ cycle_base = 5;
+ cycle_adjustment = -1;
+ flag = &I.ZF;
+ break;
+
+ case 0xac:
+ case 0xad:
+ /* LODSB, LODSW, LODSD */
+ cycle_base = 5;
+ cycle_adjustment = 1;
+ flag = NULL;
+ break;
+
+ case 0xaa:
+ case 0xab:
+ /* STOSB, STOSW, STOSD */
+ cycle_base = 5;
+ cycle_adjustment = 0;
+ flag = NULL;
+ break;
+
+ case 0xae:
+ case 0xaf:
+ /* SCASB, SCASW, SCASD */
+ cycle_base = 5;
+ cycle_adjustment = 0;
+ flag = &I.ZF;
+ break;
+
+ default:
+ fatalerror("i386: Invalid REP/opcode %02X combination",opcode);
+ break;
+ }
+
+ if( I.sreg[CS].d ) {
+ if( REG32(ECX) == 0 )
+ return;
+ } else {
+ if( REG16(CX) == 0 )
+ return;
+ }
+
+ /* now actually perform the repeat */
+ CYCLES_NUM(cycle_base);
+ do
+ {
+ I.eip = repeated_eip;
+ I.pc = repeated_pc;
+ I386OP(decode_opcode)();
+ CYCLES_NUM(cycle_adjustment);
+
+ if (I.sreg[CS].d)
+ count = --REG32(ECX);
+ else
+ count = --REG16(CX);
+ if (I.cycles <= 0)
+ goto outofcycles;
+ }
+ while( count && (!flag || (invert_flag ? !*flag : *flag)) );
+ return;
+
+outofcycles:
+ /* if we run out of cycles to execute, and we are still in the repeat, we need
+ * to exit this instruction in such a way to go right back into it when we have
+ * time to execute cycles */
+ I.eip = I.prev_eip;
+ CHANGE_PC(I.eip);
+ CYCLES_NUM(-cycle_base);
+}
+
+static void I386OP(rep)(void) // Opcode 0xf3
+{
+ I386OP(repeat)(0);
+ }
+
+static void I386OP(repne)(void) // Opcode 0xf2
+ {
+ I386OP(repeat)(1);
+}
+
+static void I386OP(sahf)(void) // Opcode 0x9e
+{
+ set_flags( (get_flags() & 0xffffff00) | (REG8(AH) & 0xd7) );
+ CYCLES(CYCLES_SAHF);
+}
+
+static void I386OP(sbb_rm8_r8)(void) // Opcode 0x18
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm) + I.CF;
+ dst = LOAD_RM8(modrm);
+ dst = SUB8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm) + I.CF;
+ dst = READ8(ea);
+ dst = SUB8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(sbb_r8_rm8)(void) // Opcode 0x1a
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm) + I.CF;
+ dst = LOAD_REG8(modrm);
+ dst = SUB8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea) + I.CF;
+ dst = LOAD_REG8(modrm);
+ dst = SUB8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(sbb_al_i8)(void) // Opcode 0x1c
+{
+ UINT8 src, dst;
+ src = FETCH() + I.CF;
+ dst = REG8(AL);
+ dst = SUB8(dst, src);
+ REG8(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(scasb)(void) // Opcode 0xae
+{
+ UINT32 eas;
+ UINT8 src, dst;
+ eas = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ src = READ8(eas);
+ dst = REG8(AL);
+ SUB8(dst, src);
+ BUMP_DI(1);
+ CYCLES(CYCLES_SCAS);
+}
+
+static void I386OP(setalc)(void) // Opcode 0xd6 (undocumented)
+{
+ if( I.CF ) {
+ REG8(AL) = 0xff;
+ } else {
+ REG8(AL) = 0;
+ }
+ CYCLES(3);
+}
+
+static void I386OP(seta_rm8)(void) // Opcode 0x0f 97
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.CF == 0 && I.ZF == 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setbe_rm8)(void) // Opcode 0x0f 96
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.CF != 0 || I.ZF != 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setc_rm8)(void) // Opcode 0x0f 92
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.CF != 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setg_rm8)(void) // Opcode 0x0f 9f
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.ZF == 0 && (I.SF == I.OF) ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setge_rm8)(void) // Opcode 0x0f 9d
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( (I.SF == I.OF) ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setl_rm8)(void) // Opcode 0x0f 9c
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.SF != I.OF ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setle_rm8)(void) // Opcode 0x0f 9e
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.ZF != 0 || (I.SF != I.OF) ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setnc_rm8)(void) // Opcode 0x0f 93
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.CF == 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setno_rm8)(void) // Opcode 0x0f 91
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.OF == 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setnp_rm8)(void) // Opcode 0x0f 9b
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.PF == 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setns_rm8)(void) // Opcode 0x0f 99
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.SF == 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setnz_rm8)(void) // Opcode 0x0f 95
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.ZF == 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(seto_rm8)(void) // Opcode 0x0f 90
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.OF != 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setp_rm8)(void) // Opcode 0x0f 9a
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.PF != 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(sets_rm8)(void) // Opcode 0x0f 98
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.SF != 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(setz_rm8)(void) // Opcode 0x0f 94
+{
+ UINT8 modrm = FETCH();
+ UINT8 value = 0;
+ if( I.ZF != 0 ) {
+ value = 1;
+ }
+ if( modrm >= 0xc0 ) {
+ STORE_RM8(modrm, value);
+ CYCLES(CYCLES_SETCC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE8(ea, value);
+ CYCLES(CYCLES_SETCC_MEM);
+ }
+}
+
+static void I386OP(stc)(void) // Opcode 0xf9
+{
+ I.CF = 1;
+ CYCLES(CYCLES_STC);
+}
+
+static void I386OP(std)(void) // Opcode 0xfd
+{
+ I.DF = 1;
+ CYCLES(CYCLES_STD);
+}
+
+static void I386OP(sti)(void) // Opcode 0xfb
+{
+ I.IF = 1;
+ CYCLES(CYCLES_STI);
+}
+
+static void I386OP(stosb)(void) // Opcode 0xaa
+{
+ UINT32 ead;
+ ead = i386_translate( ES, I.address_size ? REG32(EDI) : REG16(DI) );
+ WRITE8(ead, REG8(AL));
+ BUMP_DI(1);
+ CYCLES(CYCLES_STOS);
+}
+
+static void I386OP(sub_rm8_r8)(void) // Opcode 0x28
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm);
+ dst = LOAD_RM8(modrm);
+ dst = SUB8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm);
+ dst = READ8(ea);
+ dst = SUB8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(sub_r8_rm8)(void) // Opcode 0x2a
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ dst = LOAD_REG8(modrm);
+ dst = SUB8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ dst = LOAD_REG8(modrm);
+ dst = SUB8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(sub_al_i8)(void) // Opcode 0x2c
+{
+ UINT8 src, dst;
+ src = FETCH();
+ dst = REG8(EAX);
+ dst = SUB8(dst, src);
+ REG8(EAX) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(test_al_i8)(void) // Opcode 0xa8
+{
+ UINT8 src = FETCH();
+ UINT8 dst = REG8(AL);
+ dst = src & dst;
+ SetSZPF8(dst);
+ I.CF = 0;
+ I.OF = 0;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+static void I386OP(test_rm8_r8)(void) // Opcode 0x84
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm);
+ dst = LOAD_RM8(modrm);
+ dst = src & dst;
+ SetSZPF8(dst);
+ I.CF = 0;
+ I.OF = 0;
+ CYCLES(CYCLES_TEST_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm);
+ dst = READ8(ea);
+ dst = src & dst;
+ SetSZPF8(dst);
+ I.CF = 0;
+ I.OF = 0;
+ CYCLES(CYCLES_TEST_REG_MEM);
+ }
+}
+
+static void I386OP(xchg_r8_rm8)(void) // Opcode 0x86
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT8 src = LOAD_RM8(modrm);
+ UINT8 dst = LOAD_REG8(modrm);
+ STORE_REG8(modrm, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_XCHG_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT8 src = READ8(ea);
+ UINT8 dst = LOAD_REG8(modrm);
+ STORE_REG8(modrm, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_XCHG_REG_MEM);
+ }
+}
+
+static void I386OP(xor_rm8_r8)(void) // Opcode 0x30
+{
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_REG8(modrm);
+ dst = LOAD_RM8(modrm);
+ dst = XOR8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = LOAD_REG8(modrm);
+ dst = READ8(ea);
+ dst = XOR8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+}
+
+static void I386OP(xor_r8_rm8)(void) // Opcode 0x32
+{
+ UINT32 src, dst;
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ dst = LOAD_REG8(modrm);
+ dst = XOR8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ dst = LOAD_REG8(modrm);
+ dst = XOR8(dst, src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_ALU_MEM_REG);
+ }
+}
+
+static void I386OP(xor_al_i8)(void) // Opcode 0x34
+{
+ UINT8 src, dst;
+ src = FETCH();
+ dst = REG8(AL);
+ dst = XOR8(dst, src);
+ REG8(AL) = dst;
+ CYCLES(CYCLES_ALU_IMM_ACC);
+}
+
+
+
+static void I386OP(group80_8)(void) // Opcode 0x80
+{
+ UINT32 ea;
+ UINT8 src, dst;
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: // ADD Rm8, i8
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ src = FETCH();
+ dst = ADD8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ8(ea);
+ src = FETCH();
+ dst = ADD8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 1: // OR Rm8, i8
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ src = FETCH();
+ dst = OR8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ8(ea);
+ src = FETCH();
+ dst = OR8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 2: // ADC Rm8, i8
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ src = FETCH();
+ src = ADD8(src, I.CF);
+ dst = ADD8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ8(ea);
+ src = FETCH();
+ src = ADD8(src, I.CF);
+ dst = ADD8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 3: // SBB Rm8, i8
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ src = FETCH() + I.CF;
+ dst = SUB8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ8(ea);
+ src = FETCH() + I.CF;
+ dst = SUB8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 4: // AND Rm8, i8
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ src = FETCH();
+ dst = AND8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ8(ea);
+ src = FETCH();
+ dst = AND8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 5: // SUB Rm8, i8
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ src = FETCH();
+ dst = SUB8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ8(ea);
+ src = FETCH();
+ dst = SUB8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 6: // XOR Rm8, i8
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ src = FETCH();
+ dst = XOR8(dst, src);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_ALU_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ8(ea);
+ src = FETCH();
+ dst = XOR8(dst, src);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_ALU_REG_MEM);
+ }
+ break;
+ case 7: // CMP Rm8, i8
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ src = FETCH();
+ SUB8(dst, src);
+ CYCLES(CYCLES_CMP_REG_REG);
+ } else {
+ ea = GetEA(modrm);
+ dst = READ8(ea);
+ src = FETCH();
+ SUB8(dst, src);
+ CYCLES(CYCLES_CMP_REG_MEM);
+ }
+ break;
+ }
+}
+
+static void I386OP(groupC0_8)(void) // Opcode 0xc0
+{
+ UINT8 dst;
+ UINT8 modrm = FETCH();
+ UINT8 shift;
+
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ shift = FETCH() & 0x1f;
+ dst = i386_shift_rotate8(modrm, dst, shift);
+ STORE_RM8(modrm, dst);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = READ8(ea);
+ shift = FETCH() & 0x1f;
+ dst = i386_shift_rotate8(modrm, dst, shift);
+ WRITE8(ea, dst);
+ }
+}
+
+static void I386OP(groupD0_8)(void) // Opcode 0xd0
+{
+ UINT8 dst;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ dst = i386_shift_rotate8(modrm, dst, 1);
+ STORE_RM8(modrm, dst);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = READ8(ea);
+ dst = i386_shift_rotate8(modrm, dst, 1);
+ WRITE8(ea, dst);
+ }
+}
+
+static void I386OP(groupD2_8)(void) // Opcode 0xd2
+{
+ UINT8 dst;
+ UINT8 modrm = FETCH();
+
+ if( modrm >= 0xc0 ) {
+ dst = LOAD_RM8(modrm);
+ dst = i386_shift_rotate8(modrm, dst, REG8(CL));
+ STORE_RM8(modrm, dst);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ dst = READ8(ea);
+ dst = i386_shift_rotate8(modrm, dst, REG8(CL));
+ WRITE8(ea, dst);
+ }
+}
+
+static void I386OP(groupF6_8)(void) // Opcode 0xf6
+{
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* TEST Rm8, i8 */
+ if( modrm >= 0xc0 ) {
+ UINT8 dst = LOAD_RM8(modrm);
+ UINT8 src = FETCH();
+ dst &= src;
+ I.CF = I.OF = I.AF = 0;
+ SetSZPF8(dst);
+ CYCLES(CYCLES_TEST_IMM_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT8 dst = READ8(ea);
+ UINT8 src = FETCH();
+ dst &= src;
+ I.CF = I.OF = I.AF = 0;
+ SetSZPF8(dst);
+ CYCLES(CYCLES_TEST_IMM_MEM);
+ }
+ break;
+ case 2: /* NOT Rm8 */
+ if( modrm >= 0xc0 ) {
+ UINT8 dst = LOAD_RM8(modrm);
+ dst = ~dst;
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_NOT_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT8 dst = READ8(ea);
+ dst = ~dst;
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_NOT_MEM);
+ }
+ break;
+ case 3: /* NEG Rm8 */
+ if( modrm >= 0xc0 ) {
+ UINT8 dst = LOAD_RM8(modrm);
+ dst = SUB8( 0, dst );
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_NEG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT8 dst = READ8(ea);
+ dst = SUB8( 0, dst );
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_NEG_MEM);
+ }
+ break;
+ case 4: /* MUL AL, Rm8 */
+ {
+ UINT16 result;
+ UINT8 src, dst;
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ CYCLES(CYCLES_MUL8_ACC_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ CYCLES(CYCLES_MUL8_ACC_MEM); /* TODO: Correct multiply timing */
+ }
+
+ dst = REG8(AL);
+ result = (UINT16)src * (UINT16)dst;
+ REG16(AX) = (UINT16)result;
+
+ I.CF = I.OF = (REG16(AX) > 0xff);
+ }
+ break;
+ case 5: /* IMUL AL, Rm8 */
+ {
+ INT16 result;
+ INT16 src, dst;
+ if( modrm >= 0xc0 ) {
+ src = (INT16)(INT8)LOAD_RM8(modrm);
+ CYCLES(CYCLES_IMUL8_ACC_REG); /* TODO: Correct multiply timing */
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = (INT16)(INT8)READ8(ea);
+ CYCLES(CYCLES_IMUL8_ACC_MEM); /* TODO: Correct multiply timing */
+ }
+
+ dst = (INT16)(INT8)REG8(AL);
+ result = src * dst;
+
+ REG16(AX) = (UINT16)result;
+
+ I.CF = I.OF = !(result == (INT16)(INT8)result);
+ }
+ break;
+ case 6: /* DIV AL, Rm8 */
+ {
+ UINT16 quotient, remainder, result;
+ UINT8 src;
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ CYCLES(CYCLES_DIV8_ACC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ CYCLES(CYCLES_DIV8_ACC_MEM);
+ }
+
+ quotient = (UINT16)REG16(AX);
+ if( src ) {
+ remainder = quotient % (UINT16)src;
+ result = quotient / (UINT16)src;
+ if( result > 0xff ) {
+ /* TODO: Divide error */
+ } else {
+ REG8(AH) = (UINT8)remainder & 0xff;
+ REG8(AL) = (UINT8)result & 0xff;
+ }
+ } else {
+ /* TODO: Divide by zero */
+ }
+ }
+ break;
+ case 7: /* IDIV AL, Rm8 */
+ {
+ INT16 quotient, remainder, result;
+ UINT8 src;
+ if( modrm >= 0xc0 ) {
+ src = LOAD_RM8(modrm);
+ CYCLES(CYCLES_IDIV8_ACC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ src = READ8(ea);
+ CYCLES(CYCLES_IDIV8_ACC_MEM);
+ }
+
+ quotient = (INT16)REG16(AX);
+ if( src ) {
+ remainder = quotient % (INT16)(INT8)src;
+ result = quotient / (INT16)(INT8)src;
+ if( result > 0xff ) {
+ /* TODO: Divide error */
+ } else {
+ REG8(AH) = (UINT8)remainder & 0xff;
+ REG8(AL) = (UINT8)result & 0xff;
+ }
+ } else {
+ /* TODO: Divide by zero */
+ }
+ }
+ break;
+ }
+}
+
+static void I386OP(groupFE_8)(void) // Opcode 0xfe
+{
+ UINT8 modrm = FETCH();
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* INC Rm8 */
+ if( modrm >= 0xc0 ) {
+ UINT8 dst = LOAD_RM8(modrm);
+ dst = INC8(dst);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_INC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT8 dst = READ8(ea);
+ dst = INC8(dst);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_INC_MEM);
+ }
+ break;
+ case 1: /* DEC Rm8 */
+ if( modrm >= 0xc0 ) {
+ UINT8 dst = LOAD_RM8(modrm);
+ dst = DEC8(dst);
+ STORE_RM8(modrm, dst);
+ CYCLES(CYCLES_DEC_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT8 dst = READ8(ea);
+ dst = DEC8(dst);
+ WRITE8(ea, dst);
+ CYCLES(CYCLES_DEC_MEM);
+ }
+ break;
+ case 6: /* PUSH Rm8 */
+ {
+ UINT8 value;
+ if( modrm >= 0xc0 ) {
+ value = LOAD_RM8(modrm);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ value = READ8(ea);
+ }
+ if( I.operand_size ) {
+ PUSH32(value);
+ } else {
+ PUSH16(value);
+ }
+ CYCLES(CYCLES_PUSH_RM);
+ }
+ break;
+ default:
+ fatalerror("i386: groupFE_8 /%d unimplemented", (modrm >> 3) & 0x7);
+ break;
+ }
+}
+
+
+
+static void I386OP(segment_CS)(void) // Opcode 0x2e
+{
+ I.segment_prefix = 1;
+ I.segment_override = CS;
+
+ I386OP(decode_opcode)();
+}
+
+static void I386OP(segment_DS)(void) // Opcode 0x3e
+{
+ I.segment_prefix = 1;
+ I.segment_override = DS;
+ CYCLES(0); // TODO: Specify cycle count
+ I386OP(decode_opcode)();
+}
+
+static void I386OP(segment_ES)(void) // Opcode 0x26
+{
+ I.segment_prefix = 1;
+ I.segment_override = ES;
+ CYCLES(0); // TODO: Specify cycle count
+ I386OP(decode_opcode)();
+}
+
+static void I386OP(segment_FS)(void) // Opcode 0x64
+{
+ I.segment_prefix = 1;
+ I.segment_override = FS;
+ CYCLES(1); // TODO: Specify cycle count
+ I386OP(decode_opcode)();
+}
+
+static void I386OP(segment_GS)(void) // Opcode 0x65
+{
+ I.segment_prefix = 1;
+ I.segment_override = GS;
+ CYCLES(1); // TODO: Specify cycle count
+ I386OP(decode_opcode)();
+}
+
+static void I386OP(segment_SS)(void) // Opcode 0x36
+{
+ I.segment_prefix = 1;
+ I.segment_override = SS;
+ CYCLES(0); // TODO: Specify cycle count
+ I386OP(decode_opcode)();
+}
+
+static void I386OP(operand_size)(void) // Opcode 0x66
+{
+ I.operand_size ^= 1;
+ I386OP(decode_opcode)();
+}
+
+static void I386OP(address_size)(void) // Opcode 0x67
+{
+ I.address_size ^= 1;
+ I386OP(decode_opcode)();
+}
+
+static void I386OP(nop)(void) // Opcode 0x90
+{
+ CYCLES(CYCLES_NOP);
+}
+
+static void I386OP(int3)(void) // Opcode 0xcc
+{
+ CYCLES(CYCLES_INT3);
+ i386_trap(3, 1);
+}
+
+static void I386OP(int)(void) // Opcode 0xcd
+{
+ int interrupt = FETCH();
+ CYCLES(CYCLES_INT);
+ i386_trap(interrupt, 1);
+}
+
+static void I386OP(into)(void) // Opcode 0xce
+{
+ if( I.OF ) {
+ i386_trap(4, 1);
+ CYCLES(CYCLES_INTO_OF1);
+ }
+ else
+ {
+ CYCLES(CYCLES_INTO_OF0);
+ }
+}
+
+static void I386OP(escape)(void) // Opcodes 0xd8 - 0xdf
+{
+ UINT8 modrm = FETCH();
+ CYCLES(3); // TODO: confirm this
+ (void) LOAD_RM8(modrm);
+}
+
+static void I386OP(hlt)(void) // Opcode 0xf4
+{
+ // TODO: We need to raise an exception in protected mode and when
+ // the current privilege level is not zero
+ I.halted = 1;
+ I.cycles = 0;
+ CYCLES(CYCLES_HLT);
+}
+
+static void I386OP(decimal_adjust)(int direction)
+{
+ UINT8 tmpAL = REG8(AL);
+
+ if (I.AF || ((REG8(AL) & 0xf) > 9))
+ {
+ REG8(AL) = REG8(AL) + (direction * 0x06);
+ I.AF = 1;
+ if (REG8(AL) & 0x100)
+ I.CF = 1;
+ if (direction > 0)
+ tmpAL = REG8(AL);
+ }
+
+ if (I.CF || (tmpAL > 0x9f))
+ {
+ REG8(AL) += (direction * 0x60);
+ I.CF = 1;
+ }
+
+ SetSZPF8(REG8(AL));
+}
+
+static void I386OP(daa)(void) // Opcode 0x27
+{
+ I386OP(decimal_adjust)(+1);
+ CYCLES(CYCLES_DAA);
+}
+
+static void I386OP(das)(void) // Opcode 0x2f
+{
+ I386OP(decimal_adjust)(-1);
+ CYCLES(CYCLES_DAS);
+}
+
+static void I386OP(aaa)(void) // Opcode 0x37
+{
+ if( (REG8(AL) & 0x0f) || I.AF != 0 ) {
+ REG16(AX) = REG16(AX) + 6;
+ REG8(AH) = REG8(AH) + 1;
+ I.AF = 1;
+ I.CF = 1;
+ } else {
+ I.AF = 0;
+ I.CF = 0;
+ }
+ REG8(AL) = REG8(AL) & 0x0f;
+ CYCLES(CYCLES_AAA);
+}
+
+static void I386OP(aas)(void) // Opcode 0x3f
+{
+ if (I.AF || ((REG8(AL) & 0xf) > 9))
+ {
+ REG16(AX) -= 6;
+ REG8(AH) -= 1;
+ I.AF = 1;
+ I.CF = 1;
+ }
+ else
+ {
+ I.AF = 0;
+ I.CF = 0;
+ }
+ REG8(AL) &= 0x0f;
+ CYCLES(CYCLES_AAS);
+}
+
+static void I386OP(aad)(void) // Opcode 0xd5
+{
+ UINT8 tempAL = REG8(AL);
+ UINT8 tempAH = REG8(AH);
+ UINT8 i = FETCH();
+
+ REG8(AL) = (tempAL + (tempAH * i)) & 0xff;
+ REG8(AH) = 0;
+ SetSZPF8( REG8(AL) );
+ CYCLES(CYCLES_AAD);
+}
+
+static void I386OP(aam)(void) // Opcode 0xd4
+{
+ UINT8 tempAL = REG8(AL);
+ UINT8 i = FETCH();
+
+ REG8(AH) = tempAL / i;
+ REG8(AL) = tempAL % i;
+ SetSZPF8( REG8(AL) );
+ CYCLES(CYCLES_AAM);
+}
+
+static void I386OP(clts)(void) // Opcode 0x0f 0x06
+{
+ // TODO: #GP(0) is executed
+ I.cr[0] &= ~0x08; /* clear TS bit */
+ CYCLES(CYCLES_CLTS);
+}
+
+static void I386OP(wait)(void) // Opcode 0x9B
+{
+ // TODO
+}
+
+static void I386OP(lock)(void) // Opcode 0xf0
+{
+ CYCLES(CYCLES_LOCK); // TODO: Determine correct cycle count
+ I386OP(decode_opcode)();
+}
+
+static void I386OP(mov_r32_tr)(void) // Opcode 0x0f 24
+{
+ FETCH();
+ CYCLES(1); // TODO: correct cycle count
+}
+
+static void I386OP(mov_tr_r32)(void) // Opcode 0x0f 26
+{
+ FETCH();
+ CYCLES(1); // TODO: correct cycle count
+}
+
+static void I386OP(unimplemented)(void)
+{
+ fatalerror("i386: Unimplemented opcode %02X at %08X", I.opcode, I.pc - 1 );
+}
+
+static void I386OP(invalid)(void)
+{
+ //i386_trap(6);
+ fatalerror("i386: Invalid opcode %02X at %08X", I.opcode, I.pc - 1);
+}
diff --git a/src/emu/cpu/i386/i386ops.h b/src/emu/cpu/i386/i386ops.h
new file mode 100644
index 00000000000..797d89f6b72
--- /dev/null
+++ b/src/emu/cpu/i386/i386ops.h
@@ -0,0 +1,369 @@
+typedef struct {
+ UINT8 opcode;
+ UINT32 flags;
+ void (*handler16)(void);
+ void (*handler32)(void);
+} X86_OPCODE;
+
+#define OP_I386 0x1
+#define OP_FPU 0x2
+#define OP_I486 0x4
+#define OP_PENTIUM 0x8
+#define OP_MMX 0x10
+#define OP_PPRO 0x20
+#define OP_SSE 0x40
+#define OP_SSE2 0x80
+#define OP_SSE3 0x100
+#define OP_CYRIX 0x8000
+#define OP_2BYTE 0x80000000
+
+static const X86_OPCODE x86_opcode_table[] =
+{
+// Opcode Flags 16-bit handler 32-bit handler
+ { 0x00, OP_I386, I386OP(add_rm8_r8), I386OP(add_rm8_r8), },
+ { 0x01, OP_I386, I386OP(add_rm16_r16), I386OP(add_rm32_r32), },
+ { 0x02, OP_I386, I386OP(add_r8_rm8), I386OP(add_r8_rm8), },
+ { 0x03, OP_I386, I386OP(add_r16_rm16), I386OP(add_r32_rm32), },
+ { 0x04, OP_I386, I386OP(add_al_i8), I386OP(add_al_i8), },
+ { 0x05, OP_I386, I386OP(add_ax_i16), I386OP(add_eax_i32), },
+ { 0x06, OP_I386, I386OP(push_es16), I386OP(push_es32), },
+ { 0x07, OP_I386, I386OP(pop_es16), I386OP(pop_es32), },
+ { 0x08, OP_I386, I386OP(or_rm8_r8), I386OP(or_rm8_r8), },
+ { 0x09, OP_I386, I386OP(or_rm16_r16), I386OP(or_rm32_r32), },
+ { 0x0A, OP_I386, I386OP(or_r8_rm8), I386OP(or_r8_rm8), },
+ { 0x0B, OP_I386, I386OP(or_r16_rm16), I386OP(or_r32_rm32), },
+ { 0x0C, OP_I386, I386OP(or_al_i8), I386OP(or_al_i8), },
+ { 0x0D, OP_I386, I386OP(or_ax_i16), I386OP(or_eax_i32), },
+ { 0x0E, OP_I386, I386OP(push_cs16), I386OP(push_cs32), },
+ { 0x0F, OP_I386, I386OP(decode_two_byte), I386OP(decode_two_byte), },
+ { 0x10, OP_I386, I386OP(adc_rm8_r8), I386OP(adc_rm8_r8), },
+ { 0x11, OP_I386, I386OP(adc_rm16_r16), I386OP(adc_rm32_r32), },
+ { 0x12, OP_I386, I386OP(adc_r8_rm8), I386OP(adc_r8_rm8), },
+ { 0x13, OP_I386, I386OP(adc_r16_rm16), I386OP(adc_r32_rm32), },
+ { 0x14, OP_I386, I386OP(adc_al_i8), I386OP(adc_al_i8), },
+ { 0x15, OP_I386, I386OP(adc_ax_i16), I386OP(adc_eax_i32), },
+ { 0x16, OP_I386, I386OP(push_ss16), I386OP(push_ss32), },
+ { 0x17, OP_I386, I386OP(pop_ss16), I386OP(pop_ss32), },
+ { 0x18, OP_I386, I386OP(sbb_rm8_r8), I386OP(sbb_rm8_r8), },
+ { 0x19, OP_I386, I386OP(sbb_rm16_r16), I386OP(sbb_rm32_r32), },
+ { 0x1A, OP_I386, I386OP(sbb_r8_rm8), I386OP(sbb_r8_rm8), },
+ { 0x1B, OP_I386, I386OP(sbb_r16_rm16), I386OP(sbb_r32_rm32), },
+ { 0x1C, OP_I386, I386OP(sbb_al_i8), I386OP(sbb_al_i8), },
+ { 0x1D, OP_I386, I386OP(sbb_ax_i16), I386OP(sbb_eax_i32), },
+ { 0x1E, OP_I386, I386OP(push_ds16), I386OP(push_ds32), },
+ { 0x1F, OP_I386, I386OP(pop_ds16), I386OP(pop_ds32), },
+ { 0x20, OP_I386, I386OP(and_rm8_r8), I386OP(and_rm8_r8), },
+ { 0x21, OP_I386, I386OP(and_rm16_r16), I386OP(and_rm32_r32), },
+ { 0x22, OP_I386, I386OP(and_r8_rm8), I386OP(and_r8_rm8), },
+ { 0x23, OP_I386, I386OP(and_r16_rm16), I386OP(and_r32_rm32), },
+ { 0x24, OP_I386, I386OP(and_al_i8), I386OP(and_al_i8), },
+ { 0x25, OP_I386, I386OP(and_ax_i16), I386OP(and_eax_i32), },
+ { 0x26, OP_I386, I386OP(segment_ES), I386OP(segment_ES), },
+ { 0x27, OP_I386, I386OP(daa), I386OP(daa), },
+ { 0x28, OP_I386, I386OP(sub_rm8_r8), I386OP(sub_rm8_r8), },
+ { 0x29, OP_I386, I386OP(sub_rm16_r16), I386OP(sub_rm32_r32), },
+ { 0x2A, OP_I386, I386OP(sub_r8_rm8), I386OP(sub_r8_rm8), },
+ { 0x2B, OP_I386, I386OP(sub_r16_rm16), I386OP(sub_r32_rm32), },
+ { 0x2C, OP_I386, I386OP(sub_al_i8), I386OP(sub_al_i8), },
+ { 0x2D, OP_I386, I386OP(sub_ax_i16), I386OP(sub_eax_i32), },
+ { 0x2E, OP_I386, I386OP(segment_CS), I386OP(segment_CS), },
+ { 0x2F, OP_I386, I386OP(das), I386OP(das), },
+ { 0x30, OP_I386, I386OP(xor_rm8_r8), I386OP(xor_rm8_r8), },
+ { 0x31, OP_I386, I386OP(xor_rm16_r16), I386OP(xor_rm32_r32), },
+ { 0x32, OP_I386, I386OP(xor_r8_rm8), I386OP(xor_r8_rm8), },
+ { 0x33, OP_I386, I386OP(xor_r16_rm16), I386OP(xor_r32_rm32), },
+ { 0x34, OP_I386, I386OP(xor_al_i8), I386OP(xor_al_i8), },
+ { 0x35, OP_I386, I386OP(xor_ax_i16), I386OP(xor_eax_i32), },
+ { 0x36, OP_I386, I386OP(segment_SS), I386OP(segment_SS), },
+ { 0x37, OP_I386, I386OP(aaa), I386OP(aaa), },
+ { 0x38, OP_I386, I386OP(cmp_rm8_r8), I386OP(cmp_rm8_r8), },
+ { 0x39, OP_I386, I386OP(cmp_rm16_r16), I386OP(cmp_rm32_r32), },
+ { 0x3A, OP_I386, I386OP(cmp_r8_rm8), I386OP(cmp_r8_rm8), },
+ { 0x3B, OP_I386, I386OP(cmp_r16_rm16), I386OP(cmp_r32_rm32), },
+ { 0x3C, OP_I386, I386OP(cmp_al_i8), I386OP(cmp_al_i8), },
+ { 0x3D, OP_I386, I386OP(cmp_ax_i16), I386OP(cmp_eax_i32), },
+ { 0x3E, OP_I386, I386OP(segment_DS), I386OP(segment_DS), },
+ { 0x3F, OP_I386, I386OP(aas), I386OP(aas), },
+ { 0x40, OP_I386, I386OP(inc_ax), I386OP(inc_eax), },
+ { 0x41, OP_I386, I386OP(inc_cx), I386OP(inc_ecx), },
+ { 0x42, OP_I386, I386OP(inc_dx), I386OP(inc_edx), },
+ { 0x43, OP_I386, I386OP(inc_bx), I386OP(inc_ebx), },
+ { 0x44, OP_I386, I386OP(inc_sp), I386OP(inc_esp), },
+ { 0x45, OP_I386, I386OP(inc_bp), I386OP(inc_ebp), },
+ { 0x46, OP_I386, I386OP(inc_si), I386OP(inc_esi), },
+ { 0x47, OP_I386, I386OP(inc_di), I386OP(inc_edi), },
+ { 0x48, OP_I386, I386OP(dec_ax), I386OP(dec_eax), },
+ { 0x49, OP_I386, I386OP(dec_cx), I386OP(dec_ecx), },
+ { 0x4A, OP_I386, I386OP(dec_dx), I386OP(dec_edx), },
+ { 0x4B, OP_I386, I386OP(dec_bx), I386OP(dec_ebx), },
+ { 0x4C, OP_I386, I386OP(dec_sp), I386OP(dec_esp), },
+ { 0x4D, OP_I386, I386OP(dec_bp), I386OP(dec_ebp), },
+ { 0x4E, OP_I386, I386OP(dec_si), I386OP(dec_esi), },
+ { 0x4F, OP_I386, I386OP(dec_di), I386OP(dec_edi), },
+ { 0x50, OP_I386, I386OP(push_ax), I386OP(push_eax), },
+ { 0x51, OP_I386, I386OP(push_cx), I386OP(push_ecx), },
+ { 0x52, OP_I386, I386OP(push_dx), I386OP(push_edx), },
+ { 0x53, OP_I386, I386OP(push_bx), I386OP(push_ebx), },
+ { 0x54, OP_I386, I386OP(push_sp), I386OP(push_esp), },
+ { 0x55, OP_I386, I386OP(push_bp), I386OP(push_ebp), },
+ { 0x56, OP_I386, I386OP(push_si), I386OP(push_esi), },
+ { 0x57, OP_I386, I386OP(push_di), I386OP(push_edi), },
+ { 0x58, OP_I386, I386OP(pop_ax), I386OP(pop_eax), },
+ { 0x59, OP_I386, I386OP(pop_cx), I386OP(pop_ecx), },
+ { 0x5A, OP_I386, I386OP(pop_dx), I386OP(pop_edx), },
+ { 0x5B, OP_I386, I386OP(pop_bx), I386OP(pop_ebx), },
+ { 0x5C, OP_I386, I386OP(pop_sp), I386OP(pop_esp), },
+ { 0x5D, OP_I386, I386OP(pop_bp), I386OP(pop_ebp), },
+ { 0x5E, OP_I386, I386OP(pop_si), I386OP(pop_esi), },
+ { 0x5F, OP_I386, I386OP(pop_di), I386OP(pop_edi), },
+ { 0x60, OP_I386, I386OP(pusha), I386OP(pushad), },
+ { 0x61, OP_I386, I386OP(popa), I386OP(popad), },
+ { 0x62, OP_I386, I386OP(bound_r16_m16_m16), I386OP(bound_r32_m32_m32), },
+ { 0x63, OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
+ { 0x64, OP_I386, I386OP(segment_FS), I386OP(segment_FS), },
+ { 0x65, OP_I386, I386OP(segment_GS), I386OP(segment_GS), },
+ { 0x66, OP_I386, I386OP(operand_size), I386OP(operand_size), },
+ { 0x67, OP_I386, I386OP(address_size), I386OP(address_size), },
+ { 0x68, OP_I386, I386OP(push_i16), I386OP(push_i32), },
+ { 0x69, OP_I386, I386OP(imul_r16_rm16_i16), I386OP(imul_r32_rm32_i32), },
+ { 0x6A, OP_I386, I386OP(push_i8), I386OP(push_i8), },
+ { 0x6B, OP_I386, I386OP(imul_r16_rm16_i8), I386OP(imul_r32_rm32_i8), },
+ { 0x6C, OP_I386, I386OP(insb), I386OP(insb), },
+ { 0x6D, OP_I386, I386OP(insw), I386OP(insd), },
+ { 0x6E, OP_I386, I386OP(outsb), I386OP(outsb), },
+ { 0x6F, OP_I386, I386OP(outsw), I386OP(outsd), },
+ { 0x70, OP_I386, I386OP(jo_rel8), I386OP(jo_rel8), },
+ { 0x71, OP_I386, I386OP(jno_rel8), I386OP(jno_rel8), },
+ { 0x72, OP_I386, I386OP(jc_rel8), I386OP(jc_rel8), },
+ { 0x73, OP_I386, I386OP(jnc_rel8), I386OP(jnc_rel8), },
+ { 0x74, OP_I386, I386OP(jz_rel8), I386OP(jz_rel8), },
+ { 0x75, OP_I386, I386OP(jnz_rel8), I386OP(jnz_rel8), },
+ { 0x76, OP_I386, I386OP(jbe_rel8), I386OP(jbe_rel8), },
+ { 0x77, OP_I386, I386OP(ja_rel8), I386OP(ja_rel8), },
+ { 0x78, OP_I386, I386OP(js_rel8), I386OP(js_rel8), },
+ { 0x79, OP_I386, I386OP(jns_rel8), I386OP(jns_rel8), },
+ { 0x7A, OP_I386, I386OP(jp_rel8), I386OP(jp_rel8), },
+ { 0x7B, OP_I386, I386OP(jnp_rel8), I386OP(jnp_rel8), },
+ { 0x7C, OP_I386, I386OP(jl_rel8), I386OP(jl_rel8), },
+ { 0x7D, OP_I386, I386OP(jge_rel8), I386OP(jge_rel8), },
+ { 0x7E, OP_I386, I386OP(jle_rel8), I386OP(jle_rel8), },
+ { 0x7F, OP_I386, I386OP(jg_rel8), I386OP(jg_rel8), },
+ { 0x80, OP_I386, I386OP(group80_8), I386OP(group80_8), },
+ { 0x81, OP_I386, I386OP(group81_16), I386OP(group81_32), },
+ { 0x82, OP_I386, I386OP(group80_8), I386OP(group80_8), },
+ { 0x83, OP_I386, I386OP(group83_16), I386OP(group83_32), },
+ { 0x84, OP_I386, I386OP(test_rm8_r8), I386OP(test_rm8_r8), },
+ { 0x85, OP_I386, I386OP(test_rm16_r16), I386OP(test_rm32_r32), },
+ { 0x86, OP_I386, I386OP(xchg_r8_rm8), I386OP(xchg_r8_rm8), },
+ { 0x87, OP_I386, I386OP(xchg_r16_rm16), I386OP(xchg_r32_rm32), },
+ { 0x88, OP_I386, I386OP(mov_rm8_r8), I386OP(mov_rm8_r8), },
+ { 0x89, OP_I386, I386OP(mov_rm16_r16), I386OP(mov_rm32_r32), },
+ { 0x8A, OP_I386, I386OP(mov_r8_rm8), I386OP(mov_r8_rm8), },
+ { 0x8B, OP_I386, I386OP(mov_r16_rm16), I386OP(mov_r32_rm32), },
+ { 0x8C, OP_I386, I386OP(mov_rm16_sreg), I386OP(mov_rm16_sreg), },
+ { 0x8D, OP_I386, I386OP(lea16), I386OP(lea32), },
+ { 0x8E, OP_I386, I386OP(mov_sreg_rm16), I386OP(mov_sreg_rm16), },
+ { 0x8F, OP_I386, I386OP(pop_rm16), I386OP(pop_rm32), },
+ { 0x90, OP_I386, I386OP(nop), I386OP(nop), },
+ { 0x91, OP_I386, I386OP(xchg_ax_cx), I386OP(xchg_eax_ecx), },
+ { 0x92, OP_I386, I386OP(xchg_ax_dx), I386OP(xchg_eax_edx), },
+ { 0x93, OP_I386, I386OP(xchg_ax_bx), I386OP(xchg_eax_ebx), },
+ { 0x94, OP_I386, I386OP(xchg_ax_sp), I386OP(xchg_eax_esp), },
+ { 0x95, OP_I386, I386OP(xchg_ax_bp), I386OP(xchg_eax_ebp), },
+ { 0x96, OP_I386, I386OP(xchg_ax_si), I386OP(xchg_eax_esi), },
+ { 0x97, OP_I386, I386OP(xchg_ax_di), I386OP(xchg_eax_edi), },
+ { 0x98, OP_I386, I386OP(cbw), I386OP(cwde), },
+ { 0x99, OP_I386, I386OP(cwd), I386OP(cdq), },
+ { 0x9A, OP_I386, I386OP(call_abs16), I386OP(call_abs32), },
+ { 0x9B, OP_I386, I386OP(wait), I386OP(wait), },
+ { 0x9C, OP_I386, I386OP(pushf), I386OP(pushfd), },
+ { 0x9D, OP_I386, I386OP(popf), I386OP(popfd), },
+ { 0x9E, OP_I386, I386OP(sahf), I386OP(sahf), },
+ { 0x9F, OP_I386, I386OP(lahf), I386OP(lahf), },
+ { 0xA0, OP_I386, I386OP(mov_al_m8), I386OP(mov_al_m8), },
+ { 0xA1, OP_I386, I386OP(mov_ax_m16), I386OP(mov_eax_m32), },
+ { 0xA2, OP_I386, I386OP(mov_m8_al), I386OP(mov_m8_al), },
+ { 0xA3, OP_I386, I386OP(mov_m16_ax), I386OP(mov_m32_eax), },
+ { 0xA4, OP_I386, I386OP(movsb), I386OP(movsb), },
+ { 0xA5, OP_I386, I386OP(movsw), I386OP(movsd), },
+ { 0xA6, OP_I386, I386OP(cmpsb), I386OP(cmpsb), },
+ { 0xA7, OP_I386, I386OP(cmpsw), I386OP(cmpsd), },
+ { 0xA8, OP_I386, I386OP(test_al_i8), I386OP(test_al_i8), },
+ { 0xA9, OP_I386, I386OP(test_ax_i16), I386OP(test_eax_i32), },
+ { 0xAA, OP_I386, I386OP(stosb), I386OP(stosb), },
+ { 0xAB, OP_I386, I386OP(stosw), I386OP(stosd), },
+ { 0xAC, OP_I386, I386OP(lodsb), I386OP(lodsb), },
+ { 0xAD, OP_I386, I386OP(lodsw), I386OP(lodsd), },
+ { 0xAE, OP_I386, I386OP(scasb), I386OP(scasb), },
+ { 0xAF, OP_I386, I386OP(scasw), I386OP(scasd), },
+ { 0xB0, OP_I386, I386OP(mov_al_i8), I386OP(mov_al_i8), },
+ { 0xB1, OP_I386, I386OP(mov_cl_i8), I386OP(mov_cl_i8), },
+ { 0xB2, OP_I386, I386OP(mov_dl_i8), I386OP(mov_dl_i8), },
+ { 0xB3, OP_I386, I386OP(mov_bl_i8), I386OP(mov_bl_i8), },
+ { 0xB4, OP_I386, I386OP(mov_ah_i8), I386OP(mov_ah_i8), },
+ { 0xB5, OP_I386, I386OP(mov_ch_i8), I386OP(mov_ch_i8), },
+ { 0xB6, OP_I386, I386OP(mov_dh_i8), I386OP(mov_dh_i8), },
+ { 0xB7, OP_I386, I386OP(mov_bh_i8), I386OP(mov_bh_i8), },
+ { 0xB8, OP_I386, I386OP(mov_ax_i16), I386OP(mov_eax_i32), },
+ { 0xB9, OP_I386, I386OP(mov_cx_i16), I386OP(mov_ecx_i32), },
+ { 0xBA, OP_I386, I386OP(mov_dx_i16), I386OP(mov_edx_i32), },
+ { 0xBB, OP_I386, I386OP(mov_bx_i16), I386OP(mov_ebx_i32), },
+ { 0xBC, OP_I386, I386OP(mov_sp_i16), I386OP(mov_esp_i32), },
+ { 0xBD, OP_I386, I386OP(mov_bp_i16), I386OP(mov_ebp_i32), },
+ { 0xBE, OP_I386, I386OP(mov_si_i16), I386OP(mov_esi_i32), },
+ { 0xBF, OP_I386, I386OP(mov_di_i16), I386OP(mov_edi_i32), },
+ { 0xC0, OP_I386, I386OP(groupC0_8), I386OP(groupC0_8), },
+ { 0xC1, OP_I386, I386OP(groupC1_16), I386OP(groupC1_32), },
+ { 0xC2, OP_I386, I386OP(ret_near16_i16), I386OP(ret_near32_i16), },
+ { 0xC3, OP_I386, I386OP(ret_near16), I386OP(ret_near32), },
+ { 0xC4, OP_I386, I386OP(les16), I386OP(les32), },
+ { 0xC5, OP_I386, I386OP(lds16), I386OP(lds32), },
+ { 0xC6, OP_I386, I386OP(mov_rm8_i8), I386OP(mov_rm8_i8), },
+ { 0xC7, OP_I386, I386OP(mov_rm16_i16), I386OP(mov_rm32_i32), },
+ { 0xC8, OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
+ { 0xC9, OP_I386, I386OP(leave16), I386OP(leave32), },
+ { 0xCA, OP_I386, I386OP(retf_i16), I386OP(retf_i32), },
+ { 0xCB, OP_I386, I386OP(retf16), I386OP(retf32), },
+ { 0xCC, OP_I386, I386OP(int3), I386OP(int3), },
+ { 0xCD, OP_I386, I386OP(int), I386OP(int), },
+ { 0xCE, OP_I386, I386OP(into), I386OP(into), },
+ { 0xCF, OP_I386, I386OP(iret16), I386OP(iret32), },
+ { 0xD0, OP_I386, I386OP(groupD0_8), I386OP(groupD0_8), },
+ { 0xD1, OP_I386, I386OP(groupD1_16), I386OP(groupD1_32), },
+ { 0xD2, OP_I386, I386OP(groupD2_8), I386OP(groupD2_8), },
+ { 0xD3, OP_I386, I386OP(groupD3_16), I386OP(groupD3_32), },
+ { 0xD4, OP_I386, I386OP(aam), I386OP(aam), },
+ { 0xD5, OP_I386, I386OP(aad), I386OP(aad), },
+ { 0xD6, OP_I386, I386OP(setalc), I386OP(setalc), },
+ { 0xD7, OP_I386, I386OP(xlat16), I386OP(xlat32), },
+ { 0xD8, OP_I386, I386OP(escape), I386OP(escape), },
+ { 0xD9, OP_I386, I386OP(escape), I386OP(escape), },
+ { 0xDA, OP_I386, I386OP(escape), I386OP(escape), },
+ { 0xDB, OP_I386, I386OP(escape), I386OP(escape), },
+ { 0xDC, OP_I386, I386OP(escape), I386OP(escape), },
+ { 0xDD, OP_I386, I386OP(escape), I386OP(escape), },
+ { 0xDE, OP_I386, I386OP(escape), I386OP(escape), },
+ { 0xDF, OP_I386, I386OP(escape), I386OP(escape), },
+ { 0xD8, OP_FPU, I386OP(fpu_group_d8), I386OP(fpu_group_d8), },
+ { 0xD9, OP_FPU, I386OP(fpu_group_d9), I386OP(fpu_group_d9), },
+ { 0xDA, OP_FPU, I386OP(fpu_group_da), I386OP(fpu_group_da), },
+ { 0xDB, OP_FPU, I386OP(fpu_group_db), I386OP(fpu_group_db), },
+ { 0xDC, OP_FPU, I386OP(fpu_group_dc), I386OP(fpu_group_dc), },
+ { 0xDD, OP_FPU, I386OP(fpu_group_dd), I386OP(fpu_group_dd), },
+ { 0xDE, OP_FPU, I386OP(fpu_group_de), I386OP(fpu_group_de), },
+ { 0xDF, OP_FPU, I386OP(fpu_group_df), I386OP(fpu_group_df), },
+ { 0xE0, OP_I386, I386OP(loopne16), I386OP(loopne32), },
+ { 0xE1, OP_I386, I386OP(loopz16), I386OP(loopz32), },
+ { 0xE2, OP_I386, I386OP(loop16), I386OP(loop32), },
+ { 0xE3, OP_I386, I386OP(jcxz16), I386OP(jcxz32), },
+ { 0xE4, OP_I386, I386OP(in_al_i8), I386OP(in_al_i8), },
+ { 0xE5, OP_I386, I386OP(in_ax_i8), I386OP(in_eax_i8), },
+ { 0xE6, OP_I386, I386OP(out_al_i8), I386OP(out_al_i8), },
+ { 0xE7, OP_I386, I386OP(out_ax_i8), I386OP(out_eax_i8), },
+ { 0xE8, OP_I386, I386OP(call_rel16), I386OP(call_rel32), },
+ { 0xE9, OP_I386, I386OP(jmp_rel16), I386OP(jmp_rel32), },
+ { 0xEA, OP_I386, I386OP(jmp_abs16), I386OP(jmp_abs32), },
+ { 0xEB, OP_I386, I386OP(jmp_rel8), I386OP(jmp_rel8), },
+ { 0xEC, OP_I386, I386OP(in_al_dx), I386OP(in_al_dx), },
+ { 0xED, OP_I386, I386OP(in_ax_dx), I386OP(in_eax_dx), },
+ { 0xEE, OP_I386, I386OP(out_al_dx), I386OP(out_al_dx), },
+ { 0xEF, OP_I386, I386OP(out_ax_dx), I386OP(out_eax_dx), },
+ { 0xF0, OP_I386, I386OP(lock), I386OP(lock), },
+ { 0xF1, OP_I386, I386OP(invalid), I386OP(invalid), },
+ { 0xF2, OP_I386, I386OP(repne), I386OP(repne), },
+ { 0xF3, OP_I386, I386OP(rep), I386OP(rep), },
+ { 0xF4, OP_I386, I386OP(hlt), I386OP(hlt), },
+ { 0xF5, OP_I386, I386OP(cmc), I386OP(cmc), },
+ { 0xF6, OP_I386, I386OP(groupF6_8), I386OP(groupF6_8), },
+ { 0xF7, OP_I386, I386OP(groupF7_16), I386OP(groupF7_32), },
+ { 0xF8, OP_I386, I386OP(clc), I386OP(clc), },
+ { 0xF9, OP_I386, I386OP(stc), I386OP(stc), },
+ { 0xFA, OP_I386, I386OP(cli), I386OP(cli), },
+ { 0xFB, OP_I386, I386OP(sti), I386OP(sti), },
+ { 0xFC, OP_I386, I386OP(cld), I386OP(cld), },
+ { 0xFD, OP_I386, I386OP(std), I386OP(std), },
+ { 0xFE, OP_I386, I386OP(groupFE_8), I386OP(groupFE_8), },
+ { 0xFF, OP_I386, I386OP(groupFF_16), I386OP(groupFF_32), },
+ { 0x00, OP_2BYTE|OP_I386, I386OP(group0F00_16), I386OP(group0F00_32), },
+ { 0x01, OP_2BYTE|OP_I386, I386OP(group0F01_16), I386OP(group0F01_32), },
+ { 0x01, OP_2BYTE|OP_I486, I486OP(group0F01_16), I486OP(group0F01_32), },
+ { 0x02, OP_2BYTE|OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
+ { 0x03, OP_2BYTE|OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
+ { 0x06, OP_2BYTE|OP_I386, I386OP(clts), I386OP(clts), },
+ { 0x08, OP_2BYTE|OP_I486, I486OP(invd), I486OP(invd), },
+ { 0x09, OP_2BYTE|OP_I486, I486OP(wbinvd), I486OP(wbinvd), },
+ { 0x0B, OP_2BYTE|OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
+ { 0x20, OP_2BYTE|OP_I386, I386OP(mov_r32_cr), I386OP(mov_r32_cr), },
+ { 0x21, OP_2BYTE|OP_I386, I386OP(mov_r32_dr), I386OP(mov_r32_dr), },
+ { 0x22, OP_2BYTE|OP_I386, I386OP(mov_cr_r32), I386OP(mov_cr_r32), },
+ { 0x23, OP_2BYTE|OP_I386, I386OP(mov_dr_r32), I386OP(mov_dr_r32), },
+ { 0x24, OP_2BYTE|OP_I386, I386OP(mov_r32_tr), I386OP(mov_r32_tr), },
+ { 0x26, OP_2BYTE|OP_I386, I386OP(mov_tr_r32), I386OP(mov_tr_r32), },
+ { 0x30, OP_2BYTE|OP_PENTIUM, PENTIUMOP(wrmsr), PENTIUMOP(wrmsr), },
+ { 0x31, OP_2BYTE|OP_PENTIUM, PENTIUMOP(rdtsc), PENTIUMOP(rdtsc), },
+ { 0x32, OP_2BYTE|OP_PENTIUM, PENTIUMOP(rdmsr), PENTIUMOP(rdmsr), },
+ { 0x74, OP_2BYTE|OP_CYRIX, I386OP(cyrix_unknown), I386OP(cyrix_unknown), },
+ { 0x80, OP_2BYTE|OP_I386, I386OP(jo_rel16), I386OP(jo_rel32), },
+ { 0x81, OP_2BYTE|OP_I386, I386OP(jno_rel16), I386OP(jno_rel32), },
+ { 0x82, OP_2BYTE|OP_I386, I386OP(jc_rel16), I386OP(jc_rel32), },
+ { 0x83, OP_2BYTE|OP_I386, I386OP(jnc_rel16), I386OP(jnc_rel32), },
+ { 0x84, OP_2BYTE|OP_I386, I386OP(jz_rel16), I386OP(jz_rel32), },
+ { 0x85, OP_2BYTE|OP_I386, I386OP(jnz_rel16), I386OP(jnz_rel32), },
+ { 0x86, OP_2BYTE|OP_I386, I386OP(jbe_rel16), I386OP(jbe_rel32), },
+ { 0x87, OP_2BYTE|OP_I386, I386OP(ja_rel16), I386OP(ja_rel32), },
+ { 0x88, OP_2BYTE|OP_I386, I386OP(js_rel16), I386OP(js_rel32), },
+ { 0x89, OP_2BYTE|OP_I386, I386OP(jns_rel16), I386OP(jns_rel32), },
+ { 0x8A, OP_2BYTE|OP_I386, I386OP(jp_rel16), I386OP(jp_rel32), },
+ { 0x8B, OP_2BYTE|OP_I386, I386OP(jnp_rel16), I386OP(jnp_rel32), },
+ { 0x8C, OP_2BYTE|OP_I386, I386OP(jl_rel16), I386OP(jl_rel32), },
+ { 0x8D, OP_2BYTE|OP_I386, I386OP(jge_rel16), I386OP(jge_rel32), },
+ { 0x8E, OP_2BYTE|OP_I386, I386OP(jle_rel16), I386OP(jle_rel32), },
+ { 0x8F, OP_2BYTE|OP_I386, I386OP(jg_rel16), I386OP(jg_rel32), },
+ { 0x90, OP_2BYTE|OP_I386, I386OP(seto_rm8), I386OP(seto_rm8), },
+ { 0x91, OP_2BYTE|OP_I386, I386OP(setno_rm8), I386OP(setno_rm8), },
+ { 0x92, OP_2BYTE|OP_I386, I386OP(setc_rm8), I386OP(setc_rm8), },
+ { 0x93, OP_2BYTE|OP_I386, I386OP(setnc_rm8), I386OP(setnc_rm8), },
+ { 0x94, OP_2BYTE|OP_I386, I386OP(setz_rm8), I386OP(setz_rm8), },
+ { 0x95, OP_2BYTE|OP_I386, I386OP(setnz_rm8), I386OP(setnz_rm8), },
+ { 0x96, OP_2BYTE|OP_I386, I386OP(setbe_rm8), I386OP(setbe_rm8), },
+ { 0x97, OP_2BYTE|OP_I386, I386OP(seta_rm8), I386OP(seta_rm8), },
+ { 0x98, OP_2BYTE|OP_I386, I386OP(sets_rm8), I386OP(sets_rm8), },
+ { 0x99, OP_2BYTE|OP_I386, I386OP(setns_rm8), I386OP(setns_rm8), },
+ { 0x9A, OP_2BYTE|OP_I386, I386OP(setp_rm8), I386OP(setp_rm8), },
+ { 0x9B, OP_2BYTE|OP_I386, I386OP(setnp_rm8), I386OP(setnp_rm8), },
+ { 0x9C, OP_2BYTE|OP_I386, I386OP(setl_rm8), I386OP(setl_rm8), },
+ { 0x9D, OP_2BYTE|OP_I386, I386OP(setge_rm8), I386OP(setge_rm8), },
+ { 0x9E, OP_2BYTE|OP_I386, I386OP(setle_rm8), I386OP(setle_rm8), },
+ { 0x9F, OP_2BYTE|OP_I386, I386OP(setg_rm8), I386OP(setg_rm8), },
+ { 0xA0, OP_2BYTE|OP_I386, I386OP(push_fs16), I386OP(push_fs32), },
+ { 0xA1, OP_2BYTE|OP_I386, I386OP(pop_fs16), I386OP(pop_fs32), },
+ { 0xA2, OP_2BYTE|OP_I486, I486OP(cpuid), I486OP(cpuid), },
+ { 0xA3, OP_2BYTE|OP_I386, I386OP(bt_rm16_r16), I386OP(bt_rm32_r32), },
+ { 0xA4, OP_2BYTE|OP_I386, I386OP(shld16_i8), I386OP(shld32_i8), },
+ { 0xA5, OP_2BYTE|OP_I386, I386OP(shld16_cl), I386OP(shld32_cl), },
+ { 0xA8, OP_2BYTE|OP_I386, I386OP(push_gs16), I386OP(push_gs32), },
+ { 0xA9, OP_2BYTE|OP_I386, I386OP(pop_gs16), I386OP(pop_gs32), },
+ { 0xAA, OP_2BYTE|OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
+ { 0xAB, OP_2BYTE|OP_I386, I386OP(bts_rm16_r16), I386OP(bts_rm32_r32), },
+ { 0xAC, OP_2BYTE|OP_I386, I386OP(shrd16_i8), I386OP(shrd32_i8), },
+ { 0xAD, OP_2BYTE|OP_I386, I386OP(shrd16_cl), I386OP(shrd32_cl), },
+ { 0xAE, OP_2BYTE|OP_I386, I386OP(invalid), I386OP(invalid), },
+ { 0xAF, OP_2BYTE|OP_I386, I386OP(imul_r16_rm16), I386OP(imul_r32_rm32), },
+ { 0xB0, OP_2BYTE|OP_I486, I486OP(cmpxchg_rm8_r8), I486OP(cmpxchg_rm8_r8), },
+ { 0xB1, OP_2BYTE|OP_I486, I486OP(cmpxchg_rm16_r16), I486OP(cmpxchg_rm32_r32), },
+ { 0xB2, OP_2BYTE|OP_I386, I386OP(lss16), I386OP(lss32), },
+ { 0xB3, OP_2BYTE|OP_I386, I386OP(btr_rm16_r16), I386OP(btr_rm32_r32), },
+ { 0xB4, OP_2BYTE|OP_I386, I386OP(lfs16), I386OP(lfs32), },
+ { 0xB5, OP_2BYTE|OP_I386, I386OP(lgs16), I386OP(lgs32), },
+ { 0xB6, OP_2BYTE|OP_I386, I386OP(movzx_r16_rm8), I386OP(movzx_r32_rm8), },
+ { 0xB7, OP_2BYTE|OP_I386, I386OP(invalid), I386OP(movzx_r32_rm16), },
+ { 0xBA, OP_2BYTE|OP_I386, I386OP(group0FBA_16), I386OP(group0FBA_32), },
+ { 0xBB, OP_2BYTE|OP_I386, I386OP(btc_rm16_r16), I386OP(btc_rm32_r32), },
+ { 0xBC, OP_2BYTE|OP_I386, I386OP(bsf_r16_rm16), I386OP(bsf_r32_rm32), },
+ { 0xBD, OP_2BYTE|OP_I386, I386OP(bsr_r16_rm16), I386OP(bsr_r32_rm32), },
+ { 0xBE, OP_2BYTE|OP_I386, I386OP(movsx_r16_rm8), I386OP(movsx_r32_rm8), },
+ { 0xBF, OP_2BYTE|OP_I386, I386OP(invalid), I386OP(movsx_r32_rm16), },
+ { 0xC0, OP_2BYTE|OP_I486, I486OP(xadd_rm8_r8), I486OP(xadd_rm8_r8), },
+ { 0xC1, OP_2BYTE|OP_I486, I486OP(xadd_rm16_r16), I486OP(xadd_rm32_r32), },
+ { 0xC7, OP_2BYTE|OP_PENTIUM, PENTIUMOP(cmpxchg8b_m64), PENTIUMOP(cmpxchg8b_m64), }
+};
diff --git a/src/emu/cpu/i386/i486ops.c b/src/emu/cpu/i386/i486ops.c
new file mode 100644
index 00000000000..f14d6a6feab
--- /dev/null
+++ b/src/emu/cpu/i386/i486ops.c
@@ -0,0 +1,368 @@
+// Intel 486+ specific opcodes
+
+static void I486OP(cpuid)(void) // Opcode 0x0F A2
+{
+ switch (REG32(EAX))
+ {
+ case 0:
+ {
+ REG32(EAX) = I.cpuid_max_input_value_eax;
+ REG32(EBX) = I.cpuid_id0;
+ REG32(ECX) = I.cpuid_id2;
+ REG32(EDX) = I.cpuid_id1;
+ CYCLES(CYCLES_CPUID);
+ break;
+ }
+
+ case 1:
+ {
+ REG32(EAX) = I.cpu_version;
+ REG32(EDX) = I.feature_flags;
+ CYCLES(CYCLES_CPUID_EAX1);
+ break;
+ }
+ }
+}
+
+static void I486OP(invd)(void) // Opcode 0x0f 08
+{
+ // Nothing to do ?
+ CYCLES(CYCLES_INVD);
+}
+
+static void I486OP(wbinvd)(void) // Opcode 0x0f 09
+{
+ // Nothing to do ?
+}
+
+static void I486OP(cmpxchg_rm8_r8)(void) // Opcode 0x0f b0
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT8 dst = LOAD_RM8(modrm);
+ UINT8 src = LOAD_REG8(modrm);
+
+ if( REG8(AL) == dst ) {
+ STORE_RM8(modrm, src);
+ I.ZF = 1;
+ CYCLES(CYCLES_CMPXCHG_REG_REG_T);
+ } else {
+ REG8(AL) = dst;
+ I.ZF = 0;
+ CYCLES(CYCLES_CMPXCHG_REG_REG_F);
+ }
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT8 dst = READ8(ea);
+ UINT8 src = LOAD_REG8(modrm);
+
+ if( REG8(AL) == dst ) {
+ WRITE8(modrm, src);
+ I.ZF = 1;
+ CYCLES(CYCLES_CMPXCHG_REG_MEM_T);
+ } else {
+ REG8(AL) = dst;
+ I.ZF = 0;
+ CYCLES(CYCLES_CMPXCHG_REG_MEM_F);
+ }
+ }
+}
+
+static void I486OP(cmpxchg_rm16_r16)(void) // Opcode 0x0f b1
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 src = LOAD_REG16(modrm);
+
+ if( REG16(AX) == dst ) {
+ STORE_RM16(modrm, src);
+ I.ZF = 1;
+ CYCLES(CYCLES_CMPXCHG_REG_REG_T);
+ } else {
+ REG16(AX) = dst;
+ I.ZF = 0;
+ CYCLES(CYCLES_CMPXCHG_REG_REG_F);
+ }
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 src = LOAD_REG16(modrm);
+
+ if( REG16(AX) == dst ) {
+ WRITE16(modrm, src);
+ I.ZF = 1;
+ CYCLES(CYCLES_CMPXCHG_REG_MEM_T);
+ } else {
+ REG16(AX) = dst;
+ I.ZF = 0;
+ CYCLES(CYCLES_CMPXCHG_REG_MEM_F);
+ }
+ }
+}
+
+static void I486OP(cmpxchg_rm32_r32)(void) // Opcode 0x0f b1
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 src = LOAD_REG32(modrm);
+
+ if( REG32(EAX) == dst ) {
+ STORE_RM32(modrm, src);
+ I.ZF = 1;
+ CYCLES(CYCLES_CMPXCHG_REG_REG_T);
+ } else {
+ REG32(EAX) = dst;
+ I.ZF = 0;
+ CYCLES(CYCLES_CMPXCHG_REG_REG_F);
+ }
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 src = LOAD_REG32(modrm);
+
+ if( REG32(EAX) == dst ) {
+ WRITE32(ea, src);
+ I.ZF = 1;
+ CYCLES(CYCLES_CMPXCHG_REG_MEM_T);
+ } else {
+ REG32(EAX) = dst;
+ I.ZF = 0;
+ CYCLES(CYCLES_CMPXCHG_REG_MEM_F);
+ }
+ }
+}
+
+static void I486OP(xadd_rm8_r8)(void) // Opcode 0x0f c0
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT8 dst = LOAD_RM8(modrm);
+ UINT8 src = LOAD_REG8(modrm);
+ STORE_RM16(modrm, dst + src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_XADD_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT8 dst = READ8(ea);
+ UINT8 src = LOAD_REG8(modrm);
+ WRITE8(ea, dst + src);
+ STORE_REG8(modrm, dst);
+ CYCLES(CYCLES_XADD_REG_MEM);
+ }
+}
+
+static void I486OP(xadd_rm16_r16)(void) // Opcode 0x0f c1
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT16 dst = LOAD_RM16(modrm);
+ UINT16 src = LOAD_REG16(modrm);
+ STORE_RM16(modrm, dst + src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_XADD_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT16 dst = READ16(ea);
+ UINT16 src = LOAD_REG16(modrm);
+ WRITE16(ea, dst + src);
+ STORE_REG16(modrm, dst);
+ CYCLES(CYCLES_XADD_REG_MEM);
+ }
+}
+
+static void I486OP(xadd_rm32_r32)(void) // Opcode 0x0f c1
+{
+ UINT8 modrm = FETCH();
+ if( modrm >= 0xc0 ) {
+ UINT32 dst = LOAD_RM32(modrm);
+ UINT32 src = LOAD_REG32(modrm);
+ STORE_RM32(modrm, dst + src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_XADD_REG_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ UINT32 dst = READ32(ea);
+ UINT32 src = LOAD_REG32(modrm);
+ WRITE32(ea, dst + src);
+ STORE_REG32(modrm, dst);
+ CYCLES(CYCLES_XADD_REG_MEM);
+ }
+}
+
+static void I486OP(group0F01_16)(void) // Opcode 0x0f 01
+{
+ UINT8 modrm = FETCH();
+ UINT16 address;
+ UINT32 ea;
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* SGDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ WRITE16(ea, I.gdtr.limit);
+ WRITE32(ea + 2, I.gdtr.base & 0xffffff);
+ CYCLES(CYCLES_SGDT);
+ break;
+ }
+ case 1: /* SIDT */
+ {
+ if (modrm >= 0xc0)
+ {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ }
+ else
+ {
+ ea = GetEA(modrm);
+ }
+ WRITE16(ea, I.idtr.limit);
+ WRITE32(ea + 2, I.idtr.base & 0xffffff);
+ CYCLES(CYCLES_SIDT);
+ break;
+ }
+ case 2: /* LGDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ I.gdtr.limit = READ16(ea);
+ I.gdtr.base = READ32(ea + 2) & 0xffffff;
+ CYCLES(CYCLES_LGDT);
+ break;
+ }
+ case 3: /* LIDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM16(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ I.idtr.limit = READ16(ea);
+ I.idtr.base = READ32(ea + 2) & 0xffffff;
+ CYCLES(CYCLES_LIDT);
+ break;
+ }
+ case 4: /* SMSW */
+ {
+ if( modrm >= 0xc0 ) {
+ STORE_RM16(modrm, I.cr[0]);
+ CYCLES(CYCLES_SMSW_REG);
+ } else {
+ UINT32 ea = GetEA(modrm);
+ WRITE16(ea, I.cr[0]);
+ CYCLES(CYCLES_SMSW_MEM);
+ }
+ break;
+ }
+ case 6: /* LMSW */
+ {
+ // TODO: Check for protection fault
+ UINT8 b;
+ if( modrm >= 0xc0 ) {
+ b = LOAD_RM8(modrm);
+ CYCLES(CYCLES_LMSW_REG);
+ } else {
+ ea = GetEA(modrm);
+ CYCLES(CYCLES_LMSW_MEM);
+ b = READ8(ea);
+ }
+ I.cr[0] &= ~0x03;
+ I.cr[0] |= b & 0x03;
+ break;
+ }
+ case 7: /* INVLPG */
+ {
+ // Nothing to do ?
+ break;
+ }
+ default:
+ fatalerror("i486: unimplemented opcode 0x0f 01 /%d at %08X", (modrm >> 3) & 0x7, I.eip - 2);
+ break;
+ }
+}
+
+static void I486OP(group0F01_32)(void) // Opcode 0x0f 01
+{
+ UINT8 modrm = FETCH();
+ UINT32 address, ea;
+
+ switch( (modrm >> 3) & 0x7 )
+ {
+ case 0: /* SGDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ WRITE16(ea, I.gdtr.limit);
+ WRITE32(ea + 2, I.gdtr.base);
+ CYCLES(CYCLES_SGDT);
+ break;
+ }
+ case 1: /* SIDT */
+ {
+ if (modrm >= 0xc0)
+ {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ }
+ else
+ {
+ ea = GetEA(modrm);
+ }
+ WRITE16(ea, I.idtr.limit);
+ WRITE32(ea + 2, I.idtr.base);
+ CYCLES(CYCLES_SIDT);
+ break;
+ }
+ case 2: /* LGDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ I.gdtr.limit = READ16(ea);
+ I.gdtr.base = READ32(ea + 2);
+ CYCLES(CYCLES_LGDT);
+ break;
+ }
+ case 3: /* LIDT */
+ {
+ if( modrm >= 0xc0 ) {
+ address = LOAD_RM32(modrm);
+ ea = i386_translate( CS, address );
+ } else {
+ ea = GetEA(modrm);
+ }
+ I.idtr.limit = READ16(ea);
+ I.idtr.base = READ32(ea + 2);
+ CYCLES(CYCLES_LIDT);
+ break;
+ }
+ case 7: /* INVLPG */
+ {
+ // Nothing to do ?
+ break;
+ }
+ default:
+ fatalerror("i486: unimplemented opcode 0x0f 01 /%d at %08X", (modrm >> 3) & 0x7, I.eip - 2);
+ break;
+ }
+}
+
diff --git a/src/emu/cpu/i386/pentops.c b/src/emu/cpu/i386/pentops.c
new file mode 100644
index 00000000000..b7fb394e301
--- /dev/null
+++ b/src/emu/cpu/i386/pentops.c
@@ -0,0 +1,53 @@
+// Pentium+ specific opcodes
+
+static void PENTIUMOP(rdmsr)(void) // Opcode 0x0f 32
+{
+ // TODO
+ CYCLES(CYCLES_RDMSR);
+}
+
+static void PENTIUMOP(wrmsr)(void) // Opcode 0x0f 30
+{
+ // TODO
+ CYCLES(1); // TODO: correct cycle count
+}
+
+static void PENTIUMOP(rdtsc)(void) // Opcode 0x0f 31
+{
+ UINT64 ts = I.tsc + (I.base_cycles - I.cycles);
+ REG32(EAX) = (UINT32)(ts);
+ REG32(EDX) = (UINT32)(ts >> 32);
+
+ CYCLES(CYCLES_RDTSC);
+}
+
+static void I386OP(cyrix_unknown)(void) // Opcode 0x0f 74
+{
+ CYCLES(1);
+}
+
+static void PENTIUMOP(cmpxchg8b_m64)(void) // Opcode 0x0f c7
+{
+ UINT8 modm = FETCH();
+ if( modm >= 0xc0 ) {
+ fatalerror("invalid modm");
+ } else {
+ UINT32 ea = GetEA(modm);
+ UINT64 value = READ64(ea);
+ UINT64 edx_eax = (((UINT64) REG32(EDX)) << 32) | REG32(EAX);
+ UINT64 ecx_ebx = (((UINT64) REG32(ECX)) << 32) | REG32(EBX);
+
+ if( value == edx_eax ) {
+ WRITE64(ea, ecx_ebx);
+ I.ZF = 1;
+ CYCLES(CYCLES_CMPXCHG_REG_MEM_T);
+ } else {
+ REG32(EDX) = (UINT32) (value >> 32);
+ REG32(EAX) = (UINT32) (value >> 0);
+ I.ZF = 0;
+ CYCLES(CYCLES_CMPXCHG_REG_MEM_F);
+ }
+ }
+}
+
+
diff --git a/src/emu/cpu/i386/x87ops.c b/src/emu/cpu/i386/x87ops.c
new file mode 100644
index 00000000000..abcf05754e2
--- /dev/null
+++ b/src/emu/cpu/i386/x87ops.c
@@ -0,0 +1,352 @@
+// Intel x87 FPU opcodes
+
+#define ST(x) (I.fpu_reg[(I.fpu_top + (x)) & 7])
+#define FPU_INFINITY_DOUBLE U64(0x7ff0000000000000)
+#define FPU_INFINITY_SINGLE (0x7f800000)
+#define FPU_SIGN_BIT_DOUBLE U64(0x8000000000000000)
+#define FPU_SIGN_BIT_SINGLE (0x80000000)
+
+// FPU control word flags
+#define FPU_MASK_INVALID_OP 0x0001
+#define FPU_MASK_DENORMAL_OP 0x0002
+#define FPU_MASK_ZERO_DIVIDE 0x0004
+#define FPU_MASK_OVERFLOW 0x0008
+#define FPU_MASK_UNDERFLOW 0x0010
+#define FPU_MASK_PRECISION 0x0020
+
+// FPU status word flags
+#define FPU_BUSY 0x8000
+#define FPU_C3 0x4000
+#define FPU_STACK_TOP_MASK 0x3800
+#define FPU_C2 0x0400
+#define FPU_C1 0x0200
+#define FPU_C0 0x0100
+#define FPU_ERROR_SUMMARY 0x0080
+#define FPU_STACK_FAULT 0x0040
+#define FPU_EXCEPTION_PRECISION 0x0020
+#define FPU_EXCEPTION_UNDERFLOW 0x0010
+#define FPU_EXCEPTION_OVERFLOW 0x0008
+#define FPU_EXCEPTION_ZERO_DIVIDE 0x0004
+#define FPU_EXCEPTION_DENORMAL_OP 0x0002
+#define FPU_EXCEPTION_INVALID_OP 0x0001
+
+INLINE void FPU_PUSH(X87_REG value)
+{
+ I.fpu_top--;
+ if (I.fpu_top < 0)
+ {
+ I.fpu_top = 7;
+ }
+
+ I.fpu_reg[I.fpu_top] = value;
+}
+
+INLINE X87_REG FPU_POP(void)
+{
+ X87_REG value = I.fpu_reg[I.fpu_top];
+
+ I.fpu_tag_word |= 3 << (I.fpu_top * 2); // set FPU register tag to 3 (empty)
+
+ I.fpu_top++;
+ if (I.fpu_top > 7)
+ {
+ I.fpu_top = 0;
+ }
+
+ return value;
+}
+
+static void I386OP(fpu_group_d8)(void) // Opcode 0xd8
+{
+ UINT8 modrm = FETCH();
+ fatalerror("I386: FPU Op D8 %02X at %08X", modrm, I.pc-2);
+}
+
+static void I386OP(fpu_group_d9)(void) // Opcode 0xd9
+{
+ UINT8 modrm = FETCH();
+
+ if (modrm < 0xc0)
+ {
+ UINT32 ea = GetEA(modrm);
+
+ switch ((modrm >> 3) & 0x7)
+ {
+ case 5: // FLDCW
+ {
+ I.fpu_control_word = READ16(ea);
+ CYCLES(1); // TODO
+ break;
+ }
+
+ case 7: // FSTCW
+ {
+ WRITE16(ea, I.fpu_control_word);
+ CYCLES(1); // TODO
+ break;
+ }
+
+ default:
+ fatalerror("I386: FPU Op D9 %02X at %08X", modrm, I.pc-2);
+ }
+ }
+ else
+ {
+ switch (modrm & 0x3f)
+ {
+ // FLD
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ {
+ X87_REG t = ST(modrm & 7);
+ FPU_PUSH(t);
+ CYCLES(1); // TODO
+ break;
+ }
+
+ case 0x20: // FCHS
+ {
+ ST(0).i ^= FPU_SIGN_BIT_DOUBLE;
+ CYCLES(1); // TODO
+ break;
+ }
+
+ case 0x28: // FLD1
+ {
+ X87_REG t;
+ t.f = 1.0;
+ FPU_PUSH(t);
+ CYCLES(1); // TODO
+ break;
+ }
+
+ case 0x2e: // FLDZ
+ {
+ X87_REG t;
+ t.f = 0.0;
+ FPU_PUSH(t);
+ CYCLES(1); // TODO
+ break;
+ }
+ default:
+ fatalerror("I386: FPU Op D9 %02X at %08X", modrm, I.pc-2);
+ }
+ }
+}
+
+static void I386OP(fpu_group_da)(void) // Opcode 0xda
+{
+ UINT8 modrm = FETCH();
+ fatalerror("I386: FPU Op DA %02X at %08X", modrm, I.pc-2);
+}
+
+static void I386OP(fpu_group_db)(void) // Opcode 0xdb
+{
+ UINT8 modrm = FETCH();
+
+ if (modrm < 0xc0)
+ {
+ fatalerror("I386: FPU Op DB %02X at %08X", modrm, I.pc-2);
+ }
+ else
+ {
+ switch (modrm & 0x3f)
+ {
+ case 0x23: // FINIT
+ {
+ I.fpu_control_word = 0x37f;
+ I.fpu_status_word = 0;
+ I.fpu_tag_word = 0xffff;
+ I.fpu_data_ptr = 0;
+ I.fpu_inst_ptr = 0;
+ I.fpu_opcode = 0;
+
+ CYCLES(1); // TODO
+ break;
+ }
+
+ case 0x24: // FSETPM (treated as nop on 387+)
+ {
+ CYCLES(1);
+ break;
+ }
+
+ default:
+ fatalerror("I386: FPU Op DB %02X at %08X", modrm, I.pc-2);
+ }
+ }
+}
+
+static void I386OP(fpu_group_dc)(void) // Opcode 0xdc
+{
+ UINT8 modrm = FETCH();
+
+ if (modrm < 0xc0)
+ {
+ //UINT32 ea = GetEA(modrm);
+
+ switch ((modrm >> 3) & 0x7)
+ {
+ default:
+ fatalerror("I386: FPU Op DC %02X at %08X", modrm, I.pc-2);
+ }
+ }
+ else
+ {
+ switch (modrm & 0x3f)
+ {
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ {
+ // FDIVR
+ if ((ST(modrm & 7).i & U64(0x7fffffffffffffff)) == 0)
+ {
+ // set result as infinity if zero divide is masked
+ if (I.fpu_control_word & FPU_MASK_ZERO_DIVIDE)
+ {
+ ST(modrm & 7).i |= FPU_INFINITY_DOUBLE;
+ }
+ }
+ else
+ {
+ ST(modrm & 7).f = ST(0).f / ST(modrm & 7).f;
+ }
+ CYCLES(1); // TODO
+ break;
+ }
+
+ default:
+ fatalerror("I386: FPU Op DC %02X at %08X", modrm, I.pc-2);
+ }
+ }
+}
+
+static void I386OP(fpu_group_dd)(void) // Opcode 0xdd
+{
+ UINT8 modrm = FETCH();
+
+ if (modrm < 0xc0)
+ {
+ UINT32 ea = GetEA(modrm);
+
+ switch ((modrm >> 3) & 0x7)
+ {
+ case 7: // FSTSW
+ {
+ WRITE16(ea, (I.fpu_status_word & ~FPU_STACK_TOP_MASK) | (I.fpu_top << 10));
+ CYCLES(1); // TODO
+ break;
+ }
+
+ default:
+ fatalerror("I386: FPU Op DD %02X at %08X", modrm, I.pc-2);
+ }
+ }
+ else
+ {
+ switch (modrm & 0x3f)
+ {
+ default:
+ fatalerror("I386: FPU Op DD %02X at %08X", modrm, I.pc-2);
+ }
+ }
+}
+
+static void I386OP(fpu_group_de)(void) // Opcode 0xde
+{
+ UINT8 modrm = FETCH();
+
+ if (modrm < 0xc0)
+ {
+ // UINT32 ea = GetEA(modrm);
+
+ switch ((modrm >> 3) & 0x7)
+ {
+ default:
+ fatalerror("I386: FPU Op DE %02X at %08X", modrm, I.pc-2);
+ }
+ }
+ else
+ {
+ switch (modrm & 0x3f)
+ {
+ case 0x19: // FCOMPP
+ {
+ I.fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
+ if (ST(0).f > ST(1).f)
+ {
+ // C3 = 0, C2 = 0, C0 = 0
+ }
+ else if (ST(0).f < ST(1).f)
+ {
+ I.fpu_status_word |= FPU_C0;
+ }
+ else if (ST(0).f == ST(1).f)
+ {
+ I.fpu_status_word |= FPU_C3;
+ }
+ else
+ {
+ // unordered
+ I.fpu_status_word |= (FPU_C3 | FPU_C2 | FPU_C0);
+ }
+ FPU_POP();
+ FPU_POP();
+ CYCLES(1); // TODO
+ break;
+ }
+
+ // FDIVP
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ {
+ if ((ST(0).i & U64(0x7fffffffffffffff)) == 0)
+ {
+ // set result as infinity if zero divide is masked
+ if (I.fpu_control_word & FPU_MASK_ZERO_DIVIDE)
+ {
+ ST(modrm & 7).i |= FPU_INFINITY_DOUBLE;
+ }
+ }
+ else
+ {
+ ST(modrm & 7).f = ST(modrm & 7).f / ST(0).f;
+ }
+ FPU_POP();
+ CYCLES(1); // TODO
+ break;
+ }
+
+ default:
+ fatalerror("I386: FPU Op DE %02X at %08X", modrm, I.pc-2);
+ }
+ }
+}
+
+static void I386OP(fpu_group_df)(void) // Opcode 0xdf
+{
+ UINT8 modrm = FETCH();
+
+ if (modrm < 0xc0)
+ {
+ // UINT32 ea = GetEA(modrm);
+
+ switch ((modrm >> 3) & 0x7)
+ {
+ default:
+ fatalerror("I386: FPU Op DF %02X at %08X", modrm, I.pc-2);
+ }
+ }
+ else
+ {
+ switch (modrm & 0x3f)
+ {
+ case 0x20: // FSTSW AX
+ {
+ REG16(AX) = (I.fpu_status_word & ~FPU_STACK_TOP_MASK) | (I.fpu_top << 10);
+ CYCLES(1); // TODO
+ break;
+ }
+
+ default:
+ fatalerror("I386: FPU Op DF %02X at %08X", modrm, I.pc-2);
+ }
+ }
+}
diff --git a/src/emu/cpu/i8039/8039dasm.c b/src/emu/cpu/i8039/8039dasm.c
new file mode 100644
index 00000000000..e138cf8ff15
--- /dev/null
+++ b/src/emu/cpu/i8039/8039dasm.c
@@ -0,0 +1,302 @@
+/****************************************************************************
+ *
+ * mcs48 disassembler
+ *
+ * This file is Copyright 1996 Michael Cuddy, Fen's Ende Sofware.
+ * Redistribution is allowed in source and binary form as long as both
+ * forms are distributed together with the file 'README'. This copyright
+ * notice must also accompany the files.
+ *
+ * This software should be considered a small token to all of the
+ * emulator authors for thier dilligence in preserving our Arcade and
+ * Computer history.
+ *
+ * Michael Cuddy, Fen's Ende Software.
+ * 11/25/1996
+ *
+ * Adapted by Andrea Mazzoleni for use with MAME
+ *
+ ***************************************************************************/
+
+#include <ctype.h>
+
+#include "cpuintrf.h"
+
+#define mame_printf_debug printf
+
+typedef unsigned char byte;
+
+#define FMT(a,b) a, b
+#define PTRS_PER_FORMAT 2
+
+static const char *Formats[] = {
+ FMT("00000011dddddddd", "add a,#$%X"),
+ FMT("01101rrr", "add a,%R"),
+ FMT("0110000r", "add a,@%R"),
+ FMT("00010011dddddddd", "adc a,#$%X"),
+ FMT("01111rrr", "adc a,%R"),
+ FMT("0111000r", "adc a,@%R"),
+ FMT("01010011dddddddd", "anl a,#$%X"),
+ FMT("01011rrr", "anl a,%R"),
+ FMT("0101000r", "anl a,@%R"),
+ FMT("10011000dddddddd", "anl bus,#$%X"),
+ FMT("10011001dddddddd", "anl p1,#$%X"),
+ FMT("10011010dddddddd", "anl p2,#$%X"),
+ FMT("100111pp", "anld %P,a"),
+ FMT("aaa10100aaaaaaaa", "!call %A"),
+ FMT("00100111", "clr a"),
+ FMT("10010111", "clr c"),
+ FMT("10100101", "clr f1"),
+ FMT("10000101", "clr f0"),
+ FMT("00110111", "cpl a"),
+ FMT("10100111", "cpl c"),
+ FMT("10010101", "cpl f0"),
+ FMT("10110101", "cpl f1"),
+ FMT("01010111", "da a"),
+ FMT("00000111", "dec a"),
+ FMT("11001rrr", "dec %R"),
+ FMT("00010101", "dis i"),
+ FMT("00110101", "dis tcnti"),
+ FMT("11101rrraaaaaaaa", "!djnz %R,%J"),
+ FMT("00000101", "en i"),
+ FMT("00100101", "en tcnti"),
+ FMT("01110101", "ent0 clk"),
+ FMT("00001001", "in a,p1"),
+ FMT("00001010", "in a,p2"),
+ FMT("00010111", "inc a"),
+ FMT("00011rrr", "inc %R"),
+ FMT("0001000r", "inc @%R"),
+ FMT("00001000", "ins a,bus"),
+ FMT("0001 0110aaaaaaaa", "jtf %J"),
+ FMT("0010 0110aaaaaaaa", "jnt0 %J"),
+ FMT("0011 0110aaaaaaaa", "jt0 %J"),
+ FMT("0100 0110aaaaaaaa", "jnt1 %J"),
+ FMT("0101 0110aaaaaaaa", "jt1 %J"),
+ FMT("0111 0110aaaaaaaa", "jf1 %J"),
+ FMT("1000 0110aaaaaaaa", "jni %J"),
+ FMT("1001 0110aaaaaaaa", "jnz %J"),
+ FMT("1011 0110aaaaaaaa", "jf0 %J"),
+ FMT("1100 0110aaaaaaaa", "jz %J"),
+ FMT("1110 0110aaaaaaaa", "jnc %J"),
+ FMT("1111 0110aaaaaaaa", "jc %J"),
+ FMT("bbb10010aaaaaaaa", "jb%B %J"),
+ FMT("aaa00100aaaaaaaa", "jmp %A"),
+ FMT("10110011", "jmpp @a"),
+ FMT("00100011dddddddd", "mov a,#$%X"),
+ FMT("11111rrr", "mov a,%R"),
+ FMT("1111000r", "mov a,@%R"),
+ FMT("11000111", "mov a,psw"),
+ FMT("10111rrrdddddddd", "mov %R,#$%X"),
+ FMT("10101rrr", "mov %R,a"),
+ FMT("1010000r", "mov @%R,a"),
+ FMT("1011000rdddddddd", "mov @%R,#$%X"),
+ FMT("11010111", "mov psw,a"),
+ FMT("000011pp", "movd a,%P"),
+ FMT("001111pp", "movd %P,a"),
+ FMT("01000010", "mov a,t"),
+ FMT("01100010", "mov t,a"),
+ FMT("11100011", "movp3 a,@a"),
+ FMT("10100011", "movp a,@a"),
+ FMT("1000000r", "movx a,@%R"),
+ FMT("1001000r", "movx @%R,a"),
+ FMT("0100 1rrr", "orl a,%R"),
+ FMT("0100 000r", "orl a,@%R"),
+ FMT("0100 0011dddddddd", "orl a,#$%X"),
+ FMT("1000 1000dddddddd", "orl bus,#$%X"),
+ FMT("1000 1001dddddddd", "orl p1,#$%X"),
+ FMT("1000 1010dddddddd", "orl p2,#$%X"),
+ FMT("1000 11pp", "orld %P,a"),
+ FMT("00000010", "outl bus,a"),
+ FMT("001110pp", "outl %P,a"),
+ FMT("10000011", "^ret"),
+ FMT("10010011", "^retr"),
+ FMT("11100111", "rl a"),
+ FMT("11110111", "rlc a"),
+ FMT("01110111", "rr a"),
+ FMT("01100111", "rrc a"),
+ FMT("11100101", "sel mb0"),
+ FMT("11110101", "sel mb1"),
+ FMT("11000101", "sel rb0"),
+ FMT("11010101", "sel rb1"),
+ FMT("01100101", "stop tcnt"),
+ FMT("01000101", "strt cnt"),
+ FMT("01010101", "strt t"),
+ FMT("01000111", "swap a"),
+ FMT("00101rrr", "xch a,%R"),
+ FMT("0010000r", "xch a,@%R"),
+ FMT("0011000r", "xchd a,@%R"),
+ FMT("1101 0011dddddddd", "xrl a,#$%X"),
+ FMT("1101 1rrr", "xrl a,%R"),
+ FMT("1101 000r", "xrl a,@%R"),
+ FMT("00000000", "nop"),
+ NULL
+};
+
+#define MAX_OPS (((sizeof(Formats) / sizeof(Formats[0])) - 1) / PTRS_PER_FORMAT)
+
+typedef struct opcode {
+ byte mask; /* instruction mask */
+ byte bits; /* constant bits */
+ char extcode; /* value that gets extension code */
+ const char *parse; /* how to parse bits */
+ const char *fmt; /* instruction format */
+ unsigned long flags;
+} M48Opcode;
+
+static M48Opcode Op[MAX_OPS+1];
+static int OpInizialized = 0;
+
+static void InitDasm8039(void)
+{
+ const char *p, **ops;
+ byte mask, bits;
+ int bit;
+ int i;
+
+ ops = Formats; i = 0;
+ while (*ops) {
+ unsigned long flags = 0;
+ p = *ops;
+ mask = 0; bits = 0; bit = 7;
+ while (*p && bit >= 0) {
+ switch (*p++) {
+ case '1': mask |= 1<<bit; bits |= 1<<bit; bit--; break;
+ case '0': mask |= 1<<bit; bit--; break;
+ case ' ': break;
+ case 'b':
+ case 'a': case 'r': case 'd': case 'p':
+ bit --;
+ break;
+ default:
+ fatalerror("Invalid instruction encoding '%s %s'\n", ops[0],ops[1]);
+ break;
+ }
+ }
+ if (bit != -1 ) {
+ fatalerror("not enough bits in encoding '%s %s' %d\n", ops[0],ops[1],bit);
+ break;
+ }
+ while (isspace(*p)) p++;
+ if (*p) Op[i].extcode = *p;
+ Op[i].bits = bits;
+ Op[i].mask = mask;
+ Op[i].fmt = ops[1];
+ Op[i].parse = ops[0];
+
+ if (Op[i].fmt[0] == '!')
+ {
+ flags |= DASMFLAG_STEP_OVER;
+ Op[i].fmt++;
+ }
+ if (Op[i].fmt[0] == '^')
+ {
+ flags |= DASMFLAG_STEP_OUT;
+ Op[i].fmt++;
+ }
+ Op[i].flags = flags;
+
+ ops += PTRS_PER_FORMAT;
+ i++;
+ }
+
+ OpInizialized = 1;
+}
+
+offs_t i8039_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int b, a, d, r, p; /* these can all be filled in by parsing an instruction */
+ int i;
+ int op;
+ int cnt = 1;
+ int code, bit;
+ const char *cp;
+
+ if (!OpInizialized) InitDasm8039();
+
+ code = oprom[0];
+ op = -1; /* no matching opcode */
+ for ( i = 0; i < MAX_OPS; i++)
+ {
+ if( (code & Op[i].mask) == Op[i].bits )
+ {
+ if (op != -1)
+ {
+ fprintf(stderr, "Error: opcode %02X matches %d (%s) and %d (%s)\n",
+ code,i,Op[i].fmt,op,Op[op].fmt);
+ }
+ op = i;
+ }
+ }
+
+ if (op == -1)
+ {
+ sprintf(buffer,"db %2.2x",code);
+ return cnt | DASMFLAG_SUPPORTED;
+ }
+
+ if (Op[op].extcode)
+ {
+ cnt++;
+ code <<= 8;
+ code |= opram[1];
+ bit = 15;
+ }
+ else
+ {
+ bit = 7;
+ }
+
+ /* shift out operands */
+ cp = Op[op].parse;
+ b = a = d = r = p = 0;
+
+ while (bit >= 0)
+ {
+ /* mame_printf_debug("{%c/%d}",*cp,bit); */
+ switch(*cp)
+ {
+ case 'a': a <<=1; a |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'b': b <<=1; b |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'd': d <<=1; d |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'r': r <<=1; r |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'p': p <<=1; p |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case ' ': break;
+ case '1': case '0': bit--; break;
+ case '\0': fatalerror("premature end of parse string, opcode %x, bit = %d\n",code,bit); break;
+ }
+ cp++;
+ }
+
+ /* now traverse format string */
+ cp = Op[op].fmt;
+ while (*cp)
+ {
+ if (*cp == '%')
+ {
+ char num[10], *q;
+ cp++;
+ switch (*cp++)
+ {
+ case 'A': sprintf(num,"$%04X",a); break;
+ case 'J': sprintf(num,"$%04X",((pc+1) & 0xf00) | a); break;
+ case 'B': sprintf(num,"%d",b); break;
+ case 'D': sprintf(num,"%d",d); break;
+ case 'X': sprintf(num,"%X",d); break;
+ case 'R': sprintf(num,"r%d",r); break;
+ case 'P': sprintf(num,"p%d",p); break;
+ default:
+ fatalerror("illegal escape character in format '%s'\n",Op[op].fmt);
+ break;
+ }
+ q = num; while (*q) *buffer++ = *q++;
+ *buffer = '\0';
+ }
+ else
+ {
+ *buffer++ = *cp++;
+ *buffer = '\0';
+ }
+ }
+
+ return cnt | Op[op].flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/i8039/i8039.c b/src/emu/cpu/i8039/i8039.c
new file mode 100644
index 00000000000..3c1f8df449c
--- /dev/null
+++ b/src/emu/cpu/i8039/i8039.c
@@ -0,0 +1,949 @@
+/****************************************************************************
+ * Intel 8039 Portable Emulator *
+ * *
+ * Copyright (C) 1997 by Mirko Buffoni *
+ * Based on the original work (C) 1997 by Dan Boris, an 8048 emulator *
+ * You are not allowed to distribute this software commercially *
+ * Please, notify me, if you make any changes to this file *
+ * *
+ * *
+ * **** Change Log **** *
+ * *
+ * TLP (19-Jun-2001) *
+ * - Changed Ports 1 and 2 to quasi bidirectional output latched ports *
+ * - Added the Port 1 & 2 output latch data to the debugger window *
+ * TLP (02-Jan-2002) *
+ * - External IRQs no longer go pending (sampled as a level state) *
+ * - Timer IRQs do not go pending if Timer interrupts are disabled *
+ * - Timer IRQs made pending, were incorrectly being cleared if the *
+ * external interrupt was being serviced *
+ * - External interrupts now take precedence when simultaneous *
+ * internal and external interrupt requests occur *
+ * - 'DIS TCNTI' now removes pending timer IRQs *
+ * - Nested IRQs of any sort are no longer allowed *
+ * - T_flag was not being set in the right place of execution, which *
+ * could have lead to it being incorrectly set after being cleared *
+ * - Counter overflows now also set the T_flag *
+ * - Added the Timer/Counter register to the debugger window *
+ * TLP (09-Jan-2002) *
+ * - Changed Interrupt system to instant servicing *
+ * - The Timer and Counter can no longer be 'on' simultaneously *
+ * - Added Save State *
+ * TLP (15-Feb-2002) *
+ * - Corrected Positive signal edge sensing (used on the T1 input) *
+ ****************************************************************************/
+
+
+#include "debugger.h"
+#include "i8039.h"
+
+
+/*** Cycle times for the jump on condition instructions, are unusual.
+ Condition is tested during the first cycle, so if condition is not
+ met, second address fetch cycle may not really be taken. For now we
+ just use the cycle counts as listed in the i8048 user manual.
+***/
+
+#if 0
+#define ADJUST_CYCLES { inst_cycles -= 1; } /* Possible real cycles setting */
+#else
+#define ADJUST_CYCLES { } /* User Manual cycles setting */
+#endif
+
+
+
+/* HJB 01/05/99 changed to positive values to use pending_irq as a flag */
+#define I8039_NO_INT 0 /* No Interrupts pending or executing */
+#define I8039_EXTERNAL_INT 1 /* Execute a normal external interrupt */
+#define I8039_TIMCNT_INT 2 /* Execute a Timer/Counter interrupt */
+
+
+static int Ext_IRQ(void);
+static int Timer_IRQ(void);
+
+#define M_RDMEM(A) I8039_RDMEM(A)
+#define M_RDOP(A) I8039_RDOP(A)
+#define M_RDOP_ARG(A) I8039_RDOP_ARG(A)
+#define M_IN(A) I8039_In(A)
+#define M_OUT(A,V) I8039_Out(A,V)
+
+#define port_r(A) I8039_In(I8039_p0 + A)
+#define port_w(A,V) I8039_Out(I8039_p0 + A,V)
+#define test_r(A) I8039_In(I8039_t0 + A)
+#define test_w(A,V) I8039_Out(I8039_t0 + A,V)
+#define bus_r() I8039_In(I8039_bus)
+#define bus_w(V) I8039_Out(I8039_bus,V)
+
+#define C_FLAG 0x80
+#define A_FLAG 0x40
+#define F_FLAG 0x20
+#define B_FLAG 0x10
+
+typedef struct
+{
+ PAIR PREVPC; /* previous program counter */
+ PAIR PC; /* program counter */
+ UINT8 A, SP, PSW;
+ UINT8 RAM[128];
+ UINT8 bus, f1; /* Bus data, and flag1 */
+ UINT8 P1, P2; /* Internal Port 1 and 2 latched outputs */
+
+ UINT8 pending_irq, irq_executing, masterClock, regPtr;
+ UINT8 t_flag, timer, timerON, countON, xirq_en, tirq_en;
+ UINT16 A11;
+ UINT8 irq_state, irq_extra_cycles;
+ int (*irq_callback)(int irqline);
+} I8039_Regs;
+
+static I8039_Regs R;
+int i8039_ICount;
+static int inst_cycles;
+static UINT8 Old_T1;
+
+/* The opcode table now is a combination of cycle counts and function pointers */
+typedef struct {
+ unsigned cycles;
+ void (*function) (void);
+} s_opcode;
+
+#define POSITIVE_EDGE_T1 (( (int)(T1-Old_T1) > 0) ? 1 : 0)
+#define NEGATIVE_EDGE_T1 (( (int)(Old_T1-T1) > 0) ? 1 : 0)
+
+#define M_Cy ((R.PSW & C_FLAG) >> 7)
+#define M_Cn (!M_Cy)
+#define M_Ay ((R.PSW & A_FLAG))
+#define M_An (!M_Ay)
+#define M_F0y ((R.PSW & F_FLAG))
+#define M_F0n (!M_F0y)
+#define M_By ((R.PSW & B_FLAG))
+#define M_Bn (!M_By)
+
+#define intRAM R.RAM
+#define regPTR R.regPtr
+
+#define R0 intRAM[regPTR ]
+#define R1 intRAM[regPTR+1]
+#define R2 intRAM[regPTR+2]
+#define R3 intRAM[regPTR+3]
+#define R4 intRAM[regPTR+4]
+#define R5 intRAM[regPTR+5]
+#define R6 intRAM[regPTR+6]
+#define R7 intRAM[regPTR+7]
+
+
+INLINE void CLR (UINT8 flag) { R.PSW &= ~flag; }
+INLINE void SET (UINT8 flag) { R.PSW |= flag; }
+
+
+/* Get next opcode argument and increment program counter */
+INLINE unsigned M_RDMEM_OPCODE (void)
+{
+ unsigned retval;
+ retval=M_RDOP_ARG(R.PC.w.l);
+ R.PC.w.l++;
+ return retval;
+}
+
+INLINE void push(UINT8 d)
+{
+ intRAM[8+R.SP++] = d;
+ R.SP = R.SP & 0x0f;
+ R.PSW = R.PSW & 0xf8;
+ R.PSW = R.PSW | (R.SP >> 1);
+}
+
+INLINE UINT8 pull(void) {
+ R.SP = (R.SP + 15) & 0x0f; /* if (--R.SP < 0) R.SP = 15; */
+ R.PSW = R.PSW & 0xf8;
+ R.PSW = R.PSW | (R.SP >> 1);
+ /* regPTR = ((M_By) ? 24 : 0); regPTR should not change */
+ return intRAM[8+R.SP];
+}
+
+INLINE void daa_a(void)
+{
+ if ((R.A & 0x0f) > 0x09 || (R.PSW & A_FLAG))
+ R.A += 0x06;
+ if ((R.A & 0xf0) > 0x90 || (R.PSW & C_FLAG))
+ {
+ R.A += 0x60;
+ SET(C_FLAG);
+ } else CLR(C_FLAG);
+}
+
+INLINE void M_ADD(UINT8 dat)
+{
+ UINT16 temp;
+
+ CLR(C_FLAG | A_FLAG);
+ if ((R.A & 0xf) + (dat & 0xf) > 0xf) SET(A_FLAG);
+ temp = R.A + dat;
+ if (temp > 0xff) SET(C_FLAG);
+ R.A = temp & 0xff;
+}
+
+INLINE void M_ADDC(UINT8 dat)
+{
+ UINT16 temp;
+
+ CLR(A_FLAG);
+ if ((R.A & 0xf) + (dat & 0xf) + M_Cy > 0xf) SET(A_FLAG);
+ temp = R.A + dat + M_Cy;
+ CLR(C_FLAG);
+ if (temp > 0xff) SET(C_FLAG);
+ R.A = temp & 0xff;
+}
+
+INLINE void M_CALL(UINT16 addr)
+{
+ push(R.PC.b.l);
+ push((R.PC.b.h & 0x0f) | (R.PSW & 0xf0));
+ R.PC.w.l = addr;
+ change_pc(addr);
+}
+
+INLINE void M_XCHD(UINT8 addr)
+{
+ UINT8 dat = R.A & 0x0f;
+ R.A &= 0xf0;
+ R.A |= intRAM[addr] & 0x0f;
+ intRAM[addr] &= 0xf0;
+ intRAM[addr] |= dat;
+}
+
+
+INLINE void M_ILLEGAL(void)
+{
+ logerror("I8039: PC = %04x, Illegal opcode = %02x\n", R.PC.w.l-1, M_RDMEM(R.PC.w.l-1));
+}
+
+INLINE void M_UNDEFINED(void)
+{
+ logerror("I8039: PC = %04x, Unimplemented opcode = %02x\n", R.PC.w.l-1, M_RDMEM(R.PC.w.l-1));
+}
+
+static void illegal(void) { M_ILLEGAL(); }
+
+static void add_a_n(void) { M_ADD(M_RDMEM_OPCODE()); }
+static void add_a_r0(void) { M_ADD(R0); }
+static void add_a_r1(void) { M_ADD(R1); }
+static void add_a_r2(void) { M_ADD(R2); }
+static void add_a_r3(void) { M_ADD(R3); }
+static void add_a_r4(void) { M_ADD(R4); }
+static void add_a_r5(void) { M_ADD(R5); }
+static void add_a_r6(void) { M_ADD(R6); }
+static void add_a_r7(void) { M_ADD(R7); }
+static void add_a_xr0(void) { M_ADD(intRAM[R0 & 0x7f]); }
+static void add_a_xr1(void) { M_ADD(intRAM[R1 & 0x7f]); }
+static void adc_a_n(void) { M_ADDC(M_RDMEM_OPCODE()); }
+static void adc_a_r0(void) { M_ADDC(R0); }
+static void adc_a_r1(void) { M_ADDC(R1); }
+static void adc_a_r2(void) { M_ADDC(R2); }
+static void adc_a_r3(void) { M_ADDC(R3); }
+static void adc_a_r4(void) { M_ADDC(R4); }
+static void adc_a_r5(void) { M_ADDC(R5); }
+static void adc_a_r6(void) { M_ADDC(R6); }
+static void adc_a_r7(void) { M_ADDC(R7); }
+static void adc_a_xr0(void) { M_ADDC(intRAM[R0 & 0x7f]); }
+static void adc_a_xr1(void) { M_ADDC(intRAM[R1 & 0x7f]); }
+static void anl_a_n(void) { R.A &= M_RDMEM_OPCODE(); }
+static void anl_a_r0(void) { R.A &= R0; }
+static void anl_a_r1(void) { R.A &= R1; }
+static void anl_a_r2(void) { R.A &= R2; }
+static void anl_a_r3(void) { R.A &= R3; }
+static void anl_a_r4(void) { R.A &= R4; }
+static void anl_a_r5(void) { R.A &= R5; }
+static void anl_a_r6(void) { R.A &= R6; }
+static void anl_a_r7(void) { R.A &= R7; }
+static void anl_a_xr0(void) { R.A &= intRAM[R0 & 0x7f]; }
+static void anl_a_xr1(void) { R.A &= intRAM[R1 & 0x7f]; }
+static void anl_bus_n(void) { bus_w( bus_r() & M_RDMEM_OPCODE() ); }
+static void anl_p1_n(void) { R.P1 &= M_RDMEM_OPCODE(); port_w( 1, R.P1 ); }
+static void anl_p2_n(void) { R.P2 &= M_RDMEM_OPCODE(); port_w( 2, R.P2 ); }
+static void anld_p4_a(void) { port_w( 4, port_r(4) & M_RDMEM_OPCODE() ); }
+static void anld_p5_a(void) { port_w( 5, port_r(5) & M_RDMEM_OPCODE() ); }
+static void anld_p6_a(void) { port_w( 6, port_r(6) & M_RDMEM_OPCODE() ); }
+static void anld_p7_a(void) { port_w( 7, port_r(7) & M_RDMEM_OPCODE() ); }
+static void call(void) { UINT8 i=M_RDMEM_OPCODE(); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; M_CALL(i | a11); }
+static void call_1(void) { UINT8 i=M_RDMEM_OPCODE(); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; M_CALL(i | 0x100 | a11); }
+static void call_2(void) { UINT8 i=M_RDMEM_OPCODE(); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; M_CALL(i | 0x200 | a11); }
+static void call_3(void) { UINT8 i=M_RDMEM_OPCODE(); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; M_CALL(i | 0x300 | a11); }
+static void call_4(void) { UINT8 i=M_RDMEM_OPCODE(); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; M_CALL(i | 0x400 | a11); }
+static void call_5(void) { UINT8 i=M_RDMEM_OPCODE(); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; M_CALL(i | 0x500 | a11); }
+static void call_6(void) { UINT8 i=M_RDMEM_OPCODE(); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; M_CALL(i | 0x600 | a11); }
+static void call_7(void) { UINT8 i=M_RDMEM_OPCODE(); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; M_CALL(i | 0x700 | a11); }
+static void clr_a(void) { R.A=0; }
+static void clr_c(void) { CLR(C_FLAG); }
+static void clr_f0(void) { CLR(F_FLAG); }
+static void clr_f1(void) { R.f1 = 0; }
+static void cpl_a(void) { R.A ^= 0xff; }
+static void cpl_c(void) { R.PSW ^= C_FLAG; }
+static void cpl_f0(void) { R.PSW ^= F_FLAG; }
+static void cpl_f1(void) { R.f1 ^= 1; }
+static void dec_a(void) { R.A--; }
+static void dec_r0(void) { R0--; }
+static void dec_r1(void) { R1--; }
+static void dec_r2(void) { R2--; }
+static void dec_r3(void) { R3--; }
+static void dec_r4(void) { R4--; }
+static void dec_r5(void) { R5--; }
+static void dec_r6(void) { R6--; }
+static void dec_r7(void) { R7--; }
+static void dis_i(void) { R.xirq_en = 0; }
+static void dis_tcnti(void) { R.tirq_en = 0; R.pending_irq &= ~I8039_TIMCNT_INT; }
+static void djnz_r0(void) { UINT8 i=M_RDMEM_OPCODE(); R0--; if (R0 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void djnz_r1(void) { UINT8 i=M_RDMEM_OPCODE(); R1--; if (R1 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void djnz_r2(void) { UINT8 i=M_RDMEM_OPCODE(); R2--; if (R2 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void djnz_r3(void) { UINT8 i=M_RDMEM_OPCODE(); R3--; if (R3 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void djnz_r4(void) { UINT8 i=M_RDMEM_OPCODE(); R4--; if (R4 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void djnz_r5(void) { UINT8 i=M_RDMEM_OPCODE(); R5--; if (R5 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void djnz_r6(void) { UINT8 i=M_RDMEM_OPCODE(); R6--; if (R6 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void djnz_r7(void) { UINT8 i=M_RDMEM_OPCODE(); R7--; if (R7 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void en_i(void) { R.xirq_en = 1; if (R.irq_state == I8039_EXTERNAL_INT) { R.irq_extra_cycles += Ext_IRQ(); } }
+static void en_tcnti(void) { R.tirq_en = 1; }
+static void ento_clk(void) { M_UNDEFINED(); }
+static void in_a_p1(void) { R.A = port_r(1) & R.P1; }
+static void in_a_p2(void) { R.A = port_r(2) & R.P2; }
+static void ins_a_bus(void) { R.A = bus_r(); }
+static void inc_a(void) { R.A++; }
+static void inc_r0(void) { R0++; }
+static void inc_r1(void) { R1++; }
+static void inc_r2(void) { R2++; }
+static void inc_r3(void) { R3++; }
+static void inc_r4(void) { R4++; }
+static void inc_r5(void) { R5++; }
+static void inc_r6(void) { R6++; }
+static void inc_r7(void) { R7++; }
+static void inc_xr0(void) { intRAM[R0 & 0x7f]++; }
+static void inc_xr1(void) { intRAM[R1 & 0x7f]++; }
+
+static void jmp(void)
+{
+ UINT8 i=M_RDOP(R.PC.w.l);
+ UINT16 oldpc,newpc;
+ UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0;
+
+ oldpc = R.PC.w.l-1;
+ R.PC.w.l = i | a11;
+ change_pc(R.PC.w.l);
+ newpc = R.PC.w.l;
+ if (newpc == oldpc) { if (i8039_ICount > 0) i8039_ICount = 0; } /* speed up busy loop */
+ else if (newpc == oldpc-1 && M_RDOP(newpc) == 0x00) /* NOP - Gyruss */
+ { if (i8039_ICount > 0) i8039_ICount = 0; }
+}
+
+static void jmp_1(void) { UINT8 i=M_RDOP(R.PC.w.l); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; R.PC.w.l = i | 0x100 | a11; change_pc(R.PC.w.l); }
+static void jmp_2(void) { UINT8 i=M_RDOP(R.PC.w.l); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; R.PC.w.l = i | 0x200 | a11; change_pc(R.PC.w.l); }
+static void jmp_3(void) { UINT8 i=M_RDOP(R.PC.w.l); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; R.PC.w.l = i | 0x300 | a11; change_pc(R.PC.w.l); }
+static void jmp_4(void) { UINT8 i=M_RDOP(R.PC.w.l); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; R.PC.w.l = i | 0x400 | a11; change_pc(R.PC.w.l); }
+static void jmp_5(void) { UINT8 i=M_RDOP(R.PC.w.l); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; R.PC.w.l = i | 0x500 | a11; change_pc(R.PC.w.l); }
+static void jmp_6(void) { UINT8 i=M_RDOP(R.PC.w.l); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; R.PC.w.l = i | 0x600 | a11; change_pc(R.PC.w.l); }
+static void jmp_7(void) { UINT8 i=M_RDOP(R.PC.w.l); UINT16 a11 = (R.irq_executing == I8039_NO_INT) ? R.A11 : 0; R.PC.w.l = i | 0x700 | a11; change_pc(R.PC.w.l); }
+static void jmpp_xa(void) { UINT16 addr = (R.PC.w.l & 0xf00) | R.A; R.PC.w.l = (R.PC.w.l & 0xf00) | M_RDMEM(addr); change_pc(R.PC.w.l); }
+static void jb_0(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x01) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jb_1(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x02) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jb_2(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x04) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jb_3(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x08) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jb_4(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x10) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jb_5(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x20) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jb_6(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x40) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jb_7(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x80) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jf0(void) { UINT8 i=M_RDMEM_OPCODE(); if (M_F0y) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jf1(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.f1) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jnc(void) { UINT8 i=M_RDMEM_OPCODE(); if (M_Cn) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jc(void) { UINT8 i=M_RDMEM_OPCODE(); if (M_Cy) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jni(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.irq_state == I8039_EXTERNAL_INT) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jnt_0(void) { UINT8 i=M_RDMEM_OPCODE(); if (!test_r(0)) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jt_0(void) { UINT8 i=M_RDMEM_OPCODE(); if (test_r(0)) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jnt_1(void) { UINT8 i=M_RDMEM_OPCODE(); if (!test_r(1)) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jt_1(void) { UINT8 i=M_RDMEM_OPCODE(); if (test_r(1)) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jnz(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jz(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A == 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); } else ADJUST_CYCLES }
+static void jtf(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.t_flag) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; change_pc(R.PC.w.l); R.t_flag = 0; } else ADJUST_CYCLES }
+static void mov_a_n(void) { R.A = M_RDMEM_OPCODE(); }
+static void mov_a_r0(void) { R.A = R0; }
+static void mov_a_r1(void) { R.A = R1; }
+static void mov_a_r2(void) { R.A = R2; }
+static void mov_a_r3(void) { R.A = R3; }
+static void mov_a_r4(void) { R.A = R4; }
+static void mov_a_r5(void) { R.A = R5; }
+static void mov_a_r6(void) { R.A = R6; }
+static void mov_a_r7(void) { R.A = R7; }
+static void mov_a_psw(void) { R.A = R.PSW; }
+static void mov_a_xr0(void) { R.A = intRAM[R0 & 0x7f]; }
+static void mov_a_xr1(void) { R.A = intRAM[R1 & 0x7f]; }
+static void mov_r0_a(void) { R0 = R.A; }
+static void mov_r1_a(void) { R1 = R.A; }
+static void mov_r2_a(void) { R2 = R.A; }
+static void mov_r3_a(void) { R3 = R.A; }
+static void mov_r4_a(void) { R4 = R.A; }
+static void mov_r5_a(void) { R5 = R.A; }
+static void mov_r6_a(void) { R6 = R.A; }
+static void mov_r7_a(void) { R7 = R.A; }
+static void mov_psw_a(void) { R.PSW = R.A; regPTR = ((M_By) ? 24 : 0); R.SP = (R.PSW & 7) << 1; }
+static void mov_r0_n(void) { R0 = M_RDMEM_OPCODE(); }
+static void mov_r1_n(void) { R1 = M_RDMEM_OPCODE(); }
+static void mov_r2_n(void) { R2 = M_RDMEM_OPCODE(); }
+static void mov_r3_n(void) { R3 = M_RDMEM_OPCODE(); }
+static void mov_r4_n(void) { R4 = M_RDMEM_OPCODE(); }
+static void mov_r5_n(void) { R5 = M_RDMEM_OPCODE(); }
+static void mov_r6_n(void) { R6 = M_RDMEM_OPCODE(); }
+static void mov_r7_n(void) { R7 = M_RDMEM_OPCODE(); }
+static void mov_a_t(void) { R.A = R.timer; }
+static void mov_t_a(void) { R.timer = R.A; }
+static void mov_xr0_a(void) { intRAM[R0 & 0x7f] = R.A; }
+static void mov_xr1_a(void) { intRAM[R1 & 0x7f] = R.A; }
+static void mov_xr0_n(void) { intRAM[R0 & 0x7f] = M_RDMEM_OPCODE(); }
+static void mov_xr1_n(void) { intRAM[R1 & 0x7f] = M_RDMEM_OPCODE(); }
+static void movd_a_p4(void) { R.A = port_r(4); }
+static void movd_a_p5(void) { R.A = port_r(5); }
+static void movd_a_p6(void) { R.A = port_r(6); }
+static void movd_a_p7(void) { R.A = port_r(7); }
+static void movd_p4_a(void) { port_w(4, R.A); }
+static void movd_p5_a(void) { port_w(5, R.A); }
+static void movd_p6_a(void) { port_w(6, R.A); }
+static void movd_p7_a(void) { port_w(7, R.A); }
+static void movp_a_xa(void) { R.A = M_RDMEM((R.PC.w.l & 0x0f00) | R.A); }
+static void movp3_a_xa(void) { R.A = M_RDMEM(0x300 | R.A); }
+static void movx_a_xr0(void) { R.A = M_IN(R0); }
+static void movx_a_xr1(void) { R.A = M_IN(R1); }
+static void movx_xr0_a(void) { M_OUT(R0, R.A); }
+static void movx_xr1_a(void) { M_OUT(R1, R.A); }
+static void nop(void) { }
+static void orl_a_n(void) { R.A |= M_RDMEM_OPCODE(); }
+static void orl_a_r0(void) { R.A |= R0; }
+static void orl_a_r1(void) { R.A |= R1; }
+static void orl_a_r2(void) { R.A |= R2; }
+static void orl_a_r3(void) { R.A |= R3; }
+static void orl_a_r4(void) { R.A |= R4; }
+static void orl_a_r5(void) { R.A |= R5; }
+static void orl_a_r6(void) { R.A |= R6; }
+static void orl_a_r7(void) { R.A |= R7; }
+static void orl_a_xr0(void) { R.A |= intRAM[R0 & 0x7f]; }
+static void orl_a_xr1(void) { R.A |= intRAM[R1 & 0x7f]; }
+static void orl_bus_n(void) { bus_w( bus_r() | M_RDMEM_OPCODE() ); }
+static void orl_p1_n(void) { R.P1 |= M_RDMEM_OPCODE(); port_w(1, R.P1); }
+static void orl_p2_n(void) { R.P2 |= M_RDMEM_OPCODE(); port_w(2, R.P2); }
+static void orld_p4_a(void) { port_w(4, port_r(4) | R.A ); }
+static void orld_p5_a(void) { port_w(5, port_r(5) | R.A ); }
+static void orld_p6_a(void) { port_w(6, port_r(6) | R.A ); }
+static void orld_p7_a(void) { port_w(7, port_r(7) | R.A ); }
+static void outl_bus_a(void) { bus_w(R.A); }
+static void outl_p1_a(void) { port_w(1, R.A); R.P1 = R.A; }
+static void outl_p2_a(void) { port_w(2, R.A); R.P2 = R.A; }
+static void ret(void) { R.PC.w.l = ((pull() & 0x0f) << 8); R.PC.w.l |= pull(); change_pc(R.PC.w.l); }
+
+static void retr(void)
+{
+ UINT8 i=pull();
+ R.PC.w.l = ((i & 0x0f) << 8) | pull();
+ change_pc(R.PC.w.l);
+ R.PSW = (R.PSW & 0x0f) | (i & 0xf0); /* Stack is already changed by pull */
+ regPTR = ((M_By) ? 24 : 0);
+
+ R.irq_executing = I8039_NO_INT;
+
+ /* Take an interrupt if a request is still being made */
+ if (R.irq_state == I8039_EXTERNAL_INT) {
+ R.irq_extra_cycles += Ext_IRQ(); /* Service External IRQ */
+ }
+ else if (R.pending_irq == I8039_TIMCNT_INT) {
+ R.irq_extra_cycles += Timer_IRQ(); /* Service pending Timer/Counter IRQ */
+ }
+}
+static void rl_a(void) { UINT8 i=R.A & 0x80; R.A <<= 1; if (i) R.A |= 0x01; else R.A &= 0xfe; }
+/* NS990113 */
+static void rlc_a(void) { UINT8 i=M_Cy; if (R.A & 0x80) SET(C_FLAG); else CLR(C_FLAG); R.A <<= 1; if (i) R.A |= 0x01; else R.A &= 0xfe; }
+static void rr_a(void) { UINT8 i=R.A & 1; R.A >>= 1; if (i) R.A |= 0x80; else R.A &= 0x7f; }
+/* NS990113 */
+static void rrc_a(void) { UINT8 i=M_Cy; if (R.A & 1) SET(C_FLAG); else CLR(C_FLAG); R.A >>= 1; if (i) R.A |= 0x80; else R.A &= 0x7f; }
+static void sel_mb0(void) { R.A11 = 0x000; }
+static void sel_mb1(void) { R.A11 = 0x800; }
+static void sel_rb0(void) { CLR(B_FLAG); regPTR = 0; }
+static void sel_rb1(void) { SET(B_FLAG); regPTR = 24; }
+static void stop_tcnt(void) { R.timerON = R.countON = 0; }
+static void strt_cnt(void) { R.countON = 1; R.timerON = 0; Old_T1 = test_r(1); } /* NS990113 */
+static void strt_t(void) { R.timerON = 1; R.countON = 0; R.masterClock = 0; } /* NS990113 */
+static void swap_a(void) { UINT8 i=R.A >> 4; R.A <<= 4; R.A |= i; }
+static void xch_a_r0(void) { UINT8 i=R.A; R.A=R0; R0=i; }
+static void xch_a_r1(void) { UINT8 i=R.A; R.A=R1; R1=i; }
+static void xch_a_r2(void) { UINT8 i=R.A; R.A=R2; R2=i; }
+static void xch_a_r3(void) { UINT8 i=R.A; R.A=R3; R3=i; }
+static void xch_a_r4(void) { UINT8 i=R.A; R.A=R4; R4=i; }
+static void xch_a_r5(void) { UINT8 i=R.A; R.A=R5; R5=i; }
+static void xch_a_r6(void) { UINT8 i=R.A; R.A=R6; R6=i; }
+static void xch_a_r7(void) { UINT8 i=R.A; R.A=R7; R7=i; }
+static void xch_a_xr0(void) { UINT8 i=R.A; R.A=intRAM[R0 & 0x7f]; intRAM[R0 & 0x7f]=i; }
+static void xch_a_xr1(void) { UINT8 i=R.A; R.A=intRAM[R1 & 0x7f]; intRAM[R1 & 0x7f]=i; }
+static void xchd_a_xr0(void) { M_XCHD(R0 & 0x7f); }
+static void xchd_a_xr1(void) { M_XCHD(R1 & 0x7f); }
+static void xrl_a_n(void) { R.A ^= M_RDMEM_OPCODE(); }
+static void xrl_a_r0(void) { R.A ^= R0; }
+static void xrl_a_r1(void) { R.A ^= R1; }
+static void xrl_a_r2(void) { R.A ^= R2; }
+static void xrl_a_r3(void) { R.A ^= R3; }
+static void xrl_a_r4(void) { R.A ^= R4; }
+static void xrl_a_r5(void) { R.A ^= R5; }
+static void xrl_a_r6(void) { R.A ^= R6; }
+static void xrl_a_r7(void) { R.A ^= R7; }
+static void xrl_a_xr0(void) { R.A ^= intRAM[R0 & 0x7f]; }
+static void xrl_a_xr1(void) { R.A ^= intRAM[R1 & 0x7f]; }
+
+static s_opcode opcode_main[256]=
+{
+ {1, nop },{0, illegal },{2, outl_bus_a },{2, add_a_n },{2, jmp },{1, en_i },{0, illegal },{1, dec_a },
+ {2, ins_a_bus },{2, in_a_p1 },{2, in_a_p2 },{0, illegal },{2, movd_a_p4 },{2, movd_a_p5 },{2, movd_a_p6 },{2, movd_a_p7 },
+ {1, inc_xr0 },{1, inc_xr1 },{2, jb_0 },{2, adc_a_n },{2, call },{1, dis_i },{2, jtf },{1, inc_a },
+ {1, inc_r0 },{1, inc_r1 },{1, inc_r2 },{1, inc_r3 },{1, inc_r4 },{1, inc_r5 },{1, inc_r6 },{1, inc_r7 },
+ {1, xch_a_xr0 },{1, xch_a_xr1 },{0, illegal },{2, mov_a_n },{2, jmp_1 },{1, en_tcnti },{2, jnt_0 },{1, clr_a },
+ {1, xch_a_r0 },{1, xch_a_r1 },{1, xch_a_r2 },{1, xch_a_r3 },{1, xch_a_r4 },{1, xch_a_r5 },{1, xch_a_r6 },{1, xch_a_r7 },
+ {1, xchd_a_xr0 },{1, xchd_a_xr1 },{2, jb_1 },{0, illegal },{2, call_1 },{1, dis_tcnti },{2, jt_0 },{1, cpl_a },
+ {0, illegal },{2, outl_p1_a },{2, outl_p2_a },{0, illegal },{2, movd_p4_a },{2, movd_p5_a },{2, movd_p6_a },{2, movd_p7_a },
+ {1, orl_a_xr0 },{1, orl_a_xr1 },{1, mov_a_t },{2, orl_a_n },{2, jmp_2 },{1, strt_cnt },{2, jnt_1 },{1, swap_a },
+ {1, orl_a_r0 },{1, orl_a_r1 },{1, orl_a_r2 },{1, orl_a_r3 },{1, orl_a_r4 },{1, orl_a_r5 },{1, orl_a_r6 },{1, orl_a_r7 },
+ {1, anl_a_xr0 },{1, anl_a_xr1 },{2, jb_2 },{2, anl_a_n },{2, call_2 },{1, strt_t },{2, jt_1 },{1, daa_a },
+ {1, anl_a_r0 },{1, anl_a_r1 },{1, anl_a_r2 },{1, anl_a_r3 },{1, anl_a_r4 },{1, anl_a_r5 },{1, anl_a_r6 },{1, anl_a_r7 },
+ {1, add_a_xr0 },{1, add_a_xr1 },{1, mov_t_a },{0, illegal },{2, jmp_3 },{1, stop_tcnt },{0, illegal },{1, rrc_a },
+ {1, add_a_r0 },{1, add_a_r1 },{1, add_a_r2 },{1, add_a_r3 },{1, add_a_r4 },{1, add_a_r5 },{1, add_a_r6 },{1, add_a_r7 },
+ {1, adc_a_xr0 },{1, adc_a_xr1 },{2, jb_3 },{0, illegal },{2, call_3 },{1, ento_clk },{2, jf1 },{1, rr_a },
+ {1, adc_a_r0 },{1, adc_a_r1 },{1, adc_a_r2 },{1, adc_a_r3 },{1, adc_a_r4 },{1, adc_a_r5 },{1, adc_a_r6 },{1, adc_a_r7 },
+ {2, movx_a_xr0 },{2, movx_a_xr1 },{0, illegal },{2, ret },{2, jmp_4 },{1, clr_f0 },{2, jni },{0, illegal },
+ {2, orl_bus_n },{2, orl_p1_n },{2, orl_p2_n },{0, illegal },{2, orld_p4_a },{2, orld_p5_a },{2, orld_p6_a },{2, orld_p7_a },
+ {2, movx_xr0_a },{2, movx_xr1_a },{2, jb_4 },{2, retr },{2, call_4 },{1, cpl_f0 },{2, jnz },{1, clr_c },
+ {2, anl_bus_n },{2, anl_p1_n },{2, anl_p2_n },{0, illegal },{2, anld_p4_a },{2, anld_p5_a },{2, anld_p6_a },{2, anld_p7_a },
+ {1, mov_xr0_a },{1, mov_xr1_a },{0, illegal },{2, movp_a_xa },{2, jmp_5 },{1, clr_f1 },{0, illegal },{1, cpl_c },
+ {1, mov_r0_a },{1, mov_r1_a },{1, mov_r2_a },{1, mov_r3_a },{1, mov_r4_a },{1, mov_r5_a },{1, mov_r6_a },{1, mov_r7_a },
+ {2, mov_xr0_n },{2, mov_xr1_n },{2, jb_5 },{2, jmpp_xa },{2, call_5 },{1, cpl_f1 },{2, jf0 },{0, illegal },
+ {2, mov_r0_n },{2, mov_r1_n },{2, mov_r2_n },{2, mov_r3_n },{2, mov_r4_n },{2, mov_r5_n },{2, mov_r6_n },{2, mov_r7_n },
+ {0, illegal },{0, illegal },{0, illegal },{0, illegal },{2, jmp_6 },{1, sel_rb0 },{2, jz },{1, mov_a_psw },
+ {1, dec_r0 },{1, dec_r1 },{1, dec_r2 },{1, dec_r3 },{1, dec_r4 },{1, dec_r5 },{1, dec_r6 },{1, dec_r7 },
+ {1, xrl_a_xr0 },{1, xrl_a_xr1 },{2, jb_6 },{2, xrl_a_n },{2, call_6 },{1, sel_rb1 },{0, illegal },{1, mov_psw_a },
+ {1, xrl_a_r0 },{1, xrl_a_r1 },{1, xrl_a_r2 },{1, xrl_a_r3 },{1, xrl_a_r4 },{1, xrl_a_r5 },{1, xrl_a_r6 },{1, xrl_a_r7 },
+ {0, illegal },{0, illegal },{0, illegal },{2, movp3_a_xa },{2, jmp_7 },{1, sel_mb0 },{2, jnc },{1, rl_a },
+ {2, djnz_r0 },{2, djnz_r1 },{2, djnz_r2 },{2, djnz_r3 },{2, djnz_r4 },{2, djnz_r5 },{2, djnz_r6 },{2, djnz_r7 },
+ {1, mov_a_xr0 },{1, mov_a_xr1 },{2, jb_7 },{0, illegal },{2, call_7 },{1, sel_mb1 },{2, jc },{1, rlc_a },
+ {1, mov_a_r0 },{1, mov_a_r1 },{1, mov_a_r2 },{1, mov_a_r3 },{1, mov_a_r4 },{1, mov_a_r5 },{1, mov_a_r6 },{1, mov_a_r7 }
+};
+
+
+
+
+/****************************************************************************
+ * Initialize emulation
+ ****************************************************************************/
+static void i8039_init (int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ R.irq_callback = irqcallback;
+
+ state_save_register_item("i8039", index, R.PC.w.l);
+ state_save_register_item("i8039", index, R.PREVPC.w.l);
+ state_save_register_item("i8039", index, R.A);
+ state_save_register_item("i8039", index, R.SP);
+ state_save_register_item("i8039", index, R.PSW);
+ state_save_register_item_array("i8039", index, R.RAM);
+ state_save_register_item("i8039", index, R.bus);
+ state_save_register_item("i8039", index, R.f1);
+ state_save_register_item("i8039", index, R.P1);
+ state_save_register_item("i8039", index, R.P2);
+ state_save_register_item("i8039", index, R.pending_irq);
+ state_save_register_item("i8039", index, R.irq_executing);
+ state_save_register_item("i8039", index, R.masterClock);
+ state_save_register_item("i8039", index, R.regPtr);
+ state_save_register_item("i8039", index, R.t_flag);
+ state_save_register_item("i8039", index, R.timer);
+ state_save_register_item("i8039", index, R.timerON);
+ state_save_register_item("i8039", index, R.countON);
+ state_save_register_item("i8039", index, R.xirq_en);
+ state_save_register_item("i8039", index, R.tirq_en);
+ state_save_register_item("i8039", index, R.A11);
+ state_save_register_item("i8039", index, R.irq_state);
+ state_save_register_item("i8039", index, R.irq_extra_cycles);
+}
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+static void i8039_reset (void)
+{
+ R.PC.w.l = 0;
+ R.SP = 0;
+ R.A = 0;
+ R.PSW = 0x08; /* Start with Carry SET, Bit 4 is always SET */
+ memset(R.RAM, 0x0, 128);
+ R.P1 = 0xff;
+ R.P2 = 0xff;
+ R.bus = 0;
+ R.irq_executing = I8039_NO_INT;
+ R.pending_irq = I8039_NO_INT;
+
+ R.A11 = 0;
+ R.tirq_en = R.xirq_en = 0;
+ R.timerON = R.countON = 0;
+ R.timerON = 1; /* Mario Bros. doesn't work without this */
+ R.irq_extra_cycles = 0;
+ R.masterClock = 0;
+}
+
+
+/****************************************************************************
+ * Shut down CPU emulation
+ ****************************************************************************/
+static void i8039_exit (void)
+{
+ /* nothing to do ? */
+}
+
+/****************************************************************************
+ * Issue an interrupt if necessary
+ ****************************************************************************/
+static int Ext_IRQ(void)
+{
+ int extra_cycles = 0;
+
+ if (R.xirq_en) {
+ if (R.irq_executing == I8039_NO_INT) {
+// logerror("I8039: EXT INTERRUPT being serviced\n");
+ R.irq_executing = I8039_EXTERNAL_INT;
+ push(R.PC.b.l);
+ push((R.PC.b.h & 0x0f) | (R.PSW & 0xf0));
+ R.PC.w.l = 0x03;
+
+ extra_cycles = 2; /* 2 clock cycles used */
+
+ if (R.timerON) /* NS990113 */
+ R.masterClock += extra_cycles;
+ if (R.irq_callback) (*R.irq_callback)(0);
+ }
+ }
+
+ return extra_cycles;
+}
+
+static int Timer_IRQ(void)
+{
+ int extra_cycles = 0;
+
+ if (R.tirq_en) {
+ if (R.irq_executing == I8039_NO_INT) {
+// logerror("I8039: TIMER/COUNTER INTERRUPT\n");
+ R.irq_executing = I8039_TIMCNT_INT;
+ R.pending_irq &= ~I8039_TIMCNT_INT;
+ push(R.PC.b.l);
+ push((R.PC.b.h & 0x0f) | (R.PSW & 0xf0));
+ R.PC.w.l = 0x07;
+ change_pc(0x07);
+
+ extra_cycles = 2; /* 2 clock cycles used */
+
+ if (R.timerON) /* NS990113 */
+ R.masterClock += extra_cycles;
+ }
+ else {
+ if (R.irq_executing == I8039_EXTERNAL_INT) {
+ R.pending_irq |= I8039_TIMCNT_INT;
+ }
+ }
+ }
+
+ R.t_flag = 1;
+
+ return extra_cycles;
+}
+
+
+/****************************************************************************
+ * Execute cycles CPU cycles. Return number of cycles really executed
+ ****************************************************************************/
+static int i8039_execute(int cycles)
+{
+ unsigned opcode, T1;
+ int count;
+
+ i8039_ICount = (cycles - R.irq_extra_cycles);
+ R.irq_extra_cycles = 0;
+
+ do
+ {
+ R.PREVPC = R.PC;
+
+ CALL_MAME_DEBUG;
+
+ opcode=M_RDOP(R.PC.w.l);
+
+/* logerror("I8039: PC = %04x, opcode = %02x\n", R.PC.w.l, opcode); */
+
+ R.PC.w.l++;
+ inst_cycles = opcode_main[opcode].cycles;
+ (*(opcode_main[opcode].function))();
+ i8039_ICount -= inst_cycles; ///
+
+ if (R.countON) /* NS990113 */
+ {
+ for ( ; inst_cycles > 0; inst_cycles-- )
+ {
+ T1 = test_r(1);
+ if (POSITIVE_EDGE_T1)
+ {
+ R.timer++;
+ if (R.timer == 0) {
+ count = Timer_IRQ(); /* Handle Counter IRQ */
+ i8039_ICount -= count;
+ }
+ }
+ Old_T1 = T1;
+ }
+ }
+
+ if (R.timerON) {
+ R.masterClock += opcode_main[opcode].cycles;
+ if (R.masterClock >= 32) { /* NS990113 */
+ R.masterClock -= 32;
+ R.timer++;
+ if (R.timer == 0) {
+ count = Timer_IRQ(); /* Handle Timer IRQ */
+ i8039_ICount -= count;
+ }
+ }
+ }
+ } while (i8039_ICount>0);
+
+ i8039_ICount -= R.irq_extra_cycles;
+ R.irq_extra_cycles = 0;
+
+ return cycles - i8039_ICount;
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void i8039_get_context (void *dst)
+{
+ if( dst )
+ *(I8039_Regs*)dst = R;
+}
+
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void i8039_set_context (void *src)
+{
+ if( src )
+ {
+ R = *(I8039_Regs*)src;
+ regPTR = ((M_By) ? 24 : 0);
+ R.SP = (R.PSW << 1) & 0x0f;
+ change_pc(R.PC.w.l);
+ }
+ /* Handle forced Interrupts throught the Debugger */
+ if (R.irq_state != I8039_NO_INT) {
+ R.irq_extra_cycles += Ext_IRQ(); /* Handle External IRQ */
+ }
+ if (R.timer == 0) {
+ R.irq_extra_cycles += Timer_IRQ(); /* Handle Timer IRQ */
+ }
+}
+
+
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+static void set_irq_line(int irqline, int state)
+{
+ if (state != CLEAR_LINE) {
+ R.irq_state = I8039_EXTERNAL_INT;
+ R.irq_extra_cycles += Ext_IRQ(); /* Handle External IRQ */
+ }
+ else {
+ R.irq_state = I8039_NO_INT;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void i8039_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I8039_PC: R.PC.w.l = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + I8039_SP: R.SP = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_PSW: R.PSW = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_A: R.A = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_TC: R.timer = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_P1: R.P1 = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_P2: R.P2 = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_R0: R0 = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_R1: R1 = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_R2: R2 = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_R3: R3 = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_R4: R4 = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_R5: R5 = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_R6: R6 = info->i; break;
+ case CPUINFO_INT_REGISTER + I8039_R7: R7 = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void i8039_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(R); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = I8039_CLOCK_DIVIDER; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 3; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 12; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 9; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = (R.irq_state == I8039_EXTERNAL_INT) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = R.PREVPC.w.l; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I8039_PC: info->i = R.PC.w.l; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + I8039_SP: info->i = R.SP; break;
+ case CPUINFO_INT_REGISTER + I8039_PSW: info->i = R.PSW; break;
+ case CPUINFO_INT_REGISTER + I8039_A: info->i = R.A; break;
+ case CPUINFO_INT_REGISTER + I8039_TC: info->i = R.timer; break;
+ case CPUINFO_INT_REGISTER + I8039_P1: info->i = R.P1; break;
+ case CPUINFO_INT_REGISTER + I8039_P2: info->i = R.P2; break;
+ case CPUINFO_INT_REGISTER + I8039_R0: info->i = R0; break;
+ case CPUINFO_INT_REGISTER + I8039_R1: info->i = R1; break;
+ case CPUINFO_INT_REGISTER + I8039_R2: info->i = R2; break;
+ case CPUINFO_INT_REGISTER + I8039_R3: info->i = R3; break;
+ case CPUINFO_INT_REGISTER + I8039_R4: info->i = R4; break;
+ case CPUINFO_INT_REGISTER + I8039_R5: info->i = R5; break;
+ case CPUINFO_INT_REGISTER + I8039_R6: info->i = R6; break;
+ case CPUINFO_INT_REGISTER + I8039_R7: info->i = R7; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i8039_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8039_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8039_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8039_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8039_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8039_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8039_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = i8039_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i8039_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8039"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel 8039"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.2"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 1997 by Mirko Buffoni\nBased on the original work (C) 1997 by Dan Boris"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ R.PSW & 0x80 ? 'C':'.',
+ R.PSW & 0x40 ? 'A':'.',
+ R.PSW & 0x20 ? 'F':'.',
+ R.PSW & 0x10 ? 'B':'.',
+ R.PSW & 0x08 ? '?':'.',
+ R.PSW & 0x04 ? '4':'.',
+ R.PSW & 0x02 ? '2':'.',
+ R.PSW & 0x01 ? '1':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + I8039_PC: sprintf(info->s, "PC:%04X", R.PC.w.l); break;
+ case CPUINFO_STR_REGISTER + I8039_SP: sprintf(info->s, "SP:%02X", R.SP); break;
+ case CPUINFO_STR_REGISTER + I8039_PSW: sprintf(info->s, "PSW:%02X", R.PSW); break;
+ case CPUINFO_STR_REGISTER + I8039_A: sprintf(info->s, "A:%02X", R.A); break;
+ case CPUINFO_STR_REGISTER + I8039_TC: sprintf(info->s, "TC:%02X", R.timer); break;
+ case CPUINFO_STR_REGISTER + I8039_P1: sprintf(info->s, "P1:%02X", R.P1); break;
+ case CPUINFO_STR_REGISTER + I8039_P2: sprintf(info->s, "P2:%02X", R.P2); break;
+ case CPUINFO_STR_REGISTER + I8039_R0: sprintf(info->s, "R0:%02X", R.RAM[R.regPtr+0]); break;
+ case CPUINFO_STR_REGISTER + I8039_R1: sprintf(info->s, "R1:%02X", R.RAM[R.regPtr+1]); break;
+ case CPUINFO_STR_REGISTER + I8039_R2: sprintf(info->s, "R2:%02X", R.RAM[R.regPtr+2]); break;
+ case CPUINFO_STR_REGISTER + I8039_R3: sprintf(info->s, "R3:%02X", R.RAM[R.regPtr+3]); break;
+ case CPUINFO_STR_REGISTER + I8039_R4: sprintf(info->s, "R4:%02X", R.RAM[R.regPtr+4]); break;
+ case CPUINFO_STR_REGISTER + I8039_R5: sprintf(info->s, "R5:%02X", R.RAM[R.regPtr+5]); break;
+ case CPUINFO_STR_REGISTER + I8039_R6: sprintf(info->s, "R6:%02X", R.RAM[R.regPtr+6]); break;
+ case CPUINFO_STR_REGISTER + I8039_R7: sprintf(info->s, "R7:%02X", R.RAM[R.regPtr+7]); break;
+ }
+}
+
+
+
+#if (HAS_I8035)
+/**************************************************************************
+ * CPU-specific get_info/set_info
+ **************************************************************************/
+void i8035_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8035"); break;
+
+ default: i8039_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_I8048)
+/**************************************************************************
+ * CPU-specific get_info/set_info
+ **************************************************************************/
+void i8048_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8048"); break;
+
+ default: i8039_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_N7751)
+/**************************************************************************
+ * CPU-specific get_info/set_info
+ **************************************************************************/
+void n7751_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "N7751"); break;
+
+ default: i8039_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/i8039/i8039.h b/src/emu/cpu/i8039/i8039.h
new file mode 100644
index 00000000000..85926da010a
--- /dev/null
+++ b/src/emu/cpu/i8039/i8039.h
@@ -0,0 +1,175 @@
+/**************************************************************************
+ * Intel 8039 Portable Emulator *
+ * *
+ * Copyright (C) 1997 by Mirko Buffoni *
+ * Based on the original work (C) 1997 by Dan Boris, an 8048 emulator *
+ * You are not allowed to distribute this software commercially *
+ * Please, notify me, if you make any changes to this file *
+ **************************************************************************/
+
+#ifndef _I8039_H
+#define _I8039_H
+
+#ifndef INLINE
+#define INLINE static inline
+#endif
+
+#include "cpuintrf.h"
+
+
+/**************************************************************************
+ Internal Clock divisor
+
+ External Clock is divided internally by 3 to produce the machine state
+ generator. This is then divided by 5 for the instruction cycle times.
+ (Each instruction cycle passes through 5 machine states).
+*/
+
+#define I8039_CLOCK_DIVIDER (3*5)
+
+
+
+enum { I8039_PC=1, I8039_SP, I8039_PSW, I8039_A, I8039_TC,
+ I8039_P1, I8039_P2, I8039_R0, I8039_R1, I8039_R2,
+ I8039_R3, I8039_R4, I8039_R5, I8039_R6, I8039_R7
+};
+
+extern void i8039_get_info(UINT32 state, cpuinfo *info);
+
+/* This handling of special I/O ports should be better for actual MAME
+ * architecture. (i.e., define access to ports { I8039_p1, I8039_p1, dkong_out_w })
+ */
+
+#define I8039_p0 0x100 /* Not used */
+#define I8039_p1 0x101
+#define I8039_p2 0x102
+#define I8039_p4 0x104
+#define I8039_p5 0x105
+#define I8039_p6 0x106
+#define I8039_p7 0x107
+#define I8039_t0 0x110
+#define I8039_t1 0x111
+#define I8039_bus 0x120
+
+/**************************************************************************
+ * I8035 section
+ **************************************************************************/
+#if (HAS_I8035)
+#define I8035_PC I8039_PC
+#define I8035_SP I8039_SP
+#define I8035_PSW I8039_PSW
+#define I8035_A I8039_A
+#define I8035_TC I8039_TC
+#define I8035_P1 I8039_P1
+#define I8035_P2 I8039_P2
+#define I8035_R0 I8039_R0
+#define I8035_R1 I8039_R1
+#define I8035_R2 I8039_R2
+#define I8035_R3 I8039_R3
+#define I8035_R4 I8039_R4
+#define I8035_R5 I8039_R5
+#define I8035_R6 I8039_R6
+#define I8035_R7 I8039_R7
+
+#define I8035_CLOCK_DIVIDER I8039_CLOCK_DIVIDER
+#define i8035_ICount i8039_ICount
+
+extern void i8035_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/**************************************************************************
+ * I8048 section
+ **************************************************************************/
+#if (HAS_I8048)
+#define I8048_PC I8039_PC
+#define I8048_SP I8039_SP
+#define I8048_PSW I8039_PSW
+#define I8048_A I8039_A
+#define I8048_TC I8039_TC
+#define I8048_P1 I8039_P1
+#define I8048_P2 I8039_P2
+#define I8048_R0 I8039_R0
+#define I8048_R1 I8039_R1
+#define I8048_R2 I8039_R2
+#define I8048_R3 I8039_R3
+#define I8048_R4 I8039_R4
+#define I8048_R5 I8039_R5
+#define I8048_R6 I8039_R6
+#define I8048_R7 I8039_R7
+
+#define I8048_CLOCK_DIVIDER I8039_CLOCK_DIVIDER
+#define i8048_ICount i8039_ICount
+
+extern void i8048_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/**************************************************************************
+ * N7751 section
+ **************************************************************************/
+#if (HAS_N7751)
+#define N7751_PC I8039_PC
+#define N7751_SP I8039_SP
+#define N7751_PSW I8039_PSW
+#define N7751_A I8039_A
+#define N7751_TC I8039_TC
+#define N7751_P1 I8039_P1
+#define N7751_P2 I8039_P2
+#define N7751_R0 I8039_R0
+#define N7751_R1 I8039_R1
+#define N7751_R2 I8039_R2
+#define N7751_R3 I8039_R3
+#define N7751_R4 I8039_R4
+#define N7751_R5 I8039_R5
+#define N7751_R6 I8039_R6
+#define N7751_R7 I8039_R7
+
+#define N7751_CLOCK_DIVIDER I8039_CLOCK_DIVIDER
+#define n7751_ICount i8039_ICount
+
+extern void n7751_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/*
+ * Input a UINT8 from given I/O port
+ */
+#define I8039_In(Port) ((UINT8)io_read_byte_8(Port))
+
+
+/*
+ * Output a UINT8 to given I/O port
+ */
+#define I8039_Out(Port,Value) (io_write_byte_8(Port,Value))
+
+
+/*
+ * Read a UINT8 from given memory location
+ */
+#define I8039_RDMEM(A) ((unsigned)program_read_byte_8(A))
+
+
+/*
+ * Write a UINT8 to given memory location
+ */
+#define I8039_WRMEM(A,V) (program_write_byte_8(A,V))
+
+
+/*
+ * I8039_RDOP() is identical to I8039_RDMEM() except it is used for reading
+ * opcodes. In case of system with memory mapped I/O, this function can be
+ * used to greatly speed up emulation
+ */
+#define I8039_RDOP(A) ((unsigned)cpu_readop(A))
+
+
+/*
+ * I8039_RDOP_ARG() is identical to I8039_RDOP() except it is used for reading
+ * opcode arguments. This difference can be used to support systems that
+ * use different encoding mechanisms for opcodes and opcode arguments
+ */
+#define I8039_RDOP_ARG(A) ((unsigned)cpu_readop_arg(A))
+
+#ifdef MAME_DEBUG
+offs_t i8039_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _I8039_H */
diff --git a/src/emu/cpu/i8051/8051dasm.c b/src/emu/cpu/i8051/8051dasm.c
new file mode 100644
index 00000000000..fa98d8aaab9
--- /dev/null
+++ b/src/emu/cpu/i8051/8051dasm.c
@@ -0,0 +1,1034 @@
+/*****************************************************************************
+ *
+ * i8051dasm.c
+ * Portable MCS-51 Family Emulator
+ *
+ * Chips in the family:
+ * 8051 Product Line (8031,8051,8751)
+ * 8052 Product Line (8032,8052,8752)
+ * 8054 Product Line (8054)
+ * 8058 Product Line (8058)
+ *
+ * Copyright (c) 2003 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Intel(tm) MC51 Microcontroller Family Users Manual' and
+ * #2) 8051 simulator by Travis Marlatte
+ * #3) Portable UPI-41/8041/8741/8042/8742 emulator V0.1 by Juergen Buchmueller (MAME CORE)
+ *
+ *****************************************************************************
+ * Symbol Memory Name Tables borrowed from:
+ * D52 8052 Disassembler - Copyright (C) 1995-2002 by
+ * Jeffery L. Post
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "i8051.h"
+
+#define SHOW_MEMORY_NAMES 1
+
+#ifdef SHOW_MEMORY_NAMES
+
+/*Display the memory address names for data & bit address access*/
+
+//SFR Names
+static const char sfr[128][7] = {
+ "p0", "sp", "dpl", "dph", /* 80 - 83 */
+ "adat", "85h", "86h", "pcon", /* 84 - 87 */
+ "tcon", "tmod", "tl0", "tl1", /* 88 - 8b */
+ "th0", "th1", "pwcm", "pwmp", /* 8a - 8f */
+ "p1", "91h", "92h", "93h", /* 90 - 93 */
+ "94h", "95h", "96h", "97h", /* 94 - 97 */
+ "scon", "sbuf", "9ah", "9bh", /* 98 - 9b */
+ "9ch", "9dh", "9eh", "9fh", /* 9c - 9f */
+ "p2", "0a1h", "0a2h", "0a3h", /* a0 - a3 */
+ "0a4h", "0a5h", "0a6h", "0a7h", /* a4 - a7 */
+ "ie", "cml0", "cml1", "cml2", /* a8 - ab */
+ "ctl0", "ctl1", "ctl2", "ctl3", /* ac - af */
+ "p3", "0b1h", "0b2h", "0b3h", /* b0 - b3 */
+ "0b4h", "0b5h", "0b6h", "0b7h", /* b4 - b7 */
+ "ip", "0b9h", "0bah", "0bbh", /* b8 - bb */
+ "0bch", "0bdh", "0beh", "0bfh", /* bc - bf */
+ "p4", "0c1h", "0c2h", "0c3h", /* c0 - c3 */
+ "p5", "adcon", "adch", "0c7h", /* c4 - c7 */
+ "t2con", "cmh0", "rcap2l", "rcap2h", /* c8 - cb */
+ "tl2", "th2", "cth2", "cth3", /* cc - cf */
+ "psw", "0d1h", "0d2h", "0d3h", /* d0 - d3 */
+ "0d4h", "0d5h", "0d6h", "0d7h", /* d4 - d7 */
+ "i2cfg", "s1sta", "s1dat", "s1adr", /* d8 - db */
+ "0dch", "0ddh", "0deh", "0dfh", /* dc - df */
+ "acc", "0e1h", "0e2h", "0e3h", /* e0 - e3 */
+ "0e4h", "0e5h", "0e6h", "0e7h", /* e4 - e7 */
+ "csr", "0e9h", "tm2con", "ctcon", /* e8 - eb */
+ "tml2", "tmh2", "ste", "rte", /* ec - ef */
+ "b", "0f1h", "0f2h", "0f3h", /* f0 - f3 */
+ "0f4h", "0f5h", "0f6h", "0f7h", /* f4 - f7 */
+ "i2sta", "0f9h", "0fah", "0fbh", /* f8 - fb */
+ "pwm0", "pwm1", "pwena", "t3" /* fc - ff */
+};
+
+//SFR Addressable bits
+static const char sfrbits[128][8] = {
+ "p0.0", "p0.1", "p0.2", "p0.3", /* 80 - 83 */
+ "p0.4", "p0.5", "p0.6", "p0.7", /* 84 - 87 */
+ "it0", "ie0", "it1", "ie1", /* 88 - 8b */
+ "tr0", "tf0", "tr1", "tf1", /* 8c - 8f */
+ "p1.0", "p1.1", "p1.2", "p1.3", /* 90 - 93 */
+ "p1.4", "p1.5", "p1.6", "p1.7", /* 94 - 97 */
+ "ri", "ti", "rb8", "tb8", /* 98 - 9b */
+ "ren", "sm2", "sm1", "sm0", /* 9c - 9f */
+ "p2.0", "p2.1", "p2.2", "p2.3", /* a0 - a3 */
+ "p2.4", "p2.5", "p2.6", "p2.7", /* a4 - a7 */
+ "ex0", "et0", "ex1", "et1", /* a8 - ab */
+ "es", "ie.5", "ie.6", "ea", /* ac - af */
+ "rxd", "txd", "int0", "int1", /* b0 - b3 */
+ "t0", "t1", "wr", "rd", /* b4 - b7 */
+ "px0", "pt0", "px1", "pt1", /* b8 - bb */
+ "ps", "ip.5", "ip.6", "ip.7", /* bc - bf */
+ "0c0h.0", "0c0h.1", "0c0h.2", "0c0h.3", /* c0 - c3 */
+ "0c0h.4", "0c0h.5", "0c0h.6", "0c0h.7", /* c4 - c7 */
+ "cprl2", "ct2", "tr2", "exen2", /* c8 - cb */
+ "tclk", "rclk", "exf2", "tf2", /* cc - cf */
+ "p", "psw.1", "ov", "rs0", /* d0 - d3 */
+ "rs1", "f0", "ac", "cy", /* d4 - d7 */
+ "ct0", "ct1", "i2cfg.2","i2cfg.3",/* d8 - db */
+ "tirun", "clrti", "mastrq", "slaven", /* dc - df */
+ "acc.0", "acc.1", "acc.2", "acc.3", /* e0 - e3 */
+ "acc.4", "acc.5", "acc.6", "acc.7", /* e4 - e7 */
+ "ibf", "obf", "idsm", "obfc", /* e8 - eb */
+ "ma0", "ma1", "mb0", "mb1", /* ec - ef */
+ "b.0", "b.1", "b.2", "b.3", /* f0 - f3 */
+ "b.4", "b.5", "b.6", "b.7", /* f4 - f7 */
+ "xstp", "xstr", "makstp", "makstr", /* f8 - fb */
+ "xactv", "xdata", "idle", "i2sta.7" /* fc - ff */
+} ;
+
+//Names for bit addressable memory
+static const char membits[128][6] = {
+ "20h.0", "20h.1", "20h.2", "20h.3",
+ "20h.4", "20h.5", "20h.6", "20h.7",
+ "21h.0", "21h.1", "21h.2", "21h.3",
+ "21h.4", "21h.5", "21h.6", "21h.7",
+ "22h.0", "22h.1", "22h.2", "22h.3",
+ "22h.4", "22h.5", "22h.6", "22h.7",
+ "23h.0", "23h.1", "23h.2", "23h.3",
+ "23h.4", "23h.5", "23h.6", "23h.7",
+ "24h.0", "24h.1", "24h.2", "24h.3",
+ "24h.4", "24h.5", "24h.6", "24h.7",
+ "25h.0", "25h.1", "25h.2", "25h.3",
+ "25h.4", "25h.5", "25h.6", "25h.7",
+ "26h.0", "26h.1", "26h.2", "26h.3",
+ "26h.4", "26h.5", "26h.6", "26h.7",
+ "27h.0", "27h.1", "27h.2", "27h.3",
+ "27h.4", "27h.5", "27h.6", "27h.7",
+ "28h.0", "28h.1", "28h.2", "28h.3",
+ "28h.4", "28h.5", "28h.6", "28h.7",
+ "29h.0", "29h.1", "29h.2", "29h.3",
+ "29h.4", "29h.5", "29h.6", "29h.7",
+ "2ah.0", "2ah.1", "2ah.2", "2ah.3",
+ "2ah.4", "2ah.5", "2ah.6", "2ah.7",
+ "2bh.0", "2bh.1", "2bh.2", "2bh.3",
+ "2bh.4", "2bh.5", "2bh.6", "2bh.7",
+ "2ch.0", "2ch.1", "2ch.2", "2ch.3",
+ "2ch.4", "2ch.5", "2ch.6", "2ch.7",
+ "2dh.0", "2dh.1", "2dh.2", "2dh.3",
+ "2dh.4", "2dh.5", "2dh.6", "2dh.7",
+ "2eh.0", "2eh.1", "2eh.2", "2eh.3",
+ "2eh.4", "2eh.5", "2eh.6", "2eh.7",
+ "2fh.0", "2fh.1", "2fh.2", "2fh.3",
+ "2fh.4", "2fh.5", "2fh.6", "2fh.7"
+};
+
+//Regiser Bank memory names
+static const char regbank[][6] = {
+ "rb0r0", "rb0r1", "rb0r2", "rb0r3",
+ "rb0r4", "rb0r5", "rb0r6", "rb0r7",
+ "rb1r0", "rb1r1", "rb1r2", "rb1r3",
+ "rb1r4", "rb1r5", "rb1r6", "rb1r7",
+ "rb2r0", "rb2r1", "rb2r2", "rb2r3",
+ "rb2r4", "rb2r5", "rb2r6", "rb2r7",
+ "rb3r0", "rb3r1", "rb3r2", "rb3r3",
+ "rb3r4", "rb3r5", "rb3r6", "rb3r7"
+};
+
+static const char *get_data_address( UINT8 arg )
+{
+ char *buffer = cpuintrf_temp_str();
+
+ if(arg < 0x80)
+ {
+ //Ram locations 0-0x1F are considered register access in 3 banks
+ if(arg < 0x1f)
+ sprintf(buffer,"%s",regbank[arg]);
+ else
+ sprintf(buffer,"$%02X",arg);
+ }
+ else
+ sprintf(buffer,"%s",sfr[arg-0x80]);
+ return buffer;
+}
+
+static const char *get_bit_address( UINT8 arg )
+{
+ char *buffer = cpuintrf_temp_str();
+
+ if(arg < 0x80)
+ {
+ //Bit address 0-7F can be referred to as 20.0, 20.1, to 20.7 for address 0, and 2f.0,2f.1 to 2f.7 for address 7f
+ if(arg < 0x7f)
+ sprintf(buffer,"%s",membits[arg]);
+ else
+ sprintf(buffer,"$%02X",arg);
+ }
+ else
+ sprintf(buffer,"%s",sfrbits[arg-0x80]);
+ return buffer;
+}
+
+#else
+
+/*Just display the actual memory address for data & bit address access*/
+
+static const char *get_data_address( UINT8 arg )
+{
+ char *buffer = cpuintrf_temp_str();
+ sprintf(buffer,"$%02X",arg);
+ return buffer;
+}
+
+static const char *get_bit_address( UINT8 arg )
+{
+ char *buffer = cpuintrf_temp_str();
+ sprintf(buffer,"$%02X",arg);
+ return buffer;
+}
+
+#endif
+
+
+unsigned i8051_dasm(char *dst, unsigned pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ unsigned PC = pc;
+ const char *sym, *sym2;
+ UINT8 op, data;
+ UINT16 addr;
+ INT8 rel;
+
+ op = oprom[PC++ - pc];
+ switch( op )
+ {
+ //NOP
+ case 0x00: /* 1: 0000 0000 */
+ sprintf(dst, "nop");
+ break;
+
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x01:
+ case 0x21:
+ case 0x41:
+ case 0x61:
+ case 0x81:
+ case 0xa1:
+ case 0xc1:
+ case 0xe1:
+ addr = opram[PC++ - pc];
+ addr|= (PC++ & 0xf800) | ((op & 0xe0) << 3);
+ sprintf(dst, "ajmp $%04X", addr);
+ break;
+
+ //LJMP code addr
+ case 0x02: /* 1: 0000 0010 */
+ addr = (opram[PC++ - pc]<<8) & 0xff00;
+ addr|= opram[PC++ - pc];
+ sprintf(dst, "ljmp $%04X", addr);
+ break;
+
+ //RR A
+ case 0x03: /* 1: 0000 0011 */
+ sprintf(dst, "rr a");
+ break;
+
+ //INC A
+ case 0x04: /* 1: 0000 0100 */
+ sprintf(dst, "inc a");
+ break;
+
+ //INC data addr
+ case 0x05: /* 1: 0000 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "inc %s", sym);
+ break;
+
+ //INC @R0/@R1 /* 1: 0000 011i */
+ case 0x06:
+ case 0x07:
+ sprintf(dst, "inc @r%d", op&1);
+ break;
+
+ //INC R0 to R7 /* 1: 0000 1rrr */
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ sprintf(dst, "inc r%d", op&7);
+ break;
+
+ //JBC bit addr, code addr
+ case 0x10: /* 1: 0001 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jbc %s,$%04X", sym, PC + rel);
+ break;
+
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x11:
+ case 0x31:
+ case 0x51:
+ case 0x71:
+ case 0x91:
+ case 0xb1:
+ case 0xd1:
+ case 0xf1:
+ sprintf(dst, "acall $%04X", (PC & 0xf800) | ((op & 0xe0) << 3) | opram[PC - pc]);
+ PC++;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ //LCALL code addr
+ case 0x12: /* 1: 0001 0010 */
+ addr = (opram[PC++ - pc]<<8) & 0xff00;
+ addr|= opram[PC++ - pc];
+ sprintf(dst, "lcall $%04X", addr);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ //RRC A
+ case 0x13: /* 1: 0001 0011 */
+ sprintf(dst, "rrc a");
+ break;
+
+ //DEC A
+ case 0x14: /* 1: 0001 0100 */
+ sprintf(dst, "dec a");
+ break;
+
+ //DEC data addr
+ case 0x15: /* 1: 0001 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "dec %s", sym);
+ break;
+
+ //Unable to test
+ //DEC @R0/@R1 /* 1: 0001 011i */
+ case 0x16:
+ case 0x17:
+ sprintf(dst, "dec @r%d", op&1);
+ break;
+
+ //DEC R0 to R7 /* 1: 0001 1rrr */
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ sprintf(dst, "dec r%d", op&7);
+ break;
+
+ //JB bit addr, code addr
+ case 0x20: /* 1: 0010 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jb %s,$%04X", sym, (PC + rel));
+ break;
+
+ //RET
+ case 0x22: /* 1: 0010 0010 */
+ sprintf(dst, "ret");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ //RL A
+ case 0x23: /* 1: 0010 0011 */
+ sprintf(dst, "rl a");
+ break;
+
+ //ADD A, #data
+ case 0x24: /* 1: 0010 0100 */
+ sprintf(dst, "add a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //ADD A, data addr
+ case 0x25: /* 1: 0010 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "add a,%s", sym);
+ break;
+
+ //Unable to Test
+ //ADD A, @R0/@R1 /* 1: 0010 011i */
+ case 0x26:
+ case 0x27:
+ sprintf(dst, "add a,@r%d", op&1);
+ break;
+
+ //ADD A, R0 to R7 /* 1: 0010 1rrr */
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ sprintf(dst, "add a,r%d", op&7);
+ break;
+
+ //JNB bit addr, code addr
+ case 0x30: /* 1: 0011 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jnb %s,$%04X", sym, (PC + rel));
+ break;
+
+ //RETI
+ case 0x32: /* 1: 0011 0010 */
+ sprintf(dst, "reti");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ //RLC A
+ case 0x33: /* 1: 0011 0011 */
+ sprintf(dst, "rlc a");
+ break;
+
+ //ADDC A, #data
+ case 0x34: /* 1: 0011 0100 */
+ sprintf(dst, "addc a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //ADDC A, data addr
+ case 0x35: /* 1: 0011 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "addc a,%s", sym);
+ break;
+
+ //ADDC A, @R0/@R1 /* 1: 0011 011i */
+ case 0x36:
+ case 0x37:
+ sprintf(dst, "addc a,@r%d", op&1);
+ break;
+
+ //ADDC A, R0 to R7 /* 1: 0011 1rrr */
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ sprintf(dst, "addc a,r%d", op&7);
+ break;
+
+ //JC code addr
+ case 0x40: /* 1: 0100 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jc $%04X", PC + rel);
+ break;
+
+ //ORL data addr, A
+ case 0x42: /* 1: 0100 0010 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "orl %s,a", sym);
+ break;
+
+ //ORL data addr, #data
+ case 0x43: /* 1: 0100 0011 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "orl %s,#$%02X", sym, opram[PC++ - pc]);
+ break;
+
+ //Unable to Test
+ //ORL A, #data
+ case 0x44: /* 1: 0100 0100 */
+ sprintf(dst, "orl a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //ORL A, data addr
+ case 0x45: /* 1: 0100 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "orl a,%s", sym);
+ break;
+
+ //ORL A, @RO/@R1 /* 1: 0100 011i */
+ case 0x46:
+ case 0x47:
+ sprintf(dst, "orl a,@r%d", op&1);
+ break;
+
+ //ORL A, RO to R7 /* 1: 0100 1rrr */
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ sprintf(dst, "orl a,r%d", op&7);
+ break;
+
+ //JNC code addr
+ case 0x50: /* 1: 0101 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jnc $%04X", PC + rel);
+ break;
+
+ //Unable to test
+ //ANL data addr, A
+ case 0x52: /* 1: 0101 0010 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "anl %s,a", sym);
+ break;
+
+ //Unable to test
+ //ANL data addr, #data
+ case 0x53: /* 1: 0101 0011 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "anl %s,#$%02X", sym, opram[PC++ - pc]);
+ break;
+
+ //ANL A, #data
+ case 0x54: /* 1: 0101 0100 */
+ sprintf(dst, "anl a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //ANL A, data addr
+ case 0x55: /* 1: 0101 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "anl a,%s", sym);
+ break;
+
+ //Unable to test
+ //ANL A, @RO/@R1 /* 1: 0101 011i */
+ case 0x56:
+ case 0x57:
+ sprintf(dst, "anl a,@r%d", op&1);
+ break;
+
+ //ANL A, RO to R7 /* 1: 0101 1rrr */
+ case 0x58:
+ case 0x59:
+ case 0x5a:
+ case 0x5b:
+ case 0x5c:
+ case 0x5d:
+ case 0x5e:
+ case 0x5f:
+ sprintf(dst, "anl a,r%d", op&7);
+ break;
+
+ //JZ code addr
+ case 0x60: /* 1: 0110 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jz $%04X", PC + rel);
+ break;
+
+ //Unable to test
+ //XRL data addr, A
+ case 0x62: /* 1: 0110 0010 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "xrl %s,a", sym);
+ break;
+
+ //XRL data addr, #data
+ case 0x63: /* 1: 0110 0011 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "xrl %s,#$%02X", sym, opram[PC++ - pc]);
+ break;
+
+ //XRL A, #data
+ case 0x64: /* 1: 0110 0100 */
+ sprintf(dst, "xrl a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //XRL A, data addr
+ case 0x65: /* 1: 0110 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "xrl a,%s", sym);
+ break;
+
+ //Unable to test
+ //XRL A, @R0/@R1 /* 1: 0110 011i */
+ case 0x66:
+ case 0x67:
+ sprintf(dst, "xrl a,@r%d", op&1);
+ break;
+
+ //XRL A, R0 to R7 /* 1: 0110 1rrr */
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f:
+ sprintf(dst, "xrl a,r%d", op&7);
+ break;
+
+ //JNZ code addr
+ case 0x70: /* 1: 0111 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "jnz $%04X", PC + rel);
+ break;
+
+ //Unable to test
+ //ORL C, bit addr
+ case 0x72: /* 1: 0111 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "orl c,%s", sym);
+ break;
+
+ //Unable to test
+ //JMP @A+DPTR
+ case 0x73: /* 1: 0111 0011 */
+ sprintf(dst, "jmp @a+dptr");
+ break;
+
+ //MOV A, #data
+ case 0x74: /* 1: 0111 0100 */
+ sprintf(dst, "mov a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //MOV data addr, #data
+ case 0x75: /* 1: 0111 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,#$%02X", sym, opram[PC++ - pc]);
+ break;
+
+ //Unable to test
+ //MOV @R0/@R1, #data /* 1: 0111 011i */
+ case 0x76:
+ case 0x77:
+ sprintf(dst, "mov @r%d,#$%02X", op&1, opram[PC++ - pc]);
+ break;
+
+ //MOV R0 to R7, #data /* 1: 0111 1rrr */
+ case 0x78:
+ case 0x79:
+ case 0x7a:
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f:
+ sprintf(dst, "mov r%d,#$%02X", (op & 7), opram[PC++ - pc]);
+ break;
+
+ //SJMP code addr
+ case 0x80: /* 1: 1000 0000 */
+ rel = opram[PC++ - pc];
+ sprintf(dst, "sjmp $%04X", PC + rel);
+ break;
+
+ //ANL C, bit addr
+ case 0x82: /* 1: 1000 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "anl c,%s", sym);
+ break;
+
+ //MOVC A, @A + PC
+ case 0x83: /* 1: 1000 0011 */
+ sprintf(dst, "movc a,@a+pc");
+ break;
+
+ //DIV AB
+ case 0x84: /* 1: 1000 0100 */
+ sprintf(dst, "div ab");
+ break;
+
+ //MOV data addr, data addr (Note: 1st address is src, 2nd is dst, but the mov command works as mov dst,src)
+ case 0x85: /* 1: 1000 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sym2 = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,%s", sym2, sym);
+ break;
+
+ //Unable to test
+ //MOV data addr, @R0/@R1/* 1: 1000 011i */
+ case 0x86:
+ case 0x87:
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,@r%d", sym, op&1);
+ break;
+
+ //MOV data addr,R0 to R7/* 1: 1000 1rrr */
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,r%d", sym, op&7);
+ break;
+
+ //MOV DPTR, #data16
+ case 0x90: /* 1: 1001 0000 */
+ addr = (opram[PC++ - pc]<<8) & 0xff00;
+ addr|= opram[PC++ - pc];
+ sprintf(dst, "mov dptr,#$%04X", addr);
+ break;
+
+ //MOV bit addr, C
+ case 0x92: /* 1: 1001 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,c", sym);
+ break;
+
+ //MOVC A, @A + DPTR
+ case 0x93: /* 1: 1001 0011 */
+ sprintf(dst, "movc a,@a+dptr");
+ break;
+
+ //SUBB A, #data
+ case 0x94: /* 1: 1001 0100 */
+ sprintf(dst, "subb a,#$%02X", opram[PC++ - pc]);
+ break;
+
+ //SUBB A, data addr
+ case 0x95: /* 1: 1001 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "subb a,%s", sym);
+ break;
+
+ //Unable to test
+ //SUBB A, @R0/@R1 /* 1: 1001 011i */
+ case 0x96:
+ case 0x97:
+ sprintf(dst, "subb a,@r%d", op&1);
+ break;
+
+ //SUBB A, R0 to R7 /* 1: 1001 1rrr */
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+ sprintf(dst, "subb a,r%d", op&7);
+ break;
+
+ //Unable to test
+ //ORL C, /bit addr
+ case 0xa0: /* 1: 1010 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "orl c,/%s", sym);
+ break;
+
+ //MOV C, bit addr
+ case 0xa2: /* 1: 1010 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "mov c,%s", sym);
+ break;
+
+ //INC DPTR
+ case 0xa3: /* 1: 1010 0011 */
+ sprintf(dst, "inc dptr");
+ break;
+
+ //MUL AB
+ case 0xa4: /* 1: 1010 0100 */
+ sprintf(dst, "mul ab");
+ break;
+
+ //reserved
+ case 0xa5: /* 1: 1010 0101 */
+ sprintf(dst, "ill/rsv");
+ break;
+
+ //Unable to test
+ //MOV @R0/@R1, data addr /* 1: 1010 011i */
+ case 0xa6:
+ case 0xa7:
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov @r%d,%s", op&1, sym);
+ break;
+
+ //MOV R0 to R7, data addr /* 1: 1010 1rrr */
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov r%d,%s", op&7, sym);
+ break;
+
+ //ANL C,/bit addr
+ case 0xb0: /* 1: 1011 0000 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "anl c,/%s", sym);
+ break;
+
+ //CPL bit addr
+ case 0xb2: /* 1: 1011 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "cpl %s", sym);
+ break;
+
+ //Unable to test
+ //CPL C
+ case 0xb3: /* 1: 1011 0011 */
+ sprintf(dst, "cpl c");
+ break;
+
+ //CJNE A, #data, code addr
+ case 0xb4: /* 1: 1011 0100 */
+ data = opram[PC++ - pc];
+ rel = opram[PC++ - pc];
+ sprintf(dst, "cjne a,#$%02X,$%04X", data, PC + rel);
+ break;
+
+ //CJNE A, data addr, code addr
+ case 0xb5: /* 1: 1011 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "cjne a,%s,$%04X", sym, PC + rel);
+ break;
+
+ //Unable to test
+ //CJNE @R0/@R1, #data, code addr /* 1: 1011 011i */
+ case 0xb6:
+ case 0xb7:
+ data = opram[PC++ - pc];
+ rel = opram[PC++ - pc];
+ sprintf(dst, "cjne @r%d,#$%02X,$%04X", op&1, data, PC + rel);
+ break;
+
+ //CJNE R0 to R7, #data, code addr/* 1: 1011 1rrr */
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ data = opram[PC++ - pc];
+ rel = opram[PC++ - pc];
+ sprintf(dst, "cjne r%d,#$%02X,$%04X", op&7, data, PC + rel);
+ break;
+
+ //PUSH data addr
+ case 0xc0: /* 1: 1100 0000 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "push %s", sym);
+ break;
+
+ //CLR bit addr
+ case 0xc2: /* 1: 1100 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "clr %s", sym);
+ break;
+
+ //CLR C
+ case 0xc3: /* 1: 1100 0011 */
+ sprintf(dst, "clr c");
+ break;
+
+ //SWAP A
+ case 0xc4: /* 1: 1100 0100 */
+ sprintf(dst, "swap a");
+ break;
+
+ //XCH A, data addr
+ case 0xc5: /* 1: 1100 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "xch a,%s", sym);
+ break;
+
+ //XCH A, @RO/@R1 /* 1: 1100 011i */
+ case 0xc6:
+ case 0xc7:
+ sprintf(dst, "xch a,@r%d", op&1);
+ break;
+
+ //XCH A, RO to R7 /* 1: 1100 1rrr */
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ sprintf(dst, "xch a,r%d", op&7);
+ break;
+
+ //POP data addr
+ case 0xd0: /* 1: 1101 0000 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "pop %s", sym);
+ break;
+
+ //SETB bit addr
+ case 0xd2: /* 1: 1101 0010 */
+ sym = get_bit_address(opram[PC++ - pc]);
+ sprintf(dst, "setb %s", sym);
+ break;
+
+ //SETB C
+ case 0xd3: /* 1: 1101 0011 */
+ sprintf(dst, "setb c");
+ break;
+
+ //Unable to test
+ //DA A
+ case 0xd4: /* 1: 1101 0100 */
+ sprintf(dst, "da a");
+ break;
+
+ //DJNZ data addr, code addr
+ case 0xd5: /* 1: 1101 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ rel = opram[PC++ - pc];
+ sprintf(dst, "djnz %s,$%04X", sym, PC + rel);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ //XCHD A, @R0/@R1 /* 1: 1101 011i */
+ case 0xd6:
+ case 0xd7:
+ sprintf(dst, "xchd a,@r%d", op&1);
+ break;
+
+ //DJNZ R0 to R7,code addr /* 1: 1101 1rrr */
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ rel = opram[PC++ - pc];
+ sprintf(dst, "djnz r%d,$%04X", op&7, (PC + rel));
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ //MOVX A,@DPTR
+ case 0xe0: /* 1: 1110 0000 */
+ sprintf(dst, "movx a,@dptr");
+ break;
+
+ //Unable to test
+ //MOVX A, @R0/@R1 /* 1: 1110 001i */
+ case 0xe2:
+ case 0xe3:
+ sprintf(dst, "movx a,@r%d", op&1);
+ break;
+
+ //CLR A
+ case 0xe4: /* 1: 1110 0100 */
+ sprintf(dst, "clr a");
+ break;
+
+ //MOV A, data addr
+ case 0xe5: /* 1: 1110 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov a,%s", sym);
+ break;
+
+ //Unable to test
+ //MOV A,@RO/@R1 /* 1: 1110 011i */
+ case 0xe6:
+ case 0xe7:
+ sprintf(dst, "mov a,@r%d", op&1);
+ break;
+
+ //MOV A,R0 to R7 /* 1: 1110 1rrr */
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ sprintf(dst, "mov a,r%d", op&7);
+ break;
+
+ //MOVX @DPTR,A
+ case 0xf0: /* 1: 1111 0000 */
+ sprintf(dst, "movx @dptr,a");
+ break;
+
+ //Unable to test
+ //MOVX @R0/@R1,A /* 1: 1111 001i */
+ case 0xf2:
+ case 0xf3:
+ sprintf(dst, "movx @r%d,a", op&1);
+ break;
+
+ //CPL A
+ case 0xf4: /* 1: 1111 0100 */
+ sprintf(dst, "cpl a");
+ break;
+
+ //MOV data addr, A
+ case 0xf5: /* 1: 1111 0101 */
+ sym = get_data_address(opram[PC++ - pc]);
+ sprintf(dst, "mov %s,a", sym);
+ break;
+
+ //MOV @R0/@R1, A /* 1: 1111 011i */
+ case 0xf6:
+ case 0xf7:
+ sprintf(dst, "mov @r%d,a", op&1);
+ break;
+
+ //MOV R0 to R7, A /* 1: 1111 1rrr */
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ sprintf(dst, "mov r%d,a", op&7);
+ break;
+
+ default:
+ sprintf(dst, "illegal");
+ }
+ return (PC - pc) | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/i8051/i8051.c b/src/emu/cpu/i8051/i8051.c
new file mode 100644
index 00000000000..3231cb69ffc
--- /dev/null
+++ b/src/emu/cpu/i8051/i8051.c
@@ -0,0 +1,2583 @@
+/*****************************************************************************
+ *
+ * i8051.c
+ * Portable MCS-51 Family Emulator
+ *
+ * Chips in the family:
+ * 8051 Product Line (8031,8051,8751)
+ * 8052 Product Line (8032,8052,8752)
+ * 8054 Product Line (8054)
+ * 8058 Product Line (8058)
+ *
+ * Copyright (c) 2003 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Intel(tm) MC51 Microcontroller Family Users Manual' and
+ * #2) 8051 simulator by Travis Marlatte
+ * #3) Portable UPI-41/8041/8741/8042/8742 emulator V0.1 by Juergen Buchmueller (MAME CORE)
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ * Notes:
+ * *Important*: Internal ROM needs to be treated the same as external rom by the programmer
+ * creating the driver (ie, use standard cpu rom region)
+ *
+ * The term cycles is used here to really refer to clock oscilations, because 1 machine cycle
+ * actually takes 12 oscilations.
+ *
+ * Read/Write/Modify Instruction -
+ * Data is read from the Port Latch (not the Port Pin!), possibly modified, and
+ * written back to (the pin? and) the latch!
+ *
+ * The following all perform this on a port address..
+ * (anl, orl, xrl, jbc, cpl, inc, dec, djnz, mov px.y,c, clr px.y, setb px.y)
+ *
+ * Serial UART emulation is not really accurate, but faked enough to work as far as i can tell
+ *
+ * August 27,2003: Currently support for only 8031/8051/8751 chips (ie 128 RAM)
+ * October 14,2003: Added initial support for the 8752 (ie 256 RAM)
+ * October 22,2003: Full support for the 8752 (ie 256 RAM)
+ * July 28,2004: Fixed MOVX command and added External Ram Paging Support
+ * July 31,2004: Added Serial Mode 0 Support & Fixed Interrupt Flags for Serial Port
+ *
+ * Todo: Full Timer support (all modes)
+ *
+ * NOW Implemented: RAM paging using hardware configured addressing...
+ * (July 28,2004) the "MOVX a,@R0/R1" and "MOVX @R0/R1,a" commands can use any of the other ports
+ * to output a page offset into external ram, but it is totally based on the hardware setup.
+ *
+ * Timing needs to be implemented via MAME timers perhaps?
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "i8051.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+//Prototypes
+INLINE void push_pc(void);
+INLINE void pop_pc(void);
+INLINE void set_parity(void);
+INLINE void do_add_flags(UINT8 a, UINT8 data, UINT8 c);
+INLINE void do_sub_flags(UINT8 a, UINT8 data, UINT8 c);
+INLINE UINT8 check_interrupts(void);
+INLINE void update_timer(int cyc);
+INLINE void update_serial(int cyc);
+INLINE void serial_transmit(UINT8 data);
+static READ8_HANDLER(internal_ram_read);
+static WRITE8_HANDLER(internal_ram_write);
+static READ8_HANDLER(internal_ram_iread);
+static READ32_HANDLER(external_ram_iaddr);
+static WRITE8_HANDLER(internal_ram_iwrite);
+static READ8_HANDLER(sfr_read);
+static WRITE8_HANDLER(sfr_write);
+static WRITE8_HANDLER( bit_address_w );
+static READ8_HANDLER( bit_address_r );
+
+#if (HAS_I8052 || HAS_I8752)
+static READ8_HANDLER(i8052_internal_ram_iread);
+static WRITE8_HANDLER(i8052_internal_ram_iwrite);
+#endif
+//
+
+typedef struct {
+ UINT8 timerbaud; //Flag set if timer overflow is controlling baud
+ UINT8 sending; //Flag set when uart is sending
+ UINT8 data_out; //Data to send out
+ UINT8 bits_to_send; //How many bits left to send when transmitting out the serial port
+ UINT8 bitcycles; //# of bitcycles passed since last bit was sent
+} I8051_UART;
+
+typedef struct {
+
+ //Internal stuff
+ UINT16 ppc; //previous pc
+ UINT16 pc; //current pc
+ UINT16 subtype; //specific version of the cpu, ie 8031, or 8051 for example
+ UINT8 cur_irq; //Holds value of any current IRQ being serviced
+ UINT8 irq_priority; //Holds value of the current IRQ Priority Level
+ UINT8 rwm; //Signals that the current instruction is a read/write/modify instruction
+ int prev_used_cycles; //Track previous # of used cycles
+ int last_int0; //Store state of int0
+ int last_int1; //Store state of int1
+ UINT8 int_vec; //Pending Interrupt Vector
+ int priority_request; //Priority level of incoming new irq
+ //SFR Registers (Note: Appear in order as they do in memory)
+ UINT8 po; //Port 0
+ UINT8 sp; //Stack Pointer
+ UINT8 dpl; //Data Pointer (DPTR) (Hi bit)
+ UINT8 dph; //Data Pointer (DPTR) (Lo bit)
+ UINT8 pcon; //Power Mode Control
+ UINT8 tcon; //Timer/Counter Control
+ UINT8 tmod; //Timer/Counter Mode Control
+ UINT8 tl0; //Timer 0 Lo
+ UINT8 tl1; //Timer 1 Lo
+ UINT8 th0; //Timer 0 Hi
+ UINT8 th1; //Timer 1 Hi
+ UINT8 p1; //Port 1
+ UINT8 scon; //Serial Control
+ UINT8 sbuf; //Serial Data Buffer
+ UINT8 p2; //Port 2
+ UINT8 ie; //Interrupt Enable
+ UINT8 p3; //Port 3
+ UINT8 ip; //Interrupt Priority
+ //8052 Only registers
+ #if (HAS_I8052 || HAS_I8752)
+ UINT8 t2con; //Timer/Counter 2 Control
+ UINT8 rcap2l; //Timer/Counter 2 Capture Register Lo
+ UINT8 rcap2h; //Timer/Counter 2 Capture Register Hi
+ UINT8 tl2; //Timer 2 Lo
+ UINT8 th2; //Timer 2 Hi
+ #endif
+ UINT8 psw; //Program Status Word
+ UINT8 acc; //Accumulator
+ UINT8 b; //Register B
+
+ //Internal Ram
+ UINT8 IntRam[0xff+1]; //Max 256 Bytes of Internal RAM (8031/51 have 128, 8032/52 have 256)
+
+ //Interrupt Callback
+ int (*irq_callback)(int irqline);
+
+ //Serial Port TX/RX Call backs
+ void (*serial_tx_callback)(int data); //Call back funciton when sending data out of serial port
+ int (*serial_rx_callback)(void); //Call back function to retrieve data when receiving serial port data
+
+ //Internal Indirect Read/Write Handlers
+ READ8_HANDLER((*iram_iread));
+ WRITE8_HANDLER((*iram_iwrite));
+
+ //External Ram Address Callback for generating the hardware specific access to external ram
+ READ32_HANDLER((*eram_iaddr_callback));
+
+} I8051;
+
+int i8051_icount;
+
+static I8051 i8051;
+static I8051_UART uart;
+
+//Hold callback functions so they can be set by caller (before the cpu reset)
+static void (*hold_serial_tx_callback)(int data);
+static int (*hold_serial_rx_callback)(void);
+static READ32_HANDLER((*hold_eram_iaddr_callback));
+
+/*Short cuts*/
+
+/***************************************************************
+ * Read Opcode/Opcode Arguments from Program Code
+ ***************************************************************/
+#define ROP(pc) cpu_readop(pc)
+#define ROP_ARG(pc) cpu_readop_arg(pc)
+/*****************************************************************************
+ * Read a byte from External Code Memory (Usually Program Rom(s) Space)
+ *****************************************************************************
+ This area is mapped from 0-FFFF internally (64K) */
+#define CODEMEM_R(a) (UINT8)program_read_byte_8(a)
+/*****************************************************************************
+ * Read/Write a byte from/to External Data Memory (Usually RAM or other I/O)
+ *****************************************************************************
+ This area is *ALSO* mapped from 0-FFFF internally (64K)
+ ** HOWEVER **
+ We *FORCE* the address space into the range 10000-1FFFF to allow both
+ Code Memory and Data Memory to be pyshically separate while mapped @ the same
+ addresses, w/o any contention.
+ As far as the 8051 program code which is executing knows data memory still lives
+ in the 0-FFFF range.*/
+#define DATAMEM_R(a) (UINT8)data_read_byte_8(a)
+#define DATAMEM_W(a,v) data_write_byte_8(a,v)
+
+/***************************************************************
+ * Read/Write a byte from/to the Internal RAM
+ ***************************************************************/
+#define IRAM_R(a) internal_ram_read(a)
+#define IRAM_W(a,v) internal_ram_write(a,v)
+/***************************************************************
+ * Read/Write a byte from/to the Internal RAM indirectly (called from indirect addressing)
+ ***************************************************************/
+#define IRAM_IR(a) internal_ram_iread(a)
+#define IRAM_IW(a,v) internal_ram_iwrite(a,v)
+/***************************************************************
+ * Form an Address to Read/Write to External RAM indirectly (called from indirect addressing)
+ ***************************************************************/
+#define ERAM_ADDR(a,m) external_ram_iaddr(a,m)
+/***************************************************************
+ * Read/Write a byte from/to the SFR Registers
+ ***************************************************************/
+#define SFR_R(a) sfr_read(a)
+#define SFR_W(a,v) sfr_write(a,v)
+/***************************************************************
+ * Read/Write a bit from Bit Addressable Memory
+ ***************************************************************/
+#define BIT_R(a) bit_address_r(a)
+#define BIT_W(a,v) bit_address_w(a,v)
+/***************************************************************
+ * Input/Output a byte from given I/O port
+ ***************************************************************/
+#define IN(port) ((UINT8)io_read_byte(port))
+#define OUT(port,value) io_write_byte(port,value)
+/***************************************************************
+ * Access the 4 banks of R registers (R0...R7)
+ ***************************************************************/
+#define R_R(n) i8051.IntRam[(GET_RS*8)+(n)]
+/***************************************************************
+ * Easy macro for working with 16 bit DPTR
+ ***************************************************************/
+#define R_DPTR ((R_DPH<<8) | R_DPL)
+#define DPTR_W(n) SFR_W(DPH, ((n)>>8)&0xff);\
+ SFR_W(DPL, ((n)&0xff));
+/***************************************************************
+ * Easy macros for Setting Flags
+ ***************************************************************/
+/*PSW Flags*/
+#define SET_CY(n) R_PSW = (R_PSW & 0x7f) | (n<<7); //Carry Flag
+#define SET_AC(n) R_PSW = (R_PSW & 0xbf) | (n<<6); //Aux.Carry Flag
+#define SET_FO(n) R_PSW = (R_PSW & 0xdf) | (n<<5); //User Flag
+#define SET_RS(n) R_PSW = (R_PSW & 0xe7) | (n<<3); //R Bank Select
+#define SET_OV(n) R_PSW = (R_PSW & 0xfb) | (n<<2); //Overflow Flag
+#define SET_P(n) R_PSW = (R_PSW & 0xfe) | (n<<0); //Parity Flag
+/*IE Flags*/
+#define SET_EA(n) R_IE = (R_IE & 0x7f) | (n<<7); //Global Interrupt Enable/Disable
+#if (HAS_I8052 || HAS_I8752)
+ #define SET_ET2(n) R_IE = (R_IE & 0xdf) | (n<<5); //Timer 2 Interrupt Enable/Disable
+#endif
+#define SET_ES(n) R_IE = (R_IE & 0xef) | (n<<4); //Serial Interrupt Enable/Disable
+#define SET_ET1(n) R_IE = (R_IE & 0xf7) | (n<<3); //Timer 1 Interrupt Enable/Disable
+#define SET_EX1(n) R_IE = (R_IE & 0xfb) | (n<<2); //External Int 1 Interrupt Enable/Disable
+#define SET_ET0(n) R_IE = (R_IE & 0xfd) | (n<<1); //Timer 0 Interrupt Enable/Disable
+#define SET_EX0(n) R_IE = (R_IE & 0xfe) | (n<<0); //External Int 0 Interrupt Enable/Disable
+/*IP Flags*/
+#if (HAS_I8052 || HAS_I8752)
+ #define SET_PT2(n) R_IP = (R_IP & 0xdf) | (n<<5); //Set Timer 2 Priority Level
+#endif
+#define SET_PS0(n) R_IP = (R_IP & 0xef) | (n<<4); //Set Serial Priority Level
+#define SET_PT1(n) R_IP = (R_IP & 0xf7) | (n<<3); //Set Timer 1 Priority Level
+#define SET_PX1(n) R_IP = (R_IP & 0xfb) | (n<<2); //Set External Int 1 Priority Level
+#define SET_PT0(n) R_IP = (R_IP & 0xfd) | (n<<1); //Set Timer 0 Priority Level
+#define SET_PX0(n) R_IP = (R_IP & 0xfe) | (n<<0); //Set External Int 0 Priority Level
+/*TCON Flags*/
+#define SET_TF1(n) R_TCON = (R_TCON & 0x7f) | (n<<7); //Indicated Timer 1 Overflow Int Triggered
+#define SET_TR1(n) R_TCON = (R_TCON & 0xbf) | (n<<6); //IndicateS Timer 1 is running
+#define SET_TF0(n) R_TCON = (R_TCON & 0xdf) | (n<<5); //Indicated Timer 0 Overflow Int Triggered
+#define SET_TR0(n) R_TCON = (R_TCON & 0xef) | (n<<4); //IndicateS Timer 0 is running
+#define SET_IE1(n) R_TCON = (R_TCON & 0xf7) | (n<<3); //Indicated External Int 1 Triggered
+#define SET_IT1(n) R_TCON = (R_TCON & 0xfb) | (n<<2); //Indicates how External Int 1 is Triggered
+#define SET_IE0(n) R_TCON = (R_TCON & 0xfd) | (n<<1); //Indicated External Int 0 Triggered
+#define SET_IT0(n) R_TCON = (R_TCON & 0xfe) | (n<<0); //Indicates how External Int 0 is Triggered
+/*SCON Flags*/
+#define SET_SM0(n) R_SCON = (R_SCON & 0x7f) | (n<<7); //Sets Serial Port Mode
+#define SET_SM1(n) R_SCON = (R_SCON & 0xbf) | (n<<6); //Sets Serial Port Mode
+#define SET_SM2(n) R_SCON = (R_SCON & 0xdf) | (n<<5); //Sets Serial Port Mode (Multiprocesser mode)
+#define SET_REN(n) R_SCON = (R_SCON & 0xef) | (n<<4); //Sets Serial Port Receive Enable
+#define SET_TB8(n) R_SCON = (R_SCON & 0xf7) | (n<<3); //Transmit 8th Bit
+#define SET_RB8(n) R_SCON = (R_SCON & 0xfb) | (n<<2); //Receive 8th Bit
+#define SET_TI(n) R_SCON = (R_SCON & 0xfd) | (n<<1); //Indicates Transmit Interrupt Occurred
+#define SET_RI(n) R_SCON = (R_SCON & 0xfe) | (n<<0); //Indicates Receive Interrupt Occurred
+/*TMOD Flags*/
+#define SET_GATE1(n) R_TMOD = (R_TMOD & 0x7f) | (n<<7); //Timer 1 Gate Mode
+#define SET_CT1(n) R_TMOD = (R_TMOD & 0xbf) | (n<<6); //Timer 1 Counter Mode
+#define SET_M1_1(n) R_TMOD = (R_TMOD & 0xdf) | (n<<5); //Timer 1 Timer Mode Bit 1
+#define SET_M1_0(n) R_TMOD = (R_TMOD & 0xef) | (n<<4); //Timer 1 Timer Mode Bit 0
+#define SET_GATE0(n) R_TMOD = (R_TMOD & 0xf7) | (n<<3); //Timer 0 Gate Mode
+#define SET_CT0(n) R_TMOD = (R_TMOD & 0xfb) | (n<<2); //Timer 0 Counter Mode
+#define SET_M0_1(n) R_TMOD = (R_TMOD & 0xfd) | (n<<1); //Timer 0 Timer Mode Bit 1
+#define SET_M0_0(n) R_TMOD = (R_TMOD & 0xfe) | (n<<0); //Timer 0 Timer Mode Bit 0
+
+#if (HAS_I8052 || HAS_I8752)
+ /*T2CON Flags*/
+ #define SET_TF2(n) R_T2CON = (R_T2CON & 0x7f) | (n<<7); //Indicated Timer 2 Overflow Int Triggered
+ #define SET_EXF2(n) R_T2CON = (R_T2CON & 0xbf) | (n<<6); //Indicates Timer 2 External Flag
+ #define SET_RCLK(n) R_T2CON = (R_T2CON & 0xdf) | (n<<5); //Receive Clock
+ #define SET_TCLK(n) R_T2CON = (R_T2CON & 0xef) | (n<<4); //Transmit Clock
+ #define SET_EXEN2(n) R_T2CON = (R_T2CON & 0xf7) | (n<<3); //Timer 2 External Interrupt Enable
+ #define SET_TR2(n) R_T2CON = (R_T2CON & 0xfb) | (n<<2); //Indicates Timer 2 is running
+ #define SET_CT2(n) R_T2CON = (R_T2CON & 0xfd) | (n<<1); //Sets Timer 2 Counter/Timer Mode
+ #define SET_CP(n) R_T2CON = (R_T2CON & 0xfe) | (n<<0); //Sets Timer 2 Capture/Reload Mode
+#endif
+
+/***************************************************************
+ * Easy macros for Getting Flags
+ ***************************************************************/
+/*PSW Flags*/
+#define GET_CY ((R_PSW & 0x80)>>7)
+#define GET_AC ((R_PSW & 0x40)>>6)
+#define GET_FO ((R_PSW & 0x20)>>5)
+#define GET_RS ((R_PSW & 0x18)>>3)
+#define GET_OV ((R_PSW & 0x04)>>2)
+#define GET_P ((R_PSW & 0x01)>>0)
+/*IE Flags*/
+#define GET_EA ((R_IE & 0x80)>>7)
+#define GET_ET2 ((R_IE & 0x20)>>5)
+#define GET_ES ((R_IE & 0x10)>>4)
+#define GET_ET1 ((R_IE & 0x08)>>3)
+#define GET_EX1 ((R_IE & 0x04)>>2)
+#define GET_ET0 ((R_IE & 0x02)>>1)
+#define GET_EX0 ((R_IE & 0x01)>>0)
+/*IP Flags*/
+#if (HAS_I8052 || HAS_I8752)
+ #define GET_PT2 ((R_IP & 0x20)>>5)
+#endif
+#define GET_PS ((R_IP & 0x10)>>4)
+#define GET_PT1 ((R_IP & 0x08)>>3)
+#define GET_PX1 ((R_IP & 0x04)>>2)
+#define GET_PT0 ((R_IP & 0x02)>>1)
+#define GET_PX0 ((R_IP & 0x01)>>0)
+/*TCON Flags*/
+#define GET_TF1 ((R_TCON & 0x80)>>7)
+#define GET_TR1 ((R_TCON & 0x40)>>6)
+#define GET_TF0 ((R_TCON & 0x20)>>5)
+#define GET_TR0 ((R_TCON & 0x10)>>4)
+#define GET_IE1 ((R_TCON & 0x08)>>3)
+#define GET_IT1 ((R_TCON & 0x04)>>2)
+#define GET_IE0 ((R_TCON & 0x02)>>1)
+#define GET_IT0 ((R_TCON & 0x01)>>0)
+/*SCON Flags*/
+#define GET_SM0 ((R_SCON & 0x80)>>7)
+#define GET_SM1 ((R_SCON & 0x40)>>6)
+#define GET_SM2 ((R_SCON & 0x20)>>5)
+#define GET_REN ((R_SCON & 0x10)>>4)
+#define GET_TB8 ((R_SCON & 0x08)>>3)
+#define GET_RB8 ((R_SCON & 0x04)>>2)
+#define GET_TI ((R_SCON & 0x02)>>1)
+#define GET_RI ((R_SCON & 0x01)>>0)
+/*TMOD Flags*/
+#define GET_GATE1 ((R_TMOD & 0x80)>>7)
+#define GET_CT1 ((R_TMOD & 0x40)>>6)
+#define GET_M1_1 ((R_TMOD & 0x20)>>5)
+#define GET_M1_0 ((R_TMOD & 0x10)>>4)
+#define GET_GATE0 ((R_TMOD & 0x08)>>3)
+#define GET_CT0 ((R_TMOD & 0x04)>>2)
+#define GET_M0_1 ((R_TMOD & 0x02)>>1)
+#define GET_M0_0 ((R_TMOD & 0x01)>>0)
+
+#if (HAS_I8052 || HAS_I8752)
+ /*T2CON Flags*/
+ #define GET_TF2 ((R_T2CON & 0x80)>>7)
+ #define GET_EXF2 ((R_T2CON & 0x40)>>6)
+ #define GET_RCLK ((R_T2CON & 0x20)>>5)
+ #define GET_TCLK ((R_T2CON & 0x10)>>4)
+ #define GET_EXEN2 ((R_T2CON & 0x08)>>3)
+ #define GET_TR2 ((R_T2CON & 0x04)>>2)
+ #define GET_CT2 ((R_T2CON & 0x02)>>1)
+ #define GET_CP ((R_T2CON & 0x01)>>0)
+#endif
+
+/*Add and Subtract Flag settings*/
+#define DO_ADD_FLAGS(a,d,c) do_add_flags(a,d,c);
+#define DO_SUB_FLAGS(a,d,c) do_sub_flags(a,d,c);
+
+#define SET_PARITY set_parity();
+#define PUSH_PC push_pc();
+#define POP_PC pop_pc();
+
+/* PC vectors */
+#define V_RESET 0x000 /* power on address */
+#define V_IE0 0x003 /* External Interrupt 0 */
+#define V_TF0 0x00b /* Timer 0 Overflow */
+#define V_IE1 0x013 /* External Interrupt 1 */
+#define V_TF1 0x01b /* Timer 1 Overflow */
+#define V_RITI 0x023 /* Serial Receive/Transmit */
+
+#if (HAS_I8052 || HAS_I8752)
+#define V_TF2 0x02b /* Timer 2 Overflow */
+#endif
+
+/* Any pending IRQ */
+#define SERIALPORT_IRQ ((R_SCON & 0x03) && GET_ES)
+
+#if (HAS_I8052 || HAS_I8752)
+#define NO_PENDING_IRQ !(R_TCON & 0xaa) && !(SERIALPORT_IRQ) && !GET_ET2 //!GET_TF2 && !GET_EXF2
+#else
+#define NO_PENDING_IRQ !(R_TCON & 0xaa) && !(SERIALPORT_IRQ)
+#endif
+
+/* Clear Current IRQ */
+#define CLEAR_CURRENT_IRQ i8051.cur_irq = 0xff;\
+ i8051.irq_priority = 0;
+
+/* shorter names for the I8051 structure elements */
+
+//Internal stuff
+#define PPC i8051.ppc
+#define PC i8051.pc
+#define TYPE i8051.subtype
+#define RWM i8051.rwm
+
+//SFR Registers
+#define R_P0 i8051.po
+#define R_SP i8051.sp
+#define R_DPL i8051.dpl
+#define R_DPH i8051.dph
+#define R_PCON i8051.pcon
+#define R_TCON i8051.tcon
+#define R_TMOD i8051.tmod
+#define R_TL0 i8051.tl0
+#define R_TL1 i8051.tl1
+#define R_TH0 i8051.th0
+#define R_TH1 i8051.th1
+#define R_P1 i8051.p1
+#define R_SCON i8051.scon
+#define R_SBUF i8051.sbuf
+#define R_P2 i8051.p2
+#define R_IE i8051.ie
+#define R_P3 i8051.p3
+#define R_IP i8051.ip
+//8052 Only registers
+#if (HAS_I8052 || HAS_I8752)
+ #define R_T2CON i8051.t2con
+ #define R_RCAP2L i8051.rcap2l
+ #define R_RCAP2H i8051.rcap2h
+ #define R_TL2 i8051.tl2
+ #define R_TH2 i8051.th2
+#endif
+#define R_PSW i8051.psw
+#define R_ACC i8051.acc
+#define R_B i8051.b
+
+/* # of oscilations each opcode requires*/
+static UINT8 i8051_cycles[] = {
+ 12,24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,24,12,24,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,24,48,24,24,24,24,24,24,24,24,24,24,24,
+ 24,24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,24,48,12,24,24,24,24,24,24,24,24,24,24,
+ 24,24,12,12,24,24,24,24,24,24,24,24,24,24,24,24,
+ 24,24,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,12,12,12,24,12,12,24,24,24,24,24,24,24,24,
+ 24,24,24,24,12,12,12,12,12,12,12,12,12,12,12,12,
+ 24,24,24,24,12,12,12,12,12,12,12,12,12,12,12,12
+};
+
+/* Include Opcode functions */
+#include "i8051ops.c"
+
+void i8051_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ i8051_set_irq_callback(irqcallback);
+
+ //Internal stuff
+ state_save_register_item("i8051", index, i8051.ppc);
+ state_save_register_item("i8051", index, i8051.pc);
+ state_save_register_item("i8051", index, i8051.subtype);
+ state_save_register_item("i8051", index, i8051.rwm );
+ state_save_register_item("i8051", index, i8051.cur_irq );
+ //SFR Registers
+ state_save_register_item("i8051", index, i8051.po);
+ state_save_register_item("i8051", index, i8051.sp);
+ state_save_register_item("i8051", index, i8051.dpl);
+ state_save_register_item("i8051", index, i8051.dph);
+ state_save_register_item("i8051", index, i8051.pcon);
+ state_save_register_item("i8051", index, i8051.tcon);
+ state_save_register_item("i8051", index, i8051.tmod);
+ state_save_register_item("i8051", index, i8051.tl0);
+ state_save_register_item("i8051", index, i8051.tl1);
+ state_save_register_item("i8051", index, i8051.th0);
+ state_save_register_item("i8051", index, i8051.th1);
+ state_save_register_item("i8051", index, i8051.p1);
+ state_save_register_item("i8051", index, i8051.scon);
+ state_save_register_item("i8051", index, i8051.sbuf);
+ state_save_register_item("i8051", index, i8051.p2);
+ state_save_register_item("i8051", index, i8051.ie);
+ state_save_register_item("i8051", index, i8051.p3);
+ state_save_register_item("i8051", index, i8051.ip);
+ //8052 Only registers
+ #if (HAS_I8052 || HAS_I8752)
+ state_save_register_item("i8051", index, i8051.rcap2l);
+ state_save_register_item("i8051", index, i8051.rcap2h);
+ state_save_register_item("i8051", index, i8051.tl2);
+ state_save_register_item("i8051", index, i8051.th2);
+ #endif
+ state_save_register_item("i8051", index, i8051.psw);
+ state_save_register_item("i8051", index, i8051.acc);
+ state_save_register_item("i8051", index, i8051.b);
+}
+
+/* Reset registers to the initial values */
+void i8051_reset(void)
+{
+ int (*save_irqcallback)(int);
+
+ save_irqcallback = i8051.irq_callback;
+ memset(&i8051, 0, sizeof(I8051));
+ i8051.irq_callback = save_irqcallback;
+
+ memset(&uart, 0, sizeof(I8051_UART));
+ i8051.subtype = 8051;
+
+ //Set up 8051 specific internal read/write (indirect) handlers..
+ i8051.iram_iread = internal_ram_read; //Indirect ram read/write handled the same as direct for 8051!
+ i8051.iram_iwrite = internal_ram_write; //Indirect ram read/write handled the same as direct for 8051!
+
+ //Set up serial call back handlers
+ i8051.serial_tx_callback = hold_serial_tx_callback;
+ hold_serial_tx_callback = NULL;
+ i8051.serial_rx_callback = hold_serial_rx_callback;
+ hold_serial_rx_callback = NULL;
+
+ //Setup External ram callback handlers
+ i8051.eram_iaddr_callback = hold_eram_iaddr_callback;
+ hold_eram_iaddr_callback = NULL;
+
+ //Clear Ram (w/0xff)
+ memset(&i8051.IntRam,0xff,sizeof(i8051.IntRam));
+
+ /* these are all defined reset states */
+ PC = 0;
+ SFR_W(SP, 0x7);
+ SFR_W(PSW, 0);
+ SFR_W(DPH, 0);
+ SFR_W(DPL, 0);
+ SFR_W(ACC, 0);
+ SFR_W(B, 0);
+ SFR_W(IP, 0);
+ SFR_W(IE, 0);
+ SFR_W(SCON, 0);
+ SFR_W(TCON, 0);
+ SFR_W(TMOD, 0);
+ SFR_W(TH1, 0);
+ SFR_W(TH0, 0);
+ SFR_W(TL1, 0);
+ SFR_W(TL0, 0);
+ /* set the port configurations to all 1's */
+ SFR_W(P3, 0xff);
+ SFR_W(P2, 0xff);
+ SFR_W(P1, 0xff);
+ SFR_W(P0, 0xff);
+
+ /* Flag as NO IRQ in Progress */
+ CLEAR_CURRENT_IRQ
+}
+
+/* Shut down CPU core */
+void i8051_exit(void)
+{
+ /* nothing to do */
+}
+
+/* Execute cycles - returns number of cycles actually run */
+int i8051_execute(int cycles)
+{
+ i8051_icount = cycles;
+
+ do
+ {
+ //Read next opcode
+ UINT8 op = cpu_readop(PC);
+
+ //Store previous PC
+ PPC = PC;
+
+ //Call Debugger
+ CALL_MAME_DEBUG;
+
+ //remove after testing
+ if(PC != PPC) op = cpu_readop(PC);
+
+ //Update Timer (if any timers are running)
+ if(R_TCON & 0x50)
+ update_timer(i8051.prev_used_cycles);
+
+ //Update Serial (if serial port sending data)
+ if(uart.sending)
+ update_serial(i8051.prev_used_cycles);
+
+ //Update PC
+ PC += 1;
+ //Decrement total count by # of cycles used for this opcode
+ i8051_icount -= (i8051_cycles[op]);
+
+ switch( op )
+ {
+ //NOP
+ case 0x00: /* 1: 0000 0000 */
+ nop();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x01:
+ ajmp();
+ break;
+ //LJMP code addr
+ case 0x02: /* 1: 0000 0010 */
+ ljmp();
+ break;
+ //RR A
+ case 0x03: /* 1: 0000 0011 */
+ rr_a();
+ break;
+ //INC A
+ case 0x04: /* 1: 0000 0100 */
+ inc_a();
+ break;
+ //INC data addr
+ case 0x05: /* 1: 0000 0101 */
+ RWM=1;
+ inc_mem();
+ RWM=0;
+ break;
+ //INC @R0/@R1 /* 1: 0000 011i */
+ case 0x06:
+ case 0x07:
+ inc_ir(op&1);
+ break;
+ //INC R0 to R7 /* 1: 0000 1rrr */
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ inc_r(op&7);
+ break;
+ //JBC bit addr, code addr
+ case 0x10: /* 1: 0001 0000 */
+ RWM=1;
+ jbc();
+ RWM=0;
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x11:
+ acall();
+ break;
+ //LCALL code addr
+ case 0x12: /* 1: 0001 0010 */
+ lcall();
+ break;
+ //RRC A
+ case 0x13: /* 1: 0001 0011 */
+ rrc_a();
+ break;
+ //DEC A
+ case 0x14: /* 1: 0001 0100 */
+ dec_a();
+ break;
+ //DEC data addr
+ case 0x15: /* 1: 0001 0101 */
+ RWM=1;
+ dec_mem();
+ RWM=0;
+ break;
+ //DEC @R0/@R1 /* 1: 0001 011i */
+ case 0x16:
+ case 0x17:
+ dec_ir(op&1);
+ break;
+ //DEC R0 to R7 /* 1: 0001 1rrr */
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ dec_r(op&7);
+ break;
+ //JB bit addr, code addr
+ case 0x20: /* 1: 0010 0000 */
+ jb();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x21:
+ ajmp();
+ break;
+ //RET
+ case 0x22: /* 1: 0010 0010 */
+ ret();
+ break;
+ //RL A
+ case 0x23: /* 1: 0010 0011 */
+ rl_a();
+ break;
+ //ADD A, #data
+ case 0x24: /* 1: 0010 0100 */
+ add_a_byte();
+ break;
+ //ADD A, data addr
+ case 0x25: /* 1: 0010 0101 */
+ add_a_mem();
+ break;
+ //ADD A, @R0/@R1 /* 1: 0010 011i */
+ case 0x26:
+ case 0x27:
+ add_a_ir(op&1);
+ break;
+ //ADD A, R0 to R7 /* 1: 0010 1rrr */
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ add_a_r(op&7);
+ break;
+ //JNB bit addr, code addr
+ case 0x30: /* 1: 0011 0000 */
+ jnb();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x31:
+ acall();
+ break;
+ //RETI
+ case 0x32: /* 1: 0011 0010 */
+ reti();
+ break;
+ //RLC A
+ case 0x33: /* 1: 0011 0011 */
+ rlc_a();
+ break;
+ //ADDC A, #data
+ case 0x34: /* 1: 0011 0100 */
+ addc_a_byte();
+ break;
+ //ADDC A, data addr
+ case 0x35: /* 1: 0011 0101 */
+ addc_a_mem();
+ break;
+ //ADDC A, @R0/@R1 /* 1: 0011 011i */
+ case 0x36:
+ case 0x37:
+ addc_a_ir(op&1);
+ break;
+ //ADDC A, R0 to R7 /* 1: 0011 1rrr */
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ addc_a_r(op&7);
+ break;
+ //JC code addr
+ case 0x40: /* 1: 0100 0000 */
+ jc();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x41:
+ ajmp();
+ break;
+ //ORL data addr, A
+ case 0x42: /* 1: 0100 0010 */
+ RWM=1;
+ orl_mem_a();
+ RWM=0;
+ break;
+ //ORL data addr, #data
+ case 0x43: /* 1: 0100 0011 */
+ RWM=1;
+ orl_mem_byte();
+ RWM=0;
+ break;
+ //ORL A, #data
+ case 0x44: /* 1: 0100 0100 */
+ orl_a_byte();
+ break;
+ //ORL A, data addr
+ case 0x45: /* 1: 0100 0101 */
+ orl_a_mem();
+ break;
+ //ORL A, @RO/@R1 /* 1: 0100 011i */
+ case 0x46:
+ case 0x47:
+ orl_a_ir(op&1);
+ break;
+ //ORL A, RO to R7 /* 1: 0100 1rrr */
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ orl_a_r(op&7);
+ break;
+ //JNC code addr
+ case 0x50: /* 1: 0101 0000 */
+ jnc();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x51:
+ acall();
+ break;
+ //ANL data addr, A
+ case 0x52: /* 1: 0101 0010 */
+ RWM=1;
+ anl_mem_a();
+ RWM=0;
+ break;
+ //ANL data addr, #data
+ case 0x53: /* 1: 0101 0011 */
+ RWM=1;
+ anl_mem_byte();
+ RWM=0;
+ break;
+ //ANL A, #data
+ case 0x54: /* 1: 0101 0100 */
+ anl_a_byte();
+ break;
+ //ANL A, data addr
+ case 0x55: /* 1: 0101 0101 */
+ anl_a_mem();
+ break;
+ //ANL A, @RO/@R1 /* 1: 0101 011i */
+ case 0x56:
+ case 0x57:
+ anl_a_ir(op&1);
+ break;
+ //ANL A, RO to R7 /* 1: 0101 1rrr */
+ case 0x58:
+ case 0x59:
+ case 0x5a:
+ case 0x5b:
+ case 0x5c:
+ case 0x5d:
+ case 0x5e:
+ case 0x5f:
+ anl_a_r(op&7);
+ break;
+ //JZ code addr
+ case 0x60: /* 1: 0110 0000 */
+ jz();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x61:
+ ajmp();
+ break;
+ //XRL data addr, A
+ case 0x62: /* 1: 0110 0010 */
+ RWM=1;
+ xrl_mem_a();
+ RWM=0;
+ break;
+ //XRL data addr, #data
+ case 0x63: /* 1: 0110 0011 */
+ RWM=1;
+ xrl_mem_byte();
+ RWM=0;
+ break;
+ //XRL A, #data
+ case 0x64: /* 1: 0110 0100 */
+ xrl_a_byte();
+ break;
+ //XRL A, data addr
+ case 0x65: /* 1: 0110 0101 */
+ xrl_a_mem();
+ break;
+ //XRL A, @R0/@R1 /* 1: 0110 011i */
+ case 0x66:
+ case 0x67:
+ xrl_a_ir(op&1);
+ break;
+ //XRL A, R0 to R7 /* 1: 0110 1rrr */
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f:
+ xrl_a_r(op&7);
+ break;
+ //JNZ code addr
+ case 0x70: /* 1: 0111 0000 */
+ jnz();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x71:
+ acall();
+ break;
+ //ORL C, bit addr
+ case 0x72: /* 1: 0111 0010 */
+ orl_c_bitaddr();
+ break;
+ //JMP @A+DPTR
+ case 0x73: /* 1: 0111 0011 */
+ jmp_iadptr();
+ break;
+ //MOV A, #data
+ case 0x74: /* 1: 0111 0100 */
+ mov_a_byte();
+ break;
+ //MOV data addr, #data
+ case 0x75: /* 1: 0111 0101 */
+ mov_mem_byte();
+ break;
+ //MOV @R0/@R1, #data /* 1: 0111 011i */
+ case 0x76:
+ case 0x77:
+ mov_ir_byte(op&1);
+ break;
+ //MOV R0 to R7, #data /* 1: 0111 1rrr */
+ case 0x78:
+ case 0x79:
+ case 0x7a:
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f:
+ mov_r_byte(op&7);
+ break;
+ //SJMP code addr
+ case 0x80: /* 1: 1000 0000 */
+ sjmp();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0x81:
+ ajmp();
+ break;
+ //ANL C, bit addr
+ case 0x82: /* 1: 1000 0010 */
+ anl_c_bitaddr();
+ break;
+ //MOVC A, @A + PC
+ case 0x83: /* 1: 1000 0011 */
+ movc_a_iapc();
+ break;
+ //DIV AB
+ case 0x84: /* 1: 1000 0100 */
+ div_ab();
+ break;
+ //MOV data addr, data addr
+ case 0x85: /* 1: 1000 0101 */
+ mov_mem_mem();
+ break;
+ //MOV data addr, @R0/@R1 /* 1: 1000 011i */
+ case 0x86:
+ case 0x87:
+ mov_mem_ir(op&1);
+ break;
+ //MOV data addr,R0 to R7 /* 1: 1000 1rrr */
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+ mov_mem_r(op&7);
+ break;
+ //MOV DPTR, #data
+ case 0x90: /* 1: 1001 0000 */
+ mov_dptr_byte();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0x91:
+ acall();
+ break;
+ //MOV bit addr, C
+ case 0x92: /* 1: 1001 0010 */
+ RWM = 1;
+ mov_bitaddr_c();
+ RWM = 0;
+ break;
+ //MOVC A, @A + DPTR
+ case 0x93: /* 1: 1001 0011 */
+ movc_a_iadptr();
+ break;
+ //SUBB A, #data
+ case 0x94: /* 1: 1001 0100 */
+ subb_a_byte();
+ break;
+ //SUBB A, data addr
+ case 0x95: /* 1: 1001 0101 */
+ subb_a_mem();
+ break;
+ //SUBB A, @R0/@R1 /* 1: 1001 011i */
+ case 0x96:
+ case 0x97:
+ subb_a_ir(op&1);
+ break;
+ //SUBB A, R0 to R7 /* 1: 1001 1rrr */
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+ subb_a_r(op&7);
+ break;
+ //ORL C, /bit addr
+ case 0xa0: /* 1: 1010 0000 */
+ orl_c_nbitaddr();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0xa1:
+ ajmp();
+ break;
+ //MOV C, bit addr
+ case 0xa2: /* 1: 1010 0010 */
+ mov_c_bitaddr();
+ break;
+ //INC DPTR
+ case 0xa3: /* 1: 1010 0011 */
+ inc_dptr();
+ break;
+ //MUL AB
+ case 0xa4: /* 1: 1010 0100 */
+ mul_ab();
+ break;
+ //reserved
+ case 0xa5: /* 1: 1010 0101 */
+ illegal();
+ break;
+ //MOV @R0/@R1, data addr /* 1: 1010 011i */
+ case 0xa6:
+ case 0xa7:
+ mov_ir_mem(op&1);
+ break;
+ //MOV R0 to R7, data addr /* 1: 1010 1rrr */
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ mov_r_mem(op&7);
+ break;
+ //ANL C,/bit addr
+ case 0xb0: /* 1: 1011 0000 */
+ anl_c_nbitaddr();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0xb1:
+ acall();
+ break;
+ //CPL bit addr
+ case 0xb2: /* 1: 1011 0010 */
+ RWM=1;
+ cpl_bitaddr();
+ RWM=0;
+ break;
+ //CPL C
+ case 0xb3: /* 1: 1011 0011 */
+ cpl_c();
+ break;
+ //CJNE A, #data, code addr
+ case 0xb4: /* 1: 1011 0100 */
+ cjne_a_byte();
+ break;
+ //CJNE A, data addr, code addr
+ case 0xb5: /* 1: 1011 0101 */
+ cjne_a_mem();
+ break;
+ //CJNE @R0/@R1, #data, code addr /* 1: 1011 011i */
+ case 0xb6:
+ case 0xb7:
+ cjne_ir_byte(op&1);
+ break;
+ //CJNE R0 to R7, #data, code addr/* 1: 1011 1rrr */
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ cjne_r_byte(op&7);
+ break;
+ //PUSH data addr
+ case 0xc0: /* 1: 1100 0000 */
+ push();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0xc1:
+ ajmp();
+ break;
+ //CLR bit addr
+ case 0xc2: /* 1: 1100 0010 */
+ RWM=1;
+ clr_bitaddr();
+ RWM=0;
+ break;
+ //CLR C
+ case 0xc3: /* 1: 1100 0011 */
+ clr_c();
+ break;
+ //SWAP A
+ case 0xc4: /* 1: 1100 0100 */
+ swap_a();
+ break;
+ //XCH A, data addr
+ case 0xc5: /* 1: 1100 0101 */
+ xch_a_mem();
+ break;
+ //XCH A, @RO/@R1 /* 1: 1100 011i */
+ case 0xc6:
+ case 0xc7:
+ xch_a_ir(op&1);
+ break;
+ //XCH A, RO to R7 /* 1: 1100 1rrr */
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ xch_a_r(op&7);
+ break;
+ //POP data addr
+ case 0xd0: /* 1: 1101 0000 */
+ pop();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0xd1:
+ acall();
+ break;
+ //SETB bit addr
+ case 0xd2: /* 1: 1101 0010 */
+ RWM=1;
+ setb_bitaddr();
+ RWM=0;
+ break;
+ //SETB C
+ case 0xd3: /* 1: 1101 0011 */
+ setb_c();
+ break;
+ //DA A
+ case 0xd4: /* 1: 1101 0100 */
+ da_a();
+ break;
+ //DJNZ data addr, code addr
+ case 0xd5: /* 1: 1101 0101 */
+ RWM=1;
+ djnz_mem();
+ RWM=0;
+ break;
+ //XCHD A, @R0/@R1 /* 1: 1101 011i */
+ case 0xd6:
+ case 0xd7:
+ xchd_a_ir(op&1);
+ break;
+ //DJNZ R0 to R7,code addr /* 1: 1101 1rrr */
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ djnz_r(op&7);
+ break;
+ //MOVX A,@DPTR
+ case 0xe0: /* 1: 1110 0000 */
+ movx_a_idptr();
+ break;
+ //AJMP code addr /* 1: aaa0 0001 */
+ case 0xe1:
+ ajmp();
+ break;
+ //MOVX A, @R0/@R1 /* 1: 1110 001i */
+ case 0xe2:
+ case 0xe3:
+ movx_a_ir(op&1);
+ break;
+ //CLR A
+ case 0xe4: /* 1: 1110 0100 */
+ clr_a();
+ break;
+ //MOV A, data addr
+ case 0xe5: /* 1: 1110 0101 */
+ mov_a_mem();
+ break;
+ //MOV A,@RO/@R1 /* 1: 1110 011i */
+ case 0xe6:
+ case 0xe7:
+ mov_a_ir(op&1);
+ break;
+ //MOV A,R0 to R7 /* 1: 1110 1rrr */
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ mov_a_r(op&7);
+ break;
+ //MOVX @DPTR,A
+ case 0xf0: /* 1: 1111 0000 */
+ movx_idptr_a();
+ break;
+ //ACALL code addr /* 1: aaa1 0001 */
+ case 0xf1:
+ acall();
+ break;
+ //MOVX @R0/@R1,A /* 1: 1111 001i */
+ case 0xf2:
+ case 0xf3:
+ movx_ir_a(op&1);
+ break;
+ //CPL A
+ case 0xf4: /* 1: 1111 0100 */
+ cpl_a();
+ break;
+ //MOV data addr, A
+ case 0xf5: /* 1: 1111 0101 */
+ mov_mem_a();
+ break;
+ //MOV @R0/@R1, A /* 1: 1111 011i */
+ case 0xf6:
+ case 0xf7:
+ mov_ir_a(op&1);
+ break;
+ //MOV R0 to R7, A /* 1: 1111 1rrr */
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ mov_r_a(op&7);
+ break;
+ default:
+ illegal();
+ }
+
+ //Store # of used cycles for this opcode (for timer & serial check at top of code)
+ i8051.prev_used_cycles = i8051_cycles[op];
+
+ //Check for pending interrupts & handle - remove cycles used
+ i8051_icount-=check_interrupts();
+
+ } while( i8051_icount > 0 );
+
+ return cycles - i8051_icount;
+}
+
+/* Get registers, return context size */
+void i8051_get_context(void *dst)
+{
+ if( dst )
+ memcpy(dst, &i8051, sizeof(I8051));
+}
+
+/* Set registers */
+void i8051_set_context(void *src)
+{
+ if( src )
+ memcpy(&i8051, src, sizeof(I8051));
+}
+
+/* Get Internal RAM value */
+unsigned i8051_get_intram(int offset)
+{
+ UINT8 ram_ret = 0;
+ RWM = 1;
+ ram_ret = IRAM_R(offset);
+ RWM = 0;
+ return ram_ret;
+}
+
+/*NOTE: These are not used by the opcode functions, they are here only for MAME requirements*/
+unsigned i8051_get_reg(int regnum)
+{
+ switch( regnum )
+ {
+ case REG_PREVIOUSPC: return PPC;
+ case REG_PC:
+ case I8051_PC: return PC;
+ case REG_SP:
+ case I8051_SP: return R_SP;
+ case I8051_ACC: return R_ACC;
+ case I8051_PSW: return R_PSW;
+ case I8051_B: return R_B;
+ case I8051_DPH: return R_DPH;
+ case I8051_DPL: return R_DPL;
+ case I8051_IE: return R_IE;
+ //Not real registers
+ case I8051_R0: return R_R(0);
+ case I8051_R1: return R_R(1);
+ case I8051_R2: return R_R(2);
+ case I8051_R3: return R_R(3);
+ case I8051_R4: return R_R(4);
+ case I8051_R5: return R_R(5);
+ case I8051_R6: return R_R(6);
+ case I8051_R7: return R_R(7);
+ case I8051_RB: return GET_RS;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+/*NOTE: These are not used by the opcode functions, they are here only for MAME requirements*/
+void i8051_set_reg (int regnum, unsigned val)
+{
+ switch( regnum )
+ {
+ case REG_PC:
+ case I8051_PC: PC = val & 0xffff; break;
+ case REG_SP:
+ case I8051_SP: SFR_W(SP,val); break; //Use SFR to handle error checking
+ case I8051_ACC: SFR_W(ACC,val); break;
+ case I8051_PSW: SFR_W(PSW,val); break;
+ case I8051_B: SFR_W(B,val); break;
+ case I8051_DPH: SFR_W(DPH,val); break;
+ case I8051_DPL: SFR_W(DPL,val); break;
+ case I8051_IE: SFR_W(IE,val); break;
+ //Not real registers
+ case I8051_R0: R_R(0) = val; break;
+ case I8051_R1: R_R(1) = val; break;
+ case I8051_R2: R_R(2) = val; break;
+ case I8051_R3: R_R(3) = val; break;
+ case I8051_R4: R_R(4) = val; break;
+ case I8051_R5: R_R(5) = val; break;
+ case I8051_R6: R_R(6) = val; break;
+ case I8051_R7: R_R(7) = val; break;
+ case I8051_RB: SET_RS( (val&3) ); break;
+
+ default:
+ return;
+ }
+}
+
+void i8051_set_irq_line(int irqline, int state)
+{
+ switch( irqline )
+ {
+ //External Interrupt 0
+ case I8051_INT0_LINE:
+ //Line Asserted?
+ if (state != CLEAR_LINE) {
+ //Is the enable flag for this interrupt set?
+ if(GET_EX0) {
+ //Need cleared->active line transition? (Logical 1-0 Pulse on the line) - CLEAR->ASSERT Transition since INT0 active lo!
+ if(GET_IT0){
+ if(i8051.last_int0 == CLEAR_LINE)
+ SET_IE0(1);
+ }
+ else
+ SET_IE0(1); //Nope, just set it..
+ }
+ }
+ else
+ SET_IE0(0); //Clear Int occurred flag
+ i8051.last_int0 = state;
+
+ //Do the interrupt & handle - remove machine cycles used
+ if(GET_IE0)
+ i8051_icount-=check_interrupts();
+ break;
+
+ //External Interrupt 1
+ case I8051_INT1_LINE:
+
+ //Line Asserted?
+ if (state != CLEAR_LINE) {
+ if(GET_EX1) {
+ //Need cleared->active line transition? (Logical 1-0 Pulse on the line) - CLEAR->ASSERT Transition since INT1 active lo!
+ if(GET_IT1){
+ if(i8051.last_int1 == CLEAR_LINE)
+ SET_IE1(1);
+ }
+ else
+ SET_IE1(1); //Nope, just set it..
+ }
+ }
+ else
+ SET_IE1(0); //Clear Int occurred flag
+ i8051.last_int1 = state;
+
+ //Do the interrupt & handle - remove machine cycles used
+ if(GET_IE1)
+ i8051_icount-=check_interrupts();
+ break;
+
+ //Serial Port Receive
+ case I8051_RX_LINE:
+ //Is the enable flags for this interrupt set?
+ if(GET_ES && GET_REN) {
+ int data = 0;
+ //Call our callball function to retrieve the data
+ if(i8051.serial_rx_callback)
+ data = i8051.serial_rx_callback();
+ //Update the register directly, since SFR_W() will trigger a serial transmit instead!
+ R_SBUF=data;
+ //Flag the IRQ
+ SET_RI(1);
+ }
+ break;
+ //Note: we won't call check interrupts, we'll let the main loop catch it
+ }
+}
+
+/***********************************************************************************
+ Check for pending Interrupts and process - returns # of cycles used for the int
+
+ Note about priority & interrupting interrupts..
+ 1) A high priority interrupt cannot be interrupted by anything!
+ 2) A low priority interrupt can ONLY be interrupted by a high priority interrupt
+ 3) If more than 1 Interrupt Flag is set (ie, 2 simultaneous requests occur),
+ the following logic works as follows:
+ 1) If two requests come in of different priority levels, the higher one is selected..
+ 2) If the requests are of the same level, an internal order is used:
+ a) IEO
+ b) TFO
+ c) IE1
+ d) TF1
+ e) RI+TI
+ f) TF2+EXF2
+ **********************************************************************************/
+INLINE UINT8 check_interrupts(void)
+{
+ //If All Inerrupts Disabled or no pending abort..
+ if(!GET_EA) return 0;
+
+ //Any Interrupts Pending?
+ if(NO_PENDING_IRQ) return 0;
+
+ //Skip if current irq in progress is high priority!
+ if(i8051.irq_priority) { /* LOG(("high priority irq in progress, skipping irq request\n")); */ return 0; }
+
+ //Check which interrupt(s) requests have occurred..
+ //NOTE: The order of checking is based on the internal/default priority levels when levels are the same
+
+ //External Int 0
+ if(GET_IE0) {
+ //Set vector & priority level request
+ i8051.int_vec = V_IE0;
+ i8051.priority_request = GET_PX0;
+ }
+ //Timer 0 overflow
+ if(!i8051.priority_request && GET_TF0 && (!i8051.int_vec || (i8051.int_vec && GET_PT0))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_TF0;
+ i8051.priority_request = GET_PT0;
+ }
+ //External Int 1
+ if(!i8051.priority_request && GET_IE1 && (!i8051.int_vec || (i8051.int_vec && GET_PX1))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_IE1;
+ i8051.priority_request = GET_PX1;
+ }
+ //Timer 1 overflow
+ if(!i8051.priority_request && GET_TF1 && (!i8051.int_vec || (i8051.int_vec && GET_PT1))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_TF1;
+ i8051.priority_request = GET_PT1;
+ }
+ //Serial Interrupt Transmit/Receive Interrupts (Note: ES Bit - Serial Interrupts must be enabled)
+ if(!i8051.priority_request && GET_ES && (GET_TI || GET_RI) && (!i8051.int_vec || (i8051.int_vec && GET_PS))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_RITI;
+ i8051.priority_request = GET_PS;
+ }
+#if (HAS_I8052 || HAS_I8752)
+ //Timer 2 overflow (Either Timer Overflow OR External Interrupt)
+ if(!i8051.priority_request && GET_ET2 && (GET_TF2 || GET_EXF2) && (!i8051.int_vec || (i8051.int_vec && GET_PT2))) {
+ //Set vector & priority level request
+ i8051.int_vec = V_TF2;
+ i8051.priority_request = GET_PT2;
+ }
+#endif
+
+ //Skip the interrupt request if currently processing is lo priority, and the new request IS NOT HI PRIORITY!
+ if(i8051.cur_irq < 0xff && !i8051.priority_request)
+ { LOG(("low priority irq in progress already, skipping low irq request\n")); return 0; }
+
+ /*** --- Perform the interrupt --- ***/
+
+ //Save current pc to stack, set pc to new interrupt vector
+ push_pc();
+ PC = i8051.int_vec;
+
+ //Set current Irq & Priority being serviced
+ i8051.cur_irq = i8051.int_vec;
+ i8051.irq_priority = i8051.priority_request;
+
+ //Clear any interrupt flags that should be cleared since we're servicing the irq!
+ switch(i8051.cur_irq) {
+ case V_IE0:
+ //External Int Flag only cleared when configured as Edge Triggered..
+ //if(GET_IT0) - for some reason having this, breaks alving dmd games
+ SET_IE0(0);
+ break;
+ case V_TF0:
+ //Timer 0 - Always clear Flag
+ SET_TF0(0);
+ break;
+ case V_IE1:
+ //External Int Flag only cleared when configured as Edge Triggered..
+ //if(GET_IT1) - for some reason having this, breaks alving dmd games
+ SET_IE1(0);
+ break;
+ case V_TF1:
+ //Timer 0 - Always clear Flag
+ SET_TF1(0);
+ break;
+ case V_RITI:
+ // no flags are cleared, TI and RI remain set until reset by software
+ break;
+#if (HAS_I8052 || HAS_I8752)
+ case V_TF2:
+ // no flags are cleared according to manual
+ break;
+#endif
+ }
+
+ //Clear vars.. (these are part of the 8051 structure for speed, so we don't have to dynamically allocate space each time)
+ i8051.int_vec = 0;
+ i8051.priority_request = 0;
+
+ //All interrupts use 2 machine cycles
+ return 24;
+}
+
+
+void i8051_set_irq_callback(int (*callback)(int irqline))
+{
+ i8051.irq_callback = callback;
+}
+
+void i8051_set_serial_tx_callback(void (*callback)(int data))
+{
+ //Hold in static variable since this function can get called before reset has run, which wipes i8051 memory clean
+ hold_serial_tx_callback = callback;
+}
+void i8051_set_serial_rx_callback(int (*callback)(void))
+{
+ //Hold in static variable since this function can get called before reset has run, which wipes i8051 memory clean
+ hold_serial_rx_callback = callback;
+}
+
+void i8051_set_eram_iaddr_callback(READ32_HANDLER((*callback)))
+{
+ //Hold in static variable since this function can get called before reset has run, which wipes i8051 memory clean
+ hold_eram_iaddr_callback = callback;
+}
+
+
+void i8051_state_save(void *file)
+{
+}
+
+void i8051_state_load(void *file)
+{
+}
+
+/* HELPER FUNCTIONS */
+
+/*All writes to SFR are handled here*/
+static WRITE8_HANDLER(sfr_write)
+{
+ data &= 0xff; //Ensure only 8 bits
+ switch (offset)
+ {
+ case P0:
+ R_P0 = data;
+ OUT(0,data);
+ break;
+
+ case SP:
+ if(offset > 0xff)
+ LOG(("i8051 #%d: attemping to write value to SP past 256 bytes at 0x%04x\n", cpu_getactivecpu(), PC));
+ R_SP = data&0xff; //keep sp w/in 256 bytes
+ break;
+
+ case DPL: R_DPL = data; break;
+ case DPH: R_DPH = data; break;
+ case PCON: R_PCON= data; break;
+ case TCON: R_TCON= data; break;
+ case TMOD: R_TMOD= data; break;
+ case TL0: R_TL0 = data; break;
+ case TL1: R_TL1 = data; break;
+ case TH0: R_TH0 = data; break;
+ case TH1: R_TH1 = data; break;
+
+ case P1:
+ R_P1 = data;
+ OUT(1,data);
+ break;
+
+ case SCON: {
+ //Update register
+ R_SCON = data;
+ break;
+ }
+
+ case SBUF:
+ //R_SBUF = data; //This register is used only for "Receiving data coming in!"
+ serial_transmit(data); //Set up to transmit the data
+ break;
+
+ case P2:
+ R_P2 = data;
+ OUT(2,data);
+ break;
+
+ case IE: R_IE = data; break;
+
+ case P3:
+ R_P3 = data;
+ OUT(3,data);
+ break;
+
+ case IP: R_IP = data; break;
+
+ //8052 Only registers
+ #if (HAS_I8052 || HAS_I8752)
+ case T2CON: R_T2CON = data; break;
+ case RCAP2L: R_RCAP2L = data; break;
+ case RCAP2H: R_RCAP2H = data; break;
+ case TL2: R_TL2 = data; break;
+ case TH2: R_TH2 = data; break;
+ #endif
+
+ case PSW:
+ R_PSW = data;
+ SET_PARITY;
+ break;
+
+ case ACC:
+ R_ACC = data;
+ SET_PARITY;
+ break;
+
+ case B: R_B = data; break;
+
+ /* Illegal or non-implemented sfr */
+ default:
+ LOG(("i8051 #%d: attemping to write to an invalid/non-implemented SFR address: %x at 0x%04x, data=%x\n", cpu_getactivecpu(), offset,PC,data));
+ }
+}
+
+/*All reads to SFR are handled here*/
+static READ8_HANDLER(sfr_read)
+{
+ switch (offset)
+ {
+ case P0:
+ if(RWM)
+ return R_P0; //Read directly from port latch
+ else
+ return IN(0); //Read from actual port
+ case SP: return R_SP;
+ case DPL: return R_DPL;
+ case DPH: return R_DPH;
+ case PCON: return R_PCON;
+ case TCON: return R_TCON;
+ case TMOD: return R_TMOD;
+ case TL0: return R_TL0;
+ case TL1: return R_TL1;
+ case TH0: return R_TH0;
+ case TH1: return R_TH1;
+ case P1:
+ if(RWM)
+ return R_P1; //Read directly from port latch
+ else
+ return IN(1); //Read from actual port
+ case SCON: return R_SCON;
+ case SBUF: return R_SBUF;
+ case P2:
+ if(RWM)
+ return R_P2; //Read directly from port latch
+ else
+ return IN(2); //Read from actual port
+ case IE: return R_IE;
+ case P3:
+ if(RWM)
+ return R_P3; //Read directly from port latch
+ else
+ return IN(3); //Read from actual port
+ case IP: return R_IP;
+ //8052 Only registers
+ #if (HAS_I8052 || HAS_I8752)
+ case T2CON: return R_T2CON;
+ case RCAP2L: return R_RCAP2L;
+ case RCAP2H: return R_RCAP2H;
+ case TL2: return R_TL2;
+ case TH2: return R_TH2;
+ #endif
+ case PSW: return R_PSW;
+ case ACC: return R_ACC;
+ case B: return R_B;
+
+ /* Illegal or non-implemented sfr */
+ default:
+ LOG(("i8051 #%d: attemping to read an invalid/non-implemented SFR address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+ }
+ return 0xff;
+}
+
+/* Reads the contents of the Internal RAM memory */
+/* Anything above 0x7f is a sfr/register */
+static READ8_HANDLER(internal_ram_read)
+{
+ if (offset < 0x80)
+ return i8051.IntRam[offset];
+ else {
+ if (offset < 0x100)
+ return SFR_R(offset);
+ else
+ LOG(("i8051 #%d: attemping to read from an invalid Internal Ram address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+ }
+ return 0xff;
+}
+
+/* Writes the contents of the Internal RAM memory */
+/* Anything above 0x7f is a sfr/register */
+static WRITE8_HANDLER(internal_ram_write)
+{
+ data &= 0xff; //Ensure it's only 8 bits
+ if (offset < 0x80)
+ i8051.IntRam[offset] = data;
+ else {
+ if (offset < 0x100)
+ SFR_W(offset,data);
+ else
+ LOG(("i8051 #%d: attemping to write to invalid Internal Ram address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+ }
+}
+
+/* Reads the contents of the Internal RAM memory (BUT CALLED FROM AN INDIRECT ADDRESSING MODE) */
+/* Different chip types handle differently, for speed, simply call the chip's handler */
+static READ8_HANDLER(internal_ram_iread)
+{
+ return i8051.iram_iread(offset);
+}
+
+/* Writes the contents of the Internal RAM memory (BUT CALLED FROM AN INDIRECT ADDRESSING MODE) */
+/* Different chip types handle differently, for speed, simply call the chip's handler */
+static WRITE8_HANDLER(internal_ram_iwrite)
+{
+ i8051.iram_iwrite(offset,data);
+}
+
+/*Generate an external ram address for read/writing using indirect addressing mode */
+/*The lowest 8 bits of the address are passed in (from the R0/R1 register), however
+ the hardware can be configured to set the rest of the address lines to any available output port pins, which
+ means the only way we can implement this is to allow the driver to setup a callback to generate the
+ address as defined by the specific hardware setup. We'll assume the address won't be bigger than 32 bits
+*/
+static READ32_HANDLER(external_ram_iaddr)
+{
+ if(i8051.eram_iaddr_callback)
+ return i8051.eram_iaddr_callback(offset,mem_mask);
+ else
+ LOG(("i8051 #%d: external ram address requested (8 bit offset=%02x), but no callback available! at PC:%04x\n", cpu_getactivecpu(), offset, PC));
+
+ return offset;
+}
+
+/*Push the current PC to the stack*/
+INLINE void push_pc()
+{
+ UINT8 tmpSP = R_SP; //Grab and Increment Stack Pointer
+ tmpSP++; // ""
+ SFR_W(SP,tmpSP); // ""
+ if (tmpSP == R_SP) //Ensure it was able to write to new stack location
+ IRAM_IW(tmpSP, (PC & 0xff)); //Store low byte of PC to Internal Ram (Use IRAM_IW to store stack above 128 bytes)
+ tmpSP = R_SP; //Increment Stack Pointer
+ tmpSP++; // ""
+ SFR_W(SP,tmpSP); // ""
+ if (tmpSP == R_SP) //Ensure it was able to write to new stack location
+ IRAM_IW(tmpSP, ( (PC & 0xff00) >> 8)); //Store hi byte of PC to next address in Internal Ram (Use IRAM_IW to store stack above 128 bytes)
+}
+
+/*Pop the current PC off the stack and into the pc*/
+INLINE void pop_pc()
+{
+ UINT8 tmpSP = R_SP; //Grab Stack Pointer
+ PC = (IRAM_IR(tmpSP) & 0xff) << 8; //Store hi byte to PC (must use IRAM_IR to access stack pointing above 128 bytes)
+ tmpSP = R_SP-1; //Decrement Stack Pointer
+ SFR_W(SP,tmpSP); // ""
+ if (tmpSP == R_SP) //Ensure it was able to write to new stack location
+ PC = PC | IRAM_IR(tmpSP); //Store lo byte to PC (must use IRAM_IR to access stack pointing above 128 bytes)
+ SFR_W(SP,tmpSP-1); //Decrement Stack Pointer
+}
+
+//Set the PSW Parity Flag
+INLINE void set_parity()
+{
+ //This flag will be set when the accumulator contains an odd # of bits set..
+ int i,
+ p = 0;
+ for (i=1; i<=128; i=i*2) { //Test for each of the 8 bits in the ACC!
+ if ((R_ACC & i) != 0)
+ p++; //Keep track of how many bits are set
+ }
+
+ //Update the PSW Pairty bit
+ SET_P(p & 1);
+}
+
+static READ8_HANDLER(bit_address_r)
+{
+ int word;
+ int mask;
+ int bit_pos;
+ int base; /* base of bit space or sfr */
+ int distance; /* distance between bit addressable words */
+ /* 1 for normal bits, 8 for sfr bit addresses */
+
+ offset &= 0xff;
+
+ //User defined bit addresses 0x20-0x2f (values are 0x0-0x7f)
+ if (offset < 0x80) {
+ base = 0x20;
+ distance = 1;
+ }
+ //SFR bit addressable registers
+ else {
+ base = 0x80;
+ distance = 8;
+ }
+ word = ( (offset & 0x78) >> 3) * distance + base;
+ bit_pos = offset & 0x7;
+ mask = 0x1 << bit_pos;
+ return((IRAM_R(word) & mask) >> bit_pos); //Do not use IRAM_IR
+}
+
+
+static WRITE8_HANDLER(bit_address_w)
+{
+ int word;
+ int mask;
+ int bit_pos;
+ int result;
+ int base;
+ int distance;
+
+ offset &= 0xff;
+
+ //User defined bit addresses 0x20-0x2f (values are 0x0-0x7f)
+ if (offset < 0x80) {
+ base = 0x20;
+ distance = 1;
+ }
+ //SFR bit addressable registers
+ else {
+ base = 0x80;
+ distance = 8;
+ }
+ word = ((offset & 0x78) >> 3) * distance + base;
+ bit_pos = offset & 0x7;
+ data = (data & 0x1) << bit_pos;
+ mask = ~(1 << bit_pos) & 0xff;
+ result = IRAM_R(word) & mask; //Do not use IRAM_IR
+ result = result | data;
+ IRAM_W(word, result); //Do not use IRAM_IW
+}
+
+/* The following two handlers are used by the MAME Debugger Memory Window...
+ By keeping these functions separate from the internally used IRAM_W/IRAM_R functions,
+ we can manipulate and display internal memory in the debugger memory window in a layout
+ that is not necessarily how the real memory is.. this will be especially useful for
+ the 8052 chip where both the SFR and the upper 128 bytes of ram are mapped to the same
+ address, so we can handle that here by mapping the sfr to a different address */
+
+READ8_HANDLER(i8051_internal_r)
+{
+ //Restrict internal ram to 256 Bytes max
+ if(offset < 0x100)
+ return IRAM_R(offset);
+ else
+ return 0;
+}
+WRITE8_HANDLER(i8051_internal_w)
+{
+ //Restrict internal ram to 256 Bytes max
+ if(offset < 0x100)
+ IRAM_W(offset,data);
+}
+
+INLINE void do_add_flags(UINT8 a, UINT8 data, UINT8 c)
+{
+ UINT16 result = a+data+c;
+ INT16 result1 = (INT8)a+(INT8)data+c;
+ int cy, ac, ov;
+
+ cy = (result & 0x100) >> 8;
+ result = (a&0x0f)+(data&0x0f)+c;
+ ac = (result & 0x10) >> 4;
+ ov = (result1 < -128 || result1 > 127);
+
+ SET_CY(cy);
+ SET_AC(ac);
+ SET_OV(ov);
+
+#ifdef MAME_DEBUG
+// mame_printf_debug("add: result=%x, c=%x, ac=%x, ov=%x\n",a+data+c,cy,ac,ov);
+#endif
+}
+
+INLINE void do_sub_flags(UINT8 a, UINT8 data, UINT8 c)
+{
+ UINT16 result = a-(data+c);
+ INT16 result1 = (INT8)a-(INT8)(data+c);
+ int cy, ac, ov;
+ cy = (result & 0x100) >> 8;
+ result = (a&0x0f)-((data&0x0f)+c);
+ ac = (result & 0x10) >> 4;
+ ov = (result1 < -128 || result1 > 127);
+ SET_CY(cy);
+ SET_AC(ac);
+ SET_OV(ov);
+
+#ifdef MAME_DEBUG
+// mame_printf_debug("sub: a=%x, d=%x, c=%x, result=%x, cy=%x, ac=%x, ov=%x\n",a,data,c,a-data-c,cy,ac,ov);
+#endif
+}
+
+INLINE void update_timer(int cyc)
+{
+ //This code sucks, needs to be rewritten SJE
+
+ //Todo: Probably better to store the current mode of the timer on a write, so we don't waste time reading it.
+
+ //Note: Counting modes increment on 1 machine cycle (12 oscilator periods) - except Timer 2 in certain modes
+
+ //Update Timer 0
+ if(GET_TR0) {
+ //Determine Mode
+ int mode = (GET_M0_1<<1) | GET_M0_0;
+ int overflow;
+ UINT16 count = 0;
+ switch(mode) {
+ case 0: //13 Bit Timer Mode
+ count = ((R_TH0<<8) | R_TL0);
+ overflow = 0x3fff;
+ //Todo - really, we update HI counter when LO counter hits 0x20
+ case 1: //16 Bit Timer Mode
+ count = ((R_TH0<<8) | R_TL0);
+ overflow = 0xffff;
+ //Check for overflow
+ if((UINT32)(count+(cyc/12))>overflow) {
+ //Any overflow from cycles?
+ cyc-= (overflow-count)*12;
+ count = 0;
+ SET_TF0(1);
+ }
+ //Update the timer
+ if(cyc) {
+ int inctimer = 0;
+ //Gate Bit Set? Timer only incremented if Int0 is set!
+ if(GET_GATE0 && GET_IE0)
+ inctimer = (cyc/12);
+ //Counter Mode? Only increment on 1-0 transition of the Port 3's T0 Line
+ if(GET_CT0) {
+ //Not supported
+ }
+ //Neither, regular timer mode
+ if(!GET_GATE0 && !GET_CT0)
+ inctimer = (cyc/12);
+
+ count+=inctimer; //Increment counter
+ }
+ //Update new values of the counter
+ R_TH0 = (count>>8) & 0xff;
+ R_TL0 = count & 0xff;
+ break;
+ case 2: //8 Bit Autoreload
+ overflow = 0xff;
+ count = R_TL0;
+ //Check for overflow
+ if(count+(cyc/12)>overflow) {
+ SET_TF0(1);
+ //Reload
+ count = R_TH0+(overflow-count);
+ }
+ else
+ count+=(cyc/12);
+ //Update new values of the counter
+ R_TL0 = count & 0xff;
+ break;
+ case 3: //Split Timer
+ //Split Timer 1
+ overflow = 0xff;
+ count = R_TL0;
+ //Check for overflow
+ if(count+(cyc/12)>overflow) {
+ count = overflow-count;
+ SET_TF0(1);
+ }
+ else
+ count+=(cyc/12);
+ //Update new values of the counter
+ R_TL0 = count & 0xff;
+
+ //Split Timer 2
+ if(GET_TR1) {
+ overflow = 0xff;
+ count = R_TH0;
+ //Check for overflow
+ if(count+(cyc/12)>overflow) {
+ count = overflow-count;
+ SET_TF1(1);
+ }
+ else
+ count+=(cyc/12);
+ //Update new values of the counter
+ R_TH0 = count & 0xff;
+ }
+ break;
+ }
+ }
+
+ //Update Timer 1
+ if(GET_TR1) {
+ //Determine Mode
+ int mode = (GET_M1_1<<1) | GET_M1_0;
+ int overflow;
+ UINT16 count = 0;
+ switch(mode) {
+ case 0: //13 Bit Timer Mode
+ count = ((R_TH1<<8) | R_TL1);
+ overflow = 0x3fff;
+ //Todo - really, we update HI counter when LO counter hits 0x20
+ case 1: //16 Bit Timer Mode
+ count = ((R_TH1<<8) | R_TL1);
+ overflow = 0xffff;
+ //Check for overflow
+ if((UINT32)(count+(cyc/12))>overflow) {
+
+ //TODO: Timer 1 can be set as Serial Baud Rate in the 8051 only... process bits here..
+
+ //Any overflow from cycles?
+ cyc-= (overflow-count)*12;
+ count = 0;
+ SET_TF1(1);
+ }
+ //Update the timer
+ if(cyc) {
+ int inctimer = 0;
+ //Gate Bit Set? Timer only incremented if Int0 is set!
+ if(GET_GATE1 && GET_IE1)
+ inctimer = (cyc/12);
+ //Counter Mode? Only increment on 1-0 transition of the Port 3's T0 Line
+ if(GET_CT1) {
+ //Not supported
+ }
+ //Neither, regular timer mode
+ if(!GET_GATE1 && !GET_CT1)
+ inctimer = (cyc/12);
+
+ count+=inctimer; //Increment counter
+ }
+ //Update new values of the counter
+ R_TH1 = (count>>8) & 0xff;
+ R_TL1 = count & 0xff;
+ break;
+ case 2: //8 Bit Autoreload
+ overflow = 0xff;
+ count = R_TL1;
+ //Check for overflow
+ if(count+(cyc/12)>overflow) {
+ SET_TF1(1);
+ //Reload
+ count = R_TH1+(overflow-count);
+ }
+ else
+ count+=(cyc/12);
+ //Update new values of the counter
+ R_TL1 = count & 0xff;
+ break;
+ case 3: //Split Timer
+ break;
+ }
+ }
+
+#if (HAS_I8052 || HAS_I8752)
+ //Update Timer 2
+ if(GET_TR2) {
+ int timerinc, overflow, isoverflow;
+ UINT16 count = ((R_TH2<<8) | R_TL2);
+ timerinc = overflow = isoverflow = 0;
+
+ //Are we in counter mode?
+ if(GET_CT2) {
+ //Not supported
+ }
+ //Are we in timer mode?
+ else {
+ //16 Bit Timer Mode
+ overflow = 0xffff;
+ //Timer 2 Used as Baud Generator? (For now, only *same* send/receive rates supported)
+ if(GET_TCLK || GET_RCLK)
+ timerinc = cyc/2; //Timer increments ever 1/2 cycle in baud mode
+ else
+ //REGULAR TIMER -
+ timerinc = cyc/12; //Timer increments ever 1/12 cycles in normal mode
+
+ //Check for overflow
+ if((UINT32)(count+timerinc)>overflow) {
+ //Set Interrupt flag *unless* used as baud generator
+ if(!GET_TCLK && !GET_RCLK) {
+ SET_TF2(1);
+ }
+ else {
+ //Update bits sent if sending & bits left to send!
+ if(uart.sending && uart.bits_to_send && uart.timerbaud)
+ uart.bits_to_send-=1;
+ }
+ //Auto reload?
+ if(!GET_CP)
+ count = ((R_RCAP2H<<8) | R_RCAP2L); //+(overflow-count);
+ else
+ count = overflow-count;
+ }
+ else {
+ //No overflow, just increment timer
+ count+=timerinc;
+ }
+ //Update flags
+ R_TH2 = (count>>8) & 0xff;
+ R_TL2 = count & 0xff;
+ }
+ }
+#endif
+}
+
+//Set up to transmit data out of serial port
+//NOTE: Enable Serial Port Interrupt bit is NOT required to send/receive data!
+INLINE void serial_transmit(UINT8 data)
+{
+ int mode = (GET_SM0<<1) | GET_SM1;
+
+ //Flag that we're sending data
+ uart.sending = 1;
+ uart.data_out = data;
+ switch(mode) {
+ //8 bit shifter ( + start,stop bit ) - baud set by clock freq / 12
+ case 0:
+ uart.timerbaud = 0;
+ uart.bitcycles = 0;
+ uart.bits_to_send = 8+2;
+ break;
+ //8 bit uart ( + start,stop bit ) - baud set by timer1 or timer2
+ case 1:
+ uart.timerbaud = 1;
+ uart.bits_to_send = 8+2;
+ break;
+ //9 bit uart
+ case 2:
+ case 3:
+ LOG(("Serial mode 2 & 3 not supported in i8051!\n"));
+ break;
+ }
+}
+
+//Check and update status of serial port
+INLINE void update_serial(int cyc)
+{
+ //Any bits left to send?
+ if(uart.bits_to_send) {
+ //Timer Generated baud?
+ if(uart.timerbaud) {
+ //Let Timer overflow handle removing bits
+ }
+ else {
+ //Oscillator Based baud rate = Osc/12 baud rate, however it also means 1 bit = 12 cycles.
+ uart.bitcycles+=cyc;
+ if(uart.bitcycles > 11) {
+ int bits_sent = uart.bitcycles / 12;
+ int diff = uart.bitcycles % 12;
+ //don't allow more bits sent than ready to send
+ if(bits_sent > uart.bits_to_send) {
+ bits_sent = uart.bits_to_send;
+ diff = 0;
+ }
+ uart.bits_to_send-=bits_sent;
+ uart.bitcycles = diff;
+ }
+ }
+ }
+ //If no bits left to send - flag the interrupt & call the callback
+ if(!uart.bits_to_send) {
+ //Clear sending flag
+ uart.sending = 0;
+ uart.bitcycles = 0;
+ //Call the callback function
+ if(i8051.serial_tx_callback)
+ i8051.serial_tx_callback(uart.data_out);
+ //Set Interrupt Flag
+ SET_TI(1);
+ //Note: we'll let the main loop catch the interrupt
+ }
+}
+
+
+/****************************************************************************
+ * 8752 Section
+ ****************************************************************************/
+#if (HAS_I8052 || HAS_I8752)
+void i8752_init (int index, int clock, const void *config, int (*irqcallback)(int)) { i8051_init(index, clock, config, irqcallback); }
+void i8752_reset (void)
+{
+ memset(&i8051, 0, sizeof(I8051));
+ memset(&uart, 0, sizeof(I8051_UART));
+ i8051.subtype = 8752;
+
+ //Set up 8052 specific internal read/write (indirect) handlers..
+ i8051.iram_iread = i8052_internal_ram_iread;
+ i8051.iram_iwrite = i8052_internal_ram_iwrite;
+
+ //Set up serial call back handlers
+ i8051.serial_tx_callback = hold_serial_tx_callback;
+ hold_serial_tx_callback = NULL;
+ i8051.serial_rx_callback = hold_serial_rx_callback;
+ hold_serial_rx_callback = NULL;
+
+ //Setup External ram callback handlers
+ i8051.eram_iaddr_callback = hold_eram_iaddr_callback;
+ hold_eram_iaddr_callback = NULL;
+
+ //Clear Ram (w/0xff)
+ memset(&i8051.IntRam,0xff,sizeof(i8051.IntRam));
+
+ /* these are all defined reset states */
+ PC = 0;
+ SFR_W(SP, 0x7);
+ SFR_W(PSW, 0);
+ SFR_W(DPH, 0);
+ SFR_W(DPL, 0);
+ SFR_W(ACC, 0);
+ SFR_W(B, 0);
+ SFR_W(IP, 0);
+ SFR_W(IE, 0);
+ SFR_W(SCON, 0);
+ SFR_W(TCON, 0);
+ SFR_W(TMOD, 0);
+ SFR_W(TH1, 0);
+ SFR_W(TH0, 0);
+ SFR_W(TL1, 0);
+ SFR_W(TL0, 0);
+ //8052 Only registers
+ SFR_W(T2CON, 0);
+ SFR_W(RCAP2L, 0);
+ SFR_W(RCAP2H, 0);
+ SFR_W(TL2, 0);
+ SFR_W(TH2, 0);
+
+ /* set the port configurations to all 1's */
+ SFR_W(P3, 0xff);
+ SFR_W(P2, 0xff);
+ SFR_W(P1, 0xff);
+ SFR_W(P0, 0xff);
+
+ /* Flag as NO IRQ in Progress */
+ CLEAR_CURRENT_IRQ
+}
+
+void i8752_exit (void) { i8051_exit(); }
+int i8752_execute(int cycles) { return i8051_execute(cycles); }
+void i8752_get_context (void *dst) { i8051_get_context(dst); }
+void i8752_set_context (void *src) { i8051_set_context(src); }
+unsigned i8752_get_reg (int regnum) { return i8051_get_reg(regnum); }
+void i8752_set_reg (int regnum, unsigned val) { i8051_set_reg(regnum,val); }
+void i8752_set_irq_line(int irqline, int state) { i8051_set_irq_line(irqline,state); }
+void i8752_set_irq_callback(int (*callback)(int irqline)) { i8051_set_irq_callback(callback); }
+void i8752_set_serial_tx_callback(void (*callback)(int data)) { i8051_set_serial_tx_callback(callback); }
+void i8752_set_serial_rx_callback(int (*callback)(void)) { i8051_set_serial_rx_callback(callback); }
+void i8752_state_save(void *file) { i8051_state_save(file); }
+void i8752_state_load(void *file) { i8051_state_load(file); }
+#if 0
+const char *i8752_info(void *context, int regnum)
+{
+ switch( regnum )
+ {
+ case CPU_INFO_NAME: return "I8752";
+ }
+ return i8051_info(context,regnum);
+}
+#endif
+
+/* The following two handlers are used by the MAME Debugger Memory Window...
+ By keeping these functions separate from the internally used IRAM_W/IRAM_R functions,
+ we can manipulate and display internal memory in the debugger memory window in a layout
+ that is not necessarily how the real memory is.. this will be especially useful for
+ the 8052 chip where both the SFR and the upper 128 bytes of ram are mapped to the same
+ address, so we can handle that here by mapping the sfr to a different address */
+
+READ8_HANDLER(i8752_internal_r)
+{
+ //USE INDIRECT READ TO ALLOW FULL 256 Bytes of RAM to show in the debugger
+ if(offset < 0x100)
+ return IRAM_IR(offset);
+ else
+ //MAP SFR registers starting at 256 (they are only 128 bytes in size)
+ if(offset < 0x100+0x80)
+ return SFR_R(offset-0x80);
+ else
+ //Everything else is 0 (and invalid)
+ return 0;
+}
+WRITE8_HANDLER(i8752_internal_w)
+{
+ //USE INDIRECT WRITE TO ALLOW FULL 256 Bytes of RAM to show in the debugger
+ if(offset < 0x100)
+ IRAM_IW(offset,data);
+ else
+ if(offset < 0x100+0x80)
+ SFR_W(offset-0x80,data);
+}
+
+/* Reads the contents of the Internal RAM memory INDIRECTLY */
+/* Anything above 0x7f is NOT sfr/register, but rather UPPER 128K OF INTERNAL RAM */
+static READ8_HANDLER(i8052_internal_ram_iread)
+{
+ if (offset < 0x100)
+ return i8051.IntRam[offset];
+ else
+ LOG(("i8051 #%d: attemping to read from an invalid Internal Ram address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+ return 0xff;
+}
+
+/* Writes the contents of the Internal RAM memory INDIRECTLY */
+/* Anything above 0x7f is NOT sfr/register, but rather UPPER 128K OF INTERNAL RAM */
+static WRITE8_HANDLER(i8052_internal_ram_iwrite)
+{
+ data &= 0xff; //Ensure it's only 8 bits
+ if (offset < 0x100)
+ i8051.IntRam[offset] = data;
+ else
+ LOG(("i8051 #%d: attemping to write to an invalid Internal Ram address: %x at 0x%04x\n", cpu_getactivecpu(), offset,PC));
+}
+
+#endif //(HAS_8752)
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void i8051_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC: PC = info->i; break;
+ case CPUINFO_INT_SP: i8051.sp = info->i; break;
+
+ case CPUINFO_INT_INPUT_STATE + I8051_INT0_LINE: i8051_set_irq_line(I8051_INT0_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8051_INT1_LINE: i8051_set_irq_line(I8051_INT1_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8051_T0_LINE: i8051_set_irq_line(I8051_T0_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8051_T1_LINE: i8051_set_irq_line(I8051_T1_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8051_RX_LINE: i8051_set_irq_line(I8051_RX_LINE, info->i); break;
+
+ case CPUINFO_INT_REGISTER + I8051_PC: PC = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_SP: R_SP = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_PSW: i8051.psw = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_ACC: i8051.acc = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_B: i8051.b = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_DPH: i8051.dph = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_DPL: i8051.dpl = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_IE: i8051.ie = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R0: i8051.IntRam[0+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R1: i8051.IntRam[1+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R2: i8051.IntRam[2+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R3: i8051.IntRam[3+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R4: i8051.IntRam[4+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R5: i8051.IntRam[5+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R6: i8051.IntRam[6+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_R7: i8051.IntRam[7+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8051_RB: i8051.IntRam[8+(8*((i8051.psw & 0x18)>>3))] = info->i; break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void i8051_get_info(UINT32 state, cpuinfo *info)
+{
+ I8051 *r = &i8051;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(i8051); break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 20; /* rough guess */ break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+ case CPUINFO_INT_PC: info->i = PC; break;
+ case CPUINFO_INT_SP: info->i = R_SP; break;
+
+ case CPUINFO_INT_REGISTER + I8051_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + I8051_SP: info->i = R_SP; break;
+ case CPUINFO_INT_REGISTER + I8051_PSW: info->i = i8051.psw; break;
+ case CPUINFO_INT_REGISTER + I8051_ACC: info->i = i8051.acc; break;
+ case CPUINFO_INT_REGISTER + I8051_B: info->i = i8051.b; break;
+ case CPUINFO_INT_REGISTER + I8051_DPH: info->i = i8051.dph; break;
+ case CPUINFO_INT_REGISTER + I8051_DPL: info->i = i8051.dpl; break;
+ case CPUINFO_INT_REGISTER + I8051_IE: info->i = i8051.ie; break;
+ case CPUINFO_INT_REGISTER + I8051_R0: info->i = i8051.IntRam[0+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R1: info->i = i8051.IntRam[1+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R2: info->i = i8051.IntRam[2+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R3: info->i = i8051.IntRam[3+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R4: info->i = i8051.IntRam[4+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R5: info->i = i8051.IntRam[5+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R6: info->i = i8051.IntRam[6+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_R7: info->i = i8051.IntRam[7+(8*((i8051.psw & 0x18)>>3))]; break;
+ case CPUINFO_INT_REGISTER + I8051_RB: info->i = i8051.IntRam[8+(8*((i8051.psw & 0x18)>>3))]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i8051_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8051_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8051_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8051_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8051_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8051_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8051_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = i8051_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i8051_icount; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO: info->internal_map = 0; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8051"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "MCS-51"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2003-2004 Steve Ellenoff"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ r->psw & 0x80 ? 'C':'.',
+ r->psw & 0x40 ? 'A':'.',
+ r->psw & 0x20 ? 'F':'.',
+ r->psw & 0x10 ? '0':'.',
+ r->psw & 0x08 ? '1':'.',
+ r->psw & 0x04 ? 'V':'.',
+ r->psw & 0x02 ? '?':'.',
+ r->psw & 0x01 ? 'P':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + I8051_PC: sprintf(info->s, "PC:%04X", r->pc); break;
+ case CPUINFO_STR_REGISTER + I8051_SP: sprintf(info->s, "SP:%02X", r->sp); break;
+ case CPUINFO_STR_REGISTER + I8051_PSW: sprintf(info->s, "PSW:%02X", r->psw); break;
+ case CPUINFO_STR_REGISTER + I8051_ACC: sprintf(info->s, "A:%02X", r->acc); break;
+ case CPUINFO_STR_REGISTER + I8051_B: sprintf(info->s, "B:%02X", r->b); break;
+ case CPUINFO_STR_REGISTER + I8051_DPH: sprintf(info->s, "DPH:%02X", r->dph); break;
+ case CPUINFO_STR_REGISTER + I8051_DPL: sprintf(info->s, "DPL:%02X", r->dpl); break;
+ case CPUINFO_STR_REGISTER + I8051_IE: sprintf(info->s, "IE:%02X", r->ie); break;
+ case CPUINFO_STR_REGISTER + I8051_R0: sprintf(info->s, "R0:%02X", r->IntRam[0+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R1: sprintf(info->s, "R1:%02X", r->IntRam[1+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R2: sprintf(info->s, "R2:%02X", r->IntRam[2+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R3: sprintf(info->s, "R3:%02X", r->IntRam[3+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R4: sprintf(info->s, "R4:%02X", r->IntRam[4+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R5: sprintf(info->s, "R5:%02X", r->IntRam[5+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R6: sprintf(info->s, "R6:%02X", r->IntRam[6+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_R7: sprintf(info->s, "R7:%02X", r->IntRam[7+(8*((r->psw & 0x18)>>3))]); break;
+ case CPUINFO_STR_REGISTER + I8051_RB: sprintf(info->s, "RB:%02X", ((r->psw & 0x18)>>3)); break;
+ }
+}
+
+#if (HAS_I8052)
+void i8052_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8752_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8752_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8752_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8752_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8752_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8752_execute; break;
+
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8052"); break;
+
+ default: i8051_get_info(state, info); break;
+ }
+}
+#endif
+
+#if (HAS_I8751)
+void i8751_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8751"); break;
+
+ default: i8051_get_info(state, info); break;
+ }
+}
+#endif
+
+#if (HAS_I8752)
+void i8752_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8752_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8752_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8752_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8752_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8752_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8752_execute; break;
+
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8752"); break;
+
+ default: i8051_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/i8051/i8051.h b/src/emu/cpu/i8051/i8051.h
new file mode 100644
index 00000000000..6b5178d3400
--- /dev/null
+++ b/src/emu/cpu/i8051/i8051.h
@@ -0,0 +1,157 @@
+/*****************************************************************************
+ *
+ * i8051.h
+ * Portable MCS-51 Family Emulator
+ *
+ * Chips in the family:
+ * 8051 Product Line (8031,8051,8751)
+ * 8052 Product Line (8032,8052,8752)
+ * 8054 Product Line (8054)
+ * 8058 Product Line (8058)
+ *
+ * Copyright (c) 2003 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Intel(tm) MC51 Microcontroller Family Users Manual' and
+ * #2) 8051 simulator by Travis Marlatte
+ * #3) Portable UPI-41/8041/8741/8042/8742 emulator V0.1 by Juergen Buchmueller (MAME CORE)
+ *
+ *****************************************************************************/
+
+#ifndef _I8051_H
+#define _I8051_H
+
+#include "cpuintrf.h"
+
+enum {
+ I8051_PC=1, I8051_SP, I8051_PSW, I8051_ACC, I8051_B, I8051_DPH, I8051_DPL, I8051_IE,
+ I8051_R0, I8051_R1, I8051_R2, I8051_R3, I8051_R4, I8051_R5, I8051_R6, I8051_R7, I8051_RB
+};
+
+#define I8051_INT0_LINE 0 /* External Interrupt 0 */
+#define I8051_INT1_LINE 1 /* External Interrupt 1 */
+#define I8051_T0_LINE 2 /* Timer 0 External Input */
+#define I8051_T1_LINE 3 /* Timer 1 External Input */
+#define I8051_RX_LINE 4 /* Serial Port Receive Line */
+
+/* definition of the special function registers. Note that the values are */
+/* the same as the internal memory address in the 8051 */
+#define P0 0x80
+#define SP 0x81
+#define DPL 0x82
+#define DPH 0x83
+#define PCON 0x87
+#define TCON 0x88
+#define TMOD 0x89
+#define TL0 0x8a
+#define TL1 0x8b
+#define TH0 0x8c
+#define TH1 0x8d
+#define P1 0x90
+#define SCON 0x98
+#define SBUF 0x99
+#define P2 0xa0
+#define IE 0xa8
+#define P3 0xb0
+#define IP 0xb8
+//8052 Only registers
+#if (HAS_I8052 || HAS_I8752)
+ #define T2CON 0xc8
+ #define RCAP2L 0xca
+ #define RCAP2H 0xcb
+ #define TL2 0xcc
+ #define TH2 0xcd
+#endif
+#define PSW 0xd0
+#define ACC 0xe0
+#define B 0xf0
+
+/* commonly used bit address for the 8051 */
+#define C 0xd7
+#define P 0xd0
+#define AC 0xd6
+#define OV 0xd2
+#define TF0 0x8d
+#define TF1 0x8f
+#define IE0 0x89
+#define IE1 0x8b
+#define TI 0x99
+#define RI 0x98
+
+#define TI_FLAG 1
+#define RI_FLAG 2
+
+extern int i8051_icount; /* cycle count */
+
+extern void i8051_init (int index, int clock, const void *config, int (*irqcallback)(int)); /* Initialize save states */
+extern void i8051_reset (void); /* Reset registers to the initial values */
+extern void i8051_exit (void); /* Shut down CPU core */
+extern int i8051_execute(int cycles); /* Execute cycles - returns number of cycles actually run */
+extern void i8051_get_context (void *dst); /* Get registers, return context size */
+extern void i8051_set_context (void *src); /* Set registers */
+extern unsigned i8051_get_intram (int offset);
+extern unsigned i8051_get_reg (int regnum);
+extern void i8051_set_reg (int regnum, unsigned val);
+extern void i8051_set_irq_line(int irqline, int state);
+extern void i8051_set_irq_callback(int (*callback)(int irqline));
+extern void i8051_state_save(void *file);
+extern void i8051_state_load(void *file);
+extern const char *i8051_info(void *context, int regnum);
+
+WRITE8_HANDLER( i8051_internal_w );
+READ8_HANDLER( i8051_internal_r );
+
+extern void i8051_set_serial_tx_callback(void (*callback)(int data));
+extern void i8051_set_serial_rx_callback(int (*callback)(void));
+extern void i8051_set_eram_iaddr_callback(READ32_HANDLER((*callback)));
+
+#ifdef MAME_DEBUG
+extern offs_t i8051_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+/****************************************************************************
+ * 8752 Section
+ ****************************************************************************/
+#if (HAS_I8752)
+#define i8752_icount i8051_icount
+
+extern void i8752_init (int index, int clock, const void *config, int (*irqcallback)(int)); /* Initialize save states */
+extern void i8752_reset (void); /* Reset registers to the initial values */
+extern void i8752_exit (void); /* Shut down CPU core */
+extern int i8752_execute(int cycles); /* Execute cycles - returns number of cycles actually run */
+extern void i8752_get_context (void *dst); /* Get registers, return context size */
+extern void i8752_set_context (void *src); /* Set registers */
+extern unsigned i8752_get_reg (int regnum);
+extern void i8752_set_reg (int regnum, unsigned val);
+extern void i8752_set_irq_line(int irqline, int state);
+extern void i8752_set_irq_callback(int (*callback)(int irqline));
+extern void i8752_state_save(void *file);
+extern void i8752_state_load(void *file);
+extern const char *i8752_info(void *context, int regnum);
+extern void i8752_set_serial_tx_callback(void (*callback)(int data));
+extern void i8752_set_serial_rx_callback(int (*callback)(void));
+WRITE8_HANDLER( i8752_internal_w );
+READ8_HANDLER( i8752_internal_r );
+#endif //(HAS_8752)
+
+
+void i8051_get_info(UINT32 state, cpuinfo *info);
+void i8052_get_info(UINT32 state, cpuinfo *info);
+void i8751_get_info(UINT32 state, cpuinfo *info);
+void i8752_get_info(UINT32 state, cpuinfo *info);
+
+#endif /* _I8051_H */
+
+
diff --git a/src/emu/cpu/i8051/i8051ops.c b/src/emu/cpu/i8051/i8051ops.c
new file mode 100644
index 00000000000..ce1d5a76349
--- /dev/null
+++ b/src/emu/cpu/i8051/i8051ops.c
@@ -0,0 +1,960 @@
+/*******************************************************************************************
+ NOTE: All registers are accessed directly, instead of using the SFR_R() function for speed
+ Direct register access is availabe from the R_(register name) macros.. ex: R_ACC for the ACC
+ with the exception of the PC
+********************************************************************************************/
+
+//ACALL code addr /* 1: aaa1 0001 */
+INLINE void acall(void)
+{
+ UINT8 op = ROP(PC-1); //Grab the opcode for ACALL
+ UINT8 addr = ROP_ARG(PC++); //Grab code address byte
+ PUSH_PC //Save PC to the stack
+ //Thanks Gerrit for help with this! :)
+ PC = (PC & 0xf800) | ((op & 0xe0) << 3) | addr;
+}
+
+//ADD A, #data /* 1: 0010 0100 */
+INLINE void add_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 result = R_ACC + data; //Add data to accumulator
+ DO_ADD_FLAGS(R_ACC,data,0) //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADD A, data addr /* 1: 0010 0101 */
+INLINE void add_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ UINT8 result = R_ACC + data; //Add data to accumulator
+ DO_ADD_FLAGS(R_ACC,data,0); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADD A, @R0/@R1 /* 1: 0010 011i */
+INLINE void add_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from memory pointed to by R0 or R1
+ UINT8 result = R_ACC + data; //Add data to accumulator
+ DO_ADD_FLAGS(R_ACC,data,0); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADD A, R0 to R7 /* 1: 0010 1rrr */
+INLINE void add_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ UINT8 result = R_ACC + data; //Add data to accumulator
+ DO_ADD_FLAGS(R_ACC,data,0); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADDC A, #data /* 1: 0011 0100 */
+INLINE void addc_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 result = R_ACC + data + GET_CY; //Add data + carry flag to accumulator
+ DO_ADD_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADDC A, data addr /* 1: 0011 0101 */
+INLINE void addc_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ UINT8 result = R_ACC + data + GET_CY; //Add data + carry flag to accumulator
+ DO_ADD_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADDC A, @R0/@R1 /* 1: 0011 011i */
+INLINE void addc_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from memory pointed to by R0 or R1
+ UINT8 result = R_ACC + data + GET_CY; //Add data + carry flag to accumulator
+ DO_ADD_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//ADDC A, R0 to R7 /* 1: 0011 1rrr */
+INLINE void addc_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ UINT8 result = R_ACC + data + GET_CY; //Add data + carry flag to accumulator
+ DO_ADD_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//AJMP code addr /* 1: aaa0 0001 */
+INLINE void ajmp(void)
+{
+ UINT8 op = ROP(PC-1); //Grab the opcode for AJMP
+ UINT8 addr = ROP_ARG(PC++); //Grab code address byte
+ //Thanks Gerrit for help with this! :)
+ PC = (PC & 0xf800) | ((op & 0xe0) << 3) | addr;
+}
+
+//ANL data addr, A /* 1: 0101 0010 */
+INLINE void anl_mem_a(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,data & R_ACC); //Set data address value to it's value Logical AND with ACC
+}
+
+//ANL data addr, #data /* 1: 0101 0011 */
+INLINE void anl_mem_byte(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 srcdata = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,srcdata & data); //Set data address value to it's value Logical AND with Data
+}
+
+//ANL A, #data /* 1: 0101 0100 */
+INLINE void anl_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ SFR_W(ACC,R_ACC & data); //Set ACC to value of ACC Logical AND with Data
+}
+
+//ANL A, data addr /* 1: 0101 0101 */
+INLINE void anl_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ SFR_W(ACC,R_ACC & data); //Set ACC to value of ACC Logical AND with Data
+}
+
+//ANL A, @RO/@R1 /* 1: 0101 011i */
+INLINE void anl_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from address R0 or R1 points to
+ SFR_W(ACC,R_ACC & data); //Set ACC to value of ACC Logical AND with Data
+}
+
+//ANL A, RO to R7 /* 1: 0101 1rrr */
+INLINE void anl_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ SFR_W(ACC,R_ACC & data); //Set ACC to value of ACC Logical AND with Data
+}
+
+//ANL C, bit addr /* 1: 1000 0010 */
+INLINE void anl_c_bitaddr(void)
+{
+ int cy = GET_CY;
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 bit = BIT_R(addr); //Grab bit data from bit address
+ SET_CY( (cy & bit) ); //Set Carry flag to Carry Flag Value Logical AND with Bit
+}
+
+//ANL C,/bit addr /* 1: 1011 0000 */
+INLINE void anl_c_nbitaddr(void)
+{
+ int cy = GET_CY;
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 bit = BIT_R(addr); //Grab bit data from bit address
+ bit = ((~bit)&1); //Complement bit
+ SET_CY( (cy & bit) ); //Set Carry flag to Carry Flag Value Logical AND with Complemented Bit
+}
+
+//CJNE A, #data, code addr /* 1: 1011 0100 */
+INLINE void cjne_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+
+ if(R_ACC != data) //Jump if values are not equal
+ PC = PC + rel_addr;
+
+ //Set carry flag to 1 if 1st compare value is < 2nd compare value
+ SET_CY( (R_ACC < data) );
+}
+
+//CJNE A, data addr, code addr /* 1: 1011 0101 */
+INLINE void cjne_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ UINT8 data = IRAM_R(addr); //Pull value from data address
+
+ if(R_ACC != data) //Jump if values are not equal
+ PC = PC + rel_addr;
+
+ //Set carry flag to 1 if 1st compare value is < 2nd compare value
+ SET_CY( (R_ACC < data) );
+}
+
+//CJNE @R0/@R1, #data, code addr /* 1: 1011 011i */
+INLINE void cjne_ir_byte(int r)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ UINT8 srcdata = IRAM_IR(R_R(r)); //Grab value pointed to by R0 or R1
+
+ if(srcdata != data) //Jump if values are not equal
+ PC = PC + rel_addr;
+
+ //Set carry flag to 1 if 1st compare value is < 2nd compare value
+ SET_CY( (srcdata < data) );
+}
+
+//CJNE R0 to R7, #data, code addr /* 1: 1011 1rrr */
+INLINE void cjne_r_byte(int r)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ UINT8 srcdata = R_R(r); //Grab value of R0 - R7
+
+ if(srcdata != data) //Jump if values are not equal
+ PC = PC + rel_addr;
+
+ //Set carry flag to 1 if 1st compare value is < 2nd compare value
+ SET_CY( (srcdata < data) );
+}
+
+//CLR bit addr /* 1: 1100 0010 */
+INLINE void clr_bitaddr(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ BIT_W(addr,0); //Clear bit at specified bit address
+}
+
+//CLR C /* 1: 1100 0011 */
+INLINE void clr_c(void)
+{
+ SET_CY(0); //Clear Carry Flag
+}
+
+//CLR A /* 1: 1110 0100 */
+INLINE void clr_a(void)
+{
+ SFR_W(ACC,0); //Clear Accumulator
+}
+
+//CPL bit addr /* 1: 1011 0010 */
+INLINE void cpl_bitaddr(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 data = (~BIT_R(addr))&1;
+ BIT_W(addr,data); //Complement bit at specified bit address
+}
+
+//CPL C /* 1: 1011 0011 */
+INLINE void cpl_c(void)
+{
+ UINT8 bit = (~GET_CY)&1; //Complement Carry Flag
+ SET_CY(bit);
+}
+
+//CPL A /* 1: 1111 0100 */
+INLINE void cpl_a(void)
+{
+ UINT8 data = ((~R_ACC)&0xff);
+ SFR_W(ACC,data); //Complement Accumulator
+}
+
+//DA A /* 1: 1101 0100 */
+INLINE void da_a(void)
+{
+/*From several sources, since none said the same thing:
+ The decimal adjust instruction is associated with the use of the ADD and ADDC instructions.
+ The eight-bit value in the accumulator is adjusted to form two BCD digits of four bits each.
+ If the accumulator contents bits 0-3 are greater than 9, OR the AC flag is set, then six is added to
+ produce a proper BCD digit.
+ If the carry is set, OR the four high bits 4-7 exceed nine, six is added to the value of these bits.
+ The carry flag will be set if the result is > 0x99, but not cleared otherwise */
+
+ UINT16 new_acc = R_ACC & 0xff;
+ if(GET_AC || (R_ACC & 0x0f) > 0x09)
+ new_acc += 0x06;
+ if(GET_CY || (R_ACC & 0xf0) > 0x90)
+ new_acc += 0x60;
+ SFR_W(ACC,new_acc&0xff);
+ if(new_acc & ~0xff)
+ SET_CY(1);
+}
+
+//DEC A /* 1: 0001 0100 */
+INLINE void dec_a(void)
+{
+ SFR_W(ACC,R_ACC-1);
+}
+
+//DEC data addr /* 1: 0001 0101 */
+INLINE void dec_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr);
+ IRAM_W(addr,data-1);
+}
+
+//DEC @R0/@R1 /* 1: 0001 011i */
+INLINE void dec_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r));
+ IRAM_W(R_R(r),data-1);
+}
+
+//DEC R0 to R7 /* 1: 0001 1rrr */
+INLINE void dec_r(int r)
+{
+ R_R(r) = R_R(r) - 1;
+}
+
+//DIV AB /* 1: 1000 0100 */
+INLINE void div_ab(void)
+{
+ if( R_B == 0 ) {
+ //Overflow flag is set!
+ SET_OV(1);
+ //Really the values are undefined according to the manual, but we'll just leave them as is..
+ //SFR_W(ACC,0xff);
+ //SFR_W(B,0xff);
+ }
+ else {
+ int a = (int)R_ACC/R_B;
+ int b = (int)R_ACC%R_B;
+ //A gets quotient byte, B gets remainder byte
+ SFR_W(ACC,a);
+ SFR_W(B, b);
+ //Overflow flag is cleared
+ SET_OV(0);
+ }
+ //Carry Flag is always cleared
+ SET_CY(0);
+}
+
+//DJNZ data addr, code addr /* 1: 1101 0101 */
+INLINE void djnz_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ IRAM_W(addr,IRAM_R(addr) - 1); //Decrement value contained at data address
+ if(IRAM_R(addr) != 0) //Branch if contents of data address is not 0
+ PC = PC + rel_addr;
+}
+
+//DJNZ R0 to R7,code addr /* 1: 1101 1rrr */
+INLINE void djnz_r(int r)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ R_R(r) = R_R(r) - 1; //Decrement value
+ if(R_R(r) != 0) //Branch if contents of R0 - R7 is not 0
+ PC = PC + rel_addr;
+}
+
+//INC A /* 1: 0000 0100 */
+INLINE void inc_a(void)
+{
+ SFR_W(ACC,R_ACC+1);
+}
+
+//INC data addr /* 1: 0000 0101 */
+INLINE void inc_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr);
+ IRAM_W(addr,data+1);
+}
+
+//INC @R0/@R1 /* 1: 0000 011i */
+INLINE void inc_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r));
+ IRAM_W(R_R(r),data+1);
+}
+
+//INC R0 to R7 /* 1: 0000 1rrr */
+INLINE void inc_r(int r)
+{
+ UINT8 data = R_R(r);
+ R_R(r) = data + 1;
+}
+
+//INC DPTR /* 1: 1010 0011 */
+INLINE void inc_dptr(void)
+{
+ UINT16 dptr = (R_DPTR)+1;
+ DPTR_W(dptr);
+}
+
+//JB bit addr, code addr /* 1: 0010 0000 */
+INLINE void jb(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(BIT_R(addr)) //If bit set at specified bit address, jump
+ PC = PC + rel_addr;
+}
+
+//JBC bit addr, code addr /* 1: 0001 0000 */
+INLINE void jbc(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(BIT_R(addr)) { //If bit set at specified bit address, jump
+ PC = PC + rel_addr;
+ BIT_W(addr,0); //Clear Bit also
+ }
+}
+
+//JC code addr /* 1: 0100 0000 */
+INLINE void jc(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(GET_CY) //Jump if Carry Flag Set
+ PC = PC + rel_addr;
+}
+
+//JMP @A+DPTR /* 1: 0111 0011 */
+INLINE void jmp_iadptr(void)
+{
+ PC = R_ACC+R_DPTR;
+}
+
+//JNB bit addr, code addr /* 1: 0011 0000 */
+INLINE void jnb(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(!BIT_R(addr)) //If bit NOT set at specified bit address, jump
+ PC = PC + rel_addr;
+}
+
+//JNC code addr /* 1: 0101 0000 */
+INLINE void jnc(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(!GET_CY) //Jump if Carry Flag not set
+ PC = PC + rel_addr;
+}
+
+//JNZ code addr /* 1: 0111 0000 */
+INLINE void jnz(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(R_ACC != 0) //Branch if ACC is not 0
+ PC = PC+rel_addr;
+}
+
+//JZ code addr /* 1: 0110 0000 */
+INLINE void jz(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ if(R_ACC == 0) //Branch if ACC is 0
+ PC = PC+rel_addr;
+}
+
+//LCALL code addr /* 1: 0001 0010 */
+INLINE void lcall(void)
+{
+ UINT8 addr_hi, addr_lo;
+ addr_hi = ROP_ARG(PC++);
+ addr_lo = ROP_ARG(PC++);
+ PUSH_PC
+ PC = (UINT16)((addr_hi<<8) | addr_lo);
+}
+
+//LJMP code addr /* 1: 0000 0010 */
+INLINE void ljmp(void)
+{
+ UINT8 addr_hi, addr_lo;
+ addr_hi = ROP_ARG(PC++);
+ addr_lo = ROP_ARG(PC++);
+ PC = (UINT16)((addr_hi<<8) | addr_lo);
+}
+
+//MOV A, #data /* 1: 0111 0100 */
+INLINE void mov_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ SFR_W(ACC,data); //Store data to ACC
+}
+
+//MOV A, data addr /* 1: 1110 0101 */
+INLINE void mov_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ SFR_W(ACC,IRAM_R(addr)); //Store contents of data address to ACC
+}
+
+//MOV A,@RO/@R1 /* 1: 1110 011i */
+INLINE void mov_a_ir(int r)
+{
+ SFR_W(ACC,IRAM_IR(R_R(r))); //Store contents of address pointed by R0 or R1 to ACC
+}
+
+//MOV A,R0 to R7 /* 1: 1110 1rrr */
+INLINE void mov_a_r(int r)
+{
+ SFR_W(ACC,R_R(r)); //Store contents of R0 - R7 to ACC
+}
+
+//MOV data addr, #data /* 1: 0111 0101 */
+INLINE void mov_mem_byte(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ IRAM_W(addr,data); //Store data to data address location
+}
+
+//MOV data addr, data addr /* 1: 1000 0101 */
+INLINE void mov_mem_mem(void)
+{
+ //1st address is src, 2nd is dst, but the mov command works as mov dst,src)
+ UINT8 src,dst;
+ src = ROP_ARG(PC++); //Grab source data address
+ dst = ROP_ARG(PC++); //Grab destination data address
+ IRAM_W(dst,IRAM_R(src)); //Read source address contents and store to destination address
+}
+
+//MOV @R0/@R1, #data /* 1: 0111 011i */
+INLINE void mov_ir_byte(int r)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ IRAM_IW(R_R(r),data); //Store data to address pointed by R0 or R1
+}
+
+//MOV R0 to R7, #data /* 1: 0111 1rrr */
+INLINE void mov_r_byte(int r)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ R_R(r) = data; //Store to R0 - R7
+}
+
+//MOV data addr, @R0/@R1 /* 1: 1000 011i */
+INLINE void mov_mem_ir(int r)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_W(addr,IRAM_IR(R_R(r))); //Store contents pointed to by R0 or R1 to data address
+}
+
+//MOV data addr,R0 to R7 /* 1: 1000 1rrr */
+INLINE void mov_mem_r(int r)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_W(addr,R_R(r)); //Store contents of R0 - R7 to data address
+}
+
+//MOV DPTR, #data16 /* 1: 1001 0000 */
+INLINE void mov_dptr_byte(void)
+{
+ UINT8 data_hi, data_lo;
+ data_hi = ROP_ARG(PC++); //Grab hi byte
+ data_lo = ROP_ARG(PC++); //Grab lo byte
+ DPTR_W((UINT16)((data_hi<<8)|data_lo)); //Store to DPTR
+}
+
+//MOV bit addr, C /* 1: 1001 0010 */
+INLINE void mov_bitaddr_c(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ BIT_W(addr,GET_CY); //Store Carry Flag to Bit Address
+}
+
+//MOV @R0/@R1, data addr /* 1: 1010 011i */
+INLINE void mov_ir_mem(int r)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_IW(R_R(r),IRAM_R(addr)); //Store data from data address to address pointed to by R0 or R1
+}
+
+//MOV R0 to R7, data addr /* 1: 1010 1rrr */
+INLINE void mov_r_mem(int r)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ R_R(r) = IRAM_R(addr); //Store to R0 - R7
+}
+
+//MOV data addr, A /* 1: 1111 0101 */
+INLINE void mov_mem_a(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_W(addr,R_ACC); //Store A to data address
+}
+
+//MOV @R0/@R1, A /* 1: 1111 011i */
+INLINE void mov_ir_a(int r)
+{
+ IRAM_IW(R_R(r),R_ACC); //Store A to location pointed to by R0 or R1
+}
+
+//MOV R0 to R7, A /* 1: 1111 1rrr */
+INLINE void mov_r_a(int r)
+{
+ R_R(r) = R_ACC; //Store A to R0-R7
+}
+
+//MOVC A, @A + PC /* 1: 1000 0011 */
+INLINE void movc_a_iapc(void)
+{
+ UINT8 data;
+ data = CODEMEM_R(R_ACC+PC); //Move a byte from CODE(Program) Memory and store to ACC
+ SFR_W(ACC,data);
+}
+
+//MOV C, bit addr /* 1: 1010 0010 */
+INLINE void mov_c_bitaddr(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ SET_CY( (BIT_R(addr)) ); //Store Bit from Bit Address to Carry Flag
+}
+
+//MOVC A, @A + DPTR /* 1: 1001 0011 */
+INLINE void movc_a_iadptr(void)
+{
+ UINT8 data;
+ data = CODEMEM_R(R_ACC+R_DPTR); //Move a byte from CODE(Program) Memory and store to ACC
+ SFR_W(ACC,data);
+}
+
+//MOVX A,@DPTR /* 1: 1110 0000 */
+//(Move External Ram 16 bit address to A)
+INLINE void movx_a_idptr(void)
+{
+// UINT8 byte = DATAMEM_R(R_DPTR); //Grab 1 byte from External DATA memory pointed to by dptr
+ UINT32 addr = ERAM_ADDR(R_DPTR,0xFFFF);
+ UINT8 byte = DATAMEM_R(addr); //Grab 1 byte from External DATA memory pointed to by dptr
+ SFR_W(ACC,byte); //Store to ACC
+}
+
+//MOVX A, @R0/@R1 /* 1: 1110 001i */
+//(Move External Ram 8 bit address to A)
+INLINE void movx_a_ir(int r)
+{
+ UINT32 addr = ERAM_ADDR(R_R(r),0xFF); //Grab address by reading location pointed to by R0 or R1
+ UINT8 byte = DATAMEM_R(addr); //Grab 1 byte from External DATA memory pointed to by address
+ SFR_W(ACC,byte); //Store to ACC
+}
+
+//MOVX @DPTR,A /* 1: 1111 0000 */
+//(Move A to External Ram 16 bit address)
+INLINE void movx_idptr_a(void)
+{
+// DATAMEM_W(R_DPTR, R_ACC); //Store ACC to External DATA memory address pointed to by DPTR
+ UINT32 addr = ERAM_ADDR(R_DPTR,0xFFFF);
+ DATAMEM_W(addr, R_ACC); //Store ACC to External DATA memory address pointed to by DPTR
+}
+
+//MOVX @R0/@R1,A /* 1: 1111 001i */
+//(Move A to External Ram 8 bit address)
+INLINE void movx_ir_a(int r)
+{
+ UINT32 addr = ERAM_ADDR(R_R(r),0xFF); //Grab address by reading location pointed to by R0 or R1
+ DATAMEM_W(addr, R_ACC); //Store ACC to External DATA memory address
+}
+
+//MUL AB /* 1: 1010 0100 */
+INLINE void mul_ab(void)
+{
+ UINT16 result = R_ACC * R_B;
+ //A gets lo bits, B gets hi bits of result
+ SFR_W(B,(UINT8)((result & 0xFF00) >> 8));
+ SFR_W(ACC,(UINT8)(result & 0x00FF));
+ //Set flags
+ SET_OV( ((result & 0x100) >> 8) ); //Set/Clear Overflow Flag if result > 255
+ SET_CY(0); //Carry Flag always cleared
+}
+
+//NOP /* 1: 0000 0000 */
+INLINE void nop(void)
+{
+}
+
+//ORL data addr, A /* 1: 0100 0010 */
+INLINE void orl_mem_a(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,data | R_ACC); //Set data address value to it's value Logical OR with ACC
+}
+
+//ORL data addr, #data /* 1: 0100 0011 */
+INLINE void orl_mem_byte(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 srcdata = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,srcdata | data); //Set data address value to it's value Logical OR with Data
+}
+
+//ORL A, #data /* 1: 0100 0100 */
+INLINE void orl_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ SFR_W(ACC,R_ACC | data); //Set ACC to value of ACC Logical OR with Data
+}
+
+//ORL A, data addr /* 1: 0100 0101 */
+INLINE void orl_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ SFR_W(ACC,R_ACC | data); //Set ACC to value of ACC Logical OR with Data
+}
+
+//ORL A, @RO/@R1 /* 1: 0100 011i */
+INLINE void orl_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from address R0 or R1 points to
+ SFR_W(ACC,R_ACC | data); //Set ACC to value of ACC Logical OR with Data
+}
+
+//ORL A, RO to R7 /* 1: 0100 1rrr */
+INLINE void orl_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ SFR_W(ACC,R_ACC | data); //Set ACC to value of ACC Logical OR with Data
+}
+
+//ORL C, bit addr /* 1: 0111 0010 */
+INLINE void orl_c_bitaddr(void)
+{
+ int cy = GET_CY;
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 bit = BIT_R(addr); //Grab bit data from bit address
+ SET_CY( (cy | bit) ); //Set Carry flag to Carry Flag Value Logical OR with Bit
+}
+
+//ORL C, /bit addr /* 1: 1010 0000 */
+INLINE void orl_c_nbitaddr(void)
+{
+ int cy = GET_CY;
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ UINT8 bit = BIT_R(addr); //Grab bit data from bit address
+ bit = ((~bit)&1); //Complement bit
+ SET_CY( (cy | bit) ); //Set Carry flag to Carry Flag Value Logical OR with Complemented Bit
+}
+
+//POP data addr /* 1: 1101 0000 */
+INLINE void pop(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ IRAM_W(addr, IRAM_IR(R_SP)); //Store to contents of data addr, data pointed to by Stack - IRAM_IR needed to access upper 128 bytes of stack
+ //IRAM_IW(addr, IRAM_IR(R_SP)); //Store to contents of data addr, data pointed to by Stack - doesn't work, sfr's are not restored this way and it's not an indirect access anyway
+ SFR_W(SP,R_SP-1); //Decrement SP
+}
+
+//PUSH data addr /* 1: 1100 0000 */
+INLINE void push(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 tmpSP = R_SP; //Grab and Increment Stack Pointer
+ tmpSP++; // ""
+ SFR_W(SP,tmpSP); // ""
+ if (tmpSP == R_SP) //Ensure it was able to write to new stack location
+ IRAM_IW(tmpSP, IRAM_R(addr)); //Store to stack contents of data address - IRAM_IW needed to store to upper 128 bytes of stack, however, can't use IRAM_IR because that won't store the sfrs and it's not an indirect access anyway
+}
+
+//RET /* 1: 0010 0010 */
+INLINE void ret(void)
+{
+ POP_PC
+}
+
+//RETI /* 1: 0011 0010 */
+INLINE void reti(void)
+{
+ POP_PC
+ CLEAR_CURRENT_IRQ
+}
+
+//RL A /* 1: 0010 0011 */
+INLINE void rl_a(void)
+{
+ //Left Shift A, Bit 7 carries to Bit 0
+ int carry = ((R_ACC & 0x80) >> 7);
+ int data = (R_ACC<<1) & 0xfe;
+ SFR_W(ACC, data | carry);
+}
+
+//RLC A /* 1: 0011 0011 */
+INLINE void rlc_a(void)
+{
+ //Left Shift A, Bit 7 goes to Carry Flag, Original Carry Flag goes to Bit 0 of ACC
+ int carry = ((R_ACC & 0x80) >> 7);
+ int data = ((R_ACC<<1) & 0xfe) | GET_CY;
+ SFR_W(ACC, data);
+ SET_CY(carry);
+}
+
+//RR A /* 1: 0000 0011 */
+INLINE void rr_a(void)
+{
+ //Right Shift A, Bit 0 carries to Bit 7
+ int carry = ((R_ACC & 1) << 7);
+ int data = (R_ACC>>1) & 0x7f;
+ SFR_W(ACC, data | carry);
+}
+
+//RRC A /* 1: 0001 0011 */
+INLINE void rrc_a(void)
+{
+ //Right Shift A, Bit 0 goes to Carry Flag, Bit 7 of ACC gets set to original Carry Flag
+ int carry = (R_ACC & 1);
+ int data = ((R_ACC>>1) & 0x7f) | (GET_CY<<7);
+ SFR_W(ACC, data);
+ SET_CY(carry);
+}
+
+//SETB C /* 1: 1101 0011 */
+INLINE void setb_c(void)
+{
+ SET_CY(1); //Set Carry Flag
+}
+
+//SETB bit addr /* 1: 1101 0010 */
+INLINE void setb_bitaddr(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab bit address
+ BIT_W(addr,1); //Set Bit at Bit Address
+}
+
+//SJMP code addr /* 1: 1000 0000 */
+INLINE void sjmp(void)
+{
+ INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address
+ PC = PC + rel_addr; //Update PC
+}
+
+//SUBB A, #data /* 1: 1001 0100 */
+INLINE void subb_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 result = R_ACC - data - GET_CY; //Subtract data & carry flag from accumulator
+ DO_SUB_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+
+}
+
+//SUBB A, data addr /* 1: 1001 0101 */
+INLINE void subb_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ UINT8 result = R_ACC - data - GET_CY; //Subtract data & carry flag from accumulator
+ DO_SUB_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//SUBB A, @R0/@R1 /* 1: 1001 011i */
+INLINE void subb_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from memory pointed to by R0 or R1
+ UINT8 result = R_ACC - data - GET_CY; //Subtract data & carry flag from accumulator
+ DO_SUB_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//SUBB A, R0 to R7 /* 1: 1001 1rrr */
+INLINE void subb_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ UINT8 result = R_ACC - data - GET_CY; //Subtract data & carry flag from accumulator
+ DO_SUB_FLAGS(R_ACC,data,GET_CY); //Set Flags
+ SFR_W(ACC,result); //Store 8 bit result of addtion in ACC
+}
+
+//SWAP A /* 1: 1100 0100 */
+INLINE void swap_a(void)
+{
+ UINT8 a_nib_lo, a_nib_hi;
+ a_nib_hi = (R_ACC & 0x0f) << 4; //Grab lo byte of ACC and move to hi
+ a_nib_lo = (R_ACC & 0xf0) >> 4; //Grab hi byte of ACC and move to lo
+ SFR_W(ACC, a_nib_hi | a_nib_lo);
+}
+
+//XCH A, data addr /* 1: 1100 0101 */
+INLINE void xch_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data
+ UINT8 oldACC = R_ACC; //Hold value of ACC
+ SFR_W(ACC,data); //Sets ACC to data
+ IRAM_W(addr,oldACC); //Sets data address to old value of ACC
+}
+
+//XCH A, @RO/@R1 /* 1: 1100 011i */
+INLINE void xch_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data pointed to by R0 or R1
+ UINT8 oldACC = R_ACC; //Hold value of ACC
+ SFR_W(ACC,data); //Sets ACC to data
+ IRAM_W(R_R(r),oldACC); //Sets data address to old value of ACC
+}
+
+//XCH A, RO to R7 /* 1: 1100 1rrr */
+INLINE void xch_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0-R7
+ UINT8 oldACC = R_ACC; //Hold value of ACC
+ SFR_W(ACC,data); //Sets ACC to data
+ R_R(r) = oldACC; //Sets data address to old value of ACC
+}
+
+//XCHD A, @R0/@R1 /* 1: 1101 011i */
+INLINE void xchd_a_ir(int r)
+{
+ UINT8 acc, ir_data;
+ ir_data = IRAM_IR(R_R(r)); //Grab data pointed to by R0 or R1
+ acc = R_ACC; //Grab ACC value
+ SFR_W(ACC, (acc & 0xf0) | (ir_data & 0x0f) ); //Set ACC to lower nibble of data pointed to by R0 or R1
+ IRAM_W(R_R(r), (ir_data & 0xf0) | (acc & 0x0f) ); //Set data pointed to by R0 or R1 to lower nibble of ACC
+}
+
+//XRL data addr, A /* 1: 0110 0010 */
+INLINE void xrl_mem_a(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,data ^ R_ACC); //Set data address value to it's value Logical XOR with ACC
+}
+
+//XRL data addr, #data /* 1: 0110 0011 */
+INLINE void xrl_mem_byte(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ UINT8 srcdata = IRAM_R(addr); //Grab data from data address
+ IRAM_W(addr,srcdata ^ data); //Set data address value to it's value Logical XOR with Data
+}
+
+//XRL A, #data /* 1: 0110 0100 */
+INLINE void xrl_a_byte(void)
+{
+ UINT8 data = ROP_ARG(PC++); //Grab data
+ SFR_W(ACC,R_ACC ^ data); //Set ACC to value of ACC Logical XOR with Data
+}
+
+//XRL A, data addr /* 1: 0110 0101 */
+INLINE void xrl_a_mem(void)
+{
+ UINT8 addr = ROP_ARG(PC++); //Grab data address
+ UINT8 data = IRAM_R(addr); //Grab data from data address
+ SFR_W(ACC,R_ACC ^ data); //Set ACC to value of ACC Logical XOR with Data
+}
+
+//XRL A, @R0/@R1 /* 1: 0110 011i */
+INLINE void xrl_a_ir(int r)
+{
+ UINT8 data = IRAM_IR(R_R(r)); //Grab data from address R0 or R1 points to
+ SFR_W(ACC,R_ACC ^ data); //Set ACC to value of ACC Logical XOR with Data
+}
+
+//XRL A, R0 to R7 /* 1: 0110 1rrr */
+INLINE void xrl_a_r(int r)
+{
+ UINT8 data = R_R(r); //Grab data from R0 - R7
+ SFR_W(ACC,R_ACC ^ data); //Set ACC to value of ACC Logical XOR with Data
+}
+
+//illegal opcodes
+INLINE void illegal(void)
+{
+ LOG(("i8051 #%d: illegal opcode at 0x%03x: %02x\n", cpu_getactivecpu(), PC, ROP(PC)));
+}
diff --git a/src/emu/cpu/i8085/8085dasm.c b/src/emu/cpu/i8085/8085dasm.c
new file mode 100644
index 00000000000..6857b738c0b
--- /dev/null
+++ b/src/emu/cpu/i8085/8085dasm.c
@@ -0,0 +1,581 @@
+/*****************************************************************************
+ *
+ * 8085dasm.c
+ * Portable I8085A disassembler
+ *
+ * Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * You can contact me at juergen@mame.net or pullmoll@stop1984.com
+ *
+ * - This source code is released as freeware for non-commercial purposes
+ * as part of the M.A.M.E. (Multiple Arcade Machine Emulator) project.
+ * The licensing terms of MAME apply to this piece of code for the MAME
+ * project and derviative works, as defined by the MAME license. You
+ * may opt to make modifications, improvements or derivative works under
+ * that same conditions, and the MAME project may opt to keep
+ * modifications, improvements or derivatives under their terms exclusively.
+ *
+ * - Alternatively you can choose to apply the terms of the "GPL" (see
+ * below) to this - and only this - piece of code or your derivative works.
+ * Note that in no case your choice can have any impact on any other
+ * source code of the MAME project, or binary, or executable, be it closely
+ * or losely related to this piece of code.
+ *
+ * - At your choice you are also free to remove either licensing terms from
+ * this file and continue to use it under only one of the two licenses. Do this
+ * if you think that licenses are not compatible (enough) for you, or if you
+ * consider either license 'too restrictive' or 'too free'.
+ *
+ * - GPL (GNU General Public License)
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *****************************************************************************/
+
+#include "cpuintrf.h"
+
+/* 8080/8085A mnemonics were more irritation than information
+ What would you guess "CP $3456" to mean? It's not compare,
+ but call if plus ... therefore: */
+//#define Z80_MNEMONICS
+
+#define OP(A) oprom[(A) - PC]
+#define ARG(A) opram[(A) - PC]
+#define ARGW(A) (opram[(A) - PC] | (opram[(A) + 1 - PC] << 8))
+
+offs_t i8085_dasm(char *buff, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ UINT8 op;
+ unsigned PC = pc;
+ switch (op = OP(pc++))
+ {
+#ifdef Z80_MNEMONICS
+ case 0x00: sprintf (buff,"nop"); break;
+ case 0x01: sprintf (buff,"ld bc,$%04x", ARGW(pc)); pc+=2; break;
+ case 0x02: sprintf (buff,"ld (bc),a"); break;
+ case 0x03: sprintf (buff,"inc bc"); break;
+ case 0x04: sprintf (buff,"inc b"); break;
+ case 0x05: sprintf (buff,"dec b"); break;
+ case 0x06: sprintf (buff,"ld b,$%02x", ARG(pc)); pc++; break;
+ case 0x07: sprintf (buff,"rlca"); break;
+ case 0x08: sprintf (buff,"sub hl,bc (*)"); break;
+ case 0x09: sprintf (buff,"add hl,bc"); break;
+ case 0x0a: sprintf (buff,"ld a,(bc)"); break;
+ case 0x0b: sprintf (buff,"dec bc"); break;
+ case 0x0c: sprintf (buff,"inc c"); break;
+ case 0x0d: sprintf (buff,"dec c"); break;
+ case 0x0e: sprintf (buff,"ld c,$%02x", ARG(pc)); pc++; break;
+ case 0x0f: sprintf (buff,"rrca"); break;
+ case 0x10: sprintf (buff,"sra hl (*)"); break;
+ case 0x11: sprintf (buff,"ld de,$%04x", ARGW(pc)); pc+=2; break;
+ case 0x12: sprintf (buff,"ld (de),a"); break;
+ case 0x13: sprintf (buff,"inc de"); break;
+ case 0x14: sprintf (buff,"inc d"); break;
+ case 0x15: sprintf (buff,"dec d"); break;
+ case 0x16: sprintf (buff,"ld d,$%02x", ARG(pc)); pc++; break;
+ case 0x17: sprintf (buff,"rla"); break;
+ case 0x18: sprintf (buff,"rl de (*)"); break;
+ case 0x19: sprintf (buff,"add hl,de"); break;
+ case 0x1a: sprintf (buff,"ld a,(de)"); break;
+ case 0x1b: sprintf (buff,"dec de"); break;
+ case 0x1c: sprintf (buff,"inc e"); break;
+ case 0x1d: sprintf (buff,"dec e"); break;
+ case 0x1e: sprintf (buff,"ld e,$%02x", ARG(pc)); pc++; break;
+ case 0x1f: sprintf (buff,"rra"); break;
+ case 0x20: sprintf (buff,"rim"); break;
+ case 0x21: sprintf (buff,"ld hl,$%04x", ARGW(pc)); pc+=2; break;
+ case 0x22: sprintf (buff,"ld ($%04x),hl", ARGW(pc)); pc+=2;break;
+ case 0x23: sprintf (buff,"inc hl"); break;
+ case 0x24: sprintf (buff,"inc h"); break;
+ case 0x25: sprintf (buff,"dec h"); break;
+ case 0x26: sprintf (buff,"ld h,$%02x", ARG(pc)); pc++; break;
+ case 0x27: sprintf (buff,"daa"); break;
+ case 0x28: sprintf (buff,"ld de,hl+$%02x (*)",ARG(pc));pc++;break;
+ case 0x29: sprintf (buff,"add hl,hl"); break;
+ case 0x2a: sprintf (buff,"ld hl,($%04x)", ARGW(pc)); pc+=2;break;
+ case 0x2b: sprintf (buff,"dec hl"); break;
+ case 0x2c: sprintf (buff,"inc l"); break;
+ case 0x2d: sprintf (buff,"dec l"); break;
+ case 0x2e: sprintf (buff,"ld l,$%02x", ARG(pc)); pc++; break;
+ case 0x2f: sprintf (buff,"cpl"); break;
+ case 0x30: sprintf (buff,"sim"); break;
+ case 0x31: sprintf (buff,"ld sp,$%04x", ARGW(pc)); pc+=2; break;
+ case 0x32: sprintf (buff,"ld ($%04x),a", ARGW(pc)); pc+=2; break;
+ case 0x33: sprintf (buff,"inc sp"); break;
+ case 0x34: sprintf (buff,"inc (hl)"); break;
+ case 0x35: sprintf (buff,"dec (hl)"); break;
+ case 0x36: sprintf (buff,"ld (hl),$%02x", ARG(pc)); pc++; break;
+ case 0x37: sprintf (buff,"scf"); break;
+ case 0x38: sprintf (buff,"ld de,sp+$%02x (*)",ARG(pc));pc++;break;
+ case 0x39: sprintf (buff,"add hl,sp"); break;
+ case 0x3a: sprintf (buff,"ld a,($%04x)", ARGW(pc)); pc+=2; break;
+ case 0x3b: sprintf (buff,"dec sp"); break;
+ case 0x3c: sprintf (buff,"inc a"); break;
+ case 0x3d: sprintf (buff,"dec a"); break;
+ case 0x3e: sprintf (buff,"ld a,$%02x", ARG(pc)); pc++; break;
+ case 0x3f: sprintf (buff,"ccf"); break;
+ case 0x40: sprintf (buff,"ld b,b"); break;
+ case 0x41: sprintf (buff,"ld b,c"); break;
+ case 0x42: sprintf (buff,"ld b,d"); break;
+ case 0x43: sprintf (buff,"ld b,e"); break;
+ case 0x44: sprintf (buff,"ld b,h"); break;
+ case 0x45: sprintf (buff,"ld b,l"); break;
+ case 0x46: sprintf (buff,"ld b,(hl)"); break;
+ case 0x47: sprintf (buff,"ld b,a"); break;
+ case 0x48: sprintf (buff,"ld c,b"); break;
+ case 0x49: sprintf (buff,"ld c,c"); break;
+ case 0x4a: sprintf (buff,"ld c,d"); break;
+ case 0x4b: sprintf (buff,"ld c,e"); break;
+ case 0x4c: sprintf (buff,"ld c,h"); break;
+ case 0x4d: sprintf (buff,"ld c,l"); break;
+ case 0x4e: sprintf (buff,"ld c,(hl)"); break;
+ case 0x4f: sprintf (buff,"ld c,a"); break;
+ case 0x50: sprintf (buff,"ld d,b"); break;
+ case 0x51: sprintf (buff,"ld d,c"); break;
+ case 0x52: sprintf (buff,"ld d,d"); break;
+ case 0x53: sprintf (buff,"ld d,e"); break;
+ case 0x54: sprintf (buff,"ld d,h"); break;
+ case 0x55: sprintf (buff,"ld d,l"); break;
+ case 0x56: sprintf (buff,"ld d,(hl)"); break;
+ case 0x57: sprintf (buff,"ld d,a"); break;
+ case 0x58: sprintf (buff,"ld e,b"); break;
+ case 0x59: sprintf (buff,"ld e,c"); break;
+ case 0x5a: sprintf (buff,"ld e,d"); break;
+ case 0x5b: sprintf (buff,"ld e,e"); break;
+ case 0x5c: sprintf (buff,"ld e,h"); break;
+ case 0x5d: sprintf (buff,"ld e,l"); break;
+ case 0x5e: sprintf (buff,"ld e,(hl)"); break;
+ case 0x5f: sprintf (buff,"ld e,a"); break;
+ case 0x60: sprintf (buff,"ld h,b"); break;
+ case 0x61: sprintf (buff,"ld h,c"); break;
+ case 0x62: sprintf (buff,"ld h,d"); break;
+ case 0x63: sprintf (buff,"ld h,e"); break;
+ case 0x64: sprintf (buff,"ld h,h"); break;
+ case 0x65: sprintf (buff,"ld h,l"); break;
+ case 0x66: sprintf (buff,"ld h,(hl)"); break;
+ case 0x67: sprintf (buff,"ld h,a"); break;
+ case 0x68: sprintf (buff,"ld l,b"); break;
+ case 0x69: sprintf (buff,"ld l,c"); break;
+ case 0x6a: sprintf (buff,"ld l,d"); break;
+ case 0x6b: sprintf (buff,"ld l,e"); break;
+ case 0x6c: sprintf (buff,"ld l,h"); break;
+ case 0x6d: sprintf (buff,"ld l,l"); break;
+ case 0x6e: sprintf (buff,"ld l,(hl)"); break;
+ case 0x6f: sprintf (buff,"ld l,a"); break;
+ case 0x70: sprintf (buff,"ld (hl),b"); break;
+ case 0x71: sprintf (buff,"ld (hl),c"); break;
+ case 0x72: sprintf (buff,"ld (hl),d"); break;
+ case 0x73: sprintf (buff,"ld (hl),e"); break;
+ case 0x74: sprintf (buff,"ld (hl),h"); break;
+ case 0x75: sprintf (buff,"ld (hl),l"); break;
+ case 0x76: sprintf (buff,"halt"); break;
+ case 0x77: sprintf (buff,"ld (hl),a"); break;
+ case 0x78: sprintf (buff,"ld a,b"); break;
+ case 0x79: sprintf (buff,"ld a,c"); break;
+ case 0x7a: sprintf (buff,"ld a,d"); break;
+ case 0x7b: sprintf (buff,"ld a,e"); break;
+ case 0x7c: sprintf (buff,"ld a,h"); break;
+ case 0x7d: sprintf (buff,"ld a,l"); break;
+ case 0x7e: sprintf (buff,"ld a,(hl)"); break;
+ case 0x7f: sprintf (buff,"ld a,a"); break;
+ case 0x80: sprintf (buff,"add a,b"); break;
+ case 0x81: sprintf (buff,"add a,c"); break;
+ case 0x82: sprintf (buff,"add a,d"); break;
+ case 0x83: sprintf (buff,"add a,e"); break;
+ case 0x84: sprintf (buff,"add a,h"); break;
+ case 0x85: sprintf (buff,"add a,l"); break;
+ case 0x86: sprintf (buff,"add a,(hl)"); break;
+ case 0x87: sprintf (buff,"add a,a"); break;
+ case 0x88: sprintf (buff,"adc a,b"); break;
+ case 0x89: sprintf (buff,"adc a,c"); break;
+ case 0x8a: sprintf (buff,"adc a,d"); break;
+ case 0x8b: sprintf (buff,"adc a,e"); break;
+ case 0x8c: sprintf (buff,"adc a,h"); break;
+ case 0x8d: sprintf (buff,"adc a,l"); break;
+ case 0x8e: sprintf (buff,"adc a,(hl)"); break;
+ case 0x8f: sprintf (buff,"adc a,a"); break;
+ case 0x90: sprintf (buff,"sub b"); break;
+ case 0x91: sprintf (buff,"sub c"); break;
+ case 0x92: sprintf (buff,"sub d"); break;
+ case 0x93: sprintf (buff,"sub e"); break;
+ case 0x94: sprintf (buff,"sub h"); break;
+ case 0x95: sprintf (buff,"sub l"); break;
+ case 0x96: sprintf (buff,"sub (hl)"); break;
+ case 0x97: sprintf (buff,"sub a"); break;
+ case 0x98: sprintf (buff,"sbc a,b"); break;
+ case 0x99: sprintf (buff,"sbc a,c"); break;
+ case 0x9a: sprintf (buff,"sbc a,d"); break;
+ case 0x9b: sprintf (buff,"sbc a,e"); break;
+ case 0x9c: sprintf (buff,"sbc a,h"); break;
+ case 0x9d: sprintf (buff,"sbc a,l"); break;
+ case 0x9e: sprintf (buff,"sbc a,(hl)"); break;
+ case 0x9f: sprintf (buff,"sbc a,a"); break;
+ case 0xa0: sprintf (buff,"and b"); break;
+ case 0xa1: sprintf (buff,"and c"); break;
+ case 0xa2: sprintf (buff,"and d"); break;
+ case 0xa3: sprintf (buff,"and e"); break;
+ case 0xa4: sprintf (buff,"and h"); break;
+ case 0xa5: sprintf (buff,"and l"); break;
+ case 0xa6: sprintf (buff,"and (hl)"); break;
+ case 0xa7: sprintf (buff,"and a"); break;
+ case 0xa8: sprintf (buff,"xor b"); break;
+ case 0xa9: sprintf (buff,"xor c"); break;
+ case 0xaa: sprintf (buff,"xor d"); break;
+ case 0xab: sprintf (buff,"xor e"); break;
+ case 0xac: sprintf (buff,"xor h"); break;
+ case 0xad: sprintf (buff,"xor l"); break;
+ case 0xae: sprintf (buff,"xor (hl)"); break;
+ case 0xaf: sprintf (buff,"xor a"); break;
+ case 0xb0: sprintf (buff,"or b"); break;
+ case 0xb1: sprintf (buff,"or c"); break;
+ case 0xb2: sprintf (buff,"or d"); break;
+ case 0xb3: sprintf (buff,"or e"); break;
+ case 0xb4: sprintf (buff,"or h"); break;
+ case 0xb5: sprintf (buff,"or l"); break;
+ case 0xb6: sprintf (buff,"or (hl)"); break;
+ case 0xb7: sprintf (buff,"or a"); break;
+ case 0xb8: sprintf (buff,"cp b"); break;
+ case 0xb9: sprintf (buff,"cp c"); break;
+ case 0xba: sprintf (buff,"cp d"); break;
+ case 0xbb: sprintf (buff,"cp e"); break;
+ case 0xbc: sprintf (buff,"cp h"); break;
+ case 0xbd: sprintf (buff,"cp l"); break;
+ case 0xbe: sprintf (buff,"cp (hl)"); break;
+ case 0xbf: sprintf (buff,"cp a"); break;
+ case 0xc0: sprintf (buff,"ret nz"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xc1: sprintf (buff,"pop bc"); break;
+ case 0xc2: sprintf (buff,"jp nz,$%04x", ARGW(pc)); pc+=2; break;
+ case 0xc3: sprintf (buff,"jp $%04x", ARGW(pc)); pc+=2; break;
+ case 0xc4: sprintf (buff,"call nz,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xc5: sprintf (buff,"push bc"); break;
+ case 0xc6: sprintf (buff,"add a,$%02x", ARG(pc)); pc++; break;
+ case 0xc7: sprintf (buff,"rst $00"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xc8: sprintf (buff,"ret z"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xc9: sprintf (buff,"ret"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xca: sprintf (buff,"jp z,$%04x", ARGW(pc)); pc+=2; break;
+ case 0xcb: sprintf (buff,"rst v,$40 (*)"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xcc: sprintf (buff,"call z,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xcd: sprintf (buff,"call $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xce: sprintf (buff,"adc a,$%02x", ARG(pc)); pc++; break;
+ case 0xcf: sprintf (buff,"rst $08"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xd0: sprintf (buff,"ret nc"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xd1: sprintf (buff,"pop de"); break;
+ case 0xd2: sprintf (buff,"jp nc,$%04x", ARGW(pc)); pc+=2; break;
+ case 0xd3: sprintf (buff,"out ($%02x),a", ARG(pc)); pc++; break;
+ case 0xd4: sprintf (buff,"call nc,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xd5: sprintf (buff,"push de"); break;
+ case 0xd6: sprintf (buff,"sub $%02x", ARG(pc)); pc++; break;
+ case 0xd7: sprintf (buff,"rst $10"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xd8: sprintf (buff,"ret c"); break;
+ case 0xd9: sprintf (buff,"ld (de),hl (*)"); break;
+ case 0xda: sprintf (buff,"jp c,$%04x", ARGW(pc)); pc+=2; break;
+ case 0xdb: sprintf (buff,"in a,($%02x)", ARG(pc)); pc++; break;
+ case 0xdc: sprintf (buff,"call c,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xdd: sprintf (buff,"jp nx,$%04x (*)",ARGW(pc));pc+=2;break;
+ case 0xde: sprintf (buff,"sub $%02x", ARG(pc)); pc++; break;
+ case 0xdf: sprintf (buff,"rst $18"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xe0: sprintf (buff,"ret pe"); break;
+ case 0xe1: sprintf (buff,"pop hl"); break;
+ case 0xe2: sprintf (buff,"jp pe,$%04x", ARGW(pc)); pc+=2; break;
+ case 0xe3: sprintf (buff,"ex (sp),hl"); break;
+ case 0xe4: sprintf (buff,"call pe,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xe5: sprintf (buff,"push hl"); break;
+ case 0xe6: sprintf (buff,"and $%02x", ARG(pc)); pc++; break;
+ case 0xe7: sprintf (buff,"rst $20"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xe8: sprintf (buff,"ret po"); break;
+ case 0xe9: sprintf (buff,"jp (hl)"); break;
+ case 0xea: sprintf (buff,"jp po,$%04x", ARGW(pc)); pc+=2; break;
+ case 0xeb: sprintf (buff,"ex de,hl"); break;
+ case 0xec: sprintf (buff,"call po,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xed: sprintf (buff,"ld hl,(de) (*)"); break;
+ case 0xee: sprintf (buff,"xor $%02x", ARG(pc)); pc++; break;
+ case 0xef: sprintf (buff,"rst $28"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xf0: sprintf (buff,"ret p"); break;
+ case 0xf1: sprintf (buff,"pop af"); break;
+ case 0xf2: sprintf (buff,"jp p,$%04x", ARGW(pc)); pc+=2; break;
+ case 0xf3: sprintf (buff,"di"); break;
+ case 0xf4: sprintf (buff,"cp $%04x", ARGW(pc)); pc+=2; break;
+ case 0xf5: sprintf (buff,"push af"); break;
+ case 0xf6: sprintf (buff,"or $%02x", ARG(pc)); pc++; break;
+ case 0xf7: sprintf (buff,"rst $30"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xf8: sprintf (buff,"ret m"); break;
+ case 0xf9: sprintf (buff,"ld sp,hl"); break;
+ case 0xfa: sprintf (buff,"jp m,$%04x", ARGW(pc)); pc+=2; break;
+ case 0xfb: sprintf (buff,"ei"); break;
+ case 0xfc: sprintf (buff,"call m,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xfd: sprintf (buff,"jp x,$%04x (*)",ARGW(pc));pc+=2; break;
+ case 0xfe: sprintf (buff,"cp $%02x", ARG(pc)); pc++; break;
+ case 0xff: sprintf (buff,"rst $38"); flags = DASMFLAG_STEP_OVER; break;
+#else
+ case 0x00: sprintf (buff,"nop"); break;
+ case 0x01: sprintf (buff,"lxi b,$%04x", ARGW(pc)); pc+=2; break;
+ case 0x02: sprintf (buff,"stax b"); break;
+ case 0x03: sprintf (buff,"inx b"); break;
+ case 0x04: sprintf (buff,"inr b"); break;
+ case 0x05: sprintf (buff,"dcr b"); break;
+ case 0x06: sprintf (buff,"mvi b,$%02x", ARG(pc)); pc++; break;
+ case 0x07: sprintf (buff,"rlc"); break;
+ case 0x08: sprintf (buff,"dsub (*)"); break;
+ case 0x09: sprintf (buff,"dad b"); break;
+ case 0x0a: sprintf (buff,"ldax b"); break;
+ case 0x0b: sprintf (buff,"dcx b"); break;
+ case 0x0c: sprintf (buff,"inr c"); break;
+ case 0x0d: sprintf (buff,"dcr c"); break;
+ case 0x0e: sprintf (buff,"mvi c,$%02x", ARG(pc)); pc++; break;
+ case 0x0f: sprintf (buff,"rrc"); break;
+ case 0x10: sprintf (buff,"asrh (*)"); break;
+ case 0x11: sprintf (buff,"lxi d,$%04x", ARGW(pc)); pc+=2; break;
+ case 0x12: sprintf (buff,"stax d"); break;
+ case 0x13: sprintf (buff,"inx d"); break;
+ case 0x14: sprintf (buff,"inr d"); break;
+ case 0x15: sprintf (buff,"dcr d"); break;
+ case 0x16: sprintf (buff,"mvi d,$%02x", ARG(pc)); pc++; break;
+ case 0x17: sprintf (buff,"ral"); break;
+ case 0x18: sprintf (buff,"rlde (*)"); break;
+ case 0x19: sprintf (buff,"dad d"); break;
+ case 0x1a: sprintf (buff,"ldax d"); break;
+ case 0x1b: sprintf (buff,"dcx d"); break;
+ case 0x1c: sprintf (buff,"inr e"); break;
+ case 0x1d: sprintf (buff,"dcr e"); break;
+ case 0x1e: sprintf (buff,"mvi e,$%02x", ARG(pc)); pc++; break;
+ case 0x1f: sprintf (buff,"rar"); break;
+ case 0x20: sprintf (buff,"rim"); break;
+ case 0x21: sprintf (buff,"lxi h,$%04x", ARGW(pc)); pc+=2; break;
+ case 0x22: sprintf (buff,"shld $%04x", ARGW(pc)); pc+=2; break;
+ case 0x23: sprintf (buff,"inx h"); break;
+ case 0x24: sprintf (buff,"inr h"); break;
+ case 0x25: sprintf (buff,"dcr h"); break;
+ case 0x26: sprintf (buff,"mvi h,$%02x", ARG(pc)); pc++; break;
+ case 0x27: sprintf (buff,"daa"); break;
+ case 0x28: sprintf (buff,"ldeh $%02x (*)", ARG(pc)); pc++; break;
+ case 0x29: sprintf (buff,"dad h"); break;
+ case 0x2a: sprintf (buff,"lhld $%04x", ARGW(pc)); pc+=2; break;
+ case 0x2b: sprintf (buff,"dcx h"); break;
+ case 0x2c: sprintf (buff,"inr l"); break;
+ case 0x2d: sprintf (buff,"dcr l"); break;
+ case 0x2e: sprintf (buff,"mvi l,$%02x", ARG(pc)); pc++; break;
+ case 0x2f: sprintf (buff,"cma"); break;
+ case 0x30: sprintf (buff,"sim"); break;
+ case 0x31: sprintf (buff,"lxi sp,$%04x", ARGW(pc)); pc+=2; break;
+ case 0x32: sprintf (buff,"stax $%04x", ARGW(pc)); pc+=2; break;
+ case 0x33: sprintf (buff,"inx sp"); break;
+ case 0x34: sprintf (buff,"inr m"); break;
+ case 0x35: sprintf (buff,"dcr m"); break;
+ case 0x36: sprintf (buff,"mvi m,$%02x", ARG(pc)); pc++; break;
+ case 0x37: sprintf (buff,"stc"); break;
+ case 0x38: sprintf (buff,"ldes $%02x", ARG(pc)); pc++; break;
+ case 0x39: sprintf (buff,"dad sp"); break;
+ case 0x3a: sprintf (buff,"ldax $%04x", ARGW(pc)); pc+=2; break;
+ case 0x3b: sprintf (buff,"dcx sp"); break;
+ case 0x3c: sprintf (buff,"inr a"); break;
+ case 0x3d: sprintf (buff,"dcr a"); break;
+ case 0x3e: sprintf (buff,"mvi a,$%02x", ARG(pc)); pc++; break;
+ case 0x3f: sprintf (buff,"cmf"); break;
+ case 0x40: sprintf (buff,"mov b,b"); break;
+ case 0x41: sprintf (buff,"mov b,c"); break;
+ case 0x42: sprintf (buff,"mov b,d"); break;
+ case 0x43: sprintf (buff,"mov b,e"); break;
+ case 0x44: sprintf (buff,"mov b,h"); break;
+ case 0x45: sprintf (buff,"mov b,l"); break;
+ case 0x46: sprintf (buff,"mov b,m"); break;
+ case 0x47: sprintf (buff,"mov b,a"); break;
+ case 0x48: sprintf (buff,"mov c,b"); break;
+ case 0x49: sprintf (buff,"mov c,c"); break;
+ case 0x4a: sprintf (buff,"mov c,d"); break;
+ case 0x4b: sprintf (buff,"mov c,e"); break;
+ case 0x4c: sprintf (buff,"mov c,h"); break;
+ case 0x4d: sprintf (buff,"mov c,l"); break;
+ case 0x4e: sprintf (buff,"mov c,m"); break;
+ case 0x4f: sprintf (buff,"mov c,a"); break;
+ case 0x50: sprintf (buff,"mov d,b"); break;
+ case 0x51: sprintf (buff,"mov d,c"); break;
+ case 0x52: sprintf (buff,"mov d,d"); break;
+ case 0x53: sprintf (buff,"mov d,e"); break;
+ case 0x54: sprintf (buff,"mov d,h"); break;
+ case 0x55: sprintf (buff,"mov d,l"); break;
+ case 0x56: sprintf (buff,"mov d,m"); break;
+ case 0x57: sprintf (buff,"mov d,a"); break;
+ case 0x58: sprintf (buff,"mov e,b"); break;
+ case 0x59: sprintf (buff,"mov e,c"); break;
+ case 0x5a: sprintf (buff,"mov e,d"); break;
+ case 0x5b: sprintf (buff,"mov e,e"); break;
+ case 0x5c: sprintf (buff,"mov e,h"); break;
+ case 0x5d: sprintf (buff,"mov e,l"); break;
+ case 0x5e: sprintf (buff,"mov e,m"); break;
+ case 0x5f: sprintf (buff,"mov e,a"); break;
+ case 0x60: sprintf (buff,"mov h,b"); break;
+ case 0x61: sprintf (buff,"mov h,c"); break;
+ case 0x62: sprintf (buff,"mov h,d"); break;
+ case 0x63: sprintf (buff,"mov h,e"); break;
+ case 0x64: sprintf (buff,"mov h,h"); break;
+ case 0x65: sprintf (buff,"mov h,l"); break;
+ case 0x66: sprintf (buff,"mov h,m"); break;
+ case 0x67: sprintf (buff,"mov h,a"); break;
+ case 0x68: sprintf (buff,"mov l,b"); break;
+ case 0x69: sprintf (buff,"mov l,c"); break;
+ case 0x6a: sprintf (buff,"mov l,d"); break;
+ case 0x6b: sprintf (buff,"mov l,e"); break;
+ case 0x6c: sprintf (buff,"mov l,h"); break;
+ case 0x6d: sprintf (buff,"mov l,l"); break;
+ case 0x6e: sprintf (buff,"mov l,m"); break;
+ case 0x6f: sprintf (buff,"mov l,a"); break;
+ case 0x70: sprintf (buff,"mov m,b"); break;
+ case 0x71: sprintf (buff,"mov m,c"); break;
+ case 0x72: sprintf (buff,"mov m,d"); break;
+ case 0x73: sprintf (buff,"mov m,e"); break;
+ case 0x74: sprintf (buff,"mov m,h"); break;
+ case 0x75: sprintf (buff,"mov m,l"); break;
+ case 0x76: sprintf (buff,"mov m,m"); break;
+ case 0x77: sprintf (buff,"mov m,a"); break;
+ case 0x78: sprintf (buff,"mov a,b"); break;
+ case 0x79: sprintf (buff,"mov a,c"); break;
+ case 0x7a: sprintf (buff,"mov a,d"); break;
+ case 0x7b: sprintf (buff,"mov a,e"); break;
+ case 0x7c: sprintf (buff,"mov a,h"); break;
+ case 0x7d: sprintf (buff,"mov a,l"); break;
+ case 0x7e: sprintf (buff,"mov a,m"); break;
+ case 0x7f: sprintf (buff,"mov a,a"); break;
+ case 0x80: sprintf (buff,"add b"); break;
+ case 0x81: sprintf (buff,"add c"); break;
+ case 0x82: sprintf (buff,"add d"); break;
+ case 0x83: sprintf (buff,"add e"); break;
+ case 0x84: sprintf (buff,"add h"); break;
+ case 0x85: sprintf (buff,"add l"); break;
+ case 0x86: sprintf (buff,"add m"); break;
+ case 0x87: sprintf (buff,"add a"); break;
+ case 0x88: sprintf (buff,"adc b"); break;
+ case 0x89: sprintf (buff,"adc c"); break;
+ case 0x8a: sprintf (buff,"adc d"); break;
+ case 0x8b: sprintf (buff,"adc e"); break;
+ case 0x8c: sprintf (buff,"adc h"); break;
+ case 0x8d: sprintf (buff,"adc l"); break;
+ case 0x8e: sprintf (buff,"adc m"); break;
+ case 0x8f: sprintf (buff,"adc a"); break;
+ case 0x90: sprintf (buff,"sub b"); break;
+ case 0x91: sprintf (buff,"sub c"); break;
+ case 0x92: sprintf (buff,"sub d"); break;
+ case 0x93: sprintf (buff,"sub e"); break;
+ case 0x94: sprintf (buff,"sub h"); break;
+ case 0x95: sprintf (buff,"sub l"); break;
+ case 0x96: sprintf (buff,"sub m"); break;
+ case 0x97: sprintf (buff,"sub a"); break;
+ case 0x98: sprintf (buff,"sbb b"); break;
+ case 0x99: sprintf (buff,"sbb c"); break;
+ case 0x9a: sprintf (buff,"sbb d"); break;
+ case 0x9b: sprintf (buff,"sbb e"); break;
+ case 0x9c: sprintf (buff,"sbb h"); break;
+ case 0x9d: sprintf (buff,"sbb l"); break;
+ case 0x9e: sprintf (buff,"sbb m"); break;
+ case 0x9f: sprintf (buff,"sbb a"); break;
+ case 0xa0: sprintf (buff,"ana b"); break;
+ case 0xa1: sprintf (buff,"ana c"); break;
+ case 0xa2: sprintf (buff,"ana d"); break;
+ case 0xa3: sprintf (buff,"ana e"); break;
+ case 0xa4: sprintf (buff,"ana h"); break;
+ case 0xa5: sprintf (buff,"ana l"); break;
+ case 0xa6: sprintf (buff,"ana m"); break;
+ case 0xa7: sprintf (buff,"ana a"); break;
+ case 0xa8: sprintf (buff,"xra b"); break;
+ case 0xa9: sprintf (buff,"xra c"); break;
+ case 0xaa: sprintf (buff,"xra d"); break;
+ case 0xab: sprintf (buff,"xra e"); break;
+ case 0xac: sprintf (buff,"xra h"); break;
+ case 0xad: sprintf (buff,"xra l"); break;
+ case 0xae: sprintf (buff,"xra m"); break;
+ case 0xaf: sprintf (buff,"xra a"); break;
+ case 0xb0: sprintf (buff,"ora b"); break;
+ case 0xb1: sprintf (buff,"ora c"); break;
+ case 0xb2: sprintf (buff,"ora d"); break;
+ case 0xb3: sprintf (buff,"ora e"); break;
+ case 0xb4: sprintf (buff,"ora h"); break;
+ case 0xb5: sprintf (buff,"ora l"); break;
+ case 0xb6: sprintf (buff,"ora m"); break;
+ case 0xb7: sprintf (buff,"ora a"); break;
+ case 0xb8: sprintf (buff,"cmp b"); break;
+ case 0xb9: sprintf (buff,"cmp c"); break;
+ case 0xba: sprintf (buff,"cmp d"); break;
+ case 0xbb: sprintf (buff,"cmp e"); break;
+ case 0xbc: sprintf (buff,"cmp h"); break;
+ case 0xbd: sprintf (buff,"cmp l"); break;
+ case 0xbe: sprintf (buff,"cmp m"); break;
+ case 0xbf: sprintf (buff,"cmp a"); break;
+ case 0xc0: sprintf (buff,"rnz"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xc1: sprintf (buff,"pop b"); break;
+ case 0xc2: sprintf (buff,"jnz $%04x", ARGW(pc)); pc+=2; break;
+ case 0xc3: sprintf (buff,"jmp $%04x", ARGW(pc)); pc+=2; break;
+ case 0xc4: sprintf (buff,"cnz $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xc5: sprintf (buff,"push b"); break;
+ case 0xc6: sprintf (buff,"adi $%02x", ARG(pc)); pc++; break;
+ case 0xc7: sprintf (buff,"rst 0"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xc8: sprintf (buff,"rz"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xc9: sprintf (buff,"ret"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xca: sprintf (buff,"jz $%04x", ARGW(pc)); pc+=2; break;
+ case 0xcb: sprintf (buff,"rstv 8 (*)"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xcc: sprintf (buff,"cz $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xcd: sprintf (buff,"call $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xce: sprintf (buff,"aci $%02x", ARG(pc)); pc++; break;
+ case 0xcf: sprintf (buff,"rst 1"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xd0: sprintf (buff,"rnc"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xd1: sprintf (buff,"pop d"); break;
+ case 0xd2: sprintf (buff,"jnc $%04x", ARGW(pc)); pc+=2; break;
+ case 0xd3: sprintf (buff,"out $%02x", ARG(pc)); pc++; break;
+ case 0xd4: sprintf (buff,"cnc $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xd5: sprintf (buff,"push d"); break;
+ case 0xd6: sprintf (buff,"sui $%02x", ARG(pc)); pc++; break;
+ case 0xd7: sprintf (buff,"rst 2"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xd8: sprintf (buff,"rc"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xd9: sprintf (buff,"shlx d (*)"); break;
+ case 0xda: sprintf (buff,"jc $%04x", ARGW(pc)); pc+=2; break;
+ case 0xdb: sprintf (buff,"in $%02x", ARG(pc)); pc++; break;
+ case 0xdc: sprintf (buff,"cc $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xdd: sprintf (buff,"jnx $%04x (*)", ARGW(pc)); pc+=2; break;
+ case 0xde: sprintf (buff,"sbi $%02x", ARG(pc)); pc++; break;
+ case 0xdf: sprintf (buff,"rst 3"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xe0: sprintf (buff,"rpo"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xe1: sprintf (buff,"pop h"); break;
+ case 0xe2: sprintf (buff,"jpo $%04x", ARGW(pc)); pc+=2; break;
+ case 0xe3: sprintf (buff,"xthl"); break;
+ case 0xe4: sprintf (buff,"cpo $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xe5: sprintf (buff,"push h"); break;
+ case 0xe6: sprintf (buff,"ani $%02x", ARG(pc)); pc++; break;
+ case 0xe7: sprintf (buff,"rst 4"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xe8: sprintf (buff,"rpe"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xe9: sprintf (buff,"pchl"); break;
+ case 0xea: sprintf (buff,"jpe $%04x", ARGW(pc)); pc+=2; break;
+ case 0xeb: sprintf (buff,"xchg"); break;
+ case 0xec: sprintf (buff,"cpe $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xed: sprintf (buff,"lhlx d (*)"); break;
+ case 0xee: sprintf (buff,"xri $%02x", ARG(pc)); pc++; break;
+ case 0xef: sprintf (buff,"rst 5"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xf0: sprintf (buff,"rp"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xf1: sprintf (buff,"pop a"); break;
+ case 0xf2: sprintf (buff,"jp $%04x", ARGW(pc)); pc+=2; break;
+ case 0xf3: sprintf (buff,"di"); break;
+ case 0xf4: sprintf (buff,"cp $%04x", ARGW(pc)); pc+=2; break;
+ case 0xf5: sprintf (buff,"push a"); break;
+ case 0xf6: sprintf (buff,"ori $%02x", ARG(pc)); pc++; break;
+ case 0xf7: sprintf (buff,"rst 6"); flags = DASMFLAG_STEP_OVER; break;
+ case 0xf8: sprintf (buff,"rm"); flags = DASMFLAG_STEP_OUT; break;
+ case 0xf9: sprintf (buff,"sphl"); break;
+ case 0xfa: sprintf (buff,"jm $%04x", ARGW(pc)); pc+=2; break;
+ case 0xfb: sprintf (buff,"ei"); break;
+ case 0xfc: sprintf (buff,"cm $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break;
+ case 0xfd: sprintf (buff,"jx $%04x (*)", ARGW(pc)); pc+=2; break;
+ case 0xfe: sprintf (buff,"cpi $%02x", ARG(pc)); pc++; break;
+ case 0xff: sprintf (buff,"rst 7"); flags = DASMFLAG_STEP_OVER; break;
+#endif
+ }
+ return (pc - PC) | flags | DASMFLAG_SUPPORTED;
+}
+
diff --git a/src/emu/cpu/i8085/i8085.c b/src/emu/cpu/i8085/i8085.c
new file mode 100644
index 00000000000..11ea984e54d
--- /dev/null
+++ b/src/emu/cpu/i8085/i8085.c
@@ -0,0 +1,1759 @@
+/*****************************************************************************
+ *
+ * i8085.c
+ * Portable I8085A emulator V1.2
+ *
+ * Copyright (c) 1999 Juergen Buchmueller, all rights reserved.
+ * Partially based on information out of Z80Em by Marcel De Kogel
+ *
+ * changes in V1.3
+ * - Added undocumented opcodes for the 8085A, based on a german
+ * book about microcomputers: "Mikrocomputertechnik mit dem
+ * Prozessor 8085A".
+ * - This book also suggest that INX/DCX should modify the X flag bit
+ * for a LSB to MSB carry and
+ * - that jumps take 10 T-states only when they're executed, 7 when
+ * they're skipped.
+ * Thanks for the info and a copy of the tables go to Timo Sachsenberg
+ * <timo.sachsenberg@student.uni-tuebingen.de>
+ * changes in V1.2
+ * - corrected cycle counts for these classes of opcodes
+ * Thanks go to Jim Battle <frustum@pacbell.bet>
+ *
+ * 808x Z80
+ * DEC A 5 4 \
+ * INC A 5 4 \
+ * LD A,B 5 4 >-- Z80 is faster
+ * JP (HL) 5 4 /
+ * CALL cc,nnnn: 11/17 10/17 /
+ *
+ * INC HL 5 6 \
+ * DEC HL 5 6 \
+ * LD SP,HL 5 6 \
+ * ADD HL,BC 10 11 \
+ * INC (HL) 10 11 >-- 8080 is faster
+ * DEC (HL) 10 11 /
+ * IN A,(#) 10 11 /
+ * OUT (#),A 10 11 /
+ * EX (SP),HL 18 19 /
+ *
+ * Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * You can contact me at juergen@mame.net or pullmoll@stop1984.com
+ *
+ * - This source code is released as freeware for non-commercial purposes
+ * as part of the M.A.M.E. (Multiple Arcade Machine Emulator) project.
+ * The licensing terms of MAME apply to this piece of code for the MAME
+ * project and derviative works, as defined by the MAME license. You
+ * may opt to make modifications, improvements or derivative works under
+ * that same conditions, and the MAME project may opt to keep
+ * modifications, improvements or derivatives under their terms exclusively.
+ *
+ * - Alternatively you can choose to apply the terms of the "GPL" (see
+ * below) to this - and only this - piece of code or your derivative works.
+ * Note that in no case your choice can have any impact on any other
+ * source code of the MAME project, or binary, or executable, be it closely
+ * or losely related to this piece of code.
+ *
+ * - At your choice you are also free to remove either licensing terms from
+ * this file and continue to use it under only one of the two licenses. Do this
+ * if you think that licenses are not compatible (enough) for you, or if you
+ * consider either license 'too restrictive' or 'too free'.
+ *
+ * - GPL (GNU General Public License)
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Revisions:
+ *
+ * xx-xx-2002 Acho A. Tang
+ *
+ * - 8085 emulation was in fact never used. It's been treated as a plain 8080.
+ * - protected IRQ0 vector from being overwritten
+ * - modified interrupt handler to properly process 8085-specific IRQ's
+ * - corrected interrupt masking, RIM and SIM behaviors according to Intel's documentation
+ *
+ * 20-Jul-2002 Krzysztof Strzecha
+ *
+ * - SBB r instructions should affect parity flag.
+ * Fixed only for non x86 asm version (#define i8080_EXACT 1).
+ * There are probably more opcodes which should affect this flag, but don't.
+ * - JPO nnnn and JPE nnnn opcodes in disassembler were misplaced. Fixed.
+ * - Undocumented i8080 opcodes added:
+ * 08h, 10h, 18h, 20h, 28h, 30h, 38h - NOP
+ * 0CBh - JMP
+ * 0D9h - RET
+ * 0DDh, 0EDh, 0FDh - CALL
+ * Thanks for the info go to Anton V. Ignatichev.
+ *
+ * 08-Dec-2002 Krzysztof Strzecha
+ *
+ * - ADC r instructions should affect parity flag.
+ * Fixed only for non x86 asm version (#define i8080_EXACT 1).
+ * There are probably more opcodes which should affect this flag, but don't.
+ *
+ * 05-Sep-2003 Krzysztof Strzecha
+ *
+ * - INR r, DCR r, ADD r, SUB r, CMP r instructions should affect parity flag.
+ * Fixed only for non x86 asm version (#define i8080_EXACT 1).
+ *
+ * 23-Dec-2006 Tomasz Slanina
+ *
+ * - SIM fixed
+ *
+ * 28-Jan-2007 Zsolt Vasvari
+ *
+ * - Removed archaic i8080_EXACT flag.
+ *
+ *****************************************************************************/
+
+/*int survival_prot = 0; */
+
+#define VERBOSE 0
+
+#include "debugger.h"
+#include "i8085.h"
+#include "i8085cpu.h"
+#include "i8085daa.h"
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+#define I8085_INTR 0xff
+
+typedef struct {
+ int cputype; /* 0 8080, 1 8085A */
+ PAIR PC,SP,AF,BC,DE,HL,XX;
+ UINT8 HALT;
+ UINT8 IM; /* interrupt mask */
+ UINT8 IREQ; /* requested interrupts */
+ UINT8 ISRV; /* serviced interrupt */
+ UINT32 INTR; /* vector for INTR */
+ UINT32 IRQ2; /* scheduled interrupt address */
+ UINT32 IRQ1; /* executed interrupt address */
+ INT8 irq_state[4];
+ int (*irq_callback)(int);
+ void (*sod_callback)(int state);
+} i8085_Regs;
+
+int i8085_ICount = 0;
+
+static i8085_Regs I;
+static UINT8 ZS[256];
+static UINT8 ZSP[256];
+static UINT8 RIM_IEN = 0; //AT: IEN status latch used by the RIM instruction
+static UINT8 ROP(void)
+{
+ return cpu_readop(I.PC.w.l++);
+}
+
+static UINT8 ARG(void)
+{
+ return cpu_readop_arg(I.PC.w.l++);
+}
+
+static UINT16 ARG16(void)
+{
+ UINT16 w;
+ w = cpu_readop_arg(I.PC.d);
+ I.PC.w.l++;
+ w += cpu_readop_arg(I.PC.d) << 8;
+ I.PC.w.l++;
+ return w;
+}
+
+static UINT8 RM(UINT32 a)
+{
+ return program_read_byte_8(a);
+}
+
+static void WM(UINT32 a, UINT8 v)
+{
+ program_write_byte_8(a, v);
+}
+
+INLINE void execute_one(int opcode)
+{
+ switch (opcode)
+ {
+ case 0x00: i8085_ICount -= 4; /* NOP */
+ /* no op */
+ break;
+ case 0x01: i8085_ICount -= 10; /* LXI B,nnnn */
+ I.BC.w.l = ARG16();
+ break;
+ case 0x02: i8085_ICount -= 7; /* STAX B */
+ WM(I.BC.d, I.AF.b.h);
+ break;
+ case 0x03: i8085_ICount -= 5; /* INX B */
+ I.BC.w.l++;
+ if (I.BC.b.l == 0x00) I.AF.b.l |= XF; else I.AF.b.l &= ~XF;
+ break;
+ case 0x04: i8085_ICount -= 5; /* INR B */
+ M_INR(I.BC.b.h);
+ break;
+ case 0x05: i8085_ICount -= 5; /* DCR B */
+ M_DCR(I.BC.b.h);
+ break;
+ case 0x06: i8085_ICount -= 7; /* MVI B,nn */
+ M_MVI(I.BC.b.h);
+ break;
+ case 0x07: i8085_ICount -= 4; /* RLC */
+ M_RLC;
+ break;
+
+ case 0x08:
+ if( I.cputype ) {
+ i8085_ICount -= 10; /* DSUB */
+ M_DSUB();
+ } else {
+ i8085_ICount -= 4; /* NOP undocumented */
+ }
+ break;
+ case 0x09: i8085_ICount -= 10; /* DAD B */
+ M_DAD(BC);
+ break;
+ case 0x0a: i8085_ICount -= 7; /* LDAX B */
+ I.AF.b.h = RM(I.BC.d);
+ break;
+ case 0x0b: i8085_ICount -= 5; /* DCX B */
+ I.BC.w.l--;
+ if (I.BC.b.l == 0xff) I.AF.b.l |= XF; else I.AF.b.l &= ~XF;
+ break;
+ case 0x0c: i8085_ICount -= 5; /* INR C */
+ M_INR(I.BC.b.l);
+ break;
+ case 0x0d: i8085_ICount -= 5; /* DCR C */
+ M_DCR(I.BC.b.l);
+ break;
+ case 0x0e: i8085_ICount -= 7; /* MVI C,nn */
+ M_MVI(I.BC.b.l);
+ break;
+ case 0x0f: i8085_ICount -= 4; /* RRC */
+ M_RRC;
+ break;
+
+ case 0x10:
+ if( I.cputype ) {
+ i8085_ICount -= 7; /* ASRH */
+ I.AF.b.l = (I.AF.b.l & ~CF) | (I.HL.b.l & CF);
+ I.HL.w.l = (I.HL.w.l >> 1);
+ } else {
+ i8085_ICount -= 4; /* NOP undocumented */
+ }
+ break;
+ case 0x11: i8085_ICount -= 10; /* LXI D,nnnn */
+ I.DE.w.l = ARG16();
+ break;
+ case 0x12: i8085_ICount -= 7; /* STAX D */
+ WM(I.DE.d, I.AF.b.h);
+ break;
+ case 0x13: i8085_ICount -= 5; /* INX D */
+ I.DE.w.l++;
+ if (I.DE.b.l == 0x00) I.AF.b.l |= XF; else I.AF.b.l &= ~XF;
+ break;
+ case 0x14: i8085_ICount -= 5; /* INR D */
+ M_INR(I.DE.b.h);
+ break;
+ case 0x15: i8085_ICount -= 5; /* DCR D */
+ M_DCR(I.DE.b.h);
+ break;
+ case 0x16: i8085_ICount -= 7; /* MVI D,nn */
+ M_MVI(I.DE.b.h);
+ break;
+ case 0x17: i8085_ICount -= 4; /* RAL */
+ M_RAL;
+ break;
+
+ case 0x18:
+ if( I.cputype ) {
+ i8085_ICount -= 10; /* RLDE */
+ I.AF.b.l = (I.AF.b.l & ~(CF | VF)) | (I.DE.b.h >> 7);
+ I.DE.w.l = (I.DE.w.l << 1) | (I.DE.w.l >> 15);
+ if (0 != (((I.DE.w.l >> 15) ^ I.AF.b.l) & CF))
+ I.AF.b.l |= VF;
+ } else {
+ i8085_ICount -= 4; /* NOP undocumented */
+ }
+ break;
+ case 0x19: i8085_ICount -= 10; /* DAD D */
+ M_DAD(DE);
+ break;
+ case 0x1a: i8085_ICount -= 7; /* LDAX D */
+ I.AF.b.h = RM(I.DE.d);
+ break;
+ case 0x1b: i8085_ICount -= 5; /* DCX D */
+ I.DE.w.l--;
+ if (I.DE.b.l == 0xff) I.AF.b.l |= XF; else I.AF.b.l &= ~XF;
+ break;
+ case 0x1c: i8085_ICount -= 5; /* INR E */
+ M_INR(I.DE.b.l);
+ break;
+ case 0x1d: i8085_ICount -= 5; /* DCR E */
+ M_DCR(I.DE.b.l);
+ break;
+ case 0x1e: i8085_ICount -= 7; /* MVI E,nn */
+ M_MVI(I.DE.b.l);
+ break;
+ case 0x1f: i8085_ICount -= 4; /* RAR */
+ M_RAR;
+ break;
+
+ case 0x20:
+ if( I.cputype ) {
+ i8085_ICount -= 7; /* RIM */
+ I.AF.b.h = I.IM;
+ I.AF.b.h |= RIM_IEN; RIM_IEN = 0; //AT: read and clear IEN status latch
+ } else {
+ i8085_ICount -= 4; /* NOP undocumented */
+ }
+ break;
+ case 0x21: i8085_ICount -= 10; /* LXI H,nnnn */
+ I.HL.w.l = ARG16();
+ break;
+ case 0x22: i8085_ICount -= 16; /* SHLD nnnn */
+ I.XX.w.l = ARG16();
+ WM(I.XX.d, I.HL.b.l);
+ I.XX.w.l++;
+ WM(I.XX.d, I.HL.b.h);
+ break;
+ case 0x23: i8085_ICount -= 5; /* INX H */
+ I.HL.w.l++;
+ if (I.HL.b.l == 0x00) I.AF.b.l |= XF; else I.AF.b.l &= ~XF;
+ break;
+ case 0x24: i8085_ICount -= 5; /* INR H */
+ M_INR(I.HL.b.h);
+ break;
+ case 0x25: i8085_ICount -= 5; /* DCR H */
+ M_DCR(I.HL.b.h);
+ break;
+ case 0x26: i8085_ICount -= 7; /* MVI H,nn */
+ M_MVI(I.HL.b.h);
+ break;
+ case 0x27: i8085_ICount -= 4; /* DAA */
+ I.XX.d = I.AF.b.h;
+ if (I.AF.b.l & CF) I.XX.d |= 0x100;
+ if (I.AF.b.l & HF) I.XX.d |= 0x200;
+ if (I.AF.b.l & NF) I.XX.d |= 0x400;
+ I.AF.w.l = DAA[I.XX.d];
+ break;
+
+ case 0x28:
+ if( I.cputype ) {
+ i8085_ICount -= 10; /* LDEH nn */
+ I.XX.d = ARG();
+ I.DE.d = (I.HL.d + I.XX.d) & 0xffff;
+ } else {
+ i8085_ICount -= 4; /* NOP undocumented */
+ }
+ break;
+ case 0x29: i8085_ICount -= 10; /* DAD H */
+ M_DAD(HL);
+ break;
+ case 0x2a: i8085_ICount -= 16; /* LHLD nnnn */
+ I.XX.d = ARG16();
+ I.HL.b.l = RM(I.XX.d);
+ I.XX.w.l++;
+ I.HL.b.h = RM(I.XX.d);
+ break;
+ case 0x2b: i8085_ICount -= 5; /* DCX H */
+ I.HL.w.l--;
+ if (I.HL.b.l == 0xff) I.AF.b.l |= XF; else I.AF.b.l &= ~XF;
+ break;
+ case 0x2c: i8085_ICount -= 5; /* INR L */
+ M_INR(I.HL.b.l);
+ break;
+ case 0x2d: i8085_ICount -= 5; /* DCR L */
+ M_DCR(I.HL.b.l);
+ break;
+ case 0x2e: i8085_ICount -= 7; /* MVI L,nn */
+ M_MVI(I.HL.b.l);
+ break;
+ case 0x2f: i8085_ICount -= 4; /* CMA */
+ if( I.cputype )
+ {
+ I.AF.b.h ^= 0xff;
+ I.AF.b.l |= HF + NF;
+ }
+ else
+ {
+ I.AF.b.h ^= 0xff; /* 8080 */
+ }
+ break;
+
+ case 0x30:
+ if( I.cputype )
+ {
+ i8085_ICount -= 7; /* SIM */
+
+ if (I.AF.b.h & 0x40) //SOE - only when bit 0x40 is set!
+ {
+ I.IM &=~IM_SOD;
+ if (I.AF.b.h & 0x80) I.IM |= IM_SOD; //is it needed ?
+ if (I.sod_callback) (*I.sod_callback)(I.AF.b.h >> 7); //SOD - data = bit 0x80
+ }
+//AT
+ //I.IM &= (IM_SID + IM_IEN + IM_TRAP);
+ //I.IM |= (I.AF.b.h & ~(IM_SID + IM_SOD + IM_IEN + IM_TRAP));
+
+ // overwrite RST5.5-7.5 interrupt masks only when bit 0x08 of the accumulator is set
+ if (I.AF.b.h & 0x08)
+ I.IM = (I.IM & ~(IM_RST55+IM_RST65+IM_RST75)) | (I.AF.b.h & (IM_RST55+IM_RST65+IM_RST75));
+
+ } else {
+ i8085_ICount -= 4; /* NOP undocumented */
+ }
+ break;
+
+ case 0x31: i8085_ICount -= 10; /* LXI SP,nnnn */
+ I.SP.w.l = ARG16();
+ break;
+ case 0x32: i8085_ICount -= 13; /* STAX nnnn */
+ I.XX.d = ARG16();
+ WM(I.XX.d, I.AF.b.h);
+ break;
+ case 0x33: i8085_ICount -= 5; /* INX SP */
+ I.SP.w.l++;
+ if (I.SP.b.l == 0x00) I.AF.b.l |= XF; else I.AF.b.l &= ~XF;
+ break;
+ case 0x34: i8085_ICount -= 10; /* INR M */
+ I.XX.b.l = RM(I.HL.d);
+ M_INR(I.XX.b.l);
+ WM(I.HL.d, I.XX.b.l);
+ break;
+ case 0x35: i8085_ICount -= 10; /* DCR M */
+ I.XX.b.l = RM(I.HL.d);
+ M_DCR(I.XX.b.l);
+ WM(I.HL.d, I.XX.b.l);
+ break;
+ case 0x36: i8085_ICount -= 10; /* MVI M,nn */
+ I.XX.b.l = ARG();
+ WM(I.HL.d, I.XX.b.l);
+ break;
+ case 0x37: i8085_ICount -= 4; /* STC */
+ I.AF.b.l = (I.AF.b.l & ~(HF + NF)) | CF;
+ break;
+
+ case 0x38:
+ if( I.cputype ) {
+ i8085_ICount -= 10; /* LDES nn */
+ I.XX.d = ARG();
+ I.DE.d = (I.SP.d + I.XX.d) & 0xffff;
+ } else {
+ i8085_ICount -= 4; /* NOP undocumented */
+ }
+ break;
+ case 0x39: i8085_ICount -= 10; /* DAD SP */
+ M_DAD(SP);
+ break;
+ case 0x3a: i8085_ICount -= 13; /* LDAX nnnn */
+ I.XX.d = ARG16();
+ I.AF.b.h = RM(I.XX.d);
+ break;
+ case 0x3b: i8085_ICount -= 5; /* DCX SP */
+ I.SP.w.l--;
+ if (I.SP.b.l == 0xff) I.AF.b.l |= XF; else I.AF.b.l &= ~XF;
+ break;
+ case 0x3c: i8085_ICount -= 5; /* INR A */
+ M_INR(I.AF.b.h);
+ break;
+ case 0x3d: i8085_ICount -= 5; /* DCR A */
+ M_DCR(I.AF.b.h);
+ break;
+ case 0x3e: i8085_ICount -= 7; /* MVI A,nn */
+ M_MVI(I.AF.b.h);
+ break;
+ case 0x3f: i8085_ICount -= 4; /* CMF */
+ I.AF.b.l = ((I.AF.b.l & ~(HF + NF)) |
+ ((I.AF.b.l & CF) << 4)) ^ CF;
+ break;
+
+ case 0x40: i8085_ICount -= 5; /* MOV B,B */
+ /* no op */
+ break;
+ case 0x41: i8085_ICount -= 5; /* MOV B,C */
+ I.BC.b.h = I.BC.b.l;
+ break;
+ case 0x42: i8085_ICount -= 5; /* MOV B,D */
+ I.BC.b.h = I.DE.b.h;
+ break;
+ case 0x43: i8085_ICount -= 5; /* MOV B,E */
+ I.BC.b.h = I.DE.b.l;
+ break;
+ case 0x44: i8085_ICount -= 5; /* MOV B,H */
+ I.BC.b.h = I.HL.b.h;
+ break;
+ case 0x45: i8085_ICount -= 5; /* MOV B,L */
+ I.BC.b.h = I.HL.b.l;
+ break;
+ case 0x46: i8085_ICount -= 7; /* MOV B,M */
+ I.BC.b.h = RM(I.HL.d);
+ break;
+ case 0x47: i8085_ICount -= 5; /* MOV B,A */
+ I.BC.b.h = I.AF.b.h;
+ break;
+
+ case 0x48: i8085_ICount -= 5; /* MOV C,B */
+ I.BC.b.l = I.BC.b.h;
+ break;
+ case 0x49: i8085_ICount -= 5; /* MOV C,C */
+ /* no op */
+ break;
+ case 0x4a: i8085_ICount -= 5; /* MOV C,D */
+ I.BC.b.l = I.DE.b.h;
+ break;
+ case 0x4b: i8085_ICount -= 5; /* MOV C,E */
+ I.BC.b.l = I.DE.b.l;
+ break;
+ case 0x4c: i8085_ICount -= 5; /* MOV C,H */
+ I.BC.b.l = I.HL.b.h;
+ break;
+ case 0x4d: i8085_ICount -= 5; /* MOV C,L */
+ I.BC.b.l = I.HL.b.l;
+ break;
+ case 0x4e: i8085_ICount -= 7; /* MOV C,M */
+ I.BC.b.l = RM(I.HL.d);
+ break;
+ case 0x4f: i8085_ICount -= 5; /* MOV C,A */
+ I.BC.b.l = I.AF.b.h;
+ break;
+
+ case 0x50: i8085_ICount -= 5; /* MOV D,B */
+ I.DE.b.h = I.BC.b.h;
+ break;
+ case 0x51: i8085_ICount -= 5; /* MOV D,C */
+ I.DE.b.h = I.BC.b.l;
+ break;
+ case 0x52: i8085_ICount -= 5; /* MOV D,D */
+ /* no op */
+ break;
+ case 0x53: i8085_ICount -= 5; /* MOV D,E */
+ I.DE.b.h = I.DE.b.l;
+ break;
+ case 0x54: i8085_ICount -= 5; /* MOV D,H */
+ I.DE.b.h = I.HL.b.h;
+ break;
+ case 0x55: i8085_ICount -= 5; /* MOV D,L */
+ I.DE.b.h = I.HL.b.l;
+ break;
+ case 0x56: i8085_ICount -= 7; /* MOV D,M */
+ I.DE.b.h = RM(I.HL.d);
+ break;
+ case 0x57: i8085_ICount -= 5; /* MOV D,A */
+ I.DE.b.h = I.AF.b.h;
+ break;
+
+ case 0x58: i8085_ICount -= 5; /* MOV E,B */
+ I.DE.b.l = I.BC.b.h;
+ break;
+ case 0x59: i8085_ICount -= 5; /* MOV E,C */
+ I.DE.b.l = I.BC.b.l;
+ break;
+ case 0x5a: i8085_ICount -= 5; /* MOV E,D */
+ I.DE.b.l = I.DE.b.h;
+ break;
+ case 0x5b: i8085_ICount -= 5; /* MOV E,E */
+ /* no op */
+ break;
+ case 0x5c: i8085_ICount -= 5; /* MOV E,H */
+ I.DE.b.l = I.HL.b.h;
+ break;
+ case 0x5d: i8085_ICount -= 5; /* MOV E,L */
+ I.DE.b.l = I.HL.b.l;
+ break;
+ case 0x5e: i8085_ICount -= 7; /* MOV E,M */
+ I.DE.b.l = RM(I.HL.d);
+ break;
+ case 0x5f: i8085_ICount -= 5; /* MOV E,A */
+ I.DE.b.l = I.AF.b.h;
+ break;
+
+ case 0x60: i8085_ICount -= 5; /* MOV H,B */
+ I.HL.b.h = I.BC.b.h;
+ break;
+ case 0x61: i8085_ICount -= 5; /* MOV H,C */
+ I.HL.b.h = I.BC.b.l;
+ break;
+ case 0x62: i8085_ICount -= 5; /* MOV H,D */
+ I.HL.b.h = I.DE.b.h;
+ break;
+ case 0x63: i8085_ICount -= 5; /* MOV H,E */
+ I.HL.b.h = I.DE.b.l;
+ break;
+ case 0x64: i8085_ICount -= 5; /* MOV H,H */
+ /* no op */
+ break;
+ case 0x65: i8085_ICount -= 5; /* MOV H,L */
+ I.HL.b.h = I.HL.b.l;
+ break;
+ case 0x66: i8085_ICount -= 7; /* MOV H,M */
+ I.HL.b.h = RM(I.HL.d);
+ break;
+ case 0x67: i8085_ICount -= 5; /* MOV H,A */
+ I.HL.b.h = I.AF.b.h;
+ break;
+
+ case 0x68: i8085_ICount -= 5; /* MOV L,B */
+ I.HL.b.l = I.BC.b.h;
+ break;
+ case 0x69: i8085_ICount -= 5; /* MOV L,C */
+ I.HL.b.l = I.BC.b.l;
+ break;
+ case 0x6a: i8085_ICount -= 5; /* MOV L,D */
+ I.HL.b.l = I.DE.b.h;
+ break;
+ case 0x6b: i8085_ICount -= 5; /* MOV L,E */
+ I.HL.b.l = I.DE.b.l;
+ break;
+ case 0x6c: i8085_ICount -= 5; /* MOV L,H */
+ I.HL.b.l = I.HL.b.h;
+ break;
+ case 0x6d: i8085_ICount -= 5; /* MOV L,L */
+ /* no op */
+ break;
+ case 0x6e: i8085_ICount -= 7; /* MOV L,M */
+ I.HL.b.l = RM(I.HL.d);
+ break;
+ case 0x6f: i8085_ICount -= 5; /* MOV L,A */
+ I.HL.b.l = I.AF.b.h;
+ break;
+
+ case 0x70: i8085_ICount -= 7; /* MOV M,B */
+ WM(I.HL.d, I.BC.b.h);
+ break;
+ case 0x71: i8085_ICount -= 7; /* MOV M,C */
+ WM(I.HL.d, I.BC.b.l);
+ break;
+ case 0x72: i8085_ICount -= 7; /* MOV M,D */
+ WM(I.HL.d, I.DE.b.h);
+ break;
+ case 0x73: i8085_ICount -= 7; /* MOV M,E */
+ WM(I.HL.d, I.DE.b.l);
+ break;
+ case 0x74: i8085_ICount -= 7; /* MOV M,H */
+ WM(I.HL.d, I.HL.b.h);
+ break;
+ case 0x75: i8085_ICount -= 7; /* MOV M,L */
+ WM(I.HL.d, I.HL.b.l);
+ break;
+ case 0x76: i8085_ICount -= 4; /* HALT */
+ I.PC.w.l--;
+ I.HALT = 1;
+ if (i8085_ICount > 0) i8085_ICount = 0;
+ break;
+ case 0x77: i8085_ICount -= 7; /* MOV M,A */
+ WM(I.HL.d, I.AF.b.h);
+ break;
+
+ case 0x78: i8085_ICount -= 5; /* MOV A,B */
+ I.AF.b.h = I.BC.b.h;
+ break;
+ case 0x79: i8085_ICount -= 5; /* MOV A,C */
+ I.AF.b.h = I.BC.b.l;
+ break;
+ case 0x7a: i8085_ICount -= 5; /* MOV A,D */
+ I.AF.b.h = I.DE.b.h;
+ break;
+ case 0x7b: i8085_ICount -= 5; /* MOV A,E */
+ I.AF.b.h = I.DE.b.l;
+ break;
+ case 0x7c: i8085_ICount -= 5; /* MOV A,H */
+ I.AF.b.h = I.HL.b.h;
+ break;
+ case 0x7d: i8085_ICount -= 5; /* MOV A,L */
+ I.AF.b.h = I.HL.b.l;
+ break;
+ case 0x7e: i8085_ICount -= 7; /* MOV A,M */
+ I.AF.b.h = RM(I.HL.d);
+ break;
+ case 0x7f: i8085_ICount -= 5; /* MOV A,A */
+ /* no op */
+ break;
+
+ case 0x80: i8085_ICount -= 4; /* ADD B */
+ M_ADD(I.BC.b.h);
+ break;
+ case 0x81: i8085_ICount -= 4; /* ADD C */
+ M_ADD(I.BC.b.l);
+ break;
+ case 0x82: i8085_ICount -= 4; /* ADD D */
+ M_ADD(I.DE.b.h);
+ break;
+ case 0x83: i8085_ICount -= 4; /* ADD E */
+ M_ADD(I.DE.b.l);
+ break;
+ case 0x84: i8085_ICount -= 4; /* ADD H */
+ M_ADD(I.HL.b.h);
+ break;
+ case 0x85: i8085_ICount -= 4; /* ADD L */
+ M_ADD(I.HL.b.l);
+ break;
+ case 0x86: i8085_ICount -= 7; /* ADD M */
+ M_ADD(RM(I.HL.d));
+ break;
+ case 0x87: i8085_ICount -= 4; /* ADD A */
+ M_ADD(I.AF.b.h);
+ break;
+
+ case 0x88: i8085_ICount -= 4; /* ADC B */
+ M_ADC(I.BC.b.h);
+ break;
+ case 0x89: i8085_ICount -= 4; /* ADC C */
+ M_ADC(I.BC.b.l);
+ break;
+ case 0x8a: i8085_ICount -= 4; /* ADC D */
+ M_ADC(I.DE.b.h);
+ break;
+ case 0x8b: i8085_ICount -= 4; /* ADC E */
+ M_ADC(I.DE.b.l);
+ break;
+ case 0x8c: i8085_ICount -= 4; /* ADC H */
+ M_ADC(I.HL.b.h);
+ break;
+ case 0x8d: i8085_ICount -= 4; /* ADC L */
+ M_ADC(I.HL.b.l);
+ break;
+ case 0x8e: i8085_ICount -= 7; /* ADC M */
+ M_ADC(RM(I.HL.d));
+ break;
+ case 0x8f: i8085_ICount -= 4; /* ADC A */
+ M_ADC(I.AF.b.h);
+ break;
+
+ case 0x90: i8085_ICount -= 4; /* SUB B */
+ M_SUB(I.BC.b.h);
+ break;
+ case 0x91: i8085_ICount -= 4; /* SUB C */
+ M_SUB(I.BC.b.l);
+ break;
+ case 0x92: i8085_ICount -= 4; /* SUB D */
+ M_SUB(I.DE.b.h);
+ break;
+ case 0x93: i8085_ICount -= 4; /* SUB E */
+ M_SUB(I.DE.b.l);
+ break;
+ case 0x94: i8085_ICount -= 4; /* SUB H */
+ M_SUB(I.HL.b.h);
+ break;
+ case 0x95: i8085_ICount -= 4; /* SUB L */
+ M_SUB(I.HL.b.l);
+ break;
+ case 0x96: i8085_ICount -= 7; /* SUB M */
+ M_SUB(RM(I.HL.d));
+ break;
+ case 0x97: i8085_ICount -= 4; /* SUB A */
+ M_SUB(I.AF.b.h);
+ break;
+
+ case 0x98: i8085_ICount -= 4; /* SBB B */
+ M_SBB(I.BC.b.h);
+ break;
+ case 0x99: i8085_ICount -= 4; /* SBB C */
+ M_SBB(I.BC.b.l);
+ break;
+ case 0x9a: i8085_ICount -= 4; /* SBB D */
+ M_SBB(I.DE.b.h);
+ break;
+ case 0x9b: i8085_ICount -= 4; /* SBB E */
+ M_SBB(I.DE.b.l);
+ break;
+ case 0x9c: i8085_ICount -= 4; /* SBB H */
+ M_SBB(I.HL.b.h);
+ break;
+ case 0x9d: i8085_ICount -= 4; /* SBB L */
+ M_SBB(I.HL.b.l);
+ break;
+ case 0x9e: i8085_ICount -= 7; /* SBB M */
+ M_SBB(RM(I.HL.d));
+ break;
+ case 0x9f: i8085_ICount -= 4; /* SBB A */
+ M_SBB(I.AF.b.h);
+ break;
+
+ case 0xa0: i8085_ICount -= 4; /* ANA B */
+ M_ANA(I.BC.b.h);
+ break;
+ case 0xa1: i8085_ICount -= 4; /* ANA C */
+ M_ANA(I.BC.b.l);
+ break;
+ case 0xa2: i8085_ICount -= 4; /* ANA D */
+ M_ANA(I.DE.b.h);
+ break;
+ case 0xa3: i8085_ICount -= 4; /* ANA E */
+ M_ANA(I.DE.b.l);
+ break;
+ case 0xa4: i8085_ICount -= 4; /* ANA H */
+ M_ANA(I.HL.b.h);
+ break;
+ case 0xa5: i8085_ICount -= 4; /* ANA L */
+ M_ANA(I.HL.b.l);
+ break;
+ case 0xa6: i8085_ICount -= 7; /* ANA M */
+ M_ANA(RM(I.HL.d));
+ break;
+ case 0xa7: i8085_ICount -= 4; /* ANA A */
+ M_ANA(I.AF.b.h);
+ break;
+
+ case 0xa8: i8085_ICount -= 4; /* XRA B */
+ M_XRA(I.BC.b.h);
+ break;
+ case 0xa9: i8085_ICount -= 4; /* XRA C */
+ M_XRA(I.BC.b.l);
+ break;
+ case 0xaa: i8085_ICount -= 4; /* XRA D */
+ M_XRA(I.DE.b.h);
+ break;
+ case 0xab: i8085_ICount -= 4; /* XRA E */
+ M_XRA(I.DE.b.l);
+ break;
+ case 0xac: i8085_ICount -= 4; /* XRA H */
+ M_XRA(I.HL.b.h);
+ break;
+ case 0xad: i8085_ICount -= 4; /* XRA L */
+ M_XRA(I.HL.b.l);
+ break;
+ case 0xae: i8085_ICount -= 7; /* XRA M */
+ M_XRA(RM(I.HL.d));
+ break;
+ case 0xaf: i8085_ICount -= 4; /* XRA A */
+ M_XRA(I.AF.b.h);
+ break;
+
+ case 0xb0: i8085_ICount -= 4; /* ORA B */
+ M_ORA(I.BC.b.h);
+ break;
+ case 0xb1: i8085_ICount -= 4; /* ORA C */
+ M_ORA(I.BC.b.l);
+ break;
+ case 0xb2: i8085_ICount -= 4; /* ORA D */
+ M_ORA(I.DE.b.h);
+ break;
+ case 0xb3: i8085_ICount -= 4; /* ORA E */
+ M_ORA(I.DE.b.l);
+ break;
+ case 0xb4: i8085_ICount -= 4; /* ORA H */
+ M_ORA(I.HL.b.h);
+ break;
+ case 0xb5: i8085_ICount -= 4; /* ORA L */
+ M_ORA(I.HL.b.l);
+ break;
+ case 0xb6: i8085_ICount -= 7; /* ORA M */
+ M_ORA(RM(I.HL.d));
+ break;
+ case 0xb7: i8085_ICount -= 4; /* ORA A */
+ M_ORA(I.AF.b.h);
+ break;
+
+ case 0xb8: i8085_ICount -= 4; /* CMP B */
+ M_CMP(I.BC.b.h);
+ break;
+ case 0xb9: i8085_ICount -= 4; /* CMP C */
+ M_CMP(I.BC.b.l);
+ break;
+ case 0xba: i8085_ICount -= 4; /* CMP D */
+ M_CMP(I.DE.b.h);
+ break;
+ case 0xbb: i8085_ICount -= 4; /* CMP E */
+ M_CMP(I.DE.b.l);
+ break;
+ case 0xbc: i8085_ICount -= 4; /* CMP H */
+ M_CMP(I.HL.b.h);
+ break;
+ case 0xbd: i8085_ICount -= 4; /* CMP L */
+ M_CMP(I.HL.b.l);
+ break;
+ case 0xbe: i8085_ICount -= 7; /* CMP M */
+ M_CMP(RM(I.HL.d));
+ break;
+ case 0xbf: i8085_ICount -= 4; /* CMP A */
+ M_CMP(I.AF.b.h);
+ break;
+
+ case 0xc0: i8085_ICount -= 5; /* RNZ */
+ M_RET( !(I.AF.b.l & ZF) );
+ break;
+ case 0xc1: i8085_ICount -= 10; /* POP B */
+ M_POP(BC);
+ break;
+ case 0xc2: i8085_ICount -= 7; /* JNZ nnnn */
+ M_JMP( !(I.AF.b.l & ZF) );
+ break;
+ case 0xc3: i8085_ICount -= 7; /* JMP nnnn */
+ M_JMP(1);
+ break;
+ case 0xc4: i8085_ICount -= 11; /* CNZ nnnn */
+ M_CALL( !(I.AF.b.l & ZF) );
+ break;
+ case 0xc5: i8085_ICount -= 11; /* PUSH B */
+ M_PUSH(BC);
+ break;
+ case 0xc6: i8085_ICount -= 7; /* ADI nn */
+ I.XX.b.l = ARG();
+ M_ADD(I.XX.b.l);
+ break;
+ case 0xc7: i8085_ICount -= 11; /* RST 0 */
+ M_RST(0);
+ break;
+
+ case 0xc8: i8085_ICount -= 5; /* RZ */
+ M_RET( I.AF.b.l & ZF );
+ break;
+ case 0xc9: i8085_ICount -= 4; /* RET */
+ M_RET(1);
+ break;
+ case 0xca: i8085_ICount -= 7; /* JZ nnnn */
+ M_JMP( I.AF.b.l & ZF );
+ break;
+ case 0xcb:
+ if( I.cputype ) {
+ if (I.AF.b.l & VF) {
+ i8085_ICount -= 12;
+ M_RST(8); /* call 0x40 */
+ } else {
+ i8085_ICount -= 6; /* RST V */
+ }
+ } else {
+ i8085_ICount -= 7; /* JMP nnnn undocumented*/
+ M_JMP(1);
+ }
+ break;
+ case 0xcc: i8085_ICount -= 11; /* CZ nnnn */
+ M_CALL( I.AF.b.l & ZF );
+ break;
+ case 0xcd: i8085_ICount -= 11; /* CALL nnnn */
+ M_CALL(1);
+ break;
+ case 0xce: i8085_ICount -= 7; /* ACI nn */
+ I.XX.b.l = ARG();
+ M_ADC(I.XX.b.l);
+ break;
+ case 0xcf: i8085_ICount -= 11; /* RST 1 */
+ M_RST(1);
+ break;
+
+ case 0xd0: i8085_ICount -= 5; /* RNC */
+ M_RET( !(I.AF.b.l & CF) );
+ break;
+ case 0xd1: i8085_ICount -= 10; /* POP D */
+ M_POP(DE);
+ break;
+ case 0xd2: i8085_ICount -= 7; /* JNC nnnn */
+ M_JMP( !(I.AF.b.l & CF) );
+ break;
+ case 0xd3: i8085_ICount -= 10; /* OUT nn */
+ M_OUT;
+ break;
+ case 0xd4: i8085_ICount -= 11; /* CNC nnnn */
+ M_CALL( !(I.AF.b.l & CF) );
+ break;
+ case 0xd5: i8085_ICount -= 11; /* PUSH D */
+ M_PUSH(DE);
+ break;
+ case 0xd6: i8085_ICount -= 7; /* SUI nn */
+ I.XX.b.l = ARG();
+ M_SUB(I.XX.b.l);
+ break;
+ case 0xd7: i8085_ICount -= 11; /* RST 2 */
+ M_RST(2);
+ break;
+
+ case 0xd8: i8085_ICount -= 5; /* RC */
+ M_RET( I.AF.b.l & CF );
+ break;
+ case 0xd9:
+ if( I.cputype ) {
+ i8085_ICount -= 10; /* SHLX */
+ I.XX.w.l = I.DE.w.l;
+ WM(I.XX.d, I.HL.b.l);
+ I.XX.w.l++;
+ WM(I.XX.d, I.HL.b.h);
+ } else {
+ i8085_ICount -= 4; /* RET undocumented */
+ M_RET(1);
+ }
+ break;
+ case 0xda: i8085_ICount -= 7; /* JC nnnn */
+ M_JMP( I.AF.b.l & CF );
+ break;
+ case 0xdb: i8085_ICount -= 10; /* IN nn */
+ M_IN;
+ break;
+ case 0xdc: i8085_ICount -= 11; /* CC nnnn */
+ M_CALL( I.AF.b.l & CF );
+ break;
+ case 0xdd:
+ if( I.cputype ) {
+ i8085_ICount -= 7; /* JNX nnnn */
+ M_JMP( !(I.AF.b.l & XF) );
+ } else {
+ i8085_ICount -= 11; /* CALL nnnn undocumented */
+ M_CALL(1);
+ }
+ break;
+ case 0xde: i8085_ICount -= 7; /* SBI nn */
+ I.XX.b.l = ARG();
+ M_SBB(I.XX.b.l);
+ break;
+ case 0xdf: i8085_ICount -= 11; /* RST 3 */
+ M_RST(3);
+ break;
+
+ case 0xe0: i8085_ICount -= 5; /* RPO */
+ M_RET( !(I.AF.b.l & VF) );
+ break;
+ case 0xe1: i8085_ICount -= 10; /* POP H */
+ M_POP(HL);
+ break;
+ case 0xe2: i8085_ICount -= 7; /* JPO nnnn */
+ M_JMP( !(I.AF.b.l & VF) );
+ break;
+ case 0xe3: i8085_ICount -= 18; /* XTHL */
+ M_POP(XX);
+ M_PUSH(HL);
+ I.HL.d = I.XX.d;
+ break;
+ case 0xe4: i8085_ICount -= 11; /* CPO nnnn */
+ M_CALL( !(I.AF.b.l & VF) );
+ break;
+ case 0xe5: i8085_ICount -= 11; /* PUSH H */
+ M_PUSH(HL);
+ break;
+ case 0xe6: i8085_ICount -= 7; /* ANI nn */
+ I.XX.b.l = ARG();
+ M_ANA(I.XX.b.l);
+ break;
+ case 0xe7: i8085_ICount -= 11; /* RST 4 */
+ M_RST(4);
+ break;
+
+ case 0xe8: i8085_ICount -= 5; /* RPE */
+ M_RET( I.AF.b.l & VF );
+ break;
+ case 0xe9: i8085_ICount -= 5; /* PCHL */
+ I.PC.d = I.HL.w.l;
+ change_pc(I.PC.d);
+ break;
+ case 0xea: i8085_ICount -= 7; /* JPE nnnn */
+ M_JMP( I.AF.b.l & VF );
+ break;
+ case 0xeb: i8085_ICount -= 4; /* XCHG */
+ I.XX.d = I.DE.d;
+ I.DE.d = I.HL.d;
+ I.HL.d = I.XX.d;
+ break;
+ case 0xec: i8085_ICount -= 11; /* CPE nnnn */
+ M_CALL( I.AF.b.l & VF );
+ break;
+ case 0xed:
+ if( I.cputype ) {
+ i8085_ICount -= 10; /* LHLX */
+ I.XX.w.l = I.DE.w.l;
+ I.HL.b.l = RM(I.XX.d);
+ I.XX.w.l++;
+ I.HL.b.h = RM(I.XX.d);
+ } else {
+ i8085_ICount -= 11; /* CALL nnnn undocumented */
+ M_CALL(1);
+ }
+ break;
+ case 0xee: i8085_ICount -= 7; /* XRI nn */
+ I.XX.b.l = ARG();
+ M_XRA(I.XX.b.l);
+ break;
+ case 0xef: i8085_ICount -= 11; /* RST 5 */
+ M_RST(5);
+ break;
+
+ case 0xf0: i8085_ICount -= 5; /* RP */
+ M_RET( !(I.AF.b.l&SF) );
+ break;
+ case 0xf1: i8085_ICount -= 10; /* POP A */
+ M_POP(AF);
+ break;
+ case 0xf2: i8085_ICount -= 7; /* JP nnnn */
+ M_JMP( !(I.AF.b.l & SF) );
+ break;
+ case 0xf3: i8085_ICount -= 4; /* DI */
+ /* remove interrupt enable */
+ I.IM &= ~IM_IEN;
+ break;
+ case 0xf4: i8085_ICount -= 11; /* CP nnnn */
+ M_CALL( !(I.AF.b.l & SF) );
+ break;
+ case 0xf5: i8085_ICount -= 11; /* PUSH A */
+ M_PUSH(AF);
+ break;
+ case 0xf6: i8085_ICount -= 7; /* ORI nn */
+ I.XX.b.l = ARG();
+ M_ORA(I.XX.b.l);
+ break;
+ case 0xf7: i8085_ICount -= 11; /* RST 6 */
+ M_RST(6);
+ break;
+
+ case 0xf8: i8085_ICount -= 5; /* RM */
+ M_RET( I.AF.b.l & SF );
+ break;
+ case 0xf9: i8085_ICount -= 5; /* SPHL */
+ I.SP.d = I.HL.d;
+ break;
+ case 0xfa: i8085_ICount -= 7; /* JM nnnn */
+ M_JMP( I.AF.b.l & SF );
+ break;
+ case 0xfb: i8085_ICount -= 4; /* EI */
+ /* set interrupt enable */
+ I.IM |= IM_IEN;
+ /* remove serviced IRQ flag */
+ I.IREQ &= ~I.ISRV;
+ /* reset serviced IRQ */
+ I.ISRV = 0;
+ if( I.irq_state[0] != CLEAR_LINE ) {
+ LOG(("i8085 EI sets INTR\n"));
+ I.IREQ |= IM_INTR;
+ I.INTR = I8085_INTR;
+ }
+ if( I.cputype ) {
+ if( I.irq_state[1] != CLEAR_LINE ) {
+ LOG(("i8085 EI sets RST5.5\n"));
+ I.IREQ |= IM_RST55;
+ }
+ if( I.irq_state[2] != CLEAR_LINE ) {
+ LOG(("i8085 EI sets RST6.5\n"));
+ I.IREQ |= IM_RST65;
+ }
+ if( I.irq_state[3] != CLEAR_LINE ) {
+ LOG(("i8085 EI sets RST7.5\n"));
+ I.IREQ |= IM_RST75;
+ }
+ /* find highest priority IREQ flag with
+ IM enabled and schedule for execution */
+ if( !(I.IM & IM_RST75) && (I.IREQ & IM_RST75) ) {
+ I.ISRV = IM_RST75;
+ I.IRQ2 = ADDR_RST75;
+ }
+ else
+ if( !(I.IM & IM_RST65) && (I.IREQ & IM_RST65) ) {
+ I.ISRV = IM_RST65;
+ I.IRQ2 = ADDR_RST65;
+ } else if( !(I.IM & IM_RST55) && (I.IREQ & IM_RST55) ) {
+ I.ISRV = IM_RST55;
+ I.IRQ2 = ADDR_RST55;
+ } else if( !(I.IM & IM_INTR) && (I.IREQ & IM_INTR) ) {
+ I.ISRV = IM_INTR;
+ I.IRQ2 = I.INTR;
+ }
+ } else {
+ if( !(I.IM & IM_INTR) && (I.IREQ & IM_INTR) ) {
+ I.ISRV = IM_INTR;
+ I.IRQ2 = I.INTR;
+ }
+ }
+ break;
+ case 0xfc: i8085_ICount -= 11; /* CM nnnn */
+ M_CALL( I.AF.b.l & SF );
+ break;
+ case 0xfd:
+ if( I.cputype ) {
+ i8085_ICount -= 7; /* JX nnnn */
+ M_JMP( I.AF.b.l & XF );
+ } else {
+ i8085_ICount -= 11; /* CALL nnnn undocumented */
+ M_CALL(1);
+ }
+ break;
+ case 0xfe: i8085_ICount -= 7; /* CPI nn */
+ I.XX.b.l = ARG();
+ M_CMP(I.XX.b.l);
+ break;
+ case 0xff: i8085_ICount -= 11; /* RST 7 */
+ M_RST(7);
+ break;
+ }
+}
+
+static void Interrupt(void)
+{
+
+ if( I.HALT ) /* if the CPU was halted */
+ {
+ I.PC.w.l++; /* skip HALT instr */
+ I.HALT = 0;
+ }
+//AT
+ I.IREQ &= ~I.ISRV; // remove serviced IRQ flag
+ RIM_IEN = (I.ISRV==IM_TRAP) ? I.IM & IM_IEN : 0; // latch general interrupt enable bit on TRAP or NMI
+//ZT
+ I.IM &= ~IM_IEN; /* remove general interrupt enable bit */
+
+ if( I.ISRV == IM_INTR )
+ {
+ LOG(("Interrupt get INTR vector\n"));
+ I.IRQ1 = (I.irq_callback)(0);
+ }
+
+ if( I.cputype )
+ {
+ if( I.ISRV == IM_RST55 )
+ {
+ LOG(("Interrupt get RST5.5 vector\n"));
+ //I.IRQ1 = (I.irq_callback)(1);
+ I.irq_state[I8085_RST55_LINE] = CLEAR_LINE; //AT: processing RST5.5, reset interrupt line
+ }
+
+ if( I.ISRV == IM_RST65 )
+ {
+ LOG(("Interrupt get RST6.5 vector\n"));
+ //I.IRQ1 = (I.irq_callback)(2);
+ I.irq_state[I8085_RST65_LINE] = CLEAR_LINE; //AT: processing RST6.5, reset interrupt line
+ }
+
+ if( I.ISRV == IM_RST75 )
+ {
+ LOG(("Interrupt get RST7.5 vector\n"));
+ //I.IRQ1 = (I.irq_callback)(3);
+ I.irq_state[I8085_RST75_LINE] = CLEAR_LINE; //AT: processing RST7.5, reset interrupt line
+ }
+ }
+
+ switch( I.IRQ1 & 0xff0000 )
+ {
+ case 0xcd0000: /* CALL nnnn */
+ i8085_ICount -= 7;
+ M_PUSH(PC);
+ case 0xc30000: /* JMP nnnn */
+ i8085_ICount -= 10;
+ I.PC.d = I.IRQ1 & 0xffff;
+ change_pc(I.PC.d);
+ break;
+ default:
+ switch( I.ISRV )
+ {
+ case IM_TRAP:
+ case IM_RST75:
+ case IM_RST65:
+ case IM_RST55:
+ M_PUSH(PC);
+ if (I.IRQ1 != (1 << I8085_RST75_LINE))
+ I.PC.d = I.IRQ1;
+ else
+ I.PC.d = 0x3c;
+ change_pc(I.PC.d);
+ break;
+ default:
+ LOG(("i8085 take int $%02x\n", I.IRQ1));
+ execute_one(I.IRQ1 & 0xff);
+ }
+ }
+}
+
+int i8085_execute(int cycles)
+{
+
+ i8085_ICount = cycles;
+ do
+ {
+ CALL_MAME_DEBUG;
+ /* interrupts enabled or TRAP pending ? */
+ if ( (I.IM & IM_IEN) || (I.IREQ & IM_TRAP) )
+ {
+ /* copy scheduled to executed interrupt request */
+ I.IRQ1 = I.IRQ2;
+ /* reset scheduled interrupt request */
+ I.IRQ2 = 0;
+ /* interrupt now ? */
+ if (I.IRQ1) Interrupt();
+ }
+
+ /* here we go... */
+ execute_one(ROP());
+
+ } while (i8085_ICount > 0);
+
+ return cycles - i8085_ICount;
+}
+
+/****************************************************************************
+ * Initialise the various lookup tables used by the emulation code
+ ****************************************************************************/
+static void init_tables (void)
+{
+ UINT8 zs;
+ int i, p;
+ for (i = 0; i < 256; i++)
+ {
+ zs = 0;
+ if (i==0) zs |= ZF;
+ if (i&128) zs |= SF;
+ p = 0;
+ if (i&1) ++p;
+ if (i&2) ++p;
+ if (i&4) ++p;
+ if (i&8) ++p;
+ if (i&16) ++p;
+ if (i&32) ++p;
+ if (i&64) ++p;
+ if (i&128) ++p;
+ ZS[i] = zs;
+ ZSP[i] = zs | ((p&1) ? 0 : VF);
+ }
+}
+
+/****************************************************************************
+ * Init the 8085 emulation
+ ****************************************************************************/
+static void i8085_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ init_tables();
+ I.cputype = 1;
+ I.irq_callback = irqcallback;
+
+ state_save_register_item("i8085", index, I.AF.w.l);
+ state_save_register_item("i8085", index, I.BC.w.l);
+ state_save_register_item("i8085", index, I.DE.w.l);
+ state_save_register_item("i8085", index, I.HL.w.l);
+ state_save_register_item("i8085", index, I.SP.w.l);
+ state_save_register_item("i8085", index, I.PC.w.l);
+ state_save_register_item("i8085", index, I.HALT);
+ state_save_register_item("i8085", index, I.IM);
+ state_save_register_item("i8085", index, I.IREQ);
+ state_save_register_item("i8085", index, I.ISRV);
+ state_save_register_item("i8085", index, I.INTR);
+ state_save_register_item("i8085", index, I.IRQ2);
+ state_save_register_item("i8085", index, I.IRQ1);
+ state_save_register_item_array("i8085", index, I.irq_state);
+}
+
+/****************************************************************************
+ * Reset the 8085 emulation
+ ****************************************************************************/
+static void i8085_reset(void)
+{
+ int (*save_irqcallback)(int);
+ int cputype_bak = I.cputype;
+
+ init_tables();
+ save_irqcallback = I.irq_callback;
+ memset(&I, 0, sizeof(i8085_Regs));
+ I.irq_callback = save_irqcallback;
+ change_pc(I.PC.d);
+
+ I.cputype = cputype_bak;
+}
+
+/****************************************************************************
+ * Shut down the CPU emulation
+ ****************************************************************************/
+static void i8085_exit(void)
+{
+ /* nothing to do */
+}
+
+/****************************************************************************
+ * Get the current 8085 context
+ ****************************************************************************/
+static void i8085_get_context(void *dst)
+{
+ if( dst )
+ *(i8085_Regs*)dst = I;
+}
+
+/****************************************************************************
+ * Set the current 8085 context
+ ****************************************************************************/
+static void i8085_set_context(void *src)
+{
+ if( src )
+ {
+ I = *(i8085_Regs*)src;
+ change_pc(I.PC.d);
+ }
+}
+
+/****************************************************************************/
+/* Set TRAP signal state */
+/****************************************************************************/
+static void i8085_set_TRAP(int state)
+{
+ LOG(("i8085: TRAP %d\n", state));
+ if (state)
+ {
+ I.IREQ |= IM_TRAP;
+ if( I.ISRV & IM_TRAP ) return; /* already servicing TRAP ? */
+ I.ISRV = IM_TRAP; /* service TRAP */
+ I.IRQ2 = ADDR_TRAP;
+ }
+ else
+ {
+ I.IREQ &= ~IM_TRAP; /* remove request for TRAP */
+ }
+}
+
+/****************************************************************************/
+/* Set RST7.5 signal state */
+/****************************************************************************/
+static void i8085_set_RST75(int state)
+{
+ LOG(("i8085: RST7.5 %d\n", state));
+ if( state )
+ {
+
+ I.IREQ |= IM_RST75; /* request RST7.5 */
+ if( I.IM & IM_RST75 ) return; /* if masked, ignore it for now */
+ if( !I.ISRV ) /* if no higher priority IREQ is serviced */
+ {
+ I.ISRV = IM_RST75; /* service RST7.5 */
+ I.IRQ2 = ADDR_RST75;
+ }
+ }
+ /* RST7.5 is reset only by SIM or end of service routine ! */
+}
+
+/****************************************************************************/
+/* Set RST6.5 signal state */
+/****************************************************************************/
+static void i8085_set_RST65(int state)
+{
+ LOG(("i8085: RST6.5 %d\n", state));
+ if( state )
+ {
+ I.IREQ |= IM_RST65; /* request RST6.5 */
+ if( I.IM & IM_RST65 ) return; /* if masked, ignore it for now */
+ if( !I.ISRV ) /* if no higher priority IREQ is serviced */
+ {
+ I.ISRV = IM_RST65; /* service RST6.5 */
+ I.IRQ2 = ADDR_RST65;
+ }
+ }
+ else
+ {
+ I.IREQ &= ~IM_RST65; /* remove request for RST6.5 */
+ }
+}
+
+/****************************************************************************/
+/* Set RST5.5 signal state */
+/****************************************************************************/
+static void i8085_set_RST55(int state)
+{
+ LOG(("i8085: RST5.5 %d\n", state));
+ if( state )
+ {
+ I.IREQ |= IM_RST55; /* request RST5.5 */
+ if( I.IM & IM_RST55 ) return; /* if masked, ignore it for now */
+ if( !I.ISRV ) /* if no higher priority IREQ is serviced */
+ {
+ I.ISRV = IM_RST55; /* service RST5.5 */
+ I.IRQ2 = ADDR_RST55;
+ }
+ }
+ else
+ {
+ I.IREQ &= ~IM_RST55; /* remove request for RST5.5 */
+ }
+}
+
+/****************************************************************************/
+/* Set INTR signal */
+/****************************************************************************/
+static void i8085_set_INTR(int state)
+{
+ LOG(("i8085: INTR %d\n", state));
+ if( state )
+ {
+ I.IREQ |= IM_INTR; /* request INTR */
+ //I.INTR = state;
+ I.INTR = I8085_INTR; //AT: I.INTR is supposed to hold IRQ0 vector(0x38) (0xff in this implementation)
+ if( I.IM & IM_INTR ) return; /* if masked, ignore it for now */
+ if( !I.ISRV ) /* if no higher priority IREQ is serviced */
+ {
+ I.ISRV = IM_INTR; /* service INTR */
+ I.IRQ2 = I.INTR;
+ }
+ }
+ else
+ {
+ I.IREQ &= ~IM_INTR; /* remove request for INTR */
+ }
+}
+
+static void i8085_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if( state != CLEAR_LINE )
+ i8085_set_TRAP(1);
+ }
+ else if (irqline < 4)
+ {
+ I.irq_state[irqline] = state;
+ if (state == CLEAR_LINE)
+ {
+ if( !(I.IM & IM_IEN) )
+ {
+ switch (irqline)
+ {
+ case I8085_INTR_LINE: i8085_set_INTR(0); break;
+ case I8085_RST55_LINE: i8085_set_RST55(0); break;
+ case I8085_RST65_LINE: i8085_set_RST65(0); break;
+ case I8085_RST75_LINE: i8085_set_RST75(0); break;
+ }
+ }
+ }
+ else
+ {
+ if( I.IM & IM_IEN )
+ {
+ switch( irqline )
+ {
+ case I8085_INTR_LINE: i8085_set_INTR(1); break;
+ case I8085_RST55_LINE: i8085_set_RST55(1); break;
+ case I8085_RST65_LINE: i8085_set_RST65(1); break;
+ case I8085_RST75_LINE: i8085_set_RST75(1); break;
+ }
+ }
+ }
+ }
+}
+
+
+/**************************************************************************
+ * 8080 section
+ **************************************************************************/
+#if (HAS_8080)
+
+void i8080_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ init_tables();
+ I.cputype = 0;
+ I.irq_callback = irqcallback;
+
+ state_save_register_item("i8080", index, I.AF.w.l);
+ state_save_register_item("i8080", index, I.BC.w.l);
+ state_save_register_item("i8080", index, I.DE.w.l);
+ state_save_register_item("i8080", index, I.HL.w.l);
+ state_save_register_item("i8080", index, I.SP.w.l);
+ state_save_register_item("i8080", index, I.PC.w.l);
+ state_save_register_item("i8080", index, I.HALT);
+ state_save_register_item("i8085", index, I.IM);
+ state_save_register_item("i8080", index, I.IREQ);
+ state_save_register_item("i8080", index, I.ISRV);
+ state_save_register_item("i8080", index, I.INTR);
+ state_save_register_item("i8080", index, I.IRQ2);
+ state_save_register_item("i8080", index, I.IRQ1);
+ state_save_register_item_array("i8080", index, I.irq_state);
+}
+
+void i8080_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if( state != CLEAR_LINE )
+ i8085_set_TRAP(1);
+ }
+ else
+ {
+ I.irq_state[irqline] = state;
+ if (state == CLEAR_LINE)
+ {
+ if (!(I.IM & IM_IEN))
+ i8085_set_INTR(0);
+ }
+ else
+ {
+ if (I.IM & IM_IEN)
+ i8085_set_INTR(1);
+ }
+ }
+}
+#endif
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void i8085_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + I8085_INTR_LINE: i8085_set_irq_line(I8085_INTR_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8085_RST55_LINE:i8085_set_irq_line(I8085_RST55_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8085_RST65_LINE:i8085_set_irq_line(I8085_RST65_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8085_RST75_LINE:i8085_set_irq_line(I8085_RST75_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: i8085_set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC: I.PC.w.l = info->i; change_pc(I.PC.d); break;
+ case CPUINFO_INT_REGISTER + I8085_PC: I.PC.w.l = info->i; break;
+ case CPUINFO_INT_SP: I.SP.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_SP: I.SP.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_AF: I.AF.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_BC: I.BC.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_DE: I.DE.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_HL: I.HL.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_IM: I.IM = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_HALT: I.HALT = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_IREQ: I.IREQ = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_ISRV: I.ISRV = info->i; break;
+ case CPUINFO_INT_REGISTER + I8085_VECTOR: I.INTR = info->i; break;
+
+ case CPUINFO_INT_I8085_SID: if (info->i) I.IM |= IM_SID; else I.IM &= ~IM_SID; break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_I8085_SOD_CALLBACK: I.sod_callback = (void (*)(int))info->f; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void i8085_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(I); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 4; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 4; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 16; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + I8085_INTR_LINE: info->i = (I.IREQ & IM_INTR) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + I8085_RST55_LINE:info->i = (I.IREQ & IM_RST55) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + I8085_RST65_LINE:info->i = (I.IREQ & IM_RST65) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + I8085_RST75_LINE:info->i = (I.IREQ & IM_RST75) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = (I.IREQ & IM_TRAP) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not supported */ break;
+
+ case CPUINFO_INT_PC: info->i = I.PC.d; break;
+ case CPUINFO_INT_REGISTER + I8085_PC: info->i = I.PC.w.l; break;
+ case CPUINFO_INT_SP: info->i = I.SP.d; break;
+ case CPUINFO_INT_REGISTER + I8085_SP: info->i = I.SP.w.l; break;
+ case CPUINFO_INT_REGISTER + I8085_AF: info->i = I.AF.w.l; break;
+ case CPUINFO_INT_REGISTER + I8085_BC: info->i = I.BC.w.l; break;
+ case CPUINFO_INT_REGISTER + I8085_DE: info->i = I.DE.w.l; break;
+ case CPUINFO_INT_REGISTER + I8085_HL: info->i = I.HL.w.l; break;
+ case CPUINFO_INT_REGISTER + I8085_IM: info->i = I.IM; break;
+ case CPUINFO_INT_REGISTER + I8085_HALT: info->i = I.HALT; break;
+ case CPUINFO_INT_REGISTER + I8085_IREQ: info->i = I.IREQ; break;
+ case CPUINFO_INT_REGISTER + I8085_ISRV: info->i = I.ISRV; break;
+ case CPUINFO_INT_REGISTER + I8085_VECTOR: info->i = I.INTR; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i8085_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8085_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8085_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8085_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8085_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8085_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8085_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = i8085_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i8085_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "8085A"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel 8080"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.1"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 1999 Juergen Buchmueller, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ I.AF.b.l & 0x80 ? 'S':'.',
+ I.AF.b.l & 0x40 ? 'Z':'.',
+ I.AF.b.l & 0x20 ? '?':'.',
+ I.AF.b.l & 0x10 ? 'H':'.',
+ I.AF.b.l & 0x08 ? '?':'.',
+ I.AF.b.l & 0x04 ? 'P':'.',
+ I.AF.b.l & 0x02 ? 'N':'.',
+ I.AF.b.l & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + I8085_AF: sprintf(info->s, "AF:%04X", I.AF.w.l); break;
+ case CPUINFO_STR_REGISTER + I8085_BC: sprintf(info->s, "BC:%04X", I.BC.w.l); break;
+ case CPUINFO_STR_REGISTER + I8085_DE: sprintf(info->s, "DE:%04X", I.DE.w.l); break;
+ case CPUINFO_STR_REGISTER + I8085_HL: sprintf(info->s, "HL:%04X", I.HL.w.l); break;
+ case CPUINFO_STR_REGISTER + I8085_SP: sprintf(info->s, "SP:%04X", I.SP.w.l); break;
+ case CPUINFO_STR_REGISTER + I8085_PC: sprintf(info->s, "PC:%04X", I.PC.w.l); break;
+ case CPUINFO_STR_REGISTER + I8085_IM: sprintf(info->s, "IM:%02X", I.IM); break;
+ case CPUINFO_STR_REGISTER + I8085_HALT: sprintf(info->s, "HALT:%d", I.HALT); break;
+ case CPUINFO_STR_REGISTER + I8085_IREQ: sprintf(info->s, "IREQ:%02X", I.IREQ); break;
+ case CPUINFO_STR_REGISTER + I8085_ISRV: sprintf(info->s, "ISRV:%02X", I.ISRV); break;
+ case CPUINFO_STR_REGISTER + I8085_VECTOR: sprintf(info->s, "VEC:%02X", I.INTR); break;
+ }
+}
+
+
+#if (HAS_8080)
+/**************************************************************************
+ * CPU-specific get_info/set_info
+ **************************************************************************/
+
+static void i8080_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + I8080_INTR_LINE: i8080_set_irq_line(I8080_INTR_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: i8080_set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ default: i8085_set_info(state, info); break;
+ }
+}
+
+void i8080_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_INPUT_STATE + I8085_INTR_LINE: info->i = (I.IREQ & IM_INTR) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = (I.IREQ & IM_TRAP) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i8080_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = i8080_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "8080"); break;
+
+ default: i8085_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/i8085/i8085.h b/src/emu/cpu/i8085/i8085.h
new file mode 100644
index 00000000000..f364218e32e
--- /dev/null
+++ b/src/emu/cpu/i8085/i8085.h
@@ -0,0 +1,57 @@
+#ifndef I8085_H
+#define I8085_H
+
+#include "cpuintrf.h"
+
+enum {
+ I8085_PC=1, I8085_SP, I8085_AF ,I8085_BC, I8085_DE, I8085_HL,
+ I8085_HALT, I8085_IM, I8085_IREQ, I8085_ISRV, I8085_VECTOR,
+ I8085_TRAP_STATE, I8085_INTR_STATE,
+ I8085_RST55_STATE, I8085_RST65_STATE, I8085_RST75_STATE};
+
+enum
+{
+ CPUINFO_PTR_I8085_SOD_CALLBACK = CPUINFO_PTR_CPU_SPECIFIC,
+ CPUINFO_INT_I8085_SID = CPUINFO_INT_CPU_SPECIFIC
+};
+
+#define I8085_INTR_LINE 0
+#define I8085_RST55_LINE 1
+#define I8085_RST65_LINE 2
+#define I8085_RST75_LINE 3
+
+void i8085_get_info(UINT32 state, cpuinfo *info);
+
+/**************************************************************************
+ * I8080 section
+ **************************************************************************/
+#if (HAS_8080)
+#define I8080_PC I8085_PC
+#define I8080_SP I8085_SP
+#define I8080_BC I8085_BC
+#define I8080_DE I8085_DE
+#define I8080_HL I8085_HL
+#define I8080_AF I8085_AF
+#define I8080_HALT I8085_HALT
+#define I8080_IREQ I8085_IREQ
+#define I8080_ISRV I8085_ISRV
+#define I8080_VECTOR I8085_VECTOR
+#define I8080_TRAP_STATE I8085_TRAP_STATE
+#define I8080_INTR_STATE I8085_INTR_STATE
+
+#define I8080_REG_LAYOUT \
+{ CPU_8080, \
+ I8080_AF,I8080_BC,I8080_DE,I8080_HL,I8080_SP,I8080_PC, DBG_ROW, \
+ I8080_HALT,I8080_IREQ,I8080_ISRV,I8080_VECTOR, \
+ DBG_END }
+
+#define I8080_INTR_LINE I8085_INTR_LINE
+
+void i8080_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#ifdef MAME_DEBUG
+offs_t i8085_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif
diff --git a/src/emu/cpu/i8085/i8085cpu.h b/src/emu/cpu/i8085/i8085cpu.h
new file mode 100644
index 00000000000..63a6cc6eefc
--- /dev/null
+++ b/src/emu/cpu/i8085/i8085cpu.h
@@ -0,0 +1,181 @@
+/*******************************************************
+ *
+ * Portable (hopefully ;-) 8085A emulator
+ *
+ * Written by J. Buchmueller for use with MAME
+ *
+ * Partially based on Z80Em by Marcel De Kogel
+ *
+ * CPU related macros
+ *
+ *******************************************************/
+
+#define SF 0x80
+#define ZF 0x40
+#define YF 0x20
+#define HF 0x10
+#define XF 0x08
+#define VF 0x04
+#define NF 0x02
+#define CF 0x01
+
+#define IM_SID 0x80
+#define IM_SOD 0x40
+//#define IM_IEN 0x20
+#define IM_INTR 0x20 //AT: the 8085 ignores bit 0x20. we move IM_INTR here for compatibility.
+#define IM_TRAP 0x10
+//#define IM_INTR 0x08
+#define IM_IEN 0x08 //AT: RIM returns IEN status on this bit. SIM checks this bit to allow masking RST55-75
+#define IM_RST75 0x04
+#define IM_RST65 0x02
+#define IM_RST55 0x01
+
+#define ADDR_TRAP 0x0024
+#define ADDR_RST55 0x002c
+#define ADDR_RST65 0x0034
+#define ADDR_RST75 0x003c
+#define ADDR_INTR 0x0038
+
+#define M_INR(R) ++R; I.AF.b.l=(I.AF.b.l&CF)|ZS[R]|((R==0x80)?VF:0)|((R&0x0F)?0:HF)
+#define M_DCR(R) I.AF.b.l=(I.AF.b.l&CF)|NF|((R==0x80)?VF:0)|((R&0x0F)?0:HF); I.AF.b.l|=ZS[--R]
+#define M_MVI(R) R=ARG()
+
+#define M_ANA(R) I.AF.b.h&=R; I.AF.b.l=ZSP[I.AF.b.h]|HF
+#define M_ORA(R) I.AF.b.h|=R; I.AF.b.l=ZSP[I.AF.b.h]
+#define M_XRA(R) I.AF.b.h^=R; I.AF.b.l=ZSP[I.AF.b.h]
+
+#define M_RLC { \
+ I.AF.b.h = (I.AF.b.h << 1) | (I.AF.b.h >> 7); \
+ I.AF.b.l = (I.AF.b.l & ~(HF+NF+CF)) | (I.AF.b.h & CF); \
+}
+
+#define M_RRC { \
+ I.AF.b.l = (I.AF.b.l & ~(HF+NF+CF)) | (I.AF.b.h & CF); \
+ I.AF.b.h = (I.AF.b.h >> 1) | (I.AF.b.h << 7); \
+}
+
+#define M_RAL { \
+ int c = I.AF.b.l&CF; \
+ I.AF.b.l = (I.AF.b.l & ~(HF+NF+CF)) | (I.AF.b.h >> 7); \
+ I.AF.b.h = (I.AF.b.h << 1) | c; \
+}
+
+#define M_RAR { \
+ int c = (I.AF.b.l&CF) << 7; \
+ I.AF.b.l = (I.AF.b.l & ~(HF+NF+CF)) | (I.AF.b.h & CF); \
+ I.AF.b.h = (I.AF.b.h >> 1) | c; \
+}
+
+#define M_ADD(R) { \
+int q = I.AF.b.h+R; \
+ I.AF.b.l=ZSP[q&255]|((q>>8)&CF)| \
+ ((I.AF.b.h^q^R)&HF)| \
+ (((R^I.AF.b.h^SF)&(R^q)&SF)>>5); \
+ I.AF.b.h=q; \
+}
+
+#define M_ADC(R) { \
+ int q = I.AF.b.h+R+(I.AF.b.l&CF); \
+ I.AF.b.l=ZSP[q&255]|((q>>8)&CF)| \
+ ((I.AF.b.h^q^R)&HF)| \
+ (((R^I.AF.b.h^SF)&(R^q)&SF)>>5); \
+ I.AF.b.h=q; \
+}
+
+#define M_SUB(R) { \
+ int q = I.AF.b.h-R; \
+ I.AF.b.l=ZSP[q&255]|((q>>8)&CF)|NF| \
+ ((I.AF.b.h^q^R)&HF)| \
+ (((R^I.AF.b.h)&(I.AF.b.h^q)&SF)>>5); \
+ I.AF.b.h=q; \
+}
+
+#define M_SBB(R) { \
+ int q = I.AF.b.h-R-(I.AF.b.l&CF); \
+ I.AF.b.l=ZSP[q&255]|((q>>8)&CF)|NF| \
+ ((I.AF.b.h^q^R)&HF)| \
+ (((R^I.AF.b.h)&(I.AF.b.h^q)&SF)>>5); \
+ I.AF.b.h=q; \
+}
+
+#define M_CMP(R) { \
+ int q = I.AF.b.h-R; \
+ I.AF.b.l=ZSP[q&255]|((q>>8)&CF)|NF| \
+ ((I.AF.b.h^q^R)&HF)| \
+ (((R^I.AF.b.h)&(I.AF.b.h^q)&SF)>>5); \
+}
+
+#define M_IN \
+ I.XX.d=ARG(); \
+ I.AF.b.h=io_read_byte_8(I.XX.d);
+
+#define M_OUT \
+ I.XX.d=ARG(); \
+ io_write_byte_8(I.XX.d,I.AF.b.h)
+
+#define M_DAD(R) { \
+ int q = I.HL.d + I.R.d; \
+ I.AF.b.l = ( I.AF.b.l & ~(HF+CF) ) | \
+ ( ((I.HL.d^q^I.R.d) >> 8) & HF ) | \
+ ( (q>>16) & CF ); \
+ I.HL.w.l = q; \
+}
+
+#define M_PUSH(R) { \
+ WM(--I.SP.w.l, I.R.b.h); \
+ WM(--I.SP.w.l, I.R.b.l); \
+}
+
+#define M_POP(R) { \
+ I.R.b.l = RM(I.SP.w.l++); \
+ I.R.b.h = RM(I.SP.w.l++); \
+}
+
+#define M_RET(cc) \
+{ \
+ if (cc) \
+ { \
+ i8085_ICount -= 6; \
+ M_POP(PC); \
+ change_pc(I.PC.d); \
+ } \
+}
+
+#define M_JMP(cc) { \
+ if (cc) { \
+ i8085_ICount -= 3; \
+ I.PC.w.l = ARG16(); \
+ change_pc(I.PC.d); \
+ } else I.PC.w.l += 2; \
+}
+
+#define M_CALL(cc) \
+{ \
+ if (cc) \
+ { \
+ UINT16 a = ARG16(); \
+ i8085_ICount -= 6; \
+ M_PUSH(PC); \
+ I.PC.d = a; \
+ change_pc(I.PC.d); \
+ } else I.PC.w.l += 2; \
+}
+
+#define M_RST(nn) { \
+ M_PUSH(PC); \
+ I.PC.d = 8 * nn; \
+ change_pc(I.PC.d); \
+}
+
+#define M_DSUB() { \
+ int q = I.HL.b.l-I.BC.b.l; \
+ I.AF.b.l=ZS[q&255]|((q>>8)&CF)|NF| \
+ ((I.HL.b.l^q^I.BC.b.l)&HF)| \
+ (((I.BC.b.l^I.HL.b.l)&(I.HL.b.l^q)&SF)>>5); \
+ I.HL.b.l=q; \
+ q = I.HL.b.h-I.BC.b.h-(I.AF.b.l&CF); \
+ I.AF.b.l=ZS[q&255]|((q>>8)&CF)|NF| \
+ ((I.HL.b.h^q^I.BC.b.h)&HF)| \
+ (((I.BC.b.h^I.HL.b.h)&(I.HL.b.h^q)&SF)>>5); \
+ if (I.HL.b.l!=0) I.AF.b.l&=~ZF; \
+}
diff --git a/src/emu/cpu/i8085/i8085daa.h b/src/emu/cpu/i8085/i8085daa.h
new file mode 100644
index 00000000000..891c7222fd5
--- /dev/null
+++ b/src/emu/cpu/i8085/i8085daa.h
@@ -0,0 +1,2050 @@
+static UINT16 DAA[2048] = {
+ (0x00<<8) +ZF +VF ,
+ (0x01<<8) ,
+ (0x02<<8) ,
+ (0x03<<8) +VF ,
+ (0x04<<8) ,
+ (0x05<<8) +VF ,
+ (0x06<<8) +VF ,
+ (0x07<<8) ,
+ (0x08<<8) +XF ,
+ (0x09<<8) +XF+VF ,
+ (0x10<<8) +HF ,
+ (0x11<<8) +HF +VF ,
+ (0x12<<8) +HF +VF ,
+ (0x13<<8) +HF ,
+ (0x14<<8) +HF +VF ,
+ (0x15<<8) +HF ,
+ (0x10<<8) ,
+ (0x11<<8) +VF ,
+ (0x12<<8) +VF ,
+ (0x13<<8) ,
+ (0x14<<8) +VF ,
+ (0x15<<8) ,
+ (0x16<<8) ,
+ (0x17<<8) +VF ,
+ (0x18<<8) +XF+VF ,
+ (0x19<<8) +XF ,
+ (0x20<<8) +YF+HF ,
+ (0x21<<8) +YF+HF +VF ,
+ (0x22<<8) +YF+HF +VF ,
+ (0x23<<8) +YF+HF ,
+ (0x24<<8) +YF+HF +VF ,
+ (0x25<<8) +YF+HF ,
+ (0x20<<8) +YF ,
+ (0x21<<8) +YF +VF ,
+ (0x22<<8) +YF +VF ,
+ (0x23<<8) +YF ,
+ (0x24<<8) +YF +VF ,
+ (0x25<<8) +YF ,
+ (0x26<<8) +YF ,
+ (0x27<<8) +YF +VF ,
+ (0x28<<8) +YF +XF+VF ,
+ (0x29<<8) +YF +XF ,
+ (0x30<<8) +YF+HF +VF ,
+ (0x31<<8) +YF+HF ,
+ (0x32<<8) +YF+HF ,
+ (0x33<<8) +YF+HF +VF ,
+ (0x34<<8) +YF+HF ,
+ (0x35<<8) +YF+HF +VF ,
+ (0x30<<8) +YF +VF ,
+ (0x31<<8) +YF ,
+ (0x32<<8) +YF ,
+ (0x33<<8) +YF +VF ,
+ (0x34<<8) +YF ,
+ (0x35<<8) +YF +VF ,
+ (0x36<<8) +YF +VF ,
+ (0x37<<8) +YF ,
+ (0x38<<8) +YF +XF ,
+ (0x39<<8) +YF +XF+VF ,
+ (0x40<<8) +HF ,
+ (0x41<<8) +HF +VF ,
+ (0x42<<8) +HF +VF ,
+ (0x43<<8) +HF ,
+ (0x44<<8) +HF +VF ,
+ (0x45<<8) +HF ,
+ (0x40<<8) ,
+ (0x41<<8) +VF ,
+ (0x42<<8) +VF ,
+ (0x43<<8) ,
+ (0x44<<8) +VF ,
+ (0x45<<8) ,
+ (0x46<<8) ,
+ (0x47<<8) +VF ,
+ (0x48<<8) +XF+VF ,
+ (0x49<<8) +XF ,
+ (0x50<<8) +HF +VF ,
+ (0x51<<8) +HF ,
+ (0x52<<8) +HF ,
+ (0x53<<8) +HF +VF ,
+ (0x54<<8) +HF ,
+ (0x55<<8) +HF +VF ,
+ (0x50<<8) +VF ,
+ (0x51<<8) ,
+ (0x52<<8) ,
+ (0x53<<8) +VF ,
+ (0x54<<8) ,
+ (0x55<<8) +VF ,
+ (0x56<<8) +VF ,
+ (0x57<<8) ,
+ (0x58<<8) +XF ,
+ (0x59<<8) +XF+VF ,
+ (0x60<<8) +YF+HF +VF ,
+ (0x61<<8) +YF+HF ,
+ (0x62<<8) +YF+HF ,
+ (0x63<<8) +YF+HF +VF ,
+ (0x64<<8) +YF+HF ,
+ (0x65<<8) +YF+HF +VF ,
+ (0x60<<8) +YF +VF ,
+ (0x61<<8) +YF ,
+ (0x62<<8) +YF ,
+ (0x63<<8) +YF +VF ,
+ (0x64<<8) +YF ,
+ (0x65<<8) +YF +VF ,
+ (0x66<<8) +YF +VF ,
+ (0x67<<8) +YF ,
+ (0x68<<8) +YF +XF ,
+ (0x69<<8) +YF +XF+VF ,
+ (0x70<<8) +YF+HF ,
+ (0x71<<8) +YF+HF +VF ,
+ (0x72<<8) +YF+HF +VF ,
+ (0x73<<8) +YF+HF ,
+ (0x74<<8) +YF+HF +VF ,
+ (0x75<<8) +YF+HF ,
+ (0x70<<8) +YF ,
+ (0x71<<8) +YF +VF ,
+ (0x72<<8) +YF +VF ,
+ (0x73<<8) +YF ,
+ (0x74<<8) +YF +VF ,
+ (0x75<<8) +YF ,
+ (0x76<<8) +YF ,
+ (0x77<<8) +YF +VF ,
+ (0x78<<8) +YF +XF+VF ,
+ (0x79<<8) +YF +XF ,
+ (0x80<<8)+SF +HF ,
+ (0x81<<8)+SF +HF +VF ,
+ (0x82<<8)+SF +HF +VF ,
+ (0x83<<8)+SF +HF ,
+ (0x84<<8)+SF +HF +VF ,
+ (0x85<<8)+SF +HF ,
+ (0x80<<8)+SF ,
+ (0x81<<8)+SF +VF ,
+ (0x82<<8)+SF +VF ,
+ (0x83<<8)+SF ,
+ (0x84<<8)+SF +VF ,
+ (0x85<<8)+SF ,
+ (0x86<<8)+SF ,
+ (0x87<<8)+SF +VF ,
+ (0x88<<8)+SF +XF+VF ,
+ (0x89<<8)+SF +XF ,
+ (0x90<<8)+SF +HF +VF ,
+ (0x91<<8)+SF +HF ,
+ (0x92<<8)+SF +HF ,
+ (0x93<<8)+SF +HF +VF ,
+ (0x94<<8)+SF +HF ,
+ (0x95<<8)+SF +HF +VF ,
+ (0x90<<8)+SF +VF ,
+ (0x91<<8)+SF ,
+ (0x92<<8)+SF ,
+ (0x93<<8)+SF +VF ,
+ (0x94<<8)+SF ,
+ (0x95<<8)+SF +VF ,
+ (0x96<<8)+SF +VF ,
+ (0x97<<8)+SF ,
+ (0x98<<8)+SF +XF ,
+ (0x99<<8)+SF +XF+VF ,
+ (0x00<<8) +ZF +HF +VF +CF,
+ (0x01<<8) +HF +CF,
+ (0x02<<8) +HF +CF,
+ (0x03<<8) +HF +VF +CF,
+ (0x04<<8) +HF +CF,
+ (0x05<<8) +HF +VF +CF,
+ (0x00<<8) +ZF +VF +CF,
+ (0x01<<8) +CF,
+ (0x02<<8) +CF,
+ (0x03<<8) +VF +CF,
+ (0x04<<8) +CF,
+ (0x05<<8) +VF +CF,
+ (0x06<<8) +VF +CF,
+ (0x07<<8) +CF,
+ (0x08<<8) +XF +CF,
+ (0x09<<8) +XF+VF +CF,
+ (0x10<<8) +HF +CF,
+ (0x11<<8) +HF +VF +CF,
+ (0x12<<8) +HF +VF +CF,
+ (0x13<<8) +HF +CF,
+ (0x14<<8) +HF +VF +CF,
+ (0x15<<8) +HF +CF,
+ (0x10<<8) +CF,
+ (0x11<<8) +VF +CF,
+ (0x12<<8) +VF +CF,
+ (0x13<<8) +CF,
+ (0x14<<8) +VF +CF,
+ (0x15<<8) +CF,
+ (0x16<<8) +CF,
+ (0x17<<8) +VF +CF,
+ (0x18<<8) +XF+VF +CF,
+ (0x19<<8) +XF +CF,
+ (0x20<<8) +YF+HF +CF,
+ (0x21<<8) +YF+HF +VF +CF,
+ (0x22<<8) +YF+HF +VF +CF,
+ (0x23<<8) +YF+HF +CF,
+ (0x24<<8) +YF+HF +VF +CF,
+ (0x25<<8) +YF+HF +CF,
+ (0x20<<8) +YF +CF,
+ (0x21<<8) +YF +VF +CF,
+ (0x22<<8) +YF +VF +CF,
+ (0x23<<8) +YF +CF,
+ (0x24<<8) +YF +VF +CF,
+ (0x25<<8) +YF +CF,
+ (0x26<<8) +YF +CF,
+ (0x27<<8) +YF +VF +CF,
+ (0x28<<8) +YF +XF+VF +CF,
+ (0x29<<8) +YF +XF +CF,
+ (0x30<<8) +YF+HF +VF +CF,
+ (0x31<<8) +YF+HF +CF,
+ (0x32<<8) +YF+HF +CF,
+ (0x33<<8) +YF+HF +VF +CF,
+ (0x34<<8) +YF+HF +CF,
+ (0x35<<8) +YF+HF +VF +CF,
+ (0x30<<8) +YF +VF +CF,
+ (0x31<<8) +YF +CF,
+ (0x32<<8) +YF +CF,
+ (0x33<<8) +YF +VF +CF,
+ (0x34<<8) +YF +CF,
+ (0x35<<8) +YF +VF +CF,
+ (0x36<<8) +YF +VF +CF,
+ (0x37<<8) +YF +CF,
+ (0x38<<8) +YF +XF +CF,
+ (0x39<<8) +YF +XF+VF +CF,
+ (0x40<<8) +HF +CF,
+ (0x41<<8) +HF +VF +CF,
+ (0x42<<8) +HF +VF +CF,
+ (0x43<<8) +HF +CF,
+ (0x44<<8) +HF +VF +CF,
+ (0x45<<8) +HF +CF,
+ (0x40<<8) +CF,
+ (0x41<<8) +VF +CF,
+ (0x42<<8) +VF +CF,
+ (0x43<<8) +CF,
+ (0x44<<8) +VF +CF,
+ (0x45<<8) +CF,
+ (0x46<<8) +CF,
+ (0x47<<8) +VF +CF,
+ (0x48<<8) +XF+VF +CF,
+ (0x49<<8) +XF +CF,
+ (0x50<<8) +HF +VF +CF,
+ (0x51<<8) +HF +CF,
+ (0x52<<8) +HF +CF,
+ (0x53<<8) +HF +VF +CF,
+ (0x54<<8) +HF +CF,
+ (0x55<<8) +HF +VF +CF,
+ (0x50<<8) +VF +CF,
+ (0x51<<8) +CF,
+ (0x52<<8) +CF,
+ (0x53<<8) +VF +CF,
+ (0x54<<8) +CF,
+ (0x55<<8) +VF +CF,
+ (0x56<<8) +VF +CF,
+ (0x57<<8) +CF,
+ (0x58<<8) +XF +CF,
+ (0x59<<8) +XF+VF +CF,
+ (0x60<<8) +YF+HF +VF +CF,
+ (0x61<<8) +YF+HF +CF,
+ (0x62<<8) +YF+HF +CF,
+ (0x63<<8) +YF+HF +VF +CF,
+ (0x64<<8) +YF+HF +CF,
+ (0x65<<8) +YF+HF +VF +CF,
+ (0x60<<8) +YF +VF +CF,
+ (0x61<<8) +YF +CF,
+ (0x62<<8) +YF +CF,
+ (0x63<<8) +YF +VF +CF,
+ (0x64<<8) +YF +CF,
+ (0x65<<8) +YF +VF +CF,
+ (0x66<<8) +YF +VF +CF,
+ (0x67<<8) +YF +CF,
+ (0x68<<8) +YF +XF +CF,
+ (0x69<<8) +YF +XF+VF +CF,
+ (0x70<<8) +YF+HF +CF,
+ (0x71<<8) +YF+HF +VF +CF,
+ (0x72<<8) +YF+HF +VF +CF,
+ (0x73<<8) +YF+HF +CF,
+ (0x74<<8) +YF+HF +VF +CF,
+ (0x75<<8) +YF+HF +CF,
+ (0x70<<8) +YF +CF,
+ (0x71<<8) +YF +VF +CF,
+ (0x72<<8) +YF +VF +CF,
+ (0x73<<8) +YF +CF,
+ (0x74<<8) +YF +VF +CF,
+ (0x75<<8) +YF +CF,
+ (0x76<<8) +YF +CF,
+ (0x77<<8) +YF +VF +CF,
+ (0x78<<8) +YF +XF+VF +CF,
+ (0x79<<8) +YF +XF +CF,
+ (0x80<<8)+SF +HF +CF,
+ (0x81<<8)+SF +HF +VF +CF,
+ (0x82<<8)+SF +HF +VF +CF,
+ (0x83<<8)+SF +HF +CF,
+ (0x84<<8)+SF +HF +VF +CF,
+ (0x85<<8)+SF +HF +CF,
+ (0x80<<8)+SF +CF,
+ (0x81<<8)+SF +VF +CF,
+ (0x82<<8)+SF +VF +CF,
+ (0x83<<8)+SF +CF,
+ (0x84<<8)+SF +VF +CF,
+ (0x85<<8)+SF +CF,
+ (0x86<<8)+SF +CF,
+ (0x87<<8)+SF +VF +CF,
+ (0x88<<8)+SF +XF+VF +CF,
+ (0x89<<8)+SF +XF +CF,
+ (0x90<<8)+SF +HF +VF +CF,
+ (0x91<<8)+SF +HF +CF,
+ (0x92<<8)+SF +HF +CF,
+ (0x93<<8)+SF +HF +VF +CF,
+ (0x94<<8)+SF +HF +CF,
+ (0x95<<8)+SF +HF +VF +CF,
+ (0x90<<8)+SF +VF +CF,
+ (0x91<<8)+SF +CF,
+ (0x92<<8)+SF +CF,
+ (0x93<<8)+SF +VF +CF,
+ (0x94<<8)+SF +CF,
+ (0x95<<8)+SF +VF +CF,
+ (0x96<<8)+SF +VF +CF,
+ (0x97<<8)+SF +CF,
+ (0x98<<8)+SF +XF +CF,
+ (0x99<<8)+SF +XF+VF +CF,
+ (0xA0<<8)+SF +YF+HF +VF +CF,
+ (0xA1<<8)+SF +YF+HF +CF,
+ (0xA2<<8)+SF +YF+HF +CF,
+ (0xA3<<8)+SF +YF+HF +VF +CF,
+ (0xA4<<8)+SF +YF+HF +CF,
+ (0xA5<<8)+SF +YF+HF +VF +CF,
+ (0xA0<<8)+SF +YF +VF +CF,
+ (0xA1<<8)+SF +YF +CF,
+ (0xA2<<8)+SF +YF +CF,
+ (0xA3<<8)+SF +YF +VF +CF,
+ (0xA4<<8)+SF +YF +CF,
+ (0xA5<<8)+SF +YF +VF +CF,
+ (0xA6<<8)+SF +YF +VF +CF,
+ (0xA7<<8)+SF +YF +CF,
+ (0xA8<<8)+SF +YF +XF +CF,
+ (0xA9<<8)+SF +YF +XF+VF +CF,
+ (0xB0<<8)+SF +YF+HF +CF,
+ (0xB1<<8)+SF +YF+HF +VF +CF,
+ (0xB2<<8)+SF +YF+HF +VF +CF,
+ (0xB3<<8)+SF +YF+HF +CF,
+ (0xB4<<8)+SF +YF+HF +VF +CF,
+ (0xB5<<8)+SF +YF+HF +CF,
+ (0xB0<<8)+SF +YF +CF,
+ (0xB1<<8)+SF +YF +VF +CF,
+ (0xB2<<8)+SF +YF +VF +CF,
+ (0xB3<<8)+SF +YF +CF,
+ (0xB4<<8)+SF +YF +VF +CF,
+ (0xB5<<8)+SF +YF +CF,
+ (0xB6<<8)+SF +YF +CF,
+ (0xB7<<8)+SF +YF +VF +CF,
+ (0xB8<<8)+SF +YF +XF+VF +CF,
+ (0xB9<<8)+SF +YF +XF +CF,
+ (0xC0<<8)+SF +HF +VF +CF,
+ (0xC1<<8)+SF +HF +CF,
+ (0xC2<<8)+SF +HF +CF,
+ (0xC3<<8)+SF +HF +VF +CF,
+ (0xC4<<8)+SF +HF +CF,
+ (0xC5<<8)+SF +HF +VF +CF,
+ (0xC0<<8)+SF +VF +CF,
+ (0xC1<<8)+SF +CF,
+ (0xC2<<8)+SF +CF,
+ (0xC3<<8)+SF +VF +CF,
+ (0xC4<<8)+SF +CF,
+ (0xC5<<8)+SF +VF +CF,
+ (0xC6<<8)+SF +VF +CF,
+ (0xC7<<8)+SF +CF,
+ (0xC8<<8)+SF +XF +CF,
+ (0xC9<<8)+SF +XF+VF +CF,
+ (0xD0<<8)+SF +HF +CF,
+ (0xD1<<8)+SF +HF +VF +CF,
+ (0xD2<<8)+SF +HF +VF +CF,
+ (0xD3<<8)+SF +HF +CF,
+ (0xD4<<8)+SF +HF +VF +CF,
+ (0xD5<<8)+SF +HF +CF,
+ (0xD0<<8)+SF +CF,
+ (0xD1<<8)+SF +VF +CF,
+ (0xD2<<8)+SF +VF +CF,
+ (0xD3<<8)+SF +CF,
+ (0xD4<<8)+SF +VF +CF,
+ (0xD5<<8)+SF +CF,
+ (0xD6<<8)+SF +CF,
+ (0xD7<<8)+SF +VF +CF,
+ (0xD8<<8)+SF +XF+VF +CF,
+ (0xD9<<8)+SF +XF +CF,
+ (0xE0<<8)+SF +YF+HF +CF,
+ (0xE1<<8)+SF +YF+HF +VF +CF,
+ (0xE2<<8)+SF +YF+HF +VF +CF,
+ (0xE3<<8)+SF +YF+HF +CF,
+ (0xE4<<8)+SF +YF+HF +VF +CF,
+ (0xE5<<8)+SF +YF+HF +CF,
+ (0xE0<<8)+SF +YF +CF,
+ (0xE1<<8)+SF +YF +VF +CF,
+ (0xE2<<8)+SF +YF +VF +CF,
+ (0xE3<<8)+SF +YF +CF,
+ (0xE4<<8)+SF +YF +VF +CF,
+ (0xE5<<8)+SF +YF +CF,
+ (0xE6<<8)+SF +YF +CF,
+ (0xE7<<8)+SF +YF +VF +CF,
+ (0xE8<<8)+SF +YF +XF+VF +CF,
+ (0xE9<<8)+SF +YF +XF +CF,
+ (0xF0<<8)+SF +YF+HF +VF +CF,
+ (0xF1<<8)+SF +YF+HF +CF,
+ (0xF2<<8)+SF +YF+HF +CF,
+ (0xF3<<8)+SF +YF+HF +VF +CF,
+ (0xF4<<8)+SF +YF+HF +CF,
+ (0xF5<<8)+SF +YF+HF +VF +CF,
+ (0xF0<<8)+SF +YF +VF +CF,
+ (0xF1<<8)+SF +YF +CF,
+ (0xF2<<8)+SF +YF +CF,
+ (0xF3<<8)+SF +YF +VF +CF,
+ (0xF4<<8)+SF +YF +CF,
+ (0xF5<<8)+SF +YF +VF +CF,
+ (0xF6<<8)+SF +YF +VF +CF,
+ (0xF7<<8)+SF +YF +CF,
+ (0xF8<<8)+SF +YF +XF +CF,
+ (0xF9<<8)+SF +YF +XF+VF +CF,
+ (0x00<<8) +ZF +HF +VF +CF,
+ (0x01<<8) +HF +CF,
+ (0x02<<8) +HF +CF,
+ (0x03<<8) +HF +VF +CF,
+ (0x04<<8) +HF +CF,
+ (0x05<<8) +HF +VF +CF,
+ (0x00<<8) +ZF +VF +CF,
+ (0x01<<8) +CF,
+ (0x02<<8) +CF,
+ (0x03<<8) +VF +CF,
+ (0x04<<8) +CF,
+ (0x05<<8) +VF +CF,
+ (0x06<<8) +VF +CF,
+ (0x07<<8) +CF,
+ (0x08<<8) +XF +CF,
+ (0x09<<8) +XF+VF +CF,
+ (0x10<<8) +HF +CF,
+ (0x11<<8) +HF +VF +CF,
+ (0x12<<8) +HF +VF +CF,
+ (0x13<<8) +HF +CF,
+ (0x14<<8) +HF +VF +CF,
+ (0x15<<8) +HF +CF,
+ (0x10<<8) +CF,
+ (0x11<<8) +VF +CF,
+ (0x12<<8) +VF +CF,
+ (0x13<<8) +CF,
+ (0x14<<8) +VF +CF,
+ (0x15<<8) +CF,
+ (0x16<<8) +CF,
+ (0x17<<8) +VF +CF,
+ (0x18<<8) +XF+VF +CF,
+ (0x19<<8) +XF +CF,
+ (0x20<<8) +YF+HF +CF,
+ (0x21<<8) +YF+HF +VF +CF,
+ (0x22<<8) +YF+HF +VF +CF,
+ (0x23<<8) +YF+HF +CF,
+ (0x24<<8) +YF+HF +VF +CF,
+ (0x25<<8) +YF+HF +CF,
+ (0x20<<8) +YF +CF,
+ (0x21<<8) +YF +VF +CF,
+ (0x22<<8) +YF +VF +CF,
+ (0x23<<8) +YF +CF,
+ (0x24<<8) +YF +VF +CF,
+ (0x25<<8) +YF +CF,
+ (0x26<<8) +YF +CF,
+ (0x27<<8) +YF +VF +CF,
+ (0x28<<8) +YF +XF+VF +CF,
+ (0x29<<8) +YF +XF +CF,
+ (0x30<<8) +YF+HF +VF +CF,
+ (0x31<<8) +YF+HF +CF,
+ (0x32<<8) +YF+HF +CF,
+ (0x33<<8) +YF+HF +VF +CF,
+ (0x34<<8) +YF+HF +CF,
+ (0x35<<8) +YF+HF +VF +CF,
+ (0x30<<8) +YF +VF +CF,
+ (0x31<<8) +YF +CF,
+ (0x32<<8) +YF +CF,
+ (0x33<<8) +YF +VF +CF,
+ (0x34<<8) +YF +CF,
+ (0x35<<8) +YF +VF +CF,
+ (0x36<<8) +YF +VF +CF,
+ (0x37<<8) +YF +CF,
+ (0x38<<8) +YF +XF +CF,
+ (0x39<<8) +YF +XF+VF +CF,
+ (0x40<<8) +HF +CF,
+ (0x41<<8) +HF +VF +CF,
+ (0x42<<8) +HF +VF +CF,
+ (0x43<<8) +HF +CF,
+ (0x44<<8) +HF +VF +CF,
+ (0x45<<8) +HF +CF,
+ (0x40<<8) +CF,
+ (0x41<<8) +VF +CF,
+ (0x42<<8) +VF +CF,
+ (0x43<<8) +CF,
+ (0x44<<8) +VF +CF,
+ (0x45<<8) +CF,
+ (0x46<<8) +CF,
+ (0x47<<8) +VF +CF,
+ (0x48<<8) +XF+VF +CF,
+ (0x49<<8) +XF +CF,
+ (0x50<<8) +HF +VF +CF,
+ (0x51<<8) +HF +CF,
+ (0x52<<8) +HF +CF,
+ (0x53<<8) +HF +VF +CF,
+ (0x54<<8) +HF +CF,
+ (0x55<<8) +HF +VF +CF,
+ (0x50<<8) +VF +CF,
+ (0x51<<8) +CF,
+ (0x52<<8) +CF,
+ (0x53<<8) +VF +CF,
+ (0x54<<8) +CF,
+ (0x55<<8) +VF +CF,
+ (0x56<<8) +VF +CF,
+ (0x57<<8) +CF,
+ (0x58<<8) +XF +CF,
+ (0x59<<8) +XF+VF +CF,
+ (0x60<<8) +YF+HF +VF +CF,
+ (0x61<<8) +YF+HF +CF,
+ (0x62<<8) +YF+HF +CF,
+ (0x63<<8) +YF+HF +VF +CF,
+ (0x64<<8) +YF+HF +CF,
+ (0x65<<8) +YF+HF +VF +CF,
+ (0x06<<8) +VF ,
+ (0x07<<8) ,
+ (0x08<<8) +XF ,
+ (0x09<<8) +XF+VF ,
+ (0x0A<<8) +XF+VF ,
+ (0x0B<<8) +XF ,
+ (0x0C<<8) +XF+VF ,
+ (0x0D<<8) +XF ,
+ (0x0E<<8) +XF ,
+ (0x0F<<8) +XF+VF ,
+ (0x10<<8) +HF ,
+ (0x11<<8) +HF +VF ,
+ (0x12<<8) +HF +VF ,
+ (0x13<<8) +HF ,
+ (0x14<<8) +HF +VF ,
+ (0x15<<8) +HF ,
+ (0x16<<8) ,
+ (0x17<<8) +VF ,
+ (0x18<<8) +XF+VF ,
+ (0x19<<8) +XF ,
+ (0x1A<<8) +XF ,
+ (0x1B<<8) +XF+VF ,
+ (0x1C<<8) +XF ,
+ (0x1D<<8) +XF+VF ,
+ (0x1E<<8) +XF+VF ,
+ (0x1F<<8) +XF ,
+ (0x20<<8) +YF+HF ,
+ (0x21<<8) +YF+HF +VF ,
+ (0x22<<8) +YF+HF +VF ,
+ (0x23<<8) +YF+HF ,
+ (0x24<<8) +YF+HF +VF ,
+ (0x25<<8) +YF+HF ,
+ (0x26<<8) +YF ,
+ (0x27<<8) +YF +VF ,
+ (0x28<<8) +YF +XF+VF ,
+ (0x29<<8) +YF +XF ,
+ (0x2A<<8) +YF +XF ,
+ (0x2B<<8) +YF +XF+VF ,
+ (0x2C<<8) +YF +XF ,
+ (0x2D<<8) +YF +XF+VF ,
+ (0x2E<<8) +YF +XF+VF ,
+ (0x2F<<8) +YF +XF ,
+ (0x30<<8) +YF+HF +VF ,
+ (0x31<<8) +YF+HF ,
+ (0x32<<8) +YF+HF ,
+ (0x33<<8) +YF+HF +VF ,
+ (0x34<<8) +YF+HF ,
+ (0x35<<8) +YF+HF +VF ,
+ (0x36<<8) +YF +VF ,
+ (0x37<<8) +YF ,
+ (0x38<<8) +YF +XF ,
+ (0x39<<8) +YF +XF+VF ,
+ (0x3A<<8) +YF +XF+VF ,
+ (0x3B<<8) +YF +XF ,
+ (0x3C<<8) +YF +XF+VF ,
+ (0x3D<<8) +YF +XF ,
+ (0x3E<<8) +YF +XF ,
+ (0x3F<<8) +YF +XF+VF ,
+ (0x40<<8) +HF ,
+ (0x41<<8) +HF +VF ,
+ (0x42<<8) +HF +VF ,
+ (0x43<<8) +HF ,
+ (0x44<<8) +HF +VF ,
+ (0x45<<8) +HF ,
+ (0x46<<8) ,
+ (0x47<<8) +VF ,
+ (0x48<<8) +XF+VF ,
+ (0x49<<8) +XF ,
+ (0x4A<<8) +XF ,
+ (0x4B<<8) +XF+VF ,
+ (0x4C<<8) +XF ,
+ (0x4D<<8) +XF+VF ,
+ (0x4E<<8) +XF+VF ,
+ (0x4F<<8) +XF ,
+ (0x50<<8) +HF +VF ,
+ (0x51<<8) +HF ,
+ (0x52<<8) +HF ,
+ (0x53<<8) +HF +VF ,
+ (0x54<<8) +HF ,
+ (0x55<<8) +HF +VF ,
+ (0x56<<8) +VF ,
+ (0x57<<8) ,
+ (0x58<<8) +XF ,
+ (0x59<<8) +XF+VF ,
+ (0x5A<<8) +XF+VF ,
+ (0x5B<<8) +XF ,
+ (0x5C<<8) +XF+VF ,
+ (0x5D<<8) +XF ,
+ (0x5E<<8) +XF ,
+ (0x5F<<8) +XF+VF ,
+ (0x60<<8) +YF+HF +VF ,
+ (0x61<<8) +YF+HF ,
+ (0x62<<8) +YF+HF ,
+ (0x63<<8) +YF+HF +VF ,
+ (0x64<<8) +YF+HF ,
+ (0x65<<8) +YF+HF +VF ,
+ (0x66<<8) +YF +VF ,
+ (0x67<<8) +YF ,
+ (0x68<<8) +YF +XF ,
+ (0x69<<8) +YF +XF+VF ,
+ (0x6A<<8) +YF +XF+VF ,
+ (0x6B<<8) +YF +XF ,
+ (0x6C<<8) +YF +XF+VF ,
+ (0x6D<<8) +YF +XF ,
+ (0x6E<<8) +YF +XF ,
+ (0x6F<<8) +YF +XF+VF ,
+ (0x70<<8) +YF+HF ,
+ (0x71<<8) +YF+HF +VF ,
+ (0x72<<8) +YF+HF +VF ,
+ (0x73<<8) +YF+HF ,
+ (0x74<<8) +YF+HF +VF ,
+ (0x75<<8) +YF+HF ,
+ (0x76<<8) +YF ,
+ (0x77<<8) +YF +VF ,
+ (0x78<<8) +YF +XF+VF ,
+ (0x79<<8) +YF +XF ,
+ (0x7A<<8) +YF +XF ,
+ (0x7B<<8) +YF +XF+VF ,
+ (0x7C<<8) +YF +XF ,
+ (0x7D<<8) +YF +XF+VF ,
+ (0x7E<<8) +YF +XF+VF ,
+ (0x7F<<8) +YF +XF ,
+ (0x80<<8)+SF +HF ,
+ (0x81<<8)+SF +HF +VF ,
+ (0x82<<8)+SF +HF +VF ,
+ (0x83<<8)+SF +HF ,
+ (0x84<<8)+SF +HF +VF ,
+ (0x85<<8)+SF +HF ,
+ (0x86<<8)+SF ,
+ (0x87<<8)+SF +VF ,
+ (0x88<<8)+SF +XF+VF ,
+ (0x89<<8)+SF +XF ,
+ (0x8A<<8)+SF +XF ,
+ (0x8B<<8)+SF +XF+VF ,
+ (0x8C<<8)+SF +XF ,
+ (0x8D<<8)+SF +XF+VF ,
+ (0x8E<<8)+SF +XF+VF ,
+ (0x8F<<8)+SF +XF ,
+ (0x90<<8)+SF +HF +VF ,
+ (0x91<<8)+SF +HF ,
+ (0x92<<8)+SF +HF ,
+ (0x93<<8)+SF +HF +VF ,
+ (0x94<<8)+SF +HF ,
+ (0x95<<8)+SF +HF +VF ,
+ (0x96<<8)+SF +VF ,
+ (0x97<<8)+SF ,
+ (0x98<<8)+SF +XF ,
+ (0x99<<8)+SF +XF+VF ,
+ (0x9A<<8)+SF +XF+VF ,
+ (0x9B<<8)+SF +XF ,
+ (0x9C<<8)+SF +XF+VF ,
+ (0x9D<<8)+SF +XF ,
+ (0x9E<<8)+SF +XF ,
+ (0x9F<<8)+SF +XF+VF ,
+ (0x00<<8) +ZF +HF +VF +CF,
+ (0x01<<8) +HF +CF,
+ (0x02<<8) +HF +CF,
+ (0x03<<8) +HF +VF +CF,
+ (0x04<<8) +HF +CF,
+ (0x05<<8) +HF +VF +CF,
+ (0x06<<8) +VF +CF,
+ (0x07<<8) +CF,
+ (0x08<<8) +XF +CF,
+ (0x09<<8) +XF+VF +CF,
+ (0x0A<<8) +XF+VF +CF,
+ (0x0B<<8) +XF +CF,
+ (0x0C<<8) +XF+VF +CF,
+ (0x0D<<8) +XF +CF,
+ (0x0E<<8) +XF +CF,
+ (0x0F<<8) +XF+VF +CF,
+ (0x10<<8) +HF +CF,
+ (0x11<<8) +HF +VF +CF,
+ (0x12<<8) +HF +VF +CF,
+ (0x13<<8) +HF +CF,
+ (0x14<<8) +HF +VF +CF,
+ (0x15<<8) +HF +CF,
+ (0x16<<8) +CF,
+ (0x17<<8) +VF +CF,
+ (0x18<<8) +XF+VF +CF,
+ (0x19<<8) +XF +CF,
+ (0x1A<<8) +XF +CF,
+ (0x1B<<8) +XF+VF +CF,
+ (0x1C<<8) +XF +CF,
+ (0x1D<<8) +XF+VF +CF,
+ (0x1E<<8) +XF+VF +CF,
+ (0x1F<<8) +XF +CF,
+ (0x20<<8) +YF+HF +CF,
+ (0x21<<8) +YF+HF +VF +CF,
+ (0x22<<8) +YF+HF +VF +CF,
+ (0x23<<8) +YF+HF +CF,
+ (0x24<<8) +YF+HF +VF +CF,
+ (0x25<<8) +YF+HF +CF,
+ (0x26<<8) +YF +CF,
+ (0x27<<8) +YF +VF +CF,
+ (0x28<<8) +YF +XF+VF +CF,
+ (0x29<<8) +YF +XF +CF,
+ (0x2A<<8) +YF +XF +CF,
+ (0x2B<<8) +YF +XF+VF +CF,
+ (0x2C<<8) +YF +XF +CF,
+ (0x2D<<8) +YF +XF+VF +CF,
+ (0x2E<<8) +YF +XF+VF +CF,
+ (0x2F<<8) +YF +XF +CF,
+ (0x30<<8) +YF+HF +VF +CF,
+ (0x31<<8) +YF+HF +CF,
+ (0x32<<8) +YF+HF +CF,
+ (0x33<<8) +YF+HF +VF +CF,
+ (0x34<<8) +YF+HF +CF,
+ (0x35<<8) +YF+HF +VF +CF,
+ (0x36<<8) +YF +VF +CF,
+ (0x37<<8) +YF +CF,
+ (0x38<<8) +YF +XF +CF,
+ (0x39<<8) +YF +XF+VF +CF,
+ (0x3A<<8) +YF +XF+VF +CF,
+ (0x3B<<8) +YF +XF +CF,
+ (0x3C<<8) +YF +XF+VF +CF,
+ (0x3D<<8) +YF +XF +CF,
+ (0x3E<<8) +YF +XF +CF,
+ (0x3F<<8) +YF +XF+VF +CF,
+ (0x40<<8) +HF +CF,
+ (0x41<<8) +HF +VF +CF,
+ (0x42<<8) +HF +VF +CF,
+ (0x43<<8) +HF +CF,
+ (0x44<<8) +HF +VF +CF,
+ (0x45<<8) +HF +CF,
+ (0x46<<8) +CF,
+ (0x47<<8) +VF +CF,
+ (0x48<<8) +XF+VF +CF,
+ (0x49<<8) +XF +CF,
+ (0x4A<<8) +XF +CF,
+ (0x4B<<8) +XF+VF +CF,
+ (0x4C<<8) +XF +CF,
+ (0x4D<<8) +XF+VF +CF,
+ (0x4E<<8) +XF+VF +CF,
+ (0x4F<<8) +XF +CF,
+ (0x50<<8) +HF +VF +CF,
+ (0x51<<8) +HF +CF,
+ (0x52<<8) +HF +CF,
+ (0x53<<8) +HF +VF +CF,
+ (0x54<<8) +HF +CF,
+ (0x55<<8) +HF +VF +CF,
+ (0x56<<8) +VF +CF,
+ (0x57<<8) +CF,
+ (0x58<<8) +XF +CF,
+ (0x59<<8) +XF+VF +CF,
+ (0x5A<<8) +XF+VF +CF,
+ (0x5B<<8) +XF +CF,
+ (0x5C<<8) +XF+VF +CF,
+ (0x5D<<8) +XF +CF,
+ (0x5E<<8) +XF +CF,
+ (0x5F<<8) +XF+VF +CF,
+ (0x60<<8) +YF+HF +VF +CF,
+ (0x61<<8) +YF+HF +CF,
+ (0x62<<8) +YF+HF +CF,
+ (0x63<<8) +YF+HF +VF +CF,
+ (0x64<<8) +YF+HF +CF,
+ (0x65<<8) +YF+HF +VF +CF,
+ (0x66<<8) +YF +VF +CF,
+ (0x67<<8) +YF +CF,
+ (0x68<<8) +YF +XF +CF,
+ (0x69<<8) +YF +XF+VF +CF,
+ (0x6A<<8) +YF +XF+VF +CF,
+ (0x6B<<8) +YF +XF +CF,
+ (0x6C<<8) +YF +XF+VF +CF,
+ (0x6D<<8) +YF +XF +CF,
+ (0x6E<<8) +YF +XF +CF,
+ (0x6F<<8) +YF +XF+VF +CF,
+ (0x70<<8) +YF+HF +CF,
+ (0x71<<8) +YF+HF +VF +CF,
+ (0x72<<8) +YF+HF +VF +CF,
+ (0x73<<8) +YF+HF +CF,
+ (0x74<<8) +YF+HF +VF +CF,
+ (0x75<<8) +YF+HF +CF,
+ (0x76<<8) +YF +CF,
+ (0x77<<8) +YF +VF +CF,
+ (0x78<<8) +YF +XF+VF +CF,
+ (0x79<<8) +YF +XF +CF,
+ (0x7A<<8) +YF +XF +CF,
+ (0x7B<<8) +YF +XF+VF +CF,
+ (0x7C<<8) +YF +XF +CF,
+ (0x7D<<8) +YF +XF+VF +CF,
+ (0x7E<<8) +YF +XF+VF +CF,
+ (0x7F<<8) +YF +XF +CF,
+ (0x80<<8)+SF +HF +CF,
+ (0x81<<8)+SF +HF +VF +CF,
+ (0x82<<8)+SF +HF +VF +CF,
+ (0x83<<8)+SF +HF +CF,
+ (0x84<<8)+SF +HF +VF +CF,
+ (0x85<<8)+SF +HF +CF,
+ (0x86<<8)+SF +CF,
+ (0x87<<8)+SF +VF +CF,
+ (0x88<<8)+SF +XF+VF +CF,
+ (0x89<<8)+SF +XF +CF,
+ (0x8A<<8)+SF +XF +CF,
+ (0x8B<<8)+SF +XF+VF +CF,
+ (0x8C<<8)+SF +XF +CF,
+ (0x8D<<8)+SF +XF+VF +CF,
+ (0x8E<<8)+SF +XF+VF +CF,
+ (0x8F<<8)+SF +XF +CF,
+ (0x90<<8)+SF +HF +VF +CF,
+ (0x91<<8)+SF +HF +CF,
+ (0x92<<8)+SF +HF +CF,
+ (0x93<<8)+SF +HF +VF +CF,
+ (0x94<<8)+SF +HF +CF,
+ (0x95<<8)+SF +HF +VF +CF,
+ (0x96<<8)+SF +VF +CF,
+ (0x97<<8)+SF +CF,
+ (0x98<<8)+SF +XF +CF,
+ (0x99<<8)+SF +XF+VF +CF,
+ (0x9A<<8)+SF +XF+VF +CF,
+ (0x9B<<8)+SF +XF +CF,
+ (0x9C<<8)+SF +XF+VF +CF,
+ (0x9D<<8)+SF +XF +CF,
+ (0x9E<<8)+SF +XF +CF,
+ (0x9F<<8)+SF +XF+VF +CF,
+ (0xA0<<8)+SF +YF+HF +VF +CF,
+ (0xA1<<8)+SF +YF+HF +CF,
+ (0xA2<<8)+SF +YF+HF +CF,
+ (0xA3<<8)+SF +YF+HF +VF +CF,
+ (0xA4<<8)+SF +YF+HF +CF,
+ (0xA5<<8)+SF +YF+HF +VF +CF,
+ (0xA6<<8)+SF +YF +VF +CF,
+ (0xA7<<8)+SF +YF +CF,
+ (0xA8<<8)+SF +YF +XF +CF,
+ (0xA9<<8)+SF +YF +XF+VF +CF,
+ (0xAA<<8)+SF +YF +XF+VF +CF,
+ (0xAB<<8)+SF +YF +XF +CF,
+ (0xAC<<8)+SF +YF +XF+VF +CF,
+ (0xAD<<8)+SF +YF +XF +CF,
+ (0xAE<<8)+SF +YF +XF +CF,
+ (0xAF<<8)+SF +YF +XF+VF +CF,
+ (0xB0<<8)+SF +YF+HF +CF,
+ (0xB1<<8)+SF +YF+HF +VF +CF,
+ (0xB2<<8)+SF +YF+HF +VF +CF,
+ (0xB3<<8)+SF +YF+HF +CF,
+ (0xB4<<8)+SF +YF+HF +VF +CF,
+ (0xB5<<8)+SF +YF+HF +CF,
+ (0xB6<<8)+SF +YF +CF,
+ (0xB7<<8)+SF +YF +VF +CF,
+ (0xB8<<8)+SF +YF +XF+VF +CF,
+ (0xB9<<8)+SF +YF +XF +CF,
+ (0xBA<<8)+SF +YF +XF +CF,
+ (0xBB<<8)+SF +YF +XF+VF +CF,
+ (0xBC<<8)+SF +YF +XF +CF,
+ (0xBD<<8)+SF +YF +XF+VF +CF,
+ (0xBE<<8)+SF +YF +XF+VF +CF,
+ (0xBF<<8)+SF +YF +XF +CF,
+ (0xC0<<8)+SF +HF +VF +CF,
+ (0xC1<<8)+SF +HF +CF,
+ (0xC2<<8)+SF +HF +CF,
+ (0xC3<<8)+SF +HF +VF +CF,
+ (0xC4<<8)+SF +HF +CF,
+ (0xC5<<8)+SF +HF +VF +CF,
+ (0xC6<<8)+SF +VF +CF,
+ (0xC7<<8)+SF +CF,
+ (0xC8<<8)+SF +XF +CF,
+ (0xC9<<8)+SF +XF+VF +CF,
+ (0xCA<<8)+SF +XF+VF +CF,
+ (0xCB<<8)+SF +XF +CF,
+ (0xCC<<8)+SF +XF+VF +CF,
+ (0xCD<<8)+SF +XF +CF,
+ (0xCE<<8)+SF +XF +CF,
+ (0xCF<<8)+SF +XF+VF +CF,
+ (0xD0<<8)+SF +HF +CF,
+ (0xD1<<8)+SF +HF +VF +CF,
+ (0xD2<<8)+SF +HF +VF +CF,
+ (0xD3<<8)+SF +HF +CF,
+ (0xD4<<8)+SF +HF +VF +CF,
+ (0xD5<<8)+SF +HF +CF,
+ (0xD6<<8)+SF +CF,
+ (0xD7<<8)+SF +VF +CF,
+ (0xD8<<8)+SF +XF+VF +CF,
+ (0xD9<<8)+SF +XF +CF,
+ (0xDA<<8)+SF +XF +CF,
+ (0xDB<<8)+SF +XF+VF +CF,
+ (0xDC<<8)+SF +XF +CF,
+ (0xDD<<8)+SF +XF+VF +CF,
+ (0xDE<<8)+SF +XF+VF +CF,
+ (0xDF<<8)+SF +XF +CF,
+ (0xE0<<8)+SF +YF+HF +CF,
+ (0xE1<<8)+SF +YF+HF +VF +CF,
+ (0xE2<<8)+SF +YF+HF +VF +CF,
+ (0xE3<<8)+SF +YF+HF +CF,
+ (0xE4<<8)+SF +YF+HF +VF +CF,
+ (0xE5<<8)+SF +YF+HF +CF,
+ (0xE6<<8)+SF +YF +CF,
+ (0xE7<<8)+SF +YF +VF +CF,
+ (0xE8<<8)+SF +YF +XF+VF +CF,
+ (0xE9<<8)+SF +YF +XF +CF,
+ (0xEA<<8)+SF +YF +XF +CF,
+ (0xEB<<8)+SF +YF +XF+VF +CF,
+ (0xEC<<8)+SF +YF +XF +CF,
+ (0xED<<8)+SF +YF +XF+VF +CF,
+ (0xEE<<8)+SF +YF +XF+VF +CF,
+ (0xEF<<8)+SF +YF +XF +CF,
+ (0xF0<<8)+SF +YF+HF +VF +CF,
+ (0xF1<<8)+SF +YF+HF +CF,
+ (0xF2<<8)+SF +YF+HF +CF,
+ (0xF3<<8)+SF +YF+HF +VF +CF,
+ (0xF4<<8)+SF +YF+HF +CF,
+ (0xF5<<8)+SF +YF+HF +VF +CF,
+ (0xF6<<8)+SF +YF +VF +CF,
+ (0xF7<<8)+SF +YF +CF,
+ (0xF8<<8)+SF +YF +XF +CF,
+ (0xF9<<8)+SF +YF +XF+VF +CF,
+ (0xFA<<8)+SF +YF +XF+VF +CF,
+ (0xFB<<8)+SF +YF +XF +CF,
+ (0xFC<<8)+SF +YF +XF+VF +CF,
+ (0xFD<<8)+SF +YF +XF +CF,
+ (0xFE<<8)+SF +YF +XF +CF,
+ (0xFF<<8)+SF +YF +XF+VF +CF,
+ (0x00<<8) +ZF +HF +VF +CF,
+ (0x01<<8) +HF +CF,
+ (0x02<<8) +HF +CF,
+ (0x03<<8) +HF +VF +CF,
+ (0x04<<8) +HF +CF,
+ (0x05<<8) +HF +VF +CF,
+ (0x06<<8) +VF +CF,
+ (0x07<<8) +CF,
+ (0x08<<8) +XF +CF,
+ (0x09<<8) +XF+VF +CF,
+ (0x0A<<8) +XF+VF +CF,
+ (0x0B<<8) +XF +CF,
+ (0x0C<<8) +XF+VF +CF,
+ (0x0D<<8) +XF +CF,
+ (0x0E<<8) +XF +CF,
+ (0x0F<<8) +XF+VF +CF,
+ (0x10<<8) +HF +CF,
+ (0x11<<8) +HF +VF +CF,
+ (0x12<<8) +HF +VF +CF,
+ (0x13<<8) +HF +CF,
+ (0x14<<8) +HF +VF +CF,
+ (0x15<<8) +HF +CF,
+ (0x16<<8) +CF,
+ (0x17<<8) +VF +CF,
+ (0x18<<8) +XF+VF +CF,
+ (0x19<<8) +XF +CF,
+ (0x1A<<8) +XF +CF,
+ (0x1B<<8) +XF+VF +CF,
+ (0x1C<<8) +XF +CF,
+ (0x1D<<8) +XF+VF +CF,
+ (0x1E<<8) +XF+VF +CF,
+ (0x1F<<8) +XF +CF,
+ (0x20<<8) +YF+HF +CF,
+ (0x21<<8) +YF+HF +VF +CF,
+ (0x22<<8) +YF+HF +VF +CF,
+ (0x23<<8) +YF+HF +CF,
+ (0x24<<8) +YF+HF +VF +CF,
+ (0x25<<8) +YF+HF +CF,
+ (0x26<<8) +YF +CF,
+ (0x27<<8) +YF +VF +CF,
+ (0x28<<8) +YF +XF+VF +CF,
+ (0x29<<8) +YF +XF +CF,
+ (0x2A<<8) +YF +XF +CF,
+ (0x2B<<8) +YF +XF+VF +CF,
+ (0x2C<<8) +YF +XF +CF,
+ (0x2D<<8) +YF +XF+VF +CF,
+ (0x2E<<8) +YF +XF+VF +CF,
+ (0x2F<<8) +YF +XF +CF,
+ (0x30<<8) +YF+HF +VF +CF,
+ (0x31<<8) +YF+HF +CF,
+ (0x32<<8) +YF+HF +CF,
+ (0x33<<8) +YF+HF +VF +CF,
+ (0x34<<8) +YF+HF +CF,
+ (0x35<<8) +YF+HF +VF +CF,
+ (0x36<<8) +YF +VF +CF,
+ (0x37<<8) +YF +CF,
+ (0x38<<8) +YF +XF +CF,
+ (0x39<<8) +YF +XF+VF +CF,
+ (0x3A<<8) +YF +XF+VF +CF,
+ (0x3B<<8) +YF +XF +CF,
+ (0x3C<<8) +YF +XF+VF +CF,
+ (0x3D<<8) +YF +XF +CF,
+ (0x3E<<8) +YF +XF +CF,
+ (0x3F<<8) +YF +XF+VF +CF,
+ (0x40<<8) +HF +CF,
+ (0x41<<8) +HF +VF +CF,
+ (0x42<<8) +HF +VF +CF,
+ (0x43<<8) +HF +CF,
+ (0x44<<8) +HF +VF +CF,
+ (0x45<<8) +HF +CF,
+ (0x46<<8) +CF,
+ (0x47<<8) +VF +CF,
+ (0x48<<8) +XF+VF +CF,
+ (0x49<<8) +XF +CF,
+ (0x4A<<8) +XF +CF,
+ (0x4B<<8) +XF+VF +CF,
+ (0x4C<<8) +XF +CF,
+ (0x4D<<8) +XF+VF +CF,
+ (0x4E<<8) +XF+VF +CF,
+ (0x4F<<8) +XF +CF,
+ (0x50<<8) +HF +VF +CF,
+ (0x51<<8) +HF +CF,
+ (0x52<<8) +HF +CF,
+ (0x53<<8) +HF +VF +CF,
+ (0x54<<8) +HF +CF,
+ (0x55<<8) +HF +VF +CF,
+ (0x56<<8) +VF +CF,
+ (0x57<<8) +CF,
+ (0x58<<8) +XF +CF,
+ (0x59<<8) +XF+VF +CF,
+ (0x5A<<8) +XF+VF +CF,
+ (0x5B<<8) +XF +CF,
+ (0x5C<<8) +XF+VF +CF,
+ (0x5D<<8) +XF +CF,
+ (0x5E<<8) +XF +CF,
+ (0x5F<<8) +XF+VF +CF,
+ (0x60<<8) +YF+HF +VF +CF,
+ (0x61<<8) +YF+HF +CF,
+ (0x62<<8) +YF+HF +CF,
+ (0x63<<8) +YF+HF +VF +CF,
+ (0x64<<8) +YF+HF +CF,
+ (0x65<<8) +YF+HF +VF +CF,
+ (0x00<<8) +ZF +VF+NF ,
+ (0x01<<8) +NF ,
+ (0x02<<8) +NF ,
+ (0x03<<8) +VF+NF ,
+ (0x04<<8) +NF ,
+ (0x05<<8) +VF+NF ,
+ (0x06<<8) +VF+NF ,
+ (0x07<<8) +NF ,
+ (0x08<<8) +XF +NF ,
+ (0x09<<8) +XF+VF+NF ,
+ (0x04<<8) +NF ,
+ (0x05<<8) +VF+NF ,
+ (0x06<<8) +VF+NF ,
+ (0x07<<8) +NF ,
+ (0x08<<8) +XF +NF ,
+ (0x09<<8) +XF+VF+NF ,
+ (0x10<<8) +NF ,
+ (0x11<<8) +VF+NF ,
+ (0x12<<8) +VF+NF ,
+ (0x13<<8) +NF ,
+ (0x14<<8) +VF+NF ,
+ (0x15<<8) +NF ,
+ (0x16<<8) +NF ,
+ (0x17<<8) +VF+NF ,
+ (0x18<<8) +XF+VF+NF ,
+ (0x19<<8) +XF +NF ,
+ (0x14<<8) +VF+NF ,
+ (0x15<<8) +NF ,
+ (0x16<<8) +NF ,
+ (0x17<<8) +VF+NF ,
+ (0x18<<8) +XF+VF+NF ,
+ (0x19<<8) +XF +NF ,
+ (0x20<<8) +YF +NF ,
+ (0x21<<8) +YF +VF+NF ,
+ (0x22<<8) +YF +VF+NF ,
+ (0x23<<8) +YF +NF ,
+ (0x24<<8) +YF +VF+NF ,
+ (0x25<<8) +YF +NF ,
+ (0x26<<8) +YF +NF ,
+ (0x27<<8) +YF +VF+NF ,
+ (0x28<<8) +YF +XF+VF+NF ,
+ (0x29<<8) +YF +XF +NF ,
+ (0x24<<8) +YF +VF+NF ,
+ (0x25<<8) +YF +NF ,
+ (0x26<<8) +YF +NF ,
+ (0x27<<8) +YF +VF+NF ,
+ (0x28<<8) +YF +XF+VF+NF ,
+ (0x29<<8) +YF +XF +NF ,
+ (0x30<<8) +YF +VF+NF ,
+ (0x31<<8) +YF +NF ,
+ (0x32<<8) +YF +NF ,
+ (0x33<<8) +YF +VF+NF ,
+ (0x34<<8) +YF +NF ,
+ (0x35<<8) +YF +VF+NF ,
+ (0x36<<8) +YF +VF+NF ,
+ (0x37<<8) +YF +NF ,
+ (0x38<<8) +YF +XF +NF ,
+ (0x39<<8) +YF +XF+VF+NF ,
+ (0x34<<8) +YF +NF ,
+ (0x35<<8) +YF +VF+NF ,
+ (0x36<<8) +YF +VF+NF ,
+ (0x37<<8) +YF +NF ,
+ (0x38<<8) +YF +XF +NF ,
+ (0x39<<8) +YF +XF+VF+NF ,
+ (0x40<<8) +NF ,
+ (0x41<<8) +VF+NF ,
+ (0x42<<8) +VF+NF ,
+ (0x43<<8) +NF ,
+ (0x44<<8) +VF+NF ,
+ (0x45<<8) +NF ,
+ (0x46<<8) +NF ,
+ (0x47<<8) +VF+NF ,
+ (0x48<<8) +XF+VF+NF ,
+ (0x49<<8) +XF +NF ,
+ (0x44<<8) +VF+NF ,
+ (0x45<<8) +NF ,
+ (0x46<<8) +NF ,
+ (0x47<<8) +VF+NF ,
+ (0x48<<8) +XF+VF+NF ,
+ (0x49<<8) +XF +NF ,
+ (0x50<<8) +VF+NF ,
+ (0x51<<8) +NF ,
+ (0x52<<8) +NF ,
+ (0x53<<8) +VF+NF ,
+ (0x54<<8) +NF ,
+ (0x55<<8) +VF+NF ,
+ (0x56<<8) +VF+NF ,
+ (0x57<<8) +NF ,
+ (0x58<<8) +XF +NF ,
+ (0x59<<8) +XF+VF+NF ,
+ (0x54<<8) +NF ,
+ (0x55<<8) +VF+NF ,
+ (0x56<<8) +VF+NF ,
+ (0x57<<8) +NF ,
+ (0x58<<8) +XF +NF ,
+ (0x59<<8) +XF+VF+NF ,
+ (0x60<<8) +YF +VF+NF ,
+ (0x61<<8) +YF +NF ,
+ (0x62<<8) +YF +NF ,
+ (0x63<<8) +YF +VF+NF ,
+ (0x64<<8) +YF +NF ,
+ (0x65<<8) +YF +VF+NF ,
+ (0x66<<8) +YF +VF+NF ,
+ (0x67<<8) +YF +NF ,
+ (0x68<<8) +YF +XF +NF ,
+ (0x69<<8) +YF +XF+VF+NF ,
+ (0x64<<8) +YF +NF ,
+ (0x65<<8) +YF +VF+NF ,
+ (0x66<<8) +YF +VF+NF ,
+ (0x67<<8) +YF +NF ,
+ (0x68<<8) +YF +XF +NF ,
+ (0x69<<8) +YF +XF+VF+NF ,
+ (0x70<<8) +YF +NF ,
+ (0x71<<8) +YF +VF+NF ,
+ (0x72<<8) +YF +VF+NF ,
+ (0x73<<8) +YF +NF ,
+ (0x74<<8) +YF +VF+NF ,
+ (0x75<<8) +YF +NF ,
+ (0x76<<8) +YF +NF ,
+ (0x77<<8) +YF +VF+NF ,
+ (0x78<<8) +YF +XF+VF+NF ,
+ (0x79<<8) +YF +XF +NF ,
+ (0x74<<8) +YF +VF+NF ,
+ (0x75<<8) +YF +NF ,
+ (0x76<<8) +YF +NF ,
+ (0x77<<8) +YF +VF+NF ,
+ (0x78<<8) +YF +XF+VF+NF ,
+ (0x79<<8) +YF +XF +NF ,
+ (0x80<<8)+SF +NF ,
+ (0x81<<8)+SF +VF+NF ,
+ (0x82<<8)+SF +VF+NF ,
+ (0x83<<8)+SF +NF ,
+ (0x84<<8)+SF +VF+NF ,
+ (0x85<<8)+SF +NF ,
+ (0x86<<8)+SF +NF ,
+ (0x87<<8)+SF +VF+NF ,
+ (0x88<<8)+SF +XF+VF+NF ,
+ (0x89<<8)+SF +XF +NF ,
+ (0x84<<8)+SF +VF+NF ,
+ (0x85<<8)+SF +NF ,
+ (0x86<<8)+SF +NF ,
+ (0x87<<8)+SF +VF+NF ,
+ (0x88<<8)+SF +XF+VF+NF ,
+ (0x89<<8)+SF +XF +NF ,
+ (0x90<<8)+SF +VF+NF ,
+ (0x91<<8)+SF +NF ,
+ (0x92<<8)+SF +NF ,
+ (0x93<<8)+SF +VF+NF ,
+ (0x94<<8)+SF +NF ,
+ (0x95<<8)+SF +VF+NF ,
+ (0x96<<8)+SF +VF+NF ,
+ (0x97<<8)+SF +NF ,
+ (0x98<<8)+SF +XF +NF ,
+ (0x99<<8)+SF +XF+VF+NF ,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x40<<8) +NF+CF,
+ (0x41<<8) +VF+NF+CF,
+ (0x42<<8) +VF+NF+CF,
+ (0x43<<8) +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x50<<8) +VF+NF+CF,
+ (0x51<<8) +NF+CF,
+ (0x52<<8) +NF+CF,
+ (0x53<<8) +VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x60<<8) +YF +VF+NF+CF,
+ (0x61<<8) +YF +NF+CF,
+ (0x62<<8) +YF +NF+CF,
+ (0x63<<8) +YF +VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x70<<8) +YF +NF+CF,
+ (0x71<<8) +YF +VF+NF+CF,
+ (0x72<<8) +YF +VF+NF+CF,
+ (0x73<<8) +YF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x80<<8)+SF +NF+CF,
+ (0x81<<8)+SF +VF+NF+CF,
+ (0x82<<8)+SF +VF+NF+CF,
+ (0x83<<8)+SF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x90<<8)+SF +VF+NF+CF,
+ (0x91<<8)+SF +NF+CF,
+ (0x92<<8)+SF +NF+CF,
+ (0x93<<8)+SF +VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0xA0<<8)+SF +YF +VF+NF+CF,
+ (0xA1<<8)+SF +YF +NF+CF,
+ (0xA2<<8)+SF +YF +NF+CF,
+ (0xA3<<8)+SF +YF +VF+NF+CF,
+ (0xA4<<8)+SF +YF +NF+CF,
+ (0xA5<<8)+SF +YF +VF+NF+CF,
+ (0xA6<<8)+SF +YF +VF+NF+CF,
+ (0xA7<<8)+SF +YF +NF+CF,
+ (0xA8<<8)+SF +YF +XF +NF+CF,
+ (0xA9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xA4<<8)+SF +YF +NF+CF,
+ (0xA5<<8)+SF +YF +VF+NF+CF,
+ (0xA6<<8)+SF +YF +VF+NF+CF,
+ (0xA7<<8)+SF +YF +NF+CF,
+ (0xA8<<8)+SF +YF +XF +NF+CF,
+ (0xA9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xB0<<8)+SF +YF +NF+CF,
+ (0xB1<<8)+SF +YF +VF+NF+CF,
+ (0xB2<<8)+SF +YF +VF+NF+CF,
+ (0xB3<<8)+SF +YF +NF+CF,
+ (0xB4<<8)+SF +YF +VF+NF+CF,
+ (0xB5<<8)+SF +YF +NF+CF,
+ (0xB6<<8)+SF +YF +NF+CF,
+ (0xB7<<8)+SF +YF +VF+NF+CF,
+ (0xB8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xB9<<8)+SF +YF +XF +NF+CF,
+ (0xB4<<8)+SF +YF +VF+NF+CF,
+ (0xB5<<8)+SF +YF +NF+CF,
+ (0xB6<<8)+SF +YF +NF+CF,
+ (0xB7<<8)+SF +YF +VF+NF+CF,
+ (0xB8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xB9<<8)+SF +YF +XF +NF+CF,
+ (0xC0<<8)+SF +VF+NF+CF,
+ (0xC1<<8)+SF +NF+CF,
+ (0xC2<<8)+SF +NF+CF,
+ (0xC3<<8)+SF +VF+NF+CF,
+ (0xC4<<8)+SF +NF+CF,
+ (0xC5<<8)+SF +VF+NF+CF,
+ (0xC6<<8)+SF +VF+NF+CF,
+ (0xC7<<8)+SF +NF+CF,
+ (0xC8<<8)+SF +XF +NF+CF,
+ (0xC9<<8)+SF +XF+VF+NF+CF,
+ (0xC4<<8)+SF +NF+CF,
+ (0xC5<<8)+SF +VF+NF+CF,
+ (0xC6<<8)+SF +VF+NF+CF,
+ (0xC7<<8)+SF +NF+CF,
+ (0xC8<<8)+SF +XF +NF+CF,
+ (0xC9<<8)+SF +XF+VF+NF+CF,
+ (0xD0<<8)+SF +NF+CF,
+ (0xD1<<8)+SF +VF+NF+CF,
+ (0xD2<<8)+SF +VF+NF+CF,
+ (0xD3<<8)+SF +NF+CF,
+ (0xD4<<8)+SF +VF+NF+CF,
+ (0xD5<<8)+SF +NF+CF,
+ (0xD6<<8)+SF +NF+CF,
+ (0xD7<<8)+SF +VF+NF+CF,
+ (0xD8<<8)+SF +XF+VF+NF+CF,
+ (0xD9<<8)+SF +XF +NF+CF,
+ (0xD4<<8)+SF +VF+NF+CF,
+ (0xD5<<8)+SF +NF+CF,
+ (0xD6<<8)+SF +NF+CF,
+ (0xD7<<8)+SF +VF+NF+CF,
+ (0xD8<<8)+SF +XF+VF+NF+CF,
+ (0xD9<<8)+SF +XF +NF+CF,
+ (0xE0<<8)+SF +YF +NF+CF,
+ (0xE1<<8)+SF +YF +VF+NF+CF,
+ (0xE2<<8)+SF +YF +VF+NF+CF,
+ (0xE3<<8)+SF +YF +NF+CF,
+ (0xE4<<8)+SF +YF +VF+NF+CF,
+ (0xE5<<8)+SF +YF +NF+CF,
+ (0xE6<<8)+SF +YF +NF+CF,
+ (0xE7<<8)+SF +YF +VF+NF+CF,
+ (0xE8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xE9<<8)+SF +YF +XF +NF+CF,
+ (0xE4<<8)+SF +YF +VF+NF+CF,
+ (0xE5<<8)+SF +YF +NF+CF,
+ (0xE6<<8)+SF +YF +NF+CF,
+ (0xE7<<8)+SF +YF +VF+NF+CF,
+ (0xE8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xE9<<8)+SF +YF +XF +NF+CF,
+ (0xF0<<8)+SF +YF +VF+NF+CF,
+ (0xF1<<8)+SF +YF +NF+CF,
+ (0xF2<<8)+SF +YF +NF+CF,
+ (0xF3<<8)+SF +YF +VF+NF+CF,
+ (0xF4<<8)+SF +YF +NF+CF,
+ (0xF5<<8)+SF +YF +VF+NF+CF,
+ (0xF6<<8)+SF +YF +VF+NF+CF,
+ (0xF7<<8)+SF +YF +NF+CF,
+ (0xF8<<8)+SF +YF +XF +NF+CF,
+ (0xF9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xF4<<8)+SF +YF +NF+CF,
+ (0xF5<<8)+SF +YF +VF+NF+CF,
+ (0xF6<<8)+SF +YF +VF+NF+CF,
+ (0xF7<<8)+SF +YF +NF+CF,
+ (0xF8<<8)+SF +YF +XF +NF+CF,
+ (0xF9<<8)+SF +YF +XF+VF+NF+CF,
+ (0x00<<8) +ZF +VF+NF+CF,
+ (0x01<<8) +NF+CF,
+ (0x02<<8) +NF+CF,
+ (0x03<<8) +VF+NF+CF,
+ (0x04<<8) +NF+CF,
+ (0x05<<8) +VF+NF+CF,
+ (0x06<<8) +VF+NF+CF,
+ (0x07<<8) +NF+CF,
+ (0x08<<8) +XF +NF+CF,
+ (0x09<<8) +XF+VF+NF+CF,
+ (0x04<<8) +NF+CF,
+ (0x05<<8) +VF+NF+CF,
+ (0x06<<8) +VF+NF+CF,
+ (0x07<<8) +NF+CF,
+ (0x08<<8) +XF +NF+CF,
+ (0x09<<8) +XF+VF+NF+CF,
+ (0x10<<8) +NF+CF,
+ (0x11<<8) +VF+NF+CF,
+ (0x12<<8) +VF+NF+CF,
+ (0x13<<8) +NF+CF,
+ (0x14<<8) +VF+NF+CF,
+ (0x15<<8) +NF+CF,
+ (0x16<<8) +NF+CF,
+ (0x17<<8) +VF+NF+CF,
+ (0x18<<8) +XF+VF+NF+CF,
+ (0x19<<8) +XF +NF+CF,
+ (0x14<<8) +VF+NF+CF,
+ (0x15<<8) +NF+CF,
+ (0x16<<8) +NF+CF,
+ (0x17<<8) +VF+NF+CF,
+ (0x18<<8) +XF+VF+NF+CF,
+ (0x19<<8) +XF +NF+CF,
+ (0x20<<8) +YF +NF+CF,
+ (0x21<<8) +YF +VF+NF+CF,
+ (0x22<<8) +YF +VF+NF+CF,
+ (0x23<<8) +YF +NF+CF,
+ (0x24<<8) +YF +VF+NF+CF,
+ (0x25<<8) +YF +NF+CF,
+ (0x26<<8) +YF +NF+CF,
+ (0x27<<8) +YF +VF+NF+CF,
+ (0x28<<8) +YF +XF+VF+NF+CF,
+ (0x29<<8) +YF +XF +NF+CF,
+ (0x24<<8) +YF +VF+NF+CF,
+ (0x25<<8) +YF +NF+CF,
+ (0x26<<8) +YF +NF+CF,
+ (0x27<<8) +YF +VF+NF+CF,
+ (0x28<<8) +YF +XF+VF+NF+CF,
+ (0x29<<8) +YF +XF +NF+CF,
+ (0x30<<8) +YF +VF+NF+CF,
+ (0x31<<8) +YF +NF+CF,
+ (0x32<<8) +YF +NF+CF,
+ (0x33<<8) +YF +VF+NF+CF,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x40<<8) +NF+CF,
+ (0x41<<8) +VF+NF+CF,
+ (0x42<<8) +VF+NF+CF,
+ (0x43<<8) +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x50<<8) +VF+NF+CF,
+ (0x51<<8) +NF+CF,
+ (0x52<<8) +NF+CF,
+ (0x53<<8) +VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x60<<8) +YF +VF+NF+CF,
+ (0x61<<8) +YF +NF+CF,
+ (0x62<<8) +YF +NF+CF,
+ (0x63<<8) +YF +VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x70<<8) +YF +NF+CF,
+ (0x71<<8) +YF +VF+NF+CF,
+ (0x72<<8) +YF +VF+NF+CF,
+ (0x73<<8) +YF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x80<<8)+SF +NF+CF,
+ (0x81<<8)+SF +VF+NF+CF,
+ (0x82<<8)+SF +VF+NF+CF,
+ (0x83<<8)+SF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x90<<8)+SF +VF+NF+CF,
+ (0x91<<8)+SF +NF+CF,
+ (0x92<<8)+SF +NF+CF,
+ (0x93<<8)+SF +VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0xFA<<8)+SF +YF+HF+XF+VF+NF ,
+ (0xFB<<8)+SF +YF+HF+XF +NF ,
+ (0xFC<<8)+SF +YF+HF+XF+VF+NF ,
+ (0xFD<<8)+SF +YF+HF+XF +NF ,
+ (0xFE<<8)+SF +YF+HF+XF +NF ,
+ (0xFF<<8)+SF +YF+HF+XF+VF+NF ,
+ (0x00<<8) +ZF +VF+NF ,
+ (0x01<<8) +NF ,
+ (0x02<<8) +NF ,
+ (0x03<<8) +VF+NF ,
+ (0x04<<8) +NF ,
+ (0x05<<8) +VF+NF ,
+ (0x06<<8) +VF+NF ,
+ (0x07<<8) +NF ,
+ (0x08<<8) +XF +NF ,
+ (0x09<<8) +XF+VF+NF ,
+ (0x0A<<8) +HF+XF+VF+NF ,
+ (0x0B<<8) +HF+XF +NF ,
+ (0x0C<<8) +HF+XF+VF+NF ,
+ (0x0D<<8) +HF+XF +NF ,
+ (0x0E<<8) +HF+XF +NF ,
+ (0x0F<<8) +HF+XF+VF+NF ,
+ (0x10<<8) +NF ,
+ (0x11<<8) +VF+NF ,
+ (0x12<<8) +VF+NF ,
+ (0x13<<8) +NF ,
+ (0x14<<8) +VF+NF ,
+ (0x15<<8) +NF ,
+ (0x16<<8) +NF ,
+ (0x17<<8) +VF+NF ,
+ (0x18<<8) +XF+VF+NF ,
+ (0x19<<8) +XF +NF ,
+ (0x1A<<8) +HF+XF +NF ,
+ (0x1B<<8) +HF+XF+VF+NF ,
+ (0x1C<<8) +HF+XF +NF ,
+ (0x1D<<8) +HF+XF+VF+NF ,
+ (0x1E<<8) +HF+XF+VF+NF ,
+ (0x1F<<8) +HF+XF +NF ,
+ (0x20<<8) +YF +NF ,
+ (0x21<<8) +YF +VF+NF ,
+ (0x22<<8) +YF +VF+NF ,
+ (0x23<<8) +YF +NF ,
+ (0x24<<8) +YF +VF+NF ,
+ (0x25<<8) +YF +NF ,
+ (0x26<<8) +YF +NF ,
+ (0x27<<8) +YF +VF+NF ,
+ (0x28<<8) +YF +XF+VF+NF ,
+ (0x29<<8) +YF +XF +NF ,
+ (0x2A<<8) +YF+HF+XF +NF ,
+ (0x2B<<8) +YF+HF+XF+VF+NF ,
+ (0x2C<<8) +YF+HF+XF +NF ,
+ (0x2D<<8) +YF+HF+XF+VF+NF ,
+ (0x2E<<8) +YF+HF+XF+VF+NF ,
+ (0x2F<<8) +YF+HF+XF +NF ,
+ (0x30<<8) +YF +VF+NF ,
+ (0x31<<8) +YF +NF ,
+ (0x32<<8) +YF +NF ,
+ (0x33<<8) +YF +VF+NF ,
+ (0x34<<8) +YF +NF ,
+ (0x35<<8) +YF +VF+NF ,
+ (0x36<<8) +YF +VF+NF ,
+ (0x37<<8) +YF +NF ,
+ (0x38<<8) +YF +XF +NF ,
+ (0x39<<8) +YF +XF+VF+NF ,
+ (0x3A<<8) +YF+HF+XF+VF+NF ,
+ (0x3B<<8) +YF+HF+XF +NF ,
+ (0x3C<<8) +YF+HF+XF+VF+NF ,
+ (0x3D<<8) +YF+HF+XF +NF ,
+ (0x3E<<8) +YF+HF+XF +NF ,
+ (0x3F<<8) +YF+HF+XF+VF+NF ,
+ (0x40<<8) +NF ,
+ (0x41<<8) +VF+NF ,
+ (0x42<<8) +VF+NF ,
+ (0x43<<8) +NF ,
+ (0x44<<8) +VF+NF ,
+ (0x45<<8) +NF ,
+ (0x46<<8) +NF ,
+ (0x47<<8) +VF+NF ,
+ (0x48<<8) +XF+VF+NF ,
+ (0x49<<8) +XF +NF ,
+ (0x4A<<8) +HF+XF +NF ,
+ (0x4B<<8) +HF+XF+VF+NF ,
+ (0x4C<<8) +HF+XF +NF ,
+ (0x4D<<8) +HF+XF+VF+NF ,
+ (0x4E<<8) +HF+XF+VF+NF ,
+ (0x4F<<8) +HF+XF +NF ,
+ (0x50<<8) +VF+NF ,
+ (0x51<<8) +NF ,
+ (0x52<<8) +NF ,
+ (0x53<<8) +VF+NF ,
+ (0x54<<8) +NF ,
+ (0x55<<8) +VF+NF ,
+ (0x56<<8) +VF+NF ,
+ (0x57<<8) +NF ,
+ (0x58<<8) +XF +NF ,
+ (0x59<<8) +XF+VF+NF ,
+ (0x5A<<8) +HF+XF+VF+NF ,
+ (0x5B<<8) +HF+XF +NF ,
+ (0x5C<<8) +HF+XF+VF+NF ,
+ (0x5D<<8) +HF+XF +NF ,
+ (0x5E<<8) +HF+XF +NF ,
+ (0x5F<<8) +HF+XF+VF+NF ,
+ (0x60<<8) +YF +VF+NF ,
+ (0x61<<8) +YF +NF ,
+ (0x62<<8) +YF +NF ,
+ (0x63<<8) +YF +VF+NF ,
+ (0x64<<8) +YF +NF ,
+ (0x65<<8) +YF +VF+NF ,
+ (0x66<<8) +YF +VF+NF ,
+ (0x67<<8) +YF +NF ,
+ (0x68<<8) +YF +XF +NF ,
+ (0x69<<8) +YF +XF+VF+NF ,
+ (0x6A<<8) +YF+HF+XF+VF+NF ,
+ (0x6B<<8) +YF+HF+XF +NF ,
+ (0x6C<<8) +YF+HF+XF+VF+NF ,
+ (0x6D<<8) +YF+HF+XF +NF ,
+ (0x6E<<8) +YF+HF+XF +NF ,
+ (0x6F<<8) +YF+HF+XF+VF+NF ,
+ (0x70<<8) +YF +NF ,
+ (0x71<<8) +YF +VF+NF ,
+ (0x72<<8) +YF +VF+NF ,
+ (0x73<<8) +YF +NF ,
+ (0x74<<8) +YF +VF+NF ,
+ (0x75<<8) +YF +NF ,
+ (0x76<<8) +YF +NF ,
+ (0x77<<8) +YF +VF+NF ,
+ (0x78<<8) +YF +XF+VF+NF ,
+ (0x79<<8) +YF +XF +NF ,
+ (0x7A<<8) +YF+HF+XF +NF ,
+ (0x7B<<8) +YF+HF+XF+VF+NF ,
+ (0x7C<<8) +YF+HF+XF +NF ,
+ (0x7D<<8) +YF+HF+XF+VF+NF ,
+ (0x7E<<8) +YF+HF+XF+VF+NF ,
+ (0x7F<<8) +YF+HF+XF +NF ,
+ (0x80<<8)+SF +NF ,
+ (0x81<<8)+SF +VF+NF ,
+ (0x82<<8)+SF +VF+NF ,
+ (0x83<<8)+SF +NF ,
+ (0x84<<8)+SF +VF+NF ,
+ (0x85<<8)+SF +NF ,
+ (0x86<<8)+SF +NF ,
+ (0x87<<8)+SF +VF+NF ,
+ (0x88<<8)+SF +XF+VF+NF ,
+ (0x89<<8)+SF +XF +NF ,
+ (0x8A<<8)+SF +HF+XF +NF ,
+ (0x8B<<8)+SF +HF+XF+VF+NF ,
+ (0x8C<<8)+SF +HF+XF +NF ,
+ (0x8D<<8)+SF +HF+XF+VF+NF ,
+ (0x8E<<8)+SF +HF+XF+VF+NF ,
+ (0x8F<<8)+SF +HF+XF +NF ,
+ (0x90<<8)+SF +VF+NF ,
+ (0x91<<8)+SF +NF ,
+ (0x92<<8)+SF +NF ,
+ (0x93<<8)+SF +VF+NF ,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x3A<<8) +YF+HF+XF+VF+NF+CF,
+ (0x3B<<8) +YF+HF+XF +NF+CF,
+ (0x3C<<8) +YF+HF+XF+VF+NF+CF,
+ (0x3D<<8) +YF+HF+XF +NF+CF,
+ (0x3E<<8) +YF+HF+XF +NF+CF,
+ (0x3F<<8) +YF+HF+XF+VF+NF+CF,
+ (0x40<<8) +NF+CF,
+ (0x41<<8) +VF+NF+CF,
+ (0x42<<8) +VF+NF+CF,
+ (0x43<<8) +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x4A<<8) +HF+XF +NF+CF,
+ (0x4B<<8) +HF+XF+VF+NF+CF,
+ (0x4C<<8) +HF+XF +NF+CF,
+ (0x4D<<8) +HF+XF+VF+NF+CF,
+ (0x4E<<8) +HF+XF+VF+NF+CF,
+ (0x4F<<8) +HF+XF +NF+CF,
+ (0x50<<8) +VF+NF+CF,
+ (0x51<<8) +NF+CF,
+ (0x52<<8) +NF+CF,
+ (0x53<<8) +VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x5A<<8) +HF+XF+VF+NF+CF,
+ (0x5B<<8) +HF+XF +NF+CF,
+ (0x5C<<8) +HF+XF+VF+NF+CF,
+ (0x5D<<8) +HF+XF +NF+CF,
+ (0x5E<<8) +HF+XF +NF+CF,
+ (0x5F<<8) +HF+XF+VF+NF+CF,
+ (0x60<<8) +YF +VF+NF+CF,
+ (0x61<<8) +YF +NF+CF,
+ (0x62<<8) +YF +NF+CF,
+ (0x63<<8) +YF +VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x6A<<8) +YF+HF+XF+VF+NF+CF,
+ (0x6B<<8) +YF+HF+XF +NF+CF,
+ (0x6C<<8) +YF+HF+XF+VF+NF+CF,
+ (0x6D<<8) +YF+HF+XF +NF+CF,
+ (0x6E<<8) +YF+HF+XF +NF+CF,
+ (0x6F<<8) +YF+HF+XF+VF+NF+CF,
+ (0x70<<8) +YF +NF+CF,
+ (0x71<<8) +YF +VF+NF+CF,
+ (0x72<<8) +YF +VF+NF+CF,
+ (0x73<<8) +YF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x7A<<8) +YF+HF+XF +NF+CF,
+ (0x7B<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7C<<8) +YF+HF+XF +NF+CF,
+ (0x7D<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7E<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7F<<8) +YF+HF+XF +NF+CF,
+ (0x80<<8)+SF +NF+CF,
+ (0x81<<8)+SF +VF+NF+CF,
+ (0x82<<8)+SF +VF+NF+CF,
+ (0x83<<8)+SF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x8A<<8)+SF +HF+XF +NF+CF,
+ (0x8B<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8C<<8)+SF +HF+XF +NF+CF,
+ (0x8D<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8E<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8F<<8)+SF +HF+XF +NF+CF,
+ (0x90<<8)+SF +VF+NF+CF,
+ (0x91<<8)+SF +NF+CF,
+ (0x92<<8)+SF +NF+CF,
+ (0x93<<8)+SF +VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0x9A<<8)+SF +HF+XF+VF+NF+CF,
+ (0x9B<<8)+SF +HF+XF +NF+CF,
+ (0x9C<<8)+SF +HF+XF+VF+NF+CF,
+ (0x9D<<8)+SF +HF+XF +NF+CF,
+ (0x9E<<8)+SF +HF+XF +NF+CF,
+ (0x9F<<8)+SF +HF+XF+VF+NF+CF,
+ (0xA0<<8)+SF +YF +VF+NF+CF,
+ (0xA1<<8)+SF +YF +NF+CF,
+ (0xA2<<8)+SF +YF +NF+CF,
+ (0xA3<<8)+SF +YF +VF+NF+CF,
+ (0xA4<<8)+SF +YF +NF+CF,
+ (0xA5<<8)+SF +YF +VF+NF+CF,
+ (0xA6<<8)+SF +YF +VF+NF+CF,
+ (0xA7<<8)+SF +YF +NF+CF,
+ (0xA8<<8)+SF +YF +XF +NF+CF,
+ (0xA9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xAA<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xAB<<8)+SF +YF+HF+XF +NF+CF,
+ (0xAC<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xAD<<8)+SF +YF+HF+XF +NF+CF,
+ (0xAE<<8)+SF +YF+HF+XF +NF+CF,
+ (0xAF<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xB0<<8)+SF +YF +NF+CF,
+ (0xB1<<8)+SF +YF +VF+NF+CF,
+ (0xB2<<8)+SF +YF +VF+NF+CF,
+ (0xB3<<8)+SF +YF +NF+CF,
+ (0xB4<<8)+SF +YF +VF+NF+CF,
+ (0xB5<<8)+SF +YF +NF+CF,
+ (0xB6<<8)+SF +YF +NF+CF,
+ (0xB7<<8)+SF +YF +VF+NF+CF,
+ (0xB8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xB9<<8)+SF +YF +XF +NF+CF,
+ (0xBA<<8)+SF +YF+HF+XF +NF+CF,
+ (0xBB<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xBC<<8)+SF +YF+HF+XF +NF+CF,
+ (0xBD<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xBE<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xBF<<8)+SF +YF+HF+XF +NF+CF,
+ (0xC0<<8)+SF +VF+NF+CF,
+ (0xC1<<8)+SF +NF+CF,
+ (0xC2<<8)+SF +NF+CF,
+ (0xC3<<8)+SF +VF+NF+CF,
+ (0xC4<<8)+SF +NF+CF,
+ (0xC5<<8)+SF +VF+NF+CF,
+ (0xC6<<8)+SF +VF+NF+CF,
+ (0xC7<<8)+SF +NF+CF,
+ (0xC8<<8)+SF +XF +NF+CF,
+ (0xC9<<8)+SF +XF+VF+NF+CF,
+ (0xCA<<8)+SF +HF+XF+VF+NF+CF,
+ (0xCB<<8)+SF +HF+XF +NF+CF,
+ (0xCC<<8)+SF +HF+XF+VF+NF+CF,
+ (0xCD<<8)+SF +HF+XF +NF+CF,
+ (0xCE<<8)+SF +HF+XF +NF+CF,
+ (0xCF<<8)+SF +HF+XF+VF+NF+CF,
+ (0xD0<<8)+SF +NF+CF,
+ (0xD1<<8)+SF +VF+NF+CF,
+ (0xD2<<8)+SF +VF+NF+CF,
+ (0xD3<<8)+SF +NF+CF,
+ (0xD4<<8)+SF +VF+NF+CF,
+ (0xD5<<8)+SF +NF+CF,
+ (0xD6<<8)+SF +NF+CF,
+ (0xD7<<8)+SF +VF+NF+CF,
+ (0xD8<<8)+SF +XF+VF+NF+CF,
+ (0xD9<<8)+SF +XF +NF+CF,
+ (0xDA<<8)+SF +HF+XF +NF+CF,
+ (0xDB<<8)+SF +HF+XF+VF+NF+CF,
+ (0xDC<<8)+SF +HF+XF +NF+CF,
+ (0xDD<<8)+SF +HF+XF+VF+NF+CF,
+ (0xDE<<8)+SF +HF+XF+VF+NF+CF,
+ (0xDF<<8)+SF +HF+XF +NF+CF,
+ (0xE0<<8)+SF +YF +NF+CF,
+ (0xE1<<8)+SF +YF +VF+NF+CF,
+ (0xE2<<8)+SF +YF +VF+NF+CF,
+ (0xE3<<8)+SF +YF +NF+CF,
+ (0xE4<<8)+SF +YF +VF+NF+CF,
+ (0xE5<<8)+SF +YF +NF+CF,
+ (0xE6<<8)+SF +YF +NF+CF,
+ (0xE7<<8)+SF +YF +VF+NF+CF,
+ (0xE8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xE9<<8)+SF +YF +XF +NF+CF,
+ (0xEA<<8)+SF +YF+HF+XF +NF+CF,
+ (0xEB<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xEC<<8)+SF +YF+HF+XF +NF+CF,
+ (0xED<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xEE<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xEF<<8)+SF +YF+HF+XF +NF+CF,
+ (0xF0<<8)+SF +YF +VF+NF+CF,
+ (0xF1<<8)+SF +YF +NF+CF,
+ (0xF2<<8)+SF +YF +NF+CF,
+ (0xF3<<8)+SF +YF +VF+NF+CF,
+ (0xF4<<8)+SF +YF +NF+CF,
+ (0xF5<<8)+SF +YF +VF+NF+CF,
+ (0xF6<<8)+SF +YF +VF+NF+CF,
+ (0xF7<<8)+SF +YF +NF+CF,
+ (0xF8<<8)+SF +YF +XF +NF+CF,
+ (0xF9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xFA<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xFB<<8)+SF +YF+HF+XF +NF+CF,
+ (0xFC<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xFD<<8)+SF +YF+HF+XF +NF+CF,
+ (0xFE<<8)+SF +YF+HF+XF +NF+CF,
+ (0xFF<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0x00<<8) +ZF +VF+NF+CF,
+ (0x01<<8) +NF+CF,
+ (0x02<<8) +NF+CF,
+ (0x03<<8) +VF+NF+CF,
+ (0x04<<8) +NF+CF,
+ (0x05<<8) +VF+NF+CF,
+ (0x06<<8) +VF+NF+CF,
+ (0x07<<8) +NF+CF,
+ (0x08<<8) +XF +NF+CF,
+ (0x09<<8) +XF+VF+NF+CF,
+ (0x0A<<8) +HF+XF+VF+NF+CF,
+ (0x0B<<8) +HF+XF +NF+CF,
+ (0x0C<<8) +HF+XF+VF+NF+CF,
+ (0x0D<<8) +HF+XF +NF+CF,
+ (0x0E<<8) +HF+XF +NF+CF,
+ (0x0F<<8) +HF+XF+VF+NF+CF,
+ (0x10<<8) +NF+CF,
+ (0x11<<8) +VF+NF+CF,
+ (0x12<<8) +VF+NF+CF,
+ (0x13<<8) +NF+CF,
+ (0x14<<8) +VF+NF+CF,
+ (0x15<<8) +NF+CF,
+ (0x16<<8) +NF+CF,
+ (0x17<<8) +VF+NF+CF,
+ (0x18<<8) +XF+VF+NF+CF,
+ (0x19<<8) +XF +NF+CF,
+ (0x1A<<8) +HF+XF +NF+CF,
+ (0x1B<<8) +HF+XF+VF+NF+CF,
+ (0x1C<<8) +HF+XF +NF+CF,
+ (0x1D<<8) +HF+XF+VF+NF+CF,
+ (0x1E<<8) +HF+XF+VF+NF+CF,
+ (0x1F<<8) +HF+XF +NF+CF,
+ (0x20<<8) +YF +NF+CF,
+ (0x21<<8) +YF +VF+NF+CF,
+ (0x22<<8) +YF +VF+NF+CF,
+ (0x23<<8) +YF +NF+CF,
+ (0x24<<8) +YF +VF+NF+CF,
+ (0x25<<8) +YF +NF+CF,
+ (0x26<<8) +YF +NF+CF,
+ (0x27<<8) +YF +VF+NF+CF,
+ (0x28<<8) +YF +XF+VF+NF+CF,
+ (0x29<<8) +YF +XF +NF+CF,
+ (0x2A<<8) +YF+HF+XF +NF+CF,
+ (0x2B<<8) +YF+HF+XF+VF+NF+CF,
+ (0x2C<<8) +YF+HF+XF +NF+CF,
+ (0x2D<<8) +YF+HF+XF+VF+NF+CF,
+ (0x2E<<8) +YF+HF+XF+VF+NF+CF,
+ (0x2F<<8) +YF+HF+XF +NF+CF,
+ (0x30<<8) +YF +VF+NF+CF,
+ (0x31<<8) +YF +NF+CF,
+ (0x32<<8) +YF +NF+CF,
+ (0x33<<8) +YF +VF+NF+CF,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x3A<<8) +YF+HF+XF+VF+NF+CF,
+ (0x3B<<8) +YF+HF+XF +NF+CF,
+ (0x3C<<8) +YF+HF+XF+VF+NF+CF,
+ (0x3D<<8) +YF+HF+XF +NF+CF,
+ (0x3E<<8) +YF+HF+XF +NF+CF,
+ (0x3F<<8) +YF+HF+XF+VF+NF+CF,
+ (0x40<<8) +NF+CF,
+ (0x41<<8) +VF+NF+CF,
+ (0x42<<8) +VF+NF+CF,
+ (0x43<<8) +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x4A<<8) +HF+XF +NF+CF,
+ (0x4B<<8) +HF+XF+VF+NF+CF,
+ (0x4C<<8) +HF+XF +NF+CF,
+ (0x4D<<8) +HF+XF+VF+NF+CF,
+ (0x4E<<8) +HF+XF+VF+NF+CF,
+ (0x4F<<8) +HF+XF +NF+CF,
+ (0x50<<8) +VF+NF+CF,
+ (0x51<<8) +NF+CF,
+ (0x52<<8) +NF+CF,
+ (0x53<<8) +VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x5A<<8) +HF+XF+VF+NF+CF,
+ (0x5B<<8) +HF+XF +NF+CF,
+ (0x5C<<8) +HF+XF+VF+NF+CF,
+ (0x5D<<8) +HF+XF +NF+CF,
+ (0x5E<<8) +HF+XF +NF+CF,
+ (0x5F<<8) +HF+XF+VF+NF+CF,
+ (0x60<<8) +YF +VF+NF+CF,
+ (0x61<<8) +YF +NF+CF,
+ (0x62<<8) +YF +NF+CF,
+ (0x63<<8) +YF +VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x6A<<8) +YF+HF+XF+VF+NF+CF,
+ (0x6B<<8) +YF+HF+XF +NF+CF,
+ (0x6C<<8) +YF+HF+XF+VF+NF+CF,
+ (0x6D<<8) +YF+HF+XF +NF+CF,
+ (0x6E<<8) +YF+HF+XF +NF+CF,
+ (0x6F<<8) +YF+HF+XF+VF+NF+CF,
+ (0x70<<8) +YF +NF+CF,
+ (0x71<<8) +YF +VF+NF+CF,
+ (0x72<<8) +YF +VF+NF+CF,
+ (0x73<<8) +YF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x7A<<8) +YF+HF+XF +NF+CF,
+ (0x7B<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7C<<8) +YF+HF+XF +NF+CF,
+ (0x7D<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7E<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7F<<8) +YF+HF+XF +NF+CF,
+ (0x80<<8)+SF +NF+CF,
+ (0x81<<8)+SF +VF+NF+CF,
+ (0x82<<8)+SF +VF+NF+CF,
+ (0x83<<8)+SF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x8A<<8)+SF +HF+XF +NF+CF,
+ (0x8B<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8C<<8)+SF +HF+XF +NF+CF,
+ (0x8D<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8E<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8F<<8)+SF +HF+XF +NF+CF,
+ (0x90<<8)+SF +VF+NF+CF,
+ (0x91<<8)+SF +NF+CF,
+ (0x92<<8)+SF +NF+CF,
+ (0x93<<8)+SF +VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF
+};
diff --git a/src/emu/cpu/i86/ea.h b/src/emu/cpu/i86/ea.h
new file mode 100644
index 00000000000..3dbb6e0e802
--- /dev/null
+++ b/src/emu/cpu/i86/ea.h
@@ -0,0 +1,58 @@
+static unsigned EA;
+static UINT16 EO; /* HJB 12/13/98 effective offset of the address (before segment is added) */
+
+static unsigned EA_000(void) { i8086_ICount-=7; EO=(WORD)(I.regs.w[BX]+I.regs.w[SI]); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_001(void) { i8086_ICount-=8; EO=(WORD)(I.regs.w[BX]+I.regs.w[DI]); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_002(void) { i8086_ICount-=8; EO=(WORD)(I.regs.w[BP]+I.regs.w[SI]); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_003(void) { i8086_ICount-=7; EO=(WORD)(I.regs.w[BP]+I.regs.w[DI]); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_004(void) { i8086_ICount-=5; EO=I.regs.w[SI]; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_005(void) { i8086_ICount-=5; EO=I.regs.w[DI]; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_006(void) { i8086_ICount-=6; EO=FETCHOP; EO+=FETCHOP<<8; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_007(void) { i8086_ICount-=5; EO=I.regs.w[BX]; EA=DefaultBase(DS)+EO; return EA; }
+
+static unsigned EA_100(void) { i8086_ICount-=11; EO=(WORD)(I.regs.w[BX]+I.regs.w[SI]+(INT8)FETCHOP); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_101(void) { i8086_ICount-=12; EO=(WORD)(I.regs.w[BX]+I.regs.w[DI]+(INT8)FETCHOP); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_102(void) { i8086_ICount-=12; EO=(WORD)(I.regs.w[BP]+I.regs.w[SI]+(INT8)FETCHOP); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_103(void) { i8086_ICount-=11; EO=(WORD)(I.regs.w[BP]+I.regs.w[DI]+(INT8)FETCHOP); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_104(void) { i8086_ICount-=9; EO=(WORD)(I.regs.w[SI]+(INT8)FETCHOP); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_105(void) { i8086_ICount-=9; EO=(WORD)(I.regs.w[DI]+(INT8)FETCHOP); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_106(void) { i8086_ICount-=9; EO=(WORD)(I.regs.w[BP]+(INT8)FETCHOP); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_107(void) { i8086_ICount-=9; EO=(WORD)(I.regs.w[BX]+(INT8)FETCHOP); EA=DefaultBase(DS)+EO; return EA; }
+
+static unsigned EA_200(void) { i8086_ICount-=11; EO=FETCHOP; EO+=FETCHOP<<8; EO+=I.regs.w[BX]+I.regs.w[SI]; EA=DefaultBase(DS)+(WORD)EO; return EA; }
+static unsigned EA_201(void) { i8086_ICount-=12; EO=FETCHOP; EO+=FETCHOP<<8; EO+=I.regs.w[BX]+I.regs.w[DI]; EA=DefaultBase(DS)+(WORD)EO; return EA; }
+static unsigned EA_202(void) { i8086_ICount-=12; EO=FETCHOP; EO+=FETCHOP<<8; EO+=I.regs.w[BP]+I.regs.w[SI]; EA=DefaultBase(SS)+(WORD)EO; return EA; }
+static unsigned EA_203(void) { i8086_ICount-=11; EO=FETCHOP; EO+=FETCHOP<<8; EO+=I.regs.w[BP]+I.regs.w[DI]; EA=DefaultBase(SS)+(WORD)EO; return EA; }
+static unsigned EA_204(void) { i8086_ICount-=9; EO=FETCHOP; EO+=FETCHOP<<8; EO+=I.regs.w[SI]; EA=DefaultBase(DS)+(WORD)EO; return EA; }
+static unsigned EA_205(void) { i8086_ICount-=9; EO=FETCHOP; EO+=FETCHOP<<8; EO+=I.regs.w[DI]; EA=DefaultBase(DS)+(WORD)EO; return EA; }
+static unsigned EA_206(void) { i8086_ICount-=9; EO=FETCHOP; EO+=FETCHOP<<8; EO+=I.regs.w[BP]; EA=DefaultBase(SS)+(WORD)EO; return EA; }
+static unsigned EA_207(void) { i8086_ICount-=9; EO=FETCHOP; EO+=FETCHOP<<8; EO+=I.regs.w[BX]; EA=DefaultBase(DS)+(WORD)EO; return EA; }
+
+static unsigned (*GetEA[192])(void)={
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207
+};
diff --git a/src/emu/cpu/i86/host.h b/src/emu/cpu/i86/host.h
new file mode 100644
index 00000000000..d19042c7e28
--- /dev/null
+++ b/src/emu/cpu/i86/host.h
@@ -0,0 +1,12 @@
+/*****************************************************************************/
+/* host dependent types */
+
+/*#define BIGCASE*/
+
+#include "cpuintrf.h"
+
+typedef UINT8 BOOLEAN;
+
+typedef UINT8 BYTE;
+typedef UINT16 WORD;
+typedef UINT32 DWORD;
diff --git a/src/emu/cpu/i86/i186intf.h b/src/emu/cpu/i86/i186intf.h
new file mode 100644
index 00000000000..bfc6275bb6e
--- /dev/null
+++ b/src/emu/cpu/i86/i186intf.h
@@ -0,0 +1,10 @@
+/* ASG 971222 -- rewrote this interface */
+#ifndef __I186INTR_H_
+#define __I186INTR_H_
+
+#include "i86intf.h"
+
+/* Public functions */
+void i80186_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/i86/i188intf.h b/src/emu/cpu/i86/i188intf.h
new file mode 100644
index 00000000000..49675a8a332
--- /dev/null
+++ b/src/emu/cpu/i86/i188intf.h
@@ -0,0 +1,9 @@
+#ifndef __I188INTR_H_
+#define __I188INTR_H_
+
+#include "i186intf.h"
+
+/* Public functions */
+void i80188_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/i86/i286.c b/src/emu/cpu/i86/i286.c
new file mode 100644
index 00000000000..f4baf825069
--- /dev/null
+++ b/src/emu/cpu/i86/i286.c
@@ -0,0 +1,510 @@
+/****************************************************************************
+* real mode i286 emulator v1.4 by Fabrice Frances *
+* (initial work based on David Hedley's pcemu) *
+****************************************************************************/
+
+#include "host.h"
+#include "debugger.h"
+
+
+/* All post-i286 CPUs have a 16MB address space */
+#define AMASK I.amask
+
+
+#define i8086_ICount i80286_ICount
+
+#include "i286.h"
+#include "i286intf.h"
+
+
+#include "i86time.c"
+#include "i86mem.h"
+
+/***************************************************************************/
+/* cpu state */
+/***************************************************************************/
+/* I86 registers */
+typedef union
+{ /* eight general registers */
+ UINT16 w[8]; /* viewed as 16 bits registers */
+ UINT8 b[16]; /* or as 8 bit registers */
+} i80286basicregs;
+
+typedef struct
+{
+ i80286basicregs regs;
+ UINT32 amask; /* address mask */
+ UINT32 pc;
+ UINT32 prevpc;
+ UINT16 flags;
+ UINT16 msw;
+ UINT32 base[4];
+ UINT16 sregs[4];
+ UINT16 limit[4];
+ UINT8 rights[4];
+ struct {
+ UINT32 base;
+ UINT16 limit;
+ } gdtr, idtr;
+ struct {
+ UINT16 sel;
+ UINT32 base;
+ UINT16 limit;
+ UINT8 rights;
+ } ldtr, tr;
+ int (*irq_callback)(int irqline);
+ INT32 AuxVal, OverVal, SignVal, ZeroVal, CarryVal, DirVal; /* 0 or non-0 valued flags */
+ UINT8 ParityVal;
+ UINT8 TF, IF; /* 0 or 1 valued flags */
+ UINT8 int_vector;
+ INT8 nmi_state;
+ INT8 irq_state;
+ INT8 test_state; /* PJB 03/05 */
+ INT32 extra_cycles; /* extra cycles for interrupts */
+
+ memory_interface mem;
+} i80286_Regs;
+
+int i80286_ICount;
+
+static i80286_Regs I;
+static unsigned prefix_base; /* base address of the latest prefix segment */
+static char seg_prefix; /* prefix segment indicator */
+
+#define INT_IRQ 0x01
+#define NMI_IRQ 0x02
+
+static UINT8 parity_table[256];
+
+static struct i80x86_timing cycles;
+
+/***************************************************************************/
+
+#define I80286
+#define PREFIX(fname) i80286##fname
+#define PREFIX86(fname) i80286##fname
+#define PREFIX186(fname) i80286##fname
+#define PREFIX286(fname) i80286##fname
+
+#include "ea.h"
+#include "modrm.h"
+#include "instr86.h"
+#include "instr186.h"
+#include "instr286.h"
+#include "table286.h"
+#include "instr86.c"
+#include "instr186.c"
+#include "instr286.c"
+#include "i86mem.c"
+
+static void i80286_urinit(void)
+{
+ unsigned int i,j,c;
+ static const BREGS reg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH };
+
+ for (i = 0;i < 256; i++)
+ {
+ for (j = i, c = 0; j > 0; j >>= 1)
+ if (j & 1) c++;
+
+ parity_table[i] = !(c & 1);
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3];
+ Mod_RM.reg.w[i] = (WREGS) ( (i & 0x38) >> 3) ;
+ }
+
+ for (i = 0xc0; i < 0x100; i++)
+ {
+ Mod_RM.RM.w[i] = (WREGS)( i & 7 );
+ Mod_RM.RM.b[i] = (BREGS)reg_name[i & 7];
+ }
+}
+
+static void i80286_set_a20_line(int state)
+{
+ I.amask = state ? 0x00ffffff : 0x000fffff;
+}
+
+static void i80286_reset (void)
+{
+ static int urinit=1;
+
+ /* in my docu not all registers are initialized! */
+ if (urinit) {
+ i80286_urinit();
+ urinit=0;
+
+ }
+
+ I.sregs[CS] = 0xf000;
+ I.base[CS] = 0xff0000;
+ /* temporary, until I have the right reset vector working */
+ I.base[CS] = I.sregs[CS] << 4;
+ I.pc = 0xffff0;
+ I.limit[CS]=I.limit[SS]=I.limit[DS]=I.limit[ES]=0xffff;
+ I.sregs[DS]=I.sregs[SS]=I.sregs[ES]=0;
+ I.base[DS]=I.base[SS]=I.base[ES]=0;
+ I.msw=0xfff0;
+ I.flags=2;
+ ExpandFlags(I.flags);
+ I.idtr.base=0;I.idtr.limit=0x3ff;
+
+ CHANGE_PC(I.pc);
+
+}
+
+/****************************************************************************/
+
+/* ASG 971222 -- added these interface functions */
+
+static void i80286_get_context(void *dst)
+{
+ if( dst )
+ *(i80286_Regs*)dst = I;
+}
+
+static void i80286_set_context(void *src)
+{
+ if( src )
+ {
+ I = *(i80286_Regs*)src;
+ if (PM) {
+
+ } else {
+ I.base[CS] = SegBase(CS);
+ I.base[DS] = SegBase(DS);
+ I.base[ES] = SegBase(ES);
+ I.base[SS] = SegBase(SS);
+ }
+ CHANGE_PC(I.pc);
+ }
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (I.nmi_state == state)
+ return;
+ I.nmi_state = state;
+
+ /* on a rising edge, signal the NMI */
+ if (state != CLEAR_LINE)
+ PREFIX(_interrupt)(I8086_NMI_INT_VECTOR);
+ }
+ else
+ {
+ I.irq_state = state;
+
+ /* if the IF is set, signal an interrupt */
+ if (state != CLEAR_LINE && I.IF)
+ PREFIX(_interrupt)(-1);
+ }
+}
+
+static int i80286_execute(int num_cycles)
+{
+ /* copy over the cycle counts if they're not correct */
+ if (cycles.id != 80286)
+ cycles = i80286_cycles;
+
+ /* adjust for any interrupts that came in */
+ i80286_ICount = num_cycles;
+ i80286_ICount -= I.extra_cycles;
+ I.extra_cycles = 0;
+
+ /* run until we're out */
+ while(i80286_ICount>0)
+ {
+
+//#define VERBOSE_DEBUG
+#ifdef VERBOSE_DEBUG
+ mame_printf_debug("[%04x:%04x]=%02x\tF:%04x\tAX=%04x\tBX=%04x\tCX=%04x\tDX=%04x %d%d%d%d%d%d%d%d%d\n",I.sregs[CS],I.pc - I.base[CS],ReadByte(I.pc),I.flags,I.regs.w[AX],I.regs.w[BX],I.regs.w[CX],I.regs.w[DX], I.AuxVal?1:0, I.OverVal?1:0, I.SignVal?1:0, I.ZeroVal?1:0, I.CarryVal?1:0, I.ParityVal?1:0,I.TF, I.IF, I.DirVal<0?1:0);
+#endif
+
+ CALL_MAME_DEBUG;
+
+ seg_prefix=FALSE;
+ I.prevpc = I.pc;
+
+ TABLE286 // call instruction
+ }
+
+ /* adjust for any interrupts that came in */
+ i80286_ICount -= I.extra_cycles;
+ I.extra_cycles = 0;
+
+ return num_cycles - i80286_ICount;
+}
+
+extern int i386_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom, int mode);
+
+#ifdef MAME_DEBUG
+static offs_t i80286_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return i386_dasm_one(buffer, pc, oprom, 16);
+}
+#endif /* MAME_DEBUG */
+
+static void i80286_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ static const char type[] = "80286";
+ state_save_register_item_array(type, index, I.regs.w);
+ state_save_register_item(type, index, I.amask);
+ state_save_register_item(type, index, I.pc);
+ state_save_register_item(type, index, I.prevpc);
+ state_save_register_item(type, index, I.msw);
+ state_save_register_item_array(type, index, I.base);
+ state_save_register_item_array(type, index, I.sregs);
+ state_save_register_item_array(type, index, I.limit);
+ state_save_register_item_array(type, index, I.rights);
+ state_save_register_item(type, index, I.gdtr.base);
+ state_save_register_item(type, index, I.gdtr.limit);
+ state_save_register_item(type, index, I.idtr.base);
+ state_save_register_item(type, index, I.idtr.limit);
+ state_save_register_item(type, index, I.ldtr.sel);
+ state_save_register_item(type, index, I.ldtr.base);
+ state_save_register_item(type, index, I.ldtr.limit);
+ state_save_register_item(type, index, I.ldtr.rights);
+ state_save_register_item(type, index, I.tr.sel);
+ state_save_register_item(type, index, I.tr.base);
+ state_save_register_item(type, index, I.tr.limit);
+ state_save_register_item(type, index, I.tr.rights);
+ state_save_register_item(type, index, I.AuxVal);
+ state_save_register_item(type, index, I.OverVal);
+ state_save_register_item(type, index, I.SignVal);
+ state_save_register_item(type, index, I.ZeroVal);
+ state_save_register_item(type, index, I.CarryVal);
+ state_save_register_item(type, index, I.DirVal);
+ state_save_register_item(type, index, I.ParityVal);
+ state_save_register_item(type, index, I.TF);
+ state_save_register_item(type, index, I.IF);
+ state_save_register_item(type, index, I.int_vector);
+ state_save_register_item(type, index, I.nmi_state);
+ state_save_register_item(type, index, I.irq_state);
+ state_save_register_item(type, index, I.extra_cycles);
+
+ I.irq_callback = irqcallback;
+
+ /* If a reset parameter is given, take it as pointer to an address mask */
+ if( config )
+ I.amask = *(unsigned*)config;
+ else
+ I.amask = 0x00ffff;
+
+ configure_memory_16bit();
+}
+
+
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void i80286_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_A20: i80286_set_a20_line(info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I80286_PC:
+ if (PM)
+ {
+ /* protected mode NYI */
+ }
+ else
+ {
+ if (info->i - I.base[CS] >= 0x10000)
+ {
+ I.base[CS] = info->i & 0xffff0;
+ I.sregs[CS] = I.base[CS] >> 4;
+ }
+ I.pc = info->i;
+ }
+ break;
+
+ case CPUINFO_INT_REGISTER + I80286_IP: I.pc = I.base[CS] + info->i; break;
+ case CPUINFO_INT_SP:
+ if (PM)
+ {
+ /* protected mode NYI */
+ }
+ else
+ {
+ if (info->i - I.base[SS] < 0x10000)
+ {
+ I.regs.w[SP] = info->i - I.base[SS];
+ }
+ else
+ {
+ I.base[SS] = info->i & 0xffff0;
+ I.sregs[SS] = I.base[SS] >> 4;
+ I.regs.w[SP] = info->i & 0x0000f;
+ }
+ }
+ break;
+
+ case CPUINFO_INT_REGISTER + I80286_SP: I.regs.w[SP] = info->i; break;
+ case CPUINFO_INT_REGISTER + I80286_FLAGS: I.flags = info->i; ExpandFlags(info->i); break;
+ case CPUINFO_INT_REGISTER + I80286_AX: I.regs.w[AX] = info->i; break;
+ case CPUINFO_INT_REGISTER + I80286_CX: I.regs.w[CX] = info->i; break;
+ case CPUINFO_INT_REGISTER + I80286_DX: I.regs.w[DX] = info->i; break;
+ case CPUINFO_INT_REGISTER + I80286_BX: I.regs.w[BX] = info->i; break;
+ case CPUINFO_INT_REGISTER + I80286_BP: I.regs.w[BP] = info->i; break;
+ case CPUINFO_INT_REGISTER + I80286_SI: I.regs.w[SI] = info->i; break;
+ case CPUINFO_INT_REGISTER + I80286_DI: I.regs.w[DI] = info->i; break;
+ case CPUINFO_INT_REGISTER + I80286_ES: I.sregs[ES] = info->i; I.base[ES] = SegBase(ES); break;
+ case CPUINFO_INT_REGISTER + I80286_CS: I.sregs[CS] = info->i; I.base[CS] = SegBase(CS); break;
+ case CPUINFO_INT_REGISTER + I80286_SS: I.sregs[SS] = info->i; I.base[SS] = SegBase(SS); break;
+ case CPUINFO_INT_REGISTER + I80286_DS: I.sregs[DS] = info->i; I.base[DS] = SegBase(DS); break;
+ case CPUINFO_INT_REGISTER + I80286_VECTOR: I.int_vector = info->i; break;
+ }
+}
+
+
+
+/****************************************************************************
+ * Generic get_info
+ ****************************************************************************/
+
+void i80286_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(I); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 50; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = I.irq_state; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = I.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = I.prevpc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I80286_PC: info->i = I.pc; break;
+ case CPUINFO_INT_REGISTER + I80286_IP: info->i = I.pc - I.base[CS]; break;
+ case CPUINFO_INT_SP: info->i = I.base[SS] + I.regs.w[SP]; break;
+ case CPUINFO_INT_REGISTER + I80286_SP: info->i = I.regs.w[SP]; break;
+ case CPUINFO_INT_REGISTER + I80286_FLAGS: I.flags = CompressFlags(); info->i = I.flags; break;
+ case CPUINFO_INT_REGISTER + I80286_AX: info->i = I.regs.w[AX]; break;
+ case CPUINFO_INT_REGISTER + I80286_CX: info->i = I.regs.w[CX]; break;
+ case CPUINFO_INT_REGISTER + I80286_DX: info->i = I.regs.w[DX]; break;
+ case CPUINFO_INT_REGISTER + I80286_BX: info->i = I.regs.w[BX]; break;
+ case CPUINFO_INT_REGISTER + I80286_BP: info->i = I.regs.w[BP]; break;
+ case CPUINFO_INT_REGISTER + I80286_SI: info->i = I.regs.w[SI]; break;
+ case CPUINFO_INT_REGISTER + I80286_DI: info->i = I.regs.w[DI]; break;
+ case CPUINFO_INT_REGISTER + I80286_ES: info->i = I.sregs[ES]; break;
+ case CPUINFO_INT_REGISTER + I80286_CS: info->i = I.sregs[CS]; break;
+ case CPUINFO_INT_REGISTER + I80286_SS: info->i = I.sregs[SS]; break;
+ case CPUINFO_INT_REGISTER + I80286_DS: info->i = I.sregs[DS]; break;
+ case CPUINFO_INT_REGISTER + I80286_VECTOR: info->i = I.int_vector; break;
+ case CPUINFO_INT_REGISTER + I80286_MSW: info->i = I.msw; break;
+ case CPUINFO_INT_REGISTER + I80286_GDTR_BASE: info->i = I.gdtr.base; break;
+ case CPUINFO_INT_REGISTER + I80286_GDTR_LIMIT: info->i = I.gdtr.limit; break;
+ case CPUINFO_INT_REGISTER + I80286_IDTR_BASE: info->i = I.idtr.base; break;
+ case CPUINFO_INT_REGISTER + I80286_IDTR_LIMIT: info->i = I.idtr.limit; break;
+ case CPUINFO_INT_REGISTER + I80286_LDTR_BASE: info->i = I.ldtr.base; break;
+ case CPUINFO_INT_REGISTER + I80286_LDTR_LIMIT: info->i = I.ldtr.limit; break;
+ case CPUINFO_INT_REGISTER + I80286_TR_BASE: info->i = I.tr.base; break;
+ case CPUINFO_INT_REGISTER + I80286_TR_LIMIT: info->i = I.tr.limit; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i80286_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i80286_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i80286_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i80286_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i80286_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = NULL; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i80286_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = i80286_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i80286_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "80286"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel 80286"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.4"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Real mode i286 emulator v1.4 by Fabrice Frances\n(initial work I.based on David Hedley's pcemu)"); break;
+
+ case CPUINFO_STR_FLAGS:
+ I.flags = CompressFlags();
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ I.flags & 0x8000 ? '?' : '.',
+ I.flags & 0x4000 ? '?' : '.',
+ I.flags & 0x2000 ? '?' : '.',
+ I.flags & 0x1000 ? '?' : '.',
+ I.flags & 0x0800 ? 'O' : '.',
+ I.flags & 0x0400 ? 'D' : '.',
+ I.flags & 0x0200 ? 'I' : '.',
+ I.flags & 0x0100 ? 'T' : '.',
+ I.flags & 0x0080 ? 'S' : '.',
+ I.flags & 0x0040 ? 'Z' : '.',
+ I.flags & 0x0020 ? '?' : '.',
+ I.flags & 0x0010 ? 'A' : '.',
+ I.flags & 0x0008 ? '?' : '.',
+ I.flags & 0x0004 ? 'P' : '.',
+ I.flags & 0x0002 ? 'N' : '.',
+ I.flags & 0x0001 ? 'C' : '.');
+ break;
+
+ case CPUINFO_STR_REGISTER + I80286_PC: sprintf(info->s, "PC:%04X", I.pc); break;
+ case CPUINFO_STR_REGISTER + I80286_IP: sprintf(info->s, "IP: %04X", I.pc - I.base[CS]); break;
+ case CPUINFO_STR_REGISTER + I80286_SP: sprintf(info->s, "SP: %04X", I.regs.w[SP]); break;
+ case CPUINFO_STR_REGISTER + I80286_FLAGS: sprintf(info->s, "F:%04X", I.flags); break;
+ case CPUINFO_STR_REGISTER + I80286_AX: sprintf(info->s, "AX:%04X", I.regs.w[AX]); break;
+ case CPUINFO_STR_REGISTER + I80286_CX: sprintf(info->s, "CX:%04X", I.regs.w[CX]); break;
+ case CPUINFO_STR_REGISTER + I80286_DX: sprintf(info->s, "DX:%04X", I.regs.w[DX]); break;
+ case CPUINFO_STR_REGISTER + I80286_BX: sprintf(info->s, "BX:%04X", I.regs.w[BX]); break;
+ case CPUINFO_STR_REGISTER + I80286_BP: sprintf(info->s, "BP:%04X", I.regs.w[BP]); break;
+ case CPUINFO_STR_REGISTER + I80286_SI: sprintf(info->s, "SI: %04X", I.regs.w[SI]); break;
+ case CPUINFO_STR_REGISTER + I80286_DI: sprintf(info->s, "DI: %04X", I.regs.w[DI]); break;
+ case CPUINFO_STR_REGISTER + I80286_CS: sprintf(info->s, "CS: %04X %02X", I.sregs[CS], I.rights[CS]); break;
+ case CPUINFO_STR_REGISTER + I80286_CS_2: sprintf(info->s, "%06X %04X", I.base[CS], I.limit[CS]); break;
+ case CPUINFO_STR_REGISTER + I80286_SS: sprintf(info->s, "SS: %04X %02X", I.sregs[SS], I.rights[SS]); break;
+ case CPUINFO_STR_REGISTER + I80286_SS_2: sprintf(info->s, "%06X %04X", I.base[SS], I.limit[SS]); break;
+ case CPUINFO_STR_REGISTER + I80286_DS: sprintf(info->s, "DS: %04X %02X", I.sregs[DS], I.rights[DS]); break;
+ case CPUINFO_STR_REGISTER + I80286_DS_2: sprintf(info->s, "%06X %04X", I.base[DS], I.limit[DS]); break;
+ case CPUINFO_STR_REGISTER + I80286_ES: sprintf(info->s, "ES: %04X %02X", I.sregs[ES], I.rights[ES]); break;
+ case CPUINFO_STR_REGISTER + I80286_ES_2: sprintf(info->s, "%06X %04X", I.base[ES], I.limit[ES]); break;
+ case CPUINFO_STR_REGISTER + I80286_VECTOR: sprintf(info->s, "V:%02X", I.int_vector); break;
+ case CPUINFO_STR_REGISTER + I80286_MSW: sprintf(info->s, "MSW:%04X", I.msw); break;
+ case CPUINFO_STR_REGISTER + I80286_TR_BASE: sprintf(info->s, "GDTR: %06X", I.gdtr.base); break;
+ case CPUINFO_STR_REGISTER + I80286_TR_LIMIT: sprintf(info->s, "%04X", I.gdtr.limit); break;
+ case CPUINFO_STR_REGISTER + I80286_GDTR_BASE: sprintf(info->s, "IDTR: %06X", I.idtr.base); break;
+ case CPUINFO_STR_REGISTER + I80286_GDTR_LIMIT: sprintf(info->s, "%04X", I.idtr.limit); break;
+ case CPUINFO_STR_REGISTER + I80286_LDTR_BASE: sprintf(info->s, "LDTR:%04X %02X", I.ldtr.sel, I.ldtr.rights); break;
+ case CPUINFO_STR_REGISTER + I80286_LDTR_LIMIT: sprintf(info->s, "%06X %04X", I.ldtr.base, I.ldtr.limit); break;
+ case CPUINFO_STR_REGISTER + I80286_IDTR_BASE: sprintf(info->s, "IDTR: %06X", I.idtr.base); break;
+ case CPUINFO_STR_REGISTER + I80286_IDTR_LIMIT: sprintf(info->s, "%04X", I.idtr.limit); break;
+ }
+}
diff --git a/src/emu/cpu/i86/i286.h b/src/emu/cpu/i86/i286.h
new file mode 100644
index 00000000000..9243d048e21
--- /dev/null
+++ b/src/emu/cpu/i86/i286.h
@@ -0,0 +1,36 @@
+/****************************************************************************/
+/* real mode i286 emulator by Fabrice Frances */
+/* (initial work based on David Hedley's pcemu) */
+/* */
+/****************************************************************************/
+
+#include "i86.h"
+
+#define INPUT_LINE_A20 1
+
+#undef GetMemB
+#undef GetMemW
+#undef PutMemB
+#undef PutMemW
+
+/* ASG 971005 -- changed to program_read_byte_8/program_write_byte_8 */
+#define GetMemB(Seg,Off) ( (BYTE)program_read_byte_8((DefaultBase(Seg)+(Off))&AMASK))
+#define GetMemW(Seg,Off) ( (WORD)GetMemB(Seg,Off)+(WORD)(GetMemB(Seg,(Off)+1)<<8))
+#define PutMemB(Seg,Off,x) { program_write_byte_8((DefaultBase(Seg)+(Off))&AMASK,(x)); }
+#define PutMemW(Seg,Off,x) { PutMemB(Seg,Off,(BYTE)(x)); PutMemB(Seg,(Off)+1,(BYTE)((x)>>8)); }
+
+#undef PEEKBYTE
+#define PEEKBYTE(ea) ((BYTE)program_read_byte_8((ea)&AMASK))
+
+#undef ReadByte
+#undef ReadWord
+#undef WriteByte
+#undef WriteWord
+
+#define ReadByte(ea) ((BYTE)program_read_byte_8((ea)&AMASK))
+#define ReadWord(ea) (program_read_byte_8((ea)&AMASK)+(program_read_byte_8(((ea)+1)&AMASK)<<8))
+#define WriteByte(ea,val) { program_write_byte_8((ea)&AMASK,val); }
+#define WriteWord(ea,val) { program_write_byte_8((ea)&AMASK,(BYTE)(val)); program_write_byte_8(((ea)+1)&AMASK,(val)>>8); }
+
+#undef CHANGE_PC
+#define CHANGE_PC(addr) change_pc(addr)
diff --git a/src/emu/cpu/i86/i286intf.h b/src/emu/cpu/i86/i286intf.h
new file mode 100644
index 00000000000..c1c92a78c30
--- /dev/null
+++ b/src/emu/cpu/i86/i286intf.h
@@ -0,0 +1,46 @@
+/* ASG 971222 -- rewrote this interface */
+#ifndef __I286INTR_H_
+#define __I286INTR_H_
+
+#include "i86intf.h"
+
+enum
+{
+ I80286_PC=0,
+ I80286_IP,
+ I80286_AX,
+ I80286_CX,
+ I80286_DX,
+ I80286_BX,
+ I80286_SP,
+ I80286_BP,
+ I80286_SI,
+ I80286_DI,
+ I80286_FLAGS,
+ I80286_ES,
+ I80286_CS,
+ I80286_SS,
+ I80286_DS,
+ I80286_ES_2,
+ I80286_CS_2,
+ I80286_SS_2,
+ I80286_DS_2,
+ I80286_MSW,
+ I80286_GDTR_BASE,
+ I80286_IDTR_BASE,
+ I80286_LDTR_BASE,
+ I80286_TR_BASE,
+ I80286_GDTR_LIMIT,
+ I80286_IDTR_LIMIT,
+ I80286_LDTR_LIMIT,
+ I80286_TR_LIMIT,
+ I80286_VECTOR,
+ I80286_PENDING,
+ I80286_NMI_STATE,
+ I80286_IRQ_STATE
+};
+
+/* Public functions */
+void i80286_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/i86/i86.c b/src/emu/cpu/i86/i86.c
new file mode 100644
index 00000000000..840e5b6d89e
--- /dev/null
+++ b/src/emu/cpu/i86/i86.c
@@ -0,0 +1,561 @@
+/****************************************************************************
+* real mode i286 emulator v1.4 by Fabrice Frances *
+* (initial work based on David Hedley's pcemu) *
+****************************************************************************/
+/* 26.March 2000 PeT changed set_irq_line */
+
+#include "host.h"
+#include "debugger.h"
+
+#include "i86.h"
+#include "i86intf.h"
+
+#include "i86mem.h"
+
+extern int i386_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom, int mode);
+
+
+/* All pre-i286 CPUs have a 1MB address space */
+#define AMASK 0xfffff
+
+
+/* I86 registers */
+typedef union
+{ /* eight general registers */
+ UINT16 w[8]; /* viewed as 16 bits registers */
+ UINT8 b[16]; /* or as 8 bit registers */
+}
+i8086basicregs;
+
+typedef struct
+{
+ i8086basicregs regs;
+ UINT32 pc;
+ UINT32 prevpc;
+ UINT32 base[4];
+ UINT16 sregs[4];
+ UINT16 flags;
+ int (*irq_callback) (int irqline);
+ INT32 AuxVal, OverVal, SignVal, ZeroVal, CarryVal, DirVal; /* 0 or non-0 valued flags */
+ UINT8 ParityVal;
+ UINT8 TF, IF; /* 0 or 1 valued flags */
+ UINT8 MF; /* V30 mode flag */
+ UINT8 int_vector;
+ INT8 nmi_state;
+ INT8 irq_state;
+ INT8 test_state; /* PJB 03/05 */
+ INT32 extra_cycles; /* extra cycles for interrupts */
+
+ memory_interface mem;
+}
+i8086_Regs;
+
+
+#include "i86time.c"
+
+/***************************************************************************/
+/* cpu state */
+/***************************************************************************/
+
+int i8086_ICount;
+
+static i8086_Regs I;
+static unsigned prefix_base; /* base address of the latest prefix segment */
+static char seg_prefix; /* prefix segment indicator */
+
+static UINT8 parity_table[256];
+
+static struct i80x86_timing cycles;
+
+/* The interrupt number of a pending external interrupt pending NMI is 2. */
+/* For INTR interrupts, the level is caught on the bus during an INTA cycle */
+
+#define PREFIX(name) i8086##name
+#define PREFIX86(name) i8086##name
+
+#define I8086
+#include "instr86.h"
+#include "ea.h"
+#include "modrm.h"
+#include "table86.h"
+
+#include "instr86.c"
+#include "i86mem.c"
+#undef I8086
+
+
+/***************************************************************************/
+static void i8086_state_register(int index)
+{
+ static const char type[] = "I8086";
+ state_save_register_item_array(type, index, I.regs.w);
+ state_save_register_item(type, index, I.pc);
+ state_save_register_item(type, index, I.prevpc);
+ state_save_register_item_array(type, index, I.base);
+ state_save_register_item_array(type, index, I.sregs);
+ state_save_register_item(type, index, I.flags);
+ state_save_register_item(type, index, I.AuxVal);
+ state_save_register_item(type, index, I.OverVal);
+ state_save_register_item(type, index, I.SignVal);
+ state_save_register_item(type, index, I.ZeroVal);
+ state_save_register_item(type, index, I.CarryVal);
+ state_save_register_item(type, index, I.DirVal);
+ state_save_register_item(type, index, I.ParityVal);
+ state_save_register_item(type, index, I.TF);
+ state_save_register_item(type, index, I.IF);
+ state_save_register_item(type, index, I.MF);
+ state_save_register_item(type, index, I.int_vector);
+ state_save_register_item(type, index, I.nmi_state);
+ state_save_register_item(type, index, I.irq_state);
+ state_save_register_item(type, index, I.extra_cycles);
+ state_save_register_item(type, index, I.test_state); /* PJB 03/05 */
+}
+
+static void i8086_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ unsigned int i, j, c;
+ static const BREGS reg_name[8] = {AL, CL, DL, BL, AH, CH, DH, BH};
+ for (i = 0; i < 256; i++)
+ {
+ for (j = i, c = 0; j > 0; j >>= 1)
+ if (j & 1)
+ c++;
+
+ parity_table[i] = !(c & 1);
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3];
+ Mod_RM.reg.w[i] = (WREGS) ((i & 0x38) >> 3);
+ }
+
+ for (i = 0xc0; i < 0x100; i++)
+ {
+ Mod_RM.RM.w[i] = (WREGS) (i & 7);
+ Mod_RM.RM.b[i] = (BREGS) reg_name[i & 7];
+ }
+
+ I.irq_callback = irqcallback;
+
+ i8086_state_register(index);
+ configure_memory_16bit();
+}
+
+#if (HAS_I8088||HAS_I80188)
+static void i8088_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ i8086_init(index, clock, config, irqcallback);
+ configure_memory_8bit();
+}
+#endif
+
+static void i8086_reset(void)
+{
+ int (*save_irqcallback)(int);
+ memory_interface save_mem;
+
+ save_irqcallback = I.irq_callback;
+ save_mem = I.mem;
+ memset(&I, 0, sizeof (I));
+ I.irq_callback = save_irqcallback;
+ I.mem = save_mem;
+
+ I.sregs[CS] = 0xf000;
+ I.base[CS] = SegBase(CS);
+ I.pc = 0xffff0 & AMASK;
+ ExpandFlags(I.flags);
+
+ change_pc(I.pc);
+}
+
+static void i8086_exit(void)
+{
+ /* nothing to do ? */
+}
+
+/* ASG 971222 -- added these interface functions */
+
+static void i8086_get_context(void *dst)
+{
+ if (dst)
+ *(i8086_Regs *) dst = I;
+}
+
+static void i8086_set_context(void *src)
+{
+ if (src)
+ {
+ I = *(i8086_Regs *)src;
+ I.base[CS] = SegBase(CS);
+ I.base[DS] = SegBase(DS);
+ I.base[ES] = SegBase(ES);
+ I.base[SS] = SegBase(SS);
+ change_pc(I.pc);
+ }
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (I.nmi_state == state)
+ return;
+ I.nmi_state = state;
+
+ /* on a rising edge, signal the NMI */
+ if (state != CLEAR_LINE)
+ PREFIX(_interrupt)(I8086_NMI_INT_VECTOR);
+ }
+ else
+ {
+ I.irq_state = state;
+
+ /* if the IF is set, signal an interrupt */
+ if (state != CLEAR_LINE && I.IF)
+ PREFIX(_interrupt)(-1);
+ }
+}
+
+/* PJB 03/05 */
+static void set_test_line(int state)
+{
+ I.test_state = !state;
+}
+
+static int i8086_execute(int num_cycles)
+{
+ /* copy over the cycle counts if they're not correct */
+ if (cycles.id != 8086)
+ cycles = i8086_cycles;
+
+ /* adjust for any interrupts that came in */
+ i8086_ICount = num_cycles;
+ i8086_ICount -= I.extra_cycles;
+ I.extra_cycles = 0;
+
+ /* run until we're out */
+ while (i8086_ICount > 0)
+ {
+//#define VERBOSE_DEBUG
+#ifdef VERBOSE_DEBUG
+ logerror("[%04x:%04x]=%02x\tF:%04x\tAX=%04x\tBX=%04x\tCX=%04x\tDX=%04x %d%d%d%d%d%d%d%d%d\n",
+ I.sregs[CS], I.pc - I.base[CS], ReadByte(I.pc), I.flags, I.regs.w[AX], I.regs.w[BX], I.regs.w[CX], I.regs.w[DX], I.AuxVal ? 1 : 0, I.OverVal ? 1 : 0,
+ I.SignVal ? 1 : 0, I.ZeroVal ? 1 : 0, I.CarryVal ? 1 : 0, I.ParityVal ? 1 : 0, I.TF, I.IF, I.DirVal < 0 ? 1 : 0);
+#endif
+ CALL_MAME_DEBUG;
+
+ seg_prefix = FALSE;
+ I.prevpc = I.pc;
+ TABLE86;
+ }
+
+ /* adjust for any interrupts that came in */
+ i8086_ICount -= I.extra_cycles;
+ I.extra_cycles = 0;
+
+ return num_cycles - i8086_ICount;
+}
+
+
+#ifdef MAME_DEBUG
+static offs_t i8086_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return i386_dasm_one(buffer, pc, oprom, 16);
+}
+#endif /* MAME_DEBUG */
+
+
+#if (HAS_I80186 || HAS_I80188)
+
+#include "i186intf.h"
+
+#undef PREFIX
+#define PREFIX(name) i80186##name
+#define PREFIX186(name) i80186##name
+
+#define I80186
+#include "instr186.h"
+#include "table186.h"
+
+#include "instr86.c"
+#include "instr186.c"
+#undef I80186
+
+static int i80186_execute(int num_cycles)
+{
+ /* copy over the cycle counts if they're not correct */
+ if (cycles.id != 80186)
+ cycles = i80186_cycles;
+
+ /* adjust for any interrupts that came in */
+ i8086_ICount = num_cycles;
+ i8086_ICount -= I.extra_cycles;
+ I.extra_cycles = 0;
+
+ /* run until we're out */
+ while (i8086_ICount > 0)
+ {
+#ifdef VERBOSE_DEBUG
+ mame_printf_debug("[%04x:%04x]=%02x\tAX=%04x\tBX=%04x\tCX=%04x\tDX=%04x\n", I.sregs[CS], I.pc, ReadByte(I.pc), I.regs.w[AX],
+ I.regs.w[BX], I.regs.w[CX], I.regs.w[DX]);
+#endif
+ CALL_MAME_DEBUG;
+
+ seg_prefix = FALSE;
+ I.prevpc = I.pc;
+ TABLE186;
+ }
+
+ /* adjust for any interrupts that came in */
+ i8086_ICount -= I.extra_cycles;
+ I.extra_cycles = 0;
+
+ return num_cycles - i8086_ICount;
+}
+
+#endif
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void i8086_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_TEST: set_test_line(info->i); break; /* PJB 03/05 */
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I8086_PC:
+ if (info->i - I.base[CS] >= 0x10000)
+ {
+ I.base[CS] = info->i & 0xffff0;
+ I.sregs[CS] = I.base[CS] >> 4;
+ }
+ I.pc = info->i;
+ break;
+ case CPUINFO_INT_REGISTER + I8086_IP: I.pc = I.base[CS] + info->i; break;
+ case CPUINFO_INT_SP:
+ if (info->i - I.base[SS] < 0x10000)
+ {
+ I.regs.w[SP] = info->i - I.base[SS];
+ }
+ else
+ {
+ I.base[SS] = info->i & 0xffff0;
+ I.sregs[SS] = I.base[SS] >> 4;
+ I.regs.w[SP] = info->i & 0x0000f;
+ }
+ break;
+ case CPUINFO_INT_REGISTER + I8086_SP: I.regs.w[SP] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8086_FLAGS: I.flags = info->i; ExpandFlags(info->i); break;
+ case CPUINFO_INT_REGISTER + I8086_AX: I.regs.w[AX] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8086_CX: I.regs.w[CX] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8086_DX: I.regs.w[DX] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8086_BX: I.regs.w[BX] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8086_BP: I.regs.w[BP] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8086_SI: I.regs.w[SI] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8086_DI: I.regs.w[DI] = info->i; break;
+ case CPUINFO_INT_REGISTER + I8086_ES: I.sregs[ES] = info->i; I.base[ES] = SegBase(ES); break;
+ case CPUINFO_INT_REGISTER + I8086_CS: I.sregs[CS] = info->i; I.base[CS] = SegBase(CS); break;
+ case CPUINFO_INT_REGISTER + I8086_SS: I.sregs[SS] = info->i; I.base[SS] = SegBase(SS); break;
+ case CPUINFO_INT_REGISTER + I8086_DS: I.sregs[DS] = info->i; I.base[DS] = SegBase(DS); break;
+ case CPUINFO_INT_REGISTER + I8086_VECTOR: I.int_vector = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void i8086_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(I); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 15; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 50; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 20; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = I.irq_state; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = I.nmi_state; break;
+
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_TEST: info->i = I.test_state; break; /* PJB 03/05 */
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = I.prevpc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I8086_PC: info->i = I.pc; break;
+ case CPUINFO_INT_REGISTER + I8086_IP: info->i = I.pc - I.base[CS]; break;
+ case CPUINFO_INT_SP: info->i = I.base[SS] + I.regs.w[SP]; break;
+ case CPUINFO_INT_REGISTER + I8086_SP: info->i = I.regs.w[SP]; break;
+ case CPUINFO_INT_REGISTER + I8086_FLAGS: I.flags = CompressFlags(); info->i = I.flags; break;
+ case CPUINFO_INT_REGISTER + I8086_AX: info->i = I.regs.w[AX]; break;
+ case CPUINFO_INT_REGISTER + I8086_CX: info->i = I.regs.w[CX]; break;
+ case CPUINFO_INT_REGISTER + I8086_DX: info->i = I.regs.w[DX]; break;
+ case CPUINFO_INT_REGISTER + I8086_BX: info->i = I.regs.w[BX]; break;
+ case CPUINFO_INT_REGISTER + I8086_BP: info->i = I.regs.w[BP]; break;
+ case CPUINFO_INT_REGISTER + I8086_SI: info->i = I.regs.w[SI]; break;
+ case CPUINFO_INT_REGISTER + I8086_DI: info->i = I.regs.w[DI]; break;
+ case CPUINFO_INT_REGISTER + I8086_ES: info->i = I.sregs[ES]; break;
+ case CPUINFO_INT_REGISTER + I8086_CS: info->i = I.sregs[CS]; break;
+ case CPUINFO_INT_REGISTER + I8086_SS: info->i = I.sregs[SS]; break;
+ case CPUINFO_INT_REGISTER + I8086_DS: info->i = I.sregs[DS]; break;
+ case CPUINFO_INT_REGISTER + I8086_VECTOR: info->i = I.int_vector; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i8086_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8086_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8086_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8086_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8086_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8086_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8086_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = i8086_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i8086_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "8086"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel 80x86"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.4"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Real mode i286 emulator v1.4 by Fabrice Frances\n(initial work I.based on David Hedley's pcemu)"); break;
+
+ case CPUINFO_STR_FLAGS:
+ I.flags = CompressFlags();
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ I.flags & 0x8000 ? '?' : '.',
+ I.flags & 0x4000 ? '?' : '.',
+ I.flags & 0x2000 ? '?' : '.',
+ I.flags & 0x1000 ? '?' : '.',
+ I.flags & 0x0800 ? 'O' : '.',
+ I.flags & 0x0400 ? 'D' : '.',
+ I.flags & 0x0200 ? 'I' : '.',
+ I.flags & 0x0100 ? 'T' : '.',
+ I.flags & 0x0080 ? 'S' : '.',
+ I.flags & 0x0040 ? 'Z' : '.',
+ I.flags & 0x0020 ? '?' : '.',
+ I.flags & 0x0010 ? 'A' : '.',
+ I.flags & 0x0008 ? '?' : '.',
+ I.flags & 0x0004 ? 'P' : '.',
+ I.flags & 0x0002 ? 'N' : '.',
+ I.flags & 0x0001 ? 'C' : '.');
+ break;
+
+ case CPUINFO_STR_REGISTER + I8086_PC: sprintf(info->s, "PC:%04X", I.pc); break;
+ case CPUINFO_STR_REGISTER + I8086_IP: sprintf(info->s, "IP: %04X", I.pc - I.base[CS]); break;
+ case CPUINFO_STR_REGISTER + I8086_SP: sprintf(info->s, "SP: %04X", I.regs.w[SP]); break;
+ case CPUINFO_STR_REGISTER + I8086_FLAGS: sprintf(info->s, "F:%04X", I.flags); break;
+ case CPUINFO_STR_REGISTER + I8086_AX: sprintf(info->s, "AX:%04X", I.regs.w[AX]); break;
+ case CPUINFO_STR_REGISTER + I8086_CX: sprintf(info->s, "CX:%04X", I.regs.w[CX]); break;
+ case CPUINFO_STR_REGISTER + I8086_DX: sprintf(info->s, "DX:%04X", I.regs.w[DX]); break;
+ case CPUINFO_STR_REGISTER + I8086_BX: sprintf(info->s, "BX:%04X", I.regs.w[BX]); break;
+ case CPUINFO_STR_REGISTER + I8086_BP: sprintf(info->s, "BP:%04X", I.regs.w[BP]); break;
+ case CPUINFO_STR_REGISTER + I8086_SI: sprintf(info->s, "SI: %04X", I.regs.w[SI]); break;
+ case CPUINFO_STR_REGISTER + I8086_DI: sprintf(info->s, "DI: %04X", I.regs.w[DI]); break;
+ case CPUINFO_STR_REGISTER + I8086_ES: sprintf(info->s, "ES:%04X", I.sregs[ES]); break;
+ case CPUINFO_STR_REGISTER + I8086_CS: sprintf(info->s, "CS:%04X", I.sregs[CS]); break;
+ case CPUINFO_STR_REGISTER + I8086_SS: sprintf(info->s, "SS:%04X", I.sregs[SS]); break;
+ case CPUINFO_STR_REGISTER + I8086_DS: sprintf(info->s, "DS:%04X", I.sregs[DS]); break;
+ case CPUINFO_STR_REGISTER + I8086_VECTOR: sprintf(info->s, "V:%02X", I.int_vector); break;
+ }
+}
+
+
+#if (HAS_I8088)
+/**************************************************************************
+ * CPU-specific get_info/set_info
+ **************************************************************************/
+
+void i8088_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = i8088_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "8088"); break;
+
+ default: i8086_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_I80186)
+/**************************************************************************
+ * CPU-specific get_info/set_info
+ **************************************************************************/
+
+void i80186_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_EXECUTE: info->execute = i80186_execute; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "80186"); break;
+
+ default: i8086_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_I80188)
+/**************************************************************************
+ * CPU-specific get_info/set_info
+ **************************************************************************/
+
+void i80188_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = i8088_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i80186_execute; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "80188"); break;
+
+ default: i8086_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/i86/i86.h b/src/emu/cpu/i86/i86.h
new file mode 100644
index 00000000000..fa7912644df
--- /dev/null
+++ b/src/emu/cpu/i86/i86.h
@@ -0,0 +1,127 @@
+/****************************************************************************/
+/* real mode i286 emulator by Fabrice Frances */
+/* (initial work based on David Hedley's pcemu) */
+/* */
+/****************************************************************************/
+#ifndef __I86_H_
+#define __I86_H_
+
+#define I8086_NMI_INT_VECTOR 2
+#define INPUT_LINE_TEST 20 /* PJB 03/05 */
+
+typedef enum { ES, CS, SS, DS } SREGS;
+typedef enum { AX, CX, DX, BX, SP, BP, SI, DI } WREGS;
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+#ifdef LSB_FIRST
+typedef enum { AL,AH,CL,CH,DL,DH,BL,BH,SPL,SPH,BPL,BPH,SIL,SIH,DIL,DIH } BREGS;
+#else
+typedef enum { AH,AL,CH,CL,DH,DL,BH,BL,SPH,SPL,BPH,BPL,SIH,SIL,DIH,DIL } BREGS;
+#endif
+
+/* parameter x = result, y = source 1, z = source 2 */
+
+#define SetTF(x) (I.TF = (x))
+#define SetIF(x) (I.IF = (x))
+#define SetDF(x) (I.DirVal = (x) ? -1 : 1)
+
+#define SetOFW_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x8000)
+#define SetOFB_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x80)
+#define SetOFW_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x8000)
+#define SetOFB_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x80)
+
+#define SetCFB(x) (I.CarryVal = (x) & 0x100)
+#define SetCFW(x) (I.CarryVal = (x) & 0x10000)
+#define SetAF(x,y,z) (I.AuxVal = ((x) ^ ((y) ^ (z))) & 0x10)
+#define SetSF(x) (I.SignVal = (x))
+#define SetZF(x) (I.ZeroVal = (x))
+#define SetPF(x) (I.ParityVal = (x))
+
+#define SetSZPF_Byte(x) (I.ParityVal = I.SignVal = I.ZeroVal = (INT8)(x))
+#define SetSZPF_Word(x) (I.ParityVal = I.SignVal = I.ZeroVal = (INT16)(x))
+
+#define ADDB(dst,src) { unsigned res=dst+src; SetCFB(res); SetOFB_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; }
+#define ADDW(dst,src) { unsigned res=dst+src; SetCFW(res); SetOFW_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; }
+
+#define SUBB(dst,src) { unsigned res=dst-src; SetCFB(res); SetOFB_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; }
+#define SUBW(dst,src) { unsigned res=dst-src; SetCFW(res); SetOFW_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; }
+
+#define ORB(dst,src) dst |= src; I.CarryVal = I.OverVal = I.AuxVal = 0; SetSZPF_Byte(dst)
+#define ORW(dst,src) dst |= src; I.CarryVal = I.OverVal = I.AuxVal = 0; SetSZPF_Word(dst)
+
+#define ANDB(dst,src) dst &= src; I.CarryVal = I.OverVal = I.AuxVal = 0; SetSZPF_Byte(dst)
+#define ANDW(dst,src) dst &= src; I.CarryVal = I.OverVal = I.AuxVal = 0; SetSZPF_Word(dst)
+
+#define XORB(dst,src) dst ^= src; I.CarryVal = I.OverVal = I.AuxVal = 0; SetSZPF_Byte(dst)
+#define XORW(dst,src) dst ^= src; I.CarryVal = I.OverVal = I.AuxVal = 0; SetSZPF_Word(dst)
+
+#define CF (I.CarryVal != 0)
+#define SF (I.SignVal < 0)
+#define ZF (I.ZeroVal == 0)
+#define PF parity_table[I.ParityVal]
+#define AF (I.AuxVal != 0)
+#define OF (I.OverVal != 0)
+#define DF (I.DirVal < 0)
+
+/************************************************************************/
+
+#define read_byte(a) (*I.mem.rbyte)(a)
+#define read_word(a) (*I.mem.rword)(a)
+#define write_byte(a,d) (*I.mem.wbyte)((a),(d))
+#define write_word(a,d) (*I.mem.wword)((a),(d))
+
+#define read_port_byte(a) (*I.mem.rbyte_port)(a)
+#define read_port_word(a) (*I.mem.rword_port)(a)
+#define write_port_byte(a,d) (*I.mem.wbyte_port)((a),(d))
+#define write_port_word(a,d) (*I.mem.wword_port)((a),(d))
+
+/************************************************************************/
+
+#define SegBase(Seg) (I.sregs[Seg] << 4)
+
+#define DefaultBase(Seg) ((seg_prefix && (Seg == DS || Seg == SS)) ? prefix_base : I.base[Seg])
+
+#define GetMemB(Seg,Off) (read_byte((DefaultBase(Seg) + (Off)) & AMASK))
+#define GetMemW(Seg,Off) (read_word((DefaultBase(Seg) + (Off)) & AMASK))
+#define PutMemB(Seg,Off,x) write_byte((DefaultBase(Seg) + (Off)) & AMASK, (x))
+#define PutMemW(Seg,Off,x) write_word((DefaultBase(Seg) + (Off)) & AMASK, (x))
+
+#define PEEKBYTE(ea) (read_byte((ea) & AMASK))
+#define ReadByte(ea) (read_byte((ea) & AMASK))
+#define ReadWord(ea) (read_word((ea) & AMASK))
+#define WriteByte(ea,val) write_byte((ea) & AMASK, val);
+#define WriteWord(ea,val) write_word((ea) & AMASK, val);
+
+#define FETCH_XOR(a) ((a) ^ I.mem.fetch_xor)
+#define FETCH (cpu_readop_arg(FETCH_XOR(I.pc++)))
+#define FETCHOP (cpu_readop(FETCH_XOR(I.pc++)))
+#define PEEKOP(addr) (cpu_readop(FETCH_XOR(addr)))
+#define FETCHWORD(var) { var = cpu_readop_arg(FETCH_XOR(I.pc)); var += (cpu_readop_arg(FETCH_XOR(I.pc + 1)) << 8); I.pc += 2; }
+#define CHANGE_PC(addr) change_pc(addr)
+#define PUSH(val) { I.regs.w[SP] -= 2; WriteWord(((I.base[SS] + I.regs.w[SP]) & AMASK), val); }
+#define POP(var) { var = ReadWord(((I.base[SS] + I.regs.w[SP]) & AMASK)); I.regs.w[SP] += 2; }
+
+/************************************************************************/
+
+#define CompressFlags() (WORD)(CF | (PF << 2) | (AF << 4) | (ZF << 6) \
+ | (SF << 7) | (I.TF << 8) | (I.IF << 9) \
+ | (DF << 10) | (OF << 11))
+
+#define ExpandFlags(f) \
+{ \
+ I.CarryVal = (f) & 1; \
+ I.ParityVal = !((f) & 4); \
+ I.AuxVal = (f) & 16; \
+ I.ZeroVal = !((f) & 64); \
+ I.SignVal = ((f) & 128) ? -1 : 0; \
+ I.TF = ((f) & 256) >> 8; \
+ I.IF = ((f) & 512) >> 9; \
+ I.DirVal = ((f) & 1024) ? -1 : 1; \
+ I.OverVal = (f) & 2048; \
+}
+#endif
+
diff --git a/src/emu/cpu/i86/i86.txt b/src/emu/cpu/i86/i86.txt
new file mode 100644
index 00000000000..c9234bfafd8
--- /dev/null
+++ b/src/emu/cpu/i86/i86.txt
@@ -0,0 +1,111 @@
+intel 8086 and compatibles
+--------------------------
+
+this info is here,
+to list and give some remarks on all 8086 compatible processors
+
+excellent info in Hamarsoft's 86BUGS list
+(also distributed in ralf browns interrupt list)
+
+8086/8088
+---------
+20 bit adress bus, 16 bit data bus and registers
+many 8080 assembler sources should be compilable/reusable
+
+8086
+----
+6 bytes prefetch queue
+
+8088
+----
+8086 with 8 bit data bus,
+prefetch queue only 4 byte, and refilled when 1 byte empty
+
+early 8086/8088 revisions bug
+-----------------------------
+(copyright 1978 on package)
+mov sreg, doesnot disable until next operation is executed
+
+8086/8088
+---------
+"mov cs, " causes unconditional jump!
+
+80C86/80C88
+-----------
+"mov cs, " ignored
+
+80186/80188
+-----------
+integrated pic8259, pit8253, dma8253 (but not at standard pc addresses)
+additional instructions
+"mov cs, " ?
+shift count anded with 0x1f
+
+80188
+-----
+8bit data bus
+
+NEC series
+----------
+80186 instruction set, additional nec instructions
+although it is based on 80186 instruction set, some behaviours follow 8086
+8080 emulation mode
+"mov cs, " ignored
+shift count not anded (acts like 8086)
+
+NEC 70116 (V30)
+---------------
+8086 pin compatible
+
+NEC 70108 (V20)
+---------------
+8088 pinout
+
+NEC V30MX
+---------
+on die ems hardware
+24 bit address but for ems memory!?
+no 8080 emulation mode
+
+NEC V40
+-------
+pinout, integrated peripherals as 80186
+
+NEC V50
+-------
+pinout, integrated peripherals as 80188
+
+NEC V33?
+--------
+speed optimized V30?
+
+NEC V25/V35?
+------------
+
+NEC V25+/V35+?
+--------------
+
+NEC V60/V70
+-----------
+risc (misc/delux) like instruction set
+v30? emulation mode (without 8080 emulation mode)
+
+80286
+-----
+80186 with additional instructions
+24 bit address bus,
+protected mode
+
+80386 and later
+---------------
+not covered here
+
+8087/80287/80387/80387sx
+------------------------
+mathematical coprocessors
+
+weitek, iit variants
+
+in 80486 coprocessor integrated
+(except 80486sx and several clones)
+80487: 80486 with other pinout
diff --git a/src/emu/cpu/i86/i86intf.h b/src/emu/cpu/i86/i86intf.h
new file mode 100644
index 00000000000..0f7b8984102
--- /dev/null
+++ b/src/emu/cpu/i86/i86intf.h
@@ -0,0 +1,30 @@
+/* ASG 971222 -- rewrote this interface */
+#ifndef __I86INTRF_H_
+#define __I86INTRF_H_
+
+#include "cpuintrf.h"
+
+enum
+{
+ I8086_PC=0,
+ I8086_IP,
+ I8086_AX,
+ I8086_CX,
+ I8086_DX,
+ I8086_BX,
+ I8086_SP,
+ I8086_BP,
+ I8086_SI,
+ I8086_DI,
+ I8086_FLAGS,
+ I8086_ES,
+ I8086_CS,
+ I8086_SS,
+ I8086_DS,
+ I8086_VECTOR
+};
+
+/* Public functions */
+void i8086_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/i86/i86mem.c b/src/emu/cpu/i86/i86mem.c
new file mode 100644
index 00000000000..3a06419dc36
--- /dev/null
+++ b/src/emu/cpu/i86/i86mem.c
@@ -0,0 +1,110 @@
+/*****************************************************************************
+ 8-bit memory accessors
+ *****************************************************************************/
+
+#ifdef I8086
+#if (HAS_I8088||HAS_I80188)
+static UINT16 read_word_8(offs_t addr)
+{
+ UINT16 result = program_read_byte_8(addr);
+ return result | (program_read_byte_8(addr + 1) << 8);
+}
+
+static void write_word_8(offs_t addr, UINT16 data)
+{
+ program_write_byte_8(addr, data);
+ program_write_byte_8(addr + 1, data >> 8);
+}
+
+static UINT16 read_port_word_8(offs_t addr)
+{
+ UINT16 result = io_read_byte_8(addr);
+ return result | (io_read_byte_8(addr + 1) << 8);
+}
+
+static void write_port_word_8(offs_t addr, UINT16 data)
+{
+ io_write_byte_8(addr, data);
+ io_write_byte_8(addr + 1, data >> 8);
+}
+
+static void configure_memory_8bit(void)
+{
+ I.mem.fetch_xor = 0;
+
+ I.mem.rbyte = program_read_byte_8;
+ I.mem.rword = read_word_8;
+ I.mem.wbyte = program_write_byte_8;
+ I.mem.wword = write_word_8;
+
+ I.mem.rbyte_port = io_read_byte_8;
+ I.mem.rword_port = read_port_word_8;
+ I.mem.wbyte_port = io_write_byte_8;
+ I.mem.wword_port = write_port_word_8;
+}
+#endif
+#endif
+
+
+/*****************************************************************************
+ 16-bit memory accessors
+ *****************************************************************************/
+
+static UINT16 read_word_16le(offs_t addr)
+{
+ if (!(addr & 1))
+ return program_read_word_16le(addr);
+ else
+ {
+ UINT16 result = program_read_byte_16le(addr);
+ return result | (program_read_byte_16le(addr + 1) << 8);
+ }
+}
+
+static void write_word_16le(offs_t addr, UINT16 data)
+{
+ if (!(addr & 1))
+ program_write_word_16le(addr, data);
+ else
+ {
+ program_write_byte_16le(addr, data);
+ program_write_byte_16le(addr + 1, data >> 8);
+ }
+}
+
+static UINT16 read_port_word_16le(offs_t addr)
+{
+ if (!(addr & 1))
+ return io_read_word_16le(addr);
+ else
+ {
+ UINT16 result = io_read_byte_16le(addr);
+ return result | (io_read_byte_16le(addr + 1) << 8);
+ }
+}
+
+static void write_port_word_16le(offs_t addr, UINT16 data)
+{
+ if (!(addr & 1))
+ io_write_word_16le(addr, data);
+ else
+ {
+ io_write_byte_16le(addr, data);
+ io_write_byte_16le(addr + 1, data >> 8);
+ }
+}
+
+static void configure_memory_16bit(void)
+{
+ I.mem.fetch_xor = BYTE_XOR_LE(0);
+
+ I.mem.rbyte = program_read_byte_16le;
+ I.mem.rword = read_word_16le;
+ I.mem.wbyte = program_write_byte_16le;
+ I.mem.wword = write_word_16le;
+
+ I.mem.rbyte_port = io_read_byte_16le;
+ I.mem.rword_port = read_port_word_16le;
+ I.mem.wbyte_port = io_write_byte_16le;
+ I.mem.wword_port = write_port_word_16le;
+}
diff --git a/src/emu/cpu/i86/i86mem.h b/src/emu/cpu/i86/i86mem.h
new file mode 100644
index 00000000000..1233b4816c9
--- /dev/null
+++ b/src/emu/cpu/i86/i86mem.h
@@ -0,0 +1,14 @@
+typedef struct
+{
+ offs_t fetch_xor;
+
+ UINT8 (*rbyte)(offs_t);
+ UINT16 (*rword)(offs_t);
+ void (*wbyte)(offs_t, UINT8);
+ void (*wword)(offs_t, UINT16);
+
+ UINT8 (*rbyte_port)(offs_t);
+ UINT16 (*rword_port)(offs_t);
+ void (*wbyte_port)(offs_t, UINT8);
+ void (*wword_port)(offs_t, UINT16);
+} memory_interface;
diff --git a/src/emu/cpu/i86/i86time.c b/src/emu/cpu/i86/i86time.c
new file mode 100644
index 00000000000..c9c1c808763
--- /dev/null
+++ b/src/emu/cpu/i86/i86time.c
@@ -0,0 +1,312 @@
+/****************************************************************************
+* real mode i286 emulator v1.4 by Fabrice Frances *
+* (initial work based on David Hedley's pcemu) *
+****************************************************************************/
+
+struct i80x86_timing
+{
+ int id;
+
+ UINT8 exception, iret; /* exception, IRET */
+ UINT8 int3, int_imm, into_nt, into_t; /* INTs */
+ UINT8 override; /* segment overrides */
+ UINT8 flag_ops, lahf, sahf; /* flag operations */
+ UINT8 aaa, aas, aam, aad; /* arithmetic adjusts */
+ UINT8 daa, das; /* decimal adjusts */
+ UINT8 cbw, cwd; /* sign extension */
+ UINT8 hlt, load_ptr, lea, nop, wait, xlat; /* misc */
+
+ UINT8 jmp_short, jmp_near, jmp_far; /* direct JMPs */
+ UINT8 jmp_r16, jmp_m16, jmp_m32; /* indirect JMPs */
+ UINT8 call_near, call_far; /* direct CALLs */
+ UINT8 call_r16, call_m16, call_m32; /* indirect CALLs */
+ UINT8 ret_near, ret_far, ret_near_imm, ret_far_imm; /* returns */
+ UINT8 jcc_nt, jcc_t, jcxz_nt, jcxz_t; /* conditional JMPs */
+ UINT8 loop_nt, loop_t, loope_nt, loope_t; /* loops */
+
+ UINT8 in_imm8, in_imm16, in_dx8, in_dx16; /* port reads */
+ UINT8 out_imm8, out_imm16, out_dx8, out_dx16; /* port writes */
+
+ UINT8 mov_rr8, mov_rm8, mov_mr8; /* move, 8-bit */
+ UINT8 mov_ri8, mov_mi8; /* move, 8-bit immediate */
+ UINT8 mov_rr16, mov_rm16, mov_mr16; /* move, 16-bit */
+ UINT8 mov_ri16, mov_mi16; /* move, 16-bit immediate */
+ UINT8 mov_am8, mov_am16, mov_ma8, mov_ma16; /* move, AL/AX memory */
+ UINT8 mov_sr, mov_sm, mov_rs, mov_ms; /* move, segment registers */
+ UINT8 xchg_rr8, xchg_rm8; /* exchange, 8-bit */
+ UINT8 xchg_rr16, xchg_rm16, xchg_ar16; /* exchange, 16-bit */
+
+ UINT8 push_r16, push_m16, push_seg, pushf; /* pushes */
+ UINT8 pop_r16, pop_m16, pop_seg, popf; /* pops */
+
+ UINT8 alu_rr8, alu_rm8, alu_mr8; /* ALU ops, 8-bit */
+ UINT8 alu_ri8, alu_mi8, alu_mi8_ro; /* ALU ops, 8-bit immediate */
+ UINT8 alu_rr16, alu_rm16, alu_mr16; /* ALU ops, 16-bit */
+ UINT8 alu_ri16, alu_mi16, alu_mi16_ro; /* ALU ops, 16-bit immediate */
+ UINT8 alu_r16i8, alu_m16i8, alu_m16i8_ro; /* ALU ops, 16-bit w/8-bit immediate */
+ UINT8 mul_r8, mul_r16, mul_m8, mul_m16; /* MUL */
+ UINT8 imul_r8, imul_r16, imul_m8, imul_m16; /* IMUL */
+ UINT8 div_r8, div_r16, div_m8, div_m16; /* DIV */
+ UINT8 idiv_r8, idiv_r16, idiv_m8, idiv_m16; /* IDIV */
+ UINT8 incdec_r8, incdec_r16, incdec_m8, incdec_m16; /* INC/DEC */
+ UINT8 negnot_r8, negnot_r16, negnot_m8, negnot_m16; /* NEG/NOT */
+
+ UINT8 rot_reg_1, rot_reg_base, rot_reg_bit; /* reg shift/rotate */
+ UINT8 rot_m8_1, rot_m8_base, rot_m8_bit; /* m8 shift/rotate */
+ UINT8 rot_m16_1, rot_m16_base, rot_m16_bit; /* m16 shift/rotate */
+
+ UINT8 cmps8, rep_cmps8_base, rep_cmps8_count; /* CMPS 8-bit */
+ UINT8 cmps16, rep_cmps16_base, rep_cmps16_count; /* CMPS 16-bit */
+ UINT8 scas8, rep_scas8_base, rep_scas8_count; /* SCAS 8-bit */
+ UINT8 scas16, rep_scas16_base, rep_scas16_count; /* SCAS 16-bit */
+ UINT8 lods8, rep_lods8_base, rep_lods8_count; /* LODS 8-bit */
+ UINT8 lods16, rep_lods16_base, rep_lods16_count; /* LODS 16-bit */
+ UINT8 stos8, rep_stos8_base, rep_stos8_count; /* STOS 8-bit */
+ UINT8 stos16, rep_stos16_base, rep_stos16_count; /* STOS 16-bit */
+ UINT8 movs8, rep_movs8_base, rep_movs8_count; /* MOVS 8-bit */
+ UINT8 movs16, rep_movs16_base, rep_movs16_count; /* MOVS 16-bit */
+
+ void * check1; /* marker to make sure we line up */
+
+ UINT8 ins8, rep_ins8_base, rep_ins8_count; /* (80186) INS 8-bit */
+ UINT8 ins16, rep_ins16_base, rep_ins16_count; /* (80186) INS 16-bit */
+ UINT8 outs8, rep_outs8_base, rep_outs8_count; /* (80186) OUTS 8-bit */
+ UINT8 outs16, rep_outs16_base, rep_outs16_count; /* (80186) OUTS 16-bit */
+ UINT8 push_imm, pusha, popa; /* (80186) PUSH immediate, PUSHA/POPA */
+ UINT8 imul_rri8, imul_rmi8; /* (80186) IMUL immediate 8-bit */
+ UINT8 imul_rri16, imul_rmi16; /* (80186) IMUL immediate 16-bit */
+ UINT8 enter0, enter1, enter_base, enter_count, leave; /* (80186) ENTER/LEAVE */
+ UINT8 bound; /* (80186) BOUND */
+
+ void * check2; /* marker to make sure we line up */
+};
+
+
+/* these come from the 8088 timings in OPCODE.LST, but with the
+ penalty for 16-bit memory accesses removed wherever possible */
+static const struct i80x86_timing i8086_cycles =
+{
+ 8086,
+
+ 51,32, /* exception, IRET */
+ 2, 0, 4, 2, /* INTs */
+ 2, /* segment overrides */
+ 2, 4, 4, /* flag operations */
+ 4, 4,83,60, /* arithmetic adjusts */
+ 4, 4, /* decimal adjusts */
+ 2, 5, /* sign extension */
+ 2,24, 2, 2, 3,11, /* misc */
+
+ 15,15,15, /* direct JMPs */
+ 11,18,24, /* indirect JMPs */
+ 19,28, /* direct CALLs */
+ 16,21,37, /* indirect CALLs */
+ 20,32,24,31, /* returns */
+ 4,16, 6,18, /* conditional JMPs */
+ 5,17, 6,18, /* loops */
+
+ 10,14, 8,12, /* port reads */
+ 10,14, 8,12, /* port writes */
+
+ 2, 8, 9, /* move, 8-bit */
+ 4,10, /* move, 8-bit immediate */
+ 2, 8, 9, /* move, 16-bit */
+ 4,10, /* move, 16-bit immediate */
+ 10,10,10,10, /* move, AL/AX memory */
+ 2, 8, 2, 9, /* move, segment registers */
+ 4,17, /* exchange, 8-bit */
+ 4,17, 3, /* exchange, 16-bit */
+
+ 15,24,14,14, /* pushes */
+ 12,25,12,12, /* pops */
+
+ 3, 9,16, /* ALU ops, 8-bit */
+ 4,17,10, /* ALU ops, 8-bit immediate */
+ 3, 9,16, /* ALU ops, 16-bit */
+ 4,17,10, /* ALU ops, 16-bit immediate */
+ 4,17,10, /* ALU ops, 16-bit w/8-bit immediate */
+ 70,118,76,128, /* MUL */
+ 80,128,86,138, /* IMUL */
+ 80,144,86,154, /* DIV */
+ 101,165,107,175,/* IDIV */
+ 3, 2,15,15, /* INC/DEC */
+ 3, 3,16,16, /* NEG/NOT */
+
+ 2, 8, 4, /* reg shift/rotate */
+ 15,20, 4, /* m8 shift/rotate */
+ 15,20, 4, /* m16 shift/rotate */
+
+ 22, 9,21, /* CMPS 8-bit */
+ 22, 9,21, /* CMPS 16-bit */
+ 15, 9,14, /* SCAS 8-bit */
+ 15, 9,14, /* SCAS 16-bit */
+ 12, 9,11, /* LODS 8-bit */
+ 12, 9,11, /* LODS 16-bit */
+ 11, 9,10, /* STOS 8-bit */
+ 11, 9,10, /* STOS 16-bit */
+ 18, 9,17, /* MOVS 8-bit */
+ 18, 9,17, /* MOVS 16-bit */
+
+ (void *)-1 /* marker to make sure we line up */
+};
+
+
+/* these come from the Intel 80186 datasheet */
+static const struct i80x86_timing i80186_cycles =
+{
+ 80186,
+
+ 45,28, /* exception, IRET */
+ 0, 2, 4, 3, /* INTs */
+ 2, /* segment overrides */
+ 2, 2, 3, /* flag operations */
+ 8, 7,19,15, /* arithmetic adjusts */
+ 4, 4, /* decimal adjusts */
+ 2, 4, /* sign extension */
+ 2,18, 6, 2, 6,11, /* misc */
+
+ 14,14,14, /* direct JMPs */
+ 11,17,26, /* indirect JMPs */
+ 15,23, /* direct CALLs */
+ 13,19,38, /* indirect CALLs */
+ 16,22,18,25, /* returns */
+ 4,13, 5,15, /* conditional JMPs */
+ 6,16, 6,16, /* loops */
+
+ 10,10, 8, 8, /* port reads */
+ 9, 9, 7, 7, /* port writes */
+
+ 2, 9,12, /* move, 8-bit */
+ 3,12, /* move, 8-bit immediate */
+ 2, 9,12, /* move, 16-bit */
+ 4,13, /* move, 16-bit immediate */
+ 8, 8, 9, 9, /* move, AL/AX memory */
+ 2,11, 2,11, /* move, segment registers */
+ 4,17, /* exchange, 8-bit */
+ 4,17, 3, /* exchange, 16-bit */
+
+ 10,16, 9, 9, /* pushes */
+ 10,20, 8, 8, /* pops */
+
+ 3,10,10, /* ALU ops, 8-bit */
+ 4,16,10, /* ALU ops, 8-bit immediate */
+ 3,10,10, /* ALU ops, 16-bit */
+ 4,16,10, /* ALU ops, 16-bit immediate */
+ 4,16,10, /* ALU ops, 16-bit w/8-bit immediate */
+ 26,35,32,41, /* MUL */
+ 25,34,31,40, /* IMUL */
+ 29,38,35,44, /* DIV */
+ 44,53,50,59, /* IDIV */
+ 3, 3,15,15, /* INC/DEC */
+ 3, 3,10,10, /* NEG/NOT */
+
+ 2, 5, 1, /* reg shift/rotate */
+ 15,17, 1, /* m8 shift/rotate */
+ 15,17, 1, /* m16 shift/rotate */
+
+ 22, 5,22, /* CMPS 8-bit */
+ 22, 5,22, /* CMPS 16-bit */
+ 15, 5,15, /* SCAS 8-bit */
+ 15, 5,15, /* SCAS 16-bit */
+ 12, 6,11, /* LODS 8-bit */
+ 12, 6,11, /* LODS 16-bit */
+ 10, 6, 9, /* STOS 8-bit */
+ 10, 6, 9, /* STOS 16-bit */
+ 14, 8, 8, /* MOVS 8-bit */
+ 14, 8, 8, /* MOVS 16-bit */
+
+ (void *)-1, /* marker to make sure we line up */
+
+ 14, 8, 8, /* (80186) INS 8-bit */
+ 14, 8, 8, /* (80186) INS 16-bit */
+ 14, 8, 8, /* (80186) OUTS 8-bit */
+ 14, 8, 8, /* (80186) OUTS 16-bit */
+ 14,68,83, /* (80186) PUSH immediate, PUSHA/POPA */
+ 22,29, /* (80186) IMUL immediate 8-bit */
+ 25,32, /* (80186) IMUL immediate 16-bit */
+ 15,25,4,16, 8, /* (80186) ENTER/LEAVE */
+ 33, /* (80186) BOUND */
+
+ (void *)-1 /* marker to make sure we line up */
+};
+
+
+/* these come from the 80286 timings in OPCODE.LST */
+/* many of these numbers are suspect */
+static const struct i80x86_timing i80286_cycles =
+{
+ 80286,
+
+ 23,17, /* exception, IRET */
+ 0, 2, 3, 1, /* INTs */
+ 2, /* segment overrides */
+ 2, 2, 2, /* flag operations */
+ 3, 3,16,14, /* arithmetic adjusts */
+ 3, 3, /* decimal adjusts */
+ 2, 2, /* sign extension */
+ 2, 7, 3, 3, 3, 5, /* misc */
+
+ 7, 7,11, /* direct JMPs */
+ 7,11,26, /* indirect JMPs */
+ 7,13, /* direct CALLs */
+ 7,11,29, /* indirect CALLs */
+ 11,15,11,15, /* returns */
+ 3, 7, 4, 8, /* conditional JMPs */
+ 4, 8, 4, 8, /* loops */
+
+ 5, 5, 5, 5, /* port reads */
+ 3, 3, 3, 3, /* port writes */
+
+ 2, 3, 3, /* move, 8-bit */
+ 2, 3, /* move, 8-bit immediate */
+ 2, 3, 3, /* move, 16-bit */
+ 2, 3, /* move, 16-bit immediate */
+ 5, 5, 3, 3, /* move, AL/AX memory */
+ 2, 5, 2, 3, /* move, segment registers */
+ 3, 5, /* exchange, 8-bit */
+ 3, 5, 3, /* exchange, 16-bit */
+
+ 5, 5, 3, 3, /* pushes */
+ 5, 5, 5, 5, /* pops */
+
+ 2, 7, 7, /* ALU ops, 8-bit */
+ 3, 7, 7, /* ALU ops, 8-bit immediate */
+ 2, 7, 7, /* ALU ops, 16-bit */
+ 3, 7, 7, /* ALU ops, 16-bit immediate */
+ 3, 7, 7, /* ALU ops, 16-bit w/8-bit immediate */
+ 13,21,16,24, /* MUL */
+ 13,21,16,24, /* IMUL */
+ 14,22,17,25, /* DIV */
+ 17,25,20,28, /* IDIV */
+ 2, 2, 7, 7, /* INC/DEC */
+ 2, 2, 7, 7, /* NEG/NOT */
+
+ 2, 5, 0, /* reg shift/rotate */
+ 7, 8, 1, /* m8 shift/rotate */
+ 7, 8, 1, /* m16 shift/rotate */
+
+ 13, 5,12, /* CMPS 8-bit */
+ 13, 5,12, /* CMPS 16-bit */
+ 9, 5, 8, /* SCAS 8-bit */
+ 9, 5, 8, /* SCAS 16-bit */
+ 5, 5, 4, /* LODS 8-bit */
+ 5, 5, 4, /* LODS 16-bit */
+ 4, 4, 3, /* STOS 8-bit */
+ 4, 4, 3, /* STOS 16-bit */
+ 5, 5, 4, /* MOVS 8-bit */
+ 5, 5, 4, /* MOVS 16-bit */
+
+ (void *)-1, /* marker to make sure we line up */
+
+ 5, 5, 4, /* (80186) INS 8-bit */
+ 5, 5, 4, /* (80186) INS 16-bit */
+ 5, 5, 4, /* (80186) OUTS 8-bit */
+ 5, 5, 4, /* (80186) OUTS 16-bit */
+ 3,17,19, /* (80186) PUSH immediate, PUSHA/POPA */
+ 21,24, /* (80186) IMUL immediate 8-bit */
+ 21,24, /* (80186) IMUL immediate 16-bit */
+ 11,15,12, 4, 5, /* (80186) ENTER/LEAVE */
+ 13, /* (80186) BOUND */
+
+ (void *)-1 /* marker to make sure we line up */
+};
diff --git a/src/emu/cpu/i86/i88intf.h b/src/emu/cpu/i86/i88intf.h
new file mode 100644
index 00000000000..76555583cd8
--- /dev/null
+++ b/src/emu/cpu/i86/i88intf.h
@@ -0,0 +1,9 @@
+#ifndef __I88INTR_H_
+#define __I88INTR_H_
+
+#include "i86intf.h"
+
+/* Public functions */
+void i8088_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/i86/instr186.c b/src/emu/cpu/i86/instr186.c
new file mode 100644
index 00000000000..11c313a3eb2
--- /dev/null
+++ b/src/emu/cpu/i86/instr186.c
@@ -0,0 +1,165 @@
+/****************************************************************************
+* real mode i286 emulator v1.4 by Fabrice Frances *
+* (initial work based on David Hedley's pcemu) *
+****************************************************************************/
+
+// file will be included in all cpu variants
+// function renaming will be added when neccessary
+// timing value should move to separate array
+
+#undef ICOUNT
+
+#define ICOUNT i8086_ICount
+
+
+static void PREFIX186(_pusha)(void) /* Opcode 0x60 */
+{
+ unsigned tmp=I.regs.w[SP];
+
+ ICOUNT -= cycles.pusha;
+ PUSH(I.regs.w[AX]);
+ PUSH(I.regs.w[CX]);
+ PUSH(I.regs.w[DX]);
+ PUSH(I.regs.w[BX]);
+ PUSH(tmp);
+ PUSH(I.regs.w[BP]);
+ PUSH(I.regs.w[SI]);
+ PUSH(I.regs.w[DI]);
+}
+
+static void PREFIX186(_popa)(void) /* Opcode 0x61 */
+{
+ unsigned tmp;
+
+ ICOUNT -= cycles.popa;
+ POP(I.regs.w[DI]);
+ POP(I.regs.w[SI]);
+ POP(I.regs.w[BP]);
+ POP(tmp);
+ POP(I.regs.w[BX]);
+ POP(I.regs.w[DX]);
+ POP(I.regs.w[CX]);
+ POP(I.regs.w[AX]);
+}
+
+static void PREFIX186(_bound)(void) /* Opcode 0x62 */
+{
+ unsigned ModRM = FETCHOP;
+ int low = (INT16)GetRMWord(ModRM);
+ int high= (INT16)GetnextRMWord;
+ int tmp= (INT16)RegWord(ModRM);
+ if (tmp<low || tmp>high) {
+ I.pc-=2;
+ PREFIX86(_interrupt)(5);
+ }
+ ICOUNT -= cycles.bound;
+}
+
+static void PREFIX186(_push_d16)(void) /* Opcode 0x68 */
+{
+ unsigned tmp = FETCH;
+
+ ICOUNT -= cycles.push_imm;
+ tmp += FETCH << 8;
+ PUSH(tmp);
+}
+
+static void PREFIX186(_imul_d16)(void) /* Opcode 0x69 */
+{
+ DEF_r16w(dst,src);
+ unsigned src2=FETCH;
+ src+=(FETCH<<8);
+
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.imul_rri16 : cycles.imul_rmi16;
+
+ dst = (INT32)((INT16)src)*(INT32)((INT16)src2);
+ I.CarryVal = I.OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1);
+ RegWord(ModRM)=(WORD)dst;
+}
+
+
+static void PREFIX186(_push_d8)(void) /* Opcode 0x6a */
+{
+ unsigned tmp = (WORD)((INT16)((INT8)FETCH));
+
+ ICOUNT -= cycles.push_imm;
+ PUSH(tmp);
+}
+
+static void PREFIX186(_imul_d8)(void) /* Opcode 0x6b */
+{
+ DEF_r16w(dst,src);
+ unsigned src2= (WORD)((INT16)((INT8)FETCH));
+
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.imul_rri8 : cycles.imul_rmi8;
+
+ dst = (INT32)((INT16)src)*(INT32)((INT16)src2);
+ I.CarryVal = I.OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1);
+ RegWord(ModRM)=(WORD)dst;
+}
+
+static void PREFIX186(_insb)(void) /* Opcode 0x6c */
+{
+ ICOUNT -= cycles.ins8;
+ PutMemB(ES,I.regs.w[DI],read_port_byte(I.regs.w[DX]));
+ I.regs.w[DI] += I.DirVal;
+}
+
+static void PREFIX186(_insw)(void) /* Opcode 0x6d */
+{
+ ICOUNT -= cycles.ins16;
+ PutMemW(ES,I.regs.w[DI],read_port_word(I.regs.w[DX]));
+ I.regs.w[DI] += 2 * I.DirVal;
+}
+
+static void PREFIX186(_outsb)(void) /* Opcode 0x6e */
+{
+ ICOUNT -= cycles.outs8;
+ write_port_byte(I.regs.w[DX],GetMemB(DS,I.regs.w[SI]));
+ I.regs.w[SI] += I.DirVal; /* GOL 11/27/01 */
+}
+
+static void PREFIX186(_outsw)(void) /* Opcode 0x6f */
+{
+ ICOUNT -= cycles.outs16;
+ write_port_word(I.regs.w[DX],GetMemW(DS,I.regs.w[SI]));
+ I.regs.w[SI] += 2 * I.DirVal; /* GOL 11/27/01 */
+}
+
+static void PREFIX186(_rotshft_bd8)(void) /* Opcode 0xc0 */
+{
+ unsigned ModRM = FETCH;
+ unsigned count = FETCH;
+
+ PREFIX86(_rotate_shift_Byte)(ModRM,count);
+}
+
+static void PREFIX186(_rotshft_wd8)(void) /* Opcode 0xc1 */
+{
+ unsigned ModRM = FETCH;
+ unsigned count = FETCH;
+
+ PREFIX86(_rotate_shift_Word)(ModRM,count);
+}
+
+static void PREFIX186(_enter)(void) /* Opcode 0xc8 */
+{
+ unsigned nb = FETCH; unsigned i,level;
+
+ nb += FETCH << 8;
+ level = FETCH;
+ ICOUNT -= (level == 0) ? cycles.enter0 : (level == 1) ? cycles.enter1 : cycles.enter_base + level * cycles.enter_count;
+ PUSH(I.regs.w[BP]);
+ I.regs.w[BP]=I.regs.w[SP];
+ I.regs.w[SP] -= nb;
+ for (i=1;i<level;i++)
+ PUSH(GetMemW(SS,I.regs.w[BP]-i*2));
+ if (level) PUSH(I.regs.w[BP]);
+}
+
+static void PREFIX186(_leave)(void) /* Opcode 0xc9 */
+{
+ ICOUNT -= cycles.leave;
+ I.regs.w[SP]=I.regs.w[BP];
+ POP(I.regs.w[BP]);
+}
diff --git a/src/emu/cpu/i86/instr186.h b/src/emu/cpu/i86/instr186.h
new file mode 100644
index 00000000000..54de28e18ad
--- /dev/null
+++ b/src/emu/cpu/i86/instr186.h
@@ -0,0 +1,27 @@
+/****************************************************************************
+* real mode i286 emulator v1.4 by Fabrice Frances *
+* (initial work based on David Hedley's pcemu) *
+****************************************************************************/
+
+// file will be included in all cpu variants
+// timing value should move to separate array
+
+static void PREFIX186(_pusha)(void);
+static void PREFIX186(_popa)(void);
+static void PREFIX186(_bound)(void);
+static void PREFIX186(_push_d16)(void);
+static void PREFIX186(_imul_d16)(void);
+static void PREFIX186(_push_d8)(void);
+static void PREFIX186(_imul_d8)(void);
+static void PREFIX186(_rotshft_bd8)(void);
+static void PREFIX186(_rotshft_wd8)(void);
+static void PREFIX186(_enter)(void);
+static void PREFIX186(_leave)(void);
+static void PREFIX186(_insb)(void);
+static void PREFIX186(_insw)(void);
+static void PREFIX186(_outsb)(void);
+static void PREFIX186(_outsw)(void);
+
+/* changed instructions */
+static void PREFIX186(_repne)(void);
+static void PREFIX186(_repe)(void);
diff --git a/src/emu/cpu/i86/instr286.c b/src/emu/cpu/i86/instr286.c
new file mode 100644
index 00000000000..23ae968f4fc
--- /dev/null
+++ b/src/emu/cpu/i86/instr286.c
@@ -0,0 +1,308 @@
+/* descriptor table format in memory
+ UINT16 limit
+ UINT24 addr
+ 0..3 type
+ system segment
+ 3 execute:
+ 0 data segment: readable,
+ 1: write
+ 2: expand down
+ 1 code segment
+ 1: readable
+ 2: conforming (can be used with higher privilege level)
+ 0: access (set when processor accesses segment)
+
+ 4 dt 0 system segment, 1 application segment (code, data)
+ 5,6 dpl descriptor privileg level
+ 7 p present 0 gives trap when accessed
+ UINT16 reserved (should be zero)
+*/
+#define WRITEABLE(a) ((a&0xa)==2)
+#define READABLE(a) ( ((a&0xa)==0xa)|| ((a&8)==0) )
+
+static void i80286_trap2(int number)
+{
+ i80286_interrupt(number);
+}
+
+static int i80286_selector_okay(UINT16 selector)
+{
+ if (selector&4) {
+ return (selector&~7)<I.ldtr.limit;
+ } else {
+ return (selector&~7)<I.gdtr.limit;
+ }
+}
+
+static offs_t i80286_selector_to_address(UINT16 selector)
+{
+ if (selector&4) {
+ return I.ldtr.base+(selector&~7);
+ } else {
+ return I.gdtr.base+(selector&~7);
+ }
+}
+
+static void i80286_data_descriptor(int reg, UINT16 selector)
+{
+ if (PM) {
+ UINT16 help;
+ /* selector format
+ 15..3 number/address in descriptor table
+ 2: 0 global, 1 local descriptor table
+ 1,0: requested privileg level
+ must be higher or same as current privileg level in code selector */
+ if (selector&4) { /* local descriptor table */
+ if (selector>I.ldtr.limit) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.sregs[reg]=selector;
+ I.limit[reg]=ReadWord(I.ldtr.base+(selector&~7));
+ I.base[reg]=ReadWord(I.ldtr.base+(selector&~7)+2)
+ |(ReadWord(I.ldtr.base+(selector&~7)+4)<<16);
+ I.rights[reg]=I.base[reg]>>24;
+ I.base[reg]&=0xffffff;
+ } else { /* global descriptor table */
+ if (!(selector&~7)||(selector>I.gdtr.limit)) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.sregs[reg]=selector;
+ I.limit[reg]=ReadWord(I.gdtr.base+(selector&~7));
+ I.base[reg]=ReadWord(I.gdtr.base+(selector&~7)+2);
+ help=ReadWord(I.gdtr.base+(selector&~7)+4);
+ I.rights[reg]=help>>8;
+ I.base[reg]|=(help&0xff)<<16;
+ }
+ } else {
+ I.sregs[reg]=selector;
+ I.base[reg]=selector<<4;
+ }
+}
+
+static void i80286_code_descriptor(UINT16 selector, UINT16 offset)
+{
+ UINT16 word1, word2, word3;
+ if (PM) {
+ /* selector format
+ 15..3 number/address in descriptor table
+ 2: 0 global, 1 local descriptor table
+ 1,0: requested privileg level
+ must be higher or same as current privileg level in code selector */
+ if (selector&4) { /* local descriptor table */
+ if (selector>I.ldtr.limit) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ word1=ReadWord(I.ldtr.base+(selector&~7));
+ word2=ReadWord(I.ldtr.base+(selector&~7)+2);
+ word3=ReadWord(I.ldtr.base+(selector&~7)+4);
+ } else { /* global descriptor table */
+ if (!(selector&~7)||(selector>I.gdtr.limit)) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ word1=ReadWord(I.gdtr.base+(selector&~7));
+ word2=ReadWord(I.gdtr.base+(selector&~7)+2);
+ word3=ReadWord(I.gdtr.base+(selector&~7)+4);
+ }
+ if (word3&0x1000) {
+ I.sregs[CS]=selector;
+ I.limit[CS]=word1;
+ I.base[CS]=word2|((word3&0xff)<<16);
+ I.rights[CS]=word3>>8;
+ I.pc=I.base[CS]+offset;
+ } else { // systemdescriptor
+ switch (word3&0xf00) {
+ case 0x400: // call gate
+ // word3&0x1f words to be copied from stack to stack
+ i80286_data_descriptor(CS, word2);
+ I.pc=I.base[CS]+word1;
+ break;
+ case 0x500: // task gate
+ i80286_data_descriptor(CS, word2);
+ I.pc=I.base[CS]+word1;
+ break;
+ case 0x600: // interrupt gate
+ I.TF = I.IF = 0;
+ i80286_data_descriptor(CS, word2);
+ I.pc=I.base[CS]+word1;
+ break;
+ case 0x700: // trap gate
+ i80286_data_descriptor(CS, word2);
+ I.pc=I.base[CS]+word1;
+ break;
+ }
+ }
+ } else {
+ I.sregs[CS]=selector;
+ I.base[CS]=selector<<4;
+ I.pc=I.base[CS]+offset;
+ }
+}
+
+static void i80286_interrupt_descriptor(UINT16 number)
+{
+ UINT16 word1,word2,word3;
+ if ((number<<3)>=I.idtr.limit) {
+ ;// go into shutdown mode
+ return;
+ }
+ PREFIX(_pushf());
+ PUSH(I.sregs[CS]);
+ PUSH(I.pc - I.base[CS]);
+ word1=ReadWord(I.idtr.base+(number<<3));
+ word2=ReadWord(I.idtr.base+(number<<3)+2);
+ word3=ReadWord(I.idtr.base+(number<<3)+4);
+ switch (word3&0xf00) {
+ case 0x500: // task gate
+ i80286_data_descriptor(CS, word2);
+ I.pc=I.base[CS]+word1;
+ break;
+ case 0x600: // interrupt gate
+ I.TF = I.IF = 0;
+ i80286_data_descriptor(CS, word2);
+ I.pc=I.base[CS]+word1;
+ break;
+ case 0x700: // trap gate
+ i80286_data_descriptor(CS, word2);
+ I.pc=I.base[CS]+word1;
+ break;
+ }
+}
+
+static void PREFIX286(_0fpre)(void)
+{
+ unsigned next = FETCHOP;
+ UINT16 ModRM;
+ UINT16 tmp;
+ offs_t addr;
+
+ switch (next) {
+ case 0:
+ ModRM=FETCHOP;
+ switch (ModRM&0x38) {
+ case 0: /* sldt */
+ if (!PM) i80286_trap2(ILLEGAL_INSTRUCTION);
+ PutRMWord(ModRM, I.ldtr.sel);
+ break;
+ case 8: /* str */
+ if (!PM) i80286_trap2(ILLEGAL_INSTRUCTION);
+ PutRMWord(ModRM, I.tr.sel);
+ break;
+ case 0x10: /* lldt */
+ if (!PM) i80286_trap2(ILLEGAL_INSTRUCTION);
+ if (PM&&(CPL!=0)) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.ldtr.sel=GetRMWord(ModRM);
+ if ((I.ldtr.sel&~7)>=I.gdtr.limit) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.ldtr.limit=ReadWord(I.gdtr.base+(I.ldtr.sel&~7));
+ I.ldtr.base=ReadWord(I.gdtr.base+(I.ldtr.sel&~7)+2)
+ |(ReadWord(I.gdtr.base+(I.ldtr.sel&~7)+4)<<16);
+ I.ldtr.rights=I.ldtr.base>>24;
+ I.ldtr.base&=0xffffff;
+ break;
+ case 0x18: /* ltr */
+ if (!PM) i80286_trap2(ILLEGAL_INSTRUCTION);
+ if (CPL!=0) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.tr.sel=GetRMWord(ModRM);
+ if ((I.tr.sel&~7)>=I.gdtr.limit) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.tr.limit=ReadWord(I.gdtr.base+(I.tr.sel&~7));
+ I.tr.base=ReadWord(I.gdtr.base+(I.tr.sel&~7)+2)
+ |(ReadWord(I.gdtr.base+(I.tr.sel&~7)+4)<<16);
+ I.tr.rights=I.tr.base>>24;
+ I.tr.base&=0xffffff;
+ break;
+ case 0x20: /* verr */
+ if (!PM) i80286_trap2(ILLEGAL_INSTRUCTION);
+ tmp=GetRMWord(ModRM);
+ if (tmp&4) {
+ I.ZeroVal=( ((tmp&~7)<I.ldtr.limit)
+ && READABLE( ReadByte(I.ldtr.base+(tmp&~7)+5)) );
+ } else {
+ I.ZeroVal=( ((tmp&~7)<I.gdtr.limit)
+ && READABLE( ReadByte(I.gdtr.base+(tmp&~7)+5)) );
+ }
+ break;
+ case 0x28: /* verw */
+ if (!PM) i80286_trap2(ILLEGAL_INSTRUCTION);
+ tmp=GetRMWord(ModRM);
+ if (tmp&4) {
+ I.ZeroVal=( ((tmp&~7)<I.ldtr.limit)
+ && WRITEABLE( ReadByte(I.ldtr.base+(tmp&~7)+5)) );
+ } else {
+ I.ZeroVal=( ((tmp&~7)<I.gdtr.limit)
+ && WRITEABLE( ReadByte(I.gdtr.base+(tmp&~7)+5)) );
+ }
+ break;
+ default:
+ i80286_trap2(ILLEGAL_INSTRUCTION);
+ break;
+ }
+ break;
+ case 1:
+ /* lgdt, lldt in protected mode privilege level 0 required else common protection
+ failure 0xd */
+ ModRM = FETCHOP;
+ switch (ModRM&0x38) {
+ case 0: /* sgdt */
+ PutRMWord(ModRM,I.gdtr.limit);
+ PutRMWordOffset(2,I.gdtr.base&0xffff);
+ PutRMByteOffset(4,I.gdtr.base>>16);
+ break;
+ case 8: /* sidt */
+ PutRMWord(ModRM,I.idtr.limit);
+ PutRMWordOffset(2,I.idtr.base&0xffff);
+ PutRMByteOffset(4,I.idtr.base>>16);
+ break;
+ case 0x10: /* lgdt */
+ if (PM&&(CPL!=0)) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.gdtr.limit=GetRMWord(ModRM);
+ I.gdtr.base=GetRMWordOffset(2)|(GetRMByteOffset(4)<<16);
+ break;
+ case 0x18: /* lidt */
+ if (PM&&(CPL!=0)) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.idtr.limit=GetRMWord(ModRM);
+ I.idtr.base=GetRMWordOffset(2)|(GetRMByteOffset(4)<<16);
+ break;
+ case 0x20: /* smsw */
+ PutRMWord(ModRM, I.msw);
+ break;
+ case 0x30: /* lmsw */
+ if (PM&&(CPL!=0)) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.msw=(I.msw&1)|GetRMWord(ModRM);
+ break;
+ default:
+ i80286_trap2(ILLEGAL_INSTRUCTION);
+ break;
+ }
+ break;
+ case 2: /* LAR */
+ ModRM = FETCHOP;
+ tmp=GetRMWord(ModRM);
+ I.ZeroVal=i80286_selector_okay(tmp);
+ if (I.ZeroVal) {
+ RegWord(ModRM)=tmp;
+ }
+ break;
+ case 3: /* LSL */
+ if (!PM) i80286_trap2(ILLEGAL_INSTRUCTION);
+ ModRM = FETCHOP;
+ tmp=GetRMWord(ModRM);
+ I.ZeroVal=i80286_selector_okay(tmp);
+ if (I.ZeroVal) {
+ addr=i80286_selector_to_address(tmp);
+ RegWord(ModRM)=ReadWord(addr);
+ }
+ break;
+ case 6: /* clts */
+ if (PM&&(CPL!=0)) i80286_trap2(GENERAL_PROTECTION_FAULT);
+ I.msw=~8;
+ break;
+ default:
+ i80286_trap2(ILLEGAL_INSTRUCTION);
+ break;
+ }
+}
+
+static void PREFIX286(_arpl)(void) /* 0x63 */
+{
+ if (PM) {
+ UINT16 ModRM=FETCHOP, tmp=GetRMWord(ModRM);
+
+ I.ZeroVal=i80286_selector_okay(RegWord(ModRM))
+ &&i80286_selector_okay(RegWord(ModRM))
+ &&((tmp&3)<(RegWord(ModRM)&3));
+ if (I.ZeroVal) PutbackRMWord(ModRM, (tmp&~3)|(RegWord(ModRM)&3));
+ } else {
+ i80286_trap2(ILLEGAL_INSTRUCTION);
+ }
+}
diff --git a/src/emu/cpu/i86/instr286.h b/src/emu/cpu/i86/instr286.h
new file mode 100644
index 00000000000..53431ada3be
--- /dev/null
+++ b/src/emu/cpu/i86/instr286.h
@@ -0,0 +1,13 @@
+#define ILLEGAL_INSTRUCTION 6
+#define GENERAL_PROTECTION_FAULT 0xd
+
+#define PM (I.msw&1)
+#define CPL (I.sregs[CS]&3)
+#define IOPL ((I.flags&0x3000)>>12)
+
+static void i80286_trap2(int number);
+static void i80286_interrupt_descriptor(UINT16 number);
+static void i80286_code_descriptor(UINT16 selector, UINT16 offset);
+static void i80286_data_descriptor(int reg, UINT16 selector);
+static void PREFIX286(_0fpre)(void);
+static void PREFIX286(_arpl)(void);
diff --git a/src/emu/cpu/i86/instr86.c b/src/emu/cpu/i86/instr86.c
new file mode 100644
index 00000000000..0ede0be802f
--- /dev/null
+++ b/src/emu/cpu/i86/instr86.c
@@ -0,0 +1,3137 @@
+/****************************************************************************
+* real mode i286 emulator v1.4 by Fabrice Frances *
+* (initial work based on David Hedley's pcemu) *
+****************************************************************************/
+
+/*
+ * file will be included in all cpu variants
+ * put non i86 instructions in own files (i286, i386, nec)
+ * function renaming will be added when neccessary
+ * timing value should move to separate array
+ */
+
+#undef ICOUNT
+
+#define ICOUNT i8086_ICount
+
+
+#if !defined(I80186)
+static void PREFIX86(_interrupt)(unsigned int_num)
+{
+ unsigned dest_seg, dest_off;
+ WORD ip = I.pc - I.base[CS];
+
+ if (int_num == -1)
+ int_num = (*I.irq_callback)(0);
+
+#ifdef I80286
+ if (PM) {
+ i80286_interrupt_descriptor(int_num);
+ } else {
+#endif
+ dest_off = ReadWord(int_num*4);
+ dest_seg = ReadWord(int_num*4+2);
+
+ PREFIX(_pushf());
+ I.TF = I.IF = 0;
+ PUSH(I.sregs[CS]);
+ PUSH(ip);
+ I.sregs[CS] = (WORD)dest_seg;
+ I.base[CS] = SegBase(CS);
+ I.pc = (I.base[CS] + dest_off) & AMASK;
+#ifdef I80286
+ }
+#endif
+ CHANGE_PC(I.pc);
+
+ I.extra_cycles += cycles.exception;
+}
+
+static void PREFIX86(_trap)(void)
+{
+ PREFIX(_instruction)[FETCHOP]();
+ PREFIX(_interrupt)(1);
+}
+#endif
+
+#ifndef I80186
+static void PREFIX86(_rotate_shift_Byte)(unsigned ModRM, unsigned count)
+{
+ unsigned src = (unsigned)GetRMByte(ModRM);
+ unsigned dst=src;
+
+ if (count==0)
+ {
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.rot_reg_base : cycles.rot_m8_base;
+ }
+ else if (count==1)
+ {
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.rot_reg_1 : cycles.rot_m8_1;
+
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* ROL eb,1 */
+ I.CarryVal = src & 0x80;
+ dst=(src<<1)+CF;
+ PutbackRMByte(ModRM,dst);
+ I.OverVal = (src^dst)&0x80;
+ break;
+ case 0x08: /* ROR eb,1 */
+ I.CarryVal = src & 0x01;
+ dst = ((CF<<8)+src) >> 1;
+ PutbackRMByte(ModRM,dst);
+ I.OverVal = (src^dst)&0x80;
+ break;
+ case 0x10: /* RCL eb,1 */
+ dst=(src<<1)+CF;
+ PutbackRMByte(ModRM,dst);
+ SetCFB(dst);
+ I.OverVal = (src^dst)&0x80;
+ break;
+ case 0x18: /* RCR eb,1 */
+ dst = ((CF<<8)+src) >> 1;
+ PutbackRMByte(ModRM,dst);
+ I.CarryVal = src & 0x01;
+ I.OverVal = (src^dst)&0x80;
+ break;
+ case 0x20: /* SHL eb,1 */
+ case 0x30:
+ dst = src << 1;
+ PutbackRMByte(ModRM,dst);
+ SetCFB(dst);
+ I.OverVal = (src^dst)&0x80;
+ I.AuxVal = 1;
+ SetSZPF_Byte(dst);
+ break;
+ case 0x28: /* SHR eb,1 */
+ dst = src >> 1;
+ PutbackRMByte(ModRM,dst);
+ I.CarryVal = src & 0x01;
+ I.OverVal = src & 0x80;
+ I.AuxVal = 1;
+ SetSZPF_Byte(dst);
+ break;
+ case 0x38: /* SAR eb,1 */
+ dst = ((INT8)src) >> 1;
+ PutbackRMByte(ModRM,dst);
+ I.CarryVal = src & 0x01;
+ I.OverVal = 0;
+ I.AuxVal = 1;
+ SetSZPF_Byte(dst);
+ break;
+ }
+ }
+ else
+ {
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.rot_reg_base + cycles.rot_reg_bit : cycles.rot_m8_base + cycles.rot_m8_bit;
+
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* ROL eb,count */
+ for (; count > 0; count--)
+ {
+ I.CarryVal = dst & 0x80;
+ dst = (dst << 1) + CF;
+ }
+ PutbackRMByte(ModRM,(BYTE)dst);
+ break;
+ case 0x08: /* ROR eb,count */
+ for (; count > 0; count--)
+ {
+ I.CarryVal = dst & 0x01;
+ dst = (dst >> 1) + (CF << 7);
+ }
+ PutbackRMByte(ModRM,(BYTE)dst);
+ break;
+ case 0x10: /* RCL eb,count */
+ for (; count > 0; count--)
+ {
+ dst = (dst << 1) + CF;
+ SetCFB(dst);
+ }
+ PutbackRMByte(ModRM,(BYTE)dst);
+ break;
+ case 0x18: /* RCR eb,count */
+ for (; count > 0; count--)
+ {
+ dst = (CF<<8)+dst;
+ I.CarryVal = dst & 0x01;
+ dst >>= 1;
+ }
+ PutbackRMByte(ModRM,(BYTE)dst);
+ break;
+ case 0x20:
+ case 0x30: /* SHL eb,count */
+ dst <<= count;
+ SetCFB(dst);
+ I.AuxVal = 1;
+ SetSZPF_Byte(dst);
+ PutbackRMByte(ModRM,(BYTE)dst);
+ break;
+ case 0x28: /* SHR eb,count */
+ dst >>= count-1;
+ I.CarryVal = dst & 0x1;
+ dst >>= 1;
+ SetSZPF_Byte(dst);
+ I.AuxVal = 1;
+ PutbackRMByte(ModRM,(BYTE)dst);
+ break;
+ case 0x38: /* SAR eb,count */
+ dst = ((INT8)dst) >> (count-1);
+ I.CarryVal = dst & 0x1;
+ dst = ((INT8)((BYTE)dst)) >> 1;
+ SetSZPF_Byte(dst);
+ I.AuxVal = 1;
+ PutbackRMByte(ModRM,(BYTE)dst);
+ break;
+ }
+ }
+}
+
+static void PREFIX86(_rotate_shift_Word)(unsigned ModRM, unsigned count)
+{
+ unsigned src = GetRMWord(ModRM);
+ unsigned dst=src;
+
+ if (count==0)
+ {
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.rot_reg_base : cycles.rot_m16_base;
+ }
+ else if (count==1)
+ {
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.rot_reg_1 : cycles.rot_m16_1;
+
+ switch (ModRM & 0x38)
+ {
+#if 0
+ case 0x00: /* ROL ew,1 */
+ tmp2 = (tmp << 1) + CF;
+ SetCFW(tmp2);
+ I.OverVal = !(!(tmp & 0x4000)) != CF;
+ PutbackRMWord(ModRM,tmp2);
+ break;
+ case 0x08: /* ROR ew,1 */
+ I.CarryVal = tmp & 0x01;
+ tmp2 = (tmp >> 1) + ((unsigned)CF << 15);
+ I.OverVal = !(!(tmp & 0x8000)) != CF;
+ PutbackRMWord(ModRM,tmp2);
+ break;
+ case 0x10: /* RCL ew,1 */
+ tmp2 = (tmp << 1) + CF;
+ SetCFW(tmp2);
+ I.OverVal = (tmp ^ (tmp << 1)) & 0x8000;
+ PutbackRMWord(ModRM,tmp2);
+ break;
+ case 0x18: /* RCR ew,1 */
+ tmp2 = (tmp >> 1) + ((unsigned)CF << 15);
+ I.OverVal = !(!(tmp & 0x8000)) != CF;
+ I.CarryVal = tmp & 0x01;
+ PutbackRMWord(ModRM,tmp2);
+ break;
+ case 0x20: /* SHL ew,1 */
+ case 0x30:
+ tmp <<= 1;
+
+ SetCFW(tmp);
+ SetOFW_Add(tmp,tmp2,tmp2);
+ I.AuxVal = 1;
+ SetSZPF_Word(tmp);
+
+ PutbackRMWord(ModRM,tmp);
+ break;
+ case 0x28: /* SHR ew,1 */
+ I.CarryVal = tmp & 0x01;
+ I.OverVal = tmp & 0x8000;
+
+ tmp2 = tmp >> 1;
+
+ SetSZPF_Word(tmp2);
+ I.AuxVal = 1;
+ PutbackRMWord(ModRM,tmp2);
+ break;
+ case 0x38: /* SAR ew,1 */
+ I.CarryVal = tmp & 0x01;
+ I.OverVal = 0;
+
+ tmp2 = (tmp >> 1) | (tmp & 0x8000);
+
+ SetSZPF_Word(tmp2);
+ I.AuxVal = 1;
+ PutbackRMWord(ModRM,tmp2);
+ break;
+#else
+ case 0x00: /* ROL ew,1 */
+ I.CarryVal = src & 0x8000;
+ dst=(src<<1)+CF;
+ PutbackRMWord(ModRM,dst);
+ I.OverVal = (src^dst)&0x8000;
+ break;
+ case 0x08: /* ROR ew,1 */
+ I.CarryVal = src & 0x01;
+ dst = ((CF<<16)+src) >> 1;
+ PutbackRMWord(ModRM,dst);
+ I.OverVal = (src^dst)&0x8000;
+ break;
+ case 0x10: /* RCL ew,1 */
+ dst=(src<<1)+CF;
+ PutbackRMWord(ModRM,dst);
+ SetCFW(dst);
+ I.OverVal = (src^dst)&0x8000;
+ break;
+ case 0x18: /* RCR ew,1 */
+ dst = ((CF<<16)+src) >> 1;
+ PutbackRMWord(ModRM,dst);
+ I.CarryVal = src & 0x01;
+ I.OverVal = (src^dst)&0x8000;
+ break;
+ case 0x20: /* SHL ew,1 */
+ case 0x30:
+ dst = src << 1;
+ PutbackRMWord(ModRM,dst);
+ SetCFW(dst);
+ I.OverVal = (src^dst)&0x8000;
+ I.AuxVal = 1;
+ SetSZPF_Word(dst);
+ break;
+ case 0x28: /* SHR ew,1 */
+ dst = src >> 1;
+ PutbackRMWord(ModRM,dst);
+ I.CarryVal = src & 0x01;
+ I.OverVal = src & 0x8000;
+ I.AuxVal = 1;
+ SetSZPF_Word(dst);
+ break;
+ case 0x38: /* SAR ew,1 */
+ dst = ((INT16)src) >> 1;
+ PutbackRMWord(ModRM,dst);
+ I.CarryVal = src & 0x01;
+ I.OverVal = 0;
+ I.AuxVal = 1;
+ SetSZPF_Word(dst);
+ break;
+#endif
+ }
+ }
+ else
+ {
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.rot_reg_base + cycles.rot_reg_bit : cycles.rot_m8_base + cycles.rot_m16_bit;
+
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* ROL ew,count */
+ for (; count > 0; count--)
+ {
+ I.CarryVal = dst & 0x8000;
+ dst = (dst << 1) + CF;
+ }
+ PutbackRMWord(ModRM,dst);
+ break;
+ case 0x08: /* ROR ew,count */
+ for (; count > 0; count--)
+ {
+ I.CarryVal = dst & 0x01;
+ dst = (dst >> 1) + (CF << 15);
+ }
+ PutbackRMWord(ModRM,dst);
+ break;
+ case 0x10: /* RCL ew,count */
+ for (; count > 0; count--)
+ {
+ dst = (dst << 1) + CF;
+ SetCFW(dst);
+ }
+ PutbackRMWord(ModRM,dst);
+ break;
+ case 0x18: /* RCR ew,count */
+ for (; count > 0; count--)
+ {
+ dst = dst + (CF << 16);
+ I.CarryVal = dst & 0x01;
+ dst >>= 1;
+ }
+ PutbackRMWord(ModRM,dst);
+ break;
+ case 0x20:
+ case 0x30: /* SHL ew,count */
+ dst <<= count;
+ SetCFW(dst);
+ I.AuxVal = 1;
+ SetSZPF_Word(dst);
+ PutbackRMWord(ModRM,dst);
+ break;
+ case 0x28: /* SHR ew,count */
+ dst >>= count-1;
+ I.CarryVal = dst & 0x1;
+ dst >>= 1;
+ SetSZPF_Word(dst);
+ I.AuxVal = 1;
+ PutbackRMWord(ModRM,dst);
+ break;
+ case 0x38: /* SAR ew,count */
+ dst = ((INT16)dst) >> (count-1);
+ I.CarryVal = dst & 0x01;
+ dst = ((INT16)((WORD)dst)) >> 1;
+ SetSZPF_Word(dst);
+ I.AuxVal = 1;
+ PutbackRMWord(ModRM,dst);
+ break;
+ }
+ }
+}
+#endif
+
+static void PREFIX(rep)(int flagval)
+{
+ /* Handles rep- and repnz- prefixes. flagval is the value of ZF for the
+ loop to continue for CMPS and SCAS instructions. */
+
+ unsigned next = FETCHOP;
+ unsigned count = I.regs.w[CX];
+
+ switch(next)
+ {
+ case 0x26: /* ES: */
+ seg_prefix=TRUE;
+ prefix_base=I.base[ES];
+ ICOUNT -= cycles.override;
+ PREFIX(rep)(flagval);
+ break;
+ case 0x2e: /* CS: */
+ seg_prefix=TRUE;
+ prefix_base=I.base[CS];
+ ICOUNT -= cycles.override;
+ PREFIX(rep)(flagval);
+ break;
+ case 0x36: /* SS: */
+ seg_prefix=TRUE;
+ prefix_base=I.base[SS];
+ ICOUNT -= cycles.override;
+ PREFIX(rep)(flagval);
+ break;
+ case 0x3e: /* DS: */
+ seg_prefix=TRUE;
+ prefix_base=I.base[DS];
+ ICOUNT -= cycles.override;
+ PREFIX(rep)(flagval);
+ break;
+#ifndef I8086
+ case 0x6c: /* REP INSB */
+ ICOUNT -= cycles.rep_ins8_base;
+ for (; count > 0; count--)
+ {
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ PutMemB(ES,I.regs.w[DI],read_port_byte(I.regs.w[DX]));
+ I.regs.w[DI] += I.DirVal;
+ ICOUNT -= cycles.rep_ins8_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0x6d: /* REP INSW */
+ ICOUNT -= cycles.rep_ins16_base;
+ for (; count > 0; count--)
+ {
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ PutMemW(ES,I.regs.w[DI],read_port_word(I.regs.w[DX]));
+ I.regs.w[DI] += 2 * I.DirVal;
+ ICOUNT -= cycles.rep_ins16_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0x6e: /* REP OUTSB */
+ ICOUNT -= cycles.rep_outs8_base;
+ for (; count > 0; count--)
+ {
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ write_port_byte(I.regs.w[DX],GetMemB(DS,I.regs.w[SI]));
+ I.regs.w[SI] += I.DirVal; /* GOL 11/27/01 */
+ ICOUNT -= cycles.rep_outs8_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0x6f: /* REP OUTSW */
+ ICOUNT -= cycles.rep_outs16_base;
+ for (; count > 0; count--)
+ {
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ write_port_word(I.regs.w[DX],GetMemW(DS,I.regs.w[SI]));
+ I.regs.w[SI] += 2 * I.DirVal; /* GOL 11/27/01 */
+ ICOUNT -= cycles.rep_outs16_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+#endif
+ case 0xa4: /* REP MOVSB */
+ ICOUNT -= cycles.rep_movs8_base;
+ for (; count > 0; count--)
+ {
+ BYTE tmp;
+
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ tmp = GetMemB(DS,I.regs.w[SI]);
+ PutMemB(ES,I.regs.w[DI], tmp);
+ I.regs.w[DI] += I.DirVal;
+ I.regs.w[SI] += I.DirVal;
+ ICOUNT -= cycles.rep_movs8_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0xa5: /* REP MOVSW */
+ ICOUNT -= cycles.rep_movs16_base;
+ for (; count > 0; count--)
+ {
+ WORD tmp;
+
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ tmp = GetMemW(DS,I.regs.w[SI]);
+ PutMemW(ES,I.regs.w[DI], tmp);
+ I.regs.w[DI] += 2 * I.DirVal;
+ I.regs.w[SI] += 2 * I.DirVal;
+ ICOUNT -= cycles.rep_movs16_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0xa6: /* REP(N)E CMPSB */
+ ICOUNT -= cycles.rep_cmps8_base;
+ for (I.ZeroVal = !flagval; (ZF == flagval) && (count > 0); count--)
+ {
+ unsigned dst, src;
+
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ dst = GetMemB(ES, I.regs.w[DI]);
+ src = GetMemB(DS, I.regs.w[SI]);
+ SUBB(src,dst); /* opposite of the usual convention */
+ I.regs.w[DI] += I.DirVal;
+ I.regs.w[SI] += I.DirVal;
+ ICOUNT -= cycles.rep_cmps8_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0xa7: /* REP(N)E CMPSW */
+ ICOUNT -= cycles.rep_cmps16_base;
+ for (I.ZeroVal = !flagval; (ZF == flagval) && (count > 0); count--)
+ {
+ unsigned dst, src;
+
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ dst = GetMemW(ES, I.regs.w[DI]);
+ src = GetMemW(DS, I.regs.w[SI]);
+ SUBW(src,dst); /* opposite of the usual convention */
+ I.regs.w[DI] += 2 * I.DirVal;
+ I.regs.w[SI] += 2 * I.DirVal;
+ ICOUNT -= cycles.rep_cmps16_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0xaa: /* REP STOSB */
+ ICOUNT -= cycles.rep_stos8_base;
+ for (; count > 0; count--)
+ {
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ PutMemB(ES,I.regs.w[DI],I.regs.b[AL]);
+ I.regs.w[DI] += I.DirVal;
+ ICOUNT -= cycles.rep_stos8_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0xab: /* REP STOSW */
+ ICOUNT -= cycles.rep_stos16_base;
+ for (; count > 0; count--)
+ {
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ PutMemW(ES,I.regs.w[DI],I.regs.w[AX]);
+ I.regs.w[DI] += 2 * I.DirVal;
+ ICOUNT -= cycles.rep_stos16_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0xac: /* REP LODSB */
+ ICOUNT -= cycles.rep_lods8_base;
+ for (; count > 0; count--)
+ {
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ I.regs.b[AL] = GetMemB(DS,I.regs.w[SI]);
+ I.regs.w[SI] += I.DirVal;
+ ICOUNT -= cycles.rep_lods8_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0xad: /* REP LODSW */
+ ICOUNT -= cycles.rep_lods16_base;
+ for (; count > 0; count--)
+ {
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ I.regs.w[AX] = GetMemW(DS,I.regs.w[SI]);
+ I.regs.w[SI] += 2 * I.DirVal;
+ ICOUNT -= cycles.rep_lods16_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0xae: /* REP(N)E SCASB */
+ ICOUNT -= cycles.rep_scas8_base;
+ for (I.ZeroVal = !flagval; (ZF == flagval) && (count > 0); count--)
+ {
+ unsigned src, dst;
+
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ src = GetMemB(ES, I.regs.w[DI]);
+ dst = I.regs.b[AL];
+ SUBB(dst,src);
+ I.regs.w[DI] += I.DirVal;
+ ICOUNT -= cycles.rep_scas8_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ case 0xaf: /* REP(N)E SCASW */
+ ICOUNT -= cycles.rep_scas16_base;
+ for (I.ZeroVal = !flagval; (ZF == flagval) && (count > 0); count--)
+ {
+ unsigned src, dst;
+
+ if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
+ src = GetMemW(ES, I.regs.w[DI]);
+ dst = I.regs.w[AX];
+ SUBW(dst,src);
+ I.regs.w[DI] += 2 * I.DirVal;
+ ICOUNT -= cycles.rep_scas16_count;
+ }
+ I.regs.w[CX]=count;
+ break;
+ default:
+ PREFIX(_instruction)[next]();
+ }
+}
+
+#ifndef I80186
+static void PREFIX86(_add_br8)(void) /* Opcode 0x00 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_mr8;
+ ADDB(dst,src);
+ PutbackRMByte(ModRM,dst);
+}
+
+static void PREFIX86(_add_wr16)(void) /* Opcode 0x01 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_mr16;
+ ADDW(dst,src);
+ PutbackRMWord(ModRM,dst);
+}
+
+static void PREFIX86(_add_r8b)(void) /* Opcode 0x02 */
+{
+ DEF_r8b(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ ADDB(dst,src);
+ RegByte(ModRM)=dst;
+}
+
+static void PREFIX86(_add_r16w)(void) /* Opcode 0x03 */
+{
+ DEF_r16w(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ ADDW(dst,src);
+ RegWord(ModRM)=dst;
+}
+
+
+static void PREFIX86(_add_ald8)(void) /* Opcode 0x04 */
+{
+ DEF_ald8(dst,src);
+ ICOUNT -= cycles.alu_ri8;
+ ADDB(dst,src);
+ I.regs.b[AL]=dst;
+}
+
+
+static void PREFIX86(_add_axd16)(void) /* Opcode 0x05 */
+{
+ DEF_axd16(dst,src);
+ ICOUNT -= cycles.alu_ri16;
+ ADDW(dst,src);
+ I.regs.w[AX]=dst;
+}
+
+
+static void PREFIX86(_push_es)(void) /* Opcode 0x06 */
+{
+ ICOUNT -= cycles.push_seg;
+ PUSH(I.sregs[ES]);
+}
+
+
+static void PREFIX86(_pop_es)(void) /* Opcode 0x07 */
+{
+ POP(I.sregs[ES]);
+ I.base[ES] = SegBase(ES);
+ ICOUNT -= cycles.pop_seg;
+}
+
+static void PREFIX86(_or_br8)(void) /* Opcode 0x08 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_mr8;
+ ORB(dst,src);
+ PutbackRMByte(ModRM,dst);
+}
+
+static void PREFIX86(_or_wr16)(void) /* Opcode 0x09 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_mr16;
+ ORW(dst,src);
+ PutbackRMWord(ModRM,dst);
+}
+
+static void PREFIX86(_or_r8b)(void) /* Opcode 0x0a */
+{
+ DEF_r8b(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ ORB(dst,src);
+ RegByte(ModRM)=dst;
+}
+
+static void PREFIX86(_or_r16w)(void) /* Opcode 0x0b */
+{
+ DEF_r16w(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ ORW(dst,src);
+ RegWord(ModRM)=dst;
+}
+
+static void PREFIX86(_or_ald8)(void) /* Opcode 0x0c */
+{
+ DEF_ald8(dst,src);
+ ICOUNT -= cycles.alu_ri8;
+ ORB(dst,src);
+ I.regs.b[AL]=dst;
+}
+
+static void PREFIX86(_or_axd16)(void) /* Opcode 0x0d */
+{
+ DEF_axd16(dst,src);
+ ICOUNT -= cycles.alu_ri16;
+ ORW(dst,src);
+ I.regs.w[AX]=dst;
+}
+
+static void PREFIX86(_push_cs)(void) /* Opcode 0x0e */
+{
+ ICOUNT -= cycles.push_seg;
+ PUSH(I.sregs[CS]);
+}
+
+/* Opcode 0x0f invalid */
+
+static void PREFIX86(_adc_br8)(void) /* Opcode 0x10 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_mr8;
+ src+=CF;
+ ADDB(dst,src);
+ PutbackRMByte(ModRM,dst);
+}
+
+static void PREFIX86(_adc_wr16)(void) /* Opcode 0x11 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_mr16;
+ src+=CF;
+ ADDW(dst,src);
+ PutbackRMWord(ModRM,dst);
+}
+
+static void PREFIX86(_adc_r8b)(void) /* Opcode 0x12 */
+{
+ DEF_r8b(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ src+=CF;
+ ADDB(dst,src);
+ RegByte(ModRM)=dst;
+}
+
+static void PREFIX86(_adc_r16w)(void) /* Opcode 0x13 */
+{
+ DEF_r16w(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ src+=CF;
+ ADDW(dst,src);
+ RegWord(ModRM)=dst;
+}
+
+static void PREFIX86(_adc_ald8)(void) /* Opcode 0x14 */
+{
+ DEF_ald8(dst,src);
+ ICOUNT -= cycles.alu_ri8;
+ src+=CF;
+ ADDB(dst,src);
+ I.regs.b[AL] = dst;
+}
+
+static void PREFIX86(_adc_axd16)(void) /* Opcode 0x15 */
+{
+ DEF_axd16(dst,src);
+ ICOUNT -= cycles.alu_ri16;
+ src+=CF;
+ ADDW(dst,src);
+ I.regs.w[AX]=dst;
+}
+
+static void PREFIX86(_push_ss)(void) /* Opcode 0x16 */
+{
+ PUSH(I.sregs[SS]);
+ ICOUNT -= cycles.push_seg;
+}
+
+static void PREFIX86(_pop_ss)(void) /* Opcode 0x17 */
+{
+#ifdef I80286
+ UINT16 tmp;
+ POP(tmp);
+ i80286_data_descriptor(SS, tmp);
+#else
+ POP(I.sregs[SS]);
+ I.base[SS] = SegBase(SS);
+#endif
+ ICOUNT -= cycles.pop_seg;
+ PREFIX(_instruction)[FETCHOP](); /* no interrupt before next instruction */
+}
+
+static void PREFIX86(_sbb_br8)(void) /* Opcode 0x18 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_mr8;
+ src+=CF;
+ SUBB(dst,src);
+ PutbackRMByte(ModRM,dst);
+}
+
+static void PREFIX86(_sbb_wr16)(void) /* Opcode 0x19 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_mr16;
+ src+=CF;
+ SUBW(dst,src);
+ PutbackRMWord(ModRM,dst);
+}
+
+static void PREFIX86(_sbb_r8b)(void) /* Opcode 0x1a */
+{
+ DEF_r8b(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ src+=CF;
+ SUBB(dst,src);
+ RegByte(ModRM)=dst;
+}
+
+static void PREFIX86(_sbb_r16w)(void) /* Opcode 0x1b */
+{
+ DEF_r16w(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ src+=CF;
+ SUBW(dst,src);
+ RegWord(ModRM)= dst;
+}
+
+static void PREFIX86(_sbb_ald8)(void) /* Opcode 0x1c */
+{
+ DEF_ald8(dst,src);
+ ICOUNT -= cycles.alu_ri8;
+ src+=CF;
+ SUBB(dst,src);
+ I.regs.b[AL] = dst;
+}
+
+static void PREFIX86(_sbb_axd16)(void) /* Opcode 0x1d */
+{
+ DEF_axd16(dst,src);
+ ICOUNT -= cycles.alu_ri16;
+ src+=CF;
+ SUBW(dst,src);
+ I.regs.w[AX]=dst;
+}
+
+static void PREFIX86(_push_ds)(void) /* Opcode 0x1e */
+{
+ PUSH(I.sregs[DS]);
+ ICOUNT -= cycles.push_seg;
+}
+
+static void PREFIX86(_pop_ds)(void) /* Opcode 0x1f */
+{
+#ifdef I80286
+ UINT16 tmp;
+ POP(tmp);
+ i80286_data_descriptor(DS,tmp);
+#else
+ POP(I.sregs[DS]);
+ I.base[DS] = SegBase(DS);
+#endif
+ ICOUNT -= cycles.push_seg;
+}
+
+static void PREFIX86(_and_br8)(void) /* Opcode 0x20 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_mr8;
+ ANDB(dst,src);
+ PutbackRMByte(ModRM,dst);
+}
+
+static void PREFIX86(_and_wr16)(void) /* Opcode 0x21 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_mr16;
+ ANDW(dst,src);
+ PutbackRMWord(ModRM,dst);
+}
+
+static void PREFIX86(_and_r8b)(void) /* Opcode 0x22 */
+{
+ DEF_r8b(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ ANDB(dst,src);
+ RegByte(ModRM)=dst;
+}
+
+static void PREFIX86(_and_r16w)(void) /* Opcode 0x23 */
+{
+ DEF_r16w(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ ANDW(dst,src);
+ RegWord(ModRM)=dst;
+}
+
+static void PREFIX86(_and_ald8)(void) /* Opcode 0x24 */
+{
+ DEF_ald8(dst,src);
+ ICOUNT -= cycles.alu_ri8;
+ ANDB(dst,src);
+ I.regs.b[AL] = dst;
+}
+
+static void PREFIX86(_and_axd16)(void) /* Opcode 0x25 */
+{
+ DEF_axd16(dst,src);
+ ICOUNT -= cycles.alu_ri16;
+ ANDW(dst,src);
+ I.regs.w[AX]=dst;
+}
+
+static void PREFIX86(_es)(void) /* Opcode 0x26 */
+{
+ seg_prefix=TRUE;
+ prefix_base=I.base[ES];
+ ICOUNT -= cycles.override;
+ PREFIX(_instruction)[FETCHOP]();
+}
+
+static void PREFIX86(_daa)(void) /* Opcode 0x27 */
+{
+ if (AF || ((I.regs.b[AL] & 0xf) > 9))
+ {
+ int tmp;
+ I.regs.b[AL] = tmp = I.regs.b[AL] + 6;
+ I.AuxVal = 1;
+ I.CarryVal |= tmp & 0x100;
+ }
+
+ if (CF || (I.regs.b[AL] > 0x9f))
+ {
+ I.regs.b[AL] += 0x60;
+ I.CarryVal = 1;
+ }
+
+ SetSZPF_Byte(I.regs.b[AL]);
+ ICOUNT -= cycles.daa;
+}
+
+static void PREFIX86(_sub_br8)(void) /* Opcode 0x28 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_mr8;
+ SUBB(dst,src);
+ PutbackRMByte(ModRM,dst);
+}
+
+static void PREFIX86(_sub_wr16)(void) /* Opcode 0x29 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_mr16;
+ SUBW(dst,src);
+ PutbackRMWord(ModRM,dst);
+}
+
+static void PREFIX86(_sub_r8b)(void) /* Opcode 0x2a */
+{
+ DEF_r8b(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ SUBB(dst,src);
+ RegByte(ModRM)=dst;
+}
+
+static void PREFIX86(_sub_r16w)(void) /* Opcode 0x2b */
+{
+ DEF_r16w(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ SUBW(dst,src);
+ RegWord(ModRM)=dst;
+}
+
+static void PREFIX86(_sub_ald8)(void) /* Opcode 0x2c */
+{
+ DEF_ald8(dst,src);
+ ICOUNT -= cycles.alu_ri8;
+ SUBB(dst,src);
+ I.regs.b[AL] = dst;
+}
+
+static void PREFIX86(_sub_axd16)(void) /* Opcode 0x2d */
+{
+ DEF_axd16(dst,src);
+ ICOUNT -= cycles.alu_ri16;
+ SUBW(dst,src);
+ I.regs.w[AX]=dst;
+}
+
+static void PREFIX86(_cs)(void) /* Opcode 0x2e */
+{
+ seg_prefix=TRUE;
+ prefix_base=I.base[CS];
+ ICOUNT -= cycles.override;
+ PREFIX(_instruction)[FETCHOP]();
+}
+
+static void PREFIX86(_das)(void) /* Opcode 0x2f */
+{
+ UINT8 tmpAL=I.regs.b[AL];
+ if (AF || ((I.regs.b[AL] & 0xf) > 9))
+ {
+ int tmp;
+ I.regs.b[AL] = tmp = I.regs.b[AL] - 6;
+ I.AuxVal = 1;
+ I.CarryVal |= tmp & 0x100;
+ }
+
+ if (CF || (tmpAL > 0x9f))
+ {
+ I.regs.b[AL] -= 0x60;
+ I.CarryVal = 1;
+ }
+
+ SetSZPF_Byte(I.regs.b[AL]);
+ ICOUNT -= cycles.das;
+}
+
+static void PREFIX86(_xor_br8)(void) /* Opcode 0x30 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_mr8;
+ XORB(dst,src);
+ PutbackRMByte(ModRM,dst);
+}
+
+static void PREFIX86(_xor_wr16)(void) /* Opcode 0x31 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_mr16;
+ XORW(dst,src);
+ PutbackRMWord(ModRM,dst);
+}
+
+static void PREFIX86(_xor_r8b)(void) /* Opcode 0x32 */
+{
+ DEF_r8b(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ XORB(dst,src);
+ RegByte(ModRM)=dst;
+}
+
+static void PREFIX86(_xor_r16w)(void) /* Opcode 0x33 */
+{
+ DEF_r16w(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ XORW(dst,src);
+ RegWord(ModRM)=dst;
+}
+
+static void PREFIX86(_xor_ald8)(void) /* Opcode 0x34 */
+{
+ DEF_ald8(dst,src);
+ ICOUNT -= cycles.alu_ri8;
+ XORB(dst,src);
+ I.regs.b[AL] = dst;
+}
+
+static void PREFIX86(_xor_axd16)(void) /* Opcode 0x35 */
+{
+ DEF_axd16(dst,src);
+ ICOUNT -= cycles.alu_ri16;
+ XORW(dst,src);
+ I.regs.w[AX]=dst;
+}
+
+static void PREFIX86(_ss)(void) /* Opcode 0x36 */
+{
+ seg_prefix=TRUE;
+ prefix_base=I.base[SS];
+ ICOUNT -= cycles.override;
+ PREFIX(_instruction)[FETCHOP]();
+}
+
+static void PREFIX86(_aaa)(void) /* Opcode 0x37 */
+{
+ UINT8 ALcarry=1;
+ if (I.regs.b[AL]>0xf9) ALcarry=2;
+
+ if (AF || ((I.regs.b[AL] & 0xf) > 9))
+ {
+ I.regs.b[AL] += 6;
+ I.regs.b[AH] += ALcarry;
+ I.AuxVal = 1;
+ I.CarryVal = 1;
+ }
+ else
+ {
+ I.AuxVal = 0;
+ I.CarryVal = 0;
+ }
+ I.regs.b[AL] &= 0x0F;
+ ICOUNT -= cycles.aaa;
+}
+
+static void PREFIX86(_cmp_br8)(void) /* Opcode 0x38 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ SUBB(dst,src);
+}
+
+static void PREFIX86(_cmp_wr16)(void) /* Opcode 0x39 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ SUBW(dst,src);
+}
+
+static void PREFIX86(_cmp_r8b)(void) /* Opcode 0x3a */
+{
+ DEF_r8b(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ SUBB(dst,src);
+}
+
+static void PREFIX86(_cmp_r16w)(void) /* Opcode 0x3b */
+{
+ DEF_r16w(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ SUBW(dst,src);
+}
+
+static void PREFIX86(_cmp_ald8)(void) /* Opcode 0x3c */
+{
+ DEF_ald8(dst,src);
+ ICOUNT -= cycles.alu_ri8;
+ SUBB(dst,src);
+}
+
+static void PREFIX86(_cmp_axd16)(void) /* Opcode 0x3d */
+{
+ DEF_axd16(dst,src);
+ ICOUNT -= cycles.alu_ri16;
+ SUBW(dst,src);
+}
+
+static void PREFIX86(_ds)(void) /* Opcode 0x3e */
+{
+ seg_prefix=TRUE;
+ prefix_base=I.base[DS];
+ ICOUNT -= cycles.override;
+ PREFIX(_instruction)[FETCHOP]();
+}
+
+static void PREFIX86(_aas)(void) /* Opcode 0x3f */
+{
+ UINT8 ALcarry=1;
+ if (I.regs.b[AL]>0xf9) ALcarry=2;
+
+ if (AF || ((I.regs.b[AL] & 0xf) > 9))
+ {
+ I.regs.b[AL] -= 6;
+ I.regs.b[AH] -= 1;
+ I.AuxVal = 1;
+ I.CarryVal = 1;
+ }
+ else
+ {
+ I.AuxVal = 0;
+ I.CarryVal = 0;
+ }
+ I.regs.b[AL] &= 0x0F;
+ ICOUNT -= cycles.aas;
+}
+
+#define IncWordReg(Reg) \
+{ \
+ unsigned tmp = (unsigned)I.regs.w[Reg]; \
+ unsigned tmp1 = tmp+1; \
+ SetOFW_Add(tmp1,tmp,1); \
+ SetAF(tmp1,tmp,1); \
+ SetSZPF_Word(tmp1); \
+ I.regs.w[Reg]=tmp1; \
+ ICOUNT -= cycles.incdec_r16; \
+}
+
+static void PREFIX86(_inc_ax)(void) /* Opcode 0x40 */
+{
+ IncWordReg(AX);
+}
+
+static void PREFIX86(_inc_cx)(void) /* Opcode 0x41 */
+{
+ IncWordReg(CX);
+}
+
+static void PREFIX86(_inc_dx)(void) /* Opcode 0x42 */
+{
+ IncWordReg(DX);
+}
+
+static void PREFIX(_inc_bx)(void) /* Opcode 0x43 */
+{
+ IncWordReg(BX);
+}
+
+static void PREFIX86(_inc_sp)(void) /* Opcode 0x44 */
+{
+ IncWordReg(SP);
+}
+
+static void PREFIX86(_inc_bp)(void) /* Opcode 0x45 */
+{
+ IncWordReg(BP);
+}
+
+static void PREFIX86(_inc_si)(void) /* Opcode 0x46 */
+{
+ IncWordReg(SI);
+}
+
+static void PREFIX86(_inc_di)(void) /* Opcode 0x47 */
+{
+ IncWordReg(DI);
+}
+
+#define DecWordReg(Reg) \
+{ \
+ unsigned tmp = (unsigned)I.regs.w[Reg]; \
+ unsigned tmp1 = tmp-1; \
+ SetOFW_Sub(tmp1,1,tmp); \
+ SetAF(tmp1,tmp,1); \
+ SetSZPF_Word(tmp1); \
+ I.regs.w[Reg]=tmp1; \
+ ICOUNT -= cycles.incdec_r16; \
+}
+
+static void PREFIX86(_dec_ax)(void) /* Opcode 0x48 */
+{
+ DecWordReg(AX);
+}
+
+static void PREFIX86(_dec_cx)(void) /* Opcode 0x49 */
+{
+ DecWordReg(CX);
+}
+
+static void PREFIX86(_dec_dx)(void) /* Opcode 0x4a */
+{
+ DecWordReg(DX);
+}
+
+static void PREFIX86(_dec_bx)(void) /* Opcode 0x4b */
+{
+ DecWordReg(BX);
+}
+
+static void PREFIX86(_dec_sp)(void) /* Opcode 0x4c */
+{
+ DecWordReg(SP);
+}
+
+static void PREFIX86(_dec_bp)(void) /* Opcode 0x4d */
+{
+ DecWordReg(BP);
+}
+
+static void PREFIX86(_dec_si)(void) /* Opcode 0x4e */
+{
+ DecWordReg(SI);
+}
+
+static void PREFIX86(_dec_di)(void) /* Opcode 0x4f */
+{
+ DecWordReg(DI);
+}
+
+static void PREFIX86(_push_ax)(void) /* Opcode 0x50 */
+{
+ ICOUNT -= cycles.push_r16;
+ PUSH(I.regs.w[AX]);
+}
+
+static void PREFIX86(_push_cx)(void) /* Opcode 0x51 */
+{
+ ICOUNT -= cycles.push_r16;
+ PUSH(I.regs.w[CX]);
+}
+
+static void PREFIX86(_push_dx)(void) /* Opcode 0x52 */
+{
+ ICOUNT -= cycles.push_r16;
+ PUSH(I.regs.w[DX]);
+}
+
+static void PREFIX86(_push_bx)(void) /* Opcode 0x53 */
+{
+ ICOUNT -= cycles.push_r16;
+ PUSH(I.regs.w[BX]);
+}
+
+static void PREFIX86(_push_sp)(void) /* Opcode 0x54 */
+{
+ ICOUNT -= cycles.push_r16;
+ PUSH(I.regs.w[SP]);
+}
+
+static void PREFIX86(_push_bp)(void) /* Opcode 0x55 */
+{
+ ICOUNT -= cycles.push_r16;
+ PUSH(I.regs.w[BP]);
+}
+
+
+static void PREFIX86(_push_si)(void) /* Opcode 0x56 */
+{
+ ICOUNT -= cycles.push_r16;
+ PUSH(I.regs.w[SI]);
+}
+
+static void PREFIX86(_push_di)(void) /* Opcode 0x57 */
+{
+ ICOUNT -= cycles.push_r16;
+ PUSH(I.regs.w[DI]);
+}
+
+static void PREFIX86(_pop_ax)(void) /* Opcode 0x58 */
+{
+ ICOUNT -= cycles.pop_r16;
+ POP(I.regs.w[AX]);
+}
+
+static void PREFIX86(_pop_cx)(void) /* Opcode 0x59 */
+{
+ ICOUNT -= cycles.pop_r16;
+ POP(I.regs.w[CX]);
+}
+
+static void PREFIX86(_pop_dx)(void) /* Opcode 0x5a */
+{
+ ICOUNT -= cycles.pop_r16;
+ POP(I.regs.w[DX]);
+}
+
+static void PREFIX86(_pop_bx)(void) /* Opcode 0x5b */
+{
+ ICOUNT -= cycles.pop_r16;
+ POP(I.regs.w[BX]);
+}
+
+static void PREFIX86(_pop_sp)(void) /* Opcode 0x5c */
+{
+ ICOUNT -= cycles.pop_r16;
+ POP(I.regs.w[SP]);
+}
+
+static void PREFIX86(_pop_bp)(void) /* Opcode 0x5d */
+{
+ ICOUNT -= cycles.pop_r16;
+ POP(I.regs.w[BP]);
+}
+
+static void PREFIX86(_pop_si)(void) /* Opcode 0x5e */
+{
+ ICOUNT -= cycles.pop_r16;
+ POP(I.regs.w[SI]);
+}
+
+static void PREFIX86(_pop_di)(void) /* Opcode 0x5f */
+{
+ ICOUNT -= cycles.pop_r16;
+ POP(I.regs.w[DI]);
+}
+
+static void PREFIX86(_jo)(void) /* Opcode 0x70 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (OF)
+ {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jno)(void) /* Opcode 0x71 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (!OF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jb)(void) /* Opcode 0x72 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (CF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jnb)(void) /* Opcode 0x73 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (!CF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jz)(void) /* Opcode 0x74 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (ZF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jnz)(void) /* Opcode 0x75 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (!ZF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jbe)(void) /* Opcode 0x76 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (CF || ZF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jnbe)(void) /* Opcode 0x77 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (!(CF || ZF)) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_js)(void) /* Opcode 0x78 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (SF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jns)(void) /* Opcode 0x79 */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (!SF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jp)(void) /* Opcode 0x7a */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (PF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jnp)(void) /* Opcode 0x7b */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (!PF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jl)(void) /* Opcode 0x7c */
+{
+ int tmp = (int)((INT8)FETCH);
+ if ((SF!=OF)&&!ZF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jnl)(void) /* Opcode 0x7d */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (ZF||(SF==OF)) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jle)(void) /* Opcode 0x7e */
+{
+ int tmp = (int)((INT8)FETCH);
+ if (ZF||(SF!=OF)) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_jnle)(void) /* Opcode 0x7f */
+{
+ int tmp = (int)((INT8)FETCH);
+ if ((SF==OF)&&!ZF) {
+ I.pc += tmp;
+ ICOUNT -= cycles.jcc_t;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.jcc_nt;
+}
+
+static void PREFIX86(_80pre)(void) /* Opcode 0x80 */
+{
+ unsigned ModRM = FETCHOP;
+ unsigned dst = GetRMByte(ModRM);
+ unsigned src = FETCH;
+
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* ADD eb,d8 */
+ ADDB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x08: /* OR eb,d8 */
+ ORB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x10: /* ADC eb,d8 */
+ src+=CF;
+ ADDB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x18: /* SBB eb,b8 */
+ src+=CF;
+ SUBB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x20: /* AND eb,d8 */
+ ANDB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x28: /* SUB eb,d8 */
+ SUBB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x30: /* XOR eb,d8 */
+ XORB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x38: /* CMP eb,d8 */
+ SUBB(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8_ro;
+ break;
+ }
+}
+
+
+static void PREFIX86(_81pre)(void) /* Opcode 0x81 */
+{
+ unsigned ModRM = FETCH;
+ unsigned dst = GetRMWord(ModRM);
+ unsigned src = FETCH;
+ src+= (FETCH << 8);
+
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* ADD ew,d16 */
+ ADDW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri16 : cycles.alu_mi16;
+ break;
+ case 0x08: /* OR ew,d16 */
+ ORW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri16 : cycles.alu_mi16;
+ break;
+ case 0x10: /* ADC ew,d16 */
+ src+=CF;
+ ADDW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri16 : cycles.alu_mi16;
+ break;
+ case 0x18: /* SBB ew,d16 */
+ src+=CF;
+ SUBW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri16 : cycles.alu_mi16;
+ break;
+ case 0x20: /* AND ew,d16 */
+ ANDW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri16 : cycles.alu_mi16;
+ break;
+ case 0x28: /* SUB ew,d16 */
+ SUBW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri16 : cycles.alu_mi16;
+ break;
+ case 0x30: /* XOR ew,d16 */
+ XORW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri16 : cycles.alu_mi16;
+ break;
+ case 0x38: /* CMP ew,d16 */
+ SUBW(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri16 : cycles.alu_mi16_ro;
+ break;
+ }
+}
+
+static void PREFIX86(_82pre)(void) /* Opcode 0x82 */
+{
+ unsigned ModRM = FETCH;
+ unsigned dst = GetRMByte(ModRM);
+ unsigned src = FETCH;
+
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* ADD eb,d8 */
+ ADDB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x08: /* OR eb,d8 */
+ ORB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x10: /* ADC eb,d8 */
+ src+=CF;
+ ADDB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x18: /* SBB eb,d8 */
+ src+=CF;
+ SUBB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x20: /* AND eb,d8 */
+ ANDB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x28: /* SUB eb,d8 */
+ SUBB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x30: /* XOR eb,d8 */
+ XORB(dst,src);
+ PutbackRMByte(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8;
+ break;
+ case 0x38: /* CMP eb,d8 */
+ SUBB(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8_ro;
+ break;
+ }
+}
+
+static void PREFIX86(_83pre)(void) /* Opcode 0x83 */
+{
+ unsigned ModRM = FETCH;
+ unsigned dst = GetRMWord(ModRM);
+ unsigned src = (WORD)((INT16)((INT8)FETCH));
+
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* ADD ew,d16 */
+ ADDW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_r16i8 : cycles.alu_m16i8;
+ break;
+ case 0x08: /* OR ew,d16 */
+ ORW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_r16i8 : cycles.alu_m16i8;
+ break;
+ case 0x10: /* ADC ew,d16 */
+ src+=CF;
+ ADDW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_r16i8 : cycles.alu_m16i8;
+ break;
+ case 0x18: /* SBB ew,d16 */
+ src+=CF;
+ SUBW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_r16i8 : cycles.alu_m16i8;
+ break;
+ case 0x20: /* AND ew,d16 */
+ ANDW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_r16i8 : cycles.alu_m16i8;
+ break;
+ case 0x28: /* SUB ew,d16 */
+ SUBW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_r16i8 : cycles.alu_m16i8;
+ break;
+ case 0x30: /* XOR ew,d16 */
+ XORW(dst,src);
+ PutbackRMWord(ModRM,dst);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_r16i8 : cycles.alu_m16i8;
+ break;
+ case 0x38: /* CMP ew,d16 */
+ SUBW(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_r16i8 : cycles.alu_m16i8_ro;
+ break;
+ }
+}
+
+static void PREFIX86(_test_br8)(void) /* Opcode 0x84 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr8 : cycles.alu_rm8;
+ ANDB(dst,src);
+}
+
+static void PREFIX86(_test_wr16)(void) /* Opcode 0x85 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_rr16 : cycles.alu_rm16;
+ ANDW(dst,src);
+}
+
+static void PREFIX86(_xchg_br8)(void) /* Opcode 0x86 */
+{
+ DEF_br8(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.xchg_rr8 : cycles.xchg_rm8;
+ RegByte(ModRM)=dst;
+ PutbackRMByte(ModRM,src);
+}
+
+static void PREFIX86(_xchg_wr16)(void) /* Opcode 0x87 */
+{
+ DEF_wr16(dst,src);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.xchg_rr16 : cycles.xchg_rm16;
+ RegWord(ModRM)=dst;
+ PutbackRMWord(ModRM,src);
+}
+
+static void PREFIX86(_mov_br8)(void) /* Opcode 0x88 */
+{
+ unsigned ModRM = FETCH;
+ BYTE src = RegByte(ModRM);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mov_rr8 : cycles.mov_mr8;
+ PutRMByte(ModRM,src);
+}
+
+static void PREFIX86(_mov_wr16)(void) /* Opcode 0x89 */
+{
+ unsigned ModRM = FETCH;
+ WORD src = RegWord(ModRM);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mov_rr16 : cycles.mov_mr16;
+ PutRMWord(ModRM,src);
+}
+
+static void PREFIX86(_mov_r8b)(void) /* Opcode 0x8a */
+{
+ unsigned ModRM = FETCH;
+ BYTE src = GetRMByte(ModRM);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mov_rr8 : cycles.mov_rm8;
+ RegByte(ModRM)=src;
+}
+
+static void PREFIX86(_mov_r16w)(void) /* Opcode 0x8b */
+{
+ unsigned ModRM = FETCH;
+ WORD src = GetRMWord(ModRM);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mov_rr8 : cycles.mov_rm16;
+ RegWord(ModRM)=src;
+}
+
+static void PREFIX86(_mov_wsreg)(void) /* Opcode 0x8c */
+{
+ unsigned ModRM = FETCH;
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mov_rs : cycles.mov_ms;
+#ifdef I80286
+ if (ModRM & 0x20) { /* HJB 12/13/98 1xx is invalid */
+ i80286_trap2(ILLEGAL_INSTRUCTION);
+ return;
+ }
+#else
+ if (ModRM & 0x20) return; /* HJB 12/13/98 1xx is invalid */
+#endif
+ PutRMWord(ModRM,I.sregs[(ModRM & 0x38) >> 3]);
+}
+
+static void PREFIX86(_lea)(void) /* Opcode 0x8d */
+{
+ unsigned ModRM = FETCH;
+ ICOUNT -= cycles.lea;
+ (void)(*GetEA[ModRM])();
+ RegWord(ModRM)=EO; /* HJB 12/13/98 effective offset (no segment part) */
+}
+
+static void PREFIX86(_mov_sregw)(void) /* Opcode 0x8e */
+{
+ unsigned ModRM = FETCH;
+ WORD src = GetRMWord(ModRM);
+
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mov_sr : cycles.mov_sm;
+#ifdef I80286
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* mov es,ew */
+ i80286_data_descriptor(ES,src);
+ break;
+ case 0x18: /* mov ds,ew */
+ i80286_data_descriptor(DS,src);
+ break;
+ case 0x10: /* mov ss,ew */
+ i80286_data_descriptor(SS,src);
+ PREFIX(_instruction)[FETCHOP]();
+ break;
+ case 0x08: /* mov cs,ew */
+ break; /* doesn't do a jump far */
+ }
+#else
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* mov es,ew */
+ I.sregs[ES] = src;
+ I.base[ES] = SegBase(ES);
+ break;
+ case 0x18: /* mov ds,ew */
+ I.sregs[DS] = src;
+ I.base[DS] = SegBase(DS);
+ break;
+ case 0x10: /* mov ss,ew */
+ I.sregs[SS] = src;
+ I.base[SS] = SegBase(SS); /* no interrupt allowed before next instr */
+ PREFIX(_instruction)[FETCHOP]();
+ break;
+ case 0x08: /* mov cs,ew */
+ break; /* doesn't do a jump far */
+ }
+#endif
+}
+
+static void PREFIX86(_popw)(void) /* Opcode 0x8f */
+{
+ unsigned ModRM = FETCH;
+ WORD tmp;
+ POP(tmp);
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.pop_r16 : cycles.pop_m16;
+ PutRMWord(ModRM,tmp);
+}
+
+
+#define XchgAXReg(Reg) \
+{ \
+ WORD tmp; \
+ tmp = I.regs.w[Reg]; \
+ I.regs.w[Reg] = I.regs.w[AX]; \
+ I.regs.w[AX] = tmp; \
+ ICOUNT -= cycles.xchg_ar16; \
+}
+
+
+static void PREFIX86(_nop)(void) /* Opcode 0x90 */
+{
+ /* this is XchgAXReg(AX); */
+ ICOUNT -= cycles.nop;
+}
+
+static void PREFIX86(_xchg_axcx)(void) /* Opcode 0x91 */
+{
+ XchgAXReg(CX);
+}
+
+static void PREFIX86(_xchg_axdx)(void) /* Opcode 0x92 */
+{
+ XchgAXReg(DX);
+}
+
+static void PREFIX86(_xchg_axbx)(void) /* Opcode 0x93 */
+{
+ XchgAXReg(BX);
+}
+
+static void PREFIX86(_xchg_axsp)(void) /* Opcode 0x94 */
+{
+ XchgAXReg(SP);
+}
+
+static void PREFIX86(_xchg_axbp)(void) /* Opcode 0x95 */
+{
+ XchgAXReg(BP);
+}
+
+static void PREFIX86(_xchg_axsi)(void) /* Opcode 0x96 */
+{
+ XchgAXReg(SI);
+}
+
+static void PREFIX86(_xchg_axdi)(void) /* Opcode 0x97 */
+{
+ XchgAXReg(DI);
+}
+
+static void PREFIX86(_cbw)(void) /* Opcode 0x98 */
+{
+ ICOUNT -= cycles.cbw;
+ I.regs.b[AH] = (I.regs.b[AL] & 0x80) ? 0xff : 0;
+}
+
+static void PREFIX86(_cwd)(void) /* Opcode 0x99 */
+{
+ ICOUNT -= cycles.cwd;
+ I.regs.w[DX] = (I.regs.b[AH] & 0x80) ? 0xffff : 0;
+}
+
+static void PREFIX86(_call_far)(void)
+{
+ unsigned tmp, tmp2;
+ WORD ip;
+
+ tmp = FETCH;
+ tmp += FETCH << 8;
+
+ tmp2 = FETCH;
+ tmp2 += FETCH << 8;
+
+ ip = I.pc - I.base[CS];
+ PUSH(I.sregs[CS]);
+ PUSH(ip);
+
+#ifdef I80286
+ i80286_code_descriptor(tmp2, tmp);
+#else
+ I.sregs[CS] = (WORD)tmp2;
+ I.base[CS] = SegBase(CS);
+ I.pc = (I.base[CS] + (WORD)tmp) & AMASK;
+#endif
+ ICOUNT -= cycles.call_far;
+ CHANGE_PC(I.pc);
+}
+
+static void PREFIX86(_wait)(void) /* Opcode 0x9b */
+{
+ if (I.test_state)
+ {
+ ICOUNT = 0;
+ I.pc--;
+ }
+ else
+ ICOUNT -= cycles.wait;
+}
+
+static void PREFIX86(_pushf)(void) /* Opcode 0x9c */
+{
+ unsigned tmp;
+ ICOUNT -= cycles.pushf;
+
+ tmp = CompressFlags();
+#ifdef I80286
+ PUSH( tmp &= ~0xf000 );
+#else
+ PUSH( tmp | 0xf000 );
+#endif
+}
+
+static void PREFIX86(_popf)(void) /* Opcode 0x9d */
+{
+ unsigned tmp;
+ POP(tmp);
+ ICOUNT -= cycles.popf;
+ ExpandFlags(tmp);
+
+ if (I.TF) PREFIX(_trap)();
+
+ /* if the IF is set, and an interrupt is pending, signal an interrupt */
+ if (I.IF && I.irq_state)
+ PREFIX(_interrupt)(-1);
+}
+
+static void PREFIX86(_sahf)(void) /* Opcode 0x9e */
+{
+ unsigned tmp = (CompressFlags() & 0xff00) | (I.regs.b[AH] & 0xd5);
+ ICOUNT -= cycles.sahf;
+ ExpandFlags(tmp);
+}
+
+static void PREFIX86(_lahf)(void) /* Opcode 0x9f */
+{
+ I.regs.b[AH] = CompressFlags() & 0xff;
+ ICOUNT -= cycles.lahf;
+}
+
+
+static void PREFIX86(_mov_aldisp)(void) /* Opcode 0xa0 */
+{
+ unsigned addr;
+
+ addr = FETCH;
+ addr += FETCH << 8;
+
+ ICOUNT -= cycles.mov_am8;
+ I.regs.b[AL] = GetMemB(DS, addr);
+}
+
+static void PREFIX86(_mov_axdisp)(void) /* Opcode 0xa1 */
+{
+ unsigned addr;
+
+ addr = FETCH;
+ addr += FETCH << 8;
+
+ ICOUNT -= cycles.mov_am16;
+ I.regs.w[AX] = GetMemW(DS, addr);
+}
+
+static void PREFIX86(_mov_dispal)(void) /* Opcode 0xa2 */
+{
+ unsigned addr;
+
+ addr = FETCH;
+ addr += FETCH << 8;
+
+ ICOUNT -= cycles.mov_ma8;
+ PutMemB(DS, addr, I.regs.b[AL]);
+}
+
+static void PREFIX86(_mov_dispax)(void) /* Opcode 0xa3 */
+{
+ unsigned addr;
+
+ addr = FETCH;
+ addr += FETCH << 8;
+
+ ICOUNT -= cycles.mov_ma16;
+ PutMemW(DS, addr, I.regs.w[AX]);
+}
+
+static void PREFIX86(_movsb)(void) /* Opcode 0xa4 */
+{
+ BYTE tmp = GetMemB(DS,I.regs.w[SI]);
+ PutMemB(ES,I.regs.w[DI], tmp);
+ I.regs.w[DI] += I.DirVal;
+ I.regs.w[SI] += I.DirVal;
+ ICOUNT -= cycles.movs8;
+}
+
+static void PREFIX86(_movsw)(void) /* Opcode 0xa5 */
+{
+ WORD tmp = GetMemW(DS,I.regs.w[SI]);
+ PutMemW(ES,I.regs.w[DI], tmp);
+ I.regs.w[DI] += 2 * I.DirVal;
+ I.regs.w[SI] += 2 * I.DirVal;
+ ICOUNT -= cycles.movs16;
+}
+
+static void PREFIX86(_cmpsb)(void) /* Opcode 0xa6 */
+{
+ unsigned dst = GetMemB(ES, I.regs.w[DI]);
+ unsigned src = GetMemB(DS, I.regs.w[SI]);
+ SUBB(src,dst); /* opposite of the usual convention */
+ I.regs.w[DI] += I.DirVal;
+ I.regs.w[SI] += I.DirVal;
+ ICOUNT -= cycles.cmps8;
+}
+
+static void PREFIX86(_cmpsw)(void) /* Opcode 0xa7 */
+{
+ unsigned dst = GetMemW(ES, I.regs.w[DI]);
+ unsigned src = GetMemW(DS, I.regs.w[SI]);
+ SUBW(src,dst); /* opposite of the usual convention */
+ I.regs.w[DI] += 2 * I.DirVal;
+ I.regs.w[SI] += 2 * I.DirVal;
+ ICOUNT -= cycles.cmps16;
+}
+
+static void PREFIX86(_test_ald8)(void) /* Opcode 0xa8 */
+{
+ DEF_ald8(dst,src);
+ ICOUNT -= cycles.alu_ri8;
+ ANDB(dst,src);
+}
+
+static void PREFIX86(_test_axd16)(void) /* Opcode 0xa9 */
+{
+ DEF_axd16(dst,src);
+ ICOUNT -= cycles.alu_ri16;
+ ANDW(dst,src);
+}
+
+static void PREFIX86(_stosb)(void) /* Opcode 0xaa */
+{
+ PutMemB(ES,I.regs.w[DI],I.regs.b[AL]);
+ I.regs.w[DI] += I.DirVal;
+ ICOUNT -= cycles.stos8;
+}
+
+static void PREFIX86(_stosw)(void) /* Opcode 0xab */
+{
+ PutMemW(ES,I.regs.w[DI],I.regs.w[AX]);
+ I.regs.w[DI] += 2 * I.DirVal;
+ ICOUNT -= cycles.stos16;
+}
+
+static void PREFIX86(_lodsb)(void) /* Opcode 0xac */
+{
+ I.regs.b[AL] = GetMemB(DS,I.regs.w[SI]);
+ I.regs.w[SI] += I.DirVal;
+ ICOUNT -= cycles.lods8;
+}
+
+static void PREFIX86(_lodsw)(void) /* Opcode 0xad */
+{
+ I.regs.w[AX] = GetMemW(DS,I.regs.w[SI]);
+ I.regs.w[SI] += 2 * I.DirVal;
+ ICOUNT -= cycles.lods16;
+}
+
+static void PREFIX86(_scasb)(void) /* Opcode 0xae */
+{
+ unsigned src = GetMemB(ES, I.regs.w[DI]);
+ unsigned dst = I.regs.b[AL];
+ SUBB(dst,src);
+ I.regs.w[DI] += I.DirVal;
+ ICOUNT -= cycles.scas8;
+}
+
+static void PREFIX86(_scasw)(void) /* Opcode 0xaf */
+{
+ unsigned src = GetMemW(ES, I.regs.w[DI]);
+ unsigned dst = I.regs.w[AX];
+ SUBW(dst,src);
+ I.regs.w[DI] += 2 * I.DirVal;
+ ICOUNT -= cycles.scas16;
+}
+
+static void PREFIX86(_mov_ald8)(void) /* Opcode 0xb0 */
+{
+ I.regs.b[AL] = FETCH;
+ ICOUNT -= cycles.mov_ri8;
+}
+
+static void PREFIX86(_mov_cld8)(void) /* Opcode 0xb1 */
+{
+ I.regs.b[CL] = FETCH;
+ ICOUNT -= cycles.mov_ri8;
+}
+
+static void PREFIX86(_mov_dld8)(void) /* Opcode 0xb2 */
+{
+ I.regs.b[DL] = FETCH;
+ ICOUNT -= cycles.mov_ri8;
+}
+
+static void PREFIX86(_mov_bld8)(void) /* Opcode 0xb3 */
+{
+ I.regs.b[BL] = FETCH;
+ ICOUNT -= cycles.mov_ri8;
+}
+
+static void PREFIX86(_mov_ahd8)(void) /* Opcode 0xb4 */
+{
+ I.regs.b[AH] = FETCH;
+ ICOUNT -= cycles.mov_ri8;
+}
+
+static void PREFIX86(_mov_chd8)(void) /* Opcode 0xb5 */
+{
+ I.regs.b[CH] = FETCH;
+ ICOUNT -= cycles.mov_ri8;
+}
+
+static void PREFIX86(_mov_dhd8)(void) /* Opcode 0xb6 */
+{
+ I.regs.b[DH] = FETCH;
+ ICOUNT -= cycles.mov_ri8;
+}
+
+static void PREFIX86(_mov_bhd8)(void) /* Opcode 0xb7 */
+{
+ I.regs.b[BH] = FETCH;
+ ICOUNT -= cycles.mov_ri8;
+}
+
+static void PREFIX86(_mov_axd16)(void) /* Opcode 0xb8 */
+{
+ I.regs.b[AL] = FETCH;
+ I.regs.b[AH] = FETCH;
+ ICOUNT -= cycles.mov_ri16;
+}
+
+static void PREFIX86(_mov_cxd16)(void) /* Opcode 0xb9 */
+{
+ I.regs.b[CL] = FETCH;
+ I.regs.b[CH] = FETCH;
+ ICOUNT -= cycles.mov_ri16;
+}
+
+static void PREFIX86(_mov_dxd16)(void) /* Opcode 0xba */
+{
+ I.regs.b[DL] = FETCH;
+ I.regs.b[DH] = FETCH;
+ ICOUNT -= cycles.mov_ri16;
+}
+
+static void PREFIX86(_mov_bxd16)(void) /* Opcode 0xbb */
+{
+ I.regs.b[BL] = FETCH;
+ I.regs.b[BH] = FETCH;
+ ICOUNT -= cycles.mov_ri16;
+}
+
+static void PREFIX86(_mov_spd16)(void) /* Opcode 0xbc */
+{
+ I.regs.b[SPL] = FETCH;
+ I.regs.b[SPH] = FETCH;
+ ICOUNT -= cycles.mov_ri16;
+}
+
+static void PREFIX86(_mov_bpd16)(void) /* Opcode 0xbd */
+{
+ I.regs.b[BPL] = FETCH;
+ I.regs.b[BPH] = FETCH;
+ ICOUNT -= cycles.mov_ri16;
+}
+
+static void PREFIX86(_mov_sid16)(void) /* Opcode 0xbe */
+{
+ I.regs.b[SIL] = FETCH;
+ I.regs.b[SIH] = FETCH;
+ ICOUNT -= cycles.mov_ri16;
+}
+
+static void PREFIX86(_mov_did16)(void) /* Opcode 0xbf */
+{
+ I.regs.b[DIL] = FETCH;
+ I.regs.b[DIH] = FETCH;
+ ICOUNT -= cycles.mov_ri16;
+}
+
+static void PREFIX86(_ret_d16)(void) /* Opcode 0xc2 */
+{
+ unsigned count = FETCH;
+ count += FETCH << 8;
+ POP(I.pc);
+ I.pc = (I.pc + I.base[CS]) & AMASK;
+ I.regs.w[SP]+=count;
+ ICOUNT -= cycles.ret_near_imm;
+ CHANGE_PC(I.pc);
+}
+
+static void PREFIX86(_ret)(void) /* Opcode 0xc3 */
+{
+ POP(I.pc);
+ I.pc = (I.pc + I.base[CS]) & AMASK;
+ ICOUNT -= cycles.ret_near;
+ CHANGE_PC(I.pc);
+}
+
+static void PREFIX86(_les_dw)(void) /* Opcode 0xc4 */
+{
+ unsigned ModRM = FETCH;
+ WORD tmp = GetRMWord(ModRM);
+
+ RegWord(ModRM)= tmp;
+#ifdef I80286
+ i80286_data_descriptor(ES,GetnextRMWord);
+#else
+ I.sregs[ES] = GetnextRMWord;
+ I.base[ES] = SegBase(ES);
+#endif
+ ICOUNT -= cycles.load_ptr;
+}
+
+static void PREFIX86(_lds_dw)(void) /* Opcode 0xc5 */
+{
+ unsigned ModRM = FETCH;
+ WORD tmp = GetRMWord(ModRM);
+
+ RegWord(ModRM)=tmp;
+#ifdef I80286
+ i80286_data_descriptor(DS,GetnextRMWord);
+#else
+ I.sregs[DS] = GetnextRMWord;
+ I.base[DS] = SegBase(DS);
+#endif
+ ICOUNT -= cycles.load_ptr;
+}
+
+static void PREFIX86(_mov_bd8)(void) /* Opcode 0xc6 */
+{
+ unsigned ModRM = FETCH;
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mov_ri8 : cycles.mov_mi8;
+ PutImmRMByte(ModRM);
+}
+
+static void PREFIX86(_mov_wd16)(void) /* Opcode 0xc7 */
+{
+ unsigned ModRM = FETCH;
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mov_ri16 : cycles.mov_mi16;
+ PutImmRMWord(ModRM);
+}
+
+static void PREFIX86(_retf_d16)(void) /* Opcode 0xca */
+{
+ unsigned count = FETCH;
+ count += FETCH << 8;
+
+#ifdef I80286
+ {
+ int tmp, tmp2;
+ POP(tmp2);
+ POP(tmp);
+ i80286_code_descriptor(tmp, tmp2);
+ }
+#else
+ POP(I.pc);
+ POP(I.sregs[CS]);
+ I.base[CS] = SegBase(CS);
+ I.pc = (I.pc + I.base[CS]) & AMASK;
+#endif
+ I.regs.w[SP]+=count;
+ ICOUNT -= cycles.ret_far_imm;
+ CHANGE_PC(I.pc);
+}
+
+static void PREFIX86(_retf)(void) /* Opcode 0xcb */
+{
+#ifdef I80286
+ {
+ int tmp, tmp2;
+ POP(tmp2);
+ POP(tmp);
+ i80286_code_descriptor(tmp, tmp2);
+ }
+#else
+ POP(I.pc);
+ POP(I.sregs[CS]);
+ I.base[CS] = SegBase(CS);
+ I.pc = (I.pc + I.base[CS]) & AMASK;
+#endif
+ ICOUNT -= cycles.ret_far;
+ CHANGE_PC(I.pc);
+}
+
+static void PREFIX86(_int3)(void) /* Opcode 0xcc */
+{
+ ICOUNT -= cycles.int3;
+ PREFIX(_interrupt)(3);
+}
+
+static void PREFIX86(_int)(void) /* Opcode 0xcd */
+{
+ unsigned int_num = FETCH;
+ ICOUNT -= cycles.int_imm;
+ PREFIX(_interrupt)(int_num);
+}
+
+static void PREFIX86(_into)(void) /* Opcode 0xce */
+{
+ if (OF) {
+ ICOUNT -= cycles.into_t;
+ PREFIX(_interrupt)(4);
+ } else ICOUNT -= cycles.into_nt;
+}
+
+static void PREFIX86(_iret)(void) /* Opcode 0xcf */
+{
+ ICOUNT -= cycles.iret;
+#ifdef I80286
+ {
+ int tmp, tmp2;
+ POP(tmp2);
+ POP(tmp);
+ i80286_code_descriptor(tmp, tmp2);
+ }
+#else
+ POP(I.pc);
+ POP(I.sregs[CS]);
+ I.base[CS] = SegBase(CS);
+ I.pc = (I.pc + I.base[CS]) & AMASK;
+#endif
+ PREFIX(_popf)();
+ CHANGE_PC(I.pc);
+
+ /* if the IF is set, and an interrupt is pending, signal an interrupt */
+ if (I.IF && I.irq_state)
+ PREFIX(_interrupt)(-1);
+}
+
+static void PREFIX86(_rotshft_b)(void) /* Opcode 0xd0 */
+{
+ PREFIX(_rotate_shift_Byte)(FETCHOP,1);
+}
+
+
+static void PREFIX86(_rotshft_w)(void) /* Opcode 0xd1 */
+{
+ PREFIX(_rotate_shift_Word)(FETCHOP,1);
+}
+
+
+static void PREFIX86(_rotshft_bcl)(void) /* Opcode 0xd2 */
+{
+ PREFIX(_rotate_shift_Byte)(FETCHOP,I.regs.b[CL]);
+}
+
+static void PREFIX86(_rotshft_wcl)(void) /* Opcode 0xd3 */
+{
+ PREFIX(_rotate_shift_Word)(FETCHOP,I.regs.b[CL]);
+}
+
+/* OB: Opcode works on NEC V-Series but not the Variants */
+/* one could specify any byte value as operand but the NECs */
+/* always substitute 0x0a. */
+static void PREFIX86(_aam)(void) /* Opcode 0xd4 */
+{
+ unsigned mult = FETCH;
+
+ ICOUNT -= cycles.aam;
+ if (mult == 0)
+ PREFIX(_interrupt)(0);
+ else
+ {
+ I.regs.b[AH] = I.regs.b[AL] / mult;
+ I.regs.b[AL] %= mult;
+
+ SetSZPF_Word(I.regs.w[AX]);
+ }
+}
+
+static void PREFIX86(_aad)(void) /* Opcode 0xd5 */
+{
+ unsigned mult = FETCH;
+
+ ICOUNT -= cycles.aad;
+
+ I.regs.b[AL] = I.regs.b[AH] * mult + I.regs.b[AL];
+ I.regs.b[AH] = 0;
+
+ SetZF(I.regs.b[AL]);
+ SetPF(I.regs.b[AL]);
+ I.SignVal = 0;
+}
+
+
+static void PREFIX86(_xlat)(void) /* Opcode 0xd7 */
+{
+ unsigned dest = I.regs.w[BX]+I.regs.b[AL];
+
+ ICOUNT -= cycles.xlat;
+ I.regs.b[AL] = GetMemB(DS, dest);
+}
+
+static void PREFIX86(_escape)(void) /* Opcodes 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde and 0xdf */
+{
+ unsigned ModRM = FETCH;
+ ICOUNT -= cycles.nop;
+ GetRMByte(ModRM);
+}
+
+static void PREFIX86(_loopne)(void) /* Opcode 0xe0 */
+{
+ int disp = (int)((INT8)FETCH);
+ unsigned tmp = I.regs.w[CX]-1;
+
+ I.regs.w[CX]=tmp;
+
+ if (!ZF && tmp) {
+ ICOUNT -= cycles.loop_t;
+ I.pc += disp;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.loop_nt;
+}
+
+static void PREFIX86(_loope)(void) /* Opcode 0xe1 */
+{
+ int disp = (int)((INT8)FETCH);
+ unsigned tmp = I.regs.w[CX]-1;
+
+ I.regs.w[CX]=tmp;
+
+ if (ZF && tmp) {
+ ICOUNT -= cycles.loope_t;
+ I.pc += disp;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.loope_nt;
+}
+
+static void PREFIX86(_loop)(void) /* Opcode 0xe2 */
+{
+ int disp = (int)((INT8)FETCH);
+ unsigned tmp = I.regs.w[CX]-1;
+
+ I.regs.w[CX]=tmp;
+
+ if (tmp) {
+ ICOUNT -= cycles.loop_t;
+ I.pc += disp;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else ICOUNT -= cycles.loop_nt;
+}
+
+static void PREFIX86(_jcxz)(void) /* Opcode 0xe3 */
+{
+ int disp = (int)((INT8)FETCH);
+
+ if (I.regs.w[CX] == 0) {
+ ICOUNT -= cycles.jcxz_t;
+ I.pc += disp;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ } else
+ ICOUNT -= cycles.jcxz_nt;
+}
+
+static void PREFIX86(_inal)(void) /* Opcode 0xe4 */
+{
+ unsigned port = FETCH;
+
+ ICOUNT -= cycles.in_imm8;
+ I.regs.b[AL] = read_port_byte(port);
+}
+
+static void PREFIX86(_inax)(void) /* Opcode 0xe5 */
+{
+ unsigned port = FETCH;
+
+ ICOUNT -= cycles.in_imm16;
+ I.regs.w[AX] = read_port_word(port);
+}
+
+static void PREFIX86(_outal)(void) /* Opcode 0xe6 */
+{
+ unsigned port = FETCH;
+
+ ICOUNT -= cycles.out_imm8;
+ write_port_byte(port, I.regs.b[AL]);
+}
+
+static void PREFIX86(_outax)(void) /* Opcode 0xe7 */
+{
+ unsigned port = FETCH;
+
+ ICOUNT -= cycles.out_imm16;
+ write_port_word(port, I.regs.w[AX]);
+}
+
+static void PREFIX86(_call_d16)(void) /* Opcode 0xe8 */
+{
+ WORD ip, tmp;
+
+ FETCHWORD(tmp);
+ ip = I.pc - I.base[CS];
+ PUSH(ip);
+ ip += tmp;
+ I.pc = (ip + I.base[CS]) & AMASK;
+ ICOUNT -= cycles.call_near;
+ CHANGE_PC(I.pc);
+}
+
+static void PREFIX86(_jmp_d16)(void) /* Opcode 0xe9 */
+{
+ WORD ip, tmp;
+
+ FETCHWORD(tmp);
+ ip = I.pc - I.base[CS] + tmp;
+ I.pc = (ip + I.base[CS]) & AMASK;
+ ICOUNT -= cycles.jmp_near;
+ CHANGE_PC(I.pc);
+}
+
+static void PREFIX86(_jmp_far)(void) /* Opcode 0xea */
+{
+ unsigned tmp,tmp1;
+
+ tmp = FETCH;
+ tmp += FETCH << 8;
+
+ tmp1 = FETCH;
+ tmp1 += FETCH << 8;
+
+#ifdef I80286
+ i80286_code_descriptor(tmp1,tmp);
+#else
+ I.sregs[CS] = (WORD)tmp1;
+ I.base[CS] = SegBase(CS);
+ I.pc = (I.base[CS] + tmp) & AMASK;
+#endif
+ ICOUNT -= cycles.jmp_far;
+ CHANGE_PC(I.pc);
+}
+
+static void PREFIX86(_jmp_d8)(void) /* Opcode 0xeb */
+{
+ int tmp = (int)((INT8)FETCH);
+ I.pc += tmp;
+/* ASG - can probably assume this is safe
+ CHANGE_PC(I.pc);*/
+ ICOUNT -= cycles.jmp_short;
+}
+
+static void PREFIX86(_inaldx)(void) /* Opcode 0xec */
+{
+ ICOUNT -= cycles.in_dx8;
+ I.regs.b[AL] = read_port_byte(I.regs.w[DX]);
+}
+
+static void PREFIX86(_inaxdx)(void) /* Opcode 0xed */
+{
+ unsigned port = I.regs.w[DX];
+
+ ICOUNT -= cycles.in_dx16;
+ I.regs.w[AX] = read_port_word(port);
+}
+
+static void PREFIX86(_outdxal)(void) /* Opcode 0xee */
+{
+ ICOUNT -= cycles.out_dx8;
+ write_port_byte(I.regs.w[DX], I.regs.b[AL]);
+}
+
+static void PREFIX86(_outdxax)(void) /* Opcode 0xef */
+{
+ unsigned port = I.regs.w[DX];
+
+ ICOUNT -= cycles.out_dx16;
+ write_port_word(port, I.regs.w[AX]);
+}
+
+/* I think thats not a V20 instruction...*/
+static void PREFIX86(_lock)(void) /* Opcode 0xf0 */
+{
+ ICOUNT -= cycles.nop;
+ PREFIX(_instruction)[FETCHOP](); /* un-interruptible */
+}
+#endif
+
+static void PREFIX(_repne)(void) /* Opcode 0xf2 */
+{
+ PREFIX(rep)(0);
+}
+
+static void PREFIX(_repe)(void) /* Opcode 0xf3 */
+{
+ PREFIX(rep)(1);
+}
+
+#ifndef I80186
+static void PREFIX86(_hlt)(void) /* Opcode 0xf4 */
+{
+ I.pc--;
+ ICOUNT = 0;
+}
+
+static void PREFIX86(_cmc)(void) /* Opcode 0xf5 */
+{
+ ICOUNT -= cycles.flag_ops;
+ I.CarryVal = !CF;
+}
+
+static void PREFIX86(_f6pre)(void)
+{
+ /* Opcode 0xf6 */
+ unsigned ModRM = FETCH;
+ unsigned tmp = (unsigned)GetRMByte(ModRM);
+ unsigned tmp2;
+
+
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* TEST Eb, data8 */
+ case 0x08: /* ??? */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri8 : cycles.alu_mi8_ro;
+ tmp &= FETCH;
+
+ I.CarryVal = I.OverVal = I.AuxVal = 0;
+ SetSZPF_Byte(tmp);
+ break;
+
+ case 0x10: /* NOT Eb */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.negnot_r8 : cycles.negnot_m8;
+ PutbackRMByte(ModRM,~tmp);
+ break;
+
+ case 0x18: /* NEG Eb */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.negnot_r8 : cycles.negnot_m8;
+ tmp2=0;
+ SUBB(tmp2,tmp);
+ PutbackRMByte(ModRM,tmp2);
+ break;
+ case 0x20: /* MUL AL, Eb */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mul_r8 : cycles.mul_m8;
+ {
+ UINT16 result;
+ tmp2 = I.regs.b[AL];
+
+ SetSF((INT8)tmp2);
+ SetPF(tmp2);
+
+ result = (UINT16)tmp2*tmp;
+ I.regs.w[AX]=(WORD)result;
+
+ SetZF(I.regs.w[AX]);
+ I.CarryVal = I.OverVal = (I.regs.b[AH] != 0);
+ }
+ break;
+ case 0x28: /* IMUL AL, Eb */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.imul_r8 : cycles.imul_m8;
+ {
+ INT16 result;
+
+ tmp2 = (unsigned)I.regs.b[AL];
+
+ SetSF((INT8)tmp2);
+ SetPF(tmp2);
+
+ result = (INT16)((INT8)tmp2)*(INT16)((INT8)tmp);
+ I.regs.w[AX]=(WORD)result;
+
+ SetZF(I.regs.w[AX]);
+
+ I.CarryVal = I.OverVal = (result >> 7 != 0) && (result >> 7 != -1);
+ }
+ break;
+ case 0x30: /* DIV AL, Ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.div_r8 : cycles.div_m8;
+ {
+ UINT16 result;
+
+ result = I.regs.w[AX];
+
+ if (tmp)
+ {
+ if ((result / tmp) > 0xff)
+ {
+ PREFIX(_interrupt)(0);
+ break;
+ }
+ else
+ {
+ I.regs.b[AH] = result % tmp;
+ I.regs.b[AL] = result / tmp;
+ }
+ }
+ else
+ {
+ PREFIX(_interrupt)(0);
+ break;
+ }
+ }
+ break;
+ case 0x38: /* IDIV AL, Ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.idiv_r8 : cycles.idiv_m8;
+ {
+
+ INT16 result;
+
+ result = I.regs.w[AX];
+
+ if (tmp)
+ {
+ tmp2 = result % (INT16)((INT8)tmp);
+
+ if ((result /= (INT16)((INT8)tmp)) > 0xff)
+ {
+ PREFIX(_interrupt)(0);
+ break;
+ }
+ else
+ {
+ I.regs.b[AL] = result;
+ I.regs.b[AH] = tmp2;
+ }
+ }
+ else
+ {
+ PREFIX(_interrupt)(0);
+ break;
+ }
+ }
+ break;
+ }
+}
+
+
+static void PREFIX86(_f7pre)(void)
+{
+ /* Opcode 0xf7 */
+ unsigned ModRM = FETCH;
+ unsigned tmp = GetRMWord(ModRM);
+ unsigned tmp2;
+
+
+ switch (ModRM & 0x38)
+ {
+ case 0x00: /* TEST Ew, data16 */
+ case 0x08: /* ??? */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.alu_ri16 : cycles.alu_mi16_ro;
+ tmp2 = FETCH;
+ tmp2 += FETCH << 8;
+
+ tmp &= tmp2;
+
+ I.CarryVal = I.OverVal = I.AuxVal = 0;
+ SetSZPF_Word(tmp);
+ break;
+
+ case 0x10: /* NOT Ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.negnot_r16 : cycles.negnot_m16;
+ tmp = ~tmp;
+ PutbackRMWord(ModRM,tmp);
+ break;
+
+ case 0x18: /* NEG Ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.negnot_r16 : cycles.negnot_m16;
+ tmp2 = 0;
+ SUBW(tmp2,tmp);
+ PutbackRMWord(ModRM,tmp2);
+ break;
+ case 0x20: /* MUL AX, Ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.mul_r16 : cycles.mul_m16;
+ {
+ UINT32 result;
+ tmp2 = I.regs.w[AX];
+
+ SetSF((INT16)tmp2);
+ SetPF(tmp2);
+
+ result = (UINT32)tmp2*tmp;
+ I.regs.w[AX]=(WORD)result;
+ result >>= 16;
+ I.regs.w[DX]=result;
+
+ SetZF(I.regs.w[AX] | I.regs.w[DX]);
+ I.CarryVal = I.OverVal = (I.regs.w[DX] != 0);
+ }
+ break;
+
+ case 0x28: /* IMUL AX, Ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.imul_r16 : cycles.imul_m16;
+ {
+ INT32 result;
+
+ tmp2 = I.regs.w[AX];
+
+ SetSF((INT16)tmp2);
+ SetPF(tmp2);
+
+ result = (INT32)((INT16)tmp2)*(INT32)((INT16)tmp);
+ I.CarryVal = I.OverVal = (result >> 15 != 0) && (result >> 15 != -1);
+
+ I.regs.w[AX]=(WORD)result;
+ result = (WORD)(result >> 16);
+ I.regs.w[DX]=result;
+
+ SetZF(I.regs.w[AX] | I.regs.w[DX]);
+ }
+ break;
+ case 0x30: /* DIV AX, Ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.div_r16 : cycles.div_m16;
+ {
+ UINT32 result;
+
+ result = (I.regs.w[DX] << 16) + I.regs.w[AX];
+
+ if (tmp)
+ {
+ tmp2 = result % tmp;
+ if ((result / tmp) > 0xffff)
+ {
+ PREFIX(_interrupt)(0);
+ break;
+ }
+ else
+ {
+ I.regs.w[DX]=tmp2;
+ result /= tmp;
+ I.regs.w[AX]=result;
+ }
+ }
+ else
+ {
+ PREFIX(_interrupt)(0);
+ break;
+ }
+ }
+ break;
+ case 0x38: /* IDIV AX, Ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.idiv_r16 : cycles.idiv_m16;
+ {
+ INT32 result;
+
+ result = (I.regs.w[DX] << 16) + I.regs.w[AX];
+
+ if (tmp)
+ {
+ tmp2 = result % (INT32)((INT16)tmp);
+ if ((result /= (INT32)((INT16)tmp)) > 0xffff)
+ {
+ PREFIX(_interrupt)(0);
+ break;
+ }
+ else
+ {
+ I.regs.w[AX]=result;
+ I.regs.w[DX]=tmp2;
+ }
+ }
+ else
+ {
+ PREFIX(_interrupt)(0);
+ break;
+ }
+ }
+ break;
+ }
+}
+
+
+static void PREFIX86(_clc)(void) /* Opcode 0xf8 */
+{
+ ICOUNT -= cycles.flag_ops;
+ I.CarryVal = 0;
+}
+
+static void PREFIX86(_stc)(void) /* Opcode 0xf9 */
+{
+ ICOUNT -= cycles.flag_ops;
+ I.CarryVal = 1;
+}
+
+static void PREFIX86(_cli)(void) /* Opcode 0xfa */
+{
+ ICOUNT -= cycles.flag_ops;
+ SetIF(0);
+}
+
+static void PREFIX86(_sti)(void) /* Opcode 0xfb */
+{
+ ICOUNT -= cycles.flag_ops;
+ SetIF(1);
+ PREFIX(_instruction)[FETCHOP](); /* no interrupt before next instruction */
+
+ /* if an interrupt is pending, signal an interrupt */
+ if (I.irq_state)
+ PREFIX(_interrupt)(-1);
+}
+
+static void PREFIX86(_cld)(void) /* Opcode 0xfc */
+{
+ ICOUNT -= cycles.flag_ops;
+ SetDF(0);
+}
+
+static void PREFIX86(_std)(void) /* Opcode 0xfd */
+{
+ ICOUNT -= cycles.flag_ops;
+ SetDF(1);
+}
+
+static void PREFIX86(_fepre)(void) /* Opcode 0xfe */
+{
+ unsigned ModRM = FETCH;
+ unsigned tmp = GetRMByte(ModRM);
+ unsigned tmp1;
+
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.incdec_r8 : cycles.incdec_m8;
+ if ((ModRM & 0x38) == 0) /* INC eb */
+ {
+ tmp1 = tmp+1;
+ SetOFB_Add(tmp1,tmp,1);
+ }
+ else /* DEC eb */
+ {
+ tmp1 = tmp-1;
+ SetOFB_Sub(tmp1,1,tmp);
+ }
+
+ SetAF(tmp1,tmp,1);
+ SetSZPF_Byte(tmp1);
+
+ PutbackRMByte(ModRM,(BYTE)tmp1);
+}
+
+
+static void PREFIX86(_ffpre)(void) /* Opcode 0xff */
+{
+ unsigned ModRM = FETCHOP;
+ unsigned tmp;
+ unsigned tmp1;
+ WORD ip;
+
+ switch(ModRM & 0x38)
+ {
+ case 0x00: /* INC ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.incdec_r16 : cycles.incdec_m16;
+ tmp = GetRMWord(ModRM);
+ tmp1 = tmp+1;
+
+ SetOFW_Add(tmp1,tmp,1);
+ SetAF(tmp1,tmp,1);
+ SetSZPF_Word(tmp1);
+
+ PutbackRMWord(ModRM,(WORD)tmp1);
+ break;
+
+ case 0x08: /* DEC ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.incdec_r16 : cycles.incdec_m16;
+ tmp = GetRMWord(ModRM);
+ tmp1 = tmp-1;
+
+ SetOFW_Sub(tmp1,1,tmp);
+ SetAF(tmp1,tmp,1);
+ SetSZPF_Word(tmp1);
+
+ PutbackRMWord(ModRM,(WORD)tmp1);
+ break;
+
+ case 0x10: /* CALL ew */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.call_r16 : cycles.call_m16;
+ tmp = GetRMWord(ModRM);
+ ip = I.pc - I.base[CS];
+ PUSH(ip);
+ I.pc = (I.base[CS] + (WORD)tmp) & AMASK;
+ CHANGE_PC(I.pc);
+ break;
+
+ case 0x18: /* CALL FAR ea */
+ ICOUNT -= cycles.call_m32;
+ tmp = I.sregs[CS]; /* HJB 12/13/98 need to skip displacements of EA */
+ tmp1 = GetRMWord(ModRM);
+ ip = I.pc - I.base[CS];
+ PUSH(tmp);
+ PUSH(ip);
+#ifdef I80286
+ i80286_code_descriptor(GetnextRMWord, tmp1);
+#else
+ I.sregs[CS] = GetnextRMWord;
+ I.base[CS] = SegBase(CS);
+ I.pc = (I.base[CS] + tmp1) & AMASK;
+#endif
+ CHANGE_PC(I.pc);
+ break;
+
+ case 0x20: /* JMP ea */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.jmp_r16 : cycles.jmp_m16;
+ ip = GetRMWord(ModRM);
+ I.pc = (I.base[CS] + ip) & AMASK;
+ CHANGE_PC(I.pc);
+ break;
+
+ case 0x28: /* JMP FAR ea */
+ ICOUNT -= cycles.jmp_m32;
+
+#ifdef I80286
+ tmp = GetRMWord(ModRM);
+ i80286_code_descriptor(GetnextRMWord, tmp);
+#else
+ I.pc = GetRMWord(ModRM);
+ I.sregs[CS] = GetnextRMWord;
+ I.base[CS] = SegBase(CS);
+ I.pc = (I.pc + I.base[CS]) & AMASK;
+#endif
+ CHANGE_PC(I.pc);
+ break;
+
+ case 0x30: /* PUSH ea */
+ ICOUNT -= (ModRM >= 0xc0) ? cycles.push_r16 : cycles.push_m16;
+ tmp = GetRMWord(ModRM);
+ PUSH(tmp);
+ break;
+ }
+}
+
+
+static void PREFIX86(_invalid)(void)
+{
+#ifdef I80286
+ i80286_trap2(ILLEGAL_INSTRUCTION);
+#else
+ /* makes the cpu loops forever until user resets it */
+ /*{ DEBUGGER_BREAK; } */
+ logerror("illegal instruction %.2x at %.5x\n",PEEKBYTE(I.pc), I.pc);
+ I.pc--;
+ ICOUNT -= 10;
+#endif
+}
+#endif
diff --git a/src/emu/cpu/i86/instr86.h b/src/emu/cpu/i86/instr86.h
new file mode 100644
index 00000000000..6bcf350479a
--- /dev/null
+++ b/src/emu/cpu/i86/instr86.h
@@ -0,0 +1,237 @@
+/****************************************************************************
+* real mode i286 emulator v1.4 by Fabrice Frances *
+* (initial work based on David Hedley's pcemu) *
+****************************************************************************/
+
+// file will be included in all cpu variants
+// put non i86 instructions in own files (i286, i386, nec)
+// function renaming will be added when neccessary
+// timing value should move to separate array
+
+static void PREFIX86(_add_br8)(void);
+static void PREFIX86(_add_wr16)(void);
+static void PREFIX86(_add_r8b)(void);
+static void PREFIX86(_add_r16w)(void);
+static void PREFIX86(_add_ald8)(void);
+static void PREFIX86(_add_axd16)(void);
+static void PREFIX86(_push_es)(void);
+static void PREFIX86(_pop_es)(void);
+static void PREFIX86(_or_br8)(void);
+static void PREFIX86(_or_r8b)(void);
+static void PREFIX86(_or_wr16)(void);
+static void PREFIX86(_or_r16w)(void);
+static void PREFIX86(_or_ald8)(void);
+static void PREFIX86(_or_axd16)(void);
+static void PREFIX86(_push_cs)(void);
+static void PREFIX86(_adc_br8)(void);
+static void PREFIX86(_adc_wr16)(void);
+static void PREFIX86(_adc_r8b)(void);
+static void PREFIX86(_adc_r16w)(void);
+static void PREFIX86(_adc_ald8)(void);
+static void PREFIX86(_adc_axd16)(void);
+static void PREFIX86(_push_ss)(void);
+static void PREFIX86(_pop_ss)(void);
+static void PREFIX86(_sbb_br8)(void);
+static void PREFIX86(_sbb_wr16)(void);
+static void PREFIX86(_sbb_r8b)(void);
+static void PREFIX86(_sbb_r16w)(void);
+static void PREFIX86(_sbb_ald8)(void);
+static void PREFIX86(_sbb_axd16)(void);
+static void PREFIX86(_push_ds)(void);
+static void PREFIX86(_pop_ds)(void);
+static void PREFIX86(_and_br8)(void);
+static void PREFIX86(_and_r8b)(void);
+static void PREFIX86(_and_wr16)(void);
+static void PREFIX86(_and_r16w)(void);
+static void PREFIX86(_and_ald8)(void);
+static void PREFIX86(_and_axd16)(void);
+static void PREFIX86(_es)(void);
+static void PREFIX86(_daa)(void);
+static void PREFIX86(_sub_br8)(void);
+static void PREFIX86(_sub_wr16)(void);
+static void PREFIX86(_sub_r8b)(void);
+static void PREFIX86(_sub_r16w)(void);
+static void PREFIX86(_sub_ald8)(void);
+static void PREFIX86(_sub_axd16)(void);
+static void PREFIX86(_cs)(void);
+static void PREFIX86(_das)(void);
+static void PREFIX86(_xor_br8)(void);
+static void PREFIX86(_xor_r8b)(void);
+static void PREFIX86(_xor_wr16)(void);
+static void PREFIX86(_xor_r16w)(void);
+static void PREFIX86(_xor_ald8)(void);
+static void PREFIX86(_xor_axd16)(void);
+static void PREFIX86(_ss)(void);
+static void PREFIX86(_aaa)(void);
+static void PREFIX86(_cmp_br8)(void);
+static void PREFIX86(_cmp_wr16)(void);
+static void PREFIX86(_cmp_r8b)(void);
+static void PREFIX86(_cmp_r16w)(void);
+static void PREFIX86(_cmp_ald8)(void);
+static void PREFIX86(_cmp_axd16)(void);
+static void PREFIX86(_ds)(void);
+static void PREFIX86(_aas)(void);
+static void PREFIX86(_inc_ax)(void);
+static void PREFIX86(_inc_cx)(void);
+static void PREFIX86(_inc_dx)(void);
+static void PREFIX86(_inc_bx)(void);
+static void PREFIX86(_inc_sp)(void);
+static void PREFIX86(_inc_bp)(void);
+static void PREFIX86(_inc_si)(void);
+static void PREFIX86(_inc_di)(void);
+static void PREFIX86(_dec_ax)(void);
+static void PREFIX86(_dec_cx)(void);
+static void PREFIX86(_dec_dx)(void);
+static void PREFIX86(_dec_bx)(void);
+static void PREFIX86(_dec_sp)(void);
+static void PREFIX86(_dec_bp)(void);
+static void PREFIX86(_dec_si)(void);
+static void PREFIX86(_dec_di)(void);
+static void PREFIX86(_push_ax)(void);
+static void PREFIX86(_push_cx)(void);
+static void PREFIX86(_push_dx)(void);
+static void PREFIX86(_push_bx)(void);
+static void PREFIX86(_push_sp)(void);
+static void PREFIX86(_push_bp)(void);
+static void PREFIX86(_push_si)(void);
+static void PREFIX86(_push_di)(void);
+static void PREFIX86(_pop_ax)(void);
+static void PREFIX86(_pop_cx)(void);
+static void PREFIX86(_pop_dx)(void);
+static void PREFIX86(_pop_bx)(void);
+static void PREFIX86(_pop_sp)(void);
+static void PREFIX86(_pop_bp)(void);
+static void PREFIX86(_pop_si)(void);
+static void PREFIX86(_pop_di)(void);
+static void PREFIX86(_jo)(void);
+static void PREFIX86(_jno)(void);
+static void PREFIX86(_jb)(void);
+static void PREFIX86(_jnb)(void);
+static void PREFIX86(_jz)(void);
+static void PREFIX86(_jnz)(void);
+static void PREFIX86(_jbe)(void);
+static void PREFIX86(_jnbe)(void);
+static void PREFIX86(_js)(void);
+static void PREFIX86(_jns)(void);
+static void PREFIX86(_jp)(void);
+static void PREFIX86(_jnp)(void);
+static void PREFIX86(_jl)(void);
+static void PREFIX86(_jnl)(void);
+static void PREFIX86(_jle)(void);
+static void PREFIX86(_jnle)(void);
+static void PREFIX86(_80pre)(void);
+static void PREFIX86(_82pre)(void);
+static void PREFIX86(_81pre)(void);
+static void PREFIX86(_83pre)(void);
+static void PREFIX86(_test_br8)(void);
+static void PREFIX86(_test_wr16)(void);
+static void PREFIX86(_xchg_br8)(void);
+static void PREFIX86(_xchg_wr16)(void);
+static void PREFIX86(_mov_br8)(void);
+static void PREFIX86(_mov_r8b)(void);
+static void PREFIX86(_mov_wr16)(void);
+static void PREFIX86(_mov_r16w)(void);
+static void PREFIX86(_mov_wsreg)(void);
+static void PREFIX86(_lea)(void);
+static void PREFIX86(_mov_sregw)(void);
+static void PREFIX86(_invalid)(void);
+static void PREFIX86(_popw)(void);
+static void PREFIX86(_nop)(void);
+static void PREFIX86(_xchg_axcx)(void);
+static void PREFIX86(_xchg_axdx)(void);
+static void PREFIX86(_xchg_axbx)(void);
+static void PREFIX86(_xchg_axsp)(void);
+static void PREFIX86(_xchg_axbp)(void);
+static void PREFIX86(_xchg_axsi)(void);
+static void PREFIX86(_xchg_axdi)(void);
+static void PREFIX86(_cbw)(void);
+static void PREFIX86(_cwd)(void);
+static void PREFIX86(_call_far)(void);
+static void PREFIX86(_pushf)(void);
+static void PREFIX86(_popf)(void);
+static void PREFIX86(_sahf)(void);
+static void PREFIX86(_lahf)(void);
+static void PREFIX86(_mov_aldisp)(void);
+static void PREFIX86(_mov_axdisp)(void);
+static void PREFIX86(_mov_dispal)(void);
+static void PREFIX86(_mov_dispax)(void);
+static void PREFIX86(_movsb)(void);
+static void PREFIX86(_movsw)(void);
+static void PREFIX86(_cmpsb)(void);
+static void PREFIX86(_cmpsw)(void);
+static void PREFIX86(_test_ald8)(void);
+static void PREFIX86(_test_axd16)(void);
+static void PREFIX86(_stosb)(void);
+static void PREFIX86(_stosw)(void);
+static void PREFIX86(_lodsb)(void);
+static void PREFIX86(_lodsw)(void);
+static void PREFIX86(_scasb)(void);
+static void PREFIX86(_scasw)(void);
+static void PREFIX86(_mov_ald8)(void);
+static void PREFIX86(_mov_cld8)(void);
+static void PREFIX86(_mov_dld8)(void);
+static void PREFIX86(_mov_bld8)(void);
+static void PREFIX86(_mov_ahd8)(void);
+static void PREFIX86(_mov_chd8)(void);
+static void PREFIX86(_mov_dhd8)(void);
+static void PREFIX86(_mov_bhd8)(void);
+static void PREFIX86(_mov_axd16)(void);
+static void PREFIX86(_mov_cxd16)(void);
+static void PREFIX86(_mov_dxd16)(void);
+static void PREFIX86(_mov_bxd16)(void);
+static void PREFIX86(_mov_spd16)(void);
+static void PREFIX86(_mov_bpd16)(void);
+static void PREFIX86(_mov_sid16)(void);
+static void PREFIX86(_mov_did16)(void);
+static void PREFIX86(_ret_d16)(void);
+static void PREFIX86(_ret)(void);
+static void PREFIX86(_les_dw)(void);
+static void PREFIX86(_lds_dw)(void);
+static void PREFIX86(_mov_bd8)(void);
+static void PREFIX86(_mov_wd16)(void);
+static void PREFIX86(_retf_d16)(void);
+static void PREFIX86(_retf)(void);
+static void PREFIX86(_int3)(void);
+static void PREFIX86(_int)(void);
+static void PREFIX86(_into)(void);
+static void PREFIX86(_iret)(void);
+static void PREFIX86(_rotshft_b)(void);
+static void PREFIX86(_rotshft_w)(void);
+static void PREFIX86(_rotshft_bcl)(void);
+static void PREFIX86(_rotshft_wcl)(void);
+static void PREFIX86(_aam)(void);
+static void PREFIX86(_aad)(void);
+static void PREFIX86(_xlat)(void);
+static void PREFIX86(_escape)(void);
+static void PREFIX86(_loopne)(void);
+static void PREFIX86(_loope)(void);
+static void PREFIX86(_loop)(void);
+static void PREFIX86(_jcxz)(void);
+static void PREFIX86(_inal)(void);
+static void PREFIX86(_inax)(void);
+static void PREFIX86(_outal)(void);
+static void PREFIX86(_outax)(void);
+static void PREFIX86(_call_d16)(void);
+static void PREFIX86(_jmp_d16)(void);
+static void PREFIX86(_jmp_far)(void);
+static void PREFIX86(_jmp_d8)(void);
+static void PREFIX86(_inaldx)(void);
+static void PREFIX86(_inaxdx)(void);
+static void PREFIX86(_outdxal)(void);
+static void PREFIX86(_outdxax)(void);
+static void PREFIX86(_lock)(void);
+static void PREFIX86(_repne)(void);
+static void PREFIX86(_repe)(void);
+static void PREFIX86(_hlt)(void);
+static void PREFIX86(_cmc)(void);
+static void PREFIX86(_f6pre)(void);
+static void PREFIX86(_f7pre)(void);
+static void PREFIX86(_clc)(void);
+static void PREFIX86(_stc)(void);
+static void PREFIX86(_cli)(void);
+static void PREFIX86(_sti)(void);
+static void PREFIX86(_cld)(void);
+static void PREFIX86(_std)(void);
+static void PREFIX86(_fepre)(void);
+static void PREFIX86(_ffpre)(void);
+static void PREFIX86(_wait)(void);
diff --git a/src/emu/cpu/i86/instrv30.c b/src/emu/cpu/i86/instrv30.c
new file mode 100644
index 00000000000..39272760f8f
--- /dev/null
+++ b/src/emu/cpu/i86/instrv30.c
@@ -0,0 +1,1311 @@
+static void PREFIXV30(_0fpre) (void) /* Opcode 0x0f */
+{
+ unsigned Opcode = FETCH;
+ unsigned ModRM;
+ unsigned tmp;
+ unsigned tmp2;
+
+ switch (Opcode)
+ {
+ case 0x10: /* 0F 10 47 30 - TEST1 [bx+30h],cl */
+ ModRM = FETCH;
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 3;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 12; /* my source says 14 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = I.regs.b[CL] & 0x7;
+ I.ZeroVal = tmp & bytes[tmp2] ? 1 : 0;
+/* SetZF(tmp & (1<<tmp2)); */
+ break;
+
+ case 0x11: /* 0F 11 47 30 - TEST1 [bx+30h],cl */
+ ModRM = FETCH;
+ /* tmp = GetRMWord(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.w[Mod_RM.RM.w[ModRM]];
+ nec_ICount -= 3;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadWord(EA);
+ nec_ICount = old - 12; /* my source says 14 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = I.regs.b[CL] & 0xF;
+ I.ZeroVal = tmp & bytes[tmp2] ? 1 : 0;
+/* SetZF(tmp & (1<<tmp2)); */
+ break;
+
+ case 0x12: /* 0F 12 [mod:000:r/m] - CLR1 reg/m8,cl */
+ ModRM = FETCH;
+ /* need the long if due to correct cycles OB[19.07.99] */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 5;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 14; /* my source says 14 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = I.regs.b[CL] & 0x7; /* hey its a Byte so &07 NOT &0f */
+ tmp &= ~(bytes[tmp2]);
+ PutbackRMByte(ModRM, tmp);
+ break;
+
+ case 0x13: /* 0F 13 [mod:000:r/m] - CLR1 reg/m16,cl */
+ ModRM = FETCH;
+ /* tmp = GetRMWord(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.w[Mod_RM.RM.w[ModRM]];
+ nec_ICount -= 5;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadWord(EA);
+ nec_ICount = old - 14; /* my source says 14 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = I.regs.b[CL] & 0xF; /* this time its a word */
+ tmp &= ~(bytes[tmp2]);
+ PutbackRMWord(ModRM, tmp);
+ break;
+
+ case 0x14: /* 0F 14 47 30 - SET1 [bx+30h],cl */
+ ModRM = FETCH;
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 4;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 13;
+ }
+ tmp2 = I.regs.b[CL] & 0x7;
+ tmp |= (bytes[tmp2]);
+ PutbackRMByte(ModRM, tmp);
+ break;
+
+ case 0x15: /* 0F 15 C6 - SET1 si,cl */
+ ModRM = FETCH;
+ /* tmp = GetRMWord(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.w[Mod_RM.RM.w[ModRM]];
+ nec_ICount -= 4;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadWord(EA);
+ nec_ICount = old - 13;
+ }
+ tmp2 = I.regs.b[CL] & 0xF;
+ tmp |= (bytes[tmp2]);
+ PutbackRMWord(ModRM, tmp);
+ break;
+
+ case 0x16: /* 0F 16 C6 - NOT1 si,cl */
+ ModRM = FETCH;
+ /* need the long if due to correct cycles OB[19.07.99] */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 4;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 18; /* my source says 18 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = I.regs.b[CL] & 0x7; /* hey its a Byte so &07 NOT &0f */
+ if (tmp & bytes[tmp2])
+ tmp &= ~(bytes[tmp2]);
+ else
+ tmp |= (bytes[tmp2]);
+ PutbackRMByte(ModRM, tmp);
+ break;
+
+ case 0x17: /* 0F 17 C6 - NOT1 si,cl */
+ ModRM = FETCH;
+ /* tmp = GetRMWord(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.w[Mod_RM.RM.w[ModRM]];
+ nec_ICount -= 4;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadWord(EA);
+ nec_ICount = old - 18; /* my source says 14 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = I.regs.b[CL] & 0xF; /* this time its a word */
+ if (tmp & bytes[tmp2])
+ tmp &= ~(bytes[tmp2]);
+ else
+ tmp |= (bytes[tmp2]);
+ PutbackRMWord(ModRM, tmp);
+ break;
+
+ case 0x18: /* 0F 18 XX - TEST1 [bx+30h],07 */
+ ModRM = FETCH;
+ /* tmp = GetRMByte(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 4;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 13; /* my source says 15 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = FETCH;
+ tmp2 &= 0xF;
+ I.ZeroVal = tmp & (bytes[tmp2]) ? 1 : 0;
+/* SetZF(tmp & (1<<tmp2)); */
+ break;
+
+ case 0x19: /* 0F 19 XX - TEST1 [bx+30h],07 */
+ ModRM = FETCH;
+ /* tmp = GetRMWord(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.w[Mod_RM.RM.w[ModRM]];
+ nec_ICount -= 4;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadWord(EA);
+ nec_ICount = old - 13; /* my source says 14 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = FETCH;
+ tmp2 &= 0xf;
+ I.ZeroVal = tmp & (bytes[tmp2]) ? 1 : 0;
+/* SetZF(tmp & (1<<tmp2)); */
+ break;
+
+ case 0x1a: /* 0F 1A 06 - CLR1 si,cl */
+ ModRM = FETCH;
+ /* tmp = GetRMByte(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 6;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 15; /* my source says 15 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = FETCH;
+ tmp2 &= 0x7;
+ tmp &= ~(bytes[tmp2]);
+ PutbackRMByte(ModRM, tmp);
+ break;
+
+ case 0x1B: /* 0F 1B 06 - CLR1 si,cl */
+ ModRM = FETCH;
+ /* tmp = GetRMWord(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.w[Mod_RM.RM.w[ModRM]];
+ nec_ICount -= 6;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadWord(EA);
+ nec_ICount = old - 15; /* my source says 15 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = FETCH;
+ tmp2 &= 0xF;
+ tmp &= ~(bytes[tmp2]);
+ PutbackRMWord(ModRM, tmp);
+ break;
+
+ case 0x1C: /* 0F 1C 47 30 - SET1 [bx+30h],cl */
+ ModRM = FETCH;
+ /* tmp = GetRMByte(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 5;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 14; /* my source says 15 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = FETCH;
+ tmp2 &= 0x7;
+ tmp |= (bytes[tmp2]);
+ PutbackRMByte(ModRM, tmp);
+ break;
+
+ case 0x1D: /* 0F 1D C6 - SET1 si,cl */
+ /* logerror("PC=%06x : Set1 ",activecpu_get_pc()-2); */
+ ModRM = FETCH;
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.w[Mod_RM.RM.w[ModRM]];
+ nec_ICount -= 5;
+ /* logerror("reg=%04x ->",tmp); */
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) (); /* calculate EA */
+ tmp = ReadWord(EA); /* read from EA */
+ nec_ICount = old - 14;
+ /* logerror("[%04x]=%04x ->",EA,tmp); */
+ }
+ tmp2 = FETCH;
+ tmp2 &= 0xF;
+ tmp |= (bytes[tmp2]);
+ /* logerror("%04x",tmp); */
+ PutbackRMWord(ModRM, tmp);
+ break;
+
+ case 0x1e: /* 0F 1e C6 - NOT1 si,07 */
+ ModRM = FETCH;
+ /* tmp = GetRMByte(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 5;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 19;
+ }
+ tmp2 = FETCH;
+ tmp2 &= 0x7;
+ if (tmp & bytes[tmp2])
+ tmp &= ~(bytes[tmp2]);
+ else
+ tmp |= (bytes[tmp2]);
+ PutbackRMByte(ModRM, tmp);
+ break;
+
+ case 0x1f: /* 0F 1f C6 - NOT1 si,07 */
+ ModRM = FETCH;
+ //tmp = GetRMWord(ModRM);
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.w[Mod_RM.RM.w[ModRM]];
+ nec_ICount -= 5;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadWord(EA);
+ nec_ICount = old - 19; /* my source says 15 cycles everytime and not
+ * ModRM-dependent like GetEA[] does..hmmm */
+ }
+ tmp2 = FETCH;
+ tmp2 &= 0xF;
+ if (tmp & bytes[tmp2])
+ tmp &= ~(bytes[tmp2]);
+ else
+ tmp |= (bytes[tmp2]);
+ PutbackRMWord(ModRM, tmp);
+ break;
+
+ case 0x20: /* 0F 20 59 - add4s */
+ {
+ /* length in words ! */
+ int count = (I.regs.b[CL] + 1) / 2;
+ int i;
+ unsigned di = I.regs.w[DI];
+ unsigned si = I.regs.w[SI];
+
+ I.ZeroVal = 1;
+ I.CarryVal = 0; /* NOT ADC */
+ for (i = 0; i < count; i++)
+ {
+ int v1, v2;
+ int result;
+
+ tmp = GetMemB(DS, si);
+ tmp2 = GetMemB(ES, di);
+
+ v1 = (tmp >> 4) * 10 + (tmp & 0xf);
+ v2 = (tmp2 >> 4) * 10 + (tmp2 & 0xf);
+ result = v1 + v2 + I.CarryVal;
+ I.CarryVal = result > 99 ? 1 : 0;
+ result = result % 100;
+ v1 = ((result / 10) << 4) | (result % 10);
+ PutMemB(ES, di, v1);
+ if (v1)
+ I.ZeroVal = 0;
+ si++;
+ di++;
+ }
+ I.OverVal = I.CarryVal;
+ nec_ICount -= 7 + 19 * count; /* 7+19n, n #operand words */
+ }
+ break;
+
+ case 0x22: /* 0F 22 59 - sub4s */
+ {
+ int count = (I.regs.b[CL] + 1) / 2;
+ int i;
+ unsigned di = I.regs.w[DI];
+ unsigned si = I.regs.w[SI];
+
+ I.ZeroVal = 1;
+ I.CarryVal = 0; /* NOT ADC */
+ for (i = 0; i < count; i++)
+ {
+ int v1, v2;
+ int result;
+
+ tmp = GetMemB(ES, di);
+ tmp2 = GetMemB(DS, si);
+
+ v1 = (tmp >> 4) * 10 + (tmp & 0xf);
+ v2 = (tmp2 >> 4) * 10 + (tmp2 & 0xf);
+ if (v1 < (v2 + I.CarryVal))
+ {
+ v1 += 100;
+ result = v1 - (v2 + I.CarryVal);
+ I.CarryVal = 1;
+ }
+ else
+ {
+ result = v1 - (v2 + I.CarryVal);
+ I.CarryVal = 0;
+ }
+ v1 = ((result / 10) << 4) | (result % 10);
+ PutMemB(ES, di, v1);
+ if (v1)
+ I.ZeroVal = 0;
+ si++;
+ di++;
+ }
+ I.OverVal = I.CarryVal;
+ nec_ICount -= 7 + 19 * count;
+ }
+ break;
+
+ case 0x25:
+ /*
+ * ----------O-MOVSPA---------------------------------
+ * OPCODE MOVSPA - Move Stack Pointer After Bank Switched
+ *
+ * CPU: NEC V25,V35,V25 Plus,V35 Plus,V25 Software Guard
+ * Type of Instruction: System
+ *
+ * Instruction: MOVSPA
+ *
+ * Description: This instruction transfer both SS and SP of the old register
+ * bank to new register bank after the bank has been switched by
+ * interrupt or BRKCS instruction.
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form: MOVSPA
+ * COP (Code of Operation) : 0Fh 25h
+ *
+ * Clocks: 16
+ */
+ logerror("PC=%06x : MOVSPA\n", activecpu_get_pc() - 2);
+ nec_ICount -= 16;
+ break;
+ case 0x26: /* 0F 22 59 - cmp4s */
+ {
+ int count = (I.regs.b[CL] + 1) / 2;
+ int i;
+ unsigned di = I.regs.w[DI];
+ unsigned si = I.regs.w[SI];
+
+ I.ZeroVal = 1;
+ I.CarryVal = 0; /* NOT ADC */
+ for (i = 0; i < count; i++)
+ {
+ int v1, v2;
+ int result;
+
+ tmp = GetMemB(ES, di);
+ tmp2 = GetMemB(DS, si);
+
+ v1 = (tmp >> 4) * 10 + (tmp & 0xf);
+ v2 = (tmp2 >> 4) * 10 + (tmp2 & 0xf);
+ if (v1 < (v2 + I.CarryVal))
+ {
+ v1 += 100;
+ result = v1 - (v2 + I.CarryVal);
+ I.CarryVal = 1;
+ }
+ else
+ {
+ result = v1 - (v2 + I.CarryVal);
+ I.CarryVal = 0;
+ }
+ v1 = ((result / 10) << 4) | (result % 10);
+/* PutMemB(ES, di,v1); */ /* no store, only compare */
+ if (v1)
+ I.ZeroVal = 0;
+ si++;
+ di++;
+ }
+ I.OverVal = I.CarryVal;
+ nec_ICount -= 7 + 19 * (I.regs.b[CL] + 1); // 7+19n, n #operand bytes
+ }
+ break;
+ case 0x28: /* 0F 28 C7 - ROL4 bh */
+ ModRM = FETCH;
+ /* tmp = GetRMByte(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 25;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 28;
+ }
+ tmp <<= 4;
+ tmp |= I.regs.b[AL] & 0xF;
+ I.regs.b[AL] = (I.regs.b[AL] & 0xF0) | ((tmp >> 8) & 0xF);
+ tmp &= 0xff;
+ PutbackRMByte(ModRM, tmp);
+ break;
+
+ /* Is this a REAL instruction?? */
+ case 0x29: /* 0F 29 C7 - ROL4 bx */
+
+ ModRM = FETCH;
+ /*
+ * if (ModRM >= 0xc0)
+ * {
+ * tmp=I.regs.w[Mod_RM.RM.w[ModRM]];
+ * nec_ICount-=29;
+ * }
+ * else
+ * {
+ * int old=nec_ICount;
+ * (*GetEA[ModRM])();
+ * tmp=ReadWord(EA);
+ * nec_ICount=old-33;
+ * }
+ * tmp <<= 4;
+ * tmp |= I.regs.b[AL] & 0xF;
+ * I.regs.b[AL] = (I.regs.b[AL] & 0xF0) | ((tmp>>8)&0xF);
+ * tmp &= 0xffff;
+ * PutbackRMWord(ModRM,tmp);
+ */
+ logerror("PC=%06x : ROL4 %02x\n", activecpu_get_pc() - 3, ModRM);
+ break;
+
+ case 0x2A: /* 0F 2a c2 - ROR4 bh */
+ ModRM = FETCH;
+ /* tmp = GetRMByte(ModRM); */
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ nec_ICount -= 29;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ nec_ICount = old - 33;
+ }
+ tmp2 = (I.regs.b[AL] & 0xF) << 4;
+ I.regs.b[AL] = (I.regs.b[AL] & 0xF0) | (tmp & 0xF);
+ tmp = tmp2 | (tmp >> 4);
+ PutbackRMByte(ModRM, tmp);
+ break;
+
+ case 0x2B: // 0F 2b c2 - ROR4 bx
+ ModRM = FETCH;
+ /*
+ * /* tmp = GetRMWord(ModRM);
+ * if (ModRM >= 0xc0)
+ * {
+ * tmp=I.regs.w[Mod_RM.RM.w[ModRM]];
+ * nec_ICount-=29;
+ * }
+ * else {
+ * int old=nec_ICount;
+ * (*GetEA[ModRM])();
+ * tmp=ReadWord(EA);
+ * nec_ICount=old-33;
+ * }
+ * tmp2 = (I.regs.b[AL] & 0xF)<<4;
+ * I.regs.b[AL] = (I.regs.b[AL] & 0xF0) | (tmp&0xF);
+ * tmp = tmp2 | (tmp>>4);
+ * PutbackRMWord(ModRM,tmp);
+ */
+ logerror("PC=%06x : ROR4 %02x\n", activecpu_get_pc() - 3, ModRM);
+ break;
+
+ case 0x2D: /* 0Fh 2Dh <1111 1RRR> */
+ /* OPCODE BRKCS - Break with Contex Switch
+ * CPU: NEC V25,V35,V25 Plus,V35 Plus,V25 Software Guard
+ * Description:
+ *
+ * Perform a High-Speed Software Interrupt with contex-switch to
+ * register bank indicated by the lower 3-bits of 'bank'.
+ *
+ * Info: NEC V25/V35/V25 Plus/V35 Plus Bank System
+ *
+ * This Chips have 8 32bytes register banks, which placed in
+ * Internal chip RAM by addresses:
+ * xxE00h..xxE1Fh Bank 0
+ * xxE20h..xxE3Fh Bank 1
+ * .........
+ * xxEC0h..xxEDFh Bank 6
+ * xxEE0h..xxEFFh Bank 7
+ * xxF00h..xxFFFh Special Functions Register
+ * Where xx is Value of IDB register.
+ * IBD is Byte Register contained Internal data area base
+ * IBD addresses is FFFFFh and xxFFFh where xx is data in IBD.
+ *
+ * Format of Bank:
+ * +0 Reserved
+ * +2 Vector PC
+ * +4 Save PSW
+ * +6 Save PC
+ * +8 DS0 ;DS
+ * +A SS ;SS
+ * +C PS ;CS
+ * +E DS1 ;ES
+ * +10 IY ;DI
+ * +11 IX ;SI
+ * +14 BP ;BP
+ * +16 SP ;SP
+ * +18 BW ;BX
+ * +1A DW ;DX
+ * +1C CW ;CX
+ * +1E AW ;AX
+ *
+ * Format of V25 etc. PSW (FLAGS):
+ * Bit Description
+ * 15 1
+ * 14 RB2 \
+ * 13 RB1 > Current Bank Number
+ * 12 RB0 /
+ * 11 V ;OF
+ * 10 IYR ;DF
+ * 9 IE ;IF
+ * 8 BRK ;TF
+ * 7 S ;SF
+ * 6 Z ;ZF
+ * 5 F1 General Purpose user flag #1 (accessed by Flag Special Function Register)
+ * 4 AC ;AF
+ * 3 F0 General purpose user flag #0 (accessed by Flag Special Function Register)
+ * 2 P ;PF
+ * 1 BRKI I/O Trap Enable Flag
+ * 0 CY ;CF
+ *
+ * Flags Affected: None
+ */
+ ModRM = FETCH;
+ logerror("PC=%06x : BRKCS %02x\n", activecpu_get_pc() - 3, ModRM);
+ nec_ICount -= 15; /* checked ! */
+ break;
+
+ case 0x31: /* 0F 31 [mod:reg:r/m] - INS reg8,reg8 or INS reg8,imm4 */
+ ModRM = FETCH;
+ logerror("PC=%06x : INS ", activecpu_get_pc() - 2);
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ logerror("ModRM=%04x \n", ModRM);
+ nec_ICount -= 29;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ logerror("ModRM=%04x Byte=%04x\n", EA, tmp);
+ nec_ICount = old - 33;
+ }
+
+ /* more to come
+ * bfl=tmp2 & 0xf; /* bit field length
+ * bfs=tmp & 0xf; /* bit field start (bit offset in DS:SI)
+ * I.regs.b[AH] =0; /* AH =0
+ */
+
+ /* 2do: the rest is silence....yet
+ * ----------O-INS------------------------------------
+ * OPCODE INS - Insert Bit String
+ *
+ * CPU: NEC/Sony all V-series
+ * Type of Instruction: User
+ *
+ * Instruction: INS start,len
+ *
+ * Description:
+ *
+ * BitField [ BASE = ES:DI
+ * START BIT OFFSET = start
+ * LENGTH = len
+ * ] <- AX [ bits= (len-1)..0]
+ *
+ * Note: di and start automatically UPDATE
+ * Note: Alternative Name of this instruction is NECINS
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form : INS reg8,reg8
+ * COP (Code of Operation) : 0FH 31H PostByte
+ */
+
+ /* nec_ICount-=31; */ /* 31 -117 clocks ....*/
+ break;
+
+ case 0x33: /* 0F 33 [mod:reg:r/m] - EXT reg8,reg8 or EXT reg8,imm4 */
+ ModRM = FETCH;
+ logerror("PC=%06x : EXT ", activecpu_get_pc() - 2);
+ if (ModRM >= 0xc0)
+ {
+ tmp = I.regs.b[Mod_RM.RM.b[ModRM]];
+ logerror("ModRM=%04x \n", ModRM);
+ nec_ICount -= 29;
+ }
+ else
+ {
+ int old = nec_ICount;
+
+ (*GetEA[ModRM]) ();
+ tmp = ReadByte(EA);
+ logerror("ModRM=%04x Byte=%04x\n", EA, tmp);
+ nec_ICount = old - 33;
+ }
+ /* 2do: the rest is silence....yet
+ /*
+ * bfl=tmp2 & 0xf; /* bit field length
+ * bfs=tmp & 0xf; /* bit field start (bit offset in DS:SI)
+ * I.regs.b[AH] =0; /* AH =0
+ */
+
+ /*
+ *
+ * ----------O-EXT------------------------------------
+ * OPCODE EXT - Extract Bit Field
+ *
+ * CPU: NEC/Sony all V-series
+ * Type of Instruction: User
+ *
+ * Instruction: EXT start,len
+ *
+ * Description:
+ *
+ * AX <- BitField [
+ * BASE = DS:SI
+ * START BIT OFFSET = start
+ * LENGTH = len
+ * ];
+ *
+ * Note: si and start automatically UPDATE
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form : EXT reg8,reg8
+ * COP (Code of Operation) : 0FH 33H PostByte
+ *
+ * Clocks: EXT reg8,reg8
+ * NEC V20: 26-55
+ */
+
+ /* NEC_ICount-=26; */ /* 26 -55 clocks ....*/
+ break;
+
+ case 0x91:
+ /*
+ * ----------O-RETRBI---------------------------------
+ * OPCODE RETRBI - Return from Register Bank Context
+ * Switch Interrupt.
+ *
+ * CPU: NEC V25,V35,V25 Plus,V35 Plus,V25 Software Guard
+ * Type of Instruction: System
+ *
+ * Instruction: RETRBI
+ *
+ * Description:
+ *
+ * PC <- Save PC;
+ * PSW <- Save PSW;
+ *
+ * Flags Affected: All
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form: RETRBI
+ * COP (Code of Operation) : 0Fh 91h
+ *
+ * Clocks: 12
+ */
+ logerror("PC=%06x : RETRBI\n", activecpu_get_pc() - 2);
+ nec_ICount -= 12;
+ break;
+
+ case 0x94:
+ /*
+ * ----------O-TSKSW----------------------------------
+ * OPCODE TSKSW - Task Switch
+ *
+ * CPU: NEC V25,V35,V25 Plus,V35 Plus,V25 Software Guard
+ * Type of Instruction: System
+ *
+ * Instruction: TSKSW reg16
+ *
+ * Description: Perform a High-Speed task switch to the register bank indicated
+ * by lower 3 bits of reg16. The PC and PSW are saved in the old
+ * banks. PC and PSW save Registers and the new PC and PSW values
+ * are retrived from the new register bank's save area.
+ *
+ * Note: See BRKCS instruction for more Info about banks.
+ *
+ * Flags Affected: All
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form: TSCSW reg16
+ * COP (Code of Operation) : 0Fh 94h <1111 1RRR>
+ *
+ * Clocks: 11
+ */
+ ModRM = FETCH;
+
+ logerror("PC=%06x : TSCSW %02x\n", activecpu_get_pc() - 3, ModRM);
+ nec_ICount -= 11;
+ break;
+
+ case 0x95:
+ /*
+ * ----------O-MOVSPB---------------------------------
+ * OPCODE MOVSPB - Move Stack Pointer Before Bamk Switching
+ *
+ * CPU: NEC V25,V35,V25 Plus,V35 Plus,V25 Software Guard
+ * Type of Instruction: System
+ *
+ * Instruction: MOVSPB Number_of_bank
+ *
+ * Description: The MOVSPB instruction transfers the current SP and SS before
+ * the bank switching to new register bank.
+ *
+ * Note: New Register Bank Number indicated by lower 3bit of Number_of_
+ * _bank.
+ *
+ * Note: See BRKCS instruction for more info about banks.
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form: MOVSPB reg16
+ * COP (Code of Operation) : 0Fh 95h <1111 1RRR>
+ *
+ * Clocks: 11
+ */
+ ModRM = FETCH;
+ logerror("PC=%06x : MOVSPB %02x\n", activecpu_get_pc() - 3, ModRM);
+ nec_ICount -= 11;
+ break;
+
+ case 0xbe:
+ /*
+ * ----------O-STOP-----------------------------------
+ * OPCODE STOP - Stop CPU
+ *
+ * CPU: NEC V25,V35,V25 Plus,V35 Plus,V25 Software Guard
+ * Type of Instruction: System
+ *
+ * Instruction: STOP
+ *
+ * Description:
+ * PowerDown instruction, Stop Oscillator,
+ * Halt CPU.
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form: STOP
+ * COP (Code of Operation) : 0Fh BEh
+ *
+ * Clocks: N/A
+ */
+ logerror("PC=%06x : STOP\n", activecpu_get_pc() - 2);
+ nec_ICount -= 2; /* of course this is crap */
+ break;
+
+ case 0xe0:
+ /*
+ * ----------O-BRKXA----------------------------------
+ * OPCODE BRKXA - Break to Expansion Address
+ *
+ * CPU: NEC V33/V53 only
+ * Type of Instruction: System
+ *
+ * Instruction: BRKXA int_vector
+ *
+ * Description:
+ * [sp-1,sp-2] <- PSW ; PSW EQU FLAGS
+ * [sp-3,sp-4] <- PS ; PS EQU CS
+ * [sp-5,sp-6] <- PC ; PC EQU IP
+ * SP <- SP -6
+ * IE <- 0
+ * BRK <- 0
+ * MD <- 0
+ * PC <- [int_vector*4 +0,+1]
+ * PS <- [int_vector*4 +2,+3]
+ * Enter Expansion Address Mode.
+ *
+ * Note: In NEC V53 Memory Space dividing into 1024 16K pages.
+ * The programming model is Same as in Normal mode.
+ *
+ * Mechanism is:
+ * 20 bit Logical Address: 19..14 Page Num 13..0 Offset
+ *
+ * page Num convertin by internal table to 23..14 Page Base
+ * tHE pHYIXCAL ADDRESS is both Base and Offset.
+ *
+ * Address Expansion Registers:
+ * logical Address A19..A14 I/O Address
+ * 0 FF00h
+ * 1 FF02h
+ * ... ...
+ * 63 FF7Eh
+ *
+ * Register XAM aliased with port # FF80h indicated current mode
+ * of operation.
+ * Format of XAM register (READ ONLY):
+ * 15..1 reserved
+ * 0 XA Flag, if=1 then in XA mode.
+ *
+ * Format of V53 PSW:
+ * 15..12 1
+ * 11 V
+ * 10 IYR
+ * 9 IE
+ * 8 BRK
+ * 7 S
+ * 6 Z
+ * 5 0
+ * 4 AC
+ * 3 0
+ * 2 P
+ * 1 1
+ * 0 CY
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form: BRKXA imm8
+ * COP (Code of Operation) : 0Fh E0h imm8
+ */
+
+ ModRM = FETCH;
+ logerror("PC=%06x : BRKXA %02x\n", activecpu_get_pc() - 3, ModRM);
+ nec_ICount -= 12;
+ break;
+
+ case 0xf0:
+ /*
+ * ----------O-RETXA----------------------------------
+ * OPCODE RETXA - Return from Expansion Address
+ *
+ * CPU: NEC V33/V53 only
+ * Type of Instruction: System
+ *
+ * Instruction: RETXA int_vector
+ *
+ * Description:
+ * [sp-1,sp-2] <- PSW ; PSW EQU FLAGS
+ * [sp-3,sp-4] <- PS ; PS EQU CS
+ * [sp-5,sp-6] <- PC ; PC EQU IP
+ * SP <- SP -6
+ * IE <- 0
+ * BRK <- 0
+ * MD <- 0
+ * PC <- [int_vector*4 +0,+1]
+ * PS <- [int_vector*4 +2,+3]
+ * Disable EA mode.
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form: RETXA imm8
+ * COP (Code of Operation) : 0Fh F0h imm8
+ *
+ * Clocks: 12
+ */
+ ModRM = FETCH;
+ logerror("PC=%06x : RETXA %02x\n", activecpu_get_pc() - 3, ModRM);
+ nec_ICount -= 12;
+ break;
+
+ case 0xff: /* 0F ff imm8 - BRKEM */
+ /*
+ * OPCODE BRKEM - Break for Emulation
+ *
+ * CPU: NEC/Sony V20/V30/V40/V50
+ * Description:
+ *
+ * PUSH FLAGS
+ * PUSH CS
+ * PUSH IP
+ * MOV CS,0:[intnum*4+2]
+ * MOV IP,0:[intnum*4]
+ * MD <- 0; // Enable 8080 emulation
+ *
+ * Note:
+ * BRKEM instruction do software interrupt and then New CS,IP loaded
+ * it switch to 8080 mode i.e. CPU will execute 8080 code.
+ * Mapping Table of Registers in 8080 Mode
+ * 8080 Md. A B C D E H L SP PC F
+ * native. AL CH CL DH DL BH BL BP IP FLAGS(low)
+ * For Return of 8080 mode use CALLN instruction.
+ * Note: I.e. 8080 addressing only 64KB then "Real Address" is CS*16+PC
+ *
+ * Flags Affected: MD
+ */
+ ModRM = FETCH;
+ nec_ICount -= 38;
+ logerror("PC=%06x : BRKEM %02x\n", activecpu_get_pc() - 3, ModRM);
+ PREFIXV30(_interrupt) (ModRM, 1);
+ break;
+ }
+}
+
+static void PREFIXV30(_brkn) (void) /* Opcode 0x63 BRKN - Break to Native Mode */
+{
+ /*
+ * CPU: NEC (V25/V35) Software Guard only
+ * Instruction: BRKN int_vector
+ *
+ * Description:
+ * [sp-1,sp-2] <- PSW ; PSW EQU FLAGS
+ * [sp-3,sp-4] <- PS ; PS EQU CS
+ * [sp-5,sp-6] <- PC ; PC EQU IP
+ * SP <- SP -6
+ * IE <- 0
+ * BRK <- 0
+ * MD <- 1
+ * PC <- [int_vector*4 +0,+1]
+ * PS <- [int_vector*4 +2,+3]
+ *
+ * Note: The BRKN instruction switches operations in Native Mode
+ * from Security Mode via Interrupt call. In Normal Mode
+ * Instruction executed as mPD70320/70322 (V25) operation mode.
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form: BRKN imm8
+ * COP (Code of Operation) : 63h imm8
+ *
+ * Clocks: 56+10T [44+10T]
+ */
+ /* nec_ICount-=56; */
+ unsigned int_vector;
+
+ int_vector = FETCH;
+ logerror("PC=%06x : BRKN %02x\n", activecpu_get_pc() - 2, int_vector);
+}
+
+static void PREFIXV30(repc) (int flagval)
+{
+ /* Handles repc- and repnc- prefixes. flagval is the value of ZF
+ * for the loop to continue for CMPS and SCAS instructions.
+ */
+
+ unsigned next = FETCHOP;
+ unsigned count = I.regs.w[CX];
+
+ switch (next)
+ {
+ case 0x26: /* ES: */
+ seg_prefix = TRUE;
+ prefix_base = I.base[ES];
+ nec_ICount -= 2;
+ PREFIXV30(repc) (flagval);
+ break;
+ case 0x2e: /* CS: */
+ seg_prefix = TRUE;
+ prefix_base = I.base[CS];
+ nec_ICount -= 2;
+ PREFIXV30(repc) (flagval);
+ break;
+ case 0x36: /* SS: */
+ seg_prefix = TRUE;
+ prefix_base = I.base[SS];
+ nec_ICount -= 2;
+ PREFIXV30(repc) (flagval);
+ break;
+ case 0x3e: /* DS: */
+ seg_prefix = TRUE;
+ prefix_base = I.base[DS];
+ nec_ICount -= 2;
+ PREFIXV30(repc) (flagval);
+ break;
+ case 0x6c: /* REP INSB */
+ nec_ICount -= 9 - count;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX186(_insb) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0x6d: /* REP INSW */
+ nec_ICount -= 9 - count;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX186(_insw) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0x6e: /* REP OUTSB */
+ nec_ICount -= 9 - count;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX186(_outsb) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0x6f: /* REP OUTSW */
+ nec_ICount -= 9 - count;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX186(_outsw) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xa4: /* REP MOVSB */
+ nec_ICount -= 9 - count;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX86(_movsb) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xa5: /* REP MOVSW */
+ nec_ICount -= 9 - count;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX86(_movsw) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xa6: /* REP(N)E CMPSB */
+ nec_ICount -= 9;
+ for (I.ZeroVal = !flagval; (ZF == flagval) && (CF == flagval) && (count > 0); count--)
+ PREFIX86(_cmpsb) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xa7: /* REP(N)E CMPSW */
+ nec_ICount -= 9;
+ for (I.ZeroVal = !flagval; (ZF == flagval) && (CF == flagval) && (count > 0); count--)
+ PREFIX86(_cmpsw) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xaa: /* REP STOSB */
+ nec_ICount -= 9 - count;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX86(_stosb) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xab: /* REP STOSW */
+ nec_ICount -= 9 - count;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX86(_stosw) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xac: /* REP LODSB */
+ nec_ICount -= 9;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX86(_lodsb) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xad: /* REP LODSW */
+ nec_ICount -= 9;
+ for (; (CF == flagval) && (count > 0); count--)
+ PREFIX86(_lodsw) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xae: /* REP(N)E SCASB */
+ nec_ICount -= 9;
+ for (I.ZeroVal = !flagval; (ZF == flagval) && (CF == flagval) && (count > 0); count--)
+ PREFIX86(_scasb) ();
+ I.regs.w[CX] = count;
+ break;
+ case 0xaf: /* REP(N)E SCASW */
+ nec_ICount -= 9;
+ for (I.ZeroVal = !flagval; (ZF == flagval) && (CF == flagval) && (count > 0); count--)
+ PREFIX86(_scasw) ();
+ I.regs.w[CX] = count;
+ break;
+ default:
+ PREFIXV30(_instruction)[next] ();
+ }
+}
+
+static void PREFIXV30(_repnc) (void) /* Opcode 0x64 */
+{
+ PREFIXV30(repc) (0);
+}
+
+static void PREFIXV30(_repc) (void) /* Opcode 0x65 */
+{
+ PREFIXV30(repc) (1);
+}
+
+static void PREFIXV30(_setalc) (void) /* Opcode 0xd6 */
+{
+ /*
+ * ----------O-SETALC---------------------------------
+ * OPCODE SETALC - Set AL to Carry Flag
+ *
+ * CPU: Intel 8086 and all its clones and upward
+ * compatibility chips.
+ * Type of Instruction: User
+ *
+ * Instruction: SETALC
+ *
+ * Description:
+ *
+ * IF (CF=0) THEN AL:=0 ELSE AL:=FFH;
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM,PM,VM,SMM
+ *
+ * Physical Form: SETALC
+ * COP (Code of Operation): D6H
+ * Clocks: 80286 : n/a [3]
+ * 80386 : n/a [3]
+ * Cx486SLC : n/a [2]
+ * i486 : n/a [3]
+ * Pentium : n/a [3]
+ * Note: n/a is Time that Intel etc not say.
+ * [3] is real time it executed.
+ *
+ */
+ I.regs.b[AL] = (CF) ? 0xff : 0x00;
+ nec_ICount -= 3; // V30
+ logerror("PC=%06x : SETALC\n", activecpu_get_pc() - 1);
+}
+
+#if 0
+static void PREFIXV30(_brks) (void) /* Opcode 0xf1 - Break to Security Mode */
+{
+ /*
+ * CPU: NEC (V25/V35) Software Guard only
+ * Instruction: BRKS int_vector
+ *
+ * Description:
+ * [sp-1,sp-2] <- PSW ; PSW EQU FLAGS
+ * [sp-3,sp-4] <- PS ; PS EQU CS
+ * [sp-5,sp-6] <- PC ; PC EQU IP
+ * SP <- SP -6
+ * IE <- 0
+ * BRK <- 0
+ * MD <- 0
+ * PC <- [int_vector*4 +0,+1]
+ * PS <- [int_vector*4 +2,+3]
+ *
+ * Note: The BRKS instruction switches operations in Security Mode
+ * via Interrupt call. In Security Mode the fetched operation
+ * code is executed after conversion in accordance with build-in
+ * translation table
+ *
+ * Flags Affected: None
+ *
+ * CPU mode: RM
+ *
+ * +++++++++++++++++++++++
+ * Physical Form: BRKS imm8
+ * Clocks: 56+10T [44+10T]
+ */
+ unsigned int_vector;
+
+ int_vector = FETCH;
+ logerror("PC=%06x : BRKS %02x\n", activecpu_get_pc() - 2, int_vector);
+}
+#endif
diff --git a/src/emu/cpu/i86/instrv30.h b/src/emu/cpu/i86/instrv30.h
new file mode 100644
index 00000000000..0647ae8d841
--- /dev/null
+++ b/src/emu/cpu/i86/instrv30.h
@@ -0,0 +1,7 @@
+static void PREFIXV30(_0fpre)(void);
+static void PREFIXV30(_repnc)(void);
+static void PREFIXV30(_repc)(void);
+static void PREFIXV30(_setalc)(void);
+#if 0
+static void PREFIXV30(_brks)(void);
+#endif
diff --git a/src/emu/cpu/i86/modrm.h b/src/emu/cpu/i86/modrm.h
new file mode 100644
index 00000000000..146ee13e348
--- /dev/null
+++ b/src/emu/cpu/i86/modrm.h
@@ -0,0 +1,118 @@
+static struct {
+ struct {
+ WREGS w[256];
+ BREGS b[256];
+ } reg;
+ struct {
+ WREGS w[256];
+ BREGS b[256];
+ } RM;
+} Mod_RM;
+
+#define RegWord(ModRM) I.regs.w[Mod_RM.reg.w[ModRM]]
+#define RegByte(ModRM) I.regs.b[Mod_RM.reg.b[ModRM]]
+
+#define GetRMWord(ModRM) \
+ ((ModRM) >= 0xc0 ? I.regs.w[Mod_RM.RM.w[ModRM]] : ( (*GetEA[ModRM])(), ReadWord( EA ) ))
+
+#define PutbackRMWord(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) I.regs.w[Mod_RM.RM.w[ModRM]]=val; \
+ else WriteWord(EA,val); \
+}
+
+#define GetnextRMWord ReadWord(EA+2)
+
+#define GetRMWordOffset(offs) \
+ ReadWord(EA-EO+(UINT16)(EO+offs))
+
+#define GetRMByteOffset(offs) \
+ ReadByte(EA-EO+(UINT16)(EO+offs))
+
+#define PutRMWord(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.w[Mod_RM.RM.w[ModRM]]=val; \
+ else { \
+ (*GetEA[ModRM])(); \
+ WriteWord( EA ,val); \
+ } \
+}
+
+#define PutRMWordOffset(offs, val) \
+ WriteWord( EA-EO+(UINT16)(EO+offs), val)
+
+#define PutRMByteOffset(offs, val) \
+ WriteByte( EA-EO+(UINT16)(EO+offs), val)
+
+#define PutImmRMWord(ModRM) \
+{ \
+ WORD val; \
+ if (ModRM >= 0xc0) \
+ FETCHWORD(I.regs.w[Mod_RM.RM.w[ModRM]]) \
+ else { \
+ (*GetEA[ModRM])(); \
+ FETCHWORD(val) \
+ WriteWord( EA , val); \
+ } \
+}
+
+#define GetRMByte(ModRM) \
+ ((ModRM) >= 0xc0 ? I.regs.b[Mod_RM.RM.b[ModRM]] : ReadByte( (*GetEA[ModRM])() ))
+
+#define PutRMByte(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.b[Mod_RM.RM.b[ModRM]]=val; \
+ else \
+ WriteByte( (*GetEA[ModRM])() ,val); \
+}
+
+#define PutImmRMByte(ModRM) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.b[Mod_RM.RM.b[ModRM]]=FETCH; \
+ else { \
+ (*GetEA[ModRM])(); \
+ WriteByte( EA , FETCH ); \
+ } \
+}
+
+#define PutbackRMByte(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.b[Mod_RM.RM.b[ModRM]]=val; \
+ else \
+ WriteByte(EA,val); \
+}
+
+#define DEF_br8(dst,src) \
+ unsigned ModRM = FETCHOP; \
+ unsigned src = RegByte(ModRM); \
+ unsigned dst = GetRMByte(ModRM)
+
+#define DEF_wr16(dst,src) \
+ unsigned ModRM = FETCHOP; \
+ unsigned src = RegWord(ModRM); \
+ unsigned dst = GetRMWord(ModRM)
+
+#define DEF_r8b(dst,src) \
+ unsigned ModRM = FETCHOP; \
+ unsigned dst = RegByte(ModRM); \
+ unsigned src = GetRMByte(ModRM)
+
+#define DEF_r16w(dst,src) \
+ unsigned ModRM = FETCHOP; \
+ unsigned dst = RegWord(ModRM); \
+ unsigned src = GetRMWord(ModRM)
+
+#define DEF_ald8(dst,src) \
+ unsigned src = FETCHOP; \
+ unsigned dst = I.regs.b[AL]
+
+#define DEF_axd16(dst,src) \
+ unsigned src = FETCHOP; \
+ unsigned dst = I.regs.w[AX]; \
+ src += (FETCH << 8)
+
+
diff --git a/src/emu/cpu/i86/table186.h b/src/emu/cpu/i86/table186.h
new file mode 100644
index 00000000000..5835d4fa21a
--- /dev/null
+++ b/src/emu/cpu/i86/table186.h
@@ -0,0 +1,525 @@
+static void (*PREFIX186(_instruction)[256])(void) =
+{
+ PREFIX86(_add_br8), /* 0x00 */
+ PREFIX86(_add_wr16), /* 0x01 */
+ PREFIX86(_add_r8b), /* 0x02 */
+ PREFIX86(_add_r16w), /* 0x03 */
+ PREFIX86(_add_ald8), /* 0x04 */
+ PREFIX86(_add_axd16), /* 0x05 */
+ PREFIX86(_push_es), /* 0x06 */
+ PREFIX86(_pop_es), /* 0x07 */
+ PREFIX86(_or_br8), /* 0x08 */
+ PREFIX86(_or_wr16), /* 0x09 */
+ PREFIX86(_or_r8b), /* 0x0a */
+ PREFIX86(_or_r16w), /* 0x0b */
+ PREFIX86(_or_ald8), /* 0x0c */
+ PREFIX86(_or_axd16), /* 0x0d */
+ PREFIX86(_push_cs), /* 0x0e */
+ PREFIX86(_invalid),
+ PREFIX86(_adc_br8), /* 0x10 */
+ PREFIX86(_adc_wr16), /* 0x11 */
+ PREFIX86(_adc_r8b), /* 0x12 */
+ PREFIX86(_adc_r16w), /* 0x13 */
+ PREFIX86(_adc_ald8), /* 0x14 */
+ PREFIX86(_adc_axd16), /* 0x15 */
+ PREFIX86(_push_ss), /* 0x16 */
+ PREFIX86(_pop_ss), /* 0x17 */
+ PREFIX86(_sbb_br8), /* 0x18 */
+ PREFIX86(_sbb_wr16), /* 0x19 */
+ PREFIX86(_sbb_r8b), /* 0x1a */
+ PREFIX86(_sbb_r16w), /* 0x1b */
+ PREFIX86(_sbb_ald8), /* 0x1c */
+ PREFIX86(_sbb_axd16), /* 0x1d */
+ PREFIX86(_push_ds), /* 0x1e */
+ PREFIX86(_pop_ds), /* 0x1f */
+ PREFIX86(_and_br8), /* 0x20 */
+ PREFIX86(_and_wr16), /* 0x21 */
+ PREFIX86(_and_r8b), /* 0x22 */
+ PREFIX86(_and_r16w), /* 0x23 */
+ PREFIX86(_and_ald8), /* 0x24 */
+ PREFIX86(_and_axd16), /* 0x25 */
+ PREFIX86(_es), /* 0x26 */
+ PREFIX86(_daa), /* 0x27 */
+ PREFIX86(_sub_br8), /* 0x28 */
+ PREFIX86(_sub_wr16), /* 0x29 */
+ PREFIX86(_sub_r8b), /* 0x2a */
+ PREFIX86(_sub_r16w), /* 0x2b */
+ PREFIX86(_sub_ald8), /* 0x2c */
+ PREFIX86(_sub_axd16), /* 0x2d */
+ PREFIX86(_cs), /* 0x2e */
+ PREFIX86(_das), /* 0x2f */
+ PREFIX86(_xor_br8), /* 0x30 */
+ PREFIX86(_xor_wr16), /* 0x31 */
+ PREFIX86(_xor_r8b), /* 0x32 */
+ PREFIX86(_xor_r16w), /* 0x33 */
+ PREFIX86(_xor_ald8), /* 0x34 */
+ PREFIX86(_xor_axd16), /* 0x35 */
+ PREFIX86(_ss), /* 0x36 */
+ PREFIX86(_aaa), /* 0x37 */
+ PREFIX86(_cmp_br8), /* 0x38 */
+ PREFIX86(_cmp_wr16), /* 0x39 */
+ PREFIX86(_cmp_r8b), /* 0x3a */
+ PREFIX86(_cmp_r16w), /* 0x3b */
+ PREFIX86(_cmp_ald8), /* 0x3c */
+ PREFIX86(_cmp_axd16), /* 0x3d */
+ PREFIX86(_ds), /* 0x3e */
+ PREFIX86(_aas), /* 0x3f */
+ PREFIX86(_inc_ax), /* 0x40 */
+ PREFIX86(_inc_cx), /* 0x41 */
+ PREFIX86(_inc_dx), /* 0x42 */
+ PREFIX86(_inc_bx), /* 0x43 */
+ PREFIX86(_inc_sp), /* 0x44 */
+ PREFIX86(_inc_bp), /* 0x45 */
+ PREFIX86(_inc_si), /* 0x46 */
+ PREFIX86(_inc_di), /* 0x47 */
+ PREFIX86(_dec_ax), /* 0x48 */
+ PREFIX86(_dec_cx), /* 0x49 */
+ PREFIX86(_dec_dx), /* 0x4a */
+ PREFIX86(_dec_bx), /* 0x4b */
+ PREFIX86(_dec_sp), /* 0x4c */
+ PREFIX86(_dec_bp), /* 0x4d */
+ PREFIX86(_dec_si), /* 0x4e */
+ PREFIX86(_dec_di), /* 0x4f */
+ PREFIX86(_push_ax), /* 0x50 */
+ PREFIX86(_push_cx), /* 0x51 */
+ PREFIX86(_push_dx), /* 0x52 */
+ PREFIX86(_push_bx), /* 0x53 */
+ PREFIX86(_push_sp), /* 0x54 */
+ PREFIX86(_push_bp), /* 0x55 */
+ PREFIX86(_push_si), /* 0x56 */
+ PREFIX86(_push_di), /* 0x57 */
+ PREFIX86(_pop_ax), /* 0x58 */
+ PREFIX86(_pop_cx), /* 0x59 */
+ PREFIX86(_pop_dx), /* 0x5a */
+ PREFIX86(_pop_bx), /* 0x5b */
+ PREFIX86(_pop_sp), /* 0x5c */
+ PREFIX86(_pop_bp), /* 0x5d */
+ PREFIX86(_pop_si), /* 0x5e */
+ PREFIX86(_pop_di), /* 0x5f */
+ PREFIX186(_pusha), /* 0x60 */
+ PREFIX186(_popa), /* 0x61 */
+ PREFIX186(_bound), /* 0x62 */
+ PREFIX86(_invalid),
+ PREFIX86(_invalid),
+ PREFIX86(_invalid),
+ PREFIX86(_invalid),
+ PREFIX86(_invalid),
+ PREFIX186(_push_d16), /* 0x68 */
+ PREFIX186(_imul_d16), /* 0x69 */
+ PREFIX186(_push_d8), /* 0x6a */
+ PREFIX186(_imul_d8), /* 0x6b */
+ PREFIX186(_insb), /* 0x6c */
+ PREFIX186(_insw), /* 0x6d */
+ PREFIX186(_outsb), /* 0x6e */
+ PREFIX186(_outsw), /* 0x6f */
+ PREFIX86(_jo), /* 0x70 */
+ PREFIX86(_jno), /* 0x71 */
+ PREFIX86(_jb), /* 0x72 */
+ PREFIX86(_jnb), /* 0x73 */
+ PREFIX86(_jz), /* 0x74 */
+ PREFIX86(_jnz), /* 0x75 */
+ PREFIX86(_jbe), /* 0x76 */
+ PREFIX86(_jnbe), /* 0x77 */
+ PREFIX86(_js), /* 0x78 */
+ PREFIX86(_jns), /* 0x79 */
+ PREFIX86(_jp), /* 0x7a */
+ PREFIX86(_jnp), /* 0x7b */
+ PREFIX86(_jl), /* 0x7c */
+ PREFIX86(_jnl), /* 0x7d */
+ PREFIX86(_jle), /* 0x7e */
+ PREFIX86(_jnle), /* 0x7f */
+ PREFIX86(_80pre), /* 0x80 */
+ PREFIX86(_81pre), /* 0x81 */
+ PREFIX86(_82pre), /* 0x82 */
+ PREFIX86(_83pre), /* 0x83 */
+ PREFIX86(_test_br8), /* 0x84 */
+ PREFIX86(_test_wr16), /* 0x85 */
+ PREFIX86(_xchg_br8), /* 0x86 */
+ PREFIX86(_xchg_wr16), /* 0x87 */
+ PREFIX86(_mov_br8), /* 0x88 */
+ PREFIX86(_mov_wr16), /* 0x89 */
+ PREFIX86(_mov_r8b), /* 0x8a */
+ PREFIX86(_mov_r16w), /* 0x8b */
+ PREFIX86(_mov_wsreg), /* 0x8c */
+ PREFIX86(_lea), /* 0x8d */
+ PREFIX86(_mov_sregw), /* 0x8e */
+ PREFIX86(_popw), /* 0x8f */
+ PREFIX86(_nop), /* 0x90 */
+ PREFIX86(_xchg_axcx), /* 0x91 */
+ PREFIX86(_xchg_axdx), /* 0x92 */
+ PREFIX86(_xchg_axbx), /* 0x93 */
+ PREFIX86(_xchg_axsp), /* 0x94 */
+ PREFIX86(_xchg_axbp), /* 0x95 */
+ PREFIX86(_xchg_axsi), /* 0x97 */
+ PREFIX86(_xchg_axdi), /* 0x97 */
+ PREFIX86(_cbw), /* 0x98 */
+ PREFIX86(_cwd), /* 0x99 */
+ PREFIX86(_call_far), /* 0x9a */
+ PREFIX86(_wait), /* 0x9b */
+ PREFIX86(_pushf), /* 0x9c */
+ PREFIX86(_popf), /* 0x9d */
+ PREFIX86(_sahf), /* 0x9e */
+ PREFIX86(_lahf), /* 0x9f */
+ PREFIX86(_mov_aldisp), /* 0xa0 */
+ PREFIX86(_mov_axdisp), /* 0xa1 */
+ PREFIX86(_mov_dispal), /* 0xa2 */
+ PREFIX86(_mov_dispax), /* 0xa3 */
+ PREFIX86(_movsb), /* 0xa4 */
+ PREFIX86(_movsw), /* 0xa5 */
+ PREFIX86(_cmpsb), /* 0xa6 */
+ PREFIX86(_cmpsw), /* 0xa7 */
+ PREFIX86(_test_ald8), /* 0xa8 */
+ PREFIX86(_test_axd16), /* 0xa9 */
+ PREFIX86(_stosb), /* 0xaa */
+ PREFIX86(_stosw), /* 0xab */
+ PREFIX86(_lodsb), /* 0xac */
+ PREFIX86(_lodsw), /* 0xad */
+ PREFIX86(_scasb), /* 0xae */
+ PREFIX86(_scasw), /* 0xaf */
+ PREFIX86(_mov_ald8), /* 0xb0 */
+ PREFIX86(_mov_cld8), /* 0xb1 */
+ PREFIX86(_mov_dld8), /* 0xb2 */
+ PREFIX86(_mov_bld8), /* 0xb3 */
+ PREFIX86(_mov_ahd8), /* 0xb4 */
+ PREFIX86(_mov_chd8), /* 0xb5 */
+ PREFIX86(_mov_dhd8), /* 0xb6 */
+ PREFIX86(_mov_bhd8), /* 0xb7 */
+ PREFIX86(_mov_axd16), /* 0xb8 */
+ PREFIX86(_mov_cxd16), /* 0xb9 */
+ PREFIX86(_mov_dxd16), /* 0xba */
+ PREFIX86(_mov_bxd16), /* 0xbb */
+ PREFIX86(_mov_spd16), /* 0xbc */
+ PREFIX86(_mov_bpd16), /* 0xbd */
+ PREFIX86(_mov_sid16), /* 0xbe */
+ PREFIX86(_mov_did16), /* 0xbf */
+ PREFIX186(_rotshft_bd8), /* 0xc0 */
+ PREFIX186(_rotshft_wd8), /* 0xc1 */
+ PREFIX86(_ret_d16), /* 0xc2 */
+ PREFIX86(_ret), /* 0xc3 */
+ PREFIX86(_les_dw), /* 0xc4 */
+ PREFIX86(_lds_dw), /* 0xc5 */
+ PREFIX86(_mov_bd8), /* 0xc6 */
+ PREFIX86(_mov_wd16), /* 0xc7 */
+ PREFIX186(_enter), /* 0xc8 */
+ PREFIX186(_leave), /* 0xc9 */
+ PREFIX86(_retf_d16), /* 0xca */
+ PREFIX86(_retf), /* 0xcb */
+ PREFIX86(_int3), /* 0xcc */
+ PREFIX86(_int), /* 0xcd */
+ PREFIX86(_into), /* 0xce */
+ PREFIX86(_iret), /* 0xcf */
+ PREFIX86(_rotshft_b), /* 0xd0 */
+ PREFIX86(_rotshft_w), /* 0xd1 */
+ PREFIX86(_rotshft_bcl), /* 0xd2 */
+ PREFIX86(_rotshft_wcl), /* 0xd3 */
+ PREFIX86(_aam), /* 0xd4 */
+ PREFIX86(_aad), /* 0xd5 */
+ PREFIX86(_invalid),
+ PREFIX86(_xlat), /* 0xd7 */
+ PREFIX86(_escape), /* 0xd8 */
+ PREFIX86(_escape), /* 0xd9 */
+ PREFIX86(_escape), /* 0xda */
+ PREFIX86(_escape), /* 0xdb */
+ PREFIX86(_escape), /* 0xdc */
+ PREFIX86(_escape), /* 0xdd */
+ PREFIX86(_escape), /* 0xde */
+ PREFIX86(_escape), /* 0xdf */
+ PREFIX86(_loopne), /* 0xe0 */
+ PREFIX86(_loope), /* 0xe1 */
+ PREFIX86(_loop), /* 0xe2 */
+ PREFIX86(_jcxz), /* 0xe3 */
+ PREFIX86(_inal), /* 0xe4 */
+ PREFIX86(_inax), /* 0xe5 */
+ PREFIX86(_outal), /* 0xe6 */
+ PREFIX86(_outax), /* 0xe7 */
+ PREFIX86(_call_d16), /* 0xe8 */
+ PREFIX86(_jmp_d16), /* 0xe9 */
+ PREFIX86(_jmp_far), /* 0xea */
+ PREFIX86(_jmp_d8), /* 0xeb */
+ PREFIX86(_inaldx), /* 0xec */
+ PREFIX86(_inaxdx), /* 0xed */
+ PREFIX86(_outdxal), /* 0xee */
+ PREFIX86(_outdxax), /* 0xef */
+ PREFIX86(_lock), /* 0xf0 */
+ PREFIX86(_invalid), /* 0xf1 */
+ PREFIX186(_repne), /* 0xf2 */
+ PREFIX186(_repe), /* 0xf3 */
+ PREFIX86(_hlt), /* 0xf4 */
+ PREFIX86(_cmc), /* 0xf5 */
+ PREFIX86(_f6pre), /* 0xf6 */
+ PREFIX86(_f7pre), /* 0xf7 */
+ PREFIX86(_clc), /* 0xf8 */
+ PREFIX86(_stc), /* 0xf9 */
+ PREFIX86(_cli), /* 0xfa */
+ PREFIX86(_sti), /* 0xfb */
+ PREFIX86(_cld), /* 0xfc */
+ PREFIX86(_std), /* 0xfd */
+ PREFIX86(_fepre), /* 0xfe */
+ PREFIX86(_ffpre) /* 0xff */
+};
+
+#if defined(BIGCASE) && !defined(RS6000)
+ /* Some compilers cannot handle large case statements */
+#define TABLE186 \
+ switch(FETCHOP)\
+ {\
+ case 0x00: PREFIX86(_add_br8)(); break;\
+ case 0x01: PREFIX86(_add_wr16)(); break;\
+ case 0x02: PREFIX86(_add_r8b)(); break;\
+ case 0x03: PREFIX86(_add_r16w)(); break;\
+ case 0x04: PREFIX86(_add_ald8)(); break;\
+ case 0x05: PREFIX86(_add_axd16)(); break;\
+ case 0x06: PREFIX86(_push_es)(); break;\
+ case 0x07: PREFIX86(_pop_es)(); break;\
+ case 0x08: PREFIX86(_or_br8)(); break;\
+ case 0x09: PREFIX86(_or_wr16)(); break;\
+ case 0x0a: PREFIX86(_or_r8b)(); break;\
+ case 0x0b: PREFIX86(_or_r16w)(); break;\
+ case 0x0c: PREFIX86(_or_ald8)(); break;\
+ case 0x0d: PREFIX86(_or_axd16)(); break;\
+ case 0x0e: PREFIX86(_push_cs)(); break;\
+ case 0x0f: PREFIX86(_invalid)(); break;\
+ case 0x10: PREFIX86(_adc_br8)(); break;\
+ case 0x11: PREFIX86(_adc_wr16)(); break;\
+ case 0x12: PREFIX86(_adc_r8b)(); break;\
+ case 0x13: PREFIX86(_adc_r16w)(); break;\
+ case 0x14: PREFIX86(_adc_ald8)(); break;\
+ case 0x15: PREFIX86(_adc_axd16)(); break;\
+ case 0x16: PREFIX86(_push_ss)(); break;\
+ case 0x17: PREFIX86(_pop_ss)(); break;\
+ case 0x18: PREFIX86(_sbb_br8)(); break;\
+ case 0x19: PREFIX86(_sbb_wr16)(); break;\
+ case 0x1a: PREFIX86(_sbb_r8b)(); break;\
+ case 0x1b: PREFIX86(_sbb_r16w)(); break;\
+ case 0x1c: PREFIX86(_sbb_ald8)(); break;\
+ case 0x1d: PREFIX86(_sbb_axd16)(); break;\
+ case 0x1e: PREFIX86(_push_ds)(); break;\
+ case 0x1f: PREFIX86(_pop_ds)(); break;\
+ case 0x20: PREFIX86(_and_br8)(); break;\
+ case 0x21: PREFIX86(_and_wr16)(); break;\
+ case 0x22: PREFIX86(_and_r8b)(); break;\
+ case 0x23: PREFIX86(_and_r16w)(); break;\
+ case 0x24: PREFIX86(_and_ald8)(); break;\
+ case 0x25: PREFIX86(_and_axd16)(); break;\
+ case 0x26: PREFIX86(_es)(); break;\
+ case 0x27: PREFIX86(_daa)(); break;\
+ case 0x28: PREFIX86(_sub_br8)(); break;\
+ case 0x29: PREFIX86(_sub_wr16)(); break;\
+ case 0x2a: PREFIX86(_sub_r8b)(); break;\
+ case 0x2b: PREFIX86(_sub_r16w)(); break;\
+ case 0x2c: PREFIX86(_sub_ald8)(); break;\
+ case 0x2d: PREFIX86(_sub_axd16)(); break;\
+ case 0x2e: PREFIX86(_cs)(); break;\
+ case 0x2f: PREFIX86(_das)(); break;\
+ case 0x30: PREFIX86(_xor_br8)(); break;\
+ case 0x31: PREFIX86(_xor_wr16)(); break;\
+ case 0x32: PREFIX86(_xor_r8b)(); break;\
+ case 0x33: PREFIX86(_xor_r16w)(); break;\
+ case 0x34: PREFIX86(_xor_ald8)(); break;\
+ case 0x35: PREFIX86(_xor_axd16)(); break;\
+ case 0x36: PREFIX86(_ss)(); break;\
+ case 0x37: PREFIX86(_aaa)(); break;\
+ case 0x38: PREFIX86(_cmp_br8)(); break;\
+ case 0x39: PREFIX86(_cmp_wr16)(); break;\
+ case 0x3a: PREFIX86(_cmp_r8b)(); break;\
+ case 0x3b: PREFIX86(_cmp_r16w)(); break;\
+ case 0x3c: PREFIX86(_cmp_ald8)(); break;\
+ case 0x3d: PREFIX86(_cmp_axd16)(); break;\
+ case 0x3e: PREFIX86(_ds)(); break;\
+ case 0x3f: PREFIX86(_aas)(); break;\
+ case 0x40: PREFIX86(_inc_ax)(); break;\
+ case 0x41: PREFIX86(_inc_cx)(); break;\
+ case 0x42: PREFIX86(_inc_dx)(); break;\
+ case 0x43: PREFIX86(_inc_bx)(); break;\
+ case 0x44: PREFIX86(_inc_sp)(); break;\
+ case 0x45: PREFIX86(_inc_bp)(); break;\
+ case 0x46: PREFIX86(_inc_si)(); break;\
+ case 0x47: PREFIX86(_inc_di)(); break;\
+ case 0x48: PREFIX86(_dec_ax)(); break;\
+ case 0x49: PREFIX86(_dec_cx)(); break;\
+ case 0x4a: PREFIX86(_dec_dx)(); break;\
+ case 0x4b: PREFIX86(_dec_bx)(); break;\
+ case 0x4c: PREFIX86(_dec_sp)(); break;\
+ case 0x4d: PREFIX86(_dec_bp)(); break;\
+ case 0x4e: PREFIX86(_dec_si)(); break;\
+ case 0x4f: PREFIX86(_dec_di)(); break;\
+ case 0x50: PREFIX86(_push_ax)(); break;\
+ case 0x51: PREFIX86(_push_cx)(); break;\
+ case 0x52: PREFIX86(_push_dx)(); break;\
+ case 0x53: PREFIX86(_push_bx)(); break;\
+ case 0x54: PREFIX86(_push_sp)(); break;\
+ case 0x55: PREFIX86(_push_bp)(); break;\
+ case 0x56: PREFIX86(_push_si)(); break;\
+ case 0x57: PREFIX86(_push_di)(); break;\
+ case 0x58: PREFIX86(_pop_ax)(); break;\
+ case 0x59: PREFIX86(_pop_cx)(); break;\
+ case 0x5a: PREFIX86(_pop_dx)(); break;\
+ case 0x5b: PREFIX86(_pop_bx)(); break;\
+ case 0x5c: PREFIX86(_pop_sp)(); break;\
+ case 0x5d: PREFIX86(_pop_bp)(); break;\
+ case 0x5e: PREFIX86(_pop_si)(); break;\
+ case 0x5f: PREFIX86(_pop_di)(); break;\
+ case 0x60: PREFIX186(_pusha)(); break;\
+ case 0x61: PREFIX186(_popa)(); break;\
+ case 0x62: PREFIX186(_bound)(); break;\
+ case 0x63: PREFIX86(_invalid)(); break;\
+ case 0x64: PREFIX86(_invalid)(); break;\
+ case 0x65: PREFIX86(_invalid)(); break;\
+ case 0x66: PREFIX86(_invalid)(); break;\
+ case 0x67: PREFIX86(_invalid)(); break;\
+ case 0x68: PREFIX186(_push_d16)(); break;\
+ case 0x69: PREFIX186(_imul_d16)(); break;\
+ case 0x6a: PREFIX186(_push_d8)(); break;\
+ case 0x6b: PREFIX186(_imul_d8)(); break;\
+ case 0x6c: PREFIX186(_insb)(); break;\
+ case 0x6d: PREFIX186(_insw)(); break;\
+ case 0x6e: PREFIX186(_outsb)(); break;\
+ case 0x6f: PREFIX186(_outsw)(); break;\
+ case 0x70: PREFIX86(_jo)(); break;\
+ case 0x71: PREFIX86(_jno)(); break;\
+ case 0x72: PREFIX86(_jb)(); break;\
+ case 0x73: PREFIX86(_jnb)(); break;\
+ case 0x74: PREFIX86(_jz)(); break;\
+ case 0x75: PREFIX86(_jnz)(); break;\
+ case 0x76: PREFIX86(_jbe)(); break;\
+ case 0x77: PREFIX86(_jnbe)(); break;\
+ case 0x78: PREFIX86(_js)(); break;\
+ case 0x79: PREFIX86(_jns)(); break;\
+ case 0x7a: PREFIX86(_jp)(); break;\
+ case 0x7b: PREFIX86(_jnp)(); break;\
+ case 0x7c: PREFIX86(_jl)(); break;\
+ case 0x7d: PREFIX86(_jnl)(); break;\
+ case 0x7e: PREFIX86(_jle)(); break;\
+ case 0x7f: PREFIX86(_jnle)(); break;\
+ case 0x80: PREFIX86(_80pre)(); break;\
+ case 0x81: PREFIX86(_81pre)(); break;\
+ case 0x82: PREFIX86(_82pre)(); break;\
+ case 0x83: PREFIX86(_83pre)(); break;\
+ case 0x84: PREFIX86(_test_br8)(); break;\
+ case 0x85: PREFIX86(_test_wr16)(); break;\
+ case 0x86: PREFIX86(_xchg_br8)(); break;\
+ case 0x87: PREFIX86(_xchg_wr16)(); break;\
+ case 0x88: PREFIX86(_mov_br8)(); break;\
+ case 0x89: PREFIX86(_mov_wr16)(); break;\
+ case 0x8a: PREFIX86(_mov_r8b)(); break;\
+ case 0x8b: PREFIX86(_mov_r16w)(); break;\
+ case 0x8c: PREFIX86(_mov_wsreg)(); break;\
+ case 0x8d: PREFIX86(_lea)(); break;\
+ case 0x8e: PREFIX86(_mov_sregw)(); break;\
+ case 0x8f: PREFIX86(_popw)(); break;\
+ case 0x90: PREFIX86(_nop)(); break;\
+ case 0x91: PREFIX86(_xchg_axcx)(); break;\
+ case 0x92: PREFIX86(_xchg_axdx)(); break;\
+ case 0x93: PREFIX86(_xchg_axbx)(); break;\
+ case 0x94: PREFIX86(_xchg_axsp)(); break;\
+ case 0x95: PREFIX86(_xchg_axbp)(); break;\
+ case 0x96: PREFIX86(_xchg_axsi)(); break;\
+ case 0x97: PREFIX86(_xchg_axdi)(); break;\
+ case 0x98: PREFIX86(_cbw)(); break;\
+ case 0x99: PREFIX86(_cwd)(); break;\
+ case 0x9a: PREFIX86(_call_far)(); break;\
+ case 0x9b: PREFIX86(_wait)(); break;\
+ case 0x9c: PREFIX86(_pushf)(); break;\
+ case 0x9d: PREFIX86(_popf)(); break;\
+ case 0x9e: PREFIX86(_sahf)(); break;\
+ case 0x9f: PREFIX86(_lahf)(); break;\
+ case 0xa0: PREFIX86(_mov_aldisp)(); break;\
+ case 0xa1: PREFIX86(_mov_axdisp)(); break;\
+ case 0xa2: PREFIX86(_mov_dispal)(); break;\
+ case 0xa3: PREFIX86(_mov_dispax)(); break;\
+ case 0xa4: PREFIX86(_movsb)(); break;\
+ case 0xa5: PREFIX86(_movsw)(); break;\
+ case 0xa6: PREFIX86(_cmpsb)(); break;\
+ case 0xa7: PREFIX86(_cmpsw)(); break;\
+ case 0xa8: PREFIX86(_test_ald8)(); break;\
+ case 0xa9: PREFIX86(_test_axd16)(); break;\
+ case 0xaa: PREFIX86(_stosb)(); break;\
+ case 0xab: PREFIX86(_stosw)(); break;\
+ case 0xac: PREFIX86(_lodsb)(); break;\
+ case 0xad: PREFIX86(_lodsw)(); break;\
+ case 0xae: PREFIX86(_scasb)(); break;\
+ case 0xaf: PREFIX86(_scasw)(); break;\
+ case 0xb0: PREFIX86(_mov_ald8)(); break;\
+ case 0xb1: PREFIX86(_mov_cld8)(); break;\
+ case 0xb2: PREFIX86(_mov_dld8)(); break;\
+ case 0xb3: PREFIX86(_mov_bld8)(); break;\
+ case 0xb4: PREFIX86(_mov_ahd8)(); break;\
+ case 0xb5: PREFIX86(_mov_chd8)(); break;\
+ case 0xb6: PREFIX86(_mov_dhd8)(); break;\
+ case 0xb7: PREFIX86(_mov_bhd8)(); break;\
+ case 0xb8: PREFIX86(_mov_axd16)(); break;\
+ case 0xb9: PREFIX86(_mov_cxd16)(); break;\
+ case 0xba: PREFIX86(_mov_dxd16)(); break;\
+ case 0xbb: PREFIX86(_mov_bxd16)(); break;\
+ case 0xbc: PREFIX86(_mov_spd16)(); break;\
+ case 0xbd: PREFIX86(_mov_bpd16)(); break;\
+ case 0xbe: PREFIX86(_mov_sid16)(); break;\
+ case 0xbf: PREFIX86(_mov_did16)(); break;\
+ case 0xc0: PREFIX186(_rotshft_bd8)(); break;\
+ case 0xc1: PREFIX186(_rotshft_wd8)(); break;\
+ case 0xc2: PREFIX86(_ret_d16)(); break;\
+ case 0xc3: PREFIX86(_ret)(); break;\
+ case 0xc4: PREFIX86(_les_dw)(); break;\
+ case 0xc5: PREFIX86(_lds_dw)(); break;\
+ case 0xc6: PREFIX86(_mov_bd8)(); break;\
+ case 0xc7: PREFIX86(_mov_wd16)(); break;\
+ case 0xc8: PREFIX186(_enter)(); break;\
+ case 0xc9: PREFIX186(_leave)(); break;\
+ case 0xca: PREFIX86(_retf_d16)(); break;\
+ case 0xcb: PREFIX86(_retf)(); break;\
+ case 0xcc: PREFIX86(_int3)(); break;\
+ case 0xcd: PREFIX86(_int)(); break;\
+ case 0xce: PREFIX86(_into)(); break;\
+ case 0xcf: PREFIX86(_iret)(); break;\
+ case 0xd0: PREFIX86(_rotshft_b)(); break;\
+ case 0xd1: PREFIX86(_rotshft_w)(); break;\
+ case 0xd2: PREFIX86(_rotshft_bcl)(); break;\
+ case 0xd3: PREFIX86(_rotshft_wcl)(); break;\
+ case 0xd4: PREFIX86(_aam)(); break;\
+ case 0xd5: PREFIX86(_aad)(); break;\
+ case 0xd6: PREFIX86(_invalid)(); break;\
+ case 0xd7: PREFIX86(_xlat)(); break;\
+ case 0xd8: PREFIX86(_escape)(); break;\
+ case 0xd9: PREFIX86(_escape)(); break;\
+ case 0xda: PREFIX86(_escape)(); break;\
+ case 0xdb: PREFIX86(_escape)(); break;\
+ case 0xdc: PREFIX86(_escape)(); break;\
+ case 0xdd: PREFIX86(_escape)(); break;\
+ case 0xde: PREFIX86(_escape)(); break;\
+ case 0xdf: PREFIX86(_escape)(); break;\
+ case 0xe0: PREFIX86(_loopne)(); break;\
+ case 0xe1: PREFIX86(_loope)(); break;\
+ case 0xe2: PREFIX86(_loop)(); break;\
+ case 0xe3: PREFIX86(_jcxz)(); break;\
+ case 0xe4: PREFIX86(_inal)(); break;\
+ case 0xe5: PREFIX86(_inax)(); break;\
+ case 0xe6: PREFIX86(_outal)(); break;\
+ case 0xe7: PREFIX86(_outax)(); break;\
+ case 0xe8: PREFIX86(_call_d16)(); break;\
+ case 0xe9: PREFIX86(_jmp_d16)(); break;\
+ case 0xea: PREFIX86(_jmp_far)(); break;\
+ case 0xeb: PREFIX86(_jmp_d8)(); break;\
+ case 0xec: PREFIX86(_inaldx)(); break;\
+ case 0xed: PREFIX86(_inaxdx)(); break;\
+ case 0xee: PREFIX86(_outdxal)(); break;\
+ case 0xef: PREFIX86(_outdxax)(); break;\
+ case 0xf0: PREFIX86(_lock)(); break;\
+ case 0xf1: PREFIX86(_invalid)(); break;\
+ case 0xf2: PREFIX186(_repne)(); break;\
+ case 0xf3: PREFIX186(_repe)(); break;\
+ case 0xf4: PREFIX86(_hlt)(); break;\
+ case 0xf5: PREFIX86(_cmc)(); break;\
+ case 0xf6: PREFIX86(_f6pre)(); break;\
+ case 0xf7: PREFIX86(_f7pre)(); break;\
+ case 0xf8: PREFIX86(_clc)(); break;\
+ case 0xf9: PREFIX86(_stc)(); break;\
+ case 0xfa: PREFIX86(_cli)(); break;\
+ case 0xfb: PREFIX86(_sti)(); break;\
+ case 0xfc: PREFIX86(_cld)(); break;\
+ case 0xfd: PREFIX86(_std)(); break;\
+ case 0xfe: PREFIX86(_fepre)(); break;\
+ case 0xff: PREFIX86(_ffpre)(); break;\
+ };
+#else
+#define TABLE186 PREFIX186(_instruction)[FETCHOP]();
+#endif
diff --git a/src/emu/cpu/i86/table286.h b/src/emu/cpu/i86/table286.h
new file mode 100644
index 00000000000..941c635fd62
--- /dev/null
+++ b/src/emu/cpu/i86/table286.h
@@ -0,0 +1,531 @@
+/*
+ * special 286 protected mode instructions missing
+ * at the time the same like table186.h
+ */
+
+static void (*PREFIX286(_instruction)[256])(void) =
+{
+ PREFIX86(_add_br8), /* 0x00 */
+ PREFIX86(_add_wr16), /* 0x01 */
+ PREFIX86(_add_r8b), /* 0x02 */
+ PREFIX86(_add_r16w), /* 0x03 */
+ PREFIX86(_add_ald8), /* 0x04 */
+ PREFIX86(_add_axd16), /* 0x05 */
+ PREFIX86(_push_es), /* 0x06 */
+ PREFIX86(_pop_es), /* 0x07 */
+ PREFIX86(_or_br8), /* 0x08 */
+ PREFIX86(_or_wr16), /* 0x09 */
+ PREFIX86(_or_r8b), /* 0x0a */
+ PREFIX86(_or_r16w), /* 0x0b */
+ PREFIX86(_or_ald8), /* 0x0c */
+ PREFIX86(_or_axd16), /* 0x0d */
+ PREFIX86(_push_cs), /* 0x0e */
+ PREFIX286(_0fpre),
+ PREFIX86(_adc_br8), /* 0x10 */
+ PREFIX86(_adc_wr16), /* 0x11 */
+ PREFIX86(_adc_r8b), /* 0x12 */
+ PREFIX86(_adc_r16w), /* 0x13 */
+ PREFIX86(_adc_ald8), /* 0x14 */
+ PREFIX86(_adc_axd16), /* 0x15 */
+ PREFIX86(_push_ss), /* 0x16 */
+ PREFIX86(_pop_ss), /* 0x17 */
+ PREFIX86(_sbb_br8), /* 0x18 */
+ PREFIX86(_sbb_wr16), /* 0x19 */
+ PREFIX86(_sbb_r8b), /* 0x1a */
+ PREFIX86(_sbb_r16w), /* 0x1b */
+ PREFIX86(_sbb_ald8), /* 0x1c */
+ PREFIX86(_sbb_axd16), /* 0x1d */
+ PREFIX86(_push_ds), /* 0x1e */
+ PREFIX86(_pop_ds), /* 0x1f */
+ PREFIX86(_and_br8), /* 0x20 */
+ PREFIX86(_and_wr16), /* 0x21 */
+ PREFIX86(_and_r8b), /* 0x22 */
+ PREFIX86(_and_r16w), /* 0x23 */
+ PREFIX86(_and_ald8), /* 0x24 */
+ PREFIX86(_and_axd16), /* 0x25 */
+ PREFIX86(_es), /* 0x26 */
+ PREFIX86(_daa), /* 0x27 */
+ PREFIX86(_sub_br8), /* 0x28 */
+ PREFIX86(_sub_wr16), /* 0x29 */
+ PREFIX86(_sub_r8b), /* 0x2a */
+ PREFIX86(_sub_r16w), /* 0x2b */
+ PREFIX86(_sub_ald8), /* 0x2c */
+ PREFIX86(_sub_axd16), /* 0x2d */
+ PREFIX86(_cs), /* 0x2e */
+ PREFIX86(_das), /* 0x2f */
+ PREFIX86(_xor_br8), /* 0x30 */
+ PREFIX86(_xor_wr16), /* 0x31 */
+ PREFIX86(_xor_r8b), /* 0x32 */
+ PREFIX86(_xor_r16w), /* 0x33 */
+ PREFIX86(_xor_ald8), /* 0x34 */
+ PREFIX86(_xor_axd16), /* 0x35 */
+ PREFIX86(_ss), /* 0x36 */
+ PREFIX86(_aaa), /* 0x37 */
+ PREFIX86(_cmp_br8), /* 0x38 */
+ PREFIX86(_cmp_wr16), /* 0x39 */
+ PREFIX86(_cmp_r8b), /* 0x3a */
+ PREFIX86(_cmp_r16w), /* 0x3b */
+ PREFIX86(_cmp_ald8), /* 0x3c */
+ PREFIX86(_cmp_axd16), /* 0x3d */
+ PREFIX86(_ds), /* 0x3e */
+ PREFIX86(_aas), /* 0x3f */
+ PREFIX86(_inc_ax), /* 0x40 */
+ PREFIX86(_inc_cx), /* 0x41 */
+ PREFIX86(_inc_dx), /* 0x42 */
+ PREFIX86(_inc_bx), /* 0x43 */
+ PREFIX86(_inc_sp), /* 0x44 */
+ PREFIX86(_inc_bp), /* 0x45 */
+ PREFIX86(_inc_si), /* 0x46 */
+ PREFIX86(_inc_di), /* 0x47 */
+ PREFIX86(_dec_ax), /* 0x48 */
+ PREFIX86(_dec_cx), /* 0x49 */
+ PREFIX86(_dec_dx), /* 0x4a */
+ PREFIX86(_dec_bx), /* 0x4b */
+ PREFIX86(_dec_sp), /* 0x4c */
+ PREFIX86(_dec_bp), /* 0x4d */
+ PREFIX86(_dec_si), /* 0x4e */
+ PREFIX86(_dec_di), /* 0x4f */
+ PREFIX86(_push_ax), /* 0x50 */
+ PREFIX86(_push_cx), /* 0x51 */
+ PREFIX86(_push_dx), /* 0x52 */
+ PREFIX86(_push_bx), /* 0x53 */
+ PREFIX86(_push_sp), /* 0x54 */
+ PREFIX86(_push_bp), /* 0x55 */
+ PREFIX86(_push_si), /* 0x56 */
+ PREFIX86(_push_di), /* 0x57 */
+ PREFIX86(_pop_ax), /* 0x58 */
+ PREFIX86(_pop_cx), /* 0x59 */
+ PREFIX86(_pop_dx), /* 0x5a */
+ PREFIX86(_pop_bx), /* 0x5b */
+ PREFIX86(_pop_sp), /* 0x5c */
+ PREFIX86(_pop_bp), /* 0x5d */
+ PREFIX86(_pop_si), /* 0x5e */
+ PREFIX86(_pop_di), /* 0x5f */
+ PREFIX186(_pusha), /* 0x60 */
+ PREFIX186(_popa), /* 0x61 */
+ PREFIX186(_bound), /* 0x62 */
+ PREFIX286(_arpl), /* 0x63 */
+ PREFIX286(_invalid),
+ PREFIX286(_invalid),
+ PREFIX286(_invalid),
+ PREFIX286(_invalid),
+ PREFIX186(_push_d16), /* 0x68 */
+ PREFIX186(_imul_d16), /* 0x69 */
+ PREFIX186(_push_d8), /* 0x6a */
+ PREFIX186(_imul_d8), /* 0x6b */
+ PREFIX186(_insb), /* 0x6c */
+ PREFIX186(_insw), /* 0x6d */
+ PREFIX186(_outsb), /* 0x6e */
+ PREFIX186(_outsw), /* 0x6f */
+ PREFIX86(_jo), /* 0x70 */
+ PREFIX86(_jno), /* 0x71 */
+ PREFIX86(_jb), /* 0x72 */
+ PREFIX86(_jnb), /* 0x73 */
+ PREFIX86(_jz), /* 0x74 */
+ PREFIX86(_jnz), /* 0x75 */
+ PREFIX86(_jbe), /* 0x76 */
+ PREFIX86(_jnbe), /* 0x77 */
+ PREFIX86(_js), /* 0x78 */
+ PREFIX86(_jns), /* 0x79 */
+ PREFIX86(_jp), /* 0x7a */
+ PREFIX86(_jnp), /* 0x7b */
+ PREFIX86(_jl), /* 0x7c */
+ PREFIX86(_jnl), /* 0x7d */
+ PREFIX86(_jle), /* 0x7e */
+ PREFIX86(_jnle), /* 0x7f */
+ PREFIX86(_80pre), /* 0x80 */
+ PREFIX86(_81pre), /* 0x81 */
+ PREFIX86(_82pre), /* 0x82 */
+ PREFIX86(_83pre), /* 0x83 */
+ PREFIX86(_test_br8), /* 0x84 */
+ PREFIX86(_test_wr16), /* 0x85 */
+ PREFIX86(_xchg_br8), /* 0x86 */
+ PREFIX86(_xchg_wr16), /* 0x87 */
+ PREFIX86(_mov_br8), /* 0x88 */
+ PREFIX86(_mov_wr16), /* 0x89 */
+ PREFIX86(_mov_r8b), /* 0x8a */
+ PREFIX86(_mov_r16w), /* 0x8b */
+ PREFIX86(_mov_wsreg), /* 0x8c */
+ PREFIX86(_lea), /* 0x8d */
+ PREFIX86(_mov_sregw), /* 0x8e */
+ PREFIX86(_popw), /* 0x8f */
+ PREFIX86(_nop), /* 0x90 */
+ PREFIX86(_xchg_axcx), /* 0x91 */
+ PREFIX86(_xchg_axdx), /* 0x92 */
+ PREFIX86(_xchg_axbx), /* 0x93 */
+ PREFIX86(_xchg_axsp), /* 0x94 */
+ PREFIX86(_xchg_axbp), /* 0x95 */
+ PREFIX86(_xchg_axsi), /* 0x97 */
+ PREFIX86(_xchg_axdi), /* 0x97 */
+ PREFIX86(_cbw), /* 0x98 */
+ PREFIX86(_cwd), /* 0x99 */
+ PREFIX86(_call_far), /* 0x9a */
+ PREFIX86(_wait), /* 0x9b */
+ PREFIX86(_pushf), /* 0x9c */
+ PREFIX86(_popf), /* 0x9d */
+ PREFIX86(_sahf), /* 0x9e */
+ PREFIX86(_lahf), /* 0x9f */
+ PREFIX86(_mov_aldisp), /* 0xa0 */
+ PREFIX86(_mov_axdisp), /* 0xa1 */
+ PREFIX86(_mov_dispal), /* 0xa2 */
+ PREFIX86(_mov_dispax), /* 0xa3 */
+ PREFIX86(_movsb), /* 0xa4 */
+ PREFIX86(_movsw), /* 0xa5 */
+ PREFIX86(_cmpsb), /* 0xa6 */
+ PREFIX86(_cmpsw), /* 0xa7 */
+ PREFIX86(_test_ald8), /* 0xa8 */
+ PREFIX86(_test_axd16), /* 0xa9 */
+ PREFIX86(_stosb), /* 0xaa */
+ PREFIX86(_stosw), /* 0xab */
+ PREFIX86(_lodsb), /* 0xac */
+ PREFIX86(_lodsw), /* 0xad */
+ PREFIX86(_scasb), /* 0xae */
+ PREFIX86(_scasw), /* 0xaf */
+ PREFIX86(_mov_ald8), /* 0xb0 */
+ PREFIX86(_mov_cld8), /* 0xb1 */
+ PREFIX86(_mov_dld8), /* 0xb2 */
+ PREFIX86(_mov_bld8), /* 0xb3 */
+ PREFIX86(_mov_ahd8), /* 0xb4 */
+ PREFIX86(_mov_chd8), /* 0xb5 */
+ PREFIX86(_mov_dhd8), /* 0xb6 */
+ PREFIX86(_mov_bhd8), /* 0xb7 */
+ PREFIX86(_mov_axd16), /* 0xb8 */
+ PREFIX86(_mov_cxd16), /* 0xb9 */
+ PREFIX86(_mov_dxd16), /* 0xba */
+ PREFIX86(_mov_bxd16), /* 0xbb */
+ PREFIX86(_mov_spd16), /* 0xbc */
+ PREFIX86(_mov_bpd16), /* 0xbd */
+ PREFIX86(_mov_sid16), /* 0xbe */
+ PREFIX86(_mov_did16), /* 0xbf */
+ PREFIX186(_rotshft_bd8), /* 0xc0 */
+ PREFIX186(_rotshft_wd8), /* 0xc1 */
+ PREFIX86(_ret_d16), /* 0xc2 */
+ PREFIX86(_ret), /* 0xc3 */
+ PREFIX86(_les_dw), /* 0xc4 */
+ PREFIX86(_lds_dw), /* 0xc5 */
+ PREFIX86(_mov_bd8), /* 0xc6 */
+ PREFIX86(_mov_wd16), /* 0xc7 */
+ PREFIX186(_enter), /* 0xc8 */
+ PREFIX186(_leave), /* 0xc9 */
+ PREFIX86(_retf_d16), /* 0xca */
+ PREFIX86(_retf), /* 0xcb */
+ PREFIX86(_int3), /* 0xcc */
+ PREFIX86(_int), /* 0xcd */
+ PREFIX86(_into), /* 0xce */
+ PREFIX86(_iret), /* 0xcf */
+ PREFIX86(_rotshft_b), /* 0xd0 */
+ PREFIX86(_rotshft_w), /* 0xd1 */
+ PREFIX86(_rotshft_bcl), /* 0xd2 */
+ PREFIX86(_rotshft_wcl), /* 0xd3 */
+ PREFIX86(_aam), /* 0xd4 */
+ PREFIX86(_aad), /* 0xd5 */
+ PREFIX286(_invalid),
+ PREFIX86(_xlat), /* 0xd7 */
+ PREFIX86(_escape), /* 0xd8 */
+ PREFIX86(_escape), /* 0xd9 */
+ PREFIX86(_escape), /* 0xda */
+ PREFIX86(_escape), /* 0xdb */
+ PREFIX86(_escape), /* 0xdc */
+ PREFIX86(_escape), /* 0xdd */
+ PREFIX86(_escape), /* 0xde */
+ PREFIX86(_escape), /* 0xdf */
+ PREFIX86(_loopne), /* 0xe0 */
+ PREFIX86(_loope), /* 0xe1 */
+ PREFIX86(_loop), /* 0xe2 */
+ PREFIX86(_jcxz), /* 0xe3 */
+ PREFIX86(_inal), /* 0xe4 */
+ PREFIX86(_inax), /* 0xe5 */
+ PREFIX86(_outal), /* 0xe6 */
+ PREFIX86(_outax), /* 0xe7 */
+ PREFIX86(_call_d16), /* 0xe8 */
+ PREFIX86(_jmp_d16), /* 0xe9 */
+ PREFIX86(_jmp_far), /* 0xea */
+ PREFIX86(_jmp_d8), /* 0xeb */
+ PREFIX86(_inaldx), /* 0xec */
+ PREFIX86(_inaxdx), /* 0xed */
+ PREFIX86(_outdxal), /* 0xee */
+ PREFIX86(_outdxax), /* 0xef */
+ PREFIX86(_lock), /* 0xf0 */
+ PREFIX286(_invalid), /* 0xf1 */
+ PREFIX186(_repne), /* 0xf2 */
+ PREFIX186(_repe), /* 0xf3 */
+ PREFIX86(_hlt), /* 0xf4 */
+ PREFIX86(_cmc), /* 0xf5 */
+ PREFIX86(_f6pre), /* 0xf6 */
+ PREFIX86(_f7pre), /* 0xf7 */
+ PREFIX86(_clc), /* 0xf8 */
+ PREFIX86(_stc), /* 0xf9 */
+ PREFIX86(_cli), /* 0xfa */
+ PREFIX86(_sti), /* 0xfb */
+ PREFIX86(_cld), /* 0xfc */
+ PREFIX86(_std), /* 0xfd */
+ PREFIX86(_fepre), /* 0xfe */
+ PREFIX86(_ffpre) /* 0xff */
+};
+
+#if defined(BIGCASE) && !defined(RS6000)
+ /* Some compilers cannot handle large case statements */
+#define TABLE286 \
+ switch(FETCHOP)\
+ {\
+ case 0x00: PREFIX86(_add_br8)(); break;\
+ case 0x01: PREFIX86(_add_wr16)(); break;\
+ case 0x02: PREFIX86(_add_r8b)(); break;\
+ case 0x03: PREFIX86(_add_r16w)(); break;\
+ case 0x04: PREFIX86(_add_ald8)(); break;\
+ case 0x05: PREFIX86(_add_axd16)(); break;\
+ case 0x06: PREFIX86(_push_es)(); break;\
+ case 0x07: PREFIX86(_pop_es)(); break;\
+ case 0x08: PREFIX86(_or_br8)(); break;\
+ case 0x09: PREFIX86(_or_wr16)(); break;\
+ case 0x0a: PREFIX86(_or_r8b)(); break;\
+ case 0x0b: PREFIX86(_or_r16w)(); break;\
+ case 0x0c: PREFIX86(_or_ald8)(); break;\
+ case 0x0d: PREFIX86(_or_axd16)(); break;\
+ case 0x0e: PREFIX86(_push_cs)(); break;\
+ case 0x0f: PREFIX286(_0fpre)(); break;\
+ case 0x10: PREFIX86(_adc_br8)(); break;\
+ case 0x11: PREFIX86(_adc_wr16)(); break;\
+ case 0x12: PREFIX86(_adc_r8b)(); break;\
+ case 0x13: PREFIX86(_adc_r16w)(); break;\
+ case 0x14: PREFIX86(_adc_ald8)(); break;\
+ case 0x15: PREFIX86(_adc_axd16)(); break;\
+ case 0x16: PREFIX86(_push_ss)(); break;\
+ case 0x17: PREFIX86(_pop_ss)(); break;\
+ case 0x18: PREFIX86(_sbb_br8)(); break;\
+ case 0x19: PREFIX86(_sbb_wr16)(); break;\
+ case 0x1a: PREFIX86(_sbb_r8b)(); break;\
+ case 0x1b: PREFIX86(_sbb_r16w)(); break;\
+ case 0x1c: PREFIX86(_sbb_ald8)(); break;\
+ case 0x1d: PREFIX86(_sbb_axd16)(); break;\
+ case 0x1e: PREFIX86(_push_ds)(); break;\
+ case 0x1f: PREFIX86(_pop_ds)(); break;\
+ case 0x20: PREFIX86(_and_br8)(); break;\
+ case 0x21: PREFIX86(_and_wr16)(); break;\
+ case 0x22: PREFIX86(_and_r8b)(); break;\
+ case 0x23: PREFIX86(_and_r16w)(); break;\
+ case 0x24: PREFIX86(_and_ald8)(); break;\
+ case 0x25: PREFIX86(_and_axd16)(); break;\
+ case 0x26: PREFIX86(_es)(); break;\
+ case 0x27: PREFIX86(_daa)(); break;\
+ case 0x28: PREFIX86(_sub_br8)(); break;\
+ case 0x29: PREFIX86(_sub_wr16)(); break;\
+ case 0x2a: PREFIX86(_sub_r8b)(); break;\
+ case 0x2b: PREFIX86(_sub_r16w)(); break;\
+ case 0x2c: PREFIX86(_sub_ald8)(); break;\
+ case 0x2d: PREFIX86(_sub_axd16)(); break;\
+ case 0x2e: PREFIX86(_cs)(); break;\
+ case 0x2f: PREFIX86(_das)(); break;\
+ case 0x30: PREFIX86(_xor_br8)(); break;\
+ case 0x31: PREFIX86(_xor_wr16)(); break;\
+ case 0x32: PREFIX86(_xor_r8b)(); break;\
+ case 0x33: PREFIX86(_xor_r16w)(); break;\
+ case 0x34: PREFIX86(_xor_ald8)(); break;\
+ case 0x35: PREFIX86(_xor_axd16)(); break;\
+ case 0x36: PREFIX86(_ss)(); break;\
+ case 0x37: PREFIX86(_aaa)(); break;\
+ case 0x38: PREFIX86(_cmp_br8)(); break;\
+ case 0x39: PREFIX86(_cmp_wr16)(); break;\
+ case 0x3a: PREFIX86(_cmp_r8b)(); break;\
+ case 0x3b: PREFIX86(_cmp_r16w)(); break;\
+ case 0x3c: PREFIX86(_cmp_ald8)(); break;\
+ case 0x3d: PREFIX86(_cmp_axd16)(); break;\
+ case 0x3e: PREFIX86(_ds)(); break;\
+ case 0x3f: PREFIX86(_aas)(); break;\
+ case 0x40: PREFIX86(_inc_ax)(); break;\
+ case 0x41: PREFIX86(_inc_cx)(); break;\
+ case 0x42: PREFIX86(_inc_dx)(); break;\
+ case 0x43: PREFIX86(_inc_bx)(); break;\
+ case 0x44: PREFIX86(_inc_sp)(); break;\
+ case 0x45: PREFIX86(_inc_bp)(); break;\
+ case 0x46: PREFIX86(_inc_si)(); break;\
+ case 0x47: PREFIX86(_inc_di)(); break;\
+ case 0x48: PREFIX86(_dec_ax)(); break;\
+ case 0x49: PREFIX86(_dec_cx)(); break;\
+ case 0x4a: PREFIX86(_dec_dx)(); break;\
+ case 0x4b: PREFIX86(_dec_bx)(); break;\
+ case 0x4c: PREFIX86(_dec_sp)(); break;\
+ case 0x4d: PREFIX86(_dec_bp)(); break;\
+ case 0x4e: PREFIX86(_dec_si)(); break;\
+ case 0x4f: PREFIX86(_dec_di)(); break;\
+ case 0x50: PREFIX86(_push_ax)(); break;\
+ case 0x51: PREFIX86(_push_cx)(); break;\
+ case 0x52: PREFIX86(_push_dx)(); break;\
+ case 0x53: PREFIX86(_push_bx)(); break;\
+ case 0x54: PREFIX86(_push_sp)(); break;\
+ case 0x55: PREFIX86(_push_bp)(); break;\
+ case 0x56: PREFIX86(_push_si)(); break;\
+ case 0x57: PREFIX86(_push_di)(); break;\
+ case 0x58: PREFIX86(_pop_ax)(); break;\
+ case 0x59: PREFIX86(_pop_cx)(); break;\
+ case 0x5a: PREFIX86(_pop_dx)(); break;\
+ case 0x5b: PREFIX86(_pop_bx)(); break;\
+ case 0x5c: PREFIX86(_pop_sp)(); break;\
+ case 0x5d: PREFIX86(_pop_bp)(); break;\
+ case 0x5e: PREFIX86(_pop_si)(); break;\
+ case 0x5f: PREFIX86(_pop_di)(); break;\
+ case 0x60: PREFIX186(_pusha)(); break;\
+ case 0x61: PREFIX186(_popa)(); break;\
+ case 0x62: PREFIX186(_bound)(); break;\
+ case 0x63: PREFIX286(_arpl)(); break;\
+ case 0x64: PREFIX286(_invalid)(); break;\
+ case 0x65: PREFIX286(_invalid)(); break;\
+ case 0x66: PREFIX286(_invalid)(); break;\
+ case 0x67: PREFIX286(_invalid)(); break;\
+ case 0x68: PREFIX186(_push_d16)(); break;\
+ case 0x69: PREFIX186(_imul_d16)(); break;\
+ case 0x6a: PREFIX186(_push_d8)(); break;\
+ case 0x6b: PREFIX186(_imul_d8)(); break;\
+ case 0x6c: PREFIX186(_insb)(); break;\
+ case 0x6d: PREFIX186(_insw)(); break;\
+ case 0x6e: PREFIX186(_outsb)(); break;\
+ case 0x6f: PREFIX186(_outsw)(); break;\
+ case 0x70: PREFIX86(_jo)(); break;\
+ case 0x71: PREFIX86(_jno)(); break;\
+ case 0x72: PREFIX86(_jb)(); break;\
+ case 0x73: PREFIX86(_jnb)(); break;\
+ case 0x74: PREFIX86(_jz)(); break;\
+ case 0x75: PREFIX86(_jnz)(); break;\
+ case 0x76: PREFIX86(_jbe)(); break;\
+ case 0x77: PREFIX86(_jnbe)(); break;\
+ case 0x78: PREFIX86(_js)(); break;\
+ case 0x79: PREFIX86(_jns)(); break;\
+ case 0x7a: PREFIX86(_jp)(); break;\
+ case 0x7b: PREFIX86(_jnp)(); break;\
+ case 0x7c: PREFIX86(_jl)(); break;\
+ case 0x7d: PREFIX86(_jnl)(); break;\
+ case 0x7e: PREFIX86(_jle)(); break;\
+ case 0x7f: PREFIX86(_jnle)(); break;\
+ case 0x80: PREFIX86(_80pre)(); break;\
+ case 0x81: PREFIX86(_81pre)(); break;\
+ case 0x82: PREFIX86(_82pre)(); break;\
+ case 0x83: PREFIX86(_83pre)(); break;\
+ case 0x84: PREFIX86(_test_br8)(); break;\
+ case 0x85: PREFIX86(_test_wr16)(); break;\
+ case 0x86: PREFIX86(_xchg_br8)(); break;\
+ case 0x87: PREFIX86(_xchg_wr16)(); break;\
+ case 0x88: PREFIX86(_mov_br8)(); break;\
+ case 0x89: PREFIX86(_mov_wr16)(); break;\
+ case 0x8a: PREFIX86(_mov_r8b)(); break;\
+ case 0x8b: PREFIX86(_mov_r16w)(); break;\
+ case 0x8c: PREFIX86(_mov_wsreg)(); break;\
+ case 0x8d: PREFIX86(_lea)(); break;\
+ case 0x8e: PREFIX86(_mov_sregw)(); break;\
+ case 0x8f: PREFIX86(_popw)(); break;\
+ case 0x90: PREFIX86(_nop)(); break;\
+ case 0x91: PREFIX86(_xchg_axcx)(); break;\
+ case 0x92: PREFIX86(_xchg_axdx)(); break;\
+ case 0x93: PREFIX86(_xchg_axbx)(); break;\
+ case 0x94: PREFIX86(_xchg_axsp)(); break;\
+ case 0x95: PREFIX86(_xchg_axbp)(); break;\
+ case 0x96: PREFIX86(_xchg_axsi)(); break;\
+ case 0x97: PREFIX86(_xchg_axdi)(); break;\
+ case 0x98: PREFIX86(_cbw)(); break;\
+ case 0x99: PREFIX86(_cwd)(); break;\
+ case 0x9a: PREFIX86(_call_far)(); break;\
+ case 0x9b: PREFIX86(_wait)(); break;\
+ case 0x9c: PREFIX86(_pushf)(); break;\
+ case 0x9d: PREFIX86(_popf)(); break;\
+ case 0x9e: PREFIX86(_sahf)(); break;\
+ case 0x9f: PREFIX86(_lahf)(); break;\
+ case 0xa0: PREFIX86(_mov_aldisp)(); break;\
+ case 0xa1: PREFIX86(_mov_axdisp)(); break;\
+ case 0xa2: PREFIX86(_mov_dispal)(); break;\
+ case 0xa3: PREFIX86(_mov_dispax)(); break;\
+ case 0xa4: PREFIX86(_movsb)(); break;\
+ case 0xa5: PREFIX86(_movsw)(); break;\
+ case 0xa6: PREFIX86(_cmpsb)(); break;\
+ case 0xa7: PREFIX86(_cmpsw)(); break;\
+ case 0xa8: PREFIX86(_test_ald8)(); break;\
+ case 0xa9: PREFIX86(_test_axd16)(); break;\
+ case 0xaa: PREFIX86(_stosb)(); break;\
+ case 0xab: PREFIX86(_stosw)(); break;\
+ case 0xac: PREFIX86(_lodsb)(); break;\
+ case 0xad: PREFIX86(_lodsw)(); break;\
+ case 0xae: PREFIX86(_scasb)(); break;\
+ case 0xaf: PREFIX86(_scasw)(); break;\
+ case 0xb0: PREFIX86(_mov_ald8)(); break;\
+ case 0xb1: PREFIX86(_mov_cld8)(); break;\
+ case 0xb2: PREFIX86(_mov_dld8)(); break;\
+ case 0xb3: PREFIX86(_mov_bld8)(); break;\
+ case 0xb4: PREFIX86(_mov_ahd8)(); break;\
+ case 0xb5: PREFIX86(_mov_chd8)(); break;\
+ case 0xb6: PREFIX86(_mov_dhd8)(); break;\
+ case 0xb7: PREFIX86(_mov_bhd8)(); break;\
+ case 0xb8: PREFIX86(_mov_axd16)(); break;\
+ case 0xb9: PREFIX86(_mov_cxd16)(); break;\
+ case 0xba: PREFIX86(_mov_dxd16)(); break;\
+ case 0xbb: PREFIX86(_mov_bxd16)(); break;\
+ case 0xbc: PREFIX86(_mov_spd16)(); break;\
+ case 0xbd: PREFIX86(_mov_bpd16)(); break;\
+ case 0xbe: PREFIX86(_mov_sid16)(); break;\
+ case 0xbf: PREFIX86(_mov_did16)(); break;\
+ case 0xc0: PREFIX186(_rotshft_bd8)(); break;\
+ case 0xc1: PREFIX186(_rotshft_wd8)(); break;\
+ case 0xc2: PREFIX86(_ret_d16)(); break;\
+ case 0xc3: PREFIX86(_ret)(); break;\
+ case 0xc4: PREFIX86(_les_dw)(); break;\
+ case 0xc5: PREFIX86(_lds_dw)(); break;\
+ case 0xc6: PREFIX86(_mov_bd8)(); break;\
+ case 0xc7: PREFIX86(_mov_wd16)(); break;\
+ case 0xc8: PREFIX186(_enter)(); break;\
+ case 0xc9: PREFIX186(_leave)(); break;\
+ case 0xca: PREFIX86(_retf_d16)(); break;\
+ case 0xcb: PREFIX86(_retf)(); break;\
+ case 0xcc: PREFIX86(_int3)(); break;\
+ case 0xcd: PREFIX86(_int)(); break;\
+ case 0xce: PREFIX86(_into)(); break;\
+ case 0xcf: PREFIX86(_iret)(); break;\
+ case 0xd0: PREFIX86(_rotshft_b)(); break;\
+ case 0xd1: PREFIX86(_rotshft_w)(); break;\
+ case 0xd2: PREFIX86(_rotshft_bcl)(); break;\
+ case 0xd3: PREFIX86(_rotshft_wcl)(); break;\
+ case 0xd4: PREFIX86(_aam)(); break;\
+ case 0xd5: PREFIX86(_aad)(); break;\
+ case 0xd6: PREFIX286(_invalid)(); break;\
+ case 0xd7: PREFIX86(_xlat)(); break;\
+ case 0xd8: PREFIX86(_escape)(); break;\
+ case 0xd9: PREFIX86(_escape)(); break;\
+ case 0xda: PREFIX86(_escape)(); break;\
+ case 0xdb: PREFIX86(_escape)(); break;\
+ case 0xdc: PREFIX86(_escape)(); break;\
+ case 0xdd: PREFIX86(_escape)(); break;\
+ case 0xde: PREFIX86(_escape)(); break;\
+ case 0xdf: PREFIX86(_escape)(); break;\
+ case 0xe0: PREFIX86(_loopne)(); break;\
+ case 0xe1: PREFIX86(_loope)(); break;\
+ case 0xe2: PREFIX86(_loop)(); break;\
+ case 0xe3: PREFIX86(_jcxz)(); break;\
+ case 0xe4: PREFIX86(_inal)(); break;\
+ case 0xe5: PREFIX86(_inax)(); break;\
+ case 0xe6: PREFIX86(_outal)(); break;\
+ case 0xe7: PREFIX86(_outax)(); break;\
+ case 0xe8: PREFIX86(_call_d16)(); break;\
+ case 0xe9: PREFIX86(_jmp_d16)(); break;\
+ case 0xea: PREFIX86(_jmp_far)(); break;\
+ case 0xeb: PREFIX86(_jmp_d8)(); break;\
+ case 0xec: PREFIX86(_inaldx)(); break;\
+ case 0xed: PREFIX86(_inaxdx)(); break;\
+ case 0xee: PREFIX86(_outdxal)(); break;\
+ case 0xef: PREFIX86(_outdxax)(); break;\
+ case 0xf0: PREFIX86(_lock)(); break;\
+ case 0xf1: PREFIX286(_invalid)(); break;\
+ case 0xf2: PREFIX186(_repne)(); break;\
+ case 0xf3: PREFIX186(_repe)(); break;\
+ case 0xf4: PREFIX86(_hlt)(); break;\
+ case 0xf5: PREFIX86(_cmc)(); break;\
+ case 0xf6: PREFIX86(_f6pre)(); break;\
+ case 0xf7: PREFIX86(_f7pre)(); break;\
+ case 0xf8: PREFIX86(_clc)(); break;\
+ case 0xf9: PREFIX86(_stc)(); break;\
+ case 0xfa: PREFIX86(_cli)(); break;\
+ case 0xfb: PREFIX86(_sti)(); break;\
+ case 0xfc: PREFIX86(_cld)(); break;\
+ case 0xfd: PREFIX86(_std)(); break;\
+ case 0xfe: PREFIX86(_fepre)(); break;\
+ case 0xff: PREFIX86(_ffpre)(); break;\
+ };
+#else
+#define TABLE286 PREFIX286(_instruction)[FETCHOP]();
+#endif
+
diff --git a/src/emu/cpu/i86/table86.h b/src/emu/cpu/i86/table86.h
new file mode 100644
index 00000000000..2acd4347477
--- /dev/null
+++ b/src/emu/cpu/i86/table86.h
@@ -0,0 +1,525 @@
+static void (*PREFIX86(_instruction)[256])(void) =
+{
+ PREFIX86(_add_br8), /* 0x00 */
+ PREFIX86(_add_wr16), /* 0x01 */
+ PREFIX86(_add_r8b), /* 0x02 */
+ PREFIX86(_add_r16w), /* 0x03 */
+ PREFIX86(_add_ald8), /* 0x04 */
+ PREFIX86(_add_axd16), /* 0x05 */
+ PREFIX86(_push_es), /* 0x06 */
+ PREFIX86(_pop_es), /* 0x07 */
+ PREFIX86(_or_br8), /* 0x08 */
+ PREFIX86(_or_wr16), /* 0x09 */
+ PREFIX86(_or_r8b), /* 0x0a */
+ PREFIX86(_or_r16w), /* 0x0b */
+ PREFIX86(_or_ald8), /* 0x0c */
+ PREFIX86(_or_axd16), /* 0x0d */
+ PREFIX86(_push_cs), /* 0x0e */
+ PREFIX86(_invalid),
+ PREFIX86(_adc_br8), /* 0x10 */
+ PREFIX86(_adc_wr16), /* 0x11 */
+ PREFIX86(_adc_r8b), /* 0x12 */
+ PREFIX86(_adc_r16w), /* 0x13 */
+ PREFIX86(_adc_ald8), /* 0x14 */
+ PREFIX86(_adc_axd16), /* 0x15 */
+ PREFIX86(_push_ss), /* 0x16 */
+ PREFIX86(_pop_ss), /* 0x17 */
+ PREFIX86(_sbb_br8), /* 0x18 */
+ PREFIX86(_sbb_wr16), /* 0x19 */
+ PREFIX86(_sbb_r8b), /* 0x1a */
+ PREFIX86(_sbb_r16w), /* 0x1b */
+ PREFIX86(_sbb_ald8), /* 0x1c */
+ PREFIX86(_sbb_axd16), /* 0x1d */
+ PREFIX86(_push_ds), /* 0x1e */
+ PREFIX86(_pop_ds), /* 0x1f */
+ PREFIX86(_and_br8), /* 0x20 */
+ PREFIX86(_and_wr16), /* 0x21 */
+ PREFIX86(_and_r8b), /* 0x22 */
+ PREFIX86(_and_r16w), /* 0x23 */
+ PREFIX86(_and_ald8), /* 0x24 */
+ PREFIX86(_and_axd16), /* 0x25 */
+ PREFIX86(_es), /* 0x26 */
+ PREFIX86(_daa), /* 0x27 */
+ PREFIX86(_sub_br8), /* 0x28 */
+ PREFIX86(_sub_wr16), /* 0x29 */
+ PREFIX86(_sub_r8b), /* 0x2a */
+ PREFIX86(_sub_r16w), /* 0x2b */
+ PREFIX86(_sub_ald8), /* 0x2c */
+ PREFIX86(_sub_axd16), /* 0x2d */
+ PREFIX86(_cs), /* 0x2e */
+ PREFIX86(_das), /* 0x2f */
+ PREFIX86(_xor_br8), /* 0x30 */
+ PREFIX86(_xor_wr16), /* 0x31 */
+ PREFIX86(_xor_r8b), /* 0x32 */
+ PREFIX86(_xor_r16w), /* 0x33 */
+ PREFIX86(_xor_ald8), /* 0x34 */
+ PREFIX86(_xor_axd16), /* 0x35 */
+ PREFIX86(_ss), /* 0x36 */
+ PREFIX86(_aaa), /* 0x37 */
+ PREFIX86(_cmp_br8), /* 0x38 */
+ PREFIX86(_cmp_wr16), /* 0x39 */
+ PREFIX86(_cmp_r8b), /* 0x3a */
+ PREFIX86(_cmp_r16w), /* 0x3b */
+ PREFIX86(_cmp_ald8), /* 0x3c */
+ PREFIX86(_cmp_axd16), /* 0x3d */
+ PREFIX86(_ds), /* 0x3e */
+ PREFIX86(_aas), /* 0x3f */
+ PREFIX86(_inc_ax), /* 0x40 */
+ PREFIX86(_inc_cx), /* 0x41 */
+ PREFIX86(_inc_dx), /* 0x42 */
+ PREFIX86(_inc_bx), /* 0x43 */
+ PREFIX86(_inc_sp), /* 0x44 */
+ PREFIX86(_inc_bp), /* 0x45 */
+ PREFIX86(_inc_si), /* 0x46 */
+ PREFIX86(_inc_di), /* 0x47 */
+ PREFIX86(_dec_ax), /* 0x48 */
+ PREFIX86(_dec_cx), /* 0x49 */
+ PREFIX86(_dec_dx), /* 0x4a */
+ PREFIX86(_dec_bx), /* 0x4b */
+ PREFIX86(_dec_sp), /* 0x4c */
+ PREFIX86(_dec_bp), /* 0x4d */
+ PREFIX86(_dec_si), /* 0x4e */
+ PREFIX86(_dec_di), /* 0x4f */
+ PREFIX86(_push_ax), /* 0x50 */
+ PREFIX86(_push_cx), /* 0x51 */
+ PREFIX86(_push_dx), /* 0x52 */
+ PREFIX86(_push_bx), /* 0x53 */
+ PREFIX86(_push_sp), /* 0x54 */
+ PREFIX86(_push_bp), /* 0x55 */
+ PREFIX86(_push_si), /* 0x56 */
+ PREFIX86(_push_di), /* 0x57 */
+ PREFIX86(_pop_ax), /* 0x58 */
+ PREFIX86(_pop_cx), /* 0x59 */
+ PREFIX86(_pop_dx), /* 0x5a */
+ PREFIX86(_pop_bx), /* 0x5b */
+ PREFIX86(_pop_sp), /* 0x5c */
+ PREFIX86(_pop_bp), /* 0x5d */
+ PREFIX86(_pop_si), /* 0x5e */
+ PREFIX86(_pop_di), /* 0x5f */
+ PREFIX86(_invalid), // PREFIX86(_pusha), /* 0x60 */
+ PREFIX86(_invalid), // PREFIX86(_popa), /* 0x61 */
+ PREFIX86(_invalid), // PREFIX86(_bound), /* 0x62 */
+ PREFIX86(_invalid),
+ PREFIX86(_invalid),
+ PREFIX86(_invalid),
+ PREFIX86(_invalid),
+ PREFIX86(_invalid),
+ PREFIX86(_invalid), //i_push_d16), /* 0x68 */
+ PREFIX86(_invalid), //i_imul_d16), /* 0x69 */
+ PREFIX86(_invalid), //i_push_d8), /* 0x6a */
+ PREFIX86(_invalid), //i_imul_d8), /* 0x6b */
+ PREFIX86(_invalid), //i_insb), /* 0x6c */
+ PREFIX86(_invalid), //i_insw), /* 0x6d */
+ PREFIX86(_invalid), //i_outsb), /* 0x6e */
+ PREFIX86(_invalid), //i_outsw), /* 0x6f */
+ PREFIX86(_jo), /* 0x70 */
+ PREFIX86(_jno), /* 0x71 */
+ PREFIX86(_jb), /* 0x72 */
+ PREFIX86(_jnb), /* 0x73 */
+ PREFIX86(_jz), /* 0x74 */
+ PREFIX86(_jnz), /* 0x75 */
+ PREFIX86(_jbe), /* 0x76 */
+ PREFIX86(_jnbe), /* 0x77 */
+ PREFIX86(_js), /* 0x78 */
+ PREFIX86(_jns), /* 0x79 */
+ PREFIX86(_jp), /* 0x7a */
+ PREFIX86(_jnp), /* 0x7b */
+ PREFIX86(_jl), /* 0x7c */
+ PREFIX86(_jnl), /* 0x7d */
+ PREFIX86(_jle), /* 0x7e */
+ PREFIX86(_jnle), /* 0x7f */
+ PREFIX86(_80pre), /* 0x80 */
+ PREFIX86(_81pre), /* 0x81 */
+ PREFIX86(_82pre), /* 0x82 */
+ PREFIX86(_83pre), /* 0x83 */
+ PREFIX86(_test_br8), /* 0x84 */
+ PREFIX86(_test_wr16), /* 0x85 */
+ PREFIX86(_xchg_br8), /* 0x86 */
+ PREFIX86(_xchg_wr16), /* 0x87 */
+ PREFIX86(_mov_br8), /* 0x88 */
+ PREFIX86(_mov_wr16), /* 0x89 */
+ PREFIX86(_mov_r8b), /* 0x8a */
+ PREFIX86(_mov_r16w), /* 0x8b */
+ PREFIX86(_mov_wsreg), /* 0x8c */
+ PREFIX86(_lea), /* 0x8d */
+ PREFIX86(_mov_sregw), /* 0x8e */
+ PREFIX86(_popw), /* 0x8f */
+ PREFIX86(_nop), /* 0x90 */
+ PREFIX86(_xchg_axcx), /* 0x91 */
+ PREFIX86(_xchg_axdx), /* 0x92 */
+ PREFIX86(_xchg_axbx), /* 0x93 */
+ PREFIX86(_xchg_axsp), /* 0x94 */
+ PREFIX86(_xchg_axbp), /* 0x95 */
+ PREFIX86(_xchg_axsi), /* 0x97 */
+ PREFIX86(_xchg_axdi), /* 0x97 */
+ PREFIX86(_cbw), /* 0x98 */
+ PREFIX86(_cwd), /* 0x99 */
+ PREFIX86(_call_far), /* 0x9a */
+ PREFIX86(_wait), /* 0x9b */
+ PREFIX86(_pushf), /* 0x9c */
+ PREFIX86(_popf), /* 0x9d */
+ PREFIX86(_sahf), /* 0x9e */
+ PREFIX86(_lahf), /* 0x9f */
+ PREFIX86(_mov_aldisp), /* 0xa0 */
+ PREFIX86(_mov_axdisp), /* 0xa1 */
+ PREFIX86(_mov_dispal), /* 0xa2 */
+ PREFIX86(_mov_dispax), /* 0xa3 */
+ PREFIX86(_movsb), /* 0xa4 */
+ PREFIX86(_movsw), /* 0xa5 */
+ PREFIX86(_cmpsb), /* 0xa6 */
+ PREFIX86(_cmpsw), /* 0xa7 */
+ PREFIX86(_test_ald8), /* 0xa8 */
+ PREFIX86(_test_axd16), /* 0xa9 */
+ PREFIX86(_stosb), /* 0xaa */
+ PREFIX86(_stosw), /* 0xab */
+ PREFIX86(_lodsb), /* 0xac */
+ PREFIX86(_lodsw), /* 0xad */
+ PREFIX86(_scasb), /* 0xae */
+ PREFIX86(_scasw), /* 0xaf */
+ PREFIX86(_mov_ald8), /* 0xb0 */
+ PREFIX86(_mov_cld8), /* 0xb1 */
+ PREFIX86(_mov_dld8), /* 0xb2 */
+ PREFIX86(_mov_bld8), /* 0xb3 */
+ PREFIX86(_mov_ahd8), /* 0xb4 */
+ PREFIX86(_mov_chd8), /* 0xb5 */
+ PREFIX86(_mov_dhd8), /* 0xb6 */
+ PREFIX86(_mov_bhd8), /* 0xb7 */
+ PREFIX86(_mov_axd16), /* 0xb8 */
+ PREFIX86(_mov_cxd16), /* 0xb9 */
+ PREFIX86(_mov_dxd16), /* 0xba */
+ PREFIX86(_mov_bxd16), /* 0xbb */
+ PREFIX86(_mov_spd16), /* 0xbc */
+ PREFIX86(_mov_bpd16), /* 0xbd */
+ PREFIX86(_mov_sid16), /* 0xbe */
+ PREFIX86(_mov_did16), /* 0xbf */
+ PREFIX86(_invalid), // PREFIX86(_rotshft_bd8), /* 0xc0 */
+ PREFIX86(_invalid), // PREFIX86(_rotshft_wd8), /* 0xc1 */
+ PREFIX86(_ret_d16), /* 0xc2 */
+ PREFIX86(_ret), /* 0xc3 */
+ PREFIX86(_les_dw), /* 0xc4 */
+ PREFIX86(_lds_dw), /* 0xc5 */
+ PREFIX86(_mov_bd8), /* 0xc6 */
+ PREFIX86(_mov_wd16), /* 0xc7 */
+ PREFIX86(_invalid), //i_enter), /* 0xc8 */
+ PREFIX86(_invalid), //leave), /* 0xc9 */
+ PREFIX86(_retf_d16), /* 0xca */
+ PREFIX86(_retf), /* 0xcb */
+ PREFIX86(_int3), /* 0xcc */
+ PREFIX86(_int), /* 0xcd */
+ PREFIX86(_into), /* 0xce */
+ PREFIX86(_iret), /* 0xcf */
+ PREFIX86(_rotshft_b), /* 0xd0 */
+ PREFIX86(_rotshft_w), /* 0xd1 */
+ PREFIX86(_rotshft_bcl), /* 0xd2 */
+ PREFIX86(_rotshft_wcl), /* 0xd3 */
+ PREFIX86(_aam), /* 0xd4 */
+ PREFIX86(_aad), /* 0xd5 */
+ PREFIX86(_invalid),
+ PREFIX86(_xlat), /* 0xd7 */
+ PREFIX86(_escape), /* 0xd8 */
+ PREFIX86(_escape), /* 0xd9 */
+ PREFIX86(_escape), /* 0xda */
+ PREFIX86(_escape), /* 0xdb */
+ PREFIX86(_escape), /* 0xdc */
+ PREFIX86(_escape), /* 0xdd */
+ PREFIX86(_escape), /* 0xde */
+ PREFIX86(_escape), /* 0xdf */
+ PREFIX86(_loopne), /* 0xe0 */
+ PREFIX86(_loope), /* 0xe1 */
+ PREFIX86(_loop), /* 0xe2 */
+ PREFIX86(_jcxz), /* 0xe3 */
+ PREFIX86(_inal), /* 0xe4 */
+ PREFIX86(_inax), /* 0xe5 */
+ PREFIX86(_outal), /* 0xe6 */
+ PREFIX86(_outax), /* 0xe7 */
+ PREFIX86(_call_d16), /* 0xe8 */
+ PREFIX86(_jmp_d16), /* 0xe9 */
+ PREFIX86(_jmp_far), /* 0xea */
+ PREFIX86(_jmp_d8), /* 0xeb */
+ PREFIX86(_inaldx), /* 0xec */
+ PREFIX86(_inaxdx), /* 0xed */
+ PREFIX86(_outdxal), /* 0xee */
+ PREFIX86(_outdxax), /* 0xef */
+ PREFIX86(_lock), /* 0xf0 */
+ PREFIX86(_invalid), /* 0xf1 */
+ PREFIX86(_repne), /* 0xf2 */
+ PREFIX86(_repe), /* 0xf3 */
+ PREFIX86(_hlt), /* 0xf4 */
+ PREFIX86(_cmc), /* 0xf5 */
+ PREFIX86(_f6pre), /* 0xf6 */
+ PREFIX86(_f7pre), /* 0xf7 */
+ PREFIX86(_clc), /* 0xf8 */
+ PREFIX86(_stc), /* 0xf9 */
+ PREFIX86(_cli), /* 0xfa */
+ PREFIX86(_sti), /* 0xfb */
+ PREFIX86(_cld), /* 0xfc */
+ PREFIX86(_std), /* 0xfd */
+ PREFIX86(_fepre), /* 0xfe */
+ PREFIX86(_ffpre) /* 0xff */
+};
+
+#if defined(BIGCASE) && !defined(RS6000)
+ /* Some compilers cannot handle large case statements */
+#define TABLE86 \
+ switch(FETCHOP)\
+ {\
+ case 0x00: PREFIX86(_add_br8)(); break;\
+ case 0x01: PREFIX86(_add_wr16)(); break;\
+ case 0x02: PREFIX86(_add_r8b)(); break;\
+ case 0x03: PREFIX86(_add_r16w)(); break;\
+ case 0x04: PREFIX86(_add_ald8)(); break;\
+ case 0x05: PREFIX86(_add_axd16)(); break;\
+ case 0x06: PREFIX86(_push_es)(); break;\
+ case 0x07: PREFIX86(_pop_es)(); break;\
+ case 0x08: PREFIX86(_or_br8)(); break;\
+ case 0x09: PREFIX86(_or_wr16)(); break;\
+ case 0x0a: PREFIX86(_or_r8b)(); break;\
+ case 0x0b: PREFIX86(_or_r16w)(); break;\
+ case 0x0c: PREFIX86(_or_ald8)(); break;\
+ case 0x0d: PREFIX86(_or_axd16)(); break;\
+ case 0x0e: PREFIX86(_push_cs)(); break;\
+ case 0x0f: PREFIX86(_invalid)(); break;\
+ case 0x10: PREFIX86(_adc_br8)(); break;\
+ case 0x11: PREFIX86(_adc_wr16)(); break;\
+ case 0x12: PREFIX86(_adc_r8b)(); break;\
+ case 0x13: PREFIX86(_adc_r16w)(); break;\
+ case 0x14: PREFIX86(_adc_ald8)(); break;\
+ case 0x15: PREFIX86(_adc_axd16)(); break;\
+ case 0x16: PREFIX86(_push_ss)(); break;\
+ case 0x17: PREFIX86(_pop_ss)(); break;\
+ case 0x18: PREFIX86(_sbb_br8)(); break;\
+ case 0x19: PREFIX86(_sbb_wr16)(); break;\
+ case 0x1a: PREFIX86(_sbb_r8b)(); break;\
+ case 0x1b: PREFIX86(_sbb_r16w)(); break;\
+ case 0x1c: PREFIX86(_sbb_ald8)(); break;\
+ case 0x1d: PREFIX86(_sbb_axd16)(); break;\
+ case 0x1e: PREFIX86(_push_ds)(); break;\
+ case 0x1f: PREFIX86(_pop_ds)(); break;\
+ case 0x20: PREFIX86(_and_br8)(); break;\
+ case 0x21: PREFIX86(_and_wr16)(); break;\
+ case 0x22: PREFIX86(_and_r8b)(); break;\
+ case 0x23: PREFIX86(_and_r16w)(); break;\
+ case 0x24: PREFIX86(_and_ald8)(); break;\
+ case 0x25: PREFIX86(_and_axd16)(); break;\
+ case 0x26: PREFIX86(_es)(); break;\
+ case 0x27: PREFIX86(_daa)(); break;\
+ case 0x28: PREFIX86(_sub_br8)(); break;\
+ case 0x29: PREFIX86(_sub_wr16)(); break;\
+ case 0x2a: PREFIX86(_sub_r8b)(); break;\
+ case 0x2b: PREFIX86(_sub_r16w)(); break;\
+ case 0x2c: PREFIX86(_sub_ald8)(); break;\
+ case 0x2d: PREFIX86(_sub_axd16)(); break;\
+ case 0x2e: PREFIX86(_cs)(); break;\
+ case 0x2f: PREFIX86(_das)(); break;\
+ case 0x30: PREFIX86(_xor_br8)(); break;\
+ case 0x31: PREFIX86(_xor_wr16)(); break;\
+ case 0x32: PREFIX86(_xor_r8b)(); break;\
+ case 0x33: PREFIX86(_xor_r16w)(); break;\
+ case 0x34: PREFIX86(_xor_ald8)(); break;\
+ case 0x35: PREFIX86(_xor_axd16)(); break;\
+ case 0x36: PREFIX86(_ss)(); break;\
+ case 0x37: PREFIX86(_aaa)(); break;\
+ case 0x38: PREFIX86(_cmp_br8)(); break;\
+ case 0x39: PREFIX86(_cmp_wr16)(); break;\
+ case 0x3a: PREFIX86(_cmp_r8b)(); break;\
+ case 0x3b: PREFIX86(_cmp_r16w)(); break;\
+ case 0x3c: PREFIX86(_cmp_ald8)(); break;\
+ case 0x3d: PREFIX86(_cmp_axd16)(); break;\
+ case 0x3e: PREFIX86(_ds)(); break;\
+ case 0x3f: PREFIX86(_aas)(); break;\
+ case 0x40: PREFIX86(_inc_ax)(); break;\
+ case 0x41: PREFIX86(_inc_cx)(); break;\
+ case 0x42: PREFIX86(_inc_dx)(); break;\
+ case 0x43: PREFIX86(_inc_bx)(); break;\
+ case 0x44: PREFIX86(_inc_sp)(); break;\
+ case 0x45: PREFIX86(_inc_bp)(); break;\
+ case 0x46: PREFIX86(_inc_si)(); break;\
+ case 0x47: PREFIX86(_inc_di)(); break;\
+ case 0x48: PREFIX86(_dec_ax)(); break;\
+ case 0x49: PREFIX86(_dec_cx)(); break;\
+ case 0x4a: PREFIX86(_dec_dx)(); break;\
+ case 0x4b: PREFIX86(_dec_bx)(); break;\
+ case 0x4c: PREFIX86(_dec_sp)(); break;\
+ case 0x4d: PREFIX86(_dec_bp)(); break;\
+ case 0x4e: PREFIX86(_dec_si)(); break;\
+ case 0x4f: PREFIX86(_dec_di)(); break;\
+ case 0x50: PREFIX86(_push_ax)(); break;\
+ case 0x51: PREFIX86(_push_cx)(); break;\
+ case 0x52: PREFIX86(_push_dx)(); break;\
+ case 0x53: PREFIX86(_push_bx)(); break;\
+ case 0x54: PREFIX86(_push_sp)(); break;\
+ case 0x55: PREFIX86(_push_bp)(); break;\
+ case 0x56: PREFIX86(_push_si)(); break;\
+ case 0x57: PREFIX86(_push_di)(); break;\
+ case 0x58: PREFIX86(_pop_ax)(); break;\
+ case 0x59: PREFIX86(_pop_cx)(); break;\
+ case 0x5a: PREFIX86(_pop_dx)(); break;\
+ case 0x5b: PREFIX86(_pop_bx)(); break;\
+ case 0x5c: PREFIX86(_pop_sp)(); break;\
+ case 0x5d: PREFIX86(_pop_bp)(); break;\
+ case 0x5e: PREFIX86(_pop_si)(); break;\
+ case 0x5f: PREFIX86(_pop_di)(); break;\
+ case 0x60: PREFIX86(_invalid)(); break;\
+ case 0x61: PREFIX86(_invalid)(); break;\
+ case 0x62: PREFIX86(_invalid)(); break;\
+ case 0x63: PREFIX86(_invalid)(); break;\
+ case 0x64: PREFIX86(_invalid)(); break;\
+ case 0x65: PREFIX86(_invalid)(); break;\
+ case 0x66: PREFIX86(_invalid)(); break;\
+ case 0x67: PREFIX86(_invalid)(); break;\
+ case 0x68: PREFIX86(_invalid)(); break;\
+ case 0x69: PREFIX86(_invalid)(); break;\
+ case 0x6a: PREFIX86(_invalid)(); break;\
+ case 0x6b: PREFIX86(_invalid)(); break;\
+ case 0x6c: PREFIX86(_invalid)(); break;\
+ case 0x6d: PREFIX86(_invalid)(); break;\
+ case 0x6e: PREFIX86(_invalid)(); break;\
+ case 0x6f: PREFIX86(_invalid)(); break;\
+ case 0x70: PREFIX86(_jo)(); break;\
+ case 0x71: PREFIX86(_jno)(); break;\
+ case 0x72: PREFIX86(_jb)(); break;\
+ case 0x73: PREFIX86(_jnb)(); break;\
+ case 0x74: PREFIX86(_jz)(); break;\
+ case 0x75: PREFIX86(_jnz)(); break;\
+ case 0x76: PREFIX86(_jbe)(); break;\
+ case 0x77: PREFIX86(_jnbe)(); break;\
+ case 0x78: PREFIX86(_js)(); break;\
+ case 0x79: PREFIX86(_jns)(); break;\
+ case 0x7a: PREFIX86(_jp)(); break;\
+ case 0x7b: PREFIX86(_jnp)(); break;\
+ case 0x7c: PREFIX86(_jl)(); break;\
+ case 0x7d: PREFIX86(_jnl)(); break;\
+ case 0x7e: PREFIX86(_jle)(); break;\
+ case 0x7f: PREFIX86(_jnle)(); break;\
+ case 0x80: PREFIX86(_80pre)(); break;\
+ case 0x81: PREFIX86(_81pre)(); break;\
+ case 0x82: PREFIX86(_82pre)(); break;\
+ case 0x83: PREFIX86(_83pre)(); break;\
+ case 0x84: PREFIX86(_test_br8)(); break;\
+ case 0x85: PREFIX86(_test_wr16)(); break;\
+ case 0x86: PREFIX86(_xchg_br8)(); break;\
+ case 0x87: PREFIX86(_xchg_wr16)(); break;\
+ case 0x88: PREFIX86(_mov_br8)(); break;\
+ case 0x89: PREFIX86(_mov_wr16)(); break;\
+ case 0x8a: PREFIX86(_mov_r8b)(); break;\
+ case 0x8b: PREFIX86(_mov_r16w)(); break;\
+ case 0x8c: PREFIX86(_mov_wsreg)(); break;\
+ case 0x8d: PREFIX86(_lea)(); break;\
+ case 0x8e: PREFIX86(_mov_sregw)(); break;\
+ case 0x8f: PREFIX86(_popw)(); break;\
+ case 0x90: PREFIX86(_nop)(); break;\
+ case 0x91: PREFIX86(_xchg_axcx)(); break;\
+ case 0x92: PREFIX86(_xchg_axdx)(); break;\
+ case 0x93: PREFIX86(_xchg_axbx)(); break;\
+ case 0x94: PREFIX86(_xchg_axsp)(); break;\
+ case 0x95: PREFIX86(_xchg_axbp)(); break;\
+ case 0x96: PREFIX86(_xchg_axsi)(); break;\
+ case 0x97: PREFIX86(_xchg_axdi)(); break;\
+ case 0x98: PREFIX86(_cbw)(); break;\
+ case 0x99: PREFIX86(_cwd)(); break;\
+ case 0x9a: PREFIX86(_call_far)(); break;\
+ case 0x9b: PREFIX86(_wait)(); break;\
+ case 0x9c: PREFIX86(_pushf)(); break;\
+ case 0x9d: PREFIX86(_popf)(); break;\
+ case 0x9e: PREFIX86(_sahf)(); break;\
+ case 0x9f: PREFIX86(_lahf)(); break;\
+ case 0xa0: PREFIX86(_mov_aldisp)(); break;\
+ case 0xa1: PREFIX86(_mov_axdisp)(); break;\
+ case 0xa2: PREFIX86(_mov_dispal)(); break;\
+ case 0xa3: PREFIX86(_mov_dispax)(); break;\
+ case 0xa4: PREFIX86(_movsb)(); break;\
+ case 0xa5: PREFIX86(_movsw)(); break;\
+ case 0xa6: PREFIX86(_cmpsb)(); break;\
+ case 0xa7: PREFIX86(_cmpsw)(); break;\
+ case 0xa8: PREFIX86(_test_ald8)(); break;\
+ case 0xa9: PREFIX86(_test_axd16)(); break;\
+ case 0xaa: PREFIX86(_stosb)(); break;\
+ case 0xab: PREFIX86(_stosw)(); break;\
+ case 0xac: PREFIX86(_lodsb)(); break;\
+ case 0xad: PREFIX86(_lodsw)(); break;\
+ case 0xae: PREFIX86(_scasb)(); break;\
+ case 0xaf: PREFIX86(_scasw)(); break;\
+ case 0xb0: PREFIX86(_mov_ald8)(); break;\
+ case 0xb1: PREFIX86(_mov_cld8)(); break;\
+ case 0xb2: PREFIX86(_mov_dld8)(); break;\
+ case 0xb3: PREFIX86(_mov_bld8)(); break;\
+ case 0xb4: PREFIX86(_mov_ahd8)(); break;\
+ case 0xb5: PREFIX86(_mov_chd8)(); break;\
+ case 0xb6: PREFIX86(_mov_dhd8)(); break;\
+ case 0xb7: PREFIX86(_mov_bhd8)(); break;\
+ case 0xb8: PREFIX86(_mov_axd16)(); break;\
+ case 0xb9: PREFIX86(_mov_cxd16)(); break;\
+ case 0xba: PREFIX86(_mov_dxd16)(); break;\
+ case 0xbb: PREFIX86(_mov_bxd16)(); break;\
+ case 0xbc: PREFIX86(_mov_spd16)(); break;\
+ case 0xbd: PREFIX86(_mov_bpd16)(); break;\
+ case 0xbe: PREFIX86(_mov_sid16)(); break;\
+ case 0xbf: PREFIX86(_mov_did16)(); break;\
+ case 0xc0: PREFIX86(_invalid)(); break;\
+ case 0xc1: PREFIX86(_invalid)(); break;\
+ case 0xc2: PREFIX86(_ret_d16)(); break;\
+ case 0xc3: PREFIX86(_ret)(); break;\
+ case 0xc4: PREFIX86(_les_dw)(); break;\
+ case 0xc5: PREFIX86(_lds_dw)(); break;\
+ case 0xc6: PREFIX86(_mov_bd8)(); break;\
+ case 0xc7: PREFIX86(_mov_wd16)(); break;\
+ case 0xc8: PREFIX86(_invalid)(); break;\
+ case 0xc9: PREFIX86(_invalid)(); break;\
+ case 0xca: PREFIX86(_retf_d16)(); break;\
+ case 0xcb: PREFIX86(_retf)(); break;\
+ case 0xcc: PREFIX86(_int3)(); break;\
+ case 0xcd: PREFIX86(_int)(); break;\
+ case 0xce: PREFIX86(_into)(); break;\
+ case 0xcf: PREFIX86(_iret)(); break;\
+ case 0xd0: PREFIX86(_rotshft_b)(); break;\
+ case 0xd1: PREFIX86(_rotshft_w)(); break;\
+ case 0xd2: PREFIX86(_rotshft_bcl)(); break;\
+ case 0xd3: PREFIX86(_rotshft_wcl)(); break;\
+ case 0xd4: PREFIX86(_aam)(); break;\
+ case 0xd5: PREFIX86(_aad)(); break;\
+ case 0xd6: PREFIX86(_invalid)(); break;\
+ case 0xd7: PREFIX86(_xlat)(); break;\
+ case 0xd8: PREFIX86(_escape)(); break;\
+ case 0xd9: PREFIX86(_escape)(); break;\
+ case 0xda: PREFIX86(_escape)(); break;\
+ case 0xdb: PREFIX86(_escape)(); break;\
+ case 0xdc: PREFIX86(_escape)(); break;\
+ case 0xdd: PREFIX86(_escape)(); break;\
+ case 0xde: PREFIX86(_escape)(); break;\
+ case 0xdf: PREFIX86(_escape)(); break;\
+ case 0xe0: PREFIX86(_loopne)(); break;\
+ case 0xe1: PREFIX86(_loope)(); break;\
+ case 0xe2: PREFIX86(_loop)(); break;\
+ case 0xe3: PREFIX86(_jcxz)(); break;\
+ case 0xe4: PREFIX86(_inal)(); break;\
+ case 0xe5: PREFIX86(_inax)(); break;\
+ case 0xe6: PREFIX86(_outal)(); break;\
+ case 0xe7: PREFIX86(_outax)(); break;\
+ case 0xe8: PREFIX86(_call_d16)(); break;\
+ case 0xe9: PREFIX86(_jmp_d16)(); break;\
+ case 0xea: PREFIX86(_jmp_far)(); break;\
+ case 0xeb: PREFIX86(_jmp_d8)(); break;\
+ case 0xec: PREFIX86(_inaldx)(); break;\
+ case 0xed: PREFIX86(_inaxdx)(); break;\
+ case 0xee: PREFIX86(_outdxal)(); break;\
+ case 0xef: PREFIX86(_outdxax)(); break;\
+ case 0xf0: PREFIX86(_lock)(); break;\
+ case 0xf1: PREFIX86(_invalid)(); break;\
+ case 0xf2: PREFIX86(_repne)(); break;\
+ case 0xf3: PREFIX86(_repe)(); break;\
+ case 0xf4: PREFIX86(_hlt)(); break;\
+ case 0xf5: PREFIX86(_cmc)(); break;\
+ case 0xf6: PREFIX86(_f6pre)(); break;\
+ case 0xf7: PREFIX86(_f7pre)(); break;\
+ case 0xf8: PREFIX86(_clc)(); break;\
+ case 0xf9: PREFIX86(_stc)(); break;\
+ case 0xfa: PREFIX86(_cli)(); break;\
+ case 0xfb: PREFIX86(_sti)(); break;\
+ case 0xfc: PREFIX86(_cld)(); break;\
+ case 0xfd: PREFIX86(_std)(); break;\
+ case 0xfe: PREFIX86(_fepre)(); break;\
+ case 0xff: PREFIX86(_ffpre)(); break;\
+ };
+#else
+#define TABLE86 PREFIX86(_instruction)[FETCHOP]();
+#endif
diff --git a/src/emu/cpu/i86/tablev30.h b/src/emu/cpu/i86/tablev30.h
new file mode 100644
index 00000000000..25a5cb0f226
--- /dev/null
+++ b/src/emu/cpu/i86/tablev30.h
@@ -0,0 +1,528 @@
+// special nec instructions missing
+// at the time the same like table186.h
+
+static void (*PREFIXV30(_instruction)[256])(void) =
+{
+ PREFIX86(_add_br8), /* 0x00 */
+ PREFIX86(_add_wr16), /* 0x01 */
+ PREFIX86(_add_r8b), /* 0x02 */
+ PREFIX86(_add_r16w), /* 0x03 */
+ PREFIX86(_add_ald8), /* 0x04 */
+ PREFIX86(_add_axd16), /* 0x05 */
+ PREFIX86(_push_es), /* 0x06 */
+ PREFIX86(_pop_es), /* 0x07 */
+ PREFIX86(_or_br8), /* 0x08 */
+ PREFIX86(_or_wr16), /* 0x09 */
+ PREFIX86(_or_r8b), /* 0x0a */
+ PREFIX86(_or_r16w), /* 0x0b */
+ PREFIX86(_or_ald8), /* 0x0c */
+ PREFIX86(_or_axd16), /* 0x0d */
+ PREFIX86(_push_cs), /* 0x0e */
+ PREFIXV30(_0fpre),
+ PREFIX86(_adc_br8), /* 0x10 */
+ PREFIX86(_adc_wr16), /* 0x11 */
+ PREFIX86(_adc_r8b), /* 0x12 */
+ PREFIX86(_adc_r16w), /* 0x13 */
+ PREFIX86(_adc_ald8), /* 0x14 */
+ PREFIX86(_adc_axd16), /* 0x15 */
+ PREFIX86(_push_ss), /* 0x16 */
+ PREFIX86(_pop_ss), /* 0x17 */
+ PREFIX86(_sbb_br8), /* 0x18 */
+ PREFIX86(_sbb_wr16), /* 0x19 */
+ PREFIX86(_sbb_r8b), /* 0x1a */
+ PREFIX86(_sbb_r16w), /* 0x1b */
+ PREFIX86(_sbb_ald8), /* 0x1c */
+ PREFIX86(_sbb_axd16), /* 0x1d */
+ PREFIX86(_push_ds), /* 0x1e */
+ PREFIX86(_pop_ds), /* 0x1f */
+ PREFIX86(_and_br8), /* 0x20 */
+ PREFIX86(_and_wr16), /* 0x21 */
+ PREFIX86(_and_r8b), /* 0x22 */
+ PREFIX86(_and_r16w), /* 0x23 */
+ PREFIX86(_and_ald8), /* 0x24 */
+ PREFIX86(_and_axd16), /* 0x25 */
+ PREFIX86(_es), /* 0x26 */
+ PREFIX86(_daa), /* 0x27 */
+ PREFIX86(_sub_br8), /* 0x28 */
+ PREFIX86(_sub_wr16), /* 0x29 */
+ PREFIX86(_sub_r8b), /* 0x2a */
+ PREFIX86(_sub_r16w), /* 0x2b */
+ PREFIX86(_sub_ald8), /* 0x2c */
+ PREFIX86(_sub_axd16), /* 0x2d */
+ PREFIX86(_cs), /* 0x2e */
+ PREFIX86(_das), /* 0x2f */
+ PREFIX86(_xor_br8), /* 0x30 */
+ PREFIX86(_xor_wr16), /* 0x31 */
+ PREFIX86(_xor_r8b), /* 0x32 */
+ PREFIX86(_xor_r16w), /* 0x33 */
+ PREFIX86(_xor_ald8), /* 0x34 */
+ PREFIX86(_xor_axd16), /* 0x35 */
+ PREFIX86(_ss), /* 0x36 */
+ PREFIX86(_aaa), /* 0x37 */
+ PREFIX86(_cmp_br8), /* 0x38 */
+ PREFIX86(_cmp_wr16), /* 0x39 */
+ PREFIX86(_cmp_r8b), /* 0x3a */
+ PREFIX86(_cmp_r16w), /* 0x3b */
+ PREFIX86(_cmp_ald8), /* 0x3c */
+ PREFIX86(_cmp_axd16), /* 0x3d */
+ PREFIX86(_ds), /* 0x3e */
+ PREFIX86(_aas), /* 0x3f */
+ PREFIX86(_inc_ax), /* 0x40 */
+ PREFIX86(_inc_cx), /* 0x41 */
+ PREFIX86(_inc_dx), /* 0x42 */
+ PREFIX86(_inc_bx), /* 0x43 */
+ PREFIX86(_inc_sp), /* 0x44 */
+ PREFIX86(_inc_bp), /* 0x45 */
+ PREFIX86(_inc_si), /* 0x46 */
+ PREFIX86(_inc_di), /* 0x47 */
+ PREFIX86(_dec_ax), /* 0x48 */
+ PREFIX86(_dec_cx), /* 0x49 */
+ PREFIX86(_dec_dx), /* 0x4a */
+ PREFIX86(_dec_bx), /* 0x4b */
+ PREFIX86(_dec_sp), /* 0x4c */
+ PREFIX86(_dec_bp), /* 0x4d */
+ PREFIX86(_dec_si), /* 0x4e */
+ PREFIX86(_dec_di), /* 0x4f */
+ PREFIX86(_push_ax), /* 0x50 */
+ PREFIX86(_push_cx), /* 0x51 */
+ PREFIX86(_push_dx), /* 0x52 */
+ PREFIX86(_push_bx), /* 0x53 */
+ PREFIX86(_push_sp), /* 0x54 */
+ PREFIX86(_push_bp), /* 0x55 */
+ PREFIX86(_push_si), /* 0x56 */
+ PREFIX86(_push_di), /* 0x57 */
+ PREFIX86(_pop_ax), /* 0x58 */
+ PREFIX86(_pop_cx), /* 0x59 */
+ PREFIX86(_pop_dx), /* 0x5a */
+ PREFIX86(_pop_bx), /* 0x5b */
+ PREFIX86(_pop_sp), /* 0x5c */
+ PREFIX86(_pop_bp), /* 0x5d */
+ PREFIX86(_pop_si), /* 0x5e */
+ PREFIX86(_pop_di), /* 0x5f */
+ PREFIX186(_pusha), /* 0x60 */
+ PREFIX186(_popa), /* 0x61 */
+ PREFIX186(_bound), /* 0x62 */
+ PREFIX86(_invalid),
+ PREFIXV30(_repnc),
+ PREFIXV30(_repc),
+ PREFIX86(_invalid),
+ PREFIX86(_invalid),
+ PREFIX186(_push_d16), /* 0x68 */
+ PREFIX186(_imul_d16), /* 0x69 */
+ PREFIX186(_push_d8), /* 0x6a */
+ PREFIX186(_imul_d8), /* 0x6b */
+ PREFIX186(_insb), /* 0x6c */
+ PREFIX186(_insw), /* 0x6d */
+ PREFIX186(_outsb), /* 0x6e */
+ PREFIX186(_outsw), /* 0x6f */
+ PREFIX86(_jo), /* 0x70 */
+ PREFIX86(_jno), /* 0x71 */
+ PREFIX86(_jb), /* 0x72 */
+ PREFIX86(_jnb), /* 0x73 */
+ PREFIX86(_jz), /* 0x74 */
+ PREFIX86(_jnz), /* 0x75 */
+ PREFIX86(_jbe), /* 0x76 */
+ PREFIX86(_jnbe), /* 0x77 */
+ PREFIX86(_js), /* 0x78 */
+ PREFIX86(_jns), /* 0x79 */
+ PREFIX86(_jp), /* 0x7a */
+ PREFIX86(_jnp), /* 0x7b */
+ PREFIX86(_jl), /* 0x7c */
+ PREFIX86(_jnl), /* 0x7d */
+ PREFIX86(_jle), /* 0x7e */
+ PREFIX86(_jnle), /* 0x7f */
+ PREFIX86(_80pre), /* 0x80 */
+ PREFIX86(_81pre), /* 0x81 */
+ PREFIX86(_82pre), /* 0x82 */
+ PREFIX86(_83pre), /* 0x83 */
+ PREFIX86(_test_br8), /* 0x84 */
+ PREFIX86(_test_wr16), /* 0x85 */
+ PREFIX86(_xchg_br8), /* 0x86 */
+ PREFIX86(_xchg_wr16), /* 0x87 */
+ PREFIX86(_mov_br8), /* 0x88 */
+ PREFIX86(_mov_wr16), /* 0x89 */
+ PREFIX86(_mov_r8b), /* 0x8a */
+ PREFIX86(_mov_r16w), /* 0x8b */
+ PREFIX86(_mov_wsreg), /* 0x8c */
+ PREFIX86(_lea), /* 0x8d */
+ PREFIX86(_mov_sregw), /* 0x8e */
+ PREFIX86(_popw), /* 0x8f */
+ PREFIX86(_nop), /* 0x90 */
+ PREFIX86(_xchg_axcx), /* 0x91 */
+ PREFIX86(_xchg_axdx), /* 0x92 */
+ PREFIX86(_xchg_axbx), /* 0x93 */
+ PREFIX86(_xchg_axsp), /* 0x94 */
+ PREFIX86(_xchg_axbp), /* 0x95 */
+ PREFIX86(_xchg_axsi), /* 0x97 */
+ PREFIX86(_xchg_axdi), /* 0x97 */
+ PREFIX86(_cbw), /* 0x98 */
+ PREFIX86(_cwd), /* 0x99 */
+ PREFIX86(_call_far), /* 0x9a */
+ PREFIX86(_wait), /* 0x9b */
+ PREFIXV30(_pushf), /* 0x9c */
+ PREFIX86(_popf), /* 0x9d */
+ PREFIX86(_sahf), /* 0x9e */
+ PREFIX86(_lahf), /* 0x9f */
+ PREFIX86(_mov_aldisp), /* 0xa0 */
+ PREFIX86(_mov_axdisp), /* 0xa1 */
+ PREFIX86(_mov_dispal), /* 0xa2 */
+ PREFIX86(_mov_dispax), /* 0xa3 */
+ PREFIX86(_movsb), /* 0xa4 */
+ PREFIX86(_movsw), /* 0xa5 */
+ PREFIX86(_cmpsb), /* 0xa6 */
+ PREFIX86(_cmpsw), /* 0xa7 */
+ PREFIX86(_test_ald8), /* 0xa8 */
+ PREFIX86(_test_axd16), /* 0xa9 */
+ PREFIX86(_stosb), /* 0xaa */
+ PREFIX86(_stosw), /* 0xab */
+ PREFIX86(_lodsb), /* 0xac */
+ PREFIX86(_lodsw), /* 0xad */
+ PREFIX86(_scasb), /* 0xae */
+ PREFIX86(_scasw), /* 0xaf */
+ PREFIX86(_mov_ald8), /* 0xb0 */
+ PREFIX86(_mov_cld8), /* 0xb1 */
+ PREFIX86(_mov_dld8), /* 0xb2 */
+ PREFIX86(_mov_bld8), /* 0xb3 */
+ PREFIX86(_mov_ahd8), /* 0xb4 */
+ PREFIX86(_mov_chd8), /* 0xb5 */
+ PREFIX86(_mov_dhd8), /* 0xb6 */
+ PREFIX86(_mov_bhd8), /* 0xb7 */
+ PREFIX86(_mov_axd16), /* 0xb8 */
+ PREFIX86(_mov_cxd16), /* 0xb9 */
+ PREFIX86(_mov_dxd16), /* 0xba */
+ PREFIX86(_mov_bxd16), /* 0xbb */
+ PREFIX86(_mov_spd16), /* 0xbc */
+ PREFIX86(_mov_bpd16), /* 0xbd */
+ PREFIX86(_mov_sid16), /* 0xbe */
+ PREFIX86(_mov_did16), /* 0xbf */
+ PREFIX186(_rotshft_bd8), /* 0xc0 */
+ PREFIX186(_rotshft_wd8), /* 0xc1 */
+ PREFIX86(_ret_d16), /* 0xc2 */
+ PREFIX86(_ret), /* 0xc3 */
+ PREFIX86(_les_dw), /* 0xc4 */
+ PREFIX86(_lds_dw), /* 0xc5 */
+ PREFIX86(_mov_bd8), /* 0xc6 */
+ PREFIX86(_mov_wd16), /* 0xc7 */
+ PREFIX186(_enter), /* 0xc8 */
+ PREFIX186(_leave), /* 0xc9 */
+ PREFIX86(_retf_d16), /* 0xca */
+ PREFIX86(_retf), /* 0xcb */
+ PREFIX86(_int3), /* 0xcc */
+ PREFIX86(_int), /* 0xcd */
+ PREFIX86(_into), /* 0xce */
+ PREFIX86(_iret), /* 0xcf */
+ PREFIX86(_rotshft_b), /* 0xd0 */
+ PREFIX86(_rotshft_w), /* 0xd1 */
+ PREFIX86(_rotshft_bcl), /* 0xd2 */
+ PREFIX86(_rotshft_wcl), /* 0xd3 */
+ PREFIX86(_aam), /* 0xd4 */
+ PREFIX86(_aad), /* 0xd5 */
+ PREFIXV30(_setalc),
+ PREFIX86(_xlat), /* 0xd7 */
+ PREFIX86(_escape), /* 0xd8 */
+ PREFIX86(_escape), /* 0xd9 */
+ PREFIX86(_escape), /* 0xda */
+ PREFIX86(_escape), /* 0xdb */
+ PREFIX86(_escape), /* 0xdc */
+ PREFIX86(_escape), /* 0xdd */
+ PREFIX86(_escape), /* 0xde */
+ PREFIX86(_escape), /* 0xdf */
+ PREFIX86(_loopne), /* 0xe0 */
+ PREFIX86(_loope), /* 0xe1 */
+ PREFIX86(_loop), /* 0xe2 */
+ PREFIX86(_jcxz), /* 0xe3 */
+ PREFIX86(_inal), /* 0xe4 */
+ PREFIX86(_inax), /* 0xe5 */
+ PREFIX86(_outal), /* 0xe6 */
+ PREFIX86(_outax), /* 0xe7 */
+ PREFIX86(_call_d16), /* 0xe8 */
+ PREFIX86(_jmp_d16), /* 0xe9 */
+ PREFIX86(_jmp_far), /* 0xea */
+ PREFIX86(_jmp_d8), /* 0xeb */
+ PREFIX86(_inaldx), /* 0xec */
+ PREFIX86(_inaxdx), /* 0xed */
+ PREFIX86(_outdxal), /* 0xee */
+ PREFIX86(_outdxax), /* 0xef */
+ PREFIX86(_lock), /* 0xf0 */
+ PREFIX86(_invalid), /* 0xf1 */
+ PREFIX186(_repne), /* 0xf2 */
+ PREFIX186(_repe), /* 0xf3 */
+ PREFIX86(_hlt), /* 0xf4 */
+ PREFIX86(_cmc), /* 0xf5 */
+ PREFIX86(_f6pre), /* 0xf6 */
+ PREFIX86(_f7pre), /* 0xf7 */
+ PREFIX86(_clc), /* 0xf8 */
+ PREFIX86(_stc), /* 0xf9 */
+ PREFIX86(_cli), /* 0xfa */
+ PREFIX86(_sti), /* 0xfb */
+ PREFIX86(_cld), /* 0xfc */
+ PREFIX86(_std), /* 0xfd */
+ PREFIX86(_fepre), /* 0xfe */
+ PREFIX86(_ffpre) /* 0xff */
+};
+
+#if defined(BIGCASE) && !defined(RS6000)
+ /* Some compilers cannot handle large case statements */
+#define TABLEV30 \
+ switch(FETCHOP)\
+ {\
+ case 0x00: PREFIX86(_add_br8)(); break;\
+ case 0x01: PREFIX86(_add_wr16)(); break;\
+ case 0x02: PREFIX86(_add_r8b)(); break;\
+ case 0x03: PREFIX86(_add_r16w)(); break;\
+ case 0x04: PREFIX86(_add_ald8)(); break;\
+ case 0x05: PREFIX86(_add_axd16)(); break;\
+ case 0x06: PREFIX86(_push_es)(); break;\
+ case 0x07: PREFIX86(_pop_es)(); break;\
+ case 0x08: PREFIX86(_or_br8)(); break;\
+ case 0x09: PREFIX86(_or_wr16)(); break;\
+ case 0x0a: PREFIX86(_or_r8b)(); break;\
+ case 0x0b: PREFIX86(_or_r16w)(); break;\
+ case 0x0c: PREFIX86(_or_ald8)(); break;\
+ case 0x0d: PREFIX86(_or_axd16)(); break;\
+ case 0x0e: PREFIX86(_push_cs)(); break;\
+ case 0x0f: PREFIXV30(_0fpre)(); break;\
+ case 0x10: PREFIX86(_adc_br8)(); break;\
+ case 0x11: PREFIX86(_adc_wr16)(); break;\
+ case 0x12: PREFIX86(_adc_r8b)(); break;\
+ case 0x13: PREFIX86(_adc_r16w)(); break;\
+ case 0x14: PREFIX86(_adc_ald8)(); break;\
+ case 0x15: PREFIX86(_adc_axd16)(); break;\
+ case 0x16: PREFIX86(_push_ss)(); break;\
+ case 0x17: PREFIX86(_pop_ss)(); break;\
+ case 0x18: PREFIX86(_sbb_br8)(); break;\
+ case 0x19: PREFIX86(_sbb_wr16)(); break;\
+ case 0x1a: PREFIX86(_sbb_r8b)(); break;\
+ case 0x1b: PREFIX86(_sbb_r16w)(); break;\
+ case 0x1c: PREFIX86(_sbb_ald8)(); break;\
+ case 0x1d: PREFIX86(_sbb_axd16)(); break;\
+ case 0x1e: PREFIX86(_push_ds)(); break;\
+ case 0x1f: PREFIX86(_pop_ds)(); break;\
+ case 0x20: PREFIX86(_and_br8)(); break;\
+ case 0x21: PREFIX86(_and_wr16)(); break;\
+ case 0x22: PREFIX86(_and_r8b)(); break;\
+ case 0x23: PREFIX86(_and_r16w)(); break;\
+ case 0x24: PREFIX86(_and_ald8)(); break;\
+ case 0x25: PREFIX86(_and_axd16)(); break;\
+ case 0x26: PREFIX86(_es)(); break;\
+ case 0x27: PREFIX86(_daa)(); break;\
+ case 0x28: PREFIX86(_sub_br8)(); break;\
+ case 0x29: PREFIX86(_sub_wr16)(); break;\
+ case 0x2a: PREFIX86(_sub_r8b)(); break;\
+ case 0x2b: PREFIX86(_sub_r16w)(); break;\
+ case 0x2c: PREFIX86(_sub_ald8)(); break;\
+ case 0x2d: PREFIX86(_sub_axd16)(); break;\
+ case 0x2e: PREFIX86(_cs)(); break;\
+ case 0x2f: PREFIX86(_das)(); break;\
+ case 0x30: PREFIX86(_xor_br8)(); break;\
+ case 0x31: PREFIX86(_xor_wr16)(); break;\
+ case 0x32: PREFIX86(_xor_r8b)(); break;\
+ case 0x33: PREFIX86(_xor_r16w)(); break;\
+ case 0x34: PREFIX86(_xor_ald8)(); break;\
+ case 0x35: PREFIX86(_xor_axd16)(); break;\
+ case 0x36: PREFIX86(_ss)(); break;\
+ case 0x37: PREFIX86(_aaa)(); break;\
+ case 0x38: PREFIX86(_cmp_br8)(); break;\
+ case 0x39: PREFIX86(_cmp_wr16)(); break;\
+ case 0x3a: PREFIX86(_cmp_r8b)(); break;\
+ case 0x3b: PREFIX86(_cmp_r16w)(); break;\
+ case 0x3c: PREFIX86(_cmp_ald8)(); break;\
+ case 0x3d: PREFIX86(_cmp_axd16)(); break;\
+ case 0x3e: PREFIX86(_ds)(); break;\
+ case 0x3f: PREFIX86(_aas)(); break;\
+ case 0x40: PREFIX86(_inc_ax)(); break;\
+ case 0x41: PREFIX86(_inc_cx)(); break;\
+ case 0x42: PREFIX86(_inc_dx)(); break;\
+ case 0x43: PREFIX86(_inc_bx)(); break;\
+ case 0x44: PREFIX86(_inc_sp)(); break;\
+ case 0x45: PREFIX86(_inc_bp)(); break;\
+ case 0x46: PREFIX86(_inc_si)(); break;\
+ case 0x47: PREFIX86(_inc_di)(); break;\
+ case 0x48: PREFIX86(_dec_ax)(); break;\
+ case 0x49: PREFIX86(_dec_cx)(); break;\
+ case 0x4a: PREFIX86(_dec_dx)(); break;\
+ case 0x4b: PREFIX86(_dec_bx)(); break;\
+ case 0x4c: PREFIX86(_dec_sp)(); break;\
+ case 0x4d: PREFIX86(_dec_bp)(); break;\
+ case 0x4e: PREFIX86(_dec_si)(); break;\
+ case 0x4f: PREFIX86(_dec_di)(); break;\
+ case 0x50: PREFIX86(_push_ax)(); break;\
+ case 0x51: PREFIX86(_push_cx)(); break;\
+ case 0x52: PREFIX86(_push_dx)(); break;\
+ case 0x53: PREFIX86(_push_bx)(); break;\
+ case 0x54: PREFIX86(_push_sp)(); break;\
+ case 0x55: PREFIX86(_push_bp)(); break;\
+ case 0x56: PREFIX86(_push_si)(); break;\
+ case 0x57: PREFIX86(_push_di)(); break;\
+ case 0x58: PREFIX86(_pop_ax)(); break;\
+ case 0x59: PREFIX86(_pop_cx)(); break;\
+ case 0x5a: PREFIX86(_pop_dx)(); break;\
+ case 0x5b: PREFIX86(_pop_bx)(); break;\
+ case 0x5c: PREFIX86(_pop_sp)(); break;\
+ case 0x5d: PREFIX86(_pop_bp)(); break;\
+ case 0x5e: PREFIX86(_pop_si)(); break;\
+ case 0x5f: PREFIX86(_pop_di)(); break;\
+ case 0x60: PREFIX186(_pusha)(); break;\
+ case 0x61: PREFIX186(_popa)(); break;\
+ case 0x62: PREFIX186(_bound)(); break;\
+ case 0x63: PREFIX86(_invalid)(); break;\
+ case 0x64: PREFIXV30(_repnc)(); break;\
+ case 0x65: PREFIXV30(_repc)(); break;\
+ case 0x66: PREFIX86(_invalid)(); break;\
+ case 0x67: PREFIX86(_invalid)(); break;\
+ case 0x68: PREFIX186(_push_d16)(); break;\
+ case 0x69: PREFIX186(_imul_d16)(); break;\
+ case 0x6a: PREFIX186(_push_d8)(); break;\
+ case 0x6b: PREFIX186(_imul_d8)(); break;\
+ case 0x6c: PREFIX186(_insb)(); break;\
+ case 0x6d: PREFIX186(_insw)(); break;\
+ case 0x6e: PREFIX186(_outsb)(); break;\
+ case 0x6f: PREFIX186(_outsw)(); break;\
+ case 0x70: PREFIX86(_jo)(); break;\
+ case 0x71: PREFIX86(_jno)(); break;\
+ case 0x72: PREFIX86(_jb)(); break;\
+ case 0x73: PREFIX86(_jnb)(); break;\
+ case 0x74: PREFIX86(_jz)(); break;\
+ case 0x75: PREFIX86(_jnz)(); break;\
+ case 0x76: PREFIX86(_jbe)(); break;\
+ case 0x77: PREFIX86(_jnbe)(); break;\
+ case 0x78: PREFIX86(_js)(); break;\
+ case 0x79: PREFIX86(_jns)(); break;\
+ case 0x7a: PREFIX86(_jp)(); break;\
+ case 0x7b: PREFIX86(_jnp)(); break;\
+ case 0x7c: PREFIX86(_jl)(); break;\
+ case 0x7d: PREFIX86(_jnl)(); break;\
+ case 0x7e: PREFIX86(_jle)(); break;\
+ case 0x7f: PREFIX86(_jnle)(); break;\
+ case 0x80: PREFIX86(_80pre)(); break;\
+ case 0x81: PREFIX86(_81pre)(); break;\
+ case 0x82: PREFIX86(_82pre)(); break;\
+ case 0x83: PREFIX86(_83pre)(); break;\
+ case 0x84: PREFIX86(_test_br8)(); break;\
+ case 0x85: PREFIX86(_test_wr16)(); break;\
+ case 0x86: PREFIX86(_xchg_br8)(); break;\
+ case 0x87: PREFIX86(_xchg_wr16)(); break;\
+ case 0x88: PREFIX86(_mov_br8)(); break;\
+ case 0x89: PREFIX86(_mov_wr16)(); break;\
+ case 0x8a: PREFIX86(_mov_r8b)(); break;\
+ case 0x8b: PREFIX86(_mov_r16w)(); break;\
+ case 0x8c: PREFIX86(_mov_wsreg)(); break;\
+ case 0x8d: PREFIX86(_lea)(); break;\
+ case 0x8e: PREFIX86(_mov_sregw)(); break;\
+ case 0x8f: PREFIX86(_popw)(); break;\
+ case 0x90: PREFIX86(_nop)(); break;\
+ case 0x91: PREFIX86(_xchg_axcx)(); break;\
+ case 0x92: PREFIX86(_xchg_axdx)(); break;\
+ case 0x93: PREFIX86(_xchg_axbx)(); break;\
+ case 0x94: PREFIX86(_xchg_axsp)(); break;\
+ case 0x95: PREFIX86(_xchg_axbp)(); break;\
+ case 0x96: PREFIX86(_xchg_axsi)(); break;\
+ case 0x97: PREFIX86(_xchg_axdi)(); break;\
+ case 0x98: PREFIX86(_cbw)(); break;\
+ case 0x99: PREFIX86(_cwd)(); break;\
+ case 0x9a: PREFIX86(_call_far)(); break;\
+ case 0x9b: PREFIX86(_wait)(); break;\
+ case 0x9c: PREFIXV30(_pushf)(); break;\
+ case 0x9d: PREFIX86(_popf)(); break;\
+ case 0x9e: PREFIX86(_sahf)(); break;\
+ case 0x9f: PREFIX86(_lahf)(); break;\
+ case 0xa0: PREFIX86(_mov_aldisp)(); break;\
+ case 0xa1: PREFIX86(_mov_axdisp)(); break;\
+ case 0xa2: PREFIX86(_mov_dispal)(); break;\
+ case 0xa3: PREFIX86(_mov_dispax)(); break;\
+ case 0xa4: PREFIX86(_movsb)(); break;\
+ case 0xa5: PREFIX86(_movsw)(); break;\
+ case 0xa6: PREFIX86(_cmpsb)(); break;\
+ case 0xa7: PREFIX86(_cmpsw)(); break;\
+ case 0xa8: PREFIX86(_test_ald8)(); break;\
+ case 0xa9: PREFIX86(_test_axd16)(); break;\
+ case 0xaa: PREFIX86(_stosb)(); break;\
+ case 0xab: PREFIX86(_stosw)(); break;\
+ case 0xac: PREFIX86(_lodsb)(); break;\
+ case 0xad: PREFIX86(_lodsw)(); break;\
+ case 0xae: PREFIX86(_scasb)(); break;\
+ case 0xaf: PREFIX86(_scasw)(); break;\
+ case 0xb0: PREFIX86(_mov_ald8)(); break;\
+ case 0xb1: PREFIX86(_mov_cld8)(); break;\
+ case 0xb2: PREFIX86(_mov_dld8)(); break;\
+ case 0xb3: PREFIX86(_mov_bld8)(); break;\
+ case 0xb4: PREFIX86(_mov_ahd8)(); break;\
+ case 0xb5: PREFIX86(_mov_chd8)(); break;\
+ case 0xb6: PREFIX86(_mov_dhd8)(); break;\
+ case 0xb7: PREFIX86(_mov_bhd8)(); break;\
+ case 0xb8: PREFIX86(_mov_axd16)(); break;\
+ case 0xb9: PREFIX86(_mov_cxd16)(); break;\
+ case 0xba: PREFIX86(_mov_dxd16)(); break;\
+ case 0xbb: PREFIX86(_mov_bxd16)(); break;\
+ case 0xbc: PREFIX86(_mov_spd16)(); break;\
+ case 0xbd: PREFIX86(_mov_bpd16)(); break;\
+ case 0xbe: PREFIX86(_mov_sid16)(); break;\
+ case 0xbf: PREFIX86(_mov_did16)(); break;\
+ case 0xc0: PREFIX186(_rotshft_bd8)(); break;\
+ case 0xc1: PREFIX186(_rotshft_wd8)(); break;\
+ case 0xc2: PREFIX86(_ret_d16)(); break;\
+ case 0xc3: PREFIX86(_ret)(); break;\
+ case 0xc4: PREFIX86(_les_dw)(); break;\
+ case 0xc5: PREFIX86(_lds_dw)(); break;\
+ case 0xc6: PREFIX86(_mov_bd8)(); break;\
+ case 0xc7: PREFIX86(_mov_wd16)(); break;\
+ case 0xc8: PREFIX186(_enter)(); break;\
+ case 0xc9: PREFIX186(_leave)(); break;\
+ case 0xca: PREFIX86(_retf_d16)(); break;\
+ case 0xcb: PREFIX86(_retf)(); break;\
+ case 0xcc: PREFIX86(_int3)(); break;\
+ case 0xcd: PREFIX86(_int)(); break;\
+ case 0xce: PREFIX86(_into)(); break;\
+ case 0xcf: PREFIX86(_iret)(); break;\
+ case 0xd0: PREFIX86(_rotshft_b)(); break;\
+ case 0xd1: PREFIX86(_rotshft_w)(); break;\
+ case 0xd2: PREFIX86(_rotshft_bcl)(); break;\
+ case 0xd3: PREFIX86(_rotshft_wcl)(); break;\
+ case 0xd4: PREFIX86(_aam)(); break;\
+ case 0xd5: PREFIX86(_aad)(); break;\
+ case 0xd6: PREFIXV30(_setalc)(); break;\
+ case 0xd7: PREFIX86(_xlat)(); break;\
+ case 0xd8: PREFIX86(_escape)(); break;\
+ case 0xd9: PREFIX86(_escape)(); break;\
+ case 0xda: PREFIX86(_escape)(); break;\
+ case 0xdb: PREFIX86(_escape)(); break;\
+ case 0xdc: PREFIX86(_escape)(); break;\
+ case 0xdd: PREFIX86(_escape)(); break;\
+ case 0xde: PREFIX86(_escape)(); break;\
+ case 0xdf: PREFIX86(_escape)(); break;\
+ case 0xe0: PREFIX86(_loopne)(); break;\
+ case 0xe1: PREFIX86(_loope)(); break;\
+ case 0xe2: PREFIX86(_loop)(); break;\
+ case 0xe3: PREFIX86(_jcxz)(); break;\
+ case 0xe4: PREFIX86(_inal)(); break;\
+ case 0xe5: PREFIX86(_inax)(); break;\
+ case 0xe6: PREFIX86(_outal)(); break;\
+ case 0xe7: PREFIX86(_outax)(); break;\
+ case 0xe8: PREFIX86(_call_d16)(); break;\
+ case 0xe9: PREFIX86(_jmp_d16)(); break;\
+ case 0xea: PREFIX86(_jmp_far)(); break;\
+ case 0xeb: PREFIX86(_jmp_d8)(); break;\
+ case 0xec: PREFIX86(_inaldx)(); break;\
+ case 0xed: PREFIX86(_inaxdx)(); break;\
+ case 0xee: PREFIX86(_outdxal)(); break;\
+ case 0xef: PREFIX86(_outdxax)(); break;\
+ case 0xf0: PREFIX86(_lock)(); break;\
+ case 0xf1: PREFIX86(_invalid)(); break;\
+ case 0xf2: PREFIX186(_repne)(); break;\
+ case 0xf3: PREFIX186(_repe)(); break;\
+ case 0xf4: PREFIX86(_hlt)(); break;\
+ case 0xf5: PREFIX86(_cmc)(); break;\
+ case 0xf6: PREFIX86(_f6pre)(); break;\
+ case 0xf7: PREFIX86(_f7pre)(); break;\
+ case 0xf8: PREFIX86(_clc)(); break;\
+ case 0xf9: PREFIX86(_stc)(); break;\
+ case 0xfa: PREFIX86(_cli)(); break;\
+ case 0xfb: PREFIX86(_sti)(); break;\
+ case 0xfc: PREFIX86(_cld)(); break;\
+ case 0xfd: PREFIX86(_std)(); break;\
+ case 0xfe: PREFIX86(_fepre)(); break;\
+ case 0xff: PREFIX86(_ffpre)(); break;\
+ };
+#else
+#define TABLEV30 PREFIXV30(_instruction)[FETCHOP]();
+#endif
diff --git a/src/emu/cpu/i86/v20intf.h b/src/emu/cpu/i86/v20intf.h
new file mode 100644
index 00000000000..88a42617d48
--- /dev/null
+++ b/src/emu/cpu/i86/v20intf.h
@@ -0,0 +1,11 @@
+/* ASG 971222 -- rewrote this interface */
+#ifndef __V20INTRF_H_
+#define __V20INTRF_H_
+
+#include "i86intrf.h"
+#include "v30intrf.h"
+
+/* Public functions */
+void v20_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/i86/v30.h b/src/emu/cpu/i86/v30.h
new file mode 100644
index 00000000000..61792b5176d
--- /dev/null
+++ b/src/emu/cpu/i86/v30.h
@@ -0,0 +1,23 @@
+#define SetMD(x) (I.MF = (x)) /* OB [19.07.99] Mode Flag V30 */
+
+#define MD (I.MF!=0)
+
+#undef CompressFlags
+#define CompressFlags() (WORD)(CF | (PF << 2) | (AF << 4) | (ZF << 6) \
+ | (SF << 7) | (I.TF << 8) | (I.IF << 9) \
+ | (I.DF << 10) | (OF << 11)| (MD << 15))
+
+#undef ExpandFlags
+#define ExpandFlags(f) \
+{ \
+ I.CarryVal = (f) & 1; \
+ I.ParityVal = !((f) & 4); \
+ I.AuxVal = (f) & 16; \
+ I.ZeroVal = !((f) & 64); \
+ I.SignVal = (f) & 128 ? -1 : 0; \
+ I.TF = ((f) & 256) == 256; \
+ I.IF = ((f) & 512) == 512; \
+ I.DF = ((f) & 1024) == 1024; \
+ I.OverVal = (f) & 2048; \
+ I.MF = ((f) & 0x8000) == 0x8000; \
+}
diff --git a/src/emu/cpu/i86/v30intf.h b/src/emu/cpu/i86/v30intf.h
new file mode 100644
index 00000000000..3eb09015980
--- /dev/null
+++ b/src/emu/cpu/i86/v30intf.h
@@ -0,0 +1,9 @@
+#ifndef __V30INTRF_H_
+#define __V30INTRF_H_
+
+#include "i86intf.h"
+
+/* Public functions */
+void v30_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/i86/v33intf.h b/src/emu/cpu/i86/v33intf.h
new file mode 100644
index 00000000000..fa74dcf0781
--- /dev/null
+++ b/src/emu/cpu/i86/v33intf.h
@@ -0,0 +1,10 @@
+#ifndef __V33INTRF_H_
+#define __V33INTRF_H_
+
+#include "i86intrf.h"
+#include "v30intrf.h"
+
+/* Public functions */
+void v33_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/i8x41/8x41dasm.c b/src/emu/cpu/i8x41/8x41dasm.c
new file mode 100644
index 00000000000..ccc3073971b
--- /dev/null
+++ b/src/emu/cpu/i8x41/8x41dasm.c
@@ -0,0 +1,523 @@
+#include "debugger.h"
+#include "i8x41.h"
+
+offs_t i8x41_dasm(char *dst, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ unsigned PC = pc;
+ UINT8 op;
+ UINT8 arg;
+
+ op = oprom[PC++ - pc];
+ switch( op )
+ {
+ case 0x00: /* 1: 0000 0000 */
+ sprintf(dst, "nop");
+ break;
+ case 0x01: /* 1: 0000 0001 */
+ sprintf(dst, "ill");
+ break;
+ case 0x02: /* 1: 0000 0010 */
+ sprintf(dst, "out dbb,a");
+ break;
+ case 0x03: /* 2: 0000 0011 */
+ sprintf(dst, "add a,#$%02X", opram[PC++ - pc]);
+ break;
+ case 0x04: /* 2: aaa0 0100 */
+ case 0x24: /* 2: aaa0 0100 */
+ case 0x44: /* 2: aaa0 0100 */
+ case 0x64: /* 2: aaa0 0100 */
+ case 0x84: /* 2: aaa0 0100 */
+ case 0xa4: /* 2: aaa0 0100 */
+ case 0xc4: /* 2: aaa0 0100 */
+ case 0xe4: /* 2: aaa0 0100 */
+ sprintf(dst, "jmp $%04X", ((op<<3) & 0x700) | opram[PC++ - pc]);
+ break;
+ case 0x05: /* 1: 0000 0101 */
+ sprintf(dst, "en i");
+ break;
+ case 0x06: /* 1: 0000 0110 */
+ sprintf(dst, "ill");
+ break;
+ case 0x07: /* 1: 0000 0111 */
+ sprintf(dst, "dec a");
+ break;
+ case 0x08: /* 2: 0000 10pp */
+ case 0x09: /* 2: 0000 10pp */
+ case 0x0a: /* 2: 0000 10pp */
+ case 0x0b: /* 2: 0000 10pp */
+ sprintf(dst, "in a,p%d", op&3);
+ break;
+ case 0x0c: /* 2: 0000 11pp */
+ case 0x0d: /* 2: 0000 11pp */
+ case 0x0e: /* 2: 0000 11pp */
+ case 0x0f: /* 2: 0000 11pp */
+ sprintf(dst, "movd a,p%d", op&3);
+ break;
+ case 0x10: /* 1: 0001 000r */
+ case 0x11: /* 1: 0001 000r */
+ sprintf(dst, "inc @r%d", op&1);
+ break;
+ case 0x12: /* 2: bbb1 0010 */
+ case 0x32: /* 2: bbb1 0010 */
+ case 0x52: /* 2: bbb1 0010 */
+ case 0x72: /* 2: bbb1 0010 */
+ case 0x92: /* 2: bbb1 0010 */
+ case 0xb2: /* 2: bbb1 0010 */
+ case 0xd2: /* 2: bbb1 0010 */
+ case 0xf2: /* 2: bbb1 0010 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jb%d $%04X", op >> 5, (PC & 0x700) | arg);
+ break;
+ case 0x13: /* 2: 0001 0011 */
+ sprintf(dst, "addc $%02X", opram[PC++ - pc]);
+ break;
+ case 0x14: /* 2: aaa1 0100 */
+ case 0x34: /* 2: aaa1 0100 */
+ case 0x54: /* 2: aaa1 0100 */
+ case 0x74: /* 2: aaa1 0100 */
+ case 0x94: /* 2: aaa1 0100 */
+ case 0xb4: /* 2: aaa1 0100 */
+ case 0xd4: /* 2: aaa1 0100 */
+ case 0xf4: /* 2: aaa1 0100 */
+ sprintf(dst, "call $%04X", ((op<<3) & 0x700) | opram[PC++ - pc]);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0x15: /* 1: 0001 0101 */
+ sprintf(dst, "dis i");
+ break;
+ case 0x16: /* 2: 0001 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jtf $%04X", (PC & 0x700) | arg);
+ break;
+ case 0x17: /* 1: 0001 0111 */
+ sprintf(dst, "inc a");
+ break;
+ case 0x18: /* 1: 0001 1rrr */
+ case 0x19: /* 1: 0001 1rrr */
+ case 0x1a: /* 1: 0001 1rrr */
+ case 0x1b: /* 1: 0001 1rrr */
+ case 0x1c: /* 1: 0001 1rrr */
+ case 0x1d: /* 1: 0001 1rrr */
+ case 0x1e: /* 1: 0001 1rrr */
+ case 0x1f: /* 1: 0001 1rrr */
+ sprintf(dst, "inc r%d", op&7);
+ break;
+ case 0x20: /* 1: 0010 000r */
+ case 0x21: /* 1: 0010 000r */
+ sprintf(dst, "xch a,@r%d", op&1);
+ break;
+ case 0x22: /* 1: 0010 0010 */
+ sprintf(dst, "in a,ddb");
+ break;
+ case 0x23: /* 2: 0010 0011 */
+ sprintf(dst, "mov a,#$%02X", opram[PC++ - pc]);
+ break;
+ case 0x25: /* 1: 0010 0101 */
+ sprintf(dst, "en tcnti");
+ break;
+ case 0x26: /* 2: 0010 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jnt0 $%04X", (PC & 0x700) | arg);
+ break;
+ case 0x27: /* 1: 0010 0111 */
+ sprintf(dst, "clr a");
+ break;
+ case 0x28: /* 1: 0010 1rrr */
+ case 0x29: /* 1: 0010 1rrr */
+ case 0x2a: /* 1: 0010 1rrr */
+ case 0x2b: /* 1: 0010 1rrr */
+ case 0x2c: /* 1: 0010 1rrr */
+ case 0x2d: /* 1: 0010 1rrr */
+ case 0x2e: /* 1: 0010 1rrr */
+ case 0x2f: /* 1: 0010 1rrr */
+ sprintf(dst, "xch a,r%d", op&7);
+ break;
+ case 0x30: /* 1: 0011 000r */
+ case 0x31: /* 1: 0011 000r */
+ sprintf(dst, "xchd a,@r%d", op&1);
+ break;
+ case 0x33: /* 1: 0011 0101 */
+ sprintf(dst, "ill");
+ break;
+ case 0x35: /* 1: 0000 0101 */
+ sprintf(dst, "dis tcnti");
+ break;
+ case 0x36: /* 2: 0011 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jt0 $%04X", (PC & 0x700) | arg);
+ break;
+ case 0x37: /* 1: 0011 0111 */
+ sprintf(dst, "cpl a");
+ break;
+ case 0x38: /* 2: 0011 10pp */
+ case 0x39: /* 2: 0011 10pp */
+ case 0x3a: /* 2: 0011 10pp */
+ case 0x3b: /* 2: 0011 10pp */
+ sprintf(dst, "out p%d,a", op&3);
+ break;
+ case 0x3c: /* 2: 0011 11pp */
+ case 0x3d: /* 2: 0011 11pp */
+ case 0x3e: /* 2: 0011 11pp */
+ case 0x3f: /* 2: 0011 11pp */
+ sprintf(dst, "movd p%d,a", op&7);
+ break;
+ case 0x40: /* 1: 0100 000r */
+ case 0x41: /* 1: 0100 000r */
+ sprintf(dst, "orl a,@r%d", op&1);
+ break;
+ case 0x42: /* 1: 0100 0010 */
+ sprintf(dst, "mov a,t");
+ break;
+ case 0x43: /* 2: 0100 0011 */
+ sprintf(dst, "orl a,#$%02X", opram[PC++ - pc]);
+ break;
+ case 0x45: /* 1: 0100 0101 */
+ sprintf(dst, "strt cnt");
+ break;
+ case 0x46: /* 2: 0100 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jnt1 $%04X", (PC & 0x700) | arg);
+ break;
+ case 0x47: /* 1: 0100 0111 */
+ sprintf(dst, "swap a");
+ break;
+ case 0x48: /* 1: 0100 1rrr */
+ case 0x49: /* 1: 0100 1rrr */
+ case 0x4a: /* 1: 0100 1rrr */
+ case 0x4b: /* 1: 0100 1rrr */
+ case 0x4c: /* 1: 0100 1rrr */
+ case 0x4d: /* 1: 0100 1rrr */
+ case 0x4e: /* 1: 0100 1rrr */
+ case 0x4f: /* 1: 0100 1rrr */
+ sprintf(dst, "orl a,r%d", op&7);
+ break;
+ case 0x50: /* 1: 0101 000r */
+ case 0x51: /* 1: 0101 000r */
+ sprintf(dst, "anl a,@r%d", op&1);
+ break;
+ case 0x53: /* 2: 0101 0011 */
+ sprintf(dst, "anl a,#$%02X", opram[PC++ - pc]);
+ break;
+ case 0x55: /* 1: 0101 0101 */
+ sprintf(dst, "strt t");
+ break;
+ case 0x56: /* 2: 0101 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jt1 $%04X", (PC & 0x700) | arg);
+ break;
+ case 0x57: /* 1: 0101 0111 */
+ sprintf(dst, "da a");
+ break;
+ case 0x58: /* 1: 0101 1rrr */
+ case 0x59: /* 1: 0101 1rrr */
+ case 0x5a: /* 1: 0101 1rrr */
+ case 0x5b: /* 1: 0101 1rrr */
+ case 0x5c: /* 1: 0101 1rrr */
+ case 0x5d: /* 1: 0101 1rrr */
+ case 0x5e: /* 1: 0101 1rrr */
+ case 0x5f: /* 1: 0101 1rrr */
+ sprintf(dst, "anl a,r%d", op&7);
+ break;
+ case 0x60: /* 1: 0110 000r */
+ case 0x61: /* 1: 0110 000r */
+ sprintf(dst, "add a,@r%d", op&1);
+ break;
+ case 0x62: /* 1: 0110 0010 */
+ sprintf(dst, "mov t,a");
+ break;
+ case 0x63: /* 1: 0110 0011 */
+ sprintf(dst, "ill");
+ break;
+ case 0x65: /* 1: 0110 0101 */
+ sprintf(dst, "stop tcnt");
+ break;
+ case 0x66: /* 1: 0110 0110 */
+ sprintf(dst, "ill");
+ break;
+ case 0x67: /* 1: 0110 0111 */
+ sprintf(dst, "rlc a");
+ break;
+ case 0x68: /* 1: 0110 1rrr */
+ case 0x69: /* 1: 0110 1rrr */
+ case 0x6a: /* 1: 0110 1rrr */
+ case 0x6b: /* 1: 0110 1rrr */
+ case 0x6c: /* 1: 0110 1rrr */
+ case 0x6d: /* 1: 0110 1rrr */
+ case 0x6e: /* 1: 0110 1rrr */
+ case 0x6f: /* 1: 0110 1rrr */
+ sprintf(dst, "add a,r%d", op&7);
+ break;
+ case 0x70: /* 1: 0111 000r */
+ case 0x71: /* 1: 0111 000r */
+ sprintf(dst, "addc a,@r%d", op&1);
+ break;
+ case 0x73: /* 1: 0111 0011 */
+ sprintf(dst, "ill");
+ break;
+ case 0x75: /* 1: 0111 0101 */
+ sprintf(dst, "ill");
+ break;
+ case 0x76: /* 2: 0111 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jf1 $%04X", (PC & 0x700) | arg);
+ break;
+ case 0x77: /* 1: 0111 0111 */
+ sprintf(dst, "rl a");
+ break;
+ case 0x78: /* 1: 0111 1rrr */
+ case 0x79: /* 1: 0111 1rrr */
+ case 0x7a: /* 1: 0111 1rrr */
+ case 0x7b: /* 1: 0111 1rrr */
+ case 0x7c: /* 1: 0111 1rrr */
+ case 0x7d: /* 1: 0111 1rrr */
+ case 0x7e: /* 1: 0111 1rrr */
+ case 0x7f: /* 1: 0111 1rrr */
+ sprintf(dst, "addc a,r%d", op&7);
+ break;
+ case 0x80: /* 1: 1000 0000 */
+ sprintf(dst, "ill ");
+ break;
+ case 0x81: /* 1: 1000 0001 */
+ sprintf(dst, "ill ");
+ break;
+ case 0x82: /* 1: 1000 0010 */
+ sprintf(dst, "ill ");
+ break;
+ case 0x83: /* 2: 1000 0011 */
+ sprintf(dst, "ret");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ case 0x85: /* 1: 1000 0101 */
+ sprintf(dst, "clr f0");
+ break;
+ case 0x86: /* 2: 1000 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jobf $%04X", (PC & 0x700) | arg);
+ break;
+ case 0x87: /* 1: 1000 0111 */
+ sprintf(dst, "ill");
+ break;
+ case 0x88: /* 2: 1000 10pp */
+ case 0x89: /* 2: 1000 10pp */
+ case 0x8a: /* 2: 1000 10pp */
+ case 0x8b: /* 2: 1000 10pp */
+ sprintf(dst, "orl p%d,#$%02X", op&3, opram[PC++ - pc]);
+ break;
+ case 0x8c: /* 2: 1000 11pp */
+ case 0x8d: /* 2: 1000 11pp */
+ case 0x8e: /* 2: 1000 11pp */
+ case 0x8f: /* 2: 1000 11pp */
+ sprintf(dst, "orld p%d,a", op&7);
+ break;
+ case 0x90: /* 1: 1001 0000 */
+ sprintf(dst, "mov sts,a");
+ break;
+ case 0x91: /* 1: 1001 0001 */
+ sprintf(dst, "ill");
+ break;
+ case 0x93: /* 2: 1001 0011 */
+ sprintf(dst, "retr");
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0x95: /* 1: 1001 0101 */
+ sprintf(dst, "cpl f0");
+ break;
+ case 0x96: /* 2: 1001 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jnz $%04X", (PC & 0x700) | arg);
+ break;
+ case 0x97: /* 1: 1001 0111 */
+ sprintf(dst, "clr c");
+ break;
+ case 0x98: /* 2: 1001 10pp */
+ case 0x99: /* 2: 1001 10pp */
+ case 0x9a: /* 2: 1001 10pp */
+ case 0x9b: /* 2: 1001 10pp */
+ sprintf(dst, "anl p%d,#$%02X", op&3, opram[PC++ - pc]);
+ break;
+ case 0x9c: /* 2: 1001 11pp */
+ case 0x9d: /* 2: 1001 11pp */
+ case 0x9e: /* 2: 1001 11pp */
+ case 0x9f: /* 2: 1001 11pp */
+ sprintf(dst, "anld p%d,a", op&7);
+ break;
+ case 0xa0: /* 1: 1010 000r */
+ case 0xa1: /* 1: 1010 000r */
+ sprintf(dst, "mov @r%d,a", op&1);
+ break;
+ case 0xa2: /* 1: 1010 0010 */
+ sprintf(dst, "ill");
+ break;
+ case 0xa3: /* 2: 1010 0011 */
+ sprintf(dst, "movp a,@a");
+ break;
+ case 0xa5: /* 1: 1010 0101 */
+ sprintf(dst, "clr f1");
+ break;
+ case 0xa6: /* 1: 1010 0110 */
+ sprintf(dst, "ill");
+ break;
+ case 0xa7: /* 1: 1010 0111 */
+ sprintf(dst, "cpl c");
+ break;
+ case 0xa8: /* 1: 1010 1rrr */
+ case 0xa9: /* 1: 1010 1rrr */
+ case 0xaa: /* 1: 1010 1rrr */
+ case 0xab: /* 1: 1010 1rrr */
+ case 0xac: /* 1: 1010 1rrr */
+ case 0xad: /* 1: 1010 1rrr */
+ case 0xae: /* 1: 1010 1rrr */
+ case 0xaf: /* 1: 1010 1rrr */
+ sprintf(dst, "mov r%d,a", op&7);
+ break;
+ case 0xb0: /* 2: 1011 000r */
+ case 0xb1: /* 2: 1011 000r */
+ sprintf(dst, "mov @r%d,#$%02X", op&1, opram[PC++ - pc]);
+ break;
+ case 0xb3: /* 2: 1011 0011 */
+ sprintf(dst, "jmpp @a");
+ break;
+ case 0xb5: /* 1: 1011 0101 */
+ sprintf(dst, "cpl f1");
+ break;
+ case 0xb6: /* 2: 1011 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jf0 $%04X", (PC & 0x700) | arg);
+ break;
+ case 0xb7: /* 1: 1011 0111 */
+ sprintf(dst, "ill");
+ break;
+ case 0xb8: /* 1: 1011 1rrr */
+ case 0xb9: /* 1: 1011 1rrr */
+ case 0xba: /* 1: 1011 1rrr */
+ case 0xbb: /* 1: 1011 1rrr */
+ case 0xbc: /* 1: 1011 1rrr */
+ case 0xbd: /* 1: 1011 1rrr */
+ case 0xbe: /* 1: 1011 1rrr */
+ case 0xbf: /* 1: 1011 1rrr */
+ sprintf(dst, "mov r%d,#$%02X", op&7, opram[PC++ - pc]);
+ break;
+ case 0xc0: /* 1: 1100 0000 */
+ sprintf(dst, "ill");
+ break;
+ case 0xc1: /* 1: 1100 0001 */
+ sprintf(dst, "ill");
+ break;
+ case 0xc2: /* 1: 1100 0010 */
+ sprintf(dst, "ill");
+ break;
+ case 0xc3: /* 1: 1100 0011 */
+ sprintf(dst, "ill");
+ break;
+ case 0xc5: /* 1: 1100 0101 */
+ sprintf(dst, "sel rb0");
+ break;
+ case 0xc6: /* 2: 1100 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jz $%04X", (PC & 0x700) | arg);
+ break;
+ case 0xc7: /* 1: 1100 0111 */
+ sprintf(dst, "mov a,psw");
+ break;
+ case 0xc8: /* 1: 1100 1rrr */
+ case 0xc9: /* 1: 1100 1rrr */
+ case 0xca: /* 1: 1100 1rrr */
+ case 0xcb: /* 1: 1100 1rrr */
+ case 0xcc: /* 1: 1100 1rrr */
+ case 0xcd: /* 1: 1100 1rrr */
+ case 0xce: /* 1: 1100 1rrr */
+ case 0xcf: /* 1: 1100 1rrr */
+ sprintf(dst, "dec r%d", op&7);
+ break;
+ case 0xd0: /* 1: 1101 000r */
+ case 0xd1: /* 1: 1101 000r */
+ sprintf(dst, "xrl a,@r%d", op&1);
+ break;
+ case 0xd3: /* 1: 1101 0011 */
+ sprintf(dst, "xrl a,#$%02X", opram[PC++ - pc]);
+ break;
+ case 0xd5: /* 1: 1101 0101 */
+ sprintf(dst, "sel rb1");
+ break;
+ case 0xd6: /* 2: 1101 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jnibf $%04X", (PC & 0x700) | arg);
+ break;
+ case 0xd7: /* 1: 1101 0111 */
+ sprintf(dst, "mov psw,a");
+ break;
+ case 0xd8: /* 1: 1101 1rrr */
+ case 0xd9: /* 1: 1101 1rrr */
+ case 0xda: /* 1: 1101 1rrr */
+ case 0xdb: /* 1: 1101 1rrr */
+ case 0xdc: /* 1: 1101 1rrr */
+ case 0xdd: /* 1: 1101 1rrr */
+ case 0xde: /* 1: 1101 1rrr */
+ case 0xdf: /* 1: 1101 1rrr */
+ sprintf(dst, "xrl a,r%d", op&7);
+ break;
+ case 0xe0: /* 1: 1110 0000 */
+ sprintf(dst, "ill");
+ break;
+ case 0xe1: /* 1: 1110 0001 */
+ sprintf(dst, "ill");
+ break;
+ case 0xe2: /* 1: 1110 0010 */
+ sprintf(dst, "ill");
+ break;
+ case 0xe3: /* 2: 1110 0011 */
+ sprintf(dst, "movp3 a,@a");
+ break;
+ case 0xe5: /* 1: 1110 0101 */
+ sprintf(dst, "en dma");
+ break;
+ case 0xe6: /* 2: 1110 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jnc $%04X", (PC & 0x700) | arg);
+ break;
+ case 0xe7: /* 1: 1110 0111 */
+ sprintf(dst, "rl a");
+ break;
+ case 0xe8: /* 2: 1110 1rrr */
+ case 0xe9: /* 2: 1110 1rrr */
+ case 0xea: /* 2: 1110 1rrr */
+ case 0xeb: /* 2: 1110 1rrr */
+ case 0xec: /* 2: 1110 1rrr */
+ case 0xed: /* 2: 1110 1rrr */
+ case 0xee: /* 2: 1110 1rrr */
+ case 0xef: /* 2: 1110 1rrr */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "djnz r%d,$%04X", op&7, (PC & 0x700) | arg);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0xf0: /* 1: 1111 000r */
+ case 0xf1: /* 1: 1111 000r */
+ sprintf(dst, "mov a,@r%d", op&1);
+ break;
+ case 0xf3: /* 1: 1111 0011 */
+ sprintf(dst, "ill");
+ break;
+ case 0xf5: /* 1: 1111 0101 */
+ sprintf(dst, "en flags");
+ break;
+ case 0xf6: /* 2: 1111 0110 */
+ arg = opram[PC++ - pc];
+ sprintf(dst, "jc $%04X", (PC & 0x700) | arg);
+ break;
+ case 0xf7: /* 1: 1111 0111 */
+ sprintf(dst, "rlc a");
+ break;
+ case 0xf8: /* 1: 1111 1rrr */
+ case 0xf9: /* 1: 1111 1rrr */
+ case 0xfa: /* 1: 1111 1rrr */
+ case 0xfb: /* 1: 1111 1rrr */
+ case 0xfc: /* 1: 1111 1rrr */
+ case 0xfd: /* 1: 1111 1rrr */
+ case 0xfe: /* 1: 1111 1rrr */
+ case 0xff: /* 1: 1111 1rrr */
+ sprintf(dst, "mov a,r%d", op&7);
+ break;
+ }
+ return (PC - pc) | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/i8x41/i8x41.c b/src/emu/cpu/i8x41/i8x41.c
new file mode 100644
index 00000000000..e5642bbabca
--- /dev/null
+++ b/src/emu/cpu/i8x41/i8x41.c
@@ -0,0 +1,2316 @@
+/*****************************************************************************
+ *
+ * i8x41.c
+ * Portable UPI-41/8041/8741/8042/8742 emulator V0.2
+ *
+ * Copyright (c) 1999 Juergen Buchmueller, all rights reserved.
+ *
+ * Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * You can contact me at juergen@mame.net or pullmoll@stop1984.com
+ *
+ * - This source code is released as freeware for non-commercial purposes
+ * as part of the M.A.M.E. (Multiple Arcade Machine Emulator) project.
+ * The licensing terms of MAME apply to this piece of code for the MAME
+ * project and derviative works, as defined by the MAME license. You
+ * may opt to make modifications, improvements or derivative works under
+ * that same conditions, and the MAME project may opt to keep
+ * modifications, improvements or derivatives under their terms exclusively.
+ *
+ * - Alternatively you can choose to apply the terms of the "GPL" (see
+ * below) to this - and only this - piece of code or your derivative works.
+ * Note that in no case your choice can have any impact on any other
+ * source code of the MAME project, or binary, or executable, be it closely
+ * or losely related to this piece of code.
+ *
+ * - At your choice you are also free to remove either licensing terms from
+ * this file and continue to use it under only one of the two licenses. Do this
+ * if you think that licenses are not compatible (enough) for you, or if you
+ * consider either license 'too restrictive' or 'too free'.
+ *
+ * - GPL (GNU General Public License)
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * This work is solely based on the
+ * 'Intel(tm) UPI(tm)-41AH/42AH Users Manual'
+ *
+ *
+ * **** Change Log ****
+ * HJB (19-Dec-2004) changed version to 0.3
+ * - Tried to handle accesses to registers in get_info/set_info
+ * before i8x41.ram is is initialized.
+ * - cosmetics: readability in get_info/set_info, replaced non-ASCII
+ * codes in comments, add 'ex' tabstop definition
+ *
+ * TLP (10-Jan-2003) Changed ver from 0.1 to 0.2
+ * - Changed the internal RAM mask from 3Fh to FFh . The i8x41/i8x42 have
+ * 128/256 bytes of internal RAM respectively.
+ * - Added output port data to the debug register view window.
+ * - Added some missing break commands to the set_reg switch function.
+ * - Changed Ports 1 and 2 to latched types (Quasi-bidirectional).
+ * - Stopped illegal access to Port 0 and 3 (they don't exist).
+ * - Changed ANLD, ORLD and MOVD instructions to act through Port 2 in
+ * nibble mode.
+ * - Copied F0 and moved F1 flags to the STATE flag bits where they belong.
+ * - Corrected the 'addr' field by changing it from UINT8 to UINT16 for:
+ * 'INC @Rr' 'MOV @Rr,A' 'MOV @Rr,#N' 'XCH A,@Rr' 'XCHD A,@Rr'
+ * - Added mask to TIMER when the TEST1 Counter overflows.
+ * - Seperated the prescaler out of the timer/counter, in order to correct
+ * the TEST1 input counter step.
+ * - Moved TEST0 and TEST1 status flags out of the STATE register.
+ * STATE register uses these upper bits for user definable purposes.
+ * - TEST0 and TEST1 input lines are now sampled during the JTx/JNTx
+ * instructions.
+ * - Two methods for updating TEST1 input during counter mode are now
+ * supported depending on the mode of use required.
+ * You can use the Interrupt method, or input port read method.
+ * - TIMER is now only controlled by the timer or counter (not both)
+ * ie, When Starting the Counter, Stop the Timer and viceversa.
+ * - Nested IRQs of any sort are no longer allowed, however IRQs can
+ * become pending while a current interrupt is being serviced.
+ * - IBF Interrupt now has priority over the Timer Interrupt, when they
+ * occur simultaneously.
+ * - Add the external Interrupt FLAGS (Port 24, Port 25).
+ * To Do:
+ * - Add the external DMA FLAGS (Port 26, Port 27). Page 4 and 37
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "i8x41.h"
+
+typedef struct {
+ UINT16 ppc;
+ UINT16 pc;
+ UINT8 timer;
+ UINT8 prescaler;
+ UINT16 subtype;
+ UINT8 a;
+ UINT8 psw;
+ UINT8 state;
+ UINT8 enable;
+ UINT8 control;
+ UINT8 dbbi;
+ UINT8 dbbo;
+ UINT8 p1;
+ UINT8 p2;
+ UINT8 p2_hs;
+ UINT8 *ram;
+ int (*irq_callback)(int irqline);
+} I8X41;
+
+int i8x41_ICount;
+
+static I8X41 i8x41;
+
+#define RM(a) program_read_byte_8(a)
+#define WM(a,v) program_write_byte_8(a,v)
+#define RP(a) io_read_byte_8(a)
+#define WP(a,v) io_write_byte_8(a,v)
+#define ROP(pc) cpu_readop(pc)
+#define ROP_ARG(pc) cpu_readop_arg(pc)
+
+/* PC vectors */
+#define V_RESET 0x000 /* power on address */
+#define V_IBF 0x003 /* input buffer full interrupt vector */
+#define V_TIMER 0x007 /* timer/counter interrupt vector */
+
+/*
+ * Memory locations
+ * Note:
+ * 000-3ff internal ROM for 8x41 (1K)
+ * 400-7ff (more) internal for 8x42 type (2K)
+ * 800-8ff internal RAM
+ */
+#define M_IRAM 0x800 /* internal RAM is mapped here */
+#define M_BANK0 0x800 /* register bank 0 (8 times 8 bits) */
+#define M_STACK 0x808 /* stack (8 times 16 bits) */
+#define M_BANK1 0x818 /* register bank 1 (8 times 8 bits) */
+#define M_USER 0x820 /* user memory (224 times 8 bits) */
+
+/* PSW flag bits */
+#define FC 0x80 /* carry flag */
+#define FA 0x40 /* auxiliary carry flag */
+#define Ff0 0x20 /* flag 0 - same flag as F0 below */
+#define BS 0x10 /* bank select */
+#define FU 0x08 /* unused */
+#define SP 0x07 /* lower three bits are used as stack pointer */
+
+/* STATE flag bits */
+#define OBF 0x01 /* output buffer full */
+#define IBF 0x02 /* input buffer full */
+#define F0 0x04 /* flag 0 - same flag as Ff0 above */
+#define F1 0x08 /* flag 1 */
+
+/* ENABLE flag bits */
+#define IBFI 0x01 /* input buffer full interrupt */
+#define TCNTI 0x02 /* timer/counter interrupt */
+#define DMA 0x04 /* DMA mode */
+#define FLAGS 0x08 /* FLAGS mode */
+#define T 0x10 /* timer */
+#define CNT 0x20 /* counter */
+
+/* CONTROL flag bits */
+#define IBFI_EXEC 0x01 /* IBFI is currently being serviced */
+#define IBFI_PEND 0x02 /* IBFI is pending */
+#define TIRQ_EXEC 0x04 /* Timer interrupt is currently being serviced */
+#define TIRQ_PEND 0x08 /* Timer interrupt is pending */
+#define TEST1 0x10 /* Test1 line mode */
+#define TOVF 0x20 /* Timer Overflow Flag */
+
+#define IRQ_EXEC 0x05 /* Mask for IRQs being serviced */
+#define IRQ_PEND 0x0a /* Mask for IRQs pending */
+
+
+/* shorter names for the I8x41 structure elements */
+#define PPC i8x41.ppc
+#define PC i8x41.pc
+#define A i8x41.a
+#define PSW i8x41.psw
+#define DBBI i8x41.dbbi
+#define DBBO i8x41.dbbo
+#define R(n) i8x41.ram[((PSW & BS) ? M_BANK1:M_BANK0)+(n)]
+#define STATE i8x41.state
+#define ENABLE i8x41.enable
+#define TIMER i8x41.timer
+#define PRESCALER i8x41.prescaler
+#define P1 i8x41.p1
+#define P2 i8x41.p2
+#define P2_HS i8x41.p2_hs /* Port 2 Hand Shaking */
+#define CONTROL i8x41.control
+
+
+static void set_irq_line(int irqline, int state);
+
+
+/************************************************************************
+ * Shortcuts
+ ************************************************************************/
+
+INLINE void PUSH_PC_TO_STACK(void)
+{
+ WM( M_STACK + (PSW&SP) * 2 + 0, PC & 0xff);
+ WM( M_STACK + (PSW&SP) * 2 + 1, ((PC >> 8) & 0x0f) | (PSW & 0xf0) );
+ PSW = (PSW & ~SP) | ((PSW + 1) & SP);
+}
+
+
+/************************************************************************
+ * Emulate the Instructions
+ ************************************************************************/
+
+/***********************************
+ * illegal opcodes
+ ***********************************/
+INLINE void illegal(void)
+{
+ logerror("i8x41 #%d: illegal opcode at 0x%03x: %02x\n", cpu_getactivecpu(), PC, ROP(PC));
+}
+
+/***********************************
+ * 0110 1rrr * ADD A,Rr
+ ***********************************/
+INLINE void add_r(int r)
+{
+ UINT8 res = A + R(r);
+ if( res < A ) PSW |= FC;
+ if( (res & 0x0f) < (A & 0x0f) ) PSW |= FA;
+ A = res;
+}
+
+/***********************************
+ * 0110 000r
+ * ADD A,@Rr
+ ***********************************/
+INLINE void add_rm(int r)
+{
+ UINT8 res = A + RM( M_IRAM + (R(r) & I8X42_intRAM_MASK) );
+ if( res < A ) PSW |= FC;
+ if( (res & 0x0f) < (A & 0x0f) ) PSW |= FA;
+ A = res;
+}
+
+/***********************************
+ * 0000 0011 7654 3210
+ * ADD A,#n
+ ***********************************/
+INLINE void add_i(void)
+{
+ UINT8 res = A + ROP_ARG(PC);
+ PC++;
+ if( res < A ) PSW |= FC;
+ if( (res & 0x0f) < (A & 0x0f) ) PSW |= FA;
+ A = res;
+}
+
+/***********************************
+ * 0111 1rrr
+ * ADDC A,Rr
+ ***********************************/
+INLINE void addc_r(int r)
+{
+ UINT8 res = A + R(r) + (PSW >> 7);
+ if( res <= A ) PSW |= FC;
+ if( (res & 0x0f) <= (A & 0x0f) ) PSW |= FA;
+ A = res;
+}
+
+/***********************************
+ * 0111 000r
+ * ADDC A,@Rr
+ ***********************************/
+INLINE void addc_rm(int r)
+{
+ UINT8 res = A + RM( M_IRAM + (R(r) & I8X42_intRAM_MASK) ) + (PSW >> 7);
+ if( res <= A ) PSW |= FC;
+ if( (res & 0x0f) <= (A & 0x0f) ) PSW |= FA;
+ A = res;
+}
+
+/***********************************
+ * 0001 0011 7654 3210
+ * ADDC A,#n
+ ***********************************/
+INLINE void addc_i(void)
+{
+ UINT8 res = A + ROP_ARG(PC);
+ PC++;
+ if( res < A ) PSW |= FC;
+ if( (res & 0x0f) < (A & 0x0f) ) PSW |= FA;
+ A = res;
+}
+
+/***********************************
+ * 0101 1rrr
+ * ANL A,Rr
+ ***********************************/
+INLINE void anl_r(int r)
+{
+ A = A & R(r);
+}
+
+/***********************************
+ * 0101 000r
+ * ANL A,@Rr
+ ***********************************/
+INLINE void anl_rm(int r)
+{
+ A = A & RM( M_IRAM + (R(r) & I8X42_intRAM_MASK) );
+}
+
+/***********************************
+ * 0101 0011 7654 3210
+ * ANL A,#n
+ ***********************************/
+INLINE void anl_i(void)
+{
+ A = A & ROP_ARG(PC);
+ PC++;
+}
+
+/***********************************
+ * 1001 10pp 7654 3210
+ * ANL Pp,#n
+ ***********************************/
+INLINE void anl_p_i(int p)
+{
+ UINT8 val = ROP_ARG(PC);
+ PC++;
+ /* changed to latched port scheme */
+ switch (p)
+ {
+ case 00: break; /* invalid port */
+ case 01: P1 &= val; WP(p, P1); break;
+ case 02: P2 &= val; WP(p, (P2 & P2_HS) ); break;
+ case 03: break; /* invalid port */
+ default: break;
+ }
+}
+
+/***********************************
+ * 1001 11pp 7654 3210
+ * ANLD Pp,A
+ ***********************************/
+INLINE void anld_p_a(int p)
+{
+ /* added proper expanded port setup */
+ WP(2, (P2 & 0xf0) | 0x0c | p); /* AND mode */
+ WP(I8X41_ps, 0); /* activate command strobe */
+ WP(2, (A & 0x0f)); /* Expander to take care of AND function */
+ WP(I8X41_ps, 1); /* release command strobe */
+}
+
+/***********************************
+ * aaa1 0100 7654 3210
+ * CALL addr
+ ***********************************/
+INLINE void call_i(int page)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC++;
+ PUSH_PC_TO_STACK();
+ PC = page | adr;
+}
+
+/***********************************
+ * 0010 0111
+ * CLR A
+ ***********************************/
+INLINE void clr_a(void)
+{
+ A = 0;
+}
+
+/***********************************
+ * 1001 0111
+ * CLR C
+ ***********************************/
+INLINE void clr_c(void)
+{
+ PSW &= ~FC;
+}
+
+/***********************************
+ * 1000 0101
+ * CLR F0
+ ***********************************/
+INLINE void clr_f0(void)
+{
+ PSW &= ~Ff0;
+ STATE &= ~F0;
+}
+
+/***********************************
+ * 1010 0101
+ * CLR F1
+ ***********************************/
+INLINE void clr_f1(void)
+{
+ STATE &= ~F1;
+}
+
+/***********************************
+ * 0011 0111
+ * CPL A
+ ***********************************/
+INLINE void cpl_a(void)
+{
+ A = ~A;
+}
+
+/***********************************
+ * 1010 0111
+ * CPL C
+ ***********************************/
+INLINE void cpl_c(void)
+{
+ PSW ^= FC;
+}
+
+/***********************************
+ * 1001 0101
+ * CPL F0
+ ***********************************/
+INLINE void cpl_f0(void)
+{
+ PSW ^= Ff0;
+ STATE ^= F0;
+}
+
+/***********************************
+ * 1011 0101
+ * CPL F1
+ ***********************************/
+INLINE void cpl_f1(void)
+{
+ STATE ^= F1;
+}
+
+/***********************************
+ * 0101 0111
+ * DA A
+ ***********************************/
+INLINE void da_a(void)
+{
+ UINT8 res = A + ((PSW & FA) || ((A & 0x0f) > 0x09)) ? 0x06 : 0x00;
+ if( (PSW & FC) || ((res & 0xf0) > 0x90) )
+ res += 0x60;
+ if( res < A )
+ PSW |= FC;
+ else
+ PSW &= ~FC;
+ A = res;
+}
+
+/***********************************
+ * 0000 0111
+ * DEC A
+ ***********************************/
+INLINE void dec_a(void)
+{
+ A -= 1;
+}
+
+/***********************************
+ * 1100 1rrr
+ * DEC Rr
+ ***********************************/
+INLINE void dec_r(int r)
+{
+ R(r) -= 1;
+}
+
+/***********************************
+ * 0001 0101
+ * DIS I
+ ***********************************/
+INLINE void dis_i(void)
+{
+ ENABLE &= ~IBFI; /* disable input buffer full interrupt */
+}
+
+/***********************************
+ * 0011 0101
+ * DIS TCNTI
+ ***********************************/
+INLINE void dis_tcnti(void)
+{
+ ENABLE &= ~TCNTI; /* disable timer/counter interrupt */
+}
+
+/***********************************
+ * 0111 1rrr 7654 3210
+ * DJNZ Rr,addr
+ ***********************************/
+INLINE void djnz_r_i(int r)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC++;
+ R(r) -= 1;
+ if( R(r) )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 1110 0101
+ * EN DMA
+ ***********************************/
+INLINE void en_dma(void)
+{
+ ENABLE |= DMA; /* enable DMA handshake lines */
+ P2_HS &= 0xbf;
+ WP(0x02, (P2 & P2_HS) );
+}
+
+/***********************************
+ * 1111 0101
+ * EN FLAGS
+ ***********************************/
+INLINE void en_flags(void)
+{
+ if( 0 == (ENABLE & FLAGS) )
+ {
+ /* Configure upper lines on Port 2 for IRQ handshaking (P24 and P25) */
+
+ ENABLE |= FLAGS;
+ if( STATE & OBF ) P2_HS |= 0x10;
+ else P2_HS &= 0xef;
+ if( STATE & IBF ) P2_HS |= 0x20;
+ else P2_HS &= 0xdf;
+ WP(0x02, (P2 & P2_HS) );
+ }
+}
+
+/***********************************
+ * 0000 0101
+ * EN I
+ ***********************************/
+INLINE void en_i(void)
+{
+ if( 0 == (ENABLE & IBFI) )
+ {
+ ENABLE |= IBFI; /* enable input buffer full interrupt */
+ if( STATE & IBF ) /* already got data in the buffer? */
+ set_irq_line(I8X41_INT_IBF, HOLD_LINE);
+ }
+}
+
+/***********************************
+ * 0010 0101
+ * EN TCNTI
+ ***********************************/
+INLINE void en_tcnti(void)
+{
+ ENABLE |= TCNTI; /* enable timer/counter interrupt */
+}
+
+/***********************************
+ * 0010 0010
+ * IN A,DBB
+ ***********************************/
+INLINE void in_a_dbb(void)
+{
+ if( i8x41.irq_callback )
+ (*i8x41.irq_callback)(I8X41_INT_IBF);
+
+ STATE &= ~IBF; /* clear input buffer full flag */
+ if( ENABLE & FLAGS )
+ {
+ P2_HS &= 0xdf;
+ if( STATE & OBF ) P2_HS |= 0x10;
+ else P2_HS &= 0xef;
+ WP(0x02, (P2 & P2_HS) ); /* Clear the DBBI IRQ out on P25 */
+ }
+ A = DBBI;
+}
+
+/***********************************
+ * 0000 10pp
+ * IN A,Pp
+ ***********************************/
+INLINE void in_a_p(int p)
+{
+ /* changed to latched port scheme */
+ switch( p )
+ {
+ case 00: break; /* invalid port */
+ case 01: A = (RP(p) & P1); break;
+ case 02: A = (RP(p) & P2); break;
+ case 03: break; /* invalid port */
+ default: break;
+ }
+}
+
+/***********************************
+ * 0001 0111
+ * INC A
+ ***********************************/
+INLINE void inc_a(void)
+{
+ A += 1;
+}
+
+/***********************************
+ * 0001 1rrr
+ * INC Rr
+ ***********************************/
+INLINE void inc_r(int r)
+{
+ R(r) += 1;
+}
+
+/***********************************
+ * 0001 000r
+ * INC @ Rr
+ ***********************************/
+INLINE void inc_rm(int r)
+{
+ UINT16 addr = M_IRAM + (R(r) & I8X42_intRAM_MASK);
+ WM( addr, RM(addr) + 1 );
+}
+
+/***********************************
+ * bbb1 0010
+ * JBb addr
+ ***********************************/
+INLINE void jbb_i(int bit)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( A & (1 << bit) )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 1111 0110
+ * JC addr
+ ***********************************/
+INLINE void jc_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( PSW & FC )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 1011 0110
+ * JF0 addr
+ ***********************************/
+INLINE void jf0_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( STATE & F0 )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 0111 0110
+ * JF1 addr
+ ***********************************/
+INLINE void jf1_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( STATE & F1 )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * aaa0 0100
+ * JMP addr
+ ***********************************/
+INLINE void jmp_i(int page)
+{
+ /* err.. do we have 10 or 11 PC bits?
+ * CALL is said to use 0aa1 (4 pages)
+ * JMP is said to use aaa0 (8 pages)
+ */
+ UINT8 adr = ROP_ARG(PC);
+ PC = page | adr;
+}
+
+/***********************************
+ * 1011 0011
+ * JMP @ A
+ ***********************************/
+INLINE void jmpp_a(void)
+{
+ UINT16 adr = (PC & 0x700) | A;
+ PC = (PC & 0x700) | RM(adr);
+}
+
+/***********************************
+ * 1110 0110
+ * JNC addr
+ ***********************************/
+INLINE void jnc_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( !(PSW & FC) )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 1101 0110
+ * JNIBF addr
+ ***********************************/
+INLINE void jnibf_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( 0 == (STATE & IBF) )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 0010 0110
+ * JNT0 addr
+ ***********************************/
+INLINE void jnt0_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( 0 == RP(I8X41_t0) )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 0100 0110
+ * JNT1 addr
+ ***********************************/
+INLINE void jnt1_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( !(ENABLE & CNT) )
+ {
+ UINT8 level = RP(I8X41_t1);
+ if( level ) CONTROL |= TEST1;
+ else CONTROL &= ~TEST1;
+ }
+ if( !(CONTROL & TEST1) )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 1001 0110
+ * JNZ addr
+ ***********************************/
+INLINE void jnz_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( A )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 1000 0110
+ * JOBF addr
+ ***********************************/
+INLINE void jobf_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( STATE & OBF )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 0001 0110
+ * JTF addr
+ ***********************************/
+INLINE void jtf_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( CONTROL & TOVF )
+ PC = (PC & 0x700) | adr;
+ CONTROL &= ~TOVF;
+}
+
+/***********************************
+ * 0011 0110
+ * JT0 addr
+ ***********************************/
+INLINE void jt0_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( RP(I8X41_t0) )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 0101 0110
+ * JT1 addr
+ ***********************************/
+INLINE void jt1_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( !(ENABLE & CNT) )
+ {
+ UINT8 level = RP(I8X41_t1);
+ if( level ) CONTROL |= TEST1;
+ else CONTROL &= ~TEST1;
+ }
+ if( (CONTROL & TEST1) )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 1100 0110
+ * JZ addr
+ ***********************************/
+INLINE void jz_i(void)
+{
+ UINT8 adr = ROP_ARG(PC);
+ PC += 1;
+ if( !A )
+ PC = (PC & 0x700) | adr;
+}
+
+/***********************************
+ * 0010 0011
+ * MOV A,#n
+ ***********************************/
+INLINE void mov_a_i(void)
+{
+ A = ROP(PC);
+ PC += 1;
+}
+
+/***********************************
+ * 1100 0111
+ * MOV A,PSW
+ ***********************************/
+INLINE void mov_a_psw(void)
+{
+ A = PSW;
+}
+
+/***********************************
+ * 1111 1rrr
+ * MOV A,Rr
+ ***********************************/
+INLINE void mov_a_r(int r)
+{
+ A = R(r);
+}
+
+/***********************************
+ * 1111 000r
+ * MOV A,Rr
+ ***********************************/
+INLINE void mov_a_rm(int r)
+{
+ A = RM( M_IRAM + (R(r) & I8X42_intRAM_MASK) );
+}
+
+/***********************************
+ * 0100 0010
+ * MOV A,T
+ ***********************************/
+INLINE void mov_a_t(void)
+{
+ A = TIMER;
+}
+
+/***********************************
+ * 1101 0111
+ * MOV PSW,A
+ ***********************************/
+INLINE void mov_psw_a(void)
+{
+ PSW = A;
+}
+
+/***********************************
+ * 1010 1rrr
+ * MOV Rr,A
+ ***********************************/
+INLINE void mov_r_a(int r)
+{
+ R(r) = A;
+}
+
+/***********************************
+ * 1011 1rrr
+ * MOV Rr,#n
+ ***********************************/
+INLINE void mov_r_i(int r)
+{
+ UINT8 val = ROP_ARG(PC);
+ PC += 1;
+ R(r) = val;
+}
+
+/***********************************
+ * 1010 000r
+ * MOV @Rr,A
+ ***********************************/
+INLINE void mov_rm_a(int r)
+{
+ WM( M_IRAM + (R(r) & I8X42_intRAM_MASK), A );
+}
+
+/***********************************
+ * 1011 000r
+ * MOV @Rr,#n
+ ***********************************/
+INLINE void mov_rm_i(int r)
+{
+ UINT8 val = ROP_ARG(PC);
+ PC += 1;
+ WM( M_IRAM + (R(r) & I8X42_intRAM_MASK), val );
+}
+
+/***********************************
+ * 1001 0000
+ * MOV STS,A
+ ***********************************/
+INLINE void mov_sts_a(void)
+{
+ STATE = (STATE & 0x0f) | (A & 0xf0);
+}
+
+/***********************************
+ * 0110 0010
+ * MOV T,A
+ ***********************************/
+INLINE void mov_t_a(void)
+{
+ TIMER = A;
+}
+
+/***********************************
+ * 0000 11pp
+ * MOVD A,Pp
+ ***********************************/
+INLINE void movd_a_p(int p)
+{
+ /* added proper expanded port setup */
+ WP(2, (P2 & 0xf0) | 0x00 | p); /* READ mode */
+ WP(I8X41_ps, 0); /* activate command strobe */
+ A = RP(2) & 0xf;
+ WP(I8X41_ps, 1); /* release command strobe */
+}
+
+/***********************************
+ * 0011 11pp
+ * MOVD Pp,A
+ ***********************************/
+INLINE void movd_p_a(int p)
+{
+ /* added proper expanded port setup */
+ WP(2, (P2 & 0xf0) | 0x04 | p); /* WRITE mode */
+ WP(I8X41_ps, 0); /* activate command strobe */
+ WP(2, A & 0x0f);
+ WP(I8X41_ps, 1); /* release command strobe */
+}
+
+/***********************************
+ * 1010 0011
+ * MOVP A,@A
+ ***********************************/
+INLINE void movp_a_am(void)
+{
+ UINT16 addr = (PC & 0x700) | A;
+ A = RM(addr);
+}
+
+/***********************************
+ * 1110 0011
+ * MOVP3 A,@A
+ ***********************************/
+INLINE void movp3_a_am(void)
+{
+ UINT16 addr = 0x300 | A;
+ A = RM(addr);
+}
+
+/***********************************
+ * 0000 0000
+ * NOP
+ ***********************************/
+INLINE void nop(void)
+{
+}
+
+/***********************************
+ * 0100 1rrr
+ * ORL A,Rr
+ ***********************************/
+INLINE void orl_r(int r)
+{
+ A = A | R(r);
+}
+
+/***********************************
+ * 0100 000r
+ * ORL A,@Rr
+ ***********************************/
+INLINE void orl_rm(int r)
+{
+ A = A | RM( M_IRAM + (R(r) & I8X42_intRAM_MASK) );
+}
+
+/***********************************
+ * 0100 0011 7654 3210
+ * ORL A,#n
+ ***********************************/
+INLINE void orl_i(void)
+{
+ UINT8 val = ROP_ARG(PC);
+ PC++;
+ A = A | val;
+}
+
+/***********************************
+ * 1000 10pp 7654 3210
+ * ORL Pp,#n
+ ***********************************/
+INLINE void orl_p_i(int p)
+{
+ UINT8 val = ROP_ARG(PC);
+ PC++;
+ /* changed to latched port scheme */
+ switch (p)
+ {
+ case 00: break; /* invalid port */
+ case 01: P1 |= val; WP(p, P1); break;
+ case 02: P2 |= val; WP(p, P2); break;
+ case 03: break; /* invalid port */
+ default: break;
+ }
+}
+
+/***********************************
+ * 1000 11pp 7654 3210
+ * ORLD Pp,A
+ ***********************************/
+INLINE void orld_p_a(int p)
+{
+ /* added proper expanded port setup */
+ WP(2, (P2 & 0xf0) | 0x08 | p); /* OR mode */
+ WP(I8X41_ps, 0); /* activate command strobe */
+ WP(2, A & 0x0f); /* Expander to take care of OR function */
+ WP(I8X41_ps, 1); /* release command strobe */
+}
+
+/***********************************
+ * 0000 0010
+ * OUT DBB,A
+ ***********************************/
+INLINE void out_dbb_a(void)
+{
+ DBBO = A; /* DBB output buffer */
+ STATE |= OBF; /* assert the output buffer full flag */
+ if( ENABLE & FLAGS )
+ {
+ P2_HS |= 0x10;
+ if( STATE & IBF ) P2_HS |= 0x20;
+ else P2_HS &= 0xdf;
+ WP(0x02, (P2 & P2_HS) ); /* Assert the DBBO IRQ out on P24 */
+ }
+}
+
+/***********************************
+ * 0011 10pp
+ * OUT Pp,A
+ ***********************************/
+INLINE void out_p_a(int p)
+{
+ /* changed to latched port scheme */
+ switch (p)
+ {
+ case 00: break; /* invalid port */
+ case 01: WP(p, A); P1 = A; break;
+ case 02: WP(p, A); P2 = A; break;
+ case 03: break; /* invalid port */
+ default: break;
+ }
+}
+
+/***********************************
+ * 1000 0011
+ * RET
+ ***********************************/
+INLINE void ret(void)
+{
+ UINT8 msb;
+ PSW = (PSW & ~SP) | ((PSW - 1) & SP);
+ msb = RM(M_STACK + (PSW&SP) * 2 + 1);
+ PC = RM(M_STACK + (PSW&SP) * 2 + 0);
+ PC |= (msb << 8) & 0x700;
+}
+
+/***********************************
+ * 1001 0011
+ * RETR
+ ***********************************/
+INLINE void retr(void)
+{
+ UINT8 msb;
+ PSW = (PSW & ~SP) | ((PSW - 1) & SP);
+ msb = RM(M_STACK + (PSW&SP) * 2 + 1);
+ PC = RM(M_STACK + (PSW&SP) * 2 + 0);
+ PC |= (msb << 8) & 0x700;
+ PSW = (PSW & 0x0f) | (msb & 0xf0);
+ CONTROL &= ~IBFI_EXEC;
+ CONTROL &= ~TIRQ_EXEC;
+}
+
+/***********************************
+ * 1110 0111
+ * RL A
+ ***********************************/
+INLINE void rl_a(void)
+{
+ A = (A << 1) | (A >> 7);
+}
+
+/***********************************
+ * 1111 0111
+ * RLC A
+ ***********************************/
+INLINE void rlc_a(void)
+{
+ UINT8 c = PSW >> 7;
+ PSW = (PSW & ~FC) | (A >> 7);
+ A = (A << 1) | c;
+}
+
+/***********************************
+ * 0111 0111
+ * RR A
+ ***********************************/
+INLINE void rr_a(void)
+{
+ A = (A >> 1) | (A << 7);
+}
+
+/***********************************
+ * 0110 0111
+ * RRC A
+ ***********************************/
+INLINE void rrc_a(void)
+{
+ UINT8 c = PSW & 0x80;
+ PSW = (PSW & ~FC) | (A << 7);
+ A = (A >> 1) | c;
+}
+
+/***********************************
+ * 1100 0101
+ * SEL RB0
+ ***********************************/
+INLINE void sel_rb0(void)
+{
+ PSW &= ~BS;
+}
+
+/***********************************
+ * 1101 0101
+ * SEL RB1
+ ***********************************/
+INLINE void sel_rb1(void)
+{
+ PSW |= BS;
+}
+
+/***********************************
+ * 0110 0101
+ * STOP TCNT
+ ***********************************/
+INLINE void stop_tcnt(void)
+{
+ ENABLE &= ~(T|CNT);
+}
+
+/***********************************
+ * 0100 0101
+ * STRT CNT
+ ***********************************/
+INLINE void strt_cnt(void)
+{
+ ENABLE |= CNT;
+ ENABLE &= ~T;
+}
+
+/***********************************
+ * 0101 0101
+ * STRT T
+ ***********************************/
+INLINE void strt_t(void)
+{
+ ENABLE |= T;
+ ENABLE &= ~CNT;
+}
+
+/***********************************
+ * 0100 0111
+ * SWAP A
+ ***********************************/
+INLINE void swap_a(void)
+{
+ A = (A << 4) | (A >> 4);
+}
+
+/***********************************
+ * 0010 1rrr
+ * XCH A,Rr
+ ***********************************/
+INLINE void xch_a_r(int r)
+{
+ UINT8 tmp = R(r);
+ R(r) = A;
+ A = tmp;
+}
+
+/***********************************
+ * 0010 000r
+ * XCH A,@Rr
+ ***********************************/
+INLINE void xch_a_rm(int r)
+{
+ UINT16 addr = M_IRAM + (R(r) & I8X42_intRAM_MASK);
+ UINT8 tmp = RM(addr);
+ WM( addr, A );
+ A = tmp;
+}
+
+/***********************************
+ * 0011 000r
+ * XCHD A,@Rr
+ ***********************************/
+INLINE void xchd_a_rm(int r)
+{
+ UINT16 addr = M_IRAM + (R(r) & I8X42_intRAM_MASK);
+ UINT8 tmp = RM(addr);
+ WM( addr, (tmp & 0xf0) | (A & 0x0f) );
+ A = (A & 0xf0) | (tmp & 0x0f);
+}
+
+/***********************************
+ * 1101 1rrr
+ * XRL A,Rr
+ ***********************************/
+INLINE void xrl_r(int r)
+{
+ A = A ^ R(r);
+}
+
+/***********************************
+ * 1101 000r
+ * XRL A,@Rr
+ ***********************************/
+INLINE void xrl_rm(int r)
+{
+ A = A ^ RM( M_IRAM + (R(r) & I8X42_intRAM_MASK) );
+}
+
+/***********************************
+ * 1101 0011 7654 3210
+ * XRL A,#n
+ ***********************************/
+INLINE void xrl_i(void)
+{
+ UINT8 val = ROP_ARG(PC);
+ PC++;
+ A = A ^ val;
+}
+
+
+/***********************************************************************
+ * Cycle Timings
+ ***********************************************************************/
+
+static UINT8 i8x41_cycles[] = {
+ 1,1,1,2,2,1,1,1,2,2,2,2,2,2,2,2,
+ 1,1,2,2,2,1,2,1,1,1,1,1,1,1,1,1,
+ 1,1,1,2,2,1,2,1,1,1,1,1,1,1,1,1,
+ 1,1,2,1,2,1,2,1,2,2,2,2,2,2,2,2,
+ 1,1,1,2,2,1,2,1,1,1,1,1,1,1,1,1,
+ 1,1,2,2,2,1,2,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1,
+ 1,1,1,2,2,1,2,1,2,2,2,2,2,2,2,2,
+ 1,1,2,2,1,1,2,1,2,2,2,2,2,2,2,2,
+ 1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,
+ 1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,
+ 1,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1,
+ 1,1,1,2,2,1,2,1,1,1,1,1,1,1,1,1,
+ 1,1,2,1,2,1,2,1,2,2,2,2,2,2,2,2
+};
+
+
+/****************************************************************************
+ * Inits CPU emulation
+ ****************************************************************************/
+
+static void i8x41_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ i8x41.irq_callback = irqcallback;
+
+ state_save_register_item("i8x41", index, i8x41.ppc);
+ state_save_register_item("i8x41", index, i8x41.pc);
+ state_save_register_item("i8x41", index, i8x41.timer);
+ state_save_register_item("i8x41", index, i8x41.prescaler);
+ state_save_register_item("i8x41", index, i8x41.subtype);
+ state_save_register_item("i8x41", index, i8x41.a);
+ state_save_register_item("i8x41", index, i8x41.psw);
+ state_save_register_item("i8x41", index, i8x41.state);
+ state_save_register_item("i8x41", index, i8x41.enable);
+ state_save_register_item("i8x41", index, i8x41.control);
+ state_save_register_item("i8x41", index, i8x41.dbbi);
+ state_save_register_item("i8x41", index, i8x41.dbbo);
+ state_save_register_item("i8x41", index, i8x41.p1);
+ state_save_register_item("i8x41", index, i8x41.p2);
+ state_save_register_item("i8x41", index, i8x41.p2_hs);
+}
+
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+
+static void i8x41_reset(void)
+{
+ int (*save_irqcallback)(int) = i8x41.irq_callback;
+ memset(&i8x41, 0, sizeof(I8X41));
+ i8x41.irq_callback = save_irqcallback;
+
+ /* default to 8041 behaviour for DBBI/DBBO and extended commands */
+ i8x41.subtype = 8041;
+ /* ugly hack.. excuse my lazyness */
+ i8x41.ram = memory_region(REGION_CPU1 + cpu_getactivecpu());
+ ENABLE = IBFI | TCNTI;
+ DBBI = 0xff;
+ DBBO = 0xff;
+ /* Set Ports 1 and 2 to input mode */
+ P1 = 0xff;
+ P2 = 0xff;
+ P2_HS= 0xff;
+}
+
+
+/****************************************************************************
+ * Shut down CPU emulation
+ ****************************************************************************/
+
+static void i8x41_exit(void)
+{
+ /* nothing to do */
+}
+
+
+/****************************************************************************
+ * Execute cycles - returns number of cycles actually run
+ ****************************************************************************/
+
+static int i8x41_execute(int cycles)
+{
+ int inst_cycles, T1_level;
+
+ i8x41_ICount = cycles;
+
+ do
+ {
+ UINT8 op = cpu_readop(PC);
+
+ PPC = PC;
+
+ CALL_MAME_DEBUG;
+
+ PC += 1;
+ i8x41_ICount -= i8x41_cycles[op];
+
+ switch( op )
+ {
+ /* opcode cycles bitmask */
+ case 0x00: /* 1: 0000 0000 */
+ nop();
+ break;
+ case 0x01: /* 1: 0000 0001 */
+ illegal();
+ break;
+ case 0x02: /* 1: 0000 0010 */
+ out_dbb_a();
+ break;
+ case 0x03: /* 2: 0000 0011 */
+ add_i();
+ break;
+ case 0x04: /* 2: aaa0 0100 */
+ jmp_i(0x000);
+ break;
+ case 0x05: /* 1: 0000 0101 */
+ en_i();
+ break;
+ case 0x06: /* 1: 0000 0110 */
+ illegal();
+ break;
+ case 0x07: /* 1: 0000 0111 */
+ dec_a();
+ break;
+ case 0x08: /* 2: 0000 10pp */
+ case 0x09: /* 2: 0000 10pp */
+ case 0x0a: /* 2: 0000 10pp */
+ case 0x0b: /* 2: 0000 10pp */
+ in_a_p(op & 3);
+ break;
+ case 0x0c: /* 2: 0000 11pp */
+ case 0x0d: /* 2: 0000 11pp */
+ case 0x0e: /* 2: 0000 11pp */
+ case 0x0f: /* 2: 0000 11pp */
+ movd_a_p(op & 3);
+ break;
+ case 0x10: /* 1: 0001 000r */
+ inc_rm(0);
+ break;
+ case 0x11: /* 1: 0001 000r */
+ inc_rm(1);
+ break;
+ case 0x12: /* 2: bbb1 0010 */
+ jbb_i(0);
+ break;
+ case 0x13: /* 2: 0001 0011 */
+ addc_i();
+ break;
+ case 0x14: /* 2: aaa1 0100 */
+ call_i(0x000);
+ break;
+ case 0x15: /* 1: 0001 0101 */
+ dis_i();
+ break;
+ case 0x16: /* 2: 0001 0110 */
+ jtf_i();
+ break;
+ case 0x17: /* 1: 0001 0111 */
+ inc_a();
+ break;
+ case 0x18: /* 1: 0001 1rrr */
+ case 0x19: /* 1: 0001 1rrr */
+ case 0x1a: /* 1: 0001 1rrr */
+ case 0x1b: /* 1: 0001 1rrr */
+ case 0x1c: /* 1: 0001 1rrr */
+ case 0x1d: /* 1: 0001 1rrr */
+ case 0x1e: /* 1: 0001 1rrr */
+ case 0x1f: /* 1: 0001 1rrr */
+ inc_r(op & 7);
+ break;
+ case 0x20: /* 1: 0010 000r */
+ xch_a_rm(0);
+ break;
+ case 0x21: /* 1: 0010 000r */
+ xch_a_rm(1);
+ break;
+ case 0x22: /* 1: 0010 0010 */
+ in_a_dbb();
+ break;
+ case 0x23: /* 2: 0010 0011 */
+ mov_a_i();
+ break;
+ case 0x24: /* 2: aaa0 0100 */
+ jmp_i(0x100);
+ break;
+ case 0x25: /* 1: 0010 0101 */
+ en_tcnti();
+ break;
+ case 0x26: /* 2: 0010 0110 */
+ jnt0_i();
+ break;
+ case 0x27: /* 1: 0010 0111 */
+ clr_a();
+ break;
+ case 0x28: /* 1: 0010 1rrr */
+ case 0x29: /* 1: 0010 1rrr */
+ case 0x2a: /* 1: 0010 1rrr */
+ case 0x2b: /* 1: 0010 1rrr */
+ case 0x2c: /* 1: 0010 1rrr */
+ case 0x2d: /* 1: 0010 1rrr */
+ case 0x2e: /* 1: 0010 1rrr */
+ case 0x2f: /* 1: 0010 1rrr */
+ xch_a_r(op & 7);
+ break;
+ case 0x30: /* 1: 0011 000r */
+ xchd_a_rm(0);
+ break;
+ case 0x31: /* 1: 0011 000r */
+ xchd_a_rm(1);
+ break;
+ case 0x32: /* 2: bbb1 0010 */
+ jbb_i(1);
+ break;
+ case 0x33: /* 1: 0011 0101 */
+ illegal();
+ break;
+ case 0x34: /* 2: aaa1 0100 */
+ call_i(0x100);
+ break;
+ case 0x35: /* 1: 0000 0101 */
+ dis_tcnti();
+ break;
+ case 0x36: /* 2: 0011 0110 */
+ jt0_i();
+ break;
+ case 0x37: /* 1: 0011 0111 */
+ cpl_a();
+ break;
+ case 0x38: /* 2: 0011 10pp */
+ case 0x39: /* 2: 0011 10pp */
+ case 0x3a: /* 2: 0011 10pp */
+ case 0x3b: /* 2: 0011 10pp */
+ out_p_a(op & 3);
+ break;
+ case 0x3c: /* 2: 0011 11pp */
+ case 0x3d: /* 2: 0011 11pp */
+ case 0x3e: /* 2: 0011 11pp */
+ case 0x3f: /* 2: 0011 11pp */
+ movd_p_a(op & 3);
+ break;
+ case 0x40: /* 1: 0100 000r */
+ orl_rm(0);
+ break;
+ case 0x41: /* 1: 0100 000r */
+ orl_rm(1);
+ break;
+ case 0x42: /* 1: 0100 0010 */
+ mov_a_t();
+ break;
+ case 0x43: /* 2: 0100 0011 */
+ orl_i();
+ break;
+ case 0x44: /* 2: aaa0 0100 */
+ jmp_i(0x200);
+ break;
+ case 0x45: /* 1: 0100 0101 */
+ strt_cnt();
+ break;
+ case 0x46: /* 2: 0100 0110 */
+ jnt1_i();
+ break;
+ case 0x47: /* 1: 0100 0111 */
+ swap_a();
+ break;
+ case 0x48: /* 1: 0100 1rrr */
+ case 0x49: /* 1: 0100 1rrr */
+ case 0x4a: /* 1: 0100 1rrr */
+ case 0x4b: /* 1: 0100 1rrr */
+ case 0x4c: /* 1: 0100 1rrr */
+ case 0x4d: /* 1: 0100 1rrr */
+ case 0x4e: /* 1: 0100 1rrr */
+ case 0x4f: /* 1: 0100 1rrr */
+ orl_r(op & 7);
+ break;
+ case 0x50: /* 1: 0101 000r */
+ anl_rm(0);
+ break;
+ case 0x51: /* 1: 0101 000r */
+ anl_rm(1);
+ break;
+ case 0x52: /* 2: bbb1 0010 */
+ jbb_i(2);
+ break;
+ case 0x53: /* 2: 0101 0011 */
+ anl_i();
+ break;
+ case 0x54: /* 2: aaa1 0100 */
+ call_i(0x200);
+ break;
+ case 0x55: /* 1: 0101 0101 */
+ strt_t();
+ break;
+ case 0x56: /* 2: 0101 0110 */
+ jt1_i();
+ break;
+ case 0x57: /* 1: 0101 0111 */
+ da_a();
+ break;
+ case 0x58: /* 1: 0101 1rrr */
+ case 0x59: /* 1: 0101 1rrr */
+ case 0x5a: /* 1: 0101 1rrr */
+ case 0x5b: /* 1: 0101 1rrr */
+ case 0x5c: /* 1: 0101 1rrr */
+ case 0x5d: /* 1: 0101 1rrr */
+ case 0x5e: /* 1: 0101 1rrr */
+ case 0x5f: /* 1: 0101 1rrr */
+ anl_r(op & 7);
+ break;
+ case 0x60: /* 1: 0110 000r */
+ add_rm(0);
+ break;
+ case 0x61: /* 1: 0110 000r */
+ add_rm(1);
+ break;
+ case 0x62: /* 1: 0110 0010 */
+ mov_t_a();
+ break;
+ case 0x63: /* 1: 0110 0011 */
+ illegal();
+ break;
+ case 0x64: /* 2: aaa0 0100 */
+ jmp_i(0x300);
+ break;
+ case 0x65: /* 1: 0110 0101 */
+ stop_tcnt();
+ break;
+ case 0x66: /* 1: 0110 0110 */
+ illegal();
+ break;
+ case 0x67: /* 1: 0110 0111 */
+ rrc_a();
+ break;
+ case 0x68: /* 1: 0110 1rrr */
+ case 0x69: /* 1: 0110 1rrr */
+ case 0x6a: /* 1: 0110 1rrr */
+ case 0x6b: /* 1: 0110 1rrr */
+ case 0x6c: /* 1: 0110 1rrr */
+ case 0x6d: /* 1: 0110 1rrr */
+ case 0x6e: /* 1: 0110 1rrr */
+ case 0x6f: /* 1: 0110 1rrr */
+ add_r(op & 7);
+ break;
+ case 0x70: /* 1: 0111 000r */
+ addc_rm(0);
+ break;
+ case 0x71: /* 1: 0111 000r */
+ addc_rm(1);
+ break;
+ case 0x72: /* 2: bbb1 0010 */
+ jbb_i(3);
+ break;
+ case 0x73: /* 1: 0111 0011 */
+ illegal();
+ break;
+ case 0x74: /* 2: aaa1 0100 */
+ call_i(0x300);
+ break;
+ case 0x75: /* 1: 0111 0101 */
+ illegal();
+ break;
+ case 0x76: /* 2: 0111 0110 */
+ jf1_i();
+ break;
+ case 0x77: /* 1: 0111 0111 */
+ rr_a();
+ break;
+ case 0x78: /* 1: 0111 1rrr */
+ case 0x79: /* 1: 0111 1rrr */
+ case 0x7a: /* 1: 0111 1rrr */
+ case 0x7b: /* 1: 0111 1rrr */
+ case 0x7c: /* 1: 0111 1rrr */
+ case 0x7d: /* 1: 0111 1rrr */
+ case 0x7e: /* 1: 0111 1rrr */
+ case 0x7f: /* 1: 0111 1rrr */
+ addc_r(op & 7);
+ break;
+ case 0x80: /* 1: 1000 0000 */
+ illegal();
+ break;
+ case 0x81: /* 1: 1000 0001 */
+ illegal();
+ break;
+ case 0x82: /* 1: 1000 0010 */
+ illegal();
+ break;
+ case 0x83: /* 2: 1000 0011 */
+ ret();
+ break;
+ case 0x84: /* 2: aaa0 0100 */
+ jmp_i(0x400);
+ break;
+ case 0x85: /* 1: 1000 0101 */
+ clr_f0();
+ break;
+ case 0x86: /* 2: 1000 0110 */
+ jobf_i();
+ break;
+ case 0x87: /* 1: 1000 0111 */
+ illegal();
+ break;
+ case 0x88: /* 2: 1000 10pp */
+ case 0x89: /* 2: 1000 10pp */
+ case 0x8a: /* 2: 1000 10pp */
+ case 0x8b: /* 2: 1000 10pp */
+ orl_p_i(op & 3);
+ break;
+ case 0x8c: /* 2: 1000 11pp */
+ case 0x8d: /* 2: 1000 11pp */
+ case 0x8e: /* 2: 1000 11pp */
+ case 0x8f: /* 2: 1000 11pp */
+ orld_p_a(op & 7);
+ break;
+ case 0x90: /* 1: 1001 0000 */
+ mov_sts_a();
+ break;
+ case 0x91: /* 1: 1001 0001 */
+ illegal();
+ break;
+ case 0x92: /* 2: bbb1 0010 */
+ jbb_i(4);
+ break;
+ case 0x93: /* 2: 1001 0011 */
+ retr();
+ break;
+ case 0x94: /* 1: aaa1 0100 */
+ call_i(0x400);
+ break;
+ case 0x95: /* 1: 1001 0101 */
+ cpl_f0();
+ break;
+ case 0x96: /* 2: 1001 0110 */
+ jnz_i();
+ break;
+ case 0x97: /* 1: 1001 0111 */
+ clr_c();
+ break;
+ case 0x98: /* 2: 1001 10pp , illegal port */
+ case 0x99: /* 2: 1001 10pp */
+ case 0x9a: /* 2: 1001 10pp */
+ case 0x9b: /* 2: 1001 10pp , illegal port */
+ anl_p_i(op & 3);
+ break;
+ case 0x9c: /* 2: 1001 11pp */
+ case 0x9d: /* 2: 1001 11pp */
+ case 0x9e: /* 2: 1001 11pp */
+ case 0x9f: /* 2: 1001 11pp */
+ anld_p_a(op & 7);
+ break;
+ case 0xa0: /* 1: 1010 000r */
+ mov_rm_a(0);
+ break;
+ case 0xa1: /* 1: 1010 000r */
+ mov_rm_a(1);
+ break;
+ case 0xa2: /* 1: 1010 0010 */
+ illegal();
+ break;
+ case 0xa3: /* 2: 1010 0011 */
+ movp_a_am();
+ break;
+ case 0xa4: /* 2: aaa0 0100 */
+ jmp_i(0x500);
+ break;
+ case 0xa5: /* 1: 1010 0101 */
+ clr_f1();
+ break;
+ case 0xa6: /* 1: 1010 0110 */
+ illegal();
+ break;
+ case 0xa7: /* 1: 1010 0111 */
+ cpl_c();
+ break;
+ case 0xa8: /* 1: 1010 1rrr */
+ case 0xa9: /* 1: 1010 1rrr */
+ case 0xaa: /* 1: 1010 1rrr */
+ case 0xab: /* 1: 1010 1rrr */
+ case 0xac: /* 1: 1010 1rrr */
+ case 0xad: /* 1: 1010 1rrr */
+ case 0xae: /* 1: 1010 1rrr */
+ case 0xaf: /* 1: 1010 1rrr */
+ mov_r_a(op & 7);
+ break;
+ case 0xb0: /* 2: 1011 000r */
+ mov_rm_i(0);
+ break;
+ case 0xb1: /* 2: 1011 000r */
+ mov_rm_i(1);
+ break;
+ case 0xb2: /* 2: bbb1 0010 */
+ jbb_i(5);
+ break;
+ case 0xb3: /* 2: 1011 0011 */
+ jmpp_a();
+ break;
+ case 0xb4: /* 2: aaa1 0100 */
+ call_i(0x500);
+ break;
+ case 0xb5: /* 1: 1011 0101 */
+ cpl_f1();
+ break;
+ case 0xb6: /* 2: 1011 0110 */
+ jf0_i();
+ break;
+ case 0xb7: /* 1: 1011 0111 */
+ illegal();
+ break;
+ case 0xb8: /* 2: 1011 1rrr */
+ case 0xb9: /* 2: 1011 1rrr */
+ case 0xba: /* 2: 1011 1rrr */
+ case 0xbb: /* 2: 1011 1rrr */
+ case 0xbc: /* 2: 1011 1rrr */
+ case 0xbd: /* 2: 1011 1rrr */
+ case 0xbe: /* 2: 1011 1rrr */
+ case 0xbf: /* 2: 1011 1rrr */
+ mov_r_i(op & 7);
+ break;
+ case 0xc0: /* 1: 1100 0000 */
+ illegal();
+ break;
+ case 0xc1: /* 1: 1100 0001 */
+ illegal();
+ break;
+ case 0xc2: /* 1: 1100 0010 */
+ illegal();
+ break;
+ case 0xc3: /* 1: 1100 0011 */
+ illegal();
+ break;
+ case 0xc4: /* 2: aaa0 0100 */
+ jmp_i(0x600);
+ break;
+ case 0xc5: /* 1: 1100 0101 */
+ sel_rb0();
+ break;
+ case 0xc6: /* 2: 1100 0110 */
+ jz_i();
+ break;
+ case 0xc7: /* 1: 1100 0111 */
+ mov_a_psw();
+ break;
+ case 0xc8: /* 1: 1100 1rrr */
+ case 0xc9: /* 1: 1100 1rrr */
+ case 0xca: /* 1: 1100 1rrr */
+ case 0xcb: /* 1: 1100 1rrr */
+ case 0xcc: /* 1: 1100 1rrr */
+ case 0xcd: /* 1: 1100 1rrr */
+ case 0xcf: /* 1: 1100 1rrr */
+ dec_r(op & 7);
+ break;
+ case 0xd0: /* 1: 1101 000r */
+ xrl_rm(0);
+ break;
+ case 0xd1: /* 1: 1101 000r */
+ xrl_rm(1);
+ break;
+ case 0xd2: /* 2: bbb1 0010 */
+ jbb_i(6);
+ break;
+ case 0xd3: /* 1: 1101 0011 */
+ xrl_i();
+ break;
+ case 0xd4: /* 2: aaa1 0100 */
+ call_i(0x600);
+ break;
+ case 0xd5: /* 1: 1101 0101 */
+ sel_rb1();
+ break;
+ case 0xd6: /* 2: 1101 0110 */
+ jnibf_i();
+ break;
+ case 0xd7: /* 1: 1101 0111 */
+ mov_psw_a();
+ break;
+ case 0xd8: /* 1: 1101 1rrr */
+ case 0xd9: /* 1: 1101 1rrr */
+ case 0xda: /* 1: 1101 1rrr */
+ case 0xdb: /* 1: 1101 1rrr */
+ case 0xdc: /* 1: 1101 1rrr */
+ case 0xdd: /* 1: 1101 1rrr */
+ case 0xde: /* 1: 1101 1rrr */
+ case 0xdf: /* 1: 1101 1rrr */
+ xrl_r(op & 7);
+ break;
+ case 0xe0: /* 1: 1110 0000 */
+ illegal();
+ break;
+ case 0xe1: /* 1: 1110 0001 */
+ illegal();
+ break;
+ case 0xe2: /* 1: 1110 0010 */
+ illegal();
+ break;
+ case 0xe3: /* 2: 1110 0011 */
+ movp3_a_am();
+ break;
+ case 0xe4: /* 2: aaa0 0100 */
+ jmp_i(0x700);
+ break;
+ case 0xe5: /* 1: 1110 0101 */
+ en_dma();
+ break;
+ case 0xe6: /* 2: 1110 0110 */
+ jnc_i();
+ break;
+ case 0xe7: /* 1: 1110 0111 */
+ rl_a();
+ break;
+ case 0xe8: /* 2: 1110 1rrr */
+ case 0xe9: /* 2: 1110 1rrr */
+ case 0xea: /* 2: 1110 1rrr */
+ case 0xeb: /* 2: 1110 1rrr */
+ case 0xec: /* 2: 1110 1rrr */
+ case 0xed: /* 2: 1110 1rrr */
+ case 0xee: /* 2: 1110 1rrr */
+ case 0xef: /* 2: 1110 1rrr */
+ djnz_r_i(op & 7);
+ break;
+ case 0xf0: /* 1: 1111 000r */
+ mov_a_rm(0);
+ break;
+ case 0xf1: /* 1: 1111 000r */
+ mov_a_rm(1);
+ break;
+ case 0xf2: /* 2: bbb1 0010 */
+ jbb_i(7);
+ break;
+ case 0xf3: /* 1: 1111 0011 */
+ illegal();
+ break;
+ case 0xf4: /* 2: aaa1 0100 */
+ call_i(0x700);
+ break;
+ case 0xf5: /* 1: 1111 0101 */
+ en_flags();
+ break;
+ case 0xf6: /* 2: 1111 0110 */
+ jc_i();
+ break;
+ case 0xf7: /* 1: 1111 0111 */
+ rlc_a();
+ break;
+ case 0xf8: /* 1: 1111 1rrr */
+ case 0xf9: /* 1: 1111 1rrr */
+ case 0xfa: /* 1: 1111 1rrr */
+ case 0xfb: /* 1: 1111 1rrr */
+ case 0xfc: /* 1: 1111 1rrr */
+ case 0xfd: /* 1: 1111 1rrr */
+ case 0xfe: /* 1: 1111 1rrr */
+ case 0xff: /* 1: 1111 1rrr */
+ mov_a_r(op & 7);
+ break;
+ }
+
+
+ if( ENABLE & CNT )
+ {
+ inst_cycles = i8x41_cycles[op];
+ for ( ; inst_cycles > 0; inst_cycles-- )
+ {
+ T1_level = RP(I8X41_t1);
+ if( (CONTROL & TEST1) && (T1_level == 0) ) /* Negative Edge */
+ {
+ TIMER++;
+ if (TIMER == 0)
+ {
+ CONTROL |= TOVF;
+ if( ENABLE & TCNTI )
+ CONTROL |= TIRQ_PEND;
+ }
+ }
+ if( T1_level ) CONTROL |= TEST1;
+ else CONTROL &= ~TEST1;
+ }
+ }
+
+ if( ENABLE & T )
+ {
+ PRESCALER += i8x41_cycles[op];
+ /**** timer is prescaled by 32 ****/
+ if( PRESCALER >= 32 )
+ {
+ PRESCALER -= 32;
+ TIMER++;
+ if( TIMER == 0 )
+ {
+ CONTROL |= TOVF;
+ if( ENABLE & TCNTI )
+ CONTROL |= TIRQ_PEND;
+ }
+ }
+ }
+
+ if( CONTROL & IRQ_PEND ) /* Are any Interrupts Pending ? */
+ {
+ if( 0 == (CONTROL & IRQ_EXEC) ) /* Are any Interrupts being serviced ? */
+ {
+ if( (ENABLE & IBFI) && (CONTROL & IBFI_PEND) )
+ {
+ PUSH_PC_TO_STACK();
+ PC = V_IBF;
+ CONTROL &= ~IBFI_PEND;
+ CONTROL |= IBFI_EXEC;
+ i8x41_ICount -= 2;
+ }
+ }
+ if( 0 == (CONTROL & IRQ_EXEC) ) /* Are any Interrupts being serviced ? */
+ {
+ if( (ENABLE & TCNTI) && (CONTROL & TIRQ_PEND) )
+ {
+ PUSH_PC_TO_STACK();
+ PC = V_TIMER;
+ CONTROL &= ~TIRQ_PEND;
+ CONTROL |= TIRQ_EXEC;
+ if( ENABLE & T ) PRESCALER += 2; /* 2 states */
+ i8x41_ICount -= 2; /* 2 states to take interrupt */
+ }
+ }
+ }
+
+
+ } while( i8x41_ICount > 0 );
+
+ return cycles - i8x41_ICount;
+}
+
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+
+static void i8x41_get_context(void *dst)
+{
+ if( dst )
+ memcpy(dst, &i8x41, sizeof(I8X41));
+}
+
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+
+static void i8x41_set_context(void *src)
+{
+ if( src )
+ memcpy(&i8x41, src, sizeof(I8X41));
+}
+
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+
+static void set_irq_line(int irqline, int state)
+{
+ switch( irqline )
+ {
+ case I8X41_INT_IBF:
+ if (state != CLEAR_LINE)
+ {
+ STATE |= IBF;
+ if (ENABLE & IBFI)
+ {
+ CONTROL |= IBFI_PEND;
+ }
+ }
+ else
+ {
+ STATE &= ~IBF;
+ }
+ break;
+
+ case I8X41_INT_TEST1:
+ if( state != CLEAR_LINE )
+ {
+ CONTROL |= TEST1;
+ }
+ else
+ {
+ /* high to low transition? */
+ if( CONTROL & TEST1 )
+ {
+ /* counting enabled? */
+ if( ENABLE & CNT )
+ {
+ TIMER++;
+ if( TIMER == 0 )
+ {
+ CONTROL |= TOVF;
+ CONTROL |= TIRQ_PEND;
+ }
+ }
+ }
+ CONTROL &= ~TEST1;
+ }
+ break;
+ }
+}
+
+
+/**************************************************************************
+ * Register accesses catching uninitialized i8x41.ram pointer
+ **************************************************************************/
+#define GETR(n) (NULL == i8x41.ram ? 0 : \
+ i8x41.ram[((PSW & BS) ? M_BANK1:M_BANK0)+(n)])
+
+#define SETR(n,v) do { \
+ if (NULL != i8x41.ram) { \
+ i8x41.ram[((PSW & BS) ? M_BANK1:M_BANK0)+(n)] = (v); \
+ } \
+} while (0)
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void i8x41_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + I8X41_INT_IBF: set_irq_line(I8X41_INT_IBF, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I8X41_INT_TEST1: set_irq_line(I8X41_INT_TEST1, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I8X41_PC: PC = info->i & 0x7ff; break;
+
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + I8X41_SP: PSW = (PSW & ~SP) | (info->i & SP); break;
+
+ case CPUINFO_INT_REGISTER + I8X41_PSW: PSW = info->i; break;
+ case CPUINFO_INT_REGISTER + I8X41_A: A = info->i; break;
+ case CPUINFO_INT_REGISTER + I8X41_T: TIMER = info->i & 0x1fff; break;
+ case CPUINFO_INT_REGISTER + I8X41_R0: SETR(0, info->i); break;
+ case CPUINFO_INT_REGISTER + I8X41_R1: SETR(1, info->i); break;
+ case CPUINFO_INT_REGISTER + I8X41_R2: SETR(2, info->i); break;
+ case CPUINFO_INT_REGISTER + I8X41_R3: SETR(3, info->i); break;
+ case CPUINFO_INT_REGISTER + I8X41_R4: SETR(4, info->i); break;
+ case CPUINFO_INT_REGISTER + I8X41_R5: SETR(5, info->i); break;
+ case CPUINFO_INT_REGISTER + I8X41_R6: SETR(6, info->i); break;
+ case CPUINFO_INT_REGISTER + I8X41_R7: SETR(7, info->i); break;
+
+ case CPUINFO_INT_REGISTER + I8X41_DATA:
+ DBBI = info->i;
+ if( i8x41.subtype == 8041 ) /* plain 8041 had no split input/output DBB buffers */
+ DBBO = info->i;
+ STATE &= ~F1;
+ STATE |= IBF;
+ if( ENABLE & IBFI )
+ CONTROL |= IBFI_PEND;
+ if( ENABLE & FLAGS)
+ {
+ P2_HS |= 0x20;
+ if( 0 == (STATE & OBF) ) P2_HS |= 0x10;
+ else P2_HS &= 0xef;
+ WP(0x02, (P2 & P2_HS) ); /* Assert the DBBI IRQ out on P25 */
+ }
+ break;
+
+ case CPUINFO_INT_REGISTER + I8X41_DATA_DASM:
+ /* Same as I8X41_DATA, except this is used by the */
+ /* debugger and does not upset the flag states */
+ DBBI = info->i;
+ if( i8x41.subtype == 8041 ) /* plain 8041 had no split input/output DBB buffers */
+ DBBO = info->i;
+ break;
+
+ case CPUINFO_INT_REGISTER + I8X41_CMND:
+ DBBI = info->i;
+ if( i8x41.subtype == 8041 ) /* plain 8041 had no split input/output DBB buffers */
+ DBBO = info->i;
+ STATE |= F1;
+ STATE |= IBF;
+ if( ENABLE & IBFI )
+ CONTROL |= IBFI_PEND;
+ if( ENABLE & FLAGS)
+ {
+ P2_HS |= 0x20;
+ if( 0 == (STATE & OBF) ) P2_HS |= 0x10;
+ else P2_HS &= 0xef;
+ WP(0x02, (P2 & P2_HS) ); /* Assert the DBBI IRQ out on P25 */
+ }
+ break;
+
+ case CPUINFO_INT_REGISTER + I8X41_CMND_DASM:
+ /* Same as I8X41_CMND, except this is used by the */
+ /* debugger and does not upset the flag states */
+ DBBI = info->i;
+ if( i8x41.subtype == 8041 ) /* plain 8041 had no split input/output DBB buffers */
+ DBBO = info->i;
+ break;
+
+ case CPUINFO_INT_REGISTER + I8X41_STAT:
+ logerror("i8x41 #%d:%03x Setting STAT DBBI to %02x\n", cpu_getactivecpu(), PC, (UINT8)info->i);
+ /* writing status.. hmm, should we issue interrupts here too? */
+ STATE = info->i;
+ break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void i8x41_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(i8x41); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = I8X41_CLOCK_DIVIDER; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 2; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + I8X41_INT_IBF: info->i = (STATE & IBF) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + I8X41_INT_TEST1: info->i = (STATE & TEST1) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I8X41_PC: info->i = PC; break;
+
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + I8X41_SP: info->i = PSW & SP; break;
+
+ case CPUINFO_INT_REGISTER + I8X41_PSW: info->i = PSW; break;
+ case CPUINFO_INT_REGISTER + I8X41_A: info->i = A; break;
+ case CPUINFO_INT_REGISTER + I8X41_T: info->i = TIMER; break;
+ case CPUINFO_INT_REGISTER + I8X41_R0: info->i = GETR(0); break;
+ case CPUINFO_INT_REGISTER + I8X41_R1: info->i = GETR(1); break;
+ case CPUINFO_INT_REGISTER + I8X41_R2: info->i = GETR(2); break;
+ case CPUINFO_INT_REGISTER + I8X41_R3: info->i = GETR(3); break;
+ case CPUINFO_INT_REGISTER + I8X41_R4: info->i = GETR(4); break;
+ case CPUINFO_INT_REGISTER + I8X41_R5: info->i = GETR(5); break;
+ case CPUINFO_INT_REGISTER + I8X41_R6: info->i = GETR(6); break;
+ case CPUINFO_INT_REGISTER + I8X41_R7: info->i = GETR(7); break;
+
+ case CPUINFO_INT_REGISTER + I8X41_DATA:
+ STATE &= ~OBF; /* reset the output buffer full flag */
+ if( ENABLE & FLAGS)
+ {
+ P2_HS &= 0xef;
+ if( STATE & IBF ) P2_HS |= 0x20;
+ else P2_HS &= 0xdf;
+ WP(0x02, (P2 & P2_HS) ); /* Clear the DBBO IRQ out on P24 */
+ }
+ info->i = DBBO;
+ break;
+
+ case CPUINFO_INT_REGISTER + I8X41_DATA_DASM:
+ /* Same as I8X41_DATA, except this is used by the */
+ /* debugger and does not upset the flag states */
+ info->i = DBBO;
+ break;
+
+ case CPUINFO_INT_REGISTER + I8X41_STAT:
+ logerror("i8x41 #%d:%03x Reading STAT %02x\n", cpu_getactivecpu(), PC, STATE);
+ info->i = STATE;
+ break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i8x41_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i8x41_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i8x41_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i8x41_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i8x41_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = i8x41_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i8x41_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = i8x41_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i8x41_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "I8X41"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel 8x41"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.3"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 1999 Juergen Buchmueller, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ i8x41.psw & 0x80 ? 'C':'.',
+ i8x41.psw & 0x40 ? 'A':'.',
+ i8x41.psw & 0x20 ? '0':'.',
+ i8x41.psw & 0x10 ? 'B':'.',
+ i8x41.psw & 0x08 ? '?':'.',
+ i8x41.psw & 0x04 ? 's':'.',
+ i8x41.psw & 0x02 ? 's':'.',
+ i8x41.psw & 0x01 ? 's':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + I8X41_PC: sprintf(info->s, "PC:%04X", i8x41.pc); break;
+ case CPUINFO_STR_REGISTER + I8X41_SP: sprintf(info->s, "S:%X", i8x41.psw & SP); break;
+ case CPUINFO_STR_REGISTER + I8X41_PSW: sprintf(info->s, "PSW:%02X", i8x41.psw); break;
+ case CPUINFO_STR_REGISTER + I8X41_A: sprintf(info->s, "A:%02X", i8x41.a); break;
+ case CPUINFO_STR_REGISTER + I8X41_T: sprintf(info->s, "T:%02X.%02X", i8x41.timer, (i8x41.prescaler & 0x1f) ); break;
+ case CPUINFO_STR_REGISTER + I8X41_R0: sprintf(info->s, "R0:%02X", GETR(0)); break;
+ case CPUINFO_STR_REGISTER + I8X41_R1: sprintf(info->s, "R1:%02X", GETR(1)); break;
+ case CPUINFO_STR_REGISTER + I8X41_R2: sprintf(info->s, "R2:%02X", GETR(2)); break;
+ case CPUINFO_STR_REGISTER + I8X41_R3: sprintf(info->s, "R3:%02X", GETR(3)); break;
+ case CPUINFO_STR_REGISTER + I8X41_R4: sprintf(info->s, "R4:%02X", GETR(4)); break;
+ case CPUINFO_STR_REGISTER + I8X41_R5: sprintf(info->s, "R5:%02X", GETR(5)); break;
+ case CPUINFO_STR_REGISTER + I8X41_R6: sprintf(info->s, "R6:%02X", GETR(6)); break;
+ case CPUINFO_STR_REGISTER + I8X41_R7: sprintf(info->s, "R7:%02X", GETR(7)); break;
+ case CPUINFO_STR_REGISTER + I8X41_P1: sprintf(info->s, "P1:%02X", i8x41.p1); break;
+ case CPUINFO_STR_REGISTER + I8X41_P2: sprintf(info->s, "P2:%02X", i8x41.p2); break;
+ case CPUINFO_STR_REGISTER + I8X41_DATA_DASM: sprintf(info->s, "DBBI:%02X", i8x41.dbbi); break;
+ case CPUINFO_STR_REGISTER + I8X41_CMND_DASM: sprintf(info->s, "DBBO:%02X", i8x41.dbbo); break;
+ case CPUINFO_STR_REGISTER + I8X41_STAT: sprintf(info->s, "STAT:%02X", i8x41.state); break;
+ }
+}
diff --git a/src/emu/cpu/i8x41/i8x41.h b/src/emu/cpu/i8x41/i8x41.h
new file mode 100644
index 00000000000..d8c55058df2
--- /dev/null
+++ b/src/emu/cpu/i8x41/i8x41.h
@@ -0,0 +1,88 @@
+/*****************************************************************************
+ *
+ * i8x41.h
+ * Portable UPI-41/8041/8741/8042/8742 emulator interface
+ *
+ * Copyright (c) 1999 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * TLP (10-Jan-2003)
+ * Added output ports registers to the debug viewer
+ * Added the Clock Divider
+ *
+ *****************************************************************************/
+
+#ifndef _I8X41_H
+#define _I8X41_H
+
+#include "cpuintrf.h"
+
+
+/* The i8x41/i8x42 input clock is divided by 15. Use it with your CPU speed */
+#define I8X41_CLOCK_DIVIDER 15
+
+/* Note:
+ * I8X41_DATA is A0 = 0 and R/W
+ * I8X41_CMND is A0 = 1 and W only
+ * I8X41_STAT is A0 = 1 and R only
+ */
+
+
+/****************************************************************************
+ * Interrupt constants
+ */
+
+#define I8X41_INT_IBF 0 /* input buffer full interrupt */
+#define I8X41_INT_TEST1 1 /* test1 line (also counter interrupt; taken on cntr overflow) */
+
+
+/****************************************************************************
+ * Use these in the I/O port fields of your driver for the test lines - i.e,
+ * { I8X41_t0, I8X41_t0, i8041_test0_r },
+ * { I8X41_t1, I8X41_t1, i8041_test1_r },
+ * { I8X41_ps, I8X41_ps, i8041_port_strobe_w },
+ */
+
+#define I8X41_t0 0x80 /* TEST0 input port handle */
+#define I8X41_t1 0x81 /* TEST1 input port handle */
+#define I8X41_ps 0x82 /* Prog pin strobe for expanded port sync */
+
+
+/****************************************************************************
+ * The i8x41/i8x42 have 128/256 bytes of internal memory respectively
+ */
+
+#define I8X41_intRAM_MASK 0x7f
+#define I8X42_intRAM_MASK 0xff
+
+
+enum {
+ I8X41_PC=1, I8X41_SP, I8X41_PSW, I8X41_T, I8X41_DATA, I8X41_DATA_DASM,
+ I8X41_CMND, I8X41_CMND_DASM, I8X41_STAT, I8X41_P1, I8X41_P2,I8X41_A,
+ I8X41_R0, I8X41_R1, I8X41_R2, I8X41_R3, I8X41_R4, I8X41_R5, I8X41_R6, I8X41_R7
+};
+
+
+
+/****************************************************************************
+ * Public Functions
+ */
+
+extern void i8x41_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern offs_t i8x41_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _I8X41_H */
diff --git a/src/emu/cpu/i960/i960.c b/src/emu/cpu/i960/i960.c
new file mode 100644
index 00000000000..60662190142
--- /dev/null
+++ b/src/emu/cpu/i960/i960.c
@@ -0,0 +1,2225 @@
+#include "debugger.h"
+#include "i960.h"
+#include "i960dis.h"
+#include <math.h>
+
+#ifdef _MSC_VER
+/* logb prototype is different for MS Visual C */
+#include <float.h>
+#define logb _logb
+#endif
+
+
+// Warning, IP = Instruction Pointer, called PC outside of Intel
+// PC = Process Control
+
+enum { RCACHE_SIZE = 4 };
+
+typedef struct {
+ UINT32 r[0x20];
+ UINT32 rcache[RCACHE_SIZE][0x10];
+ UINT32 rcache_frame_addr[RCACHE_SIZE];
+ // rcache_pos = how deep in the stack we are. 0-(RCACHE_SIZE-1) means in-cache.
+ // RCACHE_SIZE or greater means out of cache, must save to memory.
+ INT32 rcache_pos;
+
+ double fp[4];
+
+ UINT32 SAT, PRCB, PC, AC;
+ UINT32 IP, PIP, ICR;
+ int bursting;
+
+ int immediate_irq, immediate_vector, immediate_pri;
+
+ int (*irq_cb)(int);
+} i960_state;
+
+static int i960_icount;
+static i960_state i960;
+static void do_call(UINT32 adr, int type, UINT32 stack);
+
+INLINE UINT32 i960_read_dword_unaligned(UINT32 address)
+{
+ if (address & 3)
+ return program_read_byte_32le(address) | program_read_byte_32le(address+1)<<8 | program_read_byte_32le(address+2)<<16 | program_read_byte_32le(address+3)<<24;
+ else
+ return program_read_dword_32le(address);
+}
+
+INLINE UINT16 i960_read_word_unaligned(UINT32 address)
+{
+ if (address & 1)
+ return program_read_byte_32le(address) | program_read_byte_32le(address+1)<<8;
+ else
+ return program_read_word_32le(address);
+}
+
+INLINE void i960_write_dword_unaligned(UINT32 address, UINT32 data)
+{
+ if (address & 3)
+ {
+ program_write_byte_32le(address, data & 0xff);
+ program_write_byte_32le(address+1, (data>>8)&0xff);
+ program_write_byte_32le(address+2, (data>>16)&0xff);
+ program_write_byte_32le(address+3, (data>>24)&0xff);
+ }
+ else
+ {
+ program_write_dword_32le(address, data);
+ }
+}
+
+INLINE void i960_write_word_unaligned(UINT32 address, UINT16 data)
+{
+ if (address & 1)
+ {
+ program_write_byte_32le(address, data & 0xff);
+ program_write_byte_32le(address+1, (data>>8)&0xff);
+ }
+ else
+ {
+ program_write_word_32le(address, data);
+ }
+}
+
+static void send_iac(UINT32 adr)
+{
+ UINT32 iac[4];
+ iac[0] = program_read_dword_32le(adr);
+ iac[1] = program_read_dword_32le(adr+4);
+ iac[2] = program_read_dword_32le(adr+8);
+ iac[3] = program_read_dword_32le(adr+12);
+
+ switch(iac[0]>>24) {
+ case 0x93: // reinit
+ i960.SAT = iac[1];
+ i960.PRCB = iac[2];
+ i960.IP = iac[3];
+ change_pc(i960.IP);
+ break;
+ default:
+ fatalerror("I960: %x: IAC %08x %08x %08x %08x", i960.PIP, iac[0], iac[1], iac[2], iac[3]);
+ break;
+ }
+}
+
+static UINT32 get_ea(UINT32 opcode)
+{
+ int abase = (opcode >> 14) & 0x1f;
+ if(!(opcode & 0x00001000)) { // MEMA
+ UINT32 offset = opcode & 0x1fff;
+ if(!(opcode & 0x2000))
+ return offset;
+ else
+ return i960.r[abase]+offset;
+ } else { // MEMB
+ int index = opcode & 0x1f;
+ int scale = (opcode >> 7) & 0x7;
+ int mode = (opcode >> 10) & 0xf;
+ UINT32 ret;
+
+ switch(mode) {
+ case 0x4:
+ return i960.r[abase];
+
+ case 0x7:
+ return i960.r[abase] + (i960.r[index] << scale);
+
+ case 0xc:
+ ret = cpu_readop32(i960.IP);
+ i960.IP += 4;
+ return ret;
+
+ case 0xd:
+ ret = cpu_readop32(i960.IP) + i960.r[abase];
+ i960.IP += 4;
+ return ret;
+
+ case 0xe:
+ ret = cpu_readop32(i960.IP) + (i960.r[index] << scale);
+ i960.IP += 4;
+ return ret;
+
+ case 0xf:
+ ret = cpu_readop32(i960.IP) + i960.r[abase] + (i960.r[index] << scale);
+ i960.IP += 4;
+ return ret;
+
+ default:
+ fatalerror("I960: %x: unhandled MEMB mode %x", i960.PIP, mode);
+ return 0;
+ }
+ }
+}
+
+static UINT32 get_1_ri(UINT32 opcode)
+{
+ if(!(opcode & 0x00000800))
+ return i960.r[opcode & 0x1f];
+ else
+ return opcode & 0x1f;
+}
+
+static UINT32 get_2_ri(UINT32 opcode)
+{
+ if(!(opcode & 0x00001000))
+ return i960.r[(opcode>>14) & 0x1f];
+ else
+ return (opcode>>14) & 0x1f;
+}
+
+static UINT64 get_2_ri64(UINT32 opcode)
+{
+ if(!(opcode & 0x00001000))
+ return i960.r[(opcode>>14) & 0x1f] | ((UINT64)i960.r[((opcode>>14) & 0x1f)+1]<<32);
+ else
+ return (opcode>>14) & 0x1f;
+}
+
+static void set_ri(UINT32 opcode, UINT32 val)
+{
+ if(!(opcode & 0x00002000))
+ i960.r[(opcode>>19) & 0x1f] = val;
+ else {
+ fatalerror("I960: %x: set_ri on literal?", i960.PIP);
+ }
+}
+
+static void set_ri2(UINT32 opcode, UINT32 val, UINT32 val2)
+{
+ if(!(opcode & 0x00002000))
+ {
+ i960.r[(opcode>>19) & 0x1f] = val;
+ i960.r[((opcode>>19) & 0x1f)+1] = val2;
+ }
+ else {
+ fatalerror("I960: %x: set_ri2 on literal?", i960.PIP);
+ }
+}
+
+static void set_ri64(UINT32 opcode, UINT64 val)
+{
+ if(!(opcode & 0x00002000)) {
+ i960.r[(opcode>>19) & 0x1f] = val;
+ i960.r[((opcode>>19) & 0x1f)+1] = val >> 32;
+ } else
+ fatalerror("I960: %x: set_ri64 on literal?", i960.PIP);
+}
+
+static double get_1_rif(UINT32 opcode)
+{
+ if(!(opcode & 0x00000800))
+ return u2f(i960.r[opcode & 0x1f]);
+ else {
+ int idx = opcode & 0x1f;
+ if(idx < 4)
+ return i960.fp[idx];
+ if(idx == 0x16)
+ return 1.0;
+ return 0.0;
+ }
+}
+
+static double get_2_rif(UINT32 opcode)
+{
+ if(!(opcode & 0x00001000))
+ return u2f(i960.r[(opcode>>14) & 0x1f]);
+ else {
+ int idx = (opcode>>14) & 0x1f;
+ if(idx < 4)
+ return i960.fp[idx];
+ if(idx == 0x16)
+ return 1.0;
+ return 0.0;
+ }
+}
+
+static void set_rif(UINT32 opcode, double val)
+{
+ if(!(opcode & 0x00002000))
+ i960.r[(opcode>>19) & 0x1f] = f2u(val);
+ else if(!(opcode & 0x00e00000))
+ i960.fp[(opcode>>19) & 3] = val;
+ else
+ fatalerror("I960: %x: set_rif on literal?", i960.PIP);
+}
+
+static double get_1_rifl(UINT32 opcode)
+{
+ if(!(opcode & 0x00000800)) {
+ UINT64 v = i960.r[opcode & 0x1e];
+ v |= ((UINT64)(i960.r[(opcode & 0x1e)+1]))<<32;
+ return u2d(v);
+ } else {
+ int idx = opcode & 0x1f;
+ if(idx < 4)
+ return i960.fp[idx];
+ if(idx == 0x16)
+ return 1.0;
+ return 0.0;
+ }
+}
+
+static double get_2_rifl(UINT32 opcode)
+{
+ if(!(opcode & 0x00001000)) {
+ UINT64 v = i960.r[(opcode >> 14) & 0x1e];
+ v |= ((UINT64)(i960.r[((opcode>>14) & 0x1e)+1]))<<32;
+ return u2d(v);
+ } else {
+ int idx = (opcode>>14) & 0x1f;
+ if(idx < 4)
+ return i960.fp[idx];
+ if(idx == 0x16)
+ return 1.0;
+ return 0.0;
+ }
+}
+
+static void set_rifl(UINT32 opcode, double val)
+{
+ if(!(opcode & 0x00002000)) {
+ UINT64 v = d2u(val);
+ i960.r[(opcode>>19) & 0x1e] = v;
+ i960.r[((opcode>>19) & 0x1e)+1] = v>>32;
+ } else if(!(opcode & 0x00e00000))
+ i960.fp[(opcode>>19) & 3] = val;
+ else
+ fatalerror("I960: %x: set_rifl on literal?", i960.PIP);
+}
+
+static UINT32 get_1_ci(UINT32 opcode)
+{
+ if(!(opcode & 0x00002000))
+ return i960.r[(opcode >> 19) & 0x1f];
+ else
+ return (opcode >> 19) & 0x1f;
+}
+
+static UINT32 get_2_ci(UINT32 opcode)
+{
+ return i960.r[(opcode >> 14) & 0x1f];
+}
+
+static UINT32 get_disp(UINT32 opcode)
+{
+ UINT32 disp;
+ disp = opcode & 0xffffff;
+ if(disp & 0x00800000)
+ disp |= 0xff000000;
+ return disp-4;
+}
+
+static UINT32 get_disp_s(UINT32 opcode)
+{
+ UINT32 disp;
+ disp = opcode & 0x1fff;
+ if(disp & 0x00001000)
+ disp |= 0xffffe000;
+ return disp-4;
+}
+
+static void cmp_s(INT32 v1, INT32 v2)
+{
+ i960.AC &= ~7;
+ if(v1<v2)
+ i960.AC |= 4;
+ else if(v1 == v2)
+ i960.AC |= 2;
+ else
+ i960.AC |= 1;
+}
+
+static void cmp_u(UINT32 v1, UINT32 v2)
+{
+ i960.AC &= ~7;
+ if(v1<v2)
+ i960.AC |= 4;
+ else if(v1 == v2)
+ i960.AC |= 2;
+ else
+ i960.AC |= 1;
+}
+
+static void concmp_s(INT32 v1, INT32 v2)
+{
+ i960.AC &= ~7;
+ if(v1 <= v2)
+ i960.AC |= 2;
+ else
+ i960.AC |= 1;
+}
+
+static void concmp_u(UINT32 v1, UINT32 v2)
+{
+ i960.AC &= ~7;
+ if(v1 <= v2)
+ i960.AC |= 2;
+ else
+ i960.AC |= 1;
+}
+
+static void cmp_d(double v1, double v2)
+{
+ i960.AC &= ~7;
+ if(v1<v2)
+ i960.AC |= 4;
+ else if(v1 == v2)
+ i960.AC |= 2;
+ else if(v1 > v2)
+ i960.AC |= 1;
+}
+
+INLINE void bxx(UINT32 opcode, int mask)
+{
+ if(i960.AC & mask) {
+ i960.IP += get_disp(opcode);
+ change_pc(i960.IP);
+ }
+}
+
+INLINE void bxx_s(UINT32 opcode, int mask)
+{
+ if(i960.AC & mask) {
+ i960.IP += get_disp_s(opcode);
+ change_pc(i960.IP);
+ }
+}
+
+INLINE void test(UINT32 opcode, int mask)
+{
+ if(i960.AC & mask)
+ i960.r[(opcode>>19) & 0x1f] = 1;
+ else
+ i960.r[(opcode>>19) & 0x1f] = 0;
+}
+
+static const char *i960_get_strflags(void)
+{
+ static const char *conditions[8] =
+ {
+ "no", "g", "e", "ge", "l", "ne", "le", "o"
+ };
+
+ return (conditions[i960.AC & 7]);
+}
+
+// interrupt dispatch
+static void take_interrupt(int vector, int lvl)
+{
+ int int_tab = program_read_dword_32le(i960.PRCB+20); // interrupt table
+ int int_SP = program_read_dword_32le(i960.PRCB+24); // interrupt stack
+ int SP;
+ UINT32 IRQV;
+
+ IRQV = program_read_dword_32le(int_tab + 36 + (vector-8)*4);
+
+ // start the process
+ if(!(i960.PC & 0x2000)) // if this is a nested interrupt, don't re-get int_SP
+ {
+ SP = int_SP;
+ }
+ else
+ {
+ SP = i960.r[I960_SP];
+ }
+
+ SP = (SP + 63) & ~63;
+ SP += 128; // emulate ElSemi's core, this fixes the crash in sonic the fighters
+
+ do_call(IRQV, 7, SP);
+
+ // save the processor state
+ program_write_dword_32le(i960.r[I960_FP]-16, i960.AC);
+ program_write_dword_32le(i960.r[I960_FP]-12, i960.PC);
+ // store the vector
+ program_write_dword_32le(i960.r[I960_FP]-8, vector-8);
+
+ i960.PC &= ~0x1f00; // clear priority, state, trace-fault pending, and trace enable
+ i960.PC |= (lvl<<16); // set CPU level to current IRQ level
+ i960.PC |= 0x2002; // set supervisor mode & interrupt flag
+}
+
+static void check_irqs(void)
+{
+ int int_tab = program_read_dword_32le(i960.PRCB+20); // interrupt table
+ int cpu_pri = (i960.PC>>16)&0x1f;
+ int pending_pri;
+ int lvl, irq, take = -1;
+ int vword;
+ static const UINT32 lvlmask[4] = { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };
+
+ pending_pri = program_read_dword_32le(int_tab); // read pending priorities
+
+ if ((i960.immediate_irq) && ((cpu_pri < i960.immediate_pri) || (i960.immediate_pri == 31)))
+ {
+ take_interrupt(i960.immediate_vector, i960.immediate_pri);
+ i960.immediate_irq = 0;
+ }
+ else
+ {
+ for(lvl = 31; lvl >= 0; lvl--) {
+ if((pending_pri & (1 << lvl)) && ((cpu_pri < lvl) || (lvl == 31))) {
+ int word, wordl, wordh;
+
+ // figure out which word contains this level's priorities
+ word = ((lvl / 4) * 4) + 4; // (lvl/4) = word address, *4 for byte address, +4 to skip pending priorities
+ wordl = (lvl % 4) * 8;
+ wordh = (wordl + 8) - 1;
+
+ vword = program_read_dword_32le(int_tab + word);
+
+ // take the first vector we find for this level
+ for (irq = wordh; irq >= wordl; irq--) {
+ if(vword & (1 << irq)) {
+ // clear pending bit
+ vword &= ~(1 << irq);
+ program_write_dword_32le(int_tab + word, vword);
+ take = irq;
+ break;
+ }
+ }
+
+ // if no vectors were found at our level, it's an error
+ if(take == -1) {
+ logerror("i960: ERROR! no vector found for pending level %d\n", lvl);
+
+ // try to recover...
+ pending_pri &= ~(1 << lvl);
+ program_write_dword_32le(int_tab, pending_pri);
+ return;
+ }
+
+ // if no vectors are waiting for this level, clear the level bit
+ if(!(vword & lvlmask[lvl % 4])) {
+ pending_pri &= ~(1 << lvl);
+ program_write_dword_32le(int_tab, pending_pri);
+ }
+
+ take += ((lvl/4) * 32);
+
+ take_interrupt(take, lvl);
+ return;
+ }
+ }
+ }
+}
+
+static void do_call(UINT32 adr, int type, UINT32 stack)
+{
+ int i;
+ UINT32 FP;
+
+ // call and callx take 9 cycles base
+ i960_icount -= 9;
+
+ // set the new RIP
+ i960.r[I960_RIP] = i960.IP;
+// mame_printf_debug("CALL (type %d): FP %x, %x => %x, stack %x, rcache_pos %d\n", type, i960.r[I960_FP], i960.r[I960_RIP], adr, stack, i960.rcache_pos);
+
+ // are we out of cache entries?
+ if (i960.rcache_pos >= RCACHE_SIZE) {
+ // flush the current register set to the current frame
+ FP = i960.r[I960_FP] & ~0x3f;
+ for (i = 0; i < 16; i++) {
+ program_write_dword_32le(FP + (i*4), i960.r[i]);
+ }
+ }
+ else // a cache entry is available, use it
+ {
+ memcpy(&i960.rcache[i960.rcache_pos][0], i960.r, 0x10 * sizeof(UINT32));
+ i960.rcache_frame_addr[i960.rcache_pos] = i960.r[I960_FP] & ~0x3f;
+ }
+ i960.rcache_pos++;
+
+ i960.IP = adr;
+ i960.r[I960_PFP] = i960.r[I960_FP] & ~7;
+ i960.r[I960_PFP] |= type;
+
+ if(type == 7) { // interrupts need special handling
+ // set the stack to the passed-in value to properly handle nested interrupts
+ // (can't set it externally or the original program's SP will be lost)
+ i960.r[I960_SP] = stack;
+ }
+
+ i960.r[I960_FP] = (i960.r[I960_SP] + 63) & ~63;
+ i960.r[I960_SP] = i960.r[I960_FP] + 64;
+
+ change_pc(i960.IP);
+}
+
+static void do_ret_0(void)
+{
+// int type = i960.r[I960_PFP] & 7;
+
+ i960.r[I960_FP] = i960.r[I960_PFP] & ~0x3f;
+
+ i960.rcache_pos--;
+
+ // normal situation: if we're still above rcache size, we're not in cache.
+ // abnormal situation (after the app does a FLUSHREG): rcache_pos will be 0
+ // coming in, but we must still treat it as a not-in-cache situation.
+ if ((i960.rcache_pos >= RCACHE_SIZE) || (i960.rcache_pos < 0))
+ {
+ int i;
+ for(i=0; i<0x10; i++)
+ i960.r[i] = program_read_dword_32le(i960.r[I960_FP]+4*i);
+
+ if (i960.rcache_pos < 0)
+ {
+ i960.rcache_pos = 0;
+ }
+ }
+ else
+ {
+ memcpy(i960.r, i960.rcache[i960.rcache_pos], 0x10*sizeof(UINT32));
+ }
+
+// mame_printf_debug("RET (type %d): FP %x, %x => %x, rcache_pos %d\n", type, i960.r[I960_FP], i960.IP, i960.r[I960_RIP], i960.rcache_pos);
+ i960.IP = i960.r[I960_RIP];
+ change_pc(i960.IP);
+}
+
+static void do_ret(void)
+{
+ UINT32 x, y;
+ i960_icount -= 7;
+ switch(i960.r[I960_PFP] & 7) {
+ case 0:
+ do_ret_0();
+ break;
+
+ case 7:
+ x = program_read_dword(i960.r[I960_FP]-16);
+ y = program_read_dword(i960.r[I960_FP]-12);
+ do_ret_0();
+ i960.AC = x;
+ // #### test supervisor
+ i960.PC = y;
+
+ // check for another IRQ now that we're back
+ check_irqs();
+ break;
+
+ default:
+ fatalerror("I960: %x: Unsupported return mode %d", i960.PIP, i960.r[I960_PFP] & 7);
+ }
+}
+
+static int i960_execute(int cycles)
+{
+ UINT32 opcode;
+ UINT32 t1, t2;
+ double t1f, t2f;
+
+ t1 = t2 = 0;
+
+ i960_icount = cycles;
+ check_irqs();
+ while(i960_icount >= 0) {
+ i960.PIP = i960.IP;
+ CALL_MAME_DEBUG;
+
+ i960.bursting = 0;
+
+ opcode = cpu_readop32(i960.IP);
+ i960.IP += 4;
+
+ switch(opcode >> 24) {
+ case 0x08: // b
+ i960_icount--;
+ i960.IP += get_disp(opcode);
+ change_pc(i960.IP);
+ break;
+
+ case 0x09: // call
+ do_call(i960.IP+get_disp(opcode), 0, i960.r[I960_SP]);
+ break;
+
+ case 0x0a: // ret
+ do_ret();
+ break;
+
+ case 0x0b: // bal
+ i960_icount -= 5;
+ i960.r[0x1e] = i960.IP;
+ i960.IP += get_disp(opcode);
+ change_pc(i960.IP);
+ break;
+
+ case 0x10: // bno
+ i960_icount--;
+ if(!(i960.AC & 7)) {
+ i960.IP += get_disp(opcode);
+ change_pc(i960.IP);
+ }
+ break;
+
+ case 0x11: // bg
+ i960_icount--;
+ bxx(opcode, 1);
+ break;
+
+ case 0x12: // be
+ i960_icount--;
+ bxx(opcode, 2);
+ break;
+
+ case 0x13: // bge
+ i960_icount--;
+ bxx(opcode, 3);
+ break;
+
+ case 0x14: // bl
+ i960_icount--;
+ bxx(opcode, 4);
+ break;
+
+ case 0x15: // bne
+ i960_icount--;
+ bxx(opcode, 5);
+ break;
+
+ case 0x16: // ble
+ i960_icount--;
+ bxx(opcode, 6);
+ break;
+
+ case 0x17: // bo
+ i960_icount--;
+ bxx(opcode, 7);
+ break;
+
+ case 0x20: // testno
+ i960_icount--;
+ if(!(i960.AC & 7))
+ i960.r[(opcode>>19) & 0x1f] = 1;
+ else
+ i960.r[(opcode>>19) & 0x1f] = 0;
+ break;
+
+ case 0x21: // testg
+ i960_icount--;
+ test(opcode, 1);
+ break;
+
+ case 0x22: // teste
+ i960_icount--;
+ test(opcode, 2);
+ break;
+
+ case 0x23: // testge
+ i960_icount--;
+ test(opcode, 3);
+ break;
+
+ case 0x24: // testl
+ i960_icount--;
+ test(opcode, 4);
+ break;
+
+ case 0x25: // testne
+ i960_icount--;
+ test(opcode, 5);
+ break;
+
+ case 0x26: // testle
+ i960_icount--;
+ test(opcode, 6);
+ break;
+
+ case 0x27: // testo
+ i960_icount--;
+ test(opcode, 7);
+ break;
+
+ case 0x30: // bbc
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode) & 0x1f;
+ t2 = get_2_ci(opcode);
+ if(!(t2 & (1<<t1))) {
+ i960.AC = (i960.AC & ~7) | 2;
+ i960.IP += get_disp_s(opcode);
+ change_pc(i960.IP);
+ } else
+ i960.AC &= ~7;
+ break;
+
+ case 0x31: // cmp0bg
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_u(t1, t2);
+ bxx_s(opcode, 1);
+ break;
+
+ case 0x32: // cmpobe
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_u(t1, t2);
+ bxx_s(opcode, 2);
+ break;
+
+ case 0x33: // cmpobge
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_u(t1, t2);
+ bxx_s(opcode, 3);
+ break;
+
+ case 0x34: // cmpobl
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_u(t1, t2);
+ bxx_s(opcode, 4);
+ break;
+
+ case 0x35: // cmpobne
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_u(t1, t2);
+ bxx_s(opcode, 5);
+ break;
+
+ case 0x36: // cmpoble
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_u(t1, t2);
+ bxx_s(opcode, 6);
+ break;
+
+ case 0x37: // bbs
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode) & 0x1f;
+ t2 = get_2_ci(opcode);
+ if(t2 & (1<<t1)) {
+ i960.AC = (i960.AC & ~7) | 2;
+ i960.IP += get_disp_s(opcode);
+ change_pc(i960.IP);
+ } else
+ i960.AC &= ~7;
+ break;
+
+ case 0x39: // cmpibg
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_s(t1, t2);
+ bxx_s(opcode, 1);
+ break;
+
+ case 0x3a: // cmpibe
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_s(t1, t2);
+ bxx_s(opcode, 2);
+ break;
+
+ case 0x3b: // cmpibge
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_s(t1, t2);
+ bxx_s(opcode, 3);
+ break;
+
+ case 0x3c: // cmpibl
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_s(t1, t2);
+ bxx_s(opcode, 4);
+ break;
+
+ case 0x3d: // cmpibne
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_s(t1, t2);
+ bxx_s(opcode, 5);
+ break;
+
+ case 0x3e: // cmpible
+ i960_icount -= 4;
+ t1 = get_1_ci(opcode);
+ t2 = get_2_ci(opcode);
+ cmp_s(t1, t2);
+ bxx_s(opcode, 6);
+ break;
+
+ case 0x58:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // notbit
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2 ^ (1<<(t1 & 31)));
+ break;
+
+ case 0x1: // and
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2 & t1);
+ break;
+
+ case 0x2: // andnot
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2 & ~t1);
+ break;
+
+ case 0x3: // setbit
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2 | (1<<(t1 & 31)));
+ break;
+
+ case 0x4: // notand
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, (~t2) & t1);
+ break;
+
+ case 0x6: // xor
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2 ^ t1);
+ break;
+
+ case 0x7: // or
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2 | t1);
+ break;
+
+ case 0x8: // nor
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, ((~t2) ^ (~t1)));
+ break;
+
+ case 0x9: // xnor
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, ~(t2 ^ t1));
+ break;
+
+ case 0xa: // not
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ set_ri(opcode, ~t1);
+ break;
+
+ case 0xb: // ornot
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2 | ~t1);
+ break;
+
+ case 0xc: // clrbit
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2 & ~(1<<(t1 & 31)));
+ break;
+
+ case 0xe: // nand
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, ~t2 | ~t1);
+ break;
+
+ case 0xf: // alterbit
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ if(i960.AC & 2)
+ set_ri(opcode, t2 | (1<<(t1 & 31)));
+ else
+ set_ri(opcode, t2 & ~(1<<(t1 & 31)));
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 58.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x59:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // addo
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2+t1);
+ break;
+
+ case 0x1: // addi
+ // #### overflow
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2+t1);
+ break;
+
+ case 0x2: // subo
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2-t1);
+ break;
+
+ case 0x3: // subi
+ // #### overflow
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2-t1);
+ break;
+
+ case 0x8: // shro
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2>>t1);
+ break;
+
+ case 0xa: // shrdi
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ if(((INT32)t2) < 0) {
+ if(t2 & ((1<<t1)-1))
+ set_ri(opcode, (((INT32)t2)>>t1)+1);
+ else
+ set_ri(opcode, ((INT32)t2)>>t1);
+ } else
+ set_ri(opcode, t2>>t1);
+ break;
+
+ case 0xb: // shri
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, ((INT32)t2)>>t1);
+ break;
+
+ case 0xc: // shlo
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2<<t1);
+ break;
+
+ case 0xd: // rotate
+ i960_icount--;
+ t1 = get_1_ri(opcode) & 0x1f;
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, (t2<<t1)|(t2>>(32-t1)));
+ break;
+
+ case 0xe: // shli
+ // missing overflow
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2<<t1);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 59.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x5a:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // cmpo
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ cmp_u(t1, t2);
+ break;
+
+ case 0x1: // cmpi
+ i960_icount--;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ cmp_s(t1, t2);
+ break;
+
+ case 0x2: // concmpo
+ i960_icount--;
+ if(!(i960.AC & 0x4)) {
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ concmp_u(t1, t2);
+ }
+ break;
+
+ case 0x3: // concmpi
+ i960_icount--;
+ if(!(i960.AC & 0x4)) {
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ concmp_s(t1, t2);
+ }
+ break;
+
+ case 0x4: // cmpinco
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ cmp_u(t1, t2);
+ set_ri(opcode, t2+1);
+ break;
+
+ case 0x5: // cmpinci
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ cmp_s(t1, t2);
+ set_ri(opcode, t2+1);
+ break;
+
+ case 0x6: // cmpdeco
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ cmp_u(t1, t2);
+ set_ri(opcode, t2-1);
+ break;
+
+ case 0x7: // cmpdeci
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ cmp_s(t1, t2);
+ set_ri(opcode, t2-1);
+ break;
+
+ case 0xe: // chkbit
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode) & 0x1f;
+ t2 = get_2_ri(opcode);
+ if(t2 & (1<<t1))
+ i960.AC = (i960.AC & ~7) | 2;
+ else
+ i960.AC &= ~7;
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 5a.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x5b:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // addc
+ {
+ UINT64 res;
+
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ res = t2+(t1+((i960.AC>>1)&1));
+ set_ri(opcode, res&0xffffffff);
+
+ i960.AC &= ~0x3; // clear C and V
+ // set carry
+ i960.AC |= ((res) & (((UINT64)1) << 32)) ? 0x2 : 0;
+ // set overflow
+ i960.AC |= (((res) ^ (t1)) & ((res) ^ (t2)) & 0x80000000) ? 1: 0;
+ }
+ break;
+
+ case 0x2: // subc
+ {
+ UINT64 res;
+
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ res = t2-(t1+((i960.AC>>1)&1));
+ set_ri(opcode, res&0xffffffff);
+
+ i960.AC &= ~0x3; // clear C and V
+ // set carry
+ i960.AC |= ((res) & (((UINT64)1) << 32)) ? 0x2 : 0;
+ // set overflow
+ i960.AC |= (((t2) ^ (t1)) & ((t2) ^ (res)) & 0x80000000) ? 1 : 0;
+ }
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 5b.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x5c:
+ switch((opcode >> 7) & 0xf) {
+ case 0xc: // mov
+ i960_icount -= 2;
+ t1 = get_1_ri(opcode);
+ set_ri(opcode, t1);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 5c.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x5d:
+ switch((opcode >> 7) & 0xf) {
+ case 0xc: // movl
+ i960_icount -= 2;
+ t2 = (opcode>>19) & 0x1e;
+ if(opcode & 0x00000800) { // litteral
+ t1 = opcode & 0x1f;
+ i960.r[t2] = i960.r[t2+1] = t1;
+ } else
+ memcpy(i960.r+t2, i960.r+(opcode & 0x1f), 2*sizeof(UINT32));
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 5d.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x5e:
+ switch((opcode >> 7) & 0xf) {
+ case 0xc: // movt
+ i960_icount -= 3;
+ t2 = (opcode>>19) & 0x1c;
+ if(opcode & 0x00000800) { // litteral
+ t1 = opcode & 0x1f;
+ i960.r[t2] = i960.r[t2+1] = i960.r[t2+2]= t1;
+ } else
+ memcpy(i960.r+t2, i960.r+(opcode & 0x1f), 3*sizeof(UINT32));
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 5e.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x5f:
+ switch((opcode >> 7) & 0xf) {
+ case 0xc: // movq
+ i960_icount -= 4;
+ t2 = (opcode>>19) & 0x1c;
+ if(opcode & 0x00000800) { // litteral
+ t1 = opcode & 0x1f;
+ i960.r[t2] = i960.r[t2+1] = i960.r[t2+2] = i960.r[t2+3] = t1;
+ } else
+ memcpy(i960.r+t2, i960.r+(opcode & 0x1f), 4*sizeof(UINT32));
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 5f.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x60:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // synmov
+ i960_icount -= 6;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ // interrupt control register
+ if(t1 == 0xff000004)
+ i960.ICR = program_read_dword_32le(t2);
+ else
+ program_write_dword_32le(t1, program_read_dword_32le(t2));
+ i960.AC = (i960.AC & ~7) | 2;
+ break;
+
+ case 0x2: // synmovq
+ i960_icount -= 12;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ if(t1 == 0xff000010)
+ send_iac(t2);
+ else {
+ program_write_dword_32le(t1, program_read_dword_32le(t2));
+ program_write_dword_32le(t1+4, program_read_dword_32le(t2+4));
+ program_write_dword_32le(t1+8, program_read_dword_32le(t2+8));
+ program_write_dword_32le(t1+12, program_read_dword_32le(t2+12));
+ }
+ i960.AC = (i960.AC & ~7) | 2;
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 60.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x64:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // spanbit
+ {
+ UINT32 res = 0xffffffff;
+ int i;
+
+ i960_icount -= 10;
+
+ t1 = get_1_ri(opcode);
+ i960.AC &= ~7;
+
+ for (i = 31; i >= 0; i--)
+ {
+ if (!(t1 & (1<<i)))
+ {
+ i960.AC |= 2;
+ res = i;
+ break;
+ }
+ }
+
+ set_ri(opcode, res);
+ }
+ break;
+
+ case 0x1: // scanbit
+ {
+ UINT32 res = 0xffffffff;
+ int i;
+
+ i960_icount -= 10;
+
+ t1 = get_1_ri(opcode);
+ i960.AC &= ~7;
+
+ for (i = 31; i >= 0; i--)
+ {
+ if (t1 & (1<<i))
+ {
+ i960.AC |= 2;
+ res = i;
+ break;
+ }
+ }
+
+ set_ri(opcode, res);
+ }
+ break;
+
+ case 0x5: // modac
+ i960_icount -= 10;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, i960.AC);
+ i960.AC = (i960.AC & ~t1) | (t2 & t1);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 64.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x65:
+ switch((opcode >> 7) & 0xf) {
+ case 0x5: // modpc
+ i960_icount -= 10;
+ t1 = i960.PC;
+ t2 = get_2_ri(opcode);
+ i960.PC = (i960.PC & ~t2) | (i960.r[(opcode>>19) & 0x1f] & t2);
+ set_ri(opcode, t1);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 65.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x66:
+ switch((opcode >> 7) & 0xf) {
+ case 0xd: // flushreg
+ if (i960.rcache_pos > 4)
+ {
+ i960.rcache_pos = 4;
+ }
+ for(t1=0; t1 < i960.rcache_pos; t1++)
+ {
+ int i;
+
+ for (i = 0; i < 0x10; i++)
+ {
+ program_write_dword_32le(i960.rcache_frame_addr[t1] + (i * sizeof(UINT32)), i960.rcache[t1][i]);
+ }
+ }
+ i960.rcache_pos = 0;
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 66.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x67:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // emul
+ i960_icount -= 37;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+
+ set_ri64(opcode, (INT64)t1 * (INT64)t2);
+ break;
+
+ case 0x1: // ediv
+ i960_icount -= 37;
+ {
+ UINT64 src1, src2;
+
+ src1 = get_1_ri(opcode);
+ src2 = get_2_ri64(opcode);
+
+ set_ri2(opcode, src2 % src1, src2 / src1);
+ }
+ break;
+
+ case 0x4: // cvtir
+ i960_icount -= 30;
+ t1 = get_1_ri(opcode);
+ set_rif(opcode, (double)(INT32)t1);
+ break;
+
+ case 0x6: // scalerl
+ i960_icount -= 30;
+ t1 = get_1_ri(opcode);
+ t2f = get_2_rifl(opcode);
+ set_rifl(opcode, t2f * pow(2.0, (double)(INT32)t1));
+ break;
+
+ case 0x7: // scaler
+ i960_icount -= 30;
+ t1 = get_1_ri(opcode);
+ t2f = get_2_rif(opcode);
+ set_rif(opcode, t2f * pow(2.0, (double)(INT32)t1));
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 67.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x68:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // atanr
+ i960_icount -= 267;
+ t1f = get_1_rif(opcode);
+ t2f = get_2_rif(opcode);
+ set_rif(opcode, atan2(t2f, t1f));
+ break;
+
+ case 0x1: // logepr
+ i960_icount -= 400;
+ t1f = get_1_rif(opcode);
+ t2f = get_2_rif(opcode);
+ set_rif(opcode, t2f*log(t1f+1.0)/log(2.0));
+ break;
+
+ case 0x3: // remr
+ i960_icount -= 67; // (67 to 75878 depending on opcodes!!!)
+ t1f = get_1_rif(opcode);
+ t2f = get_2_rif(opcode);
+ set_rif(opcode, fmod(t2f, t1f));
+ break;
+
+ case 0x5: // cmpr
+ i960_icount -= 10;
+ t1f = get_1_rif(opcode);
+ t2f = get_2_rif(opcode);
+ cmp_d(t1f, t2f);
+ break;
+
+ case 0x8: // sqrtr
+ i960_icount -= 104;
+ t1f = get_1_rif(opcode);
+ set_rif(opcode, sqrt(t1f));
+ break;
+
+ case 0xa: // logbnr
+ i960_icount -= 37;
+ t1f = get_1_rif(opcode);
+ set_rif(opcode, logb(t1f));
+ break;
+
+ case 0xb: // roundr
+ {
+ INT32 st1 = get_1_rif(opcode);
+ i960_icount -= 69;
+ set_rif(opcode, (double)st1);
+ }
+ break;
+
+ case 0xc: // sinr
+ i960_icount -= 406;
+ t1f = get_1_rif(opcode);
+ set_rif(opcode, sin(t1f));
+ break;
+
+ case 0xd: // cosr
+ i960_icount -= 406;
+ t1f = get_1_rif(opcode);
+ set_rif(opcode, sin(t1f));
+ break;
+
+ case 0xe: // tanr
+ i960_icount -= 293;
+ t1f = get_1_rif(opcode);
+ set_rif(opcode, tan(t1f));
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 68.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x69:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // atanrl
+ i960_icount -= 350;
+ t1f = get_1_rifl(opcode);
+ t2f = get_2_rifl(opcode);
+ set_rifl(opcode, atan2(t2f, t1f));
+ break;
+
+ case 0x2: // logrl
+ i960_icount -= 438;
+ t1f = get_1_rifl(opcode);
+ set_rifl(opcode, log(t1f));
+ break;
+
+ case 0x5: // cmprl
+ i960_icount -= 12;
+ t1f = get_1_rifl(opcode);
+ t2f = get_2_rifl(opcode);
+ cmp_d(t1f, t2f);
+ break;
+
+ case 0x8: // sqrtrl
+ i960_icount -= 104;
+ t1f = get_1_rifl(opcode);
+ set_rifl(opcode, sqrt(t1f));
+ break;
+
+ case 0x9: // exprl
+ i960_icount -= 334;
+ t1f = get_1_rifl(opcode);
+ set_rifl(opcode, pow(2.0, t1f)-1.0);
+ break;
+
+ case 0xa: // logbnrl
+ i960_icount -= 37;
+ t1f = get_1_rifl(opcode);
+ set_rifl(opcode, logb(t1f));
+ break;
+
+ case 0xb: // roundrl
+ {
+ INT32 st1 = get_1_rifl(opcode);
+ i960_icount -= 70;
+ set_rifl(opcode, (double)st1);
+ }
+ break;
+
+ case 0xc: // sinrl
+ i960_icount -= 441;
+ t1f = get_1_rifl(opcode);
+ set_rifl(opcode, sin(t1f));
+ break;
+
+ case 0xd: // cosrl
+ i960_icount -= 441;
+ t1f = get_1_rifl(opcode);
+ set_rifl(opcode, cos(t1f));
+ break;
+
+ case 0xe: // tanrl
+ i960_icount -= 323;
+ t1f = get_1_rifl(opcode);
+ set_rifl(opcode, tan(t1f));
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 69.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x6c:
+ switch((opcode >> 7) & 0xf) {
+ case 0x0: // cvtri
+ i960_icount -= 33;
+ t1f = get_1_rif(opcode);
+ set_ri(opcode, (INT32)t1f);
+ break;
+
+ case 0x2: // cvtzri
+ i960_icount -= 43;
+ t1f = get_1_rif(opcode);
+ set_ri(opcode, (INT32)t1f);
+ break;
+
+ case 0x3: // cvtzril
+ i960_icount -= 44;
+ t1f = get_1_rif(opcode);
+ set_ri64(opcode, (INT64)t1f);
+ break;
+
+ case 0x9: // movr
+ i960_icount -= 5;
+ t1f = get_1_rif(opcode);
+ set_rif(opcode, t1f);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 6c.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x6d:
+ switch((opcode >> 7) & 0xf) {
+ case 0x9: // movrl
+ i960_icount -= 6;
+ t1f = get_1_rifl(opcode);
+ set_rifl(opcode, t1f);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 6d.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x6e:
+ switch((opcode >> 7) & 0xf) {
+ case 0x1: // movre
+ {
+ UINT32 *src=0, *dst=0;
+
+ i960_icount -= 8;
+
+ if(!(opcode & 0x00000800)) {
+ src = (UINT32 *)&i960.r[opcode & 0x1e];
+ } else {
+ int idx = opcode & 0x1f;
+ if(idx < 4)
+ src = (UINT32 *)&i960.fp[idx];
+ }
+
+ if(!(opcode & 0x00002000)) {
+ dst = (UINT32 *)&i960.r[(opcode>>19) & 0x1e];
+ } else if(!(opcode & 0x00e00000))
+ dst = (UINT32 *)&i960.fp[(opcode>>19) & 3];
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2]&0xffff;
+ }
+ break;
+ case 0x2: // cpysre
+ i960_icount -= 8;
+ t1f = get_1_rifl(opcode);
+ t2f = get_2_rifl(opcode);
+
+ if (t2f >= 0.0)
+ set_rifl(opcode, fabs(t1f));
+ else
+ set_rifl(opcode, -fabs(t1f));
+ break;
+ default:
+ fatalerror("I960: %x: Unhandled 6e.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x70:
+ switch((opcode >> 7) & 0xf) {
+ case 0x1: // mulo
+ i960_icount -= 18;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2*t1);
+ break;
+
+ case 0x8: // remo
+ i960_icount -= 37;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, t2%t1);
+ break;
+
+ case 0xb: // divo
+ i960_icount -= 37;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ if (t1 == 0) // HACK!
+ set_ri(opcode, 0);
+ else
+ set_ri(opcode, t2/t1);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 70.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x74:
+ switch((opcode >> 7) & 0xf) {
+ case 0x1: // muli
+ i960_icount -= 18;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, ((INT32)t2)*((INT32)t1));
+ break;
+
+ case 0x8: // remi
+ i960_icount -= 37;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, ((INT32)t2)%((INT32)t1));
+ break;
+
+ case 0x9:{// modi
+ INT32 src1, src2, dst;
+ i960_icount -= 37;
+ src1 = (INT32)get_1_ri(opcode);
+ src2 = (INT32)get_2_ri(opcode);
+ dst = src2 - ((src2/src1)*src1);
+ if(((src2*src1) < 0) && (dst != 0))
+ dst += src1;
+ set_ri(opcode, dst);
+ break;
+ }
+
+ case 0xb: // divi
+ i960_icount -= 37;
+ t1 = get_1_ri(opcode);
+ t2 = get_2_ri(opcode);
+ set_ri(opcode, ((INT32)t2)/((INT32)t1));
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 74.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x78:
+ switch((opcode >> 7) & 0xf) {
+ case 0xb: // divr
+ i960_icount -= 35;
+ t1f = get_1_rif(opcode);
+ t2f = get_2_rif(opcode);
+ set_rif(opcode, t2f/t1f);
+ break;
+
+ case 0xc: // mulr
+ i960_icount -= 18;
+ t1f = get_1_rif(opcode);
+ t2f = get_2_rif(opcode);
+ set_rif(opcode, t2f*t1f);
+ break;
+
+ case 0xd: // subr
+ i960_icount -= 10;
+ t1f = get_1_rif(opcode);
+ t2f = get_2_rif(opcode);
+ set_rif(opcode, t2f-t1f);
+ break;
+
+ case 0xf: // addr
+ i960_icount -= 10;
+ t1f = get_1_rif(opcode);
+ t2f = get_2_rif(opcode);
+ set_rif(opcode, t2f+t1f);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 78.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x79:
+ switch((opcode >> 7) & 0xf) {
+ case 0xb: // divrl
+ i960_icount -= 77;
+ t1f = get_1_rifl(opcode);
+ t2f = get_2_rifl(opcode);
+ set_rifl(opcode, t2f/t1f);
+ break;
+
+ case 0xc: // mulrl
+ i960_icount -= 36;
+ t1f = get_1_rifl(opcode);
+ t2f = get_2_rifl(opcode);
+ set_rifl(opcode, t2f*t1f);
+ break;
+
+ case 0xd: // subrl
+ i960_icount -= 13;
+ t1f = get_1_rifl(opcode);
+ t2f = get_2_rifl(opcode);
+ set_rifl(opcode, t2f-t1f);
+ break;
+
+ case 0xf: // addrl
+ i960_icount -= 13;
+ t1f = get_1_rifl(opcode);
+ t2f = get_2_rifl(opcode);
+ set_rifl(opcode, t2f+t1f);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled 79.%x", i960.PIP, (opcode >> 7) & 0xf);
+ }
+ break;
+
+ case 0x80: // ldob
+ i960_icount -= 4;
+ i960.r[(opcode>>19)&0x1f] = program_read_byte_32le(get_ea(opcode));
+ break;
+
+ case 0x82: // stob
+ i960_icount -= 2;
+ program_write_byte_32le(get_ea(opcode), i960.r[(opcode>>19)&0x1f]);
+ break;
+
+ case 0x84: // bx
+ i960_icount -= 3;
+ i960.IP = get_ea(opcode);
+ change_pc(i960.IP);
+ break;
+
+ case 0x85: // balx
+ i960_icount -= 5;
+ t1 = get_ea(opcode);
+ i960.r[(opcode>>19)&0x1f] = i960.IP;
+ i960.IP = t1;
+ change_pc(i960.IP);
+ break;
+
+ case 0x86: // callx
+ t1 = get_ea(opcode);
+ do_call(t1, 0, i960.r[I960_SP]);
+ break;
+
+ case 0x88: // ldos
+ i960_icount -= 4;
+ i960.r[(opcode>>19)&0x1f] = i960_read_word_unaligned(get_ea(opcode));
+ break;
+
+ case 0x8a: // stos
+ i960_icount -= 2;
+ i960_write_word_unaligned(get_ea(opcode), i960.r[(opcode>>19)&0x1f]);
+ break;
+
+ case 0x8c: // lda
+ i960_icount--;
+ i960.r[(opcode>>19)&0x1f] = get_ea(opcode);
+ break;
+
+ case 0x90: // ld
+ i960_icount -= 4;
+ i960.r[(opcode>>19)&0x1f] = i960_read_dword_unaligned(get_ea(opcode));
+ break;
+
+ case 0x92: // st
+ i960_icount -= 2;
+ i960_write_dword_unaligned(get_ea(opcode), i960.r[(opcode>>19)&0x1f]);
+ break;
+
+ case 0x98:{// ldl
+ int i;
+ i960_icount -= 5;
+ t1 = get_ea(opcode);
+ t2 = (opcode>>19)&0x1e;
+ i960.bursting = 1;
+ for(i=0; i<2; i++) {
+ i960.r[t2+i] = i960_read_dword_unaligned(t1);
+ if(i960.bursting)
+ t1 += 4;
+ }
+ break;
+ }
+
+ case 0x9a:{// stl
+ int i;
+ i960_icount -= 3;
+ t1 = get_ea(opcode);
+ t2 = (opcode>>19)&0x1e;
+ i960.bursting = 1;
+ for(i=0; i<2; i++) {
+ i960_write_dword_unaligned(t1, i960.r[t2+i]);
+ if(i960.bursting)
+ t1 += 4;
+ }
+ break;
+ }
+
+ case 0xa0:{// ldt
+ int i;
+ i960_icount -= 6;
+ t1 = get_ea(opcode);
+ t2 = (opcode>>19)&0x1c;
+ i960.bursting = 1;
+ for(i=0; i<3; i++) {
+ i960.r[t2+i] = i960_read_dword_unaligned(t1);
+ if(i960.bursting)
+ t1 += 4;
+ }
+ break;
+ }
+
+ case 0xa2:{// stt
+ int i;
+ i960_icount -= 4;
+ t1 = get_ea(opcode);
+ t2 = (opcode>>19)&0x1c;
+ i960.bursting = 1;
+ for(i=0; i<3; i++) {
+ i960_write_dword_unaligned(t1, i960.r[t2+i]);
+ if(i960.bursting)
+ t1 += 4;
+ }
+ break;
+ }
+
+ case 0xb0:{// ldq
+ int i;
+ i960_icount -= 7;
+ t1 = get_ea(opcode);
+ t2 = (opcode>>19)&0x1c;
+ i960.bursting = 1;
+ for(i=0; i<4; i++) {
+ i960.r[t2+i] = i960_read_dword_unaligned(t1);
+ if(i960.bursting)
+ t1 += 4;
+ }
+ break;
+ }
+
+ case 0xb2:{// stq
+ int i;
+ i960_icount -= 5;
+ t1 = get_ea(opcode);
+ t2 = (opcode>>19)&0x1c;
+ i960.bursting = 1;
+ for(i=0; i<4; i++) {
+ i960_write_dword_unaligned(t1, i960.r[t2+i]);
+ if(i960.bursting)
+ t1 += 4;
+ }
+ break;
+ }
+
+ case 0xc0: // ldib
+ i960_icount -= 4;
+ i960.r[(opcode>>19)&0x1f] = (INT8)program_read_byte_32le(get_ea(opcode));
+ break;
+
+ case 0xc2: // stib
+ i960_icount -= 2;
+ program_write_byte_32le(get_ea(opcode), i960.r[(opcode>>19)&0x1f]);
+ break;
+
+ case 0xc8: // ldis
+ i960_icount -= 4;
+ i960.r[(opcode>>19)&0x1f] = (INT16)i960_read_word_unaligned(get_ea(opcode));
+ break;
+
+ case 0xca: // stis
+ i960_icount -= 2;
+ i960_write_word_unaligned(get_ea(opcode), i960.r[(opcode>>19)&0x1f]);
+ break;
+
+ default:
+ fatalerror("I960: %x: Unhandled %02x", i960.PIP, opcode >> 24);
+ }
+ }
+ return cycles - i960_icount;
+}
+
+static void i960_get_context(void *context)
+{
+ *(i960_state *)context = i960;
+}
+
+static void i960_set_context(void *context)
+{
+ i960 = *(i960_state *)context;
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ int int_tab = program_read_dword_32le(i960.PRCB+20); // interrupt table
+ int cpu_pri = (i960.PC>>16)&0x1f;
+ int vector =0;
+ int priority;
+ UINT32 pend, word, wordofs;
+
+ // We support the 4 external IRQ lines in "normal" mode only.
+ // The i960's interrupt support is a bit more complete than that,
+ // but Namco and Sega both went for the cheapest solution.
+
+ switch (irqline)
+ {
+ case I960_IRQ0:
+ vector = i960.ICR & 0xff;
+ break;
+
+ case I960_IRQ1:
+ vector = (i960.ICR>>8)&0xff;
+ break;
+
+ case I960_IRQ2:
+ vector = (i960.ICR>>16)&0xff;
+ break;
+
+ case I960_IRQ3:
+ vector = (i960.ICR>>24)&0xff;
+ break;
+ }
+
+ if(!vector)
+ {
+ logerror("i960: interrupt line %d in IAC mode, unsupported!\n", irqline);
+ return;
+ }
+
+
+ priority = vector / 8;
+
+ if(state) {
+ // check if we can take this "right now"
+ if (((cpu_pri < priority) || (priority == 31)) && (i960.immediate_irq == 0))
+ {
+ i960.immediate_irq = 1;
+ i960.immediate_vector = vector;
+ i960.immediate_pri = priority;
+ }
+ else
+ {
+ // store the interrupt in the "pending" table
+ pend = program_read_dword_32le(int_tab);
+ pend |= (1 << priority);
+ program_write_dword_32le(int_tab, pend);
+
+ // now bitfield-ize the vector
+ word = ((vector / 32) * 4) + 4;
+ wordofs = vector % 32;
+ pend = program_read_dword_32le(int_tab + word);
+ pend |= (1 << wordofs);
+ program_write_dword_32le(int_tab + word, pend);
+ }
+
+ // and ack it to the core now that it's queued
+ (*i960.irq_cb)(irqline);
+ }
+}
+
+static void i960_set_info(UINT32 state, cpuinfo *info)
+{
+ if(state >= CPUINFO_INT_REGISTER+I960_R0 && state <= CPUINFO_INT_REGISTER + I960_G15) {
+ i960.r[state - (CPUINFO_INT_REGISTER + I960_R0)] = info->i;
+ return;
+ }
+
+ switch(state) {
+ // Interfacing
+ case CPUINFO_INT_REGISTER + I960_IP: i960.IP = info->i; change_pc(i960.IP); break;
+ case CPUINFO_INT_INPUT_STATE + I960_IRQ0: set_irq_line(I960_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I960_IRQ1: set_irq_line(I960_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I960_IRQ2: set_irq_line(I960_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + I960_IRQ3: set_irq_line(I960_IRQ3, info->i); break;
+
+ default:
+ fatalerror("i960_set_info %x", state);
+ }
+}
+
+static void i960_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ memset(&i960, 0, sizeof(i960));
+ i960.irq_cb = irqcallback;
+
+ state_save_register_item("i960", index, i960.PIP);
+ state_save_register_item("i960", index, i960.SAT);
+ state_save_register_item("i960", index, i960.PRCB);
+ state_save_register_item("i960", index, i960.PC);
+ state_save_register_item("i960", index, i960.AC);
+ state_save_register_item("i960", index, i960.ICR);
+ state_save_register_item_array("i960", index, i960.r);
+ state_save_register_item_array("i960", index, i960.fp);
+ state_save_register_item_2d_array("i960", index, i960.rcache);
+ state_save_register_item_array("i960", index, i960.rcache_frame_addr);
+}
+
+#ifdef MAME_DEBUG
+static offs_t i960_disasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ disassemble_t dis;
+
+ dis.IP = pc;
+ dis.buffer = buffer;
+ dis.oprom = oprom;
+
+ i960_disassemble(&dis);
+
+ return dis.IPinc | dis.disflags | DASMFLAG_SUPPORTED;
+}
+#endif /* MAME_DEBUG */
+
+static void i960_reset(void)
+{
+ i960.SAT = program_read_dword_32le(0);
+ i960.PRCB = program_read_dword_32le(4);
+ i960.IP = program_read_dword_32le(12);
+ i960.PC = 0x001f2002;
+ i960.AC = 0;
+ i960.ICR = 0xff000000;
+ i960.bursting = 0;
+ i960.immediate_irq = 0;
+
+ memset(i960.r, 0, sizeof(i960.r));
+ memset(i960.rcache, 0, sizeof(i960.rcache));
+
+ i960.r[I960_FP] = program_read_dword_32le(i960.PRCB+24);
+ i960.r[I960_SP] = i960.r[I960_FP] + 64;
+ i960.rcache_pos = 0;
+}
+
+void i960_get_info(UINT32 state, cpuinfo *info)
+{
+ if(state >= CPUINFO_INT_REGISTER+I960_R0 && state <= CPUINFO_INT_REGISTER + I960_G15) {
+ info->i = i960.r[state - (CPUINFO_INT_REGISTER + I960_R0)];
+ return;
+ }
+
+ switch(state) {
+ // Interface functions and variables
+ case CPUINFO_PTR_SET_INFO: info->setinfo = i960_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = i960_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = i960_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = i960_init; break;
+ case CPUINFO_PTR_RESET: info->reset = i960_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = 0; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = i960_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = 0; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = i960_disasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i960_icount; break;
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(i960_state); break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break;
+
+ // Bus sizes
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ // Internal maps
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO: info->internal_map = 0; break;
+
+ // CPU misc parameters
+ case CPUINFO_STR_NAME: strcpy(info->s, "i960KB"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_FLAGS: strcpy(info->s, i960_get_strflags()); break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 4; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = -1; break;
+
+ // CPU main state
+ case CPUINFO_INT_PC: info->i = i960.IP; break;
+ case CPUINFO_INT_SP: info->i = i960.r[I960_SP]; break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = i960.PIP; break;
+
+ case CPUINFO_INT_REGISTER + I960_SAT: info->i = i960.SAT; break;
+ case CPUINFO_INT_REGISTER + I960_PRCB: info->i = i960.PRCB; break;
+ case CPUINFO_INT_REGISTER + I960_PC: info->i = i960.PC; break;
+ case CPUINFO_INT_REGISTER + I960_AC: info->i = i960.AC; break;
+ case CPUINFO_INT_REGISTER + I960_IP: info->i = i960.IP; break;
+ case CPUINFO_INT_REGISTER + I960_PIP: info->i = i960.PIP; break;
+
+ // CPU debug stuff
+ case CPUINFO_STR_REGISTER + I960_SAT: sprintf(info->s, "sat :%08x", i960.SAT); break;
+ case CPUINFO_STR_REGISTER + I960_PRCB: sprintf(info->s, "prcb :%08x", i960.PRCB); break;
+ case CPUINFO_STR_REGISTER + I960_PC: sprintf(info->s, "pc :%08x", i960.PC); break;
+ case CPUINFO_STR_REGISTER + I960_AC: sprintf(info->s, "ac :%08x", i960.AC); break;
+ case CPUINFO_STR_REGISTER + I960_IP: sprintf(info->s, "ip :%08x", i960.IP); break;
+ case CPUINFO_STR_REGISTER + I960_PIP: sprintf(info->s, "pip :%08x", i960.PIP); break;
+
+ case CPUINFO_STR_REGISTER + I960_R0: sprintf(info->s, "pfp :%08x", i960.r[ 0]); break;
+ case CPUINFO_STR_REGISTER + I960_R1: sprintf(info->s, "sp :%08x", i960.r[ 1]); break;
+ case CPUINFO_STR_REGISTER + I960_R2: sprintf(info->s, "rip :%08x", i960.r[ 2]); break;
+ case CPUINFO_STR_REGISTER + I960_R3: sprintf(info->s, "r3 :%08x", i960.r[ 3]); break;
+ case CPUINFO_STR_REGISTER + I960_R4: sprintf(info->s, "r4 :%08x", i960.r[ 4]); break;
+ case CPUINFO_STR_REGISTER + I960_R5: sprintf(info->s, "r5 :%08x", i960.r[ 5]); break;
+ case CPUINFO_STR_REGISTER + I960_R6: sprintf(info->s, "r6 :%08x", i960.r[ 6]); break;
+ case CPUINFO_STR_REGISTER + I960_R7: sprintf(info->s, "r7 :%08x", i960.r[ 7]); break;
+ case CPUINFO_STR_REGISTER + I960_R8: sprintf(info->s, "r8 :%08x", i960.r[ 8]); break;
+ case CPUINFO_STR_REGISTER + I960_R9: sprintf(info->s, "r9 :%08x", i960.r[ 9]); break;
+ case CPUINFO_STR_REGISTER + I960_R10: sprintf(info->s, "r10 :%08x", i960.r[10]); break;
+ case CPUINFO_STR_REGISTER + I960_R11: sprintf(info->s, "r11 :%08x", i960.r[11]); break;
+ case CPUINFO_STR_REGISTER + I960_R12: sprintf(info->s, "r12 :%08x", i960.r[12]); break;
+ case CPUINFO_STR_REGISTER + I960_R13: sprintf(info->s, "r13 :%08x", i960.r[13]); break;
+ case CPUINFO_STR_REGISTER + I960_R14: sprintf(info->s, "r14 :%08x", i960.r[14]); break;
+ case CPUINFO_STR_REGISTER + I960_R15: sprintf(info->s, "r15 :%08x", i960.r[15]); break;
+
+ case CPUINFO_STR_REGISTER + I960_G0: sprintf(info->s, "g0 :%08x", i960.r[16]); break;
+ case CPUINFO_STR_REGISTER + I960_G1: sprintf(info->s, "g1 :%08x", i960.r[17]); break;
+ case CPUINFO_STR_REGISTER + I960_G2: sprintf(info->s, "g2 :%08x", i960.r[18]); break;
+ case CPUINFO_STR_REGISTER + I960_G3: sprintf(info->s, "g3 :%08x", i960.r[19]); break;
+ case CPUINFO_STR_REGISTER + I960_G4: sprintf(info->s, "g4 :%08x", i960.r[20]); break;
+ case CPUINFO_STR_REGISTER + I960_G5: sprintf(info->s, "g5 :%08x", i960.r[21]); break;
+ case CPUINFO_STR_REGISTER + I960_G6: sprintf(info->s, "g6 :%08x", i960.r[22]); break;
+ case CPUINFO_STR_REGISTER + I960_G7: sprintf(info->s, "g7 :%08x", i960.r[23]); break;
+ case CPUINFO_STR_REGISTER + I960_G8: sprintf(info->s, "g8 :%08x", i960.r[24]); break;
+ case CPUINFO_STR_REGISTER + I960_G9: sprintf(info->s, "g9 :%08x", i960.r[25]); break;
+ case CPUINFO_STR_REGISTER + I960_G10: sprintf(info->s, "g10 :%08x", i960.r[26]); break;
+ case CPUINFO_STR_REGISTER + I960_G11: sprintf(info->s, "g11 :%08x", i960.r[27]); break;
+ case CPUINFO_STR_REGISTER + I960_G12: sprintf(info->s, "g12 :%08x", i960.r[28]); break;
+ case CPUINFO_STR_REGISTER + I960_G13: sprintf(info->s, "g13 :%08x", i960.r[29]); break;
+ case CPUINFO_STR_REGISTER + I960_G14: sprintf(info->s, "g14 :%08x", i960.r[30]); break;
+ case CPUINFO_STR_REGISTER + I960_G15: sprintf(info->s, "fp :%08x", i960.r[31]); break;
+
+// default:
+// fatalerror("i960_get_info %x ", state);
+ }
+}
+
+// call from any read/write handler for a memory area that can't be bursted
+// on the real hardware (e.g. Model 2's interrupt control registers)
+void i960_noburst(void)
+{
+ i960.bursting = 0;
+}
+
+void i960_stall(void)
+{
+ i960.IP = i960.PIP;
+}
diff --git a/src/emu/cpu/i960/i960.h b/src/emu/cpu/i960/i960.h
new file mode 100644
index 00000000000..320d25c77a6
--- /dev/null
+++ b/src/emu/cpu/i960/i960.h
@@ -0,0 +1,64 @@
+#ifndef __I960_H
+#define __I960_H
+
+#include "cpuintrf.h"
+
+enum {
+ I960_PFP = 0,
+ I960_SP = 1,
+ I960_RIP = 2,
+ I960_FP = 31,
+
+ I960_R0 = 0,
+ I960_R1 = 1,
+ I960_R2 = 2,
+ I960_R3 = 3,
+ I960_R4 = 4,
+ I960_R5 = 5,
+ I960_R6 = 6,
+ I960_R7 = 7,
+ I960_R8 = 8,
+ I960_R9 = 9,
+ I960_R10 = 10,
+ I960_R11 = 11,
+ I960_R12 = 12,
+ I960_R13 = 13,
+ I960_R14 = 14,
+ I960_R15 = 15,
+ I960_G0 = 16,
+ I960_G1 = 17,
+ I960_G2 = 18,
+ I960_G3 = 19,
+ I960_G4 = 20,
+ I960_G5 = 21,
+ I960_G6 = 22,
+ I960_G7 = 23,
+ I960_G8 = 24,
+ I960_G9 = 25,
+ I960_G10 = 26,
+ I960_G11 = 27,
+ I960_G12 = 28,
+ I960_G13 = 29,
+ I960_G14 = 30,
+ I960_G15 = 31,
+
+ I960_SAT = 32,
+ I960_PRCB = 33,
+ I960_PC = 34,
+ I960_AC = 35,
+ I960_IP = 36,
+ I960_PIP = 37
+};
+
+enum {
+ I960_IRQ0 = 0,
+ I960_IRQ1 = 1,
+ I960_IRQ2 = 2,
+ I960_IRQ3 = 3
+};
+
+void i960_get_info(UINT32 state, cpuinfo *info);
+void i960_noburst(void);
+void i960_stall(void);
+
+#endif
diff --git a/src/emu/cpu/i960/i960dis.c b/src/emu/cpu/i960/i960dis.c
new file mode 100644
index 00000000000..67837f21cf5
--- /dev/null
+++ b/src/emu/cpu/i960/i960dis.c
@@ -0,0 +1,291 @@
+/*
+ Intel i960 disassembler
+
+ By Farfetch'd and R. Belmont
+*/
+
+#include "i960.h"
+#include "i960dis.h"
+
+typedef struct
+{
+ const char *mnem;
+ unsigned short type;
+} mnemonic_t;
+
+
+static const mnemonic_t mnemonic[256] = {
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 00
+ { "b", 8 }, { "call", 8 }, { "ret", 9 }, { "bal", 8 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "bno", 8 }, { "bg", 8 }, { "be", 8 }, { "bge", 8 }, { "bl", 8 }, { "bne", 8 }, { "ble", 8 }, { "bo", 8 }, // 10
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "testno", 10 }, { "testg", 10 }, { "teste", 10 }, { "testge", 10 }, { "testl", 10 }, { "testne", 10 }, { "testle", 10 }, { "testo", 10 }, // 20
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "bbc", 6 }, { "cmpobg", 7 }, { "cmpobe", 7 }, { "cmpobge", 7 }, { "cmpobl", 7 }, { "cmpobne", 7 }, { "cmpoble", 7 }, { "bbs", 6 }, // 30
+ { "cmpibno", 7 }, { "cmpibg", 7 }, { "cmpibe", 7 }, { "cmpibge", 7 }, { "cmpibl", 7 }, { "cmpibne", 7 }, { "cmpible", 7 }, { "cmpibo", 7 },
+
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 40
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 50
+ { "58", 3 }, { "59", 3 }, { "5A", 3 }, { "5B", 3 }, { "5C", 2 }, { "5D", 3 }, { "?", 0 }, { "5F", 3 },
+
+ { "synmov", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "64", 3 }, { "65", 3 }, { "calls", 0 }, { "67", 3 }, // 60
+ { "68", 3 }, { "69", 3 }, { "?", 0 }, { "?", 0 }, { "6C", 3 }, { "6D", 3 }, { "6E", 3 }, { "?", 0 },
+
+ { "70", 3 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "74", 3 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 70
+ { "78", 3 }, { "79", 3 }, { "7A", 3 }, { "7B", 3 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "ldob", 1 }, { "?", 0 }, { "stob", 1 }, { "?", 0 }, { "bx", 1 }, { "balx", 1 }, { "callx", 1 }, { "?", 0 }, // 80
+ { "ldos", 1 }, { "?", 0 }, { "stos", 1 }, { "?", 0 }, { "lda", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "ld", 1 }, { "?", 0 }, { "st", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 90
+ { "ldl", 1 }, { "?", 0 }, { "stl", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "ldt", 1 }, { "?", 0 }, { "stt", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // a0
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "ldq", 1 }, { "?", 0 }, { "stq", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // b0
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "ldib", 1 }, { "?", 0 }, { "stib", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // c0
+ { "ldis", 1 }, { "?", 0 }, { "stis", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // d0
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // e0
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 },
+
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // f0
+ { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }
+};
+
+static const mnemonic_t mnem_reg[100] =
+{
+ { "notbit", 0x580 }, { "and", 0x581 }, { "andnot", 0x582 }, { "setbit", 0x583 }, { "notand",0x584 },
+ { "xor", 0x586 }, { "or", 0x587 }, { "nor", 0x588 }, { "xnor",0x589 }, { "not",0x58a },
+ { "clrbit", 0x58c },
+ { "addo", 0x590 }, { "addi",0x591 }, { "subo",0x592 }, { "subi",0x593 }, { "cmpob",0x594 }, { "shro",0x598 }, { "shrdi",0x59a }, { "shri",0x59b }, { "shlo",0x59c }, { "rotate",0x59d }, { "shli",0x59e },
+ { "cmpo",0x5a0 }, { "cmpi",0x5a1 }, { "concmpo",0x5a2 }, { "concmpi",0x5a3 }, { "cmpinco",0x5a4 }, { "cmpinci",0x5a5 }, { "cmpdeco",0x5a6 }, { "cmpdeci",0x5a7 }, { "scanbyte",0x5ac }, { "bswap",0x5ad }, { "chkbit",0x5ae },
+ { "addc",0x5b0 }, { "subc",0x5b2 },
+ { "mov", 0x5cc },
+ { "movl",0x5dc },
+ { "movq",0x5fc },
+ { "scanbit", 0x641 }, { "daddc", 0x642 }, { "dsubc", 0x643 }, { "dmovt", 0x644 }, { "modac",0x645 },
+ { "modify",0x650 }, { "extract",0x651 }, { "modtc",0x654 }, { "modpc",0x655 },
+ { "emul",0x670 }, { "ediv",0x671 },
+ { "atanr",0x680 }, { "logepr", 0x681 }, { "logr", 0x682 }, { "remr", 0x683 }, { "cmpor", 0x684 }, { "cmpr", 0x685 }, { "sqrtr", 0x688 },
+ { "expr", 0x689 }, { "logbnr", 0x68a }, { "roundr", 0x68b }, { "sinr", 0x68c }, { "cosr", 0x68d }, { "tanr", 0x68e }, { "classr", 0x68f },
+ { "atanrl",0x690 }, { "logeprl", 0x691 }, { "logrl", 0x692 }, { "remrl", 0x693 }, { "cmporl", 0x694 }, { "cmprl", 0x695 }, { "sqrtrl", 0x698 },
+ { "exprl", 0x699 }, { "logbnrl", 0x69a }, { "roundrl", 0x69b }, { "sinrl", 0x69c }, { "cosrl", 0x69d }, { "tanrl", 0x69e }, { "classrl", 0x69f },
+ { "cvtri", 0x6c0 }, { "cvtril", 0x6c1 }, { "cvtzri", 0x6c2 }, { "cvtzril", 0x6c3 }, { "movr", 0x6c9 },
+ { "movrl", 0x6d9 },
+ { "movre", 0x6e1 }, { "cpysre", 0x6e2 }, { "cpyrsre", 0x6e3 },
+ { "mulo", 0x701 }, { "remo",0x708 }, { "divo",0x70b },
+ { "muli",0x741 }, { "remi",0x748 }, { "modi",0x749 }, { "divi",0x74b },
+ { "ending_code",0 }
+};
+
+static const char *constnames[32] =
+{
+ "0x0", "0x1", "0x2", "0x3", "0x4", "0x5", "0x6", "0x7", "0x8", "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf",
+ "0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f"
+};
+
+static const char *regnames[32] =
+{
+ "pfp","sp","rip","r3", "r4","r5","r6","r7", "r8","r9","r10","r11", "r12","r13","r14","r15",
+ "g0","g1","g2","g3", "g4","g5","g6","g7", "g8","g9","g10","g11", "g12","g13","g14","fp",
+};
+
+#define REG_DST regnames[dst]
+#define REG_ABASE regnames[abase]
+#define REG_REG2 regnames[reg2]
+#define REG_COBR_SRC1 ((iCode & 0x2000) ? constnames[COBRSRC1] : regnames[COBRSRC1])
+#define REG_COBR_SRC2 regnames[COBRSRC2]
+#define NEM mnemonic[op].mnem
+
+// REG format
+#define SRC1 (iCode & 0x1f)
+#define S1 ((iCode >> 5) & 0x1)
+#define S2 ((iCode >> 6) & 0x1)
+#define OP2 ((iCode >> 7) & 0xf)
+#define M1 ((iCode >> 11) & 0x1)
+#define M2 ((iCode >> 12) & 0x1)
+#define M3 ((iCode >> 13) & 0x1)
+#define SRC2 ((iCode >> 14) & 0x1f)
+#define DST ((iCode >> 19) & 0x1f)
+#define OP ((iCode >> 24) & 0xff)
+
+// COBR format
+#define COBRSRC1 ((iCode >> 19) & 0x1f)
+#define COBRSRC2 ((iCode >> 14) & 0x1f)
+
+static char *dis_decode_reg(unsigned long iCode, char* tmpStr,unsigned char cnt)
+{
+ char src1[10];
+ char src2[10];
+ char dst[10];
+
+ if (S1) src1[0] = 0;
+ else
+ {
+ if(M1) sprintf(src1,"0x%lx",SRC1);
+ else sprintf(src1,"%s",regnames[SRC1]);
+ }
+ if (S2) sprintf(src2,"reserved");
+ else
+ {
+ if(M2) sprintf(src2,"0x%lx,",SRC2);
+ else sprintf(src2,"%s,",regnames[SRC2]);
+ }
+ if(M3) dst[0] = 0;
+ else sprintf(dst,"%s,",regnames[DST]);
+ if (cnt == 1)
+ sprintf(tmpStr,"%s%s",dst,src1);
+ else
+ sprintf(tmpStr,"%s%s%s",dst,src2,src1);
+ return tmpStr;
+}
+
+#define READ32(dis,offs) ((dis)->oprom[(offs) + 0] | ((dis)->oprom[(offs) + 1] << 8) | ((dis)->oprom[(offs) + 2] << 16) | ((dis)->oprom[(offs) + 3] << 24))
+
+char *i960_disassemble(disassemble_t *diss)
+{
+ unsigned char op,op2;
+ unsigned char mode, modeh, model;
+ unsigned char dst,abase,reg2;
+ unsigned short opc;
+ unsigned long iCode;
+ char tmpStr[256];
+ long i;
+
+ iCode = READ32(diss,0);
+ op = (unsigned char) (iCode >> 24);
+ op2 = (unsigned char) (iCode >> 7)&0xf;
+
+ model = (unsigned char) (iCode >> 10) &0x3;
+ modeh = (unsigned char) (iCode >> 12) &0x3;
+ mode = (unsigned char) (iCode >> 10) &0x7;
+ dst = (unsigned char) (iCode >> 19) &0x1f;
+ abase = (unsigned char) (iCode>>14)&0x1f;
+ reg2 = (unsigned char) (iCode)&0x1f;
+
+ sprintf(diss->buffer,"???");
+ diss->IPinc = 4;
+ diss->disflags = 0;
+
+ if (op == 0x09 || op == 0x0b || op == 0x66 || op == 0x85 || op == 0x86)
+ diss->disflags = DASMFLAG_STEP_OVER;
+ else if (op == 0x0a)
+ diss->disflags = DASMFLAG_STEP_OUT;
+
+ switch(mnemonic[op].type)
+ {
+ case 0: // not yet implemented
+ sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model);
+ break;
+ case 1: // memory access
+ switch(modeh)
+ {
+ case 0:
+ sprintf(diss->buffer, "%-8s%s,0x%lx",NEM,REG_DST, iCode&0xfff);
+ break;
+ case 1:
+ switch (model)
+ {
+ case 0:
+ sprintf(diss->buffer, "%-8s%s,(%s)",NEM,REG_DST, REG_ABASE);
+ break;
+ case 3:
+ sprintf(diss->buffer, "%-8s%s,(%s)[%s*%ld]",NEM,REG_DST, REG_ABASE,REG_REG2,(iCode>>7)&0x7);
+ break;
+ default:
+ sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model);
+ break;
+ }
+ break;
+ case 2:
+ sprintf(diss->buffer, "%-8s%s,0x%lx(%s)",NEM,REG_DST, iCode&0xfff,REG_ABASE);
+ break;
+ case 3:
+ switch (model)
+ {
+ case 0:
+ sprintf(diss->buffer, "%-8s%s,0x%x",NEM,REG_DST, READ32(diss,4));
+ diss->IPinc = 8;
+ break;
+ case 1:
+ sprintf(diss->buffer, "%-8s%s,0x%x(%s)",NEM,REG_DST, READ32(diss,4),REG_ABASE);
+ diss->IPinc = 8;
+ break;
+ case 2:
+ sprintf(diss->buffer, "%-8s%s,0x%x[%s*%ld]",NEM,REG_DST, READ32(diss,4),REG_REG2,(iCode>>7)&0x7);
+ diss->IPinc = 8;
+ break;
+ case 3:
+ sprintf(diss->buffer, "%-8s%s,0x%x(%s)[%s*%ld]",NEM,REG_DST, READ32(diss,4),REG_ABASE,REG_REG2,(iCode>>7)&0x7);
+ diss->IPinc = 8;
+ break;
+ default:
+ sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model);
+ break;
+ }
+ break;
+ default:
+ sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model);
+ break;
+ }
+ break;
+ case 2:
+ i = 0;
+ opc = op<<4|op2;
+
+ while(mnem_reg[i].type != 0)
+ {
+ if (mnem_reg[i].type == opc) break;
+ i++;
+ }
+
+ if (mnem_reg[i].type == opc) sprintf(diss->buffer, "%-8s%s", mnem_reg[i].mnem,dis_decode_reg(iCode,tmpStr,1));
+ else sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model);
+ break;
+ case 3:
+ i = 0;
+ opc = op<<4|op2;
+
+ while(mnem_reg[i].type != 0)
+ {
+ if (mnem_reg[i].type == opc) break;
+ i++;
+ }
+
+ if (mnem_reg[i].type == opc) sprintf(diss->buffer, "%-8s%s", mnem_reg[i].mnem,dis_decode_reg(iCode,tmpStr,0));
+ else sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model);
+ break;
+
+ case 6: // bitpos and branch type
+ sprintf(diss->buffer, "%-8s%ld,%s,0x%lx",NEM, COBRSRC1, REG_COBR_SRC2,((((long)iCode&0x00fffffc)<<19)>>19) + (diss->IP));
+ break;
+ case 7: // compare and branch type
+ sprintf(diss->buffer, "%-8s%s,%s,0x%lx",NEM,REG_COBR_SRC1,REG_COBR_SRC2,((((long)iCode&0x00fffffc)<<19)>>19) + (diss->IP));
+ break;
+ case 8: // target type
+ sprintf(diss->buffer, "%-8s%08lx",NEM,((((long)iCode&0x00fffffc)<<8)>>8) + (diss->IP));
+ break;
+ case 9: // no operands
+ sprintf(diss->buffer, "%s",NEM);
+ break;
+ case 10: // TEST type: register only
+ sprintf(diss->buffer, "%s %s", NEM, REG_DST);
+ break;
+ }
+ return diss->buffer;
+}
+
+
+
diff --git a/src/emu/cpu/i960/i960dis.h b/src/emu/cpu/i960/i960dis.h
new file mode 100644
index 00000000000..82f0c3bf467
--- /dev/null
+++ b/src/emu/cpu/i960/i960dis.h
@@ -0,0 +1,15 @@
+#ifndef _I960DISASSEMBLER_H
+#define _I960DISASSEMBLER_H
+
+typedef struct
+{
+ char *buffer; // output buffer
+ unsigned long IP;
+ unsigned long IPinc;
+ const UINT8 *oprom;
+ UINT32 disflags;
+} disassemble_t;
+
+char *i960_disassemble(disassemble_t *diss);
+
+#endif // _I960DISASSEMBLER_H
diff --git a/src/emu/cpu/jaguar/jagdasm.c b/src/emu/cpu/jaguar/jagdasm.c
new file mode 100644
index 00000000000..7fea6be4e08
--- /dev/null
+++ b/src/emu/cpu/jaguar/jagdasm.c
@@ -0,0 +1,182 @@
+/***************************************************************************
+
+ jagdasm.c
+ Disassembler for the portable Jaguar DSP emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#include "jaguar.h"
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(offs) ((oprom[offs] << 8) | oprom[(offs) + 1])
+
+
+/***************************************************************************
+ STATIC VARIABLES
+***************************************************************************/
+
+static const UINT8 convert_zero[32] =
+{ 32,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 };
+
+static const char *condition[32] =
+{
+ "",
+ "nz,",
+ "z,",
+ "???,",
+ "nc,",
+ "nc nz,",
+ "nc z,",
+ "???,",
+ "c,",
+ "c nz,",
+ "c z,",
+ "???,",
+ "???,",
+ "???,",
+ "???,",
+ "???,",
+
+ "???,",
+ "???,",
+ "???,",
+ "???,",
+ "nn,",
+ "nn nz,",
+ "nn z,",
+ "???,",
+ "n,",
+ "n nz,",
+ "n z,",
+ "???,",
+ "???,",
+ "???,",
+ "???,",
+ "never,"
+};
+
+
+
+/***************************************************************************
+ CODE CODE
+***************************************************************************/
+
+INLINE char *signed_16bit(INT16 val)
+{
+ static char temp[10];
+ if (val < 0)
+ sprintf(temp, "-$%x", -val);
+ else
+ sprintf(temp, "$%x", val);
+ return temp;
+}
+
+unsigned dasmjag(int variant, char *buffer, unsigned pc, const UINT8 *oprom)
+{
+ UINT32 flags = 0;
+ int op = ROPCODE(0);
+ int reg1 = (op >> 5) & 31;
+ int reg2 = op & 31;
+ int size = 2;
+
+ pc += 2;
+ switch (op >> 10)
+ {
+ case 0: sprintf(buffer, "add r%d,r%d", reg1, reg2); break;
+ case 1: sprintf(buffer, "addc r%d,r%d", reg1, reg2); break;
+ case 2: sprintf(buffer, "addq $%x,r%d", convert_zero[reg1], reg2); break;
+ case 3: sprintf(buffer, "addqt $%x,r%d", convert_zero[reg1], reg2); break;
+ case 4: sprintf(buffer, "sub r%d,r%d", reg1, reg2); break;
+ case 5: sprintf(buffer, "subc r%d,r%d", reg1, reg2); break;
+ case 6: sprintf(buffer, "subq $%x,r%d", convert_zero[reg1], reg2); break;
+ case 7: sprintf(buffer, "subqt $%x,r%d", convert_zero[reg1], reg2); break;
+ case 8: sprintf(buffer, "neg r%d", reg2); break;
+ case 9: sprintf(buffer, "and r%d,r%d", reg1, reg2); break;
+ case 10: sprintf(buffer, "or r%d,r%d", reg1, reg2); break;
+ case 11: sprintf(buffer, "xor r%d,r%d", reg1, reg2); break;
+ case 12: sprintf(buffer, "not r%d", reg2); break;
+ case 13: sprintf(buffer, "btst $%x,r%d", reg1, reg2); break;
+ case 14: sprintf(buffer, "bset $%x,r%d", reg1, reg2); break;
+ case 15: sprintf(buffer, "bclr $%x,r%d", reg1, reg2); break;
+ case 16: sprintf(buffer, "mult r%d,r%d", reg1, reg2); break;
+ case 17: sprintf(buffer, "imult r%d,r%d", reg1, reg2); break;
+ case 18: sprintf(buffer, "imultn r%d,r%d", reg1, reg2); break;
+ case 19: sprintf(buffer, "resmac r%d", reg2); break;
+ case 20: sprintf(buffer, "imacn r%d,r%d", reg1, reg2); break;
+ case 21: sprintf(buffer, "div r%d,r%d", reg1, reg2); break;
+ case 22: sprintf(buffer, "abs r%d", reg2); break;
+ case 23: sprintf(buffer, "sh r%d,r%d", reg1, reg2); break;
+ case 24: sprintf(buffer, "shlq $%x,r%d", 32 - convert_zero[reg1], reg2); break;
+ case 25: sprintf(buffer, "shrq $%x,r%d", convert_zero[reg1], reg2); break;
+ case 26: sprintf(buffer, "sha r%d,r%d", reg1, reg2); break;
+ case 27: sprintf(buffer, "sharq $%x,r%d", convert_zero[reg1], reg2); break;
+ case 28: sprintf(buffer, "ror r%d,r%d", reg1, reg2); break;
+ case 29: sprintf(buffer, "rorq $%x,r%d", convert_zero[reg1], reg2); break;
+ case 30: sprintf(buffer, "cmp r%d,r%d", reg1, reg2); break;
+ case 31: sprintf(buffer, "cmpq %s,r%d", signed_16bit((INT16)(reg1 << 11) >> 11), reg2);break;
+ case 32: if (variant == JAGUAR_VARIANT_GPU)
+ sprintf(buffer, "sat8 r%d", reg2);
+ else
+ sprintf(buffer, "subqmod $%x,r%d", convert_zero[reg1], reg2);
+ break;
+ case 33: if (variant == JAGUAR_VARIANT_GPU)
+ sprintf(buffer, "sat16 r%d", reg2);
+ else
+ sprintf(buffer, "sat16s r%d", reg2);
+ break;
+ case 34: sprintf(buffer, "move r%d,r%d", reg1, reg2); break;
+ case 35: sprintf(buffer, "moveq %d,r%d", reg1, reg2); break;
+ case 36: sprintf(buffer, "moveta r%d,r%d", reg1, reg2); break;
+ case 37: sprintf(buffer, "movefa r%d,r%d", reg1, reg2); break;
+ case 38: sprintf(buffer, "movei $%x,r%d", ROPCODE(2) | (ROPCODE(4)<<16), reg2); size = 6; break;
+ case 39: sprintf(buffer, "loadb (r%d),r%d", reg1, reg2); break;
+ case 40: sprintf(buffer, "loadw (r%d),r%d", reg1, reg2); break;
+ case 41: sprintf(buffer, "load (r%d),r%d", reg1, reg2); break;
+ case 42: if (variant == JAGUAR_VARIANT_GPU)
+ sprintf(buffer, "loadp (r%d),r%d", reg1, reg2);
+ else
+ sprintf(buffer, "sat32s r%d", reg2);
+ break;
+ case 43: sprintf(buffer, "load (r14+$%x),r%d", convert_zero[reg1]*4, reg2);break;
+ case 44: sprintf(buffer, "load (r15+$%x),r%d", convert_zero[reg1]*4, reg2);break;
+ case 45: sprintf(buffer, "storeb r%d,(r%d)", reg2, reg1); break;
+ case 46: sprintf(buffer, "storew r%d,(r%d)", reg2, reg1); break;
+ case 47: sprintf(buffer, "store r%d,(r%d)", reg2, reg1); break;
+ case 48: if (variant == JAGUAR_VARIANT_GPU)
+ sprintf(buffer, "storep r%d,(r%d)", reg2, reg1);
+ else
+ sprintf(buffer, "mirror r%d", reg2);
+ break;
+ case 49: sprintf(buffer, "store r%d,(r14+$%x)", reg2, convert_zero[reg1]*4);break;
+ case 50: sprintf(buffer, "store r%d,(r15+$%x)", reg2, convert_zero[reg1]*4);break;
+ case 51: sprintf(buffer, "move pc,r%d", reg2); break;
+ case 52: sprintf(buffer, "jump %s(r%d)", condition[reg2], reg1); break;
+ case 53: sprintf(buffer, "jr %s%08X", condition[reg2], pc + ((INT8)(reg1 << 3) >> 2)); break;
+ case 54: sprintf(buffer, "mmult r%d,r%d", reg1, reg2); break;
+ case 55: sprintf(buffer, "mtoi r%d,r%d", reg1, reg2); break;
+ case 56: sprintf(buffer, "normi r%d,r%d", reg1, reg2); break;
+ case 57: sprintf(buffer, "nop"); break;
+ case 58: sprintf(buffer, "load (r14+r%d),r%d", reg1, reg2); break;
+ case 59: sprintf(buffer, "load (r15+r%d),r%d", reg1, reg2); break;
+ case 60: sprintf(buffer, "store r%d,(r14+r%d)", reg2, reg1); break;
+ case 61: sprintf(buffer, "store r%d,(r15+r%d)", reg2, reg1); break;
+ case 62: if (variant == JAGUAR_VARIANT_GPU)
+ sprintf(buffer, "sat24 r%d", reg2);
+ else
+ sprintf(buffer, "illegal");
+ break;
+ case 63: if (variant == JAGUAR_VARIANT_GPU)
+ sprintf(buffer, reg1 ?
+ "unpack r%d" :
+ "pack r%d", reg2);
+ else
+ sprintf(buffer, "addqmod $%x,r%d", convert_zero[reg1], reg2);
+ break;
+ }
+ return size | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/jaguar/jaguar.c b/src/emu/cpu/jaguar/jaguar.c
new file mode 100644
index 00000000000..1fc18b71269
--- /dev/null
+++ b/src/emu/cpu/jaguar/jaguar.c
@@ -0,0 +1,1761 @@
+/***************************************************************************
+
+ jaguar.c
+ Core implementation for the portable Jaguar DSP emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#include "debugger.h"
+#include "jaguar.h"
+
+#define LOG_GPU_IO 0
+#define LOG_DSP_IO 0
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define ZFLAG 0x00001
+#define CFLAG 0x00002
+#define NFLAG 0x00004
+#define IFLAG 0x00008
+#define EINT0FLAG 0x00010
+#define EINT1FLAG 0x00020
+#define EINT2FLAG 0x00040
+#define EINT3FLAG 0x00080
+#define EINT4FLAG 0x00100
+#define EINT04FLAGS (EINT0FLAG | EINT1FLAG | EINT2FLAG | EINT3FLAG | EINT4FLAG)
+#define CINT0FLAG 0x00200
+#define CINT1FLAG 0x00400
+#define CINT2FLAG 0x00800
+#define CINT3FLAG 0x01000
+#define CINT4FLAG 0x02000
+#define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
+#define RPAGEFLAG 0x04000
+#define DMAFLAG 0x08000
+#define EINT5FLAG 0x10000 /* DSP only */
+#define CINT5FLAG 0x20000 /* DSP only */
+
+#define CLR_Z (jaguar.FLAGS &= ~ZFLAG)
+#define CLR_ZN (jaguar.FLAGS &= ~(ZFLAG | NFLAG))
+#define CLR_ZNC (jaguar.FLAGS &= ~(CFLAG | ZFLAG | NFLAG))
+#define SET_Z(r) (jaguar.FLAGS |= ((r) == 0))
+#define SET_C_ADD(a,b) (jaguar.FLAGS |= ((UINT32)(b) > (UINT32)(~(a))) << 1)
+#define SET_C_SUB(a,b) (jaguar.FLAGS |= ((UINT32)(b) > (UINT32)(a)) << 1)
+#define SET_N(r) (jaguar.FLAGS |= (((UINT32)(r) >> 29) & 4))
+#define SET_ZN(r) SET_N(r); SET_Z(r)
+#define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
+#define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define PC ctrl[G_PC]
+#define FLAGS ctrl[G_FLAGS]
+
+#define CONDITION(x) condition_table[(x) + ((jaguar.FLAGS & 7) << 5)]
+
+#define READBYTE(a) program_read_byte_32be(a)
+#define READWORD(a) program_read_word_32be(a)
+#define READLONG(a) program_read_dword_32be(a)
+
+#define WRITEBYTE(a,v) program_write_byte_32be(a,v)
+#define WRITEWORD(a,v) program_write_word_32be(a,v)
+#define WRITELONG(a,v) program_write_dword_32be(a,v)
+
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+/* Jaguar Registers */
+typedef struct
+{
+ /* core registers */
+ UINT32 r[32];
+ UINT32 a[32];
+ UINT32 * b0;
+ UINT32 * b1;
+
+ /* control registers */
+ UINT32 ctrl[G_CTRLMAX];
+ UINT32 ppc;
+ UINT64 accum;
+
+ /* internal stuff */
+ int isdsp;
+ int op;
+ int interrupt_cycles;
+ void (**table)(void);
+ int (*irq_callback)(int irqline);
+ void (*cpu_interrupt)(void);
+} jaguar_regs;
+
+
+
+/***************************************************************************
+ PUBLIC GLOBAL VARIABLES
+***************************************************************************/
+
+static int jaguar_icount;
+static int bankswitch_icount;
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static jaguar_regs jaguar;
+static UINT16 * mirror_table;
+static UINT8 * condition_table;
+static int executing_cpu = -1;
+
+static const UINT32 convert_zero[32] =
+{ 32,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 };
+
+
+
+/***************************************************************************
+ FUNCTION TABLES
+***************************************************************************/
+
+static void abs_rn(void);
+static void add_rn_rn(void);
+static void addc_rn_rn(void);
+static void addq_n_rn(void);
+static void addqmod_n_rn(void); /* DSP only */
+static void addqt_n_rn(void);
+static void and_rn_rn(void);
+static void bclr_n_rn(void);
+static void bset_n_rn(void);
+static void btst_n_rn(void);
+static void cmp_rn_rn(void);
+static void cmpq_n_rn(void);
+static void div_rn_rn(void);
+static void illegal(void);
+static void imacn_rn_rn(void);
+static void imult_rn_rn(void);
+static void imultn_rn_rn(void);
+static void jr_cc_n(void);
+static void jump_cc_rn(void);
+static void load_rn_rn(void);
+static void load_r14n_rn(void);
+static void load_r15n_rn(void);
+static void load_r14rn_rn(void);
+static void load_r15rn_rn(void);
+static void loadb_rn_rn(void);
+static void loadw_rn_rn(void);
+static void loadp_rn_rn(void); /* GPU only */
+static void mirror_rn(void); /* DSP only */
+static void mmult_rn_rn(void);
+static void move_rn_rn(void);
+static void move_pc_rn(void);
+static void movefa_rn_rn(void);
+static void movei_n_rn(void);
+static void moveq_n_rn(void);
+static void moveta_rn_rn(void);
+static void mtoi_rn_rn(void);
+static void mult_rn_rn(void);
+static void neg_rn(void);
+static void nop(void);
+static void normi_rn_rn(void);
+static void not_rn(void);
+static void or_rn_rn(void);
+static void pack_rn(void); /* GPU only */
+static void resmac_rn(void);
+static void ror_rn_rn(void);
+static void rorq_n_rn(void);
+static void sat8_rn(void); /* GPU only */
+static void sat16_rn(void); /* GPU only */
+static void sat16s_rn(void); /* DSP only */
+static void sat24_rn(void); /* GPU only */
+static void sat32s_rn(void); /* DSP only */
+static void sh_rn_rn(void);
+static void sha_rn_rn(void);
+static void sharq_n_rn(void);
+static void shlq_n_rn(void);
+static void shrq_n_rn(void);
+static void store_rn_rn(void);
+static void store_rn_r14n(void);
+static void store_rn_r15n(void);
+static void store_rn_r14rn(void);
+static void store_rn_r15rn(void);
+static void storeb_rn_rn(void);
+static void storew_rn_rn(void);
+static void storep_rn_rn(void); /* GPU only */
+static void sub_rn_rn(void);
+static void subc_rn_rn(void);
+static void subq_n_rn(void);
+static void subqmod_n_rn(void); /* DSP only */
+static void subqt_n_rn(void);
+static void xor_rn_rn(void);
+
+static void (*gpu_op_table[64])(void) =
+{
+ /* 00-03 */ add_rn_rn, addc_rn_rn, addq_n_rn, addqt_n_rn,
+ /* 04-07 */ sub_rn_rn, subc_rn_rn, subq_n_rn, subqt_n_rn,
+ /* 08-11 */ neg_rn, and_rn_rn, or_rn_rn, xor_rn_rn,
+ /* 12-15 */ not_rn, btst_n_rn, bset_n_rn, bclr_n_rn,
+ /* 16-19 */ mult_rn_rn, imult_rn_rn, imultn_rn_rn, resmac_rn,
+ /* 20-23 */ imacn_rn_rn, div_rn_rn, abs_rn, sh_rn_rn,
+ /* 24-27 */ shlq_n_rn, shrq_n_rn, sha_rn_rn, sharq_n_rn,
+ /* 28-31 */ ror_rn_rn, rorq_n_rn, cmp_rn_rn, cmpq_n_rn,
+ /* 32-35 */ sat8_rn, sat16_rn, move_rn_rn, moveq_n_rn,
+ /* 36-39 */ moveta_rn_rn, movefa_rn_rn, movei_n_rn, loadb_rn_rn,
+ /* 40-43 */ loadw_rn_rn, load_rn_rn, loadp_rn_rn, load_r14n_rn,
+ /* 44-47 */ load_r15n_rn, storeb_rn_rn, storew_rn_rn, store_rn_rn,
+ /* 48-51 */ storep_rn_rn, store_rn_r14n, store_rn_r15n, move_pc_rn,
+ /* 52-55 */ jump_cc_rn, jr_cc_n, mmult_rn_rn, mtoi_rn_rn,
+ /* 56-59 */ normi_rn_rn, nop, load_r14rn_rn, load_r15rn_rn,
+ /* 60-63 */ store_rn_r14rn, store_rn_r15rn, sat24_rn, pack_rn
+};
+
+static void (*dsp_op_table[64])(void) =
+{
+ /* 00-03 */ add_rn_rn, addc_rn_rn, addq_n_rn, addqt_n_rn,
+ /* 04-07 */ sub_rn_rn, subc_rn_rn, subq_n_rn, subqt_n_rn,
+ /* 08-11 */ neg_rn, and_rn_rn, or_rn_rn, xor_rn_rn,
+ /* 12-15 */ not_rn, btst_n_rn, bset_n_rn, bclr_n_rn,
+ /* 16-19 */ mult_rn_rn, imult_rn_rn, imultn_rn_rn, resmac_rn,
+ /* 20-23 */ imacn_rn_rn, div_rn_rn, abs_rn, sh_rn_rn,
+ /* 24-27 */ shlq_n_rn, shrq_n_rn, sha_rn_rn, sharq_n_rn,
+ /* 28-31 */ ror_rn_rn, rorq_n_rn, cmp_rn_rn, cmpq_n_rn,
+ /* 32-35 */ subqmod_n_rn, sat16s_rn, move_rn_rn, moveq_n_rn,
+ /* 36-39 */ moveta_rn_rn, movefa_rn_rn, movei_n_rn, loadb_rn_rn,
+ /* 40-43 */ loadw_rn_rn, load_rn_rn, sat32s_rn, load_r14n_rn,
+ /* 44-47 */ load_r15n_rn, storeb_rn_rn, storew_rn_rn, store_rn_rn,
+ /* 48-51 */ mirror_rn, store_rn_r14n, store_rn_r15n, move_pc_rn,
+ /* 52-55 */ jump_cc_rn, jr_cc_n, mmult_rn_rn, mtoi_rn_rn,
+ /* 56-59 */ normi_rn_rn, nop, load_r14rn_rn, load_r15rn_rn,
+ /* 60-63 */ store_rn_r14rn, store_rn_r15rn, illegal, addqmod_n_rn
+};
+
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(pc) (cpu_readop16(WORD_XOR_BE((UINT32)(pc))))
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE void update_register_banks(void)
+{
+ UINT32 temp;
+ int i, bank;
+
+ /* pick the bank */
+ bank = jaguar.FLAGS & RPAGEFLAG;
+ if (jaguar.FLAGS & IFLAG) bank = 0;
+
+ /* do we need to swap? */
+ if ((!bank && jaguar.b0 != jaguar.r) || (bank && jaguar.b1 != jaguar.r))
+ {
+ /* remember the icount of the instruction after we swap */
+ bankswitch_icount = jaguar_icount - 1;
+
+ /* exchange the contents */
+ for (i = 0; i < 32; i++)
+ temp = jaguar.r[i], jaguar.r[i] = jaguar.a[i], jaguar.a[i] = temp;
+
+ /* swap the bank pointers */
+ if (!bank)
+ {
+ jaguar.b0 = jaguar.r;
+ jaguar.b1 = jaguar.a;
+ }
+ else
+ {
+ jaguar.b0 = jaguar.a;
+ jaguar.b1 = jaguar.r;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ IRQ HANDLING
+***************************************************************************/
+
+static void check_irqs(void)
+{
+ int bits, mask, which = 0;
+
+ /* if the IMASK is set, bail */
+ if (jaguar.FLAGS & IFLAG)
+ return;
+
+ /* get the active interrupt bits */
+ bits = (jaguar.ctrl[G_CTRL] >> 6) & 0x1f;
+ bits |= (jaguar.ctrl[G_CTRL] >> 10) & 0x20;
+
+ /* get the interrupt mask */
+ mask = (jaguar.FLAGS >> 4) & 0x1f;
+ mask |= (jaguar.FLAGS >> 11) & 0x20;
+
+ /* bail if nothing is available */
+ bits &= mask;
+ if (!bits)
+ return;
+
+ /* determine which interrupt */
+ if (bits & 0x01) which = 0;
+ if (bits & 0x02) which = 1;
+ if (bits & 0x04) which = 2;
+ if (bits & 0x08) which = 3;
+ if (bits & 0x10) which = 4;
+ if (bits & 0x20) which = 5;
+
+ /* set the interrupt flag */
+ jaguar.FLAGS |= IFLAG;
+ update_register_banks();
+
+ /* push the PC-2 on the stack */
+ jaguar.r[31] -= 4;
+ WRITELONG(jaguar.r[31], jaguar.PC - 2);
+
+ /* dispatch */
+ jaguar.PC = (jaguar.isdsp) ? 0xf1b000 : 0xf03000;
+ jaguar.PC += which * 0x10;
+ change_pc(jaguar.PC);
+}
+
+
+static void set_irq_line(int irqline, int state)
+{
+ int mask = (irqline < 5) ? (0x40 << irqline) : 0x10000;
+ jaguar.ctrl[G_CTRL] &= ~mask;
+ if (state != CLEAR_LINE)
+ {
+ jaguar.ctrl[G_CTRL] |= mask;
+ check_irqs();
+ }
+}
+
+
+
+/***************************************************************************
+ CONTEXT SWITCHING
+***************************************************************************/
+
+static void jaguar_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(jaguar_regs *)dst = jaguar;
+}
+
+
+static void jaguar_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ jaguar = *(jaguar_regs *)src;
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+static void init_tables(void)
+{
+ int i, j;
+
+ /* allocate the mirror table */
+ if (!mirror_table)
+ mirror_table = malloc_or_die(65536 * sizeof(mirror_table[0]));
+
+ /* fill in the mirror table */
+ for (i = 0; i < 65536; i++)
+ mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
+ ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
+ ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
+ ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
+ ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
+ ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
+ ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
+ ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
+
+ /* allocate the condition table */
+ if (!condition_table)
+ condition_table = malloc_or_die(32 * 8 * sizeof(condition_table[0]));
+
+ /* fill in the condition table */
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 32; j++)
+ {
+ int result = 1;
+ if (j & 1)
+ if (i & ZFLAG) result = 0;
+ if (j & 2)
+ if (!(i & ZFLAG)) result = 0;
+ if (j & 4)
+ if (i & (CFLAG << (j >> 4))) result = 0;
+ if (j & 8)
+ if (!(i & (CFLAG << (j >> 4)))) result = 0;
+ condition_table[i * 32 + j] = result;
+ }
+}
+
+static void jaguar_state_register(int index, const char *type)
+{
+ state_save_register_item_array(type, index, jaguar.r);
+ state_save_register_item_array(type, index, jaguar.a);
+ state_save_register_item_array(type, index, jaguar.ctrl);
+ state_save_register_item(type, index, jaguar.ppc);
+ state_save_register_func_postload(update_register_banks);
+ state_save_register_func_postload(check_irqs);
+}
+
+static void jaguargpu_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const struct jaguar_config *config = _config;
+
+ memset(&jaguar, 0, sizeof(jaguar));
+
+ jaguar_state_register(index, "jaguargpu");
+
+ jaguar.irq_callback = irqcallback;
+ if (config)
+ jaguar.cpu_interrupt = config->cpu_int_callback;
+}
+
+static void jaguardsp_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const struct jaguar_config *config = _config;
+
+ memset(&jaguar, 0, sizeof(jaguar));
+
+ jaguar_state_register(index, "jaguardsp");
+
+ jaguar.irq_callback = irqcallback;
+ if (config)
+ jaguar.cpu_interrupt = config->cpu_int_callback;
+}
+
+INLINE void common_reset(void)
+{
+ init_tables();
+
+ jaguar.b0 = jaguar.r;
+ jaguar.b1 = jaguar.a;
+
+ change_pc(jaguar.PC);
+}
+
+static void jaguargpu_reset(void)
+{
+ common_reset();
+ jaguar.table = gpu_op_table;
+ jaguar.isdsp = 0;
+}
+
+static void jaguardsp_reset(void)
+{
+ common_reset();
+ jaguar.table = dsp_op_table;
+ jaguar.isdsp = 1;
+}
+
+static void jaguar_exit(void)
+{
+ if (mirror_table)
+ free(mirror_table);
+ mirror_table = NULL;
+
+ if (condition_table)
+ free(condition_table);
+ condition_table = NULL;
+}
+
+
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+static int jaguargpu_execute(int cycles)
+{
+ /* if we're halted, we shouldn't be here */
+ if (!(jaguar.ctrl[G_CTRL] & 1))
+ {
+ cpunum_set_input_line(cpu_getactivecpu(), INPUT_LINE_HALT, ASSERT_LINE);
+ return cycles;
+ }
+
+ /* count cycles and interrupt cycles */
+ bankswitch_icount = -1000;
+ jaguar_icount = cycles;
+ jaguar_icount -= jaguar.interrupt_cycles;
+ jaguar.interrupt_cycles = 0;
+ change_pc(jaguar.PC);
+
+ /* remember that we're executing */
+ executing_cpu = cpu_getactivecpu();
+
+ /* core execution loop */
+ do
+ {
+ /* debugging */
+ //if (jaguar.PC < 0xf03000 || jaguar.PC > 0xf04000) { fatalerror("GPU: jaguar.PC = %06X (ppc = %06X)", jaguar.PC, jaguar.ppc); }
+ jaguar.ppc = jaguar.PC;
+ CALL_MAME_DEBUG;
+
+ /* instruction fetch */
+ jaguar.op = ROPCODE(jaguar.PC);
+ jaguar.PC += 2;
+
+ /* parse the instruction */
+ (*gpu_op_table[jaguar.op >> 10])();
+ jaguar_icount--;
+
+ } while (jaguar_icount > 0 || jaguar_icount == bankswitch_icount);
+
+ /* no longer executing */
+ executing_cpu = -1;
+
+ /* adjust cycles for interrupts */
+ jaguar_icount -= jaguar.interrupt_cycles;
+ jaguar.interrupt_cycles = 0;
+ return cycles - jaguar_icount;
+}
+
+static int jaguardsp_execute(int cycles)
+{
+ /* if we're halted, we shouldn't be here */
+ if (!(jaguar.ctrl[G_CTRL] & 1))
+ {
+ cpunum_set_input_line(cpu_getactivecpu(), INPUT_LINE_HALT, ASSERT_LINE);
+ return cycles;
+ }
+
+ /* count cycles and interrupt cycles */
+ bankswitch_icount = -1000;
+ jaguar_icount = cycles;
+ jaguar_icount -= jaguar.interrupt_cycles;
+ jaguar.interrupt_cycles = 0;
+ change_pc(jaguar.PC);
+
+ /* remember that we're executing */
+ executing_cpu = cpu_getactivecpu();
+
+ /* core execution loop */
+ do
+ {
+ /* debugging */
+ //if (jaguar.PC < 0xf1b000 || jaguar.PC > 0xf1d000) { fatalerror(stderr, "DSP: jaguar.PC = %06X", jaguar.PC); }
+ jaguar.ppc = jaguar.PC;
+ CALL_MAME_DEBUG;
+
+ /* instruction fetch */
+ jaguar.op = ROPCODE(jaguar.PC);
+ jaguar.PC += 2;
+
+ /* parse the instruction */
+ (*dsp_op_table[jaguar.op >> 10])();
+ jaguar_icount--;
+
+ } while (jaguar_icount > 0 || jaguar_icount == bankswitch_icount);
+
+ /* no longer executing */
+ executing_cpu = -1;
+
+ /* adjust cycles for interrupts */
+ jaguar_icount -= jaguar.interrupt_cycles;
+ jaguar.interrupt_cycles = 0;
+ return cycles - jaguar_icount;
+}
+
+
+
+/***************************************************************************
+ DISASSEMBLY HOOK
+***************************************************************************/
+
+#ifdef MAME_DEBUG
+static offs_t jaguargpu_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ extern unsigned dasmjag(int, char *, unsigned, const UINT8 *);
+ return dasmjag(JAGUAR_VARIANT_GPU, buffer, pc, oprom);
+}
+
+static offs_t jaguardsp_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ extern unsigned dasmjag(int, char *, unsigned, const UINT8 *);
+ return dasmjag(JAGUAR_VARIANT_DSP, buffer, pc, oprom);
+}
+#endif /* MAME_DEBUG */
+
+
+
+/***************************************************************************
+ OPCODES
+***************************************************************************/
+
+void abs_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 res = jaguar.r[dreg];
+ CLR_ZNC;
+ if (res & 0x80000000)
+ {
+ jaguar.r[dreg] = res = -res;
+ jaguar.FLAGS |= CFLAG;
+ }
+ SET_Z(res);
+}
+
+void add_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 + r1;
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZNC_ADD(r2,r1,res);
+}
+
+void addc_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 + r1 + ((jaguar.FLAGS >> 1) & 1);
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZNC_ADD(r2,r1,res);
+}
+
+void addq_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 + r1;
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZNC_ADD(r2,r1,res);
+}
+
+void addqmod_n_rn(void) /* DSP only */
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 + r1;
+ res = (res & ~jaguar.ctrl[D_MOD]) | (r2 & ~jaguar.ctrl[D_MOD]);
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZNC_ADD(r2,r1,res);
+}
+
+void addqt_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 + r1;
+ jaguar.r[dreg] = res;
+}
+
+void and_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 & r1;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void bclr_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = (jaguar.op >> 5) & 31;
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 & ~(1 << r1);
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void bset_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = (jaguar.op >> 5) & 31;
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 | (1 << r1);
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void btst_n_rn(void)
+{
+ UINT32 r1 = (jaguar.op >> 5) & 31;
+ UINT32 r2 = jaguar.r[jaguar.op & 31];
+ CLR_Z; jaguar.FLAGS |= (~r2 >> r1) & 1;
+}
+
+void cmp_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[jaguar.op & 31];
+ UINT32 res = r2 - r1;
+ CLR_ZNC; SET_ZNC_SUB(r2,r1,res);
+}
+
+void cmpq_n_rn(void)
+{
+ UINT32 r1 = (INT8)(jaguar.op >> 2) >> 3;
+ UINT32 r2 = jaguar.r[jaguar.op & 31];
+ UINT32 res = r2 - r1;
+ CLR_ZNC; SET_ZNC_SUB(r2,r1,res);
+}
+
+void div_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ if (r1)
+ {
+ if (jaguar.ctrl[D_DIVCTRL] & 1)
+ {
+ jaguar.r[dreg] = ((UINT64)r2 << 16) / r1;
+ jaguar.ctrl[D_REMAINDER] = ((UINT64)r2 << 16) % r1;
+ }
+ else
+ {
+ jaguar.r[dreg] = r2 / r1;
+ jaguar.ctrl[D_REMAINDER] = r2 % r1;
+ }
+ }
+ else
+ jaguar.r[dreg] = 0xffffffff;
+}
+
+void illegal(void)
+{
+}
+
+void imacn_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[jaguar.op & 31];
+ jaguar.accum += (INT64)((INT16)r1 * (INT16)r2);
+ logerror("Unexpected IMACN instruction!\n");
+}
+
+void imult_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = (INT16)r1 * (INT16)r2;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void imultn_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = (INT16)r1 * (INT16)r2;
+ jaguar.accum = (INT32)res;
+ CLR_ZN; SET_ZN(res);
+
+ jaguar.op = ROPCODE(jaguar.PC);
+ while ((jaguar.op >> 10) == 20)
+ {
+ r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ r2 = jaguar.r[jaguar.op & 31];
+ jaguar.accum += (INT64)((INT16)r1 * (INT16)r2);
+ jaguar.PC += 2;
+ jaguar.op = ROPCODE(jaguar.PC);
+ }
+ if ((jaguar.op >> 10) == 19)
+ {
+ jaguar.PC += 2;
+ jaguar.r[jaguar.op & 31] = (UINT32)jaguar.accum;
+ }
+}
+
+void jr_cc_n(void)
+{
+ if (CONDITION(jaguar.op & 31))
+ {
+ INT32 r1 = (INT8)((jaguar.op >> 2) & 0xf8) >> 2;
+ UINT32 newpc = jaguar.PC + r1;
+ CALL_MAME_DEBUG;
+ jaguar.op = ROPCODE(jaguar.PC);
+ jaguar.PC = newpc;
+ (*jaguar.table[jaguar.op >> 10])();
+
+ jaguar_icount -= 3; /* 3 wait states guaranteed */
+ }
+}
+
+void jump_cc_rn(void)
+{
+ if (CONDITION(jaguar.op & 31))
+ {
+ UINT8 reg = (jaguar.op >> 5) & 31;
+
+ /* special kludge for risky code in the cojag DSP interrupt handlers */
+ UINT32 newpc = (jaguar_icount == bankswitch_icount) ? jaguar.a[reg] : jaguar.r[reg];
+ CALL_MAME_DEBUG;
+ jaguar.op = ROPCODE(jaguar.PC);
+ jaguar.PC = newpc;
+ (*jaguar.table[jaguar.op >> 10])();
+
+ jaguar_icount -= 3; /* 3 wait states guaranteed */
+ }
+}
+
+void load_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ jaguar.r[jaguar.op & 31] = READLONG(r1);
+}
+
+void load_r14n_rn(void)
+{
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ jaguar.r[jaguar.op & 31] = READLONG(jaguar.r[14] + 4 * r1);
+}
+
+void load_r15n_rn(void)
+{
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ jaguar.r[jaguar.op & 31] = READLONG(jaguar.r[15] + 4 * r1);
+}
+
+void load_r14rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ jaguar.r[jaguar.op & 31] = READLONG(jaguar.r[14] + r1);
+}
+
+void load_r15rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ jaguar.r[jaguar.op & 31] = READLONG(jaguar.r[15] + r1);
+}
+
+void loadb_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ jaguar.r[jaguar.op & 31] = READBYTE(r1);
+}
+
+void loadw_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ jaguar.r[jaguar.op & 31] = READWORD(r1);
+}
+
+void loadp_rn_rn(void) /* GPU only */
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ jaguar.ctrl[G_HIDATA] = READWORD(r1);
+ jaguar.r[jaguar.op & 31] = READWORD(r1+4);
+}
+
+void mirror_rn(void) /* DSP only */
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[dreg];
+ UINT32 res = (mirror_table[r1 & 0xffff] << 16) | mirror_table[r1 >> 16];
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void mmult_rn_rn(void)
+{
+ int count = jaguar.ctrl[G_MTXC] & 15, i;
+ int sreg = (jaguar.op >> 5) & 31;
+ int dreg = jaguar.op & 31;
+ UINT32 addr = jaguar.ctrl[G_MTXA];
+ INT64 accum = 0;
+ UINT32 res;
+
+ if (!(jaguar.ctrl[G_MTXC] & 0x10))
+ {
+ for (i = 0; i < count; i++)
+ {
+ accum += (INT16)(jaguar.b1[sreg + i/2] >> (16 * ((i & 1) ^ 1))) * (INT16)READWORD(addr);
+ addr += 2;
+ }
+ }
+ else
+ {
+ for (i = 0; i < count; i++)
+ {
+ accum += (INT16)(jaguar.b1[sreg + i/2] >> (16 * ((i & 1) ^ 1))) * (INT16)READWORD(addr);
+ addr += 2 * count;
+ }
+ }
+ jaguar.r[dreg] = res = (UINT32)accum;
+ CLR_ZN; SET_ZN(res);
+}
+
+void move_rn_rn(void)
+{
+ jaguar.r[jaguar.op & 31] = jaguar.r[(jaguar.op >> 5) & 31];
+}
+
+void move_pc_rn(void)
+{
+ jaguar.r[jaguar.op & 31] = jaguar.ppc;
+}
+
+void movefa_rn_rn(void)
+{
+ jaguar.r[jaguar.op & 31] = jaguar.a[(jaguar.op >> 5) & 31];
+}
+
+void movei_n_rn(void)
+{
+ UINT32 res = ROPCODE(jaguar.PC) | (ROPCODE(jaguar.PC + 2) << 16);
+ jaguar.PC += 4;
+ jaguar.r[jaguar.op & 31] = res;
+}
+
+void moveq_n_rn(void)
+{
+ jaguar.r[jaguar.op & 31] = (jaguar.op >> 5) & 31;
+}
+
+void moveta_rn_rn(void)
+{
+ jaguar.a[jaguar.op & 31] = jaguar.r[(jaguar.op >> 5) & 31];
+}
+
+void mtoi_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ jaguar.r[jaguar.op & 31] = (((INT32)r1 >> 8) & 0xff800000) | (r1 & 0x007fffff);
+}
+
+void mult_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = (UINT16)r1 * (UINT16)r2;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void neg_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = -r2;
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZNC_SUB(0,r2,res);
+}
+
+void nop(void)
+{
+}
+
+void normi_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 res = 0;
+ if (r1 != 0)
+ {
+ while ((r1 & 0xffc00000) == 0)
+ {
+ r1 <<= 1;
+ res--;
+ }
+ while ((r1 & 0xff800000) != 0)
+ {
+ r1 >>= 1;
+ res++;
+ }
+ }
+ jaguar.r[jaguar.op & 31] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void not_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 res = ~jaguar.r[dreg];
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void or_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r1 | r2;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void pack_rn(void) /* GPU only */
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res;
+ if (r1 == 0) /* PACK */
+ res = ((r2 >> 10) & 0xf000) | ((r2 >> 5) & 0x0f00) | (r2 & 0xff);
+ else /* UNPACK */
+ res = ((r2 & 0xf000) << 10) | ((r2 & 0x0f00) << 5) | (r2 & 0xff);
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void resmac_rn(void)
+{
+ jaguar.r[jaguar.op & 31] = (UINT32)jaguar.accum;
+}
+
+void ror_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31] & 31;
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZN(res); jaguar.FLAGS |= (r2 >> 30) & 2;
+}
+
+void rorq_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZN(res); jaguar.FLAGS |= (r2 >> 30) & 2;
+}
+
+void sat8_rn(void) /* GPU only */
+{
+ int dreg = jaguar.op & 31;
+ INT32 r2 = jaguar.r[dreg];
+ UINT32 res = (r2 < 0) ? 0 : (r2 > 255) ? 255 : r2;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void sat16_rn(void) /* GPU only */
+{
+ int dreg = jaguar.op & 31;
+ INT32 r2 = jaguar.r[dreg];
+ UINT32 res = (r2 < 0) ? 0 : (r2 > 65535) ? 65535 : r2;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void sat16s_rn(void) /* DSP only */
+{
+ int dreg = jaguar.op & 31;
+ INT32 r2 = jaguar.r[dreg];
+ UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void sat24_rn(void) /* GPU only */
+{
+ int dreg = jaguar.op & 31;
+ INT32 r2 = jaguar.r[dreg];
+ UINT32 res = (r2 < 0) ? 0 : (r2 > 16777215) ? 16777215 : r2;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void sat32s_rn(void) /* DSP only */
+{
+ int dreg = jaguar.op & 31;
+ INT32 r2 = (UINT32)jaguar.r[dreg];
+ INT32 temp = jaguar.accum >> 32;
+ UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7fffffff : r2;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+void sh_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ INT32 r1 = (INT32)jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res;
+
+ CLR_ZNC;
+ if (r1 < 0)
+ {
+ res = (r1 <= -32) ? 0 : (r2 << -r1);
+ jaguar.FLAGS |= (r2 >> 30) & 2;
+ }
+ else
+ {
+ res = (r1 >= 32) ? 0 : (r2 >> r1);
+ jaguar.FLAGS |= (r2 << 1) & 2;
+ }
+ jaguar.r[dreg] = res;
+ SET_ZN(res);
+}
+
+void sha_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ INT32 r1 = (INT32)jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res;
+
+ CLR_ZNC;
+ if (r1 < 0)
+ {
+ res = (r1 <= -32) ? 0 : (r2 << -r1);
+ jaguar.FLAGS |= (r2 >> 30) & 2;
+ }
+ else
+ {
+ res = (r1 >= 32) ? ((INT32)r2 >> 31) : ((INT32)r2 >> r1);
+ jaguar.FLAGS |= (r2 << 1) & 2;
+ }
+ jaguar.r[dreg] = res;
+ SET_ZN(res);
+}
+
+void sharq_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ INT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = (INT32)r2 >> r1;
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZN(res); jaguar.FLAGS |= (r2 << 1) & 2;
+}
+
+void shlq_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ INT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 << (32 - r1);
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZN(res); jaguar.FLAGS |= (r2 >> 30) & 2;
+}
+
+void shrq_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ INT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 >> r1;
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZN(res); jaguar.FLAGS |= (r2 << 1) & 2;
+}
+
+void store_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ WRITELONG(r1, jaguar.r[jaguar.op & 31]);
+}
+
+void store_rn_r14n(void)
+{
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ WRITELONG(jaguar.r[14] + r1 * 4, jaguar.r[jaguar.op & 31]);
+}
+
+void store_rn_r15n(void)
+{
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ WRITELONG(jaguar.r[15] + r1 * 4, jaguar.r[jaguar.op & 31]);
+}
+
+void store_rn_r14rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ WRITELONG(jaguar.r[14] + r1, jaguar.r[jaguar.op & 31]);
+}
+
+void store_rn_r15rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ WRITELONG(jaguar.r[15] + r1, jaguar.r[jaguar.op & 31]);
+}
+
+void storeb_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ WRITEBYTE(r1, jaguar.r[jaguar.op & 31]);
+}
+
+void storew_rn_rn(void)
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ WRITEWORD(r1, jaguar.r[jaguar.op & 31]);
+}
+
+void storep_rn_rn(void) /* GPU only */
+{
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ WRITELONG(r1, jaguar.ctrl[G_HIDATA]);
+ WRITELONG(r1+4, jaguar.r[jaguar.op & 31]);
+}
+
+void sub_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 - r1;
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZNC_SUB(r2,r1,res);
+}
+
+void subc_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 - r1 - ((jaguar.FLAGS >> 1) & 1);
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZNC_SUB(r2,r1,res);
+}
+
+void subq_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 - r1;
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZNC_SUB(r2,r1,res);
+}
+
+void subqmod_n_rn(void) /* DSP only */
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 - r1;
+ res = (res & ~jaguar.ctrl[D_MOD]) | (r2 & ~jaguar.ctrl[D_MOD]);
+ jaguar.r[dreg] = res;
+ CLR_ZNC; SET_ZNC_SUB(r2,r1,res);
+}
+
+void subqt_n_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = convert_zero[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r2 - r1;
+ jaguar.r[dreg] = res;
+}
+
+void xor_rn_rn(void)
+{
+ int dreg = jaguar.op & 31;
+ UINT32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
+ UINT32 r2 = jaguar.r[dreg];
+ UINT32 res = r1 ^ r2;
+ jaguar.r[dreg] = res;
+ CLR_ZN; SET_ZN(res);
+}
+
+
+
+/***************************************************************************
+ I/O HANDLING
+***************************************************************************/
+
+UINT32 jaguargpu_ctrl_r(int cpunum, offs_t offset)
+{
+ UINT32 result;
+
+#if LOG_GPU_IO
+ logerror("%08X/%d:GPU read register @ F021%02X\n", activecpu_get_previouspc(), cpu_getactivecpu(), offset * 4);
+#endif
+
+ /* switch to the target context */
+ cpuintrf_push_context(cpunum);
+ result = jaguar.ctrl[offset];
+ cpuintrf_pop_context();
+
+ return result;
+}
+
+
+void jaguargpu_ctrl_w(int cpunum, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ UINT32 oldval, newval;
+
+#if LOG_GPU_IO
+ if (offset != G_HIDATA)
+ logerror("%08X/%d:GPU write register @ F021%02X = %08X\n", activecpu_get_previouspc(), cpu_getactivecpu(), offset * 4, data);
+#endif
+
+ /* switch to the target context */
+ cpuintrf_push_context(cpunum);
+
+ /* remember the old and set the new */
+ oldval = jaguar.ctrl[offset];
+ newval = oldval;
+ COMBINE_DATA(&newval);
+
+ /* handle the various registers */
+ switch (offset)
+ {
+ case G_FLAGS:
+
+ /* combine the data properly */
+ jaguar.ctrl[offset] = newval & (ZFLAG | CFLAG | NFLAG | EINT04FLAGS | RPAGEFLAG);
+ if (newval & IFLAG)
+ jaguar.ctrl[offset] |= oldval & IFLAG;
+
+ /* clear interrupts */
+ jaguar.ctrl[G_CTRL] &= ~((newval & CINT04FLAGS) >> 3);
+
+ /* determine which register bank should be active */
+ update_register_banks();
+
+ /* update IRQs */
+ check_irqs();
+ break;
+
+ case G_MTXC:
+ case G_MTXA:
+ jaguar.ctrl[offset] = newval;
+ break;
+
+ case G_END:
+ jaguar.ctrl[offset] = newval;
+ if ((newval & 7) != 7)
+ logerror("GPU to set to little-endian!\n");
+ break;
+
+ case G_PC:
+ jaguar.PC = newval & 0xffffff;
+ if (executing_cpu == cpunum)
+ change_pc(jaguar.PC);
+ break;
+
+ case G_CTRL:
+ jaguar.ctrl[offset] = newval;
+ if ((oldval ^ newval) & 0x01)
+ {
+ cpunum_set_input_line(cpunum, INPUT_LINE_HALT, (newval & 1) ? CLEAR_LINE : ASSERT_LINE);
+ if (cpu_getexecutingcpu() >= 0)
+ cpu_yield();
+ }
+ if (newval & 0x02)
+ {
+ if (jaguar.cpu_interrupt)
+ (*jaguar.cpu_interrupt)();
+ jaguar.ctrl[offset] &= ~0x02;
+ }
+ if (newval & 0x04)
+ {
+ jaguar.ctrl[G_CTRL] |= 1 << 6;
+ jaguar.ctrl[offset] &= ~0x04;
+ check_irqs();
+ }
+ if (newval & 0x18)
+ {
+ logerror("GPU single stepping was enabled!\n");
+ }
+ break;
+
+ case G_HIDATA:
+ case G_DIVCTRL:
+ jaguar.ctrl[offset] = newval;
+ break;
+ }
+
+ /* restore old context */
+ cpuintrf_pop_context();
+}
+
+
+
+/***************************************************************************
+ I/O HANDLING
+***************************************************************************/
+
+UINT32 jaguardsp_ctrl_r(int cpunum, offs_t offset)
+{
+ UINT32 result;
+
+#if LOG_DSP_IO
+ if (offset != D_FLAGS)
+ logerror("%08X/%d:DSP read register @ F1A1%02X\n", activecpu_get_previouspc(), cpu_getactivecpu(), offset * 4);
+#endif
+
+ /* switch to the target context */
+ cpuintrf_push_context(cpunum);
+ result = jaguar.ctrl[offset];
+ cpuintrf_pop_context();
+
+ return result;
+}
+
+
+void jaguardsp_ctrl_w(int cpunum, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ UINT32 oldval, newval;
+
+#if LOG_DSP_IO
+ if (offset != D_FLAGS)
+ logerror("%08X/%d:DSP write register @ F1A1%02X = %08X\n", activecpu_get_previouspc(), cpu_getactivecpu(), offset * 4, data);
+#endif
+
+ /* switch to the target context */
+ cpuintrf_push_context(cpunum);
+
+ /* remember the old and set the new */
+ oldval = jaguar.ctrl[offset];
+ newval = oldval;
+ COMBINE_DATA(&newval);
+
+ /* handle the various registers */
+ switch (offset)
+ {
+ case D_FLAGS:
+
+ /* combine the data properly */
+ jaguar.ctrl[offset] = newval & (ZFLAG | CFLAG | NFLAG | EINT04FLAGS | EINT5FLAG | RPAGEFLAG);
+ if (newval & IFLAG)
+ jaguar.ctrl[offset] |= oldval & IFLAG;
+
+ /* clear interrupts */
+ jaguar.ctrl[D_CTRL] &= ~((newval & CINT04FLAGS) >> 3);
+ jaguar.ctrl[D_CTRL] &= ~((newval & CINT5FLAG) >> 1);
+
+ /* determine which register bank should be active */
+ update_register_banks();
+
+ /* update IRQs */
+ check_irqs();
+ break;
+
+ case D_MTXC:
+ case D_MTXA:
+ jaguar.ctrl[offset] = newval;
+ break;
+
+ case D_END:
+ jaguar.ctrl[offset] = newval;
+ if ((newval & 7) != 7)
+ logerror("DSP to set to little-endian!\n");
+ break;
+
+ case D_PC:
+ jaguar.PC = newval & 0xffffff;
+ if (executing_cpu == cpunum)
+ change_pc(jaguar.PC);
+ break;
+
+ case D_CTRL:
+ jaguar.ctrl[offset] = newval;
+ if ((oldval ^ newval) & 0x01)
+ {
+ cpunum_set_input_line(cpunum, INPUT_LINE_HALT, (newval & 1) ? CLEAR_LINE : ASSERT_LINE);
+ if (cpu_getexecutingcpu() >= 0)
+ cpu_yield();
+ }
+ if (newval & 0x02)
+ {
+ if (jaguar.cpu_interrupt)
+ (*jaguar.cpu_interrupt)();
+ jaguar.ctrl[offset] &= ~0x02;
+ }
+ if (newval & 0x04)
+ {
+ jaguar.ctrl[D_CTRL] |= 1 << 6;
+ jaguar.ctrl[offset] &= ~0x04;
+ check_irqs();
+ }
+ if (newval & 0x18)
+ {
+ logerror("DSP single stepping was enabled!\n");
+ }
+ break;
+
+ case D_MOD:
+ case D_DIVCTRL:
+ jaguar.ctrl[offset] = newval;
+ break;
+ }
+
+ /* restore old context */
+ cpuintrf_pop_context();
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void jaguargpu_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ0: set_irq_line(JAGUAR_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ1: set_irq_line(JAGUAR_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ2: set_irq_line(JAGUAR_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ3: set_irq_line(JAGUAR_IRQ3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ4: set_irq_line(JAGUAR_IRQ4, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + JAGUAR_PC: jaguar.PC = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_FLAGS: jaguar.FLAGS = info->i; break;
+
+ case CPUINFO_INT_REGISTER + JAGUAR_R0: jaguar.r[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R1: jaguar.r[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R2: jaguar.r[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R3: jaguar.r[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R4: jaguar.r[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R5: jaguar.r[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R6: jaguar.r[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R7: jaguar.r[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R8: jaguar.r[8] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R9: jaguar.r[9] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R10: jaguar.r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R11: jaguar.r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R12: jaguar.r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R13: jaguar.r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R14: jaguar.r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R15: jaguar.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R16: jaguar.r[16] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R17: jaguar.r[17] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R18: jaguar.r[18] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R19: jaguar.r[19] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R20: jaguar.r[20] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R21: jaguar.r[21] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R22: jaguar.r[22] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R23: jaguar.r[23] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R24: jaguar.r[24] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R25: jaguar.r[25] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R26: jaguar.r[26] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R27: jaguar.r[27] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R28: jaguar.r[28] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R29: jaguar.r[29] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R30: jaguar.r[30] = info->i; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R31: jaguar.r[31] = info->i; break;
+ case CPUINFO_INT_SP: jaguar.b0[31] = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void jaguargpu_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(jaguar); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ0: info->i = (jaguar.ctrl[G_CTRL] & 0x40) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ1: info->i = (jaguar.ctrl[G_CTRL] & 0x80) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ2: info->i = (jaguar.ctrl[G_CTRL] & 0x100) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ3: info->i = (jaguar.ctrl[G_CTRL] & 0x200) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ4: info->i = (jaguar.ctrl[G_CTRL] & 0x400) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = jaguar.ppc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + JAGUAR_PC: info->i = jaguar.PC; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_FLAGS: info->i = jaguar.FLAGS; break;
+
+ case CPUINFO_INT_REGISTER + JAGUAR_R0: info->i = jaguar.r[0]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R1: info->i = jaguar.r[1]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R2: info->i = jaguar.r[2]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R3: info->i = jaguar.r[3]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R4: info->i = jaguar.r[4]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R5: info->i = jaguar.r[5]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R6: info->i = jaguar.r[6]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R7: info->i = jaguar.r[7]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R8: info->i = jaguar.r[8]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R9: info->i = jaguar.r[9]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R10: info->i = jaguar.r[10]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R11: info->i = jaguar.r[11]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R12: info->i = jaguar.r[12]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R13: info->i = jaguar.r[13]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R14: info->i = jaguar.r[14]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R15: info->i = jaguar.r[15]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R16: info->i = jaguar.r[16]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R17: info->i = jaguar.r[17]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R18: info->i = jaguar.r[18]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R19: info->i = jaguar.r[19]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R20: info->i = jaguar.r[20]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R21: info->i = jaguar.r[21]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R22: info->i = jaguar.r[22]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R23: info->i = jaguar.r[23]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R24: info->i = jaguar.r[24]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R25: info->i = jaguar.r[25]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R26: info->i = jaguar.r[26]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R27: info->i = jaguar.r[27]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R28: info->i = jaguar.r[28]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R29: info->i = jaguar.r[29]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R30: info->i = jaguar.r[30]; break;
+ case CPUINFO_INT_REGISTER + JAGUAR_R31: info->i = jaguar.r[31]; break;
+ case CPUINFO_INT_SP: info->i = jaguar.b0[31]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = jaguargpu_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = jaguar_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = jaguar_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = jaguargpu_init; break;
+ case CPUINFO_PTR_RESET: info->reset = jaguargpu_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = jaguar_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = jaguargpu_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = jaguargpu_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &jaguar_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "Jaguar GPU"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Atari Jaguar"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) Aaron Giles 2000-2004"); break;
+
+ case CPUINFO_STR_FLAGS: sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c",
+ jaguar.FLAGS & 0x8000 ? 'D':'.',
+ jaguar.FLAGS & 0x4000 ? 'A':'.',
+ jaguar.FLAGS & 0x0100 ? '4':'.',
+ jaguar.FLAGS & 0x0080 ? '3':'.',
+ jaguar.FLAGS & 0x0040 ? '2':'.',
+ jaguar.FLAGS & 0x0020 ? '1':'.',
+ jaguar.FLAGS & 0x0010 ? '0':'.',
+ jaguar.FLAGS & 0x0008 ? 'I':'.',
+ jaguar.FLAGS & 0x0004 ? 'N':'.',
+ jaguar.FLAGS & 0x0002 ? 'C':'.',
+ jaguar.FLAGS & 0x0001 ? 'Z':'.'); break;
+
+ case CPUINFO_STR_REGISTER + JAGUAR_PC: sprintf(info->s, "PC: %08X", jaguar.PC); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_FLAGS: sprintf(info->s, "FLAGS: %08X", jaguar.FLAGS); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R0: sprintf(info->s, "R0: %08X", jaguar.r[0]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R1: sprintf(info->s, "R1: %08X", jaguar.r[1]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R2: sprintf(info->s, "R2: %08X", jaguar.r[2]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R3: sprintf(info->s, "R3: %08X", jaguar.r[3]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R4: sprintf(info->s, "R4: %08X", jaguar.r[4]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R5: sprintf(info->s, "R5: %08X", jaguar.r[5]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R6: sprintf(info->s, "R6: %08X", jaguar.r[6]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R7: sprintf(info->s, "R7: %08X", jaguar.r[7]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R8: sprintf(info->s, "R8: %08X", jaguar.r[8]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R9: sprintf(info->s, "R9: %08X", jaguar.r[9]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R10: sprintf(info->s, "R10:%08X", jaguar.r[10]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R11: sprintf(info->s, "R11:%08X", jaguar.r[11]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R12: sprintf(info->s, "R12:%08X", jaguar.r[12]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R13: sprintf(info->s, "R13:%08X", jaguar.r[13]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R14: sprintf(info->s, "R14:%08X", jaguar.r[14]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R15: sprintf(info->s, "R15:%08X", jaguar.r[15]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R16: sprintf(info->s, "R16:%08X", jaguar.r[16]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R17: sprintf(info->s, "R17:%08X", jaguar.r[17]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R18: sprintf(info->s, "R18:%08X", jaguar.r[18]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R19: sprintf(info->s, "R19:%08X", jaguar.r[19]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R20: sprintf(info->s, "R20:%08X", jaguar.r[20]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R21: sprintf(info->s, "R21:%08X", jaguar.r[21]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R22: sprintf(info->s, "R22:%08X", jaguar.r[22]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R23: sprintf(info->s, "R23:%08X", jaguar.r[23]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R24: sprintf(info->s, "R24:%08X", jaguar.r[24]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R25: sprintf(info->s, "R25:%08X", jaguar.r[25]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R26: sprintf(info->s, "R26:%08X", jaguar.r[26]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R27: sprintf(info->s, "R27:%08X", jaguar.r[27]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R28: sprintf(info->s, "R28:%08X", jaguar.r[28]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R29: sprintf(info->s, "R29:%08X", jaguar.r[29]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R30: sprintf(info->s, "R30:%08X", jaguar.r[30]); break;
+ case CPUINFO_STR_REGISTER + JAGUAR_R31: sprintf(info->s, "R31:%08X", jaguar.r[31]); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+static void jaguardsp_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ5: set_irq_line(JAGUAR_IRQ5, info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+
+ default:
+ jaguargpu_set_info(state, info);
+ break;
+ }
+}
+
+void jaguardsp_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 6; break;
+ case CPUINFO_INT_INPUT_STATE + JAGUAR_IRQ5: info->i = (jaguar.ctrl[G_CTRL] & 0x10000) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = jaguardsp_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = jaguardsp_init; break;
+ case CPUINFO_PTR_RESET: info->reset = jaguardsp_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = jaguardsp_execute; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = jaguardsp_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "Jaguar DSP"); break;
+
+ default:
+ jaguargpu_get_info(state, info);
+ break;
+ }
+}
diff --git a/src/emu/cpu/jaguar/jaguar.h b/src/emu/cpu/jaguar/jaguar.h
new file mode 100644
index 00000000000..ba075a588fc
--- /dev/null
+++ b/src/emu/cpu/jaguar/jaguar.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+
+ jaguar.h
+ Interface file for the portable Jaguar DSP emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#ifndef _JAGUAR_H
+#define _JAGUAR_H
+
+#include "cpuintrf.h"
+
+
+/***************************************************************************
+ COMPILE-TIME DEFINITIONS
+***************************************************************************/
+
+
+/***************************************************************************
+ GLOBAL CONSTANTS
+***************************************************************************/
+
+#define JAGUAR_VARIANT_GPU 0
+#define JAGUAR_VARIANT_DSP 1
+
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ JAGUAR_PC=1,JAGUAR_FLAGS,
+ JAGUAR_R0,JAGUAR_R1,JAGUAR_R2,JAGUAR_R3,JAGUAR_R4,JAGUAR_R5,JAGUAR_R6,JAGUAR_R7,
+ JAGUAR_R8,JAGUAR_R9,JAGUAR_R10,JAGUAR_R11,JAGUAR_R12,JAGUAR_R13,JAGUAR_R14,JAGUAR_R15,
+ JAGUAR_R16,JAGUAR_R17,JAGUAR_R18,JAGUAR_R19,JAGUAR_R20,JAGUAR_R21,JAGUAR_R22,JAGUAR_R23,
+ JAGUAR_R24,JAGUAR_R25,JAGUAR_R26,JAGUAR_R27,JAGUAR_R28,JAGUAR_R29,JAGUAR_R30,JAGUAR_R31
+};
+
+enum
+{
+ G_FLAGS = 0,
+ G_MTXC,
+ G_MTXA,
+ G_END,
+ G_PC,
+ G_CTRL,
+ G_HIDATA,
+ G_DIVCTRL,
+ G_DUMMY,
+ G_REMAINDER,
+ G_CTRLMAX
+};
+
+enum
+{
+ D_FLAGS = 0,
+ D_MTXC,
+ D_MTXA,
+ D_END,
+ D_PC,
+ D_CTRL,
+ D_MOD,
+ D_DIVCTRL,
+ D_MACHI,
+ D_REMAINDER,
+ D_CTRLMAX
+};
+
+
+/***************************************************************************
+ CONFIGURATION STRUCTURE
+***************************************************************************/
+
+struct jaguar_config
+{
+ void (*cpu_int_callback)(void);
+};
+
+
+/***************************************************************************
+ INTERRUPT CONSTANTS
+***************************************************************************/
+
+#define JAGUAR_IRQ0 0 /* IRQ0 */
+#define JAGUAR_IRQ1 1 /* IRQ1 */
+#define JAGUAR_IRQ2 2 /* IRQ2 */
+#define JAGUAR_IRQ3 3 /* IRQ3 */
+#define JAGUAR_IRQ4 4 /* IRQ4 */
+#define JAGUAR_IRQ5 5 /* IRQ5 */
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+extern void jaguargpu_get_info(UINT32 state, cpuinfo *info);
+extern void jaguargpu_ctrl_w(int cpunum, offs_t offset, UINT32 data, UINT32 mem_mask);
+extern UINT32 jaguargpu_ctrl_r(int cpunum, offs_t offset);
+
+extern void jaguardsp_get_info(UINT32 state, cpuinfo *info);
+extern void jaguardsp_ctrl_w(int cpunum, offs_t offset, UINT32 data, UINT32 mem_mask);
+extern UINT32 jaguardsp_ctrl_r(int cpunum, offs_t offset);
+
+
+#endif /* _JAGUAR_H */
diff --git a/src/emu/cpu/konami/knmidasm.c b/src/emu/cpu/konami/knmidasm.c
new file mode 100644
index 00000000000..6fcffd0843a
--- /dev/null
+++ b/src/emu/cpu/konami/knmidasm.c
@@ -0,0 +1,1874 @@
+#include "debugger.h"
+#include "konami.h"
+
+#ifndef TRUE
+#define TRUE -1
+#define FALSE 0
+#endif
+
+/*
+
+0x08 leax indexed
+0x09 leay indexed (not confirmed)
+0x0a leau indexed
+0x0b leas indexed (not confirmed)
+
+0x0c pushs xx
+0x0d pushu xx (not confirmed)
+0x0e pulls xx
+0x0f pulls xx (not confirmed)
+
+0x10 lda xx
+0x11 ldb xx
+0x12 lda indexed
+0x13 ldb indexed
+
+0x14 adda xx
+0x15 addb xx (not confirmed)
+0x16 adda indexed (not confirmed)
+0x17 addb indexed
+
+0x18 adca xx
+0x19 adcb xx (not confirmed)
+0x1a adca indexed (not confirmed)
+0x1b adcb indexed (not confirmed)
+
+0x1c suba xx
+0x1d subb xx
+0x1e suba indexed
+0x1f subb indexed
+
+0x20 sbca xx
+0x21 sbcb xx
+0x22 sbca indexed
+0x23 sbcb indexed
+
+0x24 anda xx
+0x25 andb xx
+0x26 anda indexed
+0x27 andb indexed
+
+0x28 bita xx
+0x29 bitb xx
+0x2a bita indexed
+0x2b bitb indexed
+
+0x2c eora xx
+0x2d eorb xx
+0x2e eora indexed
+0x2f eorb indexed
+
+0x30 ora xx
+0x31 orb xx
+0x32 ora indexed
+0x33 orb indexed
+
+0x34 cmpa xx
+0x35 cmpb xx
+0x36 cmpa indexed
+0x37 cmpb indexed
+
+CUSTOM OPCODE: Set Address lines 16-23
+--------------------------------------
+0x38 setlines xx
+0x39 setlines indexed
+
+The eight bits taken as parameter set address lines 16 to 23.
+
+
+0x3a sta indexed
+0x3b stb indexed
+0x3c andcc
+0x3d orcc
+
+0x3e exg xx
+0x3f tfr xx
+
+0x40 ldd xx xx
+0x41 ldd indexed
+0x42 ldx xx xx
+0x43 ldx indexed
+0x44 ldy xx xx
+0x45 ldy indexed (not confirmed)
+0x46 ldu xx xx
+0x47 ldu indexed
+0x48 lds xx xx
+0x49 lds indexed (not confirmed)
+
+0x4a cmpd xx xx
+0x4b cmpd indexed
+0x4c cmpx xx xx
+0x4d cmpx indexed
+0x4e cmpy xx xx (not confirmed)
+0x4f cmpy indexed (not confirmed)
+0x50 cmpu xx xx (not confirmed)
+0x51 cmpu indexed (not confirmed)
+0x52 cmps xx xx (not confirmed)
+0x53 cmps indexed (not confirmed)
+
+0x54 addd xx xx
+0x55 addd indexed (not confirmed)
+0x56 subd xx xx
+0x57 subd indexed (not confirmed)
+
+0x58 std indexed
+0x59 stx indexed
+0x5a sty indexed
+0x5b stu indexed
+0x5c sts indexed (not confirmed)
+
+
+BRANCH OPCODE TABLE :
+---------------------
+
+Opcode M6809 Konami
+BRA 20 60
+BRN 21 70
+BHI 22 61
+BLS 23 71
+BCC 24 62
+BCS 25 72
+BNE 26 63
+BEQ 27 73
+BVC 28 64
+BVS 29 74
+BPL 2a 65
+BMI 2b 75
+BGE 2c 66
+BLT 2d 76
+BGT 2e 67
+BLE 2f 77
+
+Long versions of the branchs are the number + 8.
+
+0x80 clra
+0x81 clrb
+0x82 clr indexed
+
+0x83 coma
+0x84 comb
+0x85 com indexed
+
+0x86 nega (not confirmed)
+0x87 negb (not confirmed)
+0x88 neg indexed (not confirmed)
+
+0x89 inca
+0x8a incb (not confirmed)
+0x8b inc indexed
+
+0x8c deca
+0x8d decb
+0x8e dec indexed
+
+0x8f rts
+
+0x90 tsta (not confirmed)
+0x91 tstb (not confirmed)
+0x92 tst indexed (not confirmed)
+
+0x93 lsra
+0x94 lsrb
+0x95 lsr indexed
+
+0x96 rora
+0x97 rorb
+0x98 ror indexed
+
+0x99 asra
+0x9a asrb
+0x9b asr indexed
+
+0x9c asla
+0x9d aslb
+0x9e asl indexed
+
+0x9f rti
+
+0xa0 rola
+0xa1 rolb
+0xa2 rol indexed
+
+0xa3 lsrw indexed ( not confirmed )
+0xa4 rorw indexed ( not confirmed )
+0xa5 asrw indexed ( not confirmed )
+0xa6 aslw indexed ( not confirmed )
+0xa7 rolw indexed ( not confirmed )
+
+0xa8 jmp indexed
+0xa9 jsr indexed
+0xaa bsr xx
+0xab lbsr xx xx
+0xac decb,jnz xx
+0xad decx,jnz xx
+0xae nop
+
+0xb0 abx
+0xb1 daa
+0xb2 sex
+
+0xb3 mul
+
+0xb4 lmul x:y = x * y
+
+0xb5 divx x = ( x / b ), b = ( x % b )
+
+CUSTOM OPCODE: BlockMove (y,x,u):
+---------------------------------
+0xb6 bmove y,x,u
+
+y = pointer to source address
+x = pointer to destination address
+u = bytes to move
+
+One byte is copied at a time and x and y get incremented for each access.
+
+CUSTOM OPCODE: Move (y,x,u):
+---------------------------------
+0xb7 move y,x,u
+
+y = pointer to source address
+x = pointer to destination address
+u = counter
+
+Copy ONE byte, increment x and y, decrement u.
+
+0xb8 lsrd xx
+0xb9 lsrd indexed
+0xba rord xx ( not confirmed )
+0xbb rord indexed ( not confirmed )
+0xbc asrd xx ( not confirmed )
+0xbd asrd indexed ( not confirmed )
+0xbe asld xx
+0xbf asld indexed ( not confirmed )
+0xc0 rold xx ( not confirmed )
+0xc1 rold indexed ( not confirmed )
+
+0xc2 clrd
+0xc3 clrw indexed ( clears an entire word ) ( not confirmed )
+
+0xc4 negd (not confirmed )
+0xc5 negw indexed
+
+0xc6 incd (not confirmed )
+0xc7 incw indexed
+
+0xc8 decd (not confirmed )
+0xc9 decw indexed
+
+0xca tstd
+0xcb tstw indexed
+
+0xcc absa
+0xcd absb
+0xce absd
+
+CUSTOM OPCODE: BlockSet (a,x,u):
+---------------------------------
+0xcf bset a,x,u
+
+a = source data
+x = pointer to destination address
+u = bytes to move
+
+One byte is copied at a time and x get incremented for each access.
+
+CUSTOM OPCODE: BlockSet (d,x,u): (not confirmed)
+--------------------------------
+0xd0 bset d,x,u
+
+d = source data
+x = pointer to destination address
+u = bytes to move/2
+
+Two bytes are copied at a time and x get incremented twice for each access.
+
+*/
+
+static unsigned byte_count;
+static unsigned local_pc;
+static unsigned flags;
+
+static const unsigned char *opram_ptr;
+
+static unsigned char get_next_byte( void ) {
+ return opram_ptr[byte_count++];
+}
+
+/* Table for indexed operations */
+static char index_reg[8][3] = {
+ "?", /* 0 - extended mode */
+ "?", /* 1 */
+ "x", /* 2 */
+ "y", /* 3 */
+ "?", /* 4 - direct page */
+ "u", /* 5 */
+ "s", /* 6 */
+ "pc" /* 7 - pc */
+};
+
+/* Table for tfr/exg operations */
+static char tfrexg_reg[8][3] = {
+ "a", /* 0 */
+ "b", /* 1 */
+ "x", /* 2 */
+ "y", /* 3 */
+ "s", /* 4 */
+ "u", /* 5 */
+ "?", /* 6 */
+ "?", /* 7 */
+};
+
+/* Table for stack S operations */
+static char stack_reg_s[8][3] = {
+ "cc",
+ "a",
+ "b",
+ "dp",
+ "x",
+ "y",
+ "u",
+ "pc"
+};
+
+/* Table for stack U operations */
+static char stack_reg_u[8][3] = {
+ "cc",
+ "a",
+ "b",
+ "dp",
+ "x",
+ "y",
+ "s",
+ "pc"
+};
+
+static void calc_indexed( unsigned char mode, char *buf ) {
+ char buf2[30];
+ int idx, type;
+
+ idx = ( mode >> 4 ) & 7;
+ type = mode & 0x0f;
+
+ /* special modes */
+ if ( mode & 0x80 ) {
+ if ( type & 8 ) { /* indirect */
+ switch ( type & 7 ) {
+ case 0x00: /* register a */
+ sprintf( buf2, "[a,%s]", index_reg[idx] );
+ break;
+
+ case 0x01: /* register b */
+ sprintf( buf2, "[b,%s]", index_reg[idx] );
+ break;
+
+ case 0x04: /* direct - mode */
+ sprintf( buf2, "[$%02x]", get_next_byte() );
+ break;
+
+ case 0x07: /* register d */
+ sprintf( buf2, "[d,%s]", index_reg[idx] );
+ break;
+
+ default:
+ sprintf( buf2, "[?,%s]", index_reg[idx] );
+ break;
+ }
+ } else {
+ switch ( type & 7 ) {
+ case 0x00: /* register a */
+ sprintf( buf2, "a,%s", index_reg[idx] );
+ break;
+
+ case 0x01: /* register b */
+ sprintf( buf2, "b,%s", index_reg[idx] );
+ break;
+
+ case 0x04: /* direct - mode */
+ sprintf( buf2, "$%02x", get_next_byte() );
+ break;
+
+ case 0x07: /* register d */
+ sprintf( buf2, "d,%s", index_reg[idx] );
+ break;
+
+ default:
+ sprintf( buf2, "????,%s", index_reg[idx] );
+ break;
+ }
+ }
+ } else {
+ if ( type & 8 ) { /* indirect */
+ switch ( type & 7 ) {
+ case 0: /* auto increment */
+ sprintf( buf2, "[,%s+]", index_reg[idx] );
+ break;
+
+ case 1: /* auto increment double */
+ sprintf( buf2, "[,%s++]", index_reg[idx] );
+ break;
+
+ case 2: /* auto decrement */
+ sprintf( buf2, "[,-%s]", index_reg[idx] );
+ break;
+
+ case 3: /* auto decrement double */
+ sprintf( buf2, "[,--%s]", index_reg[idx] );
+ break;
+
+ case 4: /* post byte offset */
+ {
+ int val = get_next_byte();
+
+ if ( val & 0x80 )
+ sprintf( buf2, "[#$-%02x,%s]", 0x100 - val, index_reg[idx] );
+ else
+ sprintf( buf2, "[#$%02x,%s]", val, index_reg[idx] );
+ }
+ break;
+
+ case 5: /* post word offset */
+ {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ if ( val & 0x8000 )
+ sprintf( buf2, "[#$-%04x,%s]", 0x10000 - val, index_reg[idx] );
+ else
+ sprintf( buf2, "[#$%04x,%s]", val, index_reg[idx] );
+ }
+ break;
+
+ case 6: /* simple */
+ sprintf( buf2, "[,%s]", index_reg[idx] );
+ break;
+
+ case 7: /* extended */
+ {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf2, "[$%04x]", val );
+ }
+ break;
+ }
+ } else {
+ switch ( type & 7 ) {
+ case 0: /* auto increment */
+ sprintf( buf2, ",%s+", index_reg[idx] );
+ break;
+
+ case 1: /* auto increment double */
+ sprintf( buf2, ",%s++", index_reg[idx] );
+ break;
+
+ case 2: /* auto decrement */
+ sprintf( buf2, ",-%s", index_reg[idx] );
+ break;
+
+ case 3: /* auto decrement double */
+ sprintf( buf2, ",--%s", index_reg[idx] );
+ break;
+
+ case 4: /* post byte offset */
+ {
+ int val = get_next_byte();
+
+ if ( val & 0x80 )
+ sprintf( buf2, "#$-%02x,%s", 0x100 - val , index_reg[idx] );
+ else
+ sprintf( buf2, "#$%02x,%s", val, index_reg[idx] );
+ }
+ break;
+
+ case 5: /* post word offset */
+ {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ if ( val & 0x8000 )
+ sprintf( buf2, "#$-%04x,%s", 0x10000 - val, index_reg[idx] );
+ else
+ sprintf( buf2, "#$%04x,%s", val, index_reg[idx] );
+ }
+ break;
+
+ case 6: /* simple */
+ sprintf( buf2, ",%s", index_reg[idx] );
+ break;
+
+ case 7: /* extended */
+ {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf2, "$%04x", val );
+ }
+ break;
+
+ }
+ }
+ }
+
+ strcat( buf, buf2 );
+}
+
+static void do_relative( char *buf ) {
+ char buf2[30];
+ signed char offs = ( signed char )get_next_byte();
+
+ sprintf( buf2, "$%04x (%d)", local_pc + byte_count + offs, (int)offs );
+
+ strcat( buf, buf2 );
+}
+
+static void do_relative_word( char *buf ) {
+ char buf2[30];
+ signed short offs;
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ offs = ( signed short )val;
+
+ sprintf( buf2, "$%04x (%d)", local_pc + byte_count + offs, (int)offs );
+
+ strcat( buf, buf2 );
+}
+
+static void do_addressing( char *buf ) {
+ unsigned char mode = get_next_byte();
+
+ calc_indexed( mode, buf );
+}
+
+/*********************************************************************************
+
+ Opcodes
+
+*********************************************************************************/
+
+static void illegal( char *buf ) {
+ sprintf( buf, "illegal/unknown " );
+
+}
+
+static void leax( char *buf ) {
+ sprintf( buf, "leax " );
+ do_addressing( buf );
+}
+
+static void leay( char *buf ) {
+ sprintf( buf, "leay " );
+ do_addressing( buf );
+}
+
+static void leau( char *buf ) {
+ sprintf( buf, "leau " );
+ do_addressing( buf );
+}
+
+static void leas( char *buf ) {
+ sprintf( buf, "leas " );
+ do_addressing( buf );
+}
+
+static void lda( char *buf ) {
+ sprintf( buf, "lda #$%02x", get_next_byte() );
+}
+
+static void ldb( char *buf ) {
+ sprintf( buf, "ldb #$%02x", get_next_byte() );
+}
+
+static void lda2( char *buf ) {
+ sprintf( buf, "lda " );
+ do_addressing( buf );
+}
+
+static void ldb2( char *buf ) {
+ sprintf( buf, "ldb " );
+ do_addressing( buf );
+}
+
+static void adda( char *buf ) {
+ sprintf( buf, "adda #$%02x", get_next_byte() );
+}
+
+static void addb( char *buf ) {
+ sprintf( buf, "addb #$%02x", get_next_byte() );
+}
+
+static void adda2( char *buf ) {
+ sprintf( buf, "adda " );
+ do_addressing( buf );
+}
+
+static void addb2( char *buf ) {
+ sprintf( buf, "addb " );
+ do_addressing( buf );
+}
+
+static void suba( char *buf ) {
+ sprintf( buf, "suba #$%02x", get_next_byte() );
+}
+
+static void subb( char *buf ) {
+ sprintf( buf, "subb #$%02x", get_next_byte() );
+}
+
+static void suba2( char *buf ) {
+ sprintf( buf, "suba " );
+ do_addressing( buf );
+}
+
+static void subb2( char *buf ) {
+ sprintf( buf, "subb " );
+ do_addressing( buf );
+}
+
+static void sbca( char *buf ) {
+ sprintf( buf, "sbca #$%02x", get_next_byte() );
+}
+
+static void sbcb( char *buf ) {
+ sprintf( buf, "sbcb #$%02x", get_next_byte() );
+}
+
+static void sbca2( char *buf ) {
+ sprintf( buf, "sbca " );
+ do_addressing( buf );
+}
+
+static void sbcb2( char *buf ) {
+ sprintf( buf, "sbcb " );
+ do_addressing( buf );
+}
+
+static void adca( char *buf ) {
+ sprintf( buf, "adca #$%02x", get_next_byte() );
+}
+
+static void adca2( char *buf ) {
+ sprintf( buf, "adca " );
+ do_addressing( buf );
+}
+
+static void adcb2( char *buf ) {
+ sprintf( buf, "adcb " );
+ do_addressing( buf );
+}
+
+static void adcb( char *buf ) {
+ sprintf( buf, "adcb #$%02x", get_next_byte() );
+}
+
+static void anda( char *buf ) {
+ sprintf( buf, "anda #$%02x", get_next_byte() );
+}
+
+static void andb( char *buf ) {
+ sprintf( buf, "andb #$%02x", get_next_byte() );
+}
+
+static void anda2( char *buf ) {
+ sprintf( buf, "anda " );
+ do_addressing( buf );
+}
+
+static void andb2( char *buf ) {
+ sprintf( buf, "andb " );
+ do_addressing( buf );
+}
+
+static void bita( char *buf ) {
+ sprintf( buf, "bita #$%02x", get_next_byte() );
+}
+
+static void bitb( char *buf ) {
+ sprintf( buf, "bitb #$%02x", get_next_byte() );
+}
+
+static void bita2( char *buf ) {
+ sprintf( buf, "bita " );
+ do_addressing( buf );
+}
+
+static void bitb2( char *buf ) {
+ sprintf( buf, "bitb " );
+ do_addressing( buf );
+}
+
+static void eora( char *buf ) {
+ sprintf( buf, "eora #$%02x", get_next_byte() );
+}
+
+static void eorb( char *buf ) {
+ sprintf( buf, "eorb #$%02x", get_next_byte() );
+}
+
+static void eora2( char *buf ) {
+ sprintf( buf, "eora " );
+ do_addressing( buf );
+}
+
+static void eorb2( char *buf ) {
+ sprintf( buf, "eorb " );
+ do_addressing( buf );
+}
+
+static void ora( char *buf ) {
+ sprintf( buf, "ora #$%02x", get_next_byte() );
+}
+
+static void orb( char *buf ) {
+ sprintf( buf, "orb #$%02x", get_next_byte() );
+}
+
+static void ora2( char *buf ) {
+ sprintf( buf, "ora " );
+ do_addressing( buf );
+}
+
+static void orb2( char *buf ) {
+ sprintf( buf, "orb " );
+ do_addressing( buf );
+}
+
+static void cmpa( char *buf ) {
+ sprintf( buf, "cmpa #$%02x", get_next_byte() );
+}
+
+static void cmpb( char *buf ) {
+ sprintf( buf, "cmpb #$%02x", get_next_byte() );
+}
+
+static void cmpa2( char *buf ) {
+ sprintf( buf, "cmpa " );
+ do_addressing( buf );
+}
+
+static void cmpb2( char *buf ) {
+ sprintf( buf, "cmpb " );
+ do_addressing( buf );
+}
+
+static void setlines( char *buf ) {
+ sprintf( buf, "setlines #$%02x", get_next_byte() );
+}
+
+static void setlines2( char *buf ) {
+ sprintf( buf, "setlines " );
+ do_addressing( buf );
+}
+
+static void sta2( char *buf ) {
+ sprintf( buf, "sta " );
+ do_addressing( buf );
+}
+
+static void stb2( char *buf ) {
+ sprintf( buf, "stb " );
+ do_addressing( buf );
+}
+
+static void ldd( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "ldd #$%04x", val );
+}
+
+static void ldd2( char *buf ) {
+ sprintf( buf, "ldd " );
+ do_addressing( buf );
+}
+
+static void ldx( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "ldx #$%04x", val );
+}
+
+static void ldx2( char *buf ) {
+ sprintf( buf, "ldx " );
+ do_addressing( buf );
+}
+
+static void ldy( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "ldy #$%04x", val );
+}
+
+static void ldy2( char *buf ) {
+ sprintf( buf, "ldy " );
+ do_addressing( buf );
+}
+
+static void ldu( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "ldu #$%04x", val );
+}
+
+static void ldu2( char *buf ) {
+ sprintf( buf, "ldu " );
+ do_addressing( buf );
+}
+
+static void lds( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "lds #$%04x", val );
+}
+
+static void lds2( char *buf ) {
+ sprintf( buf, "lds " );
+ do_addressing( buf );
+}
+
+static void cmpd( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "cmpd #$%04x", val );
+}
+
+static void cmpd2( char *buf ) {
+ sprintf( buf, "cmpd " );
+ do_addressing( buf );
+}
+
+static void cmpx( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "cmpx #$%04x", val );
+}
+
+static void cmpx2( char *buf ) {
+ sprintf( buf, "cmpx " );
+ do_addressing( buf );
+}
+
+static void cmpy( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "cmpy #$%04x", val );
+}
+
+static void cmpy2( char *buf ) {
+ sprintf( buf, "cmpy " );
+ do_addressing( buf );
+}
+
+static void cmpu( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "cmpu #$%04x", val );
+}
+
+static void cmpu2( char *buf ) {
+ sprintf( buf, "cmpu " );
+ do_addressing( buf );
+}
+
+static void cmps( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "cmps #$%04x", val );
+}
+
+static void cmps2( char *buf ) {
+ sprintf( buf, "cmps " );
+ do_addressing( buf );
+}
+
+static void addd2( char *buf ) {
+ sprintf( buf, "addd " );
+ do_addressing( buf );
+}
+
+static void subd2( char *buf ) {
+ sprintf( buf, "subd " );
+ do_addressing( buf );
+}
+
+static void std2( char *buf ) {
+ sprintf( buf, "std " );
+ do_addressing( buf );
+}
+
+static void stx2( char *buf ) {
+ sprintf( buf, "stx " );
+ do_addressing( buf );
+}
+
+static void sty2( char *buf ) {
+ sprintf( buf, "sty " );
+ do_addressing( buf );
+}
+
+static void stu2( char *buf ) {
+ sprintf( buf, "stu " );
+ do_addressing( buf );
+}
+
+static void sts2( char *buf ) {
+ sprintf( buf, "sts " );
+ do_addressing( buf );
+}
+
+static void bra( char *buf ) {
+ sprintf( buf, "bra " );
+ do_relative( buf );
+}
+
+static void lbra( char *buf ) {
+ sprintf( buf, "lbra " );
+ do_relative_word( buf );
+}
+
+static void brn( char *buf ) {
+ sprintf( buf, "brn " );
+ do_relative( buf );
+}
+
+static void lbrn( char *buf ) {
+ sprintf( buf, "lbrn " );
+ do_relative_word( buf );
+}
+
+static void bhi( char *buf ) {
+ sprintf( buf, "bhi " );
+ do_relative( buf );
+}
+
+static void lbhi( char *buf ) {
+ sprintf( buf, "lbhi " );
+ do_relative_word( buf );
+}
+
+static void bls( char *buf ) {
+ sprintf( buf, "bls " );
+ do_relative( buf );
+}
+
+static void lbls( char *buf ) {
+ sprintf( buf, "lbls " );
+ do_relative_word( buf );
+}
+
+static void bcc( char *buf ) {
+ sprintf( buf, "bcc " );
+ do_relative( buf );
+}
+
+static void lbcc( char *buf ) {
+ sprintf( buf, "lbcc " );
+ do_relative_word( buf );
+}
+
+static void bcs( char *buf ) {
+ sprintf( buf, "bcs " );
+ do_relative( buf );
+}
+
+static void lbcs( char *buf ) {
+ sprintf( buf, "lbcs " );
+ do_relative_word( buf );
+}
+
+static void bne( char *buf ) {
+ sprintf( buf, "bne " );
+ do_relative( buf );
+}
+
+static void lbne( char *buf ) {
+ sprintf( buf, "lbne " );
+ do_relative_word( buf );
+}
+
+static void beq( char *buf ) {
+ sprintf( buf, "beq " );
+ do_relative( buf );
+}
+
+static void lbeq( char *buf ) {
+ sprintf( buf, "lbeq " );
+ do_relative_word( buf );
+}
+
+static void bvc( char *buf ) {
+ sprintf( buf, "bvc " );
+ do_relative( buf );
+}
+
+static void lbvc( char *buf ) {
+ sprintf( buf, "lbvc " );
+ do_relative_word( buf );
+}
+
+static void bvs( char *buf ) {
+ sprintf( buf, "bvs " );
+ do_relative( buf );
+}
+
+static void lbvs( char *buf ) {
+ sprintf( buf, "lbvs " );
+ do_relative_word( buf );
+}
+
+static void bpl( char *buf ) {
+ sprintf( buf, "bpl " );
+ do_relative( buf );
+}
+
+static void lbpl( char *buf ) {
+ sprintf( buf, "lbpl " );
+ do_relative_word( buf );
+}
+
+static void bmi( char *buf ) {
+ sprintf( buf, "bmi " );
+ do_relative( buf );
+}
+
+static void lbmi( char *buf ) {
+ sprintf( buf, "lbmi " );
+ do_relative_word( buf );
+}
+
+static void bge( char *buf ) {
+ sprintf( buf, "bge " );
+ do_relative( buf );
+}
+
+static void lbge( char *buf ) {
+ sprintf( buf, "lbge " );
+ do_relative_word( buf );
+}
+
+static void blt( char *buf ) {
+ sprintf( buf, "blt " );
+ do_relative( buf );
+}
+
+static void lblt( char *buf ) {
+ sprintf( buf, "lblt " );
+ do_relative_word( buf );
+}
+
+static void bgt( char *buf ) {
+ sprintf( buf, "bgt " );
+ do_relative( buf );
+}
+
+static void lbgt( char *buf ) {
+ sprintf( buf, "lbgt " );
+ do_relative_word( buf );
+}
+
+static void ble( char *buf ) {
+ sprintf( buf, "ble " );
+ do_relative( buf );
+}
+
+static void lble( char *buf ) {
+ sprintf( buf, "lble " );
+ do_relative_word( buf );
+}
+
+static void clra( char *buf ) {
+ sprintf( buf, "clra" );
+}
+
+static void clrb( char *buf ) {
+ sprintf( buf, "clrb" );
+}
+
+static void clrd( char *buf ) {
+ sprintf( buf, "clrd" );
+}
+
+static void clrw( char *buf ) {
+ sprintf( buf, "clrw " );
+ do_addressing( buf );
+}
+
+static void negd( char *buf ) {
+ sprintf( buf, "negd" );
+}
+
+static void negw( char *buf ) {
+ sprintf( buf, "negw" );
+ do_addressing( buf );
+}
+
+static void incd( char *buf ) {
+ sprintf( buf, "incd" );
+}
+
+static void incw( char *buf ) {
+ sprintf( buf, "incw " );
+ do_addressing( buf );
+}
+
+static void decd( char *buf ) {
+ sprintf( buf, "decd" );
+}
+
+static void decw( char *buf ) {
+ sprintf( buf, "decw " );
+ do_addressing( buf );
+}
+
+static void tstd( char *buf ) {
+ sprintf( buf, "tstd " );
+}
+
+static void tstw( char *buf ) {
+ sprintf( buf, "tstw " );
+ do_addressing( buf );
+}
+
+static void clr2( char *buf ) {
+ sprintf( buf, "clr " );
+ do_addressing( buf );
+}
+
+static void coma( char *buf ) {
+ sprintf( buf, "coma" );
+}
+
+static void comb( char *buf ) {
+ sprintf( buf, "comb" );
+}
+
+static void com2( char *buf ) {
+ sprintf( buf, "com " );
+ do_addressing( buf );
+}
+
+static void nega( char *buf ) {
+ sprintf( buf, "nega" );
+}
+
+static void negb( char *buf ) {
+ sprintf( buf, "negb" );
+}
+
+static void neg2( char *buf ) {
+ sprintf( buf, "neg " );
+ do_addressing( buf );
+}
+
+static void inca( char *buf ) {
+ sprintf( buf, "inca" );
+}
+
+static void incb( char *buf ) {
+ sprintf( buf, "incb" );
+}
+
+static void inc2( char *buf ) {
+ sprintf( buf, "inc " );
+ do_addressing( buf );
+}
+
+static void deca( char *buf ) {
+ sprintf( buf, "deca" );
+}
+
+static void decb( char *buf ) {
+ sprintf( buf, "decb" );
+}
+
+static void dec2( char *buf ) {
+ sprintf( buf, "dec " );
+ do_addressing( buf );
+}
+
+static void rts( char *buf ) {
+ sprintf( buf, "rts" );
+ flags = DASMFLAG_STEP_OUT;
+}
+
+static void asla( char *buf ) {
+ sprintf( buf, "asla" );
+}
+
+static void aslb( char *buf ) {
+ sprintf( buf, "aslb" );
+}
+
+static void asl2( char *buf ) {
+ sprintf( buf, "asl " );
+ do_addressing( buf );
+}
+
+static void rora( char *buf ) {
+ sprintf( buf, "rora" );
+}
+
+static void rorb( char *buf ) {
+ sprintf( buf, "rorb" );
+}
+
+static void ror2( char *buf ) {
+ sprintf( buf, "ror " );
+ do_addressing( buf );
+}
+
+static void rti( char *buf ) {
+ sprintf( buf, "rti" );
+ flags = DASMFLAG_STEP_OUT;
+}
+
+static void jsr2( char *buf ) {
+ sprintf( buf, "jsr " );
+ do_addressing( buf );
+ flags = DASMFLAG_STEP_OVER;
+}
+
+static void jmp2( char *buf ) {
+ sprintf( buf, "jmp " );
+ do_addressing( buf );
+}
+
+static void bsr( char *buf ) {
+ sprintf( buf, "bsr " );
+ do_relative( buf );
+ flags = DASMFLAG_STEP_OVER;
+}
+
+static void lbsr( char *buf ) {
+ sprintf( buf, "lbsr " );
+ do_relative_word( buf );
+ flags = DASMFLAG_STEP_OVER;
+}
+
+static void decbjnz( char *buf ) {
+ sprintf( buf, "decb,jnz " );
+ do_relative( buf );
+ flags = DASMFLAG_STEP_OVER;
+}
+
+static void decxjnz( char *buf ) {
+ sprintf( buf, "decx,jnz " );
+ do_relative( buf );
+ flags = DASMFLAG_STEP_OVER;
+}
+
+static void addd( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "addd #$%04x", val );
+}
+
+static void subd( char *buf ) {
+ int val = get_next_byte() << 8;
+
+ val |= get_next_byte();
+
+ sprintf( buf, "subd #$%04x", val );
+}
+
+static void tsta( char *buf ) {
+ sprintf( buf, "tsta" );
+}
+
+static void tstb( char *buf ) {
+ sprintf( buf, "tstb" );
+}
+
+static void tst2( char *buf ) {
+ sprintf( buf, "tst " );
+ do_addressing( buf );
+}
+
+static void lsra( char *buf ) {
+ sprintf( buf, "lsra" );
+}
+
+static void lsrb( char *buf ) {
+ sprintf( buf, "lsrb" );
+}
+
+static void lsr2( char *buf ) {
+ sprintf( buf, "lsr " );
+ do_addressing( buf );
+}
+
+static void asra( char *buf ) {
+ sprintf( buf, "asra" );
+}
+
+static void asrb( char *buf ) {
+ sprintf( buf, "asrb" );
+}
+
+static void asr2( char *buf ) {
+ sprintf( buf, "asr " );
+ do_addressing( buf );
+}
+
+static void abx( char *buf ) {
+ sprintf( buf, "abx" );
+}
+
+static void sex( char *buf ) {
+ sprintf( buf, "sex" );
+}
+
+static void daa( char *buf ) {
+ sprintf( buf, "daa" );
+}
+
+static void mul( char *buf ) {
+ sprintf( buf, "mul" );
+}
+
+static void lmul( char *buf ) {
+ sprintf( buf, "lmul" );
+}
+
+static void divx( char *buf ) {
+ sprintf( buf, "div x,b" );
+}
+
+static void andcc( char *buf ) {
+ sprintf( buf, "andcc #$%02x", get_next_byte() );
+}
+
+static void orcc( char *buf ) {
+ sprintf( buf, "orcc #$%02x", get_next_byte() );
+}
+
+static void pushs( char *buf ) {
+ int mask = get_next_byte(), i;
+
+ sprintf( buf, "pushs " );
+
+ for ( i = 0; i < 8; i++ ) {
+ if ( ( mask >> i ) & 1 ) {
+ strcat( buf, stack_reg_s[i] );
+ mask &= ~( 1 << i );
+ if ( mask )
+ strcat( buf, "," );
+ else
+ return;
+ }
+ }
+}
+
+static void pushu( char *buf ) {
+ int mask = get_next_byte(), i;
+
+ sprintf( buf, "pushu " );
+
+ for ( i = 0; i < 8; i++ ) {
+ if ( ( mask >> i ) & 1 ) {
+ strcat( buf, stack_reg_u[i] );
+ mask &= ~( 1 << i );
+ if ( mask )
+ strcat( buf, "," );
+ else
+ return;
+ }
+ }
+}
+
+static void pulls( char *buf ) {
+ int mask = get_next_byte(), i;
+
+ sprintf( buf, "pulls " );
+
+ for ( i = 0; i < 8; i++ ) {
+ if ( ( mask >> i ) & 1 ) {
+ strcat( buf, stack_reg_s[i] );
+ if (i == 7)
+ flags = DASMFLAG_STEP_OUT;
+ mask &= ~( 1 << i );
+ if ( mask )
+ strcat( buf, "," );
+ else
+ return;
+ }
+ }
+}
+
+static void pullu( char *buf ) {
+ int mask = get_next_byte(), i;
+
+ sprintf( buf, "pullu " );
+
+ for ( i = 0; i < 8; i++ ) {
+ if ( ( mask >> i ) & 1 ) {
+ strcat( buf, stack_reg_s[i] );
+ mask &= ~( 1 << i );
+ if ( mask )
+ strcat( buf, "," );
+ else
+ return;
+ }
+ }
+}
+
+static void rola( char *buf ) {
+ sprintf( buf, "rola" );
+}
+
+static void rolb( char *buf ) {
+ sprintf( buf, "rolb" );
+}
+
+static void rol2( char *buf ) {
+ sprintf( buf, "rol " );
+ do_addressing( buf );
+}
+
+static void bmove( char *buf ) {
+ sprintf( buf, "bmove y,x,u" );
+}
+
+static void move( char *buf ) {
+ sprintf( buf, "move y,x,u" );
+}
+
+static void bset( char *buf ) {
+ sprintf( buf, "bset a,x,u" );
+}
+
+static void bset2( char *buf ) {
+ sprintf( buf, "bset d,x,u" );
+}
+
+static void nop( char *buf ) {
+ sprintf( buf, "nop" );
+}
+
+static void tfr( char *buf ) {
+ int mask = get_next_byte();
+
+ sprintf( buf, "tfr " );
+
+ strcat( buf, tfrexg_reg[ mask & 0x07 ] );
+ strcat( buf, "," );
+ strcat( buf, tfrexg_reg[ ( mask >> 4 ) & 0x07 ] );
+}
+
+static void exg( char *buf ) {
+ int mask = get_next_byte();
+
+ sprintf( buf, "exg " );
+
+ strcat( buf, tfrexg_reg[ mask & 0x07 ] );
+ strcat( buf, "," );
+ strcat( buf, tfrexg_reg[ ( mask >> 4 ) & 0x07 ] );
+}
+
+static void lsrd( char *buf ) {
+ sprintf( buf, "lsrd #$%02x", get_next_byte() );
+}
+
+static void lsrd2( char *buf ) {
+ sprintf( buf, "lsrd " );
+ do_addressing( buf );
+}
+
+static void rord( char *buf ) {
+ sprintf( buf, "rord #$%02x", get_next_byte() );
+}
+
+static void rord2( char *buf ) {
+ sprintf( buf, "rord " );
+ do_addressing( buf );
+}
+
+static void asrd( char *buf ) {
+ sprintf( buf, "asrd #$%02x", get_next_byte() );
+}
+
+static void asrd2( char *buf ) {
+ sprintf( buf, "asrd " );
+ do_addressing( buf );
+}
+
+static void asld( char *buf ) {
+ sprintf( buf, "asld #$%02x", get_next_byte() );
+}
+
+static void asld2( char *buf ) {
+ sprintf( buf, "asld " );
+ do_addressing( buf );
+}
+
+static void rold( char *buf ) {
+ sprintf( buf, "rold #$%02x", get_next_byte() );
+}
+
+static void rold2( char *buf ) {
+ sprintf( buf, "rold " );
+ do_addressing( buf );
+}
+
+static void lsrw( char *buf ) {
+ sprintf( buf, "lsrw " );
+ do_addressing( buf );
+}
+
+static void rorw( char *buf ) {
+ sprintf( buf, "lsrw " );
+ do_addressing( buf );
+}
+
+static void asrw( char *buf ) {
+ sprintf( buf, "asrw " );
+ do_addressing( buf );
+}
+
+static void aslw( char *buf ) {
+ sprintf( buf, "aslw " );
+ do_addressing( buf );
+}
+
+static void rolw( char *buf ) {
+ sprintf( buf, "rolw " );
+ do_addressing( buf );
+}
+
+static void absa( char *buf ) {
+ sprintf( buf, "absa" );
+}
+
+static void absb( char *buf ) {
+ sprintf( buf, "absb" );
+}
+
+static void absd( char *buf ) {
+ sprintf( buf, "absd" );
+}
+
+/*********************************************************************************
+
+ Opcode Table
+
+*********************************************************************************/
+
+typedef struct {
+ void (*decode)( char *buf );
+ int confirmed;
+} konami_opcode_def;
+
+static konami_opcode_def op_table[256] = {
+ /* 00 */ { illegal, 0 },
+ /* 01 */ { illegal, 0 },
+ /* 02 */ { illegal, 0 },
+ /* 03 */ { illegal, 0 },
+ /* 04 */ { illegal, 0 },
+ /* 05 */ { illegal, 0 },
+ /* 06 */ { illegal, 0 },
+ /* 07 */ { illegal, 0 },
+ /* 08 */ { leax, 1 },
+ /* 09 */ { leay, 1 },
+ /* 0a */ { leau, 1 },
+ /* 0b */ { leas, 0 },
+ /* 0c */ { pushs, 1 },
+ /* 0d */ { pushu, 0 },
+ /* 0e */ { pulls, 1 },
+ /* 0f */ { pullu, 0 },
+
+ /* 10 */ { lda, 1 },
+ /* 11 */ { ldb, 1 },
+ /* 12 */ { lda2, 1 },
+ /* 13 */ { ldb2, 1 },
+ /* 14 */ { adda, 1 },
+ /* 15 */ { addb, 1 },
+ /* 16 */ { adda2, 1 },
+ /* 17 */ { addb2, 1 },
+ /* 18 */ { adca, 1 },
+ /* 19 */ { adcb, 1 },
+ /* 1a */ { adca2, 1 },
+ /* 1b */ { adcb2, 1 },
+ /* 1c */ { suba, 1 },
+ /* 1d */ { subb, 1 },
+ /* 1e */ { suba2, 1 },
+ /* 1f */ { subb2, 1 },
+
+ /* 20 */ { sbca, 0 },
+ /* 21 */ { sbcb, 0 },
+ /* 22 */ { sbca2, 0 },
+ /* 23 */ { sbcb2, 0 },
+ /* 24 */ { anda, 1 },
+ /* 25 */ { andb, 1 },
+ /* 26 */ { anda2, 1 },
+ /* 27 */ { andb2, 1 },
+ /* 28 */ { bita, 0 },
+ /* 29 */ { bitb, 0 },
+ /* 2a */ { bita2, 0 },
+ /* 2b */ { bitb2, 0 },
+ /* 2c */ { eora, 0 },
+ /* 2d */ { eorb, 0 },
+ /* 2e */ { eora2, 0 },
+ /* 2f */ { eorb2, 0 },
+
+ /* 30 */ { ora, 1 },
+ /* 31 */ { orb, 1 },
+ /* 32 */ { ora2, 1 },
+ /* 33 */ { orb2, 1 },
+ /* 34 */ { cmpa, 1 },
+ /* 35 */ { cmpb, 1 },
+ /* 36 */ { cmpa2, 1 },
+ /* 37 */ { cmpb2, 1 },
+ /* 38 */ { setlines, 0 },
+ /* 39 */ { setlines2, 0 },
+ /* 3a */ { sta2, 1 },
+ /* 3b */ { stb2, 1 },
+ /* 3c */ { andcc, 1 },
+ /* 3d */ { orcc, 0 },
+ /* 3e */ { exg, 0 },
+ /* 3f */ { tfr, 0 },
+
+ /* 40 */ { ldd, 1 },
+ /* 41 */ { ldd2, 1 },
+ /* 42 */ { ldx, 1 },
+ /* 43 */ { ldx2, 1 },
+ /* 44 */ { ldy, 1 },
+ /* 45 */ { ldy2, 1 },
+ /* 46 */ { ldu, 1 },
+ /* 47 */ { ldu2, 1 },
+ /* 48 */ { lds, 1 },
+ /* 49 */ { lds2, 1 },
+ /* 4a */ { cmpd, 1 },
+ /* 4b */ { cmpd2, 1 },
+ /* 4c */ { cmpx, 1 },
+ /* 4d */ { cmpx2, 1 },
+ /* 4e */ { cmpy, 1 },
+ /* 4f */ { cmpy2, 1 },
+
+ /* 50 */ { cmpu, 1 },
+ /* 51 */ { cmpu2, 1 },
+ /* 52 */ { cmps, 1 },
+ /* 53 */ { cmps2, 1 },
+ /* 54 */ { addd, 0 },
+ /* 55 */ { addd2, 0 },
+ /* 56 */ { subd, 1 },
+ /* 57 */ { subd2, 0 },
+ /* 58 */ { std2, 1 },
+ /* 59 */ { stx2, 1 },
+ /* 5a */ { sty2, 1 },
+ /* 5b */ { stu2, 1 },
+ /* 5c */ { sts2, 1 },
+ /* 5d */ { illegal, 0 },
+ /* 5e */ { illegal, 0 },
+ /* 5f */ { illegal, 0 },
+
+ /* 60 */ { bra, 1 },
+ /* 61 */ { bhi, 1 },
+ /* 62 */ { bcc, 1 },
+ /* 63 */ { bne, 1 },
+ /* 64 */ { bvc, 1 },
+ /* 65 */ { bpl, 1 },
+ /* 66 */ { bge, 1 },
+ /* 67 */ { bgt, 1 },
+ /* 68 */ { lbra, 1 },
+ /* 69 */ { lbhi, 1 },
+ /* 6a */ { lbcc, 1 },
+ /* 6b */ { lbne, 1 },
+ /* 6c */ { lbvc, 1 },
+ /* 6d */ { lbpl, 1 },
+ /* 6e */ { lbge, 1 },
+ /* 6f */ { lbgt, 1 },
+
+ /* 70 */ { brn, 1 },
+ /* 71 */ { bls, 1 },
+ /* 72 */ { bcs, 1 },
+ /* 73 */ { beq, 1 },
+ /* 74 */ { bvs, 1 },
+ /* 75 */ { bmi, 1 },
+ /* 76 */ { blt, 1 },
+ /* 77 */ { ble, 1 },
+ /* 78 */ { lbrn, 1 },
+ /* 79 */ { lbls, 1 },
+ /* 7a */ { lbcs, 1 },
+ /* 7b */ { lbeq, 1 },
+ /* 7c */ { lbvs, 1 },
+ /* 7d */ { lbmi, 1 },
+ /* 7e */ { lblt, 1 },
+ /* 7f */ { lble, 1 },
+
+ /* 80 */ { clra, 1 },
+ /* 81 */ { clrb, 1 },
+ /* 82 */ { clr2, 1 },
+ /* 83 */ { coma, 1 },
+ /* 84 */ { comb, 0 },
+ /* 85 */ { com2, 0 },
+ /* 86 */ { nega, 0 },
+ /* 87 */ { negb, 0 },
+ /* 88 */ { neg2, 0 },
+ /* 89 */ { inca, 1 },
+ /* 8a */ { incb, 1 },
+ /* 8b */ { inc2, 1 },
+ /* 8c */ { deca, 1 },
+ /* 8d */ { decb, 1 },
+ /* 8e */ { dec2, 1 },
+ /* 8f */ { rts, 1 },
+
+ /* 90 */ { tsta, 0 },
+ /* 91 */ { tstb, 0 },
+ /* 92 */ { tst2, 0 },
+ /* 93 */ { lsra, 1 },
+ /* 94 */ { lsrb, 1 },
+ /* 95 */ { lsr2, 0 },
+ /* 96 */ { rora, 0 },
+ /* 97 */ { rorb, 0 },
+ /* 98 */ { ror2, 0 },
+ /* 99 */ { asra, 0 },
+ /* 9a */ { asrb, 0 },
+ /* 9b */ { asr2, 0 },
+ /* 9c */ { asla, 1 },
+ /* 9d */ { aslb, 1 },
+ /* 9e */ { asl2, 0 },
+ /* 9f */ { rti, 1 },
+
+ /* a0 */ { rola, 1 },
+ /* a1 */ { rolb, 0 },
+ /* a2 */ { rol2, 0 },
+ /* a3 */ { lsrw, 0 },
+ /* a4 */ { rorw, 0 },
+ /* a5 */ { asrw, 0 },
+ /* a6 */ { aslw, 0 },
+ /* a7 */ { rolw, 0 },
+ /* a8 */ { jmp2, 1 },
+ /* a9 */ { jsr2, 1 },
+ /* aa */ { bsr, 1 },
+ /* ab */ { lbsr, 1 },
+ /* ac */ { decbjnz, 0 },
+ /* ad */ { decxjnz, 0 },
+ /* ae */ { nop, 0 },
+ /* af */ { illegal, 0 },
+
+ /* b0 */ { abx, 0 },
+ /* b1 */ { daa, 0 },
+ /* b2 */ { sex, 0 },
+ /* b3 */ { mul, 1 },
+ /* b4 */ { lmul, 0 },
+ /* b5 */ { divx, 0 },
+ /* b6 */ { bmove, 1 },
+ /* b7 */ { move, 0 },
+ /* b8 */ { lsrd, 0 },
+ /* b9 */ { lsrd2, 0 },
+ /* ba */ { rord, 0 },
+ /* bb */ { rord2, 0 },
+ /* bc */ { asrd, 0 },
+ /* bd */ { asrd2, 0 },
+ /* be */ { asld, 0 },
+ /* bf */ { asld2, 0 },
+
+ /* c0 */ { rold, 0 },
+ /* c1 */ { rold2, 0 },
+ /* c2 */ { clrd, 1 },
+ /* c3 */ { clrw, 0 },
+ /* c4 */ { negd, 0 },
+ /* c5 */ { negw, 0 },
+ /* c6 */ { incd, 0 },
+ /* c7 */ { incw, 0 },
+ /* c8 */ { decd, 0 },
+ /* c9 */ { decw, 0 },
+ /* ca */ { tstd, 0 },
+ /* cb */ { tstw, 0 },
+ /* cc */ { absa, 0 },
+ /* cd */ { absb, 0 },
+ /* ce */ { absd, 0 },
+ /* cf */ { bset, 0 },
+
+ /* d0 */ { bset2, 0 },
+ /* d1 */ { illegal, 0 },
+ /* d2 */ { illegal, 0 },
+ /* d3 */ { illegal, 0 },
+ /* d4 */ { illegal, 0 },
+ /* d5 */ { illegal, 0 },
+ /* d6 */ { illegal, 0 },
+ /* d7 */ { illegal, 0 },
+ /* d8 */ { illegal, 0 },
+ /* d9 */ { illegal, 0 },
+ /* da */ { illegal, 0 },
+ /* db */ { illegal, 0 },
+ /* dc */ { illegal, 0 },
+ /* dd */ { illegal, 0 },
+ /* de */ { illegal, 0 },
+ /* df */ { illegal, 0 },
+
+ /* e0 */ { illegal, 0 },
+ /* e1 */ { illegal, 0 },
+ /* e2 */ { illegal, 0 },
+ /* e3 */ { illegal, 0 },
+ /* e4 */ { illegal, 0 },
+ /* e5 */ { illegal, 0 },
+ /* e6 */ { illegal, 0 },
+ /* e7 */ { illegal, 0 },
+ /* e8 */ { illegal, 0 },
+ /* e9 */ { illegal, 0 },
+ /* ea */ { illegal, 0 },
+ /* eb */ { illegal, 0 },
+ /* ec */ { illegal, 0 },
+ /* ed */ { illegal, 0 },
+ /* ee */ { illegal, 0 },
+ /* ef */ { illegal, 0 },
+
+ /* f0 */ { illegal, 0 },
+ /* f1 */ { illegal, 0 },
+ /* f2 */ { illegal, 0 },
+ /* f3 */ { illegal, 0 },
+ /* f4 */ { illegal, 0 },
+ /* f5 */ { illegal, 0 },
+ /* f6 */ { illegal, 0 },
+ /* f7 */ { illegal, 0 },
+ /* f8 */ { illegal, 0 },
+ /* f9 */ { illegal, 0 },
+ /* fa */ { illegal, 0 },
+ /* fb */ { illegal, 0 },
+ /* fc */ { illegal, 0 },
+ /* fd */ { illegal, 0 },
+ /* fe */ { illegal, 0 },
+ /* ff */ { illegal, 0 }
+};
+
+offs_t konami_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ buffer[0] = '\0';
+
+ local_pc = pc;
+ byte_count = 1;
+ opram_ptr = opram;
+ flags = 0;
+
+ (op_table[*oprom].decode)( buffer );
+
+ return byte_count | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/konami/konami.c b/src/emu/cpu/konami/konami.c
new file mode 100644
index 00000000000..d02753ac695
--- /dev/null
+++ b/src/emu/cpu/konami/konami.c
@@ -0,0 +1,651 @@
+/*** konami: Portable Konami cpu emulator ******************************************
+
+ Copyright (C) The MAME Team 1999
+
+ Based on M6809 cpu core copyright (C) John Butler 1997
+
+ References:
+
+ 6809 Simulator V09, By L.C. Benschop, Eidnhoven The Netherlands.
+
+ m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from
+ the 6809 Simulator V09)
+
+ 6809 Microcomputer Programming & Interfacing with Experiments"
+ by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc.
+
+ System dependencies: UINT16 must be 16 bit unsigned int
+ UINT8 must be 8 bit unsigned int
+ UINT32 must be more than 16 bits
+ arrays up to 65536 bytes must be supported
+ machine must be twos complement
+
+ History:
+991022 HJB:
+ Tried to improve speed: Using bit7 of cycles1 as flag for multi
+ byte opcodes is gone, those opcodes now instead go through opcode2().
+ Inlined fetch_effective_address() into that function as well.
+ Got rid of the slow/fast flags for stack (S and U) memory accesses.
+ Minor changes to use 32 bit values as arguments to memory functions
+ and added defines for that purpose (e.g. X = 16bit XD = 32bit).
+
+990720 EHC:
+ Created this file
+
+*****************************************************************************/
+
+#include "debugger.h"
+#include "konami.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+/* Konami Registers */
+typedef struct
+{
+ PAIR pc; /* Program counter */
+ PAIR ppc; /* Previous program counter */
+ PAIR d; /* Accumulator a and b */
+ PAIR dp; /* Direct Page register (page in MSB) */
+ PAIR u, s; /* Stack pointers */
+ PAIR x, y; /* Index registers */
+ UINT8 cc;
+ UINT8 ireg; /* first opcode */
+ UINT8 irq_state[2];
+ int extra_cycles; /* cycles used up by interrupts */
+ int (*irq_callback)(int irqline);
+ UINT8 int_state; /* SYNC and CWAI flags */
+ UINT8 nmi_state;
+ void (*setlines_callback)( int lines ); /* callback called when A16-A23 are set */
+} konami_Regs;
+
+/* flag bits in the cc register */
+#define CC_C 0x01 /* Carry */
+#define CC_V 0x02 /* Overflow */
+#define CC_Z 0x04 /* Zero */
+#define CC_N 0x08 /* Negative */
+#define CC_II 0x10 /* Inhibit IRQ */
+#define CC_H 0x20 /* Half (auxiliary) carry */
+#define CC_IF 0x40 /* Inhibit FIRQ */
+#define CC_E 0x80 /* entire state pushed */
+
+/* Konami registers */
+static konami_Regs konami;
+
+#define pPPC konami.ppc
+#define pPC konami.pc
+#define pU konami.u
+#define pS konami.s
+#define pX konami.x
+#define pY konami.y
+#define pD konami.d
+
+#define PPC konami.ppc.w.l
+#define PC konami.pc.w.l
+#define PCD konami.pc.d
+#define U konami.u.w.l
+#define UD konami.u.d
+#define S konami.s.w.l
+#define SD konami.s.d
+#define X konami.x.w.l
+#define XD konami.x.d
+#define Y konami.y.w.l
+#define YD konami.y.d
+#define D konami.d.w.l
+#define A konami.d.b.h
+#define B konami.d.b.l
+#define DP konami.dp.b.h
+#define DPD konami.dp.d
+#define CC konami.cc
+
+static PAIR ea; /* effective address */
+#define EA ea.w.l
+#define EAD ea.d
+
+#define KONAMI_CWAI 8 /* set when CWAI is waiting for an interrupt */
+#define KONAMI_SYNC 16 /* set when SYNC is waiting for an interrupt */
+#define KONAMI_LDS 32 /* set when LDS occured at least once */
+
+#define CHECK_IRQ_LINES \
+ if( konami.irq_state[KONAMI_IRQ_LINE] != CLEAR_LINE || \
+ konami.irq_state[KONAMI_FIRQ_LINE] != CLEAR_LINE ) \
+ konami.int_state &= ~KONAMI_SYNC; /* clear SYNC flag */ \
+ if( konami.irq_state[KONAMI_FIRQ_LINE]!=CLEAR_LINE && !(CC & CC_IF) ) \
+ { \
+ /* fast IRQ */ \
+ /* state already saved by CWAI? */ \
+ if( konami.int_state & KONAMI_CWAI ) \
+ { \
+ konami.int_state &= ~KONAMI_CWAI; /* clear CWAI */ \
+ konami.extra_cycles += 7; /* subtract +7 cycles */ \
+ } \
+ else \
+ { \
+ CC &= ~CC_E; /* save 'short' state */ \
+ PUSHWORD(pPC); \
+ PUSHBYTE(CC); \
+ konami.extra_cycles += 10; /* subtract +10 cycles */ \
+ } \
+ CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */ \
+ PCD = RM16(0xfff6); \
+ change_pc(PC); /* TS 971002 */ \
+ (void)(*konami.irq_callback)(KONAMI_FIRQ_LINE); \
+ } \
+ else \
+ if( konami.irq_state[KONAMI_IRQ_LINE]!=CLEAR_LINE && !(CC & CC_II) )\
+ { \
+ /* standard IRQ */ \
+ /* state already saved by CWAI? */ \
+ if( konami.int_state & KONAMI_CWAI ) \
+ { \
+ konami.int_state &= ~KONAMI_CWAI; /* clear CWAI flag */ \
+ konami.extra_cycles += 7; /* subtract +7 cycles */ \
+ } \
+ else \
+ { \
+ CC |= CC_E; /* save entire state */ \
+ PUSHWORD(pPC); \
+ PUSHWORD(pU); \
+ PUSHWORD(pY); \
+ PUSHWORD(pX); \
+ PUSHBYTE(DP); \
+ PUSHBYTE(B); \
+ PUSHBYTE(A); \
+ PUSHBYTE(CC); \
+ konami.extra_cycles += 19; /* subtract +19 cycles */ \
+ } \
+ CC |= CC_II; /* inhibit IRQ */ \
+ PCD = RM16(0xfff8); \
+ change_pc(PC); /* TS 971002 */ \
+ (void)(*konami.irq_callback)(KONAMI_IRQ_LINE); \
+ }
+
+/* public globals */
+int konami_ICount=50000;
+int konami_Flags; /* flags for speed optimization (obsolete!!) */
+
+/* these are re-defined in konami.h TO RAM, ROM or functions in memory.c */
+#define RM(Addr) KONAMI_RDMEM(Addr)
+#define WM(Addr,Value) KONAMI_WRMEM(Addr,Value)
+#define ROP(Addr) KONAMI_RDOP(Addr)
+#define ROP_ARG(Addr) KONAMI_RDOP_ARG(Addr)
+
+#define SIGNED(a) (UINT16)(INT16)(INT8)(a)
+
+/* macros to access memory */
+#define IMMBYTE(b) { b = ROP_ARG(PCD); PC++; }
+#define IMMWORD(w) { w.d = (ROP_ARG(PCD)<<8) | ROP_ARG(PCD+1); PC += 2; }
+
+#define PUSHBYTE(b) --S; WM(SD,b)
+#define PUSHWORD(w) --S; WM(SD,w.b.l); --S; WM(SD,w.b.h)
+#define PULLBYTE(b) b=KONAMI_RDMEM(SD); S++
+#define PULLWORD(w) w=KONAMI_RDMEM(SD)<<8; S++; w|=KONAMI_RDMEM(SD); S++
+
+#define PSHUBYTE(b) --U; WM(UD,b);
+#define PSHUWORD(w) --U; WM(UD,w.b.l); --U; WM(UD,w.b.h)
+#define PULUBYTE(b) b=KONAMI_RDMEM(UD); U++
+#define PULUWORD(w) w=KONAMI_RDMEM(UD)<<8; U++; w|=KONAMI_RDMEM(UD); U++
+
+#define CLR_HNZVC CC&=~(CC_H|CC_N|CC_Z|CC_V|CC_C)
+#define CLR_NZV CC&=~(CC_N|CC_Z|CC_V)
+#define CLR_NZ CC&=~(CC_N|CC_Z)
+#define CLR_HNZC CC&=~(CC_H|CC_N|CC_Z|CC_C)
+#define CLR_NZVC CC&=~(CC_N|CC_Z|CC_V|CC_C)
+#define CLR_Z CC&=~(CC_Z)
+#define CLR_NZC CC&=~(CC_N|CC_Z|CC_C)
+#define CLR_ZC CC&=~(CC_Z|CC_C)
+
+/* macros for CC -- CC bits affected should be reset before calling */
+#define SET_Z(a) if(!a)SEZ
+#define SET_Z8(a) SET_Z((UINT8)a)
+#define SET_Z16(a) SET_Z((UINT16)a)
+#define SET_N8(a) CC|=((a&0x80)>>4)
+#define SET_N16(a) CC|=((a&0x8000)>>12)
+#define SET_H(a,b,r) CC|=(((a^b^r)&0x10)<<1)
+#define SET_C8(a) CC|=((a&0x100)>>8)
+#define SET_C16(a) CC|=((a&0x10000)>>16)
+#define SET_V8(a,b,r) CC|=(((a^b^r^(r>>1))&0x80)>>6)
+#define SET_V16(a,b,r) CC|=(((a^b^r^(r>>1))&0x8000)>>14)
+
+static UINT8 flags8i[256]= /* increment */
+{
+CC_Z,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+CC_N|CC_V,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N
+};
+static UINT8 flags8d[256]= /* decrement */
+{
+CC_Z,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,CC_V,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N
+};
+#define SET_FLAGS8I(a) {CC|=flags8i[(a)&0xff];}
+#define SET_FLAGS8D(a) {CC|=flags8d[(a)&0xff];}
+
+/* combos */
+#define SET_NZ8(a) {SET_N8(a);SET_Z(a);}
+#define SET_NZ16(a) {SET_N16(a);SET_Z(a);}
+#define SET_FLAGS8(a,b,r) {SET_N8(r);SET_Z8(r);SET_V8(a,b,r);SET_C8(r);}
+#define SET_FLAGS16(a,b,r) {SET_N16(r);SET_Z16(r);SET_V16(a,b,r);SET_C16(r);}
+
+/* macros for addressing modes (postbytes have their own code) */
+#define DIRECT EAD = DPD; IMMBYTE(ea.b.l)
+#define IMM8 EAD = PCD; PC++
+#define IMM16 EAD = PCD; PC+=2
+#define EXTENDED IMMWORD(ea)
+
+/* macros to set status flags */
+#define SEC CC|=CC_C
+#define CLC CC&=~CC_C
+#define SEZ CC|=CC_Z
+#define CLZ CC&=~CC_Z
+#define SEN CC|=CC_N
+#define CLN CC&=~CC_N
+#define SEV CC|=CC_V
+#define CLV CC&=~CC_V
+#define SEH CC|=CC_H
+#define CLH CC&=~CC_H
+
+/* macros for convenience */
+#define DIRBYTE(b) DIRECT; b=RM(EAD)
+#define DIRWORD(w) DIRECT; w.d=RM16(EAD)
+#define EXTBYTE(b) EXTENDED; b=RM(EAD)
+#define EXTWORD(w) EXTENDED; w.d=RM16(EAD)
+
+/* macros for branch instructions */
+#define BRANCH(f) { \
+ UINT8 t; \
+ IMMBYTE(t); \
+ if( f ) \
+ { \
+ PC += SIGNED(t); \
+ change_pc(PC); /* TS 971002 */ \
+ } \
+}
+
+#define LBRANCH(f) { \
+ PAIR t; \
+ IMMWORD(t); \
+ if( f ) \
+ { \
+ konami_ICount -= 1; \
+ PC += t.w.l; \
+ change_pc(PC); /* TS 971002 */ \
+ } \
+}
+
+#define NXORV ((CC&CC_N)^((CC&CC_V)<<2))
+
+/* macros for setting/getting registers in TFR/EXG instructions */
+#define GETREG(val,reg) \
+ switch(reg) { \
+ case 0: val = A; break; \
+ case 1: val = B; break; \
+ case 2: val = X; break; \
+ case 3: val = Y; break; \
+ case 4: val = S; break; /* ? */ \
+ case 5: val = U; break; \
+ default: val = 0xff; logerror("Unknown TFR/EXG idx at PC:%04x\n", PC ); break; \
+}
+
+#define SETREG(val,reg) \
+ switch(reg) { \
+ case 0: A = val; break; \
+ case 1: B = val; break; \
+ case 2: X = val; break; \
+ case 3: Y = val; break; \
+ case 4: S = val; break; /* ? */ \
+ case 5: U = val; break; \
+ default: logerror("Unknown TFR/EXG idx at PC:%04x\n", PC ); break; \
+}
+
+/* opcode timings */
+static UINT8 cycles1[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 5, 5, 5, 5,
+ /*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, 2, 2, 2, 2, 2,
+ /*3*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 7, 6,
+ /*4*/ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, 4,
+ /*5*/ 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 1, 1, 1,
+ /*6*/ 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+ /*7*/ 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+ /*8*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5,
+ /*9*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,
+ /*A*/ 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 3, 3, 2, 1,
+ /*B*/ 3, 2, 2,11,22,11, 2, 4, 3, 3, 3, 3, 3, 3, 3, 3,
+ /*C*/ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 2,
+ /*D*/ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /*E*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /*F*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+INLINE UINT32 RM16( UINT32 Addr )
+{
+ UINT32 result = RM(Addr) << 8;
+ return result | RM((Addr+1)&0xffff);
+}
+
+INLINE void WM16( UINT32 Addr, PAIR *p )
+{
+ WM( Addr, p->b.h );
+ WM( (Addr+1)&0xffff, p->b.l );
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void konami_get_context(void *dst)
+{
+ if( dst )
+ *(konami_Regs*)dst = konami;
+}
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void konami_set_context(void *src)
+{
+ if( src )
+ konami = *(konami_Regs*)src;
+ change_pc(PC); /* TS 971002 */
+
+ CHECK_IRQ_LINES;
+}
+
+/****************************************************************************/
+/* Reset registers to their initial values */
+/****************************************************************************/
+static void konami_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ konami.irq_callback = irqcallback;
+}
+
+static void konami_reset(void)
+{
+ konami.int_state = 0;
+ konami.nmi_state = CLEAR_LINE;
+ konami.irq_state[0] = CLEAR_LINE;
+ konami.irq_state[0] = CLEAR_LINE;
+
+ DPD = 0; /* Reset direct page register */
+
+ CC |= CC_II; /* IRQ disabled */
+ CC |= CC_IF; /* FIRQ disabled */
+
+ PCD = RM16(0xfffe);
+ change_pc(PC); /* TS 971002 */
+}
+
+static void konami_exit(void)
+{
+}
+
+/* Generate interrupts */
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (konami.nmi_state == state) return;
+ konami.nmi_state = state;
+ LOG(("KONAMI#%d set_nmi_line %d\n", cpu_getactivecpu(), state));
+ if( state == CLEAR_LINE ) return;
+
+ /* if the stack was not yet initialized */
+ if( !(konami.int_state & KONAMI_LDS) ) return;
+
+ konami.int_state &= ~KONAMI_SYNC;
+ /* state already saved by CWAI? */
+ if( konami.int_state & KONAMI_CWAI )
+ {
+ konami.int_state &= ~KONAMI_CWAI;
+ konami.extra_cycles += 7; /* subtract +7 cycles next time */
+ }
+ else
+ {
+ CC |= CC_E; /* save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ konami.extra_cycles += 19; /* subtract +19 cycles next time */
+ }
+ CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */
+ PCD = RM16(0xfffc);
+ change_pc(PC); /* TS 971002 */
+ }
+ else if (irqline < 2)
+ {
+ LOG(("KONAMI#%d set_irq_line %d, %d\n", cpu_getactivecpu(), irqline, state));
+ konami.irq_state[irqline] = state;
+ if (state == CLEAR_LINE) return;
+ CHECK_IRQ_LINES;
+ }
+}
+
+#if 0
+/****************************************************************************
+ * Save CPU state
+ ****************************************************************************/
+static void state_save(void *file, const char *module)
+{
+ int cpu = cpu_getactivecpu();
+ state_save_register_item(file, cpu, module, PC);
+ state_save_register_item(file, cpu, module, U);
+ state_save_register_item(file, cpu, module, S);
+ state_save_register_item(file, cpu, module, X);
+ state_save_register_item(file, cpu, module, Y);
+ state_save_register_item(file, cpu, module, DP);
+ state_save_register_item(file, cpu, module, CC);
+ state_save_register_item(file, cpu, module, konami.int_state);
+ state_save_register_item(file, cpu, module, konami.nmi_state);
+ state_save_register_item(file, cpu, module, konami.irq_state[0]);
+ state_save_register_item(file, cpu, module, konami.irq_state[1]);
+}
+#endif
+
+/* includes the static function prototypes and the master opcode table */
+#include "konamtbl.c"
+
+/* includes the actual opcode implementations */
+#include "konamops.c"
+
+/* execute instructions on this CPU until icount expires */
+static int konami_execute(int cycles)
+{
+ konami_ICount = cycles - konami.extra_cycles;
+ konami.extra_cycles = 0;
+
+ if( konami.int_state & (KONAMI_CWAI | KONAMI_SYNC) )
+ {
+ konami_ICount = 0;
+ }
+ else
+ {
+ do
+ {
+ pPPC = pPC;
+
+ CALL_MAME_DEBUG;
+
+ konami.ireg = ROP(PCD);
+ PC++;
+
+ (*konami_main[konami.ireg])();
+
+ konami_ICount -= cycles1[konami.ireg];
+
+ } while( konami_ICount > 0 );
+
+ konami_ICount -= konami.extra_cycles;
+ konami.extra_cycles = 0;
+ }
+
+ return cycles - konami_ICount;
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void konami_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + KONAMI_IRQ_LINE: set_irq_line(KONAMI_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + KONAMI_FIRQ_LINE:set_irq_line(KONAMI_FIRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + KONAMI_PC: PC = info->i; change_pc(PC); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + KONAMI_S: S = info->i; break;
+ case CPUINFO_INT_REGISTER + KONAMI_CC: CC = info->i; CHECK_IRQ_LINES; break;
+ case CPUINFO_INT_REGISTER + KONAMI_U: U = info->i; break;
+ case CPUINFO_INT_REGISTER + KONAMI_A: A = info->i; break;
+ case CPUINFO_INT_REGISTER + KONAMI_B: B = info->i; break;
+ case CPUINFO_INT_REGISTER + KONAMI_X: X = info->i; break;
+ case CPUINFO_INT_REGISTER + KONAMI_Y: Y = info->i; break;
+ case CPUINFO_INT_REGISTER + KONAMI_DP: DP = info->i; break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_KONAMI_SETLINES_CALLBACK: konami.setlines_callback = (void (*)(int))info->f; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void konami_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(konami); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 13; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + KONAMI_IRQ_LINE: info->i = konami.irq_state[KONAMI_IRQ_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + KONAMI_FIRQ_LINE:info->i = konami.irq_state[KONAMI_FIRQ_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = konami.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + KONAMI_PC: info->i = PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + KONAMI_S: info->i = S; break;
+ case CPUINFO_INT_REGISTER + KONAMI_CC: info->i = CC; break;
+ case CPUINFO_INT_REGISTER + KONAMI_U: info->i = U; break;
+ case CPUINFO_INT_REGISTER + KONAMI_A: info->i = A; break;
+ case CPUINFO_INT_REGISTER + KONAMI_B: info->i = B; break;
+ case CPUINFO_INT_REGISTER + KONAMI_X: info->i = X; break;
+ case CPUINFO_INT_REGISTER + KONAMI_Y: info->i = Y; break;
+ case CPUINFO_INT_REGISTER + KONAMI_DP: info->i = DP; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = konami_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = konami_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = konami_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = konami_init; break;
+ case CPUINFO_PTR_RESET: info->reset = konami_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = konami_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = konami_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = konami_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &konami_ICount; break;
+ case CPUINFO_PTR_KONAMI_SETLINES_CALLBACK: info->f = (genf *)konami.setlines_callback; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "KONAMI"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "KONAMI 5000x"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) The MAME Team 1999"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ konami.cc & 0x80 ? 'E':'.',
+ konami.cc & 0x40 ? 'F':'.',
+ konami.cc & 0x20 ? 'H':'.',
+ konami.cc & 0x10 ? 'I':'.',
+ konami.cc & 0x08 ? 'N':'.',
+ konami.cc & 0x04 ? 'Z':'.',
+ konami.cc & 0x02 ? 'V':'.',
+ konami.cc & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + KONAMI_PC: sprintf(info->s, "PC:%04X", konami.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + KONAMI_S: sprintf(info->s, "S:%04X", konami.s.w.l); break;
+ case CPUINFO_STR_REGISTER + KONAMI_CC: sprintf(info->s, "CC:%02X", konami.cc); break;
+ case CPUINFO_STR_REGISTER + KONAMI_U: sprintf(info->s, "U:%04X", konami.u.w.l); break;
+ case CPUINFO_STR_REGISTER + KONAMI_A: sprintf(info->s, "A:%02X", konami.d.b.h); break;
+ case CPUINFO_STR_REGISTER + KONAMI_B: sprintf(info->s, "B:%02X", konami.d.b.l); break;
+ case CPUINFO_STR_REGISTER + KONAMI_X: sprintf(info->s, "X:%04X", konami.x.w.l); break;
+ case CPUINFO_STR_REGISTER + KONAMI_Y: sprintf(info->s, "Y:%04X", konami.y.w.l); break;
+ case CPUINFO_STR_REGISTER + KONAMI_DP: sprintf(info->s, "DP:%02X", konami.dp.b.h); break;
+ }
+}
diff --git a/src/emu/cpu/konami/konami.h b/src/emu/cpu/konami/konami.h
new file mode 100644
index 00000000000..c76821663bc
--- /dev/null
+++ b/src/emu/cpu/konami/konami.h
@@ -0,0 +1,58 @@
+/*** konami: Portable Konami cpu emulator ******************************************/
+
+#ifndef _KONAMI_H
+#define _KONAMI_H
+
+#include "cpuintrf.h"
+
+enum {
+ KONAMI_PC=1, KONAMI_S, KONAMI_CC ,KONAMI_A, KONAMI_B, KONAMI_U, KONAMI_X, KONAMI_Y,
+ KONAMI_DP };
+
+enum
+{
+ CPUINFO_PTR_KONAMI_SETLINES_CALLBACK = CPUINFO_PTR_CPU_SPECIFIC
+};
+
+#define KONAMI_IRQ_LINE 0 /* IRQ line number */
+#define KONAMI_FIRQ_LINE 1 /* FIRQ line number */
+
+/* PUBLIC FUNCTIONS */
+void konami_get_info(UINT32 state, cpuinfo *info);
+
+/****************************************************************************/
+/* Read a byte from given memory location */
+/****************************************************************************/
+#define KONAMI_RDMEM(Addr) ((unsigned)program_read_byte_8(Addr))
+
+/****************************************************************************/
+/* Write a byte to given memory location */
+/****************************************************************************/
+#define KONAMI_WRMEM(Addr,Value) (program_write_byte_8(Addr,Value))
+
+/****************************************************************************/
+/* Z80_RDOP() is identical to Z80_RDMEM() except it is used for reading */
+/* opcodes. In case of system with memory mapped I/O, this function can be */
+/* used to greatly speed up emulation */
+/****************************************************************************/
+#define KONAMI_RDOP(Addr) ((unsigned)cpu_readop(Addr))
+
+/****************************************************************************/
+/* Z80_RDOP_ARG() is identical to Z80_RDOP() except it is used for reading */
+/* opcode arguments. This difference can be used to support systems that */
+/* use different encoding mechanisms for opcodes and opcode arguments */
+/****************************************************************************/
+#define KONAMI_RDOP_ARG(Addr) ((unsigned)cpu_readop_arg(Addr))
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE (!FALSE)
+#endif
+
+#ifdef MAME_DEBUG
+offs_t konami_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _KONAMI_H */
diff --git a/src/emu/cpu/konami/konamops.c b/src/emu/cpu/konami/konamops.c
new file mode 100644
index 00000000000..808b2a58603
--- /dev/null
+++ b/src/emu/cpu/konami/konamops.c
@@ -0,0 +1,4361 @@
+/*
+
+HNZVC
+
+? = undefined
+* = affected
+- = unaffected
+0 = cleared
+1 = set
+# = CCr directly affected by instruction
+@ = special - carry set if bit 7 is set
+
+*/
+
+#ifdef NEW
+static void illegal( void )
+#else
+INLINE void illegal( void )
+#endif
+{
+ logerror("KONAMI: illegal opcode at %04x\n",PC);
+}
+
+/* $00 NEG direct ?**** */
+INLINE void neg_di( void )
+{
+ UINT16 r,t;
+ DIRBYTE(t);
+ r = -t;
+ CLR_NZVC;
+ SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $01 ILLEGAL */
+
+/* $02 ILLEGAL */
+
+/* $03 COM direct -**01 */
+INLINE void com_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ t = ~t;
+ CLR_NZV;
+ SET_NZ8(t);
+ SEC;
+ WM(EAD,t);
+}
+
+/* $04 LSR direct -0*-* */
+INLINE void lsr_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t >>= 1;
+ SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $05 ILLEGAL */
+
+/* $06 ROR direct -**-* */
+INLINE void ror_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r= (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (t & CC_C);
+ r |= t>>1;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $07 ASR direct ?**-* */
+INLINE void asr_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t = (t & 0x80) | (t >> 1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $08 ASL direct ?**** */
+INLINE void asl_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $09 ROL direct -**** */
+INLINE void rol_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = (CC & CC_C) | (t << 1);
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $0A DEC direct -***- */
+INLINE void dec_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ --t;
+ CLR_NZV;
+ SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $0B ILLEGAL */
+
+/* $OC INC direct -***- */
+INLINE void inc_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ ++t;
+ CLR_NZV;
+ SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $OD TST direct -**0- */
+INLINE void tst_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZV;
+ SET_NZ8(t);
+}
+
+/* $0E JMP direct ----- */
+INLINE void jmp_di( void )
+{
+ DIRECT;
+ PCD=EAD;
+ change_pc(PCD);
+}
+
+/* $0F CLR direct -0100 */
+INLINE void clr_di( void )
+{
+ DIRECT;
+ WM(EAD,0);
+ CLR_NZVC;
+ SEZ;
+}
+
+/* $10 FLAG */
+
+/* $11 FLAG */
+
+/* $12 NOP inherent ----- */
+INLINE void nop( void )
+{
+ ;
+}
+
+/* $13 SYNC inherent ----- */
+INLINE void sync( void )
+{
+ /* SYNC stops processing instructions until an interrupt request happens. */
+ /* This doesn't require the corresponding interrupt to be enabled: if it */
+ /* is disabled, execution continues with the next instruction. */
+ konami.int_state |= KONAMI_SYNC;
+ CHECK_IRQ_LINES;
+ /* if KONAMI_SYNC has not been cleared by CHECK_IRQ_LINES,
+ * stop execution until the interrupt lines change. */
+ if( (konami.int_state & KONAMI_SYNC) && konami_ICount > 0 )
+ konami_ICount = 0;
+}
+
+/* $14 ILLEGAL */
+
+/* $15 ILLEGAL */
+
+/* $16 LBRA relative ----- */
+INLINE void lbra( void )
+{
+ IMMWORD(ea);
+ PC += EA;
+ change_pc(PCD);
+
+ /* EHC 980508 speed up busy loop */
+ if( EA == 0xfffd && konami_ICount > 0 )
+ konami_ICount = 0;
+}
+
+/* $17 LBSR relative ----- */
+INLINE void lbsr( void )
+{
+ IMMWORD(ea);
+ PUSHWORD(pPC);
+ PC += EA;
+ change_pc(PCD);
+}
+
+/* $18 ILLEGAL */
+
+#if 1
+/* $19 DAA inherent (A) -**0* */
+INLINE void daa( void )
+{
+ UINT8 msn, lsn;
+ UINT16 t, cf = 0;
+ msn = A & 0xf0; lsn = A & 0x0f;
+ if( lsn>0x09 || CC & CC_H) cf |= 0x06;
+ if( msn>0x80 && lsn>0x09 ) cf |= 0x60;
+ if( msn>0x90 || CC & CC_C) cf |= 0x60;
+ t = cf + A;
+ CLR_NZV; /* keep carry from previous operation */
+ SET_NZ8((UINT8)t); SET_C8(t);
+ A = t;
+}
+#else
+/* $19 DAA inherent (A) -**0* */
+INLINE void daa( void )
+{
+ UINT16 t;
+ t = A;
+ if (CC & CC_H) t+=0x06;
+ if ((t&0x0f)>9) t+=0x06; /* ASG -- this code is broken! $66+$99=$FF -> DAA should = $65, we get $05! */
+ if (CC & CC_C) t+=0x60;
+ if ((t&0xf0)>0x90) t+=0x60;
+ if (t&0x100) SEC;
+ A = t;
+}
+#endif
+
+/* $1A ORCC immediate ##### */
+INLINE void orcc( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ CC |= t;
+ CHECK_IRQ_LINES;
+}
+
+/* $1B ILLEGAL */
+
+/* $1C ANDCC immediate ##### */
+INLINE void andcc( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ CC &= t;
+ CHECK_IRQ_LINES;
+}
+
+/* $1D SEX inherent -**0- */
+INLINE void sex( void )
+{
+ UINT16 t;
+ t = SIGNED(B);
+ D = t;
+// CLR_NZV; NS 20020905: applying the same fix that was applied to 6809 and 6309
+ CLR_NZ;
+ SET_NZ16(t);
+}
+
+/* $1E EXG inherent ----- */
+INLINE void exg( void )
+{
+ UINT16 t1 = 0, t2 = 0;
+ UINT8 tb;
+
+ IMMBYTE(tb);
+
+ GETREG( t1, tb >> 4 );
+ GETREG( t2, tb & 0x0f );
+
+ SETREG( t2, tb >> 4 );
+ SETREG( t1, tb & 0x0f );
+}
+
+/* $1F TFR inherent ----- */
+INLINE void tfr( void )
+{
+ UINT8 tb;
+ UINT16 t = 0;
+
+ IMMBYTE(tb);
+
+ GETREG( t, tb & 0x0f );
+ SETREG( t, ( tb >> 4 ) & 0x07 );
+}
+
+/* $20 BRA relative ----- */
+INLINE void bra( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ PC += SIGNED(t);
+ change_pc(PCD);
+ /* JB 970823 - speed up busy loops */
+ if( t == 0xfe && konami_ICount > 0 )
+ konami_ICount = 0;
+}
+
+/* $21 BRN relative ----- */
+INLINE void brn( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+}
+
+/* $1021 LBRN relative ----- */
+INLINE void lbrn( void )
+{
+ IMMWORD(ea);
+}
+
+/* $22 BHI relative ----- */
+INLINE void bhi( void )
+{
+ BRANCH( !(CC & (CC_Z|CC_C)) );
+}
+
+/* $1022 LBHI relative ----- */
+INLINE void lbhi( void )
+{
+ LBRANCH( !(CC & (CC_Z|CC_C)) );
+}
+
+/* $23 BLS relative ----- */
+INLINE void bls( void )
+{
+ BRANCH( (CC & (CC_Z|CC_C)) );
+}
+
+/* $1023 LBLS relative ----- */
+INLINE void lbls( void )
+{
+ LBRANCH( (CC&(CC_Z|CC_C)) );
+}
+
+/* $24 BCC relative ----- */
+INLINE void bcc( void )
+{
+ BRANCH( !(CC&CC_C) );
+}
+
+/* $1024 LBCC relative ----- */
+INLINE void lbcc( void )
+{
+ LBRANCH( !(CC&CC_C) );
+}
+
+/* $25 BCS relative ----- */
+INLINE void bcs( void )
+{
+ BRANCH( (CC&CC_C) );
+}
+
+/* $1025 LBCS relative ----- */
+INLINE void lbcs( void )
+{
+ LBRANCH( (CC&CC_C) );
+}
+
+/* $26 BNE relative ----- */
+INLINE void bne( void )
+{
+ BRANCH( !(CC&CC_Z) );
+}
+
+/* $1026 LBNE relative ----- */
+INLINE void lbne( void )
+{
+ LBRANCH( !(CC&CC_Z) );
+}
+
+/* $27 BEQ relative ----- */
+INLINE void beq( void )
+{
+ BRANCH( (CC&CC_Z) );
+}
+
+/* $1027 LBEQ relative ----- */
+INLINE void lbeq( void )
+{
+ LBRANCH( (CC&CC_Z) );
+}
+
+/* $28 BVC relative ----- */
+INLINE void bvc( void )
+{
+ BRANCH( !(CC&CC_V) );
+}
+
+/* $1028 LBVC relative ----- */
+INLINE void lbvc( void )
+{
+ LBRANCH( !(CC&CC_V) );
+}
+
+/* $29 BVS relative ----- */
+INLINE void bvs( void )
+{
+ BRANCH( (CC&CC_V) );
+}
+
+/* $1029 LBVS relative ----- */
+INLINE void lbvs( void )
+{
+ LBRANCH( (CC&CC_V) );
+}
+
+/* $2A BPL relative ----- */
+INLINE void bpl( void )
+{
+ BRANCH( !(CC&CC_N) );
+}
+
+/* $102A LBPL relative ----- */
+INLINE void lbpl( void )
+{
+ LBRANCH( !(CC&CC_N) );
+}
+
+/* $2B BMI relative ----- */
+INLINE void bmi( void )
+{
+ BRANCH( (CC&CC_N) );
+}
+
+/* $102B LBMI relative ----- */
+INLINE void lbmi( void )
+{
+ LBRANCH( (CC&CC_N) );
+}
+
+/* $2C BGE relative ----- */
+INLINE void bge( void )
+{
+ BRANCH( !NXORV );
+}
+
+/* $102C LBGE relative ----- */
+INLINE void lbge( void )
+{
+ LBRANCH( !NXORV );
+}
+
+/* $2D BLT relative ----- */
+INLINE void blt( void )
+{
+ BRANCH( NXORV );
+}
+
+/* $102D LBLT relative ----- */
+INLINE void lblt( void )
+{
+ LBRANCH( NXORV );
+}
+
+/* $2E BGT relative ----- */
+INLINE void bgt( void )
+{
+ BRANCH( !(NXORV || (CC&CC_Z)) );
+}
+
+/* $102E LBGT relative ----- */
+INLINE void lbgt( void )
+{
+ LBRANCH( !(NXORV || (CC&CC_Z)) );
+}
+
+/* $2F BLE relative ----- */
+INLINE void ble( void )
+{
+ BRANCH( (NXORV || (CC&CC_Z)) );
+}
+
+/* $102F LBLE relative ----- */
+INLINE void lble( void )
+{
+ LBRANCH( (NXORV || (CC&CC_Z)) );
+}
+
+/* $30 LEAX indexed --*-- */
+INLINE void leax( void )
+{
+ X = EA;
+ CLR_Z;
+ SET_Z(X);
+}
+
+/* $31 LEAY indexed --*-- */
+INLINE void leay( void )
+{
+ Y = EA;
+ CLR_Z;
+ SET_Z(Y);
+}
+
+/* $32 LEAS indexed ----- */
+INLINE void leas( void )
+{
+ S = EA;
+ konami.int_state |= KONAMI_LDS;
+}
+
+/* $33 LEAU indexed ----- */
+INLINE void leau( void )
+{
+ U = EA;
+}
+
+/* $34 PSHS inherent ----- */
+INLINE void pshs( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x80 ) { PUSHWORD(pPC); konami_ICount -= 2; }
+ if( t&0x40 ) { PUSHWORD(pU); konami_ICount -= 2; }
+ if( t&0x20 ) { PUSHWORD(pY); konami_ICount -= 2; }
+ if( t&0x10 ) { PUSHWORD(pX); konami_ICount -= 2; }
+ if( t&0x08 ) { PUSHBYTE(DP); konami_ICount -= 1; }
+ if( t&0x04 ) { PUSHBYTE(B); konami_ICount -= 1; }
+ if( t&0x02 ) { PUSHBYTE(A); konami_ICount -= 1; }
+ if( t&0x01 ) { PUSHBYTE(CC); konami_ICount -= 1; }
+}
+
+/* 35 PULS inherent ----- */
+INLINE void puls( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x01 ) { PULLBYTE(CC); konami_ICount -= 1; }
+ if( t&0x02 ) { PULLBYTE(A); konami_ICount -= 1; }
+ if( t&0x04 ) { PULLBYTE(B); konami_ICount -= 1; }
+ if( t&0x08 ) { PULLBYTE(DP); konami_ICount -= 1; }
+ if( t&0x10 ) { PULLWORD(XD); konami_ICount -= 2; }
+ if( t&0x20 ) { PULLWORD(YD); konami_ICount -= 2; }
+ if( t&0x40 ) { PULLWORD(UD); konami_ICount -= 2; }
+ if( t&0x80 ) { PULLWORD(PCD); change_pc(PCD); konami_ICount -= 2; }
+
+ /* check after all PULLs */
+ if( t&0x01 ) { CHECK_IRQ_LINES; }
+}
+
+/* $36 PSHU inherent ----- */
+INLINE void pshu( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x80 ) { PSHUWORD(pPC); konami_ICount -= 2; }
+ if( t&0x40 ) { PSHUWORD(pS); konami_ICount -= 2; }
+ if( t&0x20 ) { PSHUWORD(pY); konami_ICount -= 2; }
+ if( t&0x10 ) { PSHUWORD(pX); konami_ICount -= 2; }
+ if( t&0x08 ) { PSHUBYTE(DP); konami_ICount -= 1; }
+ if( t&0x04 ) { PSHUBYTE(B); konami_ICount -= 1; }
+ if( t&0x02 ) { PSHUBYTE(A); konami_ICount -= 1; }
+ if( t&0x01 ) { PSHUBYTE(CC); konami_ICount -= 1; }
+}
+
+/* 37 PULU inherent ----- */
+INLINE void pulu( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x01 ) { PULUBYTE(CC); konami_ICount -= 1; }
+ if( t&0x02 ) { PULUBYTE(A); konami_ICount -= 1; }
+ if( t&0x04 ) { PULUBYTE(B); konami_ICount -= 1; }
+ if( t&0x08 ) { PULUBYTE(DP); konami_ICount -= 1; }
+ if( t&0x10 ) { PULUWORD(XD); konami_ICount -= 2; }
+ if( t&0x20 ) { PULUWORD(YD); konami_ICount -= 2; }
+ if( t&0x40 ) { PULUWORD(SD); konami_ICount -= 2; }
+ if( t&0x80 ) { PULUWORD(PCD); change_pc(PCD); konami_ICount -= 2; }
+
+ /* check after all PULLs */
+ if( t&0x01 ) { CHECK_IRQ_LINES; }
+}
+
+/* $38 ILLEGAL */
+
+/* $39 RTS inherent ----- */
+INLINE void rts( void )
+{
+ PULLWORD(PCD);
+ change_pc(PCD);
+}
+
+/* $3A ABX inherent ----- */
+INLINE void abx( void )
+{
+ X += B;
+}
+
+/* $3B RTI inherent ##### */
+INLINE void rti( void )
+{
+ PULLBYTE(CC);
+ if( CC & CC_E ) /* entire state saved? */
+ {
+ konami_ICount -= 9;
+ PULLBYTE(A);
+ PULLBYTE(B);
+ PULLBYTE(DP);
+ PULLWORD(XD);
+ PULLWORD(YD);
+ PULLWORD(UD);
+ }
+ PULLWORD(PCD);
+ change_pc(PCD);
+ CHECK_IRQ_LINES;
+}
+
+/* $3C CWAI inherent ----1 */
+INLINE void cwai( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ CC &= t;
+ /*
+ * CWAI stacks the entire machine state on the hardware stack,
+ * then waits for an interrupt; when the interrupt is taken
+ * later, the state is *not* saved again after CWAI.
+ */
+ CC |= CC_E; /* HJB 990225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ konami.int_state |= KONAMI_CWAI;
+ CHECK_IRQ_LINES;
+ if( (konami.int_state & KONAMI_CWAI) && konami_ICount > 0 )
+ konami_ICount = 0;
+}
+
+/* $3D MUL inherent --*-@ */
+INLINE void mul( void )
+{
+ UINT16 t;
+ t = A * B;
+ CLR_ZC; SET_Z16(t); if(t&0x80) SEC;
+ D = t;
+}
+
+/* $3E ILLEGAL */
+
+/* $3F SWI (SWI2 SWI3) absolute indirect ----- */
+INLINE void swi( void )
+{
+ CC |= CC_E; /* HJB 980225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */
+ PCD=RM16(0xfffa);
+ change_pc(PCD);
+}
+
+/* $103F SWI2 absolute indirect ----- */
+INLINE void swi2( void )
+{
+ CC |= CC_E; /* HJB 980225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ PCD=RM16(0xfff4);
+ change_pc(PCD);
+}
+
+/* $113F SWI3 absolute indirect ----- */
+INLINE void swi3( void )
+{
+ CC |= CC_E; /* HJB 980225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ PCD=RM16(0xfff2);
+ change_pc(PCD);
+}
+
+/* $40 NEGA inherent ?**** */
+INLINE void nega( void )
+{
+ UINT16 r;
+ r = -A;
+ CLR_NZVC;
+ SET_FLAGS8(0,A,r);
+ A = r;
+}
+
+/* $41 ILLEGAL */
+
+/* $42 ILLEGAL */
+
+/* $43 COMA inherent -**01 */
+INLINE void coma( void )
+{
+ A = ~A;
+ CLR_NZV;
+ SET_NZ8(A);
+ SEC;
+}
+
+/* $44 LSRA inherent -0*-* */
+INLINE void lsra( void )
+{
+ CLR_NZC;
+ CC |= (A & CC_C);
+ A >>= 1;
+ SET_Z8(A);
+}
+
+/* $45 ILLEGAL */
+
+/* $46 RORA inherent -**-* */
+INLINE void rora( void )
+{
+ UINT8 r;
+ r = (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (A & CC_C);
+ r |= A >> 1;
+ SET_NZ8(r);
+ A = r;
+}
+
+/* $47 ASRA inherent ?**-* */
+INLINE void asra( void )
+{
+ CLR_NZC;
+ CC |= (A & CC_C);
+ A = (A & 0x80) | (A >> 1);
+ SET_NZ8(A);
+}
+
+/* $48 ASLA inherent ?**** */
+INLINE void asla( void )
+{
+ UINT16 r;
+ r = A << 1;
+ CLR_NZVC;
+ SET_FLAGS8(A,A,r);
+ A = r;
+}
+
+/* $49 ROLA inherent -**** */
+INLINE void rola( void )
+{
+ UINT16 t,r;
+ t = A;
+ r = (CC & CC_C) | (t<<1);
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ A = r;
+}
+
+/* $4A DECA inherent -***- */
+INLINE void deca( void )
+{
+ --A;
+ CLR_NZV;
+ SET_FLAGS8D(A);
+}
+
+/* $4B ILLEGAL */
+
+/* $4C INCA inherent -***- */
+INLINE void inca( void )
+{
+ ++A;
+ CLR_NZV;
+ SET_FLAGS8I(A);
+}
+
+/* $4D TSTA inherent -**0- */
+INLINE void tsta( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $4E ILLEGAL */
+
+/* $4F CLRA inherent -0100 */
+INLINE void clra( void )
+{
+ A = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $50 NEGB inherent ?**** */
+INLINE void negb( void )
+{
+ UINT16 r;
+ r = -B;
+ CLR_NZVC;
+ SET_FLAGS8(0,B,r);
+ B = r;
+}
+
+/* $51 ILLEGAL */
+
+/* $52 ILLEGAL */
+
+/* $53 COMB inherent -**01 */
+INLINE void comb( void )
+{
+ B = ~B;
+ CLR_NZV;
+ SET_NZ8(B);
+ SEC;
+}
+
+/* $54 LSRB inherent -0*-* */
+INLINE void lsrb( void )
+{
+ CLR_NZC;
+ CC |= (B & CC_C);
+ B >>= 1;
+ SET_Z8(B);
+}
+
+/* $55 ILLEGAL */
+
+/* $56 RORB inherent -**-* */
+INLINE void rorb( void )
+{
+ UINT8 r;
+ r = (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (B & CC_C);
+ r |= B >> 1;
+ SET_NZ8(r);
+ B = r;
+}
+
+/* $57 ASRB inherent ?**-* */
+INLINE void asrb( void )
+{
+ CLR_NZC;
+ CC |= (B & CC_C);
+ B= (B & 0x80) | (B >> 1);
+ SET_NZ8(B);
+}
+
+/* $58 ASLB inherent ?**** */
+INLINE void aslb( void )
+{
+ UINT16 r;
+ r = B << 1;
+ CLR_NZVC;
+ SET_FLAGS8(B,B,r);
+ B = r;
+}
+
+/* $59 ROLB inherent -**** */
+INLINE void rolb( void )
+{
+ UINT16 t,r;
+ t = B;
+ r = CC & CC_C;
+ r |= t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ B = r;
+}
+
+/* $5A DECB inherent -***- */
+INLINE void decb( void )
+{
+ --B;
+ CLR_NZV;
+ SET_FLAGS8D(B);
+}
+
+/* $5B ILLEGAL */
+
+/* $5C INCB inherent -***- */
+INLINE void incb( void )
+{
+ ++B;
+ CLR_NZV;
+ SET_FLAGS8I(B);
+}
+
+/* $5D TSTB inherent -**0- */
+INLINE void tstb( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $5E ILLEGAL */
+
+/* $5F CLRB inherent -0100 */
+INLINE void clrb( void )
+{
+ B = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $60 NEG indexed ?**** */
+INLINE void neg_ix( void )
+{
+ UINT16 r,t;
+ t = RM(EAD);
+ r = -t;
+ CLR_NZVC;
+ SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $61 ILLEGAL */
+
+/* $62 ILLEGAL */
+
+/* $63 COM indexed -**01 */
+INLINE void com_ix( void )
+{
+ UINT8 t;
+ t = ~RM(EAD);
+ CLR_NZV;
+ SET_NZ8(t);
+ SEC;
+ WM(EAD,t);
+}
+
+/* $64 LSR indexed -0*-* */
+INLINE void lsr_ix( void )
+{
+ UINT8 t;
+ t = RM(EAD);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t>>=1; SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $65 ILLEGAL */
+
+/* $66 ROR indexed -**-* */
+INLINE void ror_ix( void )
+{
+ UINT8 t,r;
+ t = RM(EAD);
+ r = (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (t & CC_C);
+ r |= t>>1; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $67 ASR indexed ?**-* */
+INLINE void asr_ix( void )
+{
+ UINT8 t;
+ t = RM(EAD);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t=(t&0x80)|(t>>1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $68 ASL indexed ?**** */
+INLINE void asl_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $69 ROL indexed -**** */
+INLINE void rol_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = CC & CC_C;
+ r |= t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $6A DEC indexed -***- */
+INLINE void dec_ix( void )
+{
+ UINT8 t;
+ t = RM(EAD) - 1;
+ CLR_NZV; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $6B ILLEGAL */
+
+/* $6C INC indexed -***- */
+INLINE void inc_ix( void )
+{
+ UINT8 t;
+ t = RM(EAD) + 1;
+ CLR_NZV; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $6D TST indexed -**0- */
+INLINE void tst_ix( void )
+{
+ UINT8 t;
+ t = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(t);
+}
+
+/* $6E JMP indexed ----- */
+INLINE void jmp_ix( void )
+{
+ PCD=EAD;
+ change_pc(PCD);
+}
+
+/* $6F CLR indexed -0100 */
+INLINE void clr_ix( void )
+{
+ WM(EAD,0);
+ CLR_NZVC; SEZ;
+}
+
+/* $70 NEG extended ?**** */
+INLINE void neg_ex( void )
+{
+ UINT16 r,t;
+ EXTBYTE(t); r=-t;
+ CLR_NZVC; SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $71 ILLEGAL */
+
+/* $72 ILLEGAL */
+
+/* $73 COM extended -**01 */
+INLINE void com_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); t = ~t;
+ CLR_NZV; SET_NZ8(t); SEC;
+ WM(EAD,t);
+}
+
+/* $74 LSR extended -0*-* */
+INLINE void lsr_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZC; CC |= (t & CC_C);
+ t>>=1; SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $75 ILLEGAL */
+
+/* $76 ROR extended -**-* */
+INLINE void ror_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t); r=(CC & CC_C) << 7;
+ CLR_NZC; CC |= (t & CC_C);
+ r |= t>>1; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $77 ASR extended ?**-* */
+INLINE void asr_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZC; CC |= (t & CC_C);
+ t=(t&0x80)|(t>>1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $78 ASL extended ?**** */
+INLINE void asl_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r=t<<1;
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $79 ROL extended -**** */
+INLINE void rol_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = (CC & CC_C) | (t << 1);
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $7A DEC extended -***- */
+INLINE void dec_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); --t;
+ CLR_NZV; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $7B ILLEGAL */
+
+/* $7C INC extended -***- */
+INLINE void inc_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); ++t;
+ CLR_NZV; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $7D TST extended -**0- */
+INLINE void tst_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZV; SET_NZ8(t);
+}
+
+/* $7E JMP extended ----- */
+INLINE void jmp_ex( void )
+{
+ EXTENDED;
+ PCD=EAD;
+ change_pc(PCD);
+}
+
+/* $7F CLR extended -0100 */
+INLINE void clr_ex( void )
+{
+ EXTENDED;
+ WM(EAD,0);
+ CLR_NZVC; SEZ;
+}
+
+/* $80 SUBA immediate ?**** */
+INLINE void suba_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $81 CMPA immediate ?**** */
+INLINE void cmpa_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $82 SBCA immediate ?**** */
+INLINE void sbca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $83 SUBD (CMPD CMPU) immediate -**** */
+INLINE void subd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $1083 CMPD immediate -**** */
+INLINE void cmpd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $1183 CMPU immediate -**** */
+INLINE void cmpu_im( void )
+{
+ UINT32 r, d;
+ PAIR b;
+ IMMWORD(b);
+ d = U;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $84 ANDA immediate -**0- */
+INLINE void anda_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A &= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $85 BITA immediate -**0- */
+INLINE void bita_im( void )
+{
+ UINT8 t,r;
+ IMMBYTE(t);
+ r = A & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $86 LDA immediate -**0- */
+INLINE void lda_im( void )
+{
+ IMMBYTE(A);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* is this a legal instruction? */
+/* $87 STA immediate -**0- */
+INLINE void sta_im( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+ IMM8;
+ WM(EAD,A);
+}
+
+/* $88 EORA immediate -**0- */
+INLINE void eora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A ^= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $89 ADCA immediate ***** */
+INLINE void adca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $8A ORA immediate -**0- */
+INLINE void ora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A |= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $8B ADDA immediate ***** */
+INLINE void adda_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $8C CMPX (CMPY CMPS) immediate -**** */
+INLINE void cmpx_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $108C CMPY immediate -**** */
+INLINE void cmpy_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $118C CMPS immediate -**** */
+INLINE void cmps_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $8D BSR ----- */
+INLINE void bsr( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ PUSHWORD(pPC);
+ PC += SIGNED(t);
+ change_pc(PCD);
+}
+
+/* $8E LDX (LDY) immediate -**0- */
+INLINE void ldx_im( void )
+{
+ IMMWORD(pX);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $108E LDY immediate -**0- */
+INLINE void ldy_im( void )
+{
+ IMMWORD(pY);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* is this a legal instruction? */
+/* $8F STX (STY) immediate -**0- */
+INLINE void stx_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ IMM16;
+ WM16(EAD,&pX);
+}
+
+/* is this a legal instruction? */
+/* $108F STY immediate -**0- */
+INLINE void sty_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(Y);
+ IMM16;
+ WM16(EAD,&pY);
+}
+
+/* $90 SUBA direct ?**** */
+INLINE void suba_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $91 CMPA direct ?**** */
+INLINE void cmpa_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $92 SBCA direct ?**** */
+INLINE void sbca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $93 SUBD (CMPD CMPU) direct -**** */
+INLINE void subd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $1093 CMPD direct -**** */
+INLINE void cmpd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $1193 CMPU direct -**** */
+INLINE void cmpu_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = U;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(U,b.d,r);
+}
+
+/* $94 ANDA direct -**0- */
+INLINE void anda_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A &= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $95 BITA direct -**0- */
+INLINE void bita_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r = A & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $96 LDA direct -**0- */
+INLINE void lda_di( void )
+{
+ DIRBYTE(A);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $97 STA direct -**0- */
+INLINE void sta_di( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+ DIRECT;
+ WM(EAD,A);
+}
+
+/* $98 EORA direct -**0- */
+INLINE void eora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A ^= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $99 ADCA direct ***** */
+INLINE void adca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $9A ORA direct -**0- */
+INLINE void ora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A |= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $9B ADDA direct ***** */
+INLINE void adda_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $9C CMPX (CMPY CMPS) direct -**** */
+INLINE void cmpx_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $109C CMPY direct -**** */
+INLINE void cmpy_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $119C CMPS direct -**** */
+INLINE void cmps_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $9D JSR direct ----- */
+INLINE void jsr_di( void )
+{
+ DIRECT;
+ PUSHWORD(pPC);
+ PCD=EAD;
+ change_pc(PCD);
+}
+
+/* $9E LDX (LDY) direct -**0- */
+INLINE void ldx_di( void )
+{
+ DIRWORD(pX);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $109E LDY direct -**0- */
+INLINE void ldy_di( void )
+{
+ DIRWORD(pY);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $9F STX (STY) direct -**0- */
+INLINE void stx_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ DIRECT;
+ WM16(EAD,&pX);
+}
+
+/* $109F STY direct -**0- */
+INLINE void sty_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(Y);
+ DIRECT;
+ WM16(EAD,&pY);
+}
+
+/* $a0 SUBA indexed ?**** */
+INLINE void suba_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a1 CMPA indexed ?**** */
+INLINE void cmpa_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $a2 SBCA indexed ?**** */
+INLINE void sbca_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a3 SUBD (CMPD CMPU) indexed -**** */
+INLINE void subd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ b.d=RM16(EAD);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $10a3 CMPD indexed -**** */
+INLINE void cmpd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ b.d=RM16(EAD);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11a3 CMPU indexed -**** */
+INLINE void cmpu_ix( void )
+{
+ UINT32 r;
+ PAIR b;
+ b.d=RM16(EAD);
+ r = U - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(U,b.d,r);
+}
+
+/* $a4 ANDA indexed -**0- */
+INLINE void anda_ix( void )
+{
+ A &= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $a5 BITA indexed -**0- */
+INLINE void bita_ix( void )
+{
+ UINT8 r;
+ r = A & RM(EAD);
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $a6 LDA indexed -**0- */
+INLINE void lda_ix( void )
+{
+ A = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $a7 STA indexed -**0- */
+INLINE void sta_ix( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+ WM(EAD,A);
+}
+
+/* $a8 EORA indexed -**0- */
+INLINE void eora_ix( void )
+{
+ A ^= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $a9 ADCA indexed ***** */
+INLINE void adca_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $aA ORA indexed -**0- */
+INLINE void ora_ix( void )
+{
+ A |= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $aB ADDA indexed ***** */
+INLINE void adda_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $aC CMPX (CMPY CMPS) indexed -**** */
+INLINE void cmpx_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ b.d=RM16(EAD);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $10aC CMPY indexed -**** */
+INLINE void cmpy_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ b.d=RM16(EAD);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11aC CMPS indexed -**** */
+INLINE void cmps_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ b.d=RM16(EAD);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $aD JSR indexed ----- */
+INLINE void jsr_ix( void )
+{
+ PUSHWORD(pPC);
+ PCD=EAD;
+ change_pc(PCD);
+}
+
+/* $aE LDX (LDY) indexed -**0- */
+INLINE void ldx_ix( void )
+{
+ X=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $10aE LDY indexed -**0- */
+INLINE void ldy_ix( void )
+{
+ Y=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $aF STX (STY) indexed -**0- */
+INLINE void stx_ix( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ WM16(EAD,&pX);
+}
+
+/* $10aF STY indexed -**0- */
+INLINE void sty_ix( void )
+{
+ CLR_NZV;
+ SET_NZ16(Y);
+ WM16(EAD,&pY);
+}
+
+/* $b0 SUBA extended ?**** */
+INLINE void suba_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b1 CMPA extended ?**** */
+INLINE void cmpa_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $b2 SBCA extended ?**** */
+INLINE void sbca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b3 SUBD (CMPD CMPU) extended -**** */
+INLINE void subd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $10b3 CMPD extended -**** */
+INLINE void cmpd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11b3 CMPU extended -**** */
+INLINE void cmpu_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = U;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $b4 ANDA extended -**0- */
+INLINE void anda_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A &= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $b5 BITA extended -**0- */
+INLINE void bita_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t);
+ r = A & t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $b6 LDA extended -**0- */
+INLINE void lda_ex( void )
+{
+ EXTBYTE(A);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $b7 STA extended -**0- */
+INLINE void sta_ex( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+ EXTENDED;
+ WM(EAD,A);
+}
+
+/* $b8 EORA extended -**0- */
+INLINE void eora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A ^= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $b9 ADCA extended ***** */
+INLINE void adca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $bA ORA extended -**0- */
+INLINE void ora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A |= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $bB ADDA extended ***** */
+INLINE void adda_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $bC CMPX (CMPY CMPS) extended -**** */
+INLINE void cmpx_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $10bC CMPY extended -**** */
+INLINE void cmpy_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11bC CMPS extended -**** */
+INLINE void cmps_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $bD JSR extended ----- */
+INLINE void jsr_ex( void )
+{
+ EXTENDED;
+ PUSHWORD(pPC);
+ PCD=EAD;
+ change_pc(PCD);
+}
+
+/* $bE LDX (LDY) extended -**0- */
+INLINE void ldx_ex( void )
+{
+ EXTWORD(pX);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $10bE LDY extended -**0- */
+INLINE void ldy_ex( void )
+{
+ EXTWORD(pY);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $bF STX (STY) extended -**0- */
+INLINE void stx_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ EXTENDED;
+ WM16(EAD,&pX);
+}
+
+/* $10bF STY extended -**0- */
+INLINE void sty_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(Y);
+ EXTENDED;
+ WM16(EAD,&pY);
+}
+
+/* $c0 SUBB immediate ?**** */
+INLINE void subb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $c1 CMPB immediate ?**** */
+INLINE void cmpb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B - t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+}
+
+/* $c2 SBCB immediate ?**** */
+INLINE void sbcb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $c3 ADDD immediate -**** */
+INLINE void addd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $c4 ANDB immediate -**0- */
+INLINE void andb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $c5 BITB immediate -**0- */
+INLINE void bitb_im( void )
+{
+ UINT8 t,r;
+ IMMBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $c6 LDB immediate -**0- */
+INLINE void ldb_im( void )
+{
+ IMMBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* is this a legal instruction? */
+/* $c7 STB immediate -**0- */
+INLINE void stb_im( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+ IMM8;
+ WM(EAD,B);
+}
+
+/* $c8 EORB immediate -**0- */
+INLINE void eorb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ B ^= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $c9 ADCB immediate ***** */
+INLINE void adcb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $cA ORB immediate -**0- */
+INLINE void orb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ B |= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $cB ADDB immediate ***** */
+INLINE void addb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $cC LDD immediate -**0- */
+INLINE void ldd_im( void )
+{
+ IMMWORD(pD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* is this a legal instruction? */
+/* $cD STD immediate -**0- */
+INLINE void std_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+ IMM16;
+ WM16(EAD,&pD);
+}
+
+/* $cE LDU (LDS) immediate -**0- */
+INLINE void ldu_im( void )
+{
+ IMMWORD(pU);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10cE LDS immediate -**0- */
+INLINE void lds_im( void )
+{
+ IMMWORD(pS);
+ CLR_NZV;
+ SET_NZ16(S);
+ konami.int_state |= KONAMI_LDS;
+}
+
+/* is this a legal instruction? */
+/* $cF STU (STS) immediate -**0- */
+INLINE void stu_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(U);
+ IMM16;
+ WM16(EAD,&pU);
+}
+
+/* is this a legal instruction? */
+/* $10cF STS immediate -**0- */
+INLINE void sts_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ IMM16;
+ WM16(EAD,&pS);
+}
+
+/* $d0 SUBB direct ?**** */
+INLINE void subb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $d1 CMPB direct ?**** */
+INLINE void cmpb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+}
+
+/* $d2 SBCB direct ?**** */
+INLINE void sbcb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $d3 ADDD direct -**** */
+INLINE void addd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $d4 ANDB direct -**0- */
+INLINE void andb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $d5 BITB direct -**0- */
+INLINE void bitb_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $d6 LDB direct -**0- */
+INLINE void ldb_di( void )
+{
+ DIRBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $d7 STB direct -**0- */
+INLINE void stb_di( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+ DIRECT;
+ WM(EAD,B);
+}
+
+/* $d8 EORB direct -**0- */
+INLINE void eorb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ B ^= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $d9 ADCB direct ***** */
+INLINE void adcb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $dA ORB direct -**0- */
+INLINE void orb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ B |= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $dB ADDB direct ***** */
+INLINE void addb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $dC LDD direct -**0- */
+INLINE void ldd_di( void )
+{
+ DIRWORD(pD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $dD STD direct -**0- */
+INLINE void std_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+ DIRECT;
+ WM16(EAD,&pD);
+}
+
+/* $dE LDU (LDS) direct -**0- */
+INLINE void ldu_di( void )
+{
+ DIRWORD(pU);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10dE LDS direct -**0- */
+INLINE void lds_di( void )
+{
+ DIRWORD(pS);
+ CLR_NZV;
+ SET_NZ16(S);
+ konami.int_state |= KONAMI_LDS;
+}
+
+/* $dF STU (STS) direct -**0- */
+INLINE void stu_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(U);
+ DIRECT;
+ WM16(EAD,&pU);
+}
+
+/* $10dF STS direct -**0- */
+INLINE void sts_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ DIRECT;
+ WM16(EAD,&pS);
+}
+
+/* $e0 SUBB indexed ?**** */
+INLINE void subb_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $e1 CMPB indexed ?**** */
+INLINE void cmpb_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+}
+
+/* $e2 SBCB indexed ?**** */
+INLINE void sbcb_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $e3 ADDD indexed -**** */
+INLINE void addd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ b.d=RM16(EAD);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $e4 ANDB indexed -**0- */
+INLINE void andb_ix( void )
+{
+ B &= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $e5 BITB indexed -**0- */
+INLINE void bitb_ix( void )
+{
+ UINT8 r;
+ r = B & RM(EAD);
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $e6 LDB indexed -**0- */
+INLINE void ldb_ix( void )
+{
+ B = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $e7 STB indexed -**0- */
+INLINE void stb_ix( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+ WM(EAD,B);
+}
+
+/* $e8 EORB indexed -**0- */
+INLINE void eorb_ix( void )
+{
+ B ^= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $e9 ADCB indexed ***** */
+INLINE void adcb_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $eA ORB indexed -**0- */
+INLINE void orb_ix( void )
+{
+ B |= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $eb ADDB indexed ***** */
+INLINE void addb_ix( void )
+{
+ UINT16 t,r;
+ t = RM(EAD);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $ec LDD indexed -**0- */
+INLINE void ldd_ix( void )
+{
+ D=RM16(EAD);
+ CLR_NZV; SET_NZ16(D);
+}
+
+/* $eD STD indexed -**0- */
+INLINE void std_ix( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+ WM16(EAD,&pD);
+}
+
+/* $eE LDU (LDS) indexed -**0- */
+INLINE void ldu_ix( void )
+{
+ U=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10eE LDS indexed -**0- */
+INLINE void lds_ix( void )
+{
+ S=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(S);
+ konami.int_state |= KONAMI_LDS;
+}
+
+/* $eF STU (STS) indexed -**0- */
+INLINE void stu_ix( void )
+{
+ CLR_NZV;
+ SET_NZ16(U);
+ WM16(EAD,&pU);
+}
+
+/* $10eF STS indexed -**0- */
+INLINE void sts_ix( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ WM16(EAD,&pS);
+}
+
+/* $f0 SUBB extended ?**** */
+INLINE void subb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $f1 CMPB extended ?**** */
+INLINE void cmpb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+}
+
+/* $f2 SBCB extended ?**** */
+INLINE void sbcb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $f3 ADDD extended -**** */
+INLINE void addd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $f4 ANDB extended -**0- */
+INLINE void andb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $f5 BITB extended -**0- */
+INLINE void bitb_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $f6 LDB extended -**0- */
+INLINE void ldb_ex( void )
+{
+ EXTBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $f7 STB extended -**0- */
+INLINE void stb_ex( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+ EXTENDED;
+ WM(EAD,B);
+}
+
+/* $f8 EORB extended -**0- */
+INLINE void eorb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B ^= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $f9 ADCB extended ***** */
+INLINE void adcb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $fA ORB extended -**0- */
+INLINE void orb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B |= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $fB ADDB extended ***** */
+INLINE void addb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $fC LDD extended -**0- */
+INLINE void ldd_ex( void )
+{
+ EXTWORD(pD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $fD STD extended -**0- */
+INLINE void std_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+ EXTENDED;
+ WM16(EAD,&pD);
+}
+
+/* $fE LDU (LDS) extended -**0- */
+INLINE void ldu_ex( void )
+{
+ EXTWORD(pU);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10fE LDS extended -**0- */
+INLINE void lds_ex( void )
+{
+ EXTWORD(pS);
+ CLR_NZV;
+ SET_NZ16(S);
+ konami.int_state |= KONAMI_LDS;
+}
+
+/* $fF STU (STS) extended -**0- */
+INLINE void stu_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(U);
+ EXTENDED;
+ WM16(EAD,&pU);
+}
+
+/* $10fF STS extended -**0- */
+INLINE void sts_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ EXTENDED;
+ WM16(EAD,&pS);
+}
+
+INLINE void setline_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+
+ if ( konami.setlines_callback )
+ (*konami.setlines_callback)( t );
+}
+
+INLINE void setline_ix( void )
+{
+ UINT8 t;
+ t = RM(EA);
+
+ if ( konami.setlines_callback )
+ (*konami.setlines_callback)( t );
+}
+
+INLINE void setline_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+
+ if ( konami.setlines_callback )
+ (*konami.setlines_callback)( t );
+}
+
+INLINE void setline_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+
+ if ( konami.setlines_callback )
+ (*konami.setlines_callback)( t );
+}
+
+INLINE void bmove( void )
+{
+ UINT8 t;
+
+ while( U != 0 ) {
+ t = RM(Y);
+ WM(X,t);
+ Y++;
+ X++;
+ U--;
+ konami_ICount -= 2;
+ }
+}
+
+INLINE void move( void )
+{
+ UINT8 t;
+
+ t = RM(Y);
+ WM(X,t);
+ Y++;
+ X++;
+ U--;
+}
+
+/* CLRD inherent -0100 */
+INLINE void clrd( void )
+{
+ D = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* CLRW indexed -0100 */
+INLINE void clrw_ix( void )
+{
+ PAIR t;
+ t.d = 0;
+ WM16(EAD,&t);
+ CLR_NZVC; SEZ;
+}
+
+/* CLRW direct -0100 */
+INLINE void clrw_di( void )
+{
+ PAIR t;
+ t.d = 0;
+ DIRECT;
+ WM16(EAD,&t);
+ CLR_NZVC;
+ SEZ;
+}
+
+/* CLRW extended -0100 */
+INLINE void clrw_ex( void )
+{
+ PAIR t;
+ t.d = 0;
+ EXTENDED;
+ WM16(EAD,&t);
+ CLR_NZVC; SEZ;
+}
+
+/* LSRD immediate -0*-* */
+INLINE void lsrd( void )
+{
+ UINT8 t;
+
+ IMMBYTE( t );
+
+ while ( t-- ) {
+ CLR_NZC;
+ CC |= (D & CC_C);
+ D >>= 1;
+ SET_Z16(D);
+ }
+}
+
+/* RORD immediate -**-* */
+INLINE void rord( void )
+{
+ UINT16 r;
+ UINT8 t;
+
+ IMMBYTE(t);
+
+ while ( t-- ) {
+ r = (CC & CC_C) << 15;
+ CLR_NZC;
+ CC |= (D & CC_C);
+ r |= D >> 1;
+ SET_NZ16(r);
+ D = r;
+ }
+}
+
+/* ASRD immediate ?**-* */
+INLINE void asrd( void )
+{
+ UINT8 t;
+
+ IMMBYTE(t);
+
+ while ( t-- ) {
+ CLR_NZC;
+ CC |= (D & CC_C);
+ D = (D & 0x8000) | (D >> 1);
+ SET_NZ16(D);
+ }
+}
+
+/* ASLD immediate ?**** */
+INLINE void asld( void )
+{
+ UINT32 r;
+ UINT8 t;
+
+ IMMBYTE( t );
+
+ while ( t-- ) {
+ r = D << 1;
+ CLR_NZVC;
+ SET_FLAGS16(D,D,r);
+ D = r;
+ }
+}
+
+/* ROLD immediate -**-* */
+INLINE void rold( void )
+{
+ UINT16 r;
+ UINT8 t;
+
+ IMMBYTE(t);
+
+ while ( t-- ) {
+ CLR_NZC;
+ if ( D & 0x8000 ) SEC;
+ r = CC & CC_C;
+ r |= D << 1;
+ SET_NZ16(r);
+ D = r;
+ }
+}
+
+/* DECB,JNZ relative ----- */
+INLINE void decbjnz( void )
+{
+ --B;
+ CLR_NZV;
+ SET_FLAGS8D(B);
+ BRANCH( !(CC&CC_Z) );
+}
+
+/* DECX,JNZ relative ----- */
+INLINE void decxjnz( void )
+{
+ --X;
+ CLR_NZV;
+ SET_NZ16(X); /* should affect V as well? */
+ BRANCH( !(CC&CC_Z) );
+}
+
+INLINE void bset( void )
+{
+ UINT8 t;
+
+ while( U != 0 ) {
+ t = A;
+ WM(XD,t);
+ X++;
+ U--;
+ konami_ICount -= 2;
+ }
+}
+
+INLINE void bset2( void )
+{
+ while( U != 0 ) {
+ WM16(XD,&pD);
+ X += 2;
+ U--;
+ konami_ICount -= 3;
+ }
+}
+
+/* LMUL inherent --*-@ */
+INLINE void lmul( void )
+{
+ UINT32 t;
+ t = X * Y;
+ X = (t >> 16);
+ Y = (t & 0xffff);
+ CLR_ZC; SET_Z(t); if( t & 0x8000 ) SEC;
+}
+
+/* DIVX inherent --*-@ */
+INLINE void divx( void )
+{
+ UINT16 t;
+ UINT8 r;
+ if ( B != 0 )
+ {
+ t = X / B;
+ r = X % B;
+ }
+ else
+ {
+ /* ?? */
+ t = 0;
+ r = 0;
+ }
+ CLR_ZC; SET_Z16(t); if ( t & 0x80 ) SEC;
+ X = t;
+ B = r;
+}
+
+/* INCD inherent -***- */
+INLINE void incd( void )
+{
+ UINT32 r;
+ r = D + 1;
+ CLR_NZV;
+ SET_FLAGS16(D,D,r);
+ D = r;
+}
+
+/* INCW direct -***- */
+INLINE void incw_di( void )
+{
+ PAIR t,r;
+ DIRWORD(t);
+ r = t;
+ ++r.d;
+ CLR_NZV;
+ SET_FLAGS16(t.d, t.d, r.d);
+ WM16(EAD,&r);
+}
+
+/* INCW indexed -***- */
+INLINE void incw_ix( void )
+{
+ PAIR t,r;
+ t.d=RM16(EAD);
+ r = t;
+ ++r.d;
+ CLR_NZV;
+ SET_FLAGS16(t.d, t.d, r.d);
+ WM16(EAD,&r);
+}
+
+/* INCW extended -***- */
+INLINE void incw_ex( void )
+{
+ PAIR t, r;
+ EXTWORD(t);
+ r = t;
+ ++r.d;
+ CLR_NZV; SET_FLAGS16(t.d,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* DECD inherent -***- */
+INLINE void decd( void )
+{
+ UINT32 r;
+ r = D - 1;
+ CLR_NZV;
+ SET_FLAGS16(D,D,r);
+ D = r;
+}
+
+/* DECW direct -***- */
+INLINE void decw_di( void )
+{
+ PAIR t,r;
+ DIRWORD(t);
+ r = t;
+ --r.d;
+ CLR_NZV;
+ SET_FLAGS16(t.d, t.d, r.d);
+ WM16(EAD,&r);
+}
+
+/* DECW indexed -***- */
+INLINE void decw_ix( void )
+{
+ PAIR t, r;
+ t.d=RM16(EAD);
+ r = t;
+ --r.d;
+ CLR_NZV; SET_FLAGS16(t.d, t.d, r.d);
+ WM16(EAD,&r);
+}
+
+/* DECW extended -***- */
+INLINE void decw_ex( void )
+{
+ PAIR t, r;
+ EXTWORD(t);
+ r = t;
+ --r.d;
+ CLR_NZV; SET_FLAGS16(t.d,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* TSTD inherent -**0- */
+INLINE void tstd( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* TSTW direct -**0- */
+INLINE void tstw_di( void )
+{
+ PAIR t;
+ CLR_NZV;
+ DIRWORD(t);
+ SET_NZ16(t.d);
+}
+
+/* TSTW indexed -**0- */
+INLINE void tstw_ix( void )
+{
+ PAIR t;
+ CLR_NZV;
+ t.d=RM16(EAD);
+ SET_NZ16(t.d);
+}
+
+/* TSTW extended -**0- */
+INLINE void tstw_ex( void )
+{
+ PAIR t;
+ CLR_NZV;
+ EXTWORD(t);
+ SET_NZ16(t.d);
+}
+
+/* LSRW direct -0*-* */
+INLINE void lsrw_di( void )
+{
+ PAIR t;
+ DIRWORD(t);
+ CLR_NZC;
+ CC |= (t.d & CC_C);
+ t.d >>= 1;
+ SET_Z16(t.d);
+ WM16(EAD,&t);
+}
+
+/* LSRW indexed -0*-* */
+INLINE void lsrw_ix( void )
+{
+ PAIR t;
+ t.d=RM16(EAD);
+ CLR_NZC;
+ CC |= (t.d & CC_C);
+ t.d >>= 1;
+ SET_Z16(t.d);
+ WM16(EAD,&t);
+}
+
+/* LSRW extended -0*-* */
+INLINE void lsrw_ex( void )
+{
+ PAIR t;
+ EXTWORD(t);
+ CLR_NZC;
+ CC |= (t.d & CC_C);
+ t.d >>= 1;
+ SET_Z16(t.d);
+ WM16(EAD,&t);
+}
+
+/* RORW direct -**-* */
+INLINE void rorw_di( void )
+{
+ PAIR t,r;
+ DIRWORD(t);
+ r.d = (CC & CC_C) << 15;
+ CLR_NZC;
+ CC |= (t.d & CC_C);
+ r.d |= t.d>>1;
+ SET_NZ16(r.d);
+ WM16(EAD,&r);
+}
+
+/* RORW indexed -**-* */
+INLINE void rorw_ix( void )
+{
+ PAIR t,r;
+ t.d=RM16(EAD);
+ r.d = (CC & CC_C) << 15;
+ CLR_NZC;
+ CC |= (t.d & CC_C);
+ r.d |= t.d>>1;
+ SET_NZ16(r.d);
+ WM16(EAD,&r);
+}
+
+/* RORW extended -**-* */
+INLINE void rorw_ex( void )
+{
+ PAIR t,r;
+ EXTWORD(t);
+ r.d = (CC & CC_C) << 15;
+ CLR_NZC;
+ CC |= (t.d & CC_C);
+ r.d |= t.d>>1;
+ SET_NZ16(r.d);
+ WM16(EAD,&r);
+}
+
+/* ASRW direct ?**-* */
+INLINE void asrw_di( void )
+{
+ PAIR t;
+ DIRWORD(t);
+ CLR_NZC;
+ CC |= (t.d & CC_C);
+ t.d = (t.d & 0x8000) | (t.d >> 1);
+ SET_NZ16(t.d);
+ WM16(EAD,&t);
+}
+
+/* ASRW indexed ?**-* */
+INLINE void asrw_ix( void )
+{
+ PAIR t;
+ t.d=RM16(EAD);
+ CLR_NZC;
+ CC |= (t.d & CC_C);
+ t.d = (t.d & 0x8000) | (t.d >> 1);
+ SET_NZ16(t.d);
+ WM16(EAD,&t);
+}
+
+/* ASRW extended ?**-* */
+INLINE void asrw_ex( void )
+{
+ PAIR t;
+ EXTWORD(t);
+ CLR_NZC;
+ CC |= (t.d & CC_C);
+ t.d = (t.d & 0x8000) | (t.d >> 1);
+ SET_NZ16(t.d);
+ WM16(EAD,&t);
+}
+
+/* ASLW direct ?**** */
+INLINE void aslw_di( void )
+{
+ PAIR t,r;
+ DIRWORD(t);
+ r.d = t.d << 1;
+ CLR_NZVC;
+ SET_FLAGS16(t.d,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* ASLW indexed ?**** */
+INLINE void aslw_ix( void )
+{
+ PAIR t,r;
+ t.d=RM16(EAD);
+ r.d = t.d << 1;
+ CLR_NZVC;
+ SET_FLAGS16(t.d,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* ASLW extended ?**** */
+INLINE void aslw_ex( void )
+{
+ PAIR t,r;
+ EXTWORD(t);
+ r.d = t.d << 1;
+ CLR_NZVC;
+ SET_FLAGS16(t.d,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* ROLW direct -**** */
+INLINE void rolw_di( void )
+{
+ PAIR t,r;
+ DIRWORD(t);
+ r.d = (CC & CC_C) | (t.d << 1);
+ CLR_NZVC;
+ SET_FLAGS16(t.d,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* ROLW indexed -**** */
+INLINE void rolw_ix( void )
+{
+ PAIR t,r;
+ t.d=RM16(EAD);
+ r.d = (CC & CC_C) | (t.d << 1);
+ CLR_NZVC;
+ SET_FLAGS16(t.d,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* ROLW extended -**** */
+INLINE void rolw_ex( void )
+{
+ PAIR t,r;
+ EXTWORD(t);
+ r.d = (CC & CC_C) | (t.d << 1);
+ CLR_NZVC;
+ SET_FLAGS16(t.d,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* NEGD inherent ?**** */
+INLINE void negd( void )
+{
+ UINT32 r;
+ r = -D;
+ CLR_NZVC;
+ SET_FLAGS16(0,D,r);
+ D = r;
+}
+
+/* NEGW direct ?**** */
+INLINE void negw_di( void )
+{
+ PAIR r,t;
+ DIRWORD(t);
+ r.d = -t.d;
+ CLR_NZVC;
+ SET_FLAGS16(0,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* NEGW indexed ?**** */
+INLINE void negw_ix( void )
+{
+ PAIR r,t;
+ t.d=RM16(EAD);
+ r.d = -t.d;
+ CLR_NZVC;
+ SET_FLAGS16(0,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* NEGW extended ?**** */
+INLINE void negw_ex( void )
+{
+ PAIR r,t;
+ EXTWORD(t);
+ r.d = -t.d;
+ CLR_NZVC;
+ SET_FLAGS16(0,t.d,r.d);
+ WM16(EAD,&r);
+}
+
+/* ABSA inherent ?**** */
+INLINE void absa( void )
+{
+ UINT16 r;
+ if (A & 0x80)
+ r = -A;
+ else
+ r = A;
+ CLR_NZVC;
+ SET_FLAGS8(0,A,r);
+ A = r;
+}
+
+/* ABSB inherent ?**** */
+INLINE void absb( void )
+{
+ UINT16 r;
+ if (B & 0x80)
+ r = -B;
+ else
+ r = B;
+ CLR_NZVC;
+ SET_FLAGS8(0,B,r);
+ B = r;
+}
+
+/* ABSD inherent ?**** */
+INLINE void absd( void )
+{
+ UINT32 r;
+ if (D & 0x8000)
+ r = -D;
+ else
+ r = D;
+ CLR_NZVC;
+ SET_FLAGS16(0,D,r);
+ D = r;
+}
+
+/* LSRD direct -0*-* */
+INLINE void lsrd_di( void )
+{
+ UINT8 t;
+
+ DIRBYTE( t );
+
+ while ( t-- ) {
+ CLR_NZC;
+ CC |= (D & CC_C);
+ D >>= 1;
+ SET_Z16(D);
+ }
+}
+
+/* RORD direct -**-* */
+INLINE void rord_di( void )
+{
+ UINT16 r;
+ UINT8 t;
+
+ DIRBYTE(t);
+
+ while ( t-- ) {
+ r = (CC & CC_C) << 15;
+ CLR_NZC;
+ CC |= (D & CC_C);
+ r |= D >> 1;
+ SET_NZ16(r);
+ D = r;
+ }
+}
+
+/* ASRD direct ?**-* */
+INLINE void asrd_di( void )
+{
+ UINT8 t;
+
+ DIRBYTE(t);
+
+ while ( t-- ) {
+ CLR_NZC;
+ CC |= (D & CC_C);
+ D = (D & 0x8000) | (D >> 1);
+ SET_NZ16(D);
+ }
+}
+
+/* ASLD direct ?**** */
+INLINE void asld_di( void )
+{
+ UINT32 r;
+ UINT8 t;
+
+ DIRBYTE( t );
+
+ while ( t-- ) {
+ r = D << 1;
+ CLR_NZVC;
+ SET_FLAGS16(D,D,r);
+ D = r;
+ }
+}
+
+/* ROLD direct -**-* */
+INLINE void rold_di( void )
+{
+ UINT16 r;
+ UINT8 t;
+
+ DIRBYTE(t);
+
+ while ( t-- ) {
+ CLR_NZC;
+ if ( D & 0x8000 ) SEC;
+ r = CC & CC_C;
+ r |= D << 1;
+ SET_NZ16(r);
+ D = r;
+ }
+}
+
+/* LSRD indexed -0*-* */
+INLINE void lsrd_ix( void )
+{
+ UINT8 t;
+
+ t=RM(EA);
+
+ while ( t-- ) {
+ CLR_NZC;
+ CC |= (D & CC_C);
+ D >>= 1;
+ SET_Z16(D);
+ }
+}
+
+/* RORD indexed -**-* */
+INLINE void rord_ix( void )
+{
+ UINT16 r;
+ UINT8 t;
+
+ t=RM(EA);
+
+ while ( t-- ) {
+ r = (CC & CC_C) << 15;
+ CLR_NZC;
+ CC |= (D & CC_C);
+ r |= D >> 1;
+ SET_NZ16(r);
+ D = r;
+ }
+}
+
+/* ASRD indexed ?**-* */
+INLINE void asrd_ix( void )
+{
+ UINT8 t;
+
+ t=RM(EA);
+
+ while ( t-- ) {
+ CLR_NZC;
+ CC |= (D & CC_C);
+ D = (D & 0x8000) | (D >> 1);
+ SET_NZ16(D);
+ }
+}
+
+/* ASLD indexed ?**** */
+INLINE void asld_ix( void )
+{
+ UINT32 r;
+ UINT8 t;
+
+ t=RM(EA);
+
+ while ( t-- ) {
+ r = D << 1;
+ CLR_NZVC;
+ SET_FLAGS16(D,D,r);
+ D = r;
+ }
+}
+
+/* ROLD indexed -**-* */
+INLINE void rold_ix( void )
+{
+ UINT16 r;
+ UINT8 t;
+
+ t=RM(EA);
+
+ while ( t-- ) {
+ CLR_NZC;
+ if ( D & 0x8000 ) SEC;
+ r = CC & CC_C;
+ r |= D << 1;
+ SET_NZ16(r);
+ D = r;
+ }
+}
+
+/* LSRD extended -0*-* */
+INLINE void lsrd_ex( void )
+{
+ UINT8 t;
+
+ EXTBYTE(t);
+
+ while ( t-- ) {
+ CLR_NZC;
+ CC |= (D & CC_C);
+ D >>= 1;
+ SET_Z16(D);
+ }
+}
+
+/* RORD extended -**-* */
+INLINE void rord_ex( void )
+{
+ UINT16 r;
+ UINT8 t;
+
+ EXTBYTE(t);
+
+ while ( t-- ) {
+ r = (CC & CC_C) << 15;
+ CLR_NZC;
+ CC |= (D & CC_C);
+ r |= D >> 1;
+ SET_NZ16(r);
+ D = r;
+ }
+}
+
+/* ASRD extended ?**-* */
+INLINE void asrd_ex( void )
+{
+ UINT8 t;
+
+ EXTBYTE(t);
+
+ while ( t-- ) {
+ CLR_NZC;
+ CC |= (D & CC_C);
+ D = (D & 0x8000) | (D >> 1);
+ SET_NZ16(D);
+ }
+}
+
+/* ASLD extended ?**** */
+INLINE void asld_ex( void )
+{
+ UINT32 r;
+ UINT8 t;
+
+ EXTBYTE(t);
+
+ while ( t-- ) {
+ r = D << 1;
+ CLR_NZVC;
+ SET_FLAGS16(D,D,r);
+ D = r;
+ }
+}
+
+/* ROLD extended -**-* */
+INLINE void rold_ex( void )
+{
+ UINT16 r;
+ UINT8 t;
+
+ EXTBYTE(t);
+
+ while ( t-- ) {
+ CLR_NZC;
+ if ( D & 0x8000 ) SEC;
+ r = CC & CC_C;
+ r |= D << 1;
+ SET_NZ16(r);
+ D = r;
+ }
+}
+
+INLINE void opcode2( void )
+{
+ UINT8 ireg2 = ROP_ARG(PCD);
+ PC++;
+
+ switch ( ireg2 ) {
+// case 0x00: EA=0; break; /* auto increment */
+// case 0x01: EA=0; break; /* double auto increment */
+// case 0x02: EA=0; break; /* auto decrement */
+// case 0x03: EA=0; break; /* double auto decrement */
+// case 0x04: EA=0; break; /* postbyte offs */
+// case 0x05: EA=0; break; /* postword offs */
+// case 0x06: EA=0; break; /* normal */
+ case 0x07:
+ EAD=0;
+ (*konami_extended[konami.ireg])();
+ konami_ICount -= 2;
+ return;
+// case 0x08: EA=0; break; /* indirect - auto increment */
+// case 0x09: EA=0; break; /* indirect - double auto increment */
+// case 0x0a: EA=0; break; /* indirect - auto decrement */
+// case 0x0b: EA=0; break; /* indirect - double auto decrement */
+// case 0x0c: EA=0; break; /* indirect - postbyte offs */
+// case 0x0d: EA=0; break; /* indirect - postword offs */
+// case 0x0e: EA=0; break; /* indirect - normal */
+ case 0x0f: /* indirect - extended */
+ IMMWORD(ea);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+// case 0x10: EA=0; break; /* auto increment */
+// case 0x11: EA=0; break; /* double auto increment */
+// case 0x12: EA=0; break; /* auto decrement */
+// case 0x13: EA=0; break; /* double auto decrement */
+// case 0x14: EA=0; break; /* postbyte offs */
+// case 0x15: EA=0; break; /* postword offs */
+// case 0x16: EA=0; break; /* normal */
+// case 0x17: EA=0; break; /* extended */
+// case 0x18: EA=0; break; /* indirect - auto increment */
+// case 0x19: EA=0; break; /* indirect - double auto increment */
+// case 0x1a: EA=0; break; /* indirect - auto decrement */
+// case 0x1b: EA=0; break; /* indirect - double auto decrement */
+// case 0x1c: EA=0; break; /* indirect - postbyte offs */
+// case 0x1d: EA=0; break; /* indirect - postword offs */
+// case 0x1e: EA=0; break; /* indirect - normal */
+// case 0x1f: EA=0; break; /* indirect - extended */
+
+/* base X */
+ case 0x20: /* auto increment */
+ EA=X;
+ X++;
+ konami_ICount-=2;
+ break;
+ case 0x21: /* double auto increment */
+ EA=X;
+ X+=2;
+ konami_ICount-=3;
+ break;
+ case 0x22: /* auto decrement */
+ X--;
+ EA=X;
+ konami_ICount-=2;
+ break;
+ case 0x23: /* double auto decrement */
+ X-=2;
+ EA=X;
+ konami_ICount-=3;
+ break;
+ case 0x24: /* postbyte offs */
+ IMMBYTE(EA);
+ EA=X+SIGNED(EA);
+ konami_ICount-=2;
+ break;
+ case 0x25: /* postword offs */
+ IMMWORD(ea);
+ EA+=X;
+ konami_ICount-=4;
+ break;
+ case 0x26: /* normal */
+ EA=X;
+ break;
+// case 0x27: EA=0; break; /* extended */
+ case 0x28: /* indirect - auto increment */
+ EA=X;
+ X++;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x29: /* indirect - double auto increment */
+ EA=X;
+ X+=2;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x2a: /* indirect - auto decrement */
+ X--;
+ EA=X;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x2b: /* indirect - double auto decrement */
+ X-=2;
+ EA=X;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x2c: /* indirect - postbyte offs */
+ IMMBYTE(EA);
+ EA=X+SIGNED(EA);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0x2d: /* indirect - postword offs */
+ IMMWORD(ea);
+ EA+=X;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+ case 0x2e: /* indirect - normal */
+ EA=X;
+ EA=RM16(EAD);
+ konami_ICount-=3;
+ break;
+// case 0x2f: EA=0; break; /* indirect - extended */
+
+/* base Y */
+ case 0x30: /* auto increment */
+ EA=Y;
+ Y++;
+ konami_ICount-=2;
+ break;
+ case 0x31: /* double auto increment */
+ EA=Y;
+ Y+=2;
+ konami_ICount-=3;
+ break;
+ case 0x32: /* auto decrement */
+ Y--;
+ EA=Y;
+ konami_ICount-=2;
+ break;
+ case 0x33: /* double auto decrement */
+ Y-=2;
+ EA=Y;
+ konami_ICount-=3;
+ break;
+ case 0x34: /* postbyte offs */
+ IMMBYTE(EA);
+ EA=Y+SIGNED(EA);
+ konami_ICount-=2;
+ break;
+ case 0x35: /* postword offs */
+ IMMWORD(ea);
+ EA+=Y;
+ konami_ICount-=4;
+ break;
+ case 0x36: /* normal */
+ EA=Y;
+ break;
+// case 0x37: EA=0; break; /* extended */
+ case 0x38: /* indirect - auto increment */
+ EA=Y;
+ Y++;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x39: /* indirect - double auto increment */
+ EA=Y;
+ Y+=2;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x3a: /* indirect - auto decrement */
+ Y--;
+ EA=Y;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x3b: /* indirect - double auto decrement */
+ Y-=2;
+ EA=Y;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x3c: /* indirect - postbyte offs */
+ IMMBYTE(EA);
+ EA=Y+SIGNED(EA);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0x3d: /* indirect - postword offs */
+ IMMWORD(ea);
+ EA+=Y;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+ case 0x3e: /* indirect - normal */
+ EA=Y;
+ EA=RM16(EAD);
+ konami_ICount-=3;
+ break;
+// case 0x3f: EA=0; break; /* indirect - extended */
+
+// case 0x40: EA=0; break; /* auto increment */
+// case 0x41: EA=0; break; /* double auto increment */
+// case 0x42: EA=0; break; /* auto decrement */
+// case 0x43: EA=0; break; /* double auto decrement */
+// case 0x44: EA=0; break; /* postbyte offs */
+// case 0x45: EA=0; break; /* postword offs */
+// case 0x46: EA=0; break; /* normal */
+// case 0x47: EA=0; break; /* extended */
+// case 0x48: EA=0; break; /* indirect - auto increment */
+// case 0x49: EA=0; break; /* indirect - double auto increment */
+// case 0x4a: EA=0; break; /* indirect - auto decrement */
+// case 0x4b: EA=0; break; /* indirect - double auto decrement */
+// case 0x4c: EA=0; break; /* indirect - postbyte offs */
+// case 0x4d: EA=0; break; /* indirect - postword offs */
+// case 0x4e: EA=0; break; /* indirect - normal */
+// case 0x4f: EA=0; break; /* indirect - extended */
+
+/* base U */
+ case 0x50: /* auto increment */
+ EA=U;
+ U++;
+ konami_ICount-=2;
+ break;
+ case 0x51: /* double auto increment */
+ EA=U;
+ U+=2;
+ konami_ICount-=3;
+ break;
+ case 0x52: /* auto decrement */
+ U--;
+ EA=U;
+ konami_ICount-=2;
+ break;
+ case 0x53: /* double auto decrement */
+ U-=2;
+ EA=U;
+ konami_ICount-=3;
+ break;
+ case 0x54: /* postbyte offs */
+ IMMBYTE(EA);
+ EA=U+SIGNED(EA);
+ konami_ICount-=2;
+ break;
+ case 0x55: /* postword offs */
+ IMMWORD(ea);
+ EA+=U;
+ konami_ICount-=4;
+ break;
+ case 0x56: /* normal */
+ EA=U;
+ break;
+// case 0x57: EA=0; break; /* extended */
+ case 0x58: /* indirect - auto increment */
+ EA=U;
+ U++;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x59: /* indirect - double auto increment */
+ EA=U;
+ U+=2;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x5a: /* indirect - auto decrement */
+ U--;
+ EA=U;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x5b: /* indirect - double auto decrement */
+ U-=2;
+ EA=U;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x5c: /* indirect - postbyte offs */
+ IMMBYTE(EA);
+ EA=U+SIGNED(EA);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0x5d: /* indirect - postword offs */
+ IMMWORD(ea);
+ EA+=U;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+ case 0x5e: /* indirect - normal */
+ EA=U;
+ EA=RM16(EAD);
+ konami_ICount-=3;
+ break;
+// case 0x5f: EA=0; break; /* indirect - extended */
+
+/* base S */
+ case 0x60: /* auto increment */
+ EAD=SD;
+ S++;
+ konami_ICount-=2;
+ break;
+ case 0x61: /* double auto increment */
+ EAD=SD;
+ S+=2;
+ konami_ICount-=3;
+ break;
+ case 0x62: /* auto decrement */
+ S--;
+ EAD=SD;
+ konami_ICount-=2;
+ break;
+ case 0x63: /* double auto decrement */
+ S-=2;
+ EAD=SD;
+ konami_ICount-=3;
+ break;
+ case 0x64: /* postbyte offs */
+ IMMBYTE(EA);
+ EA=S+SIGNED(EA);
+ konami_ICount-=2;
+ break;
+ case 0x65: /* postword offs */
+ IMMWORD(ea);
+ EA+=S;
+ konami_ICount-=4;
+ break;
+ case 0x66: /* normal */
+ EAD=SD;
+ break;
+// case 0x67: EA=0; break; /* extended */
+ case 0x68: /* indirect - auto increment */
+ EAD=SD;
+ S++;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x69: /* indirect - double auto increment */
+ EAD=SD;
+ S+=2;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x6a: /* indirect - auto decrement */
+ S--;
+ EAD=SD;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x6b: /* indirect - double auto decrement */
+ S-=2;
+ EAD=SD;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x6c: /* indirect - postbyte offs */
+ IMMBYTE(EA);
+ EA=S+SIGNED(EA);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0x6d: /* indirect - postword offs */
+ IMMWORD(ea);
+ EA+=S;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+ case 0x6e: /* indirect - normal */
+ EAD=SD;
+ EA=RM16(EAD);
+ konami_ICount-=3;
+ break;
+// case 0x6f: EA=0; break; /* indirect - extended */
+
+/* base PC */
+ case 0x70: /* auto increment */
+ EAD=PCD;
+ PC++;
+ konami_ICount-=2;
+ break;
+ case 0x71: /* double auto increment */
+ EAD=PCD;
+ PC+=2;
+ konami_ICount-=3;
+ break;
+ case 0x72: /* auto decrement */
+ PC--;
+ EAD=PCD;
+ konami_ICount-=2;
+ break;
+ case 0x73: /* double auto decrement */
+ PC-=2;
+ EAD=PCD;
+ konami_ICount-=3;
+ break;
+ case 0x74: /* postbyte offs */
+ IMMBYTE(EA);
+ EA=PC-1+SIGNED(EA);
+ konami_ICount-=2;
+ break;
+ case 0x75: /* postword offs */
+ IMMWORD(ea);
+ EA+=PC-2;
+ konami_ICount-=4;
+ break;
+ case 0x76: /* normal */
+ EAD=PCD;
+ break;
+// case 0x77: EA=0; break; /* extended */
+ case 0x78: /* indirect - auto increment */
+ EAD=PCD;
+ PC++;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x79: /* indirect - double auto increment */
+ EAD=PCD;
+ PC+=2;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x7a: /* indirect - auto decrement */
+ PC--;
+ EAD=PCD;
+ EA=RM16(EAD);
+ konami_ICount-=5;
+ break;
+ case 0x7b: /* indirect - double auto decrement */
+ PC-=2;
+ EAD=PCD;
+ EA=RM16(EAD);
+ konami_ICount-=6;
+ break;
+ case 0x7c: /* indirect - postbyte offs */
+ IMMBYTE(EA);
+ EA=PC-1+SIGNED(EA);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0x7d: /* indirect - postword offs */
+ IMMWORD(ea);
+ EA+=PC-2;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+ case 0x7e: /* indirect - normal */
+ EAD=PCD;
+ EA=RM16(EAD);
+ konami_ICount-=3;
+ break;
+// case 0x7f: EA=0; break; /* indirect - extended */
+
+// case 0x80: EA=0; break; /* register a */
+// case 0x81: EA=0; break; /* register b */
+// case 0x82: EA=0; break; /* ???? */
+// case 0x83: EA=0; break; /* ???? */
+// case 0x84: EA=0; break; /* ???? */
+// case 0x85: EA=0; break; /* ???? */
+// case 0x86: EA=0; break; /* ???? */
+// case 0x87: EA=0; break; /* register d */
+// case 0x88: EA=0; break; /* indirect - register a */
+// case 0x89: EA=0; break; /* indirect - register b */
+// case 0x8a: EA=0; break; /* indirect - ???? */
+// case 0x8b: EA=0; break; /* indirect - ???? */
+// case 0x8c: EA=0; break; /* indirect - ???? */
+// case 0x8d: EA=0; break; /* indirect - ???? */
+// case 0x8e: EA=0; break; /* indirect - register d */
+// case 0x8f: EA=0; break; /* indirect - ???? */
+// case 0x90: EA=0; break; /* register a */
+// case 0x91: EA=0; break; /* register b */
+// case 0x92: EA=0; break; /* ???? */
+// case 0x93: EA=0; break; /* ???? */
+// case 0x94: EA=0; break; /* ???? */
+// case 0x95: EA=0; break; /* ???? */
+// case 0x96: EA=0; break; /* ???? */
+// case 0x97: EA=0; break; /* register d */
+// case 0x98: EA=0; break; /* indirect - register a */
+// case 0x99: EA=0; break; /* indirect - register b */
+// case 0x9a: EA=0; break; /* indirect - ???? */
+// case 0x9b: EA=0; break; /* indirect - ???? */
+// case 0x9c: EA=0; break; /* indirect - ???? */
+// case 0x9d: EA=0; break; /* indirect - ???? */
+// case 0x9e: EA=0; break; /* indirect - register d */
+// case 0x9f: EA=0; break; /* indirect - ???? */
+ case 0xa0: /* register a */
+ EA=X+SIGNED(A);
+ konami_ICount-=1;
+ break;
+ case 0xa1: /* register b */
+ EA=X+SIGNED(B);
+ konami_ICount-=1;
+ break;
+// case 0xa2: EA=0; break; /* ???? */
+// case 0xa3: EA=0; break; /* ???? */
+// case 0xa4: EA=0; break; /* ???? */
+// case 0xa5: EA=0; break; /* ???? */
+// case 0xa6: EA=0; break; /* ???? */
+ case 0xa7: /* register d */
+ EA=X+D;
+ konami_ICount-=4;
+ break;
+ case 0xa8: /* indirect - register a */
+ EA=X+SIGNED(A);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0xa9: /* indirect - register b */
+ EA=X+SIGNED(B);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+// case 0xaa: EA=0; break; /* indirect - ???? */
+// case 0xab: EA=0; break; /* indirect - ???? */
+// case 0xac: EA=0; break; /* indirect - ???? */
+// case 0xad: EA=0; break; /* indirect - ???? */
+// case 0xae: EA=0; break; /* indirect - ???? */
+ case 0xaf: /* indirect - register d */
+ EA=X+D;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+ case 0xb0: /* register a */
+ EA=Y+SIGNED(A);
+ konami_ICount-=1;
+ break;
+ case 0xb1: /* register b */
+ EA=Y+SIGNED(B);
+ konami_ICount-=1;
+ break;
+// case 0xb2: EA=0; break; /* ???? */
+// case 0xb3: EA=0; break; /* ???? */
+// case 0xb4: EA=0; break; /* ???? */
+// case 0xb5: EA=0; break; /* ???? */
+// case 0xb6: EA=0; break; /* ???? */
+ case 0xb7: /* register d */
+ EA=Y+D;
+ konami_ICount-=4;
+ break;
+ case 0xb8: /* indirect - register a */
+ EA=Y+SIGNED(A);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0xb9: /* indirect - register b */
+ EA=Y+SIGNED(B);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+// case 0xba: EA=0; break; /* indirect - ???? */
+// case 0xbb: EA=0; break; /* indirect - ???? */
+// case 0xbc: EA=0; break; /* indirect - ???? */
+// case 0xbd: EA=0; break; /* indirect - ???? */
+// case 0xbe: EA=0; break; /* indirect - ???? */
+ case 0xbf: /* indirect - register d */
+ EA=Y+D;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+// case 0xc0: EA=0; break; /* register a */
+// case 0xc1: EA=0; break; /* register b */
+// case 0xc2: EA=0; break; /* ???? */
+// case 0xc3: EA=0; break; /* ???? */
+ case 0xc4:
+ EAD=0;
+ (*konami_direct[konami.ireg])();
+ konami_ICount -= 1;
+ return;
+// case 0xc5: EA=0; break; /* ???? */
+// case 0xc6: EA=0; break; /* ???? */
+// case 0xc7: EA=0; break; /* register d */
+// case 0xc8: EA=0; break; /* indirect - register a */
+// case 0xc9: EA=0; break; /* indirect - register b */
+// case 0xca: EA=0; break; /* indirect - ???? */
+// case 0xcb: EA=0; break; /* indirect - ???? */
+ case 0xcc: /* indirect - direct */
+ DIRWORD(ea);
+ konami_ICount-=4;
+ break;
+// case 0xcd: EA=0; break; /* indirect - ???? */
+// case 0xce: EA=0; break; /* indirect - register d */
+// case 0xcf: EA=0; break; /* indirect - ???? */
+ case 0xd0: /* register a */
+ EA=U+SIGNED(A);
+ konami_ICount-=1;
+ break;
+ case 0xd1: /* register b */
+ EA=U+SIGNED(B);
+ konami_ICount-=1;
+ break;
+// case 0xd2: EA=0; break; /* ???? */
+// case 0xd3: EA=0; break; /* ???? */
+// case 0xd4: EA=0; break; /* ???? */
+// case 0xd5: EA=0; break; /* ???? */
+// case 0xd6: EA=0; break; /* ???? */
+ case 0xd7: /* register d */
+ EA=U+D;
+ konami_ICount-=4;
+ break;
+ case 0xd8: /* indirect - register a */
+ EA=U+SIGNED(A);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0xd9: /* indirect - register b */
+ EA=U+SIGNED(B);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+// case 0xda: EA=0; break; /* indirect - ???? */
+// case 0xdb: EA=0; break; /* indirect - ???? */
+// case 0xdc: EA=0; break; /* indirect - ???? */
+// case 0xdd: EA=0; break; /* indirect - ???? */
+// case 0xde: EA=0; break; /* indirect - ???? */
+ case 0xdf: /* indirect - register d */
+ EA=U+D;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+ case 0xe0: /* register a */
+ EA=S+SIGNED(A);
+ konami_ICount-=1;
+ break;
+ case 0xe1: /* register b */
+ EA=S+SIGNED(B);
+ konami_ICount-=1;
+ break;
+// case 0xe2: EA=0; break; /* ???? */
+// case 0xe3: EA=0; break; /* ???? */
+// case 0xe4: EA=0; break; /* ???? */
+// case 0xe5: EA=0; break; /* ???? */
+// case 0xe6: EA=0; break; /* ???? */
+ case 0xe7: /* register d */
+ EA=S+D;
+ konami_ICount-=4;
+ break;
+ case 0xe8: /* indirect - register a */
+ EA=S+SIGNED(A);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0xe9: /* indirect - register b */
+ EA=S+SIGNED(B);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+// case 0xea: EA=0; break; /* indirect - ???? */
+// case 0xeb: EA=0; break; /* indirect - ???? */
+// case 0xec: EA=0; break; /* indirect - ???? */
+// case 0xed: EA=0; break; /* indirect - ???? */
+// case 0xee: EA=0; break; /* indirect - ???? */
+ case 0xef: /* indirect - register d */
+ EA=S+D;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+ case 0xf0: /* register a */
+ EA=PC+SIGNED(A);
+ konami_ICount-=1;
+ break;
+ case 0xf1: /* register b */
+ EA=PC+SIGNED(B);
+ konami_ICount-=1;
+ break;
+// case 0xf2: EA=0; break; /* ???? */
+// case 0xf3: EA=0; break; /* ???? */
+// case 0xf4: EA=0; break; /* ???? */
+// case 0xf5: EA=0; break; /* ???? */
+// case 0xf6: EA=0; break; /* ???? */
+ case 0xf7: /* register d */
+ EA=PC+D;
+ konami_ICount-=4;
+ break;
+ case 0xf8: /* indirect - register a */
+ EA=PC+SIGNED(A);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+ case 0xf9: /* indirect - register b */
+ EA=PC+SIGNED(B);
+ EA=RM16(EAD);
+ konami_ICount-=4;
+ break;
+// case 0xfa: EA=0; break; /* indirect - ???? */
+// case 0xfb: EA=0; break; /* indirect - ???? */
+// case 0xfc: EA=0; break; /* indirect - ???? */
+// case 0xfd: EA=0; break; /* indirect - ???? */
+// case 0xfe: EA=0; break; /* indirect - ???? */
+ case 0xff: /* indirect - register d */
+ EA=PC+D;
+ EA=RM16(EAD);
+ konami_ICount-=7;
+ break;
+ default:
+ logerror("KONAMI: Unknown/Invalid postbyte at PC = %04x\n", PC -1 );
+ EAD = 0;
+ }
+ (*konami_indexed[konami.ireg])();
+}
diff --git a/src/emu/cpu/konami/konamtbl.c b/src/emu/cpu/konami/konamtbl.c
new file mode 100644
index 00000000000..f2725c3be73
--- /dev/null
+++ b/src/emu/cpu/konami/konamtbl.c
@@ -0,0 +1,491 @@
+INLINE void abx(void);
+INLINE void adca_di(void);
+INLINE void adca_ex(void);
+INLINE void adca_im(void);
+INLINE void adca_ix(void);
+INLINE void adcb_di(void);
+INLINE void adcb_ex(void);
+INLINE void adcb_im(void);
+INLINE void adcb_ix(void);
+INLINE void adda_di(void);
+INLINE void adda_ex(void);
+INLINE void adda_im(void);
+INLINE void adda_ix(void);
+INLINE void addb_di(void);
+INLINE void addb_ex(void);
+INLINE void addb_im(void);
+INLINE void addb_ix(void);
+INLINE void addd_di(void);
+INLINE void addd_ex(void);
+INLINE void addd_im(void);
+INLINE void addd_ix(void);
+INLINE void anda_di(void);
+INLINE void anda_ex(void);
+INLINE void anda_im(void);
+INLINE void anda_ix(void);
+INLINE void andb_di(void);
+INLINE void andb_ex(void);
+INLINE void andb_im(void);
+INLINE void andb_ix(void);
+INLINE void andcc(void);
+INLINE void asl_di(void);
+INLINE void asl_ex(void);
+INLINE void asl_ix(void);
+INLINE void asla(void);
+INLINE void aslb(void);
+INLINE void asr_di(void);
+INLINE void asr_ex(void);
+INLINE void asr_ix(void);
+INLINE void asra(void);
+INLINE void asrb(void);
+INLINE void bcc(void);
+INLINE void bcs(void);
+INLINE void beq(void);
+INLINE void bge(void);
+INLINE void bgt(void);
+INLINE void bhi(void);
+INLINE void bita_di(void);
+INLINE void bita_ex(void);
+INLINE void bita_im(void);
+INLINE void bita_ix(void);
+INLINE void bitb_di(void);
+INLINE void bitb_ex(void);
+INLINE void bitb_im(void);
+INLINE void bitb_ix(void);
+INLINE void ble(void);
+INLINE void bls(void);
+INLINE void blt(void);
+INLINE void bmi(void);
+INLINE void bne(void);
+INLINE void bpl(void);
+INLINE void bra(void);
+INLINE void brn(void);
+INLINE void bsr(void);
+INLINE void bvc(void);
+INLINE void bvs(void);
+INLINE void clr_di(void);
+INLINE void clr_ex(void);
+INLINE void clr_ix(void);
+INLINE void clra(void);
+INLINE void clrb(void);
+INLINE void cmpa_di(void);
+INLINE void cmpa_ex(void);
+INLINE void cmpa_im(void);
+INLINE void cmpa_ix(void);
+INLINE void cmpb_di(void);
+INLINE void cmpb_ex(void);
+INLINE void cmpb_im(void);
+INLINE void cmpb_ix(void);
+INLINE void cmpd_di(void);
+INLINE void cmpd_ex(void);
+INLINE void cmpd_im(void);
+INLINE void cmpd_ix(void);
+INLINE void cmps_di(void);
+INLINE void cmps_ex(void);
+INLINE void cmps_im(void);
+INLINE void cmps_ix(void);
+INLINE void cmpu_di(void);
+INLINE void cmpu_ex(void);
+INLINE void cmpu_im(void);
+INLINE void cmpu_ix(void);
+INLINE void cmpx_di(void);
+INLINE void cmpx_ex(void);
+INLINE void cmpx_im(void);
+INLINE void cmpx_ix(void);
+INLINE void cmpy_di(void);
+INLINE void cmpy_ex(void);
+INLINE void cmpy_im(void);
+INLINE void cmpy_ix(void);
+INLINE void com_di(void);
+INLINE void com_ex(void);
+INLINE void com_ix(void);
+INLINE void coma(void);
+INLINE void comb(void);
+INLINE void cwai(void);
+INLINE void daa(void);
+INLINE void dec_di(void);
+INLINE void dec_ex(void);
+INLINE void dec_ix(void);
+INLINE void deca(void);
+INLINE void decb(void);
+INLINE void eora_di(void);
+INLINE void eora_ex(void);
+INLINE void eora_im(void);
+INLINE void eora_ix(void);
+INLINE void eorb_di(void);
+INLINE void eorb_ex(void);
+INLINE void eorb_im(void);
+INLINE void eorb_ix(void);
+INLINE void exg(void);
+INLINE void illegal(void);
+INLINE void inc_di(void);
+INLINE void inc_ex(void);
+INLINE void inc_ix(void);
+INLINE void inca(void);
+INLINE void incb(void);
+INLINE void jmp_di(void);
+INLINE void jmp_ex(void);
+INLINE void jmp_ix(void);
+INLINE void jsr_di(void);
+INLINE void jsr_ex(void);
+INLINE void jsr_ix(void);
+INLINE void lbcc(void);
+INLINE void lbcs(void);
+INLINE void lbeq(void);
+INLINE void lbge(void);
+INLINE void lbgt(void);
+INLINE void lbhi(void);
+INLINE void lble(void);
+INLINE void lbls(void);
+INLINE void lblt(void);
+INLINE void lbmi(void);
+INLINE void lbne(void);
+INLINE void lbpl(void);
+INLINE void lbra(void);
+INLINE void lbrn(void);
+INLINE void lbsr(void);
+INLINE void lbvc(void);
+INLINE void lbvs(void);
+INLINE void lda_di(void);
+INLINE void lda_ex(void);
+INLINE void lda_im(void);
+INLINE void lda_ix(void);
+INLINE void ldb_di(void);
+INLINE void ldb_ex(void);
+INLINE void ldb_im(void);
+INLINE void ldb_ix(void);
+INLINE void ldd_di(void);
+INLINE void ldd_ex(void);
+INLINE void ldd_im(void);
+INLINE void ldd_ix(void);
+INLINE void lds_di(void);
+INLINE void lds_ex(void);
+INLINE void lds_im(void);
+INLINE void lds_ix(void);
+INLINE void ldu_di(void);
+INLINE void ldu_ex(void);
+INLINE void ldu_im(void);
+INLINE void ldu_ix(void);
+INLINE void ldx_di(void);
+INLINE void ldx_ex(void);
+INLINE void ldx_im(void);
+INLINE void ldx_ix(void);
+INLINE void ldy_di(void);
+INLINE void ldy_ex(void);
+INLINE void ldy_im(void);
+INLINE void ldy_ix(void);
+INLINE void leas(void);
+INLINE void leau(void);
+INLINE void leax(void);
+INLINE void leay(void);
+INLINE void lsr_di(void);
+INLINE void lsr_ex(void);
+INLINE void lsr_ix(void);
+INLINE void lsra(void);
+INLINE void lsrb(void);
+INLINE void mul(void);
+INLINE void neg_di(void);
+INLINE void neg_ex(void);
+INLINE void neg_ix(void);
+INLINE void nega(void);
+INLINE void negb(void);
+INLINE void nop(void);
+INLINE void ora_di(void);
+INLINE void ora_ex(void);
+INLINE void ora_im(void);
+INLINE void ora_ix(void);
+INLINE void orb_di(void);
+INLINE void orb_ex(void);
+INLINE void orb_im(void);
+INLINE void orb_ix(void);
+INLINE void orcc(void);
+INLINE void pshs(void);
+INLINE void pshu(void);
+INLINE void puls(void);
+INLINE void pulu(void);
+INLINE void rol_di(void);
+INLINE void rol_ex(void);
+INLINE void rol_ix(void);
+INLINE void rola(void);
+INLINE void rolb(void);
+INLINE void ror_di(void);
+INLINE void ror_ex(void);
+INLINE void ror_ix(void);
+INLINE void rora(void);
+INLINE void rorb(void);
+INLINE void rti(void);
+INLINE void rts(void);
+INLINE void sbca_di(void);
+INLINE void sbca_ex(void);
+INLINE void sbca_im(void);
+INLINE void sbca_ix(void);
+INLINE void sbcb_di(void);
+INLINE void sbcb_ex(void);
+INLINE void sbcb_im(void);
+INLINE void sbcb_ix(void);
+INLINE void sex(void);
+INLINE void sta_di(void);
+INLINE void sta_ex(void);
+INLINE void sta_im(void);
+INLINE void sta_ix(void);
+INLINE void stb_di(void);
+INLINE void stb_ex(void);
+INLINE void stb_im(void);
+INLINE void stb_ix(void);
+INLINE void std_di(void);
+INLINE void std_ex(void);
+INLINE void std_im(void);
+INLINE void std_ix(void);
+INLINE void sts_di(void);
+INLINE void sts_ex(void);
+INLINE void sts_im(void);
+INLINE void sts_ix(void);
+INLINE void stu_di(void);
+INLINE void stu_ex(void);
+INLINE void stu_im(void);
+INLINE void stu_ix(void);
+INLINE void stx_di(void);
+INLINE void stx_ex(void);
+INLINE void stx_im(void);
+INLINE void stx_ix(void);
+INLINE void sty_di(void);
+INLINE void sty_ex(void);
+INLINE void sty_im(void);
+INLINE void sty_ix(void);
+INLINE void suba_di(void);
+INLINE void suba_ex(void);
+INLINE void suba_im(void);
+INLINE void suba_ix(void);
+INLINE void subb_di(void);
+INLINE void subb_ex(void);
+INLINE void subb_im(void);
+INLINE void subb_ix(void);
+INLINE void subd_di(void);
+INLINE void subd_ex(void);
+INLINE void subd_im(void);
+INLINE void subd_ix(void);
+INLINE void swi(void);
+INLINE void swi2(void);
+INLINE void swi3(void);
+INLINE void sync(void);
+INLINE void tfr(void);
+INLINE void tst_di(void);
+INLINE void tst_ex(void);
+INLINE void tst_ix(void);
+INLINE void tsta(void);
+INLINE void tstb(void);
+
+INLINE void clrd(void); /* 6309 */
+INLINE void clrw_ix(void); /* 6309 ? */
+INLINE void clrw_di(void); /* 6309 ? */
+INLINE void clrw_ex(void); /* 6309 ? */
+INLINE void negd(void);
+INLINE void negw_ix(void); /* 6309 ? */
+INLINE void negw_di(void); /* 6309 ? */
+INLINE void negw_ex(void); /* 6309 ? */
+INLINE void lsrd( void ); /* 6309 */
+INLINE void lsrd_di( void ); /* 6309 */
+INLINE void lsrd_ix( void ); /* 6309 */
+INLINE void lsrd_ex( void ); /* 6309 */
+INLINE void rord( void ); /* 6309 ? */
+INLINE void rord_di( void ); /* 6309 */
+INLINE void rord_ix( void ); /* 6309 */
+INLINE void rord_ex( void ); /* 6309 */
+INLINE void asrd( void ); /* 6309 ? */
+INLINE void asrd_di( void ); /* 6309 */
+INLINE void asrd_ix( void ); /* 6309 */
+INLINE void asrd_ex( void ); /* 6309 */
+INLINE void asld( void ); /* 6309 */
+INLINE void asld_di( void ); /* 6309 */
+INLINE void asld_ix( void ); /* 6309 */
+INLINE void asld_ex( void ); /* 6309 */
+INLINE void rold( void ); /* 6309 ? */
+INLINE void rold_di( void ); /* 6309 */
+INLINE void rold_ix( void ); /* 6309 */
+INLINE void rold_ex( void ); /* 6309 */
+INLINE void tstd(void);
+INLINE void tstw_di( void );
+INLINE void tstw_ix( void );
+INLINE void tstw_ex( void );
+
+/* Custom opcodes */
+INLINE void setline_im( void );
+INLINE void setline_ix( void );
+INLINE void setline_di( void );
+INLINE void setline_ex( void );
+INLINE void bmove( void );
+INLINE void move( void );
+INLINE void decbjnz( void );
+INLINE void decxjnz( void );
+INLINE void bset( void );
+INLINE void bset2( void );
+INLINE void lmul(void);
+INLINE void divx( void );
+INLINE void incd( void );
+INLINE void incw_di( void );
+INLINE void incw_ix( void );
+INLINE void incw_ex( void );
+INLINE void decd( void );
+INLINE void decw_di( void );
+INLINE void decw_ix( void );
+INLINE void decw_ex( void );
+INLINE void lsrw_di( void );
+INLINE void lsrw_ix( void );
+INLINE void lsrw_ex( void );
+INLINE void rorw_di( void );
+INLINE void rorw_ix( void );
+INLINE void rorw_ex( void );
+INLINE void asrw_di( void );
+INLINE void asrw_ix( void );
+INLINE void asrw_ex( void );
+INLINE void aslw_di( void );
+INLINE void aslw_ix( void );
+INLINE void aslw_ex( void );
+INLINE void rolw_di( void );
+INLINE void rolw_ix( void );
+INLINE void rolw_ex( void );
+INLINE void absa( void );
+INLINE void absb( void );
+INLINE void absd( void );
+
+INLINE void opcode2( void );
+
+static void (*konami_main[0x100])(void) = {
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 00 */
+ opcode2,opcode2,opcode2,opcode2,pshs ,pshu ,puls ,pulu ,
+ lda_im ,ldb_im ,opcode2,opcode2,adda_im,addb_im,opcode2,opcode2, /* 10 */
+ adca_im,adcb_im,opcode2,opcode2,suba_im,subb_im,opcode2,opcode2,
+ sbca_im,sbcb_im,opcode2,opcode2,anda_im,andb_im,opcode2,opcode2, /* 20 */
+ bita_im,bitb_im,opcode2,opcode2,eora_im,eorb_im,opcode2,opcode2,
+ ora_im ,orb_im ,opcode2,opcode2,cmpa_im,cmpb_im,opcode2,opcode2, /* 30 */
+ setline_im,opcode2,opcode2,opcode2,andcc,orcc ,exg ,tfr ,
+ ldd_im ,opcode2,ldx_im ,opcode2,ldy_im ,opcode2,ldu_im ,opcode2, /* 40 */
+ lds_im ,opcode2,cmpd_im,opcode2,cmpx_im,opcode2,cmpy_im,opcode2,
+ cmpu_im,opcode2,cmps_im,opcode2,addd_im,opcode2,subd_im,opcode2, /* 50 */
+ opcode2,opcode2,opcode2,opcode2,opcode2,illegal,illegal,illegal,
+ bra ,bhi ,bcc ,bne ,bvc ,bpl ,bge ,bgt , /* 60 */
+ lbra ,lbhi ,lbcc ,lbne ,lbvc ,lbpl ,lbge ,lbgt ,
+ brn ,bls ,bcs ,beq ,bvs ,bmi ,blt ,ble , /* 70 */
+ lbrn ,lbls ,lbcs ,lbeq ,lbvs ,lbmi ,lblt ,lble ,
+ clra ,clrb ,opcode2,coma ,comb ,opcode2,nega ,negb , /* 80 */
+ opcode2,inca ,incb ,opcode2,deca ,decb ,opcode2,rts ,
+ tsta ,tstb ,opcode2,lsra ,lsrb ,opcode2,rora ,rorb , /* 90 */
+ opcode2,asra ,asrb ,opcode2,asla ,aslb ,opcode2,rti ,
+ rola ,rolb ,opcode2,opcode2,opcode2,opcode2,opcode2,opcode2, /* a0 */
+ opcode2,opcode2,bsr ,lbsr ,decbjnz,decxjnz,nop ,illegal,
+ abx ,daa ,sex ,mul ,lmul ,divx ,bmove ,move , /* b0 */
+ lsrd ,opcode2,rord ,opcode2,asrd ,opcode2,asld ,opcode2,
+ rold ,opcode2,clrd ,opcode2,negd ,opcode2,incd ,opcode2, /* c0 */
+ decd ,opcode2,tstd ,opcode2,absa ,absb ,absd ,bset ,
+ bset2 ,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* d0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* e0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* f0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal
+};
+
+static void (*konami_indexed[0x100])(void) = {
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 00 */
+ leax ,leay ,leau ,leas ,illegal,illegal,illegal,illegal,
+ illegal,illegal,lda_ix ,ldb_ix ,illegal,illegal,adda_ix,addb_ix, /* 10 */
+ illegal,illegal,adca_ix,adcb_ix,illegal,illegal,suba_ix,subb_ix,
+ illegal,illegal,sbca_ix,sbcb_ix,illegal,illegal,anda_ix,andb_ix, /* 20 */
+ illegal,illegal,bita_ix,bitb_ix,illegal,illegal,eora_ix,eorb_ix,
+ illegal,illegal,ora_ix ,orb_ix ,illegal,illegal,cmpa_ix,cmpb_ix, /* 30 */
+ illegal,setline_ix,sta_ix,stb_ix,illegal,illegal,illegal,illegal,
+ illegal,ldd_ix ,illegal,ldx_ix ,illegal,ldy_ix ,illegal,ldu_ix , /* 40 */
+ illegal,lds_ix ,illegal,cmpd_ix,illegal,cmpx_ix,illegal,cmpy_ix,
+ illegal,cmpu_ix,illegal,cmps_ix,illegal,addd_ix,illegal,subd_ix, /* 50 */
+ std_ix ,stx_ix ,sty_ix ,stu_ix ,sts_ix ,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 60 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 70 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,clr_ix ,illegal,illegal,com_ix ,illegal,illegal, /* 80 */
+ neg_ix ,illegal,illegal,inc_ix ,illegal,illegal,dec_ix ,illegal,
+ illegal,illegal,tst_ix ,illegal,illegal,lsr_ix ,illegal,illegal, /* 90 */
+ ror_ix ,illegal,illegal,asr_ix ,illegal,illegal,asl_ix ,illegal,
+ illegal,illegal,rol_ix ,lsrw_ix,rorw_ix,asrw_ix,aslw_ix,rolw_ix, /* a0 */
+ jmp_ix ,jsr_ix ,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* b0 */
+ illegal,lsrd_ix,illegal,rord_ix,illegal,asrd_ix,illegal,asld_ix,
+ illegal,rold_ix,illegal,clrw_ix,illegal,negw_ix,illegal,incw_ix, /* c0 */
+ illegal,decw_ix,illegal,tstw_ix,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* d0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* e0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* f0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal
+};
+
+static void (*konami_direct[0x100])(void) = {
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 00 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,lda_di ,ldb_di ,illegal,illegal,adda_di,addb_di, /* 10 */
+ illegal,illegal,adca_di,adcb_di,illegal,illegal,suba_di,subb_di,
+ illegal,illegal,sbca_di,sbcb_di,illegal,illegal,anda_di,andb_di, /* 20 */
+ illegal,illegal,bita_di,bitb_di,illegal,illegal,eora_di,eorb_di,
+ illegal,illegal,ora_di ,orb_di ,illegal,illegal,cmpa_di,cmpb_di, /* 30 */
+ illegal,setline_di,sta_di,stb_di,illegal,illegal,illegal,illegal,
+ illegal,ldd_di ,illegal,ldx_di ,illegal,ldy_di ,illegal,ldu_di , /* 40 */
+ illegal,lds_di ,illegal,cmpd_di,illegal,cmpx_di,illegal,cmpy_di,
+ illegal,cmpu_di,illegal,cmps_di,illegal,addd_di,illegal,subd_di, /* 50 */
+ std_di ,stx_di ,sty_di ,stu_di ,sts_di ,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 60 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 70 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,clr_di ,illegal,illegal,com_di ,illegal,illegal, /* 80 */
+ neg_di ,illegal,illegal,inc_di ,illegal,illegal,dec_di ,illegal,
+ illegal,illegal,tst_di ,illegal,illegal,lsr_di ,illegal,illegal, /* 90 */
+ ror_di ,illegal,illegal,asr_di ,illegal,illegal,asl_di ,illegal,
+ illegal,illegal,rol_di ,lsrw_di,rorw_di,asrw_di,aslw_di,rolw_di, /* a0 */
+ jmp_di ,jsr_di ,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* b0 */
+ illegal,lsrd_di,illegal,rord_di,illegal,asrd_di,illegal,asld_di,
+ illegal,rold_di,illegal,clrw_di,illegal,negw_di,illegal,incw_di, /* c0 */
+ illegal,decw_di,illegal,tstw_di,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* d0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* e0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* f0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal
+};
+
+static void (*konami_extended[0x100])(void) = {
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 00 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,lda_ex ,ldb_ex ,illegal,illegal,adda_ex,addb_ex, /* 10 */
+ illegal,illegal,adca_ex,adcb_ex,illegal,illegal,suba_ex,subb_ex,
+ illegal,illegal,sbca_ex,sbcb_ex,illegal,illegal,anda_ex,andb_ex, /* 20 */
+ illegal,illegal,bita_ex,bitb_ex,illegal,illegal,eora_ex,eorb_ex,
+ illegal,illegal,ora_ex ,orb_ex ,illegal,illegal,cmpa_ex,cmpb_ex, /* 30 */
+ illegal,setline_ex,sta_ex,stb_ex,illegal,illegal,illegal,illegal,
+ illegal,ldd_ex ,illegal,ldx_ex ,illegal,ldy_ex ,illegal,ldu_ex , /* 40 */
+ illegal,lds_ex ,illegal,cmpd_ex,illegal,cmpx_ex,illegal,cmpy_ex,
+ illegal,cmpu_ex,illegal,cmps_ex,illegal,addd_ex,illegal,subd_ex, /* 50 */
+ std_ex ,stx_ex ,sty_ex ,stu_ex ,sts_ex ,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 60 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* 70 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,clr_ex ,illegal,illegal,com_ex ,illegal,illegal, /* 80 */
+ neg_ex ,illegal,illegal,inc_ex ,illegal,illegal,dec_ex ,illegal,
+ illegal,illegal,tst_ex ,illegal,illegal,lsr_ex ,illegal,illegal, /* 90 */
+ ror_ex ,illegal,illegal,asr_ex ,illegal,illegal,asl_ex ,illegal,
+ illegal,illegal,rol_ex ,lsrw_ex,rorw_ex,asrw_ex,aslw_ex,rolw_ex, /* a0 */
+ jmp_ex ,jsr_ex ,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* b0 */
+ illegal,lsrd_ex,illegal,rord_ex,illegal,asrd_ex,illegal,asld_ex,
+ illegal,rold_ex,illegal,clrw_ex,illegal,negw_ex,illegal,incw_ex, /* c0 */
+ illegal,decw_ex,illegal,tstw_ex,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* d0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* e0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal,
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal, /* f0 */
+ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal
+};
diff --git a/src/emu/cpu/lh5801/5801dasm.c b/src/emu/cpu/lh5801/5801dasm.c
new file mode 100644
index 00000000000..d94882c5233
--- /dev/null
+++ b/src/emu/cpu/lh5801/5801dasm.c
@@ -0,0 +1,729 @@
+/*****************************************************************************
+ *
+ * disasm.c
+ * portable lh5801 emulator interface
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+
+#include "lh5801.h"
+
+typedef enum {
+ Imp,
+ Reg,
+ Vec, // imm byte (vector at 0xffxx)
+ Vej,
+ Imm,
+ RegImm,
+ Imm16,
+ RegImm16,
+ ME0,
+ ME0Imm,
+ Abs,
+ AbsImm,
+ ME1,
+ ME1Imm,
+ ME1Abs,
+ ME1AbsImm,
+ RelP,
+ RelM
+} Adr;
+
+typedef enum {
+ RegNone,
+ A,
+ XL, XH, X,
+ YL, YH, Y,
+ UL, UH, U,
+ P, S
+} Regs;
+
+static const char *RegNames[]= {
+ 0, "A", "XL", "XH", "X", "YL", "YH", "Y", "UL", "UH", "U", "P", "S"
+};
+
+typedef enum {
+ ILL, ILL2, PREFD, NOP,
+
+ LDA, STA, LDI, LDX, STX,
+ LDE, SDE, LIN, SIN,
+ TIN, // (x++)->(y++)
+ ADC, ADI, ADR, SBC, SBI,
+ DCA, DCS, // bcd add and sub
+ CPA, CPI, CIN, // A compared with (x++)
+ AND, ANI, ORA, ORI, EOR, EAI, BIT, BII,
+ INC, DEC,
+ DRL, DRR, // digit rotates
+ ROL, ROR,
+ SHL, SHR,
+ AEX, // A nibble swap
+
+ BCR, BCS, BHR, BHS, BZR, BZS, BVR, BVS,
+ BCH, LOP, // loop with ul
+ JMP, SJP, RTN, RTI, HLT,
+ VCR, VCS, VHR, VHS, VVS, VZR, VZS,
+ VMJ, VEJ,
+ PSH, POP, ATT, TTA,
+ REC, SEC, RIE, SIE,
+
+ AM0, AM1, // load timer reg
+ ITA, // reads input port
+ ATP, // akku send to data bus
+ CDV, // clears internal divider
+ OFF, // clears bf flip flop
+ RDP, SDP,// reset display flip flop
+ RPU, SPU,// flip flop pu off
+ RPV, SPV,// flip flop pv off
+} Ins;
+
+static const char *InsNames[]={
+ "ILL", "ILL", 0, "NOP",
+ "LDA", "STA", "LDI", "LDX", "STX",
+ "LDE", "SDE", "LIN", "SIN",
+ "TIN",
+ "ADC", "ADI", "ADR", "SBC", "SBI",
+ "DCA", "DCS",
+ "CPA", "CPI", "CIN",
+ "AND", "ANI", "ORA", "ORI", "EOR", "EAI", "BIT", "BII",
+ "INC", "DEC",
+ "DRL", "DRR",
+ "ROL", "ROR",
+ "SHL", "SHR",
+ "AEX",
+ "BCR", "BCS", "BHR", "BHS", "BZR", "BZS", "BVR", "BVS",
+ "BCH", "LOP",
+ "JMP", "SJP", "RTN", "RTI", "HLT",
+ "VCR", "VCS", "VHR", "VHS", "VVS", "VZR", "VZS",
+ "VMJ", "VEJ",
+ "PSH", "POP", "ATT", "TTA",
+ "REC", "SEC", "RIE", "SIE",
+
+ "AM0", "AM1",
+ "ITA",
+ "ATP",
+ "CDV",
+ "OFF",
+ "RDP", "SDP",
+ "RPU", "SPU",
+ "RPV", "SPV",
+};
+
+typedef struct { Ins ins; Adr adr; Regs reg; } Entry;
+
+static const Entry table[0x100]={
+ { SBC, Reg, XL }, // 0
+ { SBC, ME0, X },
+ { ADC, Reg, XL },
+ { ADC, ME0, X },
+ { LDA, Reg, XL },
+ { LDA, ME0, X },
+ { CPA, Reg, XL },
+ { CPA, ME0, X },
+ { STA, Reg, XH },
+ { AND, ME0, X },
+ { STA, Reg, XL },
+ { ORA, ME0, X },
+ { DCS, ME0, X },
+ { EOR, ME0, X },
+ { STA, ME0, X },
+ { BIT, ME0, X },
+ { SBC, Reg, YL }, // 0x10
+ { SBC, ME0, Y },
+ { ADC, Reg, YL },
+ { ADC, ME0, Y },
+ { LDA, Reg, YL },
+ { LDA, ME0, Y },
+ { CPA, Reg, YL },
+ { CPA, ME0, Y },
+ { STA, Reg, YH },
+ { AND, ME0, Y },
+ { STA, Reg, YL },
+ { ORA, ME0, Y },
+ { DCS, ME0, Y },
+ { EOR, ME0, Y },
+ { STA, ME0, Y },
+ { BIT, ME0, Y },
+ { SBC, Reg, UL }, // 0x20
+ { SBC, ME0, U },
+ { ADC, Reg, UL },
+ { ADC, ME0, U },
+ { LDA, Reg, UL },
+ { LDA, ME0, U },
+ { CPA, Reg, UL },
+ { CPA, ME0, U },
+ { STA, Reg, UH },
+ { AND, ME0, U },
+ { STA, Reg, UL },
+ { ORA, ME0, U },
+ { DCS, ME0, U },
+ { EOR, ME0, U },
+ { STA, ME0, U },
+ { BIT, ME0, U },
+ { ILL }, // 0x30
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { NOP, Imp },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { INC, Reg, XL }, //0x40
+ { SIN, Reg, X },
+ { DEC, Reg, XL },
+ { SDE, Reg, X },
+ { INC, Reg, X },
+ { LIN, Reg, X },
+ { DEC, Reg, X },
+ { LDE, Reg, X },
+ { LDI, RegImm, XH },
+ { ANI, ME0Imm, X },
+ { LDI, RegImm, XL },
+ { ORI, ME0Imm, X },
+ { CPI, RegImm, XH },
+ { BII, ME0Imm, X },
+ { CPI, RegImm, XL },
+ { ADI, ME0Imm, X },
+ { INC, Reg, YL }, //0x50
+ { SIN, Reg, Y },
+ { DEC, Reg, YL },
+ { SDE, Reg, Y },
+ { INC, Reg, Y },
+ { LIN, Reg, Y },
+ { DEC, Reg, Y },
+ { LDE, Reg, Y },
+ { LDI, RegImm, YH },
+ { ANI, ME0Imm, Y },
+ { LDI, RegImm, YL },
+ { ORI, ME0Imm, Y },
+ { CPI, RegImm, YH },
+ { BII, ME0Imm, Y },
+ { CPI, RegImm, YL },
+ { ADI, ME0Imm, Y },
+ { INC, Reg, UL }, //0x60
+ { SIN, Reg, U },
+ { DEC, Reg, UL },
+ { SDE, Reg, U },
+ { INC, Reg, U },
+ { LIN, Reg, U },
+ { DEC, Reg, U },
+ { LDE, Reg, U },
+ { LDI, RegImm, UH },
+ { ANI, ME0Imm, U },
+ { LDI, RegImm, UL },
+ { ORI, ME0Imm, U },
+ { CPI, RegImm, UH },
+ { BII, ME0Imm, U },
+ { CPI, RegImm, UL },
+ { ADI, ME0Imm, U },
+ { ILL }, // 0X70
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { ILL },
+ { SBC, Reg, XH }, // 0x80
+ { BCR, RelP },
+ { ADC, Reg, XH },
+ { BCS, RelP },
+ { LDA, Reg, XH },
+ { BHR, RelP },
+ { CPA, Reg, XH },
+ { BHS, RelP },
+ { LOP, RelM },
+ { BZR, RelP },
+ { RTI, Imp },
+ { BZS, RelP },
+ { DCA, ME0, X },
+ { BVR, RelP },
+ { BCH, RelP },
+ { BVS, RelP },
+ { SBC, Reg, YH }, // 0x90
+ { BCR, RelM },
+ { ADC, Reg, YH },
+ { BCS, RelM },
+ { LDA, Reg, YH },
+ { BHR, RelM },
+ { CPA, Reg, YH },
+ { BHS, RelM },
+ { ILL },
+ { BZR, RelM },
+ { RTN, Imp },
+ { BZS, RelM },
+ { DCA, ME0, Y },
+ { BVR, RelM },
+ { BCH, RelM },
+ { BVS, RelM },
+ { SBC, Reg, UH }, // 0xa0
+ { SBC, Abs },
+ { ADC, Reg, UH },
+ { ADC, Abs },
+ { LDA, Reg, UH },
+ { LDA, Abs },
+ { CPA, Reg, UH },
+ { CPA, Abs },
+ { SPV, Imp },
+ { AND, Abs },
+ { LDI, RegImm16, S },
+ { ORA, Abs },
+ { DCA, ME0, U },
+ { EOR, Abs },
+ { STA, Abs },
+ { BIT, Abs },
+ { ILL }, //0xb0
+ { SBI },
+ { ILL },
+ { ADI, RegImm, A },
+ { ILL },
+ { LDI, RegImm, A },
+ { ILL },
+ { CPI, RegImm, A },
+ { RPV, Imp },
+ { ANI, RegImm, A },
+ { JMP, Imm16 },
+ { ORI, RegImm, A },
+ { ILL },
+ { EAI, Imm },
+ { SJP, Imm16 },
+ { BII, RegImm, A },
+ { VEJ, Vej }, // 0xc0
+ { VCR, Vec },
+ { VEJ, Vej },
+ { VCS, Vec },
+ { VEJ, Vej },
+ { VHR, Vec },
+ { VEJ, Vej },
+ { VHS, Vec },
+ { VEJ, Vej },
+ { VZR, Vec },
+ { VEJ, Vej },
+ { VZS, Vec },
+ { VEJ, Vej },
+ { VMJ, Vec },
+ { VEJ, Vej },
+ { VVS, Vec },
+ { VEJ, Vej }, // 0xd0
+ { ROR, Imp },
+ { VEJ, Vej },
+ { DRR, Imp },
+ { VEJ, Vej },
+ { SHR, Imp },
+ { VEJ, Vej },
+ { DRL, Imp },
+ { VEJ, Vej },
+ { SHL, Imp },
+ { VEJ, Vej },
+ { ROL, Imp },
+ { VEJ, Vej },
+ { INC, Reg, A },
+ { VEJ, Vej },
+ { DEC, Reg, A },
+ { VEJ, Vej }, //0xe0
+ { SPU, Imp },
+ { VEJ, Vej },
+ { RPU, Imp },
+ { VEJ, Vej },
+ { ILL },
+ { VEJ, Vej },
+ { ILL },
+ { VEJ, Vej },
+ { ANI, AbsImm },
+ { VEJ, Vej },
+ { ORI, AbsImm },
+ { VEJ, Vej },
+ { BII, AbsImm },
+ { VEJ, Vej },
+ { ADI, AbsImm },
+ { VEJ, Vej }, //0xf0
+ { AEX, Imp },
+ { VEJ, Vej },
+ { ILL },
+ { VEJ, Vej },
+ { TIN, Imp },
+ { VEJ, Vej },
+ { CIN, Imp },
+ { ILL },
+ { REC, Imp },
+ { ILL },
+ { SEC, Imp },
+ { ILL },
+ { PREFD },
+ { ILL },
+ { ILL }
+};
+static const Entry table_fd[0x100]={
+ { ILL2 }, // 0x00
+ { SBC, ME1, X },
+ { ILL2 },
+ { ADC, ME1, X },
+ { ILL2 },
+ { LDA, ME1, X },
+ { ILL2 },
+ { CPA, ME1, X },
+ { LDX, Reg, X },
+ { AND, ME1, X },
+ { POP, Reg, X },
+ { ORA, ME1, X },
+ { DCS, ME1, X },
+ { EOR, ME1, X },
+ { STA, ME1, X },
+ { BIT, ME1, X },
+ { ILL2 }, // 0x10
+ { SBC, ME1, Y },
+ { ILL2 },
+ { ADC, ME1, Y },
+ { ILL2 },
+ { LDA, ME1, Y },
+ { ILL2 },
+ { CPA, ME1, Y },
+ { LDX, Reg, Y },
+ { AND, ME1, Y },
+ { POP, Reg, Y },
+ { ORA, ME1, Y },
+ { DCS, ME1, Y },
+ { EOR, ME1, Y },
+ { STA, ME1, Y },
+ { BIT, ME1, Y },
+ { ILL2 }, // 0x20
+ { SBC, ME1, U },
+ { ILL2 },
+ { ADC, ME1, U },
+ { ILL2 },
+ { LDA, ME1, U },
+ { ILL2 },
+ { CPA, ME1, U },
+ { LDX, Reg, U },
+ { AND, ME1, U },
+ { POP, Reg, U },
+ { ORA, ME1, U },
+ { DCS, ME1, U },
+ { EOR, ME1, U },
+ { STA, ME1, U },
+ { BIT, ME1, U },
+ { ILL2 }, // 0x30
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { INC, Reg, XH }, // 0x40
+ { ILL2 },
+ { DEC, Reg, XH }, //46 in other part of manual
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { LDX, Reg, S },
+ { ANI, ME1Imm, X },
+ { STX, Reg, X },
+ { ORI, ME1Imm, X },
+ { OFF, Imp },
+ { BII, ME1Imm, X },
+ { STX, Reg, S },
+ { ADI, ME1Imm, X },
+ { INC, Reg, YH }, // 0x50
+ { ILL2 },
+ { DEC, Reg, YH }, // 56 in other part of manual
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { LDX, Reg, P },
+ { ANI, ME1Imm, Y },
+ { STX, Reg, Y },
+ { ORI, ME1Imm, Y },
+ { ILL2 },
+ { BII, ME1Imm, Y },
+ { STX, Reg, P },
+ { ADI, ME1Imm, Y },
+ { INC, Reg, UH }, // 0x60
+ { ILL2 },
+ { DEC, Reg, UH }, // 66 in other part of manual
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ANI, ME1Imm, U },
+ { STX, Reg, U },
+ { ORI, ME1Imm, U },
+ { ILL2 },
+ { BII, ME1Imm, U },
+ { ILL },
+ { ADI, ME1Imm, U },
+ { ILL2 }, // 0x70
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 }, // 0x80
+ { SIE, Imp },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { PSH, Reg, X },
+ { ILL2 },
+ { POP, Reg, A },
+ { ILL2 },
+ { DCA, ME1, X },
+ { ILL2 },
+ { CDV, Imp },
+ { ILL2 },
+ { ILL2 }, // 0x90
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { PSH, Reg, Y },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { DCA, ME1, Y },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 }, // 0xa0
+ { SBC, ME1Abs },
+ { ILL2 },
+ { ADC, ME1Abs },
+ { ILL2 },
+ { LDA, ME1Abs },
+ { ILL2 },
+ { CPA, ME1Abs },
+ { PSH, Reg, U },
+ { AND, ME1Abs },
+ { TTA, Imp },
+ { ORA, ME1Abs },
+ { DCA, ME1, U },
+ { EOR, ME1Abs },
+ { STA, ME1Abs },
+ { BIT, ME1Abs },
+ { ILL2 }, // 0xb0
+ { HLT, Imp },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ITA, Imp },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { RIE, Imp },
+ { ILL2 },
+ { RDP, Imp }, // 0xc0
+ { SDP, Imp },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { PSH, Reg, A },
+ { ILL2 },
+ { ADR, Reg, X },
+ { ILL2 },
+ { ATP, Imp },
+ { ILL2 },
+ { AM0, Imp },
+ { ILL2 },
+ { ILL2 }, // 0xd0
+ { ILL2 },
+ { ILL2 },
+ { DRR, ME1, X },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { DRL, ME1, X },
+ { ILL2 },
+ { ILL2 },
+ { ADR, Reg, Y },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { AM1, Imp },
+ { ILL2 },
+ { ILL2 }, // 0xe0
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ANI, ME1AbsImm },
+ { ADR, Reg, U },
+ { ORI, ME1AbsImm },
+ { ATT, Imp },
+ { BII, ME1AbsImm },
+ { ILL2 },
+ { ADI, ME1AbsImm },
+ { ILL2 }, // 0xf0
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 },
+ { ILL2 }
+};
+
+offs_t lh5801_dasm(char *dst, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int pos = 0;
+ int oper;
+ UINT16 absolut;
+ const Entry *entry;
+ int temp;
+
+ oper=oprom[pos++];
+ entry=table+oper;
+
+ if (table[oper].ins==PREFD) {
+ oper=oprom[pos++];
+ entry=table_fd+oper;
+ }
+ switch (entry->ins) {
+ case ILL:
+ sprintf(dst,"%s %.2x", InsNames[entry->ins], oper);break;
+ case ILL2:
+ sprintf(dst,"%s fd%.2x", InsNames[entry->ins], oper);break;
+ default:
+ switch(entry->adr) {
+ case Imp:
+ sprintf(dst,"%s", InsNames[entry->ins]);break;
+ case Reg:
+ sprintf(dst,"%s %s", InsNames[entry->ins],RegNames[entry->reg]);break;
+ case RegImm:
+ sprintf(dst,"%s %s,%.2x", InsNames[entry->ins],
+ RegNames[entry->reg], oprom[pos++]);
+ break;
+ case RegImm16:
+ absolut=oprom[pos++]<<8;
+ absolut|=oprom[pos++];
+ sprintf(dst,"%s %s,%.4x", InsNames[entry->ins],RegNames[entry->reg],absolut );
+ break;
+ case Vec:
+ sprintf(dst,"%s (ff%.2x)", InsNames[entry->ins],oprom[pos++]);break;
+ case Vej:
+ sprintf(dst,"%s (ff%.2x)", InsNames[entry->ins], oper);break;
+ case Imm:
+ sprintf(dst,"%s %.2x", InsNames[entry->ins],oprom[pos++]);break;
+ case Imm16:
+ absolut=oprom[pos++]<<8;
+ absolut|=oprom[pos++];
+ sprintf(dst,"%s %.4x", InsNames[entry->ins],absolut );break;
+ case RelP:
+ temp=oprom[pos++];
+ sprintf(dst,"%s %.4x", InsNames[entry->ins],pc+pos+temp );break;
+ case RelM:
+ temp=oprom[pos++];
+ sprintf(dst,"%s %.4x", InsNames[entry->ins],pc+pos-temp );break;
+ case Abs:
+ absolut=oprom[pos++]<<8;
+ absolut|=oprom[pos++];
+ sprintf(dst,"%s (%.4x)", InsNames[entry->ins],absolut );break;
+ case ME1Abs:
+ absolut=oprom[pos++]<<8;
+ absolut|=oprom[pos++];
+ sprintf(dst,"%s #(%.4x)", InsNames[entry->ins],absolut );break;
+ case AbsImm:
+ absolut=oprom[pos++]<<8;
+ absolut|=oprom[pos++];
+ sprintf(dst,"%s (%.4x),%.2x", InsNames[entry->ins],absolut,
+ oprom[pos++]);break;
+ case ME1AbsImm:
+ absolut=oprom[pos++]<<8;
+ absolut|=oprom[pos++];
+ sprintf(dst,"%s #(%.4x),%.2x", InsNames[entry->ins],absolut,
+ oprom[pos++]);break;
+ case ME0:
+ sprintf(dst,"%s (%s)", InsNames[entry->ins],RegNames[entry->reg] );break;
+ case ME0Imm:
+ sprintf(dst,"%s (%s),%.2x", InsNames[entry->ins],RegNames[entry->reg],oprom[pos++] );
+ break;
+ case ME1:
+ sprintf(dst,"%s #(%s)", InsNames[entry->ins],RegNames[entry->reg] );break;
+ case ME1Imm:
+ sprintf(dst,"%s #(%s),%.2x", InsNames[entry->ins],RegNames[entry->reg],oprom[pos++] );
+ break;
+ }
+ }
+
+ return pos;
+}
diff --git a/src/emu/cpu/lh5801/5801tbl.c b/src/emu/cpu/lh5801/5801tbl.c
new file mode 100644
index 00000000000..b1861d6104c
--- /dev/null
+++ b/src/emu/cpu/lh5801/5801tbl.c
@@ -0,0 +1,691 @@
+/* assumed
+ res=left+right+c
+ sbc is like adc with inverted carry and right side
+ (decrement, compare the same)
+ (like in the m6502 processors)
+*/
+INLINE UINT8 lh5801_add_generic(int left, int right, int carry)
+{
+ int res=left+right+carry;
+ int v,c;
+
+ lh5801.t&=~(H|V|Z|C);
+
+ if (!(res&0xff)) lh5801.t|=Z;
+ c=res&0x100;
+ if (c) lh5801.t|=C;
+ if (((left&0xf)+(right&0xf)+carry)&0x10) lh5801.t|=H;
+ v=((left&0x7f)+(right&0x7f)+carry)&0x80;
+ if ( (c&&!v)||(!c&&v) ) lh5801.t|=V;
+
+ return res;
+}
+
+INLINE UINT16 lh5801_readop_word(void)
+{
+ UINT16 r;
+ r=cpu_readop(P++)<<8;
+ r|=cpu_readop(P++);
+ return r;
+}
+
+
+INLINE void lh5801_adc(UINT8 data)
+{
+ lh5801.a=lh5801_add_generic(lh5801.a,data,lh5801.t&C);
+}
+
+INLINE void lh5801_add_mem(int addr, UINT8 data)
+{
+ int v=lh5801_add_generic(program_read_byte(addr),data,0);
+ program_write_byte(addr,v);
+}
+
+INLINE void lh5801_adr(PAIR *reg)
+{
+ reg->b.l=lh5801_add_generic(reg->b.l,lh5801.a,0);
+ if (lh5801.t&C) {
+ reg->b.h++;
+ }
+}
+
+INLINE void lh5801_sbc(UINT8 data)
+{
+ lh5801.a=lh5801_add_generic(lh5801.a,data^0xff,(lh5801.t&C)^1);
+}
+
+INLINE void lh5801_cpa(UINT8 a, UINT8 b)
+{
+ lh5801_add_generic(a, b^0xff, 1);
+}
+
+INLINE UINT8 lh5801_decimaladd_generic(int left, int right, int carry)
+{
+ int res=(left&0xf)+(right&0xf)+carry;
+ lh5801.t&=~(H|V|Z|C);
+
+ if (res>=10) {
+ res+=6;
+ lh5801.t|=H;
+ }
+ res+=(left&0xf0)+(right&0xf0);
+ if (res>=0xa0) {
+ res+=0x60;
+ lh5801.t|=C;
+ }
+ if (!(res&0xff)) lh5801.t|=Z;
+ //v???
+ return res;
+}
+
+INLINE void lh5801_dca(UINT8 data)
+{
+ lh5801.a=lh5801_decimaladd_generic(lh5801.a, data, lh5801.t&C);
+}
+
+INLINE void lh5801_dcs(UINT8 data)
+{
+ lh5801.a=lh5801_decimaladd_generic(lh5801.a, data^0xff, (lh5801.t&C)^1);
+}
+
+INLINE void lh5801_and(UINT8 data)
+{
+ lh5801.a&=data;
+ lh5801.t&=~Z;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+INLINE void lh5801_and_mem(int addr, UINT8 data)
+{
+ data&=program_read_byte(addr);
+ lh5801.t&=~Z;
+ if (!data) lh5801.t|=Z;
+ program_write_byte(addr,data);
+}
+
+INLINE void lh5801_bit(UINT8 a, UINT8 b)
+{
+ lh5801.t&=~Z;
+ if (!(a&b)) lh5801.t|=Z;
+}
+
+INLINE void lh5801_eor(UINT8 data)
+{
+ lh5801.a^=data;
+ lh5801.t&=~Z;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+INLINE void lh5801_ora(UINT8 data)
+{
+ lh5801.a^=data;
+ lh5801.t&=~Z;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+INLINE void lh5801_ora_mem(int addr, UINT8 data)
+{
+ data|=program_read_byte(addr);
+ lh5801.t&=~Z;
+ if (!data) lh5801.t|=Z;
+ program_write_byte(addr,data);
+}
+
+INLINE void lh5801_lda(UINT8 data)
+{
+ lh5801.a=data;
+ lh5801.t&=~Z;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+INLINE void lh5801_lde(PAIR *reg)
+{
+ // or z flag depends on reg
+ lh5801.a=program_read_byte(reg->w.l--);
+ lh5801.t&=~Z;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+INLINE void lh5801_sde(PAIR *reg)
+{
+ program_write_byte(reg->w.l--, lh5801.a);
+}
+
+INLINE void lh5801_lin(PAIR *reg)
+{
+ // or z flag depends on reg
+ lh5801.a=program_read_byte(reg->w.l++);
+ lh5801.t&=~Z;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+INLINE void lh5801_sin(PAIR *reg)
+{
+ program_write_byte(reg->w.l++, lh5801.a);
+}
+
+INLINE void lh5801_dec(UINT8 *adr)
+{
+ *adr=lh5801_add_generic(*adr,0xff,0);
+}
+
+INLINE void lh5801_inc(UINT8 *adr)
+{
+ *adr=lh5801_add_generic(*adr,1,0);
+}
+
+INLINE void lh5801_pop(void)
+{
+ lh5801.a=program_read_byte(++S);
+ lh5801.t&=~Z;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+INLINE void lh5801_pop_word(PAIR *reg)
+{
+ reg->b.h=program_read_byte(++S);
+ reg->b.l=program_read_byte(++S);
+ // z flag?
+}
+
+INLINE void lh5801_rtn(void)
+{
+ P=program_read_byte(++S)<<8;
+ P|=program_read_byte(++S);
+ change_pc(P);
+}
+
+INLINE void lh5801_rti(void)
+{
+ P=program_read_byte(++S)<<8;
+ P|=program_read_byte(++S);
+ change_pc(P);
+ lh5801.t=program_read_byte(++S);
+}
+
+INLINE void lh5801_push(UINT8 data)
+{
+ program_write_byte(S--, data);
+}
+
+INLINE void lh5801_push_word(UINT16 data)
+{
+ program_write_byte(S--, data&0xff);
+ program_write_byte(S--, data>>8);
+}
+
+INLINE void lh5801_jmp(UINT16 adr)
+{
+ P=adr;
+ change_pc(P);
+}
+
+INLINE void lh5801_branch_plus(int doit)
+{
+ UINT8 t=cpu_readop(P++);
+ if (doit) {
+ lh5801_icount-=3;
+ P+=t;
+ change_pc(P);
+ }
+}
+
+INLINE void lh5801_branch_minus(int doit)
+{
+ UINT8 t=cpu_readop(P++);
+ if (doit) {
+ lh5801_icount-=3;
+ P-=t;
+ change_pc(P);
+ }
+}
+
+INLINE void lh5801_lop(void)
+{
+ UINT8 t=cpu_readop(P++);
+ lh5801_icount-=8;
+ if (UL--) {
+ lh5801_icount-=3;
+ P-=t;
+ change_pc(P);
+ }
+}
+
+INLINE void lh5801_sjp(void)
+{
+ UINT16 n=lh5801_readop_word();
+ lh5801_push_word(P);
+ P=n;
+ change_pc(n);
+}
+
+INLINE void lh5801_vector(int doit, int nr)
+{
+ if (doit) {
+ lh5801_push_word(P);
+ P=program_read_byte(0xff00+nr)<<8;
+ P|=program_read_byte(0xff00+nr+1);
+ change_pc(P);
+ lh5801_icount-=21-8;
+ }
+ lh5801.t&=~Z; // after the jump!?
+}
+
+INLINE void lh5801_aex(void)
+{
+ UINT8 t=lh5801.a;
+ lh5801.a=(t<<4)|(t>>4);
+ // flags?
+}
+
+INLINE void lh5801_drl(int adr)
+{
+ UINT16 t=lh5801.a|(program_read_byte(adr)<<8);
+
+ lh5801.a=t>>8;
+ program_write_byte(adr,t>>4);
+}
+
+INLINE void lh5801_drr(int adr)
+{
+ UINT16 t=program_read_byte(adr)|(lh5801.a<<8);
+
+ lh5801.a=t;
+ program_write_byte(adr,t>>4);
+}
+
+INLINE void lh5801_rol(void)
+{
+ // maybe use of the adder
+ int n=(lh5801.a<<1)|(lh5801.t&C);
+ lh5801.a=n;
+ // flags cvhz
+ lh5801.t&=~(C&Z);
+ if (n&0x100) lh5801.t|=C;
+ if (!(n&0xff)) lh5801.t|=Z;
+}
+
+INLINE void lh5801_ror(void)
+{
+ int n=lh5801.a|((lh5801.t&C)<<8);
+ lh5801.a=n>>1;
+ // flags cvhz
+ lh5801.t&=~(C&Z);
+ lh5801.t|=(n&C);
+ if (!(n&0x1fe)) lh5801.t|=Z;
+}
+
+INLINE void lh5801_shl(void)
+{
+ int nc=lh5801.a&0x80;
+ lh5801.a<<=1;
+ // flags cvhz
+ lh5801.t&=~(C&Z);
+ if (nc) lh5801.t|=C;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+INLINE void lh5801_shr(void)
+{
+ int nc=lh5801.a&1;
+ lh5801.a>>=1;
+ // flags cvhz
+ lh5801.t&=~(C|Z);
+ if (nc) lh5801.t|=C;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+INLINE void lh5801_am(int value)
+{
+ lh5801.tm=value;
+ // jfkas?jfkl?jkd?
+}
+
+INLINE void lh5801_ita(void)
+{
+ if (lh5801.config&&lh5801.config->in) {
+ lh5801.a=lh5801.config->in();
+ } else {
+ lh5801.a=0;
+ }
+ lh5801.t&=~Z;
+ if (!lh5801.a) lh5801.t|=Z;
+}
+
+static void lh5801_instruction_fd(void)
+{
+ int oper;
+ int adr;
+
+ oper=cpu_readop(P++);
+ switch (oper) {
+ case 0x01: lh5801_sbc(program_read_byte(0x10000|X)); lh5801_icount-=11;break;
+ case 0x03: lh5801_adc(program_read_byte(0x10000|X)); lh5801_icount-=11;break;
+ case 0x05: lh5801_lda(program_read_byte(0x10000|X)); lh5801_icount-=10;break;
+ case 0x07: lh5801_cpa(lh5801.a, program_read_byte(0x10000|X)); lh5801_icount-=11;break;
+ case 0x08: X=X;lh5801_icount-=11;break; //!!!
+ case 0x09: lh5801_and(program_read_byte(0x10000|X)); lh5801_icount-=11;break;
+ case 0x0a: lh5801_pop_word(&lh5801.x); lh5801_icount-=15;break;
+ case 0x0b: lh5801_ora(program_read_byte(0x10000|X)); lh5801_icount-=11;break;
+ case 0x0c: lh5801_dcs(program_read_byte(0x10000|X)); lh5801_icount-=17; break;
+ case 0x0d: lh5801_eor(program_read_byte(0x10000|X)); lh5801_icount-=11;break;
+ case 0x0e: program_write_byte(0x10000|X,lh5801.a); lh5801_icount-=10;break;
+ case 0x0f: lh5801_bit(program_read_byte(0x10000|X),lh5801.a); lh5801_icount-=11;break;
+ case 0x11: lh5801_sbc(program_read_byte(0x10000|Y)); lh5801_icount-=11;break;
+ case 0x13: lh5801_adc(program_read_byte(0x10000|Y)); lh5801_icount-=11;break;
+ case 0x15: lh5801_lda(program_read_byte(0x10000|Y)); lh5801_icount-=10;break;
+ case 0x17: lh5801_cpa(lh5801.a, program_read_byte(0x10000|Y)); lh5801_icount-=11;break;
+ case 0x18: X=Y;lh5801_icount-=11;break;
+ case 0x19: lh5801_and(program_read_byte(0x10000|Y)); lh5801_icount-=11;break;
+ case 0x1a: lh5801_pop_word(&lh5801.y); lh5801_icount-=15;break;
+ case 0x1b: lh5801_ora(program_read_byte(0x10000|Y)); lh5801_icount-=11;break;
+ case 0x1c: lh5801_dcs(program_read_byte(0x10000|Y)); lh5801_icount-=17; break;
+ case 0x1d: lh5801_eor(program_read_byte(0x10000|Y)); lh5801_icount-=11;break;
+ case 0x1e: program_write_byte(0x10000|Y,lh5801.a); lh5801_icount-=10;break;
+ case 0x1f: lh5801_bit(program_read_byte(0x10000|Y),lh5801.a); lh5801_icount-=11;break;
+ case 0x21: lh5801_sbc(program_read_byte(0x10000|U)); lh5801_icount-=11;break;
+ case 0x23: lh5801_adc(program_read_byte(0x10000|U)); lh5801_icount-=11;break;
+ case 0x25: lh5801_lda(program_read_byte(0x10000|U)); lh5801_icount-=10;break;
+ case 0x27: lh5801_cpa(lh5801.a, program_read_byte(0x10000|U)); lh5801_icount-=11;break;
+ case 0x28: X=U;lh5801_icount-=11;break;
+ case 0x29: lh5801_and(program_read_byte(0x10000|U)); lh5801_icount-=11;break;
+ case 0x2a: lh5801_pop_word(&lh5801.u); lh5801_icount-=15;break;
+ case 0x2b: lh5801_ora(program_read_byte(0x10000|U)); lh5801_icount-=11;break;
+ case 0x2c: lh5801_dcs(program_read_byte(0x10000|U)); lh5801_icount-=17; break;
+ case 0x2d: lh5801_eor(program_read_byte(0x10000|U)); lh5801_icount-=11;break;
+ case 0x2e: program_write_byte(0x10000|U,lh5801.a); lh5801_icount-=10;break;
+ case 0x2f: lh5801_bit(program_read_byte(0x10000|U),lh5801.a); lh5801_icount-=11;break;
+ case 0x40: lh5801_inc(&XH);lh5801_icount-=9;break;
+ case 0x42: lh5801_dec(&XH);lh5801_icount-=9;break;
+ case 0x48: X=S;lh5801_icount-=11;break;
+ case 0x49: lh5801_and_mem(0x10000|X, cpu_readop(P++)); lh5801_icount-=17;break;
+ case 0x4a: X=X;lh5801_icount-=11;break; //!!!
+ case 0x4b: lh5801_ora_mem(0x10000|X, cpu_readop(P++)); lh5801_icount-=17;break;
+ case 0x4c: lh5801.bf=0;/*off !*/ lh5801_icount-=8;break;
+ case 0x4d: lh5801_bit(program_read_byte(X|0x10000), cpu_readop(P++));lh5801_icount-=14;break;
+ case 0x4e: S=X;lh5801_icount-=11;break;
+ case 0x4f: lh5801_add_mem(0x10000|X, cpu_readop(P++)); lh5801_icount-=17;break;
+ case 0x50: lh5801_inc(&YH);lh5801_icount-=9;break;
+ case 0x52: lh5801_dec(&YH);lh5801_icount-=9;break;
+ case 0x58: X=P;lh5801_icount-=11;break;
+ case 0x59: lh5801_and_mem(0x10000|Y, cpu_readop(P++)); lh5801_icount-=17;break;
+ case 0x5a: Y=X;lh5801_icount-=11;break;
+ case 0x5b: lh5801_ora_mem(0x10000|Y, cpu_readop(P++)); lh5801_icount-=17;break;
+ case 0x5d: lh5801_bit(program_read_byte(Y|0x10000), cpu_readop(P++));lh5801_icount-=14;break;
+ case 0x5e: lh5801_jmp(X);lh5801_icount-=11;break; // P=X
+ case 0x5f: lh5801_add_mem(0x10000|Y, cpu_readop(P++)); lh5801_icount-=17;break;
+ case 0x60: lh5801_inc(&UH);lh5801_icount-=9;break;
+ case 0x62: lh5801_dec(&UH);lh5801_icount-=9;break;
+ case 0x69: lh5801_and_mem(0x10000|U, cpu_readop(P++)); lh5801_icount-=17;break;
+ case 0x6a: U=X;lh5801_icount-=11;break;
+ case 0x6b: lh5801_ora_mem(0x10000|U, cpu_readop(P++)); lh5801_icount-=17;break;
+ case 0x6d: lh5801_bit(program_read_byte(X|0x10000), cpu_readop(P++));lh5801_icount-=14;break;
+ case 0x6f: lh5801_add_mem(0x10000|U, cpu_readop(P++)); lh5801_icount-=17;break;
+ case 0x81: lh5801.t|=IE; /*sie !*/lh5801_icount-=8;break;
+ case 0x88: lh5801_push_word(X); lh5801_icount-=14;break;
+ case 0x8a: lh5801_pop(); lh5801_icount-=12; break;
+ case 0x8c: lh5801_dca(program_read_byte(0x10000|X)); lh5801_icount-=19; break;
+ case 0x8e: /*cdv clears internal devider*/lh5801_icount-=8;break;
+ case 0x98: lh5801_push_word(Y); lh5801_icount-=14;break;
+ case 0x9c: lh5801_dca(program_read_byte(0x10000|Y)); lh5801_icount-=19; break;
+ case 0xa1: lh5801_sbc(program_read_byte(0x10000|lh5801_readop_word())); lh5801_icount-=17;break;
+ case 0xa3: lh5801_adc(program_read_byte(0x10000|lh5801_readop_word())); lh5801_icount-=17;break;
+ case 0xa5: lh5801_lda(program_read_byte(0x10000|lh5801_readop_word())); lh5801_icount-=16;break;
+ case 0xa7: lh5801_cpa(lh5801.a, program_read_byte(0x10000|lh5801_readop_word())); lh5801_icount-=17;break;
+ case 0xa8: lh5801_push_word(U); lh5801_icount-=14;break;
+ case 0xa9: lh5801_and(program_read_byte(0x10000|lh5801_readop_word())); lh5801_icount-=17;break;
+ case 0xaa: lh5801_lda(lh5801.t); lh5801_icount-=9;break;
+ case 0xab: lh5801_ora(program_read_byte(0x10000|lh5801_readop_word())); lh5801_icount-=17;break;
+ case 0xac: lh5801_dca(program_read_byte(0x10000|U)); lh5801_icount-=19; break;
+ case 0xad: lh5801_eor(program_read_byte(0x10000|lh5801_readop_word())); lh5801_icount-=17;break;
+ case 0xae: program_write_byte(0x10000|lh5801_readop_word(),lh5801.a); lh5801_icount-=16;break;
+ case 0xaf: lh5801_bit(program_read_byte(0x10000|lh5801_readop_word()),lh5801.a); lh5801_icount-=17;break;
+ case 0xb1: /*hlt*/lh5801_icount-=8;break;
+ case 0xba: lh5801_ita();lh5801_icount-=9;break;
+ case 0xbe: lh5801.t&=~IE; /*rie !*/lh5801_icount-=8;break;
+ case 0xc0: lh5801.dp=0; /*rdp !*/lh5801_icount-=8;break;
+ case 0xc1: lh5801.dp=1; /*sdp !*/lh5801_icount-=8;break;
+ case 0xc8: lh5801_push(lh5801.a); lh5801_icount-=11;break;
+ case 0xca: lh5801_adr(&lh5801.x);lh5801_icount-=11;break;
+ case 0xcc: /*atp sends a to data bus*/lh5801_icount-=9;break;
+ case 0xce: lh5801_am(lh5801.a); lh5801_icount-=9; break;
+ case 0xd3: lh5801_drr(0x10000|X); lh5801_icount-=16; break;
+ case 0xd7: lh5801_drl(0x10000|X); lh5801_icount-=16; break;
+ case 0xda: lh5801_adr(&lh5801.y);lh5801_icount-=11;break;
+ case 0xde: lh5801_am(lh5801.a|0x100); lh5801_icount-=9; break;
+ case 0xea: lh5801_adr(&lh5801.u);lh5801_icount-=11;break;
+ case 0xe9:
+ adr=lh5801_readop_word()|0x10000;
+ lh5801_and_mem(adr, cpu_readop(P++)); lh5801_icount-=23;
+ break;
+ case 0xeb:
+ adr=lh5801_readop_word()|0x10000;
+ lh5801_ora_mem(adr, cpu_readop(P++)); lh5801_icount-=23;
+ break;
+ case 0xec: lh5801.t=lh5801.a; lh5801_icount-=9;break;
+ case 0xed:
+ adr=lh5801_readop_word()|0x10000;lh5801_bit(program_read_byte(adr), cpu_readop(P++));
+ lh5801_icount-=20;break;
+ case 0xef:
+ adr=lh5801_readop_word()|0x10000;
+ lh5801_add_mem(adr, cpu_readop(P++)); lh5801_icount-=23;
+ break;
+
+ default:
+ logerror("lh5801 illegal opcode at %.4x fd%.2x\n",P-2, oper);
+ }
+}
+
+static void lh5801_instruction(void)
+{
+ int oper;
+ int adr;
+
+ oper=cpu_readop(P++);
+ switch (oper) {
+ case 0x00: lh5801_sbc(XL); lh5801_icount-=6;break;
+ case 0x01: lh5801_sbc(program_read_byte(X)); lh5801_icount-=7;break;
+ case 0x02: lh5801_adc(XL); lh5801_icount-=6;break;
+ case 0x03: lh5801_adc(program_read_byte(X)); lh5801_icount-=7;break;
+ case 0x04: lh5801_lda(XL); lh5801_icount-=5;break;
+ case 0x05: lh5801_lda(program_read_byte(X)); lh5801_icount-=6;break;
+ case 0x06: lh5801_cpa(lh5801.a, XL); lh5801_icount-=6;break;
+ case 0x07: lh5801_cpa(lh5801.a, program_read_byte(X)); lh5801_icount-=7;break;
+ case 0x08: XH=lh5801.a; lh5801_icount-=5; break;
+ case 0x09: lh5801_and(program_read_byte(X)); lh5801_icount-=7;break;
+ case 0x0a: XL=lh5801.a; lh5801_icount-=5; break;
+ case 0x0b: lh5801_ora(program_read_byte(X)); lh5801_icount-=7;break;
+ case 0x0c: lh5801_dcs(program_read_byte(X)); lh5801_icount-=13; break;
+ case 0x0d: lh5801_eor(program_read_byte(X)); lh5801_icount-=7;break;
+ case 0x0e: program_write_byte(X,lh5801.a); lh5801_icount-=6;break;
+ case 0x0f: lh5801_bit(program_read_byte(X),lh5801.a); lh5801_icount-=7;break;
+ case 0x10: lh5801_sbc(YL); lh5801_icount-=6;break;
+ case 0x11: lh5801_sbc(program_read_byte(Y)); lh5801_icount-=7;break;
+ case 0x12: lh5801_adc(YL); lh5801_icount-=6;break;
+ case 0x13: lh5801_adc(program_read_byte(Y)); lh5801_icount-=7;break;
+ case 0x14: lh5801_lda(YL); lh5801_icount-=5;break;
+ case 0x15: lh5801_lda(program_read_byte(Y)); lh5801_icount-=6;break;
+ case 0x16: lh5801_cpa(lh5801.a, YL); lh5801_icount-=6;break;
+ case 0x17: lh5801_cpa(lh5801.a, program_read_byte(Y)); lh5801_icount-=7;break;
+ case 0x18: YH=lh5801.a; lh5801_icount-=5; break;
+ case 0x19: lh5801_and(program_read_byte(Y)); lh5801_icount-=7;break;
+ case 0x1a: YL=lh5801.a; lh5801_icount-=5; break;
+ case 0x1b: lh5801_ora(program_read_byte(Y)); lh5801_icount-=7;break;
+ case 0x1c: lh5801_dcs(program_read_byte(Y)); lh5801_icount-=13; break;
+ case 0x1d: lh5801_eor(program_read_byte(Y)); lh5801_icount-=7;break;
+ case 0x1e: program_write_byte(Y,lh5801.a); lh5801_icount-=6;break;
+ case 0x1f: lh5801_bit(program_read_byte(Y),lh5801.a); lh5801_icount-=7;break;
+ case 0x20: lh5801_sbc(UL); lh5801_icount-=6;break;
+ case 0x21: lh5801_sbc(program_read_byte(U)); lh5801_icount-=7;break;
+ case 0x22: lh5801_adc(UL); lh5801_icount-=6;break;
+ case 0x23: lh5801_adc(program_read_byte(U)); lh5801_icount-=7;break;
+ case 0x24: lh5801_lda(UL); lh5801_icount-=5;break;
+ case 0x25: lh5801_lda(program_read_byte(U)); lh5801_icount-=6;break;
+ case 0x26: lh5801_cpa(lh5801.a, UL); lh5801_icount-=6;break;
+ case 0x27: lh5801_cpa(lh5801.a, program_read_byte(U)); lh5801_icount-=7;break;
+ case 0x28: UH=lh5801.a; lh5801_icount-=5; break;
+ case 0x29: lh5801_and(program_read_byte(U)); lh5801_icount-=7;break;
+ case 0x2a: UL=lh5801.a; lh5801_icount-=5; break;
+ case 0x2b: lh5801_ora(program_read_byte(U)); lh5801_icount-=7;break;
+ case 0x2c: lh5801_dcs(program_read_byte(U)); lh5801_icount-=13; break;
+ case 0x2d: lh5801_eor(program_read_byte(U)); lh5801_icount-=7;break;
+ case 0x2e: program_write_byte(U,lh5801.a); lh5801_icount-=6;break;
+ case 0x2f: lh5801_bit(program_read_byte(U),lh5801.a); lh5801_icount-=7;break;
+ case 0x38: /*nop*/lh5801_icount-=5;break;
+ case 0x40: lh5801_inc(&XL);lh5801_icount-=5;break;
+ case 0x41: lh5801_sin(&lh5801.x); lh5801_icount-=6;break;
+ case 0x42: lh5801_dec(&XL);lh5801_icount-=5;break;
+ case 0x43: lh5801_sde(&lh5801.x); lh5801_icount-=6;break;
+ case 0x44: X++;lh5801_icount-=5;break;
+ case 0x45: lh5801_lin(&lh5801.x);lh5801_icount-=6;break;
+ case 0x46: X--;lh5801_icount-=5;break;
+ case 0x47: lh5801_lde(&lh5801.x);lh5801_icount-=6;break;
+ case 0x48: XH=cpu_readop(P++);lh5801_icount-=6;break;
+ case 0x49: lh5801_and_mem(X, cpu_readop(P++)); lh5801_icount-=13;break;
+ case 0x4a: XL=cpu_readop(P++);lh5801_icount-=6;break;
+ case 0x4b: lh5801_ora_mem(X, cpu_readop(P++)); lh5801_icount-=13;break;
+ case 0x4c: lh5801_cpa(XH, cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0x4d: lh5801_bit(program_read_byte(X), cpu_readop(P++));lh5801_icount-=10;break;
+ case 0x4e: lh5801_cpa(XL, cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0x4f: lh5801_add_mem(X, cpu_readop(P++)); lh5801_icount-=13;break;
+ case 0x50: lh5801_inc(&YL);lh5801_icount-=5;break;
+ case 0x51: lh5801_sin(&lh5801.y); lh5801_icount-=6;break;
+ case 0x52: lh5801_dec(&YL);lh5801_icount-=5;break;
+ case 0x53: lh5801_sde(&lh5801.y); lh5801_icount-=6;break;
+ case 0x54: Y++;lh5801_icount-=5;break;
+ case 0x55: lh5801_lin(&lh5801.y);lh5801_icount-=6;break;
+ case 0x56: Y--;lh5801_icount-=5;break;
+ case 0x57: lh5801_lde(&lh5801.y);lh5801_icount-=6;break;
+ case 0x58: YH=cpu_readop(P++);lh5801_icount-=6;break;
+ case 0x59: lh5801_and_mem(Y, cpu_readop(P++)); lh5801_icount-=13;break;
+ case 0x5a: YL=cpu_readop(P++);lh5801_icount-=6;break;
+ case 0x5b: lh5801_ora_mem(Y, cpu_readop(P++)); lh5801_icount-=13;break;
+ case 0x5c: lh5801_cpa(YH, cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0x5d: lh5801_bit(program_read_byte(Y), cpu_readop(P++));lh5801_icount-=10;break;
+ case 0x5e: lh5801_cpa(YL, cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0x5f: lh5801_add_mem(Y, cpu_readop(P++)); lh5801_icount-=13;break;
+ case 0x60: lh5801_inc(&UL);lh5801_icount-=5;break;
+ case 0x61: lh5801_sin(&lh5801.u); lh5801_icount-=6;break;
+ case 0x62: lh5801_dec(&UL);lh5801_icount-=5;break;
+ case 0x63: lh5801_sde(&lh5801.u); lh5801_icount-=6;break;
+ case 0x64: U++;lh5801_icount-=5;break;
+ case 0x65: lh5801_lin(&lh5801.u);lh5801_icount-=6;break;
+ case 0x66: U--;lh5801_icount-=5;break;
+ case 0x67: lh5801_lde(&lh5801.u);lh5801_icount-=6;break;
+ case 0x68: UH=cpu_readop(P++);lh5801_icount-=6;break;
+ case 0x69: lh5801_and_mem(U, cpu_readop(P++)); lh5801_icount-=13;break;
+ case 0x6a: UL=cpu_readop(P++);lh5801_icount-=6;break;
+ case 0x6b: lh5801_ora_mem(U, cpu_readop(P++)); lh5801_icount-=13;break;
+ case 0x6c: lh5801_cpa(UH, cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0x6d: lh5801_bit(program_read_byte(U), cpu_readop(P++));lh5801_icount-=10;break;
+ case 0x6e: lh5801_cpa(UL, cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0x6f: lh5801_add_mem(U, cpu_readop(P++)); lh5801_icount-=13;break;
+ case 0x80: lh5801_sbc(XH); lh5801_icount-=6;break;
+ case 0x81: lh5801_branch_plus(!(lh5801.t&C)); lh5801_icount-=8; break;
+ case 0x82: lh5801_adc(XH); lh5801_icount-=6;break;
+ case 0x83: lh5801_branch_plus(lh5801.t&C); lh5801_icount-=8; break;
+ case 0x84: lh5801_lda(XH); lh5801_icount-=5;break;
+ case 0x85: lh5801_branch_plus(!(lh5801.t&H)); lh5801_icount-=8; break;
+ case 0x86: lh5801_cpa(lh5801.a, XH); lh5801_icount-=6;break;
+ case 0x87: lh5801_branch_plus(lh5801.t&H); lh5801_icount-=8; break;
+ case 0x88: lh5801_lop(); break;
+ case 0x89: lh5801_branch_plus(!(lh5801.t&Z)); lh5801_icount-=8; break;
+ case 0x8a: lh5801_rti(); lh5801_icount-=14; break;
+ case 0x8b: lh5801_branch_plus(lh5801.t&Z); lh5801_icount-=8; break;
+ case 0x8c: lh5801_dca(program_read_byte(X)); lh5801_icount-=15; break;
+ case 0x8d: lh5801_branch_plus(!(lh5801.t&V)); lh5801_icount-=8; break;
+ case 0x8e: lh5801_branch_plus(1); lh5801_icount-=5; break;
+ case 0x8f: lh5801_branch_plus(lh5801.t&V); lh5801_icount-=8; break;
+ case 0x90: lh5801_sbc(YH); lh5801_icount-=6;break;
+ case 0x91: lh5801_branch_minus(!(lh5801.t&C)); lh5801_icount-=8; break;
+ case 0x92: lh5801_adc(YH); lh5801_icount-=6;break;
+ case 0x93: lh5801_branch_minus(lh5801.t&C); lh5801_icount-=8; break;
+ case 0x94: lh5801_lda(YH); lh5801_icount-=5;break;
+ case 0x95: lh5801_branch_minus(!(lh5801.t&H)); lh5801_icount-=8; break;
+ case 0x96: lh5801_cpa(lh5801.a, YH); lh5801_icount-=6;break;
+ case 0x97: lh5801_branch_minus(lh5801.t&H); lh5801_icount-=8; break;
+ case 0x99: lh5801_branch_minus(!(lh5801.t&Z)); lh5801_icount-=8; break;
+ case 0x9a: lh5801_rtn(); lh5801_icount-=11; break;
+ case 0x9b: lh5801_branch_minus(lh5801.t&Z); lh5801_icount-=8; break;
+ case 0x9c: lh5801_dca(program_read_byte(Y)); lh5801_icount-=15; break;
+ case 0x9d: lh5801_branch_minus(!(lh5801.t&V)); lh5801_icount-=8; break;
+ case 0x9e: lh5801_branch_minus(1); lh5801_icount-=6; break;
+ case 0x9f: lh5801_branch_minus(lh5801.t&V); lh5801_icount-=8; break;
+ case 0xa0: lh5801_sbc(UH); lh5801_icount-=6;break;
+ case 0xa2: lh5801_adc(UH); lh5801_icount-=6;break;
+ case 0xa1: lh5801_sbc(program_read_byte(lh5801_readop_word())); lh5801_icount-=13;break;
+ case 0xa3: lh5801_adc(program_read_byte(lh5801_readop_word())); lh5801_icount-=13;break;
+ case 0xa4: lh5801_lda(UH); lh5801_icount-=5;break;
+ case 0xa5: lh5801_lda(program_read_byte(lh5801_readop_word())); lh5801_icount-=12;break;
+ case 0xa6: lh5801_cpa(lh5801.a, UH); lh5801_icount-=6;break;
+ case 0xa7: lh5801_cpa(lh5801.a, program_read_byte(lh5801_readop_word())); lh5801_icount-=13;break;
+ case 0xa8: lh5801.pv=1;/*spv!*/ lh5801_icount-=4; break;
+ case 0xa9: lh5801_and(program_read_byte(lh5801_readop_word())); lh5801_icount-=13;break;
+ case 0xaa: S=lh5801_readop_word();lh5801_icount-=6;break;
+ case 0xab: lh5801_ora(program_read_byte(lh5801_readop_word())); lh5801_icount-=13;break;
+ case 0xac: lh5801_dca(program_read_byte(U)); lh5801_icount-=15; break;
+ case 0xad: lh5801_eor(program_read_byte(lh5801_readop_word())); lh5801_icount-=13;break;
+ case 0xae: program_write_byte(lh5801_readop_word(),lh5801.a); lh5801_icount-=12;break;
+ case 0xaf: lh5801_bit(program_read_byte(lh5801_readop_word()),lh5801.a); lh5801_icount-=13;break;
+ case 0xb1: lh5801_sbc(cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0xb3: lh5801_adc(cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0xb5: lh5801_lda(cpu_readop(P++)); lh5801_icount-=6;break;
+ case 0xb7: lh5801_cpa(lh5801.a, cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0xb8: lh5801.pv=0;/*rpv!*/ lh5801_icount-=4; break;
+ case 0xb9: lh5801_and(cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0xba: lh5801_jmp(lh5801_readop_word()); lh5801_icount-=12;break;
+ case 0xbb: lh5801_ora(cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0xbd: lh5801_eor(cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0xbe: lh5801_sjp(); lh5801_icount-=19; break;
+ case 0xbf: lh5801_bit(lh5801.a, cpu_readop(P++));lh5801_icount-=7;break;
+ case 0xc1: lh5801_vector(!(lh5801.t&C), cpu_readop(P++)); lh5801_icount-=8;break;
+ case 0xc3: lh5801_vector(lh5801.t&C, cpu_readop(P++)); lh5801_icount-=8;break;
+ case 0xc5: lh5801_vector(!(lh5801.t&H), cpu_readop(P++)); lh5801_icount-=8;break;
+ case 0xc7: lh5801_vector(lh5801.t&H, cpu_readop(P++)); lh5801_icount-=8;break;
+ case 0xc9: lh5801_vector(!(lh5801.t&Z), cpu_readop(P++)); lh5801_icount-=8;break;
+ case 0xcb: lh5801_vector(lh5801.t&Z, cpu_readop(P++)); lh5801_icount-=8;break;
+ case 0xcd: lh5801_vector(1, cpu_readop(P++)); lh5801_icount-=7;break;
+ case 0xcf: lh5801_vector(lh5801.t&V, cpu_readop(P++)); lh5801_icount-=8;break;
+ case 0xd1: lh5801_ror(); lh5801_icount-=6; break;
+ case 0xd3: lh5801_drr(X); lh5801_icount-=12; break;
+ case 0xd5: lh5801_shr(); lh5801_icount-=6; break;
+ case 0xd7: lh5801_drl(X); lh5801_icount-=12; break;
+ case 0xd9: lh5801_shl(); lh5801_icount-=6; break;
+ case 0xdb: lh5801_rol(); lh5801_icount-=6; break;
+ case 0xdd: lh5801_inc(&lh5801.a);lh5801_icount-=5;break;
+ case 0xdf: lh5801_dec(&lh5801.a);lh5801_icount-=5;break;
+ case 0xe1: lh5801.pu=1;/*spu!*/ lh5801_icount-=4; break;
+ case 0xe3: lh5801.pu=0;/*rpu!*/ lh5801_icount-=4; break;
+ case 0xe9:
+ adr=lh5801_readop_word();lh5801_and_mem(adr, cpu_readop(P++));
+ lh5801_icount-=19;break;
+ case 0xeb:
+ adr=lh5801_readop_word();lh5801_ora_mem(adr, cpu_readop(P++));
+ lh5801_icount-=19;break;
+ case 0xed:
+ adr=lh5801_readop_word();lh5801_bit(program_read_byte(adr), cpu_readop(P++));
+ lh5801_icount-=16;break;
+ case 0xef:
+ adr=lh5801_readop_word();
+ lh5801_add_mem(adr, cpu_readop(P++)); lh5801_icount-=19;
+ break;
+ case 0xf1: lh5801_aex(); lh5801_icount-=6; break;
+ case 0xf5: program_write_byte(Y++, program_read_byte(X++)); lh5801_icount-=7; break; //tin
+ case 0xf7: lh5801_cpa(lh5801.a, program_read_byte(X++));lh5801_icount-=7; break; //cin
+ case 0xf9: lh5801.t&=~C;lh5801_icount-=4;break;
+ case 0xfb: lh5801.t|=C;lh5801_icount-=4;break;
+ case 0xfd: lh5801_instruction_fd();break;
+ case 0xc0: case 0xc2: case 0xc4: case 0xc6:
+ case 0xc8: case 0xca: case 0xcc: case 0xce:
+ case 0xd0: case 0xd2: case 0xd4: case 0xd6:
+ case 0xd8: case 0xda: case 0xdc: case 0xde:
+ case 0xe0: case 0xe2: case 0xe4: case 0xe6:
+ case 0xe8: case 0xea: case 0xec: case 0xee:
+ case 0xf0: case 0xf2: case 0xf4: case 0xf6:
+ lh5801_vector(1, oper);lh5801_icount-=4;break;
+ default:
+ logerror("lh5801 illegal opcode at %.4x %.2x\n",P-1, oper);
+ }
+
+}
+
diff --git a/src/emu/cpu/lh5801/lh5801.c b/src/emu/cpu/lh5801/lh5801.c
new file mode 100644
index 00000000000..223a2dee576
--- /dev/null
+++ b/src/emu/cpu/lh5801/lh5801.c
@@ -0,0 +1,281 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * based on info found on an artikel for the tandy trs80 pc2
+ *
+ *****************************************************************************/
+#include "cpuintrf.h"
+#include "debugger.h"
+
+#include "lh5801.h"
+
+//typedef int bool;
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+enum {
+ LH5801_T=1,
+ LH5801_P,
+ LH5801_S,
+ LH5801_U,
+ LH5801_X,
+ LH5801_Y,
+ LH5801_A,
+
+ LH5801_TM,
+ LH5801_IN,
+ LH5801_BF,
+ LH5801_PU,
+ LH5801_PV,
+ LH5801_DP,
+ LH5801_IRQ_STATE
+};
+
+typedef struct
+{
+ const LH5801_CONFIG *config;
+
+ PAIR s, p, u, x, y;
+ int tm; //9 bit
+
+ UINT8 t, a;
+
+ int bf, dp, pu, pv;
+
+ UINT16 oldpc;
+
+ int irq_state;
+
+ int idle;
+} LH5801_Regs;
+
+static int lh5801_icount = 0;
+
+static LH5801_Regs lh5801= { 0 };
+
+#define P lh5801.p.w.l
+#define S lh5801.s.w.l
+#define U lh5801.u.w.l
+#define UL lh5801.u.b.l
+#define UH lh5801.u.b.h
+#define X lh5801.x.w.l
+#define XL lh5801.x.b.l
+#define XH lh5801.x.b.h
+#define Y lh5801.y.w.l
+#define YL lh5801.y.b.l
+#define YH lh5801.y.b.h
+
+#define C 0x01
+#define IE 0x02
+#define Z 0x04
+#define V 0x08
+#define H 0x10
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+#include "5801tbl.c"
+
+static void lh5801_init(int cpu, int clock, const void *config, int (*irqcallback)(int))
+{
+ memset(&lh5801, 0, sizeof(lh5801));
+ lh5801.config = (const LH5801_CONFIG *) config;
+}
+
+static void lh5801_reset(void)
+{
+ P = (program_read_byte(0xfffe)<<8) | program_read_byte(0xffff);
+
+ change_pc(P);
+
+ lh5801.idle=0;
+}
+
+static void lh5801_get_context (void *dst)
+{
+ if( dst )
+ *(LH5801_Regs*)dst = lh5801;
+}
+
+static void lh5801_set_context (void *src)
+{
+ if( src )
+ {
+ lh5801 = *(LH5801_Regs*)src;
+ change_pc(P);
+ }
+}
+
+static int lh5801_execute(int cycles)
+{
+ lh5801_icount = cycles;
+
+ change_pc(P);
+
+ if (lh5801.idle) {
+ lh5801_icount=0;
+ } else {
+ do
+ {
+ lh5801.oldpc = P;
+
+ CALL_MAME_DEBUG;
+ lh5801_instruction();
+
+ } while (lh5801_icount > 0);
+ }
+
+ return cycles - lh5801_icount;
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ lh5801.idle=0;
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void lh5801_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE: set_irq_line(0, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + LH5801_P: P = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + LH5801_S: S = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_U: U = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_X: X = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_Y: Y = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_T: lh5801.t = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_TM: lh5801.tm = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_BF: lh5801.bf = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_PV: lh5801.pv = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_PU: lh5801.pu = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_DP: lh5801.dp = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void lh5801_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(lh5801); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 19; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = lh5801.irq_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = lh5801.oldpc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + LH5801_P: info->i = P; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + LH5801_S: info->i = S; break;
+ case CPUINFO_INT_REGISTER + LH5801_U: info->i = U; break;
+ case CPUINFO_INT_REGISTER + LH5801_X: info->i = X; break;
+ case CPUINFO_INT_REGISTER + LH5801_Y: info->i = Y; break;
+ case CPUINFO_INT_REGISTER + LH5801_T: info->i = lh5801.t; break;
+ case CPUINFO_INT_REGISTER + LH5801_TM: info->i = lh5801.tm; break;
+ case CPUINFO_INT_REGISTER + LH5801_IN: info->i = lh5801.config->in(); break;
+ case CPUINFO_INT_REGISTER + LH5801_BF: info->i = lh5801.bf; break;
+ case CPUINFO_INT_REGISTER + LH5801_PV: info->i = lh5801.pv; break;
+ case CPUINFO_INT_REGISTER + LH5801_PU: info->i = lh5801.pu; break;
+ case CPUINFO_INT_REGISTER + LH5801_DP: info->i = lh5801.dp; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = lh5801_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = lh5801_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = lh5801_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = lh5801_init; break;
+ case CPUINFO_PTR_RESET: info->reset = lh5801_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = NULL; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = lh5801_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = lh5801_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &lh5801_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "LH5801"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "LH5801"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0alpha"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "Copyright (c) 2000 Peter Trauner, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s = cpuintrf_temp_str(), "%s%s%s%s%s%s%s%s",
+ lh5801.t&0x80?"1":"0",
+ lh5801.t&0x40?"1":"0",
+ lh5801.t&0x20?"1":"0",
+ lh5801.t&0x10?"H":".",
+ lh5801.t&8?"V":".",
+ lh5801.t&4?"Z":".",
+ lh5801.t&2?"I":".",
+ lh5801.t&1?"C":".");
+ break;
+
+ case CPUINFO_STR_REGISTER + LH5801_P: sprintf(info->s = cpuintrf_temp_str(), "P:%04X", lh5801.p.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_S: sprintf(info->s = cpuintrf_temp_str(), "S:%04X", lh5801.s.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_U: sprintf(info->s = cpuintrf_temp_str(), "U:%04X", lh5801.u.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_X: sprintf(info->s = cpuintrf_temp_str(), "X:%04X", lh5801.x.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_Y: sprintf(info->s = cpuintrf_temp_str(), "Y:%04X", lh5801.y.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_T: sprintf(info->s = cpuintrf_temp_str(), "T:%02X", lh5801.t); break;
+ case CPUINFO_STR_REGISTER + LH5801_A: sprintf(info->s = cpuintrf_temp_str(), "A:%02X", lh5801.a); break;
+ case CPUINFO_STR_REGISTER + LH5801_TM: sprintf(info->s = cpuintrf_temp_str(), "TM:%03X", lh5801.tm); break;
+ case CPUINFO_STR_REGISTER + LH5801_IN: sprintf(info->s = cpuintrf_temp_str(), "IN:%02X", lh5801.config->in()); break;
+ case CPUINFO_STR_REGISTER + LH5801_PV: sprintf(info->s = cpuintrf_temp_str(), "PV:%04X", lh5801.pv); break;
+ case CPUINFO_STR_REGISTER + LH5801_PU: sprintf(info->s = cpuintrf_temp_str(), "PU:%04X", lh5801.pu); break;
+ case CPUINFO_STR_REGISTER + LH5801_BF: sprintf(info->s = cpuintrf_temp_str(), "BF:%04X", lh5801.bf); break;
+ case CPUINFO_STR_REGISTER + LH5801_DP: sprintf(info->s = cpuintrf_temp_str(), "DP:%04X", lh5801.dp); break;
+ }
+}
diff --git a/src/emu/cpu/lh5801/lh5801.h b/src/emu/cpu/lh5801/lh5801.h
new file mode 100644
index 00000000000..b0bf6a30d84
--- /dev/null
+++ b/src/emu/cpu/lh5801/lh5801.h
@@ -0,0 +1,76 @@
+/*****************************************************************************
+ *
+ * lh5801.h
+ * portable lh5801 emulator interface
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+#ifndef _LH5801_H
+#define _LH5801_H
+
+/*
+lh5801
+
+little endian
+
+ph, pl p
+sh, sl s
+
+xh, xl x
+yh, yl y
+uh, ul u
+
+a A
+
+0 0 0 H V Z IE C
+
+TM 9bit polynominal?
+
+pu pv disp flipflops
+
+bf flipflop (break key connected)
+
+ me0, me1 chip select for 2 64kb memory blocks
+
+in0-in7 input pins
+
+ mi maskable interrupt input (fff8/9)
+ timer fffa/b
+ nmi non .. (fffc/d)
+ reset fffe/f
+e ?
+
+
+
+lh5811 chip
+pa 8bit io
+pb 8bit io
+pc 8bit
+*/
+
+#include "cpuintrf.h"
+
+
+typedef struct {
+ UINT8 (*in)(void);
+} LH5801_CONFIG;
+
+#define LH5801_INT_NONE 0
+#define LH5801_IRQ 1
+
+extern offs_t lh5801_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+
+#endif
diff --git a/src/emu/cpu/m37710/m37710.c b/src/emu/cpu/m37710/m37710.c
new file mode 100644
index 00000000000..5ce1a75b2c7
--- /dev/null
+++ b/src/emu/cpu/m37710/m37710.c
@@ -0,0 +1,1284 @@
+/*
+ Mitsubishi M37702/37710 CPU Emulator
+
+ The 7700 series is based on the WDC 65C816 core, with the following
+ notable changes:
+
+ - Second accumulator called "B" (on the 65816, "A" and "B" were the
+ two 8-bit halves of the 16-bit "C" accumulator).
+ - 6502 emulation mode and XCE instruction are not present.
+ - No NMI line. BRK and the watchdog interrupt are non-maskable, but there
+ is no provision for the traditional 6502/65816 NMI line.
+ - 3-bit interrupt priority levels like the 68000. Interrupts in general
+ are very different from the 65816.
+ - New single-instruction immediate-to-memory move instructions (LDM)
+ replaces STZ.
+ - CLM and SEM (clear and set "M" status bit) replace CLD/SED. Decimal
+ mode is still available via REP/SEP instructions.
+ - INC and DEC (0x1A and 0x3A) switch places for no particular reason.
+ - The microcode bug that caused MVN/NVP to take 2 extra cycles per byte
+ on the 65816 seems to have been fixed.
+ - The WDM (0x42) and BIT immediate (0x89) instructions are now prefixes.
+ 0x42 when used before an instruction involving the A accumulator makes
+ it use the B accumulator instead. 0x89 adds multiply and divide
+ opcodes, which the real 65816 doesn't have.
+ - The 65C816 preserves the upper 8 bits of A when in 8-bit M mode, but
+ not the upper 8 bits of X or Y when in 8-bit X. The 7700 preserves
+ the top bits of all registers in all modes (code in the C74 BIOS
+ starting at d881 requires this!).
+
+ The various 7700 series models differ primarily by their on board
+ peripherals. The 7750 and later models do include some additional
+ instructions, vs. the 770x/1x/2x, notably signed multiply/divide and
+ sign extension opcodes.
+
+ Peripherals common across the 7700 series include: programmable timers,
+ digital I/O ports, and analog to digital converters.
+
+ Reference: 7700 Family Software User's Manual (instruction set)
+ 7702/7703 Family User's Manual (on-board peripherals)
+ 7720 Family User's Manual
+
+ Emulator by R. Belmont.
+ Based on G65816 Emulator by Karl Stenrud.
+
+ History:
+ - v1.0 RB First version, basic operation OK, timers not complete
+ - v1.1 RB Data bus is 16-bit, dozens of bugfixes to IRQs, opcodes,
+ and opcode mapping. New opcodes added, internal timers added.
+ - v1.2 RB Fixed execution outside of bank 0, fixed LDM outside of bank 0,
+ fixed so top 8 bits of X & Y are preserved while in 8-bit mode,
+ added save state support.
+*/
+
+#include "debugger.h"
+#include "m37710cm.h"
+
+#define M37710_DEBUG (0) // enables verbose logging for peripherals, etc.
+
+extern void m37710_set_irq_line(int line, int state);
+
+/* Our CPU structure */
+m37710i_cpu_struct m37710i_cpu = {0};
+
+int m37710_ICount = 0, m37710_fullCount = 0;
+
+/* Temporary Variables */
+uint m37710i_source;
+uint m37710i_destination;
+
+/* interrupt control mapping */
+
+int m37710_irq_levels[M37710_LINE_MAX] =
+{
+ // maskable
+ 0x70, // ADC
+ 0x73, // UART 1 XMIT
+ 0x74, // UART 1 RECV
+ 0x71, // UART 0 XMIT
+ 0x72, // UART 0 RECV
+ 0x7c, // Timer B2
+ 0x7b, // Timer B1
+ 0x7a, // Timer B0
+ 0x79, // Timer A4
+ 0x78, // Timer A3
+ 0x77, // Timer A2
+ 0x76, // Timer A1
+ 0x75, // Timer A0
+ 0x7f, // IRQ 2
+ 0x7e, // IRQ 1
+ 0x7d, // IRQ 0
+
+ // non-maskable
+ 0, // watchdog
+ 0, // debugger control
+ 0, // BRK
+ 0, // divide by zero
+ 0, // reset
+};
+
+static int m37710_irq_vectors[M37710_LINE_MAX] =
+{
+ // maskable C74
+ 0xffd6, // A-D converter c68b
+ 0xffd8, // UART1 transmit c68e
+ 0xffda, // UART1 receive c691
+ 0xffdc, // UART0 transmit c694
+ 0xffde, // UART0 receive c697
+ 0xffe0, // Timer B2 c69a
+ 0xffe2, // Timer B1 c69d
+ 0xffe4, // Timer B0 c6a0
+ 0xffe6, // Timer A4 c6a3
+ 0xffe8, // Timer A3 c6a6
+ 0xffea, // Timer A2 c6a9
+ 0xffec, // Timer A1 c6ac
+ 0xffee, // Timer A0 c6af
+ 0xfff0, // external INT2 pin c6b2
+ 0xfff2, // external INT1 pin c6b5
+ 0xfff4, // external INT0 pin c6b8
+
+ // non-maskable
+ 0xfff6, // watchdog timer
+ 0xfff8, // debugger control (not used in shipping ICs?)
+ 0xfffa, // BRK
+ 0xfffc, // divide by zero
+ 0xfffe, // RESET
+};
+
+// M37710 internal peripherals
+
+#if M37710_DEBUG
+static const char *m37710_rnames[128] =
+{
+ "",
+ "",
+ "Port P0 reg",
+ "Port P1 reg",
+ "Port P0 dir reg",
+ "Port P1 dir reg",
+ "Port P2 reg",
+ "Port P3 reg",
+ "Port P2 dir reg",
+ "Port P3 dir reg",
+ "Port P4 reg",
+ "Port P5 reg",
+ "Port P4 dir reg",
+ "Port P5 dir reg",
+ "Port P6 reg",
+ "Port P7 reg",
+ "Port P6 dir reg", // 16
+ "Port P7 dir reg",
+ "Port P8 reg",
+ "",
+ "Port P8 dir reg",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "A/D control reg",
+ "A/D sweep pin select",
+ "A/D 0", // 32 (0x20)
+ "",
+ "A/D 1",
+ "",
+ "A/D 2",
+ "",
+ "A/D 3",
+ "",
+ "A/D 4",
+ "",
+ "A/D 5",
+ "",
+ "A/D 6",
+ "",
+ "A/D 7",
+ "",
+ "UART0 transmit/recv mode", // 48 (0x30)
+ "UART0 baud rate", // 0x31
+ "UART0 transmit buf L", // 0x32
+ "UART0 transmit buf H", // 0x33
+ "UART0 transmit/recv ctrl 0", // 0x34
+ "UART0 transmit/recv ctrl 1", // 0x35
+ "UART0 recv buf L", // 0x36
+ "UART0 recv buf H", // 0x37
+ "UART1 transmit/recv mode", // 0x38
+ "UART1 baud rate",
+ "UART1 transmit buf L",
+ "UART1 transmit buf H",
+ "UART1 transmit/recv ctrl 0",
+ "UART1 transmit/recv ctrl 1",
+ "UART1 recv buf L",
+ "UART1 recv buf H",
+ "Count start",
+ "",
+ "One-shot start",
+ "",
+ "Up-down register",
+ "",
+ "Timer A0 L",
+ "Timer A0 H",
+ "Timer A1 L",
+ "Timer A1 H",
+ "Timer A2 L",
+ "Timer A2 H",
+ "Timer A3 L",
+ "Timer A3 H",
+ "Timer A4 L",
+ "Timer A4 H",
+ "Timer B0 L",
+ "Timer B0 H",
+ "Timer B1 L",
+ "Timer B1 H",
+ "Timer B2 L",
+ "Timer B2 H",
+ "Timer A0 mode",
+ "Timer A1 mode",
+ "Timer A2 mode",
+ "Timer A3 mode",
+ "Timer A4 mode",
+ "Timer B0 mode",
+ "Timer B1 mode",
+ "Timer B2 mode",
+ "Processor mode",
+ "",
+ "Watchdog reset",
+ "Watchdog frequency",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "A/D IRQ ctrl",
+ "UART0 xmit IRQ ctrl",
+ "UART0 recv IRQ ctrl",
+ "UART1 xmit IRQ ctrl",
+ "UART1 recv IRQ ctrl",
+ "Timer A0 IRQ ctrl",
+ "Timer A1 IRQ ctrl",
+ "Timer A2 IRQ ctrl",
+ "Timer A3 IRQ ctrl",
+ "Timer A4 IRQ ctrl",
+ "Timer B0 IRQ ctrl",
+ "Timer B1 IRQ ctrl",
+ "Timer B2 IRQ ctrl",
+ "INT0 IRQ ctrl",
+ "INT1 IRQ ctrl",
+ "INT2 IRQ ctrl",
+};
+
+static const char *m37710_tnames[8] =
+{
+ "A0", "A1", "A2", "A3", "A4", "B0", "B1", "B2"
+};
+#endif
+
+static TIMER_CALLBACK( m37710_timer_a0_cb)
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ timer_adjust(m37710i_cpu.timers[0], m37710i_cpu.reload[0], cpunum, attotime_zero);
+
+ m37710i_cpu.m37710_regs[m37710_irq_levels[12]] |= 0x04;
+ m37710_set_irq_line(M37710_LINE_TIMERA0, PULSE_LINE);
+ cpu_triggerint(cpunum);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( m37710_timer_a1_cb )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ timer_adjust(m37710i_cpu.timers[1], m37710i_cpu.reload[1], cpunum, attotime_zero);
+
+ m37710i_cpu.m37710_regs[m37710_irq_levels[11]] |= 0x04;
+ m37710_set_irq_line(M37710_LINE_TIMERA1, PULSE_LINE);
+ cpu_triggerint(cpunum);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( m37710_timer_a2_cb )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ timer_adjust(m37710i_cpu.timers[2], m37710i_cpu.reload[2], cpunum, attotime_zero);
+
+ m37710i_cpu.m37710_regs[m37710_irq_levels[10]] |= 0x04;
+ m37710_set_irq_line(M37710_LINE_TIMERA2, PULSE_LINE);
+ cpu_triggerint(cpunum);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( m37710_timer_a3_cb )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ timer_adjust(m37710i_cpu.timers[3], m37710i_cpu.reload[3], cpunum, attotime_zero);
+
+ m37710i_cpu.m37710_regs[m37710_irq_levels[9]] |= 0x04;
+ m37710_set_irq_line(M37710_LINE_TIMERA3, PULSE_LINE);
+ cpu_triggerint(cpunum);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( m37710_timer_a4_cb )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ timer_adjust(m37710i_cpu.timers[4], m37710i_cpu.reload[4], cpunum, attotime_zero);
+
+ m37710i_cpu.m37710_regs[m37710_irq_levels[8]] |= 0x04;
+ m37710_set_irq_line(M37710_LINE_TIMERA4, PULSE_LINE);
+ cpu_triggerint(cpunum);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( m37710_timer_b0_cb )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ timer_adjust(m37710i_cpu.timers[5], m37710i_cpu.reload[5], cpunum, attotime_zero);
+
+ m37710i_cpu.m37710_regs[m37710_irq_levels[7]] |= 0x04;
+ m37710_set_irq_line(M37710_LINE_TIMERB0, PULSE_LINE);
+ cpu_triggerint(cpunum);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( m37710_timer_b1_cb )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ timer_adjust(m37710i_cpu.timers[6], m37710i_cpu.reload[6], cpunum, attotime_zero);
+
+ m37710i_cpu.m37710_regs[m37710_irq_levels[6]] |= 0x04;
+ m37710_set_irq_line(M37710_LINE_TIMERB1, PULSE_LINE);
+ cpu_triggerint(cpunum);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( m37710_timer_b2_cb )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ timer_adjust(m37710i_cpu.timers[7], m37710i_cpu.reload[7], cpunum, attotime_zero);
+
+ m37710i_cpu.m37710_regs[m37710_irq_levels[5]] |= 0x04;
+ m37710_set_irq_line(M37710_LINE_TIMERB2, PULSE_LINE);
+ cpu_triggerint(cpunum);
+ cpuintrf_pop_context();
+}
+
+static void m37710_external_tick(int timer, int state)
+{
+ // we only care if the state is "on"
+ if (!state)
+ {
+ return;
+ }
+
+ // check if enabled
+ if (m37710i_cpu.m37710_regs[0x40] & (1<<timer))
+ {
+ if ((m37710i_cpu.m37710_regs[0x56+timer] & 0x3) == 1)
+ {
+ if (m37710i_cpu.m37710_regs[0x46+(timer*2)] == 0xff)
+ {
+ m37710i_cpu.m37710_regs[0x46+(timer*2)] = 0;
+ m37710i_cpu.m37710_regs[0x46+(timer*2)+1]++;
+ }
+ else
+ {
+ m37710i_cpu.m37710_regs[0x46+(timer*2)]++;
+ }
+ }
+ else
+ {
+ logerror("M37710: external tick for timer %d, not in event counter mode!\n", timer);
+ }
+ }
+}
+
+static void m37710_recalc_timer(int timer)
+{
+ int cpunum = cpu_getactivecpu();
+ int tval;
+ static const int tcr[8] = { 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d };
+ attotime time;
+ static const int tscales[4] = { 2, 16, 64, 512 };
+
+ // check if enabled
+ if (m37710i_cpu.m37710_regs[0x40] & (1<<timer))
+ {
+ #if M37710_DEBUG
+ mame_printf_debug("Timer %d (%s) is enabled\n", timer, m37710_tnames[timer]);
+ #endif
+
+ // set the timer's value
+ tval = m37710i_cpu.m37710_regs[0x46+(timer*2)] | (m37710i_cpu.m37710_regs[0x47+(timer*2)]<<8);
+
+ // check timer's mode
+ // modes are slightly different between timer groups A and B
+ if (timer < 5)
+ {
+ switch (m37710i_cpu.m37710_regs[0x56+timer] & 0x3)
+ {
+ case 0: // timer mode
+ time = attotime_mul(ATTOTIME_IN_HZ(16000000), tscales[m37710i_cpu.m37710_regs[tcr[timer]]>>6]);
+ time = attotime_mul(time, tval + 1);
+
+ #if M37710_DEBUG
+ mame_printf_debug("Timer %d in timer mode, %f Hz\n", timer, 1.0 / attotime_to_double(time));
+ #endif
+
+ timer_adjust(m37710i_cpu.timers[timer], time, cpunum, attotime_zero);
+ m37710i_cpu.reload[timer] = time;
+ break;
+
+ case 1: // event counter mode
+ #if M37710_DEBUG
+ mame_printf_debug("Timer %d in event counter mode\n", timer);
+ #endif
+ break;
+
+ case 2: // one-shot pulse mode
+ #if M37710_DEBUG
+ mame_printf_debug("Timer %d in one-shot mode\n", timer);
+ #endif
+ break;
+
+ case 3: // PWM mode
+ #if M37710_DEBUG
+ mame_printf_debug("Timer %d in PWM mode\n", timer);
+ #endif
+ break;
+ }
+ }
+ else
+ {
+ switch (m37710i_cpu.m37710_regs[0x56+timer] & 0x3)
+ {
+ case 0: // timer mode
+ time = attotime_mul(ATTOTIME_IN_HZ(16000000), tscales[m37710i_cpu.m37710_regs[tcr[timer]]>>6]);
+ time = attotime_mul(time, tval + 1);
+
+ #if M37710_DEBUG
+ mame_printf_debug("Timer %d in timer mode, %f Hz\n", timer, 1.0 / attotime_to_double(time));
+ #endif
+
+ timer_adjust(m37710i_cpu.timers[timer], time, cpunum, attotime_zero);
+ m37710i_cpu.reload[timer] = time;
+ break;
+
+ case 1: // event counter mode
+ #if M37710_DEBUG
+ mame_printf_debug("Timer %d in event counter mode\n", timer);
+ #endif
+ break;
+
+ case 2: // pulse period/pulse width measurement mode
+ #if M37710_DEBUG
+ mame_printf_debug("Timer %d in pulse period/width measurement mode\n", timer);
+ #endif
+ break;
+
+ case 3:
+ #if M37710_DEBUG
+ mame_printf_debug("Timer %d in unknown mode!\n", timer);
+ #endif
+ break;
+ }
+ }
+ }
+}
+
+static UINT8 m37710_internal_r(int offset)
+{
+ #if M37710_DEBUG
+ if (offset > 1)
+ logerror("m37710_internal_r from %02x: %s (PC=%x)\n", (int)offset, m37710_rnames[(int)offset], REG_PB<<16 | REG_PC);
+ #endif
+
+ switch (offset)
+ {
+ case 2: // p0
+ return io_read_byte_8(M37710_PORT0);
+ break;
+ case 3: // p1
+ return io_read_byte_8(M37710_PORT1);
+ break;
+ case 6: // p2
+ return io_read_byte_8(M37710_PORT2);
+ break;
+ case 7: // p3
+ return io_read_byte_8(M37710_PORT3);
+ break;
+ case 0xa: // p4
+ return io_read_byte_8(M37710_PORT4);
+ break;
+ case 0xb: // p5
+ return io_read_byte_8(M37710_PORT5);
+ break;
+ case 0xe: // p6
+ return io_read_byte_8(M37710_PORT6);
+ break;
+ case 0xf: // p7
+ return io_read_byte_8(M37710_PORT7);
+ break;
+ case 0x12: // p8
+ return io_read_byte_8(M37710_PORT8);
+ break;
+
+ case 0x20:
+ return io_read_byte_8(M37710_ADC0_L);
+ break;
+ case 0x21:
+ return io_read_byte_8(M37710_ADC0_H);
+ break;
+ case 0x22:
+ return io_read_byte_8(M37710_ADC1_L);
+ break;
+ case 0x23:
+ return io_read_byte_8(M37710_ADC1_H);
+ break;
+ case 0x24:
+ return io_read_byte_8(M37710_ADC2_L);
+ break;
+ case 0x25:
+ return io_read_byte_8(M37710_ADC2_H);
+ break;
+ case 0x26:
+ return io_read_byte_8(M37710_ADC3_L);
+ break;
+ case 0x27:
+ return io_read_byte_8(M37710_ADC3_H);
+ break;
+ case 0x28:
+ return io_read_byte_8(M37710_ADC4_L);
+ break;
+ case 0x29:
+ return io_read_byte_8(M37710_ADC4_H);
+ break;
+ case 0x2a:
+ return io_read_byte_8(M37710_ADC5_L);
+ break;
+ case 0x2b:
+ return io_read_byte_8(M37710_ADC5_H);
+ break;
+ case 0x2c:
+ return io_read_byte_8(M37710_ADC6_L);
+ break;
+ case 0x2d:
+ return io_read_byte_8(M37710_ADC6_H);
+ break;
+ case 0x2e:
+ return io_read_byte_8(M37710_ADC7_L);
+ break;
+ case 0x2f:
+ return io_read_byte_8(M37710_ADC7_H);
+ break;
+ case 0x35:
+ return 0xff; // UART control
+ break;
+
+ case 0x70: // A/D IRQ control
+ return m37710i_cpu.m37710_regs[offset] | 8;
+ break;
+ }
+
+ return m37710i_cpu.m37710_regs[offset];
+}
+
+static void m37710_internal_w(int offset, UINT8 data)
+{
+ int i;
+
+ switch(offset)
+ {
+ case 2: // p0
+ io_write_byte_8(M37710_PORT0, data);
+ return;
+ break;
+ case 3: // p1
+ io_write_byte_8(M37710_PORT1, data);
+ return;
+ break;
+ case 6: // p2
+ io_write_byte_8(M37710_PORT2, data);
+ return;
+ break;
+ case 7: // p3
+ io_write_byte_8(M37710_PORT3, data);
+ return;
+ break;
+ case 0xa: // p4
+ io_write_byte_8(M37710_PORT4, data);
+ return;
+ break;
+ case 0xb: // p5
+ io_write_byte_8(M37710_PORT5, data);
+ return;
+ break;
+ case 0xe: // p6
+ io_write_byte_8(M37710_PORT6, data);
+ return;
+ break;
+ case 0xf: // p7
+ io_write_byte_8(M37710_PORT7, data);
+ return;
+ break;
+ case 0x12: // p8
+ io_write_byte_8(M37710_PORT8, data);
+ return;
+ break;
+
+ case 0x40: // count start
+ for (i = 0; i < 8; i++)
+ {
+ if ((data & (1<<i)) && !(m37710i_cpu.m37710_regs[offset] & (1<<i)))
+ {
+ m37710i_cpu.m37710_regs[offset] |= (1<<i);
+ m37710_recalc_timer(i);
+ }
+ }
+
+ m37710i_cpu.m37710_regs[offset] = data;
+
+ return;
+ break;
+
+ case 0x60: // watchdog reset
+ return;
+ break;
+ }
+
+ m37710i_cpu.m37710_regs[offset] = data;
+
+ #if M37710_DEBUG
+ if (offset >= 0x1e && offset <= 0x40)
+ logerror("m37710_internal_w %x to %02x: %s = %x\n", data, (int)offset, m37710_rnames[(int)offset], m37710i_cpu.m37710_regs[offset]);
+ #endif
+}
+
+static READ16_HANDLER( m37710_internal_word_r )
+{
+ return (m37710_internal_r(offset*2) | m37710_internal_r((offset*2)+1)<<8);
+}
+
+static WRITE16_HANDLER( m37710_internal_word_w )
+{
+ if (mem_mask == 0)
+ {
+ m37710_internal_w((offset*2), data & 0xff);
+ m37710_internal_w((offset*2)+1, data>>8);
+ }
+ else if (mem_mask == 0xff)
+ {
+ m37710_internal_w((offset*2)+1, data>>8);
+ }
+ else if (mem_mask == 0xff00)
+ {
+ m37710_internal_w((offset*2), data & 0xff);
+ }
+}
+
+extern void (*m37710i_opcodes_M0X0[])(void);
+extern void (*m37710i_opcodes42_M0X0[])(void);
+extern void (*m37710i_opcodes89_M0X0[])(void);
+extern uint m37710i_get_reg_M0X0(int regnum);
+extern void m37710i_set_reg_M0X0(int regnum, uint val);
+extern void m37710i_set_line_M0X0(int line, int state);
+extern int m37710i_execute_M0X0(int cycles);
+
+extern void (*m37710i_opcodes_M0X1[])(void);
+extern void (*m37710i_opcodes42_M0X1[])(void);
+extern void (*m37710i_opcodes89_M0X1[])(void);
+extern uint m37710i_get_reg_M0X1(int regnum);
+extern void m37710i_set_reg_M0X1(int regnum, uint val);
+extern void m37710i_set_line_M0X1(int line, int state);
+extern int m37710i_execute_M0X1(int cycles);
+
+extern void (*m37710i_opcodes_M1X0[])(void);
+extern void (*m37710i_opcodes42_M1X0[])(void);
+extern void (*m37710i_opcodes89_M1X0[])(void);
+extern uint m37710i_get_reg_M1X0(int regnum);
+extern void m37710i_set_reg_M1X0(int regnum, uint val);
+extern void m37710i_set_line_M1X0(int line, int state);
+extern int m37710i_execute_M1X0(int cycles);
+
+extern void (*m37710i_opcodes_M1X1[])(void);
+extern void (*m37710i_opcodes42_M1X1[])(void);
+extern void (*m37710i_opcodes89_M1X1[])(void);
+extern uint m37710i_get_reg_M1X1(int regnum);
+extern void m37710i_set_reg_M1X1(int regnum, uint val);
+extern void m37710i_set_line_M1X1(int line, int state);
+extern int m37710i_execute_M1X1(int cycles);
+
+void (**m37710i_opcodes[4])(void) =
+{
+ m37710i_opcodes_M0X0,
+ m37710i_opcodes_M0X1,
+ m37710i_opcodes_M1X0,
+ m37710i_opcodes_M1X1,
+};
+
+void (**m37710i_opcodes2[4])(void) =
+{
+ m37710i_opcodes42_M0X0,
+ m37710i_opcodes42_M0X1,
+ m37710i_opcodes42_M1X0,
+ m37710i_opcodes42_M1X1,
+};
+
+void (**m37710i_opcodes3[4])(void) =
+{
+ m37710i_opcodes89_M0X0,
+ m37710i_opcodes89_M0X1,
+ m37710i_opcodes89_M1X0,
+ m37710i_opcodes89_M1X1,
+};
+
+uint (*m37710i_get_reg[4])(int regnum) =
+{
+ m37710i_get_reg_M0X0,
+ m37710i_get_reg_M0X1,
+ m37710i_get_reg_M1X0,
+ m37710i_get_reg_M1X1,
+};
+
+void (*m37710i_set_reg[4])(int regnum, uint val) =
+{
+ m37710i_set_reg_M0X0,
+ m37710i_set_reg_M0X1,
+ m37710i_set_reg_M1X0,
+ m37710i_set_reg_M1X1,
+};
+
+void (*m37710i_set_line[4])(int line, int state) =
+{
+ m37710i_set_line_M0X0,
+ m37710i_set_line_M0X1,
+ m37710i_set_line_M1X0,
+ m37710i_set_line_M1X1,
+};
+
+int (*m37710i_execute[4])(int cycles) =
+{
+ m37710i_execute_M0X0,
+ m37710i_execute_M0X1,
+ m37710i_execute_M1X0,
+ m37710i_execute_M1X1,
+};
+
+/* internal functions */
+
+INLINE void m37710i_push_8(uint value)
+{
+ m37710_write_8(REG_S, value);
+ REG_S = MAKE_UINT_16(REG_S-1);
+}
+
+INLINE void m37710i_push_16(uint value)
+{
+ m37710i_push_8(value>>8);
+ m37710i_push_8(value&0xff);
+}
+
+INLINE uint m37710i_get_reg_p(void)
+{
+ return (FLAG_N&0x80) |
+ ((FLAG_V>>1)&0x40) |
+ FLAG_M |
+ FLAG_X |
+ FLAG_D |
+ FLAG_I |
+ ((!FLAG_Z)<<1) |
+ ((FLAG_C>>8)&1);
+}
+
+void m37710i_update_irqs(void)
+{
+ int curirq, pending = LINE_IRQ;
+ int wantedIRQ, curpri;
+
+ if (FLAG_I)
+ {
+ return;
+ }
+
+ curpri = -1;
+ wantedIRQ = -1;
+
+ for (curirq = M37710_LINE_MAX - 1; curirq >= 0; curirq--)
+ {
+ if ((pending & (1 << curirq)))
+ {
+ // this IRQ is set
+ if (m37710_irq_levels[curirq])
+ {
+// logerror("line %d set, level %x curpri %x IPL %x\n", curirq, m37710i_cpu.m37710_regs[m37710_irq_levels[curirq]] & 7, curpri, m37710i_cpu.ipl);
+ // it's maskable, check if the level works
+ if ((m37710i_cpu.m37710_regs[m37710_irq_levels[curirq]] & 7) > curpri)
+ {
+ // also make sure it's acceptable for the current CPU level
+ if ((m37710i_cpu.m37710_regs[m37710_irq_levels[curirq]] & 7) > m37710i_cpu.ipl)
+ {
+ // mark us as the best candidate
+ wantedIRQ = curirq;
+ curpri = m37710i_cpu.m37710_regs[m37710_irq_levels[curirq]] & 7;
+ }
+ }
+ }
+ else
+ {
+ // non-maskable
+ wantedIRQ = curirq;
+ curirq = -1;
+ break; // no more processing, NMIs always win
+ }
+ }
+ }
+
+ if (wantedIRQ != -1)
+ {
+ if (INT_ACK) INT_ACK(wantedIRQ);
+
+ // make sure we're running to service the interrupt
+ CPU_STOPPED &= ~STOP_LEVEL_WAI;
+
+ // indicate we're servicing it now
+ if (m37710_irq_levels[wantedIRQ])
+ {
+ m37710i_cpu.m37710_regs[m37710_irq_levels[wantedIRQ]] &= ~8;
+ }
+
+ // auto-clear if it's an internal line
+ if (wantedIRQ <= 12)
+ {
+ m37710_set_irq_line(wantedIRQ, CLEAR_LINE);
+ }
+
+ // let's do it...
+ // push PB, then PC, then status
+ CLK(8);
+// mame_printf_debug("taking IRQ %d: PC = %06x, SP = %04x, IPL %d\n", wantedIRQ, REG_PB | REG_PC, REG_S, m37710i_cpu.ipl);
+ m37710i_push_8(REG_PB>>16);
+ m37710i_push_16(REG_PC);
+ m37710i_push_8(m37710i_cpu.ipl);
+ m37710i_push_8(m37710i_get_reg_p());
+
+ // set I to 1, set IPL to the interrupt we're taking
+ FLAG_I = IFLAG_SET;
+ m37710i_cpu.ipl = curpri;
+ // then PB=0, PC=(vector)
+ REG_PB = 0;
+ REG_PC = m37710_read_8(m37710_irq_vectors[wantedIRQ]) |
+ m37710_read_8(m37710_irq_vectors[wantedIRQ]+1)<<8;
+// logerror("IRQ @ %06x\n", REG_PB | REG_PC);
+ m37710i_jumping(REG_PB | REG_PC);
+ }
+}
+
+/* external functions */
+
+void m37710_reset(void)
+{
+ /* Start the CPU */
+ CPU_STOPPED = 0;
+
+ /* 37710 boots in full native mode */
+ REG_D = 0;
+ REG_PB = 0;
+ REG_DB = 0;
+ REG_S = (REG_S & 0xff) | 0x100;
+ REG_X &= 0xff;
+ REG_Y &= 0xff;
+ if(!FLAG_M)
+ {
+ REG_B = REG_A & 0xff00;
+ REG_A &= 0xff;
+ }
+ FLAG_M = MFLAG_CLEAR;
+ FLAG_X = XFLAG_CLEAR;
+
+ /* Clear D and set I */
+ FLAG_D = DFLAG_CLEAR;
+ FLAG_I = IFLAG_SET;
+
+ /* Clear all pending interrupts (should we really do this?) */
+ LINE_IRQ = 0;
+ IRQ_DELAY = 0;
+
+ /* Set the function tables to emulation mode */
+ m37710i_set_execution_mode(EXECUTION_MODE_M0X0);
+
+ FLAG_Z = ZFLAG_CLEAR;
+ REG_S = 0x1ff;
+
+ /* Fetch the reset vector */
+ REG_PC = m37710_read_8(0xfffe) | (m37710_read_8(0xffff)<<8);
+ m37710i_jumping(REG_PB | REG_PC);
+}
+
+/* Exit and clean up */
+void m37710_exit(void)
+{
+ /* nothing to do yet */
+}
+
+/* return elapsed cycles in the current slice */
+int m37710_getcycles(void)
+{
+ return (m37710_fullCount - m37710_ICount);
+}
+
+/* yield the current slice */
+void m37710_yield(void)
+{
+ m37710_fullCount = m37710_getcycles();
+
+ m37710_ICount = 0;
+}
+
+/* Execute some instructions */
+int m37710_execute(int cycles)
+{
+ m37710_fullCount = cycles;
+
+ m37710i_update_irqs();
+
+ return FTABLE_EXECUTE(cycles);
+}
+
+
+/* Get the current CPU context */
+static void m37710_get_context(void *dst_context)
+{
+ *(m37710i_cpu_struct*)dst_context = m37710i_cpu;
+}
+
+/* Set the current CPU context */
+void m37710_set_context(void *src_context)
+{
+ m37710i_cpu = *(m37710i_cpu_struct*)src_context;
+ m37710i_jumping(REG_PB | REG_PC);
+}
+
+/* Get the current Program Counter */
+unsigned m37710_get_pc(void)
+{
+ return REG_PC;
+}
+
+/* Set the Program Counter */
+void m37710_set_pc(unsigned val)
+{
+ REG_PC = MAKE_UINT_16(val);
+ m37710_jumping(REG_PB | REG_PC);
+}
+
+/* Get the current Stack Pointer */
+unsigned m37710_get_sp(void)
+{
+ return REG_S;
+}
+
+/* Set the Stack Pointer */
+void m37710_set_sp(unsigned val)
+{
+ REG_S = MAKE_UINT_16(val);
+}
+
+/* Get a register */
+unsigned m37710_get_reg(int regnum)
+{
+ return FTABLE_GET_REG(regnum);
+}
+
+/* Set a register */
+void m37710_set_reg(int regnum, unsigned value)
+{
+ FTABLE_SET_REG(regnum, value);
+}
+
+/* Load a CPU state */
+void m37710_state_load(void *file)
+{
+}
+
+/* Save the current CPU state */
+void m37710_state_save(void *file)
+{
+}
+
+/* Set an interrupt line */
+void m37710_set_irq_line(int line, int state)
+{
+ FTABLE_SET_LINE(line, state);
+}
+
+/* Set the callback that is called when servicing an interrupt */
+void m37710_set_irq_callback(int (*callback)(int))
+{
+ INT_ACK = callback;
+}
+
+/* Disassemble an instruction */
+#ifdef MAME_DEBUG
+#include "m7700ds.h"
+
+static offs_t m37710_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return m7700_disassemble(buffer, (pc&0xffff), pc>>16, oprom, FLAG_M, FLAG_X);
+}
+#endif /* MAME_DEBUG */
+
+static void m37710_restore_state(void)
+{
+ // restore proper function pointers
+ m37710i_set_execution_mode((FLAG_M>>4) | (FLAG_X>>4));
+
+ // make sure the memory system can keep up
+ m37710i_jumping(REG_PB | REG_PC);
+}
+
+void m37710_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ INT_ACK = irqcallback;
+
+ m37710i_cpu.timers[0] = timer_alloc(m37710_timer_a0_cb);
+ m37710i_cpu.timers[1] = timer_alloc(m37710_timer_a1_cb);
+ m37710i_cpu.timers[2] = timer_alloc(m37710_timer_a2_cb);
+ m37710i_cpu.timers[3] = timer_alloc(m37710_timer_a3_cb);
+ m37710i_cpu.timers[4] = timer_alloc(m37710_timer_a4_cb);
+ m37710i_cpu.timers[5] = timer_alloc(m37710_timer_b0_cb);
+ m37710i_cpu.timers[6] = timer_alloc(m37710_timer_b1_cb);
+ m37710i_cpu.timers[7] = timer_alloc(m37710_timer_b2_cb);
+
+ state_save_register_item("M377xx", index, m37710i_cpu.a);
+ state_save_register_item("M377xx", index, m37710i_cpu.b);
+ state_save_register_item("M377xx", index, m37710i_cpu.ba);
+ state_save_register_item("M377xx", index, m37710i_cpu.bb);
+ state_save_register_item("M377xx", index, m37710i_cpu.x);
+ state_save_register_item("M377xx", index, m37710i_cpu.y);
+ state_save_register_item("M377xx", index, m37710i_cpu.s);
+ state_save_register_item("M377xx", index, m37710i_cpu.pc);
+ state_save_register_item("M377xx", index, m37710i_cpu.ppc);
+ state_save_register_item("M377xx", index, m37710i_cpu.pb);
+ state_save_register_item("M377xx", index, m37710i_cpu.db);
+ state_save_register_item("M377xx", index, m37710i_cpu.d);
+ state_save_register_item("M377xx", index, m37710i_cpu.flag_e);
+ state_save_register_item("M377xx", index, m37710i_cpu.flag_m);
+ state_save_register_item("M377xx", index, m37710i_cpu.flag_x);
+ state_save_register_item("M377xx", index, m37710i_cpu.flag_n);
+ state_save_register_item("M377xx", index, m37710i_cpu.flag_v);
+ state_save_register_item("M377xx", index, m37710i_cpu.flag_d);
+ state_save_register_item("M377xx", index, m37710i_cpu.flag_i);
+ state_save_register_item("M377xx", index, m37710i_cpu.flag_z);
+ state_save_register_item("M377xx", index, m37710i_cpu.flag_c);
+ state_save_register_item("M377xx", index, m37710i_cpu.line_irq);
+ state_save_register_item("M377xx", index, m37710i_cpu.ipl);
+ state_save_register_item("M377xx", index, m37710i_cpu.ir);
+ state_save_register_item("M377xx", index, m37710i_cpu.im);
+ state_save_register_item("M377xx", index, m37710i_cpu.im2);
+ state_save_register_item("M377xx", index, m37710i_cpu.im3);
+ state_save_register_item("M377xx", index, m37710i_cpu.im4);
+ state_save_register_item("M377xx", index, m37710i_cpu.irq_delay);
+ state_save_register_item("M377xx", index, m37710i_cpu.irq_level);
+ state_save_register_item("M377xx", index, m37710i_cpu.stopped);
+ state_save_register_item_array("M377xx", index, m37710i_cpu.m37710_regs);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[0].seconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[0].attoseconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[1].seconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[1].attoseconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[2].seconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[2].attoseconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[3].seconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[3].attoseconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[4].seconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[4].attoseconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[5].seconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[5].attoseconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[6].seconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[6].attoseconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[7].seconds);
+ state_save_register_item("M377xx", index, m37710i_cpu.reload[7].attoseconds);
+
+ state_save_register_func_postload(m37710_restore_state);
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void m37710_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_ADC: m37710_set_irq_line(M37710_LINE_ADC, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_IRQ0: m37710_set_irq_line(M37710_LINE_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_IRQ1: m37710_set_irq_line(M37710_LINE_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_IRQ2: m37710_set_irq_line(M37710_LINE_IRQ2, info->i); break;
+
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_TIMERA0TICK: m37710_external_tick(state - CPUINFO_INT_INPUT_STATE - M37710_LINE_TIMERA0TICK, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_TIMERA1TICK: m37710_external_tick(state - CPUINFO_INT_INPUT_STATE - M37710_LINE_TIMERA0TICK, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_TIMERA2TICK: m37710_external_tick(state - CPUINFO_INT_INPUT_STATE - M37710_LINE_TIMERA0TICK, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_TIMERA3TICK: m37710_external_tick(state - CPUINFO_INT_INPUT_STATE - M37710_LINE_TIMERA0TICK, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_TIMERA4TICK: m37710_external_tick(state - CPUINFO_INT_INPUT_STATE - M37710_LINE_TIMERA0TICK, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_TIMERB0TICK: m37710_external_tick(state - CPUINFO_INT_INPUT_STATE - M37710_LINE_TIMERA0TICK, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_TIMERB1TICK: m37710_external_tick(state - CPUINFO_INT_INPUT_STATE - M37710_LINE_TIMERA0TICK, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_TIMERB2TICK: m37710_external_tick(state - CPUINFO_INT_INPUT_STATE - M37710_LINE_TIMERA0TICK, info->i); break;
+
+ case CPUINFO_INT_PC: REG_PB = info->i & 0xff0000; m37710_set_pc(info->i & 0xffff); break;
+ case CPUINFO_INT_SP: m37710_set_sp(info->i); break;
+
+ case CPUINFO_INT_REGISTER + M37710_PC: m37710_set_reg(M37710_PC, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_S: m37710_set_reg(M37710_S, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_P: m37710_set_reg(M37710_P, info->i&0xff); m37710i_cpu.ipl = (info->i>>8)&0xff; break;
+ case CPUINFO_INT_REGISTER + M37710_A: m37710_set_reg(M37710_A, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_X: m37710_set_reg(M37710_X, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_Y: m37710_set_reg(M37710_Y, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_PB: m37710_set_reg(M37710_PB, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_DB: m37710_set_reg(M37710_DB, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_D: m37710_set_reg(M37710_D, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_E: m37710_set_reg(M37710_E, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_NMI_STATE: m37710_set_reg(M37710_NMI_STATE, info->i); break;
+ case CPUINFO_INT_REGISTER + M37710_IRQ_STATE: m37710_set_reg(M37710_IRQ_STATE, info->i); break;
+ }
+}
+
+// On-board RAM and peripherals
+static ADDRESS_MAP_START( m37710_internal_map, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000000, 0x00007f) AM_READWRITE(m37710_internal_word_r, m37710_internal_word_w)
+ AM_RANGE(0x000080, 0x00027f) AM_RAM
+ADDRESS_MAP_END
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void m37710_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(m37710i_cpu); break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 20; /* rough guess */ break;
+ case CPUINFO_INT_INPUT_LINES: info->i = M37710_LINE_MAX; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_IRQ0: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_IRQ1: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_IRQ2: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + M37710_LINE_RESET: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = REG_PPC; break;
+ case CPUINFO_INT_PC: info->i = (REG_PB | REG_PC); break;
+ case CPUINFO_INT_SP: info->i = m37710_get_sp(); break;
+
+ case CPUINFO_INT_REGISTER + M37710_PC: info->i = m37710_get_reg(M37710_PC); break;
+ case CPUINFO_INT_REGISTER + M37710_S: info->i = m37710_get_reg(M37710_S); break;
+ case CPUINFO_INT_REGISTER + M37710_P: info->i = m37710_get_reg(M37710_P) | (m37710i_cpu.ipl<<8); break;
+ case CPUINFO_INT_REGISTER + M37710_A: info->i = m37710_get_reg(M37710_A); break;
+ case CPUINFO_INT_REGISTER + M37710_B: info->i = m37710_get_reg(M37710_B); break;
+ case CPUINFO_INT_REGISTER + M37710_X: info->i = m37710_get_reg(M37710_X); break;
+ case CPUINFO_INT_REGISTER + M37710_Y: info->i = m37710_get_reg(M37710_Y); break;
+ case CPUINFO_INT_REGISTER + M37710_PB: info->i = m37710_get_reg(M37710_PB); break;
+ case CPUINFO_INT_REGISTER + M37710_DB: info->i = m37710_get_reg(M37710_DB); break;
+ case CPUINFO_INT_REGISTER + M37710_D: info->i = m37710_get_reg(M37710_D); break;
+ case CPUINFO_INT_REGISTER + M37710_E: info->i = m37710_get_reg(M37710_E); break;
+ case CPUINFO_INT_REGISTER + M37710_NMI_STATE: info->i = m37710_get_reg(M37710_NMI_STATE); break;
+ case CPUINFO_INT_REGISTER + M37710_IRQ_STATE: info->i = m37710_get_reg(M37710_IRQ_STATE); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m37710_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m37710_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m37710_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m37710_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m37710_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m37710_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m37710_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m37710_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m37710_ICount; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_m37710_internal_map; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO: info->internal_map = 0; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M37710"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "M7700"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.2"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2004-2006 R. Belmont, based on G65816 by Karl Stenerud"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ m37710i_cpu.flag_n & NFLAG_SET ? 'N':'.',
+ m37710i_cpu.flag_v & VFLAG_SET ? 'V':'.',
+ m37710i_cpu.flag_m & MFLAG_SET ? 'M':'.',
+ m37710i_cpu.flag_x & XFLAG_SET ? 'X':'.',
+ m37710i_cpu.flag_d & DFLAG_SET ? 'D':'.',
+ m37710i_cpu.flag_i & IFLAG_SET ? 'I':'.',
+ m37710i_cpu.flag_z == 0 ? 'Z':'.',
+ m37710i_cpu.flag_c & CFLAG_SET ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M37710_PC: sprintf(info->s, "PC:%04X", m37710i_cpu.pc); break;
+ case CPUINFO_STR_REGISTER + M37710_PB: sprintf(info->s, "PB:%02X", m37710i_cpu.pb>>16); break;
+ case CPUINFO_STR_REGISTER + M37710_DB: sprintf(info->s, "DB:%02X", m37710i_cpu.db>>16); break;
+ case CPUINFO_STR_REGISTER + M37710_D: sprintf(info->s, "D:%04X", m37710i_cpu.d); break;
+ case CPUINFO_STR_REGISTER + M37710_S: sprintf(info->s, "S:%04X", m37710i_cpu.s); break;
+ case CPUINFO_STR_REGISTER + M37710_P: sprintf(info->s, "P:%04X",
+ (m37710i_cpu.flag_n&0x80) |
+ ((m37710i_cpu.flag_v>>1)&0x40) |
+ m37710i_cpu.flag_m |
+ m37710i_cpu.flag_x |
+ m37710i_cpu.flag_d |
+ m37710i_cpu.flag_i |
+ ((!m37710i_cpu.flag_z)<<1) |
+ ((m37710i_cpu.flag_c>>8)&1) | (m37710i_cpu.ipl<<8)); break;
+ case CPUINFO_STR_REGISTER + M37710_E: sprintf(info->s, "E:%d", m37710i_cpu.flag_e); break;
+ case CPUINFO_STR_REGISTER + M37710_A: sprintf(info->s, "A:%04X", m37710i_cpu.a | m37710i_cpu.b); break;
+ case CPUINFO_STR_REGISTER + M37710_B: sprintf(info->s, "B:%04X", m37710i_cpu.ba | m37710i_cpu.bb); break;
+ case CPUINFO_STR_REGISTER + M37710_X: sprintf(info->s, "X:%04X", m37710i_cpu.x); break;
+ case CPUINFO_STR_REGISTER + M37710_Y: sprintf(info->s, "Y:%04X", m37710i_cpu.y); break;
+ case CPUINFO_STR_REGISTER + M37710_IRQ_STATE: sprintf(info->s, "IRQ:%X", m37710i_cpu.line_irq); break;
+ }
+}
+
+// 37702 is identical except with an internal ROM, so just change the name
+void m37702_get_info(UINT32 state, cpuinfo *info)
+{
+ if (state == CPUINFO_STR_NAME)
+ {
+ strcpy(info->s, "M37702");
+ return;
+ }
+
+ m37710_get_info(state, info);
+}
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
diff --git a/src/emu/cpu/m37710/m37710.h b/src/emu/cpu/m37710/m37710.h
new file mode 100644
index 00000000000..d8ccc1dc518
--- /dev/null
+++ b/src/emu/cpu/m37710/m37710.h
@@ -0,0 +1,123 @@
+#ifndef HEADER__M37710
+#define HEADER__M37710
+
+/* ======================================================================== */
+/* =============================== COPYRIGHT ============================== */
+/* ======================================================================== */
+/*
+
+M37710 CPU Emulator v0.1
+
+*/
+
+/* ======================================================================== */
+/* =============================== DEFINES ================================ */
+/* ======================================================================== */
+/*
+ Input lines - used with cpunum_set_input_line() and the like.
+ WARNING: these are in the same order as the vector table for simplicity.
+ Do not alter this order!
+*/
+
+enum
+{
+ // these interrupts are maskable
+ M37710_LINE_ADC = 0,
+ M37710_LINE_UART1XMIT,
+ M37710_LINE_UART1RECV,
+ M37710_LINE_UART0XMIT,
+ M37710_LINE_UART0RECV,
+ M37710_LINE_TIMERB2,
+ M37710_LINE_TIMERB1,
+ M37710_LINE_TIMERB0,
+ M37710_LINE_TIMERA4,
+ M37710_LINE_TIMERA3,
+ M37710_LINE_TIMERA2,
+ M37710_LINE_TIMERA1,
+ M37710_LINE_TIMERA0,
+ M37710_LINE_IRQ2,
+ M37710_LINE_IRQ1,
+ M37710_LINE_IRQ0,
+ // these interrupts are non-maskable
+ M37710_LINE_WATCHDOG,
+ M37710_LINE_DEBUG,
+ M37710_LINE_BRK,
+ M37710_LINE_ZERODIV,
+ M37710_LINE_RESET,
+
+ // these are not interrupts, they're signals external hardware can send
+ M37710_LINE_TIMERA0TICK,
+ M37710_LINE_TIMERA1TICK,
+ M37710_LINE_TIMERA2TICK,
+ M37710_LINE_TIMERA3TICK,
+ M37710_LINE_TIMERA4TICK,
+ M37710_LINE_TIMERB0TICK,
+ M37710_LINE_TIMERB1TICK,
+ M37710_LINE_TIMERB2TICK,
+
+ M37710_LINE_MAX
+};
+
+/* Registers - used by m37710_set_reg() and m37710_get_reg() */
+enum
+{
+ M37710_PC=1, M37710_S, M37710_P, M37710_A, M37710_B, M37710_X, M37710_Y,
+ M37710_PB, M37710_DB, M37710_D, M37710_E,
+ M37710_NMI_STATE, M37710_IRQ_STATE
+};
+
+
+/* I/O ports */
+enum
+{
+ M37710_PORT0 = 0,
+ M37710_PORT1, M37710_PORT2, M37710_PORT3, M37710_PORT4,
+ M37710_PORT5, M37710_PORT6, M37710_PORT7, M37710_PORT8,
+
+ M37710_ADC0_L = 0x10, M37710_ADC0_H,
+ M37710_ADC1_L, M37710_ADC1_H, M37710_ADC2_L, M37710_ADC2_H, M37710_ADC3_L, M37710_ADC3_H,
+ M37710_ADC4_L, M37710_ADC4_H, M37710_ADC5_L, M37710_ADC5_H, M37710_ADC6_L, M37710_ADC6_H,
+ M37710_ADC7_L, M37710_ADC7_H,
+
+ M37710_SER0_REC = 0x20,
+ M37710_SER0_XMIT, M37710_SER1_REC, M37710_SER1_XMIT
+};
+
+/* ======================================================================== */
+/* ============================== PROTOTYPES ============================== */
+/* ======================================================================== */
+
+extern int m37710_ICount; /* cycle count */
+
+/* ======================================================================== */
+/* ================================= MAME ================================= */
+/* ======================================================================== */
+
+/* Clean up after the emulation core - Not used in this core - */
+void m37710_exit(void);
+
+/* Save the current CPU state to disk */
+void m37710_state_save(void *file);
+
+/* Load a CPU state from disk */
+void m37710_state_load(void *file);
+
+#undef M37710_CALL_DEBUGGER
+
+#define M37710_CALL_DEBUGGER CALL_MAME_DEBUG
+#define m37710_read_8(addr) program_read_byte_16le(addr)
+#define m37710_write_8(addr,data) program_write_byte_16le(addr,data)
+#define m37710_read_8_immediate(A) program_read_byte_16le(A)
+#define m37710_read_16(addr) program_read_word_16le(addr)
+#define m37710_write_16(addr,data) program_write_word_16le(addr,data)
+#define m37710_jumping(A) change_pc(A)
+#define m37710_branching(A)
+
+
+void m37710_get_info(UINT32 state, cpuinfo *info);
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+#endif /* HEADER__M37710 */
diff --git a/src/emu/cpu/m37710/m37710cm.h b/src/emu/cpu/m37710/m37710cm.h
new file mode 100644
index 00000000000..59568c624ba
--- /dev/null
+++ b/src/emu/cpu/m37710/m37710cm.h
@@ -0,0 +1,318 @@
+#ifndef HEADER__M37710CM
+#define HEADER__M37710CM
+
+#define m37710i_branching(A)
+#define m37710i_jumping(A)
+
+
+/* ======================================================================== */
+/* ================================ INCLUDES ============================== */
+/* ======================================================================== */
+
+#include <limits.h>
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "m37710.h"
+
+
+/* ======================================================================== */
+/* ================================ GENERAL =============================== */
+/* ======================================================================== */
+
+/* Fallback on static if we don't have inline */
+#ifndef INLINE
+#define INLINE static
+#endif
+
+/* This should be set to the default size of your processor (min 16 bit) */
+#undef uint
+#define uint unsigned int
+
+#undef uint8
+#define uint8 unsigned char
+
+#undef int8
+
+/* Allow for architectures that don't have 8-bit sizes */
+#if UCHAR_MAX == 0xff
+#define int8 char
+#define MAKE_INT_8(A) (int8)((A)&0xff)
+#else
+#define int8 int
+INLINE int MAKE_INT_8(int A) {return (A & 0x80) ? A | ~0xff : A & 0xff;}
+#endif /* UCHAR_MAX == 0xff */
+
+#define MAKE_UINT_8(A) ((A)&0xff)
+#define MAKE_UINT_16(A) ((A)&0xffff)
+#define MAKE_UINT_24(A) ((A)&0xffffff)
+
+/* Bits */
+#define BIT_0 0x01
+#define BIT_1 0x02
+#define BIT_2 0x04
+#define BIT_3 0x08
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+
+/* ======================================================================== */
+/* ================================== CPU ================================= */
+/* ======================================================================== */
+
+/* CPU Structure */
+typedef struct
+{
+ uint a; /* Accumulator */
+ uint b; /* holds high byte of accumulator */
+ uint ba; /* Secondary Accumulator */
+ uint bb; /* holds high byte of secondary accumulator */
+ uint x; /* Index Register X */
+ uint y; /* Index Register Y */
+ uint s; /* Stack Pointer */
+ uint pc; /* Program Counter */
+ uint ppc; /* Previous Program Counter */
+ uint pb; /* Program Bank (shifted left 16) */
+ uint db; /* Data Bank (shifted left 16) */
+ uint d; /* Direct Register */
+ uint flag_e; /* Emulation Mode Flag */
+ uint flag_m; /* Memory/Accumulator Select Flag */
+ uint flag_x; /* Index Select Flag */
+ uint flag_n; /* Negative Flag */
+ uint flag_v; /* Overflow Flag */
+ uint flag_d; /* Decimal Mode Flag */
+ uint flag_i; /* Interrupt Mask Flag */
+ uint flag_z; /* Zero Flag (inverted) */
+ uint flag_c; /* Carry Flag */
+ uint line_irq; /* Bitmask of pending IRQs */
+ uint ipl; /* Interrupt priority level (top of PSW) */
+ uint ir; /* Instruction Register */
+ uint im; /* Immediate load value */
+ uint im2; /* Immediate load target */
+ uint im3; /* Immediate load target */
+ uint im4; /* Immediate load target */
+ uint irq_delay; /* delay 1 instruction before checking irq */
+ uint irq_level; /* irq level */
+ int (*int_ack)(int); /* Interrupt Acknowledge */
+ uint stopped; /* Sets how the CPU is stopped */
+ void (**opcodes)(void); /* opcodes with no prefix */
+ void (**opcodes42)(void); /* opcodes with 0x42 prefix */
+ void (**opcodes89)(void); /* opcodes with 0x89 prefix */
+ uint (*get_reg)(int regnum);
+ void (*set_reg)(int regnum, uint val);
+ void (*set_line)(int line, int state);
+ int (*execute)(int cycles);
+
+ // on-board peripheral stuff
+ UINT8 m37710_regs[128];
+ attotime reload[8];
+ emu_timer *timers[8];
+} m37710i_cpu_struct;
+
+extern m37710i_cpu_struct m37710i_cpu;
+extern int m37710_ICount;
+extern uint m37710i_source;
+extern uint m37710i_destination;
+extern uint m37710i_adc_tbl[];
+extern uint m37710i_sbc_tbl[];
+
+extern void (**m37710i_opcodes[])(void);
+extern void (**m37710i_opcodes2[])(void);
+extern void (**m37710i_opcodes3[])(void);
+extern uint (*m37710i_get_reg[])(int regnum);
+extern void (*m37710i_set_reg[])(int regnum, uint val);
+extern void (*m37710i_set_line[])(int line, int state);
+extern int (*m37710i_execute[])(int cycles);
+
+#define REG_A m37710i_cpu.a /* Accumulator */
+#define REG_B m37710i_cpu.b /* Accumulator hi byte */
+#define REG_BA m37710i_cpu.ba /* Secondary Accumulator */
+#define REG_BB m37710i_cpu.bb /* Secondary Accumulator hi byte */
+#define REG_X m37710i_cpu.x /* Index X Register */
+#define REG_Y m37710i_cpu.y /* Index Y Register */
+#define REG_S m37710i_cpu.s /* Stack Pointer */
+#define REG_PC m37710i_cpu.pc /* Program Counter */
+#define REG_PPC m37710i_cpu.ppc /* Previous Program Counter */
+#define REG_PB m37710i_cpu.pb /* Program Bank */
+#define REG_DB m37710i_cpu.db /* Data Bank */
+#define REG_D m37710i_cpu.d /* Direct Register */
+#define FLAG_M m37710i_cpu.flag_m /* Memory/Accumulator Select Flag */
+#define FLAG_X m37710i_cpu.flag_x /* Index Select Flag */
+#define FLAG_N m37710i_cpu.flag_n /* Negative Flag */
+#define FLAG_V m37710i_cpu.flag_v /* Overflow Flag */
+#define FLAG_D m37710i_cpu.flag_d /* Decimal Mode Flag */
+#define FLAG_I m37710i_cpu.flag_i /* Interrupt Mask Flag */
+#define FLAG_Z m37710i_cpu.flag_z /* Zero Flag (inverted) */
+#define FLAG_C m37710i_cpu.flag_c /* Carry Flag */
+#define LINE_IRQ m37710i_cpu.line_irq /* Status of the IRQ line */
+#define REG_IR m37710i_cpu.ir /* Instruction Register */
+#define REG_IM m37710i_cpu.im /* Immediate load value */
+#define REG_IM2 m37710i_cpu.im2 /* Immediate load target */
+#define REG_IM3 m37710i_cpu.im3 /* Immediate load target */
+#define REG_IM4 m37710i_cpu.im4 /* Immediate load target */
+#define INT_ACK m37710i_cpu.int_ack /* Interrupt Acknowledge function pointer */
+#define CLOCKS m37710_ICount /* Clock cycles remaining */
+#define IRQ_DELAY m37710i_cpu.irq_delay /* Delay 1 instruction before checking IRQ */
+#define CPU_STOPPED m37710i_cpu.stopped /* Stopped status of the CPU */
+
+#define FTABLE_OPCODES m37710i_cpu.opcodes
+#define FTABLE_OPCODES2 m37710i_cpu.opcodes42
+#define FTABLE_OPCODES3 m37710i_cpu.opcodes89
+#define FTABLE_GET_REG m37710i_cpu.get_reg
+#define FTABLE_SET_REG m37710i_cpu.set_reg
+#define FTABLE_SET_LINE m37710i_cpu.set_line
+#define FTABLE_EXECUTE m37710i_cpu.execute
+
+#define SRC m37710i_source /* Source Operand */
+#define DST m37710i_destination /* Destination Operand */
+
+#define STOP_LEVEL_WAI 1
+#define STOP_LEVEL_STOP 2
+
+#define EXECUTION_MODE_M0X0 0
+#define EXECUTION_MODE_M0X1 1
+#define EXECUTION_MODE_M1X0 2
+#define EXECUTION_MODE_M1X1 3
+
+INLINE void m37710i_set_execution_mode(uint mode)
+{
+ FTABLE_OPCODES = m37710i_opcodes[mode];
+ FTABLE_OPCODES2 = m37710i_opcodes2[mode];
+ FTABLE_OPCODES3 = m37710i_opcodes3[mode];
+ FTABLE_GET_REG = m37710i_get_reg[mode];
+ FTABLE_SET_REG = m37710i_set_reg[mode];
+ FTABLE_SET_LINE = m37710i_set_line[mode];
+ FTABLE_EXECUTE = m37710i_execute[mode];
+}
+
+/* ======================================================================== */
+/* ================================= CLOCK ================================ */
+/* ======================================================================== */
+
+#define CLK_OP 1
+#define CLK_R8 1
+#define CLK_R16 2
+#define CLK_R24 3
+#define CLK_W8 1
+#define CLK_W16 2
+#define CLK_W24 3
+#define CLK_RMW8 3
+#define CLK_RMW16 5
+
+#define CLK_IMPLIED 1
+#define CLK_IMPLIED 1
+#define CLK_RELATIVE_8 1
+#define CLK_RELATIVE_16 2
+#define CLK_IMM 0
+#define CLK_AI 4
+#define CLK_AXI 4
+#define CLK_A 2
+#define CLK_AL 3
+#define CLK_ALX 3
+#define CLK_AX 2
+#define CLK_AY 2
+#define CLK_D 1
+#define CLK_DI 3
+#define CLK_DIY 3
+#define CLK_DLI 4
+#define CLK_DLIY 4
+#define CLK_DX 2
+#define CLK_DXI 4
+#define CLK_DY 2
+#define CLK_S 2
+#define CLK_SIY 5
+
+/* AX and AY addressing modes take 1 extra cycle when writing */
+#define CLK_W_IMM 0
+#define CLK_W_AI 4
+#define CLK_W_AXI 4
+#define CLK_W_A 2
+#define CLK_W_AL 3
+#define CLK_W_ALX 3
+#define CLK_W_AX 3
+#define CLK_W_AY 3
+#define CLK_W_D 1
+#define CLK_W_DI 3
+#define CLK_W_DIY 3
+#define CLK_W_DLI 4
+#define CLK_W_DLIY 4
+#define CLK_W_DX 2
+#define CLK_W_DXI 4
+#define CLK_W_DY 2
+#define CLK_W_S 2
+#define CLK_W_SIY 5
+
+#define CLK(A) CLOCKS -= (A)
+#define USE_ALL_CLKS() CLOCKS = 0
+
+
+/* ======================================================================== */
+/* ============================ STATUS REGISTER =========================== */
+/* ======================================================================== */
+
+/* Flag positions in Processor Status Register */
+/* common */
+#define FLAGPOS_N BIT_7 /* Negative */
+#define FLAGPOS_V BIT_6 /* Overflow */
+#define FLAGPOS_D BIT_3 /* Decimal Mode */
+#define FLAGPOS_I BIT_2 /* Interrupt Mask */
+#define FLAGPOS_Z BIT_1 /* Zero */
+#define FLAGPOS_C BIT_0 /* Carry */
+/* emulation */
+#define FLAGPOS_R BIT_5 /* Reserved */
+#define FLAGPOS_B BIT_4 /* BRK Instruction */
+/* native */
+#define FLAGPOS_M BIT_5 /* Mem/Reg Select */
+#define FLAGPOS_X BIT_4 /* Index Select */
+
+#define EFLAG_SET 1
+#define EFLAG_CLEAR 0
+#define MFLAG_SET FLAGPOS_M
+#define MFLAG_CLEAR 0
+#define XFLAG_SET FLAGPOS_X
+#define XFLAG_CLEAR 0
+#define NFLAG_SET 0x80
+#define NFLAG_CLEAR 0
+#define VFLAG_SET 0x80
+#define VFLAG_CLEAR 0
+#define DFLAG_SET FLAGPOS_D
+#define DFLAG_CLEAR 0
+#define IFLAG_SET FLAGPOS_I
+#define IFLAG_CLEAR 0
+#define BFLAG_SET FLAGPOS_B
+#define BFLAG_CLEAR 0
+#define ZFLAG_SET 0
+#define ZFLAG_CLEAR 1
+#define CFLAG_SET 0x100
+#define CFLAG_CLEAR 0
+
+/* Codition code tests */
+#define COND_CC() (!(FLAG_C&0x100)) /* Carry Clear */
+#define COND_CS() (FLAG_C&0x100) /* Carry Set */
+#define COND_EQ() (!FLAG_Z) /* Equal */
+#define COND_NE() FLAG_Z /* Not Equal */
+#define COND_MI() (FLAG_N&0x80) /* Minus */
+#define COND_PL() (!(FLAG_N&0x80)) /* Plus */
+#define COND_VC() (!(FLAG_V&0x80)) /* Overflow Clear */
+#define COND_VS() (FLAG_V&0x80) /* Overflow Set */
+
+/* Set Overflow flag in math operations */
+#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R))
+#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8)
+#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D))
+#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8)
+
+#define CFLAG_8(A) (A)
+#define CFLAG_16(A) ((A)>>8)
+#define NFLAG_8(A) (A)
+#define NFLAG_16(A) ((A)>>8)
+
+#define CFLAG_AS_1() ((FLAG_C>>8)&1)
+
+/* update IRQ state (internal use only) */
+void m37710i_update_irqs(void);
+
+/* ======================================================================== */
+/* ================================== CPU ================================= */
+/* ======================================================================== */
+#endif /* HEADER__M37710CM */
diff --git a/src/emu/cpu/m37710/m37710o0.c b/src/emu/cpu/m37710/m37710o0.c
new file mode 100644
index 00000000000..14a01e909bd
--- /dev/null
+++ b/src/emu/cpu/m37710/m37710o0.c
@@ -0,0 +1,3 @@
+#include "m37710cm.h"
+#define EXECUTION_MODE EXECUTION_MODE_M0X0
+#include "m37710op.h"
diff --git a/src/emu/cpu/m37710/m37710o1.c b/src/emu/cpu/m37710/m37710o1.c
new file mode 100644
index 00000000000..123c03d1506
--- /dev/null
+++ b/src/emu/cpu/m37710/m37710o1.c
@@ -0,0 +1,3 @@
+#include "m37710cm.h"
+#define EXECUTION_MODE EXECUTION_MODE_M0X1
+#include "m37710op.h"
diff --git a/src/emu/cpu/m37710/m37710o2.c b/src/emu/cpu/m37710/m37710o2.c
new file mode 100644
index 00000000000..5d4e8f25ff3
--- /dev/null
+++ b/src/emu/cpu/m37710/m37710o2.c
@@ -0,0 +1,3 @@
+#include "m37710cm.h"
+#define EXECUTION_MODE EXECUTION_MODE_M1X0
+#include "m37710op.h"
diff --git a/src/emu/cpu/m37710/m37710o3.c b/src/emu/cpu/m37710/m37710o3.c
new file mode 100644
index 00000000000..038ed9d90db
--- /dev/null
+++ b/src/emu/cpu/m37710/m37710o3.c
@@ -0,0 +1,3 @@
+#include "m37710cm.h"
+#define EXECUTION_MODE EXECUTION_MODE_M1X1
+#include "m37710op.h"
diff --git a/src/emu/cpu/m37710/m37710op.h b/src/emu/cpu/m37710/m37710op.h
new file mode 100644
index 00000000000..5939b385cef
--- /dev/null
+++ b/src/emu/cpu/m37710/m37710op.h
@@ -0,0 +1,2959 @@
+/* ======================================================================== */
+/* ============================= CONFIGURATION ============================ */
+/* ======================================================================== */
+
+#undef FLAG_SET_M
+#undef FLAG_SET_X
+
+#if EXECUTION_MODE == EXECUTION_MODE_M0X0
+#define FLAG_SET_M 0
+#define FLAG_SET_X 0
+#elif EXECUTION_MODE == EXECUTION_MODE_M0X1
+#define FLAG_SET_M 0
+#define FLAG_SET_X 1
+#elif EXECUTION_MODE == EXECUTION_MODE_M1X0
+#define FLAG_SET_M 1
+#define FLAG_SET_X 0
+#elif EXECUTION_MODE == EXECUTION_MODE_M1X1
+#define FLAG_SET_M 1
+#define FLAG_SET_X 1
+#endif
+
+/* ======================================================================== */
+/* ================================= MEMORY =============================== */
+/* ======================================================================== */
+
+#define ADDRESS_37710(A) ((A)&0xffffff)
+
+INLINE uint m37710i_read_8_normal(uint address)
+{
+ address = ADDRESS_37710(address);
+ return m37710_read_8(address);
+}
+
+INLINE uint m37710i_read_8_immediate(uint address)
+{
+ address = ADDRESS_37710(address);
+ return m37710_read_8_immediate(address);
+}
+
+INLINE uint m37710i_read_8_direct(uint address)
+{
+ address = ADDRESS_37710(address);
+ return m37710_read_8(address);
+}
+
+INLINE void m37710i_write_8_normal(uint address, uint value)
+{
+ address = ADDRESS_37710(address);
+ m37710_write_8(address, MAKE_UINT_8(value));
+}
+
+INLINE void m37710i_write_8_direct(uint address, uint value)
+{
+ address = ADDRESS_37710(address);
+ m37710_write_8(address, MAKE_UINT_8(value));
+}
+
+INLINE uint m37710i_read_16_normal(uint address)
+{
+ address = ADDRESS_37710(address);
+ if (address & 1)
+ return m37710i_read_8_normal(address) | m37710i_read_8_normal(address+1)<<8;
+ else
+ return m37710_read_16(address);
+}
+
+INLINE uint m37710i_read_16_immediate(uint address)
+{
+ address = ADDRESS_37710(address);
+ if (address & 1)
+ return m37710_read_8_immediate(address) | m37710_read_8_immediate(address+1)<<8;
+ else
+ return m37710_read_16(address);
+}
+
+INLINE uint m37710i_read_16_direct(uint address)
+{
+ address = ADDRESS_37710(address);
+ if (address & 1)
+ return m37710_read_8(address) | m37710_read_8(address+1)<<8;
+ else
+ return m37710_read_16(address);
+}
+
+INLINE void m37710i_write_16_normal(uint address, uint value)
+{
+ address = ADDRESS_37710(address);
+ if (address & 1)
+ {
+ m37710_write_8(address, value);
+ m37710_write_8(address+1, value>>8);
+ }
+ else
+ m37710_write_16(address, value);
+}
+
+INLINE void m37710i_write_16_direct(uint address, uint value)
+{
+ address = ADDRESS_37710(address);
+ if (address & 1)
+ {
+ m37710_write_8(address, value);
+ m37710_write_8(address+1, value>>8);
+ }
+ else
+ m37710_write_16(address, value);
+}
+
+INLINE uint m37710i_read_24_normal(uint address)
+{
+ return m37710i_read_16_normal(address) |
+ (m37710i_read_8_normal(address+2)<<16);
+}
+
+INLINE uint m37710i_read_24_immediate(uint address)
+{
+ return m37710i_read_16_immediate(address) |
+ (m37710i_read_8_immediate(address+2)<<16);
+}
+
+INLINE uint m37710i_read_24_direct(uint address)
+{
+ return m37710i_read_16_direct(address) |
+ (m37710i_read_8_direct(address+2)<<16);
+}
+
+
+
+/* ======================================================================== */
+/* ================================= STACK ================================ */
+/* ======================================================================== */
+
+INLINE void m37710i_push_8(uint value)
+{
+ m37710i_write_8_normal(REG_S, value);
+ REG_S = MAKE_UINT_16(REG_S-1);
+}
+
+INLINE uint m37710i_pull_8(void)
+{
+ REG_S = MAKE_UINT_16(REG_S+1);
+ return m37710i_read_8_normal(REG_S);
+}
+
+INLINE void m37710i_push_16(uint value)
+{
+ m37710i_push_8(value>>8);
+ m37710i_push_8(value&0xff);
+}
+
+INLINE uint m37710i_pull_16(void)
+{
+ uint res = m37710i_pull_8();
+ return res | (m37710i_pull_8() << 8);
+}
+
+INLINE void m37710i_push_24(uint value)
+{
+ m37710i_push_8(value>>16);
+ m37710i_push_8((value>>8)&0xff);
+ m37710i_push_8(value&0xff);
+}
+
+INLINE uint m37710i_pull_24(void)
+{
+ uint res = m37710i_pull_8();
+ res |= m37710i_pull_8() << 8;
+ return res | (m37710i_pull_8() << 16);
+}
+
+
+/* ======================================================================== */
+/* ============================ PROGRAM COUNTER =========================== */
+/* ======================================================================== */
+
+INLINE void m37710i_jump_16(uint address)
+{
+ REG_PC = MAKE_UINT_16(address);
+ m37710i_jumping(REG_PC);
+}
+
+INLINE void m37710i_jump_24(uint address)
+{
+ REG_PB = address&0xff0000;
+ REG_PC = MAKE_UINT_16(address);
+ m37710i_jumping(REG_PC);
+}
+
+INLINE void m37710i_branch_8(uint offset)
+{
+ REG_PC = MAKE_UINT_16(REG_PC + MAKE_INT_8(offset));
+ m37710i_branching(REG_PC);
+}
+
+INLINE void m37710i_branch_16(uint offset)
+{
+ REG_PC = MAKE_UINT_16(REG_PC + offset);
+ m37710i_branching(REG_PC);
+}
+
+
+/* ======================================================================== */
+/* ============================ STATUS REGISTER =========================== */
+/* ======================================================================== */
+
+/* note: difference from 65816. when switching to 8-bit X/Y, X and Y are *not* truncated
+ to 8 bits! */
+
+INLINE void m37710i_set_flag_mx(uint value)
+{
+#if FLAG_SET_M
+ if(!(value & FLAGPOS_M))
+ {
+ REG_A |= REG_B;
+ REG_B = 0;
+ REG_BA |= REG_BB;
+ REG_BB = 0;
+ FLAG_M = MFLAG_CLEAR;
+ }
+#else
+ if(value & FLAGPOS_M)
+ {
+ REG_B = REG_A & 0xff00;
+ REG_A = MAKE_UINT_8(REG_A);
+ REG_BB = REG_BA & 0xff00;
+ REG_BA = MAKE_UINT_8(REG_BA);
+ FLAG_M = MFLAG_SET;
+ }
+#endif
+#if FLAG_SET_X
+ if(!(value & FLAGPOS_X))
+ {
+ FLAG_X = XFLAG_CLEAR;
+ }
+#else
+ if(value & FLAGPOS_X)
+ {
+ FLAG_X = XFLAG_SET;
+ }
+#endif
+ m37710i_set_execution_mode((FLAG_M>>4) | (FLAG_X>>4));
+}
+
+
+INLINE void m37710i_set_flag_i(uint value)
+{
+ value &= FLAGPOS_I;
+ if(!FLAG_I || value)
+ {
+ FLAG_I = value;
+ return;
+ }
+ FLAG_I = value;
+}
+
+
+
+
+/* Get the Processor Status Register */
+INLINE uint m37710i_get_reg_p(void)
+{
+ return (FLAG_N&0x80) |
+ ((FLAG_V>>1)&0x40) |
+ FLAG_M |
+ FLAG_X |
+ FLAG_D |
+ FLAG_I |
+ ((!FLAG_Z)<<1) |
+ ((FLAG_C>>8)&1);
+}
+
+INLINE void m37710i_set_reg_p(uint value)
+{
+ FLAG_N = value;
+ FLAG_V = value << 1;
+ FLAG_D = value & FLAGPOS_D;
+ FLAG_Z = !(value & FLAGPOS_Z);
+ FLAG_C = value << 8;
+ m37710i_set_flag_mx(value);
+ m37710i_set_flag_i(value);
+}
+
+INLINE void m37710i_set_reg_ipl(uint value)
+{
+ m37710i_cpu.ipl = value & 7;
+}
+
+/* ======================================================================== */
+/* =============================== INTERRUPTS ============================= */
+/* ======================================================================== */
+
+INLINE void m37710i_interrupt_hardware(uint vector)
+{
+ CLK(8);
+ m37710i_push_8(REG_PB>>16);
+ m37710i_push_16(REG_PC);
+ m37710i_push_8(m37710i_get_reg_p());
+ FLAG_D = DFLAG_CLEAR;
+ m37710i_set_flag_i(IFLAG_SET);
+ REG_PB = 0;
+ m37710i_jump_16(m37710i_read_16_normal(vector));
+ if(INT_ACK) INT_ACK(0);
+}
+
+INLINE void m37710i_interrupt_software(uint vector)
+{
+ CLK(8);
+ m37710i_push_8(REG_PB>>16);
+ m37710i_push_16(REG_PC);
+ m37710i_push_8(m37710i_get_reg_p());
+ FLAG_D = DFLAG_CLEAR;
+ m37710i_set_flag_i(IFLAG_SET);
+ REG_PB = 0;
+ m37710i_jump_16(m37710i_read_16_normal(vector));
+}
+
+
+/* ======================================================================== */
+/* ========================== EFFECTIVE ADDRESSES ========================= */
+/* ======================================================================== */
+
+/* Effective-address based memory access macros */
+#define read_8_NORM(A) m37710i_read_8_normal(A)
+#define read_8_IMM(A) m37710i_read_8_immediate(A)
+#define read_8_D(A) m37710i_read_8_direct(A)
+#define read_8_A(A) m37710i_read_8_normal(A)
+#define read_8_AL(A) m37710i_read_8_normal(A)
+#define read_8_DX(A) m37710i_read_8_direct(A)
+#define read_8_DY(A) m37710i_read_8_direct(A)
+#define read_8_AX(A) m37710i_read_8_normal(A)
+#define read_8_ALX(A) m37710i_read_8_normal(A)
+#define read_8_AY(A) m37710i_read_8_normal(A)
+#define read_8_DI(A) m37710i_read_8_normal(A)
+#define read_8_DLI(A) m37710i_read_8_normal(A)
+#define read_8_AI(A) m37710i_read_8_normal(A)
+#define read_8_ALI(A) m37710i_read_8_normal(A)
+#define read_8_DXI(A) m37710i_read_8_normal(A)
+#define read_8_DIY(A) m37710i_read_8_normal(A)
+#define read_8_DLIY(A) m37710i_read_8_normal(A)
+#define read_8_AXI(A) m37710i_read_8_normal(A)
+#define read_8_S(A) m37710i_read_8_normal(A)
+#define read_8_SIY(A) m37710i_read_8_normal(A)
+
+#define read_16_NORM(A) m37710i_read_16_normal(A)
+#define read_16_IMM(A) m37710i_read_16_immediate(A)
+#define read_16_D(A) m37710i_read_16_direct(A)
+#define read_16_A(A) m37710i_read_16_normal(A)
+#define read_16_AL(A) m37710i_read_16_normal(A)
+#define read_16_DX(A) m37710i_read_16_direct(A)
+#define read_16_DY(A) m37710i_read_16_direct(A)
+#define read_16_AX(A) m37710i_read_16_normal(A)
+#define read_16_ALX(A) m37710i_read_16_normal(A)
+#define read_16_AY(A) m37710i_read_16_normal(A)
+#define read_16_DI(A) m37710i_read_16_normal(A)
+#define read_16_DLI(A) m37710i_read_16_normal(A)
+#define read_16_AI(A) m37710i_read_16_normal(A)
+#define read_16_ALI(A) m37710i_read_16_normal(A)
+#define read_16_DXI(A) m37710i_read_16_normal(A)
+#define read_16_DIY(A) m37710i_read_16_normal(A)
+#define read_16_DLIY(A) m37710i_read_16_normal(A)
+#define read_16_AXI(A) m37710i_read_16_normal(A)
+#define read_16_S(A) m37710i_read_16_normal(A)
+#define read_16_SIY(A) m37710i_read_16_normal(A)
+
+#define read_24_NORM(A) m37710i_read_24_normal(A)
+#define read_24_IMM(A) m37710i_read_24_immediate(A)
+#define read_24_D(A) m37710i_read_24_direct(A)
+#define read_24_A(A) m37710i_read_24_normal(A)
+#define read_24_AL(A) m37710i_read_24_normal(A)
+#define read_24_DX(A) m37710i_read_24_direct(A)
+#define read_24_DY(A) m37710i_read_24_direct(A)
+#define read_24_AX(A) m37710i_read_24_normal(A)
+#define read_24_ALX(A) m37710i_read_24_normal(A)
+#define read_24_AY(A) m37710i_read_24_normal(A)
+#define read_24_DI(A) m37710i_read_24_normal(A)
+#define read_24_DLI(A) m37710i_read_24_normal(A)
+#define read_24_AI(A) m37710i_read_24_normal(A)
+#define read_24_ALI(A) m37710i_read_24_normal(A)
+#define read_24_DXI(A) m37710i_read_24_normal(A)
+#define read_24_DIY(A) m37710i_read_24_normal(A)
+#define read_24_DLIY(A) m37710i_read_24_normal(A)
+#define read_24_AXI(A) m37710i_read_24_normal(A)
+#define read_24_S(A) m37710i_read_24_normal(A)
+#define read_24_SIY(A) m37710i_read_24_normal(A)
+
+#define write_8_NORM(A, V) m37710i_write_8_normal(A, V)
+#define write_8_D(A, V) m37710i_write_8_direct(A, V)
+#define write_8_A(A, V) m37710i_write_8_normal(A, V)
+#define write_8_AL(A, V) m37710i_write_8_normal(A, V)
+#define write_8_DX(A, V) m37710i_write_8_direct(A, V)
+#define write_8_DY(A, V) m37710i_write_8_direct(A, V)
+#define write_8_AX(A, V) m37710i_write_8_normal(A, V)
+#define write_8_ALX(A, V) m37710i_write_8_normal(A, V)
+#define write_8_AY(A, V) m37710i_write_8_normal(A, V)
+#define write_8_DI(A, V) m37710i_write_8_normal(A, V)
+#define write_8_DLI(A, V) m37710i_write_8_normal(A, V)
+#define write_8_AI(A, V) m37710i_write_8_normal(A, V)
+#define write_8_ALI(A, V) m37710i_write_8_normal(A, V)
+#define write_8_DXI(A, V) m37710i_write_8_normal(A, V)
+#define write_8_DIY(A, V) m37710i_write_8_normal(A, V)
+#define write_8_DLIY(A, V) m37710i_write_8_normal(A, V)
+#define write_8_AXI(A, V) m37710i_write_8_normal(A, V)
+#define write_8_S(A, V) m37710i_write_8_normal(A, V)
+#define write_8_SIY(A, V) m37710i_write_8_normal(A, V)
+
+#define write_16_NORM(A, V) m37710i_write_16_normal(A, V)
+#define write_16_D(A, V) m37710i_write_16_direct(A, V)
+#define write_16_A(A, V) m37710i_write_16_normal(A, V)
+#define write_16_AL(A, V) m37710i_write_16_normal(A, V)
+#define write_16_DX(A, V) m37710i_write_16_direct(A, V)
+#define write_16_DY(A, V) m37710i_write_16_direct(A, V)
+#define write_16_AX(A, V) m37710i_write_16_normal(A, V)
+#define write_16_ALX(A, V) m37710i_write_16_normal(A, V)
+#define write_16_AY(A, V) m37710i_write_16_normal(A, V)
+#define write_16_DI(A, V) m37710i_write_16_normal(A, V)
+#define write_16_DLI(A, V) m37710i_write_16_normal(A, V)
+#define write_16_AI(A, V) m37710i_write_16_normal(A, V)
+#define write_16_ALI(A, V) m37710i_write_16_normal(A, V)
+#define write_16_DXI(A, V) m37710i_write_16_normal(A, V)
+#define write_16_DIY(A, V) m37710i_write_16_normal(A, V)
+#define write_16_DLIY(A, V) m37710i_write_16_normal(A, V)
+#define write_16_AXI(A, V) m37710i_write_16_normal(A, V)
+#define write_16_S(A, V) m37710i_write_16_normal(A, V)
+#define write_16_SIY(A, V) m37710i_write_16_normal(A, V)
+
+
+#define OPER_8_IMM() read_8_IMM(EA_IMM8())
+#define OPER_8_D() read_8_D(EA_D())
+#define OPER_8_A() read_8_A(EA_A())
+#define OPER_8_AL() read_8_AL(EA_AL())
+#define OPER_8_DX() read_8_DX(EA_DX())
+#define OPER_8_DY() read_8_DY(EA_DY())
+#define OPER_8_AX() read_8_AX(EA_AX())
+#define OPER_8_ALX() read_8_ALX(EA_ALX())
+#define OPER_8_AY() read_8_AY(EA_AY())
+#define OPER_8_DI() read_8_DI(EA_DI())
+#define OPER_8_DLI() read_8_DLI(EA_DLI())
+#define OPER_8_AI() read_8_AI(EA_AI())
+#define OPER_8_ALI() read_8_ALI(EA_ALI())
+#define OPER_8_DXI() read_8_DXI(EA_DXI())
+#define OPER_8_DIY() read_8_DIY(EA_DIY())
+#define OPER_8_DLIY() read_8_DLIY(EA_DLIY())
+#define OPER_8_AXI() read_8_AXI(EA_AXI())
+#define OPER_8_S() read_8_S(EA_S())
+#define OPER_8_SIY() read_8_SIY(EA_SIY())
+
+#define OPER_16_IMM() read_16_IMM(EA_IMM16())
+#define OPER_16_D() read_16_D(EA_D())
+#define OPER_16_A() read_16_A(EA_A())
+#define OPER_16_AL() read_16_AL(EA_AL())
+#define OPER_16_DX() read_16_DX(EA_DX())
+#define OPER_16_DY() read_16_DY(EA_DY())
+#define OPER_16_AX() read_16_AX(EA_AX())
+#define OPER_16_ALX() read_16_ALX(EA_ALX())
+#define OPER_16_AY() read_16_AY(EA_AY())
+#define OPER_16_DI() read_16_DI(EA_DI())
+#define OPER_16_DLI() read_16_DLI(EA_DLI())
+#define OPER_16_AI() read_16_AI(EA_AI())
+#define OPER_16_ALI() read_16_ALI(EA_ALI())
+#define OPER_16_DXI() read_16_DXI(EA_DXI())
+#define OPER_16_DIY() read_16_DIY(EA_DIY())
+#define OPER_16_DLIY() read_16_DLIY(EA_DLIY())
+#define OPER_16_AXI() read_16_AXI(EA_AXI())
+#define OPER_16_S() read_16_S(EA_S())
+#define OPER_16_SIY() read_16_SIY(EA_SIY())
+
+#define OPER_24_IMM() read_24_IMM(EA_IMM24())
+#define OPER_24_D() read_24_D(EA_D())
+#define OPER_24_A() read_24_A(EA_A())
+#define OPER_24_AL() read_24_AL(EA_AL())
+#define OPER_24_DX() read_24_DX(EA_DX())
+#define OPER_24_DY() read_24_DY(EA_DY())
+#define OPER_24_AX() read_24_AX(EA_AX())
+#define OPER_24_ALX() read_24_ALX(EA_ALX())
+#define OPER_24_AY() read_24_AY(EA_AY())
+#define OPER_24_DI() read_24_DI(EA_DI())
+#define OPER_24_DLI() read_24_DLI(EA_DLI())
+#define OPER_24_AI() read_24_AI(EA_AI())
+#define OPER_24_ALI() read_24_ALI(EA_ALI())
+#define OPER_24_DXI() read_24_DXI(EA_DXI())
+#define OPER_24_DIY() read_24_DIY(EA_DIY())
+#define OPER_24_DLIY() read_24_DLIY(EA_DLIY())
+#define OPER_24_AXI() read_24_AXI(EA_AXI())
+#define OPER_24_S() read_24_S(EA_S())
+#define OPER_24_SIY() read_24_SIY(EA_SIY())
+
+INLINE uint EA_IMM8(void) {REG_PC += 1; return REG_PB | MAKE_UINT_16(REG_PC-1);}
+INLINE uint EA_IMM16(void) {REG_PC += 2; return REG_PB | MAKE_UINT_16(REG_PC-2);}
+INLINE uint EA_IMM24(void) {REG_PC += 3; return REG_PB | MAKE_UINT_16(REG_PC-3);}
+INLINE uint EA_D(void) {if(MAKE_UINT_8(REG_D)) CLK(1); return MAKE_UINT_16(REG_D + OPER_8_IMM());}
+INLINE uint EA_A(void) {return REG_DB | OPER_16_IMM();}
+INLINE uint EA_AL(void) {return OPER_24_IMM();}
+INLINE uint EA_DX(void) {return MAKE_UINT_16(REG_D + OPER_8_IMM() + REG_X);}
+INLINE uint EA_DY(void) {return MAKE_UINT_16(REG_D + OPER_8_IMM() + REG_Y);}
+INLINE uint EA_AX(void) {uint tmp = EA_A(); if((tmp^(tmp+REG_X))&0xff00) CLK(1); return tmp + REG_X;}
+INLINE uint EA_ALX(void) {return EA_AL() + REG_X;}
+INLINE uint EA_AY(void) {uint tmp = EA_A(); if((tmp^(tmp+REG_X))&0xff00) CLK(1); return tmp + REG_Y;}
+INLINE uint EA_DI(void) {return REG_DB | OPER_16_D();}
+INLINE uint EA_DLI(void) {return OPER_24_D();}
+INLINE uint EA_AI(void) {return read_16_A(OPER_16_IMM());}
+INLINE uint EA_ALI(void) {return OPER_24_A();}
+INLINE uint EA_DXI(void) {return REG_DB | OPER_16_DX();}
+INLINE uint EA_DIY(void) {uint tmp = REG_DB | OPER_16_D(); if((tmp^(tmp+REG_X))&0xff00) CLK(1); return tmp + REG_Y;}
+INLINE uint EA_DLIY(void) {return OPER_24_D() + REG_Y;}
+INLINE uint EA_AXI(void) {return read_16_AXI(MAKE_UINT_16(OPER_16_IMM() + REG_X));}
+INLINE uint EA_S(void) {return MAKE_UINT_16(REG_S + OPER_8_IMM());}
+INLINE uint EA_SIY(void) {return MAKE_UINT_16(read_16_SIY(REG_S + OPER_8_IMM()) + REG_Y) | REG_DB;}
+
+
+
+/* ======================================================================== */
+/* =========================== OPERATION MACROS =========================== */
+/* ======================================================================== */
+
+/* M37710 Push all */
+#undef OP_PSH
+
+#if FLAG_SET_M
+#if FLAG_SET_X
+#define OP_PSH(MODE) \
+ SRC = OPER_8_##MODE(); \
+ if (SRC&0x1) \
+ m37710i_push_8(REG_A); \
+ if (SRC&0x2) \
+ m37710i_push_8(REG_BA); \
+ if (SRC&0x4) \
+ m37710i_push_8(REG_X); \
+ if (SRC&0x8) \
+ m37710i_push_8(REG_Y); \
+ if (SRC&0x10) \
+ m37710i_push_16(REG_D); \
+ if (SRC&0x20) \
+ m37710i_push_8(REG_DB>>16); \
+ if (SRC&0x40) \
+ m37710i_push_8(REG_PB>>16); \
+ if (SRC&0x80) \
+ m37710i_push_8(m37710i_get_reg_p());
+#else // FLAG_SET_X
+#define OP_PSH(MODE) \
+ SRC = OPER_8_##MODE(); \
+ if (SRC&0x1) \
+ m37710i_push_8(REG_A); \
+ if (SRC&0x2) \
+ m37710i_push_8(REG_BA); \
+ if (SRC&0x4) \
+ m37710i_push_16(REG_X); \
+ if (SRC&0x8) \
+ m37710i_push_16(REG_Y); \
+ if (SRC&0x10) \
+ m37710i_push_16(REG_D); \
+ if (SRC&0x20) \
+ m37710i_push_8(REG_DB>>16); \
+ if (SRC&0x40) \
+ m37710i_push_8(REG_PB>>16); \
+ if (SRC&0x80) \
+ m37710i_push_8(m37710i_get_reg_p());
+#endif // FLAG_SET_X
+#else // FLAG_SET_M
+#if FLAG_SET_X
+#define OP_PSH(MODE) \
+ SRC = OPER_8_##MODE(); \
+ if (SRC&0x1) \
+ m37710i_push_16(REG_A); \
+ if (SRC&0x2) \
+ m37710i_push_16(REG_BA); \
+ if (SRC&0x4) \
+ m37710i_push_8(REG_X); \
+ if (SRC&0x8) \
+ m37710i_push_8(REG_Y); \
+ if (SRC&0x10) \
+ m37710i_push_16(REG_D); \
+ if (SRC&0x20) \
+ m37710i_push_8(REG_DB>>16); \
+ if (SRC&0x40) \
+ m37710i_push_8(REG_PB>>16); \
+ if (SRC&0x80) \
+ m37710i_push_8(m37710i_get_reg_p());
+#else // FLAG_SET_X
+#define OP_PSH(MODE) \
+ SRC = OPER_8_##MODE(); \
+ if (SRC&0x1) \
+ m37710i_push_16(REG_A); \
+ if (SRC&0x2) \
+ m37710i_push_16(REG_BA); \
+ if (SRC&0x4) \
+ m37710i_push_16(REG_X); \
+ if (SRC&0x8) \
+ m37710i_push_16(REG_Y); \
+ if (SRC&0x10) \
+ m37710i_push_16(REG_D); \
+ if (SRC&0x20) \
+ m37710i_push_8(REG_DB>>16); \
+ if (SRC&0x40) \
+ m37710i_push_8(REG_PB>>16); \
+ if (SRC&0x80) \
+ m37710i_push_8(m37710i_get_reg_p());
+#endif // FLAG_SET_X
+#endif // FLAG_SET_M
+
+/* M37710 Pull all */
+#undef OP_PUL
+#if FLAG_SET_M
+#if FLAG_SET_X
+#define OP_PUL(MODE) \
+ SRC = OPER_8_##MODE(); \
+ if (SRC&0x80) \
+ m37710i_set_reg_p(m37710i_pull_8()); \
+ if (SRC&0x40) \
+ REG_PB = m37710i_pull_8() << 16; \
+ if (SRC&0x20) \
+ REG_DB = m37710i_pull_8() << 16; \
+ if (SRC&0x10) \
+ REG_D = m37710i_pull_16(); \
+ if (SRC&0x8) \
+ REG_Y = m37710i_pull_8(); \
+ if (SRC&0x4) \
+ REG_X = m37710i_pull_8(); \
+ if (SRC&0x2) \
+ REG_BA = m37710i_pull_8(); \
+ if (SRC&0x1) \
+ REG_A = m37710i_pull_8();
+#else
+#define OP_PUL(MODE) \
+ SRC = OPER_8_##MODE(); \
+ if (SRC&0x80) \
+ m37710i_set_reg_p(m37710i_pull_8()); \
+ if (SRC&0x40) \
+ REG_PB = m37710i_pull_8() << 16; \
+ if (SRC&0x20) \
+ REG_DB = m37710i_pull_8() << 16; \
+ if (SRC&0x10) \
+ REG_D = m37710i_pull_16(); \
+ if (SRC&0x8) \
+ REG_Y = m37710i_pull_16(); \
+ if (SRC&0x4) \
+ REG_X = m37710i_pull_16(); \
+ if (SRC&0x2) \
+ REG_BA = m37710i_pull_8(); \
+ if (SRC&0x1) \
+ REG_A = m37710i_pull_8();
+#endif
+#else
+#if FLAG_SET_X
+#define OP_PUL(MODE) \
+ SRC = OPER_8_##MODE(); \
+ if (SRC&0x80) \
+ m37710i_set_reg_p(m37710i_pull_8()); \
+ if (SRC&0x40) \
+ REG_PB = m37710i_pull_8() << 16; \
+ if (SRC&0x20) \
+ REG_DB = m37710i_pull_8() << 16; \
+ if (SRC&0x10) \
+ REG_D = m37710i_pull_16(); \
+ if (SRC&0x8) \
+ REG_Y = m37710i_pull_8(); \
+ if (SRC&0x4) \
+ REG_X = m37710i_pull_8(); \
+ if (SRC&0x2) \
+ REG_BA = m37710i_pull_16(); \
+ if (SRC&0x1) \
+ REG_A = m37710i_pull_16();
+#else
+#define OP_PUL(MODE) \
+ SRC = OPER_8_##MODE(); \
+ if (SRC&0x80) \
+ m37710i_set_reg_p(m37710i_pull_8()); \
+ if (SRC&0x40) \
+ REG_PB = m37710i_pull_8() << 16; \
+ if (SRC&0x20) \
+ REG_DB = m37710i_pull_8() << 16; \
+ if (SRC&0x10) \
+ REG_D = m37710i_pull_16(); \
+ if (SRC&0x8) \
+ REG_Y = m37710i_pull_16(); \
+ if (SRC&0x4) \
+ REG_X = m37710i_pull_16(); \
+ if (SRC&0x2) \
+ REG_BA = m37710i_pull_16(); \
+ if (SRC&0x1) \
+ REG_A = m37710i_pull_16();
+#endif
+#endif
+
+/* M37710 Multiply */
+#undef OP_MPY
+#if FLAG_SET_M
+#define OP_MPY(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ SRC = OPER_8_##MODE(); \
+ { int temp = SRC * REG_A; REG_A = temp & 0xff; REG_BA = (temp>>8)&0xff; FLAG_Z = temp; FLAG_N = (temp & 0x8000) ? 1 : 0; FLAG_C = 0; }
+#else
+#define OP_MPY(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ SRC = OPER_16_##MODE(); \
+ { int temp = SRC * REG_A; REG_A = temp & 0xffff; REG_BA = (temp>>16)&0xffff; FLAG_Z = temp; FLAG_N = (temp & 0x80000000) ? 1 : 0; FLAG_C = 0; }
+#endif
+
+/* M37710 Divide */
+#undef OP_DIV
+#if FLAG_SET_M
+#define OP_DIV(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE + 25); \
+ SRC = (REG_BA&0xff)<<8 | (REG_A & 0xff); \
+ DST = OPER_8_##MODE(); \
+ if (DST != 0) { REG_A = SRC / DST; REG_BA = SRC % DST; SRC /= DST; } \
+ FLAG_N = (SRC & 0x80) ? 1 : 0; \
+ FLAG_Z = MAKE_UINT_8(SRC); \
+ if (DST != 0) { FLAG_V = 0; FLAG_C = 0; }
+#else
+#define OP_DIV(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE + 25); \
+ SRC = (REG_BA<<16) | REG_A; \
+ DST = OPER_16_##MODE(); \
+ if (DST != 0) { REG_A = SRC / DST; REG_BA = SRC % DST; SRC /= DST; } \
+ FLAG_N = (SRC & 0x8000) ? 1 : 0; \
+ FLAG_Z = SRC; \
+ if (DST != 0) { FLAG_V = 0; FLAG_C = 0; }
+#endif
+
+/* M37710 Add With Carry */
+#undef OP_ADC
+#if FLAG_SET_M
+#define OP_ADC(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ SRC = OPER_8_##MODE(); \
+ FLAG_C = REG_A + SRC + CFLAG_AS_1(); \
+ if(FLAG_D) \
+ { \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C+=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C+=0x60; \
+ } \
+ FLAG_V = VFLAG_ADD_8(SRC, REG_A, FLAG_C); \
+ FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C)
+#else
+#define OP_ADC(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ SRC = OPER_16_##MODE(); \
+ if(!FLAG_D) \
+ { \
+ FLAG_C = REG_A + SRC + CFLAG_AS_1(); \
+ FLAG_V = VFLAG_ADD_16(SRC, REG_A, FLAG_C); \
+ FLAG_Z = REG_A = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(REG_A); \
+ FLAG_C = CFLAG_16(FLAG_C); \
+ BREAKOUT; \
+ } \
+ FLAG_C = MAKE_UINT_8(REG_A) + MAKE_UINT_8(SRC) + CFLAG_AS_1(); \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C+=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C+=0x60; \
+ FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ \
+ FLAG_C = MAKE_UINT_8(REG_A>>8) + MAKE_UINT_8(SRC>>8) + CFLAG_AS_1(); \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C+=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C+=0x60; \
+ FLAG_Z |= MAKE_UINT_8(FLAG_C) << 8; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ FLAG_V = VFLAG_ADD_16(SRC, REG_A, FLAG_C); \
+ REG_A = FLAG_Z
+#endif
+
+/* M37710 Add With Carry - B accumulator*/
+#undef OP_ADCB
+#if FLAG_SET_M
+#define OP_ADCB(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ SRC = OPER_8_##MODE(); \
+ FLAG_C = REG_BA + SRC + CFLAG_AS_1(); \
+ if(FLAG_D) \
+ { \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C+=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C+=0x60; \
+ } \
+ FLAG_V = VFLAG_ADD_8(SRC, REG_BA, FLAG_C); \
+ FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C)
+#else
+#define OP_ADCB(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ SRC = OPER_16_##MODE(); \
+ if(!FLAG_D) \
+ { \
+ FLAG_C = REG_BA + SRC + CFLAG_AS_1(); \
+ FLAG_V = VFLAG_ADD_16(SRC, REG_BA, FLAG_C); \
+ FLAG_Z = REG_BA = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(REG_BA); \
+ FLAG_C = CFLAG_16(FLAG_C); \
+ BREAKOUT; \
+ } \
+ FLAG_C = MAKE_UINT_8(REG_BA) + MAKE_UINT_8(SRC) + CFLAG_AS_1(); \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C+=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C+=0x60; \
+ FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ \
+ FLAG_C = MAKE_UINT_8(REG_BA>>8) + MAKE_UINT_8(SRC>>8) + CFLAG_AS_1(); \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C+=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C+=0x60; \
+ FLAG_Z |= MAKE_UINT_8(FLAG_C) << 8; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ FLAG_V = VFLAG_ADD_16(SRC, REG_BA, FLAG_C); \
+ REG_BA = FLAG_Z
+#endif
+
+/* M37710 Logical AND with accumulator */
+#undef OP_AND
+#if FLAG_SET_M
+#define OP_AND(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG_A &= OPER_8_##MODE()
+#else
+#define OP_AND(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG_A &= OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG_A)
+#endif
+
+/* M37710 Logical AND with B accumulator */
+#undef OP_ANDB
+#if FLAG_SET_M
+#define OP_ANDB(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG_BA &= OPER_8_##MODE()
+#else
+#define OP_ANDB(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG_BA &= OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG_BA)
+#endif
+
+/* M37710 Arithmetic Shift Left accumulator */
+#undef OP_ASL
+#if FLAG_SET_M
+#define OP_ASL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = REG_A << 1; \
+ FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C)
+#else
+#define OP_ASL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = REG_A << 1; \
+ FLAG_Z = REG_A = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C)
+#endif
+
+/* M37710 Arithmetic Shift Left B accumulator */
+#undef OP_BSL
+#if FLAG_SET_M
+#define OP_BSL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = REG_BA << 1; \
+ FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C)
+#else
+#define OP_BSL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = REG_BA << 1; \
+ FLAG_Z = REG_BA = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C)
+#endif
+
+/* M37710 Arithmetic Shift Left operand */
+#undef OP_ASLM
+#if FLAG_SET_M
+#define OP_ASLM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_C = read_8_##MODE(DST) << 1; \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_ASLM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_C = read_16_##MODE(DST) << 1; \
+ FLAG_Z = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M37710 Branch on Condition Code */
+#undef OP_BCC
+#define OP_BCC(COND) \
+ DST = OPER_8_IMM(); \
+ if(COND) \
+ { \
+ CLK(CLK_OP + CLK_RELATIVE_8 + 1); \
+ m37710i_branch_8(DST); \
+ BREAKOUT; \
+ } \
+ CLK(CLK_OP + CLK_RELATIVE_8); \
+
+/* M37710 Set flags according to bits */
+#undef OP_BIT
+#if FLAG_SET_M
+#define OP_BIT(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = OPER_8_##MODE(); \
+ FLAG_Z = FLAG_N & REG_A; \
+ FLAG_V = FLAG_N << 1
+#else
+#define OP_BIT(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_N = OPER_16_##MODE(); \
+ FLAG_Z = FLAG_N & REG_A; \
+ FLAG_N = NFLAG_16(FLAG_N); \
+ FLAG_V = FLAG_N << 1
+#endif
+
+/* M37710 Set flags according to bits (immediate addressing mode) */
+#undef OP_BITI
+#if FLAG_SET_M
+#define OP_BITI() \
+ CLK(CLK_OP + CLK_R8 + CLK_IMM); \
+ FLAG_Z = REG_A & OPER_8_IMM()
+#else
+#define OP_BITI() \
+ CLK(CLK_OP + CLK_R16 + CLK_IMM); \
+ FLAG_Z = REG_A & OPER_16_IMM()
+#endif
+
+/* M37710 Cause a Break interrupt */
+#undef OP_BRK
+#define OP_BRK() \
+ REG_PC++; \
+ fatalerror("BRK at PC=%06x", REG_PB|REG_PC); \
+ m37710i_interrupt_software(0xfffa)
+
+/* M37710 Branch Always */
+#undef OP_BRA
+#define OP_BRA() \
+ CLK(CLK_OP + CLK_IMPLIED + CLK_RELATIVE_8); \
+ m37710i_branch_8(OPER_8_IMM())
+
+/* M37710 Branch Always Long */
+#undef OP_BRL
+#define OP_BRL() \
+ CLK(CLK_OP + CLK_IMPLIED + CLK_RELATIVE_16); \
+ m37710i_branch_16(OPER_16_IMM())
+
+/* M37710 Clear Carry flag */
+#undef OP_CLC
+#define OP_CLC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = CFLAG_CLEAR
+
+/* M37710 Clear Decimal flag */
+#undef OP_CLD
+#define OP_CLD() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_D = DFLAG_CLEAR
+
+/* M37710 Clear Interrupt Mask flag */
+#undef OP_CLI
+#define OP_CLI() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ m37710i_set_flag_i(IFLAG_CLEAR)
+
+/* M37710 Clear oVerflow flag */
+#undef OP_CLV
+#define OP_CLV() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_V = VFLAG_CLEAR
+
+/* M37710 Compare operand to accumulator */
+/* Unusual behavior: C flag is inverted */
+#undef OP_CMP
+#if FLAG_SET_M
+#define OP_CMP(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_C = REG_A - OPER_8_##MODE(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ FLAG_C ^= CFLAG_SET
+#else
+#define OP_CMP(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_C = REG_A - OPER_16_##MODE(); \
+ FLAG_Z = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = ~CFLAG_16(FLAG_C)
+#endif
+
+/* M37710 Compare operand to B accumulator */
+/* Unusual behavior: C flag is inverted */
+#undef OP_CMPB
+#if FLAG_SET_M
+#define OP_CMPB(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_C = REG_BA - OPER_8_##MODE(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ FLAG_C ^= CFLAG_SET
+#else
+#define OP_CMPB(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_C = REG_BA - OPER_16_##MODE(); \
+ FLAG_Z = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = ~CFLAG_16(FLAG_C)
+#endif
+
+/* M37710 Compare operand to index register */
+/* Unusual behavior: C flag is inverted */
+#undef OP_CMPX
+#if FLAG_SET_X
+#define OP_CMPX(REG, MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_C = REG - OPER_8_##MODE(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ FLAG_C ^= CFLAG_SET
+#else
+#define OP_CMPX(REG, MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_C = REG - OPER_16_##MODE(); \
+ FLAG_Z = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = ~CFLAG_16(FLAG_C)
+#endif
+
+/* M37710 Coprocessor operation */
+#undef OP_COP
+#define OP_COP() \
+ REG_PC++; \
+ m37710i_interrupt_software(VECTOR_COP)
+
+/* M37710 Decrement accumulator */
+#undef OP_DEC
+#if FLAG_SET_M
+#define OP_DEC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(REG_A - 1)
+#else
+#define OP_DEC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_A = MAKE_UINT_16(REG_A - 1); \
+ FLAG_N = NFLAG_16(REG_A)
+#endif
+
+/* M37710 Decrement B accumulator */
+#undef OP_DECB
+#if FLAG_SET_M
+#define OP_DECB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(REG_BA - 1)
+#else
+#define OP_DECB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_BA = MAKE_UINT_16(REG_BA - 1); \
+ FLAG_N = NFLAG_16(REG_BA)
+#endif
+
+/* M37710 Decrement operand */
+#undef OP_DECM
+#if FLAG_SET_M
+#define OP_DECM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(read_8_##MODE(DST) - 1); \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_DECM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = MAKE_UINT_16(read_16_##MODE(DST) - 1); \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M37710 Decrement index register */
+#undef OP_DECX
+#if FLAG_SET_X
+#define OP_DECX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REG = MAKE_UINT_8(REG - 1)
+#else
+#define OP_DECX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = MAKE_UINT_16(REG - 1); \
+ FLAG_N = NFLAG_16(REG)
+#endif
+
+/* M37710 Exclusive Or operand to accumulator */
+#undef OP_EOR
+#if FLAG_SET_M
+#define OP_EOR(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG_A ^= OPER_8_##MODE()
+#else
+#define OP_EOR(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG_A ^= OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG_A)
+#endif
+
+/* M37710 Exclusive Or operand to accumulator B */
+#undef OP_EORB
+#if FLAG_SET_M
+#define OP_EORB(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG_BA ^= OPER_8_##MODE()
+#else
+#define OP_EORB(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG_BA ^= OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG_BA)
+#endif
+
+/* M37710 Increment accumulator */
+#undef OP_INC
+#if FLAG_SET_M
+#define OP_INC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(REG_A + 1)
+#else
+#define OP_INC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_A = MAKE_UINT_16(REG_A + 1); \
+ FLAG_N = NFLAG_16(REG_A)
+#endif
+
+/* M37710 Increment B accumulator */
+#undef OP_INCB
+#if FLAG_SET_M
+#define OP_INCB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(REG_BA + 1)
+#else
+#define OP_INCB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_BA = MAKE_UINT_16(REG_BA + 1); \
+ FLAG_N = NFLAG_16(REG_BA)
+#endif
+
+/* M37710 Increment operand */
+#undef OP_INCM
+#if FLAG_SET_M
+#define OP_INCM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(read_8_##MODE(DST) + 1); \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_INCM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = MAKE_UINT_16(read_16_##MODE(DST) + 1); \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M37710 Increment index register */
+#undef OP_INCX
+#if FLAG_SET_X
+#define OP_INCX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = FLAG_Z = REG = MAKE_UINT_8(REG + 1)
+#else
+#define OP_INCX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = MAKE_UINT_16(REG + 1); \
+ FLAG_N = NFLAG_16(REG)
+#endif
+
+/* M37710 Jump Long */
+#undef OP_JMLAI
+#define OP_JMLAI() \
+ CLK(CLK_OP + CLK_AI + 1); \
+ m37710i_jump_24(read_24_A(OPER_16_IMM()))
+
+/* M37710 Jump */
+#undef OP_JMP
+#define OP_JMP(MODE) \
+ CLK(CLK_OP + CLK_##MODE); \
+ m37710i_jump_16(EA_##MODE())
+
+/* M37710 Jump absolute indexed indirect */
+#undef OP_JMPAXI
+#define OP_JMPAXI() \
+ CLK(CLK_OP + CLK_AXI); \
+ m37710i_jump_16(read_16_AXI(REG_PB | (MAKE_UINT_16(OPER_16_IMM() + REG_X))))
+
+/* M37710 Jump absolute long */
+#undef OP_JMPAL
+#define OP_JMPAL() \
+ CLK(CLK_OP + CLK_AL); \
+ m37710i_jump_24(EA_AL())
+
+/* M37710 Jump to Subroutine Long */
+#undef OP_JSL
+#define OP_JSL(MODE) \
+ CLK(CLK_OP + CLK_W24 + CLK_##MODE + 1); \
+ DST = EA_##MODE(); \
+ m37710i_push_8(REG_PB>>16); \
+ m37710i_push_16(REG_PC); \
+ m37710i_jump_24(DST)
+
+/* M37710 Jump to Subroutine */
+#undef OP_JSR
+#define OP_JSR(MODE) \
+ CLK(CLK_OP + CLK_W16 + CLK_##MODE); \
+ DST = EA_##MODE(); \
+ m37710i_push_16(REG_PC); \
+ m37710i_jump_16(DST)
+
+/* M37710 Jump to Subroutine */
+#undef OP_JSRAXI
+#define OP_JSRAXI() \
+ CLK(CLK_OP + CLK_W16 + CLK_AXI); \
+ DST = read_16_AXI(REG_PB | (MAKE_UINT_16(OPER_16_IMM() + REG_X))); \
+ m37710i_push_16(REG_PC); \
+ m37710i_jump_16(DST)
+
+/* M37710 Load accumulator with operand */
+#undef OP_LDA
+#if FLAG_SET_M
+#define OP_LDA(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG_A = OPER_8_##MODE()
+#else
+#define OP_LDA(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG_A = OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG_A)
+#endif
+
+/* M37710 Load B accumulator with operand */
+#undef OP_LDB
+#if FLAG_SET_M
+#define OP_LDB(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG_BA = OPER_8_##MODE()
+#else
+#define OP_LDB(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG_BA = OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG_BA)
+#endif
+
+/* M37710 Load memory with operand */
+#undef OP_LDM
+#if FLAG_SET_M
+#define OP_LDM(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ REG_IM2 = EA_##MODE(); \
+ REG_IM = read_8_NORM(REG_PB|REG_PC); \
+ REG_PC++; \
+ write_8_##MODE(REG_IM2, REG_IM)
+#else
+#define OP_LDM(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ REG_IM2 = EA_##MODE(); \
+ REG_IM = read_16_NORM(REG_PB|REG_PC); \
+ REG_PC+=2; \
+ write_16_##MODE(REG_IM2, REG_IM)
+#endif
+
+/* M37710 Branch if bits set */
+#undef OP_BBS
+#if FLAG_SET_M
+#define OP_BBS(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ REG_IM2 = read_8_NORM(EA_##MODE()); \
+ REG_IM = read_8_NORM(REG_PC); \
+ REG_PC++; \
+ DST = OPER_8_IMM(); \
+ if ((REG_IM2 & REG_IM) == REG_IM) \
+ { \
+ CLK(CLK_OP + CLK_RELATIVE_8 + 1); \
+ m37710i_branch_8(DST); \
+ BREAKOUT; \
+ }
+#else
+#define OP_BBS(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ REG_IM2 = read_16_NORM(EA_##MODE()); \
+ REG_IM = read_16_NORM(REG_PC); \
+ REG_PC++; \
+ REG_PC++; \
+ DST = OPER_8_IMM(); \
+ if ((REG_IM2 & REG_IM) == REG_IM) \
+ { \
+ CLK(CLK_OP + CLK_RELATIVE_8 + 1); \
+ m37710i_branch_8(DST); \
+ BREAKOUT; \
+ }
+#endif
+
+/* M37710 Branch if bits clear */
+#undef OP_BBC
+#if FLAG_SET_M
+#define OP_BBC(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ REG_IM2 = read_8_NORM(EA_##MODE()); \
+ REG_IM = read_8_NORM(REG_PC); \
+ REG_PC++; \
+ DST = OPER_8_IMM(); \
+ if ((REG_IM2 & REG_IM) == 0) \
+ { \
+ CLK(CLK_OP + CLK_RELATIVE_8 + 1); \
+ m37710i_branch_8(DST); \
+ BREAKOUT; \
+ }
+#else
+#define OP_BBC(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ REG_IM2 = read_16_NORM(EA_##MODE()); \
+ REG_IM = read_16_NORM(REG_PC); \
+ REG_PC++; \
+ REG_PC++; \
+ DST = OPER_8_IMM(); \
+ if ((REG_IM2 & REG_IM) == 0) \
+ { \
+ CLK(CLK_OP + CLK_RELATIVE_8 + 1); \
+ m37710i_branch_8(DST); \
+ BREAKOUT; \
+ }
+#endif
+
+/* M37710 Swap accumulators */
+#undef OP_XAB
+#if FLAG_SET_M
+#define OP_XAB() \
+ CLK(6); \
+ DST = REG_A; \
+ FLAG_N = FLAG_Z = REG_A = REG_BA; \
+ REG_BA = DST;
+#else
+#define OP_XAB() \
+ CLK(6); \
+ DST = REG_A; \
+ FLAG_Z = REG_A = REG_BA; \
+ FLAG_N = NFLAG_16(REG_A); \
+ REG_BA = DST;
+#endif
+
+/* M37710 Load index register with operand */
+#undef OP_LDX
+#if FLAG_SET_X
+#define OP_LDX(REG, MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG = OPER_8_##MODE()
+#else
+#define OP_LDX(REG, MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG = OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG)
+#endif
+
+/* M37710 Logical Shift Right accumulator */
+#undef OP_LSR
+#if FLAG_SET_M
+#define OP_LSR() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = 0; \
+ FLAG_C = REG_A << 8; \
+ FLAG_Z = REG_A >>= 1
+#else
+#define OP_LSR() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = 0; \
+ FLAG_C = REG_A << 8; \
+ FLAG_Z = REG_A >>= 1
+#endif
+
+/* M37710 Logical Shift Right B accumulator */
+#undef OP_LSRB
+#if FLAG_SET_M
+#define OP_LSRB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = 0; \
+ FLAG_C = REG_BA << 8; \
+ FLAG_Z = REG_BA >>= 1
+#else
+#define OP_LSRB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_N = 0; \
+ FLAG_C = REG_BA << 8; \
+ FLAG_Z = REG_BA >>= 1
+#endif
+
+/* M37710 Logical Shift Right operand */
+#undef OP_LSRM
+#if FLAG_SET_M
+#define OP_LSRM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_N = 0; \
+ FLAG_Z = read_8_##MODE(DST); \
+ FLAG_C = FLAG_Z << 8; \
+ FLAG_Z >>= 1; \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_LSRM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_N = 0; \
+ FLAG_Z = read_16_##MODE(DST); \
+ FLAG_C = FLAG_Z << 8; \
+ FLAG_Z >>= 1; \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M37710 Move Block Negative */
+#undef OP_MVN
+#if FLAG_SET_X
+#define OP_MVN() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REG_DB = DST; \
+ REG_A |= REG_B; \
+ CLK(7); \
+ if (REG_A > 0) \
+ { \
+ write_8_NORM(DST | REG_Y, read_8_NORM(SRC | REG_X)); \
+ REG_X = MAKE_UINT_8(REG_X+1); \
+ REG_Y = MAKE_UINT_8(REG_Y+1); \
+ REG_A--; \
+ if ((REG_A&0xffff) != 0) \
+ {\
+ REG_PC -= 3; \
+ }\
+ else \
+ { \
+ if (FLAG_M) \
+ { \
+ REG_A = 0xff; \
+ REG_B = 0xff00; \
+ } \
+ else \
+ { \
+ REG_A = 0xffff; \
+ } \
+ } \
+ }
+#else
+#define OP_MVN() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REG_DB = DST; \
+ REG_A |= REG_B; \
+ CLK(7); \
+ if (REG_A > 0) \
+ { \
+ write_8_NORM(DST | REG_Y, read_8_NORM(SRC | REG_X)); \
+ REG_X = MAKE_UINT_16(REG_X+1); \
+ REG_Y = MAKE_UINT_16(REG_Y+1); \
+ REG_A--; \
+ if ((REG_A&0xffff) != 0) \
+ {\
+ REG_PC -= 3; \
+ }\
+ else \
+ { \
+ if (FLAG_M) \
+ { \
+ REG_A = 0xff; \
+ REG_B = 0xff00; \
+ } \
+ else \
+ { \
+ REG_A = 0xffff; \
+ } \
+ } \
+ }
+#endif
+
+/* M37710 Move Block Positive */
+#undef OP_MVP
+#if FLAG_SET_X
+#define OP_MVP() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REG_DB = DST; \
+ REG_A |= REG_B; \
+ CLK(7); \
+ if (REG_A > 0) \
+ { \
+ write_8_NORM(DST | REG_Y, read_8_NORM(SRC | REG_X)); \
+ REG_X = MAKE_UINT_8(REG_X-1); \
+ REG_Y = MAKE_UINT_8(REG_Y-1); \
+ REG_A--; \
+ if ((REG_A&0xffff) != 0) \
+ {\
+ REG_PC -= 3; \
+ }\
+ else \
+ { \
+ if (FLAG_M) \
+ { \
+ REG_A = 0xff; \
+ REG_B = 0xff00; \
+ } \
+ else \
+ { \
+ REG_A = 0xffff; \
+ } \
+ } \
+ }
+#else
+#define OP_MVP() \
+ DST = OPER_8_IMM()<<16; \
+ SRC = OPER_8_IMM()<<16; \
+ REG_DB = DST; \
+ REG_A |= REG_B; \
+ CLK(7); \
+ if (REG_A > 0) \
+ { \
+ write_8_NORM(DST | REG_Y, read_8_NORM(SRC | REG_X)); \
+ REG_X = MAKE_UINT_16(REG_X-1); \
+ REG_Y = MAKE_UINT_16(REG_Y-1); \
+ REG_A--; \
+ if ((REG_A&0xffff) != 0) \
+ {\
+ REG_PC -= 3; \
+ }\
+ else \
+ { \
+ if (FLAG_M) \
+ { \
+ REG_A = 0xff; \
+ REG_B = 0xff00; \
+ } \
+ else \
+ { \
+ REG_A = 0xffff; \
+ } \
+ } \
+ }
+#endif
+
+/* M37710 No Operation */
+#undef OP_NOP
+#define OP_NOP() \
+ CLK(CLK_OP + CLK_IMPLIED)
+
+/* M37710 Logical OR operand to accumulator */
+#undef OP_ORA
+#if FLAG_SET_M
+#define OP_ORA(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG_A |= OPER_8_ ## MODE()
+#else
+#define OP_ORA(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG_A |= OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG_A)
+#endif
+
+/* M37710 Logical OR operand to B accumulator */
+#undef OP_ORB
+#if FLAG_SET_M
+#define OP_ORB(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ FLAG_N = FLAG_Z = REG_BA |= OPER_8_ ## MODE()
+#else
+#define OP_ORB(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ FLAG_Z = REG_BA |= OPER_16_##MODE(); \
+ FLAG_N = NFLAG_16(REG_BA)
+#endif
+
+/* M37710 Push Effective Address */
+#undef OP_PEA
+#define OP_PEA() \
+ CLK(CLK_OP + CLK_R16 + CLK_W16); \
+ m37710i_push_16(OPER_16_IMM())
+
+/* M37710 Push Effective Indirect Address */
+#undef OP_PEI
+#define OP_PEI() \
+ CLK(CLK_OP + CLK_R16 + CLK_W16 + CLK_D); \
+ m37710i_push_16(EA_DI())
+
+/* M37710 Push Effective PC-Relative Address */
+#undef OP_PER
+#define OP_PER() \
+ CLK(CLK_OP + CLK_R16 + CLK_W16 + 1); \
+ SRC = OPER_16_IMM(); \
+ m37710i_push_16(REG_PC + SRC)
+
+/* M37710 Push accumulator to the stack */
+#undef OP_PHA
+#if FLAG_SET_M
+#define OP_PHA() \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ m37710i_push_8(REG_A)
+#else
+#define OP_PHA() \
+ CLK(CLK_OP + CLK_W16 + 1); \
+ m37710i_push_16(REG_A)
+#endif
+
+/* M37710 Push B accumulator to the stack */
+#undef OP_PHAB
+#if FLAG_SET_M
+#define OP_PHAB() \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ m37710i_push_8(REG_BA)
+#else
+#define OP_PHAB() \
+ CLK(CLK_OP + CLK_W16 + 1); \
+ m37710i_push_16(REG_BA)
+#endif
+
+/* M37710 Push index register to the stack */
+#undef OP_PHX
+#if FLAG_SET_X
+#define OP_PHX(REG) \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ m37710i_push_8(REG)
+#else
+#define OP_PHX(REG) \
+ CLK(CLK_OP + CLK_W16 + 1); \
+ m37710i_push_16(REG)
+#endif
+
+/* M37710 Push data bank register */
+#undef OP_PHT
+#define OP_PHT() \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ m37710i_push_8(REG_DB>>16)
+
+/* M37710 Push direct register */
+#undef OP_PHD
+#define OP_PHD() \
+ CLK(CLK_OP + CLK_W16 + 1); \
+ m37710i_push_16(REG_D)
+
+/* M37710 Push program bank register */
+#undef OP_PHK
+#define OP_PHK() \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ m37710i_push_8(REG_PB>>16)
+
+/* M37710 Push the Processor Status Register to the stack */
+#undef OP_PHP
+#define OP_PHP() \
+ CLK(CLK_OP + CLK_W8 + 1); \
+ m37710i_push_8(m37710i_cpu.ipl); \
+ m37710i_push_8(m37710i_get_reg_p())
+
+/* M37710 Pull accumulator from the stack */
+#undef OP_PLA
+#if FLAG_SET_M
+#define OP_PLA() \
+ CLK(CLK_OP + CLK_R8 + 2); \
+ FLAG_N = FLAG_Z = REG_A = m37710i_pull_8()
+#else
+#define OP_PLA() \
+ CLK(CLK_OP + CLK_R16 + 2); \
+ FLAG_Z = REG_A = m37710i_pull_16(); \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Pull B accumulator from the stack */
+#undef OP_PLAB
+#if FLAG_SET_M
+#define OP_PLAB() \
+ CLK(CLK_OP + CLK_R8 + 2); \
+ FLAG_N = FLAG_Z = REG_BA = m37710i_pull_8()
+#else
+#define OP_PLAB() \
+ CLK(CLK_OP + CLK_R16 + 2); \
+ FLAG_Z = REG_BA = m37710i_pull_16(); \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Pull index register from the stack */
+#undef OP_PLX
+#if FLAG_SET_X
+#define OP_PLX(REG) \
+ CLK(CLK_OP + CLK_R8 + 2); \
+ FLAG_N = FLAG_Z = REG = m37710i_pull_8()
+#else
+#define OP_PLX(REG) \
+ CLK(CLK_OP + CLK_R16 + 2); \
+ FLAG_Z = REG = m37710i_pull_16(); \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Pull data bank register */
+#undef OP_PLT
+#define OP_PLT() \
+ CLK(CLK_OP + CLK_R8 + 2); \
+ FLAG_N = FLAG_Z = m37710i_pull_8(); \
+ REG_DB = FLAG_Z << 16
+
+/* M37710 Pull direct register */
+#undef OP_PLD
+#define OP_PLD() \
+ CLK(CLK_OP + CLK_R16 + 2); \
+ FLAG_Z = REG_D = m37710i_pull_16(); \
+ FLAG_N = NFLAG_16(FLAG_Z)
+
+/* M37710 Pull the Processor Status Register from the stack */
+#undef OP_PLP
+#define OP_PLP() \
+ CLK(CLK_OP + CLK_R8 + 2); \
+ m37710i_set_reg_p(m37710i_pull_8()); \
+ m37710i_set_reg_ipl(m37710i_pull_8())
+
+/* M37710 Reset Program status word */
+#undef OP_REP
+#define OP_REP() \
+ CLK(CLK_OP + CLK_R8 + 1); \
+ m37710i_set_reg_p(m37710i_get_reg_p() & ~OPER_8_IMM())
+
+/* M37710 Clear "M" status bit */
+#undef OP_CLM
+#define OP_CLM() \
+ CLK(CLK_OP + CLK_R8 + 1); \
+ m37710i_set_reg_p(m37710i_get_reg_p() & ~FLAGPOS_M)
+
+/* M37710 Rotate Left the accumulator */
+#undef OP_ROL
+#if FLAG_SET_M
+#define OP_ROL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = (REG_A<<1) | CFLAG_AS_1(); \
+ FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C)
+#else
+#define OP_ROL() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = (REG_A<<1) | CFLAG_AS_1(); \
+ FLAG_Z = REG_A = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C)
+#endif
+
+/* M37710 Rotate Left the B accumulator */
+#undef OP_ROLB
+#if FLAG_SET_M
+#define OP_ROLB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = (REG_BA<<1) | CFLAG_AS_1(); \
+ FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C)
+#else
+#define OP_ROLB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = (REG_BA<<1) | CFLAG_AS_1(); \
+ FLAG_Z = REG_BA = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C)
+#endif
+
+/* M37710 Rotate Left the accumulator by a specified amount */
+#undef OP_RLA
+#if FLAG_SET_M
+#define OP_RLA(MODE) \
+ { int cnt = OPER_8_##MODE(); int tmp; while (cnt > 0) { CLK(6); tmp = REG_A; REG_A=(REG_A<<1)&0xff; REG_A |= (tmp>>7); cnt--; } }
+#else
+#define OP_RLA(MODE) \
+ { int cnt = OPER_16_##MODE(); int tmp; while (cnt > 0) { CLK(6); tmp = REG_A; REG_A=(REG_A<<1)&0xffff; REG_A |= (tmp>>15); cnt--; } }
+#endif
+
+/* M37710 Rotate Left an operand */
+#undef OP_ROLM
+#if FLAG_SET_M
+#define OP_ROLM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_C = (read_8_##MODE(DST)<<1) | CFLAG_AS_1(); \
+ FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_ROLM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_C = (read_16_##MODE(DST)<<1) | CFLAG_AS_1(); \
+ FLAG_Z = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(FLAG_C); \
+ FLAG_C = CFLAG_16(FLAG_C); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M37710 Rotate Right the accumulator */
+#undef OP_ROR
+#if FLAG_SET_M
+#define OP_ROR() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REG_A |= FLAG_C & 0x100; \
+ FLAG_C = REG_A << 8; \
+ FLAG_N = FLAG_Z = REG_A >>= 1
+#else
+#define OP_ROR() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REG_A |= (FLAG_C<<8) & 0x10000; \
+ FLAG_C = REG_A << 8; \
+ FLAG_Z = REG_A >>= 1; \
+ FLAG_N = NFLAG_16(REG_A)
+#endif
+
+/* M37710 Rotate Right the B accumulator */
+#undef OP_RORB
+#if FLAG_SET_M
+#define OP_RORB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REG_BA |= FLAG_C & 0x100; \
+ FLAG_C = REG_BA << 8; \
+ FLAG_N = FLAG_Z = REG_BA >>= 1
+#else
+#define OP_RORB() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REG_BA |= (FLAG_C<<8) & 0x10000; \
+ FLAG_C = REG_BA << 8; \
+ FLAG_Z = REG_BA >>= 1; \
+ FLAG_N = NFLAG_16(REG_BA)
+#endif
+
+/* M37710 Rotate Right an operand */
+#undef OP_RORM
+#if FLAG_SET_M
+#define OP_RORM(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = read_8_##MODE(DST) | (FLAG_C & 0x100); \
+ FLAG_C = FLAG_Z << 8; \
+ FLAG_N = FLAG_Z >>= 1; \
+ write_8_##MODE(DST, FLAG_Z)
+#else
+#define OP_RORM(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ FLAG_Z = read_16_##MODE(DST) | ((FLAG_C<<8) & 0x10000); \
+ FLAG_C = FLAG_Z << 8; \
+ FLAG_Z >>= 1; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ write_16_##MODE(DST, FLAG_Z)
+#endif
+
+/* M37710 Return from Interrupt */
+#undef OP_RTI
+#define OP_RTI() \
+ CLK(8); \
+ m37710i_set_reg_p(m37710i_pull_8()); \
+ m37710i_set_reg_ipl(m37710i_pull_8()); \
+ m37710i_jump_16(m37710i_pull_16()); \
+ REG_PB = m37710i_pull_8() << 16; \
+ m37710i_jumping(REG_PB | REG_PC)
+
+/* M37710 Return from Subroutine Long */
+#undef OP_RTL
+#define OP_RTL() \
+ CLK(6); \
+ m37710i_jump_24(m37710i_pull_24())
+
+/* M37710 Return from Subroutine */
+#undef OP_RTS
+#define OP_RTS() \
+ CLK(6); \
+ DST = m37710i_pull_16(); \
+ m37710i_jump_16(DST)
+
+/* M37710 Subtract with Carry */
+/* Unusual behavior: C flag is inverted */
+#undef OP_SBC
+#if FLAG_SET_M
+#define OP_SBC(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ SRC = OPER_8_##MODE(); \
+ FLAG_C = ~FLAG_C; \
+ if(!FLAG_D) \
+ { \
+ FLAG_C = REG_A - SRC - CFLAG_AS_1(); \
+ FLAG_V = VFLAG_SUB_8(SRC, REG_A, FLAG_C); \
+ FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C); \
+ FLAG_C = ~FLAG_C; \
+ BREAKOUT; \
+ } \
+ DST = CFLAG_AS_1(); \
+ FLAG_C = REG_A - SRC - DST; \
+ FLAG_V = VFLAG_SUB_8(SRC, REG_A, FLAG_C); \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C-=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C-=0x60; \
+ FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C); \
+ FLAG_C = ~FLAG_C
+#else
+#define OP_SBC(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ SRC = OPER_16_##MODE(); \
+ FLAG_C = ~FLAG_C; \
+ if(!FLAG_D) \
+ { \
+ FLAG_C = REG_A - SRC - CFLAG_AS_1(); \
+ FLAG_V = VFLAG_SUB_16(SRC, REG_A, FLAG_C); \
+ FLAG_Z = REG_A = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(REG_A); \
+ FLAG_C = ~CFLAG_16(FLAG_C); \
+ BREAKOUT; \
+ } \
+ DST = CFLAG_AS_1(); \
+ FLAG_C = MAKE_UINT_8(REG_A) - MAKE_UINT_8(SRC) - DST; \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C-=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C-=0x60; \
+ FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ DST = CFLAG_AS_1(); \
+ FLAG_C = MAKE_UINT_8(REG_A>>8) - MAKE_UINT_8(SRC>>8) - DST; \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C-=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C-=0x60; \
+ FLAG_Z |= MAKE_UINT_8(FLAG_C) << 8; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ FLAG_V = VFLAG_SUB_16(SRC, REG_A, FLAG_Z); \
+ REG_A = FLAG_Z; \
+ FLAG_C = ~FLAG_C
+#endif
+
+/* M37710 Subtract with Carry - B accumulator */
+/* Unusual behavior: C flag is inverted */
+#undef OP_SBCB
+#if FLAG_SET_M
+#define OP_SBCB(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ SRC = OPER_8_##MODE(); \
+ FLAG_C = ~FLAG_C; \
+ if(!FLAG_D) \
+ { \
+ FLAG_C = REG_BA - SRC - CFLAG_AS_1(); \
+ FLAG_V = VFLAG_SUB_8(SRC, REG_BA, FLAG_C); \
+ FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C); \
+ FLAG_C = ~FLAG_C; \
+ BREAKOUT; \
+ } \
+ DST = CFLAG_AS_1(); \
+ FLAG_C = REG_BA - SRC - DST; \
+ FLAG_V = VFLAG_SUB_8(SRC, REG_BA, FLAG_C); \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C-=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C-=0x60; \
+ FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C); \
+ FLAG_C = ~FLAG_C
+#else
+#define OP_SBCB(MODE) \
+ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
+ SRC = OPER_16_##MODE(); \
+ FLAG_C = ~FLAG_C; \
+ if(!FLAG_D) \
+ { \
+ FLAG_C = REG_BA - SRC - CFLAG_AS_1(); \
+ FLAG_V = VFLAG_SUB_16(SRC, REG_BA, FLAG_C); \
+ FLAG_Z = REG_BA = MAKE_UINT_16(FLAG_C); \
+ FLAG_N = NFLAG_16(REG_BA); \
+ FLAG_C = ~CFLAG_16(FLAG_C); \
+ BREAKOUT; \
+ } \
+ DST = CFLAG_AS_1(); \
+ FLAG_C = MAKE_UINT_8(REG_BA) - MAKE_UINT_8(SRC) - DST; \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C-=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C-=0x60; \
+ FLAG_Z = MAKE_UINT_8(FLAG_C); \
+ DST = CFLAG_AS_1(); \
+ FLAG_C = MAKE_UINT_8(REG_A>>8) - MAKE_UINT_8(SRC>>8) - DST; \
+ if((FLAG_C & 0xf) > 9) \
+ FLAG_C-=6; \
+ if((FLAG_C & 0xf0) > 0x90) \
+ FLAG_C-=0x60; \
+ FLAG_Z |= MAKE_UINT_8(FLAG_C) << 8; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ FLAG_V = VFLAG_SUB_16(SRC, REG_BA, FLAG_Z); \
+ REG_BA = FLAG_Z; \
+ FLAG_C = ~FLAG_C
+#endif
+
+/* M37710 Set Carry flag */
+#undef OP_SEC
+#define OP_SEC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_C = CFLAG_SET
+
+/* M37710 Set Decimal flag */
+#undef OP_SED
+#define OP_SED() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_D = DFLAG_SET
+
+/* M37710 Set Interrupt Mask flag */
+#undef OP_SEI
+#define OP_SEI() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ m37710i_set_flag_i(IFLAG_SET)
+
+/* M37710 Set Program status word */
+#undef OP_SEP
+#define OP_SEP() \
+ CLK(CLK_OP + CLK_R8 + 1); \
+ m37710i_set_reg_p(m37710i_get_reg_p() | OPER_8_IMM())
+
+/* M37710 Set "M" status bit */
+#undef OP_SEM
+#define OP_SEM() \
+ CLK(CLK_OP + CLK_R8 + 1); \
+ m37710i_set_reg_p(m37710i_get_reg_p() | FLAGPOS_M)
+
+/* M37710 Store accumulator to memory */
+#undef OP_STA
+#if FLAG_SET_M
+#define OP_STA(MODE) \
+ CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \
+ write_8_##MODE(EA_##MODE(), REG_A)
+#else
+#define OP_STA(MODE) \
+ CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \
+ write_16_##MODE(EA_##MODE(), REG_A)
+#endif
+
+/* M37710 Store B accumulator to memory */
+#undef OP_STB
+#if FLAG_SET_M
+#define OP_STB(MODE) \
+ CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \
+ write_8_##MODE(EA_##MODE(), REG_BA)
+#else
+#define OP_STB(MODE) \
+ CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \
+ write_16_##MODE(EA_##MODE(), REG_BA)
+#endif
+
+/* M37710 Store index register to memory */
+#undef OP_STX
+#if FLAG_SET_X
+#define OP_STX(REG, MODE) \
+ CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \
+ write_8_##MODE(EA_##MODE(), REG)
+#else
+#define OP_STX(REG, MODE) \
+ CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \
+ write_16_##MODE(EA_##MODE(), REG)
+#endif
+
+/* M37710 Store zero to memory */
+#undef OP_STZ
+#if FLAG_SET_M
+#define OP_STZ(MODE) \
+ CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \
+ write_8_##MODE(EA_##MODE(), 0)
+#else
+#define OP_STZ(MODE) \
+ CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \
+ write_16_##MODE(EA_##MODE(), 0)
+#endif
+
+/* M37710 Stop the clock */
+#undef OP_STP
+#define OP_STP() \
+ USE_ALL_CLKS(); \
+ CPU_STOPPED |= STOP_LEVEL_STOP
+
+/* M37710 Transfer accumulator to index */
+#undef OP_TAX
+#if FLAG_SET_M
+#if FLAG_SET_X
+#define OP_TAX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = REG_A; \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else /* FLAG_SET_X */
+#define OP_TAX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = REG_B | REG_A; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif /* FLAG_SET_X */
+#else /* FLAG_SET_M */
+#if FLAG_SET_X
+#define OP_TAX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = MAKE_UINT_8(REG_A); \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else /* FLAG_SET_X */
+#define OP_TAX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = REG_A; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif /* FLAG_SET_X */
+#endif /* FLAG_SET_M */
+
+
+/* M37710 Transfer accumulator B to index */
+#undef OP_TBX
+#if FLAG_SET_M
+#if FLAG_SET_X
+#define OP_TBX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = REG_BA; \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else /* FLAG_SET_X */
+#define OP_TBX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = REG_BB | REG_BA; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif /* FLAG_SET_X */
+#else /* FLAG_SET_M */
+#if FLAG_SET_X
+#define OP_TBX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = MAKE_UINT_8(REG_BA); \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else /* FLAG_SET_X */
+#define OP_TBX(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG = REG_BA; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif /* FLAG_SET_X */
+#endif /* FLAG_SET_M */
+
+/* M37710 Transfer index to accumulator */
+#undef OP_TXA
+#if FLAG_SET_M
+#define OP_TXA(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_A = MAKE_UINT_8(REG); \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_TXA(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_A = REG; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Transfer index to accumulator */
+#undef OP_TXB
+#if FLAG_SET_M
+#define OP_TXB(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_BA = MAKE_UINT_8(REG); \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_TXB(REG) \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_BA = REG; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Transfer C to direct register */
+#undef OP_TCD
+#if FLAG_SET_M
+#define OP_TCD() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_D = REG_A | REG_B; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#else
+#define OP_TCD() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_D = REG_A; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Transfer direct register to C */
+#undef OP_TDC
+#if FLAG_SET_M
+#define OP_TDC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_D; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ REG_A = MAKE_UINT_8(REG_D); \
+ REG_B = REG_D & 0xff00
+#else
+#define OP_TDC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_A = REG_D; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Transfer C to stack pointer */
+#undef OP_TCS
+#define OP_TCS() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REG_S = REG_A | REG_B
+
+/* M37710 Transfer stack pointer to C */
+#undef OP_TSC
+#if FLAG_SET_M
+#define OP_TSC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_S; \
+ FLAG_N = NFLAG_16(FLAG_Z); \
+ REG_A = MAKE_UINT_8(REG_S); \
+ REG_B = REG_S & 0xff00
+#else
+#define OP_TSC() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_A = REG_S; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Transfer stack pointer to X */
+#undef OP_TSX
+#if FLAG_SET_X
+#define OP_TSX() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_X = MAKE_UINT_8(REG_S); \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_TSX() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_X = REG_S; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Transfer X to stack pointer */
+#undef OP_TXS
+#define OP_TXS() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ REG_S = REG_X
+
+/* M37710 Transfer X to Y */
+#undef OP_TXY
+#if FLAG_SET_X
+#define OP_TXY() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_Y = REG_X; \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_TXY() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_Y = REG_X; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 Transfer Y to X */
+#undef OP_TYX
+#if FLAG_SET_X
+#define OP_TYX() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_X = REG_Y; \
+ FLAG_N = NFLAG_8(FLAG_Z)
+#else
+#define OP_TYX() \
+ CLK(CLK_OP + CLK_IMPLIED); \
+ FLAG_Z = REG_X = REG_Y; \
+ FLAG_N = NFLAG_16(FLAG_Z)
+#endif
+
+/* M37710 clear bit */
+#undef OP_CLB
+#if FLAG_SET_M
+#define OP_CLB(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ REG_IM = read_8_##MODE(DST); \
+ REG_IM2 = read_8_NORM(REG_PC); \
+ REG_PC++; \
+ write_8_##MODE(DST, REG_IM & ~REG_IM2);
+#else
+#define OP_CLB(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ REG_IM = read_16_##MODE(DST); \
+ REG_IM2 = read_16_NORM(REG_PC); \
+ REG_PC+=2; \
+ write_16_##MODE(DST, REG_IM & ~REG_IM2);
+#endif
+
+/* M37710 set bit */
+#undef OP_SEB
+#if FLAG_SET_M
+#define OP_SEB(MODE) \
+ CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ REG_IM = read_8_##MODE(DST); \
+ REG_IM2 = read_8_NORM(REG_PC); \
+ REG_PC++; \
+ write_8_##MODE(DST, REG_IM | REG_IM2);
+#else
+#define OP_SEB(MODE) \
+ CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \
+ DST = EA_##MODE(); \
+ REG_IM = read_16_##MODE(DST); \
+ REG_IM2 = read_16_NORM(REG_PC); \
+ REG_PC+=2; \
+ write_16_##MODE(DST, REG_IM | REG_IM2);
+#endif
+
+/* M37710 Wait for interrupt */
+#undef OP_WAI
+#define OP_WAI() \
+ USE_ALL_CLKS(); \
+ CPU_STOPPED |= STOP_LEVEL_WAI
+
+/* M37710 prefix for B accumulator (0x42) */
+/* There is a 2 cycle penalty for all instructions using this prefix */
+#undef OP_PFB
+#define OP_PFB() \
+ CLK(2); \
+ REG_IR = read_8_IMM(REG_PB | REG_PC); \
+ REG_PC++; \
+ FTABLE_OPCODES2[REG_IR]();
+
+
+/* M37710 prefix for multiply / divide instructions (0x89) */
+#undef OP_PFXM
+#define OP_PFXM() \
+ REG_IR = read_8_IMM(REG_PB | REG_PC); \
+ REG_PC++; \
+ FTABLE_OPCODES3[REG_IR]();
+
+
+/* M37710 unimplemented opcode */
+#undef OP_UNIMP
+#define OP_UNIMP() \
+ fatalerror("M37710: UNIMPLEMENTED OPCODE! K=%x PC=%x", REG_PB, REG_PPC);
+
+/* M37710 load data bank register */
+#undef OP_LDTAAA
+#define OP_LDT(MODE) \
+ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
+ REG_DB = OPER_8_##MODE()<<16;
+
+/* ======================================================================== */
+/* ======================== OPCODE & FUNCTION TABLES ====================== */
+/* ======================================================================== */
+
+#undef OP
+#undef O
+#undef TABLE_OPCODES
+#undef TABLE_FUNCTION
+
+#if !FLAG_SET_M && !FLAG_SET_X
+#define OP(CODE, OPERATION) static void m37710i_ ## CODE ## _M0X0(void) {OPERATION;}
+#define O(CODE) m37710i_ ## CODE ## _M0X0
+#define TABLE_OPCODES void (*m37710i_opcodes_M0X0[256])(void)
+#define TABLE_OPCODES2 void (*m37710i_opcodes42_M0X0[256])(void)
+#define TABLE_OPCODES3 void (*m37710i_opcodes89_M0X0[256])(void)
+#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE m37710i_ ## NAME ## _M0X0 ARGS
+
+#elif !FLAG_SET_M && FLAG_SET_X
+
+#define OP(CODE, OPERATION) static void m37710i_ ## CODE ## _M0X1(void) {OPERATION;}
+#define O(CODE) m37710i_ ## CODE ## _M0X1
+#define TABLE_OPCODES void (*m37710i_opcodes_M0X1[256])(void)
+#define TABLE_OPCODES2 void (*m37710i_opcodes42_M0X1[256])(void)
+#define TABLE_OPCODES3 void (*m37710i_opcodes89_M0X1[256])(void)
+#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE m37710i_ ## NAME ## _M0X1 ARGS
+
+#elif FLAG_SET_M && !FLAG_SET_X
+
+#define OP(CODE, OPERATION) static void m37710i_ ## CODE ## _M1X0(void) {OPERATION;}
+#define O(CODE) m37710i_ ## CODE ## _M1X0
+#define TABLE_OPCODES void (*m37710i_opcodes_M1X0[256])(void)
+#define TABLE_OPCODES2 void (*m37710i_opcodes42_M1X0[256])(void)
+#define TABLE_OPCODES3 void (*m37710i_opcodes89_M1X0[256])(void)
+#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE m37710i_ ## NAME ## _M1X0 ARGS
+
+#elif FLAG_SET_M && FLAG_SET_X
+
+#define OP(CODE, OPERATION) static void m37710i_ ## CODE ## _M1X1(void) {OPERATION;}
+#define O(CODE) m37710i_ ## CODE ## _M1X1
+#define TABLE_OPCODES void (*m37710i_opcodes_M1X1[256])(void)
+#define TABLE_OPCODES2 void (*m37710i_opcodes42_M1X1[256])(void)
+#define TABLE_OPCODES3 void (*m37710i_opcodes89_M1X1[256])(void)
+#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE m37710i_ ## NAME ## _M1X1 ARGS
+
+#endif
+
+#define BREAKOUT return
+
+/* OP FUNCTION Comment */
+OP(00, OP_BRK ( ) ) /* BRK */
+OP(01, OP_ORA ( DXI ) ) /* ORA dxi */
+OP(02, OP_NOP ( ) ) /* unused */
+OP(03, OP_ORA ( S ) ) /* ORA s (G) */
+OP(04, OP_SEB ( D ) ) /* SEB d (C) */
+OP(05, OP_ORA ( D ) ) /* ORA d */
+OP(06, OP_ASLM ( D ) ) /* ASL d */
+OP(07, OP_ORA ( DLI ) ) /* ORA dli (G) */
+OP(08, OP_PHP ( ) ) /* PHP */
+OP(09, OP_ORA ( IMM ) ) /* ORA imm */
+OP(0a, OP_ASL ( ) ) /* ASL acc */
+OP(0b, OP_PHD ( ) ) /* PHD (G) */
+OP(0c, OP_SEB ( A ) ) /* SEB a (C) */
+OP(0d, OP_ORA ( A ) ) /* ORA a */
+OP(0e, OP_ASLM ( A ) ) /* ASL a */
+OP(0f, OP_ORA ( AL ) ) /* ORA al (G) */
+OP(10, OP_BCC ( COND_PL() ) ) /* BPL */
+OP(11, OP_ORA ( DIY ) ) /* ORA diy */
+OP(12, OP_ORA ( DI ) ) /* ORA di (C) */
+OP(13, OP_ORA ( SIY ) ) /* ORA siy (G) */
+OP(14, OP_CLB ( D ) ) /* CLB d (C) */
+OP(15, OP_ORA ( DX ) ) /* ORA dx */
+OP(16, OP_ASLM ( DX ) ) /* ASL dx */
+OP(17, OP_ORA ( DLIY ) ) /* ORA dliy(C) */
+OP(18, OP_CLC ( ) ) /* CLC */
+OP(19, OP_ORA ( AY ) ) /* ORA ay */
+OP(1a, OP_DEC ( ) ) /* DEA (C) */
+OP(1b, OP_TCS ( ) ) /* TCS (G) */
+OP(1c, OP_CLB ( A ) ) /* CLB a (C) */
+OP(1d, OP_ORA ( AX ) ) /* ORA ax */
+OP(1e, OP_ASLM ( AX ) ) /* ASL ax */
+OP(1f, OP_ORA ( ALX ) ) /* ORA alx (G) */
+OP(20, OP_JSR ( A ) ) /* JSR a */
+OP(21, OP_AND ( DXI ) ) /* AND dxi */
+OP(22, OP_JSL ( AL ) ) /* JSL al (G) */
+OP(23, OP_AND ( S ) ) /* AND s (G) */
+OP(24, OP_BBS ( D ) ) /* BBS d */
+OP(25, OP_AND ( D ) ) /* AND d */
+OP(26, OP_ROLM ( D ) ) /* ROL d */
+OP(27, OP_AND ( DLI ) ) /* AND dli (G) */
+OP(28, OP_PLP ( ) ) /* PLP */
+OP(29, OP_AND ( IMM ) ) /* AND imm */
+OP(2a, OP_ROL ( ) ) /* ROL acc */
+OP(2b, OP_PLD ( ) ) /* PLD (G) */
+OP(2c, OP_BBS ( A ) ) /* BBS a */
+OP(2d, OP_AND ( A ) ) /* AND a */
+OP(2e, OP_ROLM ( A ) ) /* ROL a */
+OP(2f, OP_AND ( AL ) ) /* AND al (G) */
+OP(30, OP_BCC ( COND_MI() ) ) /* BMI */
+OP(31, OP_AND ( DIY ) ) /* AND diy */
+OP(32, OP_AND ( DI ) ) /* AND di (C) */
+OP(33, OP_AND ( SIY ) ) /* AND siy */
+OP(34, OP_BBC ( D ) ) /* BBC d */
+OP(35, OP_AND ( DX ) ) /* AND dx */
+OP(36, OP_ROLM ( DX ) ) /* ROL dx */
+OP(37, OP_AND ( DLIY ) ) /* AND dliy(G) */
+OP(38, OP_SEC ( ) ) /* SEC */
+OP(39, OP_AND ( AY ) ) /* AND ay */
+OP(3a, OP_INC ( ) ) /* INA (C) */
+OP(3b, OP_TSC ( ) ) /* TSC (G) */
+OP(3c, OP_BBC ( A ) ) /* BBC a */
+OP(3d, OP_AND ( AX ) ) /* AND ax */
+OP(3e, OP_ROLM ( AX ) ) /* ROL ax */
+OP(3f, OP_AND ( ALX ) ) /* AND alx (G) */
+OP(40, OP_RTI ( ) ) /* RTI */
+OP(41, OP_EOR ( DXI ) ) /* EOR dxi */
+OP(42, OP_PFB ( ) ) /* prefix for "B" accumulator */
+OP(43, OP_EOR ( S ) ) /* EOR s (G) */
+OP(44, OP_MVP ( ) ) /* MVP (G) */
+OP(45, OP_EOR ( D ) ) /* EOR d */
+OP(46, OP_LSRM ( D ) ) /* LSR d */
+OP(47, OP_EOR ( DLI ) ) /* EOR dli (G) */
+OP(48, OP_PHA ( ) ) /* PHA */
+OP(49, OP_EOR ( IMM ) ) /* EOR imm */
+OP(4a, OP_LSR ( ) ) /* LSR acc */
+OP(4b, OP_PHK ( ) ) /* PHK (G) */
+OP(4c, OP_JMP ( A ) ) /* JMP a */
+OP(4d, OP_EOR ( A ) ) /* EOR a */
+OP(4e, OP_LSRM ( A ) ) /* LSR a */
+OP(4f, OP_EOR ( AL ) ) /* EOR al (G) */
+OP(50, OP_BCC ( COND_VC() ) ) /* BVC */
+OP(51, OP_EOR ( DIY ) ) /* EOR diy */
+OP(52, OP_EOR ( DI ) ) /* EOR di (C) */
+OP(53, OP_EOR ( SIY ) ) /* EOR siy (G) */
+OP(54, OP_MVN ( ) ) /* MVN (G) */
+OP(55, OP_EOR ( DX ) ) /* EOR dx */
+OP(56, OP_LSRM ( DX ) ) /* LSR dx */
+OP(57, OP_EOR ( DLIY ) ) /* EOR dliy(G) */
+OP(58, OP_CLI ( ) ) /* CLI */
+OP(59, OP_EOR ( AY ) ) /* EOR ay */
+OP(5a, OP_PHX ( REG_Y ) ) /* PHY (C) */
+OP(5b, OP_TCD ( ) ) /* TCD (G) */
+OP(5c, OP_JMPAL( ) ) /* JMP al (G) */
+OP(5d, OP_EOR ( AX ) ) /* EOR ax */
+OP(5e, OP_LSRM ( AX ) ) /* LSR ax */
+OP(5f, OP_EOR ( ALX ) ) /* EOR alx (G) */
+OP(60, OP_RTS ( ) ) /* RTS */
+OP(61, OP_ADC ( DXI ) ) /* ADC dxi */
+OP(62, OP_PER ( ) ) /* PER (G) */
+OP(63, OP_ADC ( S ) ) /* ADC s (G) */
+OP(64, OP_LDM ( D ) ) /* LDM d (C) */
+OP(65, OP_ADC ( D ) ) /* ADC d */
+OP(66, OP_RORM ( D ) ) /* ROR d */
+OP(67, OP_ADC ( DLI ) ) /* ADC dli (G) */
+OP(68, OP_PLA ( ) ) /* PLA */
+OP(69, OP_ADC ( IMM ) ) /* ADC imm */
+OP(6a, OP_ROR ( ) ) /* ROR acc */
+OP(6b, OP_RTL ( ) ) /* RTL (G) */
+OP(6c, OP_JMP ( AI ) ) /* JMP ai */
+OP(6d, OP_ADC ( A ) ) /* ADC a */
+OP(6e, OP_RORM ( A ) ) /* ROR a */
+OP(6f, OP_ADC ( AL ) ) /* ADC al (G) */
+OP(70, OP_BCC ( COND_VS() ) ) /* BVS */
+OP(71, OP_ADC ( DIY ) ) /* ADC diy */
+OP(72, OP_ADC ( DI ) ) /* ADC di (G) */
+OP(73, OP_ADC ( SIY ) ) /* ADC siy (G) */
+OP(74, OP_LDM ( DX ) ) /* LDM dx (C) */
+OP(75, OP_ADC ( DX ) ) /* ADC dx */
+OP(76, OP_RORM ( DX ) ) /* ROR dx */
+OP(77, OP_ADC ( DLIY ) ) /* ADC dliy(G) */
+OP(78, OP_SEI ( ) ) /* SEI */
+OP(79, OP_ADC ( AY ) ) /* ADC ay */
+OP(7a, OP_PLX ( REG_Y ) ) /* PLY (C) */
+OP(7b, OP_TDC ( ) ) /* TDC (G) */
+OP(7c, OP_JMPAXI( ) ) /* JMP axi (C) */
+OP(7d, OP_ADC ( AX ) ) /* ADC ax */
+OP(7e, OP_RORM ( AX ) ) /* ROR ax */
+OP(7f, OP_ADC ( ALX ) ) /* ADC alx (G) */
+OP(80, OP_BRA ( ) ) /* BRA (C) */
+OP(81, OP_STA ( DXI ) ) /* STA dxi */
+OP(82, OP_BRL ( ) ) /* BRL (G) */
+OP(83, OP_STA ( S ) ) /* STA s (G) */
+OP(84, OP_STX ( REG_Y, D ) ) /* STY d */
+OP(85, OP_STA ( D ) ) /* STA d */
+OP(86, OP_STX ( REG_X, D ) ) /* STX d */
+OP(87, OP_STA ( DLI ) ) /* STA dli (G) */
+OP(88, OP_DECX ( REG_Y ) ) /* DEY */
+OP(89, OP_PFXM ( ) ) /* prefix for mul/div insns */
+OP(8a, OP_TXA ( REG_X ) ) /* TXA */
+OP(8b, OP_PHT ( ) ) /* PHT (G) */
+OP(8c, OP_STX ( REG_Y, A ) ) /* STY a */
+OP(8d, OP_STA ( A ) ) /* STA a */
+OP(8e, OP_STX ( REG_X, A ) ) /* STX a */
+OP(8f, OP_STA ( AL ) ) /* STA al (G) */
+OP(90, OP_BCC ( COND_CC() ) ) /* BCC */
+OP(91, OP_STA ( DIY ) ) /* STA diy */
+OP(92, OP_STA ( DI ) ) /* STA di (C) */
+OP(93, OP_STA ( SIY ) ) /* STA siy (G) */
+OP(94, OP_STX ( REG_Y, DX ) ) /* STY dx */
+OP(95, OP_STA ( DX ) ) /* STA dx */
+OP(96, OP_STX ( REG_X, DY ) ) /* STX dy */
+OP(97, OP_STA ( DLIY ) ) /* STA dliy(G) */
+OP(98, OP_TXA ( REG_Y ) ) /* TYA */
+OP(99, OP_STA ( AY ) ) /* STA ay */
+OP(9a, OP_TXS ( ) ) /* TXS */
+OP(9b, OP_TXY ( ) ) /* TXY (G) */
+OP(9c, OP_LDM ( A ) ) /* LDM a (C) */
+OP(9d, OP_STA ( AX ) ) /* STA ax */
+OP(9e, OP_LDM ( AX ) ) /* LDM ax (C) */
+OP(9f, OP_STA ( ALX ) ) /* STA alx (G) */
+OP(a0, OP_LDX ( REG_Y, IMM ) ) /* LDY imm */
+OP(a1, OP_LDA ( DXI ) ) /* LDA dxi */
+OP(a2, OP_LDX ( REG_X, IMM ) ) /* LDX imm */
+OP(a3, OP_LDA ( S ) ) /* LDA s (G) */
+OP(a4, OP_LDX ( REG_Y, D ) ) /* LDY d */
+OP(a5, OP_LDA ( D ) ) /* LDA d */
+OP(a6, OP_LDX ( REG_X, D ) ) /* LDX d */
+OP(a7, OP_LDA ( DLI ) ) /* LDA dli (G) */
+OP(a8, OP_TAX ( REG_Y ) ) /* TAY */
+OP(a9, OP_LDA ( IMM ) ) /* LDA imm */
+OP(aa, OP_TAX ( REG_X ) ) /* TAX */
+OP(ab, OP_PLT ( ) ) /* PLT (G) */
+OP(ac, OP_LDX ( REG_Y, A ) ) /* LDY a */
+OP(ad, OP_LDA ( A ) ) /* LDA a */
+OP(ae, OP_LDX ( REG_X, A ) ) /* LDX a */
+OP(af, OP_LDA ( AL ) ) /* LDA al (G) */
+OP(b0, OP_BCC ( COND_CS() ) ) /* BCS */
+OP(b1, OP_LDA ( DIY ) ) /* LDA diy */
+OP(b2, OP_LDA ( DI ) ) /* LDA di (C) */
+OP(b3, OP_LDA ( SIY ) ) /* LDA siy (G) */
+OP(b4, OP_LDX ( REG_Y, DX ) ) /* LDY dx */
+OP(b5, OP_LDA ( DX ) ) /* LDA dx */
+OP(b6, OP_LDX ( REG_X, DY ) ) /* LDX dy */
+OP(b7, OP_LDA ( DLIY ) ) /* LDA dliy(G) */
+OP(b8, OP_CLV ( ) ) /* CLV */
+OP(b9, OP_LDA ( AY ) ) /* LDA ay */
+OP(ba, OP_TSX ( ) ) /* TSX */
+OP(bb, OP_TYX ( ) ) /* TYX (G) */
+OP(bc, OP_LDX ( REG_Y, AX ) ) /* LDY ax */
+OP(bd, OP_LDA ( AX ) ) /* LDA ax */
+OP(be, OP_LDX ( REG_X, AY ) ) /* LDX ay */
+OP(bf, OP_LDA ( ALX ) ) /* LDA alx (G) */
+OP(c0, OP_CMPX ( REG_Y, IMM ) ) /* CPY imm */
+OP(c1, OP_CMP ( DXI ) ) /* CMP dxi */
+OP(c2, OP_REP ( ) ) /* REP (G) */
+OP(c3, OP_CMP ( S ) ) /* CMP s (G) */
+OP(c4, OP_CMPX ( REG_Y, D ) ) /* CPY d */
+OP(c5, OP_CMP ( D ) ) /* CMP d */
+OP(c6, OP_DECM ( D ) ) /* DEC d */
+OP(c7, OP_CMP ( DLI ) ) /* CMP dli (G) */
+OP(c8, OP_INCX ( REG_Y ) ) /* INY */
+OP(c9, OP_CMP ( IMM ) ) /* CMP imm */
+OP(ca, OP_DECX ( REG_X ) ) /* DEX */
+OP(cb, OP_WAI ( ) ) /* WAI (G) */
+OP(cc, OP_CMPX ( REG_Y, A ) ) /* CPY a */
+OP(cd, OP_CMP ( A ) ) /* CMP a */
+OP(ce, OP_DECM ( A ) ) /* DEC a */
+OP(cf, OP_CMP ( AL ) ) /* CMP al (G) */
+OP(d0, OP_BCC ( COND_NE() ) ) /* BNE */
+OP(d1, OP_CMP ( DIY ) ) /* CMP diy */
+OP(d2, OP_CMP ( DI ) ) /* CMP di (C) */
+OP(d3, OP_CMP ( SIY ) ) /* CMP siy (G) */
+OP(d4, OP_PEI ( ) ) /* PEI (G) */
+OP(d5, OP_CMP ( DX ) ) /* CMP dx */
+OP(d6, OP_DECM ( DX ) ) /* DEC dx */
+OP(d7, OP_CMP ( DLIY ) ) /* CMP dliy(G) */
+OP(d8, OP_CLM ( ) ) /* CLM */
+OP(d9, OP_CMP ( AY ) ) /* CMP ay */
+OP(da, OP_PHX ( REG_X ) ) /* PHX (C) */
+OP(db, OP_STP ( ) ) /* STP (G) */
+OP(dc, OP_JMLAI( ) ) /* JML ai (G) */
+OP(dd, OP_CMP ( AX ) ) /* CMP ax */
+OP(de, OP_DECM ( AX ) ) /* DEC ax */
+OP(df, OP_CMP ( ALX ) ) /* CMP alx (G) */
+OP(e0, OP_CMPX ( REG_X, IMM ) ) /* CPX imm */
+OP(e1, OP_SBC ( DXI ) ) /* SBC dxi */
+OP(e2, OP_SEP ( ) ) /* SEP imm (G) */
+OP(e3, OP_SBC ( S ) ) /* SBC s (G) */
+OP(e4, OP_CMPX ( REG_X, D ) ) /* CPX d */
+OP(e5, OP_SBC ( D ) ) /* SBC d */
+OP(e6, OP_INCM ( D ) ) /* INC d */
+OP(e7, OP_SBC ( DLI ) ) /* SBC dli (G) */
+OP(e8, OP_INCX ( REG_X ) ) /* INX */
+OP(e9, OP_SBC ( IMM ) ) /* SBC imm */
+OP(ea, OP_NOP ( ) ) /* NOP */
+OP(eb, OP_PSH ( IMM ) ) /* PSH imm */
+OP(ec, OP_CMPX ( REG_X, A ) ) /* CPX a */
+OP(ed, OP_SBC ( A ) ) /* SBC a */
+OP(ee, OP_INCM ( A ) ) /* INC a */
+OP(ef, OP_SBC ( AL ) ) /* SBC al (G) */
+OP(f0, OP_BCC ( COND_EQ() ) ) /* BEQ */
+OP(f1, OP_SBC ( DIY ) ) /* SBC diy */
+OP(f2, OP_SBC ( DI ) ) /* SBC di (C) */
+OP(f3, OP_SBC ( SIY ) ) /* SBC siy (G) */
+OP(f4, OP_PEA ( ) ) /* PEA (G) */
+OP(f5, OP_SBC ( DX ) ) /* SBC dx */
+OP(f6, OP_INCM ( DX ) ) /* INC dx */
+OP(f7, OP_SBC ( DLIY ) ) /* SBC dliy(G) */
+OP(f8, OP_SEM ( ) ) /* SEM */
+OP(f9, OP_SBC ( AY ) ) /* SBC ay */
+OP(fa, OP_PLX ( REG_X ) ) /* PLX (C) */
+OP(fb, OP_PUL ( IMM ) ) /* PUL imm */
+OP(fc, OP_JSRAXI( ) ) /* JSR axi (G) */
+OP(fd, OP_SBC ( AX ) ) /* SBC ax */
+OP(fe, OP_INCM ( AX ) ) /* INC ax */
+OP(ff, OP_SBC ( ALX ) ) /* SBC alx (G) */
+OP(101, OP_ORB ( DXI ) ) /* ORB dxi */
+OP(103, OP_ORB ( S ) ) /* ORB s (G) */
+OP(105, OP_ORB ( D ) ) /* ORB d */
+OP(107, OP_ORB ( DLI ) ) /* ORB dli (G) */
+OP(109, OP_ORB ( IMM ) ) /* ORB imm */
+OP(10a, OP_BSL ( ) ) /* BSL acc */
+OP(10d, OP_ORB ( A ) ) /* ORB a */
+OP(10f, OP_ORB ( AL ) ) /* ORB al (G) */
+OP(111, OP_ORB ( DIY ) ) /* ORB diy */
+OP(112, OP_ORB ( DI ) ) /* ORB di (C) */
+OP(113, OP_ORB ( SIY ) ) /* ORB siy (G) */
+OP(115, OP_ORB ( DX ) ) /* ORB dx */
+OP(117, OP_ORB ( DLIY ) ) /* ORB dliy(C) */
+OP(119, OP_ORB ( AY ) ) /* ORB ay */
+OP(11a, OP_DECB ( ) ) /* DEB (C) */
+OP(11d, OP_ORB ( AX ) ) /* ORB ax */
+OP(11f, OP_ORB ( ALX ) ) /* ORB alx (G) */
+OP(129, OP_ANDB ( IMM ) ) /* ANDB imm */
+OP(12a, OP_ROLB ( ) ) /* ROL Bacc */
+OP(13a, OP_INCB ( ) ) /* INB (C) */
+OP(148, OP_PHAB ( ) ) /* PHB */
+OP(149, OP_EORB ( IMM ) ) /* EORB imm */
+OP(14a, OP_LSRB ( ) ) /* LSRB acc */
+OP(161, OP_ADCB ( DXI ) ) /* ADCB dxi */
+OP(163, OP_ADCB ( S ) ) /* ADCB s (G) */
+OP(165, OP_ADCB ( D ) ) /* ADCB d */
+OP(167, OP_ADCB ( DLI ) ) /* ADCB dli (G) */
+OP(168, OP_PLAB ( ) ) /* PLB */
+OP(169, OP_ADCB ( IMM ) ) /* ADCB imm */
+OP(16a, OP_RORB ( ) ) /* ROR Bacc */
+OP(16d, OP_ADCB ( A ) ) /* ADCB a */
+OP(16f, OP_ADCB ( AL ) ) /* ADCB al (G) */
+OP(171, OP_ADCB ( DIY ) ) /* ADCB diy */
+OP(172, OP_ADCB ( DI ) ) /* ADCB di (G) */
+OP(173, OP_ADCB ( SIY ) ) /* ADCB siy (G) */
+OP(175, OP_ADCB ( DX ) ) /* ADCB dx */
+OP(177, OP_ADCB ( DLIY ) ) /* ADCB dliy(G) */
+OP(179, OP_ADCB ( AY ) ) /* ADCB ay */
+OP(17d, OP_ADCB ( AX ) ) /* ADCB ax */
+OP(17f, OP_ADCB ( ALX ) ) /* ADCB alx (G) */
+OP(181, OP_STB ( DXI ) ) /* STB dxi */
+OP(183, OP_STB ( S ) ) /* STB s (G) */
+OP(185, OP_STB ( D ) ) /* STB d */
+OP(187, OP_STB ( DLI ) ) /* STB dli (G) */
+OP(18a, OP_TXB ( REG_X ) ) /* TXB */
+OP(18d, OP_STB ( A ) ) /* STB a */
+OP(18f, OP_STB ( AL ) ) /* STB al (G) */
+OP(191, OP_STB ( DIY ) ) /* STB diy */
+OP(192, OP_STB ( DI ) ) /* STB di (C) */
+OP(193, OP_STB ( SIY ) ) /* STB siy (G) */
+OP(195, OP_STB ( DX ) ) /* STB dx */
+OP(197, OP_STB ( DLIY ) ) /* STB dliy(G) */
+OP(198, OP_TXB ( REG_Y ) ) /* TYB */
+OP(199, OP_STB ( AY ) ) /* STB ay */
+OP(19d, OP_STB ( AX ) ) /* STB ax */
+OP(19f, OP_STB ( ALX ) ) /* STB alx (G) */
+OP(1a1, OP_LDB ( DXI ) ) /* LDB dxi */
+OP(1a5, OP_LDB ( D ) ) /* LDB d */
+OP(1a8, OP_TBX ( REG_Y ) ) /* TBY */
+OP(1a9, OP_LDB ( IMM ) ) /* LDB imm */
+OP(1aa, OP_TBX ( REG_X ) ) /* TBX */
+OP(1ad, OP_LDB ( A ) ) /* LDB a */
+OP(1b2, OP_LDB ( DI ) ) /* LDB di (C) */
+OP(1b5, OP_LDB ( DX ) ) /* LDB dx */
+OP(1b9, OP_LDB ( AY ) ) /* LDB ay */
+OP(1bd, OP_LDB ( AX ) ) /* LDB ax */
+OP(1c1, OP_CMPB ( DXI ) ) /* CMPB dxi */
+OP(1c3, OP_CMPB ( S ) ) /* CMPB s (G) */
+OP(1c5, OP_CMPB ( D ) ) /* CMPB d */
+OP(1c7, OP_CMPB ( DLI ) ) /* CMPB dli (G) */
+OP(1c9, OP_CMPB ( IMM ) ) /* CMPB imm */
+OP(1cd, OP_CMPB ( A ) ) /* CMPB a */
+OP(1cf, OP_CMPB ( AL ) ) /* CMPB al (G) */
+OP(1d1, OP_CMPB ( DIY ) ) /* CMPB diy */
+OP(1d2, OP_CMPB ( DI ) ) /* CMPB di (C) */
+OP(1d3, OP_CMPB ( SIY ) ) /* CMPB siy (G) */
+OP(1d5, OP_CMPB ( DX ) ) /* CMPB dx */
+OP(1d7, OP_CMPB ( DLIY ) ) /* CMPB dliy(G) */
+OP(1d9, OP_CMPB ( AY ) ) /* CMPB ay */
+OP(1dd, OP_CMPB ( AX ) ) /* CMPB ax */
+OP(1df, OP_CMPB ( ALX ) ) /* CMPB alx (G) */
+OP(1e9, OP_SBCB ( IMM ) ) /* SBCB imm */
+OP(1f5, OP_SBCB ( DX ) ) /* SBCB dx */
+OP(200, OP_UNIMP ( ) ) /* unimplemented */
+OP(203, OP_MPY ( S ) ) /* MPY s */
+OP(205, OP_MPY ( D ) ) /* MPY d */
+OP(209, OP_MPY ( IMM ) ) /* MPY imm */
+OP(215, OP_MPY ( DX ) ) /* MPY dx */
+OP(219, OP_MPY ( AY ) ) /* MPY ay */
+OP(225, OP_DIV ( D ) ) /* DIV d */
+OP(228, OP_XAB ( ) ) /* XAB */
+OP(235, OP_DIV ( DX ) ) /* DIV dx */
+OP(249, OP_RLA ( IMM ) ) /* RLA imm */
+OP(2c2, OP_LDT ( IMM ) ) /* LDT imm */
+
+TABLE_OPCODES =
+{
+ O(00),O(01),O(02),O(03),O(04),O(05),O(06),O(07),
+ O(08),O(09),O(0a),O(0b),O(0c),O(0d),O(0e),O(0f),
+ O(10),O(11),O(12),O(13),O(14),O(15),O(16),O(17),
+ O(18),O(19),O(1a),O(1b),O(1c),O(1d),O(1e),O(1f),
+ O(20),O(21),O(22),O(23),O(24),O(25),O(26),O(27),
+ O(28),O(29),O(2a),O(2b),O(2c),O(2d),O(2e),O(2f),
+ O(30),O(31),O(32),O(33),O(34),O(35),O(36),O(37),
+ O(38),O(39),O(3a),O(3b),O(3c),O(3d),O(3e),O(3f),
+ O(40),O(41),O(42),O(43),O(44),O(45),O(46),O(47),
+ O(48),O(49),O(4a),O(4b),O(4c),O(4d),O(4e),O(4f),
+ O(50),O(51),O(52),O(53),O(54),O(55),O(56),O(57),
+ O(58),O(59),O(5a),O(5b),O(5c),O(5d),O(5e),O(5f),
+ O(60),O(61),O(62),O(63),O(64),O(65),O(66),O(67),
+ O(68),O(69),O(6a),O(6b),O(6c),O(6d),O(6e),O(6f),
+ O(70),O(71),O(72),O(73),O(74),O(75),O(76),O(77),
+ O(78),O(79),O(7a),O(7b),O(7c),O(7d),O(7e),O(7f),
+ O(80),O(81),O(82),O(83),O(84),O(85),O(86),O(87),
+ O(88),O(89),O(8a),O(8b),O(8c),O(8d),O(8e),O(8f),
+ O(90),O(91),O(92),O(93),O(94),O(95),O(96),O(97),
+ O(98),O(99),O(9a),O(9b),O(9c),O(9d),O(9e),O(9f),
+ O(a0),O(a1),O(a2),O(a3),O(a4),O(a5),O(a6),O(a7),
+ O(a8),O(a9),O(aa),O(ab),O(ac),O(ad),O(ae),O(af),
+ O(b0),O(b1),O(b2),O(b3),O(b4),O(b5),O(b6),O(b7),
+ O(b8),O(b9),O(ba),O(bb),O(bc),O(bd),O(be),O(bf),
+ O(c0),O(c1),O(c2),O(c3),O(c4),O(c5),O(c6),O(c7),
+ O(c8),O(c9),O(ca),O(cb),O(cc),O(cd),O(ce),O(cf),
+ O(d0),O(d1),O(d2),O(d3),O(d4),O(d5),O(d6),O(d7),
+ O(d8),O(d9),O(da),O(db),O(dc),O(dd),O(de),O(df),
+ O(e0),O(e1),O(e2),O(e3),O(e4),O(e5),O(e6),O(e7),
+ O(e8),O(e9),O(ea),O(eb),O(ec),O(ed),O(ee),O(ef),
+ O(f0),O(f1),O(f2),O(f3),O(f4),O(f5),O(f6),O(f7),
+ O(f8),O(f9),O(fa),O(fb),O(fc),O(fd),O(fe),O(ff)
+};
+
+TABLE_OPCODES2 =
+{
+ O(200),O(101),O(200),O(103),O(200),O(105),O(200),O(107),
+ O(200),O(109),O(10a),O(200),O(200),O(10d),O(200),O(10f),
+ O(200),O(111),O(112),O(113),O(200),O(115),O(200),O(117), // 10
+ O(200),O(119),O(11a),O(200),O(200),O(11d),O(200),O(11f),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 20
+ O(200),O(129),O(12a),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 30
+ O(200),O(200),O(13a),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 40
+ O(148),O(149),O(14a),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 50
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(161),O(200),O(163),O(200),O(165),O(200),O(167), // 60
+ O(168),O(169),O(16a),O(200),O(200),O(16d),O(200),O(16f),
+ O(200),O(171),O(172),O(173),O(200),O(175),O(200),O(177), // 70
+ O(200),O(179),O(200),O(200),O(200),O(17d),O(200),O(17f),
+ O(200),O(181),O(200),O(183),O(200),O(185),O(200),O(187), // 80
+ O(200),O(200),O(18a),O(200),O(200),O(18d),O(200),O(18f),
+ O(200),O(191),O(192),O(193),O(200),O(195),O(200),O(197), // 90
+ O(198),O(199),O(200),O(200),O(200),O(19d),O(200),O(19f),
+ O(200),O(1a1),O(200),O(200),O(200),O(1a5),O(200),O(200), // a0
+ O(1a8),O(1a9),O(1aa),O(200),O(200),O(1ad),O(200),O(200),
+ O(200),O(200),O(1b2),O(200),O(200),O(1b5),O(200),O(200), // b0
+ O(200),O(1b9),O(200),O(200),O(200),O(1bd),O(200),O(200),
+ O(200),O(1c1),O(200),O(1c3),O(200),O(1c5),O(200),O(1c7), // c0
+ O(200),O(1c9),O(200),O(200),O(200),O(1cd),O(200),O(1cf),
+ O(200),O(1d1),O(1d2),O(1d3),O(200),O(1d5),O(200),O(1d7), // d0
+ O(200),O(1d9),O(200),O(200),O(200),O(1dd),O(200),O(1df),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // e0
+ O(200),O(1e9),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(1f5),O(200),O(200), // f0
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200)
+};
+
+TABLE_OPCODES3 =
+{
+ O(200),O(200),O(200),O(203),O(200),O(205),O(200),O(200),
+ O(200),O(209),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(215),O(200),O(200), // 10
+ O(200),O(219),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(225),O(200),O(200), // 20
+ O(228),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(235),O(200),O(200), // 30
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 40
+ O(200),O(249),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 50
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 60
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 70
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 80
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 90
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // a0
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // b0
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(2c2),O(200),O(200),O(200),O(200),O(200), // c0
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // d0
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // e0
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200),
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // f0
+ O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200)
+};
+
+extern int m37710_irq_levels[M37710_LINE_MAX];
+
+/* Assert or clear a line on the CPU */
+TABLE_FUNCTION(void, set_line, (int line, int state))
+{
+ switch(line)
+ {
+ // maskable interrupts
+ case M37710_LINE_ADC:
+ case M37710_LINE_UART1XMIT:
+ case M37710_LINE_UART1RECV:
+ case M37710_LINE_UART0XMIT:
+ case M37710_LINE_UART0RECV:
+ case M37710_LINE_TIMERB2:
+ case M37710_LINE_TIMERB1:
+ case M37710_LINE_TIMERB0:
+ case M37710_LINE_TIMERA4:
+ case M37710_LINE_TIMERA3:
+ case M37710_LINE_TIMERA2:
+ case M37710_LINE_TIMERA1:
+ case M37710_LINE_TIMERA0:
+ case M37710_LINE_IRQ2:
+ case M37710_LINE_IRQ1:
+ case M37710_LINE_IRQ0:
+ switch(state)
+ {
+ case CLEAR_LINE:
+ LINE_IRQ &= ~(1 << line);
+ if (m37710_irq_levels[line])
+ {
+ m37710i_cpu.m37710_regs[m37710_irq_levels[line]] |= 8;
+ }
+ return;
+ break;
+ case ASSERT_LINE:
+ case PULSE_LINE:
+ case HOLD_LINE:
+ LINE_IRQ |= (1 << line);
+ if (m37710_irq_levels[line])
+ {
+ m37710i_cpu.m37710_regs[m37710_irq_levels[line]] &= ~8;
+ }
+ break;
+ }
+
+ // if I flag is set, trip the WAI mechanism only (may not be totally accurate)
+ if(FLAG_I)
+ {
+ if(CPU_STOPPED & STOP_LEVEL_WAI)
+ CPU_STOPPED &= ~STOP_LEVEL_WAI;
+ return;
+ }
+ return;
+ }
+}
+
+
+
+/* Get a register from the CPU core */
+TABLE_FUNCTION(uint, get_reg, (int regnum))
+{
+ switch(regnum)
+ {
+ case M37710_A: return REG_B | REG_A;
+ case M37710_B: return REG_BB | REG_BA;
+ case M37710_X: return REG_X;
+ case M37710_Y: return REG_Y;
+ case M37710_S: return REG_S;
+ case M37710_PC: return REG_PC;
+ case M37710_PB: return REG_PB >> 16;
+ case M37710_DB: return REG_DB >> 16;
+ case M37710_D: return REG_D;
+ case M37710_P: return m37710i_get_reg_p();
+ case M37710_IRQ_STATE: return LINE_IRQ;
+ case REG_PREVIOUSPC: return REG_PPC;
+ }
+ return 0;
+}
+
+TABLE_FUNCTION(void, set_reg, (int regnum, uint val))
+{
+ switch(regnum)
+ {
+ case M37710_PC: REG_PC = MAKE_UINT_16(val); break;
+ case M37710_S: REG_S = MAKE_UINT_16(val); break;
+ case M37710_P: m37710i_set_reg_p(val); break;
+#if FLAG_SET_M
+ case M37710_A: REG_A = MAKE_UINT_8(val); REG_B = val&0xff00; break;
+ case M37710_B: REG_BA = MAKE_UINT_8(val); REG_BB = val&0xff00; break;
+#else
+ case M37710_A: REG_A = MAKE_UINT_16(val); break;
+ case M37710_B: REG_BA = MAKE_UINT_16(val); break;
+#endif
+#if FLAG_SET_X
+ case M37710_X: REG_X = MAKE_UINT_8(val); break;
+ case M37710_Y: REG_Y = MAKE_UINT_8(val); break;
+#else
+ case M37710_X: REG_X = MAKE_UINT_16(val); break;
+ case M37710_Y: REG_Y = MAKE_UINT_16(val); break;
+#endif
+ case M37710_IRQ_STATE: FTABLE_SET_LINE(M37710_LINE_IRQ0, val == 0 ? CLEAR_LINE : ASSERT_LINE); break;
+ }
+}
+
+TABLE_FUNCTION(int, execute, (int clocks))
+{
+ if(!CPU_STOPPED)
+ {
+ CLOCKS = clocks;
+ do
+ {
+ REG_PPC = REG_PC;
+ M37710_CALL_DEBUGGER;
+ REG_PC++;
+ REG_IR = read_8_IMM(REG_PB | REG_PPC);
+ FTABLE_OPCODES[REG_IR]();
+ } while(CLOCKS > 0);
+ return clocks - CLOCKS;
+ }
+ return clocks;
+}
+
+
+/* ======================================================================== */
+/* ================================== EOF ================================= */
+/* ======================================================================== */
diff --git a/src/emu/cpu/m37710/m7700ds.c b/src/emu/cpu/m37710/m7700ds.c
new file mode 100644
index 00000000000..05fe804dda7
--- /dev/null
+++ b/src/emu/cpu/m37710/m7700ds.c
@@ -0,0 +1,614 @@
+/*
+
+Mitsubishi 7700 Series CPU disassembler v1.1
+
+By R. Belmont
+Based on G65C816 CPU Emulator by Karl Stenerud
+
+*/
+
+#include "cpuintrf.h"
+#include "m7700ds.h"
+
+#ifdef SEC
+#undef SEC
+#endif
+
+#define ADDRESS_24BIT(A) ((A)&0xffffff)
+
+#ifndef INLINE
+#define INLINE static
+#endif
+
+typedef struct
+{
+ unsigned char name;
+ unsigned char flag;
+ unsigned char ea;
+} opcode_struct;
+
+enum
+{
+ IMP , ACC , RELB, RELW, IMM , A , AI , AL , ALX , AX , AXI ,
+ AY , D , DI , DIY , DLI , DLIY, DX , DXI , DY , S , SIY ,
+ SIG /*, MVN , MVP , PEA , PEI , PER */, LDM4, LDM5, LDM4X, LDM5X,
+ BBCD, BBCA, ACCB
+};
+
+enum
+{
+ I, /* ignore */
+ M, /* check m bit */
+ X /* check x bit */
+};
+
+enum
+{
+ ADC , AND , ASL , BCC , BCS , BEQ , BIT , BMI , BNE , BPL , BRA ,
+ BRK , BRL , BVC , BVS , CLC , CLD , CLI , CLV , CMP , COP , CPX ,
+ CPY , DEA , DEC , DEX , DEY , EOR , INA , INC , INX , INY , JML ,
+ JMP , JSL , JSR , LDA , LDX , LDY , LSR , MVN , MVP , NOP , ORA ,
+ PEA , PEI , PER , PHA , PHT , PHD , PHK , PHP , PHX , PHY , PLA ,
+ PLB , PLD , PLP , PLX , PLY , CLP , ROL , ROR , RTI , RTL , RTS ,
+ SBC , SEC , SED , SEI , SEP , STA , STP , STX , STY , STZ , TAX ,
+ TAY , TCS , TCD , TDC , TRB , TSB , TSC , TSX , TXA , TXS , TXY ,
+ TYA , TYX , WAI , WDM , XBA , XCE , MPY , DIV , MPYS, DIVS, RLA ,
+ EXTS, EXTZ , LDT , LDM , UNK , SEB , SEM , CLM , STB , LDB , ADCB ,
+ SBCB, EORB , TBX , CMPB, INB , DEB , TXB , TYB , LSRB, ORB , CLB ,
+ BBC, BBS, TBY, ANDB, PUL , PSH , PLAB, XAB , PHB
+};
+
+static const char* g_opnames[] =
+{
+ "ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI", "BNE", "BPL", "BRA",
+ "BRK", "BRL", "BVC", "BVS", "CLC", "CLD", "CLI", "CLV", "CMP", "COP", "CPX",
+ "CPY", "DEA", "DEC", "DEX", "DEY", "EOR", "INA", "INC", "INX", "INY", "JML",
+ "JMP", "JSL", "JSR", "LDA", "LDX", "LDY", "LSR", "MVN", "MVP", "NOP", "ORA",
+ "PEA", "PEI", "PER", "PHA", "PHT", "PHD", "PHK", "PHP", "PHX", "PHY", "PLA",
+ "PLT", "PLD", "PLP", "PLX", "PLY", "CLP", "ROL", "ROR", "RTI", "RTL", "RTS",
+ "SBC", "SEC", "SED", "SEI", "SEP", "STA", "STP", "STX", "STY", "STZ", "TAX",
+ "TAY", "TCS", "TCD", "TDC", "TRB", "TSB", "TSC", "TSX", "TXA", "TXS", "TXY",
+ "TYA", "TYX", "WAI", "WDM", "XBA", "XCE", "MPY", "DIV", "MPYS", "DIVS", "RLA",
+ "EXTS","EXTZ","LDT", "LDM", "UNK", "SEB", "SEM", "CLM", "STB", "LDB", "ADCB",
+ "SBCB","EORB","TBX", "CMPB","INB", "DEB", "TXB", "TYB", "LSRB", "ORB", "CLB",
+ "BBC", "BBS", "TBY", "ANDB","PUL", "PSH", "PLB", "XAB", "PHB",
+};
+
+static opcode_struct g_opcodes[256] =
+{
+ {BRK, I, SIG }, {ORA, M, DXI }, {UNK, I, SIG }, {ORA, M, S },
+ {SEB, M, LDM4 }, {ORA, M, D }, {ASL, M, D }, {ORA, M, DLI },
+ {PHP, I, IMP }, {ORA, M, IMM }, {ASL, M, ACC }, {PHD, I, IMP },
+ {SEB, M, LDM5 }, {ORA, M, A }, {ASL, M, A }, {ORA, M, AL },
+// 0x10
+ {BPL, I, RELB}, {ORA, M, DIY }, {ORA, M, DI }, {ORA, M, SIY },
+ {CLB, M, LDM4}, {ORA, M, DX }, {ASL, M, DX }, {ORA, M, DLIY},
+ {CLC, I, IMP }, {ORA, M, AY }, {DEA, I, IMP }, {TCS, I, IMP },
+ {CLB, M, LDM5}, {ORA, M, AX }, {ASL, M, AX }, {ORA, M, ALX },
+// 0x20
+ {JSR, I, A }, {AND, M, DXI }, {JSL, I, AL }, {AND, M, S },
+ {BBS, M, BBCD}, {AND, M, D }, {ROL, M, D }, {AND, M, DLI },
+ {PLP, I, IMP }, {AND, M, IMM }, {ROL, M, ACC }, {PLD, I, IMP },
+ {BBS, M, BBCA}, {AND, M, A }, {ROL, M, A }, {AND, M, AL },
+// 0x30
+ {BMI, I, RELB}, {AND, M, DIY }, {AND, M, DI }, {AND, M, SIY },
+ {BBC, M, BBCD}, {AND, M, DX }, {ROL, M, DX }, {AND, M, DLIY},
+ {SEC, I, IMP }, {AND, M, AY }, {INA, I, IMP }, {TSC, I, IMP },
+ {BBC, M, BBCA}, {AND, M, AX }, {ROL, M, AX }, {AND, M, ALX },
+// 0x40
+ {RTI, I, IMP }, {EOR, M, DXI }, {WDM, I, IMP }, {EOR, M, S },
+ {MVP, I, MVP }, {EOR, M, D }, {LSR, M, D }, {EOR, M, DLI },
+ {PHA, I, IMP }, {EOR, M, IMM }, {LSR, M, ACC }, {PHK, I, IMP },
+ {JMP, I, A }, {EOR, M, A }, {LSR, M, A }, {EOR, M, AL },
+// 0x50
+ {BVC, I, RELB}, {EOR, M, DIY }, {EOR, M, DI }, {EOR, M, SIY },
+ {MVN, I, MVN }, {EOR, M, DX }, {LSR, M, DX }, {EOR, M, DLIY},
+ {CLI, I, IMP }, {EOR, M, AY }, {PHY, I, IMP }, {TCD, I, IMP },
+ {JMP, I, AL }, {EOR, M, AX }, {LSR, M, AX }, {EOR, M, ALX },
+// 0x60
+ {RTS, I, IMP }, {ADC, M, DXI }, {PER, I, PER }, {ADC, M, S },
+ {LDM, M, LDM4 }, {ADC, M, D }, {ROR, M, D }, {ADC, M, DLI },
+ {PLA, I, IMP }, {ADC, M, IMM }, {ROR, M, ACC }, {RTL, I, IMP },
+ {JMP, I, AI }, {ADC, M, A }, {ROR, M, A }, {ADC, M, AL },
+// 0x70
+ {BVS, I, RELB}, {ADC, M, DIY }, {ADC, M, DI }, {ADC, M, SIY },
+ {LDM, M, LDM4X }, {ADC, M, DX }, {ROR, M, DX }, {ADC, M, DLIY},
+ {SEI, I, IMP }, {ADC, M, AY }, {PLY, I, IMP }, {TDC, I, IMP },
+ {JMP, I, AXI }, {ADC, M, AX }, {ROR, M, AX }, {ADC, M, ALX },
+// 0x80
+ {BRA, I, RELB}, {STA, M, DXI }, {BRL, I, RELW}, {STA, M, S },
+ {STY, X, D }, {STA, M, D }, {STX, X, D }, {STA, M, DLI },
+ {DEY, I, IMP }, {BIT, M, IMM }, {TXA, I, IMP }, {PHT, I, IMP },
+ {STY, X, A }, {STA, M, A }, {STX, X, A }, {STA, M, AL },
+// 0x90
+ {BCC, I, RELB}, {STA, M, DIY }, {STA, M, DI }, {STA, M, SIY },
+ {STY, X, DX }, {STA, M, DX }, {STX, X, DY }, {STA, M, DLIY},
+ {TYA, I, IMP }, {STA, M, AY }, {TXS, I, IMP }, {TXY, I, IMP },
+ {LDM, M, LDM5 }, {STA, M, AX }, {LDM, M, LDM5X }, {STA, M, ALX },
+// 0xA0
+ {LDY, X, IMM }, {LDA, M, DXI }, {LDX, X, IMM }, {LDA, M, S },
+ {LDY, X, D }, {LDA, M, D }, {LDX, X, D }, {LDA, M, DLI },
+ {TAY, I, IMP }, {LDA, M, IMM }, {TAX, I, IMP }, {PLB, I, IMP },
+ {LDY, X, A }, {LDA, M, A }, {LDX, X, A }, {LDA, M, AL },
+// 0xB0
+ {BCS, I, RELB}, {LDA, M, DIY }, {LDA, M, DI }, {LDA, M, SIY },
+ {LDY, X, DX }, {LDA, M, DX }, {LDX, X, DY }, {LDA, M, DLIY},
+ {CLV, I, IMP }, {LDA, M, AY }, {TSX, I, IMP }, {TYX, I, IMP },
+ {LDY, X, AX }, {LDA, M, AX }, {LDX, X, AY }, {LDA, M, ALX },
+// 0xC0
+ {CPY, X, IMM }, {CMP, M, DXI }, {CLP, I, IMM }, {CMP, M, S },
+ {CPY, X, D }, {CMP, M, D }, {DEC, M, D }, {CMP, M, DLI },
+ {INY, I, IMP }, {CMP, M, IMM }, {DEX, I, IMP }, {WAI, I, IMP },
+ {CPY, X, A }, {CMP, M, A }, {DEC, M, A }, {CMP, M, AL },
+// 0xD0
+ {BNE, I, RELB}, {CMP, M, DIY }, {CMP, M, DI }, {CMP, M, SIY },
+ {PEI, I, PEI }, {CMP, M, DX }, {DEC, M, DX }, {CMP, M, DLIY},
+ {CLM, I, IMP }, {CMP, M, AY }, {PHX, I, IMP }, {STP, I, IMP },
+ {JML, I, AI }, {CMP, M, AX }, {DEC, M, AX }, {CMP, M, ALX },
+// 0xE0
+ {CPX, X, IMM }, {SBC, M, DXI }, {SEP, I, IMM }, {SBC, M, S },
+ {CPX, X, D }, {SBC, M, D }, {INC, M, D }, {SBC, M, DLI },
+ {INX, M, IMP }, {SBC, M, IMM }, {NOP, I, IMP }, {PSH, I, IMM },
+ {CPX, X, A }, {SBC, M, A }, {INC, M, A }, {SBC, M, AL },
+// 0xF0
+ {BEQ, I, RELB}, {SBC, M, DIY }, {SBC, M, DI }, {SBC, M, SIY },
+ {PEA, I, PEA }, {SBC, M, DX }, {INC, M, DX }, {SBC, M, DLIY},
+ {SEM, I, IMP }, {SBC, M, AY }, {PLX, I, IMP }, {PUL, I, IMM },
+ {JSR, I, AXI }, {SBC, M, AX }, {INC, M, AX }, {SBC, M, ALX }
+};
+
+static opcode_struct g_opcodes_prefix42[256] =
+{
+ {BRK, I, SIG }, {ORB, M, DXI }, {COP, I, SIG }, {ORB, M, S },
+ {TSB, M, D }, {ORB, M, D }, {ASL, M, D }, {ORB, M, DLI },
+ {PHP, I, IMP }, {ORB, M, IMM }, {ASL, M, ACCB }, {PHD, I, IMP },
+ {TSB, M, A }, {ORB, M, A }, {ASL, M, A }, {ORB, M, AL },
+// 0x10
+ {BPL, I, RELB}, {ORB, M, DIY }, {ORB, M, DI }, {ORB, M, SIY },
+ {TRB, M, D }, {ORB, M, DX }, {ASL, M, DX }, {ORB, M, DLIY},
+ {CLC, I, IMP }, {ORB, M, AY }, {DEB, I, IMP }, {TCS, I, IMP },
+ {TRB, M, A }, {ORB, M, AX }, {ASL, M, AX }, {ORB, M, ALX },
+// 0x20
+ {JSR, I, A }, {ANDB, M, DXI }, {JSL, I, AL }, {ANDB, M, S },
+ {BIT, M, D }, {ANDB, M, D }, {ROL, M, D }, {ANDB, M, DLI },
+ {PLP, I, IMP }, {ANDB, M, IMM }, {ROL, M, ACCB }, {PLD, I, IMP },
+ {BIT, M, A }, {ANDB, M, A }, {ROL, M, A }, {ANDB, M, AL },
+// 0x30
+ {BMI, I, RELB}, {AND, M, DIY }, {AND, M, DI }, {AND, M, SIY },
+ {BIT, M, DX }, {AND, M, DX }, {ROL, M, DX }, {AND, M, DLIY},
+ {SEC, I, IMP }, {AND, M, AY }, {INB, I, IMP }, {TSC, I, IMP },
+ {BIT, M, AX }, {AND, M, AX }, {ROL, M, AX }, {AND, M, ALX },
+// 0x40
+ {RTI, I, IMP }, {EORB, M, DXI }, {WDM, I, IMP }, {EORB, M, S },
+ {MVP, I, MVP }, {EORB, M, D }, {LSRB, M, D }, {EORB, M, DLI },
+ {PHB, I, IMP }, {EORB, M, IMM }, {LSRB, M, ACC }, {PHK, I, IMP },
+ {JMP, I, A }, {EORB, M, A }, {LSRB, M, A }, {EORB, M, AL },
+// 0x50
+ {BVC, I, RELB}, {EORB, M, DIY }, {EORB, M, DI }, {EORB, M, SIY },
+ {MVN, I, MVN }, {EORB, M, DX }, {LSRB, M, DX }, {EORB, M, DLIY},
+ {CLI, I, IMP }, {EORB, M, AY }, {PHY, I, IMP }, {TCD, I, IMP },
+ {JMP, I, AL }, {EORB, M, AX }, {LSRB, M, AX }, {EORB, M, ALX },
+// 0x60
+ {RTS, I, IMP }, {ADCB, M, DXI }, {PER, I, PER }, {ADCB, M, S },
+ {STZ, M, D }, {ADCB, M, D }, {ROR, M, D }, {ADCB, M, DLI },
+ {PLAB,I, IMP }, {ADCB, M, IMM }, {ROR, M, ACC }, {RTL, I, IMP },
+ {JMP, I, AI }, {ADCB, M, A }, {ROR, M, A }, {ADCB, M, AL },
+// 0x70
+ {BVS, I, RELB}, {ADCB, M, DIY }, {ADCB, M, DI }, {ADCB, M, SIY },
+ {STZ, M, DX }, {ADCB, M, DX }, {ROR, M, DX }, {ADCB, M, DLIY},
+ {SEI, I, IMP }, {ADCB, M, AY }, {PLY, I, IMP }, {TDC, I, IMP },
+ {JMP, I, AXI }, {ADCB, M, AX }, {ROR, M, AX }, {ADCB, M, ALX },
+// 0x80
+ {BRA, I, RELB}, {STB, M, DXI }, {BRL, I, RELW}, {STB, M, S },
+ {STY, X, D }, {STB, M, D }, {STX, X, D }, {STB, M, DLI },
+ {DEY, I, IMP }, {BIT, M, IMM }, {TXB, I, IMP }, {PHB, I, IMP },
+ {STY, X, A }, {STB, M, A }, {STX, X, A }, {STB, M, AL },
+// 0x90
+ {BCC, I, RELB}, {STB, M, DIY }, {STB, M, DI }, {STB, M, SIY },
+ {STY, X, DX }, {STB, M, DX }, {STX, X, DY }, {STB, M, DLIY},
+ {TYB, I, IMP }, {STB, M, AY }, {TXS, I, IMP }, {TXY, I, IMP },
+ {STZ, M, A }, {STB, M, AX }, {STZ, M, AX }, {STB, M, ALX },
+// 0xA0
+ {LDY, X, IMM }, {LDB, M, DXI }, {LDX, X, IMM }, {LDB, M, S },
+ {LDY, X, D }, {LDB, M, D }, {LDX, X, D }, {LDB, M, DLI },
+ {TBY, I, IMP }, {LDB, M, IMM }, {TBX, I, IMP }, {PLB, I, IMP },
+ {LDY, X, A }, {LDB, M, A }, {LDX, X, A }, {LDB, M, AL },
+// 0xB0
+ {BCS, I, RELB}, {LDB, M, DIY }, {LDB, M, DI }, {LDB, M, SIY },
+ {LDY, X, DX }, {LDB, M, DX }, {LDX, X, DY }, {LDB, M, DLIY},
+ {CLV, I, IMP }, {LDB, M, AY }, {TSX, I, IMP }, {TYX, I, IMP },
+ {LDY, X, AX }, {LDB, M, AX }, {LDX, X, AY }, {LDB, M, ALX },
+// 0xC0
+ {CPY, X, IMM }, {CMPB, M, DXI }, {CLP, I, IMM }, {CMPB, M, S },
+ {CPY, X, D }, {CMPB, M, D }, {DEC, M, D }, {CMPB, M, DLI },
+ {INY, I, IMP }, {CMPB, M, IMM }, {DEX, I, IMP }, {WAI, I, IMP },
+ {CPY, X, A }, {CMPB, M, A }, {DEC, M, A }, {CMPB, M, AL },
+// 0xD0
+ {BNE, I, RELB}, {CMPB, M, DIY }, {CMPB, M, DI }, {CMPB, M, SIY },
+ {PEI, I, PEI }, {CMPB, M, DX }, {DEC, M, DX }, {CMPB, M, DLIY},
+ {CLD, I, IMP }, {CMPB, M, AY }, {PHX, I, IMP }, {STP, I, IMP },
+ {JML, I, AI }, {CMPB, M, AX }, {DEC, M, AX }, {CMPB, M, ALX },
+// 0xE0
+ {CPX, X, IMM }, {SBCB, M, DXI }, {SEP, I, IMM }, {SBCB, M, S },
+ {CPX, X, D }, {SBCB, M, D }, {INC, M, D }, {SBCB, M, DLI },
+ {INX, M, IMP }, {SBCB, M, IMM }, {NOP, I, IMP }, {XBA, I, IMP },
+ {CPX, X, A }, {SBCB, M, A }, {INC, M, A }, {SBCB, M, AL },
+// 0xF0
+ {BEQ, I, RELB}, {SBCB, M, DIY }, {SBCB, M, DI }, {SBCB, M, SIY },
+ {PEA, I, PEA }, {SBCB, M, DX }, {INC, M, DX }, {SBCB, M, DLIY},
+ {SED, I, IMP }, {SBCB, M, AY }, {PLX, I, IMP }, {XCE, I, IMP },
+ {JSR, I, AXI }, {SBCB, M, AX }, {INC, M, AX }, {SBCB, M, ALX }
+};
+
+static opcode_struct g_opcodes_prefix89[256] =
+{
+ {BRK, I, SIG }, {MPY, M, DXI }, {COP, I, SIG }, {MPY, M, S },
+ {TSB, M, D }, {MPY, M, D }, {ASL, M, D }, {MPY, M, DLI },
+ {PHP, I, IMP }, {MPY, M, IMM }, {ASL, M, ACC }, {PHD, I, IMP },
+ {TSB, M, A }, {MPY, M, A }, {ASL, M, A }, {MPY, M, AL },
+// 0x10
+ {BPL, I, RELB}, {ORA, M, DIY }, {ORA, M, DI }, {ORA, M, SIY },
+ {TRB, M, D }, {MPY, M, DX }, {ASL, M, DX }, {ORA, M, DLIY},
+ {CLC, I, IMP }, {MPY, M, AY }, {INA, I, IMP }, {TCS, I, IMP },
+ {TRB, M, A }, {ORA, M, AX }, {ASL, M, AX }, {ORA, M, ALX },
+// 0x20
+ {JSR, I, A }, {AND, M, DXI }, {JSL, I, AL }, {AND, M, S },
+ {BIT, M, D }, {AND, M, D }, {ROL, M, D }, {AND, M, DLI },
+ {XAB, I, IMP }, {AND, M, IMM }, {ROL, M, ACC }, {PLD, I, IMP },
+ {BIT, M, A }, {AND, M, A }, {ROL, M, A }, {AND, M, AL },
+// 0x30
+ {BMI, I, RELB}, {AND, M, DIY }, {AND, M, DI }, {AND, M, SIY },
+ {BIT, M, DX }, {AND, M, DX }, {ROL, M, DX }, {AND, M, DLIY},
+ {SEC, I, IMP }, {AND, M, AY }, {DEA, I, IMP }, {TSC, I, IMP },
+ {BIT, M, AX }, {AND, M, AX }, {ROL, M, AX }, {AND, M, ALX },
+// 0x40
+ {RTI, I, IMP }, {EOR, M, DXI }, {WDM, I, IMP }, {EOR, M, S },
+ {MVP, I, MVP }, {EOR, M, D }, {LSR, M, D }, {EOR, M, DLI },
+ {PHA, I, IMP }, {RLA, M, IMM }, {LSR, M, ACC }, {PHK, I, IMP },
+ {JMP, I, A }, {EOR, M, A }, {LSR, M, A }, {EOR, M, AL },
+// 0x50
+ {BVC, I, RELB}, {EOR, M, DIY }, {EOR, M, DI }, {EOR, M, SIY },
+ {MVN, I, MVN }, {EOR, M, DX }, {LSR, M, DX }, {EOR, M, DLIY},
+ {CLI, I, IMP }, {EOR, M, AY }, {PHY, I, IMP }, {TCD, I, IMP },
+ {JMP, I, AL }, {EOR, M, AX }, {LSR, M, AX }, {EOR, M, ALX },
+// 0x60
+ {RTS, I, IMP }, {ADC, M, DXI }, {PER, I, PER }, {ADC, M, S },
+ {STZ, M, D }, {ADC, M, D }, {ROR, M, D }, {ADC, M, DLI },
+ {PLA, I, IMP }, {ADC, M, IMM }, {ROR, M, ACC }, {RTL, I, IMP },
+ {JMP, I, AI }, {ADC, M, A }, {ROR, M, A }, {ADC, M, AL },
+// 0x70
+ {BVS, I, RELB}, {ADC, M, DIY }, {ADC, M, DI }, {ADC, M, SIY },
+ {STZ, M, DX }, {ADC, M, DX }, {ROR, M, DX }, {ADC, M, DLIY},
+ {SEI, I, IMP }, {ADC, M, AY }, {PLY, I, IMP }, {TDC, I, IMP },
+ {JMP, I, AXI }, {ADC, M, AX }, {ROR, M, AX }, {ADC, M, ALX },
+// 0x80
+ {BRA, I, RELB}, {STA, M, DXI }, {BRL, I, RELW}, {STA, M, S },
+ {STY, X, D }, {STA, M, D }, {STX, X, D }, {STA, M, DLI },
+ {DEY, I, IMP }, {BIT, M, IMM }, {TXA, I, IMP }, {PHB, I, IMP },
+ {STY, X, A }, {STA, M, A }, {STX, X, A }, {STA, M, AL },
+// 0x90
+ {BCC, I, RELB}, {STA, M, DIY }, {STA, M, DI }, {STA, M, SIY },
+ {STY, X, DX }, {STA, M, DX }, {STX, X, DY }, {STA, M, DLIY},
+ {TYA, I, IMP }, {STA, M, AY }, {TXS, I, IMP }, {TXY, I, IMP },
+ {STZ, M, A }, {STA, M, AX }, {STZ, M, AX }, {STA, M, ALX },
+// 0xA0
+ {LDY, X, IMM }, {LDA, M, DXI }, {LDX, X, IMM }, {LDA, M, S },
+ {LDY, X, D }, {LDA, M, D }, {LDX, X, D }, {LDA, M, DLI },
+ {TAY, I, IMP }, {LDA, M, IMM }, {TAX, I, IMP }, {PLB, I, IMP },
+ {LDY, X, A }, {LDA, M, A }, {LDX, X, A }, {LDA, M, AL },
+// 0xB0
+ {BCS, I, RELB}, {LDA, M, DIY }, {LDA, M, DI }, {LDA, M, SIY },
+ {LDY, X, DX }, {LDA, M, DX }, {LDX, X, DY }, {LDA, M, DLIY},
+ {CLV, I, IMP }, {LDA, M, AY }, {TSX, I, IMP }, {TYX, I, IMP },
+ {LDY, X, AX }, {LDA, M, AX }, {LDX, X, AY }, {LDA, M, ALX },
+// 0xC0
+ {CPY, X, IMM }, {CMP, M, DXI }, {LDT, I, IMM }, {CMP, M, S },
+ {CPY, X, D }, {CMP, M, D }, {DEC, M, D }, {CMP, M, DLI },
+ {INY, I, IMP }, {CMP, M, IMM }, {DEX, I, IMP }, {WAI, I, IMP },
+ {CPY, X, A }, {CMP, M, A }, {DEC, M, A }, {CMP, M, AL },
+// 0xD0
+ {BNE, I, RELB}, {CMP, M, DIY }, {CMP, M, DI }, {CMP, M, SIY },
+ {PEI, I, PEI }, {CMP, M, DX }, {DEC, M, DX }, {CMP, M, DLIY},
+ {CLD, I, IMP }, {CMP, M, AY }, {PHX, I, IMP }, {STP, I, IMP },
+ {JML, I, AI }, {CMP, M, AX }, {DEC, M, AX }, {CMP, M, ALX },
+// 0xE0
+ {CPX, X, IMM }, {SBC, M, DXI }, {SEP, I, IMM }, {SBC, M, S },
+ {CPX, X, D }, {SBC, M, D }, {INC, M, D }, {SBC, M, DLI },
+ {INX, M, IMP }, {SBC, M, IMM }, {NOP, I, IMP }, {XBA, I, IMP },
+ {CPX, X, A }, {SBC, M, A }, {INC, M, A }, {SBC, M, AL },
+// 0xF0
+ {BEQ, I, RELB}, {SBC, M, DIY }, {SBC, M, DI }, {SBC, M, SIY },
+ {PEA, I, PEA }, {SBC, M, DX }, {INC, M, DX }, {SBC, M, DLIY},
+ {SEM, I, IMP }, {SBC, M, AY }, {PLX, I, IMP }, {XCE, I, IMP },
+ {JSR, I, AXI }, {SBC, M, AX }, {INC, M, AX }, {SBC, M, ALX }
+};
+
+INLINE unsigned int read_8(const UINT8 *oprom, unsigned int offset)
+{
+ return oprom[offset];
+}
+
+INLINE unsigned int read_16(const UINT8 *oprom, unsigned int offset)
+{
+ unsigned int val = read_8(oprom, offset);
+ return val | (read_8(oprom, offset+1)<<8);
+}
+
+INLINE unsigned int read_24(const UINT8 *oprom, unsigned int offset)
+{
+ unsigned int val = read_8(oprom, offset);
+ val |= (read_8(oprom, offset+1)<<8);
+ return val | (read_8(oprom, offset+2)<<16);
+}
+
+INLINE char* int_8_str(unsigned int val)
+{
+ static char str[20];
+
+ val &= 0xff;
+
+ if(val & 0x80)
+ sprintf(str, "-$%x", (0-val) & 0x7f);
+ else
+ sprintf(str, "$%x", val & 0x7f);
+
+ return str;
+}
+
+INLINE char* int_16_str(unsigned int val)
+{
+ static char str[20];
+
+ val &= 0xffff;
+
+ if(val & 0x8000)
+ sprintf(str, "-$%x", (0-val) & 0x7fff);
+ else
+ sprintf(str, "$%x", val & 0x7fff);
+
+ return str;
+}
+
+
+int m7700_disassemble(char* buff, unsigned int pc, unsigned int pb, const UINT8 *oprom, int m_flag, int x_flag)
+{
+ unsigned int instruction;
+ opcode_struct *opcode;
+ char* ptr;
+ int var;
+ signed char varS;
+ int length = 1;
+ unsigned int address;
+ unsigned int start;
+ UINT32 flags = 0;
+
+ pb <<= 16;
+ address = pc | pb;
+ start = address;
+
+ instruction = read_8(oprom,0);
+
+ // check for prefixes
+ switch (instruction)
+ {
+ case 0x42:
+ address++;
+ length++;
+ oprom++;
+ instruction = read_8(oprom,0);
+ opcode = g_opcodes_prefix42 + instruction;
+ break;
+
+ case 0x89:
+ address++;
+ length++;
+ oprom++;
+ instruction = read_8(oprom,0);
+ opcode = g_opcodes_prefix89 + instruction;
+ break;
+
+ default:
+ opcode = g_opcodes + instruction;
+ break;
+ }
+
+ if (opcode->name == JSR)
+ flags = DASMFLAG_STEP_OVER;
+ else if (opcode->name == RTS || opcode->name == RTI)
+ flags = DASMFLAG_STEP_OUT;
+
+ sprintf(buff, "%s", g_opnames[opcode->name]);
+ ptr = buff + strlen(buff);
+
+ switch(opcode->ea)
+ {
+ case IMP :
+ break;
+ case ACC :
+ sprintf(ptr, " A");
+ break;
+ case ACCB :
+ sprintf(ptr, " B");
+ break;
+ case RELB:
+ varS = read_8(oprom,1);
+ length++;
+ sprintf(ptr, " %06x (%s)", pb | ((pc + length + varS)&0xffff), int_8_str(varS));
+ break;
+ case RELW:
+ case PER :
+ var = read_16(oprom,1);
+ sprintf(ptr, " %06x (%s)", pb | ((pc + 1 + var)&0xffff), int_16_str(var));
+ length += 2;
+ break;
+ case IMM :
+ if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag))
+ {
+ sprintf(ptr, " #$%04x", read_16(oprom,1));
+ length += 2;
+ }
+ else
+ {
+ sprintf(ptr, " #$%02x", read_8(oprom,1));
+ length++;
+ }
+ break;
+ case BBCD:
+ if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag))
+ {
+ varS = read_8(oprom,4);
+ length += 4;
+ sprintf(ptr, " #$%04x, $%02x, %06x (%s)", read_16(oprom,2), read_8(oprom,1), pb | ((pc + length + varS)&0xffff), int_8_str(varS));
+ }
+ else
+ {
+ varS = read_8(oprom,3);
+ length += 3;
+ sprintf(ptr, " #$%02x, $%02x, %06x (%s)", read_8(oprom,2), read_8(oprom,1), pb | ((pc + length + varS)&0xffff), int_8_str(varS));
+ }
+ break;
+ case BBCA:
+ if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag))
+ {
+ length += 5;
+ varS = read_8(oprom,5);
+ sprintf(ptr, " #$%04x, $%04x, %06x (%s)", read_16(oprom,3), read_16(oprom,1), pb | ((pc + length + varS)&0xffff), int_8_str(varS));
+ }
+ else
+ {
+ length += 4;
+ varS = read_8(oprom,4);
+ sprintf(ptr, " #$%02x, $%04x, %06x (%s)", read_8(oprom,3), read_16(oprom,1), pb | ((pc + length + varS)&0xffff), int_8_str(varS));
+ }
+ break;
+ case LDM4:
+ if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag))
+ {
+ sprintf(ptr, " #$%04x, $%02x", read_16(oprom,2), read_8(oprom,1));
+ length += 3;
+ }
+ else
+ {
+ sprintf(ptr, " #$%02x, $%02x", read_8(oprom,2), read_8(oprom,1));
+ length += 2;
+ }
+ break;
+ case LDM5:
+ if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag))
+ {
+ sprintf(ptr, " #$%04x, $%04x", read_16(oprom,3), read_16(oprom,1));
+ length += 4;
+ }
+ else
+ {
+ sprintf(ptr, " #$%02x, $%04x", read_8(oprom,3), read_16(oprom,1));
+ length += 3;
+ }
+ break;
+ case LDM4X:
+ if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag))
+ {
+ sprintf(ptr, " #$%04x, $%02x, X", read_16(oprom,2), read_8(oprom,1));
+ length += 3;
+ }
+ else
+ {
+ sprintf(ptr, " #$%02x, $%02x, X", read_8(oprom,2), read_8(oprom,1));
+ length += 2;
+ }
+ break;
+ case LDM5X:
+ if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag))
+ {
+ sprintf(ptr, " #$%04x, $%04x, X", read_16(oprom,3), read_16(oprom,1));
+ length += 4;
+ }
+ else
+ {
+ sprintf(ptr, " #$%02x, $%04x, X", read_8(oprom,3), read_16(oprom,1));
+ length += 3;
+ }
+ break;
+ case A :
+ case PEA :
+ sprintf(ptr, " $%04x", read_16(oprom,1));
+ length += 2;
+ break;
+ case AI :
+ sprintf(ptr, " ($%04x)", read_16(oprom,1));
+ length += 2;
+ break;
+ case AL :
+ sprintf(ptr, " $%06x", read_24(oprom,1));
+ length += 3;
+ break;
+ case ALX :
+ sprintf(ptr, " $%06x,X", read_24(oprom,1));
+ length += 3;
+ break;
+ case AX :
+ sprintf(ptr, " $%04x,X", read_16(oprom,1));
+ length += 2;
+ break;
+ case AXI :
+ sprintf(ptr, " ($%04x,X)", read_16(oprom,1));
+ length += 2;
+ break;
+ case AY :
+ sprintf(ptr, " $%04x,Y", read_16(oprom,1));
+ length += 2;
+ break;
+ case D :
+ sprintf(ptr, " $%02x", read_8(oprom,1));
+ length++;
+ break;
+ case DI :
+ case PEI :
+ sprintf(ptr, " ($%02x)", read_8(oprom,1));
+ length++;
+ break;
+ case DIY :
+ sprintf(ptr, " ($%02x),Y", read_8(oprom,1));
+ length++;
+ break;
+ case DLI :
+ sprintf(ptr, " [$%02x]", read_8(oprom,1));
+ length++;
+ break;
+ case DLIY:
+ sprintf(ptr, " [$%02x],Y", read_8(oprom,1));
+ length++;
+ break;
+ case DX :
+ sprintf(ptr, " $%02x,X", read_8(oprom,1));
+ length++;
+ break;
+ case DXI :
+ sprintf(ptr, " ($%02x,X)", read_8(oprom,1));
+ length++;
+ break;
+ case DY :
+ sprintf(ptr, " $%02x,Y", read_8(oprom,1));
+ length++;
+ break;
+ case S :
+ sprintf(ptr, " %s,S", int_8_str(read_8(oprom,1)));
+ length++;
+ break;
+ case SIY :
+ sprintf(ptr, " (%s,S),Y", int_8_str(read_8(oprom,1)));
+ length++;
+ break;
+ case SIG :
+ sprintf(ptr, " #$%02x", read_8(oprom,1));
+ length++;
+ break;
+ case MVN :
+ case MVP :
+ sprintf(ptr, " $%02x, $%02x", read_8(oprom,2), read_8(oprom,1));
+ length += 2;
+ break;
+ }
+
+ return length | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/m37710/m7700ds.h b/src/emu/cpu/m37710/m7700ds.h
new file mode 100644
index 00000000000..b298cd46963
--- /dev/null
+++ b/src/emu/cpu/m37710/m7700ds.h
@@ -0,0 +1,19 @@
+#ifndef HEADER__M7700DS
+#define HEADER__M7700DS
+
+/*
+
+Mitsubishi 7700 CPU Emulator v0.10
+By R. Belmont
+
+Based on:
+G65C816 CPU Emulator V0.92
+
+Copyright (c) 2000 Karl Stenerud
+All rights reserved.
+
+*/
+
+int m7700_disassemble(char* buff, unsigned int pc, unsigned int pb, const UINT8 *oprom, int m_flag, int x_flag);
+
+#endif /* HEADER__7700DS */
diff --git a/src/emu/cpu/m6502/6502dasm.c b/src/emu/cpu/m6502/6502dasm.c
new file mode 100644
index 00000000000..e89067237c5
--- /dev/null
+++ b/src/emu/cpu/m6502/6502dasm.c
@@ -0,0 +1,788 @@
+/*****************************************************************************
+ *
+ * 6502dasm.c
+ * 6502/65c02/6510 disassembler
+ *
+ * Copyright (c) 1998 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+/* 2. February 2000 PeT added support for 65sc02 subtype */
+/* 2. February 2000 PeT added support for 65ce02 variant */
+/* 3. February 2000 PeT bbr bbs displayment */
+/* 4. February 2000 PeT ply inw dew */
+/* 4. February 2000 PeT fixed relative word operand */
+/* 9. May 2000 PeT added m4510 */
+
+#include "debugger.h"
+#include "m6502.h"
+#if (HAS_M65CE02)
+#include "m65ce02.h"
+#endif
+#if (HAS_M6509)
+#include "m6509.h"
+#endif
+#if (HAS_M4510)
+#include "m4510.h"
+#endif
+
+enum addr_mode {
+ non, /* no additional arguments */
+ imp, /* implicit */
+ acc, /* accumulator */
+ imm, /* immediate */
+ iw2, /* immediate word (65ce02) */
+ iw3, /* augment (65ce02) */
+ adr, /* absolute address (jmp,jsr) */
+ aba, /* absolute */
+ zpg, /* zero page */
+ zpx, /* zero page + X */
+ zpy, /* zero page + Y */
+ zpi, /* zero page indirect (65c02) */
+ zpb, /* zero page and branch (65c02 bbr,bbs) */
+ abx, /* absolute + X */
+ aby, /* absolute + Y */
+ rel, /* relative */
+ rw2, /* relative word (65cs02, 65ce02) */
+ idx, /* zero page pre indexed */
+ idy, /* zero page post indexed */
+ idz, /* zero page post indexed (65ce02) */
+ isy, /* zero page pre indexed sp and post indexed y (65ce02) */
+ ind, /* indirect (jmp) */
+ iax /* indirect + X (65c02 jmp) */
+};
+
+enum opcodes {
+ adc, and, asl, bcc, bcs, beq, bit, bmi,
+ bne, bpl, m6502_brk, bvc, bvs, clc, cld, cli,
+ clv, cmp, cpx, cpy, dec, dex, dey, eor,
+ inc, inx, iny, jmp, jsr, lda, ldx, ldy,
+ lsr, nop, ora, pha, php, pla, plp, rol,
+ ror, rti, rts, sbc, sec, sed, sei, sta,
+ stx, sty, tax, tay, tsx, txa, txs, tya,
+ ill,
+/* 65c02 (only) mnemonics */
+ bbr, bbs, bra, rmb, smb, stz, trb, tsb,
+/* 65sc02 (only) mnemonics */
+ bsr,
+/* 6510 + 65c02 mnemonics */
+ anc, asr, ast, arr, asx, axa, dcp, dea,
+ dop, ina, isc, lax, phx, phy, plx, ply,
+ rla, rra, sax, slo, sre, sah, say, ssh,
+ sxh, syh, top, oal, kil,
+/* 65ce02 mnemonics */
+ cle, see, rtn, aug,
+ tab, tba, taz, tza, tys, tsy,
+ ldz, stz2/* real register store */,
+ dez, inz, cpz, phz, plz,
+ neg, asr2/* arithmetic shift right */,
+ asw, row, dew, inw, phw,
+/* 4510 mnemonics */
+ map,
+
+/* Deco CPU16 mnemonics */
+ vbl, u13, u8F, uAB, u87, u0B, uA3, u4B,
+ u3F, uBB, u23
+};
+
+
+static const char *token[]=
+{
+ "adc", "and", "asl", "bcc", "bcs", "beq", "bit", "bmi",
+ "bne", "bpl", "m6502_brk", "bvc", "bvs", "clc", "cld", "cli",
+ "clv", "cmp", "cpx", "cpy", "dec", "dex", "dey", "eor",
+ "inc", "inx", "iny", "jmp", "jsr", "lda", "ldx", "ldy",
+ "lsr", "nop", "ora", "pha", "php", "pla", "plp", "rol",
+ "ror", "rti", "rts", "sbc", "sec", "sed", "sei", "sta",
+ "stx", "sty", "tax", "tay", "tsx", "txa", "txs", "tya",
+ "ill",
+/* 65c02 mnemonics */
+ "bbr", "bbs", "bra", "rmb", "smb", "stz", "trb", "tsb",
+/* 65sc02 mnemonics */
+ "bsr",
+/* 6510 mnemonics */
+ "anc", "asr", "ast", "arr", "asx", "axa", "dcp", "dea",
+ "dop", "ina", "isc", "lax", "phx", "phy", "plx", "ply",
+ "rla", "rra", "sax", "slo", "sre", "sah", "say", "ssh",
+ "sxh", "syh", "top", "oal", "kil",
+/* 65ce02 mnemonics */
+ "cle", "see", "rtn", "aug",
+ "tab", "tba", "taz", "tza", "tys", "tsy",
+ "ldz", "stz",
+ "dez", "inz", "cpz", "phz", "plz",
+ "neg", "asr",
+ "asw", "row", "dew", "inw", "phw",
+/* 4510 mnemonics */
+ "map",
+
+/* Deco CPU16 mnemonics */
+ "VBL", "u13", "u8F", "uAB", "u87", "u0B", "uA3", "u4B",
+ "u3F", "uBB", "u23"
+};
+
+struct op6502_info
+{
+ UINT8 opc;
+ UINT8 arg;
+};
+
+static const struct op6502_info op6502[256] = {
+ {m6502_brk,imm},{ora,idx},{kil,non},{slo,idx},/* 00 */
+ {dop,imm},{ora,zpg},{asl,zpg},{slo,zpg},
+ {php,imp},{ora,imm},{asl,acc},{anc,imm},
+ {top,iw2},{ora,aba},{asl,aba},{slo,aba},
+ {bpl,rel},{ora,idy},{nop,imp},{slo,idy},/* 10 */
+ {dop,imm},{ora,zpx},{asl,zpx},{slo,zpx},
+ {clc,imp},{ora,aby},{kil,non},{slo,aby},
+ {top,iw2},{ora,abx},{asl,abx},{slo,abx},
+ {jsr,adr},{and,idx},{kil,non},{rla,idx},/* 20 */
+ {bit,zpg},{and,zpg},{rol,zpg},{rla,zpg},
+ {plp,imp},{and,imm},{rol,acc},{anc,imm},
+ {bit,aba},{and,aba},{rol,aba},{rla,aba},
+ {bmi,rel},{and,idy},{kil,non},{rla,idy},/* 30 */
+ {dop,imm},{and,zpx},{rol,zpx},{rla,zpx},
+ {sec,imp},{and,aby},{nop,imp},{rla,aby},
+ {top,iw2},{and,abx},{rol,abx},{rla,abx},
+ {rti,imp},{eor,idx},{kil,non},{sre,idx},/* 40 */
+ {dop,imm},{eor,zpg},{lsr,zpg},{sre,zpg},
+ {pha,imp},{eor,imm},{lsr,acc},{asr,imm},
+ {jmp,adr},{eor,aba},{lsr,aba},{sre,aba},
+ {bvc,rel},{eor,idy},{kil,non},{sre,idy},/* 50 */
+ {dop,imm},{eor,zpx},{lsr,zpx},{sre,zpx},
+ {cli,imp},{eor,aby},{nop,imp},{sre,aby},
+ {top,iw2},{eor,abx},{lsr,abx},{sre,abx},
+ {rts,imp},{adc,idx},{kil,non},{rra,idx},/* 60 */
+ {dop,imm},{adc,zpg},{ror,zpg},{rra,zpg},
+ {pla,imp},{adc,imm},{ror,acc},{arr,imm},
+ {jmp,ind},{adc,aba},{ror,aba},{rra,aba},
+ {bvs,rel},{adc,idy},{kil,non},{rra,idy},/* 70 */
+ {dop,imm},{adc,zpx},{ror,zpx},{rra,zpx},
+ {sei,imp},{adc,aby},{nop,imp},{rra,aby},
+ {top,iw2},{adc,abx},{ror,abx},{rra,abx},
+ {dop,imm},{sta,idx},{dop,imm},{sax,idx},/* 80 */
+ {sty,zpg},{sta,zpg},{stx,zpg},{sax,zpg},
+ {dey,imp},{dop,imm},{txa,imp},{axa,imm},
+ {sty,aba},{sta,aba},{stx,aba},{sax,aba},
+ {bcc,rel},{sta,idy},{kil,non},{say,idy},/* 90 */
+ {sty,zpx},{sta,zpx},{stx,zpy},{sax,zpx},
+ {tya,imp},{sta,aby},{txs,imp},{ssh,aby},
+ {syh,abx},{sta,abx},{sxh,aby},{sah,aby},
+ {ldy,imm},{lda,idx},{ldx,imm},{lax,idx},/* a0 */
+ {ldy,zpg},{lda,zpg},{ldx,zpg},{lax,zpg},
+ {tay,imp},{lda,imm},{tax,imp},{oal,imm},
+ {ldy,aba},{lda,aba},{ldx,aba},{lax,aba},
+ {bcs,rel},{lda,idy},{kil,non},{lax,idy},/* b0 */
+ {ldy,zpx},{lda,zpx},{ldx,zpy},{lax,zpx},
+ {clv,imp},{lda,aby},{tsx,imp},{ast,aby},
+ {ldy,abx},{lda,abx},{ldx,aby},{lax,abx},
+ {cpy,imm},{cmp,idx},{dop,imm},{dcp,idx},/* c0 */
+ {cpy,zpg},{cmp,zpg},{dec,zpg},{dcp,zpg},
+ {iny,imp},{cmp,imm},{dex,imp},{asx,imm},
+ {cpy,aba},{cmp,aba},{dec,aba},{dcp,aba},
+ {bne,rel},{cmp,idy},{kil,non},{dcp,idy},/* d0 */
+ {dop,imm},{cmp,zpx},{dec,zpx},{dcp,zpx},
+ {cld,imp},{cmp,aby},{nop,imp},{dcp,aby},
+ {top,iw2},{cmp,abx},{dec,abx},{dcp,abx},
+ {cpx,imm},{sbc,idx},{dop,imm},{isc,idx},/* e0 */
+ {cpx,zpg},{sbc,zpg},{inc,zpg},{isc,zpg},
+ {inx,imp},{sbc,imm},{nop,imp},{sbc,imm},
+ {cpx,aba},{sbc,aba},{inc,aba},{isc,aba},
+ {beq,rel},{sbc,idy},{kil,non},{isc,idy},/* f0 */
+ {dop,imm},{sbc,zpx},{inc,zpx},{isc,zpx},
+ {sed,imp},{sbc,aby},{nop,imp},{isc,aby},
+ {top,iw2},{sbc,abx},{inc,abx},{isc,abx}
+};
+
+static const struct op6502_info op65c02[256] = {
+ {m6502_brk,imm},{ora,idx},{ill,non},{ill,non},/* 00 */
+ {tsb,zpg},{ora,zpg},{asl,zpg},{rmb,zpg},
+ {php,imp},{ora,imm},{asl,acc},{ill,non},
+ {tsb,aba},{ora,aba},{asl,aba},{bbr,zpb},
+ {bpl,rel},{ora,idy},{ora,zpi},{ill,non},/* 10 */
+ {trb,zpg},{ora,zpx},{asl,zpx},{rmb,zpg},
+ {clc,imp},{ora,aby},{ina,imp},{ill,non},
+ {trb,aba},{ora,abx},{asl,abx},{bbr,zpb},
+ {jsr,adr},{and,idx},{ill,non},{ill,non},/* 20 */
+ {bit,zpg},{and,zpg},{rol,zpg},{rmb,zpg},
+ {plp,imp},{and,imm},{rol,acc},{ill,non},
+ {bit,aba},{and,aba},{rol,aba},{bbr,zpb},
+ {bmi,rel},{and,idy},{and,zpi},{ill,non},/* 30 */
+ {bit,zpx},{and,zpx},{rol,zpx},{rmb,zpg},
+ {sec,imp},{and,aby},{dea,imp},{ill,non},
+ {bit,abx},{and,abx},{rol,abx},{bbr,zpb},
+ {rti,imp},{eor,idx},{ill,non},{ill,non},/* 40 */
+ {ill,non},{eor,zpg},{lsr,zpg},{rmb,zpg},
+ {pha,imp},{eor,imm},{lsr,acc},{ill,non},
+ {jmp,adr},{eor,aba},{lsr,aba},{bbr,zpb},
+ {bvc,rel},{eor,idy},{eor,zpi},{ill,non},/* 50 */
+ {ill,non},{eor,zpx},{lsr,zpx},{rmb,zpg},
+ {cli,imp},{eor,aby},{phy,imp},{ill,non},
+ {ill,non},{eor,abx},{lsr,abx},{bbr,zpb},
+ {rts,imp},{adc,idx},{ill,non},{ill,non},/* 60 */
+ {stz,zpg},{adc,zpg},{ror,zpg},{rmb,zpg},
+ {pla,imp},{adc,imm},{ror,acc},{ill,non},
+ {jmp,ind},{adc,aba},{ror,aba},{bbr,zpb},
+ {bvs,rel},{adc,idy},{adc,zpi},{ill,non},/* 70 */
+ {stz,zpx},{adc,zpx},{ror,zpx},{rmb,zpg},
+ {sei,imp},{adc,aby},{ply,imp},{ill,non},
+ {jmp,iax},{adc,abx},{ror,abx},{bbr,zpb},
+ {bra,rel},{sta,idx},{ill,non},{ill,non},/* 80 */
+ {sty,zpg},{sta,zpg},{stx,zpg},{smb,zpg},
+ {dey,imp},{bit,imm},{txa,imp},{ill,non},
+ {sty,aba},{sta,aba},{stx,aba},{bbs,zpb},
+ {bcc,rel},{sta,idy},{sta,zpi},{ill,non},/* 90 */
+ {sty,zpx},{sta,zpx},{stx,zpy},{smb,zpg},
+ {tya,imp},{sta,aby},{txs,imp},{ill,non},
+ {stz,aba},{sta,abx},{stz,abx},{bbs,zpb},
+ {ldy,imm},{lda,idx},{ldx,imm},{ill,non},/* a0 */
+ {ldy,zpg},{lda,zpg},{ldx,zpg},{smb,zpg},
+ {tay,imp},{lda,imm},{tax,imp},{ill,non},
+ {ldy,aba},{lda,aba},{ldx,aba},{bbs,zpb},
+ {bcs,rel},{lda,idy},{lda,zpi},{ill,non},/* b0 */
+ {ldy,zpx},{lda,zpx},{ldx,zpy},{smb,zpg},
+ {clv,imp},{lda,aby},{tsx,imp},{ill,non},
+ {ldy,abx},{lda,abx},{ldx,aby},{bbs,zpb},
+ {cpy,imm},{cmp,idx},{ill,non},{ill,non},/* c0 */
+ {cpy,zpg},{cmp,zpg},{dec,zpg},{smb,zpg},
+ {iny,imp},{cmp,imm},{dex,imp},{ill,non},
+ {cpy,aba},{cmp,aba},{dec,aba},{bbs,zpb},
+ {bne,rel},{cmp,idy},{cmp,zpi},{ill,non},/* d0 */
+ {ill,non},{cmp,zpx},{dec,zpx},{smb,zpg},
+ {cld,imp},{cmp,aby},{phx,imp},{ill,non},
+ {ill,non},{cmp,abx},{dec,abx},{bbs,zpb},
+ {cpx,imm},{sbc,idx},{ill,non},{ill,non},/* e0 */
+ {cpx,zpg},{sbc,zpg},{inc,zpg},{smb,zpg},
+ {inx,imp},{sbc,imm},{nop,imp},{ill,non},
+ {cpx,aba},{sbc,aba},{inc,aba},{bbs,zpb},
+ {beq,rel},{sbc,idy},{sbc,zpi},{ill,non},/* f0 */
+ {ill,non},{sbc,zpx},{inc,zpx},{smb,zpg},
+ {sed,imp},{sbc,aby},{plx,imp},{ill,non},
+ {ill,non},{sbc,abx},{inc,abx},{bbs,zpb}
+};
+
+/* only bsr additional to 65c02 yet */
+static const struct op6502_info op65sc02[256] = {
+ {m6502_brk,imm},{ora,idx},{ill,non},{ill,non},/* 00 */
+ {tsb,zpg},{ora,zpg},{asl,zpg},{rmb,zpg},
+ {php,imp},{ora,imm},{asl,acc},{ill,non},
+ {tsb,aba},{ora,aba},{asl,aba},{bbr,zpb},
+ {bpl,rel},{ora,idy},{ora,zpi},{ill,non},/* 10 */
+ {trb,zpg},{ora,zpx},{asl,zpx},{rmb,zpg},
+ {clc,imp},{ora,aby},{ina,imp},{ill,non},
+ {trb,aba},{ora,abx},{asl,abx},{bbr,zpb},
+ {jsr,adr},{and,idx},{ill,non},{ill,non},/* 20 */
+ {bit,zpg},{and,zpg},{rol,zpg},{rmb,zpg},
+ {plp,imp},{and,imm},{rol,acc},{ill,non},
+ {bit,aba},{and,aba},{rol,aba},{bbr,zpb},
+ {bmi,rel},{and,idy},{and,zpi},{ill,non},/* 30 */
+ {bit,zpx},{and,zpx},{rol,zpx},{rmb,zpg},
+ {sec,imp},{and,aby},{dea,imp},{ill,non},
+ {bit,abx},{and,abx},{rol,abx},{bbr,zpb},
+ {rti,imp},{eor,idx},{ill,non},{ill,non},/* 40 */
+ {ill,non},{eor,zpg},{lsr,zpg},{rmb,zpg},
+ {pha,imp},{eor,imm},{lsr,acc},{ill,non},
+ {jmp,adr},{eor,aba},{lsr,aba},{bbr,zpb},
+ {bvc,rel},{eor,idy},{eor,zpi},{ill,non},/* 50 */
+ {ill,non},{eor,zpx},{lsr,zpx},{rmb,zpg},
+ {cli,imp},{eor,aby},{phy,imp},{ill,non},
+ {ill,non},{eor,abx},{lsr,abx},{bbr,zpb},
+ {rts,imp},{adc,idx},{ill,non},{bsr,rw2},/* 60 */
+ {stz,zpg},{adc,zpg},{ror,zpg},{rmb,zpg},
+ {pla,imp},{adc,imm},{ror,acc},{ill,non},
+ {jmp,ind},{adc,aba},{ror,aba},{bbr,zpb},
+ {bvs,rel},{adc,idy},{adc,zpi},{ill,non},/* 70 */
+ {stz,zpx},{adc,zpx},{ror,zpx},{rmb,zpg},
+ {sei,imp},{adc,aby},{ply,imp},{ill,non},
+ {jmp,iax},{adc,abx},{ror,abx},{bbr,zpb},
+ {bra,rel},{sta,idx},{ill,non},{ill,non},/* 80 */
+ {sty,zpg},{sta,zpg},{stx,zpg},{smb,zpg},
+ {dey,imp},{bit,imm},{txa,imp},{ill,non},
+ {sty,aba},{sta,aba},{stx,aba},{bbs,zpb},
+ {bcc,rel},{sta,idy},{sta,zpi},{ill,non},/* 90 */
+ {sty,zpx},{sta,zpx},{stx,zpy},{smb,zpg},
+ {tya,imp},{sta,aby},{txs,imp},{ill,non},
+ {stz,aba},{sta,abx},{stz,abx},{bbs,zpb},
+ {ldy,imm},{lda,idx},{ldx,imm},{ill,non},/* a0 */
+ {ldy,zpg},{lda,zpg},{ldx,zpg},{smb,zpg},
+ {tay,imp},{lda,imm},{tax,imp},{ill,non},
+ {ldy,aba},{lda,aba},{ldx,aba},{bbs,zpb},
+ {bcs,rel},{lda,idy},{lda,zpi},{ill,non},/* b0 */
+ {ldy,zpx},{lda,zpx},{ldx,zpy},{smb,zpg},
+ {clv,imp},{lda,aby},{tsx,imp},{ill,non},
+ {ldy,abx},{lda,abx},{ldx,aby},{bbs,zpb},
+ {cpy,imm},{cmp,idx},{ill,non},{ill,non},/* c0 */
+ {cpy,zpg},{cmp,zpg},{dec,zpg},{smb,zpg},
+ {iny,imp},{cmp,imm},{dex,imp},{ill,non},
+ {cpy,aba},{cmp,aba},{dec,aba},{bbs,zpb},
+ {bne,rel},{cmp,idy},{cmp,zpi},{ill,non},/* d0 */
+ {ill,non},{cmp,zpx},{dec,zpx},{smb,zpg},
+ {cld,imp},{cmp,aby},{phx,imp},{ill,non},
+ {ill,non},{cmp,abx},{dec,abx},{bbs,zpb},
+ {cpx,imm},{sbc,idx},{ill,non},{ill,non},/* e0 */
+ {cpx,zpg},{sbc,zpg},{inc,zpg},{smb,zpg},
+ {inx,imp},{sbc,imm},{nop,imp},{ill,non},
+ {cpx,aba},{sbc,aba},{inc,aba},{bbs,zpb},
+ {beq,rel},{sbc,idy},{sbc,zpi},{ill,non},/* f0 */
+ {ill,non},{sbc,zpx},{inc,zpx},{smb,zpg},
+ {sed,imp},{sbc,aby},{plx,imp},{ill,non},
+ {ill,non},{sbc,abx},{inc,abx},{bbs,zpb}
+};
+
+#if (HAS_M65CE02)
+static const struct op6502_info op65ce02[256] = {
+ {m6502_brk,imm},{ora,idx},{cle,imp},{see,imp},/* 00 */
+ {tsb,zpg},{ora,zpg},{asl,zpg},{rmb,zpg},
+ {php,imp},{ora,imm},{asl,acc},{tsy,imp},
+ {tsb,aba},{ora,aba},{asl,aba},{bbr,zpb},
+ {bpl,rel},{ora,idy},{ora,idz},{bpl,rw2},/* 10 */
+ {trb,zpg},{ora,zpx},{asl,zpx},{rmb,zpg},
+ {clc,imp},{ora,aby},{ina,imp},{inz,imp},
+ {trb,aba},{ora,abx},{asl,abx},{bbr,zpb},
+ {jsr,adr},{and,idx},{jsr,ind},{jsr,iax},/* 20 */
+ {bit,zpg},{and,zpg},{rol,zpg},{rmb,zpg},
+ {plp,imp},{and,imm},{rol,acc},{tys,imp},
+ {bit,aba},{and,aba},{rol,aba},{bbr,zpb},
+ {bmi,rel},{and,idz},{and,zpi},{bmi,rw2},/* 30 */
+ {bit,zpx},{and,zpx},{rol,zpx},{rmb,zpg},
+ {sec,imp},{and,aby},{dea,imp},{dez,imp},
+ {bit,abx},{and,abx},{rol,abx},{bbr,zpb},
+ {rti,imp},{eor,idx},{neg,imp},{asr2,imp},/* 40 */
+ {asr2,zpg},{eor,zpg},{lsr,zpg},{rmb,zpg},
+ {pha,imp},{eor,imm},{lsr,acc},{taz,imp},
+ {jmp,adr},{eor,aba},{lsr,aba},{bbr,zpb},
+ {bvc,rel},{eor,idy},{eor,idz},{bvc,rw2},/* 50 */
+ {asr2,zpx},{eor,zpx},{lsr,zpx},{rmb,zpg},
+ {cli,imp},{eor,aby},{phy,imp},{tab,imp},
+ {aug,iw3},{eor,abx},{lsr,abx},{bbr,zpb},
+ {rts,imp},{adc,idx},{rtn,imm},{bsr,rw2},/* 60 */
+ {stz2,zpg},{adc,zpg},{ror,zpg},{rmb,zpg},
+ {pla,imp},{adc,imm},{ror,acc},{tza,imp},
+ {jmp,ind},{adc,aba},{ror,aba},{bbr,zpb},
+ {bvs,rel},{adc,idy},{adc,zpi},{bvs,rw2},/* 70 */
+ {stz2,zpx},{adc,zpx},{ror,zpx},{rmb,zpg},
+ {sei,imp},{adc,aby},{ply,imp},{tba,imp},
+ {jmp,iax},{adc,abx},{ror,abx},{bbr,zpb},
+ {bra,rel},{sta,idx},{sta,isy},{bra,rw2},/* 80 */
+ {sty,zpg},{sta,zpg},{stx,zpg},{smb,zpg},
+ {dey,imp},{bit,imm},{txa,imp},{sty,abx},
+ {sty,aba},{sta,aba},{stx,aba},{bbs,zpb},
+ {bcc,rel},{sta,idy},{sta,inz},{bcc,rw2},/* 90 */
+ {sty,zpx},{sta,zpx},{stx,zpy},{smb,zpg},
+ {tya,imp},{sta,aby},{txs,imp},{stx,aby},
+ {stz2,aba},{sta,abx},{stz2,abx},{bbs,zpb},
+ {ldy,imm},{lda,idx},{ldx,imm},{ldz,imm},/* a0 */
+ {ldy,zpg},{lda,zpg},{ldx,zpg},{smb,zpg},
+ {tay,imp},{lda,imm},{tax,imp},{ldz,aba},
+ {ldy,aba},{lda,aba},{ldx,aba},{bbs,zpb},
+ {bcs,rel},{lda,idy},{lda,inz},{bcs,rw2},/* b0 */
+ {ldy,zpx},{lda,zpx},{ldx,zpy},{smb,zpg},
+ {clv,imp},{lda,aby},{tsx,imp},{ldz,abx},
+ {ldy,abx},{lda,abx},{ldx,aby},{bbs,zpb},
+ {cpy,imm},{cmp,idx},{cpz,imm},{dew,zpg},/* c0 */
+ {cpy,zpg},{cmp,zpg},{dec,zpg},{smb,zpg},
+ {iny,imp},{cmp,imm},{dex,imp},{asw,aba},
+ {cpy,aba},{cmp,aba},{dec,aba},{bbs,zpb},
+ {bne,rel},{cmp,idy},{cmp,idz},{bne,rw2},/* d0 */
+ {cpz,zpg},{cmp,zpx},{dec,zpx},{smb,zpg},
+ {cld,imp},{cmp,aby},{phx,imp},{phz,imp},
+ {cpz,aba},{cmp,abx},{dec,abx},{bbs,zpb},
+ {cpx,imm},{sbc,idx},{lda,isy},{inw,zpg},/* e0 */
+ {cpx,zpg},{sbc,zpg},{inc,zpg},{smb,zpg},
+ {inx,imp},{sbc,imm},{nop,imp},{row,aba},
+ {cpx,aba},{sbc,aba},{inc,aba},{bbs,zpb},
+ {beq,rel},{sbc,idy},{sbc,idz},{beq,rw2},/* f0 */
+ {phw,iw2},{sbc,zpx},{inc,zpx},{smb,zpg},
+ {sed,imp},{sbc,aby},{plx,imp},{plz,imp},
+ {phw,aba},{sbc,abx},{inc,abx},{bbs,zpb}
+};
+#endif
+
+#if (HAS_M4510)
+// only map instead of aug and 20 bit memory management
+static const struct op6502_info op4510[256] = {
+ {m6502_brk,imm},{ora,idx},{cle,imp},{see,imp},/* 00 */
+ {tsb,zpg},{ora,zpg},{asl,zpg},{rmb,zpg},
+ {php,imp},{ora,imm},{asl,acc},{tsy,imp},
+ {tsb,aba},{ora,aba},{asl,aba},{bbr,zpb},
+ {bpl,rel},{ora,idy},{ora,idz},{bpl,rw2},/* 10 */
+ {trb,zpg},{ora,zpx},{asl,zpx},{rmb,zpg},
+ {clc,imp},{ora,aby},{ina,imp},{inz,imp},
+ {trb,aba},{ora,abx},{asl,abx},{bbr,zpb},
+ {jsr,adr},{and,idx},{jsr,ind},{jsr,iax},/* 20 */
+ {bit,zpg},{and,zpg},{rol,zpg},{rmb,zpg},
+ {plp,imp},{and,imm},{rol,acc},{tys,imp},
+ {bit,aba},{and,aba},{rol,aba},{bbr,zpb},
+ {bmi,rel},{and,idz},{and,zpi},{bmi,rw2},/* 30 */
+ {bit,zpx},{and,zpx},{rol,zpx},{rmb,zpg},
+ {sec,imp},{and,aby},{dea,imp},{dez,imp},
+ {bit,abx},{and,abx},{rol,abx},{bbr,zpb},
+ {rti,imp},{eor,idx},{neg,imp},{asr2,imp},/* 40 */
+ {asr2,zpg},{eor,zpg},{lsr,zpg},{rmb,zpg},
+ {pha,imp},{eor,imm},{lsr,acc},{taz,imp},
+ {jmp,adr},{eor,aba},{lsr,aba},{bbr,zpb},
+ {bvc,rel},{eor,idy},{eor,idz},{bvc,rw2},/* 50 */
+ {asr2,zpx},{eor,zpx},{lsr,zpx},{rmb,zpg},
+ {cli,imp},{eor,aby},{phy,imp},{tab,imp},
+ {map,imp},{eor,abx},{lsr,abx},{bbr,zpb},
+ {rts,imp},{adc,idx},{rtn,imm},{bsr,rw2},/* 60 */
+ {stz2,zpg},{adc,zpg},{ror,zpg},{rmb,zpg},
+ {pla,imp},{adc,imm},{ror,acc},{tza,imp},
+ {jmp,ind},{adc,aba},{ror,aba},{bbr,zpb},
+ {bvs,rel},{adc,idy},{adc,zpi},{bvs,rw2},/* 70 */
+ {stz2,zpx},{adc,zpx},{ror,zpx},{rmb,zpg},
+ {sei,imp},{adc,aby},{ply,imp},{tba,imp},
+ {jmp,iax},{adc,abx},{ror,abx},{bbr,zpb},
+ {bra,rel},{sta,idx},{sta,isy},{bra,rw2},/* 80 */
+ {sty,zpg},{sta,zpg},{stx,zpg},{smb,zpg},
+ {dey,imp},{bit,imm},{txa,imp},{sty,abx},
+ {sty,aba},{sta,aba},{stx,aba},{bbs,zpb},
+ {bcc,rel},{sta,idy},{sta,inz},{bcc,rw2},/* 90 */
+ {sty,zpx},{sta,zpx},{stx,zpy},{smb,zpg},
+ {tya,imp},{sta,aby},{txs,imp},{stx,aby},
+ {stz2,aba},{sta,abx},{stz2,abx},{bbs,zpb},
+ {ldy,imm},{lda,idx},{ldx,imm},{ldz,imm},/* a0 */
+ {ldy,zpg},{lda,zpg},{ldx,zpg},{smb,zpg},
+ {tay,imp},{lda,imm},{tax,imp},{ldz,aba},
+ {ldy,aba},{lda,aba},{ldx,aba},{bbs,zpb},
+ {bcs,rel},{lda,idy},{lda,inz},{bcs,rw2},/* b0 */
+ {ldy,zpx},{lda,zpx},{ldx,zpy},{smb,zpg},
+ {clv,imp},{lda,aby},{tsx,imp},{ldz,abx},
+ {ldy,abx},{lda,abx},{ldx,aby},{bbs,zpb},
+ {cpy,imm},{cmp,idx},{cpz,imm},{dew,zpg},/* c0 */
+ {cpy,zpg},{cmp,zpg},{dec,zpg},{smb,zpg},
+ {iny,imp},{cmp,imm},{dex,imp},{asw,aba},
+ {cpy,aba},{cmp,aba},{dec,aba},{bbs,zpb},
+ {bne,rel},{cmp,idy},{cmp,idz},{bne,rw2},/* d0 */
+ {cpz,zpg},{cmp,zpx},{dec,zpx},{smb,zpg},
+ {cld,imp},{cmp,aby},{phx,imp},{phz,imp},
+ {cpz,aba},{cmp,abx},{dec,abx},{bbs,zpb},
+ {cpx,imm},{sbc,idx},{lda,isy},{inw,zpg},/* e0 */
+ {cpx,zpg},{sbc,zpg},{inc,zpg},{smb,zpg},
+ {inx,imp},{sbc,imm},{nop,imp},{row,aba},
+ {cpx,aba},{sbc,aba},{inc,aba},{bbs,zpb},
+ {beq,rel},{sbc,idy},{sbc,idz},{beq,rw2},/* f0 */
+ {phw,iw2},{sbc,zpx},{inc,zpx},{smb,zpg},
+ {sed,imp},{sbc,aby},{plx,imp},{plz,imp},
+ {phw,aba},{sbc,abx},{inc,abx},{bbs,zpb}
+};
+#endif
+
+#if (HAS_DECO16)
+static const struct op6502_info opdeco16[256] =
+{
+ {m6502_brk,imp},{ora,idx},{ill,non},{ill,non},/* 00 */
+ {ill,non},{ora,zpg},{asl,zpg},{ill,non},
+ {php,imp},{ora,imm},{asl,acc},{u0B,zpg},
+ {ill,non},{ora,aba},{asl,aba},{ill,non},
+ {bpl,rel},{ora,idy},{ill,non},{u13,zpg},/* 10 */
+ {ill,non},{ora,zpx},{asl,zpx},{ill,non},
+ {clc,imp},{ora,aby},{ill,non},{ill,non},
+ {ill,non},{ora,abx},{asl,abx},{ill,non},
+ {jsr,adr},{and,idx},{ill,non},{u23,zpg},/* 20 */
+ {bit,zpg},{and,zpg},{rol,zpg},{ill,non},
+ {plp,imp},{and,imm},{rol,acc},{ill,non},
+ {bit,aba},{and,aba},{rol,aba},{ill,non},
+ {bmi,rel},{and,idy},{ill,non},{ill,non},/* 30 */
+ {ill,non},{and,zpx},{rol,zpx},{ill,non},
+ {sec,imp},{and,aby},{ill,non},{ill,non},
+ {ill,non},{and,abx},{rol,abx},{u3F,zpg},
+ {rti,imp},{eor,idx},{ill,non},{ill,non},/* 40 */
+ {ill,non},{eor,zpg},{lsr,zpg},{ill,non},
+ {pha,imp},{eor,imm},{lsr,acc},{u4B,zpg},
+ {jmp,adr},{eor,aba},{lsr,aba},{ill,non},
+ {bvc,rel},{eor,idy},{ill,non},{ill,non},/* 50 */
+ {ill,non},{eor,zpx},{lsr,zpx},{ill,non},
+ {cli,imp},{eor,aby},{ill,non},{ill,non},
+ {ill,non},{eor,abx},{lsr,abx},{ill,non},
+ {rts,imp},{adc,idx},{ill,non},{ill,non},/* 60 */
+ {ill,non},{adc,zpg},{ror,zpg},{vbl,zpg}, // MISH
+ {pla,imp},{adc,imm},{ror,acc},{ill,non},
+ {jmp,ind},{adc,aba},{ror,aba},{ill,non},
+ {bvs,rel},{adc,idy},{ill,non},{ill,non},/* 70 */
+ {ill,non},{adc,zpx},{ror,zpx},{ill,non},
+ {sei,imp},{adc,aby},{ill,non},{ill,non},
+ {ill,non},{adc,abx},{ror,abx},{ill,non},
+ {ill,non},{sta,idx},{ill,non},{ill,non},/* 80 */
+ {sty,zpg},{sta,zpg},{stx,zpg},{u87,zpg},
+ {dey,imp},{ill,non},{txa,imp},{ill,non},
+ {sty,aba},{sta,aba},{stx,aba},{u8F,zpg},
+ {bcc,rel},{sta,idy},{ill,non},{ill,non},/* 90 */
+ {sty,zpx},{sta,zpx},{stx,zpy},{ill,non},
+ {tya,imp},{sta,aby},{txs,imp},{ill,non},
+ {ill,non},{sta,abx},{ill,non},{ill,non},
+ {ldy,imm},{lda,idx},{ldx,imm},{uA3,zpg},/* a0 */
+ {ldy,zpg},{lda,zpg},{ldx,zpg},{ill,non},
+ {tay,imp},{lda,imm},{tax,imp},{uAB,zpg},
+ {ldy,aba},{lda,aba},{ldx,aba},{ill,non},
+ {bcs,rel},{lda,idy},{ill,non},{ill,non},/* b0 */
+ {ldy,zpx},{lda,zpx},{ldx,zpy},{ill,non},
+ {clv,imp},{lda,aby},{tsx,imp},{uBB,zpg},
+ {ldy,abx},{lda,abx},{ldx,aby},{ill,non},
+ {cpy,imm},{cmp,idx},{ill,non},{ill,non},/* c0 */
+ {cpy,zpg},{cmp,zpg},{dec,zpg},{ill,non},
+ {iny,imp},{cmp,imm},{dex,imp},{ill,non},
+ {cpy,aba},{cmp,aba},{dec,aba},{ill,non},
+ {bne,rel},{cmp,idy},{ill,non},{ill,non},/* d0 */
+ {ill,non},{cmp,zpx},{dec,zpx},{ill,non},
+ {cld,imp},{cmp,aby},{ill,non},{ill,non},
+ {ill,non},{cmp,abx},{dec,abx},{ill,non},
+ {cpx,imm},{sbc,idx},{ill,non},{ill,non},/* e0 */
+ {cpx,zpg},{sbc,zpg},{inc,zpg},{ill,non},
+ {inx,imp},{sbc,imm},{nop,imp},{ill,non},
+ {cpx,aba},{sbc,aba},{inc,aba},{ill,non},
+ {beq,rel},{sbc,idy},{ill,non},{ill,non},/* f0 */
+ {ill,non},{sbc,zpx},{inc,zpx},{ill,non},
+ {sed,imp},{sbc,aby},{ill,non},{ill,non},
+ {ill,non},{sbc,abx},{inc,abx},{ill,non}
+};
+#endif
+
+/*****************************************************************************
+ * Disassemble a single opcode starting at pc
+ *****************************************************************************/
+static unsigned internal_m6502_dasm(const struct op6502_info *opinfo, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ char *dst = buffer;
+ INT8 offset;
+ INT16 offset16;
+ unsigned PC = pc;
+ UINT16 addr;
+ UINT8 op, opc, arg, value;
+ UINT32 flags;
+ int pos = 0;
+
+ op = oprom[pos++];
+ pc++;
+
+ opc = opinfo[op].opc;
+ arg = opinfo[op].arg;
+
+ /* determine dasmflags */
+ switch(opc)
+ {
+ case jsr:
+ case bsr:
+ flags = DASMFLAG_SUPPORTED | DASMFLAG_STEP_OVER;
+ break;
+
+ case rts:
+ case rti:
+ case rtn:
+ flags = DASMFLAG_SUPPORTED | DASMFLAG_STEP_OUT;
+ break;
+
+ default:
+ flags = DASMFLAG_SUPPORTED;
+ break;
+ }
+
+ dst += sprintf(dst, "%-5s", token[opc]);
+ if( opc == bbr || opc == bbs || opc == rmb || opc == smb )
+ dst += sprintf(dst, "%d,", (op >> 3) & 7);
+
+ switch(arg)
+ {
+ case imp:
+ break;
+
+ case acc:
+ dst += sprintf(dst,"a");
+ break;
+
+ case rel:
+ offset = (INT8) opram[pos++];
+ pc++;
+ dst += sprintf(dst, "$%04X", (pc + offset) & 0xFFFF);
+ break;
+
+ case rw2:
+ offset16 = (opram[pos] | (opram[pos+1] << 8)) -1;
+ pos += 2;
+ pc += 2;
+ dst += sprintf(dst, "$%04X", (pc + offset16) & 0xFFFF);
+ break;
+
+ case imm:
+ value = opram[pos++];
+ pc++;
+ dst += sprintf(dst,"#$%02X", value);
+ break;
+
+ case zpg:
+ addr = opram[pos++];
+ pc++;
+ dst += sprintf(dst,"$%02X", addr);
+ break;
+
+ case zpx:
+ addr = opram[pos++];
+ pc++;
+ dst += sprintf(dst,"$%02X,x", addr);
+ break;
+
+ case zpy:
+ addr = opram[pos++];
+ pc++;
+ dst += sprintf(dst,"$%02X,y", addr);
+ break;
+
+ case idx:
+ addr = opram[pos++];
+ pc++;
+ dst += sprintf(dst,"($%02X,x)", addr);
+ break;
+
+ case idy:
+ addr = opram[pos++];
+ pc++;
+ dst += sprintf(dst,"($%02X),y", addr);
+ break;
+
+ case zpi:
+ addr = opram[pos++];
+ pc++;
+ dst += sprintf(dst,"($%02X)", addr);
+ break;
+
+ case zpb:
+ addr = opram[pos++];
+ pc++;
+ dst += sprintf(dst,"$%02X", addr);
+ offset = (INT8) opram[pos++];
+ pc++;
+ dst += sprintf(dst,",$%04X", pc + offset);
+ break;
+
+ case adr:
+ addr = (opram[pos] | (opram[pos+1] << 8));
+ pos += 2;
+ pc += 2;
+ dst += sprintf(dst, "$%04X", addr);
+ break;
+
+ case aba:
+ addr = (opram[pos] | (opram[pos+1] << 8));
+ pos += 2;
+ pc += 2;
+ dst += sprintf(dst, "$%04X", addr);
+ break;
+
+ case abx:
+ addr = (opram[pos] | (opram[pos+1] << 8));
+ pos += 2;
+ pc += 2;
+ dst += sprintf(dst,"$%04X,x", addr);
+ break;
+
+ case aby:
+ addr = (opram[pos] | (opram[pos+1] << 8));
+ pos += 2;
+ pc += 2;
+ dst += sprintf(dst,"$%04X,y", addr);
+ break;
+
+ case ind:
+ addr = (opram[pos] | (opram[pos+1] << 8));
+ pos += 2;
+ pc += 2;
+ dst += sprintf(dst,"($%04X)", addr);
+ break;
+
+ case iax:
+ addr = (opram[pos] | (opram[pos+1] << 8));
+ pos += 2;
+ pc += 2;
+ dst += sprintf(dst,"($%04X),X", addr);
+ break;
+
+ case iw2:
+ addr = (opram[pos] | (opram[pos+1] << 8));
+ pos += 2;
+ pc += 2;
+ dst += sprintf(dst,"#%04X", addr);
+ break;
+
+ case iw3:
+ addr = (opram[pos] | (opram[pos+1] << 8) | (opram[pos+2] << 16));
+ pos += 3;
+ pc += 3;
+ dst += sprintf(dst,"#%06x", addr);
+ break;
+
+ case idz:
+ addr = (INT8) opram[pos++];
+ pc++;
+ dst += sprintf(dst,"($%02X),z", addr);
+ break;
+
+ case isy:
+ op = opram[pos++];
+ pc++;
+ addr = op;
+ dst += sprintf(dst,"(s,$%02X),y", addr);
+ break;
+
+ default:
+ dst += sprintf(dst,"$%02X", op);
+ break;
+ }
+ return (pc - PC) | flags;
+}
+
+unsigned m6502_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return internal_m6502_dasm(op6502, buffer, pc, oprom, opram);
+}
+
+#if (HAS_M65SC02)
+unsigned m65sc02_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return internal_m6502_dasm(op65sc02, buffer, pc, oprom, opram);
+}
+#endif
+
+#if (HAS_M65C02||HAS_M65SC02||HAS_DECO16)
+unsigned m65c02_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return internal_m6502_dasm(op65c02, buffer, pc, oprom, opram);
+}
+#endif
+
+#if (HAS_M65CE02)
+unsigned m65ce02_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return internal_m6502_dasm(op65ce02, buffer, pc, oprom, opram);
+}
+#endif
+
+#if (HAS_M6510)
+unsigned m6510_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return internal_m6502_dasm(op6502, buffer, pc, oprom, opram);
+}
+#endif
+
+#if (HAS_DECO16)
+unsigned deco16_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return internal_m6502_dasm(opdeco16, buffer, pc, oprom, opram);
+}
+#endif
+
+#if (HAS_M4510)
+unsigned m4510_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return internal_m6502_dasm(op4510, buffer, pc, oprom, opram);
+}
+#endif
diff --git a/src/emu/cpu/m6502/ill02.h b/src/emu/cpu/m6502/ill02.h
new file mode 100644
index 00000000000..4ad4160bc49
--- /dev/null
+++ b/src/emu/cpu/m6502/ill02.h
@@ -0,0 +1,278 @@
+/*****************************************************************************
+ *
+ * ill02.h
+ * Addressing mode and opcode macros for the NMOS 6502 illegal opcodes
+ *
+ * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * 65sc02 core Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+/* test with the excellent C64 Emulator test suite
+ ? at www.funet.fi/pub/cbm/documents/chipdata/tsuit215.zip
+ good reference in the vice emulator (source) distribution doc/64doc.txt
+
+ $ab=OAL like in 6502-NMOS.extra.opcodes, vice so in vice (lxa)
+*/
+
+/***************************************************************
+ ***************************************************************
+ * Macros to emulate the 6510 opcodes
+ ***************************************************************
+ ***************************************************************/
+
+/* 6510 ********************************************************
+ * ANC logical and, set carry from bit of A
+ ***************************************************************/
+#define ANC \
+ P &= ~F_C; \
+ A = (UINT8)(A & tmp); \
+ if (A & 0x80) \
+ P |= F_C; \
+ SET_NZ(A)
+
+/* 6510 ********************************************************
+ * ASR logical and, logical shift right
+ ***************************************************************/
+#define ASR \
+ tmp &= A; \
+ LSR
+
+/* 6510 ********************************************************
+ * AST and stack; transfer to accumulator and index X
+ * logical and stack (LSB) with data, transfer result to S
+ * transfer result to accumulator and index X also
+ ***************************************************************/
+#define AST \
+ S &= tmp; \
+ A = X = S; \
+ SET_NZ(A)
+
+/* 6510 ********************************************************
+ * ARR logical and, rotate right
+ ***************************************************************/
+#define ARR \
+ if( P & F_D ) \
+ { \
+ int lo, hi, t; \
+ tmp &= A; \
+ t = tmp; \
+ hi = tmp &0xf0; \
+ lo = tmp &0x0f; \
+ if( P & F_C ) \
+ { \
+ tmp = (tmp >> 1) | 0x80; \
+ P |= F_N; \
+ } \
+ else \
+ { \
+ tmp >>= 1; \
+ P &= ~F_N; \
+ } \
+ if( tmp ) \
+ P &= ~F_Z; \
+ else \
+ P |= F_Z; \
+ if( (t^tmp) & 0x40 ) \
+ P|=F_V; \
+ else \
+ P &= ~F_V; \
+ if( lo + (lo & 0x01) > 0x05 ) \
+ tmp = (tmp & 0xf0) | ((tmp+6) & 0xf); \
+ if( hi + (hi & 0x10) > 0x50 ) \
+ { \
+ P |= F_C; \
+ tmp = (tmp+0x60) & 0xff; \
+ } \
+ else \
+ P &= ~F_C; \
+ } \
+ else \
+ { \
+ tmp &= A; \
+ ROR; \
+ P &=~(F_V|F_C); \
+ if( tmp & 0x40 ) \
+ P|=F_C; \
+ if( (tmp & 0x60) == 0x20 || (tmp & 0x60) == 0x40 ) \
+ P|=F_V; \
+ }
+
+/* 6510 ********************************************************
+ * ASX logical and X w/ A, subtract data from X
+ ***************************************************************/
+#define ASX \
+ P &= ~F_C; \
+ X &= A; \
+ if (X >= tmp) \
+ P |= F_C; \
+ X = (UINT8)(X - tmp); \
+ SET_NZ(X)
+
+/* 6510 ********************************************************
+ * AXA transfer index X to accumulator, logical and
+ * depends on the data of the dma device (videochip) fetched
+ * between opcode read and operand read
+ ***************************************************************/
+#define AXA \
+ A = (UINT8)( (A|0xee)& X & tmp); \
+ SET_NZ(A)
+
+/* 6510 ********************************************************
+ * DCP decrement data and compare
+ ***************************************************************/
+#define DCP \
+ tmp = (UINT8)(tmp-1); \
+ P &= ~F_C; \
+ if (A >= tmp) \
+ P |= F_C; \
+ SET_NZ((UINT8)(A - tmp))
+
+/* 6502 ********************************************************
+ * DOP double no operation
+ ***************************************************************/
+#define DOP \
+ RDOPARG()
+
+/* 6510 ********************************************************
+ * ISB increment and subtract with carry
+ ***************************************************************/
+#define ISB \
+ tmp = (UINT8)(tmp+1); \
+ SBC
+
+/* 6510 ********************************************************
+ * LAX load accumulator and index X
+ ***************************************************************/
+#define LAX \
+ A = X = (UINT8)tmp; \
+ SET_NZ(A)
+
+/* 6510 ********************************************************
+ * OAL load accumulator and index X
+ ***************************************************************/
+#define OAL \
+ A = X = (UINT8)((A|0xee)&tmp); \
+ SET_NZ(A)
+
+/* 6510 ********************************************************
+ * RLA rotate left and logical and accumulator
+ * new C <- [7][6][5][4][3][2][1][0] <- C
+ ***************************************************************/
+#define RLA \
+ tmp = (tmp << 1) | (P & F_C); \
+ P = (P & ~F_C) | ((tmp >> 8) & F_C); \
+ tmp = (UINT8)tmp; \
+ A &= tmp; \
+ SET_NZ(A)
+
+/* 6510 ********************************************************
+ * RRA rotate right and add with carry
+ * C -> [7][6][5][4][3][2][1][0] -> C
+ ***************************************************************/
+#define RRA \
+ tmp |= (P & F_C) << 8; \
+ P = (P & ~F_C) | (tmp & F_C); \
+ tmp = (UINT8)(tmp >> 1); \
+ ADC
+
+/* 6510 ********************************************************
+ * SAX logical and accumulator with index X and store
+ ***************************************************************/
+#define SAX \
+ tmp = A & X
+
+/* 6510 ********************************************************
+ * SLO shift left and logical or
+ ***************************************************************/
+#define SLO \
+ P = (P & ~F_C) | ((tmp >> 7) & F_C); \
+ tmp = (UINT8)(tmp << 1); \
+ A |= tmp; \
+ SET_NZ(A)
+
+/* 6510 ********************************************************
+ * SRE logical shift right and logical exclusive or
+ * 0 -> [7][6][5][4][3][2][1][0] -> C
+ ***************************************************************/
+#define SRE \
+ P = (P & ~F_C) | (tmp & F_C); \
+ tmp = (UINT8)tmp >> 1; \
+ A ^= tmp; \
+ SET_NZ(A)
+
+/* 6510 ********************************************************
+ * SAH store accumulator and index X and high + 1
+ * result = accumulator and index X and memory [PC+1] + 1
+ ***************************************************************/
+#define SAH tmp = A & X & (EAH+1)
+
+/* 6510 ********************************************************
+ * SSH store stack high
+ * logical and accumulator with index X, transfer result to S
+ * logical and result with memory [PC+1] + 1
+ ***************************************************************/
+#define SSH \
+ S = A & X; \
+ tmp = S & (EAH+1)
+#if 0
+ tmp = S = A & X; \
+ tmp &= (UINT8)(cpu_readop_arg((PCW + 1) & 0xffff) + 1)
+#endif
+
+/* 6510 ********************************************************
+ * SXH store index X high
+ * logical and index X with memory[PC+1] and store the result
+ ***************************************************************/
+#define SXH tmp = X & (EAH+1)
+
+/* 6510 ********************************************************
+ * SYH store index Y and (high + 1)
+ * logical and index Y with memory[PC+1] + 1 and store the result
+ ***************************************************************/
+#define SYH tmp = Y & (EAH+1)
+
+/* 6510 ********************************************************
+ * TOP triple no operation
+ ***************************************************************/
+#define TOP \
+ PCW+=2
+
+/* 6510 ********************************************************
+ * KIL Illegal opcode
+ * processor halted: no hardware interrupt will help,
+ * only reset
+ ***************************************************************/
+#define KIL \
+ PCW--; \
+ logerror("M6510 KILL opcode %04x: %02x\n", \
+ PCW, cpu_readop(PCW))
+
+/* N2A03 *******************************************************
+ * ARR logical and, rotate right - no decimal mode
+ ***************************************************************/
+#define ARR_NES \
+ { \
+ tmp &= A; \
+ ROR; \
+ P &=~(F_V|F_C); \
+ if( tmp & 0x40 ) \
+ P|=F_C; \
+ if( (tmp & 0x60) == 0x20 || (tmp & 0x60) == 0x40 ) \
+ P|=F_V; \
+ }
+
+
+
diff --git a/src/emu/cpu/m6502/m4510.c b/src/emu/cpu/m6502/m4510.c
new file mode 100644
index 00000000000..b5a3adc8bef
--- /dev/null
+++ b/src/emu/cpu/m6502/m4510.c
@@ -0,0 +1,540 @@
+/*****************************************************************************
+ *
+ * m4510.c
+ * Portable 4510 emulator V1.0beta1
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved
+ * documentation preliminary databook
+ * documentation by michael steil mist@c64.org
+ * available at ftp://ftp.funet.fi/pub/cbm/c65
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+/*
+ c65 memory management
+ (reset)
+ c64 ff
+ c65 20 (interface)
+
+a (c65 mode)
+ a:00 x:e3 y:00 z:b3
+ c65 64 (interface)
+ c64 ff
+
+b (c65 dosmode?)
+ c65 65 (interface, full colorram)
+ a:00 x:11 y:80 z:31
+ c64 ff
+
+c (?)
+ c64 07
+ a:00 x:00 y:00 z:00
+
+ a c65 mode
+
+ diskcontroller accesses
+
+
+ monitor
+ c64 ff
+ a:a0 x:82 y:00 z:83
+
+ c64 mode
+ c65 0
+ c65 2f:0 !
+ c64 ff
+ a:00 x:00 y:00 z:00
+
+internal 8 mb to 64k switching (jmp routine in rom)
+( seams to be incomplete, in chapter 1 1megabyte memory mapper )
+ a x y z
+g 0 00 e0 00 f0
+g 10000 00 e1 00 f1
+g 20000 00 e2 00 f2
+g 30000 00 e3 00 f3
+g 40000 00 e4 00 f4
+g 50000 00 e5 00 f5
+g 60000 00 e6 00 f6
+.
+.
+g f0000 00 ef 00 ff
+the same for 100000 .. 700000
+g 800000 00 e3 00 b3
+
+thesis:
+a: ?0?0 0000
+ ? ? only in monitor mode set
+x: xxxx address bits a19 .. a16 for memory accesses with a15 0 ?
+ 0000 c64 mode
+ 0001 dosmode
+ 1110 c65 mode, plain ram access
+ (0000-1fff contains the switching code, so not switchable!?)
+ 1000 monitor
+ 1 map 6000-7fff
+ 1 map 4000-5fff
+ 1 map 2000-3fff
+ 1 map 0000-1fff
+y: ?000 0000
+ ? only in dos mode set
+z: xxxx address bits a19 .. a16 for memory accesses with a15 1 ?
+ 0000 c64 mode
+ 0011 dosmode
+ 1000 monitor
+ 1011 c65 mode
+ 1111 plain ram access
+ 1 map e000-ffff
+ 1 map c000-dfff
+ 1 map a000-bfff
+ 1 map 8000-9fff
+ */
+
+#include "debugger.h"
+#include "m6502.h"
+#include "m4510.h"
+
+#include "minc4510.h"
+#include "opsce02.h"
+#include "ops4510.h"
+
+#define M6502_NMI_VEC 0xfffa
+#define M6502_RST_VEC 0xfffc
+#define M6502_IRQ_VEC 0xfffe
+#define M4510_RST_VEC M6502_RST_VEC
+#define M4510_IRQ_VEC M6502_IRQ_VEC
+#define M4510_NMI_VEC M6502_NMI_VEC
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+typedef struct {
+ void (**insn)(void); /* pointer to the function pointer table */
+ PAIR ppc; /* previous program counter */
+ PAIR pc; /* program counter */
+ PAIR sp; /* stack pointer (always 100 - 1FF) */
+ PAIR zp; /* zero page address */
+ /* contains B register zp.b.h */
+ PAIR ea; /* effective address */
+ UINT8 a; /* Accumulator */
+ UINT8 x; /* X index register */
+ UINT8 y; /* Y index register */
+ UINT8 z; /* Z index register */
+ UINT8 p; /* Processor status */
+ UINT8 pending_irq; /* nonzero if an IRQ is pending */
+ UINT8 after_cli; /* pending IRQ and last insn cleared I */
+ UINT8 nmi_state;
+ UINT8 irq_state;
+ UINT16 low, high;
+ UINT32 mem[8];
+ int (*irq_callback)(int irqline); /* IRQ callback */
+ read8_handler rdmem_id; /* readmem callback for indexed instructions */
+ write8_handler wrmem_id; /* writemem callback for indexed instructions */
+
+ UINT8 ddr;
+ UINT8 port;
+ UINT8 (*port_read)(void);
+ void (*port_write)(UINT8 data);
+} m4510_Regs;
+
+static int m4510_ICount = 0;
+
+static m4510_Regs m4510;
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+
+INLINE int m4510_cpu_readop(void)
+{
+ register UINT16 t=m4510.pc.w.l++;
+ return cpu_readop(M4510_MEM(t));
+}
+
+INLINE int m4510_cpu_readop_arg(void)
+{
+ register UINT16 t=m4510.pc.w.l++;
+ return cpu_readop_arg(M4510_MEM(t));
+}
+
+#define M4510
+#include "t65ce02.c"
+
+static void m4510_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m4510.rdmem_id = program_read_byte_8;
+ m4510.wrmem_id = program_write_byte_8;
+ m4510.irq_callback = irqcallback;
+}
+
+static void m4510_reset (void)
+{
+ m4510.insn = insn4510;
+
+ /* wipe out the rest of the m65ce02 structure */
+ /* read the reset vector into PC */
+ /* reset z index and b bank */
+ PCL = RDMEM(M4510_RST_VEC);
+ PCH = RDMEM(M4510_RST_VEC+1);
+
+ /* after reset in 6502 compatibility mode */
+ m4510.sp.d = 0x01ff; /* high byte descriped in databook */
+ m4510.z = 0;
+ B = 0;
+ m4510.p = F_E|F_B|F_I|F_Z; /* set E, I and Z flags */
+ m4510.pending_irq = 0; /* nonzero if an IRQ is pending */
+ m4510.after_cli = 0; /* pending IRQ and last insn cleared I */
+ m4510.irq_callback = NULL;
+
+ /* don't know */
+ m4510.high=0x8200;
+ m4510.mem[7]=0x20000;
+
+ CHANGE_PC;
+
+ m4510.port = 0xff;
+ m4510.ddr = 0x00;
+}
+
+static void m4510_exit(void)
+{
+ /* nothing to do yet */
+}
+
+static void m4510_get_context (void *dst)
+{
+ if( dst )
+ *(m4510_Regs*)dst = m4510;
+}
+
+static void m4510_set_context (void *src)
+{
+ if( src )
+ {
+ m4510 = *(m4510_Regs*)src;
+ CHANGE_PC;
+ }
+}
+
+
+INLINE void m4510_take_irq(void)
+{
+ if( !(P & F_I) )
+ {
+ EAD = M4510_IRQ_VEC;
+ m4510_ICount -= 7;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P = (P & ~F_D) | F_I; /* knock out D and set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG((errorlog,"M4510#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
+ /* call back the cpuintrf to let it clear the line */
+ if (m4510.irq_callback) (*m4510.irq_callback)(0);
+ CHANGE_PC;
+ }
+ m4510.pending_irq = 0;
+}
+
+static int m4510_execute(int cycles)
+{
+ m4510_ICount = cycles;
+
+ CHANGE_PC;
+
+ do
+ {
+ UINT8 op;
+ PPC = PCD;
+
+ CALL_MAME_DEBUG;
+
+ /* if an irq is pending, take it now */
+ if( m4510.pending_irq )
+ m4510_take_irq();
+
+ op = RDOP();
+ (*insn4510[op])();
+
+ /* check if the I flag was just reset (interrupts enabled) */
+ if( m4510.after_cli )
+ {
+ LOG((errorlog,"M4510#%d after_cli was >0", cpu_getactivecpu()));
+ m4510.after_cli = 0;
+ if (m4510.irq_state != CLEAR_LINE)
+ {
+ LOG((errorlog,": irq line is asserted: set pending IRQ\n"));
+ m4510.pending_irq = 1;
+ }
+ else
+ {
+ LOG((errorlog,": irq line is clear\n"));
+ }
+ }
+ else
+ if( m4510.pending_irq )
+ m4510_take_irq();
+
+ } while (m4510_ICount > 0);
+
+ return cycles - m4510_ICount;
+}
+
+static void m4510_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m4510.nmi_state == state) return;
+ m4510.nmi_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG((errorlog, "M4510#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
+ EAD = M4510_NMI_VEC;
+ m4510_ICount -= 7;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P = (P & ~F_D) | F_I; /* knock out D and set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG((errorlog,"M4510#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
+ CHANGE_PC;
+ }
+ }
+ else
+ {
+ m4510.irq_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG((errorlog, "M4510#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
+ m4510.pending_irq = 1;
+ }
+ }
+}
+
+static UINT8 m4510_get_port(void)
+{
+ return (m4510.port & m4510.ddr) | (m4510.ddr ^ 0xff);
+}
+
+static READ8_HANDLER( m4510_read_0000 )
+{
+ UINT8 result = 0x00;
+
+ switch(offset)
+ {
+ case 0x0000: /* DDR */
+ result = m4510.ddr;
+ break;
+ case 0x0001: /* Data Port */
+ if (m4510.port_read)
+ result = m4510.port_read();
+ result = (m4510.ddr & m4510.port) | (~m4510.ddr & result);
+ break;
+ }
+ return result;
+}
+
+static WRITE8_HANDLER( m4510_write_0000 )
+{
+ switch(offset)
+ {
+ case 0x0000: /* DDR */
+ m4510.ddr = data;
+ break;
+ case 0x0001: /* Data Port */
+ m4510.port = data;
+ break;
+ }
+
+ if (m4510.port_write)
+ m4510.port_write(m4510_get_port());
+}
+
+static ADDRESS_MAP_START(m4510_mem, ADDRESS_SPACE_PROGRAM, 8)
+ AM_RANGE(0x0000, 0x0001) AM_READWRITE(m4510_read_0000, m4510_write_0000)
+ADDRESS_MAP_END
+
+static int m4510_translate(int space, offs_t *addr)
+{
+ if (space == ADDRESS_SPACE_PROGRAM)
+ *addr = M4510_MEM(*addr);
+ return 1;
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void m4510_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M4510_IRQ_LINE: m4510_set_irq_line(M4510_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: m4510_set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC: PCW = info->i; change_pc(PCD); break;
+ case CPUINFO_INT_REGISTER + M4510_PC: m4510.pc.w.l = info->i; break;
+ case CPUINFO_INT_SP: SPL = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_S: m4510.sp.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_P: m4510.p = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_A: m4510.a = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_X: m4510.x = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_Y: m4510.y = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_Z: m4510.z = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_B: m4510.zp.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM_LOW: m4510.low = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM_HIGH: m4510.high = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_EA: m4510.ea.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_ZP: m4510.zp.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM0: m4510.mem[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM1: m4510.mem[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM2: m4510.mem[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM3: m4510.mem[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM4: m4510.mem[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM5: m4510.mem[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM6: m4510.mem[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM7: m4510.mem[7] = info->i; break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_M6502_READINDEXED_CALLBACK: m4510.rdmem_id = (read8_handler) info->f; break;
+ case CPUINFO_PTR_M6502_WRITEINDEXED_CALLBACK: m4510.wrmem_id = (write8_handler) info->f; break;
+ case CPUINFO_PTR_M6510_PORTREAD: m4510.port_read = (UINT8 (*)(void)) info->f; break;
+ case CPUINFO_PTR_M6510_PORTWRITE: m4510.port_write = (void (*)(UINT8)) info->f; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void m4510_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(m4510); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 10; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 20; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 13; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + M4510_IRQ_LINE: info->i = m4510.irq_state; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = m4510.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = m4510.ppc.w.l; break;
+
+ case CPUINFO_INT_PC: info->i = PCD; break;
+ case CPUINFO_INT_REGISTER + M4510_PC: info->i = m4510.pc.w.l; break;
+ case CPUINFO_INT_SP: info->i = SPL; break;
+ case CPUINFO_INT_REGISTER + M4510_S: info->i = m4510.sp.b.l; break;
+ case CPUINFO_INT_REGISTER + M4510_P: info->i = m4510.p; break;
+ case CPUINFO_INT_REGISTER + M4510_A: info->i = m4510.a; break;
+ case CPUINFO_INT_REGISTER + M4510_X: info->i = m4510.x; break;
+ case CPUINFO_INT_REGISTER + M4510_Y: info->i = m4510.y; break;
+ case CPUINFO_INT_REGISTER + M4510_Z: info->i = m4510.z; break;
+ case CPUINFO_INT_REGISTER + M4510_B: info->i = m4510.zp.b.h; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM_LOW: info->i = m4510.low; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM_HIGH: info->i = m4510.high; break;
+ case CPUINFO_INT_REGISTER + M4510_EA: info->i = m4510.ea.w.l; break;
+ case CPUINFO_INT_REGISTER + M4510_ZP: info->i = m4510.zp.w.l; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM0: info->i = m4510.mem[0]; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM1: info->i = m4510.mem[1]; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM2: info->i = m4510.mem[2]; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM3: info->i = m4510.mem[3]; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM4: info->i = m4510.mem[4]; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM5: info->i = m4510.mem[5]; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM6: info->i = m4510.mem[6]; break;
+ case CPUINFO_INT_REGISTER + M4510_MEM7: info->i = m4510.mem[7]; break;
+ case CPUINFO_INT_M6510_PORT: info->i = m4510_get_port(); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m4510_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m4510_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m4510_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m4510_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m4510_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m4510_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m4510_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m4510_dasm; break;
+#endif
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m4510_ICount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP: info->internal_map = construct_map_m4510_mem; break;
+ case CPUINFO_PTR_TRANSLATE: info->translate = m4510_translate; break;
+ case CPUINFO_PTR_M6502_READINDEXED_CALLBACK: info->f = (genf *) m4510.rdmem_id; break;
+ case CPUINFO_PTR_M6502_WRITEINDEXED_CALLBACK: info->f = (genf *) m4510.wrmem_id; break;
+ case CPUINFO_PTR_M6510_PORTREAD: info->f = (genf *) m4510.port_read; break;
+ case CPUINFO_PTR_M6510_PORTWRITE: info->f = (genf *) m4510.port_write; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M4510"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "CBM Semiconductor Group CSG 65CE02"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0beta"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 1998 Juergen Buchmueller\nCopyright (c) 2000 Peter Trauner\nall rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ m4510.p & 0x80 ? 'N':'.',
+ m4510.p & 0x40 ? 'V':'.',
+ m4510.p & 0x20 ? 'R':'.',
+ m4510.p & 0x10 ? 'B':'.',
+ m4510.p & 0x08 ? 'D':'.',
+ m4510.p & 0x04 ? 'I':'.',
+ m4510.p & 0x02 ? 'Z':'.',
+ m4510.p & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M4510_PC: sprintf(info->s, "PC:%04X", m4510.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + M4510_S: sprintf(info->s, "S:%02X", m4510.sp.b.l); break;
+ case CPUINFO_STR_REGISTER + M4510_P: sprintf(info->s, "P:%02X", m4510.p); break;
+ case CPUINFO_STR_REGISTER + M4510_A: sprintf(info->s, "A:%02X", m4510.a); break;
+ case CPUINFO_STR_REGISTER + M4510_X: sprintf(info->s, "X:%02X", m4510.x); break;
+ case CPUINFO_STR_REGISTER + M4510_Y: sprintf(info->s, "Y:%02X", m4510.y); break;
+ case CPUINFO_STR_REGISTER + M4510_Z: sprintf(info->s, "Z:%02X", m4510.z); break;
+ case CPUINFO_STR_REGISTER + M4510_B: sprintf(info->s, "B:%02X", m4510.zp.b.h); break;
+ case CPUINFO_STR_REGISTER + M4510_MEM_LOW: sprintf(info->s, "M0:%01X", m4510.low); break;
+ case CPUINFO_STR_REGISTER + M4510_MEM_HIGH: sprintf(info->s, "M1:%01X", m4510.high); break;
+ case CPUINFO_STR_REGISTER + M4510_EA: sprintf(info->s, "EA:%04X", m4510.ea.w.l); break;
+ case CPUINFO_STR_REGISTER + M4510_ZP: sprintf(info->s, "ZP:%03X", m4510.zp.w.l); break;
+ }
+}
+
diff --git a/src/emu/cpu/m6502/m4510.h b/src/emu/cpu/m6502/m4510.h
new file mode 100644
index 00000000000..81605ca71ca
--- /dev/null
+++ b/src/emu/cpu/m6502/m4510.h
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ *
+ * m4510.c
+ * Portable 4510 emulator V1.0beta
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#ifndef _M4510_H
+#define _M4510_H
+
+#include "m6502.h"
+
+
+enum {
+ M4510_PC=1, M4510_S, M4510_P, M4510_A, M4510_X, M4510_Y,
+ M4510_Z, M4510_B, M4510_EA, M4510_ZP,
+ M4510_NMI_STATE, M4510_IRQ_STATE,
+ M4510_MEM_LOW,M4510_MEM_HIGH,
+ M4510_MEM0, M4510_MEM1, M4510_MEM2, M4510_MEM3,
+ M4510_MEM4, M4510_MEM5, M4510_MEM6, M4510_MEM7
+};
+
+#define M4510_IRQ_LINE M6502_IRQ_LINE
+
+void m4510_get_info(UINT32 state, cpuinfo *info);
+
+
+#ifdef MAME_DEBUG
+extern unsigned m4510_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+#endif
+
+
diff --git a/src/emu/cpu/m6502/m6502.c b/src/emu/cpu/m6502/m6502.c
new file mode 100644
index 00000000000..89da4704784
--- /dev/null
+++ b/src/emu/cpu/m6502/m6502.c
@@ -0,0 +1,1017 @@
+/*****************************************************************************
+ *
+ * m6502.c
+ * Portable 6502/65c02/65sc02/6510/n2a03 emulator V1.2
+ *
+ * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * 65sc02 core Copyright (c) 2000 Peter Trauner.
+ * Deco16 portions Copyright (c) 2001-2003 Bryan McPhail.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+/* 2.February 2000 PeT added 65sc02 subtype */
+/* 10.March 2000 PeT added 6502 set overflow input line */
+/* 13.September 2000 PeT N2A03 jmp indirect */
+
+#if ((HAS_M65SC02 || HAS_DECO16) && !HAS_M65C02)
+#undef HAS_M65C02
+#define HAS_M65C02 1
+#endif
+
+#include "debugger.h"
+#include "m6502.h"
+#include "ops02.h"
+#include "ill02.h"
+
+
+#define M6502_NMI_VEC 0xfffa
+#define M6502_RST_VEC 0xfffc
+#define M6502_IRQ_VEC 0xfffe
+
+#define DECO16_RST_VEC 0xfff0
+#define DECO16_IRQ_VEC 0xfff2
+#define DECO16_NMI_VEC 0xfff4
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+
+/****************************************************************************
+ * The 6502 registers.
+ ****************************************************************************/
+typedef struct
+{
+ UINT8 subtype; /* currently selected cpu sub type */
+ void (**insn)(void); /* pointer to the function pointer table */
+ PAIR ppc; /* previous program counter */
+ PAIR pc; /* program counter */
+ PAIR sp; /* stack pointer (always 100 - 1FF) */
+ PAIR zp; /* zero page address */
+ PAIR ea; /* effective address */
+ UINT8 a; /* Accumulator */
+ UINT8 x; /* X index register */
+ UINT8 y; /* Y index register */
+ UINT8 p; /* Processor status */
+ UINT8 pending_irq; /* nonzero if an IRQ is pending */
+ UINT8 after_cli; /* pending IRQ and last insn cleared I */
+ UINT8 nmi_state;
+ UINT8 irq_state;
+ UINT8 so_state;
+ int (*irq_callback)(int irqline); /* IRQ callback */
+ read8_handler rdmem_id; /* readmem callback for indexed instructions */
+ write8_handler wrmem_id; /* writemem callback for indexed instructions */
+
+#if (HAS_M6510) || (HAS_M6510T) || (HAS_M8502) || (HAS_M7501)
+ UINT8 ddr;
+ UINT8 port;
+ UINT8 (*port_read)(UINT8 direction);
+ void (*port_write)(UINT8 direction, UINT8 data);
+#endif
+
+} m6502_Regs;
+
+int m6502_IntOccured = 0;
+int m6502_ICount = 0;
+
+static m6502_Regs m6502;
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+#include "t6502.c"
+
+#if (HAS_M6510)
+#include "t6510.c"
+#endif
+
+#include "opsn2a03.h"
+
+#if (HAS_N2A03)
+#include "tn2a03.c"
+#endif
+
+#include "opsc02.h"
+
+#if (HAS_M65C02)
+#include "t65c02.c"
+#endif
+
+#if (HAS_M65SC02)
+#include "t65sc02.c"
+#endif
+
+#if (HAS_DECO16)
+#include "tdeco16.c"
+#endif
+
+/*****************************************************************************
+ *
+ * 6502 CPU interface functions
+ *
+ *****************************************************************************/
+
+static void m6502_common_init(int index, int clock, const void *config, int (*irqcallback)(int), UINT8 subtype, void (**insn)(void), const char *type)
+{
+ memset(&m6502, 0, sizeof(m6502));
+ m6502.irq_callback = irqcallback;
+ m6502.subtype = subtype;
+ m6502.insn = insn;
+ m6502.rdmem_id = program_read_byte_8;
+ m6502.wrmem_id = program_write_byte_8;
+
+ state_save_register_item(type, index, m6502.pc.w.l);
+ state_save_register_item(type, index, m6502.sp.w.l);
+ state_save_register_item(type, index, m6502.p);
+ state_save_register_item(type, index, m6502.a);
+ state_save_register_item(type, index, m6502.x);
+ state_save_register_item(type, index, m6502.y);
+ state_save_register_item(type, index, m6502.pending_irq);
+ state_save_register_item(type, index, m6502.after_cli);
+ state_save_register_item(type, index, m6502.nmi_state);
+ state_save_register_item(type, index, m6502.irq_state);
+ state_save_register_item(type, index, m6502.so_state);
+
+#if (HAS_M6510) || (HAS_M6510T) || (HAS_M8502) || (HAS_M7501)
+ if (subtype == SUBTYPE_6510)
+ {
+ state_save_register_item(type, index, m6502.port);
+ state_save_register_item(type, index, m6502.ddr);
+ }
+#endif
+}
+
+static void m6502_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m6502_common_init(index, clock, config, irqcallback, SUBTYPE_6502, insn6502, "m6502");
+}
+
+static void m6502_reset(void)
+{
+ /* wipe out the rest of the m6502 structure */
+ /* read the reset vector into PC */
+ PCL = RDMEM(M6502_RST_VEC);
+ PCH = RDMEM(M6502_RST_VEC+1);
+
+ m6502.sp.d = 0x01ff; /* stack pointer starts at page 1 offset FF */
+ m6502.p = F_T|F_I|F_Z|F_B|(P&F_D); /* set T, I and Z flags */
+ m6502.pending_irq = 0; /* nonzero if an IRQ is pending */
+ m6502.after_cli = 0; /* pending IRQ and last insn cleared I */
+ m6502.irq_state = 0;
+ m6502.nmi_state = 0;
+
+ change_pc(PCD);
+}
+
+static void m6502_exit(void)
+{
+ /* nothing to do yet */
+}
+
+static void m6502_get_context (void *dst)
+{
+ if( dst )
+ *(m6502_Regs*)dst = m6502;
+}
+
+static void m6502_set_context (void *src)
+{
+ if( src )
+ {
+ m6502 = *(m6502_Regs*)src;
+ change_pc(PCD);
+ }
+}
+
+INLINE void m6502_take_irq(void)
+{
+ if( !(P & F_I) )
+ {
+ EAD = M6502_IRQ_VEC;
+ m6502_ICount -= 2;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P |= F_I; /* set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG(("M6502#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
+ /* call back the cpuintrf to let it clear the line */
+ if (m6502.irq_callback) (*m6502.irq_callback)(0);
+ change_pc(PCD);
+ }
+ m6502.pending_irq = 0;
+}
+
+static int m6502_execute(int cycles)
+{
+ m6502_ICount = cycles;
+
+ change_pc(PCD);
+
+ do
+ {
+ UINT8 op;
+ PPC = PCD;
+
+ CALL_MAME_DEBUG;
+
+ /* if an irq is pending, take it now */
+ if( m6502.pending_irq )
+ m6502_take_irq();
+
+ op = RDOP();
+ (*m6502.insn[op])();
+
+ /* check if the I flag was just reset (interrupts enabled) */
+ if( m6502.after_cli )
+ {
+ LOG(("M6502#%d after_cli was >0", cpu_getactivecpu()));
+ m6502.after_cli = 0;
+ if (m6502.irq_state != CLEAR_LINE)
+ {
+ LOG((": irq line is asserted: set pending IRQ\n"));
+ m6502.pending_irq = 1;
+ }
+ else
+ {
+ LOG((": irq line is clear\n"));
+ }
+ }
+ else {
+ if ( m6502.pending_irq == 2 ) {
+ if ( m6502_IntOccured - m6502_ICount > 1 ) {
+ m6502.pending_irq = 1;
+ }
+ }
+ if( m6502.pending_irq == 1 )
+ m6502_take_irq();
+ if ( m6502.pending_irq == 2 ) {
+ m6502.pending_irq = 1;
+ }
+ }
+
+ } while (m6502_ICount > 0);
+
+ return cycles - m6502_ICount;
+}
+
+static void m6502_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m6502.nmi_state == state) return;
+ m6502.nmi_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(( "M6502#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
+ EAD = M6502_NMI_VEC;
+ m6502_ICount -= 2;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P |= F_I; /* set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG(("M6502#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
+ change_pc(PCD);
+ }
+ }
+ else
+ {
+ if( irqline == M6502_SET_OVERFLOW )
+ {
+ if( m6502.so_state && !state )
+ {
+ LOG(( "M6502#%d set overflow\n", cpu_getactivecpu()));
+ P|=F_V;
+ }
+ m6502.so_state=state;
+ return;
+ }
+ m6502.irq_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(( "M6502#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
+ m6502.pending_irq = 1;
+// m6502.pending_irq = 2;
+ m6502_IntOccured = m6502_ICount;
+ }
+ }
+}
+
+
+
+/****************************************************************************
+ * 2A03 section
+ ****************************************************************************/
+#if (HAS_N2A03)
+
+static void n2a03_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m6502_common_init(index, clock, config, irqcallback, SUBTYPE_2A03, insn2a03, "n2a03");
+}
+
+/* The N2A03 is integrally tied to its PSG (they're on the same die).
+ Bit 7 of address $4011 (the PSG's DPCM control register), when set,
+ causes an IRQ to be generated. This function allows the IRQ to be called
+ from the PSG core when such an occasion arises. */
+void n2a03_irq(void)
+{
+ m6502_take_irq();
+}
+#endif
+
+
+/****************************************************************************
+ * 6510 section
+ ****************************************************************************/
+#if (HAS_M6510)
+
+static void m6510_init (int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m6502_common_init(index, clock, config, irqcallback, SUBTYPE_6510, insn6510, "m6510");
+}
+
+static void m6510_reset (void)
+{
+ m6502_reset();
+ m6502.port = 0xff;
+ m6502.ddr = 0x00;
+}
+
+static UINT8 m6510_get_port(void)
+{
+ return (m6502.port & m6502.ddr) | (m6502.ddr ^ 0xff);
+}
+
+static READ8_HANDLER( m6510_read_0000 )
+{
+ UINT8 result = 0x00;
+
+ switch(offset)
+ {
+ case 0x0000: /* DDR */
+ result = m6502.ddr;
+ break;
+ case 0x0001: /* Data Port */
+ if (m6502.port_read)
+ result = m6502.port_read( m6502.ddr );
+ result = (m6502.ddr & m6502.port) | (~m6502.ddr & result);
+ break;
+ }
+ return result;
+}
+
+static WRITE8_HANDLER( m6510_write_0000 )
+{
+ switch(offset)
+ {
+ case 0x0000: /* DDR */
+ m6502.ddr = data;
+ break;
+ case 0x0001: /* Data Port */
+ m6502.port = data;
+ break;
+ }
+
+ if (m6502.port_write)
+ m6502.port_write( m6502.ddr, m6502.port & m6502.ddr );
+}
+
+static ADDRESS_MAP_START(m6510_mem, ADDRESS_SPACE_PROGRAM, 8)
+ AM_RANGE(0x0000, 0x0001) AM_READWRITE(m6510_read_0000, m6510_write_0000)
+ADDRESS_MAP_END
+
+#endif
+
+
+/****************************************************************************
+ * 65C02 section
+ ****************************************************************************/
+#if (HAS_M65C02)
+
+static void m65c02_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m6502_common_init(index, clock, config, irqcallback, SUBTYPE_65C02, insn65c02, "m65c02");
+}
+
+static void m65c02_reset (void)
+{
+ m6502_reset();
+ P &=~F_D;
+}
+
+INLINE void m65c02_take_irq(void)
+{
+ if( !(P & F_I) )
+ {
+ EAD = M6502_IRQ_VEC;
+ m6502_ICount -= 2;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P = (P & ~F_D) | F_I; /* knock out D and set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG(("M65c02#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
+ /* call back the cpuintrf to let it clear the line */
+ if (m6502.irq_callback) (*m6502.irq_callback)(0);
+ change_pc(PCD);
+ }
+ m6502.pending_irq = 0;
+}
+
+static int m65c02_execute(int cycles)
+{
+ m6502_ICount = cycles;
+
+ change_pc(PCD);
+
+ do
+ {
+ UINT8 op;
+ PPC = PCD;
+
+ CALL_MAME_DEBUG;
+
+ op = RDOP();
+ (*m6502.insn[op])();
+
+ /* if an irq is pending, take it now */
+ if( m6502.pending_irq )
+ m65c02_take_irq();
+
+
+ /* check if the I flag was just reset (interrupts enabled) */
+ if( m6502.after_cli )
+ {
+ LOG(("M6502#%d after_cli was >0", cpu_getactivecpu()));
+ m6502.after_cli = 0;
+ if (m6502.irq_state != CLEAR_LINE)
+ {
+ LOG((": irq line is asserted: set pending IRQ\n"));
+ m6502.pending_irq = 1;
+ }
+ else
+ {
+ LOG((": irq line is clear\n"));
+ }
+ }
+ else
+ if( m6502.pending_irq )
+ m65c02_take_irq();
+
+ } while (m6502_ICount > 0);
+
+ return cycles - m6502_ICount;
+}
+
+static void m65c02_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m6502.nmi_state == state) return;
+ m6502.nmi_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(( "M6502#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
+ EAD = M6502_NMI_VEC;
+ m6502_ICount -= 2;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P = (P & ~F_D) | F_I; /* knock out D and set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG(("M6502#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
+ change_pc(PCD);
+ }
+ }
+ else
+ m6502_set_irq_line(irqline,state);
+}
+#endif
+
+/****************************************************************************
+ * 65SC02 section
+ ****************************************************************************/
+#if (HAS_M65SC02)
+static void m65sc02_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m6502_common_init(index, clock, config, irqcallback, SUBTYPE_65SC02, insn65sc02, "m65sc02");
+}
+#endif
+
+/****************************************************************************
+ * DECO16 section
+ ****************************************************************************/
+#if (HAS_DECO16)
+
+static void deco16_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m6502_common_init(index, clock, config, irqcallback, SUBTYPE_DECO16, insndeco16, "deco16");
+}
+
+
+static void deco16_reset (void)
+{
+ m6502_reset();
+ m6502.subtype = SUBTYPE_DECO16;
+ m6502.insn = insndeco16;
+
+ PCL = RDMEM(DECO16_RST_VEC+1);
+ PCH = RDMEM(DECO16_RST_VEC);
+
+ m6502.sp.d = 0x01ff; /* stack pointer starts at page 1 offset FF */
+ m6502.p = F_T|F_I|F_Z|F_B|(P&F_D); /* set T, I and Z flags */
+ m6502.pending_irq = 0; /* nonzero if an IRQ is pending */
+ m6502.after_cli = 0; /* pending IRQ and last insn cleared I */
+
+ change_pc(PCD);
+}
+
+INLINE void deco16_take_irq(void)
+{
+ if( !(P & F_I) )
+ {
+ EAD = DECO16_IRQ_VEC;
+ m6502_ICount -= 2;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P |= F_I; /* set I flag */
+ PCL = RDMEM(EAD+1);
+ PCH = RDMEM(EAD);
+ LOG(("M6502#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
+ /* call back the cpuintrf to let it clear the line */
+ if (m6502.irq_callback) (*m6502.irq_callback)(0);
+ change_pc(PCD);
+ }
+ m6502.pending_irq = 0;
+}
+
+static void deco16_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m6502.nmi_state == state) return;
+ m6502.nmi_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(( "M6502#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
+ EAD = DECO16_NMI_VEC;
+ m6502_ICount -= 7;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P |= F_I; /* set I flag */
+ PCL = RDMEM(EAD+1);
+ PCH = RDMEM(EAD);
+ LOG(("M6502#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
+ change_pc(PCD);
+ }
+ }
+ else
+ {
+ if( irqline == M6502_SET_OVERFLOW )
+ {
+ if( m6502.so_state && !state )
+ {
+ LOG(( "M6502#%d set overflow\n", cpu_getactivecpu()));
+ P|=F_V;
+ }
+ m6502.so_state=state;
+ return;
+ }
+ m6502.irq_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(( "M6502#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
+ m6502.pending_irq = 1;
+ }
+ }
+}
+
+static int deco16_execute(int cycles)
+{
+ m6502_ICount = cycles;
+
+ change_pc(PCD);
+
+ do
+ {
+ UINT8 op;
+ PPC = PCD;
+
+ CALL_MAME_DEBUG;
+
+ op = RDOP();
+ (*m6502.insn[op])();
+
+ /* if an irq is pending, take it now */
+ if( m6502.pending_irq )
+ deco16_take_irq();
+
+
+ /* check if the I flag was just reset (interrupts enabled) */
+ if( m6502.after_cli )
+ {
+ LOG(("M6502#%d after_cli was >0", cpu_getactivecpu()));
+ m6502.after_cli = 0;
+ if (m6502.irq_state != CLEAR_LINE)
+ {
+ LOG((": irq line is asserted: set pending IRQ\n"));
+ m6502.pending_irq = 1;
+ }
+ else
+ {
+ LOG((": irq line is clear\n"));
+ }
+ }
+ else
+ if( m6502.pending_irq )
+ deco16_take_irq();
+
+ } while (m6502_ICount > 0);
+
+ return cycles - m6502_ICount;
+}
+
+#endif
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void m6502_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M6502_IRQ_LINE: m6502_set_irq_line(M6502_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M6502_SET_OVERFLOW: m6502_set_irq_line(M6502_SET_OVERFLOW, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: m6502_set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC: PCW = info->i; change_pc(PCD); break;
+ case CPUINFO_INT_REGISTER + M6502_PC: m6502.pc.w.l = info->i; break;
+ case CPUINFO_INT_SP: S = info->i; break;
+ case CPUINFO_INT_REGISTER + M6502_S: m6502.sp.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M6502_P: m6502.p = info->i; break;
+ case CPUINFO_INT_REGISTER + M6502_A: m6502.a = info->i; break;
+ case CPUINFO_INT_REGISTER + M6502_X: m6502.x = info->i; break;
+ case CPUINFO_INT_REGISTER + M6502_Y: m6502.y = info->i; break;
+ case CPUINFO_INT_REGISTER + M6502_EA: m6502.ea.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M6502_ZP: m6502.zp.w.l = info->i; break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_M6502_READINDEXED_CALLBACK: m6502.rdmem_id = (read8_handler) info->f; break;
+ case CPUINFO_PTR_M6502_WRITEINDEXED_CALLBACK: m6502.wrmem_id = (write8_handler) info->f; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void m6502_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(m6502); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 10; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + M6502_IRQ_LINE: info->i = m6502.irq_state; break;
+ case CPUINFO_INT_INPUT_STATE + M6502_SET_OVERFLOW: info->i = m6502.so_state; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = m6502.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = m6502.ppc.w.l; break;
+
+ case CPUINFO_INT_PC: info->i = PCD; break;
+ case CPUINFO_INT_REGISTER + M6502_PC: info->i = m6502.pc.w.l; break;
+ case CPUINFO_INT_SP: info->i = S; break;
+ case CPUINFO_INT_REGISTER + M6502_S: info->i = m6502.sp.b.l; break;
+ case CPUINFO_INT_REGISTER + M6502_P: info->i = m6502.p; break;
+ case CPUINFO_INT_REGISTER + M6502_A: info->i = m6502.a; break;
+ case CPUINFO_INT_REGISTER + M6502_X: info->i = m6502.x; break;
+ case CPUINFO_INT_REGISTER + M6502_Y: info->i = m6502.y; break;
+ case CPUINFO_INT_REGISTER + M6502_EA: info->i = m6502.ea.w.l; break;
+ case CPUINFO_INT_REGISTER + M6502_ZP: info->i = m6502.zp.w.l; break;
+ case CPUINFO_INT_REGISTER + M6502_SUBTYPE: info->i = m6502.subtype; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m6502_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m6502_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m6502_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m6502_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m6502_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m6502_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m6502_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6502_dasm; break;
+#endif
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m6502_ICount; break;
+ case CPUINFO_PTR_M6502_READINDEXED_CALLBACK: info->f = (genf *) m6502.rdmem_id; break;
+ case CPUINFO_PTR_M6502_WRITEINDEXED_CALLBACK: info->f = (genf *) m6502.wrmem_id; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6502"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Mostek 6502"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.2"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 1998 Juergen Buchmueller, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ m6502.p & 0x80 ? 'N':'.',
+ m6502.p & 0x40 ? 'V':'.',
+ m6502.p & 0x20 ? 'R':'.',
+ m6502.p & 0x10 ? 'B':'.',
+ m6502.p & 0x08 ? 'D':'.',
+ m6502.p & 0x04 ? 'I':'.',
+ m6502.p & 0x02 ? 'Z':'.',
+ m6502.p & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M6502_PC: sprintf(info->s, "PC:%04X", m6502.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + M6502_S: sprintf(info->s, "S:%02X", m6502.sp.b.l); break;
+ case CPUINFO_STR_REGISTER + M6502_P: sprintf(info->s, "P:%02X", m6502.p); break;
+ case CPUINFO_STR_REGISTER + M6502_A: sprintf(info->s, "A:%02X", m6502.a); break;
+ case CPUINFO_STR_REGISTER + M6502_X: sprintf(info->s, "X:%02X", m6502.x); break;
+ case CPUINFO_STR_REGISTER + M6502_Y: sprintf(info->s, "Y:%02X", m6502.y); break;
+ case CPUINFO_STR_REGISTER + M6502_EA: sprintf(info->s, "EA:%04X", m6502.ea.w.l); break;
+ case CPUINFO_STR_REGISTER + M6502_ZP: sprintf(info->s, "ZP:%03X", m6502.zp.w.l); break;
+ }
+}
+
+
+#if (HAS_N2A03)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void n2a03_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = n2a03_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "N2A03"); break;
+
+ default: m6502_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_M6510) || (HAS_M6510T) || (HAS_M8502) || (HAS_M7501)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+static void m6510_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_M6510_PORTREAD: m6502.port_read = (UINT8 (*)(UINT8)) info->f; break;
+ case CPUINFO_PTR_M6510_PORTWRITE: m6502.port_write = (void (*)(UINT8,UINT8)) info->f; break;
+
+ default: m6502_set_info(state, info); break;
+ }
+}
+
+void m6510_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m6510_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = m6510_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m6510_reset; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6510_dasm; break;
+#endif
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP: info->internal_map = construct_map_m6510_mem; break;
+ case CPUINFO_PTR_M6510_PORTREAD: info->f = (genf *) m6502.port_read; break;
+ case CPUINFO_PTR_M6510_PORTWRITE: info->f = (genf *) m6502.port_write; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6510"); break;
+
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_M6510_PORT: info->i = m6510_get_port(); break;
+
+ default: m6502_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_M6510T)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void m6510t_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6510T"); break;
+
+ default: m6510_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_M7501)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void m7501_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M7501"); break;
+
+ default: m6510_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_M8502)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void m8502_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M8502"); break;
+
+ default: m6510_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_M65C02)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+static void m65c02_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: m65c02_set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ default: m6502_set_info(state, info); break;
+ }
+}
+
+void m65c02_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m65c02_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = m65c02_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m65c02_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m65c02_execute; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m65c02_dasm; break;
+#endif
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M65C02"); break;
+
+ default: m6502_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_M65SC02)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void m65sc02_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = m65sc02_init; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m65sc02_dasm; break;
+#endif
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M65SC02"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Metal Oxid Semiconductor MOS 6502"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0beta"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 1998 Juergen Buchmueller\nCopyright (c) 2000 Peter Trauner\nall rights reserved."); break;
+
+ default: m65c02_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_DECO16)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+static void deco16_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M6502_IRQ_LINE: deco16_set_irq_line(M6502_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M6502_SET_OVERFLOW: deco16_set_irq_line(M6502_SET_OVERFLOW, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: deco16_set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ default: m6502_set_info(state, info); break;
+ }
+}
+
+void deco16_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = deco16_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = deco16_init; break;
+ case CPUINFO_PTR_RESET: info->reset = deco16_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = deco16_execute; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = deco16_dasm; break;
+#endif
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "DECO CPU16"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "DECO"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.1"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 1998 Juergen Buchmueller\nCopyright (c) 2001-2003 Bryan McPhail\nall rights reserved."); break;
+
+ default: m6502_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/m6502/m6502.h b/src/emu/cpu/m6502/m6502.h
new file mode 100644
index 00000000000..c0de2d9689b
--- /dev/null
+++ b/src/emu/cpu/m6502/m6502.h
@@ -0,0 +1,259 @@
+/*****************************************************************************
+ *
+ * m6502.h
+ * Portable 6502/65c02/65sc02/6510/n2a03 emulator interface
+ *
+ * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * 65sc02 core Copyright (c) 2000 Peter Trauner.
+ * Deco16 portions Copyright (c) 2001 Bryan McPhail.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+/* 2.February 2000 PeT added 65sc02 subtype */
+
+#ifndef _M6502_H
+#define _M6502_H
+
+#include "cpuintrf.h"
+
+/* set to 1 to test cur_mrhard/cur_wmhard to avoid calls */
+#define FAST_MEMORY 0
+
+#define SUBTYPE_6502 0
+#if (HAS_M65C02)
+#define SUBTYPE_65C02 1
+#endif
+#if (HAS_M6510)
+#define SUBTYPE_6510 2
+#endif
+#if (HAS_N2A03)
+#define SUBTYPE_2A03 3
+#endif
+#if (HAS_M65SC02)
+#define SUBTYPE_65SC02 4
+#endif
+#if (HAS_DECO16)
+#define SUBTYPE_DECO16 5
+#endif
+
+enum {
+ M6502_PC=1, M6502_S, M6502_P, M6502_A, M6502_X, M6502_Y,
+ M6502_EA, M6502_ZP,
+ M6502_SUBTYPE
+};
+
+#define M6502_IRQ_LINE 0
+/* use cpunum_set_input_line(cpu, M6502_SET_OVERFLOW, level)
+ to change level of the so input line
+ positiv edge sets overflow flag */
+#define M6502_SET_OVERFLOW 1
+
+enum
+{
+ CPUINFO_PTR_M6502_READINDEXED_CALLBACK = CPUINFO_PTR_CPU_SPECIFIC,
+ CPUINFO_PTR_M6502_WRITEINDEXED_CALLBACK,
+ CPUINFO_PTR_M6510_PORTREAD,
+ CPUINFO_PTR_M6510_PORTWRITE,
+
+ CPUINFO_INT_M6510_PORT = CPUINFO_INT_CPU_SPECIFIC
+};
+
+extern void m6502_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern unsigned m6502_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+/****************************************************************************
+ * The 6510
+ ****************************************************************************/
+#if (HAS_M6510)
+#define M6510_A M6502_A
+#define M6510_X M6502_X
+#define M6510_Y M6502_Y
+#define M6510_S M6502_S
+#define M6510_PC M6502_PC
+#define M6510_P M6502_P
+#define M6510_EA M6502_EA
+#define M6510_ZP M6502_ZP
+#define M6510_NMI_STATE M6502_NMI_STATE
+#define M6510_IRQ_STATE M6502_IRQ_STATE
+
+#define M6510_IRQ_LINE M6502_IRQ_LINE
+
+extern void m6510_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern unsigned m6510_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif
+
+#if (HAS_M6510T)
+#define M6510T_A M6502_A
+#define M6510T_X M6502_X
+#define M6510T_Y M6502_Y
+#define M6510T_S M6502_S
+#define M6510T_PC M6502_PC
+#define M6510T_P M6502_P
+#define M6510T_EA M6502_EA
+#define M6510T_ZP M6502_ZP
+#define M6510T_NMI_STATE M6502_NMI_STATE
+#define M6510T_IRQ_STATE M6502_IRQ_STATE
+
+#define M6510T_IRQ_LINE M6502_IRQ_LINE
+
+extern void m6510t_get_info(UINT32 state, cpuinfo *info);
+
+#endif
+
+#if (HAS_M7501)
+#define M7501_A M6502_A
+#define M7501_X M6502_X
+#define M7501_Y M6502_Y
+#define M7501_S M6502_S
+#define M7501_PC M6502_PC
+#define M7501_P M6502_P
+#define M7501_EA M6502_EA
+#define M7501_ZP M6502_ZP
+#define M7501_NMI_STATE M6502_NMI_STATE
+#define M7501_IRQ_STATE M6502_IRQ_STATE
+
+#define M7501_IRQ_LINE M6502_IRQ_LINE
+
+extern void m7501_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_M8502)
+#define M8502_A M6502_A
+#define M8502_X M6502_X
+#define M8502_Y M6502_Y
+#define M8502_S M6502_S
+#define M8502_PC M6502_PC
+#define M8502_P M6502_P
+#define M8502_EA M6502_EA
+#define M8502_ZP M6502_ZP
+#define M8502_NMI_STATE M6502_NMI_STATE
+#define M8502_IRQ_STATE M6502_IRQ_STATE
+
+#define M8502_IRQ_LINE M6502_IRQ_LINE
+
+extern void m8502_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+
+/****************************************************************************
+ * The 2A03 (NES 6502 without decimal mode ADC/SBC)
+ ****************************************************************************/
+#if (HAS_N2A03)
+#define N2A03_A M6502_A
+#define N2A03_X M6502_X
+#define N2A03_Y M6502_Y
+#define N2A03_S M6502_S
+#define N2A03_PC M6502_PC
+#define N2A03_P M6502_P
+#define N2A03_EA M6502_EA
+#define N2A03_ZP M6502_ZP
+#define N2A03_NMI_STATE M6502_NMI_STATE
+#define N2A03_IRQ_STATE M6502_IRQ_STATE
+
+#define N2A03_IRQ_LINE M6502_IRQ_LINE
+
+extern void n2a03_get_info(UINT32 state, cpuinfo *info);
+
+#define N2A03_DEFAULTCLOCK (21477272.724 / 12)
+
+/* The N2A03 is integrally tied to its PSG (they're on the same die).
+ Bit 7 of address $4011 (the PSG's DPCM control register), when set,
+ causes an IRQ to be generated. This function allows the IRQ to be called
+ from the PSG core when such an occasion arises. */
+extern void n2a03_irq(void);
+#endif
+
+
+/****************************************************************************
+ * The 65C02
+ ****************************************************************************/
+#if (HAS_M65C02)
+#define M65C02_A M6502_A
+#define M65C02_X M6502_X
+#define M65C02_Y M6502_Y
+#define M65C02_S M6502_S
+#define M65C02_PC M6502_PC
+#define M65C02_P M6502_P
+#define M65C02_EA M6502_EA
+#define M65C02_ZP M6502_ZP
+#define M65C02_NMI_STATE M6502_NMI_STATE
+#define M65C02_IRQ_STATE M6502_IRQ_STATE
+
+#define M65C02_IRQ_LINE M6502_IRQ_LINE
+
+extern void m65c02_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern unsigned m65c02_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif
+
+/****************************************************************************
+ * The 65SC02
+ ****************************************************************************/
+#if (HAS_M65SC02)
+#define M65SC02_A M6502_A
+#define M65SC02_X M6502_X
+#define M65SC02_Y M6502_Y
+#define M65SC02_S M6502_S
+#define M65SC02_PC M6502_PC
+#define M65SC02_P M6502_P
+#define M65SC02_EA M6502_EA
+#define M65SC02_ZP M6502_ZP
+#define M65SC02_NMI_STATE M6502_NMI_STATE
+#define M65SC02_IRQ_STATE M6502_IRQ_STATE
+
+#define M65SC02_IRQ_LINE M6502_IRQ_LINE
+
+extern void m65sc02_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern unsigned m65sc02_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+#endif
+
+/****************************************************************************
+ * The DECO CPU16
+ ****************************************************************************/
+#if (HAS_DECO16)
+#define DECO16_A M6502_A
+#define DECO16_X M6502_X
+#define DECO16_Y M6502_Y
+#define DECO16_S M6502_S
+#define DECO16_PC M6502_PC
+#define DECO16_P M6502_P
+#define DECO16_EA M6502_EA
+#define DECO16_ZP M6502_ZP
+#define DECO16_NMI_STATE M6502_NMI_STATE
+#define DECO16_IRQ_STATE M6502_IRQ_STATE
+
+#define DECO16_IRQ_LINE M6502_IRQ_LINE
+
+extern void deco16_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#ifdef MAME_DEBUG
+extern unsigned deco16_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _M6502_H */
+
diff --git a/src/emu/cpu/m6502/m6502.txt b/src/emu/cpu/m6502/m6502.txt
new file mode 100644
index 00000000000..c68e6964b55
--- /dev/null
+++ b/src/emu/cpu/m6502/m6502.txt
@@ -0,0 +1,163 @@
+mos metal oxid semiconductor
+bought by cbm
+
+licence to produce chips
+ rockwell
+
+transistor, logic gate designs:
+NMOS (M65xx)
+CMOS (M65Cxx)
+HMOS (M75xx) hyper? MOS, used in early c16/plus4 series
+H2MOS (M85xx) hyper2 MOS, used in C128, later c16/plus4, late C64
+?SCMOS (M65SCxx) Super? CMOS
+?CE (M65CExx, M45xx) CMOS Enhanced?, used in not released C65
+
+HMOS, H2MOS CPUs have the same core as the NMOS series
+
+6500 / 6501
+mask programable microcontroller
+32 io ports (2 interruptable)
+timer
+64 byte ram
+8 kbyte rom
+
+6502 (used in many designs)
+b-flag always 1! (only pushed as 0 when break executed!)
+memory changing opcodes accesses memory: read, write data, write modified data
+
+6504
+only 12 address pins a11..a0
+
+6508
+8 io pins (p0 bis p7)
+
+6509
+1 megabyte memory management
+(lda,sta (zeropage),y modified, uses 2nd address extension register)
+
+6510/8500 (used in some designs)
+6 io pins (p0 bis p5)
+
+6510T/8503? (used in commodore C1551 floppy)
+8 io pins
+integrated clock generation?
+
+7501/8501 (c16, c116, c232, c264, plus4, c364)
+7 io pins (no p5)
+no nmi
+
+8502 (c128)
+7 io pins (no p7)
+
+the above series is opcode compatible (including illegal opcodes)
+
+
+n2a03 (some arcades, NES)
+-------------------------
+(nintendo variant)
+NMOS based!
+illegal opcodes
+$6c jump indirect low byte overrun problem as in 6502
+no decimal mode
+integrated sound hardware
+
+
+65c02 (used in some designs)
+----------------------------
+fixed jmp ind opcode
+memory changing opcodes accesses memory: read, read, write
+no illegal opcodes from the above series
+so not full compatible to 6502 series
+b flag always 1 as in NMOS Series is not known?
+additional commands
+
+several other CMOS variants
+
+
+65sc02 (where used?)
+--------------------
+65c02 compatible
+additional commands
+
+atari lynx bastian schicks bll
+integrated m65sc02 cpu core
+no bbr bbs instructions, else m65c02 compatible
+
+watara supervision
+integrated m65c02 cpu core (or m65sc02 or m65ce02?)
+
+
+gte65816 (nintendo snes)
+------------------------
+65802 upgrade cpu (c64 and c128 upgrade cpu)
+16 bit wide registers
+24 bit address space
+65c02? compatible mode
+additional commands
+
+
+spc700
+------
+(snes sound processor)
+same register layout?
+same addressing modes?
+heavily modified opcodes
+YA could be combined for 16 bit operations?
+
+
+huc6280 (nec pcengine)
+----------------------
+65sc02 compatible?
+8 memory registers
+(highest 3 bits select memory register, these build a22..a13)
+(so 2 Megabyte address room!)
+additional commands?
+several additional integrated features
+
+
+65ce02 (c65 prototype)
+----------------------
+(scan of documentation available, also use
+c65 m4510 documentation)
+(cpu core to be used in asics)
+65sc02 compatible
+z register
+(65c02 zeropage indexed addressing is now (zeropage),z)
+b bank register, highbyte of all zerozape addressing
+register for stack high byte
+additional command (some from the 65816)
+
+
+m4510 (Commodore C65 CPU)
+-------------------------
+(scan of documentation (in c65 documentation) available)
+65ce02 compatible
+integrated 20 bit memory management (map)
+(aug opcode changed to map opcode)
+2 cia6526 integrated
+1 uart integrated
+
+
+mitsubishi 740 series
+---------------------
+(data book in electronic form available)
+(M507xx, M509xx, M374xx, M38xxx, M375xx)
+NMOS based
+additional operation mode
+(arithmetic instruction not performing on akku (a=a operation addressing mode)
+but on zeropage ([x]=[x] operation addressing mode))
+additional instructions LDM, MUL, DIV, TST, COM, RRF, CLT, SET, WIT, STP, CLP
+BRK 1 byte only?
+BRA CMOS compatible
+BBC, BBR different opcode as CMOS, and also akku addressing
+different TRB, TSB
+no CMOS STZ, JMP ind,x
+STP not in all variants
+MUL, DIV not in all variants
+
+
+Set Overflow Pin
+----------------
+in 6502 and pin compatibles (65C02 65SC02 65SC802 65CE02), M6509
+no SO pin 6510/7501/8500/8501/8502/65sc816
+6510T ?
diff --git a/src/emu/cpu/m6502/m6509.c b/src/emu/cpu/m6502/m6509.c
new file mode 100644
index 00000000000..49b66b9a006
--- /dev/null
+++ b/src/emu/cpu/m6502/m6509.c
@@ -0,0 +1,413 @@
+/*****************************************************************************
+ *
+ * m6509.c
+ * Portable 6509 emulator V1.0beta1
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ * documentation by vice emulator team
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+/*
+ 2000 March 10 PeT added SO input line
+
+The basic difference is the amount of RAM these machines have been supplied with. The B128 and the CBM *10
+models had 128k RAM, the others 256k. This implies some banking scheme, as the 6502 can only address 64k. And
+indeed those machines use a 6509, that can address 1 MByte of RAM. It has 2 registers at addresses 0 and 1. The
+indirect bank register at address 1 determines the bank (0-15) where the opcodes LDA (zp),Y and STA (zp),Y
+take the data from. The exec bank register at address 0 determines the bank where all other read and write
+addresses take place.
+
+ vice writes to bank register only with zeropage operand
+ 0, 1 are bank register in all banks
+
+ lda (zp),y
+ sta (zp),y
+
+*/
+
+#include "debugger.h"
+#include "m6509.h"
+
+#include "ops02.h"
+#include "ill02.h"
+#include "ops09.h"
+
+#define M6502_NMI_VEC 0xfffa
+#define M6502_RST_VEC 0xfffc
+#define M6502_IRQ_VEC 0xfffe
+#define M6509_RST_VEC M6502_RST_VEC
+#define M6509_IRQ_VEC M6502_IRQ_VEC
+#define M6509_NMI_VEC M6502_NMI_VEC
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+typedef struct {
+ UINT8 subtype; /* currently selected cpu sub type */
+ void (**insn)(void); /* pointer to the function pointer table */
+ PAIR ppc; /* previous program counter */
+ /* pc.w.h contains the current page pc_bank.w.h for better speed */
+ PAIR pc; /* program counter */
+ PAIR sp; /* stack pointer (always 100 - 1FF) */
+ PAIR zp; /* zero page address */
+ PAIR ea; /* effective address */
+ UINT8 a; /* Accumulator */
+ UINT8 x; /* X index register */
+ UINT8 y; /* Y index register */
+ PAIR pc_bank; /* 4 bits, addressed over address 0 */
+ PAIR ind_bank; /* 4 bits, addressed over address 1 */
+ UINT8 p; /* Processor status */
+ UINT8 pending_irq; /* nonzero if an IRQ is pending */
+ UINT8 after_cli; /* pending IRQ and last insn cleared I */
+ UINT8 nmi_state;
+ UINT8 irq_state;
+ UINT8 so_state;
+ int (*irq_callback)(int irqline); /* IRQ callback */
+ read8_handler rdmem_id; /* readmem callback for indexed instructions */
+ write8_handler wrmem_id; /* readmem callback for indexed instructions */
+} m6509_Regs;
+
+static int m6502_ICount = 0;
+
+static m6509_Regs m6509;
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+
+#include "t6509.c"
+
+static READ8_HANDLER( m6509_read_00000 )
+{
+ return m6509.pc_bank.b.h2;
+}
+
+static READ8_HANDLER( m6509_read_00001 )
+{
+ return m6509.ind_bank.b.h2;
+}
+
+static WRITE8_HANDLER( m6509_write_00000 )
+{
+ m6509.pc_bank.b.h2=data&0xf;
+ m6509.pc.w.h=m6509.pc_bank.w.h;
+ change_pc(PCD);
+}
+
+static WRITE8_HANDLER( m6509_write_00001 )
+{
+ m6509.ind_bank.b.h2=data&0xf;
+}
+
+static ADDRESS_MAP_START(m6509_mem, ADDRESS_SPACE_PROGRAM, 8)
+ AM_RANGE(0x00000, 0x00000) AM_MIRROR(0xF0000) AM_READWRITE(m6509_read_00000, m6509_write_00000)
+ AM_RANGE(0x00001, 0x00001) AM_MIRROR(0xF0000) AM_READWRITE(m6509_read_00001, m6509_write_00001)
+ADDRESS_MAP_END
+
+static void m6509_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m6509.rdmem_id = program_read_byte_8;
+ m6509.wrmem_id = program_write_byte_8;
+ m6509.irq_callback = irqcallback;
+}
+
+static void m6509_reset (void)
+{
+ m6509.insn = insn6509;
+
+ m6509.pc_bank.d=m6509.ind_bank.d=0;
+ m6509.pc_bank.b.h2=m6509.ind_bank.b.h2=0xf; /* cbm500 needs this */
+ m6509.pc.w.h=m6509.pc_bank.w.h;
+ /* wipe out the rest of the m6509 structure */
+ /* read the reset vector into PC */
+ PCL = RDMEM(M6509_RST_VEC|PB);
+ PCH = RDMEM((M6509_RST_VEC+1)|PB);
+
+ m6509.sp.d = 0x01ff;
+ m6509.p = F_T|F_B|F_I|F_Z|(P&F_D); /* set T, I and Z flags */
+ m6509.pending_irq = 0; /* nonzero if an IRQ is pending */
+ m6509.after_cli = 0; /* pending IRQ and last insn cleared I */
+ m6509.irq_callback = NULL;
+
+ change_pc(PCD);
+}
+
+static void m6509_exit(void)
+{
+ /* nothing to do yet */
+}
+
+static void m6509_get_context (void *dst)
+{
+ if( dst )
+ *(m6509_Regs*)dst = m6509;
+}
+
+static void m6509_set_context (void *src)
+{
+ if( src )
+ {
+ m6509 = *(m6509_Regs*)src;
+ change_pc(PCD);
+ }
+}
+
+
+
+INLINE void m6509_take_irq(void)
+{
+ if( !(P & F_I) )
+ {
+ EAD = M6509_IRQ_VEC;
+ EAWH = PBWH;
+ m6502_ICount -= 2;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P |= F_I; /* knock out D and set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG(("M6509#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
+ /* call back the cpuintrf to let it clear the line */
+ if (m6509.irq_callback) (*m6509.irq_callback)(0);
+ change_pc(PCD);
+ }
+ m6509.pending_irq = 0;
+}
+
+static int m6509_execute(int cycles)
+{
+ m6502_ICount = cycles;
+
+ change_pc(PCD);
+
+ do
+ {
+ UINT8 op;
+ PPC = PCD;
+
+ CALL_MAME_DEBUG;
+
+ /* if an irq is pending, take it now */
+ if( m6509.pending_irq )
+ m6509_take_irq();
+
+ op = RDOP();
+ (*m6509.insn[op])();
+
+ /* check if the I flag was just reset (interrupts enabled) */
+ if( m6509.after_cli )
+ {
+ LOG(("M6509#%d after_cli was >0", cpu_getactivecpu()));
+ m6509.after_cli = 0;
+ if (m6509.irq_state != CLEAR_LINE)
+ {
+ LOG((": irq line is asserted: set pending IRQ\n"));
+ m6509.pending_irq = 1;
+ }
+ else
+ {
+ LOG((": irq line is clear\n"));
+ }
+ }
+ else
+ if( m6509.pending_irq )
+ m6509_take_irq();
+
+ } while (m6502_ICount > 0);
+
+ return cycles - m6502_ICount;
+}
+
+static void m6509_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m6509.nmi_state == state) return;
+ m6509.nmi_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(( "M6509#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
+ EAD = M6509_NMI_VEC;
+ EAWH = PBWH;
+ m6502_ICount -= 2;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P |= F_I; /* knock out D and set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG(("M6509#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
+ change_pc(PCD);
+ }
+ }
+ else
+ {
+ if( irqline == M6509_SET_OVERFLOW )
+ {
+ if( m6509.so_state && !state )
+ {
+ LOG(( "M6509#%d set overflow\n", cpu_getactivecpu()));
+ P|=F_V;
+ }
+ m6509.so_state=state;
+ return;
+ }
+ m6509.irq_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(( "M6509#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
+ m6509.pending_irq = 1;
+ }
+ }
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void m6509_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M6509_IRQ_LINE: m6509_set_irq_line(M6509_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M6509_SET_OVERFLOW:m6509_set_irq_line(M6509_SET_OVERFLOW, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: m6509_set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC: PCW = info->i; change_pc(PCD); break;
+ case CPUINFO_INT_REGISTER + M6509_PC: m6509.pc.w.l = info->i; break;
+ case CPUINFO_INT_SP: S = info->i; break;
+ case CPUINFO_INT_REGISTER + M6509_S: m6509.sp.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M6509_P: m6509.p = info->i; break;
+ case CPUINFO_INT_REGISTER + M6509_A: m6509.a = info->i; break;
+ case CPUINFO_INT_REGISTER + M6509_X: m6509.x = info->i; break;
+ case CPUINFO_INT_REGISTER + M6509_Y: m6509.y = info->i; break;
+ case CPUINFO_INT_REGISTER + M6509_PC_BANK: m6509.pc_bank.b.h2 = info->i; break;
+ case CPUINFO_INT_REGISTER + M6509_IND_BANK: m6509.ind_bank.b.h2 = info->i; break;
+ case CPUINFO_INT_REGISTER + M6509_EA: m6509.ea.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M6509_ZP: m6509.zp.w.l = info->i; break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_M6502_READINDEXED_CALLBACK: m6509.rdmem_id = (read8_handler) info->f; break;
+ case CPUINFO_PTR_M6502_WRITEINDEXED_CALLBACK: m6509.wrmem_id = (write8_handler) info->f; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void m6509_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(m6502); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 10; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 20; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + M6509_IRQ_LINE: info->i = m6509.irq_state; break;
+ case CPUINFO_INT_INPUT_STATE + M6509_SET_OVERFLOW:info->i = m6509.so_state; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = m6509.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = m6509.ppc.w.l; break;
+
+ case CPUINFO_INT_PC: info->i = PCD; break;
+ case CPUINFO_INT_REGISTER + M6509_PC: info->i = m6509.pc.w.l; break;
+ case CPUINFO_INT_SP: info->i = S; break;
+ case CPUINFO_INT_REGISTER + M6509_S: info->i = m6509.sp.b.l; break;
+ case CPUINFO_INT_REGISTER + M6509_P: info->i = m6509.p; break;
+ case CPUINFO_INT_REGISTER + M6509_A: info->i = m6509.a; break;
+ case CPUINFO_INT_REGISTER + M6509_X: info->i = m6509.x; break;
+ case CPUINFO_INT_REGISTER + M6509_Y: info->i = m6509.y; break;
+ case CPUINFO_INT_REGISTER + M6509_PC_BANK: info->i = m6509.pc_bank.b.h2; break;
+ case CPUINFO_INT_REGISTER + M6509_IND_BANK: info->i = m6509.ind_bank.b.h2; break;
+ case CPUINFO_INT_REGISTER + M6509_EA: info->i = m6509.ea.w.l; break;
+ case CPUINFO_INT_REGISTER + M6509_ZP: info->i = m6509.zp.w.l; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m6509_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m6509_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m6509_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m6509_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m6509_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m6509_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m6509_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6502_dasm; break;
+#endif
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m6502_ICount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP: info->internal_map = construct_map_m6509_mem; break;
+ case CPUINFO_PTR_M6502_READINDEXED_CALLBACK: info->f = (genf *) m6509.rdmem_id; break;
+ case CPUINFO_PTR_M6502_WRITEINDEXED_CALLBACK: info->f = (genf *) m6509.wrmem_id; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6509"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "MOS Technology 6509"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0beta"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 1998 Juergen Buchmueller\nCopyright (c) 2000 Peter Trauner\nall rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ m6509.p & 0x80 ? 'N':'.',
+ m6509.p & 0x40 ? 'V':'.',
+ m6509.p & 0x20 ? 'R':'.',
+ m6509.p & 0x10 ? 'B':'.',
+ m6509.p & 0x08 ? 'D':'.',
+ m6509.p & 0x04 ? 'I':'.',
+ m6509.p & 0x02 ? 'Z':'.',
+ m6509.p & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M6509_PC: sprintf(info->s, "PC:%04X", m6509.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + M6509_S: sprintf(info->s, "S:%02X", m6509.sp.b.l); break;
+ case CPUINFO_STR_REGISTER + M6509_P: sprintf(info->s, "P:%02X", m6509.p); break;
+ case CPUINFO_STR_REGISTER + M6509_A: sprintf(info->s, "A:%02X", m6509.a); break;
+ case CPUINFO_STR_REGISTER + M6509_X: sprintf(info->s, "X:%02X", m6509.x); break;
+ case CPUINFO_STR_REGISTER + M6509_Y: sprintf(info->s, "Y:%02X", m6509.y); break;
+ case CPUINFO_STR_REGISTER + M6509_PC_BANK: sprintf(info->s, "M0:%01X", m6509.pc_bank.b.h2); break;
+ case CPUINFO_STR_REGISTER + M6509_IND_BANK: sprintf(info->s, "M1:%01X", m6509.ind_bank.b.h2); break;
+ case CPUINFO_STR_REGISTER + M6509_EA: sprintf(info->s, "EA:%04X", m6509.ea.w.l); break;
+ case CPUINFO_STR_REGISTER + M6509_ZP: sprintf(info->s, "ZP:%03X", m6509.zp.w.l); break;
+ }
+}
+
diff --git a/src/emu/cpu/m6502/m6509.h b/src/emu/cpu/m6502/m6509.h
new file mode 100644
index 00000000000..070e3ca3a96
--- /dev/null
+++ b/src/emu/cpu/m6502/m6509.h
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ *
+ * m6509.h
+ * Portable 6509 emulator V1.0beta
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#ifndef _M6509_H
+#define _M6509_H
+
+#include "m6502.h"
+
+enum {
+ M6509_PC=1, M6509_S, M6509_P, M6509_A, M6509_X, M6509_Y,
+ M6509_EA, M6509_ZP, M6509_NMI_STATE, M6509_IRQ_STATE, M6509_SO_STATE,
+ M6509_PC_BANK, M6509_IND_BANK
+};
+
+#define M6509_IRQ_LINE M6502_IRQ_LINE
+/* use cpunum_set_input_line(cpu, M6509_SET_OVERFLOW, level)
+ to change level of the so input line
+ positiv edge sets overflow flag */
+#define M6509_SET_OVERFLOW 3
+
+void m6509_get_info(UINT32 state, cpuinfo *info);
+
+#endif /* _M6509_H */
+
+
diff --git a/src/emu/cpu/m6502/m65ce02.c b/src/emu/cpu/m6502/m65ce02.c
new file mode 100644
index 00000000000..36d2b0c6928
--- /dev/null
+++ b/src/emu/cpu/m6502/m65ce02.c
@@ -0,0 +1,389 @@
+/*****************************************************************************
+ *
+ * m65ce02.c
+ * Portable 65ce02 emulator V1.0beta3
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved
+ * documentation preliminary databook
+ * documentation by michael steil mist@c64.org
+ * available at ftp://ftp.funet.fi/pub/cbm/c65
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+/* 4. February 2000 PeT fixed relative word operand */
+/* 4. February 2000 PeT jsr (absolut) jsr (absolut,x) inw dew */
+/* 17.February 2000 PeT phw */
+/* 16.March 2000 PeT fixed some instructions accordingly to databook */
+/* 7. May 2000 PeT splittet into m65ce02 and m4510 */
+
+/*
+
+* neg is now simple 2er komplement negation with set of N and Z
+
+* phw push low order byte, push high order byte!
+
+* tys txs not interruptable, not implemented
+
+*/
+
+#include "debugger.h"
+#include "m65ce02.h"
+
+#include "mincce02.h"
+#include "opsce02.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+/* Layout of the registers in the debugger */
+static UINT8 m65ce02_reg_layout[] = {
+ M65CE02_A,M65CE02_X,M65CE02_Y,M65CE02_Z,M65CE02_S,M65CE02_PC,
+ M65CE02_P,
+ -1,
+ M65CE02_EA,M65CE02_ZP,M65CE02_NMI_STATE,M65CE02_IRQ_STATE, M65CE02_B,
+ 0
+};
+
+/* Layout of the debugger windows x,y,w,h */
+static UINT8 m65ce02_win_layout[] = {
+ 25, 0,55, 2, /* register window (top, right rows) */
+ 0, 0,24,22, /* disassembler window (left colums) */
+ 25, 3,55, 9, /* memory #1 window (right, upper middle) */
+ 25,13,55, 9, /* memory #2 window (right, lower middle) */
+ 0,23,80, 1, /* command line window (bottom rows) */
+};
+
+typedef struct {
+ void (**insn)(void); /* pointer to the function pointer table */
+ PAIR ppc; /* previous program counter */
+ PAIR pc; /* program counter */
+ PAIR sp; /* stack pointer (always 100 - 1FF) */
+ PAIR zp; /* zero page address */
+ /* contains B register zp.b.h */
+ PAIR ea; /* effective address */
+ UINT8 a; /* Accumulator */
+ UINT8 x; /* X index register */
+ UINT8 y; /* Y index register */
+ UINT8 z; /* Z index register */
+ UINT8 p; /* Processor status */
+ UINT8 pending_irq; /* nonzero if an IRQ is pending */
+ UINT8 after_cli; /* pending IRQ and last insn cleared I */
+ UINT8 nmi_state;
+ UINT8 irq_state;
+ int (*irq_callback)(int irqline); /* IRQ callback */
+} m65ce02_Regs;
+
+
+int m65ce02_ICount = 0;
+
+static m65ce02_Regs m65ce02;
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+
+#include "t65ce02.c"
+
+void m65ce02_reset (void *param)
+{
+ m65ce02.insn = insn65ce02;
+
+ /* wipe out the rest of the m65ce02 structure */
+ /* read the reset vector into PC */
+ /* reset z index and b bank */
+ PCL = RDMEM(M65CE02_RST_VEC);
+ PCH = RDMEM(M65CE02_RST_VEC+1);
+
+ /* after reset in 6502 compatibility mode */
+ m65ce02.sp.d = 0x01ff; /* high byte descriped in databook */
+ m65ce02.z = 0;
+ B = 0;
+ m65ce02.p = F_E|F_B|F_I|F_Z; /* set E, I and Z flags */
+ m65ce02.pending_irq = 0; /* nonzero if an IRQ is pending */
+ m65ce02.after_cli = 0; /* pending IRQ and last insn cleared I */
+ m65ce02.irq_callback = NULL;
+
+ change_pc(PCD);
+}
+
+void m65ce02_exit(void)
+{
+ /* nothing to do yet */
+}
+
+unsigned m65ce02_get_context (void *dst)
+{
+ if( dst )
+ *(m65ce02_Regs*)dst = m65ce02;
+ return sizeof(m65ce02_Regs);
+}
+
+void m65ce02_set_context (void *src)
+{
+ if( src )
+ {
+ m65ce02 = *(m65ce02_Regs*)src;
+ change_pc(PCD);
+ }
+}
+
+unsigned m65ce02_get_reg (int regnum)
+{
+ switch( regnum )
+ {
+ case REG_PC: return PCD;
+ case M65CE02_PC: return m65ce02.pc.w.l;
+ case REG_SP: return S;
+ case M65CE02_S: return m65ce02.sp.w.l;
+ case M65CE02_P: return m65ce02.p;
+ case M65CE02_A: return m65ce02.a;
+ case M65CE02_X: return m65ce02.x;
+ case M65CE02_Y: return m65ce02.y;
+ case M65CE02_Z: return m65ce02.z;
+ case M65CE02_B: return m65ce02.zp.b.h;
+ case M65CE02_EA: return m65ce02.ea.w.l;
+ case M65CE02_ZP: return m65ce02.zp.b.l;
+ case M65CE02_NMI_STATE: return m65ce02.nmi_state;
+ case M65CE02_IRQ_STATE: return m65ce02.irq_state;
+ case REG_PREVIOUSPC: return m65ce02.ppc.w.l;
+ }
+ return 0;
+}
+
+void m65ce02_set_reg (int regnum, unsigned val)
+{
+ switch( regnum )
+ {
+ case REG_PC: PCW = val; change_pc(PCD); break;
+ case M65CE02_PC: m65ce02.pc.w.l = val; break;
+ case REG_SP: S = val; break;
+ case M65CE02_S: m65ce02.sp.w.l = val; break;
+ case M65CE02_P: m65ce02.p = val; break;
+ case M65CE02_A: m65ce02.a = val; break;
+ case M65CE02_X: m65ce02.x = val; break;
+ case M65CE02_Y: m65ce02.y = val; break;
+ case M65CE02_Z: m65ce02.z = val; break;
+ case M65CE02_B: m65ce02.zp.b.h = val; break;
+ case M65CE02_EA: m65ce02.ea.w.l = val; break;
+ case M65CE02_ZP: m65ce02.zp.b.l = val; break;
+ case M65CE02_NMI_STATE: m65ce02_set_irq_line( INPUT_LINE_NMI, val ); break;
+ case M65CE02_IRQ_STATE: m65ce02_set_irq_line( 0, val ); break;
+ }
+}
+
+INLINE void m65ce02_take_irq(void)
+{
+ if( !(P & F_I) )
+ {
+ EAD = M65CE02_IRQ_VEC;
+ m65ce02_ICount -= 7;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P = (P & ~F_D) | F_I; /* knock out D and set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG(("M65ce02#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
+ /* call back the cpuintrf to let it clear the line */
+ if (m65ce02.irq_callback) (*m65ce02.irq_callback)(0);
+ change_pc(PCD);
+ }
+ m65ce02.pending_irq = 0;
+}
+
+int m65ce02_execute(int cycles)
+{
+ m65ce02_ICount = cycles;
+
+ change_pc(PCD);
+
+ do
+ {
+ UINT8 op;
+ PPC = PCD;
+
+ CALL_MAME_DEBUG;
+
+ /* if an irq is pending, take it now */
+ if( m65ce02.pending_irq )
+ m65ce02_take_irq();
+
+ op = RDOP();
+ (*insn65ce02[op])();
+
+ /* check if the I flag was just reset (interrupts enabled) */
+ if( m65ce02.after_cli )
+ {
+ LOG(("M65ce02#%d after_cli was >0", cpu_getactivecpu()));
+ m65ce02.after_cli = 0;
+ if (m65ce02.irq_state != CLEAR_LINE)
+ {
+ LOG((": irq line is asserted: set pending IRQ\n"));
+ m65ce02.pending_irq = 1;
+ }
+ else
+ {
+ LOG((": irq line is clear\n"));
+ }
+ }
+ else
+ if( m65ce02.pending_irq )
+ m65ce02_take_irq();
+
+ } while (m65ce02_ICount > 0);
+
+ return cycles - m65ce02_ICount;
+}
+
+void m65ce02_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m65ce02.nmi_state == state) return;
+ m65ce02.nmi_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(("M65ce02#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
+ EAD = M65CE02_NMI_VEC;
+ m65ce02_ICount -= 7;
+ PUSH(PCH);
+ PUSH(PCL);
+ PUSH(P & ~F_B);
+ P = (P & ~F_D) | F_I; /* knock out D and set I flag */
+ PCL = RDMEM(EAD);
+ PCH = RDMEM(EAD+1);
+ LOG(("M65ce02#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
+ change_pc(PCD);
+ }
+ }
+ else
+ {
+ m65ce02.irq_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(("M65ce02#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
+ m65ce02.pending_irq = 1;
+ }
+ }
+}
+
+void m65ce02_set_irq_callback(int (*callback)(int))
+{
+ m65ce02.irq_callback = callback;
+}
+
+void m65ce02_state_save(void *file)
+{
+ int cpu = cpu_getactivecpu();
+ /* insn is set at restore since it's a pointer */
+ state_save_UINT16(file,"m65ce02",cpu,"PC",&m65ce02.pc.w.l,2);
+ state_save_UINT16(file,"m65ce02",cpu,"SP",&m65ce02.sp.w.l,2);
+ state_save_UINT8(file,"m65ce02",cpu,"P",&m65ce02.p,1);
+ state_save_UINT8(file,"m65ce02",cpu,"A",&m65ce02.a,1);
+ state_save_UINT8(file,"m65ce02",cpu,"X",&m65ce02.x,1);
+ state_save_UINT8(file,"m65ce02",cpu,"Y",&m65ce02.y,1);
+ state_save_UINT8(file,"m65ce02",cpu,"Z",&m65ce02.z,1);
+ state_save_UINT8(file,"m65ce02",cpu,"B",&m65ce02.zp.b.h,1);
+ state_save_UINT8(file,"m65ce02",cpu,"PENDING",&m65ce02.pending_irq,1);
+ state_save_UINT8(file,"m65ce02",cpu,"AFTER_CLI",&m65ce02.after_cli,1);
+ state_save_UINT8(file,"m65ce02",cpu,"NMI_STATE",&m65ce02.nmi_state,1);
+ state_save_UINT8(file,"m65ce02",cpu,"IRQ_STATE",&m65ce02.irq_state,1);
+}
+
+void m65ce02_state_load(void *file)
+{
+ int cpu = cpu_getactivecpu();
+ m65ce02.insn = insn65ce02;
+ state_load_UINT16(file,"m65ce02",cpu,"PC",&m65ce02.pc.w.l,2);
+ state_load_UINT16(file,"m65ce02",cpu,"SP",&m65ce02.sp.w.l,2);
+ state_load_UINT8(file,"m65ce02",cpu,"P",&m65ce02.p,1);
+ state_load_UINT8(file,"m65ce02",cpu,"A",&m65ce02.a,1);
+ state_load_UINT8(file,"m65ce02",cpu,"X",&m65ce02.x,1);
+ state_load_UINT8(file,"m65ce02",cpu,"Y",&m65ce02.y,1);
+ state_load_UINT8(file,"m65ce02",cpu,"Z",&m65ce02.z,1);
+ state_load_UINT8(file,"m65ce02",cpu,"B",&m65ce02.zp.b.h,1);
+ state_load_UINT8(file,"m65ce02",cpu,"PENDING",&m65ce02.pending_irq,1);
+ state_load_UINT8(file,"m65ce02",cpu,"AFTER_CLI",&m65ce02.after_cli,1);
+ state_load_UINT8(file,"m65ce02",cpu,"NMI_STATE",&m65ce02.nmi_state,1);
+ state_load_UINT8(file,"m65ce02",cpu,"IRQ_STATE",&m65ce02.irq_state,1);
+}
+
+/****************************************************************************
+ * Return a formatted string for a register
+ ****************************************************************************/
+const char *m65ce02_info(void *context, int regnum)
+{
+ char *buffer = cpuintrf_temp_str();
+ m65ce02_Regs *r = context;
+
+ if( !context )
+ r = &m65ce02;
+
+ switch( regnum )
+ {
+ case CPU_INFO_REG+M65CE02_PC: sprintf(buffer, "PC:%04X", r->pc.w.l); break;
+ case CPU_INFO_REG+M65CE02_S: sprintf(buffer, "S:%04X", r->sp.w.l); break;
+ case CPU_INFO_REG+M65CE02_P: sprintf(buffer, "P:%02X", r->p); break;
+ case CPU_INFO_REG+M65CE02_A: sprintf(buffer, "A:%02X", r->a); break;
+ case CPU_INFO_REG+M65CE02_X: sprintf(buffer, "X:%02X", r->x); break;
+ case CPU_INFO_REG+M65CE02_Y: sprintf(buffer, "Y:%02X", r->y); break;
+ case CPU_INFO_REG+M65CE02_Z: sprintf(buffer, "Z:%02X", r->z); break;
+ case CPU_INFO_REG+M65CE02_B: sprintf(buffer, "B:%02X", r->zp.b.h); break;
+ case CPU_INFO_REG+M65CE02_EA: sprintf(buffer, "EA:%04X", r->ea.w.l); break;
+ case CPU_INFO_REG+M65CE02_ZP: sprintf(buffer, "ZP:%04X", r->zp.w.l); break;
+ case CPU_INFO_REG+M65CE02_NMI_STATE: sprintf(buffer, "NMI:%X", r->nmi_state); break;
+ case CPU_INFO_REG+M65CE02_IRQ_STATE: sprintf(buffer, "IRQ:%X", r->irq_state); break;
+ case CPU_INFO_FLAGS:
+ sprintf(buffer, "%c%c%c%c%c%c%c%c",
+ r->p & 0x80 ? 'N':'.',
+ r->p & 0x40 ? 'V':'.',
+ r->p & 0x20 ? 'E':'.',
+ r->p & 0x10 ? 'B':'.',
+ r->p & 0x08 ? 'D':'.',
+ r->p & 0x04 ? 'I':'.',
+ r->p & 0x02 ? 'Z':'.',
+ r->p & 0x01 ? 'C':'.');
+ break;
+ case CPU_INFO_NAME: return "M65CE02";
+ case CPU_INFO_FAMILY: return "CBM Semiconductor Group CSG 65CE02";
+ case CPU_INFO_VERSION: return "1.0beta";
+ case CPU_INFO_CREDITS:
+ return "Copyright (c) 1998 Juergen Buchmueller\n"
+ "Copyright (c) 2000 Peter Trauner\n"
+ "all rights reserved.";
+ case CPU_INFO_FILE: return __FILE__;
+ case CPU_INFO_REG_LAYOUT: return (const char*)m65ce02_reg_layout;
+ case CPU_INFO_WIN_LAYOUT: return (const char*)m65ce02_win_layout;
+ }
+ return buffer;
+}
+
+unsigned int m65ce02_dasm(char *buffer, unsigned pc)
+{
+#ifdef MAME_DEBUG
+ return Dasm65ce02( buffer, pc );
+#else
+ sprintf( buffer, "$%02X", cpu_readop(pc) );
+ return 1;
+#endif
+}
+
+
+
diff --git a/src/emu/cpu/m6502/m65ce02.h b/src/emu/cpu/m6502/m65ce02.h
new file mode 100644
index 00000000000..8b2231b6d9d
--- /dev/null
+++ b/src/emu/cpu/m6502/m65ce02.h
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ *
+ * m65ce02.c
+ * Portable 65ce02 emulator V1.0beta
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#ifndef _M65CE02_H
+#define _M65CE02_H
+
+#include "m6502.h"
+
+enum {
+ M65CE02_PC=1, M65CE02_S, M65CE02_P, M65CE02_A, M65CE02_X, M65CE02_Y,
+ M65CE02_Z, M65CE02_B, M65CE02_EA, M65CE02_ZP,
+ M65CE02_NMI_STATE, M65CE02_IRQ_STATE
+};
+
+#define M65CE02_IRQ_LINE M6502_IRQ_LINE
+
+extern int m65ce02_ICount; /* cycle count */
+
+extern void m65ce02_reset(void *param);
+extern void m65ce02_exit(void);
+extern int m65ce02_execute(int cycles);
+extern unsigned m65ce02_get_context (void *dst);
+extern void m65ce02_set_context (void *src);
+extern unsigned m65ce02_get_reg (int regnum);
+extern void m65ce02_set_reg (int regnum, unsigned val);
+extern void m65ce02_set_irq_line(int irqline, int state);
+extern void m65ce02_set_irq_callback(int (*callback)(int irqline));
+extern void m65ce02_state_save(void *file);
+extern void m65ce02_state_load(void *file);
+extern const char *m65ce02_info(void *context, int regnum);
+extern unsigned m65ce02_dasm(char *buffer, unsigned pc);
+
+#ifdef MAME_DEBUG
+extern unsigned int Dasm65ce02( char *dst, unsigned pc );
+#endif
+
+#endif /* _M65CE02_H */
+
+
diff --git a/src/emu/cpu/m6502/minc4510.h b/src/emu/cpu/m6502/minc4510.h
new file mode 100644
index 00000000000..f71baa6f35b
--- /dev/null
+++ b/src/emu/cpu/m6502/minc4510.h
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ *
+ * minc4510.h
+ * Base macros for 4510 CPU files
+ *
+ *****************************************************************************/
+
+/* 4510 flags */
+#define F_C 0x01
+#define F_Z 0x02
+#define F_I 0x04
+#define F_D 0x08
+#define F_B 0x10
+#define F_E 0x20
+#define F_V 0x40
+#define F_N 0x80
+
+/* some shortcuts for improved readability */
+#define A m4510.a
+#define X m4510.x
+#define Y m4510.y
+#define P m4510.p
+#define Z m4510.z
+#define B m4510.zp.b.h
+#define SW m4510.sp.w.l
+#define SPL m4510.sp.b.l
+#define SPH m4510.sp.b.h
+#define SPD m4510.sp.d
+
+#define NZ m4510.nz
+
+#define EAL m4510.ea.b.l
+#define EAH m4510.ea.b.h
+#define EAW m4510.ea.w.l
+#define EAD m4510.ea.d
+
+#define ZPL m4510.zp.b.l
+#define ZPH m4510.zp.b.h
+#define ZPW m4510.zp.w.l
+#define ZPD m4510.zp.d
+
+#define PCL m4510.pc.b.l
+#define PCH m4510.pc.b.h
+#define PCW m4510.pc.w.l
+#define PCD m4510.pc.d
+
+#define PPC m4510.ppc.d
+
+#define IRQ_STATE m4510.irq_state
+#define AFTER_CLI m4510.after_cli
+
+#define M4510_MEM(addr) (m4510.mem[(addr)>>13]+(addr))
+
+#define CHANGE_PC change_pc(M4510_MEM(PCD))
+
+#define PEEK_OP() cpu_readop(M4510_MEM(PCD))
+
+#define RDMEM(addr) program_read_byte_8(addr); m4510_ICount -= 1
+#define WRMEM(addr,data) program_write_byte_8(addr,data); m4510_ICount -= 1
+
+/***************************************************************
+ * RDOP read an opcode
+ ***************************************************************/
+#undef RDOP
+#define RDOP() m4510_cpu_readop(); m4510_ICount -= 1
+
+/***************************************************************
+ * RDOPARG read an opcode argument
+ ***************************************************************/
+#undef RDOPARG
+#define RDOPARG() m4510_cpu_readop_arg(); m4510_ICount -= 1
+
diff --git a/src/emu/cpu/m6502/mincce02.h b/src/emu/cpu/m6502/mincce02.h
new file mode 100644
index 00000000000..40940b88478
--- /dev/null
+++ b/src/emu/cpu/m6502/mincce02.h
@@ -0,0 +1,71 @@
+/*****************************************************************************
+ *
+ * mincce02.h
+ * Base macros for 65ce02 CPU files
+ *
+ *****************************************************************************/
+
+/* 65ce02 flags */
+#define F_C 0x01
+#define F_Z 0x02
+#define F_I 0x04
+#define F_D 0x08
+#define F_B 0x10
+#define F_E 0x20
+#define F_V 0x40
+#define F_N 0x80
+
+/* some shortcuts for improved readability */
+#define A m65ce02.a
+#define X m65ce02.x
+#define Y m65ce02.y
+#define P m65ce02.p
+#define Z m65ce02.z
+#define B m65ce02.zp.b.h
+#define SW m65ce02.sp.w.l
+#define SPL m65ce02.sp.b.l
+#define SPH m65ce02.sp.b.h
+#define SPD m65ce02.sp.d
+
+#define NZ m65ce02.nz
+
+#define EAL m65ce02.ea.b.l
+#define EAH m65ce02.ea.b.h
+#define EAW m65ce02.ea.w.l
+#define EAD m65ce02.ea.d
+
+#define ZPL m65ce02.zp.b.l
+#define ZPH m65ce02.zp.b.h
+#define ZPW m65ce02.zp.w.l
+#define ZPD m65ce02.zp.d
+
+#define PCL m65ce02.pc.b.l
+#define PCH m65ce02.pc.b.h
+#define PCW m65ce02.pc.w.l
+#define PCD m65ce02.pc.d
+
+#define PPC m65ce02.ppc.d
+
+#define RDMEM_ID m65ce02.rdmem_id
+#define WRMEM_ID m65ce02.wrmem_id
+
+#define IRQ_STATE m65ce02.irq_state
+#define AFTER_CLI m65ce02.after_cli
+
+#define CHANGE_PC change_pc(PCD)
+
+/***************************************************************
+ * RDOP read an opcode
+ ***************************************************************/
+#define RDOP() cpu_readop(PCW++); m65ce02_ICount -= 1
+
+/***************************************************************
+ * RDOPARG read an opcode argument
+ ***************************************************************/
+#define RDOPARG() cpu_readop_arg(PCW++); m65ce02_ICount -= 1
+
+#define PEEK_OP() cpu_readop(PCW)
+
+#define RDMEM(addr) program_read_byte_8(addr); m65ce02_ICount -= 1
+#define WRMEM(addr,data) program_write_byte_8(addr,data); m65ce02_ICount -= 1
+
diff --git a/src/emu/cpu/m6502/ops02.h b/src/emu/cpu/m6502/ops02.h
new file mode 100644
index 00000000000..45006b1de3f
--- /dev/null
+++ b/src/emu/cpu/m6502/ops02.h
@@ -0,0 +1,803 @@
+/*****************************************************************************
+ *
+ * ops02.h
+ * Addressing mode and opcode macros for 6502,65c02,65sc02,6510,n2a03 CPUs
+ *
+ * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * 65sc02 core Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+/* 6502 flags */
+#define F_C 0x01
+#define F_Z 0x02
+#define F_I 0x04
+#define F_D 0x08
+#define F_B 0x10
+#define F_T 0x20
+#define F_V 0x40
+#define F_N 0x80
+
+/* some shortcuts for improved readability */
+#define A m6502.a
+#define X m6502.x
+#define Y m6502.y
+#define P m6502.p
+#define S m6502.sp.b.l
+#define SPD m6502.sp.d
+
+#define NZ m6502.nz
+
+#define SET_NZ(n) \
+ if ((n) == 0) P = (P & ~F_N) | F_Z; else P = (P & ~(F_N | F_Z)) | ((n) & F_N)
+
+#define SET_Z(n) \
+ if ((n) == 0) P |= F_Z; else P &= ~F_Z
+
+#define EAL m6502.ea.b.l
+#define EAH m6502.ea.b.h
+#define EAW m6502.ea.w.l
+#define EAD m6502.ea.d
+
+#define ZPL m6502.zp.b.l
+#define ZPH m6502.zp.b.h
+#define ZPW m6502.zp.w.l
+#define ZPD m6502.zp.d
+
+#define PCL m6502.pc.b.l
+#define PCH m6502.pc.b.h
+#define PCW m6502.pc.w.l
+#define PCD m6502.pc.d
+
+#define PPC m6502.ppc.d
+
+#define RDMEM_ID m6502.rdmem_id
+#define WRMEM_ID m6502.wrmem_id
+
+#define CHANGE_PC change_pc(PCD)
+
+/***************************************************************
+ * RDOP read an opcode
+ ***************************************************************/
+#define RDOP() cpu_readop(PCW++); m6502_ICount -= 1
+
+/***************************************************************
+ * RDOPARG read an opcode argument
+ ***************************************************************/
+#define RDOPARG() cpu_readop_arg(PCW++); m6502_ICount -= 1
+
+/***************************************************************
+ * RDMEM read memory
+ ***************************************************************/
+#define RDMEM(addr) program_read_byte_8(addr); m6502_ICount -= 1
+
+/***************************************************************
+ * WRMEM write memory
+ ***************************************************************/
+#define WRMEM(addr,data) program_write_byte_8(addr,data); m6502_ICount -= 1
+
+/***************************************************************
+ * BRA branch relative
+ * extra cycle if page boundary is crossed
+ ***************************************************************/
+#define BRA(cond) \
+ tmp = RDOPARG(); \
+ if (cond) \
+ { \
+ RDMEM(PCW); \
+ EAW = PCW + (signed char)tmp; \
+ if ( EAH != PCH ) { \
+ RDMEM( (PCH << 8 ) | EAL) ; \
+ } \
+ PCD = EAD; \
+ CHANGE_PC; \
+ }
+
+/***************************************************************
+ *
+ * Helper macros to build the effective address
+ *
+ ***************************************************************/
+
+/***************************************************************
+ * EA = zero page address
+ ***************************************************************/
+#define EA_ZPG \
+ ZPL = RDOPARG(); \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page address + X
+ ***************************************************************/
+#define EA_ZPX \
+ ZPL = RDOPARG(); \
+ RDMEM(ZPD); \
+ ZPL = X + ZPL; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page address + Y
+ ***************************************************************/
+#define EA_ZPY \
+ ZPL = RDOPARG(); \
+ RDMEM(ZPD); \
+ ZPL = Y + ZPL; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = absolute address
+ ***************************************************************/
+#define EA_ABS \
+ EAL = RDOPARG(); \
+ EAH = RDOPARG()
+
+/***************************************************************
+ * EA = absolute address + X
+ * one additional read if page boundary is crossed
+ ***************************************************************/
+#define EA_ABX_P \
+ EA_ABS; \
+ if ( EAL + X > 0xff ) { \
+ RDMEM( ( EAH << 8 ) | ( ( EAL + X ) & 0xff ) ); \
+ } \
+ EAW += X;
+
+/***************************************************************
+ * EA = absolute address + X
+ ***************************************************************/
+#define EA_ABX_NP \
+ EA_ABS; \
+ RDMEM( ( EAH << 8 ) | ( ( EAL + X ) & 0xff ) ); \
+ EAW += X
+
+/***************************************************************
+ * EA = absolute address + Y
+ * one additional read if page boundary is crossed
+ ***************************************************************/
+#define EA_ABY_P \
+ EA_ABS; \
+ if ( EAL + Y > 0xff ) { \
+ RDMEM( ( EAH << 8 ) | ( ( EAL + Y ) & 0xff ) ); \
+ } \
+ EAW += Y;
+
+/***************************************************************
+ * EA = absolute address + Y
+ ***************************************************************/
+#define EA_ABY_NP \
+ EA_ABS; \
+ RDMEM( ( EAH << 8 ) | ( ( EAL + Y ) & 0xff ) ); \
+ EAW += Y
+
+/***************************************************************
+ * EA = zero page + X indirect (pre indexed)
+ ***************************************************************/
+#define EA_IDX \
+ ZPL = RDOPARG(); \
+ RDMEM(ZPD); \
+ ZPL = ZPL + X; \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD)
+
+/***************************************************************
+ * EA = zero page indirect + Y (post indexed)
+ * subtract 1 cycle if page boundary is crossed
+ ***************************************************************/
+#define EA_IDY_P \
+ ZPL = RDOPARG(); \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD); \
+ if (EAL + Y > 0xff) { \
+ RDMEM( ( EAH << 8 ) | ( ( EAL + Y ) & 0xff ) ); \
+ } \
+ EAW += Y;
+
+/***************************************************************
+ * EA = zero page indirect + Y
+ ***************************************************************/
+#define EA_IDY_NP \
+ ZPL = RDOPARG(); \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD); \
+ RDMEM( ( EAH << 8 ) | ( ( EAL + Y ) & 0xff ) ); \
+ EAW += Y
+
+/***************************************************************
+ * EA = zero page indirect (65c02 pre indexed w/o X)
+ ***************************************************************/
+#define EA_ZPI \
+ ZPL = RDOPARG(); \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD)
+
+/***************************************************************
+ * EA = indirect (only used by JMP)
+ ***************************************************************/
+#define EA_IND \
+ EA_ABS; \
+ tmp = RDMEM(EAD); \
+ EAL++; /* booby trap: stay in same page! ;-) */ \
+ EAH = RDMEM(EAD); \
+ EAL = tmp
+
+
+/* read a value into tmp */
+/* Base number of cycles taken for each mode (including reading of opcode):
+ RD_IMM 2
+ RD_DUM 2
+ RD_ACC 0
+ RD_ZPG/WR_ZPG 3
+ RD_ZPX/WR_ZPX 4
+ RD_ZPY/WR_ZPY 4
+ RD_ABS/WR_ABS 4
+ RD_ABX_P 4/5
+ RD_ABX_NP/WR_ABX_NP 5
+ RD_ABY_P 4/5
+ RD_ABY_NP/WR_ABY_NP 5
+ RD_IDX/WR_IDX 6
+ RD_IDY_P 5/6
+ RD_IDY_NP/WR_IDY_NP 6
+ RD_ZPI/WR_ZPI 5
+ */
+#define RD_IMM tmp = RDOPARG()
+#define RD_DUM RDMEM(PCW)
+#define RD_ACC tmp = A
+#define RD_ZPG EA_ZPG; tmp = RDMEM(EAD)
+#define RD_ZPX EA_ZPX; tmp = RDMEM(EAD)
+#define RD_ZPY EA_ZPY; tmp = RDMEM(EAD)
+#define RD_ABS EA_ABS; tmp = RDMEM(EAD)
+#define RD_ABX_P EA_ABX_P; tmp = RDMEM(EAD)
+#define RD_ABX_NP EA_ABX_NP; tmp = RDMEM(EAD)
+#define RD_ABY_P EA_ABY_P; tmp = RDMEM(EAD)
+#define RD_ABY_NP EA_ABY_NP; tmp = RDMEM(EAD)
+#define RD_IDX EA_IDX; tmp = RDMEM_ID(EAD); m6502_ICount -= 1
+#define RD_IDY_P EA_IDY_P; tmp = RDMEM_ID(EAD); m6502_ICount -= 1
+#define RD_IDY_NP EA_IDY_NP; tmp = RDMEM_ID(EAD); m6502_ICount -= 1
+#define RD_ZPI EA_ZPI; tmp = RDMEM(EAD)
+
+/* write a value from tmp */
+#define WR_ZPG EA_ZPG; WRMEM(EAD, tmp)
+#define WR_ZPX EA_ZPX; WRMEM(EAD, tmp)
+#define WR_ZPY EA_ZPY; WRMEM(EAD, tmp)
+#define WR_ABS EA_ABS; WRMEM(EAD, tmp)
+#define WR_ABX_NP EA_ABX_NP; WRMEM(EAD, tmp)
+#define WR_ABY_NP EA_ABY_NP; WRMEM(EAD, tmp)
+#define WR_IDX EA_IDX; WRMEM_ID(EAD, tmp); m6502_ICount -= 1
+#define WR_IDY_NP EA_IDY_NP; WRMEM_ID(EAD, tmp); m6502_ICount -= 1
+#define WR_ZPI EA_ZPI; WRMEM(EAD, tmp)
+
+/* dummy read from the last EA */
+#define RD_EA RDMEM(EAD)
+
+/* write back a value from tmp to the last EA */
+#define WB_ACC A = (UINT8)tmp;
+#define WB_EA WRMEM(EAD, tmp)
+
+/***************************************************************
+ ***************************************************************
+ * Macros to emulate the plain 6502 opcodes
+ ***************************************************************
+ ***************************************************************/
+
+/***************************************************************
+ * push a register onto the stack
+ ***************************************************************/
+#define PUSH(Rg) WRMEM(SPD, Rg); S--
+
+/***************************************************************
+ * pull a register from the stack
+ ***************************************************************/
+#define PULL(Rg) S++; Rg = RDMEM(SPD)
+
+/* 6502 ********************************************************
+ * ADC Add with carry
+ ***************************************************************/
+#define ADC \
+ if (P & F_D) { \
+ int c = (P & F_C); \
+ int lo = (A & 0x0f) + (tmp & 0x0f) + c; \
+ int hi = (A & 0xf0) + (tmp & 0xf0); \
+ P &= ~(F_V | F_C|F_N|F_Z); \
+ if (!((lo+hi)&0xff)) P|=F_Z; \
+ if (lo > 0x09) { \
+ hi += 0x10; \
+ lo += 0x06; \
+ } \
+ if (hi&0x80) P|=F_N; \
+ if (~(A^tmp) & (A^hi) & F_N) \
+ P |= F_V; \
+ if (hi > 0x90) \
+ hi += 0x60; \
+ if (hi & 0xff00) \
+ P |= F_C; \
+ A = (lo & 0x0f) + (hi & 0xf0); \
+ } else { \
+ int c = (P & F_C); \
+ int sum = A + tmp + c; \
+ P &= ~(F_V | F_C); \
+ if (~(A^tmp) & (A^sum) & F_N) \
+ P |= F_V; \
+ if (sum & 0xff00) \
+ P |= F_C; \
+ A = (UINT8) sum; \
+ SET_NZ(A); \
+ }
+
+/* 6502 ********************************************************
+ * AND Logical and
+ ***************************************************************/
+#define AND \
+ A = (UINT8)(A & tmp); \
+ SET_NZ(A)
+
+/* 6502 ********************************************************
+ * ASL Arithmetic shift left
+ ***************************************************************/
+#define ASL \
+ P = (P & ~F_C) | ((tmp >> 7) & F_C); \
+ tmp = (UINT8)(tmp << 1); \
+ SET_NZ(tmp)
+
+/* 6502 ********************************************************
+ * BCC Branch if carry clear
+ ***************************************************************/
+#define BCC BRA(!(P & F_C))
+
+/* 6502 ********************************************************
+ * BCS Branch if carry set
+ ***************************************************************/
+#define BCS BRA(P & F_C)
+
+/* 6502 ********************************************************
+ * BEQ Branch if equal
+ ***************************************************************/
+#define BEQ BRA(P & F_Z)
+
+/* 6502 ********************************************************
+ * BIT Bit test
+ ***************************************************************/
+#undef BIT
+#define BIT \
+ P &= ~(F_N|F_V|F_Z); \
+ P |= tmp & (F_N|F_V); \
+ if ((tmp & A) == 0) \
+ P |= F_Z
+
+/* 6502 ********************************************************
+ * BMI Branch if minus
+ ***************************************************************/
+#define BMI BRA(P & F_N)
+
+/* 6502 ********************************************************
+ * BNE Branch if not equal
+ ***************************************************************/
+#define BNE BRA(!(P & F_Z))
+
+/* 6502 ********************************************************
+ * BPL Branch if plus
+ ***************************************************************/
+#define BPL BRA(!(P & F_N))
+
+/* 6502 ********************************************************
+ * BRK Break
+ * increment PC, push PC hi, PC lo, flags (with B bit set),
+ * set I flag, jump via IRQ vector
+ ***************************************************************/
+#define BRK \
+ RDOPARG(); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ PUSH(P | F_B); \
+ P = (P | F_I); \
+ PCL = RDMEM(M6502_IRQ_VEC); \
+ PCH = RDMEM(M6502_IRQ_VEC+1); \
+ CHANGE_PC
+
+/* 6502 ********************************************************
+ * BVC Branch if overflow clear
+ ***************************************************************/
+#define BVC BRA(!(P & F_V))
+
+/* 6502 ********************************************************
+ * BVS Branch if overflow set
+ ***************************************************************/
+#define BVS BRA(P & F_V)
+
+/* 6502 ********************************************************
+ * CLC Clear carry flag
+ ***************************************************************/
+#define CLC \
+ P &= ~F_C
+
+/* 6502 ********************************************************
+ * CLD Clear decimal flag
+ ***************************************************************/
+#define CLD \
+ P &= ~F_D
+
+/* 6502 ********************************************************
+ * CLI Clear interrupt flag
+ ***************************************************************/
+#define CLI \
+ if ((m6502.irq_state != CLEAR_LINE) && (P & F_I)) { \
+ m6502.after_cli = 1; \
+ } \
+ P &= ~F_I
+
+/* 6502 ********************************************************
+ * CLV Clear overflow flag
+ ***************************************************************/
+#define CLV \
+ P &= ~F_V
+
+/* 6502 ********************************************************
+ * CMP Compare accumulator
+ ***************************************************************/
+#define CMP \
+ P &= ~F_C; \
+ if (A >= tmp) \
+ P |= F_C; \
+ SET_NZ((UINT8)(A - tmp))
+
+/* 6502 ********************************************************
+ * CPX Compare index X
+ ***************************************************************/
+#define CPX \
+ P &= ~F_C; \
+ if (X >= tmp) \
+ P |= F_C; \
+ SET_NZ((UINT8)(X - tmp))
+
+/* 6502 ********************************************************
+ * CPY Compare index Y
+ ***************************************************************/
+#define CPY \
+ P &= ~F_C; \
+ if (Y >= tmp) \
+ P |= F_C; \
+ SET_NZ((UINT8)(Y - tmp))
+
+/* 6502 ********************************************************
+ * DEC Decrement memory
+ ***************************************************************/
+#define DEC \
+ tmp = (UINT8)(tmp-1); \
+ SET_NZ(tmp)
+
+/* 6502 ********************************************************
+ * DEX Decrement index X
+ ***************************************************************/
+#define DEX \
+ X = (UINT8)(X-1); \
+ SET_NZ(X)
+
+/* 6502 ********************************************************
+ * DEY Decrement index Y
+ ***************************************************************/
+#define DEY \
+ Y = (UINT8)(Y-1); \
+ SET_NZ(Y)
+
+/* 6502 ********************************************************
+ * EOR Logical exclusive or
+ ***************************************************************/
+#define EOR \
+ A = (UINT8)(A ^ tmp); \
+ SET_NZ(A)
+
+/* 6502 ********************************************************
+ * ILL Illegal opcode
+ ***************************************************************/
+#define ILL \
+ logerror("M6502 illegal opcode %04x: %02x\n",(PCW-1)&0xffff, cpu_readop((PCW-1)&0xffff))
+
+/* 6502 ********************************************************
+ * INC Increment memory
+ ***************************************************************/
+#define INC \
+ tmp = (UINT8)(tmp+1); \
+ SET_NZ(tmp)
+
+/* 6502 ********************************************************
+ * INX Increment index X
+ ***************************************************************/
+#define INX \
+ X = (UINT8)(X+1); \
+ SET_NZ(X)
+
+/* 6502 ********************************************************
+ * INY Increment index Y
+ ***************************************************************/
+#define INY \
+ Y = (UINT8)(Y+1); \
+ SET_NZ(Y)
+
+/* 6502 ********************************************************
+ * JMP Jump to address
+ * set PC to the effective address
+ ***************************************************************/
+#define JMP \
+ if( EAD == PPC && !m6502.pending_irq && !m6502.after_cli ) \
+ if( m6502_ICount > 0 ) m6502_ICount = 0; \
+ PCD = EAD; \
+ CHANGE_PC
+
+/* 6502 ********************************************************
+ * JSR Jump to subroutine
+ * decrement PC (sic!) push PC hi, push PC lo and set
+ * PC to the effective address
+ ***************************************************************/
+#define JSR \
+ EAL = RDOPARG(); \
+ RDMEM(SPD); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ EAH = RDOPARG(); \
+ PCD = EAD; \
+ CHANGE_PC
+
+/* 6502 ********************************************************
+ * LDA Load accumulator
+ ***************************************************************/
+#define LDA \
+ A = (UINT8)tmp; \
+ SET_NZ(A)
+
+/* 6502 ********************************************************
+ * LDX Load index X
+ ***************************************************************/
+#define LDX \
+ X = (UINT8)tmp; \
+ SET_NZ(X)
+
+/* 6502 ********************************************************
+ * LDY Load index Y
+ ***************************************************************/
+#define LDY \
+ Y = (UINT8)tmp; \
+ SET_NZ(Y)
+
+/* 6502 ********************************************************
+ * LSR Logic shift right
+ * 0 -> [7][6][5][4][3][2][1][0] -> C
+ ***************************************************************/
+#define LSR \
+ P = (P & ~F_C) | (tmp & F_C); \
+ tmp = (UINT8)tmp >> 1; \
+ SET_NZ(tmp)
+
+/* 6502 ********************************************************
+ * NOP No operation
+ ***************************************************************/
+#define NOP
+
+/* 6502 ********************************************************
+ * ORA Logical inclusive or
+ ***************************************************************/
+#define ORA \
+ A = (UINT8)(A | tmp); \
+ SET_NZ(A)
+
+/* 6502 ********************************************************
+ * PHA Push accumulator
+ ***************************************************************/
+#define PHA \
+ PUSH(A)
+
+/* 6502 ********************************************************
+ * PHP Push processor status (flags)
+ ***************************************************************/
+#define PHP \
+ PUSH(P)
+
+/* 6502 ********************************************************
+ * PLA Pull accumulator
+ ***************************************************************/
+#define PLA \
+ RDMEM(SPD); \
+ PULL(A); \
+ SET_NZ(A)
+
+
+/* 6502 ********************************************************
+ * PLP Pull processor status (flags)
+ ***************************************************************/
+#define PLP \
+ RDMEM(SPD); \
+ if ( P & F_I ) { \
+ PULL(P); \
+ if ((m6502.irq_state != CLEAR_LINE) && !(P & F_I)) { \
+ LOG(("M6502#%d PLP sets after_cli\n",cpu_getactivecpu())); \
+ m6502.after_cli = 1; \
+ } \
+ } else { \
+ PULL(P); \
+ } \
+ P |= (F_T|F_B);
+
+/* 6502 ********************************************************
+ * ROL Rotate left
+ * new C <- [7][6][5][4][3][2][1][0] <- C
+ ***************************************************************/
+#define ROL \
+ tmp = (tmp << 1) | (P & F_C); \
+ P = (P & ~F_C) | ((tmp >> 8) & F_C); \
+ tmp = (UINT8)tmp; \
+ SET_NZ(tmp)
+
+/* 6502 ********************************************************
+ * ROR Rotate right
+ * C -> [7][6][5][4][3][2][1][0] -> new C
+ ***************************************************************/
+#define ROR \
+ tmp |= (P & F_C) << 8; \
+ P = (P & ~F_C) | (tmp & F_C); \
+ tmp = (UINT8)(tmp >> 1); \
+ SET_NZ(tmp)
+
+/* 6502 ********************************************************
+ * RTI Return from interrupt
+ * pull flags, pull PC lo, pull PC hi and increment PC
+ * PCW++;
+ ***************************************************************/
+#define RTI \
+ RDOPARG(); \
+ RDMEM(SPD); \
+ PULL(P); \
+ PULL(PCL); \
+ PULL(PCH); \
+ P |= F_T | F_B; \
+ if( (m6502.irq_state != CLEAR_LINE) && !(P & F_I) ) \
+ { \
+ LOG(("M6502#%d RTI sets after_cli\n",cpu_getactivecpu())); \
+ m6502.after_cli = 1; \
+ } \
+ CHANGE_PC
+
+/* 6502 ********************************************************
+ * RTS Return from subroutine
+ * pull PC lo, PC hi and increment PC
+ ***************************************************************/
+#define RTS \
+ RDOPARG(); \
+ RDMEM(SPD); \
+ PULL(PCL); \
+ PULL(PCH); \
+ RDMEM(PCW); PCW++; \
+ CHANGE_PC
+
+/* 6502 ********************************************************
+ * SBC Subtract with carry
+ ***************************************************************/
+#define SBC \
+ if (P & F_D) \
+ { \
+ int c = (P & F_C) ^ F_C; \
+ int sum = A - tmp - c; \
+ int lo = (A & 0x0f) - (tmp & 0x0f) - c; \
+ int hi = (A & 0xf0) - (tmp & 0xf0); \
+ if (lo & 0x10) \
+ { \
+ lo -= 6; \
+ hi--; \
+ } \
+ P &= ~(F_V | F_C|F_Z|F_N); \
+ if( (A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( hi & 0x0100 ) \
+ hi -= 0x60; \
+ if( (sum & 0xff00) == 0 ) \
+ P |= F_C; \
+ if( !((A-tmp-c) & 0xff) ) \
+ P |= F_Z; \
+ if( (A-tmp-c) & 0x80 ) \
+ P |= F_N; \
+ A = (lo & 0x0f) | (hi & 0xf0); \
+ } \
+ else \
+ { \
+ int c = (P & F_C) ^ F_C; \
+ int sum = A - tmp - c; \
+ P &= ~(F_V | F_C); \
+ if( (A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( (sum & 0xff00) == 0 ) \
+ P |= F_C; \
+ A = (UINT8) sum; \
+ SET_NZ(A); \
+ }
+
+/* 6502 ********************************************************
+ * SEC Set carry flag
+ ***************************************************************/
+#define SEC \
+ P |= F_C
+
+/* 6502 ********************************************************
+ * SED Set decimal flag
+ ***************************************************************/
+#define SED \
+ P |= F_D
+
+/* 6502 ********************************************************
+ * SEI Set interrupt flag
+ ***************************************************************/
+#define SEI \
+ P |= F_I
+
+/* 6502 ********************************************************
+ * STA Store accumulator
+ ***************************************************************/
+#define STA \
+ tmp = A
+
+/* 6502 ********************************************************
+ * STX Store index X
+ ***************************************************************/
+#define STX \
+ tmp = X
+
+/* 6502 ********************************************************
+ * STY Store index Y
+ ***************************************************************/
+#define STY \
+ tmp = Y
+
+/* 6502 ********************************************************
+ * TAX Transfer accumulator to index X
+ ***************************************************************/
+#define TAX \
+ X = A; \
+ SET_NZ(X)
+
+/* 6502 ********************************************************
+ * TAY Transfer accumulator to index Y
+ ***************************************************************/
+#define TAY \
+ Y = A; \
+ SET_NZ(Y)
+
+/* 6502 ********************************************************
+ * TSX Transfer stack LSB to index X
+ ***************************************************************/
+#define TSX \
+ X = S; \
+ SET_NZ(X)
+
+/* 6502 ********************************************************
+ * TXA Transfer index X to accumulator
+ ***************************************************************/
+#define TXA \
+ A = X; \
+ SET_NZ(A)
+
+/* 6502 ********************************************************
+ * TXS Transfer index X to stack LSB
+ * no flags changed (sic!)
+ ***************************************************************/
+#define TXS \
+ S = X
+
+/* 6502 ********************************************************
+ * TYA Transfer index Y to accumulator
+ ***************************************************************/
+#define TYA \
+ A = Y; \
+ SET_NZ(A)
+
diff --git a/src/emu/cpu/m6502/ops09.h b/src/emu/cpu/m6502/ops09.h
new file mode 100644
index 00000000000..5175c12e940
--- /dev/null
+++ b/src/emu/cpu/m6502/ops09.h
@@ -0,0 +1,217 @@
+/*****************************************************************************
+ *
+ * ops09.h
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ * documentation by michael steil mist@c64.org
+ * available at ftp://ftp.funet.fi/pub/cbm/c65
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#define m6502 m6509
+#define m6502_ICount m6509_ICount
+
+#define ZPWH m6509.zp.w.h
+
+#define EAWH m6509.ea.w.h
+
+#define PBWH m6509.pc_bank.w.h
+#define PB m6509.pc_bank.d
+
+#define IBWH m6509.ind_bank.w.h
+#define IB m6509.ind_bank.d
+
+#undef CHANGE_PC
+#define CHANGE_PC change_pc(PCD|PB)
+
+/***************************************************************
+ * RDOP read an opcode
+ ***************************************************************/
+#undef RDOP
+#define RDOP() cpu_readop((PCW++)|PB); m6502_ICount -= 1
+
+/***************************************************************
+ * RDOPARG read an opcode argument
+ ***************************************************************/
+#undef RDOPARG
+#define RDOPARG() cpu_readop_arg((PCW++)|PB); m6502_ICount -= 1
+
+/***************************************************************
+ * RDMEM read memory
+ ***************************************************************/
+#undef RDMEM
+#define RDMEM(addr) program_read_byte_8(addr); m6502_ICount -= 1
+
+/***************************************************************
+ * WRMEM write memory
+ ***************************************************************/
+#undef WRMEM
+#define WRMEM(addr,data) program_write_byte_8(addr,data); m6502_ICount -= 1
+
+/***************************************************************
+ * push a register onto the stack
+ ***************************************************************/
+#undef PUSH
+#define PUSH(Rg) WRMEM(SPD|PB, Rg); S--
+
+/***************************************************************
+ * pull a register from the stack
+ ***************************************************************/
+#undef PULL
+#define PULL(Rg) S++; Rg = RDMEM(SPD|PB)
+
+
+/***************************************************************
+ * EA = zero page address
+ ***************************************************************/
+#undef EA_ZPG
+#define EA_ZPG \
+ ZPL = RDOPARG(); \
+ ZPWH = PBWH; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page address + X
+ ***************************************************************/
+#undef EA_ZPX
+#define EA_ZPX \
+ ZPL = X + RDOPARG(); \
+ ZPWH = PBWH; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page address + Y
+ ***************************************************************/
+#undef EA_ZPY
+#define EA_ZPY \
+ ZPL = Y + RDOPARG(); \
+ ZPWH = PBWH; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = absolute address
+ ***************************************************************/
+#undef EA_ABS
+#define EA_ABS \
+ EAL = RDOPARG(); \
+ EAH = RDOPARG(); \
+ EAWH = PBWH
+
+/***************************************************************
+ * EA = zero page + X indirect (pre indexed)
+ ***************************************************************/
+#undef EA_IDX
+#define EA_IDX \
+ ZPL = X + RDOPARG(); \
+ ZPWH=PBWH; \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD); \
+ EAWH = PBWH
+
+/***************************************************************
+ * EA = zero page indirect + Y (post indexed)
+ * subtract 1 cycle if page boundary is crossed
+ ***************************************************************/
+#undef EA_IDY
+#define EA_IDY \
+ ZPL = RDOPARG(); \
+ ZPWH = PBWH; \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD); \
+ EAWH = PBWH; \
+ if (EAL + Y > 0xff) \
+ m6509_ICount--; \
+ EAW += Y
+
+
+/***************************************************************
+ * EA = zero page indirect + Y (post indexed)
+ * subtract 1 cycle if page boundary is crossed
+ ***************************************************************/
+#define EA_IDY_6509 \
+ ZPL = RDOPARG(); \
+ ZPWH = PBWH; \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD); \
+ EAWH = IBWH; \
+ if (EAL + Y > 0xff) \
+ m6509_ICount--; \
+ EAW += Y
+
+/***************************************************************
+ * EA = indirect (only used by JMP)
+ ***************************************************************/
+#undef EA_IND
+#define EA_IND \
+ EA_ABS; \
+ tmp = RDMEM(EAD); \
+ EAL++; /* booby trap: stay in same page! ;-) */ \
+ EAH = RDMEM(EAD); \
+ EAL = tmp;
+/* EAWH = PBWH */
+
+#define RD_IDY_6509 EA_IDY_6509; tmp = RDMEM(EAD)
+#define WR_IDY_6509 EA_IDY_6509; WRMEM(EAD, tmp)
+
+/***************************************************************
+ * BRA branch relative
+ * extra cycle if page boundary is crossed
+ ***************************************************************/
+#undef BRA
+#define BRA(cond) \
+ if (cond) \
+ { \
+ tmp = RDOPARG(); \
+ EAW = PCW + (signed char)tmp; \
+ m6509_ICount -= (PCH == EAH) ? 1 : 2; \
+ PCD = EAD|PB; \
+ CHANGE_PC; \
+ } \
+ else \
+ { \
+ PCW++; \
+ m6509_ICount -= 1; \
+ }
+
+/* 6502 ********************************************************
+ * JSR Jump to subroutine
+ * decrement PC (sic!) push PC hi, push PC lo and set
+ * PC to the effective address
+ ***************************************************************/
+#undef JSR
+#define JSR \
+ EAL = RDOPARG(); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ EAH = RDOPARG(); \
+ EAWH = PBWH; \
+ PCD = EAD; \
+ CHANGE_PC
+
+/* 6510 ********************************************************
+ * KIL Illegal opcode
+ * processor haltet, no hardware interrupt will help
+ * only reset
+ ***************************************************************/
+#undef KIL
+#define KIL \
+ PCW--; \
+ logerror("M6509 KILL opcode %05x: %02x\n", PCD, cpu_readop(PCD))
+
+
+
diff --git a/src/emu/cpu/m6502/ops4510.h b/src/emu/cpu/m6502/ops4510.h
new file mode 100644
index 00000000000..749dcd49094
--- /dev/null
+++ b/src/emu/cpu/m6502/ops4510.h
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ *
+ * ops4510.h
+ * Addressing mode and opcode macros for 4510 CPU
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ * documentation preliminary databook
+ * documentation by michael steil mist@c64.org
+ * available at ftp://ftp.funet.fi/pub/cbm/c65
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+/* 65ce02 ********************************************************
+ * TXS Transfer index X to stack LSB
+ * no flags changed (sic!)
+ * txs tys not interruptable
+ ***************************************************************/
+#undef TXS
+#define TXS \
+ SPL = X; \
+ if (PEEK_OP() == 0x2b /*TYS*/ ) { \
+ UINT8 op = RDOP(); \
+ (*m4510.insn[op])(); \
+ }
+
+/* c65 docu says transfer of axyz to the mapper register
+ so no readback!? */
+#define MAP \
+ if (PEEK_OP() == 0xea /*NOP, in this case end of map*/ )\
+ { \
+ m4510.mem[0]=0; \
+ m4510.mem[1]=0; \
+ m4510.mem[2]=0; \
+ m4510.mem[3]=0; \
+ m4510.mem[4]=0; \
+ m4510.mem[5]=0; \
+ m4510.mem[6]=0; \
+ m4510.mem[7]=0; \
+ CHANGE_PC; \
+} else { \
+ /*UINT16 low, high;*/ \
+ /*low=m4510.low;*/ \
+ /*high=m4510.high;*/ \
+ m4510.low=m4510.a|(m4510.x<<8); \
+ m4510.high=m4510.y|(m4510.z<<8); \
+ /*m4510.a=low&0xff;*/ \
+ /*m4510.x=low>>8;*/ \
+ /*m4510.y=high&0xff;*/ \
+ /*m4510.z=high>>8;*/ \
+ m4510.mem[0]=(m4510.low&0x1000) ? (m4510.low&0xfff)<<8:0; \
+ m4510.mem[1]=(m4510.low&0x2000) ? (m4510.low&0xfff)<<8:0; \
+ m4510.mem[2]=(m4510.low&0x4000) ? (m4510.low&0xfff)<<8:0; \
+ m4510.mem[3]=(m4510.low&0x8000) ? (m4510.low&0xfff)<<8:0; \
+ m4510.mem[4]=(m4510.high&0x1000) ? (m4510.high&0xfff)<<8:0; \
+ m4510.mem[5]=(m4510.high&0x2000) ? (m4510.high&0xfff)<<8:0; \
+ m4510.mem[6]=(m4510.high&0x4000) ? (m4510.high&0xfff)<<8:0; \
+ m4510.mem[7]=(m4510.high&0x8000) ? (m4510.high&0xfff)<<8:0; \
+ CHANGE_PC; \
+ } \
+ m4510_ICount -= 3; \
+ { \
+ UINT8 op = RDOP(); \
+ (*m4510.insn[op])(); \
+ } \
+
diff --git a/src/emu/cpu/m6502/opsc02.h b/src/emu/cpu/m6502/opsc02.h
new file mode 100644
index 00000000000..383d2dcb510
--- /dev/null
+++ b/src/emu/cpu/m6502/opsc02.h
@@ -0,0 +1,353 @@
+/*****************************************************************************
+ *
+ * m6502ops.h
+ * Addressing mode and opcode macros for 6502,65c02,65sc02,6510,n2a03 CPUs
+ *
+ * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * 65sc02 core Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+/***************************************************************
+ ***************************************************************
+ * Macros to emulate the 65C02 opcodes
+ ***************************************************************
+ ***************************************************************/
+
+/* 65C02 *******************************************************
+ * EA = absolute address + X
+ * one additional read if page boundary is crossed
+ ***************************************************************/
+#define EA_ABX_C02_P \
+ EA_ABS; \
+ if ( EAL + X > 0xff ) { \
+ RDMEM( PCW - 1 ); \
+ } \
+ EAW += X;
+
+/* 65C02 *******************************************************
+ * EA = absolute address + X
+ ***************************************************************/
+#define EA_ABX_C02_NP \
+ EA_ABS; \
+ RDMEM( PCW - 1 ); \
+ EAW += X;
+
+/***************************************************************
+ * EA = absolute address + Y
+ * one additional read if page boundary is crossed
+ ***************************************************************/
+#define EA_ABY_C02_P \
+ EA_ABS; \
+ if ( EAL + Y > 0xff ) { \
+ RDMEM( PCW - 1 ); \
+ } \
+ EAW += Y;
+
+/* 65C02 *******************************************************
+ * EA = absolute address + Y
+ ***************************************************************/
+#define EA_ABY_C02_NP \
+ EA_ABS; \
+ RDMEM( PCW - 1 ); \
+ EAW += Y
+
+/* 65C02 *******************************************************
+ * EA = zero page indirect + Y (post indexed)
+ * subtract 1 cycle if page boundary is crossed
+ ***************************************************************/
+#define EA_IDY_C02_P \
+ ZPL = RDOPARG(); \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD); \
+ if (EAL + Y > 0xff) { \
+ RDMEM( PCW - 1 ); \
+ } \
+ EAW += Y;
+
+/* 65C02 *******************************************************
+ * EA = zero page indirect + Y
+ ***************************************************************/
+#define EA_IDY_C02_NP \
+ ZPL = RDOPARG(); \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD); \
+ RDMEM( PCW - 1 ); \
+ EAW += Y
+
+/* 65C02 *******************************************************
+ * EA = indirect (only used by JMP)
+ * correct overflow handling
+ ***************************************************************/
+#define EA_IND_C02 \
+ EA_ABS; \
+ tmp = RDMEM(EAD); \
+ RDMEM(PCW-1); \
+ EAD++; \
+ EAH = RDMEM(EAD); \
+ EAL = tmp
+
+/* 65C02 *******************************************************
+ * EA = indirect plus x (only used by 65c02 JMP)
+ ***************************************************************/
+#define EA_IAX \
+ EA_ABS; \
+ RDMEM( PCW - 1 ); \
+ if (EAL + X > 0xff) { \
+ RDMEM( PCW - 1 ); \
+ } \
+ EAW += X; \
+ tmp = RDMEM(EAD); \
+ EAD++; \
+ EAH = RDMEM(EAD); \
+ EAL = tmp
+
+/* read a value into tmp */
+/* Base number of cycles taken for each mode (including reading of opcode):
+ RD_ABX_C02_P 4/5
+ RD_ABX_C02_NP/WR_ABX_C02_NP 5
+ RD_ABY_C02_P 4/5
+ RD_IDY_C02_P 5/6
+ WR_IDY_C02_NP 6
+ */
+#define RD_ABX_C02_P EA_ABX_C02_P; tmp = RDMEM(EAD)
+#define RD_ABX_C02_NP EA_ABX_C02_NP; tmp = RDMEM(EAD)
+#define RD_ABY_C02_P EA_ABY_C02_P; tmp = RDMEM(EAD)
+#define RD_IDY_C02_P EA_IDY_C02_P; tmp = RDMEM_ID(EAD); m6502_ICount -= 1
+
+#define WR_ABX_C02_NP EA_ABX_C02_NP; WRMEM(EAD, tmp)
+#define WR_ABY_C02_NP EA_ABY_C02_NP; WRMEM(EAD, tmp)
+#define WR_IDY_C02_NP EA_IDY_C02_NP; WRMEM_ID(EAD, tmp); m6502_ICount -= 1
+
+
+/* 65C02********************************************************
+ * BRA branch relative
+ * extra cycle if page boundary is crossed
+ ***************************************************************/
+#define BRA_C02(cond) \
+ tmp = RDOPARG(); \
+ if (cond) \
+ { \
+ RDMEM(PCW); \
+ EAW = PCW + (signed char)tmp; \
+ if ( EAH != PCH ) { \
+ RDMEM( PCW - 1 ); \
+ } \
+ PCD = EAD; \
+ CHANGE_PC; \
+ }
+
+/* 65C02 ********************************************************
+ * ADC Add with carry
+ * different setting of flags in decimal mode
+ ***************************************************************/
+#define ADC_C02 \
+ if (P & F_D) \
+ { \
+ int c = (P & F_C); \
+ int lo = (A & 0x0f) + (tmp & 0x0f) + c; \
+ int hi = (A & 0xf0) + (tmp & 0xf0); \
+ P &= ~(F_V | F_C); \
+ if( lo > 0x09 ) \
+ { \
+ hi += 0x10; \
+ lo += 0x06; \
+ } \
+ if( ~(A^tmp) & (A^hi) & F_N ) \
+ P |= F_V; \
+ if( hi > 0x90 ) \
+ hi += 0x60; \
+ if( hi & 0xff00 ) \
+ P |= F_C; \
+ A = (lo & 0x0f) + (hi & 0xf0); \
+ RDMEM( PCW - 1 ); \
+ } \
+ else \
+ { \
+ int c = (P & F_C); \
+ int sum = A + tmp + c; \
+ P &= ~(F_V | F_C); \
+ if( ~(A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( sum & 0xff00 ) \
+ P |= F_C; \
+ A = (UINT8) sum; \
+ } \
+ SET_NZ(A)
+
+/* 65C02 ********************************************************
+ * SBC Subtract with carry
+ * different setting of flags in decimal mode
+ ***************************************************************/
+#define SBC_C02 \
+ if (P & F_D) \
+ { \
+ int c = (P & F_C) ^ F_C; \
+ int sum = A - tmp - c; \
+ int lo = (A & 0x0f) - (tmp & 0x0f) - c; \
+ int hi = (A & 0xf0) - (tmp & 0xf0); \
+ P &= ~(F_V | F_C); \
+ if( (A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( lo & 0xf0 ) \
+ lo -= 6; \
+ if( lo & 0x80 ) \
+ hi -= 0x10; \
+ if( hi & 0x0f00 ) \
+ hi -= 0x60; \
+ if( (sum & 0xff00) == 0 ) \
+ P |= F_C; \
+ A = (lo & 0x0f) + (hi & 0xf0); \
+ RDMEM( PCW - 1 ); \
+ } \
+ else \
+ { \
+ int c = (P & F_C) ^ F_C; \
+ int sum = A - tmp - c; \
+ P &= ~(F_V | F_C); \
+ if( (A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( (sum & 0xff00) == 0 ) \
+ P |= F_C; \
+ A = (UINT8) sum; \
+ } \
+ SET_NZ(A)
+
+/* 65C02 *******************************************************
+ * BBR Branch if bit is reset
+ ***************************************************************/
+#define BBR(bit) \
+ BRA(!(tmp & (1<<bit)))
+
+/* 65C02 *******************************************************
+ * BBS Branch if bit is set
+ ***************************************************************/
+#define BBS(bit) \
+ BRA(tmp & (1<<bit))
+
+/* 65c02 ********************************************************
+ * BRK Break
+ * increment PC, push PC hi, PC lo, flags (with B bit set),
+ * set I flag, reset D flag and jump via IRQ vector
+ ***************************************************************/
+#define BRK_C02 \
+ RDOPARG(); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ PUSH(P | F_B); \
+ P = (P | F_I) & ~F_D; \
+ PCL = RDMEM(M6502_IRQ_VEC); \
+ PCH = RDMEM(M6502_IRQ_VEC+1); \
+ CHANGE_PC
+
+
+/* 65C02 *******************************************************
+ * DEA Decrement accumulator
+ ***************************************************************/
+#define DEA \
+ A = (UINT8)--A; \
+ SET_NZ(A)
+
+/* 65C02 *******************************************************
+ * INA Increment accumulator
+ ***************************************************************/
+#define INA \
+ A = (UINT8)++A; \
+ SET_NZ(A)
+
+/* 65C02 *******************************************************
+ * PHX Push index X
+ ***************************************************************/
+#define PHX \
+ PUSH(X)
+
+/* 65C02 *******************************************************
+ * PHY Push index Y
+ ***************************************************************/
+#define PHY \
+ PUSH(Y)
+
+/* 65C02 *******************************************************
+ * PLX Pull index X
+ ***************************************************************/
+#define PLX \
+ RDMEM(SPD); \
+ PULL(X); \
+ SET_NZ(X)
+
+/* 65C02 *******************************************************
+ * PLY Pull index Y
+ ***************************************************************/
+#define PLY \
+ RDMEM(SPD); \
+ PULL(Y); \
+ SET_NZ(Y)
+
+/* 65C02 *******************************************************
+ * RMB Reset memory bit
+ ***************************************************************/
+#define RMB(bit) \
+ tmp &= ~(1<<bit)
+
+/* 65C02 *******************************************************
+ * SMB Set memory bit
+ ***************************************************************/
+#define SMB(bit) \
+ tmp |= (1<<bit)
+
+/* 65C02 *******************************************************
+ * STZ Store zero
+ ***************************************************************/
+#define STZ \
+ tmp = 0
+
+/* 65C02 *******************************************************
+ * TRB Test and reset bits
+ ***************************************************************/
+#define TRB \
+ SET_Z(tmp&A); \
+ tmp &= ~A
+
+/* 65C02 *******************************************************
+ * TSB Test and set bits
+ ***************************************************************/
+#define TSB \
+ SET_Z(tmp&A); \
+ tmp |= A
+
+
+/***************************************************************
+ ***************************************************************
+ * Macros to emulate the 65sc02 opcodes
+ ***************************************************************
+ ***************************************************************/
+
+
+/* 65sc02 ********************************************************
+ * BSR Branch to subroutine
+ ***************************************************************/
+#define BSR \
+ EAL = RDOPARG(); \
+ RDMEM(SPD); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ EAH = RDOPARG(); \
+ EAW = PCW + (INT16)(EAW-1); \
+ PCD = EAD; \
+ CHANGE_PC
+
+
diff --git a/src/emu/cpu/m6502/opsce02.h b/src/emu/cpu/m6502/opsce02.h
new file mode 100644
index 00000000000..b7f936bf270
--- /dev/null
+++ b/src/emu/cpu/m6502/opsce02.h
@@ -0,0 +1,988 @@
+/*****************************************************************************
+ *
+ * opsce02.h
+ * Addressing mode and opcode macros for 65ce02 CPU
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ * documentation preliminary databook
+ * documentation by michael steil mist@c64.org
+ * available at ftp://ftp.funet.fi/pub/cbm/c65
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#define SET_NZ(n) if ((n) == 0) P = (P & ~F_N) | F_Z; else P = (P & ~(F_N | F_Z)) | ((n) & F_N)
+#define SET_Z(n) if ((n) == 0) P |= F_Z; else P &= ~F_Z
+
+#define RDMEM_WORD(addr, pair) pair.b.l=RDMEM( addr ); pair.b.h=RDMEM( (addr+1) & 0xffff )
+#define WRMEM_WORD(addr,pair) WRMEM(addr,pair.b.l); WRMEM((addr+1)&0xffff,pair.b.h)
+
+#define SET_NZ_WORD(n) \
+ if( n.w.l == 0 ) \
+ P = (P & ~F_N) | F_Z; \
+ else \
+ P = (P & ~(F_N | F_Z)) | ((n.b.h) & F_N)
+
+/***************************************************************
+ * EA = absolute address
+ ***************************************************************/
+#define EA_ABS \
+ EAL = RDOPARG(); \
+ EAH = RDOPARG()
+
+/***************************************************************
+ * EA = absolute address + X
+ ***************************************************************/
+#define EA_ABX \
+ EA_ABS; \
+ EAW += X
+
+/***************************************************************
+ * EA = absolute address + Y
+ * one additional read if page boundary is crossed
+ ***************************************************************/
+#define EA_ABY \
+ EA_ABS; \
+ EAW += Y;
+
+/***************************************************************
+ * EA = zero page address
+ ***************************************************************/
+#define EA_ZPG \
+ ZPL = RDOPARG(); \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page address + X
+ ***************************************************************/
+#define EA_ZPX \
+ ZPL = RDOPARG(); \
+ ZPL = X + ZPL; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page address + Y
+ ***************************************************************/
+#define EA_ZPY \
+ ZPL = RDOPARG(); \
+ ZPL = Y + ZPL; \
+ EAD = ZPD
+
+/***************************************************************
+ * EA = zero page + X indirect (pre indexed)
+ ***************************************************************/
+#define EA_IDX \
+ ZPL = RDOPARG(); \
+ ZPL = ZPL + X; \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD)
+
+/***************************************************************
+ * EA = zero page indirect + Y (post indexed)
+ ***************************************************************/
+#define EA_IDY \
+ ZPL = RDOPARG(); \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD); \
+ EAW += Y
+
+/***************************************************************
+ * EA = zero page indirect + Z (post indexed)
+ * ???? subtract 1 cycle if page boundary is crossed
+ ***************************************************************/
+#define EA_IDZ \
+ ZPL = RDOPARG(); \
+ EAL = RDMEM(ZPD); \
+ ZPL++; \
+ EAH = RDMEM(ZPD); \
+ EAW += Z
+
+/***************************************************************
+ * EA = zero page indexed stack, indirect + Y (post indexed)
+ ***************************************************************/
+#define EA_INSY \
+ { \
+ PAIR pair={{0}}; \
+ pair.b.l = SPL+RDOPARG(); \
+ pair.b.h = SPH; \
+ EAL = RDMEM(pair.d); \
+ if( P & F_E ) \
+ pair.b.l++; \
+ else \
+ pair.w.l++; \
+ EAH = RDMEM(pair.d); \
+ RDMEM(PCW-1); \
+ EAW += Y; \
+ }
+
+/***************************************************************
+ * EA = indirect (only used by JMP)
+ ***************************************************************/
+#define EA_IND \
+ EA_ABS; \
+ tmp = RDMEM(EAD); \
+ EAD++; \
+ EAH = RDMEM(EAD); \
+ EAL = tmp
+
+/* 65ce02 ******************************************************
+ * EA = indirect plus x (only used by 65c02 JMP)
+ ***************************************************************/
+#define EA_IAX \
+ EA_ABS; \
+ EAW += X; \
+ tmp = RDMEM(EAD); \
+ EAD++; \
+ EAH = RDMEM(EAD); \
+ EAL = tmp
+
+/* read a value into tmp */
+/* Base number of cycles taken for each mode (including reading of opcode):
+ RD_ACC/WR_ACC 0
+ RD_IMM 2
+ RD_DUM 2
+ RD_ABS/WR_ABS 4
+ RD_ABS_WORD/WR_ABS_WORD 5
+ RD_ABX/WR_ABX 4
+ RD_ABY/WR_ABY 4
+ RD_IDX/WR_IDX 5
+ RD_IDY/WR_IDY 5
+ RD_IDZ 5
+ RD_INSY/WR_INSY 6
+ RD_ZPG/WR_ZPG 3
+ RD_ZPG_WORD 4
+ RD_ZPX/WR_ZPX 3
+ RD_ZPY/WR_ZPY 3
+ */
+#define RD_ACC tmp = A
+#define RD_IMM tmp = RDOPARG()
+#define RD_IMM_WORD tmp.b.l = RDOPARG(); tmp.b.h=RDOPARG()
+#define RD_DUM RDMEM(PCW-1)
+#define RD_ABS EA_ABS; tmp = RDMEM(EAD)
+#define RD_ABS_WORD EA_ABS; RDMEM_WORD(EAD, tmp)
+#define RD_ABX EA_ABX; tmp = RDMEM(EAD)
+#define RD_ABY EA_ABY; tmp = RDMEM(EAD)
+#define RD_IDX EA_IDX; tmp = RDMEM(EAD)
+#define RD_IDY EA_IDY; tmp = RDMEM(EAD)
+#define RD_IDZ EA_IDZ; tmp = RDMEM(EAD)
+#define RD_INSY EA_INSY; tmp = RDMEM(EAD)
+#define RD_ZPG EA_ZPG; tmp = RDMEM(EAD)
+#define RD_ZPG_WORD EA_ZPG; RDMEM_WORD(EAD, tmp)
+#define RD_ZPX EA_ZPX; tmp = RDMEM(EAD)
+#define RD_ZPY EA_ZPY; tmp = RDMEM(EAD)
+
+/* write a value from tmp */
+#define WR_ACC A = (UINT8)tmp
+#define WR_ABS EA_ABS; WRMEM(EAD, tmp)
+#define WR_ABS_WORD EA_ABS; WRMEM_WORD(EAD, tmp)
+#define WR_ABX EA_ABX; WRMEM(EAD, tmp)
+#define WR_ABY EA_ABY; WRMEM(EAD, tmp)
+#define WR_IDX EA_IDX; WRMEM(EAD, tmp)
+#define WR_IDY EA_IDY; WRMEM(EAD, tmp)
+#define WR_INSY EA_INSY; WRMEM(EAD, tmp)
+#define WR_ZPG EA_ZPG; WRMEM(EAD, tmp)
+#define WR_ZPX EA_ZPX; WRMEM(EAD, tmp)
+#define WR_ZPY EA_ZPY; WRMEM(EAD, tmp)
+
+#define WB_EA WRMEM(EAD, tmp)
+#define WB_EA_WORD WRMEM_WORD(EAD, tmp)
+
+/***************************************************************
+ * push a register onto the stack
+ ***************************************************************/
+#define PUSH(Rg) WRMEM(SPD, Rg); if (P&F_E) { SPL--; } else { SW--; }
+
+/***************************************************************
+ * pull a register from the stack
+ ***************************************************************/
+#define PULL(Rg) if (P&F_E) { SPL++; } else { SW++; } Rg = RDMEM(SPD)
+
+/* the order in which the args are pushed is correct! */
+#define PUSH_WORD(pair) PUSH(pair.b.l);PUSH(pair.b.h)
+
+/* 65ce02 *******************************************************
+ * ADC Add with carry
+ * correct setting of flags in decimal mode
+ ***************************************************************/
+#define ADC \
+ if (P & F_D) { \
+ int c = (P & F_C); \
+ int lo = (A & 0x0f) + (tmp & 0x0f) + c; \
+ int hi = (A & 0xf0) + (tmp & 0xf0); \
+ P &= ~(F_V | F_C); \
+ if( lo > 0x09 ) { \
+ hi += 0x10; \
+ lo += 0x06; \
+ } \
+ if( ~(A^tmp) & (A^hi) & F_N ) \
+ P |= F_V; \
+ if( hi > 0x90 ) \
+ hi += 0x60; \
+ if( hi & 0xff00 ) \
+ P |= F_C; \
+ A = (lo & 0x0f) + (hi & 0xf0); \
+ } else { \
+ int c = (P & F_C); \
+ int sum = A + tmp + c; \
+ P &= ~(F_V | F_C); \
+ if( ~(A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( sum & 0xff00 ) \
+ P |= F_C; \
+ A = (UINT8) sum; \
+ } \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * AND Logical and
+ ***************************************************************/
+#define AND \
+ A = (UINT8)(A & tmp); \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * ASL Arithmetic shift left
+ ***************************************************************/
+#define ASL \
+ P = (P & ~F_C) | ((tmp >> 7) & F_C); \
+ tmp = (UINT8)(tmp << 1); \
+ SET_NZ(tmp)
+
+/* 65ce02 ******************************************************
+ * ASR arithmetic (signed) shift right
+ * [7] -> [7][6][5][4][3][2][1][0] -> C
+ ***************************************************************/
+#define ASR_65CE02 \
+ P = (P & ~F_C) | (tmp & F_C); \
+ tmp = (signed char)tmp >> 1; \
+ SET_NZ(tmp)
+
+/* 65ce02 ******************************************************
+ * ASW arithmetic shift left word
+ * [c] <- [15]..[6][5][4][3][2][1][0]
+ ***************************************************************/
+/* not sure about how 16 bit memory modifying is executed */
+#define ASW \
+ tmp.w.l = tmp.w.l << 1; \
+ P = (P & ~F_C) | (tmp.b.h2 & F_C); \
+ SET_NZ_WORD(tmp);
+
+
+/* 65ce02 ******************************************************
+ * augment
+ ***************************************************************/
+#define AUG \
+ t1=RDOPARG(); \
+ t2=RDOPARG(); \
+ t3=RDOPARG(); \
+ logerror("m65ce02 at pc:%.4x reserved op aug %.2x %.2x %.2x\n", t1,t2,t3);
+
+/* 65ce02 ******************************************************
+ * BBR Branch if bit is reset
+ ***************************************************************/
+#define BBR(bit) \
+ BRA(!(tmp & (1<<bit)))
+
+/* 65ce02 ******************************************************
+ * BBS Branch if bit is set
+ ***************************************************************/
+#define BBS(bit) \
+ BRA(tmp & (1<<bit))
+
+/* 65ce02 ******************************************************
+ * BIT Bit test
+ ***************************************************************/
+#undef BIT
+#define BIT \
+ P &= ~(F_N|F_V|F_Z); \
+ P |= tmp & (F_N|F_V); \
+ if ((tmp & A) == 0) \
+ P |= F_Z
+
+/***************************************************************
+ * BRA branch relative
+ ***************************************************************/
+#define BRA(cond) \
+ tmp = RDOPARG(); \
+ if (cond) \
+ { \
+ EAW = PCW + (signed char)tmp; \
+ PCD = EAD; \
+ CHANGE_PC; \
+ }
+
+/***************************************************************
+ * BRA branch relative
+ ***************************************************************/
+#define BRA_WORD(cond) \
+ EAL = RDOPARG(); \
+ EAH = RDOPARG(); \
+ if (cond) \
+ { \
+ EAW = PCW + (short)(EAW-1); \
+ PCD = EAD; \
+ CHANGE_PC; \
+ }
+
+/* 65ce02 ******************************************************
+ * BRK Break
+ * increment PC, push PC hi, PC lo, flags (with B bit set),
+ * set I flag, jump via IRQ vector
+ ***************************************************************/
+#define BRK \
+ RDOPARG(); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ PUSH(P | F_B); \
+ P = (P | F_I); \
+ PCL = RDMEM(M6502_IRQ_VEC); \
+ PCH = RDMEM(M6502_IRQ_VEC+1); \
+ CHANGE_PC
+
+/* 65ce02 ********************************************************
+ * BSR Branch to subroutine
+ ***************************************************************/
+#define BSR \
+ EAL = RDOPARG(); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ EAH = RDOPARG(); \
+ EAW = PCW + (INT16)(EAW-1); \
+ PCD = EAD; \
+ CHANGE_PC
+
+/* 65ce02 ******************************************************
+ * CLC Clear carry flag
+ ***************************************************************/
+#define CLC \
+ P &= ~F_C
+
+/* 65ce02 ******************************************************
+ * CLD Clear decimal flag
+ ***************************************************************/
+#define CLD \
+ P &= ~F_D
+
+/* 65ce02 ******************************************************
+ * cle clear disable extended stack flag
+ ***************************************************************/
+#define CLE \
+ P|=F_E
+
+/* 65ce02 ******************************************************
+ * CLI Clear interrupt flag
+ ***************************************************************/
+#define CLI \
+ if ((IRQ_STATE != CLEAR_LINE) && (P & F_I)) { \
+ AFTER_CLI = 1; \
+ } \
+ P &= ~F_I
+
+/* 65ce02 ******************************************************
+ * CLV Clear overflow flag
+ ***************************************************************/
+#define CLV \
+ P &= ~F_V
+
+/* 65ce02 ******************************************************
+ * CMP Compare accumulator
+ ***************************************************************/
+#define CMP \
+ P &= ~F_C; \
+ if (A >= tmp) \
+ P |= F_C; \
+ SET_NZ((UINT8)(A - tmp))
+
+/* 65ce02 ******************************************************
+ * CPX Compare index X
+ ***************************************************************/
+#define CPX \
+ P &= ~F_C; \
+ if (X >= tmp) \
+ P |= F_C; \
+ SET_NZ((UINT8)(X - tmp))
+
+/* 65ce02 ******************************************************
+ * CPY Compare index Y
+ ***************************************************************/
+#define CPY \
+ P &= ~F_C; \
+ if (Y >= tmp) \
+ P |= F_C; \
+ SET_NZ((UINT8)(Y - tmp))
+
+/* 65ce02 ******************************************************
+ * CPZ Compare index Z
+ ***************************************************************/
+#define CPZ \
+ P &= ~F_C; \
+ if (Z >= tmp) \
+ P |= F_C; \
+ SET_NZ((UINT8)(Z - tmp))
+
+/* 65ce02 ******************************************************
+ * DEA Decrement accumulator
+ ***************************************************************/
+#define DEA \
+ A = (UINT8)--A; \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * DEC Decrement memory
+ ***************************************************************/
+#define DEC \
+ tmp = (UINT8)(tmp-1); \
+ SET_NZ(tmp)
+
+/* 65ce02 ******************************************************
+ * DEW Decrement memory word
+ ***************************************************************/
+#define DEW \
+ tmp.w.l = --tmp.w.l; \
+ SET_NZ_WORD(tmp)
+
+/* 65ce02 ******************************************************
+ * DEX Decrement index X
+ ***************************************************************/
+#define DEX \
+ X = (UINT8)(X-1); \
+ SET_NZ(X)
+
+/* 65ce02 ******************************************************
+ * DEY Decrement index Y
+ ***************************************************************/
+#define DEY \
+ Y = (UINT8)(Y-1); \
+ SET_NZ(Y)
+
+/* 65ce02 ******************************************************
+ * DEZ Decrement index Z
+ ***************************************************************/
+#define DEZ \
+ Z = (UINT8)(Z-1); \
+ SET_NZ(Z)
+
+/* 65ce02 ******************************************************
+ * EOR Logical exclusive or
+ ***************************************************************/
+#define EOR \
+ A = (UINT8)(A ^ tmp); \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * INA Increment accumulator
+ ***************************************************************/
+#define INA \
+ A = (UINT8)++A; \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * INC Increment memory
+ ***************************************************************/
+#define INC \
+ tmp = (UINT8)(tmp+1); \
+ SET_NZ(tmp)
+
+/* 65ce02 ******************************************************
+ * INW Increment memory word
+ ***************************************************************/
+#define INW \
+ tmp.w.l = ++tmp.w.l; \
+ SET_NZ_WORD(tmp)
+
+/* 65ce02 ******************************************************
+ * INX Increment index X
+ ***************************************************************/
+#define INX \
+ X = (UINT8)(X+1); \
+ SET_NZ(X)
+
+/* 65ce02 ******************************************************
+ * INY Increment index Y
+ ***************************************************************/
+#define INY \
+ Y = (UINT8)(Y+1); \
+ SET_NZ(Y)
+
+/* 65ce02 ******************************************************
+ * INZ Increment index Z
+ ***************************************************************/
+#define INZ \
+ Z = (UINT8)(Z+1); \
+ SET_NZ(Z)
+
+/* 65ce02 ******************************************************
+ * JMP Jump to address
+ * set PC to the effective address
+ ***************************************************************/
+#define JMP \
+ PCD = EAD; \
+ CHANGE_PC
+
+/* 65ce02 ******************************************************
+ * JSR Jump to subroutine
+ * decrement PC (sic!) push PC hi, push PC lo and set
+ * PC to the effective address
+ ***************************************************************/
+#define JSR \
+ EAL = RDOPARG(); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ EAH = RDOPARG(); \
+ PCD = EAD; \
+ CHANGE_PC
+
+/* 65ce02 ******************************************************
+ * JSR Jump to subroutine
+ * decrement PC (sic!) push PC hi, push PC lo and set
+ * PC to the effective address
+ ***************************************************************/
+#define JSR_IND \
+ EAL = RDOPARG(); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ EAH = RDOPARG(); \
+ PCL = RDMEM(EAD); \
+ PCH = RDMEM(EAD); \
+ CHANGE_PC
+
+/* 65ce02 ******************************************************
+ * JSR Jump to subroutine
+ * decrement PC (sic!) push PC hi, push PC lo and set
+ * PC to the effective address
+ ***************************************************************/
+#define JSR_INDX \
+ EAL = RDOPARG()+X; \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ EAH = RDOPARG(); \
+ PCL = RDMEM(EAD); \
+ PCH = RDMEM(EAD); \
+ CHANGE_PC
+
+/* 65ce02 ******************************************************
+ * LDA Load accumulator
+ ***************************************************************/
+#define LDA \
+ A = (UINT8)tmp; \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * LDX Load index X
+ ***************************************************************/
+#define LDX \
+ X = (UINT8)tmp; \
+ SET_NZ(X)
+
+/* 65ce02 ******************************************************
+ * LDY Load index Y
+ ***************************************************************/
+#define LDY \
+ Y = (UINT8)tmp; \
+ SET_NZ(Y)
+
+/* 65ce02 ******************************************************
+ * LDZ Load index Z
+ ***************************************************************/
+#define LDZ \
+ Z = (UINT8)tmp; \
+ SET_NZ(Z)
+
+/* 65ce02 ******************************************************
+ * LSR Logic shift right
+ * 0 -> [7][6][5][4][3][2][1][0] -> C
+ ***************************************************************/
+#define LSR \
+ P = (P & ~F_C) | (tmp & F_C); \
+ tmp = (UINT8)tmp >> 1; \
+ SET_NZ(tmp)
+
+/* 65ce02 ******************************************************
+ * NEG accu
+ * twos complement
+ ***************************************************************/
+#define NEG \
+ A= (A^0xff)+1; \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * NOP No operation
+ ***************************************************************/
+#define NOP
+
+/* 65ce02 ******************************************************
+ * ORA Logical inclusive or
+ ***************************************************************/
+#define ORA \
+ A = (UINT8)(A | tmp); \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * PHA Push accumulator
+ ***************************************************************/
+#define PHA \
+ PUSH(A)
+
+/* 65ce02 ******************************************************
+ * PHP Push processor status (flags)
+ ***************************************************************/
+#define PHP \
+ PUSH(P)
+
+/* 65ce02 ******************************************************
+ * PHX Push index X
+ ***************************************************************/
+#define PHX \
+ PUSH(X)
+
+/* 65ce02 ******************************************************
+ * PHY Push index Y
+ ***************************************************************/
+#define PHY \
+ PUSH(Y)
+
+/* 65ce02 ******************************************************
+ * PHZ Push index z
+ ***************************************************************/
+#define PHZ \
+ PUSH(Z)
+
+/* 65ce02 ******************************************************
+ * PLA Pull accumulator
+ ***************************************************************/
+#define PLA \
+ PULL(A); \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * PLP Pull processor status (flags)
+ ***************************************************************/
+#define PLP \
+ if ( P & F_I ) { \
+ UINT8 temp; \
+ PULL(temp); \
+ P=(P&F_E)|F_B|(temp&~F_E); \
+ if( IRQ_STATE != CLEAR_LINE && !(P & F_I) ) { \
+ LOG(("M65ce02#%d PLP sets after_cli\n", cpu_getactivecpu())); \
+ AFTER_CLI = 1; \
+ } \
+ } else { \
+ UINT8 temp; \
+ PULL(temp); \
+ P=(P&F_E)|F_B|(temp&~F_E); \
+ }
+
+/* 65ce02 ******************************************************
+ * PLX Pull index X
+ ***************************************************************/
+#define PLX \
+ PULL(X); \
+ SET_NZ(X)
+
+/* 65ce02 ******************************************************
+ * PLY Pull index Y
+ ***************************************************************/
+#define PLY \
+ PULL(Y); \
+ SET_NZ(Y)
+
+/* 65ce02 ******************************************************
+ * PLZ Pull index Z
+ ***************************************************************/
+#define PLZ \
+ PULL(Z); \
+ SET_NZ(Z)
+
+/* 65ce02 ******************************************************
+ * RMB Reset memory bit
+ ***************************************************************/
+#define RMB(bit) \
+ tmp &= ~(1<<bit)
+
+/* 65ce02 ******************************************************
+ * ROL Rotate left
+ * new C <- [7][6][5][4][3][2][1][0] <- C
+ ***************************************************************/
+#define ROL \
+ tmp = (tmp << 1) | (P & F_C); \
+ P = (P & ~F_C) | ((tmp >> 8) & F_C); \
+ tmp = (UINT8)tmp; \
+ SET_NZ(tmp)
+
+/* 65ce02 ******************************************************
+ * ROR Rotate right
+ * C -> [7][6][5][4][3][2][1][0] -> new C
+ ***************************************************************/
+#define ROR \
+ tmp |= (P & F_C) << 8; \
+ P = (P & ~F_C) | (tmp & F_C); \
+ tmp = (UINT8)(tmp >> 1); \
+ SET_NZ(tmp)
+
+/* 65ce02 ******************************************************
+ * ROW rotate left word
+ * [c] <- [15]..[6][5][4][3][2][1][0] <- C
+ ***************************************************************/
+/* not sure about how 16 bit memory modifying is executed */
+#define ROW \
+ tmp.d =(tmp.d << 1); \
+ tmp.w.l |= (P & F_C); \
+ P = (P & ~F_C) | (tmp.w.l & F_C); \
+ SET_NZ_WORD(tmp);
+
+
+/* 65ce02 ********************************************************
+ * RTI Return from interrupt
+ * pull flags, pull PC lo, pull PC hi
+ ***************************************************************/
+#define RTI \
+ RDMEM(SPD); \
+ PULL(tmp); \
+ P = (P&F_E)|F_B|(tmp&~F_E); \
+ PULL(PCL); \
+ PULL(PCH); \
+ if( IRQ_STATE != CLEAR_LINE && !(P & F_I) ) \
+ { \
+ LOG(("M65ce02#%d RTI sets after_cli\n", cpu_getactivecpu())); \
+ AFTER_CLI = 1; \
+ } \
+ CHANGE_PC
+
+/* 65ce02 ******************************************************
+ * RTS Return from subroutine
+ * pull PC lo, PC hi and increment PC
+ ***************************************************************/
+#define RTS \
+ PULL(PCL); \
+ PULL(PCH); \
+ RDMEM(PCW); PCW++; \
+ CHANGE_PC
+
+/* 65ce02 ******************************************************
+ * RTS imm
+ * Is the stack adjustment done before or after the return actions?
+ * Exact order of the read instructions unknown
+ ***************************************************************/
+#define RTN \
+ if (P&F_E) { \
+ SPL+=tmp; \
+ } else { \
+ SW+=tmp; \
+ } \
+ RDMEM(PCW-1); \
+ RDMEM(PCW-1); \
+ RDMEM(SPD); \
+ P = (P&F_E)|F_B|(tmp&~F_E); \
+ PULL(PCL); \
+ PULL(PCH); \
+ if( IRQ_STATE != CLEAR_LINE && !(P & F_I) ) { \
+ LOG(("M65ce02#%d RTI sets after_cli\n", cpu_getactivecpu())); \
+ AFTER_CLI = 1; \
+ } \
+ CHANGE_PC
+
+
+/* 65ce02 *******************************************************
+ * SBC Subtract with carry
+ * correct setting of flags in decimal mode
+ ***************************************************************/
+#define SBC \
+ if (P & F_D) { \
+ int c = (P & F_C) ^ F_C; \
+ int sum = A - tmp - c; \
+ int lo = (A & 0x0f) - (tmp & 0x0f) - c; \
+ int hi = (A & 0xf0) - (tmp & 0xf0); \
+ P &= ~(F_V | F_C); \
+ if( (A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( lo & 0xf0 ) \
+ lo -= 6; \
+ if( lo & 0x80 ) \
+ hi -= 0x10; \
+ if( hi & 0x0f00 ) \
+ hi -= 0x60; \
+ if( (sum & 0xff00) == 0 ) \
+ P |= F_C; \
+ A = (lo & 0x0f) + (hi & 0xf0); \
+ } else { \
+ int c = (P & F_C) ^ F_C; \
+ int sum = A - tmp - c; \
+ P &= ~(F_V | F_C); \
+ if( (A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( (sum & 0xff00) == 0 ) \
+ P |= F_C; \
+ A = (UINT8) sum; \
+ } \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * SEC Set carry flag
+ ***************************************************************/
+#define SEC \
+ P |= F_C
+
+/* 65ce02 ******************************************************
+ * SED Set decimal flag
+ ***************************************************************/
+#define SED \
+ P |= F_D
+
+/* 65ce02 ******************************************************
+ * see set disable extended stack flag
+ ***************************************************************/
+#define SEE \
+ P&=~F_E
+
+/* 65ce02 ******************************************************
+ * SEI Set interrupt flag
+ ***************************************************************/
+#define SEI \
+ P |= F_I
+
+/* 65ce02 ******************************************************
+ * SMB Set memory bit
+ ***************************************************************/
+#define SMB(bit) \
+ tmp |= (1<<bit)
+
+/* 65ce02 ******************************************************
+ * STA Store accumulator
+ ***************************************************************/
+#define STA \
+ tmp = A
+
+/* 65ce02 ******************************************************
+ * STX Store index X
+ ***************************************************************/
+#define STX \
+ tmp = X
+
+/* 65ce02 ******************************************************
+ * STY Store index Y
+ ***************************************************************/
+#define STY \
+ tmp = Y
+
+/* 65ce02 ******************************************************
+ * STZ Store index Z
+ ***************************************************************/
+#define STZ_65CE02 \
+ tmp = Z
+
+/* 65ce02 ******************************************************
+ * TAB Transfer accumulator to Direct Page
+ ***************************************************************/
+#define TAB \
+ B = A; \
+ SET_NZ(B)
+
+/* 65ce02 ******************************************************
+ * TAX Transfer accumulator to index X
+ ***************************************************************/
+#define TAX \
+ X = A; \
+ SET_NZ(X)
+
+/* 65ce02 ******************************************************
+ * TAY Transfer accumulator to index Y
+ ***************************************************************/
+#define TAY \
+ Y = A; \
+ SET_NZ(Y)
+
+/* 65ce02 ******************************************************
+ * TAZ Transfer accumulator to index z
+ ***************************************************************/
+#define TAZ \
+ Z = A; \
+ SET_NZ(Z)
+
+/* 65ce02 ******************************************************
+ * TBA Transfer direct page to accumulator
+ ***************************************************************/
+#define TBA \
+ A = B; \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * TRB Test and reset bits
+ ***************************************************************/
+#define TRB \
+ SET_Z(tmp&A); \
+ tmp &= ~A
+
+/* 65ce02 ******************************************************
+ * TSB Test and set bits
+ ***************************************************************/
+#define TSB \
+ SET_Z(tmp&A); \
+ tmp |= A
+
+/* 65ce02 ******************************************************
+ * TSX Transfer stack LSB to index X
+ ***************************************************************/
+#define TSX \
+ X = SPL; \
+ SET_NZ(X)
+
+/* 65ce02 ******************************************************
+ * TSY Transfer stack pointer to index y
+ ***************************************************************/
+#define TSY \
+ Y = SPL; \
+ SET_NZ(Y)
+
+/* 65ce02 ******************************************************
+ * TXA Transfer index X to accumulator
+ ***************************************************************/
+#define TXA \
+ A = X; \
+ SET_NZ(A)
+
+/* 65ce02 ********************************************************
+ * TXS Transfer index X to stack LSB
+ * no flags changed (sic!)
+ * txs tys not interruptable
+ ***************************************************************/
+#define TXS \
+ SPL = X; \
+ if (PEEK_OP() == 0x2b /*TYS*/ ) { \
+ UINT8 op = RDOP(); \
+ (*m65ce02.insn[op])(); \
+ }
+
+
+/* 65ce02 ******************************************************
+ * TYA Transfer index Y to accumulator
+ ***************************************************************/
+#define TYA \
+ A = Y; \
+ SET_NZ(A)
+
+/* 65ce02 ******************************************************
+ * TYS Transfer index y to stack pointer
+ ***************************************************************/
+#define TYS \
+ SPH = Y;
+
+/* 65ce02 ******************************************************
+ * TZA Transfer index z to accumulator
+ ***************************************************************/
+#define TZA \
+ A = Z; \
+ SET_NZ(A)
+
diff --git a/src/emu/cpu/m6502/opsn2a03.h b/src/emu/cpu/m6502/opsn2a03.h
new file mode 100644
index 00000000000..0264100fd45
--- /dev/null
+++ b/src/emu/cpu/m6502/opsn2a03.h
@@ -0,0 +1,40 @@
+/***************************************************************
+ ***************************************************************
+ * Macros to emulate the N2A03 opcodes
+ ***************************************************************
+ ***************************************************************/
+
+
+/* N2A03 *******************************************************
+ * ADC Add with carry - no decimal mode
+ ***************************************************************/
+#define ADC_NES \
+ { \
+ int c = (P & F_C); \
+ int sum = A + tmp + c; \
+ P &= ~(F_V | F_C); \
+ if( ~(A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( sum & 0xff00 ) \
+ P |= F_C; \
+ A = (UINT8) sum; \
+ } \
+ SET_NZ(A)
+
+/* N2A03 *******************************************************
+ * SBC Subtract with carry - no decimal mode
+ ***************************************************************/
+#define SBC_NES \
+ { \
+ int c = (P & F_C) ^ F_C; \
+ int sum = A - tmp - c; \
+ P &= ~(F_V | F_C); \
+ if( (A^tmp) & (A^sum) & F_N ) \
+ P |= F_V; \
+ if( (sum & 0xff00) == 0 ) \
+ P |= F_C; \
+ A = (UINT8) sum; \
+ } \
+ SET_NZ(A)
+
+
diff --git a/src/emu/cpu/m6502/t6502.c b/src/emu/cpu/m6502/t6502.c
new file mode 100644
index 00000000000..806b63379f4
--- /dev/null
+++ b/src/emu/cpu/m6502/t6502.c
@@ -0,0 +1,360 @@
+/*****************************************************************************
+ *
+ * tbl6502.c
+ * 6502 opcode functions and function pointer table
+ *
+ * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * 2003-05-26 Fixed PHP, PLP, PHA, PLA cycle counts. [SJ]
+ * 2004-04-30 Fixed STX (abs) cycle count. [SJ]
+ *
+ *****************************************************************************/
+
+#undef OP
+#define OP(nn) INLINE void m6502_##nn(void)
+
+/*****************************************************************************
+ *****************************************************************************
+ *
+ * plain vanilla 6502 opcodes
+ *
+ *****************************************************************************
+ * op temp cycles rdmem opc wrmem ********************/
+
+OP(00) { BRK; } /* 7 BRK */
+OP(20) { JSR; } /* 6 JSR */
+OP(40) { RTI; } /* 6 RTI */
+OP(60) { RTS; } /* 6 RTS */
+OP(80) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+OP(a0) { int tmp; RD_IMM; LDY; } /* 2 LDY IMM */
+OP(c0) { int tmp; RD_IMM; CPY; } /* 2 CPY IMM */
+OP(e0) { int tmp; RD_IMM; CPX; } /* 2 CPX IMM */
+
+OP(10) { int tmp; BPL; } /* 2-4 BPL REL */
+OP(30) { int tmp; BMI; } /* 2-4 BMI REL */
+OP(50) { int tmp; BVC; } /* 2-4 BVC REL */
+OP(70) { int tmp; BVS; } /* 2-4 BVS REL */
+OP(90) { int tmp; BCC; } /* 2-4 BCC REL */
+OP(b0) { int tmp; BCS; } /* 2-4 BCS REL */
+OP(d0) { int tmp; BNE; } /* 2-4 BNE REL */
+OP(f0) { int tmp; BEQ; } /* 2-4 BEQ REL */
+
+OP(01) { int tmp; RD_IDX; ORA; } /* 6 ORA IDX */
+OP(21) { int tmp; RD_IDX; AND; } /* 6 AND IDX */
+OP(41) { int tmp; RD_IDX; EOR; } /* 6 EOR IDX */
+OP(61) { int tmp; RD_IDX; ADC; } /* 6 ADC IDX */
+OP(81) { int tmp; STA; WR_IDX; } /* 6 STA IDX */
+OP(a1) { int tmp; RD_IDX; LDA; } /* 6 LDA IDX */
+OP(c1) { int tmp; RD_IDX; CMP; } /* 6 CMP IDX */
+OP(e1) { int tmp; RD_IDX; SBC; } /* 6 SBC IDX */
+
+OP(11) { int tmp; RD_IDY_P; ORA; } /* 5 ORA IDY page penalty */
+OP(31) { int tmp; RD_IDY_P; AND; } /* 5 AND IDY page penalty */
+OP(51) { int tmp; RD_IDY_P; EOR; } /* 5 EOR IDY page penalty */
+OP(71) { int tmp; RD_IDY_P; ADC; } /* 5 ADC IDY page penalty */
+OP(91) { int tmp; STA; WR_IDY_NP; } /* 6 STA IDY */
+OP(b1) { int tmp; RD_IDY_P; LDA; } /* 5 LDA IDY page penalty */
+OP(d1) { int tmp; RD_IDY_P; CMP; } /* 5 CMP IDY page penalty */
+OP(f1) { int tmp; RD_IDY_P; SBC; } /* 5 SBC IDY page penalty */
+
+OP(02) { KIL; } /* 1 KIL */
+OP(22) { KIL; } /* 1 KIL */
+OP(42) { KIL; } /* 1 KIL */
+OP(62) { KIL; } /* 1 KIL */
+OP(82) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+OP(a2) { int tmp; RD_IMM; LDX; } /* 2 LDX IMM */
+OP(c2) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+OP(e2) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+
+OP(12) { KIL; } /* 1 KIL */
+OP(32) { KIL; } /* 1 KIL */
+OP(52) { KIL; } /* 1 KIL */
+OP(72) { KIL; } /* 1 KIL */
+OP(92) { KIL; } /* 1 KIL */
+OP(b2) { KIL; } /* 1 KIL */
+OP(d2) { KIL; } /* 1 KIL */
+OP(f2) { KIL; } /* 1 KIL */
+
+OP(03) { int tmp; RD_IDX; WB_EA; SLO; WB_EA; } /* 7 SLO IDX */
+OP(23) { int tmp; RD_IDX; WB_EA; RLA; WB_EA; } /* 7 RLA IDX */
+OP(43) { int tmp; RD_IDX; WB_EA; SRE; WB_EA; } /* 7 SRE IDX */
+OP(63) { int tmp; RD_IDX; WB_EA; RRA; WB_EA; } /* 7 RRA IDX */
+OP(83) { int tmp; SAX; WR_IDX; } /* 6 SAX IDX */
+OP(a3) { int tmp; RD_IDX; LAX; } /* 6 LAX IDX */
+OP(c3) { int tmp; RD_IDX; WB_EA; DCP; WB_EA; } /* 7 DCP IDX */
+OP(e3) { int tmp; RD_IDX; WB_EA; ISB; WB_EA; } /* 7 ISB IDX */
+
+OP(13) { int tmp; RD_IDY_NP; WB_EA; SLO; WB_EA; } /* 7 SLO IDY */
+OP(33) { int tmp; RD_IDY_NP; WB_EA; RLA; WB_EA; } /* 7 RLA IDY */
+OP(53) { int tmp; RD_IDY_NP; WB_EA; SRE; WB_EA; } /* 7 SRE IDY */
+OP(73) { int tmp; RD_IDY_NP; WB_EA; RRA; WB_EA; } /* 7 RRA IDY */
+OP(93) { int tmp; EA_IDY_NP; SAH; WB_EA; } /* 5 SAH IDY */
+OP(b3) { int tmp; RD_IDY_P; LAX; } /* 5 LAX IDY page penalty */
+OP(d3) { int tmp; RD_IDY_NP; WB_EA; DCP; WB_EA; } /* 7 DCP IDY */
+OP(f3) { int tmp; RD_IDY_NP; WB_EA; ISB; WB_EA; } /* 7 ISB IDY */
+
+OP(04) { int tmp; RD_ZPG; NOP; } /* 3 NOP ZPG */
+OP(24) { int tmp; RD_ZPG; BIT; } /* 3 BIT ZPG */
+OP(44) { int tmp; RD_ZPG; NOP; } /* 3 NOP ZPG */
+OP(64) { int tmp; RD_ZPG; NOP; } /* 3 NOP ZPG */
+OP(84) { int tmp; STY; WR_ZPG; } /* 3 STY ZPG */
+OP(a4) { int tmp; RD_ZPG; LDY; } /* 3 LDY ZPG */
+OP(c4) { int tmp; RD_ZPG; CPY; } /* 3 CPY ZPG */
+OP(e4) { int tmp; RD_ZPG; CPX; } /* 3 CPX ZPG */
+
+OP(14) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(34) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(54) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(74) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(94) { int tmp; STY; WR_ZPX; } /* 4 STY ZPX */
+OP(b4) { int tmp; RD_ZPX; LDY; } /* 4 LDY ZPX */
+OP(d4) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(f4) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+
+OP(05) { int tmp; RD_ZPG; ORA; } /* 3 ORA ZPG */
+OP(25) { int tmp; RD_ZPG; AND; } /* 3 AND ZPG */
+OP(45) { int tmp; RD_ZPG; EOR; } /* 3 EOR ZPG */
+OP(65) { int tmp; RD_ZPG; ADC; } /* 3 ADC ZPG */
+OP(85) { int tmp; STA; WR_ZPG; } /* 3 STA ZPG */
+OP(a5) { int tmp; RD_ZPG; LDA; } /* 3 LDA ZPG */
+OP(c5) { int tmp; RD_ZPG; CMP; } /* 3 CMP ZPG */
+OP(e5) { int tmp; RD_ZPG; SBC; } /* 3 SBC ZPG */
+
+OP(15) { int tmp; RD_ZPX; ORA; } /* 4 ORA ZPX */
+OP(35) { int tmp; RD_ZPX; AND; } /* 4 AND ZPX */
+OP(55) { int tmp; RD_ZPX; EOR; } /* 4 EOR ZPX */
+OP(75) { int tmp; RD_ZPX; ADC; } /* 4 ADC ZPX */
+OP(95) { int tmp; STA; WR_ZPX; } /* 4 STA ZPX */
+OP(b5) { int tmp; RD_ZPX; LDA; } /* 4 LDA ZPX */
+OP(d5) { int tmp; RD_ZPX; CMP; } /* 4 CMP ZPX */
+OP(f5) { int tmp; RD_ZPX; SBC; } /* 4 SBC ZPX */
+
+OP(06) { int tmp; RD_ZPG; WB_EA; ASL; WB_EA; } /* 5 ASL ZPG */
+OP(26) { int tmp; RD_ZPG; WB_EA; ROL; WB_EA; } /* 5 ROL ZPG */
+OP(46) { int tmp; RD_ZPG; WB_EA; LSR; WB_EA; } /* 5 LSR ZPG */
+OP(66) { int tmp; RD_ZPG; WB_EA; ROR; WB_EA; } /* 5 ROR ZPG */
+OP(86) { int tmp; STX; WR_ZPG; } /* 3 STX ZPG */
+OP(a6) { int tmp; RD_ZPG; LDX; } /* 3 LDX ZPG */
+OP(c6) { int tmp; RD_ZPG; WB_EA; DEC; WB_EA; } /* 5 DEC ZPG */
+OP(e6) { int tmp; RD_ZPG; WB_EA; INC; WB_EA; } /* 5 INC ZPG */
+
+OP(16) { int tmp; RD_ZPX; WB_EA; ASL; WB_EA; } /* 6 ASL ZPX */
+OP(36) { int tmp; RD_ZPX; WB_EA; ROL; WB_EA; } /* 6 ROL ZPX */
+OP(56) { int tmp; RD_ZPX; WB_EA; LSR; WB_EA; } /* 6 LSR ZPX */
+OP(76) { int tmp; RD_ZPX; WB_EA; ROR; WB_EA; } /* 6 ROR ZPX */
+OP(96) { int tmp; STX; WR_ZPY; } /* 4 STX ZPY */
+OP(b6) { int tmp; RD_ZPY; LDX; } /* 4 LDX ZPY */
+OP(d6) { int tmp; RD_ZPX; WB_EA; DEC; WB_EA; } /* 6 DEC ZPX */
+OP(f6) { int tmp; RD_ZPX; WB_EA; INC; WB_EA; } /* 6 INC ZPX */
+
+OP(07) { int tmp; RD_ZPG; WB_EA; SLO; WB_EA; } /* 5 SLO ZPG */
+OP(27) { int tmp; RD_ZPG; WB_EA; RLA; WB_EA; } /* 5 RLA ZPG */
+OP(47) { int tmp; RD_ZPG; WB_EA; SRE; WB_EA; } /* 5 SRE ZPG */
+OP(67) { int tmp; RD_ZPG; WB_EA; RRA; WB_EA; } /* 5 RRA ZPG */
+OP(87) { int tmp; SAX; WR_ZPG; } /* 3 SAX ZPG */
+OP(a7) { int tmp; RD_ZPG; LAX; } /* 3 LAX ZPG */
+OP(c7) { int tmp; RD_ZPG; WB_EA; DCP; WB_EA; } /* 5 DCP ZPG */
+OP(e7) { int tmp; RD_ZPG; WB_EA; ISB; WB_EA; } /* 5 ISB ZPG */
+
+OP(17) { int tmp; RD_ZPX; WB_EA; SLO; WB_EA; } /* 6 SLO ZPX */
+OP(37) { int tmp; RD_ZPX; WB_EA; RLA; WB_EA; } /* 6 RLA ZPX */
+OP(57) { int tmp; RD_ZPX; WB_EA; SRE; WB_EA; } /* 6 SRE ZPX */
+OP(77) { int tmp; RD_ZPX; WB_EA; RRA; WB_EA; } /* 6 RRA ZPX */
+OP(97) { int tmp; SAX; WR_ZPY; } /* 4 SAX ZPY */
+OP(b7) { int tmp; RD_ZPY; LAX; } /* 4 LAX ZPY */
+OP(d7) { int tmp; RD_ZPX; WB_EA; DCP; WB_EA; } /* 6 DCP ZPX */
+OP(f7) { int tmp; RD_ZPX; WB_EA; ISB; WB_EA; } /* 6 ISB ZPX */
+
+OP(08) { RD_DUM; PHP; } /* 3 PHP */
+OP(28) { RD_DUM; PLP; } /* 4 PLP */
+OP(48) { RD_DUM; PHA; } /* 3 PHA */
+OP(68) { RD_DUM; PLA; } /* 4 PLA */
+OP(88) { RD_DUM; DEY; } /* 2 DEY */
+OP(a8) { RD_DUM; TAY; } /* 2 TAY */
+OP(c8) { RD_DUM; INY; } /* 2 INY */
+OP(e8) { RD_DUM; INX; } /* 2 INX */
+
+OP(18) { RD_DUM; CLC; } /* 2 CLC */
+OP(38) { RD_DUM; SEC; } /* 2 SEC */
+OP(58) { RD_DUM; CLI; } /* 2 CLI */
+OP(78) { RD_DUM; SEI; } /* 2 SEI */
+OP(98) { RD_DUM; TYA; } /* 2 TYA */
+OP(b8) { RD_DUM; CLV; } /* 2 CLV */
+OP(d8) { RD_DUM; CLD; } /* 2 CLD */
+OP(f8) { RD_DUM; SED; } /* 2 SED */
+
+OP(09) { int tmp; RD_IMM; ORA; } /* 2 ORA IMM */
+OP(29) { int tmp; RD_IMM; AND; } /* 2 AND IMM */
+OP(49) { int tmp; RD_IMM; EOR; } /* 2 EOR IMM */
+OP(69) { int tmp; RD_IMM; ADC; } /* 2 ADC IMM */
+OP(89) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+OP(a9) { int tmp; RD_IMM; LDA; } /* 2 LDA IMM */
+OP(c9) { int tmp; RD_IMM; CMP; } /* 2 CMP IMM */
+OP(e9) { int tmp; RD_IMM; SBC; } /* 2 SBC IMM */
+
+OP(19) { int tmp; RD_ABY_P; ORA; } /* 4 ORA ABY page penalty */
+OP(39) { int tmp; RD_ABY_P; AND; } /* 4 AND ABY page penalty */
+OP(59) { int tmp; RD_ABY_P; EOR; } /* 4 EOR ABY page penalty */
+OP(79) { int tmp; RD_ABY_P; ADC; } /* 4 ADC ABY page penalty */
+OP(99) { int tmp; STA; WR_ABY_NP; } /* 5 STA ABY */
+OP(b9) { int tmp; RD_ABY_P; LDA; } /* 4 LDA ABY page penalty */
+OP(d9) { int tmp; RD_ABY_P; CMP; } /* 4 CMP ABY page penalty */
+OP(f9) { int tmp; RD_ABY_P; SBC; } /* 4 SBC ABY page penalty */
+
+OP(0a) { int tmp; RD_DUM; RD_ACC; ASL; WB_ACC; } /* 2 ASL A */
+OP(2a) { int tmp; RD_DUM; RD_ACC; ROL; WB_ACC; } /* 2 ROL A */
+OP(4a) { int tmp; RD_DUM; RD_ACC; LSR; WB_ACC; } /* 2 LSR A */
+OP(6a) { int tmp; RD_DUM; RD_ACC; ROR; WB_ACC; } /* 2 ROR A */
+OP(8a) { RD_DUM; TXA; } /* 2 TXA */
+OP(aa) { RD_DUM; TAX; } /* 2 TAX */
+OP(ca) { RD_DUM; DEX; } /* 2 DEX */
+OP(ea) { RD_DUM; NOP; } /* 2 NOP */
+
+OP(1a) { RD_DUM; NOP; } /* 2 NOP */
+OP(3a) { RD_DUM; NOP; } /* 2 NOP */
+OP(5a) { RD_DUM; NOP; } /* 2 NOP */
+OP(7a) { RD_DUM; NOP; } /* 2 NOP */
+OP(9a) { RD_DUM; TXS; } /* 2 TXS */
+OP(ba) { RD_DUM; TSX; } /* 2 TSX */
+OP(da) { RD_DUM; NOP; } /* 2 NOP */
+OP(fa) { RD_DUM; NOP; } /* 2 NOP */
+
+OP(0b) { int tmp; RD_IMM; ANC; } /* 2 ANC IMM */
+OP(2b) { int tmp; RD_IMM; ANC; } /* 2 ANC IMM */
+OP(4b) { int tmp; RD_IMM; ASR; WB_ACC; } /* 2 ASR IMM */
+OP(6b) { int tmp; RD_IMM; ARR; WB_ACC; } /* 2 ARR IMM */
+OP(8b) { int tmp; RD_IMM; AXA; } /* 2 AXA IMM */
+OP(ab) { int tmp; RD_IMM; OAL; } /* 2 OAL IMM */
+OP(cb) { int tmp; RD_IMM; ASX; } /* 2 ASX IMM */
+OP(eb) { int tmp; RD_IMM; SBC; } /* 2 SBC IMM */
+
+OP(1b) { int tmp; RD_ABY_NP; WB_EA; SLO; WB_EA; } /* 7 SLO ABY */
+OP(3b) { int tmp; RD_ABY_NP; WB_EA; RLA; WB_EA; } /* 7 RLA ABY */
+OP(5b) { int tmp; RD_ABY_NP; WB_EA; SRE; WB_EA; } /* 7 SRE ABY */
+OP(7b) { int tmp; RD_ABY_NP; WB_EA; RRA; WB_EA; } /* 7 RRA ABY */
+OP(9b) { int tmp; EA_ABY_NP; SSH; WB_EA; } /* 5 SSH ABY */
+OP(bb) { int tmp; RD_ABY_P; AST; } /* 4 AST ABY page penalty */
+OP(db) { int tmp; RD_ABY_NP; WB_EA; DCP; WB_EA; } /* 7 DCP ABY */
+OP(fb) { int tmp; RD_ABY_NP; WB_EA; ISB; WB_EA; } /* 7 ISB ABY */
+
+OP(0c) { int tmp; RD_ABS; NOP; } /* 4 NOP ABS */
+OP(2c) { int tmp; RD_ABS; BIT; } /* 4 BIT ABS */
+OP(4c) { EA_ABS; JMP; } /* 3 JMP ABS */
+OP(6c) { int tmp; EA_IND; JMP; } /* 5 JMP IND */
+OP(8c) { int tmp; STY; WR_ABS; } /* 4 STY ABS */
+OP(ac) { int tmp; RD_ABS; LDY; } /* 4 LDY ABS */
+OP(cc) { int tmp; RD_ABS; CPY; } /* 4 CPY ABS */
+OP(ec) { int tmp; RD_ABS; CPX; } /* 4 CPX ABS */
+
+OP(1c) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(3c) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(5c) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(7c) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(9c) { int tmp; EA_ABX_NP; SYH; WB_EA; } /* 5 SYH ABX */
+OP(bc) { int tmp; RD_ABX_P; LDY; } /* 4 LDY ABX page penalty */
+OP(dc) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(fc) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+
+OP(0d) { int tmp; RD_ABS; ORA; } /* 4 ORA ABS */
+OP(2d) { int tmp; RD_ABS; AND; } /* 4 AND ABS */
+OP(4d) { int tmp; RD_ABS; EOR; } /* 4 EOR ABS */
+OP(6d) { int tmp; RD_ABS; ADC; } /* 4 ADC ABS */
+OP(8d) { int tmp; STA; WR_ABS; } /* 4 STA ABS */
+OP(ad) { int tmp; RD_ABS; LDA; } /* 4 LDA ABS */
+OP(cd) { int tmp; RD_ABS; CMP; } /* 4 CMP ABS */
+OP(ed) { int tmp; RD_ABS; SBC; } /* 4 SBC ABS */
+
+OP(1d) { int tmp; RD_ABX_P; ORA; } /* 4 ORA ABX page penalty */
+OP(3d) { int tmp; RD_ABX_P; AND; } /* 4 AND ABX page penalty */
+OP(5d) { int tmp; RD_ABX_P; EOR; } /* 4 EOR ABX page penalty */
+OP(7d) { int tmp; RD_ABX_P; ADC; } /* 4 ADC ABX page penalty */
+OP(9d) { int tmp; STA; WR_ABX_NP; } /* 5 STA ABX */
+OP(bd) { int tmp; RD_ABX_P; LDA; } /* 4 LDA ABX page penalty */
+OP(dd) { int tmp; RD_ABX_P; CMP; } /* 4 CMP ABX page penalty */
+OP(fd) { int tmp; RD_ABX_P; SBC; } /* 4 SBC ABX page penalty */
+
+OP(0e) { int tmp; RD_ABS; WB_EA; ASL; WB_EA; } /* 6 ASL ABS */
+OP(2e) { int tmp; RD_ABS; WB_EA; ROL; WB_EA; } /* 6 ROL ABS */
+OP(4e) { int tmp; RD_ABS; WB_EA; LSR; WB_EA; } /* 6 LSR ABS */
+OP(6e) { int tmp; RD_ABS; WB_EA; ROR; WB_EA; } /* 6 ROR ABS */
+OP(8e) { int tmp; STX; WR_ABS; } /* 4 STX ABS */
+OP(ae) { int tmp; RD_ABS; LDX; } /* 4 LDX ABS */
+OP(ce) { int tmp; RD_ABS; WB_EA; DEC; WB_EA; } /* 6 DEC ABS */
+OP(ee) { int tmp; RD_ABS; WB_EA; INC; WB_EA; } /* 6 INC ABS */
+
+OP(1e) { int tmp; RD_ABX_NP; WB_EA; ASL; WB_EA; } /* 7 ASL ABX */
+OP(3e) { int tmp; RD_ABX_NP; WB_EA; ROL; WB_EA; } /* 7 ROL ABX */
+OP(5e) { int tmp; RD_ABX_NP; WB_EA; LSR; WB_EA; } /* 7 LSR ABX */
+OP(7e) { int tmp; RD_ABX_NP; WB_EA; ROR; WB_EA; } /* 7 ROR ABX */
+OP(9e) { int tmp; EA_ABY_NP; SXH; WB_EA; } /* 5 SXH ABY */
+OP(be) { int tmp; RD_ABY_P; LDX; } /* 4 LDX ABY page penalty */
+OP(de) { int tmp; RD_ABX_NP; WB_EA; DEC; WB_EA; } /* 7 DEC ABX */
+OP(fe) { int tmp; RD_ABX_NP; WB_EA; INC; WB_EA; } /* 7 INC ABX */
+
+OP(0f) { int tmp; RD_ABS; WB_EA; SLO; WB_EA; } /* 6 SLO ABS */
+OP(2f) { int tmp; RD_ABS; WB_EA; RLA; WB_EA; } /* 6 RLA ABS */
+OP(4f) { int tmp; RD_ABS; WB_EA; SRE; WB_EA; } /* 6 SRE ABS */
+OP(6f) { int tmp; RD_ABS; WB_EA; RRA; WB_EA; } /* 6 RRA ABS */
+OP(8f) { int tmp; SAX; WR_ABS; } /* 4 SAX ABS */
+OP(af) { int tmp; RD_ABS; LAX; } /* 4 LAX ABS */
+OP(cf) { int tmp; RD_ABS; WB_EA; DCP; WB_EA; } /* 6 DCP ABS */
+OP(ef) { int tmp; RD_ABS; WB_EA; ISB; WB_EA; } /* 6 ISB ABS */
+
+OP(1f) { int tmp; RD_ABX_NP; WB_EA; SLO; WB_EA; } /* 7 SLO ABX */
+OP(3f) { int tmp; RD_ABX_NP; WB_EA; RLA; WB_EA; } /* 7 RLA ABX */
+OP(5f) { int tmp; RD_ABX_NP; WB_EA; SRE; WB_EA; } /* 7 SRE ABX */
+OP(7f) { int tmp; RD_ABX_NP; WB_EA; RRA; WB_EA; } /* 7 RRA ABX */
+OP(9f) { int tmp; EA_ABY_NP; SAH; WB_EA; } /* 5 SAH ABY */
+OP(bf) { int tmp; RD_ABY_P; LAX; } /* 4 LAX ABY page penalty */
+OP(df) { int tmp; RD_ABX_NP; WB_EA; DCP; WB_EA; } /* 7 DCP ABX */
+OP(ff) { int tmp; RD_ABX_NP; WB_EA; ISB; WB_EA; } /* 7 ISB ABX */
+
+/* and here's the array of function pointers */
+
+static void (*insn6502[0x100])(void) = {
+ m6502_00,m6502_01,m6502_02,m6502_03,m6502_04,m6502_05,m6502_06,m6502_07,
+ m6502_08,m6502_09,m6502_0a,m6502_0b,m6502_0c,m6502_0d,m6502_0e,m6502_0f,
+ m6502_10,m6502_11,m6502_12,m6502_13,m6502_14,m6502_15,m6502_16,m6502_17,
+ m6502_18,m6502_19,m6502_1a,m6502_1b,m6502_1c,m6502_1d,m6502_1e,m6502_1f,
+ m6502_20,m6502_21,m6502_22,m6502_23,m6502_24,m6502_25,m6502_26,m6502_27,
+ m6502_28,m6502_29,m6502_2a,m6502_2b,m6502_2c,m6502_2d,m6502_2e,m6502_2f,
+ m6502_30,m6502_31,m6502_32,m6502_33,m6502_34,m6502_35,m6502_36,m6502_37,
+ m6502_38,m6502_39,m6502_3a,m6502_3b,m6502_3c,m6502_3d,m6502_3e,m6502_3f,
+ m6502_40,m6502_41,m6502_42,m6502_43,m6502_44,m6502_45,m6502_46,m6502_47,
+ m6502_48,m6502_49,m6502_4a,m6502_4b,m6502_4c,m6502_4d,m6502_4e,m6502_4f,
+ m6502_50,m6502_51,m6502_52,m6502_53,m6502_54,m6502_55,m6502_56,m6502_57,
+ m6502_58,m6502_59,m6502_5a,m6502_5b,m6502_5c,m6502_5d,m6502_5e,m6502_5f,
+ m6502_60,m6502_61,m6502_62,m6502_63,m6502_64,m6502_65,m6502_66,m6502_67,
+ m6502_68,m6502_69,m6502_6a,m6502_6b,m6502_6c,m6502_6d,m6502_6e,m6502_6f,
+ m6502_70,m6502_71,m6502_72,m6502_73,m6502_74,m6502_75,m6502_76,m6502_77,
+ m6502_78,m6502_79,m6502_7a,m6502_7b,m6502_7c,m6502_7d,m6502_7e,m6502_7f,
+ m6502_80,m6502_81,m6502_82,m6502_83,m6502_84,m6502_85,m6502_86,m6502_87,
+ m6502_88,m6502_89,m6502_8a,m6502_8b,m6502_8c,m6502_8d,m6502_8e,m6502_8f,
+ m6502_90,m6502_91,m6502_92,m6502_93,m6502_94,m6502_95,m6502_96,m6502_97,
+ m6502_98,m6502_99,m6502_9a,m6502_9b,m6502_9c,m6502_9d,m6502_9e,m6502_9f,
+ m6502_a0,m6502_a1,m6502_a2,m6502_a3,m6502_a4,m6502_a5,m6502_a6,m6502_a7,
+ m6502_a8,m6502_a9,m6502_aa,m6502_ab,m6502_ac,m6502_ad,m6502_ae,m6502_af,
+ m6502_b0,m6502_b1,m6502_b2,m6502_b3,m6502_b4,m6502_b5,m6502_b6,m6502_b7,
+ m6502_b8,m6502_b9,m6502_ba,m6502_bb,m6502_bc,m6502_bd,m6502_be,m6502_bf,
+ m6502_c0,m6502_c1,m6502_c2,m6502_c3,m6502_c4,m6502_c5,m6502_c6,m6502_c7,
+ m6502_c8,m6502_c9,m6502_ca,m6502_cb,m6502_cc,m6502_cd,m6502_ce,m6502_cf,
+ m6502_d0,m6502_d1,m6502_d2,m6502_d3,m6502_d4,m6502_d5,m6502_d6,m6502_d7,
+ m6502_d8,m6502_d9,m6502_da,m6502_db,m6502_dc,m6502_dd,m6502_de,m6502_df,
+ m6502_e0,m6502_e1,m6502_e2,m6502_e3,m6502_e4,m6502_e5,m6502_e6,m6502_e7,
+ m6502_e8,m6502_e9,m6502_ea,m6502_eb,m6502_ec,m6502_ed,m6502_ee,m6502_ef,
+ m6502_f0,m6502_f1,m6502_f2,m6502_f3,m6502_f4,m6502_f5,m6502_f6,m6502_f7,
+ m6502_f8,m6502_f9,m6502_fa,m6502_fb,m6502_fc,m6502_fd,m6502_fe,m6502_ff
+};
+
diff --git a/src/emu/cpu/m6502/t6509.c b/src/emu/cpu/m6502/t6509.c
new file mode 100644
index 00000000000..71bcade3b42
--- /dev/null
+++ b/src/emu/cpu/m6502/t6509.c
@@ -0,0 +1,352 @@
+/*****************************************************************************
+ *
+ * tbl6509.c
+ * 6509 opcode functions and function pointer table
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * - Opcode information based on an Intel 386 '6510.asm' core
+ * written by R.F. van Ee (1993)
+ * - Cycle counts are guesswork :-)
+ *
+ *****************************************************************************/
+
+#undef OP
+#define OP(nn) INLINE void m6509_##nn(void)
+
+OP(00) { BRK; } /* 7 BRK */
+OP(20) { JSR; } /* 6 JSR */
+OP(40) { RTI; } /* 6 RTI */
+OP(60) { RTS; } /* 6 RTS */
+OP(80) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+OP(a0) { int tmp; RD_IMM; LDY; } /* 2 LDY IMM */
+OP(c0) { int tmp; RD_IMM; CPY; } /* 2 CPY IMM */
+OP(e0) { int tmp; RD_IMM; CPX; } /* 2 CPX IMM */
+
+OP(10) { int tmp; BPL; } /* 2-4 BPL REL */
+OP(30) { int tmp; BMI; } /* 2-4 BMI REL */
+OP(50) { int tmp; BVC; } /* 2-4 BVC REL */
+OP(70) { int tmp; BVS; } /* 2-4 BVS REL */
+OP(90) { int tmp; BCC; } /* 2-4 BCC REL */
+OP(b0) { int tmp; BCS; } /* 2-4 BCS REL */
+OP(d0) { int tmp; BNE; } /* 2-4 BNE REL */
+OP(f0) { int tmp; BEQ; } /* 2-4 BEQ REL */
+
+OP(01) { int tmp; RD_IDX; ORA; } /* 6 ORA IDX */
+OP(21) { int tmp; RD_IDX; AND; } /* 6 AND IDX */
+OP(41) { int tmp; RD_IDX; EOR; } /* 6 EOR IDX */
+OP(61) { int tmp; RD_IDX; ADC; } /* 6 ADC IDX */
+OP(81) { int tmp; STA; WR_IDX; } /* 6 STA IDX */
+OP(a1) { int tmp; RD_IDX; LDA; } /* 6 LDA IDX */
+OP(c1) { int tmp; RD_IDX; CMP; } /* 6 CMP IDX */
+OP(e1) { int tmp; RD_IDX; SBC; } /* 6 SBC IDX */
+
+OP(11) { int tmp; RD_IDY_P; ORA; } /* 5 ORA IDY page penalty */
+OP(31) { int tmp; RD_IDY_P; AND; } /* 5 AND IDY page penalty */
+OP(51) { int tmp; RD_IDY_P; EOR; } /* 5 EOR IDY page penalty */
+OP(71) { int tmp; RD_IDY_P; ADC; } /* 5 ADC IDY page penalty */
+OP(91) { int tmp; STA; WR_IDY_6509; } /* 6 STA IDY */
+OP(b1) { int tmp; RD_IDY_6509; LDA; } /* 5 LDA IDY page penalty */
+OP(d1) { int tmp; RD_IDY_P; CMP; } /* 5 CMP IDY page penalty */
+OP(f1) { int tmp; RD_IDY_P; SBC; } /* 5 SBC IDY page penalty */
+
+OP(02) { KIL; } /* 1 KIL */
+OP(22) { KIL; } /* 1 KIL */
+OP(42) { KIL; } /* 1 KIL */
+OP(62) { KIL; } /* 1 KIL */
+OP(82) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+OP(a2) { int tmp; RD_IMM; LDX; } /* 2 LDX IMM */
+OP(c2) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+OP(e2) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+
+OP(12) { KIL; } /* 1 KIL */
+OP(32) { KIL; } /* 1 KIL */
+OP(52) { KIL; } /* 1 KIL */
+OP(72) { KIL; } /* 1 KIL */
+OP(92) { KIL; } /* 1 KIL */
+OP(b2) { KIL; } /* 1 KIL */
+OP(d2) { KIL; } /* 1 KIL */
+OP(f2) { KIL; } /* 1 KIL */
+
+OP(03) { int tmp; RD_IDX; WB_EA; SLO; WB_EA; } /* 7 SLO IDX */
+OP(23) { int tmp; RD_IDX; WB_EA; RLA; WB_EA; } /* 7 RLA IDX */
+OP(43) { int tmp; RD_IDX; WB_EA; SRE; WB_EA; } /* 7 SRE IDX */
+OP(63) { int tmp; RD_IDX; WB_EA; RRA; WB_EA; } /* 7 RRA IDX */
+OP(83) { int tmp; SAX; WR_IDX; } /* 6 SAX IDX */
+OP(a3) { int tmp; RD_IDX; LAX; } /* 6 LAX IDX */
+OP(c3) { int tmp; RD_IDX; WB_EA; DCP; WB_EA; } /* 7 DCP IDX */
+OP(e3) { int tmp; RD_IDX; WB_EA; ISB; WB_EA; } /* 7 ISB IDX */
+
+OP(13) { int tmp; RD_IDY_NP; WB_EA; SLO; WB_EA; } /* 7 SLO IDY */
+OP(33) { int tmp; RD_IDY_NP; WB_EA; RLA; WB_EA; } /* 7 RLA IDY */
+OP(53) { int tmp; RD_IDY_NP; WB_EA; SRE; WB_EA; } /* 7 SRE IDY */
+OP(73) { int tmp; RD_IDY_NP; WB_EA; RRA; WB_EA; } /* 7 RRA IDY */
+OP(93) { int tmp; EA_IDY_NP; SAH; WB_EA; } /* 5 SAH IDY */
+OP(b3) { int tmp; RD_IDY_P; LAX; } /* 5 LAX IDY page penalty */
+OP(d3) { int tmp; RD_IDY_NP; WB_EA; DCP; WB_EA; } /* 7 DCP IDY */
+OP(f3) { int tmp; RD_IDY_NP; WB_EA; ISB; WB_EA; } /* 7 ISB IDY */
+
+OP(04) { int tmp; RD_ZPG; NOP; } /* 3 NOP ZPG */
+OP(24) { int tmp; RD_ZPG; BIT; } /* 3 BIT ZPG */
+OP(44) { int tmp; RD_ZPG; NOP; } /* 3 NOP ZPG */
+OP(64) { int tmp; RD_ZPG; NOP; } /* 3 NOP ZPG */
+OP(84) { int tmp; STY; WR_ZPG; } /* 3 STY ZPG */
+OP(a4) { int tmp; RD_ZPG; LDY; } /* 3 LDY ZPG */
+OP(c4) { int tmp; RD_ZPG; CPY; } /* 3 CPY ZPG */
+OP(e4) { int tmp; RD_ZPG; CPX; } /* 3 CPX ZPG */
+
+OP(14) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(34) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(54) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(74) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(94) { int tmp; STY; WR_ZPX; } /* 4 STY ZPX */
+OP(b4) { int tmp; RD_ZPX; LDY; } /* 4 LDY ZPX */
+OP(d4) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+OP(f4) { int tmp; RD_ZPX; NOP; } /* 4 NOP ZPX */
+
+OP(05) { int tmp; RD_ZPG; ORA; } /* 3 ORA ZPG */
+OP(25) { int tmp; RD_ZPG; AND; } /* 3 AND ZPG */
+OP(45) { int tmp; RD_ZPG; EOR; } /* 3 EOR ZPG */
+OP(65) { int tmp; RD_ZPG; ADC; } /* 3 ADC ZPG */
+OP(85) { int tmp; STA; WR_ZPG; } /* 3 STA ZPG */
+OP(a5) { int tmp; RD_ZPG; LDA; } /* 3 LDA ZPG */
+OP(c5) { int tmp; RD_ZPG; CMP; } /* 3 CMP ZPG */
+OP(e5) { int tmp; RD_ZPG; SBC; } /* 3 SBC ZPG */
+
+OP(15) { int tmp; RD_ZPX; ORA; } /* 4 ORA ZPX */
+OP(35) { int tmp; RD_ZPX; AND; } /* 4 AND ZPX */
+OP(55) { int tmp; RD_ZPX; EOR; } /* 4 EOR ZPX */
+OP(75) { int tmp; RD_ZPX; ADC; } /* 4 ADC ZPX */
+OP(95) { int tmp; STA; WR_ZPX; } /* 4 STA ZPX */
+OP(b5) { int tmp; RD_ZPX; LDA; } /* 4 LDA ZPX */
+OP(d5) { int tmp; RD_ZPX; CMP; } /* 4 CMP ZPX */
+OP(f5) { int tmp; RD_ZPX; SBC; } /* 4 SBC ZPX */
+
+OP(06) { int tmp; RD_ZPG; WB_EA; ASL; WB_EA; } /* 5 ASL ZPG */
+OP(26) { int tmp; RD_ZPG; WB_EA; ROL; WB_EA; } /* 5 ROL ZPG */
+OP(46) { int tmp; RD_ZPG; WB_EA; LSR; WB_EA; } /* 5 LSR ZPG */
+OP(66) { int tmp; RD_ZPG; WB_EA; ROR; WB_EA; } /* 5 ROR ZPG */
+OP(86) { int tmp; STX; WR_ZPG; } /* 3 STX ZPG */
+OP(a6) { int tmp; RD_ZPG; LDX; } /* 3 LDX ZPG */
+OP(c6) { int tmp; RD_ZPG; WB_EA; DEC; WB_EA; } /* 5 DEC ZPG */
+OP(e6) { int tmp; RD_ZPG; WB_EA; INC; WB_EA; } /* 5 INC ZPG */
+
+OP(16) { int tmp; RD_ZPX; WB_EA; ASL; WB_EA; } /* 6 ASL ZPX */
+OP(36) { int tmp; RD_ZPX; WB_EA; ROL; WB_EA; } /* 6 ROL ZPX */
+OP(56) { int tmp; RD_ZPX; WB_EA; LSR; WB_EA; } /* 6 LSR ZPX */
+OP(76) { int tmp; RD_ZPX; WB_EA; ROR; WB_EA; } /* 6 ROR ZPX */
+OP(96) { int tmp; STX; WR_ZPY; } /* 4 STX ZPY */
+OP(b6) { int tmp; RD_ZPY; LDX; } /* 4 LDX ZPY */
+OP(d6) { int tmp; RD_ZPX; WB_EA; DEC; WB_EA; } /* 6 DEC ZPX */
+OP(f6) { int tmp; RD_ZPX; WB_EA; INC; WB_EA; } /* 6 INC ZPX */
+
+OP(07) { int tmp; RD_ZPG; WB_EA; SLO; WB_EA; } /* 5 SLO ZPG */
+OP(27) { int tmp; RD_ZPG; WB_EA; RLA; WB_EA; } /* 5 RLA ZPG */
+OP(47) { int tmp; RD_ZPG; WB_EA; SRE; WB_EA; } /* 5 SRE ZPG */
+OP(67) { int tmp; RD_ZPG; WB_EA; RRA; WB_EA; } /* 5 RRA ZPG */
+OP(87) { int tmp; SAX; WR_ZPG; } /* 3 SAX ZPG */
+OP(a7) { int tmp; RD_ZPG; LAX; } /* 3 LAX ZPG */
+OP(c7) { int tmp; RD_ZPG; WB_EA; DCP; WB_EA; } /* 5 DCP ZPG */
+OP(e7) { int tmp; RD_ZPG; WB_EA; ISB; WB_EA; } /* 5 ISB ZPG */
+
+OP(17) { int tmp; RD_ZPX; WB_EA; SLO; WB_EA; } /* 6 SLO ZPX */
+OP(37) { int tmp; RD_ZPX; WB_EA; RLA; WB_EA; } /* 6 RLA ZPX */
+OP(57) { int tmp; RD_ZPX; WB_EA; SRE; WB_EA; } /* 6 SRE ZPX */
+OP(77) { int tmp; RD_ZPX; WB_EA; RRA; WB_EA; } /* 6 RRA ZPX */
+OP(97) { int tmp; SAX; WR_ZPY; } /* 4 SAX ZPY */
+OP(b7) { int tmp; RD_ZPY; LAX; } /* 4 LAX ZPY */
+OP(d7) { int tmp; RD_ZPX; WB_EA; DCP; WB_EA; } /* 6 DCP ZPX */
+OP(f7) { int tmp; RD_ZPX; WB_EA; ISB; WB_EA; } /* 6 ISB ZPX */
+
+OP(08) { RD_DUM; PHP; } /* 3 PHP */
+OP(28) { RD_DUM; PLP; } /* 4 PLP */
+OP(48) { RD_DUM; PHA; } /* 3 PHA */
+OP(68) { RD_DUM; PLA; } /* 4 PLA */
+OP(88) { RD_DUM; DEY; } /* 2 DEY */
+OP(a8) { RD_DUM; TAY; } /* 2 TAY */
+OP(c8) { RD_DUM; INY; } /* 2 INY */
+OP(e8) { RD_DUM; INX; } /* 2 INX */
+
+OP(18) { RD_DUM; CLC; } /* 2 CLC */
+OP(38) { RD_DUM; SEC; } /* 2 SEC */
+OP(58) { RD_DUM; CLI; } /* 2 CLI */
+OP(78) { RD_DUM; SEI; } /* 2 SEI */
+OP(98) { RD_DUM; TYA; } /* 2 TYA */
+OP(b8) { RD_DUM; CLV; } /* 2 CLV */
+OP(d8) { RD_DUM; CLD; } /* 2 CLD */
+OP(f8) { RD_DUM; SED; } /* 2 SED */
+
+OP(09) { int tmp; RD_IMM; ORA; } /* 2 ORA IMM */
+OP(29) { int tmp; RD_IMM; AND; } /* 2 AND IMM */
+OP(49) { int tmp; RD_IMM; EOR; } /* 2 EOR IMM */
+OP(69) { int tmp; RD_IMM; ADC; } /* 2 ADC IMM */
+OP(89) { int tmp; RD_IMM; NOP; } /* 2 NOP IMM */
+OP(a9) { int tmp; RD_IMM; LDA; } /* 2 LDA IMM */
+OP(c9) { int tmp; RD_IMM; CMP; } /* 2 CMP IMM */
+OP(e9) { int tmp; RD_IMM; SBC; } /* 2 SBC IMM */
+
+OP(19) { int tmp; RD_ABY_P; ORA; } /* 4 ORA ABY page penalty */
+OP(39) { int tmp; RD_ABY_P; AND; } /* 4 AND ABY page penalty */
+OP(59) { int tmp; RD_ABY_P; EOR; } /* 4 EOR ABY page penalty */
+OP(79) { int tmp; RD_ABY_P; ADC; } /* 4 ADC ABY page penalty */
+OP(99) { int tmp; STA; WR_ABY_NP; } /* 5 STA ABY */
+OP(b9) { int tmp; RD_ABY_P; LDA; } /* 4 LDA ABY page penalty */
+OP(d9) { int tmp; RD_ABY_P; CMP; } /* 4 CMP ABY page penalty */
+OP(f9) { int tmp; RD_ABY_P; SBC; } /* 4 SBC ABY page penalty */
+
+OP(0a) { int tmp; RD_DUM; RD_ACC; ASL; WB_ACC; } /* 2 ASL A */
+OP(2a) { int tmp; RD_DUM; RD_ACC; ROL; WB_ACC; } /* 2 ROL A */
+OP(4a) { int tmp; RD_DUM; RD_ACC; LSR; WB_ACC; } /* 2 LSR A */
+OP(6a) { int tmp; RD_DUM; RD_ACC; ROR; WB_ACC; } /* 2 ROR A */
+OP(8a) { RD_DUM; TXA; } /* 2 TXA */
+OP(aa) { RD_DUM; TAX; } /* 2 TAX */
+OP(ca) { RD_DUM; DEX; } /* 2 DEX */
+OP(ea) { RD_DUM; NOP; } /* 2 NOP */
+
+OP(1a) { RD_DUM; NOP; } /* 2 NOP */
+OP(3a) { RD_DUM; NOP; } /* 2 NOP */
+OP(5a) { RD_DUM; NOP; } /* 2 NOP */
+OP(7a) { RD_DUM; NOP; } /* 2 NOP */
+OP(9a) { RD_DUM; TXS; } /* 2 TXS */
+OP(ba) { RD_DUM; TSX; } /* 2 TSX */
+OP(da) { RD_DUM; NOP; } /* 2 NOP */
+OP(fa) { RD_DUM; NOP; } /* 2 NOP */
+
+OP(0b) { int tmp; RD_IMM; ANC; } /* 2 ANC IMM */
+OP(2b) { int tmp; RD_IMM; ANC; } /* 2 ANC IMM */
+OP(4b) { int tmp; RD_IMM; ASR; WB_ACC; } /* 2 ASR IMM */
+OP(6b) { int tmp; RD_IMM; ARR; WB_ACC; } /* 2 ARR IMM */
+OP(8b) { int tmp; RD_IMM; AXA; } /* 2 AXA IMM */
+OP(ab) { int tmp; RD_IMM; OAL; } /* 2 OAL IMM */
+OP(cb) { int tmp; RD_IMM; ASX; } /* 2 ASX IMM */
+OP(eb) { int tmp; RD_IMM; SBC; } /* 2 SBC IMM */
+
+OP(1b) { int tmp; RD_ABY_NP; WB_EA; SLO; WB_EA; } /* 7 SLO ABY */
+OP(3b) { int tmp; RD_ABY_NP; WB_EA; RLA; WB_EA; } /* 7 RLA ABY */
+OP(5b) { int tmp; RD_ABY_NP; WB_EA; SRE; WB_EA; } /* 7 SRE ABY */
+OP(7b) { int tmp; RD_ABY_NP; WB_EA; RRA; WB_EA; } /* 7 RRA ABY */
+OP(9b) { int tmp; EA_ABY_NP; SSH; WB_EA; } /* 5 SSH ABY */
+OP(bb) { int tmp; RD_ABY_P; AST; } /* 4 AST ABY page penalty */
+OP(db) { int tmp; RD_ABY_NP; WB_EA; DCP; WB_EA; } /* 7 DCP ABY */
+OP(fb) { int tmp; RD_ABY_NP; WB_EA; ISB; WB_EA; } /* 7 ISB ABY */
+
+OP(0c) { int tmp; RD_ABS; NOP; } /* 4 NOP ABS */
+OP(2c) { int tmp; RD_ABS; BIT; } /* 4 BIT ABS */
+OP(4c) { EA_ABS; JMP; } /* 3 JMP ABS */
+OP(6c) { int tmp; EA_IND; JMP; } /* 5 JMP IND */
+OP(8c) { int tmp; STY; WR_ABS; } /* 4 STY ABS */
+OP(ac) { int tmp; RD_ABS; LDY; } /* 4 LDY ABS */
+OP(cc) { int tmp; RD_ABS; CPY; } /* 4 CPY ABS */
+OP(ec) { int tmp; RD_ABS; CPX; } /* 4 CPX ABS */
+
+OP(1c) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(3c) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(5c) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(7c) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(9c) { int tmp; EA_ABX_NP; SYH; WB_EA; } /* 5 SYH ABX */
+OP(bc) { int tmp; RD_ABX_P; LDY; } /* 4 LDY ABX page penalty */
+OP(dc) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+OP(fc) { int tmp; RD_ABX_P; NOP; } /* 4 NOP ABX page penalty */
+
+OP(0d) { int tmp; RD_ABS; ORA; } /* 4 ORA ABS */
+OP(2d) { int tmp; RD_ABS; AND; } /* 4 AND ABS */
+OP(4d) { int tmp; RD_ABS; EOR; } /* 4 EOR ABS */
+OP(6d) { int tmp; RD_ABS; ADC; } /* 4 ADC ABS */
+OP(8d) { int tmp; STA; WR_ABS; } /* 4 STA ABS */
+OP(ad) { int tmp; RD_ABS; LDA; } /* 4 LDA ABS */
+OP(cd) { int tmp; RD_ABS; CMP; } /* 4 CMP ABS */
+OP(ed) { int tmp; RD_ABS; SBC; } /* 4 SBC ABS */
+
+OP(1d) { int tmp; RD_ABX_P; ORA; } /* 4 ORA ABX page penalty */
+OP(3d) { int tmp; RD_ABX_P; AND; } /* 4 AND ABX page penalty */
+OP(5d) { int tmp; RD_ABX_P; EOR; } /* 4 EOR ABX page penalty */
+OP(7d) { int tmp; RD_ABX_P; ADC; } /* 4 ADC ABX page penalty */
+OP(9d) { int tmp; STA; WR_ABX_NP; } /* 5 STA ABX */
+OP(bd) { int tmp; RD_ABX_P; LDA; } /* 4 LDA ABX page penalty */
+OP(dd) { int tmp; RD_ABX_P; CMP; } /* 4 CMP ABX page penalty */
+OP(fd) { int tmp; RD_ABX_P; SBC; } /* 4 SBC ABX page penalty */
+
+OP(0e) { int tmp; RD_ABS; WB_EA; ASL; WB_EA; } /* 6 ASL ABS */
+OP(2e) { int tmp; RD_ABS; WB_EA; ROL; WB_EA; } /* 6 ROL ABS */
+OP(4e) { int tmp; RD_ABS; WB_EA; LSR; WB_EA; } /* 6 LSR ABS */
+OP(6e) { int tmp; RD_ABS; WB_EA; ROR; WB_EA; } /* 6 ROR ABS */
+OP(8e) { int tmp; STX; WR_ABS; } /* 4 STX ABS */
+OP(ae) { int tmp; RD_ABS; LDX; } /* 4 LDX ABS */
+OP(ce) { int tmp; RD_ABS; WB_EA; DEC; WB_EA; } /* 6 DEC ABS */
+OP(ee) { int tmp; RD_ABS; WB_EA; INC; WB_EA; } /* 6 INC ABS */
+
+OP(1e) { int tmp; RD_ABX_NP; WB_EA; ASL; WB_EA; } /* 7 ASL ABX */
+OP(3e) { int tmp; RD_ABX_NP; WB_EA; ROL; WB_EA; } /* 7 ROL ABX */
+OP(5e) { int tmp; RD_ABX_NP; WB_EA; LSR; WB_EA; } /* 7 LSR ABX */
+OP(7e) { int tmp; RD_ABX_NP; WB_EA; ROR; WB_EA; } /* 7 ROR ABX */
+OP(9e) { int tmp; EA_ABY_NP; SXH; WB_EA; } /* 5 SXH ABY */
+OP(be) { int tmp; RD_ABY_P; LDX; } /* 4 LDX ABY page penalty */
+OP(de) { int tmp; RD_ABX_NP; WB_EA; DEC; WB_EA; } /* 7 DEC ABX */
+OP(fe) { int tmp; RD_ABX_NP; WB_EA; INC; WB_EA; } /* 7 INC ABX */
+
+OP(0f) { int tmp; RD_ABS; WB_EA; SLO; WB_EA; } /* 6 SLO ABS */
+OP(2f) { int tmp; RD_ABS; WB_EA; RLA; WB_EA; } /* 6 RLA ABS */
+OP(4f) { int tmp; RD_ABS; WB_EA; SRE; WB_EA; } /* 6 SRE ABS */
+OP(6f) { int tmp; RD_ABS; WB_EA; RRA; WB_EA; } /* 6 RRA ABS */
+OP(8f) { int tmp; SAX; WR_ABS; } /* 4 SAX ABS */
+OP(af) { int tmp; RD_ABS; LAX; } /* 4 LAX ABS */
+OP(cf) { int tmp; RD_ABS; WB_EA; DCP; WB_EA; } /* 6 DCP ABS */
+OP(ef) { int tmp; RD_ABS; WB_EA; ISB; WB_EA; } /* 6 ISB ABS */
+
+OP(1f) { int tmp; RD_ABX_NP; WB_EA; SLO; WB_EA; } /* 7 SLO ABX */
+OP(3f) { int tmp; RD_ABX_NP; WB_EA; RLA; WB_EA; } /* 7 RLA ABX */
+OP(5f) { int tmp; RD_ABX_NP; WB_EA; SRE; WB_EA; } /* 7 SRE ABX */
+OP(7f) { int tmp; RD_ABX_NP; WB_EA; RRA; WB_EA; } /* 7 RRA ABX */
+OP(9f) { int tmp; EA_ABY_NP; SAH; WB_EA; } /* 5 SAH ABY */
+OP(bf) { int tmp; RD_ABY_P; LAX; } /* 4 LAX ABY page penalty */
+OP(df) { int tmp; RD_ABX_NP; WB_EA; DCP; WB_EA; } /* 7 DCP ABX */
+OP(ff) { int tmp; RD_ABX_NP; WB_EA; ISB; WB_EA; } /* 7 ISB ABX */
+
+static void (*insn6509[0x100])(void) = {
+ m6509_00,m6509_01,m6509_02,m6509_03,m6509_04,m6509_05,m6509_06,m6509_07,
+ m6509_08,m6509_09,m6509_0a,m6509_0b,m6509_0c,m6509_0d,m6509_0e,m6509_0f,
+ m6509_10,m6509_11,m6509_12,m6509_13,m6509_14,m6509_15,m6509_16,m6509_17,
+ m6509_18,m6509_19,m6509_1a,m6509_1b,m6509_1c,m6509_1d,m6509_1e,m6509_1f,
+ m6509_20,m6509_21,m6509_22,m6509_23,m6509_24,m6509_25,m6509_26,m6509_27,
+ m6509_28,m6509_29,m6509_2a,m6509_2b,m6509_2c,m6509_2d,m6509_2e,m6509_2f,
+ m6509_30,m6509_31,m6509_32,m6509_33,m6509_34,m6509_35,m6509_36,m6509_37,
+ m6509_38,m6509_39,m6509_3a,m6509_3b,m6509_3c,m6509_3d,m6509_3e,m6509_3f,
+ m6509_40,m6509_41,m6509_42,m6509_43,m6509_44,m6509_45,m6509_46,m6509_47,
+ m6509_48,m6509_49,m6509_4a,m6509_4b,m6509_4c,m6509_4d,m6509_4e,m6509_4f,
+ m6509_50,m6509_51,m6509_52,m6509_53,m6509_54,m6509_55,m6509_56,m6509_57,
+ m6509_58,m6509_59,m6509_5a,m6509_5b,m6509_5c,m6509_5d,m6509_5e,m6509_5f,
+ m6509_60,m6509_61,m6509_62,m6509_63,m6509_64,m6509_65,m6509_66,m6509_67,
+ m6509_68,m6509_69,m6509_6a,m6509_6b,m6509_6c,m6509_6d,m6509_6e,m6509_6f,
+ m6509_70,m6509_71,m6509_72,m6509_73,m6509_74,m6509_75,m6509_76,m6509_77,
+ m6509_78,m6509_79,m6509_7a,m6509_7b,m6509_7c,m6509_7d,m6509_7e,m6509_7f,
+ m6509_80,m6509_81,m6509_82,m6509_83,m6509_84,m6509_85,m6509_86,m6509_87,
+ m6509_88,m6509_89,m6509_8a,m6509_8b,m6509_8c,m6509_8d,m6509_8e,m6509_8f,
+ m6509_90,m6509_91,m6509_92,m6509_93,m6509_94,m6509_95,m6509_96,m6509_97,
+ m6509_98,m6509_99,m6509_9a,m6509_9b,m6509_9c,m6509_9d,m6509_9e,m6509_9f,
+ m6509_a0,m6509_a1,m6509_a2,m6509_a3,m6509_a4,m6509_a5,m6509_a6,m6509_a7,
+ m6509_a8,m6509_a9,m6509_aa,m6509_ab,m6509_ac,m6509_ad,m6509_ae,m6509_af,
+ m6509_b0,m6509_b1,m6509_b2,m6509_b3,m6509_b4,m6509_b5,m6509_b6,m6509_b7,
+ m6509_b8,m6509_b9,m6509_ba,m6509_bb,m6509_bc,m6509_bd,m6509_be,m6509_bf,
+ m6509_c0,m6509_c1,m6509_c2,m6509_c3,m6509_c4,m6509_c5,m6509_c6,m6509_c7,
+ m6509_c8,m6509_c9,m6509_ca,m6509_cb,m6509_cc,m6509_cd,m6509_ce,m6509_cf,
+ m6509_d0,m6509_d1,m6509_d2,m6509_d3,m6509_d4,m6509_d5,m6509_d6,m6509_d7,
+ m6509_d8,m6509_d9,m6509_da,m6509_db,m6509_dc,m6509_dd,m6509_de,m6509_df,
+ m6509_e0,m6509_e1,m6509_e2,m6509_e3,m6509_e4,m6509_e5,m6509_e6,m6509_e7,
+ m6509_e8,m6509_e9,m6509_ea,m6509_eb,m6509_ec,m6509_ed,m6509_ee,m6509_ef,
+ m6509_f0,m6509_f1,m6509_f2,m6509_f3,m6509_f4,m6509_f5,m6509_f6,m6509_f7,
+ m6509_f8,m6509_f9,m6509_fa,m6509_fb,m6509_fc,m6509_fd,m6509_fe,m6509_ff
+};
+
+
diff --git a/src/emu/cpu/m6502/t6510.c b/src/emu/cpu/m6502/t6510.c
new file mode 100644
index 00000000000..21aea777b31
--- /dev/null
+++ b/src/emu/cpu/m6502/t6510.c
@@ -0,0 +1,27 @@
+/*****************************************************************************
+ *
+ * tbl6510.c
+ * 6510 opcode functions and function pointer table
+ *
+ * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * - Opcode information based on an Intel 386 '6510.asm' core
+ * written by R.F. van Ee (1993)
+ * - Cycle counts are guesswork :-)
+ *
+ *****************************************************************************/
+
+#define insn6510 insn6502
+
diff --git a/src/emu/cpu/m6502/t65c02.c b/src/emu/cpu/m6502/t65c02.c
new file mode 100644
index 00000000000..a40876e3c76
--- /dev/null
+++ b/src/emu/cpu/m6502/t65c02.c
@@ -0,0 +1,410 @@
+/*****************************************************************************
+ *
+ * tbl65c02.c
+ * 65c02 opcode functions and function pointer table
+ *
+ * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * Not sure about the timing of all the extra (undocumented) NOP instructions.
+ * Core may need to be split up into two 65c02 core. Not all versions supported
+ * the bit operation RMB/SMB/etc.
+ *
+ *****************************************************************************/
+
+#undef OP
+#define OP(nn) INLINE void m65c02_##nn(void)
+
+/*****************************************************************************
+ *****************************************************************************
+ *
+ * Implementations for 65C02 opcodes
+ *
+ * There are a few slight differences between Rockwell and WDC 65C02 CPUs.
+ * The absolute indexed addressing mode RMW instructions take 6 cycles on
+ * WDC 65C02 CPU but 7 cycles on a regular 6502 and a Rockwell 65C02 CPU.
+ * TODO: Implement STP and WAI for wdc65c02.
+ *
+ *****************************************************************************
+ * op temp cycles rdmem opc wrmem ********************/
+OP(00) { BRK_C02; } /* 7 BRK */
+OP(20) { JSR; } /* 6 JSR */
+OP(40) { RTI; } /* 6 RTI */
+OP(60) { RTS; } /* 6 RTS */
+OP(80) { int tmp; BRA_C02( 1 ); } /* 3-4 BRA REL */
+OP(a0) { int tmp; RD_IMM; LDY; } /* 2 LDY IMM */
+OP(c0) { int tmp; RD_IMM; CPY; } /* 2 CPY IMM */
+OP(e0) { int tmp; RD_IMM; CPX; } /* 2 CPX IMM */
+
+OP(10) { int tmp; BRA_C02( ! ( P & F_N ) ); } /* 2-4 BPL REL */
+OP(30) { int tmp; BRA_C02( ( P & F_N ) ); } /* 2-4 BMI REL */
+OP(50) { int tmp; BRA_C02( ! ( P & F_V ) ); } /* 2-4 BVC REL */
+OP(70) { int tmp; BRA_C02( ( P & F_V ) ); } /* 2-4 BVS REL */
+OP(90) { int tmp; BRA_C02( ! ( P & F_C ) ); } /* 2-4 BCC REL */
+OP(b0) { int tmp; BRA_C02( ( P & F_C ) ); } /* 2-4 BCS REL */
+OP(d0) { int tmp; BRA_C02( ! ( P & F_Z ) ); } /* 2-4 BNE REL */
+OP(f0) { int tmp; BRA_C02( ( P & F_Z ) ); } /* 2-4 BEQ REL */
+
+OP(01) { int tmp; RD_IDX; ORA; } /* 6 ORA IDX */
+OP(21) { int tmp; RD_IDX; AND; } /* 6 AND IDX */
+OP(41) { int tmp; RD_IDX; EOR; } /* 6 EOR IDX */
+OP(61) { int tmp; RD_IDX; ADC_C02; } /* 6/7 ADC IDX */
+OP(81) { int tmp; STA; WR_IDX; } /* 6 STA IDX */
+OP(a1) { int tmp; RD_IDX; LDA; } /* 6 LDA IDX */
+OP(c1) { int tmp; RD_IDX; CMP; } /* 6 CMP IDX */
+OP(e1) { int tmp; RD_IDX; SBC_C02; } /* 6/7 SBC IDX */
+
+OP(11) { int tmp; RD_IDY_C02_P; ORA; } /* 5 ORA IDY page penalty */
+OP(31) { int tmp; RD_IDY_C02_P; AND; } /* 5 AND IDY page penalty */
+OP(51) { int tmp; RD_IDY_C02_P; EOR; } /* 5 EOR IDY page penalty */
+OP(71) { int tmp; RD_IDY_C02_P; ADC_C02; } /* 5/6 ADC IDY page penalty */
+OP(91) { int tmp; STA; WR_IDY_C02_NP; } /* 6 STA IDY */
+OP(b1) { int tmp; RD_IDY_C02_P; LDA; } /* 5 LDA IDY page penalty */
+OP(d1) { int tmp; RD_IDY_C02_P; CMP; } /* 5 CMP IDY page penalty */
+OP(f1) { int tmp; RD_IDY_C02_P; SBC_C02; } /* 5/6 SBC IDY page penalty */
+
+OP(02) { int tmp; RD_IMM; NOP; } /* 2 NOP not sure for rockwell */
+OP(22) { int tmp; RD_IMM; NOP; } /* 2 NOP not sure for rockwell */
+OP(42) { int tmp; RD_IMM; NOP; } /* 2 NOP not sure for rockwell */
+OP(62) { int tmp; RD_IMM; NOP; } /* 2 NOP not sure for rockwell */
+OP(82) { int tmp; RD_IMM; NOP; } /* 2 NOP not sure for rockwell */
+OP(a2) { int tmp; RD_IMM; LDX; } /* 2 LDX IMM */
+OP(c2) { int tmp; RD_IMM; NOP; } /* 2 NOP not sure for rockwell */
+OP(e2) { int tmp; RD_IMM; NOP; } /* 2 NOP not sure for rockwell */
+
+OP(12) { int tmp; RD_ZPI; ORA; } /* 5 ORA ZPI */
+OP(32) { int tmp; RD_ZPI; AND; } /* 5 AND ZPI */
+OP(52) { int tmp; RD_ZPI; EOR; } /* 5 EOR ZPI */
+OP(72) { int tmp; RD_ZPI; ADC_C02; } /* 5/6 ADC ZPI */
+OP(92) { int tmp; STA; WR_ZPI; } /* 5 STA ZPI */
+OP(b2) { int tmp; RD_ZPI; LDA; } /* 5 LDA ZPI */
+OP(d2) { int tmp; RD_ZPI; CMP; } /* 5 CMP ZPI */
+OP(f2) { int tmp; RD_ZPI; SBC_C02; } /* 5/6 SBC ZPI */
+
+OP(03) { NOP; } /* 1 NOP not sure for rockwell */
+OP(23) { NOP; } /* 1 NOP not sure for rockwell */
+OP(43) { NOP; } /* 1 NOP not sure for rockwell */
+OP(63) { NOP; } /* 1 NOP not sure for rockwell */
+OP(83) { NOP; } /* 1 NOP not sure for rockwell */
+OP(a3) { NOP; } /* 1 NOP not sure for rockwell */
+OP(c3) { NOP; } /* 1 NOP not sure for rockwell */
+OP(e3) { NOP; } /* 1 NOP not sure for rockwell */
+
+OP(13) { NOP; } /* 1 NOP not sure for rockwell */
+OP(33) { NOP; } /* 1 NOP not sure for rockwell */
+OP(53) { NOP; } /* 1 NOP not sure for rockwell */
+OP(73) { NOP; } /* 1 NOP not sure for rockwell */
+OP(93) { NOP; } /* 1 NOP not sure for rockwell */
+OP(b3) { NOP; } /* 1 NOP not sure for rockwell */
+OP(d3) { NOP; } /* 1 NOP not sure for rockwell */
+OP(f3) { NOP; } /* 1 NOP not sure for rockwell */
+
+OP(04) { int tmp; RD_ZPG; RD_EA; TSB; WB_EA; } /* 5 TSB ZPG */
+OP(24) { int tmp; RD_ZPG; BIT; } /* 3 BIT ZPG */
+OP(44) { int tmp; RD_ZPG; NOP; } /* 3 NOP not sure for rockwell */
+OP(64) { int tmp; STZ; WR_ZPG; } /* 3 STZ ZPG */
+OP(84) { int tmp; STY; WR_ZPG; } /* 3 STY ZPG */
+OP(a4) { int tmp; RD_ZPG; LDY; } /* 3 LDY ZPG */
+OP(c4) { int tmp; RD_ZPG; CPY; } /* 3 CPY ZPG */
+OP(e4) { int tmp; RD_ZPG; CPX; } /* 3 CPX ZPG */
+
+OP(14) { int tmp; RD_ZPG; RD_EA; TRB; WB_EA; } /* 5 TRB ZPG */
+OP(34) { int tmp; RD_ZPX; BIT; } /* 4 BIT ZPX */
+OP(54) { int tmp; RD_ZPX; NOP; } /* 4 NOP not sure for rockwell */
+OP(74) { int tmp; STZ; WR_ZPX; } /* 4 STZ ZPX */
+OP(94) { int tmp; STY; WR_ZPX; } /* 4 STY ZPX */
+OP(b4) { int tmp; RD_ZPX; LDY; } /* 4 LDY ZPX */
+OP(d4) { int tmp; RD_ZPX; NOP; } /* 4 NOP not sure for rockwell */
+OP(f4) { int tmp; RD_ZPX; NOP; } /* 4 NOP not sure for rockwell */
+
+OP(05) { int tmp; RD_ZPG; ORA; } /* 3 ORA ZPG */
+OP(25) { int tmp; RD_ZPG; AND; } /* 3 AND ZPG */
+OP(45) { int tmp; RD_ZPG; EOR; } /* 3 EOR ZPG */
+OP(65) { int tmp; RD_ZPG; ADC_C02; } /* 3/4 ADC ZPG */
+OP(85) { int tmp; STA; WR_ZPG; } /* 3 STA ZPG */
+OP(a5) { int tmp; RD_ZPG; LDA; } /* 3 LDA ZPG */
+OP(c5) { int tmp; RD_ZPG; CMP; } /* 3 CMP ZPG */
+OP(e5) { int tmp; RD_ZPG; SBC_C02; } /* 3/4 SBC ZPG */
+
+OP(15) { int tmp; RD_ZPX; ORA; } /* 4 ORA ZPX */
+OP(35) { int tmp; RD_ZPX; AND; } /* 4 AND ZPX */
+OP(55) { int tmp; RD_ZPX; EOR; } /* 4 EOR ZPX */
+OP(75) { int tmp; RD_ZPX; ADC_C02; } /* 4/5 ADC ZPX */
+OP(95) { int tmp; STA; WR_ZPX; } /* 4 STA ZPX */
+OP(b5) { int tmp; RD_ZPX; LDA; } /* 4 LDA ZPX */
+OP(d5) { int tmp; RD_ZPX; CMP; } /* 4 CMP ZPX */
+OP(f5) { int tmp; RD_ZPX; SBC_C02; } /* 4/5 SBC ZPX */
+
+OP(06) { int tmp; RD_ZPG, RD_EA; ASL; WB_EA; } /* 5 ASL ZPG */
+OP(26) { int tmp; RD_ZPG; RD_EA; ROL; WB_EA; } /* 5 ROL ZPG */
+OP(46) { int tmp; RD_ZPG; RD_EA; LSR; WB_EA; } /* 5 LSR ZPG */
+OP(66) { int tmp; RD_ZPG; RD_EA; ROR; WB_EA; } /* 5 ROR ZPG */
+OP(86) { int tmp; STX; WR_ZPG; } /* 3 STX ZPG */
+OP(a6) { int tmp; RD_ZPG; LDX; } /* 3 LDX ZPG */
+OP(c6) { int tmp; RD_ZPG; RD_EA; DEC; WB_EA; } /* 5 DEC ZPG */
+OP(e6) { int tmp; RD_ZPG; RD_EA; INC; WB_EA; } /* 5 INC ZPG */
+
+OP(16) { int tmp; RD_ZPX; RD_EA; ASL; WB_EA; } /* 6 ASL ZPX */
+OP(36) { int tmp; RD_ZPX; RD_EA; ROL; WB_EA; } /* 6 ROL ZPX */
+OP(56) { int tmp; RD_ZPX; RD_EA; LSR; WB_EA; } /* 6 LSR ZPX */
+OP(76) { int tmp; RD_ZPX; RD_EA; ROR; WB_EA; } /* 6 ROR ZPX */
+OP(96) { int tmp; STX; WR_ZPY; } /* 4 STX ZPY */
+OP(b6) { int tmp; RD_ZPY; LDX; } /* 4 LDX ZPY */
+OP(d6) { int tmp; RD_ZPX; RD_EA; DEC; WB_EA; } /* 6 DEC ZPX */
+OP(f6) { int tmp; RD_ZPX; RD_EA; INC; WB_EA; } /* 6 INC ZPX */
+
+OP(07) { int tmp; RD_ZPG; RD_EA; RMB(0);WB_EA; } /* 5 RMB0 ZPG */
+OP(27) { int tmp; RD_ZPG; RD_EA; RMB(2);WB_EA; } /* 5 RMB2 ZPG */
+OP(47) { int tmp; RD_ZPG; RD_EA; RMB(4);WB_EA; } /* 5 RMB4 ZPG */
+OP(67) { int tmp; RD_ZPG; RD_EA; RMB(6);WB_EA; } /* 5 RMB6 ZPG */
+OP(87) { int tmp; RD_ZPG; RD_EA; SMB(0);WB_EA; } /* 5 SMB0 ZPG */
+OP(a7) { int tmp; RD_ZPG; RD_EA; SMB(2);WB_EA; } /* 5 SMB2 ZPG */
+OP(c7) { int tmp; RD_ZPG; RD_EA; SMB(4);WB_EA; } /* 5 SMB4 ZPG */
+OP(e7) { int tmp; RD_ZPG; RD_EA; SMB(6);WB_EA; } /* 5 SMB6 ZPG */
+
+OP(17) { int tmp; RD_ZPG; RD_EA; RMB(1);WB_EA; } /* 5 RMB1 ZPG */
+OP(37) { int tmp; RD_ZPG; RD_EA; RMB(3);WB_EA; } /* 5 RMB3 ZPG */
+OP(57) { int tmp; RD_ZPG; RD_EA; RMB(5);WB_EA; } /* 5 RMB5 ZPG */
+OP(77) { int tmp; RD_ZPG; RD_EA; RMB(7);WB_EA; } /* 5 RMB7 ZPG */
+OP(97) { int tmp; RD_ZPG; RD_EA; SMB(1);WB_EA; } /* 5 SMB1 ZPG */
+OP(b7) { int tmp; RD_ZPG; RD_EA; SMB(3);WB_EA; } /* 5 SMB3 ZPG */
+OP(d7) { int tmp; RD_ZPG; RD_EA; SMB(5);WB_EA; } /* 5 SMB5 ZPG */
+OP(f7) { int tmp; RD_ZPG; RD_EA; SMB(7);WB_EA; } /* 5 SMB7 ZPG */
+
+OP(08) { RD_DUM; PHP; } /* 3 PHP */
+OP(28) { RD_DUM; PLP; } /* 4 PLP */
+OP(48) { RD_DUM; PHA; } /* 3 PHA */
+OP(68) { RD_DUM; PLA; } /* 4 PLA */
+OP(88) { RD_DUM; DEY; } /* 2 DEY */
+OP(a8) { RD_DUM; TAY; } /* 2 TAY */
+OP(c8) { RD_DUM; INY; } /* 2 INY */
+OP(e8) { RD_DUM; INX; } /* 2 INX */
+
+OP(18) { RD_DUM; CLC; } /* 2 CLC */
+OP(38) { RD_DUM; SEC; } /* 2 SEC */
+OP(58) { RD_DUM; CLI; } /* 2 CLI */
+OP(78) { RD_DUM; SEI; } /* 2 SEI */
+OP(98) { RD_DUM; TYA; } /* 2 TYA */
+OP(b8) { RD_DUM; CLV; } /* 2 CLV */
+OP(d8) { RD_DUM; CLD; } /* 2 CLD */
+OP(f8) { RD_DUM; SED; } /* 2 SED */
+
+OP(09) { int tmp; RD_IMM; ORA; } /* 2 ORA IMM */
+OP(29) { int tmp; RD_IMM; AND; } /* 2 AND IMM */
+OP(49) { int tmp; RD_IMM; EOR; } /* 2 EOR IMM */
+OP(69) { int tmp; RD_IMM; ADC_C02; } /* 2/3 ADC IMM */
+OP(89) { int tmp; RD_IMM; BIT; } /* 2 BIT IMM */
+OP(a9) { int tmp; RD_IMM; LDA; } /* 2 LDA IMM */
+OP(c9) { int tmp; RD_IMM; CMP; } /* 2 CMP IMM */
+OP(e9) { int tmp; RD_IMM; SBC_C02; } /* 2/3 SBC IMM */
+
+OP(19) { int tmp; RD_ABY_C02_P; ORA; } /* 4 ORA ABY page penalty */
+OP(39) { int tmp; RD_ABY_C02_P; AND; } /* 4 AND ABY page penalty */
+OP(59) { int tmp; RD_ABY_C02_P; EOR; } /* 4 EOR ABY page penalty */
+OP(79) { int tmp; RD_ABY_C02_P; ADC_C02; } /* 4/5 ADC ABY page penalty */
+OP(99) { int tmp; STA; WR_ABY_C02_NP; } /* 5 STA ABY */
+OP(b9) { int tmp; RD_ABY_C02_P; LDA; } /* 4 LDA ABY page penalty */
+OP(d9) { int tmp; RD_ABY_C02_P; CMP; } /* 4 CMP ABY page penalty */
+OP(f9) { int tmp; RD_ABY_C02_P; SBC_C02; } /* 4/5 SBC ABY page penalty */
+
+OP(0a) { int tmp; RD_DUM; RD_ACC; ASL; WB_ACC; } /* 2 ASL A */
+OP(2a) { int tmp; RD_DUM; RD_ACC; ROL; WB_ACC; } /* 2 ROL A */
+OP(4a) { int tmp; RD_DUM; RD_ACC; LSR; WB_ACC; } /* 2 LSR A */
+OP(6a) { int tmp; RD_DUM; RD_ACC; ROR; WB_ACC; } /* 2 ROR A */
+OP(8a) { RD_DUM; TXA; } /* 2 TXA */
+OP(aa) { RD_DUM; TAX; } /* 2 TAX */
+OP(ca) { RD_DUM; DEX; } /* 2 DEX */
+OP(ea) { RD_DUM; NOP; } /* 2 NOP */
+
+OP(1a) { RD_DUM;INA; } /* 2 INA */
+OP(3a) { RD_DUM;DEA; } /* 2 DEA */
+OP(5a) { RD_DUM;PHY; } /* 3 PHY */
+OP(7a) { RD_DUM;PLY; } /* 4 PLY */
+OP(9a) { RD_DUM; TXS; } /* 2 TXS */
+OP(ba) { RD_DUM; TSX; } /* 2 TSX */
+OP(da) { RD_DUM;PHX; } /* 3 PHX */
+OP(fa) { RD_DUM;PLX; } /* 4 PLX */
+
+OP(0b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(2b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(4b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(6b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(8b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(ab) { NOP; } /* 1 NOP not sure for rockwell */
+OP(cb) { NOP; } /* 1 NOP not sure for rockwell */
+OP(eb) { NOP; } /* 1 NOP not sure for rockwell */
+
+OP(1b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(3b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(5b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(7b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(9b) { NOP; } /* 1 NOP not sure for rockwell */
+OP(bb) { NOP; } /* 1 NOP not sure for rockwell */
+OP(db) { NOP; } /* 1 NOP not sure for rockwell */
+OP(fb) { NOP; } /* 1 NOP not sure for rockwell */
+
+OP(0c) { int tmp; RD_ABS; RD_EA; TSB; WB_EA; } /* 6 TSB ABS */
+OP(2c) { int tmp; RD_ABS; BIT; } /* 4 BIT ABS */
+OP(4c) { EA_ABS; JMP; } /* 3 JMP ABS */
+OP(6c) { int tmp; EA_IND_C02; JMP; } /* 6 JMP IND */
+OP(8c) { int tmp; STY; WR_ABS; } /* 4 STY ABS */
+OP(ac) { int tmp; RD_ABS; LDY; } /* 4 LDY ABS */
+OP(cc) { int tmp; RD_ABS; CPY; } /* 4 CPY ABS */
+OP(ec) { int tmp; RD_ABS; CPX; } /* 4 CPX ABS */
+
+OP(1c) { int tmp; RD_ABS; RD_EA; TRB; WB_EA; } /* 6 TRB ABS */
+OP(3c) { int tmp; RD_ABX_C02_P; BIT; } /* 4 BIT ABX page penalty */
+OP(5c) { int tmp; RD_ABX_C02_NP; RD_DUM; RD_DUM; RD_DUM; RD_DUM; } /* 8 NOP ABX not sure for rockwell. Page penalty not sure */
+OP(7c) { int tmp; EA_IAX; JMP; } /* 6 JMP IAX page penalty */
+OP(9c) { int tmp; STZ; WR_ABS; } /* 4 STZ ABS */
+OP(bc) { int tmp; RD_ABX_C02_P; LDY; } /* 4 LDY ABX page penalty */
+OP(dc) { int tmp; RD_ABX_C02_NP; NOP; } /* 4 NOP ABX not sure for rockwell. Page penalty not sure */
+OP(fc) { int tmp; RD_ABX_C02_NP; NOP; } /* 4 NOP ABX not sure for rockwell. Page penalty not sure */
+
+OP(0d) { int tmp; RD_ABS; ORA; } /* 4 ORA ABS */
+OP(2d) { int tmp; RD_ABS; AND; } /* 4 AND ABS */
+OP(4d) { int tmp; RD_ABS; EOR; } /* 4 EOR ABS */
+OP(6d) { int tmp; RD_ABS; ADC_C02; } /* 4/5 ADC ABS */
+OP(8d) { int tmp; STA; WR_ABS; } /* 4 STA ABS */
+OP(ad) { int tmp; RD_ABS; LDA; } /* 4 LDA ABS */
+OP(cd) { int tmp; RD_ABS; CMP; } /* 4 CMP ABS */
+OP(ed) { int tmp; RD_ABS; SBC_C02; } /* 4/5 SBC ABS */
+
+OP(1d) { int tmp; RD_ABX_C02_P; ORA; } /* 4 ORA ABX page penalty */
+OP(3d) { int tmp; RD_ABX_C02_P; AND; } /* 4 AND ABX page penalty */
+OP(5d) { int tmp; RD_ABX_C02_P; EOR; } /* 4 EOR ABX page penalty */
+OP(7d) { int tmp; RD_ABX_C02_P; ADC_C02; } /* 4/5 ADC ABX page penalty */
+OP(9d) { int tmp; STA; WR_ABX_C02_NP; } /* 5 STA ABX */
+OP(bd) { int tmp; RD_ABX_C02_P; LDA; } /* 4 LDA ABX page penalty */
+OP(dd) { int tmp; RD_ABX_C02_P; CMP; } /* 4 CMP ABX page penalty */
+OP(fd) { int tmp; RD_ABX_C02_P; SBC_C02; } /* 4/5 SBC ABX page penalty */
+
+OP(0e) { int tmp; RD_ABS; RD_EA; ASL; WB_EA; } /* 6 ASL ABS */
+OP(2e) { int tmp; RD_ABS; RD_EA; ROL; WB_EA; } /* 6 ROL ABS */
+OP(4e) { int tmp; RD_ABS; RD_EA; LSR; WB_EA; } /* 6 LSR ABS */
+OP(6e) { int tmp; RD_ABS; RD_EA; ROR; WB_EA; } /* 6 ROR ABS */
+OP(8e) { int tmp; STX; WR_ABS; } /* 4 STX ABS */
+OP(ae) { int tmp; RD_ABS; LDX; } /* 4 LDX ABS */
+OP(ce) { int tmp; RD_ABS; RD_EA; DEC; WB_EA; } /* 6 DEC ABS */
+OP(ee) { int tmp; RD_ABS; RD_EA; INC; WB_EA; } /* 6 INC ABS */
+
+OP(1e) { int tmp; RD_ABX_C02_NP; RD_EA; ASL; WB_EA; } /* 7 ASL ABX */
+OP(3e) { int tmp; RD_ABX_C02_NP; RD_EA; ROL; WB_EA; } /* 7 ROL ABX */
+OP(5e) { int tmp; RD_ABX_C02_NP; RD_EA; LSR; WB_EA; } /* 7 LSR ABX */
+OP(7e) { int tmp; RD_ABX_C02_NP; RD_EA; ROR; WB_EA; } /* 7 ROR ABX */
+OP(9e) { int tmp; STZ; WR_ABX_C02_NP; } /* 5 STZ ABX */
+OP(be) { int tmp; RD_ABY_C02_P; LDX; } /* 4 LDX ABY page penalty */
+OP(de) { int tmp; RD_ABX_C02_NP; RD_EA; DEC; WB_EA; } /* 7 DEC ABX */
+OP(fe) { int tmp; RD_ABX_C02_NP; RD_EA; INC; WB_EA; } /* 7 INC ABX */
+
+OP(0f) { int tmp; RD_ZPG; BBR(0); } /* 5-7 BBR0 ZPG */
+OP(2f) { int tmp; RD_ZPG; BBR(2); } /* 5-7 BBR2 ZPG */
+OP(4f) { int tmp; RD_ZPG; BBR(4); } /* 5-7 BBR4 ZPG */
+OP(6f) { int tmp; RD_ZPG; BBR(6); } /* 5-7 BBR6 ZPG */
+OP(8f) { int tmp; RD_ZPG; BBS(0); } /* 5-7 BBS0 ZPG */
+OP(af) { int tmp; RD_ZPG; BBS(2); } /* 5-7 BBS2 ZPG */
+OP(cf) { int tmp; RD_ZPG; BBS(4); } /* 5-7 BBS4 ZPG */
+OP(ef) { int tmp; RD_ZPG; BBS(6); } /* 5-7 BBS6 ZPG */
+
+OP(1f) { int tmp; RD_ZPG; BBR(1); } /* 5-7 BBR1 ZPG */
+OP(3f) { int tmp; RD_ZPG; BBR(3); } /* 5-7 BBR3 ZPG */
+OP(5f) { int tmp; RD_ZPG; BBR(5); } /* 5-7 BBR5 ZPG */
+OP(7f) { int tmp; RD_ZPG; BBR(7); } /* 5-7 BBR7 ZPG */
+OP(9f) { int tmp; RD_ZPG; BBS(1); } /* 5-7 BBS1 ZPG */
+OP(bf) { int tmp; RD_ZPG; BBS(3); } /* 5-7 BBS3 ZPG */
+OP(df) { int tmp; RD_ZPG; BBS(5); } /* 5-7 BBS5 ZPG */
+OP(ff) { int tmp; RD_ZPG; BBS(7); } /* 5-7 BBS7 ZPG */
+
+static void (*insn65c02[0x100])(void) = {
+ m65c02_00,m65c02_01,m65c02_02,m65c02_03,m65c02_04,m65c02_05,m65c02_06,m65c02_07,
+ m65c02_08,m65c02_09,m65c02_0a,m65c02_0b,m65c02_0c,m65c02_0d,m65c02_0e,m65c02_0f,
+ m65c02_10,m65c02_11,m65c02_12,m65c02_13,m65c02_14,m65c02_15,m65c02_16,m65c02_17,
+ m65c02_18,m65c02_19,m65c02_1a,m65c02_1b,m65c02_1c,m65c02_1d,m65c02_1e,m65c02_1f,
+ m65c02_20,m65c02_21,m65c02_22,m65c02_23,m65c02_24,m65c02_25,m65c02_26,m65c02_27,
+ m65c02_28,m65c02_29,m65c02_2a,m65c02_2b,m65c02_2c,m65c02_2d,m65c02_2e,m65c02_2f,
+ m65c02_30,m65c02_31,m65c02_32,m65c02_33,m65c02_34,m65c02_35,m65c02_36,m65c02_37,
+ m65c02_38,m65c02_39,m65c02_3a,m65c02_3b,m65c02_3c,m65c02_3d,m65c02_3e,m65c02_3f,
+ m65c02_40,m65c02_41,m65c02_42,m65c02_43,m65c02_44,m65c02_45,m65c02_46,m65c02_47,
+ m65c02_48,m65c02_49,m65c02_4a,m65c02_4b,m65c02_4c,m65c02_4d,m65c02_4e,m65c02_4f,
+ m65c02_50,m65c02_51,m65c02_52,m65c02_53,m65c02_54,m65c02_55,m65c02_56,m65c02_57,
+ m65c02_58,m65c02_59,m65c02_5a,m65c02_5b,m65c02_5c,m65c02_5d,m65c02_5e,m65c02_5f,
+ m65c02_60,m65c02_61,m65c02_62,m65c02_63,m65c02_64,m65c02_65,m65c02_66,m65c02_67,
+ m65c02_68,m65c02_69,m65c02_6a,m65c02_6b,m65c02_6c,m65c02_6d,m65c02_6e,m65c02_6f,
+ m65c02_70,m65c02_71,m65c02_72,m65c02_73,m65c02_74,m65c02_75,m65c02_76,m65c02_77,
+ m65c02_78,m65c02_79,m65c02_7a,m65c02_7b,m65c02_7c,m65c02_7d,m65c02_7e,m65c02_7f,
+ m65c02_80,m65c02_81,m65c02_82,m65c02_83,m65c02_84,m65c02_85,m65c02_86,m65c02_87,
+ m65c02_88,m65c02_89,m65c02_8a,m65c02_8b,m65c02_8c,m65c02_8d,m65c02_8e,m65c02_8f,
+ m65c02_90,m65c02_91,m65c02_92,m65c02_93,m65c02_94,m65c02_95,m65c02_96,m65c02_97,
+ m65c02_98,m65c02_99,m65c02_9a,m65c02_9b,m65c02_9c,m65c02_9d,m65c02_9e,m65c02_9f,
+ m65c02_a0,m65c02_a1,m65c02_a2,m65c02_a3,m65c02_a4,m65c02_a5,m65c02_a6,m65c02_a7,
+ m65c02_a8,m65c02_a9,m65c02_aa,m65c02_ab,m65c02_ac,m65c02_ad,m65c02_ae,m65c02_af,
+ m65c02_b0,m65c02_b1,m65c02_b2,m65c02_b3,m65c02_b4,m65c02_b5,m65c02_b6,m65c02_b7,
+ m65c02_b8,m65c02_b9,m65c02_ba,m65c02_bb,m65c02_bc,m65c02_bd,m65c02_be,m65c02_bf,
+ m65c02_c0,m65c02_c1,m65c02_c2,m65c02_c3,m65c02_c4,m65c02_c5,m65c02_c6,m65c02_c7,
+ m65c02_c8,m65c02_c9,m65c02_ca,m65c02_cb,m65c02_cc,m65c02_cd,m65c02_ce,m65c02_cf,
+ m65c02_d0,m65c02_d1,m65c02_d2,m65c02_d3,m65c02_d4,m65c02_d5,m65c02_d6,m65c02_d7,
+ m65c02_d8,m65c02_d9,m65c02_da,m65c02_db,m65c02_dc,m65c02_dd,m65c02_de,m65c02_df,
+ m65c02_e0,m65c02_e1,m65c02_e2,m65c02_e3,m65c02_e4,m65c02_e5,m65c02_e6,m65c02_e7,
+ m65c02_e8,m65c02_e9,m65c02_ea,m65c02_eb,m65c02_ec,m65c02_ed,m65c02_ee,m65c02_ef,
+ m65c02_f0,m65c02_f1,m65c02_f2,m65c02_f3,m65c02_f4,m65c02_f5,m65c02_f6,m65c02_f7,
+ m65c02_f8,m65c02_f9,m65c02_fa,m65c02_fb,m65c02_fc,m65c02_fd,m65c02_fe,m65c02_ff
+};
+
+#ifdef WDC65C02
+OP(cb_wdc) { RD_DUM; RD_DUM; } /* 3 WAI, TODO: Implement HALT mode */
+OP(db_wdc) { RD_DUM; RD_DUM; } /* 3 STP, TODO: Implement STP mode */
+OP(1e_wdc) { int tmp; RD_ABX_P; RD_EA; ASL; WB_EA; } /* 6 ASL ABX page penalty */
+OP(3e_wdc) { int tmp; RD_ABX_P; RD_EA; ROL; WB_EA; } /* 6 ROL ABX page penalty */
+OP(5e_wdc) { int tmp; RD_ABX_P; RD_EA; LSR; WB_EA; } /* 6 LSR ABX page penalty */
+OP(7e_wdc) { int tmp; RD_ABX_P; RD_EA; ROR; WB_EA; } /* 6 ROR ABX page penalty */
+OP(de_wdc) { int tmp; RD_ABX_P; RD_EA; DEC; WB_EA; } /* 6 DEC ABX page penalty */
+OP(fe_wdc) { int tmp; RD_ABX_P; RD_EA; INC; WB_EA; } /* 6 INC ABX page penalty */
+
+static void (*insnwdc65c02[0x100])(void) = {
+ m65c02_00,m65c02_01,m65c02_02,m65c02_03,m65c02_04,m65c02_05,m65c02_06,m65c02_07,
+ m65c02_08,m65c02_09,m65c02_0a,m65c02_0b,m65c02_0c,m65c02_0d,m65c02_0e,m65c02_0f,
+ m65c02_10,m65c02_11,m65c02_12,m65c02_13,m65c02_14,m65c02_15,m65c02_16,m65c02_17,
+ m65c02_18,m65c02_19,m65c02_1a,m65c02_1b,m65c02_1c,m65c02_1d,m65c02_1e_wdc,m65c02_1f,
+ m65c02_20,m65c02_21,m65c02_22,m65c02_23,m65c02_24,m65c02_25,m65c02_26,m65c02_27,
+ m65c02_28,m65c02_29,m65c02_2a,m65c02_2b,m65c02_2c,m65c02_2d,m65c02_2e,m65c02_2f,
+ m65c02_30,m65c02_31,m65c02_32,m65c02_33,m65c02_34,m65c02_35,m65c02_36,m65c02_37,
+ m65c02_38,m65c02_39,m65c02_3a,m65c02_3b,m65c02_3c,m65c02_3d,m65c02_3e_wdc,m65c02_3f,
+ m65c02_40,m65c02_41,m65c02_42,m65c02_43,m65c02_44,m65c02_45,m65c02_46,m65c02_47,
+ m65c02_48,m65c02_49,m65c02_4a,m65c02_4b,m65c02_4c,m65c02_4d,m65c02_4e,m65c02_4f,
+ m65c02_50,m65c02_51,m65c02_52,m65c02_53,m65c02_54,m65c02_55,m65c02_56,m65c02_57,
+ m65c02_58,m65c02_59,m65c02_5a,m65c02_5b,m65c02_5c,m65c02_5d,m65c02_5e_wdc,m65c02_5f,
+ m65c02_60,m65c02_61,m65c02_62,m65c02_63,m65c02_64,m65c02_65,m65c02_66,m65c02_67,
+ m65c02_68,m65c02_69,m65c02_6a,m65c02_6b,m65c02_6c,m65c02_6d,m65c02_6e,m65c02_6f,
+ m65c02_70,m65c02_71,m65c02_72,m65c02_73,m65c02_74,m65c02_75,m65c02_76,m65c02_77,
+ m65c02_78,m65c02_79,m65c02_7a,m65c02_7b,m65c02_7c,m65c02_7d,m65c02_7e_wdc,m65c02_7f,
+ m65c02_80,m65c02_81,m65c02_82,m65c02_83,m65c02_84,m65c02_85,m65c02_86,m65c02_87,
+ m65c02_88,m65c02_89,m65c02_8a,m65c02_8b,m65c02_8c,m65c02_8d,m65c02_8e,m65c02_8f,
+ m65c02_90,m65c02_91,m65c02_92,m65c02_93,m65c02_94,m65c02_95,m65c02_96,m65c02_97,
+ m65c02_98,m65c02_99,m65c02_9a,m65c02_9b,m65c02_9c,m65c02_9d,m65c02_9e,m65c02_9f,
+ m65c02_a0,m65c02_a1,m65c02_a2,m65c02_a3,m65c02_a4,m65c02_a5,m65c02_a6,m65c02_a7,
+ m65c02_a8,m65c02_a9,m65c02_aa,m65c02_ab,m65c02_ac,m65c02_ad,m65c02_ae,m65c02_af,
+ m65c02_b0,m65c02_b1,m65c02_b2,m65c02_b3,m65c02_b4,m65c02_b5,m65c02_b6,m65c02_b7,
+ m65c02_b8,m65c02_b9,m65c02_ba,m65c02_bb,m65c02_bc,m65c02_bd,m65c02_be,m65c02_bf,
+ m65c02_c0,m65c02_c1,m65c02_c2,m65c02_c3,m65c02_c4,m65c02_c5,m65c02_c6,m65c02_c7,
+ m65c02_c8,m65c02_c9,m65c02_ca,m65c02_cb_wdc,m65c02_cc,m65c02_cd,m65c02_ce,m65c02_cf,
+ m65c02_d0,m65c02_d1,m65c02_d2,m65c02_d3,m65c02_d4,m65c02_d5,m65c02_d6,m65c02_d7,
+ m65c02_d8,m65c02_d9,m65c02_da,m65c02_db_wdc,m65c02_dc,m65c02_dd,m65c02_de_wdc,m65c02_df,
+ m65c02_e0,m65c02_e1,m65c02_e2,m65c02_e3,m65c02_e4,m65c02_e5,m65c02_e6,m65c02_e7,
+ m65c02_e8,m65c02_e9,m65c02_ea,m65c02_eb,m65c02_ec,m65c02_ed,m65c02_ee,m65c02_ef,
+ m65c02_f0,m65c02_f1,m65c02_f2,m65c02_f3,m65c02_f4,m65c02_f5,m65c02_f6,m65c02_f7,
+ m65c02_f8,m65c02_f9,m65c02_fa,m65c02_fb,m65c02_fc,m65c02_fd,m65c02_fe_wdc,m65c02_ff
+};
+#endif
+
+
diff --git a/src/emu/cpu/m6502/t65ce02.c b/src/emu/cpu/m6502/t65ce02.c
new file mode 100644
index 00000000000..4ae71dec749
--- /dev/null
+++ b/src/emu/cpu/m6502/t65ce02.c
@@ -0,0 +1,399 @@
+/*****************************************************************************
+ *
+ * t65ce02.c
+ * 65ce02 opcode functions and function pointer table
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#undef OP
+#ifdef M4510
+#define OP(nn) INLINE void m4510_##nn(void)
+#else
+#define OP(nn) INLINE void m65ce02_##nn(void)
+#endif
+
+/*****************************************************************************
+ *****************************************************************************
+ *
+ * overrides for 65CE02 opcodes
+ *
+ *****************************************************************************
+ * op temp cycles rdmem opc wrmem ********************/
+OP(00) { BRK; } /* 7 BRK */
+OP(20) { JSR; } /* 5 JSR */
+OP(40) { int tmp; RTI; } /* 5 RTI */
+OP(60) { RTS; } /* 4 RTS */
+OP(80) { int tmp; BRA(1); } /* 2 BRA */
+OP(a0) { int tmp; RD_IMM; LDY; } /* 2 LDY IMM */
+OP(c0) { int tmp; RD_IMM; CPY; } /* 2 CPY IMM */
+OP(e0) { int tmp; RD_IMM; CPX; } /* 2 CPX IMM */
+
+OP(10) { int tmp; BRA( ! ( P & F_N ) ); } /* 2 BPL REL */
+OP(30) { int tmp; BRA( ( P & F_N ) ); } /* 2 BMI REL */
+OP(50) { int tmp; BRA( ! ( P & F_V ) ); } /* 2 BVC REL */
+OP(70) { int tmp; BRA( ( P & F_V ) ); } /* 2 BVS REL */
+OP(90) { int tmp; BRA( ! ( P & F_C ) ); } /* 2 BCC REL */
+OP(b0) { int tmp; BRA( ( P & F_C ) ); } /* 2 BCS REL */
+OP(d0) { int tmp; BRA( ! ( P & F_Z ) ); } /* 2 BNE REL */
+OP(f0) { int tmp; BRA( ( P & F_Z ) ); } /* 2 BEQ REL */
+
+OP(01) { int tmp; RD_IDX; ORA; } /* 5 ORA IDX */
+OP(21) { int tmp; RD_IDX; AND; } /* 5 AND IDX */
+OP(41) { int tmp; RD_IDX; EOR; } /* 5 EOR IDX */
+OP(61) { int tmp; RD_IDX; ADC; } /* 5 ADC IDX */
+OP(81) { int tmp; STA; WR_IDX; } /* 5 STA IDX */
+OP(a1) { int tmp; RD_IDX; LDA; } /* 5 LDA IDX */
+OP(c1) { int tmp; RD_IDX; CMP; } /* 5 CMP IDX */
+OP(e1) { int tmp; RD_IDX; SBC; } /* 5 SBC IDX */
+
+OP(11) { int tmp; RD_IDY; ORA; } /* 5 ORA IDY */
+OP(31) { int tmp; RD_IDY; AND; } /* 5 AND IDY */
+OP(51) { int tmp; RD_IDY; EOR; } /* 5 EOR IDY */
+OP(71) { int tmp; RD_IDY; ADC; } /* 5 ADC IDY */
+OP(91) { int tmp; STA; WR_IDY; } /* 5 STA IDY */
+OP(b1) { int tmp; RD_IDY; LDA; } /* 5 LDA IDY */
+OP(d1) { int tmp; RD_IDY; CMP; } /* 5 CMP IDY */
+OP(f1) { int tmp; RD_IDY; SBC; } /* 5 SBC IDY */
+
+OP(02) { RD_DUM; CLE; } /* 2 CLE */
+OP(22) { JSR_IND; } /* 7 JSR IND */
+OP(42) { RD_DUM; NEG; } /* 2 NEG */
+OP(62) { int tmp; RD_IMM; RTN; } /* 7 RTN IMM */
+OP(82) { int tmp; RD_INSY; STA; } /* 6 STA INSY */
+OP(a2) { int tmp; RD_IMM; LDX; } /* 2 LDX IMM */
+OP(c2) { int tmp; RD_IMM; CPZ; } /* 2 CPZ IMM */
+OP(e2) { int tmp; RD_INSY; LDA; } /* 6 LDA INSY */
+
+OP(12) { int tmp; RD_IDZ; ORA; } /* 5 ORA IDZ */
+OP(32) { int tmp; RD_IDZ; AND; } /* 5 AND IDZ */
+OP(52) { int tmp; RD_IDZ; EOR; } /* 5 EOR IDZ */
+OP(72) { int tmp; RD_IDZ; ADC; } /* 5 ADC IDZ */
+OP(92) { int tmp; RD_IDZ; STA; } /* 5 STA IDZ */
+OP(b2) { int tmp; RD_IDZ; LDA; } /* 5 LDA IDZ */
+OP(d2) { int tmp; RD_IDZ; CMP; } /* 5 CMP IDZ */
+OP(f2) { int tmp; RD_IDZ; SBC; } /* 5 SBC IDZ */
+
+OP(03) { RD_DUM; SEE; } /* 2 SEE */
+OP(23) { JSR_INDX; } /* 7 JSR INDX */
+OP(43) { int tmp; RD_DUM; RD_ACC; ASR_65CE02; WR_ACC; } /* 2 ASR A */
+OP(63) { BSR; } /* 5 BSR */
+OP(83) { BRA_WORD(1); } /* 3 BRA REL WORD */
+OP(a3) { int tmp; RD_IMM; LDZ; } /* 2 LDZ IMM */
+OP(c3) { PAIR tmp; RD_ZPG_WORD; DEW; WB_EA_WORD; } /* 6 DEW ABS */
+OP(e3) { PAIR tmp; RD_ZPG_WORD; INW; WB_EA_WORD; } /* 6 INW ABS */
+
+OP(13) { BRA_WORD( ! ( P & F_N ) ); } /* 3 BPL REL WORD */
+OP(33) { BRA_WORD( ( P & F_N ) ); } /* 3 BMI REL WORD */
+OP(53) { BRA_WORD( ! ( P & F_V ) ); } /* 3 BVC REL WORD */
+OP(73) { BRA_WORD( ( P & F_V ) ); } /* 3 BVS REL WORD */
+OP(93) { BRA_WORD( ! ( P & F_C ) ); } /* 3 BCC REL WORD */
+OP(b3) { BRA_WORD( ( P & F_C ) ); } /* 3 BCS REL WORD */
+OP(d3) { BRA_WORD( ! ( P & F_Z ) ); } /* 3 BNE REL WORD */
+OP(f3) { BRA_WORD( ( P & F_Z ) ); } /* 3 BEQ REL WORD */
+
+OP(04) { int tmp; RD_ZPG; TSB; WB_EA; } /* 4 TSB ZPG */
+OP(24) { int tmp; RD_ZPG; RD_DUM; BIT; } /* 4 BIT ZPG */
+OP(44) { int tmp; RD_ZPG; ASR_65CE02; WB_EA; } /* 4 ASR ZPG */
+OP(64) { int tmp; STZ_65CE02; WR_ZPG; } /* 3 STZ ZPG */
+OP(84) { int tmp; STY; WR_ZPG; } /* 3 STY ZPG */
+OP(a4) { int tmp; RD_ZPG; LDY; } /* 3 LDY ZPG */
+OP(c4) { int tmp; RD_ZPG; CPY; } /* 3 CPY ZPG */
+OP(e4) { int tmp; RD_ZPG; CPX; } /* 3 CPX ZPG */
+
+OP(14) { int tmp; RD_ZPG; TRB; WB_EA; } /* 4 TRB ZPG */
+OP(34) { int tmp; RD_ZPX; RD_DUM; BIT; } /* 4 BIT ZPX */
+OP(54) { int tmp; RD_ZPX; ASR_65CE02; WB_EA; } /* 4 ASR ZPX */
+OP(74) { int tmp; STZ_65CE02; WR_ZPX; } /* 3 STZ ZPX */
+OP(94) { int tmp; STY; WR_ZPX; } /* 3 STY ZPX */
+OP(b4) { int tmp; RD_ZPX; LDY; } /* 3 LDY ZPX */
+OP(d4) { int tmp; RD_ZPG; CPZ; } /* 3 CPZ ZPG */
+OP(f4) { PAIR tmp; RD_IMM_WORD; PUSH_WORD(tmp); } /* 5 PHW imm16 */
+
+OP(05) { int tmp; RD_ZPG; ORA; } /* 3 ORA ZPG */
+OP(25) { int tmp; RD_ZPG; AND; } /* 3 AND ZPG */
+OP(45) { int tmp; RD_ZPG; EOR; } /* 3 EOR ZPG */
+OP(65) { int tmp; RD_ZPG; ADC; } /* 3 ADC ZPG */
+OP(85) { int tmp; STA; WR_ZPG; } /* 3 STA ZPG */
+OP(a5) { int tmp; RD_ZPG; LDA; } /* 3 LDA ZPG */
+OP(c5) { int tmp; RD_ZPG; CMP; } /* 3 CMP ZPG */
+OP(e5) { int tmp; RD_ZPG; SBC; } /* 3 SBC ZPG */
+
+OP(15) { int tmp; RD_ZPX; ORA; } /* 3 ORA ZPX */
+OP(35) { int tmp; RD_ZPX; AND; } /* 3 AND ZPX */
+OP(55) { int tmp; RD_ZPX; EOR; } /* 3 EOR ZPX */
+OP(75) { int tmp; RD_ZPX; ADC; } /* 3 ADC ZPX */
+OP(95) { int tmp; STA; WR_ZPX; } /* 3 STA ZPX */
+OP(b5) { int tmp; RD_ZPX; LDA; } /* 3 LDA ZPX */
+OP(d5) { int tmp; RD_ZPX; CMP; } /* 3 CMP ZPX */
+OP(f5) { int tmp; RD_ZPX; SBC; } /* 3 SBC ZPX */
+
+OP(06) { int tmp; RD_ZPG; ASL; WB_EA; } /* 4 ASL ZPG */
+OP(26) { int tmp; RD_ZPG; ROL; WB_EA; } /* 4 ROL ZPG */
+OP(46) { int tmp; RD_ZPG; LSR; WB_EA; } /* 4 LSR ZPG */
+OP(66) { int tmp; RD_ZPG; ROR; WB_EA; } /* 4 ROR ZPG */
+OP(86) { int tmp; STX; WR_ZPG; } /* 3 STX ZPG */
+OP(a6) { int tmp; RD_ZPG; LDX; } /* 3 LDX ZPG */
+OP(c6) { int tmp; RD_ZPG; DEC; WB_EA; } /* 4 DEC ZPG */
+OP(e6) { int tmp; RD_ZPG; INC; WB_EA; } /* 4 INC ZPG */
+
+OP(16) { int tmp; RD_ZPX; ASL; WB_EA; } /* 4 ASL ZPX */
+OP(36) { int tmp; RD_ZPX; ROL; WB_EA; } /* 4 ROL ZPX */
+OP(56) { int tmp; RD_ZPX; LSR; WB_EA; } /* 4 LSR ZPX */
+OP(76) { int tmp; RD_ZPX; ROR; WB_EA; } /* 4 ROR ZPX */
+OP(96) { int tmp; STX; WR_ZPY; } /* 3 STX ZPY */
+OP(b6) { int tmp; RD_ZPY; LDX; } /* 3 LDX ZPY */
+OP(d6) { int tmp; RD_ZPX; DEC; WB_EA; } /* 4 DEC ZPX */
+OP(f6) { int tmp; RD_ZPX; INC; WB_EA; } /* 4 INC ZPX */
+
+OP(07) { int tmp; RD_ZPG; RMB(0); WB_EA; } /* 4 RMB0 ZPG */
+OP(27) { int tmp; RD_ZPG; RMB(2); WB_EA; } /* 4 RMB2 ZPG */
+OP(47) { int tmp; RD_ZPG; RMB(4); WB_EA; } /* 4 RMB4 ZPG */
+OP(67) { int tmp; RD_ZPG; RMB(6); WB_EA; } /* 4 RMB6 ZPG */
+OP(87) { int tmp; RD_ZPG; SMB(0); WB_EA; } /* 4 SMB0 ZPG */
+OP(a7) { int tmp; RD_ZPG; SMB(2); WB_EA; } /* 4 SMB2 ZPG */
+OP(c7) { int tmp; RD_ZPG; SMB(4); WB_EA; } /* 4 SMB4 ZPG */
+OP(e7) { int tmp; RD_ZPG; SMB(6); WB_EA; } /* 4 SMB6 ZPG */
+
+OP(17) { int tmp; RD_ZPG; RMB(1); WB_EA; } /* 4 RMB1 ZPG */
+OP(37) { int tmp; RD_ZPG; RMB(3); WB_EA; } /* 4 RMB3 ZPG */
+OP(57) { int tmp; RD_ZPG; RMB(5); WB_EA; } /* 4 RMB5 ZPG */
+OP(77) { int tmp; RD_ZPG; RMB(7); WB_EA; } /* 4 RMB7 ZPG */
+OP(97) { int tmp; RD_ZPG; SMB(1); WB_EA; } /* 4 SMB1 ZPG */
+OP(b7) { int tmp; RD_ZPG; SMB(3); WB_EA; } /* 4 SMB3 ZPG */
+OP(d7) { int tmp; RD_ZPG; SMB(5); WB_EA; } /* 4 SMB5 ZPG */
+OP(f7) { int tmp; RD_ZPG; SMB(7); WB_EA; } /* 4 SMB7 ZPG */
+
+OP(08) { RD_DUM; PHP; } /* 3 PHP */
+OP(28) { RD_DUM; PLP; } /* 3 PLP */
+OP(48) { RD_DUM; PHA; } /* 3 PHA */
+OP(68) { RD_DUM; PLA; } /* 3 PLA */
+OP(88) { DEY; } /* 1 DEY */
+OP(a8) { TAY; } /* 1 TAY */
+OP(c8) { INY; } /* 1 INY */
+OP(e8) { INX; } /* 1 INX */
+
+OP(18) { CLC; } /* 1 CLC */
+OP(38) { SEC; } /* 1 SEC */
+OP(58) { CLI; } /* 1 CLI */
+OP(78) { RD_DUM; SEI; } /* 2 SEI */
+OP(98) { TYA; } /* 1 TYA */
+OP(b8) { CLV; } /* 1 CLV */
+OP(d8) { CLD; } /* 1 CLD */
+OP(f8) { SED; } /* 1 SED */
+
+OP(09) { int tmp; RD_IMM; ORA; } /* 2 ORA IMM */
+OP(29) { int tmp; RD_IMM; AND; } /* 2 AND IMM */
+OP(49) { int tmp; RD_IMM; EOR; } /* 2 EOR IMM */
+OP(69) { int tmp; RD_IMM; ADC; } /* 2 ADC IMM */
+OP(89) { int tmp; RD_IMM; BIT; } /* 2 BIT IMM */
+OP(a9) { int tmp; RD_IMM; LDA; } /* 2 LDA IMM */
+OP(c9) { int tmp; RD_IMM; CMP; } /* 2 CMP IMM */
+OP(e9) { int tmp; RD_IMM; SBC; } /* 2 SBC IMM */
+
+OP(19) { int tmp; RD_ABY; ORA; } /* 4 ORA ABY */
+OP(39) { int tmp; RD_ABY; AND; } /* 4 AND ABY */
+OP(59) { int tmp; RD_ABY; EOR; } /* 4 EOR ABY */
+OP(79) { int tmp; RD_ABY; ADC; } /* 4 ADC ABY */
+OP(99) { int tmp; STA; WR_ABY; } /* 4 STA ABY */
+OP(b9) { int tmp; RD_ABY; LDA; } /* 4 LDA ABY */
+OP(d9) { int tmp; RD_ABY; CMP; } /* 4 CMP ABY */
+OP(f9) { int tmp; RD_ABY; SBC; } /* 4 SBC ABY */
+
+OP(0a) { int tmp; RD_ACC; ASL; WR_ACC; } /* 1 ASL A */
+OP(2a) { int tmp; RD_ACC; ROL; WR_ACC; } /* 1 ROL A */
+OP(4a) { int tmp; RD_ACC; LSR; WR_ACC; } /* 1 LSR A */
+OP(6a) { int tmp; RD_ACC; ROR; WR_ACC; } /* 1 ROR A */
+OP(8a) { TXA; } /* 1 TXA */
+OP(aa) { TAX; } /* 1 TAX */
+OP(ca) { DEX; } /* 1 DEX */
+OP(ea) { NOP; } /* 1 NOP */
+
+OP(1a) { INA; } /* 1 INA */
+OP(3a) { DEA; } /* 1 DEA */
+OP(5a) { RD_DUM; PHY; } /* 3 PHY */
+OP(7a) { RD_DUM; PLY; } /* 3 PLY */
+OP(9a) { TXS; } /* 1 TXS */
+OP(ba) { TSX; } /* 1 TSX */
+OP(da) { RD_DUM; PHX; } /* 3 PHX */
+OP(fa) { RD_DUM; PLX; } /* 3 PLX */
+
+OP(0b) { TSY; } /* 1 TSY */
+OP(2b) { TYS; } /* 1 TYS */
+OP(4b) { TAZ; } /* 1 TAZ */
+OP(6b) { TZA; } /* 1 TZA */
+OP(8b) { int tmp; STY; WR_ABX; } /* 4 STY ABX */
+OP(ab) { int tmp; RD_ABS; LDZ; } /* 4 LDZ ABS */
+OP(cb) { PAIR tmp; tmp.d = 0; RD_ABS_WORD; ASW; WB_EA_WORD; } /* 7 ASW ABS */
+OP(eb) { PAIR tmp; RD_ABS_WORD; ROW; WB_EA_WORD; } /* 6/7? roW ABS */
+
+OP(1b) { INZ; } /* 1 INZ */
+OP(3b) { DEZ; } /* 1 DEZ */
+OP(5b) { TAB; } /* 1 TAB */
+OP(7b) { TBA; } /* 1 TBA */
+OP(9b) { int tmp; STX; WR_ABY; } /* 4 STX ABY */
+OP(bb) { int tmp; RD_ABX; LDZ; } /* 4 LDZ ABX */
+OP(db) { RD_DUM; PHZ; } /* 3 PHZ */
+OP(fb) { RD_DUM; PLZ; } /* 3 PLZ */
+
+OP(0c) { int tmp; RD_ABS; TSB; WB_EA; } /* 5 TSB ABS */
+OP(2c) { int tmp; RD_ABS; RD_DUM; BIT; } /* 5 BIT ABS */
+OP(4c) { EA_ABS; JMP; } /* 3 JMP ABS */
+OP(6c) { int tmp; EA_IND; JMP; } /* 5 JMP IND */
+OP(8c) { int tmp; STY; WR_ABS; } /* 4 STY ABS */
+OP(ac) { int tmp; RD_ABS; LDY; } /* 4 LDY ABS */
+OP(cc) { int tmp; RD_ABS; CPY; } /* 4 CPY ABS */
+OP(ec) { int tmp; RD_ABS; CPX; } /* 4 CPX ABS */
+
+OP(1c) { int tmp; RD_ABS; TRB; WB_EA; } /* 5 TRB ABS */
+OP(3c) { int tmp; RD_ABX; RD_DUM; BIT; } /* 5 BIT ABX */
+#ifdef M4510
+OP(5c) { MAP; } /* 4? MAP */
+#else
+OP(5c) { int t1,t2,t3; AUG; } /* 4 AUGMENT/no operation */
+#endif
+OP(7c) { int tmp; EA_IAX; JMP; } /* 5 JMP IAX */
+OP(9c) { int tmp; STZ_65CE02; WR_ABS; } /* 4 STZ ABS */
+OP(bc) { int tmp; RD_ABX; LDY; } /* 4 LDY ABX */
+OP(dc) { int tmp; RD_ABS; CPZ; } /* 4 CPZ ABS */
+OP(fc) { PAIR tmp; RD_ABS_WORD; PUSH_WORD(tmp); } /* 7 PHW ab */
+
+OP(0d) { int tmp; RD_ABS; ORA; } /* 4 ORA ABS */
+OP(2d) { int tmp; RD_ABS; AND; } /* 4 AND ABS */
+OP(4d) { int tmp; RD_ABS; EOR; } /* 4 EOR ABS */
+OP(6d) { int tmp; RD_ABS; ADC; } /* 4 ADC ABS */
+OP(8d) { int tmp; STA; WR_ABS; } /* 4 STA ABS */
+OP(ad) { int tmp; RD_ABS; LDA; } /* 4 LDA ABS */
+OP(cd) { int tmp; RD_ABS; CMP; } /* 4 CMP ABS */
+OP(ed) { int tmp; RD_ABS; SBC; } /* 4 SBC ABS */
+
+OP(1d) { int tmp; RD_ABX; ORA; } /* 4 ORA ABX */
+OP(3d) { int tmp; RD_ABX; AND; } /* 4 AND ABX */
+OP(5d) { int tmp; RD_ABX; EOR; } /* 4 EOR ABX */
+OP(7d) { int tmp; RD_ABX; ADC; } /* 4 ADC ABX */
+OP(9d) { int tmp; STA; WR_ABX; } /* 4 STA ABX */
+OP(bd) { int tmp; RD_ABX; LDA; } /* 4 LDA ABX */
+OP(dd) { int tmp; RD_ABX; CMP; } /* 4 CMP ABX */
+OP(fd) { int tmp; RD_ABX; SBC; } /* 4 SBC ABX */
+
+OP(0e) { int tmp; RD_ABS; ASL; WB_EA; } /* 5 ASL ABS */
+OP(2e) { int tmp; RD_ABS; ROL; WB_EA; } /* 5 ROL ABS */
+OP(4e) { int tmp; RD_ABS; LSR; WB_EA; } /* 5 LSR ABS */
+OP(6e) { int tmp; RD_ABS; ROR; WB_EA; } /* 5 ROR ABS */
+OP(8e) { int tmp; STX; WR_ABS; } /* 4 STX ABS */
+OP(ae) { int tmp; RD_ABS; LDX; } /* 4 LDX ABS */
+OP(ce) { int tmp; RD_ABS; DEC; WB_EA; } /* 5 DEC ABS */
+OP(ee) { int tmp; RD_ABS; INC; WB_EA; } /* 5 INC ABS */
+
+OP(1e) { int tmp; RD_ABX; ASL; WB_EA; } /* 5 ASL ABX */
+OP(3e) { int tmp; RD_ABX; ROL; WB_EA; } /* 5 ROL ABX */
+OP(5e) { int tmp; RD_ABX; LSR; WB_EA; } /* 5 LSR ABX */
+OP(7e) { int tmp; RD_ABX; ROR; WB_EA; } /* 5 ROR ABX */
+OP(9e) { int tmp; STZ_65CE02; WR_ABX; } /* 4 STZ ABX */
+OP(be) { int tmp; RD_ABY; LDX; } /* 4 LDX ABY */
+OP(de) { int tmp; RD_ABX; DEC; WB_EA; } /* 5 DEC ABX */
+OP(fe) { int tmp; RD_ABX; INC; WB_EA; } /* 5 INC ABX */
+
+OP(0f) { int tmp; RD_ZPG; BBR(0); } /* 4 BBR0 ZPG */
+OP(2f) { int tmp; RD_ZPG; BBR(2); } /* 4 BBR2 ZPG */
+OP(4f) { int tmp; RD_ZPG; BBR(4); } /* 4 BBR4 ZPG */
+OP(6f) { int tmp; RD_ZPG; BBR(6); } /* 4 BBR6 ZPG */
+OP(8f) { int tmp; RD_ZPG; BBS(0); } /* 4 BBS0 ZPG */
+OP(af) { int tmp; RD_ZPG; BBS(2); } /* 4 BBS2 ZPG */
+OP(cf) { int tmp; RD_ZPG; BBS(4); } /* 4 BBS4 ZPG */
+OP(ef) { int tmp; RD_ZPG; BBS(6); } /* 4 BBS6 ZPG */
+
+OP(1f) { int tmp; RD_ZPG; BBR(1); } /* 4 BBR1 ZPG */
+OP(3f) { int tmp; RD_ZPG; BBR(3); } /* 4 BBR3 ZPG */
+OP(5f) { int tmp; RD_ZPG; BBR(5); } /* 4 BBR5 ZPG */
+OP(7f) { int tmp; RD_ZPG; BBR(7); } /* 4 BBR7 ZPG */
+OP(9f) { int tmp; RD_ZPG; BBS(1); } /* 4 BBS1 ZPG */
+OP(bf) { int tmp; RD_ZPG; BBS(3); } /* 4 BBS3 ZPG */
+OP(df) { int tmp; RD_ZPG; BBS(5); } /* 4 BBS5 ZPG */
+OP(ff) { int tmp; RD_ZPG; BBS(7); } /* 4 BBS7 ZPG */
+
+#ifdef M4510
+static void (*insn4510[0x100])(void) = {
+ m4510_00,m4510_01,m4510_02,m4510_03,m4510_04,m4510_05,m4510_06,m4510_07,
+ m4510_08,m4510_09,m4510_0a,m4510_0b,m4510_0c,m4510_0d,m4510_0e,m4510_0f,
+ m4510_10,m4510_11,m4510_12,m4510_13,m4510_14,m4510_15,m4510_16,m4510_17,
+ m4510_18,m4510_19,m4510_1a,m4510_1b,m4510_1c,m4510_1d,m4510_1e,m4510_1f,
+ m4510_20,m4510_21,m4510_22,m4510_23,m4510_24,m4510_25,m4510_26,m4510_27,
+ m4510_28,m4510_29,m4510_2a,m4510_2b,m4510_2c,m4510_2d,m4510_2e,m4510_2f,
+ m4510_30,m4510_31,m4510_32,m4510_33,m4510_34,m4510_35,m4510_36,m4510_37,
+ m4510_38,m4510_39,m4510_3a,m4510_3b,m4510_3c,m4510_3d,m4510_3e,m4510_3f,
+ m4510_40,m4510_41,m4510_42,m4510_43,m4510_44,m4510_45,m4510_46,m4510_47,
+ m4510_48,m4510_49,m4510_4a,m4510_4b,m4510_4c,m4510_4d,m4510_4e,m4510_4f,
+ m4510_50,m4510_51,m4510_52,m4510_53,m4510_54,m4510_55,m4510_56,m4510_57,
+ m4510_58,m4510_59,m4510_5a,m4510_5b,m4510_5c,m4510_5d,m4510_5e,m4510_5f,
+ m4510_60,m4510_61,m4510_62,m4510_63,m4510_64,m4510_65,m4510_66,m4510_67,
+ m4510_68,m4510_69,m4510_6a,m4510_6b,m4510_6c,m4510_6d,m4510_6e,m4510_6f,
+ m4510_70,m4510_71,m4510_72,m4510_73,m4510_74,m4510_75,m4510_76,m4510_77,
+ m4510_78,m4510_79,m4510_7a,m4510_7b,m4510_7c,m4510_7d,m4510_7e,m4510_7f,
+ m4510_80,m4510_81,m4510_82,m4510_83,m4510_84,m4510_85,m4510_86,m4510_87,
+ m4510_88,m4510_89,m4510_8a,m4510_8b,m4510_8c,m4510_8d,m4510_8e,m4510_8f,
+ m4510_90,m4510_91,m4510_92,m4510_93,m4510_94,m4510_95,m4510_96,m4510_97,
+ m4510_98,m4510_99,m4510_9a,m4510_9b,m4510_9c,m4510_9d,m4510_9e,m4510_9f,
+ m4510_a0,m4510_a1,m4510_a2,m4510_a3,m4510_a4,m4510_a5,m4510_a6,m4510_a7,
+ m4510_a8,m4510_a9,m4510_aa,m4510_ab,m4510_ac,m4510_ad,m4510_ae,m4510_af,
+ m4510_b0,m4510_b1,m4510_b2,m4510_b3,m4510_b4,m4510_b5,m4510_b6,m4510_b7,
+ m4510_b8,m4510_b9,m4510_ba,m4510_bb,m4510_bc,m4510_bd,m4510_be,m4510_bf,
+ m4510_c0,m4510_c1,m4510_c2,m4510_c3,m4510_c4,m4510_c5,m4510_c6,m4510_c7,
+ m4510_c8,m4510_c9,m4510_ca,m4510_cb,m4510_cc,m4510_cd,m4510_ce,m4510_cf,
+ m4510_d0,m4510_d1,m4510_d2,m4510_d3,m4510_d4,m4510_d5,m4510_d6,m4510_d7,
+ m4510_d8,m4510_d9,m4510_da,m4510_db,m4510_dc,m4510_dd,m4510_de,m4510_df,
+ m4510_e0,m4510_e1,m4510_e2,m4510_e3,m4510_e4,m4510_e5,m4510_e6,m4510_e7,
+ m4510_e8,m4510_e9,m4510_ea,m4510_eb,m4510_ec,m4510_ed,m4510_ee,m4510_ef,
+ m4510_f0,m4510_f1,m4510_f2,m4510_f3,m4510_f4,m4510_f5,m4510_f6,m4510_f7,
+ m4510_f8,m4510_f9,m4510_fa,m4510_fb,m4510_fc,m4510_fd,m4510_fe,m4510_ff
+};
+#else
+static void (*insn65ce02[0x100])(void) = {
+ m65ce02_00,m65ce02_01,m65ce02_02,m65ce02_03,m65ce02_04,m65ce02_05,m65ce02_06,m65ce02_07,
+ m65ce02_08,m65ce02_09,m65ce02_0a,m65ce02_0b,m65ce02_0c,m65ce02_0d,m65ce02_0e,m65ce02_0f,
+ m65ce02_10,m65ce02_11,m65ce02_12,m65ce02_13,m65ce02_14,m65ce02_15,m65ce02_16,m65ce02_17,
+ m65ce02_18,m65ce02_19,m65ce02_1a,m65ce02_1b,m65ce02_1c,m65ce02_1d,m65ce02_1e,m65ce02_1f,
+ m65ce02_20,m65ce02_21,m65ce02_22,m65ce02_23,m65ce02_24,m65ce02_25,m65ce02_26,m65ce02_27,
+ m65ce02_28,m65ce02_29,m65ce02_2a,m65ce02_2b,m65ce02_2c,m65ce02_2d,m65ce02_2e,m65ce02_2f,
+ m65ce02_30,m65ce02_31,m65ce02_32,m65ce02_33,m65ce02_34,m65ce02_35,m65ce02_36,m65ce02_37,
+ m65ce02_38,m65ce02_39,m65ce02_3a,m65ce02_3b,m65ce02_3c,m65ce02_3d,m65ce02_3e,m65ce02_3f,
+ m65ce02_40,m65ce02_41,m65ce02_42,m65ce02_43,m65ce02_44,m65ce02_45,m65ce02_46,m65ce02_47,
+ m65ce02_48,m65ce02_49,m65ce02_4a,m65ce02_4b,m65ce02_4c,m65ce02_4d,m65ce02_4e,m65ce02_4f,
+ m65ce02_50,m65ce02_51,m65ce02_52,m65ce02_53,m65ce02_54,m65ce02_55,m65ce02_56,m65ce02_57,
+ m65ce02_58,m65ce02_59,m65ce02_5a,m65ce02_5b,m65ce02_5c,m65ce02_5d,m65ce02_5e,m65ce02_5f,
+ m65ce02_60,m65ce02_61,m65ce02_62,m65ce02_63,m65ce02_64,m65ce02_65,m65ce02_66,m65ce02_67,
+ m65ce02_68,m65ce02_69,m65ce02_6a,m65ce02_6b,m65ce02_6c,m65ce02_6d,m65ce02_6e,m65ce02_6f,
+ m65ce02_70,m65ce02_71,m65ce02_72,m65ce02_73,m65ce02_74,m65ce02_75,m65ce02_76,m65ce02_77,
+ m65ce02_78,m65ce02_79,m65ce02_7a,m65ce02_7b,m65ce02_7c,m65ce02_7d,m65ce02_7e,m65ce02_7f,
+ m65ce02_80,m65ce02_81,m65ce02_82,m65ce02_83,m65ce02_84,m65ce02_85,m65ce02_86,m65ce02_87,
+ m65ce02_88,m65ce02_89,m65ce02_8a,m65ce02_8b,m65ce02_8c,m65ce02_8d,m65ce02_8e,m65ce02_8f,
+ m65ce02_90,m65ce02_91,m65ce02_92,m65ce02_93,m65ce02_94,m65ce02_95,m65ce02_96,m65ce02_97,
+ m65ce02_98,m65ce02_99,m65ce02_9a,m65ce02_9b,m65ce02_9c,m65ce02_9d,m65ce02_9e,m65ce02_9f,
+ m65ce02_a0,m65ce02_a1,m65ce02_a2,m65ce02_a3,m65ce02_a4,m65ce02_a5,m65ce02_a6,m65ce02_a7,
+ m65ce02_a8,m65ce02_a9,m65ce02_aa,m65ce02_ab,m65ce02_ac,m65ce02_ad,m65ce02_ae,m65ce02_af,
+ m65ce02_b0,m65ce02_b1,m65ce02_b2,m65ce02_b3,m65ce02_b4,m65ce02_b5,m65ce02_b6,m65ce02_b7,
+ m65ce02_b8,m65ce02_b9,m65ce02_ba,m65ce02_bb,m65ce02_bc,m65ce02_bd,m65ce02_be,m65ce02_bf,
+ m65ce02_c0,m65ce02_c1,m65ce02_c2,m65ce02_c3,m65ce02_c4,m65ce02_c5,m65ce02_c6,m65ce02_c7,
+ m65ce02_c8,m65ce02_c9,m65ce02_ca,m65ce02_cb,m65ce02_cc,m65ce02_cd,m65ce02_ce,m65ce02_cf,
+ m65ce02_d0,m65ce02_d1,m65ce02_d2,m65ce02_d3,m65ce02_d4,m65ce02_d5,m65ce02_d6,m65ce02_d7,
+ m65ce02_d8,m65ce02_d9,m65ce02_da,m65ce02_db,m65ce02_dc,m65ce02_dd,m65ce02_de,m65ce02_df,
+ m65ce02_e0,m65ce02_e1,m65ce02_e2,m65ce02_e3,m65ce02_e4,m65ce02_e5,m65ce02_e6,m65ce02_e7,
+ m65ce02_e8,m65ce02_e9,m65ce02_ea,m65ce02_eb,m65ce02_ec,m65ce02_ed,m65ce02_ee,m65ce02_ef,
+ m65ce02_f0,m65ce02_f1,m65ce02_f2,m65ce02_f3,m65ce02_f4,m65ce02_f5,m65ce02_f6,m65ce02_f7,
+ m65ce02_f8,m65ce02_f9,m65ce02_fa,m65ce02_fb,m65ce02_fc,m65ce02_fd,m65ce02_fe,m65ce02_ff
+};
+#endif
+
diff --git a/src/emu/cpu/m6502/t65sc02.c b/src/emu/cpu/m6502/t65sc02.c
new file mode 100644
index 00000000000..aab67064035
--- /dev/null
+++ b/src/emu/cpu/m6502/t65sc02.c
@@ -0,0 +1,80 @@
+/*****************************************************************************
+ *
+ * tbl65sc02.c
+ * 65sc02 opcode functions and function pointer table
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+/* 4. February 2000 PeT fixed relative word operand */
+
+/* opcode already in 65c02
+ although docu says they were introduced with this cpu
+
+ bbr
+ bbs
+ rmb
+ smb
+ trb
+ tsb
+*/
+
+#undef OP
+#define OP(nn) INLINE void m65sc02_##nn(void)
+
+/*****************************************************************************
+ *****************************************************************************
+ *
+ * overrides for 65SC02 opcodes
+ *
+ *****************************************************************************
+ * op temp cycles rdmem opc wrmem ********************/
+OP(63) { BSR; } /* 5? BSR */
+
+static void (*insn65sc02[0x100])(void) = {
+ m65c02_00,m65c02_01,m65c02_02,m65c02_03,m65c02_04,m65c02_05,m65c02_06,m65c02_07,
+ m65c02_08,m65c02_09,m65c02_0a,m65c02_0b,m65c02_0c,m65c02_0d,m65c02_0e,m65c02_0f,
+ m65c02_10,m65c02_11,m65c02_12,m65c02_13,m65c02_14,m65c02_15,m65c02_16,m65c02_17,
+ m65c02_18,m65c02_19,m65c02_1a,m65c02_1b,m65c02_1c,m65c02_1d,m65c02_1e,m65c02_1f,
+ m65c02_20,m65c02_21,m65c02_22,m65c02_23,m65c02_24,m65c02_25,m65c02_26,m65c02_27,
+ m65c02_28,m65c02_29,m65c02_2a,m65c02_2b,m65c02_2c,m65c02_2d,m65c02_2e,m65c02_2f,
+ m65c02_30,m65c02_31,m65c02_32,m65c02_33,m65c02_34,m65c02_35,m65c02_36,m65c02_37,
+ m65c02_38,m65c02_39,m65c02_3a,m65c02_3b,m65c02_3c,m65c02_3d,m65c02_3e,m65c02_3f,
+ m65c02_40,m65c02_41,m65c02_42,m65c02_43,m65c02_44,m65c02_45,m65c02_46,m65c02_47,
+ m65c02_48,m65c02_49,m65c02_4a,m65c02_4b,m65c02_4c,m65c02_4d,m65c02_4e,m65c02_4f,
+ m65c02_50,m65c02_51,m65c02_52,m65c02_53,m65c02_54,m65c02_55,m65c02_56,m65c02_57,
+ m65c02_58,m65c02_59,m65c02_5a,m65c02_5b,m65c02_5c,m65c02_5d,m65c02_5e,m65c02_5f,
+ m65c02_60,m65c02_61,m65c02_62,m65c02_63,m65c02_64,m65c02_65,m65c02_66,m65c02_67,
+ m65c02_68,m65c02_69,m65c02_6a,m65c02_6b,m65c02_6c,m65c02_6d,m65c02_6e,m65c02_6f,
+ m65c02_70,m65c02_71,m65c02_72,m65c02_73,m65c02_74,m65c02_75,m65c02_76,m65c02_77,
+ m65c02_78,m65c02_79,m65c02_7a,m65c02_7b,m65c02_7c,m65c02_7d,m65c02_7e,m65c02_7f,
+ m65c02_80,m65c02_81,m65c02_82,m65c02_83,m65c02_84,m65c02_85,m65c02_86,m65c02_87,
+ m65c02_88,m65c02_89,m65c02_8a,m65c02_8b,m65c02_8c,m65c02_8d,m65c02_8e,m65c02_8f,
+ m65c02_90,m65c02_91,m65c02_92,m65c02_93,m65c02_94,m65c02_95,m65c02_96,m65c02_97,
+ m65c02_98,m65c02_99,m65c02_9a,m65c02_9b,m65c02_9c,m65c02_9d,m65c02_9e,m65c02_9f,
+ m65c02_a0,m65c02_a1,m65c02_a2,m65c02_a3,m65c02_a4,m65c02_a5,m65c02_a6,m65c02_a7,
+ m65c02_a8,m65c02_a9,m65c02_aa,m65c02_ab,m65c02_ac,m65c02_ad,m65c02_ae,m65c02_af,
+ m65c02_b0,m65c02_b1,m65c02_b2,m65c02_b3,m65c02_b4,m65c02_b5,m65c02_b6,m65c02_b7,
+ m65c02_b8,m65c02_b9,m65c02_ba,m65c02_bb,m65c02_bc,m65c02_bd,m65c02_be,m65c02_bf,
+ m65c02_c0,m65c02_c1,m65c02_c2,m65c02_c3,m65c02_c4,m65c02_c5,m65c02_c6,m65c02_c7,
+ m65c02_c8,m65c02_c9,m65c02_ca,m65c02_cb,m65c02_cc,m65c02_cd,m65c02_ce,m65c02_cf,
+ m65c02_d0,m65c02_d1,m65c02_d2,m65c02_d3,m65c02_d4,m65c02_d5,m65c02_d6,m65c02_d7,
+ m65c02_d8,m65c02_d9,m65c02_da,m65c02_db,m65c02_dc,m65c02_dd,m65c02_de,m65c02_df,
+ m65c02_e0,m65c02_e1,m65c02_e2,m65c02_e3,m65c02_e4,m65c02_e5,m65c02_e6,m65c02_e7,
+ m65c02_e8,m65c02_e9,m65c02_ea,m65c02_eb,m65c02_ec,m65c02_ed,m65c02_ee,m65c02_ef,
+ m65c02_f0,m65c02_f1,m65c02_f2,m65c02_f3,m65c02_f4,m65c02_f5,m65c02_f6,m65c02_f7,
+ m65c02_f8,m65c02_f9,m65c02_fa,m65c02_fb,m65c02_fc,m65c02_fd,m65c02_fe,m65c02_ff
+};
+
diff --git a/src/emu/cpu/m6502/tdeco16.c b/src/emu/cpu/m6502/tdeco16.c
new file mode 100644
index 00000000000..f1802ad1b03
--- /dev/null
+++ b/src/emu/cpu/m6502/tdeco16.c
@@ -0,0 +1,429 @@
+/*****************************************************************************
+ * Deco CPU16 instructions - still very work in progress!
+ *
+ *****************************************************************************/
+
+#define DECO16_VERBOSE 0
+
+#undef OP
+#define OP(nn) INLINE void deco16_##nn(void)
+
+#define DECO16_BRK \
+ logerror("%04x: BRK\n",activecpu_get_pc()); \
+ RDOPARG(); \
+ PUSH(PCH); \
+ PUSH(PCL); \
+ PUSH(P | F_B); \
+ P = (P | F_I); \
+ PCL = RDMEM(DECO16_IRQ_VEC+1); \
+ PCH = RDMEM(DECO16_IRQ_VEC); \
+ CHANGE_PC
+
+
+/*****************************************************************************
+ *****************************************************************************
+ *
+ * overrides for 6502 opcodes
+ *
+ *****************************************************************************
+ * op temp cycles rdmem opc wrmem ********************/
+OP(00) { DECO16_BRK; } /* 7 BRK */
+#define deco16_20 m6502_20 /* 6 JSR ABS */
+#define deco16_40 m6502_40 /* 6 RTI */
+#define deco16_60 m6502_60 /* 6 RTS */
+OP(80) { RD_DUM; ILL; } /* 2 ILL */
+#define deco16_a0 m6502_a0 /* 2 LDY IMM */
+#define deco16_c0 m6502_c0 /* 2 CPY IMM */
+#define deco16_e0 m6502_e0 /* 2 CPX IMM */
+
+#define deco16_10 m6502_10 /* 2 BPL */
+#define deco16_30 m6502_30 /* 2 BMI */
+#define deco16_50 m6502_50 /* 2 BVC */
+#define deco16_70 m6502_70 /* 2 BVS */
+#define deco16_90 m6502_90 /* 2 BCC */
+#define deco16_b0 m6502_b0 /* 2 BCS */
+#define deco16_d0 m6502_d0 /* 2 BNE */
+#define deco16_f0 m6502_f0 /* 2 BEQ */
+
+#define deco16_01 m6502_01 /* 6 ORA IDX */
+#define deco16_21 m6502_21 /* 6 AND IDX */
+#define deco16_41 m6502_41 /* 6 EOR IDX */
+#define deco16_61 m6502_61 /* 6 ADC IDX */
+#define deco16_81 m6502_81 /* 6 STA IDX */
+#define deco16_a1 m6502_a1 /* 6 LDA IDX */
+#define deco16_c1 m6502_c1 /* 6 CMP IDX */
+#define deco16_e1 m6502_e1 /* 6 SBC IDX */
+
+#define deco16_11 m6502_11 /* 5 ORA IDY; */
+#define deco16_31 m6502_31 /* 5 AND IDY; */
+#define deco16_51 m6502_51 /* 5 EOR IDY; */
+#define deco16_71 m6502_71 /* 5 ADC IDY; */
+#define deco16_91 m6502_91 /* 6 STA IDY; */
+#define deco16_b1 m6502_b1 /* 5 LDA IDY; */
+#define deco16_d1 m6502_d1 /* 5 CMP IDY; */
+#define deco16_f1 m6502_f1 /* 5 SBC IDY; */
+
+OP(02) { RD_DUM; ILL; } /* 2 ILL */
+OP(22) { RD_DUM; ILL; } /* 2 ILL */
+OP(42) { RD_DUM; ILL; } /* 2 ILL */
+OP(62) { RD_DUM; ILL; } /* 2 ILL */
+OP(82) { RD_DUM; ILL; } /* 2 ILL */
+#define deco16_a2 m6502_a2 /* 2 LDX IMM */
+OP(c2) { RD_DUM; ILL; } /* 2 ILL */
+OP(e2) { RD_DUM; ILL; } /* 2 ILL */
+
+OP(12) { RD_DUM; ILL; } /* 2 ILL / 3 ora zpi ?? */
+OP(32) { RD_DUM; ILL; } /* 2 ILL / 3 and zpi ?? */
+OP(52) { RD_DUM; ILL; } /* 2 ILL / 3 eor zpi ?? */
+OP(72) { RD_DUM; ILL; } /* 2 ILL / 3 adc zpi ?? */
+OP(92) { RD_DUM; ILL; } /* 2 ILL / 3 sta zpi ?? */
+OP(b2) { RD_DUM; ILL; } /* 2 ILL / 3 lda zpi ?? */
+OP(d2) { RD_DUM; ILL; } /* 2 ILL / 3 cmp zpi ?? */
+OP(f2) { RD_DUM; ILL; } /* 2 ILL / 3 sbc zpi ?? */
+
+OP(03) { RD_DUM; ILL; } /* 2 ILL */
+OP(23) {
+ int tmp;
+
+ m6502_ICount -= 1;
+ RD_IMM;
+
+ if (DECO16_VERBOSE)
+ logerror("%04x: OP23 %02x\n",activecpu_get_pc(),tmp);
+}
+OP(43) { RD_DUM; ILL; } /* 2 ILL */
+OP(63) {
+ int tmp;
+
+ m6502_ICount -= 1;
+ RD_IMM;
+
+ if (DECO16_VERBOSE)
+ logerror("%04x: OP63 %02x\n",activecpu_get_pc(),tmp);
+}
+OP(83) { RD_DUM; ILL; } /* 2 ILL */
+OP(a3) {
+ int tmp;
+
+ m6502_ICount -= 1;
+ RD_IMM;
+
+ if (DECO16_VERBOSE)
+ logerror("%04x: OPA3 %02x\n",activecpu_get_pc(),tmp);
+}
+OP(c3) { RD_DUM; ILL; } /* 2 ILL */
+OP(e3) { RD_DUM; ILL; } /* 2 ILL */
+
+OP(13) { int tmp; m6502_ICount -= 1; RD_IMM;
+
+ if (DECO16_VERBOSE)
+ logerror("%04x: OP13 %02x\n",activecpu_get_pc(),tmp);
+
+//bank select control?
+
+ } /* */
+OP(33) { RD_DUM; ILL; } /* 2 ILL */
+OP(53) { RD_DUM; ILL; } /* 2 ILL */
+OP(73) { RD_DUM; ILL; } /* 2 ILL */
+OP(93) { RD_DUM; ILL; } /* 2 ILL */
+OP(b3) { RD_DUM; ILL; } /* 2 ILL */
+OP(d3) { RD_DUM; ILL; } /* 2 ILL */
+OP(f3) { RD_DUM; ILL; } /* 2 ILL */
+
+OP(04) { RD_DUM; ILL; } /* 2 ILL / 3 tsb zpg ?? */
+#define deco16_24 m6502_24 /* 3 BIT ZPG */
+OP(44) { RD_DUM; ILL; } /* 2 ILL */
+OP(64) { RD_DUM; ILL; } /* 2 ILL / 3 stz zpg ?? */
+#define deco16_84 m6502_84 /* 3 STY ZPG */
+#define deco16_a4 m6502_a4 /* 3 LDY ZPG */
+#define deco16_c4 m6502_c4 /* 3 CPY ZPG */
+#define deco16_e4 m6502_e4 /* 3 CPX ZPG */
+
+OP(14) { RD_DUM; ILL; } /* 2 ILL / 3 trb zpg ?? */
+OP(34) { RD_DUM; ILL; } /* 2 ILL / 4 bit zpx ?? */
+OP(54) { RD_DUM; ILL; } /* 2 ILL */
+OP(74) { RD_DUM; ILL; } /* 2 ILL / 4 stz zpx ?? */
+OP(94) { RD_DUM; ILL; } /* 2 ILL / 4 sty zpx ?? */
+#define deco16_b4 m6502_b4 /* 4 ldy zpx */
+OP(d4) { RD_DUM; ILL; } /* 2 ILL */
+OP(f4) { RD_DUM; ILL; } /* 2 ILL */
+
+#define deco16_05 m6502_05 /* 3 ORA ZPG */
+#define deco16_25 m6502_25 /* 3 AND ZPG */
+#define deco16_45 m6502_45 /* 3 EOR ZPG */
+#define deco16_65 m6502_65 /* 3 ADC ZPG */
+#define deco16_85 m6502_85 /* 3 STA ZPG */
+#define deco16_a5 m6502_a5 /* 3 LDA ZPG */
+#define deco16_c5 m6502_c5 /* 3 CMP ZPG */
+#define deco16_e5 m6502_e5 /* 3 SBC ZPG */
+
+#define deco16_15 m6502_15 /* 4 ORA ZPX */
+#define deco16_35 m6502_35 /* 4 AND ZPX */
+#define deco16_55 m6502_55 /* 4 EOR ZPX */
+#define deco16_75 m6502_75 /* 4 ADC ZPX */
+#define deco16_95 m6502_95 /* 4 STA ZPX */
+#define deco16_b5 m6502_b5 /* 4 LDA ZPX */
+#define deco16_d5 m6502_d5 /* 4 CMP ZPX */
+#define deco16_f5 m6502_f5 /* 4 SBC ZPX */
+
+#define deco16_06 m6502_06 /* 5 ASL ZPG */
+#define deco16_26 m6502_26 /* 5 ROL ZPG */
+#define deco16_46 m6502_46 /* 5 LSR ZPG */
+#define deco16_66 m6502_66 /* 5 ROR ZPG */
+#define deco16_86 m6502_86 /* 3 STX ZPG */
+#define deco16_a6 m6502_a6 /* 3 LDX ZPG */
+#define deco16_c6 m6502_c6 /* 5 DEC ZPG */
+#define deco16_e6 m6502_e6 /* 5 INC ZPG */
+
+#define deco16_16 m6502_16 /* 6 ASL ZPX */
+#define deco16_36 m6502_36 /* 6 ROL ZPX */
+#define deco16_56 m6502_56 /* 6 LSR ZPX */
+#define deco16_76 m6502_76 /* 6 ROR ZPX */
+#define deco16_96 m6502_96 /* 4 STX ZPY */
+#define deco16_b6 m6502_b6 /* 4 LDX ZPY */
+#define deco16_d6 m6502_d6 /* 6 DEC ZPX */
+#define deco16_f6 m6502_f6 /* 6 INC ZPX */
+
+OP(07) { RD_DUM; ILL; } /* 2 ILL / 5 RMB0 ZPG ?? */
+OP(27) { RD_DUM; ILL; } /* 2 ILL / 5 RMB2 ZPG ?? */
+OP(47) { RD_DUM; ILL; } /* 2 ILL / 5 RMB4 ZPG ?? */
+OP(67) {
+ int tmp; RD_IMM;
+ m6502.a=io_read_byte_8(0);
+
+// logerror("%04x: VBL (0x67)\n",activecpu_get_pc());
+
+// really - wait for status?
+
+} /* */
+OP(87) { int tmp; m6502_ICount -= 1; RD_IMM;
+ logerror("%04x: OP87 %02x\n",activecpu_get_pc(),tmp);
+
+ } /* */
+OP(a7) { RD_DUM; ILL; } /* 2 ILL / 5 SMB2 ZPG ?? */
+OP(c7) { RD_DUM; ILL; } /* 2 ILL / 5 SMB4 ZPG ?? */
+OP(e7) { RD_DUM; ILL; } /* 2 ILL / 5 SMB6 ZPG ?? */
+
+OP(17) { RD_DUM; ILL; } /* 2 ILL / 5 RMB1 ZPG ?? */
+OP(37) { RD_DUM; ILL; } /* 2 ILL / 5 RMB3 ZPG ?? */
+OP(57) { RD_DUM; ILL; } /* 2 ILL / 5 RMB5 ZPG ?? */
+OP(77) { RD_DUM; ILL; } /* 2 ILL / 5 RMB7 ZPG ?? */
+OP(97) { RD_DUM; ILL; } /* 2 ILL / 5 SMB1 ZPG ?? */
+OP(b7) { RD_DUM; ILL; } /* 2 ILL / 5 SMB3 ZPG ?? */
+OP(d7) { RD_DUM; ILL; } /* 2 ILL / 5 SMB5 ZPG ?? */
+OP(f7) { RD_DUM; ILL; } /* 2 ILL / 5 SMB7 ZPG ?? */
+
+#define deco16_08 m6502_08 /* 3 PHP */
+#define deco16_28 m6502_28 /* 4 PLP */
+#define deco16_48 m6502_48 /* 3 PHA */
+#define deco16_68 m6502_68 /* 4 PLA */
+#define deco16_88 m6502_88 /* 2 DEY */
+#define deco16_a8 m6502_a8 /* 2 TAY */
+#define deco16_c8 m6502_c8 /* 2 INY */
+#define deco16_e8 m6502_e8 /* 2 INX */
+
+#define deco16_18 m6502_18 /* 2 CLC */
+#define deco16_38 m6502_38 /* 2 SEC */
+#define deco16_58 m6502_58 /* 2 CLI */
+#define deco16_78 m6502_78 /* 2 SEI */
+#define deco16_98 m6502_98 /* 2 TYA */
+#define deco16_b8 m6502_b8 /* 2 CLV */
+#define deco16_d8 m6502_d8 /* 2 CLD */
+#define deco16_f8 m6502_f8 /* 2 SED */
+
+#define deco16_09 m6502_09 /* 2 ORA IMM */
+#define deco16_29 m6502_29 /* 2 AND IMM */
+#define deco16_49 m6502_49 /* 2 EOR IMM */
+#define deco16_69 m6502_69 /* 2 ADC IMM */
+#define deco16_89 m65c02_89 /* 2 BIT IMM */
+#define deco16_a9 m6502_a9 /* 2 LDA IMM */
+#define deco16_c9 m6502_c9 /* 2 CMP IMM */
+#define deco16_e9 m6502_e9 /* 2 SBC IMM */
+
+#define deco16_19 m6502_19 /* 4 ORA ABY */
+#define deco16_39 m6502_39 /* 4 AND ABY */
+#define deco16_59 m6502_59 /* 4 EOR ABY */
+#define deco16_79 m6502_79 /* 4 ADC ABY */
+#define deco16_99 m6502_99 /* 5 STA ABY */
+#define deco16_b9 m6502_b9 /* 4 LDA ABY */
+#define deco16_d9 m6502_d9 /* 4 CMP ABY */
+#define deco16_f9 m6502_f9 /* 4 SBC ABY */
+
+#define deco16_0a m6502_0a /* 2 ASL */
+#define deco16_2a m6502_2a /* 2 ROL */
+#define deco16_4a m6502_4a /* 2 LSR */
+#define deco16_6a m6502_6a /* 2 ROR */
+#define deco16_8a m6502_8a /* 2 TXA */
+#define deco16_aa m6502_aa /* 2 TAX */
+#define deco16_ca m6502_ca /* 2 DEX */
+#define deco16_ea m6502_ea /* 2 NOP */
+
+#define deco16_1a m65c02_1a /* 2 INA */
+#define deco16_3a m65c02_3a /* 2 DEA */
+#define deco16_5a m65c02_5a /* 3 PHY */
+#define deco16_7a m65c02_7a /* 4 PLY */
+#define deco16_9a m6502_9a /* 2 TXS */
+#define deco16_ba m6502_ba /* 2 TSX */
+#define deco16_da m65c02_da /* 3 PHX */
+#define deco16_fa m65c02_fa /* 4 PLX */
+
+OP(0b) { int tmp; m6502_ICount -= 1; RD_IMM;
+ logerror("%04x: OP0B %02x\n",activecpu_get_pc(),tmp);
+
+ }
+OP(2b) { RD_DUM; ILL; } /* 2 ILL */
+OP(4b) { int tmp; m6502_ICount -= 1; RD_IMM;
+ logerror("%04x: OP4B %02x\n",activecpu_get_pc(),tmp);
+
+// m6502.a=io_read_byte_8(0);
+
+//tilt??
+
+//VBL on expr-raider
+//VBL on boomrang (bit 2)
+
+ }
+OP(6b) { RD_DUM; ILL; } /* 2 ILL */
+OP(8b) { RD_DUM; ILL; } /* 2 ILL */
+OP(ab) { RD_DUM; ILL; } /* 2 ILL */
+OP(cb) { RD_DUM; ILL; } /* 2 ILL */
+OP(eb) { RD_DUM; ILL; } /* 2 ILL */
+
+OP(1b) { RD_DUM; ILL; } /* 2 ILL */
+OP(3b) { RD_DUM; ILL; } /* 2 ILL */
+OP(5b) { RD_DUM; ILL; } /* 2 ILL */
+OP(7b) { RD_DUM; ILL; } /* 2 ILL */
+OP(9b) { RD_DUM; ILL; } /* 2 ILL */
+OP(bb) {
+ int tmp;
+
+ m6502_ICount -= 1;
+ RD_IMM;
+
+ if (DECO16_VERBOSE)
+ logerror("%04x: OPBB %02x\n",activecpu_get_pc(),tmp);
+}
+OP(db) { RD_DUM; ILL; } /* 2 ILL */
+OP(fb) { RD_DUM; ILL; } /* 2 ILL */
+
+#define deco16_0c m65c02_0c /* 4 TSB ABS */
+#define deco16_2c m6502_2c /* 4 BIT ABS */
+#define deco16_4c m6502_4c /* 3 JMP ABS */
+#define deco16_6c m65c02_6c /* 5 JMP IND */
+#define deco16_8c m6502_8c /* 4 STY ABS */
+#define deco16_ac m6502_ac /* 4 LDY ABS */
+#define deco16_cc m6502_cc /* 4 CPY ABS */
+#define deco16_ec m6502_ec /* 4 CPX ABS */
+
+#define deco16_1c m65c02_1c /* 4 TRB ABS */
+#define deco16_3c m65c02_3c /* 4 BIT ABX */
+OP(5c) { RD_DUM; ILL; } /* 2 ILL */
+#define deco16_7c m65c02_7c /* 6 JMP IAX */
+#define deco16_9c m65c02_9c /* 4 STZ ABS */
+#define deco16_bc m65c02_bc /* 4 LDY ABX */
+OP(dc) { RD_DUM; ILL; } /* 2 ILL */
+OP(fc) { RD_DUM; ILL; } /* 2 ILL */
+
+#define deco16_0d m6502_0d /* 4 ORA ABS */
+#define deco16_2d m6502_2d /* 4 AND ABS */
+#define deco16_4d m6502_4d /* 4 EOR ABS */
+#define deco16_6d m6502_6d /* 4 ADC ABS */
+#define deco16_8d m6502_8d /* 4 STA ABS */
+#define deco16_ad m6502_ad /* 4 LDA ABS */
+#define deco16_cd m6502_cd /* 4 CMP ABS */
+#define deco16_ed m6502_ed /* 4 SBC ABS */
+
+#define deco16_1d m6502_1d /* 4 ORA ABX */
+#define deco16_3d m6502_3d /* 4 AND ABX */
+#define deco16_5d m6502_5d /* 4 EOR ABX */
+#define deco16_7d m6502_7d /* 4 ADC ABX */
+#define deco16_9d m6502_9d /* 5 STA ABX */
+#define deco16_bd m6502_bd /* 4 LDA ABX */
+#define deco16_dd m6502_dd /* 4 CMP ABX */
+#define deco16_fd m6502_fd /* 4 SBC ABX */
+
+#define deco16_0e m6502_0e /* 6 ASL ABS */
+#define deco16_2e m6502_2e /* 6 ROL ABS */
+#define deco16_4e m6502_4e /* 6 LSR ABS */
+#define deco16_6e m6502_6e /* 6 ROR ABS */
+#define deco16_8e m6502_8e /* 4 STX ABS */
+#define deco16_ae m6502_ae /* 4 LDX ABS */
+#define deco16_ce m6502_ce /* 6 DEC ABS */
+#define deco16_ee m6502_ee /* 6 INC ABS */
+
+#define deco16_1e m6502_1e /* 7 ASL ABX */
+#define deco16_3e m6502_3e /* 7 ROL ABX */
+#define deco16_5e m6502_5e /* 7 LSR ABX */
+#define deco16_7e m6502_7e /* 7 ROR ABX */
+#define deco16_9e m65c02_9e /* 5 STZ ABX */
+#define deco16_be m6502_be /* 4 LDX ABY */
+#define deco16_de m6502_de /* 7 DEC ABX */
+#define deco16_fe m6502_fe /* 7 INC ABX */
+
+OP(0f) { RD_DUM; ILL; } /* 2 ILL / 5 BBR0 ZPG ?? */
+OP(2f) { RD_DUM; ILL; } /* 2 ILL / 5 BBR2 ZPG ?? */
+OP(4f) { RD_DUM; ILL; } /* 2 ILL / 5 BBR4 ZPG ?? */
+OP(6f) { RD_DUM; ILL; } /* 2 ILL / 5 BBR6 ZPG ?? */
+OP(8f) { int tmp; m6502_ICount -= 1; RD_IMM;
+ logerror("%04x: BANK (8F) %02x\n",activecpu_get_pc(),tmp);
+
+ io_write_byte_8(0,tmp);
+
+//swap bank in/out
+
+ } /* */
+OP(af) { RD_DUM; ILL; } /* 2 ILL / 5 BBS2 ZPG ?? */
+OP(cf) { RD_DUM; ILL; } /* 2 ILL / 5 BBS4 ZPG ?? */
+OP(ef) { RD_DUM; ILL; } /* 2 ILL / 5 BBS6 ZPG ?? */
+
+OP(1f) { RD_DUM; ILL; } /* 2 ILL / 5 BBR1 ZPG ?? */
+OP(3f) {
+ int tmp;
+
+ m6502_ICount -= 1;
+ RD_IMM;
+
+ if (DECO16_VERBOSE)
+ logerror("%04x: OP3F %02x\n",activecpu_get_pc(),tmp);
+}
+OP(5f) { RD_DUM; ILL; } /* 2 ILL / 5 BBR5 ZPG ?? */
+OP(7f) { RD_DUM; ILL; } /* 2 ILL / 5 BBR7 ZPG ?? */
+OP(9f) { RD_DUM; ILL; } /* 2 ILL / 5 BBS1 ZPG ?? */
+OP(bf) { RD_DUM; ILL; } /* 2 ILL / 5 BBS3 ZPG ?? */
+OP(df) { RD_DUM; ILL; } /* 2 ILL / 5 BBS5 ZPG ?? */
+OP(ff) { RD_DUM; ILL; } /* 2 ILL / 5 BBS7 ZPG ?? */
+
+static void (*insndeco16[0x100])(void) = {
+ deco16_00,deco16_01,deco16_02,deco16_03,deco16_04,deco16_05,deco16_06,deco16_07,
+ deco16_08,deco16_09,deco16_0a,deco16_0b,deco16_0c,deco16_0d,deco16_0e,deco16_0f,
+ deco16_10,deco16_11,deco16_12,deco16_13,deco16_14,deco16_15,deco16_16,deco16_17,
+ deco16_18,deco16_19,deco16_1a,deco16_1b,deco16_1c,deco16_1d,deco16_1e,deco16_1f,
+ deco16_20,deco16_21,deco16_22,deco16_23,deco16_24,deco16_25,deco16_26,deco16_27,
+ deco16_28,deco16_29,deco16_2a,deco16_2b,deco16_2c,deco16_2d,deco16_2e,deco16_2f,
+ deco16_30,deco16_31,deco16_32,deco16_33,deco16_34,deco16_35,deco16_36,deco16_37,
+ deco16_38,deco16_39,deco16_3a,deco16_3b,deco16_3c,deco16_3d,deco16_3e,deco16_3f,
+ deco16_40,deco16_41,deco16_42,deco16_43,deco16_44,deco16_45,deco16_46,deco16_47,
+ deco16_48,deco16_49,deco16_4a,deco16_4b,deco16_4c,deco16_4d,deco16_4e,deco16_4f,
+ deco16_50,deco16_51,deco16_52,deco16_53,deco16_54,deco16_55,deco16_56,deco16_57,
+ deco16_58,deco16_59,deco16_5a,deco16_5b,deco16_5c,deco16_5d,deco16_5e,deco16_5f,
+ deco16_60,deco16_61,deco16_62,deco16_63,deco16_64,deco16_65,deco16_66,deco16_67,
+ deco16_68,deco16_69,deco16_6a,deco16_6b,deco16_6c,deco16_6d,deco16_6e,deco16_6f,
+ deco16_70,deco16_71,deco16_72,deco16_73,deco16_74,deco16_75,deco16_76,deco16_77,
+ deco16_78,deco16_79,deco16_7a,deco16_7b,deco16_7c,deco16_7d,deco16_7e,deco16_7f,
+ deco16_80,deco16_81,deco16_82,deco16_83,deco16_84,deco16_85,deco16_86,deco16_87,
+ deco16_88,deco16_89,deco16_8a,deco16_8b,deco16_8c,deco16_8d,deco16_8e,deco16_8f,
+ deco16_90,deco16_91,deco16_92,deco16_93,deco16_94,deco16_95,deco16_96,deco16_97,
+ deco16_98,deco16_99,deco16_9a,deco16_9b,deco16_9c,deco16_9d,deco16_9e,deco16_9f,
+ deco16_a0,deco16_a1,deco16_a2,deco16_a3,deco16_a4,deco16_a5,deco16_a6,deco16_a7,
+ deco16_a8,deco16_a9,deco16_aa,deco16_ab,deco16_ac,deco16_ad,deco16_ae,deco16_af,
+ deco16_b0,deco16_b1,deco16_b2,deco16_b3,deco16_b4,deco16_b5,deco16_b6,deco16_b7,
+ deco16_b8,deco16_b9,deco16_ba,deco16_bb,deco16_bc,deco16_bd,deco16_be,deco16_bf,
+ deco16_c0,deco16_c1,deco16_c2,deco16_c3,deco16_c4,deco16_c5,deco16_c6,deco16_c7,
+ deco16_c8,deco16_c9,deco16_ca,deco16_cb,deco16_cc,deco16_cd,deco16_ce,deco16_cf,
+ deco16_d0,deco16_d1,deco16_d2,deco16_d3,deco16_d4,deco16_d5,deco16_d6,deco16_d7,
+ deco16_d8,deco16_d9,deco16_da,deco16_db,deco16_dc,deco16_dd,deco16_de,deco16_df,
+ deco16_e0,deco16_e1,deco16_e2,deco16_e3,deco16_e4,deco16_e5,deco16_e6,deco16_e7,
+ deco16_e8,deco16_e9,deco16_ea,deco16_eb,deco16_ec,deco16_ed,deco16_ee,deco16_ef,
+ deco16_f0,deco16_f1,deco16_f2,deco16_f3,deco16_f4,deco16_f5,deco16_f6,deco16_f7,
+ deco16_f8,deco16_f9,deco16_fa,deco16_fb,deco16_fc,deco16_fd,deco16_fe,deco16_ff
+};
diff --git a/src/emu/cpu/m6502/tn2a03.c b/src/emu/cpu/m6502/tn2a03.c
new file mode 100644
index 00000000000..2a74f088105
--- /dev/null
+++ b/src/emu/cpu/m6502/tn2a03.c
@@ -0,0 +1,97 @@
+/*****************************************************************************
+ *
+ * tbl2a03.c
+ * 2a03 opcode functions and function pointer table
+ *
+ * The 2a03 is a 6502 CPU that does not support the decimal mode
+ * of the ADC and SBC instructions, so all opcodes except ADC/SBC
+ * are simply mapped to the m6502 ones.
+ *
+ * Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+/*
+ based on the nmos 6502
+
+ b flag handling might be changed,
+ although only nmos series b-flag handling is quite sure
+*/
+
+
+#undef OP
+#define OP(nn) INLINE void n2a03_##nn(void)
+
+/*****************************************************************************
+ *****************************************************************************
+ *
+ * overrides for 2a03 opcodes
+ *
+ *****************************************************************************
+ ********** insn temp cycles rdmem opc wrmem **********/
+OP(61) { int tmp; RD_IDX; ADC_NES; } /* 6 ADC IDX */
+OP(e1) { int tmp; RD_IDX; SBC_NES; } /* 6 SBC IDX */
+OP(71) { int tmp; RD_IDY_P; ADC_NES; } /* 5 ADC IDY page penalty */
+OP(f1) { int tmp; RD_IDY_P; SBC_NES; } /* 5 SBC IDY page penalty */
+OP(65) { int tmp; RD_ZPG; ADC_NES; } /* 3 ADC ZPG */
+OP(e5) { int tmp; RD_ZPG; SBC_NES; } /* 3 SBC ZPG */
+OP(75) { int tmp; RD_ZPX; ADC_NES; } /* 4 ADC ZPX */
+OP(f5) { int tmp; RD_ZPX; SBC_NES; } /* 4 SBC ZPX */
+OP(69) { int tmp; RD_IMM; ADC_NES; } /* 2 ADC IMM */
+OP(e9) { int tmp; RD_IMM; SBC_NES; } /* 2 SBC IMM */
+OP(79) { int tmp; RD_ABY_P; ADC_NES; } /* 4 ADC ABY page penalty */
+OP(f9) { int tmp; RD_ABY_P; SBC_NES; } /* 4 SBC ABY page penalty */
+OP(6b) { int tmp; RD_IMM; ARR_NES; WB_ACC; } /* 2 ARR IMM */
+OP(eb) { int tmp; RD_IMM; SBC_NES; } /* 2 SBC IMM */
+OP(6d) { int tmp; RD_ABS; ADC_NES; } /* 4 ADC ABS */
+OP(ed) { int tmp; RD_ABS; SBC_NES; } /* 4 SBC ABS */
+OP(7d) { int tmp; RD_ABX_P; ADC_NES; } /* 4 ADC ABX page penalty */
+OP(fd) { int tmp; RD_ABX_P; SBC_NES; } /* 4 SBC ABX page penalty */
+
+static void (*insn2a03[0x100])(void) = {
+ m6502_00,m6502_01,m6502_02,m6502_03,m6502_04,m6502_05,m6502_06,m6502_07,
+ m6502_08,m6502_09,m6502_0a,m6502_0b,m6502_0c,m6502_0d,m6502_0e,m6502_0f,
+ m6502_10,m6502_11,m6502_12,m6502_13,m6502_14,m6502_15,m6502_16,m6502_17,
+ m6502_18,m6502_19,m6502_1a,m6502_1b,m6502_1c,m6502_1d,m6502_1e,m6502_1f,
+ m6502_20,m6502_21,m6502_22,m6502_23,m6502_24,m6502_25,m6502_26,m6502_27,
+ m6502_28,m6502_29,m6502_2a,m6502_2b,m6502_2c,m6502_2d,m6502_2e,m6502_2f,
+ m6502_30,m6502_31,m6502_32,m6502_33,m6502_34,m6502_35,m6502_36,m6502_37,
+ m6502_38,m6502_39,m6502_3a,m6502_3b,m6502_3c,m6502_3d,m6502_3e,m6502_3f,
+ m6502_40,m6502_41,m6502_42,m6502_43,m6502_44,m6502_45,m6502_46,m6502_47,
+ m6502_48,m6502_49,m6502_4a,m6502_4b,m6502_4c,m6502_4d,m6502_4e,m6502_4f,
+ m6502_50,m6502_51,m6502_52,m6502_53,m6502_54,m6502_55,m6502_56,m6502_57,
+ m6502_58,m6502_59,m6502_5a,m6502_5b,m6502_5c,m6502_5d,m6502_5e,m6502_5f,
+ m6502_60,n2a03_61,m6502_62,m6502_63,m6502_64,n2a03_65,m6502_66,m6502_67,
+ m6502_68,n2a03_69,m6502_6a,n2a03_6b,m6502_6c,n2a03_6d,m6502_6e,m6502_6f,
+ m6502_70,n2a03_71,m6502_72,m6502_73,m6502_74,n2a03_75,m6502_76,m6502_77,
+ m6502_78,n2a03_79,m6502_7a,m6502_7b,m6502_7c,n2a03_7d,m6502_7e,m6502_7f,
+ m6502_80,m6502_81,m6502_82,m6502_83,m6502_84,m6502_85,m6502_86,m6502_87,
+ m6502_88,m6502_89,m6502_8a,m6502_8b,m6502_8c,m6502_8d,m6502_8e,m6502_8f,
+ m6502_90,m6502_91,m6502_92,m6502_93,m6502_94,m6502_95,m6502_96,m6502_97,
+ m6502_98,m6502_99,m6502_9a,m6502_9b,m6502_9c,m6502_9d,m6502_9e,m6502_9f,
+ m6502_a0,m6502_a1,m6502_a2,m6502_a3,m6502_a4,m6502_a5,m6502_a6,m6502_a7,
+ m6502_a8,m6502_a9,m6502_aa,m6502_ab,m6502_ac,m6502_ad,m6502_ae,m6502_af,
+ m6502_b0,m6502_b1,m6502_b2,m6502_b3,m6502_b4,m6502_b5,m6502_b6,m6502_b7,
+ m6502_b8,m6502_b9,m6502_ba,m6502_bb,m6502_bc,m6502_bd,m6502_be,m6502_bf,
+ m6502_c0,m6502_c1,m6502_c2,m6502_c3,m6502_c4,m6502_c5,m6502_c6,m6502_c7,
+ m6502_c8,m6502_c9,m6502_ca,m6502_cb,m6502_cc,m6502_cd,m6502_ce,m6502_cf,
+ m6502_d0,m6502_d1,m6502_d2,m6502_d3,m6502_d4,m6502_d5,m6502_d6,m6502_d7,
+ m6502_d8,m6502_d9,m6502_da,m6502_db,m6502_dc,m6502_dd,m6502_de,m6502_df,
+ m6502_e0,n2a03_e1,m6502_e2,m6502_e3,m6502_e4,n2a03_e5,m6502_e6,m6502_e7,
+ m6502_e8,n2a03_e9,m6502_ea,n2a03_eb,m6502_ec,n2a03_ed,m6502_ee,m6502_ef,
+ m6502_f0,n2a03_f1,m6502_f2,m6502_f3,m6502_f4,n2a03_f5,m6502_f6,m6502_f7,
+ m6502_f8,n2a03_f9,m6502_fa,m6502_fb,m6502_fc,n2a03_fd,m6502_fe,m6502_ff
+};
+
diff --git a/src/emu/cpu/m6800/6800dasm.c b/src/emu/cpu/m6800/6800dasm.c
new file mode 100644
index 00000000000..467fe1adee6
--- /dev/null
+++ b/src/emu/cpu/m6800/6800dasm.c
@@ -0,0 +1,274 @@
+/*
+ * A quick-hack 6803/6808 disassembler
+ *
+ * Note: this is not the good and proper way to disassemble anything, but it works
+ *
+ * I'm afraid to put my name on it, but I feel obligated:
+ * This code written by Aaron Giles (agiles@sirius.com) for the MAME project
+ *
+ * History:
+ * 990314 HJB
+ * The disassembler knows about valid opcodes for M6800/1/2/3/8 and HD63701.
+ * 990302 HJB
+ * Changed the string array into a table of opcode names (or tokens) and
+ * argument types. This second try should give somewhat better results.
+ * Named the undocumented HD63701YO opcodes $12 and $13 'asx1' and 'asx2',
+ * since 'add contents of stack to x register' is what they do.
+ *
+ */
+
+#include "debugger.h"
+#include "m6800.h"
+
+enum addr_mode {
+ inh, /* inherent */
+ rel, /* relative */
+ imb, /* immediate (byte) */
+ imw, /* immediate (word) */
+ dir, /* direct address */
+ imd, /* HD63701YO: immediate, direct address */
+ ext, /* extended address */
+ idx, /* x + byte offset */
+ imx, /* HD63701YO: immediate, x + byte offset */
+ sx1 /* HD63701YO: undocumented opcodes: byte from (s+1) */
+};
+
+enum op_names {
+ aba=0, abx, adca, adcb, adda, addb, addd, aim,
+ anda, andb, asl, asla, aslb, asld, asr, asra,
+ asrb, bcc, bcs, beq, bge, bgt, bhi, bita,
+ bitb, ble, bls, blt, bmi, bne, bpl, bra,
+ brn, bsr, bvc, bvs, cba, clc, cli, clr,
+ clra, clrb, clv, cmpa, cmpb, cmpx, com, coma,
+ comb, daa, dec, deca, decb, des, dex, eim,
+ eora, eorb, ill, inc, inca, incb, ins, inx,
+ jmp, jsr, lda, ldb, ldd, lds, ldx, lsr,
+ lsra, lsrb, lsrd, mul, neg, nega, negb, nop,
+ oim, ora, orb, psha, pshb, pshx, pula, pulb,
+ pulx, rol, rola, rolb, ror, rora, rorb, rti,
+ rts, sba, sbca, sbcb, sec, sev, sta, stb,
+ std, sei, sts, stx, suba, subb, subd, swi,
+ wai, tab, tap, tba, tim, tpa, tst, tsta,
+ tstb, tsx, txs, asx1, asx2, xgdx, addx, adcx
+};
+
+static const char *op_name_str[] = {
+ "aba", "abx", "adca", "adcb", "adda", "addb", "addd", "aim",
+ "anda", "andb", "asl", "asla", "aslb", "asld", "asr", "asra",
+ "asrb", "bcc", "bcs", "beq", "bge", "bgt", "bhi", "bita",
+ "bitb", "ble", "bls", "blt", "bmi", "bne", "bpl", "bra",
+ "brn", "bsr", "bvc", "bvs", "cba", "clc", "cli", "clr",
+ "clra", "clrb", "clv", "cmpa", "cmpb", "cmpx", "com", "coma",
+ "comb", "daa", "dec", "deca", "decb", "des", "dex", "eim",
+ "eora", "eorb", "illegal","inc", "inca", "incb", "ins", "inx",
+ "jmp", "jsr", "lda", "ldb", "ldd", "lds", "ldx", "lsr",
+ "lsra", "lsrb", "lsrd", "mul", "neg", "nega", "negb", "nop",
+ "oim", "ora", "orb", "psha", "pshb", "pshx", "pula", "pulb",
+ "pulx", "rol", "rola", "rolb", "ror", "rora", "rorb", "rti",
+ "rts", "sba", "sbca", "sbcb", "sec", "sev", "sta", "stb",
+ "std", "sei", "sts", "stx", "suba", "subb", "subd", "swi",
+ "wai", "tab", "tap", "tba", "tim", "tpa", "tst", "tsta",
+ "tstb", "tsx", "txs", "asx1", "asx2", "xgdx", "addx", "adcx"
+};
+
+/*
+ * This table defines the opcodes:
+ * byte meaning
+ * 0 token (menmonic)
+ * 1 addressing mode
+ * 2 invalid opcode for 1:6800/6802/6808, 2:6801/6803, 4:HD63701
+ */
+
+static UINT8 table[0x102][3] = {
+ {ill, inh,7},{nop, inh,0},{ill, inh,7},{ill, inh,7},/* 00 */
+ {lsrd,inh,1},{asld,inh,1},{tap, inh,0},{tpa, inh,0},
+ {inx, inh,0},{dex, inh,0},{clv, inh,0},{sev, inh,0},
+ {clc, inh,0},{sec, inh,0},{cli, inh,0},{sei, inh,0},
+ {sba, inh,0},{cba, inh,0},{asx1,sx1,0},{asx2,sx1,0},/* 10 */
+ {ill, inh,7},{ill, inh,7},{tab, inh,0},{tba, inh,0},
+ {xgdx,inh,3},{daa, inh,0},{ill, inh,7},{aba, inh,0},
+ {ill, inh,7},{ill, inh,7},{ill, inh,7},{ill, inh,7},
+ {bra, rel,0},{brn, rel,0},{bhi, rel,0},{bls, rel,0},/* 20 */
+ {bcc, rel,0},{bcs, rel,0},{bne, rel,0},{beq, rel,0},
+ {bvc, rel,0},{bvs, rel,0},{bpl, rel,0},{bmi, rel,0},
+ {bge, rel,0},{blt, rel,0},{bgt, rel,0},{ble, rel,0},
+ {tsx, inh,0},{ins, inh,0},{pula,inh,0},{pulb,inh,0},/* 30 */
+ {des, inh,0},{txs, inh,0},{psha,inh,0},{pshb,inh,0},
+ {pulx,inh,1},{rts, inh,0},{abx, inh,1},{rti, inh,0},
+ {pshx,inh,1},{mul, inh,1},{wai, inh,0},{swi, inh,0},
+ {nega,inh,0},{ill, inh,7},{ill, inh,7},{coma,inh,0},/* 40 */
+ {lsra,inh,0},{ill, inh,7},{rora,inh,0},{asra,inh,0},
+ {asla,inh,0},{rola,inh,0},{deca,inh,0},{ill, inh,7},
+ {inca,inh,0},{tsta,inh,0},{ill, inh,7},{clra,inh,0},
+ {negb,inh,0},{ill, inh,7},{ill, inh,7},{comb,inh,0},/* 50 */
+ {lsrb,inh,0},{ill, inh,7},{rorb,inh,0},{asrb,inh,0},
+ {aslb,inh,0},{rolb,inh,0},{decb,inh,0},{ill, inh,7},
+ {incb,inh,0},{tstb,inh,0},{ill, inh,7},{clrb,inh,0},
+ {neg, idx,0},{aim, imx,3},{oim, imx,3},{com, idx,0},/* 60 */
+ {lsr, idx,0},{eim, imx,3},{ror, idx,0},{asr, idx,0},
+ {asl, idx,0},{rol, idx,0},{dec, idx,0},{tim, imx,3},
+ {inc, idx,0},{tst, idx,0},{jmp, idx,0},{clr, idx,0},
+ {neg, ext,0},{aim, imd,3},{oim, imd,3},{com, ext,0},/* 70 */
+ {lsr, ext,0},{eim, imd,3},{ror, ext,0},{asr, ext,0},
+ {asl, ext,0},{rol, ext,0},{dec, ext,0},{tim, imd,3},
+ {inc, ext,0},{tst, ext,0},{jmp, ext,0},{clr, ext,0},
+ {suba,imb,0},{cmpa,imb,0},{sbca,imb,0},{subd,imw,1},/* 80 */
+ {anda,imb,0},{bita,imb,0},{lda, imb,0},{sta, imb,0},
+ {eora,imb,0},{adca,imb,0},{ora, imb,0},{adda,imb,0},
+ {cmpx,imw,0},{bsr, rel,0},{lds, imw,0},{sts, imw,0},
+ {suba,dir,0},{cmpa,dir,0},{sbca,dir,0},{subd,dir,1},/* 90 */
+ {anda,dir,0},{bita,dir,0},{lda, dir,0},{sta, dir,0},
+ {eora,dir,0},{adca,dir,0},{ora, dir,0},{adda,dir,0},
+ {cmpx,dir,0},{jsr, dir,0},{lds, dir,0},{sts, dir,0},
+ {suba,idx,0},{cmpa,idx,0},{sbca,idx,0},{subd,idx,1},/* a0 */
+ {anda,idx,0},{bita,idx,0},{lda, idx,0},{sta, idx,0},
+ {eora,idx,0},{adca,idx,0},{ora, idx,0},{adda,idx,0},
+ {cmpx,idx,0},{jsr, idx,0},{lds, idx,0},{sts, idx,0},
+ {suba,ext,0},{cmpa,ext,0},{sbca,ext,0},{subd,ext,1},/* b0 */
+ {anda,ext,0},{bita,ext,0},{lda, ext,0},{sta, ext,0},
+ {eora,ext,0},{adca,ext,0},{ora, ext,0},{adda,ext,0},
+ {cmpx,ext,0},{jsr, ext,0},{lds, ext,0},{sts, ext,0},
+ {subb,imb,0},{cmpb,imb,0},{sbcb,imb,0},{addd,imw,1},/* c0 */
+ {andb,imb,0},{bitb,imb,0},{ldb, imb,0},{stb, imb,0},
+ {eorb,imb,0},{adcb,imb,0},{orb, imb,0},{addb,imb,0},
+ {ldd, imw,1},{std, imw,1},{ldx, imw,0},{stx, imw,0},
+ {subb,dir,0},{cmpb,dir,0},{sbcb,dir,0},{addd,dir,1},/* d0 */
+ {andb,dir,0},{bitb,dir,0},{ldb, dir,0},{stb, dir,0},
+ {eorb,dir,0},{adcb,dir,0},{orb, dir,0},{addb,dir,0},
+ {ldd, dir,1},{std, dir,1},{ldx, dir,0},{stx, dir,0},
+ {subb,idx,0},{cmpb,idx,0},{sbcb,idx,0},{addd,idx,1},/* e0 */
+ {andb,idx,0},{bitb,idx,0},{ldb, idx,0},{stb, idx,0},
+ {eorb,idx,0},{adcb,idx,0},{orb, idx,0},{addb,idx,0},
+ {ldd, idx,1},{std, idx,1},{ldx, idx,0},{stx, idx,0},
+ {subb,ext,0},{cmpb,ext,0},{sbcb,ext,0},{addd,ext,1},/* f0 */
+ {andb,ext,0},{bitb,ext,0},{ldb, ext,0},{stb, ext,0},
+ {eorb,ext,0},{adcb,ext,0},{orb, ext,0},{addb,ext,0},
+ {ldd, ext,1},{std, ext,1},{ldx, ext,0},{stx, ext,0},
+
+ /* extra instruction $fc for NSC-8105 */
+ {addx,ext,0},
+ /* extra instruction $ec for NSC-8105 */
+ {adcx,imb,0}
+};
+
+/* some macros to keep things short */
+#define OP oprom[0]
+#define ARG1 opram[1]
+#define ARG2 opram[2]
+#define ARGW (opram[1]<<8) + opram[2]
+
+static unsigned Dasm680x (int subtype, char *buf, unsigned pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ int invalid_mask;
+ int code = OP;
+ UINT8 opcode, args, invalid;
+
+ switch( subtype )
+ {
+ case 6800: case 6802: case 6808: case 8105:
+ invalid_mask = 1;
+ break;
+ case 6801: case 6803:
+ invalid_mask = 2;
+ break;
+ default:
+ invalid_mask = 4;
+ }
+
+ /* NSC-8105 is a special case */
+ if (subtype == 8105)
+ {
+ /* swap bits */
+ code = (code & 0x3c) | ((code & 0x41) << 1) | ((code & 0x82) >> 1);
+
+ /* and check for extra instruction */
+ if (code == 0xfc) code = 0x0100;
+ if (code == 0xec) code = 0x0101;
+ }
+
+ opcode = table[code][0];
+ args = table[code][1];
+ invalid = table[code][2];
+
+ if (opcode == bsr || opcode == jsr)
+ flags = DASMFLAG_STEP_OVER;
+ else if (opcode == rti || opcode == rts)
+ flags = DASMFLAG_STEP_OUT;
+
+ if ( invalid & invalid_mask ) /* invalid for this cpu type ? */
+ {
+ strcpy(buf, "illegal");
+ return 1 | flags | DASMFLAG_SUPPORTED;
+ }
+
+ buf += sprintf(buf, "%-5s", op_name_str[opcode]);
+
+ switch( args )
+ {
+ case rel: /* relative */
+ sprintf (buf, "$%04X", pc + (INT8)ARG1 + 2);
+ return 2 | flags | DASMFLAG_SUPPORTED;
+ case imb: /* immediate (byte) */
+ sprintf (buf, "#$%02X", ARG1);
+ return 2 | flags | DASMFLAG_SUPPORTED;
+ case imw: /* immediate (word) */
+ sprintf (buf, "#$%04X", ARGW);
+ return 3 | flags | DASMFLAG_SUPPORTED;
+ case idx: /* indexed + byte offset */
+ sprintf (buf, "(x+$%02X)", ARG1 );
+ return 2 | flags | DASMFLAG_SUPPORTED;
+ case imx: /* immediate, indexed + byte offset */
+ sprintf (buf, "#$%02X,(x+$%02x)", ARG1, ARG2 );
+ return 3 | flags | DASMFLAG_SUPPORTED;
+ case dir: /* direct address */
+ sprintf (buf, "$%02X", ARG1 );
+ return 2 | flags | DASMFLAG_SUPPORTED;
+ case imd: /* immediate, direct address */
+ sprintf (buf, "#$%02X,$%02X", ARG1, ARG2);
+ return 3 | flags | DASMFLAG_SUPPORTED;
+ case ext: /* extended address */
+ sprintf (buf, "$%04X", ARGW);
+ return 3 | flags | DASMFLAG_SUPPORTED;
+ case sx1: /* byte from address (s + 1) */
+ sprintf (buf, "(s+1)");
+ return 1 | flags | DASMFLAG_SUPPORTED;
+ default:
+ return 1 | flags | DASMFLAG_SUPPORTED;
+ }
+}
+
+offs_t m6800_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return Dasm680x(6800,buffer,pc,oprom,opram);
+}
+
+offs_t m6801_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return Dasm680x(6801,buffer,pc,oprom,opram);
+}
+
+offs_t m6802_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return Dasm680x(6802,buffer,pc,oprom,opram);
+}
+
+offs_t m6803_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return Dasm680x(6803,buffer,pc,oprom,opram);
+}
+
+offs_t m6808_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return Dasm680x(6808,buffer,pc,oprom,opram);
+}
+
+offs_t hd63701_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return Dasm680x(63701,buffer,pc,oprom,opram);
+}
+
+offs_t nsc8105_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return Dasm680x(8105,buffer,pc,oprom,opram);
+}
diff --git a/src/emu/cpu/m6800/6800ops.c b/src/emu/cpu/m6800/6800ops.c
new file mode 100644
index 00000000000..b964547c010
--- /dev/null
+++ b/src/emu/cpu/m6800/6800ops.c
@@ -0,0 +1,2140 @@
+
+/*
+
+HNZVC
+
+? = undefined
+* = affected
+- = unaffected
+0 = cleared
+1 = set
+# = ccr directly affected by instruction
+@ = special - carry set if bit 7 is set
+
+*/
+
+//INLINE void illegal( void )
+static void illegal( void )
+{
+ logerror("M6808: illegal opcode: address %04X, op %02X\n",PC,(int) M_RDOP_ARG(PC)&0xFF);
+}
+
+/* HD63701 only */
+#if (HAS_HD63701)
+//INLINE void trap( void )
+static void trap( void )
+{
+ logerror("M6808: illegal opcode: address %04X, op %02X\n",PC,(int) M_RDOP_ARG(PC)&0xFF);
+ TAKE_TRAP;
+}
+#endif
+
+/* $00 ILLEGAL */
+
+/* $01 NOP */
+INLINE void nop( void )
+{
+}
+
+/* $02 ILLEGAL */
+
+/* $03 ILLEGAL */
+
+/* $04 LSRD inherent -0*-* */
+INLINE void lsrd (void)
+{
+ UINT16 t;
+ CLR_NZC; t = D; CC|=(t&0x0001);
+ t>>=1; SET_Z16(t); D=t;
+}
+
+/* $05 ASLD inherent ?**** */
+INLINE void asld (void)
+{
+ int r;
+ UINT16 t;
+ t = D; r=t<<1;
+ CLR_NZVC; SET_FLAGS16(t,t,r);
+ D=r;
+}
+
+/* $06 TAP inherent ##### */
+INLINE void tap (void)
+{
+ CC=A;
+ ONE_MORE_INSN();
+ CHECK_IRQ_LINES(); /* HJB 990417 */
+}
+
+/* $07 TPA inherent ----- */
+INLINE void tpa (void)
+{
+ A=CC;
+}
+
+/* $08 INX inherent --*-- */
+INLINE void inx (void)
+{
+ ++X;
+ CLR_Z; SET_Z16(X);
+}
+
+/* $09 DEX inherent --*-- */
+INLINE void dex (void)
+{
+ --X;
+ CLR_Z; SET_Z16(X);
+}
+
+/* $0a CLV */
+INLINE void clv (void)
+{
+ CLV;
+}
+
+/* $0b SEV */
+INLINE void sev (void)
+{
+ SEV;
+}
+
+/* $0c CLC */
+INLINE void clc (void)
+{
+ CLC;
+}
+
+/* $0d SEC */
+INLINE void sec (void)
+{
+ SEC;
+}
+
+/* $0e CLI */
+INLINE void cli (void)
+{
+ CLI;
+ ONE_MORE_INSN();
+ CHECK_IRQ_LINES(); /* HJB 990417 */
+}
+
+/* $0f SEI */
+INLINE void sei (void)
+{
+ SEI;
+ ONE_MORE_INSN();
+ CHECK_IRQ_LINES(); /* HJB 990417 */
+}
+
+/* $10 SBA inherent -**** */
+INLINE void sba (void)
+{
+ UINT16 t;
+ t=A-B;
+ CLR_NZVC; SET_FLAGS8(A,B,t);
+ A=t;
+}
+
+/* $11 CBA inherent -**** */
+INLINE void cba (void)
+{
+ UINT16 t;
+ t=A-B;
+ CLR_NZVC; SET_FLAGS8(A,B,t);
+}
+
+/* $12 ILLEGAL */
+INLINE void undoc1 (void)
+{
+ X += RM( S + 1 );
+}
+
+/* $13 ILLEGAL */
+INLINE void undoc2 (void)
+{
+ X += RM( S + 1 );
+}
+
+
+/* $14 ILLEGAL */
+
+/* $15 ILLEGAL */
+
+/* $16 TAB inherent -**0- */
+INLINE void tab (void)
+{
+ B=A;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $17 TBA inherent -**0- */
+INLINE void tba (void)
+{
+ A=B;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $18 XGDX inherent ----- */ /* HD63701YO only */
+INLINE void xgdx( void )
+{
+ UINT16 t = X;
+ X = D;
+ D=t;
+}
+
+/* $19 DAA inherent (A) -**0* */
+INLINE void daa( void )
+{
+ UINT8 msn, lsn;
+ UINT16 t, cf = 0;
+ msn=A & 0xf0; lsn=A & 0x0f;
+ if( lsn>0x09 || CC&0x20 ) cf |= 0x06;
+ if( msn>0x80 && lsn>0x09 ) cf |= 0x60;
+ if( msn>0x90 || CC&0x01 ) cf |= 0x60;
+ t = cf + A;
+ CLR_NZV; /* keep carry from previous operation */
+ SET_NZ8((UINT8)t); SET_C8(t);
+ A = t;
+}
+
+/* $1a ILLEGAL */
+
+#if (HAS_HD63701)
+/* $1a SLP */ /* HD63701YO only */
+INLINE void slp (void)
+{
+ /* wait for next IRQ (same as waiting of wai) */
+ m6808.wai_state |= HD63701_SLP;
+ EAT_CYCLES;
+}
+#endif
+
+/* $1b ABA inherent ***** */
+INLINE void aba (void)
+{
+ UINT16 t;
+ t=A+B;
+ CLR_HNZVC; SET_FLAGS8(A,B,t); SET_H(A,B,t);
+ A=t;
+}
+
+/* $1c ILLEGAL */
+
+/* $1d ILLEGAL */
+
+/* $1e ILLEGAL */
+
+/* $1f ILLEGAL */
+
+/* $20 BRA relative ----- */
+INLINE void bra( void )
+{
+ UINT8 t;
+ IMMBYTE(t);PC+=SIGNED(t);CHANGE_PC();
+ /* speed up busy loops */
+ if (t==0xfe) EAT_CYCLES;
+}
+
+/* $21 BRN relative ----- */
+INLINE void brn( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+}
+
+/* $22 BHI relative ----- */
+INLINE void bhi( void )
+{
+ UINT8 t;
+ BRANCH(!(CC&0x05));
+}
+
+/* $23 BLS relative ----- */
+INLINE void bls( void )
+{
+ UINT8 t;
+ BRANCH(CC&0x05);
+}
+
+/* $24 BCC relative ----- */
+INLINE void bcc( void )
+{
+ UINT8 t;
+ BRANCH(!(CC&0x01));
+}
+
+/* $25 BCS relative ----- */
+INLINE void bcs( void )
+{
+ UINT8 t;
+ BRANCH(CC&0x01);
+}
+
+/* $26 BNE relative ----- */
+INLINE void bne( void )
+{
+ UINT8 t;
+ BRANCH(!(CC&0x04));
+}
+
+/* $27 BEQ relative ----- */
+INLINE void beq( void )
+{
+ UINT8 t;
+ BRANCH(CC&0x04);
+}
+
+/* $28 BVC relative ----- */
+INLINE void bvc( void )
+{
+ UINT8 t;
+ BRANCH(!(CC&0x02));
+}
+
+/* $29 BVS relative ----- */
+INLINE void bvs( void )
+{
+ UINT8 t;
+ BRANCH(CC&0x02);
+}
+
+/* $2a BPL relative ----- */
+INLINE void bpl( void )
+{
+ UINT8 t;
+ BRANCH(!(CC&0x08));
+}
+
+/* $2b BMI relative ----- */
+INLINE void bmi( void )
+{
+ UINT8 t;
+ BRANCH(CC&0x08);
+}
+
+/* $2c BGE relative ----- */
+INLINE void bge( void )
+{
+ UINT8 t;
+ BRANCH(!NXORV);
+}
+
+/* $2d BLT relative ----- */
+INLINE void blt( void )
+{
+ UINT8 t;
+ BRANCH(NXORV);
+}
+
+/* $2e BGT relative ----- */
+INLINE void bgt( void )
+{
+ UINT8 t;
+ BRANCH(!(NXORV||CC&0x04));
+}
+
+/* $2f BLE relative ----- */
+INLINE void ble( void )
+{
+ UINT8 t;
+ BRANCH(NXORV||CC&0x04);
+}
+
+/* $30 TSX inherent ----- */
+INLINE void tsx (void)
+{
+ X = ( S + 1 );
+}
+
+/* $31 INS inherent ----- */
+INLINE void ins (void)
+{
+ ++S;
+}
+
+/* $32 PULA inherent ----- */
+INLINE void pula (void)
+{
+ PULLBYTE(m6808.d.b.h);
+}
+
+/* $33 PULB inherent ----- */
+INLINE void pulb (void)
+{
+ PULLBYTE(m6808.d.b.l);
+}
+
+/* $34 DES inherent ----- */
+INLINE void des (void)
+{
+ --S;
+}
+
+/* $35 TXS inherent ----- */
+INLINE void txs (void)
+{
+ S = ( X - 1 );
+}
+
+/* $36 PSHA inherent ----- */
+INLINE void psha (void)
+{
+ PUSHBYTE(m6808.d.b.h);
+}
+
+/* $37 PSHB inherent ----- */
+INLINE void pshb (void)
+{
+ PUSHBYTE(m6808.d.b.l);
+}
+
+/* $38 PULX inherent ----- */
+INLINE void pulx (void)
+{
+ PULLWORD(pX);
+}
+
+/* $39 RTS inherent ----- */
+INLINE void rts( void )
+{
+ PULLWORD(pPC);
+ CHANGE_PC();
+}
+
+/* $3a ABX inherent ----- */
+INLINE void abx( void )
+{
+ X += B;
+}
+
+/* $3b RTI inherent ##### */
+INLINE void rti( void )
+{
+ PULLBYTE(CC);
+ PULLBYTE(B);
+ PULLBYTE(A);
+ PULLWORD(pX);
+ PULLWORD(pPC);
+ CHANGE_PC();
+ CHECK_IRQ_LINES(); /* HJB 990417 */
+}
+
+/* $3c PSHX inherent ----- */
+INLINE void pshx (void)
+{
+ PUSHWORD(pX);
+}
+
+/* $3d MUL inherent --*-@ */
+INLINE void mul( void )
+{
+ UINT16 t;
+ t=A*B;
+ CLR_C; if(t&0x80) SEC;
+ D=t;
+}
+
+/* $3e WAI inherent ----- */
+INLINE void wai( void )
+{
+ /*
+ * WAI stacks the entire machine state on the
+ * hardware stack, then waits for an interrupt.
+ */
+ m6808.wai_state |= M6800_WAI;
+ PUSHWORD(pPC);
+ PUSHWORD(pX);
+ PUSHBYTE(A);
+ PUSHBYTE(B);
+ PUSHBYTE(CC);
+ CHECK_IRQ_LINES();
+ if (m6808.wai_state & M6800_WAI) EAT_CYCLES;
+}
+
+/* $3f SWI absolute indirect ----- */
+INLINE void swi( void )
+{
+ PUSHWORD(pPC);
+ PUSHWORD(pX);
+ PUSHBYTE(A);
+ PUSHBYTE(B);
+ PUSHBYTE(CC);
+ SEI;
+ PCD = RM16(0xfffa);
+ CHANGE_PC();
+}
+
+/* $40 NEGA inherent ?**** */
+INLINE void nega( void )
+{
+ UINT16 r;
+ r=-A;
+ CLR_NZVC; SET_FLAGS8(0,A,r);
+ A=r;
+}
+
+/* $41 ILLEGAL */
+
+/* $42 ILLEGAL */
+
+/* $43 COMA inherent -**01 */
+INLINE void coma( void )
+{
+ A = ~A;
+ CLR_NZV; SET_NZ8(A); SEC;
+}
+
+/* $44 LSRA inherent -0*-* */
+INLINE void lsra( void )
+{
+ CLR_NZC; CC|=(A&0x01);
+ A>>=1; SET_Z8(A);
+}
+
+/* $45 ILLEGAL */
+
+/* $46 RORA inherent -**-* */
+INLINE void rora( void )
+{
+ UINT8 r;
+ r=(CC&0x01)<<7;
+ CLR_NZC; CC|=(A&0x01);
+ r |= A>>1; SET_NZ8(r);
+ A=r;
+}
+
+/* $47 ASRA inherent ?**-* */
+INLINE void asra( void )
+{
+ CLR_NZC; CC|=(A&0x01);
+ A>>=1; A|=((A&0x40)<<1);
+ SET_NZ8(A);
+}
+
+/* $48 ASLA inherent ?**** */
+INLINE void asla( void )
+{
+ UINT16 r;
+ r=A<<1;
+ CLR_NZVC; SET_FLAGS8(A,A,r);
+ A=r;
+}
+
+/* $49 ROLA inherent -**** */
+INLINE void rola( void )
+{
+ UINT16 t,r;
+ t = A; r = CC&0x01; r |= t<<1;
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ A=r;
+}
+
+/* $4a DECA inherent -***- */
+INLINE void deca( void )
+{
+ --A;
+ CLR_NZV; SET_FLAGS8D(A);
+}
+
+/* $4b ILLEGAL */
+
+/* $4c INCA inherent -***- */
+INLINE void inca( void )
+{
+ ++A;
+ CLR_NZV; SET_FLAGS8I(A);
+}
+
+/* $4d TSTA inherent -**0- */
+INLINE void tsta( void )
+{
+ CLR_NZVC; SET_NZ8(A);
+}
+
+/* $4e ILLEGAL */
+
+/* $4f CLRA inherent -0100 */
+INLINE void clra( void )
+{
+ A=0;
+ CLR_NZVC; SEZ;
+}
+
+/* $50 NEGB inherent ?**** */
+INLINE void negb( void )
+{
+ UINT16 r;
+ r=-B;
+ CLR_NZVC; SET_FLAGS8(0,B,r);
+ B=r;
+}
+
+/* $51 ILLEGAL */
+
+/* $52 ILLEGAL */
+
+/* $53 COMB inherent -**01 */
+INLINE void comb( void )
+{
+ B = ~B;
+ CLR_NZV; SET_NZ8(B); SEC;
+}
+
+/* $54 LSRB inherent -0*-* */
+INLINE void lsrb( void )
+{
+ CLR_NZC; CC|=(B&0x01);
+ B>>=1; SET_Z8(B);
+}
+
+/* $55 ILLEGAL */
+
+/* $56 RORB inherent -**-* */
+INLINE void rorb( void )
+{
+ UINT8 r;
+ r=(CC&0x01)<<7;
+ CLR_NZC; CC|=(B&0x01);
+ r |= B>>1; SET_NZ8(r);
+ B=r;
+}
+
+/* $57 ASRB inherent ?**-* */
+INLINE void asrb( void )
+{
+ CLR_NZC; CC|=(B&0x01);
+ B>>=1; B|=((B&0x40)<<1);
+ SET_NZ8(B);
+}
+
+/* $58 ASLB inherent ?**** */
+INLINE void aslb( void )
+{
+ UINT16 r;
+ r=B<<1;
+ CLR_NZVC; SET_FLAGS8(B,B,r);
+ B=r;
+}
+
+/* $59 ROLB inherent -**** */
+INLINE void rolb( void )
+{
+ UINT16 t,r;
+ t = B; r = CC&0x01; r |= t<<1;
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ B=r;
+}
+
+/* $5a DECB inherent -***- */
+INLINE void decb( void )
+{
+ --B;
+ CLR_NZV; SET_FLAGS8D(B);
+}
+
+/* $5b ILLEGAL */
+
+/* $5c INCB inherent -***- */
+INLINE void incb( void )
+{
+ ++B;
+ CLR_NZV; SET_FLAGS8I(B);
+}
+
+/* $5d TSTB inherent -**0- */
+INLINE void tstb( void )
+{
+ CLR_NZVC; SET_NZ8(B);
+}
+
+/* $5e ILLEGAL */
+
+/* $5f CLRB inherent -0100 */
+INLINE void clrb( void )
+{
+ B=0;
+ CLR_NZVC; SEZ;
+}
+
+/* $60 NEG indexed ?**** */
+INLINE void neg_ix( void )
+{
+ UINT16 r,t;
+ IDXBYTE(t); r=-t;
+ CLR_NZVC; SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $61 AIM --**0- */ /* HD63701YO only */
+INLINE void aim_ix( void )
+{
+ UINT8 t, r;
+ IMMBYTE(t);
+ IDXBYTE(r);
+ r &= t;
+ CLR_NZV; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $62 OIM --**0- */ /* HD63701YO only */
+INLINE void oim_ix( void )
+{
+ UINT8 t, r;
+ IMMBYTE(t);
+ IDXBYTE(r);
+ r |= t;
+ CLR_NZV; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $63 COM indexed -**01 */
+INLINE void com_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); t = ~t;
+ CLR_NZV; SET_NZ8(t); SEC;
+ WM(EAD,t);
+}
+
+/* $64 LSR indexed -0*-* */
+INLINE void lsr_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); CLR_NZC; CC|=(t&0x01);
+ t>>=1; SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $65 EIM --**0- */ /* HD63701YO only */
+INLINE void eim_ix( void )
+{
+ UINT8 t, r;
+ IMMBYTE(t);
+ IDXBYTE(r);
+ r ^= t;
+ CLR_NZV; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $66 ROR indexed -**-* */
+INLINE void ror_ix( void )
+{
+ UINT8 t,r;
+ IDXBYTE(t); r=(CC&0x01)<<7;
+ CLR_NZC; CC|=(t&0x01);
+ r |= t>>1; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $67 ASR indexed ?**-* */
+INLINE void asr_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); CLR_NZC; CC|=(t&0x01);
+ t>>=1; t|=((t&0x40)<<1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $68 ASL indexed ?**** */
+INLINE void asl_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r=t<<1;
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $69 ROL indexed -**** */
+INLINE void rol_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = CC&0x01; r |= t<<1;
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $6a DEC indexed -***- */
+INLINE void dec_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); --t;
+ CLR_NZV; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $6b TIM --**0- */ /* HD63701YO only */
+INLINE void tim_ix( void )
+{
+ UINT8 t, r;
+ IMMBYTE(t);
+ IDXBYTE(r);
+ r &= t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $6c INC indexed -***- */
+INLINE void inc_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); ++t;
+ CLR_NZV; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $6d TST indexed -**0- */
+INLINE void tst_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); CLR_NZVC; SET_NZ8(t);
+}
+
+/* $6e JMP indexed ----- */
+INLINE void jmp_ix( void )
+{
+ INDEXED; PC=EA; CHANGE_PC();
+}
+
+/* $6f CLR indexed -0100 */
+INLINE void clr_ix( void )
+{
+ INDEXED; WM(EAD,0);
+ CLR_NZVC; SEZ;
+}
+
+/* $70 NEG extended ?**** */
+INLINE void neg_ex( void )
+{
+ UINT16 r,t;
+ EXTBYTE(t); r=-t;
+ CLR_NZVC; SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $71 AIM --**0- */ /* HD63701YO only */
+INLINE void aim_di( void )
+{
+ UINT8 t, r;
+ IMMBYTE(t);
+ DIRBYTE(r);
+ r &= t;
+ CLR_NZV; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $72 OIM --**0- */ /* HD63701YO only */
+INLINE void oim_di( void )
+{
+ UINT8 t, r;
+ IMMBYTE(t);
+ DIRBYTE(r);
+ r |= t;
+ CLR_NZV; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $73 COM extended -**01 */
+INLINE void com_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); t = ~t;
+ CLR_NZV; SET_NZ8(t); SEC;
+ WM(EAD,t);
+}
+
+/* $74 LSR extended -0*-* */
+INLINE void lsr_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ CLR_NZC;
+ CC|=(t&0x01);
+ t>>=1;
+ SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $75 EIM --**0- */ /* HD63701YO only */
+INLINE void eim_di( void )
+{
+ UINT8 t, r;
+ IMMBYTE(t);
+ DIRBYTE(r);
+ r ^= t;
+ CLR_NZV; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $76 ROR extended -**-* */
+INLINE void ror_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t); r=(CC&0x01)<<7;
+ CLR_NZC; CC|=(t&0x01);
+ r |= t>>1; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $77 ASR extended ?**-* */
+INLINE void asr_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZC; CC|=(t&0x01);
+ t>>=1; t|=((t&0x40)<<1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $78 ASL extended ?**** */
+INLINE void asl_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r=t<<1;
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $79 ROL extended -**** */
+INLINE void rol_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = CC&0x01; r |= t<<1;
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $7a DEC extended -***- */
+INLINE void dec_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); --t;
+ CLR_NZV; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $7b TIM --**0- */ /* HD63701YO only */
+INLINE void tim_di( void )
+{
+ UINT8 t, r;
+ IMMBYTE(t);
+ DIRBYTE(r);
+ r &= t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $7c INC extended -***- */
+INLINE void inc_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); ++t;
+ CLR_NZV; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $7d TST extended -**0- */
+INLINE void tst_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZVC; SET_NZ8(t);
+}
+
+/* $7e JMP extended ----- */
+INLINE void jmp_ex( void )
+{
+ EXTENDED; PC=EA; CHANGE_PC(); /* TS 971002 */
+}
+
+/* $7f CLR extended -0100 */
+INLINE void clr_ex( void )
+{
+ EXTENDED; WM(EAD,0);
+ CLR_NZVC; SEZ;
+}
+
+/* $80 SUBA immediate ?**** */
+INLINE void suba_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = A-t;
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $81 CMPA immediate ?**** */
+INLINE void cmpa_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = A-t;
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+}
+
+/* $82 SBCA immediate ?**** */
+INLINE void sbca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = A-t-(CC&0x01);
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $83 SUBD immediate -**** */
+INLINE void subd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $84 ANDA immediate -**0- */
+INLINE void anda_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t); A &= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $85 BITA immediate -**0- */
+INLINE void bita_im( void )
+{
+ UINT8 t,r;
+ IMMBYTE(t); r = A&t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $86 LDA immediate -**0- */
+INLINE void lda_im( void )
+{
+ IMMBYTE(A);
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* is this a legal instruction? */
+/* $87 STA immediate -**0- */
+INLINE void sta_im( void )
+{
+ CLR_NZV; SET_NZ8(A);
+ IMM8; WM(EAD,A);
+}
+
+/* $88 EORA immediate -**0- */
+INLINE void eora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t); A ^= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $89 ADCA immediate ***** */
+INLINE void adca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = A+t+(CC&0x01);
+ CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r);
+ A = r;
+}
+
+/* $8a ORA immediate -**0- */
+INLINE void ora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t); A |= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $8b ADDA immediate ***** */
+INLINE void adda_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = A+t;
+ CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r);
+ A = r;
+}
+
+/* $8c CMPX immediate -***- */
+INLINE void cmpx_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZV;
+ SET_NZ16(r); SET_V16(d,b.d,r);
+}
+
+/* $8c CPX immediate -**** (6803) */
+INLINE void cpx_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC; SET_FLAGS16(d,b.d,r);
+}
+
+
+/* $8d BSR ----- */
+INLINE void bsr( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ PUSHWORD(pPC);
+ PC += SIGNED(t);
+ CHANGE_PC(); /* TS 971002 */
+}
+
+/* $8e LDS immediate -**0- */
+INLINE void lds_im( void )
+{
+ IMMWORD(m6808.s);
+ CLR_NZV;
+ SET_NZ16(S);
+}
+
+/* $8f STS immediate -**0- */
+INLINE void sts_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ IMM16;
+ WM16(EAD,&m6808.s);
+}
+
+/* $90 SUBA direct ?**** */
+INLINE void suba_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = A-t;
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $91 CMPA direct ?**** */
+INLINE void cmpa_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = A-t;
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+}
+
+/* $92 SBCA direct ?**** */
+INLINE void sbca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = A-t-(CC&0x01);
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $93 SUBD direct -**** */
+INLINE void subd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D=r;
+}
+
+/* $94 ANDA direct -**0- */
+INLINE void anda_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t); A &= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $95 BITA direct -**0- */
+INLINE void bita_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t); r = A&t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $96 LDA direct -**0- */
+INLINE void lda_di( void )
+{
+ DIRBYTE(A);
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $97 STA direct -**0- */
+INLINE void sta_di( void )
+{
+ CLR_NZV; SET_NZ8(A);
+ DIRECT; WM(EAD,A);
+}
+
+/* $98 EORA direct -**0- */
+INLINE void eora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t); A ^= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $99 ADCA direct ***** */
+INLINE void adca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = A+t+(CC&0x01);
+ CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r);
+ A = r;
+}
+
+/* $9a ORA direct -**0- */
+INLINE void ora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t); A |= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $9b ADDA direct ***** */
+INLINE void adda_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = A+t;
+ CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r);
+ A = r;
+}
+
+/* $9c CMPX direct -***- */
+INLINE void cmpx_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZV;
+ SET_NZ16(r); SET_V16(d,b.d,r);
+}
+
+/* $9c CPX direct -**** (6803) */
+INLINE void cpx_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC; SET_FLAGS16(d,b.d,r);
+}
+
+/* $9d JSR direct ----- */
+INLINE void jsr_di( void )
+{
+ DIRECT;
+ PUSHWORD(pPC);
+ PC = EA;
+ CHANGE_PC();
+}
+
+/* $9e LDS direct -**0- */
+INLINE void lds_di( void )
+{
+ DIRWORD(m6808.s);
+ CLR_NZV;
+ SET_NZ16(S);
+}
+
+/* $9f STS direct -**0- */
+INLINE void sts_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ DIRECT;
+ WM16(EAD,&m6808.s);
+}
+
+/* $a0 SUBA indexed ?**** */
+INLINE void suba_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = A-t;
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a1 CMPA indexed ?**** */
+INLINE void cmpa_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = A-t;
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+}
+
+/* $a2 SBCA indexed ?**** */
+INLINE void sbca_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = A-t-(CC&0x01);
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a3 SUBD indexed -**** */
+INLINE void subd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IDXWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $a4 ANDA indexed -**0- */
+INLINE void anda_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); A &= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $a5 BITA indexed -**0- */
+INLINE void bita_ix( void )
+{
+ UINT8 t,r;
+ IDXBYTE(t); r = A&t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $a6 LDA indexed -**0- */
+INLINE void lda_ix( void )
+{
+ IDXBYTE(A);
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $a7 STA indexed -**0- */
+INLINE void sta_ix( void )
+{
+ CLR_NZV; SET_NZ8(A);
+ INDEXED; WM(EAD,A);
+}
+
+/* $a8 EORA indexed -**0- */
+INLINE void eora_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); A ^= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $a9 ADCA indexed ***** */
+INLINE void adca_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = A+t+(CC&0x01);
+ CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r);
+ A = r;
+}
+
+/* $aa ORA indexed -**0- */
+INLINE void ora_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); A |= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $ab ADDA indexed ***** */
+INLINE void adda_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = A+t;
+ CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r);
+ A = r;
+}
+
+/* $ac CMPX indexed -***- */
+INLINE void cmpx_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IDXWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZV;
+ SET_NZ16(r); SET_V16(d,b.d,r);
+}
+
+/* $ac CPX indexed -**** (6803)*/
+INLINE void cpx_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IDXWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC; SET_FLAGS16(d,b.d,r);
+}
+
+/* $ad JSR indexed ----- */
+INLINE void jsr_ix( void )
+{
+ INDEXED;
+ PUSHWORD(pPC);
+ PC = EA;
+ CHANGE_PC();
+}
+
+/* $ae LDS indexed -**0- */
+INLINE void lds_ix( void )
+{
+ IDXWORD(m6808.s);
+ CLR_NZV;
+ SET_NZ16(S);
+}
+
+/* $af STS indexed -**0- */
+INLINE void sts_ix( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ INDEXED;
+ WM16(EAD,&m6808.s);
+}
+
+/* $b0 SUBA extended ?**** */
+INLINE void suba_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = A-t;
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b1 CMPA extended ?**** */
+INLINE void cmpa_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = A-t;
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+}
+
+/* $b2 SBCA extended ?**** */
+INLINE void sbca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = A-t-(CC&0x01);
+ CLR_NZVC; SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b3 SUBD extended -**** */
+INLINE void subd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D=r;
+}
+
+/* $b4 ANDA extended -**0- */
+INLINE void anda_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); A &= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $b5 BITA extended -**0- */
+INLINE void bita_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t); r = A&t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $b6 LDA extended -**0- */
+INLINE void lda_ex( void )
+{
+ EXTBYTE(A);
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $b7 STA extended -**0- */
+INLINE void sta_ex( void )
+{
+ CLR_NZV; SET_NZ8(A);
+ EXTENDED; WM(EAD,A);
+}
+
+/* $b8 EORA extended -**0- */
+INLINE void eora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); A ^= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $b9 ADCA extended ***** */
+INLINE void adca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = A+t+(CC&0x01);
+ CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r);
+ A = r;
+}
+
+/* $ba ORA extended -**0- */
+INLINE void ora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); A |= t;
+ CLR_NZV; SET_NZ8(A);
+}
+
+/* $bb ADDA extended ***** */
+INLINE void adda_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = A+t;
+ CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r);
+ A = r;
+}
+
+/* $bc CMPX extended -***- */
+INLINE void cmpx_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZV;
+ SET_NZ16(r); SET_V16(d,b.d,r);
+}
+
+/* $bc CPX extended -**** (6803) */
+INLINE void cpx_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC; SET_FLAGS16(d,b.d,r);
+}
+
+/* $bd JSR extended ----- */
+INLINE void jsr_ex( void )
+{
+ EXTENDED;
+ PUSHWORD(pPC);
+ PC = EA;
+ CHANGE_PC();
+}
+
+/* $be LDS extended -**0- */
+INLINE void lds_ex( void )
+{
+ EXTWORD(m6808.s);
+ CLR_NZV;
+ SET_NZ16(S);
+}
+
+/* $bf STS extended -**0- */
+INLINE void sts_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ EXTENDED;
+ WM16(EAD,&m6808.s);
+}
+
+/* $c0 SUBB immediate ?**** */
+INLINE void subb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = B-t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $c1 CMPB immediate ?**** */
+INLINE void cmpb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = B-t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+}
+
+/* $c2 SBCB immediate ?**** */
+INLINE void sbcb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = B-t-(CC&0x01);
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $c3 ADDD immediate -**** */
+INLINE void addd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $c4 ANDB immediate -**0- */
+INLINE void andb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t); B &= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $c5 BITB immediate -**0- */
+INLINE void bitb_im( void )
+{
+ UINT8 t,r;
+ IMMBYTE(t); r = B&t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $c6 LDB immediate -**0- */
+INLINE void ldb_im( void )
+{
+ IMMBYTE(B);
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* is this a legal instruction? */
+/* $c7 STB immediate -**0- */
+INLINE void stb_im( void )
+{
+ CLR_NZV; SET_NZ8(B);
+ IMM8; WM(EAD,B);
+}
+
+/* $c8 EORB immediate -**0- */
+INLINE void eorb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t); B ^= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $c9 ADCB immediate ***** */
+INLINE void adcb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = B+t+(CC&0x01);
+ CLR_HNZVC; SET_FLAGS8(B,t,r); SET_H(B,t,r);
+ B = r;
+}
+
+/* $ca ORB immediate -**0- */
+INLINE void orb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t); B |= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $cb ADDB immediate ***** */
+INLINE void addb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = B+t;
+ CLR_HNZVC; SET_FLAGS8(B,t,r); SET_H(B,t,r);
+ B = r;
+}
+
+/* $CC LDD immediate -**0- */
+INLINE void ldd_im( void )
+{
+ IMMWORD(m6808.d);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* is this a legal instruction? */
+/* $cd STD immediate -**0- */
+INLINE void std_im( void )
+{
+ IMM16;
+ CLR_NZV;
+ SET_NZ16(D);
+ WM16(EAD,&m6808.d);
+}
+
+/* $ce LDX immediate -**0- */
+INLINE void ldx_im( void )
+{
+ IMMWORD(m6808.x);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $cf STX immediate -**0- */
+INLINE void stx_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ IMM16;
+ WM16(EAD,&m6808.x);
+}
+
+/* $d0 SUBB direct ?**** */
+INLINE void subb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = B-t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $d1 CMPB direct ?**** */
+INLINE void cmpb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = B-t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+}
+
+/* $d2 SBCB direct ?**** */
+INLINE void sbcb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = B-t-(CC&0x01);
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $d3 ADDD direct -**** */
+INLINE void addd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $d4 ANDB direct -**0- */
+INLINE void andb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t); B &= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $d5 BITB direct -**0- */
+INLINE void bitb_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t); r = B&t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $d6 LDB direct -**0- */
+INLINE void ldb_di( void )
+{
+ DIRBYTE(B);
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $d7 STB direct -**0- */
+INLINE void stb_di( void )
+{
+ CLR_NZV; SET_NZ8(B);
+ DIRECT; WM(EAD,B);
+}
+
+/* $d8 EORB direct -**0- */
+INLINE void eorb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t); B ^= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $d9 ADCB direct ***** */
+INLINE void adcb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = B+t+(CC&0x01);
+ CLR_HNZVC; SET_FLAGS8(B,t,r); SET_H(B,t,r);
+ B = r;
+}
+
+/* $da ORB direct -**0- */
+INLINE void orb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t); B |= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $db ADDB direct ***** */
+INLINE void addb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t); r = B+t;
+ CLR_HNZVC; SET_FLAGS8(B,t,r); SET_H(B,t,r);
+ B = r;
+}
+
+/* $dc LDD direct -**0- */
+INLINE void ldd_di( void )
+{
+ DIRWORD(m6808.d);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $dd STD direct -**0- */
+INLINE void std_di( void )
+{
+ DIRECT;
+ CLR_NZV;
+ SET_NZ16(D);
+ WM16(EAD,&m6808.d);
+}
+
+/* $de LDX direct -**0- */
+INLINE void ldx_di( void )
+{
+ DIRWORD(m6808.x);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $dF STX direct -**0- */
+INLINE void stx_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ DIRECT;
+ WM16(EAD,&m6808.x);
+}
+
+/* $e0 SUBB indexed ?**** */
+INLINE void subb_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = B-t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $e1 CMPB indexed ?**** */
+INLINE void cmpb_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = B-t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+}
+
+/* $e2 SBCB indexed ?**** */
+INLINE void sbcb_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = B-t-(CC&0x01);
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $e3 ADDD indexed -**** */
+INLINE void addd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IDXWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $e4 ANDB indexed -**0- */
+INLINE void andb_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); B &= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $e5 BITB indexed -**0- */
+INLINE void bitb_ix( void )
+{
+ UINT8 t,r;
+ IDXBYTE(t); r = B&t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $e6 LDB indexed -**0- */
+INLINE void ldb_ix( void )
+{
+ IDXBYTE(B);
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $e7 STB indexed -**0- */
+INLINE void stb_ix( void )
+{
+ CLR_NZV; SET_NZ8(B);
+ INDEXED; WM(EAD,B);
+}
+
+/* $e8 EORB indexed -**0- */
+INLINE void eorb_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); B ^= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $e9 ADCB indexed ***** */
+INLINE void adcb_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = B+t+(CC&0x01);
+ CLR_HNZVC; SET_FLAGS8(B,t,r); SET_H(B,t,r);
+ B = r;
+}
+
+/* $ea ORB indexed -**0- */
+INLINE void orb_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); B |= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $eb ADDB indexed ***** */
+INLINE void addb_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t); r = B+t;
+ CLR_HNZVC; SET_FLAGS8(B,t,r); SET_H(B,t,r);
+ B = r;
+}
+
+/* $ec LDD indexed -**0- */
+INLINE void ldd_ix( void )
+{
+ IDXWORD(m6808.d);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $ec ADCX immediate -**** NSC8105 only. Flags are a guess - copied from addb_im() */
+INLINE void adcx_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t); r = X+t+(CC&0x01);
+ CLR_HNZVC; SET_FLAGS8(X,t,r); SET_H(X,t,r);
+ X = r;
+}
+
+/* $ed STD indexed -**0- */
+INLINE void std_ix( void )
+{
+ INDEXED;
+ CLR_NZV;
+ SET_NZ16(D);
+ WM16(EAD,&m6808.d);
+}
+
+/* $ee LDX indexed -**0- */
+INLINE void ldx_ix( void )
+{
+ IDXWORD(m6808.x);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $ef STX indexed -**0- */
+INLINE void stx_ix( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ INDEXED;
+ WM16(EAD,&m6808.x);
+}
+
+/* $f0 SUBB extended ?**** */
+INLINE void subb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = B-t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $f1 CMPB extended ?**** */
+INLINE void cmpb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = B-t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+}
+
+/* $f2 SBCB extended ?**** */
+INLINE void sbcb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = B-t-(CC&0x01);
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $f3 ADDD extended -**** */
+INLINE void addd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $f4 ANDB extended -**0- */
+INLINE void andb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $f5 BITB extended -**0- */
+INLINE void bitb_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $f6 LDB extended -**0- */
+INLINE void ldb_ex( void )
+{
+ EXTBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $f7 STB extended -**0- */
+INLINE void stb_ex( void )
+{
+ CLR_NZV; SET_NZ8(B);
+ EXTENDED; WM(EAD,B);
+}
+
+/* $f8 EORB extended -**0- */
+INLINE void eorb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); B ^= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $f9 ADCB extended ***** */
+INLINE void adcb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = B+t+(CC&0x01);
+ CLR_HNZVC; SET_FLAGS8(B,t,r); SET_H(B,t,r);
+ B = r;
+}
+
+/* $fa ORB extended -**0- */
+INLINE void orb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); B |= t;
+ CLR_NZV; SET_NZ8(B);
+}
+
+/* $fb ADDB extended ***** */
+INLINE void addb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = B+t;
+ CLR_HNZVC; SET_FLAGS8(B,t,r); SET_H(B,t,r);
+ B = r;
+}
+
+/* $fc LDD extended -**0- */
+INLINE void ldd_ex( void )
+{
+ EXTWORD(m6808.d);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $fc ADDX extended -**** NSC8105 only. Flags are a guess */
+INLINE void addx_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = X;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ X = r;
+}
+
+/* $fd STD extended -**0- */
+INLINE void std_ex( void )
+{
+ EXTENDED;
+ CLR_NZV;
+ SET_NZ16(D);
+ WM16(EAD,&m6808.d);
+}
+
+/* $fe LDX extended -**0- */
+INLINE void ldx_ex( void )
+{
+ EXTWORD(m6808.x);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $ff STX extended -**0- */
+INLINE void stx_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ EXTENDED;
+ WM16(EAD,&m6808.x);
+}
diff --git a/src/emu/cpu/m6800/6800tbl.c b/src/emu/cpu/m6800/6800tbl.c
new file mode 100644
index 00000000000..26795c0c9e5
--- /dev/null
+++ b/src/emu/cpu/m6800/6800tbl.c
@@ -0,0 +1,398 @@
+INLINE void aba(void);
+INLINE void abx(void);
+INLINE void adca_di(void);
+INLINE void adca_ex(void);
+INLINE void adca_im(void);
+INLINE void adca_ix(void);
+INLINE void adcb_di(void);
+INLINE void adcb_ex(void);
+INLINE void adcb_im(void);
+INLINE void adcb_ix(void);
+INLINE void adcx_im(void);
+INLINE void adda_di(void);
+INLINE void adda_ex(void);
+INLINE void adda_im(void);
+INLINE void adda_ix(void);
+INLINE void addb_di(void);
+INLINE void addb_ex(void);
+INLINE void addb_im(void);
+INLINE void addb_ix(void);
+INLINE void addd_di(void);
+INLINE void addd_ex(void);
+INLINE void addx_ex(void);
+INLINE void addd_im(void);
+INLINE void addd_ix(void);
+INLINE void aim_di(void);
+INLINE void aim_ix(void);
+INLINE void anda_di(void);
+INLINE void anda_ex(void);
+INLINE void anda_im(void);
+INLINE void anda_ix(void);
+INLINE void andb_di(void);
+INLINE void andb_ex(void);
+INLINE void andb_im(void);
+INLINE void andb_ix(void);
+INLINE void asl_ex(void);
+INLINE void asl_ix(void);
+INLINE void asla(void);
+INLINE void aslb(void);
+INLINE void asld(void);
+INLINE void asr_ex(void);
+INLINE void asr_ix(void);
+INLINE void asra(void);
+INLINE void asrb(void);
+INLINE void bcc(void);
+INLINE void bcs(void);
+INLINE void beq(void);
+INLINE void bge(void);
+INLINE void bgt(void);
+INLINE void bhi(void);
+INLINE void bita_di(void);
+INLINE void bita_ex(void);
+INLINE void bita_im(void);
+INLINE void bita_ix(void);
+INLINE void bitb_di(void);
+INLINE void bitb_ex(void);
+INLINE void bitb_im(void);
+INLINE void bitb_ix(void);
+INLINE void ble(void);
+INLINE void bls(void);
+INLINE void blt(void);
+INLINE void bmi(void);
+INLINE void bne(void);
+INLINE void bpl(void);
+INLINE void bra(void);
+INLINE void brn(void);
+INLINE void bsr(void);
+INLINE void bvc(void);
+INLINE void bvs(void);
+INLINE void cba(void);
+INLINE void clc(void);
+INLINE void cli(void);
+INLINE void clr_ex(void);
+INLINE void clr_ix(void);
+INLINE void clra(void);
+INLINE void clrb(void);
+INLINE void clv(void);
+INLINE void cmpa_di(void);
+INLINE void cmpa_ex(void);
+INLINE void cmpa_im(void);
+INLINE void cmpa_ix(void);
+INLINE void cmpb_di(void);
+INLINE void cmpb_ex(void);
+INLINE void cmpb_im(void);
+INLINE void cmpb_ix(void);
+INLINE void cmpx_di(void);
+INLINE void cmpx_ex(void);
+INLINE void cmpx_im(void);
+INLINE void cmpx_ix(void);
+INLINE void com_ex(void);
+INLINE void com_ix(void);
+INLINE void coma(void);
+INLINE void comb(void);
+INLINE void daa(void);
+INLINE void dec_ex(void);
+INLINE void dec_ix(void);
+INLINE void deca(void);
+INLINE void decb(void);
+INLINE void des(void);
+INLINE void dex(void);
+INLINE void eim_di(void);
+INLINE void eim_ix(void);
+INLINE void eora_di(void);
+INLINE void eora_ex(void);
+INLINE void eora_im(void);
+INLINE void eora_ix(void);
+INLINE void eorb_di(void);
+INLINE void eorb_ex(void);
+INLINE void eorb_im(void);
+INLINE void eorb_ix(void);
+//INLINE void illegal(void);
+static void illegal(void);
+INLINE void inc_ex(void);
+INLINE void inc_ix(void);
+INLINE void inca(void);
+INLINE void incb(void);
+INLINE void ins(void);
+INLINE void inx(void);
+INLINE void jmp_ex(void);
+INLINE void jmp_ix(void);
+INLINE void jsr_di(void);
+INLINE void jsr_ex(void);
+INLINE void jsr_ix(void);
+INLINE void lda_di(void);
+INLINE void lda_ex(void);
+INLINE void lda_im(void);
+INLINE void lda_ix(void);
+INLINE void ldb_di(void);
+INLINE void ldb_ex(void);
+INLINE void ldb_im(void);
+INLINE void ldb_ix(void);
+INLINE void ldd_di(void);
+INLINE void ldd_ex(void);
+INLINE void ldd_im(void);
+INLINE void ldd_ix(void);
+INLINE void lds_di(void);
+INLINE void lds_ex(void);
+INLINE void lds_im(void);
+INLINE void lds_ix(void);
+INLINE void ldx_di(void);
+INLINE void ldx_ex(void);
+INLINE void ldx_im(void);
+INLINE void ldx_ix(void);
+INLINE void lsr_ex(void);
+INLINE void lsr_ix(void);
+INLINE void lsra(void);
+INLINE void lsrb(void);
+INLINE void lsrd(void);
+INLINE void mul(void);
+INLINE void neg_ex(void);
+INLINE void neg_ix(void);
+INLINE void nega(void);
+INLINE void negb(void);
+INLINE void nop(void);
+INLINE void oim_di(void);
+INLINE void oim_ix(void);
+INLINE void ora_di(void);
+INLINE void ora_ex(void);
+INLINE void ora_im(void);
+INLINE void ora_ix(void);
+INLINE void orb_di(void);
+INLINE void orb_ex(void);
+INLINE void orb_im(void);
+INLINE void orb_ix(void);
+INLINE void psha(void);
+INLINE void pshb(void);
+INLINE void pshx(void);
+INLINE void pula(void);
+INLINE void pulb(void);
+INLINE void pulx(void);
+INLINE void rol_ex(void);
+INLINE void rol_ix(void);
+INLINE void rola(void);
+INLINE void rolb(void);
+INLINE void ror_ex(void);
+INLINE void ror_ix(void);
+INLINE void rora(void);
+INLINE void rorb(void);
+INLINE void rti(void);
+INLINE void rts(void);
+INLINE void sba(void);
+INLINE void sbca_di(void);
+INLINE void sbca_ex(void);
+INLINE void sbca_im(void);
+INLINE void sbca_ix(void);
+INLINE void sbcb_di(void);
+INLINE void sbcb_ex(void);
+INLINE void sbcb_im(void);
+INLINE void sbcb_ix(void);
+INLINE void sec(void);
+INLINE void sei(void);
+INLINE void sev(void);
+#if (HAS_HD63701)
+INLINE void slp(void);
+#endif
+INLINE void sta_di(void);
+INLINE void sta_ex(void);
+INLINE void sta_im(void);
+INLINE void sta_ix(void);
+INLINE void stb_di(void);
+INLINE void stb_ex(void);
+INLINE void stb_im(void);
+INLINE void stb_ix(void);
+INLINE void std_di(void);
+INLINE void std_ex(void);
+INLINE void std_im(void);
+INLINE void std_ix(void);
+INLINE void sts_di(void);
+INLINE void sts_ex(void);
+INLINE void sts_im(void);
+INLINE void sts_ix(void);
+INLINE void stx_di(void);
+INLINE void stx_ex(void);
+INLINE void stx_im(void);
+INLINE void stx_ix(void);
+INLINE void suba_di(void);
+INLINE void suba_ex(void);
+INLINE void suba_im(void);
+INLINE void suba_ix(void);
+INLINE void subb_di(void);
+INLINE void subb_ex(void);
+INLINE void subb_im(void);
+INLINE void subb_ix(void);
+INLINE void subd_di(void);
+INLINE void subd_ex(void);
+INLINE void subd_im(void);
+INLINE void subd_ix(void);
+INLINE void swi(void);
+INLINE void tab(void);
+INLINE void tap(void);
+INLINE void tba(void);
+INLINE void tim_di(void);
+INLINE void tim_ix(void);
+INLINE void tpa(void);
+INLINE void tst_ex(void);
+INLINE void tst_ix(void);
+INLINE void tsta(void);
+INLINE void tstb(void);
+INLINE void tsx(void);
+INLINE void txs(void);
+INLINE void undoc1(void);
+INLINE void undoc2(void);
+INLINE void wai(void);
+INLINE void xgdx(void);
+
+INLINE void cpx_di(void);
+INLINE void cpx_ex(void);
+INLINE void cpx_im(void);
+INLINE void cpx_ix(void);
+#if (HAS_HD63701)
+//INLINE void trap(void);
+static void trap(void);
+#endif
+
+static void (*m6800_insn[0x100])(void) = {
+illegal,nop, illegal,illegal,illegal,illegal,tap, tpa,
+inx, dex, clv, sev, clc, sec, cli, sei,
+sba, cba, illegal,illegal,illegal,illegal,tab, tba,
+illegal,daa, illegal,aba, illegal,illegal,illegal,illegal,
+bra, brn, bhi, bls, bcc, bcs, bne, beq,
+bvc, bvs, bpl, bmi, bge, blt, bgt, ble,
+tsx, ins, pula, pulb, des, txs, psha, pshb,
+illegal,rts, illegal,rti, illegal,illegal,wai, swi,
+nega, illegal,illegal,coma, lsra, illegal,rora, asra,
+asla, rola, deca, illegal,inca, tsta, illegal,clra,
+negb, illegal,illegal,comb, lsrb, illegal,rorb, asrb,
+aslb, rolb, decb, illegal,incb, tstb, illegal,clrb,
+neg_ix, illegal,illegal,com_ix, lsr_ix, illegal,ror_ix, asr_ix,
+asl_ix, rol_ix, dec_ix, illegal,inc_ix, tst_ix, jmp_ix, clr_ix,
+neg_ex, illegal,illegal,com_ex, lsr_ex, illegal,ror_ex, asr_ex,
+asl_ex, rol_ex, dec_ex, illegal,inc_ex, tst_ex, jmp_ex, clr_ex,
+suba_im,cmpa_im,sbca_im,illegal,anda_im,bita_im,lda_im, sta_im,
+eora_im,adca_im,ora_im, adda_im,cmpx_im,bsr, lds_im, sts_im,
+suba_di,cmpa_di,sbca_di,illegal,anda_di,bita_di,lda_di, sta_di,
+eora_di,adca_di,ora_di, adda_di,cmpx_di,jsr_di, lds_di, sts_di,
+suba_ix,cmpa_ix,sbca_ix,illegal,anda_ix,bita_ix,lda_ix, sta_ix,
+eora_ix,adca_ix,ora_ix, adda_ix,cmpx_ix,jsr_ix, lds_ix, sts_ix,
+suba_ex,cmpa_ex,sbca_ex,illegal,anda_ex,bita_ex,lda_ex, sta_ex,
+eora_ex,adca_ex,ora_ex, adda_ex,cmpx_ex,jsr_ex, lds_ex, sts_ex,
+subb_im,cmpb_im,sbcb_im,illegal,andb_im,bitb_im,ldb_im, stb_im,
+eorb_im,adcb_im,orb_im, addb_im,illegal,illegal,ldx_im, stx_im,
+subb_di,cmpb_di,sbcb_di,illegal,andb_di,bitb_di,ldb_di, stb_di,
+eorb_di,adcb_di,orb_di, addb_di,illegal,illegal,ldx_di, stx_di,
+subb_ix,cmpb_ix,sbcb_ix,illegal,andb_ix,bitb_ix,ldb_ix, stb_ix,
+eorb_ix,adcb_ix,orb_ix, addb_ix,illegal,illegal,ldx_ix, stx_ix,
+subb_ex,cmpb_ex,sbcb_ex,illegal,andb_ex,bitb_ex,ldb_ex, stb_ex,
+eorb_ex,adcb_ex,orb_ex, addb_ex,illegal,illegal,ldx_ex, stx_ex
+};
+
+#if (HAS_M6801||HAS_M6803)
+static void (*m6803_insn[0x100])(void) = {
+illegal,nop, illegal,illegal,lsrd, asld, tap, tpa,
+inx, dex, clv, sev, clc, sec, cli, sei,
+sba, cba, illegal,illegal,illegal,illegal,tab, tba,
+illegal,daa, illegal,aba, illegal,illegal,illegal,illegal,
+bra, brn, bhi, bls, bcc, bcs, bne, beq,
+bvc, bvs, bpl, bmi, bge, blt, bgt, ble,
+tsx, ins, pula, pulb, des, txs, psha, pshb,
+pulx, rts, abx, rti, pshx, mul, wai, swi,
+nega, illegal,illegal,coma, lsra, illegal,rora, asra,
+asla, rola, deca, illegal,inca, tsta, illegal,clra,
+negb, illegal,illegal,comb, lsrb, illegal,rorb, asrb,
+aslb, rolb, decb, illegal,incb, tstb, illegal,clrb,
+neg_ix, illegal,illegal,com_ix, lsr_ix, illegal,ror_ix, asr_ix,
+asl_ix, rol_ix, dec_ix, illegal,inc_ix, tst_ix, jmp_ix, clr_ix,
+neg_ex, illegal,illegal,com_ex, lsr_ex, illegal,ror_ex, asr_ex,
+asl_ex, rol_ex, dec_ex, illegal,inc_ex, tst_ex, jmp_ex, clr_ex,
+suba_im,cmpa_im,sbca_im,subd_im,anda_im,bita_im,lda_im, sta_im,
+eora_im,adca_im,ora_im, adda_im,cpx_im ,bsr, lds_im, sts_im,
+suba_di,cmpa_di,sbca_di,subd_di,anda_di,bita_di,lda_di, sta_di,
+eora_di,adca_di,ora_di, adda_di,cpx_di ,jsr_di, lds_di, sts_di,
+suba_ix,cmpa_ix,sbca_ix,subd_ix,anda_ix,bita_ix,lda_ix, sta_ix,
+eora_ix,adca_ix,ora_ix, adda_ix,cpx_ix ,jsr_ix, lds_ix, sts_ix,
+suba_ex,cmpa_ex,sbca_ex,subd_ex,anda_ex,bita_ex,lda_ex, sta_ex,
+eora_ex,adca_ex,ora_ex, adda_ex,cpx_ex ,jsr_ex, lds_ex, sts_ex,
+subb_im,cmpb_im,sbcb_im,addd_im,andb_im,bitb_im,ldb_im, stb_im,
+eorb_im,adcb_im,orb_im, addb_im,ldd_im, std_im, ldx_im, stx_im,
+subb_di,cmpb_di,sbcb_di,addd_di,andb_di,bitb_di,ldb_di, stb_di,
+eorb_di,adcb_di,orb_di, addb_di,ldd_di, std_di, ldx_di, stx_di,
+subb_ix,cmpb_ix,sbcb_ix,addd_ix,andb_ix,bitb_ix,ldb_ix, stb_ix,
+eorb_ix,adcb_ix,orb_ix, addb_ix,ldd_ix, std_ix, ldx_ix, stx_ix,
+subb_ex,cmpb_ex,sbcb_ex,addd_ex,andb_ex,bitb_ex,ldb_ex, stb_ex,
+eorb_ex,adcb_ex,orb_ex, addb_ex,ldd_ex, std_ex, ldx_ex, stx_ex
+};
+#endif
+
+#if (HAS_HD63701)
+static void (*hd63701_insn[0x100])(void) = {
+trap ,nop, trap ,trap ,lsrd, asld, tap, tpa,
+inx, dex, clv, sev, clc, sec, cli, sei,
+sba, cba, undoc1, undoc2, trap ,trap ,tab, tba,
+xgdx, daa, slp ,aba, trap ,trap ,trap ,trap ,
+bra, brn, bhi, bls, bcc, bcs, bne, beq,
+bvc, bvs, bpl, bmi, bge, blt, bgt, ble,
+tsx, ins, pula, pulb, des, txs, psha, pshb,
+pulx, rts, abx, rti, pshx, mul, wai, swi,
+nega, trap ,trap ,coma, lsra, trap ,rora, asra,
+asla, rola, deca, trap ,inca, tsta, trap ,clra,
+negb, trap ,trap ,comb, lsrb, trap ,rorb, asrb,
+aslb, rolb, decb, trap ,incb, tstb, trap ,clrb,
+neg_ix, aim_ix, oim_ix, com_ix, lsr_ix, eim_ix, ror_ix, asr_ix,
+asl_ix, rol_ix, dec_ix, tim_ix, inc_ix, tst_ix, jmp_ix, clr_ix,
+neg_ex, aim_di, oim_di, com_ex, lsr_ex, eim_di, ror_ex, asr_ex,
+asl_ex, rol_ex, dec_ex, tim_di, inc_ex, tst_ex, jmp_ex, clr_ex,
+suba_im,cmpa_im,sbca_im,subd_im,anda_im,bita_im,lda_im, sta_im,
+eora_im,adca_im,ora_im, adda_im,cpx_im ,bsr, lds_im, sts_im,
+suba_di,cmpa_di,sbca_di,subd_di,anda_di,bita_di,lda_di, sta_di,
+eora_di,adca_di,ora_di, adda_di,cpx_di ,jsr_di, lds_di, sts_di,
+suba_ix,cmpa_ix,sbca_ix,subd_ix,anda_ix,bita_ix,lda_ix, sta_ix,
+eora_ix,adca_ix,ora_ix, adda_ix,cpx_ix ,jsr_ix, lds_ix, sts_ix,
+suba_ex,cmpa_ex,sbca_ex,subd_ex,anda_ex,bita_ex,lda_ex, sta_ex,
+eora_ex,adca_ex,ora_ex, adda_ex,cpx_ex ,jsr_ex, lds_ex, sts_ex,
+subb_im,cmpb_im,sbcb_im,addd_im,andb_im,bitb_im,ldb_im, stb_im,
+eorb_im,adcb_im,orb_im, addb_im,ldd_im, std_im, ldx_im, stx_im,
+subb_di,cmpb_di,sbcb_di,addd_di,andb_di,bitb_di,ldb_di, stb_di,
+eorb_di,adcb_di,orb_di, addb_di,ldd_di, std_di, ldx_di, stx_di,
+subb_ix,cmpb_ix,sbcb_ix,addd_ix,andb_ix,bitb_ix,ldb_ix, stb_ix,
+eorb_ix,adcb_ix,orb_ix, addb_ix,ldd_ix, std_ix, ldx_ix, stx_ix,
+subb_ex,cmpb_ex,sbcb_ex,addd_ex,andb_ex,bitb_ex,ldb_ex, stb_ex,
+eorb_ex,adcb_ex,orb_ex, addb_ex,ldd_ex, std_ex, ldx_ex, stx_ex
+};
+#endif
+
+#if (HAS_NSC8105)
+static void (*nsc8105_insn[0x100])(void) = {
+illegal,illegal,nop, illegal,illegal,tap, illegal,tpa,
+inx, clv, dex, sev, clc, cli, sec, sei,
+sba, illegal,cba, illegal,illegal,tab, illegal,tba,
+illegal,illegal,daa, aba, illegal,illegal,illegal,illegal,
+bra, bhi, brn, bls, bcc, bne, bcs, beq,
+bvc, bpl, bvs, bmi, bge, bgt, blt, ble,
+tsx, pula, ins, pulb, des, psha, txs, pshb,
+illegal,illegal,rts, rti, illegal,wai, illegal,swi,
+suba_im,sbca_im,cmpa_im,illegal,anda_im,lda_im, bita_im,sta_im,
+eora_im,ora_im, adca_im,adda_im,cmpx_im,lds_im, bsr, sts_im,
+suba_di,sbca_di,cmpa_di,illegal,anda_di,lda_di, bita_di,sta_di,
+eora_di,ora_di, adca_di,adda_di,cmpx_di,lds_di, jsr_di, sts_di,
+suba_ix,sbca_ix,cmpa_ix,illegal,anda_ix,lda_ix, bita_ix,sta_ix,
+eora_ix,ora_ix, adca_ix,adda_ix,cmpx_ix,lds_ix, jsr_ix, sts_ix,
+suba_ex,sbca_ex,cmpa_ex,illegal,anda_ex,lda_ex, bita_ex,sta_ex,
+eora_ex,ora_ex, adca_ex,adda_ex,cmpx_ex,lds_ex, jsr_ex, sts_ex,
+nega, illegal,illegal,coma, lsra, rora, illegal,asra,
+asla, deca, rola, illegal,inca, illegal,tsta, clra,
+negb, illegal,illegal,comb, lsrb, rorb, illegal,asrb,
+aslb, decb, rolb, illegal,incb, illegal,tstb, clrb,
+neg_ix, illegal,illegal,com_ix, lsr_ix, ror_ix, illegal,asr_ix,
+asl_ix, dec_ix, rol_ix, illegal,inc_ix, jmp_ix, tst_ix, clr_ix,
+neg_ex, illegal,illegal,com_ex, lsr_ex, ror_ex, illegal,asr_ex,
+asl_ex, dec_ex, rol_ex, illegal,inc_ex, jmp_ex, tst_ex, clr_ex,
+subb_im,sbcb_im,cmpb_im,illegal,andb_im,ldb_im, bitb_im,stb_im,
+eorb_im,orb_im, adcb_im,addb_im,illegal,ldx_im, illegal,stx_im,
+subb_di,sbcb_di,cmpb_di,illegal,andb_di,ldb_di, bitb_di,stb_di,
+eorb_di,orb_di, adcb_di,addb_di,illegal,ldx_di, illegal,stx_di,
+subb_ix,sbcb_ix,cmpb_ix,illegal,andb_ix,ldb_ix, bitb_ix,stb_ix,
+eorb_ix,orb_ix, adcb_ix,addb_ix,adcx_im,ldx_ix, illegal,stx_ix,
+subb_ex,sbcb_ex,cmpb_ex,illegal,andb_ex,ldb_ex, bitb_ex,stb_ex,
+eorb_ex,orb_ex, adcb_ex,addb_ex,addx_ex,ldx_ex, illegal,stx_ex
+};
+#endif
diff --git a/src/emu/cpu/m6800/m6800.c b/src/emu/cpu/m6800/m6800.c
new file mode 100644
index 00000000000..5964e86212f
--- /dev/null
+++ b/src/emu/cpu/m6800/m6800.c
@@ -0,0 +1,2850 @@
+/*** m6800: Portable 6800 class emulator *************************************
+
+ m6800.c
+
+ References:
+
+ 6809 Simulator V09, By L.C. Benschop, Eidnhoven The Netherlands.
+
+ m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from
+ the 6809 Simulator V09)
+
+ 6809 Microcomputer Programming & Interfacing with Experiments"
+ by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc.
+
+ System dependencies: UINT16 must be 16 bit unsigned int
+ UINT8 must be 8 bit unsigned int
+ UINT32 must be more than 16 bits
+ arrays up to 65536 bytes must be supported
+ machine must be twos complement
+
+History
+991031 ZV
+ Added NSC-8105 support
+
+990319 HJB
+ Fixed wrong LSB/MSB order for push/pull word.
+ Subtract .extra_cycles at the beginning/end of the exectuion loops.
+
+990316 HJB
+ Renamed to 6800, since that's the basic CPU.
+ Added different cycle count tables for M6800/2/8, M6801/3 and HD63701.
+
+990314 HJB
+ Also added the M6800 subtype.
+
+990311 HJB
+ Added _info functions. Now uses static m6808_Regs struct instead
+ of single statics. Changed the 16 bit registers to use the generic
+ PAIR union. Registers defined using macros. Split the core into
+ four execution loops for M6802, M6803, M6808 and HD63701.
+ TST, TSTA and TSTB opcodes reset carry flag.
+TODO:
+ Verify invalid opcodes for the different CPU types.
+ Add proper credits to _info functions.
+ Integrate m6808_Flags into the registers (multiple m6808 type CPUs?)
+
+990301 HJB
+ Modified the interrupt handling. No more pending interrupt checks.
+ WAI opcode saves state, when an interrupt is taken (IRQ or OCI),
+ the state is only saved if not already done by WAI.
+
+*****************************************************************************/
+
+/*
+
+ Chip RAM NVRAM ROM SCI
+ -----------------------------------------------
+ MC6800 - - - no
+ MC6801 128 64 2K yes
+ MC68701 128 64 - yes
+ MC6803 128 64 - yes
+ MC6802 128 32 - no
+ MC6802NS 128 - - no
+ MC6808 - - - no
+
+ HD6301 128 - 4K yes
+ HD63701 192 - 4K yes
+ HD6303 128 - - yes
+ HD6801 128 64 2K yes
+
+ NSC8105
+ MS2010-A
+
+*/
+
+#include "debugger.h"
+#include "m6800.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+#if 0
+/* CPU subtypes, needed for extra insn after TAP/CLI/SEI */
+enum {
+ SUBTYPE_M6800,
+ SUBTYPE_M6801,
+ SUBTYPE_M6802,
+ SUBTYPE_M6803,
+ SUBTYPE_M6808,
+ SUBTYPE_HD63701,
+ SUBTYPE_NSC8105
+};
+#endif
+
+/* 6800 Registers */
+typedef struct
+{
+// int subtype; /* CPU subtype */
+ PAIR ppc; /* Previous program counter */
+ PAIR pc; /* Program counter */
+ PAIR s; /* Stack pointer */
+ PAIR x; /* Index register */
+ PAIR d; /* Accumulators */
+ UINT8 cc; /* Condition codes */
+ UINT8 wai_state; /* WAI opcode state ,(or sleep opcode state) */
+ UINT8 nmi_state; /* NMI line state */
+ UINT8 irq_state[2]; /* IRQ line state [IRQ1,TIN] */
+ UINT8 ic_eddge; /* InputCapture eddge , b.0=fall,b.1=raise */
+
+ int (*irq_callback)(int irqline);
+ int extra_cycles; /* cycles used for interrupts */
+ void (* const * insn)(void); /* instruction table */
+ const UINT8 *cycles; /* clock cycle of instruction table */
+ /* internal registers */
+ UINT8 port1_ddr;
+ UINT8 port2_ddr;
+ UINT8 port3_ddr;
+ UINT8 port4_ddr;
+ UINT8 port1_data;
+ UINT8 port2_data;
+ UINT8 port3_data;
+ UINT8 port4_data;
+ UINT8 tcsr; /* Timer Control and Status Register */
+ UINT8 pending_tcsr; /* pending IRQ flag for clear IRQflag process */
+ UINT8 irq2; /* IRQ2 flags */
+ UINT8 ram_ctrl;
+ PAIR counter; /* free running counter */
+ PAIR output_compare; /* output compare */
+ UINT16 input_capture; /* input capture */
+
+ int clock;
+ UINT8 trcsr, rmcr, rdr, tdr, rsr, tsr;
+ int rxbits, txbits, txstate, trcsr_read, tx;
+
+ PAIR timer_over;
+} m6800_Regs;
+
+/* 680x registers */
+static m6800_Regs m6800;
+
+static emu_timer *m6800_rx_timer;
+static emu_timer *m6800_tx_timer;
+
+#define m6801 m6800
+#define m6802 m6800
+#define m6803 m6800
+#define m6808 m6800
+#define hd63701 m6800
+#define nsc8105 m6800
+
+#define pPPC m6800.ppc
+#define pPC m6800.pc
+#define pS m6800.s
+#define pX m6800.x
+#define pD m6800.d
+
+#define PC m6800.pc.w.l
+#define PCD m6800.pc.d
+#define S m6800.s.w.l
+#define SD m6800.s.d
+#define X m6800.x.w.l
+#define D m6800.d.w.l
+#define A m6800.d.b.h
+#define B m6800.d.b.l
+#define CC m6800.cc
+
+#define CT m6800.counter.w.l
+#define CTH m6800.counter.w.h
+#define CTD m6800.counter.d
+#define OC m6800.output_compare.w.l
+#define OCH m6800.output_compare.w.h
+#define OCD m6800.output_compare.d
+#define TOH m6800.timer_over.w.l
+#define TOD m6800.timer_over.d
+
+static PAIR ea; /* effective address */
+#define EAD ea.d
+#define EA ea.w.l
+
+/* public globals */
+static int m6800_ICount;
+
+/* point of next timer event */
+static UINT32 timer_next;
+
+/* DS -- THESE ARE RE-DEFINED IN m6800.h TO RAM, ROM or FUNCTIONS IN cpuintrf.c */
+#define RM M6800_RDMEM
+#define WM M6800_WRMEM
+#define M_RDOP M6800_RDOP
+#define M_RDOP_ARG M6800_RDOP_ARG
+
+/* macros to access memory */
+#define IMMBYTE(b) b = M_RDOP_ARG(PCD); PC++
+#define IMMWORD(w) w.d = (M_RDOP_ARG(PCD)<<8) | M_RDOP_ARG((PCD+1)&0xffff); PC+=2
+
+#define PUSHBYTE(b) WM(SD,b); --S
+#define PUSHWORD(w) WM(SD,w.b.l); --S; WM(SD,w.b.h); --S
+#define PULLBYTE(b) S++; b = RM(SD)
+#define PULLWORD(w) S++; w.d = RM(SD)<<8; S++; w.d |= RM(SD)
+
+#define MODIFIED_tcsr { \
+ m6800.irq2 = (m6800.tcsr&(m6800.tcsr<<3))&(TCSR_ICF|TCSR_OCF|TCSR_TOF); \
+}
+
+#define SET_TIMER_EVENT { \
+ timer_next = (OCD - CTD < TOD - CTD) ? OCD : TOD; \
+}
+
+/* cleanup high-word of counters */
+#define CLEANUP_conters { \
+ OCH -= CTH; \
+ TOH -= CTH; \
+ CTH = 0; \
+ SET_TIMER_EVENT; \
+}
+
+/* when change freerunningcounter or outputcapture */
+#define MODIFIED_counters { \
+ OCH = (OC >= CT) ? CTH : CTH+1; \
+ SET_TIMER_EVENT; \
+}
+
+// serial I/O
+
+#define M6800_RMCR_SS_MASK 0x03 // Speed Select
+#define M6800_RMCR_SS_4096 0x03 // E / 4096
+#define M6800_RMCR_SS_1024 0x02 // E / 1024
+#define M6800_RMCR_SS_128 0x01 // E / 128
+#define M6800_RMCR_SS_16 0x00 // E / 16
+#define M6800_RMCR_CC_MASK 0x0c // Clock Control/Format Select
+
+#define M6800_TRCSR_RDRF 0x80 // Receive Data Register Full
+#define M6800_TRCSR_ORFE 0x40 // Over Run Framing Error
+#define M6800_TRCSR_TDRE 0x20 // Transmit Data Register Empty
+#define M6800_TRCSR_RIE 0x10 // Receive Interrupt Enable
+#define M6800_TRCSR_RE 0x08 // Receive Enable
+#define M6800_TRCSR_TIE 0x04 // Transmit Interrupt Enable
+#define M6800_TRCSR_TE 0x02 // Transmit Enable
+#define M6800_TRCSR_WU 0x01 // Wake Up
+
+#define M6800_PORT2_IO4 0x10
+#define M6800_PORT2_IO3 0x08
+
+static const int M6800_RMCR_SS[] = { 16, 128, 1024, 4096 };
+
+#define M6800_SERIAL_START 0
+#define M6800_SERIAL_STOP 9
+
+enum
+{
+ M6800_TX_STATE_INIT = 0,
+ M6800_TX_STATE_READY
+};
+
+/* take interrupt */
+#define TAKE_ICI ENTER_INTERRUPT("M6800#%d take ICI\n",0xfff6)
+#define TAKE_OCI ENTER_INTERRUPT("M6800#%d take OCI\n",0xfff4)
+#define TAKE_TOI ENTER_INTERRUPT("M6800#%d take TOI\n",0xfff2)
+#define TAKE_SCI ENTER_INTERRUPT("M6800#%d take SCI\n",0xfff0)
+#define TAKE_TRAP ENTER_INTERRUPT("M6800#%d take TRAP\n",0xffee)
+
+/* operate one instruction for */
+#define ONE_MORE_INSN() { \
+ UINT8 ireg; \
+ pPPC = pPC; \
+ CALL_MAME_DEBUG; \
+ ireg=M_RDOP(PCD); \
+ PC++; \
+ (*m6800.insn[ireg])(); \
+ INCREMENT_COUNTER(m6800.cycles[ireg]); \
+}
+
+/* check the IRQ lines for pending interrupts */
+#define CHECK_IRQ_LINES() { \
+ if( !(CC & 0x10) ) \
+ { \
+ if( m6800.irq_state[M6800_IRQ_LINE] != CLEAR_LINE ) \
+ { /* standard IRQ */ \
+ ENTER_INTERRUPT("M6800#%d take IRQ1\n",0xfff8); \
+ if( m6800.irq_callback ) \
+ (void)(*m6800.irq_callback)(M6800_IRQ_LINE); \
+ } \
+ else \
+ m6800_check_irq2(); \
+ } \
+}
+
+/* CC masks HI NZVC
+ 7654 3210 */
+#define CLR_HNZVC CC&=0xd0
+#define CLR_NZV CC&=0xf1
+#define CLR_HNZC CC&=0xd2
+#define CLR_NZVC CC&=0xf0
+#define CLR_Z CC&=0xfb
+#define CLR_NZC CC&=0xf2
+#define CLR_ZC CC&=0xfa
+#define CLR_C CC&=0xfe
+
+/* macros for CC -- CC bits affected should be reset before calling */
+#define SET_Z(a) if(!(a))SEZ
+#define SET_Z8(a) SET_Z((UINT8)(a))
+#define SET_Z16(a) SET_Z((UINT16)(a))
+#define SET_N8(a) CC|=(((a)&0x80)>>4)
+#define SET_N16(a) CC|=(((a)&0x8000)>>12)
+#define SET_H(a,b,r) CC|=((((a)^(b)^(r))&0x10)<<1)
+#define SET_C8(a) CC|=(((a)&0x100)>>8)
+#define SET_C16(a) CC|=(((a)&0x10000)>>16)
+#define SET_V8(a,b,r) CC|=((((a)^(b)^(r)^((r)>>1))&0x80)>>6)
+#define SET_V16(a,b,r) CC|=((((a)^(b)^(r)^((r)>>1))&0x8000)>>14)
+
+static const UINT8 flags8i[256]= /* increment */
+{
+0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x0a,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
+};
+static const UINT8 flags8d[256]= /* decrement */
+{
+0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
+};
+#define SET_FLAGS8I(a) {CC|=flags8i[(a)&0xff];}
+#define SET_FLAGS8D(a) {CC|=flags8d[(a)&0xff];}
+
+/* combos */
+#define SET_NZ8(a) {SET_N8(a);SET_Z8(a);}
+#define SET_NZ16(a) {SET_N16(a);SET_Z16(a);}
+#define SET_FLAGS8(a,b,r) {SET_N8(r);SET_Z8(r);SET_V8(a,b,r);SET_C8(r);}
+#define SET_FLAGS16(a,b,r) {SET_N16(r);SET_Z16(r);SET_V16(a,b,r);SET_C16(r);}
+
+/* for treating an UINT8 as a signed INT16 */
+#define SIGNED(b) ((INT16)(b&0x80?b|0xff00:b))
+
+/* Macros for addressing modes */
+#define DIRECT IMMBYTE(EAD)
+#define IMM8 EA=PC++
+#define IMM16 {EA=PC;PC+=2;}
+#define EXTENDED IMMWORD(ea)
+#define INDEXED {EA=X+(UINT8)M_RDOP_ARG(PCD);PC++;}
+
+/* macros to set status flags */
+#define SEC CC|=0x01
+#define CLC CC&=0xfe
+#define SEZ CC|=0x04
+#define CLZ CC&=0xfb
+#define SEN CC|=0x08
+#define CLN CC&=0xf7
+#define SEV CC|=0x02
+#define CLV CC&=0xfd
+#define SEH CC|=0x20
+#define CLH CC&=0xdf
+#define SEI CC|=0x10
+#define CLI CC&=~0x10
+
+/* mnemonicos for the Timer Control and Status Register bits */
+#define TCSR_OLVL 0x01
+#define TCSR_IEDG 0x02
+#define TCSR_ETOI 0x04
+#define TCSR_EOCI 0x08
+#define TCSR_EICI 0x10
+#define TCSR_TOF 0x20
+#define TCSR_OCF 0x40
+#define TCSR_ICF 0x80
+
+#define INCREMENT_COUNTER(amount) \
+{ \
+ m6800_ICount -= amount; \
+ CTD += amount; \
+ if( CTD >= timer_next) \
+ check_timer_event(); \
+}
+
+#define EAT_CYCLES \
+{ \
+ int cycles_to_eat; \
+ \
+ cycles_to_eat = timer_next - CTD; \
+ if( cycles_to_eat > m6800_ICount) cycles_to_eat = m6800_ICount; \
+ if (cycles_to_eat > 0) \
+ { \
+ INCREMENT_COUNTER(cycles_to_eat); \
+ } \
+}
+
+/* macros for convenience */
+#define DIRBYTE(b) {DIRECT;b=RM(EAD);}
+#define DIRWORD(w) {DIRECT;w.d=RM16(EAD);}
+#define EXTBYTE(b) {EXTENDED;b=RM(EAD);}
+#define EXTWORD(w) {EXTENDED;w.d=RM16(EAD);}
+
+#define IDXBYTE(b) {INDEXED;b=RM(EAD);}
+#define IDXWORD(w) {INDEXED;w.d=RM16(EAD);}
+
+/* Macros for branch instructions */
+#define CHANGE_PC() change_pc(PCD)
+#define BRANCH(f) {IMMBYTE(t);if(f){PC+=SIGNED(t);CHANGE_PC();}}
+#define NXORV ((CC&0x08)^((CC&0x02)<<2))
+
+/* Note: we use 99 cycles here for invalid opcodes so that we don't */
+/* hang in an infinite loop if we hit one */
+static const UINT8 cycles_6800[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ 99, 2,99,99,99,99, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2,
+ /*1*/ 2, 2,99,99,99,99, 2, 2,99, 2,99, 2,99,99,99,99,
+ /*2*/ 4,99, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ /*3*/ 4, 4, 4, 4, 4, 4, 4, 4,99, 5,99,10,99,99, 9,12,
+ /*4*/ 2,99,99, 2, 2,99, 2, 2, 2, 2, 2,99, 2, 2,99, 2,
+ /*5*/ 2,99,99, 2, 2,99, 2, 2, 2, 2, 2,99, 2, 2,99, 2,
+ /*6*/ 7,99,99, 7, 7,99, 7, 7, 7, 7, 7,99, 7, 7, 4, 7,
+ /*7*/ 6,99,99, 6, 6,99, 6, 6, 6, 6, 6,99, 6, 6, 3, 6,
+ /*8*/ 2, 2, 2,99, 2, 2, 2,99, 2, 2, 2, 2, 3, 8, 3,99,
+ /*9*/ 3, 3, 3,99, 3, 3, 3, 4, 3, 3, 3, 3, 4,99, 4, 5,
+ /*A*/ 5, 5, 5,99, 5, 5, 5, 6, 5, 5, 5, 5, 6, 8, 6, 7,
+ /*B*/ 4, 4, 4,99, 4, 4, 4, 5, 4, 4, 4, 4, 5, 9, 5, 6,
+ /*C*/ 2, 2, 2,99, 2, 2, 2,99, 2, 2, 2, 2,99,99, 3,99,
+ /*D*/ 3, 3, 3,99, 3, 3, 3, 4, 3, 3, 3, 3,99,99, 4, 5,
+ /*E*/ 5, 5, 5,99, 5, 5, 5, 6, 5, 5, 5, 5,99,99, 6, 7,
+ /*F*/ 4, 4, 4,99, 4, 4, 4, 5, 4, 4, 4, 4,99,99, 5, 6
+};
+
+static const UINT8 cycles_6803[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ 99, 2,99,99, 3, 3, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2,
+ /*1*/ 2, 2,99,99,99,99, 2, 2,99, 2,99, 2,99,99,99,99,
+ /*2*/ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ /*3*/ 3, 3, 4, 4, 3, 3, 3, 3, 5, 5, 3,10, 4,10, 9,12,
+ /*4*/ 2,99,99, 2, 2,99, 2, 2, 2, 2, 2,99, 2, 2,99, 2,
+ /*5*/ 2,99,99, 2, 2,99, 2, 2, 2, 2, 2,99, 2, 2,99, 2,
+ /*6*/ 6,99,99, 6, 6,99, 6, 6, 6, 6, 6,99, 6, 6, 3, 6,
+ /*7*/ 6,99,99, 6, 6,99, 6, 6, 6, 6, 6,99, 6, 6, 3, 6,
+ /*8*/ 2, 2, 2, 4, 2, 2, 2,99, 2, 2, 2, 2, 4, 6, 3,99,
+ /*9*/ 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 4, 4,
+ /*A*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 5, 5,
+ /*B*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 5, 5,
+ /*C*/ 2, 2, 2, 4, 2, 2, 2,99, 2, 2, 2, 2, 3,99, 3,99,
+ /*D*/ 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ /*E*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ /*F*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5
+};
+
+static const UINT8 cycles_63701[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ 99, 1,99,99, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /*1*/ 1, 1,99,99,99,99, 1, 1, 2, 2, 4, 1,99,99,99,99,
+ /*2*/ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ /*3*/ 1, 1, 3, 3, 1, 1, 4, 4, 4, 5, 1,10, 5, 7, 9,12,
+ /*4*/ 1,99,99, 1, 1,99, 1, 1, 1, 1, 1,99, 1, 1,99, 1,
+ /*5*/ 1,99,99, 1, 1,99, 1, 1, 1, 1, 1,99, 1, 1,99, 1,
+ /*6*/ 6, 7, 7, 6, 6, 7, 6, 6, 6, 6, 6, 5, 6, 4, 3, 5,
+ /*7*/ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 3, 5,
+ /*8*/ 2, 2, 2, 3, 2, 2, 2,99, 2, 2, 2, 2, 3, 5, 3,99,
+ /*9*/ 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4,
+ /*A*/ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ /*B*/ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 5, 5,
+ /*C*/ 2, 2, 2, 3, 2, 2, 2,99, 2, 2, 2, 2, 3,99, 3,99,
+ /*D*/ 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ /*E*/ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ /*F*/ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5
+};
+
+static const UINT8 cycles_nsc8105[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ 99,99, 2,99,99, 2,99, 2, 4, 2, 4, 2, 2, 2, 2, 2,
+ /*1*/ 2,99, 2,99,99, 2,99, 2,99,99, 2, 2,99,99,99,99,
+ /*2*/ 4, 4,99, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ /*3*/ 4, 4, 4, 4, 4, 4, 4, 4,99,99, 5,10,99, 9,99,12,
+ /*4*/ 2,99,99, 2, 2, 2,99, 2, 2, 2, 2,99, 2,99, 2, 2,
+ /*5*/ 2,99,99, 2, 2, 2,99, 2, 2, 2, 2,99, 2,99, 2, 2,
+ /*6*/ 7,99,99, 7, 7, 7,99, 7, 7, 7, 7,99, 7, 4, 7, 7,
+ /*7*/ 6,99,99, 6, 6, 6,99, 6, 6, 6, 6,99, 6, 3, 6, 6,
+ /*8*/ 2, 2, 2,99, 2, 2, 2,99, 2, 2, 2, 2, 3, 3, 8,99,
+ /*9*/ 3, 3, 3,99, 3, 3, 3, 4, 3, 3, 3, 3, 4, 4,99, 5,
+ /*A*/ 5, 5, 5,99, 5, 5, 5, 6, 5, 5, 5, 5, 6, 6, 8, 7,
+ /*B*/ 4, 4, 4,99, 4, 4, 4, 5, 4, 4, 4, 4, 5, 5, 9, 6,
+ /*C*/ 2, 2, 2,99, 2, 2, 2,99, 2, 2, 2, 2,99, 3,99,99,
+ /*D*/ 3, 3, 3,99, 3, 3, 3, 4, 3, 3, 3, 3,99, 4,99, 5,
+ /*E*/ 5, 5, 5,99, 5, 5, 5, 6, 5, 5, 5, 5, 5, 6,99, 7,
+ /*F*/ 4, 4, 4,99, 4, 4, 4, 5, 4, 4, 4, 4, 4, 5,99, 6
+};
+
+INLINE UINT32 RM16( UINT32 Addr )
+{
+ UINT32 result = RM(Addr) << 8;
+ return result | RM((Addr+1)&0xffff);
+}
+
+INLINE void WM16( UINT32 Addr, PAIR *p )
+{
+ WM( Addr, p->b.h );
+ WM( (Addr+1)&0xffff, p->b.l );
+}
+
+/* IRQ enter */
+static void ENTER_INTERRUPT(const char *message,UINT16 irq_vector)
+{
+ LOG((message, cpu_getactivecpu()));
+ if( m6800.wai_state & (M6800_WAI|M6800_SLP) )
+ {
+ if( m6800.wai_state & M6800_WAI )
+ m6800.extra_cycles += 4;
+ m6800.wai_state &= ~(M6800_WAI|M6800_SLP);
+ }
+ else
+ {
+ PUSHWORD(pPC);
+ PUSHWORD(pX);
+ PUSHBYTE(A);
+ PUSHBYTE(B);
+ PUSHBYTE(CC);
+ m6800.extra_cycles += 12;
+ }
+ SEI;
+ PCD = RM16( irq_vector );
+ CHANGE_PC();
+}
+
+static void m6800_check_irq2(void)
+{
+ if ((m6800.tcsr & (TCSR_EICI|TCSR_ICF)) == (TCSR_EICI|TCSR_ICF))
+ {
+ TAKE_ICI;
+ if( m6800.irq_callback )
+ (void)(*m6800.irq_callback)(M6800_TIN_LINE);
+ }
+ else if ((m6800.tcsr & (TCSR_EOCI|TCSR_OCF)) == (TCSR_EOCI|TCSR_OCF))
+ {
+ TAKE_OCI;
+ }
+ else if ((m6800.tcsr & (TCSR_ETOI|TCSR_TOF)) == (TCSR_ETOI|TCSR_TOF))
+ {
+ TAKE_TOI;
+ }
+ else if (((m6800.trcsr & (M6800_TRCSR_RIE|M6800_TRCSR_RDRF)) == (M6800_TRCSR_RIE|M6800_TRCSR_RDRF)) ||
+ ((m6800.trcsr & (M6800_TRCSR_RIE|M6800_TRCSR_ORFE)) == (M6800_TRCSR_RIE|M6800_TRCSR_ORFE)) ||
+ ((m6800.trcsr & (M6800_TRCSR_TIE|M6800_TRCSR_TDRE)) == (M6800_TRCSR_TIE|M6800_TRCSR_TDRE)))
+ {
+ TAKE_SCI;
+ }
+}
+
+/* check OCI or TOI */
+static void check_timer_event(void)
+{
+ /* OCI */
+ if( CTD >= OCD)
+ {
+ OCH++; // next IRQ point
+ m6800.tcsr |= TCSR_OCF;
+ m6800.pending_tcsr |= TCSR_OCF;
+ MODIFIED_tcsr;
+ if ( !(CC & 0x10) && (m6800.tcsr & TCSR_EOCI))
+ TAKE_OCI;
+ }
+ /* TOI */
+ if( CTD >= TOD)
+ {
+ TOH++; // next IRQ point
+#if 0
+ CLEANUP_conters;
+#endif
+ m6800.tcsr |= TCSR_TOF;
+ m6800.pending_tcsr |= TCSR_TOF;
+ MODIFIED_tcsr;
+ if ( !(CC & 0x10) && (m6800.tcsr & TCSR_ETOI))
+ TAKE_TOI;
+ }
+ /* set next event */
+ SET_TIMER_EVENT;
+}
+
+/* include the opcode prototypes and function pointer tables */
+#include "6800tbl.c"
+
+/* include the opcode functions */
+#include "6800ops.c"
+
+static void m6800_tx(int value)
+{
+ m6800.port2_data = (m6800.port2_data & 0xef) | (value << 4);
+
+ if(m6800.port2_ddr == 0xff)
+ io_write_byte_8(M6803_PORT2,m6800.port2_data);
+ else
+ io_write_byte_8(M6803_PORT2,(m6800.port2_data & m6800.port2_ddr)
+ | (io_read_byte_8(M6803_PORT2) & (m6800.port2_ddr ^ 0xff)));
+}
+
+static int m6800_rx(void)
+{
+ return (io_read_byte_8(M6803_PORT2) & M6800_PORT2_IO3) >> 3;
+}
+
+static TIMER_CALLBACK(m6800_tx_tick)
+{
+ int cpunum = param;
+
+ if (m6800.trcsr & M6800_TRCSR_TE)
+ {
+ // force Port 2 bit 4 as output
+ m6800.port2_ddr |= M6800_PORT2_IO4;
+
+ switch (m6800.txstate)
+ {
+ case M6800_TX_STATE_INIT:
+ m6800.tx = 1;
+ m6800.txbits++;
+
+ if (m6800.txbits == 10)
+ {
+ m6800.txstate = M6800_TX_STATE_READY;
+ m6800.txbits = M6800_SERIAL_START;
+ }
+ break;
+
+ case M6800_TX_STATE_READY:
+ switch (m6800.txbits)
+ {
+ case M6800_SERIAL_START:
+ if (m6800.trcsr & M6800_TRCSR_TDRE)
+ {
+ // transmit buffer is empty, send consecutive '1's
+ m6800.tx = 1;
+ }
+ else
+ {
+ // transmit buffer is full, send data
+
+ // load TDR to shift register
+ m6800.tsr = m6800.tdr;
+
+ // transmit buffer is empty, set TDRE flag
+ m6800.trcsr |= M6800_TRCSR_TDRE;
+
+ // send start bit '0'
+ m6800.tx = 0;
+
+ m6800.txbits++;
+ }
+ break;
+
+ case M6800_SERIAL_STOP:
+ // send stop bit '1'
+ m6800.tx = 1;
+
+ cpuintrf_push_context(cpunum);
+ CHECK_IRQ_LINES();
+ cpuintrf_pop_context();
+
+ m6800.txbits = M6800_SERIAL_START;
+ break;
+
+ default:
+ // send data bit '0' or '1'
+ m6800.tx = m6800.tsr & 0x01;
+
+ // shift transmit register
+ m6800.tsr >>= 1;
+
+ m6800.txbits++;
+ break;
+ }
+ break;
+ }
+ }
+
+ m6800_tx(m6800.tx);
+}
+
+static TIMER_CALLBACK(m6800_rx_tick)
+{
+ int cpunum = param;
+
+ if (m6800.trcsr & M6800_TRCSR_RE)
+ {
+ if (m6800.trcsr & M6800_TRCSR_WU)
+ {
+ // wait for 10 bits of '1'
+
+ if (m6800_rx() == 1)
+ {
+ m6800.rxbits++;
+
+ if (m6800.rxbits == 10)
+ {
+ m6800.trcsr &= ~M6800_TRCSR_WU;
+ m6800.rxbits = M6800_SERIAL_START;
+ }
+ }
+ else
+ {
+ m6800.rxbits = M6800_SERIAL_START;
+ }
+ }
+ else
+ {
+ // receive data
+
+ switch (m6800.rxbits)
+ {
+ case M6800_SERIAL_START:
+ if (m6800_rx() == 0)
+ {
+ // start bit found
+ m6800.rxbits++;
+ }
+ break;
+
+ case M6800_SERIAL_STOP:
+ if (m6800_rx() == 1)
+ {
+ if (m6800.trcsr & M6800_TRCSR_RDRF)
+ {
+ // overrun error
+
+ m6800.trcsr |= M6800_TRCSR_ORFE;
+
+ cpuintrf_push_context(cpunum);
+ CHECK_IRQ_LINES();
+ cpuintrf_pop_context();
+ }
+ else
+ {
+ if (!(m6800.trcsr & M6800_TRCSR_ORFE))
+ {
+ // transfer data into receive register
+ m6800.rdr = m6800.rsr;
+
+ // set RDRF flag
+ m6800.trcsr |= M6800_TRCSR_RDRF;
+
+ cpuintrf_push_context(cpunum);
+ CHECK_IRQ_LINES();
+ cpuintrf_pop_context();
+ }
+ }
+ }
+ else
+ {
+ // framing error
+
+ if (!(m6800.trcsr & M6800_TRCSR_ORFE))
+ {
+ // transfer unframed data into receive register
+ m6800.rdr = m6800.rsr;
+ }
+
+ m6800.trcsr |= M6800_TRCSR_ORFE;
+ m6800.trcsr &= ~M6800_TRCSR_RDRF;
+
+ cpuintrf_push_context(cpunum);
+ CHECK_IRQ_LINES();
+ cpuintrf_pop_context();
+ }
+
+ m6800.rxbits = M6800_SERIAL_START;
+ break;
+
+ default:
+ // shift receive register
+ m6800.rsr >>= 1;
+
+ // receive bit into register
+ m6800.rsr |= (m6800_rx() << 7);
+
+ m6800.rxbits++;
+ break;
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+static void state_register(const char *type, int index)
+{
+ state_save_register_item(type, index, m6800.ppc.w.l);
+ state_save_register_item(type, index, m6800.pc.w.l);
+ state_save_register_item(type, index, m6800.s.w.l);
+ state_save_register_item(type, index, m6800.x.w.l);
+ state_save_register_item(type, index, m6800.d.w.l);
+ state_save_register_item(type, index, m6800.cc);
+ state_save_register_item(type, index, m6800.wai_state);
+ state_save_register_item(type, index, m6800.nmi_state);
+ state_save_register_item_array(type, index, m6800.irq_state);
+ state_save_register_item(type, index, m6800.ic_eddge);
+
+ state_save_register_item(type, index, m6800.port1_ddr);
+ state_save_register_item(type, index, m6800.port2_ddr);
+ state_save_register_item(type, index, m6800.port3_ddr);
+ state_save_register_item(type, index, m6800.port4_ddr);
+ state_save_register_item(type, index, m6800.port1_data);
+ state_save_register_item(type, index, m6800.port2_data);
+ state_save_register_item(type, index, m6800.port3_data);
+ state_save_register_item(type, index, m6800.port4_data);
+ state_save_register_item(type, index, m6800.tcsr);
+ state_save_register_item(type, index, m6800.pending_tcsr);
+ state_save_register_item(type, index, m6800.irq2);
+ state_save_register_item(type, index, m6800.ram_ctrl);
+
+ state_save_register_item(type, index, m6800.counter.d);
+ state_save_register_item(type, index, m6800.output_compare.d);
+ state_save_register_item(type, index, m6800.input_capture);
+ state_save_register_item(type, index, m6800.timer_over.d);
+
+ state_save_register_item(type, index, m6800.clock);
+ state_save_register_item(type, index, m6800.trcsr);
+ state_save_register_item(type, index, m6800.rmcr);
+ state_save_register_item(type, index, m6800.rdr);
+ state_save_register_item(type, index, m6800.tdr);
+ state_save_register_item(type, index, m6800.rsr);
+ state_save_register_item(type, index, m6800.tsr);
+ state_save_register_item(type, index, m6800.rxbits);
+ state_save_register_item(type, index, m6800.txbits);
+ state_save_register_item(type, index, m6800.txstate);
+ state_save_register_item(type, index, m6800.trcsr_read);
+ state_save_register_item(type, index, m6800.tx);
+}
+
+static void m6800_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+// m6800.subtype = SUBTYPE_M6800;
+ m6800.insn = m6800_insn;
+ m6800.cycles = cycles_6800;
+ m6800.irq_callback = irqcallback;
+ state_register("m6800", index);
+}
+
+static void m6800_reset(void)
+{
+ SEI; /* IRQ disabled */
+ PCD = RM16( 0xfffe );
+ CHANGE_PC();
+
+ m6800.wai_state = 0;
+ m6800.nmi_state = 0;
+ m6800.irq_state[M6800_IRQ_LINE] = 0;
+ m6800.irq_state[M6800_TIN_LINE] = 0;
+ m6800.ic_eddge = 0;
+
+ m6800.port1_ddr = 0x00;
+ m6800.port2_ddr = 0x00;
+ /* TODO: on reset port 2 should be read to determine the operating mode (bits 0-2) */
+ m6800.tcsr = 0x00;
+ m6800.pending_tcsr = 0x00;
+ m6800.irq2 = 0;
+ CTD = 0x0000;
+ OCD = 0xffff;
+ TOD = 0xffff;
+ m6800.ram_ctrl |= 0x40;
+
+ m6800.trcsr = M6800_TRCSR_TDRE;
+ m6800.rmcr = 0;
+ if (m6800_rx_timer) timer_enable(m6800_rx_timer, 0);
+ if (m6800_tx_timer) timer_enable(m6800_tx_timer, 0);
+ m6800.txstate = M6800_TX_STATE_INIT;
+ m6800.txbits = m6800.rxbits = 0;
+ m6800.trcsr_read = 0;
+}
+
+/****************************************************************************
+ * Shut down CPU emulation
+ ****************************************************************************/
+static void m6800_exit(void)
+{
+ /* nothing to do */
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void m6800_get_context(void *dst)
+{
+ if( dst )
+ *(m6800_Regs*)dst = m6800;
+}
+
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void m6800_set_context(void *src)
+{
+ if( src )
+ m6800 = *(m6800_Regs*)src;
+ CHANGE_PC();
+ CHECK_IRQ_LINES(); /* HJB 990417 */
+}
+
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m6800.nmi_state == state) return;
+ LOG(("M6800#%d set_nmi_line %d \n", cpu_getactivecpu(), state));
+ m6800.nmi_state = state;
+ if (state == CLEAR_LINE) return;
+
+ /* NMI */
+ ENTER_INTERRUPT("M6800#%d take NMI\n",0xfffc);
+ }
+ else
+ {
+ int eddge;
+
+ if (m6800.irq_state[irqline] == state) return;
+ LOG(("M6800#%d set_irq_line %d,%d\n", cpu_getactivecpu(), irqline, state));
+ m6800.irq_state[irqline] = state;
+
+ switch(irqline)
+ {
+ case M6800_IRQ_LINE:
+ if (state == CLEAR_LINE) return;
+ break;
+ case M6800_TIN_LINE:
+ eddge = (state == CLEAR_LINE ) ? 2 : 0;
+ if( ((m6800.tcsr&TCSR_IEDG) ^ (state==CLEAR_LINE ? TCSR_IEDG : 0))==0 )
+ return;
+ /* active edge in */
+ m6800.tcsr |= TCSR_ICF;
+ m6800.pending_tcsr |= TCSR_ICF;
+ m6800.input_capture = CT;
+ MODIFIED_tcsr;
+ if( !(CC & 0x10) )
+ m6800_check_irq2();
+ break;
+ default:
+ return;
+ }
+ CHECK_IRQ_LINES(); /* HJB 990417 */
+ }
+}
+
+/****************************************************************************
+ * Execute cycles CPU cycles. Return number of cycles really executed
+ ****************************************************************************/
+static int m6800_execute(int cycles)
+{
+ UINT8 ireg;
+ m6800_ICount = cycles;
+
+ CLEANUP_conters;
+ INCREMENT_COUNTER(m6800.extra_cycles);
+ m6800.extra_cycles = 0;
+
+ do
+ {
+ if( m6800.wai_state & M6800_WAI )
+ {
+ EAT_CYCLES;
+ }
+ else
+ {
+ pPPC = pPC;
+ CALL_MAME_DEBUG;
+ ireg=M_RDOP(PCD);
+ PC++;
+
+ switch( ireg )
+ {
+ case 0x00: illegal(); break;
+ case 0x01: nop(); break;
+ case 0x02: illegal(); break;
+ case 0x03: illegal(); break;
+ case 0x04: illegal(); break;
+ case 0x05: illegal(); break;
+ case 0x06: tap(); break;
+ case 0x07: tpa(); break;
+ case 0x08: inx(); break;
+ case 0x09: dex(); break;
+ case 0x0A: CLV; break;
+ case 0x0B: SEV; break;
+ case 0x0C: CLC; break;
+ case 0x0D: SEC; break;
+ case 0x0E: cli(); break;
+ case 0x0F: sei(); break;
+ case 0x10: sba(); break;
+ case 0x11: cba(); break;
+ case 0x12: illegal(); break;
+ case 0x13: illegal(); break;
+ case 0x14: illegal(); break;
+ case 0x15: illegal(); break;
+ case 0x16: tab(); break;
+ case 0x17: tba(); break;
+ case 0x18: illegal(); break;
+ case 0x19: daa(); break;
+ case 0x1a: illegal(); break;
+ case 0x1b: aba(); break;
+ case 0x1c: illegal(); break;
+ case 0x1d: illegal(); break;
+ case 0x1e: illegal(); break;
+ case 0x1f: illegal(); break;
+ case 0x20: bra(); break;
+ case 0x21: brn(); break;
+ case 0x22: bhi(); break;
+ case 0x23: bls(); break;
+ case 0x24: bcc(); break;
+ case 0x25: bcs(); break;
+ case 0x26: bne(); break;
+ case 0x27: beq(); break;
+ case 0x28: bvc(); break;
+ case 0x29: bvs(); break;
+ case 0x2a: bpl(); break;
+ case 0x2b: bmi(); break;
+ case 0x2c: bge(); break;
+ case 0x2d: blt(); break;
+ case 0x2e: bgt(); break;
+ case 0x2f: ble(); break;
+ case 0x30: tsx(); break;
+ case 0x31: ins(); break;
+ case 0x32: pula(); break;
+ case 0x33: pulb(); break;
+ case 0x34: des(); break;
+ case 0x35: txs(); break;
+ case 0x36: psha(); break;
+ case 0x37: pshb(); break;
+ case 0x38: illegal(); break;
+ case 0x39: rts(); break;
+ case 0x3a: illegal(); break;
+ case 0x3b: rti(); break;
+ case 0x3c: illegal(); break;
+ case 0x3d: illegal(); break;
+ case 0x3e: wai(); break;
+ case 0x3f: swi(); break;
+ case 0x40: nega(); break;
+ case 0x41: illegal(); break;
+ case 0x42: illegal(); break;
+ case 0x43: coma(); break;
+ case 0x44: lsra(); break;
+ case 0x45: illegal(); break;
+ case 0x46: rora(); break;
+ case 0x47: asra(); break;
+ case 0x48: asla(); break;
+ case 0x49: rola(); break;
+ case 0x4a: deca(); break;
+ case 0x4b: illegal(); break;
+ case 0x4c: inca(); break;
+ case 0x4d: tsta(); break;
+ case 0x4e: illegal(); break;
+ case 0x4f: clra(); break;
+ case 0x50: negb(); break;
+ case 0x51: illegal(); break;
+ case 0x52: illegal(); break;
+ case 0x53: comb(); break;
+ case 0x54: lsrb(); break;
+ case 0x55: illegal(); break;
+ case 0x56: rorb(); break;
+ case 0x57: asrb(); break;
+ case 0x58: aslb(); break;
+ case 0x59: rolb(); break;
+ case 0x5a: decb(); break;
+ case 0x5b: illegal(); break;
+ case 0x5c: incb(); break;
+ case 0x5d: tstb(); break;
+ case 0x5e: illegal(); break;
+ case 0x5f: clrb(); break;
+ case 0x60: neg_ix(); break;
+ case 0x61: illegal(); break;
+ case 0x62: illegal(); break;
+ case 0x63: com_ix(); break;
+ case 0x64: lsr_ix(); break;
+ case 0x65: illegal(); break;
+ case 0x66: ror_ix(); break;
+ case 0x67: asr_ix(); break;
+ case 0x68: asl_ix(); break;
+ case 0x69: rol_ix(); break;
+ case 0x6a: dec_ix(); break;
+ case 0x6b: illegal(); break;
+ case 0x6c: inc_ix(); break;
+ case 0x6d: tst_ix(); break;
+ case 0x6e: jmp_ix(); break;
+ case 0x6f: clr_ix(); break;
+ case 0x70: neg_ex(); break;
+ case 0x71: illegal(); break;
+ case 0x72: illegal(); break;
+ case 0x73: com_ex(); break;
+ case 0x74: lsr_ex(); break;
+ case 0x75: illegal(); break;
+ case 0x76: ror_ex(); break;
+ case 0x77: asr_ex(); break;
+ case 0x78: asl_ex(); break;
+ case 0x79: rol_ex(); break;
+ case 0x7a: dec_ex(); break;
+ case 0x7b: illegal(); break;
+ case 0x7c: inc_ex(); break;
+ case 0x7d: tst_ex(); break;
+ case 0x7e: jmp_ex(); break;
+ case 0x7f: clr_ex(); break;
+ case 0x80: suba_im(); break;
+ case 0x81: cmpa_im(); break;
+ case 0x82: sbca_im(); break;
+ case 0x83: illegal(); break;
+ case 0x84: anda_im(); break;
+ case 0x85: bita_im(); break;
+ case 0x86: lda_im(); break;
+ case 0x87: sta_im(); break;
+ case 0x88: eora_im(); break;
+ case 0x89: adca_im(); break;
+ case 0x8a: ora_im(); break;
+ case 0x8b: adda_im(); break;
+ case 0x8c: cmpx_im(); break;
+ case 0x8d: bsr(); break;
+ case 0x8e: lds_im(); break;
+ case 0x8f: sts_im(); /* orthogonality */ break;
+ case 0x90: suba_di(); break;
+ case 0x91: cmpa_di(); break;
+ case 0x92: sbca_di(); break;
+ case 0x93: illegal(); break;
+ case 0x94: anda_di(); break;
+ case 0x95: bita_di(); break;
+ case 0x96: lda_di(); break;
+ case 0x97: sta_di(); break;
+ case 0x98: eora_di(); break;
+ case 0x99: adca_di(); break;
+ case 0x9a: ora_di(); break;
+ case 0x9b: adda_di(); break;
+ case 0x9c: cmpx_di(); break;
+ case 0x9d: jsr_di(); break;
+ case 0x9e: lds_di(); break;
+ case 0x9f: sts_di(); break;
+ case 0xa0: suba_ix(); break;
+ case 0xa1: cmpa_ix(); break;
+ case 0xa2: sbca_ix(); break;
+ case 0xa3: illegal(); break;
+ case 0xa4: anda_ix(); break;
+ case 0xa5: bita_ix(); break;
+ case 0xa6: lda_ix(); break;
+ case 0xa7: sta_ix(); break;
+ case 0xa8: eora_ix(); break;
+ case 0xa9: adca_ix(); break;
+ case 0xaa: ora_ix(); break;
+ case 0xab: adda_ix(); break;
+ case 0xac: cmpx_ix(); break;
+ case 0xad: jsr_ix(); break;
+ case 0xae: lds_ix(); break;
+ case 0xaf: sts_ix(); break;
+ case 0xb0: suba_ex(); break;
+ case 0xb1: cmpa_ex(); break;
+ case 0xb2: sbca_ex(); break;
+ case 0xb3: illegal(); break;
+ case 0xb4: anda_ex(); break;
+ case 0xb5: bita_ex(); break;
+ case 0xb6: lda_ex(); break;
+ case 0xb7: sta_ex(); break;
+ case 0xb8: eora_ex(); break;
+ case 0xb9: adca_ex(); break;
+ case 0xba: ora_ex(); break;
+ case 0xbb: adda_ex(); break;
+ case 0xbc: cmpx_ex(); break;
+ case 0xbd: jsr_ex(); break;
+ case 0xbe: lds_ex(); break;
+ case 0xbf: sts_ex(); break;
+ case 0xc0: subb_im(); break;
+ case 0xc1: cmpb_im(); break;
+ case 0xc2: sbcb_im(); break;
+ case 0xc3: illegal(); break;
+ case 0xc4: andb_im(); break;
+ case 0xc5: bitb_im(); break;
+ case 0xc6: ldb_im(); break;
+ case 0xc7: stb_im(); break;
+ case 0xc8: eorb_im(); break;
+ case 0xc9: adcb_im(); break;
+ case 0xca: orb_im(); break;
+ case 0xcb: addb_im(); break;
+ case 0xcc: illegal(); break;
+ case 0xcd: illegal(); break;
+ case 0xce: ldx_im(); break;
+ case 0xcf: stx_im(); break;
+ case 0xd0: subb_di(); break;
+ case 0xd1: cmpb_di(); break;
+ case 0xd2: sbcb_di(); break;
+ case 0xd3: illegal(); break;
+ case 0xd4: andb_di(); break;
+ case 0xd5: bitb_di(); break;
+ case 0xd6: ldb_di(); break;
+ case 0xd7: stb_di(); break;
+ case 0xd8: eorb_di(); break;
+ case 0xd9: adcb_di(); break;
+ case 0xda: orb_di(); break;
+ case 0xdb: addb_di(); break;
+ case 0xdc: illegal(); break;
+ case 0xdd: illegal(); break;
+ case 0xde: ldx_di(); break;
+ case 0xdf: stx_di(); break;
+ case 0xe0: subb_ix(); break;
+ case 0xe1: cmpb_ix(); break;
+ case 0xe2: sbcb_ix(); break;
+ case 0xe3: illegal(); break;
+ case 0xe4: andb_ix(); break;
+ case 0xe5: bitb_ix(); break;
+ case 0xe6: ldb_ix(); break;
+ case 0xe7: stb_ix(); break;
+ case 0xe8: eorb_ix(); break;
+ case 0xe9: adcb_ix(); break;
+ case 0xea: orb_ix(); break;
+ case 0xeb: addb_ix(); break;
+ case 0xec: illegal(); break;
+ case 0xed: illegal(); break;
+ case 0xee: ldx_ix(); break;
+ case 0xef: stx_ix(); break;
+ case 0xf0: subb_ex(); break;
+ case 0xf1: cmpb_ex(); break;
+ case 0xf2: sbcb_ex(); break;
+ case 0xf3: illegal(); break;
+ case 0xf4: andb_ex(); break;
+ case 0xf5: bitb_ex(); break;
+ case 0xf6: ldb_ex(); break;
+ case 0xf7: stb_ex(); break;
+ case 0xf8: eorb_ex(); break;
+ case 0xf9: adcb_ex(); break;
+ case 0xfa: orb_ex(); break;
+ case 0xfb: addb_ex(); break;
+ case 0xfc: addx_ex(); break;
+ case 0xfd: illegal(); break;
+ case 0xfe: ldx_ex(); break;
+ case 0xff: stx_ex(); break;
+ }
+ INCREMENT_COUNTER(cycles_6800[ireg]);
+ }
+ } while( m6800_ICount>0 );
+
+ INCREMENT_COUNTER(m6800.extra_cycles);
+ m6800.extra_cycles = 0;
+
+ return cycles - m6800_ICount;
+}
+
+/****************************************************************************
+ * M6801 almost (fully?) equal to the M6803
+ ****************************************************************************/
+#if (HAS_M6801)
+static void m6801_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+// m6800.subtype = SUBTYPE_M6801;
+ m6800.insn = m6803_insn;
+ m6800.cycles = cycles_6803;
+ m6800.irq_callback = irqcallback;
+
+ m6800.clock = clock;
+ m6800_rx_timer = timer_alloc(m6800_rx_tick);
+ m6800_tx_timer = timer_alloc(m6800_tx_tick);
+
+ state_register("m6801", index);
+}
+#endif
+
+/****************************************************************************
+ * M6802 almost (fully?) equal to the M6800
+ ****************************************************************************/
+#if (HAS_M6802)
+static void m6802_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+// m6800.subtype = SUBTYPE_M6802;
+ m6800.insn = m6800_insn;
+ m6800.cycles = cycles_6800;
+ m6800.irq_callback = irqcallback;
+ state_register("m6802", index);
+}
+#endif
+
+/****************************************************************************
+ * M6803 almost (fully?) equal to the M6801
+ ****************************************************************************/
+#if (HAS_M6803)
+void m6803_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+// m6800.subtype = SUBTYPE_M6803;
+ m6800.insn = m6803_insn;
+ m6800.cycles = cycles_6803;
+ m6800.irq_callback = irqcallback;
+
+ m6800.clock = clock;
+ m6800_rx_timer = timer_alloc(m6800_rx_tick);
+ m6800_tx_timer = timer_alloc(m6800_tx_tick);
+
+ state_register("m6803", index);
+}
+#endif
+
+/****************************************************************************
+ * Execute cycles CPU cycles. Return number of cycles really executed
+ ****************************************************************************/
+#if (HAS_M6803||HAS_M6801)
+static int m6803_execute(int cycles)
+{
+ UINT8 ireg;
+ m6800_ICount = cycles;
+
+ CLEANUP_conters;
+ INCREMENT_COUNTER(m6803.extra_cycles);
+ m6803.extra_cycles = 0;
+
+ do
+ {
+ if( m6803.wai_state & M6800_WAI )
+ {
+ EAT_CYCLES;
+ }
+ else
+ {
+ pPPC = pPC;
+ CALL_MAME_DEBUG;
+ ireg=M_RDOP(PCD);
+ PC++;
+
+ switch( ireg )
+ {
+ case 0x00: illegal(); break;
+ case 0x01: nop(); break;
+ case 0x02: illegal(); break;
+ case 0x03: illegal(); break;
+ case 0x04: lsrd(); /* 6803 only */; break;
+ case 0x05: asld(); /* 6803 only */; break;
+ case 0x06: tap(); break;
+ case 0x07: tpa(); break;
+ case 0x08: inx(); break;
+ case 0x09: dex(); break;
+ case 0x0A: CLV; break;
+ case 0x0B: SEV; break;
+ case 0x0C: CLC; break;
+ case 0x0D: SEC; break;
+ case 0x0E: cli(); break;
+ case 0x0F: sei(); break;
+ case 0x10: sba(); break;
+ case 0x11: cba(); break;
+ case 0x12: illegal(); break;
+ case 0x13: illegal(); break;
+ case 0x14: illegal(); break;
+ case 0x15: illegal(); break;
+ case 0x16: tab(); break;
+ case 0x17: tba(); break;
+ case 0x18: illegal(); break;
+ case 0x19: daa(); break;
+ case 0x1a: illegal(); break;
+ case 0x1b: aba(); break;
+ case 0x1c: illegal(); break;
+ case 0x1d: illegal(); break;
+ case 0x1e: illegal(); break;
+ case 0x1f: illegal(); break;
+ case 0x20: bra(); break;
+ case 0x21: brn(); break;
+ case 0x22: bhi(); break;
+ case 0x23: bls(); break;
+ case 0x24: bcc(); break;
+ case 0x25: bcs(); break;
+ case 0x26: bne(); break;
+ case 0x27: beq(); break;
+ case 0x28: bvc(); break;
+ case 0x29: bvs(); break;
+ case 0x2a: bpl(); break;
+ case 0x2b: bmi(); break;
+ case 0x2c: bge(); break;
+ case 0x2d: blt(); break;
+ case 0x2e: bgt(); break;
+ case 0x2f: ble(); break;
+ case 0x30: tsx(); break;
+ case 0x31: ins(); break;
+ case 0x32: pula(); break;
+ case 0x33: pulb(); break;
+ case 0x34: des(); break;
+ case 0x35: txs(); break;
+ case 0x36: psha(); break;
+ case 0x37: pshb(); break;
+ case 0x38: pulx(); /* 6803 only */ break;
+ case 0x39: rts(); break;
+ case 0x3a: abx(); /* 6803 only */ break;
+ case 0x3b: rti(); break;
+ case 0x3c: pshx(); /* 6803 only */ break;
+ case 0x3d: mul(); /* 6803 only */ break;
+ case 0x3e: wai(); break;
+ case 0x3f: swi(); break;
+ case 0x40: nega(); break;
+ case 0x41: illegal(); break;
+ case 0x42: illegal(); break;
+ case 0x43: coma(); break;
+ case 0x44: lsra(); break;
+ case 0x45: illegal(); break;
+ case 0x46: rora(); break;
+ case 0x47: asra(); break;
+ case 0x48: asla(); break;
+ case 0x49: rola(); break;
+ case 0x4a: deca(); break;
+ case 0x4b: illegal(); break;
+ case 0x4c: inca(); break;
+ case 0x4d: tsta(); break;
+ case 0x4e: illegal(); break;
+ case 0x4f: clra(); break;
+ case 0x50: negb(); break;
+ case 0x51: illegal(); break;
+ case 0x52: illegal(); break;
+ case 0x53: comb(); break;
+ case 0x54: lsrb(); break;
+ case 0x55: illegal(); break;
+ case 0x56: rorb(); break;
+ case 0x57: asrb(); break;
+ case 0x58: aslb(); break;
+ case 0x59: rolb(); break;
+ case 0x5a: decb(); break;
+ case 0x5b: illegal(); break;
+ case 0x5c: incb(); break;
+ case 0x5d: tstb(); break;
+ case 0x5e: illegal(); break;
+ case 0x5f: clrb(); break;
+ case 0x60: neg_ix(); break;
+ case 0x61: illegal(); break;
+ case 0x62: illegal(); break;
+ case 0x63: com_ix(); break;
+ case 0x64: lsr_ix(); break;
+ case 0x65: illegal(); break;
+ case 0x66: ror_ix(); break;
+ case 0x67: asr_ix(); break;
+ case 0x68: asl_ix(); break;
+ case 0x69: rol_ix(); break;
+ case 0x6a: dec_ix(); break;
+ case 0x6b: illegal(); break;
+ case 0x6c: inc_ix(); break;
+ case 0x6d: tst_ix(); break;
+ case 0x6e: jmp_ix(); break;
+ case 0x6f: clr_ix(); break;
+ case 0x70: neg_ex(); break;
+ case 0x71: illegal(); break;
+ case 0x72: illegal(); break;
+ case 0x73: com_ex(); break;
+ case 0x74: lsr_ex(); break;
+ case 0x75: illegal(); break;
+ case 0x76: ror_ex(); break;
+ case 0x77: asr_ex(); break;
+ case 0x78: asl_ex(); break;
+ case 0x79: rol_ex(); break;
+ case 0x7a: dec_ex(); break;
+ case 0x7b: illegal(); break;
+ case 0x7c: inc_ex(); break;
+ case 0x7d: tst_ex(); break;
+ case 0x7e: jmp_ex(); break;
+ case 0x7f: clr_ex(); break;
+ case 0x80: suba_im(); break;
+ case 0x81: cmpa_im(); break;
+ case 0x82: sbca_im(); break;
+ case 0x83: subd_im(); /* 6803 only */ break;
+ case 0x84: anda_im(); break;
+ case 0x85: bita_im(); break;
+ case 0x86: lda_im(); break;
+ case 0x87: sta_im(); break;
+ case 0x88: eora_im(); break;
+ case 0x89: adca_im(); break;
+ case 0x8a: ora_im(); break;
+ case 0x8b: adda_im(); break;
+ case 0x8c: cpx_im(); /* 6803 difference */ break;
+ case 0x8d: bsr(); break;
+ case 0x8e: lds_im(); break;
+ case 0x8f: sts_im(); /* orthogonality */ break;
+ case 0x90: suba_di(); break;
+ case 0x91: cmpa_di(); break;
+ case 0x92: sbca_di(); break;
+ case 0x93: subd_di(); /* 6803 only */ break;
+ case 0x94: anda_di(); break;
+ case 0x95: bita_di(); break;
+ case 0x96: lda_di(); break;
+ case 0x97: sta_di(); break;
+ case 0x98: eora_di(); break;
+ case 0x99: adca_di(); break;
+ case 0x9a: ora_di(); break;
+ case 0x9b: adda_di(); break;
+ case 0x9c: cpx_di(); /* 6803 difference */ break;
+ case 0x9d: jsr_di(); break;
+ case 0x9e: lds_di(); break;
+ case 0x9f: sts_di(); break;
+ case 0xa0: suba_ix(); break;
+ case 0xa1: cmpa_ix(); break;
+ case 0xa2: sbca_ix(); break;
+ case 0xa3: subd_ix(); /* 6803 only */ break;
+ case 0xa4: anda_ix(); break;
+ case 0xa5: bita_ix(); break;
+ case 0xa6: lda_ix(); break;
+ case 0xa7: sta_ix(); break;
+ case 0xa8: eora_ix(); break;
+ case 0xa9: adca_ix(); break;
+ case 0xaa: ora_ix(); break;
+ case 0xab: adda_ix(); break;
+ case 0xac: cpx_ix(); /* 6803 difference */ break;
+ case 0xad: jsr_ix(); break;
+ case 0xae: lds_ix(); break;
+ case 0xaf: sts_ix(); break;
+ case 0xb0: suba_ex(); break;
+ case 0xb1: cmpa_ex(); break;
+ case 0xb2: sbca_ex(); break;
+ case 0xb3: subd_ex(); /* 6803 only */ break;
+ case 0xb4: anda_ex(); break;
+ case 0xb5: bita_ex(); break;
+ case 0xb6: lda_ex(); break;
+ case 0xb7: sta_ex(); break;
+ case 0xb8: eora_ex(); break;
+ case 0xb9: adca_ex(); break;
+ case 0xba: ora_ex(); break;
+ case 0xbb: adda_ex(); break;
+ case 0xbc: cpx_ex(); /* 6803 difference */ break;
+ case 0xbd: jsr_ex(); break;
+ case 0xbe: lds_ex(); break;
+ case 0xbf: sts_ex(); break;
+ case 0xc0: subb_im(); break;
+ case 0xc1: cmpb_im(); break;
+ case 0xc2: sbcb_im(); break;
+ case 0xc3: addd_im(); /* 6803 only */ break;
+ case 0xc4: andb_im(); break;
+ case 0xc5: bitb_im(); break;
+ case 0xc6: ldb_im(); break;
+ case 0xc7: stb_im(); break;
+ case 0xc8: eorb_im(); break;
+ case 0xc9: adcb_im(); break;
+ case 0xca: orb_im(); break;
+ case 0xcb: addb_im(); break;
+ case 0xcc: ldd_im(); /* 6803 only */ break;
+ case 0xcd: std_im(); /* 6803 only -- orthogonality */ break;
+ case 0xce: ldx_im(); break;
+ case 0xcf: stx_im(); break;
+ case 0xd0: subb_di(); break;
+ case 0xd1: cmpb_di(); break;
+ case 0xd2: sbcb_di(); break;
+ case 0xd3: addd_di(); /* 6803 only */ break;
+ case 0xd4: andb_di(); break;
+ case 0xd5: bitb_di(); break;
+ case 0xd6: ldb_di(); break;
+ case 0xd7: stb_di(); break;
+ case 0xd8: eorb_di(); break;
+ case 0xd9: adcb_di(); break;
+ case 0xda: orb_di(); break;
+ case 0xdb: addb_di(); break;
+ case 0xdc: ldd_di(); /* 6803 only */ break;
+ case 0xdd: std_di(); /* 6803 only */ break;
+ case 0xde: ldx_di(); break;
+ case 0xdf: stx_di(); break;
+ case 0xe0: subb_ix(); break;
+ case 0xe1: cmpb_ix(); break;
+ case 0xe2: sbcb_ix(); break;
+ case 0xe3: addd_ix(); /* 6803 only */ break;
+ case 0xe4: andb_ix(); break;
+ case 0xe5: bitb_ix(); break;
+ case 0xe6: ldb_ix(); break;
+ case 0xe7: stb_ix(); break;
+ case 0xe8: eorb_ix(); break;
+ case 0xe9: adcb_ix(); break;
+ case 0xea: orb_ix(); break;
+ case 0xeb: addb_ix(); break;
+ case 0xec: ldd_ix(); /* 6803 only */ break;
+ case 0xed: std_ix(); /* 6803 only */ break;
+ case 0xee: ldx_ix(); break;
+ case 0xef: stx_ix(); break;
+ case 0xf0: subb_ex(); break;
+ case 0xf1: cmpb_ex(); break;
+ case 0xf2: sbcb_ex(); break;
+ case 0xf3: addd_ex(); /* 6803 only */ break;
+ case 0xf4: andb_ex(); break;
+ case 0xf5: bitb_ex(); break;
+ case 0xf6: ldb_ex(); break;
+ case 0xf7: stb_ex(); break;
+ case 0xf8: eorb_ex(); break;
+ case 0xf9: adcb_ex(); break;
+ case 0xfa: orb_ex(); break;
+ case 0xfb: addb_ex(); break;
+ case 0xfc: ldd_ex(); /* 6803 only */ break;
+ case 0xfd: std_ex(); /* 6803 only */ break;
+ case 0xfe: ldx_ex(); break;
+ case 0xff: stx_ex(); break;
+ }
+ INCREMENT_COUNTER(cycles_6803[ireg]);
+ }
+ } while( m6800_ICount>0 );
+
+ INCREMENT_COUNTER(m6803.extra_cycles);
+ m6803.extra_cycles = 0;
+
+ return cycles - m6800_ICount;
+}
+#endif
+
+#if (HAS_M6803)
+
+static READ8_HANDLER( m6803_internal_registers_r );
+static WRITE8_HANDLER( m6803_internal_registers_w );
+
+static ADDRESS_MAP_START(m6803_mem, ADDRESS_SPACE_PROGRAM, 8)
+ AM_RANGE(0x0000, 0x001f) AM_READWRITE(m6803_internal_registers_r, m6803_internal_registers_w)
+ AM_RANGE(0x0020, 0x007f) AM_NOP /* unused */
+ AM_RANGE(0x0080, 0x00ff) AM_RAM /* 6803 internal RAM */
+ADDRESS_MAP_END
+
+#endif
+
+/****************************************************************************
+ * M6808 almost (fully?) equal to the M6800
+ ****************************************************************************/
+#if (HAS_M6808)
+static void m6808_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+// m6800.subtype = SUBTYPE_M6808;
+ m6800.insn = m6800_insn;
+ m6800.cycles = cycles_6800;
+ m6800.irq_callback = irqcallback;
+ state_register("m6808", index);
+}
+#endif
+
+/****************************************************************************
+ * HD63701 similiar to the M6800
+ ****************************************************************************/
+#if (HAS_HD63701)
+
+static void hd63701_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+// m6800.subtype = SUBTYPE_HD63701;
+ m6800.insn = hd63701_insn;
+ m6800.cycles = cycles_63701;
+ m6800.irq_callback = irqcallback;
+
+ m6800.clock = clock;
+ m6800_rx_timer = timer_alloc(m6800_rx_tick);
+ m6800_tx_timer = timer_alloc(m6800_tx_tick);
+
+ state_register("hd63701", index);
+}
+/****************************************************************************
+ * Execute cycles CPU cycles. Return number of cycles really executed
+ ****************************************************************************/
+static int hd63701_execute(int cycles)
+{
+ UINT8 ireg;
+ m6800_ICount = cycles;
+
+ CLEANUP_conters;
+ INCREMENT_COUNTER(hd63701.extra_cycles);
+ hd63701.extra_cycles = 0;
+
+ do
+ {
+ if( hd63701.wai_state & (HD63701_WAI|HD63701_SLP) )
+ {
+ EAT_CYCLES;
+ }
+ else
+ {
+ pPPC = pPC;
+ CALL_MAME_DEBUG;
+ ireg=M_RDOP(PCD);
+ PC++;
+
+ switch( ireg )
+ {
+ case 0x00: trap(); break;
+ case 0x01: nop(); break;
+ case 0x02: trap(); break;
+ case 0x03: trap(); break;
+ case 0x04: lsrd(); /* 6803 only */; break;
+ case 0x05: asld(); /* 6803 only */; break;
+ case 0x06: tap(); break;
+ case 0x07: tpa(); break;
+ case 0x08: inx(); break;
+ case 0x09: dex(); break;
+ case 0x0A: CLV; break;
+ case 0x0B: SEV; break;
+ case 0x0C: CLC; break;
+ case 0x0D: SEC; break;
+ case 0x0E: cli(); break;
+ case 0x0F: sei(); break;
+ case 0x10: sba(); break;
+ case 0x11: cba(); break;
+ case 0x12: undoc1(); break;
+ case 0x13: undoc2(); break;
+ case 0x14: trap(); break;
+ case 0x15: trap(); break;
+ case 0x16: tab(); break;
+ case 0x17: tba(); break;
+ case 0x18: xgdx(); /* HD63701YO only */; break;
+ case 0x19: daa(); break;
+ case 0x1a: slp(); break;
+ case 0x1b: aba(); break;
+ case 0x1c: trap(); break;
+ case 0x1d: trap(); break;
+ case 0x1e: trap(); break;
+ case 0x1f: trap(); break;
+ case 0x20: bra(); break;
+ case 0x21: brn(); break;
+ case 0x22: bhi(); break;
+ case 0x23: bls(); break;
+ case 0x24: bcc(); break;
+ case 0x25: bcs(); break;
+ case 0x26: bne(); break;
+ case 0x27: beq(); break;
+ case 0x28: bvc(); break;
+ case 0x29: bvs(); break;
+ case 0x2a: bpl(); break;
+ case 0x2b: bmi(); break;
+ case 0x2c: bge(); break;
+ case 0x2d: blt(); break;
+ case 0x2e: bgt(); break;
+ case 0x2f: ble(); break;
+ case 0x30: tsx(); break;
+ case 0x31: ins(); break;
+ case 0x32: pula(); break;
+ case 0x33: pulb(); break;
+ case 0x34: des(); break;
+ case 0x35: txs(); break;
+ case 0x36: psha(); break;
+ case 0x37: pshb(); break;
+ case 0x38: pulx(); /* 6803 only */ break;
+ case 0x39: rts(); break;
+ case 0x3a: abx(); /* 6803 only */ break;
+ case 0x3b: rti(); break;
+ case 0x3c: pshx(); /* 6803 only */ break;
+ case 0x3d: mul(); /* 6803 only */ break;
+ case 0x3e: wai(); break;
+ case 0x3f: swi(); break;
+ case 0x40: nega(); break;
+ case 0x41: trap(); break;
+ case 0x42: trap(); break;
+ case 0x43: coma(); break;
+ case 0x44: lsra(); break;
+ case 0x45: trap(); break;
+ case 0x46: rora(); break;
+ case 0x47: asra(); break;
+ case 0x48: asla(); break;
+ case 0x49: rola(); break;
+ case 0x4a: deca(); break;
+ case 0x4b: trap(); break;
+ case 0x4c: inca(); break;
+ case 0x4d: tsta(); break;
+ case 0x4e: trap(); break;
+ case 0x4f: clra(); break;
+ case 0x50: negb(); break;
+ case 0x51: trap(); break;
+ case 0x52: trap(); break;
+ case 0x53: comb(); break;
+ case 0x54: lsrb(); break;
+ case 0x55: trap(); break;
+ case 0x56: rorb(); break;
+ case 0x57: asrb(); break;
+ case 0x58: aslb(); break;
+ case 0x59: rolb(); break;
+ case 0x5a: decb(); break;
+ case 0x5b: trap(); break;
+ case 0x5c: incb(); break;
+ case 0x5d: tstb(); break;
+ case 0x5e: trap(); break;
+ case 0x5f: clrb(); break;
+ case 0x60: neg_ix(); break;
+ case 0x61: aim_ix(); /* HD63701YO only */; break;
+ case 0x62: oim_ix(); /* HD63701YO only */; break;
+ case 0x63: com_ix(); break;
+ case 0x64: lsr_ix(); break;
+ case 0x65: eim_ix(); /* HD63701YO only */; break;
+ case 0x66: ror_ix(); break;
+ case 0x67: asr_ix(); break;
+ case 0x68: asl_ix(); break;
+ case 0x69: rol_ix(); break;
+ case 0x6a: dec_ix(); break;
+ case 0x6b: tim_ix(); /* HD63701YO only */; break;
+ case 0x6c: inc_ix(); break;
+ case 0x6d: tst_ix(); break;
+ case 0x6e: jmp_ix(); break;
+ case 0x6f: clr_ix(); break;
+ case 0x70: neg_ex(); break;
+ case 0x71: aim_di(); /* HD63701YO only */; break;
+ case 0x72: oim_di(); /* HD63701YO only */; break;
+ case 0x73: com_ex(); break;
+ case 0x74: lsr_ex(); break;
+ case 0x75: eim_di(); /* HD63701YO only */; break;
+ case 0x76: ror_ex(); break;
+ case 0x77: asr_ex(); break;
+ case 0x78: asl_ex(); break;
+ case 0x79: rol_ex(); break;
+ case 0x7a: dec_ex(); break;
+ case 0x7b: tim_di(); /* HD63701YO only */; break;
+ case 0x7c: inc_ex(); break;
+ case 0x7d: tst_ex(); break;
+ case 0x7e: jmp_ex(); break;
+ case 0x7f: clr_ex(); break;
+ case 0x80: suba_im(); break;
+ case 0x81: cmpa_im(); break;
+ case 0x82: sbca_im(); break;
+ case 0x83: subd_im(); /* 6803 only */ break;
+ case 0x84: anda_im(); break;
+ case 0x85: bita_im(); break;
+ case 0x86: lda_im(); break;
+ case 0x87: sta_im(); break;
+ case 0x88: eora_im(); break;
+ case 0x89: adca_im(); break;
+ case 0x8a: ora_im(); break;
+ case 0x8b: adda_im(); break;
+ case 0x8c: cpx_im(); /* 6803 difference */ break;
+ case 0x8d: bsr(); break;
+ case 0x8e: lds_im(); break;
+ case 0x8f: sts_im(); /* orthogonality */ break;
+ case 0x90: suba_di(); break;
+ case 0x91: cmpa_di(); break;
+ case 0x92: sbca_di(); break;
+ case 0x93: subd_di(); /* 6803 only */ break;
+ case 0x94: anda_di(); break;
+ case 0x95: bita_di(); break;
+ case 0x96: lda_di(); break;
+ case 0x97: sta_di(); break;
+ case 0x98: eora_di(); break;
+ case 0x99: adca_di(); break;
+ case 0x9a: ora_di(); break;
+ case 0x9b: adda_di(); break;
+ case 0x9c: cpx_di(); /* 6803 difference */ break;
+ case 0x9d: jsr_di(); break;
+ case 0x9e: lds_di(); break;
+ case 0x9f: sts_di(); break;
+ case 0xa0: suba_ix(); break;
+ case 0xa1: cmpa_ix(); break;
+ case 0xa2: sbca_ix(); break;
+ case 0xa3: subd_ix(); /* 6803 only */ break;
+ case 0xa4: anda_ix(); break;
+ case 0xa5: bita_ix(); break;
+ case 0xa6: lda_ix(); break;
+ case 0xa7: sta_ix(); break;
+ case 0xa8: eora_ix(); break;
+ case 0xa9: adca_ix(); break;
+ case 0xaa: ora_ix(); break;
+ case 0xab: adda_ix(); break;
+ case 0xac: cpx_ix(); /* 6803 difference */ break;
+ case 0xad: jsr_ix(); break;
+ case 0xae: lds_ix(); break;
+ case 0xaf: sts_ix(); break;
+ case 0xb0: suba_ex(); break;
+ case 0xb1: cmpa_ex(); break;
+ case 0xb2: sbca_ex(); break;
+ case 0xb3: subd_ex(); /* 6803 only */ break;
+ case 0xb4: anda_ex(); break;
+ case 0xb5: bita_ex(); break;
+ case 0xb6: lda_ex(); break;
+ case 0xb7: sta_ex(); break;
+ case 0xb8: eora_ex(); break;
+ case 0xb9: adca_ex(); break;
+ case 0xba: ora_ex(); break;
+ case 0xbb: adda_ex(); break;
+ case 0xbc: cpx_ex(); /* 6803 difference */ break;
+ case 0xbd: jsr_ex(); break;
+ case 0xbe: lds_ex(); break;
+ case 0xbf: sts_ex(); break;
+ case 0xc0: subb_im(); break;
+ case 0xc1: cmpb_im(); break;
+ case 0xc2: sbcb_im(); break;
+ case 0xc3: addd_im(); /* 6803 only */ break;
+ case 0xc4: andb_im(); break;
+ case 0xc5: bitb_im(); break;
+ case 0xc6: ldb_im(); break;
+ case 0xc7: stb_im(); break;
+ case 0xc8: eorb_im(); break;
+ case 0xc9: adcb_im(); break;
+ case 0xca: orb_im(); break;
+ case 0xcb: addb_im(); break;
+ case 0xcc: ldd_im(); /* 6803 only */ break;
+ case 0xcd: std_im(); /* 6803 only -- orthogonality */ break;
+ case 0xce: ldx_im(); break;
+ case 0xcf: stx_im(); break;
+ case 0xd0: subb_di(); break;
+ case 0xd1: cmpb_di(); break;
+ case 0xd2: sbcb_di(); break;
+ case 0xd3: addd_di(); /* 6803 only */ break;
+ case 0xd4: andb_di(); break;
+ case 0xd5: bitb_di(); break;
+ case 0xd6: ldb_di(); break;
+ case 0xd7: stb_di(); break;
+ case 0xd8: eorb_di(); break;
+ case 0xd9: adcb_di(); break;
+ case 0xda: orb_di(); break;
+ case 0xdb: addb_di(); break;
+ case 0xdc: ldd_di(); /* 6803 only */ break;
+ case 0xdd: std_di(); /* 6803 only */ break;
+ case 0xde: ldx_di(); break;
+ case 0xdf: stx_di(); break;
+ case 0xe0: subb_ix(); break;
+ case 0xe1: cmpb_ix(); break;
+ case 0xe2: sbcb_ix(); break;
+ case 0xe3: addd_ix(); /* 6803 only */ break;
+ case 0xe4: andb_ix(); break;
+ case 0xe5: bitb_ix(); break;
+ case 0xe6: ldb_ix(); break;
+ case 0xe7: stb_ix(); break;
+ case 0xe8: eorb_ix(); break;
+ case 0xe9: adcb_ix(); break;
+ case 0xea: orb_ix(); break;
+ case 0xeb: addb_ix(); break;
+ case 0xec: ldd_ix(); /* 6803 only */ break;
+ case 0xed: std_ix(); /* 6803 only */ break;
+ case 0xee: ldx_ix(); break;
+ case 0xef: stx_ix(); break;
+ case 0xf0: subb_ex(); break;
+ case 0xf1: cmpb_ex(); break;
+ case 0xf2: sbcb_ex(); break;
+ case 0xf3: addd_ex(); /* 6803 only */ break;
+ case 0xf4: andb_ex(); break;
+ case 0xf5: bitb_ex(); break;
+ case 0xf6: ldb_ex(); break;
+ case 0xf7: stb_ex(); break;
+ case 0xf8: eorb_ex(); break;
+ case 0xf9: adcb_ex(); break;
+ case 0xfa: orb_ex(); break;
+ case 0xfb: addb_ex(); break;
+ case 0xfc: ldd_ex(); /* 6803 only */ break;
+ case 0xfd: std_ex(); /* 6803 only */ break;
+ case 0xfe: ldx_ex(); break;
+ case 0xff: stx_ex(); break;
+ }
+ INCREMENT_COUNTER(cycles_63701[ireg]);
+ }
+ } while( m6800_ICount>0 );
+
+ INCREMENT_COUNTER(hd63701.extra_cycles);
+ hd63701.extra_cycles = 0;
+
+ return cycles - m6800_ICount;
+}
+
+/*
+ if change_pc() direccted these areas ,Call hd63701_trap_pc().
+ 'mode' is selected by the sense of p2.0,p2.1,and p2.3 at reset timming.
+ mode 0,1,2,4,6 : $0000-$001f
+ mode 5 : $0000-$001f,$0200-$efff
+ mode 7 : $0000-$001f,$0100-$efff
+*/
+void hd63701_trap_pc(void)
+{
+ TAKE_TRAP;
+}
+
+static READ8_HANDLER( m6803_internal_registers_r );
+static WRITE8_HANDLER( m6803_internal_registers_w );
+
+READ8_HANDLER( hd63701_internal_registers_r )
+{
+ return m6803_internal_registers_r(offset);
+}
+
+WRITE8_HANDLER( hd63701_internal_registers_w )
+{
+ m6803_internal_registers_w(offset,data);
+}
+#endif
+
+/****************************************************************************
+ * NSC-8105 similiar to the M6800, but the opcodes are scrambled and there
+ * is at least one new opcode ($fc)
+ ****************************************************************************/
+#if (HAS_NSC8105)
+static void nsc8105_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+// m6800.subtype = SUBTYPE_NSC8105;
+ m6800.insn = nsc8105_insn;
+ m6800.cycles = cycles_nsc8105;
+ state_register("nsc8105", index);
+}
+/****************************************************************************
+ * Execute cycles CPU cycles. Return number of cycles really executed
+ ****************************************************************************/
+static int nsc8105_execute(int cycles)
+{
+ UINT8 ireg;
+ m6800_ICount = cycles;
+
+ CLEANUP_conters;
+ INCREMENT_COUNTER(nsc8105.extra_cycles);
+ nsc8105.extra_cycles = 0;
+
+ do
+ {
+ if( nsc8105.wai_state & NSC8105_WAI )
+ {
+ EAT_CYCLES;
+ }
+ else
+ {
+ pPPC = pPC;
+ CALL_MAME_DEBUG;
+ ireg=M_RDOP(PCD);
+ PC++;
+
+ switch( ireg )
+ {
+ case 0x00: illegal(); break;
+ case 0x01: illegal(); break;
+ case 0x02: nop(); break;
+ case 0x03: illegal(); break;
+ case 0x04: illegal(); break;
+ case 0x05: tap(); break;
+ case 0x06: illegal(); break;
+ case 0x07: tpa(); break;
+ case 0x08: inx(); break;
+ case 0x09: CLV; break;
+ case 0x0a: dex(); break;
+ case 0x0b: SEV; break;
+ case 0x0c: CLC; break;
+ case 0x0d: cli(); break;
+ case 0x0e: SEC; break;
+ case 0x0f: sei(); break;
+ case 0x10: sba(); break;
+ case 0x11: illegal(); break;
+ case 0x12: cba(); break;
+ case 0x13: illegal(); break;
+ case 0x14: illegal(); break;
+ case 0x15: tab(); break;
+ case 0x16: illegal(); break;
+ case 0x17: tba(); break;
+ case 0x18: illegal(); break;
+ case 0x19: illegal(); break;
+ case 0x1a: daa(); break;
+ case 0x1b: aba(); break;
+ case 0x1c: illegal(); break;
+ case 0x1d: illegal(); break;
+ case 0x1e: illegal(); break;
+ case 0x1f: illegal(); break;
+ case 0x20: bra(); break;
+ case 0x21: bhi(); break;
+ case 0x22: brn(); break;
+ case 0x23: bls(); break;
+ case 0x24: bcc(); break;
+ case 0x25: bne(); break;
+ case 0x26: bcs(); break;
+ case 0x27: beq(); break;
+ case 0x28: bvc(); break;
+ case 0x29: bpl(); break;
+ case 0x2a: bvs(); break;
+ case 0x2b: bmi(); break;
+ case 0x2c: bge(); break;
+ case 0x2d: bgt(); break;
+ case 0x2e: blt(); break;
+ case 0x2f: ble(); break;
+ case 0x30: tsx(); break;
+ case 0x31: pula(); break;
+ case 0x32: ins(); break;
+ case 0x33: pulb(); break;
+ case 0x34: des(); break;
+ case 0x35: psha(); break;
+ case 0x36: txs(); break;
+ case 0x37: pshb(); break;
+ case 0x38: illegal(); break;
+ case 0x39: illegal(); break;
+ case 0x3a: rts(); break;
+ case 0x3b: rti(); break;
+ case 0x3c: illegal(); break;
+ case 0x3d: wai(); break;
+ case 0x3e: illegal(); break;
+ case 0x3f: swi(); break;
+ case 0x40: suba_im(); break;
+ case 0x41: sbca_im(); break;
+ case 0x42: cmpa_im(); break;
+ case 0x43: illegal(); break;
+ case 0x44: anda_im(); break;
+ case 0x45: lda_im(); break;
+ case 0x46: bita_im(); break;
+ case 0x47: sta_im(); break;
+ case 0x48: eora_im(); break;
+ case 0x49: ora_im(); break;
+ case 0x4a: adca_im(); break;
+ case 0x4b: adda_im(); break;
+ case 0x4c: cmpx_im(); break;
+ case 0x4d: lds_im(); break;
+ case 0x4e: bsr(); break;
+ case 0x4f: sts_im(); /* orthogonality */ break;
+ case 0x50: suba_di(); break;
+ case 0x51: sbca_di(); break;
+ case 0x52: cmpa_di(); break;
+ case 0x53: illegal(); break;
+ case 0x54: anda_di(); break;
+ case 0x55: lda_di(); break;
+ case 0x56: bita_di(); break;
+ case 0x57: sta_di(); break;
+ case 0x58: eora_di(); break;
+ case 0x59: ora_di(); break;
+ case 0x5a: adca_di(); break;
+ case 0x5b: adda_di(); break;
+ case 0x5c: cmpx_di(); break;
+ case 0x5d: lds_di(); break;
+ case 0x5e: jsr_di(); break;
+ case 0x5f: sts_di(); break;
+ case 0x60: suba_ix(); break;
+ case 0x61: sbca_ix(); break;
+ case 0x62: cmpa_ix(); break;
+ case 0x63: illegal(); break;
+ case 0x64: anda_ix(); break;
+ case 0x65: lda_ix(); break;
+ case 0x66: bita_ix(); break;
+ case 0x67: sta_ix(); break;
+ case 0x68: eora_ix(); break;
+ case 0x69: ora_ix(); break;
+ case 0x6a: adca_ix(); break;
+ case 0x6b: adda_ix(); break;
+ case 0x6c: cmpx_ix(); break;
+ case 0x6d: lds_ix(); break;
+ case 0x6e: jsr_ix(); break;
+ case 0x6f: sts_ix(); break;
+ case 0x70: suba_ex(); break;
+ case 0x71: sbca_ex(); break;
+ case 0x72: cmpa_ex(); break;
+ case 0x73: illegal(); break;
+ case 0x74: anda_ex(); break;
+ case 0x75: lda_ex(); break;
+ case 0x76: bita_ex(); break;
+ case 0x77: sta_ex(); break;
+ case 0x78: eora_ex(); break;
+ case 0x79: ora_ex(); break;
+ case 0x7a: adca_ex(); break;
+ case 0x7b: adda_ex(); break;
+ case 0x7c: cmpx_ex(); break;
+ case 0x7d: lds_ex(); break;
+ case 0x7e: jsr_ex(); break;
+ case 0x7f: sts_ex(); break;
+ case 0x80: nega(); break;
+ case 0x81: illegal(); break;
+ case 0x82: illegal(); break;
+ case 0x83: coma(); break;
+ case 0x84: lsra(); break;
+ case 0x85: rora(); break;
+ case 0x86: illegal(); break;
+ case 0x87: asra(); break;
+ case 0x88: asla(); break;
+ case 0x89: deca(); break;
+ case 0x8a: rola(); break;
+ case 0x8b: illegal(); break;
+ case 0x8c: inca(); break;
+ case 0x8d: illegal(); break;
+ case 0x8e: tsta(); break;
+ case 0x8f: clra(); break;
+ case 0x90: negb(); break;
+ case 0x91: illegal(); break;
+ case 0x92: illegal(); break;
+ case 0x93: comb(); break;
+ case 0x94: lsrb(); break;
+ case 0x95: rorb(); break;
+ case 0x96: illegal(); break;
+ case 0x97: asrb(); break;
+ case 0x98: aslb(); break;
+ case 0x99: decb(); break;
+ case 0x9a: rolb(); break;
+ case 0x9b: illegal(); break;
+ case 0x9c: incb(); break;
+ case 0x9d: illegal(); break;
+ case 0x9e: tstb(); break;
+ case 0x9f: clrb(); break;
+ case 0xa0: neg_ix(); break;
+ case 0xa1: illegal(); break;
+ case 0xa2: illegal(); break;
+ case 0xa3: com_ix(); break;
+ case 0xa4: lsr_ix(); break;
+ case 0xa5: ror_ix(); break;
+ case 0xa6: illegal(); break;
+ case 0xa7: asr_ix(); break;
+ case 0xa8: asl_ix(); break;
+ case 0xa9: dec_ix(); break;
+ case 0xaa: rol_ix(); break;
+ case 0xab: illegal(); break;
+ case 0xac: inc_ix(); break;
+ case 0xad: jmp_ix(); break;
+ case 0xae: tst_ix(); break;
+ case 0xaf: clr_ix(); break;
+ case 0xb0: neg_ex(); break;
+ case 0xb1: illegal(); break;
+ case 0xb2: illegal(); break;
+ case 0xb3: com_ex(); break;
+ case 0xb4: lsr_ex(); break;
+ case 0xb5: ror_ex(); break;
+ case 0xb6: illegal(); break;
+ case 0xb7: asr_ex(); break;
+ case 0xb8: asl_ex(); break;
+ case 0xb9: dec_ex(); break;
+ case 0xba: rol_ex(); break;
+ case 0xbb: illegal(); break;
+ case 0xbc: inc_ex(); break;
+ case 0xbd: jmp_ex(); break;
+ case 0xbe: tst_ex(); break;
+ case 0xbf: clr_ex(); break;
+ case 0xc0: subb_im(); break;
+ case 0xc1: sbcb_im(); break;
+ case 0xc2: cmpb_im(); break;
+ case 0xc3: illegal(); break;
+ case 0xc4: andb_im(); break;
+ case 0xc5: ldb_im(); break;
+ case 0xc6: bitb_im(); break;
+ case 0xc7: stb_im(); break;
+ case 0xc8: eorb_im(); break;
+ case 0xc9: orb_im(); break;
+ case 0xca: adcb_im(); break;
+ case 0xcb: addb_im(); break;
+ case 0xcc: illegal(); break;
+ case 0xcd: ldx_im(); break;
+ case 0xce: illegal(); break;
+ case 0xcf: stx_im(); break;
+ case 0xd0: subb_di(); break;
+ case 0xd1: sbcb_di(); break;
+ case 0xd2: cmpb_di(); break;
+ case 0xd3: illegal(); break;
+ case 0xd4: andb_di(); break;
+ case 0xd5: ldb_di(); break;
+ case 0xd6: bitb_di(); break;
+ case 0xd7: stb_di(); break;
+ case 0xd8: eorb_di(); break;
+ case 0xd9: orb_di(); break;
+ case 0xda: adcb_di(); break;
+ case 0xdb: addb_di(); break;
+ case 0xdc: illegal(); break;
+ case 0xdd: ldx_di(); break;
+ case 0xde: illegal(); break;
+ case 0xdf: stx_di(); break;
+ case 0xe0: subb_ix(); break;
+ case 0xe1: sbcb_ix(); break;
+ case 0xe2: cmpb_ix(); break;
+ case 0xe3: illegal(); break;
+ case 0xe4: andb_ix(); break;
+ case 0xe5: ldb_ix(); break;
+ case 0xe6: bitb_ix(); break;
+ case 0xe7: stb_ix(); break;
+ case 0xe8: eorb_ix(); break;
+ case 0xe9: orb_ix(); break;
+ case 0xea: adcb_ix(); break;
+ case 0xeb: addb_ix(); break;
+ case 0xec: adcx_im(); break; /* NSC8105 only */
+ case 0xed: ldx_ix(); break;
+ case 0xee: illegal(); break;
+ case 0xef: stx_ix(); break;
+ case 0xf0: subb_ex(); break;
+ case 0xf1: sbcb_ex(); break;
+ case 0xf2: cmpb_ex(); break;
+ case 0xf3: illegal(); break;
+ case 0xf4: andb_ex(); break;
+ case 0xf5: ldb_ex(); break;
+ case 0xf6: bitb_ex(); break;
+ case 0xf7: stb_ex(); break;
+ case 0xf8: eorb_ex(); break;
+ case 0xf9: orb_ex(); break;
+ case 0xfa: adcb_ex(); break;
+ case 0xfb: addb_ex(); break;
+ case 0xfc: addx_ex(); break;
+ case 0xfd: ldx_ex(); break;
+ case 0xfe: illegal(); break;
+ case 0xff: stx_ex(); break;
+ }
+ INCREMENT_COUNTER(cycles_nsc8105[ireg]);
+ }
+ } while( m6800_ICount>0 );
+
+ INCREMENT_COUNTER(nsc8105.extra_cycles);
+ nsc8105.extra_cycles = 0;
+
+ return cycles - m6800_ICount;
+}
+#endif
+
+
+#if (HAS_M6803||HAS_HD63701)
+
+static READ8_HANDLER( m6803_internal_registers_r )
+{
+ switch (offset)
+ {
+ case 0x00:
+ return m6800.port1_ddr;
+ case 0x01:
+ return m6800.port2_ddr;
+ case 0x02:
+ return (io_read_byte_8(M6803_PORT1) & (m6800.port1_ddr ^ 0xff))
+ | (m6800.port1_data & m6800.port1_ddr);
+ case 0x03:
+ return (io_read_byte_8(M6803_PORT2) & (m6800.port2_ddr ^ 0xff))
+ | (m6800.port2_data & m6800.port2_ddr);
+ case 0x04:
+ return m6800.port3_ddr;
+ case 0x05:
+ return m6800.port4_ddr;
+ case 0x06:
+ return (io_read_byte_8(M6803_PORT3) & (m6800.port3_ddr ^ 0xff))
+ | (m6800.port3_data & m6800.port3_ddr);
+ case 0x07:
+ return (io_read_byte_8(M6803_PORT4) & (m6800.port4_ddr ^ 0xff))
+ | (m6800.port4_data & m6800.port4_ddr);
+ case 0x08:
+ m6800.pending_tcsr = 0;
+ return m6800.tcsr;
+ case 0x09:
+ if(!(m6800.pending_tcsr&TCSR_TOF))
+ {
+ m6800.tcsr &= ~TCSR_TOF;
+ MODIFIED_tcsr;
+ }
+ return m6800.counter.b.h;
+ case 0x0a:
+ return m6800.counter.b.l;
+ case 0x0b:
+ if(!(m6800.pending_tcsr&TCSR_OCF))
+ {
+ m6800.tcsr &= ~TCSR_OCF;
+ MODIFIED_tcsr;
+ }
+ return m6800.output_compare.b.h;
+ case 0x0c:
+ if(!(m6800.pending_tcsr&TCSR_OCF))
+ {
+ m6800.tcsr &= ~TCSR_OCF;
+ MODIFIED_tcsr;
+ }
+ return m6800.output_compare.b.l;
+ case 0x0d:
+ if(!(m6800.pending_tcsr&TCSR_ICF))
+ {
+ m6800.tcsr &= ~TCSR_ICF;
+ MODIFIED_tcsr;
+ }
+ return (m6800.input_capture >> 0) & 0xff;
+ case 0x0e:
+ return (m6800.input_capture >> 8) & 0xff;
+ case 0x0f:
+ logerror("CPU #%d PC %04x: warning - read from unsupported register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),offset);
+ return 0;
+ case 0x10:
+ return m6800.rmcr;
+ case 0x11:
+ m6800.trcsr_read = 1;
+ return m6800.trcsr;
+ case 0x12:
+ if (m6800.trcsr_read)
+ {
+ m6800.trcsr_read = 0;
+ m6800.trcsr = m6800.trcsr & 0x3f;
+ }
+ return m6800.rdr;
+ case 0x13:
+ return m6800.tdr;
+ case 0x14:
+ logerror("CPU #%d PC %04x: read RAM control register\n",cpu_getactivecpu(),activecpu_get_pc());
+ return m6800.ram_ctrl;
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ default:
+ logerror("CPU #%d PC %04x: warning - read from reserved internal register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),offset);
+ return 0;
+ }
+}
+
+static WRITE8_HANDLER( m6803_internal_registers_w )
+{
+ static int latch09;
+
+ switch (offset)
+ {
+ case 0x00:
+ if (m6800.port1_ddr != data)
+ {
+ m6800.port1_ddr = data;
+ if(m6800.port1_ddr == 0xff)
+ io_write_byte_8(M6803_PORT1,m6800.port1_data);
+ else
+ io_write_byte_8(M6803_PORT1,(m6800.port1_data & m6800.port1_ddr)
+ | (io_read_byte_8(M6803_PORT1) & (m6800.port1_ddr ^ 0xff)));
+ }
+ break;
+ case 0x01:
+ if (m6800.port2_ddr != data)
+ {
+ m6800.port2_ddr = data;
+ if(m6800.port2_ddr == 0xff)
+ io_write_byte_8(M6803_PORT2,m6800.port2_data);
+ else
+ io_write_byte_8(M6803_PORT2,(m6800.port2_data & m6800.port2_ddr)
+ | (io_read_byte_8(M6803_PORT2) & (m6800.port2_ddr ^ 0xff)));
+
+ if (m6800.port2_ddr & 2)
+ logerror("CPU #%d PC %04x: warning - port 2 bit 1 set as output (OLVL) - not supported\n",cpu_getactivecpu(),activecpu_get_pc());
+ }
+ break;
+ case 0x02:
+ m6800.port1_data = data;
+ if(m6800.port1_ddr == 0xff)
+ io_write_byte_8(M6803_PORT1,m6800.port1_data);
+ else
+ io_write_byte_8(M6803_PORT1,(m6800.port1_data & m6800.port1_ddr)
+ | (io_read_byte_8(M6803_PORT1) & (m6800.port1_ddr ^ 0xff)));
+ break;
+ case 0x03:
+ if (m6800.trcsr & M6800_TRCSR_TE)
+ {
+ m6800.port2_data = (data & 0xef) | (m6800.tx << 4);
+ }
+ else
+ {
+ m6800.port2_data = data;
+ }
+ if(m6800.port2_ddr == 0xff)
+ io_write_byte_8(M6803_PORT2,m6800.port2_data);
+ else
+ io_write_byte_8(M6803_PORT2,(m6800.port2_data & m6800.port2_ddr)
+ | (io_read_byte_8(M6803_PORT2) & (m6800.port2_ddr ^ 0xff)));
+ break;
+ case 0x04:
+ if (m6800.port3_ddr != data)
+ {
+ m6800.port3_ddr = data;
+ if(m6800.port3_ddr == 0xff)
+ io_write_byte_8(M6803_PORT3,m6800.port3_data);
+ else
+ io_write_byte_8(M6803_PORT3,(m6800.port3_data & m6800.port3_ddr)
+ | (io_read_byte_8(M6803_PORT3) & (m6800.port3_ddr ^ 0xff)));
+ }
+ break;
+ case 0x05:
+ if (m6800.port4_ddr != data)
+ {
+ m6800.port4_ddr = data;
+ if(m6800.port4_ddr == 0xff)
+ io_write_byte_8(M6803_PORT4,m6800.port4_data);
+ else
+ io_write_byte_8(M6803_PORT4,(m6800.port4_data & m6800.port4_ddr)
+ | (io_read_byte_8(M6803_PORT4) & (m6800.port4_ddr ^ 0xff)));
+ }
+ break;
+ case 0x06:
+ m6800.port3_data = data;
+ if(m6800.port3_ddr == 0xff)
+ io_write_byte_8(M6803_PORT3,m6800.port3_data);
+ else
+ io_write_byte_8(M6803_PORT3,(m6800.port3_data & m6800.port3_ddr)
+ | (io_read_byte_8(M6803_PORT3) & (m6800.port3_ddr ^ 0xff)));
+ break;
+ case 0x07:
+ m6800.port4_data = data;
+ if(m6800.port4_ddr == 0xff)
+ io_write_byte_8(M6803_PORT4,m6800.port4_data);
+ else
+ io_write_byte_8(M6803_PORT4,(m6800.port4_data & m6800.port4_ddr)
+ | (io_read_byte_8(M6803_PORT4) & (m6800.port4_ddr ^ 0xff)));
+ break;
+ case 0x08:
+ m6800.tcsr = data;
+ m6800.pending_tcsr &= m6800.tcsr;
+ MODIFIED_tcsr;
+ if( !(CC & 0x10) )
+ m6800_check_irq2();
+ break;
+ case 0x09:
+ latch09 = data & 0xff; /* 6301 only */
+ CT = 0xfff8;
+ TOH = CTH;
+ MODIFIED_counters;
+ break;
+ case 0x0a: /* 6301 only */
+ CT = (latch09 << 8) | (data & 0xff);
+ TOH = CTH;
+ MODIFIED_counters;
+ break;
+ case 0x0b:
+ if( m6800.output_compare.b.h != data)
+ {
+ m6800.output_compare.b.h = data;
+ MODIFIED_counters;
+ }
+ break;
+ case 0x0c:
+ if( m6800.output_compare.b.l != data)
+ {
+ m6800.output_compare.b.l = data;
+ MODIFIED_counters;
+ }
+ break;
+ case 0x0d:
+ case 0x0e:
+ case 0x12:
+ logerror("CPU #%d PC %04x: warning - write %02x to read only internal register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),data,offset);
+ break;
+ case 0x0f:
+ logerror("CPU #%d PC %04x: warning - write %02x to unsupported internal register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),data,offset);
+ break;
+ case 0x10:
+ m6800.rmcr = data & 0x0f;
+
+ switch ((m6800.rmcr & M6800_RMCR_CC_MASK) >> 2)
+ {
+ case 0:
+ case 3: // not implemented
+ timer_enable(m6800_rx_timer, 0);
+ timer_enable(m6800_tx_timer, 0);
+ break;
+
+ case 1:
+ case 2:
+ {
+ int divisor = M6800_RMCR_SS[m6800.rmcr & M6800_RMCR_SS_MASK];
+
+ timer_adjust(m6800_rx_timer, attotime_zero, cpu_getactivecpu(), ATTOTIME_IN_HZ(m6800.clock / divisor));
+ timer_adjust(m6800_tx_timer, attotime_zero, cpu_getactivecpu(), ATTOTIME_IN_HZ(m6800.clock / divisor));
+ }
+ break;
+ }
+ break;
+ case 0x11:
+ if ((data & M6800_TRCSR_TE) && !(m6800.trcsr & M6800_TRCSR_TE))
+ {
+ m6800.txstate = M6800_TX_STATE_INIT;
+ }
+ m6800.trcsr = (m6800.trcsr & 0xe0) | (data & 0x1f);
+ break;
+ case 0x13:
+ if (m6800.trcsr_read)
+ {
+ m6800.trcsr_read = 0;
+ m6800.trcsr &= ~M6800_TRCSR_TDRE;
+ }
+ m6800.tdr = data;
+ break;
+ case 0x14:
+ logerror("CPU #%d PC %04x: write %02x to RAM control register\n",cpu_getactivecpu(),activecpu_get_pc(),data);
+ m6800.ram_ctrl = data;
+ break;
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ default:
+ logerror("CPU #%d PC %04x: warning - write %02x to reserved internal register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+#endif
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void m6800_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M6800_IRQ_LINE: set_irq_line(M6800_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M6800_TIN_LINE: set_irq_line(M6800_TIN_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC: PC = info->i; CHANGE_PC(); break;
+ case CPUINFO_INT_REGISTER + M6800_PC: m6800.pc.w.l = info->i; break;
+ case CPUINFO_INT_SP: S = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_S: m6800.s.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_CC: m6800.cc = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_A: m6800.d.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_B: m6800.d.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_X: m6800.x.w.l = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void m6800_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(m6800); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 12; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 9; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + M6800_IRQ_LINE: info->i = m6800.irq_state[M6800_IRQ_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + M6800_TIN_LINE: info->i = m6800.irq_state[M6800_TIN_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = m6800.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = m6800.ppc.w.l; break;
+
+ case CPUINFO_INT_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + M6800_PC: info->i = m6800.pc.w.l; break;
+ case CPUINFO_INT_SP: info->i = S; break;
+ case CPUINFO_INT_REGISTER + M6800_S: info->i = m6800.s.w.l; break;
+ case CPUINFO_INT_REGISTER + M6800_CC: info->i = m6800.cc; break;
+ case CPUINFO_INT_REGISTER + M6800_A: info->i = m6800.d.b.h; break;
+ case CPUINFO_INT_REGISTER + M6800_B: info->i = m6800.d.b.l; break;
+ case CPUINFO_INT_REGISTER + M6800_X: info->i = m6800.x.w.l; break;
+ case CPUINFO_INT_REGISTER + M6800_WAI_STATE: info->i = m6800.wai_state; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m6800_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m6800_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m6800_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m6800_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m6800_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m6800_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m6800_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6800_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m6800_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6800"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola 6800"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.1"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "The MAME team."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ m6800.cc & 0x80 ? '?':'.',
+ m6800.cc & 0x40 ? '?':'.',
+ m6800.cc & 0x20 ? 'H':'.',
+ m6800.cc & 0x10 ? 'I':'.',
+ m6800.cc & 0x08 ? 'N':'.',
+ m6800.cc & 0x04 ? 'Z':'.',
+ m6800.cc & 0x02 ? 'V':'.',
+ m6800.cc & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M6800_A: sprintf(info->s, "A:%02X", m6800.d.b.h); break;
+ case CPUINFO_STR_REGISTER + M6800_B: sprintf(info->s, "B:%02X", m6800.d.b.l); break;
+ case CPUINFO_STR_REGISTER + M6800_PC: sprintf(info->s, "PC:%04X", m6800.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + M6800_S: sprintf(info->s, "S:%04X", m6800.s.w.l); break;
+ case CPUINFO_STR_REGISTER + M6800_X: sprintf(info->s, "X:%04X", m6800.x.w.l); break;
+ case CPUINFO_STR_REGISTER + M6800_CC: sprintf(info->s, "CC:%02X", m6800.cc); break;
+ case CPUINFO_STR_REGISTER + M6800_WAI_STATE: sprintf(info->s, "WAI:%X", m6800.wai_state); break;
+ }
+}
+
+
+#if (HAS_M6801)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void m6801_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 9; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = m6801_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m6803_execute; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6801_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6801"); break;
+
+ default: m6800_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_M6802)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void m6802_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = m6802_init; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6802_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6802"); break;
+
+ default: m6800_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_M6803)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void m6803_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 9; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = m6803_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m6803_execute; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6803_dasm; break;
+#endif /* MAME_DEBUG */
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_m6803_mem; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6803"); break;
+
+ default: m6800_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_M6808)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void m6808_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = m6808_init; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6808_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6808"); break;
+
+ default: m6800_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_HD63701)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void hd63701_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 9; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = hd63701_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = hd63701_execute; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = hd63701_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "HD63701"); break;
+
+ default: m6800_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_NSC8105)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void nsc8105_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = nsc8105_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = nsc8105_execute; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = nsc8105_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "NSC8105"); break;
+
+ default: m6800_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/m6800/m6800.h b/src/emu/cpu/m6800/m6800.h
new file mode 100644
index 00000000000..7b711d6bc59
--- /dev/null
+++ b/src/emu/cpu/m6800/m6800.h
@@ -0,0 +1,223 @@
+/*** m6800: Portable 6800 class emulator *************************************/
+
+#ifndef _M6800_H
+#define _M6800_H
+
+#include "cpuintrf.h"
+
+enum {
+ M6800_PC=1, M6800_S, M6800_A, M6800_B, M6800_X, M6800_CC,
+ M6800_WAI_STATE };
+
+#define M6800_WAI 8 /* set when WAI is waiting for an interrupt */
+#define M6800_SLP 0x10 /* HD63701 only */
+
+
+#define M6800_IRQ_LINE 0 /* IRQ line number */
+#define M6800_TIN_LINE 1 /* P20/Tin Input Capture line (eddge sense) */
+ /* Active eddge is selecrable by internal reg. */
+ /* raise eddge : CLEAR_LINE -> ASSERT_LINE */
+ /* fall eddge : ASSERT_LINE -> CLEAR_LINE */
+ /* it is usuali to use PULSE_LINE state */
+
+extern void m6800_get_info(UINT32 state, cpuinfo *info);
+
+/****************************************************************************
+ * For now make the 6801 using the m6800 variables and functions
+ ****************************************************************************/
+#if (HAS_M6801)
+#define M6801_A M6800_A
+#define M6801_B M6800_B
+#define M6801_PC M6800_PC
+#define M6801_S M6800_S
+#define M6801_X M6800_X
+#define M6801_CC M6800_CC
+#define M6801_WAI_STATE M6800_WAI_STATE
+#define M6801_NMI_STATE M6800_NMI_STATE
+#define M6801_IRQ_STATE M6800_IRQ_STATE
+
+#define M6801_WAI M6800_WAI
+#define M6801_IRQ_LINE M6800_IRQ_LINE
+
+extern void m6801_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************
+ * For now make the 6802 using the m6800 variables and functions
+ ****************************************************************************/
+#if (HAS_M6802)
+#define M6802_A M6800_A
+#define M6802_B M6800_B
+#define M6802_PC M6800_PC
+#define M6802_S M6800_S
+#define M6802_X M6800_X
+#define M6802_CC M6800_CC
+#define M6802_WAI_STATE M6800_WAI_STATE
+#define M6802_NMI_STATE M6800_NMI_STATE
+#define M6802_IRQ_STATE M6800_IRQ_STATE
+
+#define M6802_WAI M6800_WAI
+#define M6802_IRQ_LINE M6800_IRQ_LINE
+
+extern void m6802_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************
+ * For now make the 6803 using the m6800 variables and functions
+ ****************************************************************************/
+#if (HAS_M6803)
+#define M6803_A M6800_A
+#define M6803_B M6800_B
+#define M6803_PC M6800_PC
+#define M6803_S M6800_S
+#define M6803_X M6800_X
+#define M6803_CC M6800_CC
+#define M6803_WAI_STATE M6800_WAI_STATE
+#define M6803_NMI_STATE M6800_NMI_STATE
+#define M6803_IRQ_STATE M6800_IRQ_STATE
+
+#define M6803_WAI M6800_WAI
+#define M6803_IRQ_LINE M6800_IRQ_LINE
+#define M6803_TIN_LINE M6800_TIN_LINE
+
+extern void m6803_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_M6803||HAS_HD63701)
+/* By default, on a port write port bits which are not set as output in the DDR */
+/* are set to the value returned by a read from the same port. If you need to */
+/* know the DDR for e.g. port 1, do m6803_internal_registers_r(M6801_DDR1) */
+
+#define M6803_DDR1 0x00
+#define M6803_DDR2 0x01
+#define M6803_DDR3 0x04
+#define M6803_DDR4 0x05
+
+#define M6803_PORT1 0x100
+#define M6803_PORT2 0x101
+#define M6803_PORT3 0x102
+#define M6803_PORT4 0x103
+#endif
+
+/****************************************************************************
+ * For now make the 6808 using the m6800 variables and functions
+ ****************************************************************************/
+#if (HAS_M6808)
+#define M6808_A M6800_A
+#define M6808_B M6800_B
+#define M6808_PC M6800_PC
+#define M6808_S M6800_S
+#define M6808_X M6800_X
+#define M6808_CC M6800_CC
+#define M6808_WAI_STATE M6800_WAI_STATE
+#define M6808_NMI_STATE M6800_NMI_STATE
+#define M6808_IRQ_STATE M6800_IRQ_STATE
+
+#define M6808_WAI M6800_WAI
+#define M6808_IRQ_LINE M6800_IRQ_LINE
+
+extern void m6808_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************
+ * For now make the HD63701 using the m6800 variables and functions
+ ****************************************************************************/
+#if (HAS_HD63701)
+#define HD63701_A M6800_A
+#define HD63701_B M6800_B
+#define HD63701_PC M6800_PC
+#define HD63701_S M6800_S
+#define HD63701_X M6800_X
+#define HD63701_CC M6800_CC
+#define HD63701_WAI_STATE M6800_WAI_STATE
+#define HD63701_NMI_STATE M6800_NMI_STATE
+#define HD63701_IRQ_STATE M6800_IRQ_STATE
+
+#define HD63701_WAI M6800_WAI
+#define HD63701_SLP M6800_SLP
+#define HD63701_IRQ_LINE M6800_IRQ_LINE
+#define HD63701_TIN_LINE M6800_TIN_LINE
+
+extern void hd63701_get_info(UINT32 state, cpuinfo *info);
+
+void hd63701_trap_pc(void);
+
+#define HD63701_DDR1 M6803_DDR1
+#define HD63701_DDR2 M6803_DDR2
+#define HD63701_DDR3 M6803_DDR3
+#define HD63701_DDR4 M6803_DDR4
+
+#define HD63701_PORT1 M6803_PORT1
+#define HD63701_PORT2 M6803_PORT2
+#define HD63701_PORT3 M6803_PORT3
+#define HD63701_PORT4 M6803_PORT4
+
+READ8_HANDLER( hd63701_internal_registers_r );
+WRITE8_HANDLER( hd63701_internal_registers_w );
+
+#endif
+
+/****************************************************************************
+ * For now make the NSC8105 using the m6800 variables and functions
+ ****************************************************************************/
+#if (HAS_NSC8105)
+#define NSC8105_A M6800_A
+#define NSC8105_B M6800_B
+#define NSC8105_PC M6800_PC
+#define NSC8105_S M6800_S
+#define NSC8105_X M6800_X
+#define NSC8105_CC M6800_CC
+#define NSC8105_WAI_STATE M6800_WAI_STATE
+#define NSC8105_NMI_STATE M6800_NMI_STATE
+#define NSC8105_IRQ_STATE M6800_IRQ_STATE
+
+#define NSC8105_WAI M6800_WAI
+#define NSC8105_IRQ_LINE M6800_IRQ_LINE
+#define NSC8105_TIN_LINE M6800_TIN_LINE
+
+extern void nsc8105_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************/
+/* Read a byte from given memory location */
+/****************************************************************************/
+/* ASG 971005 -- changed to program_read_byte_8/program_write_byte_8 */
+#define M6800_RDMEM(Addr) ((unsigned)program_read_byte_8(Addr))
+
+/****************************************************************************/
+/* Write a byte to given memory location */
+/****************************************************************************/
+#define M6800_WRMEM(Addr,Value) (program_write_byte_8(Addr,Value))
+
+/****************************************************************************/
+/* M6800_RDOP() is identical to M6800_RDMEM() except it is used for reading */
+/* opcodes. In case of system with memory mapped I/O, this function can be */
+/* used to greatly speed up emulation */
+/****************************************************************************/
+#define M6800_RDOP(Addr) ((unsigned)cpu_readop(Addr))
+
+/****************************************************************************/
+/* M6800_RDOP_ARG() is identical to M6800_RDOP() but it's used for reading */
+/* opcode arguments. This difference can be used to support systems that */
+/* use different encoding mechanisms for opcodes and opcode arguments */
+/****************************************************************************/
+#define M6800_RDOP_ARG(Addr) ((unsigned)cpu_readop_arg(Addr))
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE (!FALSE)
+#endif
+
+#ifdef MAME_DEBUG
+offs_t m6800_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t m6801_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t m6802_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t m6803_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t m6808_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t hd63701_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t nsc8105_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _M6800_H */
diff --git a/src/emu/cpu/m68000/m68000.h b/src/emu/cpu/m68000/m68000.h
new file mode 100644
index 00000000000..f90ac95da26
--- /dev/null
+++ b/src/emu/cpu/m68000/m68000.h
@@ -0,0 +1,162 @@
+#ifndef M68000__HEADER
+#define M68000__HEADER
+
+#include "cpuintrf.h"
+
+enum
+{
+ /* NOTE: M68K_SP fetches the current SP, be it USP, ISP, or MSP */
+ M68K_PC=1, M68K_SP, M68K_ISP, M68K_USP, M68K_MSP, M68K_SR, M68K_VBR,
+ M68K_SFC, M68K_DFC, M68K_CACR, M68K_CAAR, M68K_PREF_ADDR, M68K_PREF_DATA,
+ M68K_D0, M68K_D1, M68K_D2, M68K_D3, M68K_D4, M68K_D5, M68K_D6, M68K_D7,
+ M68K_A0, M68K_A1, M68K_A2, M68K_A3, M68K_A4, M68K_A5, M68K_A6, M68K_A7
+};
+
+enum
+{
+ CPUINFO_PTR_M68K_RESET_CALLBACK = CPUINFO_PTR_CPU_SPECIFIC,
+ CPUINFO_PTR_M68K_CMPILD_CALLBACK,
+ CPUINFO_PTR_M68K_RTE_CALLBACK,
+ CPUINFO_PTR_M68K_TAS_CALLBACK
+};
+
+extern int m68k_ICount;
+
+/* Redirect memory calls */
+
+struct m68k_memory_interface
+{
+ offs_t opcode_xor; // Address Calculation
+ UINT8 (*read8)(offs_t); // Normal read 8 bit
+ UINT16 (*read16)(offs_t); // Normal read 16 bit
+ UINT32 (*read32)(offs_t); // Normal read 32 bit
+ void (*write8)(offs_t, UINT8); // Write 8 bit
+ void (*write16)(offs_t, UINT16); // Write 16 bit
+ void (*write32)(offs_t, UINT32); // Write 32 bit
+ void (*changepc)(offs_t); // Change PC
+
+ // For Encrypted Stuff
+
+ UINT8 (*read8pc)(offs_t); // PC Relative read 8 bit
+ UINT16 (*read16pc)(offs_t); // PC Relative read 16 bit
+ UINT32 (*read32pc)(offs_t); // PC Relative read 32 bit
+
+ UINT16 (*read16d)(offs_t); // Direct read 16 bit
+ UINT32 (*read32d)(offs_t); // Direct read 32 bit
+};
+
+struct m68k_encryption_interface
+{
+ UINT8 (*read8pc)(offs_t); // PC Relative read 8 bit
+ UINT16 (*read16pc)(offs_t); // PC Relative read 16 bit
+ UINT32 (*read32pc)(offs_t); // PC Relative read 32 bit
+
+ UINT16 (*read16d)(offs_t); // Direct read 16 bit
+ UINT32 (*read32d)(offs_t); // Direct read 32 bit
+};
+
+/* The MAME API for MC68000 */
+
+#define MC68000_IRQ_1 1
+#define MC68000_IRQ_2 2
+#define MC68000_IRQ_3 3
+#define MC68000_IRQ_4 4
+#define MC68000_IRQ_5 5
+#define MC68000_IRQ_6 6
+#define MC68000_IRQ_7 7
+
+#define MC68000_INT_ACK_AUTOVECTOR -1
+#define MC68000_INT_ACK_SPURIOUS -2
+
+void m68000_get_info(UINT32 state, cpuinfo *info);
+extern void m68000_memory_interface_set(int Entry,void * memory_routine);
+
+/****************************************************************************
+ * M68008 section
+ ****************************************************************************/
+#if HAS_M68008
+#define MC68008_IRQ_1 MC68000_IRQ_1
+#define MC68008_IRQ_2 MC68000_IRQ_2
+#define MC68008_IRQ_3 MC68000_IRQ_3
+#define MC68008_IRQ_4 MC68000_IRQ_4
+#define MC68008_IRQ_5 MC68000_IRQ_5
+#define MC68008_IRQ_6 MC68000_IRQ_6
+#define MC68008_IRQ_7 MC68000_IRQ_7
+#define MC68008_INT_ACK_AUTOVECTOR MC68000_INT_ACK_AUTOVECTOR
+#define MC68008_INT_ACK_SPURIOUS MC68000_INT_ACK_SPURIOUS
+
+void m68008_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************
+ * M68010 section
+ ****************************************************************************/
+#if HAS_M68010
+#define MC68010_IRQ_1 MC68000_IRQ_1
+#define MC68010_IRQ_2 MC68000_IRQ_2
+#define MC68010_IRQ_3 MC68000_IRQ_3
+#define MC68010_IRQ_4 MC68000_IRQ_4
+#define MC68010_IRQ_5 MC68000_IRQ_5
+#define MC68010_IRQ_6 MC68000_IRQ_6
+#define MC68010_IRQ_7 MC68000_IRQ_7
+#define MC68010_INT_ACK_AUTOVECTOR MC68000_INT_ACK_AUTOVECTOR
+#define MC68010_INT_ACK_SPURIOUS MC68000_INT_ACK_SPURIOUS
+
+void m68010_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************
+ * M68EC020 section
+ ****************************************************************************/
+#if HAS_M68EC020
+#define MC68EC020_IRQ_1 MC68000_IRQ_1
+#define MC68EC020_IRQ_2 MC68000_IRQ_2
+#define MC68EC020_IRQ_3 MC68000_IRQ_3
+#define MC68EC020_IRQ_4 MC68000_IRQ_4
+#define MC68EC020_IRQ_5 MC68000_IRQ_5
+#define MC68EC020_IRQ_6 MC68000_IRQ_6
+#define MC68EC020_IRQ_7 MC68000_IRQ_7
+#define MC68EC020_INT_ACK_AUTOVECTOR MC68000_INT_ACK_AUTOVECTOR
+#define MC68EC020_INT_ACK_SPURIOUS MC68000_INT_ACK_SPURIOUS
+
+void m68ec020_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************
+ * M68020 section
+ ****************************************************************************/
+#if HAS_M68020
+#define MC68020_IRQ_1 MC68000_IRQ_1
+#define MC68020_IRQ_2 MC68000_IRQ_2
+#define MC68020_IRQ_3 MC68000_IRQ_3
+#define MC68020_IRQ_4 MC68000_IRQ_4
+#define MC68020_IRQ_5 MC68000_IRQ_5
+#define MC68020_IRQ_6 MC68000_IRQ_6
+#define MC68020_IRQ_7 MC68000_IRQ_7
+#define MC68020_INT_ACK_AUTOVECTOR MC68000_INT_ACK_AUTOVECTOR
+#define MC68020_INT_ACK_SPURIOUS MC68000_INT_ACK_SPURIOUS
+
+void m68020_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************
+ * M68040 section
+ ****************************************************************************/
+#if HAS_M68040
+#define MC68040_IRQ_1 MC68000_IRQ_1
+#define MC68040_IRQ_2 MC68000_IRQ_2
+#define MC68040_IRQ_3 MC68000_IRQ_3
+#define MC68040_IRQ_4 MC68000_IRQ_4
+#define MC68040_IRQ_5 MC68000_IRQ_5
+#define MC68040_IRQ_6 MC68000_IRQ_6
+#define MC68040_IRQ_7 MC68000_IRQ_7
+#define MC68040_INT_ACK_AUTOVECTOR MC68000_INT_ACK_AUTOVECTOR
+#define MC68040_INT_ACK_SPURIOUS MC68000_INT_ACK_SPURIOUS
+
+void m68040_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+// C Core header
+#include "m68kmame.h"
+
+#endif /* M68000__HEADER */
diff --git a/src/emu/cpu/m68000/m68k.h b/src/emu/cpu/m68000/m68k.h
new file mode 100644
index 00000000000..b04bc518351
--- /dev/null
+++ b/src/emu/cpu/m68000/m68k.h
@@ -0,0 +1,379 @@
+#ifndef M68K__HEADER
+#define M68K__HEADER
+
+/* ======================================================================== */
+/* ========================= LICENSING & COPYRIGHT ======================== */
+/* ======================================================================== */
+/*
+ * MUSASHI
+ * Version 3.31
+ *
+ * A portable Motorola M680x0 processor emulation engine.
+ * Copyright 1998-2007 Karl Stenerud. All rights reserved.
+ *
+ * This code may be freely used for non-commercial purposes as long as this
+ * copyright notice remains unaltered in the source code and any binary files
+ * containing this code in compiled form.
+ *
+ * All other lisencing terms must be negotiated with the author
+ * (Karl Stenerud).
+ *
+ * The latest version of this code can be obtained at:
+ * http://kstenerud.cjb.net
+ */
+
+/* ======================================================================== */
+/* ============================= CONFIGURATION ============================ */
+/* ======================================================================== */
+
+/* Import the configuration for this build */
+#include "m68kconf.h"
+
+
+/* ======================================================================== */
+/* ============================ GENERAL DEFINES =========================== */
+
+/* ======================================================================== */
+
+/* There are 7 levels of interrupt to the 68K.
+ * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
+ */
+#define M68K_IRQ_NONE 0
+#define M68K_IRQ_1 1
+#define M68K_IRQ_2 2
+#define M68K_IRQ_3 3
+#define M68K_IRQ_4 4
+#define M68K_IRQ_5 5
+#define M68K_IRQ_6 6
+#define M68K_IRQ_7 7
+
+
+/* Special interrupt acknowledge values.
+ * Use these as special returns from the interrupt acknowledge callback
+ * (specified later in this header).
+ */
+
+/* Causes an interrupt autovector (0x18 + interrupt level) to be taken.
+ * This happens in a real 68K if VPA or AVEC is asserted during an interrupt
+ * acknowledge cycle instead of DTACK.
+ */
+#define M68K_INT_ACK_AUTOVECTOR 0xffffffff
+
+/* Causes the spurious interrupt vector (0x18) to be taken
+ * This happens in a real 68K if BERR is asserted during the interrupt
+ * acknowledge cycle (i.e. no devices responded to the acknowledge).
+ */
+#define M68K_INT_ACK_SPURIOUS 0xfffffffe
+
+
+/* CPU types for use in m68k_set_cpu_type() */
+enum
+{
+ M68K_CPU_TYPE_INVALID,
+ M68K_CPU_TYPE_68000,
+ M68K_CPU_TYPE_68008,
+ M68K_CPU_TYPE_68010,
+ M68K_CPU_TYPE_68EC020,
+ M68K_CPU_TYPE_68020,
+ M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */
+ M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */
+};
+
+/* Registers used by m68k_get_reg() and m68k_set_reg() */
+typedef enum
+{
+ /* Real registers */
+ M68K_REG_D0, /* Data registers */
+ M68K_REG_D1,
+ M68K_REG_D2,
+ M68K_REG_D3,
+ M68K_REG_D4,
+ M68K_REG_D5,
+ M68K_REG_D6,
+ M68K_REG_D7,
+ M68K_REG_A0, /* Address registers */
+ M68K_REG_A1,
+ M68K_REG_A2,
+ M68K_REG_A3,
+ M68K_REG_A4,
+ M68K_REG_A5,
+ M68K_REG_A6,
+ M68K_REG_A7,
+ M68K_REG_PC, /* Program Counter */
+ M68K_REG_SR, /* Status Register */
+ M68K_REG_SP, /* The current Stack Pointer (located in A7) */
+ M68K_REG_USP, /* User Stack Pointer */
+ M68K_REG_ISP, /* Interrupt Stack Pointer */
+ M68K_REG_MSP, /* Master Stack Pointer */
+ M68K_REG_SFC, /* Source Function Code */
+ M68K_REG_DFC, /* Destination Function Code */
+ M68K_REG_VBR, /* Vector Base Register */
+ M68K_REG_CACR, /* Cache Control Register */
+ M68K_REG_CAAR, /* Cache Address Register */
+
+ /* Assumed registers */
+ /* These are cheat registers which emulate the 1-longword prefetch
+ * present in the 68000 and 68010.
+ */
+ M68K_REG_PREF_ADDR, /* Last prefetch address */
+ M68K_REG_PREF_DATA, /* Last prefetch data */
+
+ /* Convenience registers */
+ M68K_REG_PPC, /* Previous value in the program counter */
+ M68K_REG_IR, /* Instruction register */
+ M68K_REG_CPU_TYPE /* Type of CPU being run */
+} m68k_register_t;
+
+/* ======================================================================== */
+/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
+/* ======================================================================== */
+
+/* You will have to implement these functions */
+
+/* read/write functions called by the CPU to access memory.
+ * while values used are 32 bits, only the appropriate number
+ * of bits are relevant (i.e. in write_memory_8, only the lower 8 bits
+ * of value should be written to memory).
+ *
+ * NOTE: I have separated the immediate and PC-relative memory fetches
+ * from the other memory fetches because some systems require
+ * differentiation between PROGRAM and DATA fetches (usually
+ * for security setups such as encryption).
+ * This separation can either be achieved by setting
+ * M68K_SEPARATE_READS in m68kconf.h and defining
+ * the read functions, or by setting M68K_EMULATE_FC and
+ * making a function code callback function.
+ * Using the callback offers better emulation coverage
+ * because you can also monitor whether the CPU is in SYSTEM or
+ * USER mode, but it is also slower.
+ */
+
+/* Read from anywhere */
+unsigned int m68k_read_memory_8(unsigned int address);
+unsigned int m68k_read_memory_16(unsigned int address);
+unsigned int m68k_read_memory_32(unsigned int address);
+
+/* Read data immediately following the PC */
+unsigned int m68k_read_immediate_16(unsigned int address);
+unsigned int m68k_read_immediate_32(unsigned int address);
+
+/* Read data relative to the PC */
+unsigned int m68k_read_pcrelative_8(unsigned int address);
+unsigned int m68k_read_pcrelative_16(unsigned int address);
+unsigned int m68k_read_pcrelative_32(unsigned int address);
+
+/* Memory access for the disassembler */
+unsigned int m68k_read_disassembler_8 (unsigned int address);
+unsigned int m68k_read_disassembler_16 (unsigned int address);
+unsigned int m68k_read_disassembler_32 (unsigned int address);
+
+/* Write to anywhere */
+void m68k_write_memory_8(unsigned int address, unsigned int value);
+void m68k_write_memory_16(unsigned int address, unsigned int value);
+void m68k_write_memory_32(unsigned int address, unsigned int value);
+
+/* Special call to simulate undocumented 68k behavior when move.l with a
+ * predecrement destination mode is executed.
+ * To simulate real 68k behavior, first write the high word to
+ * [address+2], and then write the low word to [address].
+ *
+ * Enable this functionality with M68K_SIMULATE_PD_WRITES in m68kconf.h.
+ */
+void m68k_write_memory_32_pd(unsigned int address, unsigned int value);
+
+
+
+/* ======================================================================== */
+/* ============================== CALLBACKS =============================== */
+/* ======================================================================== */
+
+/* These functions allow you to set callbacks to the host when specific events
+ * occur. Note that you must enable the corresponding value in m68kconf.h
+ * in order for these to do anything useful.
+ * Note: I have defined default callbacks which are used if you have enabled
+ * the corresponding #define in m68kconf.h but either haven't assigned a
+ * callback or have assigned a callback of NULL.
+ */
+
+/* Set the callback for an interrupt acknowledge.
+ * You must enable M68K_EMULATE_INT_ACK in m68kconf.h.
+ * The CPU will call the callback with the interrupt level being acknowledged.
+ * The host program must return either a vector from 0x02-0xff, or one of the
+ * special interrupt acknowledge values specified earlier in this header.
+ * If this is not implemented, the CPU will always assume an autovectored
+ * interrupt, and will automatically clear the interrupt request when it
+ * services the interrupt.
+ * Default behavior: return M68K_INT_ACK_AUTOVECTOR.
+ */
+void m68k_set_int_ack_callback(int (*callback)(int int_level));
+
+
+/* Set the callback for a breakpoint acknowledge (68010+).
+ * You must enable M68K_EMULATE_BKPT_ACK in m68kconf.h.
+ * The CPU will call the callback with whatever was in the data field of the
+ * BKPT instruction for 68020+, or 0 for 68010.
+ * Default behavior: do nothing.
+ */
+void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data));
+
+
+/* Set the callback for the RESET instruction.
+ * You must enable M68K_EMULATE_RESET in m68kconf.h.
+ * The CPU calls this callback every time it encounters a RESET instruction.
+ * Default behavior: do nothing.
+ */
+void m68k_set_reset_instr_callback(void (*callback)(void));
+
+
+/* Set the callback for the CMPI.L #v, Dn instruction.
+ * You must enable M68K_CMPILD_HAS_CALLBACK in m68kconf.h.
+ * The CPU calls this callback every time it encounters a CMPI.L #v, Dn instruction.
+ * Default behavior: do nothing.
+ */
+void m68k_set_cmpild_instr_callback(void (*callback)(unsigned int val, int reg));
+
+
+/* Set the callback for the RTE instruction.
+ * You must enable M68K_RTE_HAS_CALLBACK in m68kconf.h.
+ * The CPU calls this callback every time it encounters a RTE instruction.
+ * Default behavior: do nothing.
+ */
+void m68k_set_rte_instr_callback(void (*callback)(void));
+
+/* Set the callback for the TAS instruction.
+ * You must enable M68K_TAS_HAS_CALLBACK in m68kconf.h.
+ * The CPU calls this callback every time it encounters a TAS instruction.
+ * Default behavior: return 1, allow writeback.
+ */
+void m68k_set_tas_instr_callback(int (*callback)(void));
+
+
+
+/* Set the callback for informing of a large PC change.
+ * You must enable M68K_MONITOR_PC in m68kconf.h.
+ * The CPU calls this callback with the new PC value every time the PC changes
+ * by a large value (currently set for changes by longwords).
+ * Default behavior: do nothing.
+ */
+void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc));
+
+
+/* Set the callback for CPU function code changes.
+ * You must enable M68K_EMULATE_FC in m68kconf.h.
+ * The CPU calls this callback with the function code before every memory
+ * access to set the CPU's function code according to what kind of memory
+ * access it is (supervisor/user, program/data and such).
+ * Default behavior: do nothing.
+ */
+void m68k_set_fc_callback(void (*callback)(unsigned int new_fc));
+
+
+/* Set a callback for the instruction cycle of the CPU.
+ * You must enable M68K_INSTRUCTION_HOOK in m68kconf.h.
+ * The CPU calls this callback just before fetching the opcode in the
+ * instruction cycle.
+ * Default behavior: do nothing.
+ */
+void m68k_set_instr_hook_callback(void (*callback)(void));
+
+
+
+/* ======================================================================== */
+/* ====================== FUNCTIONS TO ACCESS THE CPU ===================== */
+/* ======================================================================== */
+
+/* Use this function to set the CPU type you want to emulate.
+ * Currently supported types are: M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68008,
+ * M68K_CPU_TYPE_68010, M68K_CPU_TYPE_EC020, and M68K_CPU_TYPE_68020.
+ */
+void m68k_set_cpu_type(unsigned int cpu_type);
+
+/* Do whatever initialisations the core requires. Should be called
+ * at least once at init time.
+ */
+void m68k_init(void);
+
+/* Pulse the RESET pin on the CPU.
+ * You *MUST* reset the CPU at least once to initialize the emulation
+ * Note: If you didn't call m68k_set_cpu_type() before resetting
+ * the CPU for the first time, the CPU will be set to
+ * M68K_CPU_TYPE_68000.
+ */
+void m68k_pulse_reset(void);
+
+/* execute num_cycles worth of instructions. returns number of cycles used */
+int m68k_execute(int num_cycles);
+
+/* These functions let you read/write/modify the number of cycles left to run
+ * while m68k_execute() is running.
+ * These are useful if the 68k accesses a memory-mapped port on another device
+ * that requires immediate processing by another CPU.
+ */
+int m68k_cycles_run(void); /* Number of cycles run so far */
+int m68k_cycles_remaining(void); /* Number of cycles left */
+void m68k_modify_timeslice(int cycles); /* Modify cycles left */
+void m68k_end_timeslice(void); /* End timeslice now */
+
+/* Set the IPL0-IPL2 pins on the CPU (IRQ).
+ * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
+ * Setting IRQ to 0 will clear an interrupt request.
+ */
+void m68k_set_irq(unsigned int int_level);
+
+
+/* Halt the CPU as if you pulsed the HALT pin. */
+void m68k_pulse_halt(void);
+
+
+/* Context switching to allow multiple CPUs */
+
+/* Get the size of the cpu context in bytes */
+unsigned int m68k_context_size(void);
+
+/* Get a cpu context */
+unsigned int m68k_get_context(void* dst);
+
+/* set the current cpu context */
+void m68k_set_context(void* dst);
+
+/* Register the CPU state information */
+void m68k_state_register(const char *type, int index);
+
+
+/* Peek at the internals of a CPU context. This can either be a context
+ * retrieved using m68k_get_context() or the currently running context.
+ * If context is NULL, the currently running CPU context will be used.
+ */
+unsigned int m68k_get_reg(void* context, m68k_register_t reg);
+
+/* Poke values into the internals of the currently running CPU context */
+void m68k_set_reg(m68k_register_t reg, unsigned int value);
+
+/* Check if an instruction is valid for the specified CPU type */
+unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type);
+
+/* Disassemble 1 instruction using the epecified CPU type at pc. Stores
+ * disassembly in str_buff and returns the size of the instruction in bytes.
+ */
+unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type);
+
+/* Same as above but accepts raw opcode data directly rather than fetching
+ * via the read/write interfaces.
+ */
+unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigned char* opdata, const unsigned char* argdata, unsigned int cpu_type);
+
+
+/* ======================================================================== */
+/* ============================== MAME STUFF ============================== */
+/* ======================================================================== */
+
+#if M68K_COMPILE_FOR_MAME == OPT_ON
+#include "m68kmame.h"
+#endif /* M68K_COMPILE_FOR_MAME */
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+#endif /* M68K__HEADER */
diff --git a/src/emu/cpu/m68000/m68k_in.c b/src/emu/cpu/m68000/m68k_in.c
new file mode 100644
index 00000000000..79c957f4067
--- /dev/null
+++ b/src/emu/cpu/m68000/m68k_in.c
@@ -0,0 +1,10685 @@
+/*
+must fix:
+ callm
+ chk
+*/
+/* ======================================================================== */
+/* ========================= LICENSING & COPYRIGHT ======================== */
+/* ======================================================================== */
+/*
+ * MUSASHI
+ * Version 3.31
+ *
+ * A portable Motorola M680x0 processor emulation engine.
+ * Copyright 1998-2007 Karl Stenerud. All rights reserved.
+ *
+ * This code may be freely used for non-commercial purposes as long as this
+ * copyright notice remains unaltered in the source code and any binary files
+ * containing this code in compiled form.
+ *
+ * All other lisencing terms must be negotiated with the author
+ * (Karl Stenerud).
+ *
+ * The latest version of this code can be obtained at:
+ * http://kstenerud.cjb.net
+ */
+
+/* Special thanks to Bart Trzynadlowski for his insight into the
+ * undocumented features of this chip:
+ *
+ * http://dynarec.com/~bart/files/68knotes.txt
+ */
+
+
+/* Input file for m68kmake
+ * -----------------------
+ *
+ * All sections begin with 80 X's in a row followed by an end-of-line
+ * sequence.
+ * After this, m68kmake will expect to find one of the following section
+ * identifiers:
+ * M68KMAKE_PROTOTYPE_HEADER - header for opcode handler prototypes
+ * M68KMAKE_PROTOTYPE_FOOTER - footer for opcode handler prototypes
+ * M68KMAKE_TABLE_HEADER - header for opcode handler jumptable
+ * M68KMAKE_TABLE_FOOTER - footer for opcode handler jumptable
+ * M68KMAKE_TABLE_BODY - the table itself
+ * M68KMAKE_OPCODE_HANDLER_HEADER - header for opcode handler implementation
+ * M68KMAKE_OPCODE_HANDLER_FOOTER - footer for opcode handler implementation
+ * M68KMAKE_OPCODE_HANDLER_BODY - body section for opcode handler implementation
+ *
+ * NOTE: M68KMAKE_OPCODE_HANDLER_BODY must be last in the file and
+ * M68KMAKE_TABLE_BODY must be second last in the file.
+ *
+ * The M68KMAKE_OPHANDLER_BODY section contains the opcode handler
+ * primitives themselves. Each opcode handler begins with:
+ * M68KMAKE_OP(A, B, C, D)
+ *
+ * where A is the opcode handler name, B is the size of the operation,
+ * C denotes any special processing mode, and D denotes a specific
+ * addressing mode.
+ * For C and D where nothing is specified, use "."
+ *
+ * Example:
+ * M68KMAKE_OP(abcd, 8, rr, .) abcd, size 8, register to register, default EA
+ * M68KMAKE_OP(abcd, 8, mm, ax7) abcd, size 8, memory to memory, register X is A7
+ * M68KMAKE_OP(tst, 16, ., pcix) tst, size 16, PCIX addressing
+ *
+ * All opcode handler primitives end with a closing curly brace "}" at column 1
+ *
+ * NOTE: Do not place a M68KMAKE_OP() directive inside the opcode handler,
+ * and do not put a closing curly brace at column 1 unless it is
+ * marking the end of the handler!
+ *
+ * Inside the handler, m68kmake will recognize M68KMAKE_GET_OPER_xx_xx,
+ * M68KMAKE_GET_EA_xx_xx, and M68KMAKE_CC directives, and create multiple
+ * opcode handlers to handle variations in the opcode handler.
+ * Note: M68KMAKE_CC will only be interpreted in condition code opcodes.
+ * As well, M68KMAKE_GET_EA_xx_xx and M68KMAKE_GET_OPER_xx_xx will only
+ * be interpreted on instructions where the corresponding table entry
+ * specifies multiple effective addressing modes.
+ * Example:
+ * clr 32 . . 0100001010...... A+-DXWL... U U U 12 6 4
+ *
+ * This table entry says that the clr.l opcde has 7 variations (A+-DXWL).
+ * It is run in user or supervisor mode for all CPUs, and uses 12 cycles for
+ * 68000, 6 cycles for 68010, and 4 cycles for 68020.
+ */
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+M68KMAKE_PROTOTYPE_HEADER
+
+#ifndef M68KOPS__HEADER
+#define M68KOPS__HEADER
+
+/* ======================================================================== */
+/* ============================ OPCODE HANDLERS =========================== */
+/* ======================================================================== */
+
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+M68KMAKE_PROTOTYPE_FOOTER
+
+
+/* Build the opcode handler table */
+void m68ki_build_opcode_table(void);
+
+extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */
+extern unsigned char m68ki_cycles[][0x10000];
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+#endif /* M68KOPS__HEADER */
+
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+M68KMAKE_TABLE_HEADER
+
+/* ======================================================================== */
+/* ========================= OPCODE TABLE BUILDER ========================= */
+/* ======================================================================== */
+
+#include "m68kops.h"
+
+#define NUM_CPU_TYPES 4
+
+void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */
+unsigned char m68ki_cycles[NUM_CPU_TYPES][0x10000]; /* Cycles used by CPU type */
+
+/* This is used to generate the opcode handler jump table */
+typedef struct
+{
+ void (*opcode_handler)(void); /* handler function */
+ unsigned int mask; /* mask on opcode */
+ unsigned int match; /* what to match after masking */
+ unsigned char cycles[NUM_CPU_TYPES]; /* cycles each cpu type takes */
+} opcode_handler_struct;
+
+
+/* Opcode handler table */
+static opcode_handler_struct m68k_opcode_handler_table[] =
+{
+/* function mask match 000 010 020 040 */
+
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+M68KMAKE_TABLE_FOOTER
+
+ {0, 0, 0, {0, 0, 0, 0}}
+};
+
+
+/* Build the opcode handler jump table */
+void m68ki_build_opcode_table(void)
+{
+ opcode_handler_struct *ostruct;
+ int instr;
+ int i;
+ int j;
+ int k;
+
+ for(i = 0; i < 0x10000; i++)
+ {
+ /* default to illegal */
+ m68ki_instruction_jump_table[i] = m68k_op_illegal;
+ for(k=0;k<NUM_CPU_TYPES;k++)
+ m68ki_cycles[k][i] = 0;
+ }
+
+ ostruct = m68k_opcode_handler_table;
+ while(ostruct->mask != 0xff00)
+ {
+ for(i = 0;i < 0x10000;i++)
+ {
+ if((i & ostruct->mask) == ostruct->match)
+ {
+ m68ki_instruction_jump_table[i] = ostruct->opcode_handler;
+ for(k=0;k<NUM_CPU_TYPES;k++)
+ m68ki_cycles[k][i] = ostruct->cycles[k];
+ }
+ }
+ ostruct++;
+ }
+ while(ostruct->mask == 0xff00)
+ {
+ for(i = 0;i <= 0xff;i++)
+ {
+ m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler;
+ for(k=0;k<NUM_CPU_TYPES;k++)
+ m68ki_cycles[k][ostruct->match | i] = ostruct->cycles[k];
+ }
+ ostruct++;
+ }
+ while(ostruct->mask == 0xf1f8)
+ {
+ for(i = 0;i < 8;i++)
+ {
+ for(j = 0;j < 8;j++)
+ {
+ instr = ostruct->match | (i << 9) | j;
+ m68ki_instruction_jump_table[instr] = ostruct->opcode_handler;
+ for(k=0;k<NUM_CPU_TYPES;k++)
+ m68ki_cycles[k][instr] = ostruct->cycles[k];
+ }
+ }
+ ostruct++;
+ }
+ while(ostruct->mask == 0xfff0)
+ {
+ for(i = 0;i <= 0x0f;i++)
+ {
+ m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler;
+ for(k=0;k<NUM_CPU_TYPES;k++)
+ m68ki_cycles[k][ostruct->match | i] = ostruct->cycles[k];
+ }
+ ostruct++;
+ }
+ while(ostruct->mask == 0xf1ff)
+ {
+ for(i = 0;i <= 0x07;i++)
+ {
+ m68ki_instruction_jump_table[ostruct->match | (i << 9)] = ostruct->opcode_handler;
+ for(k=0;k<NUM_CPU_TYPES;k++)
+ m68ki_cycles[k][ostruct->match | (i << 9)] = ostruct->cycles[k];
+ }
+ ostruct++;
+ }
+ while(ostruct->mask == 0xfff8)
+ {
+ for(i = 0;i <= 0x07;i++)
+ {
+ m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler;
+ for(k=0;k<NUM_CPU_TYPES;k++)
+ m68ki_cycles[k][ostruct->match | i] = ostruct->cycles[k];
+ }
+ ostruct++;
+ }
+ while(ostruct->mask == 0xffff)
+ {
+ m68ki_instruction_jump_table[ostruct->match] = ostruct->opcode_handler;
+ for(k=0;k<NUM_CPU_TYPES;k++)
+ m68ki_cycles[k][ostruct->match] = ostruct->cycles[k];
+ ostruct++;
+ }
+}
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+M68KMAKE_OPCODE_HANDLER_HEADER
+
+#include "m68kcpu.h"
+extern void m68040_fpu_op0(void);
+extern void m68040_fpu_op1(void);
+
+/* ======================================================================== */
+/* ========================= INSTRUCTION HANDLERS ========================= */
+/* ======================================================================== */
+
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+M68KMAKE_OPCODE_HANDLER_FOOTER
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+M68KMAKE_TABLE_BODY
+
+The following table is arranged as follows:
+
+name: Opcode mnemonic
+
+size: Operation size
+
+spec proc: Special processing mode:
+ .: normal
+ s: static operand
+ r: register operand
+ rr: register to register
+ mm: memory to memory
+ er: effective address to register
+ re: register to effective address
+ dd: data register to data register
+ da: data register to address register
+ aa: address register to address register
+ cr: control register to register
+ rc: register to control register
+ toc: to condition code register
+ tos: to status register
+ tou: to user stack pointer
+ frc: from condition code register
+ frs: from status register
+ fru: from user stack pointer
+ * for move.x, the special processing mode is a specific
+ destination effective addressing mode.
+
+spec ea: Specific effective addressing mode:
+ .: normal
+ i: immediate
+ d: data register
+ a: address register
+ ai: address register indirect
+ pi: address register indirect with postincrement
+ pd: address register indirect with predecrement
+ di: address register indirect with displacement
+ ix: address register indirect with index
+ aw: absolute word address
+ al: absolute long address
+ pcdi: program counter relative with displacement
+ pcix: program counter relative with index
+ a7: register specified in instruction is A7
+ ax7: register field X of instruction is A7
+ ay7: register field Y of instruction is A7
+ axy7: register fields X and Y of instruction are A7
+
+bit pattern: Pattern to recognize this opcode. "." means don't care.
+
+allowed ea: List of allowed addressing modes:
+ .: not present
+ A: address register indirect
+ +: ARI (address register indirect) with postincrement
+ -: ARI with predecrement
+ D: ARI with displacement
+ X: ARI with index
+ W: absolute word address
+ L: absolute long address
+ d: program counter indirect with displacement
+ x: program counter indirect with index
+ I: immediate
+mode: CPU operating mode for each cpu type. U = user or supervisor,
+ S = supervisor only, "." = opcode not present.
+
+cpu cycles: Base number of cycles required to execute this opcode on the
+ specified CPU type.
+ Use "." if CPU does not have this opcode.
+
+
+
+ spec spec allowed ea mode cpu cycles
+name size proc ea bit pattern A+-DXWLdxI 0 1 2 4 000 010 020 040 comments
+====== ==== ==== ==== ================ ========== = = = = === === === === =============
+M68KMAKE_TABLE_START
+1010 0 . . 1010............ .......... U U U U 4 4 4 4
+1111 0 . . 1111............ .......... U U U U 4 4 4 4
+040fpu0 32 . . 11110010........ .......... . . . U . . . 0
+040fpu1 32 . . 11110011........ .......... . . . U . . . 0
+abcd 8 rr . 1100...100000... .......... U U U U 6 6 4 4
+abcd 8 mm ax7 1100111100001... .......... U U U U 18 18 16 16
+abcd 8 mm ay7 1100...100001111 .......... U U U U 18 18 16 16
+abcd 8 mm axy7 1100111100001111 .......... U U U U 18 18 16 16
+abcd 8 mm . 1100...100001... .......... U U U U 18 18 16 16
+add 8 er d 1101...000000... .......... U U U U 4 4 2 2
+add 8 er . 1101...000...... A+-DXWLdxI U U U U 4 4 2 2
+add 16 er d 1101...001000... .......... U U U U 4 4 2 2
+add 16 er a 1101...001001... .......... U U U U 4 4 2 2
+add 16 er . 1101...001...... A+-DXWLdxI U U U U 4 4 2 2
+add 32 er d 1101...010000... .......... U U U U 6 6 2 2
+add 32 er a 1101...010001... .......... U U U U 6 6 2 2
+add 32 er . 1101...010...... A+-DXWLdxI U U U U 6 6 2 2
+add 8 re . 1101...100...... A+-DXWL... U U U U 8 8 4 4
+add 16 re . 1101...101...... A+-DXWL... U U U U 8 8 4 4
+add 32 re . 1101...110...... A+-DXWL... U U U U 12 12 4 4
+adda 16 . d 1101...011000... .......... U U U U 8 8 2 2
+adda 16 . a 1101...011001... .......... U U U U 8 8 2 2
+adda 16 . . 1101...011...... A+-DXWLdxI U U U U 8 8 2 2
+adda 32 . d 1101...111000... .......... U U U U 6 6 2 2
+adda 32 . a 1101...111001... .......... U U U U 6 6 2 2
+adda 32 . . 1101...111...... A+-DXWLdxI U U U U 6 6 2 2
+addi 8 . d 0000011000000... .......... U U U U 8 8 2 2
+addi 8 . . 0000011000...... A+-DXWL... U U U U 12 12 4 4
+addi 16 . d 0000011001000... .......... U U U U 8 8 2 2
+addi 16 . . 0000011001...... A+-DXWL... U U U U 12 12 4 4
+addi 32 . d 0000011010000... .......... U U U U 16 14 2 2
+addi 32 . . 0000011010...... A+-DXWL... U U U U 20 20 4 4
+addq 8 . d 0101...000000... .......... U U U U 4 4 2 2
+addq 8 . . 0101...000...... A+-DXWL... U U U U 8 8 4 4
+addq 16 . d 0101...001000... .......... U U U U 4 4 2 2
+addq 16 . a 0101...001001... .......... U U U U 4 4 2 2
+addq 16 . . 0101...001...... A+-DXWL... U U U U 8 8 4 4
+addq 32 . d 0101...010000... .......... U U U U 8 8 2 2
+addq 32 . a 0101...010001... .......... U U U U 8 8 2 2
+addq 32 . . 0101...010...... A+-DXWL... U U U U 12 12 4 4
+addx 8 rr . 1101...100000... .......... U U U U 4 4 2 2
+addx 16 rr . 1101...101000... .......... U U U U 4 4 2 2
+addx 32 rr . 1101...110000... .......... U U U U 8 6 2 2
+addx 8 mm ax7 1101111100001... .......... U U U U 18 18 12 12
+addx 8 mm ay7 1101...100001111 .......... U U U U 18 18 12 12
+addx 8 mm axy7 1101111100001111 .......... U U U U 18 18 12 12
+addx 8 mm . 1101...100001... .......... U U U U 18 18 12 12
+addx 16 mm . 1101...101001... .......... U U U U 18 18 12 12
+addx 32 mm . 1101...110001... .......... U U U U 30 30 12 12
+and 8 er d 1100...000000... .......... U U U U 4 4 2 2
+and 8 er . 1100...000...... A+-DXWLdxI U U U U 4 4 2 2
+and 16 er d 1100...001000... .......... U U U U 4 4 2 2
+and 16 er . 1100...001...... A+-DXWLdxI U U U U 4 4 2 2
+and 32 er d 1100...010000... .......... U U U U 6 6 2 2
+and 32 er . 1100...010...... A+-DXWLdxI U U U U 6 6 2 2
+and 8 re . 1100...100...... A+-DXWL... U U U U 8 8 4 4
+and 16 re . 1100...101...... A+-DXWL... U U U U 8 8 4 4
+and 32 re . 1100...110...... A+-DXWL... U U U U 12 12 4 4
+andi 16 toc . 0000001000111100 .......... U U U U 20 16 12 12
+andi 16 tos . 0000001001111100 .......... S S S S 20 16 12 12
+andi 8 . d 0000001000000... .......... U U U U 8 8 2 2
+andi 8 . . 0000001000...... A+-DXWL... U U U U 12 12 4 4
+andi 16 . d 0000001001000... .......... U U U U 8 8 2 2
+andi 16 . . 0000001001...... A+-DXWL... U U U U 12 12 4 4
+andi 32 . d 0000001010000... .......... U U U U 14 14 2 2
+andi 32 . . 0000001010...... A+-DXWL... U U U U 20 20 4 4
+asr 8 s . 1110...000000... .......... U U U U 6 6 6 6
+asr 16 s . 1110...001000... .......... U U U U 6 6 6 6
+asr 32 s . 1110...010000... .......... U U U U 8 8 6 6
+asr 8 r . 1110...000100... .......... U U U U 6 6 6 6
+asr 16 r . 1110...001100... .......... U U U U 6 6 6 6
+asr 32 r . 1110...010100... .......... U U U U 8 8 6 6
+asr 16 . . 1110000011...... A+-DXWL... U U U U 8 8 5 5
+asl 8 s . 1110...100000... .......... U U U U 6 6 8 8
+asl 16 s . 1110...101000... .......... U U U U 6 6 8 8
+asl 32 s . 1110...110000... .......... U U U U 8 8 8 8
+asl 8 r . 1110...100100... .......... U U U U 6 6 8 8
+asl 16 r . 1110...101100... .......... U U U U 6 6 8 8
+asl 32 r . 1110...110100... .......... U U U U 8 8 8 8
+asl 16 . . 1110000111...... A+-DXWL... U U U U 8 8 6 6
+bcc 8 . . 0110............ .......... U U U U 10 10 6 6
+bcc 16 . . 0110....00000000 .......... U U U U 10 10 6 6
+bcc 32 . . 0110....11111111 .......... U U U U 10 10 6 6
+bchg 8 r . 0000...101...... A+-DXWL... U U U U 8 8 4 4
+bchg 32 r d 0000...101000... .......... U U U U 8 8 4 4
+bchg 8 s . 0000100001...... A+-DXWL... U U U U 12 12 4 4
+bchg 32 s d 0000100001000... .......... U U U U 12 12 4 4
+bclr 8 r . 0000...110...... A+-DXWL... U U U U 8 10 4 4
+bclr 32 r d 0000...110000... .......... U U U U 10 10 4 4
+bclr 8 s . 0000100010...... A+-DXWL... U U U U 12 12 4 4
+bclr 32 s d 0000100010000... .......... U U U U 14 14 4 4
+bfchg 32 . d 1110101011000... .......... . . U U . . 12 12 timing not quite correct
+bfchg 32 . . 1110101011...... A..DXWL... . . U U . . 20 20
+bfclr 32 . d 1110110011000... .......... . . U U . . 12 12
+bfclr 32 . . 1110110011...... A..DXWL... . . U U . . 20 20
+bfexts 32 . d 1110101111000... .......... . . U U . . 8 8
+bfexts 32 . . 1110101111...... A..DXWLdx. . . U U . . 15 15
+bfextu 32 . d 1110100111000... .......... . . U U . . 8 8
+bfextu 32 . . 1110100111...... A..DXWLdx. . . U U . . 15 15
+bfffo 32 . d 1110110111000... .......... . . U U . . 18 18
+bfffo 32 . . 1110110111...... A..DXWLdx. . . U U . . 28 28
+bfins 32 . d 1110111111000... .......... . . U U . . 10 10
+bfins 32 . . 1110111111...... A..DXWL... . . U U . . 17 17
+bfset 32 . d 1110111011000... .......... . . U U . . 12 12
+bfset 32 . . 1110111011...... A..DXWL... . . U U . . 20 20
+bftst 32 . d 1110100011000... .......... . . U U . . 6 6
+bftst 32 . . 1110100011...... A..DXWLdx. . . U U . . 13 13
+bkpt 0 . . 0100100001001... .......... . U U U . 10 10 10
+bra 8 . . 01100000........ .......... U U U U 10 10 10 10
+bra 16 . . 0110000000000000 .......... U U U U 10 10 10 10
+bra 32 . . 0110000011111111 .......... U U U U 10 10 10 10
+bset 32 r d 0000...111000... .......... U U U U 8 8 4 4
+bset 8 r . 0000...111...... A+-DXWL... U U U U 8 8 4 4
+bset 8 s . 0000100011...... A+-DXWL... U U U U 12 12 4 4
+bset 32 s d 0000100011000... .......... U U U U 12 12 4 4
+bsr 8 . . 01100001........ .......... U U U U 18 18 7 7
+bsr 16 . . 0110000100000000 .......... U U U U 18 18 7 7
+bsr 32 . . 0110000111111111 .......... U U U U 18 18 7 7
+btst 8 r . 0000...100...... A+-DXWLdxI U U U U 4 4 4 4
+btst 32 r d 0000...100000... .......... U U U U 6 6 4 4
+btst 8 s . 0000100000...... A+-DXWLdx. U U U U 8 8 4 4
+btst 32 s d 0000100000000... .......... U U U U 10 10 4 4
+callm 32 . . 0000011011...... A..DXWLdx. . . U U . . 60 60 not properly emulated
+cas 8 . . 0000101011...... A+-DXWL... . . U U . . 12 12
+cas 16 . . 0000110011...... A+-DXWL... . . U U . . 12 12
+cas 32 . . 0000111011...... A+-DXWL... . . U U . . 12 12
+cas2 16 . . 0000110011111100 .......... . . U U . . 12 12
+cas2 32 . . 0000111011111100 .......... . . U U . . 12 12
+chk 16 . d 0100...110000... .......... U U U U 10 8 8 8
+chk 16 . . 0100...110...... A+-DXWLdxI U U U U 10 8 8 8
+chk 32 . d 0100...100000... .......... . . U U . . 8 8
+chk 32 . . 0100...100...... A+-DXWLdxI . . U U . . 8 8
+chk2cmp2 8 . pcdi 0000000011111010 .......... . . U U . . 23 23
+chk2cmp2 8 . pcix 0000000011111011 .......... . . U U . . 23 23
+chk2cmp2 8 . . 0000000011...... A..DXWL... . . U U . . 18 18
+chk2cmp2 16 . pcdi 0000001011111010 .......... . . U U . . 23 23
+chk2cmp2 16 . pcix 0000001011111011 .......... . . U U . . 23 23
+chk2cmp2 16 . . 0000001011...... A..DXWL... . . U U . . 18 18
+chk2cmp2 32 . pcdi 0000010011111010 .......... . . U U . . 23 23
+chk2cmp2 32 . pcix 0000010011111011 .......... . . U U . . 23 23
+chk2cmp2 32 . . 0000010011...... A..DXWL... . . U U . . 18 18
+clr 8 . d 0100001000000... .......... U U U U 4 4 2 2
+clr 8 . . 0100001000...... A+-DXWL... U U U U 8 4 4 4
+clr 16 . d 0100001001000... .......... U U U U 4 4 2 2
+clr 16 . . 0100001001...... A+-DXWL... U U U U 8 4 4 4
+clr 32 . d 0100001010000... .......... U U U U 6 6 2 2
+clr 32 . . 0100001010...... A+-DXWL... U U U U 12 6 4 4
+cmp 8 . d 1011...000000... .......... U U U U 4 4 2 2
+cmp 8 . . 1011...000...... A+-DXWLdxI U U U U 4 4 2 2
+cmp 16 . d 1011...001000... .......... U U U U 4 4 2 2
+cmp 16 . a 1011...001001... .......... U U U U 4 4 2 2
+cmp 16 . . 1011...001...... A+-DXWLdxI U U U U 4 4 2 2
+cmp 32 . d 1011...010000... .......... U U U U 6 6 2 2
+cmp 32 . a 1011...010001... .......... U U U U 6 6 2 2
+cmp 32 . . 1011...010...... A+-DXWLdxI U U U U 6 6 2 2
+cmpa 16 . d 1011...011000... .......... U U U U 6 6 4 4
+cmpa 16 . a 1011...011001... .......... U U U U 6 6 4 4
+cmpa 16 . . 1011...011...... A+-DXWLdxI U U U U 6 6 4 4
+cmpa 32 . d 1011...111000... .......... U U U U 6 6 4 4
+cmpa 32 . a 1011...111001... .......... U U U U 6 6 4 4
+cmpa 32 . . 1011...111...... A+-DXWLdxI U U U U 6 6 4 4
+cmpi 8 . d 0000110000000... .......... U U U U 8 8 2 2
+cmpi 8 . . 0000110000...... A+-DXWL... U U U U 8 8 2 2
+cmpi 8 . pcdi 0000110000111010 .......... . . U U . . 7 7
+cmpi 8 . pcix 0000110000111011 .......... . . U U . . 9 9
+cmpi 16 . d 0000110001000... .......... U U U U 8 8 2 2
+cmpi 16 . . 0000110001...... A+-DXWL... U U U U 8 8 2 2
+cmpi 16 . pcdi 0000110001111010 .......... . . U U . . 7 7
+cmpi 16 . pcix 0000110001111011 .......... . . U U . . 9 9
+cmpi 32 . d 0000110010000... .......... U U U U 14 12 2 2
+cmpi 32 . . 0000110010...... A+-DXWL... U U U U 12 12 2 2
+cmpi 32 . pcdi 0000110010111010 .......... . . U U . . 7 7
+cmpi 32 . pcix 0000110010111011 .......... . . U U . . 9 9
+cmpm 8 . ax7 1011111100001... .......... U U U U 12 12 9 9
+cmpm 8 . ay7 1011...100001111 .......... U U U U 12 12 9 9
+cmpm 8 . axy7 1011111100001111 .......... U U U U 12 12 9 9
+cmpm 8 . . 1011...100001... .......... U U U U 12 12 9 9
+cmpm 16 . . 1011...101001... .......... U U U U 12 12 9 9
+cmpm 32 . . 1011...110001... .......... U U U U 20 20 9 9
+cpbcc 32 . . 1111...01....... .......... . . U . . . 4 . unemulated
+cpdbcc 32 . . 1111...001001... .......... . . U . . . 4 . unemulated
+cpgen 32 . . 1111...000...... .......... . . U . . . 4 . unemulated
+cpscc 32 . . 1111...001...... .......... . . U . . . 4 . unemulated
+cptrapcc 32 . . 1111...001111... .......... . . U . . . 4 . unemulated
+dbt 16 . . 0101000011001... .......... U U U U 12 12 6 6
+dbf 16 . . 0101000111001... .......... U U U U 12 12 6 6
+dbcc 16 . . 0101....11001... .......... U U U U 12 12 6 6
+divs 16 . d 1000...111000... .......... U U U U 158 122 56 56
+divs 16 . . 1000...111...... A+-DXWLdxI U U U U 158 122 56 56
+divu 16 . d 1000...011000... .......... U U U U 140 108 44 44
+divu 16 . . 1000...011...... A+-DXWLdxI U U U U 140 108 44 44
+divl 32 . d 0100110001000... .......... . . U U . . 84 84
+divl 32 . . 0100110001...... A+-DXWLdxI . . U U . . 84 84
+eor 8 . d 1011...100000... .......... U U U U 4 4 2 2
+eor 8 . . 1011...100...... A+-DXWL... U U U U 8 8 4 4
+eor 16 . d 1011...101000... .......... U U U U 4 4 2 2
+eor 16 . . 1011...101...... A+-DXWL... U U U U 8 8 4 4
+eor 32 . d 1011...110000... .......... U U U U 8 6 2 2
+eor 32 . . 1011...110...... A+-DXWL... U U U U 12 12 4 4
+eori 16 toc . 0000101000111100 .......... U U U U 20 16 12 12
+eori 16 tos . 0000101001111100 .......... S S S S 20 16 12 12
+eori 8 . d 0000101000000... .......... U U U U 8 8 2 2
+eori 8 . . 0000101000...... A+-DXWL... U U U U 12 12 4 4
+eori 16 . d 0000101001000... .......... U U U U 8 8 2 2
+eori 16 . . 0000101001...... A+-DXWL... U U U U 12 12 4 4
+eori 32 . d 0000101010000... .......... U U U U 16 14 2 2
+eori 32 . . 0000101010...... A+-DXWL... U U U U 20 20 4 4
+exg 32 dd . 1100...101000... .......... U U U U 6 6 2 2
+exg 32 aa . 1100...101001... .......... U U U U 6 6 2 2
+exg 32 da . 1100...110001... .......... U U U U 6 6 2 2
+ext 16 . . 0100100010000... .......... U U U U 4 4 4 4
+ext 32 . . 0100100011000... .......... U U U U 4 4 4 4
+extb 32 . . 0100100111000... .......... . . U U . . 4 4
+illegal 0 . . 0100101011111100 .......... U U U U 4 4 4 4
+jmp 32 . . 0100111011...... A..DXWLdx. U U U U 4 4 0 0
+jsr 32 . . 0100111010...... A..DXWLdx. U U U U 12 12 0 0
+lea 32 . . 0100...111...... A..DXWLdx. U U U U 0 0 2 2
+link 16 . a7 0100111001010111 .......... U U U U 16 16 5 5
+link 16 . . 0100111001010... .......... U U U U 16 16 5 5
+link 32 . a7 0100100000001111 .......... . . U U . . 6 6
+link 32 . . 0100100000001... .......... . . U U . . 6 6
+lsr 8 s . 1110...000001... .......... U U U U 6 6 4 4
+lsr 16 s . 1110...001001... .......... U U U U 6 6 4 4
+lsr 32 s . 1110...010001... .......... U U U U 8 8 4 4
+lsr 8 r . 1110...000101... .......... U U U U 6 6 6 6
+lsr 16 r . 1110...001101... .......... U U U U 6 6 6 6
+lsr 32 r . 1110...010101... .......... U U U U 8 8 6 6
+lsr 16 . . 1110001011...... A+-DXWL... U U U U 8 8 5 5
+lsl 8 s . 1110...100001... .......... U U U U 6 6 4 4
+lsl 16 s . 1110...101001... .......... U U U U 6 6 4 4
+lsl 32 s . 1110...110001... .......... U U U U 8 8 4 4
+lsl 8 r . 1110...100101... .......... U U U U 6 6 6 6
+lsl 16 r . 1110...101101... .......... U U U U 6 6 6 6
+lsl 32 r . 1110...110101... .......... U U U U 8 8 6 6
+lsl 16 . . 1110001111...... A+-DXWL... U U U U 8 8 5 5
+move 8 d d 0001...000000... .......... U U U U 4 4 2 2
+move 8 d . 0001...000...... A+-DXWLdxI U U U U 4 4 2 2
+move 8 ai d 0001...010000... .......... U U U U 8 8 4 4
+move 8 ai . 0001...010...... A+-DXWLdxI U U U U 8 8 4 4
+move 8 pi d 0001...011000... .......... U U U U 8 8 4 4
+move 8 pi . 0001...011...... A+-DXWLdxI U U U U 8 8 4 4
+move 8 pi7 d 0001111011000... .......... U U U U 8 8 4 4
+move 8 pi7 . 0001111011...... A+-DXWLdxI U U U U 8 8 4 4
+move 8 pd d 0001...100000... .......... U U U U 8 8 5 5
+move 8 pd . 0001...100...... A+-DXWLdxI U U U U 8 8 5 5
+move 8 pd7 d 0001111100000... .......... U U U U 8 8 5 5
+move 8 pd7 . 0001111100...... A+-DXWLdxI U U U U 8 8 5 5
+move 8 di d 0001...101000... .......... U U U U 12 12 5 5
+move 8 di . 0001...101...... A+-DXWLdxI U U U U 12 12 5 5
+move 8 ix d 0001...110000... .......... U U U U 14 14 7 7
+move 8 ix . 0001...110...... A+-DXWLdxI U U U U 14 14 7 7
+move 8 aw d 0001000111000... .......... U U U U 12 12 4 4
+move 8 aw . 0001000111...... A+-DXWLdxI U U U U 12 12 4 4
+move 8 al d 0001001111000... .......... U U U U 16 16 6 6
+move 8 al . 0001001111...... A+-DXWLdxI U U U U 16 16 6 6
+move 16 d d 0011...000000... .......... U U U U 4 4 2 2
+move 16 d a 0011...000001... .......... U U U U 4 4 2 2
+move 16 d . 0011...000...... A+-DXWLdxI U U U U 4 4 2 2
+move 16 ai d 0011...010000... .......... U U U U 8 8 4 4
+move 16 ai a 0011...010001... .......... U U U U 8 8 4 4
+move 16 ai . 0011...010...... A+-DXWLdxI U U U U 8 8 4 4
+move 16 pi d 0011...011000... .......... U U U U 8 8 4 4
+move 16 pi a 0011...011001... .......... U U U U 8 8 4 4
+move 16 pi . 0011...011...... A+-DXWLdxI U U U U 8 8 4 4
+move 16 pd d 0011...100000... .......... U U U U 8 8 5 5
+move 16 pd a 0011...100001... .......... U U U U 8 8 5 5
+move 16 pd . 0011...100...... A+-DXWLdxI U U U U 8 8 5 5
+move 16 di d 0011...101000... .......... U U U U 12 12 5 5
+move 16 di a 0011...101001... .......... U U U U 12 12 5 5
+move 16 di . 0011...101...... A+-DXWLdxI U U U U 12 12 5 5
+move 16 ix d 0011...110000... .......... U U U U 14 14 7 7
+move 16 ix a 0011...110001... .......... U U U U 14 14 7 7
+move 16 ix . 0011...110...... A+-DXWLdxI U U U U 14 14 7 7
+move 16 aw d 0011000111000... .......... U U U U 12 12 4 4
+move 16 aw a 0011000111001... .......... U U U U 12 12 4 4
+move 16 aw . 0011000111...... A+-DXWLdxI U U U U 12 12 4 4
+move 16 al d 0011001111000... .......... U U U U 16 16 6 6
+move 16 al a 0011001111001... .......... U U U U 16 16 6 6
+move 16 al . 0011001111...... A+-DXWLdxI U U U U 16 16 6 6
+move 32 d d 0010...000000... .......... U U U U 4 4 2 2
+move 32 d a 0010...000001... .......... U U U U 4 4 2 2
+move 32 d . 0010...000...... A+-DXWLdxI U U U U 4 4 2 2
+move 32 ai d 0010...010000... .......... U U U U 12 12 4 4
+move 32 ai a 0010...010001... .......... U U U U 12 12 4 4
+move 32 ai . 0010...010...... A+-DXWLdxI U U U U 12 12 4 4
+move 32 pi d 0010...011000... .......... U U U U 12 12 4 4
+move 32 pi a 0010...011001... .......... U U U U 12 12 4 4
+move 32 pi . 0010...011...... A+-DXWLdxI U U U U 12 12 4 4
+move 32 pd d 0010...100000... .......... U U U U 12 14 5 5
+move 32 pd a 0010...100001... .......... U U U U 12 14 5 5
+move 32 pd . 0010...100...... A+-DXWLdxI U U U U 12 14 5 5
+move 32 di d 0010...101000... .......... U U U U 16 16 5 5
+move 32 di a 0010...101001... .......... U U U U 16 16 5 5
+move 32 di . 0010...101...... A+-DXWLdxI U U U U 16 16 5 5
+move 32 ix d 0010...110000... .......... U U U U 18 18 7 7
+move 32 ix a 0010...110001... .......... U U U U 18 18 7 7
+move 32 ix . 0010...110...... A+-DXWLdxI U U U U 18 18 7 7
+move 32 aw d 0010000111000... .......... U U U U 16 16 4 4
+move 32 aw a 0010000111001... .......... U U U U 16 16 4 4
+move 32 aw . 0010000111...... A+-DXWLdxI U U U U 16 16 4 4
+move 32 al d 0010001111000... .......... U U U U 20 20 6 6
+move 32 al a 0010001111001... .......... U U U U 20 20 6 6
+move 32 al . 0010001111...... A+-DXWLdxI U U U U 20 20 6 6
+movea 16 . d 0011...001000... .......... U U U U 4 4 2 2
+movea 16 . a 0011...001001... .......... U U U U 4 4 2 2
+movea 16 . . 0011...001...... A+-DXWLdxI U U U U 4 4 2 2
+movea 32 . d 0010...001000... .......... U U U U 4 4 2 2
+movea 32 . a 0010...001001... .......... U U U U 4 4 2 2
+movea 32 . . 0010...001...... A+-DXWLdxI U U U U 4 4 2 2
+move 16 frc d 0100001011000... .......... . U U U . 4 4 4
+move 16 frc . 0100001011...... A+-DXWL... . U U U . 8 4 4
+move 16 toc d 0100010011000... .......... U U U U 12 12 4 4
+move 16 toc . 0100010011...... A+-DXWLdxI U U U U 12 12 4 4
+move 16 frs d 0100000011000... .......... U S S S 6 4 8 8 U only for 000
+move 16 frs . 0100000011...... A+-DXWL... U S S S 8 8 8 8 U only for 000
+move 16 tos d 0100011011000... .......... S S S S 12 12 8 8
+move 16 tos . 0100011011...... A+-DXWLdxI S S S S 12 12 8 8
+move 32 fru . 0100111001101... .......... S S S S 4 6 2 2
+move 32 tou . 0100111001100... .......... S S S S 4 6 2 2
+movec 32 cr . 0100111001111010 .......... . S S S . 12 6 6
+movec 32 rc . 0100111001111011 .......... . S S S . 10 12 12
+movem 16 re pd 0100100010100... .......... U U U U 8 8 4 4
+movem 16 re . 0100100010...... A..DXWL... U U U U 8 8 4 4
+movem 32 re pd 0100100011100... .......... U U U U 8 8 4 4
+movem 32 re . 0100100011...... A..DXWL... U U U U 8 8 4 4
+movem 16 er pi 0100110010011... .......... U U U U 12 12 8 8
+movem 16 er pcdi 0100110010111010 .......... U U U U 16 16 9 9
+movem 16 er pcix 0100110010111011 .......... U U U U 18 18 11 11
+movem 16 er . 0100110010...... A..DXWL... U U U U 12 12 8 8
+movem 32 er pi 0100110011011... .......... U U U U 12 12 8 8
+movem 32 er pcdi 0100110011111010 .......... U U U U 16 16 9 9
+movem 32 er pcix 0100110011111011 .......... U U U U 18 18 11 11
+movem 32 er . 0100110011...... A..DXWL... U U U U 12 12 8 8
+movep 16 er . 0000...100001... .......... U U U U 16 16 12 12
+movep 32 er . 0000...101001... .......... U U U U 24 24 18 18
+movep 16 re . 0000...110001... .......... U U U U 16 16 11 11
+movep 32 re . 0000...111001... .......... U U U U 24 24 17 17
+moveq 32 . . 0111...0........ .......... U U U U 4 4 2 2
+moves 8 . . 0000111000...... A+-DXWL... . S S S . 14 5 5
+moves 16 . . 0000111001...... A+-DXWL... . S S S . 14 5 5
+moves 32 . . 0000111010...... A+-DXWL... . S S S . 16 5 5
+move16 32 . . 1111011000100... .......... . . . U . . . 4 TODO: correct timing
+muls 16 . d 1100...111000... .......... U U U U 54 32 27 27
+muls 16 . . 1100...111...... A+-DXWLdxI U U U U 54 32 27 27
+mulu 16 . d 1100...011000... .......... U U U U 54 30 27 27
+mulu 16 . . 1100...011...... A+-DXWLdxI U U U U 54 30 27 27
+mull 32 . d 0100110000000... .......... . . U U . . 43 43
+mull 32 . . 0100110000...... A+-DXWLdxI . . U U . . 43 43
+nbcd 8 . d 0100100000000... .......... U U U U 6 6 6 6
+nbcd 8 . . 0100100000...... A+-DXWL... U U U U 8 8 6 6
+neg 8 . d 0100010000000... .......... U U U U 4 4 2 2
+neg 8 . . 0100010000...... A+-DXWL... U U U U 8 8 4 4
+neg 16 . d 0100010001000... .......... U U U U 4 4 2 2
+neg 16 . . 0100010001...... A+-DXWL... U U U U 8 8 4 4
+neg 32 . d 0100010010000... .......... U U U U 6 6 2 2
+neg 32 . . 0100010010...... A+-DXWL... U U U U 12 12 4 4
+negx 8 . d 0100000000000... .......... U U U U 4 4 2 2
+negx 8 . . 0100000000...... A+-DXWL... U U U U 8 8 4 4
+negx 16 . d 0100000001000... .......... U U U U 4 4 2 2
+negx 16 . . 0100000001...... A+-DXWL... U U U U 8 8 4 4
+negx 32 . d 0100000010000... .......... U U U U 6 6 2 2
+negx 32 . . 0100000010...... A+-DXWL... U U U U 12 12 4 4
+nop 0 . . 0100111001110001 .......... U U U U 4 4 2 2
+not 8 . d 0100011000000... .......... U U U U 4 4 2 2
+not 8 . . 0100011000...... A+-DXWL... U U U U 8 8 4 4
+not 16 . d 0100011001000... .......... U U U U 4 4 2 2
+not 16 . . 0100011001...... A+-DXWL... U U U U 8 8 4 4
+not 32 . d 0100011010000... .......... U U U U 6 6 2 2
+not 32 . . 0100011010...... A+-DXWL... U U U U 12 12 4 4
+or 8 er d 1000...000000... .......... U U U U 4 4 2 2
+or 8 er . 1000...000...... A+-DXWLdxI U U U U 4 4 2 2
+or 16 er d 1000...001000... .......... U U U U 4 4 2 2
+or 16 er . 1000...001...... A+-DXWLdxI U U U U 4 4 2 2
+or 32 er d 1000...010000... .......... U U U U 6 6 2 2
+or 32 er . 1000...010...... A+-DXWLdxI U U U U 6 6 2 2
+or 8 re . 1000...100...... A+-DXWL... U U U U 8 8 4 4
+or 16 re . 1000...101...... A+-DXWL... U U U U 8 8 4 4
+or 32 re . 1000...110...... A+-DXWL... U U U U 12 12 4 4
+ori 16 toc . 0000000000111100 .......... U U U U 20 16 12 12
+ori 16 tos . 0000000001111100 .......... S S S S 20 16 12 12
+ori 8 . d 0000000000000... .......... U U U U 8 8 2 2
+ori 8 . . 0000000000...... A+-DXWL... U U U U 12 12 4 4
+ori 16 . d 0000000001000... .......... U U U U 8 8 2 2
+ori 16 . . 0000000001...... A+-DXWL... U U U U 12 12 4 4
+ori 32 . d 0000000010000... .......... U U U U 16 14 2 2
+ori 32 . . 0000000010...... A+-DXWL... U U U U 20 20 4 4
+pack 16 rr . 1000...101000... .......... . . U U . . 6 6
+pack 16 mm ax7 1000111101001... .......... . . U U . . 13 13
+pack 16 mm ay7 1000...101001111 .......... . . U U . . 13 13
+pack 16 mm axy7 1000111101001111 .......... . . U U . . 13 13
+pack 16 mm . 1000...101001... .......... . . U U . . 13 13
+pea 32 . . 0100100001...... A..DXWLdx. U U U U 6 6 5 5
+pflush 32 . . 1111010100011000 .......... . . . S . . . 4 TODO: correct timing
+reset 0 . . 0100111001110000 .......... S S S S 0 0 0 0
+ror 8 s . 1110...000011... .......... U U U U 6 6 8 8
+ror 16 s . 1110...001011... .......... U U U U 6 6 8 8
+ror 32 s . 1110...010011... .......... U U U U 8 8 8 8
+ror 8 r . 1110...000111... .......... U U U U 6 6 8 8
+ror 16 r . 1110...001111... .......... U U U U 6 6 8 8
+ror 32 r . 1110...010111... .......... U U U U 8 8 8 8
+ror 16 . . 1110011011...... A+-DXWL... U U U U 8 8 7 7
+rol 8 s . 1110...100011... .......... U U U U 6 6 8 8
+rol 16 s . 1110...101011... .......... U U U U 6 6 8 8
+rol 32 s . 1110...110011... .......... U U U U 8 8 8 8
+rol 8 r . 1110...100111... .......... U U U U 6 6 8 8
+rol 16 r . 1110...101111... .......... U U U U 6 6 8 8
+rol 32 r . 1110...110111... .......... U U U U 8 8 8 8
+rol 16 . . 1110011111...... A+-DXWL... U U U U 8 8 7 7
+roxr 8 s . 1110...000010... .......... U U U U 6 6 12 12
+roxr 16 s . 1110...001010... .......... U U U U 6 6 12 12
+roxr 32 s . 1110...010010... .......... U U U U 8 8 12 12
+roxr 8 r . 1110...000110... .......... U U U U 6 6 12 12
+roxr 16 r . 1110...001110... .......... U U U U 6 6 12 12
+roxr 32 r . 1110...010110... .......... U U U U 8 8 12 12
+roxr 16 . . 1110010011...... A+-DXWL... U U U U 8 8 5 5
+roxl 8 s . 1110...100010... .......... U U U U 6 6 12 12
+roxl 16 s . 1110...101010... .......... U U U U 6 6 12 12
+roxl 32 s . 1110...110010... .......... U U U U 8 8 12 12
+roxl 8 r . 1110...100110... .......... U U U U 6 6 12 12
+roxl 16 r . 1110...101110... .......... U U U U 6 6 12 12
+roxl 32 r . 1110...110110... .......... U U U U 8 8 12 12
+roxl 16 . . 1110010111...... A+-DXWL... U U U U 8 8 5 5
+rtd 32 . . 0100111001110100 .......... . U U U . 16 10 10
+rte 32 . . 0100111001110011 .......... S S S S 20 24 20 20 bus fault not emulated
+rtm 32 . . 000001101100.... .......... . . U U . . 19 19 not properly emulated
+rtr 32 . . 0100111001110111 .......... U U U U 20 20 14 14
+rts 32 . . 0100111001110101 .......... U U U U 16 16 10 10
+sbcd 8 rr . 1000...100000... .......... U U U U 6 6 4 4
+sbcd 8 mm ax7 1000111100001... .......... U U U U 18 18 16 16
+sbcd 8 mm ay7 1000...100001111 .......... U U U U 18 18 16 16
+sbcd 8 mm axy7 1000111100001111 .......... U U U U 18 18 16 16
+sbcd 8 mm . 1000...100001... .......... U U U U 18 18 16 16
+st 8 . d 0101000011000... .......... U U U U 6 4 4 4
+st 8 . . 0101000011...... A+-DXWL... U U U U 8 8 6 6
+sf 8 . d 0101000111000... .......... U U U U 4 4 4 4
+sf 8 . . 0101000111...... A+-DXWL... U U U U 8 8 6 6
+scc 8 . d 0101....11000... .......... U U U U 4 4 4 4
+scc 8 . . 0101....11...... A+-DXWL... U U U U 8 8 6 6
+stop 0 . . 0100111001110010 .......... S S S S 4 4 8 8
+sub 8 er d 1001...000000... .......... U U U U 4 4 2 2
+sub 8 er . 1001...000...... A+-DXWLdxI U U U U 4 4 2 2
+sub 16 er d 1001...001000... .......... U U U U 4 4 2 2
+sub 16 er a 1001...001001... .......... U U U U 4 4 2 2
+sub 16 er . 1001...001...... A+-DXWLdxI U U U U 4 4 2 2
+sub 32 er d 1001...010000... .......... U U U U 6 6 2 2
+sub 32 er a 1001...010001... .......... U U U U 6 6 2 2
+sub 32 er . 1001...010...... A+-DXWLdxI U U U U 6 6 2 2
+sub 8 re . 1001...100...... A+-DXWL... U U U U 8 8 4 4
+sub 16 re . 1001...101...... A+-DXWL... U U U U 8 8 4 4
+sub 32 re . 1001...110...... A+-DXWL... U U U U 12 12 4 4
+suba 16 . d 1001...011000... .......... U U U U 8 8 2 2
+suba 16 . a 1001...011001... .......... U U U U 8 8 2 2
+suba 16 . . 1001...011...... A+-DXWLdxI U U U U 8 8 2 2
+suba 32 . d 1001...111000... .......... U U U U 6 6 2 2
+suba 32 . a 1001...111001... .......... U U U U 6 6 2 2
+suba 32 . . 1001...111...... A+-DXWLdxI U U U U 6 6 2 2
+subi 8 . d 0000010000000... .......... U U U U 8 8 2 2
+subi 8 . . 0000010000...... A+-DXWL... U U U U 12 12 4 4
+subi 16 . d 0000010001000... .......... U U U U 8 8 2 2
+subi 16 . . 0000010001...... A+-DXWL... U U U U 12 12 4 4
+subi 32 . d 0000010010000... .......... U U U U 16 14 2 2
+subi 32 . . 0000010010...... A+-DXWL... U U U U 20 20 4 4
+subq 8 . d 0101...100000... .......... U U U U 4 4 2 2
+subq 8 . . 0101...100...... A+-DXWL... U U U U 8 8 4 4
+subq 16 . d 0101...101000... .......... U U U U 4 4 2 2
+subq 16 . a 0101...101001... .......... U U U U 8 4 2 2
+subq 16 . . 0101...101...... A+-DXWL... U U U U 8 8 4 4
+subq 32 . d 0101...110000... .......... U U U U 8 8 2 2
+subq 32 . a 0101...110001... .......... U U U U 8 8 2 2
+subq 32 . . 0101...110...... A+-DXWL... U U U U 12 12 4 4
+subx 8 rr . 1001...100000... .......... U U U U 4 4 2 2
+subx 16 rr . 1001...101000... .......... U U U U 4 4 2 2
+subx 32 rr . 1001...110000... .......... U U U U 8 6 2 2
+subx 8 mm ax7 1001111100001... .......... U U U U 18 18 12 12
+subx 8 mm ay7 1001...100001111 .......... U U U U 18 18 12 12
+subx 8 mm axy7 1001111100001111 .......... U U U U 18 18 12 12
+subx 8 mm . 1001...100001... .......... U U U U 18 18 12 12
+subx 16 mm . 1001...101001... .......... U U U U 18 18 12 12
+subx 32 mm . 1001...110001... .......... U U U U 30 30 12 12
+swap 32 . . 0100100001000... .......... U U U U 4 4 4 4
+tas 8 . d 0100101011000... .......... U U U U 4 4 4 4
+tas 8 . . 0100101011...... A+-DXWL... U U U U 14 14 12 12
+trap 0 . . 010011100100.... .......... U U U U 4 4 4 4
+trapt 0 . . 0101000011111100 .......... . . U U . . 4 4
+trapt 16 . . 0101000011111010 .......... . . U U . . 6 6
+trapt 32 . . 0101000011111011 .......... . . U U . . 8 8
+trapf 0 . . 0101000111111100 .......... . . U U . . 4 4
+trapf 16 . . 0101000111111010 .......... . . U U . . 6 6
+trapf 32 . . 0101000111111011 .......... . . U U . . 8 8
+trapcc 0 . . 0101....11111100 .......... . . U U . . 4 4
+trapcc 16 . . 0101....11111010 .......... . . U U . . 6 6
+trapcc 32 . . 0101....11111011 .......... . . U U . . 8 8
+trapv 0 . . 0100111001110110 .......... U U U U 4 4 4 4
+tst 8 . d 0100101000000... .......... U U U U 4 4 2 2
+tst 8 . . 0100101000...... A+-DXWL... U U U U 4 4 2 2
+tst 8 . pcdi 0100101000111010 .......... . . U U . . 7 7
+tst 8 . pcix 0100101000111011 .......... . . U U . . 9 9
+tst 8 . i 0100101000111100 .......... . . U U . . 6 6
+tst 16 . d 0100101001000... .......... U U U U 4 4 2 2
+tst 16 . a 0100101001001... .......... . . U U . . 2 2
+tst 16 . . 0100101001...... A+-DXWL... U U U U 4 4 2 2
+tst 16 . pcdi 0100101001111010 .......... . . U U . . 7 7
+tst 16 . pcix 0100101001111011 .......... . . U U . . 9 9
+tst 16 . i 0100101001111100 .......... . . U U . . 6 6
+tst 32 . d 0100101010000... .......... U U U U 4 4 2 2
+tst 32 . a 0100101010001... .......... . . U U . . 2 2
+tst 32 . . 0100101010...... A+-DXWL... U U U U 4 4 2 2
+tst 32 . pcdi 0100101010111010 .......... . . U U . . 7 7
+tst 32 . pcix 0100101010111011 .......... . . U U . . 9 9
+tst 32 . i 0100101010111100 .......... . . U U . . 6 6
+unlk 32 . a7 0100111001011111 .......... U U U U 12 12 6 6
+unlk 32 . . 0100111001011... .......... U U U U 12 12 6 6
+unpk 16 rr . 1000...110000... .......... . . U U . . 8 8
+unpk 16 mm ax7 1000111110001... .......... . . U U . . 13 13
+unpk 16 mm ay7 1000...110001111 .......... . . U U . . 13 13
+unpk 16 mm axy7 1000111110001111 .......... . . U U . . 13 13
+unpk 16 mm . 1000...110001... .......... . . U U . . 13 13
+
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+M68KMAKE_OPCODE_HANDLER_BODY
+
+M68KMAKE_OP(1010, 0, ., .)
+{
+ m68ki_exception_1010();
+}
+
+
+M68KMAKE_OP(1111, 0, ., .)
+{
+ m68ki_exception_1111();
+}
+
+
+M68KMAKE_OP(040fpu0, 32, ., .)
+{
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ m68040_fpu_op0();
+ return;
+ }
+ m68ki_exception_1111();
+}
+
+
+M68KMAKE_OP(040fpu1, 32, ., .)
+{
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ m68040_fpu_op1();
+ return;
+ }
+ m68ki_exception_1111();
+}
+
+
+
+M68KMAKE_OP(abcd, 8, rr, .)
+{
+ uint* r_dst = &DX;
+ uint src = DY;
+ uint dst = *r_dst;
+ uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
+
+ FLAG_V = ~res; /* Undefined V behavior */
+
+ if(res > 9)
+ res += 6;
+ res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
+ FLAG_X = FLAG_C = (res > 0x99) << 8;
+ if(FLAG_C)
+ res -= 0xa0;
+
+ FLAG_V &= res; /* Undefined V behavior part II */
+ FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+}
+
+
+M68KMAKE_OP(abcd, 8, mm, ax7)
+{
+ uint src = OPER_AY_PD_8();
+ uint ea = EA_A7_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
+
+ FLAG_V = ~res; /* Undefined V behavior */
+
+ if(res > 9)
+ res += 6;
+ res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
+ FLAG_X = FLAG_C = (res > 0x99) << 8;
+ if(FLAG_C)
+ res -= 0xa0;
+
+ FLAG_V &= res; /* Undefined V behavior part II */
+ FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(abcd, 8, mm, ay7)
+{
+ uint src = OPER_A7_PD_8();
+ uint ea = EA_AX_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
+
+ FLAG_V = ~res; /* Undefined V behavior */
+
+ if(res > 9)
+ res += 6;
+ res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
+ FLAG_X = FLAG_C = (res > 0x99) << 8;
+ if(FLAG_C)
+ res -= 0xa0;
+
+ FLAG_V &= res; /* Undefined V behavior part II */
+ FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(abcd, 8, mm, axy7)
+{
+ uint src = OPER_A7_PD_8();
+ uint ea = EA_A7_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
+
+ FLAG_V = ~res; /* Undefined V behavior */
+
+ if(res > 9)
+ res += 6;
+ res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
+ FLAG_X = FLAG_C = (res > 0x99) << 8;
+ if(FLAG_C)
+ res -= 0xa0;
+
+ FLAG_V &= res; /* Undefined V behavior part II */
+ FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(abcd, 8, mm, .)
+{
+ uint src = OPER_AY_PD_8();
+ uint ea = EA_AX_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
+
+ FLAG_V = ~res; /* Undefined V behavior */
+
+ if(res > 9)
+ res += 6;
+ res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
+ FLAG_X = FLAG_C = (res > 0x99) << 8;
+ if(FLAG_C)
+ res -= 0xa0;
+
+ FLAG_V &= res; /* Undefined V behavior part II */
+ FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(add, 8, er, d)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_8(DY);
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(add, 8, er, .)
+{
+ uint* r_dst = &DX;
+ uint src = M68KMAKE_GET_OPER_AY_8;
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(add, 16, er, d)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_16(DY);
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(add, 16, er, a)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_16(AY);
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(add, 16, er, .)
+{
+ uint* r_dst = &DX;
+ uint src = M68KMAKE_GET_OPER_AY_16;
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(add, 32, er, d)
+{
+ uint* r_dst = &DX;
+ uint src = DY;
+ uint dst = *r_dst;
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(add, 32, er, a)
+{
+ uint* r_dst = &DX;
+ uint src = AY;
+ uint dst = *r_dst;
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(add, 32, er, .)
+{
+ uint* r_dst = &DX;
+ uint src = M68KMAKE_GET_OPER_AY_32;
+ uint dst = *r_dst;
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(add, 8, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = MASK_OUT_ABOVE_8(DX);
+ uint dst = m68ki_read_8(ea);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ m68ki_write_8(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(add, 16, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = MASK_OUT_ABOVE_16(DX);
+ uint dst = m68ki_read_16(ea);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ m68ki_write_16(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(add, 32, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint src = DX;
+ uint dst = m68ki_read_32(ea);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ m68ki_write_32(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(adda, 16, ., d)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(DY));
+}
+
+
+M68KMAKE_OP(adda, 16, ., a)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(AY));
+}
+
+
+M68KMAKE_OP(adda, 16, ., .)
+{
+ uint* r_dst = &AX;
+ uint src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16);
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst + src);
+}
+
+
+M68KMAKE_OP(adda, 32, ., d)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst + DY);
+}
+
+
+M68KMAKE_OP(adda, 32, ., a)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst + AY);
+}
+
+
+M68KMAKE_OP(adda, 32, ., .)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst + M68KMAKE_GET_OPER_AY_32);
+}
+
+
+M68KMAKE_OP(addi, 8, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = OPER_I_8();
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(addi, 8, ., .)
+{
+ uint src = OPER_I_8();
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint dst = m68ki_read_8(ea);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ m68ki_write_8(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(addi, 16, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = OPER_I_16();
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(addi, 16, ., .)
+{
+ uint src = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint dst = m68ki_read_16(ea);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ m68ki_write_16(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(addi, 32, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = OPER_I_32();
+ uint dst = *r_dst;
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(addi, 32, ., .)
+{
+ uint src = OPER_I_32();
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint dst = m68ki_read_32(ea);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ m68ki_write_32(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(addq, 8, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(addq, 8, ., .)
+{
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint dst = m68ki_read_8(ea);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ m68ki_write_8(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(addq, 16, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(addq, 16, ., a)
+{
+ uint* r_dst = &AY;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst + (((REG_IR >> 9) - 1) & 7) + 1);
+}
+
+
+M68KMAKE_OP(addq, 16, ., .)
+{
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint dst = m68ki_read_16(ea);
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ m68ki_write_16(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(addq, 32, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint dst = *r_dst;
+ uint res = src + dst;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(addq, 32, ., a)
+{
+ uint* r_dst = &AY;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst + (((REG_IR >> 9) - 1) & 7) + 1);
+}
+
+
+M68KMAKE_OP(addq, 32, ., .)
+{
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint dst = m68ki_read_32(ea);
+ uint res = src + dst;
+
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ m68ki_write_32(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(addx, 8, rr, .)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_8(DY);
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = src + dst + XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+}
+
+
+M68KMAKE_OP(addx, 16, rr, .)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_16(DY);
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src + dst + XFLAG_AS_1();
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+
+ res = MASK_OUT_ABOVE_16(res);
+ FLAG_Z |= res;
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+}
+
+
+M68KMAKE_OP(addx, 32, rr, .)
+{
+ uint* r_dst = &DX;
+ uint src = DY;
+ uint dst = *r_dst;
+ uint res = src + dst + XFLAG_AS_1();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+
+ res = MASK_OUT_ABOVE_32(res);
+ FLAG_Z |= res;
+
+ *r_dst = res;
+}
+
+
+M68KMAKE_OP(addx, 8, mm, ax7)
+{
+ uint src = OPER_AY_PD_8();
+ uint ea = EA_A7_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = src + dst + XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(addx, 8, mm, ay7)
+{
+ uint src = OPER_A7_PD_8();
+ uint ea = EA_AX_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = src + dst + XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(addx, 8, mm, axy7)
+{
+ uint src = OPER_A7_PD_8();
+ uint ea = EA_A7_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = src + dst + XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(addx, 8, mm, .)
+{
+ uint src = OPER_AY_PD_8();
+ uint ea = EA_AX_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = src + dst + XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_V = VFLAG_ADD_8(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(addx, 16, mm, .)
+{
+ uint src = OPER_AY_PD_16();
+ uint ea = EA_AX_PD_16();
+ uint dst = m68ki_read_16(ea);
+ uint res = src + dst + XFLAG_AS_1();
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_V = VFLAG_ADD_16(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+
+ res = MASK_OUT_ABOVE_16(res);
+ FLAG_Z |= res;
+
+ m68ki_write_16(ea, res);
+}
+
+
+M68KMAKE_OP(addx, 32, mm, .)
+{
+ uint src = OPER_AY_PD_32();
+ uint ea = EA_AX_PD_32();
+ uint dst = m68ki_read_32(ea);
+ uint res = src + dst + XFLAG_AS_1();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_ADD_32(src, dst, res);
+ FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res);
+
+ res = MASK_OUT_ABOVE_32(res);
+ FLAG_Z |= res;
+
+ m68ki_write_32(ea, res);
+}
+
+
+M68KMAKE_OP(and, 8, er, d)
+{
+ FLAG_Z = MASK_OUT_ABOVE_8(DX &= (DY | 0xffffff00));
+
+ FLAG_N = NFLAG_8(FLAG_Z);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(and, 8, er, .)
+{
+ FLAG_Z = MASK_OUT_ABOVE_8(DX &= (M68KMAKE_GET_OPER_AY_8 | 0xffffff00));
+
+ FLAG_N = NFLAG_8(FLAG_Z);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(and, 16, er, d)
+{
+ FLAG_Z = MASK_OUT_ABOVE_16(DX &= (DY | 0xffff0000));
+
+ FLAG_N = NFLAG_16(FLAG_Z);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(and, 16, er, .)
+{
+ FLAG_Z = MASK_OUT_ABOVE_16(DX &= (M68KMAKE_GET_OPER_AY_16 | 0xffff0000));
+
+ FLAG_N = NFLAG_16(FLAG_Z);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(and, 32, er, d)
+{
+ FLAG_Z = DX &= DY;
+
+ FLAG_N = NFLAG_32(FLAG_Z);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(and, 32, er, .)
+{
+ FLAG_Z = DX &= M68KMAKE_GET_OPER_AY_32;
+
+ FLAG_N = NFLAG_32(FLAG_Z);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(and, 8, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint res = DX & m68ki_read_8(ea);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ m68ki_write_8(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(and, 16, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint res = DX & m68ki_read_16(ea);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ m68ki_write_16(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(and, 32, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint res = DX & m68ki_read_32(ea);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+
+ m68ki_write_32(ea, res);
+}
+
+
+M68KMAKE_OP(andi, 8, ., d)
+{
+ FLAG_Z = MASK_OUT_ABOVE_8(DY &= (OPER_I_8() | 0xffffff00));
+
+ FLAG_N = NFLAG_8(FLAG_Z);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(andi, 8, ., .)
+{
+ uint src = OPER_I_8();
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint res = src & m68ki_read_8(ea);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(andi, 16, ., d)
+{
+ FLAG_Z = MASK_OUT_ABOVE_16(DY &= (OPER_I_16() | 0xffff0000));
+
+ FLAG_N = NFLAG_16(FLAG_Z);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(andi, 16, ., .)
+{
+ uint src = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint res = src & m68ki_read_16(ea);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+
+ m68ki_write_16(ea, res);
+}
+
+
+M68KMAKE_OP(andi, 32, ., d)
+{
+ FLAG_Z = DY &= (OPER_I_32());
+
+ FLAG_N = NFLAG_32(FLAG_Z);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(andi, 32, ., .)
+{
+ uint src = OPER_I_32();
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint res = src & m68ki_read_32(ea);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+
+ m68ki_write_32(ea, res);
+}
+
+
+M68KMAKE_OP(andi, 16, toc, .)
+{
+ m68ki_set_ccr(m68ki_get_ccr() & OPER_I_16());
+}
+
+
+M68KMAKE_OP(andi, 16, tos, .)
+{
+ if(FLAG_S)
+ {
+ uint src = OPER_I_16();
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_set_sr(m68ki_get_sr() & src);
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(asr, 8, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = src >> shift;
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(GET_MSB_8(src))
+ res |= m68ki_shift_8_table[shift];
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_X = FLAG_C = src << (9-shift);
+}
+
+
+M68KMAKE_OP(asr, 16, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src >> shift;
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(GET_MSB_16(src))
+ res |= m68ki_shift_16_table[shift];
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_X = FLAG_C = src << (9-shift);
+}
+
+
+M68KMAKE_OP(asr, 32, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = *r_dst;
+ uint res = src >> shift;
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(GET_MSB_32(src))
+ res |= m68ki_shift_32_table[shift];
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_X = FLAG_C = src << (9-shift);
+}
+
+
+M68KMAKE_OP(asr, 8, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = src >> shift;
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift < 8)
+ {
+ if(GET_MSB_8(src))
+ res |= m68ki_shift_8_table[shift];
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_X = FLAG_C = src << (9-shift);
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ if(GET_MSB_8(src))
+ {
+ *r_dst |= 0xff;
+ FLAG_C = CFLAG_SET;
+ FLAG_X = XFLAG_SET;
+ FLAG_N = NFLAG_SET;
+ FLAG_Z = ZFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ *r_dst &= 0xffffff00;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_X = XFLAG_CLEAR;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_8(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(asr, 16, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src >> shift;
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift < 16)
+ {
+ if(GET_MSB_16(src))
+ res |= m68ki_shift_16_table[shift];
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_C = FLAG_X = (src >> (shift - 1))<<8;
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ if(GET_MSB_16(src))
+ {
+ *r_dst |= 0xffff;
+ FLAG_C = CFLAG_SET;
+ FLAG_X = XFLAG_SET;
+ FLAG_N = NFLAG_SET;
+ FLAG_Z = ZFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ *r_dst &= 0xffff0000;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_X = XFLAG_CLEAR;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_16(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(asr, 32, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = *r_dst;
+ uint res = src >> shift;
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift < 32)
+ {
+ if(GET_MSB_32(src))
+ res |= m68ki_shift_32_table[shift];
+
+ *r_dst = res;
+
+ FLAG_C = FLAG_X = (src >> (shift - 1))<<8;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ if(GET_MSB_32(src))
+ {
+ *r_dst = 0xffffffff;
+ FLAG_C = CFLAG_SET;
+ FLAG_X = XFLAG_SET;
+ FLAG_N = NFLAG_SET;
+ FLAG_Z = ZFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ *r_dst = 0;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_X = XFLAG_CLEAR;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_32(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(asr, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = src >> 1;
+
+ if(GET_MSB_16(src))
+ res |= 0x8000;
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = FLAG_X = src << 8;
+}
+
+
+M68KMAKE_OP(asl, 8, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = MASK_OUT_ABOVE_8(src << shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_X = FLAG_C = src << shift;
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ src &= m68ki_shift_8_table[shift + 1];
+ FLAG_V = (!(src == 0 || (src == m68ki_shift_8_table[shift + 1] && shift < 8)))<<7;
+}
+
+
+M68KMAKE_OP(asl, 16, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = MASK_OUT_ABOVE_16(src << shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src >> (8-shift);
+ src &= m68ki_shift_16_table[shift + 1];
+ FLAG_V = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7;
+}
+
+
+M68KMAKE_OP(asl, 32, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = *r_dst;
+ uint res = MASK_OUT_ABOVE_32(src << shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src >> (24-shift);
+ src &= m68ki_shift_32_table[shift + 1];
+ FLAG_V = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7;
+}
+
+
+M68KMAKE_OP(asl, 8, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = MASK_OUT_ABOVE_8(src << shift);
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift < 8)
+ {
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+ FLAG_X = FLAG_C = src << shift;
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ src &= m68ki_shift_8_table[shift + 1];
+ FLAG_V = (!(src == 0 || src == m68ki_shift_8_table[shift + 1]))<<7;
+ return;
+ }
+
+ *r_dst &= 0xffffff00;
+ FLAG_X = FLAG_C = ((shift == 8 ? src & 1 : 0))<<8;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = (!(src == 0))<<7;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_8(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(asl, 16, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = MASK_OUT_ABOVE_16(src << shift);
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift < 16)
+ {
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+ FLAG_X = FLAG_C = (src << shift) >> 8;
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ src &= m68ki_shift_16_table[shift + 1];
+ FLAG_V = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7;
+ return;
+ }
+
+ *r_dst &= 0xffff0000;
+ FLAG_X = FLAG_C = ((shift == 16 ? src & 1 : 0))<<8;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = (!(src == 0))<<7;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_16(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(asl, 32, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = *r_dst;
+ uint res = MASK_OUT_ABOVE_32(src << shift);
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift < 32)
+ {
+ *r_dst = res;
+ FLAG_X = FLAG_C = (src >> (32 - shift)) << 8;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ src &= m68ki_shift_32_table[shift + 1];
+ FLAG_V = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7;
+ return;
+ }
+
+ *r_dst = 0;
+ FLAG_X = FLAG_C = ((shift == 32 ? src & 1 : 0))<<8;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = (!(src == 0))<<7;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_32(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(asl, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = MASK_OUT_ABOVE_16(src << 1);
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src >> 7;
+ src &= 0xc000;
+ FLAG_V = (!(src == 0 || src == 0xc000))<<7;
+}
+
+
+M68KMAKE_OP(bcc, 8, ., .)
+{
+ if(M68KMAKE_CC)
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR));
+ return;
+ }
+ USE_CYCLES(CYC_BCC_NOTAKE_B);
+}
+
+
+M68KMAKE_OP(bcc, 16, ., .)
+{
+ if(M68KMAKE_CC)
+ {
+ uint offset = OPER_I_16();
+ REG_PC -= 2;
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_16(offset);
+ return;
+ }
+ REG_PC += 2;
+ USE_CYCLES(CYC_BCC_NOTAKE_W);
+}
+
+
+M68KMAKE_OP(bcc, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ if(M68KMAKE_CC)
+ {
+ uint offset = OPER_I_32();
+ REG_PC -= 4;
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_32(offset);
+ return;
+ }
+ REG_PC += 4;
+ return;
+ }
+ else
+ {
+ if(M68KMAKE_CC)
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR));
+ return;
+ }
+ USE_CYCLES(CYC_BCC_NOTAKE_B);
+ }
+}
+
+
+M68KMAKE_OP(bchg, 32, r, d)
+{
+ uint* r_dst = &DY;
+ uint mask = 1 << (DX & 0x1f);
+
+ FLAG_Z = *r_dst & mask;
+ *r_dst ^= mask;
+}
+
+
+M68KMAKE_OP(bchg, 8, r, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = m68ki_read_8(ea);
+ uint mask = 1 << (DX & 7);
+
+ FLAG_Z = src & mask;
+ m68ki_write_8(ea, src ^ mask);
+}
+
+
+M68KMAKE_OP(bchg, 32, s, d)
+{
+ uint* r_dst = &DY;
+ uint mask = 1 << (OPER_I_8() & 0x1f);
+
+ FLAG_Z = *r_dst & mask;
+ *r_dst ^= mask;
+}
+
+
+M68KMAKE_OP(bchg, 8, s, .)
+{
+ uint mask = 1 << (OPER_I_8() & 7);
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = m68ki_read_8(ea);
+
+ FLAG_Z = src & mask;
+ m68ki_write_8(ea, src ^ mask);
+}
+
+
+M68KMAKE_OP(bclr, 32, r, d)
+{
+ uint* r_dst = &DY;
+ uint mask = 1 << (DX & 0x1f);
+
+ FLAG_Z = *r_dst & mask;
+ *r_dst &= ~mask;
+}
+
+
+M68KMAKE_OP(bclr, 8, r, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = m68ki_read_8(ea);
+ uint mask = 1 << (DX & 7);
+
+ FLAG_Z = src & mask;
+ m68ki_write_8(ea, src & ~mask);
+}
+
+
+M68KMAKE_OP(bclr, 32, s, d)
+{
+ uint* r_dst = &DY;
+ uint mask = 1 << (OPER_I_8() & 0x1f);
+
+ FLAG_Z = *r_dst & mask;
+ *r_dst &= ~mask;
+}
+
+
+M68KMAKE_OP(bclr, 8, s, .)
+{
+ uint mask = 1 << (OPER_I_8() & 7);
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = m68ki_read_8(ea);
+
+ FLAG_Z = src & mask;
+ m68ki_write_8(ea, src & ~mask);
+}
+
+
+M68KMAKE_OP(bfchg, 32, ., d)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint offset = (word2>>6)&31;
+ uint width = word2;
+ uint* data = &DY;
+ uint64 mask;
+
+
+ if(BIT_B(word2))
+ offset = REG_D[offset&7];
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ offset &= 31;
+ width = ((width-1) & 31) + 1;
+
+ mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask = ROR_32(mask, offset);
+
+ FLAG_N = NFLAG_32(*data<<offset);
+ FLAG_Z = *data & mask;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ *data ^= mask;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfchg, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ sint offset = (word2>>6)&31;
+ uint width = word2;
+ uint mask_base;
+ uint data_long;
+ uint mask_long;
+ uint data_byte = 0;
+ uint mask_byte = 0;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+
+
+ if(BIT_B(word2))
+ offset = MAKE_INT_32(REG_D[offset&7]);
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ /* Offset is signed so we have to use ugly math =( */
+ ea += offset / 8;
+ offset %= 8;
+ if(offset < 0)
+ {
+ offset += 8;
+ ea--;
+ }
+ width = ((width-1) & 31) + 1;
+
+ mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask_long = mask_base >> offset;
+
+ data_long = m68ki_read_32(ea);
+ FLAG_N = NFLAG_32(data_long << offset);
+ FLAG_Z = data_long & mask_long;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ m68ki_write_32(ea, data_long ^ mask_long);
+
+ if((width + offset) > 32)
+ {
+ mask_byte = MASK_OUT_ABOVE_8(mask_base);
+ data_byte = m68ki_read_8(ea+4);
+ FLAG_Z |= (data_byte & mask_byte);
+ m68ki_write_8(ea+4, data_byte ^ mask_byte);
+ }
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfclr, 32, ., d)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint offset = (word2>>6)&31;
+ uint width = word2;
+ uint* data = &DY;
+ uint64 mask;
+
+
+ if(BIT_B(word2))
+ offset = REG_D[offset&7];
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+
+ offset &= 31;
+ width = ((width-1) & 31) + 1;
+
+
+ mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask = ROR_32(mask, offset);
+
+ FLAG_N = NFLAG_32(*data<<offset);
+ FLAG_Z = *data & mask;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ *data &= ~mask;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfclr, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ sint offset = (word2>>6)&31;
+ uint width = word2;
+ uint mask_base;
+ uint data_long;
+ uint mask_long;
+ uint data_byte = 0;
+ uint mask_byte = 0;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+
+
+ if(BIT_B(word2))
+ offset = MAKE_INT_32(REG_D[offset&7]);
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ /* Offset is signed so we have to use ugly math =( */
+ ea += offset / 8;
+ offset %= 8;
+ if(offset < 0)
+ {
+ offset += 8;
+ ea--;
+ }
+ width = ((width-1) & 31) + 1;
+
+ mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask_long = mask_base >> offset;
+
+ data_long = m68ki_read_32(ea);
+ FLAG_N = NFLAG_32(data_long << offset);
+ FLAG_Z = data_long & mask_long;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ m68ki_write_32(ea, data_long & ~mask_long);
+
+ if((width + offset) > 32)
+ {
+ mask_byte = MASK_OUT_ABOVE_8(mask_base);
+ data_byte = m68ki_read_8(ea+4);
+ FLAG_Z |= (data_byte & mask_byte);
+ m68ki_write_8(ea+4, data_byte & ~mask_byte);
+ }
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfexts, 32, ., d)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint offset = (word2>>6)&31;
+ uint width = word2;
+ uint64 data = DY;
+
+
+ if(BIT_B(word2))
+ offset = REG_D[offset&7];
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ offset &= 31;
+ width = ((width-1) & 31) + 1;
+
+ data = ROL_32(data, offset);
+ FLAG_N = NFLAG_32(data);
+ data = MAKE_INT_32(data) >> (32 - width);
+
+ FLAG_Z = data;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ REG_D[(word2>>12)&7] = data;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfexts, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ sint offset = (word2>>6)&31;
+ uint width = word2;
+ uint data;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+
+
+ if(BIT_B(word2))
+ offset = MAKE_INT_32(REG_D[offset&7]);
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ /* Offset is signed so we have to use ugly math =( */
+ ea += offset / 8;
+ offset %= 8;
+ if(offset < 0)
+ {
+ offset += 8;
+ ea--;
+ }
+ width = ((width-1) & 31) + 1;
+
+ data = m68ki_read_32(ea);
+
+ data = MASK_OUT_ABOVE_32(data<<offset);
+
+ if((offset+width) > 32)
+ data |= (m68ki_read_8(ea+4) << offset) >> 8;
+
+ FLAG_N = NFLAG_32(data);
+ data = MAKE_INT_32(data) >> (32 - width);
+
+ FLAG_Z = data;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ REG_D[(word2 >> 12) & 7] = data;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfextu, 32, ., d)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint offset = (word2>>6)&31;
+ uint width = word2;
+ uint64 data = DY;
+
+
+ if(BIT_B(word2))
+ offset = REG_D[offset&7];
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ offset &= 31;
+ width = ((width-1) & 31) + 1;
+
+ data = ROL_32(data, offset);
+ FLAG_N = NFLAG_32(data);
+ data >>= 32 - width;
+
+ FLAG_Z = data;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ REG_D[(word2>>12)&7] = data;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfextu, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ sint offset = (word2>>6)&31;
+ uint width = word2;
+ uint data;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+
+
+ if(BIT_B(word2))
+ offset = MAKE_INT_32(REG_D[offset&7]);
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ /* Offset is signed so we have to use ugly math =( */
+ ea += offset / 8;
+ offset %= 8;
+ if(offset < 0)
+ {
+ offset += 8;
+ ea--;
+ }
+ width = ((width-1) & 31) + 1;
+
+ data = m68ki_read_32(ea);
+ data = MASK_OUT_ABOVE_32(data<<offset);
+
+ if((offset+width) > 32)
+ data |= (m68ki_read_8(ea+4) << offset) >> 8;
+
+ FLAG_N = NFLAG_32(data);
+ data >>= (32 - width);
+
+ FLAG_Z = data;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ REG_D[(word2 >> 12) & 7] = data;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfffo, 32, ., d)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint offset = (word2>>6)&31;
+ uint width = word2;
+ uint64 data = DY;
+ uint bit;
+
+
+ if(BIT_B(word2))
+ offset = REG_D[offset&7];
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ offset &= 31;
+ width = ((width-1) & 31) + 1;
+
+ data = ROL_32(data, offset);
+ FLAG_N = NFLAG_32(data);
+ data >>= 32 - width;
+
+ FLAG_Z = data;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1)
+ offset++;
+
+ REG_D[(word2>>12)&7] = offset;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfffo, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ sint offset = (word2>>6)&31;
+ sint local_offset;
+ uint width = word2;
+ uint data;
+ uint bit;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+
+
+ if(BIT_B(word2))
+ offset = MAKE_INT_32(REG_D[offset&7]);
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ /* Offset is signed so we have to use ugly math =( */
+ ea += offset / 8;
+ local_offset = offset % 8;
+ if(local_offset < 0)
+ {
+ local_offset += 8;
+ ea--;
+ }
+ width = ((width-1) & 31) + 1;
+
+ data = m68ki_read_32(ea);
+ data = MASK_OUT_ABOVE_32(data<<local_offset);
+
+ if((local_offset+width) > 32)
+ data |= (m68ki_read_8(ea+4) << local_offset) >> 8;
+
+ FLAG_N = NFLAG_32(data);
+ data >>= (32 - width);
+
+ FLAG_Z = data;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1)
+ offset++;
+
+ REG_D[(word2>>12)&7] = offset;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfins, 32, ., d)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint offset = (word2>>6)&31;
+ uint width = word2;
+ uint* data = &DY;
+ uint64 mask;
+ uint64 insert = REG_D[(word2>>12)&7];
+
+
+ if(BIT_B(word2))
+ offset = REG_D[offset&7];
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+
+ offset &= 31;
+ width = ((width-1) & 31) + 1;
+
+
+ mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask = ROR_32(mask, offset);
+
+ insert = MASK_OUT_ABOVE_32(insert << (32 - width));
+ FLAG_N = NFLAG_32(insert);
+ FLAG_Z = insert;
+ insert = ROR_32(insert, offset);
+
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ *data &= ~mask;
+ *data |= insert;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfins, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ sint offset = (word2>>6)&31;
+ uint width = word2;
+ uint insert_base = REG_D[(word2>>12)&7];
+ uint insert_long;
+ uint insert_byte;
+ uint mask_base;
+ uint data_long;
+ uint mask_long;
+ uint data_byte = 0;
+ uint mask_byte = 0;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+
+
+ if(BIT_B(word2))
+ offset = MAKE_INT_32(REG_D[offset&7]);
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ /* Offset is signed so we have to use ugly math =( */
+ ea += offset / 8;
+ offset %= 8;
+ if(offset < 0)
+ {
+ offset += 8;
+ ea--;
+ }
+ width = ((width-1) & 31) + 1;
+
+ mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask_long = mask_base >> offset;
+
+ insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width));
+ FLAG_N = NFLAG_32(insert_base);
+ FLAG_Z = insert_base;
+ insert_long = insert_base >> offset;
+
+ data_long = m68ki_read_32(ea);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ m68ki_write_32(ea, (data_long & ~mask_long) | insert_long);
+
+ if((width + offset) > 32)
+ {
+ mask_byte = MASK_OUT_ABOVE_8(mask_base);
+ insert_byte = MASK_OUT_ABOVE_8(insert_base);
+ data_byte = m68ki_read_8(ea+4);
+ FLAG_Z |= (data_byte & mask_byte);
+ m68ki_write_8(ea+4, (data_byte & ~mask_byte) | insert_byte);
+ }
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfset, 32, ., d)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint offset = (word2>>6)&31;
+ uint width = word2;
+ uint* data = &DY;
+ uint64 mask;
+
+
+ if(BIT_B(word2))
+ offset = REG_D[offset&7];
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+
+ offset &= 31;
+ width = ((width-1) & 31) + 1;
+
+
+ mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask = ROR_32(mask, offset);
+
+ FLAG_N = NFLAG_32(*data<<offset);
+ FLAG_Z = *data & mask;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ *data |= mask;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bfset, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ sint offset = (word2>>6)&31;
+ uint width = word2;
+ uint mask_base;
+ uint data_long;
+ uint mask_long;
+ uint data_byte = 0;
+ uint mask_byte = 0;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+
+
+ if(BIT_B(word2))
+ offset = MAKE_INT_32(REG_D[offset&7]);
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ /* Offset is signed so we have to use ugly math =( */
+ ea += offset / 8;
+ offset %= 8;
+ if(offset < 0)
+ {
+ offset += 8;
+ ea--;
+ }
+ width = ((width-1) & 31) + 1;
+
+
+ mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask_long = mask_base >> offset;
+
+ data_long = m68ki_read_32(ea);
+ FLAG_N = NFLAG_32(data_long << offset);
+ FLAG_Z = data_long & mask_long;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ m68ki_write_32(ea, data_long | mask_long);
+
+ if((width + offset) > 32)
+ {
+ mask_byte = MASK_OUT_ABOVE_8(mask_base);
+ data_byte = m68ki_read_8(ea+4);
+ FLAG_Z |= (data_byte & mask_byte);
+ m68ki_write_8(ea+4, data_byte | mask_byte);
+ }
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bftst, 32, ., d)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint offset = (word2>>6)&31;
+ uint width = word2;
+ uint* data = &DY;
+ uint64 mask;
+
+
+ if(BIT_B(word2))
+ offset = REG_D[offset&7];
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+
+ offset &= 31;
+ width = ((width-1) & 31) + 1;
+
+
+ mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask = ROR_32(mask, offset);
+
+ FLAG_N = NFLAG_32(*data<<offset);
+ FLAG_Z = *data & mask;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bftst, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ sint offset = (word2>>6)&31;
+ uint width = word2;
+ uint mask_base;
+ uint data_long;
+ uint mask_long;
+ uint data_byte = 0;
+ uint mask_byte = 0;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+
+ if(BIT_B(word2))
+ offset = MAKE_INT_32(REG_D[offset&7]);
+ if(BIT_5(word2))
+ width = REG_D[width&7];
+
+ /* Offset is signed so we have to use ugly math =( */
+ ea += offset / 8;
+ offset %= 8;
+ if(offset < 0)
+ {
+ offset += 8;
+ ea--;
+ }
+ width = ((width-1) & 31) + 1;
+
+
+ mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
+ mask_long = mask_base >> offset;
+
+ data_long = m68ki_read_32(ea);
+ FLAG_N = ((data_long & (0x80000000 >> offset))<<offset)>>24;
+ FLAG_Z = data_long & mask_long;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ if((width + offset) > 32)
+ {
+ mask_byte = MASK_OUT_ABOVE_8(mask_base);
+ data_byte = m68ki_read_8(ea+4);
+ FLAG_Z |= (data_byte & mask_byte);
+ }
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bkpt, 0, ., .)
+{
+ if(CPU_TYPE_IS_010_PLUS(CPU_TYPE))
+ {
+ m68ki_bkpt_ack(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE) ? REG_IR & 7 : 0); /* auto-disable (see m68kcpu.h) */
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(bra, 8, ., .)
+{
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR));
+ if(REG_PC == REG_PPC)
+ USE_ALL_CYCLES();
+}
+
+
+M68KMAKE_OP(bra, 16, ., .)
+{
+ uint offset = OPER_I_16();
+ REG_PC -= 2;
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_16(offset);
+ if(REG_PC == REG_PPC)
+ USE_ALL_CYCLES();
+}
+
+
+M68KMAKE_OP(bra, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint offset = OPER_I_32();
+ REG_PC -= 4;
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_32(offset);
+ if(REG_PC == REG_PPC)
+ USE_ALL_CYCLES();
+ return;
+ }
+ else
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR));
+ if(REG_PC == REG_PPC)
+ USE_ALL_CYCLES();
+ }
+}
+
+
+M68KMAKE_OP(bset, 32, r, d)
+{
+ uint* r_dst = &DY;
+ uint mask = 1 << (DX & 0x1f);
+
+ FLAG_Z = *r_dst & mask;
+ *r_dst |= mask;
+}
+
+
+M68KMAKE_OP(bset, 8, r, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = m68ki_read_8(ea);
+ uint mask = 1 << (DX & 7);
+
+ FLAG_Z = src & mask;
+ m68ki_write_8(ea, src | mask);
+}
+
+
+M68KMAKE_OP(bset, 32, s, d)
+{
+ uint* r_dst = &DY;
+ uint mask = 1 << (OPER_I_8() & 0x1f);
+
+ FLAG_Z = *r_dst & mask;
+ *r_dst |= mask;
+}
+
+
+M68KMAKE_OP(bset, 8, s, .)
+{
+ uint mask = 1 << (OPER_I_8() & 7);
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = m68ki_read_8(ea);
+
+ FLAG_Z = src & mask;
+ m68ki_write_8(ea, src | mask);
+}
+
+
+M68KMAKE_OP(bsr, 8, ., .)
+{
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_push_32(REG_PC);
+ m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR));
+}
+
+
+M68KMAKE_OP(bsr, 16, ., .)
+{
+ uint offset = OPER_I_16();
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_push_32(REG_PC);
+ REG_PC -= 2;
+ m68ki_branch_16(offset);
+}
+
+
+M68KMAKE_OP(bsr, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint offset = OPER_I_32();
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_push_32(REG_PC);
+ REG_PC -= 4;
+ m68ki_branch_32(offset);
+ return;
+ }
+ else
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_push_32(REG_PC);
+ m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR));
+ }
+}
+
+
+M68KMAKE_OP(btst, 32, r, d)
+{
+ FLAG_Z = DY & (1 << (DX & 0x1f));
+}
+
+
+M68KMAKE_OP(btst, 8, r, .)
+{
+ FLAG_Z = M68KMAKE_GET_OPER_AY_8 & (1 << (DX & 7));
+}
+
+
+M68KMAKE_OP(btst, 32, s, d)
+{
+ FLAG_Z = DY & (1 << (OPER_I_8() & 0x1f));
+}
+
+
+M68KMAKE_OP(btst, 8, s, .)
+{
+ uint bit = OPER_I_8() & 7;
+
+ FLAG_Z = M68KMAKE_GET_OPER_AY_8 & (1 << bit);
+}
+
+
+M68KMAKE_OP(callm, 32, ., .)
+{
+ /* note: watch out for pcrelative modes */
+ if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE))
+ {
+ uint ea = M68KMAKE_GET_EA_AY_32;
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ REG_PC += 2;
+(void)ea; /* just to avoid an 'unused variable' warning */
+ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR,
+ m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2))));
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cas, 8, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint dest = m68ki_read_8(ea);
+ uint* compare = &REG_D[word2 & 7];
+ uint res = dest - MASK_OUT_ABOVE_8(*compare);
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(*compare, dest, res);
+ FLAG_C = CFLAG_8(res);
+
+ if(COND_NE())
+ *compare = MASK_OUT_BELOW_8(*compare) | dest;
+ else
+ {
+ USE_CYCLES(3);
+ m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7]));
+ }
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cas, 16, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint dest = m68ki_read_16(ea);
+ uint* compare = &REG_D[word2 & 7];
+ uint res = dest - MASK_OUT_ABOVE_16(*compare);
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_V = VFLAG_SUB_16(*compare, dest, res);
+ FLAG_C = CFLAG_16(res);
+
+ if(COND_NE())
+ *compare = MASK_OUT_BELOW_16(*compare) | dest;
+ else
+ {
+ USE_CYCLES(3);
+ m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7]));
+ }
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cas, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint dest = m68ki_read_32(ea);
+ uint* compare = &REG_D[word2 & 7];
+ uint res = dest - *compare;
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(*compare, dest, res);
+ FLAG_C = CFLAG_SUB_32(*compare, dest, res);
+
+ if(COND_NE())
+ *compare = dest;
+ else
+ {
+ USE_CYCLES(3);
+ m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]);
+ }
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cas2, 16, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_32();
+ uint* compare1 = &REG_D[(word2 >> 16) & 7];
+ uint ea1 = REG_DA[(word2 >> 28) & 15];
+ uint dest1 = m68ki_read_16(ea1);
+ uint res1 = dest1 - MASK_OUT_ABOVE_16(*compare1);
+ uint* compare2 = &REG_D[word2 & 7];
+ uint ea2 = REG_DA[(word2 >> 12) & 15];
+ uint dest2 = m68ki_read_16(ea2);
+ uint res2;
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ FLAG_N = NFLAG_16(res1);
+ FLAG_Z = MASK_OUT_ABOVE_16(res1);
+ FLAG_V = VFLAG_SUB_16(*compare1, dest1, res1);
+ FLAG_C = CFLAG_16(res1);
+
+ if(COND_EQ())
+ {
+ res2 = dest2 - MASK_OUT_ABOVE_16(*compare2);
+
+ FLAG_N = NFLAG_16(res2);
+ FLAG_Z = MASK_OUT_ABOVE_16(res2);
+ FLAG_V = VFLAG_SUB_16(*compare2, dest2, res2);
+ FLAG_C = CFLAG_16(res2);
+
+ if(COND_EQ())
+ {
+ USE_CYCLES(3);
+ m68ki_write_16(ea1, REG_D[(word2 >> 22) & 7]);
+ m68ki_write_16(ea2, REG_D[(word2 >> 6) & 7]);
+ return;
+ }
+ }
+ *compare1 = BIT_1F(word2) ? MAKE_INT_16(dest1) : MASK_OUT_BELOW_16(*compare1) | dest1;
+ *compare2 = BIT_F(word2) ? MAKE_INT_16(dest2) : MASK_OUT_BELOW_16(*compare2) | dest2;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cas2, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_32();
+ uint* compare1 = &REG_D[(word2 >> 16) & 7];
+ uint ea1 = REG_DA[(word2 >> 28) & 15];
+ uint dest1 = m68ki_read_32(ea1);
+ uint res1 = dest1 - *compare1;
+ uint* compare2 = &REG_D[word2 & 7];
+ uint ea2 = REG_DA[(word2 >> 12) & 15];
+ uint dest2 = m68ki_read_32(ea2);
+ uint res2;
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ FLAG_N = NFLAG_32(res1);
+ FLAG_Z = MASK_OUT_ABOVE_32(res1);
+ FLAG_V = VFLAG_SUB_32(*compare1, dest1, res1);
+ FLAG_C = CFLAG_SUB_32(*compare1, dest1, res1);
+
+ if(COND_EQ())
+ {
+ res2 = dest2 - *compare2;
+
+ FLAG_N = NFLAG_32(res2);
+ FLAG_Z = MASK_OUT_ABOVE_32(res2);
+ FLAG_V = VFLAG_SUB_32(*compare2, dest2, res2);
+ FLAG_C = CFLAG_SUB_32(*compare2, dest2, res2);
+
+ if(COND_EQ())
+ {
+ USE_CYCLES(3);
+ m68ki_write_32(ea1, REG_D[(word2 >> 22) & 7]);
+ m68ki_write_32(ea2, REG_D[(word2 >> 6) & 7]);
+ return;
+ }
+ }
+ *compare1 = dest1;
+ *compare2 = dest2;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk, 16, ., d)
+{
+ sint src = MAKE_INT_16(DX);
+ sint bound = MAKE_INT_16(DY);
+
+ FLAG_Z = ZFLAG_16(src); /* Undocumented */
+ FLAG_V = VFLAG_CLEAR; /* Undocumented */
+ FLAG_C = CFLAG_CLEAR; /* Undocumented */
+
+ if(src >= 0 && src <= bound)
+ {
+ return;
+ }
+ FLAG_N = (src < 0)<<7;
+ m68ki_exception_trap(EXCEPTION_CHK);
+}
+
+
+M68KMAKE_OP(chk, 16, ., .)
+{
+ sint src = MAKE_INT_16(DX);
+ sint bound = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16);
+
+ FLAG_Z = ZFLAG_16(src); /* Undocumented */
+ FLAG_V = VFLAG_CLEAR; /* Undocumented */
+ FLAG_C = CFLAG_CLEAR; /* Undocumented */
+
+ if(src >= 0 && src <= bound)
+ {
+ return;
+ }
+ FLAG_N = (src < 0)<<7;
+ m68ki_exception_trap(EXCEPTION_CHK);
+}
+
+
+M68KMAKE_OP(chk, 32, ., d)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ sint src = MAKE_INT_32(DX);
+ sint bound = MAKE_INT_32(DY);
+
+ FLAG_Z = ZFLAG_32(src); /* Undocumented */
+ FLAG_V = VFLAG_CLEAR; /* Undocumented */
+ FLAG_C = CFLAG_CLEAR; /* Undocumented */
+
+ if(src >= 0 && src <= bound)
+ {
+ return;
+ }
+ FLAG_N = (src < 0)<<7;
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ sint src = MAKE_INT_32(DX);
+ sint bound = MAKE_INT_32(M68KMAKE_GET_OPER_AY_32);
+
+ FLAG_Z = ZFLAG_32(src); /* Undocumented */
+ FLAG_V = VFLAG_CLEAR; /* Undocumented */
+ FLAG_C = CFLAG_CLEAR; /* Undocumented */
+
+ if(src >= 0 && src <= bound)
+ {
+ return;
+ }
+ FLAG_N = (src < 0)<<7;
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk2cmp2, 8, ., pcdi)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint compare = REG_DA[(word2 >> 12) & 15]&0xff;
+ uint ea = EA_PCDI_8();
+ uint lower_bound = m68ki_read_pcrel_8(ea);
+ uint upper_bound = m68ki_read_pcrel_8(ea + 1);
+
+ if(!BIT_F(word2))
+ FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound);
+ else
+ FLAG_C = compare - lower_bound;
+ FLAG_Z = !((upper_bound==compare) | (lower_bound==compare));
+ if(COND_CS())
+ {
+ if(BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+
+ FLAG_C = upper_bound - compare;
+ if(COND_CS() && BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk2cmp2, 8, ., pcix)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint compare = REG_DA[(word2 >> 12) & 15]&0xff;
+ uint ea = EA_PCIX_8();
+ uint lower_bound = m68ki_read_pcrel_8(ea);
+ uint upper_bound = m68ki_read_pcrel_8(ea + 1);
+
+ if(!BIT_F(word2))
+ FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound);
+ else
+ FLAG_C = compare - lower_bound;
+ FLAG_Z = !((upper_bound==compare) | (lower_bound==compare));
+ if(COND_CS())
+ {
+ if(BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+
+ FLAG_C = upper_bound - compare;
+ if(COND_CS() && BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk2cmp2, 8, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint compare = REG_DA[(word2 >> 12) & 15]&0xff;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint lower_bound = m68ki_read_8(ea);
+ uint upper_bound = m68ki_read_8(ea + 1);
+
+ if(!BIT_F(word2))
+ FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound);
+ else
+ FLAG_C = compare - lower_bound;
+ FLAG_Z = !((upper_bound==compare) | (lower_bound==compare));
+ if(COND_CS())
+ {
+ if(BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+
+ FLAG_C = upper_bound - compare;
+ if(COND_CS() && BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk2cmp2, 16, ., pcdi)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint compare = REG_DA[(word2 >> 12) & 15]&0xffff;
+ uint ea = EA_PCDI_16();
+ uint lower_bound = m68ki_read_pcrel_16(ea);
+ uint upper_bound = m68ki_read_pcrel_16(ea + 2);
+
+ if(!BIT_F(word2))
+ FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound);
+ else
+ FLAG_C = compare - lower_bound;
+ FLAG_Z = !((upper_bound==compare) | (lower_bound==compare));
+ FLAG_C = CFLAG_16(FLAG_C);
+ if(COND_CS())
+ {
+ if(BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+
+ if(!BIT_F(word2))
+ FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare);
+ else
+ FLAG_C = upper_bound - compare;
+ FLAG_C = CFLAG_16(FLAG_C);
+ if(COND_CS() && BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk2cmp2, 16, ., pcix)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint compare = REG_DA[(word2 >> 12) & 15]&0xffff;
+ uint ea = EA_PCIX_16();
+ uint lower_bound = m68ki_read_pcrel_16(ea);
+ uint upper_bound = m68ki_read_pcrel_16(ea + 2);
+
+ if(!BIT_F(word2))
+ FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound);
+ else
+ FLAG_C = compare - lower_bound;
+ FLAG_Z = !((upper_bound==compare) | (lower_bound==compare));
+ FLAG_C = CFLAG_16(FLAG_C);
+ if(COND_CS())
+ {
+ if(BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+
+ if(!BIT_F(word2))
+ FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare);
+ else
+ FLAG_C = upper_bound - compare;
+ FLAG_C = CFLAG_16(FLAG_C);
+ if(COND_CS() && BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk2cmp2, 16, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint compare = REG_DA[(word2 >> 12) & 15]&0xffff;
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint lower_bound = m68ki_read_16(ea);
+ uint upper_bound = m68ki_read_16(ea + 2);
+
+ if(!BIT_F(word2))
+ FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound);
+ else
+ FLAG_C = compare - lower_bound;
+
+ FLAG_Z = !((upper_bound==compare) | (lower_bound==compare));
+ FLAG_C = CFLAG_16(FLAG_C);
+ if(COND_CS())
+ {
+ if(BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ if(!BIT_F(word2))
+ FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare);
+ else
+ FLAG_C = upper_bound - compare;
+
+ FLAG_C = CFLAG_16(FLAG_C);
+ if(COND_CS() && BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk2cmp2, 32, ., pcdi)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint compare = REG_DA[(word2 >> 12) & 15];
+ uint ea = EA_PCDI_32();
+ uint lower_bound = m68ki_read_pcrel_32(ea);
+ uint upper_bound = m68ki_read_pcrel_32(ea + 4);
+
+ FLAG_C = compare - lower_bound;
+ FLAG_Z = !((upper_bound==compare) | (lower_bound==compare));
+ FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C);
+ if(COND_CS())
+ {
+ if(BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+
+ FLAG_C = upper_bound - compare;
+ FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C);
+ if(COND_CS() && BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk2cmp2, 32, ., pcix)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint compare = REG_DA[(word2 >> 12) & 15];
+ uint ea = EA_PCIX_32();
+ uint lower_bound = m68ki_read_pcrel_32(ea);
+ uint upper_bound = m68ki_read_pcrel_32(ea + 4);
+
+ FLAG_C = compare - lower_bound;
+ FLAG_Z = !((upper_bound==compare) | (lower_bound==compare));
+ FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C);
+ if(COND_CS())
+ {
+ if(BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+
+ FLAG_C = upper_bound - compare;
+ FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C);
+ if(COND_CS() && BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(chk2cmp2, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint compare = REG_DA[(word2 >> 12) & 15];
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint lower_bound = m68ki_read_32(ea);
+ uint upper_bound = m68ki_read_32(ea + 4);
+
+ FLAG_C = compare - lower_bound;
+ FLAG_Z = !((upper_bound==compare) | (lower_bound==compare));
+ FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C);
+ if(COND_CS())
+ {
+ if(BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+
+ FLAG_C = upper_bound - compare;
+ FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C);
+ if(COND_CS() && BIT_B(word2))
+ m68ki_exception_trap(EXCEPTION_CHK);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(clr, 8, ., d)
+{
+ DY &= 0xffffff00;
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+}
+
+
+M68KMAKE_OP(clr, 8, ., .)
+{
+ m68ki_write_8(M68KMAKE_GET_EA_AY_8, 0);
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+}
+
+
+M68KMAKE_OP(clr, 16, ., d)
+{
+ DY &= 0xffff0000;
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+}
+
+
+M68KMAKE_OP(clr, 16, ., .)
+{
+ m68ki_write_16(M68KMAKE_GET_EA_AY_16, 0);
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+}
+
+
+M68KMAKE_OP(clr, 32, ., d)
+{
+ DY = 0;
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+}
+
+
+M68KMAKE_OP(clr, 32, ., .)
+{
+ m68ki_write_32(M68KMAKE_GET_EA_AY_32, 0);
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+}
+
+
+M68KMAKE_OP(cmp, 8, ., d)
+{
+ uint src = MASK_OUT_ABOVE_8(DY);
+ uint dst = MASK_OUT_ABOVE_8(DX);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+}
+
+
+M68KMAKE_OP(cmp, 8, ., .)
+{
+ uint src = M68KMAKE_GET_OPER_AY_8;
+ uint dst = MASK_OUT_ABOVE_8(DX);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+}
+
+
+M68KMAKE_OP(cmp, 16, ., d)
+{
+ uint src = MASK_OUT_ABOVE_16(DY);
+ uint dst = MASK_OUT_ABOVE_16(DX);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_C = CFLAG_16(res);
+}
+
+
+M68KMAKE_OP(cmp, 16, ., a)
+{
+ uint src = MASK_OUT_ABOVE_16(AY);
+ uint dst = MASK_OUT_ABOVE_16(DX);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_C = CFLAG_16(res);
+}
+
+
+M68KMAKE_OP(cmp, 16, ., .)
+{
+ uint src = M68KMAKE_GET_OPER_AY_16;
+ uint dst = MASK_OUT_ABOVE_16(DX);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_C = CFLAG_16(res);
+}
+
+
+M68KMAKE_OP(cmp, 32, ., d)
+{
+ uint src = DY;
+ uint dst = DX;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmp, 32, ., a)
+{
+ uint src = AY;
+ uint dst = DX;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmp, 32, ., .)
+{
+ uint src = M68KMAKE_GET_OPER_AY_32;
+ uint dst = DX;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmpa, 16, ., d)
+{
+ uint src = MAKE_INT_16(DY);
+ uint dst = AX;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmpa, 16, ., a)
+{
+ uint src = MAKE_INT_16(AY);
+ uint dst = AX;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmpa, 16, ., .)
+{
+ uint src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16);
+ uint dst = AX;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmpa, 32, ., d)
+{
+ uint src = DY;
+ uint dst = AX;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmpa, 32, ., a)
+{
+ uint src = AY;
+ uint dst = AX;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmpa, 32, ., .)
+{
+ uint src = M68KMAKE_GET_OPER_AY_32;
+ uint dst = AX;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmpi, 8, ., d)
+{
+ uint src = OPER_I_8();
+ uint dst = MASK_OUT_ABOVE_8(DY);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+}
+
+
+M68KMAKE_OP(cmpi, 8, ., .)
+{
+ uint src = OPER_I_8();
+ uint dst = M68KMAKE_GET_OPER_AY_8;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+}
+
+
+M68KMAKE_OP(cmpi, 8, ., pcdi)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint src = OPER_I_8();
+ uint dst = OPER_PCDI_8();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cmpi, 8, ., pcix)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint src = OPER_I_8();
+ uint dst = OPER_PCIX_8();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cmpi, 16, ., d)
+{
+ uint src = OPER_I_16();
+ uint dst = MASK_OUT_ABOVE_16(DY);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_C = CFLAG_16(res);
+}
+
+
+M68KMAKE_OP(cmpi, 16, ., .)
+{
+ uint src = OPER_I_16();
+ uint dst = M68KMAKE_GET_OPER_AY_16;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_C = CFLAG_16(res);
+}
+
+
+M68KMAKE_OP(cmpi, 16, ., pcdi)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint src = OPER_I_16();
+ uint dst = OPER_PCDI_16();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_C = CFLAG_16(res);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cmpi, 16, ., pcix)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint src = OPER_I_16();
+ uint dst = OPER_PCIX_16();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_C = CFLAG_16(res);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cmpi, 32, ., d)
+{
+ uint src = OPER_I_32();
+ uint dst = DY;
+ uint res = dst - src;
+
+ m68ki_cmpild_callback(src, REG_IR & 7); /* auto-disable (see m68kcpu.h) */
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmpi, 32, ., .)
+{
+ uint src = OPER_I_32();
+ uint dst = M68KMAKE_GET_OPER_AY_32;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cmpi, 32, ., pcdi)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint src = OPER_I_32();
+ uint dst = OPER_PCDI_32();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cmpi, 32, ., pcix)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint src = OPER_I_32();
+ uint dst = OPER_PCIX_32();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(cmpm, 8, ., ax7)
+{
+ uint src = OPER_AY_PI_8();
+ uint dst = OPER_A7_PI_8();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+}
+
+
+M68KMAKE_OP(cmpm, 8, ., ay7)
+{
+ uint src = OPER_A7_PI_8();
+ uint dst = OPER_AX_PI_8();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+}
+
+
+M68KMAKE_OP(cmpm, 8, ., axy7)
+{
+ uint src = OPER_A7_PI_8();
+ uint dst = OPER_A7_PI_8();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+}
+
+
+M68KMAKE_OP(cmpm, 8, ., .)
+{
+ uint src = OPER_AY_PI_8();
+ uint dst = OPER_AX_PI_8();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_C = CFLAG_8(res);
+}
+
+
+M68KMAKE_OP(cmpm, 16, ., .)
+{
+ uint src = OPER_AY_PI_16();
+ uint dst = OPER_AX_PI_16();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_C = CFLAG_16(res);
+}
+
+
+M68KMAKE_OP(cmpm, 32, ., .)
+{
+ uint src = OPER_AY_PI_32();
+ uint dst = OPER_AX_PI_32();
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_C = CFLAG_SUB_32(src, dst, res);
+}
+
+
+M68KMAKE_OP(cpbcc, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR,
+ m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2))));
+ return;
+ }
+ m68ki_exception_1111();
+}
+
+
+M68KMAKE_OP(cpdbcc, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR,
+ m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2))));
+ return;
+ }
+ m68ki_exception_1111();
+}
+
+
+M68KMAKE_OP(cpgen, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR,
+ m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2))));
+ return;
+ }
+ m68ki_exception_1111();
+}
+
+
+M68KMAKE_OP(cpscc, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR,
+ m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2))));
+ return;
+ }
+ m68ki_exception_1111();
+}
+
+
+M68KMAKE_OP(cptrapcc, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR,
+ m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2))));
+ return;
+ }
+ m68ki_exception_1111();
+}
+
+
+M68KMAKE_OP(dbt, 16, ., .)
+{
+ REG_PC += 2;
+}
+
+
+M68KMAKE_OP(dbf, 16, ., .)
+{
+ uint* r_dst = &DY;
+ uint res = MASK_OUT_ABOVE_16(*r_dst - 1);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+ if(res != 0xffff)
+ {
+ uint offset = OPER_I_16();
+ REG_PC -= 2;
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_16(offset);
+ USE_CYCLES(CYC_DBCC_F_NOEXP);
+ return;
+ }
+ REG_PC += 2;
+ USE_CYCLES(CYC_DBCC_F_EXP);
+}
+
+
+M68KMAKE_OP(dbcc, 16, ., .)
+{
+ if(M68KMAKE_NOT_CC)
+ {
+ uint* r_dst = &DY;
+ uint res = MASK_OUT_ABOVE_16(*r_dst - 1);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+ if(res != 0xffff)
+ {
+ uint offset = OPER_I_16();
+ REG_PC -= 2;
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_16(offset);
+ USE_CYCLES(CYC_DBCC_F_NOEXP);
+ return;
+ }
+ REG_PC += 2;
+ USE_CYCLES(CYC_DBCC_F_EXP);
+ return;
+ }
+ REG_PC += 2;
+}
+
+
+M68KMAKE_OP(divs, 16, ., d)
+{
+ uint* r_dst = &DX;
+ sint src = MAKE_INT_16(DY);
+ sint quotient;
+ sint remainder;
+
+ if(src != 0)
+ {
+ if((uint32)*r_dst == 0x80000000 && src == -1)
+ {
+ FLAG_Z = 0;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ *r_dst = 0;
+ return;
+ }
+
+ quotient = MAKE_INT_32(*r_dst) / src;
+ remainder = MAKE_INT_32(*r_dst) % src;
+
+ if(quotient == MAKE_INT_16(quotient))
+ {
+ FLAG_Z = quotient;
+ FLAG_N = NFLAG_16(quotient);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
+ return;
+ }
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
+}
+
+
+M68KMAKE_OP(divs, 16, ., .)
+{
+ uint* r_dst = &DX;
+ sint src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16);
+ sint quotient;
+ sint remainder;
+
+ if(src != 0)
+ {
+ if((uint32)*r_dst == 0x80000000 && src == -1)
+ {
+ FLAG_Z = 0;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ *r_dst = 0;
+ return;
+ }
+
+ quotient = MAKE_INT_32(*r_dst) / src;
+ remainder = MAKE_INT_32(*r_dst) % src;
+
+ if(quotient == MAKE_INT_16(quotient))
+ {
+ FLAG_Z = quotient;
+ FLAG_N = NFLAG_16(quotient);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
+ return;
+ }
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
+}
+
+
+M68KMAKE_OP(divu, 16, ., d)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_16(DY);
+
+ if(src != 0)
+ {
+ uint quotient = *r_dst / src;
+ uint remainder = *r_dst % src;
+
+ if(quotient < 0x10000)
+ {
+ FLAG_Z = quotient;
+ FLAG_N = NFLAG_16(quotient);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
+ return;
+ }
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
+}
+
+
+M68KMAKE_OP(divu, 16, ., .)
+{
+ uint* r_dst = &DX;
+ uint src = M68KMAKE_GET_OPER_AY_16;
+
+ if(src != 0)
+ {
+ uint quotient = *r_dst / src;
+ uint remainder = *r_dst % src;
+
+ if(quotient < 0x10000)
+ {
+ FLAG_Z = quotient;
+ FLAG_N = NFLAG_16(quotient);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
+ return;
+ }
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
+}
+
+
+M68KMAKE_OP(divl, 32, ., d)
+{
+#if M68K_USE_64_BIT
+
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint64 divisor = DY;
+ uint64 dividend = 0;
+ uint64 quotient = 0;
+ uint64 remainder = 0;
+
+ if(divisor != 0)
+ {
+ if(BIT_A(word2)) /* 64 bit */
+ {
+ dividend = REG_D[word2 & 7];
+ dividend <<= 32;
+ dividend |= REG_D[(word2 >> 12) & 7];
+
+ if(BIT_B(word2)) /* signed */
+ {
+ quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor));
+ remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor));
+ if((sint64)quotient != (sint64)((sint32)quotient))
+ {
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ }
+ else /* unsigned */
+ {
+ quotient = dividend / divisor;
+ if(quotient > 0xffffffff)
+ {
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ remainder = dividend % divisor;
+ }
+ }
+ else /* 32 bit */
+ {
+ dividend = REG_D[(word2 >> 12) & 7];
+ if(BIT_B(word2)) /* signed */
+ {
+ quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor));
+ remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor));
+ }
+ else /* unsigned */
+ {
+ quotient = dividend / divisor;
+ remainder = dividend % divisor;
+ }
+ }
+
+ REG_D[word2 & 7] = remainder;
+ REG_D[(word2 >> 12) & 7] = quotient;
+
+ FLAG_N = NFLAG_32(quotient);
+ FLAG_Z = quotient;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
+ return;
+ }
+ m68ki_exception_illegal();
+
+#else
+
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint divisor = DY;
+ uint dividend_hi = REG_D[word2 & 7];
+ uint dividend_lo = REG_D[(word2 >> 12) & 7];
+ uint quotient = 0;
+ uint remainder = 0;
+ uint dividend_neg = 0;
+ uint divisor_neg = 0;
+ sint i;
+ uint overflow;
+
+ if(divisor != 0)
+ {
+ /* quad / long : long quotient, long remainder */
+ if(BIT_A(word2))
+ {
+ if(BIT_B(word2)) /* signed */
+ {
+ /* special case in signed divide */
+ if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff)
+ {
+ REG_D[word2 & 7] = 0;
+ REG_D[(word2 >> 12) & 7] = 0x80000000;
+
+ FLAG_N = NFLAG_SET;
+ FLAG_Z = ZFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ if(GET_MSB_32(dividend_hi))
+ {
+ dividend_neg = 1;
+ dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0));
+ dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo);
+ }
+ if(GET_MSB_32(divisor))
+ {
+ divisor_neg = 1;
+ divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor);
+
+ }
+ }
+
+ /* if the upper long is greater than the divisor, we're overflowing. */
+ if(dividend_hi >= divisor)
+ {
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+
+ for(i = 31; i >= 0; i--)
+ {
+ quotient <<= 1;
+ remainder = (remainder << 1) + ((dividend_hi >> i) & 1);
+ if(remainder >= divisor)
+ {
+ remainder -= divisor;
+ quotient++;
+ }
+ }
+ for(i = 31; i >= 0; i--)
+ {
+ quotient <<= 1;
+ overflow = GET_MSB_32(remainder);
+ remainder = (remainder << 1) + ((dividend_lo >> i) & 1);
+ if(remainder >= divisor || overflow)
+ {
+ remainder -= divisor;
+ quotient++;
+ }
+ }
+
+ if(BIT_B(word2)) /* signed */
+ {
+ if(quotient > 0x7fffffff)
+ {
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ if(dividend_neg)
+ {
+ remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder);
+ quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient);
+ }
+ if(divisor_neg)
+ quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient);
+ }
+
+ REG_D[word2 & 7] = remainder;
+ REG_D[(word2 >> 12) & 7] = quotient;
+
+ FLAG_N = NFLAG_32(quotient);
+ FLAG_Z = quotient;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+
+ /* long / long: long quotient, maybe long remainder */
+ if(BIT_B(word2)) /* signed */
+ {
+ /* Special case in divide */
+ if(dividend_lo == 0x80000000 && divisor == 0xffffffff)
+ {
+ FLAG_N = NFLAG_SET;
+ FLAG_Z = ZFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ REG_D[(word2 >> 12) & 7] = 0x80000000;
+ REG_D[word2 & 7] = 0;
+ return;
+ }
+ REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor);
+ quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor);
+ }
+ else
+ {
+ REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor);
+ quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor);
+ }
+
+ FLAG_N = NFLAG_32(quotient);
+ FLAG_Z = quotient;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
+ return;
+ }
+ m68ki_exception_illegal();
+
+#endif
+}
+
+
+M68KMAKE_OP(divl, 32, ., .)
+{
+#if M68K_USE_64_BIT
+
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint64 divisor = M68KMAKE_GET_OPER_AY_32;
+ uint64 dividend = 0;
+ uint64 quotient = 0;
+ uint64 remainder = 0;
+
+ if(divisor != 0)
+ {
+ if(BIT_A(word2)) /* 64 bit */
+ {
+ dividend = REG_D[word2 & 7];
+ dividend <<= 32;
+ dividend |= REG_D[(word2 >> 12) & 7];
+
+ if(BIT_B(word2)) /* signed */
+ {
+ quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor));
+ remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor));
+ if((sint64)quotient != (sint64)((sint32)quotient))
+ {
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ }
+ else /* unsigned */
+ {
+ quotient = dividend / divisor;
+ if(quotient > 0xffffffff)
+ {
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ remainder = dividend % divisor;
+ }
+ }
+ else /* 32 bit */
+ {
+ dividend = REG_D[(word2 >> 12) & 7];
+ if(BIT_B(word2)) /* signed */
+ {
+ quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor));
+ remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor));
+ }
+ else /* unsigned */
+ {
+ quotient = dividend / divisor;
+ remainder = dividend % divisor;
+ }
+ }
+
+ REG_D[word2 & 7] = remainder;
+ REG_D[(word2 >> 12) & 7] = quotient;
+
+ FLAG_N = NFLAG_32(quotient);
+ FLAG_Z = quotient;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
+ return;
+ }
+ m68ki_exception_illegal();
+
+#else
+
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint divisor = M68KMAKE_GET_OPER_AY_32;
+ uint dividend_hi = REG_D[word2 & 7];
+ uint dividend_lo = REG_D[(word2 >> 12) & 7];
+ uint quotient = 0;
+ uint remainder = 0;
+ uint dividend_neg = 0;
+ uint divisor_neg = 0;
+ sint i;
+ uint overflow;
+
+ if(divisor != 0)
+ {
+ /* quad / long : long quotient, long remainder */
+ if(BIT_A(word2))
+ {
+ if(BIT_B(word2)) /* signed */
+ {
+ /* special case in signed divide */
+ if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff)
+ {
+ REG_D[word2 & 7] = 0;
+ REG_D[(word2 >> 12) & 7] = 0x80000000;
+
+ FLAG_N = NFLAG_SET;
+ FLAG_Z = ZFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ if(GET_MSB_32(dividend_hi))
+ {
+ dividend_neg = 1;
+ dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0));
+ dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo);
+ }
+ if(GET_MSB_32(divisor))
+ {
+ divisor_neg = 1;
+ divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor);
+
+ }
+ }
+
+ /* if the upper long is greater than the divisor, we're overflowing. */
+ if(dividend_hi >= divisor)
+ {
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+
+ for(i = 31; i >= 0; i--)
+ {
+ quotient <<= 1;
+ remainder = (remainder << 1) + ((dividend_hi >> i) & 1);
+ if(remainder >= divisor)
+ {
+ remainder -= divisor;
+ quotient++;
+ }
+ }
+ for(i = 31; i >= 0; i--)
+ {
+ quotient <<= 1;
+ overflow = GET_MSB_32(remainder);
+ remainder = (remainder << 1) + ((dividend_lo >> i) & 1);
+ if(remainder >= divisor || overflow)
+ {
+ remainder -= divisor;
+ quotient++;
+ }
+ }
+
+ if(BIT_B(word2)) /* signed */
+ {
+ if(quotient > 0x7fffffff)
+ {
+ FLAG_V = VFLAG_SET;
+ return;
+ }
+ if(dividend_neg)
+ {
+ remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder);
+ quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient);
+ }
+ if(divisor_neg)
+ quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient);
+ }
+
+ REG_D[word2 & 7] = remainder;
+ REG_D[(word2 >> 12) & 7] = quotient;
+
+ FLAG_N = NFLAG_32(quotient);
+ FLAG_Z = quotient;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+
+ /* long / long: long quotient, maybe long remainder */
+ if(BIT_B(word2)) /* signed */
+ {
+ /* Special case in divide */
+ if(dividend_lo == 0x80000000 && divisor == 0xffffffff)
+ {
+ FLAG_N = NFLAG_SET;
+ FLAG_Z = ZFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ REG_D[(word2 >> 12) & 7] = 0x80000000;
+ REG_D[word2 & 7] = 0;
+ return;
+ }
+ REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor);
+ quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor);
+ }
+ else
+ {
+ REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor);
+ quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor);
+ }
+
+ FLAG_N = NFLAG_32(quotient);
+ FLAG_Z = quotient;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
+ return;
+ }
+ m68ki_exception_illegal();
+
+#endif
+}
+
+
+M68KMAKE_OP(eor, 8, ., d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY ^= MASK_OUT_ABOVE_8(DX));
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eor, 8, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea));
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eor, 16, ., d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY ^= MASK_OUT_ABOVE_16(DX));
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eor, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea));
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eor, 32, ., d)
+{
+ uint res = DY ^= DX;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eor, 32, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint res = DX ^ m68ki_read_32(ea);
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eori, 8, ., d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY ^= OPER_I_8());
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eori, 8, ., .)
+{
+ uint src = OPER_I_8();
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint res = src ^ m68ki_read_8(ea);
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eori, 16, ., d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY ^= OPER_I_16());
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eori, 16, ., .)
+{
+ uint src = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint res = src ^ m68ki_read_16(ea);
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eori, 32, ., d)
+{
+ uint res = DY ^= OPER_I_32();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eori, 32, ., .)
+{
+ uint src = OPER_I_32();
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint res = src ^ m68ki_read_32(ea);
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(eori, 16, toc, .)
+{
+ m68ki_set_ccr(m68ki_get_ccr() ^ OPER_I_16());
+}
+
+
+M68KMAKE_OP(eori, 16, tos, .)
+{
+ if(FLAG_S)
+ {
+ uint src = OPER_I_16();
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_set_sr(m68ki_get_sr() ^ src);
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(exg, 32, dd, .)
+{
+ uint* reg_a = &DX;
+ uint* reg_b = &DY;
+ uint tmp = *reg_a;
+ *reg_a = *reg_b;
+ *reg_b = tmp;
+}
+
+
+M68KMAKE_OP(exg, 32, aa, .)
+{
+ uint* reg_a = &AX;
+ uint* reg_b = &AY;
+ uint tmp = *reg_a;
+ *reg_a = *reg_b;
+ *reg_b = tmp;
+}
+
+
+M68KMAKE_OP(exg, 32, da, .)
+{
+ uint* reg_a = &DX;
+ uint* reg_b = &AY;
+ uint tmp = *reg_a;
+ *reg_a = *reg_b;
+ *reg_b = tmp;
+}
+
+
+M68KMAKE_OP(ext, 16, ., .)
+{
+ uint* r_dst = &DY;
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xff00 : 0);
+
+ FLAG_N = NFLAG_16(*r_dst);
+ FLAG_Z = MASK_OUT_ABOVE_16(*r_dst);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ext, 32, ., .)
+{
+ uint* r_dst = &DY;
+
+ *r_dst = MASK_OUT_ABOVE_16(*r_dst) | (GET_MSB_16(*r_dst) ? 0xffff0000 : 0);
+
+ FLAG_N = NFLAG_32(*r_dst);
+ FLAG_Z = *r_dst;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(extb, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint* r_dst = &DY;
+
+ *r_dst = MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xffffff00 : 0);
+
+ FLAG_N = NFLAG_32(*r_dst);
+ FLAG_Z = *r_dst;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(illegal, 0, ., .)
+{
+ m68ki_exception_illegal();
+}
+
+M68KMAKE_OP(jmp, 32, ., .)
+{
+ m68ki_jump(M68KMAKE_GET_EA_AY_32);
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ if(REG_PC == REG_PPC)
+ USE_ALL_CYCLES();
+}
+
+
+M68KMAKE_OP(jsr, 32, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_push_32(REG_PC);
+ m68ki_jump(ea);
+}
+
+
+M68KMAKE_OP(lea, 32, ., .)
+{
+ AX = M68KMAKE_GET_EA_AY_32;
+}
+
+
+M68KMAKE_OP(link, 16, ., a7)
+{
+ REG_A[7] -= 4;
+ m68ki_write_32(REG_A[7], REG_A[7]);
+ REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16()));
+}
+
+
+M68KMAKE_OP(link, 16, ., .)
+{
+ uint* r_dst = &AY;
+
+ m68ki_push_32(*r_dst);
+ *r_dst = REG_A[7];
+ REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16()));
+}
+
+
+M68KMAKE_OP(link, 32, ., a7)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ REG_A[7] -= 4;
+ m68ki_write_32(REG_A[7], REG_A[7]);
+ REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + OPER_I_32());
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(link, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint* r_dst = &AY;
+
+ m68ki_push_32(*r_dst);
+ *r_dst = REG_A[7];
+ REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + OPER_I_32());
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(lsr, 8, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = src >> shift;
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src << (9-shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsr, 16, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src >> shift;
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src << (9-shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsr, 32, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = *r_dst;
+ uint res = src >> shift;
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src << (9-shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsr, 8, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = src >> shift;
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift <= 8)
+ {
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+ FLAG_X = FLAG_C = src << (9-shift);
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ *r_dst &= 0xffffff00;
+ FLAG_X = XFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_8(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsr, 16, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = src >> shift;
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift <= 16)
+ {
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+ FLAG_C = FLAG_X = (src >> (shift - 1))<<8;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ *r_dst &= 0xffff0000;
+ FLAG_X = XFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_16(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsr, 32, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = *r_dst;
+ uint res = src >> shift;
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift < 32)
+ {
+ *r_dst = res;
+ FLAG_C = FLAG_X = (src >> (shift - 1))<<8;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ *r_dst = 0;
+ FLAG_X = FLAG_C = (shift == 32 ? GET_MSB_32(src)>>23 : 0);
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_32(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsr, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = src >> 1;
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = res;
+ FLAG_C = FLAG_X = src << 8;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsl, 8, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = MASK_OUT_ABOVE_8(src << shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src << shift;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsl, 16, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = MASK_OUT_ABOVE_16(src << shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src >> (8-shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsl, 32, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = *r_dst;
+ uint res = MASK_OUT_ABOVE_32(src << shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src >> (24-shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsl, 8, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = MASK_OUT_ABOVE_8(src << shift);
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift <= 8)
+ {
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+ FLAG_X = FLAG_C = src << shift;
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ *r_dst &= 0xffffff00;
+ FLAG_X = XFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_8(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsl, 16, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = MASK_OUT_ABOVE_16(src << shift);
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift <= 16)
+ {
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+ FLAG_X = FLAG_C = (src << shift) >> 8;
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ *r_dst &= 0xffff0000;
+ FLAG_X = XFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_16(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsl, 32, r, .)
+{
+ uint* r_dst = &DY;
+ uint shift = DX & 0x3f;
+ uint src = *r_dst;
+ uint res = MASK_OUT_ABOVE_32(src << shift);
+
+ if(shift != 0)
+ {
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ if(shift < 32)
+ {
+ *r_dst = res;
+ FLAG_X = FLAG_C = (src >> (32 - shift)) << 8;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ *r_dst = 0;
+ FLAG_X = FLAG_C = ((shift == 32 ? src & 1 : 0))<<8;
+ FLAG_N = NFLAG_CLEAR;
+ FLAG_Z = ZFLAG_SET;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_32(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(lsl, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = MASK_OUT_ABOVE_16(src << 1);
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_X = FLAG_C = src >> 7;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, d, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint* r_dst = &DX;
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, d, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint* r_dst = &DX;
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, ai, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint ea = EA_AX_AI_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, ai, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint ea = EA_AX_AI_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, pi7, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint ea = EA_A7_PI_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, pi, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint ea = EA_AX_PI_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, pi7, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint ea = EA_A7_PI_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, pi, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint ea = EA_AX_PI_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, pd7, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint ea = EA_A7_PD_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, pd, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint ea = EA_AX_PD_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, pd7, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint ea = EA_A7_PD_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, pd, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint ea = EA_AX_PD_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, di, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint ea = EA_AX_DI_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, di, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint ea = EA_AX_DI_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, ix, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint ea = EA_AX_IX_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, ix, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint ea = EA_AX_IX_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, aw, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint ea = EA_AW_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, aw, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint ea = EA_AW_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, al, d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+ uint ea = EA_AL_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 8, al, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+ uint ea = EA_AL_8();
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, d, d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY);
+ uint* r_dst = &DX;
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, d, a)
+{
+ uint res = MASK_OUT_ABOVE_16(AY);
+ uint* r_dst = &DX;
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, d, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_16;
+ uint* r_dst = &DX;
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, ai, d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY);
+ uint ea = EA_AX_AI_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, ai, a)
+{
+ uint res = MASK_OUT_ABOVE_16(AY);
+ uint ea = EA_AX_AI_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, ai, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_16;
+ uint ea = EA_AX_AI_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, pi, d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY);
+ uint ea = EA_AX_PI_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, pi, a)
+{
+ uint res = MASK_OUT_ABOVE_16(AY);
+ uint ea = EA_AX_PI_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, pi, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_16;
+ uint ea = EA_AX_PI_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, pd, d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY);
+ uint ea = EA_AX_PD_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, pd, a)
+{
+ uint res = MASK_OUT_ABOVE_16(AY);
+ uint ea = EA_AX_PD_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, pd, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_16;
+ uint ea = EA_AX_PD_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, di, d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY);
+ uint ea = EA_AX_DI_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, di, a)
+{
+ uint res = MASK_OUT_ABOVE_16(AY);
+ uint ea = EA_AX_DI_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, di, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_16;
+ uint ea = EA_AX_DI_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, ix, d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY);
+ uint ea = EA_AX_IX_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, ix, a)
+{
+ uint res = MASK_OUT_ABOVE_16(AY);
+ uint ea = EA_AX_IX_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, ix, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_16;
+ uint ea = EA_AX_IX_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, aw, d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY);
+ uint ea = EA_AW_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, aw, a)
+{
+ uint res = MASK_OUT_ABOVE_16(AY);
+ uint ea = EA_AW_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, aw, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_16;
+ uint ea = EA_AW_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, al, d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY);
+ uint ea = EA_AL_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, al, a)
+{
+ uint res = MASK_OUT_ABOVE_16(AY);
+ uint ea = EA_AL_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 16, al, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_16;
+ uint ea = EA_AL_16();
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, d, d)
+{
+ uint res = DY;
+ uint* r_dst = &DX;
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, d, a)
+{
+ uint res = AY;
+ uint* r_dst = &DX;
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, d, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_32;
+ uint* r_dst = &DX;
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, ai, d)
+{
+ uint res = DY;
+ uint ea = EA_AX_AI_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, ai, a)
+{
+ uint res = AY;
+ uint ea = EA_AX_AI_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, ai, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_32;
+ uint ea = EA_AX_AI_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, pi, d)
+{
+ uint res = DY;
+ uint ea = EA_AX_PI_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, pi, a)
+{
+ uint res = AY;
+ uint ea = EA_AX_PI_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, pi, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_32;
+ uint ea = EA_AX_PI_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, pd, d)
+{
+ uint res = DY;
+ uint ea = EA_AX_PD_32();
+
+ m68ki_write_16(ea+2, res & 0xFFFF );
+ m68ki_write_16(ea, (res >> 16) & 0xFFFF );
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, pd, a)
+{
+ uint res = AY;
+ uint ea = EA_AX_PD_32();
+
+ m68ki_write_16(ea+2, res & 0xFFFF );
+ m68ki_write_16(ea, (res >> 16) & 0xFFFF );
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, pd, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_32;
+ uint ea = EA_AX_PD_32();
+
+ m68ki_write_16(ea+2, res & 0xFFFF );
+ m68ki_write_16(ea, (res >> 16) & 0xFFFF );
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, di, d)
+{
+ uint res = DY;
+ uint ea = EA_AX_DI_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, di, a)
+{
+ uint res = AY;
+ uint ea = EA_AX_DI_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, di, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_32;
+ uint ea = EA_AX_DI_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, ix, d)
+{
+ uint res = DY;
+ uint ea = EA_AX_IX_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, ix, a)
+{
+ uint res = AY;
+ uint ea = EA_AX_IX_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, ix, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_32;
+ uint ea = EA_AX_IX_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, aw, d)
+{
+ uint res = DY;
+ uint ea = EA_AW_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, aw, a)
+{
+ uint res = AY;
+ uint ea = EA_AW_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, aw, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_32;
+ uint ea = EA_AW_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, al, d)
+{
+ uint res = DY;
+ uint ea = EA_AL_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, al, a)
+{
+ uint res = AY;
+ uint ea = EA_AL_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move, 32, al, .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_32;
+ uint ea = EA_AL_32();
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(movea, 16, ., d)
+{
+ AX = MAKE_INT_16(DY);
+}
+
+
+M68KMAKE_OP(movea, 16, ., a)
+{
+ AX = MAKE_INT_16(AY);
+}
+
+
+M68KMAKE_OP(movea, 16, ., .)
+{
+ AX = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16);
+}
+
+
+M68KMAKE_OP(movea, 32, ., d)
+{
+ AX = DY;
+}
+
+
+M68KMAKE_OP(movea, 32, ., a)
+{
+ AX = AY;
+}
+
+
+M68KMAKE_OP(movea, 32, ., .)
+{
+ AX = M68KMAKE_GET_OPER_AY_32;
+}
+
+
+M68KMAKE_OP(move, 16, frc, d)
+{
+ if(CPU_TYPE_IS_010_PLUS(CPU_TYPE))
+ {
+ DY = MASK_OUT_BELOW_16(DY) | m68ki_get_ccr();
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(move, 16, frc, .)
+{
+ if(CPU_TYPE_IS_010_PLUS(CPU_TYPE))
+ {
+ m68ki_write_16(M68KMAKE_GET_EA_AY_16, m68ki_get_ccr());
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(move, 16, toc, d)
+{
+ m68ki_set_ccr(DY);
+}
+
+
+M68KMAKE_OP(move, 16, toc, .)
+{
+ m68ki_set_ccr(M68KMAKE_GET_OPER_AY_16);
+}
+
+
+M68KMAKE_OP(move, 16, frs, d)
+{
+ if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */
+ {
+ DY = MASK_OUT_BELOW_16(DY) | m68ki_get_sr();
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(move, 16, frs, .)
+{
+ if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */
+ {
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ m68ki_write_16(ea, m68ki_get_sr());
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(move, 16, tos, d)
+{
+ if(FLAG_S)
+ {
+ m68ki_set_sr(DY);
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(move, 16, tos, .)
+{
+ if(FLAG_S)
+ {
+ uint new_sr = M68KMAKE_GET_OPER_AY_16;
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_set_sr(new_sr);
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(move, 32, fru, .)
+{
+ if(FLAG_S)
+ {
+ AY = REG_USP;
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(move, 32, tou, .)
+{
+ if(FLAG_S)
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ REG_USP = AY;
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(movec, 32, cr, .)
+{
+ if(CPU_TYPE_IS_010_PLUS(CPU_TYPE))
+ {
+ if(FLAG_S)
+ {
+ uint word2 = OPER_I_16();
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ switch (word2 & 0xfff)
+ {
+ case 0x000: /* SFC */
+ REG_DA[(word2 >> 12) & 15] = REG_SFC;
+ return;
+ case 0x001: /* DFC */
+ REG_DA[(word2 >> 12) & 15] = REG_DFC;
+ return;
+ case 0x002: /* CACR */
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ REG_DA[(word2 >> 12) & 15] = REG_CACR;
+ return;
+ }
+ return;
+ case 0x800: /* USP */
+ REG_DA[(word2 >> 12) & 15] = REG_USP;
+ return;
+ case 0x801: /* VBR */
+ REG_DA[(word2 >> 12) & 15] = REG_VBR;
+ return;
+ case 0x802: /* CAAR */
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ REG_DA[(word2 >> 12) & 15] = REG_CAAR;
+ return;
+ }
+ m68ki_exception_illegal();
+ break;
+ case 0x803: /* MSP */
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ REG_DA[(word2 >> 12) & 15] = FLAG_M ? REG_SP : REG_MSP;
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x804: /* ISP */
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ REG_DA[(word2 >> 12) & 15] = FLAG_M ? REG_ISP : REG_SP;
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x003: /* TC */
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x004: /* ITT0 */
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x005: /* ITT1 */
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x006: /* DTT0 */
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x007: /* DTT1 */
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x805: /* MMUSR */
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x806: /* URP */
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x807: /* SRP */
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ default:
+ m68ki_exception_illegal();
+ return;
+ }
+ }
+ m68ki_exception_privilege_violation();
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(movec, 32, rc, .)
+{
+ if(CPU_TYPE_IS_010_PLUS(CPU_TYPE))
+ {
+ if(FLAG_S)
+ {
+ uint word2 = OPER_I_16();
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ switch (word2 & 0xfff)
+ {
+ case 0x000: /* SFC */
+ REG_SFC = REG_DA[(word2 >> 12) & 15] & 7;
+ return;
+ case 0x001: /* DFC */
+ REG_DFC = REG_DA[(word2 >> 12) & 15] & 7;
+ return;
+ case 0x002: /* CACR */
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ if (CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ REG_CACR = REG_DA[(word2 >> 12) & 15];
+ }
+ else
+ {
+ /* non 68040 can only set the lower 4 bits (C,CE,F,E) */
+ REG_CACR = REG_DA[(word2 >> 12) & 15] & 0x0f;
+ }
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x800: /* USP */
+ REG_USP = REG_DA[(word2 >> 12) & 15];
+ return;
+ case 0x801: /* VBR */
+ REG_VBR = REG_DA[(word2 >> 12) & 15];
+ return;
+ case 0x802: /* CAAR */
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ REG_CAAR = REG_DA[(word2 >> 12) & 15];
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x803: /* MSP */
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* we are in supervisor mode so just check for M flag */
+ if(!FLAG_M)
+ {
+ REG_MSP = REG_DA[(word2 >> 12) & 15];
+ return;
+ }
+ REG_SP = REG_DA[(word2 >> 12) & 15];
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x804: /* ISP */
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ if(!FLAG_M)
+ {
+ REG_SP = REG_DA[(word2 >> 12) & 15];
+ return;
+ }
+ REG_ISP = REG_DA[(word2 >> 12) & 15];
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x003: /* TC */
+ if (CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x004: /* ITT0 */
+ if (CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x005: /* ITT1 */
+ if (CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x006: /* DTT0 */
+ if (CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x007: /* DTT1 */
+ if (CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x805: /* MMUSR */
+ if (CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x806: /* URP */
+ if (CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ case 0x807: /* SRP */
+ if (CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ /* TODO */
+ return;
+ }
+ m68ki_exception_illegal();
+ return;
+ default:
+ m68ki_exception_illegal();
+ return;
+ }
+ }
+ m68ki_exception_privilege_violation();
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(movem, 16, re, pd)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = AY;
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ ea -= 2;
+ m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_DA[15-i]));
+ count++;
+ }
+ AY = ea;
+
+ USE_CYCLES(count<<CYC_MOVEM_W);
+}
+
+
+M68KMAKE_OP(movem, 16, re, .)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_DA[i]));
+ ea += 2;
+ count++;
+ }
+
+ USE_CYCLES(count<<CYC_MOVEM_W);
+}
+
+
+M68KMAKE_OP(movem, 32, re, pd)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = AY;
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ ea -= 4;
+ m68ki_write_16(ea+2, REG_DA[15-i] & 0xFFFF );
+ m68ki_write_16(ea, (REG_DA[15-i] >> 16) & 0xFFFF );
+ count++;
+ }
+ AY = ea;
+
+ USE_CYCLES(count<<CYC_MOVEM_L);
+}
+
+
+M68KMAKE_OP(movem, 32, re, .)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ m68ki_write_32(ea, REG_DA[i]);
+ ea += 4;
+ count++;
+ }
+
+ USE_CYCLES(count<<CYC_MOVEM_L);
+}
+
+
+M68KMAKE_OP(movem, 16, er, pi)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = AY;
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ REG_DA[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16(ea)));
+ ea += 2;
+ count++;
+ }
+ AY = ea;
+
+ USE_CYCLES(count<<CYC_MOVEM_W);
+}
+
+
+M68KMAKE_OP(movem, 16, er, pcdi)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = EA_PCDI_16();
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ REG_DA[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_pcrel_16(ea)));
+ ea += 2;
+ count++;
+ }
+
+ USE_CYCLES(count<<CYC_MOVEM_W);
+}
+
+
+M68KMAKE_OP(movem, 16, er, pcix)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = EA_PCIX_16();
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ REG_DA[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_pcrel_16(ea)));
+ ea += 2;
+ count++;
+ }
+
+ USE_CYCLES(count<<CYC_MOVEM_W);
+}
+
+
+M68KMAKE_OP(movem, 16, er, .)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ REG_DA[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16(ea)));
+ ea += 2;
+ count++;
+ }
+
+ USE_CYCLES(count<<CYC_MOVEM_W);
+}
+
+
+M68KMAKE_OP(movem, 32, er, pi)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = AY;
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ REG_DA[i] = m68ki_read_32(ea);
+ ea += 4;
+ count++;
+ }
+ AY = ea;
+
+ USE_CYCLES(count<<CYC_MOVEM_L);
+}
+
+
+M68KMAKE_OP(movem, 32, er, pcdi)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = EA_PCDI_32();
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ REG_DA[i] = m68ki_read_pcrel_32(ea);
+ ea += 4;
+ count++;
+ }
+
+ USE_CYCLES(count<<CYC_MOVEM_L);
+}
+
+
+M68KMAKE_OP(movem, 32, er, pcix)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = EA_PCIX_32();
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ REG_DA[i] = m68ki_read_pcrel_32(ea);
+ ea += 4;
+ count++;
+ }
+
+ USE_CYCLES(count<<CYC_MOVEM_L);
+}
+
+
+M68KMAKE_OP(movem, 32, er, .)
+{
+ uint i = 0;
+ uint register_list = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint count = 0;
+
+ for(; i < 16; i++)
+ if(register_list & (1 << i))
+ {
+ REG_DA[i] = m68ki_read_32(ea);
+ ea += 4;
+ count++;
+ }
+
+ USE_CYCLES(count<<CYC_MOVEM_L);
+}
+
+
+M68KMAKE_OP(movep, 16, re, .)
+{
+ uint ea = EA_AY_DI_16();
+ uint src = DX;
+
+ m68ki_write_8(ea, MASK_OUT_ABOVE_8(src >> 8));
+ m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src));
+}
+
+
+M68KMAKE_OP(movep, 32, re, .)
+{
+ uint ea = EA_AY_DI_32();
+ uint src = DX;
+
+ m68ki_write_8(ea, MASK_OUT_ABOVE_8(src >> 24));
+ m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src >> 16));
+ m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src >> 8));
+ m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src));
+}
+
+
+M68KMAKE_OP(movep, 16, er, .)
+{
+ uint ea = EA_AY_DI_16();
+ uint* r_dst = &DX;
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | ((m68ki_read_8(ea) << 8) + m68ki_read_8(ea + 2));
+}
+
+
+M68KMAKE_OP(movep, 32, er, .)
+{
+ uint ea = EA_AY_DI_32();
+
+ DX = (m68ki_read_8(ea) << 24) + (m68ki_read_8(ea + 2) << 16)
+ + (m68ki_read_8(ea + 4) << 8) + m68ki_read_8(ea + 6);
+}
+
+
+M68KMAKE_OP(moves, 8, ., .)
+{
+ if(CPU_TYPE_IS_010_PLUS(CPU_TYPE))
+ {
+ if(FLAG_S)
+ {
+ uint word2 = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_8;
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ if(BIT_B(word2)) /* Register to memory */
+ {
+ m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15]));
+ return;
+ }
+ if(BIT_F(word2)) /* Memory to address register */
+ {
+ REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC));
+ if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE))
+ USE_CYCLES(2);
+ return;
+ }
+ /* Memory to data register */
+ REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC);
+ if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE))
+ USE_CYCLES(2);
+ return;
+ }
+ m68ki_exception_privilege_violation();
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(moves, 16, ., .)
+{
+ if(CPU_TYPE_IS_010_PLUS(CPU_TYPE))
+ {
+ if(FLAG_S)
+ {
+ uint word2 = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_16;
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ if(BIT_B(word2)) /* Register to memory */
+ {
+ m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15]));
+ return;
+ }
+ if(BIT_F(word2)) /* Memory to address register */
+ {
+ REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC));
+ if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE))
+ USE_CYCLES(2);
+ return;
+ }
+ /* Memory to data register */
+ REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC);
+ if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE))
+ USE_CYCLES(2);
+ return;
+ }
+ m68ki_exception_privilege_violation();
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(moves, 32, ., .)
+{
+ if(CPU_TYPE_IS_010_PLUS(CPU_TYPE))
+ {
+ if(FLAG_S)
+ {
+ uint word2 = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_32;
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ if(BIT_B(word2)) /* Register to memory */
+ {
+ m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]);
+ if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE))
+ USE_CYCLES(2);
+ return;
+ }
+ /* Memory to register */
+ REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC);
+ if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE))
+ USE_CYCLES(2);
+ return;
+ }
+ m68ki_exception_privilege_violation();
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(moveq, 32, ., .)
+{
+ uint res = DX = MAKE_INT_8(MASK_OUT_ABOVE_8(REG_IR));
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(move16, 32, ., .)
+{
+ UINT16 w2 = OPER_I_16();
+ int ax = REG_IR & 7;
+ int ay = (w2 >> 12) & 7;
+
+ m68ki_write_32(REG_A[ay], m68ki_read_32(REG_A[ax]));
+ m68ki_write_32(REG_A[ay]+4, m68ki_read_32(REG_A[ax]+4));
+ m68ki_write_32(REG_A[ay]+8, m68ki_read_32(REG_A[ax]+8));
+ m68ki_write_32(REG_A[ay]+12, m68ki_read_32(REG_A[ax]+12));
+
+ REG_A[ax] += 16;
+ REG_A[ay] += 16;
+}
+
+
+M68KMAKE_OP(muls, 16, ., d)
+{
+ uint* r_dst = &DX;
+ uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(DY) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst)));
+
+ *r_dst = res;
+
+ FLAG_Z = res;
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(muls, 16, ., .)
+{
+ uint* r_dst = &DX;
+ uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(M68KMAKE_GET_OPER_AY_16) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst)));
+
+ *r_dst = res;
+
+ FLAG_Z = res;
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(mulu, 16, ., d)
+{
+ uint* r_dst = &DX;
+ uint res = MASK_OUT_ABOVE_16(DY) * MASK_OUT_ABOVE_16(*r_dst);
+
+ *r_dst = res;
+
+ FLAG_Z = res;
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(mulu, 16, ., .)
+{
+ uint* r_dst = &DX;
+ uint res = M68KMAKE_GET_OPER_AY_16 * MASK_OUT_ABOVE_16(*r_dst);
+
+ *r_dst = res;
+
+ FLAG_Z = res;
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(mull, 32, ., d)
+{
+#if M68K_USE_64_BIT
+
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint64 src = DY;
+ uint64 dst = REG_D[(word2 >> 12) & 7];
+ uint64 res;
+
+ FLAG_C = CFLAG_CLEAR;
+
+ if(BIT_B(word2)) /* signed */
+ {
+ res = (sint64)((sint32)src) * (sint64)((sint32)dst);
+ if(!BIT_A(word2))
+ {
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = ((sint64)res != (sint32)res)<<7;
+ REG_D[(word2 >> 12) & 7] = FLAG_Z;
+ return;
+ }
+ FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32);
+ FLAG_N = NFLAG_64(res);
+ FLAG_V = VFLAG_CLEAR;
+ REG_D[word2 & 7] = (res >> 32);
+ REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res);
+ return;
+ }
+
+ res = src * dst;
+ if(!BIT_A(word2))
+ {
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = (res > 0xffffffff)<<7;
+ REG_D[(word2 >> 12) & 7] = FLAG_Z;
+ return;
+ }
+ FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32);
+ FLAG_N = NFLAG_64(res);
+ FLAG_V = VFLAG_CLEAR;
+ REG_D[word2 & 7] = (res >> 32);
+ REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res);
+ return;
+ }
+ m68ki_exception_illegal();
+
+#else
+
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint src = DY;
+ uint dst = REG_D[(word2 >> 12) & 7];
+ uint neg = GET_MSB_32(src ^ dst);
+ uint src1;
+ uint src2;
+ uint dst1;
+ uint dst2;
+ uint r1;
+ uint r2;
+ uint r3;
+ uint r4;
+ uint lo;
+ uint hi;
+
+ FLAG_C = CFLAG_CLEAR;
+
+ if(BIT_B(word2)) /* signed */
+ {
+ if(GET_MSB_32(src))
+ src = (uint)MASK_OUT_ABOVE_32(-(sint)src);
+ if(GET_MSB_32(dst))
+ dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst);
+ }
+
+ src1 = MASK_OUT_ABOVE_16(src);
+ src2 = src>>16;
+ dst1 = MASK_OUT_ABOVE_16(dst);
+ dst2 = dst>>16;
+
+
+ r1 = src1 * dst1;
+ r2 = src1 * dst2;
+ r3 = src2 * dst1;
+ r4 = src2 * dst2;
+
+ lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16);
+ hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16);
+
+ if(BIT_B(word2) && neg)
+ {
+ hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0));
+ lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo);
+ }
+
+ if(BIT_A(word2))
+ {
+ REG_D[word2 & 7] = hi;
+ REG_D[(word2 >> 12) & 7] = lo;
+ FLAG_N = NFLAG_32(hi);
+ FLAG_Z = hi | lo;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ REG_D[(word2 >> 12) & 7] = lo;
+ FLAG_N = NFLAG_32(lo);
+ FLAG_Z = lo;
+ if(BIT_B(word2))
+ FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7;
+ else
+ FLAG_V = (hi != 0) << 7;
+ return;
+ }
+ m68ki_exception_illegal();
+
+#endif
+}
+
+
+M68KMAKE_OP(mull, 32, ., .)
+{
+#if M68K_USE_64_BIT
+
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint64 src = M68KMAKE_GET_OPER_AY_32;
+ uint64 dst = REG_D[(word2 >> 12) & 7];
+ uint64 res;
+
+ FLAG_C = CFLAG_CLEAR;
+
+ if(BIT_B(word2)) /* signed */
+ {
+ res = (sint64)((sint32)src) * (sint64)((sint32)dst);
+ if(!BIT_A(word2))
+ {
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = ((sint64)res != (sint32)res)<<7;
+ REG_D[(word2 >> 12) & 7] = FLAG_Z;
+ return;
+ }
+ FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32);
+ FLAG_N = NFLAG_64(res);
+ FLAG_V = VFLAG_CLEAR;
+ REG_D[word2 & 7] = (res >> 32);
+ REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res);
+ return;
+ }
+
+ res = src * dst;
+ if(!BIT_A(word2))
+ {
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_N = NFLAG_32(res);
+ FLAG_V = (res > 0xffffffff)<<7;
+ REG_D[(word2 >> 12) & 7] = FLAG_Z;
+ return;
+ }
+ FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32);
+ FLAG_N = NFLAG_64(res);
+ FLAG_V = VFLAG_CLEAR;
+ REG_D[word2 & 7] = (res >> 32);
+ REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res);
+ return;
+ }
+ m68ki_exception_illegal();
+
+#else
+
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint word2 = OPER_I_16();
+ uint src = M68KMAKE_GET_OPER_AY_32;
+ uint dst = REG_D[(word2 >> 12) & 7];
+ uint neg = GET_MSB_32(src ^ dst);
+ uint src1;
+ uint src2;
+ uint dst1;
+ uint dst2;
+ uint r1;
+ uint r2;
+ uint r3;
+ uint r4;
+ uint lo;
+ uint hi;
+
+ FLAG_C = CFLAG_CLEAR;
+
+ if(BIT_B(word2)) /* signed */
+ {
+ if(GET_MSB_32(src))
+ src = (uint)MASK_OUT_ABOVE_32(-(sint)src);
+ if(GET_MSB_32(dst))
+ dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst);
+ }
+
+ src1 = MASK_OUT_ABOVE_16(src);
+ src2 = src>>16;
+ dst1 = MASK_OUT_ABOVE_16(dst);
+ dst2 = dst>>16;
+
+
+ r1 = src1 * dst1;
+ r2 = src1 * dst2;
+ r3 = src2 * dst1;
+ r4 = src2 * dst2;
+
+ lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16);
+ hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16);
+
+ if(BIT_B(word2) && neg)
+ {
+ hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0));
+ lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo);
+ }
+
+ if(BIT_A(word2))
+ {
+ REG_D[word2 & 7] = hi;
+ REG_D[(word2 >> 12) & 7] = lo;
+ FLAG_N = NFLAG_32(hi);
+ FLAG_Z = hi | lo;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ REG_D[(word2 >> 12) & 7] = lo;
+ FLAG_N = NFLAG_32(lo);
+ FLAG_Z = lo;
+ if(BIT_B(word2))
+ FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7;
+ else
+ FLAG_V = (hi != 0) << 7;
+ return;
+ }
+ m68ki_exception_illegal();
+
+#endif
+}
+
+
+M68KMAKE_OP(nbcd, 8, ., d)
+{
+ uint* r_dst = &DY;
+ uint dst = *r_dst;
+ uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1());
+
+ if(res != 0x9a)
+ {
+ FLAG_V = ~res; /* Undefined V behavior */
+
+ if((res & 0x0f) == 0xa)
+ res = (res & 0xf0) + 0x10;
+
+ res = MASK_OUT_ABOVE_8(res);
+
+ FLAG_V &= res; /* Undefined V behavior part II */
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_Z |= res;
+ FLAG_C = CFLAG_SET;
+ FLAG_X = XFLAG_SET;
+ }
+ else
+ {
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_X = XFLAG_CLEAR;
+ }
+ FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+}
+
+
+M68KMAKE_OP(nbcd, 8, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint dst = m68ki_read_8(ea);
+ uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1());
+
+ if(res != 0x9a)
+ {
+ FLAG_V = ~res; /* Undefined V behavior */
+
+ if((res & 0x0f) == 0xa)
+ res = (res & 0xf0) + 0x10;
+
+ res = MASK_OUT_ABOVE_8(res);
+
+ FLAG_V &= res; /* Undefined V behavior part II */
+
+ m68ki_write_8(ea, MASK_OUT_ABOVE_8(res));
+
+ FLAG_Z |= res;
+ FLAG_C = CFLAG_SET;
+ FLAG_X = XFLAG_SET;
+ }
+ else
+ {
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_X = XFLAG_CLEAR;
+ }
+ FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+}
+
+
+M68KMAKE_OP(neg, 8, ., d)
+{
+ uint* r_dst = &DY;
+ uint res = 0 - MASK_OUT_ABOVE_8(*r_dst);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_C = FLAG_X = CFLAG_8(res);
+ FLAG_V = *r_dst & res;
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(neg, 8, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = m68ki_read_8(ea);
+ uint res = 0 - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_C = FLAG_X = CFLAG_8(res);
+ FLAG_V = src & res;
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ m68ki_write_8(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(neg, 16, ., d)
+{
+ uint* r_dst = &DY;
+ uint res = 0 - MASK_OUT_ABOVE_16(*r_dst);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_C = FLAG_X = CFLAG_16(res);
+ FLAG_V = (*r_dst & res)>>8;
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(neg, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = 0 - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_C = FLAG_X = CFLAG_16(res);
+ FLAG_V = (src & res)>>8;
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ m68ki_write_16(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(neg, 32, ., d)
+{
+ uint* r_dst = &DY;
+ uint res = 0 - *r_dst;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_C = FLAG_X = CFLAG_SUB_32(*r_dst, 0, res);
+ FLAG_V = (*r_dst & res)>>24;
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(neg, 32, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint src = m68ki_read_32(ea);
+ uint res = 0 - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res);
+ FLAG_V = (src & res)>>24;
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ m68ki_write_32(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(negx, 8, ., d)
+{
+ uint* r_dst = &DY;
+ uint res = 0 - MASK_OUT_ABOVE_8(*r_dst) - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = *r_dst & res;
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+}
+
+
+M68KMAKE_OP(negx, 8, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = m68ki_read_8(ea);
+ uint res = 0 - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = src & res;
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(negx, 16, ., d)
+{
+ uint* r_dst = &DY;
+ uint res = 0 - MASK_OUT_ABOVE_16(*r_dst) - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = (*r_dst & res)>>8;
+
+ res = MASK_OUT_ABOVE_16(res);
+ FLAG_Z |= res;
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+}
+
+
+M68KMAKE_OP(negx, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = (src & res)>>8;
+
+ res = MASK_OUT_ABOVE_16(res);
+ FLAG_Z |= res;
+
+ m68ki_write_16(ea, res);
+}
+
+
+M68KMAKE_OP(negx, 32, ., d)
+{
+ uint* r_dst = &DY;
+ uint res = 0 - MASK_OUT_ABOVE_32(*r_dst) - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(*r_dst, 0, res);
+ FLAG_V = (*r_dst & res)>>24;
+
+ res = MASK_OUT_ABOVE_32(res);
+ FLAG_Z |= res;
+
+ *r_dst = res;
+}
+
+
+M68KMAKE_OP(negx, 32, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint src = m68ki_read_32(ea);
+ uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res);
+ FLAG_V = (src & res)>>24;
+
+ res = MASK_OUT_ABOVE_32(res);
+ FLAG_Z |= res;
+
+ m68ki_write_32(ea, res);
+}
+
+
+M68KMAKE_OP(nop, 0, ., .)
+{
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+}
+
+
+M68KMAKE_OP(not, 8, ., d)
+{
+ uint* r_dst = &DY;
+ uint res = MASK_OUT_ABOVE_8(~*r_dst);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(not, 8, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea));
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(not, 16, ., d)
+{
+ uint* r_dst = &DY;
+ uint res = MASK_OUT_ABOVE_16(~*r_dst);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(not, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea));
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(not, 32, ., d)
+{
+ uint* r_dst = &DY;
+ uint res = *r_dst = MASK_OUT_ABOVE_32(~*r_dst);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(not, 32, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea));
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(or, 8, er, d)
+{
+ uint res = MASK_OUT_ABOVE_8((DX |= MASK_OUT_ABOVE_8(DY)));
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(or, 8, er, .)
+{
+ uint res = MASK_OUT_ABOVE_8((DX |= M68KMAKE_GET_OPER_AY_8));
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(or, 16, er, d)
+{
+ uint res = MASK_OUT_ABOVE_16((DX |= MASK_OUT_ABOVE_16(DY)));
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(or, 16, er, .)
+{
+ uint res = MASK_OUT_ABOVE_16((DX |= M68KMAKE_GET_OPER_AY_16));
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(or, 32, er, d)
+{
+ uint res = DX |= DY;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(or, 32, er, .)
+{
+ uint res = DX |= M68KMAKE_GET_OPER_AY_32;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(or, 8, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea));
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(or, 16, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea));
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(or, 32, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint res = DX | m68ki_read_32(ea);
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ori, 8, ., d)
+{
+ uint res = MASK_OUT_ABOVE_8((DY |= OPER_I_8()));
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ori, 8, ., .)
+{
+ uint src = OPER_I_8();
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea));
+
+ m68ki_write_8(ea, res);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ori, 16, ., d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY |= OPER_I_16());
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ori, 16, ., .)
+{
+ uint src = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea));
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ori, 32, ., d)
+{
+ uint res = DY |= OPER_I_32();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ori, 32, ., .)
+{
+ uint src = OPER_I_32();
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint res = src | m68ki_read_32(ea);
+
+ m68ki_write_32(ea, res);
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ori, 16, toc, .)
+{
+ m68ki_set_ccr(m68ki_get_ccr() | OPER_I_16());
+}
+
+
+M68KMAKE_OP(ori, 16, tos, .)
+{
+ if(FLAG_S)
+ {
+ uint src = OPER_I_16();
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_set_sr(m68ki_get_sr() | src);
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(pack, 16, rr, .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* Note: DX and DY are reversed in Motorola's docs */
+ uint src = DY + OPER_I_16();
+ uint* r_dst = &DX;
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | ((src >> 4) & 0x00f0) | (src & 0x000f);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(pack, 16, mm, ax7)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* Note: AX and AY are reversed in Motorola's docs */
+ uint ea_src = EA_AY_PD_8();
+ uint src = m68ki_read_8(ea_src);
+ ea_src = EA_AY_PD_8();
+ src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16();
+
+ m68ki_write_8(EA_A7_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f));
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(pack, 16, mm, ay7)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* Note: AX and AY are reversed in Motorola's docs */
+ uint ea_src = EA_A7_PD_8();
+ uint src = m68ki_read_8(ea_src);
+ ea_src = EA_A7_PD_8();
+ src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16();
+
+ m68ki_write_8(EA_AX_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f));
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(pack, 16, mm, axy7)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint ea_src = EA_A7_PD_8();
+ uint src = m68ki_read_8(ea_src);
+ ea_src = EA_A7_PD_8();
+ src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16();
+
+ m68ki_write_8(EA_A7_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f));
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(pack, 16, mm, .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* Note: AX and AY are reversed in Motorola's docs */
+ uint ea_src = EA_AY_PD_8();
+ uint src = m68ki_read_8(ea_src);
+ ea_src = EA_AY_PD_8();
+ src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16();
+
+ m68ki_write_8(EA_AX_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f));
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(pea, 32, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+
+ m68ki_push_32(ea);
+}
+
+
+M68KMAKE_OP(pflush, 32, ., .)
+{
+ if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
+ {
+ // Nothing to do, unless address translation cache is emulated
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(reset, 0, ., .)
+{
+ if(FLAG_S)
+ {
+ m68ki_output_reset(); /* auto-disable (see m68kcpu.h) */
+ USE_CYCLES(CYC_RESET);
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(ror, 8, s, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint shift = orig_shift & 7;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = ROR_8(src, shift);
+
+ if(orig_shift != 0)
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = src << (9-orig_shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ror, 16, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = ROR_16(src, shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = src << (9-shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ror, 32, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint64 src = *r_dst;
+ uint res = ROR_32(src, shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = src << (9-shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ror, 8, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+ uint shift = orig_shift & 7;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = ROR_8(src, shift);
+
+ if(orig_shift != 0)
+ {
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+ FLAG_C = src << (8-((shift-1)&7));
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_8(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ror, 16, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+ uint shift = orig_shift & 15;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = ROR_16(src, shift);
+
+ if(orig_shift != 0)
+ {
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+ FLAG_C = (src >> ((shift - 1) & 15)) << 8;
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_16(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ror, 32, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+ uint shift = orig_shift & 31;
+ uint64 src = *r_dst;
+ uint res = ROR_32(src, shift);
+
+ if(orig_shift != 0)
+ {
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ *r_dst = res;
+ FLAG_C = (src >> ((shift - 1) & 31)) << 8;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_32(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(ror, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = ROR_16(src, 1);
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = src << 8;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(rol, 8, s, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint shift = orig_shift & 7;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = ROL_8(src, shift);
+
+ if(orig_shift != 0)
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_C = src << orig_shift;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(rol, 16, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = ROL_16(src, shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = src >> (8-shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(rol, 32, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint64 src = *r_dst;
+ uint res = ROL_32(src, shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_C = src >> (24-shift);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(rol, 8, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+ uint shift = orig_shift & 7;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = ROL_8(src, shift);
+
+ if(orig_shift != 0)
+ {
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ if(shift != 0)
+ {
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+ FLAG_C = src << shift;
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+ FLAG_C = (src & 1)<<8;
+ FLAG_N = NFLAG_8(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_8(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(rol, 16, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+ uint shift = orig_shift & 15;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = MASK_OUT_ABOVE_16(ROL_16(src, shift));
+
+ if(orig_shift != 0)
+ {
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ if(shift != 0)
+ {
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+ FLAG_C = (src << shift) >> 8;
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+ FLAG_C = (src & 1)<<8;
+ FLAG_N = NFLAG_16(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_16(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(rol, 32, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+ uint shift = orig_shift & 31;
+ uint64 src = *r_dst;
+ uint res = ROL_32(src, shift);
+
+ if(orig_shift != 0)
+ {
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ *r_dst = res;
+
+ FLAG_C = (src >> ((32 - shift) & 0x1f)) << 8;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_N = NFLAG_32(src);
+ FLAG_Z = src;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(rol, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1));
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_C = src >> 7;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxr, 8, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = ROR_9(src | (XFLAG_AS_1() << 8), shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res;
+ res = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxr, 16, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = ROR_17(src | (XFLAG_AS_1() << 16), shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res >> 8;
+ res = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxr, 32, s, .)
+{
+#if M68K_USE_64_BIT
+
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint64 src = *r_dst;
+ uint64 res = src | (((uint64)XFLAG_AS_1()) << 32);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ res = ROR_33_64(res, shift);
+
+ FLAG_C = FLAG_X = res >> 24;
+ res = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+
+#else
+
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = *r_dst;
+ uint res = MASK_OUT_ABOVE_32((ROR_33(src, shift) & ~(1 << (32 - shift))) | (XFLAG_AS_1() << (32 - shift)));
+ uint new_x_flag = src & (1 << (shift - 1));
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = res;
+
+ FLAG_C = FLAG_X = (new_x_flag != 0)<<8;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+
+#endif
+}
+
+
+M68KMAKE_OP(roxr, 8, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+
+ if(orig_shift != 0)
+ {
+ uint shift = orig_shift % 9;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = ROR_9(src | (XFLAG_AS_1() << 8), shift);
+
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res;
+ res = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = FLAG_X;
+ FLAG_N = NFLAG_8(*r_dst);
+ FLAG_Z = MASK_OUT_ABOVE_8(*r_dst);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxr, 16, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+
+ if(orig_shift != 0)
+ {
+ uint shift = orig_shift % 17;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = ROR_17(src | (XFLAG_AS_1() << 16), shift);
+
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res >> 8;
+ res = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = FLAG_X;
+ FLAG_N = NFLAG_16(*r_dst);
+ FLAG_Z = MASK_OUT_ABOVE_16(*r_dst);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxr, 32, r, .)
+{
+#if M68K_USE_64_BIT
+
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+
+ if(orig_shift != 0)
+ {
+ uint shift = orig_shift % 33;
+ uint64 src = *r_dst;
+ uint64 res = src | (((uint64)XFLAG_AS_1()) << 32);
+
+ res = ROR_33_64(res, shift);
+
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res >> 24;
+ res = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = res;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = FLAG_X;
+ FLAG_N = NFLAG_32(*r_dst);
+ FLAG_Z = *r_dst;
+ FLAG_V = VFLAG_CLEAR;
+
+#else
+
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+ uint shift = orig_shift % 33;
+ uint src = *r_dst;
+ uint res = MASK_OUT_ABOVE_32((ROR_33(src, shift) & ~(1 << (32 - shift))) | (XFLAG_AS_1() << (32 - shift)));
+ uint new_x_flag = src & (1 << (shift - 1));
+
+ if(orig_shift != 0)
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ if(shift != 0)
+ {
+ *r_dst = res;
+ FLAG_X = (new_x_flag != 0)<<8;
+ }
+ else
+ res = src;
+ FLAG_C = FLAG_X;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+
+#endif
+}
+
+
+M68KMAKE_OP(roxr, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = ROR_17(src | (XFLAG_AS_1() << 16), 1);
+
+ FLAG_C = FLAG_X = res >> 8;
+ res = MASK_OUT_ABOVE_16(res);
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxl, 8, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = ROL_9(src | (XFLAG_AS_1() << 8), shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res;
+ res = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxl, 16, s, .)
+{
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = ROL_17(src | (XFLAG_AS_1() << 16), shift);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res >> 8;
+ res = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxl, 32, s, .)
+{
+#if M68K_USE_64_BIT
+
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint64 src = *r_dst;
+ uint64 res = src | (((uint64)XFLAG_AS_1()) << 32);
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ res = ROL_33_64(res, shift);
+
+ FLAG_C = FLAG_X = res >> 24;
+ res = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = res;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+
+#else
+
+ uint* r_dst = &DY;
+ uint shift = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint src = *r_dst;
+ uint res = MASK_OUT_ABOVE_32((ROL_33(src, shift) & ~(1 << (shift - 1))) | (XFLAG_AS_1() << (shift - 1)));
+ uint new_x_flag = src & (1 << (32 - shift));
+
+ if(shift != 0)
+ USE_CYCLES(shift<<CYC_SHIFT);
+
+ *r_dst = res;
+
+ FLAG_C = FLAG_X = (new_x_flag != 0)<<8;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+
+#endif
+}
+
+
+M68KMAKE_OP(roxl, 8, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+
+
+ if(orig_shift != 0)
+ {
+ uint shift = orig_shift % 9;
+ uint src = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = ROL_9(src | (XFLAG_AS_1() << 8), shift);
+
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res;
+ res = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = FLAG_X;
+ FLAG_N = NFLAG_8(*r_dst);
+ FLAG_Z = MASK_OUT_ABOVE_8(*r_dst);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxl, 16, r, .)
+{
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+
+ if(orig_shift != 0)
+ {
+ uint shift = orig_shift % 17;
+ uint src = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = ROL_17(src | (XFLAG_AS_1() << 16), shift);
+
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res >> 8;
+ res = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = FLAG_X;
+ FLAG_N = NFLAG_16(*r_dst);
+ FLAG_Z = MASK_OUT_ABOVE_16(*r_dst);
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(roxl, 32, r, .)
+{
+#if M68K_USE_64_BIT
+
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+
+ if(orig_shift != 0)
+ {
+ uint shift = orig_shift % 33;
+ uint64 src = *r_dst;
+ uint64 res = src | (((uint64)XFLAG_AS_1()) << 32);
+
+ res = ROL_33_64(res, shift);
+
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ FLAG_C = FLAG_X = res >> 24;
+ res = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = res;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ return;
+ }
+
+ FLAG_C = FLAG_X;
+ FLAG_N = NFLAG_32(*r_dst);
+ FLAG_Z = *r_dst;
+ FLAG_V = VFLAG_CLEAR;
+
+#else
+
+ uint* r_dst = &DY;
+ uint orig_shift = DX & 0x3f;
+ uint shift = orig_shift % 33;
+ uint src = *r_dst;
+ uint res = MASK_OUT_ABOVE_32((ROL_33(src, shift) & ~(1 << (shift - 1))) | (XFLAG_AS_1() << (shift - 1)));
+ uint new_x_flag = src & (1 << (32 - shift));
+
+ if(orig_shift != 0)
+ USE_CYCLES(orig_shift<<CYC_SHIFT);
+
+ if(shift != 0)
+ {
+ *r_dst = res;
+ FLAG_X = (new_x_flag != 0)<<8;
+ }
+ else
+ res = src;
+ FLAG_C = FLAG_X;
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+
+#endif
+}
+
+
+M68KMAKE_OP(roxl, 16, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = m68ki_read_16(ea);
+ uint res = ROL_17(src | (XFLAG_AS_1() << 16), 1);
+
+ FLAG_C = FLAG_X = res >> 8;
+ res = MASK_OUT_ABOVE_16(res);
+
+ m68ki_write_16(ea, res);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(rtd, 32, ., .)
+{
+ if(CPU_TYPE_IS_010_PLUS(CPU_TYPE))
+ {
+ uint new_pc = m68ki_pull_32();
+
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16()));
+ m68ki_jump(new_pc);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(rte, 32, ., .)
+{
+ if(FLAG_S)
+ {
+ uint new_sr;
+ uint new_pc;
+ uint format_word;
+
+ m68ki_rte_callback(); /* auto-disable (see m68kcpu.h) */
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+
+ if(CPU_TYPE_IS_000(CPU_TYPE))
+ {
+ new_sr = m68ki_pull_16();
+ new_pc = m68ki_pull_32();
+ m68ki_jump(new_pc);
+ m68ki_set_sr(new_sr);
+
+ CPU_INSTR_MODE = INSTRUCTION_YES;
+ CPU_RUN_MODE = RUN_MODE_NORMAL;
+
+ return;
+ }
+
+ if(CPU_TYPE_IS_010(CPU_TYPE))
+ {
+ format_word = m68ki_read_16(REG_A[7]+6) >> 12;
+ if(format_word == 0)
+ {
+ new_sr = m68ki_pull_16();
+ new_pc = m68ki_pull_32();
+ m68ki_fake_pull_16(); /* format word */
+ m68ki_jump(new_pc);
+ m68ki_set_sr(new_sr);
+ CPU_INSTR_MODE = INSTRUCTION_YES;
+ CPU_RUN_MODE = RUN_MODE_NORMAL;
+ return;
+ }
+ CPU_INSTR_MODE = INSTRUCTION_YES;
+ CPU_RUN_MODE = RUN_MODE_NORMAL;
+ /* Not handling bus fault (9) */
+ m68ki_exception_format_error();
+ return;
+ }
+
+ /* Otherwise it's 020 */
+rte_loop:
+ format_word = m68ki_read_16(REG_A[7]+6) >> 12;
+ switch(format_word)
+ {
+ case 0: /* Normal */
+ new_sr = m68ki_pull_16();
+ new_pc = m68ki_pull_32();
+ m68ki_fake_pull_16(); /* format word */
+ m68ki_jump(new_pc);
+ m68ki_set_sr(new_sr);
+ CPU_INSTR_MODE = INSTRUCTION_YES;
+ CPU_RUN_MODE = RUN_MODE_NORMAL;
+ return;
+ case 1: /* Throwaway */
+ new_sr = m68ki_pull_16();
+ m68ki_fake_pull_32(); /* program counter */
+ m68ki_fake_pull_16(); /* format word */
+ m68ki_set_sr_noint(new_sr);
+ goto rte_loop;
+ case 2: /* Trap */
+ new_sr = m68ki_pull_16();
+ new_pc = m68ki_pull_32();
+ m68ki_fake_pull_16(); /* format word */
+ m68ki_fake_pull_32(); /* address */
+ m68ki_jump(new_pc);
+ m68ki_set_sr(new_sr);
+ CPU_INSTR_MODE = INSTRUCTION_YES;
+ CPU_RUN_MODE = RUN_MODE_NORMAL;
+ return;
+ }
+ /* Not handling long or short bus fault */
+ CPU_INSTR_MODE = INSTRUCTION_YES;
+ CPU_RUN_MODE = RUN_MODE_NORMAL;
+ m68ki_exception_format_error();
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(rtm, 32, ., .)
+{
+ if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE))
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR,
+ m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2))));
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(rtr, 32, ., .)
+{
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_set_ccr(m68ki_pull_16());
+ m68ki_jump(m68ki_pull_32());
+}
+
+
+M68KMAKE_OP(rts, 32, ., .)
+{
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_jump(m68ki_pull_32());
+}
+
+
+M68KMAKE_OP(sbcd, 8, rr, .)
+{
+ uint* r_dst = &DX;
+ uint src = DY;
+ uint dst = *r_dst;
+ uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
+
+// FLAG_V = ~res; /* Undefined V behavior */
+ FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to assume cleared. */
+
+ if(res > 9)
+ res -= 6;
+ res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
+ if(res > 0x99)
+ {
+ res += 0xa0;
+ FLAG_X = FLAG_C = CFLAG_SET;
+ FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
+ }
+ else
+ FLAG_N = FLAG_X = FLAG_C = 0;
+
+ res = MASK_OUT_ABOVE_8(res);
+
+// FLAG_V &= res; /* Undefined V behavior part II */
+// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+ FLAG_Z |= res;
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+}
+
+
+M68KMAKE_OP(sbcd, 8, mm, ax7)
+{
+ uint src = OPER_AY_PD_8();
+ uint ea = EA_A7_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
+
+// FLAG_V = ~res; /* Undefined V behavior */
+ FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */
+
+ if(res > 9)
+ res -= 6;
+ res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
+ if(res > 0x99)
+ {
+ res += 0xa0;
+ FLAG_X = FLAG_C = CFLAG_SET;
+ FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
+ }
+ else
+ FLAG_N = FLAG_X = FLAG_C = 0;
+
+ res = MASK_OUT_ABOVE_8(res);
+
+// FLAG_V &= res; /* Undefined V behavior part II */
+// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(sbcd, 8, mm, ay7)
+{
+ uint src = OPER_A7_PD_8();
+ uint ea = EA_AX_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
+
+// FLAG_V = ~res; /* Undefined V behavior */
+ FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */
+
+ if(res > 9)
+ res -= 6;
+ res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
+ if(res > 0x99)
+ {
+ res += 0xa0;
+ FLAG_X = FLAG_C = CFLAG_SET;
+ FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
+ }
+ else
+ FLAG_N = FLAG_X = FLAG_C = 0;
+
+ res = MASK_OUT_ABOVE_8(res);
+
+// FLAG_V &= res; /* Undefined V behavior part II */
+// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(sbcd, 8, mm, axy7)
+{
+ uint src = OPER_A7_PD_8();
+ uint ea = EA_A7_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
+
+// FLAG_V = ~res; /* Undefined V behavior */
+ FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */
+
+ if(res > 9)
+ res -= 6;
+ res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
+ if(res > 0x99)
+ {
+ res += 0xa0;
+ FLAG_X = FLAG_C = CFLAG_SET;
+ FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
+ }
+ else
+ FLAG_N = FLAG_X = FLAG_C = 0;
+
+ res = MASK_OUT_ABOVE_8(res);
+
+// FLAG_V &= res; /* Undefined V behavior part II */
+// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(sbcd, 8, mm, .)
+{
+ uint src = OPER_AY_PD_8();
+ uint ea = EA_AX_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
+
+// FLAG_V = ~res; /* Undefined V behavior */
+ FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */
+
+ if(res > 9)
+ res -= 6;
+ res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
+ if(res > 0x99)
+ {
+ res += 0xa0;
+ FLAG_X = FLAG_C = CFLAG_SET;
+ FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
+ }
+ else
+ FLAG_N = FLAG_X = FLAG_C = 0;
+
+ res = MASK_OUT_ABOVE_8(res);
+
+// FLAG_V &= res; /* Undefined V behavior part II */
+// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(st, 8, ., d)
+{
+ DY |= 0xff;
+}
+
+
+M68KMAKE_OP(st, 8, ., .)
+{
+ m68ki_write_8(M68KMAKE_GET_EA_AY_8, 0xff);
+}
+
+
+M68KMAKE_OP(sf, 8, ., d)
+{
+ DY &= 0xffffff00;
+}
+
+
+M68KMAKE_OP(sf, 8, ., .)
+{
+ m68ki_write_8(M68KMAKE_GET_EA_AY_8, 0);
+}
+
+
+M68KMAKE_OP(scc, 8, ., d)
+{
+ if(M68KMAKE_CC)
+ {
+ DY |= 0xff;
+ USE_CYCLES(CYC_SCC_R_TRUE);
+ return;
+ }
+ DY &= 0xffffff00;
+}
+
+
+M68KMAKE_OP(scc, 8, ., .)
+{
+ m68ki_write_8(M68KMAKE_GET_EA_AY_8, M68KMAKE_CC ? 0xff : 0);
+}
+
+
+M68KMAKE_OP(stop, 0, ., .)
+{
+ if(FLAG_S)
+ {
+ uint new_sr = OPER_I_16();
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ CPU_STOPPED |= STOP_LEVEL_STOP;
+ m68ki_set_sr(new_sr);
+ m68ki_remaining_cycles = 0;
+ return;
+ }
+ m68ki_exception_privilege_violation();
+}
+
+
+M68KMAKE_OP(sub, 8, er, d)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_8(DY);
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(sub, 8, er, .)
+{
+ uint* r_dst = &DX;
+ uint src = M68KMAKE_GET_OPER_AY_8;
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(sub, 16, er, d)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_16(DY);
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(sub, 16, er, a)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_16(AY);
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(sub, 16, er, .)
+{
+ uint* r_dst = &DX;
+ uint src = M68KMAKE_GET_OPER_AY_16;
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(sub, 32, er, d)
+{
+ uint* r_dst = &DX;
+ uint src = DY;
+ uint dst = *r_dst;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(sub, 32, er, a)
+{
+ uint* r_dst = &DX;
+ uint src = AY;
+ uint dst = *r_dst;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(sub, 32, er, .)
+{
+ uint* r_dst = &DX;
+ uint src = M68KMAKE_GET_OPER_AY_32;
+ uint dst = *r_dst;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(sub, 8, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint src = MASK_OUT_ABOVE_8(DX);
+ uint dst = m68ki_read_8(ea);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ m68ki_write_8(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(sub, 16, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint src = MASK_OUT_ABOVE_16(DX);
+ uint dst = m68ki_read_16(ea);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+
+ m68ki_write_16(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(sub, 32, re, .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint src = DX;
+ uint dst = m68ki_read_32(ea);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+
+ m68ki_write_32(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(suba, 16, ., d)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(DY));
+}
+
+
+M68KMAKE_OP(suba, 16, ., a)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(AY));
+}
+
+
+M68KMAKE_OP(suba, 16, ., .)
+{
+ uint* r_dst = &AX;
+ uint src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16);
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst - src);
+}
+
+
+M68KMAKE_OP(suba, 32, ., d)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst - DY);
+}
+
+
+M68KMAKE_OP(suba, 32, ., a)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst - AY);
+}
+
+
+M68KMAKE_OP(suba, 32, ., .)
+{
+ uint* r_dst = &AX;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst - M68KMAKE_GET_OPER_AY_32);
+}
+
+
+M68KMAKE_OP(subi, 8, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = OPER_I_8();
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(subi, 8, ., .)
+{
+ uint src = OPER_I_8();
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint dst = m68ki_read_8(ea);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ m68ki_write_8(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(subi, 16, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = OPER_I_16();
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(subi, 16, ., .)
+{
+ uint src = OPER_I_16();
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint dst = m68ki_read_16(ea);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+
+ m68ki_write_16(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(subi, 32, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = OPER_I_32();
+ uint dst = *r_dst;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(subi, 32, ., .)
+{
+ uint src = OPER_I_32();
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint dst = m68ki_read_32(ea);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+
+ m68ki_write_32(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(subq, 8, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(subq, 8, ., .)
+{
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint dst = m68ki_read_8(ea);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = MASK_OUT_ABOVE_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ m68ki_write_8(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(subq, 16, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z;
+}
+
+
+M68KMAKE_OP(subq, 16, ., a)
+{
+ uint* r_dst = &AY;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst - ((((REG_IR >> 9) - 1) & 7) + 1));
+}
+
+
+M68KMAKE_OP(subq, 16, ., .)
+{
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint ea = M68KMAKE_GET_EA_AY_16;
+ uint dst = m68ki_read_16(ea);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = MASK_OUT_ABOVE_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+
+ m68ki_write_16(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(subq, 32, ., d)
+{
+ uint* r_dst = &DY;
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint dst = *r_dst;
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+
+ *r_dst = FLAG_Z;
+}
+
+
+M68KMAKE_OP(subq, 32, ., a)
+{
+ uint* r_dst = &AY;
+
+ *r_dst = MASK_OUT_ABOVE_32(*r_dst - ((((REG_IR >> 9) - 1) & 7) + 1));
+}
+
+
+M68KMAKE_OP(subq, 32, ., .)
+{
+ uint src = (((REG_IR >> 9) - 1) & 7) + 1;
+ uint ea = M68KMAKE_GET_EA_AY_32;
+ uint dst = m68ki_read_32(ea);
+ uint res = dst - src;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = MASK_OUT_ABOVE_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+
+ m68ki_write_32(ea, FLAG_Z);
+}
+
+
+M68KMAKE_OP(subx, 8, rr, .)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_8(DY);
+ uint dst = MASK_OUT_ABOVE_8(*r_dst);
+ uint res = dst - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
+}
+
+
+M68KMAKE_OP(subx, 16, rr, .)
+{
+ uint* r_dst = &DX;
+ uint src = MASK_OUT_ABOVE_16(DY);
+ uint dst = MASK_OUT_ABOVE_16(*r_dst);
+ uint res = dst - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+
+ res = MASK_OUT_ABOVE_16(res);
+ FLAG_Z |= res;
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
+}
+
+
+M68KMAKE_OP(subx, 32, rr, .)
+{
+ uint* r_dst = &DX;
+ uint src = DY;
+ uint dst = *r_dst;
+ uint res = dst - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+
+ res = MASK_OUT_ABOVE_32(res);
+ FLAG_Z |= res;
+
+ *r_dst = res;
+}
+
+
+M68KMAKE_OP(subx, 8, mm, ax7)
+{
+ uint src = OPER_AY_PD_8();
+ uint ea = EA_A7_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = dst - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(subx, 8, mm, ay7)
+{
+ uint src = OPER_A7_PD_8();
+ uint ea = EA_AX_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = dst - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(subx, 8, mm, axy7)
+{
+ uint src = OPER_A7_PD_8();
+ uint ea = EA_A7_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = dst - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(subx, 8, mm, .)
+{
+ uint src = OPER_AY_PD_8();
+ uint ea = EA_AX_PD_8();
+ uint dst = m68ki_read_8(ea);
+ uint res = dst - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_X = FLAG_C = CFLAG_8(res);
+ FLAG_V = VFLAG_SUB_8(src, dst, res);
+
+ res = MASK_OUT_ABOVE_8(res);
+ FLAG_Z |= res;
+
+ m68ki_write_8(ea, res);
+}
+
+
+M68KMAKE_OP(subx, 16, mm, .)
+{
+ uint src = OPER_AY_PD_16();
+ uint ea = EA_AX_PD_16();
+ uint dst = m68ki_read_16(ea);
+ uint res = dst - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_X = FLAG_C = CFLAG_16(res);
+ FLAG_V = VFLAG_SUB_16(src, dst, res);
+
+ res = MASK_OUT_ABOVE_16(res);
+ FLAG_Z |= res;
+
+ m68ki_write_16(ea, res);
+}
+
+
+M68KMAKE_OP(subx, 32, mm, .)
+{
+ uint src = OPER_AY_PD_32();
+ uint ea = EA_AX_PD_32();
+ uint dst = m68ki_read_32(ea);
+ uint res = dst - src - XFLAG_AS_1();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res);
+ FLAG_V = VFLAG_SUB_32(src, dst, res);
+
+ res = MASK_OUT_ABOVE_32(res);
+ FLAG_Z |= res;
+
+ m68ki_write_32(ea, res);
+}
+
+
+M68KMAKE_OP(swap, 32, ., .)
+{
+ uint* r_dst = &DY;
+
+ FLAG_Z = MASK_OUT_ABOVE_32(*r_dst<<16);
+ *r_dst = (*r_dst>>16) | FLAG_Z;
+
+ FLAG_Z = *r_dst;
+ FLAG_N = NFLAG_32(*r_dst);
+ FLAG_C = CFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(tas, 8, ., d)
+{
+ uint* r_dst = &DY;
+
+ FLAG_Z = MASK_OUT_ABOVE_8(*r_dst);
+ FLAG_N = NFLAG_8(*r_dst);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ *r_dst |= 0x80;
+}
+
+
+M68KMAKE_OP(tas, 8, ., .)
+{
+ uint ea = M68KMAKE_GET_EA_AY_8;
+ uint dst = m68ki_read_8(ea);
+ uint allow_writeback;
+
+ FLAG_Z = dst;
+ FLAG_N = NFLAG_8(dst);
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+
+ /* The Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS writeback
+ disabled in order to function properly. Some Amiga software may also rely
+ on this, but only when accessing specific addresses so additional functionality
+ will be needed. */
+ allow_writeback = m68ki_tas_callback();
+
+ if (allow_writeback==1) m68ki_write_8(ea, dst | 0x80);
+}
+
+
+M68KMAKE_OP(trap, 0, ., .)
+{
+ /* Trap#n stacks exception frame type 0 */
+ m68ki_exception_trapN(EXCEPTION_TRAP_BASE + (REG_IR & 0xf)); /* HJB 990403 */
+}
+
+
+M68KMAKE_OP(trapt, 0, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(trapt, 16, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(trapt, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(trapf, 0, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(trapf, 16, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ REG_PC += 2;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(trapf, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ REG_PC += 4;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(trapcc, 0, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ if(M68KMAKE_CC)
+ m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(trapcc, 16, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ if(M68KMAKE_CC)
+ {
+ m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */
+ return;
+ }
+ REG_PC += 2;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(trapcc, 32, ., .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ if(M68KMAKE_CC)
+ {
+ m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */
+ return;
+ }
+ REG_PC += 4;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(trapv, 0, ., .)
+{
+ if(COND_VC())
+ {
+ return;
+ }
+ m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */
+}
+
+
+M68KMAKE_OP(tst, 8, ., d)
+{
+ uint res = MASK_OUT_ABOVE_8(DY);
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(tst, 8, ., .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_8;
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(tst, 8, ., pcdi)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = OPER_PCDI_8();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 8, ., pcix)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = OPER_PCIX_8();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 8, ., i)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = OPER_I_8();
+
+ FLAG_N = NFLAG_8(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 16, ., d)
+{
+ uint res = MASK_OUT_ABOVE_16(DY);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(tst, 16, ., a)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = MAKE_INT_16(AY);
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 16, ., .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_16;
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(tst, 16, ., pcdi)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = OPER_PCDI_16();
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 16, ., pcix)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = OPER_PCIX_16();
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 16, ., i)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = OPER_I_16();
+
+ FLAG_N = NFLAG_16(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 32, ., d)
+{
+ uint res = DY;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(tst, 32, ., a)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = AY;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 32, ., .)
+{
+ uint res = M68KMAKE_GET_OPER_AY_32;
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+}
+
+
+M68KMAKE_OP(tst, 32, ., pcdi)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = OPER_PCDI_32();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 32, ., pcix)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = OPER_PCIX_32();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(tst, 32, ., i)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint res = OPER_I_32();
+
+ FLAG_N = NFLAG_32(res);
+ FLAG_Z = res;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(unlk, 32, ., a7)
+{
+ REG_A[7] = m68ki_read_32(REG_A[7]);
+}
+
+
+M68KMAKE_OP(unlk, 32, ., .)
+{
+ uint* r_dst = &AY;
+
+ REG_A[7] = *r_dst;
+ *r_dst = m68ki_pull_32();
+}
+
+
+M68KMAKE_OP(unpk, 16, rr, .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* Note: DX and DY are reversed in Motorola's docs */
+ uint src = DY;
+ uint* r_dst = &DX;
+
+ *r_dst = MASK_OUT_BELOW_16(*r_dst) | (((((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16()) & 0xffff);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(unpk, 16, mm, ax7)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* Note: AX and AY are reversed in Motorola's docs */
+ uint src = OPER_AY_PD_8();
+ uint ea_dst;
+
+ src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16();
+ ea_dst = EA_A7_PD_8();
+ m68ki_write_8(ea_dst, (src >> 8) & 0xff);
+ ea_dst = EA_A7_PD_8();
+ m68ki_write_8(ea_dst, src & 0xff);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(unpk, 16, mm, ay7)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* Note: AX and AY are reversed in Motorola's docs */
+ uint src = OPER_A7_PD_8();
+ uint ea_dst;
+
+ src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16();
+ ea_dst = EA_AX_PD_8();
+ m68ki_write_8(ea_dst, (src >> 8) & 0xff);
+ ea_dst = EA_AX_PD_8();
+ m68ki_write_8(ea_dst, src & 0xff);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(unpk, 16, mm, axy7)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ uint src = OPER_A7_PD_8();
+ uint ea_dst;
+
+ src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16();
+ ea_dst = EA_A7_PD_8();
+ m68ki_write_8(ea_dst, (src >> 8) & 0xff);
+ ea_dst = EA_A7_PD_8();
+ m68ki_write_8(ea_dst, src & 0xff);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+M68KMAKE_OP(unpk, 16, mm, .)
+{
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* Note: AX and AY are reversed in Motorola's docs */
+ uint src = OPER_AY_PD_8();
+ uint ea_dst;
+
+ src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16();
+ ea_dst = EA_AX_PD_8();
+ m68ki_write_8(ea_dst, (src >> 8) & 0xff);
+ ea_dst = EA_AX_PD_8();
+ m68ki_write_8(ea_dst, src & 0xff);
+ return;
+ }
+ m68ki_exception_illegal();
+}
+
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+M68KMAKE_END
diff --git a/src/emu/cpu/m68000/m68kconf.h b/src/emu/cpu/m68000/m68kconf.h
new file mode 100644
index 00000000000..0ad15013557
--- /dev/null
+++ b/src/emu/cpu/m68000/m68kconf.h
@@ -0,0 +1,201 @@
+/* ======================================================================== */
+/* ========================= LICENSING & COPYRIGHT ======================== */
+/* ======================================================================== */
+/*
+ * MUSASHI
+ * Version 3.31
+ *
+ * A portable Motorola M680x0 processor emulation engine.
+ * Copyright 1998-2007 Karl Stenerud. All rights reserved.
+ *
+ * This code may be freely used for non-commercial purposes as long as this
+ * copyright notice remains unaltered in the source code and any binary files
+ * containing this code in compiled form.
+ *
+ * All other lisencing terms must be negotiated with the author
+ * (Karl Stenerud).
+ *
+ * The latest version of this code can be obtained at:
+ * http://kstenerud.cjb.net
+ */
+
+
+
+#ifndef M68KCONF__HEADER
+#define M68KCONF__HEADER
+
+
+/* Configuration switches.
+ * Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
+ * OPT_SPECIFY_HANDLER causes the core to link directly to the function
+ * or macro you specify, rather than using callback functions whose pointer
+ * must be passed in using m68k_set_xxx_callback().
+ */
+#define OPT_OFF 0
+#define OPT_ON 1
+#define OPT_SPECIFY_HANDLER 2
+
+
+/* ======================================================================== */
+/* ============================== MAME STUFF ============================== */
+/* ======================================================================== */
+
+/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME
+ * to OPT_ON and use m68kmame.h to configure the 68k core.
+ */
+#ifndef M68K_COMPILE_FOR_MAME
+#define M68K_COMPILE_FOR_MAME OPT_ON
+#endif /* M68K_COMPILE_FOR_MAME */
+
+
+#if M68K_COMPILE_FOR_MAME == OPT_OFF
+
+
+/* ======================================================================== */
+/* ============================= CONFIGURATION ============================ */
+/* ======================================================================== */
+
+/* Turn ON if you want to use the following M68K variants */
+#define M68K_EMULATE_008 OPT_ON
+#define M68K_EMULATE_010 OPT_ON
+#define M68K_EMULATE_EC020 OPT_ON
+#define M68K_EMULATE_020 OPT_ON
+#define M68K_EMULATE_040 OPT_ON
+
+
+/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
+ * and m68k_read_pcrelative_xx() for PC-relative addressing.
+ * If off, all read requests from the CPU will be redirected to m68k_read_xx()
+ */
+#define M68K_SEPARATE_READS OPT_OFF
+
+/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
+ * predecrement destination EA mode instead of m68k_write_32().
+ * To simulate real 68k behavior, m68k_write_32_pd() must first write the high
+ * word to [address+2], and then write the low word to [address].
+ */
+#define M68K_SIMULATE_PD_WRITES OPT_OFF
+
+/* If ON, CPU will call the interrupt acknowledge callback when it services an
+ * interrupt.
+ * If off, all interrupts will be autovectored and all interrupt requests will
+ * auto-clear when the interrupt is serviced.
+ */
+#define M68K_EMULATE_INT_ACK OPT_OFF
+#define M68K_INT_ACK_CALLBACK(A) your_int_ack_handler_function(A)
+
+
+/* If ON, CPU will call the breakpoint acknowledge callback when it encounters
+ * a breakpoint instruction and it is running a 68010+.
+ */
+#define M68K_EMULATE_BKPT_ACK OPT_OFF
+#define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function()
+
+
+/* If ON, the CPU will monitor the trace flags and take trace exceptions
+ */
+#define M68K_EMULATE_TRACE OPT_OFF
+
+
+/* If ON, CPU will call the output reset callback when it encounters a reset
+ * instruction.
+ */
+#define M68K_EMULATE_RESET OPT_OFF
+#define M68K_RESET_CALLBACK() your_reset_handler_function()
+
+
+/* If ON, CPU will call the callback when it encounters a cmpi.l #v, dn
+ * instruction.
+ */
+#define M68K_CMPILD_HAS_CALLBACK OPT_OFF
+#define M68K_CMPILD_CALLBACK(v,r) your_cmpild_handler_function(v,r)
+
+
+/* If ON, CPU will call the callback when it encounters a rte
+ * instruction.
+ */
+#define M68K_RTE_HAS_CALLBACK OPT_OFF
+#define M68K_RTE_CALLBACK() your_rte_handler_function()
+
+/* If ON, CPU will call the callback when it encounters a tas
+ * instruction.
+ */
+#define M68K_TAS_HAS_CALLBACK OPT_OFF
+#define M68K_TAS_CALLBACK() your_tas_handler_function()
+
+
+/* If ON, CPU will call the set fc callback on every memory access to
+ * differentiate between user/supervisor, program/data access like a real
+ * 68000 would. This should be enabled and the callback should be set if you
+ * want to properly emulate the m68010 or higher. (moves uses function codes
+ * to read/write data from different address spaces)
+ */
+#define M68K_EMULATE_FC OPT_OFF
+#define M68K_SET_FC_CALLBACK(A) your_set_fc_handler_function(A)
+
+
+/* If ON, CPU will call the pc changed callback when it changes the PC by a
+ * large value. This allows host programs to be nicer when it comes to
+ * fetching immediate data and instructions on a banked memory system.
+ */
+#define M68K_MONITOR_PC OPT_OFF
+#define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A)
+
+
+/* If ON, CPU will call the instruction hook callback before every
+ * instruction.
+ */
+#define M68K_INSTRUCTION_HOOK OPT_OFF
+#define M68K_INSTRUCTION_CALLBACK() your_instruction_hook_function()
+
+
+/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
+#define M68K_EMULATE_PREFETCH OPT_OFF
+
+
+/* If ON, the CPU will generate address error exceptions if it tries to
+ * access a word or longword at an odd address.
+ * NOTE: This is only emulated properly for 68000 mode.
+ */
+#define M68K_EMULATE_ADDRESS_ERROR OPT_OFF
+
+
+/* Turn ON to enable logging of illegal instruction calls.
+ * M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
+ * Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
+ */
+#define M68K_LOG_ENABLE OPT_OFF
+#define M68K_LOG_1010_1111 OPT_OFF
+#define M68K_LOG_FILEHANDLE some_file_handle
+
+
+/* ----------------------------- COMPATIBILITY ---------------------------- */
+
+/* The following options set optimizations that violate the current ANSI
+ * standard, but will be compliant under the forthcoming C9X standard.
+ */
+
+
+/* If ON, the enulation core will use 64-bit integers to speed up some
+ * operations.
+*/
+#define M68K_USE_64_BIT OPT_OFF
+
+
+/* Set to your compiler's static inline keyword to enable it, or
+ * set it to blank to disable it.
+ * If you define INLINE in the makefile, it will override this value.
+ * NOTE: not enabling inline functions will SEVERELY slow down emulation.
+ */
+#ifndef INLINE
+#define INLINE static __inline__
+#endif /* INLINE */
+
+#endif /* M68K_COMPILE_FOR_MAME */
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+#endif /* M68KCONF__HEADER */
diff --git a/src/emu/cpu/m68000/m68kcpu.c b/src/emu/cpu/m68000/m68kcpu.c
new file mode 100644
index 00000000000..97b67df5db2
--- /dev/null
+++ b/src/emu/cpu/m68000/m68kcpu.c
@@ -0,0 +1,1025 @@
+/* ======================================================================== */
+/* ========================= LICENSING & COPYRIGHT ======================== */
+/* ======================================================================== */
+
+#if 0
+static const char* copyright_notice =
+"MUSASHI\n"
+"Version 3.31 (2007-07-09)\n"
+"A portable Motorola M680x0 processor emulation engine.\n"
+"Copyright 1998-2007 Karl Stenerud. All rights reserved.\n"
+"\n"
+"This code may be freely used for non-commercial purpooses as long as this\n"
+"copyright notice remains unaltered in the source code and any binary files\n"
+"containing this code in compiled form.\n"
+"\n"
+"All other lisencing terms must be negotiated with the author\n"
+"(Karl Stenerud).\n"
+"\n"
+"The latest version of this code can be obtained at:\n"
+"http://kstenerud.cjb.net\n"
+;
+#endif
+
+
+/* ======================================================================== */
+/* ================================= NOTES ================================ */
+/* ======================================================================== */
+
+
+
+/* ======================================================================== */
+/* ================================ INCLUDES ============================== */
+/* ======================================================================== */
+
+extern void m68040_fpu_op0(void);
+extern void m68040_fpu_op1(void);
+
+#include "m68kops.h"
+#include "m68kcpu.h"
+#include "m68kfpu.c"
+
+/* ======================================================================== */
+/* ================================= DATA ================================= */
+/* ======================================================================== */
+
+int m68ki_initial_cycles;
+int m68ki_remaining_cycles = 0; /* Number of clocks remaining */
+uint m68ki_tracing = 0;
+uint m68ki_address_space;
+
+#ifdef M68K_LOG_ENABLE
+const char* m68ki_cpu_names[] =
+{
+ "Invalid CPU",
+ "M68000",
+ "M68008",
+ "Invalid CPU",
+ "M68010",
+ "Invalid CPU",
+ "Invalid CPU",
+ "Invalid CPU",
+ "M68EC020",
+ "Invalid CPU",
+ "Invalid CPU",
+ "Invalid CPU",
+ "Invalid CPU",
+ "Invalid CPU",
+ "Invalid CPU",
+ "Invalid CPU",
+ "M68020"
+};
+#endif /* M68K_LOG_ENABLE */
+
+/* The CPU core */
+m68ki_cpu_core m68ki_cpu = {0};
+
+#if M68K_EMULATE_ADDRESS_ERROR
+jmp_buf m68ki_aerr_trap;
+#endif /* M68K_EMULATE_ADDRESS_ERROR */
+
+uint m68ki_aerr_address;
+uint m68ki_aerr_write_mode;
+uint m68ki_aerr_fc;
+
+/* Used by shift & rotate instructions */
+uint8 m68ki_shift_8_table[65] =
+{
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff
+};
+uint16 m68ki_shift_16_table[65] =
+{
+ 0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
+ 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff
+};
+uint m68ki_shift_32_table[65] =
+{
+ 0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
+ 0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
+ 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000,
+ 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
+ 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8,
+ 0xfffffffc, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+};
+
+
+/* Number of clock cycles to use for exception processing.
+ * I used 4 for any vectors that are undocumented for processing times.
+ */
+uint8 m68ki_exception_cycle_table[4][256] =
+{
+ { /* 000 */
+ 4, /* 0: Reset - Initial Stack Pointer */
+ 4, /* 1: Reset - Initial Program Counter */
+ 50, /* 2: Bus Error (unemulated) */
+ 50, /* 3: Address Error (unemulated) */
+ 34, /* 4: Illegal Instruction */
+ 38, /* 5: Divide by Zero -- ASG: changed from 42 */
+ 40, /* 6: CHK -- ASG: chanaged from 44 */
+ 34, /* 7: TRAPV */
+ 34, /* 8: Privilege Violation */
+ 34, /* 9: Trace */
+ 4, /* 10: 1010 */
+ 4, /* 11: 1111 */
+ 4, /* 12: RESERVED */
+ 4, /* 13: Coprocessor Protocol Violation (unemulated) */
+ 4, /* 14: Format Error */
+ 44, /* 15: Uninitialized Interrupt */
+ 4, /* 16: RESERVED */
+ 4, /* 17: RESERVED */
+ 4, /* 18: RESERVED */
+ 4, /* 19: RESERVED */
+ 4, /* 20: RESERVED */
+ 4, /* 21: RESERVED */
+ 4, /* 22: RESERVED */
+ 4, /* 23: RESERVED */
+ 44, /* 24: Spurious Interrupt */
+ 44, /* 25: Level 1 Interrupt Autovector */
+ 44, /* 26: Level 2 Interrupt Autovector */
+ 44, /* 27: Level 3 Interrupt Autovector */
+ 44, /* 28: Level 4 Interrupt Autovector */
+ 44, /* 29: Level 5 Interrupt Autovector */
+ 44, /* 30: Level 6 Interrupt Autovector */
+ 44, /* 31: Level 7 Interrupt Autovector */
+ 34, /* 32: TRAP #0 -- ASG: chanaged from 38 */
+ 34, /* 33: TRAP #1 */
+ 34, /* 34: TRAP #2 */
+ 34, /* 35: TRAP #3 */
+ 34, /* 36: TRAP #4 */
+ 34, /* 37: TRAP #5 */
+ 34, /* 38: TRAP #6 */
+ 34, /* 39: TRAP #7 */
+ 34, /* 40: TRAP #8 */
+ 34, /* 41: TRAP #9 */
+ 34, /* 42: TRAP #10 */
+ 34, /* 43: TRAP #11 */
+ 34, /* 44: TRAP #12 */
+ 34, /* 45: TRAP #13 */
+ 34, /* 46: TRAP #14 */
+ 34, /* 47: TRAP #15 */
+ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
+ 4, /* 49: FP Inexact Result (unemulated) */
+ 4, /* 50: FP Divide by Zero (unemulated) */
+ 4, /* 51: FP Underflow (unemulated) */
+ 4, /* 52: FP Operand Error (unemulated) */
+ 4, /* 53: FP Overflow (unemulated) */
+ 4, /* 54: FP Signaling NAN (unemulated) */
+ 4, /* 55: FP Unimplemented Data Type (unemulated) */
+ 4, /* 56: MMU Configuration Error (unemulated) */
+ 4, /* 57: MMU Illegal Operation Error (unemulated) */
+ 4, /* 58: MMU Access Level Violation Error (unemulated) */
+ 4, /* 59: RESERVED */
+ 4, /* 60: RESERVED */
+ 4, /* 61: RESERVED */
+ 4, /* 62: RESERVED */
+ 4, /* 63: RESERVED */
+ /* 64-255: User Defined */
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
+ },
+ { /* 010 */
+ 4, /* 0: Reset - Initial Stack Pointer */
+ 4, /* 1: Reset - Initial Program Counter */
+ 126, /* 2: Bus Error (unemulated) */
+ 126, /* 3: Address Error (unemulated) */
+ 38, /* 4: Illegal Instruction */
+ 44, /* 5: Divide by Zero */
+ 44, /* 6: CHK */
+ 34, /* 7: TRAPV */
+ 38, /* 8: Privilege Violation */
+ 38, /* 9: Trace */
+ 4, /* 10: 1010 */
+ 4, /* 11: 1111 */
+ 4, /* 12: RESERVED */
+ 4, /* 13: Coprocessor Protocol Violation (unemulated) */
+ 4, /* 14: Format Error */
+ 44, /* 15: Uninitialized Interrupt */
+ 4, /* 16: RESERVED */
+ 4, /* 17: RESERVED */
+ 4, /* 18: RESERVED */
+ 4, /* 19: RESERVED */
+ 4, /* 20: RESERVED */
+ 4, /* 21: RESERVED */
+ 4, /* 22: RESERVED */
+ 4, /* 23: RESERVED */
+ 46, /* 24: Spurious Interrupt */
+ 46, /* 25: Level 1 Interrupt Autovector */
+ 46, /* 26: Level 2 Interrupt Autovector */
+ 46, /* 27: Level 3 Interrupt Autovector */
+ 46, /* 28: Level 4 Interrupt Autovector */
+ 46, /* 29: Level 5 Interrupt Autovector */
+ 46, /* 30: Level 6 Interrupt Autovector */
+ 46, /* 31: Level 7 Interrupt Autovector */
+ 38, /* 32: TRAP #0 */
+ 38, /* 33: TRAP #1 */
+ 38, /* 34: TRAP #2 */
+ 38, /* 35: TRAP #3 */
+ 38, /* 36: TRAP #4 */
+ 38, /* 37: TRAP #5 */
+ 38, /* 38: TRAP #6 */
+ 38, /* 39: TRAP #7 */
+ 38, /* 40: TRAP #8 */
+ 38, /* 41: TRAP #9 */
+ 38, /* 42: TRAP #10 */
+ 38, /* 43: TRAP #11 */
+ 38, /* 44: TRAP #12 */
+ 38, /* 45: TRAP #13 */
+ 38, /* 46: TRAP #14 */
+ 38, /* 47: TRAP #15 */
+ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
+ 4, /* 49: FP Inexact Result (unemulated) */
+ 4, /* 50: FP Divide by Zero (unemulated) */
+ 4, /* 51: FP Underflow (unemulated) */
+ 4, /* 52: FP Operand Error (unemulated) */
+ 4, /* 53: FP Overflow (unemulated) */
+ 4, /* 54: FP Signaling NAN (unemulated) */
+ 4, /* 55: FP Unimplemented Data Type (unemulated) */
+ 4, /* 56: MMU Configuration Error (unemulated) */
+ 4, /* 57: MMU Illegal Operation Error (unemulated) */
+ 4, /* 58: MMU Access Level Violation Error (unemulated) */
+ 4, /* 59: RESERVED */
+ 4, /* 60: RESERVED */
+ 4, /* 61: RESERVED */
+ 4, /* 62: RESERVED */
+ 4, /* 63: RESERVED */
+ /* 64-255: User Defined */
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
+ },
+ { /* 020 */
+ 4, /* 0: Reset - Initial Stack Pointer */
+ 4, /* 1: Reset - Initial Program Counter */
+ 50, /* 2: Bus Error (unemulated) */
+ 50, /* 3: Address Error (unemulated) */
+ 20, /* 4: Illegal Instruction */
+ 38, /* 5: Divide by Zero */
+ 40, /* 6: CHK */
+ 20, /* 7: TRAPV */
+ 34, /* 8: Privilege Violation */
+ 25, /* 9: Trace */
+ 20, /* 10: 1010 */
+ 20, /* 11: 1111 */
+ 4, /* 12: RESERVED */
+ 4, /* 13: Coprocessor Protocol Violation (unemulated) */
+ 4, /* 14: Format Error */
+ 30, /* 15: Uninitialized Interrupt */
+ 4, /* 16: RESERVED */
+ 4, /* 17: RESERVED */
+ 4, /* 18: RESERVED */
+ 4, /* 19: RESERVED */
+ 4, /* 20: RESERVED */
+ 4, /* 21: RESERVED */
+ 4, /* 22: RESERVED */
+ 4, /* 23: RESERVED */
+ 30, /* 24: Spurious Interrupt */
+ 30, /* 25: Level 1 Interrupt Autovector */
+ 30, /* 26: Level 2 Interrupt Autovector */
+ 30, /* 27: Level 3 Interrupt Autovector */
+ 30, /* 28: Level 4 Interrupt Autovector */
+ 30, /* 29: Level 5 Interrupt Autovector */
+ 30, /* 30: Level 6 Interrupt Autovector */
+ 30, /* 31: Level 7 Interrupt Autovector */
+ 20, /* 32: TRAP #0 */
+ 20, /* 33: TRAP #1 */
+ 20, /* 34: TRAP #2 */
+ 20, /* 35: TRAP #3 */
+ 20, /* 36: TRAP #4 */
+ 20, /* 37: TRAP #5 */
+ 20, /* 38: TRAP #6 */
+ 20, /* 39: TRAP #7 */
+ 20, /* 40: TRAP #8 */
+ 20, /* 41: TRAP #9 */
+ 20, /* 42: TRAP #10 */
+ 20, /* 43: TRAP #11 */
+ 20, /* 44: TRAP #12 */
+ 20, /* 45: TRAP #13 */
+ 20, /* 46: TRAP #14 */
+ 20, /* 47: TRAP #15 */
+ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
+ 4, /* 49: FP Inexact Result (unemulated) */
+ 4, /* 50: FP Divide by Zero (unemulated) */
+ 4, /* 51: FP Underflow (unemulated) */
+ 4, /* 52: FP Operand Error (unemulated) */
+ 4, /* 53: FP Overflow (unemulated) */
+ 4, /* 54: FP Signaling NAN (unemulated) */
+ 4, /* 55: FP Unimplemented Data Type (unemulated) */
+ 4, /* 56: MMU Configuration Error (unemulated) */
+ 4, /* 57: MMU Illegal Operation Error (unemulated) */
+ 4, /* 58: MMU Access Level Violation Error (unemulated) */
+ 4, /* 59: RESERVED */
+ 4, /* 60: RESERVED */
+ 4, /* 61: RESERVED */
+ 4, /* 62: RESERVED */
+ 4, /* 63: RESERVED */
+ /* 64-255: User Defined */
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
+ },
+ { /* 040 */ // TODO: these values are not correct
+ 4, /* 0: Reset - Initial Stack Pointer */
+ 4, /* 1: Reset - Initial Program Counter */
+ 50, /* 2: Bus Error (unemulated) */
+ 50, /* 3: Address Error (unemulated) */
+ 20, /* 4: Illegal Instruction */
+ 38, /* 5: Divide by Zero */
+ 40, /* 6: CHK */
+ 20, /* 7: TRAPV */
+ 34, /* 8: Privilege Violation */
+ 25, /* 9: Trace */
+ 20, /* 10: 1010 */
+ 20, /* 11: 1111 */
+ 4, /* 12: RESERVED */
+ 4, /* 13: Coprocessor Protocol Violation (unemulated) */
+ 4, /* 14: Format Error */
+ 30, /* 15: Uninitialized Interrupt */
+ 4, /* 16: RESERVED */
+ 4, /* 17: RESERVED */
+ 4, /* 18: RESERVED */
+ 4, /* 19: RESERVED */
+ 4, /* 20: RESERVED */
+ 4, /* 21: RESERVED */
+ 4, /* 22: RESERVED */
+ 4, /* 23: RESERVED */
+ 30, /* 24: Spurious Interrupt */
+ 30, /* 25: Level 1 Interrupt Autovector */
+ 30, /* 26: Level 2 Interrupt Autovector */
+ 30, /* 27: Level 3 Interrupt Autovector */
+ 30, /* 28: Level 4 Interrupt Autovector */
+ 30, /* 29: Level 5 Interrupt Autovector */
+ 30, /* 30: Level 6 Interrupt Autovector */
+ 30, /* 31: Level 7 Interrupt Autovector */
+ 20, /* 32: TRAP #0 */
+ 20, /* 33: TRAP #1 */
+ 20, /* 34: TRAP #2 */
+ 20, /* 35: TRAP #3 */
+ 20, /* 36: TRAP #4 */
+ 20, /* 37: TRAP #5 */
+ 20, /* 38: TRAP #6 */
+ 20, /* 39: TRAP #7 */
+ 20, /* 40: TRAP #8 */
+ 20, /* 41: TRAP #9 */
+ 20, /* 42: TRAP #10 */
+ 20, /* 43: TRAP #11 */
+ 20, /* 44: TRAP #12 */
+ 20, /* 45: TRAP #13 */
+ 20, /* 46: TRAP #14 */
+ 20, /* 47: TRAP #15 */
+ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
+ 4, /* 49: FP Inexact Result (unemulated) */
+ 4, /* 50: FP Divide by Zero (unemulated) */
+ 4, /* 51: FP Underflow (unemulated) */
+ 4, /* 52: FP Operand Error (unemulated) */
+ 4, /* 53: FP Overflow (unemulated) */
+ 4, /* 54: FP Signaling NAN (unemulated) */
+ 4, /* 55: FP Unimplemented Data Type (unemulated) */
+ 4, /* 56: MMU Configuration Error (unemulated) */
+ 4, /* 57: MMU Illegal Operation Error (unemulated) */
+ 4, /* 58: MMU Access Level Violation Error (unemulated) */
+ 4, /* 59: RESERVED */
+ 4, /* 60: RESERVED */
+ 4, /* 61: RESERVED */
+ 4, /* 62: RESERVED */
+ 4, /* 63: RESERVED */
+ /* 64-255: User Defined */
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
+ }
+};
+
+uint8 m68ki_ea_idx_cycle_table[64] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, /* ..01.000 no memory indirect, base NULL */
+ 5, /* ..01..01 memory indirect, base NULL, outer NULL */
+ 7, /* ..01..10 memory indirect, base NULL, outer 16 */
+ 7, /* ..01..11 memory indirect, base NULL, outer 32 */
+ 0, 5, 7, 7, 0, 5, 7, 7, 0, 5, 7, 7,
+ 2, /* ..10.000 no memory indirect, base 16 */
+ 7, /* ..10..01 memory indirect, base 16, outer NULL */
+ 9, /* ..10..10 memory indirect, base 16, outer 16 */
+ 9, /* ..10..11 memory indirect, base 16, outer 32 */
+ 0, 7, 9, 9, 0, 7, 9, 9, 0, 7, 9, 9,
+ 6, /* ..11.000 no memory indirect, base 32 */
+ 11, /* ..11..01 memory indirect, base 32, outer NULL */
+ 13, /* ..11..10 memory indirect, base 32, outer 16 */
+ 13, /* ..11..11 memory indirect, base 32, outer 32 */
+ 0, 11, 13, 13, 0, 11, 13, 13, 0, 11, 13, 13
+};
+
+
+
+/* ======================================================================== */
+/* =============================== CALLBACKS ============================== */
+/* ======================================================================== */
+
+/* Default callbacks used if the callback hasn't been set yet, or if the
+ * callback is set to NULL
+ */
+
+/* Interrupt acknowledge */
+static int default_int_ack_callback_data;
+static int default_int_ack_callback(int int_level)
+{
+ default_int_ack_callback_data = int_level;
+ CPU_INT_LEVEL = 0;
+ return M68K_INT_ACK_AUTOVECTOR;
+}
+
+/* Breakpoint acknowledge */
+static unsigned int default_bkpt_ack_callback_data;
+static void default_bkpt_ack_callback(unsigned int data)
+{
+ default_bkpt_ack_callback_data = data;
+}
+
+/* Called when a reset instruction is executed */
+static void default_reset_instr_callback(void)
+{
+}
+
+/* Called when a cmpi.l #v, dn instruction is executed */
+static void default_cmpild_instr_callback(unsigned int val, int reg)
+{
+}
+
+/* Called when a rte instruction is executed */
+static void default_rte_instr_callback(void)
+{
+}
+
+/* Called when a tas instruction is executed */
+static int default_tas_instr_callback(void)
+{
+ return 1; // allow writeback
+}
+
+/* Called when the program counter changed by a large value */
+static unsigned int default_pc_changed_callback_data;
+static void default_pc_changed_callback(unsigned int new_pc)
+{
+ default_pc_changed_callback_data = new_pc;
+}
+
+/* Called every time there's bus activity (read/write to/from memory */
+static unsigned int default_set_fc_callback_data;
+static void default_set_fc_callback(unsigned int new_fc)
+{
+ default_set_fc_callback_data = new_fc;
+}
+
+/* Called every instruction cycle prior to execution */
+static void default_instr_hook_callback(void)
+{
+}
+
+
+#if M68K_EMULATE_ADDRESS_ERROR
+ #include <setjmp.h>
+ jmp_buf m68ki_aerr_trap;
+#endif /* M68K_EMULATE_ADDRESS_ERROR */
+
+
+/* ======================================================================== */
+/* ================================= API ================================== */
+/* ======================================================================== */
+
+/* Access the internals of the CPU */
+unsigned int m68k_get_reg(void* context, m68k_register_t regnum)
+{
+ m68ki_cpu_core* cpu = context != NULL ?(m68ki_cpu_core*)context : &m68ki_cpu;
+
+ switch(regnum)
+ {
+ case M68K_REG_D0: return cpu->dar[0];
+ case M68K_REG_D1: return cpu->dar[1];
+ case M68K_REG_D2: return cpu->dar[2];
+ case M68K_REG_D3: return cpu->dar[3];
+ case M68K_REG_D4: return cpu->dar[4];
+ case M68K_REG_D5: return cpu->dar[5];
+ case M68K_REG_D6: return cpu->dar[6];
+ case M68K_REG_D7: return cpu->dar[7];
+ case M68K_REG_A0: return cpu->dar[8];
+ case M68K_REG_A1: return cpu->dar[9];
+ case M68K_REG_A2: return cpu->dar[10];
+ case M68K_REG_A3: return cpu->dar[11];
+ case M68K_REG_A4: return cpu->dar[12];
+ case M68K_REG_A5: return cpu->dar[13];
+ case M68K_REG_A6: return cpu->dar[14];
+ case M68K_REG_A7: return cpu->dar[15];
+ case M68K_REG_PC: return MASK_OUT_ABOVE_32(cpu->pc);
+ case M68K_REG_SR: return cpu->t1_flag |
+ cpu->t0_flag |
+ (cpu->s_flag << 11) |
+ (cpu->m_flag << 11) |
+ cpu->int_mask |
+ ((cpu->x_flag & XFLAG_SET) >> 4) |
+ ((cpu->n_flag & NFLAG_SET) >> 4) |
+ ((!cpu->not_z_flag) << 2) |
+ ((cpu->v_flag & VFLAG_SET) >> 6) |
+ ((cpu->c_flag & CFLAG_SET) >> 8);
+ case M68K_REG_SP: return cpu->dar[15];
+ case M68K_REG_USP: return cpu->s_flag ? cpu->sp[0] : cpu->dar[15];
+ case M68K_REG_ISP: return cpu->s_flag && !cpu->m_flag ? cpu->dar[15] : cpu->sp[4];
+ case M68K_REG_MSP: return cpu->s_flag && cpu->m_flag ? cpu->dar[15] : cpu->sp[6];
+ case M68K_REG_SFC: return cpu->sfc;
+ case M68K_REG_DFC: return cpu->dfc;
+ case M68K_REG_VBR: return cpu->vbr;
+ case M68K_REG_CACR: return cpu->cacr;
+ case M68K_REG_CAAR: return cpu->caar;
+ case M68K_REG_PREF_ADDR: return cpu->pref_addr;
+ case M68K_REG_PREF_DATA: return cpu->pref_data;
+ case M68K_REG_PPC: return MASK_OUT_ABOVE_32(cpu->ppc);
+ case M68K_REG_IR: return cpu->ir;
+ case M68K_REG_CPU_TYPE:
+ switch(cpu->cpu_type)
+ {
+ case CPU_TYPE_000: return (unsigned int)M68K_CPU_TYPE_68000;
+ case CPU_TYPE_008: return (unsigned int)M68K_CPU_TYPE_68008;
+ case CPU_TYPE_010: return (unsigned int)M68K_CPU_TYPE_68010;
+ case CPU_TYPE_EC020: return (unsigned int)M68K_CPU_TYPE_68EC020;
+ case CPU_TYPE_020: return (unsigned int)M68K_CPU_TYPE_68020;
+ case CPU_TYPE_040: return (unsigned int)M68K_CPU_TYPE_68040;
+ }
+ return M68K_CPU_TYPE_INVALID;
+ default: return 0;
+ }
+ return 0;
+}
+
+void m68k_set_reg(m68k_register_t regnum, unsigned int value)
+{
+ switch(regnum)
+ {
+ case M68K_REG_D0: REG_D[0] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_D1: REG_D[1] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_D2: REG_D[2] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_D3: REG_D[3] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_D4: REG_D[4] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_D5: REG_D[5] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_D6: REG_D[6] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_D7: REG_D[7] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_A0: REG_A[0] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_A1: REG_A[1] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_A2: REG_A[2] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_A3: REG_A[3] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_A4: REG_A[4] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_A5: REG_A[5] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return;
+ case M68K_REG_SR: m68ki_set_sr(value); return;
+ case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_USP: if(FLAG_S)
+ REG_USP = MASK_OUT_ABOVE_32(value);
+ else
+ REG_SP = MASK_OUT_ABOVE_32(value);
+ return;
+ case M68K_REG_ISP: if(FLAG_S && !FLAG_M)
+ REG_SP = MASK_OUT_ABOVE_32(value);
+ else
+ REG_ISP = MASK_OUT_ABOVE_32(value);
+ return;
+ case M68K_REG_MSP: if(FLAG_S && FLAG_M)
+ REG_SP = MASK_OUT_ABOVE_32(value);
+ else
+ REG_MSP = MASK_OUT_ABOVE_32(value);
+ return;
+ case M68K_REG_VBR: REG_VBR = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_SFC: REG_SFC = value & 7; return;
+ case M68K_REG_DFC: REG_DFC = value & 7; return;
+ case M68K_REG_CACR: REG_CACR = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_CAAR: REG_CAAR = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_PPC: REG_PPC = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return;
+ case M68K_REG_PREF_ADDR: CPU_PREF_ADDR = MASK_OUT_ABOVE_32(value); return;
+ case M68K_REG_CPU_TYPE: m68k_set_cpu_type(value); return;
+ default: return;
+ }
+}
+
+/* Set the callbacks */
+void m68k_set_int_ack_callback(int (*callback)(int int_level))
+{
+ CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback;
+}
+
+void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data))
+{
+ CALLBACK_BKPT_ACK = callback ? callback : default_bkpt_ack_callback;
+}
+
+void m68k_set_reset_instr_callback(void (*callback)(void))
+{
+ CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback;
+}
+
+void m68k_set_cmpild_instr_callback(void (*callback)(unsigned int, int))
+{
+ CALLBACK_CMPILD_INSTR = callback ? callback : default_cmpild_instr_callback;
+}
+
+void m68k_set_rte_instr_callback(void (*callback)(void))
+{
+ CALLBACK_RTE_INSTR = callback ? callback : default_rte_instr_callback;
+}
+
+void m68k_set_tas_instr_callback(int (*callback)(void))
+{
+ CALLBACK_TAS_INSTR = callback ? callback : default_tas_instr_callback;
+}
+
+void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc))
+{
+ CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback;
+}
+
+void m68k_set_fc_callback(void (*callback)(unsigned int new_fc))
+{
+ CALLBACK_SET_FC = callback ? callback : default_set_fc_callback;
+}
+
+void m68k_set_instr_hook_callback(void (*callback)(void))
+{
+ CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback;
+}
+
+#include <stdio.h>
+/* Set the CPU type. */
+void m68k_set_cpu_type(unsigned int cpu_type)
+{
+ switch(cpu_type)
+ {
+ case M68K_CPU_TYPE_68000:
+ CPU_TYPE = CPU_TYPE_000;
+ CPU_ADDRESS_MASK = 0x00ffffff;
+ CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
+ CYC_INSTRUCTION = m68ki_cycles[0];
+ CYC_EXCEPTION = m68ki_exception_cycle_table[0];
+ CYC_BCC_NOTAKE_B = -2;
+ CYC_BCC_NOTAKE_W = 2;
+ CYC_DBCC_F_NOEXP = -2;
+ CYC_DBCC_F_EXP = 2;
+ CYC_SCC_R_TRUE = 2;
+ CYC_MOVEM_W = 2;
+ CYC_MOVEM_L = 3;
+ CYC_SHIFT = 1;
+ CYC_RESET = 132;
+ return;
+ case M68K_CPU_TYPE_68008:
+ CPU_TYPE = CPU_TYPE_008;
+ CPU_ADDRESS_MASK = 0x003fffff;
+ CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
+ CYC_INSTRUCTION = m68ki_cycles[0];
+ CYC_EXCEPTION = m68ki_exception_cycle_table[0];
+ CYC_BCC_NOTAKE_B = -2;
+ CYC_BCC_NOTAKE_W = 2;
+ CYC_DBCC_F_NOEXP = -2;
+ CYC_DBCC_F_EXP = 2;
+ CYC_SCC_R_TRUE = 2;
+ CYC_MOVEM_W = 2;
+ CYC_MOVEM_L = 3;
+ CYC_SHIFT = 1;
+ CYC_RESET = 132;
+ return;
+ case M68K_CPU_TYPE_68010:
+ CPU_TYPE = CPU_TYPE_010;
+ CPU_ADDRESS_MASK = 0x00ffffff;
+ CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
+ CYC_INSTRUCTION = m68ki_cycles[1];
+ CYC_EXCEPTION = m68ki_exception_cycle_table[1];
+ CYC_BCC_NOTAKE_B = -4;
+ CYC_BCC_NOTAKE_W = 0;
+ CYC_DBCC_F_NOEXP = 0;
+ CYC_DBCC_F_EXP = 6;
+ CYC_SCC_R_TRUE = 0;
+ CYC_MOVEM_W = 2;
+ CYC_MOVEM_L = 3;
+ CYC_SHIFT = 1;
+ CYC_RESET = 130;
+ return;
+ case M68K_CPU_TYPE_68EC020:
+ CPU_TYPE = CPU_TYPE_EC020;
+ CPU_ADDRESS_MASK = 0x00ffffff;
+ CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
+ CYC_INSTRUCTION = m68ki_cycles[2];
+ CYC_EXCEPTION = m68ki_exception_cycle_table[2];
+ CYC_BCC_NOTAKE_B = -2;
+ CYC_BCC_NOTAKE_W = 0;
+ CYC_DBCC_F_NOEXP = 0;
+ CYC_DBCC_F_EXP = 4;
+ CYC_SCC_R_TRUE = 0;
+ CYC_MOVEM_W = 2;
+ CYC_MOVEM_L = 2;
+ CYC_SHIFT = 0;
+ CYC_RESET = 518;
+ return;
+ case M68K_CPU_TYPE_68020:
+ CPU_TYPE = CPU_TYPE_020;
+ CPU_ADDRESS_MASK = 0xffffffff;
+ CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
+ CYC_INSTRUCTION = m68ki_cycles[2];
+ CYC_EXCEPTION = m68ki_exception_cycle_table[2];
+ CYC_BCC_NOTAKE_B = -2;
+ CYC_BCC_NOTAKE_W = 0;
+ CYC_DBCC_F_NOEXP = 0;
+ CYC_DBCC_F_EXP = 4;
+ CYC_SCC_R_TRUE = 0;
+ CYC_MOVEM_W = 2;
+ CYC_MOVEM_L = 2;
+ CYC_SHIFT = 0;
+ CYC_RESET = 518;
+ return;
+ case M68K_CPU_TYPE_68040: // TODO: these values are not correct
+ CPU_TYPE = CPU_TYPE_040;
+ CPU_ADDRESS_MASK = 0xffffffff;
+ CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
+ CYC_INSTRUCTION = m68ki_cycles[2];
+ CYC_EXCEPTION = m68ki_exception_cycle_table[2];
+ CYC_BCC_NOTAKE_B = -2;
+ CYC_BCC_NOTAKE_W = 0;
+ CYC_DBCC_F_NOEXP = 0;
+ CYC_DBCC_F_EXP = 4;
+ CYC_SCC_R_TRUE = 0;
+ CYC_MOVEM_W = 2;
+ CYC_MOVEM_L = 2;
+ CYC_SHIFT = 0;
+ CYC_RESET = 518;
+ return;
+ }
+}
+
+/* Execute some instructions until we use up num_cycles clock cycles */
+/* ASG: removed per-instruction interrupt checks */
+int m68k_execute(int num_cycles)
+{
+ /* Make sure we're not stopped */
+ if(!CPU_STOPPED)
+ {
+ /* Set our pool of clock cycles available */
+ SET_CYCLES(num_cycles);
+ m68ki_initial_cycles = num_cycles;
+
+ /* ASG: update cycles */
+ USE_CYCLES(CPU_INT_CYCLES);
+ CPU_INT_CYCLES = 0;
+
+ /* Return point if we had an address error */
+ m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */
+
+ /* Main loop. Keep going until we run out of clock cycles */
+ do
+ {
+ /* Set tracing accodring to T1. (T0 is done inside instruction) */
+ m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */
+
+ /* Set the address space for reads */
+ m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */
+
+ /* Call external hook to peek at CPU */
+ m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */
+
+ /* Record previous program counter */
+ REG_PPC = REG_PC;
+
+ /* Read an instruction and call its handler */
+ REG_IR = m68ki_read_imm_16();
+ m68ki_instruction_jump_table[REG_IR]();
+ USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
+
+ /* Trace m68k_exception, if necessary */
+ m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
+ } while(GET_CYCLES() > 0);
+
+ /* set previous PC to current PC for the next entry into the loop */
+ REG_PPC = REG_PC;
+
+ /* ASG: update cycles */
+ USE_CYCLES(CPU_INT_CYCLES);
+ CPU_INT_CYCLES = 0;
+
+ /* return how many clocks we used */
+ return m68ki_initial_cycles - GET_CYCLES();
+ }
+
+ /* We get here if the CPU is stopped or halted */
+ SET_CYCLES(0);
+ CPU_INT_CYCLES = 0;
+
+ return num_cycles;
+}
+
+
+int m68k_cycles_run(void)
+{
+ return m68ki_initial_cycles - GET_CYCLES();
+}
+
+int m68k_cycles_remaining(void)
+{
+ return GET_CYCLES();
+}
+
+/* Change the timeslice */
+void m68k_modify_timeslice(int cycles)
+{
+ m68ki_initial_cycles += cycles;
+ ADD_CYCLES(cycles);
+}
+
+
+void m68k_end_timeslice(void)
+{
+ m68ki_initial_cycles = GET_CYCLES();
+ SET_CYCLES(0);
+}
+
+
+/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
+/* KS: Modified so that IPL* bits match with mask positions in the SR
+ * and cleaned out remenants of the interrupt controller.
+ */
+void m68k_set_irq(unsigned int int_level)
+{
+ uint old_level = CPU_INT_LEVEL;
+ CPU_INT_LEVEL = int_level << 8;
+
+ /* A transition from < 7 to 7 always interrupts (NMI) */
+ /* Note: Level 7 can also level trigger like a normal IRQ */
+ if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700)
+ m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */
+ else
+ m68ki_check_interrupts(); /* Level triggered (IRQ) */
+}
+
+void m68k_init(void)
+{
+ static uint emulation_initialized = 0;
+
+ /* The first call to this function initializes the opcode handler jump table */
+ if(!emulation_initialized)
+ {
+ m68ki_build_opcode_table();
+ emulation_initialized = 1;
+ }
+
+ m68k_set_int_ack_callback(NULL);
+ m68k_set_bkpt_ack_callback(NULL);
+ m68k_set_reset_instr_callback(NULL);
+ m68k_set_cmpild_instr_callback(NULL);
+ m68k_set_rte_instr_callback(NULL);
+ m68k_set_tas_instr_callback(NULL);
+ m68k_set_pc_changed_callback(NULL);
+ m68k_set_fc_callback(NULL);
+ m68k_set_instr_hook_callback(NULL);
+}
+
+/* Pulse the RESET line on the CPU */
+void m68k_pulse_reset(void)
+{
+ /* Clear all stop levels and eat up all remaining cycles */
+ CPU_STOPPED = 0;
+ SET_CYCLES(0);
+
+ CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
+
+ /* Turn off tracing */
+ FLAG_T1 = FLAG_T0 = 0;
+ m68ki_clear_trace();
+ /* Interrupt mask to level 7 */
+ FLAG_INT_MASK = 0x0700;
+ /* Reset VBR */
+ REG_VBR = 0;
+ /* Go to supervisor mode */
+ m68ki_set_sm_flag(SFLAG_SET | MFLAG_CLEAR);
+
+ /* Invalidate the prefetch queue */
+#if M68K_EMULATE_PREFETCH
+ /* Set to arbitrary number since our first fetch is from 0 */
+ CPU_PREF_ADDR = 0x1000;
+#endif /* M68K_EMULATE_PREFETCH */
+
+ /* Read the initial stack pointer and program counter */
+ m68ki_jump(0);
+ REG_SP = m68ki_read_imm_32();
+ REG_PC = m68ki_read_imm_32();
+ m68ki_jump(REG_PC);
+
+ CPU_RUN_MODE = RUN_MODE_NORMAL;
+}
+
+/* Pulse the HALT line on the CPU */
+void m68k_pulse_halt(void)
+{
+ CPU_STOPPED |= STOP_LEVEL_HALT;
+}
+
+
+/* Get and set the current CPU context */
+/* This is to allow for multiple CPUs */
+unsigned int m68k_context_size()
+{
+ return sizeof(m68ki_cpu_core);
+}
+
+unsigned int m68k_get_context(void* dst)
+{
+ if(dst) *(m68ki_cpu_core*)dst = m68ki_cpu;
+ return sizeof(m68ki_cpu_core);
+}
+
+void m68k_set_context(void* src)
+{
+ if(src) m68ki_cpu = *(m68ki_cpu_core*)src;
+}
+
+
+
+/* ======================================================================== */
+/* ============================== MAME STUFF ============================== */
+/* ======================================================================== */
+
+#if M68K_COMPILE_FOR_MAME == OPT_ON
+
+static struct {
+ UINT16 sr;
+ UINT8 stopped;
+ UINT8 halted;
+} m68k_substate;
+
+static void m68k_prepare_substate(void)
+{
+ m68k_substate.sr = m68ki_get_sr();
+ m68k_substate.stopped = (CPU_STOPPED & STOP_LEVEL_STOP) != 0;
+ m68k_substate.halted = (CPU_STOPPED & STOP_LEVEL_HALT) != 0;
+}
+
+static void m68k_post_load(void)
+{
+ m68ki_set_sr_noint_nosp(m68k_substate.sr);
+ CPU_STOPPED = m68k_substate.stopped ? STOP_LEVEL_STOP : 0
+ | m68k_substate.halted ? STOP_LEVEL_HALT : 0;
+ m68ki_jump(REG_PC);
+}
+
+void m68k_state_register(const char *type, int index)
+{
+ state_save_register_item_array(type, index, REG_D);
+ state_save_register_item_array(type, index, REG_A);
+ state_save_register_item(type, index, REG_PPC);
+ state_save_register_item(type, index, REG_PC);
+ state_save_register_item(type, index, REG_USP);
+ state_save_register_item(type, index, REG_ISP);
+ state_save_register_item(type, index, REG_MSP);
+ state_save_register_item(type, index, REG_VBR);
+ state_save_register_item(type, index, REG_SFC);
+ state_save_register_item(type, index, REG_DFC);
+ state_save_register_item(type, index, REG_CACR);
+ state_save_register_item(type, index, REG_CAAR);
+ state_save_register_item(type, index, m68k_substate.sr);
+ state_save_register_item(type, index, CPU_INT_LEVEL);
+ state_save_register_item(type, index, CPU_INT_CYCLES);
+ state_save_register_item(type, index, m68k_substate.stopped);
+ state_save_register_item(type, index, m68k_substate.halted);
+ state_save_register_item(type, index, CPU_PREF_ADDR);
+ state_save_register_item(type, index, CPU_PREF_DATA);
+ state_save_register_func_presave(m68k_prepare_substate);
+ state_save_register_func_postload(m68k_post_load);
+}
+
+#endif /* M68K_COMPILE_FOR_MAME */
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
diff --git a/src/emu/cpu/m68000/m68kcpu.h b/src/emu/cpu/m68000/m68kcpu.h
new file mode 100644
index 00000000000..fe0a6ebfc5f
--- /dev/null
+++ b/src/emu/cpu/m68000/m68kcpu.h
@@ -0,0 +1,2037 @@
+#include <stdio.h>
+/* ======================================================================== */
+/* ========================= LICENSING & COPYRIGHT ======================== */
+/* ======================================================================== */
+/*
+ * MUSASHI
+ * Version 3.31
+ *
+ * A portable Motorola M680x0 processor emulation engine.
+ * Copyright 1998-2007 Karl Stenerud. All rights reserved.
+ *
+ * This code may be freely used for non-commercial purposes as long as this
+ * copyright notice remains unaltered in the source code and any binary files
+ * containing this code in compiled form.
+ *
+ * All other lisencing terms must be negotiated with the author
+ * (Karl Stenerud).
+ *
+ * The latest version of this code can be obtained at:
+ * http://kstenerud.cjb.net
+ */
+
+
+
+
+#ifndef M68KCPU__HEADER
+#define M68KCPU__HEADER
+
+#include "m68k.h"
+#include <limits.h>
+
+#if M68K_EMULATE_ADDRESS_ERROR
+#include <setjmp.h>
+#endif /* M68K_EMULATE_ADDRESS_ERROR */
+
+/* ======================================================================== */
+/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */
+/* ======================================================================== */
+
+/* Check for > 32bit sizes */
+#if UINT_MAX > 0xffffffff
+ #define M68K_INT_GT_32_BIT 1
+#else
+ #define M68K_INT_GT_32_BIT 0
+#endif
+
+/* Data types used in this emulation core */
+#undef sint8
+#undef sint16
+#undef sint32
+#undef sint64
+#undef uint8
+#undef uint16
+#undef uint32
+#undef uint64
+#undef sint
+#undef uint
+
+#define sint8 signed char /* ASG: changed from char to signed char */
+#define sint16 signed short
+#define sint32 signed int /* AWJ: changed from long to int */
+#define uint8 unsigned char
+#define uint16 unsigned short
+#define uint32 unsigned int /* AWJ: changed from long to int */
+
+/* signed and unsigned int must be at least 32 bits wide */
+#define sint signed int
+#define uint unsigned int
+
+
+#if M68K_USE_64_BIT
+#define sint64 signed long long
+#define uint64 unsigned long long
+#else
+#define sint64 sint32
+#define uint64 uint32
+#endif /* M68K_USE_64_BIT */
+
+
+
+/* Allow for architectures that don't have 8-bit sizes */
+#if UCHAR_MAX == 0xff
+ #define MAKE_INT_8(A) (sint8)(A)
+#else
+ #undef sint8
+ #define sint8 signed int
+ #undef uint8
+ #define uint8 unsigned int
+ INLINE sint MAKE_INT_8(uint value)
+ {
+ return (value & 0x80) ? value | ~0xff : value & 0xff;
+ }
+#endif /* UCHAR_MAX == 0xff */
+
+
+/* Allow for architectures that don't have 16-bit sizes */
+#if USHRT_MAX == 0xffff
+ #define MAKE_INT_16(A) (sint16)(A)
+#else
+ #undef sint16
+ #define sint16 signed int
+ #undef uint16
+ #define uint16 unsigned int
+ INLINE sint MAKE_INT_16(uint value)
+ {
+ return (value & 0x8000) ? value | ~0xffff : value & 0xffff;
+ }
+#endif /* USHRT_MAX == 0xffff */
+
+
+/* Allow for architectures that don't have 32-bit sizes */
+#if UINT_MAX == 0xffffffff
+ #define MAKE_INT_32(A) (sint32)(A)
+#else
+ #undef sint32
+ #define sint32 signed int
+ #undef uint32
+ #define uint32 unsigned int
+ INLINE sint MAKE_INT_32(uint value)
+ {
+ return (value & 0x80000000) ? value | ~0xffffffff : value & 0xffffffff;
+ }
+#endif /* UINT_MAX == 0xffffffff */
+
+
+
+
+/* ======================================================================== */
+/* ============================ GENERAL DEFINES =========================== */
+/* ======================================================================== */
+
+/* Exception Vectors handled by emulation */
+#define EXCEPTION_BUS_ERROR 2 /* This one is not emulated! */
+#define EXCEPTION_ADDRESS_ERROR 3 /* This one is partially emulated (doesn't stack a proper frame yet) */
+#define EXCEPTION_ILLEGAL_INSTRUCTION 4
+#define EXCEPTION_ZERO_DIVIDE 5
+#define EXCEPTION_CHK 6
+#define EXCEPTION_TRAPV 7
+#define EXCEPTION_PRIVILEGE_VIOLATION 8
+#define EXCEPTION_TRACE 9
+#define EXCEPTION_1010 10
+#define EXCEPTION_1111 11
+#define EXCEPTION_FORMAT_ERROR 14
+#define EXCEPTION_UNINITIALIZED_INTERRUPT 15
+#define EXCEPTION_SPURIOUS_INTERRUPT 24
+#define EXCEPTION_INTERRUPT_AUTOVECTOR 24
+#define EXCEPTION_TRAP_BASE 32
+
+/* Function codes set by CPU during data/address bus activity */
+#define FUNCTION_CODE_USER_DATA 1
+#define FUNCTION_CODE_USER_PROGRAM 2
+#define FUNCTION_CODE_SUPERVISOR_DATA 5
+#define FUNCTION_CODE_SUPERVISOR_PROGRAM 6
+#define FUNCTION_CODE_CPU_SPACE 7
+
+/* CPU types for deciding what to emulate */
+#define CPU_TYPE_000 1
+#define CPU_TYPE_008 2
+#define CPU_TYPE_010 4
+#define CPU_TYPE_EC020 8
+#define CPU_TYPE_020 16
+#define CPU_TYPE_040 32
+
+/* Different ways to stop the CPU */
+#define STOP_LEVEL_STOP 1
+#define STOP_LEVEL_HALT 2
+
+/* Used for 68000 address error processing */
+#define INSTRUCTION_YES 0
+#define INSTRUCTION_NO 0x08
+#define MODE_READ 0x10
+#define MODE_WRITE 0
+
+#define RUN_MODE_NORMAL 0
+#define RUN_MODE_BERR_AERR_RESET 1
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+/* ======================================================================== */
+/* ================================ MACROS ================================ */
+/* ======================================================================== */
+
+
+/* ---------------------------- General Macros ---------------------------- */
+
+/* Bit Isolation Macros */
+#define BIT_0(A) ((A) & 0x00000001)
+#define BIT_1(A) ((A) & 0x00000002)
+#define BIT_2(A) ((A) & 0x00000004)
+#define BIT_3(A) ((A) & 0x00000008)
+#define BIT_4(A) ((A) & 0x00000010)
+#define BIT_5(A) ((A) & 0x00000020)
+#define BIT_6(A) ((A) & 0x00000040)
+#define BIT_7(A) ((A) & 0x00000080)
+#define BIT_8(A) ((A) & 0x00000100)
+#define BIT_9(A) ((A) & 0x00000200)
+#define BIT_A(A) ((A) & 0x00000400)
+#define BIT_B(A) ((A) & 0x00000800)
+#define BIT_C(A) ((A) & 0x00001000)
+#define BIT_D(A) ((A) & 0x00002000)
+#define BIT_E(A) ((A) & 0x00004000)
+#define BIT_F(A) ((A) & 0x00008000)
+#define BIT_10(A) ((A) & 0x00010000)
+#define BIT_11(A) ((A) & 0x00020000)
+#define BIT_12(A) ((A) & 0x00040000)
+#define BIT_13(A) ((A) & 0x00080000)
+#define BIT_14(A) ((A) & 0x00100000)
+#define BIT_15(A) ((A) & 0x00200000)
+#define BIT_16(A) ((A) & 0x00400000)
+#define BIT_17(A) ((A) & 0x00800000)
+#define BIT_18(A) ((A) & 0x01000000)
+#define BIT_19(A) ((A) & 0x02000000)
+#define BIT_1A(A) ((A) & 0x04000000)
+#define BIT_1B(A) ((A) & 0x08000000)
+#define BIT_1C(A) ((A) & 0x10000000)
+#define BIT_1D(A) ((A) & 0x20000000)
+#define BIT_1E(A) ((A) & 0x40000000)
+#define BIT_1F(A) ((A) & 0x80000000)
+
+/* Get the most significant bit for specific sizes */
+#define GET_MSB_8(A) ((A) & 0x80)
+#define GET_MSB_9(A) ((A) & 0x100)
+#define GET_MSB_16(A) ((A) & 0x8000)
+#define GET_MSB_17(A) ((A) & 0x10000)
+#define GET_MSB_32(A) ((A) & 0x80000000)
+#if M68K_USE_64_BIT
+#define GET_MSB_33(A) ((A) & 0x100000000)
+#endif /* M68K_USE_64_BIT */
+
+/* Isolate nibbles */
+#define LOW_NIBBLE(A) ((A) & 0x0f)
+#define HIGH_NIBBLE(A) ((A) & 0xf0)
+
+/* These are used to isolate 8, 16, and 32 bit sizes */
+#define MASK_OUT_ABOVE_2(A) ((A) & 3)
+#define MASK_OUT_ABOVE_8(A) ((A) & 0xff)
+#define MASK_OUT_ABOVE_16(A) ((A) & 0xffff)
+#define MASK_OUT_BELOW_2(A) ((A) & ~3)
+#define MASK_OUT_BELOW_8(A) ((A) & ~0xff)
+#define MASK_OUT_BELOW_16(A) ((A) & ~0xffff)
+
+/* No need to mask if we are 32 bit */
+#if M68K_INT_GT_32_BIT || M68K_USE_64_BIT
+ #define MASK_OUT_ABOVE_32(A) ((A) & 0xffffffff)
+ #define MASK_OUT_BELOW_32(A) ((A) & ~0xffffffff)
+#else
+ #define MASK_OUT_ABOVE_32(A) (A)
+ #define MASK_OUT_BELOW_32(A) 0
+#endif /* M68K_INT_GT_32_BIT || M68K_USE_64_BIT */
+
+/* Simulate address lines of 68k family */
+#define ADDRESS_68K(A) ((A)&CPU_ADDRESS_MASK)
+
+
+/* Shift & Rotate Macros. */
+#define LSL(A, C) ((A) << (C))
+#define LSR(A, C) ((A) >> (C))
+
+/* Some > 32-bit optimizations */
+#if M68K_INT_GT_32_BIT
+ /* Shift left and right */
+ #define LSR_32(A, C) ((A) >> (C))
+ #define LSL_32(A, C) ((A) << (C))
+#else
+ /* We have to do this because the morons at ANSI decided that shifts
+ * by >= data size are undefined.
+ */
+ #define LSR_32(A, C) ((C) < 32 ? (A) >> (C) : 0)
+ #define LSL_32(A, C) ((C) < 32 ? (A) << (C) : 0)
+#endif /* M68K_INT_GT_32_BIT */
+
+#if M68K_USE_64_BIT
+ #define LSL_32_64(A, C) ((A) << (C))
+ #define LSR_32_64(A, C) ((A) >> (C))
+ #define ROL_33_64(A, C) (LSL_32_64(A, C) | LSR_32_64(A, 33-(C)))
+ #define ROR_33_64(A, C) (LSR_32_64(A, C) | LSL_32_64(A, 33-(C)))
+#endif /* M68K_USE_64_BIT */
+
+#define ROL_8(A, C) MASK_OUT_ABOVE_8(LSL(A, C) | LSR(A, 8-(C)))
+#define ROL_9(A, C) (LSL(A, C) | LSR(A, 9-(C)))
+#define ROL_16(A, C) MASK_OUT_ABOVE_16(LSL(A, C) | LSR(A, 16-(C)))
+#define ROL_17(A, C) (LSL(A, C) | LSR(A, 17-(C)))
+#define ROL_32(A, C) MASK_OUT_ABOVE_32(LSL_32(A, C) | LSR_32(A, 32-(C)))
+#define ROL_33(A, C) (LSL_32(A, C) | LSR_32(A, 33-(C)))
+
+#define ROR_8(A, C) MASK_OUT_ABOVE_8(LSR(A, C) | LSL(A, 8-(C)))
+#define ROR_9(A, C) (LSR(A, C) | LSL(A, 9-(C)))
+#define ROR_16(A, C) MASK_OUT_ABOVE_16(LSR(A, C) | LSL(A, 16-(C)))
+#define ROR_17(A, C) (LSR(A, C) | LSL(A, 17-(C)))
+#define ROR_32(A, C) MASK_OUT_ABOVE_32(LSR_32(A, C) | LSL_32(A, 32-(C)))
+#define ROR_33(A, C) (LSR_32(A, C) | LSL_32(A, 33-(C)))
+
+
+
+/* ------------------------------ CPU Access ------------------------------ */
+
+/* Access the CPU registers */
+#define CPU_TYPE m68ki_cpu.cpu_type
+
+#define REG_DA m68ki_cpu.dar /* easy access to data and address regs */
+#define REG_D m68ki_cpu.dar
+#define REG_A (m68ki_cpu.dar+8)
+#define REG_PPC m68ki_cpu.ppc
+#define REG_PC m68ki_cpu.pc
+#define REG_SP_BASE m68ki_cpu.sp
+#define REG_USP m68ki_cpu.sp[0]
+#define REG_ISP m68ki_cpu.sp[4]
+#define REG_MSP m68ki_cpu.sp[6]
+#define REG_SP m68ki_cpu.dar[15]
+#define REG_VBR m68ki_cpu.vbr
+#define REG_SFC m68ki_cpu.sfc
+#define REG_DFC m68ki_cpu.dfc
+#define REG_CACR m68ki_cpu.cacr
+#define REG_CAAR m68ki_cpu.caar
+#define REG_IR m68ki_cpu.ir
+
+#define REG_FP m68ki_cpu.fpr
+#define REG_FPCR m68ki_cpu.fpcr
+#define REG_FPSR m68ki_cpu.fpsr
+#define REG_FPIAR m68ki_cpu.fpiar
+
+#define FLAG_T1 m68ki_cpu.t1_flag
+#define FLAG_T0 m68ki_cpu.t0_flag
+#define FLAG_S m68ki_cpu.s_flag
+#define FLAG_M m68ki_cpu.m_flag
+#define FLAG_X m68ki_cpu.x_flag
+#define FLAG_N m68ki_cpu.n_flag
+#define FLAG_Z m68ki_cpu.not_z_flag
+#define FLAG_V m68ki_cpu.v_flag
+#define FLAG_C m68ki_cpu.c_flag
+#define FLAG_INT_MASK m68ki_cpu.int_mask
+
+#define CPU_INT_LEVEL m68ki_cpu.int_level /* ASG: changed from CPU_INTS_PENDING */
+#define CPU_INT_CYCLES m68ki_cpu.int_cycles /* ASG */
+#define CPU_STOPPED m68ki_cpu.stopped
+#define CPU_PREF_ADDR m68ki_cpu.pref_addr
+#define CPU_PREF_DATA m68ki_cpu.pref_data
+#define CPU_ADDRESS_MASK m68ki_cpu.address_mask
+#define CPU_SR_MASK m68ki_cpu.sr_mask
+#define CPU_INSTR_MODE m68ki_cpu.instr_mode
+#define CPU_RUN_MODE m68ki_cpu.run_mode
+
+#define CYC_INSTRUCTION m68ki_cpu.cyc_instruction
+#define CYC_EXCEPTION m68ki_cpu.cyc_exception
+#define CYC_BCC_NOTAKE_B m68ki_cpu.cyc_bcc_notake_b
+#define CYC_BCC_NOTAKE_W m68ki_cpu.cyc_bcc_notake_w
+#define CYC_DBCC_F_NOEXP m68ki_cpu.cyc_dbcc_f_noexp
+#define CYC_DBCC_F_EXP m68ki_cpu.cyc_dbcc_f_exp
+#define CYC_SCC_R_TRUE m68ki_cpu.cyc_scc_r_true
+#define CYC_MOVEM_W m68ki_cpu.cyc_movem_w
+#define CYC_MOVEM_L m68ki_cpu.cyc_movem_l
+#define CYC_SHIFT m68ki_cpu.cyc_shift
+#define CYC_RESET m68ki_cpu.cyc_reset
+
+
+#define CALLBACK_INT_ACK m68ki_cpu.int_ack_callback
+#define CALLBACK_BKPT_ACK m68ki_cpu.bkpt_ack_callback
+#define CALLBACK_RESET_INSTR m68ki_cpu.reset_instr_callback
+#define CALLBACK_CMPILD_INSTR m68ki_cpu.cmpild_instr_callback
+#define CALLBACK_RTE_INSTR m68ki_cpu.rte_instr_callback
+#define CALLBACK_TAS_INSTR m68ki_cpu.tas_instr_callback
+#define CALLBACK_PC_CHANGED m68ki_cpu.pc_changed_callback
+#define CALLBACK_SET_FC m68ki_cpu.set_fc_callback
+#define CALLBACK_INSTR_HOOK m68ki_cpu.instr_hook_callback
+
+
+
+/* ----------------------------- Configuration ---------------------------- */
+
+/* These defines are dependant on the configuration defines in m68kconf.h */
+
+/* Disable certain comparisons if we're not using all CPU types */
+#if M68K_EMULATE_040
+ #define CPU_TYPE_IS_040_PLUS(A) ((A) & CPU_TYPE_040)
+ #define CPU_TYPE_IS_040_LESS(A) 1
+#else
+ #define CPU_TYPE_IS_040_PLUS(A) 0
+ #define CPU_TYPE_IS_040_LESS(A) 1
+#endif
+
+#if M68K_EMULATE_020
+ #define CPU_TYPE_IS_020_PLUS(A) ((A) & (CPU_TYPE_020 | CPU_TYPE_040))
+ #define CPU_TYPE_IS_020_LESS(A) 1
+#else
+ #define CPU_TYPE_IS_020_PLUS(A) 0
+ #define CPU_TYPE_IS_020_LESS(A) 1
+#endif
+
+#if M68K_EMULATE_EC020
+ #define CPU_TYPE_IS_EC020_PLUS(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_040))
+ #define CPU_TYPE_IS_EC020_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_008 | CPU_TYPE_010 | CPU_TYPE_EC020))
+#else
+ #define CPU_TYPE_IS_EC020_PLUS(A) CPU_TYPE_IS_020_PLUS(A)
+ #define CPU_TYPE_IS_EC020_LESS(A) CPU_TYPE_IS_020_LESS(A)
+#endif
+
+#if M68K_EMULATE_010
+ #define CPU_TYPE_IS_010(A) ((A) == CPU_TYPE_010)
+ #define CPU_TYPE_IS_010_PLUS(A) ((A) & (CPU_TYPE_010 | CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_040))
+ #define CPU_TYPE_IS_010_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_008 | CPU_TYPE_010))
+#else
+ #define CPU_TYPE_IS_010(A) 0
+ #define CPU_TYPE_IS_010_PLUS(A) CPU_TYPE_IS_EC020_PLUS(A)
+ #define CPU_TYPE_IS_010_LESS(A) CPU_TYPE_IS_EC020_LESS(A)
+#endif
+
+#if M68K_EMULATE_020 || M68K_EMULATE_EC020
+ #define CPU_TYPE_IS_020_VARIANT(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020))
+#else
+ #define CPU_TYPE_IS_020_VARIANT(A) 0
+#endif
+
+#if M68K_EMULATE_040 || M68K_EMULATE_020 || M68K_EMULATE_EC020 || M68K_EMULATE_010
+ #define CPU_TYPE_IS_000(A) ((A) == CPU_TYPE_000 || (A) == CPU_TYPE_008)
+#else
+ #define CPU_TYPE_IS_000(A) 1
+#endif
+
+
+#if !M68K_SEPARATE_READS
+#define m68k_read_immediate_16(A) m68ki_read_program_16(A)
+#define m68k_read_immediate_32(A) m68ki_read_program_32(A)
+
+#define m68k_read_pcrelative_8(A) m68ki_read_program_8(A)
+#define m68k_read_pcrelative_16(A) m68ki_read_program_16(A)
+#define m68k_read_pcrelative_32(A) m68ki_read_program_32(A)
+#endif /* M68K_SEPARATE_READS */
+
+
+/* Enable or disable callback functions */
+#if M68K_EMULATE_INT_ACK
+ #if M68K_EMULATE_INT_ACK == OPT_SPECIFY_HANDLER
+ #define m68ki_int_ack(A) M68K_INT_ACK_CALLBACK(A)
+ #else
+ #define m68ki_int_ack(A) CALLBACK_INT_ACK(A)
+ #endif
+#else
+ /* Default action is to used autovector mode, which is most common */
+ #define m68ki_int_ack(A) M68K_INT_ACK_AUTOVECTOR
+#endif /* M68K_EMULATE_INT_ACK */
+
+#if M68K_EMULATE_BKPT_ACK
+ #if M68K_EMULATE_BKPT_ACK == OPT_SPECIFY_HANDLER
+ #define m68ki_bkpt_ack(A) M68K_BKPT_ACK_CALLBACK(A)
+ #else
+ #define m68ki_bkpt_ack(A) CALLBACK_BKPT_ACK(A)
+ #endif
+#else
+ #define m68ki_bkpt_ack(A)
+#endif /* M68K_EMULATE_BKPT_ACK */
+
+#if M68K_EMULATE_RESET
+ #if M68K_EMULATE_RESET == OPT_SPECIFY_HANDLER
+ #define m68ki_output_reset() M68K_RESET_CALLBACK()
+ #else
+ #define m68ki_output_reset() CALLBACK_RESET_INSTR()
+ #endif
+#else
+ #define m68ki_output_reset()
+#endif /* M68K_EMULATE_RESET */
+
+#if M68K_CMPILD_HAS_CALLBACK
+ #if M68K_CMPILD_HAS_CALLBACK == OPT_SPECIFY_HANDLER
+ #define m68ki_cmpild_callback(v,r) M68K_CMPILD_CALLBACK(v,r)
+ #else
+ #define m68ki_cmpild_callback(v,r) CALLBACK_CMPILD_INSTR(v,r)
+ #endif
+#else
+ #define m68ki_cmpild_callback(v,r)
+#endif /* M68K_CMPILD_HAS_CALLBACK */
+
+#if M68K_RTE_HAS_CALLBACK
+ #if M68K_RTE_HAS_CALLBACK == OPT_SPECIFY_HANDLER
+ #define m68ki_rte_callback() M68K_RTE_CALLBACK()
+ #else
+ #define m68ki_rte_callback() CALLBACK_RTE_INSTR()
+ #endif
+#else
+ #define m68ki_rte_callback()
+#endif /* M68K_RTE_HAS_CALLBACK */
+
+#if M68K_TAS_HAS_CALLBACK
+ #if M68K_TAS_HAS_CALLBACK == OPT_SPECIFY_HANDLER
+ #define m68ki_tas_callback() M68K_TAS_CALLBACK()
+ #else
+ #define m68ki_tas_callback() CALLBACK_TAS_INSTR()
+ #endif
+#else
+ #define m68ki_tas_callback()
+#endif /* M68K_TAS_HAS_CALLBACK */
+
+
+#if M68K_INSTRUCTION_HOOK
+ #if M68K_INSTRUCTION_HOOK == OPT_SPECIFY_HANDLER
+ #define m68ki_instr_hook() M68K_INSTRUCTION_CALLBACK()
+ #else
+ #define m68ki_instr_hook() CALLBACK_INSTR_HOOK()
+ #endif
+#else
+ #define m68ki_instr_hook()
+#endif /* M68K_INSTRUCTION_HOOK */
+
+#if M68K_MONITOR_PC
+ #if M68K_MONITOR_PC == OPT_SPECIFY_HANDLER
+ #define m68ki_pc_changed(A) M68K_SET_PC_CALLBACK(ADDRESS_68K(A))
+ #else
+ #define m68ki_pc_changed(A) CALLBACK_PC_CHANGED(ADDRESS_68K(A))
+ #endif
+#else
+ #define m68ki_pc_changed(A)
+#endif /* M68K_MONITOR_PC */
+
+
+/* Enable or disable function code emulation */
+#if M68K_EMULATE_FC
+ #if M68K_EMULATE_FC == OPT_SPECIFY_HANDLER
+ #define m68ki_set_fc(A) M68K_SET_FC_CALLBACK(A)
+ #else
+ #define m68ki_set_fc(A) CALLBACK_SET_FC(A)
+ #endif
+ #define m68ki_use_data_space() m68ki_address_space = FUNCTION_CODE_USER_DATA
+ #define m68ki_use_program_space() m68ki_address_space = FUNCTION_CODE_USER_PROGRAM
+ #define m68ki_get_address_space() m68ki_address_space
+#else
+ #define m68ki_set_fc(A)
+ #define m68ki_use_data_space()
+ #define m68ki_use_program_space()
+ #define m68ki_get_address_space() FUNCTION_CODE_USER_DATA
+#endif /* M68K_EMULATE_FC */
+
+
+/* Enable or disable trace emulation */
+#if M68K_EMULATE_TRACE
+ /* Initiates trace checking before each instruction (t1) */
+ #define m68ki_trace_t1() m68ki_tracing = FLAG_T1
+ /* adds t0 to trace checking if we encounter change of flow */
+ #define m68ki_trace_t0() m68ki_tracing |= FLAG_T0
+ /* Clear all tracing */
+ #define m68ki_clear_trace() m68ki_tracing = 0
+ /* Cause a trace exception if we are tracing */
+ #define m68ki_exception_if_trace() if(m68ki_tracing) m68ki_exception_trace()
+#else
+ #define m68ki_trace_t1()
+ #define m68ki_trace_t0()
+ #define m68ki_clear_trace()
+ #define m68ki_exception_if_trace()
+#endif /* M68K_EMULATE_TRACE */
+
+
+
+/* Address error */
+#if M68K_EMULATE_ADDRESS_ERROR
+ #include <setjmp.h>
+ extern jmp_buf m68ki_aerr_trap;
+
+ #define m68ki_set_address_error_trap() \
+ if(setjmp(m68ki_aerr_trap) != 0) \
+ { \
+ m68ki_exception_address_error(); \
+ if(CPU_STOPPED) \
+ { \
+ SET_CYCLES(0); \
+ CPU_INT_CYCLES = 0; \
+ return m68ki_initial_cycles; \
+ } \
+ }
+
+ #define m68ki_check_address_error(ADDR, WRITE_MODE, FC) \
+ if((ADDR)&1) \
+ { \
+ m68ki_aerr_address = ADDR; \
+ m68ki_aerr_write_mode = WRITE_MODE; \
+ m68ki_aerr_fc = FC; \
+ longjmp(m68ki_aerr_trap, 1); \
+ }
+
+ #define m68ki_check_address_error_010_less(ADDR, WRITE_MODE, FC) \
+ if (CPU_TYPE_IS_010_LESS(CPU_TYPE)) \
+ { \
+ m68ki_check_address_error(ADDR, WRITE_MODE, FC) \
+ }
+#else
+ #define m68ki_set_address_error_trap()
+ #define m68ki_check_address_error(ADDR, WRITE_MODE, FC)
+ #define m68ki_check_address_error_010_less(ADDR, WRITE_MODE, FC)
+#endif /* M68K_ADDRESS_ERROR */
+
+/* Logging */
+#if M68K_LOG_ENABLE
+ #include <stdio.h>
+ extern FILE* M68K_LOG_FILEHANDLE
+ extern char* m68ki_cpu_names[];
+
+ #define M68K_DO_LOG(A) if(M68K_LOG_FILEHANDLE) fprintf A
+ #if M68K_LOG_1010_1111
+ #define M68K_DO_LOG_EMU(A) if(M68K_LOG_FILEHANDLE) fprintf A
+ #else
+ #define M68K_DO_LOG_EMU(A)
+ #endif
+#else
+ #define M68K_DO_LOG(A)
+ #define M68K_DO_LOG_EMU(A)
+#endif
+
+
+
+/* -------------------------- EA / Operand Access ------------------------- */
+
+/*
+ * The general instruction format follows this pattern:
+ * .... XXX. .... .YYY
+ * where XXX is register X and YYY is register Y
+ */
+/* Data Register Isolation */
+#define DX (REG_D[(REG_IR >> 9) & 7])
+#define DY (REG_D[REG_IR & 7])
+/* Address Register Isolation */
+#define AX (REG_A[(REG_IR >> 9) & 7])
+#define AY (REG_A[REG_IR & 7])
+
+
+/* Effective Address Calculations */
+#define EA_AY_AI_8() AY /* address register indirect */
+#define EA_AY_AI_16() EA_AY_AI_8()
+#define EA_AY_AI_32() EA_AY_AI_8()
+#define EA_AY_PI_8() (AY++) /* postincrement (size = byte) */
+#define EA_AY_PI_16() ((AY+=2)-2) /* postincrement (size = word) */
+#define EA_AY_PI_32() ((AY+=4)-4) /* postincrement (size = long) */
+#define EA_AY_PD_8() (--AY) /* predecrement (size = byte) */
+#define EA_AY_PD_16() (AY-=2) /* predecrement (size = word) */
+#define EA_AY_PD_32() (AY-=4) /* predecrement (size = long) */
+#define EA_AY_DI_8() (AY+MAKE_INT_16(m68ki_read_imm_16())) /* displacement */
+#define EA_AY_DI_16() EA_AY_DI_8()
+#define EA_AY_DI_32() EA_AY_DI_8()
+#define EA_AY_IX_8() m68ki_get_ea_ix(AY) /* indirect + index */
+#define EA_AY_IX_16() EA_AY_IX_8()
+#define EA_AY_IX_32() EA_AY_IX_8()
+
+#define EA_AX_AI_8() AX
+#define EA_AX_AI_16() EA_AX_AI_8()
+#define EA_AX_AI_32() EA_AX_AI_8()
+#define EA_AX_PI_8() (AX++)
+#define EA_AX_PI_16() ((AX+=2)-2)
+#define EA_AX_PI_32() ((AX+=4)-4)
+#define EA_AX_PD_8() (--AX)
+#define EA_AX_PD_16() (AX-=2)
+#define EA_AX_PD_32() (AX-=4)
+#define EA_AX_DI_8() (AX+MAKE_INT_16(m68ki_read_imm_16()))
+#define EA_AX_DI_16() EA_AX_DI_8()
+#define EA_AX_DI_32() EA_AX_DI_8()
+#define EA_AX_IX_8() m68ki_get_ea_ix(AX)
+#define EA_AX_IX_16() EA_AX_IX_8()
+#define EA_AX_IX_32() EA_AX_IX_8()
+
+#define EA_A7_PI_8() ((REG_A[7]+=2)-2)
+#define EA_A7_PD_8() (REG_A[7]-=2)
+
+#define EA_AW_8() MAKE_INT_16(m68ki_read_imm_16()) /* absolute word */
+#define EA_AW_16() EA_AW_8()
+#define EA_AW_32() EA_AW_8()
+#define EA_AL_8() m68ki_read_imm_32() /* absolute long */
+#define EA_AL_16() EA_AL_8()
+#define EA_AL_32() EA_AL_8()
+#define EA_PCDI_8() m68ki_get_ea_pcdi() /* pc indirect + displacement */
+#define EA_PCDI_16() EA_PCDI_8()
+#define EA_PCDI_32() EA_PCDI_8()
+#define EA_PCIX_8() m68ki_get_ea_pcix() /* pc indirect + index */
+#define EA_PCIX_16() EA_PCIX_8()
+#define EA_PCIX_32() EA_PCIX_8()
+
+
+#define OPER_I_8() m68ki_read_imm_8()
+#define OPER_I_16() m68ki_read_imm_16()
+#define OPER_I_32() m68ki_read_imm_32()
+
+
+
+/* --------------------------- Status Register ---------------------------- */
+
+/* Flag Calculation Macros */
+#define CFLAG_8(A) (A)
+#define CFLAG_16(A) ((A)>>8)
+
+#if M68K_INT_GT_32_BIT
+ #define CFLAG_ADD_32(S, D, R) ((R)>>24)
+ #define CFLAG_SUB_32(S, D, R) ((R)>>24)
+#else
+ #define CFLAG_ADD_32(S, D, R) (((S & D) | (~R & (S | D)))>>23)
+ #define CFLAG_SUB_32(S, D, R) (((S & R) | (~D & (S | R)))>>23)
+#endif /* M68K_INT_GT_32_BIT */
+
+#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R))
+#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8)
+#define VFLAG_ADD_32(S, D, R) (((S^R) & (D^R))>>24)
+
+#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D))
+#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8)
+#define VFLAG_SUB_32(S, D, R) (((S^D) & (R^D))>>24)
+
+#define NFLAG_8(A) (A)
+#define NFLAG_16(A) ((A)>>8)
+#define NFLAG_32(A) ((A)>>24)
+#define NFLAG_64(A) ((A)>>56)
+
+#define ZFLAG_8(A) MASK_OUT_ABOVE_8(A)
+#define ZFLAG_16(A) MASK_OUT_ABOVE_16(A)
+#define ZFLAG_32(A) MASK_OUT_ABOVE_32(A)
+
+
+/* Flag values */
+#define NFLAG_SET 0x80
+#define NFLAG_CLEAR 0
+#define CFLAG_SET 0x100
+#define CFLAG_CLEAR 0
+#define XFLAG_SET 0x100
+#define XFLAG_CLEAR 0
+#define VFLAG_SET 0x80
+#define VFLAG_CLEAR 0
+#define ZFLAG_SET 0
+#define ZFLAG_CLEAR 0xffffffff
+
+#define SFLAG_SET 4
+#define SFLAG_CLEAR 0
+#define MFLAG_SET 2
+#define MFLAG_CLEAR 0
+
+/* Turn flag values into 1 or 0 */
+#define XFLAG_AS_1() ((FLAG_X>>8)&1)
+#define NFLAG_AS_1() ((FLAG_N>>7)&1)
+#define VFLAG_AS_1() ((FLAG_V>>7)&1)
+#define ZFLAG_AS_1() (!FLAG_Z)
+#define CFLAG_AS_1() ((FLAG_C>>8)&1)
+
+
+/* Conditions */
+#define COND_CS() (FLAG_C&0x100)
+#define COND_CC() (!COND_CS())
+#define COND_VS() (FLAG_V&0x80)
+#define COND_VC() (!COND_VS())
+#define COND_NE() FLAG_Z
+#define COND_EQ() (!COND_NE())
+#define COND_MI() (FLAG_N&0x80)
+#define COND_PL() (!COND_MI())
+#define COND_LT() ((FLAG_N^FLAG_V)&0x80)
+#define COND_GE() (!COND_LT())
+#define COND_HI() (COND_CC() && COND_NE())
+#define COND_LS() (COND_CS() || COND_EQ())
+#define COND_GT() (COND_GE() && COND_NE())
+#define COND_LE() (COND_LT() || COND_EQ())
+
+/* Reversed conditions */
+#define COND_NOT_CS() COND_CC()
+#define COND_NOT_CC() COND_CS()
+#define COND_NOT_VS() COND_VC()
+#define COND_NOT_VC() COND_VS()
+#define COND_NOT_NE() COND_EQ()
+#define COND_NOT_EQ() COND_NE()
+#define COND_NOT_MI() COND_PL()
+#define COND_NOT_PL() COND_MI()
+#define COND_NOT_LT() COND_GE()
+#define COND_NOT_GE() COND_LT()
+#define COND_NOT_HI() COND_LS()
+#define COND_NOT_LS() COND_HI()
+#define COND_NOT_GT() COND_LE()
+#define COND_NOT_LE() COND_GT()
+
+/* Not real conditions, but here for convenience */
+#define COND_XS() (FLAG_X&0x100)
+#define COND_XC() (!COND_XS)
+
+
+/* Get the condition code register */
+#define m68ki_get_ccr() ((COND_XS() >> 4) | \
+ (COND_MI() >> 4) | \
+ (COND_EQ() << 2) | \
+ (COND_VS() >> 6) | \
+ (COND_CS() >> 8))
+
+/* Get the status register */
+#define m68ki_get_sr() ( FLAG_T1 | \
+ FLAG_T0 | \
+ (FLAG_S << 11) | \
+ (FLAG_M << 11) | \
+ FLAG_INT_MASK | \
+ m68ki_get_ccr())
+
+
+
+/* ---------------------------- Cycle Counting ---------------------------- */
+
+#define ADD_CYCLES(A) m68ki_remaining_cycles += (A)
+#define USE_CYCLES(A) m68ki_remaining_cycles -= (A)
+#define SET_CYCLES(A) m68ki_remaining_cycles = A
+#define GET_CYCLES() m68ki_remaining_cycles
+#define USE_ALL_CYCLES() m68ki_remaining_cycles = 0
+
+
+
+/* ----------------------------- Read / Write ----------------------------- */
+
+/* Read from the current address space */
+#define m68ki_read_8(A) m68ki_read_8_fc (A, FLAG_S | m68ki_get_address_space())
+#define m68ki_read_16(A) m68ki_read_16_fc(A, FLAG_S | m68ki_get_address_space())
+#define m68ki_read_32(A) m68ki_read_32_fc(A, FLAG_S | m68ki_get_address_space())
+
+/* Write to the current data space */
+#define m68ki_write_8(A, V) m68ki_write_8_fc (A, FLAG_S | FUNCTION_CODE_USER_DATA, V)
+#define m68ki_write_16(A, V) m68ki_write_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V)
+#define m68ki_write_32(A, V) m68ki_write_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V)
+
+#if M68K_SIMULATE_PD_WRITES
+#define m68ki_write_32_pd(A, V) m68ki_write_32_pd_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V)
+#else
+#define m68ki_write_32_pd(A, V) m68ki_write_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V)
+#endif
+
+/* map read immediate 8 to read immediate 16 */
+#define m68ki_read_imm_8() MASK_OUT_ABOVE_8(m68ki_read_imm_16())
+
+/* Map PC-relative reads */
+#define m68ki_read_pcrel_8(A) m68k_read_pcrelative_8(A)
+#define m68ki_read_pcrel_16(A) m68k_read_pcrelative_16(A)
+#define m68ki_read_pcrel_32(A) m68k_read_pcrelative_32(A)
+
+/* Read from the program space */
+#define m68ki_read_program_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM)
+#define m68ki_read_program_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM)
+#define m68ki_read_program_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM)
+
+/* Read from the data space */
+#define m68ki_read_data_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA)
+#define m68ki_read_data_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA)
+#define m68ki_read_data_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA)
+
+
+
+/* ======================================================================== */
+/* =============================== PROTOTYPES ============================= */
+/* ======================================================================== */
+
+typedef union
+{
+ UINT64 i;
+ double f;
+} fp_reg;
+
+typedef struct
+{
+ uint cpu_type; /* CPU Type: 68000, 68008, 68010, 68EC020, or 68020 */
+ uint dar[16]; /* Data and Address Registers */
+ uint ppc; /* Previous program counter */
+ uint pc; /* Program Counter */
+ uint sp[7]; /* User, Interrupt, and Master Stack Pointers */
+ uint vbr; /* Vector Base Register (m68010+) */
+ uint sfc; /* Source Function Code Register (m68010+) */
+ uint dfc; /* Destination Function Code Register (m68010+) */
+ uint cacr; /* Cache Control Register (m68020, unemulated) */
+ uint caar; /* Cache Address Register (m68020, unemulated) */
+ uint ir; /* Instruction Register */
+ fp_reg fpr[8]; /* FPU Data Register (m68040) */
+ uint fpiar; /* FPU Instruction Address Register (m68040) */
+ uint fpsr; /* FPU Status Register (m68040) */
+ uint fpcr; /* FPU Control Register (m68040) */
+ uint t1_flag; /* Trace 1 */
+ uint t0_flag; /* Trace 0 */
+ uint s_flag; /* Supervisor */
+ uint m_flag; /* Master/Interrupt state */
+ uint x_flag; /* Extend */
+ uint n_flag; /* Negative */
+ uint not_z_flag; /* Zero, inverted for speedups */
+ uint v_flag; /* Overflow */
+ uint c_flag; /* Carry */
+ uint int_mask; /* I0-I2 */
+ uint int_level; /* State of interrupt pins IPL0-IPL2 -- ASG: changed from ints_pending */
+ uint int_cycles; /* ASG: extra cycles from generated interrupts */
+ uint stopped; /* Stopped state */
+ uint pref_addr; /* Last prefetch address */
+ uint pref_data; /* Data in the prefetch queue */
+ uint address_mask; /* Available address pins */
+ uint sr_mask; /* Implemented status register bits */
+ uint instr_mode; /* Stores whether we are in instruction mode or group 0/1 exception mode */
+ uint run_mode; /* Stores whether we are processing a reset, bus error, address error, or something else */
+
+ /* Clocks required for instructions / exceptions */
+ uint cyc_bcc_notake_b;
+ uint cyc_bcc_notake_w;
+ uint cyc_dbcc_f_noexp;
+ uint cyc_dbcc_f_exp;
+ uint cyc_scc_r_true;
+ uint cyc_movem_w;
+ uint cyc_movem_l;
+ uint cyc_shift;
+ uint cyc_reset;
+ uint8* cyc_instruction;
+ uint8* cyc_exception;
+
+ /* Callbacks to host */
+ int (*int_ack_callback)(int int_line); /* Interrupt Acknowledge */
+ void (*bkpt_ack_callback)(unsigned int data); /* Breakpoint Acknowledge */
+ void (*reset_instr_callback)(void); /* Called when a RESET instruction is encountered */
+ void (*cmpild_instr_callback)(unsigned int, int); /* Called when a CMPI.L #v, Dn instruction is encountered */
+ void (*rte_instr_callback)(void); /* Called when a RTE instruction is encountered */
+ int (*tas_instr_callback)(void); /* Called when a TAS instruction is encountered, allows / disallows writeback */
+ void (*pc_changed_callback)(unsigned int new_pc); /* Called when the PC changes by a large amount */
+ void (*set_fc_callback)(unsigned int new_fc); /* Called when the CPU function code changes */
+ void (*instr_hook_callback)(void); /* Called every instruction cycle prior to execution */
+
+} m68ki_cpu_core;
+
+
+extern m68ki_cpu_core m68ki_cpu;
+extern sint m68ki_remaining_cycles;
+extern uint m68ki_tracing;
+extern uint8 m68ki_shift_8_table[];
+extern uint16 m68ki_shift_16_table[];
+extern uint m68ki_shift_32_table[];
+extern uint8 m68ki_exception_cycle_table[][256];
+extern uint m68ki_address_space;
+extern uint8 m68ki_ea_idx_cycle_table[];
+
+extern uint m68ki_aerr_address;
+extern uint m68ki_aerr_write_mode;
+extern uint m68ki_aerr_fc;
+
+/* Read data immediately after the program counter */
+INLINE uint m68ki_read_imm_16(void);
+INLINE uint m68ki_read_imm_32(void);
+
+/* Read data with specific function code */
+INLINE uint m68ki_read_8_fc (uint address, uint fc);
+INLINE uint m68ki_read_16_fc (uint address, uint fc);
+INLINE uint m68ki_read_32_fc (uint address, uint fc);
+
+/* Write data with specific function code */
+INLINE void m68ki_write_8_fc (uint address, uint fc, uint value);
+INLINE void m68ki_write_16_fc(uint address, uint fc, uint value);
+INLINE void m68ki_write_32_fc(uint address, uint fc, uint value);
+#if M68K_SIMULATE_PD_WRITES
+INLINE void m68ki_write_32_pd_fc(uint address, uint fc, uint value);
+#endif /* M68K_SIMULATE_PD_WRITES */
+
+/* Indexed and PC-relative ea fetching */
+INLINE uint m68ki_get_ea_pcdi(void);
+INLINE uint m68ki_get_ea_pcix(void);
+INLINE uint m68ki_get_ea_ix(uint An);
+
+/* Operand fetching */
+INLINE uint OPER_AY_AI_8(void);
+INLINE uint OPER_AY_AI_16(void);
+INLINE uint OPER_AY_AI_32(void);
+INLINE uint OPER_AY_PI_8(void);
+INLINE uint OPER_AY_PI_16(void);
+INLINE uint OPER_AY_PI_32(void);
+INLINE uint OPER_AY_PD_8(void);
+INLINE uint OPER_AY_PD_16(void);
+INLINE uint OPER_AY_PD_32(void);
+INLINE uint OPER_AY_DI_8(void);
+INLINE uint OPER_AY_DI_16(void);
+INLINE uint OPER_AY_DI_32(void);
+INLINE uint OPER_AY_IX_8(void);
+INLINE uint OPER_AY_IX_16(void);
+INLINE uint OPER_AY_IX_32(void);
+
+INLINE uint OPER_AX_AI_8(void);
+INLINE uint OPER_AX_AI_16(void);
+INLINE uint OPER_AX_AI_32(void);
+INLINE uint OPER_AX_PI_8(void);
+INLINE uint OPER_AX_PI_16(void);
+INLINE uint OPER_AX_PI_32(void);
+INLINE uint OPER_AX_PD_8(void);
+INLINE uint OPER_AX_PD_16(void);
+INLINE uint OPER_AX_PD_32(void);
+INLINE uint OPER_AX_DI_8(void);
+INLINE uint OPER_AX_DI_16(void);
+INLINE uint OPER_AX_DI_32(void);
+INLINE uint OPER_AX_IX_8(void);
+INLINE uint OPER_AX_IX_16(void);
+INLINE uint OPER_AX_IX_32(void);
+
+INLINE uint OPER_A7_PI_8(void);
+INLINE uint OPER_A7_PD_8(void);
+
+INLINE uint OPER_AW_8(void);
+INLINE uint OPER_AW_16(void);
+INLINE uint OPER_AW_32(void);
+INLINE uint OPER_AL_8(void);
+INLINE uint OPER_AL_16(void);
+INLINE uint OPER_AL_32(void);
+INLINE uint OPER_PCDI_8(void);
+INLINE uint OPER_PCDI_16(void);
+INLINE uint OPER_PCDI_32(void);
+INLINE uint OPER_PCIX_8(void);
+INLINE uint OPER_PCIX_16(void);
+INLINE uint OPER_PCIX_32(void);
+
+/* Stack operations */
+INLINE void m68ki_push_16(uint value);
+INLINE void m68ki_push_32(uint value);
+INLINE uint m68ki_pull_16(void);
+INLINE uint m68ki_pull_32(void);
+
+/* Program flow operations */
+INLINE void m68ki_jump(uint new_pc);
+INLINE void m68ki_jump_vector(uint vector);
+INLINE void m68ki_branch_8(uint offset);
+INLINE void m68ki_branch_16(uint offset);
+INLINE void m68ki_branch_32(uint offset);
+
+/* Status register operations. */
+INLINE void m68ki_set_s_flag(uint value); /* Only bit 2 of value should be set (i.e. 4 or 0) */
+INLINE void m68ki_set_sm_flag(uint value); /* only bits 1 and 2 of value should be set */
+INLINE void m68ki_set_ccr(uint value); /* set the condition code register */
+INLINE void m68ki_set_sr(uint value); /* set the status register */
+INLINE void m68ki_set_sr_noint(uint value); /* set the status register */
+
+/* Exception processing */
+INLINE uint m68ki_init_exception(void); /* Initial exception processing */
+
+INLINE void m68ki_stack_frame_3word(uint pc, uint sr); /* Stack various frame types */
+INLINE void m68ki_stack_frame_buserr(uint sr);
+
+INLINE void m68ki_stack_frame_0000(uint pc, uint sr, uint vector);
+INLINE void m68ki_stack_frame_0001(uint pc, uint sr, uint vector);
+INLINE void m68ki_stack_frame_0010(uint sr, uint vector);
+INLINE void m68ki_stack_frame_1000(uint pc, uint sr, uint vector);
+INLINE void m68ki_stack_frame_1010(uint sr, uint vector, uint pc);
+INLINE void m68ki_stack_frame_1011(uint sr, uint vector, uint pc);
+
+INLINE void m68ki_exception_trap(uint vector);
+INLINE void m68ki_exception_trapN(uint vector);
+INLINE void m68ki_exception_trace(void);
+INLINE void m68ki_exception_privilege_violation(void);
+INLINE void m68ki_exception_1010(void);
+INLINE void m68ki_exception_1111(void);
+INLINE void m68ki_exception_illegal(void);
+INLINE void m68ki_exception_format_error(void);
+INLINE void m68ki_exception_address_error(void);
+INLINE void m68ki_exception_interrupt(uint int_level);
+INLINE void m68ki_check_interrupts(void); /* ASG: check for interrupts */
+
+/* quick disassembly (used for logging) */
+char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type);
+
+
+/* ======================================================================== */
+/* =========================== UTILITY FUNCTIONS ========================== */
+/* ======================================================================== */
+
+
+/* ---------------------------- Read Immediate ---------------------------- */
+
+/* Handles all immediate reads, does address error check, function code setting,
+ * and prefetching if they are enabled in m68kconf.h
+ */
+INLINE uint m68ki_read_imm_16(void)
+{
+ m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
+ m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
+#if M68K_EMULATE_PREFETCH
+ if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR)
+ {
+ CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC);
+ CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR));
+ }
+ REG_PC += 2;
+ return MASK_OUT_ABOVE_16(CPU_PREF_DATA >> ((2-((REG_PC-2)&2))<<3));
+#else
+ REG_PC += 2;
+ return m68k_read_immediate_16(ADDRESS_68K(REG_PC-2));
+#endif /* M68K_EMULATE_PREFETCH */
+}
+INLINE uint m68ki_read_imm_32(void)
+{
+#if M68K_EMULATE_PREFETCH
+ uint temp_val;
+
+ m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
+ m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
+ if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR)
+ {
+ CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC);
+ CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR));
+ }
+ temp_val = CPU_PREF_DATA;
+ REG_PC += 2;
+ if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR)
+ {
+ CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC);
+ CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR));
+ temp_val = MASK_OUT_ABOVE_32((temp_val << 16) | (CPU_PREF_DATA >> 16));
+ }
+ REG_PC += 2;
+
+ return temp_val;
+#else
+ m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
+ m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */
+ REG_PC += 4;
+ return m68k_read_immediate_32(ADDRESS_68K(REG_PC-4));
+#endif /* M68K_EMULATE_PREFETCH */
+}
+
+
+
+/* ------------------------- Top level read/write ------------------------- */
+
+/* Handles all memory accesses (except for immediate reads if they are
+ * configured to use separate functions in m68kconf.h).
+ * All memory accesses must go through these top level functions.
+ * These functions will also check for address error and set the function
+ * code if they are enabled in m68kconf.h.
+ */
+INLINE uint m68ki_read_8_fc(uint address, uint fc)
+{
+ m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
+ return m68k_read_memory_8(ADDRESS_68K(address));
+}
+INLINE uint m68ki_read_16_fc(uint address, uint fc)
+{
+ m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
+ m68ki_check_address_error_010_less(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */
+ return m68k_read_memory_16(ADDRESS_68K(address));
+}
+INLINE uint m68ki_read_32_fc(uint address, uint fc)
+{
+ m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
+ m68ki_check_address_error_010_less(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */
+ return m68k_read_memory_32(ADDRESS_68K(address));
+}
+
+INLINE void m68ki_write_8_fc(uint address, uint fc, uint value)
+{
+ m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
+ m68k_write_memory_8(ADDRESS_68K(address), value);
+}
+INLINE void m68ki_write_16_fc(uint address, uint fc, uint value)
+{
+ m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
+ m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */
+ m68k_write_memory_16(ADDRESS_68K(address), value);
+}
+INLINE void m68ki_write_32_fc(uint address, uint fc, uint value)
+{
+ m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
+ m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */
+ m68k_write_memory_32(ADDRESS_68K(address), value);
+}
+
+#if M68K_SIMULATE_PD_WRITES
+INLINE void m68ki_write_32_pd_fc(uint address, uint fc, uint value)
+{
+ m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */
+ m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */
+ m68k_write_memory_32_pd(ADDRESS_68K(address), value);
+}
+#endif
+
+
+/* --------------------- Effective Address Calculation -------------------- */
+
+/* The program counter relative addressing modes cause operands to be
+ * retrieved from program space, not data space.
+ */
+INLINE uint m68ki_get_ea_pcdi(void)
+{
+ uint old_pc = REG_PC;
+ m68ki_use_program_space(); /* auto-disable */
+ return old_pc + MAKE_INT_16(m68ki_read_imm_16());
+}
+
+
+INLINE uint m68ki_get_ea_pcix(void)
+{
+ m68ki_use_program_space(); /* auto-disable */
+ return m68ki_get_ea_ix(REG_PC);
+}
+
+/* Indexed addressing modes are encoded as follows:
+ *
+ * Base instruction format:
+ * F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0
+ * x x x x x x x x x x | 1 1 0 | BASE REGISTER (An)
+ *
+ * Base instruction format for destination EA in move instructions:
+ * F E D C | B A 9 | 8 7 6 | 5 4 3 2 1 0
+ * x x x x | BASE REG | 1 1 0 | X X X X X X (An)
+ *
+ * Brief extension format:
+ * F | E D C | B | A 9 | 8 | 7 6 5 4 3 2 1 0
+ * D/A | REGISTER | W/L | SCALE | 0 | DISPLACEMENT
+ *
+ * Full extension format:
+ * F E D C B A 9 8 7 6 5 4 3 2 1 0
+ * D/A | REGISTER | W/L | SCALE | 1 | BS | IS | BD SIZE | 0 | I/IS
+ * BASE DISPLACEMENT (0, 16, 32 bit) (bd)
+ * OUTER DISPLACEMENT (0, 16, 32 bit) (od)
+ *
+ * D/A: 0 = Dn, 1 = An (Xn)
+ * W/L: 0 = W (sign extend), 1 = L (.SIZE)
+ * SCALE: 00=1, 01=2, 10=4, 11=8 (*SCALE)
+ * BS: 0=add base reg, 1=suppress base reg (An suppressed)
+ * IS: 0=add index, 1=suppress index (Xn suppressed)
+ * BD SIZE: 00=reserved, 01=NULL, 10=Word, 11=Long (size of bd)
+ *
+ * IS I/IS Operation
+ * 0 000 No Memory Indirect
+ * 0 001 indir prex with null outer
+ * 0 010 indir prex with word outer
+ * 0 011 indir prex with long outer
+ * 0 100 reserved
+ * 0 101 indir postx with null outer
+ * 0 110 indir postx with word outer
+ * 0 111 indir postx with long outer
+ * 1 000 no memory indirect
+ * 1 001 mem indir with null outer
+ * 1 010 mem indir with word outer
+ * 1 011 mem indir with long outer
+ * 1 100-111 reserved
+ */
+INLINE uint m68ki_get_ea_ix(uint An)
+{
+ /* An = base register */
+ uint extension = m68ki_read_imm_16();
+ uint Xn = 0; /* Index register */
+ uint bd = 0; /* Base Displacement */
+ uint od = 0; /* Outer Displacement */
+
+ if(CPU_TYPE_IS_010_LESS(CPU_TYPE))
+ {
+ /* Calculate index */
+ Xn = REG_DA[extension>>12]; /* Xn */
+ if(!BIT_B(extension)) /* W/L */
+ Xn = MAKE_INT_16(Xn);
+
+ /* Add base register and displacement and return */
+ return An + Xn + MAKE_INT_8(extension);
+ }
+
+ /* Brief extension format */
+ if(!BIT_8(extension))
+ {
+ /* Calculate index */
+ Xn = REG_DA[extension>>12]; /* Xn */
+ if(!BIT_B(extension)) /* W/L */
+ Xn = MAKE_INT_16(Xn);
+ /* Add scale if proper CPU type */
+ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ Xn <<= (extension>>9) & 3; /* SCALE */
+
+ /* Add base register and displacement and return */
+ return An + Xn + MAKE_INT_8(extension);
+ }
+
+ /* Full extension format */
+
+ USE_CYCLES(m68ki_ea_idx_cycle_table[extension&0x3f]);
+
+ /* Check if base register is present */
+ if(BIT_7(extension)) /* BS */
+ An = 0; /* An */
+
+ /* Check if index is present */
+ if(!BIT_6(extension)) /* IS */
+ {
+ Xn = REG_DA[extension>>12]; /* Xn */
+ if(!BIT_B(extension)) /* W/L */
+ Xn = MAKE_INT_16(Xn);
+ Xn <<= (extension>>9) & 3; /* SCALE */
+ }
+
+ /* Check if base displacement is present */
+ if(BIT_5(extension)) /* BD SIZE */
+ bd = BIT_4(extension) ? m68ki_read_imm_32() : MAKE_INT_16(m68ki_read_imm_16());
+
+ /* If no indirect action, we are done */
+ if(!(extension&7)) /* No Memory Indirect */
+ return An + bd + Xn;
+
+ /* Check if outer displacement is present */
+ if(BIT_1(extension)) /* I/IS: od */
+ od = BIT_0(extension) ? m68ki_read_imm_32() : MAKE_INT_16(m68ki_read_imm_16());
+
+ /* Postindex */
+ if(BIT_2(extension)) /* I/IS: 0 = preindex, 1 = postindex */
+ return m68ki_read_32(An + bd) + Xn + od;
+
+ /* Preindex */
+ return m68ki_read_32(An + bd + Xn) + od;
+}
+
+
+/* Fetch operands */
+INLINE uint OPER_AY_AI_8(void) {uint ea = EA_AY_AI_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AY_AI_16(void) {uint ea = EA_AY_AI_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AY_AI_32(void) {uint ea = EA_AY_AI_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_AY_PI_8(void) {uint ea = EA_AY_PI_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AY_PI_16(void) {uint ea = EA_AY_PI_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AY_PI_32(void) {uint ea = EA_AY_PI_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_AY_PD_8(void) {uint ea = EA_AY_PD_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AY_PD_16(void) {uint ea = EA_AY_PD_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AY_PD_32(void) {uint ea = EA_AY_PD_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_AY_DI_8(void) {uint ea = EA_AY_DI_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AY_DI_16(void) {uint ea = EA_AY_DI_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AY_DI_32(void) {uint ea = EA_AY_DI_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_AY_IX_8(void) {uint ea = EA_AY_IX_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AY_IX_16(void) {uint ea = EA_AY_IX_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AY_IX_32(void) {uint ea = EA_AY_IX_32(); return m68ki_read_32(ea);}
+
+INLINE uint OPER_AX_AI_8(void) {uint ea = EA_AX_AI_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AX_AI_16(void) {uint ea = EA_AX_AI_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AX_AI_32(void) {uint ea = EA_AX_AI_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_AX_PI_8(void) {uint ea = EA_AX_PI_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AX_PI_16(void) {uint ea = EA_AX_PI_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AX_PI_32(void) {uint ea = EA_AX_PI_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_AX_PD_8(void) {uint ea = EA_AX_PD_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AX_PD_16(void) {uint ea = EA_AX_PD_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AX_PD_32(void) {uint ea = EA_AX_PD_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_AX_DI_8(void) {uint ea = EA_AX_DI_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AX_DI_16(void) {uint ea = EA_AX_DI_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AX_DI_32(void) {uint ea = EA_AX_DI_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_AX_IX_8(void) {uint ea = EA_AX_IX_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AX_IX_16(void) {uint ea = EA_AX_IX_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AX_IX_32(void) {uint ea = EA_AX_IX_32(); return m68ki_read_32(ea);}
+
+INLINE uint OPER_A7_PI_8(void) {uint ea = EA_A7_PI_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_A7_PD_8(void) {uint ea = EA_A7_PD_8(); return m68ki_read_8(ea); }
+
+INLINE uint OPER_AW_8(void) {uint ea = EA_AW_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AW_16(void) {uint ea = EA_AW_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AW_32(void) {uint ea = EA_AW_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_AL_8(void) {uint ea = EA_AL_8(); return m68ki_read_8(ea); }
+INLINE uint OPER_AL_16(void) {uint ea = EA_AL_16(); return m68ki_read_16(ea);}
+INLINE uint OPER_AL_32(void) {uint ea = EA_AL_32(); return m68ki_read_32(ea);}
+INLINE uint OPER_PCDI_8(void) {uint ea = EA_PCDI_8(); return m68ki_read_pcrel_8(ea); }
+INLINE uint OPER_PCDI_16(void) {uint ea = EA_PCDI_16(); return m68ki_read_pcrel_16(ea);}
+INLINE uint OPER_PCDI_32(void) {uint ea = EA_PCDI_32(); return m68ki_read_pcrel_32(ea);}
+INLINE uint OPER_PCIX_8(void) {uint ea = EA_PCIX_8(); return m68ki_read_pcrel_8(ea); }
+INLINE uint OPER_PCIX_16(void) {uint ea = EA_PCIX_16(); return m68ki_read_pcrel_16(ea);}
+INLINE uint OPER_PCIX_32(void) {uint ea = EA_PCIX_32(); return m68ki_read_pcrel_32(ea);}
+
+
+
+/* ---------------------------- Stack Functions --------------------------- */
+
+/* Push/pull data from the stack */
+INLINE void m68ki_push_16(uint value)
+{
+ REG_SP = MASK_OUT_ABOVE_32(REG_SP - 2);
+ m68ki_write_16(REG_SP, value);
+}
+
+INLINE void m68ki_push_32(uint value)
+{
+ REG_SP = MASK_OUT_ABOVE_32(REG_SP - 4);
+ m68ki_write_32(REG_SP, value);
+}
+
+INLINE uint m68ki_pull_16(void)
+{
+ REG_SP = MASK_OUT_ABOVE_32(REG_SP + 2);
+ return m68ki_read_16(REG_SP-2);
+}
+
+INLINE uint m68ki_pull_32(void)
+{
+ REG_SP = MASK_OUT_ABOVE_32(REG_SP + 4);
+ return m68ki_read_32(REG_SP-4);
+}
+
+
+/* Increment/decrement the stack as if doing a push/pull but
+ * don't do any memory access.
+ */
+INLINE void m68ki_fake_push_16(void)
+{
+ REG_SP = MASK_OUT_ABOVE_32(REG_SP - 2);
+}
+
+INLINE void m68ki_fake_push_32(void)
+{
+ REG_SP = MASK_OUT_ABOVE_32(REG_SP - 4);
+}
+
+INLINE void m68ki_fake_pull_16(void)
+{
+ REG_SP = MASK_OUT_ABOVE_32(REG_SP + 2);
+}
+
+INLINE void m68ki_fake_pull_32(void)
+{
+ REG_SP = MASK_OUT_ABOVE_32(REG_SP + 4);
+}
+
+
+/* ----------------------------- Program Flow ----------------------------- */
+
+/* Jump to a new program location or vector.
+ * These functions will also call the pc_changed callback if it was enabled
+ * in m68kconf.h.
+ */
+INLINE void m68ki_jump(uint new_pc)
+{
+ REG_PC = new_pc;
+ m68ki_pc_changed(REG_PC);
+}
+
+INLINE void m68ki_jump_vector(uint vector)
+{
+ REG_PC = (vector<<2) + REG_VBR;
+ REG_PC = m68ki_read_data_32(REG_PC);
+ m68ki_pc_changed(REG_PC);
+}
+
+
+/* Branch to a new memory location.
+ * The 32-bit branch will call pc_changed if it was enabled in m68kconf.h.
+ * So far I've found no problems with not calling pc_changed for 8 or 16
+ * bit branches.
+ */
+INLINE void m68ki_branch_8(uint offset)
+{
+ REG_PC += MAKE_INT_8(offset);
+}
+
+INLINE void m68ki_branch_16(uint offset)
+{
+ REG_PC += MAKE_INT_16(offset);
+}
+
+INLINE void m68ki_branch_32(uint offset)
+{
+ REG_PC += offset;
+ m68ki_pc_changed(REG_PC);
+}
+
+
+
+/* ---------------------------- Status Register --------------------------- */
+
+/* Set the S flag and change the active stack pointer.
+ * Note that value MUST be 4 or 0.
+ */
+INLINE void m68ki_set_s_flag(uint value)
+{
+ /* Backup the old stack pointer */
+ REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)] = REG_SP;
+ /* Set the S flag */
+ FLAG_S = value;
+ /* Set the new stack pointer */
+ REG_SP = REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)];
+}
+
+/* Set the S and M flags and change the active stack pointer.
+ * Note that value MUST be 0, 2, 4, or 6 (bit2 = S, bit1 = M).
+ */
+INLINE void m68ki_set_sm_flag(uint value)
+{
+ /* Backup the old stack pointer */
+ REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)] = REG_SP;
+ /* Set the S and M flags */
+ FLAG_S = value & SFLAG_SET;
+ FLAG_M = value & MFLAG_SET;
+ /* Set the new stack pointer */
+ REG_SP = REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)];
+}
+
+/* Set the S and M flags. Don't touch the stack pointer. */
+INLINE void m68ki_set_sm_flag_nosp(uint value)
+{
+ /* Set the S and M flags */
+ FLAG_S = value & SFLAG_SET;
+ FLAG_M = value & MFLAG_SET;
+}
+
+
+/* Set the condition code register */
+INLINE void m68ki_set_ccr(uint value)
+{
+ FLAG_X = BIT_4(value) << 4;
+ FLAG_N = BIT_3(value) << 4;
+ FLAG_Z = !BIT_2(value);
+ FLAG_V = BIT_1(value) << 6;
+ FLAG_C = BIT_0(value) << 8;
+}
+
+/* Set the status register but don't check for interrupts */
+INLINE void m68ki_set_sr_noint(uint value)
+{
+ /* Mask out the "unimplemented" bits */
+ value &= CPU_SR_MASK;
+
+ /* Now set the status register */
+ FLAG_T1 = BIT_F(value);
+ FLAG_T0 = BIT_E(value);
+ FLAG_INT_MASK = value & 0x0700;
+ m68ki_set_ccr(value);
+ m68ki_set_sm_flag((value >> 11) & 6);
+}
+
+/* Set the status register but don't check for interrupts nor
+ * change the stack pointer
+ */
+INLINE void m68ki_set_sr_noint_nosp(uint value)
+{
+ /* Mask out the "unimplemented" bits */
+ value &= CPU_SR_MASK;
+
+ /* Now set the status register */
+ FLAG_T1 = BIT_F(value);
+ FLAG_T0 = BIT_E(value);
+ FLAG_INT_MASK = value & 0x0700;
+ m68ki_set_ccr(value);
+ m68ki_set_sm_flag_nosp((value >> 11) & 6);
+}
+
+/* Set the status register and check for interrupts */
+INLINE void m68ki_set_sr(uint value)
+{
+ m68ki_set_sr_noint(value);
+ m68ki_check_interrupts();
+}
+
+
+/* ------------------------- Exception Processing ------------------------- */
+
+/* Initiate exception processing */
+INLINE uint m68ki_init_exception(void)
+{
+ /* Save the old status register */
+ uint sr = m68ki_get_sr();
+
+ /* Turn off trace flag, clear pending traces */
+ FLAG_T1 = FLAG_T0 = 0;
+ m68ki_clear_trace();
+ /* Enter supervisor mode */
+ m68ki_set_s_flag(SFLAG_SET);
+
+ return sr;
+}
+
+/* 3 word stack frame (68000 only) */
+INLINE void m68ki_stack_frame_3word(uint pc, uint sr)
+{
+ m68ki_push_32(pc);
+ m68ki_push_16(sr);
+}
+
+/* Format 0 stack frame.
+ * This is the standard stack frame for 68010+.
+ */
+INLINE void m68ki_stack_frame_0000(uint pc, uint sr, uint vector)
+{
+ /* Stack a 3-word frame if we are 68000 */
+ if(CPU_TYPE == CPU_TYPE_000 || CPU_TYPE == CPU_TYPE_008)
+ {
+ m68ki_stack_frame_3word(pc, sr);
+ return;
+ }
+ m68ki_push_16(vector<<2);
+ m68ki_push_32(pc);
+ m68ki_push_16(sr);
+}
+
+/* Format 1 stack frame (68020).
+ * For 68020, this is the 4 word throwaway frame.
+ */
+INLINE void m68ki_stack_frame_0001(uint pc, uint sr, uint vector)
+{
+ m68ki_push_16(0x1000 | (vector<<2));
+ m68ki_push_32(pc);
+ m68ki_push_16(sr);
+}
+
+/* Format 2 stack frame.
+ * This is used only by 68020 for trap exceptions.
+ */
+INLINE void m68ki_stack_frame_0010(uint sr, uint vector)
+{
+ m68ki_push_32(REG_PPC);
+ m68ki_push_16(0x2000 | (vector<<2));
+ m68ki_push_32(REG_PC);
+ m68ki_push_16(sr);
+}
+
+
+/* Bus error stack frame (68000 only).
+ */
+INLINE void m68ki_stack_frame_buserr(uint sr)
+{
+ m68ki_push_32(REG_PC);
+ m68ki_push_16(sr);
+ m68ki_push_16(REG_IR);
+ m68ki_push_32(m68ki_aerr_address); /* access address */
+ /* 0 0 0 0 0 0 0 0 0 0 0 R/W I/N FC
+ * R/W 0 = write, 1 = read
+ * I/N 0 = instruction, 1 = not
+ * FC 3-bit function code
+ */
+ m68ki_push_16(m68ki_aerr_write_mode | CPU_INSTR_MODE | m68ki_aerr_fc);
+}
+
+/* Format 8 stack frame (68010).
+ * 68010 only. This is the 29 word bus/address error frame.
+ */
+void m68ki_stack_frame_1000(uint pc, uint sr, uint vector)
+{
+ /* VERSION
+ * NUMBER
+ * INTERNAL INFORMATION, 16 WORDS
+ */
+ m68ki_fake_push_32();
+ m68ki_fake_push_32();
+ m68ki_fake_push_32();
+ m68ki_fake_push_32();
+ m68ki_fake_push_32();
+ m68ki_fake_push_32();
+ m68ki_fake_push_32();
+ m68ki_fake_push_32();
+
+ /* INSTRUCTION INPUT BUFFER */
+ m68ki_push_16(0);
+
+ /* UNUSED, RESERVED (not written) */
+ m68ki_fake_push_16();
+
+ /* DATA INPUT BUFFER */
+ m68ki_push_16(0);
+
+ /* UNUSED, RESERVED (not written) */
+ m68ki_fake_push_16();
+
+ /* DATA OUTPUT BUFFER */
+ m68ki_push_16(0);
+
+ /* UNUSED, RESERVED (not written) */
+ m68ki_fake_push_16();
+
+ /* FAULT ADDRESS */
+ m68ki_push_32(0);
+
+ /* SPECIAL STATUS WORD */
+ m68ki_push_16(0);
+
+ /* 1000, VECTOR OFFSET */
+ m68ki_push_16(0x8000 | (vector<<2));
+
+ /* PROGRAM COUNTER */
+ m68ki_push_32(pc);
+
+ /* STATUS REGISTER */
+ m68ki_push_16(sr);
+}
+
+/* Format A stack frame (short bus fault).
+ * This is used only by 68020 for bus fault and address error
+ * if the error happens at an instruction boundary.
+ * PC stacked is address of next instruction.
+ */
+void m68ki_stack_frame_1010(uint sr, uint vector, uint pc)
+{
+ /* INTERNAL REGISTER */
+ m68ki_push_16(0);
+
+ /* INTERNAL REGISTER */
+ m68ki_push_16(0);
+
+ /* DATA OUTPUT BUFFER (2 words) */
+ m68ki_push_32(0);
+
+ /* INTERNAL REGISTER */
+ m68ki_push_16(0);
+
+ /* INTERNAL REGISTER */
+ m68ki_push_16(0);
+
+ /* DATA CYCLE FAULT ADDRESS (2 words) */
+ m68ki_push_32(0);
+
+ /* INSTRUCTION PIPE STAGE B */
+ m68ki_push_16(0);
+
+ /* INSTRUCTION PIPE STAGE C */
+ m68ki_push_16(0);
+
+ /* SPECIAL STATUS REGISTER */
+ m68ki_push_16(0);
+
+ /* INTERNAL REGISTER */
+ m68ki_push_16(0);
+
+ /* 1010, VECTOR OFFSET */
+ m68ki_push_16(0xa000 | (vector<<2));
+
+ /* PROGRAM COUNTER */
+ m68ki_push_32(pc);
+
+ /* STATUS REGISTER */
+ m68ki_push_16(sr);
+}
+
+/* Format B stack frame (long bus fault).
+ * This is used only by 68020 for bus fault and address error
+ * if the error happens during instruction execution.
+ * PC stacked is address of instruction in progress.
+ */
+void m68ki_stack_frame_1011(uint sr, uint vector, uint pc)
+{
+ /* INTERNAL REGISTERS (18 words) */
+ m68ki_push_32(0);
+ m68ki_push_32(0);
+ m68ki_push_32(0);
+ m68ki_push_32(0);
+ m68ki_push_32(0);
+ m68ki_push_32(0);
+ m68ki_push_32(0);
+ m68ki_push_32(0);
+ m68ki_push_32(0);
+
+ /* VERSION# (4 bits), INTERNAL INFORMATION */
+ m68ki_push_16(0);
+
+ /* INTERNAL REGISTERS (3 words) */
+ m68ki_push_32(0);
+ m68ki_push_16(0);
+
+ /* DATA INTPUT BUFFER (2 words) */
+ m68ki_push_32(0);
+
+ /* INTERNAL REGISTERS (2 words) */
+ m68ki_push_32(0);
+
+ /* STAGE B ADDRESS (2 words) */
+ m68ki_push_32(0);
+
+ /* INTERNAL REGISTER (4 words) */
+ m68ki_push_32(0);
+ m68ki_push_32(0);
+
+ /* DATA OUTPUT BUFFER (2 words) */
+ m68ki_push_32(0);
+
+ /* INTERNAL REGISTER */
+ m68ki_push_16(0);
+
+ /* INTERNAL REGISTER */
+ m68ki_push_16(0);
+
+ /* DATA CYCLE FAULT ADDRESS (2 words) */
+ m68ki_push_32(0);
+
+ /* INSTRUCTION PIPE STAGE B */
+ m68ki_push_16(0);
+
+ /* INSTRUCTION PIPE STAGE C */
+ m68ki_push_16(0);
+
+ /* SPECIAL STATUS REGISTER */
+ m68ki_push_16(0);
+
+ /* INTERNAL REGISTER */
+ m68ki_push_16(0);
+
+ /* 1011, VECTOR OFFSET */
+ m68ki_push_16(0xb000 | (vector<<2));
+
+ /* PROGRAM COUNTER */
+ m68ki_push_32(pc);
+
+ /* STATUS REGISTER */
+ m68ki_push_16(sr);
+}
+
+
+/* Used for Group 2 exceptions.
+ * These stack a type 2 frame on the 020.
+ */
+INLINE void m68ki_exception_trap(uint vector)
+{
+ uint sr = m68ki_init_exception();
+
+ if(CPU_TYPE_IS_010_LESS(CPU_TYPE))
+ m68ki_stack_frame_0000(REG_PC, sr, vector);
+ else
+ m68ki_stack_frame_0010(sr, vector);
+
+ m68ki_jump_vector(vector);
+
+ /* Use up some clock cycles */
+ USE_CYCLES(CYC_EXCEPTION[vector]);
+}
+
+/* Trap#n stacks a 0 frame but behaves like group2 otherwise */
+INLINE void m68ki_exception_trapN(uint vector)
+{
+ uint sr = m68ki_init_exception();
+ m68ki_stack_frame_0000(REG_PC, sr, vector);
+ m68ki_jump_vector(vector);
+
+ /* Use up some clock cycles */
+ USE_CYCLES(CYC_EXCEPTION[vector]);
+}
+
+/* Exception for trace mode */
+INLINE void m68ki_exception_trace(void)
+{
+ uint sr = m68ki_init_exception();
+
+ if(CPU_TYPE_IS_010_LESS(CPU_TYPE))
+ {
+ #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON
+ if(CPU_TYPE_IS_000(CPU_TYPE))
+ {
+ CPU_INSTR_MODE = INSTRUCTION_NO;
+ }
+ #endif /* M68K_EMULATE_ADDRESS_ERROR */
+ m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_TRACE);
+ }
+ else
+ m68ki_stack_frame_0010(sr, EXCEPTION_TRACE);
+
+ m68ki_jump_vector(EXCEPTION_TRACE);
+
+ /* Trace nullifies a STOP instruction */
+ CPU_STOPPED &= ~STOP_LEVEL_STOP;
+
+ /* Use up some clock cycles */
+ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_TRACE]);
+}
+
+/* Exception for privilege violation */
+INLINE void m68ki_exception_privilege_violation(void)
+{
+ uint sr = m68ki_init_exception();
+
+ #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON
+ if(CPU_TYPE_IS_000(CPU_TYPE))
+ {
+ CPU_INSTR_MODE = INSTRUCTION_NO;
+ }
+ #endif /* M68K_EMULATE_ADDRESS_ERROR */
+
+ m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_PRIVILEGE_VIOLATION);
+ m68ki_jump_vector(EXCEPTION_PRIVILEGE_VIOLATION);
+
+ /* Use up some clock cycles and undo the instruction's cycles */
+ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_PRIVILEGE_VIOLATION] - CYC_INSTRUCTION[REG_IR]);
+}
+
+/* Exception for A-Line instructions */
+INLINE void m68ki_exception_1010(void)
+{
+ uint sr;
+#if M68K_LOG_1010_1111 == OPT_ON
+ M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1010 instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR,
+ m68ki_disassemble_quick(ADDRESS_68K(REG_PPC))));
+#endif
+
+ sr = m68ki_init_exception();
+ m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_1010);
+ m68ki_jump_vector(EXCEPTION_1010);
+
+ /* Use up some clock cycles and undo the instruction's cycles */
+ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1010] - CYC_INSTRUCTION[REG_IR]);
+}
+
+/* Exception for F-Line instructions */
+INLINE void m68ki_exception_1111(void)
+{
+ uint sr;
+
+#if M68K_LOG_1010_1111 == OPT_ON
+ M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1111 instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR,
+ m68ki_disassemble_quick(ADDRESS_68K(REG_PPC))));
+#endif
+
+ sr = m68ki_init_exception();
+ m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_1111);
+ m68ki_jump_vector(EXCEPTION_1111);
+
+ /* Use up some clock cycles and undo the instruction's cycles */
+ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1111] - CYC_INSTRUCTION[REG_IR]);
+}
+
+/* Exception for illegal instructions */
+INLINE void m68ki_exception_illegal(void)
+{
+ uint sr;
+
+ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: illegal instruction %04x (%s)\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR,
+ m68ki_disassemble_quick(ADDRESS_68K(REG_PPC))));
+
+ sr = m68ki_init_exception();
+
+ #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON
+ if(CPU_TYPE_IS_000(CPU_TYPE))
+ {
+ CPU_INSTR_MODE = INSTRUCTION_NO;
+ }
+ #endif /* M68K_EMULATE_ADDRESS_ERROR */
+
+ m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_ILLEGAL_INSTRUCTION);
+ m68ki_jump_vector(EXCEPTION_ILLEGAL_INSTRUCTION);
+
+ /* Use up some clock cycles and undo the instruction's cycles */
+ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_ILLEGAL_INSTRUCTION] - CYC_INSTRUCTION[REG_IR]);
+}
+
+/* Exception for format errror in RTE */
+INLINE void m68ki_exception_format_error(void)
+{
+ uint sr = m68ki_init_exception();
+ m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_FORMAT_ERROR);
+ m68ki_jump_vector(EXCEPTION_FORMAT_ERROR);
+
+ /* Use up some clock cycles and undo the instruction's cycles */
+ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_FORMAT_ERROR] - CYC_INSTRUCTION[REG_IR]);
+}
+
+/* Exception for address error */
+INLINE void m68ki_exception_address_error(void)
+{
+ uint sr = m68ki_init_exception();
+
+ /* If we were processing a bus error, address error, or reset,
+ * this is a catastrophic failure.
+ * Halt the CPU
+ */
+ if(CPU_RUN_MODE == RUN_MODE_BERR_AERR_RESET)
+ {
+ m68k_read_memory_8(0x00ffff01);
+ CPU_STOPPED = STOP_LEVEL_HALT;
+ return;
+ }
+ CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
+
+ /* Note: This is implemented for 68000 only! */
+ m68ki_stack_frame_buserr(sr);
+
+ m68ki_jump_vector(EXCEPTION_ADDRESS_ERROR);
+
+ /* Use up some clock cycles and undo the instruction's cycles */
+ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_ADDRESS_ERROR] - CYC_INSTRUCTION[REG_IR]);
+}
+
+
+/* Service an interrupt request and start exception processing */
+void m68ki_exception_interrupt(uint int_level)
+{
+ uint vector;
+ uint sr;
+ uint new_pc;
+
+ #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON
+ if(CPU_TYPE_IS_000(CPU_TYPE))
+ {
+ CPU_INSTR_MODE = INSTRUCTION_NO;
+ }
+ #endif /* M68K_EMULATE_ADDRESS_ERROR */
+
+ /* Turn off the stopped state */
+ CPU_STOPPED &= ~STOP_LEVEL_STOP;
+
+ /* If we are halted, don't do anything */
+ if(CPU_STOPPED)
+ return;
+
+ /* Acknowledge the interrupt */
+ vector = m68ki_int_ack(int_level);
+
+ /* Get the interrupt vector */
+ if(vector == M68K_INT_ACK_AUTOVECTOR)
+ /* Use the autovectors. This is the most commonly used implementation */
+ vector = EXCEPTION_INTERRUPT_AUTOVECTOR+int_level;
+ else if(vector == M68K_INT_ACK_SPURIOUS)
+ /* Called if no devices respond to the interrupt acknowledge */
+ vector = EXCEPTION_SPURIOUS_INTERRUPT;
+ else if(vector > 255)
+ {
+ M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: Interrupt acknowledge returned invalid vector $%x\n",
+ m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC), vector));
+ return;
+ }
+
+ /* Start exception processing */
+ sr = m68ki_init_exception();
+
+ /* Set the interrupt mask to the level of the one being serviced */
+ FLAG_INT_MASK = int_level<<8;
+
+ /* Get the new PC */
+ new_pc = m68ki_read_data_32((vector<<2) + REG_VBR);
+
+ /* If vector is uninitialized, call the uninitialized interrupt vector */
+ if(new_pc == 0)
+ new_pc = m68ki_read_data_32((EXCEPTION_UNINITIALIZED_INTERRUPT<<2) + REG_VBR);
+
+ /* Generate a stack frame */
+ m68ki_stack_frame_0000(REG_PC, sr, vector);
+ if(FLAG_M && CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
+ {
+ /* Create throwaway frame */
+ m68ki_set_sm_flag(FLAG_S); /* clear M */
+ sr |= 0x2000; /* Same as SR in master stack frame except S is forced high */
+ m68ki_stack_frame_0001(REG_PC, sr, vector);
+ }
+
+ m68ki_jump(new_pc);
+
+ /* Defer cycle counting until later */
+ CPU_INT_CYCLES += CYC_EXCEPTION[vector];
+
+#if !M68K_EMULATE_INT_ACK
+ /* Automatically clear IRQ if we are not using an acknowledge scheme */
+ CPU_INT_LEVEL = 0;
+#endif /* M68K_EMULATE_INT_ACK */
+}
+
+
+/* ASG: Check for interrupts */
+INLINE void m68ki_check_interrupts(void)
+{
+ if(CPU_INT_LEVEL > FLAG_INT_MASK)
+ m68ki_exception_interrupt(CPU_INT_LEVEL>>8);
+}
+
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+#endif /* M68KCPU__HEADER */
diff --git a/src/emu/cpu/m68000/m68kdasm.c b/src/emu/cpu/m68000/m68kdasm.c
new file mode 100644
index 00000000000..148e11f6707
--- /dev/null
+++ b/src/emu/cpu/m68000/m68kdasm.c
@@ -0,0 +1,3742 @@
+/* ======================================================================== */
+/* ========================= LICENSING & COPYRIGHT ======================== */
+/* ======================================================================== */
+/*
+ * MUSASHI
+ * Version 3.31
+ *
+ * A portable Motorola M680x0 processor emulation engine.
+ * Copyright 1998-2007 Karl Stenerud. All rights reserved.
+ *
+ * This code may be freely used for non-commercial purposes as long as this
+ * copyright notice remains unaltered in the source code and any binary files
+ * containing this code in compiled form.
+ *
+ * All other lisencing terms must be negotiated with the author
+ * (Karl Stenerud).
+ *
+ * The latest version of this code can be obtained at:
+ * http://kstenerud.cjb.net
+ */
+
+
+
+/* ======================================================================== */
+/* ================================ INCLUDES ============================== */
+/* ======================================================================== */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "m68k.h"
+
+#ifndef DECL_SPEC
+#define DECL_SPEC
+#endif
+
+/* ======================================================================== */
+/* ============================ GENERAL DEFINES =========================== */
+/* ======================================================================== */
+
+/* unsigned int and int must be at least 32 bits wide */
+#undef uint
+#define uint unsigned int
+
+/* Bit Isolation Functions */
+#define BIT_0(A) ((A) & 0x00000001)
+#define BIT_1(A) ((A) & 0x00000002)
+#define BIT_2(A) ((A) & 0x00000004)
+#define BIT_3(A) ((A) & 0x00000008)
+#define BIT_4(A) ((A) & 0x00000010)
+#define BIT_5(A) ((A) & 0x00000020)
+#define BIT_6(A) ((A) & 0x00000040)
+#define BIT_7(A) ((A) & 0x00000080)
+#define BIT_8(A) ((A) & 0x00000100)
+#define BIT_9(A) ((A) & 0x00000200)
+#define BIT_A(A) ((A) & 0x00000400)
+#define BIT_B(A) ((A) & 0x00000800)
+#define BIT_C(A) ((A) & 0x00001000)
+#define BIT_D(A) ((A) & 0x00002000)
+#define BIT_E(A) ((A) & 0x00004000)
+#define BIT_F(A) ((A) & 0x00008000)
+#define BIT_10(A) ((A) & 0x00010000)
+#define BIT_11(A) ((A) & 0x00020000)
+#define BIT_12(A) ((A) & 0x00040000)
+#define BIT_13(A) ((A) & 0x00080000)
+#define BIT_14(A) ((A) & 0x00100000)
+#define BIT_15(A) ((A) & 0x00200000)
+#define BIT_16(A) ((A) & 0x00400000)
+#define BIT_17(A) ((A) & 0x00800000)
+#define BIT_18(A) ((A) & 0x01000000)
+#define BIT_19(A) ((A) & 0x02000000)
+#define BIT_1A(A) ((A) & 0x04000000)
+#define BIT_1B(A) ((A) & 0x08000000)
+#define BIT_1C(A) ((A) & 0x10000000)
+#define BIT_1D(A) ((A) & 0x20000000)
+#define BIT_1E(A) ((A) & 0x40000000)
+#define BIT_1F(A) ((A) & 0x80000000)
+
+/* These are the CPU types understood by this disassembler */
+#define TYPE_68000 1
+#define TYPE_68008 2
+#define TYPE_68010 4
+#define TYPE_68020 8
+#define TYPE_68030 16
+#define TYPE_68040 32
+
+#define M68000_ONLY (TYPE_68000 | TYPE_68008)
+
+#define M68010_ONLY TYPE_68010
+#define M68010_LESS (TYPE_68000 | TYPE_68008 | TYPE_68010)
+#define M68010_PLUS (TYPE_68010 | TYPE_68020 | TYPE_68030 | TYPE_68040)
+
+#define M68020_ONLY TYPE_68020
+#define M68020_LESS (TYPE_68010 | TYPE_68020)
+#define M68020_PLUS (TYPE_68020 | TYPE_68030 | TYPE_68040)
+
+#define M68030_ONLY TYPE_68030
+#define M68030_LESS (TYPE_68010 | TYPE_68020 | TYPE_68030)
+#define M68030_PLUS (TYPE_68030 | TYPE_68040)
+
+#define M68040_PLUS TYPE_68040
+
+
+/* Extension word formats */
+#define EXT_8BIT_DISPLACEMENT(A) ((A)&0xff)
+#define EXT_FULL(A) BIT_8(A)
+#define EXT_EFFECTIVE_ZERO(A) (((A)&0xe4) == 0xc4 || ((A)&0xe2) == 0xc0)
+#define EXT_BASE_REGISTER_PRESENT(A) (!BIT_7(A))
+#define EXT_INDEX_REGISTER_PRESENT(A) (!BIT_6(A))
+#define EXT_INDEX_REGISTER(A) (((A)>>12)&7)
+#define EXT_INDEX_PRE_POST(A) (EXT_INDEX_PRESENT(A) && (A)&3)
+#define EXT_INDEX_PRE(A) (EXT_INDEX_PRESENT(A) && ((A)&7) < 4 && ((A)&7) != 0)
+#define EXT_INDEX_POST(A) (EXT_INDEX_PRESENT(A) && ((A)&7) > 4)
+#define EXT_INDEX_SCALE(A) (((A)>>9)&3)
+#define EXT_INDEX_LONG(A) BIT_B(A)
+#define EXT_INDEX_AR(A) BIT_F(A)
+#define EXT_BASE_DISPLACEMENT_PRESENT(A) (((A)&0x30) > 0x10)
+#define EXT_BASE_DISPLACEMENT_WORD(A) (((A)&0x30) == 0x20)
+#define EXT_BASE_DISPLACEMENT_LONG(A) (((A)&0x30) == 0x30)
+#define EXT_OUTER_DISPLACEMENT_PRESENT(A) (((A)&3) > 1 && ((A)&0x47) < 0x44)
+#define EXT_OUTER_DISPLACEMENT_WORD(A) (((A)&3) == 2 && ((A)&0x47) < 0x44)
+#define EXT_OUTER_DISPLACEMENT_LONG(A) (((A)&3) == 3 && ((A)&0x47) < 0x44)
+
+
+/* Opcode flags */
+#if M68K_COMPILE_FOR_MAME == OPT_ON
+#define SET_OPCODE_FLAGS(x) g_opcode_type = x;
+#define COMBINE_OPCODE_FLAGS(x) ((x) | g_opcode_type | DASMFLAG_SUPPORTED)
+#else
+#define SET_OPCODE_FLAGS(x)
+#define COMBINE_OPCODE_FLAGS(X) (x)
+#endif
+
+
+/* ======================================================================== */
+/* =============================== PROTOTYPES ============================= */
+/* ======================================================================== */
+
+/* Read data at the PC and increment PC */
+uint read_imm_8(void);
+uint read_imm_16(void);
+uint read_imm_32(void);
+
+/* Read data at the PC but don't imcrement the PC */
+uint peek_imm_8(void);
+uint peek_imm_16(void);
+uint peek_imm_32(void);
+
+/* make signed integers 100% portably */
+static int make_int_8(int value);
+static int make_int_16(int value);
+
+/* make a string of a hex value */
+static char* make_signed_hex_str_8(uint val);
+static char* make_signed_hex_str_16(uint val);
+static char* make_signed_hex_str_32(uint val);
+
+/* make string of ea mode */
+static char* get_ea_mode_str(uint instruction, uint size);
+
+char* get_ea_mode_str_8(uint instruction);
+char* get_ea_mode_str_16(uint instruction);
+char* get_ea_mode_str_32(uint instruction);
+
+/* make string of immediate value */
+static char* get_imm_str_s(uint size);
+static char* get_imm_str_u(uint size);
+
+char* get_imm_str_s8(void);
+char* get_imm_str_s16(void);
+char* get_imm_str_s32(void);
+
+/* Stuff to build the opcode handler jump table */
+static void build_opcode_table(void);
+static int valid_ea(uint opcode, uint mask);
+static int DECL_SPEC compare_nof_true_bits(const void *aptr, const void *bptr);
+
+/* used to build opcode handler jump table */
+typedef struct
+{
+ void (*opcode_handler)(void); /* handler function */
+ uint mask; /* mask on opcode */
+ uint match; /* what to match after masking */
+ uint ea_mask; /* what ea modes are allowed */
+} opcode_struct;
+
+
+
+/* ======================================================================== */
+/* ================================= DATA ================================= */
+/* ======================================================================== */
+
+/* Opcode handler jump table */
+static void (*g_instruction_table[0x10000])(void);
+/* Flag if disassembler initialized */
+static int g_initialized = 0;
+
+/* Address mask to simulate address lines */
+static unsigned int g_address_mask = 0xffffffff;
+
+static char g_dasm_str[100]; /* string to hold disassembly */
+static char g_helper_str[100]; /* string to hold helpful info */
+static uint g_cpu_pc; /* program counter */
+static uint g_cpu_ir; /* instruction register */
+static uint g_cpu_type;
+static uint g_opcode_type;
+static const unsigned char* g_rawop;
+static uint g_rawbasepc;
+
+/* used by ops like asr, ror, addq, etc */
+static uint g_3bit_qdata_table[8] = {8, 1, 2, 3, 4, 5, 6, 7};
+
+static uint g_5bit_data_table[32] =
+{
+ 32, 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
+};
+
+static const char* g_cc[16] =
+{"t", "f", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le"};
+
+static const char* g_cpcc[64] =
+{/* 000 001 010 011 100 101 110 111 */
+ "f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or", /* 000 */
+ "un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t", /* 001 */
+ "sf", "seq", "gt", "ge", "lt", "le", "gl" "gle", /* 010 */
+ "ngle", "ngl", "nle", "nlt", "nge", "ngt", "sne", "st", /* 011 */
+ "?", "?", "?", "?", "?", "?", "?", "?", /* 100 */
+ "?", "?", "?", "?", "?", "?", "?", "?", /* 101 */
+ "?", "?", "?", "?", "?", "?", "?", "?", /* 110 */
+ "?", "?", "?", "?", "?", "?", "?", "?" /* 111 */
+};
+
+
+/* ======================================================================== */
+/* =========================== UTILITY FUNCTIONS ========================== */
+/* ======================================================================== */
+
+#define LIMIT_CPU_TYPES(ALLOWED_CPU_TYPES) \
+ if(!(g_cpu_type & ALLOWED_CPU_TYPES)) \
+ { \
+ if((g_cpu_ir & 0xf000) == 0xf000) \
+ d68000_1111(); \
+ else d68000_illegal(); \
+ return; \
+ }
+
+static uint dasm_read_imm_8(uint advance)
+{
+ uint result;
+ if (g_rawop)
+ result = g_rawop[g_cpu_pc + 1 - g_rawbasepc];
+ else
+ result = m68k_read_disassembler_16(g_cpu_pc & g_address_mask) & 0xff;
+ g_cpu_pc += advance;
+ return result;
+}
+
+static uint dasm_read_imm_16(uint advance)
+{
+ uint result;
+ if (g_rawop)
+ result = (g_rawop[g_cpu_pc + 0 - g_rawbasepc] << 8) |
+ g_rawop[g_cpu_pc + 1 - g_rawbasepc];
+ else
+ result = m68k_read_disassembler_16(g_cpu_pc & g_address_mask) & 0xff;
+ g_cpu_pc += advance;
+ return result;
+}
+
+static uint dasm_read_imm_32(uint advance)
+{
+ uint result;
+ if (g_rawop)
+ result = (g_rawop[g_cpu_pc + 0 - g_rawbasepc] << 24) |
+ (g_rawop[g_cpu_pc + 1 - g_rawbasepc] << 16) |
+ (g_rawop[g_cpu_pc + 2 - g_rawbasepc] << 8) |
+ g_rawop[g_cpu_pc + 3 - g_rawbasepc];
+ else
+ result = m68k_read_disassembler_32(g_cpu_pc & g_address_mask) & 0xff;
+ g_cpu_pc += advance;
+ return result;
+}
+
+#define read_imm_8() dasm_read_imm_8(2)
+#define read_imm_16() dasm_read_imm_16(2)
+#define read_imm_32() dasm_read_imm_32(4)
+
+#define peek_imm_8() dasm_read_imm_8(0)
+#define peek_imm_16() dasm_read_imm_16(0)
+#define peek_imm_32() dasm_read_imm_32(0)
+
+/* Fake a split interface */
+#define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0)
+#define get_ea_mode_str_16(instruction) get_ea_mode_str(instruction, 1)
+#define get_ea_mode_str_32(instruction) get_ea_mode_str(instruction, 2)
+
+#define get_imm_str_s8() get_imm_str_s(0)
+#define get_imm_str_s16() get_imm_str_s(1)
+#define get_imm_str_s32() get_imm_str_s(2)
+
+#define get_imm_str_u8() get_imm_str_u(0)
+#define get_imm_str_u16() get_imm_str_u(1)
+#define get_imm_str_u32() get_imm_str_u(2)
+
+
+/* 100% portable signed int generators */
+static int make_int_8(int value)
+{
+ return (value & 0x80) ? value | ~0xff : value & 0xff;
+}
+
+static int make_int_16(int value)
+{
+ return (value & 0x8000) ? value | ~0xffff : value & 0xffff;
+}
+
+
+/* Get string representation of hex values */
+static char* make_signed_hex_str_8(uint val)
+{
+ static char str[20];
+
+ val &= 0xff;
+
+ if(val == 0x80)
+ sprintf(str, "-$80");
+ else if(val & 0x80)
+ sprintf(str, "-$%x", (0-val) & 0x7f);
+ else
+ sprintf(str, "$%x", val & 0x7f);
+
+ return str;
+}
+
+static char* make_signed_hex_str_16(uint val)
+{
+ static char str[20];
+
+ val &= 0xffff;
+
+ if(val == 0x8000)
+ sprintf(str, "-$8000");
+ else if(val & 0x8000)
+ sprintf(str, "-$%x", (0-val) & 0x7fff);
+ else
+ sprintf(str, "$%x", val & 0x7fff);
+
+ return str;
+}
+
+static char* make_signed_hex_str_32(uint val)
+{
+ static char str[20];
+
+ val &= 0xffffffff;
+
+ if(val == 0x80000000)
+ sprintf(str, "-$80000000");
+ else if(val & 0x80000000)
+ sprintf(str, "-$%x", (0-val) & 0x7fffffff);
+ else
+ sprintf(str, "$%x", val & 0x7fffffff);
+
+ return str;
+}
+
+
+/* make string of immediate value */
+static char* get_imm_str_s(uint size)
+{
+ static char str[15];
+ if(size == 0)
+ sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
+ else if(size == 1)
+ sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
+ else
+ sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
+ return str;
+}
+
+static char* get_imm_str_u(uint size)
+{
+ static char str[15];
+ if(size == 0)
+ sprintf(str, "#$%x", read_imm_8() & 0xff);
+ else if(size == 1)
+ sprintf(str, "#$%x", read_imm_16() & 0xffff);
+ else
+ sprintf(str, "#$%x", read_imm_32() & 0xffffffff);
+ return str;
+}
+
+/* Make string of effective address mode */
+static char* get_ea_mode_str(uint instruction, uint size)
+{
+ static char b1[64];
+ static char b2[64];
+ static char* mode = b2;
+ uint extension;
+ uint base;
+ uint outer;
+ char base_reg[4];
+ char index_reg[8];
+ uint preindex;
+ uint postindex;
+ uint comma = 0;
+ uint temp_value;
+ char invalid_mode = 0;
+
+ /* Switch buffers so we don't clobber on a double-call to this function */
+ mode = mode == b1 ? b2 : b1;
+
+ switch(instruction & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ /* data register direct */
+ sprintf(mode, "D%d", instruction&7);
+ break;
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ /* address register direct */
+ sprintf(mode, "A%d", instruction&7);
+ break;
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ /* address register indirect */
+ sprintf(mode, "(A%d)", instruction&7);
+ break;
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ /* address register indirect with postincrement */
+ sprintf(mode, "(A%d)+", instruction&7);
+ break;
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+ /* address register indirect with predecrement */
+ sprintf(mode, "-(A%d)", instruction&7);
+ break;
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ /* address register indirect with displacement*/
+ sprintf(mode, "(%s,A%d)", make_signed_hex_str_16(read_imm_16()), instruction&7);
+ break;
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ /* address register indirect with index */
+ extension = read_imm_16();
+
+ if((g_cpu_type & M68010_LESS) && EXT_INDEX_SCALE(extension))
+ {
+ invalid_mode = 1;
+ break;
+ }
+
+ if(EXT_FULL(extension))
+ {
+ if(g_cpu_type & M68010_LESS)
+ {
+ invalid_mode = 1;
+ break;
+ }
+
+ if(EXT_EFFECTIVE_ZERO(extension))
+ {
+ strcpy(mode, "0");
+ break;
+ }
+
+ base = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0;
+ outer = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0;
+ if(EXT_BASE_REGISTER_PRESENT(extension))
+ sprintf(base_reg, "A%d", instruction&7);
+ else
+ *base_reg = 0;
+ if(EXT_INDEX_REGISTER_PRESENT(extension))
+ {
+ sprintf(index_reg, "%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w');
+ if(EXT_INDEX_SCALE(extension))
+ sprintf(index_reg+strlen(index_reg), "*%d", 1 << EXT_INDEX_SCALE(extension));
+ }
+ else
+ *index_reg = 0;
+ preindex = (extension&7) > 0 && (extension&7) < 4;
+ postindex = (extension&7) > 4;
+
+ strcpy(mode, "(");
+ if(preindex || postindex)
+ strcat(mode, "[");
+ if(base)
+ {
+ strcat(mode, make_signed_hex_str_16(base));
+ comma = 1;
+ }
+ if(*base_reg)
+ {
+ if(comma)
+ strcat(mode, ",");
+ strcat(mode, base_reg);
+ comma = 1;
+ }
+ if(postindex)
+ {
+ strcat(mode, "]");
+ comma = 1;
+ }
+ if(*index_reg)
+ {
+ if(comma)
+ strcat(mode, ",");
+ strcat(mode, index_reg);
+ comma = 1;
+ }
+ if(preindex)
+ {
+ strcat(mode, "]");
+ comma = 1;
+ }
+ if(outer)
+ {
+ if(comma)
+ strcat(mode, ",");
+ strcat(mode, make_signed_hex_str_16(outer));
+ }
+ strcat(mode, ")");
+ break;
+ }
+
+ if(EXT_8BIT_DISPLACEMENT(extension) == 0)
+ sprintf(mode, "(A%d,%c%d.%c", instruction&7, EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w');
+ else
+ sprintf(mode, "(%s,A%d,%c%d.%c", make_signed_hex_str_8(extension), instruction&7, EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w');
+ if(EXT_INDEX_SCALE(extension))
+ sprintf(mode+strlen(mode), "*%d", 1 << EXT_INDEX_SCALE(extension));
+ strcat(mode, ")");
+ break;
+ case 0x38:
+ /* absolute short address */
+ sprintf(mode, "$%x.w", read_imm_16());
+ break;
+ case 0x39:
+ /* absolute long address */
+ sprintf(mode, "$%x.l", read_imm_32());
+ break;
+ case 0x3a:
+ /* program counter with displacement */
+ temp_value = read_imm_16();
+ sprintf(mode, "(%s,PC)", make_signed_hex_str_16(temp_value));
+ sprintf(g_helper_str, "; ($%x)", (make_int_16(temp_value) + g_cpu_pc-2) & 0xffffffff);
+ break;
+ case 0x3b:
+ /* program counter with index */
+ extension = read_imm_16();
+
+ if((g_cpu_type & M68010_LESS) && EXT_INDEX_SCALE(extension))
+ {
+ invalid_mode = 1;
+ break;
+ }
+
+ if(EXT_FULL(extension))
+ {
+ if(g_cpu_type & M68010_LESS)
+ {
+ invalid_mode = 1;
+ break;
+ }
+
+ if(EXT_EFFECTIVE_ZERO(extension))
+ {
+ strcpy(mode, "0");
+ break;
+ }
+ base = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0;
+ outer = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0;
+ if(EXT_BASE_REGISTER_PRESENT(extension))
+ strcpy(base_reg, "PC");
+ else
+ *base_reg = 0;
+ if(EXT_INDEX_REGISTER_PRESENT(extension))
+ {
+ sprintf(index_reg, "%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w');
+ if(EXT_INDEX_SCALE(extension))
+ sprintf(index_reg+strlen(index_reg), "*%d", 1 << EXT_INDEX_SCALE(extension));
+ }
+ else
+ *index_reg = 0;
+ preindex = (extension&7) > 0 && (extension&7) < 4;
+ postindex = (extension&7) > 4;
+
+ strcpy(mode, "(");
+ if(preindex || postindex)
+ strcat(mode, "[");
+ if(base)
+ {
+ strcat(mode, make_signed_hex_str_16(base));
+ comma = 1;
+ }
+ if(*base_reg)
+ {
+ if(comma)
+ strcat(mode, ",");
+ strcat(mode, base_reg);
+ comma = 1;
+ }
+ if(postindex)
+ {
+ strcat(mode, "]");
+ comma = 1;
+ }
+ if(*index_reg)
+ {
+ if(comma)
+ strcat(mode, ",");
+ strcat(mode, index_reg);
+ comma = 1;
+ }
+ if(preindex)
+ {
+ strcat(mode, "]");
+ comma = 1;
+ }
+ if(outer)
+ {
+ if(comma)
+ strcat(mode, ",");
+ strcat(mode, make_signed_hex_str_16(outer));
+ }
+ strcat(mode, ")");
+ break;
+ }
+
+ if(EXT_8BIT_DISPLACEMENT(extension) == 0)
+ sprintf(mode, "(PC,%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w');
+ else
+ sprintf(mode, "(%s,PC,%c%d.%c", make_signed_hex_str_8(extension), EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w');
+ if(EXT_INDEX_SCALE(extension))
+ sprintf(mode+strlen(mode), "*%d", 1 << EXT_INDEX_SCALE(extension));
+ strcat(mode, ")");
+ break;
+ case 0x3c:
+ /* Immediate */
+ sprintf(mode, "%s", get_imm_str_u(size));
+ break;
+ default:
+ invalid_mode = 1;
+ }
+
+ if(invalid_mode)
+ sprintf(mode, "INVALID %x", instruction & 0x3f);
+
+ return mode;
+}
+
+
+
+/* ======================================================================== */
+/* ========================= INSTRUCTION HANDLERS ========================= */
+/* ======================================================================== */
+/* Instruction handler function names follow this convention:
+ *
+ * d68000_NAME_EXTENSIONS(void)
+ * where NAME is the name of the opcode it handles and EXTENSIONS are any
+ * extensions for special instances of that opcode.
+ *
+ * Examples:
+ * d68000_add_er_8(): add opcode, from effective address to register,
+ * size = byte
+ *
+ * d68000_asr_s_8(): arithmetic shift right, static count, size = byte
+ *
+ *
+ * Common extensions:
+ * 8 : size = byte
+ * 16 : size = word
+ * 32 : size = long
+ * rr : register to register
+ * mm : memory to memory
+ * r : register
+ * s : static
+ * er : effective address -> register
+ * re : register -> effective address
+ * ea : using effective address mode of operation
+ * d : data register direct
+ * a : address register direct
+ * ai : address register indirect
+ * pi : address register indirect with postincrement
+ * pd : address register indirect with predecrement
+ * di : address register indirect with displacement
+ * ix : address register indirect with index
+ * aw : absolute word
+ * al : absolute long
+ */
+
+static void d68000_illegal(void)
+{
+ sprintf(g_dasm_str, "dc.w $%04x; ILLEGAL", g_cpu_ir);
+}
+
+static void d68000_1010(void)
+{
+ sprintf(g_dasm_str, "dc.w $%04x; opcode 1010", g_cpu_ir);
+}
+
+
+static void d68000_1111(void)
+{
+ sprintf(g_dasm_str, "dc.w $%04x; opcode 1111", g_cpu_ir);
+}
+
+
+static void d68000_abcd_rr(void)
+{
+ sprintf(g_dasm_str, "abcd D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+
+static void d68000_abcd_mm(void)
+{
+ sprintf(g_dasm_str, "abcd -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_add_er_8(void)
+{
+ sprintf(g_dasm_str, "add.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+
+static void d68000_add_er_16(void)
+{
+ sprintf(g_dasm_str, "add.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_add_er_32(void)
+{
+ sprintf(g_dasm_str, "add.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_add_re_8(void)
+{
+ sprintf(g_dasm_str, "add.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_add_re_16(void)
+{
+ sprintf(g_dasm_str, "add.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_add_re_32(void)
+{
+ sprintf(g_dasm_str, "add.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_adda_16(void)
+{
+ sprintf(g_dasm_str, "adda.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_adda_32(void)
+{
+ sprintf(g_dasm_str, "adda.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_addi_8(void)
+{
+ char* str = get_imm_str_s8();
+ sprintf(g_dasm_str, "addi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_addi_16(void)
+{
+ char* str = get_imm_str_s16();
+ sprintf(g_dasm_str, "addi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_addi_32(void)
+{
+ char* str = get_imm_str_s32();
+ sprintf(g_dasm_str, "addi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_addq_8(void)
+{
+ sprintf(g_dasm_str, "addq.b #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_addq_16(void)
+{
+ sprintf(g_dasm_str, "addq.w #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_addq_32(void)
+{
+ sprintf(g_dasm_str, "addq.l #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_addx_rr_8(void)
+{
+ sprintf(g_dasm_str, "addx.b D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_addx_rr_16(void)
+{
+ sprintf(g_dasm_str, "addx.w D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_addx_rr_32(void)
+{
+ sprintf(g_dasm_str, "addx.l D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_addx_mm_8(void)
+{
+ sprintf(g_dasm_str, "addx.b -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_addx_mm_16(void)
+{
+ sprintf(g_dasm_str, "addx.w -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_addx_mm_32(void)
+{
+ sprintf(g_dasm_str, "addx.l -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_and_er_8(void)
+{
+ sprintf(g_dasm_str, "and.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_and_er_16(void)
+{
+ sprintf(g_dasm_str, "and.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_and_er_32(void)
+{
+ sprintf(g_dasm_str, "and.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_and_re_8(void)
+{
+ sprintf(g_dasm_str, "and.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_and_re_16(void)
+{
+ sprintf(g_dasm_str, "and.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_and_re_32(void)
+{
+ sprintf(g_dasm_str, "and.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_andi_8(void)
+{
+ char* str = get_imm_str_u8();
+ sprintf(g_dasm_str, "andi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_andi_16(void)
+{
+ char* str = get_imm_str_u16();
+ sprintf(g_dasm_str, "andi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_andi_32(void)
+{
+ char* str = get_imm_str_u32();
+ sprintf(g_dasm_str, "andi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_andi_to_ccr(void)
+{
+ sprintf(g_dasm_str, "andi %s, CCR", get_imm_str_u8());
+}
+
+static void d68000_andi_to_sr(void)
+{
+ sprintf(g_dasm_str, "andi %s, SR", get_imm_str_u16());
+}
+
+static void d68000_asr_s_8(void)
+{
+ sprintf(g_dasm_str, "asr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_asr_s_16(void)
+{
+ sprintf(g_dasm_str, "asr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_asr_s_32(void)
+{
+ sprintf(g_dasm_str, "asr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_asr_r_8(void)
+{
+ sprintf(g_dasm_str, "asr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_asr_r_16(void)
+{
+ sprintf(g_dasm_str, "asr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_asr_r_32(void)
+{
+ sprintf(g_dasm_str, "asr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_asr_ea(void)
+{
+ sprintf(g_dasm_str, "asr.w %s", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_asl_s_8(void)
+{
+ sprintf(g_dasm_str, "asl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_asl_s_16(void)
+{
+ sprintf(g_dasm_str, "asl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_asl_s_32(void)
+{
+ sprintf(g_dasm_str, "asl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_asl_r_8(void)
+{
+ sprintf(g_dasm_str, "asl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_asl_r_16(void)
+{
+ sprintf(g_dasm_str, "asl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_asl_r_32(void)
+{
+ sprintf(g_dasm_str, "asl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_asl_ea(void)
+{
+ sprintf(g_dasm_str, "asl.w %s", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_bcc_8(void)
+{
+ uint temp_pc = g_cpu_pc;
+ sprintf(g_dasm_str, "b%-2s $%x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_8(g_cpu_ir));
+}
+
+static void d68000_bcc_16(void)
+{
+ uint temp_pc = g_cpu_pc;
+ sprintf(g_dasm_str, "b%-2s $%x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_16(read_imm_16()));
+}
+
+static void d68020_bcc_32(void)
+{
+ uint temp_pc = g_cpu_pc;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "b%-2s $%x; (2+)", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + read_imm_32());
+}
+
+static void d68000_bchg_r(void)
+{
+ sprintf(g_dasm_str, "bchg D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_bchg_s(void)
+{
+ char* str = get_imm_str_u8();
+ sprintf(g_dasm_str, "bchg %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_bclr_r(void)
+{
+ sprintf(g_dasm_str, "bclr D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_bclr_s(void)
+{
+ char* str = get_imm_str_u8();
+ sprintf(g_dasm_str, "bclr %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68010_bkpt(void)
+{
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ sprintf(g_dasm_str, "bkpt #%d; (1+)", g_cpu_ir&7);
+}
+
+static void d68020_bfchg(void)
+{
+ uint extension;
+ char offset[3];
+ char width[3];
+
+ LIMIT_CPU_TYPES(M68020_PLUS);
+
+ extension = read_imm_16();
+
+ if(BIT_B(extension))
+ sprintf(offset, "D%d", (extension>>6)&7);
+ else
+ sprintf(offset, "%d", (extension>>6)&31);
+ if(BIT_5(extension))
+ sprintf(width, "D%d", extension&7);
+ else
+ sprintf(width, "%d", g_5bit_data_table[extension&31]);
+ sprintf(g_dasm_str, "bfchg %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width);
+}
+
+static void d68020_bfclr(void)
+{
+ uint extension;
+ char offset[3];
+ char width[3];
+
+ LIMIT_CPU_TYPES(M68020_PLUS);
+
+ extension = read_imm_16();
+
+ if(BIT_B(extension))
+ sprintf(offset, "D%d", (extension>>6)&7);
+ else
+ sprintf(offset, "%d", (extension>>6)&31);
+ if(BIT_5(extension))
+ sprintf(width, "D%d", extension&7);
+ else
+ sprintf(width, "%d", g_5bit_data_table[extension&31]);
+ sprintf(g_dasm_str, "bfclr %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width);
+}
+
+static void d68020_bfexts(void)
+{
+ uint extension;
+ char offset[3];
+ char width[3];
+
+ LIMIT_CPU_TYPES(M68020_PLUS);
+
+ extension = read_imm_16();
+
+ if(BIT_B(extension))
+ sprintf(offset, "D%d", (extension>>6)&7);
+ else
+ sprintf(offset, "%d", (extension>>6)&31);
+ if(BIT_5(extension))
+ sprintf(width, "D%d", extension&7);
+ else
+ sprintf(width, "%d", g_5bit_data_table[extension&31]);
+ sprintf(g_dasm_str, "bfexts D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width);
+}
+
+static void d68020_bfextu(void)
+{
+ uint extension;
+ char offset[3];
+ char width[3];
+
+ LIMIT_CPU_TYPES(M68020_PLUS);
+
+ extension = read_imm_16();
+
+ if(BIT_B(extension))
+ sprintf(offset, "D%d", (extension>>6)&7);
+ else
+ sprintf(offset, "%d", (extension>>6)&31);
+ if(BIT_5(extension))
+ sprintf(width, "D%d", extension&7);
+ else
+ sprintf(width, "%d", g_5bit_data_table[extension&31]);
+ sprintf(g_dasm_str, "bfextu D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width);
+}
+
+static void d68020_bfffo(void)
+{
+ uint extension;
+ char offset[3];
+ char width[3];
+
+ LIMIT_CPU_TYPES(M68020_PLUS);
+
+ extension = read_imm_16();
+
+ if(BIT_B(extension))
+ sprintf(offset, "D%d", (extension>>6)&7);
+ else
+ sprintf(offset, "%d", (extension>>6)&31);
+ if(BIT_5(extension))
+ sprintf(width, "D%d", extension&7);
+ else
+ sprintf(width, "%d", g_5bit_data_table[extension&31]);
+ sprintf(g_dasm_str, "bfffo D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width);
+}
+
+static void d68020_bfins(void)
+{
+ uint extension;
+ char offset[3];
+ char width[3];
+
+ LIMIT_CPU_TYPES(M68020_PLUS);
+
+ extension = read_imm_16();
+
+ if(BIT_B(extension))
+ sprintf(offset, "D%d", (extension>>6)&7);
+ else
+ sprintf(offset, "%d", (extension>>6)&31);
+ if(BIT_5(extension))
+ sprintf(width, "D%d", extension&7);
+ else
+ sprintf(width, "%d", g_5bit_data_table[extension&31]);
+ sprintf(g_dasm_str, "bfins D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width);
+}
+
+static void d68020_bfset(void)
+{
+ uint extension;
+ char offset[3];
+ char width[3];
+
+ LIMIT_CPU_TYPES(M68020_PLUS);
+
+ extension = read_imm_16();
+
+ if(BIT_B(extension))
+ sprintf(offset, "D%d", (extension>>6)&7);
+ else
+ sprintf(offset, "%d", (extension>>6)&31);
+ if(BIT_5(extension))
+ sprintf(width, "D%d", extension&7);
+ else
+ sprintf(width, "%d", g_5bit_data_table[extension&31]);
+ sprintf(g_dasm_str, "bfset %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width);
+}
+
+static void d68020_bftst(void)
+{
+ uint extension;
+ char offset[3];
+ char width[3];
+
+ LIMIT_CPU_TYPES(M68020_PLUS);
+
+ extension = read_imm_16();
+
+ if(BIT_B(extension))
+ sprintf(offset, "D%d", (extension>>6)&7);
+ else
+ sprintf(offset, "%d", (extension>>6)&31);
+ if(BIT_5(extension))
+ sprintf(width, "D%d", extension&7);
+ else
+ sprintf(width, "%d", g_5bit_data_table[extension&31]);
+ sprintf(g_dasm_str, "bftst %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width);
+}
+
+static void d68000_bra_8(void)
+{
+ uint temp_pc = g_cpu_pc;
+ sprintf(g_dasm_str, "bra $%x", temp_pc + make_int_8(g_cpu_ir));
+}
+
+static void d68000_bra_16(void)
+{
+ uint temp_pc = g_cpu_pc;
+ sprintf(g_dasm_str, "bra $%x", temp_pc + make_int_16(read_imm_16()));
+}
+
+static void d68020_bra_32(void)
+{
+ uint temp_pc = g_cpu_pc;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "bra $%x; (2+)", temp_pc + read_imm_32());
+}
+
+static void d68000_bset_r(void)
+{
+ sprintf(g_dasm_str, "bset D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_bset_s(void)
+{
+ char* str = get_imm_str_u8();
+ sprintf(g_dasm_str, "bset %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_bsr_8(void)
+{
+ uint temp_pc = g_cpu_pc;
+ sprintf(g_dasm_str, "bsr $%x", temp_pc + make_int_8(g_cpu_ir));
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68000_bsr_16(void)
+{
+ uint temp_pc = g_cpu_pc;
+ sprintf(g_dasm_str, "bsr $%x", temp_pc + make_int_16(read_imm_16()));
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68020_bsr_32(void)
+{
+ uint temp_pc = g_cpu_pc;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "bsr $%x; (2+)", temp_pc + read_imm_32());
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68000_btst_r(void)
+{
+ sprintf(g_dasm_str, "btst D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_btst_s(void)
+{
+ char* str = get_imm_str_u8();
+ sprintf(g_dasm_str, "btst %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_callm(void)
+{
+ char* str;
+ LIMIT_CPU_TYPES(M68020_ONLY);
+ str = get_imm_str_u8();
+
+ sprintf(g_dasm_str, "callm %s, %s; (2)", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_cas_8(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+ sprintf(g_dasm_str, "cas.b D%d, D%d, %s; (2+)", extension&7, (extension>>8)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_cas_16(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+ sprintf(g_dasm_str, "cas.w D%d, D%d, %s; (2+)", extension&7, (extension>>8)&7, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68020_cas_32(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+ sprintf(g_dasm_str, "cas.l D%d, D%d, %s; (2+)", extension&7, (extension>>8)&7, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68020_cas2_16(void)
+{
+/* CAS2 Dc1:Dc2,Du1:Dc2:(Rn1):(Rn2)
+f e d c b a 9 8 7 6 5 4 3 2 1 0
+ DARn1 0 0 0 Du1 0 0 0 Dc1
+ DARn2 0 0 0 Du2 0 0 0 Dc2
+*/
+
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_32();
+ sprintf(g_dasm_str, "cas2.w D%d:D%d:D%d:D%d, (%c%d):(%c%d); (2+)",
+ (extension>>16)&7, extension&7, (extension>>22)&7, (extension>>6)&7,
+ BIT_1F(extension) ? 'A' : 'D', (extension>>28)&7,
+ BIT_F(extension) ? 'A' : 'D', (extension>>12)&7);
+}
+
+static void d68020_cas2_32(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_32();
+ sprintf(g_dasm_str, "cas2.l D%d:D%d:D%d:D%d, (%c%d):(%c%d); (2+)",
+ (extension>>16)&7, extension&7, (extension>>22)&7, (extension>>6)&7,
+ BIT_1F(extension) ? 'A' : 'D', (extension>>28)&7,
+ BIT_F(extension) ? 'A' : 'D', (extension>>12)&7);
+}
+
+static void d68000_chk_16(void)
+{
+ sprintf(g_dasm_str, "chk.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68020_chk_32(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "chk.l %s, D%d; (2+)", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68020_chk2_cmp2_8(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+ sprintf(g_dasm_str, "%s.b %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_8(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7);
+}
+
+static void d68020_chk2_cmp2_16(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+ sprintf(g_dasm_str, "%s.w %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_16(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7);
+}
+
+static void d68020_chk2_cmp2_32(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+ sprintf(g_dasm_str, "%s.l %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_32(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7);
+}
+
+static void d68040_cinv(void)
+{
+ LIMIT_CPU_TYPES(M68040_PLUS);
+ switch((g_cpu_ir>>3)&3)
+ {
+ case 0:
+ sprintf(g_dasm_str, "cinv (illegal scope); (4)");
+ break;
+ case 1:
+ sprintf(g_dasm_str, "cinvl %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7);
+ break;
+ case 2:
+ sprintf(g_dasm_str, "cinvp %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7);
+ break;
+ case 3:
+ sprintf(g_dasm_str, "cinva %d; (4)", (g_cpu_ir>>6)&3);
+ break;
+ }
+}
+
+static void d68000_clr_8(void)
+{
+ sprintf(g_dasm_str, "clr.b %s", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_clr_16(void)
+{
+ sprintf(g_dasm_str, "clr.w %s", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_clr_32(void)
+{
+ sprintf(g_dasm_str, "clr.l %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_cmp_8(void)
+{
+ sprintf(g_dasm_str, "cmp.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_cmp_16(void)
+{
+ sprintf(g_dasm_str, "cmp.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_cmp_32(void)
+{
+ sprintf(g_dasm_str, "cmp.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_cmpa_16(void)
+{
+ sprintf(g_dasm_str, "cmpa.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_cmpa_32(void)
+{
+ sprintf(g_dasm_str, "cmpa.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_cmpi_8(void)
+{
+ char* str = get_imm_str_s8();
+ sprintf(g_dasm_str, "cmpi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_cmpi_pcdi_8(void)
+{
+ char* str;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ str = get_imm_str_s8();
+ sprintf(g_dasm_str, "cmpi.b %s, %s; (2+)", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_cmpi_pcix_8(void)
+{
+ char* str;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ str = get_imm_str_s8();
+ sprintf(g_dasm_str, "cmpi.b %s, %s; (2+)", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_cmpi_16(void)
+{
+ char* str;
+ str = get_imm_str_s16();
+ sprintf(g_dasm_str, "cmpi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68020_cmpi_pcdi_16(void)
+{
+ char* str;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ str = get_imm_str_s16();
+ sprintf(g_dasm_str, "cmpi.w %s, %s; (2+)", str, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68020_cmpi_pcix_16(void)
+{
+ char* str;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ str = get_imm_str_s16();
+ sprintf(g_dasm_str, "cmpi.w %s, %s; (2+)", str, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_cmpi_32(void)
+{
+ char* str;
+ str = get_imm_str_s32();
+ sprintf(g_dasm_str, "cmpi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68020_cmpi_pcdi_32(void)
+{
+ char* str;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ str = get_imm_str_s32();
+ sprintf(g_dasm_str, "cmpi.l %s, %s; (2+)", str, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68020_cmpi_pcix_32(void)
+{
+ char* str;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ str = get_imm_str_s32();
+ sprintf(g_dasm_str, "cmpi.l %s, %s; (2+)", str, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_cmpm_8(void)
+{
+ sprintf(g_dasm_str, "cmpm.b (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_cmpm_16(void)
+{
+ sprintf(g_dasm_str, "cmpm.w (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_cmpm_32(void)
+{
+ sprintf(g_dasm_str, "cmpm.l (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68020_cpbcc_16(void)
+{
+ uint extension;
+ uint new_pc = g_cpu_pc;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+ new_pc += make_int_16(read_imm_16());
+ sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension);
+}
+
+static void d68020_cpbcc_32(void)
+{
+ uint extension;
+ uint new_pc = g_cpu_pc;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+ new_pc += read_imm_32();
+ sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension);
+}
+
+static void d68020_cpdbcc(void)
+{
+ uint extension1;
+ uint extension2;
+ uint new_pc = g_cpu_pc;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension1 = read_imm_16();
+ extension2 = read_imm_16();
+ new_pc += make_int_16(read_imm_16());
+ sprintf(g_dasm_str, "%ddb%-4s D%d,%s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], g_cpu_ir&7, get_imm_str_s16(), new_pc, extension2);
+}
+
+static void d68020_cpgen(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "%dgen %s; (2-3)", (g_cpu_ir>>9)&7, get_imm_str_u32());
+}
+
+static void d68020_cprestore(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "%drestore %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_cpsave(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "%dsave %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_cpscc(void)
+{
+ uint extension1;
+ uint extension2;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension1 = read_imm_16();
+ extension2 = read_imm_16();
+ sprintf(g_dasm_str, "%ds%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_ea_mode_str_8(g_cpu_ir), extension2);
+}
+
+static void d68020_cptrapcc_0(void)
+{
+ uint extension1;
+ uint extension2;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension1 = read_imm_16();
+ extension2 = read_imm_16();
+ sprintf(g_dasm_str, "%dtrap%-4s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], extension2);
+}
+
+static void d68020_cptrapcc_16(void)
+{
+ uint extension1;
+ uint extension2;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension1 = read_imm_16();
+ extension2 = read_imm_16();
+ sprintf(g_dasm_str, "%dtrap%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_imm_str_u16(), extension2);
+}
+
+static void d68020_cptrapcc_32(void)
+{
+ uint extension1;
+ uint extension2;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension1 = read_imm_16();
+ extension2 = read_imm_16();
+ sprintf(g_dasm_str, "%dtrap%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_imm_str_u32(), extension2);
+}
+
+static void d68040_cpush(void)
+{
+ LIMIT_CPU_TYPES(M68040_PLUS);
+ switch((g_cpu_ir>>3)&3)
+ {
+ case 0:
+ sprintf(g_dasm_str, "cpush (illegal scope); (4)");
+ break;
+ case 1:
+ sprintf(g_dasm_str, "cpushl %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7);
+ break;
+ case 2:
+ sprintf(g_dasm_str, "cpushp %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7);
+ break;
+ case 3:
+ sprintf(g_dasm_str, "cpusha %d; (4)", (g_cpu_ir>>6)&3);
+ break;
+ }
+}
+
+static void d68000_dbra(void)
+{
+ uint temp_pc = g_cpu_pc;
+ sprintf(g_dasm_str, "dbra D%d, $%x", g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16()));
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68000_dbcc(void)
+{
+ uint temp_pc = g_cpu_pc;
+ sprintf(g_dasm_str, "db%-2s D%d, $%x", g_cc[(g_cpu_ir>>8)&0xf], g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16()));
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68000_divs(void)
+{
+ sprintf(g_dasm_str, "divs.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_divu(void)
+{
+ sprintf(g_dasm_str, "divu.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68020_divl(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+
+ if(BIT_A(extension))
+ sprintf(g_dasm_str, "div%c.l %s, D%d:D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7);
+ else if((extension&7) == ((extension>>12)&7))
+ sprintf(g_dasm_str, "div%c.l %s, D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), (extension>>12)&7);
+ else
+ sprintf(g_dasm_str, "div%cl.l %s, D%d:D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7);
+}
+
+static void d68000_eor_8(void)
+{
+ sprintf(g_dasm_str, "eor.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_eor_16(void)
+{
+ sprintf(g_dasm_str, "eor.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_eor_32(void)
+{
+ sprintf(g_dasm_str, "eor.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_eori_8(void)
+{
+ char* str = get_imm_str_u8();
+ sprintf(g_dasm_str, "eori.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_eori_16(void)
+{
+ char* str = get_imm_str_u16();
+ sprintf(g_dasm_str, "eori.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_eori_32(void)
+{
+ char* str = get_imm_str_u32();
+ sprintf(g_dasm_str, "eori.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_eori_to_ccr(void)
+{
+ sprintf(g_dasm_str, "eori %s, CCR", get_imm_str_u8());
+}
+
+static void d68000_eori_to_sr(void)
+{
+ sprintf(g_dasm_str, "eori %s, SR", get_imm_str_u16());
+}
+
+static void d68000_exg_dd(void)
+{
+ sprintf(g_dasm_str, "exg D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_exg_aa(void)
+{
+ sprintf(g_dasm_str, "exg A%d, A%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_exg_da(void)
+{
+ sprintf(g_dasm_str, "exg D%d, A%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_ext_16(void)
+{
+ sprintf(g_dasm_str, "ext.w D%d", g_cpu_ir&7);
+}
+
+static void d68000_ext_32(void)
+{
+ sprintf(g_dasm_str, "ext.l D%d", g_cpu_ir&7);
+}
+
+static void d68020_extb_32(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "extb.l D%d; (2+)", g_cpu_ir&7);
+}
+
+static void d68040_fpu(void)
+{
+ char float_data_format[8][3] =
+ {
+ ".l", ".s", ".x", ".p", ".w", ".d", ".b", ".?"
+ };
+
+ char mnemonic[40];
+ uint w2, src, dst_reg;
+ LIMIT_CPU_TYPES(M68040_PLUS);
+ w2 = read_imm_16();
+
+ src = (w2 >> 10) & 0x7;
+ dst_reg = (w2 >> 7) & 0x7;
+
+ switch ((w2 >> 13) & 0x7)
+ {
+ case 0x0:
+ case 0x2:
+ {
+ switch(w2 & 0x7f)
+ {
+ case 0x00: sprintf(mnemonic, "fmove"); break;
+ case 0x01: sprintf(mnemonic, "fint"); break;
+ case 0x02: sprintf(mnemonic, "fsinh"); break;
+ case 0x03: sprintf(mnemonic, "fintrz"); break;
+ case 0x04: sprintf(mnemonic, "fsqrt"); break;
+ case 0x06: sprintf(mnemonic, "flognp1"); break;
+ case 0x08: sprintf(mnemonic, "fetoxm1"); break;
+ case 0x09: sprintf(mnemonic, "ftanh1"); break;
+ case 0x0a: sprintf(mnemonic, "fatan"); break;
+ case 0x0c: sprintf(mnemonic, "fasin"); break;
+ case 0x0d: sprintf(mnemonic, "fatanh"); break;
+ case 0x0e: sprintf(mnemonic, "fsin"); break;
+ case 0x0f: sprintf(mnemonic, "ftan"); break;
+ case 0x10: sprintf(mnemonic, "fetox"); break;
+ case 0x11: sprintf(mnemonic, "ftwotox"); break;
+ case 0x12: sprintf(mnemonic, "ftentox"); break;
+ case 0x14: sprintf(mnemonic, "flogn"); break;
+ case 0x15: sprintf(mnemonic, "flog10"); break;
+ case 0x16: sprintf(mnemonic, "flog2"); break;
+ case 0x18: sprintf(mnemonic, "fabs"); break;
+ case 0x19: sprintf(mnemonic, "fcosh"); break;
+ case 0x1a: sprintf(mnemonic, "fneg"); break;
+ case 0x1c: sprintf(mnemonic, "facos"); break;
+ case 0x1d: sprintf(mnemonic, "fcos"); break;
+ case 0x1e: sprintf(mnemonic, "fgetexp"); break;
+ case 0x1f: sprintf(mnemonic, "fgetman"); break;
+ case 0x20: sprintf(mnemonic, "fdiv"); break;
+ case 0x21: sprintf(mnemonic, "fmod"); break;
+ case 0x22: sprintf(mnemonic, "fadd"); break;
+ case 0x23: sprintf(mnemonic, "fmul"); break;
+ case 0x24: sprintf(mnemonic, "fsgldiv"); break;
+ case 0x25: sprintf(mnemonic, "frem"); break;
+ case 0x26: sprintf(mnemonic, "fscale"); break;
+ case 0x27: sprintf(mnemonic, "fsglmul"); break;
+ case 0x28: sprintf(mnemonic, "fsub"); break;
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ sprintf(mnemonic, "fsincos"); break;
+ case 0x38: sprintf(mnemonic, "fcmp"); break;
+ case 0x3a: sprintf(mnemonic, "ftst"); break;
+ case 0x41: sprintf(mnemonic, "fssqrt"); break;
+ case 0x45: sprintf(mnemonic, "fdsqrt"); break;
+ case 0x58: sprintf(mnemonic, "fsabs"); break;
+ case 0x5a: sprintf(mnemonic, "fsneg"); break;
+ case 0x5c: sprintf(mnemonic, "fdabs"); break;
+ case 0x5e: sprintf(mnemonic, "fdneg"); break;
+ case 0x60: sprintf(mnemonic, "fsdiv"); break;
+ case 0x62: sprintf(mnemonic, "fsadd"); break;
+ case 0x63: sprintf(mnemonic, "fsmul"); break;
+ case 0x64: sprintf(mnemonic, "fddiv"); break;
+ case 0x66: sprintf(mnemonic, "fdadd"); break;
+ case 0x67: sprintf(mnemonic, "fdmul"); break;
+ case 0x68: sprintf(mnemonic, "fssub"); break;
+ case 0x6c: sprintf(mnemonic, "fdsub"); break;
+
+ default: sprintf(mnemonic, "FPU (?)"); break;
+ }
+
+ if (w2 & 0x4000)
+ {
+ sprintf(g_dasm_str, "%s%s %s, FP%d", mnemonic, float_data_format[src], get_ea_mode_str_32(g_cpu_ir), dst_reg);
+ }
+ else
+ {
+ sprintf(g_dasm_str, "%s.x FP%d, FP%d", mnemonic, src, dst_reg);
+ }
+ break;
+ }
+
+ case 0x3:
+ {
+ sprintf(g_dasm_str, "fmove /todo");
+ break;
+ }
+
+ case 0x4:
+ case 0x5:
+ {
+ sprintf(g_dasm_str, "fmove /todo");
+ break;
+ }
+
+ case 0x6:
+ case 0x7:
+ {
+ sprintf(g_dasm_str, "fmovem /todo");
+ break;
+ }
+
+ default:
+ {
+ sprintf(g_dasm_str, "FPU (?) ");
+ break;
+ }
+ }
+}
+
+static void d68000_jmp(void)
+{
+ sprintf(g_dasm_str, "jmp %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_jsr(void)
+{
+ sprintf(g_dasm_str, "jsr %s", get_ea_mode_str_32(g_cpu_ir));
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68000_lea(void)
+{
+ sprintf(g_dasm_str, "lea %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_link_16(void)
+{
+ sprintf(g_dasm_str, "link A%d, %s", g_cpu_ir&7, get_imm_str_s16());
+}
+
+static void d68020_link_32(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "link A%d, %s; (2+)", g_cpu_ir&7, get_imm_str_s32());
+}
+
+static void d68000_lsr_s_8(void)
+{
+ sprintf(g_dasm_str, "lsr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_lsr_s_16(void)
+{
+ sprintf(g_dasm_str, "lsr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_lsr_s_32(void)
+{
+ sprintf(g_dasm_str, "lsr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_lsr_r_8(void)
+{
+ sprintf(g_dasm_str, "lsr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_lsr_r_16(void)
+{
+ sprintf(g_dasm_str, "lsr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_lsr_r_32(void)
+{
+ sprintf(g_dasm_str, "lsr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_lsr_ea(void)
+{
+ sprintf(g_dasm_str, "lsr.w %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_lsl_s_8(void)
+{
+ sprintf(g_dasm_str, "lsl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_lsl_s_16(void)
+{
+ sprintf(g_dasm_str, "lsl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_lsl_s_32(void)
+{
+ sprintf(g_dasm_str, "lsl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_lsl_r_8(void)
+{
+ sprintf(g_dasm_str, "lsl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_lsl_r_16(void)
+{
+ sprintf(g_dasm_str, "lsl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_lsl_r_32(void)
+{
+ sprintf(g_dasm_str, "lsl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_lsl_ea(void)
+{
+ sprintf(g_dasm_str, "lsl.w %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_move_8(void)
+{
+ char* str = get_ea_mode_str_8(g_cpu_ir);
+ sprintf(g_dasm_str, "move.b %s, %s", str, get_ea_mode_str_8(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38)));
+}
+
+static void d68000_move_16(void)
+{
+ char* str = get_ea_mode_str_16(g_cpu_ir);
+ sprintf(g_dasm_str, "move.w %s, %s", str, get_ea_mode_str_16(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38)));
+}
+
+static void d68000_move_32(void)
+{
+ char* str = get_ea_mode_str_32(g_cpu_ir);
+ sprintf(g_dasm_str, "move.l %s, %s", str, get_ea_mode_str_32(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38)));
+}
+
+static void d68000_movea_16(void)
+{
+ sprintf(g_dasm_str, "movea.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_movea_32(void)
+{
+ sprintf(g_dasm_str, "movea.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_move_to_ccr(void)
+{
+ sprintf(g_dasm_str, "move %s, CCR", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68010_move_fr_ccr(void)
+{
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ sprintf(g_dasm_str, "move CCR, %s; (1+)", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_move_fr_sr(void)
+{
+ sprintf(g_dasm_str, "move SR, %s", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_move_to_sr(void)
+{
+ sprintf(g_dasm_str, "move %s, SR", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_move_fr_usp(void)
+{
+ sprintf(g_dasm_str, "move USP, A%d", g_cpu_ir&7);
+}
+
+static void d68000_move_to_usp(void)
+{
+ sprintf(g_dasm_str, "move A%d, USP", g_cpu_ir&7);
+}
+
+static void d68010_movec(void)
+{
+ uint extension;
+ const char* reg_name;
+ const char* processor;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ extension = read_imm_16();
+
+ switch(extension & 0xfff)
+ {
+ case 0x000:
+ reg_name = "SFC";
+ processor = "1+";
+ break;
+ case 0x001:
+ reg_name = "DFC";
+ processor = "1+";
+ break;
+ case 0x800:
+ reg_name = "USP";
+ processor = "1+";
+ break;
+ case 0x801:
+ reg_name = "VBR";
+ processor = "1+";
+ break;
+ case 0x002:
+ reg_name = "CACR";
+ processor = "2+";
+ break;
+ case 0x802:
+ reg_name = "CAAR";
+ processor = "2,3";
+ break;
+ case 0x803:
+ reg_name = "MSP";
+ processor = "2+";
+ break;
+ case 0x804:
+ reg_name = "ISP";
+ processor = "2+";
+ break;
+ case 0x003:
+ reg_name = "TC";
+ processor = "4+";
+ break;
+ case 0x004:
+ reg_name = "ITT0";
+ processor = "4+";
+ break;
+ case 0x005:
+ reg_name = "ITT1";
+ processor = "4+";
+ break;
+ case 0x006:
+ reg_name = "DTT0";
+ processor = "4+";
+ break;
+ case 0x007:
+ reg_name = "DTT1";
+ processor = "4+";
+ break;
+ case 0x805:
+ reg_name = "MMUSR";
+ processor = "4+";
+ break;
+ case 0x806:
+ reg_name = "URP";
+ processor = "4+";
+ break;
+ case 0x807:
+ reg_name = "SRP";
+ processor = "4+";
+ break;
+ default:
+ reg_name = make_signed_hex_str_16(extension & 0xfff);
+ processor = "?";
+ }
+
+ if(BIT_0(g_cpu_ir))
+ sprintf(g_dasm_str, "movec %c%d, %s; (%s)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, reg_name, processor);
+ else
+ sprintf(g_dasm_str, "movec %s, %c%d; (%s)", reg_name, BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, processor);
+}
+
+static void d68000_movem_pd_16(void)
+{
+ uint data = read_imm_16();
+ char buffer[40];
+ uint first;
+ uint run_length;
+ uint i;
+
+ buffer[0] = 0;
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<(15-i)))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(15-(i+1)))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "D%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-D%d", first + run_length);
+ }
+ }
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<(7-i)))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(7-(i+1)))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "A%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-A%d", first + run_length);
+ }
+ }
+ sprintf(g_dasm_str, "movem.w %s, %s", buffer, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_movem_pd_32(void)
+{
+ uint data = read_imm_16();
+ char buffer[40];
+ uint first;
+ uint run_length;
+ uint i;
+
+ buffer[0] = 0;
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<(15-i)))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(15-(i+1)))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "D%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-D%d", first + run_length);
+ }
+ }
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<(7-i)))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(7-(i+1)))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "A%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-A%d", first + run_length);
+ }
+ }
+ sprintf(g_dasm_str, "movem.l %s, %s", buffer, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_movem_er_16(void)
+{
+ uint data = read_imm_16();
+ char buffer[40];
+ uint first;
+ uint run_length;
+ uint i;
+
+ buffer[0] = 0;
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<i))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(i+1))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "D%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-D%d", first + run_length);
+ }
+ }
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<(i+8)))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(i+8+1))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "A%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-A%d", first + run_length);
+ }
+ }
+ sprintf(g_dasm_str, "movem.w %s, %s", get_ea_mode_str_16(g_cpu_ir), buffer);
+}
+
+static void d68000_movem_er_32(void)
+{
+ uint data = read_imm_16();
+ char buffer[40];
+ uint first;
+ uint run_length;
+ uint i;
+
+ buffer[0] = 0;
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<i))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(i+1))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "D%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-D%d", first + run_length);
+ }
+ }
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<(i+8)))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(i+8+1))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "A%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-A%d", first + run_length);
+ }
+ }
+ sprintf(g_dasm_str, "movem.l %s, %s", get_ea_mode_str_32(g_cpu_ir), buffer);
+}
+
+static void d68000_movem_re_16(void)
+{
+ uint data = read_imm_16();
+ char buffer[40];
+ uint first;
+ uint run_length;
+ uint i;
+
+ buffer[0] = 0;
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<i))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(i+1))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "D%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-D%d", first + run_length);
+ }
+ }
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<(i+8)))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(i+8+1))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "A%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-A%d", first + run_length);
+ }
+ }
+ sprintf(g_dasm_str, "movem.w %s, %s", buffer, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_movem_re_32(void)
+{
+ uint data = read_imm_16();
+ char buffer[40];
+ uint first;
+ uint run_length;
+ uint i;
+
+ buffer[0] = 0;
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<i))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(i+1))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "D%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-D%d", first + run_length);
+ }
+ }
+ for(i=0;i<8;i++)
+ {
+ if(data&(1<<(i+8)))
+ {
+ first = i;
+ run_length = 0;
+ while(i<7 && (data&(1<<(i+8+1))))
+ {
+ i++;
+ run_length++;
+ }
+ if(buffer[0] != 0)
+ strcat(buffer, "/");
+ sprintf(buffer+strlen(buffer), "A%d", first);
+ if(run_length > 0)
+ sprintf(buffer+strlen(buffer), "-A%d", first + run_length);
+ }
+ }
+ sprintf(g_dasm_str, "movem.l %s, %s", buffer, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_movep_re_16(void)
+{
+ sprintf(g_dasm_str, "movep.w D%d, ($%x,A%d)", (g_cpu_ir>>9)&7, read_imm_16(), g_cpu_ir&7);
+}
+
+static void d68000_movep_re_32(void)
+{
+ sprintf(g_dasm_str, "movep.l D%d, ($%x,A%d)", (g_cpu_ir>>9)&7, read_imm_16(), g_cpu_ir&7);
+}
+
+static void d68000_movep_er_16(void)
+{
+ sprintf(g_dasm_str, "movep.w ($%x,A%d), D%d", read_imm_16(), g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_movep_er_32(void)
+{
+ sprintf(g_dasm_str, "movep.l ($%x,A%d), D%d", read_imm_16(), g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68010_moves_8(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ extension = read_imm_16();
+ if(BIT_B(extension))
+ sprintf(g_dasm_str, "moves.b %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir));
+ else
+ sprintf(g_dasm_str, "moves.b %s, %c%d; (1+)", get_ea_mode_str_8(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7);
+}
+
+static void d68010_moves_16(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ extension = read_imm_16();
+ if(BIT_B(extension))
+ sprintf(g_dasm_str, "moves.w %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_16(g_cpu_ir));
+ else
+ sprintf(g_dasm_str, "moves.w %s, %c%d; (1+)", get_ea_mode_str_16(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7);
+}
+
+static void d68010_moves_32(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ extension = read_imm_16();
+ if(BIT_B(extension))
+ sprintf(g_dasm_str, "moves.l %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_32(g_cpu_ir));
+ else
+ sprintf(g_dasm_str, "moves.l %s, %c%d; (1+)", get_ea_mode_str_32(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7);
+}
+
+static void d68000_moveq(void)
+{
+ sprintf(g_dasm_str, "moveq #%s, D%d", make_signed_hex_str_8(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68040_move16_pi_pi(void)
+{
+ LIMIT_CPU_TYPES(M68040_PLUS);
+ sprintf(g_dasm_str, "move16 (A%d)+, (A%d)+; (4)", g_cpu_ir&7, (read_imm_16()>>12)&7);
+}
+
+static void d68040_move16_pi_al(void)
+{
+ LIMIT_CPU_TYPES(M68040_PLUS);
+ sprintf(g_dasm_str, "move16 (A%d)+, %s; (4)", g_cpu_ir&7, get_imm_str_u32());
+}
+
+static void d68040_move16_al_pi(void)
+{
+ LIMIT_CPU_TYPES(M68040_PLUS);
+ sprintf(g_dasm_str, "move16 %s, (A%d)+; (4)", get_imm_str_u32(), g_cpu_ir&7);
+}
+
+static void d68040_move16_ai_al(void)
+{
+ LIMIT_CPU_TYPES(M68040_PLUS);
+ sprintf(g_dasm_str, "move16 (A%d), %s; (4)", g_cpu_ir&7, get_imm_str_u32());
+}
+
+static void d68040_move16_al_ai(void)
+{
+ LIMIT_CPU_TYPES(M68040_PLUS);
+ sprintf(g_dasm_str, "move16 %s, (A%d); (4)", get_imm_str_u32(), g_cpu_ir&7);
+}
+
+static void d68000_muls(void)
+{
+ sprintf(g_dasm_str, "muls.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_mulu(void)
+{
+ sprintf(g_dasm_str, "mulu.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68020_mull(void)
+{
+ uint extension;
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ extension = read_imm_16();
+
+ if(BIT_A(extension))
+ sprintf(g_dasm_str, "mul%c.l %s, D%d-D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7);
+ else
+ sprintf(g_dasm_str, "mul%c.l %s, D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), (extension>>12)&7);
+}
+
+static void d68000_nbcd(void)
+{
+ sprintf(g_dasm_str, "nbcd %s", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_neg_8(void)
+{
+ sprintf(g_dasm_str, "neg.b %s", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_neg_16(void)
+{
+ sprintf(g_dasm_str, "neg.w %s", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_neg_32(void)
+{
+ sprintf(g_dasm_str, "neg.l %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_negx_8(void)
+{
+ sprintf(g_dasm_str, "negx.b %s", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_negx_16(void)
+{
+ sprintf(g_dasm_str, "negx.w %s", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_negx_32(void)
+{
+ sprintf(g_dasm_str, "negx.l %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_nop(void)
+{
+ sprintf(g_dasm_str, "nop");
+}
+
+static void d68000_not_8(void)
+{
+ sprintf(g_dasm_str, "not.b %s", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_not_16(void)
+{
+ sprintf(g_dasm_str, "not.w %s", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_not_32(void)
+{
+ sprintf(g_dasm_str, "not.l %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_or_er_8(void)
+{
+ sprintf(g_dasm_str, "or.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_or_er_16(void)
+{
+ sprintf(g_dasm_str, "or.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_or_er_32(void)
+{
+ sprintf(g_dasm_str, "or.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_or_re_8(void)
+{
+ sprintf(g_dasm_str, "or.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_or_re_16(void)
+{
+ sprintf(g_dasm_str, "or.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_or_re_32(void)
+{
+ sprintf(g_dasm_str, "or.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_ori_8(void)
+{
+ char* str = get_imm_str_u8();
+ sprintf(g_dasm_str, "ori.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_ori_16(void)
+{
+ char* str = get_imm_str_u16();
+ sprintf(g_dasm_str, "ori.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_ori_32(void)
+{
+ char* str = get_imm_str_u32();
+ sprintf(g_dasm_str, "ori.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_ori_to_ccr(void)
+{
+ sprintf(g_dasm_str, "ori %s, CCR", get_imm_str_u8());
+}
+
+static void d68000_ori_to_sr(void)
+{
+ sprintf(g_dasm_str, "ori %s, SR", get_imm_str_u16());
+}
+
+static void d68020_pack_rr(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "pack D%d, D%d, %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16());
+}
+
+static void d68020_pack_mm(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "pack -(A%d), -(A%d), %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16());
+}
+
+static void d68000_pea(void)
+{
+ sprintf(g_dasm_str, "pea %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68040_pflush(void)
+{
+ LIMIT_CPU_TYPES(M68040_PLUS);
+
+ if (g_cpu_ir & 0x10)
+ {
+ sprintf(g_dasm_str, "pflusha%s", (g_cpu_ir & 8) ? "" : "n");
+ }
+ else
+ {
+ sprintf(g_dasm_str, "pflush%s(A%d)", (g_cpu_ir & 8) ? "" : "n", g_cpu_ir & 7);
+ }
+}
+
+static void d68000_reset(void)
+{
+ sprintf(g_dasm_str, "reset");
+}
+
+static void d68000_ror_s_8(void)
+{
+ sprintf(g_dasm_str, "ror.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_ror_s_16(void)
+{
+ sprintf(g_dasm_str, "ror.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7],g_cpu_ir&7);
+}
+
+static void d68000_ror_s_32(void)
+{
+ sprintf(g_dasm_str, "ror.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_ror_r_8(void)
+{
+ sprintf(g_dasm_str, "ror.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_ror_r_16(void)
+{
+ sprintf(g_dasm_str, "ror.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_ror_r_32(void)
+{
+ sprintf(g_dasm_str, "ror.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_ror_ea(void)
+{
+ sprintf(g_dasm_str, "ror.w %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_rol_s_8(void)
+{
+ sprintf(g_dasm_str, "rol.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_rol_s_16(void)
+{
+ sprintf(g_dasm_str, "rol.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_rol_s_32(void)
+{
+ sprintf(g_dasm_str, "rol.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_rol_r_8(void)
+{
+ sprintf(g_dasm_str, "rol.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_rol_r_16(void)
+{
+ sprintf(g_dasm_str, "rol.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_rol_r_32(void)
+{
+ sprintf(g_dasm_str, "rol.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_rol_ea(void)
+{
+ sprintf(g_dasm_str, "rol.w %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_roxr_s_8(void)
+{
+ sprintf(g_dasm_str, "roxr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_roxr_s_16(void)
+{
+ sprintf(g_dasm_str, "roxr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+
+static void d68000_roxr_s_32(void)
+{
+ sprintf(g_dasm_str, "roxr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_roxr_r_8(void)
+{
+ sprintf(g_dasm_str, "roxr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_roxr_r_16(void)
+{
+ sprintf(g_dasm_str, "roxr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_roxr_r_32(void)
+{
+ sprintf(g_dasm_str, "roxr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_roxr_ea(void)
+{
+ sprintf(g_dasm_str, "roxr.w %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_roxl_s_8(void)
+{
+ sprintf(g_dasm_str, "roxl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_roxl_s_16(void)
+{
+ sprintf(g_dasm_str, "roxl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_roxl_s_32(void)
+{
+ sprintf(g_dasm_str, "roxl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7);
+}
+
+static void d68000_roxl_r_8(void)
+{
+ sprintf(g_dasm_str, "roxl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_roxl_r_16(void)
+{
+ sprintf(g_dasm_str, "roxl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_roxl_r_32(void)
+{
+ sprintf(g_dasm_str, "roxl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7);
+}
+
+static void d68000_roxl_ea(void)
+{
+ sprintf(g_dasm_str, "roxl.w %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68010_rtd(void)
+{
+ LIMIT_CPU_TYPES(M68010_PLUS);
+ sprintf(g_dasm_str, "rtd %s; (1+)", get_imm_str_s16());
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
+}
+
+static void d68000_rte(void)
+{
+ sprintf(g_dasm_str, "rte");
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
+}
+
+static void d68020_rtm(void)
+{
+ LIMIT_CPU_TYPES(M68020_ONLY);
+ sprintf(g_dasm_str, "rtm %c%d; (2+)", BIT_3(g_cpu_ir) ? 'A' : 'D', g_cpu_ir&7);
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
+}
+
+static void d68000_rtr(void)
+{
+ sprintf(g_dasm_str, "rtr");
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
+}
+
+static void d68000_rts(void)
+{
+ sprintf(g_dasm_str, "rts");
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
+}
+
+static void d68000_sbcd_rr(void)
+{
+ sprintf(g_dasm_str, "sbcd D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_sbcd_mm(void)
+{
+ sprintf(g_dasm_str, "sbcd -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_scc(void)
+{
+ sprintf(g_dasm_str, "s%-2s %s", g_cc[(g_cpu_ir>>8)&0xf], get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_stop(void)
+{
+ sprintf(g_dasm_str, "stop %s", get_imm_str_s16());
+}
+
+static void d68000_sub_er_8(void)
+{
+ sprintf(g_dasm_str, "sub.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_sub_er_16(void)
+{
+ sprintf(g_dasm_str, "sub.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_sub_er_32(void)
+{
+ sprintf(g_dasm_str, "sub.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_sub_re_8(void)
+{
+ sprintf(g_dasm_str, "sub.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_sub_re_16(void)
+{
+ sprintf(g_dasm_str, "sub.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_sub_re_32(void)
+{
+ sprintf(g_dasm_str, "sub.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_suba_16(void)
+{
+ sprintf(g_dasm_str, "suba.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_suba_32(void)
+{
+ sprintf(g_dasm_str, "suba.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
+}
+
+static void d68000_subi_8(void)
+{
+ char* str = get_imm_str_s8();
+ sprintf(g_dasm_str, "subi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_subi_16(void)
+{
+ char* str = get_imm_str_s16();
+ sprintf(g_dasm_str, "subi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_subi_32(void)
+{
+ char* str = get_imm_str_s32();
+ sprintf(g_dasm_str, "subi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_subq_8(void)
+{
+ sprintf(g_dasm_str, "subq.b #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_subq_16(void)
+{
+ sprintf(g_dasm_str, "subq.w #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_subq_32(void)
+{
+ sprintf(g_dasm_str, "subq.l #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_subx_rr_8(void)
+{
+ sprintf(g_dasm_str, "subx.b D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_subx_rr_16(void)
+{
+ sprintf(g_dasm_str, "subx.w D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_subx_rr_32(void)
+{
+ sprintf(g_dasm_str, "subx.l D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_subx_mm_8(void)
+{
+ sprintf(g_dasm_str, "subx.b -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_subx_mm_16(void)
+{
+ sprintf(g_dasm_str, "subx.w -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_subx_mm_32(void)
+{
+ sprintf(g_dasm_str, "subx.l -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7);
+}
+
+static void d68000_swap(void)
+{
+ sprintf(g_dasm_str, "swap D%d", g_cpu_ir&7);
+}
+
+static void d68000_tas(void)
+{
+ sprintf(g_dasm_str, "tas %s", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_trap(void)
+{
+ sprintf(g_dasm_str, "trap #$%x", g_cpu_ir&0xf);
+}
+
+static void d68020_trapcc_0(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "trap%-2s; (2+)", g_cc[(g_cpu_ir>>8)&0xf]);
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68020_trapcc_16(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u16());
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68020_trapcc_32(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u32());
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68000_trapv(void)
+{
+ sprintf(g_dasm_str, "trapv");
+ SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
+}
+
+static void d68000_tst_8(void)
+{
+ sprintf(g_dasm_str, "tst.b %s", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_tst_pcdi_8(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_tst_pcix_8(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68020_tst_i_8(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir));
+}
+
+static void d68000_tst_16(void)
+{
+ sprintf(g_dasm_str, "tst.w %s", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68020_tst_a_16(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68020_tst_pcdi_16(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68020_tst_pcix_16(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68020_tst_i_16(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir));
+}
+
+static void d68000_tst_32(void)
+{
+ sprintf(g_dasm_str, "tst.l %s", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68020_tst_a_32(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68020_tst_pcdi_32(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68020_tst_pcix_32(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68020_tst_i_32(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir));
+}
+
+static void d68000_unlk(void)
+{
+ sprintf(g_dasm_str, "unlk A%d", g_cpu_ir&7);
+}
+
+static void d68020_unpk_rr(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "unpk D%d, D%d, %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16());
+}
+
+static void d68020_unpk_mm(void)
+{
+ LIMIT_CPU_TYPES(M68020_PLUS);
+ sprintf(g_dasm_str, "unpk -(A%d), -(A%d), %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16());
+}
+
+
+
+/* ======================================================================== */
+/* ======================= INSTRUCTION TABLE BUILDER ====================== */
+/* ======================================================================== */
+
+/* EA Masks:
+800 = data register direct
+400 = address register direct
+200 = address register indirect
+100 = ARI postincrement
+ 80 = ARI pre-decrement
+ 40 = ARI displacement
+ 20 = ARI index
+ 10 = absolute short
+ 8 = absolute long
+ 4 = immediate / sr
+ 2 = pc displacement
+ 1 = pc idx
+*/
+
+static opcode_struct g_opcode_info[] =
+{
+/* opcode handler mask match ea mask */
+ {d68000_1010 , 0xf000, 0xa000, 0x000},
+ {d68000_1111 , 0xf000, 0xf000, 0x000},
+ {d68000_abcd_rr , 0xf1f8, 0xc100, 0x000},
+ {d68000_abcd_mm , 0xf1f8, 0xc108, 0x000},
+ {d68000_add_er_8 , 0xf1c0, 0xd000, 0xbff},
+ {d68000_add_er_16 , 0xf1c0, 0xd040, 0xfff},
+ {d68000_add_er_32 , 0xf1c0, 0xd080, 0xfff},
+ {d68000_add_re_8 , 0xf1c0, 0xd100, 0x3f8},
+ {d68000_add_re_16 , 0xf1c0, 0xd140, 0x3f8},
+ {d68000_add_re_32 , 0xf1c0, 0xd180, 0x3f8},
+ {d68000_adda_16 , 0xf1c0, 0xd0c0, 0xfff},
+ {d68000_adda_32 , 0xf1c0, 0xd1c0, 0xfff},
+ {d68000_addi_8 , 0xffc0, 0x0600, 0xbf8},
+ {d68000_addi_16 , 0xffc0, 0x0640, 0xbf8},
+ {d68000_addi_32 , 0xffc0, 0x0680, 0xbf8},
+ {d68000_addq_8 , 0xf1c0, 0x5000, 0xbf8},
+ {d68000_addq_16 , 0xf1c0, 0x5040, 0xff8},
+ {d68000_addq_32 , 0xf1c0, 0x5080, 0xff8},
+ {d68000_addx_rr_8 , 0xf1f8, 0xd100, 0x000},
+ {d68000_addx_rr_16 , 0xf1f8, 0xd140, 0x000},
+ {d68000_addx_rr_32 , 0xf1f8, 0xd180, 0x000},
+ {d68000_addx_mm_8 , 0xf1f8, 0xd108, 0x000},
+ {d68000_addx_mm_16 , 0xf1f8, 0xd148, 0x000},
+ {d68000_addx_mm_32 , 0xf1f8, 0xd188, 0x000},
+ {d68000_and_er_8 , 0xf1c0, 0xc000, 0xbff},
+ {d68000_and_er_16 , 0xf1c0, 0xc040, 0xbff},
+ {d68000_and_er_32 , 0xf1c0, 0xc080, 0xbff},
+ {d68000_and_re_8 , 0xf1c0, 0xc100, 0x3f8},
+ {d68000_and_re_16 , 0xf1c0, 0xc140, 0x3f8},
+ {d68000_and_re_32 , 0xf1c0, 0xc180, 0x3f8},
+ {d68000_andi_to_ccr , 0xffff, 0x023c, 0x000},
+ {d68000_andi_to_sr , 0xffff, 0x027c, 0x000},
+ {d68000_andi_8 , 0xffc0, 0x0200, 0xbf8},
+ {d68000_andi_16 , 0xffc0, 0x0240, 0xbf8},
+ {d68000_andi_32 , 0xffc0, 0x0280, 0xbf8},
+ {d68000_asr_s_8 , 0xf1f8, 0xe000, 0x000},
+ {d68000_asr_s_16 , 0xf1f8, 0xe040, 0x000},
+ {d68000_asr_s_32 , 0xf1f8, 0xe080, 0x000},
+ {d68000_asr_r_8 , 0xf1f8, 0xe020, 0x000},
+ {d68000_asr_r_16 , 0xf1f8, 0xe060, 0x000},
+ {d68000_asr_r_32 , 0xf1f8, 0xe0a0, 0x000},
+ {d68000_asr_ea , 0xffc0, 0xe0c0, 0x3f8},
+ {d68000_asl_s_8 , 0xf1f8, 0xe100, 0x000},
+ {d68000_asl_s_16 , 0xf1f8, 0xe140, 0x000},
+ {d68000_asl_s_32 , 0xf1f8, 0xe180, 0x000},
+ {d68000_asl_r_8 , 0xf1f8, 0xe120, 0x000},
+ {d68000_asl_r_16 , 0xf1f8, 0xe160, 0x000},
+ {d68000_asl_r_32 , 0xf1f8, 0xe1a0, 0x000},
+ {d68000_asl_ea , 0xffc0, 0xe1c0, 0x3f8},
+ {d68000_bcc_8 , 0xf000, 0x6000, 0x000},
+ {d68000_bcc_16 , 0xf0ff, 0x6000, 0x000},
+ {d68020_bcc_32 , 0xf0ff, 0x60ff, 0x000},
+ {d68000_bchg_r , 0xf1c0, 0x0140, 0xbf8},
+ {d68000_bchg_s , 0xffc0, 0x0840, 0xbf8},
+ {d68000_bclr_r , 0xf1c0, 0x0180, 0xbf8},
+ {d68000_bclr_s , 0xffc0, 0x0880, 0xbf8},
+ {d68020_bfchg , 0xffc0, 0xeac0, 0xa78},
+ {d68020_bfclr , 0xffc0, 0xecc0, 0xa78},
+ {d68020_bfexts , 0xffc0, 0xebc0, 0xa7b},
+ {d68020_bfextu , 0xffc0, 0xe9c0, 0xa7b},
+ {d68020_bfffo , 0xffc0, 0xedc0, 0xa7b},
+ {d68020_bfins , 0xffc0, 0xefc0, 0xa78},
+ {d68020_bfset , 0xffc0, 0xeec0, 0xa78},
+ {d68020_bftst , 0xffc0, 0xe8c0, 0xa7b},
+ {d68010_bkpt , 0xfff8, 0x4848, 0x000},
+ {d68000_bra_8 , 0xff00, 0x6000, 0x000},
+ {d68000_bra_16 , 0xffff, 0x6000, 0x000},
+ {d68020_bra_32 , 0xffff, 0x60ff, 0x000},
+ {d68000_bset_r , 0xf1c0, 0x01c0, 0xbf8},
+ {d68000_bset_s , 0xffc0, 0x08c0, 0xbf8},
+ {d68000_bsr_8 , 0xff00, 0x6100, 0x000},
+ {d68000_bsr_16 , 0xffff, 0x6100, 0x000},
+ {d68020_bsr_32 , 0xffff, 0x61ff, 0x000},
+ {d68000_btst_r , 0xf1c0, 0x0100, 0xbff},
+ {d68000_btst_s , 0xffc0, 0x0800, 0xbfb},
+ {d68020_callm , 0xffc0, 0x06c0, 0x27b},
+ {d68020_cas_8 , 0xffc0, 0x0ac0, 0x3f8},
+ {d68020_cas_16 , 0xffc0, 0x0cc0, 0x3f8},
+ {d68020_cas_32 , 0xffc0, 0x0ec0, 0x3f8},
+ {d68020_cas2_16 , 0xffff, 0x0cfc, 0x000},
+ {d68020_cas2_32 , 0xffff, 0x0efc, 0x000},
+ {d68000_chk_16 , 0xf1c0, 0x4180, 0xbff},
+ {d68020_chk_32 , 0xf1c0, 0x4100, 0xbff},
+ {d68020_chk2_cmp2_8 , 0xffc0, 0x00c0, 0x27b},
+ {d68020_chk2_cmp2_16 , 0xffc0, 0x02c0, 0x27b},
+ {d68020_chk2_cmp2_32 , 0xffc0, 0x04c0, 0x27b},
+ {d68040_cinv , 0xff20, 0xf400, 0x000},
+ {d68000_clr_8 , 0xffc0, 0x4200, 0xbf8},
+ {d68000_clr_16 , 0xffc0, 0x4240, 0xbf8},
+ {d68000_clr_32 , 0xffc0, 0x4280, 0xbf8},
+ {d68000_cmp_8 , 0xf1c0, 0xb000, 0xbff},
+ {d68000_cmp_16 , 0xf1c0, 0xb040, 0xfff},
+ {d68000_cmp_32 , 0xf1c0, 0xb080, 0xfff},
+ {d68000_cmpa_16 , 0xf1c0, 0xb0c0, 0xfff},
+ {d68000_cmpa_32 , 0xf1c0, 0xb1c0, 0xfff},
+ {d68000_cmpi_8 , 0xffc0, 0x0c00, 0xbf8},
+ {d68020_cmpi_pcdi_8 , 0xffff, 0x0c3a, 0x000},
+ {d68020_cmpi_pcix_8 , 0xffff, 0x0c3b, 0x000},
+ {d68000_cmpi_16 , 0xffc0, 0x0c40, 0xbf8},
+ {d68020_cmpi_pcdi_16 , 0xffff, 0x0c7a, 0x000},
+ {d68020_cmpi_pcix_16 , 0xffff, 0x0c7b, 0x000},
+ {d68000_cmpi_32 , 0xffc0, 0x0c80, 0xbf8},
+ {d68020_cmpi_pcdi_32 , 0xffff, 0x0cba, 0x000},
+ {d68020_cmpi_pcix_32 , 0xffff, 0x0cbb, 0x000},
+ {d68000_cmpm_8 , 0xf1f8, 0xb108, 0x000},
+ {d68000_cmpm_16 , 0xf1f8, 0xb148, 0x000},
+ {d68000_cmpm_32 , 0xf1f8, 0xb188, 0x000},
+ {d68020_cpbcc_16 , 0xf1c0, 0xf080, 0x000},
+ {d68020_cpbcc_32 , 0xf1c0, 0xf0c0, 0x000},
+ {d68020_cpdbcc , 0xf1f8, 0xf048, 0x000},
+ {d68020_cpgen , 0xf1c0, 0xf000, 0x000},
+ {d68020_cprestore , 0xf1c0, 0xf140, 0x37f},
+ {d68020_cpsave , 0xf1c0, 0xf100, 0x2f8},
+ {d68020_cpscc , 0xf1c0, 0xf040, 0xbf8},
+ {d68020_cptrapcc_0 , 0xf1ff, 0xf07c, 0x000},
+ {d68020_cptrapcc_16 , 0xf1ff, 0xf07a, 0x000},
+ {d68020_cptrapcc_32 , 0xf1ff, 0xf07b, 0x000},
+ {d68040_cpush , 0xff20, 0xf420, 0x000},
+ {d68000_dbcc , 0xf0f8, 0x50c8, 0x000},
+ {d68000_dbra , 0xfff8, 0x51c8, 0x000},
+ {d68000_divs , 0xf1c0, 0x81c0, 0xbff},
+ {d68000_divu , 0xf1c0, 0x80c0, 0xbff},
+ {d68020_divl , 0xffc0, 0x4c40, 0xbff},
+ {d68000_eor_8 , 0xf1c0, 0xb100, 0xbf8},
+ {d68000_eor_16 , 0xf1c0, 0xb140, 0xbf8},
+ {d68000_eor_32 , 0xf1c0, 0xb180, 0xbf8},
+ {d68000_eori_to_ccr , 0xffff, 0x0a3c, 0x000},
+ {d68000_eori_to_sr , 0xffff, 0x0a7c, 0x000},
+ {d68000_eori_8 , 0xffc0, 0x0a00, 0xbf8},
+ {d68000_eori_16 , 0xffc0, 0x0a40, 0xbf8},
+ {d68000_eori_32 , 0xffc0, 0x0a80, 0xbf8},
+ {d68000_exg_dd , 0xf1f8, 0xc140, 0x000},
+ {d68000_exg_aa , 0xf1f8, 0xc148, 0x000},
+ {d68000_exg_da , 0xf1f8, 0xc188, 0x000},
+ {d68020_extb_32 , 0xfff8, 0x49c0, 0x000},
+ {d68000_ext_16 , 0xfff8, 0x4880, 0x000},
+ {d68000_ext_32 , 0xfff8, 0x48c0, 0x000},
+ {d68040_fpu , 0xffc0, 0xf200, 0x000},
+ {d68000_illegal , 0xffff, 0x4afc, 0x000},
+ {d68000_jmp , 0xffc0, 0x4ec0, 0x27b},
+ {d68000_jsr , 0xffc0, 0x4e80, 0x27b},
+ {d68000_lea , 0xf1c0, 0x41c0, 0x27b},
+ {d68000_link_16 , 0xfff8, 0x4e50, 0x000},
+ {d68020_link_32 , 0xfff8, 0x4808, 0x000},
+ {d68000_lsr_s_8 , 0xf1f8, 0xe008, 0x000},
+ {d68000_lsr_s_16 , 0xf1f8, 0xe048, 0x000},
+ {d68000_lsr_s_32 , 0xf1f8, 0xe088, 0x000},
+ {d68000_lsr_r_8 , 0xf1f8, 0xe028, 0x000},
+ {d68000_lsr_r_16 , 0xf1f8, 0xe068, 0x000},
+ {d68000_lsr_r_32 , 0xf1f8, 0xe0a8, 0x000},
+ {d68000_lsr_ea , 0xffc0, 0xe2c0, 0x3f8},
+ {d68000_lsl_s_8 , 0xf1f8, 0xe108, 0x000},
+ {d68000_lsl_s_16 , 0xf1f8, 0xe148, 0x000},
+ {d68000_lsl_s_32 , 0xf1f8, 0xe188, 0x000},
+ {d68000_lsl_r_8 , 0xf1f8, 0xe128, 0x000},
+ {d68000_lsl_r_16 , 0xf1f8, 0xe168, 0x000},
+ {d68000_lsl_r_32 , 0xf1f8, 0xe1a8, 0x000},
+ {d68000_lsl_ea , 0xffc0, 0xe3c0, 0x3f8},
+ {d68000_move_8 , 0xf000, 0x1000, 0xbff},
+ {d68000_move_16 , 0xf000, 0x3000, 0xfff},
+ {d68000_move_32 , 0xf000, 0x2000, 0xfff},
+ {d68000_movea_16 , 0xf1c0, 0x3040, 0xfff},
+ {d68000_movea_32 , 0xf1c0, 0x2040, 0xfff},
+ {d68000_move_to_ccr , 0xffc0, 0x44c0, 0xbff},
+ {d68010_move_fr_ccr , 0xffc0, 0x42c0, 0xbf8},
+ {d68000_move_to_sr , 0xffc0, 0x46c0, 0xbff},
+ {d68000_move_fr_sr , 0xffc0, 0x40c0, 0xbf8},
+ {d68000_move_to_usp , 0xfff8, 0x4e60, 0x000},
+ {d68000_move_fr_usp , 0xfff8, 0x4e68, 0x000},
+ {d68010_movec , 0xfffe, 0x4e7a, 0x000},
+ {d68000_movem_pd_16 , 0xfff8, 0x48a0, 0x000},
+ {d68000_movem_pd_32 , 0xfff8, 0x48e0, 0x000},
+ {d68000_movem_re_16 , 0xffc0, 0x4880, 0x2f8},
+ {d68000_movem_re_32 , 0xffc0, 0x48c0, 0x2f8},
+ {d68000_movem_er_16 , 0xffc0, 0x4c80, 0x37b},
+ {d68000_movem_er_32 , 0xffc0, 0x4cc0, 0x37b},
+ {d68000_movep_er_16 , 0xf1f8, 0x0108, 0x000},
+ {d68000_movep_er_32 , 0xf1f8, 0x0148, 0x000},
+ {d68000_movep_re_16 , 0xf1f8, 0x0188, 0x000},
+ {d68000_movep_re_32 , 0xf1f8, 0x01c8, 0x000},
+ {d68010_moves_8 , 0xffc0, 0x0e00, 0x3f8},
+ {d68010_moves_16 , 0xffc0, 0x0e40, 0x3f8},
+ {d68010_moves_32 , 0xffc0, 0x0e80, 0x3f8},
+ {d68000_moveq , 0xf100, 0x7000, 0x000},
+ {d68040_move16_pi_pi , 0xfff8, 0xf620, 0x000},
+ {d68040_move16_pi_al , 0xfff8, 0xf600, 0x000},
+ {d68040_move16_al_pi , 0xfff8, 0xf608, 0x000},
+ {d68040_move16_ai_al , 0xfff8, 0xf610, 0x000},
+ {d68040_move16_al_ai , 0xfff8, 0xf618, 0x000},
+ {d68000_muls , 0xf1c0, 0xc1c0, 0xbff},
+ {d68000_mulu , 0xf1c0, 0xc0c0, 0xbff},
+ {d68020_mull , 0xffc0, 0x4c00, 0xbff},
+ {d68000_nbcd , 0xffc0, 0x4800, 0xbf8},
+ {d68000_neg_8 , 0xffc0, 0x4400, 0xbf8},
+ {d68000_neg_16 , 0xffc0, 0x4440, 0xbf8},
+ {d68000_neg_32 , 0xffc0, 0x4480, 0xbf8},
+ {d68000_negx_8 , 0xffc0, 0x4000, 0xbf8},
+ {d68000_negx_16 , 0xffc0, 0x4040, 0xbf8},
+ {d68000_negx_32 , 0xffc0, 0x4080, 0xbf8},
+ {d68000_nop , 0xffff, 0x4e71, 0x000},
+ {d68000_not_8 , 0xffc0, 0x4600, 0xbf8},
+ {d68000_not_16 , 0xffc0, 0x4640, 0xbf8},
+ {d68000_not_32 , 0xffc0, 0x4680, 0xbf8},
+ {d68000_or_er_8 , 0xf1c0, 0x8000, 0xbff},
+ {d68000_or_er_16 , 0xf1c0, 0x8040, 0xbff},
+ {d68000_or_er_32 , 0xf1c0, 0x8080, 0xbff},
+ {d68000_or_re_8 , 0xf1c0, 0x8100, 0x3f8},
+ {d68000_or_re_16 , 0xf1c0, 0x8140, 0x3f8},
+ {d68000_or_re_32 , 0xf1c0, 0x8180, 0x3f8},
+ {d68000_ori_to_ccr , 0xffff, 0x003c, 0x000},
+ {d68000_ori_to_sr , 0xffff, 0x007c, 0x000},
+ {d68000_ori_8 , 0xffc0, 0x0000, 0xbf8},
+ {d68000_ori_16 , 0xffc0, 0x0040, 0xbf8},
+ {d68000_ori_32 , 0xffc0, 0x0080, 0xbf8},
+ {d68020_pack_rr , 0xf1f8, 0x8140, 0x000},
+ {d68020_pack_mm , 0xf1f8, 0x8148, 0x000},
+ {d68000_pea , 0xffc0, 0x4840, 0x27b},
+ {d68040_pflush , 0xffe0, 0xf500, 0x000},
+ {d68000_reset , 0xffff, 0x4e70, 0x000},
+ {d68000_ror_s_8 , 0xf1f8, 0xe018, 0x000},
+ {d68000_ror_s_16 , 0xf1f8, 0xe058, 0x000},
+ {d68000_ror_s_32 , 0xf1f8, 0xe098, 0x000},
+ {d68000_ror_r_8 , 0xf1f8, 0xe038, 0x000},
+ {d68000_ror_r_16 , 0xf1f8, 0xe078, 0x000},
+ {d68000_ror_r_32 , 0xf1f8, 0xe0b8, 0x000},
+ {d68000_ror_ea , 0xffc0, 0xe6c0, 0x3f8},
+ {d68000_rol_s_8 , 0xf1f8, 0xe118, 0x000},
+ {d68000_rol_s_16 , 0xf1f8, 0xe158, 0x000},
+ {d68000_rol_s_32 , 0xf1f8, 0xe198, 0x000},
+ {d68000_rol_r_8 , 0xf1f8, 0xe138, 0x000},
+ {d68000_rol_r_16 , 0xf1f8, 0xe178, 0x000},
+ {d68000_rol_r_32 , 0xf1f8, 0xe1b8, 0x000},
+ {d68000_rol_ea , 0xffc0, 0xe7c0, 0x3f8},
+ {d68000_roxr_s_8 , 0xf1f8, 0xe010, 0x000},
+ {d68000_roxr_s_16 , 0xf1f8, 0xe050, 0x000},
+ {d68000_roxr_s_32 , 0xf1f8, 0xe090, 0x000},
+ {d68000_roxr_r_8 , 0xf1f8, 0xe030, 0x000},
+ {d68000_roxr_r_16 , 0xf1f8, 0xe070, 0x000},
+ {d68000_roxr_r_32 , 0xf1f8, 0xe0b0, 0x000},
+ {d68000_roxr_ea , 0xffc0, 0xe4c0, 0x3f8},
+ {d68000_roxl_s_8 , 0xf1f8, 0xe110, 0x000},
+ {d68000_roxl_s_16 , 0xf1f8, 0xe150, 0x000},
+ {d68000_roxl_s_32 , 0xf1f8, 0xe190, 0x000},
+ {d68000_roxl_r_8 , 0xf1f8, 0xe130, 0x000},
+ {d68000_roxl_r_16 , 0xf1f8, 0xe170, 0x000},
+ {d68000_roxl_r_32 , 0xf1f8, 0xe1b0, 0x000},
+ {d68000_roxl_ea , 0xffc0, 0xe5c0, 0x3f8},
+ {d68010_rtd , 0xffff, 0x4e74, 0x000},
+ {d68000_rte , 0xffff, 0x4e73, 0x000},
+ {d68020_rtm , 0xfff0, 0x06c0, 0x000},
+ {d68000_rtr , 0xffff, 0x4e77, 0x000},
+ {d68000_rts , 0xffff, 0x4e75, 0x000},
+ {d68000_sbcd_rr , 0xf1f8, 0x8100, 0x000},
+ {d68000_sbcd_mm , 0xf1f8, 0x8108, 0x000},
+ {d68000_scc , 0xf0c0, 0x50c0, 0xbf8},
+ {d68000_stop , 0xffff, 0x4e72, 0x000},
+ {d68000_sub_er_8 , 0xf1c0, 0x9000, 0xbff},
+ {d68000_sub_er_16 , 0xf1c0, 0x9040, 0xfff},
+ {d68000_sub_er_32 , 0xf1c0, 0x9080, 0xfff},
+ {d68000_sub_re_8 , 0xf1c0, 0x9100, 0x3f8},
+ {d68000_sub_re_16 , 0xf1c0, 0x9140, 0x3f8},
+ {d68000_sub_re_32 , 0xf1c0, 0x9180, 0x3f8},
+ {d68000_suba_16 , 0xf1c0, 0x90c0, 0xfff},
+ {d68000_suba_32 , 0xf1c0, 0x91c0, 0xfff},
+ {d68000_subi_8 , 0xffc0, 0x0400, 0xbf8},
+ {d68000_subi_16 , 0xffc0, 0x0440, 0xbf8},
+ {d68000_subi_32 , 0xffc0, 0x0480, 0xbf8},
+ {d68000_subq_8 , 0xf1c0, 0x5100, 0xbf8},
+ {d68000_subq_16 , 0xf1c0, 0x5140, 0xff8},
+ {d68000_subq_32 , 0xf1c0, 0x5180, 0xff8},
+ {d68000_subx_rr_8 , 0xf1f8, 0x9100, 0x000},
+ {d68000_subx_rr_16 , 0xf1f8, 0x9140, 0x000},
+ {d68000_subx_rr_32 , 0xf1f8, 0x9180, 0x000},
+ {d68000_subx_mm_8 , 0xf1f8, 0x9108, 0x000},
+ {d68000_subx_mm_16 , 0xf1f8, 0x9148, 0x000},
+ {d68000_subx_mm_32 , 0xf1f8, 0x9188, 0x000},
+ {d68000_swap , 0xfff8, 0x4840, 0x000},
+ {d68000_tas , 0xffc0, 0x4ac0, 0xbf8},
+ {d68000_trap , 0xfff0, 0x4e40, 0x000},
+ {d68020_trapcc_0 , 0xf0ff, 0x50fc, 0x000},
+ {d68020_trapcc_16 , 0xf0ff, 0x50fa, 0x000},
+ {d68020_trapcc_32 , 0xf0ff, 0x50fb, 0x000},
+ {d68000_trapv , 0xffff, 0x4e76, 0x000},
+ {d68000_tst_8 , 0xffc0, 0x4a00, 0xbf8},
+ {d68020_tst_pcdi_8 , 0xffff, 0x4a3a, 0x000},
+ {d68020_tst_pcix_8 , 0xffff, 0x4a3b, 0x000},
+ {d68020_tst_i_8 , 0xffff, 0x4a3c, 0x000},
+ {d68000_tst_16 , 0xffc0, 0x4a40, 0xbf8},
+ {d68020_tst_a_16 , 0xfff8, 0x4a48, 0x000},
+ {d68020_tst_pcdi_16 , 0xffff, 0x4a7a, 0x000},
+ {d68020_tst_pcix_16 , 0xffff, 0x4a7b, 0x000},
+ {d68020_tst_i_16 , 0xffff, 0x4a7c, 0x000},
+ {d68000_tst_32 , 0xffc0, 0x4a80, 0xbf8},
+ {d68020_tst_a_32 , 0xfff8, 0x4a88, 0x000},
+ {d68020_tst_pcdi_32 , 0xffff, 0x4aba, 0x000},
+ {d68020_tst_pcix_32 , 0xffff, 0x4abb, 0x000},
+ {d68020_tst_i_32 , 0xffff, 0x4abc, 0x000},
+ {d68000_unlk , 0xfff8, 0x4e58, 0x000},
+ {d68020_unpk_rr , 0xf1f8, 0x8180, 0x000},
+ {d68020_unpk_mm , 0xf1f8, 0x8188, 0x000},
+ {0, 0, 0, 0}
+};
+
+/* Check if opcode is using a valid ea mode */
+static int valid_ea(uint opcode, uint mask)
+{
+ if(mask == 0)
+ return 1;
+
+ switch(opcode & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ return (mask & 0x800) != 0;
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ return (mask & 0x400) != 0;
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ return (mask & 0x200) != 0;
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ return (mask & 0x100) != 0;
+ case 0x20: case 0x21: case 0x22: case 0x23:
+ case 0x24: case 0x25: case 0x26: case 0x27:
+ return (mask & 0x080) != 0;
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ return (mask & 0x040) != 0;
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ return (mask & 0x020) != 0;
+ case 0x38:
+ return (mask & 0x010) != 0;
+ case 0x39:
+ return (mask & 0x008) != 0;
+ case 0x3a:
+ return (mask & 0x002) != 0;
+ case 0x3b:
+ return (mask & 0x001) != 0;
+ case 0x3c:
+ return (mask & 0x004) != 0;
+ }
+ return 0;
+
+}
+
+/* Used by qsort */
+static int DECL_SPEC compare_nof_true_bits(const void *aptr, const void *bptr)
+{
+ uint a = ((const opcode_struct*)aptr)->mask;
+ uint b = ((const opcode_struct*)bptr)->mask;
+
+ a = ((a & 0xAAAA) >> 1) + (a & 0x5555);
+ a = ((a & 0xCCCC) >> 2) + (a & 0x3333);
+ a = ((a & 0xF0F0) >> 4) + (a & 0x0F0F);
+ a = ((a & 0xFF00) >> 8) + (a & 0x00FF);
+
+ b = ((b & 0xAAAA) >> 1) + (b & 0x5555);
+ b = ((b & 0xCCCC) >> 2) + (b & 0x3333);
+ b = ((b & 0xF0F0) >> 4) + (b & 0x0F0F);
+ b = ((b & 0xFF00) >> 8) + (b & 0x00FF);
+
+ return b - a; /* reversed to get greatest to least sorting */
+}
+
+/* build the opcode handler jump table */
+static void build_opcode_table(void)
+{
+ uint i;
+ uint opcode;
+ opcode_struct* ostruct;
+ uint opcode_info_length = 0;
+
+ for(ostruct = g_opcode_info;ostruct->opcode_handler != 0;ostruct++)
+ opcode_info_length++;
+
+ qsort((void *)g_opcode_info, opcode_info_length, sizeof(g_opcode_info[0]), compare_nof_true_bits);
+
+ for(i=0;i<0x10000;i++)
+ {
+ g_instruction_table[i] = d68000_illegal; /* default to illegal */
+ opcode = i;
+ /* search through opcode info for a match */
+ for(ostruct = g_opcode_info;ostruct->opcode_handler != 0;ostruct++)
+ {
+ /* match opcode mask and allowed ea modes */
+ if((opcode & ostruct->mask) == ostruct->match)
+ {
+ /* Handle destination ea for move instructions */
+ if((ostruct->opcode_handler == d68000_move_8 ||
+ ostruct->opcode_handler == d68000_move_16 ||
+ ostruct->opcode_handler == d68000_move_32) &&
+ !valid_ea(((opcode>>9)&7) | ((opcode>>3)&0x38), 0xbf8))
+ continue;
+ if(valid_ea(opcode, ostruct->ea_mask))
+ {
+ g_instruction_table[i] = ostruct->opcode_handler;
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+
+/* ======================================================================== */
+/* ================================= API ================================== */
+/* ======================================================================== */
+
+/* Disasemble one instruction at pc and store in str_buff */
+unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type)
+{
+ if(!g_initialized)
+ {
+ build_opcode_table();
+ g_initialized = 1;
+ }
+ switch(cpu_type)
+ {
+ case M68K_CPU_TYPE_68000:
+ g_cpu_type = TYPE_68000;
+ g_address_mask = 0x00ffffff;
+ break;
+ case M68K_CPU_TYPE_68008:
+ g_cpu_type = TYPE_68008;
+ g_address_mask = 0x003fffff;
+ break;
+ case M68K_CPU_TYPE_68010:
+ g_cpu_type = TYPE_68010;
+ g_address_mask = 0x00ffffff;
+ break;
+ case M68K_CPU_TYPE_68EC020:
+ g_cpu_type = TYPE_68020;
+ g_address_mask = 0x00ffffff;
+ break;
+ case M68K_CPU_TYPE_68020:
+ g_cpu_type = TYPE_68020;
+ g_address_mask = 0xffffffff;
+ break;
+ case M68K_CPU_TYPE_68030:
+ g_cpu_type = TYPE_68030;
+ g_address_mask = 0xffffffff;
+ break;
+ case M68K_CPU_TYPE_68040:
+ g_cpu_type = TYPE_68040;
+ g_address_mask = 0xffffffff;
+ break;
+ default:
+ return 0;
+ }
+
+ g_cpu_pc = pc;
+ g_helper_str[0] = 0;
+ g_cpu_ir = read_imm_16();
+ g_opcode_type = 0;
+ g_instruction_table[g_cpu_ir]();
+ sprintf(str_buff, "%s%s", g_dasm_str, g_helper_str);
+ return COMBINE_OPCODE_FLAGS(g_cpu_pc - pc);
+}
+
+char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type)
+{
+ static char buff[100];
+ buff[0] = 0;
+ m68k_disassemble(buff, pc, cpu_type);
+ return buff;
+}
+
+unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigned char* opdata, const unsigned char* argdata, unsigned int cpu_type)
+{
+ unsigned int result;
+
+ g_rawop = opdata;
+ g_rawbasepc = pc;
+ result = m68k_disassemble(str_buff, pc, cpu_type);
+ g_rawop = NULL;
+ return result;
+}
+
+/* Check if the instruction is a valid one */
+unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type)
+{
+ if(!g_initialized)
+ {
+ build_opcode_table();
+ g_initialized = 1;
+ }
+
+ instruction &= 0xffff;
+ if(g_instruction_table[instruction] == d68000_illegal)
+ return 0;
+
+ switch(cpu_type)
+ {
+ case M68K_CPU_TYPE_68000:
+ case M68K_CPU_TYPE_68008:
+ if(g_instruction_table[instruction] == d68010_bkpt)
+ return 0;
+ if(g_instruction_table[instruction] == d68010_move_fr_ccr)
+ return 0;
+ if(g_instruction_table[instruction] == d68010_movec)
+ return 0;
+ if(g_instruction_table[instruction] == d68010_moves_8)
+ return 0;
+ if(g_instruction_table[instruction] == d68010_moves_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68010_moves_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68010_rtd)
+ return 0;
+ case M68K_CPU_TYPE_68010:
+ if(g_instruction_table[instruction] == d68020_bcc_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bfchg)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bfclr)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bfexts)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bfextu)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bfffo)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bfins)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bfset)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bftst)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bra_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_bsr_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_callm)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cas_8)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cas_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cas_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cas2_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cas2_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_chk_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_chk2_cmp2_8)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_chk2_cmp2_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_chk2_cmp2_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cmpi_pcdi_8)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cmpi_pcix_8)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cmpi_pcdi_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cmpi_pcix_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cmpi_pcdi_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cmpi_pcix_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpbcc_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpbcc_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpdbcc)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpgen)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cprestore)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpsave)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpscc)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cptrapcc_0)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cptrapcc_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cptrapcc_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_divl)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_extb_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_link_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_mull)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_pack_rr)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_pack_mm)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_rtm)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_trapcc_0)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_trapcc_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_trapcc_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_pcdi_8)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_pcix_8)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_i_8)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_a_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_pcdi_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_pcix_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_i_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_a_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_pcdi_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_pcix_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_tst_i_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_unpk_rr)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_unpk_mm)
+ return 0;
+ case M68K_CPU_TYPE_68EC020:
+ case M68K_CPU_TYPE_68020:
+ case M68K_CPU_TYPE_68030:
+ if(g_instruction_table[instruction] == d68040_cinv)
+ return 0;
+ if(g_instruction_table[instruction] == d68040_cpush)
+ return 0;
+ if(g_instruction_table[instruction] == d68040_move16_pi_pi)
+ return 0;
+ if(g_instruction_table[instruction] == d68040_move16_pi_al)
+ return 0;
+ if(g_instruction_table[instruction] == d68040_move16_al_pi)
+ return 0;
+ if(g_instruction_table[instruction] == d68040_move16_ai_al)
+ return 0;
+ if(g_instruction_table[instruction] == d68040_move16_al_ai)
+ return 0;
+ if(g_instruction_table[instruction] == d68040_pflush)
+ return 0;
+ case M68K_CPU_TYPE_68040:
+ if(g_instruction_table[instruction] == d68020_cpbcc_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpbcc_32)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpdbcc)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpgen)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cprestore)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpsave)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cpscc)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cptrapcc_0)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cptrapcc_16)
+ return 0;
+ if(g_instruction_table[instruction] == d68020_cptrapcc_32)
+ return 0;
+ }
+ if(cpu_type != M68K_CPU_TYPE_68020 && cpu_type != M68K_CPU_TYPE_68EC020 &&
+ (g_instruction_table[instruction] == d68020_callm ||
+ g_instruction_table[instruction] == d68020_rtm))
+ return 0;
+
+ return 1;
+}
+
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
diff --git a/src/emu/cpu/m68000/m68kfpu.c b/src/emu/cpu/m68000/m68kfpu.c
new file mode 100644
index 00000000000..c5ca30bb14a
--- /dev/null
+++ b/src/emu/cpu/m68000/m68kfpu.c
@@ -0,0 +1,828 @@
+#include "cpuintrf.h"
+
+#define FPCC_N 0x08000000
+#define FPCC_Z 0x04000000
+#define FPCC_I 0x02000000
+#define FPCC_NAN 0x01000000
+
+#define DOUBLE_INFINITY U64(0x7ff0000000000000)
+#define DOUBLE_EXPONENT U64(0x7ff0000000000000)
+#define DOUBLE_MANTISSA U64(0x000fffffffffffff)
+
+INLINE void SET_CONDITION_CODES(fp_reg reg)
+{
+ REG_FPSR &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN);
+
+ // sign flag
+ if (reg.i & U64(0x8000000000000000))
+ {
+ REG_FPSR |= FPCC_N;
+ }
+
+ // zero flag
+ if ((reg.i & U64(0x7fffffffffffffff)) == 0)
+ {
+ REG_FPSR |= FPCC_Z;
+ }
+
+ // infinity flag
+ if ((reg.i & U64(0x7fffffffffffffff)) == DOUBLE_INFINITY)
+ {
+ REG_FPSR |= FPCC_I;
+ }
+
+ // NaN flag
+ if (((reg.i & DOUBLE_EXPONENT) == DOUBLE_EXPONENT) && ((reg.i & DOUBLE_MANTISSA) != 0))
+ {
+ REG_FPSR |= FPCC_NAN;
+ }
+}
+
+INLINE int TEST_CONDITION(int condition)
+{
+ int n = (REG_FPSR & FPCC_N) != 0;
+ int z = (REG_FPSR & FPCC_Z) != 0;
+ int nan = (REG_FPSR & FPCC_NAN) != 0;
+ int r = 0;
+ switch (condition)
+ {
+ case 0x00: return 0; // False
+ case 0x01: return (z); // Equal
+ case 0x0e: return (!z); // Not Equal
+ case 0x0f: return 1; // True
+ case 0x12: return (!(nan || z || n)); // Greater Than
+ case 0x13: return (z || !(nan || n)); // Greater or Equal
+ case 0x14: return (n && !(nan || z)); // Less Than
+ case 0x15: return (z || (n && !nan)); // Less Than or Equal
+ case 0x1a: return (nan || !(n || z)); // Not Less Than or Equal
+ case 0x1b: return (nan || z || !n); // Not Less Than
+ case 0x1c: return (nan || (n && !z)); // Not Greater or Equal Than
+ case 0x1d: return (nan || z || n); // Not Greater Than
+
+ default: fatalerror("M68040: test_condition: unhandled condition %02X\n", condition);
+ }
+
+ return r;
+}
+
+static UINT8 READ_EA_8(int ea)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ return REG_D[reg];
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_8();
+ return m68ki_read_8(ea);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_8();
+ return m68ki_read_8(ea);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16();
+ UINT32 d2 = OPER_I_16();
+ UINT32 ea = (d1 << 16) | d2;
+ return m68ki_read_8(ea);
+ }
+ case 4: // #<data>
+ {
+ return OPER_I_8();
+ }
+ default: fatalerror("MC68040: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+
+ return 0;
+}
+
+static UINT16 READ_EA_16(int ea)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ return (UINT16)(REG_D[reg]);
+ }
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ return m68ki_read_16(ea);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_16();
+ return m68ki_read_16(ea);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_16();
+ return m68ki_read_16(ea);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16();
+ UINT32 d2 = OPER_I_16();
+ UINT32 ea = (d1 << 16) | d2;
+ return m68ki_read_16(ea);
+ }
+ case 4: // #<data>
+ {
+ return OPER_I_16();
+ }
+
+ default: fatalerror("MC68040: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+
+ return 0;
+}
+
+static UINT32 READ_EA_32(int ea)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ return REG_D[reg];
+ }
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ return m68ki_read_32(ea);
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_32();
+ return m68ki_read_32(ea);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32();
+ return m68ki_read_32(ea);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_32();
+ return m68ki_read_32(ea);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16();
+ UINT32 d2 = OPER_I_16();
+ UINT32 ea = (d1 << 16) | d2;
+ return m68ki_read_32(ea);
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32();
+ return m68ki_read_32(ea);
+ }
+ case 4: // #<data>
+ {
+ return OPER_I_32();
+ }
+ default: fatalerror("MC68040: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ return 0;
+}
+
+static void WRITE_EA_32(int ea, UINT32 data)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ REG_D[reg] = data;
+ break;
+ }
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = EA_AY_PD_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16();
+ UINT32 d2 = OPER_I_16();
+ UINT32 ea = (d1 << 16) | d2;
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ default: fatalerror("MC68040: WRITE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: WRITE_EA_32: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC);
+ }
+}
+
+static UINT64 READ_EA_64(int ea)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+ UINT32 h1, h2;
+
+ switch (mode)
+ {
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ h1 = m68ki_read_32(ea+0);
+ h2 = m68ki_read_32(ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = REG_A[reg];
+ REG_A[reg] += 8;
+ h1 = m68ki_read_32(ea+0);
+ h2 = m68ki_read_32(ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32();
+ h1 = m68ki_read_32(ea+0);
+ h2 = m68ki_read_32(ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 4: // #<data>
+ {
+ h1 = OPER_I_32();
+ h2 = OPER_I_32();
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32();
+ h1 = m68ki_read_32(ea+0);
+ h2 = m68ki_read_32(ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ default: fatalerror("MC68040: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+
+ return 0;
+}
+
+static void WRITE_EA_64(int ea, UINT64 data)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ m68ki_write_32(ea, (UINT32)(data >> 32));
+ m68ki_write_32(ea, (UINT32)(data));
+ break;
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea;
+ REG_A[reg] -= 8;
+ ea = REG_A[reg];
+ m68ki_write_32(ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(ea+4, (UINT32)(data));
+ break;
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32();
+ m68ki_write_32(ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(ea+4, (UINT32)(data));
+ break;
+ }
+ default: fatalerror("MC68040: WRITE_EA_64: unhandled mode %d, reg %d, data %08X%08X at %08X\n", mode, reg, (UINT32)(data >> 32), (UINT32)(data), REG_PC);
+ }
+}
+
+static fp_reg READ_EA_FPE(int ea)
+{
+ fp_reg r;
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ // TODO: convert to extended floating-point!
+
+ switch (mode)
+ {
+ case 3: // (An)+
+ {
+ UINT32 d1,d2,d3;
+ UINT32 ea = REG_A[reg];
+ REG_A[reg] += 12;
+ d1 = m68ki_read_32(ea+0);
+ d2 = m68ki_read_32(ea+4);
+ d3 = m68ki_read_32(ea+8);
+ r.i = (UINT64)(d1) << 32 | (UINT64)(d2);
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC);
+ }
+
+ return r;
+}
+
+static void WRITE_EA_FPE(int ea, fp_reg fpr)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ // TODO: convert to extended floating-point!
+
+ switch (mode)
+ {
+ case 4: // -(An)
+ {
+ UINT32 ea;
+ REG_A[reg] -= 12;
+ ea = REG_A[reg];
+ m68ki_write_32(ea+0, (UINT32)(fpr.i >> 32));
+ m68ki_write_32(ea+4, (UINT32)(fpr.i));
+ m68ki_write_32(ea+8, 0);
+ break;
+ }
+ default: fatalerror("MC68040: WRITE_EA_FPE: unhandled mode %d, reg %d, data %f at %08X\n", mode, reg, fpr.f, REG_PC);
+ }
+}
+
+
+static void fpgen_rm_reg(UINT16 w2)
+{
+ int ea = REG_IR & 0x3f;
+ int rm = (w2 >> 14) & 0x1;
+ int src = (w2 >> 10) & 0x7;
+ int dst = (w2 >> 7) & 0x7;
+ int opmode = w2 & 0x7f;
+ double source;
+
+ if (rm)
+ {
+ switch (src)
+ {
+ case 0: // Long-Word Integer
+ {
+ INT32 d = READ_EA_32(ea);
+ source = (double)(d);
+ break;
+ }
+ case 1: // Single-precision Real
+ {
+ UINT32 d = READ_EA_32(ea);
+ source = (double)(*(float*)&d);
+ break;
+ }
+ case 2: // Extended-precision Real
+ {
+ fatalerror("fpgen_rm_reg: extended-precision real load unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 3: // Packed-decimal Real
+ {
+ fatalerror("fpgen_rm_reg: packed-decimal real load unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 4: // Word Integer
+ {
+ INT16 d = READ_EA_16(ea);
+ source = (double)(d);
+ break;
+ }
+ case 5: // Double-precision Real
+ {
+ UINT64 d = READ_EA_64(ea);
+ source = *(double*)&d;
+ break;
+ }
+ case 6: // Byte Integer
+ {
+ INT8 d = READ_EA_8(ea);
+ source = (double)(d);
+ break;
+ }
+ default: fatalerror("fmove_rm_reg: invalid source specifier at %08X\n", REG_PC-4);
+ }
+ }
+ else
+ {
+ source = REG_FP[src].f;
+ }
+
+ switch (opmode)
+ {
+ case 0x00: // FMOVE
+ {
+ REG_FP[dst].f = source;
+ USE_CYCLES(4);
+ break;
+ }
+ case 0x04: // FSQRT
+ {
+ REG_FP[dst].f = sqrt(source);
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(109);
+ break;
+ }
+ case 0x18: // FABS
+ {
+ REG_FP[dst].f = fabs(source);
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(3);
+ break;
+ }
+ case 0x1a: // FNEG
+ {
+ REG_FP[dst].f = -source;
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(3);
+ break;
+ }
+ case 0x20: // FDIV
+ {
+ REG_FP[dst].f /= source;
+ USE_CYCLES(43);
+ break;
+ }
+ case 0x22: // FADD
+ {
+ REG_FP[dst].f += source;
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(9);
+ break;
+ }
+ case 0x23: // FMUL
+ {
+ REG_FP[dst].f *= source;
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(11);
+ break;
+ }
+ case 0x28: // FSUB
+ {
+ REG_FP[dst].f -= source;
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(9);
+ break;
+ }
+ case 0x38: // FCMP
+ {
+ fp_reg res;
+ res.f = REG_FP[dst].f - source;
+ SET_CONDITION_CODES(res);
+ USE_CYCLES(7);
+ break;
+ }
+ case 0x3a: // FTST
+ {
+ fp_reg res;
+ res.f = source;
+ SET_CONDITION_CODES(res);
+ USE_CYCLES(7);
+ break;
+ }
+
+ default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PC-4);
+ }
+}
+
+static void fmove_reg_mem(UINT16 w2)
+{
+ int ea = REG_IR & 0x3f;
+ int src = (w2 >> 7) & 0x7;
+ int dst = (w2 >> 10) & 0x7;
+ //int kfactor = w2 & 0x7f;
+
+ switch (dst)
+ {
+ case 0: // Long-Word Integer
+ {
+ INT32 d = (INT32)(REG_FP[src].f);
+ WRITE_EA_32(ea, d);
+ break;
+ }
+ case 1: // Single-precision Real
+ {
+ float f = (float)(REG_FP[src].f);
+ UINT32 d = *(UINT32 *)&f;
+ WRITE_EA_32(ea, d);
+ break;
+ }
+ case 2: // Extended-precision Real
+ {
+ fatalerror("fmove_reg_mem: extended-precision real store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 3: // Packed-decimal Real with Static K-factor
+ {
+ fatalerror("fmove_reg_mem: packed-decimal real store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 4: // Word Integer
+ {
+ fatalerror("fmove_reg_mem: word integer store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 5: // Double-precision Real
+ {
+ UINT64 d = REG_FP[src].i;
+ WRITE_EA_64(ea, d);
+ break;
+ }
+ case 6: // Byte Integer
+ {
+ fatalerror("fmove_reg_mem: byte integer store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 7: // Packed-decimal Real with Dynamic K-factor
+ {
+ fatalerror("fmove_reg_mem: packed-decimal real store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ }
+
+ USE_CYCLES(12);
+}
+
+static void fmove_fpcr(UINT16 w2)
+{
+ int ea = REG_IR & 0x3f;
+ int dir = (w2 >> 13) & 0x1;
+ int reg = (w2 >> 10) & 0x7;
+
+ if (dir) // From system control reg to <ea>
+ {
+ switch (reg)
+ {
+ case 1: WRITE_EA_32(ea, REG_FPIAR); break;
+ case 2: WRITE_EA_32(ea, REG_FPSR); break;
+ case 4: WRITE_EA_32(ea, REG_FPCR); break;
+ default: fatalerror("fmove_fpcr: unknown reg %d, dir %d\n", reg, dir);
+ }
+ }
+ else // From <ea> to system control reg
+ {
+ switch (reg)
+ {
+ case 1: REG_FPIAR = READ_EA_32(ea); break;
+ case 2: REG_FPSR = READ_EA_32(ea); break;
+ case 4: REG_FPCR = READ_EA_32(ea); break;
+ default: fatalerror("fmove_fpcr: unknown reg %d, dir %d\n", reg, dir);
+ }
+ }
+
+ USE_CYCLES(10);
+}
+
+static void fmovem(UINT16 w2)
+{
+ int i;
+ int ea = REG_IR & 0x3f;
+ int dir = (w2 >> 13) & 0x1;
+ int mode = (w2 >> 11) & 0x3;
+ int reglist = w2 & 0xff;
+
+ if (dir) // From FP regs to mem
+ {
+ switch (mode)
+ {
+ case 0: // Static register list, predecrement addressing mode
+ {
+ for (i=0; i < 8; i++)
+ {
+ if (reglist & (1 << i))
+ {
+ WRITE_EA_FPE(ea, REG_FP[i]);
+ USE_CYCLES(2);
+ }
+ }
+ break;
+ }
+
+ default: fatalerror("040fpu0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
+ }
+ }
+ else // From mem to FP regs
+ {
+ switch (mode)
+ {
+ case 2: // Static register list, postincrement addressing mode
+ {
+ for (i=0; i < 8; i++)
+ {
+ if (reglist & (1 << i))
+ {
+ REG_FP[7-i] = READ_EA_FPE(ea);
+ USE_CYCLES(2);
+ }
+ }
+ break;
+ }
+
+ default: fatalerror("040fpu0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
+ }
+ }
+}
+
+static void fbcc16(void)
+{
+ INT32 offset;
+ int condition = REG_IR & 0x3f;
+
+ offset = (INT16)(OPER_I_16());
+
+ // TODO: condition and jump!!!
+ if (TEST_CONDITION(condition))
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_16(offset-2);
+ }
+
+ USE_CYCLES(7);
+}
+
+static void fbcc32(void)
+{
+ INT32 offset;
+ int condition = REG_IR & 0x3f;
+
+ offset = OPER_I_32();
+
+ // TODO: condition and jump!!!
+ if (TEST_CONDITION(condition))
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_32(offset-4);
+ }
+
+ USE_CYCLES(7);
+}
+
+
+void m68040_fpu_op0(void)
+{
+ switch ((REG_IR >> 6) & 0x3)
+ {
+ case 0:
+ {
+ UINT16 w2 = OPER_I_16();
+ switch ((w2 >> 13) & 0x7)
+ {
+ case 0x0: // FPU ALU FP, FP
+ case 0x2: // FPU ALU ea, FP
+ {
+ fpgen_rm_reg(w2);
+ break;
+ }
+
+ case 0x3: // FMOVE FP, ea
+ {
+ fmove_reg_mem(w2);
+ break;
+ }
+
+ case 0x4: // FMOVE ea, FPCR
+ case 0x5: // FMOVE FPCR, ea
+ {
+ fmove_fpcr(w2);
+ break;
+ }
+
+ case 0x6: // FMOVEM ea, list
+ case 0x7: // FMOVEM list, ea
+ {
+ fmovem(w2);
+ break;
+ }
+
+ default: fatalerror("m68040_fpu_op0: unimplemented subop %d at %08X\n", (w2 >> 13) & 0x7, REG_PC-4);
+ }
+ break;
+ }
+
+ case 2: // FBcc disp16
+ {
+ fbcc16();
+ break;
+ }
+ case 3: // FBcc disp32
+ {
+ fbcc32();
+ break;
+ }
+
+ default: fatalerror("m68040_fpu_op0: unimplemented main op %d\n", (REG_IR >> 6) & 0x3);
+ }
+}
+
+void m68040_fpu_op1(void)
+{
+ int ea = REG_IR & 0x3f;
+
+ switch ((REG_IR >> 6) & 0x3)
+ {
+ case 0: // FSAVE <ea>
+ {
+ WRITE_EA_32(ea, 0x00000000);
+ // TODO: correct state frame
+ break;
+ }
+
+ case 1: // FRESTORE <ea>
+ {
+ READ_EA_32(ea);
+ // TODO: correct state frame
+ break;
+ }
+
+ default: fatalerror("m68040_fpu_op1: unimplemented op %d at %08X\n", (REG_IR >> 6) & 0x3, REG_PC-2);
+ }
+}
+
+
+
diff --git a/src/emu/cpu/m68000/m68kmake.c b/src/emu/cpu/m68000/m68kmake.c
new file mode 100644
index 00000000000..bf4fc741748
--- /dev/null
+++ b/src/emu/cpu/m68000/m68kmake.c
@@ -0,0 +1,1433 @@
+/* ======================================================================== */
+/* ========================= LICENSING & COPYRIGHT ======================== */
+/* ======================================================================== */
+/*
+ * MUSASHI
+ * Version 3.31
+ *
+ * A portable Motorola M680x0 processor emulation engine.
+ * Copyright 1998-2007 Karl Stenerud. All rights reserved.
+ *
+ * This code may be freely used for non-commercial purposes as long as this
+ * copyright notice remains unaltered in the source code and any binary files
+ * containing this code in compiled form.
+ *
+ * All other lisencing terms must be negotiated with the author
+ * (Karl Stenerud).
+ *
+ * The latest version of this code can be obtained at:
+ * http://kstenerud.cjb.net
+ */
+
+/*
+ * Modified For OpenVMS By: Robert Alan Byer
+ * byer@mail.ourservers.net
+ */
+
+
+/* ======================================================================== */
+/* ============================ CODE GENERATOR ============================ */
+/* ======================================================================== */
+/*
+ * This is the code generator program which will generate the opcode table
+ * and the final opcode handlers.
+ *
+ * It requires an input file to function (default m68k_in.c), but you can
+ * specify your own like so:
+ *
+ * m68kmake <output path> <input file>
+ *
+ * where output path is the path where the output files should be placed, and
+ * input file is the file to use for input.
+ *
+ * If you modify the input file greatly from its released form, you may have
+ * to tweak the configuration section a bit since I'm using static allocation
+ * to keep things simple.
+ *
+ *
+ * TODO: - build a better code generator for the move instruction.
+ * - Add callm and rtm instructions
+ * - Fix RTE to handle other format words
+ * - Add address error (and bus error?) handling
+ */
+
+
+static const char* g_version = "3.31";
+
+/* ======================================================================== */
+/* =============================== INCLUDES =============================== */
+/* ======================================================================== */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+
+
+/* ======================================================================== */
+/* ============================= CONFIGURATION ============================ */
+/* ======================================================================== */
+
+#define M68K_MAX_PATH 1024
+#define M68K_MAX_DIR 1024
+
+#define MAX_LINE_LENGTH 200 /* length of 1 line */
+#define MAX_BODY_LENGTH 300 /* Number of lines in 1 function */
+#define MAX_REPLACE_LENGTH 30 /* Max number of replace strings */
+#define MAX_INSERT_LENGTH 5000 /* Max size of insert piece */
+#define MAX_NAME_LENGTH 30 /* Max length of ophandler name */
+#define MAX_SPEC_PROC_LENGTH 4 /* Max length of special processing str */
+#define MAX_SPEC_EA_LENGTH 5 /* Max length of specified EA str */
+#define EA_ALLOWED_LENGTH 11 /* Max length of ea allowed str */
+#define MAX_OPCODE_INPUT_TABLE_LENGTH 1000 /* Max length of opcode handler tbl */
+#define MAX_OPCODE_OUTPUT_TABLE_LENGTH 3000 /* Max length of opcode handler tbl */
+
+/* Default filenames */
+#define FILENAME_INPUT "m68k_in.c"
+#define FILENAME_PROTOTYPE "m68kops.h"
+#define FILENAME_TABLE "m68kops.c"
+
+
+/* Identifier sequences recognized by this program */
+
+#define ID_INPUT_SEPARATOR "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+
+#define ID_BASE "M68KMAKE"
+#define ID_PROTOTYPE_HEADER ID_BASE "_PROTOTYPE_HEADER"
+#define ID_PROTOTYPE_FOOTER ID_BASE "_PROTOTYPE_FOOTER"
+#define ID_TABLE_HEADER ID_BASE "_TABLE_HEADER"
+#define ID_TABLE_FOOTER ID_BASE "_TABLE_FOOTER"
+#define ID_TABLE_BODY ID_BASE "_TABLE_BODY"
+#define ID_TABLE_START ID_BASE "_TABLE_START"
+#define ID_OPHANDLER_HEADER ID_BASE "_OPCODE_HANDLER_HEADER"
+#define ID_OPHANDLER_FOOTER ID_BASE "_OPCODE_HANDLER_FOOTER"
+#define ID_OPHANDLER_BODY ID_BASE "_OPCODE_HANDLER_BODY"
+#define ID_END ID_BASE "_END"
+
+#define ID_OPHANDLER_NAME ID_BASE "_OP"
+#define ID_OPHANDLER_EA_AY_8 ID_BASE "_GET_EA_AY_8"
+#define ID_OPHANDLER_EA_AY_16 ID_BASE "_GET_EA_AY_16"
+#define ID_OPHANDLER_EA_AY_32 ID_BASE "_GET_EA_AY_32"
+#define ID_OPHANDLER_OPER_AY_8 ID_BASE "_GET_OPER_AY_8"
+#define ID_OPHANDLER_OPER_AY_16 ID_BASE "_GET_OPER_AY_16"
+#define ID_OPHANDLER_OPER_AY_32 ID_BASE "_GET_OPER_AY_32"
+#define ID_OPHANDLER_CC ID_BASE "_CC"
+#define ID_OPHANDLER_NOT_CC ID_BASE "_NOT_CC"
+
+
+#ifndef DECL_SPEC
+#define DECL_SPEC
+#endif /* DECL_SPEC */
+
+
+
+/* ======================================================================== */
+/* ============================== PROTOTYPES ============================== */
+/* ======================================================================== */
+
+enum {
+ CPU_TYPE_000 = 0,
+ CPU_TYPE_010,
+ CPU_TYPE_020,
+ CPU_TYPE_040,
+ NUM_CPUS
+};
+
+#define UNSPECIFIED "."
+#define UNSPECIFIED_CH '.'
+
+#define HAS_NO_EA_MODE(A) (strcmp(A, "..........") == 0)
+#define HAS_EA_AI(A) ((A)[0] == 'A')
+#define HAS_EA_PI(A) ((A)[1] == '+')
+#define HAS_EA_PD(A) ((A)[2] == '-')
+#define HAS_EA_DI(A) ((A)[3] == 'D')
+#define HAS_EA_IX(A) ((A)[4] == 'X')
+#define HAS_EA_AW(A) ((A)[5] == 'W')
+#define HAS_EA_AL(A) ((A)[6] == 'L')
+#define HAS_EA_PCDI(A) ((A)[7] == 'd')
+#define HAS_EA_PCIX(A) ((A)[8] == 'x')
+#define HAS_EA_I(A) ((A)[9] == 'I')
+
+enum
+{
+ EA_MODE_NONE, /* No special addressing mode */
+ EA_MODE_AI, /* Address register indirect */
+ EA_MODE_PI, /* Address register indirect with postincrement */
+ EA_MODE_PI7, /* Address register 7 indirect with postincrement */
+ EA_MODE_PD, /* Address register indirect with predecrement */
+ EA_MODE_PD7, /* Address register 7 indirect with predecrement */
+ EA_MODE_DI, /* Address register indirect with displacement */
+ EA_MODE_IX, /* Address register indirect with index */
+ EA_MODE_AW, /* Absolute word */
+ EA_MODE_AL, /* Absolute long */
+ EA_MODE_PCDI, /* Program counter indirect with displacement */
+ EA_MODE_PCIX, /* Program counter indirect with index */
+ EA_MODE_I /* Immediate */
+};
+
+
+/* Everything we need to know about an opcode */
+typedef struct
+{
+ char name[MAX_NAME_LENGTH]; /* opcode handler name */
+ unsigned char size; /* Size of operation */
+ char spec_proc[MAX_SPEC_PROC_LENGTH]; /* Special processing mode */
+ char spec_ea[MAX_SPEC_EA_LENGTH]; /* Specified effective addressing mode */
+ unsigned char bits; /* Number of significant bits (used for sorting the table) */
+ unsigned short op_mask; /* Mask to apply for matching an opcode to a handler */
+ unsigned short op_match; /* Value to match after masking */
+ char ea_allowed[EA_ALLOWED_LENGTH]; /* Effective addressing modes allowed */
+ char cpu_mode[NUM_CPUS]; /* User or supervisor mode */
+ char cpus[NUM_CPUS+1]; /* Allowed CPUs */
+ unsigned char cycles[NUM_CPUS]; /* cycles for 000, 010, 020 */
+} opcode_struct;
+
+
+/* All modifications necessary for a specific EA mode of an instruction */
+typedef struct
+{
+ const char* fname_add;
+ const char* ea_add;
+ unsigned int mask_add;
+ unsigned int match_add;
+} ea_info_struct;
+
+
+/* Holds the body of a function */
+typedef struct
+{
+ char body[MAX_BODY_LENGTH][MAX_LINE_LENGTH+1];
+ int length;
+} body_struct;
+
+
+/* Holds a sequence of search / replace strings */
+typedef struct
+{
+ char replace[MAX_REPLACE_LENGTH][2][MAX_LINE_LENGTH+1];
+ int length;
+} replace_struct;
+
+
+/* Function Prototypes */
+void error_exit(const char* fmt, ...);
+void perror_exit(const char* fmt, ...);
+int check_strsncpy(char* dst, char* src, int maxlength);
+int check_atoi(char* str, int *result);
+int skip_spaces(char* str);
+int num_bits(int value);
+int atoh(char* buff);
+int fgetline(char* buff, int nchars, FILE* file);
+int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type);
+opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea);
+opcode_struct* find_illegal_opcode(void);
+int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea);
+void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str);
+void write_body(FILE* filep, body_struct* body, replace_struct* replace);
+void get_base_name(char* base_name, opcode_struct* op);
+void write_prototype(FILE* filep, char* base_name);
+void write_function_name(FILE* filep, char* base_name);
+void add_opcode_output_table_entry(opcode_struct* op, char* name);
+static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr);
+void print_opcode_output_table(FILE* filep);
+void write_table_entry(FILE* filep, opcode_struct* op);
+void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode);
+void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode);
+void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op);
+void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset);
+void process_opcode_handlers(FILE* filep);
+void populate_table(void);
+void read_insert(char* insert);
+
+
+
+/* ======================================================================== */
+/* ================================= DATA ================================= */
+/* ======================================================================== */
+
+/* Name of the input file */
+char g_input_filename[M68K_MAX_PATH] = FILENAME_INPUT;
+
+/* File handles */
+FILE* g_input_file = NULL;
+FILE* g_prototype_file = NULL;
+FILE* g_table_file = NULL;
+
+int g_num_functions = 0; /* Number of functions processed */
+int g_num_primitives = 0; /* Number of function primitives read */
+int g_line_number = 1; /* Current line number */
+
+/* Opcode handler table */
+opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];
+
+opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH];
+int g_opcode_output_table_length = 0;
+
+ea_info_struct g_ea_info_table[13] =
+{/* fname ea mask match */
+ {"", "", 0x00, 0x00}, /* EA_MODE_NONE */
+ {"ai", "AY_AI", 0x38, 0x10}, /* EA_MODE_AI */
+ {"pi", "AY_PI", 0x38, 0x18}, /* EA_MODE_PI */
+ {"pi7", "A7_PI", 0x3f, 0x1f}, /* EA_MODE_PI7 */
+ {"pd", "AY_PD", 0x38, 0x20}, /* EA_MODE_PD */
+ {"pd7", "A7_PD", 0x3f, 0x27}, /* EA_MODE_PD7 */
+ {"di", "AY_DI", 0x38, 0x28}, /* EA_MODE_DI */
+ {"ix", "AY_IX", 0x38, 0x30}, /* EA_MODE_IX */
+ {"aw", "AW", 0x3f, 0x38}, /* EA_MODE_AW */
+ {"al", "AL", 0x3f, 0x39}, /* EA_MODE_AL */
+ {"pcdi", "PCDI", 0x3f, 0x3a}, /* EA_MODE_PCDI */
+ {"pcix", "PCIX", 0x3f, 0x3b}, /* EA_MODE_PCIX */
+ {"i", "I", 0x3f, 0x3c}, /* EA_MODE_I */
+};
+
+
+const char* g_cc_table[16][2] =
+{
+ { "t", "T"}, /* 0000 */
+ { "f", "F"}, /* 0001 */
+ {"hi", "HI"}, /* 0010 */
+ {"ls", "LS"}, /* 0011 */
+ {"cc", "CC"}, /* 0100 */
+ {"cs", "CS"}, /* 0101 */
+ {"ne", "NE"}, /* 0110 */
+ {"eq", "EQ"}, /* 0111 */
+ {"vc", "VC"}, /* 1000 */
+ {"vs", "VS"}, /* 1001 */
+ {"pl", "PL"}, /* 1010 */
+ {"mi", "MI"}, /* 1011 */
+ {"ge", "GE"}, /* 1100 */
+ {"lt", "LT"}, /* 1101 */
+ {"gt", "GT"}, /* 1110 */
+ {"le", "LE"}, /* 1111 */
+};
+
+/* size to index translator (0 -> 0, 8 and 16 -> 1, 32 -> 2) */
+int g_size_select_table[33] =
+{
+ 0, /* unsized */
+ 0, 0, 0, 0, 0, 0, 0, 1, /* 8 */
+ 0, 0, 0, 0, 0, 0, 0, 1, /* 16 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 /* 32 */
+};
+
+/* Extra cycles required for certain EA modes */
+/* TODO: correct timings for 040 */
+int g_ea_cycle_table[13][NUM_CPUS][3] =
+{/* 000 010 020 040 */
+ {{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, /* EA_MODE_NONE */
+ {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AI */
+ {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI */
+ {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI7 */
+ {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD */
+ {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD7 */
+ {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_DI */
+ {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_IX */
+ {{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AW */
+ {{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AL */
+ {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PCDI */
+ {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_PCIX */
+ {{ 0, 4, 8}, { 0, 4, 8}, { 0, 2, 4}, { 0, 2, 4}}, /* EA_MODE_I */
+};
+
+/* Extra cycles for JMP instruction (000, 010) */
+int g_jmp_cycle_table[13] =
+{
+ 0, /* EA_MODE_NONE */
+ 4, /* EA_MODE_AI */
+ 0, /* EA_MODE_PI */
+ 0, /* EA_MODE_PI7 */
+ 0, /* EA_MODE_PD */
+ 0, /* EA_MODE_PD7 */
+ 6, /* EA_MODE_DI */
+ 10, /* EA_MODE_IX */
+ 6, /* EA_MODE_AW */
+ 8, /* EA_MODE_AL */
+ 6, /* EA_MODE_PCDI */
+ 10, /* EA_MODE_PCIX */
+ 0, /* EA_MODE_I */
+};
+
+/* Extra cycles for JSR instruction (000, 010) */
+int g_jsr_cycle_table[13] =
+{
+ 0, /* EA_MODE_NONE */
+ 4, /* EA_MODE_AI */
+ 0, /* EA_MODE_PI */
+ 0, /* EA_MODE_PI7 */
+ 0, /* EA_MODE_PD */
+ 0, /* EA_MODE_PD7 */
+ 6, /* EA_MODE_DI */
+ 10, /* EA_MODE_IX */
+ 6, /* EA_MODE_AW */
+ 8, /* EA_MODE_AL */
+ 6, /* EA_MODE_PCDI */
+ 10, /* EA_MODE_PCIX */
+ 0, /* EA_MODE_I */
+};
+
+/* Extra cycles for LEA instruction (000, 010) */
+int g_lea_cycle_table[13] =
+{
+ 0, /* EA_MODE_NONE */
+ 4, /* EA_MODE_AI */
+ 0, /* EA_MODE_PI */
+ 0, /* EA_MODE_PI7 */
+ 0, /* EA_MODE_PD */
+ 0, /* EA_MODE_PD7 */
+ 8, /* EA_MODE_DI */
+ 12, /* EA_MODE_IX */
+ 8, /* EA_MODE_AW */
+ 12, /* EA_MODE_AL */
+ 8, /* EA_MODE_PCDI */
+ 12, /* EA_MODE_PCIX */
+ 0, /* EA_MODE_I */
+};
+
+/* Extra cycles for PEA instruction (000, 010) */
+int g_pea_cycle_table[13] =
+{
+ 0, /* EA_MODE_NONE */
+ 6, /* EA_MODE_AI */
+ 0, /* EA_MODE_PI */
+ 0, /* EA_MODE_PI7 */
+ 0, /* EA_MODE_PD */
+ 0, /* EA_MODE_PD7 */
+ 10, /* EA_MODE_DI */
+ 14, /* EA_MODE_IX */
+ 10, /* EA_MODE_AW */
+ 14, /* EA_MODE_AL */
+ 10, /* EA_MODE_PCDI */
+ 14, /* EA_MODE_PCIX */
+ 0, /* EA_MODE_I */
+};
+
+/* Extra cycles for MOVEM instruction (000, 010) */
+int g_movem_cycle_table[13] =
+{
+ 0, /* EA_MODE_NONE */
+ 0, /* EA_MODE_AI */
+ 0, /* EA_MODE_PI */
+ 0, /* EA_MODE_PI7 */
+ 0, /* EA_MODE_PD */
+ 0, /* EA_MODE_PD7 */
+ 4, /* EA_MODE_DI */
+ 6, /* EA_MODE_IX */
+ 4, /* EA_MODE_AW */
+ 8, /* EA_MODE_AL */
+ 0, /* EA_MODE_PCDI */
+ 0, /* EA_MODE_PCIX */
+ 0, /* EA_MODE_I */
+};
+
+/* Extra cycles for MOVES instruction (010) */
+int g_moves_cycle_table[13][3] =
+{
+ { 0, 0, 0}, /* EA_MODE_NONE */
+ { 0, 4, 6}, /* EA_MODE_AI */
+ { 0, 4, 6}, /* EA_MODE_PI */
+ { 0, 4, 6}, /* EA_MODE_PI7 */
+ { 0, 6, 12}, /* EA_MODE_PD */
+ { 0, 6, 12}, /* EA_MODE_PD7 */
+ { 0, 12, 16}, /* EA_MODE_DI */
+ { 0, 16, 20}, /* EA_MODE_IX */
+ { 0, 12, 16}, /* EA_MODE_AW */
+ { 0, 16, 20}, /* EA_MODE_AL */
+ { 0, 0, 0}, /* EA_MODE_PCDI */
+ { 0, 0, 0}, /* EA_MODE_PCIX */
+ { 0, 0, 0}, /* EA_MODE_I */
+};
+
+/* Extra cycles for CLR instruction (010) */
+int g_clr_cycle_table[13][3] =
+{
+ { 0, 0, 0}, /* EA_MODE_NONE */
+ { 0, 4, 6}, /* EA_MODE_AI */
+ { 0, 4, 6}, /* EA_MODE_PI */
+ { 0, 4, 6}, /* EA_MODE_PI7 */
+ { 0, 6, 8}, /* EA_MODE_PD */
+ { 0, 6, 8}, /* EA_MODE_PD7 */
+ { 0, 8, 10}, /* EA_MODE_DI */
+ { 0, 10, 14}, /* EA_MODE_IX */
+ { 0, 8, 10}, /* EA_MODE_AW */
+ { 0, 10, 14}, /* EA_MODE_AL */
+ { 0, 0, 0}, /* EA_MODE_PCDI */
+ { 0, 0, 0}, /* EA_MODE_PCIX */
+ { 0, 0, 0}, /* EA_MODE_I */
+};
+
+
+
+/* ======================================================================== */
+/* =========================== UTILITY FUNCTIONS ========================== */
+/* ======================================================================== */
+
+/* Print an error message and exit with status error */
+void error_exit(const char* fmt, ...)
+{
+ va_list args;
+ fprintf(stderr, "In %s, near or on line %d:\n\t", g_input_filename, g_line_number);
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+
+ if(g_prototype_file) fclose(g_prototype_file);
+ if(g_table_file) fclose(g_table_file);
+ if(g_input_file) fclose(g_input_file);
+
+ exit(EXIT_FAILURE);
+}
+
+/* Print an error message, call perror(), and exit with status error */
+void perror_exit(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ perror("");
+
+ if(g_prototype_file) fclose(g_prototype_file);
+ if(g_table_file) fclose(g_table_file);
+ if(g_input_file) fclose(g_input_file);
+
+ exit(EXIT_FAILURE);
+}
+
+
+/* copy until 0 or space and exit with error if we read too far */
+int check_strsncpy(char* dst, char* src, int maxlength)
+{
+ char* p = dst;
+ while(*src && *src != ' ')
+ {
+ *p++ = *src++;
+ if(p - dst > maxlength)
+ error_exit("Field too long");
+ }
+ *p = 0;
+ return p - dst;
+}
+
+/* copy until 0 or specified character and exit with error if we read too far */
+int check_strcncpy(char* dst, char* src, char delim, int maxlength)
+{
+ char* p = dst;
+ while(*src && *src != delim)
+ {
+ *p++ = *src++;
+ if(p - dst > maxlength)
+ error_exit("Field too long");
+ }
+ *p = 0;
+ return p - dst;
+}
+
+/* convert ascii to integer and exit with error if we find invalid data */
+int check_atoi(char* str, int *result)
+{
+ int accum = 0;
+ char* p = str;
+ while(*p >= '0' && *p <= '9')
+ {
+ accum *= 10;
+ accum += *p++ - '0';
+ }
+ if(*p != ' ' && *p != 0)
+ error_exit("Malformed integer value (%c)", *p);
+ *result = accum;
+ return p - str;
+}
+
+/* Skip past spaces in a string */
+int skip_spaces(char* str)
+{
+ char* p = str;
+
+ while(*p == ' ')
+ p++;
+
+ return p - str;
+}
+
+/* Count the number of set bits in a value */
+int num_bits(int value)
+{
+ value = ((value & 0xaaaa) >> 1) + (value & 0x5555);
+ value = ((value & 0xcccc) >> 2) + (value & 0x3333);
+ value = ((value & 0xf0f0) >> 4) + (value & 0x0f0f);
+ value = ((value & 0xff00) >> 8) + (value & 0x00ff);
+ return value;
+}
+
+/* Convert a hex value written in ASCII */
+int atoh(char* buff)
+{
+ int accum = 0;
+
+ for(;;buff++)
+ {
+ if(*buff >= '0' && *buff <= '9')
+ {
+ accum <<= 4;
+ accum += *buff - '0';
+ }
+ else if(*buff >= 'a' && *buff <= 'f')
+ {
+ accum <<= 4;
+ accum += *buff - 'a' + 10;
+ }
+ else break;
+ }
+ return accum;
+}
+
+/* Get a line of text from a file, discarding any end-of-line characters */
+int fgetline(char* buff, int nchars, FILE* file)
+{
+ int length;
+
+ if(fgets(buff, nchars, file) == NULL)
+ return -1;
+ if(buff[0] == '\r')
+ memcpy(buff, buff + 1, nchars - 1);
+
+ length = strlen(buff);
+ while(length && (buff[length-1] == '\r' || buff[length-1] == '\n'))
+ length--;
+ buff[length] = 0;
+ g_line_number++;
+
+ return length;
+}
+
+
+
+/* ======================================================================== */
+/* =========================== HELPER FUNCTIONS =========================== */
+/* ======================================================================== */
+
+/* Calculate the number of cycles an opcode requires */
+int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type)
+{
+ int size = g_size_select_table[op->size];
+
+ if(op->cpus[cpu_type] == '.')
+ return 0;
+
+ if(cpu_type < CPU_TYPE_020)
+ {
+ if(cpu_type == CPU_TYPE_010)
+ {
+ if(strcmp(op->name, "moves") == 0)
+ return op->cycles[cpu_type] + g_moves_cycle_table[ea_mode][size];
+ if(strcmp(op->name, "clr") == 0)
+ return op->cycles[cpu_type] + g_clr_cycle_table[ea_mode][size];
+ }
+
+ /* ASG: added these cases -- immediate modes take 2 extra cycles here */
+ /* SV: but only when operating on long, and also on register direct mode */
+ if(cpu_type == CPU_TYPE_000 && (ea_mode == EA_MODE_I || ea_mode == EA_MODE_NONE) && op->size == 32 &&
+ ((strcmp(op->name, "add") == 0 && strcmp(op->spec_proc, "er") == 0) ||
+ strcmp(op->name, "adda") == 0 ||
+ (strcmp(op->name, "and") == 0 && strcmp(op->spec_proc, "er") == 0) ||
+ (strcmp(op->name, "or") == 0 && strcmp(op->spec_proc, "er") == 0) ||
+ (strcmp(op->name, "sub") == 0 && strcmp(op->spec_proc, "er") == 0) ||
+ strcmp(op->name, "suba") == 0))
+ return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2;
+
+ if(strcmp(op->name, "jmp") == 0)
+ return op->cycles[cpu_type] + g_jmp_cycle_table[ea_mode];
+ if(strcmp(op->name, "jsr") == 0)
+ return op->cycles[cpu_type] + g_jsr_cycle_table[ea_mode];
+ if(strcmp(op->name, "lea") == 0)
+ return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode];
+ if(strcmp(op->name, "pea") == 0)
+ return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode];
+ if(strcmp(op->name, "movem") == 0)
+ return op->cycles[cpu_type] + g_movem_cycle_table[ea_mode];
+ }
+ return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size];
+}
+
+/* Find an opcode in the opcode handler list */
+opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea)
+{
+ opcode_struct* op;
+
+
+ for(op = g_opcode_input_table;op->name != NULL;op++)
+ {
+ if( strcmp(name, op->name) == 0 &&
+ (size == op->size) &&
+ strcmp(spec_proc, op->spec_proc) == 0 &&
+ strcmp(spec_ea, op->spec_ea) == 0)
+ return op;
+ }
+ return NULL;
+}
+
+/* Specifically find the illegal opcode in the list */
+opcode_struct* find_illegal_opcode(void)
+{
+ opcode_struct* op;
+
+ for(op = g_opcode_input_table;op->name != NULL;op++)
+ {
+ if(strcmp(op->name, "illegal") == 0)
+ return op;
+ }
+ return NULL;
+}
+
+/* Parse an opcode handler name */
+int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea)
+{
+ char* ptr = strstr(src, ID_OPHANDLER_NAME);
+
+ if(ptr == NULL)
+ return 0;
+
+ ptr += strlen(ID_OPHANDLER_NAME) + 1;
+
+ ptr += check_strcncpy(name, ptr, ',', MAX_NAME_LENGTH);
+ if(*ptr != ',') return 0;
+ ptr++;
+ ptr += skip_spaces(ptr);
+
+ *size = atoi(ptr);
+ ptr = strstr(ptr, ",");
+ if(ptr == NULL) return 0;
+ ptr++;
+ ptr += skip_spaces(ptr);
+
+ ptr += check_strcncpy(spec_proc, ptr, ',', MAX_SPEC_PROC_LENGTH);
+ if(*ptr != ',') return 0;
+ ptr++;
+ ptr += skip_spaces(ptr);
+
+ ptr += check_strcncpy(spec_ea, ptr, ')', MAX_SPEC_EA_LENGTH);
+ if(*ptr != ')') return 0;
+ ptr++;
+ ptr += skip_spaces(ptr);
+
+ return 1;
+}
+
+
+/* Add a search/replace pair to a replace structure */
+void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str)
+{
+ if(replace->length >= MAX_REPLACE_LENGTH)
+ error_exit("overflow in replace structure");
+
+ strcpy(replace->replace[replace->length][0], search_str);
+ strcpy(replace->replace[replace->length++][1], replace_str);
+}
+
+/* Write a function body while replacing any selected strings */
+void write_body(FILE* filep, body_struct* body, replace_struct* replace)
+{
+ int i;
+ int j;
+ char* ptr;
+ char output[MAX_LINE_LENGTH+1];
+ char temp_buff[MAX_LINE_LENGTH+1];
+ int found;
+
+ for(i=0;i<body->length;i++)
+ {
+ strcpy(output, body->body[i]);
+ /* Check for the base directive header */
+ if(strstr(output, ID_BASE) != NULL)
+ {
+ /* Search for any text we need to replace */
+ found = 0;
+ for(j=0;j<replace->length;j++)
+ {
+ ptr = strstr(output, replace->replace[j][0]);
+ if(ptr)
+ {
+ /* We found something to replace */
+ found = 1;
+ strcpy(temp_buff, ptr+strlen(replace->replace[j][0]));
+ strcpy(ptr, replace->replace[j][1]);
+ strcat(ptr, temp_buff);
+ }
+ }
+ /* Found a directive with no matching replace string */
+ if(!found)
+ error_exit("Unknown " ID_BASE " directive");
+ }
+ fprintf(filep, "%s\n", output);
+ }
+ fprintf(filep, "\n\n");
+}
+
+/* Generate a base function name from an opcode struct */
+void get_base_name(char* base_name, opcode_struct* op)
+{
+ sprintf(base_name, "m68k_op_%s", op->name);
+ if(op->size > 0)
+ sprintf(base_name+strlen(base_name), "_%d", op->size);
+ if(strcmp(op->spec_proc, UNSPECIFIED) != 0)
+ sprintf(base_name+strlen(base_name), "_%s", op->spec_proc);
+ if(strcmp(op->spec_ea, UNSPECIFIED) != 0)
+ sprintf(base_name+strlen(base_name), "_%s", op->spec_ea);
+}
+
+/* Write the prototype of an opcode handler function */
+void write_prototype(FILE* filep, char* base_name)
+{
+ fprintf(filep, "void %s(void);\n", base_name);
+}
+
+/* Write the name of an opcode handler function */
+void write_function_name(FILE* filep, char* base_name)
+{
+ fprintf(filep, "void %s(void)\n", base_name);
+}
+
+void add_opcode_output_table_entry(opcode_struct* op, char* name)
+{
+ opcode_struct* ptr;
+ if(g_opcode_output_table_length > MAX_OPCODE_OUTPUT_TABLE_LENGTH)
+ error_exit("Opcode output table overflow");
+
+ ptr = g_opcode_output_table + g_opcode_output_table_length++;
+
+ *ptr = *op;
+ strcpy(ptr->name, name);
+ ptr->bits = num_bits(ptr->op_mask);
+}
+
+/*
+ * Comparison function for qsort()
+ * For entries with an equal number of set bits in
+ * the mask compare the match values
+ */
+static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr)
+{
+ const opcode_struct *a = aptr, *b = bptr;
+ if(a->bits != b->bits)
+ return a->bits - b->bits;
+ if(a->op_mask != b->op_mask)
+ return a->op_mask - b->op_mask;
+ return a->op_match - b->op_match;
+}
+
+void print_opcode_output_table(FILE* filep)
+{
+ int i;
+ qsort((void *)g_opcode_output_table, g_opcode_output_table_length, sizeof(g_opcode_output_table[0]), compare_nof_true_bits);
+
+ for(i=0;i<g_opcode_output_table_length;i++)
+ write_table_entry(filep, g_opcode_output_table+i);
+}
+
+/* Write an entry in the opcode handler table */
+void write_table_entry(FILE* filep, opcode_struct* op)
+{
+ int i;
+
+ fprintf(filep, "\t{%-28s, 0x%04x, 0x%04x, {",
+ op->name, op->op_mask, op->op_match);
+
+ for(i=0;i<NUM_CPUS;i++)
+ {
+ fprintf(filep, "%3d", op->cycles[i]);
+ if(i < NUM_CPUS-1)
+ fprintf(filep, ", ");
+ }
+
+ fprintf(filep, "}},\n");
+}
+
+/* Fill out an opcode struct with a specific addressing mode of the source opcode struct */
+void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode)
+{
+ int i;
+
+ *dst = *src;
+
+ for(i=0;i<NUM_CPUS;i++)
+ dst->cycles[i] = get_oper_cycles(dst, ea_mode, i);
+ if(strcmp(dst->spec_ea, UNSPECIFIED) == 0 && ea_mode != EA_MODE_NONE)
+ sprintf(dst->spec_ea, "%s", g_ea_info_table[ea_mode].fname_add);
+ dst->op_mask |= g_ea_info_table[ea_mode].mask_add;
+ dst->op_match |= g_ea_info_table[ea_mode].match_add;
+}
+
+
+/* Generate a final opcode handler from the provided data */
+void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode)
+{
+ char str[MAX_LINE_LENGTH+1];
+ opcode_struct* op = malloc(sizeof(opcode_struct));
+
+ /* Set the opcode structure and write the tables, prototypes, etc */
+ set_opcode_struct(opinfo, op, ea_mode);
+ get_base_name(str, op);
+ write_prototype(g_prototype_file, str);
+ add_opcode_output_table_entry(op, str);
+ write_function_name(filep, str);
+
+ /* Add any replace strings needed */
+ if(ea_mode != EA_MODE_NONE)
+ {
+ sprintf(str, "EA_%s_8()", g_ea_info_table[ea_mode].ea_add);
+ add_replace_string(replace, ID_OPHANDLER_EA_AY_8, str);
+ sprintf(str, "EA_%s_16()", g_ea_info_table[ea_mode].ea_add);
+ add_replace_string(replace, ID_OPHANDLER_EA_AY_16, str);
+ sprintf(str, "EA_%s_32()", g_ea_info_table[ea_mode].ea_add);
+ add_replace_string(replace, ID_OPHANDLER_EA_AY_32, str);
+ sprintf(str, "OPER_%s_8()", g_ea_info_table[ea_mode].ea_add);
+ add_replace_string(replace, ID_OPHANDLER_OPER_AY_8, str);
+ sprintf(str, "OPER_%s_16()", g_ea_info_table[ea_mode].ea_add);
+ add_replace_string(replace, ID_OPHANDLER_OPER_AY_16, str);
+ sprintf(str, "OPER_%s_32()", g_ea_info_table[ea_mode].ea_add);
+ add_replace_string(replace, ID_OPHANDLER_OPER_AY_32, str);
+ }
+
+ /* Now write the function body with the selected replace strings */
+ write_body(filep, body, replace);
+ g_num_functions++;
+ free(op);
+}
+
+/* Generate opcode variants based on available addressing modes */
+void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op)
+{
+ int old_length = replace->length;
+
+ /* No ea modes available for this opcode */
+ if(HAS_NO_EA_MODE(op->ea_allowed))
+ {
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_NONE);
+ return;
+ }
+
+ /* Check for and create specific opcodes for each available addressing mode */
+ if(HAS_EA_AI(op->ea_allowed))
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_AI);
+ replace->length = old_length;
+ if(HAS_EA_PI(op->ea_allowed))
+ {
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_PI);
+ replace->length = old_length;
+ if(op->size == 8)
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_PI7);
+ }
+ replace->length = old_length;
+ if(HAS_EA_PD(op->ea_allowed))
+ {
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_PD);
+ replace->length = old_length;
+ if(op->size == 8)
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_PD7);
+ }
+ replace->length = old_length;
+ if(HAS_EA_DI(op->ea_allowed))
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_DI);
+ replace->length = old_length;
+ if(HAS_EA_IX(op->ea_allowed))
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_IX);
+ replace->length = old_length;
+ if(HAS_EA_AW(op->ea_allowed))
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_AW);
+ replace->length = old_length;
+ if(HAS_EA_AL(op->ea_allowed))
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_AL);
+ replace->length = old_length;
+ if(HAS_EA_PCDI(op->ea_allowed))
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_PCDI);
+ replace->length = old_length;
+ if(HAS_EA_PCIX(op->ea_allowed))
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_PCIX);
+ replace->length = old_length;
+ if(HAS_EA_I(op->ea_allowed))
+ generate_opcode_handler(filep, body, replace, op, EA_MODE_I);
+ replace->length = old_length;
+}
+
+/* Generate variants of condition code opcodes */
+void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset)
+{
+ char repl[20];
+ char replnot[20];
+ int i;
+ int old_length = replace->length;
+ opcode_struct* op = malloc(sizeof(opcode_struct));
+
+ *op = *op_in;
+
+ op->op_mask |= 0x0f00;
+
+ /* Do all condition codes except t and f */
+ for(i=2;i<16;i++)
+ {
+ /* Add replace strings for this condition code */
+ sprintf(repl, "COND_%s()", g_cc_table[i][1]);
+ sprintf(replnot, "COND_NOT_%s()", g_cc_table[i][1]);
+
+ add_replace_string(replace, ID_OPHANDLER_CC, repl);
+ add_replace_string(replace, ID_OPHANDLER_NOT_CC, replnot);
+
+ /* Set the new opcode info */
+ strcpy(op->name+offset, g_cc_table[i][0]);
+
+ op->op_match = (op->op_match & 0xf0ff) | (i<<8);
+
+ /* Generate all opcode variants for this modified opcode */
+ generate_opcode_ea_variants(filep, body, replace, op);
+ /* Remove the above replace strings */
+ replace->length = old_length;
+ }
+ free(op);
+}
+
+/* Process the opcode handlers section of the input file */
+void process_opcode_handlers(FILE* filep)
+{
+ FILE* input_file = g_input_file;
+ char func_name[MAX_LINE_LENGTH+1];
+ char oper_name[MAX_LINE_LENGTH+1];
+ int oper_size;
+ char oper_spec_proc[MAX_LINE_LENGTH+1];
+ char oper_spec_ea[MAX_LINE_LENGTH+1];
+ opcode_struct* opinfo;
+ replace_struct* replace = malloc(sizeof(replace_struct));
+ body_struct* body = malloc(sizeof(body_struct));
+
+ for(;;)
+ {
+ /* Find the first line of the function */
+ func_name[0] = 0;
+ while(strstr(func_name, ID_OPHANDLER_NAME) == NULL)
+ {
+ if(strcmp(func_name, ID_INPUT_SEPARATOR) == 0)
+ {
+ free(replace);
+ free(body);
+ return; /* all done */
+ }
+ if(fgetline(func_name, MAX_LINE_LENGTH, input_file) < 0)
+ error_exit("Premature end of file when getting function name");
+ }
+ /* Get the rest of the function */
+ for(body->length=0;;body->length++)
+ {
+ if(body->length > MAX_BODY_LENGTH)
+ error_exit("Function too long");
+
+ if(fgetline(body->body[body->length], MAX_LINE_LENGTH, input_file) < 0)
+ error_exit("Premature end of file when getting function body");
+
+ if(body->body[body->length][0] == '}')
+ {
+ body->length++;
+ break;
+ }
+ }
+
+ g_num_primitives++;
+
+ /* Extract the function name information */
+ if(!extract_opcode_info(func_name, oper_name, &oper_size, oper_spec_proc, oper_spec_ea))
+ error_exit("Invalid " ID_OPHANDLER_NAME " format");
+
+ /* Find the corresponding table entry */
+ opinfo = find_opcode(oper_name, oper_size, oper_spec_proc, oper_spec_ea);
+ if(opinfo == NULL)
+ error_exit("Unable to find matching table entry for %s", func_name);
+
+ replace->length = 0;
+
+ /* Generate opcode variants */
+ if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0)
+ generate_opcode_cc_variants(filep, body, replace, opinfo, 1);
+ else if(strcmp(opinfo->name, "dbcc") == 0)
+ generate_opcode_cc_variants(filep, body, replace, opinfo, 2);
+ else if(strcmp(opinfo->name, "trapcc") == 0)
+ generate_opcode_cc_variants(filep, body, replace, opinfo, 4);
+ else
+ generate_opcode_ea_variants(filep, body, replace, opinfo);
+ }
+
+ free(replace);
+ free(body);
+}
+
+
+/* Populate the opcode handler table from the input file */
+void populate_table(void)
+{
+ char* ptr;
+ char bitpattern[17];
+ opcode_struct* op;
+ char buff[MAX_LINE_LENGTH];
+ int i;
+ int temp;
+
+ buff[0] = 0;
+
+ /* Find the start of the table */
+ while(strcmp(buff, ID_TABLE_START) != 0)
+ if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
+ error_exit("Premature EOF while reading table");
+
+ /* Process the entire table */
+ for(op = g_opcode_input_table;;op++)
+ {
+ if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
+ error_exit("Premature EOF while reading table");
+ if(strlen(buff) == 0)
+ continue;
+ /* We finish when we find an input separator */
+ if(strcmp(buff, ID_INPUT_SEPARATOR) == 0)
+ break;
+
+ /* Extract the info from the table */
+ ptr = buff;
+
+ /* Name */
+ ptr += skip_spaces(ptr);
+ ptr += check_strsncpy(op->name, ptr, MAX_NAME_LENGTH);
+
+ /* Size */
+ ptr += skip_spaces(ptr);
+ ptr += check_atoi(ptr, &temp);
+ op->size = (unsigned char)temp;
+
+ /* Special processing */
+ ptr += skip_spaces(ptr);
+ ptr += check_strsncpy(op->spec_proc, ptr, MAX_SPEC_PROC_LENGTH);
+
+ /* Specified EA Mode */
+ ptr += skip_spaces(ptr);
+ ptr += check_strsncpy(op->spec_ea, ptr, MAX_SPEC_EA_LENGTH);
+
+ /* Bit Pattern (more processing later) */
+ ptr += skip_spaces(ptr);
+ ptr += check_strsncpy(bitpattern, ptr, 17);
+
+ /* Allowed Addressing Mode List */
+ ptr += skip_spaces(ptr);
+ ptr += check_strsncpy(op->ea_allowed, ptr, EA_ALLOWED_LENGTH);
+
+ /* CPU operating mode (U = user or supervisor, S = supervisor only */
+ ptr += skip_spaces(ptr);
+ for(i=0;i<NUM_CPUS;i++)
+ {
+ op->cpu_mode[i] = *ptr++;
+ ptr += skip_spaces(ptr);
+ }
+
+ /* Allowed CPUs for this instruction */
+ for(i=0;i<NUM_CPUS;i++)
+ {
+ ptr += skip_spaces(ptr);
+ if(*ptr == UNSPECIFIED_CH)
+ {
+ op->cpus[i] = UNSPECIFIED_CH;
+ op->cycles[i] = 0;
+ ptr++;
+ }
+ else
+ {
+ op->cpus[i] = '0' + i;
+ ptr += check_atoi(ptr, &temp);
+ op->cycles[i] = (unsigned char)temp;
+ }
+ }
+
+ /* generate mask and match from bitpattern */
+ op->op_mask = 0;
+ op->op_match = 0;
+ for(i=0;i<16;i++)
+ {
+ op->op_mask |= (bitpattern[i] != '.') << (15-i);
+ op->op_match |= (bitpattern[i] == '1') << (15-i);
+ }
+ }
+ /* Terminate the list */
+ op->name[0] = 0;
+}
+
+/* Read a header or footer insert from the input file */
+void read_insert(char* insert)
+{
+ char* ptr = insert;
+ char* overflow = insert + MAX_INSERT_LENGTH - MAX_LINE_LENGTH;
+ int length;
+ char* first_blank = NULL;
+
+ first_blank = NULL;
+
+ /* Skip any leading blank lines */
+ for(length = 0;length == 0;length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file))
+ if(ptr >= overflow)
+ error_exit("Buffer overflow reading inserts");
+ if(length < 0)
+ error_exit("Premature EOF while reading inserts");
+
+ /* Advance and append newline */
+ ptr += length;
+ strcpy(ptr++, "\n");
+
+ /* Read until next separator */
+ for(;;)
+ {
+ /* Read a new line */
+ if(ptr >= overflow)
+ error_exit("Buffer overflow reading inserts");
+ if((length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) < 0)
+ error_exit("Premature EOF while reading inserts");
+
+ /* Stop if we read a separator */
+ if(strcmp(ptr, ID_INPUT_SEPARATOR) == 0)
+ break;
+
+ /* keep track in case there are trailing blanks */
+ if(length == 0)
+ {
+ if(first_blank == NULL)
+ first_blank = ptr;
+ }
+ else
+ first_blank = NULL;
+
+ /* Advance and append newline */
+ ptr += length;
+ strcpy(ptr++, "\n");
+ }
+
+ /* kill any trailing blank lines */
+ if(first_blank)
+ ptr = first_blank;
+ *ptr++ = 0;
+}
+
+
+
+/* ======================================================================== */
+/* ============================= MAIN FUNCTION ============================ */
+/* ======================================================================== */
+
+int main(int argc, char **argv)
+{
+ /* File stuff */
+ char output_path[M68K_MAX_DIR] = "";
+ char filename[M68K_MAX_PATH];
+ /* Section identifier */
+ char section_id[MAX_LINE_LENGTH+1];
+ /* Inserts */
+ char temp_insert[MAX_INSERT_LENGTH+1];
+ char prototype_footer_insert[MAX_INSERT_LENGTH+1];
+ char table_header_insert[MAX_INSERT_LENGTH+1];
+ char table_footer_insert[MAX_INSERT_LENGTH+1];
+ char ophandler_header_insert[MAX_INSERT_LENGTH+1];
+ char ophandler_footer_insert[MAX_INSERT_LENGTH+1];
+ /* Flags if we've processed certain parts already */
+ int prototype_header_read = 0;
+ int prototype_footer_read = 0;
+ int table_header_read = 0;
+ int table_footer_read = 0;
+ int ophandler_header_read = 0;
+ int ophandler_footer_read = 0;
+ int table_body_read = 0;
+ int ophandler_body_read = 0;
+
+ printf("\n\tMusashi v%s 68000, 68008, 68010, 68EC020, 68020, 68040 emulator\n", g_version);
+ printf("\tCopyright 1998-2007 Karl Stenerud (karl@mame.net)\n\n");
+
+ /* Check if output path and source for the input file are given */
+ if(argc > 1)
+ {
+ char *ptr;
+ strcpy(output_path, argv[1]);
+
+ for(ptr = strchr(output_path, '\\'); ptr; ptr = strchr(ptr, '\\'))
+ *ptr = '/';
+
+#if !(defined(__DECC) && defined(VMS))
+ if(output_path[strlen(output_path)-1] != '/')
+ strcat(output_path, "/");
+#endif
+
+ if(argc > 2)
+ strcpy(g_input_filename, argv[2]);
+ }
+
+
+#if defined(__DECC) && defined(VMS)
+
+ /* Open the files we need */
+ sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE);
+ if((g_prototype_file = fopen(filename, "w")) == NULL)
+ perror_exit("Unable to create prototype file (%s)\n", filename);
+
+ sprintf(filename, "%s%s", output_path, FILENAME_TABLE);
+ if((g_table_file = fopen(filename, "w")) == NULL)
+ perror_exit("Unable to create table file (%s)\n", filename);
+
+ if((g_input_file=fopen(g_input_filename, "r")) == NULL)
+ perror_exit("can't open %s for input", g_input_filename);
+
+#else
+
+
+ /* Open the files we need */
+ sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE);
+ if((g_prototype_file = fopen(filename, "wt")) == NULL)
+ perror_exit("Unable to create prototype file (%s)\n", filename);
+
+ sprintf(filename, "%s%s", output_path, FILENAME_TABLE);
+ if((g_table_file = fopen(filename, "wt")) == NULL)
+ perror_exit("Unable to create table file (%s)\n", filename);
+
+ if((g_input_file=fopen(g_input_filename, "rt")) == NULL)
+ perror_exit("can't open %s for input", g_input_filename);
+
+#endif
+
+ /* Get to the first section of the input file */
+ section_id[0] = 0;
+ while(strcmp(section_id, ID_INPUT_SEPARATOR) != 0)
+ if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)
+ error_exit("Premature EOF while reading input file");
+
+ /* Now process all sections */
+ for(;;)
+ {
+ if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)
+ error_exit("Premature EOF while reading input file");
+ if(strcmp(section_id, ID_PROTOTYPE_HEADER) == 0)
+ {
+ if(prototype_header_read)
+ error_exit("Duplicate prototype header");
+ read_insert(temp_insert);
+ fprintf(g_prototype_file, "%s\n\n", temp_insert);
+ prototype_header_read = 1;
+ }
+ else if(strcmp(section_id, ID_TABLE_HEADER) == 0)
+ {
+ if(table_header_read)
+ error_exit("Duplicate table header");
+ read_insert(table_header_insert);
+ table_header_read = 1;
+ }
+ else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0)
+ {
+ if(ophandler_header_read)
+ error_exit("Duplicate opcode handler header");
+ read_insert(ophandler_header_insert);
+ ophandler_header_read = 1;
+ }
+ else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0)
+ {
+ if(prototype_footer_read)
+ error_exit("Duplicate prototype footer");
+ read_insert(prototype_footer_insert);
+ prototype_footer_read = 1;
+ }
+ else if(strcmp(section_id, ID_TABLE_FOOTER) == 0)
+ {
+ if(table_footer_read)
+ error_exit("Duplicate table footer");
+ read_insert(table_footer_insert);
+ table_footer_read = 1;
+ }
+ else if(strcmp(section_id, ID_OPHANDLER_FOOTER) == 0)
+ {
+ if(ophandler_footer_read)
+ error_exit("Duplicate opcode handler footer");
+ read_insert(ophandler_footer_insert);
+ ophandler_footer_read = 1;
+ }
+ else if(strcmp(section_id, ID_TABLE_BODY) == 0)
+ {
+ if(!prototype_header_read)
+ error_exit("Table body encountered before prototype header");
+ if(!table_header_read)
+ error_exit("Table body encountered before table header");
+ if(!ophandler_header_read)
+ error_exit("Table body encountered before opcode handler header");
+
+ if(table_body_read)
+ error_exit("Duplicate table body");
+
+ populate_table();
+ table_body_read = 1;
+ }
+ else if(strcmp(section_id, ID_OPHANDLER_BODY) == 0)
+ {
+ if(!prototype_header_read)
+ error_exit("Opcode handlers encountered before prototype header");
+ if(!table_header_read)
+ error_exit("Opcode handlers encountered before table header");
+ if(!ophandler_header_read)
+ error_exit("Opcode handlers encountered before opcode handler header");
+ if(!table_body_read)
+ error_exit("Opcode handlers encountered before table body");
+
+ if(ophandler_body_read)
+ error_exit("Duplicate opcode handler section");
+
+ fprintf(g_table_file, "%s\n\n", ophandler_header_insert);
+ process_opcode_handlers(g_table_file);
+ fprintf(g_table_file, "%s\n\n", ophandler_footer_insert);
+
+ ophandler_body_read = 1;
+ }
+ else if(strcmp(section_id, ID_END) == 0)
+ {
+ /* End of input file. Do a sanity check and then write footers */
+ if(!prototype_header_read)
+ error_exit("Missing prototype header");
+ if(!prototype_footer_read)
+ error_exit("Missing prototype footer");
+ if(!table_header_read)
+ error_exit("Missing table header");
+ if(!table_footer_read)
+ error_exit("Missing table footer");
+ if(!table_body_read)
+ error_exit("Missing table body");
+ if(!ophandler_header_read)
+ error_exit("Missing opcode handler header");
+ if(!ophandler_footer_read)
+ error_exit("Missing opcode handler footer");
+ if(!ophandler_body_read)
+ error_exit("Missing opcode handler body");
+
+ fprintf(g_table_file, "%s\n\n", table_header_insert);
+ print_opcode_output_table(g_table_file);
+ fprintf(g_table_file, "%s\n\n", table_footer_insert);
+
+ fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert);
+
+ break;
+ }
+ else
+ {
+ error_exit("Unknown section identifier: %s", section_id);
+ }
+ }
+
+ /* Close all files and exit */
+ fclose(g_prototype_file);
+ fclose(g_table_file);
+ fclose(g_input_file);
+
+ printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives);
+
+ return 0;
+}
+
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
diff --git a/src/emu/cpu/m68000/m68kmame.c b/src/emu/cpu/m68000/m68kmame.c
new file mode 100644
index 00000000000..789c821c8a7
--- /dev/null
+++ b/src/emu/cpu/m68000/m68kmame.c
@@ -0,0 +1,1291 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "m68k.h"
+#include "m68000.h"
+
+/* global access */
+
+struct m68k_memory_interface m68k_memory_intf;
+offs_t m68k_encrypted_opcode_start[MAX_CPU];
+offs_t m68k_encrypted_opcode_end[MAX_CPU];
+
+
+void m68k_set_encrypted_opcode_range(int cpunum, offs_t start, offs_t end)
+{
+ m68k_encrypted_opcode_start[cpunum] = start;
+ m68k_encrypted_opcode_end[cpunum] = end;
+}
+
+/****************************************************************************
+ * 8-bit data memory interface
+ ****************************************************************************/
+
+static UINT16 readword_d8(offs_t address)
+{
+ UINT16 result = program_read_byte_8(address) << 8;
+ return result | program_read_byte_8(address + 1);
+}
+
+static void writeword_d8(offs_t address, UINT16 data)
+{
+ program_write_byte_8(address, data >> 8);
+ program_write_byte_8(address + 1, data);
+}
+
+static UINT32 readlong_d8(offs_t address)
+{
+ UINT32 result = program_read_byte_8(address) << 24;
+ result |= program_read_byte_8(address + 1) << 16;
+ result |= program_read_byte_8(address + 2) << 8;
+ return result | program_read_byte_8(address + 3);
+}
+
+static void writelong_d8(offs_t address, UINT32 data)
+{
+ program_write_byte_8(address, data >> 24);
+ program_write_byte_8(address + 1, data >> 16);
+ program_write_byte_8(address + 2, data >> 8);
+ program_write_byte_8(address + 3, data);
+}
+
+/* interface for 20/22-bit address bus, 8-bit data bus (68008) */
+static const struct m68k_memory_interface interface_d8 =
+{
+ 0,
+ program_read_byte_8,
+ readword_d8,
+ readlong_d8,
+ program_write_byte_8,
+ writeword_d8,
+ writelong_d8
+};
+
+/****************************************************************************
+ * 16-bit data memory interface
+ ****************************************************************************/
+
+static UINT32 readlong_d16(offs_t address)
+{
+ UINT32 result = program_read_word_16be(address) << 16;
+ return result | program_read_word_16be(address + 2);
+}
+
+static void writelong_d16(offs_t address, UINT32 data)
+{
+ program_write_word_16be(address, data >> 16);
+ program_write_word_16be(address + 2, data);
+}
+
+/* interface for 24-bit address bus, 16-bit data bus (68000, 68010) */
+static const struct m68k_memory_interface interface_d16 =
+{
+ 0,
+ program_read_byte_16be,
+ program_read_word_16be,
+ readlong_d16,
+ program_write_byte_16be,
+ program_write_word_16be,
+ writelong_d16
+};
+
+/****************************************************************************
+ * 32-bit data memory interface
+ ****************************************************************************/
+
+/* potentially misaligned 16-bit reads with a 32-bit data bus (and 24-bit address bus) */
+static UINT16 readword_d32(offs_t address)
+{
+ UINT16 result;
+
+ if (!(address & 1))
+ return program_read_word_32be(address);
+ result = program_read_byte_32be(address) << 8;
+ return result | program_read_byte_32be(address + 1);
+}
+
+/* potentially misaligned 16-bit writes with a 32-bit data bus (and 24-bit address bus) */
+static void writeword_d32(offs_t address, UINT16 data)
+{
+ if (!(address & 1))
+ {
+ program_write_word_32be(address, data);
+ return;
+ }
+ program_write_byte_32be(address, data >> 8);
+ program_write_byte_32be(address + 1, data);
+}
+
+/* potentially misaligned 32-bit reads with a 32-bit data bus (and 24-bit address bus) */
+static UINT32 readlong_d32(offs_t address)
+{
+ UINT32 result;
+
+ if (!(address & 3))
+ return program_read_dword_32be(address);
+ else if (!(address & 1))
+ {
+ result = program_read_word_32be(address) << 16;
+ return result | program_read_word_32be(address + 2);
+ }
+ result = program_read_byte_32be(address) << 24;
+ result |= program_read_word_32be(address + 1) << 8;
+ return result | program_read_byte_32be(address + 3);
+}
+
+/* potentially misaligned 32-bit writes with a 32-bit data bus (and 24-bit address bus) */
+static void writelong_d32(offs_t address, UINT32 data)
+{
+ if (!(address & 3))
+ {
+ program_write_dword_32be(address, data);
+ return;
+ }
+ else if (!(address & 1))
+ {
+ program_write_word_32be(address, data >> 16);
+ program_write_word_32be(address + 2, data);
+ return;
+ }
+ program_write_byte_32be(address, data >> 24);
+ program_write_word_32be(address + 1, data >> 8);
+ program_write_byte_32be(address + 3, data);
+}
+
+/* interface for 32-bit data bus (68EC020, 68020) */
+static const struct m68k_memory_interface interface_d32 =
+{
+ WORD_XOR_BE(0),
+ program_read_byte_32be,
+ readword_d32,
+ readlong_d32,
+ program_write_byte_32be,
+ writeword_d32,
+ writelong_d32
+};
+
+
+/* global access */
+struct m68k_memory_interface m68k_memory_intf;
+
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ irqline = 7;
+ switch(state)
+ {
+ case CLEAR_LINE:
+ m68k_set_irq(0);
+ break;
+ case ASSERT_LINE:
+ m68k_set_irq(irqline);
+ break;
+ default:
+ m68k_set_irq(irqline);
+ break;
+ }
+}
+
+
+/****************************************************************************
+ * 68000 section
+ ****************************************************************************/
+
+static void m68000_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m68k_init();
+ m68k_set_cpu_type(M68K_CPU_TYPE_68000);
+ m68k_memory_intf = interface_d16;
+ m68k_state_register("m68000", index);
+ m68k_set_int_ack_callback(irqcallback);
+}
+
+static void m68000_reset(void)
+{
+ m68k_pulse_reset();
+}
+
+static void m68000_exit(void)
+{
+ /* nothing to do */
+}
+
+static int m68000_execute(int cycles)
+{
+ return m68k_execute(cycles);
+}
+
+static void m68000_get_context(void *dst)
+{
+ m68k_get_context(dst);
+}
+
+static void m68000_set_context(void *src)
+{
+ if (m68k_memory_intf.read8 != program_read_byte_16be)
+ m68k_memory_intf = interface_d16;
+ m68k_set_context(src);
+}
+
+#ifdef MAME_DEBUG
+static offs_t m68000_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ M68K_SET_PC_CALLBACK(pc);
+ return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68000);
+}
+#endif /* MAME_DEBUG */
+
+/****************************************************************************
+ * M68008 section
+ ****************************************************************************/
+#if HAS_M68008
+
+static void m68008_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m68k_init();
+ m68k_set_cpu_type(M68K_CPU_TYPE_68008);
+ m68k_memory_intf = interface_d8;
+ m68k_state_register("m68008", index);
+ m68k_set_int_ack_callback(irqcallback);
+}
+
+static void m68008_reset(void)
+{
+ m68k_pulse_reset();
+}
+
+static void m68008_exit(void)
+{
+ /* nothing to do */
+}
+
+static int m68008_execute(int cycles)
+{
+ return m68k_execute(cycles);
+}
+
+static void m68008_get_context(void *dst)
+{
+ m68k_get_context(dst);
+}
+
+static void m68008_set_context(void *src)
+{
+ if (m68k_memory_intf.read8 != program_read_byte_8)
+ m68k_memory_intf = interface_d8;
+ m68k_set_context(src);
+}
+
+#ifdef MAME_DEBUG
+static offs_t m68008_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ M68K_SET_PC_CALLBACK(pc);
+ return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68008);
+}
+#endif /* MAME_DEBUG */
+
+#endif
+
+/****************************************************************************
+ * M68010 section
+ ****************************************************************************/
+#if HAS_M68010
+
+void m68010_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m68k_init();
+ m68k_set_cpu_type(M68K_CPU_TYPE_68010);
+ m68k_memory_intf = interface_d16;
+ m68k_state_register("m68010", index);
+ m68k_set_int_ack_callback(irqcallback);
+}
+
+#ifdef MAME_DEBUG
+static offs_t m68010_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ M68K_SET_PC_CALLBACK(pc);
+ return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68010);
+}
+#endif /* MAME_DEBUG */
+
+#endif /* HAS_M68010 */
+
+/****************************************************************************
+ * M68020 section
+ ****************************************************************************/
+
+static void m68020_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m68k_init();
+ m68k_set_cpu_type(M68K_CPU_TYPE_68020);
+ m68k_memory_intf = interface_d32;
+ m68k_state_register("m68020", index);
+ m68k_set_int_ack_callback(irqcallback);
+}
+
+static void m68020_reset(void)
+{
+ m68k_pulse_reset();
+}
+
+static void m68020_exit(void)
+{
+ /* nothing to do */
+}
+
+static int m68020_execute(int cycles)
+{
+ return m68k_execute(cycles);
+}
+
+static void m68020_get_context(void *dst)
+{
+ m68k_get_context(dst);
+}
+
+static void m68020_set_context(void *src)
+{
+ if (m68k_memory_intf.read8 != program_read_byte_32be)
+ m68k_memory_intf = interface_d32;
+ m68k_set_context(src);
+}
+
+#ifdef MAME_DEBUG
+static offs_t m68020_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ M68K_SET_PC_CALLBACK(pc);
+ return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68020);
+}
+#endif /* MAME_DEBUG */
+
+
+/****************************************************************************
+ * M680EC20 section
+ ****************************************************************************/
+#if HAS_M68EC020
+
+static void m68ec020_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m68k_init();
+ m68k_set_cpu_type(M68K_CPU_TYPE_68EC020);
+ m68k_memory_intf = interface_d32;
+ m68k_state_register("m68ec020", index);
+ m68k_set_int_ack_callback(irqcallback);
+}
+
+#ifdef MAME_DEBUG
+static offs_t m68ec020_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ M68K_SET_PC_CALLBACK(pc);
+ return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68EC020);
+}
+#endif /* MAME_DEBUG */
+
+#endif /* HAS_M68EC020 */
+
+/****************************************************************************
+ * M68040 section
+ ****************************************************************************/
+#if HAS_M68040
+
+static void m68040_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ m68k_init();
+ m68k_set_cpu_type(M68K_CPU_TYPE_68040);
+ m68k_memory_intf = interface_d32;
+ m68k_state_register("m68040", index);
+ m68k_set_int_ack_callback(irqcallback);
+}
+
+static void m68040_reset(void)
+{
+ m68k_pulse_reset();
+}
+
+static void m68040_exit(void)
+{
+ /* nothing to do */
+}
+
+static int m68040_execute(int cycles)
+{
+ return m68k_execute(cycles);
+}
+
+static void m68040_get_context(void *dst)
+{
+ m68k_get_context(dst);
+}
+
+static void m68040_set_context(void *src)
+{
+ if (m68k_memory_intf.read8 != program_read_byte_32be)
+ m68k_memory_intf = interface_d32;
+ m68k_set_context(src);
+}
+
+#ifdef MAME_DEBUG
+static offs_t m68040_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ M68K_SET_PC_CALLBACK(pc);
+ return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68040);
+}
+#endif /* MAME_DEBUG */
+
+#endif /* HAS_M68040 */
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void m68000_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 2: set_irq_line(2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 3: set_irq_line(3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 4: set_irq_line(4, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 5: set_irq_line(5, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 6: set_irq_line(6, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 7: set_irq_line(7, info->i); break;
+
+ case CPUINFO_INT_PC: m68k_set_reg(M68K_REG_PC, info->i&0x00ffffff); break;
+ case CPUINFO_INT_REGISTER + M68K_PC: m68k_set_reg(M68K_REG_PC, info->i); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M68K_SP: m68k_set_reg(M68K_REG_SP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_ISP: m68k_set_reg(M68K_REG_ISP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_USP: m68k_set_reg(M68K_REG_USP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_SR: m68k_set_reg(M68K_REG_SR, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D0: m68k_set_reg(M68K_REG_D0, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D1: m68k_set_reg(M68K_REG_D1, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D2: m68k_set_reg(M68K_REG_D2, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D3: m68k_set_reg(M68K_REG_D3, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D4: m68k_set_reg(M68K_REG_D4, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D5: m68k_set_reg(M68K_REG_D5, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D6: m68k_set_reg(M68K_REG_D6, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D7: m68k_set_reg(M68K_REG_D7, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A0: m68k_set_reg(M68K_REG_A0, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A1: m68k_set_reg(M68K_REG_A1, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A2: m68k_set_reg(M68K_REG_A2, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A3: m68k_set_reg(M68K_REG_A3, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A4: m68k_set_reg(M68K_REG_A4, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A5: m68k_set_reg(M68K_REG_A5, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A6: m68k_set_reg(M68K_REG_A6, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A7: m68k_set_reg(M68K_REG_A7, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_PREF_ADDR: m68k_set_reg(M68K_REG_PREF_ADDR, info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_M68K_RESET_CALLBACK: m68k_set_reset_instr_callback(info->f); break;
+ case CPUINFO_PTR_M68K_CMPILD_CALLBACK: m68k_set_cmpild_instr_callback((void (*)(unsigned int,int))(info->f)); break;
+ case CPUINFO_PTR_M68K_RTE_CALLBACK: m68k_set_rte_instr_callback(info->f); break;
+ case CPUINFO_PTR_M68K_TAS_CALLBACK: m68k_set_tas_instr_callback((int (*)(void))(info->f)); break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void m68000_get_info(UINT32 state, cpuinfo *info)
+{
+ int sr;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = m68k_get_context(NULL); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 8; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = -1; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 10; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 4; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 158; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 1: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 2: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 3: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 4: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 5: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 6: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 7: info->i = 0; /* fix me */ break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = m68k_get_reg(NULL, M68K_REG_PPC); break;
+
+ case CPUINFO_INT_PC: info->i = m68k_get_reg(NULL, M68K_REG_PC)&0x00ffffff; break;
+ case CPUINFO_INT_REGISTER + M68K_PC: info->i = m68k_get_reg(NULL, M68K_REG_PC); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M68K_SP: info->i = m68k_get_reg(NULL, M68K_REG_SP); break;
+ case CPUINFO_INT_REGISTER + M68K_ISP: info->i = m68k_get_reg(NULL, M68K_REG_ISP); break;
+ case CPUINFO_INT_REGISTER + M68K_USP: info->i = m68k_get_reg(NULL, M68K_REG_USP); break;
+ case CPUINFO_INT_REGISTER + M68K_SR: info->i = m68k_get_reg(NULL, M68K_REG_SR); break;
+ case CPUINFO_INT_REGISTER + M68K_D0: info->i = m68k_get_reg(NULL, M68K_REG_D0); break;
+ case CPUINFO_INT_REGISTER + M68K_D1: info->i = m68k_get_reg(NULL, M68K_REG_D1); break;
+ case CPUINFO_INT_REGISTER + M68K_D2: info->i = m68k_get_reg(NULL, M68K_REG_D2); break;
+ case CPUINFO_INT_REGISTER + M68K_D3: info->i = m68k_get_reg(NULL, M68K_REG_D3); break;
+ case CPUINFO_INT_REGISTER + M68K_D4: info->i = m68k_get_reg(NULL, M68K_REG_D4); break;
+ case CPUINFO_INT_REGISTER + M68K_D5: info->i = m68k_get_reg(NULL, M68K_REG_D5); break;
+ case CPUINFO_INT_REGISTER + M68K_D6: info->i = m68k_get_reg(NULL, M68K_REG_D6); break;
+ case CPUINFO_INT_REGISTER + M68K_D7: info->i = m68k_get_reg(NULL, M68K_REG_D7); break;
+ case CPUINFO_INT_REGISTER + M68K_A0: info->i = m68k_get_reg(NULL, M68K_REG_A0); break;
+ case CPUINFO_INT_REGISTER + M68K_A1: info->i = m68k_get_reg(NULL, M68K_REG_A1); break;
+ case CPUINFO_INT_REGISTER + M68K_A2: info->i = m68k_get_reg(NULL, M68K_REG_A2); break;
+ case CPUINFO_INT_REGISTER + M68K_A3: info->i = m68k_get_reg(NULL, M68K_REG_A3); break;
+ case CPUINFO_INT_REGISTER + M68K_A4: info->i = m68k_get_reg(NULL, M68K_REG_A4); break;
+ case CPUINFO_INT_REGISTER + M68K_A5: info->i = m68k_get_reg(NULL, M68K_REG_A5); break;
+ case CPUINFO_INT_REGISTER + M68K_A6: info->i = m68k_get_reg(NULL, M68K_REG_A6); break;
+ case CPUINFO_INT_REGISTER + M68K_A7: info->i = m68k_get_reg(NULL, M68K_REG_A7); break;
+ case CPUINFO_INT_REGISTER + M68K_PREF_ADDR: info->i = m68k_get_reg(NULL, M68K_REG_PREF_ADDR); break;
+ case CPUINFO_INT_REGISTER + M68K_PREF_DATA: info->i = m68k_get_reg(NULL, M68K_REG_PREF_DATA); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m68000_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m68000_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m68000_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m68000_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m68000_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m68000_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m68000_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m68000_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m68k_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "68000"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola 68K"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "3.31"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 1998-2007 Karl Stenerud. All rights reserved. (2.1 fixes HJB)"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sr = m68k_get_reg(NULL, M68K_REG_SR);
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ sr & 0x8000 ? 'T':'.',
+ sr & 0x4000 ? '?':'.',
+ sr & 0x2000 ? 'S':'.',
+ sr & 0x1000 ? '?':'.',
+ sr & 0x0800 ? '?':'.',
+ sr & 0x0400 ? 'I':'.',
+ sr & 0x0200 ? 'I':'.',
+ sr & 0x0100 ? 'I':'.',
+ sr & 0x0080 ? '?':'.',
+ sr & 0x0040 ? '?':'.',
+ sr & 0x0020 ? '?':'.',
+ sr & 0x0010 ? 'X':'.',
+ sr & 0x0008 ? 'N':'.',
+ sr & 0x0004 ? 'Z':'.',
+ sr & 0x0002 ? 'V':'.',
+ sr & 0x0001 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M68K_PC: sprintf(info->s, "PC :%08X", m68k_get_reg(NULL, M68K_REG_PC)); break;
+ case CPUINFO_STR_REGISTER + M68K_SR: sprintf(info->s, "SR :%04X", m68k_get_reg(NULL, M68K_REG_SR)); break;
+ case CPUINFO_STR_REGISTER + M68K_SP: sprintf(info->s, "SP :%08X", m68k_get_reg(NULL, M68K_REG_SP)); break;
+ case CPUINFO_STR_REGISTER + M68K_ISP: sprintf(info->s, "ISP:%08X", m68k_get_reg(NULL, M68K_REG_ISP)); break;
+ case CPUINFO_STR_REGISTER + M68K_USP: sprintf(info->s, "USP:%08X", m68k_get_reg(NULL, M68K_REG_USP)); break;
+ case CPUINFO_STR_REGISTER + M68K_D0: sprintf(info->s, "D0 :%08X", m68k_get_reg(NULL, M68K_REG_D0)); break;
+ case CPUINFO_STR_REGISTER + M68K_D1: sprintf(info->s, "D1 :%08X", m68k_get_reg(NULL, M68K_REG_D1)); break;
+ case CPUINFO_STR_REGISTER + M68K_D2: sprintf(info->s, "D2 :%08X", m68k_get_reg(NULL, M68K_REG_D2)); break;
+ case CPUINFO_STR_REGISTER + M68K_D3: sprintf(info->s, "D3 :%08X", m68k_get_reg(NULL, M68K_REG_D3)); break;
+ case CPUINFO_STR_REGISTER + M68K_D4: sprintf(info->s, "D4 :%08X", m68k_get_reg(NULL, M68K_REG_D4)); break;
+ case CPUINFO_STR_REGISTER + M68K_D5: sprintf(info->s, "D5 :%08X", m68k_get_reg(NULL, M68K_REG_D5)); break;
+ case CPUINFO_STR_REGISTER + M68K_D6: sprintf(info->s, "D6 :%08X", m68k_get_reg(NULL, M68K_REG_D6)); break;
+ case CPUINFO_STR_REGISTER + M68K_D7: sprintf(info->s, "D7 :%08X", m68k_get_reg(NULL, M68K_REG_D7)); break;
+ case CPUINFO_STR_REGISTER + M68K_A0: sprintf(info->s, "A0 :%08X", m68k_get_reg(NULL, M68K_REG_A0)); break;
+ case CPUINFO_STR_REGISTER + M68K_A1: sprintf(info->s, "A1 :%08X", m68k_get_reg(NULL, M68K_REG_A1)); break;
+ case CPUINFO_STR_REGISTER + M68K_A2: sprintf(info->s, "A2 :%08X", m68k_get_reg(NULL, M68K_REG_A2)); break;
+ case CPUINFO_STR_REGISTER + M68K_A3: sprintf(info->s, "A3 :%08X", m68k_get_reg(NULL, M68K_REG_A3)); break;
+ case CPUINFO_STR_REGISTER + M68K_A4: sprintf(info->s, "A4 :%08X", m68k_get_reg(NULL, M68K_REG_A4)); break;
+ case CPUINFO_STR_REGISTER + M68K_A5: sprintf(info->s, "A5 :%08X", m68k_get_reg(NULL, M68K_REG_A5)); break;
+ case CPUINFO_STR_REGISTER + M68K_A6: sprintf(info->s, "A6 :%08X", m68k_get_reg(NULL, M68K_REG_A6)); break;
+ case CPUINFO_STR_REGISTER + M68K_A7: sprintf(info->s, "A7 :%08X", m68k_get_reg(NULL, M68K_REG_A7)); break;
+ case CPUINFO_STR_REGISTER + M68K_PREF_ADDR: sprintf(info->s, "PAR:%08X", m68k_get_reg(NULL, M68K_REG_PREF_ADDR)); break;
+ case CPUINFO_STR_REGISTER + M68K_PREF_DATA: sprintf(info->s, "PDA:%08X", m68k_get_reg(NULL, M68K_REG_PREF_DATA)); break;
+ }
+}
+
+#if HAS_M68008
+
+static void m68008_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 2: set_irq_line(2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 3: set_irq_line(3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 4: set_irq_line(4, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 5: set_irq_line(5, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 6: set_irq_line(6, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 7: set_irq_line(7, info->i); break;
+
+ case CPUINFO_INT_PC: m68k_set_reg(M68K_REG_PC, info->i&0x00ffffff); break;
+ case CPUINFO_INT_REGISTER + M68K_PC: m68k_set_reg(M68K_REG_PC, info->i); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M68K_SP: m68k_set_reg(M68K_REG_SP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_ISP: m68k_set_reg(M68K_REG_ISP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_USP: m68k_set_reg(M68K_REG_USP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_SR: m68k_set_reg(M68K_REG_SR, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D0: m68k_set_reg(M68K_REG_D0, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D1: m68k_set_reg(M68K_REG_D1, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D2: m68k_set_reg(M68K_REG_D2, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D3: m68k_set_reg(M68K_REG_D3, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D4: m68k_set_reg(M68K_REG_D4, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D5: m68k_set_reg(M68K_REG_D5, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D6: m68k_set_reg(M68K_REG_D6, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D7: m68k_set_reg(M68K_REG_D7, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A0: m68k_set_reg(M68K_REG_A0, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A1: m68k_set_reg(M68K_REG_A1, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A2: m68k_set_reg(M68K_REG_A2, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A3: m68k_set_reg(M68K_REG_A3, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A4: m68k_set_reg(M68K_REG_A4, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A5: m68k_set_reg(M68K_REG_A5, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A6: m68k_set_reg(M68K_REG_A6, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A7: m68k_set_reg(M68K_REG_A7, info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_M68K_RESET_CALLBACK: m68k_set_reset_instr_callback(info->f); break;
+ case CPUINFO_PTR_M68K_CMPILD_CALLBACK: m68k_set_cmpild_instr_callback((void (*)(unsigned int,int))(info->f)); break;
+ case CPUINFO_PTR_M68K_RTE_CALLBACK: m68k_set_rte_instr_callback(info->f); break;
+ }
+}
+
+void m68008_get_info(UINT32 state, cpuinfo *info)
+{
+ int sr;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = m68k_get_context(NULL); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 8; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = -1; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 10; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 4; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 158; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 22; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 1: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 2: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 3: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 4: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 5: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 6: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 7: info->i = 0; /* fix me */ break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = m68k_get_reg(NULL, M68K_REG_PPC); break;
+
+ case CPUINFO_INT_PC: info->i = m68k_get_reg(NULL, M68K_REG_PC)&0x00ffffff; break;
+ case CPUINFO_INT_REGISTER + M68K_PC: info->i = m68k_get_reg(NULL, M68K_REG_PC); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M68K_SP: info->i = m68k_get_reg(NULL, M68K_REG_SP); break;
+ case CPUINFO_INT_REGISTER + M68K_ISP: info->i = m68k_get_reg(NULL, M68K_REG_ISP); break;
+ case CPUINFO_INT_REGISTER + M68K_USP: info->i = m68k_get_reg(NULL, M68K_REG_USP); break;
+ case CPUINFO_INT_REGISTER + M68K_SR: info->i = m68k_get_reg(NULL, M68K_REG_SR); break;
+ case CPUINFO_INT_REGISTER + M68K_D0: info->i = m68k_get_reg(NULL, M68K_REG_D0); break;
+ case CPUINFO_INT_REGISTER + M68K_D1: info->i = m68k_get_reg(NULL, M68K_REG_D1); break;
+ case CPUINFO_INT_REGISTER + M68K_D2: info->i = m68k_get_reg(NULL, M68K_REG_D2); break;
+ case CPUINFO_INT_REGISTER + M68K_D3: info->i = m68k_get_reg(NULL, M68K_REG_D3); break;
+ case CPUINFO_INT_REGISTER + M68K_D4: info->i = m68k_get_reg(NULL, M68K_REG_D4); break;
+ case CPUINFO_INT_REGISTER + M68K_D5: info->i = m68k_get_reg(NULL, M68K_REG_D5); break;
+ case CPUINFO_INT_REGISTER + M68K_D6: info->i = m68k_get_reg(NULL, M68K_REG_D6); break;
+ case CPUINFO_INT_REGISTER + M68K_D7: info->i = m68k_get_reg(NULL, M68K_REG_D7); break;
+ case CPUINFO_INT_REGISTER + M68K_A0: info->i = m68k_get_reg(NULL, M68K_REG_A0); break;
+ case CPUINFO_INT_REGISTER + M68K_A1: info->i = m68k_get_reg(NULL, M68K_REG_A1); break;
+ case CPUINFO_INT_REGISTER + M68K_A2: info->i = m68k_get_reg(NULL, M68K_REG_A2); break;
+ case CPUINFO_INT_REGISTER + M68K_A3: info->i = m68k_get_reg(NULL, M68K_REG_A3); break;
+ case CPUINFO_INT_REGISTER + M68K_A4: info->i = m68k_get_reg(NULL, M68K_REG_A4); break;
+ case CPUINFO_INT_REGISTER + M68K_A5: info->i = m68k_get_reg(NULL, M68K_REG_A5); break;
+ case CPUINFO_INT_REGISTER + M68K_A6: info->i = m68k_get_reg(NULL, M68K_REG_A6); break;
+ case CPUINFO_INT_REGISTER + M68K_A7: info->i = m68k_get_reg(NULL, M68K_REG_A7); break;
+ case CPUINFO_INT_REGISTER + M68K_PREF_ADDR: info->i = m68k_get_reg(NULL, M68K_REG_PREF_ADDR); break;
+ case CPUINFO_INT_REGISTER + M68K_PREF_DATA: info->i = m68k_get_reg(NULL, M68K_REG_PREF_DATA); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m68008_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m68008_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m68008_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m68008_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m68008_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m68008_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m68008_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m68008_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m68k_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "68008"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola 68K"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "3.31"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 1998-2007 Karl Stenerud. All rights reserved. (2.1 fixes HJB)"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sr = m68k_get_reg(NULL, M68K_REG_SR);
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ sr & 0x8000 ? 'T':'.',
+ sr & 0x4000 ? '?':'.',
+ sr & 0x2000 ? 'S':'.',
+ sr & 0x1000 ? '?':'.',
+ sr & 0x0800 ? '?':'.',
+ sr & 0x0400 ? 'I':'.',
+ sr & 0x0200 ? 'I':'.',
+ sr & 0x0100 ? 'I':'.',
+ sr & 0x0080 ? '?':'.',
+ sr & 0x0040 ? '?':'.',
+ sr & 0x0020 ? '?':'.',
+ sr & 0x0010 ? 'X':'.',
+ sr & 0x0008 ? 'N':'.',
+ sr & 0x0004 ? 'Z':'.',
+ sr & 0x0002 ? 'V':'.',
+ sr & 0x0001 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M68K_PC: sprintf(info->s, "PC :%08X", m68k_get_reg(NULL, M68K_REG_PC)); break;
+ case CPUINFO_STR_REGISTER + M68K_SR: sprintf(info->s, "SR :%04X", m68k_get_reg(NULL, M68K_REG_SR)); break;
+ case CPUINFO_STR_REGISTER + M68K_SP: sprintf(info->s, "SP :%08X", m68k_get_reg(NULL, M68K_REG_SP)); break;
+ case CPUINFO_STR_REGISTER + M68K_ISP: sprintf(info->s, "ISP:%08X", m68k_get_reg(NULL, M68K_REG_ISP)); break;
+ case CPUINFO_STR_REGISTER + M68K_USP: sprintf(info->s, "USP:%08X", m68k_get_reg(NULL, M68K_REG_USP)); break;
+ case CPUINFO_STR_REGISTER + M68K_D0: sprintf(info->s, "D0 :%08X", m68k_get_reg(NULL, M68K_REG_D0)); break;
+ case CPUINFO_STR_REGISTER + M68K_D1: sprintf(info->s, "D1 :%08X", m68k_get_reg(NULL, M68K_REG_D1)); break;
+ case CPUINFO_STR_REGISTER + M68K_D2: sprintf(info->s, "D2 :%08X", m68k_get_reg(NULL, M68K_REG_D2)); break;
+ case CPUINFO_STR_REGISTER + M68K_D3: sprintf(info->s, "D3 :%08X", m68k_get_reg(NULL, M68K_REG_D3)); break;
+ case CPUINFO_STR_REGISTER + M68K_D4: sprintf(info->s, "D4 :%08X", m68k_get_reg(NULL, M68K_REG_D4)); break;
+ case CPUINFO_STR_REGISTER + M68K_D5: sprintf(info->s, "D5 :%08X", m68k_get_reg(NULL, M68K_REG_D5)); break;
+ case CPUINFO_STR_REGISTER + M68K_D6: sprintf(info->s, "D6 :%08X", m68k_get_reg(NULL, M68K_REG_D6)); break;
+ case CPUINFO_STR_REGISTER + M68K_D7: sprintf(info->s, "D7 :%08X", m68k_get_reg(NULL, M68K_REG_D7)); break;
+ case CPUINFO_STR_REGISTER + M68K_A0: sprintf(info->s, "A0 :%08X", m68k_get_reg(NULL, M68K_REG_A0)); break;
+ case CPUINFO_STR_REGISTER + M68K_A1: sprintf(info->s, "A1 :%08X", m68k_get_reg(NULL, M68K_REG_A1)); break;
+ case CPUINFO_STR_REGISTER + M68K_A2: sprintf(info->s, "A2 :%08X", m68k_get_reg(NULL, M68K_REG_A2)); break;
+ case CPUINFO_STR_REGISTER + M68K_A3: sprintf(info->s, "A3 :%08X", m68k_get_reg(NULL, M68K_REG_A3)); break;
+ case CPUINFO_STR_REGISTER + M68K_A4: sprintf(info->s, "A4 :%08X", m68k_get_reg(NULL, M68K_REG_A4)); break;
+ case CPUINFO_STR_REGISTER + M68K_A5: sprintf(info->s, "A5 :%08X", m68k_get_reg(NULL, M68K_REG_A5)); break;
+ case CPUINFO_STR_REGISTER + M68K_A6: sprintf(info->s, "A6 :%08X", m68k_get_reg(NULL, M68K_REG_A6)); break;
+ case CPUINFO_STR_REGISTER + M68K_A7: sprintf(info->s, "A7 :%08X", m68k_get_reg(NULL, M68K_REG_A7)); break;
+ case CPUINFO_STR_REGISTER + M68K_PREF_ADDR: sprintf(info->s, "PAR:%08X", m68k_get_reg(NULL, M68K_REG_PREF_ADDR)); break;
+ case CPUINFO_STR_REGISTER + M68K_PREF_DATA: sprintf(info->s, "PDA:%08X", m68k_get_reg(NULL, M68K_REG_PREF_DATA)); break;
+ }
+}
+
+#endif
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+#if HAS_M68010
+
+static void m68010_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_REGISTER + M68K_VBR: m68k_set_reg(M68K_REG_VBR, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_SFC: m68k_set_reg(M68K_REG_SFC, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_DFC: m68k_set_reg(M68K_REG_DFC, info->i); break;
+
+ default: m68000_set_info(state, info); break;
+ }
+}
+
+void m68010_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_REGISTER + M68K_VBR: info->i = m68k_get_reg(NULL, M68K_REG_VBR); break;
+ case CPUINFO_INT_REGISTER + M68K_SFC: info->i = m68k_get_reg(NULL, M68K_REG_SFC); break;
+ case CPUINFO_INT_REGISTER + M68K_DFC: info->i = m68k_get_reg(NULL, M68K_REG_DFC); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m68010_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = m68010_init; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m68010_dasm; break;
+#endif /* MAME_DEBUG */
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "68010"); break;
+ case CPUINFO_STR_REGISTER + M68K_SFC: sprintf(info->s, "SFC:%X", m68k_get_reg(NULL, M68K_REG_SFC)); break;
+ case CPUINFO_STR_REGISTER + M68K_DFC: sprintf(info->s, "DFC:%X", m68k_get_reg(NULL, M68K_REG_DFC)); break;
+ case CPUINFO_STR_REGISTER + M68K_VBR: sprintf(info->s, "VBR:%08X", m68k_get_reg(NULL, M68K_REG_VBR)); break;
+
+ default: m68000_get_info(state, info); break;
+ }
+}
+
+#endif
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+static void m68020_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 2: set_irq_line(2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 3: set_irq_line(3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 4: set_irq_line(4, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 5: set_irq_line(5, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 6: set_irq_line(6, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 7: set_irq_line(7, info->i); break;
+
+ case CPUINFO_INT_PC: m68k_set_reg(M68K_REG_PC, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_PC: m68k_set_reg(M68K_REG_PC, info->i); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M68K_SP: m68k_set_reg(M68K_REG_SP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_ISP: m68k_set_reg(M68K_REG_ISP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_USP: m68k_set_reg(M68K_REG_USP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_SR: m68k_set_reg(M68K_REG_SR, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D0: m68k_set_reg(M68K_REG_D0, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D1: m68k_set_reg(M68K_REG_D1, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D2: m68k_set_reg(M68K_REG_D2, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D3: m68k_set_reg(M68K_REG_D3, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D4: m68k_set_reg(M68K_REG_D4, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D5: m68k_set_reg(M68K_REG_D5, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D6: m68k_set_reg(M68K_REG_D6, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D7: m68k_set_reg(M68K_REG_D7, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A0: m68k_set_reg(M68K_REG_A0, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A1: m68k_set_reg(M68K_REG_A1, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A2: m68k_set_reg(M68K_REG_A2, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A3: m68k_set_reg(M68K_REG_A3, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A4: m68k_set_reg(M68K_REG_A4, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A5: m68k_set_reg(M68K_REG_A5, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A6: m68k_set_reg(M68K_REG_A6, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A7: m68k_set_reg(M68K_REG_A7, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_MSP: m68k_set_reg(M68K_REG_MSP, info->i); break; /* 68020+ */
+ case CPUINFO_INT_REGISTER + M68K_CACR: m68k_set_reg(M68K_REG_CACR, info->i); break; /* 68020+ */
+ case CPUINFO_INT_REGISTER + M68K_CAAR: m68k_set_reg(M68K_REG_CAAR, info->i); break; /* 68020+ */
+ case CPUINFO_INT_REGISTER + M68K_VBR: m68k_set_reg(M68K_REG_VBR, info->i); break; /* 68010+ */
+ case CPUINFO_INT_REGISTER + M68K_SFC: m68k_set_reg(M68K_REG_SFC, info->i); break; /* 68010+ */
+ case CPUINFO_INT_REGISTER + M68K_DFC: m68k_set_reg(M68K_REG_DFC, info->i); break; /* 68010+ */
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_M68K_RESET_CALLBACK: m68k_set_reset_instr_callback(info->f); break;
+ case CPUINFO_PTR_M68K_CMPILD_CALLBACK: m68k_set_cmpild_instr_callback((void (*)(unsigned int,int))(info->f)); break;
+ case CPUINFO_PTR_M68K_RTE_CALLBACK: m68k_set_rte_instr_callback(info->f); break;
+ }
+}
+
+void m68020_get_info(UINT32 state, cpuinfo *info)
+{
+ int sr;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = m68k_get_context(NULL); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 8; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = -1; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 16; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 4; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 158; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 1: info->i = 1; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 2: info->i = 2; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 3: info->i = 3; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 4: info->i = 4; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 5: info->i = 5; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 6: info->i = 6; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 7: info->i = 7; /* fix me */ break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = m68k_get_reg(NULL, M68K_REG_PPC); break;
+
+ case CPUINFO_INT_PC: info->i = m68k_get_reg(NULL, M68K_REG_PC); break;
+ case CPUINFO_INT_REGISTER + M68K_PC: info->i = m68k_get_reg(NULL, M68K_REG_PC); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M68K_SP: info->i = m68k_get_reg(NULL, M68K_REG_SP); break;
+ case CPUINFO_INT_REGISTER + M68K_ISP: info->i = m68k_get_reg(NULL, M68K_REG_ISP); break;
+ case CPUINFO_INT_REGISTER + M68K_USP: info->i = m68k_get_reg(NULL, M68K_REG_USP); break;
+ case CPUINFO_INT_REGISTER + M68K_SR: info->i = m68k_get_reg(NULL, M68K_REG_SR); break;
+ case CPUINFO_INT_REGISTER + M68K_D0: info->i = m68k_get_reg(NULL, M68K_REG_D0); break;
+ case CPUINFO_INT_REGISTER + M68K_D1: info->i = m68k_get_reg(NULL, M68K_REG_D1); break;
+ case CPUINFO_INT_REGISTER + M68K_D2: info->i = m68k_get_reg(NULL, M68K_REG_D2); break;
+ case CPUINFO_INT_REGISTER + M68K_D3: info->i = m68k_get_reg(NULL, M68K_REG_D3); break;
+ case CPUINFO_INT_REGISTER + M68K_D4: info->i = m68k_get_reg(NULL, M68K_REG_D4); break;
+ case CPUINFO_INT_REGISTER + M68K_D5: info->i = m68k_get_reg(NULL, M68K_REG_D5); break;
+ case CPUINFO_INT_REGISTER + M68K_D6: info->i = m68k_get_reg(NULL, M68K_REG_D6); break;
+ case CPUINFO_INT_REGISTER + M68K_D7: info->i = m68k_get_reg(NULL, M68K_REG_D7); break;
+ case CPUINFO_INT_REGISTER + M68K_A0: info->i = m68k_get_reg(NULL, M68K_REG_A0); break;
+ case CPUINFO_INT_REGISTER + M68K_A1: info->i = m68k_get_reg(NULL, M68K_REG_A1); break;
+ case CPUINFO_INT_REGISTER + M68K_A2: info->i = m68k_get_reg(NULL, M68K_REG_A2); break;
+ case CPUINFO_INT_REGISTER + M68K_A3: info->i = m68k_get_reg(NULL, M68K_REG_A3); break;
+ case CPUINFO_INT_REGISTER + M68K_A4: info->i = m68k_get_reg(NULL, M68K_REG_A4); break;
+ case CPUINFO_INT_REGISTER + M68K_A5: info->i = m68k_get_reg(NULL, M68K_REG_A5); break;
+ case CPUINFO_INT_REGISTER + M68K_A6: info->i = m68k_get_reg(NULL, M68K_REG_A6); break;
+ case CPUINFO_INT_REGISTER + M68K_A7: info->i = m68k_get_reg(NULL, M68K_REG_A7); break;
+ case CPUINFO_INT_REGISTER + M68K_PREF_ADDR: info->i = m68k_get_reg(NULL, M68K_REG_PREF_ADDR); break;
+ case CPUINFO_INT_REGISTER + M68K_PREF_DATA: info->i = m68k_get_reg(NULL, M68K_REG_PREF_DATA); break;
+ case CPUINFO_INT_REGISTER + M68K_MSP: info->i = m68k_get_reg(NULL, M68K_REG_MSP); /* 68020+ */ break;
+ case CPUINFO_INT_REGISTER + M68K_CACR: info->i = m68k_get_reg(NULL, M68K_REG_CACR); /* 68020+ */ break;
+ case CPUINFO_INT_REGISTER + M68K_CAAR: info->i = m68k_get_reg(NULL, M68K_REG_CAAR); /* 68020+ */ break;
+ case CPUINFO_INT_REGISTER + M68K_VBR: info->i = m68k_get_reg(NULL, M68K_REG_VBR); /* 68010+ */ break;
+ case CPUINFO_INT_REGISTER + M68K_SFC: info->i = m68k_get_reg(NULL, M68K_REG_SFC); /* 68010" */ break;
+ case CPUINFO_INT_REGISTER + M68K_DFC: info->i = m68k_get_reg(NULL, M68K_REG_DFC); /* 68010+ */ break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m68020_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m68020_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m68020_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m68020_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m68020_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m68020_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m68020_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m68020_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m68k_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "68020"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola 68K"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "3.31"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 1998-2007 Karl Stenerud. All rights reserved. (2.1 fixes HJB)"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sr = m68k_get_reg(NULL, M68K_REG_SR);
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ sr & 0x8000 ? 'T':'.',
+ sr & 0x4000 ? 't':'.',
+ sr & 0x2000 ? 'S':'.',
+ sr & 0x1000 ? 'M':'.',
+ sr & 0x0800 ? '?':'.',
+ sr & 0x0400 ? 'I':'.',
+ sr & 0x0200 ? 'I':'.',
+ sr & 0x0100 ? 'I':'.',
+ sr & 0x0080 ? '?':'.',
+ sr & 0x0040 ? '?':'.',
+ sr & 0x0020 ? '?':'.',
+ sr & 0x0010 ? 'X':'.',
+ sr & 0x0008 ? 'N':'.',
+ sr & 0x0004 ? 'Z':'.',
+ sr & 0x0002 ? 'V':'.',
+ sr & 0x0001 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M68K_PC: sprintf(info->s, "PC :%08X", m68k_get_reg(NULL, M68K_REG_PC)); break;
+ case CPUINFO_STR_REGISTER + M68K_SR: sprintf(info->s, "SR :%04X", m68k_get_reg(NULL, M68K_REG_SR)); break;
+ case CPUINFO_STR_REGISTER + M68K_SP: sprintf(info->s, "SP :%08X", m68k_get_reg(NULL, M68K_REG_SP)); break;
+ case CPUINFO_STR_REGISTER + M68K_ISP: sprintf(info->s, "ISP:%08X", m68k_get_reg(NULL, M68K_REG_ISP)); break;
+ case CPUINFO_STR_REGISTER + M68K_USP: sprintf(info->s, "USP:%08X", m68k_get_reg(NULL, M68K_REG_USP)); break;
+ case CPUINFO_STR_REGISTER + M68K_D0: sprintf(info->s, "D0 :%08X", m68k_get_reg(NULL, M68K_REG_D0)); break;
+ case CPUINFO_STR_REGISTER + M68K_D1: sprintf(info->s, "D1 :%08X", m68k_get_reg(NULL, M68K_REG_D1)); break;
+ case CPUINFO_STR_REGISTER + M68K_D2: sprintf(info->s, "D2 :%08X", m68k_get_reg(NULL, M68K_REG_D2)); break;
+ case CPUINFO_STR_REGISTER + M68K_D3: sprintf(info->s, "D3 :%08X", m68k_get_reg(NULL, M68K_REG_D3)); break;
+ case CPUINFO_STR_REGISTER + M68K_D4: sprintf(info->s, "D4 :%08X", m68k_get_reg(NULL, M68K_REG_D4)); break;
+ case CPUINFO_STR_REGISTER + M68K_D5: sprintf(info->s, "D5 :%08X", m68k_get_reg(NULL, M68K_REG_D5)); break;
+ case CPUINFO_STR_REGISTER + M68K_D6: sprintf(info->s, "D6 :%08X", m68k_get_reg(NULL, M68K_REG_D6)); break;
+ case CPUINFO_STR_REGISTER + M68K_D7: sprintf(info->s, "D7 :%08X", m68k_get_reg(NULL, M68K_REG_D7)); break;
+ case CPUINFO_STR_REGISTER + M68K_A0: sprintf(info->s, "A0 :%08X", m68k_get_reg(NULL, M68K_REG_A0)); break;
+ case CPUINFO_STR_REGISTER + M68K_A1: sprintf(info->s, "A1 :%08X", m68k_get_reg(NULL, M68K_REG_A1)); break;
+ case CPUINFO_STR_REGISTER + M68K_A2: sprintf(info->s, "A2 :%08X", m68k_get_reg(NULL, M68K_REG_A2)); break;
+ case CPUINFO_STR_REGISTER + M68K_A3: sprintf(info->s, "A3 :%08X", m68k_get_reg(NULL, M68K_REG_A3)); break;
+ case CPUINFO_STR_REGISTER + M68K_A4: sprintf(info->s, "A4 :%08X", m68k_get_reg(NULL, M68K_REG_A4)); break;
+ case CPUINFO_STR_REGISTER + M68K_A5: sprintf(info->s, "A5 :%08X", m68k_get_reg(NULL, M68K_REG_A5)); break;
+ case CPUINFO_STR_REGISTER + M68K_A6: sprintf(info->s, "A6 :%08X", m68k_get_reg(NULL, M68K_REG_A6)); break;
+ case CPUINFO_STR_REGISTER + M68K_A7: sprintf(info->s, "A7 :%08X", m68k_get_reg(NULL, M68K_REG_A7)); break;
+ case CPUINFO_STR_REGISTER + M68K_PREF_ADDR: sprintf(info->s, "PAR:%08X", m68k_get_reg(NULL, M68K_REG_PREF_ADDR)); break;
+ case CPUINFO_STR_REGISTER + M68K_PREF_DATA: sprintf(info->s, "PDA:%08X", m68k_get_reg(NULL, M68K_REG_PREF_DATA)); break;
+ case CPUINFO_STR_REGISTER + M68K_MSP: sprintf(info->s, "MSP:%08X", m68k_get_reg(NULL, M68K_REG_MSP)); break;
+ case CPUINFO_STR_REGISTER + M68K_CACR: sprintf(info->s, "CCR:%08X", m68k_get_reg(NULL, M68K_REG_CACR)); break;
+ case CPUINFO_STR_REGISTER + M68K_CAAR: sprintf(info->s, "CAR:%08X", m68k_get_reg(NULL, M68K_REG_CAAR)); break;
+ case CPUINFO_STR_REGISTER + M68K_SFC: sprintf(info->s, "SFC:%X", m68k_get_reg(NULL, M68K_REG_SFC)); break;
+ case CPUINFO_STR_REGISTER + M68K_DFC: sprintf(info->s, "DFC:%X", m68k_get_reg(NULL, M68K_REG_DFC)); break;
+ case CPUINFO_STR_REGISTER + M68K_VBR: sprintf(info->s, "VBR:%08X", m68k_get_reg(NULL, M68K_REG_VBR)); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+#if HAS_M68EC020
+
+static void m68ec020_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC: m68k_set_reg(M68K_REG_PC, info->i&0x00ffffff); break;
+
+ default: m68020_set_info(state, info); break;
+ }
+}
+
+void m68ec020_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_REGISTER + REG_PC: info->i = m68k_get_reg(NULL, M68K_REG_PC)&0x00ffffff; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m68ec020_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = m68ec020_init; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m68ec020_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "68EC020"); break;
+
+ default: m68020_get_info(state, info); break;
+ }
+}
+
+#endif
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+#if HAS_M68040
+static void m68040_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 2: set_irq_line(2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 3: set_irq_line(3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 4: set_irq_line(4, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 5: set_irq_line(5, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 6: set_irq_line(6, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 7: set_irq_line(7, info->i); break;
+
+ case CPUINFO_INT_PC: m68k_set_reg(M68K_REG_PC, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_PC: m68k_set_reg(M68K_REG_PC, info->i); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M68K_SP: m68k_set_reg(M68K_REG_SP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_ISP: m68k_set_reg(M68K_REG_ISP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_USP: m68k_set_reg(M68K_REG_USP, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_SR: m68k_set_reg(M68K_REG_SR, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D0: m68k_set_reg(M68K_REG_D0, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D1: m68k_set_reg(M68K_REG_D1, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D2: m68k_set_reg(M68K_REG_D2, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D3: m68k_set_reg(M68K_REG_D3, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D4: m68k_set_reg(M68K_REG_D4, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D5: m68k_set_reg(M68K_REG_D5, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D6: m68k_set_reg(M68K_REG_D6, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_D7: m68k_set_reg(M68K_REG_D7, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A0: m68k_set_reg(M68K_REG_A0, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A1: m68k_set_reg(M68K_REG_A1, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A2: m68k_set_reg(M68K_REG_A2, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A3: m68k_set_reg(M68K_REG_A3, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A4: m68k_set_reg(M68K_REG_A4, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A5: m68k_set_reg(M68K_REG_A5, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A6: m68k_set_reg(M68K_REG_A6, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_A7: m68k_set_reg(M68K_REG_A7, info->i); break;
+ case CPUINFO_INT_REGISTER + M68K_MSP: m68k_set_reg(M68K_REG_MSP, info->i); break; /* 68020+ */
+ case CPUINFO_INT_REGISTER + M68K_CACR: m68k_set_reg(M68K_REG_CACR, info->i); break; /* 68020+ */
+ case CPUINFO_INT_REGISTER + M68K_CAAR: m68k_set_reg(M68K_REG_CAAR, info->i); break; /* 68020+ */
+ case CPUINFO_INT_REGISTER + M68K_VBR: m68k_set_reg(M68K_REG_VBR, info->i); break; /* 68010+ */
+ case CPUINFO_INT_REGISTER + M68K_SFC: m68k_set_reg(M68K_REG_SFC, info->i); break; /* 68010+ */
+ case CPUINFO_INT_REGISTER + M68K_DFC: m68k_set_reg(M68K_REG_DFC, info->i); break; /* 68010+ */
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_M68K_RESET_CALLBACK: m68k_set_reset_instr_callback(info->f); break;
+ case CPUINFO_PTR_M68K_CMPILD_CALLBACK: m68k_set_cmpild_instr_callback((void (*)(unsigned int,int))(info->f)); break;
+ case CPUINFO_PTR_M68K_RTE_CALLBACK: m68k_set_rte_instr_callback(info->f); break;
+ }
+}
+
+void m68040_get_info(UINT32 state, cpuinfo *info)
+{
+ int sr;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = m68k_get_context(NULL); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 8; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = -1; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 16; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 4; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 158; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 1: info->i = 1; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 2: info->i = 2; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 3: info->i = 3; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 4: info->i = 4; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 5: info->i = 5; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 6: info->i = 6; /* fix me */ break;
+ case CPUINFO_INT_INPUT_STATE + 7: info->i = 7; /* fix me */ break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = m68k_get_reg(NULL, M68K_REG_PPC); break;
+
+ case CPUINFO_INT_PC: info->i = m68k_get_reg(NULL, M68K_REG_PC); break;
+ case CPUINFO_INT_REGISTER + M68K_PC: info->i = m68k_get_reg(NULL, M68K_REG_PC); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M68K_SP: info->i = m68k_get_reg(NULL, M68K_REG_SP); break;
+ case CPUINFO_INT_REGISTER + M68K_ISP: info->i = m68k_get_reg(NULL, M68K_REG_ISP); break;
+ case CPUINFO_INT_REGISTER + M68K_USP: info->i = m68k_get_reg(NULL, M68K_REG_USP); break;
+ case CPUINFO_INT_REGISTER + M68K_SR: info->i = m68k_get_reg(NULL, M68K_REG_SR); break;
+ case CPUINFO_INT_REGISTER + M68K_D0: info->i = m68k_get_reg(NULL, M68K_REG_D0); break;
+ case CPUINFO_INT_REGISTER + M68K_D1: info->i = m68k_get_reg(NULL, M68K_REG_D1); break;
+ case CPUINFO_INT_REGISTER + M68K_D2: info->i = m68k_get_reg(NULL, M68K_REG_D2); break;
+ case CPUINFO_INT_REGISTER + M68K_D3: info->i = m68k_get_reg(NULL, M68K_REG_D3); break;
+ case CPUINFO_INT_REGISTER + M68K_D4: info->i = m68k_get_reg(NULL, M68K_REG_D4); break;
+ case CPUINFO_INT_REGISTER + M68K_D5: info->i = m68k_get_reg(NULL, M68K_REG_D5); break;
+ case CPUINFO_INT_REGISTER + M68K_D6: info->i = m68k_get_reg(NULL, M68K_REG_D6); break;
+ case CPUINFO_INT_REGISTER + M68K_D7: info->i = m68k_get_reg(NULL, M68K_REG_D7); break;
+ case CPUINFO_INT_REGISTER + M68K_A0: info->i = m68k_get_reg(NULL, M68K_REG_A0); break;
+ case CPUINFO_INT_REGISTER + M68K_A1: info->i = m68k_get_reg(NULL, M68K_REG_A1); break;
+ case CPUINFO_INT_REGISTER + M68K_A2: info->i = m68k_get_reg(NULL, M68K_REG_A2); break;
+ case CPUINFO_INT_REGISTER + M68K_A3: info->i = m68k_get_reg(NULL, M68K_REG_A3); break;
+ case CPUINFO_INT_REGISTER + M68K_A4: info->i = m68k_get_reg(NULL, M68K_REG_A4); break;
+ case CPUINFO_INT_REGISTER + M68K_A5: info->i = m68k_get_reg(NULL, M68K_REG_A5); break;
+ case CPUINFO_INT_REGISTER + M68K_A6: info->i = m68k_get_reg(NULL, M68K_REG_A6); break;
+ case CPUINFO_INT_REGISTER + M68K_A7: info->i = m68k_get_reg(NULL, M68K_REG_A7); break;
+ case CPUINFO_INT_REGISTER + M68K_PREF_ADDR: info->i = m68k_get_reg(NULL, M68K_REG_PREF_ADDR); break;
+ case CPUINFO_INT_REGISTER + M68K_PREF_DATA: info->i = m68k_get_reg(NULL, M68K_REG_PREF_DATA); break;
+ case CPUINFO_INT_REGISTER + M68K_MSP: info->i = m68k_get_reg(NULL, M68K_REG_MSP); /* 68020+ */ break;
+ case CPUINFO_INT_REGISTER + M68K_CACR: info->i = m68k_get_reg(NULL, M68K_REG_CACR); /* 68020+ */ break;
+ case CPUINFO_INT_REGISTER + M68K_CAAR: info->i = m68k_get_reg(NULL, M68K_REG_CAAR); /* 68020+ */ break;
+ case CPUINFO_INT_REGISTER + M68K_VBR: info->i = m68k_get_reg(NULL, M68K_REG_VBR); /* 68010+ */ break;
+ case CPUINFO_INT_REGISTER + M68K_SFC: info->i = m68k_get_reg(NULL, M68K_REG_SFC); /* 68010" */ break;
+ case CPUINFO_INT_REGISTER + M68K_DFC: info->i = m68k_get_reg(NULL, M68K_REG_DFC); /* 68010+ */ break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m68040_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m68040_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m68040_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m68040_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m68040_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m68040_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m68040_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m68040_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m68k_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "68040"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola 68K"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "3.31"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 1998-2007 Karl Stenerud. All rights reserved. (2.1 fixes HJB)"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sr = m68k_get_reg(NULL, M68K_REG_SR);
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ sr & 0x8000 ? 'T':'.',
+ sr & 0x4000 ? 't':'.',
+ sr & 0x2000 ? 'S':'.',
+ sr & 0x1000 ? 'M':'.',
+ sr & 0x0800 ? '?':'.',
+ sr & 0x0400 ? 'I':'.',
+ sr & 0x0200 ? 'I':'.',
+ sr & 0x0100 ? 'I':'.',
+ sr & 0x0080 ? '?':'.',
+ sr & 0x0040 ? '?':'.',
+ sr & 0x0020 ? '?':'.',
+ sr & 0x0010 ? 'X':'.',
+ sr & 0x0008 ? 'N':'.',
+ sr & 0x0004 ? 'Z':'.',
+ sr & 0x0002 ? 'V':'.',
+ sr & 0x0001 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M68K_PC: sprintf(info->s, "PC :%08X", m68k_get_reg(NULL, M68K_REG_PC)); break;
+ case CPUINFO_STR_REGISTER + M68K_SR: sprintf(info->s, "SR :%04X", m68k_get_reg(NULL, M68K_REG_SR)); break;
+ case CPUINFO_STR_REGISTER + M68K_SP: sprintf(info->s, "SP :%08X", m68k_get_reg(NULL, M68K_REG_SP)); break;
+ case CPUINFO_STR_REGISTER + M68K_ISP: sprintf(info->s, "ISP:%08X", m68k_get_reg(NULL, M68K_REG_ISP)); break;
+ case CPUINFO_STR_REGISTER + M68K_USP: sprintf(info->s, "USP:%08X", m68k_get_reg(NULL, M68K_REG_USP)); break;
+ case CPUINFO_STR_REGISTER + M68K_D0: sprintf(info->s, "D0 :%08X", m68k_get_reg(NULL, M68K_REG_D0)); break;
+ case CPUINFO_STR_REGISTER + M68K_D1: sprintf(info->s, "D1 :%08X", m68k_get_reg(NULL, M68K_REG_D1)); break;
+ case CPUINFO_STR_REGISTER + M68K_D2: sprintf(info->s, "D2 :%08X", m68k_get_reg(NULL, M68K_REG_D2)); break;
+ case CPUINFO_STR_REGISTER + M68K_D3: sprintf(info->s, "D3 :%08X", m68k_get_reg(NULL, M68K_REG_D3)); break;
+ case CPUINFO_STR_REGISTER + M68K_D4: sprintf(info->s, "D4 :%08X", m68k_get_reg(NULL, M68K_REG_D4)); break;
+ case CPUINFO_STR_REGISTER + M68K_D5: sprintf(info->s, "D5 :%08X", m68k_get_reg(NULL, M68K_REG_D5)); break;
+ case CPUINFO_STR_REGISTER + M68K_D6: sprintf(info->s, "D6 :%08X", m68k_get_reg(NULL, M68K_REG_D6)); break;
+ case CPUINFO_STR_REGISTER + M68K_D7: sprintf(info->s, "D7 :%08X", m68k_get_reg(NULL, M68K_REG_D7)); break;
+ case CPUINFO_STR_REGISTER + M68K_A0: sprintf(info->s, "A0 :%08X", m68k_get_reg(NULL, M68K_REG_A0)); break;
+ case CPUINFO_STR_REGISTER + M68K_A1: sprintf(info->s, "A1 :%08X", m68k_get_reg(NULL, M68K_REG_A1)); break;
+ case CPUINFO_STR_REGISTER + M68K_A2: sprintf(info->s, "A2 :%08X", m68k_get_reg(NULL, M68K_REG_A2)); break;
+ case CPUINFO_STR_REGISTER + M68K_A3: sprintf(info->s, "A3 :%08X", m68k_get_reg(NULL, M68K_REG_A3)); break;
+ case CPUINFO_STR_REGISTER + M68K_A4: sprintf(info->s, "A4 :%08X", m68k_get_reg(NULL, M68K_REG_A4)); break;
+ case CPUINFO_STR_REGISTER + M68K_A5: sprintf(info->s, "A5 :%08X", m68k_get_reg(NULL, M68K_REG_A5)); break;
+ case CPUINFO_STR_REGISTER + M68K_A6: sprintf(info->s, "A6 :%08X", m68k_get_reg(NULL, M68K_REG_A6)); break;
+ case CPUINFO_STR_REGISTER + M68K_A7: sprintf(info->s, "A7 :%08X", m68k_get_reg(NULL, M68K_REG_A7)); break;
+ case CPUINFO_STR_REGISTER + M68K_PREF_ADDR: sprintf(info->s, "PAR:%08X", m68k_get_reg(NULL, M68K_REG_PREF_ADDR)); break;
+ case CPUINFO_STR_REGISTER + M68K_PREF_DATA: sprintf(info->s, "PDA:%08X", m68k_get_reg(NULL, M68K_REG_PREF_DATA)); break;
+ case CPUINFO_STR_REGISTER + M68K_MSP: sprintf(info->s, "MSP:%08X", m68k_get_reg(NULL, M68K_REG_MSP)); break;
+ case CPUINFO_STR_REGISTER + M68K_CACR: sprintf(info->s, "CCR:%08X", m68k_get_reg(NULL, M68K_REG_CACR)); break;
+ case CPUINFO_STR_REGISTER + M68K_CAAR: sprintf(info->s, "CAR:%08X", m68k_get_reg(NULL, M68K_REG_CAAR)); break;
+ case CPUINFO_STR_REGISTER + M68K_SFC: sprintf(info->s, "SFC:%X", m68k_get_reg(NULL, M68K_REG_SFC)); break;
+ case CPUINFO_STR_REGISTER + M68K_DFC: sprintf(info->s, "DFC:%X", m68k_get_reg(NULL, M68K_REG_DFC)); break;
+ case CPUINFO_STR_REGISTER + M68K_VBR: sprintf(info->s, "VBR:%08X", m68k_get_reg(NULL, M68K_REG_VBR)); break;
+ }
+}
+
+#endif
+
diff --git a/src/emu/cpu/m68000/m68kmame.h b/src/emu/cpu/m68000/m68kmame.h
new file mode 100644
index 00000000000..046f38eb0ea
--- /dev/null
+++ b/src/emu/cpu/m68000/m68kmame.h
@@ -0,0 +1,182 @@
+#ifndef M68KMAME__HEADER
+#define M68KMAME__HEADER
+
+/* ======================================================================== */
+/* ============================== MAME STUFF ============================== */
+/* ======================================================================== */
+
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "m68000.h"
+
+/* Configuration switches (see m68kconf.h for explanation) */
+#define M68K_SEPARATE_READS OPT_ON
+
+#define M68K_SIMULATE_PD_WRITES OPT_ON
+
+#define M68K_EMULATE_INT_ACK OPT_ON
+#define M68K_INT_ACK_CALLBACK(A)
+
+#define M68K_EMULATE_BKPT_ACK OPT_OFF
+#define M68K_BKPT_ACK_CALLBACK()
+
+#define M68K_EMULATE_TRACE OPT_OFF
+
+#define M68K_EMULATE_RESET OPT_ON
+#define M68K_RESET_CALLBACK()
+
+#define M68K_CMPILD_HAS_CALLBACK OPT_ON
+#define M68K_CMPILD_CALLBACK()
+
+#define M68K_RTE_HAS_CALLBACK OPT_ON
+#define M68K_RTE_CALLBACK()
+
+#define M68K_TAS_HAS_CALLBACK OPT_ON
+#define M68K_TAS_CALLBACK()
+
+#define M68K_EMULATE_FC OPT_OFF
+#define M68K_SET_FC_CALLBACK(A)
+
+#define M68K_MONITOR_PC OPT_SPECIFY_HANDLER
+#define M68K_SET_PC_CALLBACK(A) change_pc(A)
+
+#define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER
+#define M68K_INSTRUCTION_CALLBACK() CALL_MAME_DEBUG
+
+#define M68K_EMULATE_PREFETCH OPT_ON
+
+#define M68K_LOG_ENABLE OPT_OFF
+#define M68K_LOG_1010_1111 OPT_OFF
+#define M68K_LOG_FILEHANDLE errorlog
+
+#define M68K_EMULATE_ADDRESS_ERROR OPT_ON
+
+#define M68K_USE_64_BIT OPT_OFF
+
+
+#define m68ki_remaining_cycles m68k_ICount
+
+
+extern struct m68k_memory_interface m68k_memory_intf;
+extern offs_t m68k_encrypted_opcode_start[MAX_CPU];
+extern offs_t m68k_encrypted_opcode_end[MAX_CPU];
+
+#define m68k_read_memory_8(address) (*m68k_memory_intf.read8)(address)
+#define m68k_read_memory_16(address) (*m68k_memory_intf.read16)(address)
+#define m68k_read_memory_32(address) (*m68k_memory_intf.read32)(address)
+
+#define m68k_read_immediate_16(address) m68kx_read_immediate_16(address)
+#define m68k_read_immediate_32(address) m68kx_read_immediate_32(address)
+#define m68k_read_pcrelative_8(address) m68kx_read_pcrelative_8(address)
+#define m68k_read_pcrelative_16(address) m68kx_read_pcrelative_16(address)
+#define m68k_read_pcrelative_32(address) m68kx_read_pcrelative_32(address)
+
+#define m68k_read_disassembler_16(address) m68kx_read_immediate_16(address)
+#define m68k_read_disassembler_32(address) m68kx_read_immediate_32(address)
+
+#define m68k_write_memory_8(address, value) (*m68k_memory_intf.write8)(address, value)
+#define m68k_write_memory_16(address, value) (*m68k_memory_intf.write16)(address, value)
+#define m68k_write_memory_32(address, value) (*m68k_memory_intf.write32)(address, value)
+#define m68k_write_memory_32_pd(address, value) m68kx_write_memory_32_pd(address, value)
+
+
+INLINE unsigned int m68k_read_immediate_16(unsigned int address);
+INLINE unsigned int m68k_read_immediate_32(unsigned int address);
+INLINE unsigned int m68k_read_pcrelative_8(unsigned int address);
+INLINE unsigned int m68k_read_pcrelative_16(unsigned int address);
+INLINE unsigned int m68k_read_pcrelative_32(unsigned int address);
+INLINE void m68k_write_memory_32_pd(unsigned int address, unsigned int value);
+
+
+INLINE unsigned int m68kx_read_immediate_16(unsigned int address)
+{
+ return cpu_readop16((address) ^ m68k_memory_intf.opcode_xor);
+}
+
+INLINE unsigned int m68kx_read_immediate_32(unsigned int address)
+{
+ return ((m68k_read_immediate_16(address) << 16) | m68k_read_immediate_16((address)+2));
+}
+
+INLINE unsigned int m68kx_read_pcrelative_8(unsigned int address)
+{
+ if (address >= m68k_encrypted_opcode_start[cpu_getactivecpu()] &&
+ address < m68k_encrypted_opcode_end[cpu_getactivecpu()])
+ return ((m68k_read_immediate_16(address&~1)>>(8*(1-(address & 1))))&0xff);
+ else
+ return m68k_read_memory_8(address);
+}
+
+INLINE unsigned int m68kx_read_pcrelative_16(unsigned int address)
+{
+ if (address >= m68k_encrypted_opcode_start[cpu_getactivecpu()] &&
+ address < m68k_encrypted_opcode_end[cpu_getactivecpu()])
+ return m68k_read_immediate_16(address);
+ else
+ return m68k_read_memory_16(address);
+}
+
+INLINE unsigned int m68kx_read_pcrelative_32(unsigned int address)
+{
+ if (address >= m68k_encrypted_opcode_start[cpu_getactivecpu()] &&
+ address < m68k_encrypted_opcode_end[cpu_getactivecpu()])
+ return m68k_read_immediate_32(address);
+ else
+ return m68k_read_memory_32(address);
+}
+
+
+/* Special call to simulate undocumented 68k behavior when move.l with a
+ * predecrement destination mode is executed.
+ * A real 68k first writes the high word to [address+2], and then writes the
+ * low word to [address].
+ */
+INLINE void m68kx_write_memory_32_pd(unsigned int address, unsigned int value)
+{
+ (*m68k_memory_intf.write16)(address+2, value>>16);
+ (*m68k_memory_intf.write16)(address, value&0xffff);
+}
+
+
+void m68k_set_encrypted_opcode_range(int cpunum, offs_t start, offs_t end);
+
+
+/* M68K Variants */
+#if HAS_M68008
+#define M68K_EMULATE_008 OPT_ON
+#else
+#define M68K_EMULATE_008 OPT_OFF
+#endif
+
+#if HAS_M68010
+#define M68K_EMULATE_010 OPT_ON
+#else
+#define M68K_EMULATE_010 OPT_OFF
+#endif
+
+#undef M68K_EMULATE_010
+#define M68K_EMULATE_010 OPT_ON
+
+#if HAS_M68EC020
+#define M68K_EMULATE_EC020 OPT_ON
+#else
+#define M68K_EMULATE_EC020 OPT_OFF
+#endif
+
+#if HAS_M68020
+#define M68K_EMULATE_020 OPT_ON
+#else
+#define M68K_EMULATE_020 OPT_OFF
+#endif
+
+#if HAS_M68040
+#define M68K_EMULATE_040 OPT_ON
+#else
+#define M68K_EMULATE_040 OPT_OFF
+#endif
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+#endif /* M68KMAME__HEADER */
diff --git a/src/emu/cpu/m6805/6805dasm.c b/src/emu/cpu/m6805/6805dasm.c
new file mode 100644
index 00000000000..79ea4c24868
--- /dev/null
+++ b/src/emu/cpu/m6805/6805dasm.c
@@ -0,0 +1,211 @@
+/*
+ * A quick-hack 68(7)05 disassembler
+ *
+ * Note: this is not the good and proper way to disassemble anything, but it works
+ *
+ * I'm afraid to put my name on it, but I feel obligated:
+ * This code written by Aaron Giles (agiles@sirius.com) for the MAME project
+ *
+ */
+
+#include "debugger.h"
+#include "m6805.h"
+
+enum addr_mode {
+ _imp=0, /* implicit */
+ _btr, /* bit test and relative */
+ _bit, /* bit set/clear */
+ _rel, /* relative */
+ _imm, /* immediate */
+ _dir, /* direct address */
+ _ext, /* extended address */
+ _idx, /* indexed */
+ _ix1, /* indexed + byte offset */
+ _ix2 /* indexed + word offset */
+};
+
+enum op_names {
+ adca=0, adda, anda, asl, asla, aslx, asr, asra,
+ asrx, bcc, bclr, bcs, beq, bhcc, bhcs, bhi,
+ bih, bil, bita, bls, bmc, bmi, bms, bne,
+ bpl, bra, brclr, brn, brset, bset, bsr, clc,
+ cli, clr, clra, clrx, cmpa, com, coma, comx,
+ cpx, dec, deca, decx, eora, ill, inc, inca,
+ incx, jmp, jsr, lda, ldx, lsr, lsra, lsrx,
+ neg, nega, negx, nop, ora, rol, rola, rolx,
+ ror, rora, rorx, rsp, rti, rts, sbca, sec,
+ sei, sta, stx, suba, swi, tax, tst, tsta,
+ tstx, txa
+};
+
+static const char *op_name_str[] = {
+ "adca", "adda", "anda", "asl", "asla", "aslx", "asr", "asra",
+ "asrx", "bcc", "bclr", "bcs", "beq", "bhcc", "bhcs", "bhi",
+ "bih", "bil", "bita", "bls", "bmc", "bmi", "bms", "bne",
+ "bpl", "bra", "brclr","brn", "brset","bset", "bsr", "clc",
+ "cli", "clr", "clra", "clrx", "cmpa", "com", "coma", "comx",
+ "cpx", "dec", "deca", "decx", "eora", "*ill", "inc", "inca",
+ "incx", "jmp", "jsr", "lda", "ldx", "lsr", "lsra", "lsrx",
+ "neg", "nega", "negx", "nop", "ora", "rol", "rola", "rolx",
+ "ror", "rora", "rorx", "rsp", "rti", "rts", "sbca", "sec",
+ "sei", "sta", "stx", "suba", "swi", "tax", "tst", "tsta",
+ "tstx", "txa"
+};
+
+static const unsigned char disasm[0x100][2] = {
+ {brset,_btr},{brclr,_btr},{brset,_btr},{brclr,_btr},/* 00 */
+ {brset,_btr},{brclr,_btr},{brset,_btr},{brclr,_btr},
+ {brset,_btr},{brclr,_btr},{brset,_btr},{brclr,_btr},
+ {brset,_btr},{brclr,_btr},{brset,_btr},{brclr,_btr},
+ {bset, _bit},{bclr, _bit},{bset, _bit},{bclr, _bit},/* 10 */
+ {bset, _bit},{bclr, _bit},{bset, _bit},{bclr, _bit},
+ {bset, _bit},{bclr, _bit},{bset, _bit},{bclr, _bit},
+ {bset, _bit},{bclr, _bit},{bset, _bit},{bclr, _bit},
+ {bra, _rel},{brn, _rel},{bhi, _rel},{bls, _rel},/* 20 */
+ {bcc, _rel},{bcs, _rel},{bne, _rel},{beq, _rel},
+ {bhcc, _rel},{bhcs, _rel},{bpl, _rel},{bmi, _rel},
+ {bmc, _rel},{bms, _rel},{bil, _rel},{bih, _rel},
+ {neg, _dir},{ill, _imp},{ill, _imp},{com, _dir},/* 30 */
+ {lsr, _dir},{ill, _imp},{ror, _dir},{asr, _dir},
+ {asl, _dir},{rol, _dir},{dec, _dir},{ill, _imp},
+ {inc, _dir},{tst, _dir},{ill, _imp},{clr, _dir},
+ {nega, _imp},{ill, _imp},{ill, _imp},{coma, _imp},/* 40 */
+ {lsra, _imp},{ill, _imp},{rora, _imp},{asra, _imp},
+ {asla, _imp},{rola, _imp},{deca, _imp},{ill, _imp},
+ {inca, _imp},{tsta, _imp},{ill, _imp},{clra, _imp},
+ {negx, _imp},{ill, _imp},{ill, _imp},{comx, _imp},/* 50 */
+ {lsrx, _imp},{ill, _imp},{rorx, _imp},{asrx, _imp},
+ {aslx, _imp},{rolx, _imp},{decx, _imp},{ill, _imp},
+ {incx, _imp},{tstx, _imp},{ill, _imp},{clrx, _imp},
+ {neg, _ix1},{ill, _imp},{ill, _imp},{com, _ix1},/* 60 */
+ {lsr, _ix1},{ill, _imp},{ror, _ix1},{asr, _ix1},
+ {asl, _ix1},{rol, _ix1},{dec, _ix1},{ill, _imp},
+ {inc, _ix1},{tst, _ix1},{jmp, _ix1},{clr, _ix1},
+ {neg, _idx},{ill, _imp},{ill, _imp},{com, _idx},/* 70 */
+ {lsr, _idx},{ill, _imp},{ror, _idx},{asr, _idx},
+ {asl, _idx},{rol, _idx},{dec, _idx},{ill, _imp},
+ {inc, _idx},{tst, _idx},{jmp, _idx},{clr, _idx},
+ {rti, _imp},{rts, _imp},{ill, _imp},{swi, _imp},/* 80 */
+ {ill, _imp},{ill, _imp},{ill, _imp},{ill, _imp},
+ {ill, _imp},{ill, _imp},{ill, _imp},{ill, _imp},
+ {ill, _imp},{ill, _imp},{ill, _imp},{ill, _imp},
+ {ill, _imp},{ill, _imp},{ill, _imp},{ill, _imp},/* 90 */
+ {ill, _imp},{ill, _imp},{ill, _imp},{tax, _imp},
+ {clc, _imp},{sec, _imp},{cli, _imp},{sei, _imp},
+ {rsp, _imp},{nop, _imp},{ill, _imp},{txa, _imp},
+ {suba, _imm},{cmpa, _imm},{sbca, _imm},{cpx, _imm},/* a0 */
+ {anda, _imm},{bita, _imm},{lda, _imm},{ill, _imp},
+ {eora, _imm},{adca, _imm},{ora, _imm},{adda, _imm},
+ {ill, _imp},{bsr, _rel},{ldx, _imm},{ill, _imp},
+ {suba, _dir},{cmpa, _dir},{sbca, _dir},{cpx, _dir},/* b0 */
+ {anda, _dir},{bita, _dir},{lda, _dir},{sta, _dir},
+ {eora, _dir},{adca, _dir},{ora, _dir},{adda, _dir},
+ {jmp, _dir},{jsr, _dir},{ldx, _dir},{stx, _dir},
+ {suba, _ext},{cmpa, _ext},{sbca, _ext},{cpx, _ext},/* c0 */
+ {anda, _ext},{bita, _ext},{lda, _ext},{sta, _ext},
+ {eora, _ext},{adca, _ext},{ora, _ext},{adda, _ext},
+ {jmp, _ext},{jsr, _ext},{ldx, _ext},{stx, _ext},
+ {suba, _ix2},{cmpa, _ix2},{sbca, _ix2},{cpx, _ix2},/* d0 */
+ {anda, _ix2},{bita, _ix2},{lda, _ix2},{sta, _ix2},
+ {eora, _ix2},{adca, _ix2},{ora, _ix2},{adda, _ix2},
+ {jmp, _ix2},{jsr, _ix2},{ldx, _ix2},{stx, _ix2},
+ {suba, _ix1},{cmpa, _ix1},{sbca, _ix1},{cpx, _ix1},/* e0 */
+ {anda, _ix1},{bita, _ix1},{lda, _ix1},{sta, _ix1},
+ {eora, _ix1},{adca, _ix1},{ora, _ix1},{adda, _ix1},
+ {jmp, _ix1},{jsr, _ix1},{ldx, _ix1},{stx, _ix1},
+ {suba, _idx},{cmpa, _idx},{sbca, _idx},{cpx, _idx},/* f0 */
+ {anda, _idx},{bita, _idx},{lda, _idx},{sta, _idx},
+ {eora, _idx},{adca, _idx},{ora, _idx},{adda, _idx},
+ {jmp, _idx},{jsr, _idx},{ldx, _idx},{stx, _idx}
+};
+
+#if 0
+static char *opcode_strings[0x0100] =
+{
+ "brset0", "brclr0", "brset1", "brclr1", "brset2", "brclr2", "brset3", "brclr3", /*00*/
+ "brset4", "brclr4", "brset5", "brclr5", "brset6", "brclr6", "brset7", "brclr7",
+ "bset0", "bclr0", "bset1", "bclr1", "bset2", "bclr2", "bset3", "bclr3", /*10*/
+ "bset4", "bclr4", "bset5", "bclr5", "bset6", "bclr6", "bset7", "bclr7",
+ "bra", "brn", "bhi", "bls", "bcc", "bcs", "bne", "beq", /*20*/
+ "bhcc", "bhcs", "bpl", "bmi", "bmc", "bms", "bil", "bih",
+ "neg_di", "illegal", "illegal", "com_di", "lsr_di", "illegal", "ror_di", "asr_di", /*30*/
+ "asl_di", "rol_di", "dec_di", "illegal", "inc_di", "tst_di", "illegal", "clr_di",
+ "nega", "illegal", "illegal", "coma", "lsra", "illegal", "rora", "asra", /*40*/
+ "asla", "rola", "deca", "illegal", "inca", "tsta", "illegal", "clra",
+ "negx", "illegal", "illegal", "comx", "lsrx", "illegal", "rorx", "asrx", /*50*/
+ "aslx", "rolx", "decx", "illegal", "incx", "tstx", "illegal", "clrx",
+ "neg_ix1", "illegal", "illegal", "com_ix1", "lsr_ix1", "illegal", "ror_ix1", "asr_ix1", /*60*/
+ "asl_ix1", "rol_ix1", "dec_ix1", "illegal", "inc_ix1", "tst_ix1", "jmp_ix1", "clr_ix1",
+ "neg_ix", "illegal", "illegal", "com_ix", "lsr_ix", "illegal", "ror_ix", "asr_ix", /*70*/
+ "asl_ix", "rol_ix", "dec_ix", "illegal", "inc_ix", "tst_ix", "jmp_ix", "clr_ix",
+ "rti", "rts", "illegal", "swi", "illegal", "illegal", "illegal", "illegal", /*80*/
+ "illegal", "illegal", "illegal", "illegal", "illegal", "illegal", "illegal", "illegal",
+ "illegal", "illegal", "illegal", "illegal", "illegal", "illegal", "illegal", "tax", /*90*/
+ "clc", "sec", "cli", "sei", "rsp", "nop", "illegal", "txa",
+ "suba_im", "cmpa_im", "sbca_im", "cpx_im", "anda_im", "bita_im", "lda_im", "illegal", /*A0*/
+ "eora_im", "adca_im", "ora_im", "adda_im", "illegal", "bsr", "ldx_im", "illegal",
+ "suba_di", "cmpa_di", "sbca_di", "cpx_di", "anda_di", "bita_di", "lda_di", "sta_di", /*B0*/
+ "eora_di", "adca_di", "ora_di", "adda_di", "jmp_di", "jsr_di", "ldx_di", "stx_di",
+ "suba_ex", "cmpa_ex", "sbca_ex", "cpx_ex", "anda_ex", "bita_ex", "lda_ex", "sta_ex", /*C0*/
+ "eora_ex", "adca_ex", "ora_ex", "adda_ex", "jmp_ex", "jsr_ex", "ldx_ex", "stx_ex",
+ "suba_ix2", "cmpa_ix2", "sbca_ix2", "cpx_ix2", "anda_ix2", "bita_ix2", "lda_ix2", "sta_ix2", /*D0*/
+ "eora_ix2", "adca_ix2", "ora_ix2", "adda_ix2", "jmp_ix2", "jsr_ix2", "ldx_ix2", "stx_ix2",
+ "suba_ix1", "cmpa_ix1", "sbca_ix1", "cpx_ix1", "anda_ix1", "bita_ix1", "lda_ix1", "sta_ix1", /*E0*/
+ "eora_ix1", "adca_ix1", "ora_ix1", "adda_ix1", "jmp_ix1", "jsr_ix1", "ldx_ix1", "stx_ix1",
+ "suba_ix", "cmpa_ix", "sbca_ix", "cpx_ix", "anda_ix", "bita_ix", "lda_ix", "sta_ix", /*F0*/
+ "eora_ix", "adca_ix", "ora_ix", "adda_ix", "jmp_ix", "jsr_ix", "ldx_ix", "stx_ix"
+};
+#endif
+
+offs_t m6805_dasm(char *buf, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int code, bit;
+ UINT16 ea;
+ UINT32 flags = 0;
+
+ code = oprom[0];
+
+ if (disasm[code][0] == bsr || disasm[code][0] == jsr)
+ flags = DASMFLAG_STEP_OVER;
+ else if (disasm[code][0] == rts || disasm[code][0] == rti)
+ flags = DASMFLAG_STEP_OUT;
+
+ buf += sprintf(buf, "%-6s", op_name_str[disasm[code][0]]);
+
+ switch( disasm[code][1] )
+ {
+ case _btr: /* bit test and relative branch */
+ bit = (code >> 1) & 7;
+ sprintf (buf, "%d,$%02X,$%03X", bit, opram[1], pc + 3 + (INT8)opram[2]);
+ return 3 | flags | DASMFLAG_SUPPORTED;
+ case _bit: /* bit test */
+ bit = (code >> 1) & 7;
+ sprintf (buf, "%d,$%03X", bit, opram[1]);
+ return 2 | flags | DASMFLAG_SUPPORTED;
+ case _rel: /* relative */
+ sprintf (buf, "$%03X", pc + 2 + (INT8)opram[1]);
+ return 2 | flags | DASMFLAG_SUPPORTED;
+ case _imm: /* immediate */
+ sprintf (buf, "#$%02X", opram[1]);
+ return 2 | flags | DASMFLAG_SUPPORTED;
+ case _dir: /* direct (zero page address) */
+ sprintf (buf, "$%02X", opram[1]);
+ return 2 | flags | DASMFLAG_SUPPORTED;
+ case _ext: /* extended (16 bit address) */
+ ea = (opram[1] << 8) + opram[2];
+ sprintf (buf, "$%04X", ea);
+ return 3 | flags | DASMFLAG_SUPPORTED;
+ case _idx: /* indexed */
+ sprintf (buf, "(x)");
+ return 1 | flags | DASMFLAG_SUPPORTED;
+ case _ix1: /* indexed + byte (zero page) */
+ sprintf (buf, "(x+$%02X)", opram[1]);
+ return 2 | flags | DASMFLAG_SUPPORTED;
+ case _ix2: /* indexed + word (16 bit address) */
+ ea = (opram[1] << 8) + opram[2];
+ sprintf (buf, "(x+$%04X)", ea);
+ return 3 | flags | DASMFLAG_SUPPORTED;
+ default: /* implicit */
+ return 1 | flags | DASMFLAG_SUPPORTED;
+ }
+}
diff --git a/src/emu/cpu/m6805/6805ops.c b/src/emu/cpu/m6805/6805ops.c
new file mode 100644
index 00000000000..3ad923cc88f
--- /dev/null
+++ b/src/emu/cpu/m6805/6805ops.c
@@ -0,0 +1,1822 @@
+
+/*
+
+HNZC
+
+? = undefined
+* = affected
+- = unaffected
+0 = cleared
+1 = set
+# = ccr directly affected by instruction
+@ = special - carry set if bit 7 is set
+
+*/
+
+static void illegal( void )
+{
+ logerror("M6805: illegal opcode\n");
+}
+
+/* $00/$02/$04/$06/$08/$0A/$0C/$0E BRSET direct,relative ---- */
+INLINE void brset (UINT8 bit)
+{
+ UINT8 t,r;
+ DIRBYTE(r);
+ IMMBYTE(t);
+
+ CLC;
+
+ if (r&bit) {
+ SEC;
+ PC+=SIGNED(t);
+
+ if (t==0xfd)
+ {
+ /* speed up busy loops */
+ if(m6805_ICount > 0)
+ m6805_ICount = 0;
+ }
+ }
+}
+
+/* $01/$03/$05/$07/$09/$0B/$0D/$0F BRCLR direct,relative ---- */
+INLINE void brclr (UINT8 bit)
+{
+ UINT8 t,r;
+ DIRBYTE(r);
+ IMMBYTE(t);
+
+ SEC;
+
+ if (!(r&bit)) {
+ CLC;
+ PC+=SIGNED(t);
+
+ if (t==0xfd)
+ {
+ /* speed up busy loops */
+ if(m6805_ICount > 0)
+ m6805_ICount = 0;
+ }
+ }
+}
+
+/* $10/$12/$14/$16/$18/$1A/$1C/$1E BSET direct ---- */
+INLINE void bset (UINT8 bit)
+{
+ UINT8 t,r;
+ DIRBYTE(t); r=t|bit;
+ WM(EAD,r);
+}
+
+/* $11/$13/$15/$17/$19/$1B/$1D/$1F BCLR direct ---- */
+INLINE void bclr (UINT8 bit)
+{
+ UINT8 t,r;
+ DIRBYTE(t); r=t&(~bit);
+ WM(EAD,r);
+}
+
+/* $20 BRA relative ---- */
+INLINE void bra( void )
+{
+ UINT8 t;
+ IMMBYTE(t);PC+=SIGNED(t);
+ if (t==0xfe)
+ {
+ /* speed up busy loops */
+ if(m6805_ICount > 0)
+ m6805_ICount = 0;
+ }
+}
+
+/* $21 BRN relative ---- */
+INLINE void brn( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+}
+
+/* $22 BHI relative ---- */
+INLINE void bhi( void )
+{
+ BRANCH( !(CC&(CFLAG|ZFLAG)) );
+}
+
+/* $23 BLS relative ---- */
+INLINE void bls( void )
+{
+ BRANCH( CC&(CFLAG|ZFLAG) );
+}
+
+/* $24 BCC relative ---- */
+INLINE void bcc( void )
+{
+ BRANCH( !(CC&CFLAG) );
+}
+
+/* $25 BCS relative ---- */
+INLINE void bcs( void )
+{
+ BRANCH( CC&CFLAG );
+}
+
+/* $26 BNE relative ---- */
+INLINE void bne( void )
+{
+ BRANCH( !(CC&ZFLAG) );
+}
+
+/* $27 BEQ relative ---- */
+INLINE void beq( void )
+{
+ BRANCH( CC&ZFLAG );
+}
+
+/* $28 BHCC relative ---- */
+INLINE void bhcc( void )
+{
+ BRANCH( !(CC&HFLAG) );
+}
+
+/* $29 BHCS relative ---- */
+INLINE void bhcs( void )
+{
+ BRANCH( CC&HFLAG );
+}
+
+/* $2a BPL relative ---- */
+INLINE void bpl( void )
+{
+ BRANCH( !(CC&NFLAG) );
+}
+
+/* $2b BMI relative ---- */
+INLINE void bmi( void )
+{
+ BRANCH( CC&NFLAG );
+}
+
+/* $2c BMC relative ---- */
+INLINE void bmc( void )
+{
+ BRANCH( !(CC&IFLAG) );
+}
+
+/* $2d BMS relative ---- */
+INLINE void bms( void )
+{
+ BRANCH( CC&IFLAG );
+}
+
+/* $2e BIL relative ---- */
+INLINE void bil( void )
+{
+ if(SUBTYPE==SUBTYPE_HD63705)
+ {
+ BRANCH( m6805.nmi_state!=CLEAR_LINE );
+ }
+ else
+ {
+ BRANCH( m6805.irq_state[0]!=CLEAR_LINE );
+ }
+}
+
+/* $2f BIH relative ---- */
+INLINE void bih( void )
+{
+ if(SUBTYPE==SUBTYPE_HD63705)
+ {
+ BRANCH( m6805.nmi_state==CLEAR_LINE );
+ }
+ else
+ {
+ BRANCH( m6805.irq_state[0]==CLEAR_LINE );
+ }
+}
+
+/* $30 NEG direct -*** */
+INLINE void neg_di( void )
+{
+ UINT8 t;
+ UINT16 r;
+ DIRBYTE(t); r=-t;
+ CLR_NZC; SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $31 ILLEGAL */
+
+/* $32 ILLEGAL */
+
+/* $33 COM direct -**1 */
+INLINE void com_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t); t = ~t;
+ CLR_NZ; SET_NZ8(t); SEC;
+ WM(EAD,t);
+}
+
+/* $34 LSR direct -0** */
+INLINE void lsr_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZC;
+ CC |= (t&0x01);
+ t >>= 1;
+ SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $35 ILLEGAL */
+
+/* $36 ROR direct -*** */
+INLINE void ror_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r = (CC & 0x01) << 7;
+ CLR_NZC;
+ CC |= (t & 0x01);
+ r |= t>>1;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $37 ASR direct ?*** */
+INLINE void asr_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZC; CC|=(t&0x01);
+ t>>=1; t|=((t&0x40)<<1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $38 LSL direct ?*** */
+INLINE void lsl_di( void )
+{
+ UINT8 t;
+ UINT16 r;
+ DIRBYTE(t);
+ r = t << 1;
+ CLR_NZC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $39 ROL direct -*** */
+INLINE void rol_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = CC & 0x01;
+ r |= t << 1;
+ CLR_NZC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $3a DEC direct -**- */
+INLINE void dec_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ --t;
+ CLR_NZ; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $3b ILLEGAL */
+
+/* $3c INC direct -**- */
+INLINE void inc_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ ++t;
+ CLR_NZ; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $3d TST direct -**- */
+INLINE void tst_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZ; SET_NZ8(t);
+}
+
+/* $3e ILLEGAL */
+
+/* $3f CLR direct -0100 */
+INLINE void clr_di( void )
+{
+ DIRECT;
+ CLR_NZC; SEZ;
+ WM(EAD,0);
+}
+
+/* $40 NEGA inherent ?*** */
+INLINE void nega( void )
+{
+ UINT16 r;
+ r = -A;
+ CLR_NZC; SET_FLAGS8(0,A,r);
+ A = r;
+}
+
+/* $41 ILLEGAL */
+
+/* $42 ILLEGAL */
+
+/* $43 COMA inherent -**1 */
+INLINE void coma( void )
+{
+ A = ~A;
+ CLR_NZ;
+ SET_NZ8(A);
+ SEC;
+}
+
+/* $44 LSRA inherent -0** */
+INLINE void lsra( void )
+{
+ CLR_NZC;
+ CC |= (A & 0x01);
+ A >>= 1;
+ SET_Z8(A);
+}
+
+/* $45 ILLEGAL */
+
+/* $46 RORA inherent -*** */
+INLINE void rora( void )
+{
+ UINT8 r;
+ r = (CC & 0x01) << 7;
+ CLR_NZC;
+ CC |= (A & 0x01);
+ r |= A >> 1;
+ SET_NZ8(r);
+ A = r;
+}
+
+/* $47 ASRA inherent ?*** */
+INLINE void asra( void )
+{
+ CLR_NZC;
+ CC |= (A & 0x01);
+ A = (A & 0x80) | (A >> 1);
+ SET_NZ8(A);
+}
+
+/* $48 LSLA inherent ?*** */
+INLINE void lsla( void )
+{
+ UINT16 r;
+ r = A << 1;
+ CLR_NZC;
+ SET_FLAGS8(A,A,r);
+ A = r;
+}
+
+/* $49 ROLA inherent -*** */
+INLINE void rola( void )
+{
+ UINT16 t,r;
+ t = A;
+ r = CC & 0x01;
+ r |= t << 1;
+ CLR_NZC;
+ SET_FLAGS8(t,t,r);
+ A = r;
+}
+
+/* $4a DECA inherent -**- */
+INLINE void deca( void )
+{
+ --A;
+ CLR_NZ;
+ SET_FLAGS8D(A);
+}
+
+/* $4b ILLEGAL */
+
+/* $4c INCA inherent -**- */
+INLINE void inca( void )
+{
+ ++A;
+ CLR_NZ;
+ SET_FLAGS8I(A);
+}
+
+/* $4d TSTA inherent -**- */
+INLINE void tsta( void )
+{
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $4e ILLEGAL */
+
+/* $4f CLRA inherent -010 */
+INLINE void clra( void )
+{
+ A = 0;
+ CLR_NZ;
+ SEZ;
+}
+
+/* $50 NEGX inherent ?*** */
+INLINE void negx( void )
+{
+ UINT16 r;
+ r = -X;
+ CLR_NZC;
+ SET_FLAGS8(0,X,r);
+ X = r;
+}
+
+/* $51 ILLEGAL */
+
+/* $52 ILLEGAL */
+
+/* $53 COMX inherent -**1 */
+INLINE void comx( void )
+{
+ X = ~X;
+ CLR_NZ;
+ SET_NZ8(X);
+ SEC;
+}
+
+/* $54 LSRX inherent -0** */
+INLINE void lsrx( void )
+{
+ CLR_NZC;
+ CC |= (X & 0x01);
+ X >>= 1;
+ SET_Z8(X);
+}
+
+/* $55 ILLEGAL */
+
+/* $56 RORX inherent -*** */
+INLINE void rorx( void )
+{
+ UINT8 r;
+ r = (CC & 0x01) << 7;
+ CLR_NZC;
+ CC |= (X & 0x01);
+ r |= X>>1;
+ SET_NZ8(r);
+ X = r;
+}
+
+/* $57 ASRX inherent ?*** */
+INLINE void asrx( void )
+{
+ CLR_NZC;
+ CC |= (X & 0x01);
+ X = (X & 0x80) | (X >> 1);
+ SET_NZ8(X);
+}
+
+/* $58 ASLX inherent ?*** */
+INLINE void aslx( void )
+{
+ UINT16 r;
+ r = X << 1;
+ CLR_NZC;
+ SET_FLAGS8(X,X,r);
+ X = r;
+}
+
+/* $59 ROLX inherent -*** */
+INLINE void rolx( void )
+{
+ UINT16 t,r;
+ t = X;
+ r = CC & 0x01;
+ r |= t<<1;
+ CLR_NZC;
+ SET_FLAGS8(t,t,r);
+ X = r;
+}
+
+/* $5a DECX inherent -**- */
+INLINE void decx( void )
+{
+ --X;
+ CLR_NZ;
+ SET_FLAGS8D(X);
+}
+
+/* $5b ILLEGAL */
+
+/* $5c INCX inherent -**- */
+INLINE void incx( void )
+{
+ ++X;
+ CLR_NZ;
+ SET_FLAGS8I(X);
+}
+
+/* $5d TSTX inherent -**- */
+INLINE void tstx( void )
+{
+ CLR_NZ;
+ SET_NZ8(X);
+}
+
+/* $5e ILLEGAL */
+
+/* $5f CLRX inherent -010 */
+INLINE void clrx( void )
+{
+ X = 0;
+ CLR_NZC;
+ SEZ;
+}
+
+/* $60 NEG indexed, 1 byte offset -*** */
+INLINE void neg_ix1( void )
+{
+ UINT8 t;
+ UINT16 r;
+ IDX1BYTE(t); r=-t;
+ CLR_NZC; SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $61 ILLEGAL */
+
+/* $62 ILLEGAL */
+
+/* $63 COM indexed, 1 byte offset -**1 */
+INLINE void com_ix1( void )
+{
+ UINT8 t;
+ IDX1BYTE(t); t = ~t;
+ CLR_NZ; SET_NZ8(t); SEC;
+ WM(EAD,t);
+}
+
+/* $64 LSR indexed, 1 byte offset -0** */
+INLINE void lsr_ix1( void )
+{
+ UINT8 t;
+ IDX1BYTE(t);
+ CLR_NZC;
+ CC |= (t & 0x01);
+ t >>= 1;
+ SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $65 ILLEGAL */
+
+/* $66 ROR indexed, 1 byte offset -*** */
+INLINE void ror_ix1( void )
+{
+ UINT8 t,r;
+ IDX1BYTE(t);
+ r = (CC & 0x01) << 7;
+ CLR_NZC;
+ CC |= (t & 0x01);
+ r |= t>>1;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $67 ASR indexed, 1 byte offset ?*** */
+INLINE void asr_ix1( void )
+{
+ UINT8 t;
+ IDX1BYTE(t);
+ CLR_NZC; CC|=(t&0x01);
+ t>>=1; t|=((t&0x40)<<1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $68 LSL indexed, 1 byte offset ?*** */
+INLINE void lsl_ix1( void )
+{
+ UINT8 t;
+ UINT16 r;
+ IDX1BYTE(t);
+ r = t << 1;
+ CLR_NZC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $69 ROL indexed, 1 byte offset -*** */
+INLINE void rol_ix1( void )
+{
+ UINT16 t,r;
+ IDX1BYTE(t);
+ r = CC & 0x01;
+ r |= t << 1;
+ CLR_NZC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $6a DEC indexed, 1 byte offset -**- */
+INLINE void dec_ix1( void )
+{
+ UINT8 t;
+ IDX1BYTE(t);
+ --t;
+ CLR_NZ; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $6b ILLEGAL */
+
+/* $6c INC indexed, 1 byte offset -**- */
+INLINE void inc_ix1( void )
+{
+ UINT8 t;
+ IDX1BYTE(t);
+ ++t;
+ CLR_NZ; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $6d TST indexed, 1 byte offset -**- */
+INLINE void tst_ix1( void )
+{
+ UINT8 t;
+ IDX1BYTE(t);
+ CLR_NZ; SET_NZ8(t);
+}
+
+/* $6e ILLEGAL */
+
+/* $6f CLR indexed, 1 byte offset -0100 */
+INLINE void clr_ix1( void )
+{
+ INDEXED1;
+ CLR_NZC; SEZ;
+ WM(EAD,0);
+}
+
+/* $70 NEG indexed -*** */
+INLINE void neg_ix( void )
+{
+ UINT8 t;
+ UINT16 r;
+ IDXBYTE(t); r=-t;
+ CLR_NZC; SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $71 ILLEGAL */
+
+/* $72 ILLEGAL */
+
+/* $73 COM indexed -**1 */
+INLINE void com_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t); t = ~t;
+ CLR_NZ; SET_NZ8(t); SEC;
+ WM(EAD,t);
+}
+
+/* $74 LSR indexed -0** */
+INLINE void lsr_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t);
+ CLR_NZC;
+ CC |= (t & 0x01);
+ t >>= 1;
+ SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $75 ILLEGAL */
+
+/* $76 ROR indexed -*** */
+INLINE void ror_ix( void )
+{
+ UINT8 t,r;
+ IDXBYTE(t);
+ r = (CC & 0x01) << 7;
+ CLR_NZC;
+ CC |= (t & 0x01);
+ r |= t >> 1;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $77 ASR indexed ?*** */
+INLINE void asr_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t);
+ CLR_NZC;
+ CC |= (t & 0x01);
+ t = (t & 0x80) | (t >> 1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $78 LSL indexed ?*** */
+INLINE void lsl_ix( void )
+{
+ UINT8 t;
+ UINT16 r;
+ IDXBYTE(t); r=t<<1;
+ CLR_NZC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $79 ROL indexed -*** */
+INLINE void rol_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t);
+ r = CC & 0x01;
+ r |= t << 1;
+ CLR_NZC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $7a DEC indexed -**- */
+INLINE void dec_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t);
+ --t;
+ CLR_NZ; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $7b ILLEGAL */
+
+/* $7c INC indexed -**- */
+INLINE void inc_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t);
+ ++t;
+ CLR_NZ; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $7d TST indexed -**- */
+INLINE void tst_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t);
+ CLR_NZ; SET_NZ8(t);
+}
+
+/* $7e ILLEGAL */
+
+/* $7f CLR indexed -0100 */
+INLINE void clr_ix( void )
+{
+ INDEXED;
+ CLR_NZC; SEZ;
+ WM(EAD,0);
+}
+
+/* $80 RTI inherent #### */
+INLINE void rti( void )
+{
+ PULLBYTE(CC);
+ PULLBYTE(A);
+ PULLBYTE(X);
+ PULLWORD(pPC);
+ change_pc(PC);
+#if IRQ_LEVEL_DETECT
+ if( m6805.irq_state != CLEAR_LINE && (CC & IFLAG) == 0 )
+ m6805.pending_interrupts |= M6805_INT_IRQ;
+#endif
+}
+
+/* $81 RTS inherent ---- */
+INLINE void rts( void )
+{
+ PULLWORD(pPC);
+ change_pc(PC);
+}
+
+/* $82 ILLEGAL */
+
+/* $83 SWI absolute indirect ---- */
+INLINE void swi( void )
+{
+ PUSHWORD(m6805.pc);
+ PUSHBYTE(m6805.x);
+ PUSHBYTE(m6805.a);
+ PUSHBYTE(m6805.cc);
+ SEI;
+ if(SUBTYPE==SUBTYPE_HD63705) RM16( 0x1ffa, &pPC ); else RM16( 0xfffc, &pPC );
+ change_pc(PC);
+}
+
+/* $84 ILLEGAL */
+
+/* $85 ILLEGAL */
+
+/* $86 ILLEGAL */
+
+/* $87 ILLEGAL */
+
+/* $88 ILLEGAL */
+
+/* $89 ILLEGAL */
+
+/* $8A ILLEGAL */
+
+/* $8B ILLEGAL */
+
+/* $8C ILLEGAL */
+
+/* $8D ILLEGAL */
+
+/* $8E ILLEGAL */
+
+/* $8F ILLEGAL */
+
+/* $90 ILLEGAL */
+
+/* $91 ILLEGAL */
+
+/* $92 ILLEGAL */
+
+/* $93 ILLEGAL */
+
+/* $94 ILLEGAL */
+
+/* $95 ILLEGAL */
+
+/* $96 ILLEGAL */
+
+/* $97 TAX inherent ---- */
+INLINE void tax (void)
+{
+ X = A;
+}
+
+/* $98 CLC */
+
+/* $99 SEC */
+
+/* $9A CLI */
+
+/* $9B SEI */
+
+/* $9C RSP inherent ---- */
+INLINE void rsp (void)
+{
+ S = SP_MASK;
+}
+
+/* $9D NOP inherent ---- */
+INLINE void nop (void)
+{
+}
+
+/* $9E ILLEGAL */
+
+/* $9F TXA inherent ---- */
+INLINE void txa (void)
+{
+ A = X;
+}
+
+/* $a0 SUBA immediate ?*** */
+INLINE void suba_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a1 CMPA immediate ?*** */
+INLINE void cmpa_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $a2 SBCA immediate ?*** */
+INLINE void sbca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t - (CC & 0x01);
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a3 CPX immediate -*** */
+INLINE void cpx_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = X - t;
+ CLR_NZC;
+ SET_FLAGS8(X,t,r);
+}
+
+/* $a4 ANDA immediate -**- */
+INLINE void anda_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A &= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $a5 BITA immediate -**- */
+INLINE void bita_im( void )
+{
+ UINT8 t,r;
+ IMMBYTE(t);
+ r = A & t;
+ CLR_NZ;
+ SET_NZ8(r);
+}
+
+/* $a6 LDA immediate -**- */
+INLINE void lda_im( void )
+{
+ IMMBYTE(A);
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $a7 ILLEGAL */
+
+/* $a8 EORA immediate -**- */
+INLINE void eora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A ^= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $a9 ADCA immediate **** */
+INLINE void adca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A + t + (CC & 0x01);
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $aa ORA immediate -**- */
+INLINE void ora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A |= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $ab ADDA immediate **** */
+INLINE void adda_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A + t;
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $ac ILLEGAL */
+
+/* $ad BSR ---- */
+INLINE void bsr( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ PUSHWORD(m6805.pc);
+ PC += SIGNED(t);
+}
+
+/* $ae LDX immediate -**- */
+INLINE void ldx_im( void )
+{
+ IMMBYTE(X);
+ CLR_NZ;
+ SET_NZ8(X);
+}
+
+/* $af ILLEGAL */
+
+/* $b0 SUBA direct ?*** */
+INLINE void suba_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b1 CMPA direct ?*** */
+INLINE void cmpa_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $b2 SBCA direct ?*** */
+INLINE void sbca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t - (CC & 0x01);
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b3 CPX direct -*** */
+INLINE void cpx_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = X - t;
+ CLR_NZC;
+ SET_FLAGS8(X,t,r);
+}
+
+/* $b4 ANDA direct -**- */
+INLINE void anda_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A &= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $b5 BITA direct -**- */
+INLINE void bita_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r = A & t;
+ CLR_NZ;
+ SET_NZ8(r);
+}
+
+/* $b6 LDA direct -**- */
+INLINE void lda_di( void )
+{
+ DIRBYTE(A);
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $b7 STA direct -**- */
+INLINE void sta_di( void )
+{
+ CLR_NZ;
+ SET_NZ8(A);
+ DIRECT;
+ WM(EAD,A);
+}
+
+/* $b8 EORA direct -**- */
+INLINE void eora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A ^= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $b9 ADCA direct **** */
+INLINE void adca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A + t + (CC & 0x01);
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $ba ORA direct -**- */
+INLINE void ora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A |= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $bb ADDA direct **** */
+INLINE void adda_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A + t;
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $bc JMP direct -*** */
+INLINE void jmp_di( void )
+{
+ DIRECT;
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $bd JSR direct ---- */
+INLINE void jsr_di( void )
+{
+ DIRECT;
+ PUSHWORD(m6805.pc);
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $be LDX direct -**- */
+INLINE void ldx_di( void )
+{
+ DIRBYTE(X);
+ CLR_NZ;
+ SET_NZ8(X);
+}
+
+/* $bf STX direct -**- */
+INLINE void stx_di( void )
+{
+ CLR_NZ;
+ SET_NZ8(X);
+ DIRECT;
+ WM(EAD,X);
+}
+
+/* $c0 SUBA extended ?*** */
+INLINE void suba_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $c1 CMPA extended ?*** */
+INLINE void cmpa_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $c2 SBCA extended ?*** */
+INLINE void sbca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t - (CC & 0x01);
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $c3 CPX extended -*** */
+INLINE void cpx_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = X - t;
+ CLR_NZC;
+ SET_FLAGS8(X,t,r);
+}
+
+/* $c4 ANDA extended -**- */
+INLINE void anda_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A &= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $c5 BITA extended -**- */
+INLINE void bita_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t);
+ r = A & t;
+ CLR_NZ;
+ SET_NZ8(r);
+}
+
+/* $c6 LDA extended -**- */
+INLINE void lda_ex( void )
+{
+ EXTBYTE(A);
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $c7 STA extended -**- */
+INLINE void sta_ex( void )
+{
+ CLR_NZ;
+ SET_NZ8(A);
+ EXTENDED;
+ WM(EAD,A);
+}
+
+/* $c8 EORA extended -**- */
+INLINE void eora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A ^= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $c9 ADCA extended **** */
+INLINE void adca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A + t + (CC & 0x01);
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $ca ORA extended -**- */
+INLINE void ora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A |= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $cb ADDA extended **** */
+INLINE void adda_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A + t;
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $cc JMP extended -*** */
+INLINE void jmp_ex( void )
+{
+ EXTENDED;
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $cd JSR extended ---- */
+INLINE void jsr_ex( void )
+{
+ EXTENDED;
+ PUSHWORD(m6805.pc);
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $ce LDX extended -**- */
+INLINE void ldx_ex( void )
+{
+ EXTBYTE(X);
+ CLR_NZ;
+ SET_NZ8(X);
+}
+
+/* $cf STX extended -**- */
+INLINE void stx_ex( void )
+{
+ CLR_NZ;
+ SET_NZ8(X);
+ EXTENDED;
+ WM(EAD,X);
+}
+
+/* $d0 SUBA indexed, 2 byte offset ?*** */
+INLINE void suba_ix2( void )
+{
+ UINT16 t,r;
+ IDX2BYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $d1 CMPA indexed, 2 byte offset ?*** */
+INLINE void cmpa_ix2( void )
+{
+ UINT16 t,r;
+ IDX2BYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $d2 SBCA indexed, 2 byte offset ?*** */
+INLINE void sbca_ix2( void )
+{
+ UINT16 t,r;
+ IDX2BYTE(t);
+ r = A - t - (CC & 0x01);
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $d3 CPX indexed, 2 byte offset -*** */
+INLINE void cpx_ix2( void )
+{
+ UINT16 t,r;
+ IDX2BYTE(t);
+ r = X - t;
+ CLR_NZC;
+ SET_FLAGS8(X,t,r);
+}
+
+/* $d4 ANDA indexed, 2 byte offset -**- */
+INLINE void anda_ix2( void )
+{
+ UINT8 t;
+ IDX2BYTE(t);
+ A &= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $d5 BITA indexed, 2 byte offset -**- */
+INLINE void bita_ix2( void )
+{
+ UINT8 t,r;
+ IDX2BYTE(t);
+ r = A & t;
+ CLR_NZ;
+ SET_NZ8(r);
+}
+
+/* $d6 LDA indexed, 2 byte offset -**- */
+INLINE void lda_ix2( void )
+{
+ IDX2BYTE(A);
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $d7 STA indexed, 2 byte offset -**- */
+INLINE void sta_ix2( void )
+{
+ CLR_NZ;
+ SET_NZ8(A);
+ INDEXED2;
+ WM(EAD,A);
+}
+
+/* $d8 EORA indexed, 2 byte offset -**- */
+INLINE void eora_ix2( void )
+{
+ UINT8 t;
+ IDX2BYTE(t);
+ A ^= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $d9 ADCA indexed, 2 byte offset **** */
+INLINE void adca_ix2( void )
+{
+ UINT16 t,r;
+ IDX2BYTE(t);
+ r = A + t + (CC & 0x01);
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $da ORA indexed, 2 byte offset -**- */
+INLINE void ora_ix2( void )
+{
+ UINT8 t;
+ IDX2BYTE(t);
+ A |= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $db ADDA indexed, 2 byte offset **** */
+INLINE void adda_ix2( void )
+{
+ UINT16 t,r;
+ IDX2BYTE(t);
+ r = A + t;
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $dc JMP indexed, 2 byte offset -*** */
+INLINE void jmp_ix2( void )
+{
+ INDEXED2;
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $dd JSR indexed, 2 byte offset ---- */
+INLINE void jsr_ix2( void )
+{
+ INDEXED2;
+ PUSHWORD(m6805.pc);
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $de LDX indexed, 2 byte offset -**- */
+INLINE void ldx_ix2( void )
+{
+ IDX2BYTE(X);
+ CLR_NZ;
+ SET_NZ8(X);
+}
+
+/* $df STX indexed, 2 byte offset -**- */
+INLINE void stx_ix2( void )
+{
+ CLR_NZ;
+ SET_NZ8(X);
+ INDEXED2;
+ WM(EAD,X);
+}
+
+/* $e0 SUBA indexed, 1 byte offset ?*** */
+INLINE void suba_ix1( void )
+{
+ UINT16 t,r;
+ IDX1BYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $e1 CMPA indexed, 1 byte offset ?*** */
+INLINE void cmpa_ix1( void )
+{
+ UINT16 t,r;
+ IDX1BYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $e2 SBCA indexed, 1 byte offset ?*** */
+INLINE void sbca_ix1( void )
+{
+ UINT16 t,r;
+ IDX1BYTE(t);
+ r = A - t - (CC & 0x01);
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $e3 CPX indexed, 1 byte offset -*** */
+INLINE void cpx_ix1( void )
+{
+ UINT16 t,r;
+ IDX1BYTE(t);
+ r = X - t;
+ CLR_NZC;
+ SET_FLAGS8(X,t,r);
+}
+
+/* $e4 ANDA indexed, 1 byte offset -**- */
+INLINE void anda_ix1( void )
+{
+ UINT8 t;
+ IDX1BYTE(t);
+ A &= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $e5 BITA indexed, 1 byte offset -**- */
+INLINE void bita_ix1( void )
+{
+ UINT8 t,r;
+ IDX1BYTE(t);
+ r = A & t;
+ CLR_NZ;
+ SET_NZ8(r);
+}
+
+/* $e6 LDA indexed, 1 byte offset -**- */
+INLINE void lda_ix1( void )
+{
+ IDX1BYTE(A);
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $e7 STA indexed, 1 byte offset -**- */
+INLINE void sta_ix1( void )
+{
+ CLR_NZ;
+ SET_NZ8(A);
+ INDEXED1;
+ WM(EAD,A);
+}
+
+/* $e8 EORA indexed, 1 byte offset -**- */
+INLINE void eora_ix1( void )
+{
+ UINT8 t;
+ IDX1BYTE(t);
+ A ^= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $e9 ADCA indexed, 1 byte offset **** */
+INLINE void adca_ix1( void )
+{
+ UINT16 t,r;
+ IDX1BYTE(t);
+ r = A + t + (CC & 0x01);
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $ea ORA indexed, 1 byte offset -**- */
+INLINE void ora_ix1( void )
+{
+ UINT8 t;
+ IDX1BYTE(t);
+ A |= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $eb ADDA indexed, 1 byte offset **** */
+INLINE void adda_ix1( void )
+{
+ UINT16 t,r;
+ IDX1BYTE(t);
+ r = A + t;
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $ec JMP indexed, 1 byte offset -*** */
+INLINE void jmp_ix1( void )
+{
+ INDEXED1;
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $ed JSR indexed, 1 byte offset ---- */
+INLINE void jsr_ix1( void )
+{
+ INDEXED1;
+ PUSHWORD(m6805.pc);
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $ee LDX indexed, 1 byte offset -**- */
+INLINE void ldx_ix1( void )
+{
+ IDX1BYTE(X);
+ CLR_NZ;
+ SET_NZ8(X);
+}
+
+/* $ef STX indexed, 1 byte offset -**- */
+INLINE void stx_ix1( void )
+{
+ CLR_NZ;
+ SET_NZ8(X);
+ INDEXED1;
+ WM(EAD,X);
+}
+
+/* $f0 SUBA indexed ?*** */
+INLINE void suba_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $f1 CMPA indexed ?*** */
+INLINE void cmpa_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t);
+ r = A - t;
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $f2 SBCA indexed ?*** */
+INLINE void sbca_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t);
+ r = A - t - (CC & 0x01);
+ CLR_NZC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $f3 CPX indexed -*** */
+INLINE void cpx_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t);
+ r = X - t;
+ CLR_NZC;
+ SET_FLAGS8(X,t,r);
+}
+
+/* $f4 ANDA indexed -**- */
+INLINE void anda_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t);
+ A &= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $f5 BITA indexed -**- */
+INLINE void bita_ix( void )
+{
+ UINT8 t,r;
+ IDXBYTE(t);
+ r = A & t;
+ CLR_NZ;
+ SET_NZ8(r);
+}
+
+/* $f6 LDA indexed -**- */
+INLINE void lda_ix( void )
+{
+ IDXBYTE(A);
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $f7 STA indexed -**- */
+INLINE void sta_ix( void )
+{
+ CLR_NZ;
+ SET_NZ8(A);
+ INDEXED;
+ WM(EAD,A);
+}
+
+/* $f8 EORA indexed -**- */
+INLINE void eora_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t);
+ A ^= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $f9 ADCA indexed **** */
+INLINE void adca_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t);
+ r = A + t + (CC & 0x01);
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $fa ORA indexed -**- */
+INLINE void ora_ix( void )
+{
+ UINT8 t;
+ IDXBYTE(t);
+ A |= t;
+ CLR_NZ;
+ SET_NZ8(A);
+}
+
+/* $fb ADDA indexed **** */
+INLINE void adda_ix( void )
+{
+ UINT16 t,r;
+ IDXBYTE(t);
+ r = A + t;
+ CLR_HNZC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $fc JMP indexed -*** */
+INLINE void jmp_ix( void )
+{
+ INDEXED;
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $fd JSR indexed ---- */
+INLINE void jsr_ix( void )
+{
+ INDEXED;
+ PUSHWORD(m6805.pc);
+ PC = EA;
+ change_pc(PC);
+}
+
+/* $fe LDX indexed -**- */
+INLINE void ldx_ix( void )
+{
+ IDXBYTE(X);
+ CLR_NZ;
+ SET_NZ8(X);
+}
+
+/* $ff STX indexed -**- */
+INLINE void stx_ix( void )
+{
+ CLR_NZ;
+ SET_NZ8(X);
+ INDEXED;
+ WM(EAD,X);
+}
diff --git a/src/emu/cpu/m6805/m6805.c b/src/emu/cpu/m6805/m6805.c
new file mode 100644
index 00000000000..eb56a4eecf5
--- /dev/null
+++ b/src/emu/cpu/m6805/m6805.c
@@ -0,0 +1,1062 @@
+/*** m6805: Portable 6805 emulator ******************************************
+
+ m6805.c (Also supports hd68705 and hd63705 variants)
+
+ References:
+
+ 6809 Simulator V09, By L.C. Benschop, Eidnhoven The Netherlands.
+
+ m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from
+ the 6809 Simulator V09)
+
+ 6809 Microcomputer Programming & Interfacing with Experiments"
+ by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc.
+
+ System dependencies: UINT16 must be 16 bit unsigned int
+ UINT8 must be 8 bit unsigned int
+ UINT32 must be more than 16 bits
+ arrays up to 65536 bytes must be supported
+ machine must be twos complement
+
+ Additional Notes:
+
+ K.Wilkins 18/03/99 - Added 63705 functonality and modified all CPU functions
+ necessary to support:
+ Variable width address bus
+ Different stack pointer
+ Alternate boot vectors
+ Alternate interrups vectors
+
+
+*****************************************************************************/
+
+
+#include "debugger.h"
+#include "m6805.h"
+
+#define IRQ_LEVEL_DETECT 0
+
+enum {
+ SUBTYPE_M6805,
+ SUBTYPE_M68705,
+ SUBTYPE_HD63705
+};
+
+/* 6805 Registers */
+typedef struct
+{
+ int subtype; /* Which sub-type is being emulated */
+ UINT32 sp_mask; /* Stack pointer address mask */
+ UINT32 sp_low; /* Stack pointer low water mark (or floor) */
+ PAIR pc; /* Program counter */
+ PAIR s; /* Stack pointer */
+ UINT8 a; /* Accumulator */
+ UINT8 x; /* Index register */
+ UINT8 cc; /* Condition codes */
+
+ UINT16 pending_interrupts; /* MB */
+ int (*irq_callback)(int irqline);
+ int irq_state[9]; /* KW Additional lines for HD63705 */
+ int nmi_state;
+} m6805_Regs;
+
+/* 6805 registers */
+static m6805_Regs m6805;
+
+#define SUBTYPE m6805.subtype /* CPU Type */
+#define SP_MASK m6805.sp_mask /* stack pointer mask */
+#define SP_LOW m6805.sp_low /* stack pointer low water mark */
+#define pPC m6805.pc /* program counter PAIR */
+#define PC m6805.pc.w.l /* program counter lower word */
+#define S m6805.s.w.l /* stack pointer lower word */
+#define A m6805.a /* accumulator */
+#define X m6805.x /* index register */
+#define CC m6805.cc /* condition codes */
+
+static PAIR ea; /* effective address */
+#define EAD ea.d
+#define EA ea.w.l
+
+/* public globals */
+int m6805_ICount=50000;
+
+/* DS -- THESE ARE RE-DEFINED IN m6805.h TO RAM, ROM or FUNCTIONS IN cpuintrf.c */
+#define RM(Addr) M6805_RDMEM(Addr)
+#define WM(Addr,Value) M6805_WRMEM(Addr,Value)
+#define M_RDOP(Addr) M6805_RDOP(Addr)
+#define M_RDOP_ARG(Addr) M6805_RDOP_ARG(Addr)
+
+/* macros to tweak the PC and SP */
+#define SP_INC if( ++S > SP_MASK) S = SP_LOW
+#define SP_DEC if( --S < SP_LOW) S = SP_MASK
+#define SP_ADJUST(s) ( ( (s) & SP_MASK ) | SP_LOW )
+
+/* macros to access memory */
+#define IMMBYTE(b) {b = M_RDOP_ARG(PC++);}
+#define IMMWORD(w) {w.d = 0; w.b.h = M_RDOP_ARG(PC); w.b.l = M_RDOP_ARG(PC+1); PC+=2;}
+
+#define PUSHBYTE(b) wr_s_handler_b(&b)
+#define PUSHWORD(w) wr_s_handler_w(&w)
+#define PULLBYTE(b) rd_s_handler_b(&b)
+#define PULLWORD(w) rd_s_handler_w(&w)
+
+/* CC masks H INZC
+ 7654 3210 */
+#define CFLAG 0x01
+#define ZFLAG 0x02
+#define NFLAG 0x04
+#define IFLAG 0x08
+#define HFLAG 0x10
+
+#define CLR_NZ CC&=~(NFLAG|ZFLAG)
+#define CLR_HNZC CC&=~(HFLAG|NFLAG|ZFLAG|CFLAG)
+#define CLR_Z CC&=~(ZFLAG)
+#define CLR_NZC CC&=~(NFLAG|ZFLAG|CFLAG)
+#define CLR_ZC CC&=~(ZFLAG|CFLAG)
+
+/* macros for CC -- CC bits affected should be reset before calling */
+#define SET_Z(a) if(!a)SEZ
+#define SET_Z8(a) SET_Z((UINT8)a)
+#define SET_N8(a) CC|=((a&0x80)>>5)
+#define SET_H(a,b,r) CC|=((a^b^r)&0x10)
+#define SET_C8(a) CC|=((a&0x100)>>8)
+
+static UINT8 flags8i[256]= /* increment */
+{
+0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04
+};
+static UINT8 flags8d[256]= /* decrement */
+{
+0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
+0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04
+};
+#define SET_FLAGS8I(a) {CC|=flags8i[(a)&0xff];}
+#define SET_FLAGS8D(a) {CC|=flags8d[(a)&0xff];}
+
+/* combos */
+#define SET_NZ8(a) {SET_N8(a);SET_Z(a);}
+#define SET_FLAGS8(a,b,r) {SET_N8(r);SET_Z8(r);SET_C8(r);}
+
+/* for treating an unsigned UINT8 as a signed INT16 */
+#define SIGNED(b) ((INT16)(b&0x80?b|0xff00:b))
+
+/* Macros for addressing modes */
+#define DIRECT EAD=0;IMMBYTE(ea.b.l)
+#define IMM8 EA=PC++
+#define EXTENDED IMMWORD(ea)
+#define INDEXED EA=X
+#define INDEXED1 {EAD=0; IMMBYTE(ea.b.l); EA+=X;}
+#define INDEXED2 {IMMWORD(ea); EA+=X;}
+
+/* macros to set status flags */
+#define SEC CC|=CFLAG
+#define CLC CC&=~CFLAG
+#define SEZ CC|=ZFLAG
+#define CLZ CC&=~ZFLAG
+#define SEN CC|=NFLAG
+#define CLN CC&=~NFLAG
+#define SEH CC|=HFLAG
+#define CLH CC&=~HFLAG
+#define SEI CC|=IFLAG
+#define CLI CC&=~IFLAG
+
+/* macros for convenience */
+#define DIRBYTE(b) {DIRECT;b=RM(EAD);}
+#define EXTBYTE(b) {EXTENDED;b=RM(EAD);}
+#define IDXBYTE(b) {INDEXED;b=RM(EAD);}
+#define IDX1BYTE(b) {INDEXED1;b=RM(EAD);}
+#define IDX2BYTE(b) {INDEXED2;b=RM(EAD);}
+/* Macros for branch instructions */
+#define BRANCH(f) { UINT8 t; IMMBYTE(t); if(f) { PC+=SIGNED(t); change_pc(PC); if (t==0xfe) { /* speed up busy loops */ if(m6805_ICount > 0) m6805_ICount = 0; } } }
+
+/* what they say it is ... */
+static unsigned char cycles1[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ /*1*/ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ /*2*/ 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ /*3*/ 6, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 0, 6, 6, 0,
+ /*4*/ 4, 0, 0, 4, 4, 0, 4, 4, 4, 4, 4, 0, 4, 4, 0, 4,
+ /*5*/ 4, 0, 0, 4, 4, 0, 4, 4, 4, 4, 4, 0, 4, 4, 0, 4,
+ /*6*/ 7, 0, 0, 7, 7, 0, 7, 7, 7, 7, 7, 0, 7, 7, 0, 7,
+ /*7*/ 6, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 0, 6, 6, 0, 6,
+ /*8*/ 9, 6, 0,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /*9*/ 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2,
+ /*A*/ 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 8, 2, 0,
+ /*B*/ 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 3, 7, 4, 5,
+ /*C*/ 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 4, 8, 5, 6,
+ /*D*/ 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 5, 9, 6, 7,
+ /*E*/ 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 4, 8, 5, 6,
+ /*F*/ 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 3, 7, 4, 5
+};
+
+
+/* pre-clear a PAIR union; clearing h2 and h3 only might be faster? */
+#define CLEAR_PAIR(p) p->d = 0
+
+INLINE void rd_s_handler_b( UINT8 *b )
+{
+ SP_INC;
+ *b = RM( S );
+}
+
+INLINE void rd_s_handler_w( PAIR *p )
+{
+ CLEAR_PAIR(p);
+ SP_INC;
+ p->b.h = RM( S );
+ SP_INC;
+ p->b.l = RM( S );
+}
+
+INLINE void wr_s_handler_b( UINT8 *b )
+{
+ WM( S, *b );
+ SP_DEC;
+}
+
+INLINE void wr_s_handler_w( PAIR *p )
+{
+ WM( S, p->b.l );
+ SP_DEC;
+ WM( S, p->b.h );
+ SP_DEC;
+}
+
+INLINE void RM16( UINT32 Addr, PAIR *p )
+{
+ CLEAR_PAIR(p);
+ p->b.h = RM(Addr);
+ ++Addr;
+// if( ++Addr > AMASK ) Addr = 0;
+ p->b.l = RM(Addr);
+}
+
+INLINE void WM16( UINT32 Addr, PAIR *p )
+{
+ WM( Addr, p->b.h );
+ ++Addr;
+// if( ++Addr > AMASK ) Addr = 0;
+ WM( Addr, p->b.l );
+}
+
+#if (HAS_M68705)
+
+/* Generate interrupt - m68705 version */
+static void m68705_Interrupt(void)
+{
+ if( (m6805.pending_interrupts & ((1<<M6805_IRQ_LINE)|M68705_INT_MASK)) != 0 )
+ {
+ if ( (CC & IFLAG) == 0 )
+ {
+ PUSHWORD(m6805.pc);
+ PUSHBYTE(m6805.x);
+ PUSHBYTE(m6805.a);
+ PUSHBYTE(m6805.cc);
+ SEI;
+ if (m6805.irq_callback)
+ (*m6805.irq_callback)(0);
+
+ if ((m6805.pending_interrupts & (1<<M68705_IRQ_LINE)) != 0 )
+ {
+ m6805.pending_interrupts &= ~(1<<M68705_IRQ_LINE);
+ RM16( 0xfffa, &pPC);
+ change_pc(PC);
+ }
+ else if((m6805.pending_interrupts&(1<<M68705_INT_TIMER))!=0)
+ {
+ m6805.pending_interrupts &= ~(1<<M68705_INT_TIMER);
+ RM16( 0xfff8, &pPC);
+ change_pc(PC);
+ }
+ }
+ m6805_ICount -= 11;
+ }
+}
+#endif
+
+/* Generate interrupts */
+static void Interrupt(void)
+{
+ /* the 6805 latches interrupt requests internally, so we don't clear */
+ /* pending_interrupts until the interrupt is taken, no matter what the */
+ /* external IRQ pin does. */
+
+#if (HAS_HD63705)
+ if( (m6805.pending_interrupts & (1<<HD63705_INT_NMI)) != 0)
+ {
+ PUSHWORD(m6805.pc);
+ PUSHBYTE(m6805.x);
+ PUSHBYTE(m6805.a);
+ PUSHBYTE(m6805.cc);
+ SEI;
+ /* no vectors supported, just do the callback to clear irq_state if needed */
+ if (m6805.irq_callback)
+ (*m6805.irq_callback)(0);
+
+ RM16( 0x1ffc, &pPC);
+ change_pc(PC);
+ m6805.pending_interrupts &= ~(1<<HD63705_INT_NMI);
+
+ m6805_ICount -= 11;
+
+ }
+ else if( (m6805.pending_interrupts & ((1<<M6805_IRQ_LINE)|HD63705_INT_MASK)) != 0 ) {
+ if ( (CC & IFLAG) == 0 ) {
+#else
+ if( (m6805.pending_interrupts & (1<<M6805_IRQ_LINE)) != 0 ) {
+ if ( (CC & IFLAG) == 0 ) {
+#endif
+ {
+ /* standard IRQ */
+//#if (HAS_HD63705)
+// if(SUBTYPE!=SUBTYPE_HD63705)
+//#endif
+// PC |= ~AMASK;
+ PUSHWORD(m6805.pc);
+ PUSHBYTE(m6805.x);
+ PUSHBYTE(m6805.a);
+ PUSHBYTE(m6805.cc);
+ SEI;
+ /* no vectors supported, just do the callback to clear irq_state if needed */
+ if (m6805.irq_callback)
+ (*m6805.irq_callback)(0);
+
+
+#if (HAS_HD63705)
+ if(SUBTYPE==SUBTYPE_HD63705)
+ {
+ /* Need to add emulation of other interrupt sources here KW-2/4/99 */
+ /* This is just a quick patch for Namco System 2 operation */
+
+ if((m6805.pending_interrupts&(1<<HD63705_INT_IRQ1))!=0)
+ {
+ m6805.pending_interrupts &= ~(1<<HD63705_INT_IRQ1);
+ RM16( 0x1ff8, &pPC);
+ change_pc(PC);
+ }
+ else if((m6805.pending_interrupts&(1<<HD63705_INT_IRQ2))!=0)
+ {
+ m6805.pending_interrupts &= ~(1<<HD63705_INT_IRQ2);
+ RM16( 0x1fec, &pPC);
+ change_pc(PC);
+ }
+ else if((m6805.pending_interrupts&(1<<HD63705_INT_ADCONV))!=0)
+ {
+ m6805.pending_interrupts &= ~(1<<HD63705_INT_ADCONV);
+ RM16( 0x1fea, &pPC);
+ change_pc(PC);
+ }
+ else if((m6805.pending_interrupts&(1<<HD63705_INT_TIMER1))!=0)
+ {
+ m6805.pending_interrupts &= ~(1<<HD63705_INT_TIMER1);
+ RM16( 0x1ff6, &pPC);
+ change_pc(PC);
+ }
+ else if((m6805.pending_interrupts&(1<<HD63705_INT_TIMER2))!=0)
+ {
+ m6805.pending_interrupts &= ~(1<<HD63705_INT_TIMER2);
+ RM16( 0x1ff4, &pPC);
+ change_pc(PC);
+ }
+ else if((m6805.pending_interrupts&(1<<HD63705_INT_TIMER3))!=0)
+ {
+ m6805.pending_interrupts &= ~(1<<HD63705_INT_TIMER3);
+ RM16( 0x1ff2, &pPC);
+ change_pc(PC);
+ }
+ else if((m6805.pending_interrupts&(1<<HD63705_INT_PCI))!=0)
+ {
+ m6805.pending_interrupts &= ~(1<<HD63705_INT_PCI);
+ RM16( 0x1ff0, &pPC);
+ change_pc(PC);
+ }
+ else if((m6805.pending_interrupts&(1<<HD63705_INT_SCI))!=0)
+ {
+ m6805.pending_interrupts &= ~(1<<HD63705_INT_SCI);
+ RM16( 0x1fee, &pPC);
+ change_pc(PC);
+ }
+ }
+ else
+#endif
+ {
+ RM16( 0xffff - 5, &pPC );
+ change_pc(PC);
+ }
+
+ } // CC & IFLAG
+ m6805.pending_interrupts &= ~(1<<M6805_IRQ_LINE);
+ }
+ m6805_ICount -= 11;
+ }
+}
+
+static void state_register(const char *type, int index)
+{
+ state_save_register_item(type, index, A);
+ state_save_register_item(type, index, PC);
+ state_save_register_item(type, index, S);
+ state_save_register_item(type, index, X);
+ state_save_register_item(type, index, CC);
+ state_save_register_item(type, index, m6805.pending_interrupts);
+ state_save_register_item_array(type, index, m6805.irq_state);
+}
+
+static void m6805_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ state_register("m6805", index);
+ m6805.irq_callback = irqcallback;
+}
+
+static void m6805_reset(void)
+{
+ int (*save_irqcallback)(int) = m6805.irq_callback;
+ memset(&m6805, 0, sizeof(m6805));
+ m6805.irq_callback = save_irqcallback;
+ /* Force CPU sub-type and relevant masks */
+ m6805.subtype = SUBTYPE_M6805;
+ SP_MASK = 0x07f;
+ SP_LOW = 0x060;
+ /* Initial stack pointer */
+ S = SP_MASK;
+ /* IRQ disabled */
+ SEI;
+ RM16( 0xfffe , &pPC );
+ change_pc(PC);
+}
+
+static void m6805_exit(void)
+{
+ /* nothing to do */
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void m6805_get_context(void *dst)
+{
+ if( dst )
+ *(m6805_Regs*)dst = m6805;
+}
+
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void m6805_set_context(void *src)
+{
+ if( src )
+ {
+ m6805 = *(m6805_Regs*)src;
+ S = SP_ADJUST( S );
+ }
+}
+
+
+static void set_irq_line(int irqline, int state)
+{
+ /* Basic 6805 only has one IRQ line */
+ /* See HD63705 specific version */
+ if (m6805.irq_state[0] == state) return;
+
+ m6805.irq_state[0] = state;
+ if (state != CLEAR_LINE)
+ m6805.pending_interrupts |= 1<<M6805_IRQ_LINE;
+}
+
+#include "6805ops.c"
+
+
+/* execute instructions on this CPU until icount expires */
+static int m6805_execute(int cycles)
+{
+ UINT8 ireg;
+ m6805_ICount = cycles;
+
+ do
+ {
+ if (m6805.pending_interrupts != 0)
+ {
+#if (HAS_M68705)
+ if (SUBTYPE==SUBTYPE_M68705)
+ {
+ m68705_Interrupt();
+ }
+ else
+#endif
+ {
+ Interrupt();
+ }
+ }
+
+ CALL_MAME_DEBUG;
+
+ ireg=M_RDOP(PC++);
+
+ switch( ireg )
+ {
+ case 0x00: brset(0x01); break;
+ case 0x01: brclr(0x01); break;
+ case 0x02: brset(0x02); break;
+ case 0x03: brclr(0x02); break;
+ case 0x04: brset(0x04); break;
+ case 0x05: brclr(0x04); break;
+ case 0x06: brset(0x08); break;
+ case 0x07: brclr(0x08); break;
+ case 0x08: brset(0x10); break;
+ case 0x09: brclr(0x10); break;
+ case 0x0A: brset(0x20); break;
+ case 0x0B: brclr(0x20); break;
+ case 0x0C: brset(0x40); break;
+ case 0x0D: brclr(0x40); break;
+ case 0x0E: brset(0x80); break;
+ case 0x0F: brclr(0x80); break;
+ case 0x10: bset(0x01); break;
+ case 0x11: bclr(0x01); break;
+ case 0x12: bset(0x02); break;
+ case 0x13: bclr(0x02); break;
+ case 0x14: bset(0x04); break;
+ case 0x15: bclr(0x04); break;
+ case 0x16: bset(0x08); break;
+ case 0x17: bclr(0x08); break;
+ case 0x18: bset(0x10); break;
+ case 0x19: bclr(0x10); break;
+ case 0x1a: bset(0x20); break;
+ case 0x1b: bclr(0x20); break;
+ case 0x1c: bset(0x40); break;
+ case 0x1d: bclr(0x40); break;
+ case 0x1e: bset(0x80); break;
+ case 0x1f: bclr(0x80); break;
+ case 0x20: bra(); break;
+ case 0x21: brn(); break;
+ case 0x22: bhi(); break;
+ case 0x23: bls(); break;
+ case 0x24: bcc(); break;
+ case 0x25: bcs(); break;
+ case 0x26: bne(); break;
+ case 0x27: beq(); break;
+ case 0x28: bhcc(); break;
+ case 0x29: bhcs(); break;
+ case 0x2a: bpl(); break;
+ case 0x2b: bmi(); break;
+ case 0x2c: bmc(); break;
+ case 0x2d: bms(); break;
+ case 0x2e: bil(); break;
+ case 0x2f: bih(); break;
+ case 0x30: neg_di(); break;
+ case 0x31: illegal(); break;
+ case 0x32: illegal(); break;
+ case 0x33: com_di(); break;
+ case 0x34: lsr_di(); break;
+ case 0x35: illegal(); break;
+ case 0x36: ror_di(); break;
+ case 0x37: asr_di(); break;
+ case 0x38: lsl_di(); break;
+ case 0x39: rol_di(); break;
+ case 0x3a: dec_di(); break;
+ case 0x3b: illegal(); break;
+ case 0x3c: inc_di(); break;
+ case 0x3d: tst_di(); break;
+ case 0x3e: illegal(); break;
+ case 0x3f: clr_di(); break;
+ case 0x40: nega(); break;
+ case 0x41: illegal(); break;
+ case 0x42: illegal(); break;
+ case 0x43: coma(); break;
+ case 0x44: lsra(); break;
+ case 0x45: illegal(); break;
+ case 0x46: rora(); break;
+ case 0x47: asra(); break;
+ case 0x48: lsla(); break;
+ case 0x49: rola(); break;
+ case 0x4a: deca(); break;
+ case 0x4b: illegal(); break;
+ case 0x4c: inca(); break;
+ case 0x4d: tsta(); break;
+ case 0x4e: illegal(); break;
+ case 0x4f: clra(); break;
+ case 0x50: negx(); break;
+ case 0x51: illegal(); break;
+ case 0x52: illegal(); break;
+ case 0x53: comx(); break;
+ case 0x54: lsrx(); break;
+ case 0x55: illegal(); break;
+ case 0x56: rorx(); break;
+ case 0x57: asrx(); break;
+ case 0x58: aslx(); break;
+ case 0x59: rolx(); break;
+ case 0x5a: decx(); break;
+ case 0x5b: illegal(); break;
+ case 0x5c: incx(); break;
+ case 0x5d: tstx(); break;
+ case 0x5e: illegal(); break;
+ case 0x5f: clrx(); break;
+ case 0x60: neg_ix1(); break;
+ case 0x61: illegal(); break;
+ case 0x62: illegal(); break;
+ case 0x63: com_ix1(); break;
+ case 0x64: lsr_ix1(); break;
+ case 0x65: illegal(); break;
+ case 0x66: ror_ix1(); break;
+ case 0x67: asr_ix1(); break;
+ case 0x68: lsl_ix1(); break;
+ case 0x69: rol_ix1(); break;
+ case 0x6a: dec_ix1(); break;
+ case 0x6b: illegal(); break;
+ case 0x6c: inc_ix1(); break;
+ case 0x6d: tst_ix1(); break;
+ case 0x6e: illegal(); break;
+ case 0x6f: clr_ix1(); break;
+ case 0x70: neg_ix(); break;
+ case 0x71: illegal(); break;
+ case 0x72: illegal(); break;
+ case 0x73: com_ix(); break;
+ case 0x74: lsr_ix(); break;
+ case 0x75: illegal(); break;
+ case 0x76: ror_ix(); break;
+ case 0x77: asr_ix(); break;
+ case 0x78: lsl_ix(); break;
+ case 0x79: rol_ix(); break;
+ case 0x7a: dec_ix(); break;
+ case 0x7b: illegal(); break;
+ case 0x7c: inc_ix(); break;
+ case 0x7d: tst_ix(); break;
+ case 0x7e: illegal(); break;
+ case 0x7f: clr_ix(); break;
+ case 0x80: rti(); break;
+ case 0x81: rts(); break;
+ case 0x82: illegal(); break;
+ case 0x83: swi(); break;
+ case 0x84: illegal(); break;
+ case 0x85: illegal(); break;
+ case 0x86: illegal(); break;
+ case 0x87: illegal(); break;
+ case 0x88: illegal(); break;
+ case 0x89: illegal(); break;
+ case 0x8a: illegal(); break;
+ case 0x8b: illegal(); break;
+ case 0x8c: illegal(); break;
+ case 0x8d: illegal(); break;
+ case 0x8e: illegal(); break;
+ case 0x8f: illegal(); break;
+ case 0x90: illegal(); break;
+ case 0x91: illegal(); break;
+ case 0x92: illegal(); break;
+ case 0x93: illegal(); break;
+ case 0x94: illegal(); break;
+ case 0x95: illegal(); break;
+ case 0x96: illegal(); break;
+ case 0x97: tax(); break;
+ case 0x98: CLC; break;
+ case 0x99: SEC; break;
+#if IRQ_LEVEL_DETECT
+ case 0x9a: CLI; if (m6805.irq_state != CLEAR_LINE) m6805.pending_interrupts |= 1<<M6805_IRQ_LINE; break;
+#else
+ case 0x9a: CLI; break;
+#endif
+ case 0x9b: SEI; break;
+ case 0x9c: rsp(); break;
+ case 0x9d: nop(); break;
+ case 0x9e: illegal(); break;
+ case 0x9f: txa(); break;
+ case 0xa0: suba_im(); break;
+ case 0xa1: cmpa_im(); break;
+ case 0xa2: sbca_im(); break;
+ case 0xa3: cpx_im(); break;
+ case 0xa4: anda_im(); break;
+ case 0xa5: bita_im(); break;
+ case 0xa6: lda_im(); break;
+ case 0xa7: illegal(); break;
+ case 0xa8: eora_im(); break;
+ case 0xa9: adca_im(); break;
+ case 0xaa: ora_im(); break;
+ case 0xab: adda_im(); break;
+ case 0xac: illegal(); break;
+ case 0xad: bsr(); break;
+ case 0xae: ldx_im(); break;
+ case 0xaf: illegal(); break;
+ case 0xb0: suba_di(); break;
+ case 0xb1: cmpa_di(); break;
+ case 0xb2: sbca_di(); break;
+ case 0xb3: cpx_di(); break;
+ case 0xb4: anda_di(); break;
+ case 0xb5: bita_di(); break;
+ case 0xb6: lda_di(); break;
+ case 0xb7: sta_di(); break;
+ case 0xb8: eora_di(); break;
+ case 0xb9: adca_di(); break;
+ case 0xba: ora_di(); break;
+ case 0xbb: adda_di(); break;
+ case 0xbc: jmp_di(); break;
+ case 0xbd: jsr_di(); break;
+ case 0xbe: ldx_di(); break;
+ case 0xbf: stx_di(); break;
+ case 0xc0: suba_ex(); break;
+ case 0xc1: cmpa_ex(); break;
+ case 0xc2: sbca_ex(); break;
+ case 0xc3: cpx_ex(); break;
+ case 0xc4: anda_ex(); break;
+ case 0xc5: bita_ex(); break;
+ case 0xc6: lda_ex(); break;
+ case 0xc7: sta_ex(); break;
+ case 0xc8: eora_ex(); break;
+ case 0xc9: adca_ex(); break;
+ case 0xca: ora_ex(); break;
+ case 0xcb: adda_ex(); break;
+ case 0xcc: jmp_ex(); break;
+ case 0xcd: jsr_ex(); break;
+ case 0xce: ldx_ex(); break;
+ case 0xcf: stx_ex(); break;
+ case 0xd0: suba_ix2(); break;
+ case 0xd1: cmpa_ix2(); break;
+ case 0xd2: sbca_ix2(); break;
+ case 0xd3: cpx_ix2(); break;
+ case 0xd4: anda_ix2(); break;
+ case 0xd5: bita_ix2(); break;
+ case 0xd6: lda_ix2(); break;
+ case 0xd7: sta_ix2(); break;
+ case 0xd8: eora_ix2(); break;
+ case 0xd9: adca_ix2(); break;
+ case 0xda: ora_ix2(); break;
+ case 0xdb: adda_ix2(); break;
+ case 0xdc: jmp_ix2(); break;
+ case 0xdd: jsr_ix2(); break;
+ case 0xde: ldx_ix2(); break;
+ case 0xdf: stx_ix2(); break;
+ case 0xe0: suba_ix1(); break;
+ case 0xe1: cmpa_ix1(); break;
+ case 0xe2: sbca_ix1(); break;
+ case 0xe3: cpx_ix1(); break;
+ case 0xe4: anda_ix1(); break;
+ case 0xe5: bita_ix1(); break;
+ case 0xe6: lda_ix1(); break;
+ case 0xe7: sta_ix1(); break;
+ case 0xe8: eora_ix1(); break;
+ case 0xe9: adca_ix1(); break;
+ case 0xea: ora_ix1(); break;
+ case 0xeb: adda_ix1(); break;
+ case 0xec: jmp_ix1(); break;
+ case 0xed: jsr_ix1(); break;
+ case 0xee: ldx_ix1(); break;
+ case 0xef: stx_ix1(); break;
+ case 0xf0: suba_ix(); break;
+ case 0xf1: cmpa_ix(); break;
+ case 0xf2: sbca_ix(); break;
+ case 0xf3: cpx_ix(); break;
+ case 0xf4: anda_ix(); break;
+ case 0xf5: bita_ix(); break;
+ case 0xf6: lda_ix(); break;
+ case 0xf7: sta_ix(); break;
+ case 0xf8: eora_ix(); break;
+ case 0xf9: adca_ix(); break;
+ case 0xfa: ora_ix(); break;
+ case 0xfb: adda_ix(); break;
+ case 0xfc: jmp_ix(); break;
+ case 0xfd: jsr_ix(); break;
+ case 0xfe: ldx_ix(); break;
+ case 0xff: stx_ix(); break;
+ }
+ m6805_ICount -= cycles1[ireg];
+ } while( m6805_ICount > 0 );
+
+ return cycles - m6805_ICount;
+}
+
+/****************************************************************************
+ * M68705 section
+ ****************************************************************************/
+#if (HAS_M68705)
+static void m68705_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ state_register("m68705", index);
+ m6805.irq_callback = irqcallback;
+}
+
+static void m68705_reset(void)
+{
+ m6805_reset();
+ /* Overide default 6805 type */
+ m6805.subtype = SUBTYPE_M68705;
+ RM16( 0xfffe, &m6805.pc );
+}
+
+static void m68705_set_irq_line(int irqline, int state)
+{
+ if (m6805.irq_state[irqline] == state ) return;
+ m6805.irq_state[irqline] = state;
+ if (state != CLEAR_LINE) m6805.pending_interrupts |= 1<<irqline;
+}
+
+#endif
+
+/****************************************************************************
+ * HD63705 section
+ ****************************************************************************/
+#if (HAS_HD63705)
+static void hd63705_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ state_register("hd63705", index);
+ m6805.irq_callback = irqcallback;
+}
+
+static void hd63705_reset(void)
+{
+ m6805_reset();
+
+ /* Overide default 6805 types */
+ m6805.subtype = SUBTYPE_HD63705;
+ SP_MASK = 0x17f;
+ SP_LOW = 0x100;
+ RM16( 0x1ffe, &m6805.pc );
+ S = 0x17f;
+}
+
+static void hd63705_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m6805.nmi_state == state) return;
+
+ m6805.nmi_state = state;
+ if (state != CLEAR_LINE)
+ m6805.pending_interrupts |= 1<<HD63705_INT_NMI;
+ }
+ else if (irqline <= HD63705_INT_ADCONV)
+ {
+ if (m6805.irq_state[irqline] == state) return;
+ m6805.irq_state[irqline] = state;
+ if (state != CLEAR_LINE) m6805.pending_interrupts |= 1<<irqline;
+ }
+}
+#endif
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void m6805_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M6805_IRQ_LINE: set_irq_line(M6805_IRQ_LINE, info->i); break;
+
+ case CPUINFO_INT_REGISTER + M6805_A: A = info->i; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + M6805_PC: PC = info->i; change_pc(PC); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M6805_S: S = SP_ADJUST(info->i); break;
+ case CPUINFO_INT_REGISTER + M6805_X: X = info->i; break;
+ case CPUINFO_INT_REGISTER + M6805_CC: CC = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void m6805_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(m6805); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = M6805_CLOCK_DIVIDER; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 10; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 12; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + M6805_IRQ_LINE: info->i = m6805.irq_state[M6805_IRQ_LINE]; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_REGISTER + M6805_A: info->i = A; break;
+ case CPUINFO_INT_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + M6805_PC: info->i = PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M6805_S: info->i = SP_ADJUST(S); break;
+ case CPUINFO_INT_REGISTER + M6805_X: info->i = X; break;
+ case CPUINFO_INT_REGISTER + M6805_CC: info->i = CC; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m6805_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m6805_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m6805_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m6805_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m6805_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m6805_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m6805_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6805_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m6805_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6805"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola 6805"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "The MAME team."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ m6805.cc & 0x80 ? '?':'.',
+ m6805.cc & 0x40 ? '?':'.',
+ m6805.cc & 0x20 ? '?':'.',
+ m6805.cc & 0x10 ? 'H':'.',
+ m6805.cc & 0x08 ? 'I':'.',
+ m6805.cc & 0x04 ? 'N':'.',
+ m6805.cc & 0x02 ? 'Z':'.',
+ m6805.cc & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M6805_A: sprintf(info->s, "A:%02X", m6805.a); break;
+ case CPUINFO_STR_REGISTER + M6805_PC: sprintf(info->s, "PC:%04X", m6805.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + M6805_S: sprintf(info->s, "S:%02X", m6805.s.w.l); break;
+ case CPUINFO_STR_REGISTER + M6805_X: sprintf(info->s, "X:%02X", m6805.x); break;
+ case CPUINFO_STR_REGISTER + M6805_CC: sprintf(info->s, "CC:%02X", m6805.cc); break;
+ }
+}
+
+
+#if (HAS_M68705)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+static void m68705_set_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M68705_INT_TIMER: m68705_set_irq_line(M68705_INT_TIMER, info->i); break;
+
+ default: m6805_set_info(state,info); break;
+ }
+}
+
+void m68705_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M68705_INT_TIMER: info->i = m6805.irq_state[M68705_INT_TIMER]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m68705_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = m68705_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m68705_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M68705"); break;
+
+ default: m6805_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_HD63705)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+static void hd63705_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_IRQ1: hd63705_set_irq_line(HD63705_INT_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_IRQ2: hd63705_set_irq_line(HD63705_INT_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_TIMER1: hd63705_set_irq_line(HD63705_INT_TIMER1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_TIMER2: hd63705_set_irq_line(HD63705_INT_TIMER2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_TIMER3: hd63705_set_irq_line(HD63705_INT_TIMER3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_PCI: hd63705_set_irq_line(HD63705_INT_PCI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_SCI: hd63705_set_irq_line(HD63705_INT_SCI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_ADCONV: hd63705_set_irq_line(HD63705_INT_ADCONV, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: hd63705_set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ default: m6805_set_info(state, info); break;
+ }
+}
+
+void hd63705_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_IRQ1: info->i = m6805.irq_state[HD63705_INT_IRQ1]; break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_IRQ2: info->i = m6805.irq_state[HD63705_INT_IRQ2]; break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_TIMER1: info->i = m6805.irq_state[HD63705_INT_TIMER1]; break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_TIMER2: info->i = m6805.irq_state[HD63705_INT_TIMER2]; break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_TIMER3: info->i = m6805.irq_state[HD63705_INT_TIMER3]; break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_PCI: info->i = m6805.irq_state[HD63705_INT_PCI]; break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_SCI: info->i = m6805.irq_state[HD63705_INT_SCI]; break;
+ case CPUINFO_INT_INPUT_STATE + HD63705_INT_ADCONV: info->i = m6805.irq_state[HD63705_INT_ADCONV]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = m6805.irq_state[HD63705_INT_NMI]; break;
+
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = hd63705_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = hd63705_init; break;
+ case CPUINFO_PTR_RESET: info->reset = hd63705_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "HD63705"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Keith Wilkins, Juergen Buchmueller"); break;
+
+ default: m6805_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/m6805/m6805.h b/src/emu/cpu/m6805/m6805.h
new file mode 100644
index 00000000000..a4d320de689
--- /dev/null
+++ b/src/emu/cpu/m6805/m6805.h
@@ -0,0 +1,95 @@
+/*** m6805: Portable 6805 emulator ******************************************/
+
+#ifndef _M6805_H
+#define _M6805_H
+
+#include "cpuintrf.h"
+
+enum { M6805_PC=1, M6805_S, M6805_CC, M6805_A, M6805_X, M6805_IRQ_STATE };
+
+#define M6805_IRQ_LINE 0
+
+#define M6805_CLOCK_DIVIDER 4
+
+extern void m6805_get_info(UINT32 state, cpuinfo *info);
+
+/****************************************************************************
+ * 68705 section
+ ****************************************************************************/
+#if (HAS_M68705)
+#define M68705_A M6805_A
+#define M68705_PC M6805_PC
+#define M68705_S M6805_S
+#define M68705_X M6805_X
+#define M68705_CC M6805_CC
+#define M68705_IRQ_STATE M6805_IRQ_STATE
+
+#define M68705_INT_MASK 0x03
+#define M68705_IRQ_LINE M6805_IRQ_LINE
+#define M68705_INT_TIMER 0x01
+
+#define M68705_CLOCK_DIVIDER M6805_CLOCK_DIVIDER
+
+extern void m68705_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************
+ * HD63705 section
+ ****************************************************************************/
+#if (HAS_HD63705)
+#define HD63705_A M6805_A
+#define HD63705_PC M6805_PC
+#define HD63705_S M6805_S
+#define HD63705_X M6805_X
+#define HD63705_CC M6805_CC
+#define HD63705_NMI_STATE M6805_IRQ_STATE
+#define HD63705_IRQ1_STATE M6805_IRQ_STATE+1
+#define HD63705_IRQ2_STATE M6805_IRQ_STATE+2
+#define HD63705_ADCONV_STATE M6805_IRQ_STATE+3
+
+#define HD63705_INT_MASK 0x1ff
+
+#define HD63705_INT_IRQ1 0x00
+#define HD63705_INT_IRQ2 0x01
+#define HD63705_INT_TIMER1 0x02
+#define HD63705_INT_TIMER2 0x03
+#define HD63705_INT_TIMER3 0x04
+#define HD63705_INT_PCI 0x05
+#define HD63705_INT_SCI 0x06
+#define HD63705_INT_ADCONV 0x07
+#define HD63705_INT_NMI 0x08
+
+#define HD3705_CLOCK_DIVIDER M6805_CLOCK_DIVIDER
+
+extern void hd63705_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+/****************************************************************************/
+/* Read a byte from given memory location */
+/****************************************************************************/
+#define M6805_RDMEM(Addr) ((unsigned)program_read_byte_8(Addr))
+
+/****************************************************************************/
+/* Write a byte to given memory location */
+/****************************************************************************/
+#define M6805_WRMEM(Addr,Value) (program_write_byte_8(Addr,Value))
+
+/****************************************************************************/
+/* M6805_RDOP() is identical to M6805_RDMEM() except it is used for reading */
+/* opcodes. In case of system with memory mapped I/O, this function can be */
+/* used to greatly speed up emulation */
+/****************************************************************************/
+#define M6805_RDOP(Addr) ((unsigned)cpu_readop(Addr))
+
+/****************************************************************************/
+/* M6805_RDOP_ARG() is identical to M6805_RDOP() but it's used for reading */
+/* opcode arguments. This difference can be used to support systems that */
+/* use different encoding mechanisms for opcodes and opcode arguments */
+/****************************************************************************/
+#define M6805_RDOP_ARG(Addr) ((unsigned)cpu_readop_arg(Addr))
+
+#ifdef MAME_DEBUG
+offs_t m6805_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _M6805_H */
diff --git a/src/emu/cpu/m6809/6809dasm.c b/src/emu/cpu/m6809/6809dasm.c
new file mode 100644
index 00000000000..e5f94619d34
--- /dev/null
+++ b/src/emu/cpu/m6809/6809dasm.c
@@ -0,0 +1,612 @@
+/*****************************************************************************
+
+ 6809dasm.c - a 6809 opcode disassembler
+ Version 1.4 1-MAR-95
+ Copyright 1995 Sean Riddle
+
+ Thanks to Franklin Bowen for bug fixes, ideas
+
+ Freely distributable on any medium given all copyrights are retained
+ by the author and no charge greater than $7.00 is made for obtaining
+ this software
+
+ Please send all bug reports, update ideas and data files to:
+ sriddle@ionet.net
+
+*****************************************************************************/
+
+#include "debugger.h"
+#include "m6809.h"
+
+// Opcode structure
+typedef struct
+{
+ UINT8 opcode; // 8-bit opcode value
+ UINT8 length; // Opcode length in bytes
+ char name[6]; // Opcode name
+ UINT8 mode; // Addressing mode
+ unsigned flags; // Disassembly flags
+} opcodeinfo;
+
+enum m6809_addressing_modes
+{
+ INH, // Inherent
+ DIR, // Direct
+ IND, // Indexed
+ REL, // Relative (8 bit)
+ LREL, // Long relative (16 bit)
+ EXT, // Extended
+ IMM, // Immediate
+ IMM_RR, // Register-to-register
+ PG1, // Switch to page 1 opcodes
+ PG2 // Switch to page 2 opcodes
+};
+
+// Page 0 opcodes (single byte)
+static const opcodeinfo m6809_pg0opcodes[] =
+{
+ { 0x00, 2, "NEG", DIR },
+ { 0x03, 2, "COM", DIR },
+ { 0x04, 2, "LSR", DIR },
+ { 0x06, 2, "ROR", DIR },
+ { 0x07, 2, "ASR", DIR },
+ { 0x08, 2, "ASL", DIR },
+ { 0x09, 2, "ROL", DIR },
+ { 0x0A, 2, "DEC", DIR },
+ { 0x0C, 2, "INC", DIR },
+ { 0x0D, 2, "TST", DIR },
+ { 0x0E, 2, "JMP", DIR },
+ { 0x0F, 2, "CLR", DIR },
+
+ { 0x10, 1, "page1", PG1 },
+ { 0x11, 1, "page2", PG2 },
+ { 0x12, 1, "NOP", INH },
+ { 0x13, 1, "SYNC", INH },
+ { 0x16, 3, "LBRA", LREL },
+ { 0x17, 3, "LBSR", LREL , DASMFLAG_STEP_OVER },
+ { 0x19, 1, "DAA", INH },
+ { 0x1A, 2, "ORCC", IMM },
+ { 0x1C, 2, "ANDCC", IMM },
+ { 0x1D, 1, "SEX", INH },
+ { 0x1E, 2, "EXG", IMM_RR },
+ { 0x1F, 2, "TFR", IMM_RR },
+
+ { 0x20, 2, "BRA", REL },
+ { 0x21, 2, "BRN", REL },
+ { 0x22, 2, "BHI", REL },
+ { 0x23, 2, "BLS", REL },
+ { 0x24, 2, "BCC", REL },
+ { 0x25, 2, "BCS", REL },
+ { 0x26, 2, "BNE", REL },
+ { 0x27, 2, "BEQ", REL },
+ { 0x28, 2, "BVC", REL },
+ { 0x29, 2, "BVS", REL },
+ { 0x2A, 2, "BPL", REL },
+ { 0x2B, 2, "BMI", REL },
+ { 0x2C, 2, "BGE", REL },
+ { 0x2D, 2, "BLT", REL },
+ { 0x2E, 2, "BGT", REL },
+ { 0x2F, 2, "BLE", REL },
+
+ { 0x30, 2, "LEAX", IND },
+ { 0x31, 2, "LEAY", IND },
+ { 0x32, 2, "LEAS", IND },
+ { 0x33, 2, "LEAU", IND },
+ { 0x34, 2, "PSHS", INH },
+ { 0x35, 2, "PULS", INH },
+ { 0x36, 2, "PSHU", INH },
+ { 0x37, 2, "PULU", INH },
+ { 0x39, 1, "RTS", INH },
+ { 0x3A, 1, "ABX", INH },
+ { 0x3B, 1, "RTI", INH },
+ { 0x3C, 2, "CWAI", IMM },
+ { 0x3D, 1, "MUL", INH },
+ { 0x3F, 1, "SWI", INH },
+
+ { 0x40, 1, "NEGA", INH },
+ { 0x43, 1, "COMA", INH },
+ { 0x44, 1, "LSRA", INH },
+ { 0x46, 1, "RORA", INH },
+ { 0x47, 1, "ASRA", INH },
+ { 0x48, 1, "ASLA", INH },
+ { 0x49, 1, "ROLA", INH },
+ { 0x4A, 1, "DECA", INH },
+ { 0x4C, 1, "INCA", INH },
+ { 0x4D, 1, "TSTA", INH },
+ { 0x4F, 1, "CLRA", INH },
+
+ { 0x50, 1, "NEGB", INH },
+ { 0x53, 1, "COMB", INH },
+ { 0x54, 1, "LSRB", INH },
+ { 0x56, 1, "RORB", INH },
+ { 0x57, 1, "ASRB", INH },
+ { 0x58, 1, "ASLB", INH },
+ { 0x59, 1, "ROLB", INH },
+ { 0x5A, 1, "DECB", INH },
+ { 0x5C, 1, "INCB", INH },
+ { 0x5D, 1, "TSTB", INH },
+ { 0x5F, 1, "CLRB", INH },
+
+ { 0x60, 2, "NEG", IND },
+ { 0x63, 2, "COM", IND },
+ { 0x64, 2, "LSR", IND },
+ { 0x66, 2, "ROR", IND },
+ { 0x67, 2, "ASR", IND },
+ { 0x68, 2, "ASL", IND },
+ { 0x69, 2, "ROL", IND },
+ { 0x6A, 2, "DEC", IND },
+ { 0x6C, 2, "INC", IND },
+ { 0x6D, 2, "TST", IND },
+ { 0x6E, 2, "JMP", IND },
+ { 0x6F, 2, "CLR", IND },
+
+ { 0x70, 3, "NEG", EXT },
+ { 0x73, 3, "COM", EXT },
+ { 0x74, 3, "LSR", EXT },
+ { 0x76, 3, "ROR", EXT },
+ { 0x77, 3, "ASR", EXT },
+ { 0x78, 3, "ASL", EXT },
+ { 0x79, 3, "ROL", EXT },
+ { 0x7A, 3, "DEC", EXT },
+ { 0x7C, 3, "INC", EXT },
+ { 0x7D, 3, "TST", EXT },
+ { 0x7E, 3, "JMP", EXT },
+ { 0x7F, 3, "CLR", EXT },
+
+ { 0x80, 2, "SUBA", IMM },
+ { 0x81, 2, "CMPA", IMM },
+ { 0x82, 2, "SBCA", IMM },
+ { 0x83, 3, "SUBD", IMM },
+ { 0x84, 2, "ANDA", IMM },
+ { 0x85, 2, "BITA", IMM },
+ { 0x86, 2, "LDA", IMM },
+ { 0x88, 2, "EORA", IMM },
+ { 0x89, 2, "ADCA", IMM },
+ { 0x8A, 2, "ORA", IMM },
+ { 0x8B, 2, "ADDA", IMM },
+ { 0x8C, 3, "CMPX", IMM },
+ { 0x8D, 2, "BSR", REL , DASMFLAG_STEP_OVER },
+ { 0x8E, 3, "LDX", IMM },
+
+ { 0x90, 2, "SUBA", DIR },
+ { 0x91, 2, "CMPA", DIR },
+ { 0x92, 2, "SBCA", DIR },
+ { 0x93, 2, "SUBD", DIR },
+ { 0x94, 2, "ANDA", DIR },
+ { 0x95, 2, "BITA", DIR },
+ { 0x96, 2, "LDA", DIR },
+ { 0x97, 2, "STA", DIR },
+ { 0x98, 2, "EORA", DIR },
+ { 0x99, 2, "ADCA", DIR },
+ { 0x9A, 2, "ORA", DIR },
+ { 0x9B, 2, "ADDA", DIR },
+ { 0x9C, 2, "CMPX", DIR },
+ { 0x9D, 2, "JSR", DIR , DASMFLAG_STEP_OVER },
+ { 0x9E, 2, "LDX", DIR },
+ { 0x9F, 2, "STX", DIR },
+
+ { 0xA0, 2, "SUBA", IND },
+ { 0xA1, 2, "CMPA", IND },
+ { 0xA2, 2, "SBCA", IND },
+ { 0xA3, 2, "SUBD", IND },
+ { 0xA4, 2, "ANDA", IND },
+ { 0xA5, 2, "BITA", IND },
+ { 0xA6, 2, "LDA", IND },
+ { 0xA7, 2, "STA", IND },
+ { 0xA8, 2, "EORA", IND },
+ { 0xA9, 2, "ADCA", IND },
+ { 0xAA, 2, "ORA", IND },
+ { 0xAB, 2, "ADDA", IND },
+ { 0xAC, 2, "CMPX", IND },
+ { 0xAD, 2, "JSR", IND , DASMFLAG_STEP_OVER },
+ { 0xAE, 2, "LDX", IND },
+ { 0xAF, 2, "STX", IND },
+
+ { 0xB0, 3, "SUBA", EXT },
+ { 0xB1, 3, "CMPA", EXT },
+ { 0xB2, 3, "SBCA", EXT },
+ { 0xB3, 3, "SUBD", EXT },
+ { 0xB4, 3, "ANDA", EXT },
+ { 0xB5, 3, "BITA", EXT },
+ { 0xB6, 3, "LDA", EXT },
+ { 0xB7, 3, "STA", EXT },
+ { 0xB8, 3, "EORA", EXT },
+ { 0xB9, 3, "ADCA", EXT },
+ { 0xBA, 3, "ORA", EXT },
+ { 0xBB, 3, "ADDA", EXT },
+ { 0xBC, 3, "CMPX", EXT },
+ { 0xBD, 3, "JSR", EXT , DASMFLAG_STEP_OVER },
+ { 0xBE, 3, "LDX", EXT },
+ { 0xBF, 3, "STX", EXT },
+
+ { 0xC0, 2, "SUBB", IMM },
+ { 0xC1, 2, "CMPB", IMM },
+ { 0xC2, 2, "SBCB", IMM },
+ { 0xC3, 3, "ADDD", IMM },
+ { 0xC4, 2, "ANDB", IMM },
+ { 0xC5, 2, "BITB", IMM },
+ { 0xC6, 2, "LDB", IMM },
+ { 0xC8, 2, "EORB", IMM },
+ { 0xC9, 2, "ADCB", IMM },
+ { 0xCA, 2, "ORB", IMM },
+ { 0xCB, 2, "ADDB", IMM },
+ { 0xCC, 3, "LDD", IMM },
+ { 0xCE, 3, "LDU", IMM },
+
+ { 0xD0, 2, "SUBB", DIR },
+ { 0xD1, 2, "CMPB", DIR },
+ { 0xD2, 2, "SBCB", DIR },
+ { 0xD3, 2, "ADDD", DIR },
+ { 0xD4, 2, "ANDB", DIR },
+ { 0xD5, 2, "BITB", DIR },
+ { 0xD6, 2, "LDB", DIR },
+ { 0xD7, 2, "STB", DIR },
+ { 0xD8, 2, "EORB", DIR },
+ { 0xD9, 2, "ADCB", DIR },
+ { 0xDA, 2, "ORB", DIR },
+ { 0xDB, 2, "ADDB", DIR },
+ { 0xDC, 2, "LDD", DIR },
+ { 0xDD, 2, "STD", DIR },
+ { 0xDE, 2, "LDU", DIR },
+ { 0xDF, 2, "STU", DIR },
+
+ { 0xE0, 2, "SUBB", IND },
+ { 0xE1, 2, "CMPB", IND },
+ { 0xE2, 2, "SBCB", IND },
+ { 0xE3, 2, "ADDD", IND },
+ { 0xE4, 2, "ANDB", IND },
+ { 0xE5, 2, "BITB", IND },
+ { 0xE6, 2, "LDB", IND },
+ { 0xE7, 2, "STB", IND },
+ { 0xE8, 2, "EORB", IND },
+ { 0xE9, 2, "ADCB", IND },
+ { 0xEA, 2, "ORB", IND },
+ { 0xEB, 2, "ADDB", IND },
+ { 0xEC, 2, "LDD", IND },
+ { 0xED, 2, "STD", IND },
+ { 0xEE, 2, "LDU", IND },
+ { 0xEF, 2, "STU", IND },
+
+ { 0xF0, 3, "SUBB", EXT },
+ { 0xF1, 3, "CMPB", EXT },
+ { 0xF2, 3, "SBCB", EXT },
+ { 0xF3, 3, "ADDD", EXT },
+ { 0xF4, 3, "ANDB", EXT },
+ { 0xF5, 3, "BITB", EXT },
+ { 0xF6, 3, "LDB", EXT },
+ { 0xF7, 3, "STB", EXT },
+ { 0xF8, 3, "EORB", EXT },
+ { 0xF9, 3, "ADCB", EXT },
+ { 0xFA, 3, "ORB", EXT },
+ { 0xFB, 3, "ADDB", EXT },
+ { 0xFC, 3, "LDD", EXT },
+ { 0xFD, 3, "STD", EXT },
+ { 0xFE, 3, "LDU", EXT },
+ { 0xFF, 3, "STU", EXT }
+};
+
+// Page 1 opcodes (0x10 0x..)
+static const opcodeinfo m6809_pg1opcodes[] =
+{
+ { 0x21, 4, "LBRN", LREL },
+ { 0x22, 4, "LBHI", LREL },
+ { 0x23, 4, "LBLS", LREL },
+ { 0x24, 4, "LBCC", LREL },
+ { 0x25, 4, "LBCS", LREL },
+ { 0x26, 4, "LBNE", LREL },
+ { 0x27, 4, "LBEQ", LREL },
+ { 0x28, 4, "LBVC", LREL },
+ { 0x29, 4, "LBVS", LREL },
+ { 0x2A, 4, "LBPL", LREL },
+ { 0x2B, 4, "LBMI", LREL },
+ { 0x2C, 4, "LBGE", LREL },
+ { 0x2D, 4, "LBLT", LREL },
+ { 0x2E, 4, "LBGT", LREL },
+ { 0x2F, 4, "LBLE", LREL },
+ { 0x3F, 2, "SWI2", INH },
+ { 0x83, 4, "CMPD", IMM },
+ { 0x8C, 4, "CMPY", IMM },
+ { 0x8E, 4, "LDY", IMM },
+ { 0x93, 3, "CMPD", DIR },
+ { 0x9C, 3, "CMPY", DIR },
+ { 0x9E, 3, "LDY", DIR },
+ { 0x9F, 3, "STY", DIR },
+ { 0xA3, 3, "CMPD", IND },
+ { 0xAC, 3, "CMPY", IND },
+ { 0xAE, 3, "LDY", IND },
+ { 0xAF, 3, "STY", IND },
+ { 0xB3, 4, "CMPD", EXT },
+ { 0xBC, 4, "CMPY", EXT },
+ { 0xBE, 4, "LDY", EXT },
+ { 0xBF, 4, "STY", EXT },
+ { 0xCE, 4, "LDS", IMM },
+ { 0xDE, 3, "LDS", DIR },
+ { 0xDF, 3, "STS", DIR },
+ { 0xEE, 3, "LDS", IND },
+ { 0xEF, 3, "STS", IND },
+ { 0xFE, 4, "LDS", EXT },
+ { 0xFF, 4, "STS", EXT }
+};
+
+// Page 2 opcodes (0x11 0x..)
+static const opcodeinfo m6809_pg2opcodes[] =
+{
+ { 0x3F, 2, "SWI3", INH },
+ { 0x83, 4, "CMPU", IMM },
+ { 0x8C, 4, "CMPS", IMM },
+ { 0x93, 3, "CMPU", DIR },
+ { 0x9C, 3, "CMPS", DIR },
+ { 0xA3, 3, "CMPU", IND },
+ { 0xAC, 3, "CMPS", IND },
+ { 0xB3, 4, "CMPU", EXT },
+ { 0xBC, 4, "CMPS", EXT }
+};
+
+static const opcodeinfo *m6809_pgpointers[3] =
+{
+ m6809_pg0opcodes, m6809_pg1opcodes, m6809_pg2opcodes
+};
+
+static const int m6809_numops[3] =
+{
+ sizeof(m6809_pg0opcodes) / sizeof(m6809_pg0opcodes[0]),
+ sizeof(m6809_pg1opcodes) / sizeof(m6809_pg1opcodes[0]),
+ sizeof(m6809_pg2opcodes) / sizeof(m6809_pg2opcodes[0])
+};
+
+static const char *m6809_regs[5] = { "X", "Y", "U", "S", "PC" };
+
+static const char *m6809_regs_te[16] =
+{
+ "D", "X", "Y", "U", "S", "PC", "inv", "inv",
+ "A", "B", "CC", "DP", "inv", "inv", "inv", "inv"
+};
+
+offs_t m6809_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT8 opcode, mode, pb, pbm, reg;
+ const UINT8 *operandarray;
+ unsigned int ea, flags;
+ int numoperands, offset, indirect;
+
+ int i, p = 0, page = 0, opcode_found = FALSE;
+
+ do
+ {
+ opcode = oprom[p++];
+ for (i = 0; i < m6809_numops[page]; i++)
+ if (m6809_pgpointers[page][i].opcode == opcode)
+ break;
+
+ if (i < m6809_numops[page])
+ opcode_found = TRUE;
+ else
+ {
+ strcpy(buffer, "Illegal Opcode");
+ return p | DASMFLAG_SUPPORTED;
+ }
+
+ if (m6809_pgpointers[page][i].mode >= PG1)
+ {
+ page = m6809_pgpointers[page][i].mode - PG1 + 1;
+ opcode_found = FALSE;
+ }
+ } while (!opcode_found);
+
+ if (page == 0)
+ numoperands = m6809_pgpointers[page][i].length - 1;
+ else
+ numoperands = m6809_pgpointers[page][i].length - 2;
+
+ operandarray = &opram[p];
+ p += numoperands;
+ pc += p;
+ mode = m6809_pgpointers[page][i].mode;
+ flags = m6809_pgpointers[page][i].flags;
+
+ buffer += sprintf(buffer, "%-6s", m6809_pgpointers[page][i].name);
+
+ switch (mode)
+ {
+ case INH:
+ switch (opcode)
+ {
+ case 0x34: // PSHS
+ case 0x36: // PSHU
+ pb = operandarray[0];
+ if (pb & 0x80)
+ buffer += sprintf(buffer, "PC");
+ if (pb & 0x40)
+ buffer += sprintf(buffer, "%s%s", (pb&0x80)?",":"", (opcode==0x34)?"U":"S");
+ if (pb & 0x20)
+ buffer += sprintf(buffer, "%sY", (pb&0xc0)?",":"");
+ if (pb & 0x10)
+ buffer += sprintf(buffer, "%sX", (pb&0xe0)?",":"");
+ if (pb & 0x08)
+ buffer += sprintf(buffer, "%sDP", (pb&0xf0)?",":"");
+ if (pb & 0x04)
+ buffer += sprintf(buffer, "%sB", (pb&0xf8)?",":"");
+ if (pb & 0x02)
+ buffer += sprintf(buffer, "%sA", (pb&0xfc)?",":"");
+ if (pb & 0x01)
+ buffer += sprintf(buffer, "%sCC", (pb&0xfe)?",":"");
+ break;
+ case 0x35: // PULS
+ case 0x37: // PULU
+ pb = operandarray[0];
+ if (pb & 0x01)
+ buffer += sprintf(buffer, "CC");
+ if (pb & 0x02)
+ buffer += sprintf(buffer, "%sA", (pb&0x01)?",":"");
+ if (pb & 0x04)
+ buffer += sprintf(buffer, "%sB", (pb&0x03)?",":"");
+ if (pb & 0x08)
+ buffer += sprintf(buffer, "%sDP", (pb&0x07)?",":"");
+ if (pb & 0x10)
+ buffer += sprintf(buffer, "%sX", (pb&0x0f)?",":"");
+ if (pb & 0x20)
+ buffer += sprintf(buffer, "%sY", (pb&0x1f)?",":"");
+ if (pb & 0x40)
+ buffer += sprintf(buffer, "%s%s", (pb&0x3f)?",":"", (opcode==0x35)?"U":"S");
+ if (pb & 0x80)
+ buffer += sprintf(buffer, "%sPC ; (PUL? PC=RTS)", (pb&0x7f)?",":"");
+ break;
+ default:
+ // No operands
+ break;
+ }
+ break;
+
+ case DIR:
+ ea = operandarray[0];
+ buffer += sprintf(buffer, "$%02X", ea);
+ break;
+
+ case REL:
+ offset = (INT8)operandarray[0];
+ buffer += sprintf(buffer, "$%04X", (pc + offset) & 0xffff);
+ break;
+
+ case LREL:
+ offset = (INT16)((operandarray[0] << 8) + operandarray[1]);
+ buffer += sprintf(buffer, "$%04X", (pc + offset) & 0xffff);
+ break;
+
+ case EXT:
+ ea = (operandarray[0] << 8) + operandarray[1];
+ buffer += sprintf(buffer, "$%04X", ea);
+ break;
+
+ case IND:
+ pb = operandarray[0];
+ reg = (pb >> 5) & 3;
+ pbm = pb & 0x8f;
+ indirect = ((pb & 0x90) == 0x90 )? TRUE : FALSE;
+
+ // open brackets if indirect
+ if (indirect && pbm != 0x80 && pbm != 0x82)
+ buffer += sprintf(buffer, "[");
+
+ switch (pbm)
+ {
+ case 0x80: // ,R+
+ if (indirect)
+ strcpy(buffer, "Illegal Postbyte");
+ else
+ buffer += sprintf(buffer, ",%s+", m6809_regs[reg]);
+ break;
+
+ case 0x81: // ,R++
+ buffer += sprintf(buffer, ",%s++", m6809_regs[reg]);
+ break;
+
+ case 0x82: // ,-R
+ if (indirect)
+ strcpy(buffer, "Illegal Postbyte");
+ else
+ buffer += sprintf(buffer, ",-%s", m6809_regs[reg]);
+ break;
+
+ case 0x83: // ,--R
+ buffer += sprintf(buffer, ",--%s", m6809_regs[reg]);
+ break;
+
+ case 0x84: // ,R
+ buffer += sprintf(buffer, ",%s", m6809_regs[reg]);
+ break;
+
+ case 0x85: // (+/- B),R
+ buffer += sprintf(buffer, "B,%s", m6809_regs[reg]);
+ break;
+
+ case 0x86: // (+/- A),R
+ buffer += sprintf(buffer, "A,%s", m6809_regs[reg]);
+ break;
+
+ case 0x87:
+ strcpy(buffer, "Illegal Postbyte");
+ break;
+
+ case 0x88: // (+/- 7 bit offset),R
+ offset = (INT8)opram[p++];
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%02X,", (offset < 0) ? -offset : offset);
+ buffer += sprintf(buffer, "%s", m6809_regs[reg]);
+ break;
+
+ case 0x89: // (+/- 15 bit offset),R
+ offset = (INT16)((opram[p+0] << 8) + opram[p+1]);
+ p += 2;
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%04X,", (offset < 0) ? -offset : offset);
+ buffer += sprintf(buffer, "%s", m6809_regs[reg]);
+ break;
+
+ case 0x8a:
+ strcpy(buffer, "Illegal Postbyte");
+ break;
+
+ case 0x8b: // (+/- D),R
+ buffer += sprintf(buffer, "D,%s", m6809_regs[reg]);
+ break;
+
+ case 0x8c: // (+/- 7 bit offset),PC
+ offset = (INT8)opram[p++];
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%02X,PC", (offset < 0) ? -offset : offset);
+ break;
+
+ case 0x8d: // (+/- 15 bit offset),PC
+ offset = (INT16)((opram[p+0] << 8) + opram[p+1]);
+ p += 2;
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%04X,PC", (offset < 0) ? -offset : offset);
+ break;
+
+ case 0x8e:
+ strcpy(buffer, "Illegal Postbyte");
+ break;
+
+ case 0x8f: // address
+ ea = (UINT16)((opram[p+0] << 8) + opram[p+1]);
+ p += 2;
+ buffer += sprintf(buffer, "$%04X", ea);
+ break;
+
+ default: // (+/- 4 bit offset),R
+ offset = pb & 0x1f;
+ if (offset > 15)
+ offset = offset - 32;
+ buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : "");
+ buffer += sprintf(buffer, "$%X,", (offset < 0) ? -offset : offset);
+ buffer += sprintf(buffer, "%s", m6809_regs[reg]);
+ break;
+ }
+
+ // close brackets if indirect
+ if (indirect && pbm != 0x80 && pbm != 0x82)
+ buffer += sprintf(buffer, "]");
+ break;
+
+ case IMM:
+ if (numoperands == 2)
+ {
+ ea = (operandarray[0] << 8) + operandarray[1];
+ buffer += sprintf(buffer, "#$%04X", ea);
+ }
+ else
+ if (numoperands == 1)
+ {
+ ea = operandarray[0];
+ buffer += sprintf(buffer, "#$%02X", ea);
+ }
+ break;
+
+ case IMM_RR:
+ pb = operandarray[0];
+ buffer += sprintf(buffer, "%s,%s", m6809_regs_te[(pb >> 4) & 0xf], m6809_regs_te[pb & 0xf]);
+ break;
+ }
+
+ return p | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/m6809/6809ops.c b/src/emu/cpu/m6809/6809ops.c
new file mode 100644
index 00000000000..7b9acc8da8e
--- /dev/null
+++ b/src/emu/cpu/m6809/6809ops.c
@@ -0,0 +1,2997 @@
+/*
+
+HNZVC
+
+? = undefined
+* = affected
+- = unaffected
+0 = cleared
+1 = set
+# = CCr directly affected by instruction
+@ = special - carry set if bit 7 is set
+
+*/
+
+#ifdef NEW
+static void illegal( void )
+#else
+INLINE void illegal( void )
+#endif
+{
+ logerror("M6809: illegal opcode at %04x\n",PC);
+}
+
+/* $00 NEG direct ?**** */
+INLINE void neg_di( void )
+{
+ UINT16 r,t;
+ DIRBYTE(t);
+ r = -t;
+ CLR_NZVC;
+ SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $01 ILLEGAL */
+
+/* $02 ILLEGAL */
+
+/* $03 COM direct -**01 */
+INLINE void com_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ t = ~t;
+ CLR_NZV;
+ SET_NZ8(t);
+ SEC;
+ WM(EAD,t);
+}
+
+/* $04 LSR direct -0*-* */
+INLINE void lsr_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t >>= 1;
+ SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $05 ILLEGAL */
+
+/* $06 ROR direct -**-* */
+INLINE void ror_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r= (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (t & CC_C);
+ r |= t>>1;
+ SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $07 ASR direct ?**-* */
+INLINE void asr_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t = (t & 0x80) | (t >> 1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $08 ASL direct ?**** */
+INLINE void asl_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $09 ROL direct -**** */
+INLINE void rol_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = (CC & CC_C) | (t << 1);
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $0A DEC direct -***- */
+INLINE void dec_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ --t;
+ CLR_NZV;
+ SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $0B ILLEGAL */
+
+/* $OC INC direct -***- */
+INLINE void inc_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ ++t;
+ CLR_NZV;
+ SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $OD TST direct -**0- */
+INLINE void tst_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ CLR_NZV;
+ SET_NZ8(t);
+}
+
+/* $0E JMP direct ----- */
+INLINE void jmp_di( void )
+{
+ DIRECT;
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $0F CLR direct -0100 */
+INLINE void clr_di( void )
+{
+ DIRECT;
+ (void)RM(EAD);
+ WM(EAD,0);
+ CLR_NZVC;
+ SEZ;
+}
+
+/* $10 FLAG */
+
+/* $11 FLAG */
+
+/* $12 NOP inherent ----- */
+INLINE void nop( void )
+{
+ ;
+}
+
+/* $13 SYNC inherent ----- */
+INLINE void sync( void )
+{
+ /* SYNC stops processing instructions until an interrupt request happens. */
+ /* This doesn't require the corresponding interrupt to be enabled: if it */
+ /* is disabled, execution continues with the next instruction. */
+ m6809.int_state |= M6809_SYNC; /* HJB 990227 */
+ CHECK_IRQ_LINES;
+ /* if M6809_SYNC has not been cleared by CHECK_IRQ_LINES,
+ * stop execution until the interrupt lines change. */
+ if( m6809.int_state & M6809_SYNC )
+ if (m6809_ICount > 0) m6809_ICount = 0;
+}
+
+/* $14 ILLEGAL */
+
+/* $15 ILLEGAL */
+
+/* $16 LBRA relative ----- */
+INLINE void lbra( void )
+{
+ IMMWORD(ea);
+ PC += EA;
+ CHANGE_PC;
+
+ if ( EA == 0xfffd ) /* EHC 980508 speed up busy loop */
+ if ( m6809_ICount > 0)
+ m6809_ICount = 0;
+}
+
+/* $17 LBSR relative ----- */
+INLINE void lbsr( void )
+{
+ IMMWORD(ea);
+ PUSHWORD(pPC);
+ PC += EA;
+ CHANGE_PC;
+}
+
+/* $18 ILLEGAL */
+
+/* $19 DAA inherent (A) -**0* */
+INLINE void daa( void )
+{
+ UINT8 msn, lsn;
+ UINT16 t, cf = 0;
+ msn = A & 0xf0; lsn = A & 0x0f;
+ if( lsn>0x09 || CC & CC_H) cf |= 0x06;
+ if( msn>0x80 && lsn>0x09 ) cf |= 0x60;
+ if( msn>0x90 || CC & CC_C) cf |= 0x60;
+ t = cf + A;
+ CLR_NZV; /* keep carry from previous operation */
+ SET_NZ8((UINT8)t); SET_C8(t);
+ A = t;
+}
+
+/* $1A ORCC immediate ##### */
+INLINE void orcc( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ CC |= t;
+ CHECK_IRQ_LINES; /* HJB 990116 */
+}
+
+/* $1B ILLEGAL */
+
+/* $1C ANDCC immediate ##### */
+INLINE void andcc( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ CC &= t;
+ CHECK_IRQ_LINES; /* HJB 990116 */
+}
+
+/* $1D SEX inherent -**-- */
+INLINE void sex( void )
+{
+ UINT16 t;
+ t = SIGNED(B);
+ D = t;
+// CLR_NZV; Tim Lindner 20020905: verified that V flag is not affected
+ CLR_NZ;
+ SET_NZ16(t);
+}
+
+/* $1E EXG inherent ----- */
+INLINE void exg( void )
+{
+ UINT16 t1,t2;
+ UINT8 tb;
+
+ IMMBYTE(tb);
+ if( (tb^(tb>>4)) & 0x08 ) /* HJB 990225: mixed 8/16 bit case? */
+ {
+ /* transfer $ff to both registers */
+ t1 = t2 = 0xff;
+ }
+ else
+ {
+ switch(tb>>4) {
+ case 0: t1 = D; break;
+ case 1: t1 = X; break;
+ case 2: t1 = Y; break;
+ case 3: t1 = U; break;
+ case 4: t1 = S; break;
+ case 5: t1 = PC; break;
+ case 8: t1 = A; break;
+ case 9: t1 = B; break;
+ case 10: t1 = CC; break;
+ case 11: t1 = DP; break;
+ default: t1 = 0xff;
+ }
+ switch(tb&15) {
+ case 0: t2 = D; break;
+ case 1: t2 = X; break;
+ case 2: t2 = Y; break;
+ case 3: t2 = U; break;
+ case 4: t2 = S; break;
+ case 5: t2 = PC; break;
+ case 8: t2 = A; break;
+ case 9: t2 = B; break;
+ case 10: t2 = CC; break;
+ case 11: t2 = DP; break;
+ default: t2 = 0xff;
+ }
+ }
+ switch(tb>>4) {
+ case 0: D = t2; break;
+ case 1: X = t2; break;
+ case 2: Y = t2; break;
+ case 3: U = t2; break;
+ case 4: S = t2; break;
+ case 5: PC = t2; CHANGE_PC; break;
+ case 8: A = t2; break;
+ case 9: B = t2; break;
+ case 10: CC = t2; break;
+ case 11: DP = t2; break;
+ }
+ switch(tb&15) {
+ case 0: D = t1; break;
+ case 1: X = t1; break;
+ case 2: Y = t1; break;
+ case 3: U = t1; break;
+ case 4: S = t1; break;
+ case 5: PC = t1; CHANGE_PC; break;
+ case 8: A = t1; break;
+ case 9: B = t1; break;
+ case 10: CC = t1; break;
+ case 11: DP = t1; break;
+ }
+}
+
+/* $1F TFR inherent ----- */
+INLINE void tfr( void )
+{
+ UINT8 tb;
+ UINT16 t;
+
+ IMMBYTE(tb);
+ if( (tb^(tb>>4)) & 0x08 ) /* HJB 990225: mixed 8/16 bit case? */
+ {
+ /* transfer $ff to register */
+ t = 0xff;
+ }
+ else
+ {
+ switch(tb>>4) {
+ case 0: t = D; break;
+ case 1: t = X; break;
+ case 2: t = Y; break;
+ case 3: t = U; break;
+ case 4: t = S; break;
+ case 5: t = PC; break;
+ case 8: t = A; break;
+ case 9: t = B; break;
+ case 10: t = CC; break;
+ case 11: t = DP; break;
+ default: t = 0xff;
+ }
+ }
+ switch(tb&15) {
+ case 0: D = t; break;
+ case 1: X = t; break;
+ case 2: Y = t; break;
+ case 3: U = t; break;
+ case 4: S = t; break;
+ case 5: PC = t; CHANGE_PC; break;
+ case 8: A = t; break;
+ case 9: B = t; break;
+ case 10: CC = t; break;
+ case 11: DP = t; break;
+ }
+}
+
+/* $20 BRA relative ----- */
+INLINE void bra( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ PC += SIGNED(t);
+ CHANGE_PC;
+ /* JB 970823 - speed up busy loops */
+ if( t == 0xfe )
+ if( m6809_ICount > 0 ) m6809_ICount = 0;
+}
+
+/* $21 BRN relative ----- */
+INLINE void brn( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+}
+
+/* $1021 LBRN relative ----- */
+INLINE void lbrn( void )
+{
+ IMMWORD(ea);
+}
+
+/* $22 BHI relative ----- */
+INLINE void bhi( void )
+{
+ BRANCH( !(CC & (CC_Z|CC_C)) );
+}
+
+/* $1022 LBHI relative ----- */
+INLINE void lbhi( void )
+{
+ LBRANCH( !(CC & (CC_Z|CC_C)) );
+}
+
+/* $23 BLS relative ----- */
+INLINE void bls( void )
+{
+ BRANCH( (CC & (CC_Z|CC_C)) );
+}
+
+/* $1023 LBLS relative ----- */
+INLINE void lbls( void )
+{
+ LBRANCH( (CC&(CC_Z|CC_C)) );
+}
+
+/* $24 BCC relative ----- */
+INLINE void bcc( void )
+{
+ BRANCH( !(CC&CC_C) );
+}
+
+/* $1024 LBCC relative ----- */
+INLINE void lbcc( void )
+{
+ LBRANCH( !(CC&CC_C) );
+}
+
+/* $25 BCS relative ----- */
+INLINE void bcs( void )
+{
+ BRANCH( (CC&CC_C) );
+}
+
+/* $1025 LBCS relative ----- */
+INLINE void lbcs( void )
+{
+ LBRANCH( (CC&CC_C) );
+}
+
+/* $26 BNE relative ----- */
+INLINE void bne( void )
+{
+ BRANCH( !(CC&CC_Z) );
+}
+
+/* $1026 LBNE relative ----- */
+INLINE void lbne( void )
+{
+ LBRANCH( !(CC&CC_Z) );
+}
+
+/* $27 BEQ relative ----- */
+INLINE void beq( void )
+{
+ BRANCH( (CC&CC_Z) );
+}
+
+/* $1027 LBEQ relative ----- */
+INLINE void lbeq( void )
+{
+ LBRANCH( (CC&CC_Z) );
+}
+
+/* $28 BVC relative ----- */
+INLINE void bvc( void )
+{
+ BRANCH( !(CC&CC_V) );
+}
+
+/* $1028 LBVC relative ----- */
+INLINE void lbvc( void )
+{
+ LBRANCH( !(CC&CC_V) );
+}
+
+/* $29 BVS relative ----- */
+INLINE void bvs( void )
+{
+ BRANCH( (CC&CC_V) );
+}
+
+/* $1029 LBVS relative ----- */
+INLINE void lbvs( void )
+{
+ LBRANCH( (CC&CC_V) );
+}
+
+/* $2A BPL relative ----- */
+INLINE void bpl( void )
+{
+ BRANCH( !(CC&CC_N) );
+}
+
+/* $102A LBPL relative ----- */
+INLINE void lbpl( void )
+{
+ LBRANCH( !(CC&CC_N) );
+}
+
+/* $2B BMI relative ----- */
+INLINE void bmi( void )
+{
+ BRANCH( (CC&CC_N) );
+}
+
+/* $102B LBMI relative ----- */
+INLINE void lbmi( void )
+{
+ LBRANCH( (CC&CC_N) );
+}
+
+/* $2C BGE relative ----- */
+INLINE void bge( void )
+{
+ BRANCH( !NXORV );
+}
+
+/* $102C LBGE relative ----- */
+INLINE void lbge( void )
+{
+ LBRANCH( !NXORV );
+}
+
+/* $2D BLT relative ----- */
+INLINE void blt( void )
+{
+ BRANCH( NXORV );
+}
+
+/* $102D LBLT relative ----- */
+INLINE void lblt( void )
+{
+ LBRANCH( NXORV );
+}
+
+/* $2E BGT relative ----- */
+INLINE void bgt( void )
+{
+ BRANCH( !(NXORV || (CC&CC_Z)) );
+}
+
+/* $102E LBGT relative ----- */
+INLINE void lbgt( void )
+{
+ LBRANCH( !(NXORV || (CC&CC_Z)) );
+}
+
+/* $2F BLE relative ----- */
+INLINE void ble( void )
+{
+ BRANCH( (NXORV || (CC&CC_Z)) );
+}
+
+/* $102F LBLE relative ----- */
+INLINE void lble( void )
+{
+ LBRANCH( (NXORV || (CC&CC_Z)) );
+}
+
+/* $30 LEAX indexed --*-- */
+INLINE void leax( void )
+{
+ fetch_effective_address();
+ X = EA;
+ CLR_Z;
+ SET_Z(X);
+}
+
+/* $31 LEAY indexed --*-- */
+INLINE void leay( void )
+{
+ fetch_effective_address();
+ Y = EA;
+ CLR_Z;
+ SET_Z(Y);
+}
+
+/* $32 LEAS indexed ----- */
+INLINE void leas( void )
+{
+ fetch_effective_address();
+ S = EA;
+ m6809.int_state |= M6809_LDS;
+}
+
+/* $33 LEAU indexed ----- */
+INLINE void leau( void )
+{
+ fetch_effective_address();
+ U = EA;
+}
+
+/* $34 PSHS inherent ----- */
+INLINE void pshs( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x80 ) { PUSHWORD(pPC); m6809_ICount -= 2; }
+ if( t&0x40 ) { PUSHWORD(pU); m6809_ICount -= 2; }
+ if( t&0x20 ) { PUSHWORD(pY); m6809_ICount -= 2; }
+ if( t&0x10 ) { PUSHWORD(pX); m6809_ICount -= 2; }
+ if( t&0x08 ) { PUSHBYTE(DP); m6809_ICount -= 1; }
+ if( t&0x04 ) { PUSHBYTE(B); m6809_ICount -= 1; }
+ if( t&0x02 ) { PUSHBYTE(A); m6809_ICount -= 1; }
+ if( t&0x01 ) { PUSHBYTE(CC); m6809_ICount -= 1; }
+}
+
+/* 35 PULS inherent ----- */
+INLINE void puls( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x01 ) { PULLBYTE(CC); m6809_ICount -= 1; }
+ if( t&0x02 ) { PULLBYTE(A); m6809_ICount -= 1; }
+ if( t&0x04 ) { PULLBYTE(B); m6809_ICount -= 1; }
+ if( t&0x08 ) { PULLBYTE(DP); m6809_ICount -= 1; }
+ if( t&0x10 ) { PULLWORD(XD); m6809_ICount -= 2; }
+ if( t&0x20 ) { PULLWORD(YD); m6809_ICount -= 2; }
+ if( t&0x40 ) { PULLWORD(UD); m6809_ICount -= 2; }
+ if( t&0x80 ) { PULLWORD(PCD); CHANGE_PC; m6809_ICount -= 2; }
+
+ /* HJB 990225: moved check after all PULLs */
+ if( t&0x01 ) { CHECK_IRQ_LINES; }
+}
+
+/* $36 PSHU inherent ----- */
+INLINE void pshu( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x80 ) { PSHUWORD(pPC); m6809_ICount -= 2; }
+ if( t&0x40 ) { PSHUWORD(pS); m6809_ICount -= 2; }
+ if( t&0x20 ) { PSHUWORD(pY); m6809_ICount -= 2; }
+ if( t&0x10 ) { PSHUWORD(pX); m6809_ICount -= 2; }
+ if( t&0x08 ) { PSHUBYTE(DP); m6809_ICount -= 1; }
+ if( t&0x04 ) { PSHUBYTE(B); m6809_ICount -= 1; }
+ if( t&0x02 ) { PSHUBYTE(A); m6809_ICount -= 1; }
+ if( t&0x01 ) { PSHUBYTE(CC); m6809_ICount -= 1; }
+}
+
+/* 37 PULU inherent ----- */
+INLINE void pulu( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ if( t&0x01 ) { PULUBYTE(CC); m6809_ICount -= 1; }
+ if( t&0x02 ) { PULUBYTE(A); m6809_ICount -= 1; }
+ if( t&0x04 ) { PULUBYTE(B); m6809_ICount -= 1; }
+ if( t&0x08 ) { PULUBYTE(DP); m6809_ICount -= 1; }
+ if( t&0x10 ) { PULUWORD(XD); m6809_ICount -= 2; }
+ if( t&0x20 ) { PULUWORD(YD); m6809_ICount -= 2; }
+ if( t&0x40 ) { PULUWORD(SD); m6809_ICount -= 2; }
+ if( t&0x80 ) { PULUWORD(PCD); CHANGE_PC; m6809_ICount -= 2; }
+
+ /* HJB 990225: moved check after all PULLs */
+ if( t&0x01 ) { CHECK_IRQ_LINES; }
+}
+
+/* $38 ILLEGAL */
+
+/* $39 RTS inherent ----- */
+INLINE void rts( void )
+{
+ PULLWORD(PCD);
+ CHANGE_PC;
+}
+
+/* $3A ABX inherent ----- */
+INLINE void abx( void )
+{
+ X += B;
+}
+
+/* $3B RTI inherent ##### */
+INLINE void rti( void )
+{
+ UINT8 t;
+ PULLBYTE(CC);
+ t = CC & CC_E; /* HJB 990225: entire state saved? */
+ if(t)
+ {
+ m6809_ICount -= 9;
+ PULLBYTE(A);
+ PULLBYTE(B);
+ PULLBYTE(DP);
+ PULLWORD(XD);
+ PULLWORD(YD);
+ PULLWORD(UD);
+ }
+ PULLWORD(PCD);
+ CHANGE_PC;
+ CHECK_IRQ_LINES; /* HJB 990116 */
+}
+
+/* $3C CWAI inherent ----1 */
+INLINE void cwai( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ CC &= t;
+ /*
+ * CWAI stacks the entire machine state on the hardware stack,
+ * then waits for an interrupt; when the interrupt is taken
+ * later, the state is *not* saved again after CWAI.
+ */
+ CC |= CC_E; /* HJB 990225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ m6809.int_state |= M6809_CWAI; /* HJB 990228 */
+ CHECK_IRQ_LINES; /* HJB 990116 */
+ if( m6809.int_state & M6809_CWAI )
+ if( m6809_ICount > 0 )
+ m6809_ICount = 0;
+}
+
+/* $3D MUL inherent --*-@ */
+INLINE void mul( void )
+{
+ UINT16 t;
+ t = A * B;
+ CLR_ZC; SET_Z16(t); if(t&0x80) SEC;
+ D = t;
+}
+
+/* $3E ILLEGAL */
+
+/* $3F SWI (SWI2 SWI3) absolute indirect ----- */
+INLINE void swi( void )
+{
+ CC |= CC_E; /* HJB 980225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */
+ PCD=RM16(0xfffa);
+ CHANGE_PC;
+}
+
+/* $103F SWI2 absolute indirect ----- */
+INLINE void swi2( void )
+{
+ CC |= CC_E; /* HJB 980225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ PCD = RM16(0xfff4);
+ CHANGE_PC;
+}
+
+/* $113F SWI3 absolute indirect ----- */
+INLINE void swi3( void )
+{
+ CC |= CC_E; /* HJB 980225: save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ PCD = RM16(0xfff2);
+ CHANGE_PC;
+}
+
+/* $40 NEGA inherent ?**** */
+INLINE void nega( void )
+{
+ UINT16 r;
+ r = -A;
+ CLR_NZVC;
+ SET_FLAGS8(0,A,r);
+ A = r;
+}
+
+/* $41 ILLEGAL */
+
+/* $42 ILLEGAL */
+
+/* $43 COMA inherent -**01 */
+INLINE void coma( void )
+{
+ A = ~A;
+ CLR_NZV;
+ SET_NZ8(A);
+ SEC;
+}
+
+/* $44 LSRA inherent -0*-* */
+INLINE void lsra( void )
+{
+ CLR_NZC;
+ CC |= (A & CC_C);
+ A >>= 1;
+ SET_Z8(A);
+}
+
+/* $45 ILLEGAL */
+
+/* $46 RORA inherent -**-* */
+INLINE void rora( void )
+{
+ UINT8 r;
+ r = (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (A & CC_C);
+ r |= A >> 1;
+ SET_NZ8(r);
+ A = r;
+}
+
+/* $47 ASRA inherent ?**-* */
+INLINE void asra( void )
+{
+ CLR_NZC;
+ CC |= (A & CC_C);
+ A = (A & 0x80) | (A >> 1);
+ SET_NZ8(A);
+}
+
+/* $48 ASLA inherent ?**** */
+INLINE void asla( void )
+{
+ UINT16 r;
+ r = A << 1;
+ CLR_NZVC;
+ SET_FLAGS8(A,A,r);
+ A = r;
+}
+
+/* $49 ROLA inherent -**** */
+INLINE void rola( void )
+{
+ UINT16 t,r;
+ t = A;
+ r = (CC & CC_C) | (t<<1);
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ A = r;
+}
+
+/* $4A DECA inherent -***- */
+INLINE void deca( void )
+{
+ --A;
+ CLR_NZV;
+ SET_FLAGS8D(A);
+}
+
+/* $4B ILLEGAL */
+
+/* $4C INCA inherent -***- */
+INLINE void inca( void )
+{
+ ++A;
+ CLR_NZV;
+ SET_FLAGS8I(A);
+}
+
+/* $4D TSTA inherent -**0- */
+INLINE void tsta( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $4E ILLEGAL */
+
+/* $4F CLRA inherent -0100 */
+INLINE void clra( void )
+{
+ A = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $50 NEGB inherent ?**** */
+INLINE void negb( void )
+{
+ UINT16 r;
+ r = -B;
+ CLR_NZVC;
+ SET_FLAGS8(0,B,r);
+ B = r;
+}
+
+/* $51 ILLEGAL */
+
+/* $52 ILLEGAL */
+
+/* $53 COMB inherent -**01 */
+INLINE void comb( void )
+{
+ B = ~B;
+ CLR_NZV;
+ SET_NZ8(B);
+ SEC;
+}
+
+/* $54 LSRB inherent -0*-* */
+INLINE void lsrb( void )
+{
+ CLR_NZC;
+ CC |= (B & CC_C);
+ B >>= 1;
+ SET_Z8(B);
+}
+
+/* $55 ILLEGAL */
+
+/* $56 RORB inherent -**-* */
+INLINE void rorb( void )
+{
+ UINT8 r;
+ r = (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (B & CC_C);
+ r |= B >> 1;
+ SET_NZ8(r);
+ B = r;
+}
+
+/* $57 ASRB inherent ?**-* */
+INLINE void asrb( void )
+{
+ CLR_NZC;
+ CC |= (B & CC_C);
+ B= (B & 0x80) | (B >> 1);
+ SET_NZ8(B);
+}
+
+/* $58 ASLB inherent ?**** */
+INLINE void aslb( void )
+{
+ UINT16 r;
+ r = B << 1;
+ CLR_NZVC;
+ SET_FLAGS8(B,B,r);
+ B = r;
+}
+
+/* $59 ROLB inherent -**** */
+INLINE void rolb( void )
+{
+ UINT16 t,r;
+ t = B;
+ r = CC & CC_C;
+ r |= t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ B = r;
+}
+
+/* $5A DECB inherent -***- */
+INLINE void decb( void )
+{
+ --B;
+ CLR_NZV;
+ SET_FLAGS8D(B);
+}
+
+/* $5B ILLEGAL */
+
+/* $5C INCB inherent -***- */
+INLINE void incb( void )
+{
+ ++B;
+ CLR_NZV;
+ SET_FLAGS8I(B);
+}
+
+/* $5D TSTB inherent -**0- */
+INLINE void tstb( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $5E ILLEGAL */
+
+/* $5F CLRB inherent -0100 */
+INLINE void clrb( void )
+{
+ B = 0;
+ CLR_NZVC; SEZ;
+}
+
+/* $60 NEG indexed ?**** */
+INLINE void neg_ix( void )
+{
+ UINT16 r,t;
+ fetch_effective_address();
+ t = RM(EAD);
+ r=-t;
+ CLR_NZVC;
+ SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $61 ILLEGAL */
+
+/* $62 ILLEGAL */
+
+/* $63 COM indexed -**01 */
+INLINE void com_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t = ~RM(EAD);
+ CLR_NZV;
+ SET_NZ8(t);
+ SEC;
+ WM(EAD,t);
+}
+
+/* $64 LSR indexed -0*-* */
+INLINE void lsr_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t=RM(EAD);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t>>=1; SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $65 ILLEGAL */
+
+/* $66 ROR indexed -**-* */
+INLINE void ror_ix( void )
+{
+ UINT8 t,r;
+ fetch_effective_address();
+ t=RM(EAD);
+ r = (CC & CC_C) << 7;
+ CLR_NZC;
+ CC |= (t & CC_C);
+ r |= t>>1; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $67 ASR indexed ?**-* */
+INLINE void asr_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t=RM(EAD);
+ CLR_NZC;
+ CC |= (t & CC_C);
+ t=(t&0x80)|(t>>1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $68 ASL indexed ?**** */
+INLINE void asl_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t=RM(EAD);
+ r = t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $69 ROL indexed -**** */
+INLINE void rol_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t=RM(EAD);
+ r = CC & CC_C;
+ r |= t << 1;
+ CLR_NZVC;
+ SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $6A DEC indexed -***- */
+INLINE void dec_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t = RM(EAD) - 1;
+ CLR_NZV; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $6B ILLEGAL */
+
+/* $6C INC indexed -***- */
+INLINE void inc_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t = RM(EAD) + 1;
+ CLR_NZV; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $6D TST indexed -**0- */
+INLINE void tst_ix( void )
+{
+ UINT8 t;
+ fetch_effective_address();
+ t = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(t);
+}
+
+/* $6E JMP indexed ----- */
+INLINE void jmp_ix( void )
+{
+ fetch_effective_address();
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $6F CLR indexed -0100 */
+INLINE void clr_ix( void )
+{
+ fetch_effective_address();
+ (void)RM(EAD);
+ WM(EAD,0);
+ CLR_NZVC; SEZ;
+}
+
+/* $70 NEG extended ?**** */
+INLINE void neg_ex( void )
+{
+ UINT16 r,t;
+ EXTBYTE(t); r=-t;
+ CLR_NZVC; SET_FLAGS8(0,t,r);
+ WM(EAD,r);
+}
+
+/* $71 ILLEGAL */
+
+/* $72 ILLEGAL */
+
+/* $73 COM extended -**01 */
+INLINE void com_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); t = ~t;
+ CLR_NZV; SET_NZ8(t); SEC;
+ WM(EAD,t);
+}
+
+/* $74 LSR extended -0*-* */
+INLINE void lsr_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZC; CC |= (t & CC_C);
+ t>>=1; SET_Z8(t);
+ WM(EAD,t);
+}
+
+/* $75 ILLEGAL */
+
+/* $76 ROR extended -**-* */
+INLINE void ror_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t); r=(CC & CC_C) << 7;
+ CLR_NZC; CC |= (t & CC_C);
+ r |= t>>1; SET_NZ8(r);
+ WM(EAD,r);
+}
+
+/* $77 ASR extended ?**-* */
+INLINE void asr_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZC; CC |= (t & CC_C);
+ t=(t&0x80)|(t>>1);
+ SET_NZ8(t);
+ WM(EAD,t);
+}
+
+/* $78 ASL extended ?**** */
+INLINE void asl_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r=t<<1;
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $79 ROL extended -**** */
+INLINE void rol_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t); r = (CC & CC_C) | (t << 1);
+ CLR_NZVC; SET_FLAGS8(t,t,r);
+ WM(EAD,r);
+}
+
+/* $7A DEC extended -***- */
+INLINE void dec_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); --t;
+ CLR_NZV; SET_FLAGS8D(t);
+ WM(EAD,t);
+}
+
+/* $7B ILLEGAL */
+
+/* $7C INC extended -***- */
+INLINE void inc_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); ++t;
+ CLR_NZV; SET_FLAGS8I(t);
+ WM(EAD,t);
+}
+
+/* $7D TST extended -**0- */
+INLINE void tst_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t); CLR_NZV; SET_NZ8(t);
+}
+
+/* $7E JMP extended ----- */
+INLINE void jmp_ex( void )
+{
+ EXTENDED;
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $7F CLR extended -0100 */
+INLINE void clr_ex( void )
+{
+ EXTENDED;
+ (void)RM(EAD);
+ WM(EAD,0);
+ CLR_NZVC; SEZ;
+}
+
+/* $80 SUBA immediate ?**** */
+INLINE void suba_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $81 CMPA immediate ?**** */
+INLINE void cmpa_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $82 SBCA immediate ?**** */
+INLINE void sbca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $83 SUBD (CMPD CMPU) immediate -**** */
+INLINE void subd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $1083 CMPD immediate -**** */
+INLINE void cmpd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $1183 CMPU immediate -**** */
+INLINE void cmpu_im( void )
+{
+ UINT32 r, d;
+ PAIR b;
+ IMMWORD(b);
+ d = U;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $84 ANDA immediate -**0- */
+INLINE void anda_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A &= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $85 BITA immediate -**0- */
+INLINE void bita_im( void )
+{
+ UINT8 t,r;
+ IMMBYTE(t);
+ r = A & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $86 LDA immediate -**0- */
+INLINE void lda_im( void )
+{
+ IMMBYTE(A);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* is this a legal instruction? */
+/* $87 STA immediate -**0- */
+INLINE void sta_im( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+ IMM8;
+ WM(EAD,A);
+}
+
+/* $88 EORA immediate -**0- */
+INLINE void eora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A ^= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $89 ADCA immediate ***** */
+INLINE void adca_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $8A ORA immediate -**0- */
+INLINE void ora_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ A |= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $8B ADDA immediate ***** */
+INLINE void adda_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $8C CMPX (CMPY CMPS) immediate -**** */
+INLINE void cmpx_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $108C CMPY immediate -**** */
+INLINE void cmpy_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $118C CMPS immediate -**** */
+INLINE void cmps_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $8D BSR ----- */
+INLINE void bsr( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ PUSHWORD(pPC);
+ PC += SIGNED(t);
+ CHANGE_PC;
+}
+
+/* $8E LDX (LDY) immediate -**0- */
+INLINE void ldx_im( void )
+{
+ IMMWORD(pX);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $108E LDY immediate -**0- */
+INLINE void ldy_im( void )
+{
+ IMMWORD(pY);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* is this a legal instruction? */
+/* $8F STX (STY) immediate -**0- */
+INLINE void stx_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ IMM16;
+ WM16(EAD,&pX);
+}
+
+/* is this a legal instruction? */
+/* $108F STY immediate -**0- */
+INLINE void sty_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(Y);
+ IMM16;
+ WM16(EAD,&pY);
+}
+
+/* $90 SUBA direct ?**** */
+INLINE void suba_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $91 CMPA direct ?**** */
+INLINE void cmpa_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $92 SBCA direct ?**** */
+INLINE void sbca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $93 SUBD (CMPD CMPU) direct -**** */
+INLINE void subd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $1093 CMPD direct -**** */
+INLINE void cmpd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $1193 CMPU direct -**** */
+INLINE void cmpu_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = U;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(U,b.d,r);
+}
+
+/* $94 ANDA direct -**0- */
+INLINE void anda_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A &= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $95 BITA direct -**0- */
+INLINE void bita_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r = A & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $96 LDA direct -**0- */
+INLINE void lda_di( void )
+{
+ DIRBYTE(A);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $97 STA direct -**0- */
+INLINE void sta_di( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+ DIRECT;
+ WM(EAD,A);
+}
+
+/* $98 EORA direct -**0- */
+INLINE void eora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A ^= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $99 ADCA direct ***** */
+INLINE void adca_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $9A ORA direct -**0- */
+INLINE void ora_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ A |= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $9B ADDA direct ***** */
+INLINE void adda_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $9C CMPX (CMPY CMPS) direct -**** */
+INLINE void cmpx_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $109C CMPY direct -**** */
+INLINE void cmpy_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $119C CMPS direct -**** */
+INLINE void cmps_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $9D JSR direct ----- */
+INLINE void jsr_di( void )
+{
+ DIRECT;
+ PUSHWORD(pPC);
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $9E LDX (LDY) direct -**0- */
+INLINE void ldx_di( void )
+{
+ DIRWORD(pX);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $109E LDY direct -**0- */
+INLINE void ldy_di( void )
+{
+ DIRWORD(pY);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $9F STX (STY) direct -**0- */
+INLINE void stx_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ DIRECT;
+ WM16(EAD,&pX);
+}
+
+/* $109F STY direct -**0- */
+INLINE void sty_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(Y);
+ DIRECT;
+ WM16(EAD,&pY);
+}
+
+/* $a0 SUBA indexed ?**** */
+INLINE void suba_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a1 CMPA indexed ?**** */
+INLINE void cmpa_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $a2 SBCA indexed ?**** */
+INLINE void sbca_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $a3 SUBD (CMPD CMPU) indexed -**** */
+INLINE void subd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $10a3 CMPD indexed -**** */
+INLINE void cmpd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11a3 CMPU indexed -**** */
+INLINE void cmpu_ix( void )
+{
+ UINT32 r;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ r = U - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(U,b.d,r);
+}
+
+/* $a4 ANDA indexed -**0- */
+INLINE void anda_ix( void )
+{
+ fetch_effective_address();
+ A &= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $a5 BITA indexed -**0- */
+INLINE void bita_ix( void )
+{
+ UINT8 r;
+ fetch_effective_address();
+ r = A & RM(EAD);
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $a6 LDA indexed -**0- */
+INLINE void lda_ix( void )
+{
+ fetch_effective_address();
+ A = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $a7 STA indexed -**0- */
+INLINE void sta_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ8(A);
+ WM(EAD,A);
+}
+
+/* $a8 EORA indexed -**0- */
+INLINE void eora_ix( void )
+{
+ fetch_effective_address();
+ A ^= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $a9 ADCA indexed ***** */
+INLINE void adca_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $aA ORA indexed -**0- */
+INLINE void ora_ix( void )
+{
+ fetch_effective_address();
+ A |= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $aB ADDA indexed ***** */
+INLINE void adda_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $aC CMPX (CMPY CMPS) indexed -**** */
+INLINE void cmpx_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $10aC CMPY indexed -**** */
+INLINE void cmpy_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11aC CMPS indexed -**** */
+INLINE void cmps_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $aD JSR indexed ----- */
+INLINE void jsr_ix( void )
+{
+ fetch_effective_address();
+ PUSHWORD(pPC);
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $aE LDX (LDY) indexed -**0- */
+INLINE void ldx_ix( void )
+{
+ fetch_effective_address();
+ X=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $10aE LDY indexed -**0- */
+INLINE void ldy_ix( void )
+{
+ fetch_effective_address();
+ Y=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $aF STX (STY) indexed -**0- */
+INLINE void stx_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(X);
+ WM16(EAD,&pX);
+}
+
+/* $10aF STY indexed -**0- */
+INLINE void sty_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(Y);
+ WM16(EAD,&pY);
+}
+
+/* $b0 SUBA extended ?**** */
+INLINE void suba_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b1 CMPA extended ?**** */
+INLINE void cmpa_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t;
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+}
+
+/* $b2 SBCA extended ?**** */
+INLINE void sbca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(A,t,r);
+ A = r;
+}
+
+/* $b3 SUBD (CMPD CMPU) extended -**** */
+INLINE void subd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $10b3 CMPD extended -**** */
+INLINE void cmpd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = D;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11b3 CMPU extended -**** */
+INLINE void cmpu_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = U;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $b4 ANDA extended -**0- */
+INLINE void anda_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A &= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $b5 BITA extended -**0- */
+INLINE void bita_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t);
+ r = A & t;
+ CLR_NZV; SET_NZ8(r);
+}
+
+/* $b6 LDA extended -**0- */
+INLINE void lda_ex( void )
+{
+ EXTBYTE(A);
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $b7 STA extended -**0- */
+INLINE void sta_ex( void )
+{
+ CLR_NZV;
+ SET_NZ8(A);
+ EXTENDED;
+ WM(EAD,A);
+}
+
+/* $b8 EORA extended -**0- */
+INLINE void eora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A ^= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $b9 ADCA extended ***** */
+INLINE void adca_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $bA ORA extended -**0- */
+INLINE void ora_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ A |= t;
+ CLR_NZV;
+ SET_NZ8(A);
+}
+
+/* $bB ADDA extended ***** */
+INLINE void adda_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = A + t;
+ CLR_HNZVC;
+ SET_FLAGS8(A,t,r);
+ SET_H(A,t,r);
+ A = r;
+}
+
+/* $bC CMPX (CMPY CMPS) extended -**** */
+INLINE void cmpx_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = X;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $10bC CMPY extended -**** */
+INLINE void cmpy_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = Y;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $11bC CMPS extended -**** */
+INLINE void cmps_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = S;
+ r = d - b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+}
+
+/* $bD JSR extended ----- */
+INLINE void jsr_ex( void )
+{
+ EXTENDED;
+ PUSHWORD(pPC);
+ PCD = EAD;
+ CHANGE_PC;
+}
+
+/* $bE LDX (LDY) extended -**0- */
+INLINE void ldx_ex( void )
+{
+ EXTWORD(pX);
+ CLR_NZV;
+ SET_NZ16(X);
+}
+
+/* $10bE LDY extended -**0- */
+INLINE void ldy_ex( void )
+{
+ EXTWORD(pY);
+ CLR_NZV;
+ SET_NZ16(Y);
+}
+
+/* $bF STX (STY) extended -**0- */
+INLINE void stx_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(X);
+ EXTENDED;
+ WM16(EAD,&pX);
+}
+
+/* $10bF STY extended -**0- */
+INLINE void sty_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(Y);
+ EXTENDED;
+ WM16(EAD,&pY);
+}
+
+/* $c0 SUBB immediate ?**** */
+INLINE void subb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $c1 CMPB immediate ?**** */
+INLINE void cmpb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B - t;
+ CLR_NZVC; SET_FLAGS8(B,t,r);
+}
+
+/* $c2 SBCB immediate ?**** */
+INLINE void sbcb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $c3 ADDD immediate -**** */
+INLINE void addd_im( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ IMMWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $c4 ANDB immediate -**0- */
+INLINE void andb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $c5 BITB immediate -**0- */
+INLINE void bitb_im( void )
+{
+ UINT8 t,r;
+ IMMBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $c6 LDB immediate -**0- */
+INLINE void ldb_im( void )
+{
+ IMMBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* is this a legal instruction? */
+/* $c7 STB immediate -**0- */
+INLINE void stb_im( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+ IMM8;
+ WM(EAD,B);
+}
+
+/* $c8 EORB immediate -**0- */
+INLINE void eorb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ B ^= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $c9 ADCB immediate ***** */
+INLINE void adcb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $cA ORB immediate -**0- */
+INLINE void orb_im( void )
+{
+ UINT8 t;
+ IMMBYTE(t);
+ B |= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $cB ADDB immediate ***** */
+INLINE void addb_im( void )
+{
+ UINT16 t,r;
+ IMMBYTE(t);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $cC LDD immediate -**0- */
+INLINE void ldd_im( void )
+{
+ IMMWORD(pD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* is this a legal instruction? */
+/* $cD STD immediate -**0- */
+INLINE void std_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+ IMM16;
+ WM16(EAD,&pD);
+}
+
+/* $cE LDU (LDS) immediate -**0- */
+INLINE void ldu_im( void )
+{
+ IMMWORD(pU);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10cE LDS immediate -**0- */
+INLINE void lds_im( void )
+{
+ IMMWORD(pS);
+ CLR_NZV;
+ SET_NZ16(S);
+ m6809.int_state |= M6809_LDS;
+}
+
+/* is this a legal instruction? */
+/* $cF STU (STS) immediate -**0- */
+INLINE void stu_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(U);
+ IMM16;
+ WM16(EAD,&pU);
+}
+
+/* is this a legal instruction? */
+/* $10cF STS immediate -**0- */
+INLINE void sts_im( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ IMM16;
+ WM16(EAD,&pS);
+}
+
+/* $d0 SUBB direct ?**** */
+INLINE void subb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $d1 CMPB direct ?**** */
+INLINE void cmpb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+}
+
+/* $d2 SBCB direct ?**** */
+INLINE void sbcb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $d3 ADDD direct -**** */
+INLINE void addd_di( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ DIRWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $d4 ANDB direct -**0- */
+INLINE void andb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $d5 BITB direct -**0- */
+INLINE void bitb_di( void )
+{
+ UINT8 t,r;
+ DIRBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $d6 LDB direct -**0- */
+INLINE void ldb_di( void )
+{
+ DIRBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $d7 STB direct -**0- */
+INLINE void stb_di( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+ DIRECT;
+ WM(EAD,B);
+}
+
+/* $d8 EORB direct -**0- */
+INLINE void eorb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ B ^= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $d9 ADCB direct ***** */
+INLINE void adcb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $dA ORB direct -**0- */
+INLINE void orb_di( void )
+{
+ UINT8 t;
+ DIRBYTE(t);
+ B |= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $dB ADDB direct ***** */
+INLINE void addb_di( void )
+{
+ UINT16 t,r;
+ DIRBYTE(t);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $dC LDD direct -**0- */
+INLINE void ldd_di( void )
+{
+ DIRWORD(pD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $dD STD direct -**0- */
+INLINE void std_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+ DIRECT;
+ WM16(EAD,&pD);
+}
+
+/* $dE LDU (LDS) direct -**0- */
+INLINE void ldu_di( void )
+{
+ DIRWORD(pU);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10dE LDS direct -**0- */
+INLINE void lds_di( void )
+{
+ DIRWORD(pS);
+ CLR_NZV;
+ SET_NZ16(S);
+ m6809.int_state |= M6809_LDS;
+}
+
+/* $dF STU (STS) direct -**0- */
+INLINE void stu_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(U);
+ DIRECT;
+ WM16(EAD,&pU);
+}
+
+/* $10dF STS direct -**0- */
+INLINE void sts_di( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ DIRECT;
+ WM16(EAD,&pS);
+}
+
+/* $e0 SUBB indexed ?**** */
+INLINE void subb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $e1 CMPB indexed ?**** */
+INLINE void cmpb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+}
+
+/* $e2 SBCB indexed ?**** */
+INLINE void sbcb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $e3 ADDD indexed -**** */
+INLINE void addd_ix( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ fetch_effective_address();
+ b.d=RM16(EAD);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $e4 ANDB indexed -**0- */
+INLINE void andb_ix( void )
+{
+ fetch_effective_address();
+ B &= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $e5 BITB indexed -**0- */
+INLINE void bitb_ix( void )
+{
+ UINT8 r;
+ fetch_effective_address();
+ r = B & RM(EAD);
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $e6 LDB indexed -**0- */
+INLINE void ldb_ix( void )
+{
+ fetch_effective_address();
+ B = RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $e7 STB indexed -**0- */
+INLINE void stb_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ8(B);
+ WM(EAD,B);
+}
+
+/* $e8 EORB indexed -**0- */
+INLINE void eorb_ix( void )
+{
+ fetch_effective_address();
+ B ^= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $e9 ADCB indexed ***** */
+INLINE void adcb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $eA ORB indexed -**0- */
+INLINE void orb_ix( void )
+{
+ fetch_effective_address();
+ B |= RM(EAD);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $eB ADDB indexed ***** */
+INLINE void addb_ix( void )
+{
+ UINT16 t,r;
+ fetch_effective_address();
+ t = RM(EAD);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $eC LDD indexed -**0- */
+INLINE void ldd_ix( void )
+{
+ fetch_effective_address();
+ D=RM16(EAD);
+ CLR_NZV; SET_NZ16(D);
+}
+
+/* $eD STD indexed -**0- */
+INLINE void std_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(D);
+ WM16(EAD,&pD);
+}
+
+/* $eE LDU (LDS) indexed -**0- */
+INLINE void ldu_ix( void )
+{
+ fetch_effective_address();
+ U=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10eE LDS indexed -**0- */
+INLINE void lds_ix( void )
+{
+ fetch_effective_address();
+ S=RM16(EAD);
+ CLR_NZV;
+ SET_NZ16(S);
+ m6809.int_state |= M6809_LDS;
+}
+
+/* $eF STU (STS) indexed -**0- */
+INLINE void stu_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(U);
+ WM16(EAD,&pU);
+}
+
+/* $10eF STS indexed -**0- */
+INLINE void sts_ix( void )
+{
+ fetch_effective_address();
+ CLR_NZV;
+ SET_NZ16(S);
+ WM16(EAD,&pS);
+}
+
+/* $f0 SUBB extended ?**** */
+INLINE void subb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $f1 CMPB extended ?**** */
+INLINE void cmpb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B - t;
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+}
+
+/* $f2 SBCB extended ?**** */
+INLINE void sbcb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B - t - (CC & CC_C);
+ CLR_NZVC;
+ SET_FLAGS8(B,t,r);
+ B = r;
+}
+
+/* $f3 ADDD extended -**** */
+INLINE void addd_ex( void )
+{
+ UINT32 r,d;
+ PAIR b;
+ EXTWORD(b);
+ d = D;
+ r = d + b.d;
+ CLR_NZVC;
+ SET_FLAGS16(d,b.d,r);
+ D = r;
+}
+
+/* $f4 ANDB extended -**0- */
+INLINE void andb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B &= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $f5 BITB extended -**0- */
+INLINE void bitb_ex( void )
+{
+ UINT8 t,r;
+ EXTBYTE(t);
+ r = B & t;
+ CLR_NZV;
+ SET_NZ8(r);
+}
+
+/* $f6 LDB extended -**0- */
+INLINE void ldb_ex( void )
+{
+ EXTBYTE(B);
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $f7 STB extended -**0- */
+INLINE void stb_ex( void )
+{
+ CLR_NZV;
+ SET_NZ8(B);
+ EXTENDED;
+ WM(EAD,B);
+}
+
+/* $f8 EORB extended -**0- */
+INLINE void eorb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B ^= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $f9 ADCB extended ***** */
+INLINE void adcb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B + t + (CC & CC_C);
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $fA ORB extended -**0- */
+INLINE void orb_ex( void )
+{
+ UINT8 t;
+ EXTBYTE(t);
+ B |= t;
+ CLR_NZV;
+ SET_NZ8(B);
+}
+
+/* $fB ADDB extended ***** */
+INLINE void addb_ex( void )
+{
+ UINT16 t,r;
+ EXTBYTE(t);
+ r = B + t;
+ CLR_HNZVC;
+ SET_FLAGS8(B,t,r);
+ SET_H(B,t,r);
+ B = r;
+}
+
+/* $fC LDD extended -**0- */
+INLINE void ldd_ex( void )
+{
+ EXTWORD(pD);
+ CLR_NZV;
+ SET_NZ16(D);
+}
+
+/* $fD STD extended -**0- */
+INLINE void std_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(D);
+ EXTENDED;
+ WM16(EAD,&pD);
+}
+
+/* $fE LDU (LDS) extended -**0- */
+INLINE void ldu_ex( void )
+{
+ EXTWORD(pU);
+ CLR_NZV;
+ SET_NZ16(U);
+}
+
+/* $10fE LDS extended -**0- */
+INLINE void lds_ex( void )
+{
+ EXTWORD(pS);
+ CLR_NZV;
+ SET_NZ16(S);
+ m6809.int_state |= M6809_LDS;
+}
+
+/* $fF STU (STS) extended -**0- */
+INLINE void stu_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(U);
+ EXTENDED;
+ WM16(EAD,&pU);
+}
+
+/* $10fF STS extended -**0- */
+INLINE void sts_ex( void )
+{
+ CLR_NZV;
+ SET_NZ16(S);
+ EXTENDED;
+ WM16(EAD,&pS);
+}
+
+/* $10xx opcodes */
+INLINE void pref10( void )
+{
+ UINT8 ireg2 = ROP(PCD);
+ PC++;
+ switch( ireg2 )
+ {
+ case 0x21: lbrn(); m6809_ICount-=5; break;
+ case 0x22: lbhi(); m6809_ICount-=5; break;
+ case 0x23: lbls(); m6809_ICount-=5; break;
+ case 0x24: lbcc(); m6809_ICount-=5; break;
+ case 0x25: lbcs(); m6809_ICount-=5; break;
+ case 0x26: lbne(); m6809_ICount-=5; break;
+ case 0x27: lbeq(); m6809_ICount-=5; break;
+ case 0x28: lbvc(); m6809_ICount-=5; break;
+ case 0x29: lbvs(); m6809_ICount-=5; break;
+ case 0x2a: lbpl(); m6809_ICount-=5; break;
+ case 0x2b: lbmi(); m6809_ICount-=5; break;
+ case 0x2c: lbge(); m6809_ICount-=5; break;
+ case 0x2d: lblt(); m6809_ICount-=5; break;
+ case 0x2e: lbgt(); m6809_ICount-=5; break;
+ case 0x2f: lble(); m6809_ICount-=5; break;
+
+ case 0x3f: swi2(); m6809_ICount-=20; break;
+
+ case 0x83: cmpd_im(); m6809_ICount-=5; break;
+ case 0x8c: cmpy_im(); m6809_ICount-=5; break;
+ case 0x8e: ldy_im(); m6809_ICount-=4; break;
+ case 0x8f: sty_im(); m6809_ICount-=4; break;
+
+ case 0x93: cmpd_di(); m6809_ICount-=7; break;
+ case 0x9c: cmpy_di(); m6809_ICount-=7; break;
+ case 0x9e: ldy_di(); m6809_ICount-=6; break;
+ case 0x9f: sty_di(); m6809_ICount-=6; break;
+
+ case 0xa3: cmpd_ix(); m6809_ICount-=7; break;
+ case 0xac: cmpy_ix(); m6809_ICount-=7; break;
+ case 0xae: ldy_ix(); m6809_ICount-=6; break;
+ case 0xaf: sty_ix(); m6809_ICount-=6; break;
+
+ case 0xb3: cmpd_ex(); m6809_ICount-=8; break;
+ case 0xbc: cmpy_ex(); m6809_ICount-=8; break;
+ case 0xbe: ldy_ex(); m6809_ICount-=7; break;
+ case 0xbf: sty_ex(); m6809_ICount-=7; break;
+
+ case 0xce: lds_im(); m6809_ICount-=4; break;
+ case 0xcf: sts_im(); m6809_ICount-=4; break;
+
+ case 0xde: lds_di(); m6809_ICount-=6; break;
+ case 0xdf: sts_di(); m6809_ICount-=6; break;
+
+ case 0xee: lds_ix(); m6809_ICount-=6; break;
+ case 0xef: sts_ix(); m6809_ICount-=6; break;
+
+ case 0xfe: lds_ex(); m6809_ICount-=7; break;
+ case 0xff: sts_ex(); m6809_ICount-=7; break;
+
+ default: illegal(); break;
+ }
+}
+
+/* $11xx opcodes */
+INLINE void pref11( void )
+{
+ UINT8 ireg2 = ROP(PCD);
+ PC++;
+ switch( ireg2 )
+ {
+ case 0x3f: swi3(); m6809_ICount-=20; break;
+
+ case 0x83: cmpu_im(); m6809_ICount-=5; break;
+ case 0x8c: cmps_im(); m6809_ICount-=5; break;
+
+ case 0x93: cmpu_di(); m6809_ICount-=7; break;
+ case 0x9c: cmps_di(); m6809_ICount-=7; break;
+
+ case 0xa3: cmpu_ix(); m6809_ICount-=7; break;
+ case 0xac: cmps_ix(); m6809_ICount-=7; break;
+
+ case 0xb3: cmpu_ex(); m6809_ICount-=8; break;
+ case 0xbc: cmps_ex(); m6809_ICount-=8; break;
+
+ default: illegal(); break;
+ }
+}
+
+
diff --git a/src/emu/cpu/m6809/6809tbl.c b/src/emu/cpu/m6809/6809tbl.c
new file mode 100644
index 00000000000..66a6afe8424
--- /dev/null
+++ b/src/emu/cpu/m6809/6809tbl.c
@@ -0,0 +1,316 @@
+INLINE void abx(void);
+INLINE void adca_di(void);
+INLINE void adca_ex(void);
+INLINE void adca_im(void);
+INLINE void adca_ix(void);
+INLINE void adcb_di(void);
+INLINE void adcb_ex(void);
+INLINE void adcb_im(void);
+INLINE void adcb_ix(void);
+INLINE void adda_di(void);
+INLINE void adda_ex(void);
+INLINE void adda_im(void);
+INLINE void adda_ix(void);
+INLINE void addb_di(void);
+INLINE void addb_ex(void);
+INLINE void addb_im(void);
+INLINE void addb_ix(void);
+INLINE void addd_di(void);
+INLINE void addd_ex(void);
+INLINE void addd_im(void);
+INLINE void addd_ix(void);
+INLINE void anda_di(void);
+INLINE void anda_ex(void);
+INLINE void anda_im(void);
+INLINE void anda_ix(void);
+INLINE void andb_di(void);
+INLINE void andb_ex(void);
+INLINE void andb_im(void);
+INLINE void andb_ix(void);
+INLINE void andcc(void);
+INLINE void asl_di(void);
+INLINE void asl_ex(void);
+INLINE void asl_ix(void);
+INLINE void asla(void);
+INLINE void aslb(void);
+INLINE void asr_di(void);
+INLINE void asr_ex(void);
+INLINE void asr_ix(void);
+INLINE void asra(void);
+INLINE void asrb(void);
+INLINE void bcc(void);
+INLINE void bcs(void);
+INLINE void beq(void);
+INLINE void bge(void);
+INLINE void bgt(void);
+INLINE void bhi(void);
+INLINE void bita_di(void);
+INLINE void bita_ex(void);
+INLINE void bita_im(void);
+INLINE void bita_ix(void);
+INLINE void bitb_di(void);
+INLINE void bitb_ex(void);
+INLINE void bitb_im(void);
+INLINE void bitb_ix(void);
+INLINE void ble(void);
+INLINE void bls(void);
+INLINE void blt(void);
+INLINE void bmi(void);
+INLINE void bne(void);
+INLINE void bpl(void);
+INLINE void bra(void);
+INLINE void brn(void);
+INLINE void bsr(void);
+INLINE void bvc(void);
+INLINE void bvs(void);
+INLINE void clr_di(void);
+INLINE void clr_ex(void);
+INLINE void clr_ix(void);
+INLINE void clra(void);
+INLINE void clrb(void);
+INLINE void cmpa_di(void);
+INLINE void cmpa_ex(void);
+INLINE void cmpa_im(void);
+INLINE void cmpa_ix(void);
+INLINE void cmpb_di(void);
+INLINE void cmpb_ex(void);
+INLINE void cmpb_im(void);
+INLINE void cmpb_ix(void);
+INLINE void cmpd_di(void);
+INLINE void cmpd_ex(void);
+INLINE void cmpd_im(void);
+INLINE void cmpd_ix(void);
+INLINE void cmps_di(void);
+INLINE void cmps_ex(void);
+INLINE void cmps_im(void);
+INLINE void cmps_ix(void);
+INLINE void cmpu_di(void);
+INLINE void cmpu_ex(void);
+INLINE void cmpu_im(void);
+INLINE void cmpu_ix(void);
+INLINE void cmpx_di(void);
+INLINE void cmpx_ex(void);
+INLINE void cmpx_im(void);
+INLINE void cmpx_ix(void);
+INLINE void cmpy_di(void);
+INLINE void cmpy_ex(void);
+INLINE void cmpy_im(void);
+INLINE void cmpy_ix(void);
+INLINE void com_di(void);
+INLINE void com_ex(void);
+INLINE void com_ix(void);
+INLINE void coma(void);
+INLINE void comb(void);
+INLINE void cwai(void);
+INLINE void daa(void);
+INLINE void dec_di(void);
+INLINE void dec_ex(void);
+INLINE void dec_ix(void);
+INLINE void deca(void);
+INLINE void decb(void);
+INLINE void eora_di(void);
+INLINE void eora_ex(void);
+INLINE void eora_im(void);
+INLINE void eora_ix(void);
+INLINE void eorb_di(void);
+INLINE void eorb_ex(void);
+INLINE void eorb_im(void);
+INLINE void eorb_ix(void);
+INLINE void exg(void);
+INLINE void illegal(void);
+INLINE void inc_di(void);
+INLINE void inc_ex(void);
+INLINE void inc_ix(void);
+INLINE void inca(void);
+INLINE void incb(void);
+INLINE void jmp_di(void);
+INLINE void jmp_ex(void);
+INLINE void jmp_ix(void);
+INLINE void jsr_di(void);
+INLINE void jsr_ex(void);
+INLINE void jsr_ix(void);
+INLINE void lbcc(void);
+INLINE void lbcs(void);
+INLINE void lbeq(void);
+INLINE void lbge(void);
+INLINE void lbgt(void);
+INLINE void lbhi(void);
+INLINE void lble(void);
+INLINE void lbls(void);
+INLINE void lblt(void);
+INLINE void lbmi(void);
+INLINE void lbne(void);
+INLINE void lbpl(void);
+INLINE void lbra(void);
+INLINE void lbrn(void);
+INLINE void lbsr(void);
+INLINE void lbvc(void);
+INLINE void lbvs(void);
+INLINE void lda_di(void);
+INLINE void lda_ex(void);
+INLINE void lda_im(void);
+INLINE void lda_ix(void);
+INLINE void ldb_di(void);
+INLINE void ldb_ex(void);
+INLINE void ldb_im(void);
+INLINE void ldb_ix(void);
+INLINE void ldd_di(void);
+INLINE void ldd_ex(void);
+INLINE void ldd_im(void);
+INLINE void ldd_ix(void);
+INLINE void lds_di(void);
+INLINE void lds_ex(void);
+INLINE void lds_im(void);
+INLINE void lds_ix(void);
+INLINE void ldu_di(void);
+INLINE void ldu_ex(void);
+INLINE void ldu_im(void);
+INLINE void ldu_ix(void);
+INLINE void ldx_di(void);
+INLINE void ldx_ex(void);
+INLINE void ldx_im(void);
+INLINE void ldx_ix(void);
+INLINE void ldy_di(void);
+INLINE void ldy_ex(void);
+INLINE void ldy_im(void);
+INLINE void ldy_ix(void);
+INLINE void leas(void);
+INLINE void leau(void);
+INLINE void leax(void);
+INLINE void leay(void);
+INLINE void lsr_di(void);
+INLINE void lsr_ex(void);
+INLINE void lsr_ix(void);
+INLINE void lsra(void);
+INLINE void lsrb(void);
+INLINE void mul(void);
+INLINE void neg_di(void);
+INLINE void neg_ex(void);
+INLINE void neg_ix(void);
+INLINE void nega(void);
+INLINE void negb(void);
+INLINE void nop(void);
+INLINE void ora_di(void);
+INLINE void ora_ex(void);
+INLINE void ora_im(void);
+INLINE void ora_ix(void);
+INLINE void orb_di(void);
+INLINE void orb_ex(void);
+INLINE void orb_im(void);
+INLINE void orb_ix(void);
+INLINE void orcc(void);
+INLINE void pshs(void);
+INLINE void pshu(void);
+INLINE void puls(void);
+INLINE void pulu(void);
+INLINE void rol_di(void);
+INLINE void rol_ex(void);
+INLINE void rol_ix(void);
+INLINE void rola(void);
+INLINE void rolb(void);
+INLINE void ror_di(void);
+INLINE void ror_ex(void);
+INLINE void ror_ix(void);
+INLINE void rora(void);
+INLINE void rorb(void);
+INLINE void rti(void);
+INLINE void rts(void);
+INLINE void sbca_di(void);
+INLINE void sbca_ex(void);
+INLINE void sbca_im(void);
+INLINE void sbca_ix(void);
+INLINE void sbcb_di(void);
+INLINE void sbcb_ex(void);
+INLINE void sbcb_im(void);
+INLINE void sbcb_ix(void);
+INLINE void sex(void);
+INLINE void sta_di(void);
+INLINE void sta_ex(void);
+INLINE void sta_im(void);
+INLINE void sta_ix(void);
+INLINE void stb_di(void);
+INLINE void stb_ex(void);
+INLINE void stb_im(void);
+INLINE void stb_ix(void);
+INLINE void std_di(void);
+INLINE void std_ex(void);
+INLINE void std_im(void);
+INLINE void std_ix(void);
+INLINE void sts_di(void);
+INLINE void sts_ex(void);
+INLINE void sts_im(void);
+INLINE void sts_ix(void);
+INLINE void stu_di(void);
+INLINE void stu_ex(void);
+INLINE void stu_im(void);
+INLINE void stu_ix(void);
+INLINE void stx_di(void);
+INLINE void stx_ex(void);
+INLINE void stx_im(void);
+INLINE void stx_ix(void);
+INLINE void sty_di(void);
+INLINE void sty_ex(void);
+INLINE void sty_im(void);
+INLINE void sty_ix(void);
+INLINE void suba_di(void);
+INLINE void suba_ex(void);
+INLINE void suba_im(void);
+INLINE void suba_ix(void);
+INLINE void subb_di(void);
+INLINE void subb_ex(void);
+INLINE void subb_im(void);
+INLINE void subb_ix(void);
+INLINE void subd_di(void);
+INLINE void subd_ex(void);
+INLINE void subd_im(void);
+INLINE void subd_ix(void);
+INLINE void swi(void);
+INLINE void swi2(void);
+INLINE void swi3(void);
+INLINE void sync(void);
+INLINE void tfr(void);
+INLINE void tst_di(void);
+INLINE void tst_ex(void);
+INLINE void tst_ix(void);
+INLINE void tsta(void);
+INLINE void tstb(void);
+
+INLINE void pref10(void);
+INLINE void pref11(void);
+
+#if (BIG_SWITCH==0)
+static void (*m6809_main[0x100])(void) = {
+ neg_di, neg_di, illegal,com_di, lsr_di, illegal,ror_di, asr_di, /* 00 */
+ asl_di, rol_di, dec_di, illegal,inc_di, tst_di, jmp_di, clr_di,
+ pref10, pref11, nop, sync, illegal,illegal,lbra, lbsr, /* 10 */
+ illegal,daa, orcc, illegal,andcc, sex, exg, tfr,
+ bra, brn, bhi, bls, bcc, bcs, bne, beq, /* 20 */
+ bvc, bvs, bpl, bmi, bge, blt, bgt, ble,
+ leax, leay, leas, leau, pshs, puls, pshu, pulu, /* 30 */
+ illegal,rts, abx, rti, cwai, mul, illegal,swi,
+ nega, illegal,illegal,coma, lsra, illegal,rora, asra, /* 40 */
+ asla, rola, deca, illegal,inca, tsta, illegal,clra,
+ negb, illegal,illegal,comb, lsrb, illegal,rorb, asrb, /* 50 */
+ aslb, rolb, decb, illegal,incb, tstb, illegal,clrb,
+ neg_ix, illegal,illegal,com_ix, lsr_ix, illegal,ror_ix, asr_ix, /* 60 */
+ asl_ix, rol_ix, dec_ix, illegal,inc_ix, tst_ix, jmp_ix, clr_ix,
+ neg_ex, illegal,illegal,com_ex, lsr_ex, illegal,ror_ex, asr_ex, /* 70 */
+ asl_ex, rol_ex, dec_ex, illegal,inc_ex, tst_ex, jmp_ex, clr_ex,
+ suba_im,cmpa_im,sbca_im,subd_im,anda_im,bita_im,lda_im, sta_im, /* 80 */
+ eora_im,adca_im,ora_im, adda_im,cmpx_im,bsr, ldx_im, stx_im,
+ suba_di,cmpa_di,sbca_di,subd_di,anda_di,bita_di,lda_di, sta_di, /* 90 */
+ eora_di,adca_di,ora_di, adda_di,cmpx_di,jsr_di, ldx_di, stx_di,
+ suba_ix,cmpa_ix,sbca_ix,subd_ix,anda_ix,bita_ix,lda_ix, sta_ix, /* a0 */
+ eora_ix,adca_ix,ora_ix, adda_ix,cmpx_ix,jsr_ix, ldx_ix, stx_ix,
+ suba_ex,cmpa_ex,sbca_ex,subd_ex,anda_ex,bita_ex,lda_ex, sta_ex, /* b0 */
+ eora_ex,adca_ex,ora_ex, adda_ex,cmpx_ex,jsr_ex, ldx_ex, stx_ex,
+ subb_im,cmpb_im,sbcb_im,addd_im,andb_im,bitb_im,ldb_im, stb_im, /* c0 */
+ eorb_im,adcb_im,orb_im, addb_im,ldd_im, std_im, ldu_im, stu_im,
+ subb_di,cmpb_di,sbcb_di,addd_di,andb_di,bitb_di,ldb_di, stb_di, /* d0 */
+ eorb_di,adcb_di,orb_di, addb_di,ldd_di, std_di, ldu_di, stu_di,
+ subb_ix,cmpb_ix,sbcb_ix,addd_ix,andb_ix,bitb_ix,ldb_ix, stb_ix, /* e0 */
+ eorb_ix,adcb_ix,orb_ix, addb_ix,ldd_ix, std_ix, ldu_ix, stu_ix,
+ subb_ex,cmpb_ex,sbcb_ex,addd_ex,andb_ex,bitb_ex,ldb_ex, stb_ex, /* f0 */
+ eorb_ex,adcb_ex,orb_ex, addb_ex,ldd_ex, std_ex, ldu_ex, stu_ex
+};
+#endif
diff --git a/src/emu/cpu/m6809/m6809.c b/src/emu/cpu/m6809/m6809.c
new file mode 100644
index 00000000000..f5cb1b5b8a9
--- /dev/null
+++ b/src/emu/cpu/m6809/m6809.c
@@ -0,0 +1,1232 @@
+/*** m6809: Portable 6809 emulator ******************************************
+
+ Copyright (C) John Butler 1997
+
+ References:
+
+ 6809 Simulator V09, By L.C. Benschop, Eidnhoven The Netherlands.
+
+ m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from
+ the 6809 Simulator V09)
+
+ 6809 Microcomputer Programming & Interfacing with Experiments"
+ by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc.
+
+ System dependencies: UINT16 must be 16 bit unsigned int
+ UINT8 must be 8 bit unsigned int
+ UINT32 must be more than 16 bits
+ arrays up to 65536 bytes must be supported
+ machine must be twos complement
+
+ History:
+991026 HJB:
+ Fixed missing calls to cpu_changepc() for the TFR and EXG ocpodes.
+ Replaced m6809_slapstic checks by a macro (CHANGE_PC). ESB still
+ needs the tweaks.
+
+991024 HJB:
+ Tried to improve speed: Using bit7 of cycles1/2 as flag for multi
+ byte opcodes is gone, those opcodes now call fetch_effective_address().
+ Got rid of the slow/fast flags for stack (S and U) memory accesses.
+ Minor changes to use 32 bit values as arguments to memory functions
+ and added defines for that purpose (e.g. X = 16bit XD = 32bit).
+
+990312 HJB:
+ Added bugfixes according to Aaron's findings.
+ Reset only sets CC_II and CC_IF, DP to zero and PC from reset vector.
+990311 HJB:
+ Added _info functions. Now uses static m6808_Regs struct instead
+ of single statics. Changed the 16 bit registers to use the generic
+ PAIR union. Registers defined using macros. Split the core into
+ four execution loops for M6802, M6803, M6808 and HD63701.
+ TST, TSTA and TSTB opcodes reset carry flag.
+ Modified the read/write stack handlers to push LSB first then MSB
+ and pull MSB first then LSB.
+
+990228 HJB:
+ Changed the interrupt handling again. Now interrupts are taken
+ either right at the moment the lines are asserted or whenever
+ an interrupt is enabled and the corresponding line is still
+ asserted. That way the pending_interrupts checks are not
+ needed anymore. However, the CWAI and SYNC flags still need
+ some flags, so I changed the name to 'int_state'.
+ This core also has the code for the old interrupt system removed.
+
+990225 HJB:
+ Cleaned up the code here and there, added some comments.
+ Slightly changed the SAR opcodes (similiar to other CPU cores).
+ Added symbolic names for the flag bits.
+ Changed the way CWAI/Interrupt() handle CPU state saving.
+ A new flag M6809_STATE in pending_interrupts is used to determine
+ if a state save is needed on interrupt entry or already done by CWAI.
+ Added M6809_IRQ_LINE and M6809_FIRQ_LINE defines to m6809.h
+ Moved the internal interrupt_pending flags from m6809.h to m6809.c
+ Changed CWAI cycles2[0x3c] to be 2 (plus all or at least 19 if
+ CWAI actually pushes the entire state).
+ Implemented undocumented TFR/EXG for undefined source and mixed 8/16
+ bit transfers (they should transfer/exchange the constant $ff).
+ Removed unused jmp/jsr _slap functions from 6809ops.c,
+ m6809_slapstick check moved into the opcode functions.
+
+*****************************************************************************/
+
+#include "debugger.h"
+#include "m6809.h"
+
+/* Enable big switch statement for the main opcodes */
+#ifndef BIG_SWITCH
+#define BIG_SWITCH 1
+#endif
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+#ifdef MAME_DEBUG
+extern offs_t m6809_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+
+INLINE void fetch_effective_address( void );
+
+/* 6809 Registers */
+typedef struct
+{
+ PAIR pc; /* Program counter */
+ PAIR ppc; /* Previous program counter */
+ PAIR d; /* Accumulator a and b */
+ PAIR dp; /* Direct Page register (page in MSB) */
+ PAIR u, s; /* Stack pointers */
+ PAIR x, y; /* Index registers */
+ UINT8 cc;
+ UINT8 ireg; /* First opcode */
+ UINT8 irq_state[2];
+ int extra_cycles; /* cycles used up by interrupts */
+ int (*irq_callback)(int irqline);
+ UINT8 int_state; /* SYNC and CWAI flags */
+ UINT8 nmi_state;
+} m6809_Regs;
+
+/* flag bits in the cc register */
+#define CC_C 0x01 /* Carry */
+#define CC_V 0x02 /* Overflow */
+#define CC_Z 0x04 /* Zero */
+#define CC_N 0x08 /* Negative */
+#define CC_II 0x10 /* Inhibit IRQ */
+#define CC_H 0x20 /* Half (auxiliary) carry */
+#define CC_IF 0x40 /* Inhibit FIRQ */
+#define CC_E 0x80 /* entire state pushed */
+
+/* 6809 registers */
+static m6809_Regs m6809;
+
+#define pPPC m6809.ppc
+#define pPC m6809.pc
+#define pU m6809.u
+#define pS m6809.s
+#define pX m6809.x
+#define pY m6809.y
+#define pD m6809.d
+
+#define PPC m6809.ppc.w.l
+#define PC m6809.pc.w.l
+#define PCD m6809.pc.d
+#define U m6809.u.w.l
+#define UD m6809.u.d
+#define S m6809.s.w.l
+#define SD m6809.s.d
+#define X m6809.x.w.l
+#define XD m6809.x.d
+#define Y m6809.y.w.l
+#define YD m6809.y.d
+#define D m6809.d.w.l
+#define A m6809.d.b.h
+#define B m6809.d.b.l
+#define DP m6809.dp.b.h
+#define DPD m6809.dp.d
+#define CC m6809.cc
+
+static PAIR ea; /* effective address */
+#define EA ea.w.l
+#define EAD ea.d
+
+#define CHANGE_PC change_pc(PCD)
+
+#define M6809_CWAI 8 /* set when CWAI is waiting for an interrupt */
+#define M6809_SYNC 16 /* set when SYNC is waiting for an interrupt */
+#define M6809_LDS 32 /* set when LDS occured at least once */
+
+#define CHECK_IRQ_LINES \
+ if( m6809.irq_state[M6809_IRQ_LINE] != CLEAR_LINE || \
+ m6809.irq_state[M6809_FIRQ_LINE] != CLEAR_LINE ) \
+ m6809.int_state &= ~M6809_SYNC; /* clear SYNC flag */ \
+ if( m6809.irq_state[M6809_FIRQ_LINE]!=CLEAR_LINE && !(CC & CC_IF) ) \
+ { \
+ /* fast IRQ */ \
+ /* HJB 990225: state already saved by CWAI? */ \
+ if( m6809.int_state & M6809_CWAI ) \
+ { \
+ m6809.int_state &= ~M6809_CWAI; /* clear CWAI */ \
+ m6809.extra_cycles += 7; /* subtract +7 cycles */ \
+ } \
+ else \
+ { \
+ CC &= ~CC_E; /* save 'short' state */ \
+ PUSHWORD(pPC); \
+ PUSHBYTE(CC); \
+ m6809.extra_cycles += 10; /* subtract +10 cycles */ \
+ } \
+ CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */ \
+ PCD=RM16(0xfff6); \
+ CHANGE_PC; \
+ (void)(*m6809.irq_callback)(M6809_FIRQ_LINE); \
+ } \
+ else \
+ if( m6809.irq_state[M6809_IRQ_LINE]!=CLEAR_LINE && !(CC & CC_II) ) \
+ { \
+ /* standard IRQ */ \
+ /* HJB 990225: state already saved by CWAI? */ \
+ if( m6809.int_state & M6809_CWAI ) \
+ { \
+ m6809.int_state &= ~M6809_CWAI; /* clear CWAI flag */ \
+ m6809.extra_cycles += 7; /* subtract +7 cycles */ \
+ } \
+ else \
+ { \
+ CC |= CC_E; /* save entire state */ \
+ PUSHWORD(pPC); \
+ PUSHWORD(pU); \
+ PUSHWORD(pY); \
+ PUSHWORD(pX); \
+ PUSHBYTE(DP); \
+ PUSHBYTE(B); \
+ PUSHBYTE(A); \
+ PUSHBYTE(CC); \
+ m6809.extra_cycles += 19; /* subtract +19 cycles */ \
+ } \
+ CC |= CC_II; /* inhibit IRQ */ \
+ PCD=RM16(0xfff8); \
+ CHANGE_PC; \
+ (void)(*m6809.irq_callback)(M6809_IRQ_LINE); \
+ }
+
+/* public globals */
+static int m6809_ICount;
+
+/* these are re-defined in m6809.h TO RAM, ROM or functions in cpuintrf.c */
+#define RM(Addr) M6809_RDMEM(Addr)
+#define WM(Addr,Value) M6809_WRMEM(Addr,Value)
+#define ROP(Addr) M6809_RDOP(Addr)
+#define ROP_ARG(Addr) M6809_RDOP_ARG(Addr)
+
+/* macros to access memory */
+#define IMMBYTE(b) b = ROP_ARG(PCD); PC++
+#define IMMWORD(w) w.d = (ROP_ARG(PCD)<<8) | ROP_ARG((PCD+1)&0xffff); PC+=2
+
+#define PUSHBYTE(b) --S; WM(SD,b)
+#define PUSHWORD(w) --S; WM(SD,w.b.l); --S; WM(SD,w.b.h)
+#define PULLBYTE(b) b = RM(SD); S++
+#define PULLWORD(w) w = RM(SD)<<8; S++; w |= RM(SD); S++
+
+#define PSHUBYTE(b) --U; WM(UD,b);
+#define PSHUWORD(w) --U; WM(UD,w.b.l); --U; WM(UD,w.b.h)
+#define PULUBYTE(b) b = RM(UD); U++
+#define PULUWORD(w) w = RM(UD)<<8; U++; w |= RM(UD); U++
+
+#define CLR_HNZVC CC&=~(CC_H|CC_N|CC_Z|CC_V|CC_C)
+#define CLR_NZV CC&=~(CC_N|CC_Z|CC_V)
+#define CLR_NZ CC&=~(CC_N|CC_Z)
+#define CLR_HNZC CC&=~(CC_H|CC_N|CC_Z|CC_C)
+#define CLR_NZVC CC&=~(CC_N|CC_Z|CC_V|CC_C)
+#define CLR_Z CC&=~(CC_Z)
+#define CLR_NZC CC&=~(CC_N|CC_Z|CC_C)
+#define CLR_ZC CC&=~(CC_Z|CC_C)
+
+/* macros for CC -- CC bits affected should be reset before calling */
+#define SET_Z(a) if(!a)SEZ
+#define SET_Z8(a) SET_Z((UINT8)a)
+#define SET_Z16(a) SET_Z((UINT16)a)
+#define SET_N8(a) CC|=((a&0x80)>>4)
+#define SET_N16(a) CC|=((a&0x8000)>>12)
+#define SET_H(a,b,r) CC|=(((a^b^r)&0x10)<<1)
+#define SET_C8(a) CC|=((a&0x100)>>8)
+#define SET_C16(a) CC|=((a&0x10000)>>16)
+#define SET_V8(a,b,r) CC|=(((a^b^r^(r>>1))&0x80)>>6)
+#define SET_V16(a,b,r) CC|=(((a^b^r^(r>>1))&0x8000)>>14)
+
+static UINT8 flags8i[256]= /* increment */
+{
+CC_Z,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+CC_N|CC_V,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N
+};
+static UINT8 flags8d[256]= /* decrement */
+{
+CC_Z,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,CC_V,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
+CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N
+};
+#define SET_FLAGS8I(a) {CC|=flags8i[(a)&0xff];}
+#define SET_FLAGS8D(a) {CC|=flags8d[(a)&0xff];}
+
+/* combos */
+#define SET_NZ8(a) {SET_N8(a);SET_Z(a);}
+#define SET_NZ16(a) {SET_N16(a);SET_Z(a);}
+#define SET_FLAGS8(a,b,r) {SET_N8(r);SET_Z8(r);SET_V8(a,b,r);SET_C8(r);}
+#define SET_FLAGS16(a,b,r) {SET_N16(r);SET_Z16(r);SET_V16(a,b,r);SET_C16(r);}
+
+/* for treating an unsigned byte as a signed word */
+#define SIGNED(b) ((UINT16)(b&0x80?b|0xff00:b))
+
+/* macros for addressing modes (postbytes have their own code) */
+#define DIRECT EAD = DPD; IMMBYTE(ea.b.l)
+#define IMM8 EAD = PCD; PC++
+#define IMM16 EAD = PCD; PC+=2
+#define EXTENDED IMMWORD(ea)
+
+/* macros to set status flags */
+#define SEC CC|=CC_C
+#define CLC CC&=~CC_C
+#define SEZ CC|=CC_Z
+#define CLZ CC&=~CC_Z
+#define SEN CC|=CC_N
+#define CLN CC&=~CC_N
+#define SEV CC|=CC_V
+#define CLV CC&=~CC_V
+#define SEH CC|=CC_H
+#define CLH CC&=~CC_H
+
+/* macros for convenience */
+#define DIRBYTE(b) {DIRECT;b=RM(EAD);}
+#define DIRWORD(w) {DIRECT;w.d=RM16(EAD);}
+#define EXTBYTE(b) {EXTENDED;b=RM(EAD);}
+#define EXTWORD(w) {EXTENDED;w.d=RM16(EAD);}
+
+/* macros for branch instructions */
+#define BRANCH(f) { \
+ UINT8 t; \
+ IMMBYTE(t); \
+ if( f ) \
+ { \
+ PC += SIGNED(t); \
+ CHANGE_PC; \
+ } \
+}
+
+#define LBRANCH(f) { \
+ PAIR t; \
+ IMMWORD(t); \
+ if( f ) \
+ { \
+ m6809_ICount -= 1; \
+ PC += t.w.l; \
+ CHANGE_PC; \
+ } \
+}
+
+#define NXORV ((CC&CC_N)^((CC&CC_V)<<2))
+
+/* macros for setting/getting registers in TFR/EXG instructions */
+
+#if (!BIG_SWITCH)
+/* timings for 1-byte opcodes */
+static UINT8 cycles1[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ 6, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 0, 6, 6, 3, 6,
+ /*1*/ 0, 0, 2, 4, 0, 0, 5, 9, 0, 2, 3, 0, 3, 2, 8, 6,
+ /*2*/ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ /*3*/ 4, 4, 4, 4, 5, 5, 5, 5, 0, 5, 3, 6,20,11, 0,19,
+ /*4*/ 2, 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2,
+ /*5*/ 2, 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2,
+ /*6*/ 6, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 0, 6, 6, 3, 6,
+ /*7*/ 7, 0, 0, 7, 7, 0, 7, 7, 7, 7, 7, 0, 7, 7, 4, 7,
+ /*8*/ 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 4, 7, 3, 0,
+ /*9*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 7, 5, 5,
+ /*A*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 7, 5, 5,
+ /*B*/ 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 5, 7, 8, 6, 6,
+ /*C*/ 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 3, 3,
+ /*D*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ /*E*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ /*F*/ 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6
+};
+#endif
+
+INLINE UINT32 RM16( UINT32 Addr )
+{
+ UINT32 result = RM(Addr) << 8;
+ return result | RM((Addr+1)&0xffff);
+}
+
+INLINE void WM16( UINT32 Addr, PAIR *p )
+{
+ WM( Addr, p->b.h );
+ WM( (Addr+1)&0xffff, p->b.l );
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void m6809_get_context(void *dst)
+{
+ if( dst )
+ *(m6809_Regs*)dst = m6809;
+}
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void m6809_set_context(void *src)
+{
+ if( src )
+ m6809 = *(m6809_Regs*)src;
+ CHANGE_PC;
+
+ CHECK_IRQ_LINES;
+}
+
+
+/****************************************************************************/
+/* Reset registers to their initial values */
+/****************************************************************************/
+static void m6809_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ state_save_register_item("m6809", index, PC);
+ state_save_register_item("m6809", index, PPC);
+ state_save_register_item("m6809", index, D);
+ state_save_register_item("m6809", index, DP);
+ state_save_register_item("m6809", index, U);
+ state_save_register_item("m6809", index, S);
+ state_save_register_item("m6809", index, X);
+ state_save_register_item("m6809", index, Y);
+ state_save_register_item("m6809", index, CC);
+ state_save_register_item_array("m6809", index, m6809.irq_state);
+ state_save_register_item("m6809", index, m6809.int_state);
+ state_save_register_item("m6809", index, m6809.nmi_state);
+
+ m6809.irq_callback = irqcallback;
+}
+
+static void m6809_reset(void)
+{
+ m6809.int_state = 0;
+ m6809.nmi_state = CLEAR_LINE;
+ m6809.irq_state[0] = CLEAR_LINE;
+ m6809.irq_state[1] = CLEAR_LINE;
+
+ DPD = 0; /* Reset direct page register */
+
+ CC |= CC_II; /* IRQ disabled */
+ CC |= CC_IF; /* FIRQ disabled */
+
+ PCD = RM16(0xfffe);
+ CHANGE_PC;
+}
+
+static void m6809_exit(void)
+{
+ /* nothing to do ? */
+}
+
+/* Generate interrupts */
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m6809.nmi_state == state) return;
+ m6809.nmi_state = state;
+ LOG(("M6809#%d set_irq_line (NMI) %d\n", cpu_getactivecpu(), state));
+ if( state == CLEAR_LINE ) return;
+
+ /* if the stack was not yet initialized */
+ if( !(m6809.int_state & M6809_LDS) ) return;
+
+ m6809.int_state &= ~M6809_SYNC;
+ /* HJB 990225: state already saved by CWAI? */
+ if( m6809.int_state & M6809_CWAI )
+ {
+ m6809.int_state &= ~M6809_CWAI;
+ m6809.extra_cycles += 7; /* subtract +7 cycles next time */
+ }
+ else
+ {
+ CC |= CC_E; /* save entire state */
+ PUSHWORD(pPC);
+ PUSHWORD(pU);
+ PUSHWORD(pY);
+ PUSHWORD(pX);
+ PUSHBYTE(DP);
+ PUSHBYTE(B);
+ PUSHBYTE(A);
+ PUSHBYTE(CC);
+ m6809.extra_cycles += 19; /* subtract +19 cycles next time */
+ }
+ CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */
+ PCD = RM16(0xfffc);
+ CHANGE_PC;
+ }
+ else if (irqline < 2)
+ {
+ LOG(("M6809#%d set_irq_line %d, %d\n", cpu_getactivecpu(), irqline, state));
+ m6809.irq_state[irqline] = state;
+ if (state == CLEAR_LINE) return;
+ CHECK_IRQ_LINES;
+ }
+}
+
+/* includes the static function prototypes and the master opcode table */
+#include "6809tbl.c"
+
+/* includes the actual opcode implementations */
+#include "6809ops.c"
+
+/* execute instructions on this CPU until icount expires */
+static int m6809_execute(int cycles) /* NS 970908 */
+{
+ m6809_ICount = cycles - m6809.extra_cycles;
+ m6809.extra_cycles = 0;
+
+ if (m6809.int_state & (M6809_CWAI | M6809_SYNC))
+ {
+ CALL_MAME_DEBUG;
+ m6809_ICount = 0;
+ }
+ else
+ {
+ do
+ {
+ pPPC = pPC;
+
+ CALL_MAME_DEBUG;
+
+ m6809.ireg = ROP(PCD);
+ PC++;
+#if BIG_SWITCH
+ switch( m6809.ireg )
+ {
+ case 0x00: neg_di(); m6809_ICount-= 6; break;
+ case 0x01: neg_di(); m6809_ICount-= 6; break; /* undocumented */
+ case 0x02: illegal(); m6809_ICount-= 2; break;
+ case 0x03: com_di(); m6809_ICount-= 6; break;
+ case 0x04: lsr_di(); m6809_ICount-= 6; break;
+ case 0x05: illegal(); m6809_ICount-= 2; break;
+ case 0x06: ror_di(); m6809_ICount-= 6; break;
+ case 0x07: asr_di(); m6809_ICount-= 6; break;
+ case 0x08: asl_di(); m6809_ICount-= 6; break;
+ case 0x09: rol_di(); m6809_ICount-= 6; break;
+ case 0x0a: dec_di(); m6809_ICount-= 6; break;
+ case 0x0b: illegal(); m6809_ICount-= 2; break;
+ case 0x0c: inc_di(); m6809_ICount-= 6; break;
+ case 0x0d: tst_di(); m6809_ICount-= 6; break;
+ case 0x0e: jmp_di(); m6809_ICount-= 3; break;
+ case 0x0f: clr_di(); m6809_ICount-= 6; break;
+ case 0x10: pref10(); break;
+ case 0x11: pref11(); break;
+ case 0x12: nop(); m6809_ICount-= 2; break;
+ case 0x13: sync(); m6809_ICount-= 4; break;
+ case 0x14: illegal(); m6809_ICount-= 2; break;
+ case 0x15: illegal(); m6809_ICount-= 2; break;
+ case 0x16: lbra(); m6809_ICount-= 5; break;
+ case 0x17: lbsr(); m6809_ICount-= 9; break;
+ case 0x18: illegal(); m6809_ICount-= 2; break;
+ case 0x19: daa(); m6809_ICount-= 2; break;
+ case 0x1a: orcc(); m6809_ICount-= 3; break;
+ case 0x1b: illegal(); m6809_ICount-= 2; break;
+ case 0x1c: andcc(); m6809_ICount-= 3; break;
+ case 0x1d: sex(); m6809_ICount-= 2; break;
+ case 0x1e: exg(); m6809_ICount-= 8; break;
+ case 0x1f: tfr(); m6809_ICount-= 6; break;
+ case 0x20: bra(); m6809_ICount-= 3; break;
+ case 0x21: brn(); m6809_ICount-= 3; break;
+ case 0x22: bhi(); m6809_ICount-= 3; break;
+ case 0x23: bls(); m6809_ICount-= 3; break;
+ case 0x24: bcc(); m6809_ICount-= 3; break;
+ case 0x25: bcs(); m6809_ICount-= 3; break;
+ case 0x26: bne(); m6809_ICount-= 3; break;
+ case 0x27: beq(); m6809_ICount-= 3; break;
+ case 0x28: bvc(); m6809_ICount-= 3; break;
+ case 0x29: bvs(); m6809_ICount-= 3; break;
+ case 0x2a: bpl(); m6809_ICount-= 3; break;
+ case 0x2b: bmi(); m6809_ICount-= 3; break;
+ case 0x2c: bge(); m6809_ICount-= 3; break;
+ case 0x2d: blt(); m6809_ICount-= 3; break;
+ case 0x2e: bgt(); m6809_ICount-= 3; break;
+ case 0x2f: ble(); m6809_ICount-= 3; break;
+ case 0x30: leax(); m6809_ICount-= 4; break;
+ case 0x31: leay(); m6809_ICount-= 4; break;
+ case 0x32: leas(); m6809_ICount-= 4; break;
+ case 0x33: leau(); m6809_ICount-= 4; break;
+ case 0x34: pshs(); m6809_ICount-= 5; break;
+ case 0x35: puls(); m6809_ICount-= 5; break;
+ case 0x36: pshu(); m6809_ICount-= 5; break;
+ case 0x37: pulu(); m6809_ICount-= 5; break;
+ case 0x38: illegal(); m6809_ICount-= 2; break;
+ case 0x39: rts(); m6809_ICount-= 5; break;
+ case 0x3a: abx(); m6809_ICount-= 3; break;
+ case 0x3b: rti(); m6809_ICount-= 6; break;
+ case 0x3c: cwai(); m6809_ICount-=20; break;
+ case 0x3d: mul(); m6809_ICount-=11; break;
+ case 0x3e: illegal(); m6809_ICount-= 2; break;
+ case 0x3f: swi(); m6809_ICount-=19; break;
+ case 0x40: nega(); m6809_ICount-= 2; break;
+ case 0x41: illegal(); m6809_ICount-= 2; break;
+ case 0x42: illegal(); m6809_ICount-= 2; break;
+ case 0x43: coma(); m6809_ICount-= 2; break;
+ case 0x44: lsra(); m6809_ICount-= 2; break;
+ case 0x45: illegal(); m6809_ICount-= 2; break;
+ case 0x46: rora(); m6809_ICount-= 2; break;
+ case 0x47: asra(); m6809_ICount-= 2; break;
+ case 0x48: asla(); m6809_ICount-= 2; break;
+ case 0x49: rola(); m6809_ICount-= 2; break;
+ case 0x4a: deca(); m6809_ICount-= 2; break;
+ case 0x4b: illegal(); m6809_ICount-= 2; break;
+ case 0x4c: inca(); m6809_ICount-= 2; break;
+ case 0x4d: tsta(); m6809_ICount-= 2; break;
+ case 0x4e: illegal(); m6809_ICount-= 2; break;
+ case 0x4f: clra(); m6809_ICount-= 2; break;
+ case 0x50: negb(); m6809_ICount-= 2; break;
+ case 0x51: illegal(); m6809_ICount-= 2; break;
+ case 0x52: illegal(); m6809_ICount-= 2; break;
+ case 0x53: comb(); m6809_ICount-= 2; break;
+ case 0x54: lsrb(); m6809_ICount-= 2; break;
+ case 0x55: illegal(); m6809_ICount-= 2; break;
+ case 0x56: rorb(); m6809_ICount-= 2; break;
+ case 0x57: asrb(); m6809_ICount-= 2; break;
+ case 0x58: aslb(); m6809_ICount-= 2; break;
+ case 0x59: rolb(); m6809_ICount-= 2; break;
+ case 0x5a: decb(); m6809_ICount-= 2; break;
+ case 0x5b: illegal(); m6809_ICount-= 2; break;
+ case 0x5c: incb(); m6809_ICount-= 2; break;
+ case 0x5d: tstb(); m6809_ICount-= 2; break;
+ case 0x5e: illegal(); m6809_ICount-= 2; break;
+ case 0x5f: clrb(); m6809_ICount-= 2; break;
+ case 0x60: neg_ix(); m6809_ICount-= 6; break;
+ case 0x61: illegal(); m6809_ICount-= 2; break;
+ case 0x62: illegal(); m6809_ICount-= 2; break;
+ case 0x63: com_ix(); m6809_ICount-= 6; break;
+ case 0x64: lsr_ix(); m6809_ICount-= 6; break;
+ case 0x65: illegal(); m6809_ICount-= 2; break;
+ case 0x66: ror_ix(); m6809_ICount-= 6; break;
+ case 0x67: asr_ix(); m6809_ICount-= 6; break;
+ case 0x68: asl_ix(); m6809_ICount-= 6; break;
+ case 0x69: rol_ix(); m6809_ICount-= 6; break;
+ case 0x6a: dec_ix(); m6809_ICount-= 6; break;
+ case 0x6b: illegal(); m6809_ICount-= 2; break;
+ case 0x6c: inc_ix(); m6809_ICount-= 6; break;
+ case 0x6d: tst_ix(); m6809_ICount-= 6; break;
+ case 0x6e: jmp_ix(); m6809_ICount-= 3; break;
+ case 0x6f: clr_ix(); m6809_ICount-= 6; break;
+ case 0x70: neg_ex(); m6809_ICount-= 7; break;
+ case 0x71: illegal(); m6809_ICount-= 2; break;
+ case 0x72: illegal(); m6809_ICount-= 2; break;
+ case 0x73: com_ex(); m6809_ICount-= 7; break;
+ case 0x74: lsr_ex(); m6809_ICount-= 7; break;
+ case 0x75: illegal(); m6809_ICount-= 2; break;
+ case 0x76: ror_ex(); m6809_ICount-= 7; break;
+ case 0x77: asr_ex(); m6809_ICount-= 7; break;
+ case 0x78: asl_ex(); m6809_ICount-= 7; break;
+ case 0x79: rol_ex(); m6809_ICount-= 7; break;
+ case 0x7a: dec_ex(); m6809_ICount-= 7; break;
+ case 0x7b: illegal(); m6809_ICount-= 2; break;
+ case 0x7c: inc_ex(); m6809_ICount-= 7; break;
+ case 0x7d: tst_ex(); m6809_ICount-= 7; break;
+ case 0x7e: jmp_ex(); m6809_ICount-= 4; break;
+ case 0x7f: clr_ex(); m6809_ICount-= 7; break;
+ case 0x80: suba_im(); m6809_ICount-= 2; break;
+ case 0x81: cmpa_im(); m6809_ICount-= 2; break;
+ case 0x82: sbca_im(); m6809_ICount-= 2; break;
+ case 0x83: subd_im(); m6809_ICount-= 4; break;
+ case 0x84: anda_im(); m6809_ICount-= 2; break;
+ case 0x85: bita_im(); m6809_ICount-= 2; break;
+ case 0x86: lda_im(); m6809_ICount-= 2; break;
+ case 0x87: sta_im(); m6809_ICount-= 2; break;
+ case 0x88: eora_im(); m6809_ICount-= 2; break;
+ case 0x89: adca_im(); m6809_ICount-= 2; break;
+ case 0x8a: ora_im(); m6809_ICount-= 2; break;
+ case 0x8b: adda_im(); m6809_ICount-= 2; break;
+ case 0x8c: cmpx_im(); m6809_ICount-= 4; break;
+ case 0x8d: bsr(); m6809_ICount-= 7; break;
+ case 0x8e: ldx_im(); m6809_ICount-= 3; break;
+ case 0x8f: stx_im(); m6809_ICount-= 2; break;
+ case 0x90: suba_di(); m6809_ICount-= 4; break;
+ case 0x91: cmpa_di(); m6809_ICount-= 4; break;
+ case 0x92: sbca_di(); m6809_ICount-= 4; break;
+ case 0x93: subd_di(); m6809_ICount-= 6; break;
+ case 0x94: anda_di(); m6809_ICount-= 4; break;
+ case 0x95: bita_di(); m6809_ICount-= 4; break;
+ case 0x96: lda_di(); m6809_ICount-= 4; break;
+ case 0x97: sta_di(); m6809_ICount-= 4; break;
+ case 0x98: eora_di(); m6809_ICount-= 4; break;
+ case 0x99: adca_di(); m6809_ICount-= 4; break;
+ case 0x9a: ora_di(); m6809_ICount-= 4; break;
+ case 0x9b: adda_di(); m6809_ICount-= 4; break;
+ case 0x9c: cmpx_di(); m6809_ICount-= 6; break;
+ case 0x9d: jsr_di(); m6809_ICount-= 7; break;
+ case 0x9e: ldx_di(); m6809_ICount-= 5; break;
+ case 0x9f: stx_di(); m6809_ICount-= 5; break;
+ case 0xa0: suba_ix(); m6809_ICount-= 4; break;
+ case 0xa1: cmpa_ix(); m6809_ICount-= 4; break;
+ case 0xa2: sbca_ix(); m6809_ICount-= 4; break;
+ case 0xa3: subd_ix(); m6809_ICount-= 6; break;
+ case 0xa4: anda_ix(); m6809_ICount-= 4; break;
+ case 0xa5: bita_ix(); m6809_ICount-= 4; break;
+ case 0xa6: lda_ix(); m6809_ICount-= 4; break;
+ case 0xa7: sta_ix(); m6809_ICount-= 4; break;
+ case 0xa8: eora_ix(); m6809_ICount-= 4; break;
+ case 0xa9: adca_ix(); m6809_ICount-= 4; break;
+ case 0xaa: ora_ix(); m6809_ICount-= 4; break;
+ case 0xab: adda_ix(); m6809_ICount-= 4; break;
+ case 0xac: cmpx_ix(); m6809_ICount-= 6; break;
+ case 0xad: jsr_ix(); m6809_ICount-= 7; break;
+ case 0xae: ldx_ix(); m6809_ICount-= 5; break;
+ case 0xaf: stx_ix(); m6809_ICount-= 5; break;
+ case 0xb0: suba_ex(); m6809_ICount-= 5; break;
+ case 0xb1: cmpa_ex(); m6809_ICount-= 5; break;
+ case 0xb2: sbca_ex(); m6809_ICount-= 5; break;
+ case 0xb3: subd_ex(); m6809_ICount-= 7; break;
+ case 0xb4: anda_ex(); m6809_ICount-= 5; break;
+ case 0xb5: bita_ex(); m6809_ICount-= 5; break;
+ case 0xb6: lda_ex(); m6809_ICount-= 5; break;
+ case 0xb7: sta_ex(); m6809_ICount-= 5; break;
+ case 0xb8: eora_ex(); m6809_ICount-= 5; break;
+ case 0xb9: adca_ex(); m6809_ICount-= 5; break;
+ case 0xba: ora_ex(); m6809_ICount-= 5; break;
+ case 0xbb: adda_ex(); m6809_ICount-= 5; break;
+ case 0xbc: cmpx_ex(); m6809_ICount-= 7; break;
+ case 0xbd: jsr_ex(); m6809_ICount-= 8; break;
+ case 0xbe: ldx_ex(); m6809_ICount-= 6; break;
+ case 0xbf: stx_ex(); m6809_ICount-= 6; break;
+ case 0xc0: subb_im(); m6809_ICount-= 2; break;
+ case 0xc1: cmpb_im(); m6809_ICount-= 2; break;
+ case 0xc2: sbcb_im(); m6809_ICount-= 2; break;
+ case 0xc3: addd_im(); m6809_ICount-= 4; break;
+ case 0xc4: andb_im(); m6809_ICount-= 2; break;
+ case 0xc5: bitb_im(); m6809_ICount-= 2; break;
+ case 0xc6: ldb_im(); m6809_ICount-= 2; break;
+ case 0xc7: stb_im(); m6809_ICount-= 2; break;
+ case 0xc8: eorb_im(); m6809_ICount-= 2; break;
+ case 0xc9: adcb_im(); m6809_ICount-= 2; break;
+ case 0xca: orb_im(); m6809_ICount-= 2; break;
+ case 0xcb: addb_im(); m6809_ICount-= 2; break;
+ case 0xcc: ldd_im(); m6809_ICount-= 3; break;
+ case 0xcd: std_im(); m6809_ICount-= 2; break;
+ case 0xce: ldu_im(); m6809_ICount-= 3; break;
+ case 0xcf: stu_im(); m6809_ICount-= 3; break;
+ case 0xd0: subb_di(); m6809_ICount-= 4; break;
+ case 0xd1: cmpb_di(); m6809_ICount-= 4; break;
+ case 0xd2: sbcb_di(); m6809_ICount-= 4; break;
+ case 0xd3: addd_di(); m6809_ICount-= 6; break;
+ case 0xd4: andb_di(); m6809_ICount-= 4; break;
+ case 0xd5: bitb_di(); m6809_ICount-= 4; break;
+ case 0xd6: ldb_di(); m6809_ICount-= 4; break;
+ case 0xd7: stb_di(); m6809_ICount-= 4; break;
+ case 0xd8: eorb_di(); m6809_ICount-= 4; break;
+ case 0xd9: adcb_di(); m6809_ICount-= 4; break;
+ case 0xda: orb_di(); m6809_ICount-= 4; break;
+ case 0xdb: addb_di(); m6809_ICount-= 4; break;
+ case 0xdc: ldd_di(); m6809_ICount-= 5; break;
+ case 0xdd: std_di(); m6809_ICount-= 5; break;
+ case 0xde: ldu_di(); m6809_ICount-= 5; break;
+ case 0xdf: stu_di(); m6809_ICount-= 5; break;
+ case 0xe0: subb_ix(); m6809_ICount-= 4; break;
+ case 0xe1: cmpb_ix(); m6809_ICount-= 4; break;
+ case 0xe2: sbcb_ix(); m6809_ICount-= 4; break;
+ case 0xe3: addd_ix(); m6809_ICount-= 6; break;
+ case 0xe4: andb_ix(); m6809_ICount-= 4; break;
+ case 0xe5: bitb_ix(); m6809_ICount-= 4; break;
+ case 0xe6: ldb_ix(); m6809_ICount-= 4; break;
+ case 0xe7: stb_ix(); m6809_ICount-= 4; break;
+ case 0xe8: eorb_ix(); m6809_ICount-= 4; break;
+ case 0xe9: adcb_ix(); m6809_ICount-= 4; break;
+ case 0xea: orb_ix(); m6809_ICount-= 4; break;
+ case 0xeb: addb_ix(); m6809_ICount-= 4; break;
+ case 0xec: ldd_ix(); m6809_ICount-= 5; break;
+ case 0xed: std_ix(); m6809_ICount-= 5; break;
+ case 0xee: ldu_ix(); m6809_ICount-= 5; break;
+ case 0xef: stu_ix(); m6809_ICount-= 5; break;
+ case 0xf0: subb_ex(); m6809_ICount-= 5; break;
+ case 0xf1: cmpb_ex(); m6809_ICount-= 5; break;
+ case 0xf2: sbcb_ex(); m6809_ICount-= 5; break;
+ case 0xf3: addd_ex(); m6809_ICount-= 7; break;
+ case 0xf4: andb_ex(); m6809_ICount-= 5; break;
+ case 0xf5: bitb_ex(); m6809_ICount-= 5; break;
+ case 0xf6: ldb_ex(); m6809_ICount-= 5; break;
+ case 0xf7: stb_ex(); m6809_ICount-= 5; break;
+ case 0xf8: eorb_ex(); m6809_ICount-= 5; break;
+ case 0xf9: adcb_ex(); m6809_ICount-= 5; break;
+ case 0xfa: orb_ex(); m6809_ICount-= 5; break;
+ case 0xfb: addb_ex(); m6809_ICount-= 5; break;
+ case 0xfc: ldd_ex(); m6809_ICount-= 6; break;
+ case 0xfd: std_ex(); m6809_ICount-= 6; break;
+ case 0xfe: ldu_ex(); m6809_ICount-= 6; break;
+ case 0xff: stu_ex(); m6809_ICount-= 6; break;
+ }
+#else
+ (*m6809_main[m6809.ireg])();
+ m6809_ICount -= cycles1[m6809.ireg];
+#endif
+
+ } while( m6809_ICount > 0 );
+
+ m6809_ICount -= m6809.extra_cycles;
+ m6809.extra_cycles = 0;
+ }
+
+ return cycles - m6809_ICount; /* NS 970908 */
+}
+
+INLINE void fetch_effective_address( void )
+{
+ UINT8 postbyte = ROP_ARG(PCD);
+ PC++;
+
+ switch(postbyte)
+ {
+ case 0x00: EA=X; m6809_ICount-=1; break;
+ case 0x01: EA=X+1; m6809_ICount-=1; break;
+ case 0x02: EA=X+2; m6809_ICount-=1; break;
+ case 0x03: EA=X+3; m6809_ICount-=1; break;
+ case 0x04: EA=X+4; m6809_ICount-=1; break;
+ case 0x05: EA=X+5; m6809_ICount-=1; break;
+ case 0x06: EA=X+6; m6809_ICount-=1; break;
+ case 0x07: EA=X+7; m6809_ICount-=1; break;
+ case 0x08: EA=X+8; m6809_ICount-=1; break;
+ case 0x09: EA=X+9; m6809_ICount-=1; break;
+ case 0x0a: EA=X+10; m6809_ICount-=1; break;
+ case 0x0b: EA=X+11; m6809_ICount-=1; break;
+ case 0x0c: EA=X+12; m6809_ICount-=1; break;
+ case 0x0d: EA=X+13; m6809_ICount-=1; break;
+ case 0x0e: EA=X+14; m6809_ICount-=1; break;
+ case 0x0f: EA=X+15; m6809_ICount-=1; break;
+
+ case 0x10: EA=X-16; m6809_ICount-=1; break;
+ case 0x11: EA=X-15; m6809_ICount-=1; break;
+ case 0x12: EA=X-14; m6809_ICount-=1; break;
+ case 0x13: EA=X-13; m6809_ICount-=1; break;
+ case 0x14: EA=X-12; m6809_ICount-=1; break;
+ case 0x15: EA=X-11; m6809_ICount-=1; break;
+ case 0x16: EA=X-10; m6809_ICount-=1; break;
+ case 0x17: EA=X-9; m6809_ICount-=1; break;
+ case 0x18: EA=X-8; m6809_ICount-=1; break;
+ case 0x19: EA=X-7; m6809_ICount-=1; break;
+ case 0x1a: EA=X-6; m6809_ICount-=1; break;
+ case 0x1b: EA=X-5; m6809_ICount-=1; break;
+ case 0x1c: EA=X-4; m6809_ICount-=1; break;
+ case 0x1d: EA=X-3; m6809_ICount-=1; break;
+ case 0x1e: EA=X-2; m6809_ICount-=1; break;
+ case 0x1f: EA=X-1; m6809_ICount-=1; break;
+
+ case 0x20: EA=Y; m6809_ICount-=1; break;
+ case 0x21: EA=Y+1; m6809_ICount-=1; break;
+ case 0x22: EA=Y+2; m6809_ICount-=1; break;
+ case 0x23: EA=Y+3; m6809_ICount-=1; break;
+ case 0x24: EA=Y+4; m6809_ICount-=1; break;
+ case 0x25: EA=Y+5; m6809_ICount-=1; break;
+ case 0x26: EA=Y+6; m6809_ICount-=1; break;
+ case 0x27: EA=Y+7; m6809_ICount-=1; break;
+ case 0x28: EA=Y+8; m6809_ICount-=1; break;
+ case 0x29: EA=Y+9; m6809_ICount-=1; break;
+ case 0x2a: EA=Y+10; m6809_ICount-=1; break;
+ case 0x2b: EA=Y+11; m6809_ICount-=1; break;
+ case 0x2c: EA=Y+12; m6809_ICount-=1; break;
+ case 0x2d: EA=Y+13; m6809_ICount-=1; break;
+ case 0x2e: EA=Y+14; m6809_ICount-=1; break;
+ case 0x2f: EA=Y+15; m6809_ICount-=1; break;
+
+ case 0x30: EA=Y-16; m6809_ICount-=1; break;
+ case 0x31: EA=Y-15; m6809_ICount-=1; break;
+ case 0x32: EA=Y-14; m6809_ICount-=1; break;
+ case 0x33: EA=Y-13; m6809_ICount-=1; break;
+ case 0x34: EA=Y-12; m6809_ICount-=1; break;
+ case 0x35: EA=Y-11; m6809_ICount-=1; break;
+ case 0x36: EA=Y-10; m6809_ICount-=1; break;
+ case 0x37: EA=Y-9; m6809_ICount-=1; break;
+ case 0x38: EA=Y-8; m6809_ICount-=1; break;
+ case 0x39: EA=Y-7; m6809_ICount-=1; break;
+ case 0x3a: EA=Y-6; m6809_ICount-=1; break;
+ case 0x3b: EA=Y-5; m6809_ICount-=1; break;
+ case 0x3c: EA=Y-4; m6809_ICount-=1; break;
+ case 0x3d: EA=Y-3; m6809_ICount-=1; break;
+ case 0x3e: EA=Y-2; m6809_ICount-=1; break;
+ case 0x3f: EA=Y-1; m6809_ICount-=1; break;
+
+ case 0x40: EA=U; m6809_ICount-=1; break;
+ case 0x41: EA=U+1; m6809_ICount-=1; break;
+ case 0x42: EA=U+2; m6809_ICount-=1; break;
+ case 0x43: EA=U+3; m6809_ICount-=1; break;
+ case 0x44: EA=U+4; m6809_ICount-=1; break;
+ case 0x45: EA=U+5; m6809_ICount-=1; break;
+ case 0x46: EA=U+6; m6809_ICount-=1; break;
+ case 0x47: EA=U+7; m6809_ICount-=1; break;
+ case 0x48: EA=U+8; m6809_ICount-=1; break;
+ case 0x49: EA=U+9; m6809_ICount-=1; break;
+ case 0x4a: EA=U+10; m6809_ICount-=1; break;
+ case 0x4b: EA=U+11; m6809_ICount-=1; break;
+ case 0x4c: EA=U+12; m6809_ICount-=1; break;
+ case 0x4d: EA=U+13; m6809_ICount-=1; break;
+ case 0x4e: EA=U+14; m6809_ICount-=1; break;
+ case 0x4f: EA=U+15; m6809_ICount-=1; break;
+
+ case 0x50: EA=U-16; m6809_ICount-=1; break;
+ case 0x51: EA=U-15; m6809_ICount-=1; break;
+ case 0x52: EA=U-14; m6809_ICount-=1; break;
+ case 0x53: EA=U-13; m6809_ICount-=1; break;
+ case 0x54: EA=U-12; m6809_ICount-=1; break;
+ case 0x55: EA=U-11; m6809_ICount-=1; break;
+ case 0x56: EA=U-10; m6809_ICount-=1; break;
+ case 0x57: EA=U-9; m6809_ICount-=1; break;
+ case 0x58: EA=U-8; m6809_ICount-=1; break;
+ case 0x59: EA=U-7; m6809_ICount-=1; break;
+ case 0x5a: EA=U-6; m6809_ICount-=1; break;
+ case 0x5b: EA=U-5; m6809_ICount-=1; break;
+ case 0x5c: EA=U-4; m6809_ICount-=1; break;
+ case 0x5d: EA=U-3; m6809_ICount-=1; break;
+ case 0x5e: EA=U-2; m6809_ICount-=1; break;
+ case 0x5f: EA=U-1; m6809_ICount-=1; break;
+
+ case 0x60: EA=S; m6809_ICount-=1; break;
+ case 0x61: EA=S+1; m6809_ICount-=1; break;
+ case 0x62: EA=S+2; m6809_ICount-=1; break;
+ case 0x63: EA=S+3; m6809_ICount-=1; break;
+ case 0x64: EA=S+4; m6809_ICount-=1; break;
+ case 0x65: EA=S+5; m6809_ICount-=1; break;
+ case 0x66: EA=S+6; m6809_ICount-=1; break;
+ case 0x67: EA=S+7; m6809_ICount-=1; break;
+ case 0x68: EA=S+8; m6809_ICount-=1; break;
+ case 0x69: EA=S+9; m6809_ICount-=1; break;
+ case 0x6a: EA=S+10; m6809_ICount-=1; break;
+ case 0x6b: EA=S+11; m6809_ICount-=1; break;
+ case 0x6c: EA=S+12; m6809_ICount-=1; break;
+ case 0x6d: EA=S+13; m6809_ICount-=1; break;
+ case 0x6e: EA=S+14; m6809_ICount-=1; break;
+ case 0x6f: EA=S+15; m6809_ICount-=1; break;
+
+ case 0x70: EA=S-16; m6809_ICount-=1; break;
+ case 0x71: EA=S-15; m6809_ICount-=1; break;
+ case 0x72: EA=S-14; m6809_ICount-=1; break;
+ case 0x73: EA=S-13; m6809_ICount-=1; break;
+ case 0x74: EA=S-12; m6809_ICount-=1; break;
+ case 0x75: EA=S-11; m6809_ICount-=1; break;
+ case 0x76: EA=S-10; m6809_ICount-=1; break;
+ case 0x77: EA=S-9; m6809_ICount-=1; break;
+ case 0x78: EA=S-8; m6809_ICount-=1; break;
+ case 0x79: EA=S-7; m6809_ICount-=1; break;
+ case 0x7a: EA=S-6; m6809_ICount-=1; break;
+ case 0x7b: EA=S-5; m6809_ICount-=1; break;
+ case 0x7c: EA=S-4; m6809_ICount-=1; break;
+ case 0x7d: EA=S-3; m6809_ICount-=1; break;
+ case 0x7e: EA=S-2; m6809_ICount-=1; break;
+ case 0x7f: EA=S-1; m6809_ICount-=1; break;
+
+ case 0x80: EA=X; X++; m6809_ICount-=2; break;
+ case 0x81: EA=X; X+=2; m6809_ICount-=3; break;
+ case 0x82: X--; EA=X; m6809_ICount-=2; break;
+ case 0x83: X-=2; EA=X; m6809_ICount-=3; break;
+ case 0x84: EA=X; break;
+ case 0x85: EA=X+SIGNED(B); m6809_ICount-=1; break;
+ case 0x86: EA=X+SIGNED(A); m6809_ICount-=1; break;
+ case 0x87: EA=0; break; /* ILLEGAL*/
+ case 0x88: IMMBYTE(EA); EA=X+SIGNED(EA); m6809_ICount-=1; break; /* this is a hack to make Vectrex work. It should be m6809_ICount-=1. Dunno where the cycle was lost :( */
+ case 0x89: IMMWORD(ea); EA+=X; m6809_ICount-=4; break;
+ case 0x8a: EA=0; break; /* ILLEGAL*/
+ case 0x8b: EA=X+D; m6809_ICount-=4; break;
+ case 0x8c: IMMBYTE(EA); EA=PC+SIGNED(EA); m6809_ICount-=1; break;
+ case 0x8d: IMMWORD(ea); EA+=PC; m6809_ICount-=5; break;
+ case 0x8e: EA=0; break; /* ILLEGAL*/
+ case 0x8f: IMMWORD(ea); m6809_ICount-=5; break;
+
+ case 0x90: EA=X; X++; EAD=RM16(EAD); m6809_ICount-=5; break; /* Indirect ,R+ not in my specs */
+ case 0x91: EA=X; X+=2; EAD=RM16(EAD); m6809_ICount-=6; break;
+ case 0x92: X--; EA=X; EAD=RM16(EAD); m6809_ICount-=5; break;
+ case 0x93: X-=2; EA=X; EAD=RM16(EAD); m6809_ICount-=6; break;
+ case 0x94: EA=X; EAD=RM16(EAD); m6809_ICount-=3; break;
+ case 0x95: EA=X+SIGNED(B); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0x96: EA=X+SIGNED(A); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0x97: EA=0; break; /* ILLEGAL*/
+ case 0x98: IMMBYTE(EA); EA=X+SIGNED(EA); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0x99: IMMWORD(ea); EA+=X; EAD=RM16(EAD); m6809_ICount-=7; break;
+ case 0x9a: EA=0; break; /* ILLEGAL*/
+ case 0x9b: EA=X+D; EAD=RM16(EAD); m6809_ICount-=7; break;
+ case 0x9c: IMMBYTE(EA); EA=PC+SIGNED(EA); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0x9d: IMMWORD(ea); EA+=PC; EAD=RM16(EAD); m6809_ICount-=8; break;
+ case 0x9e: EA=0; break; /* ILLEGAL*/
+ case 0x9f: IMMWORD(ea); EAD=RM16(EAD); m6809_ICount-=8; break;
+
+ case 0xa0: EA=Y; Y++; m6809_ICount-=2; break;
+ case 0xa1: EA=Y; Y+=2; m6809_ICount-=3; break;
+ case 0xa2: Y--; EA=Y; m6809_ICount-=2; break;
+ case 0xa3: Y-=2; EA=Y; m6809_ICount-=3; break;
+ case 0xa4: EA=Y; break;
+ case 0xa5: EA=Y+SIGNED(B); m6809_ICount-=1; break;
+ case 0xa6: EA=Y+SIGNED(A); m6809_ICount-=1; break;
+ case 0xa7: EA=0; break; /* ILLEGAL*/
+ case 0xa8: IMMBYTE(EA); EA=Y+SIGNED(EA); m6809_ICount-=1; break;
+ case 0xa9: IMMWORD(ea); EA+=Y; m6809_ICount-=4; break;
+ case 0xaa: EA=0; break; /* ILLEGAL*/
+ case 0xab: EA=Y+D; m6809_ICount-=4; break;
+ case 0xac: IMMBYTE(EA); EA=PC+SIGNED(EA); m6809_ICount-=1; break;
+ case 0xad: IMMWORD(ea); EA+=PC; m6809_ICount-=5; break;
+ case 0xae: EA=0; break; /* ILLEGAL*/
+ case 0xaf: IMMWORD(ea); m6809_ICount-=5; break;
+
+ case 0xb0: EA=Y; Y++; EAD=RM16(EAD); m6809_ICount-=5; break;
+ case 0xb1: EA=Y; Y+=2; EAD=RM16(EAD); m6809_ICount-=6; break;
+ case 0xb2: Y--; EA=Y; EAD=RM16(EAD); m6809_ICount-=5; break;
+ case 0xb3: Y-=2; EA=Y; EAD=RM16(EAD); m6809_ICount-=6; break;
+ case 0xb4: EA=Y; EAD=RM16(EAD); m6809_ICount-=3; break;
+ case 0xb5: EA=Y+SIGNED(B); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xb6: EA=Y+SIGNED(A); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xb7: EA=0; break; /* ILLEGAL*/
+ case 0xb8: IMMBYTE(EA); EA=Y+SIGNED(EA); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xb9: IMMWORD(ea); EA+=Y; EAD=RM16(EAD); m6809_ICount-=7; break;
+ case 0xba: EA=0; break; /* ILLEGAL*/
+ case 0xbb: EA=Y+D; EAD=RM16(EAD); m6809_ICount-=7; break;
+ case 0xbc: IMMBYTE(EA); EA=PC+SIGNED(EA); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xbd: IMMWORD(ea); EA+=PC; EAD=RM16(EAD); m6809_ICount-=8; break;
+ case 0xbe: EA=0; break; /* ILLEGAL*/
+ case 0xbf: IMMWORD(ea); EAD=RM16(EAD); m6809_ICount-=8; break;
+
+ case 0xc0: EA=U; U++; m6809_ICount-=2; break;
+ case 0xc1: EA=U; U+=2; m6809_ICount-=3; break;
+ case 0xc2: U--; EA=U; m6809_ICount-=2; break;
+ case 0xc3: U-=2; EA=U; m6809_ICount-=3; break;
+ case 0xc4: EA=U; break;
+ case 0xc5: EA=U+SIGNED(B); m6809_ICount-=1; break;
+ case 0xc6: EA=U+SIGNED(A); m6809_ICount-=1; break;
+ case 0xc7: EA=0; break; /*ILLEGAL*/
+ case 0xc8: IMMBYTE(EA); EA=U+SIGNED(EA); m6809_ICount-=1; break;
+ case 0xc9: IMMWORD(ea); EA+=U; m6809_ICount-=4; break;
+ case 0xca: EA=0; break; /*ILLEGAL*/
+ case 0xcb: EA=U+D; m6809_ICount-=4; break;
+ case 0xcc: IMMBYTE(EA); EA=PC+SIGNED(EA); m6809_ICount-=1; break;
+ case 0xcd: IMMWORD(ea); EA+=PC; m6809_ICount-=5; break;
+ case 0xce: EA=0; break; /*ILLEGAL*/
+ case 0xcf: IMMWORD(ea); m6809_ICount-=5; break;
+
+ case 0xd0: EA=U; U++; EAD=RM16(EAD); m6809_ICount-=5; break;
+ case 0xd1: EA=U; U+=2; EAD=RM16(EAD); m6809_ICount-=6; break;
+ case 0xd2: U--; EA=U; EAD=RM16(EAD); m6809_ICount-=5; break;
+ case 0xd3: U-=2; EA=U; EAD=RM16(EAD); m6809_ICount-=6; break;
+ case 0xd4: EA=U; EAD=RM16(EAD); m6809_ICount-=3; break;
+ case 0xd5: EA=U+SIGNED(B); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xd6: EA=U+SIGNED(A); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xd7: EA=0; break; /*ILLEGAL*/
+ case 0xd8: IMMBYTE(EA); EA=U+SIGNED(EA); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xd9: IMMWORD(ea); EA+=U; EAD=RM16(EAD); m6809_ICount-=7; break;
+ case 0xda: EA=0; break; /*ILLEGAL*/
+ case 0xdb: EA=U+D; EAD=RM16(EAD); m6809_ICount-=7; break;
+ case 0xdc: IMMBYTE(EA); EA=PC+SIGNED(EA); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xdd: IMMWORD(ea); EA+=PC; EAD=RM16(EAD); m6809_ICount-=8; break;
+ case 0xde: EA=0; break; /*ILLEGAL*/
+ case 0xdf: IMMWORD(ea); EAD=RM16(EAD); m6809_ICount-=8; break;
+
+ case 0xe0: EA=S; S++; m6809_ICount-=2; break;
+ case 0xe1: EA=S; S+=2; m6809_ICount-=3; break;
+ case 0xe2: S--; EA=S; m6809_ICount-=2; break;
+ case 0xe3: S-=2; EA=S; m6809_ICount-=3; break;
+ case 0xe4: EA=S; break;
+ case 0xe5: EA=S+SIGNED(B); m6809_ICount-=1; break;
+ case 0xe6: EA=S+SIGNED(A); m6809_ICount-=1; break;
+ case 0xe7: EA=0; break; /*ILLEGAL*/
+ case 0xe8: IMMBYTE(EA); EA=S+SIGNED(EA); m6809_ICount-=1; break;
+ case 0xe9: IMMWORD(ea); EA+=S; m6809_ICount-=4; break;
+ case 0xea: EA=0; break; /*ILLEGAL*/
+ case 0xeb: EA=S+D; m6809_ICount-=4; break;
+ case 0xec: IMMBYTE(EA); EA=PC+SIGNED(EA); m6809_ICount-=1; break;
+ case 0xed: IMMWORD(ea); EA+=PC; m6809_ICount-=5; break;
+ case 0xee: EA=0; break; /*ILLEGAL*/
+ case 0xef: IMMWORD(ea); m6809_ICount-=5; break;
+
+ case 0xf0: EA=S; S++; EAD=RM16(EAD); m6809_ICount-=5; break;
+ case 0xf1: EA=S; S+=2; EAD=RM16(EAD); m6809_ICount-=6; break;
+ case 0xf2: S--; EA=S; EAD=RM16(EAD); m6809_ICount-=5; break;
+ case 0xf3: S-=2; EA=S; EAD=RM16(EAD); m6809_ICount-=6; break;
+ case 0xf4: EA=S; EAD=RM16(EAD); m6809_ICount-=3; break;
+ case 0xf5: EA=S+SIGNED(B); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xf6: EA=S+SIGNED(A); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xf7: EA=0; break; /*ILLEGAL*/
+ case 0xf8: IMMBYTE(EA); EA=S+SIGNED(EA); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xf9: IMMWORD(ea); EA+=S; EAD=RM16(EAD); m6809_ICount-=7; break;
+ case 0xfa: EA=0; break; /*ILLEGAL*/
+ case 0xfb: EA=S+D; EAD=RM16(EAD); m6809_ICount-=7; break;
+ case 0xfc: IMMBYTE(EA); EA=PC+SIGNED(EA); EAD=RM16(EAD); m6809_ICount-=4; break;
+ case 0xfd: IMMWORD(ea); EA+=PC; EAD=RM16(EAD); m6809_ICount-=8; break;
+ case 0xfe: EA=0; break; /*ILLEGAL*/
+ case 0xff: IMMWORD(ea); EAD=RM16(EAD); m6809_ICount-=8; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void m6809_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M6809_IRQ_LINE: set_irq_line(M6809_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M6809_FIRQ_LINE: set_irq_line(M6809_FIRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + M6809_PC: PC = info->i; CHANGE_PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M6809_S: S = info->i; break;
+ case CPUINFO_INT_REGISTER + M6809_CC: CC = info->i; CHECK_IRQ_LINES; break;
+ case CPUINFO_INT_REGISTER + M6809_U: U = info->i; break;
+ case CPUINFO_INT_REGISTER + M6809_A: A = info->i; break;
+ case CPUINFO_INT_REGISTER + M6809_B: B = info->i; break;
+ case CPUINFO_INT_REGISTER + M6809_X: X = info->i; break;
+ case CPUINFO_INT_REGISTER + M6809_Y: Y = info->i; break;
+ case CPUINFO_INT_REGISTER + M6809_DP: DP = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void m6809_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(m6809); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 19; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + M6809_IRQ_LINE: info->i = m6809.irq_state[M6809_IRQ_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + M6809_FIRQ_LINE: info->i = m6809.irq_state[M6809_FIRQ_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = m6809.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + M6809_PC: info->i = PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + M6809_S: info->i = S; break;
+ case CPUINFO_INT_REGISTER + M6809_CC: info->i = CC; break;
+ case CPUINFO_INT_REGISTER + M6809_U: info->i = U; break;
+ case CPUINFO_INT_REGISTER + M6809_A: info->i = A; break;
+ case CPUINFO_INT_REGISTER + M6809_B: info->i = B; break;
+ case CPUINFO_INT_REGISTER + M6809_X: info->i = X; break;
+ case CPUINFO_INT_REGISTER + M6809_Y: info->i = Y; break;
+ case CPUINFO_INT_REGISTER + M6809_DP: info->i = DP; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = m6809_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = m6809_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = m6809_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = m6809_init; break;
+ case CPUINFO_PTR_RESET: info->reset = m6809_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = m6809_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = m6809_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = m6809_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &m6809_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6809"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola 6809"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.11"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) John Butler 1997"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ m6809.cc & 0x80 ? 'E':'.',
+ m6809.cc & 0x40 ? 'F':'.',
+ m6809.cc & 0x20 ? 'H':'.',
+ m6809.cc & 0x10 ? 'I':'.',
+ m6809.cc & 0x08 ? 'N':'.',
+ m6809.cc & 0x04 ? 'Z':'.',
+ m6809.cc & 0x02 ? 'V':'.',
+ m6809.cc & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M6809_PC: sprintf(info->s, "PC:%04X", m6809.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + M6809_S: sprintf(info->s, "S:%04X", m6809.s.w.l); break;
+ case CPUINFO_STR_REGISTER + M6809_CC: sprintf(info->s, "CC:%02X", m6809.cc); break;
+ case CPUINFO_STR_REGISTER + M6809_U: sprintf(info->s, "U:%04X", m6809.u.w.l); break;
+ case CPUINFO_STR_REGISTER + M6809_A: sprintf(info->s, "A:%02X", m6809.d.b.h); break;
+ case CPUINFO_STR_REGISTER + M6809_B: sprintf(info->s, "B:%02X", m6809.d.b.l); break;
+ case CPUINFO_STR_REGISTER + M6809_X: sprintf(info->s, "X:%04X", m6809.x.w.l); break;
+ case CPUINFO_STR_REGISTER + M6809_Y: sprintf(info->s, "Y:%04X", m6809.y.w.l); break;
+ case CPUINFO_STR_REGISTER + M6809_DP: sprintf(info->s, "DP:%02X", m6809.dp.b.h); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void m6809e_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 4; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "M6809E"); break;
+
+ default: m6809_get_info(state, info); break;
+ }
+}
diff --git a/src/emu/cpu/m6809/m6809.h b/src/emu/cpu/m6809/m6809.h
new file mode 100644
index 00000000000..9dcaccd9e88
--- /dev/null
+++ b/src/emu/cpu/m6809/m6809.h
@@ -0,0 +1,50 @@
+/*** m6809: Portable 6809 emulator ******************************************/
+
+#ifndef _M6809_H
+#define _M6809_H
+
+#include "cpuintrf.h"
+
+enum {
+ M6809_PC=1, M6809_S, M6809_CC ,M6809_A, M6809_B, M6809_U, M6809_X, M6809_Y,
+ M6809_DP };
+
+#define M6809_IRQ_LINE 0 /* IRQ line number */
+#define M6809_FIRQ_LINE 1 /* FIRQ line number */
+
+void m6809_get_info(UINT32 state, cpuinfo *info);
+void m6809e_get_info(UINT32 state, cpuinfo *info);
+
+/****************************************************************************/
+/* Read a byte from given memory location */
+/****************************************************************************/
+/* ASG 971005 -- changed to program_read_byte_8/cpu_writemem16 */
+#define M6809_RDMEM(Addr) ((unsigned)program_read_byte_8(Addr))
+
+/****************************************************************************/
+/* Write a byte to given memory location */
+/****************************************************************************/
+#define M6809_WRMEM(Addr,Value) (program_write_byte_8(Addr,Value))
+
+/****************************************************************************/
+/* Z80_RDOP() is identical to Z80_RDMEM() except it is used for reading */
+/* opcodes. In case of system with memory mapped I/O, this function can be */
+/* used to greatly speed up emulation */
+/****************************************************************************/
+#define M6809_RDOP(Addr) ((unsigned)cpu_readop(Addr))
+
+/****************************************************************************/
+/* Z80_RDOP_ARG() is identical to Z80_RDOP() except it is used for reading */
+/* opcode arguments. This difference can be used to support systems that */
+/* use different encoding mechanisms for opcodes and opcode arguments */
+/****************************************************************************/
+#define M6809_RDOP_ARG(Addr) ((unsigned)cpu_readop_arg(Addr))
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE (!FALSE)
+#endif
+
+#endif /* _M6809_H */
diff --git a/src/emu/cpu/mb86233/mb86233.c b/src/emu/cpu/mb86233/mb86233.c
new file mode 100644
index 00000000000..a7582958002
--- /dev/null
+++ b/src/emu/cpu/mb86233/mb86233.c
@@ -0,0 +1,1690 @@
+/***************************************************************************
+
+ mb86233.c
+ Core implementation for the portable Fujitsu MB86233 series DSP emulator.
+
+ Written by ElSemi
+ MAME version by Ernesto Corvi
+
+ TODO:
+ - Properly emulate the TGP Tables from the ROM (See GETEXTERNAL)
+ - Many unknown opcodes and addressing modes
+ - Interrupts?
+
+***************************************************************************/
+
+#include "mb86233.h"
+#include "debugger.h"
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+typedef union
+{
+ INT32 i;
+ UINT32 u;
+ float f;
+} MB86233_REG;
+
+typedef struct
+{
+ UINT16 pc;
+ MB86233_REG a;
+ MB86233_REG b;
+ MB86233_REG d;
+ MB86233_REG p;
+
+ UINT16 reps;
+ UINT16 pcs[4];
+ UINT8 pcsp;
+ UINT32 eb;
+ UINT32 shift;
+ UINT32 repcnt;
+ UINT16 sr;
+
+ UINT32 gpr[16];
+ UINT32 extport[0x30];
+
+ /* FIFO */
+ int fifo_wait;
+ int (*fifo_read_cb)( UINT32 *data );
+ void (*fifo_write_cb)( UINT32 data );
+
+ /* internal RAM */
+ UINT32 *RAM;
+ UINT32 *ARAM, *BRAM;
+} MB86233_REGS;
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static MB86233_REGS mb86233;
+static int mb86233_icount;
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define GETPC() mb86233.pc
+#define GETA() mb86233.a
+#define GETB() mb86233.b
+#define GETD() mb86233.d
+#define GETP() mb86233.p
+#define GETSR() mb86233.sr
+#define GETGPR(a) mb86233.gpr[a]
+#define GETSHIFT() mb86233.shift
+#define GETPCS() mb86233.pcs
+#define GETPCSP() mb86233.pcsp
+#define GETEB() mb86233.eb
+#define GETREPS() mb86233.reps
+#define GETEXTPORT() mb86233.extport
+#define GETFIFOWAIT() mb86233.fifo_wait
+#define GETARAM() mb86233.ARAM
+#define GETBRAM() mb86233.BRAM
+#define ALU(a) mb86233_alu(a)
+#define GETREPCNT() mb86233.repcnt
+
+#define ROPCODE(a) cpu_readop32(a<<2)
+#define RDMEM(a) program_read_dword_32le((a<<2))
+#define WRMEM(a,v) program_write_dword_32le((a<<2),v)
+
+/***************************************************************************
+ Context Switching
+***************************************************************************/
+
+static void mb86233_get_context(void *dst)
+{
+ /* copy the context */
+ *(MB86233_REGS *)dst = mb86233;
+}
+
+static void mb86233_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ mb86233 = *(MB86233_REGS *)src;
+ change_pc(GETPC());
+}
+
+
+/***************************************************************************
+ Initialization and Shutdown
+***************************************************************************/
+
+static void mb86233_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ struct mb86233_config * _config = (struct mb86233_config *)config;
+ (void)index;
+ (void)clock;
+ (void)irqcallback;
+
+ memset(&mb86233, 0, sizeof( MB86233_REGS ) );
+
+ if ( _config )
+ {
+ mb86233.fifo_read_cb = _config->fifo_read_cb;
+ mb86233.fifo_write_cb = _config->fifo_write_cb;
+ }
+
+ mb86233.RAM = auto_malloc(2 * 0x200 * sizeof(UINT32)); /* 2x 2KB */
+ memset( mb86233.RAM, 0, 2 * 0x200 * sizeof(UINT32) );
+ mb86233.ARAM = &mb86233.RAM[0];
+ mb86233.BRAM = &mb86233.RAM[0x200];
+
+ state_save_register_global_pointer(mb86233.RAM,2 * 0x200 * sizeof(UINT32));
+}
+
+static void mb86233_reset(void)
+{
+ /* zero registers and flags */
+ mb86233.pc = 0;
+ mb86233.sr = 0;
+ mb86233.pcsp = 0;
+ mb86233.eb = 0;
+ mb86233.shift = 0;
+ mb86233.fifo_wait = 0;
+}
+
+
+
+/***************************************************************************
+ Status Register
+***************************************************************************/
+
+#define ZERO_FLAG (1 << 0)
+#define SIGN_FLAG (1 << 1)
+
+static void FLAGSF( float v )
+{
+ GETSR() = 0;
+
+ if ( v == 0 )
+ GETSR() |= ZERO_FLAG;
+
+ if ( v < 0 )
+ GETSR() |= SIGN_FLAG;
+}
+
+static void FLAGSI( UINT32 v )
+{
+ GETSR() = 0;
+
+ if ( v == 0 )
+ GETSR() |= ZERO_FLAG;
+
+ if ( v & 0x80000000 )
+ GETSR() |= SIGN_FLAG;
+}
+
+
+
+/***************************************************************************
+ Condition Codes
+***************************************************************************/
+
+static int COND( UINT32 cond )
+{
+ switch( cond )
+ {
+ case 0x00: /* eq */
+ if ( (GETSR() & ZERO_FLAG) ) return 1;
+ break;
+
+ case 0x01: /* ge */
+ if ( (GETSR() & ZERO_FLAG) || ((GETSR() & SIGN_FLAG)==0) ) return 1;
+ break;
+
+ case 0x02: /* le */
+ if ( (GETSR() & ZERO_FLAG) || (GETSR() & SIGN_FLAG) ) return 1;
+ break;
+
+ case 0x06: /* never */
+ break;
+
+ case 0x10: /* --r12 != 0 */
+ GETGPR(12)--;
+ if ( GETGPR(12) != 0 ) return 1;
+ break;
+
+ case 0x11: /* --r13 != 0 */
+ GETGPR(13)--;
+ if ( GETGPR(13) != 0 ) return 1;
+ break;
+
+ case 0x16: /* always */
+ return 1;
+ break;
+
+ default:
+ logerror( "TGP: Unknown condition code (cc=%d) at PC:%x\n", cond, GETPC());
+ break;
+ }
+
+ return 0;
+}
+
+
+
+/***************************************************************************
+ ALU
+***************************************************************************/
+
+static void ALU( UINT32 alu)
+{
+ float ftmp;
+
+ switch(alu)
+ {
+ case 0x00: /* NOP */
+ break;
+
+ case 0x01: /* D = D & A */
+ GETD().u &= GETA().u;
+ FLAGSI(GETD().u);
+ break;
+
+ case 0x02: /* D = D | A */
+ GETD().u |= GETA().u;
+ FLAGSI(GETD().u);
+ break;
+
+ case 0x03: /* D = D ^ A */
+ GETD().u ^= GETA().u;
+ FLAGSI(GETD().u);
+ break;
+
+ case 0x05: /* CMP D,A */
+ ftmp = GETD().f - GETA().f;
+ FLAGSF(ftmp);
+ mb86233_icount--;
+ break;
+
+ case 0x06: /* D = D + A */
+ GETD().f += GETA().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x07: /* D = D - A */
+ GETD().f -= GETA().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x08: /* P = A * B */
+ GETP().f = GETA().f * GETB().f;
+ mb86233_icount--;
+ break;
+
+ case 0x09: /* D = D + P; P = A * B */
+ GETD().f += GETP().f;
+ GETP().f = GETA().f * GETB().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x0A: /* D = D - P; P = A * B */
+ GETD().f -= GETP().f;
+ GETP().f = GETA().f * GETB().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x0B: /* D = fabs(D) */
+ GETD().f = fabs( GETD().f );
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x0C: /* D = D + P */
+ GETD().f += GETP().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x0D: /* D = P; P = A * B */
+ GETD().f = GETP().f;
+ GETP().f = GETA().f * GETB().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x0E: /* D = float(D) */
+ GETD().f = (float)GETD().i;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x0F: /* D = int(D) */
+ GETD().i = (INT32)GETD().f;
+ FLAGSI(GETD().u);
+ break;
+
+ case 0x10: /* D = D / A */
+ if ( GETA().u != 0 )
+ GETD().f = GETD().f / GETA().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x11: /* D = -D */
+ GETD().f = -GETD().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x13: /* D = A + B */
+ GETD().f = GETA().f + GETB().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x14: /* D = B - A */
+ GETD().f = GETB().f - GETA().f;
+ FLAGSF(GETD().f);
+ mb86233_icount--;
+ break;
+
+ case 0x16: /* LSR D, SHIFT */
+ GETD().u >>= GETSHIFT();
+ FLAGSI(GETD().u);
+ break;
+
+ case 0x17: /* LSL D, SHIFT */
+ GETD().u <<= GETSHIFT();
+ FLAGSI(GETD().u);
+ break;
+
+ case 0x18: /* ASR D, SHIFT */
+// GETD().u = (GETD().u & 0x80000000) | (GETD().u >> GETSHIFT());
+ GETD().i >>= GETSHIFT();
+ FLAGSI(GETD().u);
+ break;
+
+ case 0x1A: /* D = D + A */
+ GETD().i += GETA().i;
+ FLAGSI(GETD().u);
+ break;
+
+ case 0x1B: /* D = D - A */
+ GETD().i -= GETA().i;
+ FLAGSI(GETD().u);
+ break;
+
+ default:
+ logerror( "TGP: Unknown ALU op %x at PC:%04x\n", alu, GETPC() );
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ Memory Access
+***************************************************************************/
+
+static UINT32 GETEXTERNAL( UINT32 EB, UINT32 offset )
+{
+ UINT32 addr;
+
+ if ( EB == 0 && offset >= 0x20 && offset <= 0x2f ) /* TGP Tables in ROM - FIXME - */
+ {
+ if ( offset == 0x20 ) /* SIN from value at RAM(0x20) in 0x4000/PI steps */
+ {
+ MB86233_REG r;
+ INT32 a;
+
+ r.u = GETEXTPORT()[0x20];
+ a = r.i;
+ if ( a == 0 || a == -32768 )
+ r.f = 0;
+ else if ( a == 16384 )
+ r.f = 1.0;
+ else if ( a == -16384 )
+ r.f=-1.0;
+ else
+ r.f = (float)sin((float)a*(2.0*M_PI/65536.0));
+
+ return r.u;
+ }
+
+ if ( offset == 0x21 ) /* COS from value at RAM(0x20) in 0x4000/PI steps */
+ {
+ MB86233_REG r;
+ INT32 a;
+
+ r.u = GETEXTPORT()[0x20];
+ a = r.i;
+ if ( a == 16384 || a == -16384 )
+ r.f = 0;
+ else if ( a == 0 )
+ r.f = 1.0;
+ else if ( a == -32768 )
+ r.f = -1.0;
+ else
+ r.f = (float)cos((float)a*(2.0*M_PI/65536.0));
+
+ return r.u;
+ }
+
+#if 0
+ if ( offset == 0x22 ) /* -SIN from value at RAM(0x20) in 0x4000/PI steps */
+ {
+ MB86233_REG r;
+ INT32 a;
+
+ r.u = GETEXTPORT()[0x20];
+ a = r.i;
+ r.f = (float)-sin((float)a*(2.0*M_PI/65536.0));
+ return r.u;
+ }
+#endif
+
+ if ( offset == 0x27 ) /* atan */
+ {
+ MB86233_REG r1, r2;
+
+ r1.u = GETEXTPORT()[0x24]; /* A */
+ r2.u = GETEXTPORT()[0x25]; /* B */
+
+ if ( r2.f == 0 )
+ {
+ if ( r1.f >= 0 )
+ GETEXTPORT()[0x27] = 0;
+ else
+ GETEXTPORT()[0x27] = 0xFFFF8000;
+ }
+ else if ( r1.f == 0 )
+ {
+ if ( r2.f >= 0 )
+ GETEXTPORT()[0x27] = 0x4000;
+ else
+ GETEXTPORT()[0x27] = 0xFFFFC000;
+ }
+ else
+ {
+ r1.i = (INT32)((atan2(r2.f,r1.f))*32768.0/M_PI);
+ GETEXTPORT()[0x27] = r1.u;
+ }
+
+ return GETEXTPORT()[0x27];
+ }
+
+ if ( offset == 0x28 ) /* 1/x - part 1 */
+ return 0;
+
+ if ( offset == 0x29 ) /* 1/x - part 2 */
+ {
+ MB86233_REG r;
+ r.u = GETEXTPORT()[0x28];
+ if ( r.f==0 )
+ r.u = 0x80000000;
+ r.f = 1/r.f;
+ return r.u;
+ }
+
+ if ( offset == 0x2a ) /* 1/sqrt(x) - part 1 */
+ return 0;
+
+ if ( offset == 0x2b) /* 1/sqrt(x) - part 2 */
+ {
+ MB86233_REG r;
+ r.u = GETEXTPORT()[0x2a];
+ if ( r.f == 0 )
+ r.u=0x80000000;
+ else
+ r.f = 1/sqrt(r.f);
+ return r.u;
+ }
+
+ return GETEXTPORT()[offset];
+ }
+
+ addr = ( EB & 0xFFFF0000 ) | ( offset & 0xFFFF );
+
+ return RDMEM(addr);
+}
+
+static void SETEXTERNAL( UINT32 EB, UINT32 offset, UINT32 value )
+{
+ UINT32 addr;
+
+ if ( EB == 0 && offset >= 0x20 && offset <= 0x2f ) /* TGP Tables in ROM - FIXME - */
+ {
+ GETEXTPORT()[offset] = value;
+ return;
+ }
+
+ addr = ( EB & 0xFFFF0000 ) | ( offset & 0xFFFF );
+
+ WRMEM( addr, value );
+}
+
+
+
+/***************************************************************************
+ Register Access
+***************************************************************************/
+
+static UINT32 GETREGS( UINT32 reg, int source )
+{
+ UINT32 mode = ( reg >> 6 ) & 0x07;
+
+ reg &= 0x3f;
+
+ if ( mode == 0 || mode == 1 || mode == 3 )
+ {
+ if ( reg < 0x10 )
+ {
+ return GETGPR(reg);
+ }
+
+ switch( reg )
+ {
+ case 0x10: /* A */
+ return GETA().u;
+ break;
+
+ case 0x11: /* A.e */
+ return (GETA().u >> 23) & 0xff;
+ break;
+
+ case 0x12: /* A.m */
+ return (GETA().u & 0x7fffff) | ((GETA().u&0x80000000) >> 8);
+ break;
+
+ case 0x13: /* B */
+ return GETB().u;
+ break;
+
+ case 0x14: /* B.e */
+ return (GETB().u >> 23) & 0xff;
+ break;
+
+ case 0x15: /* B.m */
+ return (GETB().u & 0x7fffff) | ((GETB().u&0x80000000) >> 8);
+ break;
+
+ case 0x19: /* D */
+ return GETD().u;
+ break;
+
+ case 0x1A: /* D.e */
+ return (GETD().u >> 23) & 0xff;
+ break;
+
+ case 0x1B: /* D.m */
+ return (GETD().u & 0x7fffff) | ((GETD().u&0x80000000) >> 8);
+ break;
+
+ case 0x1C: /* P */
+ return GETP().u;
+ break;
+
+ case 0x1D: /* P.e */
+ return (GETP().u >> 23) & 0xff;
+ break;
+
+ case 0x1E: /* P.m */
+ return (GETP().u & 0x7fffff) | ((GETP().u&0x80000000) >> 8);
+ break;
+
+ case 0x1F: /* Shift */
+ return GETSHIFT();
+ break;
+
+ case 0x20: /* Parallel Port */
+ logerror( "TGP: Parallel port read at PC:%04x\n", GETPC() );
+ return 0;
+ break;
+
+ case 0x21: /* FIn */
+ {
+ UINT32 fifo_data;
+
+ if ( mb86233.fifo_read_cb )
+ {
+ if ( mb86233.fifo_read_cb(&fifo_data) )
+ {
+ return fifo_data;
+ }
+ }
+
+ GETFIFOWAIT() = 1;
+ return 0;
+ }
+ break;
+
+ case 0x22: /* FOut */
+ return 0;
+ break;
+
+ case 0x23: /* EB */
+ return GETEB();
+ break;
+
+ case 0x34:
+ return GETREPCNT();
+ break;
+
+ default:
+ logerror( "TGP: Unknown GETREG (%d) at PC=%04x\n", reg, GETPC() );
+ break;
+ }
+ }
+ else if ( mode == 2 ) /* Indexed */
+ {
+ UINT32 addr = reg & 0x1f;
+
+ if ( source )
+ {
+ if( !( reg & 0x20 ) )
+ addr += GETGPR(0);
+
+ addr += GETGPR(2);
+ }
+ else
+ {
+ if( !( reg & 0x20 ) )
+ addr += GETGPR(1);
+
+ addr += GETGPR(3);
+ }
+
+ return addr;
+ }
+ else if( mode == 6 ) /* Indexed with postop */
+ {
+ UINT32 addr = 0;
+
+ if ( source )
+ {
+ if( !( reg & 0x20 ) )
+ addr += GETGPR(0);
+
+ addr += GETGPR(2);
+ }
+ else
+ {
+ if( !( reg & 0x20 ) )
+ addr += GETGPR(1);
+
+ addr += GETGPR(3);
+ }
+
+ if ( reg & 0x10 )
+ {
+ if ( source )
+ GETGPR(2) -= 0x20 - ( reg & 0x1f );
+ else
+ GETGPR(3) -= 0x20 - ( reg & 0x1f );
+ }
+ else
+ {
+ if ( source )
+ GETGPR(2) += ( reg & 0x1f );
+ else
+ GETGPR(3) += ( reg & 0x1f );
+ }
+
+ return addr;
+ }
+ else
+ {
+ fatalerror( "TGP: Unknown GETREG mode %d at PC:%04x\n", mode, GETPC() );
+ }
+
+ return 0;
+}
+
+static void SETREGS( UINT32 reg, UINT32 val )
+{
+ int mode = ( reg >> 6) & 0x07;
+
+ reg &= 0x3f;
+
+ if( mode == 0 || mode == 1 || mode == 3 )
+ {
+ if ( reg < 0x10 )
+ {
+ if ( reg == 12 || reg == 13 )
+ val &= 0xff;
+
+ GETGPR(reg) = val;
+ return;
+ }
+
+ switch( reg )
+ {
+ case 0x10: /* A */
+ GETA().u = val;
+ break;
+
+ case 0x11: /* A.e */
+ GETA().u &= ~((0x0000007f) << 23);
+ GETA().u |= (( val & 0xff ) << 23 );
+ break;
+
+ case 0x12: /* A.m */
+ GETA().u &= ~( 0x807fffff );
+ GETA().u |= ( val & 0x7fffff );
+ GETA().u |= ( val & 0x800000 ) << 8;
+ break;
+
+ case 0x13: /* B */
+ GETB().u = val;
+ break;
+
+ case 0x14: /* B.e */
+ GETB().u &= ~((0x0000007f) << 23);
+ GETB().u |= (( val & 0xff ) << 23 );
+ break;
+
+ case 0x15: /* B.m */
+ GETB().u &= ~( 0x807fffff );
+ GETB().u |= ( val & 0x7fffff );
+ GETB().u |= ( val & 0x800000 ) << 8;
+ break;
+
+ case 0x19: /* D */
+ GETD().u = val;
+ break;
+
+ case 0x1A: /* D.e */
+ GETD().u &= ~((0x0000007f) << 23);
+ GETD().u |= (( val & 0xff ) << 23 );
+ break;
+
+ case 0x1B: /* B.m */
+ GETD().u &= ~( 0x807fffff );
+ GETD().u |= ( val & 0x7fffff );
+ GETD().u |= ( val & 0x800000 ) << 8;
+ break;
+
+ case 0x1C: /* P */
+ GETP().u = val;
+ break;
+
+ case 0x1D: /* P.e */
+ GETP().u &= ~((0x0000007f) << 23);
+ GETP().u |= (( val & 0xff ) << 23 );
+ break;
+
+ case 0x1E: /* P.m */
+ GETP().u &= ~( 0x807fffff );
+ GETP().u |= ( val & 0x7fffff );
+ GETP().u |= ( val & 0x800000 ) << 8;
+ break;
+
+ case 0x1F:
+ GETSHIFT() = val;
+ break;
+
+ case 0x20: /* Parallel Port */
+ logerror( "TGP: Parallel port write: %08x at PC:%04x\n", val, GETPC() );
+ break;
+
+ case 0x22: /* FOut */
+ if ( mb86233.fifo_write_cb )
+ {
+ mb86233.fifo_write_cb( val );
+ }
+ break;
+
+ case 0x23:
+ GETEB() = val;
+ break;
+
+ case 0x34:
+ GETREPCNT() = val;
+ break;
+
+ default:
+ {
+ fatalerror( "TGP: Unknown register write (r:%d, mode:%d) at PC:%04x\n", reg, mode, GETPC());
+ }
+ break;
+ }
+ }
+ else
+ {
+ fatalerror( "TGP: Unknown register write (r:%d, mode:%d) at PC:%04x\n", reg, mode, GETPC());
+ }
+}
+
+
+/***************************************************************************
+ Addressing Modes
+***************************************************************************/
+
+static UINT32 INDIRECT( UINT32 reg, int source )
+{
+ UINT32 mode = ( reg >> 6 ) & 0x07;
+
+ if ( mode == 0 || mode == 1 || mode == 3 )
+ {
+ return reg;
+ }
+ else if ( mode == 2 )
+ {
+ UINT32 addr = reg & 0x1f;
+
+ if ( source )
+ {
+ if( !(reg & 0x20) )
+ addr += GETGPR(0);
+
+ addr += GETGPR(2);
+ }
+ else
+ {
+ if( !(reg & 0x20) )
+ addr += GETGPR(1);
+
+ addr += GETGPR(3);
+ }
+
+ return addr;
+ }
+ else if ( mode == 6 || mode == 7 )
+ {
+ UINT32 addr = 0;
+
+ if ( source )
+ {
+ if ( !( reg & 0x20 ) )
+ addr += GETGPR(0);
+
+ addr += GETGPR(2);
+ }
+ else
+ {
+ if ( !( reg & 0x20 ) )
+ addr += GETGPR(1);
+
+ addr += GETGPR(3);
+ }
+
+ if ( reg & 0x10 )
+ {
+ if ( source )
+ GETGPR(2) -= 0x20 - ( reg & 0x1f );
+ else
+ GETGPR(3) -= 0x20 - ( reg & 0x1f );
+ }
+ else
+ {
+ if ( source )
+ GETGPR(2) += ( reg & 0x1f );
+ else
+ GETGPR(3) += ( reg & 0x1f );
+ }
+
+ return addr;
+ }
+ else
+ {
+ fatalerror( "TGP: Unknown INDIRECT mode %d at PC:%04x\n", mode, GETPC() );
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ Core Execution Loop
+***************************************************************************/
+
+static int mb86233_execute(int cycles)
+{
+
+ mb86233_icount = cycles;
+
+ while( mb86233_icount > 0 )
+ {
+ UINT32 val;
+ UINT32 opcode;
+
+ CALL_MAME_DEBUG;
+
+ opcode = ROPCODE(GETPC());
+
+ GETFIFOWAIT() = 0;
+
+ switch( (opcode >> 26) & 0x3f )
+ {
+ case 0x00: /* dual move */
+ {
+ UINT32 r1 = opcode & 0x1ff;
+ UINT32 r2 = ( opcode >> 9 ) & 0x7f;
+ UINT32 alu = ( opcode >> 21 ) & 0x1f;
+ UINT32 op = ( opcode >> 16 ) & 0x1f;
+
+ ALU( alu );
+
+ switch( op )
+ {
+ case 0x0C:
+ GETA().u = GETARAM()[r1];
+ GETB().u = GETBRAM()[r2];
+ break;
+
+ case 0x0D:
+ GETA().u = GETARAM()[INDIRECT(r1,0)];
+ GETB().u = GETBRAM()[INDIRECT(r2|2<<6,0)];
+ break;
+
+ case 0x0F:
+ GETA().u = GETARAM()[r1];
+ GETB().u = GETBRAM()[INDIRECT(r2|6<<6,0)];
+ break;
+
+ case 0x10:
+ GETA().u = GETBRAM()[INDIRECT(r1,1)];
+ GETB().u = GETARAM()[r2];
+ break;
+
+ case 0x11:
+ GETA().u = GETARAM()[INDIRECT(r1,1)];
+ GETB().u = GETBRAM()[INDIRECT(r2|(2<<6),0)];
+ break;
+
+ default:
+ logerror( "TGP: Unknown TGP double move (op=%d) at PC:%x\n", op, GETPC());
+ break;
+ }
+ }
+ break;
+
+ case 0x7: /* LD/MOV */
+ {
+ UINT32 r1 = opcode & 0x1ff;
+ UINT32 r2 = ( opcode >> 9 ) & 0x7f;
+ UINT32 alu = ( opcode >> 21 ) & 0x1f;
+ UINT32 op = ( opcode >> 16 ) & 0x1f;
+
+ switch( op )
+ {
+ case 0x04: /* MOV RAM->External */
+ {
+ SETEXTERNAL(GETEB(), r2, GETARAM()[r1]);
+ ALU(alu);
+ }
+ break;
+
+ case 0x0c: /* MOV RAM->BRAM */
+ {
+ GETBRAM()[r2] = GETARAM()[r1];
+ ALU(alu);
+ }
+ break;
+
+ case 0x1d: /* MOV RAM->Reg */
+ {
+ if ( r1 & 0x180 )
+ {
+ val = GETARAM()[GETREGS(r1,0)];
+ }
+ else
+ {
+ val = GETARAM()[r1];
+ }
+
+ /* if we're waiting for data, don't complete the instruction */
+ if ( GETFIFOWAIT() )
+ break;
+
+ ALU(alu);
+ SETREGS(r2,val);
+ }
+ break;
+
+ case 0x1c: /* MOV Reg->RAMInd */
+ {
+ val = GETREGS(r2,1);
+
+ /* if we're waiting for data, don't complete the instruction */
+ if ( GETFIFOWAIT() )
+ break;
+
+ ALU(alu);
+
+ if ( ( r2 >> 6 ) & 0x01)
+ {
+ SETEXTERNAL(GETEB(),INDIRECT(r1,0),val);
+ }
+ else
+ {
+ GETARAM()[INDIRECT(r1,0)] = val;
+ }
+ }
+ break;
+
+ case 0x1f: /* MOV Reg->Reg */
+ {
+ if ( r1 == 0x10 && r2 == 0xf )
+ {
+ /* NOP */
+ ALU(alu);
+ }
+ else
+ {
+ val = GETREGS(r1,1);
+
+ /* if we're waiting for data, don't complete the instruction */
+ if ( GETFIFOWAIT() )
+ break;
+
+ ALU(alu);
+ SETREGS( r2, val );
+ }
+ }
+ break;
+
+ case 0x0f: /* MOV RAMInd->BRAMInd */
+ {
+ val = GETARAM()[INDIRECT(r1,1)];
+ ALU(alu);
+ GETBRAM()[INDIRECT(r2|(6<<6),0)] = val;
+ }
+ break;
+
+ case 0x13: /* MOV BRAMInd->RAMInd */
+ {
+ val = GETBRAM()[INDIRECT(r1,1)];
+ ALU(alu);
+ GETARAM()[INDIRECT(r2|(6<<6),0)] = val;
+ }
+ break;
+
+ case 0x10: /* MOV RAMInd->RAM */
+ {
+ val = GETBRAM()[INDIRECT(r1,1)];
+ ALU(alu);
+ GETARAM()[r2] = val;
+ }
+ break;
+
+ case 0x1e: /* External->Reg */
+ {
+ UINT32 offset;
+
+ if ( ( r2 >> 6 ) & 1 )
+ offset = INDIRECT(r1,1);
+ else
+ offset = INDIRECT(r1,0);
+
+ val = GETEXTERNAL(GETEB(),offset);
+ ALU(alu);
+ SETREGS(r2,val);
+ }
+ break;
+
+ case 0x03: /* RAM->External Ind */
+ {
+ val = GETARAM()[r1];
+ ALU(alu);
+ SETEXTERNAL(GETEB(),INDIRECT(r2|(6<<6),0),val);
+ }
+ break;
+
+ case 0x07: /* RAMInd->External */
+ {
+ val = GETARAM()[INDIRECT(r1,1)];
+ ALU(alu);
+ SETEXTERNAL(GETEB(),INDIRECT(r2|(6<<6),0),val);
+ }
+ break;
+
+ case 0x08: /* External->RAM */
+ {
+ val = GETEXTERNAL(GETEB(),INDIRECT(r1,1));
+ ALU(alu);
+ GETARAM()[r2] = val;
+ }
+ break;
+
+ case 0x0b: /* External->RAMInd */
+ {
+ val = GETEXTERNAL(GETEB(),INDIRECT(r1,1));
+ ALU(alu);
+ GETARAM()[INDIRECT(r2|(6<<6),0)] = val;
+ }
+ break;
+
+ default:
+ logerror( "TGP: Unknown TGP move (op=%d) at PC:%x\n", op, GETPC());
+ break;
+ }
+ }
+ break;
+
+ case 0x0e: /* LDIMM24 */
+ {
+ UINT32 sub = (opcode>>24) & 0x03;
+ UINT32 imm = opcode & 0xffffff;
+
+ /* sign extend 24->32 */
+ if ( imm & 0x800000 )
+ imm |= 0xFF000000;
+
+ switch( sub )
+ {
+ case 0x00: /* P */
+ GETP().u = imm;
+ break;
+
+ case 0x01: /* A */
+ GETA().u = imm;
+ break;
+
+ case 0x02: /* B */
+ GETB().u = imm;
+ break;
+
+ case 0x03: /* D */
+ GETD().u = imm;
+ break;
+ }
+ }
+ break;
+
+ case 0x0f: /* REP/CLEAR/FLAGS */
+ {
+ UINT32 alu = ( opcode >> 20 ) & 0x1f;
+ UINT32 sub2 = ( opcode >> 16 ) & 0x0f;
+
+ ALU( alu );
+
+ if( sub2 == 0x00 ) /* CLEAR reg */
+ {
+ UINT32 reg = opcode & 0x1f;
+
+ switch( reg )
+ {
+ case 0x10:
+ GETD().u = 0;
+ break;
+
+ case 0x08:
+ GETB().u = 0;
+ break;
+
+ case 0x04:
+ GETA().u = 0;
+ break;
+ }
+ }
+ else if ( sub2 == 0x04 ) /* REP xxx */
+ {
+ UINT32 sub3 = ( opcode >> 12 ) & 0x0f;
+
+ if ( sub3 == 0 )
+ {
+ GETREPS() = opcode & 0xfff;
+
+ if ( GETREPS() == 0 )
+ GETREPS() = 0x100;
+
+ GETPC()++;
+ }
+ else if ( sub3 == 8 )
+ {
+ GETREPS() = GETREGS( opcode & 0xfff, 0 );
+ GETPC()++;
+ }
+ }
+ else if ( sub2 == 0x02 ) /* CLRFLAGS */
+ {
+ GETSR() &= ~(opcode&0xfff);
+ }
+ else if ( sub2 == 0x06 ) /* SETFLAGS */
+ {
+ GETSR() |= (opcode&0xfff);
+ }
+ }
+ break;
+
+ case 0x10: /* LDIMM rx */
+ {
+ UINT32 sub = (opcode>>24) & 0x03;
+ UINT32 imm = opcode & 0xffff;
+
+ GETGPR(sub) = imm;
+ }
+ break;
+
+ case 0x13: /* LDIMM r1x */
+ {
+ UINT32 sub = (opcode>>24) & 0x03;
+ UINT32 imm = opcode & 0xffffff;
+
+ if ( sub == 0 ) /* R12 */
+ GETGPR(12) = imm & 0xff;
+ else if ( sub == 1 ) /* R13 */
+ GETGPR(13) = imm & 0xff;
+ else
+ logerror( "TGP: Unknown LDIMM r12 (sub=%d) at PC:%04x\n", sub, GETPC() );
+ }
+ break;
+
+ case 0x14: /* LDIMM m,e */
+ {
+ UINT32 sub = (opcode>>24) & 0x03;
+ UINT32 imm = opcode & 0xffffff;
+
+ if ( sub == 0 ) /* A */
+ {
+ GETA().u = imm;
+ }
+ else if ( sub == 1 ) /* A.e */
+ {
+ GETA().u = (imm & 0xff) << 23;
+ }
+ else if ( sub == 2 ) /* A.m */
+ {
+ GETA().u |= (imm & 0x7fffff ) | ((imm & 0x800000) << 8);
+ }
+ else
+ {
+ logerror( "TGP: Unknown LDIMM m,e (sub=%d) at PC:%04x\n", sub, GETPC() );
+ }
+ }
+ break;
+
+ case 0x15: /* LDIMM m,e */
+ {
+ UINT32 sub = (opcode>>24) & 0x03;
+ UINT32 imm = opcode & 0xffffff;
+
+ if ( sub == 0 ) /* B ? */
+ {
+ GETB().u = ((imm & 0x7f) << 23) | ((imm & 0xff) << 8) | ( imm & 0xff );
+ }
+ else if ( sub == 1 ) /* B.e */
+ {
+ GETB().u = (imm & 0xff) << 23;
+ }
+ else if ( sub == 2 ) /* B.m */
+ {
+ GETB().u |= (imm & 0x7fffff ) | ((imm & 0x800000) << 8);
+ }
+ else
+ {
+ logerror( "TGP: Unknown LDIMM m,e (sub=%d) at PC:%04x\n", sub, GETPC() );
+ }
+ }
+ break;
+
+ case 0x16: /* LDIMM m,e */
+ {
+ UINT32 sub = (opcode>>24) & 0x03;
+ UINT32 imm = opcode & 0xffffff;
+
+ if ( sub == 1 ) /* clear + D.m */
+ {
+ GETD().u = (imm & 0x7fffff ) | ((imm & 0x800000) << 8);
+ }
+ else if ( sub == 2 ) /* D.e */
+ {
+ GETD().u = (imm & 0xff) << 23;
+ }
+ else if ( sub == 3 ) /* D.m */
+ {
+ GETD().u |= (imm & 0x7fffff ) | ((imm & 0x800000) << 8);
+ }
+ else
+ {
+ logerror( "TGP: Unknown LDIMM m,e (sub=%d) at PC:%04x\n", sub, GETPC() );
+ }
+ }
+ break;
+
+ case 0x17: /* LDIMM special reg */
+ {
+ UINT32 sub = (opcode>>24) & 0x03;
+ UINT32 imm = opcode & 0xffffff;
+
+ if ( sub == 0x03 )
+ {
+ GETSHIFT() = imm;
+ }
+ else
+ {
+ logerror( "TGP: Unknown LDIMM special reg (sub=%d) at PC:%04x\n", sub, GETPC() );
+ }
+ }
+ break;
+
+ case 0x18: /* LDIMM external reg */
+ {
+ UINT32 sub = (opcode>>24) & 0x03;
+ UINT32 imm = opcode & 0xffffff;
+
+ if ( sub == 0x03 )
+ {
+ GETEB() = imm;
+ }
+ else
+ {
+ logerror( "TGP: Unknown LDIMM external reg (sub=%d) at PC:%04x\n", sub, GETPC() );
+ }
+ }
+ break;
+
+ case 0x1d: //LDIMM to Rep regs
+ {
+ UINT32 sub = (opcode>>24)&0x3;
+ UINT32 imm = opcode&0xffffff;
+ if(sub == 0x00)
+ {
+ GETREPCNT() = imm;
+ }
+ else
+ {
+ logerror( "TGP: Unknown LDIMM REPCnt (sub=%d) at PC:%04x\n", sub, GETPC() );
+ }
+ }
+ break;
+
+ case 0x2f: /* Conditional Branches */
+ {
+ UINT32 cond = ( opcode >> 20 ) & 0x1f;
+ UINT32 subtype = ( opcode >> 16 ) & 0x0f;
+ UINT32 data = opcode & 0xffff;
+
+ if( COND(cond) )
+ {
+ switch( subtype )
+ {
+ case 0x00: /* BRIF <addr> */
+ GETPC() = data - 1;
+ change_pc( GETPC() );
+ break;
+
+ case 0x02: /* BRIF indirect */
+ if ( data & 0x4000 )
+ data = GETREGS(data&0x3f,0) - 1;
+ else
+ data = ((GETARAM()[data&0x3ff])&0xffff)-1;
+
+ /* if we're waiting for data, don't complete the instruction */
+ if ( GETFIFOWAIT() )
+ break;
+
+ GETPC() = data;
+ change_pc( GETPC() );
+ break;
+
+ case 0x04: /* BSIF <addr> */
+ GETPCS()[GETPCSP()] = GETPC();
+ GETPCSP()++;
+ GETPC() = data - 1;
+ change_pc( GETPC() );
+ break;
+
+ case 0x06: /* BSIF indirect */
+ GETPCS()[GETPCSP()] = GETPC();
+ GETPCSP()++;
+ if ( data & 0x4000 )
+ data = GETREGS(data&0x3f,0) - 1;
+ else
+ data = ((GETARAM()[data&0x3ff])&0xffff)-1;
+
+ /* if we're waiting for data, don't complete the instruction */
+ if ( GETFIFOWAIT() )
+ break;
+
+ GETPC() = data;
+ change_pc( GETPC() );
+ break;
+
+ case 0x0a: /* RTIF */
+ --GETPCSP();
+ GETPC() = GETPCS()[GETPCSP()];
+ change_pc( GETPC() );
+ break;
+
+ case 0x0c: /* LDIF */
+ SETREGS(((data>>9)&0x3f), GETARAM()[data&0x1FF] );
+ break;
+
+ case 0x0e: /* RIIF */
+ logerror( "TGP: RIIF unimplemented at PC:%04x\n", GETPC() );
+ break;
+
+ default:
+ logerror( "TGP: Unknown Branch opcode (subtype=%d) at PC:%04x\n", subtype, GETPC() );
+ break;
+ }
+ }
+ }
+ break;
+
+ case 0x3f: /* Inverse Conditional Branches */
+ {
+ UINT32 cond = ( opcode >> 20 ) & 0x1f;
+ UINT32 subtype = ( opcode >> 16 ) & 0x0f;
+ UINT32 data = opcode & 0xffff;
+
+ if( !COND(cond) )
+ {
+ switch( subtype )
+ {
+ case 0x00: /* BRUL <addr> */
+ GETPC() = data - 1;
+ break;
+
+ case 0x02: /* BRUL indirect */
+ if ( data & 0x4000 )
+ data = GETREGS(data&0x3f,0) - 1;
+ else
+ data = ((GETARAM()[data&0x3ff])&0xffff)-1;
+
+ /* if we're waiting for data, don't complete the instruction */
+ if ( GETFIFOWAIT() )
+ break;
+
+ GETPC() = data;
+ change_pc( GETPC() );
+ break;
+
+ case 0x04: /* BSUL <addr> */
+ GETPCS()[GETPCSP()] = GETPC();
+ GETPCSP()++;
+ GETPC() = data - 1;
+ change_pc( GETPC() );
+ break;
+
+ case 0x06: /* BSUL indirect */
+ GETPCS()[GETPCSP()] = GETPC();
+ GETPCSP()++;
+ if ( data & 0x4000 )
+ data = GETREGS(data&0x3f,0) - 1;
+ else
+ data = ((GETARAM()[data&0x3ff])&0xffff)-1;
+
+ /* if we're waiting for data, don't complete the instruction */
+ if ( GETFIFOWAIT() )
+ break;
+
+ GETPC() = data;
+ change_pc( GETPC() );
+ break;
+
+ case 0x0a: /* RTUL */
+ --GETPCSP();
+ GETPC() = GETPCS()[GETPCSP()];
+ change_pc( GETPC() );
+ break;
+
+ case 0x0c: /* LDUL */
+ SETREGS(((data>>9)&0x3f), GETARAM()[data&0x1FF] );
+ break;
+
+ case 0x0e: /* RIUL */
+ logerror( "TGP: RIIF unimplemented at PC:%04x\n", GETPC() );
+ break;
+
+ default:
+ logerror( "TGP: Unknown Branch opcode (subtype=%d) at PC:%04x\n", subtype, GETPC() );
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ logerror( "TGP: unknown opcode %08x at PC:%04x\n", opcode, GETPC() );
+ break;
+ }
+
+ if ( GETFIFOWAIT() == 0 )
+ {
+ if( GETREPS() == 0 )
+ GETPC()++;
+ else
+ --GETREPS();
+
+ mb86233_icount--;
+ }
+ else
+ {
+ mb86233_icount = 0;
+ }
+ }
+
+ return cycles - mb86233_icount;
+}
+
+/***************************************************************************
+ DISASSEMBLY HOOK
+***************************************************************************/
+
+#ifdef MAME_DEBUG
+static offs_t mb86233_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ extern UINT32 dasm_mb86233(char *, UINT32);
+
+ UINT32 op = *(UINT32 *)oprom;
+ op = LITTLE_ENDIANIZE_INT32(op);
+ return dasm_mb86233(buffer, op);
+}
+#endif /* MAME_DEBUG */
+
+/***************************************************************************
+ Information Setters
+***************************************************************************/
+
+static void mb86233_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + MB86233_PC: GETPC() = info->i; change_pc(GETPC()); break;
+ case CPUINFO_INT_REGISTER + MB86233_A: GETA().u = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_B: GETB().u = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_P: GETP().u = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_D: GETD().u = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_REP: GETREPS() = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + MB86233_SP: GETPCSP() = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_EB: GETEB() = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_SHIFT: GETSHIFT() = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_FLAGS: GETSR() = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R0: GETGPR(0) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R1: GETGPR(1) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R2: GETGPR(2) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R3: GETGPR(3) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R4: GETGPR(4) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R5: GETGPR(5) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R6: GETGPR(6) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R7: GETGPR(7) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R8: GETGPR(8) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R9: GETGPR(9) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R10: GETGPR(10) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R11: GETGPR(11) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R12: GETGPR(12) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R13: GETGPR(13) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R14: GETGPR(14) = info->i; break;
+ case CPUINFO_INT_REGISTER + MB86233_R15: GETGPR(15) = info->i; break;
+ }
+}
+
+/***************************************************************************
+ Information Getters
+***************************************************************************/
+
+void mb86233_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(MB86233_REGS); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 2; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -2; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + MB86233_PC: info->i = GETPC(); break;
+ case CPUINFO_INT_REGISTER + MB86233_A: info->i = GETA().u; break;
+ case CPUINFO_INT_REGISTER + MB86233_B: info->i = GETB().u; break;
+ case CPUINFO_INT_REGISTER + MB86233_P: info->i = GETP().u; break;
+ case CPUINFO_INT_REGISTER + MB86233_D: info->i = GETD().u; break;
+ case CPUINFO_INT_REGISTER + MB86233_REP: info->i = GETREPS(); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + MB86233_SP: info->i = GETPCSP(); break;
+ case CPUINFO_INT_REGISTER + MB86233_EB: info->i = GETEB(); break;
+ case CPUINFO_INT_REGISTER + MB86233_SHIFT: info->i = GETSHIFT(); break;
+ case CPUINFO_INT_REGISTER + MB86233_FLAGS: info->i = GETSR(); break;
+ case CPUINFO_INT_REGISTER + MB86233_R0: info->i = GETGPR(0); break;
+ case CPUINFO_INT_REGISTER + MB86233_R1: info->i = GETGPR(1); break;
+ case CPUINFO_INT_REGISTER + MB86233_R2: info->i = GETGPR(2); break;
+ case CPUINFO_INT_REGISTER + MB86233_R3: info->i = GETGPR(3); break;
+ case CPUINFO_INT_REGISTER + MB86233_R4: info->i = GETGPR(4); break;
+ case CPUINFO_INT_REGISTER + MB86233_R5: info->i = GETGPR(5); break;
+ case CPUINFO_INT_REGISTER + MB86233_R6: info->i = GETGPR(6); break;
+ case CPUINFO_INT_REGISTER + MB86233_R7: info->i = GETGPR(7); break;
+ case CPUINFO_INT_REGISTER + MB86233_R8: info->i = GETGPR(8); break;
+ case CPUINFO_INT_REGISTER + MB86233_R9: info->i = GETGPR(9); break;
+ case CPUINFO_INT_REGISTER + MB86233_R10: info->i = GETGPR(10); break;
+ case CPUINFO_INT_REGISTER + MB86233_R11: info->i = GETGPR(11); break;
+ case CPUINFO_INT_REGISTER + MB86233_R12: info->i = GETGPR(12); break;
+ case CPUINFO_INT_REGISTER + MB86233_R13: info->i = GETGPR(13); break;
+ case CPUINFO_INT_REGISTER + MB86233_R14: info->i = GETGPR(14); break;
+ case CPUINFO_INT_REGISTER + MB86233_R15: info->i = GETGPR(15); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mb86233_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = mb86233_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = mb86233_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = mb86233_init; break;
+ case CPUINFO_PTR_RESET: info->reset = mb86233_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = NULL; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = mb86233_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = mb86233_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &mb86233_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MB86233"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Fujitsu MB86233"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 2007 ElSemi and Ernesto Corvi"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c", (GETSR()&SIGN_FLAG) ? 'N' : 'n', (GETSR()&ZERO_FLAG) ? 'Z' : 'z' );
+ break;
+
+ case CPUINFO_STR_REGISTER + MB86233_FLAGS:
+ sprintf(info->s, "FL:%c%c", (GETSR()&SIGN_FLAG) ? 'N' : 'n', (GETSR()&ZERO_FLAG) ? 'Z' : 'z' );
+ break;
+
+ case CPUINFO_STR_REGISTER + MB86233_PC: sprintf(info->s, "PC:%04X", GETPC()); break;
+ case CPUINFO_STR_REGISTER + MB86233_A: sprintf(info->s, "PA:%08X (%f)", GETA().u, GETA().f); break;
+ case CPUINFO_STR_REGISTER + MB86233_B: sprintf(info->s, "PB:%08X (%f)", GETB().u, GETB().f); break;
+ case CPUINFO_STR_REGISTER + MB86233_P: sprintf(info->s, "PP:%08X (%f)", GETP().u, GETP().f); break;
+ case CPUINFO_STR_REGISTER + MB86233_D: sprintf(info->s, "PD:%08X (%f)", GETD().u, GETD().f); break;
+ case CPUINFO_STR_REGISTER + MB86233_REP: sprintf(info->s, "REPS:%08X", GETREPS()); break;
+ case CPUINFO_STR_REGISTER + MB86233_SP: sprintf(info->s, "PCSP:%1X", GETPCSP()); break;
+ case CPUINFO_STR_REGISTER + MB86233_EB: sprintf(info->s, "EB:%08X", GETEB()); break;
+ case CPUINFO_STR_REGISTER + MB86233_SHIFT: sprintf(info->s, "SHIFT:%08X", GETSHIFT()); break;
+ case CPUINFO_STR_REGISTER + MB86233_R0: sprintf(info->s, "R0:%08X", GETGPR(0)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R1: sprintf(info->s, "R1:%08X", GETGPR(1)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R2: sprintf(info->s, "R2:%08X", GETGPR(2)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R3: sprintf(info->s, "R3:%08X", GETGPR(3)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R4: sprintf(info->s, "R4:%08X", GETGPR(4)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R5: sprintf(info->s, "R5:%08X", GETGPR(5)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R6: sprintf(info->s, "R6:%08X", GETGPR(6)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R7: sprintf(info->s, "R7:%08X", GETGPR(7)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R8: sprintf(info->s, "R8:%08X", GETGPR(8)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R9: sprintf(info->s, "R9:%08X", GETGPR(9)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R10: sprintf(info->s, "R10:%08X", GETGPR(10)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R11: sprintf(info->s, "R11:%08X", GETGPR(11)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R12: sprintf(info->s, "R12:%08X", GETGPR(12)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R13: sprintf(info->s, "R13:%08X", GETGPR(13)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R14: sprintf(info->s, "R14:%08X", GETGPR(14)); break;
+ case CPUINFO_STR_REGISTER + MB86233_R15: sprintf(info->s, "R15:%08X", GETGPR(15)); break;
+ }
+}
diff --git a/src/emu/cpu/mb86233/mb86233.h b/src/emu/cpu/mb86233/mb86233.h
new file mode 100644
index 00000000000..1155e67ea6d
--- /dev/null
+++ b/src/emu/cpu/mb86233/mb86233.h
@@ -0,0 +1,52 @@
+#ifndef _MB86233_H
+#define _MB86233_H
+
+#include "cpuintrf.h"
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ MB86233_PC=1,
+ MB86233_A,
+ MB86233_B,
+ MB86233_D,
+ MB86233_P,
+ MB86233_REP,
+ MB86233_SP,
+ MB86233_EB,
+ MB86233_SHIFT,
+ MB86233_FLAGS,
+ MB86233_R0,
+ MB86233_R1,
+ MB86233_R2,
+ MB86233_R3,
+ MB86233_R4,
+ MB86233_R5,
+ MB86233_R6,
+ MB86233_R7,
+ MB86233_R8,
+ MB86233_R9,
+ MB86233_R10,
+ MB86233_R11,
+ MB86233_R12,
+ MB86233_R13,
+ MB86233_R14,
+ MB86233_R15
+};
+
+/***************************************************************************
+ STRUCTURES
+***************************************************************************/
+
+struct mb86233_config
+{
+ int (*fifo_read_cb)( UINT32* data );
+ void (*fifo_write_cb)( UINT32 data );
+};
+
+extern void mb86233_get_info(UINT32 state, cpuinfo *info);
+
+#endif /* _MB86233_H */
diff --git a/src/emu/cpu/mb86233/mb86233d.c b/src/emu/cpu/mb86233/mb86233d.c
new file mode 100644
index 00000000000..fce114b8ee6
--- /dev/null
+++ b/src/emu/cpu/mb86233/mb86233d.c
@@ -0,0 +1,774 @@
+#include "debugger.h"
+#include "mb86233.h"
+
+static char * COND(unsigned int cond)
+{
+ static char bufs[4][256];
+ static int bufindex = 0;
+ char *buf = &bufs[bufindex++][0];
+
+ bufindex &= 3;
+
+ switch(cond)
+ {
+ case 0x16:
+ sprintf(buf,"always");
+ return buf;
+
+ case 0x00:
+ sprintf(buf,"eq");
+ return buf;
+
+ case 0x01:
+ sprintf(buf,"ge");
+ return buf;
+
+ case 0x02:
+ sprintf(buf,"le");
+ return buf;
+
+ case 0x06:
+ sprintf(buf,"never");
+ return buf;
+
+ case 0x10:
+ sprintf(buf,"(--r12)!=0");
+ return buf;
+
+ case 0x11:
+ sprintf(buf,"(--r13)!=0");
+ return buf;
+ }
+
+ sprintf(buf,"unk (%x)",cond);
+ return buf;
+}
+
+static char * REGS( UINT32 reg, int IsSource )
+{
+ static char bufs[4][256];
+ static int bufindex = 0;
+ char *buf = &bufs[bufindex++][0];
+ int mode = (reg >> 6 ) & 0x07;
+
+ bufindex &= 3;
+
+ reg &= 0x3f;
+
+ if ( mode == 0 || mode == 1 || mode == 3 )
+ {
+ if ( reg < 0x10 )
+ {
+ sprintf(buf,"r%d",reg);
+ return buf;
+ }
+
+ switch(reg)
+ {
+ case 0x10:
+ sprintf(buf,"a");
+ break;
+
+ case 0x11:
+ sprintf(buf,"a.e");
+ break;
+
+ case 0x12:
+ sprintf(buf,"a.m");
+ break;
+
+ case 0x13:
+ sprintf(buf,"b");
+ break;
+
+ case 0x14:
+ sprintf(buf,"b.e");
+ break;
+
+ case 0x15:
+ sprintf(buf,"b.m");
+ break;
+
+ case 0x19:
+ sprintf(buf,"d");
+ break;
+
+ case 0x1a:
+ sprintf(buf,"d.e");
+ break;
+
+ case 0x1b:
+ sprintf(buf,"d.m");
+ break;
+
+ case 0x1c:
+ sprintf(buf,"p");
+ break;
+
+ case 0x1d:
+ sprintf(buf,"p.e");
+ break;
+
+ case 0x1e:
+ sprintf(buf,"p.m");
+ break;
+
+ case 0x1f:
+ sprintf(buf,"shift");
+ break;
+
+ case 0x20:
+ sprintf(buf,"parport");
+ break;
+
+ case 0x21:
+ sprintf(buf,"FIn");
+ break;
+
+ case 0x22:
+ sprintf(buf,"FOut");
+ break;
+
+ case 0x23:
+ sprintf(buf,"EB");
+ break;
+
+ default:
+ sprintf(buf,"Unkreg (%x)",reg);
+ break;
+ }
+ }
+ else if ( mode == 2 )
+ {
+ char *p = buf;
+
+ p += sprintf(p,"0x%x+",reg & 0x1f);
+
+ if ( IsSource )
+ {
+ if ( !( reg & 0x20 ) )
+ p += sprintf(p,"r0+");
+
+ p += sprintf(p,"r2");
+ }
+ else
+ {
+ if ( !( reg & 0x20 ) )
+ p += sprintf(p,"r1+");
+
+ p += sprintf(p,"r3");
+ }
+ }
+ else if ( mode == 6 )
+ {
+ char *p = buf;
+
+ if ( IsSource )
+ {
+ if ( !( reg & 0x20 ) )
+ p += sprintf(p,"r0+");
+
+ p += sprintf(p,"r2");
+ }
+ else
+ {
+ if ( !( reg & 0x20 ) )
+ p += sprintf(p,"r1+");
+
+ p += sprintf(p,"r3");
+ }
+
+ if ( reg & 0x10 )
+ p += sprintf(p,"--%d", 0x20 - ( reg & 0x1f ) );
+ else
+ p += sprintf(p,"++%d", reg & 0x1f );
+ }
+ else
+ {
+ sprintf(buf,"UNKMOD %x (0x%x)", mode, reg);
+ }
+
+ return buf;
+}
+
+static char * INDIRECT( UINT32 reg, int IsSource )
+{
+ static char bufs[4][256];
+ static int bufindex = 0;
+ char *buf = &bufs[bufindex++][0];
+ int mode = ( reg >> 6 ) & 0x07;
+
+ bufindex &= 3;
+
+ if ( mode == 0 || mode == 3 || mode == 1)
+ {
+ sprintf(buf,"0x%x",reg);
+ }
+ else if ( mode == 2 )
+ {
+ char *p = buf;
+
+ p += sprintf(p,"0x%x+",reg&0x1f);
+
+ if ( IsSource )
+ {
+ if ( !(reg & 0x20) )
+ p += sprintf(p,"r0+");
+
+ p += sprintf(p,"r2");
+ }
+ else
+ {
+ if ( !(reg & 0x20) )
+ p += sprintf(p,"r1+");
+
+ p += sprintf(p,"r3");
+ }
+ }
+ else if ( mode == 6 || mode == 7 )
+ {
+ char *p = buf;
+
+ if ( IsSource )
+ {
+ if ( !( reg & 0x20 ) )
+ p += sprintf(p,"r0+");
+
+ p += sprintf(p,"r2");
+ }
+ else
+ {
+ if( !( reg & 0x20 ) )
+ p += sprintf(p,"r1+");
+
+ p += sprintf(p,"r3");
+ }
+
+ if ( reg & 0x10 )
+ p += sprintf(p,"--%d",0x20 - ( reg & 0x1f ));
+ else
+ p += sprintf(p,"++%d",reg & 0x1f);
+ }
+ else
+ {
+ sprintf(buf,"UNKMOD %x (0x%x)", mode, reg);
+ }
+
+ return buf;
+}
+
+
+static char * ALU( UINT32 alu)
+{
+ static char bufs[4][256];
+ static int bufindex = 0;
+ char *buf = &bufs[bufindex++][0];
+
+ bufindex &= 3;
+
+ switch( alu )
+ {
+ case 0x0:
+ buf[0] = 0;
+ break;
+
+ case 0x1:
+ sprintf(buf,"d=d&a");
+ break;
+
+ case 0x2:
+ sprintf(buf,"d=d|a");
+ break;
+
+ case 0x3:
+ sprintf(buf,"d=d^a");
+ break;
+
+ case 0x5:
+ sprintf(buf,"cmp d,a");
+ break;
+
+ case 0x6:
+ sprintf(buf,"d=d+a");
+ break;
+
+ case 0x7:
+ sprintf(buf,"d=d-a");
+ break;
+
+ case 0x8:
+ sprintf(buf,"p=a*b");
+ break;
+
+ case 0x9:
+ sprintf(buf,"d=d+p, p=a*b");
+ break;
+
+ case 0xa:
+ sprintf(buf,"d=d-p, p=a*b");
+ break;
+
+ case 0xb:
+ sprintf(buf,"d=fabs d");
+ break;
+
+ case 0xc:
+ sprintf(buf,"d=d+p");
+ break;
+
+ case 0xd:
+ sprintf(buf,"d=p, p=a*b");
+ break;
+
+ case 0xe:
+ sprintf(buf,"d=float(d)");
+ break;
+
+ case 0xf:
+ sprintf(buf,"d=int(d)");
+ break;
+
+ case 0x10:
+ sprintf(buf,"d=d/a");
+ break;
+
+ case 0x11:
+ sprintf(buf,"d=-d");
+ break;
+
+ case 0x13:
+ sprintf(buf,"d=a+b");
+ break;
+
+ case 0x14:
+ sprintf(buf,"d=b-a");
+ break;
+
+ case 0x16:
+ sprintf(buf,"d=(lsr d,shift)");
+ break;
+
+ case 0x17:
+ sprintf(buf,"d=(lsl d,shift)");
+ break;
+
+ case 0x18:
+ sprintf(buf,"d=(asr d,shift)");
+ break;
+
+ case 0x1a:
+ sprintf(buf,"d=d+a (int)");
+ break;
+
+ case 0x1b:
+ sprintf(buf,"d=d-a (int)");
+ break;
+
+ default:
+ sprintf(buf,"ALU UNK(%x)",alu);
+ break;
+ }
+
+ return buf;
+}
+
+unsigned dasm_mb86233(char *buffer, UINT32 opcode )
+{
+ char *p = buffer;
+ UINT32 grp = ( opcode >> 26 ) & 0x3f;
+
+ switch( grp )
+ {
+ case 0x0: /* Dual move */
+ {
+ UINT32 r1=opcode & 0x1ff;
+ UINT32 r2=(opcode>>9) & 0x7f;
+ UINT32 alu=(opcode>>21) & 0x1f;
+ UINT32 op=(opcode>>16) & 0x1f;
+
+ if ( alu != 0 )
+ p += sprintf(p, "%s, ", ALU(alu) );
+
+ switch( op )
+ {
+ case 0x0c: /* a = RAM[addr], b = BRAM[addr] */
+ p += sprintf(p,"LAB RAM(0x%x)->a,BRAM(0x%x)->b",r1,r2);
+ break;
+
+ case 0x0d: /* a = RAM[addr], b = BRAM[addr] */
+ p += sprintf(p,"LAB RAM(0x%x)->a,BRAM(%s)->b",r1,INDIRECT(r2|(2<<6),0));
+ break;
+
+ case 0x0f: /* a = RAM[addr], b = BRAM[reg] */
+ p += sprintf(p,"LAB RAM(0x%x)->a,BRAM(%s)->b",r1,INDIRECT(r2|(6<<6),0));
+ break;
+
+ case 0x10: /* a = BRAM[reg], b = RAM[addr] */
+ p += sprintf(p,"LAB BRAM(%s)->a,RAM(0x%x)->b",INDIRECT(r1,1),r2);
+ break;
+
+ default:
+ p += sprintf(p,"UNKDUAL (%x)",op);
+ break;
+ }
+ }
+ break;
+
+ case 0x7: /* LD/MOV */
+ {
+ UINT32 r1=opcode & 0x1ff;
+ UINT32 r2=(opcode>>9) & 0x7f;
+ UINT32 alu=(opcode>>21) & 0x1f;
+ UINT32 op=(opcode>>16) & 0x1f;
+
+ if ( alu != 0 )
+ {
+ p += sprintf(p, "%s", ALU(alu) );
+
+ if ( !(op == 0x1f && r1 == 0x10 && r2 == 0x0f) )
+ p += sprintf(p, ", ");
+ }
+
+ switch(op)
+ {
+ case 0x03: /* RAM->External Indirect */
+ {
+ p += sprintf(p,"MOV RAM(0x%x)->E(EB+%s)",r1,INDIRECT(r2|(6<<6),0));
+ }
+ break;
+
+ case 0x04: /* MOV RAM->External */
+ {
+ p += sprintf(p,"MOV RAM(0x%x)->E(EB+0x%x)",r1,r2);
+ }
+ break;
+
+ case 0x07: /* RAMInd->External */
+ {
+ p += sprintf(p,"MOV RAM(%s)->E(EB+%s)",INDIRECT(r1,1),INDIRECT(r2|(6<<6),0));
+ }
+ break;
+
+ case 0x08: /* External->RAM */
+ {
+ p += sprintf(p,"MOV EXT(EB+");
+ p += sprintf(p,"%s",INDIRECT(r1,1));
+ p += sprintf(p,")->RAM(0x%x)",r2);
+ }
+ break;
+
+ case 0x0b: /* External->RAMInd */
+ {
+ int mode = ( r1 >> 6 ) & 0x07;
+
+ p += sprintf(p,"MOV EXT(EB+");
+
+ if ( mode == 0 || mode == 3 || mode == 1 )
+ p += sprintf(p,"RAM(");
+
+ p += sprintf(p,"%s",INDIRECT(r1,1));
+
+ if ( mode == 0 || mode == 3 || mode == 1)
+ p += sprintf(p,")");
+
+ p += sprintf(p,")->RAM(%s)",INDIRECT(r2|(6<<6),0));
+ }
+ break;
+
+ case 0x0c: /* MOV RAM->BRAM */
+ p += sprintf(p,"MOV RAM(0x%x)->BRAM(0x%x)",r1,r2);
+ break;
+
+ case 0x0f: /* MOV RAMInd->BRAMInd */
+ p += sprintf(p,"MOV RAM(%s)->BRAM(%s)",INDIRECT(r1,1),INDIRECT(r2|(6<<6),0));
+ break;
+
+ case 0x10: /* MOV BRAMInd->RAM */
+ p += sprintf(p,"MOV BRAM(%s)->RAM(0x%x)",INDIRECT(r1,1),r2);
+ break;
+
+ case 0x13: /* MOV BRAMInd->RAMInd */
+ p += sprintf(p,"MOV BRAM(%s)->RAM(%s)",INDIRECT(r1,1),INDIRECT(r2|(6<<6),0));
+ break;
+
+ case 0x1c: /* MOV Reg->RAMInd */
+ if ( ( r2 >> 6 ) & 0x01)
+ {
+ p += sprintf(p,"MOV %s->EXT(EB+%s)",REGS(r2,1),INDIRECT(r1,0));
+ }
+ else
+ {
+ p += sprintf(p,"MOV %s->RAM(%s)",REGS(r2,1),INDIRECT(r1,0));
+ }
+ break;
+
+ case 0x1d: /* MOV RAM->Reg */
+ {
+ if ( r1 & 0x180 )
+ {
+ p += sprintf(p,"MOV RAM(%s)->%s",REGS(r1,0),REGS(r2,0));
+ }
+ else
+ {
+ p += sprintf(p,"MOV RAM(0x%x)->%s",r1,REGS(r2,0));
+ }
+ }
+ break;
+
+ case 0x1e: /* External->Reg */
+ {
+ int mode2 = (r2 >> 6) & 1;
+ p += sprintf(p,"MOV EXT(EB+%s)->%s",INDIRECT(r1,mode2),REGS(r2,0));
+ }
+ break;
+
+ case 0x1f: /* MOV Reg->Reg */
+ if ( !(r1 == 0x10 && r2 == 0x0f) )
+ {
+ p += sprintf(p,"MOV %s->%s",REGS(r1,1),REGS(r2,0));
+ }
+ break;
+
+ default:
+ p += sprintf(p,"UNKMV (0x%x)",op);
+ break;
+ }
+ }
+ break;
+
+ case 0x0e: /* Load 24 bit val */
+ {
+ UINT32 sub=(opcode>>24)&0x3;
+ const char regs[4] = { 'p', 'a', 'b', 'd' };
+
+ p += sprintf(p,"LDIMM24 0x%X->%c",opcode&0xffffff, regs[sub]);
+ }
+ break;
+
+ case 0x0f: /* repeat */
+ {
+ UINT32 alu = ( opcode >> 20 ) & 0x1f;
+ UINT32 sub2 = ( opcode >> 16 ) & 0x0f;
+
+ if ( alu != 0 )
+ p += sprintf(p, "%s, ", ALU(alu) );
+
+ if ( sub2 == 0x00 )
+ {
+ p += sprintf(p,"CLEAR ");
+
+ switch( opcode & 0x3f )
+ {
+ case 0x04: p += sprintf(p, "a" ); break;
+ case 0x08: p += sprintf(p, "b" ); break;
+ case 0x10: p += sprintf(p, "d" ); break;
+ default: p += sprintf(p, "UNKNOWN REG(%x)",opcode&0x3F); break;
+ }
+ }
+ else if ( sub2 == 0x02 )
+ p += sprintf(p,"CLRFLAG 0x%x",opcode&0xffff);
+ else if ( sub2==0x4 )
+ {
+ if ( (opcode & 0xfff) == 0 )
+ p += sprintf(p,"REP 0x100");
+ else
+ p += sprintf(p,"REP 0x%x",opcode&0xff);
+ }
+ else if ( sub2 == 0x06 )
+ p += sprintf(p,"SETFLAG 0x%x",opcode&0xffff);
+ }
+ break;
+
+ case 0x10:
+ {
+ UINT32 dst=(opcode>>24)&0xf;
+ UINT32 imm=(opcode)&0xFFFF;
+
+ if ( dst <= 3 )
+ p += sprintf(p,"LDIMM 0x%x->r%d",imm,dst);
+ else
+ p += sprintf(p,"LDIMM 0x%x->UNKDST(0x%x)",imm,dst);
+ }
+ break;
+
+ case 0x13:
+ {
+ UINT32 sub = ( opcode >> 24 ) & 0x03;
+
+ p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff);
+
+ if ( sub == 0 ) p += sprintf(p,"r12");
+ else if ( sub == 1 ) p += sprintf(p,"r13");
+ else p += sprintf(p,"UNKREG(%x)", sub);
+ }
+ break;
+
+ case 0x14:
+ {
+ UINT32 sub = ( opcode >> 24 ) & 0x03;
+
+ p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff);
+
+ if ( sub == 0 ) p += sprintf(p,"a.exp");
+ else if ( sub == 1 ) p += sprintf(p,"a.e");
+ else if ( sub == 2 ) p += sprintf(p,"a.m");
+ else p += sprintf(p,"UNKREG(%x)", sub);
+ }
+ break;
+
+ case 0x15:
+ {
+ UINT32 sub = ( opcode >> 24 ) & 0x03;
+
+ p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff);
+
+ if ( sub == 0 ) p += sprintf(p,"b.exp");
+ else if ( sub == 1 ) p += sprintf(p,"b.e");
+ else if ( sub == 2 ) p += sprintf(p,"b.m");
+ else p += sprintf(p,"UNKREG(%x)", sub);
+ }
+ break;
+
+ case 0x16:
+ {
+ UINT32 sub = ( opcode >> 24 ) & 0x03;
+
+ p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff);
+
+ if ( sub == 2 ) p += sprintf(p,"d.e");
+ else if ( sub == 3 ) p += sprintf(p,"d.m");
+ else p += sprintf(p,"UNKREG(%x)", sub);
+ }
+ break;
+
+ case 0x17:
+ {
+ UINT32 sub = ( opcode >> 24 ) & 0x03;
+
+ p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff);
+
+ if ( sub == 0x03 ) p += sprintf(p,"shift");
+ else p += sprintf(p,"UNKREG(%x)", sub);
+ }
+ break;
+
+ case 0x18:
+ {
+ UINT32 sub = ( opcode >> 24 ) & 0x03;
+
+ p += sprintf(p,"LDIMM24 0x%X->",opcode&0xffffff);
+
+ if ( sub == 0x03 ) p += sprintf(p,"EB");
+ else p += sprintf(p,"UNKREG(%x)", sub);
+ }
+ break;
+
+ case 0x2f:
+ {
+ UINT32 cond = ( opcode >> 20 ) & 0x1f;
+ UINT32 subtype = ( opcode >> 16 ) & 0x0f;
+ UINT32 data = opcode & 0xffff;
+
+ switch( subtype )
+ {
+ case 0:
+ p += sprintf(p,"BRIF %s 0x%X", COND(cond), data);
+ break;
+
+ case 2:
+ p += sprintf(p,"BRIF %s ", COND(cond));
+ if ( data & 0x4000 )
+ p += sprintf(p,"%s",REGS(data&0x3f,0));
+ else
+ p += sprintf(p,"RAM(0x%x)",data);
+ break;
+
+ case 4:
+ p += sprintf(p,"BSIF %s 0x%X", COND(cond), data);
+ break;
+
+ case 0x6:
+ p += sprintf(p,"BSIF %s ", COND(cond));
+ if ( data & 0x4000 )
+ p += sprintf(p,"%s",REGS(data&0x3f,0));
+ else
+ p += sprintf(p,"RAM(0x%x)",data);
+ break;
+
+ case 0xa:
+ p += sprintf(p,"RTIF %s", COND(cond));
+ break;
+
+ case 0xc:
+ p += sprintf(p,"LDIF %s RAM(0x%x)->%s", COND(cond),data&0x1ff,REGS((data>>9)&0x3f,0));
+ break;
+
+ case 0xe:
+ p += sprintf(p,"RIIF %s", COND(cond));
+ break;
+
+ default:
+ p += sprintf(p,"UNKG5 (%x cond %x)",subtype,cond);
+ break;
+ }
+ }
+ break;
+
+ case 0x3f:
+ {
+ UINT32 cond = ( opcode >> 20 ) & 0x1f;
+ UINT32 subtype = ( opcode >> 16 ) & 0x0f;
+ UINT32 data = opcode & 0xffff;
+
+ switch( subtype )
+ {
+ case 0:
+ p += sprintf(p,"BRUL %s 0x%X", COND(cond), data);
+ break;
+
+ case 2:
+ p += sprintf(p,"BRUL %s ", COND(cond));
+ if ( data & 0x4000 )
+ p += sprintf(p,"%s",REGS(data&0x3f,0));
+ else
+ p += sprintf(p,"RAM(0x%x)",data);
+ break;
+
+ case 4:
+ p += sprintf(p,"BSUL %s 0x%X", COND(cond), data);
+ break;
+
+ case 0x6:
+ p += sprintf(p,"BSUL %s ", COND(cond));
+ if ( data & 0x4000 )
+ p += sprintf(p,"%s",REGS(data&0x3f,0));
+ else
+ p += sprintf(p,"RAM(0x%x)",data);
+ break;
+
+ case 0xa:
+ p += sprintf(p,"RTUL %s", COND(cond));
+ break;
+
+ case 0xc:
+ p += sprintf(p,"LDUL %s RAM(0x%x)->%s", COND(cond),data&0x1ff,REGS((data>>9)&0x3f,0));
+ break;
+
+ case 0xe:
+ p += sprintf(p,"RIUL %s", COND(cond));
+ break;
+
+ default:
+ p += sprintf(p,"UNKG5 (%x cond %x)",subtype,cond);
+ break;
+ }
+ }
+ break;
+
+ default:
+ p += sprintf(p,"UNKOP");
+ break;
+ }
+
+ return (1 | DASMFLAG_SUPPORTED);
+}
diff --git a/src/emu/cpu/mb88xx/mb88dasm.c b/src/emu/cpu/mb88xx/mb88dasm.c
new file mode 100644
index 00000000000..f2c6326046c
--- /dev/null
+++ b/src/emu/cpu/mb88xx/mb88dasm.c
@@ -0,0 +1,221 @@
+/*******************************************************************************
+
+ mb88dasm.c
+ Core implementation for the portable Fujitsu MB88xx series MCU disassembler.
+
+ Written by Ernesto Corvi
+
+*******************************************************************************/
+
+#include "mb88xx.h"
+
+
+offs_t mb88_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ unsigned startpc = pc;
+ UINT8 op = oprom[pc++ - startpc];
+ UINT8 arg = oprom[pc - startpc];
+
+ switch( op )
+ {
+ case 0x00: sprintf( buffer, "nop" ); break;
+ case 0x01: sprintf( buffer, "outO (PortO<=A)" ); break;
+ case 0x02: sprintf( buffer, "outP" ); break;
+ case 0x03: sprintf( buffer, "outR (PortR[Y]<=A)" ); break;
+ case 0x04: sprintf( buffer, "tay (Y<=A)" ); break;
+ case 0x05: sprintf( buffer, "tath (TH<=A)" ); break;
+ case 0x06: sprintf( buffer, "tatl (TL<=A)" ); break;
+ case 0x07: sprintf( buffer, "tas (SB<=A)" ); break;
+ case 0x08: sprintf( buffer, "icy (Y++)" ); break;
+ case 0x09: sprintf( buffer, "icm (M[X,Y]++)" ); break;
+ case 0x0A: sprintf( buffer, "stic (M[X,Y]<=A; Y++)" ); break;
+ case 0x0B: sprintf( buffer, "x (A<=>M[X,Y])" ); break;
+ case 0x0C: sprintf( buffer, "rol" ); break;
+ case 0x0D: sprintf( buffer, "load (A<=M[X,Y])" ); break;
+ case 0x0E: sprintf( buffer, "adc (A<=A+M[X,Y]+cf)" ); break;
+ case 0x0F: sprintf( buffer, "and (A<=A & M[X,Y])" ); break;
+ case 0x10: sprintf( buffer, "daa (A<=A+6 if (A>9 | cf=1)" ); break;
+ case 0x11: sprintf( buffer, "das (A<=A+10 if (A>9 | cf=1)" ); break;
+ case 0x12: sprintf( buffer, "inK (A<=PortK)" ); break;
+ case 0x13: sprintf( buffer, "inR (A<=PortR[Y])" ); break;
+ case 0x14: sprintf( buffer, "tya (A<=Y)" ); break;
+ case 0x15: sprintf( buffer, "ttha (A<=TH)" ); break;
+ case 0x16: sprintf( buffer, "ttla (A<=TL)" ); break;
+ case 0x17: sprintf( buffer, "tsa (A<=S)" ); break;
+ case 0x18: sprintf( buffer, "dcy (Y--)" ); break;
+ case 0x19: sprintf( buffer, "dcm (M[X,Y]--)" ); break;
+ case 0x1A: sprintf( buffer, "stdc (M[X,Y]<=A; Y--)" ); break;
+ case 0x1B: sprintf( buffer, "xx (A<=>X)" ); break;
+ case 0x1C: sprintf( buffer, "ror" ); break;
+ case 0x1D: sprintf( buffer, "store (M[X,Y]<=A)" ); break;
+ case 0x1E: sprintf( buffer, "sbc (A<=M[X,Y]-A-cf)" ); break;
+ case 0x1F: sprintf( buffer, "or (A<=A | M[X,Y])" ); break;
+ case 0x20: sprintf( buffer, "setR (PortR bit[Y]<=1)" ); break;
+ case 0x21: sprintf( buffer, "setc (cf<=1)" ); break;
+ case 0x22: sprintf( buffer, "rstR (PortR bit[Y]<=0)" ); break;
+ case 0x23: sprintf( buffer, "rstc (cf<=0)" ); break;
+ case 0x24: sprintf( buffer, "tstR (st<=PortR bit[Y])" ); break;
+ case 0x25: sprintf( buffer, "tsti (st<=IRQ Line)" ); break;
+ case 0x26: sprintf( buffer, "tstv (st<=vf)" ); break;
+ case 0x27: sprintf( buffer, "tsts (st<=sf)" ); break;
+ case 0x28: sprintf( buffer, "tstc (st<=cf)" ); break;
+ case 0x29: sprintf( buffer, "tstz (st<=zf)" ); break;
+ case 0x2A: sprintf( buffer, "sts (M[X,Y]<=SB)" ); break;
+ case 0x2B: sprintf( buffer, "ls (SB<=M[X,Y])" ); break;
+ case 0x2C: sprintf( buffer, "rts" ); break;
+ case 0x2D: sprintf( buffer, "neg (A=-A)" ); break;
+ case 0x2E: sprintf( buffer, "c (A==M[X,Y])" ); break;
+ case 0x2F: sprintf( buffer, "eor (A ^ M[X,Y])" ); break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33: sprintf( buffer, "sbit%d (M[X,Y] bit%d=1)", op&3, op&3 ); break;
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37: sprintf( buffer, "rbit%d (M[X,Y] bit%d=0)", op&3, op&3 ); break;
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B: sprintf( buffer, "tbit%d (M[X,Y] bit%d == 1)", op&3, op&3 ); break;
+ case 0x3C: sprintf( buffer, "rti" ); break;
+ case 0x3D: sprintf( buffer, "jpa #$%02x (jump always)", arg ); pc++; break;
+ case 0x3E: sprintf( buffer, "en #$%02x (enable bits)", arg ); pc++; break;
+ case 0x3F: sprintf( buffer, "dis #$%02x (disable bits)", arg ); pc++; break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43: sprintf( buffer, "setd%d (PortR bit%d<=1)", op&3, op&3 ); break;
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47: sprintf( buffer, "rstd%d (PortR bit%d<=0)", op&3, op&3 ); break;
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B: sprintf( buffer, "tstd%d (PortR bit%d == 1)", (op&3)+8, (op&3)+8 ); break;
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F: sprintf( buffer, "tba%d (A bit%d == 1)", op&3, op&3 ); break;
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53: sprintf( buffer, "xd%d (A<=>M[0,%d])", op&3, op&3 ); break;
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57: sprintf( buffer, "xyd%d (Y<=>M[0,%d])", (op&3)+4, (op&3)+4 ); break;
+ case 0x58:
+ case 0x59:
+ case 0x5A:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x5E:
+ case 0x5F: sprintf( buffer, "lxi #$%1x (X<=$%1x)", op&7, op&7 ); break;
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67: sprintf( buffer, "call %02x%02x (call if st=1)", op&7, arg ); pc++; break;
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F: sprintf( buffer, "jpl %02x%02x (jump if st=1)", op&7, arg ); pc++; break;
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7A:
+ case 0x7B:
+ case 0x7C:
+ case 0x7D:
+ case 0x7E:
+ case 0x7F: sprintf( buffer, "ai #$%1x (A<=A+$%1x)", op&0xf, op&0xf ); break;
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8A:
+ case 0x8B:
+ case 0x8C:
+ case 0x8D:
+ case 0x8E:
+ case 0x8F: sprintf( buffer, "lyi #$%1x (Y<=$%1x)", op&0xf, op&0xf ); break;
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9A:
+ case 0x9B:
+ case 0x9C:
+ case 0x9D:
+ case 0x9E:
+ case 0x9F: sprintf( buffer, "li #$%1x (A<=$%1x)", op&0xf, op&0xf ); break;
+ case 0xA0:
+ case 0xA1:
+ case 0xA2:
+ case 0xA3:
+ case 0xA4:
+ case 0xA5:
+ case 0xA6:
+ case 0xA7:
+ case 0xA8:
+ case 0xA9:
+ case 0xAA:
+ case 0xAB:
+ case 0xAC:
+ case 0xAD:
+ case 0xAE:
+ case 0xAF: sprintf( buffer, "cyi #$%1x (Y==$%1x)", op&0xf, op&0xf ); break;
+ case 0xB0:
+ case 0xB1:
+ case 0xB2:
+ case 0xB3:
+ case 0xB4:
+ case 0xB5:
+ case 0xB6:
+ case 0xB7:
+ case 0xB8:
+ case 0xB9:
+ case 0xBA:
+ case 0xBB:
+ case 0xBC:
+ case 0xBD:
+ case 0xBE:
+ case 0xBF: sprintf( buffer, "ci #$%1x (A==$%1x)", op&0xf, op&0xf ); break;
+
+ default:
+ /* C0-FF */
+ sprintf( buffer, "jmp $%04x (jump if st=1)", (pc&(~0x3f))+ op-0xC0 );
+ break;
+ }
+
+ return (pc - startpc) | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/mb88xx/mb88xx.c b/src/emu/cpu/mb88xx/mb88xx.c
new file mode 100644
index 00000000000..01955113795
--- /dev/null
+++ b/src/emu/cpu/mb88xx/mb88xx.c
@@ -0,0 +1,955 @@
+/***************************************************************************
+
+ mb88xx.c
+ Core implementation for the portable Fujitsu MB88xx series MCU emulator.
+
+ Written by Ernesto Corvi
+
+
+ TODO:
+ - Add support for the timer
+ - Add support for the serial interface
+ - Split the core to support multiple CPU types?
+
+***************************************************************************/
+
+#include "debugger.h"
+#include "mb88xx.h"
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+typedef struct
+{
+ UINT8 PC; /* Program Counter: 6 bits */
+ UINT8 PA; /* Page Address: 4 bits */
+ UINT16 SP[4]; /* Stack is 4*10 bit addresses deep, but we also use 3 top bits per address to store flags during irq */
+ UINT8 SI; /* Stack index: 2 bits */
+ UINT8 A; /* Accumulator: 4 bits */
+ UINT8 X; /* Index X: 4 bits */
+ UINT8 Y; /* Index Y: 4 bits */
+ UINT8 st; /* State flag: 1 bit */
+ UINT8 zf; /* Zero flag: 1 bit */
+ UINT8 cf; /* Carry flag: 1 bit */
+ UINT8 vf; /* Timer overflow flag: 1 bit */
+ UINT8 sf; /* Serial Full/Empty flag: 1 bit */
+ UINT8 nf; /* Interrupt flag: 1 bit */
+
+ /* Peripheral Control */
+ UINT8 pio; /* Peripheral enable bits: 8 bits */
+
+ /* Timer registers */
+ UINT8 TH; /* Timer High: 4 bits */
+ UINT8 TL; /* Timer Low: 4 bits */
+
+ /* Serial registers */
+ UINT8 SB; /* Serial buffer: 4 bits */
+
+ /* PLA configuration */
+ UINT8 * PLA;
+
+ /* IRQ handling */
+ int pending_interrupt;
+ int (*irqcallback)(int);
+} mb88Regs;
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static mb88Regs mb88;
+static int mb88_icount;
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define READOP(a) (cpu_readop(a))
+
+#define RDMEM(a) (data_read_byte_8(a))
+#define WRMEM(a,v) (data_write_byte_8((a), (v)))
+
+#define READPORT(a) (io_read_byte_8(a))
+#define WRITEPORT(a,v) (io_write_byte_8((a), (v)))
+
+#define TEST_ST() (mb88.st & 1)
+#define TEST_ZF() (mb88.zf & 1)
+#define TEST_CF() (mb88.cf & 1)
+#define TEST_VF() (mb88.vf & 1)
+#define TEST_SF() (mb88.sf & 1)
+#define TEST_NF() (mb88.nf & 1)
+
+#define UPDATE_ST_C(v) mb88.st=(v&0x10) ? 0 : 1
+#define UPDATE_ST_Z(v) mb88.st=(v==0) ? 0 : 1
+
+#define UPDATE_CF(v) mb88.cf=((v&0x10)==0) ? 0 : 1
+#define UPDATE_ZF(v) mb88.zf=(v!=0) ? 0 : 1
+
+#define CYCLES(x) do { mb88_icount -= (x); } while (0)
+
+#define GETPC() (((int)mb88.PA << 6)+mb88.PC)
+#define GETEA() ((mb88.X << 4)+mb88.Y)
+
+#define INCPC() do { mb88.PC++; if ( mb88.PC >= 0x40 ) { mb88.PC = 0; mb88.PA++; } } while (0)
+
+
+/***************************************************************************
+ CONTEXT SWITCHING
+***************************************************************************/
+
+static void mb88_get_context(void *dst)
+{
+ /* copy the context */
+ *(mb88Regs *)dst = mb88;
+}
+
+
+static void mb88_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ mb88 = *(mb88Regs *)src;
+ change_pc(GETPC());
+}
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+static void mb88_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ if ( config )
+ {
+ const struct MB88Config *_config = (const struct MB88Config*)config;
+ mb88.PLA = _config->PLA_config;
+ }
+
+ mb88.irqcallback = irqcallback;
+
+ state_save_register_item("mb88", clock, mb88.PC);
+ state_save_register_item("mb88", clock, mb88.PA);
+ state_save_register_item("mb88", clock, mb88.SP[0]);
+ state_save_register_item("mb88", clock, mb88.SP[1]);
+ state_save_register_item("mb88", clock, mb88.SP[2]);
+ state_save_register_item("mb88", clock, mb88.SP[3]);
+ state_save_register_item("mb88", clock, mb88.SI);
+ state_save_register_item("mb88", clock, mb88.A);
+ state_save_register_item("mb88", clock, mb88.X);
+ state_save_register_item("mb88", clock, mb88.Y);
+ state_save_register_item("mb88", clock, mb88.st);
+ state_save_register_item("mb88", clock, mb88.zf);
+ state_save_register_item("mb88", clock, mb88.cf);
+ state_save_register_item("mb88", clock, mb88.vf);
+ state_save_register_item("mb88", clock, mb88.sf);
+ state_save_register_item("mb88", clock, mb88.nf);
+ state_save_register_item("mb88", clock, mb88.pio);
+ state_save_register_item("mb88", clock, mb88.TH);
+ state_save_register_item("mb88", clock, mb88.TL);
+ state_save_register_item("mb88", clock, mb88.SB);
+ state_save_register_item("mb88", clock, mb88.pending_interrupt);
+}
+
+static void mb88_reset(void)
+{
+ /* zero registers and flags */
+ mb88.PC = 0;
+ mb88.PA = 0;
+ mb88.PA = 0;
+ mb88.SP[0] = mb88.SP[1] = mb88.SP[2] = mb88.SP[3] = 0;
+ mb88.SI = 0;
+ mb88.A = 0;
+ mb88.X = 0;
+ mb88.Y = 0;
+ mb88.st = 1; /* start off with st=1 */
+ mb88.zf = 0;
+ mb88.cf = 0;
+ mb88.vf = 0;
+ mb88.sf = 0;
+ mb88.nf = 0;
+ mb88.pio = 0;
+ mb88.TH = 0;
+ mb88.TL = 0;
+ mb88.SB = 0;
+ mb88.pending_interrupt = 0;
+}
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+static int pla( int inA, int inB )
+{
+ int index = ((inB&1) << 4) | (inA&0x0f);
+
+ if ( mb88.PLA )
+ return mb88.PLA[index];
+
+ return index;
+}
+
+static void set_irq_line(int state)
+{
+ /* on falling edge trigger interrupt */
+ if ( (mb88.pio & 0x04) && mb88.nf && state == CLEAR_LINE )
+ {
+ mb88.pending_interrupt = 1;
+ }
+
+ mb88.nf = (state != CLEAR_LINE) ? 1 : 0;
+}
+
+static void update_pio( void )
+{
+ /* update interrupts, serial and timer flags */
+
+ if ( (mb88.pio & 0x04) && mb88.pending_interrupt )
+ {
+ /* no vectors supported, just do the callback to clear irq_state if needed */
+ if (mb88.irqcallback)
+ (*mb88.irqcallback)(0);
+
+ mb88.SP[mb88.SI] = GETPC();
+ mb88.SP[mb88.SI] |= TEST_CF() << 15;
+ mb88.SP[mb88.SI] |= TEST_ZF() << 14;
+ mb88.SP[mb88.SI] |= TEST_ST() << 13;
+ mb88.SI = ( mb88.SI + 1 ) & 3;
+ mb88.PC = 0x02;
+ mb88.PA = 0x00;
+ mb88.st = 1;
+ change_pc(GETPC());
+
+ mb88.pending_interrupt = 0;
+
+ CYCLES(3); /* ? */
+ }
+
+ /* TODO: add support for serial and timer */
+}
+
+static int mb88_execute(int cycles)
+{
+ mb88_icount = cycles;
+
+ while (mb88_icount >= 0)
+ {
+ UINT8 opcode, arg, oc;
+
+ /* fetch the opcode */
+ CALL_MAME_DEBUG;
+ opcode = READOP(GETPC());
+
+ /* increment the PC */
+ INCPC();
+
+ /* start with instruction doing 1 cycle */
+ oc = 1;
+
+ switch (opcode)
+ {
+ case 0x00: /* nop ZCS:...*/
+ mb88.st = 1;
+ break;
+
+ case 0x01: /* outO ZCS:...*/
+ WRITEPORT( MB88_PORTO, pla(mb88.A,TEST_CF()) );
+ mb88.st = 1;
+ break;
+
+ case 0x02: /* outP ZCS:... */
+ WRITEPORT( MB88_PORTP, mb88.A );
+ mb88.st = 1;
+ break;
+
+ case 0x03: /* outR ZCS:... */
+ arg = mb88.Y;
+ WRITEPORT( MB88_PORTR0+(arg&3), mb88.A );
+ mb88.st = 1;
+ break;
+
+ case 0x04: /* tay ZCS:... */
+ mb88.Y = mb88.A;
+ mb88.st = 1;
+ break;
+
+ case 0x05: /* tath ZCS:... */
+ mb88.TH = mb88.A;
+ mb88.st = 1;
+ break;
+
+ case 0x06: /* tatl ZCS:... */
+ mb88.TL = mb88.A;
+ mb88.st = 1;
+ break;
+
+ case 0x07: /* tas ZCS:... */
+ mb88.SB = mb88.A;
+ mb88.st = 1;
+ break;
+
+ case 0x08: /* icy ZCS:x.x */
+ mb88.Y++;
+ UPDATE_ST_C(mb88.Y);
+ mb88.Y &= 0x0f;
+ UPDATE_ZF(mb88.Y);
+ break;
+
+ case 0x09: /* icm ZCS:x.x */
+ arg=RDMEM(GETEA());
+ arg++;
+ UPDATE_ST_C(arg);
+ arg &= 0x0f;
+ UPDATE_ZF(arg);
+ WRMEM(GETEA(),arg);
+ break;
+
+ case 0x0a: /* stic ZCS:x.x */
+ WRMEM(GETEA(),mb88.A);
+ mb88.Y++;
+ UPDATE_ST_C(mb88.Y);
+ mb88.Y &= 0x0f;
+ UPDATE_ZF(mb88.Y);
+ break;
+
+ case 0x0b: /* x ZCS:x.. */
+ arg = RDMEM(GETEA());
+ WRMEM(GETEA(),mb88.A);
+ mb88.A = arg;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x0c: /* rol ZCS:xxx */
+ mb88.A <<= 1;
+ mb88.A |= TEST_CF();
+ UPDATE_ST_C(mb88.A);
+ mb88.cf = mb88.st ^ 1;
+ mb88.A &= 0x0f;
+ UPDATE_ZF(mb88.A);
+ break;
+
+ case 0x0d: /* l ZCS:x.. */
+ mb88.A = RDMEM(GETEA());
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x0e: /* adc ZCS:xxx */
+ arg = RDMEM(GETEA());
+ arg += mb88.A;
+ arg += TEST_CF();
+ UPDATE_ST_C(arg);
+ mb88.cf = mb88.st ^ 1;
+ mb88.A = arg & 0x0f;
+ UPDATE_ZF(mb88.A);
+ break;
+
+ case 0x0f: /* and ZCS:x.x */
+ mb88.A &= RDMEM(GETEA());
+ UPDATE_ZF(mb88.A);
+ mb88.st = mb88.zf ^ 1;
+ break;
+
+ case 0x10: /* daa ZCS:.xx */
+ if ( TEST_CF() || mb88.A > 9 ) mb88.A += 6;
+ UPDATE_ST_C(mb88.A);
+ mb88.cf = mb88.st ^ 1;
+ mb88.A &= 0x0f;
+ break;
+
+ case 0x11: /* das ZCS:.xx */
+ if ( TEST_CF() || mb88.A > 9 ) mb88.A += 10;
+ UPDATE_ST_C(mb88.A);
+ mb88.cf = mb88.st ^ 1;
+ mb88.A &= 0x0f;
+ break;
+
+ case 0x12: /* inK ZCS:x.. */
+ mb88.A = READPORT( MB88_PORTK ) & 0x0f;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x13: /* inR ZCS:x.. */
+ arg = mb88.Y;
+ mb88.A = READPORT( MB88_PORTR0+(arg&3) ) & 0x0f;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x14: /* tya ZCS:x.. */
+ mb88.A = mb88.Y;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x15: /* ttha ZCS:x.. */
+ mb88.A = mb88.TH;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x16: /* ttla ZCS:x.. */
+ mb88.A = mb88.TL;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x17: /* tsa ZCS:x.. */
+ mb88.A = mb88.SB;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x18: /* dcy ZCS:..x */
+ mb88.Y--;
+ UPDATE_ST_C(mb88.Y);
+ mb88.Y &= 0x0f;
+ break;
+
+ case 0x19: /* dcm ZCS:x.x */
+ arg=RDMEM(GETEA());
+ arg--;
+ UPDATE_ST_C(arg);
+ arg &= 0x0f;
+ UPDATE_ZF(arg);
+ WRMEM(GETEA(),arg);
+ break;
+
+ case 0x1a: /* stdc ZCS:x.x */
+ WRMEM(GETEA(),mb88.A);
+ mb88.Y--;
+ UPDATE_ST_C(mb88.Y);
+ mb88.Y &= 0x0f;
+ UPDATE_ZF(mb88.Y);
+ break;
+
+ case 0x1b: /* xx ZCS:x.. */
+ arg = mb88.X;
+ mb88.X = mb88.A;
+ mb88.A = arg;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x1c: /* ror ZCS:xxx */
+ mb88.A |= TEST_CF() << 4;
+ UPDATE_ST_C(mb88.A << 4);
+ mb88.cf = mb88.st ^ 1;
+ mb88.A >>= 1;
+ mb88.A &= 0x0f;
+ UPDATE_ZF(mb88.A);
+ break;
+
+ case 0x1d: /* st ZCS:x.. */
+ WRMEM(GETEA(),mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x1e: /* sbc ZCS:xxx */
+ arg = RDMEM(GETEA());
+ arg -= mb88.A;
+ arg -= TEST_CF();
+ UPDATE_ST_C(arg);
+ mb88.cf = mb88.st ^ 1;
+ mb88.A = arg & 0x0f;
+ UPDATE_ZF(mb88.A);
+ break;
+
+ case 0x1f: /* or ZCS:x.x */
+ mb88.A |= RDMEM(GETEA());
+ UPDATE_ZF(mb88.A);
+ mb88.st = mb88.zf ^ 1;
+ break;
+
+ case 0x20: /* setR ZCS:... */
+ arg = READPORT( MB88_PORTR0+(mb88.Y/4) );
+ WRITEPORT( MB88_PORTR0+(mb88.Y/4), arg | ( 1 << (mb88.Y%4) ) );
+ mb88.st = 1;
+ break;
+
+ case 0x21: /* setc ZCS:.xx */
+ mb88.cf = 1;
+ mb88.st = 1;
+ break;
+
+ case 0x22: /* rstR ZCS:... */
+ arg = READPORT( MB88_PORTR0+(mb88.Y/4) );
+ WRITEPORT( MB88_PORTR0+(mb88.Y/4), arg & ~( 1 << (mb88.Y%4) ) );
+ mb88.st = 1;
+ break;
+
+ case 0x23: /* rstc ZCS:.xx */
+ mb88.cf = 0;
+ mb88.st = 1;
+ break;
+
+ case 0x24: /* tstr ZCS:..x */
+ arg = READPORT( MB88_PORTR0+(mb88.Y/4) );
+ mb88.st = ( arg & ( 1 << (mb88.Y%4) ) ) ? 1 : 0;
+ break;
+
+ case 0x25: /* tsti ZCS:..x */
+ mb88.st = mb88.nf ^ 1;
+ break;
+
+ case 0x26: /* tstv ZCS:..x */
+ mb88.st = mb88.vf ^ 1;
+ break;
+
+ case 0x27: /* tsts ZCS:..x */
+ mb88.st = mb88.sf ^ 1;
+ break;
+
+ case 0x28: /* tstc ZCS:..x */
+ mb88.st = mb88.cf ^ 1;
+ break;
+
+ case 0x29: /* tstz ZCS:..x */
+ mb88.st = mb88.zf ^ 1;
+ break;
+
+ case 0x2a: /* sts ZCS:x.. */
+ WRMEM(GETEA(),mb88.SB);
+ UPDATE_ZF(mb88.SB);
+ mb88.st = 1;
+ break;
+
+ case 0x2b: /* ls ZCS:x.. */
+ mb88.SB = RDMEM(GETEA());
+ UPDATE_ZF(mb88.SB);
+ mb88.st = 1;
+ break;
+
+ case 0x2c: /* rts ZCS:... */
+ mb88.SI = ( mb88.SI - 1 ) & 3;
+ mb88.PC = mb88.SP[mb88.SI] & 0x3f;
+ mb88.PA = mb88.SP[mb88.SI] >> 6;
+ change_pc(GETPC());
+ mb88.st = 1;
+ break;
+
+ case 0x2d: /* neg ZCS: ..x */
+ mb88.A = (~mb88.A)+1;
+ mb88.A &= 0x0f;
+ UPDATE_ST_Z(mb88.A);
+ break;
+
+ case 0x2e: /* c ZCS:xxx */
+ arg = RDMEM(GETEA());
+ arg -= mb88.A;
+ UPDATE_CF(arg);
+ arg &= 0x0f;
+ UPDATE_ST_Z(arg);
+ mb88.zf = mb88.st ^ 1;
+ break;
+
+ case 0x2f: /* eor ZCS:x.x */
+ mb88.A ^= RDMEM(GETEA());
+ UPDATE_ST_Z(mb88.A);
+ mb88.zf = mb88.st ^ 1;
+ break;
+
+ case 0x30: case 0x31: case 0x32: case 0x33: /* sbit ZCS:... */
+ arg = RDMEM(GETEA());
+ WRMEM(GETEA(), arg | (1 << (opcode&3)));
+ mb88.st = 1;
+ break;
+
+ case 0x34: case 0x35: case 0x36: case 0x37: /* rbit ZCS:... */
+ arg = RDMEM(GETEA());
+ WRMEM(GETEA(), arg & ~(1 << (opcode&3)));
+ mb88.st = 1;
+ break;
+
+ case 0x38: case 0x39: case 0x3a: case 0x3b: /* tbit ZCS:... */
+ arg = RDMEM(GETEA());
+ mb88.st = ( arg & (1 << (opcode&3) ) ) ? 1 : 0;
+ break;
+
+ case 0x3c: /* rti ZCS:... */
+ /* restore address and saved state flags on the top bits of the stack */
+ mb88.SI = ( mb88.SI - 1 ) & 3;
+ mb88.PC = mb88.SP[mb88.SI] & 0x3f;
+ mb88.PA = mb88.SP[mb88.SI] >> 6;
+ mb88.st = (mb88.SP[mb88.SI] >> 13)&1;
+ mb88.zf = (mb88.SP[mb88.SI] >> 14)&1;
+ mb88.cf = (mb88.SP[mb88.SI] >> 15)&1;
+ change_pc(GETPC());
+ break;
+
+ case 0x3d: /* jpa imm ZCS:..x */
+ mb88.PA = READOP(GETPC()) & 0x1f;
+ mb88.PC = mb88.A * 4;
+ oc = 2;
+ mb88.st = 1;
+ break;
+
+ case 0x3e: /* en imm ZCS:... */
+ mb88.pio |= READOP(GETPC());
+ INCPC();
+ oc = 2;
+ mb88.st = 1;
+ break;
+
+ case 0x3f: /* dis imm ZCS:... */
+ mb88.pio &= ~(READOP(GETPC()));
+ INCPC();
+ oc = 2;
+ mb88.st = 1;
+ break;
+
+ case 0x40: case 0x41: case 0x42: case 0x43: /* setD ZCS:... */
+ arg = READPORT(MB88_PORTR0);
+ arg |= (1 << (opcode&3));
+ WRITEPORT(MB88_PORTR0,arg);
+ mb88.st = 1;
+ break;
+
+ case 0x44: case 0x45: case 0x46: case 0x47: /* rstD ZCS:... */
+ arg = READPORT(MB88_PORTR0);
+ arg &= ~(1 << (opcode&3));
+ WRITEPORT(MB88_PORTR0,arg);
+ mb88.st = 1;
+ break;
+
+ case 0x48: case 0x49: case 0x4a: case 0x4b: /* tstD ZCS:..x */
+ arg = READPORT(MB88_PORTR2);
+ mb88.st = (arg & (1 << (opcode&3))) ? 1 : 0;
+ break;
+
+ case 0x4c: case 0x4d: case 0x4e: case 0x4f: /* tba ZCS:..x */
+ mb88.st = (mb88.A & (1 << (opcode&3))) ? 1 : 0;
+ break;
+
+ case 0x50: case 0x51: case 0x52: case 0x53: /* xd ZCS:x.. */
+ arg = RDMEM(opcode&3);
+ WRMEM((opcode&3),mb88.A);
+ mb88.A = arg;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0x54: case 0x55: case 0x56: case 0x57: /* xyd ZCS:x.. */
+ arg = RDMEM((opcode&3)+4);
+ WRMEM((opcode&3)+4,mb88.Y);
+ mb88.Y = arg;
+ UPDATE_ZF(mb88.Y);
+ mb88.st = 1;
+ break;
+
+ case 0x58: case 0x59: case 0x5a: case 0x5b:
+ case 0x5c: case 0x5d: case 0x5e: case 0x5f: /* lxi ZCS:x.. */
+ mb88.X = opcode & 7;
+ UPDATE_ZF(mb88.X);
+ mb88.st = 1;
+ break;
+
+ case 0x60: case 0x61: case 0x62: case 0x63:
+ case 0x64: case 0x65: case 0x66: case 0x67: /* call imm ZCS:..x */
+ arg = READOP(GETPC());
+ INCPC();
+ oc = 2;
+ if ( TEST_ST() )
+ {
+ mb88.SP[mb88.SI] = GETPC();
+ mb88.SI = ( mb88.SI + 1 ) & 3;
+ mb88.PC = arg & 0x3f;
+ mb88.PA = ( ( opcode & 7 ) << 2 ) | ( arg >> 6 );
+ change_pc(GETPC());
+
+ }
+ mb88.st = 1;
+ break;
+
+ case 0x68: case 0x69: case 0x6a: case 0x6b:
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f: /* jpl imm ZCS:..x */
+ arg = READOP(GETPC());
+ INCPC();
+ oc = 2;
+ if ( TEST_ST() )
+ {
+ mb88.PC = arg & 0x3f;
+ mb88.PA = ( ( opcode & 7 ) << 2 ) | ( arg >> 6 );
+ change_pc(GETPC());
+ }
+ mb88.st = 1;
+ break;
+
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b:
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f: /* ai ZCS:xxx */
+ arg = opcode & 0x0f;
+ arg += mb88.A;
+ UPDATE_ST_C(arg);
+ mb88.cf = mb88.st ^ 1;
+ mb88.A = arg & 0x0f;
+ UPDATE_ZF(mb88.A);
+ break;
+
+ case 0x80: case 0x81: case 0x82: case 0x83:
+ case 0x84: case 0x85: case 0x86: case 0x87:
+ case 0x88: case 0x89: case 0x8a: case 0x8b:
+ case 0x8c: case 0x8d: case 0x8e: case 0x8f: /* lxi ZCS:x.. */
+ mb88.Y = opcode & 0x0f;
+ UPDATE_ZF(mb88.Y);
+ mb88.st = 1;
+ break;
+
+ case 0x90: case 0x91: case 0x92: case 0x93:
+ case 0x94: case 0x95: case 0x96: case 0x97:
+ case 0x98: case 0x99: case 0x9a: case 0x9b:
+ case 0x9c: case 0x9d: case 0x9e: case 0x9f: /* li ZCS:x.. */
+ mb88.A = opcode & 0x0f;
+ UPDATE_ZF(mb88.A);
+ mb88.st = 1;
+ break;
+
+ case 0xa0: case 0xa1: case 0xa2: case 0xa3:
+ case 0xa4: case 0xa5: case 0xa6: case 0xa7:
+ case 0xa8: case 0xa9: case 0xaa: case 0xab:
+ case 0xac: case 0xad: case 0xae: case 0xaf: /* cyi ZCS:xxx */
+ arg = mb88.Y - (opcode & 0x0f);
+ UPDATE_CF(arg);
+ arg &= 0x0f;
+ UPDATE_ST_Z(arg);
+ mb88.zf = mb88.st ^ 1;
+ break;
+
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3:
+ case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ case 0xb8: case 0xb9: case 0xba: case 0xbb:
+ case 0xbc: case 0xbd: case 0xbe: case 0xbf: /* ci ZCS:xxx */
+ arg = mb88.A - (opcode & 0x0f);
+ UPDATE_CF(arg);
+ arg &= 0x0f;
+ UPDATE_ST_Z(arg);
+ mb88.zf = mb88.st ^ 1;
+ break;
+
+ default: /* jmp ZCS:..x */
+ if ( TEST_ST() )
+ {
+ mb88.PC = opcode & 0x3f;
+ change_pc(GETPC());
+ }
+ mb88.st = 1;
+ break;
+ }
+
+ /* update cycle counts */
+ CYCLES( oc );
+
+ /* update interrupts, serial and timer flags */
+ update_pio();
+ }
+
+ return cycles - mb88_icount;
+}
+
+/***************************************************************************
+ INFORMATION SETTERS
+***************************************************************************/
+
+static void mb88_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + MB88_IRQ_LINE: set_irq_line(info->i); break;
+
+ case CPUINFO_INT_PC:
+ mb88.PC = info->i & 0x3f;
+ mb88.PA = (info->i >> 6) & 0x1f;
+ change_pc(GETPC());
+ break;
+ case CPUINFO_INT_REGISTER + MB88_PC: mb88.PC = info->i; break;
+ case CPUINFO_INT_REGISTER + MB88_PA: mb88.PA = info->i; break;
+ case CPUINFO_INT_REGISTER + MB88_FLAGS:
+ mb88.st = (info->i & 0x01) ? 1 : 0;
+ mb88.zf = (info->i & 0x02) ? 1 : 0;
+ mb88.cf = (info->i & 0x04) ? 1 : 0;
+ mb88.vf = (info->i & 0x08) ? 1 : 0;
+ mb88.sf = (info->i & 0x10) ? 1 : 0;
+ mb88.nf = (info->i & 0x20) ? 1 : 0;
+ break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + MB88_SI: mb88.SI = info->i & 0x03; break;
+ case CPUINFO_INT_REGISTER + MB88_A: mb88.A = info->i & 0x0f; break;
+ case CPUINFO_INT_REGISTER + MB88_X: mb88.X = info->i & 0x0f; break;
+ case CPUINFO_INT_REGISTER + MB88_Y: mb88.Y = info->i & 0x0f; break;
+ case CPUINFO_INT_REGISTER + MB88_PIO: mb88.pio = info->i & 0xff; break;
+ case CPUINFO_INT_REGISTER + MB88_TH: mb88.TH = info->i & 0x0f; break;
+ case CPUINFO_INT_REGISTER + MB88_TL: mb88.TL = info->i & 0x0f; break;
+ case CPUINFO_INT_REGISTER + MB88_SB: mb88.SB = info->i & 0x0f; break;
+ }
+}
+
+/***************************************************************************
+ INFORMATION GETTERS
+***************************************************************************/
+
+void mb88_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(mb88Regs); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 3; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 11; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 7; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 3; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + MB88_IRQ_LINE: info->i = mb88.pending_interrupt ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC: info->i = GETPC(); break;
+ case CPUINFO_INT_REGISTER + MB88_PC: info->i = mb88.PC; break;
+ case CPUINFO_INT_REGISTER + MB88_PA: info->i = mb88.PA; break;
+ case CPUINFO_INT_REGISTER + MB88_FLAGS: info->i = 0;
+ if (TEST_ST()) info->i |= 0x01;
+ if (TEST_ZF()) info->i |= 0x02;
+ if (TEST_CF()) info->i |= 0x04;
+ if (TEST_VF()) info->i |= 0x08;
+ if (TEST_SF()) info->i |= 0x10;
+ if (TEST_NF()) info->i |= 0x20;
+ break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + MB88_SI: info->i = mb88.SI; break;
+ case CPUINFO_INT_REGISTER + MB88_A: info->i = mb88.A; break;
+ case CPUINFO_INT_REGISTER + MB88_X: info->i = mb88.X; break;
+ case CPUINFO_INT_REGISTER + MB88_Y: info->i = mb88.Y; break;
+ case CPUINFO_INT_REGISTER + MB88_PIO: info->i = mb88.pio; break;
+ case CPUINFO_INT_REGISTER + MB88_TH: info->i = mb88.TH; break;
+ case CPUINFO_INT_REGISTER + MB88_TL: info->i = mb88.TL; break;
+ case CPUINFO_INT_REGISTER + MB88_SB: info->i = mb88.SB; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mb88_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = mb88_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = mb88_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = mb88_init; break;
+ case CPUINFO_PTR_RESET: info->reset = mb88_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = NULL; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = mb88_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = mb88_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &mb88_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MB88xx"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Fujitsu MB88xx"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 2007 Ernesto Corvi"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c",
+ TEST_ST() ? 'T' : 't',
+ TEST_ZF() ? 'Z' : 'z',
+ TEST_CF() ? 'C' : 'c',
+ TEST_VF() ? 'V' : 'v',
+ TEST_SF() ? 'S' : 's',
+ TEST_NF() ? 'I' : 'i');
+ break;
+
+ case CPUINFO_STR_REGISTER + MB88_FLAGS:
+ sprintf(info->s, "FL:%c%c%c%c%c%c",
+ TEST_ST() ? 'T' : 't',
+ TEST_ZF() ? 'Z' : 'z',
+ TEST_CF() ? 'C' : 'c',
+ TEST_VF() ? 'V' : 'v',
+ TEST_SF() ? 'S' : 's',
+ TEST_NF() ? 'I' : 'i');
+ break;
+
+ case CPUINFO_STR_REGISTER + MB88_PC: sprintf(info->s, "PC:%02X", mb88.PC); break;
+ case CPUINFO_STR_REGISTER + MB88_PA: sprintf(info->s, "PA:%02X", mb88.PA); break;
+ case CPUINFO_STR_REGISTER + MB88_SI: sprintf(info->s, "SI:%1X", mb88.SI); break;
+ case CPUINFO_STR_REGISTER + MB88_A: sprintf(info->s, "A:%1X", mb88.A); break;
+ case CPUINFO_STR_REGISTER + MB88_X: sprintf(info->s, "X:%1X", mb88.X); break;
+ case CPUINFO_STR_REGISTER + MB88_Y: sprintf(info->s, "Y:%1X", mb88.Y); break;
+ case CPUINFO_STR_REGISTER + MB88_PIO: sprintf(info->s, "PIO:%02X", mb88.pio); break;
+ case CPUINFO_STR_REGISTER + MB88_TH: sprintf(info->s, "TH:%1X", mb88.TH); break;
+ case CPUINFO_STR_REGISTER + MB88_TL: sprintf(info->s, "TL:%1X", mb88.TL); break;
+ case CPUINFO_STR_REGISTER + MB88_SB: sprintf(info->s, "SB:%1X", mb88.SB); break;
+ }
+}
+
+void mb8841_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 11; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 7; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MB8841"); break;
+
+ default: mb88_get_info(state, info); break;
+ }
+}
+
+void mb8842_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 11; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 7; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MB8842"); break;
+
+ default: mb88_get_info(state, info); break;
+ }
+}
+
+void mb8843_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 10; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 6; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MB8843"); break;
+
+ default: mb88_get_info(state, info); break;
+ }
+}
+
+void mb8844_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 10; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 6; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MB8844"); break;
+
+ default: mb88_get_info(state, info); break;
+ }
+}
diff --git a/src/emu/cpu/mb88xx/mb88xx.h b/src/emu/cpu/mb88xx/mb88xx.h
new file mode 100644
index 00000000000..3b8033d23f5
--- /dev/null
+++ b/src/emu/cpu/mb88xx/mb88xx.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+
+ mb88xx.h
+ Core implementation for the portable Fujitsu MB88xx series MCU emulator.
+
+ Written by Ernesto Corvi
+
+***************************************************************************/
+
+#ifndef _MB88xx_H_
+#define _MB88xx_H_
+
+#ifndef INLINE
+#define INLINE static inline
+#endif
+
+#include "cpuintrf.h"
+
+/***************************************************************************
+ PORT ENUMERATION
+***************************************************************************/
+
+enum
+{
+ MB88_PORTK = 0, /* input only, 4 bits */
+ MB88_PORTO, /* output only, PLA function output */
+ MB88_PORTP, /* 4 bits */
+ MB88_PORTR0, /* R0-R3, 4 bits */
+ MB88_PORTR1, /* R4-R7, 4 bits */
+ MB88_PORTR2, /* R8-R11, 4 bits */
+ MB88_PORTR3 /* R12-R15, 4 bits */
+};
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ MB88_PC=1,
+ MB88_PA,
+ MB88_FLAGS,
+ MB88_SI,
+ MB88_A,
+ MB88_X,
+ MB88_Y,
+ MB88_PIO,
+ MB88_TH,
+ MB88_TL,
+ MB88_SB
+};
+
+#define MB88_IRQ_LINE 0
+
+/***************************************************************************
+ CONFIG STRUCTURE
+***************************************************************************/
+
+struct MB88Config
+{
+ UINT8 *PLA_config; /* PLA configuration (32 byte values), if NULL assume direct output */
+};
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+void mb88_get_info(UINT32 state, cpuinfo *info);
+void mb8841_get_info(UINT32 state, cpuinfo *info);
+void mb8842_get_info(UINT32 state, cpuinfo *info);
+void mb8843_get_info(UINT32 state, cpuinfo *info);
+void mb8844_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+offs_t mb88_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif
diff --git a/src/emu/cpu/mc68hc11/hc11dasm.c b/src/emu/cpu/mc68hc11/hc11dasm.c
new file mode 100644
index 00000000000..062ab81d3b6
--- /dev/null
+++ b/src/emu/cpu/mc68hc11/hc11dasm.c
@@ -0,0 +1,1297 @@
+/*
+ Motorola M68HC11 disassembler
+
+ Written by Ville Linde
+*/
+
+#include "cpuintrf.h"
+#include <stdarg.h>
+
+enum {
+ EA_IMM8 = 1,
+ EA_IMM16,
+ EA_EXT,
+ EA_REL,
+ EA_DIRECT,
+ EA_DIRECT_IMM8,
+ EA_DIRECT_IMM8_REL,
+ EA_IND_X,
+ EA_IND_X_IMM8,
+ EA_IND_X_IMM8_REL,
+ EA_IND_Y,
+ EA_IND_Y_IMM8,
+ EA_IND_Y_IMM8_REL,
+ PAGE2,
+ PAGE3,
+ PAGE4,
+};
+
+typedef struct {
+ char mnemonic[32];
+ int address_mode;
+} M68HC11_OPCODE;
+
+static M68HC11_OPCODE opcode_table[256] =
+{
+ /* 0x00 - 0x0f */
+ { "test", 0, },
+ { "nop", 0, },
+ { "idiv", 0, },
+ { "fdiv", 0, },
+ { "lsrd", 0, },
+ { "asld", 0, },
+ { "tap", 0, },
+ { "tpa", 0, },
+ { "inx", 0, },
+ { "dex", 0, },
+ { "clv", 0, },
+ { "sev", 0, },
+ { "clc", 0, },
+ { "sec", 0, },
+ { "cli", 0, },
+ { "sei", 0, },
+ /* 0x10 - 0x1f */
+ { "sba", 0, },
+ { "cba", 0, },
+ { "brset", EA_DIRECT_IMM8_REL, },
+ { "brclr", EA_DIRECT_IMM8_REL, },
+ { "bset", EA_DIRECT_IMM8, },
+ { "bclr", EA_DIRECT_IMM8, },
+ { "tab", 0, },
+ { "tba", 0, },
+ { "page2", PAGE2, },
+ { "daa", 0, },
+ { "page3", PAGE3, },
+ { "aba", 0, },
+ { "bset", EA_IND_X_IMM8, },
+ { "bclr", EA_IND_X_IMM8, },
+ { "brset", EA_IND_X_IMM8_REL, },
+ { "brclr", EA_IND_X_IMM8_REL, },
+ /* 0x20 - 0x2f */
+ { "bra", EA_REL, },
+ { "brn", EA_REL, },
+ { "bhi", EA_REL, },
+ { "bls", EA_REL, },
+ { "bcc", EA_REL, },
+ { "bcs", EA_REL, },
+ { "bne", EA_REL, },
+ { "beq", EA_REL, },
+ { "bvc", EA_REL, },
+ { "bvs", EA_REL, },
+ { "bpl", EA_REL, },
+ { "bmi", EA_REL, },
+ { "bge", EA_REL, },
+ { "blt", EA_REL, },
+ { "bgt", EA_REL, },
+ { "ble", EA_REL, },
+ /* 0x30 - 0x3f */
+ { "tsx", 0, },
+ { "ins", 0, },
+ { "pula", 0, },
+ { "pulb", 0, },
+ { "des", 0, },
+ { "txs", 0, },
+ { "psha", 0, },
+ { "pshb", 0, },
+ { "pulx", 0, },
+ { "rts", 0, },
+ { "abx", 0, },
+ { "rti", 0, },
+ { "pshx", 0, },
+ { "mul", 0, },
+ { "wai", 0, },
+ { "swi", 0, },
+ /* 0x40 - 0x4f */
+ { "nega", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "coma", 0, },
+ { "lsra", 0, },
+ { "?", 0, },
+ { "rora", 0, },
+ { "asra", 0, },
+ { "asla", 0, },
+ { "rola", 0, },
+ { "deca", 0, },
+ { "?", 0, },
+ { "inca", 0, },
+ { "tsta", 0, },
+ { "?", 0, },
+ { "clra", 0, },
+ /* 0x50 - 0x5f */
+ { "negb", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "comb", 0, },
+ { "lsrb", 0, },
+ { "?", 0, },
+ { "rorb", 0, },
+ { "asrb", 0, },
+ { "aslb", 0, },
+ { "rolb", 0, },
+ { "decb", 0, },
+ { "?", 0, },
+ { "incb", 0, },
+ { "tstb", 0, },
+ { "?", 0, },
+ { "clrb", 0, },
+ /* 0x60 - 0x6f */
+ { "neg", EA_IND_X, },
+ { "?", 0, },
+ { "?", 0, },
+ { "com", EA_IND_X, },
+ { "lsr", EA_IND_X, },
+ { "?", 0, },
+ { "ror", EA_IND_X, },
+ { "asr", EA_IND_X, },
+ { "asl", EA_IND_X, },
+ { "rol", EA_IND_X, },
+ { "dec", EA_IND_X, },
+ { "?", 0, },
+ { "inc", EA_IND_X, },
+ { "tst", EA_IND_X, },
+ { "jmp", EA_IND_X, },
+ { "clr", EA_IND_X, },
+ /* 0x70 - 0x7f */
+ { "neg", EA_EXT, },
+ { "?", 0, },
+ { "?", 0, },
+ { "com", EA_EXT, },
+ { "lsr", EA_EXT, },
+ { "?", 0, },
+ { "ror", EA_EXT, },
+ { "asr", EA_EXT, },
+ { "asl", EA_EXT, },
+ { "rol", EA_EXT, },
+ { "dec", EA_EXT, },
+ { "?", 0, },
+ { "inc", EA_EXT, },
+ { "tst", EA_EXT, },
+ { "jmp", EA_EXT, },
+ { "clr", EA_EXT, },
+ /* 0x80 - 0x8f */
+ { "suba", EA_IMM8, },
+ { "cmpa", EA_IMM8, },
+ { "sbca", EA_IMM8, },
+ { "subd", EA_IMM16, },
+ { "anda", EA_IMM8, },
+ { "bita", EA_IMM8, },
+ { "ldaa", EA_IMM8, },
+ { "?", 0, },
+ { "eora", EA_IMM8, },
+ { "adca", EA_IMM8, },
+ { "oraa", EA_IMM8, },
+ { "adda", EA_IMM8, },
+ { "cpx", EA_IMM16, },
+ { "bsr", EA_REL, },
+ { "lds", EA_IMM16, },
+ { "xgdx", 0, },
+ /* 0x90 - 0x9f */
+ { "suba", EA_DIRECT, },
+ { "cmpa", EA_DIRECT, },
+ { "sbca", EA_DIRECT, },
+ { "subd", EA_DIRECT, },
+ { "anda", EA_DIRECT, },
+ { "bita", EA_DIRECT, },
+ { "ldaa", EA_DIRECT, },
+ { "staa", EA_DIRECT, },
+ { "eora", EA_DIRECT, },
+ { "adca", EA_DIRECT, },
+ { "oraa", EA_DIRECT, },
+ { "adda", EA_DIRECT, },
+ { "cpx", EA_DIRECT, },
+ { "jsr", EA_DIRECT, },
+ { "lds", EA_DIRECT, },
+ { "sts", EA_DIRECT, },
+ /* 0xa0 - 0xaf */
+ { "suba", EA_IND_X, },
+ { "cmpa", EA_IND_X, },
+ { "sbca", EA_IND_X, },
+ { "subd", EA_IND_X, },
+ { "anda", EA_IND_X, },
+ { "bita", EA_IND_X, },
+ { "ldaa", EA_IND_X, },
+ { "staa", EA_IND_X, },
+ { "eora", EA_IND_X, },
+ { "adca", EA_IND_X, },
+ { "oraa", EA_IND_X, },
+ { "adda", EA_IND_X, },
+ { "cpx", EA_IND_X, },
+ { "jsr", EA_IND_X, },
+ { "lds", EA_IND_X, },
+ { "sts", EA_IND_X, },
+ /* 0xb0 - 0xbf */
+ { "suba", EA_EXT, },
+ { "cmpa", EA_EXT, },
+ { "sbca", EA_EXT, },
+ { "subd", EA_EXT, },
+ { "anda", EA_EXT, },
+ { "bita", EA_EXT, },
+ { "ldaa", EA_EXT, },
+ { "staa", EA_EXT, },
+ { "eora", EA_EXT, },
+ { "adca", EA_EXT, },
+ { "oraa", EA_EXT, },
+ { "adda", EA_EXT, },
+ { "cpx", EA_EXT, },
+ { "jsr", EA_EXT, },
+ { "lds", EA_EXT, },
+ { "sts", EA_EXT, },
+ /* 0xc0 - 0xcf */
+ { "subb", EA_IMM8, },
+ { "cmpb", EA_IMM8, },
+ { "sbcb", EA_IMM8, },
+ { "addd", EA_IMM16, },
+ { "andb", EA_IMM8, },
+ { "bitb", EA_IMM8, },
+ { "ldab", EA_IMM8, },
+ { "?", 0, },
+ { "eorb", EA_IMM8, },
+ { "adcb", EA_IMM8, },
+ { "orab", EA_IMM8, },
+ { "addb", EA_IMM8, },
+ { "ldd", EA_IMM16, },
+ { "page4", PAGE4, },
+ { "ldx", EA_IMM16, },
+ { "stop", 0, },
+ /* 0xd0 - 0xdf */
+ { "subb", EA_DIRECT, },
+ { "cmpb", EA_DIRECT, },
+ { "sbcb", EA_DIRECT, },
+ { "addd", EA_DIRECT, },
+ { "andb", EA_DIRECT, },
+ { "bitb", EA_DIRECT, },
+ { "ldab", EA_DIRECT, },
+ { "stab", EA_DIRECT, },
+ { "eorb", EA_DIRECT, },
+ { "adcb", EA_DIRECT, },
+ { "orab", EA_DIRECT, },
+ { "addb", EA_DIRECT, },
+ { "ldd", EA_DIRECT, },
+ { "std", EA_DIRECT, },
+ { "ldx", EA_DIRECT, },
+ { "stx", EA_DIRECT, },
+ /* 0xe0 - 0xef */
+ { "subb", EA_IND_X, },
+ { "cmpb", EA_IND_X, },
+ { "sbcb", EA_IND_X, },
+ { "addd", EA_IND_X, },
+ { "andb", EA_IND_X, },
+ { "bitb", EA_IND_X, },
+ { "ldab", EA_IND_X, },
+ { "stab", EA_IND_X, },
+ { "eorb", EA_IND_X, },
+ { "adcb", EA_IND_X, },
+ { "orab", EA_IND_X, },
+ { "addb", EA_IND_X, },
+ { "ldd", EA_IND_X, },
+ { "std", EA_IND_X, },
+ { "ldx", EA_IND_X, },
+ { "stx", EA_IND_X, },
+ /* 0xf0 - 0xff */
+ { "subb", EA_EXT, },
+ { "cmpb", EA_EXT, },
+ { "sbcb", EA_EXT, },
+ { "addd", EA_EXT, },
+ { "andb", EA_EXT, },
+ { "bitb", EA_EXT, },
+ { "ldab", EA_EXT, },
+ { "stab", EA_EXT, },
+ { "eorb", EA_EXT, },
+ { "adcb", EA_EXT, },
+ { "orab", EA_EXT, },
+ { "addb", EA_EXT, },
+ { "ldd", EA_EXT, },
+ { "std", EA_EXT, },
+ { "ldx", EA_EXT, },
+ { "stx", EA_EXT, },
+};
+
+
+/*****************************************************************************/
+
+
+static M68HC11_OPCODE opcode_table_page2[256] =
+{
+ /* 0x00 - 0x0f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "iny", 0, },
+ { "dey", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x10 - 0x1f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "bset", EA_IND_Y_IMM8, },
+ { "bclr", EA_IND_Y_IMM8, },
+ { "brset", EA_IND_Y_IMM8_REL, },
+ { "brlcr", EA_IND_Y_IMM8_REL, },
+ /* 0x20 - 0x2f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x30 - 0x3f */
+ { "tsy", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "tys", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "puly", 0, },
+ { "?", 0, },
+ { "aby", 0, },
+ { "?", 0, },
+ { "pshy", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x40 - 0x4f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x50 - 0x5f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x60 - 0x6f */
+ { "neg", EA_IND_Y, },
+ { "?", 0, },
+ { "?", 0, },
+ { "com", EA_IND_Y, },
+ { "lsr", EA_IND_Y, },
+ { "?", 0, },
+ { "ror", EA_IND_Y, },
+ { "asr", EA_IND_Y, },
+ { "asl", EA_IND_Y, },
+ { "rol", EA_IND_Y, },
+ { "dec", EA_IND_Y, },
+ { "?", 0, },
+ { "inc", EA_IND_Y, },
+ { "tst", EA_IND_Y, },
+ { "jmp", EA_IND_Y, },
+ { "clr", EA_IND_Y, },
+ /* 0x70 - 0x7f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x80 - 0x8f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpy", EA_IMM8, },
+ { "?", 0, },
+ { "?", 0, },
+ { "xgdy", 0, },
+ /* 0x90 - 0x9f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpy", EA_DIRECT, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xa0 - 0xaf */
+ { "suba", EA_IND_Y, },
+ { "cmpa", EA_IND_Y, },
+ { "sbca", EA_IND_Y, },
+ { "subd", EA_IND_Y, },
+ { "anda", EA_IND_Y, },
+ { "bita", EA_IND_Y, },
+ { "ldaa", EA_IND_Y, },
+ { "staa", EA_IND_Y, },
+ { "eora", EA_IND_Y, },
+ { "adca", EA_IND_Y, },
+ { "oraa", EA_IND_Y, },
+ { "adda", EA_IND_Y, },
+ { "cpy", EA_IND_Y, },
+ { "jsr", EA_IND_Y, },
+ { "lds", EA_IND_Y, },
+ { "sts", EA_IND_Y, },
+ /* 0xb0 - 0xbf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpy", EA_EXT, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xc0 - 0xcf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "ldy", EA_IMM16, },
+ { "?", 0, },
+ /* 0xd0 - 0xdf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "ldy", EA_DIRECT, },
+ { "sty", EA_DIRECT, },
+ /* 0xe0 - 0xef */
+ { "subb", EA_IND_Y, },
+ { "cmpb", EA_IND_Y, },
+ { "sbcb", EA_IND_Y, },
+ { "addd", EA_IND_Y, },
+ { "andb", EA_IND_Y, },
+ { "bitb", EA_IND_Y, },
+ { "ldab", EA_IND_Y, },
+ { "stab", EA_IND_Y, },
+ { "eorb", EA_IND_Y, },
+ { "adcb", EA_IND_Y, },
+ { "orab", EA_IND_Y, },
+ { "addb", EA_IND_Y, },
+ { "ldd", EA_IND_Y, },
+ { "std", EA_IND_Y, },
+ { "ldy", EA_IND_Y, },
+ { "sty", EA_IND_Y, },
+ /* 0xf0 - 0xff */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "ldy", EA_EXT, },
+ { "sty", EA_EXT, },
+};
+
+
+/*****************************************************************************/
+
+
+static M68HC11_OPCODE opcode_table_page3[256] =
+{
+ /* 0x00 - 0x0f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x10 - 0x1f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x20 - 0x2f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x30 - 0x3f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x40 - 0x4f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x50 - 0x5f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x60 - 0x6f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x70 - 0x7f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x80 - 0x8f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpd", EA_IMM16, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x90 - 0x9f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpd", EA_DIRECT, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xa0 - 0xaf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpd", EA_IND_X, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpy", EA_IND_X, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xb0 - 0xbf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpd", EA_EXT, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xc0 - 0xcf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xd0 - 0xdf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xe0 - 0xef */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "ldy", EA_IND_X, },
+ { "sty", EA_IND_X, },
+ /* 0xf0 - 0xff */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+};
+
+
+/*****************************************************************************/
+
+
+static M68HC11_OPCODE opcode_table_page4[256] =
+{
+ /* 0x00 - 0x0f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x10 - 0x1f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x20 - 0x2f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x30 - 0x3f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x40 - 0x4f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x50 - 0x5f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x60 - 0x6f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x70 - 0x7f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x80 - 0x8f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0x90 - 0x9f */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xa0 - 0xaf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpd", EA_IND_Y, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "cpx", EA_IND_Y, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xb0 - 0xbf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xc0 - 0xcf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xd0 - 0xdf */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ /* 0xe0 - 0xef */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "ldx", EA_IND_Y, },
+ { "stx", EA_IND_Y, },
+ /* 0xf0 - 0xff */
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+ { "?", 0, },
+};
+
+
+/*****************************************************************************/
+
+static char *output;
+static const UINT8 *rombase;
+
+static void print(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ output += vsprintf(output, fmt, vl);
+ va_end(vl);
+}
+
+static UINT8 fetch(void)
+{
+ return *rombase++;
+}
+
+static UINT16 fetch16(void)
+{
+ UINT16 w;
+ w = (rombase[0] << 8) | rombase[1];
+ rombase+=2;
+ return w;
+}
+
+static UINT32 decode_opcode(UINT32 pc, M68HC11_OPCODE *op_table)
+{
+ UINT8 imm8, mask;
+ INT8 rel8;
+ UINT16 imm16;
+ UINT8 op2;
+ UINT32 flags = 0;
+
+ if (!strcmp(op_table->mnemonic, "jsr") || !strcmp(op_table->mnemonic, "bsr"))
+ flags = DASMFLAG_STEP_OVER;
+ else if (!strcmp(op_table->mnemonic, "rts") || !strcmp(op_table->mnemonic, "rti"))
+ flags = DASMFLAG_STEP_OUT;
+
+ switch(op_table->address_mode)
+ {
+ case EA_IMM8:
+ imm8 = fetch();
+ print("%s 0x%02X", op_table->mnemonic, imm8);
+ break;
+
+ case EA_IMM16:
+ imm16 = fetch16();
+ print("%s 0x%04X", op_table->mnemonic, imm16);
+ break;
+
+ case EA_DIRECT:
+ imm8 = fetch();
+ print("%s (0x%04X)", op_table->mnemonic, imm8);
+ break;
+
+ case EA_EXT:
+ imm16 = fetch16();
+ print("%s (0x%04X)", op_table->mnemonic, imm16);
+ break;
+
+ case EA_IND_X:
+ imm8 = fetch();
+ print("%s (X+0x%02X)", op_table->mnemonic, imm8);
+ break;
+
+ case EA_REL:
+ rel8 = fetch();
+ print("%s [0x%04X]", op_table->mnemonic, pc+2+rel8);
+ break;
+
+ case EA_DIRECT_IMM8:
+ imm8 = fetch();
+ mask = fetch();
+ print("%s (0x%04X), 0x%02X", op_table->mnemonic, imm8, mask);
+ break;
+
+ case EA_IND_X_IMM8:
+ imm8 = fetch();
+ mask = fetch();
+ print("%s (X+0x%02X), 0x%02X", op_table->mnemonic, imm8, mask);
+ break;
+
+ case EA_DIRECT_IMM8_REL:
+ imm8 = fetch();
+ mask = fetch();
+ rel8 = fetch();
+ print("%s (0x%04X), 0x%02X, [0x%04X]", op_table->mnemonic, imm8, mask, pc+4+rel8);
+ break;
+
+ case EA_IND_X_IMM8_REL:
+ imm8 = fetch();
+ mask = fetch();
+ rel8 = fetch();
+ print("%s (X+0x%02X), 0x%02X, [0x%04X]", op_table->mnemonic, imm8, mask, pc+4+rel8);
+ break;
+
+ case EA_IND_Y:
+ imm8 = fetch();
+ print("%s (Y+0x%02X)", op_table->mnemonic, imm8);
+ break;
+
+ case EA_IND_Y_IMM8:
+ imm8 = fetch();
+ mask = fetch();
+ print("%s (Y+0x%02X), 0x%02X", op_table->mnemonic, imm8, mask);
+ break;
+
+ case EA_IND_Y_IMM8_REL:
+ imm8 = fetch();
+ mask = fetch();
+ rel8 = fetch();
+ print("%s (Y+0x%02X), 0x%02X, [0x%04X]", op_table->mnemonic, imm8, mask, pc+2+rel8);
+ break;
+
+ case PAGE2:
+ op2 = fetch();
+ return decode_opcode(pc, &opcode_table_page2[op2]);
+
+ case PAGE3:
+ op2 = fetch();
+ return decode_opcode(pc, &opcode_table_page3[op2]);
+
+ case PAGE4:
+ op2 = fetch();
+ return decode_opcode(pc, &opcode_table_page4[op2]);
+
+ default:
+ print("%s", op_table->mnemonic);
+ }
+ return flags;
+}
+
+offs_t hc11_disasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ UINT8 opcode;
+
+ output = buffer;
+ rombase = oprom;
+
+ opcode = fetch();
+ flags = decode_opcode(pc, &opcode_table[opcode]);
+
+ return (rombase-oprom) | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/mc68hc11/hc11ops.c b/src/emu/cpu/mc68hc11/hc11ops.c
new file mode 100644
index 00000000000..0be4321cfc2
--- /dev/null
+++ b/src/emu/cpu/mc68hc11/hc11ops.c
@@ -0,0 +1,2201 @@
+#define SET_Z8(r) (hc11.ccr |= ((UINT8)r == 0) ? CC_Z : 0)
+#define SET_Z16(r) (hc11.ccr |= ((UINT16)r == 0) ? CC_Z : 0)
+#define SET_N8(r) (hc11.ccr |= (r & 0x80) ? CC_N : 0)
+#define SET_N16(r) (hc11.ccr |= (r & 0x80) ? CC_N : 0)
+#define SET_V_ADD8(r,s,d) (hc11.ccr |= (((r) ^ (s)) & ((r) ^ (d)) & 0x80) ? CC_V : 0)
+#define SET_V_SUB8(r,s,d) (hc11.ccr |= (((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? CC_V : 0)
+#define SET_V_ADD16(r,s,d) (hc11.ccr |= (((r) ^ (s)) & ((r) ^ (d)) & 0x8000) ? CC_V : 0)
+#define SET_V_SUB16(r,s,d) (hc11.ccr |= (((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? CC_V : 0)
+#define SET_H(r,s,d) (hc11.ccr |= ((((s) & (d)) | ((d) & (r)) | ((r) & (s))) & 0x10) ? CC_H : 0)
+#define SET_C8(x) (hc11.ccr |= ((x) & 0x100) ? CC_C : 0)
+#define SET_C16(x) (hc11.ccr |= ((x) & 0x10000) ? CC_C : 0)
+#define CLEAR_Z() (hc11.ccr &= ~(CC_Z))
+#define CLEAR_NZV() (hc11.ccr &= ~(CC_N | CC_Z | CC_V))
+#define CLEAR_NZVC() (hc11.ccr &= ~(CC_N | CC_Z | CC_V | CC_C))
+#define CLEAR_HNZVC() (hc11.ccr &= ~(CC_H | CC_N | CC_Z | CC_V | CC_C))
+
+#define SET_ZFLAG() (hc11.ccr |= CC_Z)
+#define SET_NFLAG() (hc11.ccr |= CC_N)
+#define SET_VFLAG() (hc11.ccr |= CC_V)
+
+#define REG_A hc11.d.d8.a
+#define REG_B hc11.d.d8.b
+#define REG_D hc11.d.d16
+
+INLINE void CYCLES(int cycles)
+{
+ hc11.icount -= cycles;
+}
+
+INLINE void SET_PC(int pc)
+{
+ hc11.pc = pc;
+ change_pc(hc11.pc);
+}
+
+INLINE void PUSH8(UINT8 value)
+{
+ WRITE8(hc11.sp--, value);
+}
+
+INLINE void PUSH16(UINT16 value)
+{
+ WRITE8(hc11.sp--, (value >> 0) & 0xff);
+ WRITE8(hc11.sp--, (value >> 8) & 0xff);
+}
+
+INLINE UINT8 POP8(void)
+{
+ return READ8(++hc11.sp);
+}
+
+INLINE UINT16 POP16(void)
+{
+ UINT16 r = 0;
+ r |= (READ8(++hc11.sp) << 8);
+ r |= (READ8(++hc11.sp) << 0);
+ return r;
+}
+
+
+
+/*****************************************************************************/
+
+/* ABA 0x1B */
+static void HC11OP(aba)(void)
+{
+ UINT16 r = REG_A + REG_B;
+ CLEAR_HNZVC();
+ SET_H(r, REG_B, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, REG_B, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(2);
+}
+
+
+/* ABX 0x3A */
+static void HC11OP(abx)(void)
+{
+ hc11.ix += REG_B;
+ CYCLES(3);
+}
+
+
+/* ABY 0x18, 0x3A */
+static void HC11OP(aby)(void)
+{
+ hc11.iy += REG_B;
+ CYCLES(4);
+}
+
+
+/* ADCA IMM 0x89 */
+static void HC11OP(adca_imm)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT8 i = FETCH();
+ UINT16 r = REG_A + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(2);
+}
+
+/* ADCA DIR 0x99 */
+static void HC11OP(adca_dir)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ UINT16 r = REG_A + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(3);
+}
+
+/* ADCA EXT 0xB9 */
+static void HC11OP(adca_ext)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ UINT16 r = REG_A + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(4);
+}
+
+/* ADCA IND, X 0xA9 */
+static void HC11OP(adca_indx)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ UINT16 r = REG_A + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(4);
+}
+
+/* ADCA IND, Y 0x18, 0xA9 */
+static void HC11OP(adca_indy)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ UINT16 r = REG_A + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(5);
+}
+
+
+/* ADCB IMM 0xC9 */
+static void HC11OP(adcb_imm)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT8 i = FETCH();
+ UINT16 r = REG_B + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(2);
+}
+
+/* ADCB DIR 0xD9 */
+static void HC11OP(adcb_dir)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ UINT16 r = REG_B + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(3);
+}
+
+/* ADCB EXT 0xF9 */
+static void HC11OP(adcb_ext)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ UINT16 r = REG_B + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(4);
+}
+
+/* ADCB IND, X 0xE9 */
+static void HC11OP(adcb_indx)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ UINT16 r = REG_B + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(4);
+}
+
+/* ADCB IND, Y 0x18, 0xE9 */
+static void HC11OP(adcb_indy)(void)
+{
+ int c = (hc11.ccr & CC_C) ? 1 : 0;
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ UINT16 r = REG_B + i + c;
+ CLEAR_HNZVC();
+ SET_H(r, i+c, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i+c, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(5);
+}
+
+
+/* ADDA IMM 0x8B */
+static void HC11OP(adda_imm)(void)
+{
+ UINT8 i = FETCH();
+ UINT16 r = REG_A + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(2);
+}
+
+/* ADDA DIR 0x9B */
+static void HC11OP(adda_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ UINT16 r = REG_A + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(3);
+}
+
+/* ADDA EXT 0xBB */
+static void HC11OP(adda_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ UINT16 r = REG_A + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(4);
+}
+
+/* ADDA IND, X 0xAB */
+static void HC11OP(adda_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ UINT16 r = REG_A + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(4);
+}
+
+/* ADDA IND, Y 0x18, 0xAB */
+static void HC11OP(adda_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ UINT16 r = REG_A + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_A);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_A);
+ SET_C8(r);
+ REG_A = (UINT8)r;
+ CYCLES(5);
+}
+
+
+/* ADDB IMM 0xCB */
+static void HC11OP(addb_imm)(void)
+{
+ UINT8 i = FETCH();
+ UINT16 r = REG_B + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(2);
+}
+
+/* ADDB DIR 0xDB */
+static void HC11OP(addb_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ UINT16 r = REG_B + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(3);
+}
+
+/* ADDB EXT 0xFB */
+static void HC11OP(addb_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ UINT16 r = REG_B + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(4);
+}
+
+/* ADDB IND, X 0xEB */
+static void HC11OP(addb_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ UINT16 r = REG_B + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(4);
+}
+
+/* ADDB IND, Y 0x18, 0xEB */
+static void HC11OP(addb_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ UINT16 r = REG_B + i;
+ CLEAR_HNZVC();
+ SET_H(r, i, REG_B);
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_ADD8(r, i, REG_B);
+ SET_C8(r);
+ REG_B = (UINT8)r;
+ CYCLES(5);
+}
+
+
+/* ADDD IMM 0xC3 */
+static void HC11OP(addd_imm)(void)
+{
+ UINT16 i = FETCH16();
+ UINT32 r = REG_D + i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_ADD16(r, i, REG_D);
+ SET_C16(r);
+ REG_D = (UINT16)r;
+ CYCLES(4);
+}
+
+/* ADDD DIR 0xD3 */
+static void HC11OP(addd_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT16 i = READ16(d);
+ UINT32 r = REG_D + i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_ADD16(r, i, REG_D);
+ SET_C16(r);
+ REG_D = (UINT16)r;
+ CYCLES(5);
+}
+
+/* ADDD EXT 0xF3 */
+static void HC11OP(addd_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT16 i = READ16(adr);
+ UINT32 r = REG_D + i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_ADD16(r, i, REG_D);
+ SET_C16(r);
+ REG_D = (UINT16)r;
+ CYCLES(6);
+}
+
+/* ADDD IND, X 0xE3 */
+static void HC11OP(addd_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT16 i = READ16(hc11.ix + offset);
+ UINT32 r = REG_D + i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_ADD16(r, i, REG_D);
+ SET_C16(r);
+ REG_D = (UINT16)r;
+ CYCLES(6);
+}
+
+/* ADDD IND, Y 0x18, 0xE3 */
+static void HC11OP(addd_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT16 i = READ16(hc11.iy + offset);
+ UINT32 r = REG_D + i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_ADD16(r, i, REG_D);
+ SET_C16(r);
+ REG_D = (UINT16)r;
+ CYCLES(7);
+}
+
+
+/* ANDA IMM 0x84 */
+static void HC11OP(anda_imm)(void)
+{
+ UINT8 i = FETCH();
+ CLEAR_NZV();
+ REG_A &= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(2);
+}
+
+/* ANDA DIR 0x94 */
+static void HC11OP(anda_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ CLEAR_NZV();
+ REG_A &= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(3);
+}
+
+/* ANDA EXT 0xB4 */
+static void HC11OP(anda_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ CLEAR_NZV();
+ REG_A &= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(4);
+}
+
+/* ANDA IND, X 0xA4 */
+static void HC11OP(anda_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ CLEAR_NZV();
+ REG_A &= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(4);
+}
+
+/* ANDA IND, Y 0x18, 0xA4 */
+static void HC11OP(anda_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ CLEAR_NZV();
+ REG_A &= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(5);
+}
+
+
+/* ANDB IMM 0xC4 */
+static void HC11OP(andb_imm)(void)
+{
+ UINT8 i = FETCH();
+ CLEAR_NZV();
+ REG_B &= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(2);
+}
+
+/* ANDB DIR 0xD4 */
+static void HC11OP(andb_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ CLEAR_NZV();
+ REG_B &= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(3);
+}
+
+/* ANDB EXT 0xF4 */
+static void HC11OP(andb_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ CLEAR_NZV();
+ REG_B &= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(4);
+}
+
+/* ANDB IND, X 0xE4 */
+static void HC11OP(andb_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ CLEAR_NZV();
+ REG_B &= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(4);
+}
+
+/* ANDB IND, Y 0x18, 0xE4 */
+static void HC11OP(andb_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ CLEAR_NZV();
+ REG_B &= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(5);
+}
+
+
+/* BITA IMM 0x85 */
+static void HC11OP(bita_imm)(void)
+{
+ UINT8 i = FETCH();
+ UINT8 r = REG_A & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(2);
+}
+
+/* BITA DIR 0x95 */
+static void HC11OP(bita_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ UINT8 r = REG_A & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(3);
+}
+
+/* BITA EXT 0xB5 */
+static void HC11OP(bita_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ UINT8 r = REG_A & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(4);
+}
+
+/* BITA IND, X 0xA5 */
+static void HC11OP(bita_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ UINT8 r = REG_A & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(4);
+}
+
+/* BITA IND, Y 0x18, 0xA5 */
+static void HC11OP(bita_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ UINT8 r = REG_A & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(5);
+}
+
+
+/* BITB IMM 0xC5 */
+static void HC11OP(bitb_imm)(void)
+{
+ UINT8 i = FETCH();
+ UINT8 r = REG_B & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(2);
+}
+
+/* BITB DIR 0xD5 */
+static void HC11OP(bitb_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ UINT8 r = REG_B & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(3);
+}
+
+/* BITB EXT 0xF5 */
+static void HC11OP(bitb_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ UINT8 r = REG_B & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(4);
+}
+
+/* BITB IND, X 0xE5 */
+static void HC11OP(bitb_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ UINT8 r = REG_B & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(4);
+}
+
+/* BITB IND, Y 0x18, 0xE5 */
+static void HC11OP(bitb_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ UINT8 r = REG_B & i;
+ CLEAR_NZV();
+ SET_N8(r);
+ SET_Z8(r);
+ CYCLES(5);
+}
+
+
+/* BCS 0x25 */
+static void HC11OP(bcs)(void)
+{
+ INT8 rel = FETCH();
+ if (hc11.ccr & CC_C) /* Branch if C flag set */
+ {
+ SET_PC(hc11.ppc + rel + 2);
+ }
+ CYCLES(3);
+}
+
+
+/* BEQ 0x27 */
+static void HC11OP(beq)(void)
+{
+ INT8 rel = FETCH();
+ if (hc11.ccr & CC_Z) /* Branch if Z flag set */
+ {
+ SET_PC(hc11.ppc + rel + 2);
+ }
+ CYCLES(3);
+}
+
+
+/* BNE 0x26 */
+static void HC11OP(bne)(void)
+{
+ INT8 rel = FETCH();
+ if ((hc11.ccr & CC_Z) == 0) /* Branch if Z flag clear */
+ {
+ SET_PC(hc11.ppc + rel + 2);
+ }
+ CYCLES(3);
+}
+
+
+/* BLE 0x2F */
+static void HC11OP(ble)(void)
+{
+ UINT8 n = (hc11.ccr & CC_N) ? 1 : 0;
+ UINT8 v = (hc11.ccr & CC_V) ? 1 : 0;
+ INT8 rel = FETCH();
+ if ((hc11.ccr & CC_Z) || (n ^ v)) /* Branch if Z flag set or (N ^ V) */
+ {
+ SET_PC(hc11.ppc + rel + 2);
+ }
+ CYCLES(3);
+}
+
+
+/* BPL 0x2A */
+static void HC11OP(bpl)(void)
+{
+ INT8 rel = FETCH();
+ if ((hc11.ccr & CC_N) == 0) /* Branch if N flag clear */
+ {
+ SET_PC(hc11.ppc + rel + 2);
+ }
+ CYCLES(3);
+}
+
+
+/* BRA 0x20 */
+static void HC11OP(bra)(void)
+{
+ INT8 rel = FETCH();
+ SET_PC(hc11.ppc + rel + 2);
+ CYCLES(3);
+}
+
+
+/* BSR 0x8D */
+static void HC11OP(bsr)(void)
+{
+ INT8 rel = FETCH();
+ UINT16 rt_adr = hc11.pc;
+ PUSH16(rt_adr);
+ SET_PC(hc11.ppc + rel + 2);
+ CYCLES(6);
+}
+
+
+/* CLI 0x0E */
+static void HC11OP(cli)(void)
+{
+ hc11.ccr &= ~CC_I;
+ CYCLES(2);
+}
+
+
+/* CLRA 0x4F */
+static void HC11OP(clra)(void)
+{
+ REG_A = 0;
+ CLEAR_NZVC();
+ SET_ZFLAG();
+ CYCLES(2);
+}
+
+/* CLRB 0x5F */
+static void HC11OP(clrb)(void)
+{
+ REG_B = 0;
+ CLEAR_NZVC();
+ SET_ZFLAG();
+ CYCLES(2);
+}
+
+/* CLR EXT 0x7F */
+static void HC11OP(clr_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ WRITE8(adr, 0);
+ CLEAR_NZVC();
+ SET_ZFLAG();
+ CYCLES(6);
+}
+
+/* CLR IND, X 0x6F */
+static void HC11OP(clr_indx)(void)
+{
+ UINT8 offset = FETCH();
+ WRITE8(hc11.ix + offset, 0);
+ CLEAR_NZVC();
+ SET_ZFLAG();
+ CYCLES(6);
+}
+
+/* CLR IND, Y 0x18, 0x6F */
+static void HC11OP(clr_indy)(void)
+{
+ UINT8 offset = FETCH();
+ WRITE8(hc11.iy + offset, 0);
+ CLEAR_NZVC();
+ SET_ZFLAG();
+ CYCLES(7);
+}
+
+
+/* CMPA IMM 0x81 */
+static void HC11OP(cmpa_imm)(void)
+{
+ UINT8 i = FETCH();
+ UINT16 r = REG_A - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_A);
+ SET_C8(r);
+ CYCLES(2);
+}
+
+/* CMPA DIR 0x91 */
+static void HC11OP(cmpa_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ UINT16 r = REG_A - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_A);
+ SET_C8(r);
+ CYCLES(3);
+}
+
+/* CMPA EXT 0xB1 */
+static void HC11OP(cmpa_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ UINT16 r = REG_A - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_A);
+ SET_C8(r);
+ CYCLES(4);
+}
+
+/* CMPA IND, X 0xA1 */
+static void HC11OP(cmpa_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ UINT16 r = REG_A - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_A);
+ SET_C8(r);
+ CYCLES(4);
+}
+
+/* CMPA IND, Y 0x18, 0xA1 */
+static void HC11OP(cmpa_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ UINT16 r = REG_A - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_A);
+ SET_C8(r);
+ CYCLES(5);
+}
+
+
+/* CMPB IMM 0xC1 */
+static void HC11OP(cmpb_imm)(void)
+{
+ UINT8 i = FETCH();
+ UINT16 r = REG_B - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_B);
+ SET_C8(r);
+ CYCLES(2);
+}
+
+/* CMPB DIR 0xD1 */
+static void HC11OP(cmpb_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ UINT16 r = REG_B - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_B);
+ SET_C8(r);
+ CYCLES(3);
+}
+
+/* CMPB EXT 0xF1 */
+static void HC11OP(cmpb_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ UINT16 r = REG_B - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_B);
+ SET_C8(r);
+ CYCLES(4);
+}
+
+/* CMPB IND, X 0xE1 */
+static void HC11OP(cmpb_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ UINT16 r = REG_B - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_B);
+ SET_C8(r);
+ CYCLES(4);
+}
+
+/* CMPB IND, Y 0x18, 0xE1 */
+static void HC11OP(cmpb_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ UINT16 r = REG_B - i;
+ CLEAR_NZVC();
+ SET_N8(r);
+ SET_Z8(r);
+ SET_V_SUB8(r, i, REG_B);
+ SET_C8(r);
+ CYCLES(5);
+}
+
+
+/* CPD IMM 0x1A, 0x83 */
+static void HC11OP(cpd_imm)(void)
+{
+ UINT16 i = FETCH16();
+ UINT32 r = REG_D - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, REG_D);
+ SET_C16(r);
+ CYCLES(5);
+}
+
+/* CPD DIR 0x1A, 0x93 */
+static void HC11OP(cpd_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT16 i = READ16(d);
+ UINT32 r = REG_D - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, REG_D);
+ SET_C16(r);
+ CYCLES(6);
+}
+
+/* CPD EXT 0x1A, 0xB3 */
+static void HC11OP(cpd_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT16 i = READ16(adr);
+ UINT32 r = REG_D - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, REG_D);
+ SET_C16(r);
+ CYCLES(7);
+}
+
+/* CPD IND, X 0x1A, 0xA3 */
+static void HC11OP(cpd_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT16 i = READ16(hc11.ix + offset);
+ UINT32 r = REG_D - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, REG_D);
+ SET_C16(r);
+ CYCLES(7);
+}
+
+/* CPD IND, Y 0xCD, 0xA3 */
+static void HC11OP(cpd_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT16 i = READ16(hc11.iy + offset);
+ UINT32 r = REG_D - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, REG_D);
+ SET_C16(r);
+ CYCLES(7);
+}
+
+
+/* CPX IMM 0x8C */
+static void HC11OP(cpx_imm)(void)
+{
+ UINT16 i = FETCH16();
+ UINT32 r = hc11.ix - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, hc11.ix);
+ SET_C16(r);
+ CYCLES(4);
+}
+
+/* CPX DIR 0x9C */
+static void HC11OP(cpx_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT16 i = READ16(d);
+ UINT32 r = hc11.ix - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, hc11.ix);
+ SET_C16(r);
+ CYCLES(5);
+}
+
+/* CPX EXT 0xBC */
+static void HC11OP(cpx_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT16 i = READ16(adr);
+ UINT32 r = hc11.ix - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, hc11.ix);
+ SET_C16(r);
+ CYCLES(6);
+}
+
+/* CPX IND, X 0xAC */
+static void HC11OP(cpx_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT16 i = READ16(hc11.ix + offset);
+ UINT32 r = hc11.ix - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, hc11.ix);
+ SET_C16(r);
+ CYCLES(6);
+}
+
+/* CPX IND, Y 0xCD, 0xAC */
+static void HC11OP(cpx_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT16 i = READ16(hc11.iy + offset);
+ UINT32 r = hc11.ix - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, hc11.ix);
+ SET_C16(r);
+ CYCLES(7);
+}
+
+
+/* CPY IMM 0x18, 0x8C */
+static void HC11OP(cpy_imm)(void)
+{
+ UINT16 i = FETCH16();
+ UINT32 r = hc11.iy - i;
+ CLEAR_NZVC();
+ SET_N16(r);
+ SET_Z16(r);
+ SET_V_SUB16(r, i, hc11.iy);
+ SET_C16(r);
+ CYCLES(5);
+}
+
+
+/* DEX 0x09 */
+static void HC11OP(dex)(void)
+{
+ CLEAR_Z();
+ hc11.ix--;
+ SET_Z16(hc11.ix);
+ CYCLES(3);
+}
+
+
+/* DEY 0x18, 0x09 */
+static void HC11OP(dey)(void)
+{
+ CLEAR_Z();
+ hc11.iy--;
+ SET_Z16(hc11.iy);
+ CYCLES(4);
+}
+
+
+/* EORA IMM 0x88 */
+static void HC11OP(eora_imm)(void)
+{
+ UINT8 i = FETCH();
+ CLEAR_NZV();
+ REG_A ^= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(2);
+}
+
+/* EORA DIR 0x98 */
+static void HC11OP(eora_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ CLEAR_NZV();
+ REG_A ^= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(3);
+}
+
+/* EORA EXT 0xB8 */
+static void HC11OP(eora_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ CLEAR_NZV();
+ REG_A ^= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(4);
+}
+
+/* EORA IND, X 0xA8 */
+static void HC11OP(eora_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ CLEAR_NZV();
+ REG_A ^= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(4);
+}
+
+/* EORA IND, Y 0x18, 0xA8 */
+static void HC11OP(eora_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ CLEAR_NZV();
+ REG_A ^= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(5);
+}
+
+
+/* EORB IMM 0xC8 */
+static void HC11OP(eorb_imm)(void)
+{
+ UINT8 i = FETCH();
+ CLEAR_NZV();
+ REG_B ^= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(2);
+}
+
+/* EORB DIR 0xD8 */
+static void HC11OP(eorb_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ CLEAR_NZV();
+ REG_B ^= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(3);
+}
+
+/* EORB EXT 0xF8 */
+static void HC11OP(eorb_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ CLEAR_NZV();
+ REG_B ^= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(4);
+}
+
+/* EORB IND, X 0xE8 */
+static void HC11OP(eorb_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ CLEAR_NZV();
+ REG_B ^= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(4);
+}
+
+/* EORB IND, Y 0x18, 0xE8 */
+static void HC11OP(eorb_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ CLEAR_NZV();
+ REG_B ^= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(5);
+}
+
+
+/* INCA 0x4C */
+static void HC11OP(inca)(void)
+{
+ CLEAR_NZV();
+ if (REG_A == 0x7f)
+ SET_VFLAG();
+ REG_A++;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(2);
+}
+
+
+/* INX 0x08 */
+static void HC11OP(inx)(void)
+{
+ CLEAR_Z();
+ hc11.ix++;
+ SET_Z16(hc11.ix);
+ CYCLES(3);
+}
+
+/* INY 0x18, 0x08 */
+static void HC11OP(iny)(void)
+{
+ CLEAR_Z();
+ hc11.iy++;
+ SET_Z16(hc11.iy);
+ CYCLES(4);
+}
+
+
+/* JMP EXT 0x7E */
+static void HC11OP(jmp_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ SET_PC(adr);
+ CYCLES(3);
+}
+
+
+/* JSR DIR 0x9D */
+static void HC11OP(jsr_dir)(void)
+{
+ UINT8 i = FETCH();
+ UINT16 rt_adr = hc11.pc;
+ PUSH16(rt_adr);
+ SET_PC(i);
+ CYCLES(5);
+}
+
+/* JSR EXT 0xBD */
+static void HC11OP(jsr_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT16 rt_adr = hc11.pc;
+ PUSH16(rt_adr);
+ SET_PC(adr);
+ CYCLES(6);
+}
+
+/* JSR IND, X 0xAD */
+static void HC11OP(jsr_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT16 rt_adr = hc11.pc;
+ PUSH16(rt_adr);
+ SET_PC(hc11.ix + offset);
+ CYCLES(6);
+}
+
+/* JSR IND, Y 0x18, 0xAD */
+static void HC11OP(jsr_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT16 rt_adr = hc11.pc;
+ PUSH16(rt_adr);
+ SET_PC(hc11.iy + offset);
+ CYCLES(6);
+}
+
+
+/* LDAA IMM 0x86 */
+static void HC11OP(ldaa_imm)(void)
+{
+ CLEAR_NZV();
+ REG_A = FETCH();
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(2);
+}
+
+/* LDAA DIR 0x96 */
+static void HC11OP(ldaa_dir)(void)
+{
+ UINT8 d = FETCH();
+ CLEAR_NZV();
+ REG_A = READ8(d);
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(3);
+}
+
+/* LDAA EXT 0xB6 */
+static void HC11OP(ldaa_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ CLEAR_NZV();
+ REG_A = READ8(adr);
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(4);
+}
+
+/* LDAA IND, X 0xA6 */
+static void HC11OP(ldaa_indx)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ REG_A = READ8(hc11.ix + offset);
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(4);
+}
+
+/* LDAA IND, Y 0x18, 0xA6 */
+static void HC11OP(ldaa_indy)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ REG_A = READ8(hc11.iy + offset);
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(5);
+}
+
+/* LDAB IMM 0xC6 */
+static void HC11OP(ldab_imm)(void)
+{
+ CLEAR_NZV();
+ REG_B = FETCH();
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(2);
+}
+
+/* LDAB DIR 0xD6 */
+static void HC11OP(ldab_dir)(void)
+{
+ UINT8 d = FETCH();
+ CLEAR_NZV();
+ REG_B = READ8(d);
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(3);
+}
+
+/* LDAB EXT 0xF6 */
+static void HC11OP(ldab_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ CLEAR_NZV();
+ REG_B = READ8(adr);
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(4);
+}
+
+/* LDAB IND, X 0xE6 */
+static void HC11OP(ldab_indx)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ REG_B = READ8(hc11.ix + offset);
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(4);
+}
+
+/* LDAB IND, Y 0x18, 0xE6 */
+static void HC11OP(ldab_indy)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ REG_B = READ8(hc11.iy + offset);
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(5);
+}
+
+
+/* LDD IMM 0xCC */
+static void HC11OP(ldd_imm)(void)
+{
+ CLEAR_NZV();
+ REG_D = FETCH16();
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+ CYCLES(3);
+}
+
+/* LDD DIR 0xDC */
+static void HC11OP(ldd_dir)(void)
+{
+ UINT8 d = FETCH();
+ CLEAR_NZV();
+ REG_D = READ16(d);
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+ CYCLES(4);
+}
+
+/* LDD EXT 0xFC */
+static void HC11OP(ldd_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ CLEAR_NZV();
+ REG_D = READ16(adr);
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+ CYCLES(5);
+}
+
+/* LDD IND, X 0xEC */
+static void HC11OP(ldd_indx)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ REG_D = READ16(hc11.ix + offset);
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+ CYCLES(5);
+}
+
+/* LDD IND, Y 0x18, 0xEC */
+static void HC11OP(ldd_indy)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ REG_D = READ16(hc11.iy + offset);
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+ CYCLES(6);
+}
+
+
+/* LDS IMM 0x8E */
+static void HC11OP(lds_imm)(void)
+{
+ CLEAR_NZV();
+ hc11.sp = FETCH16();
+ SET_N16(hc11.sp);
+ SET_Z16(hc11.sp);
+ CYCLES(3);
+}
+
+/* LDS DIR 0x9E */
+static void HC11OP(lds_dir)(void)
+{
+ UINT8 i = FETCH();
+ CLEAR_NZV();
+ hc11.sp = READ16(i);
+ SET_N16(hc11.sp);
+ SET_Z16(hc11.sp);
+ CYCLES(4);
+}
+
+/* LDS EXT 0xBE */
+static void HC11OP(lds_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ CLEAR_NZV();
+ hc11.sp = READ16(adr);
+ SET_N16(hc11.sp);
+ SET_Z16(hc11.sp);
+ CYCLES(5);
+}
+
+/* LDS IND, X 0xAE */
+static void HC11OP(lds_indx)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ hc11.sp = READ16(hc11.ix + offset);
+ SET_N16(hc11.sp);
+ SET_Z16(hc11.sp);
+ CYCLES(5);
+}
+
+/* LDS IND, Y 0x18, 0xAE */
+static void HC11OP(lds_indy)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ hc11.sp = READ16(hc11.iy + offset);
+ SET_N16(hc11.sp);
+ SET_Z16(hc11.sp);
+ CYCLES(6);
+}
+
+
+/* LDX IMM 0xCE */
+static void HC11OP(ldx_imm)(void)
+{
+ CLEAR_NZV();
+ hc11.ix = FETCH16();
+ SET_N16(hc11.ix);
+ SET_Z16(hc11.ix);
+ CYCLES(3);
+}
+
+/* LDX DIR 0xDE */
+static void HC11OP(ldx_dir)(void)
+{
+ UINT8 d = FETCH();
+ CLEAR_NZV();
+ hc11.ix = READ16(d);
+ SET_N16(hc11.ix);
+ SET_Z16(hc11.ix);
+ CYCLES(4);
+}
+
+/* LDX EXT 0xFE */
+static void HC11OP(ldx_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ CLEAR_NZV();
+ hc11.ix = READ16(adr);
+ SET_N16(hc11.ix);
+ SET_Z16(hc11.ix);
+ CYCLES(5);
+}
+
+/* LDX IND, X 0xEE */
+static void HC11OP(ldx_indx)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ hc11.ix = READ16(hc11.ix + offset);
+ SET_N16(hc11.ix);
+ SET_Z16(hc11.ix);
+ CYCLES(5);
+}
+
+/* LDX IND, Y 0xCD, 0xEE */
+static void HC11OP(ldx_indy)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ hc11.ix = READ16(hc11.iy + offset);
+ SET_N16(hc11.ix);
+ SET_Z16(hc11.ix);
+ CYCLES(6);
+}
+
+
+/* LDY IMM 0x18, 0xCE */
+static void HC11OP(ldy_imm)(void)
+{
+ CLEAR_NZV();
+ hc11.iy = FETCH16();
+ SET_N16(hc11.iy);
+ SET_Z16(hc11.iy);
+ CYCLES(4);
+}
+
+/* LDY DIR 0x18, 0xDE */
+static void HC11OP(ldy_dir)(void)
+{
+ UINT8 d = FETCH();
+ CLEAR_NZV();
+ hc11.iy = READ16(d);
+ SET_N16(hc11.iy);
+ SET_Z16(hc11.iy);
+ CYCLES(5);
+}
+
+/* LDY EXT 0x18, 0xFE */
+static void HC11OP(ldy_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ CLEAR_NZV();
+ hc11.iy = READ16(adr);
+ SET_N16(hc11.iy);
+ SET_Z16(hc11.iy);
+ CYCLES(6);
+}
+
+/* LDY IND, X 0x1A, 0xEE */
+static void HC11OP(ldy_indx)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ hc11.iy = READ16(hc11.ix + offset);
+ SET_N16(hc11.iy);
+ SET_Z16(hc11.iy);
+ CYCLES(6);
+}
+
+/* LDY IND, Y 0x18, 0xEE */
+static void HC11OP(ldy_indy)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ hc11.iy = READ16(hc11.iy + offset);
+ SET_N16(hc11.iy);
+ SET_Z16(hc11.iy);
+ CYCLES(6);
+}
+
+
+/* LSLD 0x05 */
+static void HC11OP(lsld)(void)
+{
+ UINT32 r = REG_D << 1;
+ CLEAR_NZVC();
+ SET_C16(r);
+ REG_D = (UINT16)(r);
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+
+ if (((hc11.ccr & CC_N) == CC_N && (hc11.ccr & CC_C) == 0) ||
+ ((hc11.ccr & CC_N) == 0 && (hc11.ccr & CC_C) == CC_C))
+ {
+ hc11.ccr |= CC_V;
+ }
+
+ CYCLES(3);
+}
+
+
+/* PSHA 0x36 */
+static void HC11OP(psha)(void)
+{
+ PUSH8(REG_A);
+ CYCLES(3);
+}
+
+
+/* ORAA IMM 0x8A */
+static void HC11OP(oraa_imm)(void)
+{
+ UINT8 i = FETCH();
+ CLEAR_NZV();
+ REG_A |= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(2);
+}
+
+/* ORAA DIR 0x9A */
+static void HC11OP(oraa_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ CLEAR_NZV();
+ REG_A |= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(3);
+}
+
+/* ORAA EXT 0xBA */
+static void HC11OP(oraa_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ CLEAR_NZV();
+ REG_A |= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(4);
+}
+
+/* ORAA IND, X 0xAA */
+static void HC11OP(oraa_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ CLEAR_NZV();
+ REG_A |= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(4);
+}
+
+/* ORAA IND, Y 0x18, 0xAA */
+static void HC11OP(oraa_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ CLEAR_NZV();
+ REG_A |= i;
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(5);
+}
+
+
+/* ORAB IMM 0xCA */
+static void HC11OP(orab_imm)(void)
+{
+ UINT8 i = FETCH();
+ CLEAR_NZV();
+ REG_B |= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(2);
+}
+
+/* ORAB DIR 0xDA */
+static void HC11OP(orab_dir)(void)
+{
+ UINT8 d = FETCH();
+ UINT8 i = READ8(d);
+ CLEAR_NZV();
+ REG_B |= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(3);
+}
+
+/* ORAB EXT 0xFA */
+static void HC11OP(orab_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ CLEAR_NZV();
+ REG_B |= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(4);
+}
+
+/* ORAB IND, X 0xEA */
+static void HC11OP(orab_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ CLEAR_NZV();
+ REG_B |= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(4);
+}
+
+/* ORAB IND, Y 0x18, 0xEA */
+static void HC11OP(orab_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ CLEAR_NZV();
+ REG_B |= i;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(5);
+}
+
+
+/* PSHB 0x37 */
+static void HC11OP(pshb)(void)
+{
+ PUSH8(REG_B);
+ CYCLES(3);
+}
+
+
+/* PSHX 0x3C */
+static void HC11OP(pshx)(void)
+{
+ PUSH16(hc11.ix);
+ CYCLES(4);
+}
+
+
+/* PSHY 0x18, 0x3C */
+static void HC11OP(pshy)(void)
+{
+ PUSH16(hc11.iy);
+ CYCLES(5);
+}
+
+
+/* PULA 0x32 */
+static void HC11OP(pula)(void)
+{
+ REG_A = POP8();
+ CYCLES(4);
+}
+
+
+/* PULB 0x33 */
+static void HC11OP(pulb)(void)
+{
+ REG_B = POP8();
+ CYCLES(4);
+}
+
+
+/* PULX 0x38 */
+static void HC11OP(pulx)(void)
+{
+ hc11.ix = POP16();
+ CYCLES(5);
+}
+
+
+/* PULY 0x18, 0x38 */
+static void HC11OP(puly)(void)
+{
+ hc11.iy = POP16();
+ CYCLES(6);
+}
+
+
+/* RTS 0x39 */
+static void HC11OP(rts)(void)
+{
+ UINT16 rt_adr = POP16();
+ SET_PC(rt_adr);
+ CYCLES(5);
+}
+
+
+/* SEI 0x0F */
+static void HC11OP(sei)(void)
+{
+ hc11.ccr |= CC_I;
+ CYCLES(2);
+}
+
+
+/* STAA DIR 0x97 */
+static void HC11OP(staa_dir)(void)
+{
+ UINT8 d = FETCH();
+ CLEAR_NZV();
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ WRITE8(d, REG_A);
+ CYCLES(3);
+}
+
+/* STAA EXT 0xB7 */
+static void HC11OP(staa_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ CLEAR_NZV();
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ WRITE8(adr, REG_A);
+ CYCLES(4);
+}
+
+/* STAA IND, X 0xA7 */
+static void HC11OP(staa_indx)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ WRITE8(hc11.ix + offset, REG_A);
+ CYCLES(4);
+}
+
+/* STAA IND, Y 0x18, 0xA7 */
+static void HC11OP(staa_indy)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ WRITE8(hc11.iy + offset, REG_A);
+ CYCLES(5);
+}
+
+/* STAB DIR 0xD7 */
+static void HC11OP(stab_dir)(void)
+{
+ UINT8 d = FETCH();
+ CLEAR_NZV();
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ WRITE8(d, REG_B);
+ CYCLES(3);
+}
+
+/* STAB EXT 0xF7 */
+static void HC11OP(stab_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ CLEAR_NZV();
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ WRITE8(adr, REG_B);
+ CYCLES(4);
+}
+
+/* STAB IND, X 0xE7 */
+static void HC11OP(stab_indx)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ WRITE8(hc11.ix + offset, REG_B);
+ CYCLES(4);
+}
+
+/* STAB IND, Y 0x18, 0xE7 */
+static void HC11OP(stab_indy)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ WRITE8(hc11.iy + offset, REG_B);
+ CYCLES(5);
+}
+
+
+/* STD DIR 0xDD */
+static void HC11OP(std_dir)(void)
+{
+ UINT8 d = FETCH();
+ CLEAR_NZV();
+ WRITE16(d, REG_D);
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+ CYCLES(4);
+}
+
+/* STD EXT 0xFD */
+static void HC11OP(std_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ CLEAR_NZV();
+ WRITE16(adr, REG_D);
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+ CYCLES(5);
+}
+
+/* STD IND, X 0xED */
+static void HC11OP(std_indx)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ WRITE16(hc11.ix + offset, REG_D);
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+ CYCLES(5);
+}
+
+/* STD IND, Y 0x18, 0xED */
+static void HC11OP(std_indy)(void)
+{
+ UINT8 offset = FETCH();
+ CLEAR_NZV();
+ WRITE16(hc11.iy + offset, REG_D);
+ SET_N16(REG_D);
+ SET_Z16(REG_D);
+ CYCLES(6);
+}
+
+
+/* TAB 0x16 */
+static void HC11OP(tab)(void)
+{
+ CLEAR_NZV();
+ REG_B = REG_A;
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(2);
+}
+
+
+/* TAP 0x06 */
+static void HC11OP(tap)(void)
+{
+ UINT8 ccr = hc11.ccr;
+ hc11.ccr = (REG_A & 0xbf) | (ccr & 0x40);
+ CYCLES(2);
+}
+
+
+/* TPA 0x07 */
+static void HC11OP(tpa)(void)
+{
+ REG_A = hc11.ccr;
+ CYCLES(2);
+}
+
+
+/* TSTA 0x4D */
+static void HC11OP(tsta)(void)
+{
+ CLEAR_NZVC();
+ SET_N8(REG_A);
+ SET_Z8(REG_A);
+ CYCLES(2);
+}
+
+/* TSTB 0x5D */
+static void HC11OP(tstb)(void)
+{
+ CLEAR_NZVC();
+ SET_N8(REG_B);
+ SET_Z8(REG_B);
+ CYCLES(2);
+}
+
+/* TST EXT 0x7D */
+static void HC11OP(tst_ext)(void)
+{
+ UINT16 adr = FETCH16();
+ UINT8 i = READ8(adr);
+ CLEAR_NZVC();
+ SET_N8(i);
+ SET_Z8(i);
+ CYCLES(6);
+}
+
+/* TST IND, X 0x6D */
+static void HC11OP(tst_indx)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.ix + offset);
+ CLEAR_NZVC();
+ SET_N8(i);
+ SET_Z8(i);
+ CYCLES(6);
+}
+
+/* TST IND, Y 0x18, 0x6D */
+static void HC11OP(tst_indy)(void)
+{
+ UINT8 offset = FETCH();
+ UINT8 i = READ8(hc11.iy + offset);
+ CLEAR_NZVC();
+ SET_N8(i);
+ SET_Z8(i);
+ CYCLES(6);
+}
+
+
+/* XGDX 0x8F */
+static void HC11OP(xgdx)(void)
+{
+ UINT16 tmp = REG_D;
+ REG_D = hc11.ix;
+ hc11.ix = tmp;
+ CYCLES(3);
+}
+
+
+/* XGDY 0x18, 0x8F */
+static void HC11OP(xgdy)(void)
+{
+ UINT16 tmp = REG_D;
+ REG_D = hc11.iy;
+ hc11.iy = tmp;
+ CYCLES(4);
+}
+
+/*****************************************************************************/
+
+static void HC11OP(page2)(void)
+{
+ UINT8 op2 = FETCH();
+ hc11_optable_page2[op2]();
+}
+
+static void HC11OP(page3)(void)
+{
+ UINT8 op2 = FETCH();
+ hc11_optable_page3[op2]();
+}
+
+static void HC11OP(page4)(void)
+{
+ UINT8 op2 = FETCH();
+ hc11_optable_page4[op2]();
+}
+
+static void HC11OP(invalid)(void)
+{
+ fatalerror("HC11: Invalid opcode 0x%02X at %04X", READ8(hc11.pc-1), hc11.pc-1);
+}
diff --git a/src/emu/cpu/mc68hc11/hc11ops.h b/src/emu/cpu/mc68hc11/hc11ops.h
new file mode 100644
index 00000000000..3c8b2e4aba1
--- /dev/null
+++ b/src/emu/cpu/mc68hc11/hc11ops.h
@@ -0,0 +1,189 @@
+typedef struct {
+ int page;
+ int opcode;
+ void (*handler)(void);
+} HC11_OPCODE_LIST;
+
+static HC11_OPCODE_LIST hc11_opcode_list[] =
+{
+ /* page opcode handler */
+ { 0, 0x1b, HC11OP(aba) },
+ { 0, 0x3a, HC11OP(abx) },
+ { 0x18, 0x3a, HC11OP(aby) },
+ { 0, 0x89, HC11OP(adca_imm) },
+ { 0, 0x99, HC11OP(adca_dir) },
+ { 0, 0xb9, HC11OP(adca_ext) },
+ { 0, 0xa9, HC11OP(adca_indx) },
+ { 0x18, 0xa9, HC11OP(adca_indy) },
+ { 0, 0xc9, HC11OP(adcb_imm) },
+ { 0, 0xd9, HC11OP(adcb_dir) },
+ { 0, 0xf9, HC11OP(adcb_ext) },
+ { 0, 0xe9, HC11OP(adcb_indx) },
+ { 0x18, 0xe9, HC11OP(adcb_indy) },
+ { 0, 0x8b, HC11OP(adda_imm) },
+ { 0, 0x9b, HC11OP(adda_dir) },
+ { 0, 0xbb, HC11OP(adda_ext) },
+ { 0, 0xab, HC11OP(adda_indx) },
+ { 0x18, 0xab, HC11OP(adda_indy) },
+ { 0, 0xcb, HC11OP(addb_imm) },
+ { 0, 0xdb, HC11OP(addb_dir) },
+ { 0, 0xfb, HC11OP(addb_ext) },
+ { 0, 0xeb, HC11OP(addb_indx) },
+ { 0x18, 0xeb, HC11OP(addb_indy) },
+ { 0, 0xc3, HC11OP(addd_imm) },
+ { 0, 0xd3, HC11OP(addd_dir) },
+ { 0, 0xf3, HC11OP(addd_ext) },
+ { 0, 0xe3, HC11OP(addd_indx) },
+ { 0x18, 0xe3, HC11OP(addd_indy) },
+ { 0, 0x84, HC11OP(anda_imm) },
+ { 0, 0x94, HC11OP(anda_dir) },
+ { 0, 0xb4, HC11OP(anda_ext) },
+ { 0, 0xa4, HC11OP(anda_indx) },
+ { 0x18, 0xa4, HC11OP(anda_indy) },
+ { 0, 0xc4, HC11OP(andb_imm) },
+ { 0, 0xd4, HC11OP(andb_dir) },
+ { 0, 0xf4, HC11OP(andb_ext) },
+ { 0, 0xe4, HC11OP(andb_indx) },
+ { 0x18, 0xe4, HC11OP(andb_indy) },
+ { 0, 0x85, HC11OP(bita_imm) },
+ { 0, 0x95, HC11OP(bita_dir) },
+ { 0, 0xb5, HC11OP(bita_ext) },
+ { 0, 0xa5, HC11OP(bita_indx) },
+ { 0x18, 0xa5, HC11OP(bita_indy) },
+ { 0, 0xc5, HC11OP(bitb_imm) },
+ { 0, 0xd5, HC11OP(bitb_dir) },
+ { 0, 0xf5, HC11OP(bitb_ext) },
+ { 0, 0xe5, HC11OP(bitb_indx) },
+ { 0x18, 0xe5, HC11OP(bitb_indy) },
+ { 0, 0x25, HC11OP(bcs) },
+ { 0, 0x27, HC11OP(beq) },
+ { 0, 0x26, HC11OP(bne) },
+ { 0, 0x2f, HC11OP(ble) },
+ { 0, 0x2a, HC11OP(bpl) },
+ { 0, 0x20, HC11OP(bra) },
+ { 0, 0x8d, HC11OP(bsr) },
+ { 0, 0x0e, HC11OP(cli) },
+ { 0, 0x4f, HC11OP(clra) },
+ { 0, 0x5f, HC11OP(clrb) },
+ { 0, 0x7f, HC11OP(clr_ext) },
+ { 0, 0x6f, HC11OP(clr_indx) },
+ { 0x18, 0x6f, HC11OP(clr_indy) },
+ { 0, 0x81, HC11OP(cmpa_imm) },
+ { 0, 0x91, HC11OP(cmpa_dir) },
+ { 0, 0xb1, HC11OP(cmpa_ext) },
+ { 0, 0xa1, HC11OP(cmpa_indx) },
+ { 0x18, 0x81, HC11OP(cmpa_indy) },
+ { 0, 0xc1, HC11OP(cmpb_imm) },
+ { 0, 0xd1, HC11OP(cmpb_dir) },
+ { 0, 0xf1, HC11OP(cmpb_ext) },
+ { 0, 0xe1, HC11OP(cmpb_indx) },
+ { 0x18, 0xe1, HC11OP(cmpb_indy) },
+ { 0x1a, 0x83, HC11OP(cpd_imm) },
+ { 0x1a, 0x93, HC11OP(cpd_dir) },
+ { 0x1a, 0xb3, HC11OP(cpd_ext) },
+ { 0x1a, 0xa3, HC11OP(cpd_indx) },
+ { 0xcd, 0xa3, HC11OP(cpd_indy) },
+ { 0, 0x8c, HC11OP(cpx_imm) },
+ { 0, 0x9c, HC11OP(cpx_dir) },
+ { 0, 0xbc, HC11OP(cpx_ext) },
+ { 0, 0xac, HC11OP(cpx_indx) },
+ { 0xcd, 0xac, HC11OP(cpx_indy) },
+ { 0x18, 0x8c, HC11OP(cpy_imm) },
+ { 0, 0x09, HC11OP(dex) },
+ { 0x18, 0x09, HC11OP(dey) },
+ { 0, 0x88, HC11OP(eora_imm) },
+ { 0, 0x98, HC11OP(eora_dir) },
+ { 0, 0xb8, HC11OP(eora_ext) },
+ { 0, 0xa8, HC11OP(eora_indx) },
+ { 0x18, 0xa8, HC11OP(eora_indy) },
+ { 0, 0xc8, HC11OP(eorb_imm) },
+ { 0, 0xd8, HC11OP(eorb_dir) },
+ { 0, 0xf8, HC11OP(eorb_ext) },
+ { 0, 0xe8, HC11OP(eorb_indx) },
+ { 0x18, 0xe8, HC11OP(eorb_indy) },
+ { 0, 0x4c, HC11OP(inca) },
+ { 0, 0x08, HC11OP(inx) },
+ { 0x18, 0x08, HC11OP(iny) },
+ { 0, 0x7e, HC11OP(jmp_ext) },
+ { 0, 0x9d, HC11OP(jsr_dir) },
+ { 0, 0xbd, HC11OP(jsr_ext) },
+ { 0, 0xad, HC11OP(jsr_indx) },
+ { 0x18, 0xad, HC11OP(jsr_indy) },
+ { 0, 0x86, HC11OP(ldaa_imm) },
+ { 0, 0x96, HC11OP(ldaa_dir) },
+ { 0, 0xb6, HC11OP(ldaa_ext) },
+ { 0, 0xa6, HC11OP(ldaa_indx) },
+ { 0x18, 0xa6, HC11OP(ldaa_indy) },
+ { 0, 0xc6, HC11OP(ldab_imm) },
+ { 0, 0xd6, HC11OP(ldab_dir) },
+ { 0, 0xf6, HC11OP(ldab_ext) },
+ { 0, 0xe6, HC11OP(ldab_indx) },
+ { 0x18, 0xe6, HC11OP(ldab_indy) },
+ { 0, 0xcc, HC11OP(ldd_imm) },
+ { 0, 0xdc, HC11OP(ldd_dir) },
+ { 0, 0xfc, HC11OP(ldd_ext) },
+ { 0, 0xec, HC11OP(ldd_indx) },
+ { 0x18, 0xec, HC11OP(ldd_indy) },
+ { 0, 0x8e, HC11OP(lds_imm) },
+ { 0, 0x9e, HC11OP(lds_dir) },
+ { 0, 0xbe, HC11OP(lds_ext) },
+ { 0, 0xae, HC11OP(lds_indx) },
+ { 0x18, 0xae, HC11OP(lds_indy) },
+ { 0, 0xce, HC11OP(ldx_imm) },
+ { 0, 0xde, HC11OP(ldx_dir) },
+ { 0, 0xfe, HC11OP(ldx_ext) },
+ { 0, 0xee, HC11OP(ldx_indx) },
+ { 0xcd, 0xee, HC11OP(ldx_indy) },
+ { 0x18, 0xce, HC11OP(ldy_imm) },
+ { 0x18, 0xde, HC11OP(ldy_dir) },
+ { 0x18, 0xfe, HC11OP(ldy_ext) },
+ { 0x1a, 0xee, HC11OP(ldy_indx) },
+ { 0x18, 0xee, HC11OP(ldy_indy) },
+ { 0, 0x05, HC11OP(lsld) },
+ { 0, 0x8a, HC11OP(oraa_imm) },
+ { 0, 0x9a, HC11OP(oraa_dir) },
+ { 0, 0xba, HC11OP(oraa_ext) },
+ { 0, 0xaa, HC11OP(oraa_indx) },
+ { 0x18, 0xaa, HC11OP(oraa_indy) },
+ { 0, 0xca, HC11OP(orab_imm) },
+ { 0, 0xda, HC11OP(orab_dir) },
+ { 0, 0xfa, HC11OP(orab_ext) },
+ { 0, 0xea, HC11OP(orab_indx) },
+ { 0x18, 0xea, HC11OP(orab_indy) },
+ { 0, 0x36, HC11OP(psha) },
+ { 0, 0x37, HC11OP(pshb) },
+ { 0, 0x3c, HC11OP(pshx) },
+ { 0x18, 0x3c, HC11OP(pshy) },
+ { 0, 0x32, HC11OP(pula) },
+ { 0, 0x33, HC11OP(pulb) },
+ { 0, 0x38, HC11OP(pulx) },
+ { 0x18, 0x38, HC11OP(puly) },
+ { 0, 0x39, HC11OP(rts) },
+ { 0, 0x0f, HC11OP(sei) },
+ { 0, 0x97, HC11OP(staa_dir) },
+ { 0, 0xb7, HC11OP(staa_ext) },
+ { 0, 0xa7, HC11OP(staa_indx) },
+ { 0x18, 0xa7, HC11OP(staa_indy) },
+ { 0, 0xd7, HC11OP(stab_dir) },
+ { 0, 0xf7, HC11OP(stab_ext) },
+ { 0, 0xe7, HC11OP(stab_indx) },
+ { 0x18, 0xe7, HC11OP(stab_indy) },
+ { 0, 0xdd, HC11OP(std_dir) },
+ { 0, 0xfd, HC11OP(std_ext) },
+ { 0, 0xed, HC11OP(std_indx) },
+ { 0x18, 0xed, HC11OP(std_indy) },
+ { 0, 0x16, HC11OP(tab) },
+ { 0, 0x06, HC11OP(tap) },
+ { 0, 0x07, HC11OP(tpa) },
+ { 0, 0x4d, HC11OP(tsta) },
+ { 0, 0x5d, HC11OP(tstb) },
+ { 0, 0x7d, HC11OP(tst_ext) },
+ { 0, 0x6d, HC11OP(tst_indx) },
+ { 0x18, 0x6d, HC11OP(tst_indy) },
+ { 0, 0x8f, HC11OP(xgdx) },
+ { 0x18, 0x8f, HC11OP(xgdy) },
+
+ { 0, 0x18, HC11OP(page2) },
+ { 0, 0x1a, HC11OP(page3) },
+ { 0, 0xcd, HC11OP(page4) },
+};
diff --git a/src/emu/cpu/mc68hc11/mc68hc11.c b/src/emu/cpu/mc68hc11/mc68hc11.c
new file mode 100644
index 00000000000..4fd2528c364
--- /dev/null
+++ b/src/emu/cpu/mc68hc11/mc68hc11.c
@@ -0,0 +1,494 @@
+/*
+ Motorola MC68HC11 emulator
+
+ Written by Ville Linde
+ */
+
+#include "debugger.h"
+#include "mc68hc11.h"
+
+enum {
+ HC11_PC = 1,
+ HC11_SP,
+ HC11_A,
+ HC11_B,
+ HC11_IX,
+ HC11_IY
+};
+
+#define CC_S 0x80
+#define CC_X 0x40
+#define CC_H 0x20
+#define CC_I 0x10
+#define CC_N 0x08
+#define CC_Z 0x04
+#define CC_V 0x02
+#define CC_C 0x01
+
+typedef struct
+{
+ union {
+ struct {
+#ifdef LSB_FIRST
+ UINT8 b;
+ UINT8 a;
+#else
+ UINT8 a;
+ UINT8 b;
+#endif
+ } d8;
+ UINT16 d16;
+ } d;
+
+ UINT16 ix;
+ UINT16 iy;
+ UINT16 sp;
+ UINT16 pc;
+ UINT16 ppc;
+ UINT8 ccr;
+
+ UINT8 adctl;
+ int ad_channel;
+
+ int (*irq_callback)(int irqline);
+ int icount;
+ int ram_position;
+ int reg_position;
+} HC11_REGS;
+
+static HC11_REGS hc11;
+static UINT8 *internal_ram;
+static int internal_ram_size;
+
+#define HC11OP(XX) hc11_##XX
+
+/*****************************************************************************/
+/* Internal registers */
+
+static UINT8 hc11_regs_r(UINT32 address)
+{
+ int reg = address & 0xff;
+
+ switch(reg)
+ {
+ case 0x00: /* PORTA */
+ return io_read_byte(MC68HC11_IO_PORTA);
+ case 0x01: /* DDRA */
+ return 0;
+ case 0x09: /* DDRD */
+ return 0;
+ case 0x28: /* SPCR1 */
+ return 0;
+ case 0x30: /* ADCTL */
+ return 0x80;
+ case 0x31: /* ADR1 */
+ {
+ if (hc11.adctl & 0x10)
+ {
+ return io_read_byte((hc11.adctl & 0x4) + MC68HC11_IO_AD0);
+ }
+ else
+ {
+ return io_read_byte((hc11.adctl & 0x7) + MC68HC11_IO_AD0);
+ }
+ break;
+ }
+ case 0x32: /* ADR2 */
+ {
+ if (hc11.adctl & 0x10)
+ {
+ return io_read_byte((hc11.adctl & 0x4) + MC68HC11_IO_AD1);
+ }
+ else
+ {
+ return io_read_byte((hc11.adctl & 0x7) + MC68HC11_IO_AD0);
+ }
+ break;
+ }
+ case 0x33: /* ADR3 */
+ {
+ if (hc11.adctl & 0x10)
+ {
+ return io_read_byte((hc11.adctl & 0x4) + MC68HC11_IO_AD2);
+ }
+ else
+ {
+ return io_read_byte((hc11.adctl & 0x7) + MC68HC11_IO_AD0);
+ }
+ break;
+ }
+ case 0x34: /* ADR4 */
+ {
+ if (hc11.adctl & 0x10)
+ {
+ return io_read_byte((hc11.adctl & 0x4) + MC68HC11_IO_AD3);
+ }
+ else
+ {
+ return io_read_byte((hc11.adctl & 0x7) + MC68HC11_IO_AD0);
+ }
+ break;
+ }
+ case 0x38: /* OPT2 */
+ return 0;
+ case 0x70: /* SCBDH */
+ return 0;
+ case 0x71: /* SCBDL */
+ return 0;
+ case 0x72: /* SCCR1 */
+ return 0;
+ case 0x73: /* SCCR2 */
+ return 0;
+ case 0x74: /* SCSR1 */
+ return 0x40;
+ case 0x7c: /* PORTH */
+ return io_read_byte(MC68HC11_IO_PORTH);
+ case 0x7e: /* PORTG */
+ return io_read_byte(MC68HC11_IO_PORTG);
+ case 0x7f: /* DDRG */
+ return 0;
+
+ case 0x88: /* SPCR2 */
+ return 0;
+ case 0x89: /* SPSR2 */
+ return 0x80;
+ case 0x8a: /* SPDR2 */
+ return io_read_byte(MC68HC11_IO_SPI2_DATA);
+
+ case 0x8b: /* OPT4 */
+ return 0;
+ }
+
+ fatalerror("HC11: regs_r %02X", reg);
+ return 0; // Dummy
+}
+
+static void hc11_regs_w(UINT32 address, UINT8 value)
+{
+ int reg = address & 0xff;
+
+ switch(reg)
+ {
+ case 0x00: /* PORTA */
+ io_write_byte(MC68HC11_IO_PORTA, value);
+ return;
+ case 0x01: /* DDRA */
+ //mame_printf_debug("HC11: ddra = %02X\n", value);
+ return;
+ case 0x08: /* PORTD */
+ io_write_byte(MC68HC11_IO_PORTD, value);
+ return;
+ case 0x09: /* DDRD */
+ //mame_printf_debug("HC11: ddrd = %02X\n", value);
+ return;
+ case 0x22: /* TMSK1 */
+ return;
+ case 0x24: /* TMSK2 */
+ return;
+ case 0x28: /* SPCR1 */
+ return;
+ case 0x30: /* ADCTL */
+ hc11.adctl = value;
+ return;
+ case 0x38: /* OPT2 */
+ return;
+ case 0x39: /* OPTION */
+ return;
+
+ case 0x3d: /* INIT */
+ {
+ int reg_page = value & 0xf;
+ int ram_page = (value >> 4) & 0xf;
+
+ if (reg_page == ram_page) {
+ hc11.reg_position = reg_page << 12;
+ hc11.ram_position = (ram_page << 12) + 0x100;
+ } else {
+ hc11.reg_position = reg_page << 12;
+ hc11.ram_position = ram_page << 12;
+ }
+ return;
+ }
+
+ case 0x3f: /* CONFIG */
+ return;
+
+ case 0x70: /* SCBDH */
+ return;
+ case 0x71: /* SCBDL */
+ return;
+ case 0x72: /* SCCR1 */
+ return;
+ case 0x73: /* SCCR2 */
+ return;
+ case 0x77: /* SCDRL */
+ return;
+ case 0x7c: /* PORTH */
+ io_write_byte(MC68HC11_IO_PORTH, value);
+ return;
+ case 0x7d: /* DDRH */
+ //mame_printf_debug("HC11: ddrh = %02X at %04X\n", value, hc11.pc);
+ return;
+ case 0x7e: /* PORTG */
+ io_write_byte(MC68HC11_IO_PORTG, value);
+ return;
+ case 0x7f: /* DDRG */
+ //mame_printf_debug("HC11: ddrg = %02X at %04X\n", value, hc11.pc);
+ return;
+
+ case 0x88: /* SPCR2 */
+ return;
+ case 0x89: /* SPSR2 */
+ return;
+ case 0x8a: /* SPDR2 */
+ io_write_byte(MC68HC11_IO_SPI2_DATA, value);
+ return;
+
+ case 0x8b: /* OPT4 */
+ return;
+
+ }
+ fatalerror("HC11: regs_w %02X, %02X", reg, value);
+}
+
+/*****************************************************************************/
+
+INLINE UINT8 FETCH(void)
+{
+ return cpu_readop(hc11.pc++);
+}
+
+INLINE UINT16 FETCH16(void)
+{
+ UINT16 w;
+ w = (cpu_readop(hc11.pc) << 8) | (cpu_readop(hc11.pc+1));
+ hc11.pc += 2;
+ return w;
+}
+
+INLINE UINT8 READ8(UINT32 address)
+{
+ if(address >= hc11.reg_position && address < hc11.reg_position+0x100)
+ {
+ return hc11_regs_r(address);
+ }
+ else if(address >= hc11.ram_position && address < hc11.ram_position+internal_ram_size)
+ {
+ return internal_ram[address-hc11.ram_position];
+ }
+ return program_read_byte(address);
+}
+
+INLINE void WRITE8(UINT32 address, UINT8 value)
+{
+ if(address >= hc11.reg_position && address < hc11.reg_position+0x100)
+ {
+ hc11_regs_w(address, value);
+ return;
+ }
+ else if(address >= hc11.ram_position && address < hc11.ram_position+internal_ram_size)
+ {
+ internal_ram[address-hc11.ram_position] = value;
+ return;
+ }
+ program_write_byte(address, value);
+}
+
+INLINE UINT16 READ16(UINT32 address)
+{
+ return (READ8(address) << 8) | (READ8(address+1));
+}
+
+INLINE void WRITE16(UINT32 address, UINT16 value)
+{
+ WRITE8(address+0, (value >> 8) & 0xff);
+ WRITE8(address+1, (value >> 0) & 0xff);
+}
+
+/*****************************************************************************/
+
+static void (*hc11_optable[256])(void);
+static void (*hc11_optable_page2[256])(void);
+static void (*hc11_optable_page3[256])(void);
+static void (*hc11_optable_page4[256])(void);
+
+#include "hc11ops.c"
+#include "hc11ops.h"
+
+static void hc11_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int i;
+
+ /* clear the opcode tables */
+ for(i=0; i < 256; i++) {
+ hc11_optable[i] = HC11OP(invalid);
+ hc11_optable_page2[i] = HC11OP(invalid);
+ hc11_optable_page3[i] = HC11OP(invalid);
+ hc11_optable_page4[i] = HC11OP(invalid);
+ }
+ /* fill the opcode tables */
+ for(i=0; i < sizeof(hc11_opcode_list)/sizeof(HC11_OPCODE_LIST); i++)
+ {
+ switch(hc11_opcode_list[i].page)
+ {
+ case 0x00:
+ hc11_optable[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler;
+ break;
+ case 0x18:
+ hc11_optable_page2[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler;
+ break;
+ case 0x1A:
+ hc11_optable_page3[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler;
+ break;
+ case 0xCD:
+ hc11_optable_page4[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler;
+ break;
+ }
+ }
+
+ internal_ram_size = 1280; /* FIXME: this is for MC68HC11M0 */
+ internal_ram = auto_malloc(internal_ram_size);
+
+ hc11.reg_position = 0;
+ hc11.ram_position = 0x100;
+ hc11.irq_callback = irqcallback;
+}
+
+static void hc11_reset(void)
+{
+ hc11.pc = READ16(0xfffe);
+}
+
+static void hc11_exit(void)
+{
+
+}
+
+static void hc11_get_context(void *dst)
+{
+ if (dst) {
+ *(HC11_REGS*)dst = hc11;
+ }
+}
+
+static void hc11_set_context(void *src)
+{
+ if (src) {
+ hc11 = *(HC11_REGS*)src;
+ }
+ change_pc(hc11.pc);
+}
+
+static int hc11_execute(int cycles)
+{
+ hc11.icount = cycles;
+
+ while(hc11.icount > 0)
+ {
+ UINT8 op;
+
+ hc11.ppc = hc11.pc;
+ CALL_MAME_DEBUG;
+
+ op = FETCH();
+ hc11_optable[op]();
+ }
+
+ return cycles-hc11.icount;
+}
+
+/*****************************************************************************/
+
+static void mc68hc11_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC: hc11.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_PC: hc11.pc = info->i; change_pc(hc11.pc); break;
+ case CPUINFO_INT_REGISTER + HC11_SP: hc11.sp = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_A: hc11.d.d8.a = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_B: hc11.d.d8.b = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_IX: hc11.ix = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_IY: hc11.iy = info->i; break;
+ }
+}
+
+void mc68hc11_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(hc11); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 41; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC: /* intentional fallthrough */
+ case CPUINFO_INT_REGISTER + HC11_PC: info->i = hc11.pc; break;
+ case CPUINFO_INT_REGISTER + HC11_SP: info->i = hc11.sp; break;
+ case CPUINFO_INT_REGISTER + HC11_A: info->i = hc11.d.d8.a; break;
+ case CPUINFO_INT_REGISTER + HC11_B: info->i = hc11.d.d8.b; break;
+ case CPUINFO_INT_REGISTER + HC11_IX: info->i = hc11.ix; break;
+ case CPUINFO_INT_REGISTER + HC11_IY: info->i = hc11.iy; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mc68hc11_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = hc11_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = hc11_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = hc11_init; break;
+ case CPUINFO_PTR_RESET: info->reset = hc11_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = hc11_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = hc11_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = hc11_disasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &hc11.icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MC68HC11"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola MC68HC11"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2004 Ville Linde"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ (hc11.ccr & CC_S) ? 'S' : '.',
+ (hc11.ccr & CC_X) ? 'X' : '.',
+ (hc11.ccr & CC_H) ? 'H' : '.',
+ (hc11.ccr & CC_I) ? 'I' : '.',
+ (hc11.ccr & CC_N) ? 'N' : '.',
+ (hc11.ccr & CC_Z) ? 'Z' : '.',
+ (hc11.ccr & CC_V) ? 'V' : '.',
+ (hc11.ccr & CC_C) ? 'C' : '.');
+ break;
+
+ case CPUINFO_STR_REGISTER + HC11_PC: sprintf(info->s, "PC: %04X", hc11.pc); break;
+ case CPUINFO_STR_REGISTER + HC11_SP: sprintf(info->s, "SP: %04X", hc11.sp); break;
+ case CPUINFO_STR_REGISTER + HC11_A: sprintf(info->s, "A: %02X", hc11.d.d8.a); break;
+ case CPUINFO_STR_REGISTER + HC11_B: sprintf(info->s, "B: %02X", hc11.d.d8.b); break;
+ case CPUINFO_STR_REGISTER + HC11_IX: sprintf(info->s, "IX: %04X", hc11.ix); break;
+ case CPUINFO_STR_REGISTER + HC11_IY: sprintf(info->s, "IY: %04X", hc11.iy); break;
+ }
+}
diff --git a/src/emu/cpu/mc68hc11/mc68hc11.h b/src/emu/cpu/mc68hc11/mc68hc11.h
new file mode 100644
index 00000000000..1921f65ba77
--- /dev/null
+++ b/src/emu/cpu/mc68hc11/mc68hc11.h
@@ -0,0 +1,32 @@
+#ifndef _MC68HC11_H
+#define _MC68HC11_H
+
+#include "cpuintrf.h"
+
+#ifdef MAME_DEBUG
+offs_t hc11_disasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+void mc68hc11_get_info(UINT32 state, cpuinfo *info);
+
+
+#define MC68HC11_IO_PORTA 0x00
+#define MC68HC11_IO_PORTB 0x01
+#define MC68HC11_IO_PORTC 0x02
+#define MC68HC11_IO_PORTD 0x03
+#define MC68HC11_IO_PORTE 0x04
+#define MC68HC11_IO_PORTF 0x05
+#define MC68HC11_IO_PORTG 0x06
+#define MC68HC11_IO_PORTH 0x07
+#define MC68HC11_IO_SPI1_DATA 0x08
+#define MC68HC11_IO_SPI2_DATA 0x09
+#define MC68HC11_IO_AD0 0x10
+#define MC68HC11_IO_AD1 0x11
+#define MC68HC11_IO_AD2 0x12
+#define MC68HC11_IO_AD3 0x13
+#define MC68HC11_IO_AD4 0x14
+#define MC68HC11_IO_AD5 0x15
+#define MC68HC11_IO_AD6 0x16
+#define MC68HC11_IO_AD7 0x17
+
+#endif
diff --git a/src/emu/cpu/minx/minx.c b/src/emu/cpu/minx/minx.c
new file mode 100644
index 00000000000..9f36ae3aba8
--- /dev/null
+++ b/src/emu/cpu/minx/minx.c
@@ -0,0 +1,325 @@
+/*
+ Implementation for the Nintendo Minx CPU.
+
+ Registers (mindX13.txt):
+ 8bit: A B H L FLAGS N U V
+ 16bit: BA
+ 24bit: HL, X1, X2, NN, SP
+
+
+ "sunlab":
+ 16bit:
+ V:PC if high bit set, extended to 23 bits, upper 8 bits V
+ SP
+ BA
+ I:HL
+ (XI:)X
+ (YI:)Y
+
+ 8bit:
+ A, B, H, L
+ U - delayed jump bank. When a jump occurs, V is set to this value
+ V
+ F - flags IDLBSOCZ
+ I - Interrupt branch
+ D - Interrupt disable
+ L - low mask mode enable
+ B - bcd decimal mode enable
+ S - sign flag
+ O - overflow flag
+ C - carry flag
+ Z - zero flag
+ E - exception register
+ I
+ N
+ XI - index/extension
+ YI - index/extension
+
+TODO:
+- Add support for O and C flags in NEG8 instruction
+- Add support for CE D8 (MUL) and CE D9 (DIV)
+- Add support for CF xx instructions
+- Doublecheck behaviour of CMPN instructions ( CF 60 .. CF 63 )
+- Figure out the number of cycles taken by each instruction (this
+ information is currently not known/available).
+
+*/
+
+#include "minx.h"
+#include "debugger.h"
+
+#define FLAG_I 0x80
+#define FLAG_D 0x40
+#define FLAG_L 0x20
+#define FLAG_B 0x10
+#define FLAG_S 0x08
+#define FLAG_O 0x04
+#define FLAG_C 0x02
+#define FLAG_Z 0x01
+
+#define EXEC_X0 0x80
+#define EXEC_X1 0x40
+#define EXEC_X2 0x20
+#define EXEC_DZ 0x10
+#define EXEC_EN 0x08
+#define EXEC_04 0x04
+#define EXEC_02 0x02
+#define EXEC_01 0x01
+
+
+typedef struct {
+// MINX_CONFIG config;
+ UINT16 PC;
+ UINT16 SP;
+ UINT16 BA;
+ UINT16 HL;
+ UINT16 X;
+ UINT16 Y;
+ UINT8 U;
+ UINT8 V;
+ UINT8 F;
+ UINT8 E;
+ UINT8 N;
+ UINT8 I;
+ UINT8 XI;
+ UINT8 YI;
+ UINT8 check_interrupt;
+} minx_regs;
+
+static minx_regs regs;
+int minx_icount;
+
+#define rd(offset) program_read_byte_8( offset )
+#define wr(offset,data) program_write_byte_8( offset, data )
+#define minx_PC ( ( regs.PC & 0x8000 ) ? ( regs.V << 15 ) | (regs.PC & 0x7FFF ) : regs.PC )
+
+INLINE UINT16 rd16( UINT32 offset ) {
+ return rd( offset ) | ( rd( offset + 1 ) << 8 );
+}
+
+INLINE void wr16( UINT32 offset, UINT16 data ) {
+ wr( offset, ( data & 0x00FF ) );
+ wr( offset + 1, ( data >> 8 ) );
+}
+
+static void minx_init(int index, int clock, const void *config, int (*irqcallback)(int)) {
+ if ( config != NULL ) {
+ } else {
+ }
+}
+
+static void minx_reset( void ) {
+ memset( &regs, 0, sizeof(regs) );
+ regs.PC = ( rd( 1 ) << 8 ) | rd( 0 );
+ change_pc( regs.PC );
+}
+
+static void minx_exit( void ) {
+}
+
+INLINE UINT8 rdop( void ) {
+ UINT8 op = rd( minx_PC );
+ regs.PC++;
+ return op;
+}
+
+INLINE UINT16 rdop16( void ) {
+ UINT16 op = rdop();
+ op = op | ( rdop() << 8 );
+ return op;
+}
+
+#include "minxfunc.h"
+#include "minxopce.h"
+#include "minxopcf.h"
+#include "minxops.h"
+
+static int minx_execute( int cycles ) {
+ UINT32 oldpc;
+ UINT8 op;
+
+ minx_icount = cycles;
+
+ do {
+ CALL_MAME_DEBUG;
+ oldpc = minx_PC;
+ op = rdop();
+ insnminx[op]();
+ minx_icount -= insnminx_cycles[op];
+ } while ( minx_icount > 0 );
+ return cycles - minx_icount;
+}
+
+static void minx_burn( int cycles ) {
+ minx_icount = 0;
+}
+
+static void minx_set_context( void *src ) {
+}
+
+static void minx_get_context( void *dst ) {
+}
+
+static unsigned minx_get_reg( int regnum ) {
+ switch( regnum ) {
+ case REG_PC: return (regs.PC & 0x8000) ? ( regs.V << 15 ) | ( regs.PC & 0x7FFF ) : regs.PC;
+ case MINX_PC: return regs.PC;
+ case REG_SP:
+ case MINX_SP: return regs.SP;
+ case MINX_BA: return regs.BA;
+ case MINX_HL: return regs.HL;
+ case MINX_X: return regs.X;
+ case MINX_Y: return regs.Y;
+ case MINX_U: return regs.U;
+ case MINX_V: return regs.V;
+ case MINX_F: return regs.F;
+ case MINX_E: return regs.E;
+ case MINX_N: return regs.N;
+ case MINX_I: return regs.I;
+ case MINX_XI: return regs.XI;
+ case MINX_YI: return regs.YI;
+ }
+ return 0;
+}
+
+static void minx_set_reg( int regnum, unsigned val ) {
+ switch( regnum ) {
+ case REG_PC:
+ case MINX_PC: regs.PC = val; break;
+ case REG_SP:
+ case MINX_SP: regs.SP = val; break;
+ case MINX_BA: regs.BA = val; break;
+ case MINX_HL: regs.HL = val; break;
+ case MINX_X: regs.X = val; break;
+ case MINX_Y: regs.Y = val; break;
+ case MINX_U: regs.U = val; break;
+ case MINX_V: regs.V = val; break;
+ case MINX_F: regs.F = val; break;
+ case MINX_E: regs.E = val; break;
+ case MINX_N: regs.N = val; break;
+ case MINX_I: regs.I = val; break;
+ case MINX_XI: regs.XI = val; break;
+ case MINX_YI: regs.YI = val; break;
+ }
+}
+
+static void minx_set_irq_line( int irqline, int state ) {
+ if ( state == ASSERT_LINE ) {
+ } else {
+ }
+}
+
+static void minx_set_info( UINT32 state, cpuinfo *info ) {
+ switch( state ) {
+ case CPUINFO_INT_INPUT_STATE + 0:
+ minx_set_irq_line( state - CPUINFO_INT_INPUT_STATE, info->i ); break;
+
+ case CPUINFO_INT_REGISTER + MINX_PC:
+ case CPUINFO_INT_REGISTER + MINX_SP:
+ case CPUINFO_INT_REGISTER + MINX_BA:
+ case CPUINFO_INT_REGISTER + MINX_HL:
+ case CPUINFO_INT_REGISTER + MINX_X:
+ case CPUINFO_INT_REGISTER + MINX_Y:
+ case CPUINFO_INT_REGISTER + MINX_U:
+ case CPUINFO_INT_REGISTER + MINX_V:
+ case CPUINFO_INT_REGISTER + MINX_F:
+ case CPUINFO_INT_REGISTER + MINX_E:
+ case CPUINFO_INT_REGISTER + MINX_N:
+ case CPUINFO_INT_REGISTER + MINX_I:
+ case CPUINFO_INT_REGISTER + MINX_XI:
+ case CPUINFO_INT_REGISTER + MINX_YI:
+ minx_set_reg( state - CPUINFO_INT_REGISTER, info->i ); break;
+ }
+}
+
+void minx_get_info( UINT32 state, cpuinfo *info ) {
+ switch( state ) {
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(minx_regs); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 4; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 23; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; break;
+ case CPUINFO_INT_REGISTER + REG_PC:
+ case CPUINFO_INT_REGISTER + REG_SP:
+ case CPUINFO_INT_REGISTER + MINX_PC:
+ case CPUINFO_INT_REGISTER + MINX_SP:
+ case CPUINFO_INT_REGISTER + MINX_BA:
+ case CPUINFO_INT_REGISTER + MINX_HL:
+ case CPUINFO_INT_REGISTER + MINX_X:
+ case CPUINFO_INT_REGISTER + MINX_Y:
+ case CPUINFO_INT_REGISTER + MINX_U:
+ case CPUINFO_INT_REGISTER + MINX_V:
+ case CPUINFO_INT_REGISTER + MINX_F:
+ case CPUINFO_INT_REGISTER + MINX_E:
+ case CPUINFO_INT_REGISTER + MINX_N:
+ case CPUINFO_INT_REGISTER + MINX_I:
+ case CPUINFO_INT_REGISTER + MINX_XI:
+ case CPUINFO_INT_REGISTER + MINX_YI: info->i = minx_get_reg( state - CPUINFO_INT_REGISTER ); break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0x0000; break;
+ case CPUINFO_PTR_SET_INFO: info->setinfo = minx_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = minx_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = minx_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = minx_init; break;
+ case CPUINFO_PTR_RESET: info->reset = minx_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = minx_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = minx_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = minx_burn; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = minx_dasm; break;
+#endif
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &minx_icount; break;
+ case CPUINFO_STR_NAME: strcpy( info->s = cpuintrf_temp_str(), "Minx" ); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy( info->s = cpuintrf_temp_str(), "Nintendo Minx" ); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy( info->s = cpuintrf_temp_str(), "0.1" ); break;
+ case CPUINFO_STR_CORE_FILE: strcpy( info->s = cpuintrf_temp_str(), __FILE__ ); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy( info->s = cpuintrf_temp_str(), "Copyright (C) 2006 by The MESS Team." ); break;
+ case CPUINFO_STR_FLAGS:
+ sprintf( info->s = cpuintrf_temp_str(), "%c%c%c%c%c%c%c%c-%c%c%c%c%c",
+ regs.F & FLAG_I ? 'I' : '.',
+ regs.F & FLAG_D ? 'D' : '.',
+ regs.F & FLAG_L ? 'L' : '.',
+ regs.F & FLAG_B ? 'B' : '.',
+ regs.F & FLAG_S ? 'S' : '.',
+ regs.F & FLAG_O ? 'O' : '.',
+ regs.F & FLAG_C ? 'C' : '.',
+ regs.F & FLAG_Z ? 'Z' : '.',
+ regs.E & EXEC_X0 ? '0' : '.',
+ regs.E & EXEC_X1 ? '1' : '.',
+ regs.E & EXEC_X2 ? '2' : '.',
+ regs.E & EXEC_DZ ? 'z' : '.',
+ regs.E & EXEC_EN ? 'E' : '.' );
+ break;
+ case CPUINFO_STR_REGISTER + MINX_PC: sprintf( info->s = cpuintrf_temp_str(), "PC:%04X", regs.PC ); break;
+ case CPUINFO_STR_REGISTER + MINX_SP: sprintf( info->s = cpuintrf_temp_str(), "SP:%04X", regs.SP ); break;
+ case CPUINFO_STR_REGISTER + MINX_BA: sprintf( info->s = cpuintrf_temp_str(), "BA:%04X", regs.BA ); break;
+ case CPUINFO_STR_REGISTER + MINX_HL: sprintf( info->s = cpuintrf_temp_str(), "HL:%04X", regs.HL ); break;
+ case CPUINFO_STR_REGISTER + MINX_X: sprintf( info->s = cpuintrf_temp_str(), "X:%04X", regs.X ); break;
+ case CPUINFO_STR_REGISTER + MINX_Y: sprintf( info->s = cpuintrf_temp_str(), "Y:%04X", regs.Y ); break;
+ case CPUINFO_STR_REGISTER + MINX_U: sprintf( info->s = cpuintrf_temp_str(), "U:%02X", regs.U ); break;
+ case CPUINFO_STR_REGISTER + MINX_V: sprintf( info->s = cpuintrf_temp_str(), "V:%02X", regs.V ); break;
+ case CPUINFO_STR_REGISTER + MINX_F: sprintf( info->s = cpuintrf_temp_str(), "F:%02X", regs.F ); break;
+ case CPUINFO_STR_REGISTER + MINX_E: sprintf( info->s = cpuintrf_temp_str(), "E:%02X", regs.E ); break;
+ case CPUINFO_STR_REGISTER + MINX_N: sprintf( info->s = cpuintrf_temp_str(), "N:%02X", regs.N ); break;
+ case CPUINFO_STR_REGISTER + MINX_I: sprintf( info->s = cpuintrf_temp_str(), "I:%02X", regs.I ); break;
+ case CPUINFO_STR_REGISTER + MINX_XI: sprintf( info->s = cpuintrf_temp_str(), "XI:%02X", regs.XI ); break;
+ case CPUINFO_STR_REGISTER + MINX_YI: sprintf( info->s = cpuintrf_temp_str(), "YI:%02X", regs.YI ); break;
+ }
+}
+
+
+
+
diff --git a/src/emu/cpu/minx/minx.h b/src/emu/cpu/minx/minx.h
new file mode 100644
index 00000000000..e0a661293fb
--- /dev/null
+++ b/src/emu/cpu/minx/minx.h
@@ -0,0 +1,18 @@
+#ifndef minx_H
+#define minx_H
+#include "cpuintrf.h"
+#include "osd_cpu.h"
+#include "driver.h"
+
+enum {
+ MINX_PC=1, MINX_SP, MINX_BA, MINX_HL, MINX_X, MINX_Y,
+ MINX_U, MINX_V, MINX_F, MINX_E, MINX_N, MINX_I,
+ MINX_XI, MINX_YI,
+};
+
+#ifdef MAME_DEBUG
+extern unsigned minx_dasm( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram );
+#endif
+
+#endif
+
diff --git a/src/emu/cpu/minx/minxd.c b/src/emu/cpu/minx/minxd.c
new file mode 100644
index 00000000000..479b5ff9b4b
--- /dev/null
+++ b/src/emu/cpu/minx/minxd.c
@@ -0,0 +1,465 @@
+/************************************************************
+
+ Nintendo Minx CPU disassembly
+
+
+************************************************************/
+
+#include "debugger.h"
+#include "minx.h"
+
+enum e_mnemonic {
+ zADD=0, zADDC, zAND, zBCDD, zBCDE, zBCDX, zCALL, zCALLC, zCALLG, zCALLGE, zCALLL,
+ zCALLLE, zCALLN, zCALLNC, zCALLNO, zCALLNZ, zCALLO, zCALLP, zCALLNX0,
+ zCALLNX1, zCALLNX2, zCALLNX3, zCALLX0, zCALLX1, zCALLX2, zCALLX3, zCALLZ,
+ zCMP, zCMPN, zDEC, zDIV, zEXT, zHALT, zINC, zINT,
+ zJC, zJDBNZ, zJG, zJGE, zJINT, zJL, zJLE, zJMP,
+ zJN, zJNX0, zJNX1, zJNX2, zJNX3, zJNC, zJNO, zJNZ,
+ zJO, zJP, zJX0, zJX1, zJX2, zJX3, zJZ, zMOV,
+ zMUL, zNEG, zNOP, zNOT, zOR, zPOP, zPOPA, zPOPAX,
+ zPOPX, zPUSH, zPUSHA, zPUSHAX, zPUSHX, zRET, zRETI, zRETSKIP,
+ zROL, zROLC, zROR, zRORC, zSAL, zSAR, zSHL, zSHR, zSUB,
+ zSUBC, zTEST, zXCHG, zXOR, zDB
+};
+
+enum e_operand {
+ R_A=1, /* A */
+ R_B, /* B */
+ R_L, /* L */
+ R_H, /* H */
+ R_N, /* N */
+ R_F, /* F */
+ R_SP, /* SP */
+ R_BA, /* BA */
+ R_HL, /* HL */
+ R_X, /* X */
+ R_Y, /* Y */
+ R_U, /* U */
+ R_V, /* V */
+ R_I, /* I */
+ R_XI, /* XI */
+ R_YI, /* YI */
+ R_PC, /* PC */
+ I_8, /* 8 bit immediate */
+ I_16, /* 16 bit immediate */
+ D_8, /* PC + 8 bit displacement (signed) */
+ D_16, /* PC + 16 bit displacement */
+ S_8, /* SP + 8 bit displacement (signed) */
+ M_IHL, /* [I+HL] */
+ M_N8, /* [I+N+ofs8] */
+ M_I16, /* [I+ofs16] */
+ M_X, /* [X] */
+ M_Y, /* [Y] */
+ M_X8, /* [X + 8 bit displacement (signed)] */
+ M_Y8, /* [Y + 8 bit displacement (signed)] */
+ M_XL, /* [X + L (signed)] */
+ M_YL, /* [Y + L (signed)] */
+ M_16, /* [16bit] */
+ M_HL, /* [HL] */
+ OP, OP1
+};
+
+static const char *s_mnemonic[] = {
+ "add", "addc", "and", "bcdd", "bcde", "bcdx", "call", "callc", "callg", "callge", "calll",
+ "callle", "calln", "callnc", "callno", "callnz", "callo", "callp", "callnx0",
+ "callnx1", "callnx2", "callnx3", "callx0", "callx1", "callx2", "callx3", "callz",
+ "cmp", "cmpn", "dec", "div", "ext", "halt", "inc", "int",
+ "jc", "jdbnz", "jg", "jge", "jint", "jl", "jle", "jmp",
+ "jn", "jnx0", "jnx1", "jnx2", "jnx3", "jnc", "jno", "jnz",
+ "jo", "jp", "jx0", "jx1", "jx2", "jx3", "jz", "mov",
+ "mul", "neg", "nop", "not", "or", "pop", "popa", "popax",
+ "popx", "push", "pusha", "pushax", "pushx", "ret", "reti", "retskip",
+ "rol", "rolc", "ror", "rorc", "sal", "sar", "shl", "shr", "sub",
+ "subc", "test", "xchg", "xor", "db"
+};
+
+#define _OVER DASMFLAG_STEP_OVER
+#define _OUT DASMFLAG_STEP_OUT
+
+static const UINT32 s_flags[] = {
+ 0, 0, 0, 0, 0, 0, _OVER, _OVER, _OVER, _OVER, _OVER,
+ _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, _OVER,
+ _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, _OVER,
+ 0, 0, 0, 0, 0, _OVER, 0, _OVER,
+ 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, _OUT, _OUT, _OUT,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+};
+
+typedef struct {
+ UINT8 mnemonic;
+ UINT8 argument1;
+ UINT8 argument2;
+} minxdasm;
+
+static const minxdasm mnemonic[256] = {
+ /* 00 - 0F */
+ {zADD,R_A,R_A}, {zADD,R_A,R_B}, {zADD,R_A,I_8}, {zADD,R_A,M_IHL},
+ {zADD,R_A,M_N8}, {zADD,R_A,M_I16}, {zADD,R_A,M_X}, {zADD,R_A,M_Y},
+ {zADDC,R_A,R_A}, {zADDC,R_A,R_B}, {zADDC,R_A,I_8}, {zADDC,R_A,M_IHL},
+ {zADDC,R_A,M_N8}, {zADDC,R_A,M_I16}, {zADDC,R_A,M_X}, {zADDC,R_A,M_Y},
+ /* 10 - 1F */
+ {zSUB,R_A,R_A}, {zSUB,R_A,R_B}, {zSUB,R_A,I_8}, {zSUB,R_A,M_IHL},
+ {zSUB,R_A,M_N8}, {zSUB,R_A,M_I16}, {zSUB,R_A,M_X}, {zSUB,R_A,M_Y},
+ {zSUBC,R_A,R_A}, {zSUBC,R_A,R_B}, {zSUBC,R_A,I_8}, {zSUBC,R_A,M_IHL},
+ {zSUBC,R_A,M_N8}, {zSUBC,R_A,M_I16}, {zSUBC,R_A,M_X}, {zSUBC,R_A,M_Y},
+ /* 20 - 2F */
+ {zAND,R_A,R_A}, {zAND,R_A,R_B}, {zAND,R_A,I_8}, {zAND,R_A,M_IHL},
+ {zAND,R_A,M_N8}, {zAND,R_A,M_I16}, {zAND,R_A,M_X}, {zAND,R_A,M_Y},
+ {zOR,R_A,R_A}, {zOR,R_A,R_B}, {zOR,R_A,I_8}, {zOR,R_A,M_IHL},
+ {zOR,R_A,M_N8}, {zOR,R_A,M_I16}, {zOR,R_A,M_X}, {zOR,R_A,M_Y},
+ /* 30 - 3F */
+ {zCMP,R_A,R_A}, {zCMP,R_A,R_B}, {zCMP,R_A,I_8}, {zCMP,R_A,M_IHL},
+ {zCMP,R_A,M_N8}, {zCMP,R_A,M_I16}, {zCMP,R_A,M_X}, {zCMP,R_A,M_Y},
+ {zXOR,R_A,R_A}, {zXOR,R_A,R_B}, {zXOR,R_A,I_8}, {zXOR,R_A,M_IHL},
+ {zXOR,R_A,M_N8}, {zXOR,R_A,M_I16}, {zXOR,R_A,M_X}, {zXOR,R_A,M_Y},
+ /* 40 - 4F */
+ {zMOV,R_A,R_A}, {zMOV,R_A,R_B}, {zMOV,R_A,R_L}, {zMOV,R_A,R_H},
+ {zMOV,R_A,M_N8}, {zMOV,R_A,M_IHL}, {zMOV,R_A,M_X}, {zMOV,R_A,M_Y},
+ {zMOV,R_B,R_A}, {zMOV,R_B,R_B}, {zMOV,R_B,R_L}, {zMOV,R_B,R_H},
+ {zMOV,R_B,M_N8}, {zMOV,R_B,M_IHL}, {zMOV,R_B,M_X}, {zMOV,R_B,M_Y},
+ /* 50 - 5F */
+ {zMOV,R_L,R_A}, {zMOV,R_L,R_B}, {zMOV,R_L,R_L}, {zMOV,R_L,R_H},
+ {zMOV,R_L,M_N8}, {zMOV,R_L,M_IHL}, {zMOV,R_L,M_X}, {zMOV,R_L,M_Y},
+ {zMOV,R_H,R_A}, {zMOV,R_H,R_B}, {zMOV,R_H,R_L}, {zMOV,R_H,R_H},
+ {zMOV,R_H,M_N8}, {zMOV,R_H,M_IHL}, {zMOV,R_H,M_X}, {zMOV,R_H,M_Y},
+ /* 60 - 6F */
+ {zMOV,M_X,R_A}, {zMOV,M_X,R_B}, {zMOV,M_X,R_L}, {zMOV,M_X,R_H},
+ {zMOV,M_X,M_N8}, {zMOV,M_X,M_IHL}, {zMOV,M_X,M_X}, {zMOV,M_X,M_Y},
+ {zMOV,M_IHL,R_A}, {zMOV,M_IHL,R_B}, {zMOV,M_IHL,R_L}, {zMOV,M_IHL,R_H},
+ {zMOV,M_IHL,M_N8}, {zMOV,M_IHL,M_IHL}, {zMOV,M_IHL,M_X}, {zMOV,M_IHL,M_Y},
+ /* 70 - 7F */
+ {zMOV,M_Y,R_A}, {zMOV,M_Y,R_B}, {zMOV,M_Y,R_L}, {zMOV,M_Y,R_H},
+ {zMOV,M_Y,M_N8}, {zMOV,M_Y,M_IHL}, {zMOV,M_Y,M_X}, {zMOV,M_Y,M_Y},
+ {zMOV,M_N8,R_A}, {zMOV,M_N8,R_B}, {zMOV,M_N8,R_L}, {zMOV,M_N8,R_H},
+ {zDB,OP,0}, {zMOV,M_N8,M_IHL}, {zMOV,M_N8,M_X}, {zMOV,M_N8,M_Y},
+ /* 80 - 8F */
+ {zINC,R_A,0}, {zINC,R_B,0}, {zINC,R_L,0}, {zINC,R_H,0},
+ {zINC,R_N,0}, {zINC,M_N8,0}, {zINC,M_IHL,0}, {zINC,R_SP,0},
+ {zDEC,R_A,0}, {zDEC,R_B,0}, {zDEC,R_L,0}, {zDEC,R_H,0},
+ {zDEC,R_N,0}, {zDEC,M_N8,0}, {zDEC,M_IHL,0}, {zDEC,R_SP,0},
+ /* 90 - 9F */
+ {zINC,R_BA,0}, {zINC,R_HL,0}, {zINC,R_X,0}, {zINC,R_Y,0},
+ {zTEST,R_A,R_B}, {zTEST,M_IHL,I_8}, {zTEST,R_A,I_8}, {zTEST,R_B,I_8},
+ {zDEC,R_BA,0}, {zDEC,R_HL,0}, {zDEC,R_X,0}, {zDEC,R_Y,0},
+ {zAND,R_F,I_8}, {zOR,R_F,I_8}, {zXOR,R_F,I_8}, {zMOV,R_F,I_8},
+ /* A0 - AF */
+ {zPUSH,R_BA,0}, {zPUSH,R_HL,0}, {zPUSH,R_X,0}, {zPUSH,R_Y,0},
+ {zPUSH,R_N,0}, {zPUSH,R_I,0}, {zPUSHX,0,0}, {zPUSH,R_F,0},
+ {zPOP,R_BA,0}, {zPOP,R_HL,0}, {zPOP,R_X,0}, {zPOP,R_Y,0},
+ {zPOP,R_N,0}, {zPOP,R_I,0}, {zPOP,0,0}, {zPOP,R_F,0},
+ /* B0 - BF */
+ {zMOV,R_A,I_8}, {zMOV,R_B,I_8}, {zMOV,R_L,I_8}, {zMOV,R_H,I_8},
+ {zMOV,R_N,I_8}, {zMOV,M_IHL,I_8}, {zMOV,M_X,I_8}, {zMOV,M_Y,I_8},
+ {zMOV,R_BA,M_I16}, {zMOV,R_HL,M_I16}, {zMOV,R_X,M_I16}, {zMOV,R_Y,M_I16},
+ {zMOV,M_I16,R_BA}, {zMOV,M_I16,R_HL}, {zMOV,M_I16,R_X}, {zMOV,M_I16,R_Y},
+ /* C0 - CF */
+ {zADD,R_BA,I_16}, {zADD,R_HL,I_16}, {zADD,R_X,I_16}, {zADD,R_Y,I_16},
+ {zMOV,R_BA,I_16}, {zMOV,R_HL,I_16}, {zMOV,R_X,I_16}, {zMOV,R_Y,I_16},
+ {zXCHG,R_BA,R_HL}, {zXCHG,R_BA,R_X}, {zXCHG,R_BA,R_Y}, {zXCHG,R_BA,R_SP},
+ {zXCHG,R_A,R_B}, {zXCHG,R_A,M_IHL}, {zDB,0,0}, {zDB,0,0},
+ /* D0 - DF */
+ {zSUB,R_BA,I_16}, {zSUB,R_HL,I_16}, {zSUB,R_X,I_16}, {zSUB,R_Y,I_16},
+ {zCMP,R_BA,I_16}, {zCMP,R_HL,I_16}, {zCMP,R_X,I_16}, {zCMP,R_Y,I_16},
+ {zAND,M_N8,I_8}, {zOR,M_N8,I_8}, {zXOR,M_N8,I_8}, {zCMP,M_N8,I_8},
+ {zTEST,M_N8,I_8}, {zMOV,M_N8,I_8}, {zBCDE,0,0}, {zBCDD,0,0},
+ /* E0 - EF */
+ {zCALLC,D_8,0}, {zCALLNC,D_8,0}, {zCALLZ,D_8,0}, {zCALLNZ,D_8,0},
+ {zJC,D_8,0}, {zJNC,D_8,0}, {zJZ,D_8,0}, {zJNZ,D_8,0},
+ {zCALLC,D_16,0}, {zCALLNC,D_16,0}, {zCALLZ,D_16,0}, {zCALLNZ,D_16,0},
+ {zJC,D_16,0}, {zJNC,D_16,0}, {zJZ,D_16,0}, {zJNZ,D_16,0},
+ /* F0 - FF */
+ {zCALL,D_8,0}, {zJMP,D_8,0}, {zCALL,D_16}, {zJMP,D_16},
+ {zJMP,R_HL,0}, {zJDBNZ,D_8,0}, {zBCDX,R_A,0}, {zBCDX,M_IHL,0},
+ {zRET,0,0}, {zRETI,0,0}, {zRETSKIP,0,0}, {zCALL,M_I16},
+ {zINT,I_8,0}, {zJINT,I_8,0}, {zDB,OP,0}, {zNOP,0,0}
+};
+
+static const minxdasm mnemonic_ce[256] = {
+ /* 00 - 0F */
+ {zADD,R_A,M_X8}, {zADD,R_A,M_Y8}, {zADD,R_A,M_XL}, {zADD,R_A,M_YL},
+ {zADD,M_IHL,R_A}, {zADD,M_IHL,I_8}, {zADD,M_IHL,M_X}, {zADD,M_IHL,M_Y},
+ {zADDC,R_A,M_X8}, {zADDC,R_A,M_Y8}, {zADDC,R_A,M_XL}, {zADDC,R_A,M_YL},
+ {zADDC,M_IHL,R_A}, {zADDC,M_IHL,I_8}, {zADDC,M_IHL,M_X}, {zADDC,M_IHL,M_Y},
+ /* 10 - 1F */
+ {zSUB,R_A,M_X8}, {zSUB,R_A,M_Y8}, {zSUB,R_A,M_XL}, {zSUB,R_A,M_YL},
+ {zSUB,M_IHL,R_A}, {zSUB,M_IHL,I_8}, {zSUB,M_IHL,M_X}, {zSUB,M_IHL,M_Y},
+ {zSUBC,R_A,M_X8}, {zSUBC,R_A,M_Y8}, {zSUBC,R_A,M_XL}, {zSUBC,R_A,M_YL},
+ {zSUBC,M_IHL,R_A}, {zSUBC,M_IHL,I_8}, {zSUBC,M_IHL,M_X}, {zSUBC,M_IHL,M_Y},
+ /* 20 - 2F */
+ {zAND,R_A,M_X8}, {zAND,R_A,M_Y8}, {zAND,R_A,M_XL}, {zAND,R_A,M_YL},
+ {zAND,M_IHL,R_A}, {zAND,M_IHL,I_8}, {zAND,M_IHL,M_X}, {zAND,M_IHL,M_Y},
+ {zOR,R_A,M_X8}, {zOR,R_A,M_Y8}, {zOR,R_A,M_XL}, {zOR,R_A,M_YL},
+ {zOR,M_IHL,R_A}, {zOR,M_IHL,I_8}, {zOR,M_IHL,M_X}, {zOR,M_IHL,M_Y},
+ /* 30 - 3F */
+ {zCMP,R_A,M_X8}, {zCMP,R_A,M_Y8}, {zCMP,R_A,M_XL}, {zCMP,R_A,M_YL},
+ {zCMP,M_IHL,R_A}, {zCMP,M_IHL,I_8}, {zCMP,M_IHL,M_X}, {zCMP,M_IHL,M_Y},
+ {zXOR,R_A,M_X8}, {zXOR,R_A,M_Y8}, {zXOR,R_A,M_XL}, {zXOR,R_A,M_YL},
+ {zXOR,M_IHL,R_A}, {zXOR,M_IHL,I_8}, {zXOR,M_IHL,M_X}, {zXOR,M_IHL,M_Y},
+ /* 40 - 4F */
+ {zMOV,R_A,M_X8}, {zMOV,R_A,M_Y8}, {zMOV,R_A,M_XL}, {zMOV,R_A,M_YL},
+ {zMOV,M_X8,R_A}, {zMOV,M_Y8,R_A}, {zMOV,M_X,R_A}, {zMOV,M_Y,R_A},
+ {zMOV,R_B,M_X8}, {zMOV,R_B,M_Y8}, {zMOV,R_B,M_XL}, {zMOV,R_B,M_YL},
+ {zMOV,M_X8,R_B}, {zMOV,M_Y8,R_B}, {zMOV,M_X,R_B}, {zMOV,M_Y,R_B},
+ /* 50 - 5F */
+ {zMOV,R_L,M_X8}, {zMOV,R_L,M_Y8}, {zMOV,R_L,M_XL}, {zMOV,R_L,M_YL},
+ {zMOV,M_X8,R_L}, {zMOV,M_Y8,R_L}, {zMOV,M_X,R_L}, {zMOV,M_Y,R_L},
+ {zMOV,R_H,M_X8}, {zMOV,R_H,M_Y8}, {zMOV,R_H,M_XL}, {zMOV,R_H,M_YL},
+ {zMOV,M_X8,R_H}, {zMOV,M_Y8,R_H}, {zMOV,M_X,R_H}, {zMOV,M_Y,R_H},
+ /* 60 - 6F */
+ {zMOV,M_IHL,M_X8}, {zMOV,M_IHL,M_Y8}, {zMOV,M_IHL,M_XL}, {zMOV,M_IHL,M_YL},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zMOV,M_X,M_X8}, {zMOV,M_X,M_Y8}, {zMOV,M_X,M_XL}, {zMOV,M_X,M_YL},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* 70 - 7F */
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zMOV,M_Y,M_X8}, {zMOV,M_Y,M_Y8}, {zMOV,M_Y,M_XL}, {zMOV,M_Y,M_YL},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* 80 - 8F */
+ {zSAL,R_A,0}, {zSAL,R_B,0}, {zSAL,M_N8,0}, {zSAL,M_IHL,0},
+ {zSHL,R_A,0}, {zSHL,R_B,0}, {zSHL,M_N8,0}, {zSHL,M_IHL,0},
+ {zSAR,R_A,0}, {zSAR,R_B,0}, {zSAR,M_N8,0}, {zSAR,M_IHL,0},
+ {zSHR,R_A,0}, {zSHR,R_B,0}, {zSHR,M_N8,0}, {zSHR,M_IHL,0},
+ /* 90 - 9F */
+ {zROLC,R_A,0}, {zROLC,R_B,0}, {zROLC,M_N8,0}, {zROLC,M_IHL,0},
+ {zROL,R_A,0}, {zROL,R_B,0}, {zROL,M_N8,0}, {zROL,M_IHL,0},
+ {zRORC,R_A,0}, {zRORC,R_B,0}, {zRORC,M_N8,0}, {zRORC,M_IHL,0},
+ {zROR,R_A,0}, {zROR,R_B,0}, {zROR,M_N8,0}, {zROR,M_IHL,0},
+ /* A0 - AF */
+ {zNOT,R_A,0}, {zNOT,R_B,0}, {zNOT,M_N8,0}, {zNOT,M_IHL,0},
+ {zNEG,R_A,0}, {zNEG,R_B,0}, {zNEG,M_N8,0}, {zNEG,M_IHL,0},
+ {zEXT,R_BA,R_A}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zHALT,0,0}, {zNOP,0,0},
+ /* B0 - BF */
+ {zAND,R_B,I_8}, {zAND,R_L,I_8}, {zAND,R_H,I_8}, {zDB,OP1,OP},
+ {zOR,R_B,I_8}, {zOR,R_L,I_8}, {zOR,R_H,I_8}, {zDB,OP1,OP},
+ {zXOR,R_B,I_8}, {zXOR,R_L,I_8}, {zXOR,R_H,I_8}, {zDB,OP1,OP},
+ {zCMP,R_B,I_8}, {zCMP,R_L,I_8}, {zCMP,R_H,I_8}, {zCMP,R_N,I_8},
+ /* C0 - CF */
+ {zMOV,R_A,R_N}, {zMOV,R_A,R_F}, {zMOV,R_N,R_A}, {zMOV,R_F,R_A},
+ {zMOV,R_U,I_8}, {zMOV,R_I,I_8}, {zMOV,R_XI,I_8}, {zMOV,R_YI,I_8},
+ {zMOV,R_A,R_V}, {zMOV,R_A,R_I}, {zMOV,R_A,R_XI}, {zMOV,R_A,R_YI},
+ {zMOV,R_U,R_A}, {zMOV,R_I,R_A}, {zMOV,R_XI,R_A}, {zMOV,R_YI,R_A},
+ /* D0 - DF */
+ {zMOV,R_A,M_16}, {zMOV,R_B,M_16}, {zMOV,R_H,M_16}, {zMOV,R_L,M_16},
+ {zMOV,M_16,R_A}, {zMOV,M_16,R_B}, {zMOV,M_16,R_H}, {zMOV,M_16,R_L},
+ {zMUL,R_HL,R_A}, {zDIV,R_HL,R_A}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* E0 - EF */
+ {zJL,D_8,0}, {zJLE,D_8,0}, {zJG,D_8,0}, {zJGE,D_8,0},
+ {zJO,D_8,0}, {zJNO,D_8,0}, {zJP,D_8,0}, {zJN,D_8,0},
+ {zJNX0,D_8,0}, {zJNX1,D_8,0}, {zJNX2,D_8,0}, {zJNX3,D_8,0},
+ {zJX0,D_8,0}, {zJX1,D_8,0}, {zJX2,D_8,0}, {zJX3,D_8,0},
+ /* F0 - FF */
+ {zCALLL,D_8,0}, {zCALLLE,D_8,0}, {zCALLG,D_8,0}, {zCALLGE,D_8,0},
+ {zCALLO,D_8,0}, {zCALLNO,D_8,0}, {zCALLP,D_8,0}, {zCALLN,D_8,0},
+ {zCALLNX0,D_8,0}, {zCALLNX1,D_8,0}, {zCALLNX2,D_8,0}, {zCALLNX3,D_8,0},
+ {zCALLX0,D_8,0}, {zCALLX1,D_8,0}, {zCALLX2,D_8,0}, {zCALLX3,D_8,0}
+};
+
+static const minxdasm mnemonic_cf[256] = {
+ /* 00 - 0F */
+ {zADD,R_BA,R_BA}, {zADD,R_BA,R_HL}, {zADD,R_BA,R_X}, {zADD,R_BA,R_Y},
+ {zADDC,R_BA,R_BA}, {zADDC,R_BA,R_HL}, {zADDC,R_BA,R_X}, {zADDC,R_BA,R_Y},
+ {zSUB,R_BA,R_BA}, {zSUB,R_BA,R_HL}, {zSUB,R_BA,R_X}, {zSUB,R_BA,R_Y},
+ {zSUBC,R_BA,R_BA}, {zSUBC,R_BA,R_HL}, {zSUBC,R_BA,R_X}, {zSUBC,R_BA,R_Y},
+ /* 10 - 1F */
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zCMP,R_BA,R_BA}, {zCMP,R_BA,R_HL}, {zCMP,R_BA,R_X}, {zCMP,R_BA,R_Y},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* 20 - 2F */
+ {zADD,R_HL,R_BA}, {zADD,R_HL,R_HL}, {zADD,R_HL,R_X}, {zADD,R_HL,R_Y},
+ {zADDC,R_HL,R_BA}, {zADDC,R_HL,R_HL}, {zADDC,R_HL,R_X}, {zADDC,R_HL,R_Y},
+ {zSUB,R_HL,R_BA}, {zSUB,R_HL,R_HL}, {zSUB,R_HL,R_X}, {zSUB,R_HL,R_Y},
+ {zSUBC,R_HL,R_BA}, {zSUBC,R_HL,R_HL}, {zSUBC,R_HL,R_X}, {zSUBC,R_HL,R_Y},
+ /* 30 - 3F */
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zCMP,R_HL,R_BA}, {zCMP,R_HL,R_HL}, {zCMP,R_HL,R_X}, {zCMP,R_HL,R_Y},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* 40 - 4F */
+ {zADD,R_X,R_BA}, {zADD,R_X,R_HL}, {zADD,R_Y,R_BA}, {zADD,R_Y,R_HL},
+ {zADD,R_SP,R_BA}, {zADD,R_SP,R_HL}, {zDB,OP1,}, {zDB,OP1,OP},
+ {zSUB,R_X,R_BA}, {zSUB,R_X,R_HL}, {zSUB,R_Y,R_BA}, {zSUB,R_Y,R_HL},
+ {zSUB,R_SP,R_BA}, {zSUB,R_SP,R_HL}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* 50 - 5F */
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zCMP,R_SP,R_BA}, {zCMP,R_SP,R_HL}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* 60 - 6F */
+ {zCMPN,R_BA,I_16}, {zCMPN,R_HL,I_16}, {zCMPN,R_X,I_16}, {zCMPN,R_Y,I_16},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zADD,R_SP,I_16}, {zDB,OP1,OP}, {zSUB,R_SP,I_16}, {zDB,OP1,OP},
+ {zCMP,R_SP,I_16}, {zDB,OP1,OP}, {zMOV,R_SP,I_16}, {zDB,OP1,OP},
+ /* 70 - 7F */
+ {zMOV,R_BA,S_8}, {zMOV,R_HL,S_8}, {zMOV,R_X,S_8}, {zMOV,R_Y,S_8},
+ {zMOV,S_8,R_BA}, {zMOV,S_8,R_HL}, {zMOV,S_8,R_X}, {zMOV,S_8,R_Y},
+ {zMOV,R_SP,M_I16}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zMOV,M_I16,R_SP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* 80 - 8F */
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* 90 - 9F */
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* A0 - AF */
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* B0 - BF */
+ {zPUSH,R_A,0}, {zPUSH,R_B,0}, {zPUSH,R_L,0}, {zPUSH,R_H,0},
+ {zPOP,R_A,0}, {zPOP,R_B,0}, {zPOP,R_L,0}, {zPOP,R_H,0},
+ {zPUSHA,0,0}, {zPUSHAX,0,0}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zPOPA,0,0}, {zPOPAX,0,0}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* C0 - CF */
+ {zMOV,R_BA,M_HL}, {zMOV,R_HL,M_HL}, {zMOV,R_X,M_HL}, {zMOV,R_Y,M_HL},
+ {zMOV,M_HL,R_BA}, {zMOV,M_HL,R_HL}, {zMOV,M_HL,R_X}, {zMOV,M_HL,R_Y},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ /* D0 - DF */
+ {zMOV,R_BA,M_X}, {zMOV,R_HL,M_X}, {zMOV,R_X,M_X}, {zMOV,R_Y,M_X},
+ {zMOV,M_X,R_BA}, {zMOV,M_X,R_HL}, {zMOV,M_X,R_X}, {zMOV,M_X,R_Y},
+ {zMOV,R_BA,M_Y}, {zMOV,R_HL,M_Y}, {zMOV,R_X,M_Y}, {zMOV,R_Y,M_Y},
+ {zMOV,M_Y,R_BA}, {zMOV,M_Y,R_HL}, {zMOV,M_Y,R_X}, {zMOV,M_Y,R_Y},
+ /* E0 - EF */
+ {zMOV,R_BA,R_BA}, {zMOV,R_BA,R_HL}, {zMOV,R_BA,R_X}, {zMOV,R_BA,R_Y},
+ {zMOV,R_HL,R_BA}, {zMOV,R_HL,R_HL}, {zMOV,R_HL,R_X}, {zMOV,R_HL,R_Y},
+ {zMOV,R_X,R_BA}, {zMOV,R_X,R_HL}, {zMOV,R_X,R_X}, {zMOV,R_X,R_Y},
+ {zMOV,R_Y,R_BA}, {zMOV,R_Y,R_HL}, {zMOV,R_Y,R_X}, {zMOV,R_Y,R_Y},
+ /* F0 - FF */
+ {zMOV,R_SP,R_BA}, {zMOV,R_SP,R_HL}, {zMOV,R_SP,R_X}, {zMOV,R_SP,R_Y},
+ {zMOV,R_HL,R_SP}, {zMOV,R_HL,R_PC}, {zDB,OP1,OP}, {zDB,OP1,OP},
+ {zMOV,R_BA,R_SP}, {zMOV,R_BA,R_PC}, {zMOV,R_X,R_SP}, {zDB,OP1,OP},
+ {zDB,OP1,OP}, {zDB,OP1,OP}, {zMOV,R_Y,R_SP}, {zDB,OP1,OP}
+};
+
+#define HANDLE_ARGUMENT \
+case R_A: dst += sprintf( dst, "%cA", fill ); break; \
+case R_B: dst += sprintf( dst, "%cB", fill ); break; \
+case R_L: dst += sprintf( dst, "%cL", fill ); break; \
+case R_H: dst += sprintf( dst, "%cH", fill ); break; \
+case R_N: dst += sprintf( dst, "%cN", fill ); break; \
+case R_F: dst += sprintf( dst, "%cF", fill ); break; \
+case R_SP: dst += sprintf( dst, "%cSP", fill ); break; \
+case R_BA: dst += sprintf( dst, "%cBA", fill ); break; \
+case R_HL: dst += sprintf( dst, "%cHL", fill ); break; \
+case R_X: dst += sprintf( dst, "%cX", fill ); break; \
+case R_Y: dst += sprintf( dst, "%cY", fill ); break; \
+case R_U: dst += sprintf( dst, "%cU", fill ); break; \
+case R_V: dst += sprintf( dst, "%cV", fill ); break; \
+case R_I: dst += sprintf( dst, "%cI", fill ); break; \
+case R_XI: dst += sprintf( dst, "%cXI", fill ); break; \
+case R_YI: dst += sprintf( dst, "%cYI", fill ); break; \
+case R_PC: dst += sprintf( dst, "%cPC", fill ); break; \
+case I_8: /* 8 bit immediate */ \
+ ea = oprom[pos++]; \
+ dst += sprintf( dst, "%c$%02X", fill, ea ); \
+ break; \
+case I_16: /* 16 bit immediate */ \
+ ea = oprom[pos++]; \
+ ea += oprom[pos++] << 8; \
+ dst += sprintf( dst, "%c$%04X", fill, ea ); \
+ break; \
+case D_8: /* PC + 8 bit displacement (signed) */ \
+ ofs8 = oprom[pos++]; \
+ dst += sprintf( dst, "%c$%04X", fill, pc + pos - 1 + ofs8 ); \
+ break; \
+case D_16: /* PC + 16 bit displacement */ \
+ ea = oprom[pos++]; \
+ ea += oprom[pos++] << 8; \
+ ea = ea - 1; \
+ dst += sprintf( dst, "%c$%04X", fill, pc + pos + ea ); \
+ break; \
+case S_8: /* SP + 8 bit displacement (signed) */ \
+ ea = oprom[pos++]; \
+ dst += sprintf( dst, "%cSP+$%02X", fill, ea ); \
+ break; \
+case M_IHL: dst += sprintf( dst, "%c[I+HL]", fill ); break; \
+case M_N8: /* [I+N+ofs8] */ \
+ ea = oprom[pos++]; \
+ dst += sprintf( dst, "%c[I+N+$%02X]", fill, ea ); \
+ break; \
+case M_I16: /* [I+ofs16] */ \
+ ea = oprom[pos++]; \
+ ea += oprom[pos++] << 8; \
+ dst += sprintf( dst, "%c[I+$%04X]", fill, ea ); \
+ break; \
+case M_X: dst += sprintf( dst, "%c[X]", fill ); break; \
+case M_Y: dst += sprintf( dst, "%c[Y]", fill ); break; \
+case M_X8: /* [X + 8 bit displacement (signed)] */ \
+ ea = oprom[pos++]; \
+ dst += sprintf( dst, "%c[X+$%02X]", fill, ea ); \
+ break; \
+case M_Y8: /* [Y + 8 bit displacement (signed)] */ \
+ ea = oprom[pos++]; \
+ dst += sprintf( dst, "%c[Y+$%02X]", fill, ea ); \
+ break; \
+case M_XL: dst += sprintf( dst, "%c[X+L]", fill ); break; \
+case M_YL: dst += sprintf( dst, "%c[Y+L]", fill ); break; \
+case M_16: /* [16bit] */ \
+ ea = oprom[pos++]; \
+ ea += oprom[pos++] << 8; \
+ dst += sprintf( dst, "%c[$%04X]", fill, ea ); \
+ break; \
+case M_HL: dst += sprintf( dst, "%c[HL]", fill ); break; \
+case OP: dst += sprintf( dst, "%c$%02X", fill, op ); break; \
+case OP1: dst += sprintf( dst, "%c$%02X", fill, op1 ); break;
+
+unsigned minx_dasm( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram ) {
+ const minxdasm *instr;
+ UINT8 op, op1;
+ INT8 ofs8 = 0;
+ UINT16 ea = 0;
+ int pos = 0;
+ char *dst = buffer;
+
+ op1 = op = oprom[pos++];
+
+ switch (op) {
+ case 0xCE:
+ op = oprom[pos++];
+ instr = &mnemonic_ce[op];
+ break;
+ case 0xCF:
+ op = oprom[pos++];
+ instr = &mnemonic_cf[op];
+ break;
+ default:
+ instr = &mnemonic[op];
+ break;
+ }
+
+ dst += sprintf( dst, "%-6s", s_mnemonic[ instr->mnemonic ] );
+
+ if ( instr->argument1 ) {
+ char fill = ' ';
+ //int arg = 0;
+ switch( instr->argument1 ) {
+ HANDLE_ARGUMENT;
+ }
+ }
+ if ( instr->argument2 ) {
+ char fill = ',';
+ //int arg = 1;
+ switch( instr->argument2 ) {
+ HANDLE_ARGUMENT;
+ }
+ }
+ return pos | s_flags[instr->mnemonic] | DASMFLAG_SUPPORTED;
+}
+
+
+
+
diff --git a/src/emu/cpu/minx/minxfunc.h b/src/emu/cpu/minx/minxfunc.h
new file mode 100644
index 00000000000..1a59dd1f2c9
--- /dev/null
+++ b/src/emu/cpu/minx/minxfunc.h
@@ -0,0 +1,272 @@
+
+INLINE UINT8 ADD8( UINT8 arg1, UINT8 arg2 ) {
+ UINT32 res = arg1 + arg2;
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( ( arg2 ^ arg1 ^ 0x80 ) & ( arg2 ^ res ) & 0x80 ) ? FLAG_O : 0 )
+ | ( ( res & 0xFF00 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE UINT16 ADD16( UINT16 arg1, UINT16 arg2 ) {
+ UINT32 res = arg1 + arg2;
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x8000 ) ? FLAG_S : 0 )
+ | ( ( ( arg2 ^ arg1 ^ 0x8000 ) & ( arg2 ^ res ) & 0x8000 ) ? FLAG_O : 0 )
+ | ( ( res & 0xFF0000 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFFFF;
+}
+
+INLINE UINT8 ADDC8( UINT8 arg1, UINT8 arg2 ) {
+ UINT32 res = arg1 + arg2 + ( ( regs.F & FLAG_C ) ? 1 : 0 );
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( ( arg2 ^ arg1 ^ 0x80 ) & ( arg2 ^ res ) & 0x80 ) ? FLAG_O : 0 )
+ | ( ( res & 0xFF00 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE UINT16 ADDC16( UINT16 arg1, UINT16 arg2 ) {
+ UINT32 res = arg1 + arg2 + ( ( regs.F & FLAG_C ) ? 1 : 0 );
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x8000 ) ? FLAG_S : 0 )
+ | ( ( ( arg2 ^ arg1 ^ 0x8000 ) & ( arg2 ^ res ) & 0x8000 ) ? FLAG_O : 0 )
+ | ( ( res & 0xFF0000 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFFFF;
+}
+
+INLINE UINT8 INC8( UINT8 arg ) {
+ return ADD8( arg, 1 );
+}
+
+INLINE UINT16 INC16( UINT16 arg ) {
+ return ADD16( arg, 1 );
+}
+
+INLINE UINT8 SUB8( UINT8 arg1, UINT8 arg2 ) {
+ UINT32 res = arg1 - arg2;
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( ( arg2 ^ arg1 ) & ( arg1 ^ res ) & 0x80 ) ? FLAG_O : 0 )
+ | ( ( res & 0xFF00 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE UINT16 SUB16( UINT16 arg1, UINT16 arg2 ) {
+ UINT32 res = arg1 - arg2;
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x8000 ) ? FLAG_S : 0 )
+ | ( ( ( arg2 ^ arg1 ) & ( arg1 ^ res ) & 0x8000 ) ? FLAG_O : 0 )
+ | ( ( res & 0xFF0000 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFFFF;
+}
+
+INLINE UINT8 SUBC8( UINT8 arg1, UINT8 arg2 ) {
+ UINT32 res = arg1 - arg2 - ( ( regs.F & FLAG_C ) ? 1 : 0 );
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( ( arg2 ^ arg1 ) & ( arg1 ^ res ) & 0x80 ) ? FLAG_O : 0 )
+ | ( ( res & 0xFF00 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE UINT16 SUBC16( UINT16 arg1, UINT16 arg2 ) {
+ UINT32 res = arg1 - arg2 - ( ( regs.F & FLAG_C ) ? 1 : 0 );
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x8000 ) ? FLAG_S : 0 )
+ | ( ( ( arg2 ^ arg1 ) & ( arg1 ^ res ) & 0x8000 ) ? FLAG_O : 0 )
+ | ( ( res & 0xFF0000 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFFFF;
+}
+
+INLINE UINT8 DEC8( UINT8 arg ) {
+ return SUB8( arg, 1 );
+}
+
+INLINE UINT16 DEC16( UINT16 arg ) {
+ return SUB16( arg, 1 );
+}
+
+INLINE UINT8 AND8( UINT8 arg1, UINT8 arg2 ) {
+ UINT8 res = arg1 & arg2;
+ return res;
+}
+
+INLINE UINT8 OR8( UINT8 arg1, UINT8 arg2 ) {
+ UINT8 res = arg1 | arg2;
+ return res;
+}
+
+INLINE UINT8 XOR8( UINT8 arg1, UINT8 arg2 ) {
+ UINT8 res = arg1 ^ arg2;
+ return res;
+}
+
+INLINE UINT8 NOT8( UINT8 arg ) {
+ UINT8 res = ~arg;
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res;
+}
+
+INLINE UINT8 NEG8( UINT8 arg ) {
+ UINT8 res = -arg;
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res;
+}
+
+INLINE UINT8 SAL8( UINT8 arg ) {
+ UINT16 res = arg << 1;
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( arg != 0 && res == 0 ) ? FLAG_O : 0 )
+ | ( ( arg & 0x80 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res;
+}
+
+INLINE UINT8 SAR8( UINT8 arg ) {
+ UINT16 res = ( arg >> 1 ) | ( arg & 0x80 );
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( arg != 0x80 && res == 0x80 ) ? FLAG_O : 0 )
+ | ( ( arg & 0x01 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE UINT8 SHL8( UINT8 arg ) {
+ UINT16 res = arg << 1;
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( arg & 0x80 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res;
+}
+
+INLINE UINT8 SHR8( UINT8 arg ) {
+ UINT16 res = arg >> 1;
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( arg & 0x01 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE UINT8 ROLC8( UINT8 arg ) {
+ UINT16 res = ( arg << 1 ) | ( ( regs.F & FLAG_C ) ? 1 : 0 );
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( arg & 0x80 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE UINT8 RORC8( UINT8 arg ) {
+ UINT16 res = ( arg >> 1 ) | ( ( regs.F & FLAG_C ) ? 0x80 : 0 );
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( arg & 0x01 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE UINT8 ROL8( UINT8 arg ) {
+ UINT16 res = ( arg << 1 ) | ( ( arg & 0x80 ) ? 1 : 0 );
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( arg & 0x80 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE UINT8 ROR8( UINT8 arg ) {
+ UINT16 res = ( arg >> 1 ) | ( ( arg & 0x01 ) ? 0x80 : 0 );
+ regs.F = ( regs.F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) )
+ | ( ( res & 0x80 ) ? FLAG_S : 0 )
+ | ( ( arg & 0x01 ) ? FLAG_C : 0 )
+ | ( ( res ) ? 0 : FLAG_Z )
+ ;
+ return res & 0xFF;
+}
+
+INLINE void PUSH8( UINT8 arg ) {
+ regs.SP = regs.SP - 1;
+ wr( regs.SP, arg );
+}
+
+INLINE void PUSH16( UINT16 arg ) {
+ PUSH8( arg >> 8 );
+ PUSH8( arg & 0x00FF );
+}
+
+INLINE UINT8 POP8( void ) {
+ UINT8 res = rd( regs.SP );
+ regs.SP = regs.SP + 1;
+ return res;
+}
+
+INLINE UINT16 POP16( void ) {
+ return POP8() | ( POP8() << 8 );
+}
+
+INLINE void JMP( UINT16 arg ) {
+ regs.V = regs.U;
+ regs.PC = arg;
+}
+
+INLINE void CALL( UINT16 arg ) {
+ PUSH8( regs.V );
+ PUSH16( regs.PC );
+ JMP( arg );
+}
+
+static UINT32 addr1, addr2;
+
+#define AD1_IHL addr1 = ( regs.I << 16 ) | regs.HL;
+#define AD1_IN8 addr1 = ( regs.I << 16 ) | ( regs.N << 8 ) | rdop();
+#define AD1_I16 addr1 = ( regs.I << 16 ) | rdop(); addr1 |= ( rdop() << 8 );
+#define AD1_XIX addr1 = ( regs.XI << 16 ) | regs.X;
+#define AD1_YIY addr1 = ( regs.YI << 16 ) | regs.Y;
+#define AD1_X8 addr1 = ( regs.XI << 16 ) | ( regs.X + rdop() );
+#define AD1_Y8 addr1 = ( regs.YI << 16 ) | ( regs.Y + rdop() );
+#define AD1_XL addr1 = ( regs.XI << 16 ) | ( regs.X + ( regs.HL & 0x00FF ) );
+#define AD1_YL addr1 = ( regs.YI << 16 ) | ( regs.Y + ( regs.HL & 0x00FF ) );
+#define AD2_IHL addr2 = ( regs.I << 16 ) | regs.HL;
+#define AD2_IN8 addr2 = ( regs.I << 16 ) | ( regs.N << 8 ) | rdop();
+#define AD2_I16 addr2 = ( regs.I << 16 ) | rdop(); addr2 |= ( rdop() << 8 );
+#define AD2_XIX addr2 = ( regs.XI << 16 ) | regs.X;
+#define AD2_YIY addr2 = ( regs.YI << 16 ) | regs.Y;
+#define AD2_X8 addr2 = ( regs.XI << 16 ) | ( regs.X + rdop() );
+#define AD2_Y8 addr2 = ( regs.YI << 16 ) | ( regs.Y + rdop() );
+#define AD2_XL addr2 = ( regs.XI << 16 ) | ( regs.X + ( regs.HL & 0x00FF ) );
+#define AD2_YL addr2 = ( regs.YI << 16 ) | ( regs.Y + ( regs.HL & 0x00FF ) );
+
diff --git a/src/emu/cpu/minx/minxopce.h b/src/emu/cpu/minx/minxopce.h
new file mode 100644
index 00000000000..5059582123c
--- /dev/null
+++ b/src/emu/cpu/minx/minxopce.h
@@ -0,0 +1,331 @@
+
+#undef OP
+#define OP(nn) INLINE void minx_CE_##nn(void)
+
+OP(00) { AD2_X8; regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(01) { AD2_Y8; regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(02) { AD2_XL; regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(03) { AD2_YL; regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(04) { AD1_IHL; wr( addr1, ADD8( rd( addr1 ), ( regs.BA & 0x00FF ) ) ); }
+OP(05) { AD1_IHL; wr( addr1, ADD8( rd( addr1 ), rdop() ) ); }
+OP(06) { AD1_IHL; AD2_XIX; wr( addr1, ADD8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(07) { AD1_IHL; AD2_YIY; wr( addr1, ADD8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(08) { AD2_X8; regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(09) { AD2_Y8; regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(0A) { AD2_XL; regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(0B) { AD2_YL; regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(0C) { AD1_IHL; wr( addr1, ADDC8( rd( addr1 ), ( regs.BA & 0x00FF ) ) ); }
+OP(0D) { AD1_IHL; wr( addr1, ADDC8( rd( addr1 ), rdop() ) ); }
+OP(0E) { AD1_IHL; AD2_XIX; wr( addr1, ADDC8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(0F) { AD1_IHL; AD2_YIY; wr( addr1, ADDC8( rd( addr1 ), rd( addr2 ) ) ); }
+
+OP(10) { AD2_X8; regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(11) { AD2_Y8; regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(12) { AD2_XL; regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(13) { AD2_YL; regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(14) { AD1_IHL; wr( addr1, SUB8( rd( addr1 ), ( regs.BA & 0x00FF ) ) ); }
+OP(15) { AD1_IHL; wr( addr1, SUB8( rd( addr1 ), rdop() ) ); }
+OP(16) { AD1_IHL; AD2_XIX; wr( addr1, SUB8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(17) { AD1_IHL; AD2_YIY; wr( addr1, SUB8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(18) { AD2_X8; regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(19) { AD2_Y8; regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(1A) { AD2_XL; regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(1B) { AD2_YL; regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(1C) { AD1_IHL; wr( addr1, SUBC8( rd( addr1 ), ( regs.BA & 0x00FF ) ) ); }
+OP(1D) { AD1_IHL; wr( addr1, SUBC8( rd( addr1 ), rdop() ) ); }
+OP(1E) { AD1_IHL; AD2_XIX; wr( addr1, SUBC8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(1F) { AD1_IHL; AD2_YIY; wr( addr1, SUBC8( rd( addr1 ), rd( addr2 ) ) ); }
+
+OP(20) { AD2_X8; regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(21) { AD2_Y8; regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(22) { AD2_XL; regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(23) { AD2_YL; regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(24) { AD1_IHL; wr( addr1, AND8( rd( addr1 ), ( regs.BA & 0x00FF ) ) ); }
+OP(25) { AD1_IHL; wr( addr1, AND8( rd( addr1 ), rdop() ) ); }
+OP(26) { AD1_IHL; AD2_XIX; wr( addr1, AND8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(27) { AD1_IHL; AD2_YIY; wr( addr1, AND8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(28) { AD2_X8; regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(29) { AD2_Y8; regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(2A) { AD2_XL; regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(2B) { AD2_YL; regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(2C) { AD1_IHL; wr( addr1, OR8( rd( addr1 ), ( regs.BA & 0x00FF ) ) ); }
+OP(2D) { AD1_IHL; wr( addr1, OR8( rd( addr1 ), rdop() ) ); }
+OP(2E) { AD1_IHL; AD2_XIX; wr( addr1, OR8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(2F) { AD1_IHL; AD2_YIY; wr( addr1, OR8( rd( addr1 ), rd( addr2 ) ) ); }
+
+OP(30) { AD2_X8; SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(31) { AD2_Y8; SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(32) { AD2_XL; SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(33) { AD2_YL; SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(34) { AD1_IHL; SUB8( rd( addr1 ), ( regs.BA & 0x00FF ) ); }
+OP(35) { AD1_IHL; SUB8( rd( addr1 ), rdop() ); }
+OP(36) { AD1_IHL; AD2_XIX; SUB8( rd( addr1 ), rd( addr2 ) ); }
+OP(37) { AD1_IHL; AD2_YIY; SUB8( rd( addr1 ), rd( addr2 ) ); }
+OP(38) { AD2_X8; regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(39) { AD2_Y8; regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(3A) { AD2_XL; regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(3B) { AD2_YL; regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(3C) { AD1_IHL; wr( addr1, XOR8( rd( addr1 ), ( regs.BA & 0x00FF ) ) ); }
+OP(3D) { AD1_IHL; wr( addr1, XOR8( rd( addr1 ), rdop() ) ); }
+OP(3E) { AD1_IHL; AD2_XIX; wr( addr1, XOR8( rd( addr1 ), rd( addr2 ) ) ); }
+OP(3F) { AD1_IHL; AD2_YIY; wr( addr1, XOR8( rd( addr1 ), rd( addr2 ) ) ); }
+
+OP(40) { AD2_X8; regs.BA = ( regs.BA & 0xFF00 ) | rd( addr2 ); }
+OP(41) { AD2_Y8; regs.BA = ( regs.BA & 0xFF00 ) | rd( addr2 ); }
+OP(42) { AD2_XL; regs.BA = ( regs.BA & 0xFF00 ) | rd( addr2 ); }
+OP(43) { AD2_YL; regs.BA = ( regs.BA & 0xFF00 ) | rd( addr2 ); }
+OP(44) { AD1_X8; wr( addr1, ( regs.BA & 0x00FF ) ); }
+OP(45) { AD1_Y8; wr( addr1, ( regs.BA & 0x00FF ) ); }
+OP(46) { AD1_XL; wr( addr1, ( regs.BA & 0x00FF ) ); }
+OP(47) { AD1_YL; wr( addr1, ( regs.BA & 0x00FF ) ); }
+OP(48) { AD2_X8; regs.BA = ( regs.BA & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(49) { AD2_Y8; regs.BA = ( regs.BA & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(4A) { AD2_XL; regs.BA = ( regs.BA & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(4B) { AD2_YL; regs.BA = ( regs.BA & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(4C) { AD1_X8; wr( addr1, ( regs.BA >> 8 ) ); }
+OP(4D) { AD1_Y8; wr( addr1, ( regs.BA >> 8 ) ); }
+OP(4E) { AD1_XL; wr( addr1, ( regs.BA >> 8 ) ); }
+OP(4F) { AD1_YL; wr( addr1, ( regs.BA >> 8 ) ); }
+
+OP(50) { AD2_X8; regs.HL = ( regs.HL & 0xFF00 ) | rd( addr2 ); }
+OP(51) { AD2_Y8; regs.HL = ( regs.HL & 0xFF00 ) | rd( addr2 ); }
+OP(52) { AD2_XL; regs.HL = ( regs.HL & 0xFF00 ) | rd( addr2 ); }
+OP(53) { AD2_YL; regs.HL = ( regs.HL & 0xFF00 ) | rd( addr2 ); }
+OP(54) { AD1_X8; wr( addr1, ( regs.HL & 0x00FF ) ); }
+OP(55) { AD1_Y8; wr( addr1, ( regs.HL & 0x00FF ) ); }
+OP(56) { AD1_XL; wr( addr1, ( regs.HL & 0x00FF ) ); }
+OP(57) { AD1_YL; wr( addr1, ( regs.HL & 0x00FF ) ); }
+OP(58) { AD2_X8; regs.HL = ( regs.HL & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(59) { AD2_Y8; regs.HL = ( regs.HL & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(5A) { AD2_XL; regs.HL = ( regs.HL & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(5B) { AD2_YL; regs.HL = ( regs.HL & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(5C) { AD1_X8; wr( addr1, ( regs.HL >> 8 ) ); }
+OP(5D) { AD1_Y8; wr( addr1, ( regs.HL >> 8 ) ); }
+OP(5E) { AD1_XL; wr( addr1, ( regs.HL >> 8 ) ); }
+OP(5F) { AD1_YL; wr( addr1, ( regs.HL >> 8 ) ); }
+
+OP(60) { AD1_IHL; AD2_X8; wr( addr1, rd( addr2 ) ); }
+OP(61) { AD1_IHL; AD2_Y8; wr( addr1, rd( addr2 ) ); }
+OP(62) { AD1_IHL; AD2_XL; wr( addr1, rd( addr2 ) ); }
+OP(63) { AD1_IHL; AD2_YL; wr( addr1, rd( addr2 ) ); }
+OP(64) { /* illegal operation? */ }
+OP(65) { /* illegal operation? */ }
+OP(66) { /* illegal operation? */ }
+OP(67) { /* illegal operation? */ }
+OP(68) { AD1_XIX; AD2_X8; wr( addr1, rd( addr2 ) ); }
+OP(69) { AD1_XIX; AD2_Y8; wr( addr1, rd( addr2 ) ); }
+OP(6A) { AD1_XIX; AD2_XL; wr( addr1, rd( addr2 ) ); }
+OP(6B) { AD1_XIX; AD2_YL; wr( addr1, rd( addr2 ) ); }
+OP(6C) { /* illegal operation? */ }
+OP(6D) { /* illegal operation? */ }
+OP(6E) { /* illegal operation? */ }
+OP(6F) { /* illegal operation? */ }
+
+OP(70) { /* illegal operation? */ }
+OP(71) { /* illegal operation? */ }
+OP(72) { /* illegal operation? */ }
+OP(73) { /* illegal operation? */ }
+OP(74) { /* illegal operation? */ }
+OP(75) { /* illegal operation? */ }
+OP(76) { /* illegal operation? */ }
+OP(77) { /* illegal operation? */ }
+OP(78) { AD1_YIY; AD2_X8; wr( addr1, rd( addr2 ) ); }
+OP(79) { AD1_YIY; AD2_Y8; wr( addr1, rd( addr2 ) ); }
+OP(7A) { AD1_YIY; AD2_XL; wr( addr1, rd( addr2 ) ); }
+OP(7B) { AD1_YIY; AD2_YL; wr( addr1, rd( addr2 ) ); }
+OP(7C) { /* illegal operation? */ }
+OP(7D) { /* illegal operation? */ }
+OP(7E) { /* illegal operation? */ }
+OP(7F) { /* illegal operation? */ }
+
+OP(80) { regs.BA = ( regs.BA & 0xFF00 ) | SAL8( regs.BA & 0x00FF ); }
+OP(81) { regs.BA = ( regs.BA & 0x00FF ) | ( SAL8( regs.BA >> 8 )<< 8 ); }
+OP(82) { AD1_IN8; wr( addr1, SAL8( rd( addr1 ) ) ); }
+OP(83) { AD1_IHL; wr( addr1, SAL8( rd( addr1 ) ) ); }
+OP(84) { regs.BA = ( regs.BA & 0xFF00 ) | SHL8( regs.BA & 0x00FF ); }
+OP(85) { regs.BA = ( regs.BA & 0x00FF ) | ( SHL8( regs.BA >> 8 ) << 8 ); }
+OP(86) { AD1_IN8; wr( addr1, SHL8( rd( addr1 ) ) ); }
+OP(87) { AD1_IHL; wr( addr1, SHL8( rd( addr1 ) ) ); }
+OP(88) { regs.BA = ( regs.BA & 0xFF00 ) | SAR8( regs.BA & 0x00FF ); }
+OP(89) { regs.BA = ( regs.BA & 0x00FF ) | ( SAR8( regs.BA >> 8 ) << 8 ); }
+OP(8A) { AD1_IN8; wr( addr1, SAR8( rd( addr1 ) ) ); }
+OP(8B) { AD1_IHL; wr( addr1, SAR8( rd( addr1 ) ) ); }
+OP(8C) { regs.BA = ( regs.BA & 0xFF00 ) | SHR8( regs.BA & 0x00FF ); }
+OP(8D) { regs.BA = ( regs.BA & 0x00FF ) | ( SHR8( regs.BA >> 8 ) << 8 ); }
+OP(8E) { AD1_IN8; wr( addr1, SHR8( rd( addr1 ) ) ); }
+OP(8F) { AD1_IHL; wr( addr1, SHR8( rd( addr1 ) ) ); }
+
+OP(90) { regs.BA = ( regs.BA & 0xFF00 ) | ROLC8( regs.BA & 0x00FF ); }
+OP(91) { regs.BA = ( regs.BA & 0x00FF ) | ( ROLC8( regs.BA >> 8 ) << 8 ); }
+OP(92) { AD1_IN8; wr( addr1, ROLC8( rd( addr1 ) ) ); }
+OP(93) { AD1_IHL; wr( addr1, ROLC8( rd( addr1 ) ) ); }
+OP(94) { regs.BA = ( regs.BA & 0xFF00 ) | ROL8( regs.BA & 0x00FF ); }
+OP(95) { regs.BA = ( regs.BA & 0x00FF ) | ( ROL8( regs.BA >> 8 ) << 8 ); }
+OP(96) { AD1_IN8; wr( addr1, ROL8( rd( addr1 ) ) ); }
+OP(97) { AD1_IHL; wr( addr1, ROL8( rd( addr1 ) ) ); }
+OP(98) { regs.BA = ( regs.BA & 0xFF00 ) | RORC8( regs.BA & 0x00FF ); }
+OP(99) { regs.BA = ( regs.BA & 0x00FF ) | ( RORC8( regs.BA >> 8 ) << 8 ); }
+OP(9A) { AD1_IN8; wr( addr1, RORC8( rd( addr1 ) ) ); }
+OP(9B) { AD1_IHL; wr( addr1, RORC8( rd( addr1 ) ) ); }
+OP(9C) { regs.BA = ( regs.BA & 0xFF00 ) | ROR8( regs.BA & 0x00FF ); }
+OP(9D) { regs.BA = ( regs.BA & 0x00FF ) | ( ROR8( regs.BA >> 8 ) << 8 ); }
+OP(9E) { AD1_IN8; wr( addr1, ROR8( rd( addr1 ) ) ); }
+OP(9F) { AD1_IHL; wr( addr1, ROR8( rd( addr1 ) ) ); }
+
+OP(A0) { regs.BA = ( regs.BA & 0xFF00 ) | NOT8( regs.BA & 0x00FF ); }
+OP(A1) { regs.BA = ( regs.BA & 0x00FF ) | ( NOT8( regs.BA >> 8 ) << 8 ); }
+OP(A2) { AD1_IN8; wr( addr1, NOT8( rd( addr1 ) ) ); }
+OP(A3) { AD1_IHL; wr( addr1, NOT8( rd( addr1 ) ) ); }
+OP(A4) { regs.BA = ( regs.BA & 0xFF00 ) | NEG8( regs.BA & 0x00FF ); }
+OP(A5) { regs.BA = ( regs.BA & 0x00FF ) | ( NEG8( regs.BA >> 8 ) << 8 ); }
+OP(A6) { AD1_IN8; wr( addr1, NEG8( rd( addr1 ) ) ); }
+OP(A7) { AD1_IHL; wr( addr1, NEG8( rd( addr1 ) ) ); }
+OP(A8) { regs.BA = ( ( regs.BA & 0x0080 ) ? ( 0xFF00 | regs.BA ) : ( regs.BA & 0x00FF ) ); }
+OP(A9) { /* illegal operation? */ }
+OP(AA) { /* illegal operation? */ }
+OP(AB) { /* illegal operation? */ }
+OP(AC) { /* illegal operation? */ }
+OP(AD) { /* illegal operation? */ }
+OP(AE) { /* HALT */ }
+OP(AF) { }
+
+OP(B0) { regs.BA = ( regs.BA & 0x00FF ) | ( AND8( ( regs.BA >> 8 ), rdop() ) << 8 ); }
+OP(B1) { regs.HL = ( regs.HL & 0xFF00 ) | AND8( ( regs.HL & 0x00FF ), rdop() ); }
+OP(B2) { regs.HL = ( regs.HL & 0x00FF ) | ( AND8( ( regs.HL >> 8 ), rdop() ) << 8 ); }
+OP(B3) { /* illegal operation? */ }
+OP(B4) { regs.BA = ( regs.BA & 0x00FF ) | ( OR8( ( regs.BA >> 8 ), rdop() ) << 8 ); }
+OP(B5) { regs.HL = ( regs.HL & 0xFF00 ) | OR8( ( regs.HL & 0x00FF ), rdop() ); }
+OP(B6) { regs.HL = ( regs.HL & 0x00FF ) | ( OR8( ( regs.HL >> 8 ), rdop() ) << 8 ); }
+OP(B7) { /* illegal operation? */ }
+OP(B8) { regs.BA = ( regs.BA & 0x00FF ) | ( XOR8( ( regs.BA >> 8 ), rdop() ) << 8 ); }
+OP(B9) { regs.HL = ( regs.HL & 0xFF00 ) | XOR8( ( regs.HL & 0x00FF ), rdop() ); }
+OP(BA) { regs.HL = ( regs.HL & 0x00FF ) | ( XOR8( ( regs.HL >> 8 ), rdop() ) << 8 ); }
+OP(BB) { /* illegal operation? */ }
+OP(BC) { SUB8( ( regs.BA >> 8 ), rdop() ); }
+OP(BD) { SUB8( ( regs.HL & 0x00FF), rdop() ); }
+OP(BE) { SUB8( ( regs.HL >> 8 ), rdop() ); }
+OP(BF) { SUB8( regs.N, rdop() ); }
+
+OP(C0) { regs.BA = ( regs.BA & 0xFF00 ) | regs.N; }
+OP(C1) { regs.BA = ( regs.BA & 0xFF00 ) | regs.F; }
+OP(C2) { regs.N = ( regs.BA & 0x00FF ); }
+OP(C3) { regs.F = ( regs.BA & 0x00FF ); }
+OP(C4) { regs.U = rdop(); }
+OP(C5) { regs.I = rdop(); }
+OP(C6) { regs.XI = rdop(); }
+OP(C7) { regs.YI = rdop(); }
+OP(C8) { regs.BA = ( regs.BA & 0xFF00 ) | regs.V; }
+OP(C9) { regs.BA = ( regs.BA & 0xFF00 ) | regs.I; }
+OP(CA) { regs.BA = ( regs.BA & 0xFF00 ) | regs.XI; }
+OP(CB) { regs.BA = ( regs.BA & 0xFF00 ) | regs.YI; }
+OP(CC) { regs.U = ( regs.BA & 0x00FF ); }
+OP(CD) { regs.I = ( regs.BA & 0x00FF ); }
+OP(CE) { regs.XI = ( regs.BA & 0x00FF ); }
+OP(CF) { regs.YI = ( regs.BA & 0x00FF ); }
+
+OP(D0) { AD2_I16; regs.BA = ( regs.BA & 0xFF00 ) | rd( addr2 ); }
+OP(D1) { AD2_I16; regs.BA = ( regs.BA & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(D2) { AD2_I16; regs.HL = ( regs.HL & 0xFF00 ) | rd( addr2 ); }
+OP(D3) { AD2_I16; regs.HL = ( regs.HL & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(D4) { AD1_I16; wr( addr1, ( regs.BA & 0x00FF ) ); }
+OP(D5) { AD1_I16; wr( addr1, ( regs.BA >> 8 ) ); }
+OP(D6) { AD1_I16; wr( addr1, ( regs.HL & 0x00FF ) ); }
+OP(D7) { AD1_I16; wr( addr1, ( regs.HL >> 8 ) ); }
+OP(D8) { }
+OP(D9) { }
+OP(DA) { /* illegal operation? */ }
+OP(DB) { /* illegal operation? */ }
+OP(DC) { /* illegal operation? */ }
+OP(DD) { /* illegal operation? */ }
+OP(DE) { /* illegal operation? */ }
+OP(DF) { /* illegal operation? */ }
+
+OP(E0) { INT8 d8 = rdop(); if ( ( ( regs.F & ( FLAG_S | FLAG_O ) ) == FLAG_S ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == FLAG_O ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E1) { INT8 d8 = rdop(); if ( ( regs.F & FLAG_Z ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == FLAG_S ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == FLAG_O ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E2) { INT8 d8 = rdop(); if ( !( regs.F & FLAG_Z ) && ( ( ( regs.F & ( FLAG_S | FLAG_O ) ) == 0 ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == ( FLAG_S | FLAG_O ) ) ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E3) { INT8 d8 = rdop(); if ( ( ( regs.F & ( FLAG_S | FLAG_O ) ) == 0 ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == ( FLAG_S | FLAG_O ) ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E4) { INT8 d8 = rdop(); if ( ( regs.F & FLAG_O ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E5) { INT8 d8 = rdop(); if ( ! ( regs.F & FLAG_O ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E6) { INT8 d8 = rdop(); if ( ! ( regs.F & FLAG_S ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E7) { INT8 d8 = rdop(); if ( ( regs.F & FLAG_S ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E8) { INT8 d8 = rdop(); if ( ! ( regs.E & EXEC_X0 ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E9) { INT8 d8 = rdop(); if ( ! ( regs.E & EXEC_X1 ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(EA) { INT8 d8 = rdop(); if ( ! ( regs.E & EXEC_X2 ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(EB) { INT8 d8 = rdop(); if ( ! ( regs.E & EXEC_DZ ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(EC) { INT8 d8 = rdop(); if ( ( regs.E & EXEC_X0 ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(ED) { INT8 d8 = rdop(); if ( ( regs.E & EXEC_X1 ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(EE) { INT8 d8 = rdop(); if ( ( regs.E & EXEC_X2 ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(EF) { INT8 d8 = rdop(); if ( ( regs.E & EXEC_DZ ) ) { JMP( regs.PC + d8 - 1 ); } }
+
+OP(F0) { INT8 d8 = rdop(); if ( ( ( regs.F & ( FLAG_S | FLAG_O ) ) == FLAG_S ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == FLAG_O ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(F1) { INT8 d8 = rdop(); if ( ( regs.F & FLAG_Z ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == FLAG_S ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == FLAG_O ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(F2) { INT8 d8 = rdop(); if ( !( regs.F & FLAG_Z ) && ( ( ( regs.F & ( FLAG_S | FLAG_O ) ) == 0 ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == ( FLAG_S | FLAG_O ) ) ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(F3) { INT8 d8 = rdop(); if ( ( ( regs.F & ( FLAG_S | FLAG_O ) ) == 0 ) || ( ( regs.F & ( FLAG_S | FLAG_O ) ) == ( FLAG_S | FLAG_O ) ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(F4) { INT8 d8 = rdop(); if ( ( regs.F & FLAG_O ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(F5) { INT8 d8 = rdop(); if ( ! ( regs.F & FLAG_O ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(F6) { INT8 d8 = rdop(); if ( ! ( regs.F & FLAG_S ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(F7) { INT8 d8 = rdop(); if ( ( regs.F & FLAG_S ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(F8) { INT8 d8 = rdop(); if ( ! ( regs.E & EXEC_X0 ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(F9) { INT8 d8 = rdop(); if ( ! ( regs.E & EXEC_X1 ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(FA) { INT8 d8 = rdop(); if ( ! ( regs.E & EXEC_X2 ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(FB) { INT8 d8 = rdop(); if ( ! ( regs.E & EXEC_DZ ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(FC) { INT8 d8 = rdop(); if ( ( regs.E & EXEC_X0 ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(FD) { INT8 d8 = rdop(); if ( ( regs.E & EXEC_X1 ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(FE) { INT8 d8 = rdop(); if ( ( regs.E & EXEC_X2 ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(FF) { INT8 d8 = rdop(); if ( ( regs.E & EXEC_DZ ) ) { CALL( regs.PC + d8 - 1 ); } }
+
+static void (*insnminx_CE[256])(void) = {
+ minx_CE_00, minx_CE_01, minx_CE_02, minx_CE_03, minx_CE_04, minx_CE_05, minx_CE_06, minx_CE_07,
+ minx_CE_08, minx_CE_09, minx_CE_0A, minx_CE_0B, minx_CE_0C, minx_CE_0D, minx_CE_0E, minx_CE_0F,
+ minx_CE_10, minx_CE_11, minx_CE_12, minx_CE_13, minx_CE_14, minx_CE_15, minx_CE_16, minx_CE_17,
+ minx_CE_18, minx_CE_19, minx_CE_1A, minx_CE_1B, minx_CE_1C, minx_CE_1D, minx_CE_1E, minx_CE_1F,
+ minx_CE_20, minx_CE_21, minx_CE_22, minx_CE_23, minx_CE_24, minx_CE_25, minx_CE_26, minx_CE_27,
+ minx_CE_28, minx_CE_29, minx_CE_2A, minx_CE_2B, minx_CE_2C, minx_CE_2D, minx_CE_2E, minx_CE_2F,
+ minx_CE_30, minx_CE_31, minx_CE_32, minx_CE_33, minx_CE_34, minx_CE_35, minx_CE_36, minx_CE_37,
+ minx_CE_38, minx_CE_39, minx_CE_3A, minx_CE_3B, minx_CE_3C, minx_CE_3D, minx_CE_3E, minx_CE_3F,
+ minx_CE_40, minx_CE_41, minx_CE_42, minx_CE_43, minx_CE_44, minx_CE_45, minx_CE_46, minx_CE_47,
+ minx_CE_48, minx_CE_49, minx_CE_4A, minx_CE_4B, minx_CE_4C, minx_CE_4D, minx_CE_4E, minx_CE_4F,
+ minx_CE_50, minx_CE_51, minx_CE_52, minx_CE_53, minx_CE_54, minx_CE_55, minx_CE_56, minx_CE_57,
+ minx_CE_58, minx_CE_59, minx_CE_5A, minx_CE_5B, minx_CE_5C, minx_CE_5D, minx_CE_5E, minx_CE_5F,
+ minx_CE_60, minx_CE_61, minx_CE_62, minx_CE_63, minx_CE_64, minx_CE_65, minx_CE_66, minx_CE_67,
+ minx_CE_68, minx_CE_69, minx_CE_6A, minx_CE_6B, minx_CE_6C, minx_CE_6D, minx_CE_6E, minx_CE_6F,
+ minx_CE_70, minx_CE_71, minx_CE_72, minx_CE_73, minx_CE_74, minx_CE_75, minx_CE_76, minx_CE_77,
+ minx_CE_78, minx_CE_79, minx_CE_7A, minx_CE_7B, minx_CE_7C, minx_CE_7D, minx_CE_7E, minx_CE_7F,
+ minx_CE_80, minx_CE_81, minx_CE_82, minx_CE_83, minx_CE_84, minx_CE_85, minx_CE_86, minx_CE_87,
+ minx_CE_88, minx_CE_89, minx_CE_8A, minx_CE_8B, minx_CE_8C, minx_CE_8D, minx_CE_8E, minx_CE_8F,
+ minx_CE_90, minx_CE_91, minx_CE_92, minx_CE_93, minx_CE_94, minx_CE_95, minx_CE_96, minx_CE_97,
+ minx_CE_98, minx_CE_99, minx_CE_9A, minx_CE_9B, minx_CE_9C, minx_CE_9D, minx_CE_9E, minx_CE_9F,
+ minx_CE_A0, minx_CE_A1, minx_CE_A2, minx_CE_A3, minx_CE_A4, minx_CE_A5, minx_CE_A6, minx_CE_A7,
+ minx_CE_A8, minx_CE_A9, minx_CE_AA, minx_CE_AB, minx_CE_AC, minx_CE_AD, minx_CE_AE, minx_CE_AF,
+ minx_CE_B0, minx_CE_B1, minx_CE_B2, minx_CE_B3, minx_CE_B4, minx_CE_B5, minx_CE_B6, minx_CE_B7,
+ minx_CE_B8, minx_CE_B9, minx_CE_BA, minx_CE_BB, minx_CE_BC, minx_CE_BD, minx_CE_BE, minx_CE_BF,
+ minx_CE_C0, minx_CE_C1, minx_CE_C2, minx_CE_C3, minx_CE_C4, minx_CE_C5, minx_CE_C6, minx_CE_C7,
+ minx_CE_C8, minx_CE_C9, minx_CE_CA, minx_CE_CB, minx_CE_CC, minx_CE_CD, minx_CE_CE, minx_CE_CF,
+ minx_CE_D0, minx_CE_D1, minx_CE_D2, minx_CE_D3, minx_CE_D4, minx_CE_D5, minx_CE_D6, minx_CE_D7,
+ minx_CE_D8, minx_CE_D9, minx_CE_DA, minx_CE_DB, minx_CE_DC, minx_CE_DD, minx_CE_DE, minx_CE_DF,
+ minx_CE_E0, minx_CE_E1, minx_CE_E2, minx_CE_E3, minx_CE_E4, minx_CE_E5, minx_CE_E6, minx_CE_E7,
+ minx_CE_E8, minx_CE_E9, minx_CE_EA, minx_CE_EB, minx_CE_EC, minx_CE_ED, minx_CE_EE, minx_CE_EF,
+ minx_CE_F0, minx_CE_F1, minx_CE_F2, minx_CE_F3, minx_CE_F4, minx_CE_F5, minx_CE_F6, minx_CE_F7,
+ minx_CE_F8, minx_CE_F9, minx_CE_FA, minx_CE_FB, minx_CE_FC, minx_CE_FD, minx_CE_FE, minx_CE_FF
+};
+
+static int insnminx_cycles_CE[256] = {
+ 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+
diff --git a/src/emu/cpu/minx/minxopcf.h b/src/emu/cpu/minx/minxopcf.h
new file mode 100644
index 00000000000..19c8b3f3256
--- /dev/null
+++ b/src/emu/cpu/minx/minxopcf.h
@@ -0,0 +1,330 @@
+
+#undef OP
+#define OP(nn) INLINE void minx_CF_##nn(void)
+
+OP(00) { regs.BA = ADD16( regs.BA, regs.BA ); }
+OP(01) { regs.BA = ADD16( regs.BA, regs.HL ); }
+OP(02) { regs.BA = ADD16( regs.BA, regs.X ); }
+OP(03) { regs.BA = ADD16( regs.BA, regs.Y ); }
+OP(04) { regs.BA = ADDC16( regs.BA, regs.BA ); }
+OP(05) { regs.BA = ADDC16( regs.BA, regs.HL ); }
+OP(06) { regs.BA = ADDC16( regs.BA, regs.X ); }
+OP(07) { regs.BA = ADDC16( regs.BA, regs.Y ); }
+OP(08) { regs.BA = SUB16( regs.BA, regs.BA ); }
+OP(09) { regs.BA = SUB16( regs.BA, regs.HL ); }
+OP(0A) { regs.BA = SUB16( regs.BA, regs.X ); }
+OP(0B) { regs.BA = SUB16( regs.BA, regs.Y ); }
+OP(0C) { regs.BA = SUBC16( regs.BA, regs.BA ); }
+OP(0D) { regs.BA = SUBC16( regs.BA, regs.HL ); }
+OP(0E) { regs.BA = SUBC16( regs.BA, regs.X ); }
+OP(0F) { regs.BA = SUBC16( regs.BA, regs.Y ); }
+
+OP(10) { /* illegal instruction? */ }
+OP(11) { /* illegal instruction? */ }
+OP(12) { /* illegal instruction? */ }
+OP(13) { /* illegal instruction? */ }
+OP(14) { /* illegal instruction? */ }
+OP(15) { /* illegal instruction? */ }
+OP(16) { /* illegal instruction? */ }
+OP(17) { /* illegal instruction? */ }
+OP(18) { SUB16( regs.BA, regs.BA ); }
+OP(19) { SUB16( regs.BA, regs.HL ); }
+OP(1A) { SUB16( regs.BA, regs.X ); }
+OP(1B) { SUB16( regs.BA, regs.Y ); }
+OP(1C) { /* illegal instruction? */ }
+OP(1D) { /* illegal instruction? */ }
+OP(1E) { /* illegal instruction? */ }
+OP(1F) { /* illegal instruction? */ }
+
+OP(20) { regs.HL = ADD16( regs.HL, regs.BA ); }
+OP(21) { regs.HL = ADD16( regs.HL, regs.HL ); }
+OP(22) { regs.HL = ADD16( regs.HL, regs.X ); }
+OP(23) { regs.HL = ADD16( regs.HL, regs.Y ); }
+OP(24) { regs.HL = ADDC16( regs.HL, regs.BA ); }
+OP(25) { regs.HL = ADDC16( regs.HL, regs.HL ); }
+OP(26) { regs.HL = ADDC16( regs.HL, regs.X ); }
+OP(27) { regs.HL = ADDC16( regs.HL, regs.Y ); }
+OP(28) { regs.HL = SUB16( regs.HL, regs.BA ); }
+OP(29) { regs.HL = SUB16( regs.HL, regs.HL ); }
+OP(2A) { regs.HL = SUB16( regs.HL, regs.X ); }
+OP(2B) { regs.HL = SUB16( regs.HL, regs.Y ); }
+OP(2C) { regs.HL = SUBC16( regs.HL, regs.BA ); }
+OP(2D) { regs.HL = SUBC16( regs.HL, regs.HL ); }
+OP(2E) { regs.HL = SUBC16( regs.HL, regs.X ); }
+OP(2F) { regs.HL = SUBC16( regs.HL, regs.Y ); }
+
+OP(30) { /* illegal instruction? */ }
+OP(31) { /* illegal instruction? */ }
+OP(32) { /* illegal instruction? */ }
+OP(33) { /* illegal instruction? */ }
+OP(34) { /* illegal instruction? */ }
+OP(35) { /* illegal instruction? */ }
+OP(36) { /* illegal instruction? */ }
+OP(37) { /* illegal instruction? */ }
+OP(38) { SUB16( regs.HL, regs.BA ); }
+OP(39) { SUB16( regs.HL, regs.HL ); }
+OP(3A) { SUB16( regs.HL, regs.X ); }
+OP(3B) { SUB16( regs.HL, regs.Y ); }
+OP(3C) { /* illegal instruction? */ }
+OP(3D) { /* illegal instruction? */ }
+OP(3E) { /* illegal instruction? */ }
+OP(3F) { /* illegal instruction? */ }
+
+OP(40) { regs.X = ADD16( regs.X, regs.BA ); }
+OP(41) { regs.X = ADD16( regs.X, regs.HL ); }
+OP(42) { regs.Y = ADD16( regs.Y, regs.BA ); }
+OP(43) { regs.Y = ADD16( regs.Y, regs.HL ); }
+OP(44) { regs.SP = ADD16( regs.SP, regs.BA ); }
+OP(45) { regs.SP = ADD16( regs.SP, regs.HL ); }
+OP(46) { /* illegal instruction? */ }
+OP(47) { /* illegal instruction? */ }
+OP(48) { regs.X = SUB16( regs.X, regs.BA ); }
+OP(49) { regs.X = SUB16( regs.X, regs.HL ); }
+OP(4A) { regs.Y = SUB16( regs.Y, regs.BA ); }
+OP(4B) { regs.Y = SUB16( regs.Y, regs.HL ); }
+OP(4C) { regs.SP = SUB16( regs.SP, regs.BA ); }
+OP(4D) { regs.SP = SUB16( regs.SP, regs.HL ); }
+OP(4E) { /* illegal instruction? */ }
+OP(4F) { /* illegal instruction? */ }
+
+OP(50) { /* illegal instruction? */ }
+OP(51) { /* illegal instruction? */ }
+OP(52) { /* illegal instruction? */ }
+OP(53) { /* illegal instruction? */ }
+OP(54) { /* illegal instruction? */ }
+OP(55) { /* illegal instruction? */ }
+OP(56) { /* illegal instruction? */ }
+OP(57) { /* illegal instruction? */ }
+OP(58) { /* illegal instruction? */ }
+OP(59) { /* illegal instruction? */ }
+OP(5A) { /* illegal instruction? */ }
+OP(5B) { /* illegal instruction? */ }
+OP(5C) { SUB16( regs.SP, regs.BA ); }
+OP(5D) { SUB16( regs.SP, regs.HL ); }
+OP(5E) { /* illegal instruction? */ }
+OP(5F) { /* illegal instruction? */ }
+
+OP(60) { ADDC16( regs.BA, rdop16() ); /* ??? */ }
+OP(61) { ADDC16( regs.HL, rdop16() ); /* ??? */ }
+OP(62) { ADDC16( regs.X, rdop16() ); /* ??? */ }
+OP(63) { ADDC16( regs.Y, rdop16() ); /* ??? */ }
+OP(64) { /* illegal instruction? */ }
+OP(65) { /* illegal instruction? */ }
+OP(66) { /* illegal instruction? */ }
+OP(67) { /* illegal instruction? */ }
+OP(68) { regs.SP = ADD16( regs.SP, rdop16() ); }
+OP(69) { /* illegal instruction? */ }
+OP(6A) { regs.SP = SUB16( regs.SP, rdop16() ); }
+OP(6B) { /* illegal instruction? */ }
+OP(6C) { SUB16( regs.SP, rdop16() ); }
+OP(6D) { /* illegal instruction? */ }
+OP(6E) { regs.SP = rdop16(); }
+OP(6F) { /* illegal instruction? */ }
+
+OP(70) { UINT8 ofs8 = rdop(); regs.BA = rd( regs.SP + ofs8 ); }
+OP(71) { UINT8 ofs8 = rdop(); regs.HL = rd( regs.SP + ofs8 ); }
+OP(72) { UINT8 ofs8 = rdop(); regs.X = rd( regs.SP + ofs8 ); }
+OP(73) { UINT8 ofs8 = rdop(); regs.Y = rd( regs.SP + ofs8 ); }
+OP(74) { UINT8 ofs8 = rdop(); wr( regs.SP + ofs8, regs.BA ); }
+OP(75) { UINT8 ofs8 = rdop(); wr( regs.SP + ofs8, regs.HL ); }
+OP(76) { UINT8 ofs8 = rdop(); wr( regs.SP + ofs8, regs.X ); }
+OP(77) { UINT8 ofs8 = rdop(); wr( regs.SP + ofs8, regs.Y ); }
+OP(78) { AD2_I16; regs.SP = rd16( addr2 ); }
+OP(79) { /* illegal instruction? */ }
+OP(7A) { /* illegal instruction? */ }
+OP(7B) { /* illegal instruction? */ }
+OP(7C) { AD1_I16; wr16( addr1, regs.SP ); }
+OP(7D) { /* illegal instruction? */ }
+OP(7E) { /* illegal instruction? */ }
+OP(7F) { /* illegal instruction? */ }
+
+OP(80) { /* illegal instruction? */ }
+OP(81) { /* illegal instruction? */ }
+OP(82) { /* illegal instruction? */ }
+OP(83) { /* illegal instruction? */ }
+OP(84) { /* illegal instruction? */ }
+OP(85) { /* illegal instruction? */ }
+OP(86) { /* illegal instruction? */ }
+OP(87) { /* illegal instruction? */ }
+OP(88) { /* illegal instruction? */ }
+OP(89) { /* illegal instruction? */ }
+OP(8A) { /* illegal instruction? */ }
+OP(8B) { /* illegal instruction? */ }
+OP(8C) { /* illegal instruction? */ }
+OP(8D) { /* illegal instruction? */ }
+OP(8E) { /* illegal instruction? */ }
+OP(8F) { /* illegal instruction? */ }
+
+OP(90) { /* illegal instruction? */ }
+OP(91) { /* illegal instruction? */ }
+OP(92) { /* illegal instruction? */ }
+OP(93) { /* illegal instruction? */ }
+OP(94) { /* illegal instruction? */ }
+OP(95) { /* illegal instruction? */ }
+OP(96) { /* illegal instruction? */ }
+OP(97) { /* illegal instruction? */ }
+OP(98) { /* illegal instruction? */ }
+OP(99) { /* illegal instruction? */ }
+OP(9A) { /* illegal instruction? */ }
+OP(9B) { /* illegal instruction? */ }
+OP(9C) { /* illegal instruction? */ }
+OP(9D) { /* illegal instruction? */ }
+OP(9E) { /* illegal instruction? */ }
+OP(9F) { /* illegal instruction? */ }
+
+OP(A0) { /* illegal instruction? */ }
+OP(A1) { /* illegal instruction? */ }
+OP(A2) { /* illegal instruction? */ }
+OP(A3) { /* illegal instruction? */ }
+OP(A4) { /* illegal instruction? */ }
+OP(A5) { /* illegal instruction? */ }
+OP(A6) { /* illegal instruction? */ }
+OP(A7) { /* illegal instruction? */ }
+OP(A8) { /* illegal instruction? */ }
+OP(A9) { /* illegal instruction? */ }
+OP(AA) { /* illegal instruction? */ }
+OP(AB) { /* illegal instruction? */ }
+OP(AC) { /* illegal instruction? */ }
+OP(AD) { /* illegal instruction? */ }
+OP(AE) { /* illegal instruction? */ }
+OP(AF) { /* illegal instruction? */ }
+
+OP(B0) { PUSH8( regs.BA & 0x00FF ); }
+OP(B1) { PUSH8( regs.BA >> 8 ); }
+OP(B2) { PUSH8( regs.HL & 0x00FF ); }
+OP(B3) { PUSH8( regs.HL >> 8 ); }
+OP(B4) { regs.BA = ( regs.BA & 0xFF00 ) | POP8(); }
+OP(B5) { regs.BA = ( regs.BA & 0x00FF ) | ( POP8() << 8 ); }
+OP(B6) { regs.HL = ( regs.HL & 0xFF00 ) | POP8(); }
+OP(B7) { regs.HL = ( regs.HL & 0x00FF ) | ( POP8() << 8 ); }
+OP(B8) { PUSH16( regs.BA ); PUSH16( regs.HL ); PUSH16( regs.X ); PUSH16( regs.Y ); PUSH8( regs.N ); }
+OP(B9) { PUSH16( regs.BA ); PUSH16( regs.HL ); PUSH16( regs.X ); PUSH16( regs.Y ); PUSH8( regs.N ); PUSH8( regs.I ); PUSH8( regs.XI ); PUSH8( regs.YI ); }
+OP(BA) { /* illegal instruction? */ }
+OP(BB) { /* illegal instruction? */ }
+OP(BC) { regs.N = POP8(); regs.Y = POP16(); regs.X = POP16(); regs.HL = POP16(); regs.BA = POP16(); }
+OP(BD) { regs.YI = POP8(); regs.XI = POP8(); regs.I = POP8(); regs.N = POP8(); regs.Y = POP16(); regs.X = POP16(); regs.HL = POP16(); regs.BA = POP16(); }
+OP(BE) { /* illegal instruction? */ }
+OP(BF) { /* illegal instruction? */ }
+
+OP(C0) { AD2_IHL; regs.BA = rd16( addr2 ); }
+OP(C1) { AD2_IHL; regs.HL = rd16( addr2 ); }
+OP(C2) { AD2_IHL; regs.X = rd16( addr2 ); }
+OP(C3) { AD2_IHL; regs.Y = rd16( addr2 ); }
+OP(C4) { AD1_IHL; wr16( addr1, regs.BA ); }
+OP(C5) { AD1_IHL; wr16( addr1, regs.HL ); }
+OP(C6) { AD1_IHL; wr16( addr1, regs.X ); }
+OP(C7) { AD1_IHL; wr16( addr1, regs.Y ); }
+OP(C8) { /* illegal instruction? */ }
+OP(C9) { /* illegal instruction? */ }
+OP(CA) { /* illegal instruction? */ }
+OP(CB) { /* illegal instruction? */ }
+OP(CC) { /* illegal instruction? */ }
+OP(CD) { /* illegal instruction? */ }
+OP(CE) { /* illegal instruction? */ }
+OP(CF) { /* illegal instruction? */ }
+
+OP(D0) { AD2_XIX; regs.BA = rd16( addr2 ); }
+OP(D1) { AD2_XIX; regs.HL = rd16( addr2 ); }
+OP(D2) { AD2_XIX; regs.X = rd16( addr2 ); }
+OP(D3) { AD2_XIX; regs.Y = rd16( addr2 ); }
+OP(D4) { AD1_XIX; wr16( addr1, regs.BA ); }
+OP(D5) { AD1_XIX; wr16( addr1, regs.HL ); }
+OP(D6) { AD1_XIX; wr16( addr1, regs.X ); }
+OP(D7) { AD1_XIX; wr16( addr1, regs.Y ); }
+OP(D8) { AD2_YIY; regs.BA = rd16( addr2 ); }
+OP(D9) { AD2_YIY; regs.HL = rd16( addr2 ); }
+OP(DA) { AD2_YIY; regs.X = rd16( addr2 ); }
+OP(DB) { AD2_YIY; regs.Y = rd16( addr2 ); }
+OP(DC) { AD1_YIY; wr16( addr1, regs.BA ); }
+OP(DD) { AD1_YIY; wr16( addr1, regs.HL ); }
+OP(DE) { AD1_YIY; wr16( addr1, regs.X ); }
+OP(DF) { AD1_YIY; wr16( addr1, regs.Y ); }
+
+OP(E0) { regs.BA = regs.BA; }
+OP(E1) { regs.BA = regs.HL; }
+OP(E2) { regs.BA = regs.X; }
+OP(E3) { regs.BA = regs.Y; }
+OP(E4) { regs.HL = regs.BA; }
+OP(E5) { regs.HL = regs.HL; }
+OP(E6) { regs.HL = regs.X; }
+OP(E7) { regs.HL = regs.Y; }
+OP(E8) { regs.X = regs.BA; }
+OP(E9) { regs.X = regs.HL; }
+OP(EA) { regs.X = regs.X; }
+OP(EB) { regs.X = regs.Y; }
+OP(EC) { regs.Y = regs.BA; }
+OP(ED) { regs.Y = regs.HL; }
+OP(EE) { regs.Y = regs.X; }
+OP(EF) { regs.Y = regs.Y; }
+
+OP(F0) { regs.SP = regs.BA; }
+OP(F1) { regs.SP = regs.HL; }
+OP(F2) { regs.SP = regs.X; }
+OP(F3) { regs.SP = regs.Y; }
+OP(F4) { regs.HL = regs.SP; }
+OP(F5) { regs.HL = regs.PC; }
+OP(F6) { /* illegal instruction? */ }
+OP(F7) { /* illegal instruction? */ }
+OP(F8) { regs.BA = regs.SP; }
+OP(F9) { regs.BA = regs.PC; }
+OP(FA) { regs.X = regs.SP; }
+OP(FB) { /* illegal instruction? */ }
+OP(FC) { /* illegal instruction? */ }
+OP(FD) { /* illegal instruction? */ }
+OP(FE) { regs.Y = regs.SP; }
+OP(FF) { /* illegal instruction? */ }
+
+static void (*insnminx_CF[256])(void) = {
+ minx_CF_00, minx_CF_01, minx_CF_02, minx_CF_03, minx_CF_04, minx_CF_05, minx_CF_06, minx_CF_07,
+ minx_CF_08, minx_CF_09, minx_CF_0A, minx_CF_0B, minx_CF_0C, minx_CF_0D, minx_CF_0E, minx_CF_0F,
+ minx_CF_10, minx_CF_11, minx_CF_12, minx_CF_13, minx_CF_14, minx_CF_15, minx_CF_16, minx_CF_17,
+ minx_CF_18, minx_CF_19, minx_CF_1A, minx_CF_1B, minx_CF_1C, minx_CF_1D, minx_CF_1E, minx_CF_1F,
+ minx_CF_20, minx_CF_21, minx_CF_22, minx_CF_23, minx_CF_24, minx_CF_25, minx_CF_26, minx_CF_27,
+ minx_CF_28, minx_CF_29, minx_CF_2A, minx_CF_2B, minx_CF_2C, minx_CF_2D, minx_CF_2E, minx_CF_2F,
+ minx_CF_30, minx_CF_31, minx_CF_32, minx_CF_33, minx_CF_34, minx_CF_35, minx_CF_36, minx_CF_37,
+ minx_CF_38, minx_CF_39, minx_CF_3A, minx_CF_3B, minx_CF_3C, minx_CF_3D, minx_CF_3E, minx_CF_3F,
+ minx_CF_40, minx_CF_41, minx_CF_42, minx_CF_43, minx_CF_44, minx_CF_45, minx_CF_46, minx_CF_47,
+ minx_CF_48, minx_CF_49, minx_CF_4A, minx_CF_4B, minx_CF_4C, minx_CF_4D, minx_CF_4E, minx_CF_4F,
+ minx_CF_50, minx_CF_51, minx_CF_52, minx_CF_53, minx_CF_54, minx_CF_55, minx_CF_56, minx_CF_57,
+ minx_CF_58, minx_CF_59, minx_CF_5A, minx_CF_5B, minx_CF_5C, minx_CF_5D, minx_CF_5E, minx_CF_5F,
+ minx_CF_60, minx_CF_61, minx_CF_62, minx_CF_63, minx_CF_64, minx_CF_65, minx_CF_66, minx_CF_67,
+ minx_CF_68, minx_CF_69, minx_CF_6A, minx_CF_6B, minx_CF_6C, minx_CF_6D, minx_CF_6E, minx_CF_6F,
+ minx_CF_70, minx_CF_71, minx_CF_72, minx_CF_73, minx_CF_74, minx_CF_75, minx_CF_76, minx_CF_77,
+ minx_CF_78, minx_CF_79, minx_CF_7A, minx_CF_7B, minx_CF_7C, minx_CF_7D, minx_CF_7E, minx_CF_7F,
+ minx_CF_80, minx_CF_81, minx_CF_82, minx_CF_83, minx_CF_84, minx_CF_85, minx_CF_86, minx_CF_87,
+ minx_CF_88, minx_CF_89, minx_CF_8A, minx_CF_8B, minx_CF_8C, minx_CF_8D, minx_CF_8E, minx_CF_8F,
+ minx_CF_90, minx_CF_91, minx_CF_92, minx_CF_93, minx_CF_94, minx_CF_95, minx_CF_96, minx_CF_97,
+ minx_CF_98, minx_CF_99, minx_CF_9A, minx_CF_9B, minx_CF_9C, minx_CF_9D, minx_CF_9E, minx_CF_9F,
+ minx_CF_A0, minx_CF_A1, minx_CF_A2, minx_CF_A3, minx_CF_A4, minx_CF_A5, minx_CF_A6, minx_CF_A7,
+ minx_CF_A8, minx_CF_A9, minx_CF_AA, minx_CF_AB, minx_CF_AC, minx_CF_AD, minx_CF_AE, minx_CF_AF,
+ minx_CF_B0, minx_CF_B1, minx_CF_B2, minx_CF_B3, minx_CF_B4, minx_CF_B5, minx_CF_B6, minx_CF_B7,
+ minx_CF_B8, minx_CF_B9, minx_CF_BA, minx_CF_BB, minx_CF_BC, minx_CF_BD, minx_CF_BE, minx_CF_BF,
+ minx_CF_C0, minx_CF_C1, minx_CF_C2, minx_CF_C3, minx_CF_C4, minx_CF_C5, minx_CF_C6, minx_CF_C7,
+ minx_CF_C8, minx_CF_C9, minx_CF_CA, minx_CF_CB, minx_CF_CC, minx_CF_CD, minx_CF_CE, minx_CF_CF,
+ minx_CF_D0, minx_CF_D1, minx_CF_D2, minx_CF_D3, minx_CF_D4, minx_CF_D5, minx_CF_D6, minx_CF_D7,
+ minx_CF_D8, minx_CF_D9, minx_CF_DA, minx_CF_DB, minx_CF_DC, minx_CF_DD, minx_CF_DE, minx_CF_DF,
+ minx_CF_E0, minx_CF_E1, minx_CF_E2, minx_CF_E3, minx_CF_E4, minx_CF_E5, minx_CF_E6, minx_CF_E7,
+ minx_CF_E8, minx_CF_E9, minx_CF_EA, minx_CF_EB, minx_CF_EC, minx_CF_ED, minx_CF_EE, minx_CF_EF,
+ minx_CF_F0, minx_CF_F1, minx_CF_F2, minx_CF_F3, minx_CF_F4, minx_CF_F5, minx_CF_F6, minx_CF_F7,
+ minx_CF_F8, minx_CF_F9, minx_CF_FA, minx_CF_FB, minx_CF_FC, minx_CF_FD, minx_CF_FE, minx_CF_FF
+};
+
+static int insnminx_cycles_CF[256] = {
+ 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
diff --git a/src/emu/cpu/minx/minxops.h b/src/emu/cpu/minx/minxops.h
new file mode 100644
index 00000000000..9c297ada835
--- /dev/null
+++ b/src/emu/cpu/minx/minxops.h
@@ -0,0 +1,330 @@
+
+#undef OP
+#define OP(nn) INLINE void minx_##nn(void)
+
+OP(00) { regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), ( regs.BA & 0xFF ) ); }
+OP(01) { regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), ( regs.BA >> 8 ) ); }
+OP(02) { regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rdop() ); }
+OP(03) { AD2_IHL; regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(04) { AD2_IN8; regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(05) { AD2_I16; regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(06) { AD2_XIX; regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(07) { AD2_YIY; regs.BA = ( regs.BA & 0xFF00 ) | ADD8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(08) { regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), ( regs.BA & 0xFF ) ); }
+OP(09) { regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), ( regs.BA >> 8 ) ); }
+OP(0A) { regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rdop() ); }
+OP(0B) { AD2_IHL; regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(0C) { AD2_IN8; regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(0D) { AD2_I16; regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(0E) { AD2_XIX; regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(0F) { AD2_YIY; regs.BA = ( regs.BA & 0xFF00 ) | ADDC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+
+OP(10) { regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), ( regs.BA & 0xFF ) ); }
+OP(11) { regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), ( regs.BA >> 8 ) ); }
+OP(12) { regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rdop() ); }
+OP(13) { AD2_IHL; regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(14) { AD2_IN8; regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(15) { AD2_I16; regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(16) { AD2_XIX; regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(17) { AD2_YIY; regs.BA = ( regs.BA & 0xFF00 ) | SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(18) { regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), ( regs.BA & 0xFF ) ); }
+OP(19) { regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), ( regs.BA >> 8 ) ); }
+OP(1A) { regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rdop() ); }
+OP(1B) { AD2_IHL; regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(1C) { AD2_IN8; regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(1D) { AD2_I16; regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(1E) { AD2_XIX; regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(1F) { AD2_YIY; regs.BA = ( regs.BA & 0xFF00 ) | SUBC8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+
+OP(20) { regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), ( regs.BA & 0xFF ) ); }
+OP(21) { regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), ( regs.BA >> 8 ) ); }
+OP(22) { regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rdop() ); }
+OP(23) { AD2_IHL; regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(24) { AD2_IN8; regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(25) { AD2_I16; regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(26) { AD2_XIX; regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(27) { AD2_YIY; regs.BA = ( regs.BA & 0xFF00 ) | AND8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(28) { regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), ( regs.BA & 0xFF ) ); }
+OP(29) { regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), ( regs.BA >> 8 ) ); }
+OP(2A) { regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rdop() ); }
+OP(2B) { AD2_IHL; regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(2C) { AD2_IN8; regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(2D) { AD2_I16; regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(2E) { AD2_XIX; regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(2F) { AD2_YIY; regs.BA = ( regs.BA & 0xFF00 ) | OR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+
+OP(30) { SUB8( ( regs.BA & 0x00FF ), ( regs.BA & 0xFF ) ); }
+OP(31) { SUB8( ( regs.BA & 0x00FF ), ( regs.BA >> 8 ) ); }
+OP(32) { SUB8( ( regs.BA & 0x00FF ), rdop() ); }
+OP(33) { AD2_IHL; SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(34) { AD2_IN8; SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(35) { AD2_I16; SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(36) { AD2_XIX; SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(37) { AD2_YIY; SUB8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(38) { regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), ( regs.BA & 0xFF ) ); }
+OP(39) { regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), ( regs.BA >> 8 ) ); }
+OP(3A) { regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rdop() ); }
+OP(3B) { AD2_IHL; regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(3C) { AD2_IN8; regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(3D) { AD2_I16; regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(3E) { AD2_XIX; regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+OP(3F) { AD2_YIY; regs.BA = ( regs.BA & 0xFF00 ) | XOR8( ( regs.BA & 0x00FF ), rd( addr2 ) ); }
+
+OP(40) { regs.BA = ( regs.BA & 0xFF00 ) | ( regs.BA & 0x00FF); }
+OP(41) { regs.BA = ( regs.BA & 0xFF00 ) | ( regs.BA >> 8 ); }
+OP(42) { regs.BA = ( regs.BA & 0xFF00 ) | ( regs.HL & 0x00FF); }
+OP(43) { regs.BA = ( regs.BA & 0xFF00 ) | ( regs.HL >> 8 ); }
+OP(44) { AD2_IN8; regs.BA = ( regs.BA & 0xFF00 ) | rd( addr2 ); }
+OP(45) { AD2_I16; regs.BA = ( regs.BA & 0xFF00 ) | rd( addr2 ); }
+OP(46) { AD2_XIX; regs.BA = ( regs.BA & 0xFF00 ) | rd( addr2 ); }
+OP(47) { AD2_YIY; regs.BA = ( regs.BA & 0xFF00 ) | rd( addr2 ); }
+OP(48) { regs.BA = ( regs.BA & 0x00FF ) | ( ( regs.BA & 0x00FF) << 8 ); }
+OP(49) { regs.BA = ( regs.BA & 0x00FF ) | ( ( regs.BA >> 8 ) << 8 ); }
+OP(4A) { regs.BA = ( regs.BA & 0x00FF ) | ( ( regs.HL & 0x00FF) << 8 ); }
+OP(4B) { regs.BA = ( regs.BA & 0x00FF ) | ( ( regs.HL >> 8 ) << 8 ); }
+OP(4C) { AD2_IN8; regs.BA = ( regs.BA & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(4D) { AD2_I16; regs.BA = ( regs.BA & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(4E) { AD2_XIX; regs.BA = ( regs.BA & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(4F) { AD2_YIY; regs.BA = ( regs.BA & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+
+OP(50) { regs.HL = ( regs.HL & 0xFF00 ) | ( regs.BA & 0x00FF); }
+OP(51) { regs.HL = ( regs.HL & 0xFF00 ) | ( regs.BA >> 8 ); }
+OP(52) { regs.HL = ( regs.HL & 0xFF00 ) | ( regs.HL & 0x00FF); }
+OP(53) { regs.HL = ( regs.HL & 0xFF00 ) | ( regs.HL >> 8 ); }
+OP(54) { AD2_IN8; regs.HL = ( regs.HL & 0xFF00 ) | rd( addr2 ); }
+OP(55) { AD2_I16; regs.HL = ( regs.HL & 0xFF00 ) | rd( addr2 ); }
+OP(56) { AD2_XIX; regs.HL = ( regs.HL & 0xFF00 ) | rd( addr2 ); }
+OP(57) { AD2_YIY; regs.HL = ( regs.HL & 0xFF00 ) | rd( addr2 ); }
+OP(58) { regs.HL = ( regs.HL & 0x00FF ) | ( ( regs.BA & 0x00FF) << 8 ); }
+OP(59) { regs.HL = ( regs.HL & 0x00FF ) | ( ( regs.BA >> 8 ) << 8 ); }
+OP(5A) { regs.HL = ( regs.HL & 0x00FF ) | ( ( regs.HL & 0x00FF) << 8 ); }
+OP(5B) { regs.HL = ( regs.HL & 0x00FF ) | ( ( regs.HL >> 8 ) << 8 ); }
+OP(5C) { AD2_IN8; regs.HL = ( regs.HL & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(5D) { AD2_I16; regs.HL = ( regs.HL & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(5E) { AD2_XIX; regs.HL = ( regs.HL & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+OP(5F) { AD2_YIY; regs.HL = ( regs.HL & 0x00FF ) | ( rd( addr2 ) << 8 ); }
+
+OP(60) { AD1_XIX; wr( addr1, ( regs.BA & 0x00FF ) ); }
+OP(61) { AD1_XIX; wr( addr1, ( regs.BA >> 8 ) ); }
+OP(62) { AD1_XIX; wr( addr1, ( regs.HL & 0x00FF ) ); }
+OP(63) { AD1_XIX; wr( addr1, ( regs.HL >> 8 ) ); }
+OP(64) { AD1_XIX; AD2_IN8; wr( addr1, rd( addr2 ) ); }
+OP(65) { AD1_XIX; AD2_IHL; wr( addr1, rd( addr2 ) ); }
+OP(66) { AD1_XIX; AD2_XIX; wr( addr1, rd( addr2 ) ); }
+OP(67) { AD1_XIX; AD2_YIY; wr( addr1, rd( addr2 ) ); }
+OP(68) { AD1_IHL; wr( addr1, ( regs.BA & 0x00FF ) ); }
+OP(69) { AD1_IHL; wr( addr1, ( regs.BA >> 8 ) ); }
+OP(6A) { AD1_IHL; wr( addr1, ( regs.HL & 0x00FF ) ); }
+OP(6B) { AD1_IHL; wr( addr1, ( regs.HL >> 8 ) ); }
+OP(6C) { AD1_IHL; AD2_IN8; wr( addr1, rd( addr2 ) ); }
+OP(6D) { AD1_IHL; AD2_IHL; wr( addr1, rd( addr2 ) ); }
+OP(6E) { AD1_IHL; AD2_XIX; wr( addr1, rd( addr2 ) ); }
+OP(6F) { AD1_IHL; AD2_YIY; wr( addr1, rd( addr2 ) ); }
+
+OP(70) { AD1_YIY; wr( addr1, ( regs.BA & 0x00FF ) ); }
+OP(71) { AD1_YIY; wr( addr1, ( regs.BA >> 8 ) ); }
+OP(72) { AD1_YIY; wr( addr1, ( regs.HL & 0x00FF ) ); }
+OP(73) { AD1_YIY; wr( addr1, ( regs.HL >> 8 ) ); }
+OP(74) { AD1_YIY; AD2_IN8; wr( addr1, rd( addr2 ) ); }
+OP(75) { AD1_YIY; AD2_IHL; wr( addr1, rd( addr2 ) ); }
+OP(76) { AD1_YIY; AD2_XIX; wr( addr1, rd( addr2 ) ); }
+OP(77) { AD1_YIY; AD2_YIY; wr( addr1, rd( addr2 ) ); }
+OP(78) { AD1_IN8; wr( addr1, ( regs.BA & 0x00FF ) ); }
+OP(79) { AD1_IN8; wr( addr1, ( regs.BA >> 8 ) ); }
+OP(7A) { AD1_IN8; wr( addr1, ( regs.HL & 0x00FF ) ); }
+OP(7B) { AD1_IN8; wr( addr1, ( regs.HL >> 8 ) ); }
+OP(7C) { /* illegal operation? */ }
+OP(7D) { AD1_IN8; AD2_IHL; wr( addr1, rd( addr2 ) ); }
+OP(7E) { AD1_IN8; AD2_XIX; wr( addr1, rd( addr2 ) ); }
+OP(7F) { AD1_IN8; AD2_YIY; wr( addr1, rd( addr2 ) ); }
+
+OP(80) { regs.BA = ( regs.BA & 0xFF00 ) | INC8( regs.BA & 0x00FF ); }
+OP(81) { regs.BA = ( regs.BA & 0x00FF ) | ( INC8( regs.BA >> 8 ) << 8 ); }
+OP(82) { regs.HL = ( regs.HL & 0xFF00 ) | INC8( regs.HL & 0x00FF ); }
+OP(83) { regs.HL = ( regs.HL & 0x00FF ) | ( INC8( regs.HL >> 8 ) << 8 ); }
+OP(84) { regs.N = INC8( regs.N ); }
+OP(85) { AD1_IN8; wr( addr1, INC8( rd( addr1 ) ) ); }
+OP(86) { AD1_IHL; wr( addr1, INC8( rd( addr1 ) ) ); }
+OP(87) { regs.SP = INC16( regs.SP ); }
+OP(88) { regs.BA = ( regs.BA & 0xFF00 ) | DEC8( regs.BA & 0x00FF ); }
+OP(89) { regs.BA = ( regs.BA & 0x00FF ) | ( DEC8( regs.BA >> 8 ) << 8 ); }
+OP(8A) { regs.HL = ( regs.HL & 0xFF00 ) | DEC8( regs.HL & 0x00FF ); }
+OP(8B) { regs.HL = ( regs.HL & 0x00FF ) | ( DEC8( regs.HL >> 8 ) << 8 ); }
+OP(8C) { regs.N = DEC8( regs.N ); }
+OP(8D) { AD1_IN8; wr( addr1, DEC8( rd( addr1 ) ) ); }
+OP(8E) { AD1_IHL; wr( addr1, DEC8( rd( addr1 ) ) ); }
+OP(8F) { regs.SP = DEC8( regs.SP ); }
+
+OP(90) { regs.BA = INC16( regs.BA ); }
+OP(91) { regs.HL = INC16( regs.HL ); }
+OP(92) { regs.X = INC16( regs.X ); }
+OP(93) { regs.Y = INC16( regs.Y ); }
+OP(94) { regs.F = ( AND8( ( regs.BA & 0x00FF ), ( regs.BA >> 8 ) ) ) ? regs.F & ~FLAG_Z : regs.F | FLAG_Z;}
+OP(95) { AD1_IHL; regs.F = ( AND8( rd( addr1 ), rdop() ) ) ? regs.F & ~FLAG_Z : regs.F | FLAG_Z; }
+OP(96) { regs.F = ( AND8( ( regs.BA & 0x00FF ), rdop() ) ) ? regs.F & ~FLAG_Z : regs.F | FLAG_Z; }
+OP(97) { regs.F = ( AND8( ( regs.BA >> 8 ), rdop() ) ) ? regs.F & ~FLAG_Z : regs.F | FLAG_Z; }
+OP(98) { regs.BA = DEC16( regs.BA ); }
+OP(99) { regs.HL = DEC16( regs.HL ); }
+OP(9A) { regs.X = DEC16( regs.X ); }
+OP(9B) { regs.Y = DEC16( regs.Y ); }
+OP(9C) { regs.F = regs.F & rdop(); }
+OP(9D) { regs.F = regs.F | rdop(); }
+OP(9E) { regs.F = regs.F ^ rdop(); }
+OP(9F) { regs.F = rdop(); }
+
+OP(A0) { PUSH16( regs.BA ); }
+OP(A1) { PUSH16( regs.HL ); }
+OP(A2) { PUSH16( regs.X ); }
+OP(A3) { PUSH16( regs.Y ); }
+OP(A4) { PUSH8( regs.N ); }
+OP(A5) { PUSH8( regs.I ); }
+OP(A6) { PUSH8( regs.XI ); PUSH8( regs.YI ); }
+OP(A7) { PUSH8( regs.F ); }
+OP(A8) { regs.BA = POP16(); }
+OP(A9) { regs.HL = POP16();}
+OP(AA) { regs.X = POP16(); }
+OP(AB) { regs.Y = POP16(); }
+OP(AC) { regs.N = POP8(); }
+OP(AD) { regs.I = POP8(); }
+OP(AE) { regs.YI = POP8(); regs.XI = POP8(); }
+OP(AF) { regs.F = POP8(); }
+
+OP(B0) { UINT8 op = rdop(); regs.BA = ( regs.BA & 0xFF00 ) | op; }
+OP(B1) { UINT8 op = rdop(); regs.BA = ( regs.BA & 0x00FF ) | ( op << 8 ); }
+OP(B2) { UINT8 op = rdop(); regs.HL = ( regs.HL & 0xFF00 ) | op; }
+OP(B3) { UINT8 op = rdop(); regs.HL = ( regs.HL & 0x00FF ) | ( op << 8 ); }
+OP(B4) { UINT8 op = rdop(); regs.N = op; }
+OP(B5) { UINT8 op = rdop(); wr( ( regs.I << 16 ) | regs.HL, op); }
+OP(B6) { UINT8 op = rdop(); wr( ( regs.X << 16 ), op ); }
+OP(B7) { UINT8 op = rdop(); wr( ( regs.Y << 16 ), op ); }
+OP(B8) { AD2_I16; regs.BA = rd16( addr2 ); }
+OP(B9) { AD2_I16; regs.HL = rd16( addr2 ); }
+OP(BA) { AD2_I16; regs.X = rd16( addr2 ); }
+OP(BB) { AD2_I16; regs.Y = rd16( addr2 ); }
+OP(BC) { AD1_I16; wr( addr1, regs.BA ); }
+OP(BD) { AD1_I16; wr( addr1, regs.HL ); }
+OP(BE) { AD1_I16; wr16( addr1, regs.X ); }
+OP(BF) { AD1_I16; wr16( addr1, regs.Y ); }
+
+OP(C0) { regs.BA = ADD16( regs.BA, rdop16() ); }
+OP(C1) { regs.HL = ADD16( regs.HL, rdop16() ); }
+OP(C2) { regs.X = ADD16( regs.X, rdop16() ); }
+OP(C3) { regs.Y = ADD16( regs.Y, rdop16() ); }
+OP(C4) { regs.BA = rdop16(); }
+OP(C5) { regs.HL = rdop16(); }
+OP(C6) { regs.X = rdop16(); }
+OP(C7) { regs.Y = rdop16(); }
+OP(C8) { UINT16 t = regs.BA; regs.BA = regs.HL; regs.HL = t; }
+OP(C9) { UINT16 t = regs.BA; regs.BA = regs.X; regs.X = t; }
+OP(CA) { UINT16 t = regs.BA; regs.BA = regs.Y; regs.Y = t; }
+OP(CB) { UINT16 t = regs.BA; regs.BA = regs.SP; regs.SP = t; }
+OP(CC) { regs.BA = ( regs.BA >> 8 ) | ( ( regs.BA & 0x00FF ) << 8 ); }
+OP(CD) { UINT8 t; AD2_IHL; t = rd( addr2 ); wr( addr2, ( regs.BA & 0x00FF ) ); regs.BA = ( regs.BA & 0xFF00 ) | t; }
+OP(CE) { UINT8 op = rdop(); insnminx_CE[op](); minx_icount -= insnminx_cycles_CE[op]; }
+OP(CF) { UINT8 op = rdop(); insnminx_CF[op](); minx_icount -= insnminx_cycles_CF[op]; }
+
+OP(D0) { regs.BA = SUB16( regs.BA, rdop16() ); }
+OP(D1) { regs.HL = SUB16( regs.HL, rdop16() ); }
+OP(D2) { regs.X = SUB16( regs.X, rdop16() ); }
+OP(D3) { regs.Y = SUB16( regs.Y, rdop16() ); }
+OP(D4) { SUB16( regs.BA, rdop16() ); }
+OP(D5) { SUB16( regs.HL, rdop16() ); }
+OP(D6) { SUB16( regs.X, rdop16() ); }
+OP(D7) { SUB16( regs.Y, rdop16() ); }
+OP(D8) { AD1_IN8; wr( addr1, AND8( rd( addr1 ), rdop() ) ); }
+OP(D9) { AD1_IN8; wr( addr1, OR8( rd( addr1 ), rdop() ) ); }
+OP(DA) { AD1_IN8; wr( addr1, XOR8( rd( addr1 ), rdop() ) ); }
+OP(DB) { AD1_IN8; SUB8( rd( addr1 ), rdop() ); }
+OP(DC) { AD1_IN8; regs.F = ( AND8( rd( addr1 ), rdop() ) ) ? regs.F & ~FLAG_Z : regs.F | FLAG_Z; }
+OP(DD) { AD1_IN8; wr( addr1, rdop() ); }
+OP(DE) { regs.BA = ( regs.BA & 0xFF00 ) | ( ( regs.BA & 0x000F ) | ( ( regs.BA & 0x0F00 ) >> 4 ) ); }
+OP(DF) { regs.BA = ( ( regs.BA & 0x0080 ) ? 0xFF00 : 0x0000 ) | ( regs.BA & 0x000F ); }
+
+OP(E0) { INT8 d8 = rdop(); if ( regs.F & FLAG_C ) { CALL( regs.PC + d8 - 1 ); } }
+OP(E1) { INT8 d8 = rdop(); if ( ! ( regs.F & FLAG_C ) ) { CALL( regs.PC + d8- 1 ); } }
+OP(E2) { INT8 d8 = rdop(); if ( regs.F & FLAG_Z ) { CALL( regs.PC + d8 - 1 ); } }
+OP(E3) { INT8 d8 = rdop(); if ( ! ( regs.F & FLAG_Z ) ) { CALL( regs.PC + d8 - 1 ); } }
+OP(E4) { INT8 d8 = rdop(); if ( regs.F & FLAG_C ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E5) { INT8 d8 = rdop(); if ( ! ( regs.F & FLAG_C ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E6) { INT8 d8 = rdop(); if ( regs.F & FLAG_Z ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E7) { INT8 d8 = rdop(); if ( ! ( regs.F & FLAG_Z ) ) { JMP( regs.PC + d8 - 1 ); } }
+OP(E8) { UINT16 d16 = rdop16(); if ( regs.F & FLAG_C ) { CALL( regs.PC + d16 - 1 ); } }
+OP(E9) { UINT16 d16 = rdop16(); if ( ! ( regs.F & FLAG_C ) ) { CALL( regs.PC + d16 - 1 ); } }
+OP(EA) { UINT16 d16 = rdop16(); if ( regs.F & FLAG_Z ) { CALL( regs.PC + d16 - 1 ); } }
+OP(EB) { UINT16 d16 = rdop16(); if ( ! ( regs.F & FLAG_Z ) ) { CALL( regs.PC + d16 - 1 ); } }
+OP(EC) { UINT16 d16 = rdop16(); if ( regs.F & FLAG_C ) { JMP( regs.PC + d16 - 1 ); } }
+OP(ED) { UINT16 d16 = rdop16(); if ( ! ( regs.F & FLAG_C ) ) { JMP( regs.PC + d16 - 1 ); } }
+OP(EE) { UINT16 d16 = rdop16(); if ( regs.F & FLAG_Z ) { JMP( regs.PC + d16 - 1 ); } }
+OP(EF) { UINT16 d16 = rdop16(); if ( ! ( regs.F & FLAG_Z ) ) { JMP( regs.PC + d16 - 1 ); } }
+
+OP(F0) { INT8 d8 = rdop(); CALL( regs.PC + d8 - 1 ); }
+OP(F1) { INT8 d8 = rdop(); JMP( regs.PC + d8 - 1 ); }
+OP(F2) { UINT16 d16 = rdop16(); CALL( regs.PC + d16 - 1 ); }
+OP(F3) { UINT16 d16 = rdop16(); JMP( regs.PC + d16 - 1 ); }
+OP(F4) { JMP( regs.HL ); }
+OP(F5) { INT8 d8 = rdop(); regs.BA = regs.BA - 0x0100; if ( regs.BA & 0xFF00 ) { JMP( regs.PC + d8 - 1 ); } }
+OP(F6) { regs.BA = ( regs.BA & 0xFF00 ) | ( ( regs.BA & 0x00F0 ) >> 4 ) | ( ( regs.BA & 0x000F ) << 4 ); }
+OP(F7) { UINT8 d; AD1_IHL; d = rd( addr1 ); wr( addr1, ( ( d & 0xF0 ) >> 4 ) | ( ( d & 0x0F ) << 4 ) ); }
+OP(F8) { regs.PC = POP16(); regs.V = POP8(); }
+OP(F9) { regs.F = POP8(); regs.PC = POP16(); regs.V = POP8(); }
+OP(FA) { regs.PC = POP16() + 2; regs.V = POP8(); }
+OP(FB) { AD1_I16; CALL( rd16( addr1 ) ); }
+OP(FC) { UINT16 i = rdop() << 1; CALL( i ); PUSH8( regs.F ); }
+OP(FD) { UINT16 i = rdop() << 1; JMP( i ); /* PUSH8( regs.F );?? */ }
+OP(FE) { /* illegal operation? */ }
+OP(FF) { }
+
+static void (*insnminx[256])(void) = {
+ minx_00, minx_01, minx_02, minx_03, minx_04, minx_05, minx_06, minx_07,
+ minx_08, minx_09, minx_0A, minx_0B, minx_0C, minx_0D, minx_0E, minx_0F,
+ minx_10, minx_11, minx_12, minx_13, minx_14, minx_15, minx_16, minx_17,
+ minx_18, minx_19, minx_1A, minx_1B, minx_1C, minx_1D, minx_1E, minx_1F,
+ minx_20, minx_21, minx_22, minx_23, minx_24, minx_25, minx_26, minx_27,
+ minx_28, minx_29, minx_2A, minx_2B, minx_2C, minx_2D, minx_2E, minx_2F,
+ minx_30, minx_31, minx_32, minx_33, minx_34, minx_35, minx_36, minx_37,
+ minx_38, minx_39, minx_3A, minx_3B, minx_3C, minx_3D, minx_3E, minx_3F,
+ minx_40, minx_41, minx_42, minx_43, minx_44, minx_45, minx_46, minx_47,
+ minx_48, minx_49, minx_4A, minx_4B, minx_4C, minx_4D, minx_4E, minx_4F,
+ minx_50, minx_51, minx_52, minx_53, minx_54, minx_55, minx_56, minx_57,
+ minx_58, minx_59, minx_5A, minx_5B, minx_5C, minx_5D, minx_5E, minx_5F,
+ minx_60, minx_61, minx_62, minx_63, minx_64, minx_65, minx_66, minx_67,
+ minx_68, minx_69, minx_6A, minx_6B, minx_6C, minx_6D, minx_6E, minx_6F,
+ minx_70, minx_71, minx_72, minx_73, minx_74, minx_75, minx_76, minx_77,
+ minx_78, minx_79, minx_7A, minx_7B, minx_7C, minx_7D, minx_7E, minx_7F,
+ minx_80, minx_81, minx_82, minx_83, minx_84, minx_85, minx_86, minx_87,
+ minx_88, minx_89, minx_8A, minx_8B, minx_8C, minx_8D, minx_8E, minx_8F,
+ minx_90, minx_91, minx_92, minx_93, minx_94, minx_95, minx_96, minx_97,
+ minx_98, minx_99, minx_9A, minx_9B, minx_9C, minx_9D, minx_9E, minx_9F,
+ minx_A0, minx_A1, minx_A2, minx_A3, minx_A4, minx_A5, minx_A6, minx_A7,
+ minx_A8, minx_A9, minx_AA, minx_AB, minx_AC, minx_AD, minx_AE, minx_AF,
+ minx_B0, minx_B1, minx_B2, minx_B3, minx_B4, minx_B5, minx_B6, minx_B7,
+ minx_B8, minx_B9, minx_BA, minx_BB, minx_BC, minx_BD, minx_BE, minx_BF,
+ minx_C0, minx_C1, minx_C2, minx_C3, minx_C4, minx_C5, minx_C6, minx_C7,
+ minx_C8, minx_C9, minx_CA, minx_CB, minx_CC, minx_CD, minx_CE, minx_CF,
+ minx_D0, minx_D1, minx_D2, minx_D3, minx_D4, minx_D5, minx_D6, minx_D7,
+ minx_D8, minx_D9, minx_DA, minx_DB, minx_DC, minx_DD, minx_DE, minx_DF,
+ minx_E0, minx_E1, minx_E2, minx_E3, minx_E4, minx_E5, minx_E6, minx_E7,
+ minx_E8, minx_E9, minx_EA, minx_EB, minx_EC, minx_ED, minx_EE, minx_EF,
+ minx_F0, minx_F1, minx_F2, minx_F3, minx_F4, minx_F5, minx_F6, minx_F7,
+ minx_F8, minx_F9, minx_FA, minx_FB, minx_FC, minx_FD, minx_FE, minx_FF
+};
+
+static int insnminx_cycles[256] = {
+ 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
diff --git a/src/emu/cpu/mips/dismips.c b/src/emu/cpu/mips/dismips.c
new file mode 100644
index 00000000000..3b7bc61cd8e
--- /dev/null
+++ b/src/emu/cpu/mips/dismips.c
@@ -0,0 +1,326 @@
+/*
+ * standalone MIPS disassembler by smf
+ *
+ * based on DIS68k by Aaron Giles
+ *
+ */
+
+#include "psx.h"
+
+extern unsigned dasmr3k(char *,unsigned, UINT32);
+extern unsigned dasmmips3(char *,unsigned, UINT32);
+
+struct
+{
+ UINT8 id[ 8 ];
+ UINT32 text; /* SCE only */
+ UINT32 data; /* SCE only */
+ UINT32 pc0;
+ UINT32 gp0; /* SCE only */
+ UINT32 t_addr;
+ UINT32 t_size;
+ UINT32 d_addr; /* SCE only */
+ UINT32 d_size; /* SCE only */
+ UINT32 b_addr; /* SCE only */
+ UINT32 b_size; /* SCE only */
+ UINT32 s_addr;
+ UINT32 s_size;
+ UINT32 SavedSP;
+ UINT32 SavedFP;
+ UINT32 SavedGP;
+ UINT32 SavedRA;
+ UINT32 SavedS0;
+ UINT8 dummy[ 0x800 - 76 ];
+} m_psxexe_header;
+
+#define FORMAT_BIN ( 0 )
+#define FORMAT_PSX ( 1 )
+
+#define CPU_PSX ( 0 )
+#define CPU_R3000 ( 1 )
+#define CPU_R4000 ( 2 )
+
+static UINT8 *filebuf;
+static UINT32 offset;
+static UINT8 order[] = { 0, 1, 2, 3 };
+
+static char *Options[]=
+{
+ "begin", "end", "offset", "order", "format", "cpu", 0
+};
+
+static void usage (void)
+{
+ fprintf( stderr,
+ "Usage: DISMIPS [options] <filename>\n\n"
+ "Available options are:\n"
+ " -begin - Specify begin offset in file to disassemble in bytes [0]\n"
+ " -end - Specify end offset in file to disassemble in bytes [none]\n"
+ " -offset - Specify address to load program in bytes [0]\n"
+ " -order - Specify byte order [0123]\n"
+ " -format - Specify file format bin|psx [bin]\n"
+ " -cpu - Specify cpu psx|r3000|r4000 [psx]\n\n"
+ "All values should be entered in hexadecimal\n" );
+ exit( 1 );
+}
+
+int main( int argc, char *argv[] )
+{
+ FILE *f;
+ UINT8 i;
+ UINT8 j;
+ UINT8 n;
+ UINT8 p;
+ UINT32 begin;
+ UINT32 end;
+ UINT32 filelen;
+ UINT32 len;
+ UINT32 pc;
+ char buf[ 80 ];
+ char *filename;
+ UINT32 format;
+ UINT32 cpu;
+
+ filename = NULL;
+ begin = 0;
+ end = 0xffffffff;
+ format = FORMAT_BIN;
+ cpu = CPU_PSX;
+
+ n = 0;
+ for( i = 1; i < argc; i++ )
+ {
+ if( argv[ i ][ 0 ] != '-' )
+ {
+ switch( n )
+ {
+ case 0:
+ filename = argv[ i ];
+ break;
+ default:
+ usage();
+ break;
+ }
+ n++;
+ }
+ else
+ {
+ for( j = 0; Options[ j ]; j++ )
+ {
+ if( strcmp( argv[ i ] + 1, Options[ j ] ) == 0 )
+ {
+ break;
+ }
+ }
+ switch( j )
+ {
+ case 0:
+ i++;
+ if( i > argc )
+ {
+ usage();
+ }
+ begin = strtoul( argv[ i ], 0, 16 );
+ break;
+ case 1:
+ i++;
+ if( i > argc )
+ {
+ usage();
+ }
+ end = strtoul( argv[ i ], 0, 16 );
+ break;
+ case 2:
+ i++;
+ if( i > argc )
+ {
+ usage();
+ }
+ offset = strtoul( argv[ i ], 0, 16 );
+ break;
+ case 3:
+ i++;
+ if( i > argc )
+ {
+ usage();
+ }
+ if( strlen( argv[ i ] ) != 4 )
+ {
+ usage();
+ }
+ for( p = 0; p < 4; p++ )
+ {
+ if( argv[ i ][ p ] < '0' || argv[ i ][ p ] > '3' )
+ {
+ usage();
+ }
+ order[ p ] = argv[ i ][ p ] - '0';
+ }
+ break;
+ case 4:
+ i++;
+ if( i > argc )
+ {
+ usage();
+ }
+ if( mame_stricmp( argv[ i ], "bin" ) == 0 )
+ {
+ format = FORMAT_BIN;
+ }
+ else if( mame_stricmp( argv[ i ], "psx" ) == 0 )
+ {
+ format = FORMAT_PSX;
+ }
+ else
+ {
+ usage();
+ }
+ break;
+ case 5:
+ i++;
+ if( i > argc )
+ {
+ usage();
+ }
+ if( mame_stricmp( argv[ i ], "psx" ) == 0 )
+ {
+ cpu = CPU_PSX;
+ }
+ else if( mame_stricmp( argv[ i ], "r3000" ) == 0 )
+ {
+ cpu = CPU_R3000;
+ }
+ else if( mame_stricmp( argv[ i ], "r4000" ) == 0 )
+ {
+ cpu = CPU_R4000;
+ }
+ else
+ {
+ usage();
+ }
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ }
+
+ if (!filename)
+ {
+ usage();
+ return 1;
+ }
+ f=fopen (filename,"rb");
+ if (!f)
+ {
+ printf ("Unable to open %s\n",filename);
+ return 2;
+ }
+ fseek (f,0,SEEK_END);
+ filelen=ftell (f);
+
+ if( format == FORMAT_PSX )
+ {
+ fseek( f, 0, SEEK_SET );
+ if( fread( &m_psxexe_header, 1, sizeof( m_psxexe_header ), f ) != sizeof( m_psxexe_header ) )
+ {
+ fprintf( stderr, "error reading ps-x exe header\n" );
+ fclose( f );
+ return 3;
+ }
+ if( memcmp( m_psxexe_header.id, "PS-X EXE", sizeof( m_psxexe_header.id ) ) != 0 )
+ {
+ fprintf( stderr, "invalid ps-x exe header\n" );
+ fclose( f );
+ return 3;
+ }
+ printf( "_start = $%08x\n\n", m_psxexe_header.pc0 );
+ if( offset == 0 )
+ {
+ offset = m_psxexe_header.t_addr;
+ }
+ if( begin == 0 )
+ {
+ begin = sizeof( m_psxexe_header );
+ }
+ if( end == 0xffffffff )
+ {
+ end = sizeof( m_psxexe_header ) + m_psxexe_header.t_size;
+ }
+ }
+
+ fseek (f,begin,SEEK_SET);
+ len=(filelen>end)? (end-begin+1):(filelen-begin);
+ filebuf=malloc(len+16);
+ if (!filebuf)
+ {
+ printf ("Memory allocation error\n");
+ fclose (f);
+ return 3;
+ }
+ memset (filebuf,0,len+16);
+ if (fread(filebuf,1,len,f)!=len)
+ {
+ printf ("Read error\n");
+ fclose (f);
+ free (filebuf);
+ return 4;
+ }
+ fclose (f);
+
+ pc = 0;
+ while( pc < len )
+ {
+ UINT8 op0 = filebuf[ pc + order[ 0 ] ];
+ UINT8 op1 = filebuf[ pc + order[ 1 ] ];
+ UINT8 op2 = filebuf[ pc + order[ 2 ] ];
+ UINT8 op3 = filebuf[ pc + order[ 3 ] ];
+ filebuf[ pc + 0 ] = op0;
+ filebuf[ pc + 1 ] = op1;
+ filebuf[ pc + 2 ] = op2;
+ filebuf[ pc + 3 ] = op3;
+
+ pc += 4;
+ }
+
+ pc = 0;
+ while( pc < len )
+ {
+ switch( cpu )
+ {
+ case CPU_PSX:
+ i = DasmMIPS( buf, pc + offset, filebuf + pc );
+ break;
+ case CPU_R3000:
+ {
+ UINT8 *opram = filebuf + pc;
+ UINT32 op = ( opram[ 3 ] << 24 ) | ( opram[ 2 ] << 16 ) | ( opram[ 1 ] << 8 ) | ( opram[ 0 ] << 0 );
+ i = dasmr3k( buf, pc + offset, op );
+ }
+ break;
+ case CPU_R4000:
+ {
+ UINT8 *opram = filebuf + pc;
+ UINT32 op = ( opram[ 3 ] << 24 ) | ( opram[ 2 ] << 16 ) | ( opram[ 1 ] << 8 ) | ( opram[ 0 ] << 0 );
+ i = dasmmips3( buf, pc + offset, op );
+ }
+ break;
+ }
+
+ printf( "%08x: ", pc + offset );
+ for( j = 0; j < i; j++ )
+ {
+ printf( "%02x ", filebuf[ pc ] );
+ pc++;
+ }
+ while( j < 10 )
+ {
+ printf( " " );
+ j++;
+ }
+ printf( "%s\n", buf );
+ }
+ free (filebuf);
+ return 0;
+}
diff --git a/src/emu/cpu/mips/dismips.mak b/src/emu/cpu/mips/dismips.mak
new file mode 100644
index 00000000000..b7e948dcf14
--- /dev/null
+++ b/src/emu/cpu/mips/dismips.mak
@@ -0,0 +1,2 @@
+..\..\..\..\dismips.exe: dismips.c mipsdasm.c r3kdasm.c mips3dsm.c ../../../lib/util/corestr.c
+ gcc -O3 -Wall -I../../../emu -I../../../lib/util -I../../../osd -DINLINE="static __inline__" -DSTANDALONE -DMAME_DEBUG -DLSB_FIRST dismips.c mipsdasm.c r3kdasm.c mips3dsm.c ../../../lib/util/corestr.c -o../../../../dismips
diff --git a/src/emu/cpu/mips/mdrc64.c b/src/emu/cpu/mips/mdrc64.c
new file mode 100644
index 00000000000..c2dca50e074
--- /dev/null
+++ b/src/emu/cpu/mips/mdrc64.c
@@ -0,0 +1,5731 @@
+/***************************************************************************
+
+ mdrc64.c
+
+ x64 MIPS III recompiler.
+
+ Copyright (c) 2007, Aaron Giles
+ Released for general use under the MAME license
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Conventions/rules:
+
+ * Instructions are grouped into sequences by mips3fe; each
+ sequence of instructions is guaranteed to not contain any
+ branches to any instructions within the sequence apart from
+ the first.
+
+ * Because of the above rule, assumptions are made during the
+ execution of a sequence in order to optimize the generated
+ code.
+
+ * Because some state may be live and not flushed to memory at
+ the time an exception is generated, all exception-generating
+ instructions must jump to stub code that is appended to each
+ group of instructions which cleans up live registers before
+ running the exception code.
+
+ * Page faults are trickier because they are detected in a
+ subroutine. In order to handle this, special markers are added
+ to the code consisting of one qword EXCEPTION_ADDRESS_COOKIE
+ followed by the return address of the call. When a page fault
+ needs to be generated, the common code scans forward from
+ the return address for this cookie/address pair and jumps to
+ the code immediately following.
+
+ * Convention: jumps to non-constant addresses have their target
+ PC stored at [sp+SPOFFS_NEXTPC]
+
+****************************************************************************
+
+ Future improvements:
+ * problem:
+ lui r3,$b000
+ lw r3,$100(r3)
+ if exception happens, then r3 is trashed
+
+ * register allocator can use non-volatile registers if the
+ lifetime is only for this one instruction (only for
+ registers where (gpr.used & ~gpr.modified)
+
+ * spec says if registers aren't sign-extended, then 32-bit ops have
+ undefined results; this can simplify our code
+
+ * track which results are 32-bit sign extended versus 64-bit and
+ only promote when necessary
+
+ * register aliasing - move from one to another either doesn't do
+ anything and tracks both, or else shifts ownership to new
+ target
+
+ * generic drc:
+ * common code to load registers prior to instruction
+ - each register has a callback that generates the load
+ * generate code
+ * common code to write registers afterwards
+ * common register allocation routines (64 integer, 64 FPU)
+ * common OOB mechanism
+ * common self-mod code detection (via write bitmask)
+ * common code validation routines
+
+****************************************************************************
+
+ Temporary stack usage:
+ [esp+32].b = storage for CL in LWL/LWR/SWL/SWR
+ [esp+36].l = storage for new target PC in JR/JALR
+
+***************************************************************************/
+
+#include "mips3fe.h"
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define DISABLE_FIXED_RAM_LOAD (0)
+#define DISABLE_FIXED_RAM_STORE (0)
+#define FLUSH_AFTER_EACH_INSTRUCTION (0)
+#define PRINTF_EXCEPTIONS (0)
+#define PROBE_ADDRESS (0)
+#define LOG_HOTSPOTS (0)
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* extra "conditions" used to augment the basic conditions for OOB handlers */
+#define COND_NONE 16
+#define COND_NO_JUMP 17
+
+/* 64-bit cookie that is scanned for during exception processing */
+#define EXCEPTION_ADDRESS_COOKIE U64(0xcc90cc90cc90cc90)
+
+/* append_readwrite flags */
+#define ARW_READ 0x0000
+#define ARW_WRITE 0x0001
+#define ARW_UNSIGNED 0x0000
+#define ARW_SIGNED 0x0002
+#define ARW_MASKED 0x0004
+#define ARW_CACHED 0x0008
+#define ARW_UNCACHED 0x0010
+
+/* compiler_register_allocate flags */
+#define ALLOC_SRC 0x0001
+#define ALLOC_DST 0x0002
+#define ALLOC_DIRTY 0x0004
+
+/* x86 register tracking flags */
+#define X86REG_LIVE 0x80 /* register is live and contains something */
+#define X86REG_MIPSMASK 0x3f /* low 6 bits indicate which MIPS register we hold */
+
+/* MIPS register tracking flags */
+#define MIPSREG_CONSTANT 0x8000 /* register is constant; low 10 bits select which one */
+#define MIPSREG_DIRTY 0x4000 /* register has been modified and needs to be flushed */
+#define MIPSREG_LIVE 0x2000 /* register is live in an x86 register */
+#define MIPSREG_X86MASK 0x000f /* low 4 bits indicate which x86 register holds us */
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define SPOFFS_SAVECL 32
+#define SPOFFS_NEXTPC 36
+
+#define REGADDR(reg) MDRC(&mips3.core->r[reg])
+#define HIADDR MDRC(&mips3.core->r[REG_HI])
+#define LOADDR MDRC(&mips3.core->r[REG_LO])
+#define CPR0ADDR(reg) MDRC(&mips3.core->cpr[0][reg])
+#define CCR0ADDR(reg) MDRC(&mips3.core->ccr[0][reg])
+#define CPR1ADDR(reg) MDRC(&mips3.core->cpr[1][reg])
+#define CCR1ADDR(reg) MDRC(&mips3.core->ccr[1][reg])
+#define CPR2ADDR(reg) MDRC(&mips3.core->cpr[2][reg])
+#define CCR2ADDR(reg) MDRC(&mips3.core->ccr[2][reg])
+#define FPR32(reg) (IS_FR0 ? &((float *)&mips3.core->cpr[1][0])[reg] : (float *)&mips3.core->cpr[1][reg])
+#define FPR32ADDR(reg) MDRC(FPR32(reg))
+#define FPR64(reg) (IS_FR0 ? (double *)&mips3.core->cpr[1][(reg)/2] : (double *)&mips3.core->cpr[1][reg])
+#define FPR64ADDR(reg) MDRC(FPR64(reg))
+#define CF1ADDR(which) MDRC(&mips3.core->cf[1][(mips3.core->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : (which)])
+#define PCADDR MDRC(&mips3.core->pc)
+#define ICOUNTADDR MDRC(&mips3.core->icount)
+#define COREADDR MDRC(mips3.core)
+
+/* macros for querying/accessing the tracking flags */
+#define ISCONST(x) (((x) & MIPSREG_CONSTANT) != 0)
+#define ISDIRTY(x) (((x) & MIPSREG_DIRTY) != 0)
+#define ISLIVE(x) (((x) & MIPSREG_LIVE) != 0)
+#define CONSTVAL(x) ((INT32)((x) >> 32))
+#define X86REG(x) ((x) & MIPSREG_X86MASK)
+
+/* macro for defining a small positivec constant inline */
+#define MAKE_CONST(x) (MIPSREG_CONSTANT | ((INT64)(x) << 32))
+#define MAKE_DESTREG(x) (MIPSREG_DIRTY | ((x) & MIPSREG_X86MASK))
+
+
+
+/***************************************************************************
+ TYPEDEFS
+***************************************************************************/
+
+typedef struct _readwrite_handlers readwrite_handlers;
+struct _readwrite_handlers
+{
+ x86code * read_byte_signed;
+ x86code * read_byte_unsigned;
+ x86code * read_half_signed;
+ x86code * read_half_unsigned;
+ x86code * read_word_signed;
+ x86code * read_word_unsigned;
+ x86code * read_word_masked;
+ x86code * read_double;
+ x86code * read_double_masked;
+ x86code * write_byte;
+ x86code * write_half;
+ x86code * write_word;
+ x86code * write_word_masked;
+ x86code * write_double;
+ x86code * write_double_masked;
+};
+
+
+typedef INT64 mipsreg_state;
+typedef UINT8 x86reg_state;
+
+
+typedef struct _compiler_state compiler_state;
+struct _compiler_state
+{
+ UINT32 cycles; /* accumulated cycles */
+ x86reg_state x86regs[REG_MAX]; /* tracking what is in the x86 registers */
+ mipsreg_state mipsregs[35]; /* tracking what is in the MIPS registers */
+};
+
+
+typedef struct _oob_handler oob_handler;
+
+typedef void (*oob_callback)(drc_core *drc, oob_handler *oob, void *param);
+
+struct _oob_handler
+{
+ oob_callback callback; /* pointer to callback function */
+ void * param; /* callback parameter */
+ const opcode_desc * desc; /* pointer to description of relevant instruction */
+ emit_link link; /* link to source of the branch */
+ compiler_state compiler; /* state of the compiler at this time */
+};
+
+
+struct _mips3drc_data
+{
+ /* misc data */
+ UINT64 abs64mask[2];
+ UINT32 abs32mask[4];
+
+ /* C functions */
+ x86code * activecpu_gettotalcycles64;
+ x86code * mips3com_update_cycle_counting;
+ x86code * mips3com_tlbr;
+ x86code * mips3com_tlbwi;
+ x86code * mips3com_tlbwr;
+ x86code * mips3com_tlbp;
+
+ /* internal functions */
+ x86code * generate_interrupt_exception;
+ x86code * generate_cop_exception;
+ x86code * generate_overflow_exception;
+ x86code * generate_invalidop_exception;
+ x86code * generate_syscall_exception;
+ x86code * generate_break_exception;
+ x86code * generate_trap_exception;
+ x86code * generate_tlbload_exception;
+ x86code * generate_tlbstore_exception;
+ x86code * handle_pc_tlb_mismatch;
+ x86code * find_exception_handler;
+ x86code * explode_ccr31;
+ x86code * recover_ccr31;
+
+ /* read/write handlers */
+ readwrite_handlers general;
+ readwrite_handlers cached;
+ readwrite_handlers uncached;
+
+ /* out of bounds handlers */
+ oob_handler ooblist[COMPILE_MAX_INSTRUCTIONS*2];
+ int oobcount;
+
+ /* C functions */
+ x86code * execute_c_version;
+
+ /* hotspot tracking */
+#if LOG_HOTSPOTS
+ struct
+ {
+ offs_t pc;
+ UINT32 opcode;
+ UINT64 count;
+ } hotspot[100000];
+ int next_hotspot;
+#endif
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void drc_reset_callback(drc_core *drc);
+static void drc_recompile_callback(drc_core *drc);
+static void drc_entrygen_callback(drc_core *drc);
+
+static void compile_one(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
+
+static void oob_exception_cleanup(drc_core *drc, oob_handler *oob, void *param);
+static void oob_interrupt_cleanup(drc_core *drc, oob_handler *oob, void *param);
+
+static void compiler_register_set_constant(compiler_state *compiler, UINT8 mipsreg, UINT64 constval);
+static mipsreg_state compiler_register_allocate(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 mipsreg, UINT8 flags);
+static void compiler_register_flush(drc_core *drc, compiler_state *compiler, UINT8 mipsreg, int free);
+static void compiler_register_flush_all(drc_core *drc, compiler_state *compiler);
+
+static void probe_printf(void);
+
+static void generate_read_write_handlers(drc_core *drc, readwrite_handlers *handlers, const char *type, UINT8 flags);
+static void append_generate_exception(drc_core *drc, UINT8 exception);
+static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags, UINT32 ptroffs);
+static void append_handle_pc_tlb_mismatch(drc_core *drc);
+static void append_find_exception_handler(drc_core *drc);
+static void append_explode_ccr31(drc_core *drc);
+static void append_recover_ccr31(drc_core *drc);
+static void append_check_interrupts(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
+static void append_check_sw_interrupts(drc_core *drc, int inline_generate);
+
+static void emit_update_cycles_pc_and_flush(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, offs_t destpc);
+
+static int compile_instruction(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
+static int compile_special(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
+static int compile_regimm(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
+static int compile_idt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
+static int compile_cop0(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
+static int compile_cop1(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
+static int compile_cop1x(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
+
+static int compile_shift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable);
+static int compile_dshift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable, int shift_const_plus32);
+static int compile_movzn(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_movn);
+static int compile_trapcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int immediate);
+static int compile_branchcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition);
+static int compile_branchcz(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int link);
+static int compile_add(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate);
+static int compile_dadd(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate);
+static int compile_sub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions);
+static int compile_dsub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions);
+static int compile_mult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned);
+static int compile_dmult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned);
+static int compile_div(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned);
+static int compile_ddiv(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned);
+static int compile_logical(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int operation, int immediate);
+static int compile_slt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned, int immediate);
+static int compile_load(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, int is_unsigned);
+static int compile_load_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest);
+static int compile_loadx_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest);
+static int compile_load_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right);
+static int compile_load_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right);
+static int compile_store(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size);
+static int compile_store_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src);
+static int compile_storex_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src);
+static int compile_store_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right);
+static int compile_store_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right);
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static const UINT8 nvreg[] = { REG_NV0, REG_NV1, REG_NV2, REG_NV3, REG_NV4, REG_NV5, REG_NV6 };
+
+static const char *x86regname[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ oob_request_callback - request an out-of-
+ bounds callback for later
+-------------------------------------------------*/
+
+INLINE void oob_request_callback(drc_core *drc, UINT8 condition, oob_callback callback, const compiler_state *compiler, const opcode_desc *desc, void *param)
+{
+ oob_handler *oob = &mips3.drcdata->ooblist[mips3.drcdata->oobcount++];
+
+ /* fill in the next handler */
+ oob->callback = callback;
+ oob->desc = desc;
+ oob->compiler = *compiler;
+ oob->param = param;
+
+ /* emit an appropriate jump */
+ if (condition == COND_NO_JUMP)
+ {
+ oob->link.size = 0;
+ oob->link.target = drc->cache_top;
+ }
+ else if (condition == COND_NONE)
+ emit_jmp_near_link(DRCTOP, &oob->link); // jmp <target>
+ else
+ emit_jcc_near_link(DRCTOP, condition, &oob->link); // jcc <target>
+}
+
+
+/*-------------------------------------------------
+ compiler_state_reset - reset the compiler
+ state
+-------------------------------------------------*/
+
+INLINE void compiler_state_reset(compiler_state *compiler)
+{
+ memset(compiler, 0, sizeof(*compiler));
+ compiler_register_set_constant(compiler, 0, 0);
+}
+
+
+
+/***************************************************************************
+ CORE RECOMPILER SYSTEMS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mips3drc_init - initialize the drc-specific
+ state
+-------------------------------------------------*/
+
+static void mips3drc_init(void)
+{
+ drc_config drconfig;
+
+ /* fill in the config */
+ memset(&drconfig, 0, sizeof(drconfig));
+ drconfig.cache_base = mips3.cache;
+ drconfig.cache_size = CACHE_SIZE;
+ drconfig.max_instructions = (512 + 128) / 4;
+ drconfig.address_bits = 32;
+ drconfig.lsbs_to_ignore = 2;
+ drconfig.baseptr = &mips3.core->r[17];
+ drconfig.pcptr = (UINT32 *)&mips3.core->pc;
+ drconfig.cb_reset = drc_reset_callback;
+ drconfig.cb_recompile = drc_recompile_callback;
+ drconfig.cb_entrygen = drc_entrygen_callback;
+
+ /* initialize the compiler */
+ mips3.drc = drc_init(cpu_getactivecpu(), &drconfig);
+ mips3.drcoptions = MIPS3DRC_FASTEST_OPTIONS;
+
+ /* allocate our data out of the cache */
+ mips3.drcdata = drc_alloc(mips3.drc, sizeof(*mips3.drcdata) + 16);
+ mips3.drcdata = (mips3drc_data *)((((FPTR)mips3.drcdata + 15) >> 4) << 4);
+ memset(mips3.drcdata, 0, sizeof(*mips3.drcdata));
+
+ /* set up constants */
+ mips3.drcdata->abs64mask[0] = U64(0x7fffffffffffffff);
+ mips3.drcdata->abs32mask[0] = 0x7fffffff;
+
+ /* get pointers to C functions */
+ mips3.drcdata->activecpu_gettotalcycles64 = (x86code *)activecpu_gettotalcycles64;
+ mips3.drcdata->mips3com_update_cycle_counting = (x86code *)mips3com_update_cycle_counting;
+ mips3.drcdata->mips3com_tlbr = (x86code *)mips3com_tlbr;
+ mips3.drcdata->mips3com_tlbwi = (x86code *)mips3com_tlbwi;
+ mips3.drcdata->mips3com_tlbwr = (x86code *)mips3com_tlbwr;
+ mips3.drcdata->mips3com_tlbp = (x86code *)mips3com_tlbp;
+
+#if COMPARE_AGAINST_C
+ mips3.drcdata->execute_c_version = (x86code *)execute_c_version;
+#endif
+}
+
+
+/*-------------------------------------------------
+ mips3drc_exit - clean up the drc-specific
+ state
+-------------------------------------------------*/
+
+static void mips3drc_exit(void)
+{
+ printf("Final code size = %d\n", (int)(mips3.drc->cache_top - mips3.drc->cache_base));
+#if LOG_HOTSPOTS
+ /* print top hotspots */
+ {
+ int maxspot = 0;
+ int hotnum;
+ int count;
+
+ for (count = 0; count < 10; count++)
+ {
+ for (hotnum = 1; hotnum < mips3.drcdata->next_hotspot; hotnum++)
+ if (mips3.drcdata->hotspot[hotnum].count > mips3.drcdata->hotspot[maxspot].count)
+ maxspot = hotnum;
+ printf("%08X%08X hits: add_speedup(0x%08X, 0x%08X);\n",
+ (UINT32)(mips3.drcdata->hotspot[maxspot].count >> 32),
+ (UINT32)mips3.drcdata->hotspot[maxspot].count,
+ mips3.drcdata->hotspot[maxspot].pc,
+ mips3.drcdata->hotspot[maxspot].opcode);
+ mips3.drcdata->hotspot[maxspot].count = 0;
+ }
+ }
+#endif
+}
+
+
+
+/***************************************************************************
+ RECOMPILER CALLBACKS
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ drc_reset_callback
+------------------------------------------------------------------*/
+
+static void drc_reset_callback(drc_core *drc)
+{
+ if (LOG_CODE)
+ {
+ x86log_disasm_code_range(mips3.log, "entry_point:", (x86code *)drc->entry_point, drc->exit_point);
+ x86log_disasm_code_range(mips3.log, "exit_point:", drc->exit_point, drc->recompile);
+ x86log_disasm_code_range(mips3.log, "recompile:", drc->recompile, drc->dispatch);
+ x86log_disasm_code_range(mips3.log, "dispatch:", drc->dispatch, drc->flush);
+ x86log_disasm_code_range(mips3.log, "flush:", drc->flush, drc->cache_top);
+ }
+
+ mips3.drcdata->generate_interrupt_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_INTERRUPT);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_interrupt_exception:", mips3.drcdata->generate_interrupt_exception, drc->cache_top);
+
+ mips3.drcdata->generate_cop_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_BADCOP);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_cop_exception:", mips3.drcdata->generate_cop_exception, drc->cache_top);
+
+ mips3.drcdata->generate_overflow_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_OVERFLOW);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_overflow_exception:", mips3.drcdata->generate_overflow_exception, drc->cache_top);
+
+ mips3.drcdata->generate_invalidop_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_INVALIDOP);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_invalidop_exception:", mips3.drcdata->generate_invalidop_exception, drc->cache_top);
+
+ mips3.drcdata->generate_syscall_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_SYSCALL);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_syscall_exception:", mips3.drcdata->generate_syscall_exception, drc->cache_top);
+
+ mips3.drcdata->generate_break_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_BREAK);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_break_exception:", mips3.drcdata->generate_break_exception, drc->cache_top);
+
+ mips3.drcdata->generate_trap_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_TRAP);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_trap_exception:", mips3.drcdata->generate_trap_exception, drc->cache_top);
+
+ mips3.drcdata->generate_tlbload_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_TLBLOAD);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_tlbload_exception:", mips3.drcdata->generate_tlbload_exception, drc->cache_top);
+
+ mips3.drcdata->generate_tlbstore_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_TLBSTORE);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_tlbstore_exception:", mips3.drcdata->generate_tlbstore_exception, drc->cache_top);
+
+ mips3.drcdata->handle_pc_tlb_mismatch = drc->cache_top;
+ append_handle_pc_tlb_mismatch(drc);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "handle_pc_tlb_mismatch:", mips3.drcdata->handle_pc_tlb_mismatch, drc->cache_top);
+
+ mips3.drcdata->find_exception_handler = drc->cache_top;
+ append_find_exception_handler(drc);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "find_exception_handler:", mips3.drcdata->find_exception_handler, drc->cache_top);
+
+ mips3.drcdata->explode_ccr31 = drc->cache_top;
+ append_explode_ccr31(drc);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "explode_ccr31:", mips3.drcdata->explode_ccr31, drc->cache_top);
+
+ mips3.drcdata->recover_ccr31 = drc->cache_top;
+ append_recover_ccr31(drc);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "recover_ccr31:", mips3.drcdata->recover_ccr31, drc->cache_top);
+
+ generate_read_write_handlers(drc, &mips3.drcdata->general, "general", 0);
+ generate_read_write_handlers(drc, &mips3.drcdata->cached, "cached", ARW_CACHED);
+ generate_read_write_handlers(drc, &mips3.drcdata->uncached, "uncached", ARW_UNCACHED);
+}
+
+
+/*------------------------------------------------------------------
+ drc_recompile_callback
+------------------------------------------------------------------*/
+
+static void drc_recompile_callback(drc_core *drc)
+{
+ int compiled_last_sequence = FALSE;
+ const opcode_desc *seqhead, *seqlast;
+ const opcode_desc *desclist;
+ void *start = drc->cache_top;
+ int override = FALSE;
+ int oobnum;
+
+ (void)start;
+
+ /* begin the sequence */
+ drc_begin_sequence(drc, mips3.core->pc);
+ mips3.drcdata->oobcount = 0;
+
+ /* get a description of this sequence */
+ desclist = drcfe_describe_code(mips3.drcfe, mips3.core->pc);
+ if (LOG_CODE)
+ log_opcode_desc(mips3.log, desclist, 0);
+
+ /* loop until we get through all instruction sequences */
+ for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next)
+ {
+ const opcode_desc *curdesc;
+ compiler_state compiler;
+
+ /* determine the last instruction in this sequence */
+ for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next)
+ if (seqlast->flags & OPFLAG_END_SEQUENCE)
+ break;
+ assert(seqlast != NULL);
+
+ /* add this as an entry point */
+ if (drc_add_entry_point(drc, seqhead->pc, override) && !override)
+ {
+ /* if this is the first sequence, it is a recompile request; allow overrides */
+ if (seqhead == desclist)
+ {
+ override = TRUE;
+ drc_add_entry_point(drc, seqhead->pc, override);
+ }
+
+ /* otherwise, just emit a jump to existing code */
+ else
+ {
+ if (compiled_last_sequence)
+ drc_append_fixed_dispatcher(drc, seqhead->pc, TRUE);
+ compiled_last_sequence = FALSE;
+ continue;
+ }
+ }
+ compiled_last_sequence = TRUE;
+
+ /* add a code log entry */
+ if (LOG_CODE)
+ x86log_add_comment(mips3.log, drc->cache_top, "-------------------------");
+
+ /* validate this code block if we're not pointing into ROM */
+ /* note that we assume P1 still contains the PC */
+ if (memory_get_write_ptr(cpu_getactivecpu(), ADDRESS_SPACE_PROGRAM, seqhead->physpc) != NULL)
+ {
+ if (LOG_CODE)
+ x86log_add_comment(mips3.log, drc->cache_top, "[Validation for %08X]", seqhead->pc);
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)seqhead->opptr.v); // mov rax,seqhead->opptr
+ for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next)
+ {
+ emit_cmp_m32_imm(DRCTOP, MBD(REG_RAX, curdesc->opptr.b - seqhead->opptr.b), *curdesc->opptr.l);
+ // cmp [code],val
+ emit_jcc(DRCTOP, COND_NE, mips3.drc->recompile); // jne recompile
+ }
+ }
+
+ /* initialize the compiler state */
+ compiler_state_reset(&compiler);
+
+#if LOG_HOTSPOTS
+ /* add hotspot tracking */
+ {
+ int hotnum;
+
+ drc_register_code_at_cache_top(drc, seqhead->pc);
+
+ for (hotnum = 0; hotnum < mips3.drcdata->next_hotspot; hotnum++)
+ if (mips3.drcdata->hotspot[hotnum].pc == seqhead->pc && mips3.drcdata->hotspot[hotnum].opcode == *seqhead->opptr.l)
+ break;
+ if (hotnum == mips3.drcdata->next_hotspot)
+ {
+ assert(hotnum < ARRAY_LENGTH(mips3.drcdata->hotspot));
+ mips3.drcdata->hotspot[hotnum].pc = seqhead->pc;
+ mips3.drcdata->hotspot[hotnum].opcode = *seqhead->opptr.l;
+ mips3.drcdata->hotspot[hotnum].count = 0;
+ mips3.drcdata->next_hotspot++;
+ }
+ emit_add_m64_imm(DRCTOP, MDRC(&mips3.drcdata->hotspot[hotnum].count), 1);
+ }
+#endif
+
+ /* iterate over instructions in the sequence and compile them */
+ for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next)
+ compile_one(drc, &compiler, curdesc);
+
+ /* at the end of the sequence; update the PC in memory and check cycle counts */
+ if (!(seqlast->flags & (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_WILL_CAUSE_EXCEPTION)))
+ {
+ UINT32 nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4;
+ emit_update_cycles_pc_and_flush(drc, &compiler, NULL, nextpc);
+ }
+
+ /* if this is a likely branch, the fall through case needs to skip the next instruction */
+ if ((seqlast->flags & OPFLAG_IS_CONDITIONAL_BRANCH) && seqlast->skipslots > 0)
+ if (seqlast->next != NULL && seqlast->next->pc != seqlast->pc + 8)
+ {
+ compiler_register_flush_all(drc, &compiler);
+ drc_append_tentative_fixed_dispatcher(drc, seqlast->pc + 8, TRUE); // jmp <pc+8>
+ }
+
+ /* if we need a redispatch, do it now */
+ if (seqlast->flags & OPFLAG_REDISPATCH)
+ {
+ UINT32 nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4;
+ compiler_register_flush_all(drc, &compiler);
+ drc_append_tentative_fixed_dispatcher(drc, nextpc, TRUE); // jmp <nextpc>
+ }
+
+ /* if we need to return to the start, do it */
+ if (seqlast->flags & OPFLAG_RETURN_TO_START)
+ {
+ compiler_register_flush_all(drc, &compiler);
+ drc_append_tentative_fixed_dispatcher(drc, mips3.core->pc, FALSE); // jmp <startpc>
+ }
+ }
+
+ /* end the sequence */
+ drc_end_sequence(drc);
+
+ /* run the out-of-bounds handlers */
+ for (oobnum = 0; oobnum < mips3.drcdata->oobcount; oobnum++)
+ {
+ oob_handler *oob = &mips3.drcdata->ooblist[oobnum];
+ (*oob->callback)(drc, oob, oob->param);
+ }
+
+ /* log the generated code */
+ if (LOG_CODE)
+ {
+ char label[60];
+ sprintf(label, "Code @ %08X (%08X physical)", desclist->pc, desclist->physpc);
+ x86log_disasm_code_range(mips3.log, label, start, drc->cache_top);
+ }
+}
+
+
+/*------------------------------------------------------------------
+ drc_entrygen_callback
+------------------------------------------------------------------*/
+
+static void drc_entrygen_callback(drc_core *drc)
+{
+ append_check_interrupts(drc, NULL, NULL);
+}
+
+
+
+/***************************************************************************
+ RECOMPILER CORE
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ compile_one
+------------------------------------------------------------------*/
+
+static void compile_one(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
+{
+ int hotnum;
+
+ /* register this instruction */
+ if (!(desc->flags & OPFLAG_IN_DELAY_SLOT))
+ drc_register_code_at_cache_top(drc, desc->pc);
+
+ /* add an entry for the log */
+ if (LOG_CODE)
+ log_add_disasm_comment(mips3.log, drc->cache_top, desc->pc, *desc->opptr.l);
+
+ /* if we want a probe, add it here */
+ if (desc->pc == PROBE_ADDRESS)
+ {
+ emit_mov_m32_imm(DRCTOP, PCADDR, desc->pc); // mov [pc],desc->pc
+ compiler_register_flush_all(drc, compiler);
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)probe_printf);
+ emit_call_r64(DRCTOP, REG_RAX);
+ }
+
+ /* if we are debugging, call the debugger */
+ if (Machine->debug_mode || COMPARE_AGAINST_C)
+ {
+ emit_mov_m32_imm(DRCTOP, PCADDR, desc->pc); // mov [pc],desc->pc
+ if (COMPARE_AGAINST_C && !(desc->flags & OPFLAG_IN_DELAY_SLOT))
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->execute_c_version));
+ if (Machine->debug_mode)
+ drc_append_call_debugger(drc); // <call debugger>
+ }
+
+ /* validate our TLB entry at this PC; if we fail, we need to recompile */
+ if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000))
+ {
+ emit_cmp_m32_imm(DRCTOP, MDRC(&mips3.core->tlb_table[desc->pc >> 12]), mips3.core->tlb_table[desc->pc >> 12]);
+ // cmp tlb_table[pc>>12],<original value>
+ oob_request_callback(drc, COND_NE, oob_exception_cleanup, compiler, desc, mips3.drcdata->handle_pc_tlb_mismatch);
+ // jne handle_pc_tlb_mismatch
+ }
+
+ /* accumulate total cycles */
+ compiler->cycles += desc->cycles;
+
+ /* is this a hotspot? */
+ for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++)
+ if (desc->pc == mips3.hotspot[hotnum].pc && *desc->opptr.l == mips3.hotspot[hotnum].opcode)
+ {
+ compiler->cycles += mips3.hotspot[hotnum].cycles;
+ break;
+ }
+
+ /* if this is an invalid opcode, generate the exception now */
+ if (desc->flags & OPFLAG_INVALID_OPCODE)
+ oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_invalidop_exception);
+
+ /* otherwise, it's a regular instruction */
+ else
+ {
+ /* compile the instruction */
+ if (!compile_instruction(drc, compiler, desc))
+ fatalerror("Unimplemented op %08X (%02X,%02X)", *desc->opptr.l, *desc->opptr.l >> 26, *desc->opptr.l & 0x3f);
+
+ /* flush */
+ if (FLUSH_AFTER_EACH_INSTRUCTION)
+ compiler_register_flush_all(drc, compiler);
+ }
+}
+
+
+
+/***************************************************************************
+ OUT-OF-BOUNDS CODEGEN
+***************************************************************************/
+
+/*-------------------------------------------------
+ oob_exception_cleanup - out-of-bounds code
+ generator for cleaning up and generating an
+ exception with the EPC pointing to the
+ current instruction
+-------------------------------------------------*/
+
+static void oob_exception_cleanup(drc_core *drc, oob_handler *oob, void *param)
+{
+ /* if this is non-jumping error, emit a unique signature */
+ if (oob->link.size == 0)
+ {
+ /* align to an 8-byte boundary */
+ while (((UINT64)drc->cache_top & 7) != 0)
+ emit_int_3(DRCTOP);
+
+ /* logging */
+ if (LOG_CODE)
+ {
+ x86log_add_comment(mips3.log, drc->cache_top, "[Exception path for %08X]", oob->desc->pc);
+ x86log_mark_as_data(mips3.log, drc->cache_top, drc->cache_top + 15, 8);
+ }
+
+ /* output a pair of qwords */
+ emit_qword(DRCTOP, EXCEPTION_ADDRESS_COOKIE);
+ emit_qword(DRCTOP, (UINT64)oob->link.target);
+ }
+
+ /* otherwise, just resolve the link */
+ else
+ {
+ resolve_link(DRCTOP, &oob->link);
+ if (LOG_CODE)
+ x86log_add_comment(mips3.log, drc->cache_top, "[Exception path for %08X]", oob->desc->pc);
+ }
+
+ /* adjust for cycles */
+ if (oob->compiler.cycles != 0)
+ emit_sub_m32_imm(DRCTOP, ICOUNTADDR, oob->compiler.cycles); // sub [icount],cycles
+
+ /* update the PC with the instruction PC */
+ if (!(oob->desc->flags & OPFLAG_IN_DELAY_SLOT))
+ emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->pc); // mov p1,pc
+ else
+ emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->pc | 1); // mov p1,pc | 1
+
+ /* flush any dirty registers */
+ compiler_register_flush_all(drc, &oob->compiler); // <flush registers>
+
+ /* jump to the exception generator */
+ emit_jmp(DRCTOP, param); // jmp <generate exception>
+}
+
+
+/*-------------------------------------------------
+ oob_interrupt_cleanup - out-of-bounds code
+ generator for cleaning up and generating an
+ interrupt with the EPC pointing to the
+ following instruction
+-------------------------------------------------*/
+
+static void oob_interrupt_cleanup(drc_core *drc, oob_handler *oob, void *param)
+{
+ /* resolve the link */
+ resolve_link(DRCTOP, &oob->link);
+
+ /* add a code log entry */
+ if (LOG_CODE)
+ x86log_add_comment(mips3.log, drc->cache_top, "[Interrupt path for %08X]", oob->desc->pc);
+
+ /* adjust for cycles */
+ if (oob->compiler.cycles != 0)
+ emit_sub_m32_imm(DRCTOP, ICOUNTADDR, oob->compiler.cycles); // sub [icount],cycles
+
+ /* update the PC with the following instruction PC */
+ if (!(oob->desc->flags & OPFLAG_IN_DELAY_SLOT))
+ {
+ assert(!(oob->desc->flags & OPFLAG_IS_BRANCH));
+ emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->pc + 4); // mov p1,pc + 4
+ }
+ else
+ {
+ assert(oob->desc->branch != NULL);
+ if (oob->desc->branch->targetpc != BRANCH_TARGET_DYNAMIC)
+ emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->branch->targetpc); // mov p1,<targetpc>
+ else
+ emit_mov_r32_m32(DRCTOP, REG_P1, MBD(REG_RSP, SPOFFS_NEXTPC)); // mov p1,[rsp + nextpc]
+ }
+
+ /* flush any dirty registers */
+ compiler_register_flush_all(drc, &oob->compiler); // <flush registers>
+
+ /* jump to the exception generator */
+ emit_jmp(DRCTOP, param); // jmp <generate exception>
+}
+
+
+
+/***************************************************************************
+ REGISTER ALLOCATION ROUTINES
+***************************************************************************/
+
+/*-------------------------------------------------
+ compiler_register_set_constant - set a MIPS
+ register to a constant value
+-------------------------------------------------*/
+
+static void compiler_register_set_constant(compiler_state *compiler, UINT8 mipsreg, UINT64 constval)
+{
+ mipsreg_state reg = compiler->mipsregs[mipsreg];
+
+ assert((INT32)constval == (INT64)constval);
+
+ /* if the register was previously live, free it */
+ if (ISLIVE(reg))
+ {
+ assert(compiler->x86regs[X86REG(reg)] & X86REG_LIVE);
+ compiler->x86regs[X86REG(reg)] = 0;
+ }
+
+ /* set up the constant */
+ compiler->mipsregs[mipsreg] = MAKE_CONST(constval) | ((mipsreg == 0) ? 0 : MIPSREG_DIRTY);
+}
+
+
+/*-------------------------------------------------
+ compiler_register_allocate - allocate an x86
+ register to hold a MIPS register
+-------------------------------------------------*/
+
+static mipsreg_state compiler_register_allocate(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 mipsreg, UINT8 flags)
+{
+ UINT8 regindex, regnum = 0;
+ UINT64 livemask = 0;
+
+ /* register 0 is always constant */
+ if (mipsreg == 0)
+ return MAKE_CONST(0);
+
+ /* first see if we are already allocated */
+ if (ISLIVE(compiler->mipsregs[mipsreg]))
+ {
+ /* if we're not a source, make sure we are marked dirty */
+ if (flags & ALLOC_DIRTY)
+ compiler->mipsregs[mipsreg] |= MIPSREG_DIRTY;
+ return compiler->mipsregs[mipsreg];
+ }
+
+ /* if we just want a source register, return a constant directly */
+ if (flags == ALLOC_SRC && ISCONST(compiler->mipsregs[mipsreg]))
+ return compiler->mipsregs[mipsreg];
+
+ /* first look for a free entry */
+ for (regindex = 0; regindex < NUM_NVREG; regindex++)
+ {
+ regnum = nvreg[regindex];
+ if (!(compiler->x86regs[regnum] & X86REG_LIVE))
+ goto allocateit;
+ else
+ livemask |= (UINT64)1 << (compiler->x86regs[regnum] & X86REG_MIPSMASK);
+ }
+
+ /* can't have anything we need for this instruction, however */
+ livemask &= ~desc->gpr.used & ~desc->gpr.modified;
+ desc = desc->next;
+
+ /* next loop over the registers, figuring out who has the longest until being used */
+ while (desc != NULL && livemask != 0)
+ {
+ /* if this instruction uses the last remaining register, we have to pick from among those */
+ if ((livemask & ~desc->gpr.used) == 0)
+ break;
+ livemask &= ~desc->gpr.used;
+
+ /* if this instruction modifies any of the registers, we want those */
+ if ((livemask & desc->gpr.modified) != 0)
+ {
+ livemask &= desc->gpr.modified;
+ break;
+ }
+
+ /* advance to the next instruction; stop if we hit end-of-sequence */
+ if (desc->flags & OPFLAG_END_SEQUENCE)
+ break;
+ desc = desc->next;
+ }
+
+ /* pick the first one */
+ for (regindex = 0; regindex < NUM_NVREG; regindex++)
+ {
+ regnum = nvreg[regindex];
+ if (livemask & ((UINT64)1 << (compiler->x86regs[regnum] & X86REG_MIPSMASK)))
+ break;
+ }
+ assert(regindex != NUM_NVREG);
+
+ /* flush it */
+ compiler_register_flush(drc, compiler, compiler->x86regs[regnum] & X86REG_MIPSMASK, TRUE);
+
+allocateit:
+ /* load the contents if we are a source */
+ if (LOG_CODE)
+ x86log_add_comment(mips3.log, drc->cache_top, "allocate r%d (%s)", mipsreg, x86regname[regnum]);
+ if (flags & ALLOC_SRC)
+ {
+ mipsreg_state state = compiler->mipsregs[mipsreg];
+ if (ISCONST(state))
+ emit_mov_r64_imm(DRCTOP, regnum, CONSTVAL(state)); // mov <x86reg>,constant
+ else
+ emit_mov_r64_m64(DRCTOP, regnum, REGADDR(mipsreg)); // mov <x86reg>,[reg]
+ }
+
+ /* mark it allocated */
+ assert(!(compiler->x86regs[regnum] & X86REG_LIVE));
+ compiler->x86regs[regnum] = X86REG_LIVE | mipsreg;
+ compiler->mipsregs[mipsreg] = MIPSREG_LIVE | regnum | ((flags & ALLOC_DIRTY) ? MIPSREG_DIRTY : 0);
+ return compiler->mipsregs[mipsreg];
+}
+
+
+/*-------------------------------------------------
+ compiler_register_flush - flush and optionally
+ free a single MIPS register
+-------------------------------------------------*/
+
+static void compiler_register_flush(drc_core *drc, compiler_state *compiler, UINT8 mipsreg, int free)
+{
+ mipsreg_state reg = compiler->mipsregs[mipsreg];
+
+ assert(ISCONST(reg) || ISLIVE(reg));
+
+ /* flush the value if dirty */
+ if (ISDIRTY(reg))
+ {
+ if (LOG_CODE)
+ x86log_add_comment(mips3.log, drc->cache_top, "flush r%d (%s)", mipsreg, ISCONST(reg) ? "constant" : x86regname[X86REG(reg)]);
+
+ /* flush a constant value */
+ if (ISCONST(reg))
+ emit_mov_m64_imm(DRCTOP, REGADDR(mipsreg), CONSTVAL(reg)); // mov [reg],constant
+
+ /* flush a live value */
+ else if (ISLIVE(reg))
+ emit_mov_m64_r64(DRCTOP, REGADDR(mipsreg), X86REG(reg)); // mov [reg],<x86reg>
+ }
+
+ /* clear the dirty flag */
+ if (!free)
+ compiler->mipsregs[mipsreg] &= ~MIPSREG_DIRTY;
+ else
+ {
+ if (ISLIVE(reg))
+ compiler->x86regs[X86REG(reg)] = 0;
+ compiler->mipsregs[mipsreg] = 0;
+ }
+}
+
+
+/*-------------------------------------------------
+ compiler_register_flush_all - flush all dirty
+ registers
+-------------------------------------------------*/
+
+static void compiler_register_flush_all(drc_core *drc, compiler_state *compiler)
+{
+ int mipsreg;
+
+ /* flush all dirty registers */
+ for (mipsreg = 1; mipsreg < 35; mipsreg++)
+ if (ISDIRTY(compiler->mipsregs[mipsreg]))
+ compiler_register_flush(drc, compiler, mipsreg, FALSE);
+}
+
+
+
+/***************************************************************************
+ COMPILER CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ probe_printf - print the current CPU state
+ and return
+-------------------------------------------------*/
+
+static void probe_printf(void)
+{
+ printf(" PC=%08X r1=%08X%08X r2=%08X%08X r3=%08X%08X\n",
+ mips3.core->pc,
+ (UINT32)(mips3.core->r[1] >> 32), (UINT32)mips3.core->r[1],
+ (UINT32)(mips3.core->r[2] >> 32), (UINT32)mips3.core->r[2],
+ (UINT32)(mips3.core->r[3] >> 32), (UINT32)mips3.core->r[3]);
+ printf(" r4=%08X%08X r5=%08X%08X r6=%08X%08X r7=%08X%08X\n",
+ (UINT32)(mips3.core->r[4] >> 32), (UINT32)mips3.core->r[4],
+ (UINT32)(mips3.core->r[5] >> 32), (UINT32)mips3.core->r[5],
+ (UINT32)(mips3.core->r[6] >> 32), (UINT32)mips3.core->r[6],
+ (UINT32)(mips3.core->r[7] >> 32), (UINT32)mips3.core->r[7]);
+ printf(" r8=%08X%08X r9=%08X%08X r10=%08X%08X r11=%08X%08X\n",
+ (UINT32)(mips3.core->r[8] >> 32), (UINT32)mips3.core->r[8],
+ (UINT32)(mips3.core->r[9] >> 32), (UINT32)mips3.core->r[9],
+ (UINT32)(mips3.core->r[10] >> 32), (UINT32)mips3.core->r[10],
+ (UINT32)(mips3.core->r[11] >> 32), (UINT32)mips3.core->r[11]);
+ printf("r12=%08X%08X r13=%08X%08X r14=%08X%08X r15=%08X%08X\n",
+ (UINT32)(mips3.core->r[12] >> 32), (UINT32)mips3.core->r[12],
+ (UINT32)(mips3.core->r[13] >> 32), (UINT32)mips3.core->r[13],
+ (UINT32)(mips3.core->r[14] >> 32), (UINT32)mips3.core->r[14],
+ (UINT32)(mips3.core->r[15] >> 32), (UINT32)mips3.core->r[15]);
+ printf("r16=%08X%08X r17=%08X%08X r18=%08X%08X r19=%08X%08X\n",
+ (UINT32)(mips3.core->r[16] >> 32), (UINT32)mips3.core->r[16],
+ (UINT32)(mips3.core->r[17] >> 32), (UINT32)mips3.core->r[17],
+ (UINT32)(mips3.core->r[18] >> 32), (UINT32)mips3.core->r[18],
+ (UINT32)(mips3.core->r[19] >> 32), (UINT32)mips3.core->r[19]);
+ printf("r20=%08X%08X r21=%08X%08X r22=%08X%08X r23=%08X%08X\n",
+ (UINT32)(mips3.core->r[20] >> 32), (UINT32)mips3.core->r[20],
+ (UINT32)(mips3.core->r[21] >> 32), (UINT32)mips3.core->r[21],
+ (UINT32)(mips3.core->r[22] >> 32), (UINT32)mips3.core->r[22],
+ (UINT32)(mips3.core->r[23] >> 32), (UINT32)mips3.core->r[23]);
+ printf("r24=%08X%08X r25=%08X%08X r26=%08X%08X r27=%08X%08X\n",
+ (UINT32)(mips3.core->r[24] >> 32), (UINT32)mips3.core->r[24],
+ (UINT32)(mips3.core->r[25] >> 32), (UINT32)mips3.core->r[25],
+ (UINT32)(mips3.core->r[26] >> 32), (UINT32)mips3.core->r[26],
+ (UINT32)(mips3.core->r[27] >> 32), (UINT32)mips3.core->r[27]);
+ printf("r28=%08X%08X r29=%08X%08X r30=%08X%08X r31=%08X%08X\n",
+ (UINT32)(mips3.core->r[28] >> 32), (UINT32)mips3.core->r[28],
+ (UINT32)(mips3.core->r[29] >> 32), (UINT32)mips3.core->r[29],
+ (UINT32)(mips3.core->r[30] >> 32), (UINT32)mips3.core->r[30],
+ (UINT32)(mips3.core->r[31] >> 32), (UINT32)mips3.core->r[31]);
+ printf(" hi=%08X%08X lo=%08X%08X\n",
+ (UINT32)(mips3.core->r[REG_HI] >> 32), (UINT32)mips3.core->r[REG_HI],
+ (UINT32)(mips3.core->r[REG_LO] >> 32), (UINT32)mips3.core->r[REG_LO]);
+}
+
+
+/*-------------------------------------------------
+ exception_trap - log any exceptions that
+ aren't interrupts
+-------------------------------------------------*/
+
+static void exception_trap(void)
+{
+ if ((mips3.core->cpr[0][COP0_Cause] & 0xff) != 0)
+ printf("Exception: EPC=%08X Cause=%08X BadVAddr=%08X Jmp=%08X\n", mips3.core->cpr[0][COP0_EPC], mips3.core->cpr[0][COP0_Cause], mips3.core->cpr[0][COP0_BadVAddr], mips3.core->pc);
+}
+
+
+
+/***************************************************************************
+ COMMON ROUTINES
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ generate_read_write_handlers
+------------------------------------------------------------------*/
+
+static void generate_read_write_handlers(drc_core *drc, readwrite_handlers *handlers, const char *type, UINT8 flags)
+{
+ char buffer[100];
+
+ handlers->read_byte_signed = drc->cache_top;
+ append_readwrite_and_translate(drc, 1, ARW_READ | ARW_SIGNED | flags, offsetof(readwrite_handlers, read_byte_signed));
+ sprintf(buffer, "%s.read_byte_signed:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->read_byte_signed, drc->cache_top);
+
+ handlers->read_byte_unsigned = drc->cache_top;
+ append_readwrite_and_translate(drc, 1, ARW_READ | ARW_UNSIGNED | flags, offsetof(readwrite_handlers, read_byte_unsigned));
+ sprintf(buffer, "%s.read_byte_unsigned:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->read_byte_unsigned, drc->cache_top);
+
+ handlers->read_half_signed = drc->cache_top;
+ append_readwrite_and_translate(drc, 2, ARW_READ | ARW_SIGNED | flags, offsetof(readwrite_handlers, read_half_signed));
+ sprintf(buffer, "%s.read_half_signed:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->read_half_signed, drc->cache_top);
+
+ handlers->read_half_unsigned = drc->cache_top;
+ append_readwrite_and_translate(drc, 2, ARW_READ | ARW_UNSIGNED | flags, offsetof(readwrite_handlers, read_half_unsigned));
+ sprintf(buffer, "%s.read_half_unsigned:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->read_half_unsigned, drc->cache_top);
+
+ handlers->read_word_signed = drc->cache_top;
+ append_readwrite_and_translate(drc, 4, ARW_READ | ARW_SIGNED | flags, offsetof(readwrite_handlers, read_word_signed));
+ sprintf(buffer, "%s.read_word_signed:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->read_word_signed, drc->cache_top);
+
+ handlers->read_word_unsigned = drc->cache_top;
+ append_readwrite_and_translate(drc, 4, ARW_READ | ARW_UNSIGNED | flags, offsetof(readwrite_handlers, read_word_unsigned));
+ sprintf(buffer, "%s.read_word_unsigned:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->read_word_unsigned, drc->cache_top);
+
+ handlers->read_word_masked = drc->cache_top;
+ append_readwrite_and_translate(drc, 4, ARW_READ | ARW_UNSIGNED | ARW_MASKED | flags, offsetof(readwrite_handlers, read_word_masked));
+ sprintf(buffer, "%s.read_word_masked:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->read_word_masked, drc->cache_top);
+
+ handlers->read_double = drc->cache_top;
+ append_readwrite_and_translate(drc, 8, ARW_READ | flags, offsetof(readwrite_handlers, read_double));
+ sprintf(buffer, "%s.read_double:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->read_double, drc->cache_top);
+
+ handlers->read_double_masked = drc->cache_top;
+ append_readwrite_and_translate(drc, 8, ARW_READ | ARW_MASKED | flags, offsetof(readwrite_handlers, read_double_masked));
+ sprintf(buffer, "%s.read_double_masked:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->read_double_masked, drc->cache_top);
+
+ handlers->write_byte = drc->cache_top;
+ append_readwrite_and_translate(drc, 1, ARW_WRITE | flags, offsetof(readwrite_handlers, write_byte));
+ sprintf(buffer, "%s.write_byte:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->write_byte, drc->cache_top);
+
+ handlers->write_half = drc->cache_top;
+ append_readwrite_and_translate(drc, 2, ARW_WRITE | flags, offsetof(readwrite_handlers, write_half));
+ sprintf(buffer, "%s.write_half:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->write_half, drc->cache_top);
+
+ handlers->write_word = drc->cache_top;
+ append_readwrite_and_translate(drc, 4, ARW_WRITE | flags, offsetof(readwrite_handlers, write_word));
+ sprintf(buffer, "%s.write_word:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->write_word, drc->cache_top);
+
+ handlers->write_word_masked = drc->cache_top;
+ append_readwrite_and_translate(drc, 4, ARW_WRITE | ARW_MASKED | flags, offsetof(readwrite_handlers, write_word_masked));
+ sprintf(buffer, "%s.write_word_masked:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->write_word_masked, drc->cache_top);
+
+ handlers->write_double = drc->cache_top;
+ append_readwrite_and_translate(drc, 8, ARW_WRITE | flags, offsetof(readwrite_handlers, write_double));
+ sprintf(buffer, "%s.write_double:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->write_double, drc->cache_top);
+
+ handlers->write_double_masked = drc->cache_top;
+ append_readwrite_and_translate(drc, 8, ARW_WRITE | ARW_MASKED | flags, offsetof(readwrite_handlers, write_double_masked));
+ sprintf(buffer, "%s.write_double_masked:", type);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, buffer, handlers->write_double_masked, drc->cache_top);
+}
+
+
+/*------------------------------------------------------------------
+ append_generate_exception
+------------------------------------------------------------------*/
+
+static void append_generate_exception(drc_core *drc, UINT8 exception)
+{
+ UINT32 offset = (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) ? 0x00 : 0x180;
+ emit_link link1, link2;
+
+ if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)
+ {
+ /* assumes failed address is in P2 */
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_BadVAddr), REG_P2); // mov [BadVAddr],p2
+ emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_EntryHi), 0x000000ff); // and [EntryHi],0x000000ff
+ emit_and_r32_imm(DRCTOP, REG_P2, 0xffffe000); // and p2,0xffffe000
+ emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_EntryHi), REG_P2); // or [EntryHi],p2
+ emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Context), 0xff800000); // and [Context],0xff800000
+ emit_shr_r32_imm(DRCTOP, REG_P2, 9); // shr p2,9
+ emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_Context), REG_P2); // or [Context],p2
+ }
+
+ /* on entry, exception PC must be in REG_P1, and low bit set if in a delay slot */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[Cause]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~0x800000ff); // and eax,~0x800000ff
+ emit_test_r32_imm(DRCTOP, REG_P1, 1); // test p1,1
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_or_r32_imm(DRCTOP, REG_EAX, 0x80000000); // or eax,0x80000000
+ emit_sub_r32_imm(DRCTOP, REG_P1, 5); // sub p1,5
+
+ resolve_link(DRCTOP, &link1); // skip:
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_EPC), REG_P1); // mov [EPC],p1
+ if (exception)
+ emit_or_r32_imm(DRCTOP, REG_EAX, exception << 2); // or eax,exception << 2
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [Cause],eax
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // mov eax,[SR]
+ emit_or_r32_imm(DRCTOP, REG_EAX, SR_EXL); // or eax,SR_EXL
+ emit_test_r32_imm(DRCTOP, REG_EAX, SR_BEV); // test eax,SR_BEV
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [SR],eax
+ emit_mov_r32_imm(DRCTOP, REG_P1, 0xbfc00200 + offset); // mov p1,0xbfc00200+offset
+ emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // jnz skip2
+ emit_mov_r32_imm(DRCTOP, REG_P1, 0x80000000 + offset); // mov p1,0x80000000+offset
+
+ resolve_link(DRCTOP, &link2); // skip2:
+ if (PRINTF_EXCEPTIONS)
+ {
+ emit_mov_m32_r32(DRCTOP, PCADDR, REG_P1); // mov [PC],p1
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)exception_trap); // mov rax,exception_trap
+ emit_call_r64(DRCTOP, REG_RAX); // call rax
+ emit_mov_r32_m32(DRCTOP, REG_P1, PCADDR); // mov p1,[PC]
+ }
+ drc_append_dispatcher(drc); // dispatch
+}
+
+
+/*------------------------------------------------------------------
+ append_handle_pc_tlb_mismatch
+------------------------------------------------------------------*/
+
+static void append_handle_pc_tlb_mismatch(drc_core *drc)
+{
+#if 0
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_R15D); // mov eax,edi
+ emit_shr_r32_imm(DRCTOP, REG_EAX, 12); // shr eax,12
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MISD(REG_EAX, 4, &mips3.core->tlb_table)); // mov edx,tlb_table[eax*4]
+ emit_test_r32_imm(DRCTOP, REG_EDX, 2); // test edx,2
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_R15D); // mov eax,edi
+ emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_tlbload_exception); // jnz generate_tlbload_exception
+ emit_mov_m32bd_r32(DRCTOP, drc->pcptr, REG_R15D); // mov [pcptr],edi
+ emit_jmp(DRCTOP, drc->recompile); // call recompile
+#endif
+}
+
+
+/*------------------------------------------------------------------
+ append_find_exception_handler
+------------------------------------------------------------------*/
+
+static void append_find_exception_handler(drc_core *drc)
+{
+ x86code *loop;
+
+ emit_mov_r64_m64(DRCTOP, REG_RAX, MBD(REG_RSP, 0)); // mov rax,[rsp]
+ emit_mov_r64_imm(DRCTOP, REG_V5, EXCEPTION_ADDRESS_COOKIE); // mov v5,EXCEPTION_ADDRESS_COOKIE
+ emit_mov_r64_r64(DRCTOP, REG_V6, REG_RAX); // mov v6,rax
+ emit_and_r64_imm(DRCTOP, REG_RAX, ~7); // and rax,~7
+ emit_add_r64_imm(DRCTOP, REG_RSP, 8); // add rsp,8
+ emit_add_r64_imm(DRCTOP, REG_RAX, 8); // add rax,8
+ loop = drc->cache_top; // loop:
+ emit_cmp_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_V5); // cmp [rax],v5
+ emit_lea_r64_m64(DRCTOP, REG_RAX, MBD(REG_RAX, 8)); // lea rax,[rax+8]
+ emit_jcc(DRCTOP, COND_NE, loop); // jne loop
+ emit_cmp_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_V6); // cmp [rax],v6
+ emit_lea_r64_m64(DRCTOP, REG_RAX, MBD(REG_RAX, 8)); // lea rax,[rax+8]
+ emit_jcc(DRCTOP, COND_NE, loop); // jne loop
+ emit_jmp_r64(DRCTOP, REG_RAX); // jmp rax
+}
+
+
+/*------------------------------------------------------------------
+ append_direct_ram_read
+------------------------------------------------------------------*/
+
+static void append_direct_ram_read(drc_core *drc, int size, UINT8 flags, void *rambase, offs_t ramstart)
+{
+ void *adjbase = (UINT8 *)rambase - ramstart;
+ INT64 adjdisp = (UINT8 *)adjbase - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)adjdisp != adjdisp);
+
+ /* if we can't fit the delta to adjbase within an INT32, load RAX with the full address here */
+ if (raxrel)
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)adjbase);
+
+ /* fast RAM byte read */
+ if (size == 1)
+ {
+ /* adjust for endianness */
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_P1, 3); // xor p1,3
+
+ /* read rax-relative */
+ if (raxrel)
+ {
+ if (flags & ARW_SIGNED)
+ emit_movsx_r64_m8(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movsx rax,byte ptr [p1 + rax]
+ else
+ emit_movzx_r64_m8(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movzx rax,byte ptr [p1 + rax]
+ }
+
+ /* read drc-relative */
+ else
+ {
+ if (flags & ARW_SIGNED)
+ emit_movsx_r64_m8(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movsx rax,byte ptr [p1 + adjbase]
+ else
+ emit_movzx_r64_m8(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movzx rax,byte ptr [p1 + adjbase]
+ }
+ }
+
+ /* fast RAM halfword read */
+ else if (size == 2)
+ {
+ /* adjust for endianness */
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_P1, 2); // xor p1,2
+
+ /* read rax-relative */
+ if (raxrel)
+ {
+ if (flags & ARW_SIGNED)
+ emit_movsx_r64_m16(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movsx rax,word ptr [p1 + rax]
+ else
+ emit_movzx_r64_m16(DRCTOP, REG_EAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movzx rax,word ptr [p1 + rax]
+ }
+
+ /* read drc-relative */
+ else
+ {
+ if (flags & ARW_SIGNED)
+ emit_movsx_r64_m16(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movsx rax,word ptr [p1 + adjbase]
+ else
+ emit_movzx_r64_m16(DRCTOP, REG_EAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movzx rax,word ptr [p1 + adjbase]
+ }
+ }
+
+ /* fast RAM dword read */
+ else if (size == 4)
+ {
+ /* read rax-relative */
+ if (raxrel)
+ {
+ if (flags & ARW_SIGNED)
+ emit_movsxd_r64_m32(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movsxd rax,dword ptr [p1 + rax]
+ else
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBISD(REG_RAX, REG_P1, 1, 0)); // mov eax,word ptr [p1 + rax]
+ }
+
+ /* read drc-relative */
+ else
+ {
+ if (flags & ARW_SIGNED)
+ emit_movsxd_r64_m32(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movsxd rax,dword ptr [p1 + adjbase]
+ else
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MDRCISD(adjbase, REG_P1, 1, 0)); // mov eax,word ptr [p1 + adjbase]
+ }
+ }
+
+ /* fast RAM qword read */
+ else if (size == 8)
+ {
+ /* read rax-relative */
+ if (raxrel)
+ emit_mov_r64_m64(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // mov rax,[p1 + rax]
+
+ /* read drc-relative */
+ else
+ emit_mov_r64_m64(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // mov rax,[p1 + adjbase]
+
+ /* adjust for endianness */
+ if (mips3.core->bigendian)
+ emit_ror_r64_imm(DRCTOP, REG_RAX, 32); // ror rax,32
+ }
+}
+
+
+/*------------------------------------------------------------------
+ append_direct_ram_write
+------------------------------------------------------------------*/
+
+static void append_direct_ram_write(drc_core *drc, int size, UINT8 flags, void *rambase, offs_t ramstart)
+{
+ void *adjbase = (UINT8 *)rambase - ramstart;
+ INT64 adjdisp = (UINT8 *)adjbase - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)adjdisp != adjdisp);
+
+ /* if we can't fit the delta to adjbase within an INT32, load RAX with the full address here */
+ if (raxrel)
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)adjbase);
+
+ /* fast RAM byte write */
+ if (size == 1)
+ {
+ /* adjust for endianness */
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_P1, 3); // xor p1,3
+
+ /* write either rax-relative or drc-relative */
+ if (raxrel)
+ emit_mov_m8_r8(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2
+ else
+ emit_mov_m8_r8(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2
+ }
+
+ /* fast RAM halfword write */
+ else if (size == 2)
+ {
+ /* adjust for endianness */
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_P1, 2); // xor p1,2
+
+ /* write either rax-relative or drc-relative */
+ if (raxrel)
+ emit_mov_m16_r16(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2
+ else
+ emit_mov_m16_r16(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2
+ }
+
+ /* fast RAM dword write */
+ else if (size == 4)
+ {
+ /* unmasked */
+ if (!(flags & ARW_MASKED))
+ {
+ if (raxrel)
+ emit_mov_m32_r32(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2
+ else
+ emit_mov_m32_r32(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2
+ }
+
+ /* masked */
+ else
+ {
+ emit_mov_r32_r32(DRCTOP, REG_P4, REG_P3); // mov p4,p3
+ if (raxrel)
+ emit_and_r32_m32(DRCTOP, REG_P3, MBISD(REG_RAX, REG_P1, 1, 0)); // and p3,[p1 + rax]
+ else
+ emit_and_r32_m32(DRCTOP, REG_P3, MDRCISD(adjbase, REG_P1, 1, 0)); // and p3,[p1 + adjbase]
+ emit_not_r32(DRCTOP, REG_P4); // not p4
+ emit_and_r32_r32(DRCTOP, REG_P4, REG_P2); // and p4,p2
+ emit_or_r32_r32(DRCTOP, REG_P4, REG_P3); // or p4,p3
+ if (raxrel)
+ emit_mov_m32_r32(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P4); // mov [p1 + rax],p4
+ else
+ emit_mov_m32_r32(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P4); // mov [p1 + adjbase],p4
+ }
+ }
+
+ /* fast RAM qword write */
+ else if (size == 8)
+ {
+ /* adjust for endianness */
+ if (mips3.core->bigendian)
+ emit_ror_r64_imm(DRCTOP, REG_P2, 32); // ror p2,32
+
+ /* unmasked */
+ if (!(flags & ARW_MASKED))
+ {
+ if (raxrel)
+ emit_mov_m64_r64(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2
+ else
+ emit_mov_m64_r64(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2
+ }
+
+ /* masked */
+ else
+ {
+ if (mips3.core->bigendian)
+ emit_ror_r64_imm(DRCTOP, REG_P3, 32); // ror p3,32
+ emit_mov_r64_r64(DRCTOP, REG_P4, REG_P3); // mov p4,p3
+ if (raxrel)
+ emit_and_r64_m64(DRCTOP, REG_P3, MBISD(REG_RAX, REG_P1, 1, 0)); // and p3,[p1 + rax]
+ else
+ emit_and_r64_m64(DRCTOP, REG_P3, MDRCISD(adjbase, REG_P1, 1, 0)); // and p3,[p1 + adjbase]
+ emit_not_r64(DRCTOP, REG_P4); // not p4
+ emit_and_r64_r64(DRCTOP, REG_P4, REG_P2); // and p4,p2
+ emit_or_r64_r64(DRCTOP, REG_P4, REG_P3); // or p4,p3
+ if (raxrel)
+ emit_mov_m64_r64(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P4); // mov [p1 + rax],p4
+ else
+ emit_mov_m64_r64(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P4); // mov [p1 + adjbase],p4
+ }
+ }
+}
+
+
+/*------------------------------------------------------------------
+ append_readwrite_and_translate
+------------------------------------------------------------------*/
+
+static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags, UINT32 ptroffs)
+{
+ UINT32 base = ((flags & ARW_CACHED) ? 0x80000000 : (flags & ARW_UNCACHED) ? 0xa0000000 : 0);
+ emit_link page_fault = { 0 }, handle_kernel = { 0 }, wrong_handler = { 0 };
+ x86code *continue_mapped = NULL;
+ int ramnum;
+
+ /* if the base is 0, this is a general case which may be paged; perform the translation first */
+ /* the result of the translation produces the physical address inline in P1 */
+ /* if a page fault occurs, we have to keep an original copy of the address in EAX */
+ /* note that we use RAX and P4 as scratch registers */
+ if (base == 0)
+ {
+ emit_test_r32_r32(DRCTOP, REG_P1, REG_P1); // test p1,p1
+ emit_mov_r32_r32(DRCTOP, REG_P4, REG_P1); // mov p4,p1d
+ emit_jcc_near_link(DRCTOP, COND_S, &handle_kernel); // js handle_kernel
+ continue_mapped = drc->cache_top; // continue_mapped:
+ emit_mov_r32_r32(DRCTOP, REG_V5, REG_P1); // mov v5,p1
+ emit_shr_r32_imm(DRCTOP, REG_P1, 12); // shr p1,12
+ emit_mov_r32_m32(DRCTOP, REG_P1, MDRCISD(mips3.core->tlb_table, REG_P1, 4, 0)); // mov p1,tlb_table[p1*4]
+ emit_and_r32_imm(DRCTOP, REG_P4, 0xfff); // and p4,0xfff
+ emit_shr_r32_imm(DRCTOP, REG_P1, (flags & ARW_WRITE) ? 1 : 2); // shr p1,2/1 (read/write)
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBISD(REG_P4, REG_P1, (flags & ARW_WRITE) ? 2 : 4, 0));
+ // lea p1,[p4 + p1 * 4/2 (read/write)]
+ emit_jcc_near_link(DRCTOP, COND_C, &page_fault); // jc page_fault
+ }
+
+ /* if the base is non-zero, this is a cached/uncached direct-mapped case; no translation necessary */
+ /* just subtract the base from the address to get the physcial address */
+ else
+ emit_sub_r32_imm(DRCTOP, REG_P1, base); // sub p1,base
+
+ /* iterate over all fast RAM ranges looking for matches that can be handled directly */
+ for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++)
+ {
+ const fast_ram_info *raminfo = &mips3.fastram[ramnum];
+ if (!COMPARE_AGAINST_C && !Machine->debug_mode && raminfo->base != NULL && (!(flags & ARW_WRITE) || !raminfo->readonly))
+ {
+ emit_link notram1 = { 0 }, notram2 = { 0 };
+
+ /* if we have an end, check it first */
+ if (raminfo->end != 0xffffffff)
+ {
+ emit_cmp_r32_imm(DRCTOP, REG_P1, raminfo->end); // cmp p1,fastram_end
+ emit_jcc_short_link(DRCTOP, COND_A, &notram1); // ja notram1
+ }
+
+ /* if we have a non-0 start, check it next */
+ if (raminfo->start != 0x00000000)
+ {
+ emit_cmp_r32_imm(DRCTOP, REG_P1, raminfo->start); // cmp p1,fastram_start
+ emit_jcc_short_link(DRCTOP, COND_B, &notram2); // jb notram2
+ }
+
+ /* handle a fast RAM read */
+ if (!(flags & ARW_WRITE))
+ {
+ append_direct_ram_read(drc, size, flags, raminfo->base, raminfo->start); // <direct read>
+ emit_ret(DRCTOP); // ret
+ }
+
+ /* handle a fast RAM write */
+ else
+ {
+ append_direct_ram_write(drc, size, flags, raminfo->base, raminfo->start); // <direct write>
+ emit_ret(DRCTOP); // ret
+ }
+
+ /* resolve links that skipped over us */
+ if (raminfo->end != 0xffffffff)
+ resolve_link(DRCTOP, &notram1); // notram1:
+ if (raminfo->start != 0x00000000)
+ resolve_link(DRCTOP, &notram2); // notram2:
+ }
+ }
+
+ /* failed to find it in fast RAM; make sure we are within our expected range */
+ if (base != 0)
+ {
+ emit_cmp_r32_imm(DRCTOP, REG_P1, 0x20000000); // cmp p1,0x20000000
+ emit_jcc_short_link(DRCTOP, COND_AE, &wrong_handler); // jae wrong_handler
+ }
+
+ /* handle a write */
+ if (flags & ARW_WRITE)
+ {
+ if (size == 1)
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writebyte)); // jmp writebyte
+ else if (size == 2)
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writehalf)); // jmp writehalf
+ else if (size == 4)
+ {
+ if (!(flags & ARW_MASKED))
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writeword)); // jmp writeword
+ else
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writeword_masked)); // jmp writeword_masked
+ }
+ else
+ {
+ if (!(flags & ARW_MASKED))
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writedouble)); // jmp writedouble
+ else
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writedouble_masked)); // jmp writedouble_masked
+ }
+ }
+
+ /* handle a read */
+ else
+ {
+ if (size == 1)
+ {
+ emit_sub_r64_imm(DRCTOP, REG_RSP, 0x28); // sub rsp,0x28
+ emit_call_m64(DRCTOP, MDRC(&mips3.core->memory.readbyte)); // call readbyte
+ if (flags & ARW_SIGNED)
+ emit_movsx_r64_r8(DRCTOP, REG_RAX, REG_AL); // movsx rax,al
+ else
+ emit_movzx_r64_r8(DRCTOP, REG_RAX, REG_AL); // movzx rax,al
+ emit_add_r64_imm(DRCTOP, REG_RSP, 0x28); // add rsp,0x28
+ emit_ret(DRCTOP); // ret
+ }
+ else if (size == 2)
+ {
+ emit_sub_r64_imm(DRCTOP, REG_RSP, 0x28); // sub rsp,0x28
+ emit_call_m64(DRCTOP, MDRC(&mips3.core->memory.readhalf)); // call readhalf
+ if (flags & ARW_SIGNED)
+ emit_movsx_r64_r16(DRCTOP, REG_RAX, REG_AX); // movsx rax,ax
+ else
+ emit_movzx_r64_r16(DRCTOP, REG_RAX, REG_AX); // movzx rax,ax
+ emit_add_r64_imm(DRCTOP, REG_RSP, 0x28); // add rsp,0x28
+ emit_ret(DRCTOP); // ret
+ }
+ else if (size == 4)
+ {
+ if (!(flags & ARW_MASKED))
+ {
+ if (!(flags & ARW_SIGNED))
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readword)); // jmp readword
+ else
+ {
+ emit_sub_r64_imm(DRCTOP, REG_RSP, 0x28); // sub rsp,0x28
+ emit_call_m64(DRCTOP, MDRC(&mips3.core->memory.readword)); // call readword
+ emit_movsxd_r64_r32(DRCTOP, REG_RAX, REG_EAX); // movsxd rax,eax
+ emit_add_r64_imm(DRCTOP, REG_RSP, 0x28); // add rsp,0x28
+ emit_ret(DRCTOP); // ret
+ }
+ }
+ else
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readword_masked)); // jmp readword_masked
+ }
+ else
+ {
+ if (!(flags & ARW_MASKED))
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readdouble)); // jmp readdouble
+ else
+ emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readdouble_masked)); // jmp readdouble_masked
+ }
+ }
+
+ /* handle wrong handlers */
+ if (base == 0)
+ {
+ resolve_link(DRCTOP, &handle_kernel); // handle_kernel:
+ emit_cmp_r32_imm(DRCTOP, REG_P1, 0xc0000000); // cmp p1,0xc0000000
+ emit_jcc(DRCTOP, COND_AE, continue_mapped); // jae continue_mapped
+ emit_test_r32_imm(DRCTOP, REG_P1, 0x20000000); // test p1,0x20000000
+ emit_cmovcc_r64_m64(DRCTOP, COND_Z, REG_RAX, MDRCD(&mips3.drcdata->cached, ptroffs));
+ // mov rax,<cached version>
+ emit_cmovcc_r64_m64(DRCTOP, COND_NZ, REG_RAX, MDRCD(&mips3.drcdata->uncached, ptroffs));
+ // mov rax,<uncached version>
+ emit_mov_r64_m64(DRCTOP, REG_P4, MBD(REG_RSP, 0)); // mov p4,[rsp]
+ emit_push_r64(DRCTOP, REG_RAX); // push rax
+ emit_sub_r64_r64(DRCTOP, REG_RAX, REG_P4); // sub rax,p4
+ emit_mov_m32_r32(DRCTOP, MBD(REG_P4, -4), REG_EAX); // mov [p4-4],eax
+ emit_ret(DRCTOP); // ret
+ }
+ else
+ {
+ resolve_link(DRCTOP, &wrong_handler); // wrong_handler:
+ emit_mov_r64_m64(DRCTOP, REG_RAX, MDRCD(&mips3.drcdata->general, ptroffs));
+ // mov rax,<general version>
+ emit_mov_r64_m64(DRCTOP, REG_P4, MBD(REG_RSP, 0)); // mov p4,[rsp]
+ emit_push_r64(DRCTOP, REG_RAX); // push rax
+ emit_sub_r64_r64(DRCTOP, REG_RAX, REG_P4); // sub rax,p4
+ emit_mov_m32_r32(DRCTOP, MBD(REG_P4, -4), REG_EAX); // mov [p4-4],eax
+ emit_add_r32_imm(DRCTOP, REG_P1, base); // add p1,base
+ emit_ret(DRCTOP); // ret
+ }
+
+ /* handle page faults */
+ if (base == 0)
+ {
+ resolve_link(DRCTOP, &page_fault); // page_fault:
+ emit_mov_r32_r32(DRCTOP, REG_P2, REG_V5); // mov p2,v5
+ emit_jmp(DRCTOP, mips3.drcdata->find_exception_handler); // jmp find_exception_handler
+ }
+}
+
+
+/*------------------------------------------------------------------
+ append_explode_ccr31
+------------------------------------------------------------------*/
+
+static void append_explode_ccr31(drc_core *drc)
+{
+ emit_link link1;
+ int i;
+
+ /* new CCR31 value in EAX */
+ emit_test_r32_imm(DRCTOP, REG_EAX, 1 << 23); // test eax,1 << 23
+ emit_mov_m32_r32(DRCTOP, CCR1ADDR(31), REG_EAX); // mov ccr[31],eax
+ emit_setcc_m8(DRCTOP, COND_NZ, CF1ADDR(0)); // setnz fcc[0]
+ if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
+ for (i = 1; i <= 7; i++)
+ {
+ emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (24 + i)); // test eax,1 << (24+i)
+ emit_setcc_m8(DRCTOP, COND_NZ, CF1ADDR(i)); // setnz fcc[i]
+ }
+ emit_and_r32_imm(DRCTOP, REG_EAX, 3); // and eax,3
+ emit_test_r32_imm(DRCTOP, REG_EAX, 1); // test eax,1
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_xor_r32_imm(DRCTOP, REG_EAX, 2); // xor eax,2
+ resolve_link(DRCTOP, &link1); // skip:
+ drc_append_set_sse_rounding(drc, REG_EAX); // set_rounding(EAX)
+ emit_ret(DRCTOP); // ret
+}
+
+
+/*------------------------------------------------------------------
+ append_recover_ccr31
+------------------------------------------------------------------*/
+
+static void append_recover_ccr31(drc_core *drc)
+{
+ int i;
+
+ emit_movsxd_r64_m32(DRCTOP, REG_RAX, CCR1ADDR(31)); // movsxd rax,ccr1[rd]
+ emit_and_r64_imm(DRCTOP, REG_RAX, ~0xfe800000); // and rax,~0xfe800000
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR(0), 0); // cmp fcc[0],0
+ emit_setcc_r8(DRCTOP, COND_NZ, REG_DL); // setnz dl
+ emit_shl_r32_imm(DRCTOP, REG_EDX, 23); // shl edx,23
+ emit_or_r64_r64(DRCTOP, REG_RAX, REG_RDX); // or rax,rdx
+ if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
+ for (i = 1; i <= 7; i++)
+ {
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR(i), 0); // cmp fcc[i],0
+ emit_setcc_r8(DRCTOP, COND_NZ, REG_DL); // setnz dl
+ emit_shl_r32_imm(DRCTOP, REG_EDX, 24+i); // shl edx,24+i
+ emit_or_r64_r64(DRCTOP, REG_RAX, REG_RDX); // or rax,rdx
+ }
+ emit_ret(DRCTOP); // ret
+}
+
+
+/*------------------------------------------------------------------
+ append_check_interrupts
+------------------------------------------------------------------*/
+
+static void append_check_interrupts(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
+{
+ emit_link link1, link2;
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[Cause]
+ emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[Status]
+ emit_and_r32_imm(DRCTOP, REG_EAX, 0xfc00); // and eax,0xfc00
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_IE); // test [Status],SR_IE
+ emit_jcc_short_link(DRCTOP, COND_Z, &link2); // jz skip
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_EXL | SR_ERL); // test [Status],SR_EXL | SR_ERL
+ if (desc == NULL)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_P1, MDRC(drc->pcptr)); // mov p1,[pc]
+ emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_interrupt_exception); // jz generate_interrupt_exception
+ }
+ else
+ oob_request_callback(drc, COND_Z, oob_interrupt_cleanup, compiler, desc, mips3.drcdata->generate_interrupt_exception);
+ resolve_link(DRCTOP, &link1); // skip:
+ resolve_link(DRCTOP, &link2);
+}
+
+
+
+/***************************************************************************
+ RECOMPILATION HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_load_register_value - load a register
+ either as a constant or as a register
+-------------------------------------------------*/
+
+static void emit_load_register_value(drc_core *drc, compiler_state *compiler, UINT8 dstreg, mipsreg_state regstate)
+{
+ /* must be live or constant */
+ assert(ISCONST(regstate) || ISLIVE(regstate));
+
+ /* if the register is constant, do an immediate load */
+ if (ISCONST(regstate))
+ {
+ INT32 mipsval = CONSTVAL(regstate);
+ if (mipsval != 0)
+ emit_mov_r64_imm(DRCTOP, dstreg, mipsval);
+ else
+ emit_xor_r32_r32(DRCTOP, dstreg, dstreg);
+ }
+
+ /* otherwise, load from the allocated register, but only if different */
+ else
+ {
+ UINT8 srcreg = X86REG(regstate);
+ if (dstreg != srcreg)
+ emit_mov_r64_r64(DRCTOP, dstreg, srcreg);
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_set_constant_value - set a constant
+ value; if it is too large, allocate a
+ register and populate it
+-------------------------------------------------*/
+
+static void emit_set_constant_value(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 mipsreg, UINT64 constval)
+{
+ /* ignore reigster 0 destination */
+ if (mipsreg == 0)
+ return;
+
+ /* if we fit in 32-bits, just continue the constant charade */
+ if ((INT32)constval == (INT64)constval)
+ compiler_register_set_constant(compiler, mipsreg, constval);
+
+ /* otherwise, allocate a new register and move the result into it */
+ else
+ {
+ mipsreg_state resultreg = compiler_register_allocate(drc, compiler, desc, mipsreg, ALLOC_DST | ALLOC_DIRTY);
+ emit_mov_r64_imm(DRCTOP, X86REG(resultreg), constval); // mov <rt>,result
+ }
+}
+
+
+/*------------------------------------------------------------------
+ emit_flush_cycles_before_instruction
+------------------------------------------------------------------*/
+
+static void emit_flush_cycles_before_instruction(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT32 cycles_to_leave)
+{
+ /* if we have cycles, subtract them now */
+ if (compiler->cycles - cycles_to_leave != 0)
+ emit_sub_m32_imm(DRCTOP, ICOUNTADDR, compiler->cycles - cycles_to_leave); // sub [icount],cycles
+
+ /* clear out compiler counts */
+ compiler->cycles = cycles_to_leave;
+}
+
+
+/*------------------------------------------------------------------
+ emit_update_cycles_pc_and_flush
+------------------------------------------------------------------*/
+
+static void emit_update_cycles_pc_and_flush(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, offs_t destpc)
+{
+ /* if we have cycles, subtract them now */
+ emit_sub_m32_imm(DRCTOP, ICOUNTADDR, compiler->cycles); // sub [icount],cycles
+
+ /* clear out compiler counts */
+ compiler->cycles = 0;
+
+ /* if we have an opcode descriptor, make this an oob */
+ if (desc != NULL)
+ oob_request_callback(drc, COND_S, oob_interrupt_cleanup, compiler, desc, mips3.drc->exit_point);
+
+ /* otherwise, do it inline */
+ else
+ {
+ /* load the target PC into P1 */
+ if (destpc != BRANCH_TARGET_DYNAMIC)
+ emit_mov_r32_imm(DRCTOP, REG_P1, destpc); // mov p1,destpc
+ else
+ emit_mov_r32_m32(DRCTOP, REG_P1, MBD(REG_RSP, SPOFFS_NEXTPC)); // mov p1,[esp+nextpc]
+
+ /* flush any live registers */
+ compiler_register_flush_all(drc, compiler);
+
+ /* if we subtracted cycles and went negative, time to exit */
+ emit_jcc(DRCTOP, COND_S, mips3.drc->exit_point); // js exit_point
+ }
+}
+
+
+/*------------------------------------------------------------------
+ emit_delay_slot_and_branch
+------------------------------------------------------------------*/
+
+static void emit_delay_slot_and_branch(drc_core *drc, const compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg)
+{
+ compiler_state compiler_temp = *compiler;
+
+ /* set the link if needed */
+ if (linkreg != 0)
+ compiler_register_set_constant(&compiler_temp, linkreg, (INT32)(desc->pc + 8)); // <link> = pc + 8
+
+ /* compile the delay slot using temporary compiler state */
+ assert(desc->delay != NULL);
+ compile_one(drc, &compiler_temp, desc->delay); // <next instruction>
+
+ /* update the cycles and load the new PC in case we need to stop here */
+ emit_update_cycles_pc_and_flush(drc, &compiler_temp, NULL, desc->targetpc);
+
+ /* otherwise, append a dispatcher */
+ if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
+ drc_append_tentative_fixed_dispatcher(drc, desc->targetpc, FALSE); // <redispatch>
+ else
+ drc_append_dispatcher(drc); // <redispatch>
+}
+
+
+/*------------------------------------------------------------------
+ emit_fixed_byte_read
+------------------------------------------------------------------*/
+
+static int emit_fixed_byte_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, int is_unsigned, offs_t address)
+{
+ void *fastram = fastram_ptr(address, 1, FALSE);
+
+ /* if we can't do fast RAM, we need to make the call */
+ if (fastram == NULL)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P1, address); // mov p1,address
+ if (is_unsigned)
+ emit_call(DRCTOP, mips3.drcdata->general.read_byte_unsigned); // call read_byte_unsigned
+ else
+ emit_call(DRCTOP, mips3.drcdata->general.read_byte_signed); // call read_byte_signed
+
+ /* handle exceptions */
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
+ if (destreg != REG_RAX)
+ emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax
+ }
+
+ /* if we can do fastram, emit the right form */
+ else
+ {
+ INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)fastdisp != fastdisp);
+
+ /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
+ if (raxrel)
+ {
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ if (is_unsigned)
+ emit_movzx_r64_m8(DRCTOP, destreg, MBD(REG_RAX, 0)); // movzx destreg,byte ptr [rax]
+ else
+ emit_movsx_r64_m8(DRCTOP, destreg, MBD(REG_RAX, 0)); // movsx destreg,byte ptr [rax]
+ }
+
+ /* read drc-relative */
+ else
+ {
+ if (is_unsigned)
+ emit_movzx_r64_m8(DRCTOP, destreg, MDRC(fastram)); // movzx destreg,byte ptr [p1 + adjbase]
+ else
+ emit_movsx_r64_m8(DRCTOP, destreg, MDRC(fastram)); // movsx destreg,byte ptr [p1 + adjbase]
+ }
+ }
+ return (fastram != NULL);
+}
+
+
+/*------------------------------------------------------------------
+ emit_fixed_half_read
+------------------------------------------------------------------*/
+
+static int emit_fixed_half_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, int is_unsigned, offs_t address)
+{
+ void *fastram = fastram_ptr(address & ~1, 2, FALSE);
+
+ /* if we can't do fast RAM, we need to make the call */
+ if (fastram == NULL)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P1, address & ~1); // mov p1,address & ~1
+ if (is_unsigned)
+ emit_call(DRCTOP, mips3.drcdata->general.read_half_unsigned); // call read_half_unsigned
+ else
+ emit_call(DRCTOP, mips3.drcdata->general.read_half_signed); // call read_half_signed
+
+ /* handle exceptions */
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
+ if (destreg != REG_RAX)
+ emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax
+ }
+
+ /* if we can do fastram, emit the right form */
+ else
+ {
+ INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)fastdisp != fastdisp);
+
+ /* read rax-relative */
+ if (raxrel)
+ {
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ if (is_unsigned)
+ emit_movzx_r64_m16(DRCTOP, destreg, MBD(REG_RAX, 0)); // movzx destreg,word ptr [rax]
+ else
+ emit_movsx_r64_m16(DRCTOP, destreg, MBD(REG_RAX, 0)); // movsx destreg,word ptr [rax]
+ }
+
+ /* read drc-relative */
+ else
+ {
+ if (is_unsigned)
+ emit_movzx_r64_m16(DRCTOP, destreg, MDRC(fastram)); // movzx destreg,word ptr [p1 + adjbase]
+ else
+ emit_movsx_r64_m16(DRCTOP, destreg, MDRC(fastram)); // movsx destreg,word ptr [p1 + adjbase]
+ }
+ }
+ return (fastram != NULL);
+}
+
+
+/*------------------------------------------------------------------
+ emit_fixed_word_read
+------------------------------------------------------------------*/
+
+static int emit_fixed_word_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, int is_unsigned, offs_t address, UINT32 mask)
+{
+ void *fastram = fastram_ptr(address & ~3, 4, FALSE);
+
+ /* if we can't do fast RAM, we need to make the call */
+ if (fastram == NULL)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P1, address & ~3); // mov p1,address & ~3
+ if (mask != 0)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P2, (INT32)mask); // mov p2,mask
+ emit_call(DRCTOP, mips3.drcdata->general.read_word_masked); // call read_word_masked
+ }
+ else if (is_unsigned)
+ emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call read_word_unsigned
+ else
+ emit_call(DRCTOP, mips3.drcdata->general.read_word_signed); // call read_word_signed
+
+ /* handle exceptions */
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
+ if (destreg != REG_RAX)
+ emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax
+ }
+
+ /* if we can do fastram, emit the right form */
+ else
+ {
+ INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)fastdisp != fastdisp);
+
+ /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
+ if (raxrel)
+ {
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ if (is_unsigned)
+ emit_mov_r32_m32(DRCTOP, destreg, MBD(REG_RAX, 0)); // mov destreg,word ptr [rax]
+ else
+ emit_movsxd_r64_m32(DRCTOP, destreg, MBD(REG_RAX, 0)); // movsxd destreg,dword ptr [rax]
+ }
+
+ /* read drc-relative */
+ else
+ {
+ if (is_unsigned)
+ emit_mov_r32_m32(DRCTOP, destreg, MDRC(fastram)); // mov destreg,word ptr [p1 + adjbase]
+ else
+ emit_movsxd_r64_m32(DRCTOP, destreg, MDRC(fastram)); // movsxd destreg,dword ptr [p1 + adjbase]
+ }
+ }
+ return (fastram != NULL);
+}
+
+
+/*------------------------------------------------------------------
+ emit_fixed_double_read
+------------------------------------------------------------------*/
+
+static int emit_fixed_double_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, offs_t address, UINT64 mask)
+{
+ void *fastram = fastram_ptr(address & ~7, 8, FALSE);
+
+ /* if we can't do fast RAM, we need to make the call */
+ if (fastram == NULL)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P1, address & ~7); // mov p1,address & ~7
+ if (mask != 0)
+ {
+ emit_mov_r64_imm(DRCTOP, REG_P2, mask); // mov p2,mask
+ emit_call(DRCTOP, mips3.drcdata->general.read_double_masked); // call read_double_masked
+ }
+ else
+ emit_call(DRCTOP, mips3.drcdata->general.read_double); // call read_double
+
+ /* handle exceptions */
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
+ if (destreg != REG_RAX)
+ emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax
+ }
+
+ /* if we can do fastram, emit the right form */
+ else
+ {
+ INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)fastdisp != fastdisp);
+
+ /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
+ if (raxrel)
+ {
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ emit_mov_r64_m64(DRCTOP, destreg, MBD(REG_RAX, 0)); // mov destreg,[rax]
+ }
+
+ /* read drc-relative */
+ else
+ emit_mov_r64_m64(DRCTOP, destreg, MDRC(fastram)); // mov destreg,[p1 + adjbase]
+
+ /* adjust for endianness */
+ if (mips3.core->bigendian)
+ emit_ror_r64_imm(DRCTOP, destreg, 32); // ror destreg,32
+ }
+ return (fastram != NULL);
+}
+
+
+/*------------------------------------------------------------------
+ emit_fixed_byte_write
+------------------------------------------------------------------*/
+
+static int emit_fixed_byte_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address)
+{
+ void *fastram = fastram_ptr(address, 1, TRUE);
+
+ assert(ISCONST(srcreg) || X86REG(srcreg != REG_P1));
+
+ /* if we can't do fast RAM, we need to make the call */
+ if (fastram == NULL)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P1, address); // mov p1,address
+ if (ISCONST(srcreg))
+ emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,<srcreg>
+ else if (X86REG(srcreg) != REG_P2)
+ emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,<srcreg>
+ emit_call(DRCTOP, mips3.drcdata->general.write_byte); // call write_byte
+
+ /* handle exceptions */
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
+ }
+
+ /* if we can do fastram, emit the right form */
+ else
+ {
+ INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)fastdisp != fastdisp);
+
+ /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
+ if (raxrel)
+ {
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ if (ISCONST(srcreg))
+ emit_mov_m8_imm(DRCTOP, MBD(REG_RAX, 0), CONSTVAL(srcreg)); // mov [rax],constval
+ else
+ emit_mov_m8_r8(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],<srcreg>
+ }
+
+ /* write drc-relative */
+ else
+ {
+ if (ISCONST(srcreg))
+ emit_mov_m8_imm(DRCTOP, MDRC(fastram), CONSTVAL(srcreg)); // mov [fastram],constval
+ else
+ emit_mov_m8_r8(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg
+ }
+ }
+ return (fastram != NULL);
+}
+
+
+/*------------------------------------------------------------------
+ emit_fixed_half_write
+------------------------------------------------------------------*/
+
+static int emit_fixed_half_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address)
+{
+ void *fastram = fastram_ptr(address & ~1, 2, TRUE);
+
+ assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P1);
+
+ /* if we can't do fast RAM, we need to make the call */
+ if (fastram == NULL)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P1, address & ~1); // mov p1,address & ~1
+ if (ISCONST(srcreg))
+ emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,constval
+ else if (X86REG(srcreg) != REG_P2)
+ emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
+ emit_call(DRCTOP, mips3.drcdata->general.write_half); // call write_half
+
+ /* handle exceptions */
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
+ }
+
+ /* if we can do fastram, emit the right form */
+ else
+ {
+ INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)fastdisp != fastdisp);
+
+ /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
+ if (raxrel)
+ {
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ if (ISCONST(srcreg))
+ emit_mov_m16_imm(DRCTOP, MBD(REG_RAX, 0), CONSTVAL(srcreg)); // mov [rax],constval
+ else
+ emit_mov_m16_r16(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],srcreg
+ }
+
+ /* write drc-relative */
+ else
+ {
+ if (ISCONST(srcreg))
+ emit_mov_m16_imm(DRCTOP, MDRC(fastram), CONSTVAL(srcreg)); // mov [fastram],constval
+ else
+ emit_mov_m16_r16(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg
+ }
+ }
+ return (fastram != NULL);
+}
+
+
+/*------------------------------------------------------------------
+ emit_fixed_word_write
+------------------------------------------------------------------*/
+
+static int emit_fixed_word_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address, UINT32 mask)
+{
+ void *fastram = fastram_ptr(address & ~3, 4, TRUE);
+
+ assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P1);
+ assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P3);
+
+ /* if we can't do fast RAM, we need to make the call */
+ if (fastram == NULL)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P1, address & ~3); // mov p1,address & ~3
+ if (ISCONST(srcreg))
+ emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,constval
+ else if (X86REG(srcreg) != REG_P2)
+ emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
+ if (mask == 0)
+ emit_call(DRCTOP, mips3.drcdata->general.write_word); // call write_word
+ else
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P3, mask); // mov p3,mask
+ emit_call(DRCTOP, mips3.drcdata->general.write_word_masked); // call write_word_masked
+ }
+
+ /* handle exceptions */
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
+ }
+
+ /* if we can do fastram, emit the right form */
+ else
+ {
+ INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)fastdisp != fastdisp);
+
+ /* non-masked case */
+ if (mask == 0)
+ {
+ /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
+ if (raxrel)
+ {
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ if (ISCONST(srcreg))
+ emit_mov_m32_imm(DRCTOP, MBD(REG_RAX, 0), CONSTVAL(srcreg)); // mov [rax],constval
+ else
+ emit_mov_m32_r32(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],srcreg
+ }
+
+ /* write drc-relative */
+ else
+ {
+ if (ISCONST(srcreg))
+ emit_mov_m32_imm(DRCTOP, MDRC(fastram), CONSTVAL(srcreg)); // mov [fastram],constval
+ else
+ emit_mov_m32_r32(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg
+ }
+ }
+
+ /* masked case */
+ else
+ {
+ if (raxrel)
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ else
+ emit_lea_r64_m64(DRCTOP, REG_RAX, MDRC(fastram)); // lea rax,[fastram]
+
+ /* always write rax-relative */
+ if (ISCONST(srcreg))
+ {
+ emit_mov_r32_m32(DRCTOP, REG_P2, MBD(REG_RAX, 0)); // mov p2,[rax]
+ emit_and_r32_imm(DRCTOP, REG_P2, mask); // and p2,mask
+ emit_or_r32_imm(DRCTOP, REG_P2, CONSTVAL(srcreg) & ~mask); // or p2,constval & ~mask
+ emit_mov_m32_r32(DRCTOP, MBD(REG_RAX, 0), REG_P2); // mov [rax],p2
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_P3, MBD(REG_RAX, 0)); // mov p3,[rax]
+ if (X86REG(srcreg) != REG_P2)
+ emit_mov_r32_r32(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
+ emit_and_r32_imm(DRCTOP, REG_P3, mask); // and p3,mask
+ emit_and_r32_imm(DRCTOP, REG_P2, ~mask); // and p2,~mask
+ emit_or_r32_r32(DRCTOP, REG_P3, REG_P2); // or p3,p2
+ emit_mov_m32_r32(DRCTOP, MBD(REG_RAX, 0), REG_P3); // mov [rax],p3
+ }
+ }
+ }
+ return (fastram != NULL);
+}
+
+
+/*------------------------------------------------------------------
+ emit_fixed_double_write
+------------------------------------------------------------------*/
+
+static int emit_fixed_double_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address, UINT64 mask)
+{
+ void *fastram = fastram_ptr(address & ~7, 8, TRUE);
+
+ assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P1);
+ assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P3);
+ assert((INT32)CONSTVAL(srcreg) == (INT64)CONSTVAL(srcreg));
+
+ /* if we can't do fast RAM, we need to make the call */
+ if (fastram == NULL)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_P1, address & ~7); // mov p1,address & ~7
+ if (ISCONST(srcreg))
+ emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,constval
+ else if (X86REG(srcreg) != REG_P2)
+ emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
+ if (mask == 0)
+ emit_call(DRCTOP, mips3.drcdata->general.write_double); // call write_double
+ else
+ {
+ emit_mov_r64_imm(DRCTOP, REG_P3, mask); // mov p3,mask
+ emit_call(DRCTOP, mips3.drcdata->general.write_double_masked); // call write_double_masked
+ }
+
+ /* handle exceptions */
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
+ }
+
+ /* if we can do fastram, emit the right form */
+ else
+ {
+ INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
+ int raxrel = ((INT32)fastdisp != fastdisp);
+ INT64 constval = CONSTVAL(srcreg);
+
+ /* adjust values for endianness */
+ if (mips3.core->bigendian)
+ {
+ if (ISCONST(srcreg))
+ constval = (constval << 32) | (constval >> 32);
+ else
+ {
+ emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
+ emit_ror_r64_imm(DRCTOP, REG_P2, 32); // ror p2,32
+ srcreg = REG_P2;
+ }
+ mask = (mask << 32) | (mask >> 32);
+ }
+
+ /* non-masked case */
+ if (mask == 0)
+ {
+ /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
+ if (raxrel)
+ {
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ if (ISCONST(srcreg))
+ emit_mov_m64_imm(DRCTOP, MBD(REG_RAX, 0), constval); // mov [rax],constval
+ else
+ emit_mov_m64_r64(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],srcreg
+ }
+
+ /* write drc-relative */
+ else
+ {
+ if (ISCONST(srcreg))
+ emit_mov_m64_imm(DRCTOP, MDRC(fastram), constval); // mov [fastram],constval
+ else
+ emit_mov_m64_r64(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg
+ }
+ }
+
+ /* masked case */
+ else
+ {
+ if (raxrel)
+ emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
+ else
+ emit_lea_r64_m64(DRCTOP, REG_RAX, MDRC(fastram)); // lea rax,[fastram]
+ emit_mov_r64_imm(DRCTOP, REG_P4, mask); // mov p4,mask
+
+ /* always write rax-relative */
+ if (ISCONST(srcreg))
+ {
+ emit_and_r64_m64(DRCTOP, REG_P4, MBD(REG_RAX, 0)); // and p4,[rax]
+ emit_mov_r64_imm(DRCTOP, REG_P3, constval & ~mask); // mov p3,constval & ~mask
+ emit_or_r64_r64(DRCTOP, REG_P4, REG_P3); // or p4,p3
+ emit_mov_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_P4); // mov [rax],p4
+ }
+ else
+ {
+ emit_mov_r64_m64(DRCTOP, REG_P3, MBD(REG_RAX, 0)); // mov p3,[rax]
+ if (X86REG(srcreg) != REG_P2)
+ emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
+ emit_and_r64_r64(DRCTOP, REG_P3, REG_P4); // and p3,p4
+ emit_not_r64(DRCTOP, REG_P4); // not p4
+ emit_and_r64_r64(DRCTOP, REG_P2, REG_P4); // and p2,p4
+ emit_or_r64_r64(DRCTOP, REG_P3, REG_P2); // or p3,p2
+ emit_mov_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_P3); // mov [rax],p3
+ }
+ }
+ }
+ return (fastram != NULL);
+}
+
+
+
+/***************************************************************************
+ CORE RECOMPILATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ compile_instruction - master switch statement
+ for compiling a given opcode
+-------------------------------------------------*/
+
+static int compile_instruction(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = op >> 26;
+
+ switch (opswitch)
+ {
+ /* ----- sub-groups ----- */
+
+ case 0x00: /* SPECIAL */
+ return compile_special(drc, compiler, desc);
+
+ case 0x01: /* REGIMM */
+ return compile_regimm(drc, compiler, desc);
+
+ case 0x1c: /* IDT-specific */
+ return compile_idt(drc, compiler, desc);
+
+
+ /* ----- jumps and branches ----- */
+
+ case 0x02: /* J */
+ case 0x03: /* JAL */
+ emit_delay_slot_and_branch(drc, compiler, desc, (opswitch == 0x02) ? 0 : 31); // <next instruction + redispatch>
+ return TRUE;
+
+ case 0x04: /* BEQ */
+ case 0x14: /* BEQL */
+ case 0x05: /* BNE */
+ case 0x15: /* BNEL */
+ return compile_branchcc(drc, compiler, desc, (opswitch & 1) ? COND_NE : COND_E);
+
+ case 0x06: /* BLEZ */
+ case 0x16: /* BLEZL */
+ case 0x07: /* BGTZ */
+ case 0x17: /* BGTZL */
+ return compile_branchcz(drc, compiler, desc, (opswitch & 1) ? COND_G : COND_LE, FALSE);
+
+
+ /* ----- immediate arithmetic ----- */
+
+ case 0x0f: /* LUI */
+ if (RTREG != 0)
+ emit_set_constant_value(drc, compiler, desc, RTREG, SIMMVAL << 16);
+ return TRUE;
+
+ case 0x08: /* ADDI */
+ case 0x09: /* ADDIU */
+ return compile_add(drc, compiler, desc, opswitch & 1, TRUE);
+
+ case 0x18: /* DADDI */
+ case 0x19: /* DADDIU */
+ return compile_dadd(drc, compiler, desc, opswitch & 1, TRUE);
+
+ case 0x0c: /* ANDI */
+ case 0x0d: /* ORI */
+ case 0x0e: /* XORI */
+ return compile_logical(drc, compiler, desc, opswitch & 3, TRUE);
+
+ case 0x0a: /* SLTI */
+ case 0x0b: /* SLTIU */
+ return compile_slt(drc, compiler, desc, opswitch & 1, TRUE);
+
+
+ /* ----- memory load operations ----- */
+
+ case 0x20: /* LB */
+ case 0x21: /* LH */
+ case 0x23: /* LW */
+ case 0x24: /* LBU */
+ case 0x25: /* LHU */
+ case 0x27: /* LWU */
+ return compile_load(drc, compiler, desc, (opswitch & 3) + 1, opswitch & 4);
+
+ case 0x37: /* LD */
+ return compile_load(drc, compiler, desc, 8, FALSE);
+
+ case 0x31: /* LWC1 */
+ return compile_load_cop(drc, compiler, desc, 4, FPR32(RTREG));
+
+ case 0x35: /* LDC1 */
+ return compile_load_cop(drc, compiler, desc, 8, FPR64(RTREG));
+
+ case 0x32: /* LWC2 */
+ case 0x36: /* LDC2 */
+ return compile_load_cop(drc, compiler, desc, (opswitch & 4) ? 8 : 4, &mips3.core->cpr[2][RTREG]);
+
+ case 0x1a: /* LDL */
+ case 0x1b: /* LDR */
+ return compile_load_double_partial(drc, compiler, desc, opswitch & 1);
+
+ case 0x22: /* LWL */
+ case 0x26: /* LWR */
+ return compile_load_word_partial(drc, compiler, desc, opswitch & 4);
+
+
+ /* ----- memory store operations ----- */
+
+ case 0x28: /* SB */
+ case 0x29: /* SH */
+ case 0x2b: /* SW */
+ return compile_store(drc, compiler, desc, (opswitch & 3) + 1);
+
+ case 0x3f: /* SD */
+ return compile_store(drc, compiler, desc, 8);
+
+ case 0x39: /* SWC1 */
+ return compile_store_cop(drc, compiler, desc, 4, FPR32(RTREG));
+
+ case 0x3d: /* SDC1 */
+ return compile_store_cop(drc, compiler, desc, 8, FPR64(RTREG));
+
+ case 0x3a: /* SWC2 */
+ return compile_store_cop(drc, compiler, desc, (opswitch & 4) ? 8 : 4, &mips3.core->cpr[2][RTREG]);
+
+ case 0x2a: /* SWL */
+ case 0x2e: /* SWR */
+ return compile_store_word_partial(drc, compiler, desc, opswitch & 4);
+
+ case 0x2c: /* SDL */
+ case 0x2d: /* SDR */
+ return compile_store_double_partial(drc, compiler, desc, opswitch & 1);
+
+
+ /* ----- effective no-ops ----- */
+
+ case 0x2f: /* CACHE */
+ case 0x33: /* PREF */
+ return TRUE;
+
+
+ /* ----- coprocessor instructions ----- */
+
+ case 0x10: /* COP0 */
+ return compile_cop0(drc, compiler, desc);
+
+ case 0x11: /* COP1 */
+ return compile_cop1(drc, compiler, desc);
+
+ case 0x13: /* COP1X - R5000 */
+ return compile_cop1x(drc, compiler, desc);
+
+ case 0x12: /* COP2 */
+ oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_invalidop_exception);
+ // jmp generate_invalidop_exception
+ return TRUE;
+
+
+ /* ----- unimplemented/illegal instructions ----- */
+
+// case 0x30: /* LL */ logerror("mips3 Unhandled op: LL\n"); break;
+// case 0x34: /* LLD */ logerror("mips3 Unhandled op: LLD\n"); break;
+// case 0x38: /* SC */ logerror("mips3 Unhandled op: SC\n"); break;
+// case 0x3c: /* SCD */ logerror("mips3 Unhandled op: SCD\n"); break;
+// case 0x3b: /* SWC3 */ invalid_instruction(op); break;
+// default: /* ??? */ invalid_instruction(op); break;
+ }
+
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ compile_special - compile opcodes in the
+ 'SPECIAL' group
+-------------------------------------------------*/
+
+static int compile_special(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = op & 63;
+ emit_link link1;
+
+ switch (opswitch)
+ {
+ /* ----- shift instructions ----- */
+
+ case 0x00: /* SLL - MIPS I */
+ case 0x02: /* SRL - MIPS I */
+ case 0x03: /* SRA - MIPS I */
+ case 0x04: /* SLLV - MIPS I */
+ case 0x06: /* SRLV - MIPS I */
+ case 0x07: /* SRAV - MIPS I */
+ return compile_shift(drc, compiler, desc, opswitch & 0x03, opswitch & 0x04);
+
+ case 0x14: /* DSLLV - MIPS III */
+ case 0x16: /* DSRLV - MIPS III */
+ case 0x17: /* DSRAV - MIPS III */
+ case 0x38: /* DSLL - MIPS III */
+ case 0x3a: /* DSRL - MIPS III */
+ case 0x3b: /* DSRA - MIPS III */
+ case 0x3c: /* DSLL32 - MIPS III */
+ case 0x3e: /* DSRL32 - MIPS III */
+ case 0x3f: /* DSRA32 - MIPS III */
+ return compile_dshift(drc, compiler, desc, opswitch & 0x03, ~opswitch & 0x20, opswitch & 0x04);
+
+
+ /* ----- basic arithmetic ----- */
+
+ case 0x20: /* ADD - MIPS I */
+ case 0x21: /* ADDU - MIPS I */
+ return compile_add(drc, compiler, desc, opswitch & 1, FALSE);
+
+ case 0x2c: /* DADD - MIPS III */
+ case 0x2d: /* DADDU - MIPS III */
+ return compile_dadd(drc, compiler, desc, opswitch & 1, FALSE);
+
+ case 0x22: /* SUB - MIPS I */
+ case 0x23: /* SUBU - MIPS I */
+ return compile_sub(drc, compiler, desc, opswitch & 1);
+
+ case 0x2e: /* DSUB - MIPS III */
+ case 0x2f: /* DSUBU - MIPS III */
+ return compile_dsub(drc, compiler, desc, opswitch & 1);
+
+ case 0x18: /* MULT - MIPS I */
+ case 0x19: /* MULTU - MIPS I */
+ return compile_mult(drc, compiler, desc, opswitch & 1);
+
+ case 0x1c: /* DMULT - MIPS III */
+ case 0x1d: /* DMULTU - MIPS III */
+ return compile_dmult(drc, compiler, desc, opswitch & 1);
+
+ case 0x1a: /* DIV - MIPS I */
+ case 0x1b: /* DIVU - MIPS I */
+ return compile_div(drc, compiler, desc, opswitch & 1);
+
+ case 0x1e: /* DDIV - MIPS III */
+ case 0x1f: /* DDIVU - MIPS III */
+ return compile_ddiv(drc, compiler, desc, opswitch & 1);
+
+
+ /* ----- basic logical ops ----- */
+
+ case 0x24: /* AND - MIPS I */
+ case 0x25: /* OR - MIPS I */
+ case 0x26: /* XOR - MIPS I */
+ case 0x27: /* NOR - MIPS I */
+ return compile_logical(drc, compiler, desc, opswitch & 3, FALSE);
+
+
+ /* ----- basic comparisons ----- */
+
+ case 0x2a: /* SLT - MIPS I */
+ case 0x2b: /* SLTU - MIPS I */
+ return compile_slt(drc, compiler, desc, opswitch & 1, FALSE);
+
+
+ /* ----- conditional traps ----- */
+
+ case 0x30: /* TGE - MIPS II */
+ case 0x31: /* TGEU - MIPS II */
+ case 0x32: /* TLT - MIPS II */
+ case 0x33: /* TLTU - MIPS II */
+ case 0x34: /* TEQ - MIPS II */
+ case 0x36: /* TNE - MIPS II */
+ return compile_trapcc(drc, compiler, desc, opswitch & 7, FALSE);
+
+
+ /* ----- conditional moves ----- */
+
+ case 0x0a: /* MOVZ - MIPS IV */
+ case 0x0b: /* MOVN - MIPS IV */
+ return compile_movzn(drc, compiler, desc, opswitch & 1);
+
+ case 0x01: /* MOVF - MIPS IV */
+ if (RDREG != 0)
+ {
+ mipsreg_state rs, rd;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY);
+
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[x],0
+ emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); // jz/nz skip
+ emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
+ }
+ resolve_link(DRCTOP, &link1); // skip:
+ return TRUE;
+
+
+ /* ----- jumps and branches ----- */
+
+ case 0x08: /* JR - MIPS I */
+ case 0x09: /* JALR - MIPS I */
+ {
+ mipsreg_state rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ if (ISCONST(rs))
+ emit_mov_m32_imm(DRCTOP, MBD(REG_RSP, SPOFFS_NEXTPC), CONSTVAL(rs)); // mov [esp+nextpc],rs
+ else
+ emit_mov_m32_r32(DRCTOP, MBD(REG_RSP, SPOFFS_NEXTPC), X86REG(rs)); // mov [esp+nextpc],rs
+ emit_delay_slot_and_branch(drc, compiler, desc, (opswitch == 0x09) ? RDREG : 0);
+ // <next instruction + redispatch>
+ }
+ return TRUE;
+
+
+ /* ----- system calls ----- */
+
+ case 0x0c: /* SYSCALL - MIPS I */
+ oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_syscall_exception);
+ // jmp generate_syscall_exception
+ return TRUE;
+
+ case 0x0d: /* BREAK - MIPS I */
+ oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_break_exception);
+ // jmp generate_break_exception
+ return TRUE;
+
+
+ /* ----- effective no-ops ----- */
+
+ case 0x0f: /* SYNC - MIPS II */
+ return TRUE;
+
+
+ /* ----- hi/lo register access ----- */
+
+ case 0x10: /* MFHI - MIPS I */
+ if (RDREG != 0)
+ {
+ mipsreg_state hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_SRC);
+ mipsreg_state rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY);
+ emit_load_register_value(drc, compiler, X86REG(rd), hi); // mov <rd>,<hi>
+ }
+ return TRUE;
+
+ case 0x11: /* MTHI - MIPS I */
+ if (RSREG != 0)
+ {
+ mipsreg_state rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ mipsreg_state hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
+ emit_load_register_value(drc, compiler, X86REG(hi), rs); // mov hi,<rs>
+ }
+ return TRUE;
+
+ case 0x12: /* MFLO - MIPS I */
+ if (RDREG != 0)
+ {
+ mipsreg_state lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_SRC);
+ mipsreg_state rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY);
+ emit_load_register_value(drc, compiler, X86REG(rd), lo); // mov <rd>,<lo>
+ }
+ return TRUE;
+
+ case 0x13: /* MTLO - MIPS I */
+ if (RSREG != 0)
+ {
+ mipsreg_state rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ mipsreg_state lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
+ emit_load_register_value(drc, compiler, X86REG(lo), rs); // mov lo,<rs>
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ compile_regimm - compile opcodes in the
+ 'REGIMM' group
+-------------------------------------------------*/
+
+static int compile_regimm(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = RTREG;
+
+ switch (opswitch)
+ {
+ case 0x00: /* BLTZ */
+ case 0x01: /* BGEZ */
+ case 0x02: /* BLTZL */
+ case 0x03: /* BGEZL */
+ case 0x10: /* BLTZAL */
+ case 0x11: /* BGEZAL */
+ case 0x12: /* BLTZALL */
+ case 0x13: /* BGEZALL */
+ return compile_branchcz(drc, compiler, desc, (opswitch & 1) ? COND_GE : COND_L, opswitch & 0x10);
+
+ case 0x08: /* TGEI */
+ case 0x09: /* TGEIU */
+ case 0x0a: /* TLTI */
+ case 0x0b: /* TLTIU */
+ case 0x0c: /* TEQI */
+ case 0x0e: /* TNEI */
+ return compile_trapcc(drc, compiler, desc, opswitch & 7, TRUE);
+ }
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ compile_idt - compile opcodes in the IDT-
+ specific group
+-------------------------------------------------*/
+
+static int compile_idt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
+{
+ fatalerror("Unimplemented IDT instructions");
+#if 0
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = op & 0x1f;
+
+ switch (opswitch)
+ {
+ case 0: /* MAD */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg]
+ emit_mov_r32_m32(REG_EDX, REGADDR(RTREG)); // mov edx,[rtreg]
+ emit_imul_r32(DRCTOP, REG_EDX); // imul edx
+ emit_add_r32_m32(DRCTOP, LOADDR); // add eax,[lo]
+ emit_adc_r32_m32(DRCTOP, HIADDR); // adc edx,[hi]
+ emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EAX); // mov [lo],edx:eax
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EAX); // mov [hi],edx:eax
+ }
+ return compile_SUCCESSFUL_CP(3,4);
+
+ case 1: /* MADU */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg]
+ emit_mov_r32_m32(REG_EDX, REGADDR(RTREG)); // mov edx,[rtreg]
+ emit_mul_r32(DRCTOP, REG_EDX); // mul edx
+ emit_add_r32_m32(DRCTOP, LOADDR); // add eax,[lo]
+ emit_adc_r32_m32(DRCTOP, HIADDR); // adc edx,[hi]
+ emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
+ }
+ return compile_SUCCESSFUL_CP(3,4);
+
+ case 2: /* MUL */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg]
+ emit_imul_r32_m32(REG_EAX, REGADDR(RTREG)); // imul eax,[rtreg]
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(REG_ESI, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rd],edx:eax
+ }
+ else
+ emit_zero_m64(REG_ESI, REGADDR(RDREG));
+ }
+ return compile_SUCCESSFUL_CP(3,4);
+ }
+#endif
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ COP0 RECOMPILATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ compile_set_cop0_reg - generate code to
+ handle special COP0 registers
+-------------------------------------------------*/
+
+static int compile_set_cop0_reg(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 reg)
+{
+ emit_link link1;
+
+ switch (reg)
+ {
+ case COP0_Cause:
+ emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Cause)); // mov edx,[Cause]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfc00); // and eax,~0xfc00
+ emit_and_r32_imm(DRCTOP, REG_EDX, 0xfc00); // and edx,0xfc00
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EDX); // or eax,edx
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [Cause],eax
+ emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[SR]
+ emit_test_r32_imm(DRCTOP, REG_EAX, 0x300); // test eax,0x300
+ oob_request_callback(drc, COND_NZ, oob_interrupt_cleanup, compiler, desc, mips3.drcdata->generate_interrupt_exception);
+ // jnz generate_interrupt_exception
+ return TRUE;
+
+ case COP0_Status:
+ emit_flush_cycles_before_instruction(drc, compiler, desc, 1);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Status)); // mov edx,[Status]
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [Status],eax
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EAX); // xor edx,eax
+ emit_test_r32_imm(DRCTOP, REG_EDX, 0x8000); // test edx,0x8000
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_update_cycle_counting)); // call mips3com_update_cycle_counting
+ resolve_link(DRCTOP, &link1); // skip:
+ append_check_interrupts(drc, compiler, desc); // <check interrupts>
+ return TRUE;
+
+ case COP0_Count:
+ emit_flush_cycles_before_instruction(drc, compiler, desc, 1);
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Count), REG_EAX); // mov [Count],eax
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->activecpu_gettotalcycles64)); // call activecpu_gettotalcycles64
+ emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Count)); // mov edx,[Count]
+ emit_sub_r64_r64(DRCTOP, REG_RAX, REG_RDX); // sub rax,rdx
+ emit_sub_r64_r64(DRCTOP, REG_RAX, REG_RDX); // sub rax,rdx
+ emit_mov_m64_r64(DRCTOP, MDRC(&mips3.core->count_zero_time), REG_RAX); // mov [count_zero_time],rax
+ emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_update_cycle_counting)); // call mips3com_update_cycle_counting
+ return TRUE;
+
+ case COP0_Compare:
+ emit_flush_cycles_before_instruction(drc, compiler, desc, 1);
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Compare), REG_EAX); // mov [Compare],eax
+ emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), ~0x8000); // and [Cause],~0x8000
+ emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_update_cycle_counting)); // call mips3com_update_cycle_counting
+ return TRUE;
+
+ case COP0_PRId:
+ return TRUE;
+
+ case COP0_Config:
+ emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Config)); // mov edx,[Config]
+ emit_and_r32_imm(DRCTOP, REG_EAX, 0x0007); // and eax,0x0007
+ emit_and_r32_imm(DRCTOP, REG_EDX, ~0x0007); // and edx,~0x0007
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EDX); // or eax,edx
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Config), REG_EAX); // mov [Config],eax
+ return TRUE;
+
+ default:
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(reg), REG_EAX); // mov cpr0[reg],eax
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ compile_get_cop0_reg - generate code to
+ read special COP0 registers
+-------------------------------------------------*/
+
+static int compile_get_cop0_reg(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 reg)
+{
+ emit_link link1, link2;
+
+ switch (reg)
+ {
+ case COP0_Count:
+ compiler->cycles += MIPS3_COUNT_READ_CYCLES;
+ emit_flush_cycles_before_instruction(drc, compiler, desc, MIPS3_COUNT_READ_CYCLES);
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->activecpu_gettotalcycles64)); // call activecpu_gettotalcycles64
+ emit_sub_r64_m64(DRCTOP, REG_RAX, MDRC(&mips3.core->count_zero_time)); // sub rax,[count_zero_time]
+ emit_shr_r64_imm(DRCTOP, REG_RAX, 1); // shr rax,1
+ emit_movsxd_r64_r32(DRCTOP, REG_RAX, REG_EAX); // movsxd rax,eax
+ return TRUE;
+
+ case COP0_Cause:
+ compiler->cycles += MIPS3_CAUSE_READ_CYCLES;
+ emit_movsxd_r64_m32(DRCTOP, REG_RAX, CPR0ADDR(COP0_Cause)); // movsxd rax,[Cause]
+ return TRUE;
+
+ case COP0_Random:
+ emit_flush_cycles_before_instruction(drc, compiler, desc, 1);
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->activecpu_gettotalcycles64)); // call activecpu_gettotalcycles64
+ emit_mov_r32_m32(DRCTOP, REG_ECX, CPR0ADDR(COP0_Wired)); // mov ecx,[Wired]
+ emit_mov_r32_imm(DRCTOP, REG_R8D, 48); // mov r8d,48
+ emit_and_r32_imm(DRCTOP, REG_ECX, 0x3f); // and ecx,0x3f
+ emit_sub_r64_m64(DRCTOP, REG_RAX, MDRC(&mips3.core->count_zero_time)); // sub rax,[count_zero_time]
+ emit_sub_r32_r32(DRCTOP, REG_R8D, REG_ECX); // sub r8d,ecx
+ emit_jcc_short_link(DRCTOP, COND_BE, &link1); // jbe link1
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_div_r64(DRCTOP, REG_R8); // div r8
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx
+ emit_add_r32_r32(DRCTOP, REG_EAX, REG_ECX); // add eax,ecx
+ emit_and_r32_imm(DRCTOP, REG_EAX, 0x3f); // and eax,0x3f
+ emit_jmp_short_link(DRCTOP, &link2); // jmp link2
+ resolve_link(DRCTOP, &link1); // link1:
+ emit_mov_r32_imm(DRCTOP, REG_EAX, 47); // mov eax,47
+ resolve_link(DRCTOP, &link2); // link2:
+ return TRUE;
+
+ default:
+ emit_movsxd_r64_m32(DRCTOP, REG_RAX, CPR0ADDR(reg)); // movsxd rax,cpr0[reg]
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ compile_cop0 - compile COP0 opcodes
+-------------------------------------------------*/
+
+static int compile_cop0(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = RSREG;
+
+ /* generate an exception if COP0 is disabled or we are not in kernel mode */
+ if (mips3.drcoptions & MIPS3DRC_STRICT_COP0)
+ {
+ emit_link checklink;
+
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_KSU_MASK); // test [SR],SR_KSU_MASK
+ emit_jcc_short_link(DRCTOP, COND_Z, &checklink); // jz okay
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP0); // test [SR],SR_COP0
+ oob_request_callback(drc, COND_Z, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_cop_exception);
+ // jz generate_cop_exception
+ resolve_link(DRCTOP, &checklink); // okay:
+ }
+
+ switch (opswitch)
+ {
+ case 0x00: /* MFCz */
+ case 0x01: /* DMFCz */
+ if (RTREG != 0)
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
+ compile_get_cop0_reg(drc, compiler, desc, RDREG); // mov eax,cpr0[rd])
+ if (!(opswitch & 1))
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rt), REG_EAX); // movsxd <rt>,eax
+ else
+ emit_mov_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // mov <rt>,rax
+ }
+ return TRUE;
+
+ case 0x02: /* CFCz */
+ if (RTREG != 0)
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
+ emit_movsxd_r64_m32(DRCTOP, X86REG(rt), CCR0ADDR(RDREG)); // movsxd <rt>,ccr1[rd]
+ }
+ return TRUE;
+
+ case 0x04: /* MTCz */
+ case 0x05: /* DMTCz */
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+ emit_load_register_value(drc, compiler, REG_EAX, rt); // mov eax,<rt>
+ compile_set_cop0_reg(drc, compiler, desc, RDREG); // mov cpr0[rd],rax
+ }
+ return TRUE;
+
+ case 0x06: /* CTCz */
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+ emit_load_register_value(drc, compiler, REG_EAX, rt); // mov eax,<rt>
+ emit_mov_m32_r32(DRCTOP, CCR0ADDR(RDREG), REG_EAX); // mov ccr1[rd],eax
+ }
+ return TRUE;
+
+ 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: /* COP */
+ switch (op & 0x01ffffff)
+ {
+ case 0x01: /* TLBR */
+ emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbr)); // call mips3com_tlbr
+ return TRUE;
+
+ case 0x02: /* TLBWI */
+ emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbwi)); // call mips3com_tlbwi
+ return TRUE;
+
+ case 0x06: /* TLBWR */
+ emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbwr)); // call mips3com_tlbwr
+ return TRUE;
+
+ case 0x08: /* TLBP */
+ emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
+ emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbp)); // call mips3com_tlbp
+ return TRUE;
+
+ case 0x18: /* ERET */
+ emit_mov_r32_m32(DRCTOP, REG_P1, CPR0ADDR(COP0_EPC)); // mov p1,[EPC]
+ emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), ~SR_EXL); // and [SR],~SR_EXL
+ compiler_register_flush_all(drc, compiler); // <flush registers>
+ drc_append_dispatcher(drc); // <dispatch>
+ return TRUE;
+
+ case 0x20: /* WAIT */
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ COP1 RECOMPILATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ compile_cop1 - compile COP1 opcodes
+-------------------------------------------------*/
+
+static int compile_cop1(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+ emit_link link1;
+
+ /* generate an exception if COP1 is disabled */
+ if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
+ {
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [mips3.core->cpr[0][COP0_Status]],SR_COP1
+ oob_request_callback(drc, COND_Z, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_cop_exception);
+ // jz generate_cop_exception
+ }
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */
+ if (RTREG != 0)
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
+ emit_movsxd_r64_m32(DRCTOP, X86REG(rt), FPR32ADDR(RDREG)); // movsxd <rt>,cpr[rd]
+ }
+ return TRUE;
+
+ case 0x01: /* DMFCz */
+ if (RTREG != 0)
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
+ emit_mov_r64_m64(DRCTOP, X86REG(rt), FPR64ADDR(RDREG)); // mov <rt>,cpr[rd]
+ }
+ return TRUE;
+
+ case 0x02: /* CFCz */
+ if (RTREG != 0)
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
+ if (RDREG != 31)
+ emit_movsxd_r64_m32(DRCTOP, X86REG(rt), CCR1ADDR(RDREG)); // movsxd <rt>,ccr1[rd]
+ else
+ {
+ emit_call(DRCTOP, mips3.drcdata->recover_ccr31); // call recover_ccr31
+ emit_mov_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // mov [X86REG(rt)],rax
+ }
+ }
+ return TRUE;
+
+ case 0x04: /* MTCz */
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+ UINT8 tempreg = ISCONST(rt) ? REG_EAX : X86REG(rt);
+ emit_load_register_value(drc, compiler, tempreg, rt); // mov <tempreg>,<rt>
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(RDREG), tempreg); // mov cpr1[rd],<tempreg>
+ }
+ return TRUE;
+
+ case 0x05: /* DMTCz */
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+ UINT8 tempreg = ISCONST(rt) ? REG_EAX : X86REG(rt);
+ emit_load_register_value(drc, compiler, tempreg, rt); // mov <tempreg>,<rt>
+ emit_mov_m64_r64(DRCTOP, FPR64ADDR(RDREG), tempreg); // mov cpr1[rd],<tempreg>
+ }
+ return TRUE;
+
+ case 0x06: /* CTCz */
+ {
+ mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+ emit_load_register_value(drc, compiler, REG_EAX, rt); // mov eax,<rt>
+ if (RDREG != 31)
+ emit_mov_m32_r32(DRCTOP, CCR1ADDR(RDREG), REG_EAX); // mov ccr1[rd],eax
+ else
+ emit_call(DRCTOP, mips3.drcdata->explode_ccr31); // call explode_ccr31
+ }
+ return TRUE;
+
+ case 0x08: /* BC */
+ switch ((op >> 16) & 3)
+ {
+ case 0x00: /* BCzF */
+ case 0x02: /* BCzFL */
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[which],0
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1
+ emit_delay_slot_and_branch(drc, compiler, desc, 0); // <next instruction + redispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return TRUE;
+
+ case 0x01: /* BCzT */
+ case 0x03: /* BCzTL */
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[which],0
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1
+ emit_delay_slot_and_branch(drc, compiler, desc, 0); // <next instruction + redispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return TRUE;
+ }
+ break;
+
+ default:
+ switch (op & 0x3f)
+ {
+ case 0x00:
+ if (IS_SINGLE(op)) /* ADD.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // addss xmm0,[ftreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* ADD.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // addsd xmm0,[ftreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x01:
+ if (IS_SINGLE(op)) /* SUB.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // subss xmm0,[ftreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* SUB.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // subsd xmm0,[ftreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x02:
+ if (IS_SINGLE(op)) /* MUL.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* MUL.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x03:
+ if (IS_SINGLE(op)) /* DIV.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_divss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // divss xmm0,[ftreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* DIV.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_divsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // divsd xmm0,[ftreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x04:
+ if (IS_SINGLE(op)) /* SQRT.S */
+ {
+ emit_sqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // sqrtss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* SQRT.D */
+ {
+ emit_sqrtsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // sqrtsd xmm0,[fsreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x05:
+ if (IS_SINGLE(op)) /* ABS.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_andps_r128_m128(DRCTOP, REG_XMM0, MDRC(mips3.drcdata->abs32mask));
+ // andps xmm0,[abs32mask]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* ABS.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_andps_r128_m128(DRCTOP, REG_XMM0, MDRC(mips3.drcdata->abs64mask));
+ // andpd xmm0,[abs64mask]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x06:
+ if (IS_SINGLE(op)) /* MOV.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* MOV.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x07:
+ if (IS_SINGLE(op)) /* NEG.S */
+ {
+ emit_xorps_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // xorps xmm0,xmm0
+ emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // subss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* NEG.D */
+ {
+ emit_xorps_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // xorps xmm0,xmm0
+ emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // subsd xmm0,[fsreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x08:
+ /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
+ drc_append_set_temp_sse_rounding(drc, FPRND_NEAR); // ldmxcsr [round]
+ if (IS_SINGLE(op)) /* ROUND.L.S */
+ emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg]
+ else /* ROUND.L.D */
+ emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg]
+ emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax
+ drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
+ return TRUE;
+
+ case 0x09:
+ if (IS_SINGLE(op)) /* TRUNC.L.S */
+ emit_cvttss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvttss2si rax,[fsreg]
+ else /* TRUNC.L.D */
+ emit_cvttsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvttsd2si rax,[fsreg]
+ emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax
+ return TRUE;
+
+ case 0x0a:
+ /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
+ drc_append_set_temp_sse_rounding(drc, FPRND_UP); // ldmxcsr [round]
+ if (IS_SINGLE(op)) /* CEIL.L.S */
+ emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg]
+ else /* CEIL.L.D */
+ emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg]
+ emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax
+ drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
+ return TRUE;
+
+ case 0x0b:
+ /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
+ drc_append_set_temp_sse_rounding(drc, FPRND_DOWN); // ldmxcsr [round]
+ if (IS_SINGLE(op)) /* FLOOR.L.S */
+ emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg]
+ else /* FLOOR.L.D */
+ emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg]
+ emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax
+ drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
+ return TRUE;
+
+ case 0x0c:
+ /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
+ drc_append_set_temp_sse_rounding(drc, FPRND_NEAR); // ldmxcsr [round]
+ if (IS_SINGLE(op)) /* ROUND.W.S */
+ emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg]
+ else /* ROUND.W.D */
+ emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
+ return TRUE;
+
+ case 0x0d:
+ if (IS_SINGLE(op)) /* TRUNC.W.S */
+ emit_cvttss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvttss2si eax,[fsreg]
+ else /* TRUNC.W.D */
+ emit_cvttsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvttsd2si eax,[fsreg]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ return TRUE;
+
+ case 0x0e:
+ /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
+ drc_append_set_temp_sse_rounding(drc, FPRND_UP); // ldmxcsr [round]
+ if (IS_SINGLE(op)) /* CEIL.W.S */
+ emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg]
+ else /* CEIL.W.D */
+ emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
+ return TRUE;
+
+ case 0x0f:
+ /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
+ drc_append_set_temp_sse_rounding(drc, FPRND_DOWN); // ldmxcsr [round]
+ if (IS_SINGLE(op)) /* FLOOR.W.S */
+ emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg]
+ else /* FLOOR.W.D */
+ emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
+ return TRUE;
+
+ case 0x11: /* R5000 */
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[which],0
+ emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1);
+ // jz/nz skip
+ if (IS_SINGLE(op)) /* MOVT/F.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* MOVT/F.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ resolve_link(DRCTOP, &link1); // skip:
+ return TRUE;
+
+ case 0x12: /* R5000 */
+ emit_cmp_m64_imm(DRCTOP, REGADDR(RTREG), 0); // cmp [X86REG(rt)],0
+ emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip
+ if (IS_SINGLE(op)) /* MOVZ.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* MOVZ.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ resolve_link(DRCTOP, &link1); // skip:
+ return TRUE;
+
+ case 0x13: /* R5000 */
+ emit_cmp_m64_imm(DRCTOP, REGADDR(RTREG), 0); // cmp [X86REG(rt)],0
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ if (IS_SINGLE(op)) /* MOVN.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* MOVN.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ resolve_link(DRCTOP, &link1); // skip:
+ return TRUE;
+
+ case 0x15: /* R5000 */
+ if (IS_SINGLE(op)) /* RECIP.S */
+ {
+ emit_rcpss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // rcpss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* RECIP.D */
+ {
+ emit_cvtsd2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsd2ss xmm0,[fsreg]
+ emit_rcpss_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // rcpss xmm0,xmm0
+ emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // cvtss2sd xmm0,xmm0
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x16: /* R5000 */
+ if (IS_SINGLE(op)) /* RSQRT.S */
+ {
+ emit_rsqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // rsqrtss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else /* RSQRT.D */
+ {
+ emit_cvtsd2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtss2sd xmm0,[fsreg]
+ emit_rsqrtss_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // rsqrtss xmm0,xmm0
+ emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // cvtsd2ss xmm0,xmm0
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ return TRUE;
+
+ case 0x20:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.S.W */
+ emit_cvtsi2ss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // cvtsi2ss xmm0,[fsreg]
+ else /* CVT.S.L */
+ emit_cvtsi2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsi2ss xmm0,[fsreg]
+ }
+ else /* CVT.S.D */
+ emit_cvtsd2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsd2ss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ return TRUE;
+
+ case 0x21:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.D.W */
+ emit_cvtsi2sd_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // cvtsi2sd xmm0,[fsreg]
+ else /* CVT.D.L */
+ emit_cvtsi2sd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsi2sd xmm0,[fsreg]
+ }
+ else /* CVT.D.S */
+ emit_cvtss2sd_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // cvtss2sd xmm0,[fsreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ return TRUE;
+
+ case 0x24:
+ if (IS_SINGLE(op)) /* CVT.W.S */
+ emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg]
+ else /* CVT.W.D */
+ emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ return TRUE;
+
+ case 0x25:
+ if (IS_SINGLE(op)) /* CVT.L.S */
+ emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg]
+ else /* CVT.L.D */
+ emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg]
+ emit_mov_m64_r64(DRCTOP, FPR32ADDR(FDREG), REG_RAX); // mov [fdreg],rax
+ return TRUE;
+
+ case 0x30:
+ case 0x38:
+ emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */
+ return TRUE;
+
+ case 0x31:
+ case 0x39:
+ emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */
+ return TRUE;
+
+ case 0x32:
+ case 0x3a:
+ if (IS_SINGLE(op)) /* C.EQ.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
+ }
+ else /* C.EQ.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete fcc[x]
+ return TRUE;
+
+ case 0x33:
+ case 0x3b:
+ if (IS_SINGLE(op)) /* C.UEQ.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
+ }
+ else /* C.UEQ.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete fcc[x]
+ return TRUE;
+
+ case 0x34:
+ case 0x3c:
+ if (IS_SINGLE(op)) /* C.OLT.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
+ }
+ else /* C.OLT.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb fcc[x]
+ return TRUE;
+
+ case 0x35:
+ case 0x3d:
+ if (IS_SINGLE(op)) /* C.ULT.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
+ }
+ else /* C.ULT.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb fcc[x]
+ return TRUE;
+
+ case 0x36:
+ case 0x3e:
+ if (IS_SINGLE(op)) /* C.OLE.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
+ }
+ else /* C.OLE.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe fcc[x]
+ return TRUE;
+
+ case 0x37:
+ case 0x3f:
+ if (IS_SINGLE(op)) /* C.ULE.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
+ }
+ else /* C.ULE.D */
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe fcc[x]
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ COP1X RECOMPILATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ compile_cop1x - compile COP1X opcodes
+-------------------------------------------------*/
+
+static int compile_cop1x(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+
+ if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
+ {
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [mips3.core->cpr[0][COP0_Status]],SR_COP1
+ oob_request_callback(drc, COND_Z, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_cop_exception);
+ // jz generate_cop_exception
+ }
+
+ switch (op & 0x3f)
+ {
+ case 0x00: /* LWXC1 */
+ return compile_loadx_cop(drc, compiler, desc, 4, FPR32(FDREG));
+
+ case 0x01: /* LDXC1 */
+ return compile_loadx_cop(drc, compiler, desc, 8, FPR64(FDREG));
+
+ case 0x08: /* SWXC1 */
+ return compile_storex_cop(drc, compiler, desc, 4, FPR32(FDREG));
+
+ case 0x09: /* SDXC1 */
+ return compile_storex_cop(drc, compiler, desc, 8, FPR64(FDREG));
+
+ case 0x0f: /* PREFX */
+ return TRUE;
+
+ case 0x20: /* MADD.S */
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ return TRUE;
+
+ case 0x21: /* MADD.D */
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ return TRUE;
+
+ case 0x28: /* MSUB.S */
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // subss xmm0,[frreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ return TRUE;
+
+ case 0x29: /* MSUB.D */
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // subsd xmm0,[frreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ return TRUE;
+
+ case 0x30: /* NMADD.S */
+ emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg]
+ emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1
+ return TRUE;
+
+ case 0x31: /* NMADD.D */
+ emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg]
+ emit_subsd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subsd xmm1,xmm0
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1
+ return TRUE;
+
+ case 0x38: /* NMSUB.S */
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_movss_r128_m32(DRCTOP, REG_XMM1, FPR32ADDR(FRREG)); // movss xmm1,[frreg]
+ emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1
+ return TRUE;
+
+ case 0x39: /* NMSUB.D */
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_movsd_r128_m64(DRCTOP, REG_XMM1, FPR64ADDR(FRREG)); // movsd xmm1,[frreg]
+ emit_subsd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subsd xmm1,xmm0
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1
+ return TRUE;
+
+ case 0x24: /* MADD.W */
+ case 0x25: /* MADD.L */
+ case 0x2c: /* MSUB.W */
+ case 0x2d: /* MSUB.L */
+ case 0x34: /* NMADD.W */
+ case 0x35: /* NMADD.L */
+ case 0x3c: /* NMSUB.W */
+ case 0x3d: /* NMSUB.L */
+ default:
+ fprintf(stderr, "cop1x %X\n", op);
+ break;
+ }
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ INDIVIDUAL INSTRUCTION COMPILATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ compile_shift - compile a 32-bit
+ shift, both fixed and variable counts
+
+ 0: sll/sllv rD,rT,rS
+ 2: srl/srlv rD,rT,rS
+ 3: sra/srav rD,rT,rS
+-------------------------------------------------*/
+
+static int compile_shift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rd, rs, rt;
+
+ assert(shift_type == 0 || shift_type == 2 || shift_type == 3);
+
+ /* if the destination is r0, bail */
+ if (RDREG == 0)
+ return TRUE;
+
+ /* allocate source registers */
+ rs = shift_variable ? compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC) : MAKE_CONST(SHIFT);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if rS and rT are both constant, we can compute the constant result */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ if (shift_type == 0)
+ emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)((UINT32)CONSTVAL(rt) << CONSTVAL(rs)));
+ else if (shift_type == 2)
+ emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)((UINT32)CONSTVAL(rt) >> CONSTVAL(rs)));
+ else
+ emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)((INT32)CONSTVAL(rt) >> CONSTVAL(rs)));
+ }
+
+ /* otherwise, handle generically */
+ else
+ {
+ /* allocate the register and load rT into it */
+ /* if rS is non-const, must load it first in case rD == rS */
+ rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY);
+ if (!ISCONST(rs))
+ emit_load_register_value(drc, compiler, REG_ECX, rs); // mov ecx,<rs>
+ emit_load_register_value(drc, compiler, X86REG(rd), rt); // mov <rd>,<rt>
+
+ /* if rs is constant, use immediate forms of the shift */
+ if (ISCONST(rs))
+ {
+ if (shift_type == 0)
+ emit_shl_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 31); // shl <rd>,<rs>
+ else if (shift_type == 2)
+ emit_shr_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 31); // shr <rd>,<rs>
+ else
+ emit_sar_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 31); // sar <rd>,<rs>
+ }
+
+ /* otherwise, load rs into cl so we can do a variable shift */
+ else
+ {
+ if (shift_type == 0)
+ emit_shl_r32_cl(DRCTOP, X86REG(rd)); // shl <rd>,cl
+ else if (shift_type == 2)
+ emit_shr_r32_cl(DRCTOP, X86REG(rd)); // shr <rd>,cl
+ else
+ emit_sar_r32_cl(DRCTOP, X86REG(rd)); // sar <rd>,cl
+ }
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_dshift - compile a 64-bit
+ shift, both fixed and variable counts
+
+ 0: dsll/dsll32/dsllv rD,rT,rS
+ 2: dsrl/dsrl32/dsrlv rD,rT,rS
+ 3: dsra/dsra32/dsrav rD,rT,rS
+-------------------------------------------------*/
+
+static int compile_dshift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable, int shift_const_plus32)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rd, rs, rt;
+
+ assert(shift_type == 0 || shift_type == 2 || shift_type == 3);
+
+ /* if the destination is r0, bail */
+ if (RDREG == 0)
+ return TRUE;
+
+ /* allocate source registers */
+ rs = shift_variable ? compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC) : MAKE_CONST(SHIFT + (shift_const_plus32 ? 32 : 0));
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if rS and rT are both constant, we can compute the constant result */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ if (shift_type == 0)
+ emit_set_constant_value(drc, compiler, desc, RDREG, (UINT64)CONSTVAL(rt) << CONSTVAL(rs));
+ else if (shift_type == 2)
+ emit_set_constant_value(drc, compiler, desc, RDREG, (UINT64)CONSTVAL(rt) >> CONSTVAL(rs));
+ else
+ emit_set_constant_value(drc, compiler, desc, RDREG, (INT64)CONSTVAL(rt) >> CONSTVAL(rs));
+ }
+
+ /* otherwise, handle generically */
+ else
+ {
+ /* allocate the register and load rT into it */
+ /* if rS is non-const, must load it first in case rD == rS */
+ rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY);
+ if (!ISCONST(rs))
+ emit_load_register_value(drc, compiler, REG_ECX, rs); // mov ecx,<rs>
+ emit_load_register_value(drc, compiler, X86REG(rd), rt); // mov <rd>,<rt>
+
+ /* if rs is constant, use immediate forms of the shift */
+ if (ISCONST(rs))
+ {
+ if (shift_type == 0)
+ emit_shl_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 63); // shl <rd>,<rs>
+ else if (shift_type == 2)
+ emit_shr_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 63); // shr <rd>,<rs>
+ else
+ emit_sar_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 63); // sar <rd>,<rs>
+ }
+
+ /* otherwise, load rs into cl so we can do a variable shift */
+ else
+ {
+ if (shift_type == 0)
+ emit_shl_r64_cl(DRCTOP, X86REG(rd)); // shl <rd>,cl
+ else if (shift_type == 2)
+ emit_shr_r64_cl(DRCTOP, X86REG(rd)); // shr <rd>,cl
+ else
+ emit_sar_r64_cl(DRCTOP, X86REG(rd)); // sar <rd>,cl
+ }
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_movzn - compile a conditional
+ move based on compare against 0
+
+ movz/movn rD,rS,rT
+-------------------------------------------------*/
+
+static int compile_movzn(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_movn)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rd, rs, rt;
+ emit_link skip = { 0 };
+
+ /* if the destination is r0, bail */
+ if (RDREG == 0)
+ return TRUE;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+ rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY);
+
+ /* if rT is constant and fails the condition, we're done */
+ if (ISCONST(rt))
+ {
+ INT32 rtval = CONSTVAL(rt);
+ if ((is_movn && rtval == 0) || (!is_movn && rtval != 0))
+ return TRUE;
+ }
+
+ /* if rT is not constant, check the condition */
+ else
+ {
+ emit_test_r64_r64(DRCTOP, X86REG(rt), X86REG(rt)); // test <rt>,<rt>
+ emit_jcc_short_link(DRCTOP, is_movn ? COND_Z : COND_NZ, &skip); // jz/nz skip
+ }
+
+ /* load rS into rD */
+ emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
+ if (!ISCONST(rt))
+ resolve_link(DRCTOP, &skip); // skip:
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_trapcc - compile a conditional
+ trap comparing two registers
+
+ 0/1: tge/tgeu rS,rT / tgei/tgeiu rS,SIMM
+ 2/3: tlt/tltu rS,rT / tlti/tltiu rS,SIMM
+ 4: teq rS,rT / teqi rS,SIMM
+ 6: tne rS,rT / tnei rS,SIMM
+-------------------------------------------------*/
+
+static int compile_trapcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int immediate)
+{
+ static const UINT8 condtype[] = { COND_GE, COND_AE, COND_L, COND_B, COND_E, COND_NONE, COND_NE, COND_NONE };
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rs, rt;
+
+ assert(condition < ARRAY_LENGTH(condtype) && condtype[condition] != COND_NONE);
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ INT32 rsval = CONSTVAL(rs);
+ INT32 rtval = CONSTVAL(rt);
+ int result = FALSE;
+
+ /* determine the fixed answer */
+ switch (condition)
+ {
+ case 0: result = ((INT64)rsval >= (INT64)rtval); break;
+ case 1: result = ((UINT64)rsval >= (UINT64)rtval); break;
+ case 2: result = ((INT64)rsval < (INT64)rtval); break;
+ case 3: result = ((UINT64)rsval < (UINT64)rtval); break;
+ case 4: result = (rsval == rtval); break;
+ case 6: result = (rsval != rtval); break;
+ }
+
+ /* if we're not trapping, just return; otherwise, always trap */
+ if (!result)
+ return TRUE;
+ condition = COND_NONE;
+ }
+
+ /* if rT is constant do an immediate compare */
+ else if (ISCONST(rt))
+ {
+ emit_cmp_r64_imm(DRCTOP, X86REG(rs), CONSTVAL(rt)); // cmp <rs>,<rt>
+ condition = condtype[condition];
+ }
+
+ /* if rS is constant do an immediate compare with opposite condition */
+ else if (ISCONST(rs))
+ {
+ emit_cmp_r64_imm(DRCTOP, X86REG(rt), CONSTVAL(rs)); // cmp <rt>,<rs>
+ condition = condtype[condition] ^ 1;
+ }
+
+ /* otherwise, compare the two registers with a normal condition */
+ else
+ {
+ emit_cmp_r64_imm(DRCTOP, X86REG(rs), X86REG(rt)); // cmp <rs>,<rt>
+ condition = condtype[condition];
+ }
+
+ /* generate an OOB request if the trap is taken */
+ oob_request_callback(drc, condition, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_trap_exception);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_branchcc - compile a conditional
+ branch comparing two registers
+
+ beq rS,rT,dest
+ bne rS,rT,dest
+-------------------------------------------------*/
+
+static int compile_branchcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition)
+{
+ UINT32 op = *desc->opptr.l;
+ emit_link skip = { 0 };
+ mipsreg_state rs, rt;
+
+ assert(condition == COND_E || condition == COND_NE);
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ INT32 rsval = CONSTVAL(rs);
+ INT32 rtval = CONSTVAL(rt);
+ if ((condition == COND_E && rsval != rtval) || (condition == COND_NE && rsval == rtval))
+ return TRUE;
+ }
+
+ /* if rT is constant do an immediate compare */
+ else if (ISCONST(rt))
+ {
+ emit_cmp_r64_imm(DRCTOP, X86REG(rs), CONSTVAL(rt)); // cmp <rs>,<rt>
+ emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip
+ }
+
+ /* if rS is constant do an immediate compare */
+ else if (ISCONST(rs))
+ {
+ emit_cmp_r64_imm(DRCTOP, X86REG(rt), CONSTVAL(rs)); // cmp <rt>,<rs>
+ emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip
+ }
+
+ /* otherwise, compare the two registers with a normal condition */
+ else
+ {
+ emit_cmp_r64_r64(DRCTOP, X86REG(rs), X86REG(rt)); // cmp <rs>,<rt>
+ emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip
+ }
+
+ /* append the branch logic */
+ emit_delay_slot_and_branch(drc, compiler, desc, 0); // <next instruction + redispatch>
+
+ if (!(ISCONST(rs) && ISCONST(rt)))
+ resolve_link(DRCTOP, &skip); // skip:
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_branchcz - compile a conditional
+ branch comparing one register against 0
+
+ blez rS,dest
+ blezl rS,dest
+ bgtz rS,dest
+ bgtzl rS,dest
+ bltz rS,dest
+ bltzl rS,dest
+ bltzal rS,dest
+ bltzall rS,dest
+ bgez rS,dest
+ bgezl rS,dest
+ bgezal rS,dest
+ bgezall rS,dest
+-------------------------------------------------*/
+
+static int compile_branchcz(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int link)
+{
+ UINT32 op = *desc->opptr.l;
+ emit_link skip = { 0 };
+ mipsreg_state rs;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+
+ /* if the register is constant, we know the answer up front */
+ if (ISCONST(rs))
+ {
+ INT32 rsval = CONSTVAL(rs);
+ if ((condition == COND_LE && rsval > 0) || (condition == COND_G && rsval <= 0) ||
+ (condition == COND_L && rsval >= 0) || (condition == COND_GE && rsval < 0))
+ return TRUE;
+ }
+
+ /* otherwise, perform the compare */
+ else
+ {
+ emit_cmp_r64_imm(DRCTOP, X86REG(rs), 0); // cmp <rs>,0
+ emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip
+ }
+
+ /* append the branch logic */
+ emit_delay_slot_and_branch(drc, compiler, desc, link ? 31 : 0); // <next instruction + redispatch>
+
+ if (!ISCONST(rs))
+ resolve_link(DRCTOP, &skip); // skip:
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_add - compile an add with or without
+ overflow
+
+ add rD,rS,rT / addi rT,rS,SIMM
+ addu rD,rS,rT / addiu rT,rS,SIMM
+-------------------------------------------------*/
+
+static int compile_add(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 destreg = immediate ? RTREG : RDREG;
+ mipsreg_state rd, rs, rt;
+
+ /* note that we still must perform this operation even if destreg == 0
+ in the overflow case */
+ if (destreg == 0 && suppress_exceptions)
+ return TRUE;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ INT64 result = (INT64)CONSTVAL(rs) + (INT64)CONSTVAL(rt);
+
+ /* if we overflow, always generate an exception */
+ if (!suppress_exceptions && (INT32)result != result)
+ oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
+
+ /* else just set the new constant value */
+ else if (destreg != 0)
+ emit_set_constant_value(drc, compiler, desc, destreg, (INT32)result);
+ }
+
+ /* otherwise, handle generically */
+ else
+ {
+ rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST);
+
+ /* perform the operating in EAX so we don't trash rD if an exception happens */
+ if (!suppress_exceptions)
+ {
+ emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs>
+ if (!ISCONST(rt))
+ emit_add_r32_r32(DRCTOP, REG_EAX, X86REG(rt)); // add eax,<rt>
+ else if (CONSTVAL(rt) != 0)
+ emit_add_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rt)); // add eax,<rt>
+ oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
+ // jo generate_overflow_exception
+ if (destreg != 0)
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rd), REG_EAX); // movsxd <rd>,eax
+ }
+ else
+ {
+ if (ISCONST(rs) && CONSTVAL(rs) == 0)
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rt)); // movsxd <rd>,<rt>
+ else if (ISCONST(rt) && CONSTVAL(rt) == 0)
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rs)); // movsxd <rd>,<rs>
+ else if (ISCONST(rs))
+ {
+ emit_lea_r32_m32(DRCTOP, X86REG(rd), MBD(X86REG(rt), CONSTVAL(rs))); // lea <rd>,[<rt> + <rs>]
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
+ }
+ else if (ISCONST(rt))
+ {
+ emit_lea_r32_m32(DRCTOP, X86REG(rd), MBD(X86REG(rs), CONSTVAL(rt))); // lea <rd>,[<rs> + <rt>]
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
+ }
+ else
+ {
+ emit_lea_r32_m32(DRCTOP, X86REG(rd), MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea <rd>,[<rs> + <rt>]
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
+ }
+ }
+
+ /* only mark it dirty after the exception risk is over */
+ compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DIRTY);
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_dadd - compile an add with or without
+ overflow
+
+ dadd rD,rS,rT
+ daddu rD,rS,rT
+-------------------------------------------------*/
+
+static int compile_dadd(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 destreg = immediate ? RTREG : RDREG;
+ mipsreg_state rd, rs, rt;
+
+ /* note that we still must perform this operation even if destreg == 0
+ in the overflow case */
+ if (destreg == 0 && suppress_exceptions)
+ return TRUE;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ INT64 result = (INT64)CONSTVAL(rs) + (INT64)CONSTVAL(rt);
+
+ /* if we overflow, always generate an exception */
+ if (!suppress_exceptions && (INT32)result != result)
+ oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
+
+ /* else just set the new constant value */
+ else if (destreg != 0)
+ emit_set_constant_value(drc, compiler, desc, destreg, result);
+ }
+
+ /* otherwise, handle generically */
+ else
+ {
+ rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST);
+
+ /* perform the operating in EAX so we don't trash RTREG if an exception happens */
+ if (!suppress_exceptions)
+ {
+ emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs>
+ if (!ISCONST(rt))
+ emit_add_r64_r64(DRCTOP, REG_RAX, X86REG(rt)); // add rax,<rt>
+ else if (CONSTVAL(rt) != 0)
+ emit_add_r64_imm(DRCTOP, REG_RAX, CONSTVAL(rt)); // add rax,<rt>
+ oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
+ // jo generate_overflow_exception
+ if (destreg != 0)
+ emit_mov_r64_r64(DRCTOP, X86REG(rd), REG_RAX); // mov <rd>,rax
+ }
+ else
+ {
+ if (ISCONST(rs))
+ emit_lea_r64_m64(DRCTOP, X86REG(rd), MBD(X86REG(rt), CONSTVAL(rs))); // lea <rd>,[<rt> + <rs>]
+ else if (ISCONST(rt))
+ emit_lea_r64_m64(DRCTOP, X86REG(rd), MBD(X86REG(rs), CONSTVAL(rt))); // lea <rd>,[<rs> + <rt>]
+ else
+ emit_lea_r64_m64(DRCTOP, X86REG(rd), MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea <rd>,[<rs> + <rt>]
+ }
+
+ /* only mark it dirty after the exception risk is over */
+ compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DIRTY);
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_sub - compile an add with or without
+ overflow
+
+ sub rD,rS,rT
+ subu rD,rS,rT
+-------------------------------------------------*/
+
+static int compile_sub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rd, rs, rt;
+
+ /* note that we still must perform this operation even if RDREG == 0
+ in the overflow case */
+ if (RDREG == 0 && suppress_exceptions)
+ return TRUE;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ INT64 result = (INT64)CONSTVAL(rs) - (INT64)CONSTVAL(rt);
+
+ /* if we overflow, always generate an exception */
+ if (!suppress_exceptions && (INT32)result != result)
+ oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
+
+ /* else just set the new constant value */
+ else if (RDREG != 0)
+ emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)result);
+ }
+
+ /* if rS == rT, the result is 0 */
+ else if (RSREG == RTREG)
+ {
+ if (RDREG != 0)
+ emit_set_constant_value(drc, compiler, desc, RDREG, 0);
+ }
+
+ /* otherwise, handle generically */
+ else
+ {
+ rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST);
+
+ /* perform the operating in EAX so we don't trash RTREG if an exception happens */
+ if (!suppress_exceptions)
+ {
+ emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs>
+ if (!ISCONST(rt))
+ emit_sub_r32_r32(DRCTOP, REG_EAX, X86REG(rt)); // sub eax,<rt>
+ else if (CONSTVAL(rt) != 0)
+ emit_sub_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rt)); // sub eax,<rt>
+ if (!ISCONST(rt) || CONSTVAL(rt) != 0)
+ oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
+ // jo generate_overflow_exception
+ if (RDREG != 0)
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rd), REG_EAX); // movsxd <rd>,eax
+ }
+ else
+ {
+ /* if rD and rT aren't the same, it is pretty basic */
+ if (X86REG(rd) != X86REG(rt))
+ {
+ emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
+ if (!ISCONST(rt))
+ emit_sub_r32_r32(DRCTOP, X86REG(rd), X86REG(rt)); // sub <rd>,<rt>
+ else if (CONSTVAL(rt) != 0)
+ emit_sub_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // sub <rd>,<rt>
+ }
+
+ /* otherwise, we negate rT and add rS */
+ else
+ {
+ emit_neg_r32(DRCTOP, X86REG(rd)); // neg <rd>
+ if (!ISCONST(rs))
+ emit_add_r32_r32(DRCTOP, X86REG(rd), X86REG(rs)); // add <rd>,<rs>
+ else if (CONSTVAL(rs) != 0)
+ emit_add_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs)); // add <rd>,<rs>
+ }
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
+ }
+
+ /* only mark it dirty after the exception risk is over */
+ compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DIRTY);
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_dsub - compile an add with or without
+ overflow
+
+ dsub rD,rS,rT
+ dsubu rD,rS,rT
+-------------------------------------------------*/
+
+static int compile_dsub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rd, rs, rt;
+
+ /* note that we still must perform this operation even if RDREG == 0
+ in the overflow case */
+ if (RDREG == 0 && suppress_exceptions)
+ return TRUE;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ INT64 result = (INT64)CONSTVAL(rs) - (INT64)CONSTVAL(rt);
+
+ /* if we overflow, always generate an exception */
+ if (!suppress_exceptions && (INT32)result != result)
+ oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
+
+ /* else just set the new constant value */
+ else if (RDREG != 0)
+ emit_set_constant_value(drc, compiler, desc, RDREG, result);
+ }
+
+ /* if rS == rT, the result is 0 */
+ else if (RSREG == RTREG)
+ {
+ if (RDREG != 0)
+ emit_set_constant_value(drc, compiler, desc, RDREG, 0);
+ }
+
+ /* otherwise, handle generically */
+ else
+ {
+ rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST);
+
+ /* perform the operating in EAX so we don't trash RTREG if an exception happens */
+ if (!suppress_exceptions)
+ {
+ emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs>
+ if (!ISCONST(rt))
+ emit_sub_r64_r64(DRCTOP, REG_RAX, X86REG(rt)); // sub rax,<rt>
+ else if (CONSTVAL(rt) != 0)
+ emit_sub_r64_imm(DRCTOP, REG_RAX, CONSTVAL(rt)); // sub rax,<rt>
+ if (!ISCONST(rt) || CONSTVAL(rt) != 0)
+ oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
+ // jo generate_overflow_exception
+ if (RDREG != 0)
+ emit_mov_r64_r64(DRCTOP, X86REG(rd), REG_RAX); // mov <rd>,rax
+ }
+ else
+ {
+ /* if rD and rT aren't the same, it is pretty basic */
+ if (X86REG(rd) != X86REG(rt))
+ {
+ emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
+ if (!ISCONST(rt))
+ emit_sub_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // sub <rd>,<rt>
+ else if (CONSTVAL(rt) != 0)
+ emit_sub_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // sub <rd>,<rt>
+ }
+
+ /* otherwise, we negate rT and add rS */
+ else
+ {
+ emit_neg_r64(DRCTOP, X86REG(rd)); // neg <rd>
+ if (!ISCONST(rs))
+ emit_add_r64_r64(DRCTOP, X86REG(rd), X86REG(rs)); // add <rd>,<rs>
+ else if (CONSTVAL(rs) != 0)
+ emit_add_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs)); // add <rd>,<rs>
+ }
+ }
+
+ /* only mark it dirty after the exception risk is over */
+ compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DIRTY);
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_mult - compile a 32-bit multiply
+ instruction
+
+ mult rS,rT
+ multu rS,rT
+-------------------------------------------------*/
+
+static int compile_mult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rs, rt, lo, hi;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ UINT64 result = is_unsigned ? ((UINT64)CONSTVAL(rs) * (UINT64)CONSTVAL(rt)) : ((INT64)CONSTVAL(rs) * (INT64)CONSTVAL(rt));
+ emit_set_constant_value(drc, compiler, desc, REG_LO, (INT32)result);
+ emit_set_constant_value(drc, compiler, desc, REG_HI, (INT32)(result >> 32));
+ }
+
+ /* otherwise, handle generically */
+ else
+ {
+ UINT8 mulreg = ISCONST(rt) ? REG_ECX : X86REG(rt);
+
+ hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
+ lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
+
+ emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs>
+ emit_load_register_value(drc, compiler, mulreg, rt); // mov <mulreg>,<rt>
+ if (is_unsigned)
+ emit_mul_r32(DRCTOP, mulreg); // mul <mulreg>
+ else
+ emit_imul_r32(DRCTOP, mulreg); // imul <mulreg>
+ emit_movsxd_r64_r32(DRCTOP, X86REG(hi), REG_EDX); // movsxd <hireg>,edx
+ emit_movsxd_r64_r32(DRCTOP, X86REG(lo), REG_EAX); // movsxd <loreg>,eax
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_dmult - compile a 64-bit multiply
+ instruction
+
+ dmult rS,rT
+ dmultu rS,rT
+-------------------------------------------------*/
+
+static int compile_dmult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rs, rt, lo, hi;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ UINT64 result = is_unsigned ? ((UINT64)CONSTVAL(rs) * (UINT64)CONSTVAL(rt)) : ((INT64)CONSTVAL(rs) * (INT64)CONSTVAL(rt));
+ emit_set_constant_value(drc, compiler, desc, REG_LO, (INT64)result);
+ emit_set_constant_value(drc, compiler, desc, REG_HI, (INT64)(result >> 63));
+ }
+
+ /* otherwise, handle generically */
+ else
+ {
+ UINT8 mulreg = ISCONST(rt) ? REG_ECX : X86REG(rt);
+
+ hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
+ lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
+
+ emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs>
+ emit_load_register_value(drc, compiler, mulreg, rt); // mov <mulreg>,<rt>
+ if (is_unsigned)
+ emit_mul_r64(DRCTOP, mulreg); // mul <mulreg>
+ else
+ emit_imul_r64(DRCTOP, mulreg); // imul <mulreg>
+ emit_mov_r64_r64(DRCTOP, X86REG(hi), REG_RDX); // mov <hi>,rdx
+ emit_mov_r64_r64(DRCTOP, X86REG(lo), REG_RAX); // mov <lo>,rax
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_div - compile a 32-bit divide
+ instruction
+
+ div rS,rT
+ divu rS,rT
+-------------------------------------------------*/
+
+static int compile_div(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rs, rt, lo, hi;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if rT is constant and 0, just skip */
+ if (ISCONST(rt) && CONSTVAL(rt) == 0)
+ return TRUE;
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ UINT32 result = is_unsigned ? ((UINT32)CONSTVAL(rs) / (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) / (INT32)CONSTVAL(rt));
+ UINT32 remainder = is_unsigned ? ((UINT32)CONSTVAL(rs) % (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) % (INT32)CONSTVAL(rt));
+
+ emit_set_constant_value(drc, compiler, desc, REG_LO, (INT32)result);
+ emit_set_constant_value(drc, compiler, desc, REG_HI, (INT32)remainder);
+ }
+
+ /* otherwise, handle generically */
+ else
+ {
+ UINT8 divreg = ISCONST(rt) ? REG_ECX : X86REG(rt);
+ emit_link skip = { 0 };
+
+ hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
+ lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
+
+ emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs>
+ emit_load_register_value(drc, compiler, divreg, rt); // mov <divreg>,<rt>
+ if (!ISCONST(rt))
+ {
+ emit_test_r32_r32(DRCTOP, divreg, divreg); // test <divreg>,<divreg>
+ emit_jcc_short_link(DRCTOP, COND_Z, &skip); // jz skip
+ }
+ if (is_unsigned)
+ {
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_div_r32(DRCTOP, divreg); // div <divreg>
+ }
+ else
+ {
+ emit_cdq(DRCTOP); // cdq
+ emit_idiv_r32(DRCTOP, divreg); // idiv <divreg>
+ }
+ emit_movsxd_r64_r32(DRCTOP, X86REG(hi), REG_EDX); // movsxd <hi>,edx
+ emit_movsxd_r64_r32(DRCTOP, X86REG(lo), REG_EAX); // movsxd <lo>,eax
+ if (!ISCONST(rt))
+ resolve_link(DRCTOP, &skip); // skip:
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_ddiv - compile a 64-bit divide
+ instruction
+
+ ddiv rS,rT
+ ddivu rS,rT
+-------------------------------------------------*/
+
+static int compile_ddiv(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rs, rt, lo, hi;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if rT is constant and 0, just skip */
+ if (ISCONST(rt) && CONSTVAL(rt) == 0)
+ return TRUE;
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ UINT32 result = is_unsigned ? ((UINT32)CONSTVAL(rs) / (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) / (INT32)CONSTVAL(rt));
+ UINT32 remainder = is_unsigned ? ((UINT32)CONSTVAL(rs) % (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) % (INT32)CONSTVAL(rt));
+
+ emit_set_constant_value(drc, compiler, desc, REG_LO, (INT32)result);
+ emit_set_constant_value(drc, compiler, desc, REG_HI, (INT32)remainder);
+ }
+
+ /* if one is a constant, load the constant into EAX and multiple from there */
+ else
+ {
+ UINT8 divreg = ISCONST(rt) ? REG_ECX : X86REG(rt);
+ emit_link skip = { 0 };
+
+ hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
+ lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
+
+ emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs>
+ emit_load_register_value(drc, compiler, divreg, rt); // mov <divreg>,<rt>
+ emit_test_r64_r64(DRCTOP, divreg, divreg); // test <divreg>,<divreg>
+ emit_jcc_short_link(DRCTOP, COND_Z, &skip); // jz skip
+ if (is_unsigned)
+ {
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_div_r64(DRCTOP, divreg); // div <divreg>
+ }
+ else
+ {
+ emit_cqo(DRCTOP); // cqo
+ emit_idiv_r64(DRCTOP, divreg); // idiv <divreg>
+ }
+ emit_mov_r64_r64(DRCTOP, X86REG(hi), REG_EDX); // mov <hi>,edx
+ emit_mov_r64_r64(DRCTOP, X86REG(lo), REG_EAX); // mov <loreg>,eax
+ resolve_link(DRCTOP, &skip); // skip:
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_logical - compile a logical
+ operation between two registers
+
+ 0: and rD,rS,rT / and rT,rS,UIMM
+ 1: or rD,rS,rT / or rT,rS,UIMM
+ 2: xor rD,rS,rT / xor rT,rS,UIMM
+ 3: nor rD,rS,rT
+-------------------------------------------------*/
+
+static int compile_logical(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int operation, int immediate)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 destreg = immediate ? RTREG : RDREG;
+ mipsreg_state rd, rs, rt;
+
+ assert(operation >= 0 && operation <= 3);
+ assert(!immediate || operation != 3);
+
+ /* if the destination is r0, bail */
+ if (destreg == 0)
+ return TRUE;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = immediate ? MAKE_CONST(UIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if both constant, we know the answer up front */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ UINT64 result = (operation == 0) ? (CONSTVAL(rs) & CONSTVAL(rt)) : (operation == 1) ? (CONSTVAL(rs) | CONSTVAL(rt)) : (operation == 2) ? (CONSTVAL(rs) ^ CONSTVAL(rt)) : ~(CONSTVAL(rs) | CONSTVAL(rt));
+ emit_set_constant_value(drc, compiler, desc, destreg, result);
+ }
+
+ /* an AND against 0 is constant as well */
+ else if (operation == 0 && ISCONST(rt) && CONSTVAL(rt) == 0)
+ emit_set_constant_value(drc, compiler, desc, destreg, 0);
+
+ /* else do the operation in code */
+ else
+ {
+ rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST | ALLOC_DIRTY);
+
+ /* if rD matches rT, or if rS is const and rT isn't, then swap rT and rS */
+ if (X86REG(rd) == X86REG(rt) || (ISCONST(rs) && !ISCONST(rt)))
+ {
+ mipsreg_state temp = rs;
+ rs = rt;
+ rt = temp;
+ }
+
+ /* load rS into rD */
+ emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
+
+ /* if rD does not match rT, we can work directly in rD */
+ if (!ISCONST(rt))
+ {
+ if (operation == 0)
+ emit_and_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // and <rd>,<rt>
+ else if (operation == 1)
+ emit_or_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // or <rd>,<rt>
+ else if (operation == 2)
+ emit_xor_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // xor <rd>,<rt>
+ else if (operation == 3)
+ {
+ emit_or_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // or <rd>,<rt>
+ emit_not_r64(DRCTOP, X86REG(rd)); // not <rd>
+ }
+ }
+ else
+ {
+ if (operation == 0)
+ emit_and_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // and <rd>,CONSTVAL(rt)
+ else if (operation == 1 && CONSTVAL(rt) != 0)
+ emit_or_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // or <rd>,CONSTVAL(rt)
+ else if (operation == 2 && CONSTVAL(rt) != 0)
+ emit_xor_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // xor <rd>,CONSTVAL(rt)
+ else if (operation == 3)
+ {
+ if (CONSTVAL(rt) != 0)
+ emit_or_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // or <rd>,CONSTVAL(rt)
+ emit_not_r64(DRCTOP, X86REG(rd)); // not <rd>
+ }
+ }
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_slt - compile a set if less
+ than btween two registers
+
+ slti rD,rS,rT / slti rT,rS,SIMM
+ sltiu rD,rS,rT / sltiu rT,rS,SIMM
+-------------------------------------------------*/
+
+static int compile_slt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned, int immediate)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 destreg = immediate ? RTREG : RDREG;
+ mipsreg_state rd, rs, rt;
+
+ /* if the destination is r0, bail */
+ if (destreg == 0)
+ return TRUE;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if the source is constant, compute as constant */
+ if (ISCONST(rs) && ISCONST(rt))
+ {
+ INT64 result = is_unsigned ? ((UINT32)CONSTVAL(rs) < (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) < (INT32)CONSTVAL(rt));
+ emit_set_constant_value(drc, compiler, desc, destreg, result);
+ }
+
+ /* else do the operation in code */
+ else
+ {
+ UINT8 rsreg = ISCONST(rs) ? REG_RAX : X86REG(rs);
+
+ rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST | ALLOC_DIRTY);
+
+ emit_load_register_value(drc, compiler, rsreg, rs); // mov <rsreg>,<rs>
+ if (ISCONST(rt))
+ emit_cmp_r64_imm(DRCTOP, rsreg, CONSTVAL(rt)); // cmp <rsreg>,<rt>
+ else
+ emit_cmp_r64_r64(DRCTOP, rsreg, X86REG(rt)); // cmp <rsreg>,<rt>
+ emit_setcc_r8(DRCTOP, is_unsigned ? COND_B : COND_L, X86REG(rd)); // setb/l <rd>
+ emit_movzx_r32_r8(DRCTOP, X86REG(rd), X86REG(rd)); // movzx <rd>,<rd>
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_load - compile a memory load
+ instruction
+
+ lb rT,SIMM(rS)
+ lbu rT,SIMM(rS)
+ lh rT,SIMM(rS)
+ lhu rT,SIMM(rS)
+ lw rT,SIMM(rS)
+ lwu rT,SIMM(rS)
+ ld rT,SIMM(rS)
+-------------------------------------------------*/
+
+static int compile_load(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, int is_unsigned)
+{
+ UINT32 op = *desc->opptr.l;
+ mipsreg_state rs, rt;
+ int was_fixed = FALSE;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST);
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD)
+ {
+ UINT8 destreg = (RTREG == 0) ? REG_RAX : X86REG(rt);
+
+ /* perform a fixed read if we can */
+ if (size == 1)
+ was_fixed = emit_fixed_byte_read(drc, compiler, desc, destreg, is_unsigned, CONSTVAL(rs) + SIMMVAL);
+ else if (size == 2)
+ was_fixed = emit_fixed_half_read(drc, compiler, desc, destreg, is_unsigned, CONSTVAL(rs) + SIMMVAL);
+ else if (size == 4)
+ was_fixed = emit_fixed_word_read(drc, compiler, desc, destreg, is_unsigned, CONSTVAL(rs) + SIMMVAL, 0);
+ else
+ was_fixed = emit_fixed_double_read(drc, compiler, desc, destreg, CONSTVAL(rs) + SIMMVAL, 0);
+ }
+
+ /* otherwise, we just need to call the appropriate subroutine */
+ else
+ {
+ if (ISCONST(rs))
+ emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL
+ else
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL]
+ if (size == 1 && is_unsigned)
+ emit_call(DRCTOP, mips3.drcdata->general.read_byte_unsigned); // call general.read_byte_unsigned
+ else if (size == 1 && !is_unsigned)
+ emit_call(DRCTOP, mips3.drcdata->general.read_byte_signed); // call general.read_byte_signed
+ else if (size == 2 && is_unsigned)
+ emit_call(DRCTOP, mips3.drcdata->general.read_half_unsigned); // call general.read_half_unsigned
+ else if (size == 2 && !is_unsigned)
+ emit_call(DRCTOP, mips3.drcdata->general.read_half_signed); // call general.read_half_signed
+ else if (size == 4 && is_unsigned)
+ emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call general.read_word_unsigned
+ else if (size == 4 && !is_unsigned)
+ emit_call(DRCTOP, mips3.drcdata->general.read_word_signed); // call general.read_word_signed
+ else
+ emit_call(DRCTOP, mips3.drcdata->general.read_double); // call general.read_double
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
+ if (RTREG != 0)
+ emit_mov_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // mov <rt>,rax
+ }
+
+ /* only mark dirty after the exception risk is over */
+ compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DIRTY);
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_load_cop - compile a COP memory load
+ instruction
+
+ lwc1 rT,SIMM(rs)
+ lwc2 rT,SIMM(rs)
+ ldc1 rT,SIMM(rs)
+ ldc2 rT,SIMM(rs)
+-------------------------------------------------*/
+
+static int compile_load_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest)
+{
+ UINT32 op = *desc->opptr.l;
+ int was_fixed = FALSE;
+ mipsreg_state rs;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD)
+ {
+ /* perform a fixed read if we can */
+ if (size == 4)
+ was_fixed = emit_fixed_word_read(drc, compiler, desc, REG_RAX, FALSE, CONSTVAL(rs) + SIMMVAL, 0);
+ else
+ was_fixed = emit_fixed_double_read(drc, compiler, desc, REG_RAX, CONSTVAL(rs) + SIMMVAL, 0);
+ }
+
+ /* otherwise, we just need to call the appropriate subroutine */
+ else
+ {
+ if (ISCONST(rs))
+ emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL
+ else
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL]
+ if (size == 4)
+ emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call general.read_word_unsigned
+ else
+ emit_call(DRCTOP, mips3.drcdata->general.read_double); // call general.read_double
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
+ }
+
+ /* complete the load by moving to the destination address */
+ if (size == 4)
+ emit_mov_m32_r32(DRCTOP, MDRC(dest), REG_EAX); // mov [dest],eax
+ else
+ emit_mov_m64_r64(DRCTOP, MDRC(dest), REG_RAX); // mov [dest],rax
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_loadx_cop - compile a COP indexed
+ memory load instruction
+
+ lwxc1 fD,rS,rT
+ ldxc1 fD,rS,rT
+-------------------------------------------------*/
+
+static int compile_loadx_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest)
+{
+ UINT32 op = *desc->opptr.l;
+ int was_fixed = FALSE;
+ mipsreg_state rs, rt;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && ISCONST(rt) && !DISABLE_FIXED_RAM_LOAD)
+ {
+ /* perform a fixed read if we can */
+ if (size == 4)
+ was_fixed = emit_fixed_word_read(drc, compiler, desc, REG_RAX, FALSE, CONSTVAL(rs) + CONSTVAL(rt), 0);
+ else
+ was_fixed = emit_fixed_double_read(drc, compiler, desc, REG_RAX, CONSTVAL(rs) + CONSTVAL(rt), 0);
+ }
+
+ /* otherwise, we just need to call the appropriate subroutine */
+ else
+ {
+ if (ISCONST(rs) && ISCONST(rt))
+ emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + CONSTVAL(rt)); // mov p1,<rs> + <rt>
+ else if (ISCONST(rs))
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rt), CONSTVAL(rs))); // lea p1,[<rt> + <rs>]
+ else if (ISCONST(rt))
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), CONSTVAL(rt))); // lea p1,[<rs> + <rt>]
+ else
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea p1,[<rs> + <rt>]
+ if (size == 4)
+ emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call general.read_word_unsigned
+ else
+ emit_call(DRCTOP, mips3.drcdata->general.read_double); // call general.read_double
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
+ }
+
+ /* complete the load by moving to the destination address */
+ if (size == 4)
+ emit_mov_m32_r32(DRCTOP, MDRC(dest), REG_EAX); // mov [dest],eax
+ else
+ emit_mov_m64_r64(DRCTOP, MDRC(dest), REG_RAX); // mov [dest],rax
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_load_word_partial - compile a lwl/lwr
+ instruction
+
+ lwl rT,SIMM(rS)
+ lwr rT,SIMM(rS)
+-------------------------------------------------*/
+
+static int compile_load_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right)
+{
+ UINT32 op = *desc->opptr.l;
+ int was_fixed = FALSE;
+ mipsreg_state rs, rt;
+
+ /* allocate source/dest registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY);
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD)
+ {
+ INT32 addr = CONSTVAL(rs) + SIMMVAL;
+ int shift = (addr & 3) * 8;
+
+ /* shift the opposite amount depending on right/left and endianness */
+ if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
+ shift ^= 0x18;
+
+ /* read the double value into rax, handling exceptions */
+ was_fixed = emit_fixed_word_read(drc, compiler, desc, REG_RAX, FALSE, addr, is_right ? (~((UINT32)-1 << shift)) : (~((UINT32)-1 >> shift)));
+
+ /* handle writing back the register */
+ if (RTREG != 0)
+ {
+ UINT32 mask = is_right ? (~((UINT32)-1 >> shift)) : (~((UINT32)-1 << shift));
+
+ /* AND rT with the mask */
+ emit_and_r32_imm(DRCTOP, X86REG(rt), mask); // and <rt>,mask
+
+ /* shift and merge rax into the X86REG(rt) */
+ if (!is_right)
+ emit_shl_r32_imm(DRCTOP, REG_EAX, shift); // shl eax,shift
+ else
+ emit_shr_r32_imm(DRCTOP, REG_EAX, shift); // shr eax,shift
+ emit_or_r32_r32(DRCTOP, X86REG(rt), REG_EAX); // or <rtdst>,eax
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rt), X86REG(rt)); // movsxd <rt>,<rt>
+ }
+ }
+
+ /* otherwise, we need to compute everything at runtime */
+ else
+ {
+ /* compute the address and mask values */
+ if (ISCONST(rs))
+ emit_mov_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rs) + SIMMVAL); // mov eax,<rs> + SIMMVAL
+ else
+ emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL]
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8]
+ emit_or_r32_imm(DRCTOP, REG_P2, -1); // or p2,-1
+ if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
+ if (!is_right)
+ emit_shr_r32_cl(DRCTOP, REG_P2); // shr p2,cl
+ else
+ emit_shl_r32_cl(DRCTOP, REG_P2); // shl p2,cl
+ emit_mov_m8_r8(DRCTOP, MBD(REG_RSP, SPOFFS_SAVECL), REG_CL); // mov [sp+savecl],cl
+ emit_not_r32(DRCTOP, REG_P2); // not p2
+ emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax
+ emit_call(DRCTOP, mips3.drcdata->general.read_word_masked); // call general.read_word_masked
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
+
+ /* handle writing back the register */
+ if (RTREG != 0)
+ {
+ /* recompute the mask */
+ emit_mov_r8_m8(DRCTOP, REG_CL, MBD(REG_RSP, SPOFFS_SAVECL)); // mov cl,[sp+savecl]
+ emit_or_r32_imm(DRCTOP, REG_P2, -1); // or p2,-1
+ if (!is_right)
+ emit_shl_r32_cl(DRCTOP, REG_P2); // shl p2,cl
+ else
+ emit_shr_r32_cl(DRCTOP, REG_P2); // shr p2,cl
+
+ /* apply the shifts and masks */
+ emit_not_r32(DRCTOP, REG_P2); // not p2
+ if (!is_right)
+ emit_shl_r32_cl(DRCTOP, REG_RAX); // shl rax,cl
+ else
+ emit_shr_r32_cl(DRCTOP, REG_RAX); // shr rax,cl
+ emit_and_r32_r32(DRCTOP, X86REG(rt), REG_P2); // and <rt>,p2
+ emit_or_r32_r32(DRCTOP, X86REG(rt), REG_RAX); // or <rt>,rax
+ emit_movsxd_r64_r32(DRCTOP, X86REG(rt), X86REG(rt)); // movsxd <rt>,<rt>
+ }
+ }
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_load_double_partial - compile a
+ ldl/ldr instruction
+
+ ldl rT,SIMM(rS)
+ ldr rT,SIMM(rS)
+-------------------------------------------------*/
+
+static int compile_load_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right)
+{
+ UINT32 op = *desc->opptr.l;
+ int was_fixed = FALSE;
+ mipsreg_state rs, rt;
+
+ /* allocate source/dest registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY);
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD)
+ {
+ INT32 addr = CONSTVAL(rs) + SIMMVAL;
+ int shift = (addr & 7) * 8;
+
+ /* shift the opposite amount depending on right/left and endianness */
+ if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
+ shift ^= 0x38;
+
+ /* read the double value into rax, handling exceptions */
+ was_fixed = emit_fixed_double_read(drc, compiler, desc, REG_RAX, addr, is_right ? (~((UINT64)-1 << shift)) : (~((UINT64)-1 >> shift)));
+
+ /* handle writing back the register */
+ if (RTREG != 0)
+ {
+ UINT64 mask = is_right ? (~((UINT64)-1 >> shift)) : (~((UINT64)-1 << shift));
+
+ /* AND rT with the mask, using 32 bits if we can */
+ if ((INT32)mask == (INT64)mask)
+ emit_and_r64_imm(DRCTOP, X86REG(rt), (INT32)mask); // and <rt>,mask
+ else
+ {
+ emit_mov_r64_imm(DRCTOP, REG_P2, mask); // mov p2,mask
+ emit_and_r64_r64(DRCTOP, X86REG(rt), REG_P2); // and <rt>,p2
+ }
+
+ /* shift and merge rax into the X86REG(rt) */
+ if (!is_right)
+ emit_shl_r64_imm(DRCTOP, REG_RAX, shift); // shl rax,shift
+ else
+ emit_shr_r64_imm(DRCTOP, REG_RAX, shift); // shr rax,shift
+ emit_or_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // or <rt>,rax
+ }
+ }
+
+ /* otherwise, we need to compute everything at runtime */
+ else
+ {
+ /* compute the address and mask values */
+ if (ISCONST(rs))
+ emit_mov_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rs) + SIMMVAL); // mov eax,<rs> + SIMMVAL
+ else
+ emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL]
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8]
+ emit_or_r64_imm(DRCTOP, REG_P2, -1); // or p2,-1
+ if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x38); // xor ecx,0x38
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
+ if (!is_right)
+ emit_shr_r64_cl(DRCTOP, REG_P2); // shr p2,cl
+ else
+ emit_shl_r64_cl(DRCTOP, REG_P2); // shl p2,cl
+ emit_mov_m8_r8(DRCTOP, MBD(REG_RSP, SPOFFS_SAVECL), REG_CL); // mov [sp+savecl],cl
+ emit_not_r64(DRCTOP, REG_P2); // not p2
+ emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax
+ emit_call(DRCTOP, mips3.drcdata->general.read_double_masked); // call general.read_double_masked
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
+
+ /* handle writing back the register */
+ if (RTREG != 0)
+ {
+ /* recompute the mask */
+ emit_mov_r8_m8(DRCTOP, REG_CL, MBD(REG_RSP, SPOFFS_SAVECL)); // mov cl,[sp+savecl]
+ emit_or_r64_imm(DRCTOP, REG_P2, -1); // or p2,-1
+ if (!is_right)
+ emit_shl_r64_cl(DRCTOP, REG_P2); // shl p2,cl
+ else
+ emit_shr_r64_cl(DRCTOP, REG_P2); // shr p2,cl
+
+ /* apply the shifts and masks */
+ emit_not_r64(DRCTOP, REG_P2); // not p2
+ if (!is_right)
+ emit_shl_r64_cl(DRCTOP, REG_RAX); // shl rax,cl
+ else
+ emit_shr_r64_cl(DRCTOP, REG_RAX); // shr rax,cl
+ emit_and_r64_r64(DRCTOP, X86REG(rt), REG_P2); // and <rt>,p2
+ emit_or_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // or <rt>,rax
+ }
+ }
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_store - compile a memory store
+ instruction
+
+ sb rT,SIMM(rS)
+ sh rT,SIMM(rS)
+ sw rT,SIMM(rS)
+ sd rT,SIMM(rS)
+-------------------------------------------------*/
+
+static int compile_store(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size)
+{
+ UINT32 op = *desc->opptr.l;
+ int was_fixed = FALSE;
+ mipsreg_state rs, rt;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE)
+ {
+ /* perform a fixed write if we can */
+ if (size == 1)
+ was_fixed = emit_fixed_byte_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL);
+ else if (size == 2)
+ was_fixed = emit_fixed_half_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL);
+ else if (size == 4)
+ was_fixed = emit_fixed_word_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL, 0);
+ else
+ was_fixed = emit_fixed_double_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL, 0);
+ }
+
+ /* otherwise, we just need to call the appropriate subroutine */
+ else
+ {
+ if (ISCONST(rs))
+ emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL
+ else
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL]
+ emit_load_register_value(drc, compiler, REG_P2, rt); // mov p2,<rt>
+ if (size == 1)
+ emit_call(DRCTOP, mips3.drcdata->general.write_byte); // call general.write_byte
+ else if (size == 2)
+ emit_call(DRCTOP, mips3.drcdata->general.write_half); // call general.write_half
+ else if (size == 4)
+ emit_call(DRCTOP, mips3.drcdata->general.write_word); // call general.write_word
+ else if (size == 8)
+ emit_call(DRCTOP, mips3.drcdata->general.write_double); // call general.write_double
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
+ }
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_store_cop - compile a COP memory
+ store instruction
+
+ swc1 rT,SIMM(rs)
+ swc2 rT,SIMM(rs)
+ sdc1 rT,SIMM(rs)
+ sdc2 rT,SIMM(rs)
+-------------------------------------------------*/
+
+static int compile_store_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src)
+{
+ UINT32 op = *desc->opptr.l;
+ int was_fixed = FALSE;
+ mipsreg_state rs;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+
+ /* load the value into P2 */
+ if (size == 4)
+ emit_mov_r32_m32(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src]
+ else
+ emit_mov_r64_m64(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src]
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE)
+ {
+ /* perform a fixed write if we can */
+ if (size == 4)
+ was_fixed = emit_fixed_word_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + SIMMVAL, 0);
+ else
+ was_fixed = emit_fixed_double_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + SIMMVAL, 0);
+ }
+
+ /* otherwise, we just need to call the appropriate subroutine */
+ else
+ {
+ if (ISCONST(rs))
+ emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL
+ else
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL]
+ if (size == 4)
+ emit_call(DRCTOP, mips3.drcdata->general.write_word); // call general.write_word
+ else if (size == 8)
+ emit_call(DRCTOP, mips3.drcdata->general.write_double); // call general.write_double
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
+ }
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_storex_cop - compile a COP indexed
+ memory store instruction
+
+ swxc1 fD,rS,rT
+ sdxc1 fD,rS,rT
+-------------------------------------------------*/
+
+static int compile_storex_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src)
+{
+ UINT32 op = *desc->opptr.l;
+ int was_fixed = FALSE;
+ mipsreg_state rs, rt;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* load the value into P2 */
+ if (size == 4)
+ emit_mov_r32_m32(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src]
+ else
+ emit_mov_r64_m64(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src]
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && ISCONST(rt) && !DISABLE_FIXED_RAM_STORE)
+ {
+ /* perform a fixed write if we can */
+ if (size == 4)
+ was_fixed = emit_fixed_word_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + CONSTVAL(rt), 0);
+ else
+ was_fixed = emit_fixed_double_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + CONSTVAL(rt), 0);
+ }
+
+ /* otherwise, we just need to call the appropriate subroutine */
+ else
+ {
+ if (ISCONST(rs) && ISCONST(rt))
+ emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + CONSTVAL(rt)); // mov p1,<rs> + <rt>
+ else if (ISCONST(rs))
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rt), CONSTVAL(rs))); // lea p1,[<rt> + <rs>]
+ else if (ISCONST(rt))
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), CONSTVAL(rt))); // lea p1,[<rs> + <rt>]
+ else
+ emit_lea_r32_m32(DRCTOP, REG_P1, MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea p1,[<rs> + <rt>]
+ if (size == 4)
+ emit_call(DRCTOP, mips3.drcdata->general.write_word); // call general.write_word
+ else if (size == 8)
+ emit_call(DRCTOP, mips3.drcdata->general.write_double); // call general.write_double
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
+ }
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_store_word_partial - compile a swl/swr
+ instruction
+
+ swl rT,SIMM(rS)
+ swr rT,SIMM(rS)
+-------------------------------------------------*/
+
+static int compile_store_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right)
+{
+ UINT32 op = *desc->opptr.l;
+ int was_fixed = FALSE;
+ mipsreg_state rs, rt;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE)
+ {
+ INT32 addr = CONSTVAL(rs) + SIMMVAL;
+ int shift = (addr & 3) * 8;
+ UINT32 mask;
+
+ /* shift the opposite amount depending on right/left and endianness */
+ if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
+ shift ^= 0x18;
+
+ /* if rT is not constant, load and shift it */
+ if (!ISCONST(rt))
+ {
+ emit_mov_r32_r32(DRCTOP, REG_EAX, X86REG(rt)); // mov eax,X86REG(rt)
+ emit_shr_r32_imm(DRCTOP, REG_EAX, shift); // shr eax,shift
+ rt = MAKE_DESTREG(REG_EAX);
+ }
+
+ /* compute shifted value and mask */
+ if (!is_right)
+ {
+ if (ISCONST(rt))
+ rt = MAKE_CONST((UINT32)CONSTVAL(rt) >> shift);
+ mask = ~((UINT64)-1 >> shift);
+ }
+ else
+ {
+ if (ISCONST(rt))
+ rt = MAKE_CONST((UINT32)CONSTVAL(rt) << shift);
+ mask = ~((UINT64)-1 << shift);
+ }
+
+ /* perform a fixed write */
+ was_fixed = emit_fixed_word_write(drc, compiler, desc, rt, addr & ~3, mask);
+ }
+
+ /* otherwise, we need to compute everything at runtime */
+ else
+ {
+ /* compute the address and mask values */
+ emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL]
+ emit_or_r32_imm(DRCTOP, REG_P3, -1); // or p3,-1
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8]
+ emit_load_register_value(drc, compiler, REG_P2, rt); // mov p2,<rt>
+ if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
+ if (!is_right)
+ {
+ emit_shr_r32_cl(DRCTOP, REG_P3); // shr p3,cl
+ emit_shr_r32_cl(DRCTOP, REG_P2); // shr p2,cl
+ }
+ else
+ {
+ emit_shl_r32_cl(DRCTOP, REG_P3); // shl p3,cl
+ emit_shl_r32_cl(DRCTOP, REG_P2); // shl p2,cl
+ }
+ emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax
+ emit_not_r32(DRCTOP, REG_P3); // not p3
+
+ /* perform the write */
+ emit_call(DRCTOP, mips3.drcdata->general.write_word_masked); // call general.write_word_masked
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
+ }
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ compile_store_double_partial - compile a
+ sdl/sdr instruction
+
+ sdl rT,SIMM(rS)
+ sdr rT,SIMM(rS)
+-------------------------------------------------*/
+
+static int compile_store_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right)
+{
+ UINT32 op = *desc->opptr.l;
+ int was_fixed = FALSE;
+ mipsreg_state rs, rt;
+
+ /* allocate source registers */
+ rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
+ rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
+
+ /* if rS is constant, we know the address at compile time; this simplifies the code */
+ if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE)
+ {
+ INT32 addr = CONSTVAL(rs) + SIMMVAL;
+ int shift = (addr & 7) * 8;
+ UINT64 mask;
+
+ /* shift the opposite amount depending on right/left and endianness */
+ if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
+ shift ^= 0x38;
+
+ /* if rT is not constant, load and shift it */
+ if (!ISCONST(rt))
+ {
+ emit_mov_r64_r64(DRCTOP, REG_RAX, X86REG(rt)); // mov rax,X86REG(rt)
+ emit_shr_r64_imm(DRCTOP, REG_RAX, shift); // shr rax,shift
+ rt = MAKE_DESTREG(REG_RAX);
+ }
+
+ /* compute shifted value and mask */
+ if (!is_right)
+ {
+ if (ISCONST(rt))
+ rt = MAKE_CONST((UINT64)CONSTVAL(rt) >> shift);
+ mask = ~((UINT64)-1 >> shift);
+ }
+ else
+ {
+ if (ISCONST(rt))
+ rt = MAKE_CONST((UINT64)CONSTVAL(rt) << shift);
+ mask = ~((UINT64)-1 << shift);
+ }
+
+ /* perform a fixed write */
+ was_fixed = emit_fixed_double_write(drc, compiler, desc, rt, addr & ~7, mask);
+ }
+
+ /* otherwise, we need to compute everything at runtime */
+ else
+ {
+ /* compute the address and mask values */
+ emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL]
+ emit_or_r64_imm(DRCTOP, REG_P3, -1); // or p3,-1
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8]
+ emit_load_register_value(drc, compiler, REG_P2, rt); // mov p2,<rt>
+ if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x38); // xor ecx,0x38
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
+ if (!is_right)
+ {
+ emit_shr_r64_cl(DRCTOP, REG_P3); // shr p3,cl
+ emit_shr_r64_cl(DRCTOP, REG_P2); // shr p2,cl
+ }
+ else
+ {
+ emit_shl_r64_cl(DRCTOP, REG_P3); // shl p3,cl
+ emit_shl_r64_cl(DRCTOP, REG_P2); // shl p2,cl
+ }
+ emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax
+ emit_not_r64(DRCTOP, REG_P3); // not p3
+
+ /* perform the write */
+ emit_call(DRCTOP, mips3.drcdata->general.write_double_masked); // call general.write_double_masked
+ oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
+ }
+
+ /* update cycle counts */
+ if (!was_fixed)
+ emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
+ return TRUE;
+}
diff --git a/src/emu/cpu/mips/mdrcold.c b/src/emu/cpu/mips/mdrcold.c
new file mode 100644
index 00000000000..d960eae06c0
--- /dev/null
+++ b/src/emu/cpu/mips/mdrcold.c
@@ -0,0 +1,4883 @@
+
+
+/***************************************************************************
+ CONFIGURATION
+***************************************************************************/
+
+#define STRIP_NOPS 1 /* 1 is faster */
+#define USE_SSE 0 /* can't tell any speed difference here */
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_INSTRUCTIONS ((512 + 128) / 4)
+
+/* recompiler flags */
+#define RECOMPILE_UNIMPLEMENTED 0x0000
+#define RECOMPILE_SUCCESSFUL 0x0001
+#define RECOMPILE_SUCCESSFUL_CP(c,p) (RECOMPILE_SUCCESSFUL | (((c) & 0xfff) << 8) | (((p) & 0xfff) << 20))
+#define RECOMPILE_MAY_CAUSE_EXCEPTION 0x0002
+#define RECOMPILE_END_OF_STRING 0x0004
+#define RECOMPILE_CHECK_INTERRUPTS 0x0008
+#define RECOMPILE_CHECK_SW_INTERRUPTS 0x0010
+#define RECOMPILE_ADD_DISPATCH 0x0020
+
+/* append_readwrite flags */
+#define ARW_READ 0x0000
+#define ARW_WRITE 0x0001
+#define ARW_UNSIGNED 0x0000
+#define ARW_SIGNED 0x0002
+#define ARW_MASKED 0x0004
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define REGDISP(reg) (offsetof(mips3_state, r[reg]) - offsetof(mips3_state, r[17]))
+#define REGADDR(reg) MBD(REG_ESI, REGDISP(reg))
+#define REGADDRLO(reg) MBD(REG_ESI, REGDISP(reg))
+#define REGADDRHI(reg) MBD(REG_ESI, REGDISP(reg)+4)
+
+#define HIADDR REGADDR(REG_HI)
+#define HIADDRLO REGADDRLO(REG_HI)
+#define HIADDRHI REGADDRHI(REG_HI)
+
+#define LOADDR REGADDR(REG_LO)
+#define LOADDRLO REGADDRLO(REG_LO)
+#define LOADDRHI REGADDRHI(REG_LO)
+
+#define CPR0ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg])
+#define CPR0ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg])
+#define CPR0ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg] + 4)
+
+#define CCR0ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg])
+#define CCR0ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg])
+#define CCR0ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg] + 4)
+
+#define CPR1ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg])
+#define CPR1ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg])
+#define CPR1ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg] + 4)
+
+#define CCR1ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg])
+#define CCR1ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg])
+#define CCR1ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg] + 4)
+
+#define CPR2ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg])
+#define CPR2ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg])
+#define CPR2ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg] + 4)
+
+#define CCR2ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg])
+#define CCR2ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg])
+#define CCR2ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg] + 4)
+
+#define FPR32(reg) (IS_FR0 ? &((float *)&mips3.core->cpr[1][0])[reg] : (float *)&mips3.core->cpr[1][reg])
+#define FPR32ADDR(reg) MABS(FPR32(reg))
+#define FPR32ADDRLO(reg) MABS(FPR32(reg))
+#define FPR32ADDRHI(reg) MABS((UINT8 *)FPR32(reg) + 4)
+
+#define FPR64(reg) (IS_FR0 ? (double *)&mips3.core->cpr[1][(reg)/2] : (double *)&mips3.core->cpr[1][reg])
+#define FPR64ADDR(reg) MABS(FPR64(reg))
+#define FPR64ADDR(reg) MABS(FPR64(reg))
+#define FPR64ADDRLO(reg) MABS(FPR64(reg))
+#define FPR64ADDRHI(reg) MABS((UINT8 *)FPR64(reg) + 4)
+
+#define CF1ADDR(which) MABS(&mips3.core->cf[1][(mips3.core->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : (which)])
+
+#define ICOUNTADDR MABS(&mips3.core->icount)
+
+
+/***************************************************************************
+ USEFUL PRIMITIVES
+***************************************************************************/
+
+INLINE void emit_mov_r64_m64(x86code **emitptr, UINT8 reghi, UINT8 reglo, DECLARE_MEMPARAMS)
+{
+ emit_mov_r32_m32(emitptr, reglo, MEMPARAMS);
+ emit_mov_r32_m32(emitptr, reghi, base, index, scale, disp+4);
+}
+
+INLINE void emit_mov_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 reghi, UINT8 reglo)
+{
+ emit_mov_m32_r32(emitptr, MEMPARAMS, reglo);
+ emit_mov_m32_r32(emitptr, base, index, scale, disp+4, reghi);
+}
+
+INLINE void emit_mov_m64_imm32(x86code **emitptr, DECLARE_MEMPARAMS, INT32 imm)
+{
+ emit_mov_m32_imm(emitptr, MEMPARAMS, imm);
+ emit_mov_m32_imm(emitptr, base, index, scale, disp+4, (INT32)imm >> 31);
+}
+
+INLINE void emit_zero_m64(x86code **emitptr, DECLARE_MEMPARAMS)
+{
+ if (USE_SSE)
+ {
+ emit_xorpd_r128_r128(emitptr, REG_XMM0, REG_XMM0);
+ emit_movsd_m64_r128(emitptr, MEMPARAMS, REG_XMM0);
+ }
+ else
+ emit_mov_m64_imm32(emitptr, MEMPARAMS, 0);
+}
+
+INLINE void emit_mov_m64_m64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 base2, UINT8 index2, UINT8 scale2, INT32 disp2)
+{
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(emitptr, REG_XMM0, base2, index2, scale2, disp2);
+ emit_movsd_m64_r128(emitptr, MEMPARAMS, REG_XMM0);
+ }
+ else
+ {
+ emit_mov_r64_m64(emitptr, REG_EDX, REG_EAX, base2, index2, scale2, disp2);
+ emit_mov_m64_r64(emitptr, MEMPARAMS, REG_EDX, REG_EAX);
+ }
+}
+
+#define emit_save_pc_before_call(e) \
+do { \
+ if (mips3.drcoptions & MIPS3DRC_FLUSH_PC) \
+ emit_mov_m32_r32(e, MABS(drc->pcptr), REG_EDI); \
+} while (0)
+
+
+
+
+/***************************************************************************
+ TYPEDEFS
+***************************************************************************/
+
+struct _mips3drc_data
+{
+ x86code * generate_interrupt_exception;
+ x86code * generate_cop_exception;
+ x86code * generate_overflow_exception;
+ x86code * generate_invalidop_exception;
+ x86code * generate_syscall_exception;
+ x86code * generate_break_exception;
+ x86code * generate_trap_exception;
+ x86code * generate_tlbload_exception;
+ x86code * generate_tlbstore_exception;
+ x86code * handle_pc_tlb_mismatch;
+ x86code * read_and_translate_byte_signed;
+ x86code * read_and_translate_byte_unsigned;
+ x86code * read_and_translate_half_signed;
+ x86code * read_and_translate_half_unsigned;
+ x86code * read_and_translate_word;
+ x86code * read_and_translate_word_masked;
+ x86code * read_and_translate_double;
+ x86code * read_and_translate_double_masked;
+ x86code * write_and_translate_byte;
+ x86code * write_and_translate_half;
+ x86code * write_and_translate_word;
+ x86code * write_and_translate_word_masked;
+ x86code * write_and_translate_double;
+ x86code * write_and_translate_double_masked;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void drc_reset_callback(drc_core *drc);
+static void drc_recompile_callback(drc_core *drc);
+static void drc_entrygen_callback(drc_core *drc);
+
+static UINT32 compile_one(drc_core *drc, UINT32 pc, UINT32 physpc);
+
+static void append_generate_exception(drc_core *drc, UINT8 exception);
+static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags);
+static void append_tlb_verify(drc_core *drc, UINT32 pc, void *target);
+static void append_update_cycle_counting(drc_core *drc);
+static void append_check_interrupts(drc_core *drc, int inline_generate);
+static void append_check_sw_interrupts(drc_core *drc, int inline_generate);
+
+static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 physpc);
+static UINT32 recompile_special(drc_core *drc, UINT32 pc, UINT32 op);
+static UINT32 recompile_regimm(drc_core *drc, UINT32 pc, UINT32 op);
+
+static UINT32 recompile_cop0(drc_core *drc, UINT32 pc, UINT32 op);
+static UINT32 recompile_cop1(drc_core *drc, UINT32 pc, UINT32 op);
+static UINT32 recompile_cop1x(drc_core *drc, UINT32 pc, UINT32 op);
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static UINT64 dmult_temp1;
+static UINT64 dmult_temp2;
+static UINT32 jr_temp;
+
+static UINT8 in_delay_slot = 0;
+
+
+
+/***************************************************************************
+ CORE RECOMPILER SYSTEMS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mips3drc_init - initialize the drc-specific
+ state
+-------------------------------------------------*/
+
+static void mips3drc_init(void)
+{
+ drc_config drconfig;
+
+ /* fill in the config */
+ memset(&drconfig, 0, sizeof(drconfig));
+ drconfig.cache_base = mips3.cache;
+ drconfig.cache_size = CACHE_SIZE;
+ drconfig.max_instructions = MAX_INSTRUCTIONS;
+ drconfig.address_bits = 32;
+ drconfig.lsbs_to_ignore = 2;
+ drconfig.uses_fp = 1;
+ drconfig.uses_sse = USE_SSE;
+ drconfig.pc_in_memory = 0;
+ drconfig.icount_in_memory = 0;
+ drconfig.pcptr = (UINT32 *)&mips3.core->pc;
+ drconfig.icountptr = (UINT32 *)&mips3.core->icount;
+ drconfig.esiptr = NULL;
+ drconfig.cb_reset = drc_reset_callback;
+ drconfig.cb_recompile = drc_recompile_callback;
+ drconfig.cb_entrygen = drc_entrygen_callback;
+
+ /* initialize the compiler */
+ mips3.drc = drc_init(cpu_getactivecpu(), &drconfig);
+ mips3.drcoptions = MIPS3DRC_FASTEST_OPTIONS;
+
+ /* allocate our data out of the cache */
+ mips3.drcdata = drc_alloc(mips3.drc, sizeof(*mips3.drcdata));
+ memset(mips3.drcdata, 0, sizeof(*mips3.drcdata));
+}
+
+
+/*-------------------------------------------------
+ mips3drc_exit - clean up the drc-specific
+ state
+-------------------------------------------------*/
+
+static void mips3drc_exit(void)
+{
+}
+
+
+
+/***************************************************************************
+ RECOMPILER CALLBACKS
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ drc_reset_callback
+------------------------------------------------------------------*/
+
+static void drc_reset_callback(drc_core *drc)
+{
+ if (LOG_CODE)
+ {
+ x86log_disasm_code_range(mips3.log, "entry_point:", (x86code *)drc->entry_point, drc->out_of_cycles);
+ x86log_disasm_code_range(mips3.log, "out_of_cycles:", drc->out_of_cycles, drc->recompile);
+ x86log_disasm_code_range(mips3.log, "recompile:", drc->recompile, drc->dispatch);
+ x86log_disasm_code_range(mips3.log, "dispatch:", drc->dispatch, drc->flush);
+ x86log_disasm_code_range(mips3.log, "flush:", drc->flush, drc->cache_top);
+ }
+
+ mips3.drcdata->generate_interrupt_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_INTERRUPT);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_interrupt_exception:", mips3.drcdata->generate_interrupt_exception, drc->cache_top);
+
+ mips3.drcdata->generate_cop_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_BADCOP);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_cop_exception:", mips3.drcdata->generate_cop_exception, drc->cache_top);
+
+ mips3.drcdata->generate_overflow_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_OVERFLOW);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_overflow_exception:", mips3.drcdata->generate_overflow_exception, drc->cache_top);
+
+ mips3.drcdata->generate_invalidop_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_INVALIDOP);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_invalidop_exception:", mips3.drcdata->generate_invalidop_exception, drc->cache_top);
+
+ mips3.drcdata->generate_syscall_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_SYSCALL);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_syscall_exception:", mips3.drcdata->generate_syscall_exception, drc->cache_top);
+
+ mips3.drcdata->generate_break_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_BREAK);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_break_exception:", mips3.drcdata->generate_break_exception, drc->cache_top);
+
+ mips3.drcdata->generate_trap_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_TRAP);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_trap_exception:", mips3.drcdata->generate_trap_exception, drc->cache_top);
+
+ mips3.drcdata->generate_tlbload_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_TLBLOAD);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_tlbload_exception:", mips3.drcdata->generate_tlbload_exception, drc->cache_top);
+
+ mips3.drcdata->generate_tlbstore_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_TLBSTORE);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "generate_tlbstore_exception:", mips3.drcdata->generate_tlbstore_exception, drc->cache_top);
+
+ mips3.drcdata->handle_pc_tlb_mismatch = drc->cache_top;
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi
+ emit_shr_r32_imm(DRCTOP, REG_EAX, 12); // shr eax,12
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MISD(REG_EAX, 4, mips3.core->tlb_table)); // mov ebx,tlb_table[eax*4]
+ emit_test_r32_imm(DRCTOP, REG_EBX, 2); // test ebx,2
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi
+ emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_tlbload_exception); // jnz generate_tlbload_exception
+ emit_mov_m32_r32(DRCTOP, MABS(drc->pcptr), REG_EDI); // mov [pcptr],edi
+ emit_jmp(DRCTOP, drc->recompile); // jmp recompile
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "handle_pc_tlb_mismatch:", mips3.drcdata->handle_pc_tlb_mismatch, drc->cache_top);
+
+ mips3.drcdata->read_and_translate_byte_signed = drc->cache_top;
+ append_readwrite_and_translate(drc, 1, ARW_READ | ARW_SIGNED);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "read_and_translate_byte_signed:", mips3.drcdata->read_and_translate_byte_signed, drc->cache_top);
+
+ mips3.drcdata->read_and_translate_byte_unsigned = drc->cache_top;
+ append_readwrite_and_translate(drc, 1, ARW_READ | ARW_UNSIGNED);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "read_and_translate_byte_unsigned:", mips3.drcdata->read_and_translate_byte_unsigned, drc->cache_top);
+
+ mips3.drcdata->read_and_translate_half_signed = drc->cache_top;
+ append_readwrite_and_translate(drc, 2, ARW_READ | ARW_SIGNED);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "read_and_translate_half_signed:", mips3.drcdata->read_and_translate_half_signed, drc->cache_top);
+
+ mips3.drcdata->read_and_translate_half_unsigned = drc->cache_top;
+ append_readwrite_and_translate(drc, 2, ARW_READ | ARW_UNSIGNED);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "read_and_translate_half_unsigned:", mips3.drcdata->read_and_translate_half_unsigned, drc->cache_top);
+
+ mips3.drcdata->read_and_translate_word = drc->cache_top;
+ append_readwrite_and_translate(drc, 4, ARW_READ);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "read_and_translate_word:", mips3.drcdata->read_and_translate_word, drc->cache_top);
+
+ mips3.drcdata->read_and_translate_word_masked = drc->cache_top;
+ append_readwrite_and_translate(drc, 4, ARW_READ | ARW_MASKED);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "read_and_translate_word_masked:", mips3.drcdata->read_and_translate_word_masked, drc->cache_top);
+
+ mips3.drcdata->read_and_translate_double = drc->cache_top;
+ append_readwrite_and_translate(drc, 8, ARW_READ);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "read_and_translate_double:", mips3.drcdata->read_and_translate_double, drc->cache_top);
+
+ mips3.drcdata->read_and_translate_double_masked = drc->cache_top;
+ append_readwrite_and_translate(drc, 8, ARW_READ | ARW_MASKED);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "read_and_translate_double_masked:", mips3.drcdata->read_and_translate_double_masked, drc->cache_top);
+
+ mips3.drcdata->write_and_translate_byte = drc->cache_top;
+ append_readwrite_and_translate(drc, 1, ARW_WRITE);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "write_and_translate_byte:", mips3.drcdata->write_and_translate_byte, drc->cache_top);
+
+ mips3.drcdata->write_and_translate_half = drc->cache_top;
+ append_readwrite_and_translate(drc, 2, ARW_WRITE);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "write_and_translate_half:", mips3.drcdata->write_and_translate_half, drc->cache_top);
+
+ mips3.drcdata->write_and_translate_word = drc->cache_top;
+ append_readwrite_and_translate(drc, 4, ARW_WRITE);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "write_and_translate_word:", mips3.drcdata->write_and_translate_word, drc->cache_top);
+
+ mips3.drcdata->write_and_translate_word_masked = drc->cache_top;
+ append_readwrite_and_translate(drc, 4, ARW_WRITE | ARW_MASKED);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "write_and_translate_word_masked:", mips3.drcdata->write_and_translate_word_masked, drc->cache_top);
+
+ mips3.drcdata->write_and_translate_double = drc->cache_top;
+ append_readwrite_and_translate(drc, 8, ARW_WRITE);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "write_and_translate_double:", mips3.drcdata->write_and_translate_double, drc->cache_top);
+
+ mips3.drcdata->write_and_translate_double_masked = drc->cache_top;
+ append_readwrite_and_translate(drc, 8, ARW_WRITE | ARW_MASKED);
+ if (LOG_CODE)
+ x86log_disasm_code_range(mips3.log, "write_and_translate_double_masked:", mips3.drcdata->write_and_translate_double_masked, drc->cache_top);
+}
+
+
+/*------------------------------------------------------------------
+ drc_recompile_callback
+------------------------------------------------------------------*/
+
+static void drc_recompile_callback(drc_core *drc)
+{
+ int remaining = MAX_INSTRUCTIONS;
+ x86code *start = drc->cache_top;
+ UINT32 pc = mips3.core->pc;
+ UINT32 lastpc = pc;
+ UINT32 physpc;
+
+ (void)start;
+
+ /* begin the sequence */
+ drc_begin_sequence(drc, pc);
+
+ /* make sure our FR flag matches the last time */
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_FR); // test [COP0_Status],SR_FR
+ emit_jcc(DRCTOP, IS_FR0 ? COND_NZ : COND_Z, drc->recompile); // jnz/z recompile
+
+ /* ensure that we are still mapped */
+ append_tlb_verify(drc, pc, mips3.drcdata->handle_pc_tlb_mismatch);
+ physpc = pc;
+ if (!mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc))
+ {
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi
+ emit_jmp(DRCTOP, mips3.drcdata->generate_tlbload_exception); // jmp tlbload_exception
+ goto exit;
+ }
+ change_pc(physpc);
+
+ /* loose verification case: one verification here only */
+ if (!(mips3.drcoptions & MIPS3DRC_STRICT_VERIFY))
+ drc_append_verify_code(drc, cpu_opptr(physpc), 4);
+
+ /* loop until we hit an unconditional branch */
+ while (--remaining != 0)
+ {
+ UINT32 result;
+
+ /* if we crossed a page boundary, check the mapping */
+ if ((pc ^ lastpc) & 0xfffff000)
+ {
+ physpc = pc;
+ if (!mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc))
+ break;
+ append_tlb_verify(drc, pc, drc->dispatch);
+ change_pc(physpc);
+ }
+
+ /* compile one instruction */
+ physpc = (physpc & 0xfffff000) | (pc & 0xfff);
+ result = compile_one(drc, pc, physpc);
+ lastpc = pc;
+ pc += (INT32)result >> 20;
+ if (result & RECOMPILE_END_OF_STRING)
+ break;
+ }
+
+ /* add dispatcher just in case */
+ if (remaining == 0)
+ drc_append_dispatcher(drc);
+
+exit:
+ /* end the sequence */
+ drc_end_sequence(drc);
+
+ /* log the generated code */
+ if (LOG_CODE)
+ {
+ char label[60];
+ physpc = mips3.core->pc;
+ mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc);
+ sprintf(label, "Code @ %08X (%08X physical)", mips3.core->pc, physpc);
+ x86log_disasm_code_range(mips3.log, label, start, drc->cache_top);
+ }
+}
+
+
+/*------------------------------------------------------------------
+ drc_entrygen_callback
+------------------------------------------------------------------*/
+
+static void drc_entrygen_callback(drc_core *drc)
+{
+ emit_mov_r32_imm(DRCTOP, REG_ESI, (FPTR)&mips3.core->r[17]);
+ append_check_interrupts(drc, 1);
+}
+
+
+
+/***************************************************************************
+ RECOMPILER CORE
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ compile_one
+------------------------------------------------------------------*/
+
+static UINT32 compile_one(drc_core *drc, UINT32 pc, UINT32 physpc)
+{
+ int pcdelta, cycles, hotnum;
+ UINT32 *opptr;
+ UINT32 result;
+
+ /* register this instruction */
+ drc_register_code_at_cache_top(drc, pc);
+
+ /* get a pointer to the current instruction */
+ change_pc(physpc);
+ opptr = cpu_opptr(physpc);
+
+ /* emit debugging and self-modifying code checks */
+ drc_append_call_debugger(drc);
+ if (mips3.drcoptions & MIPS3DRC_STRICT_VERIFY)
+ drc_append_verify_code(drc, opptr, 4);
+
+ /* is this a hotspot? */
+ for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++)
+ if (pc == mips3.hotspot[hotnum].pc && *(UINT32 *)opptr == mips3.hotspot[hotnum].opcode)
+ break;
+
+ /* compile the instruction */
+ result = recompile_instruction(drc, pc, physpc);
+
+ /* handle the results */
+ if (!(result & RECOMPILE_SUCCESSFUL))
+ fatalerror("Unimplemented op %08X (%02X,%02X)", *opptr, *opptr >> 26, *opptr & 0x3f);
+
+ pcdelta = (INT32)result >> 20;
+ cycles = (result >> 8) & 0xfff;
+
+ /* absorb any NOPs following */
+ if (STRIP_NOPS && !Machine->debug_mode)
+ {
+ if (!(result & (RECOMPILE_END_OF_STRING | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_CHECK_SW_INTERRUPTS)))
+ while ((((pc + pcdelta) ^ pc) & 0xfffff000) == 0 && pcdelta < 120 && opptr[pcdelta/4] == 0)
+ {
+ pcdelta += 4;
+ cycles += 1;
+ }
+ }
+
+ /* epilogue */
+ if (hotnum != MIPS3_MAX_HOTSPOTS)
+ cycles += mips3.hotspot[hotnum].cycles;
+ drc_append_standard_epilogue(drc, cycles, pcdelta, 1);
+
+ /* check interrupts */
+ if (result & RECOMPILE_CHECK_INTERRUPTS)
+ append_check_interrupts(drc, 0);
+ if (result & RECOMPILE_CHECK_SW_INTERRUPTS)
+ append_check_sw_interrupts(drc, 0);
+ if (result & RECOMPILE_ADD_DISPATCH)
+ drc_append_dispatcher(drc);
+
+ return (result & 0xff) | ((cycles & 0xfff) << 8) | ((pcdelta & 0xfff) << 20);
+}
+
+
+
+/***************************************************************************
+ COMMON ROUTINES
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ append_generate_exception
+------------------------------------------------------------------*/
+
+static void append_generate_exception(drc_core *drc, UINT8 exception)
+{
+ UINT32 offset = (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) ? 0x00 : 0x180;
+ emit_link link1, link2;
+
+ /* assumes address is in EAX */
+ if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)
+ {
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_BadVAddr), REG_EAX); // mov [BadVAddr],eax
+ emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_EntryHi), 0x000000ff); // and [EntryHi],0x000000ff
+ emit_and_r32_imm(DRCTOP, REG_EAX, 0xffffe000); // and eax,0xffffe000
+ emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_EntryHi), REG_EAX); // or [EntryHi],eax
+ emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Context), 0xff800000); // and [Context],0xff800000
+ emit_shr_r32_imm(DRCTOP, REG_EAX, 9); // shr eax,9
+ emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_Context), REG_EAX); // or [Context],eax
+ }
+
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_EPC), REG_EDI); // mov [COP0_EPC],edi
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[COP0_Cause]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~0x800000ff); // and eax,~0x800000ff
+ if (exception)
+ emit_or_r32_imm(DRCTOP, REG_EAX, exception << 2); // or eax,exception << 2
+ emit_cmp_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // cmp [mips3.nextpc],~0
+ emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip
+ emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // mov [mips3.nextpc],~0
+ emit_sub_m32_imm(DRCTOP, CPR0ADDR(COP0_EPC), 4); // sub [COP0_EPC],4
+ emit_or_r32_imm(DRCTOP, REG_EAX, 0x80000000); // or eax,0x80000000
+ resolve_link(DRCTOP, &link1); // skip:
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [COP0_Cause],eax
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // mov eax,[COP0_Status]
+ emit_or_r32_imm(DRCTOP, REG_EAX, SR_EXL); // or eax,SR_EXL
+ emit_test_r32_imm(DRCTOP, REG_EAX, SR_BEV); // test eax,SR_BEV
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [COP0_Status],eax
+ emit_mov_r32_imm(DRCTOP, REG_EDI, 0xbfc00200 + offset); // mov edi,0xbfc00200+offset
+ emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // jnz skip2
+ emit_mov_r32_imm(DRCTOP, REG_EDI, 0x80000000 + offset); // mov edi,0x80000000+offset
+ resolve_link(DRCTOP, &link2); // skip2:
+ drc_append_dispatcher(drc); // dispatch
+}
+
+
+/*------------------------------------------------------------------
+ append_readwrite_and_translate
+------------------------------------------------------------------*/
+
+static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags)
+{
+ emit_link link1 = { 0 }, link2 = { 0 }, link3 = { 0 };
+ int ramnum;
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4]
+ emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EAX); // mov ebx,eax
+ emit_shr_r32_imm(DRCTOP, REG_EBX, 12); // shr ebx,12
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MISD(REG_EBX, 4, mips3.core->tlb_table)); // mov ebx,tlb_table[ebx*4]
+ emit_and_r32_imm(DRCTOP, REG_EAX, 0xfff); // and eax,0xfff
+ emit_shr_r32_imm(DRCTOP, REG_EBX, ((flags & ARW_WRITE) ? 1 : 2)); // shr ebx,2/1 (read/write)
+ emit_lea_r32_m32(DRCTOP, REG_EBX, MBISD(REG_EAX, REG_EBX, ((flags & ARW_WRITE) ? 2 : 4), 0));
+ // lea ebx,[eax+ebx*4/2] (read/write)
+ emit_jcc_near_link(DRCTOP, COND_C, &link1); // jc error
+ for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++)
+ if (!Machine->debug_mode && mips3.fastram[ramnum].base && (!(flags & ARW_WRITE) || !mips3.fastram[ramnum].readonly))
+ {
+ UINT32 fastbase = (UINT32)((UINT8 *)mips3.fastram[ramnum].base - mips3.fastram[ramnum].start);
+ if (mips3.fastram[ramnum].end != 0xffffffff)
+ {
+ emit_cmp_r32_imm(DRCTOP, REG_EBX, mips3.fastram[ramnum].end); // cmp ebx,fastram_end
+ emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja notram
+ }
+ if (mips3.fastram[ramnum].start != 0x00000000)
+ {
+ emit_cmp_r32_imm(DRCTOP, REG_EBX, mips3.fastram[ramnum].start); // cmp ebx,fastram_start
+ emit_jcc_short_link(DRCTOP, COND_B, &link3); // jb notram
+ }
+
+ if (!(flags & ARW_WRITE))
+ {
+ if (size == 1)
+ {
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_EBX, 3); // xor ebx,3
+ if (flags & ARW_SIGNED)
+ emit_movsx_r32_m8(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movsx eax,byte ptr [ebx+fastbase]
+ else
+ emit_movzx_r32_m8(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movzx eax,byte ptr [ebx+fastbase]
+ }
+ else if (size == 2)
+ {
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_EBX, 2); // xor ebx,2
+ if (flags & ARW_SIGNED)
+ emit_movsx_r32_m16(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movsx eax,word ptr [ebx+fastbase]
+ else
+ emit_movzx_r32_m16(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movzx eax,word ptr [ebx+fastbase]
+ }
+ else if (size == 4)
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // mov eax,[ebx+fastbase]
+ else if (size == 8)
+ {
+ if (mips3.core->bigendian)
+ emit_mov_r64_m64(DRCTOP, REG_EAX, REG_EDX, MBD(REG_EBX, (FPTR)fastbase));
+ // mov eax:edx,[ebx+fastbase]
+ else
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MBD(REG_EBX, (FPTR)fastbase));
+ // mov edx:eax,[ebx+fastbase]
+ }
+ emit_ret(DRCTOP); // ret
+ }
+ else
+ {
+ if (size == 1)
+ {
+ emit_mov_r8_m8(DRCTOP, REG_AL, MBD(REG_ESP, 8)); // mov al,[esp+8]
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_EBX, 3); // xor ebx,3
+ emit_mov_m8_r8(DRCTOP, MBD(REG_EBX, fastbase), REG_AL); // mov [ebx+fastbase],al
+ }
+ else if (size == 2)
+ {
+ emit_mov_r16_m16(DRCTOP, REG_AX, MBD(REG_ESP, 8)); // mov ax,[esp+8]
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_EBX, 2); // xor ebx,2
+ emit_mov_m16_r16(DRCTOP, MBD(REG_EBX, fastbase), REG_AX); // mov [ebx+fastbase],ax
+ }
+ else if (size == 4)
+ {
+ if (!(flags & ARW_MASKED))
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8]
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 12)); // mov ecx,[esp+12]
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
+ emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase]
+ emit_not_r32(DRCTOP, REG_EAX); // not eax
+ emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8]
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
+ }
+ }
+ else if (size == 8)
+ {
+ if (!(flags & ARW_MASKED))
+ {
+ if (mips3.core->bigendian)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8]
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // mov eax,[esp+12]
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8]
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // mov eax,[esp+12]
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax
+ }
+ }
+ else
+ {
+ if (mips3.core->bigendian)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 16)); // mov ecx,[esp+16]
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
+ emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase+4)); // and ecx,[ebx+fastbase+4]
+ emit_not_r32(DRCTOP, REG_EAX); // not eax
+ emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8]
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 20)); // mov ecx,[esp+20]
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
+ emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase]
+ emit_not_r32(DRCTOP, REG_EAX); // not eax
+ emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // and eax,[esp+12]
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 16)); // mov ecx,[esp+16]
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
+ emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase]
+ emit_not_r32(DRCTOP, REG_EAX); // not eax
+ emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8]
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 20)); // mov ecx,[esp+20]
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
+ emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase+4)); // and ecx,[ebx+fastbase+4]
+ emit_not_r32(DRCTOP, REG_EAX); // not eax
+ emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // and eax,[esp+12]
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
+ emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax
+ }
+ }
+ }
+ emit_ret(DRCTOP); // ret
+ }
+
+ if (mips3.fastram[ramnum].end != 0xffffffff) // notram:
+ resolve_link(DRCTOP, &link2);
+ if (mips3.fastram[ramnum].start != 0x00000000)
+ resolve_link(DRCTOP, &link3);
+ }
+
+ if (flags & ARW_WRITE)
+ {
+ emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx
+ if (size == 1)
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writebyte); // jmp writebyte
+ else if (size == 2)
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writehalf); // jmp writehalf
+ else if (size == 4)
+ {
+ if (!(flags & ARW_MASKED))
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writeword); // jmp writeword
+ else
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writeword_masked); // jmp writeword_masked
+ }
+ else
+ {
+ if (!(flags & ARW_MASKED))
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writedouble); // jmp writedouble
+ else
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writedouble_masked); // jmp writedouble_masked
+ }
+ }
+ else
+ {
+ if (size == 1)
+ {
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ emit_call(DRCTOP, (x86code *)mips3.core->memory.readbyte); // call readbyte
+ if (flags & ARW_SIGNED)
+ emit_movsx_r32_r8(DRCTOP, REG_EAX, REG_AL); // movsx eax,al
+ else
+ emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); // movzx eax,al
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_ret(DRCTOP); // ret
+ }
+ else if (size == 2)
+ {
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ emit_call(DRCTOP, (x86code *)mips3.core->memory.readhalf); // call readhalf
+ if (flags & ARW_SIGNED)
+ emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX); // movsx eax,ax
+ else
+ emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX); // movzx eax,ax
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_ret(DRCTOP); // ret
+ }
+ else if (size == 4)
+ {
+ emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx
+ if (!(flags & ARW_MASKED))
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readword); // jmp readword
+ else
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readword_masked); // jmp readword_masked
+ }
+ else
+ {
+ emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx
+ if (!(flags & ARW_MASKED))
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readdouble); // jmp readdouble
+ else
+ emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readdouble_masked); // jmp readdouble_masked
+ }
+ }
+ {
+ int valuebytes = (size == 8) ? 8 : 4;
+ int stackbytes = 4 + ((flags & ARW_WRITE) ? 4 + valuebytes : 4) + ((flags & ARW_MASKED) ? valuebytes : 0);
+ resolve_link(DRCTOP, &link1); // error:
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4]
+ emit_add_r32_imm(DRCTOP, REG_ESP, stackbytes); // add esp,stack_bytes
+ emit_jmp(DRCTOP, (flags & ARW_WRITE) ? (x86code *)mips3.drcdata->generate_tlbstore_exception : (x86code *)mips3.drcdata->generate_tlbload_exception);
+ // jmp generate_exception
+ }
+}
+
+
+/*------------------------------------------------------------------
+ append_tlb_verify
+------------------------------------------------------------------*/
+
+static void append_tlb_verify(drc_core *drc, UINT32 pc, void *target)
+{
+ /* addresses 0x80000000-0xbfffffff are direct-mapped; no checking needed */
+ if (pc < 0x80000000 || pc >= 0xc0000000)
+ {
+ emit_cmp_m32_imm(DRCTOP, MABS(&mips3.core->tlb_table[pc >> 12]), mips3.core->tlb_table[pc >> 12]);
+ // cmp tlbtable[pc >> 12],physpc & 0xfffff000
+ emit_jcc(DRCTOP, COND_NE, target); // jne handle_pc_tlb_mismatch
+ }
+}
+
+
+/*------------------------------------------------------------------
+ append_update_cycle_counting
+------------------------------------------------------------------*/
+
+static void append_update_cycle_counting(drc_core *drc)
+{
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
+ emit_call(DRCTOP, (x86code *)mips3com_update_cycle_counting); // call update_cycle_counting
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+}
+
+
+/*------------------------------------------------------------------
+ append_check_interrupts
+------------------------------------------------------------------*/
+
+static void append_check_interrupts(drc_core *drc, int inline_generate)
+{
+ emit_link link1, link2, link3;
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[COP0_Cause]
+ emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[COP0_Status]
+ emit_and_r32_imm(DRCTOP, REG_EAX, 0xfc00); // and eax,0xfc00
+ if (!inline_generate)
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ else
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_IE); // test [COP0_Status,SR_IE
+ if (!inline_generate)
+ emit_jcc_short_link(DRCTOP, COND_Z, &link2); // jz skip
+ else
+ emit_jcc_near_link(DRCTOP, COND_Z, &link2); // jz skip
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_EXL | SR_ERL); // test [COP0_Status,SR_EXL | SR_ERL
+ if (!inline_generate)
+ emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_interrupt_exception); // jz generate_interrupt_exception
+ else
+ {
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link3); // jnz skip
+ append_generate_exception(drc, EXCEPTION_INTERRUPT); // <generate exception>
+ resolve_link(DRCTOP, &link3); // skip:
+ }
+ resolve_link(DRCTOP, &link1); // skip:
+ resolve_link(DRCTOP, &link2);
+}
+
+
+/*------------------------------------------------------------------
+ append_check_sw_interrupts
+------------------------------------------------------------------*/
+
+static void append_check_sw_interrupts(drc_core *drc, int inline_generate)
+{
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), 0x300); // test [COP0_Cause],0x300
+ emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_interrupt_exception); // jnz generate_interrupt_exception
+}
+
+
+/*------------------------------------------------------------------
+ append_branch_or_dispatch
+------------------------------------------------------------------*/
+
+static void append_branch_or_dispatch(drc_core *drc, UINT32 newpc, int cycles)
+{
+ void *code = drc_get_code_at_pc(drc, newpc);
+ emit_mov_r32_imm(DRCTOP, REG_EDI, newpc); // mov edi,newpc
+ drc_append_standard_epilogue(drc, cycles, 0, 1); // <epilogue>
+
+ if (code)
+ emit_jmp(DRCTOP, code); // jmp code
+ else
+ drc_append_tentative_fixed_dispatcher(drc, newpc); // <dispatch>
+}
+
+
+
+/***************************************************************************
+ CORE RECOMPILATION
+***************************************************************************/
+
+static void ddiv(INT64 *rs, INT64 *rt)
+{
+ if (*rt)
+ {
+ mips3.core->r[REG_LO] = *rs / *rt;
+ mips3.core->r[REG_HI] = *rs % *rt;
+ }
+}
+
+static void ddivu(UINT64 *rs, UINT64 *rt)
+{
+ if (*rt)
+ {
+ mips3.core->r[REG_LO] = *rs / *rt;
+ mips3.core->r[REG_HI] = *rs % *rt;
+ }
+}
+
+
+/*------------------------------------------------------------------
+ recompile_delay_slot
+------------------------------------------------------------------*/
+
+static int recompile_delay_slot(drc_core *drc, UINT32 pc)
+{
+ UINT8 *saved_top;
+ UINT32 result;
+ UINT32 physpc;
+
+#ifdef MAME_DEBUG
+ if (Machine->debug_mode)
+ {
+ /* emit debugging */
+ emit_mov_r32_imm(DRCTOP, REG_EDI, pc);
+ drc_append_call_debugger(drc);
+ }
+#endif
+
+ saved_top = drc->cache_top;
+
+ /* recompile the instruction as-is */
+ in_delay_slot = 1;
+ physpc = pc;
+ mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc);
+ result = recompile_instruction(drc, pc, physpc); // <next instruction>
+ in_delay_slot = 0;
+
+ /* if the instruction can cause an exception, recompile setting nextpc */
+ if (result & RECOMPILE_MAY_CAUSE_EXCEPTION)
+ {
+ drc->cache_top = saved_top;
+ emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), 0); // bogus nextpc for exceptions
+ result = recompile_instruction(drc, pc, physpc); // <next instruction>
+ emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // reset nextpc
+ }
+
+ return (result >> 8) & 0xfff;
+}
+
+
+/*------------------------------------------------------------------
+ recompile_instruction
+------------------------------------------------------------------*/
+
+static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 physpc)
+{
+ emit_link link1, link2 = { 0 }, link3;
+ UINT32 op = cpu_readop32(physpc);
+ int cycles;
+
+ if (LOG_CODE)
+ log_add_disasm_comment(mips3.log, drc->cache_top, pc, op);
+
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ return recompile_special(drc, pc, op);
+
+ case 0x01: /* REGIMM */
+ return recompile_regimm(drc, pc, op);
+
+ case 0x02: /* J */
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, (pc & 0xf0000000) | (LIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+
+ case 0x03: /* JAL */
+ emit_mov_m64_imm32(DRCTOP, REGADDR(31), pc + 8); // mov [31],pc + 8
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, (pc & 0xf0000000) | (LIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+
+ case 0x04: /* BEQ */
+ if (RSREG == RTREG)
+ {
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+ }
+ else if (RSREG == 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip
+ }
+ else if (RTREG == 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
+ emit_jcc_near_link(DRCTOP, COND_NE, &link1); // jne skip
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
+ emit_jcc_near_link(DRCTOP, COND_NE, &link2); // jne skip
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ if (RSREG != 0 && RTREG != 0)
+ resolve_link(DRCTOP, &link2); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x05: /* BNE */
+ if (RSREG == 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
+ }
+ else if (RTREG == 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
+ emit_jcc_short_link(DRCTOP, COND_NE, &link2); // jne takeit
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
+ emit_jcc_near_link(DRCTOP, COND_E, &link1); // je skip
+ resolve_link(DRCTOP, &link2); // takeit:
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x06: /* BLEZ */
+ if (RSREG == 0)
+ {
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+ }
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_G, &link1); // jg skip
+ emit_jcc_short_link(DRCTOP, COND_L, &link2); // jl takeit
+ emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0
+ emit_jcc_near_link(DRCTOP, COND_NE, &link3); // jne skip
+ resolve_link(DRCTOP, &link2); // takeit:
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ resolve_link(DRCTOP, &link3); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x07: /* BGTZ */
+ if (RSREG == 0)
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
+ emit_jcc_short_link(DRCTOP, COND_G, &link2); // jg takeit
+ emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0
+ emit_jcc_near_link(DRCTOP, COND_E, &link3); // je skip
+ resolve_link(DRCTOP, &link2); // takeit:
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ resolve_link(DRCTOP, &link3); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x08: /* ADDI */
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
+ if (RTREG != 0)
+ {
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ }
+ else if (RTREG != 0)
+ emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x09: /* ADDIU */
+ if (RTREG != 0)
+ {
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ else
+ emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0a: /* SLTI */
+ if (RTREG != 0)
+ {
+ if (RSREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo
+ emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo
+ emit_shr_r32_imm(DRCTOP, REG_EDX, 31); // shr edx,31
+ emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EDX); // mov [rdreg].lo,edx
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rdreg].hi,0
+ }
+ else
+ {
+ emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const)
+ }
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0b: /* SLTIU */
+ if (RTREG != 0)
+ {
+ if (RSREG != 0)
+ {
+ emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); // cmp [rsreg].hi,upper
+ emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb takeit
+ emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja skip
+ emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
+ emit_jcc_short_link(DRCTOP, COND_AE, &link3); // jae skip
+ resolve_link(DRCTOP, &link1); // takeit:
+ emit_add_r32_imm(DRCTOP, REG_ECX, 1); // add ecx,1
+ resolve_link(DRCTOP, &link2); // skip:
+ resolve_link(DRCTOP, &link3); // skip:
+ emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_ECX); // mov [rtreg].lo,ecx
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const)
+ }
+ else
+ {
+ emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const)
+ }
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0c: /* ANDI */
+ if (RTREG != 0)
+ {
+ if (RSREG == RTREG)
+ {
+ emit_and_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // and [rtreg],UIMMVAL
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
+ }
+ else if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_and_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // and eax,UIMMVAL
+ emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
+ }
+ else
+ emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), 0); // mov [rtreg],0
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0d: /* ORI */
+ if (RTREG != 0)
+ {
+ if (RSREG == RTREG)
+ emit_or_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // or [rtreg].lo,UIMMVAL
+ else if (RSREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_or_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // or eax,UIMMVAL
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ else
+ emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL); // mov [rtreg],const
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0e: /* XORI */
+ if (RTREG != 0)
+ {
+ if (RSREG == RTREG)
+ emit_xor_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // xor [rtreg].lo,UIMMVAL
+ else if (RSREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_xor_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // xor eax,UIMMVAL
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ else
+ emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL); // mov [rtreg],const
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0f: /* LUI */
+ if (RTREG != 0)
+ emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL << 16); // mov [rtreg],const << 16
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x10: /* COP0 */
+ return recompile_cop0(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x11: /* COP1 */
+ return recompile_cop1(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x12: /* COP2 */
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
+
+ case 0x13: /* COP1X - R5000 */
+ if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
+ }
+ return recompile_cop1x(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x14: /* BEQL */
+ if (RSREG == RTREG)
+ {
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+ }
+ else if (RSREG == 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip
+ }
+ else if (RTREG == 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
+ emit_jcc_near_link(DRCTOP, COND_NE, &link1); // jne skip
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
+ emit_jcc_near_link(DRCTOP, COND_NE, &link2); // jne skip
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ if (RSREG != 0 && RTREG != 0)
+ resolve_link(DRCTOP, &link2); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+
+ case 0x15: /* BNEL */
+ if (RSREG == 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
+ }
+ else if (RTREG == 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
+ emit_jcc_short_link(DRCTOP, COND_NE, &link2); // jne takeit
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
+ emit_jcc_near_link(DRCTOP, COND_E, &link1); // je skip
+ resolve_link(DRCTOP, &link2); // takeit:
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+
+ case 0x16: /* BLEZL */
+ if (RSREG == 0)
+ {
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+ }
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_G, &link1); // jg skip
+ emit_jcc_short_link(DRCTOP, COND_L, &link2); // jl takeit
+ emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0
+ emit_jcc_near_link(DRCTOP, COND_NE, &link3); // jne skip
+ resolve_link(DRCTOP, &link2); // takeit:
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ resolve_link(DRCTOP, &link3); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+
+ case 0x17: /* BGTZL */
+ if (RSREG == 0)
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
+ emit_jcc_short_link(DRCTOP, COND_G, &link2); // jg takeit
+ emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0
+ emit_jcc_near_link(DRCTOP, COND_E, &link3); // je skip
+ resolve_link(DRCTOP, &link2); // takeit:
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ resolve_link(DRCTOP, &link3); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+
+ case 0x18: /* DADDI */
+ if (RSREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_adc_r32_imm(DRCTOP, REG_EDX, (SIMMVAL < 0) ? -1 : 0); // adc edx,signext(SIMMVAL)
+ emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
+ if (RTREG != 0)
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ else if (RTREG != 0)
+ emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x19: /* DADDIU */
+ if (RTREG != 0)
+ {
+ if (RSREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_adc_r32_imm(DRCTOP, REG_EDX, (SIMMVAL < 0) ? -1 : 0); // adc edx,signext(SIMMVAL)
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ else
+ emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x1a: /* LDL */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ if (SIMMVAL)
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
+ if (!mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c
+ emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
+ emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl
+ emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_not_r32(DRCTOP, REG_EBP); // not ebp
+ emit_push_r32(DRCTOP, REG_ECX); // push ecx
+ emit_push_r32(DRCTOP, REG_EBP); // push ebp
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_double_masked); // call read_and_translate_double_masked
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_pop_r32(DRCTOP, REG_ECX); // pop ecx
+
+ if (RTREG != 0)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_not_r32(DRCTOP, REG_EBP); // not ebp
+ emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl
+ emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
+ emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl
+ emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
+ emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo
+ emit_and_r32_m32(DRCTOP, REG_EBP, REGADDRHI(RTREG)); // and ebp,[rtreg].hi
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
+ emit_or_r32_r32(DRCTOP, REG_EDX, REG_EBP); // or edx,ebp
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x1b: /* LDR */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ if (SIMMVAL)
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_not_r32(DRCTOP, REG_EBP); // not ebp
+ emit_push_r32(DRCTOP, REG_ECX); // push ecx
+ emit_push_r32(DRCTOP, REG_EBP); // push ebp
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_double_masked); // call read_and_translate_double_masked
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_pop_r32(DRCTOP, REG_ECX); // pop ecx
+
+ if (RTREG != 0)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
+ emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
+ emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl
+ emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_not_r32(DRCTOP, REG_EBP); // not ebp
+ emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shld eax,edx,cl
+ emit_shr_r32_cl(DRCTOP, REG_EDX); // shl edx,cl
+ emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shld eax,edx,cl
+ emit_shr_r32_cl(DRCTOP, REG_EDX); // shl edx,cl
+ emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo
+ emit_and_r32_m32(DRCTOP, REG_EBP, REGADDRHI(RTREG)); // and ebp,[rtreg].hi
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
+ emit_or_r32_r32(DRCTOP, REG_EDX, REG_EBP); // or edx,ebp
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */
+ switch (op & 0x1f)
+ {
+ case 0: /* MAD */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
+ emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg]
+ emit_imul_r32(DRCTOP, REG_EDX); // imul edx
+ emit_add_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // add eax,[lo]
+ emit_adc_r32_m32(DRCTOP, REG_EDX, HIADDRLO); // adc edx,[hi]
+ emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
+ }
+ return RECOMPILE_SUCCESSFUL_CP(3,4);
+
+ case 1: /* MADU */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
+ emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg]
+ emit_mul_r32(DRCTOP, REG_EDX); // mul edx
+ emit_add_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // add eax,[lo]
+ emit_adc_r32_m32(DRCTOP, REG_EDX, HIADDRLO); // adc edx,[hi]
+ emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
+ }
+ return RECOMPILE_SUCCESSFUL_CP(3,4);
+
+ case 2: /* MUL */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_imul_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // imul eax,[rtreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG)); // mov [rdreg],0
+ }
+ return RECOMPILE_SUCCESSFUL_CP(3,4);
+ }
+ break;
+
+ case 0x20: /* LB */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_byte_signed); // call read_and_translate_byte_signed
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ if (RTREG != 0)
+ {
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x21: /* LH */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_half_signed); // call read_and_translate_half_signed
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ if (RTREG != 0)
+ {
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x22: /* LWL */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ if (SIMMVAL)
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ if (!mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
+ emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_push_r32(DRCTOP, REG_ECX); // push ecx
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_word_masked); // call read_and_translate_word_masked
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8
+ emit_pop_r32(DRCTOP, REG_ECX); // pop ecx
+
+ if (RTREG != 0)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
+ emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4); // add esp,4
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x23: /* LW */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ if (RTREG != 0)
+ {
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x24: /* LBU */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_byte_unsigned); // call read_and_translate_byte_unsigned
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ if (RTREG != 0)
+ {
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
+ emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x25: /* LHU */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_half_unsigned); // call read_and_translate_half_unsigned
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ if (RTREG != 0)
+ {
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
+ emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x26: /* LWR */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ if (SIMMVAL)
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_push_r32(DRCTOP, REG_ECX); // push ecx
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_word_masked); // call read_and_translate_word_masked
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8
+ emit_pop_r32(DRCTOP, REG_ECX); // pop ecx
+
+ if (RTREG != 0)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_shr_r32_cl(DRCTOP, REG_EAX); // shr eax,cl
+ emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4); // add esp,4
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x27: /* LWU */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ if (RTREG != 0)
+ {
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
+ emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x28: /* SB */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ if (RTREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo
+ else
+ emit_push_imm(DRCTOP, 0); // push 0
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_byte); // call writebyte
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x29: /* SH */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ if (RTREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo
+ else
+ emit_push_imm(DRCTOP, 0); // push 0
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_half); // call writehalf
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2a: /* SWL */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ if (SIMMVAL)
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ if (!mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
+ emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg].lo
+ emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl
+ emit_push_r32(DRCTOP, REG_EDX); // push edx
+ }
+ else
+ emit_push_imm(DRCTOP, 0); // push 0
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_word_masked); // call write_and_translate_word_masked
+ emit_add_r32_imm(DRCTOP, REG_ESP, 16); // add esp,16
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2b: /* SW */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ if (RTREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo
+ else
+ emit_push_imm(DRCTOP, 0); // push 0
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2c: /* SDL */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ if (SIMMVAL)
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
+ if (!mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c
+ emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
+ emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl
+ emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
+ emit_not_r32(DRCTOP, REG_EBP); // not ebp
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_push_r32(DRCTOP, REG_EBP); // push ebp
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // mov ebx,[rtreg].lo
+ emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // mov edx,[rtreg].hi
+ emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EDX); // shrd ebx,edx,cl
+ emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl
+ emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EDX); // shrd ebx,edx,cl
+ emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl
+ emit_push_r32(DRCTOP, REG_EDX); // push edx
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ }
+ else
+ {
+ emit_push_imm(DRCTOP, 0); // push 0
+ emit_push_imm(DRCTOP, 0); // push 0
+ }
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_double_masked); // call write_and_translate_double_masked
+ emit_add_r32_imm(DRCTOP, REG_ESP, 32); // add esp,32
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2d: /* SDR */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ if (SIMMVAL)
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_not_r32(DRCTOP, REG_EBP); // not ebp
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_push_r32(DRCTOP, REG_EBP); // push ebp
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // mov ebx,[rtreg].lo
+ emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // mov edx,[rtreg].hi
+ emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EBX); // shld edx,ebx,cl
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EBX); // shld edx,ebx,cl
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_push_r32(DRCTOP, REG_EDX); // push edx
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ }
+ else
+ {
+ emit_push_imm(DRCTOP, 0); // push 0
+ emit_push_imm(DRCTOP, 0); // push 0
+ }
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_double_masked); // call write_and_translate_double_masked
+ emit_add_r32_imm(DRCTOP, REG_ESP, 32); // add esp,32
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2e: /* SWR */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ if (SIMMVAL)
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
+ emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
+ if (mips3.core->bigendian)
+ emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
+ emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
+ emit_not_r32(DRCTOP, REG_EBX); // not ebx
+ emit_push_r32(DRCTOP, REG_EBX); // push ebx
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg].lo
+ emit_shl_r32_cl(DRCTOP, REG_EDX); // shl edx,cl
+ emit_push_r32(DRCTOP, REG_EDX); // push edx
+ }
+ else
+ emit_push_imm(DRCTOP, 0); // push 0
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_word_masked); // call write_and_translate_word_masked
+ emit_add_r32_imm(DRCTOP, REG_ESP, 16); // add esp,16
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2f: /* CACHE */
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+// case 0x30: /* LL */ logerror("mips3 Unhandled op: LL\n"); break;
+
+ case 0x31: /* LWC1 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].los
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(RTREG), REG_EAX); // mov [rtreg],eax
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x32: /* LWC2 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_m32_r32(DRCTOP, CPR2ADDR(RTREG), REG_EAX); // mov [rtreg],eax
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x33: /* PREF */
+ if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ else
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
+ }
+
+// case 0x34: /* LLD */ logerror("mips3 Unhandled op: LLD\n"); break;
+
+ case 0x35: /* LDC1 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double
+ emit_mov_m64_r64(DRCTOP, FPR64ADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x36: /* LDC2 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_word
+ emit_mov_m64_r64(DRCTOP, CPR2ADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x37: /* LD */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double
+ if (RTREG != 0)
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+// case 0x38: /* SC */ logerror("mips3 Unhandled op: SC\n"); break;
+
+ case 0x39: /* SWC1 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ emit_push_m32(DRCTOP, FPR32ADDR(RTREG)); // push dword [rtreg]
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x3a: /* SWC2 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ emit_push_m32(DRCTOP, CPR2ADDR(RTREG)); // push dword [rtreg]
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+// case 0x3b: /* SWC3 */ invalid_instruction(op); break;
+// case 0x3c: /* SCD */ logerror("mips3 Unhandled op: SCD\n"); break;
+
+ case 0x3d: /* SDC1 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_push_m32(DRCTOP, FPR64ADDRHI(RTREG)); // push dword [rtreg].hi
+ emit_push_m32(DRCTOP, FPR64ADDRLO(RTREG)); // push dword [rtreg].lo
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x3e: /* SDC2 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_push_m32(DRCTOP, CPR2ADDRHI(RTREG)); // push dword [rtreg].hi
+ emit_push_m32(DRCTOP, CPR2ADDRLO(RTREG)); // push dword [rtreg].lo
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x3f: /* SD */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ if (RTREG != 0)
+ {
+ emit_push_m32(DRCTOP, REGADDRHI(RTREG)); // push dword [rtreg].hi
+ emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo
+ }
+ else
+ {
+ emit_push_imm(DRCTOP, 0); // push 0
+ emit_push_imm(DRCTOP, 0); // push 0
+ }
+ if (RSREG != 0 && SIMMVAL != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ }
+ else if (RSREG != 0)
+ emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
+ else
+ emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+// default: /* ??? */ invalid_instruction(op); break;
+ }
+ return RECOMPILE_UNIMPLEMENTED;
+}
+
+
+/*------------------------------------------------------------------
+ recompile_special
+------------------------------------------------------------------*/
+
+static UINT32 recompile_special1(drc_core *drc, UINT32 pc, UINT32 op)
+{
+ emit_link link1, link2, link3;
+ int cycles;
+
+ switch (op & 63)
+ {
+ case 0x00: /* SLL */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ if (SHIFT != 0)
+ emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x01: /* MOVF - R5000*/
+ if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
+ }
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
+ emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); // jz/nz skip
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x02: /* SRL */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ if (SHIFT != 0)
+ emit_shr_r32_imm(DRCTOP, REG_EAX, SHIFT); // shr eax,SHIFT
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x03: /* SRA */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ if (SHIFT != 0)
+ emit_sar_r32_imm(DRCTOP, REG_EAX, SHIFT); // sar eax,SHIFT
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x04: /* SLLV */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
+ emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
+ }
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x06: /* SRLV */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
+ emit_shr_r32_cl(DRCTOP, REG_EAX); // shr eax,cl
+ }
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x07: /* SRAV */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
+ emit_sar_r32_cl(DRCTOP, REG_EAX); // sar eax,cl
+ }
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x08: /* JR */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_mov_m32_r32(DRCTOP, MABS(&jr_temp), REG_EAX); // mov jr_temp,eax
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&jr_temp)); // mov edi,jr_temp
+ return RECOMPILE_SUCCESSFUL_CP(1+cycles,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
+
+ case 0x09: /* JALR */
+ if (RDREG != 0)
+ emit_mov_m64_imm32(DRCTOP, REGADDR(RDREG), pc + 8); // mov [rdreg],pc + 8
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ emit_mov_r32_m32(DRCTOP, REG_EDI, REGADDRLO(RSREG)); // mov edi,[rsreg].lo
+ return RECOMPILE_SUCCESSFUL_CP(1+cycles,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
+
+ case 0x0a: /* MOVZ - R5000 */
+ if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
+ }
+ if (RDREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
+ emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG));
+ // mov [rdreg],[rsreg]
+ resolve_link(DRCTOP, &link1); // skip:
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0b: /* MOVN - R5000 */
+ if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
+ }
+ if (RDREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG));
+ // mov [rdreg],[rsreg]
+ resolve_link(DRCTOP, &link1); // skip:
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0c: /* SYSCALL */
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_syscall_exception); // jmp generate_syscall_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
+
+ case 0x0d: /* BREAK */
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_break_exception); // jmp generate_break_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
+
+ case 0x0f: /* SYNC */
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x10: /* MFHI */
+ if (RDREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), HIADDR); // mov [rdreg],[hi]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x11: /* MTHI */
+ emit_mov_m64_m64(DRCTOP, HIADDR, REGADDR(RSREG)); // mov [hi],[rsreg]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x12: /* MFLO */
+ if (RDREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), LOADDR); // mov [rdreg],[lo]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x13: /* MTLO */
+ emit_mov_m64_m64(DRCTOP, LOADDR, REGADDR(RSREG)); // mov [lo],[rsreg]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x14: /* DSLLV */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
+ emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_mov_r32_r32(DRCTOP, REG_EDX, REG_EAX); // mov edx,eax
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ resolve_link(DRCTOP, &link1); // skip:
+ emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl
+ emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
+ }
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x16: /* DSRLV */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
+ emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ resolve_link(DRCTOP, &link1); // skip:
+ emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shrd eax,edx,cl
+ emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl
+ }
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x17: /* DSRAV */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
+ emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx
+ emit_cdq(DRCTOP); // cdq
+ resolve_link(DRCTOP, &link1); // skip:
+ emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shrd eax,edx,cl
+ emit_sar_r32_cl(DRCTOP, REG_EDX); // sar edx,cl
+ }
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x18: /* MULT */
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_imul_r32(DRCTOP, REG_ECX); // imul ecx
+ emit_push_r32(DRCTOP, REG_EDX); // push edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
+ emit_pop_r32(DRCTOP, REG_EAX); // pop eax
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
+ return RECOMPILE_SUCCESSFUL_CP(4,4);
+
+ case 0x19: /* MULTU */
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_mul_r32(DRCTOP, REG_ECX); // mul ecx
+ emit_push_r32(DRCTOP, REG_EDX); // push edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
+ emit_pop_r32(DRCTOP, REG_EAX); // pop eax
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
+ return RECOMPILE_SUCCESSFUL_CP(4,4);
+
+ case 0x1a: /* DIV */
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_cmp_r32_imm(DRCTOP, REG_ECX, 0); // cmp ecx,0
+ emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip
+ emit_idiv_r32(DRCTOP, REG_ECX); // idiv ecx
+ emit_push_r32(DRCTOP, REG_EDX); // push edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
+ emit_pop_r32(DRCTOP, REG_EAX); // pop eax
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
+ resolve_link(DRCTOP, &link1); // skip:
+ }
+ return RECOMPILE_SUCCESSFUL_CP(36,4);
+
+ case 0x1b: /* DIVU */
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_cmp_r32_imm(DRCTOP, REG_ECX, 0); // cmp ecx,0
+ emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip
+ emit_div_r32(DRCTOP, REG_ECX); // div ecx
+ emit_push_r32(DRCTOP, REG_EDX); // push edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
+ emit_pop_r32(DRCTOP, REG_EAX); // pop eax
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
+ resolve_link(DRCTOP, &link1); // skip:
+ }
+ return RECOMPILE_SUCCESSFUL_CP(36,4);
+
+ case 0x1c: /* DMULT */
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0
+ emit_jcc_short_link(DRCTOP, COND_GE, &link1); // jge skip1
+ emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_neg_r32(DRCTOP, REG_EAX); // neg eax
+ emit_sbb_r32_r32(DRCTOP, REG_EDX, REG_ECX); // sbb edx,ecx
+ resolve_link(DRCTOP, &link1); // skip1:
+ emit_mov_m64_r64(DRCTOP, MABS(&dmult_temp1), REG_EDX, REG_EAX); // mov [dmult_temp1],edx:eax
+
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
+ emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0
+ emit_jcc_short_link(DRCTOP, COND_GE, &link2); // jge skip2
+ emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_neg_r32(DRCTOP, REG_EAX); // neg eax
+ emit_sbb_r32_r32(DRCTOP, REG_EDX, REG_ECX); // sbb edx,ecx
+ resolve_link(DRCTOP, &link2); // skip2:
+ emit_mov_m64_r64(DRCTOP, MABS(&dmult_temp2), REG_EDX, REG_EAX); // mov [dmult_temp2],edx:eax
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&dmult_temp1))); // mov eax,[dmult_temp1].lo
+ emit_mul_m32(DRCTOP, MABS(LO(&dmult_temp2))); // mul [dmult_temp2].lo
+ emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx
+ emit_mov_m32_r32(DRCTOP, LOADDRLO, REG_EAX); // mov [lo].lo,eax
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(HI(&dmult_temp1))); // mov eax,[dmult_temp1].hi
+ emit_mul_m32(DRCTOP, MABS(LO(&dmult_temp2))); // mul [dmult_temp2].lo
+ emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax
+ emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&dmult_temp1))); // mov eax,[dmult_temp1].lo
+ emit_mul_m32(DRCTOP, MABS(HI(&dmult_temp2))); // mul [dmult_temp2].hi
+ emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax
+ emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx
+ emit_mov_m32_r32(DRCTOP, LOADDRHI, REG_ECX); // mov [lo].hi,ecx
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(HI(&dmult_temp1))); // mov eax,[dmult_temp1].hi
+ emit_mul_m32(DRCTOP, MABS(HI(&dmult_temp2))); // mul [dmult_temp2].hi
+ emit_add_r32_r32(DRCTOP, REG_EBX, REG_EAX); // add ebx,eax
+ emit_adc_r32_imm(DRCTOP, REG_EDX, 0); // adc edx,0
+ emit_mov_m32_r32(DRCTOP, HIADDRLO, REG_EBX); // mov [hi].lo,ebx
+ emit_mov_m32_r32(DRCTOP, HIADDRHI, REG_EDX); // mov [hi].hi,edx
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_xor_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // xor eax,[rtreg].hi
+ emit_jcc_short_link(DRCTOP, COND_NS, &link3); // jns noflip
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx
+ emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_sub_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // sub eax,[lo].lo
+ emit_sbb_r32_m32(DRCTOP, REG_EBX, LOADDRHI); // sbb ebx,[lo].hi
+ emit_sbb_r32_m32(DRCTOP, REG_ECX, HIADDRLO); // sbb ecx,[hi].lo
+ emit_sbb_r32_m32(DRCTOP, REG_EDX, HIADDRHI); // sbb edx,[hi].hi
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EBX, REG_EAX); // mov [lo],ebx:eax
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_ECX); // mov [hi],edx:ecx
+ resolve_link(DRCTOP, &link3); // noflip:
+ return RECOMPILE_SUCCESSFUL_CP(8,4);
+
+ case 0x1d: /* DMULTU */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_mul_m32(DRCTOP, REGADDRLO(RTREG)); // mul [rtreg].lo
+ emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx
+ emit_mov_m32_r32(DRCTOP, LOADDRLO, REG_EAX); // mov [lo].lo,eax
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_mul_m32(DRCTOP, REGADDRLO(RTREG)); // mul [rtreg].lo
+ emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax
+ emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_mul_m32(DRCTOP, REGADDRHI(RTREG)); // mul [rtreg].hi
+ emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax
+ emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx
+ emit_mov_m32_r32(DRCTOP, LOADDRHI, REG_ECX); // mov [lo].hi,ecx
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_mul_m32(DRCTOP, REGADDRHI(RTREG)); // mul [rtreg].hi
+ emit_add_r32_r32(DRCTOP, REG_EBX, REG_EAX); // add ebx,eax
+ emit_adc_r32_imm(DRCTOP, REG_EDX, 0); // adc edx,0
+ emit_mov_m32_r32(DRCTOP, HIADDRLO, REG_EBX); // mov [hi].lo,ebx
+ emit_mov_m32_r32(DRCTOP, HIADDRHI, REG_EDX); // mov [hi].hi,edx
+ return RECOMPILE_SUCCESSFUL_CP(8,4);
+
+ case 0x1e: /* DDIV */
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RTREG]); // push [rtreg]
+ emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RSREG]); // push [rsreg]
+ emit_call(DRCTOP, (x86code *)ddiv); // call ddiv
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ return RECOMPILE_SUCCESSFUL_CP(68,4);
+
+ case 0x1f: /* DDIVU */
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RTREG]); // push [rtreg]
+ emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RSREG]); // push [rsreg]
+ emit_call(DRCTOP, (x86code *)ddivu); // call ddivu
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ return RECOMPILE_SUCCESSFUL_CP(68,4);
+ }
+
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+}
+
+static UINT32 recompile_special2(drc_core *drc, UINT32 pc, UINT32 op)
+{
+ emit_link link1, link2, link3;
+
+ switch (op & 63)
+ {
+ case 0x20: /* ADD */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo
+ emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
+ if (RDREG != 0)
+ {
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ }
+ else if (RDREG != 0)
+ {
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x21: /* ADDU */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x22: /* SUB */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
+ emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
+ if (RDREG != 0)
+ {
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ }
+ else if (RDREG != 0)
+ {
+ if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_neg_r32(DRCTOP, REG_EAX); // neg eax
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x23: /* SUBU */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RSREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_neg_r32(DRCTOP, REG_EAX); // neg eax
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x24: /* AND */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg]
+ emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg]
+ emit_andpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // andpd xmm0,xmm1
+ emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0
+ }
+ else
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG));
+ // mov edx:eax,[rsreg]
+ emit_and_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // and eax,[rtreg].lo
+ emit_and_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // and edx,[rtreg].hi
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x25: /* OR */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg]
+ emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg]
+ emit_orpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // orpd xmm0,xmm1
+ emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0
+ }
+ else
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG));
+ // mov edx:eax,[rsreg]
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // or eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // or edx,[rtreg].hi
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ }
+ else if (RSREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
+ else if (RTREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg]
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x26: /* XOR */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg]
+ emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg]
+ emit_xorpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // xorpd xmm0,xmm1
+ emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0
+ }
+ else
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG));
+ // mov edx:eax,[rsreg]
+ emit_xor_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // xor eax,[rtreg].lo
+ emit_xor_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // xor edx,[rtreg].hi
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ }
+ else if (RSREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
+ else if (RTREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg]
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x27: /* NOR */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // or eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // or edx,[rtreg].hi
+ emit_not_r32(DRCTOP, REG_EDX); // not edx
+ emit_not_r32(DRCTOP, REG_EAX); // not eax
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RSREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_not_r32(DRCTOP, REG_EDX); // not edx
+ emit_not_r32(DRCTOP, REG_EAX); // not eax
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
+ emit_not_r32(DRCTOP, REG_EDX); // not edx
+ emit_not_r32(DRCTOP, REG_EAX); // not eax
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ {
+ emit_mov_m32_imm(DRCTOP, REGADDRLO(RDREG), ~0); // mov [rtreg].lo,~0
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), ~0); // mov [rtreg].hi,~0
+ }
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2a: /* SLT */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0)
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ else
+ {
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ }
+ if (RTREG != 0)
+ {
+ emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
+ emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].lo
+ }
+ emit_shr_r32_imm(DRCTOP, REG_EDX, 31); // shr edx,31
+ emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_EDX); // mov [rdreg].lo,edx
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2b: /* SLTU */
+ if (RDREG != 0)
+ {
+ emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
+ emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb setit
+ emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja skipit
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
+ emit_jcc_short_link(DRCTOP, COND_AE, &link3); // jae skipit
+ resolve_link(DRCTOP, &link1); // setit:
+ emit_add_r32_imm(DRCTOP, REG_ECX, 1); // add ecx,1
+ resolve_link(DRCTOP, &link2); // skipit:
+ resolve_link(DRCTOP, &link3); // skipit:
+ emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_ECX); // mov [rdreg].lo,ecx
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2c: /* DADD */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo
+ emit_adc_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // adc edx,[rtreg].hi
+ emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
+ if (RDREG != 0)
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RDREG != 0)
+ {
+ if (RSREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
+ else if (RTREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg]
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x2d: /* DADDU */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo
+ emit_adc_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // adc edx,[rtreg].hi
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RSREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG));
+ // mov [rdreg],[rsreg]
+ else if (RTREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG));
+ // mov [rdreg],[rtreg]
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x2e: /* DSUB */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
+ emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
+ emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
+ if (RDREG != 0)
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RDREG != 0)
+ {
+ if (RSREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
+ else if (RTREG != 0)
+ {
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
+ emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x2f: /* DSUBU */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
+ emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else if (RSREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
+ else if (RTREG != 0)
+ {
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
+ emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x30: /* TGE */
+ if (RSREG != 0)
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ else
+ {
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ }
+ if (RTREG != 0)
+ {
+ emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
+ emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
+ }
+ else
+ emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0
+ emit_jcc(DRCTOP, COND_GE, mips3.drcdata->generate_trap_exception); // jge generate_trap_exception
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x31: /* TGEU */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
+ emit_jcc(DRCTOP, COND_A, mips3.drcdata->generate_trap_exception); // ja generate_trap_exception
+ emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb skipit
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
+ emit_jcc(DRCTOP, COND_AE, mips3.drcdata->generate_trap_exception); // jae generate_trap_exception
+ resolve_link(DRCTOP, &link1); // skipit:
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x32: /* TLT */
+ if (RSREG != 0)
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ else
+ {
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ }
+ if (RTREG != 0)
+ {
+ emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
+ emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
+ }
+ else
+ emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0
+ emit_jcc(DRCTOP, COND_L, mips3.drcdata->generate_trap_exception); // jl generate_trap_exception
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x33: /* TLTU */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
+ emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception
+ emit_jcc_short_link(DRCTOP, COND_A, &link1); // ja skipit
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
+ emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception
+ resolve_link(DRCTOP, &link1); // skipit:
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x34: /* TEQ */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
+ emit_jcc_short_link(DRCTOP, COND_NE, &link1); // jne skipit
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
+ emit_jcc(DRCTOP, COND_E, mips3.drcdata->generate_trap_exception); // je generate_trap_exception
+ resolve_link(DRCTOP, &link1); // skipit:
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x36: /* TNE */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
+ emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skipit
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
+ emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
+ emit_jcc(DRCTOP, COND_NE, mips3.drcdata->generate_trap_exception); // jne generate_trap_exception
+ resolve_link(DRCTOP, &link1); // skipit:
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x38: /* DSLL */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
+ if (SHIFT != 0)
+ {
+ emit_shld_r32_r32_imm(DRCTOP, REG_EDX, REG_EAX, SHIFT); // shld edx,eax,SHIFT
+ emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT
+ }
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x3a: /* DSRL */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
+ if (SHIFT != 0)
+ {
+ emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, SHIFT); // shrd eax,edx,SHIFT
+ emit_shr_r32_imm(DRCTOP, REG_EDX, SHIFT); // shr edx,SHIFT
+ }
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x3b: /* DSRA */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
+ if (SHIFT != 0)
+ {
+ emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, SHIFT); // shrd eax,edx,SHIFT
+ emit_sar_r32_imm(DRCTOP, REG_EDX, SHIFT); // sar edx,SHIFT
+ }
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x3c: /* DSLL32 */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ if (SHIFT != 0)
+ emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT
+ emit_mov_m32_imm(DRCTOP, REGADDRLO(RDREG), 0); // mov [rdreg].lo,0
+ emit_mov_m32_r32(DRCTOP, REGADDRHI(RDREG), REG_EAX); // mov [rdreg].hi,eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x3e: /* DSRL32 */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // mov eax,[rtreg].hi
+ if (SHIFT != 0)
+ emit_shr_r32_imm(DRCTOP, REG_EAX, SHIFT); // shr eax,SHIFT
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0
+ emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_EAX); // mov [rdreg].lo,eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x3f: /* DSRA32 */
+ if (RDREG != 0)
+ {
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // mov eax,[rtreg].hi
+ emit_cdq(DRCTOP); // cdq
+ if (SHIFT != 0)
+ emit_sar_r32_imm(DRCTOP, REG_EAX, SHIFT); // sar eax,SHIFT
+ emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
+ }
+ else
+ emit_zero_m64(DRCTOP, REGADDR(RDREG));
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ }
+
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+}
+
+
+static UINT32 recompile_special(drc_core *drc, UINT32 pc, UINT32 op)
+{
+ if (!(op & 32))
+ return recompile_special1(drc, pc, op);
+ else
+ return recompile_special2(drc, pc, op);
+}
+
+
+/*------------------------------------------------------------------
+ recompile_regimm
+------------------------------------------------------------------*/
+
+static UINT32 recompile_regimm(drc_core *drc, UINT32 pc, UINT32 op)
+{
+ emit_link link1;
+ int cycles;
+
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */
+ if (RSREG == 0)
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x01: /* BGEZ */
+ if (RSREG == 0)
+ {
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+ }
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x02: /* BLTZL */
+ if (RSREG == 0)
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+
+ case 0x03: /* BGEZL */
+ if (RSREG == 0)
+ {
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+ }
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
+ }
+
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+
+ case 0x08: /* TGEI */
+ if (RSREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo
+ emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo
+ emit_jcc(DRCTOP, COND_GE, mips3.drcdata->generate_trap_exception); // jge generate_trap_exception
+ }
+ else
+ {
+ if (0 >= SIMMVAL)
+ emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x09: /* TGEIU */
+ if (RSREG != 0)
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31));
+ // cmp [rsreg].hi,upper
+ emit_jcc(DRCTOP, COND_A, mips3.drcdata->generate_trap_exception); // ja generate_trap_exception
+ emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb skip
+ emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
+ emit_jcc(DRCTOP, COND_AE, mips3.drcdata->generate_trap_exception); // jae generate_trap_exception
+ resolve_link(DRCTOP, &link1); // skip:
+ }
+ else
+ {
+ if (0 >= SIMMVAL)
+ emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x0a: /* TLTI */
+ if (RSREG != 0)
+ {
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
+ emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo
+ emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo
+ emit_jcc(DRCTOP, COND_L, mips3.drcdata->generate_trap_exception); // jl generate_trap_exception
+ }
+ else
+ {
+ if (0 < SIMMVAL)
+ emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x0b: /* TLTIU */
+ if (RSREG != 0)
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31));
+ // cmp [rsreg].hi,upper
+ emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception
+ emit_jcc_short_link(DRCTOP, COND_A, &link1); // ja skip
+ emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
+ emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception
+ resolve_link(DRCTOP, &link1); // skip:
+ }
+ else
+ {
+ emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const
+ emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const)
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x0c: /* TEQI */
+ if (RSREG != 0)
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31));
+ // cmp [rsreg].hi,upper
+ emit_jcc_short_link(DRCTOP, COND_NE, &link1); // jne skip
+ emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
+ emit_jcc(DRCTOP, COND_E, mips3.drcdata->generate_trap_exception); // je generate_trap_exception
+ resolve_link(DRCTOP, &link1); // skip:
+ }
+ else
+ {
+ if (0 == SIMMVAL)
+ emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x0e: /* TNEI */
+ if (RSREG != 0)
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31));
+ // cmp [rsreg].hi,upper
+ emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip
+ emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
+ emit_jcc(DRCTOP, COND_NE, mips3.drcdata->generate_trap_exception); // jne generate_trap_exception
+ resolve_link(DRCTOP, &link1); // skip:
+ }
+ else
+ {
+ if (0 != SIMMVAL)
+ emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
+
+ case 0x10: /* BLTZAL */
+ if (RSREG == 0)
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip
+ }
+ emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x11: /* BGEZAL */
+ if (RSREG == 0)
+ {
+ emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+ }
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
+ }
+
+ emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x12: /* BLTZALL */
+ if (RSREG == 0)
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip
+ }
+
+ emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+
+ case 0x13: /* BGEZALL */
+ if (RSREG == 0)
+ {
+ emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+ }
+ else
+ {
+ emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
+ emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
+ }
+
+ emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+ }
+
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+}
+
+
+
+/***************************************************************************
+ COP0 RECOMPILATION
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ recompile_set_cop0_reg
+------------------------------------------------------------------*/
+
+static UINT32 recompile_set_cop0_reg(drc_core *drc, UINT8 reg)
+{
+ emit_link link1;
+
+ switch (reg)
+ {
+ case COP0_Cause:
+ emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Cause)); // mov ebx,[COP0_Cause]
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfc00); // and eax,~0xfc00
+ emit_and_r32_imm(DRCTOP, REG_EBX, 0xfc00); // and ebx,0xfc00
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [COP0_Cause],eax
+ emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[COP0_Status]
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_CHECK_SW_INTERRUPTS;
+
+ case COP0_Status:
+ emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Status)); // mov ebx,[COP0_Status]
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [COP0_Status],eax
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EAX); // xor ebx,eax
+/*
+#ifdef MAME_DEBUG
+ _test_r32_imm(REG_EAX, 0xe0); // test eax,0xe0
+ _jcc_short_link(COND_Z, &link1); // jz skip
+ _sub_r32_imm(REG_ESP, 4); // sub esp,4
+ _push_r32(REG_EAX); // push eax
+ _push_imm("System set 64-bit addressing mode, SR=%08X"); // push <string>
+ _call(mame_printf_debug); // call mame_printf_debug
+ _call(mame_debug_break); // call mame_debug_break
+ _add_r32_imm(REG_ESP, 12); // add esp,12
+ _resolve_link(&link1); // skip:
+#endif
+*/
+ emit_test_r32_imm(DRCTOP, REG_EBX, 0x8000); // test ebx,0x8000
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ append_update_cycle_counting(drc); // update cycle counting
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
+
+ case COP0_Count:
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Count), REG_EAX); // mov [COP0_Count],eax
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, (x86code *)activecpu_gettotalcycles64); // call activecpu_gettotalcycles64
+ emit_pop_r32(DRCTOP, REG_EBX); // pop ebx
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8
+ emit_sub_r32_r32(DRCTOP, REG_EAX, REG_EBX); // sub eax,ebx
+ emit_sbb_r32_imm(DRCTOP, REG_EDX, 0); // sbb edx,0
+ emit_sub_r32_r32(DRCTOP, REG_EAX, REG_EBX); // sub eax,ebx
+ emit_sbb_r32_imm(DRCTOP, REG_EDX, 0); // sbb edx,0
+ emit_mov_m64_r64(DRCTOP, MABS(&mips3.core->count_zero_time), REG_EDX, REG_EAX); // mov [mips3.core->count_zero_time],edx:eax
+ append_update_cycle_counting(drc); // update cycle counting
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case COP0_Compare:
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Compare), REG_EAX); // mov [COP0_Compare],eax
+ emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), ~0x8000); // and [COP0_Cause],~0x8000
+ append_update_cycle_counting(drc); // update cycle counting
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case COP0_PRId:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case COP0_Config:
+ emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Config)); // mov ebx,[COP0_Cause]
+ emit_and_r32_imm(DRCTOP, REG_EAX, 0x0007); // and eax,0x0007
+ emit_and_r32_imm(DRCTOP, REG_EBX, ~0x0007); // and ebx,~0x0007
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Config), REG_EAX); // mov [COP0_Cause],eax
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ default:
+ emit_mov_m32_r32(DRCTOP, CPR0ADDR(reg), REG_EAX); // mov [reg],eax
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ }
+ return RECOMPILE_UNIMPLEMENTED;
+}
+
+
+/*------------------------------------------------------------------
+ recompile_get_cop0_reg
+------------------------------------------------------------------*/
+
+static UINT32 recompile_get_cop0_reg(drc_core *drc, UINT8 reg)
+{
+ emit_link link1;
+
+ switch (reg)
+ {
+ case COP0_Count:
+ emit_sub_r32_imm(DRCTOP, REG_EBP, 250); // sub ebp,24
+ emit_jcc_short_link(DRCTOP, COND_NS, &link1); // jns notneg
+ emit_xor_r32_r32(DRCTOP, REG_EBP, REG_EBP); // xor ebp,ebp
+ resolve_link(DRCTOP, &link1); // notneg:
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12
+ emit_call(DRCTOP, (x86code *)activecpu_gettotalcycles64); // call activecpu_gettotalcycles64
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_sub_r32_m32(DRCTOP, REG_EAX, MABS(LO(&mips3.core->count_zero_time))); // sub eax,[mips3.core->count_zero_time+0]
+ emit_sbb_r32_m32(DRCTOP, REG_EDX, MABS(HI(&mips3.core->count_zero_time))); // sbb edx,[mips3.core->count_zero_time+4]
+ emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, 1); // shrd eax,edx,1
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case COP0_Cause:
+ emit_sub_r32_imm(DRCTOP, REG_EBP, 250); // sub ebp,24
+ emit_jcc_short_link(DRCTOP, COND_NS, &link1); // jns notneg
+ emit_xor_r32_r32(DRCTOP, REG_EBP, REG_EBP); // xor ebp,ebp
+ resolve_link(DRCTOP, &link1); // notneg:
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(reg)); // mov eax,[reg]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ default:
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(reg)); // mov eax,[reg]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ }
+ return RECOMPILE_UNIMPLEMENTED;
+}
+
+
+/*------------------------------------------------------------------
+ recompile_cop0
+------------------------------------------------------------------*/
+
+static UINT32 recompile_cop0(drc_core *drc, UINT32 pc, UINT32 op)
+{
+ emit_link checklink;
+ UINT32 result;
+
+ if (mips3.drcoptions & MIPS3DRC_STRICT_COP0)
+ {
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_KSU_MASK); // test [COP0_Status],SR_KSU_MASK
+ emit_jcc_short_link(DRCTOP, COND_Z, &checklink); // jz okay
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP0); // test [COP0_Status],SR_COP0
+ emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception
+ resolve_link(DRCTOP, &checklink); // okay:
+ }
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */
+ result = RECOMPILE_SUCCESSFUL_CP(1,4);
+ if (RTREG != 0)
+ {
+ result = recompile_get_cop0_reg(drc, RDREG); // read cop0 reg
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ return result;
+
+ case 0x01: /* DMFCz */
+ result = RECOMPILE_SUCCESSFUL_CP(1,4);
+ if (RTREG != 0)
+ {
+ result = recompile_get_cop0_reg(drc, RDREG); // read cop0 reg
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ return result;
+
+ case 0x02: /* CFCz */
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CCR0ADDR(RDREG)); // mov eax,[mips3.core->ccr[0][rdreg]]
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x04: /* MTCz */
+ if (RTREG != 0)
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
+ else
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ result = recompile_set_cop0_reg(drc, RDREG); // write cop0 reg
+ return result;
+
+ case 0x05: /* DMTCz */
+ if (RTREG != 0)
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
+ else
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ result = recompile_set_cop0_reg(drc, RDREG); // write cop0 reg
+ return result;
+
+ case 0x06: /* CTCz */
+ if (RTREG != 0)
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
+ else
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ emit_mov_m32_r32(DRCTOP, CCR0ADDR(RDREG), REG_EAX); // mov [mips3.core->ccr[0][RDREG]],eax
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+// case 0x08: /* BC */
+// switch (RTREG)
+// {
+// case 0x00: /* BCzF */ if (!mips3.core->cf[0][0]) ADDPC(SIMMVAL); break;
+// case 0x01: /* BCzF */ if (mips3.core->cf[0][0]) ADDPC(SIMMVAL); break;
+// case 0x02: /* BCzFL */ invalid_instruction(op); break;
+// case 0x03: /* BCzTL */ invalid_instruction(op); break;
+// default: invalid_instruction(op); break;
+// }
+// break;
+
+ 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: /* COP */
+ switch (op & 0x01ffffff)
+ {
+ case 0x01: /* TLBR */
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
+ drc_append_save_call_restore(drc, (x86code *)mips3com_tlbr, 12); // call tlbr
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x02: /* TLBWI */
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
+ drc_append_save_call_restore(drc, (x86code *)mips3com_tlbwi, 12); // call tlbwi
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x06: /* TLBWR */
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
+ drc_append_save_call_restore(drc, (x86code *)mips3com_tlbwr, 12); // call tlbwr
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x08: /* TLBP */
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
+ drc_append_save_call_restore(drc, (x86code *)mips3com_tlbp, 12); // call tlbp
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x10: /* RFE */
+ emit_jmp(DRCTOP, mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+
+ case 0x18: /* ERET */
+ emit_mov_r32_m32(DRCTOP, REG_EDI, CPR0ADDR(COP0_EPC)); // mov edi,[COP0_EPC]
+ emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), ~SR_EXL); // and [COP0_Status],~SR_EXL
+ return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
+
+ default:
+ emit_jmp(DRCTOP, mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+ }
+ break;
+
+// default:
+// _jmp(mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+// return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+ }
+ return RECOMPILE_UNIMPLEMENTED;
+}
+
+
+
+/***************************************************************************
+ COP1 RECOMPILATION
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ recompile_cop1
+------------------------------------------------------------------*/
+
+static UINT32 recompile_cop1(drc_core *drc, UINT32 pc, UINT32 op)
+{
+ emit_link link1;
+ int cycles, i;
+
+ if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
+ {
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [COP0_Status],SR_COP1
+ emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception
+ }
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(RDREG)); // mov eax,[RDREG]
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [RTREG],edx:eax
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x01: /* DMFCz */
+ if (RTREG != 0)
+ emit_mov_m64_m64(DRCTOP, REGADDR(RTREG), FPR64ADDR(RDREG));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x02: /* CFCz */
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, CCR1ADDR(RDREG)); // mov eax,[mips3.core->ccr[1][RDREG]]
+ if (RDREG == 31)
+ {
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfe800000); // and eax,~0xfe800000
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx
+ emit_cmp_m8_imm(DRCTOP, MABS(&mips3.core->cf[1][0]), 0); // cmp [cf[0]],0
+ emit_setcc_r8(DRCTOP, COND_NZ, REG_BL); // setnz bl
+ emit_shl_r32_imm(DRCTOP, REG_EBX, 23); // shl ebx,23
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
+ if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
+ for (i = 1; i <= 7; i++)
+ {
+ emit_cmp_m8_imm(DRCTOP, MABS(&mips3.core->cf[1][i]), 0); // cmp [cf[i]],0
+ emit_setcc_r8(DRCTOP, COND_NZ, REG_BL); // setnz bl
+ emit_shl_r32_imm(DRCTOP, REG_EBX, 24+i); // shl ebx,24+i
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
+ }
+ }
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [mips3.core->r[RTREG]],edx:eax
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x04: /* MTCz */
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(RDREG), REG_EAX); // mov [mips3.core->cpr[1][RDREG]],eax
+ }
+ else
+ emit_mov_m32_imm(DRCTOP, FPR32ADDR(RDREG), 0); // mov [mips3.core->cpr[1][RDREG]],0
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x05: /* DMTCz */
+ if (RTREG != 0)
+ emit_mov_m64_m64(DRCTOP, FPR64ADDR(RDREG), REGADDR(RTREG));
+ else
+ emit_zero_m64(DRCTOP, FPR64ADDR(RDREG)); // mov [mips3.core->cpr[1][RDREG]],0
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x06: /* CTCz */
+ if (RTREG != 0)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
+ emit_mov_m32_r32(DRCTOP, CCR1ADDR(RDREG), REG_EAX); // mov [mips3.core->ccr[1][RDREG]],eax
+ }
+ else
+ emit_mov_m32_imm(DRCTOP, CCR1ADDR(RDREG), 0); // mov [mips3.core->ccr[1][RDREG]],0
+ if (RDREG == 31)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&mips3.core->ccr[1][RDREG]))); // mov eax,[mips3.core->ccr[1][RDREG]]
+ emit_test_r32_imm(DRCTOP, REG_EAX, 1 << 23); // test eax,1<<23
+ emit_setcc_m8(DRCTOP, COND_NZ, MABS(&mips3.core->cf[1][0])); // setnz [cf[0]]
+ if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
+ for (i = 1; i <= 7; i++)
+ {
+ emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (24+i)); // test eax,1<<(24+i)
+ emit_setcc_m8(DRCTOP, COND_NZ, MABS(&mips3.core->cf[1][i])); // setnz [cf[i]]
+ }
+ emit_and_r32_imm(DRCTOP, REG_EAX, 3); // and eax,3
+ emit_test_r32_imm(DRCTOP, REG_EAX, 1); // test eax,1
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
+ emit_xor_r32_imm(DRCTOP, REG_EAX, 2); // xor eax,2
+ resolve_link(DRCTOP, &link1); // skip:
+ drc_append_set_fp_rounding(drc, REG_EAX); // set_rounding(EAX)
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x08: /* BC */
+ switch ((op >> 16) & 3)
+ {
+ case 0x00: /* BCzF */
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x01: /* BCzT */
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x02: /* BCzFL */
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+
+ case 0x03: /* BCzTL */
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1
+ cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
+ append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,8);
+ }
+ break;
+
+ default:
+ switch (op & 0x3f)
+ {
+ case 0x00:
+ if (IS_SINGLE(op)) /* ADD.S */
+ {
+ if (USE_SSE)
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // addss xmm0,[ftreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_faddp(DRCTOP); // faddp
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ else /* ADD.D */
+ {
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // addsd xmm0,[ftreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_faddp(DRCTOP); // faddp
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x01:
+ if (IS_SINGLE(op)) /* SUB.S */
+ {
+ if (USE_SSE)
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // subss xmm0,[ftreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fsubp(DRCTOP); // fsubp
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ else /* SUB.D */
+ {
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // subsd xmm0,[ftreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fsubp(DRCTOP); // fsubp
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x02:
+ if (IS_SINGLE(op)) /* MUL.S */
+ {
+ if (USE_SSE)
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ else /* MUL.D */
+ {
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x03:
+ if (IS_SINGLE(op)) /* DIV.S */
+ {
+ if (USE_SSE)
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_divss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // divss xmm0,[ftreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fdivp(DRCTOP); // fdivp
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ else /* DIV.D */
+ {
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_divsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // divsd xmm0,[ftreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fdivp(DRCTOP); // fdivp
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x04:
+ if (IS_SINGLE(op)) /* SQRT.S */
+ {
+ if (USE_SSE)
+ {
+ emit_sqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // sqrtss xmm0,[fsreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fsqrt(DRCTOP); // fsqrt
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ else /* SQRT.D */
+ {
+ if (USE_SSE)
+ {
+ emit_sqrtsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // sqrtsd xmm0,[fsreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fsqrt(DRCTOP); // fsqrt
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x05:
+ if (IS_SINGLE(op)) /* ABS.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fabs(DRCTOP); // fabs
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ else /* ABS.D */
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fabs(DRCTOP); // fabs
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x06:
+ if (IS_SINGLE(op)) /* MOV.S */
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ }
+ else /* MOV.D */
+ emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x07:
+ if (IS_SINGLE(op)) /* NEG.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fchs(DRCTOP); // fchs
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ else /* NEG.D */
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fchs(DRCTOP); // fchs
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x08:
+ drc_append_set_temp_fp_rounding(drc, FPRND_NEAR);
+ if (IS_SINGLE(op)) /* ROUND.L.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* ROUND.L.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
+ drc_append_restore_fp_rounding(drc);
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x09:
+ drc_append_set_temp_fp_rounding(drc, FPRND_CHOP);
+ if (IS_SINGLE(op)) /* TRUNC.L.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* TRUNC.L.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
+ drc_append_restore_fp_rounding(drc);
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0a:
+ drc_append_set_temp_fp_rounding(drc, FPRND_UP);
+ if (IS_SINGLE(op)) /* CEIL.L.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* CEIL.L.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
+ drc_append_restore_fp_rounding(drc);
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0b:
+ drc_append_set_temp_fp_rounding(drc, FPRND_DOWN);
+ if (IS_SINGLE(op)) /* FLOOR.L.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* FLOOR.L.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
+ drc_append_restore_fp_rounding(drc);
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0c:
+ drc_append_set_temp_fp_rounding(drc, FPRND_NEAR);
+ if (IS_SINGLE(op)) /* ROUND.W.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* ROUND.W.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
+ drc_append_restore_fp_rounding(drc);
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0d:
+ drc_append_set_temp_fp_rounding(drc, FPRND_CHOP);
+ if (IS_SINGLE(op)) /* TRUNC.W.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* TRUNC.W.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
+ drc_append_restore_fp_rounding(drc);
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0e:
+ drc_append_set_temp_fp_rounding(drc, FPRND_UP);
+ if (IS_SINGLE(op)) /* CEIL.W.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* CEIL.W.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
+ drc_append_restore_fp_rounding(drc);
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0f:
+ drc_append_set_temp_fp_rounding(drc, FPRND_DOWN);
+ if (IS_SINGLE(op)) /* FLOOR.W.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* FLOOR.W.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
+ drc_append_restore_fp_rounding(drc);
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x11: /* R5000 */
+ if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
+ // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+ }
+ emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
+ emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1);
+ // jz/nz skip
+ if (IS_SINGLE(op)) /* MOVT/F.S */
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ }
+ else /* MOVT/F.D */
+ emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG));
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x12: /* R5000 */
+ if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
+ // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
+ emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip
+ if (IS_SINGLE(op)) /* MOVZ.S */
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ }
+ else /* MOVZ.D */
+ emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG));
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x13: /* R5000 */
+ if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
+ // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+ }
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
+ emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
+ if (IS_SINGLE(op)) /* MOVN.S */
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg]
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ }
+ else /* MOVN.D */
+ emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG));
+ resolve_link(DRCTOP, &link1); // skip:
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x15: /* R5000 */
+ if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
+ // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+ }
+ emit_fld1(DRCTOP); // fld1
+ if (IS_SINGLE(op)) /* RECIP.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fdivp(DRCTOP); // fdivp
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ else /* RECIP.D */
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fdivp(DRCTOP); // fdivp
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x16: /* R5000 */
+ if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
+ {
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
+ // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+ }
+ emit_fld1(DRCTOP); // fld1
+ if (IS_SINGLE(op)) /* RSQRT.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fsqrt(DRCTOP); // fsqrt
+ emit_fdivp(DRCTOP); // fdivp
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ else /* RSQRT.D */
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fsqrt(DRCTOP); // fsqrt
+ emit_fdivp(DRCTOP); // fdivp
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x20:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.S.W */
+ emit_fild_m32(DRCTOP, FPR32ADDR(FSREG)); // fild [fsreg]
+ else /* CVT.S.L */
+ emit_fild_m64(DRCTOP, FPR64ADDR(FSREG)); // fild [fsreg]
+ }
+ else /* CVT.S.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x21:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.D.W */
+ emit_fild_m32(DRCTOP, FPR32ADDR(FSREG)); // fild [fsreg]
+ else /* CVT.D.L */
+ emit_fild_m64(DRCTOP, FPR64ADDR(FSREG)); // fild [fsreg]
+ }
+ else /* CVT.D.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x24:
+ if (IS_SINGLE(op)) /* CVT.W.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* CVT.W.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x25:
+ if (IS_SINGLE(op)) /* CVT.L.S */
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ else /* CVT.L.D */
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x30:
+ case 0x38:
+ emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x31:
+ case 0x39:
+ emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.UN.S/D */
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x32:
+ case 0x3a:
+ if (USE_SSE)
+ {
+ if (IS_SINGLE(op)) /* C.EQ.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
+ }
+ else
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]]
+ }
+ else
+ {
+ if (IS_SINGLE(op)) /* C.EQ.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ }
+ emit_fcompp(DRCTOP); // fcompp
+ emit_fstsw_ax(DRCTOP); // fnstsw ax
+ emit_sahf(DRCTOP); // sahf
+ emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x33:
+ case 0x3b:
+ if (USE_SSE)
+ {
+ if (IS_SINGLE(op)) /* C.UEQ.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
+ }
+ else
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]]
+ }
+ else
+ {
+ if (IS_SINGLE(op)) /* C.UEQ.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ }
+ emit_fucompp(DRCTOP); // fucompp
+ emit_fstsw_ax(DRCTOP); // fnstsw ax
+ emit_sahf(DRCTOP); // sahf
+ emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x34:
+ case 0x3c:
+ if (USE_SSE)
+ {
+ if (IS_SINGLE(op)) /* C.OLT.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
+ }
+ else
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]]
+ }
+ else
+ {
+ if (IS_SINGLE(op)) /* C.OLT.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ }
+ emit_fcompp(DRCTOP); // fcompp
+ emit_fstsw_ax(DRCTOP); // fnstsw ax
+ emit_sahf(DRCTOP); // sahf
+ emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x35:
+ case 0x3d:
+ if (USE_SSE)
+ {
+ if (IS_SINGLE(op)) /* C.ULT.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
+ }
+ else
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]]
+ }
+ else
+ {
+ if (IS_SINGLE(op)) /* C.ULT.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ }
+ emit_fucompp(DRCTOP); // fucompp
+ emit_fstsw_ax(DRCTOP); // fnstsw ax
+ emit_sahf(DRCTOP); // sahf
+ emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x36:
+ case 0x3e:
+ if (USE_SSE)
+ {
+ if (IS_SINGLE(op)) /* C.OLE.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
+ }
+ else
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setle [cf[x]]
+ }
+ else
+ {
+ if (IS_SINGLE(op)) /* C.OLE.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ }
+ emit_fcompp(DRCTOP); // fcompp
+ emit_fstsw_ax(DRCTOP); // fnstsw ax
+ emit_sahf(DRCTOP); // sahf
+ emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe [cf[x]]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x37:
+ case 0x3f:
+ if (USE_SSE)
+ {
+ if (IS_SINGLE(op)) /* C.ULE.S */
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
+ }
+ else
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
+ }
+ emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setl [cf[x]]
+ }
+ else
+ {
+ if (IS_SINGLE(op)) /* C.ULE.S */
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ }
+ emit_fucompp(DRCTOP); // fucompp
+ emit_fstsw_ax(DRCTOP); // fnstsw ax
+ emit_sahf(DRCTOP); // sahf
+ emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe [cf[x]]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ }
+ break;
+ }
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+}
+
+
+
+/***************************************************************************
+ COP1X RECOMPILATION
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ recompile_cop1x
+------------------------------------------------------------------*/
+
+static UINT32 recompile_cop1x(drc_core *drc, UINT32 pc, UINT32 op)
+{
+ if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
+ {
+ emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [COP0_Status],SR_COP1
+ emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception
+ }
+
+ switch (op & 0x3f)
+ {
+ case 0x00: /* LWXC1 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
+ emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg]
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x01: /* LDXC1 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
+ emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg]
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double
+ emit_mov_m32_r32(DRCTOP, FPR64ADDRLO(FDREG), REG_EAX); // mov [fdreg].lo,eax
+ emit_mov_m32_r32(DRCTOP, FPR64ADDRHI(FDREG), REG_EDX); // mov [fdreg].hi,edx
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x08: /* SWXC1 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
+ emit_push_m32(DRCTOP, FPR32ADDR(FSREG)); // push [fsreg]
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
+ emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg]
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,8
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x09: /* SDXC1 */
+ emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
+ emit_save_pc_before_call(DRCTOP); // save pc
+ emit_push_m32(DRCTOP, FPR64ADDRHI(FSREG)); // push [fsreg].hi
+ emit_push_m32(DRCTOP, FPR64ADDRLO(FSREG)); // push [fsreg].lo
+ emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
+ emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg]
+ emit_push_r32(DRCTOP, REG_EAX); // push eax
+ emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
+ emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x0f: /* PREFX */
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x20: /* MADD.S */
+ if (USE_SSE)
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_faddp(DRCTOP); // faddp
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x21: /* MADD.D */
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_faddp(DRCTOP); // faddp
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x28: /* MSUB.S */
+ if (USE_SSE)
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // subss xmm0,[frreg]
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_fsubrp(DRCTOP); // fsubrp
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x29: /* MSUB.D */
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // subsd xmm0,[frreg]
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_fsubrp(DRCTOP); // fsubrp
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x30: /* NMADD.S */
+ if (USE_SSE)
+ {
+ emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg]
+ emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1
+ }
+ else
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_faddp(DRCTOP); // faddp
+ emit_fchs(DRCTOP); // fchs
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x31: /* NMADD.D */
+ if (USE_SSE)
+ {
+ emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg]
+ emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_faddp(DRCTOP); // faddp
+ emit_fchs(DRCTOP); // fchs
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x38: /* NMSUB.S */
+ if (USE_SSE)
+ {
+ emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
+ emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
+ emit_movss_r128_m32(DRCTOP, REG_XMM1, FPR32ADDR(FRREG)); // movss xmm1,[frreg]
+ emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
+ emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1
+ }
+ else
+ {
+ emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_fsubp(DRCTOP); // fsubp
+ emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x39: /* NMSUB.D */
+ if (USE_SSE)
+ {
+ emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
+ emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
+ emit_movsd_r128_m64(DRCTOP, REG_XMM1, FPR64ADDR(FRREG)); // movsd xmm1,[frreg]
+ emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
+ emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1
+ }
+ else
+ {
+ emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
+ emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
+ emit_fmulp(DRCTOP); // fmulp
+ emit_fsubp(DRCTOP); // fsubrp
+ emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+
+ case 0x24: /* MADD.W */
+ case 0x25: /* MADD.L */
+ case 0x2c: /* MSUB.W */
+ case 0x2d: /* MSUB.L */
+ case 0x34: /* NMADD.W */
+ case 0x35: /* NMADD.L */
+ case 0x3c: /* NMSUB.W */
+ case 0x3d: /* NMSUB.L */
+ default:
+ fprintf(stderr, "cop1x %X\n", op);
+ break;
+ }
+ emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+}
diff --git a/src/emu/cpu/mips/mips3.c b/src/emu/cpu/mips/mips3.c
new file mode 100644
index 00000000000..efec9518412
--- /dev/null
+++ b/src/emu/cpu/mips/mips3.c
@@ -0,0 +1,2478 @@
+/***************************************************************************
+
+ mips3.c
+ Core implementation for the portable MIPS III/IV emulator.
+ Written by Aaron Giles
+
+ Still not implemented:
+ * DMULT needs to be fixed properly
+
+***************************************************************************/
+
+#include <math.h>
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "mips3com.h"
+
+
+#define ENABLE_OVERFLOWS 0
+
+
+/***************************************************************************
+ HELPER MACROS
+***************************************************************************/
+
+#define RSVAL32 ((UINT32)mips3.core.r[RSREG])
+#define RTVAL32 ((UINT32)mips3.core.r[RTREG])
+#define RDVAL32 ((UINT32)mips3.core.r[RDREG])
+
+#define RSVAL64 (mips3.core.r[RSREG])
+#define RTVAL64 (mips3.core.r[RTREG])
+#define RDVAL64 (mips3.core.r[RDREG])
+
+#define FRVALS_FR0 (((float *)&mips3.core.cpr[1][0])[FRREG])
+#define FTVALS_FR0 (((float *)&mips3.core.cpr[1][0])[FTREG])
+#define FSVALS_FR0 (((float *)&mips3.core.cpr[1][0])[FSREG])
+#define FDVALS_FR0 (((float *)&mips3.core.cpr[1][0])[FDREG])
+#define FSVALW_FR0 (((UINT32 *)&mips3.core.cpr[1][0])[FSREG])
+#define FDVALW_FR0 (((UINT32 *)&mips3.core.cpr[1][0])[FDREG])
+
+#define FRVALD_FR0 (*(double *)&mips3.core.cpr[1][FRREG/2])
+#define FTVALD_FR0 (*(double *)&mips3.core.cpr[1][FTREG/2])
+#define FSVALD_FR0 (*(double *)&mips3.core.cpr[1][FSREG/2])
+#define FDVALD_FR0 (*(double *)&mips3.core.cpr[1][FDREG/2])
+#define FSVALL_FR0 (((UINT64 *)&mips3.core.cpr[1][0])[FSREG/2])
+#define FDVALL_FR0 (((UINT64 *)&mips3.core.cpr[1][0])[FDREG/2])
+
+#define FRVALS_FR1 (((float *)&mips3.core.cpr[1][FRREG])[BYTE_XOR_LE(0)])
+#define FTVALS_FR1 (((float *)&mips3.core.cpr[1][FTREG])[BYTE_XOR_LE(0)])
+#define FSVALS_FR1 (((float *)&mips3.core.cpr[1][FSREG])[BYTE_XOR_LE(0)])
+#define FDVALS_FR1 (((float *)&mips3.core.cpr[1][FDREG])[BYTE_XOR_LE(0)])
+#define FSVALW_FR1 (((UINT32 *)&mips3.core.cpr[1][FSREG])[BYTE_XOR_LE(0)])
+#define FDVALW_FR1 (((UINT32 *)&mips3.core.cpr[1][FDREG])[BYTE_XOR_LE(0)])
+
+#define FRVALD_FR1 (*(double *)&mips3.core.cpr[1][FRREG])
+#define FTVALD_FR1 (*(double *)&mips3.core.cpr[1][FTREG])
+#define FSVALD_FR1 (*(double *)&mips3.core.cpr[1][FSREG])
+#define FDVALD_FR1 (*(double *)&mips3.core.cpr[1][FDREG])
+#define FSVALL_FR1 (*(UINT64 *)&mips3.core.cpr[1][FSREG])
+#define FDVALL_FR1 (*(UINT64 *)&mips3.core.cpr[1][FDREG])
+
+#define ADDPC(x) mips3.nextpc = mips3.core.pc + ((x) << 2)
+#define ADDPCL(x,l) { mips3.nextpc = mips3.core.pc + ((x) << 2); mips3.core.r[l] = (INT32)(mips3.core.pc + 4); }
+#define ABSPC(x) mips3.nextpc = (mips3.core.pc & 0xf0000000) | ((x) << 2)
+#define ABSPCL(x,l) { mips3.nextpc = (mips3.core.pc & 0xf0000000) | ((x) << 2); mips3.core.r[l] = (INT32)(mips3.core.pc + 4); }
+#define SETPC(x) mips3.nextpc = (x)
+#define SETPCL(x,l) { mips3.nextpc = (x); mips3.core.r[l] = (INT32)(mips3.core.pc + 4); }
+
+#define HIVAL (UINT32)mips3.core.r[REG_HI]
+#define LOVAL (UINT32)mips3.core.r[REG_LO]
+#define HIVAL64 mips3.core.r[REG_HI]
+#define LOVAL64 mips3.core.r[REG_LO]
+#define SR mips3.core.cpr[0][COP0_Status]
+#define CAUSE mips3.core.cpr[0][COP0_Cause]
+
+#define GET_FCC(n) (mips3.core.cf[1][n])
+#define SET_FCC(n,v) (mips3.core.cf[1][n] = (v))
+
+#define IS_FR0 (!(SR & SR_FR))
+#define IS_FR1 (SR & SR_FR)
+
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+/* MIPS3 Registers */
+typedef struct
+{
+ /* core state */
+ mips3_state core;
+
+ /* internal stuff */
+ UINT32 ppc;
+ UINT32 nextpc;
+ UINT32 pcbase;
+ int op;
+ int interrupt_cycles;
+ UINT32 ll_value;
+ UINT64 lld_value;
+
+ /* endian-dependent load/store */
+ void (*lwl)(UINT32 op);
+ void (*lwr)(UINT32 op);
+ void (*swl)(UINT32 op);
+ void (*swr)(UINT32 op);
+ void (*ldl)(UINT32 op);
+ void (*ldr)(UINT32 op);
+ void (*sdl)(UINT32 op);
+ void (*sdr)(UINT32 op);
+} mips3_regs;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void lwl_be(UINT32 op);
+static void lwr_be(UINT32 op);
+static void swl_be(UINT32 op);
+static void swr_be(UINT32 op);
+
+static void lwl_le(UINT32 op);
+static void lwr_le(UINT32 op);
+static void swl_le(UINT32 op);
+static void swr_le(UINT32 op);
+
+static void ldl_be(UINT32 op);
+static void ldr_be(UINT32 op);
+static void sdl_be(UINT32 op);
+static void sdr_be(UINT32 op);
+
+static void ldl_le(UINT32 op);
+static void ldr_le(UINT32 op);
+static void sdl_le(UINT32 op);
+static void sdr_le(UINT32 op);
+
+static UINT8 fcc_shift[8] = { 23, 25, 26, 27, 28, 29, 30, 31 };
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static mips3_regs mips3;
+
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(pc) cpu_readop32(pc)
+
+
+
+/***************************************************************************
+ EXECEPTION HANDLING
+***************************************************************************/
+
+INLINE void generate_exception(int exception, int backup)
+{
+/*
+ useful for catching exceptions:
+
+ if (exception != 0)
+ {
+ fprintf(stderr, "Exception: PC=%08X, PPC=%08X\n", mips3.core.pc, mips3.ppc);
+ DEBUGGER_BREAK;
+ }
+*/
+
+ /* back up if necessary */
+ if (backup)
+ mips3.core.pc = mips3.ppc;
+
+ /* set the exception PC */
+ mips3.core.cpr[0][COP0_EPC] = mips3.core.pc;
+
+ /* put the cause in the low 8 bits and clear the branch delay flag */
+ CAUSE = (CAUSE & ~0x800000ff) | (exception << 2);
+
+ /* if we were in a branch delay slot, adjust */
+ if (mips3.nextpc != ~0)
+ {
+ mips3.nextpc = ~0;
+ mips3.core.cpr[0][COP0_EPC] -= 4;
+ CAUSE |= 0x80000000;
+ }
+
+ /* set the exception level */
+ SR |= SR_EXL;
+
+ /* based on the BEV bit, we either go to ROM or RAM */
+ mips3.core.pc = (SR & SR_BEV) ? 0xbfc00200 : 0x80000000;
+
+ /* most exceptions go to offset 0x180, except for TLB stuff */
+ if (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE)
+ {
+ mips3.core.pc += 0x00;
+ mame_printf_debug("TLB miss @ %08X\n", (UINT32)mips3.core.cpr[0][COP0_BadVAddr]);
+ }
+ else
+ mips3.core.pc += 0x180;
+
+/*
+ useful for tracking interrupts
+
+ if ((CAUSE & 0x7f) == 0)
+ logerror("Took interrupt -- Cause = %08X, PC = %08X\n", (UINT32)CAUSE, mips3.core.pc);
+*/
+}
+
+
+static void generate_tlb_exception(int exception, offs_t address)
+{
+ mips3.core.cpr[0][COP0_BadVAddr] = address;
+ mips3.core.cpr[0][COP0_Context] = (mips3.core.cpr[0][COP0_Context] & 0xff800000) | ((address >> 9) & 0x007ffff0);
+ mips3.core.cpr[0][COP0_EntryHi] = (address & 0xffffe000) | (mips3.core.cpr[0][COP0_EntryHi] & 0xff);
+ generate_exception(exception, 1);
+}
+
+
+INLINE void invalid_instruction(UINT32 op)
+{
+ generate_exception(EXCEPTION_INVALIDOP, 1);
+}
+
+
+
+/***************************************************************************
+ IRQ HANDLING
+***************************************************************************/
+
+static void check_irqs(void)
+{
+ if ((CAUSE & SR & 0xfc00) && (SR & SR_IE) && !(SR & SR_EXL) && !(SR & SR_ERL))
+ generate_exception(EXCEPTION_INTERRUPT, 0);
+}
+
+
+
+/***************************************************************************
+ CORE CALLBACKS
+***************************************************************************/
+
+static void mips3_get_context(void *dst)
+{
+ if (dst != NULL)
+ *(mips3_regs *)dst = mips3;
+}
+
+
+static void mips3_set_context(void *src)
+{
+ if (src != NULL)
+ mips3 = *(mips3_regs *)src;
+}
+
+
+static void mips3_reset(void)
+{
+ /* common reset */
+ mips3com_reset(&mips3.core);
+ mips3.nextpc = ~0;
+
+ /* set up the endianness */
+ if (mips3.core.bigendian)
+ {
+ mips3.lwl = lwl_be;
+ mips3.lwr = lwr_be;
+ mips3.swl = swl_be;
+ mips3.swr = swr_be;
+ mips3.ldl = ldl_be;
+ mips3.ldr = ldr_be;
+ mips3.sdl = sdl_be;
+ mips3.sdr = sdr_be;
+ }
+ else
+ {
+ mips3.lwl = lwl_le;
+ mips3.lwr = lwr_le;
+ mips3.swl = swl_le;
+ mips3.swr = swr_le;
+ mips3.ldl = ldl_le;
+ mips3.ldr = ldr_le;
+ mips3.sdl = sdl_le;
+ mips3.sdr = sdr_le;
+ }
+}
+
+
+static int mips3_translate(int space, offs_t *address)
+{
+ /* common translate */
+ return mips3com_translate_address(&mips3.core, space, address);
+}
+
+
+#ifdef MAME_DEBUG
+offs_t mips3_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ /* common disassemble */
+ return mips3com_dasm(&mips3.core, buffer, pc, oprom, opram);
+}
+#endif /* MAME_DEBUG */
+
+
+
+/***************************************************************************
+ TLB HANDLING
+***************************************************************************/
+
+static int update_pcbase(void)
+{
+ UINT32 entry = mips3.core.tlb_table[mips3.core.pc >> 12];
+ if (entry == 0xffffffff)
+ {
+ generate_tlb_exception(EXCEPTION_TLBLOAD, mips3.core.pc);
+ return 0;
+ }
+ mips3.pcbase = entry & ~0xfff;
+ change_pc(mips3.pcbase);
+ return 1;
+}
+
+
+INLINE int RBYTE(offs_t address, UINT32 *result)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval == 0xffffffff)
+ {
+ generate_tlb_exception(EXCEPTION_TLBLOAD, address);
+ return 0;
+ }
+ *result = (*mips3.core.memory.readbyte)((tlbval & ~0xfff) | (address & 0xfff));
+ return 1;
+}
+
+
+INLINE int RHALF(offs_t address, UINT32 *result)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval == 0xffffffff)
+ {
+ generate_tlb_exception(EXCEPTION_TLBLOAD, address);
+ return 0;
+ }
+ *result = (*mips3.core.memory.readhalf)((tlbval & ~0xfff) | (address & 0xfff));
+ return 1;
+}
+
+
+INLINE int RWORD(offs_t address, UINT32 *result)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval == 0xffffffff)
+ {
+ generate_tlb_exception(EXCEPTION_TLBLOAD, address);
+ return 0;
+ }
+ *result = (*mips3.core.memory.readword)((tlbval & ~0xfff) | (address & 0xfff));
+ return 1;
+}
+
+
+INLINE int RWORD_MASKED(offs_t address, UINT32 *result, UINT32 mem_mask)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval == 0xffffffff)
+ {
+ generate_tlb_exception(EXCEPTION_TLBLOAD, address);
+ return 0;
+ }
+ *result = (*mips3.core.memory.readword_masked)((tlbval & ~0xfff) | (address & 0xfff), mem_mask);
+ return 1;
+}
+
+
+INLINE int RDOUBLE(offs_t address, UINT64 *result)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval == 0xffffffff)
+ {
+ generate_tlb_exception(EXCEPTION_TLBLOAD, address);
+ return 0;
+ }
+ *result = (*mips3.core.memory.readdouble)((tlbval & ~0xfff) | (address & 0xfff));
+ return 1;
+}
+
+
+INLINE int RDOUBLE_MASKED(offs_t address, UINT64 *result, UINT64 mem_mask)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval == 0xffffffff)
+ {
+ generate_tlb_exception(EXCEPTION_TLBLOAD, address);
+ return 0;
+ }
+ *result = (*mips3.core.memory.readdouble_masked)((tlbval & ~0xfff) | (address & 0xfff), mem_mask);
+ return 1;
+}
+
+
+INLINE void WBYTE(offs_t address, UINT8 data)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval & 1)
+ generate_tlb_exception(EXCEPTION_TLBSTORE, address);
+ else
+ (*mips3.core.memory.writebyte)(tlbval | (address & 0xfff), data);
+}
+
+
+INLINE void WHALF(offs_t address, UINT16 data)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval & 1)
+ generate_tlb_exception(EXCEPTION_TLBSTORE, address);
+ else
+ (*mips3.core.memory.writehalf)(tlbval | (address & 0xfff), data);
+}
+
+
+INLINE void WWORD(offs_t address, UINT32 data)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval & 1)
+ generate_tlb_exception(EXCEPTION_TLBSTORE, address);
+ else
+ (*mips3.core.memory.writeword)(tlbval | (address & 0xfff), data);
+}
+
+
+INLINE void WWORD_MASKED(offs_t address, UINT32 data, UINT32 mem_mask)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval & 1)
+ generate_tlb_exception(EXCEPTION_TLBSTORE, address);
+ else
+ (*mips3.core.memory.writeword_masked)(tlbval | (address & 0xfff), data, mem_mask);
+}
+
+
+INLINE void WDOUBLE(offs_t address, UINT64 data)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval & 1)
+ generate_tlb_exception(EXCEPTION_TLBSTORE, address);
+ else
+ (*mips3.core.memory.writedouble)(tlbval | (address & 0xfff), data);
+}
+
+
+INLINE void WDOUBLE_MASKED(offs_t address, UINT64 data, UINT64 mem_mask)
+{
+ UINT32 tlbval = mips3.core.tlb_table[address >> 12];
+ if (tlbval & 1)
+ generate_tlb_exception(EXCEPTION_TLBSTORE, address);
+ else
+ (*mips3.core.memory.writedouble_masked)(tlbval | (address & 0xfff), data, mem_mask);
+}
+
+
+
+/***************************************************************************
+ COP0 (SYSTEM) EXECUTION HANDLING
+***************************************************************************/
+
+INLINE UINT64 get_cop0_reg(int idx)
+{
+ if (idx == COP0_Count)
+ {
+ /* it doesn't really take 250 cycles to read this register, but it helps speed */
+ /* up loops that hammer on it */
+ if (mips3.core.icount >= MIPS3_COUNT_READ_CYCLES)
+ mips3.core.icount -= MIPS3_COUNT_READ_CYCLES;
+ else
+ mips3.core.icount = 0;
+ return (UINT32)((activecpu_gettotalcycles64() - mips3.core.count_zero_time) / 2);
+ }
+ else if (idx == COP0_Cause)
+ {
+ /* it doesn't really take 250 cycles to read this register, but it helps speed */
+ /* up loops that hammer on it */
+ if (mips3.core.icount >= MIPS3_CAUSE_READ_CYCLES)
+ mips3.core.icount -= MIPS3_CAUSE_READ_CYCLES;
+ else
+ mips3.core.icount = 0;
+ }
+ else if (idx == COP0_Random)
+ {
+ int wired = mips3.core.cpr[0][COP0_Wired] & 0x3f;
+ int range = 48 - wired;
+ if (range > 0)
+ return ((activecpu_gettotalcycles64() - mips3.core.count_zero_time) % range + wired) & 0x3f;
+ else
+ return 47;
+ }
+ return mips3.core.cpr[0][idx];
+}
+
+INLINE void set_cop0_reg(int idx, UINT64 val)
+{
+ switch (idx)
+ {
+ case COP0_Cause:
+ CAUSE = (CAUSE & 0xfc00) | (val & ~0xfc00);
+ if (CAUSE & 0x300)
+ {
+ /* if we're in a delay slot, propogate the target PC before generating the exception */
+ if (mips3.nextpc != ~0)
+ {
+ mips3.core.pc = mips3.nextpc;
+ mips3.nextpc = ~0;
+ }
+ generate_exception(EXCEPTION_INTERRUPT, 0);
+ }
+ break;
+
+ case COP0_Status:
+ {
+ /* update interrupts and cycle counting */
+ UINT32 diff = mips3.core.cpr[0][idx] ^ val;
+// if (val & 0xe0)
+// fatalerror("System set 64-bit addressing mode, SR=%08X", val);
+ mips3.core.cpr[0][idx] = val;
+ if (diff & 0x8000)
+ mips3com_update_cycle_counting(&mips3.core);
+ check_irqs();
+ break;
+ }
+
+ case COP0_Count:
+ mips3.core.cpr[0][idx] = val;
+ mips3.core.count_zero_time = activecpu_gettotalcycles64() - ((UINT64)(UINT32)val * 2);
+ mips3com_update_cycle_counting(&mips3.core);
+ break;
+
+ case COP0_Compare:
+ CAUSE &= ~0x8000;
+ mips3.core.cpr[0][idx] = val & 0xffffffff;
+ mips3com_update_cycle_counting(&mips3.core);
+ break;
+
+ case COP0_PRId:
+ break;
+
+ case COP0_Config:
+ mips3.core.cpr[0][idx] = (mips3.core.cpr[0][idx] & ~7) | (val & 7);
+ break;
+
+ case COP0_EntryHi:
+ /* if the ASID changes, remap */
+ if ((mips3.core.cpr[0][idx] ^ val) & 0xff)
+ {
+ mips3.core.cpr[0][idx] = val;
+ mips3com_unmap_tlb_entries(&mips3.core);
+ mips3com_map_tlb_entries(&mips3.core);
+ }
+ mips3.core.cpr[0][idx] = val;
+ break;
+
+ default:
+ mips3.core.cpr[0][idx] = val;
+ break;
+ }
+}
+
+INLINE UINT64 get_cop0_creg(int idx)
+{
+ return mips3.core.ccr[0][idx];
+}
+
+INLINE void set_cop0_creg(int idx, UINT64 val)
+{
+ mips3.core.ccr[0][idx] = val;
+}
+
+INLINE void handle_cop0(UINT32 op)
+{
+ if ((SR & SR_KSU_MASK) != SR_KSU_KERNEL && !(SR & SR_COP0))
+ generate_exception(EXCEPTION_BADCOP, 1);
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop0_reg(RDREG); break;
+ case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop0_reg(RDREG); break;
+ case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (INT32)get_cop0_creg(RDREG); break;
+ case 0x04: /* MTCz */ set_cop0_reg(RDREG, RTVAL32); break;
+ case 0x05: /* DMTCz */ set_cop0_reg(RDREG, RTVAL64); break;
+ case 0x06: /* CTCz */ set_cop0_creg(RDREG, RTVAL32); break;
+ case 0x08: /* BC */
+ switch (RTREG)
+ {
+ case 0x00: /* BCzF */ if (!mips3.core.cf[0]) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzF */ if (mips3.core.cf[0]) ADDPC(SIMMVAL); break;
+ case 0x02: /* BCzFL */ invalid_instruction(op); break;
+ case 0x03: /* BCzTL */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+ break;
+ 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: /* COP */
+ switch (op & 0x01ffffff)
+ {
+ case 0x01: /* TLBR */
+ mips3com_tlbr(&mips3.core);
+ break;
+
+ case 0x02: /* TLBWI */
+ mips3com_tlbwi(&mips3.core);
+ break;
+
+ case 0x06: /* TLBWR */
+ mips3com_tlbwr(&mips3.core);
+ break;
+
+ case 0x08: /* TLBP */
+ mips3com_tlbp(&mips3.core);
+ break;
+
+ case 0x10: /* RFE */ invalid_instruction(op); break;
+ case 0x18: /* ERET */ logerror("ERET\n"); mips3.core.pc = mips3.core.cpr[0][COP0_EPC]; SR &= ~SR_EXL; check_irqs(); mips3.lld_value ^= 0xffffffff; mips3.ll_value ^= 0xffffffff; break;
+ case 0x20: /* WAIT */ break;
+ default: invalid_instruction(op); break;
+ }
+ break;
+ default: invalid_instruction(op); break;
+ }
+}
+
+
+
+/***************************************************************************
+ COP1 (FPU) EXECUTION HANDLING
+***************************************************************************/
+
+INLINE UINT32 get_cop1_reg32(int idx)
+{
+ if (IS_FR0)
+ return ((UINT32 *)&mips3.core.cpr[1][0])[idx];
+ else
+ return mips3.core.cpr[1][idx];
+}
+
+INLINE UINT64 get_cop1_reg64(int idx)
+{
+ if (IS_FR0)
+ return ((UINT64 *)&mips3.core.cpr[1][0])[idx/2];
+ else
+ return mips3.core.cpr[1][idx];
+}
+
+INLINE void set_cop1_reg32(int idx, UINT32 val)
+{
+ if (IS_FR0)
+ ((UINT32 *)&mips3.core.cpr[1][0])[idx] = val;
+ else
+ mips3.core.cpr[1][idx] = val;
+}
+
+INLINE void set_cop1_reg64(int idx, UINT64 val)
+{
+ if (IS_FR0)
+ ((UINT64 *)&mips3.core.cpr[1][0])[idx/2] = val;
+ else
+ mips3.core.cpr[1][idx] = val;
+}
+
+INLINE UINT64 get_cop1_creg(int idx)
+{
+ if (idx == 31)
+ {
+ UINT32 result = mips3.core.ccr[1][31] & ~0xfe800000;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (mips3.core.cf[1][i])
+ result |= 1 << fcc_shift[i];
+ return result;
+ }
+ return mips3.core.ccr[1][idx];
+}
+
+INLINE void set_cop1_creg(int idx, UINT64 val)
+{
+ mips3.core.ccr[1][idx] = val;
+ if (idx == 31)
+ {
+ int i;
+
+ for (i = 0; i < 8; i++)
+ mips3.core.cf[1][i] = (val >> fcc_shift[i]) & 1;
+ }
+}
+
+INLINE void handle_cop1_fr0(UINT32 op)
+{
+ double dtemp;
+
+ /* note: additional condition codes available on R5000 only */
+
+ if (!(SR & SR_COP1))
+ generate_exception(EXCEPTION_BADCOP, 1);
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop1_reg32(RDREG); break;
+ case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop1_reg64(RDREG); break;
+ case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (INT32)get_cop1_creg(RDREG); break;
+ case 0x04: /* MTCz */ set_cop1_reg32(RDREG, RTVAL32); break;
+ case 0x05: /* DMTCz */ set_cop1_reg64(RDREG, RTVAL64); break;
+ case 0x06: /* CTCz */ set_cop1_creg(RDREG, RTVAL32); break;
+ case 0x08: /* BC */
+ switch ((op >> 16) & 3)
+ {
+ case 0x00: /* BCzF */ if (!GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzT */ if (GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); break;
+ case 0x02: /* BCzFL */ if (!GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ case 0x03: /* BCzTL */ if (GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ }
+ break;
+ default:
+ switch (op & 0x3f)
+ {
+ case 0x00:
+ if (IS_SINGLE(op)) /* ADD.S */
+ FDVALS_FR0 = FSVALS_FR0 + FTVALS_FR0;
+ else /* ADD.D */
+ FDVALD_FR0 = FSVALD_FR0 + FTVALD_FR0;
+ break;
+
+ case 0x01:
+ if (IS_SINGLE(op)) /* SUB.S */
+ FDVALS_FR0 = FSVALS_FR0 - FTVALS_FR0;
+ else /* SUB.D */
+ FDVALD_FR0 = FSVALD_FR0 - FTVALD_FR0;
+ break;
+
+ case 0x02:
+ if (IS_SINGLE(op)) /* MUL.S */
+ FDVALS_FR0 = FSVALS_FR0 * FTVALS_FR0;
+ else /* MUL.D */
+ FDVALD_FR0 = FSVALD_FR0 * FTVALD_FR0;
+ break;
+
+ case 0x03:
+ if (IS_SINGLE(op)) /* DIV.S */
+ FDVALS_FR0 = FSVALS_FR0 / FTVALS_FR0;
+ else /* DIV.D */
+ FDVALD_FR0 = FSVALD_FR0 / FTVALD_FR0;
+ break;
+
+ case 0x04:
+ if (IS_SINGLE(op)) /* SQRT.S */
+ FDVALS_FR0 = sqrt(FSVALS_FR0);
+ else /* SQRT.D */
+ FDVALD_FR0 = sqrt(FSVALD_FR0);
+ break;
+
+ case 0x05:
+ if (IS_SINGLE(op)) /* ABS.S */
+ FDVALS_FR0 = fabs(FSVALS_FR0);
+ else /* ABS.D */
+ FDVALD_FR0 = fabs(FSVALD_FR0);
+ break;
+
+ case 0x06:
+ if (IS_SINGLE(op)) /* MOV.S */
+ FDVALS_FR0 = FSVALS_FR0;
+ else /* MOV.D */
+ FDVALD_FR0 = FSVALD_FR0;
+ break;
+
+ case 0x07:
+ if (IS_SINGLE(op)) /* NEG.S */
+ FDVALS_FR0 = -FSVALS_FR0;
+ else /* NEG.D */
+ FDVALD_FR0 = -FSVALD_FR0;
+ break;
+
+ case 0x08:
+ if (IS_SINGLE(op)) /* ROUND.L.S */
+ {
+ double temp = FSVALS_FR0;
+ if (temp < 0)
+ temp = ceil(temp - 0.5);
+ else
+ temp = floor(temp + 0.5);
+ FDVALL_FR0 = (INT64)temp;
+ }
+ else /* ROUND.L.D */
+ {
+ double temp = FSVALD_FR0;
+ if (temp < 0)
+ temp = ceil(temp - 0.5);
+ else
+ temp = floor(temp + 0.5);
+ FDVALL_FR0 = (INT64)temp;
+ }
+ break;
+
+ case 0x09:
+ if (IS_SINGLE(op)) /* TRUNC.L.S */
+ {
+ double temp = FSVALS_FR0;
+ if (temp < 0)
+ temp = ceil(temp);
+ else
+ temp = floor(temp);
+ FDVALL_FR0 = (INT64)temp;
+ }
+ else /* TRUNC.L.D */
+ {
+ double temp = FSVALD_FR0;
+ if (temp < 0)
+ temp = ceil(temp);
+ else
+ temp = floor(temp);
+ FDVALL_FR0 = (INT64)temp;
+ }
+ break;
+
+ case 0x0a:
+ if (IS_SINGLE(op)) /* CEIL.L.S */
+ dtemp = ceil(FSVALS_FR0);
+ else /* CEIL.L.D */
+ dtemp = ceil(FSVALD_FR0);
+ FDVALL_FR0 = (INT64)dtemp;
+ break;
+
+ case 0x0b:
+ if (IS_SINGLE(op)) /* FLOOR.L.S */
+ dtemp = floor(FSVALS_FR0);
+ else /* FLOOR.L.D */
+ dtemp = floor(FSVALD_FR0);
+ FDVALL_FR0 = (INT64)dtemp;
+ break;
+
+ case 0x0c:
+ if (IS_SINGLE(op)) /* ROUND.W.S */
+ {
+ dtemp = FSVALS_FR0;
+ if (dtemp < 0)
+ dtemp = ceil(dtemp - 0.5);
+ else
+ dtemp = floor(dtemp + 0.5);
+ FDVALW_FR0 = (INT32)dtemp;
+ }
+ else /* ROUND.W.D */
+ {
+ dtemp = FSVALD_FR0;
+ if (dtemp < 0)
+ dtemp = ceil(dtemp - 0.5);
+ else
+ dtemp = floor(dtemp + 0.5);
+ FDVALW_FR0 = (INT32)dtemp;
+ }
+ break;
+
+ case 0x0d:
+ if (IS_SINGLE(op)) /* TRUNC.W.S */
+ {
+ dtemp = FSVALS_FR0;
+ if (dtemp < 0)
+ dtemp = ceil(dtemp);
+ else
+ dtemp = floor(dtemp);
+ FDVALW_FR0 = (INT32)dtemp;
+ }
+ else /* TRUNC.W.D */
+ {
+ dtemp = FSVALD_FR0;
+ if (dtemp < 0)
+ dtemp = ceil(dtemp);
+ else
+ dtemp = floor(dtemp);
+ FDVALW_FR0 = (INT32)dtemp;
+ }
+ break;
+
+ case 0x0e:
+ if (IS_SINGLE(op)) /* CEIL.W.S */
+ dtemp = ceil(FSVALS_FR0);
+ else /* CEIL.W.D */
+ dtemp = ceil(FSVALD_FR0);
+ FDVALW_FR0 = (INT32)dtemp;
+ break;
+
+ case 0x0f:
+ if (IS_SINGLE(op)) /* FLOOR.W.S */
+ dtemp = floor(FSVALS_FR0);
+ else /* FLOOR.W.D */
+ dtemp = floor(FSVALD_FR0);
+ FDVALW_FR0 = (INT32)dtemp;
+ break;
+
+ case 0x11: /* R5000 */
+ if (GET_FCC((op >> 18) & 7) == ((op >> 16) & 1))
+ {
+ if (IS_SINGLE(op)) /* MOVT/F.S */
+ FDVALS_FR0 = FSVALS_FR0;
+ else /* MOVT/F.D */
+ FDVALD_FR0 = FSVALD_FR0;
+ }
+ break;
+
+ case 0x12: /* R5000 */
+ if (RTVAL64 == 0)
+ {
+ if (IS_SINGLE(op)) /* MOVZ.S */
+ FDVALS_FR0 = FSVALS_FR0;
+ else /* MOVZ.D */
+ FDVALD_FR0 = FSVALD_FR0;
+ }
+ break;
+
+ case 0x13: /* R5000 */
+ if (RTVAL64 != 0)
+ {
+ if (IS_SINGLE(op)) /* MOVN.S */
+ FDVALS_FR0 = FSVALS_FR0;
+ else /* MOVN.D */
+ FDVALD_FR0 = FSVALD_FR0;
+ }
+ break;
+
+ case 0x15: /* R5000 */
+ if (IS_SINGLE(op)) /* RECIP.S */
+ FDVALS_FR0 = 1.0f / FSVALS_FR0;
+ else /* RECIP.D */
+ FDVALD_FR0 = 1.0 / FSVALD_FR0;
+ break;
+
+ case 0x16: /* R5000 */
+ if (IS_SINGLE(op)) /* RSQRT.S */
+ FDVALS_FR0 = 1.0f / sqrt(FSVALS_FR0);
+ else /* RSQRT.D */
+ FDVALD_FR0 = 1.0 / sqrt(FSVALD_FR0);
+ break;
+
+ case 0x20:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.S.W */
+ FDVALS_FR0 = (INT32)FSVALW_FR0;
+ else /* CVT.S.L */
+ FDVALS_FR0 = (INT64)FSVALL_FR0;
+ }
+ else /* CVT.S.D */
+ FDVALS_FR0 = FSVALD_FR0;
+ break;
+
+ case 0x21:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.D.W */
+ FDVALD_FR0 = (INT32)FSVALW_FR0;
+ else /* CVT.D.L */
+ FDVALD_FR0 = (INT64)FSVALL_FR0;
+ }
+ else /* CVT.D.S */
+ FDVALD_FR0 = FSVALS_FR0;
+ break;
+
+ case 0x24:
+ if (IS_SINGLE(op)) /* CVT.W.S */
+ FDVALW_FR0 = (INT32)FSVALS_FR0;
+ else
+ FDVALW_FR0 = (INT32)FSVALD_FR0;
+ break;
+
+ case 0x25:
+ if (IS_SINGLE(op)) /* CVT.L.S */
+ FDVALL_FR0 = (INT64)FSVALS_FR0;
+ else /* CVT.L.D */
+ FDVALL_FR0 = (INT64)FSVALD_FR0;
+ break;
+
+ case 0x30:
+ case 0x38:
+ if (IS_SINGLE(op)) /* C.F.S */
+ SET_FCC((op >> 8) & 7, 0);
+ else /* C.F.D */
+ SET_FCC((op >> 8) & 7, 0);
+ break;
+
+ case 0x31:
+ case 0x39:
+ if (IS_SINGLE(op)) /* C.UN.S */
+ SET_FCC((op >> 8) & 7, 0);
+ else /* C.UN.D */
+ SET_FCC((op >> 8) & 7, 0);
+ break;
+
+ case 0x32:
+ case 0x3a:
+ if (IS_SINGLE(op)) /* C.EQ.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR0 == FTVALS_FR0));
+ else /* C.EQ.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR0 == FTVALD_FR0));
+ break;
+
+ case 0x33:
+ case 0x3b:
+ if (IS_SINGLE(op)) /* C.UEQ.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR0 == FTVALS_FR0));
+ else /* C.UEQ.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR0 == FTVALD_FR0));
+ break;
+
+ case 0x34:
+ case 0x3c:
+ if (IS_SINGLE(op)) /* C.OLT.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR0 < FTVALS_FR0));
+ else /* C.OLT.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR0 < FTVALD_FR0));
+ break;
+
+ case 0x35:
+ case 0x3d:
+ if (IS_SINGLE(op)) /* C.ULT.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR0 < FTVALS_FR0));
+ else /* C.ULT.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR0 < FTVALD_FR0));
+ break;
+
+ case 0x36:
+ case 0x3e:
+ if (IS_SINGLE(op)) /* C.OLE.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR0 <= FTVALS_FR0));
+ else /* C.OLE.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR0 <= FTVALD_FR0));
+ break;
+
+ case 0x37:
+ case 0x3f:
+ if (IS_SINGLE(op)) /* C.ULE.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR0 <= FTVALS_FR0));
+ else /* C.ULE.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR0 <= FTVALD_FR0));
+ break;
+
+ default:
+ fprintf(stderr, "cop1 %X\n", op);
+ break;
+ }
+ break;
+ }
+}
+
+
+INLINE void handle_cop1_fr1(UINT32 op)
+{
+ double dtemp;
+
+ /* note: additional condition codes available on R5000 only */
+
+ if (!(SR & SR_COP1))
+ generate_exception(EXCEPTION_BADCOP, 1);
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop1_reg32(RDREG); break;
+ case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop1_reg64(RDREG); break;
+ case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (INT32)get_cop1_creg(RDREG); break;
+ case 0x04: /* MTCz */ set_cop1_reg32(RDREG, RTVAL32); break;
+ case 0x05: /* DMTCz */ set_cop1_reg64(RDREG, RTVAL64); break;
+ case 0x06: /* CTCz */ set_cop1_creg(RDREG, RTVAL32); break;
+ case 0x08: /* BC */
+ switch ((op >> 16) & 3)
+ {
+ case 0x00: /* BCzF */ if (!GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzT */ if (GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); break;
+ case 0x02: /* BCzFL */ if (!GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ case 0x03: /* BCzTL */ if (GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ }
+ break;
+ default:
+ switch (op & 0x3f)
+ {
+ case 0x00:
+ if (IS_SINGLE(op)) /* ADD.S */
+ FDVALS_FR1 = FSVALS_FR1 + FTVALS_FR1;
+ else /* ADD.D */
+ FDVALD_FR1 = FSVALD_FR1 + FTVALD_FR1;
+ break;
+
+ case 0x01:
+ if (IS_SINGLE(op)) /* SUB.S */
+ FDVALS_FR1 = FSVALS_FR1 - FTVALS_FR1;
+ else /* SUB.D */
+ FDVALD_FR1 = FSVALD_FR1 - FTVALD_FR1;
+ break;
+
+ case 0x02:
+ if (IS_SINGLE(op)) /* MUL.S */
+ FDVALS_FR1 = FSVALS_FR1 * FTVALS_FR1;
+ else /* MUL.D */
+ FDVALD_FR1 = FSVALD_FR1 * FTVALD_FR1;
+ break;
+
+ case 0x03:
+ if (IS_SINGLE(op)) /* DIV.S */
+ FDVALS_FR1 = FSVALS_FR1 / FTVALS_FR1;
+ else /* DIV.D */
+ FDVALD_FR1 = FSVALD_FR1 / FTVALD_FR1;
+ break;
+
+ case 0x04:
+ if (IS_SINGLE(op)) /* SQRT.S */
+ FDVALS_FR1 = sqrt(FSVALS_FR1);
+ else /* SQRT.D */
+ FDVALD_FR1 = sqrt(FSVALD_FR1);
+ break;
+
+ case 0x05:
+ if (IS_SINGLE(op)) /* ABS.S */
+ FDVALS_FR1 = fabs(FSVALS_FR1);
+ else /* ABS.D */
+ FDVALD_FR1 = fabs(FSVALD_FR1);
+ break;
+
+ case 0x06:
+ if (IS_SINGLE(op)) /* MOV.S */
+ FDVALS_FR1 = FSVALS_FR1;
+ else /* MOV.D */
+ FDVALD_FR1 = FSVALD_FR1;
+ break;
+
+ case 0x07:
+ if (IS_SINGLE(op)) /* NEG.S */
+ FDVALS_FR1 = -FSVALS_FR1;
+ else /* NEG.D */
+ FDVALD_FR1 = -FSVALD_FR1;
+ break;
+
+ case 0x08:
+ if (IS_SINGLE(op)) /* ROUND.L.S */
+ {
+ double temp = FSVALS_FR1;
+ if (temp < 0)
+ temp = ceil(temp - 0.5);
+ else
+ temp = floor(temp + 0.5);
+ FDVALL_FR1 = (INT64)temp;
+ }
+ else /* ROUND.L.D */
+ {
+ double temp = FSVALD_FR1;
+ if (temp < 0)
+ temp = ceil(temp - 0.5);
+ else
+ temp = floor(temp + 0.5);
+ FDVALL_FR1 = (INT64)temp;
+ }
+ break;
+
+ case 0x09:
+ if (IS_SINGLE(op)) /* TRUNC.L.S */
+ {
+ double temp = FSVALS_FR1;
+ if (temp < 0)
+ temp = ceil(temp);
+ else
+ temp = floor(temp);
+ FDVALL_FR1 = (INT64)temp;
+ }
+ else /* TRUNC.L.D */
+ {
+ double temp = FSVALD_FR1;
+ if (temp < 0)
+ temp = ceil(temp);
+ else
+ temp = floor(temp);
+ FDVALL_FR1 = (INT64)temp;
+ }
+ break;
+
+ case 0x0a:
+ if (IS_SINGLE(op)) /* CEIL.L.S */
+ dtemp = ceil(FSVALS_FR1);
+ else /* CEIL.L.D */
+ dtemp = ceil(FSVALD_FR1);
+ FDVALL_FR1 = (INT64)dtemp;
+ break;
+
+ case 0x0b:
+ if (IS_SINGLE(op)) /* FLOOR.L.S */
+ dtemp = floor(FSVALS_FR1);
+ else /* FLOOR.L.D */
+ dtemp = floor(FSVALD_FR1);
+ FDVALL_FR1 = (INT64)dtemp;
+ break;
+
+ case 0x0c:
+ if (IS_SINGLE(op)) /* ROUND.W.S */
+ {
+ dtemp = FSVALS_FR1;
+ if (dtemp < 0)
+ dtemp = ceil(dtemp - 0.5);
+ else
+ dtemp = floor(dtemp + 0.5);
+ FDVALW_FR1 = (INT32)dtemp;
+ }
+ else /* ROUND.W.D */
+ {
+ dtemp = FSVALD_FR1;
+ if (dtemp < 0)
+ dtemp = ceil(dtemp - 0.5);
+ else
+ dtemp = floor(dtemp + 0.5);
+ FDVALW_FR1 = (INT32)dtemp;
+ }
+ break;
+
+ case 0x0d:
+ if (IS_SINGLE(op)) /* TRUNC.W.S */
+ {
+ dtemp = FSVALS_FR1;
+ if (dtemp < 0)
+ dtemp = ceil(dtemp);
+ else
+ dtemp = floor(dtemp);
+ FDVALW_FR1 = (INT32)dtemp;
+ }
+ else /* TRUNC.W.D */
+ {
+ dtemp = FSVALD_FR1;
+ if (dtemp < 0)
+ dtemp = ceil(dtemp);
+ else
+ dtemp = floor(dtemp);
+ FDVALW_FR1 = (INT32)dtemp;
+ }
+ break;
+
+ case 0x0e:
+ if (IS_SINGLE(op)) /* CEIL.W.S */
+ dtemp = ceil(FSVALS_FR1);
+ else /* CEIL.W.D */
+ dtemp = ceil(FSVALD_FR1);
+ FDVALW_FR1 = (INT32)dtemp;
+ break;
+
+ case 0x0f:
+ if (IS_SINGLE(op)) /* FLOOR.W.S */
+ dtemp = floor(FSVALS_FR1);
+ else /* FLOOR.W.D */
+ dtemp = floor(FSVALD_FR1);
+ FDVALW_FR1 = (INT32)dtemp;
+ break;
+
+ case 0x11: /* R5000 */
+ if (GET_FCC((op >> 18) & 7) == ((op >> 16) & 1))
+ {
+ if (IS_SINGLE(op)) /* MOVT/F.S */
+ FDVALS_FR1 = FSVALS_FR1;
+ else /* MOVT/F.D */
+ FDVALD_FR1 = FSVALD_FR1;
+ }
+ break;
+
+ case 0x12: /* R5000 */
+ if (RTVAL64 == 0)
+ {
+ if (IS_SINGLE(op)) /* MOVZ.S */
+ FDVALS_FR1 = FSVALS_FR1;
+ else /* MOVZ.D */
+ FDVALD_FR1 = FSVALD_FR1;
+ }
+ break;
+
+ case 0x13: /* R5000 */
+ if (RTVAL64 != 0)
+ {
+ if (IS_SINGLE(op)) /* MOVN.S */
+ FDVALS_FR1 = FSVALS_FR1;
+ else /* MOVN.D */
+ FDVALD_FR1 = FSVALD_FR1;
+ }
+ break;
+
+ case 0x15: /* R5000 */
+ if (IS_SINGLE(op)) /* RECIP.S */
+ FDVALS_FR1 = 1.0f / FSVALS_FR1;
+ else /* RECIP.D */
+ FDVALD_FR1 = 1.0 / FSVALD_FR1;
+ break;
+
+ case 0x16: /* R5000 */
+ if (IS_SINGLE(op)) /* RSQRT.S */
+ FDVALS_FR1 = 1.0f / sqrt(FSVALS_FR1);
+ else /* RSQRT.D */
+ FDVALD_FR1 = 1.0 / sqrt(FSVALD_FR1);
+ break;
+
+ case 0x20:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.S.W */
+ FDVALS_FR1 = (INT32)FSVALW_FR1;
+ else /* CVT.S.L */
+ FDVALS_FR1 = (INT64)FSVALL_FR1;
+ }
+ else /* CVT.S.D */
+ FDVALS_FR1 = FSVALD_FR1;
+ break;
+
+ case 0x21:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.D.W */
+ FDVALD_FR1 = (INT32)FSVALW_FR1;
+ else /* CVT.D.L */
+ FDVALD_FR1 = (INT64)FSVALL_FR1;
+ }
+ else /* CVT.D.S */
+ FDVALD_FR1 = FSVALS_FR1;
+ break;
+
+ case 0x24:
+ if (IS_SINGLE(op)) /* CVT.W.S */
+ FDVALW_FR1 = (INT32)FSVALS_FR1;
+ else
+ FDVALW_FR1 = (INT32)FSVALD_FR1;
+ break;
+
+ case 0x25:
+ if (IS_SINGLE(op)) /* CVT.L.S */
+ FDVALL_FR1 = (INT64)FSVALS_FR1;
+ else /* CVT.L.D */
+ FDVALL_FR1 = (INT64)FSVALD_FR1;
+ break;
+
+ case 0x30:
+ case 0x38:
+ if (IS_SINGLE(op)) /* C.F.S */
+ SET_FCC((op >> 8) & 7, 0);
+ else /* C.F.D */
+ SET_FCC((op >> 8) & 7, 0);
+ break;
+
+ case 0x31:
+ case 0x39:
+ if (IS_SINGLE(op)) /* C.UN.S */
+ SET_FCC((op >> 8) & 7, 0);
+ else /* C.UN.D */
+ SET_FCC((op >> 8) & 7, 0);
+ break;
+
+ case 0x32:
+ case 0x3a:
+ if (IS_SINGLE(op)) /* C.EQ.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR1 == FTVALS_FR1));
+ else /* C.EQ.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR1 == FTVALD_FR1));
+ break;
+
+ case 0x33:
+ case 0x3b:
+ if (IS_SINGLE(op)) /* C.UEQ.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR1 == FTVALS_FR1));
+ else /* C.UEQ.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR1 == FTVALD_FR1));
+ break;
+
+ case 0x34:
+ case 0x3c:
+ if (IS_SINGLE(op)) /* C.OLT.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR1 < FTVALS_FR1));
+ else /* C.OLT.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR1 < FTVALD_FR1));
+ break;
+
+ case 0x35:
+ case 0x3d:
+ if (IS_SINGLE(op)) /* C.ULT.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR1 < FTVALS_FR1));
+ else /* C.ULT.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR1 < FTVALD_FR1));
+ break;
+
+ case 0x36:
+ case 0x3e:
+ if (IS_SINGLE(op)) /* C.OLE.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR1 <= FTVALS_FR1));
+ else /* C.OLE.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR1 <= FTVALD_FR1));
+ break;
+
+ case 0x37:
+ case 0x3f:
+ if (IS_SINGLE(op)) /* C.ULE.S */
+ SET_FCC((op >> 8) & 7, (FSVALS_FR1 <= FTVALS_FR1));
+ else /* C.ULE.D */
+ SET_FCC((op >> 8) & 7, (FSVALD_FR1 <= FTVALD_FR1));
+ break;
+
+ default:
+ fprintf(stderr, "cop1 %X\n", op);
+ break;
+ }
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ COP1X (FPU EXTRA) EXECUTION HANDLING
+***************************************************************************/
+
+INLINE void handle_cop1x_fr0(UINT32 op)
+{
+ UINT64 temp64;
+ UINT32 temp;
+
+ if (!(SR & SR_COP1))
+ generate_exception(EXCEPTION_BADCOP, 1);
+
+ switch (op & 0x3f)
+ {
+ case 0x00: /* LWXC1 */
+ if (RWORD(RSVAL32 + RTVAL32, &temp)) FDVALW_FR0 = temp;
+ break;
+
+ case 0x01: /* LDXC1 */
+ if (RDOUBLE(RSVAL32 + RTVAL32, &temp64)) FDVALL_FR0 = temp64;
+ break;
+
+ case 0x08: /* SWXC1 */
+ WWORD(RSVAL32 + RTVAL32, get_cop1_reg32(FDREG));
+ break;
+
+ case 0x09: /* SDXC1 */
+ WDOUBLE(RSVAL32 + RTVAL32, get_cop1_reg64(FDREG));
+ break;
+
+ case 0x0f: /* PREFX */
+ break;
+
+ case 0x20: /* MADD.S */
+ FDVALS_FR0 = FSVALS_FR0 * FTVALS_FR0 + FRVALS_FR0;
+ break;
+
+ case 0x21: /* MADD.D */
+ FDVALD_FR0 = FSVALD_FR0 * FTVALD_FR0 + FRVALD_FR0;
+ break;
+
+ case 0x28: /* MSUB.S */
+ FDVALS_FR0 = FSVALS_FR0 * FTVALS_FR0 - FRVALS_FR0;
+ break;
+
+ case 0x29: /* MSUB.D */
+ FDVALD_FR0 = FSVALD_FR0 * FTVALD_FR0 - FRVALD_FR0;
+ break;
+
+ case 0x30: /* NMADD.S */
+ FDVALS_FR0 = -(FSVALS_FR0 * FTVALS_FR0 + FRVALS_FR0);
+ break;
+
+ case 0x31: /* NMADD.D */
+ FDVALD_FR0 = -(FSVALD_FR0 * FTVALD_FR0 + FRVALD_FR0);
+ break;
+
+ case 0x38: /* NMSUB.S */
+ FDVALS_FR0 = -(FSVALS_FR0 * FTVALS_FR0 - FRVALS_FR0);
+ break;
+
+ case 0x39: /* NMSUB.D */
+ FDVALD_FR0 = -(FSVALD_FR0 * FTVALD_FR0 - FRVALD_FR0);
+ break;
+
+ case 0x24: /* MADD.W */
+ case 0x25: /* MADD.L */
+ case 0x2c: /* MSUB.W */
+ case 0x2d: /* MSUB.L */
+ case 0x34: /* NMADD.W */
+ case 0x35: /* NMADD.L */
+ case 0x3c: /* NMSUB.W */
+ case 0x3d: /* NMSUB.L */
+ default:
+ fprintf(stderr, "cop1x %X\n", op);
+ break;
+ }
+}
+
+
+INLINE void handle_cop1x_fr1(UINT32 op)
+{
+ UINT64 temp64;
+ UINT32 temp;
+
+ if (!(SR & SR_COP1))
+ generate_exception(EXCEPTION_BADCOP, 1);
+
+ switch (op & 0x3f)
+ {
+ case 0x00: /* LWXC1 */
+ if (RWORD(RSVAL32 + RTVAL32, &temp)) FDVALW_FR1 = temp;
+ break;
+
+ case 0x01: /* LDXC1 */
+ if (RDOUBLE(RSVAL32 + RTVAL32, &temp64)) FDVALL_FR1 = temp64;
+ break;
+
+ case 0x08: /* SWXC1 */
+ WWORD(RSVAL32 + RTVAL32, get_cop1_reg32(FDREG));
+ break;
+
+ case 0x09: /* SDXC1 */
+ WDOUBLE(RSVAL32 + RTVAL32, get_cop1_reg64(FDREG));
+ break;
+
+ case 0x0f: /* PREFX */
+ break;
+
+ case 0x20: /* MADD.S */
+ FDVALS_FR1 = FSVALS_FR1 * FTVALS_FR1 + FRVALS_FR1;
+ break;
+
+ case 0x21: /* MADD.D */
+ FDVALD_FR1 = FSVALD_FR1 * FTVALD_FR1 + FRVALD_FR1;
+ break;
+
+ case 0x28: /* MSUB.S */
+ FDVALS_FR1 = FSVALS_FR1 * FTVALS_FR1 - FRVALS_FR1;
+ break;
+
+ case 0x29: /* MSUB.D */
+ FDVALD_FR1 = FSVALD_FR1 * FTVALD_FR1 - FRVALD_FR1;
+ break;
+
+ case 0x30: /* NMADD.S */
+ FDVALS_FR1 = -(FSVALS_FR1 * FTVALS_FR1 + FRVALS_FR1);
+ break;
+
+ case 0x31: /* NMADD.D */
+ FDVALD_FR1 = -(FSVALD_FR1 * FTVALD_FR1 + FRVALD_FR1);
+ break;
+
+ case 0x38: /* NMSUB.S */
+ FDVALS_FR1 = -(FSVALS_FR1 * FTVALS_FR1 - FRVALS_FR1);
+ break;
+
+ case 0x39: /* NMSUB.D */
+ FDVALD_FR1 = -(FSVALD_FR1 * FTVALD_FR1 - FRVALD_FR1);
+ break;
+
+ case 0x24: /* MADD.W */
+ case 0x25: /* MADD.L */
+ case 0x2c: /* MSUB.W */
+ case 0x2d: /* MSUB.L */
+ case 0x34: /* NMADD.W */
+ case 0x35: /* NMADD.L */
+ case 0x3c: /* NMSUB.W */
+ case 0x3d: /* NMSUB.L */
+ default:
+ fprintf(stderr, "cop1x %X\n", op);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ COP2 (CUSTOM) EXECUTION HANDLING
+***************************************************************************/
+
+INLINE UINT64 get_cop2_reg(int idx)
+{
+ return mips3.core.cpr[2][idx];
+}
+
+INLINE void set_cop2_reg(int idx, UINT64 val)
+{
+ mips3.core.cpr[2][idx] = val;
+}
+
+INLINE UINT64 get_cop2_creg(int idx)
+{
+ return mips3.core.ccr[2][idx];
+}
+
+INLINE void set_cop2_creg(int idx, UINT64 val)
+{
+ mips3.core.ccr[2][idx] = val;
+}
+
+INLINE void handle_cop2(UINT32 op)
+{
+ if (!(SR & SR_COP2))
+ generate_exception(EXCEPTION_BADCOP, 1);
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop2_reg(RDREG); break;
+ case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop2_reg(RDREG); break;
+ case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (INT32)get_cop2_creg(RDREG); break;
+ case 0x04: /* MTCz */ set_cop2_reg(RDREG, RTVAL32); break;
+ case 0x05: /* DMTCz */ set_cop2_reg(RDREG, RTVAL64); break;
+ case 0x06: /* CTCz */ set_cop2_creg(RDREG, RTVAL32); break;
+ case 0x08: /* BC */
+ switch (RTREG)
+ {
+ case 0x00: /* BCzF */ if (!mips3.core.cf[2]) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzF */ if (mips3.core.cf[2]) ADDPC(SIMMVAL); break;
+ case 0x02: /* BCzFL */ invalid_instruction(op); break;
+ case 0x03: /* BCzTL */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+ break;
+ 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: /* COP */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+}
+
+
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+int mips3_execute(int cycles)
+{
+ /* count cycles and interrupt cycles */
+ mips3.core.icount = cycles;
+ mips3.core.icount -= mips3.interrupt_cycles;
+ mips3.interrupt_cycles = 0;
+
+ /* update timers & such */
+ mips3com_update_cycle_counting(&mips3.core);
+
+ /* check for IRQs */
+ check_irqs();
+
+ /* core execution loop */
+ do
+ {
+ UINT32 op;
+ UINT64 temp64 = 0;
+ UINT32 temp;
+
+ /* see if we crossed a page boundary */
+ if ((mips3.core.pc ^ mips3.ppc) & 0xfffff000)
+ if (!update_pcbase())
+ continue;
+
+ /* debugging */
+ mips3.ppc = mips3.core.pc;
+ CALL_MAME_DEBUG;
+
+ /* instruction fetch */
+ op = ROPCODE(mips3.pcbase | (mips3.core.pc & 0xfff));
+
+ /* adjust for next PC */
+ if (mips3.nextpc != ~0)
+ {
+ mips3.core.pc = mips3.nextpc;
+ mips3.nextpc = ~0;
+ }
+ else
+ mips3.core.pc += 4;
+
+ /* parse the instruction */
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ switch (op & 63)
+ {
+ case 0x00: /* SLL */ if (RDREG) RDVAL64 = (INT32)(RTVAL32 << SHIFT); break;
+ case 0x01: /* MOVF - R5000*/if (RDREG && GET_FCC((op >> 18) & 7) == ((op >> 16) & 1)) RDVAL64 = RSVAL64; break;
+ case 0x02: /* SRL */ if (RDREG) RDVAL64 = (INT32)(RTVAL32 >> SHIFT); break;
+ case 0x03: /* SRA */ if (RDREG) RDVAL64 = (INT32)RTVAL32 >> SHIFT; break;
+ case 0x04: /* SLLV */ if (RDREG) RDVAL64 = (INT32)(RTVAL32 << (RSVAL32 & 31)); break;
+ case 0x06: /* SRLV */ if (RDREG) RDVAL64 = (INT32)(RTVAL32 >> (RSVAL32 & 31)); break;
+ case 0x07: /* SRAV */ if (RDREG) RDVAL64 = (INT32)RTVAL32 >> (RSVAL32 & 31); break;
+ case 0x08: /* JR */ SETPC(RSVAL32); break;
+ case 0x09: /* JALR */ SETPCL(RSVAL32,RDREG); break;
+ case 0x0a: /* MOVZ - R5000 */if (RTVAL64 == 0) { if (RDREG) RDVAL64 = RSVAL64; } break;
+ case 0x0b: /* MOVN - R5000 */if (RTVAL64 != 0) { if (RDREG) RDVAL64 = RSVAL64; } break;
+ case 0x0c: /* SYSCALL */ generate_exception(EXCEPTION_SYSCALL, 1); break;
+ case 0x0d: /* BREAK */ generate_exception(EXCEPTION_BREAK, 1); break;
+ case 0x0f: /* SYNC */ /* effective no-op */ break;
+ case 0x10: /* MFHI */ if (RDREG) RDVAL64 = HIVAL64; break;
+ case 0x11: /* MTHI */ HIVAL64 = RSVAL64; break;
+ case 0x12: /* MFLO */ if (RDREG) RDVAL64 = LOVAL64; break;
+ case 0x13: /* MTLO */ LOVAL64 = RSVAL64; break;
+ case 0x14: /* DSLLV */ if (RDREG) RDVAL64 = RTVAL64 << (RSVAL32 & 63); break;
+ case 0x16: /* DSRLV */ if (RDREG) RDVAL64 = RTVAL64 >> (RSVAL32 & 63); break;
+ case 0x17: /* DSRAV */ if (RDREG) RDVAL64 = (INT64)RTVAL64 >> (RSVAL32 & 63); break;
+ case 0x18: /* MULT */
+ temp64 = (INT64)(INT32)RSVAL32 * (INT64)(INT32)RTVAL32;
+ LOVAL64 = (INT32)temp64;
+ HIVAL64 = (INT32)(temp64 >> 32);
+ mips3.core.icount -= 3;
+ break;
+ case 0x19: /* MULTU */
+ temp64 = (UINT64)RSVAL32 * (UINT64)RTVAL32;
+ LOVAL64 = (INT32)temp64;
+ HIVAL64 = (INT32)(temp64 >> 32);
+ mips3.core.icount -= 3;
+ break;
+ case 0x1a: /* DIV */
+ if (RTVAL32)
+ {
+ LOVAL64 = (INT32)((INT32)RSVAL32 / (INT32)RTVAL32);
+ HIVAL64 = (INT32)((INT32)RSVAL32 % (INT32)RTVAL32);
+ }
+ mips3.core.icount -= 35;
+ break;
+ case 0x1b: /* DIVU */
+ if (RTVAL32)
+ {
+ LOVAL64 = (INT32)(RSVAL32 / RTVAL32);
+ HIVAL64 = (INT32)(RSVAL32 % RTVAL32);
+ }
+ mips3.core.icount -= 35;
+ break;
+ case 0x1c: /* DMULT */
+ temp64 = (INT64)RSVAL64 * (INT64)RTVAL64;
+ LOVAL64 = temp64;
+ HIVAL64 = (INT64)temp64 >> 63;
+ mips3.core.icount -= 7;
+ break;
+ case 0x1d: /* DMULTU */
+ temp64 = (UINT64)RSVAL64 * (UINT64)RTVAL64;
+ LOVAL64 = temp64;
+ HIVAL64 = 0;
+ mips3.core.icount -= 7;
+ break;
+ case 0x1e: /* DDIV */
+ if (RTVAL64)
+ {
+ LOVAL64 = (INT64)RSVAL64 / (INT64)RTVAL64;
+ HIVAL64 = (INT64)RSVAL64 % (INT64)RTVAL64;
+ }
+ mips3.core.icount -= 67;
+ break;
+ case 0x1f: /* DDIVU */
+ if (RTVAL64)
+ {
+ LOVAL64 = RSVAL64 / RTVAL64;
+ HIVAL64 = RSVAL64 % RTVAL64;
+ }
+ mips3.core.icount -= 67;
+ break;
+ case 0x20: /* ADD */
+ if (ENABLE_OVERFLOWS && RSVAL32 > ~RTVAL32) generate_exception(EXCEPTION_OVERFLOW, 1);
+ else RDVAL64 = (INT32)(RSVAL32 + RTVAL32);
+ break;
+ case 0x21: /* ADDU */ if (RDREG) RDVAL64 = (INT32)(RSVAL32 + RTVAL32); break;
+ case 0x22: /* SUB */
+ if (ENABLE_OVERFLOWS && RSVAL32 < RTVAL32) generate_exception(EXCEPTION_OVERFLOW, 1);
+ else RDVAL64 = (INT32)(RSVAL32 - RTVAL32);
+ break;
+ case 0x23: /* SUBU */ if (RDREG) RDVAL64 = (INT32)(RSVAL32 - RTVAL32); break;
+ case 0x24: /* AND */ if (RDREG) RDVAL64 = RSVAL64 & RTVAL64; break;
+ case 0x25: /* OR */ if (RDREG) RDVAL64 = RSVAL64 | RTVAL64; break;
+ case 0x26: /* XOR */ if (RDREG) RDVAL64 = RSVAL64 ^ RTVAL64; break;
+ case 0x27: /* NOR */ if (RDREG) RDVAL64 = ~(RSVAL64 | RTVAL64); break;
+ case 0x2a: /* SLT */ if (RDREG) RDVAL64 = (INT64)RSVAL64 < (INT64)RTVAL64; break;
+ case 0x2b: /* SLTU */ if (RDREG) RDVAL64 = (UINT64)RSVAL64 < (UINT64)RTVAL64; break;
+ case 0x2c: /* DADD */
+ if (ENABLE_OVERFLOWS && RSVAL64 > ~RTVAL64) generate_exception(EXCEPTION_OVERFLOW, 1);
+ else RDVAL64 = RSVAL64 + RTVAL64;
+ break;
+ case 0x2d: /* DADDU */ if (RDREG) RDVAL64 = RSVAL64 + RTVAL64; break;
+ case 0x2e: /* DSUB */
+ if (ENABLE_OVERFLOWS && RSVAL64 < RTVAL64) generate_exception(EXCEPTION_OVERFLOW, 1);
+ else RDVAL64 = RSVAL64 - RTVAL64;
+ break;
+ case 0x2f: /* DSUBU */ if (RDREG) RDVAL64 = RSVAL64 - RTVAL64; break;
+ case 0x30: /* TGE */ if ((INT64)RSVAL64 >= (INT64)RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x31: /* TGEU */ if (RSVAL64 >= RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x32: /* TLT */ if ((INT64)RSVAL64 < (INT64)RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x33: /* TLTU */ if (RSVAL64 < RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x34: /* TEQ */ if (RSVAL64 == RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x36: /* TNE */ if (RSVAL64 != RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x38: /* DSLL */ if (RDREG) RDVAL64 = RTVAL64 << SHIFT; break;
+ case 0x3a: /* DSRL */ if (RDREG) RDVAL64 = RTVAL64 >> SHIFT; break;
+ case 0x3b: /* DSRA */ if (RDREG) RDVAL64 = (INT64)RTVAL64 >> SHIFT; break;
+ case 0x3c: /* DSLL32 */ if (RDREG) RDVAL64 = RTVAL64 << (SHIFT + 32); break;
+ case 0x3e: /* DSRL32 */ if (RDREG) RDVAL64 = RTVAL64 >> (SHIFT + 32); break;
+ case 0x3f: /* DSRA32 */ if (RDREG) RDVAL64 = (INT64)RTVAL64 >> (SHIFT + 32); break;
+ default: /* ??? */ invalid_instruction(op); break;
+ }
+ break;
+
+ case 0x01: /* REGIMM */
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */ if ((INT64)RSVAL64 < 0) ADDPC(SIMMVAL); break;
+ case 0x01: /* BGEZ */ if ((INT64)RSVAL64 >= 0) ADDPC(SIMMVAL); break;
+ case 0x02: /* BLTZL */ if ((INT64)RSVAL64 < 0) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ case 0x03: /* BGEZL */ if ((INT64)RSVAL64 >= 0) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ case 0x08: /* TGEI */ if ((INT64)RSVAL64 >= SIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x09: /* TGEIU */ if (RSVAL64 >= SIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x0a: /* TLTI */ if ((INT64)RSVAL64 < SIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x0b: /* TLTIU */ if (RSVAL64 >= SIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x0c: /* TEQI */ if (RSVAL64 == SIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x0e: /* TNEI */ if (RSVAL64 != SIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break;
+ case 0x10: /* BLTZAL */ if ((INT64)RSVAL64 < 0) ADDPCL(SIMMVAL,31); break;
+ case 0x11: /* BGEZAL */ if ((INT64)RSVAL64 >= 0) ADDPCL(SIMMVAL,31); break;
+ case 0x12: /* BLTZALL */ if ((INT64)RSVAL64 < 0) ADDPCL(SIMMVAL,31) else mips3.core.pc += 4; break;
+ case 0x13: /* BGEZALL */ if ((INT64)RSVAL64 >= 0) ADDPCL(SIMMVAL,31) else mips3.core.pc += 4; break;
+ default: /* ??? */ invalid_instruction(op); break;
+ }
+ break;
+
+ case 0x02: /* J */ ABSPC(LIMMVAL); break;
+ case 0x03: /* JAL */ ABSPCL(LIMMVAL,31); break;
+ case 0x04: /* BEQ */ if (RSVAL64 == RTVAL64) ADDPC(SIMMVAL); break;
+ case 0x05: /* BNE */ if (RSVAL64 != RTVAL64) ADDPC(SIMMVAL); break;
+ case 0x06: /* BLEZ */ if ((INT64)RSVAL64 <= 0) ADDPC(SIMMVAL); break;
+ case 0x07: /* BGTZ */ if ((INT64)RSVAL64 > 0) ADDPC(SIMMVAL); break;
+ case 0x08: /* ADDI */
+ if (ENABLE_OVERFLOWS && RSVAL32 > ~SIMMVAL) generate_exception(EXCEPTION_OVERFLOW, 1);
+ else if (RTREG) RTVAL64 = (INT32)(RSVAL32 + SIMMVAL);
+ break;
+ case 0x09: /* ADDIU */ if (RTREG) RTVAL64 = (INT32)(RSVAL32 + SIMMVAL); break;
+ case 0x0a: /* SLTI */ if (RTREG) RTVAL64 = (INT64)RSVAL64 < (INT64)SIMMVAL; break;
+ case 0x0b: /* SLTIU */ if (RTREG) RTVAL64 = (UINT64)RSVAL64 < (UINT64)SIMMVAL; break;
+ case 0x0c: /* ANDI */ if (RTREG) RTVAL64 = RSVAL64 & UIMMVAL; break;
+ case 0x0d: /* ORI */ if (RTREG) RTVAL64 = RSVAL64 | UIMMVAL; break;
+ case 0x0e: /* XORI */ if (RTREG) RTVAL64 = RSVAL64 ^ UIMMVAL; break;
+ case 0x0f: /* LUI */ if (RTREG) RTVAL64 = (INT32)(UIMMVAL << 16); break;
+ case 0x10: /* COP0 */ handle_cop0(op); break;
+ case 0x11: /* COP1 */ if (IS_FR0) handle_cop1_fr0(op); else handle_cop1_fr1(op); break;
+ case 0x12: /* COP2 */ handle_cop2(op); break;
+ case 0x13: /* COP1X - R5000 */if (IS_FR0) handle_cop1x_fr0(op); else handle_cop1x_fr1(op); break;
+ case 0x14: /* BEQL */ if (RSVAL64 == RTVAL64) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ case 0x15: /* BNEL */ if (RSVAL64 != RTVAL64) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ case 0x16: /* BLEZL */ if ((INT64)RSVAL64 <= 0) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ case 0x17: /* BGTZL */ if ((INT64)RSVAL64 > 0) ADDPC(SIMMVAL); else mips3.core.pc += 4; break;
+ case 0x18: /* DADDI */
+ if (ENABLE_OVERFLOWS && RSVAL64 > ~SIMMVAL) generate_exception(EXCEPTION_OVERFLOW, 1);
+ else if (RTREG) RTVAL64 = RSVAL64 + (INT64)SIMMVAL;
+ break;
+ case 0x19: /* DADDIU */ if (RTREG) RTVAL64 = RSVAL64 + (UINT64)SIMMVAL; break;
+ case 0x1a: /* LDL */ (*mips3.ldl)(op); break;
+ case 0x1b: /* LDR */ (*mips3.ldr)(op); break;
+ case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */
+ switch (op & 0x1f)
+ {
+ case 2: /* MUL */
+ RDVAL64 = (INT32)((INT32)RSVAL32 * (INT32)RTVAL32);
+ mips3.core.icount -= 3;
+ break;
+ default: invalid_instruction(op);
+ }
+ break;
+ case 0x20: /* LB */ if (RBYTE(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (INT8)temp; break;
+ case 0x21: /* LH */ if (RHALF(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (INT16)temp; break;
+ case 0x22: /* LWL */ (*mips3.lwl)(op); break;
+ case 0x23: /* LW */ if (RWORD(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (INT32)temp; break;
+ case 0x24: /* LBU */ if (RBYTE(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (UINT8)temp; break;
+ case 0x25: /* LHU */ if (RHALF(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (UINT16)temp; break;
+ case 0x26: /* LWR */ (*mips3.lwr)(op); break;
+ case 0x27: /* LWU */ if (RWORD(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (UINT32)temp; break;
+ case 0x28: /* SB */ WBYTE(SIMMVAL+RSVAL32, RTVAL32); break;
+ case 0x29: /* SH */ WHALF(SIMMVAL+RSVAL32, RTVAL32); break;
+ case 0x2a: /* SWL */ (*mips3.swl)(op); break;
+ case 0x2b: /* SW */ WWORD(SIMMVAL+RSVAL32, RTVAL32); break;
+ case 0x2c: /* SDL */ (*mips3.sdl)(op); break;
+ case 0x2d: /* SDR */ (*mips3.sdr)(op); break;
+ case 0x2e: /* SWR */ (*mips3.swr)(op); break;
+ case 0x2f: /* CACHE */ /* effective no-op */ break;
+ case 0x30: /* LL */ if (RWORD(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (UINT32)temp; mips3.ll_value = RTVAL32; break;
+ case 0x31: /* LWC1 */ if (RWORD(SIMMVAL+RSVAL32, &temp)) set_cop1_reg32(RTREG, temp); break;
+ case 0x32: /* LWC2 */ if (RWORD(SIMMVAL+RSVAL32, &temp)) set_cop2_reg(RTREG, temp); break;
+ case 0x33: /* PREF */ /* effective no-op */ break;
+ case 0x34: /* LLD */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64) && RTREG) RTVAL64 = temp64; mips3.lld_value = temp64; break;
+ case 0x35: /* LDC1 */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64)) set_cop1_reg64(RTREG, temp64); break;
+ case 0x36: /* LDC2 */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64)) set_cop2_reg(RTREG, temp64); break;
+ case 0x37: /* LD */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64) && RTREG) RTVAL64 = temp64; break;
+ case 0x38: /* SC */ if (RWORD(SIMMVAL+RSVAL32, &temp) && RTREG)
+ {
+ if (temp == mips3.ll_value)
+ {
+ WWORD(SIMMVAL+RSVAL32, RTVAL32);
+ RTVAL64 = (UINT32)1;
+ }
+ else
+ {
+ RTVAL64 = (UINT32)0;
+ }
+ }
+ break;
+ case 0x39: /* SWC1 */ WWORD(SIMMVAL+RSVAL32, get_cop1_reg32(RTREG)); break;
+ case 0x3a: /* SWC2 */ WWORD(SIMMVAL+RSVAL32, get_cop2_reg(RTREG)); break;
+ case 0x3b: /* SWC3 */ invalid_instruction(op); break;
+ case 0x3c: /* SCD */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64) && RTREG)
+ {
+ if (temp64 == mips3.lld_value)
+ {
+ WDOUBLE(SIMMVAL+RSVAL32, RTVAL64);
+ RTVAL64 = 1;
+ }
+ else
+ {
+ RTVAL64 = 0;
+ }
+ }
+ break;
+ case 0x3d: /* SDC1 */ WDOUBLE(SIMMVAL+RSVAL32, get_cop1_reg64(RTREG)); break;
+ case 0x3e: /* SDC2 */ WDOUBLE(SIMMVAL+RSVAL32, get_cop2_reg(RTREG)); break;
+ case 0x3f: /* SD */ WDOUBLE(SIMMVAL+RSVAL32, RTVAL64); break;
+ default: /* ??? */ invalid_instruction(op); break;
+ }
+ mips3.core.icount--;
+
+ } while (mips3.core.icount > 0 || mips3.nextpc != ~0);
+
+ mips3.core.icount -= mips3.interrupt_cycles;
+ mips3.interrupt_cycles = 0;
+ return cycles - mips3.core.icount;
+}
+
+
+
+/***************************************************************************
+ COMPLEX OPCODE IMPLEMENTATIONS
+***************************************************************************/
+
+static void lwl_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (offs & 3);
+ UINT32 mask = 0xffffffffUL << shift;
+ UINT32 temp;
+
+ if (RWORD_MASKED(offs & ~3, &temp, ~(mask >> shift)) && RTREG)
+ RTVAL64 = (INT32)((RTVAL32 & ~mask) | (temp << shift));
+}
+
+static void lwr_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (~offs & 3);
+ UINT32 mask = 0xffffffffUL >> shift;
+ UINT32 temp;
+
+ if (RWORD_MASKED(offs & ~3, &temp, ~(mask << shift)) && RTREG)
+ RTVAL64 = (INT32)((RTVAL32 & ~mask) | (temp >> shift));
+}
+
+static void ldl_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (offs & 7);
+ UINT64 mask = U64(0xffffffffffffffff) << shift;
+ UINT64 temp;
+
+ if (RDOUBLE_MASKED(offs & ~7, &temp, ~(mask >> shift)) && RTREG)
+ RTVAL64 = (RTVAL64 & ~mask) | (temp << shift);
+}
+
+static void ldr_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (~offs & 7);
+ UINT64 mask = U64(0xffffffffffffffff) >> shift;
+ UINT64 temp;
+
+ if (RDOUBLE_MASKED(offs & ~7, &temp, ~(mask << shift)) && RTREG)
+ RTVAL64 = (RTVAL64 & ~mask) | (temp >> shift);
+}
+
+static void swl_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (offs & 3);
+ UINT32 mask = ~(0xffffffffUL >> shift);
+ WWORD_MASKED(offs & ~3, RTVAL32 >> shift, mask);
+}
+
+static void swr_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (~offs & 3);
+ UINT32 mask = ~(0xffffffffUL << shift);
+ WWORD_MASKED(offs & ~3, RTVAL32 << shift, mask);
+}
+
+static void sdl_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (offs & 7);
+ UINT64 mask = ~(U64(0xffffffffffffffff) >> shift);
+ WDOUBLE_MASKED(offs & ~7, RTVAL64 >> shift, mask);
+}
+
+static void sdr_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (~offs & 7);
+ UINT64 mask = ~(U64(0xffffffffffffffff) << shift);
+ WDOUBLE_MASKED(offs & ~7, RTVAL64 << shift, mask);
+}
+
+
+
+static void lwl_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (~offs & 3);
+ UINT32 mask = 0xffffffffUL << shift;
+ UINT32 temp;
+
+ if (RWORD_MASKED(offs & ~3, &temp, ~(mask >> shift)) && RTREG)
+ RTVAL64 = (INT32)((RTVAL32 & ~mask) | (temp << shift));
+}
+
+static void lwr_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (offs & 3);
+ UINT32 mask = 0xffffffffUL >> shift;
+ UINT32 temp;
+
+ if (RWORD_MASKED(offs & ~3, &temp, ~(mask << shift)) && RTREG)
+ RTVAL64 = (INT32)((RTVAL32 & ~mask) | (temp >> shift));
+}
+
+static void ldl_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (~offs & 7);
+ UINT64 mask = U64(0xffffffffffffffff) << shift;
+ UINT64 temp;
+
+ if (RDOUBLE_MASKED(offs & ~7, &temp, ~(mask >> shift)) && RTREG)
+ RTVAL64 = (RTVAL64 & ~mask) | (temp << shift);
+}
+
+static void ldr_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (offs & 7);
+ UINT64 mask = U64(0xffffffffffffffff) >> shift;
+ UINT64 temp;
+
+ if (RDOUBLE_MASKED(offs & ~7, &temp, ~(mask << shift)) && RTREG)
+ RTVAL64 = (RTVAL64 & ~mask) | (temp >> shift);
+}
+
+static void swl_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (~offs & 3);
+ UINT32 mask = ~(0xffffffffUL >> shift);
+ WWORD_MASKED(offs & ~3, RTVAL32 >> shift, mask);
+}
+
+static void swr_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (offs & 3);
+ UINT32 mask = ~(0xffffffffUL << shift);
+ WWORD_MASKED(offs & ~3, RTVAL32 << shift, mask);
+}
+
+static void sdl_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (~offs & 7);
+ UINT64 mask = ~(U64(0xffffffffffffffff) >> shift);
+ WDOUBLE_MASKED(offs & ~7, RTVAL64 >> shift, mask);
+}
+
+static void sdr_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL32;
+ int shift = 8 * (offs & 7);
+ UINT64 mask = ~(U64(0xffffffffffffffff) << shift);
+ WDOUBLE_MASKED(offs & ~7, RTVAL64 << shift, mask);
+}
+
+
+
+/***************************************************************************
+ GENERIC GET/SET INFO
+***************************************************************************/
+
+static void mips3_set_info(UINT32 state, cpuinfo *info)
+{
+ /* everything is handled generically here */
+ mips3com_set_info(&mips3.core, state, info);
+}
+
+
+void mips3_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(mips3); break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = mips3.ppc; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mips3_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = mips3_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = mips3_set_context; break;
+ case CPUINFO_PTR_INIT: /* provided per-CPU */ break;
+ case CPUINFO_PTR_RESET: info->reset = mips3_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = mips3_execute; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = mips3_dasm; break;
+#endif
+ case CPUINFO_PTR_TRANSLATE: info->translate = mips3_translate; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3com_get_info(&mips3.core, state, info); break;
+ }
+}
+
+
+
+/***************************************************************************
+ R4600 VARIANTS
+***************************************************************************/
+
+#if (HAS_R4600)
+static void r4600be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_R4600, TRUE, index, clock, config, irqcallback);
+}
+
+static void r4600le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_R4600, FALSE, index, clock, config, irqcallback);
+}
+
+void r4600be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4600be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R4600 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void r4600le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4600le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R4600 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ R4650 VARIANTS
+***************************************************************************/
+
+#if (HAS_R4650)
+static void r4650be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_R4650, TRUE, index, clock, config, irqcallback);
+}
+
+static void r4650le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_R4650, FALSE, index, clock, config, irqcallback);
+}
+
+void r4650be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4650be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "IDT R4650 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void r4650le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4650le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "IDT R4650 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ R4700 VARIANTS
+***************************************************************************/
+
+#if (HAS_R4700)
+static void r4700be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_R4700, TRUE, index, clock, config, irqcallback);
+}
+
+static void r4700le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_R4700, FALSE, index, clock, config, irqcallback);
+}
+
+void r4700be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4700be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R4700 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+
+void r4700le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4700le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R4700 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ R5000 VARIANTS
+***************************************************************************/
+
+#if (HAS_R5000)
+static void r5000be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_R5000, TRUE, index, clock, config, irqcallback);
+}
+
+static void r5000le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_R5000, FALSE, index, clock, config, irqcallback);
+}
+
+void r5000be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r5000be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R5000 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void r5000le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r5000le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R5000 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ QED5271 VARIANTS
+***************************************************************************/
+
+#if (HAS_QED5271)
+static void qed5271be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_QED5271, TRUE, index, clock, config, irqcallback);
+}
+
+static void qed5271le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_QED5271, FALSE, index, clock, config, irqcallback);
+}
+
+void qed5271be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = qed5271be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "QED5271 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void qed5271le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = qed5271le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "QED5271 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ RM7000 VARIANTS
+***************************************************************************/
+
+#if (HAS_RM7000)
+static void rm7000be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_RM7000, TRUE, index, clock, config, irqcallback);
+}
+
+static void rm7000le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3com_init(&mips3.core, MIPS3_TYPE_RM7000, FALSE, index, clock, config, irqcallback);
+}
+
+void rm7000be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = rm7000be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "RM7000 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void rm7000le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = rm7000le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "RM7000 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/mips/mips3.h b/src/emu/cpu/mips/mips3.h
new file mode 100644
index 00000000000..e0c22ab7ac0
--- /dev/null
+++ b/src/emu/cpu/mips/mips3.h
@@ -0,0 +1,199 @@
+/***************************************************************************
+
+ mips3.h
+ Interface file for the portable MIPS III/IV emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#ifndef __MIPS3_H__
+#define __MIPS3_H__
+
+#include "cpuintrf.h"
+
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ MIPS3_PC = 1,
+ MIPS3_R0,
+ MIPS3_R1,
+ MIPS3_R2,
+ MIPS3_R3,
+ MIPS3_R4,
+ MIPS3_R5,
+ MIPS3_R6,
+ MIPS3_R7,
+ MIPS3_R8,
+ MIPS3_R9,
+ MIPS3_R10,
+ MIPS3_R11,
+ MIPS3_R12,
+ MIPS3_R13,
+ MIPS3_R14,
+ MIPS3_R15,
+ MIPS3_R16,
+ MIPS3_R17,
+ MIPS3_R18,
+ MIPS3_R19,
+ MIPS3_R20,
+ MIPS3_R21,
+ MIPS3_R22,
+ MIPS3_R23,
+ MIPS3_R24,
+ MIPS3_R25,
+ MIPS3_R26,
+ MIPS3_R27,
+ MIPS3_R28,
+ MIPS3_R29,
+ MIPS3_R30,
+ MIPS3_R31,
+ MIPS3_HI,
+ MIPS3_LO,
+ MIPS3_FPR0,
+ MIPS3_FPR1,
+ MIPS3_FPR2,
+ MIPS3_FPR3,
+ MIPS3_FPR4,
+ MIPS3_FPR5,
+ MIPS3_FPR6,
+ MIPS3_FPR7,
+ MIPS3_FPR8,
+ MIPS3_FPR9,
+ MIPS3_FPR10,
+ MIPS3_FPR11,
+ MIPS3_FPR12,
+ MIPS3_FPR13,
+ MIPS3_FPR14,
+ MIPS3_FPR15,
+ MIPS3_FPR16,
+ MIPS3_FPR17,
+ MIPS3_FPR18,
+ MIPS3_FPR19,
+ MIPS3_FPR20,
+ MIPS3_FPR21,
+ MIPS3_FPR22,
+ MIPS3_FPR23,
+ MIPS3_FPR24,
+ MIPS3_FPR25,
+ MIPS3_FPR26,
+ MIPS3_FPR27,
+ MIPS3_FPR28,
+ MIPS3_FPR29,
+ MIPS3_FPR30,
+ MIPS3_FPR31,
+ MIPS3_SR,
+ MIPS3_EPC,
+ MIPS3_CAUSE,
+ MIPS3_COUNT,
+ MIPS3_COMPARE,
+ MIPS3_INDEX,
+ MIPS3_RANDOM,
+ MIPS3_ENTRYHI,
+ MIPS3_ENTRYLO0,
+ MIPS3_ENTRYLO1,
+ MIPS3_PAGEMASK,
+ MIPS3_WIRED,
+ MIPS3_BADVADDR
+};
+
+#define MIPS3_MAX_FASTRAM 4
+#define MIPS3_MAX_HOTSPOTS 16
+
+enum
+{
+ CPUINFO_INT_MIPS3_DRC_OPTIONS = CPUINFO_INT_CPU_SPECIFIC,
+
+ CPUINFO_INT_MIPS3_FASTRAM_SELECT,
+ CPUINFO_INT_MIPS3_FASTRAM_START,
+ CPUINFO_INT_MIPS3_FASTRAM_END,
+ CPUINFO_INT_MIPS3_FASTRAM_READONLY,
+
+ CPUINFO_INT_MIPS3_HOTSPOT_SELECT,
+ CPUINFO_INT_MIPS3_HOTSPOT_PC,
+ CPUINFO_INT_MIPS3_HOTSPOT_OPCODE,
+ CPUINFO_INT_MIPS3_HOTSPOT_CYCLES,
+
+ CPUINFO_PTR_MIPS3_FASTRAM_BASE = CPUINFO_PTR_CPU_SPECIFIC
+};
+
+
+
+/***************************************************************************
+ INTERRUPT CONSTANTS
+***************************************************************************/
+
+#define MIPS3_IRQ0 0 /* IRQ0 */
+#define MIPS3_IRQ1 1 /* IRQ1 */
+#define MIPS3_IRQ2 2 /* IRQ2 */
+#define MIPS3_IRQ3 3 /* IRQ3 */
+#define MIPS3_IRQ4 4 /* IRQ4 */
+#define MIPS3_IRQ5 5 /* IRQ5 */
+
+
+
+/***************************************************************************
+ STRUCTURES
+***************************************************************************/
+
+struct mips3_config
+{
+ size_t icache; /* code cache size */
+ size_t dcache; /* data cache size */
+ UINT32 system_clock; /* system clock rate */
+};
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+#if (HAS_R4600)
+void r4600be_get_info(UINT32 state, cpuinfo *info);
+void r4600le_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_R4700)
+void r4700be_get_info(UINT32 state, cpuinfo *info);
+void r4700le_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_R5000)
+void r5000be_get_info(UINT32 state, cpuinfo *info);
+void r5000le_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_QED5271)
+void qed5271be_get_info(UINT32 state, cpuinfo *info);
+void qed5271le_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_RM7000)
+void rm7000be_get_info(UINT32 state, cpuinfo *info);
+void rm7000le_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+
+
+/***************************************************************************
+ COMPILER-SPECIFIC OPTIONS
+***************************************************************************/
+
+/* fix me -- how do we make this work?? */
+#define MIPS3DRC_STRICT_VERIFY 0x0001 /* verify all instructions */
+#define MIPS3DRC_STRICT_COP0 0x0002 /* validate all COP0 instructions */
+#define MIPS3DRC_STRICT_COP1 0x0004 /* validate all COP1 instructions */
+#define MIPS3DRC_STRICT_COP2 0x0008 /* validate all COP2 instructions */
+#define MIPS3DRC_FLUSH_PC 0x0020 /* flush the PC value before each memory access */
+#define MIPS3DRC_CHECK_OVERFLOWS 0x0040 /* actually check overflows on add/sub instructions */
+
+#define MIPS3DRC_COMPATIBLE_OPTIONS (MIPS3DRC_STRICT_VERIFY | MIPS3DRC_STRICT_COP0 | MIPS3DRC_STRICT_COP1 | MIPS3DRC_STRICT_COP2 | MIPS3DRC_FLUSH_PC)
+#define MIPS3DRC_FASTEST_OPTIONS (0)
+
+
+
+#endif /* __MIPS3_H__ */
diff --git a/src/emu/cpu/mips/mips3com.c b/src/emu/cpu/mips/mips3com.c
new file mode 100644
index 00000000000..55fc05bcacd
--- /dev/null
+++ b/src/emu/cpu/mips/mips3com.c
@@ -0,0 +1,979 @@
+/***************************************************************************
+
+ mips3com.c
+
+ Common MIPS III/IV definitions and functions
+
+***************************************************************************/
+
+#include "mips3com.h"
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define PRINTF_TLB (1)
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static TIMER_CALLBACK( compare_int_callback );
+
+static UINT32 compute_config_register(const mips3_state *mips);
+static UINT32 compute_prid_register(const mips3_state *mips);
+
+static void tlb_write_common(mips3_state *mips, int index);
+static void tlb_entry_log_half(mips3_tlb_entry *tlbent, int index, int which);
+
+static UINT64 program_read_qword_32be(offs_t offset);
+static UINT64 program_read_qword_masked_32be(offs_t offset, UINT64 mem_mask);
+
+static void program_write_qword_32be(offs_t offset, UINT64 data);
+static void program_write_qword_masked_32be(offs_t offset, UINT64 data, UINT64 mem_mask);
+
+static UINT64 program_read_qword_32le(offs_t offset);
+static UINT64 program_read_qword_masked_32le(offs_t offset, UINT64 mem_mask);
+
+static void program_write_qword_32le(offs_t offset, UINT64 data);
+static void program_write_qword_masked_32le(offs_t offset, UINT64 data, UINT64 mem_mask);
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static const memory_handlers be_memory =
+{
+ program_read_byte_32be,
+ program_read_word_32be,
+ program_read_dword_32be,
+ program_read_masked_32be,
+ program_read_qword_32be,
+ program_read_qword_masked_32be,
+
+ program_write_byte_32be,
+ program_write_word_32be,
+ program_write_dword_32be,
+ program_write_masked_32be,
+ program_write_qword_32be,
+ program_write_qword_masked_32be
+};
+
+static const memory_handlers le_memory =
+{
+ program_read_byte_32le,
+ program_read_word_32le,
+ program_read_dword_32le,
+ program_read_masked_32le,
+ program_read_qword_32le,
+ program_read_qword_masked_32le,
+
+ program_write_byte_32le,
+ program_write_word_32le,
+ program_write_dword_32le,
+ program_write_masked_32le,
+ program_write_qword_32le,
+ program_write_qword_masked_32le
+};
+
+
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+/*-------------------------------------------------
+ mips3com_init - initialize the mips3_state
+ structure based on the configured type
+-------------------------------------------------*/
+
+void mips3com_init(mips3_state *mips, mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int))
+{
+ /* initialize the state */
+ memset(mips, 0, sizeof(*mips));
+
+ /* initialize based on the config */
+ mips->flavor = flavor;
+ mips->bigendian = bigendian;
+ mips->cpu_clock = clock;
+ mips->irq_callback = irqcallback;
+ mips->icache_size = config->icache;
+ mips->dcache_size = config->dcache;
+ mips->system_clock = config->system_clock;
+
+ /* set up the endianness */
+ if (mips->bigendian)
+ mips->memory = be_memory;
+ else
+ mips->memory = le_memory;
+
+ /* allocate memory */
+ mips->icache = auto_malloc(config->icache);
+ mips->dcache = auto_malloc(config->dcache);
+ mips->tlb_table = auto_malloc(sizeof(mips->tlb_table[0]) * (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT)));
+
+ /* allocate a timer for the compare interrupt */
+ mips->compare_int_timer = timer_alloc(compare_int_callback);
+
+ /* reset the state */
+ mips3com_reset(mips);
+}
+
+
+/*-------------------------------------------------
+ mips3com_reset - reset the state of all the
+ registers
+-------------------------------------------------*/
+
+void mips3com_reset(mips3_state *mips)
+{
+ /* initialize the state */
+ mips->pc = 0xbfc00000;
+ mips->cpr[0][COP0_Status] = SR_BEV | SR_ERL;
+ mips->cpr[0][COP0_Compare] = 0xffffffff;
+ mips->cpr[0][COP0_Count] = 0;
+ mips->cpr[0][COP0_Config] = compute_config_register(mips);
+ mips->cpr[0][COP0_PRId] = compute_prid_register(mips);
+ mips->count_zero_time = activecpu_gettotalcycles64();
+
+ /* recompute the TLB table */
+ mips3com_recompute_tlb_table(mips);
+}
+
+
+/*-------------------------------------------------
+ mips3com_dasm - handle disassembly for a
+ CPU
+-------------------------------------------------*/
+
+#ifdef MAME_DEBUG
+offs_t mips3com_dasm(mips3_state *mips, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ extern unsigned dasmmips3(char *, unsigned, UINT32);
+ UINT32 op = *(UINT32 *)oprom;
+ if (mips->bigendian)
+ op = BIG_ENDIANIZE_INT32(op);
+ else
+ op = LITTLE_ENDIANIZE_INT32(op);
+ return dasmmips3(buffer, pc, op);
+}
+#endif /* MAME_DEBUG */
+
+
+
+/*-------------------------------------------------
+ mips3com_update_cycle_counting - update cycle
+ counts and the timers
+-------------------------------------------------*/
+
+void mips3com_update_cycle_counting(mips3_state *mips)
+{
+ /* modify the timer to go off */
+ if ((mips->cpr[0][COP0_Status] & 0x8000) && mips->cpr[0][COP0_Compare] != 0xffffffff)
+ {
+ UINT32 count = (activecpu_gettotalcycles64() - mips->count_zero_time) / 2;
+ UINT32 compare = mips->cpr[0][COP0_Compare];
+ UINT32 cyclesleft = compare - count;
+ attotime newtime = ATTOTIME_IN_CYCLES(((INT64)cyclesleft * 2), cpu_getactivecpu());
+
+ /* due to accuracy issues, don't bother setting timers unless they're for less than 100msec */
+ if (attotime_compare(newtime, ATTOTIME_IN_MSEC(100)) < 0)
+ timer_adjust(mips->compare_int_timer, newtime, cpu_getactivecpu(), attotime_zero);
+ }
+ else
+ timer_adjust(mips->compare_int_timer, attotime_never, cpu_getactivecpu(), attotime_zero);
+}
+
+
+
+/***************************************************************************
+ TLB HANDLING
+***************************************************************************/
+
+/*-------------------------------------------------
+ mips3com_map_tlb_entries - map entries from the
+ TLB into the tlb_table
+-------------------------------------------------*/
+
+void mips3com_map_tlb_entries(mips3_state *mips)
+{
+ int valid_asid = mips->cpr[0][COP0_EntryHi] & 0xff;
+ int index;
+
+ /* iterate over all TLB entries */
+ for (index = 0; index < ARRAY_LENGTH(mips->tlb); index++)
+ {
+ mips3_tlb_entry *tlbent = &mips->tlb[index];
+
+ /* only process if global or if the ASID matches */
+ if ((tlbent->entry_hi & 0x1000) || valid_asid == (tlbent->entry_hi & 0xff))
+ {
+ UINT32 count = (tlbent->page_mask >> 13) & 0x00fff;
+ UINT32 vpn = ((tlbent->entry_hi >> 13) & 0x07ffffff) << 1;
+ int which, i;
+
+ /* ignore if the virtual address is beyond 32 bits */
+ if (vpn < (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT)))
+
+ /* loop over both the even and odd pages */
+ for (which = 0; which < 2; which++)
+ {
+ UINT64 lo = tlbent->entry_lo[which];
+
+ /* only map if the TLB entry is valid */
+ if (lo & 2)
+ {
+ UINT32 pfn = (lo >> 6) & 0x00ffffff;
+ UINT32 wp = (~lo >> 2) & 1;
+
+ for (i = 0; i <= count; i++, vpn++, pfn++)
+ if (vpn < 0x80000 || vpn >= 0xc0000)
+ mips->tlb_table[vpn] = (pfn << MIPS3_MIN_PAGE_SHIFT) | wp;
+ }
+
+ /* otherwise, advance by the number of pages we would have mapped */
+ else
+ vpn += count + 1;
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ mips3com_unmap_tlb_entries - unmap entries from
+ the TLB into the tlb_table
+-------------------------------------------------*/
+
+void mips3com_unmap_tlb_entries(mips3_state *mips)
+{
+ int index;
+
+ /* iterate over all TLB entries */
+ for (index = 0; index < ARRAY_LENGTH(mips->tlb); index++)
+ {
+ mips3_tlb_entry *tlbent = &mips->tlb[index];
+ UINT32 count = (tlbent->page_mask >> 13) & 0x00fff;
+ UINT32 vpn = ((tlbent->entry_hi >> 13) & 0x07ffffff) << 1;
+ int which, i;
+
+ /* ignore if the virtual address is beyond 32 bits */
+ if (vpn < (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT)))
+
+ /* loop over both the even and odd pages */
+ for (which = 0; which < 2; which++)
+ for (i = 0; i <= count; i++, vpn++)
+ if (vpn < 0x80000 || vpn >= 0xc0000)
+ mips->tlb_table[vpn] = 0xffffffff;
+ }
+}
+
+
+/*-------------------------------------------------
+ mips3com_recompute_tlb_table - recompute the TLB
+ table from scratch
+-------------------------------------------------*/
+
+void mips3com_recompute_tlb_table(mips3_state *mips)
+{
+ UINT32 addr;
+
+ /* map in the hard-coded spaces */
+ for (addr = 0x80000000; addr < 0xc0000000; addr += MIPS3_MIN_PAGE_SIZE)
+ mips->tlb_table[addr >> MIPS3_MIN_PAGE_SHIFT] = addr & 0x1ffff000;
+
+ /* reset everything else to unmapped */
+ memset(&mips->tlb_table[0x00000000 >> MIPS3_MIN_PAGE_SHIFT], 0xff, sizeof(mips->tlb_table[0]) * (0x80000000 >> MIPS3_MIN_PAGE_SHIFT));
+ memset(&mips->tlb_table[0xc0000000 >> MIPS3_MIN_PAGE_SHIFT], 0xff, sizeof(mips->tlb_table[0]) * (0x40000000 >> MIPS3_MIN_PAGE_SHIFT));
+
+ /* remap all the entries in the TLB */
+ mips3com_map_tlb_entries(mips);
+}
+
+
+/*-------------------------------------------------
+ mips3com_translate_address - translate an address
+ from logical to physical
+-------------------------------------------------*/
+
+int mips3com_translate_address(mips3_state *mips, int space, offs_t *address)
+{
+ /* only applies to the program address space */
+ if (space == ADDRESS_SPACE_PROGRAM)
+ {
+ UINT32 result = mips->tlb_table[*address >> MIPS3_MIN_PAGE_SHIFT];
+ if (result == 0xffffffff)
+ return FALSE;
+ *address = (result & ~MIPS3_MIN_PAGE_MASK) | (*address & MIPS3_MIN_PAGE_MASK);
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ mips3com_tlbr - execute the tlbr instruction
+-------------------------------------------------*/
+
+void mips3com_tlbr(mips3_state *mips)
+{
+ UINT32 index = mips->cpr[0][COP0_Index] & 0x3f;
+
+ /* only handle entries within the TLB */
+ if (index < ARRAY_LENGTH(mips->tlb))
+ {
+ mips3_tlb_entry *tlbent = &mips->tlb[index];
+
+ /* copy data from the TLB entry into the COP0 registers */
+ mips->cpr[0][COP0_PageMask] = tlbent->page_mask;
+ mips->cpr[0][COP0_EntryHi] = tlbent->entry_hi;
+ mips->cpr[0][COP0_EntryLo0] = tlbent->entry_lo[0];
+ mips->cpr[0][COP0_EntryLo1] = tlbent->entry_lo[1];
+ }
+}
+
+
+/*-------------------------------------------------
+ mips3com_tlbwi - execute the tlbwi instruction
+-------------------------------------------------*/
+
+void mips3com_tlbwi(mips3_state *mips)
+{
+ /* use the common handler and write based off the COP0 Index register */
+ tlb_write_common(mips, mips->cpr[0][COP0_Index] & 0x3f);
+}
+
+
+/*-------------------------------------------------
+ mips3com_tlbwr - execute the tlbwr instruction
+-------------------------------------------------*/
+
+void mips3com_tlbwr(mips3_state *mips)
+{
+ UINT32 wired = mips->cpr[0][COP0_Wired] & 0x3f;
+ UINT32 unwired = ARRAY_LENGTH(mips->tlb) - wired;
+ UINT32 index = ARRAY_LENGTH(mips->tlb) - 1;
+
+ /* "random" is based off of the current cycle counting through the non-wired pages */
+ if (unwired > 0)
+ index = ((activecpu_gettotalcycles64() - mips->count_zero_time) % unwired + wired) & 0x3f;
+
+ /* use the common handler to write to this index */
+ tlb_write_common(mips, index);
+}
+
+
+/*-------------------------------------------------
+ mips3com_tlbp - execute the tlbp instruction
+-------------------------------------------------*/
+
+void mips3com_tlbp(mips3_state *mips)
+{
+ UINT32 index;
+ UINT64 vpn;
+
+ /* iterate over TLB entries */
+ for (index = 0; index < ARRAY_LENGTH(mips->tlb); index++)
+ {
+ mips3_tlb_entry *tlbent = &mips->tlb[index];
+ UINT64 mask = ~((tlbent->page_mask >> 13) & 0xfff) << 13;
+
+ /* if the relevant bits of EntryHi match the relevant bits of the TLB */
+ if ((tlbent->entry_hi & mask) == (mips->cpr[0][COP0_EntryHi] & mask))
+
+ /* and if we are either global or matching the current ASID, then stop */
+ if ((tlbent->entry_hi & 0x1000) || (tlbent->entry_hi & 0xff) == (mips->cpr[0][COP0_EntryHi] & 0xff))
+ break;
+ }
+
+ /* validate that our tlb_table was in sync */
+ vpn = ((mips->cpr[0][COP0_EntryHi] >> 13) & 0x07ffffff) << 1;
+ if (index != ARRAY_LENGTH(mips->tlb))
+ {
+ /* we can't assert this because the TLB entry may not be valid */
+ /* assert(mips->tlb_table[vpn & 0xfffff] != 0xffffffff); */
+ mips->cpr[0][COP0_Index] = index;
+ }
+ else
+ {
+ assert(mips->tlb_table[vpn & 0xfffff] == 0xffffffff);
+ mips->cpr[0][COP0_Index] = 0x80000000;
+ }
+}
+
+
+
+/***************************************************************************
+ COMMON GET/SET INFO
+***************************************************************************/
+
+/*-------------------------------------------------
+ mips3com_set_info - set information about
+ a MIPS 3 CPU
+-------------------------------------------------*/
+
+void mips3com_set_info(mips3_state *mips, UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ0: mips3com_set_irq_line(mips, MIPS3_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ1: mips3com_set_irq_line(mips, MIPS3_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ2: mips3com_set_irq_line(mips, MIPS3_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ3: mips3com_set_irq_line(mips, MIPS3_IRQ3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ4: mips3com_set_irq_line(mips, MIPS3_IRQ4, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ5: mips3com_set_irq_line(mips, MIPS3_IRQ5, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + MIPS3_PC: mips->pc = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_SR: mips->cpr[0][COP0_Status] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_EPC: mips->cpr[0][COP0_EPC] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_CAUSE: mips->cpr[0][COP0_Cause] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_COUNT: mips->cpr[0][COP0_Count] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_COMPARE: mips->cpr[0][COP0_Compare] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_INDEX: mips->cpr[0][COP0_Index] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_RANDOM: mips->cpr[0][COP0_Random] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_ENTRYHI: mips->cpr[0][COP0_EntryHi] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_ENTRYLO0: mips->cpr[0][COP0_EntryLo0] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_ENTRYLO1: mips->cpr[0][COP0_EntryLo1] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_PAGEMASK: mips->cpr[0][COP0_PageMask] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_WIRED: mips->cpr[0][COP0_Wired] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_BADVADDR: mips->cpr[0][COP0_BadVAddr] = info->i; break;
+
+ case CPUINFO_INT_REGISTER + MIPS3_R0: /* can't change R0 */ break;
+ case CPUINFO_INT_REGISTER + MIPS3_R1: mips->r[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R2: mips->r[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R3: mips->r[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R4: mips->r[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R5: mips->r[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R6: mips->r[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R7: mips->r[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R8: mips->r[8] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R9: mips->r[9] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R10: mips->r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R11: mips->r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R12: mips->r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R13: mips->r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R14: mips->r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R15: mips->r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R16: mips->r[16] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R17: mips->r[17] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R18: mips->r[18] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R19: mips->r[19] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R20: mips->r[20] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R21: mips->r[21] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R22: mips->r[22] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R23: mips->r[23] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R24: mips->r[24] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R25: mips->r[25] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R26: mips->r[26] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R27: mips->r[27] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R28: mips->r[28] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R29: mips->r[29] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R30: mips->r[30] = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + MIPS3_R31: mips->r[31] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_HI: mips->r[REG_HI] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_LO: mips->r[REG_LO] = info->i; break;
+
+ case CPUINFO_INT_REGISTER + MIPS3_FPR0: mips->cpr[1][0] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR1: mips->cpr[1][1] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR2: mips->cpr[1][2] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR3: mips->cpr[1][3] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR4: mips->cpr[1][4] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR5: mips->cpr[1][5] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR6: mips->cpr[1][6] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR7: mips->cpr[1][7] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR8: mips->cpr[1][8] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR9: mips->cpr[1][9] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR10: mips->cpr[1][10] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR11: mips->cpr[1][11] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR12: mips->cpr[1][12] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR13: mips->cpr[1][13] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR14: mips->cpr[1][14] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR15: mips->cpr[1][15] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR16: mips->cpr[1][16] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR17: mips->cpr[1][17] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR18: mips->cpr[1][18] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR19: mips->cpr[1][19] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR20: mips->cpr[1][20] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR21: mips->cpr[1][21] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR22: mips->cpr[1][22] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR23: mips->cpr[1][23] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR24: mips->cpr[1][24] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR25: mips->cpr[1][25] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR26: mips->cpr[1][26] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR27: mips->cpr[1][27] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR28: mips->cpr[1][28] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR29: mips->cpr[1][29] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR30: mips->cpr[1][30] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS3_FPR31: mips->cpr[1][31] = info->i; break;
+ }
+}
+
+
+/*-------------------------------------------------
+ mips3com_get_info - get information about
+ a MIPS 3 CPU
+-------------------------------------------------*/
+
+void mips3com_get_info(mips3_state *mips, UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: /* provided by core */ break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 6; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = mips->bigendian ? CPU_IS_BE : CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = MIPS3_MAX_PADDR_SHIFT;break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = MIPS3_MIN_PAGE_SHIFT; break;
+
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ0: info->i = (mips->cpr[0][COP0_Cause] & 0x400) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ1: info->i = (mips->cpr[0][COP0_Cause] & 0x800) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ2: info->i = (mips->cpr[0][COP0_Cause] & 0x1000) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ3: info->i = (mips->cpr[0][COP0_Cause] & 0x2000) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ4: info->i = (mips->cpr[0][COP0_Cause] & 0x4000) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS3_IRQ5: info->i = (mips->cpr[0][COP0_Cause] & 0x8000) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* optionally implemented */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + MIPS3_PC: info->i = mips->pc; break;
+ case CPUINFO_INT_REGISTER + MIPS3_SR: info->i = mips->cpr[0][COP0_Status]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_EPC: info->i = mips->cpr[0][COP0_EPC]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_CAUSE: info->i = mips->cpr[0][COP0_Cause]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_COUNT: info->i = ((activecpu_gettotalcycles64() - mips->count_zero_time) / 2); break;
+ case CPUINFO_INT_REGISTER + MIPS3_COMPARE: info->i = mips->cpr[0][COP0_Compare]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_INDEX: info->i = mips->cpr[0][COP0_Index]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_RANDOM: info->i = mips->cpr[0][COP0_Random]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_ENTRYHI: info->i = mips->cpr[0][COP0_EntryHi]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_ENTRYLO0: info->i = mips->cpr[0][COP0_EntryLo0]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_ENTRYLO1: info->i = mips->cpr[0][COP0_EntryLo1]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_PAGEMASK: info->i = mips->cpr[0][COP0_PageMask]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_WIRED: info->i = mips->cpr[0][COP0_Wired]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_BADVADDR: info->i = mips->cpr[0][COP0_BadVAddr]; break;
+
+ case CPUINFO_INT_REGISTER + MIPS3_R0: info->i = mips->r[0]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R1: info->i = mips->r[1]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R2: info->i = mips->r[2]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R3: info->i = mips->r[3]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R4: info->i = mips->r[4]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R5: info->i = mips->r[5]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R6: info->i = mips->r[6]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R7: info->i = mips->r[7]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R8: info->i = mips->r[8]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R9: info->i = mips->r[9]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R10: info->i = mips->r[10]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R11: info->i = mips->r[11]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R12: info->i = mips->r[12]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R13: info->i = mips->r[13]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R14: info->i = mips->r[14]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R15: info->i = mips->r[15]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R16: info->i = mips->r[16]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R17: info->i = mips->r[17]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R18: info->i = mips->r[18]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R19: info->i = mips->r[19]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R20: info->i = mips->r[20]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R21: info->i = mips->r[21]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R22: info->i = mips->r[22]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R23: info->i = mips->r[23]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R24: info->i = mips->r[24]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R25: info->i = mips->r[25]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R26: info->i = mips->r[26]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R27: info->i = mips->r[27]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R28: info->i = mips->r[28]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R29: info->i = mips->r[29]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_R30: info->i = mips->r[30]; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + MIPS3_R31: info->i = mips->r[31]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_HI: info->i = mips->r[REG_HI]; break;
+ case CPUINFO_INT_REGISTER + MIPS3_LO: info->i = mips->r[REG_LO]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: /* provided by core */ break;
+ case CPUINFO_PTR_GET_CONTEXT: /* provided by core */ break;
+ case CPUINFO_PTR_SET_CONTEXT: /* provided by core */ break;
+ case CPUINFO_PTR_INIT: /* provided by core */ break;
+ case CPUINFO_PTR_RESET: /* provided by core */ break;
+ case CPUINFO_PTR_EXIT: /* provided by core */ break;
+ case CPUINFO_PTR_EXECUTE: /* provided by core */ break;
+ case CPUINFO_PTR_TRANSLATE: /* provided by core */ break;
+ case CPUINFO_PTR_DISASSEMBLE: /* provided by core */ break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &mips->icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MIPS III"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "MIPS III"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "3.0"); break;
+ case CPUINFO_STR_CORE_FILE: /* provided by core */ break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) Aaron Giles 2000-2007"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + MIPS3_PC: sprintf(info->s, "PC: %08X", mips->pc); break;
+ case CPUINFO_STR_REGISTER + MIPS3_SR: sprintf(info->s, "SR: %08X", (UINT32)mips->cpr[0][COP0_Status]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_EPC: sprintf(info->s, "EPC:%08X", (UINT32)mips->cpr[0][COP0_EPC]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_CAUSE: sprintf(info->s, "Cause:%08X", (UINT32)mips->cpr[0][COP0_Cause]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_COUNT: sprintf(info->s, "Count:%08X", (UINT32)((activecpu_gettotalcycles64() - mips->count_zero_time) / 2)); break;
+ case CPUINFO_STR_REGISTER + MIPS3_COMPARE: sprintf(info->s, "Compare:%08X", (UINT32)mips->cpr[0][COP0_Compare]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_INDEX: sprintf(info->s, "Index:%08X", (UINT32)mips->cpr[0][COP0_Index]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_RANDOM: sprintf(info->s, "Random:%08X", (UINT32)mips->cpr[0][COP0_Random]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_ENTRYHI: sprintf(info->s, "EntryHi:%08X%08X", (UINT32)(mips->cpr[0][COP0_EntryHi] >> 32), (UINT32)mips->cpr[0][COP0_EntryHi]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_ENTRYLO0: sprintf(info->s, "EntryLo0:%08X%08X", (UINT32)(mips->cpr[0][COP0_EntryLo0] >> 32), (UINT32)mips->cpr[0][COP0_EntryLo0]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_ENTRYLO1: sprintf(info->s, "EntryLo1:%08X%08X", (UINT32)(mips->cpr[0][COP0_EntryLo1] >> 32), (UINT32)mips->cpr[0][COP0_EntryLo1]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_PAGEMASK: sprintf(info->s, "PageMask:%08X%08X", (UINT32)(mips->cpr[0][COP0_PageMask] >> 32), (UINT32)mips->cpr[0][COP0_PageMask]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_WIRED: sprintf(info->s, "Wired:%08X", (UINT32)mips->cpr[0][COP0_Wired]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_BADVADDR: sprintf(info->s, "BadVAddr:%08X", (UINT32)mips->cpr[0][COP0_BadVAddr]); break;
+
+ case CPUINFO_STR_REGISTER + MIPS3_R0: sprintf(info->s, "R0: %08X%08X", (UINT32)(mips->r[0] >> 32), (UINT32)mips->r[0]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R1: sprintf(info->s, "R1: %08X%08X", (UINT32)(mips->r[1] >> 32), (UINT32)mips->r[1]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R2: sprintf(info->s, "R2: %08X%08X", (UINT32)(mips->r[2] >> 32), (UINT32)mips->r[2]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R3: sprintf(info->s, "R3: %08X%08X", (UINT32)(mips->r[3] >> 32), (UINT32)mips->r[3]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R4: sprintf(info->s, "R4: %08X%08X", (UINT32)(mips->r[4] >> 32), (UINT32)mips->r[4]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R5: sprintf(info->s, "R5: %08X%08X", (UINT32)(mips->r[5] >> 32), (UINT32)mips->r[5]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R6: sprintf(info->s, "R6: %08X%08X", (UINT32)(mips->r[6] >> 32), (UINT32)mips->r[6]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R7: sprintf(info->s, "R7: %08X%08X", (UINT32)(mips->r[7] >> 32), (UINT32)mips->r[7]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R8: sprintf(info->s, "R8: %08X%08X", (UINT32)(mips->r[8] >> 32), (UINT32)mips->r[8]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R9: sprintf(info->s, "R9: %08X%08X", (UINT32)(mips->r[9] >> 32), (UINT32)mips->r[9]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R10: sprintf(info->s, "R10:%08X%08X", (UINT32)(mips->r[10] >> 32), (UINT32)mips->r[10]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R11: sprintf(info->s, "R11:%08X%08X", (UINT32)(mips->r[11] >> 32), (UINT32)mips->r[11]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R12: sprintf(info->s, "R12:%08X%08X", (UINT32)(mips->r[12] >> 32), (UINT32)mips->r[12]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R13: sprintf(info->s, "R13:%08X%08X", (UINT32)(mips->r[13] >> 32), (UINT32)mips->r[13]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R14: sprintf(info->s, "R14:%08X%08X", (UINT32)(mips->r[14] >> 32), (UINT32)mips->r[14]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R15: sprintf(info->s, "R15:%08X%08X", (UINT32)(mips->r[15] >> 32), (UINT32)mips->r[15]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R16: sprintf(info->s, "R16:%08X%08X", (UINT32)(mips->r[16] >> 32), (UINT32)mips->r[16]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R17: sprintf(info->s, "R17:%08X%08X", (UINT32)(mips->r[17] >> 32), (UINT32)mips->r[17]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R18: sprintf(info->s, "R18:%08X%08X", (UINT32)(mips->r[18] >> 32), (UINT32)mips->r[18]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R19: sprintf(info->s, "R19:%08X%08X", (UINT32)(mips->r[19] >> 32), (UINT32)mips->r[19]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R20: sprintf(info->s, "R20:%08X%08X", (UINT32)(mips->r[20] >> 32), (UINT32)mips->r[20]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R21: sprintf(info->s, "R21:%08X%08X", (UINT32)(mips->r[21] >> 32), (UINT32)mips->r[21]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R22: sprintf(info->s, "R22:%08X%08X", (UINT32)(mips->r[22] >> 32), (UINT32)mips->r[22]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R23: sprintf(info->s, "R23:%08X%08X", (UINT32)(mips->r[23] >> 32), (UINT32)mips->r[23]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R24: sprintf(info->s, "R24:%08X%08X", (UINT32)(mips->r[24] >> 32), (UINT32)mips->r[24]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R25: sprintf(info->s, "R25:%08X%08X", (UINT32)(mips->r[25] >> 32), (UINT32)mips->r[25]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R26: sprintf(info->s, "R26:%08X%08X", (UINT32)(mips->r[26] >> 32), (UINT32)mips->r[26]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R27: sprintf(info->s, "R27:%08X%08X", (UINT32)(mips->r[27] >> 32), (UINT32)mips->r[27]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R28: sprintf(info->s, "R28:%08X%08X", (UINT32)(mips->r[28] >> 32), (UINT32)mips->r[28]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R29: sprintf(info->s, "R29:%08X%08X", (UINT32)(mips->r[29] >> 32), (UINT32)mips->r[29]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R30: sprintf(info->s, "R30:%08X%08X", (UINT32)(mips->r[30] >> 32), (UINT32)mips->r[30]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_R31: sprintf(info->s, "R31:%08X%08X", (UINT32)(mips->r[31] >> 32), (UINT32)mips->r[31]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_HI: sprintf(info->s, "HI: %08X%08X", (UINT32)(mips->r[REG_HI] >> 32), (UINT32)mips->r[REG_HI]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_LO: sprintf(info->s, "LO: %08X%08X", (UINT32)(mips->r[REG_LO] >> 32), (UINT32)mips->r[REG_LO]); break;
+
+ case CPUINFO_STR_REGISTER + MIPS3_FPR0: sprintf(info->s, "FPR0: %08X%08X", (UINT32)(mips->cpr[1][0] >> 32), (UINT32)mips->cpr[1][0]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR1: sprintf(info->s, "FPR1: %08X%08X", (UINT32)(mips->cpr[1][1] >> 32), (UINT32)mips->cpr[1][1]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR2: sprintf(info->s, "FPR2: %08X%08X", (UINT32)(mips->cpr[1][2] >> 32), (UINT32)mips->cpr[1][2]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR3: sprintf(info->s, "FPR3: %08X%08X", (UINT32)(mips->cpr[1][3] >> 32), (UINT32)mips->cpr[1][3]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR4: sprintf(info->s, "FPR4: %08X%08X", (UINT32)(mips->cpr[1][4] >> 32), (UINT32)mips->cpr[1][4]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR5: sprintf(info->s, "FPR5: %08X%08X", (UINT32)(mips->cpr[1][5] >> 32), (UINT32)mips->cpr[1][5]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR6: sprintf(info->s, "FPR6: %08X%08X", (UINT32)(mips->cpr[1][6] >> 32), (UINT32)mips->cpr[1][6]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR7: sprintf(info->s, "FPR7: %08X%08X", (UINT32)(mips->cpr[1][7] >> 32), (UINT32)mips->cpr[1][7]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR8: sprintf(info->s, "FPR8: %08X%08X", (UINT32)(mips->cpr[1][8] >> 32), (UINT32)mips->cpr[1][8]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR9: sprintf(info->s, "FPR9: %08X%08X", (UINT32)(mips->cpr[1][9] >> 32), (UINT32)mips->cpr[1][9]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR10: sprintf(info->s, "FPR10:%08X%08X", (UINT32)(mips->cpr[1][10] >> 32), (UINT32)mips->cpr[1][10]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR11: sprintf(info->s, "FPR11:%08X%08X", (UINT32)(mips->cpr[1][11] >> 32), (UINT32)mips->cpr[1][11]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR12: sprintf(info->s, "FPR12:%08X%08X", (UINT32)(mips->cpr[1][12] >> 32), (UINT32)mips->cpr[1][12]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR13: sprintf(info->s, "FPR13:%08X%08X", (UINT32)(mips->cpr[1][13] >> 32), (UINT32)mips->cpr[1][13]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR14: sprintf(info->s, "FPR14:%08X%08X", (UINT32)(mips->cpr[1][14] >> 32), (UINT32)mips->cpr[1][14]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR15: sprintf(info->s, "FPR15:%08X%08X", (UINT32)(mips->cpr[1][15] >> 32), (UINT32)mips->cpr[1][15]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR16: sprintf(info->s, "FPR16:%08X%08X", (UINT32)(mips->cpr[1][16] >> 32), (UINT32)mips->cpr[1][16]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR17: sprintf(info->s, "FPR17:%08X%08X", (UINT32)(mips->cpr[1][17] >> 32), (UINT32)mips->cpr[1][17]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR18: sprintf(info->s, "FPR18:%08X%08X", (UINT32)(mips->cpr[1][18] >> 32), (UINT32)mips->cpr[1][18]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR19: sprintf(info->s, "FPR19:%08X%08X", (UINT32)(mips->cpr[1][19] >> 32), (UINT32)mips->cpr[1][19]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR20: sprintf(info->s, "FPR20:%08X%08X", (UINT32)(mips->cpr[1][20] >> 32), (UINT32)mips->cpr[1][20]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR21: sprintf(info->s, "FPR21:%08X%08X", (UINT32)(mips->cpr[1][21] >> 32), (UINT32)mips->cpr[1][21]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR22: sprintf(info->s, "FPR22:%08X%08X", (UINT32)(mips->cpr[1][22] >> 32), (UINT32)mips->cpr[1][22]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR23: sprintf(info->s, "FPR23:%08X%08X", (UINT32)(mips->cpr[1][23] >> 32), (UINT32)mips->cpr[1][23]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR24: sprintf(info->s, "FPR24:%08X%08X", (UINT32)(mips->cpr[1][24] >> 32), (UINT32)mips->cpr[1][24]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR25: sprintf(info->s, "FPR25:%08X%08X", (UINT32)(mips->cpr[1][25] >> 32), (UINT32)mips->cpr[1][25]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR26: sprintf(info->s, "FPR26:%08X%08X", (UINT32)(mips->cpr[1][26] >> 32), (UINT32)mips->cpr[1][26]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR27: sprintf(info->s, "FPR27:%08X%08X", (UINT32)(mips->cpr[1][27] >> 32), (UINT32)mips->cpr[1][27]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR28: sprintf(info->s, "FPR28:%08X%08X", (UINT32)(mips->cpr[1][28] >> 32), (UINT32)mips->cpr[1][28]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR29: sprintf(info->s, "FPR29:%08X%08X", (UINT32)(mips->cpr[1][29] >> 32), (UINT32)mips->cpr[1][29]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR30: sprintf(info->s, "FPR30:%08X%08X", (UINT32)(mips->cpr[1][30] >> 32), (UINT32)mips->cpr[1][30]); break;
+ case CPUINFO_STR_REGISTER + MIPS3_FPR31: sprintf(info->s, "FPR31:%08X%08X", (UINT32)(mips->cpr[1][31] >> 32), (UINT32)mips->cpr[1][31]); break;
+ }
+}
+
+
+/***************************************************************************
+ INTERNAL HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ compare_int_callback - callback that fires
+ whenever a compare interrupt is generated
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( compare_int_callback )
+{
+ cpunum_set_input_line(param, MIPS3_IRQ5, ASSERT_LINE);
+}
+
+
+/*-------------------------------------------------
+ compute_config_register - compute the value
+ of the config register
+-------------------------------------------------*/
+
+static UINT32 compute_config_register(const mips3_state *mips)
+{
+ /* set the cache line size to 32 bytes */
+ UINT32 configreg = 0x00026030;
+ int divisor;
+
+ /* set the data cache size */
+ if (mips->icache_size <= 0x01000) configreg |= 0 << 6;
+ else if (mips->icache_size <= 0x02000) configreg |= 1 << 6;
+ else if (mips->icache_size <= 0x04000) configreg |= 2 << 6;
+ else if (mips->icache_size <= 0x08000) configreg |= 3 << 6;
+ else if (mips->icache_size <= 0x10000) configreg |= 4 << 6;
+ else if (mips->icache_size <= 0x20000) configreg |= 5 << 6;
+ else if (mips->icache_size <= 0x40000) configreg |= 6 << 6;
+ else configreg |= 7 << 6;
+
+ /* set the instruction cache size */
+ if (mips->icache_size <= 0x01000) configreg |= 0 << 9;
+ else if (mips->icache_size <= 0x02000) configreg |= 1 << 9;
+ else if (mips->icache_size <= 0x04000) configreg |= 2 << 9;
+ else if (mips->icache_size <= 0x08000) configreg |= 3 << 9;
+ else if (mips->icache_size <= 0x10000) configreg |= 4 << 9;
+ else if (mips->icache_size <= 0x20000) configreg |= 5 << 9;
+ else if (mips->icache_size <= 0x40000) configreg |= 6 << 9;
+ else configreg |= 7 << 9;
+
+ /* set the endianness bit */
+ if (mips->bigendian)
+ configreg |= 0x00008000;
+
+ /* set the system clock divider */
+ divisor = 2;
+ if (mips->system_clock != 0)
+ {
+ divisor = mips->cpu_clock / mips->system_clock;
+ if (mips->system_clock * divisor != mips->cpu_clock)
+ {
+ configreg |= 0x80000000;
+ divisor = mips->cpu_clock * 2 / mips->system_clock;
+ }
+ }
+ configreg |= (((divisor < 2) ? 2 : (divisor > 8) ? 8 : divisor) - 2) << 28;
+
+ return configreg;
+}
+
+
+/*-------------------------------------------------
+ compute_prid_register - compute the value
+ of the PRId register
+-------------------------------------------------*/
+
+static UINT32 compute_prid_register(const mips3_state *mips)
+{
+ switch (mips->flavor)
+ {
+ case MIPS3_TYPE_R4600:
+ case MIPS3_TYPE_R4650:
+ return 0x2000;
+
+ case MIPS3_TYPE_R4700:
+ return 0x2100;
+
+ case MIPS3_TYPE_R5000:
+ case MIPS3_TYPE_QED5271:
+ return 0x2300;
+
+ case MIPS3_TYPE_RM7000:
+ return 0x2700;
+
+ default:
+ fatalerror("Unknown MIPS flavor specified");
+ }
+ return 0x2000;
+}
+
+
+/*-------------------------------------------------
+ tlb_write_common - common routine for writing
+ a TLB entry
+-------------------------------------------------*/
+
+static void tlb_write_common(mips3_state *mips, int index)
+{
+ /* only handle entries within the TLB */
+ if (index < ARRAY_LENGTH(mips->tlb))
+ {
+ mips3_tlb_entry *tlbent = &mips->tlb[index];
+
+ /* unmap what we have */
+ mips3com_unmap_tlb_entries(mips);
+
+ /* fill in the new TLB entry from the COP0 registers */
+ tlbent->page_mask = mips->cpr[0][COP0_PageMask];
+ tlbent->entry_hi = mips->cpr[0][COP0_EntryHi] & ~(tlbent->page_mask & U64(0x0000000001ffe000));
+ tlbent->entry_lo[0] = mips->cpr[0][COP0_EntryLo0];
+ tlbent->entry_lo[1] = mips->cpr[0][COP0_EntryLo1];
+
+ /* remap the TLB */
+ mips3com_map_tlb_entries(mips);
+
+ /* log the two halves once they are in */
+ tlb_entry_log_half(tlbent, index, 0);
+ tlb_entry_log_half(tlbent, index, 1);
+ }
+}
+
+
+/*-------------------------------------------------
+ tlb_entry_log_half - log half of a single TLB
+ entry
+-------------------------------------------------*/
+
+static void tlb_entry_log_half(mips3_tlb_entry *tlbent, int index, int which)
+{
+#if PRINTF_TLB
+ UINT64 hi = tlbent->entry_hi;
+ UINT64 lo = tlbent->entry_lo[which];
+ UINT32 vpn = (((hi >> 13) & 0x07ffffff) << 1);
+ UINT32 asid = hi & 0xff;
+ UINT32 r = (hi >> 62) & 3;
+ UINT32 pfn = (lo >> 6) & 0x00ffffff;
+ UINT32 c = (lo >> 3) & 7;
+ UINT32 pagesize = (((tlbent->page_mask >> 13) & 0xfff) + 1) << MIPS3_MIN_PAGE_SHIFT;
+ UINT64 vaddr = (UINT64)vpn * MIPS3_MIN_PAGE_SIZE;
+ UINT64 paddr = (UINT64)pfn * MIPS3_MIN_PAGE_SIZE;
+
+ vaddr += pagesize * which;
+
+ mame_printf_debug("index=%08X pagesize=%08X vaddr=%08X%08X paddr=%08X%08X asid=%02X r=%X c=%X dvg=%c%c%c\n",
+ index, pagesize, (UINT32)(vaddr >> 32), (UINT32)vaddr, (UINT32)(paddr >> 32), (UINT32)paddr,
+ asid, r, c, (lo & 4) ? 'd' : '.', (lo & 2) ? 'v' : '.', (hi & 0x1000) ? 'g' : '.');
+#endif
+}
+
+
+
+/***************************************************************************
+ DOUBLEWORD READS/WRITES
+***************************************************************************/
+
+/*-------------------------------------------------
+ program_read_qword_32be - read a 64-bit
+ big-endian value
+-------------------------------------------------*/
+
+static UINT64 program_read_qword_32be(offs_t offset)
+{
+ UINT64 result = (UINT64)program_read_dword_32be(offset) << 32;
+ return result | program_read_dword_32be(offset + 4);
+}
+
+
+/*-------------------------------------------------
+ program_read_qword_masked_32be - read a 64-bit
+ big-endian value with explicit masking
+-------------------------------------------------*/
+
+static UINT64 program_read_qword_masked_32be(offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)program_read_masked_32be(offset, mem_mask >> 32) << 32;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= program_read_masked_32be(offset + 4, mem_mask);
+ return result;
+}
+
+
+/*-------------------------------------------------
+ program_read_qword_32le - read a 64-bit
+ little-endian value
+-------------------------------------------------*/
+
+static UINT64 program_read_qword_32le(offs_t offset)
+{
+ UINT64 result = program_read_dword_32le(offset);
+ return result | ((UINT64)program_read_dword_32le(offset + 4) << 32);
+}
+
+
+/*-------------------------------------------------
+ program_read_qword_masked_32le - read a 64-bit
+ little-endian value with explicit masking
+-------------------------------------------------*/
+
+static UINT64 program_read_qword_masked_32le(offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= program_read_masked_32le(offset, mem_mask);
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)program_read_masked_32le(offset + 4, mem_mask >> 32) << 32;
+ return result;
+}
+
+
+/*-------------------------------------------------
+ program_write_qword_32be - write a 64-bit
+ big-endian value
+-------------------------------------------------*/
+
+static void program_write_qword_32be(offs_t offset, UINT64 data)
+{
+ program_write_dword_32be(offset, data >> 32);
+ program_write_dword_32be(offset + 4, data);
+}
+
+
+/*-------------------------------------------------
+ program_write_qword_masked_32be - write a
+ 64-bit big-endian value with explicit masking
+-------------------------------------------------*/
+
+static void program_write_qword_masked_32be(offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ program_write_masked_32be(offset, data >> 32, mem_mask >> 32);
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ program_write_masked_32be(offset + 4, data, mem_mask);
+}
+
+
+/*-------------------------------------------------
+ program_write_qword_32le - write a 64-bit
+ little-endian value
+-------------------------------------------------*/
+
+static void program_write_qword_32le(offs_t offset, UINT64 data)
+{
+ program_write_dword_32le(offset, data);
+ program_write_dword_32le(offset + 4, data >> 32);
+}
+
+
+/*-------------------------------------------------
+ program_write_qword_masked_32le - write a
+ 64-bit little-endian value with explicit masking
+-------------------------------------------------*/
+
+static void program_write_qword_masked_32le(offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ program_write_masked_32le(offset, data, mem_mask);
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ program_write_masked_32le(offset + 4, data >> 32, mem_mask >> 32);
+}
diff --git a/src/emu/cpu/mips/mips3com.h b/src/emu/cpu/mips/mips3com.h
new file mode 100644
index 00000000000..a7eb879551d
--- /dev/null
+++ b/src/emu/cpu/mips/mips3com.h
@@ -0,0 +1,257 @@
+/***************************************************************************
+
+ mips3com.h
+
+ Common MIPS III/IV definitions and functions
+
+***************************************************************************/
+
+#ifndef __MIPS3COM_H__
+#define __MIPS3COM_H__
+
+#include "cpuintrf.h"
+#include "mips3.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* core parameters */
+#define MIPS3_MIN_PAGE_SHIFT 12
+#define MIPS3_MIN_PAGE_SIZE (1 << MIPS3_MIN_PAGE_SHIFT)
+#define MIPS3_MIN_PAGE_MASK (MIPS3_MIN_PAGE_SIZE - 1)
+#define MIPS3_MAX_PADDR_SHIFT 32
+
+/* cycle parameters */
+#define MIPS3_COUNT_READ_CYCLES 250
+#define MIPS3_CAUSE_READ_CYCLES 250
+
+/* MIPS flavors */
+enum _mips3_flavor
+{
+ /* MIPS III variants */
+ MIPS3_TYPE_MIPS_III,
+ MIPS3_TYPE_R4600,
+ MIPS3_TYPE_R4650,
+ MIPS3_TYPE_R4700,
+
+ /* MIPS IV variants */
+ MIPS3_TYPE_MIPS_IV,
+ MIPS3_TYPE_R5000,
+ MIPS3_TYPE_QED5271,
+ MIPS3_TYPE_RM7000
+};
+typedef enum _mips3_flavor mips3_flavor;
+
+/* COP0 registers */
+#define COP0_Index 0
+#define COP0_Random 1
+#define COP0_EntryLo 2
+#define COP0_EntryLo0 2
+#define COP0_EntryLo1 3
+#define COP0_Context 4
+#define COP0_PageMask 5
+#define COP0_Wired 6
+#define COP0_BadVAddr 8
+#define COP0_Count 9
+#define COP0_EntryHi 10
+#define COP0_Compare 11
+#define COP0_Status 12
+#define COP0_Cause 13
+#define COP0_EPC 14
+#define COP0_PRId 15
+#define COP0_Config 16
+#define COP0_XContext 20
+
+/* Status register bits */
+#define SR_IE 0x00000001
+#define SR_EXL 0x00000002
+#define SR_ERL 0x00000004
+#define SR_KSU_MASK 0x00000018
+#define SR_KSU_KERNEL 0x00000000
+#define SR_KSU_SUPERVISOR 0x00000008
+#define SR_KSU_USER 0x00000010
+#define SR_IMSW0 0x00000100
+#define SR_IMSW1 0x00000200
+#define SR_IMEX0 0x00000400
+#define SR_IMEX1 0x00000800
+#define SR_IMEX2 0x00001000
+#define SR_IMEX3 0x00002000
+#define SR_IMEX4 0x00004000
+#define SR_IMEX5 0x00008000
+#define SR_DE 0x00010000
+#define SR_CE 0x00020000
+#define SR_CH 0x00040000
+#define SR_SR 0x00100000
+#define SR_TS 0x00200000
+#define SR_BEV 0x00400000
+#define SR_RE 0x02000000
+#define SR_FR 0x04000000
+#define SR_RP 0x08000000
+#define SR_COP0 0x10000000
+#define SR_COP1 0x20000000
+#define SR_COP2 0x40000000
+#define SR_COP3 0x80000000
+
+/* exception types */
+#define EXCEPTION_INTERRUPT 0
+#define EXCEPTION_TLBMOD 1
+#define EXCEPTION_TLBLOAD 2
+#define EXCEPTION_TLBSTORE 3
+#define EXCEPTION_ADDRLOAD 4
+#define EXCEPTION_ADDRSTORE 5
+#define EXCEPTION_BUSINST 6
+#define EXCEPTION_BUSDATA 7
+#define EXCEPTION_SYSCALL 8
+#define EXCEPTION_BREAK 9
+#define EXCEPTION_INVALIDOP 10
+#define EXCEPTION_BADCOP 11
+#define EXCEPTION_OVERFLOW 12
+#define EXCEPTION_TRAP 13
+
+
+
+/***************************************************************************
+ HELPER MACROS
+***************************************************************************/
+
+#define REG_LO 32
+#define REG_HI 33
+
+#define RSREG ((op >> 21) & 31)
+#define RTREG ((op >> 16) & 31)
+#define RDREG ((op >> 11) & 31)
+#define SHIFT ((op >> 6) & 31)
+
+#define FRREG ((op >> 21) & 31)
+#define FTREG ((op >> 16) & 31)
+#define FSREG ((op >> 11) & 31)
+#define FDREG ((op >> 6) & 31)
+
+#define IS_SINGLE(o) (((o) & (1 << 21)) == 0)
+#define IS_DOUBLE(o) (((o) & (1 << 21)) != 0)
+#define IS_FLOAT(o) (((o) & (1 << 23)) == 0)
+#define IS_INTEGRAL(o) (((o) & (1 << 23)) != 0)
+
+#define SIMMVAL ((INT16)op)
+#define UIMMVAL ((UINT16)op)
+#define LIMMVAL (op & 0x03ffffff)
+
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+/* memory access function table */
+typedef struct _memory_handlers memory_handlers;
+struct _memory_handlers
+{
+ UINT8 (*readbyte)(offs_t);
+ UINT16 (*readhalf)(offs_t);
+ UINT32 (*readword)(offs_t);
+ UINT32 (*readword_masked)(offs_t, UINT32);
+ UINT64 (*readdouble)(offs_t);
+ UINT64 (*readdouble_masked)(offs_t, UINT64);
+ void (*writebyte)(offs_t, UINT8);
+ void (*writehalf)(offs_t, UINT16);
+ void (*writeword)(offs_t, UINT32);
+ void (*writeword_masked)(offs_t, UINT32, UINT32);
+ void (*writedouble)(offs_t, UINT64);
+ void (*writedouble_masked)(offs_t, UINT64, UINT64);
+};
+
+
+/* MIPS3 TLB entry */
+typedef struct _mips3_tlb_entry mips3_tlb_entry;
+struct _mips3_tlb_entry
+{
+ UINT64 page_mask;
+ UINT64 entry_hi;
+ UINT64 entry_lo[2];
+};
+
+
+/* MIPS3 state */
+typedef struct _mips3_state mips3_state;
+struct _mips3_state
+{
+ /* core registers */
+ UINT32 pc;
+ int icount;
+ UINT64 r[35];
+
+ /* COP registers */
+ UINT64 cpr[3][32];
+ UINT64 ccr[3][32];
+ UINT8 cf[3][8];
+
+ /* internal stuff */
+ mips3_flavor flavor;
+ int (*irq_callback)(int irqline);
+ UINT32 system_clock;
+ UINT32 cpu_clock;
+ UINT64 count_zero_time;
+ emu_timer * compare_int_timer;
+
+ /* memory accesses */
+ UINT8 bigendian;
+ memory_handlers memory;
+
+ /* cache memory */
+ UINT32 * icache;
+ UINT32 * dcache;
+ size_t icache_size;
+ size_t dcache_size;
+
+ /* MMU */
+ mips3_tlb_entry tlb[48];
+ UINT32 * tlb_table;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void mips3com_init(mips3_state *mips, mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int));
+void mips3com_reset(mips3_state *mips);
+#ifdef MAME_DEBUG
+offs_t mips3com_dasm(mips3_state *mips, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+void mips3com_update_cycle_counting(mips3_state *mips);
+
+void mips3com_map_tlb_entries(mips3_state *mips);
+void mips3com_unmap_tlb_entries(mips3_state *mips);
+void mips3com_recompute_tlb_table(mips3_state *mips);
+int mips3com_translate_address(mips3_state *mips, int space, offs_t *address);
+void mips3com_tlbr(mips3_state *mips);
+void mips3com_tlbwi(mips3_state *mips);
+void mips3com_tlbwr(mips3_state *mips);
+void mips3com_tlbp(mips3_state *mips);
+
+void mips3com_set_info(mips3_state *mips, UINT32 state, cpuinfo *info);
+void mips3com_get_info(mips3_state *mips, UINT32 state, cpuinfo *info);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mips3com_set_irq_line - set or clear the given
+ IRQ line
+-------------------------------------------------*/
+
+INLINE void mips3com_set_irq_line(mips3_state *mips, int irqline, int state)
+{
+ if (state != CLEAR_LINE)
+ mips->cpr[0][COP0_Cause] |= 0x400 << irqline;
+ else
+ mips->cpr[0][COP0_Cause] &= ~(0x400 << irqline);
+}
+
+#endif
diff --git a/src/emu/cpu/mips/mips3drc.c b/src/emu/cpu/mips/mips3drc.c
new file mode 100644
index 00000000000..d10378f3e95
--- /dev/null
+++ b/src/emu/cpu/mips/mips3drc.c
@@ -0,0 +1,1297 @@
+/***************************************************************************
+
+ mips3drc.c
+ x86 Dynamic recompiler for MIPS III/IV emulator.
+ Written by Aaron Giles
+
+ Philosophy: this is intended to be a very basic implementation of a
+ dynamic compiler in order to keep things simple. There are certainly
+ more optimizations that could be added but for now, we keep it
+ strictly to NOP stripping and LUI optimizations.
+
+***************************************************************************/
+
+#include <stddef.h>
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "mips3com.h"
+#include "mips3fe.h"
+#include "cpu/x86log.h"
+#include "cpu/drcfe.h"
+
+extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op);
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define LOG_CODE (0)
+#define SINGLE_INSTRUCTION_MODE (0)
+
+#ifdef MAME_DEBUG
+#define COMPARE_AGAINST_C (0)
+#else
+#define COMPARE_AGAINST_C (0)
+#endif
+
+
+
+/***************************************************************************
+ CONFIGURATION
+***************************************************************************/
+
+/* size of the execution code cache */
+#define CACHE_SIZE (32 * 1024 * 1024)
+
+/* compilation boundaries -- how far back/forward does the analysis extend? */
+#define COMPILE_BACKWARDS_BYTES 128
+#define COMPILE_FORWARDS_BYTES 512
+#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4))
+#define COMPILE_MAX_SEQUENCE 64
+
+/* hack when running comparison against the C core */
+#if COMPARE_AGAINST_C
+#undef MIPS3_COUNT_READ_CYCLES
+#undef MIPS3_CAUSE_READ_CYCLES
+#define MIPS3_COUNT_READ_CYCLES 0
+#define MIPS3_CAUSE_READ_CYCLES 0
+#endif
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define SR mips3.core->cpr[0][COP0_Status]
+#define IS_FR0 (!(SR & SR_FR))
+#define IS_FR1 (SR & SR_FR)
+
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+/* fast RAM info */
+typedef struct _fast_ram_info fast_ram_info;
+struct _fast_ram_info
+{
+ offs_t start;
+ offs_t end;
+ UINT8 readonly;
+ void * base;
+};
+
+
+/* hotspot info */
+typedef struct _hotspot_info hotspot_info;
+struct _hotspot_info
+{
+ offs_t pc;
+ UINT32 opcode;
+ UINT32 cycles;
+};
+
+
+/* opaque drc-specific info */
+typedef struct _mips3drc_data mips3drc_data;
+
+
+/* MIPS3 registers */
+typedef struct _mips3_regs mips3_regs;
+struct _mips3_regs
+{
+ /* core state */
+ UINT8 * cache; /* base of the cache */
+ mips3_state * core; /* pointer to the core MIPS3 state */
+ drcfe_state * drcfe; /* pointer to the DRC front-end state */
+ drc_core * drc; /* pointer to the DRC core */
+ mips3drc_data * drcdata; /* pointer to the DRC-specific data */
+ UINT32 drcoptions; /* configurable DRC options */
+
+ /* internal stuff */
+ UINT32 nextpc;
+ UINT8 cache_dirty;
+
+ /* fast RAM */
+ UINT32 fastram_select;
+ fast_ram_info fastram[MIPS3_MAX_FASTRAM];
+
+ /* hotspots */
+ UINT32 hotspot_select;
+ hotspot_info hotspot[MIPS3_MAX_HOTSPOTS];
+
+ /* code logging */
+ x86log_context *log;
+
+#if COMPARE_AGAINST_C
+ /* memory state */
+ UINT8 access_size;
+ UINT8 access_type;
+ offs_t access_addr;
+ UINT64 access_data;
+ UINT64 access_mask;
+ memory_handlers orighandler;
+#endif
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void mips3drc_init(void);
+static void mips3drc_exit(void);
+
+#if COMPARE_AGAINST_C
+static void execute_c_version(void);
+static void compare_c_version(void);
+static void mips3c_init(mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int));
+static void mips3c_reset(void);
+#endif
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static mips3_regs mips3;
+
+
+
+/***************************************************************************
+ CORE CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mips3_init - initialize the processor
+-------------------------------------------------*/
+
+static void mips3_init(mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int))
+{
+ drcfe_config feconfig =
+ {
+ COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */
+ COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */
+ COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */
+ mips3fe_describe /* callback to describe a single instruction */
+ };
+
+ /* allocate a cache and memory for the core data in a single block */
+ mips3.core = osd_alloc_executable(CACHE_SIZE + sizeof(*mips3.core));
+ if (mips3.core == NULL)
+ fatalerror("Unable to allocate cache of size %d\n", CACHE_SIZE);
+ mips3.cache = (UINT8 *)(mips3.core + 1);
+
+ /* initialize the core */
+ mips3com_init(mips3.core, flavor, bigendian, index, clock, config, irqcallback);
+#if COMPARE_AGAINST_C
+ mips3c_init(flavor, bigendian, index, clock, config, irqcallback);
+#endif
+
+ /* initialize the DRC to use the cache */
+ mips3drc_init();
+ if (Machine->debug_mode || SINGLE_INSTRUCTION_MODE)
+ feconfig.max_sequence = 1;
+ mips3.drcfe = drcfe_init(&feconfig, mips3.core);
+
+ /* start up code logging */
+ if (LOG_CODE)
+ mips3.log = x86log_create_context("mips3drc.asm");
+}
+
+
+/*-------------------------------------------------
+ mips3_reset - reset the processor
+-------------------------------------------------*/
+
+static void mips3_reset(void)
+{
+ /* reset the common code and flush the cache */
+ mips3com_reset(mips3.core);
+ drc_cache_reset(mips3.drc);
+
+#if COMPARE_AGAINST_C
+ mips3c_reset();
+#endif
+}
+
+
+/*-------------------------------------------------
+ mips3_execute - execute the CPU for the
+ specified number of cycles
+-------------------------------------------------*/
+
+static int mips3_execute(int cycles)
+{
+ /* reset the cache if dirty */
+ if (mips3.cache_dirty)
+ drc_cache_reset(mips3.drc);
+ mips3.cache_dirty = FALSE;
+
+ /* execute */
+ mips3.core->icount = cycles;
+ drc_execute(mips3.drc);
+ return cycles - mips3.core->icount;
+}
+
+
+/*-------------------------------------------------
+ mips3_exit - cleanup from execution
+-------------------------------------------------*/
+
+static void mips3_exit(void)
+{
+ /* clean up code logging */
+ if (LOG_CODE)
+ x86log_free_context(mips3.log);
+
+ /* clean up the DRC */
+ mips3drc_exit();
+ drcfe_exit(mips3.drcfe);
+ drc_exit(mips3.drc);
+
+ /* free the cache */
+ osd_free_executable(mips3.core, CACHE_SIZE + sizeof(*mips3.core));
+}
+
+
+/*-------------------------------------------------
+ mips3_get_context - return a copy of the
+ current context
+-------------------------------------------------*/
+
+static void mips3_get_context(void *dst)
+{
+ if (dst != NULL)
+ *(mips3_regs *)dst = mips3;
+}
+
+
+/*-------------------------------------------------
+ mips3_set_context - copy the current context
+ into the global state
+-------------------------------------------------*/
+
+static void mips3_set_context(void *src)
+{
+ if (src != NULL)
+ mips3 = *(mips3_regs *)src;
+}
+
+
+/*-------------------------------------------------
+ mips3_translate - perform virtual-to-physical
+ address translation
+-------------------------------------------------*/
+
+static int mips3_translate(int space, offs_t *address)
+{
+ return mips3com_translate_address(mips3.core, space, address);
+}
+
+
+/*-------------------------------------------------
+ mips3_dasm - disassemble an instruction
+-------------------------------------------------*/
+
+#ifdef MAME_DEBUG
+static offs_t mips3_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return mips3com_dasm(mips3.core, buffer, pc, oprom, opram);
+}
+#endif /* MAME_DEBUG */
+
+
+
+
+/***************************************************************************
+ COMMON UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ fastram_ptr - return a pointer to the base of
+ memory containing the given address, if it
+ is within a fast RAM range; returns 0
+ otherwise
+-------------------------------------------------*/
+
+#ifdef PTR64
+static void *fastram_ptr(offs_t addr, int size, int iswrite)
+{
+ int ramnum;
+
+ /* only direct maps are supported */
+ if (addr < 0x80000000 || addr >= 0xc0000000)
+ return NULL;
+ addr &= 0x1fffffff;
+
+ /* adjust address for endianness */
+ if (mips3.core->bigendian)
+ {
+ if (size == 1)
+ addr ^= 3;
+ else if (size == 2)
+ addr ^= 2;
+ }
+
+ /* search for fastram */
+ for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++)
+ if (mips3.fastram[ramnum].base != NULL && (!iswrite || !mips3.fastram[ramnum].readonly) &&
+ addr >= mips3.fastram[ramnum].start && addr <= mips3.fastram[ramnum].end)
+ {
+ return (UINT8 *)mips3.fastram[ramnum].base + (addr - mips3.fastram[ramnum].start);
+ }
+
+ return NULL;
+}
+#endif
+
+
+
+/***************************************************************************
+ CODE LOGGING HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ log_add_disasm_comment - add a comment
+ including disassembly of a MIPS instruction
+-------------------------------------------------*/
+
+static void log_add_disasm_comment(x86log_context *log, x86code *base, UINT32 pc, UINT32 op)
+{
+#if (LOG_CODE)
+ {
+ char buffer[100];
+ dasmmips3(buffer, pc, op);
+ x86log_add_comment(log, base, "%08X: %s", pc, buffer);
+ }
+#endif
+}
+
+
+#ifdef PTR64
+
+/*-------------------------------------------------
+ desc_flags_to_string - generate a string
+ representing the instruction description
+ flags
+-------------------------------------------------*/
+
+static const char *desc_flags_to_string(UINT32 flags)
+{
+ static char tempbuf[30];
+ char *dest = tempbuf;
+
+ /* branches */
+ if (flags & OPFLAG_IS_UNCONDITIONAL_BRANCH)
+ *dest++ = 'U';
+ else if (flags & OPFLAG_IS_CONDITIONAL_BRANCH)
+ *dest++ = 'C';
+ else
+ *dest++ = '.';
+
+ /* intrablock branches */
+ *dest++ = (flags & OPFLAG_INTRABLOCK_BRANCH) ? 'i' : '.';
+
+ /* branch targets */
+ *dest++ = (flags & OPFLAG_IS_BRANCH_TARGET) ? 'B' : '.';
+
+ /* delay slots */
+ *dest++ = (flags & OPFLAG_IN_DELAY_SLOT) ? 'D' : '.';
+
+ /* exceptions */
+ if (flags & OPFLAG_WILL_CAUSE_EXCEPTION)
+ *dest++ = 'E';
+ else if (flags & OPFLAG_CAN_CAUSE_EXCEPTION)
+ *dest++ = 'e';
+ else
+ *dest++ = '.';
+
+ /* read/write */
+ if (flags & OPFLAG_READS_MEMORY)
+ *dest++ = 'R';
+ else if (flags & OPFLAG_WRITES_MEMORY)
+ *dest++ = 'W';
+ else
+ *dest++ = '.';
+
+ /* TLB validation */
+ *dest++ = (flags & OPFLAG_VALIDATE_TLB) ? 'V' : '.';
+
+ /* TLB modification */
+ *dest++ = (flags & OPFLAG_MODIFIES_TRANSLATION) ? 'T' : '.';
+
+ /* redispatch */
+ *dest++ = (flags & OPFLAG_REDISPATCH) ? 'R' : '.';
+ return tempbuf;
+}
+
+
+/*-------------------------------------------------
+ log_register_list - log a list of GPR registers
+-------------------------------------------------*/
+
+static void log_register_list(x86log_context *log, const char *string, UINT64 gprmask, UINT64 fprmask)
+{
+ int count = 0;
+ int regnum;
+
+ /* skip if nothing */
+ if ((gprmask & ~1) == 0 && fprmask == 0)
+ return;
+
+ x86log_printf(log, "[%s:", string);
+
+ for (regnum = 1; regnum < 32; regnum++)
+ if (gprmask & ((UINT64)1 << regnum))
+ x86log_printf(log, "%sr%d", (count++ == 0) ? "" : ",", regnum);
+ if (gprmask & ((UINT64)1 << REG_LO))
+ x86log_printf(log, "%slo", (count++ == 0) ? "" : ",");
+ if (gprmask & ((UINT64)1 << REG_HI))
+ x86log_printf(log, "%shi", (count++ == 0) ? "" : ",");
+
+ for (regnum = 0; regnum < 32; regnum++)
+ if (fprmask & ((UINT64)1 << regnum))
+ x86log_printf(log, "%sfpr%d", (count++ == 0) ? "" : ",", regnum);
+ if (fprmask & REGFLAG_FCC)
+ x86log_printf(log, "%sfcc", (count++ == 0) ? "" : ",");
+ x86log_printf(log, "] ");
+}
+
+
+/*-------------------------------------------------
+ log_opcode_desc - log a list of descriptions
+-------------------------------------------------*/
+
+static void log_opcode_desc(x86log_context *log, const opcode_desc *desclist, int indent)
+{
+ /* open the file, creating it if necessary */
+ if (indent == 0)
+ x86log_printf(log, "\nDescriptor list @ %08X\n", desclist->pc);
+
+ /* output each descriptor */
+ for ( ; desclist != NULL; desclist = desclist->next)
+ {
+ char buffer[100];
+
+ /* disassemle the current instruction and output it to the log */
+#if LOG_CODE
+ dasmmips3(buffer, desclist->pc, *desclist->opptr.l);
+#else
+ strcpy(buffer, "???");
+#endif
+ x86log_printf(log, "%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, desc_flags_to_string(desclist->flags), buffer);
+
+ /* output register states */
+ log_register_list(log, "use", desclist->gpr.used, desclist->fpr.used);
+ log_register_list(log, "mod", desclist->gpr.modified, desclist->fpr.modified);
+ log_register_list(log, "lrd", desclist->gpr.liveread, desclist->fpr.liveread);
+ log_register_list(log, "lwr", desclist->gpr.livewrite, desclist->fpr.livewrite);
+ x86log_printf(log, "\n");
+
+ /* if we have a delay slot, output it recursively */
+ if (desclist->delay != NULL)
+ log_opcode_desc(log, desclist->delay, indent + 1);
+
+ /* at the end of a sequence add a dividing line */
+ if (desclist->flags & OPFLAG_END_SEQUENCE)
+ x86log_printf(log, "-----\n");
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ RECOMPILER CORE
+***************************************************************************/
+
+#ifdef PTR64
+#include "mdrc64.c"
+#else
+#include "mdrcold.c"
+#endif
+
+
+
+/***************************************************************************
+ GENERIC GET/SET INFO
+***************************************************************************/
+
+static void mips3_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_MIPS3_DRC_OPTIONS: mips3.drcoptions = info->i; break;
+
+ case CPUINFO_INT_MIPS3_FASTRAM_SELECT: if (info->i >= 0 && info->i < MIPS3_MAX_FASTRAM) mips3.fastram_select = info->i; mips3.cache_dirty = TRUE; break;
+ case CPUINFO_INT_MIPS3_FASTRAM_START: mips3.fastram[mips3.fastram_select].start = info->i; mips3.cache_dirty = TRUE; break;
+ case CPUINFO_INT_MIPS3_FASTRAM_END: mips3.fastram[mips3.fastram_select].end = info->i; mips3.cache_dirty = TRUE; break;
+ case CPUINFO_INT_MIPS3_FASTRAM_READONLY: mips3.fastram[mips3.fastram_select].readonly = info->i; mips3.cache_dirty = TRUE; break;
+
+ case CPUINFO_INT_MIPS3_HOTSPOT_SELECT: if (info->i >= 0 && info->i < MIPS3_MAX_HOTSPOTS) mips3.hotspot_select = info->i; mips3.cache_dirty = TRUE; break;
+ case CPUINFO_INT_MIPS3_HOTSPOT_PC: mips3.hotspot[mips3.hotspot_select].pc = info->i; mips3.cache_dirty = TRUE; break;
+ case CPUINFO_INT_MIPS3_HOTSPOT_OPCODE: mips3.hotspot[mips3.hotspot_select].opcode = info->i; mips3.cache_dirty = TRUE; break;
+ case CPUINFO_INT_MIPS3_HOTSPOT_CYCLES: mips3.hotspot[mips3.hotspot_select].cycles = info->i; mips3.cache_dirty = TRUE; break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_MIPS3_FASTRAM_BASE: mips3.fastram[mips3.fastram_select].base = info->p; break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3com_set_info(mips3.core, state, info); break;
+ }
+}
+
+
+void mips3_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(mips3); break;
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mips3_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = mips3_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = mips3_set_context; break;
+ case CPUINFO_PTR_INIT: /* provided per-CPU */ break;
+ case CPUINFO_PTR_RESET: info->reset = mips3_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = mips3_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = mips3_execute; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = mips3_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_TRANSLATE: info->translate = mips3_translate; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3com_get_info(mips3.core, state, info); break;
+ }
+}
+
+
+
+/***************************************************************************
+ R4600 VARIANTS
+***************************************************************************/
+
+#if (HAS_R4600)
+static void r4600be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_R4600, TRUE, index, clock, config, irqcallback);
+}
+
+static void r4600le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_R4600, FALSE, index, clock, config, irqcallback);
+}
+
+void r4600be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4600be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R4600 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void r4600le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4600le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R4600 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ R4650 VARIANTS
+***************************************************************************/
+
+#if (HAS_R4650)
+static void r4650be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_R4650, TRUE, index, clock, config, irqcallback);
+}
+
+static void r4650le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_R4650, FALSE, index, clock, config, irqcallback);
+}
+
+void r4650be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4650be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "IDT R4650 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void r4650le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4650le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "IDT R4650 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ R4700 VARIANTS
+***************************************************************************/
+
+#if (HAS_R4700)
+static void r4700be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_R4700, TRUE, index, clock, config, irqcallback);
+}
+
+static void r4700le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_R4700, FALSE, index, clock, config, irqcallback);
+}
+
+void r4700be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4700be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R4700 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+
+void r4700le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r4700le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R4700 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ R5000 VARIANTS
+***************************************************************************/
+
+#if (HAS_R5000)
+static void r5000be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_R5000, TRUE, index, clock, config, irqcallback);
+}
+
+static void r5000le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_R5000, FALSE, index, clock, config, irqcallback);
+}
+
+void r5000be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r5000be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R5000 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void r5000le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = r5000le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R5000 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ QED5271 VARIANTS
+***************************************************************************/
+
+#if (HAS_QED5271)
+static void qed5271be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_QED5271, TRUE, index, clock, config, irqcallback);
+}
+
+static void qed5271le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_QED5271, FALSE, index, clock, config, irqcallback);
+}
+
+void qed5271be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = qed5271be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "QED5271 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void qed5271le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = qed5271le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "QED5271 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ RM7000 VARIANTS
+***************************************************************************/
+
+#if (HAS_RM7000)
+static void rm7000be_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_RM7000, TRUE, index, clock, config, irqcallback);
+}
+
+static void rm7000le_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ mips3_init(MIPS3_TYPE_RM7000, FALSE, index, clock, config, irqcallback);
+}
+
+void rm7000be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = rm7000be_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "RM7000 (big)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+
+void rm7000le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = rm7000le_init; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "RM7000 (little)"); break;
+
+ /* --- everything else is handled generically --- */
+ default: mips3_get_info(state, info); break;
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ DISASSEMBLERS
+***************************************************************************/
+
+#if !defined(MAME_DEBUG) && (LOG_CODE)
+#include "mips3dsm.c"
+#endif
+
+
+
+/***************************************************************************
+ C CORE FOR COMPARISON
+***************************************************************************/
+
+#if COMPARE_AGAINST_C
+
+static UINT8 dummy_read_byte_32le(offs_t offs)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 1;
+ mips3.access_size = 1;
+ mips3.access_addr = offs;
+ mips3.access_mask = 0;
+ mips3.access_data = program_read_byte_32le(offs);
+ }
+ else
+ {
+ assert(mips3.access_type == 1);
+ assert(mips3.access_size == 1);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_mask == 0);
+ mips3.access_type = 0;
+ }
+ return mips3.access_data;
+}
+
+static UINT16 dummy_read_word_32le(offs_t offs)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 1;
+ mips3.access_size = 2;
+ mips3.access_addr = offs;
+ mips3.access_mask = 0;
+ mips3.access_data = program_read_word_32le(offs);
+ }
+ else
+ {
+ assert(mips3.access_type == 1);
+ assert(mips3.access_size == 2);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_mask == 0);
+ mips3.access_type = 0;
+ }
+ return mips3.access_data;
+}
+
+static UINT32 dummy_read_dword_32le(offs_t offs)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 1;
+ mips3.access_size = 4;
+ mips3.access_addr = offs;
+ mips3.access_mask = 0;
+ mips3.access_data = program_read_dword_32le(offs);
+ }
+ else
+ {
+ assert(mips3.access_type == 1);
+ assert(mips3.access_size == 4);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_mask == 0);
+ mips3.access_type = 0;
+ }
+ return mips3.access_data;
+}
+
+static UINT32 dummy_read_masked_32le(offs_t offs, UINT32 mask)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 1;
+ mips3.access_size = 4;
+ mips3.access_addr = offs;
+ mips3.access_mask = mask;
+ mips3.access_data = program_read_masked_32le(offs, mask);
+ }
+ else
+ {
+ assert(mips3.access_type == 1);
+ assert(mips3.access_size == 4);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_mask == mask);
+ mips3.access_type = 0;
+ }
+ return mips3.access_data;
+}
+
+static UINT64 dummy_read_qword_32le(offs_t offs)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 1;
+ mips3.access_size = 8;
+ mips3.access_addr = offs;
+ mips3.access_mask = 0;
+ mips3.access_data = (*mips3.orighandler.readdouble)(offs);
+ }
+ else
+ {
+ assert(mips3.access_type == 1);
+ assert(mips3.access_size == 8);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_mask == 0);
+ mips3.access_type = 0;
+ }
+ return mips3.access_data;
+}
+
+static UINT64 dummy_read_qword_masked_32le(offs_t offs, UINT64 mask)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 1;
+ mips3.access_size = 8;
+ mips3.access_addr = offs;
+ mips3.access_mask = mask;
+ mips3.access_data = (*mips3.orighandler.readdouble_masked)(offs, mask);
+ }
+ else
+ {
+ assert(mips3.access_type == 1);
+ assert(mips3.access_size == 8);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_mask == mask);
+ mips3.access_type = 0;
+ }
+ return mips3.access_data;
+}
+
+static void dummy_write_byte_32le(offs_t offs, UINT8 data)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 2;
+ mips3.access_size = 1;
+ mips3.access_addr = offs;
+ mips3.access_data = data;
+ mips3.access_mask = 0;
+ }
+ else
+ {
+ assert(mips3.access_type == 2);
+ assert(mips3.access_size == 1);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_data == data);
+ assert(mips3.access_mask == 0);
+ mips3.access_type = 0;
+ program_write_byte_32le(offs, data);
+ }
+}
+
+static void dummy_write_word_32le(offs_t offs, UINT16 data)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 2;
+ mips3.access_size = 2;
+ mips3.access_addr = offs;
+ mips3.access_data = data;
+ mips3.access_mask = 0;
+ }
+ else
+ {
+ assert(mips3.access_type == 2);
+ assert(mips3.access_size == 2);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_data == data);
+ assert(mips3.access_mask == 0);
+ mips3.access_type = 0;
+ program_write_word_32le(offs, data);
+ }
+}
+
+static void dummy_write_dword_32le(offs_t offs, UINT32 data)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 2;
+ mips3.access_size = 4;
+ mips3.access_addr = offs;
+ mips3.access_data = data;
+ mips3.access_mask = 0;
+ }
+ else
+ {
+ assert(mips3.access_type == 2);
+ assert(mips3.access_size == 4);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_data == data);
+ assert(mips3.access_mask == 0);
+ mips3.access_type = 0;
+ program_write_dword_32le(offs, data);
+ }
+}
+
+static void dummy_write_masked_32le(offs_t offs, UINT32 data, UINT32 mask)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 2;
+ mips3.access_size = 4;
+ mips3.access_addr = offs;
+ mips3.access_data = data;
+ mips3.access_mask = mask;
+ }
+ else
+ {
+ assert(mips3.access_type == 2);
+ assert(mips3.access_size == 4);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_data == data);
+ assert(mips3.access_mask == mask);
+ mips3.access_type = 0;
+ program_write_masked_32le(offs, data, mask);
+ }
+}
+
+static void dummy_write_qword_32le(offs_t offs, UINT64 data)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 2;
+ mips3.access_size = 8;
+ mips3.access_addr = offs;
+ mips3.access_data = data;
+ mips3.access_mask = 0;
+ }
+ else
+ {
+ assert(mips3.access_type == 2);
+ assert(mips3.access_size == 8);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_data == data);
+ assert(mips3.access_mask == 0);
+ mips3.access_type = 0;
+ (*mips3.orighandler.writedouble)(offs, data);
+ }
+}
+
+static void dummy_write_qword_masked_32le(offs_t offs, UINT64 data, UINT64 mask)
+{
+ if (mips3.access_type == 0)
+ {
+ mips3.access_type = 2;
+ mips3.access_size = 8;
+ mips3.access_addr = offs;
+ mips3.access_data = data;
+ mips3.access_mask = mask;
+ }
+ else
+ {
+ assert(mips3.access_type == 2);
+ assert(mips3.access_size == 8);
+ assert(mips3.access_addr == offs);
+ assert(mips3.access_data == data);
+ assert(mips3.access_mask == mask);
+ mips3.access_type = 0;
+ (*mips3.orighandler.writedouble_masked)(offs, data, mask);
+ }
+}
+
+static const memory_handlers override_memory =
+{
+ dummy_read_byte_32le,
+ dummy_read_word_32le,
+ dummy_read_dword_32le,
+ dummy_read_masked_32le,
+ dummy_read_qword_32le,
+ dummy_read_qword_masked_32le,
+
+ dummy_write_byte_32le,
+ dummy_write_word_32le,
+ dummy_write_dword_32le,
+ dummy_write_masked_32le,
+ dummy_write_qword_32le,
+ dummy_write_qword_masked_32le
+};
+
+#undef SR
+
+#define mips3 c_mips3
+#define mips3_regs c_mips3_regs
+
+#define mips3_get_context c_mips3_get_context
+#define mips3_set_context c_mips3_set_context
+#define mips3_reset c_mips3_reset
+#define mips3_translate c_mips3_translate
+#define mips3_dasm c_mips3_dasm
+#define mips3_execute c_mips3_execute
+#define mips3_set_info c_mips3_set_info
+#define mips3_get_info c_mips3_get_info
+
+#define r4600be_init c_r4600be_init
+#define r4600le_init c_r4600le_init
+#define r4600be_get_info c_r4600be_get_info
+#define r4600le_get_info c_r4600le_get_info
+
+#define r4650be_init c_r4650be_init
+#define r4650le_init c_r4650le_init
+#define r4650be_get_info c_r4650be_get_info
+#define r4650le_get_info c_r4650le_get_info
+
+#define r4700be_init c_r4700be_init
+#define r4700le_init c_r4700le_init
+#define r4700be_get_info c_r4700be_get_info
+#define r4700le_get_info c_r4700le_get_info
+
+#define r5000be_init c_r5000be_init
+#define r5000le_init c_r5000le_init
+#define r5000be_get_info c_r5000be_get_info
+#define r5000le_get_info c_r5000le_get_info
+
+#define qed5271be_init c_qed5271be_init
+#define qed5271le_init c_qed5271le_init
+#define qed5271be_get_info c_qed5271be_get_info
+#define qed5271le_get_info c_qed5271le_get_info
+
+#define rm7000be_init c_rm7000be_init
+#define rm7000le_init c_rm7000le_init
+#define rm7000be_get_info c_rm7000be_get_info
+#define rm7000le_get_info c_rm7000le_get_info
+
+#include "mips3.c"
+
+#undef mips3
+
+static void mips3c_init(mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int))
+{
+ mips3com_init(&c_mips3.core, flavor, bigendian, index, clock, config, irqcallback);
+ mips3.orighandler = mips3.core->memory;
+ mips3.core->memory = override_memory;
+ c_mips3.core.memory = override_memory;
+}
+
+static void mips3c_reset(void)
+{
+ c_mips3_reset();
+}
+
+static void execute_c_version(void)
+{
+ int save_debug_mode = Machine->debug_mode;
+ int i;
+
+ assert(mips3.access_type == 0);
+
+ c_mips3.core.cpr[0][COP0_Cause] = (c_mips3.core.cpr[0][COP0_Cause] & ~0xfc00) | (mips3.core->cpr[0][COP0_Cause] & 0xfc00);
+ check_irqs();
+
+ assert(c_mips3.core.pc == mips3.core->pc);
+ assert(c_mips3.core.r[REG_HI] == mips3.core->r[REG_HI]);
+ assert(c_mips3.core.r[REG_LO] == mips3.core->r[REG_LO]);
+ for (i = 0; i < 32; i++)
+ {
+ assert(c_mips3.core.r[i] == mips3.core->r[i]);
+ assert(c_mips3.core.cpr[0][i] == mips3.core->cpr[0][i]);
+ assert(c_mips3.core.ccr[0][i] == mips3.core->ccr[0][i]);
+ assert(c_mips3.core.cpr[1][i] == mips3.core->cpr[1][i]);
+ assert(c_mips3.core.ccr[1][i] == mips3.core->ccr[1][i]);
+ }
+ for (i = 0; i < 8; i++)
+ assert(c_mips3.core.cf[1][i] == mips3.core->cf[1][i]);
+ assert(c_mips3.core.count_zero_time == mips3.core->count_zero_time);
+
+ mips3.access_type = 0;
+
+ Machine->debug_mode = 0;
+ c_mips3_execute(0);
+ Machine->debug_mode = save_debug_mode;
+}
+
+static void compare_c_version(void)
+{
+}
+
+#endif
diff --git a/src/emu/cpu/mips/mips3dsm.c b/src/emu/cpu/mips/mips3dsm.c
new file mode 100644
index 00000000000..b7896a9f9cd
--- /dev/null
+++ b/src/emu/cpu/mips/mips3dsm.c
@@ -0,0 +1,511 @@
+/***************************************************************************
+
+ mips3dsm.c
+ Disassembler for the portable MIPS 3 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#include "cpuintrf.h"
+
+
+static const char *reg[32] =
+{
+ "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+
+static const char *cpreg[4][32] =
+{
+ {
+ "Index","Random","EntryLo0","EntryLo1","Context","PageMask","Wired","Error",
+ "BadVAddr","Count","EntryHi","Compare","SR","Cause","EPC","PRId",
+ "Config","LLAddr","WatchLo","WatchHi","XContext","cpr21","cpr22","cpr23",
+ "cpr24","cpr25","ECC","CacheError","TagLo","TagHi","ErrorEPC","cpr31"
+ },
+ {
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
+ },
+ {
+ "cpr0", "cpr1", "cpr2", "cpr3", "cpr4", "cpr5", "cpr6", "cpr7",
+ "cpr8", "cpr9", "cpr10","cpr11","cpr12","cpr13","cpr14","cpr15",
+ "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23",
+ "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31"
+ },
+ {
+ "cpr0", "cpr1", "cpr2", "cpr3", "cpr4", "cpr5", "cpr6", "cpr7",
+ "cpr8", "cpr9", "cpr10","cpr11","cpr12","cpr13","cpr14","cpr15",
+ "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23",
+ "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31"
+ }
+};
+
+
+static const char *ccreg[4][32] =
+{
+ {
+ "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7",
+ "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15",
+ "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23",
+ "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31"
+ },
+ {
+ "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7",
+ "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15",
+ "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23",
+ "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31"
+ },
+ {
+ "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7",
+ "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15",
+ "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23",
+ "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31"
+ },
+ {
+ "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7",
+ "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15",
+ "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23",
+ "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31"
+ }
+};
+
+
+/***************************************************************************
+ CODE CODE
+***************************************************************************/
+
+INLINE char *signed_16bit(INT16 val)
+{
+ static char temp[10];
+ if (val < 0)
+ sprintf(temp, "-$%x", -val);
+ else
+ sprintf(temp, "$%x", val);
+ return temp;
+}
+
+static UINT32 dasm_cop0(UINT32 pc, UINT32 op, char *buffer)
+{
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ UINT32 flags = 0;
+
+ switch ((op >> 21) & 31)
+ {
+ case 0x00: sprintf(buffer, "mfc0 %s,%s", reg[rt], cpreg[0][rd]); break;
+ case 0x01: sprintf(buffer, "dmfc0 %s,%s", reg[rt], cpreg[0][rd]); break;
+ case 0x02: sprintf(buffer, "cfc0 %s,%s", reg[rt], ccreg[0][rd]); break;
+ case 0x04: sprintf(buffer, "mtc0 %s,%s", reg[rt], cpreg[0][rd]); break;
+ case 0x05: sprintf(buffer, "dmtc0 %s,%s", reg[rt], cpreg[0][rd]); break;
+ case 0x06: sprintf(buffer, "ctc0 %s,%s", reg[rt], ccreg[0][rd]); break;
+ case 0x08: /* BC */
+ switch (rt)
+ {
+ case 0x00: sprintf(buffer, "bc0f $%08x", pc + 4 + ((INT16)op << 2)); break;
+ case 0x01: sprintf(buffer, "bc0t $%08x", pc + 4 + ((INT16)op << 2)); break;
+ case 0x02: sprintf(buffer, "bc0fl [invalid]"); break;
+ case 0x03: sprintf(buffer, "bc0tl [invalid]"); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ break;
+ 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: /* COP */
+ switch (op & 0x01ffffff)
+ {
+ case 0x01: sprintf(buffer, "tlbr"); break;
+ case 0x02: sprintf(buffer, "tlbwi"); break;
+ case 0x06: sprintf(buffer, "tlbwr"); break;
+ case 0x08: sprintf(buffer, "tlbp"); break;
+ case 0x10: sprintf(buffer, "rfe"); flags = DASMFLAG_STEP_OUT; break;
+ case 0x18: sprintf(buffer, "eret [invalid]"); break;
+ default: sprintf(buffer, "cop0 $%07x", op & 0x01ffffff); break;
+ }
+ break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ return flags;
+}
+
+static UINT32 dasm_cop1(UINT32 pc, UINT32 op, char *buffer)
+{
+ static const char *format_table[] =
+ {
+ "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?",
+ "s","d","?","?","w","l","?","?","?","?","?","?","?","?","?","?"
+ };
+ const char *fmt = format_table[(op >> 21) & 31];
+ int ft = (op >> 16) & 31;
+ int fs = (op >> 11) & 31;
+ int fd = (op >> 6) & 31;
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ UINT32 flags = 0;
+
+ switch ((op >> 21) & 31)
+ {
+ case 0x00: sprintf(buffer, "mfc1 %s,%s", reg[rt], cpreg[1][rd]); break;
+ case 0x01: sprintf(buffer, "dmfc1 %s,%s", reg[rt], cpreg[1][rd]); break;
+ case 0x02: sprintf(buffer, "cfc1 %s,%s", reg[rt], ccreg[1][rd]); break;
+ case 0x04: sprintf(buffer, "mtc1 %s,%s", reg[rt], cpreg[1][rd]); break;
+ case 0x05: sprintf(buffer, "dmtc1 %s,%s", reg[rt], cpreg[1][rd]); break;
+ case 0x06: sprintf(buffer, "ctc1 %s,%s", reg[rt], ccreg[1][rd]); break;
+ case 0x08: /* BC */
+ switch (rt & 3)
+ {
+ case 0x00: sprintf(buffer, "bc1f $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); break;
+ case 0x01: sprintf(buffer, "bc1t $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); break;
+ case 0x02: sprintf(buffer, "bc1fl $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x03: sprintf(buffer, "bc1tl $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ }
+ break;
+ default: /* COP */
+ switch (op & 0x3f)
+ {
+ case 0x00: sprintf(buffer, "add.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break;
+ case 0x01: sprintf(buffer, "sub.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break;
+ case 0x02: sprintf(buffer, "mul.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break;
+ case 0x03: sprintf(buffer, "div.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break;
+ case 0x04: sprintf(buffer, "sqrt.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x05: sprintf(buffer, "abs.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x06: sprintf(buffer, "mov.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x07: sprintf(buffer, "neg.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x08: sprintf(buffer, "round.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x09: sprintf(buffer, "trunc.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x0a: sprintf(buffer, "ceil.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x0b: sprintf(buffer, "floor.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x0c: sprintf(buffer, "round.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x0d: sprintf(buffer, "trunc.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x0e: sprintf(buffer, "ceil.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x0f: sprintf(buffer, "floor.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x11: sprintf(buffer, "mov%c.%s %s,%s,%d", ((op >> 16) & 1) ? 't' : 'f', fmt, cpreg[1][fd], cpreg[1][fs], (op >> 18) & 7); break;
+ case 0x12: sprintf(buffer, "movz.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], reg[rt]); break;
+ case 0x13: sprintf(buffer, "movn.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], reg[rt]); break;
+ case 0x15: sprintf(buffer, "recip.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x16: sprintf(buffer, "rsqrt.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x20: sprintf(buffer, "cvt.s.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x21: sprintf(buffer, "cvt.d.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x24: sprintf(buffer, "cvt.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x25: sprintf(buffer, "cvt.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break;
+ case 0x30: sprintf(buffer, "c.f.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x31: sprintf(buffer, "c.un.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x32: sprintf(buffer, "c.eq.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x33: sprintf(buffer, "c.ueq.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x34: sprintf(buffer, "c.olt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x35: sprintf(buffer, "c.ult.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x36: sprintf(buffer, "c.ole.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x37: sprintf(buffer, "c.ule.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x38: sprintf(buffer, "c.sf.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x39: sprintf(buffer, "c.ngle.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7);break;
+ case 0x3a: sprintf(buffer, "c.seq.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x3b: sprintf(buffer, "c.ngl.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x3c: sprintf(buffer, "c.lt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x3d: sprintf(buffer, "c.nge.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x3e: sprintf(buffer, "c.le.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ case 0x3f: sprintf(buffer, "c.ngt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
+ default: sprintf(buffer, "cop1 $%07x", op & 0x01ffffff); break;
+ }
+ break;
+ }
+ return flags;
+}
+
+static UINT32 dasm_cop1x(UINT32 pc, UINT32 op, char *buffer)
+{
+ static const char *format3_table[] =
+ {
+ "s","d","?","?","w","l","?","?"
+ };
+ const char *fmt3 = format3_table[op & 7];
+ int fr = (op >> 21) & 31;
+ int ft = (op >> 16) & 31;
+ int fs = (op >> 11) & 31;
+ int fd = (op >> 6) & 31;
+ int rs = (op >> 21) & 31;
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ UINT32 flags = 0;
+
+ switch (op & 0x3f)
+ {
+ case 0x00: sprintf(buffer, "lwxc1 %s,%s(%s)", cpreg[1][fd], reg[rt], reg[rs]); break;
+ case 0x01: sprintf(buffer, "ldxc1 %s,%s(%s)", cpreg[1][fd], reg[rt], reg[rs]); break;
+ case 0x08: sprintf(buffer, "swxc1 %s,%s(%s)", cpreg[1][fd], reg[rt], reg[rs]); break;
+ case 0x09: sprintf(buffer, "sdxc1 %s,%s(%s)", cpreg[1][fd], reg[rt], reg[rs]); break;
+ case 0x0f: sprintf(buffer, "prefx %d,%s(%s)", rd, reg[rt], reg[rs]); break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27: sprintf(buffer, "madd.%s %s,%s,%s,%s", fmt3, cpreg[1][fd], cpreg[1][fr], cpreg[1][fs], cpreg[1][ft]); break;
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f: sprintf(buffer, "msub.%s %s,%s,%s,%s", fmt3, cpreg[1][fd], cpreg[1][fr], cpreg[1][fs], cpreg[1][ft]); break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37: sprintf(buffer, "nmadd.%s %s,%s,%s,%s", fmt3, cpreg[1][fd], cpreg[1][fr], cpreg[1][fs], cpreg[1][ft]); break;
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f: sprintf(buffer, "nmsub.%s %s,%s,%s,%s", fmt3, cpreg[1][fd], cpreg[1][fr], cpreg[1][fs], cpreg[1][ft]); break;
+ default: sprintf(buffer, "cop1 $%07x", op & 0x01ffffff); break;
+ }
+ return flags;
+}
+
+static UINT32 dasm_cop2(UINT32 pc, UINT32 op, char *buffer)
+{
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ UINT32 flags = 0;
+
+ switch ((op >> 21) & 31)
+ {
+ case 0x00: sprintf(buffer, "mfc2 %s,%s", reg[rt], cpreg[2][rd]); break;
+ case 0x01: sprintf(buffer, "dmfc2 %s,%s", reg[rt], cpreg[2][rd]); break;
+ case 0x02: sprintf(buffer, "cfc2 %s,%s", reg[rt], ccreg[2][rd]); break;
+ case 0x04: sprintf(buffer, "mtc2 %s,%s", reg[rt], cpreg[2][rd]); break;
+ case 0x05: sprintf(buffer, "dmtc2 %s,%s", reg[rt], cpreg[2][rd]); break;
+ case 0x06: sprintf(buffer, "ctc2 %s,%s", reg[rt], ccreg[2][rd]); break;
+ case 0x08: /* BC */
+ switch (rt)
+ {
+ case 0x00: sprintf(buffer, "bc2f $%08x", pc + 4 + ((INT16)op << 2)); break;
+ case 0x01: sprintf(buffer, "bc2t $%08x", pc + 4 + ((INT16)op << 2)); break;
+ case 0x02: sprintf(buffer, "bc2fl [invalid]"); break;
+ case 0x03: sprintf(buffer, "bc2tl [invalid]"); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ break;
+ 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: /* COP */
+ sprintf(buffer, "cop2 $%07x", op & 0x01ffffff);
+ break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ return flags;
+}
+
+unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op)
+{
+ int rs = (op >> 21) & 31;
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ int shift = (op >> 6) & 31;
+ UINT32 flags = 0;
+
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ switch (op & 63)
+ {
+ case 0x00: if (op == 0)
+ sprintf(buffer, "nop");
+ else
+ sprintf(buffer, "sll %s,%s,%d", reg[rd], reg[rt], shift); break;
+ case 0x01: sprintf(buffer, "mov%c %s,%s,%d", ((op >> 16) & 1) ? 't' : 'f', reg[rd], reg[rt], (op >> 18) & 7); break;
+ case 0x02: sprintf(buffer, "srl %s,%s,%d", reg[rd], reg[rt], shift); break;
+ case 0x03: sprintf(buffer, "sra %s,%s,%d", reg[rd], reg[rt], shift); break;
+ case 0x04: sprintf(buffer, "sllv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x06: sprintf(buffer, "srlv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x07: sprintf(buffer, "srav %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x08: sprintf(buffer, "jr %s", reg[rs]); if (rs == 31) flags = DASMFLAG_STEP_OUT; break;
+ case 0x09: if (rd == 31)
+ sprintf(buffer, "jalr %s", reg[rs]);
+ else
+ sprintf(buffer, "jalr %s,%s", reg[rs], reg[rd]); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x0a: sprintf(buffer, "movz %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x0b: sprintf(buffer, "movn %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x0c: sprintf(buffer, "syscall"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x0d: sprintf(buffer, "break"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x0f: sprintf(buffer, "sync"); break;
+ case 0x10: sprintf(buffer, "mfhi %s", reg[rd]); break;
+ case 0x11: sprintf(buffer, "mthi %s", reg[rs]); break;
+ case 0x12: sprintf(buffer, "mflo %s", reg[rd]); break;
+ case 0x13: sprintf(buffer, "mtlo %s", reg[rs]); break;
+ case 0x14: sprintf(buffer, "dsllv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x16: sprintf(buffer, "dsrlv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x17: sprintf(buffer, "dsrav %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x18: sprintf(buffer, "mult %s,%s", reg[rs], reg[rt]); break;
+ case 0x19: sprintf(buffer, "multu %s,%s", reg[rs], reg[rt]); break;
+ case 0x1a: sprintf(buffer, "div %s,%s", reg[rs], reg[rt]); break;
+ case 0x1b: sprintf(buffer, "divu %s,%s", reg[rs], reg[rt]); break;
+ case 0x1c: sprintf(buffer, "dmult %s,%s", reg[rs], reg[rt]); break;
+ case 0x1d: sprintf(buffer, "dmultu %s,%s", reg[rs], reg[rt]); break;
+ case 0x1e: sprintf(buffer, "ddiv %s,%s", reg[rs], reg[rt]); break;
+ case 0x1f: sprintf(buffer, "ddivu %s,%s", reg[rs], reg[rt]); break;
+ case 0x20: sprintf(buffer, "add %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x21: sprintf(buffer, "addu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x22: sprintf(buffer, "sub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x23: sprintf(buffer, "subu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x24: sprintf(buffer, "and %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x25: sprintf(buffer, "or %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x26: sprintf(buffer, "xor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x27: sprintf(buffer, "nor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2a: sprintf(buffer, "slt %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2b: sprintf(buffer, "sltu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2c: sprintf(buffer, "dadd %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2d: sprintf(buffer, "daddu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2e: sprintf(buffer, "dsub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2f: sprintf(buffer, "dsubu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x30: sprintf(buffer, "tge %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break;
+ case 0x31: sprintf(buffer, "tgeu %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break;
+ case 0x32: sprintf(buffer, "tlt %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break;
+ case 0x33: sprintf(buffer, "tltu %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break;
+ case 0x34: sprintf(buffer, "teq %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break;
+ case 0x36: sprintf(buffer, "tne %s,%s", reg[rs], reg[rt]) ;flags = DASMFLAG_STEP_OVER; break;
+ case 0x38: sprintf(buffer, "dsll %s,%s,%d", reg[rd], reg[rt], shift); break;
+ case 0x3a: sprintf(buffer, "dsrl %s,%s,%d", reg[rd], reg[rt], shift); break;
+ case 0x3b: sprintf(buffer, "dsra %s,%s,%d", reg[rd], reg[rt], shift); break;
+ case 0x3c: sprintf(buffer, "dsll %s,%s,%d", reg[rd], reg[rt], shift+32); break;
+ case 0x3e: sprintf(buffer, "dsrl %s,%s,%d", reg[rd], reg[rt], shift+32); break;
+ case 0x3f: sprintf(buffer, "dsra %s,%s,%d", reg[rd], reg[rt], shift+32); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ break;
+
+ case 0x01: /* REGIMM */
+ switch ((op >> 16) & 31)
+ {
+ case 0x00: sprintf(buffer, "bltz %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x01: sprintf(buffer, "bgez %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x02: sprintf(buffer, "bltzl %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x03: sprintf(buffer, "bgezl %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x08: sprintf(buffer, "tgei %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break;
+ case 0x09: sprintf(buffer, "tgeiu %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break;
+ case 0x0a: sprintf(buffer, "tlti %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break;
+ case 0x0b: sprintf(buffer, "tltiu %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break;
+ case 0x0c: sprintf(buffer, "teqi %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break;
+ case 0x0e: sprintf(buffer, "tnei %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break;
+ case 0x10: sprintf(buffer, "bltzal %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x11: sprintf(buffer, "bgezal %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x12: sprintf(buffer, "bltzall %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x13: sprintf(buffer, "bgezall %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ break;
+
+ case 0x02: sprintf(buffer, "j $%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); break;
+ case 0x03: sprintf(buffer, "jal $%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x04: if (rs == 0 && rt == 0)
+ sprintf(buffer, "b $%08x", pc + 4 + ((INT16)op << 2));
+ else
+ sprintf(buffer, "beq %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break;
+ case 0x05: sprintf(buffer, "bne %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break;
+ case 0x06: sprintf(buffer, "blez %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x07: sprintf(buffer, "bgtz %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x08: sprintf(buffer, "addi %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x09: sprintf(buffer, "addiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x0a: sprintf(buffer, "slti %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x0b: sprintf(buffer, "sltiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x0c: sprintf(buffer, "andi %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break;
+ case 0x0d: sprintf(buffer, "ori %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break;
+ case 0x0e: sprintf(buffer, "xori %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break;
+ case 0x0f: sprintf(buffer, "lui %s,$%04x", reg[rt], (UINT16)op); break;
+ case 0x10: flags = dasm_cop0(pc, op, buffer); break;
+ case 0x11: flags = dasm_cop1(pc, op, buffer); break;
+ case 0x12: flags = dasm_cop2(pc, op, buffer); break;
+ case 0x13: flags = dasm_cop1x(pc, op, buffer); break;
+ case 0x14: sprintf(buffer, "beql %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break;
+ case 0x15: sprintf(buffer, "bnel %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break;
+ case 0x16: sprintf(buffer, "blezl %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break;
+ case 0x17: sprintf(buffer, "bgtzl %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break;
+ case 0x18: sprintf(buffer, "daddi %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x19: sprintf(buffer, "daddiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x1a: sprintf(buffer, "ldl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x1b: sprintf(buffer, "ldr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */
+ switch (op & 0x1f)
+ {
+ case 0: sprintf(buffer, "mad %s,%s", reg[rs], reg[rt]); break;
+ case 1: sprintf(buffer, "madu %s,%s", reg[rs], reg[rt]); break;
+ case 2: sprintf(buffer, "mul %s,%s,%s", reg[rs], reg[rt], reg[rd]); break;
+ case 4: sprintf(buffer, "msub %s,%s", reg[rs], reg[rt]); break;
+ default:sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ break;
+ case 0x20: sprintf(buffer, "lb %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x21: sprintf(buffer, "lh %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x22: sprintf(buffer, "lwl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x23: sprintf(buffer, "lw %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x24: sprintf(buffer, "lbu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x25: sprintf(buffer, "lhu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x26: sprintf(buffer, "lwr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x27: sprintf(buffer, "lwu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x28: sprintf(buffer, "sb %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x29: sprintf(buffer, "sh %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2a: sprintf(buffer, "swl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2b: sprintf(buffer, "sw %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2c: sprintf(buffer, "sdl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2d: sprintf(buffer, "sdr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2e: sprintf(buffer, "swr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2f: sprintf(buffer, "cache %s(%s)", reg[rs], signed_16bit(op)); break;
+ case 0x30: sprintf(buffer, "ll %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x31: sprintf(buffer, "lwc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
+ case 0x32: sprintf(buffer, "lwc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
+ case 0x33: sprintf(buffer, "pref $%x,%s(%s)", rt, signed_16bit(op), reg[rs]); break;
+ case 0x34: sprintf(buffer, "lld %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x35: sprintf(buffer, "ldc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
+ case 0x36: sprintf(buffer, "ldc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
+ case 0x37: sprintf(buffer, "ld %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x38: sprintf(buffer, "sc %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x39: sprintf(buffer, "swc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
+ case 0x3a: sprintf(buffer, "swc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
+ case 0x3c: sprintf(buffer, "scd %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x3d: sprintf(buffer, "sdc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
+ case 0x3e: sprintf(buffer, "sdc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
+ case 0x3f: sprintf(buffer, "sd %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ return 4 | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/mips/mips3fe.c b/src/emu/cpu/mips/mips3fe.c
new file mode 100644
index 00000000000..f8cbbcb4660
--- /dev/null
+++ b/src/emu/cpu/mips/mips3fe.c
@@ -0,0 +1,721 @@
+/***************************************************************************
+
+ mips3fe.c
+
+ Front-end for MIPS3 recompiler
+
+ Copyright (c) 2007, Aaron Giles
+ Released for general use under the MAME license
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include <stddef.h>
+#include "cpuintrf.h"
+#include "mips3fe.h"
+#include "mips3com.h"
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int describe_instruction_special(mips3_state *mips, UINT32 op, opcode_desc *desc);
+static int describe_instruction_regimm(mips3_state *mips, UINT32 op, opcode_desc *desc);
+static int describe_instruction_idt(mips3_state *mips, UINT32 op, opcode_desc *desc);
+static int describe_instruction_cop0(mips3_state *mips, UINT32 op, opcode_desc *desc);
+static int describe_instruction_cop1(mips3_state *mips, UINT32 op, opcode_desc *desc);
+static int describe_instruction_cop1x(mips3_state *mips, UINT32 op, opcode_desc *desc);
+static int describe_instruction_cop2(mips3_state *mips, UINT32 op, opcode_desc *desc);
+
+
+
+/***************************************************************************
+ INSTRUCTION PARSERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ describe_instruction - build a description
+ of a single instruction
+-------------------------------------------------*/
+
+int mips3fe_describe(void *param, opcode_desc *desc)
+{
+ mips3_state *mips = param;
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = op >> 26;
+
+ /* all instructions are 4 bytes and default to a single cycle each */
+ desc->length = 4;
+ desc->cycles = 1;
+
+ /* parse the instruction */
+ switch (opswitch)
+ {
+ case 0x00: /* SPECIAL */
+ return describe_instruction_special(mips, op, desc);
+
+ case 0x01: /* REGIMM */
+ return describe_instruction_regimm(mips, op, desc);
+
+ case 0x10: /* COP0 */
+ return describe_instruction_cop0(mips, op, desc);
+
+ case 0x11: /* COP1 */
+ return describe_instruction_cop1(mips, op, desc);
+
+ case 0x12: /* COP2 */
+ return describe_instruction_cop2(mips, op, desc);
+
+ case 0x13: /* COP1X - MIPS IV */
+ if (mips->flavor < MIPS3_TYPE_MIPS_IV)
+ return FALSE;
+ return describe_instruction_cop1x(mips, op, desc);
+
+ case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */
+ return describe_instruction_idt(mips, op, desc);
+
+ case 0x02: /* J */
+ desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc->targetpc = (desc->pc & 0xf0000000) | (LIMMVAL << 2);
+ desc->delayslots = 1;
+ return TRUE;
+
+ case 0x03: /* JAL */
+ desc->gpr.modified |= REGFLAG_R(31);
+ desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc->targetpc = (desc->pc & 0xf0000000) | (LIMMVAL << 2);
+ desc->delayslots = 1;
+ return TRUE;
+
+ case 0x04: /* BEQ */
+ case 0x05: /* BNE */
+ case 0x14: /* BEQL */
+ case 0x15: /* BNEL */
+ if ((opswitch == 0x04 || opswitch == 0x14) && RSREG == RTREG)
+ desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ else
+ {
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ }
+ desc->targetpc = desc->pc + 4 + (SIMMVAL << 2);
+ desc->delayslots = 1;
+ desc->skipslots = (opswitch & 0x10) ? 1 : 0;
+ return TRUE;
+
+ case 0x06: /* BLEZ */
+ case 0x07: /* BGTZ */
+ case 0x16: /* BLEZL */
+ case 0x17: /* BGTZL */
+ if ((opswitch == 0x06 || opswitch == 0x16) && RSREG == 0)
+ desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ else
+ {
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ }
+ desc->targetpc = desc->pc + 4 + (SIMMVAL << 2);
+ desc->delayslots = 1;
+ desc->skipslots = (opswitch & 0x10) ? 1 : 0;
+ return TRUE;
+
+ case 0x08: /* ADDI */
+ case 0x18: /* DADDI */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->gpr.modified |= REGFLAG_R(RTREG);
+ desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x09: /* ADDIU */
+ case 0x0a: /* SLTI */
+ case 0x0b: /* SLTIU */
+ case 0x0c: /* ANDI */
+ case 0x0d: /* ORI */
+ case 0x0e: /* XORI */
+ case 0x19: /* DADDIU */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->gpr.modified |= REGFLAG_R(RTREG);
+ return TRUE;
+
+ case 0x0f: /* LUI */
+ desc->gpr.modified |= REGFLAG_R(RTREG);
+ return TRUE;
+
+ case 0x1a: /* LDL */
+ case 0x1b: /* LDR */
+ case 0x22: /* LWL */
+ case 0x26: /* LWR */
+ desc->gpr.used |= REGFLAG_R(RTREG);
+ case 0x20: /* LB */
+ case 0x21: /* LH */
+ case 0x23: /* LW */
+ case 0x24: /* LBU */
+ case 0x25: /* LHU */
+ case 0x27: /* LWU */
+ case 0x30: /* LL */
+ case 0x34: /* LLD */
+ case 0x37: /* LD */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->gpr.modified |= REGFLAG_R(RTREG);
+ desc->flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x28: /* SB */
+ case 0x29: /* SH */
+ case 0x2a: /* SWL */
+ case 0x2b: /* SW */
+ case 0x2c: /* SDL */
+ case 0x2d: /* SDR */
+ case 0x2e: /* SWR */
+ case 0x38: /* SC */
+ case 0x3c: /* SCD */
+ case 0x3f: /* SD */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x31: /* LWC1 */
+ case 0x35: /* LDC1 */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->fpr.modified |= REGFLAG_CPR1(RTREG);
+ desc->flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x39: /* SWC1 */
+ case 0x3d: /* SDC1 */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->fpr.used |= REGFLAG_CPR1(RTREG);
+ desc->flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x32: /* LWC2 */
+ case 0x36: /* LDC2 */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x3a: /* SWC2 */
+ case 0x3e: /* SDC2 */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x33: /* PREF */
+ if (mips->flavor < MIPS3_TYPE_MIPS_IV)
+ return FALSE;
+ case 0x2f: /* CACHE */
+ /* effective no-op */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_special - build a
+ description of a single instruction in the
+ 'special' group
+-------------------------------------------------*/
+
+static int describe_instruction_special(mips3_state *mips, UINT32 op, opcode_desc *desc)
+{
+ switch (op & 63)
+ {
+ case 0x00: /* SLL */
+ case 0x02: /* SRL */
+ case 0x03: /* SRA */
+ case 0x38: /* DSLL */
+ case 0x3a: /* DSRL */
+ case 0x3b: /* DSRA */
+ case 0x3c: /* DSLL32 */
+ case 0x3e: /* DSRL32 */
+ case 0x3f: /* DSRA32 */
+ desc->gpr.used |= REGFLAG_R(RTREG);
+ desc->gpr.modified |= REGFLAG_R(RDREG);
+ return TRUE;
+
+ case 0x0a: /* MOVZ - MIPS IV */
+ case 0x0b: /* MOVN - MIPS IV */
+ if (mips->flavor < MIPS3_TYPE_MIPS_IV)
+ return FALSE;
+ desc->gpr.used |= REGFLAG_R(RDREG);
+ case 0x04: /* SLLV */
+ case 0x06: /* SRLV */
+ case 0x07: /* SRAV */
+ case 0x14: /* DSLLV */
+ case 0x16: /* DSRLV */
+ case 0x17: /* DSRAV */
+ case 0x21: /* ADDU */
+ case 0x23: /* SUBU */
+ case 0x24: /* AND */
+ case 0x25: /* OR */
+ case 0x26: /* XOR */
+ case 0x27: /* NOR */
+ case 0x2a: /* SLT */
+ case 0x2b: /* SLTU */
+ case 0x2d: /* DADDU */
+ case 0x2f: /* DSUBU */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->gpr.modified |= REGFLAG_R(RDREG);
+ return TRUE;
+
+ case 0x20: /* ADD */
+ case 0x22: /* SUB */
+ case 0x2c: /* DADD */
+ case 0x2e: /* DSUB */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->gpr.modified |= REGFLAG_R(RDREG);
+ desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x30: /* TGE */
+ case 0x31: /* TGEU */
+ case 0x32: /* TLT */
+ case 0x33: /* TLTU */
+ case 0x34: /* TEQ */
+ case 0x36: /* TNE */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x01: /* MOVF - MIPS IV */
+ if (mips->flavor < MIPS3_TYPE_MIPS_IV)
+ return FALSE;
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->fpr.used |= REGFLAG_FCC;
+ desc->gpr.modified |= REGFLAG_R(RDREG);
+ return TRUE;
+
+ case 0x08: /* JR */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc->delayslots = 1;
+ return TRUE;
+
+ case 0x09: /* JALR */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->gpr.modified |= REGFLAG_R(RDREG);
+ desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc->delayslots = 1;
+ return TRUE;
+
+ case 0x10: /* MFHI */
+ desc->gpr.used |= REGFLAG_HI;
+ desc->gpr.modified |= REGFLAG_R(RDREG);
+ return TRUE;
+
+ case 0x11: /* MTHI */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->gpr.modified |= REGFLAG_HI;
+ return TRUE;
+
+ case 0x12: /* MFLO */
+ desc->gpr.used |= REGFLAG_LO;
+ desc->gpr.modified |= REGFLAG_R(RDREG);
+ return TRUE;
+
+ case 0x13: /* MTLO */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->gpr.modified |= REGFLAG_LO;
+ return TRUE;
+
+ case 0x18: /* MULT */
+ case 0x19: /* MULTU */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->gpr.modified |= REGFLAG_LO | REGFLAG_HI;
+ desc->cycles = 3;
+ return TRUE;
+
+ case 0x1a: /* DIV */
+ case 0x1b: /* DIVU */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->gpr.modified |= REGFLAG_LO | REGFLAG_HI;
+ desc->cycles = 35;
+ return TRUE;
+
+ case 0x1c: /* DMULT */
+ case 0x1d: /* DMULTU */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->gpr.modified |= REGFLAG_LO | REGFLAG_HI;
+ desc->cycles = 7;
+ return TRUE;
+
+ case 0x1e: /* DDIV */
+ case 0x1f: /* DDIVU */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->gpr.modified |= REGFLAG_LO | REGFLAG_HI;
+ desc->cycles = 67;
+ return TRUE;
+
+ case 0x0c: /* SYSCALL */
+ case 0x0d: /* BREAK */
+ desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_END_SEQUENCE;
+ return TRUE;
+
+ case 0x0f: /* SYNC */
+ /* effective no-op */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_regimm - build a
+ description of a single instruction in the
+ 'regimm' group
+-------------------------------------------------*/
+
+static int describe_instruction_regimm(mips3_state *mips, UINT32 op, opcode_desc *desc)
+{
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */
+ case 0x01: /* BGEZ */
+ case 0x02: /* BLTZL */
+ case 0x03: /* BGEZL */
+ if (RTREG == 0x01 && RSREG == 0)
+ desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ else
+ {
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ }
+ desc->targetpc = desc->pc + 4 + (SIMMVAL << 2);
+ desc->delayslots = 1;
+ desc->skipslots = (RTREG & 0x02) ? 1 : 0;
+ return TRUE;
+
+ case 0x08: /* TGEI */
+ case 0x09: /* TGEIU */
+ case 0x0a: /* TLTI */
+ case 0x0b: /* TLTIU */
+ case 0x0c: /* TEQI */
+ case 0x0e: /* TNEI */
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+ return TRUE;
+
+ case 0x10: /* BLTZAL */
+ case 0x11: /* BGEZAL */
+ case 0x12: /* BLTZALL */
+ case 0x13: /* BGEZALL */
+ if (RTREG == 0x11 && RSREG == 0)
+ desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ else
+ {
+ desc->gpr.used |= REGFLAG_R(RSREG);
+ desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ }
+ desc->gpr.modified |= REGFLAG_R(31);
+ desc->targetpc = desc->pc + 4 + (SIMMVAL << 2);
+ desc->delayslots = 1;
+ desc->skipslots = (RTREG & 0x02) ? 1 : 0;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_idt - build a
+ description of a single instruction in the
+ IDT-specific group
+-------------------------------------------------*/
+
+static int describe_instruction_idt(mips3_state *mips, UINT32 op, opcode_desc *desc)
+{
+ switch (op & 0x1f)
+ {
+ case 0: /* MAD */
+ case 1: /* MADU */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG) | REGFLAG_LO | REGFLAG_HI;
+ desc->gpr.modified |= REGFLAG_LO | REGFLAG_HI;
+ return TRUE;
+
+ case 2: /* MUL */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->gpr.modified |= REGFLAG_R(RDREG);
+ desc->cycles = 3;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_cop0 - build a
+ description of a single instruction in the
+ COP0 group
+-------------------------------------------------*/
+
+static int describe_instruction_cop0(mips3_state *mips, UINT32 op, opcode_desc *desc)
+{
+ /* any COP0 instruction can potentially cause an exception */
+ desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */
+ case 0x01: /* DMFCz */
+ case 0x02: /* CFCz */
+ desc->gpr.modified |= REGFLAG_R(RTREG);
+ return TRUE;
+
+ case 0x04: /* MTCz */
+ case 0x05: /* DMTCz */
+ case 0x06: /* CTCz */
+ desc->gpr.used |= REGFLAG_R(RTREG);
+ if (RSREG == 0x04 || RSREG == 0x05)
+ {
+ if (RDREG == COP0_Cause)
+ desc->flags |= OPFLAG_CAN_TRIGGER_SW_INT;
+ if (RDREG == COP0_Status)
+ desc->flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_CAN_CHANGE_MODES | OPFLAG_END_SEQUENCE;
+ }
+ return TRUE;
+
+ case 0x08: /* BC */
+ switch (RTREG)
+ {
+ case 0x00: /* BCzF */
+ case 0x01: /* BCzT */
+ desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc->targetpc = desc->pc + 4 + (SIMMVAL << 2);
+ desc->delayslots = 1;
+ return TRUE;
+ }
+ return FALSE;
+
+ 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: /* COP */
+ switch (op & 0x01ffffff)
+ {
+ case 0x01: /* TLBR */
+ case 0x08: /* TLBP */
+ case 0x20: /* WAIT */
+ return TRUE;
+
+ case 0x02: /* TLBWI */
+ case 0x06: /* TLBWR */
+ desc->flags |= OPFLAG_MODIFIES_TRANSLATION;
+ return TRUE;
+
+ case 0x18: /* ERET */
+ desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_cop1 - build a
+ description of a single instruction in the
+ COP1 group
+-------------------------------------------------*/
+
+static int describe_instruction_cop1(mips3_state *mips, UINT32 op, opcode_desc *desc)
+{
+ /* any COP1 instruction can potentially cause an exception */
+// desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */
+ case 0x01: /* DMFCz */
+ desc->fpr.used |= REGFLAG_CPR1(RDREG);
+ desc->gpr.modified |= REGFLAG_R(RTREG);
+ return TRUE;
+
+ case 0x02: /* CFCz */
+ desc->gpr.modified |= REGFLAG_R(RTREG);
+ return TRUE;
+
+ case 0x04: /* MTCz */
+ case 0x05: /* DMTCz */
+ desc->gpr.used |= REGFLAG_R(RTREG);
+ desc->fpr.modified |= REGFLAG_CPR1(RDREG);
+ return TRUE;
+
+ case 0x06: /* CTCz */
+ desc->gpr.used |= REGFLAG_R(RTREG);
+ return TRUE;
+
+ case 0x08: /* BC */
+ switch (RTREG & 3)
+ {
+ case 0x00: /* BCzF */
+ case 0x01: /* BCzT */
+ case 0x02: /* BCzFL */
+ case 0x03: /* BCzTL */
+ desc->fpr.used |= REGFLAG_FCC;
+ desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc->targetpc = desc->pc + 4 + (SIMMVAL << 2);
+ desc->delayslots = 1;
+ desc->skipslots = (RTREG & 0x02) ? 1 : 0;
+ return TRUE;
+ }
+ return FALSE;
+
+ 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: /* COP */
+ switch (op & 0x3f)
+ {
+ case 0x12: /* MOVZ - MIPS IV */
+ case 0x13: /* MOVN - MIPS IV */
+ if (mips->flavor < MIPS3_TYPE_MIPS_IV)
+ return FALSE;
+ case 0x00: /* ADD */
+ case 0x01: /* SUB */
+ case 0x02: /* MUL */
+ case 0x03: /* DIV */
+ desc->fpr.used |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG);
+ desc->fpr.modified |= REGFLAG_CPR1(FDREG);
+ return TRUE;
+
+ case 0x15: /* RECIP - MIPS IV */
+ case 0x16: /* RSQRT - MIPS IV */
+ if (mips->flavor < MIPS3_TYPE_MIPS_IV)
+ return FALSE;
+ case 0x04: /* SQRT */
+ case 0x05: /* ABS */
+ case 0x06: /* MOV */
+ case 0x07: /* NEG */
+ case 0x08: /* ROUND.L */
+ case 0x09: /* TRUNC.L */
+ case 0x0a: /* CEIL.L */
+ case 0x0b: /* FLOOR.L */
+ case 0x0c: /* ROUND.W */
+ case 0x0d: /* TRUNC.W */
+ case 0x0e: /* CEIL.W */
+ case 0x0f: /* FLOOR.W */
+ case 0x20: /* CVT.S */
+ case 0x21: /* CVT.D */
+ case 0x24: /* CVT.W */
+ case 0x25: /* CVT.L */
+ desc->fpr.used |= REGFLAG_CPR1(FSREG);
+ desc->fpr.modified |= REGFLAG_CPR1(FDREG);
+ return TRUE;
+
+ case 0x11: /* MOVT/F - MIPS IV */
+ if (mips->flavor < MIPS3_TYPE_MIPS_IV)
+ return FALSE;
+ desc->fpr.used |= REGFLAG_CPR1(FSREG) | REGFLAG_FCC;
+ desc->fpr.modified |= REGFLAG_CPR1(FDREG);
+ return TRUE;
+
+ case 0x30: case 0x38: /* C.F */
+ case 0x31: case 0x39: /* C.UN */
+ desc->fpr.modified |= REGFLAG_FCC;
+ return TRUE;
+
+ case 0x32: case 0x3a: /* C.EQ */
+ case 0x33: case 0x3b: /* C.UEQ */
+ case 0x34: case 0x3c: /* C.OLT */
+ case 0x35: case 0x3d: /* C.ULT */
+ case 0x36: case 0x3e: /* C.OLE */
+ case 0x37: case 0x3f: /* C.ULE */
+ desc->fpr.used |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG);
+ desc->fpr.modified |= REGFLAG_FCC;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_cop1x - build a
+ description of a single instruction in the
+ COP1X group
+-------------------------------------------------*/
+
+static int describe_instruction_cop1x(mips3_state *mips, UINT32 op, opcode_desc *desc)
+{
+ /* any COP1 instruction can potentially cause an exception */
+// desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+
+ switch (op & 0x3f)
+ {
+ case 0x00: /* LWXC1 */
+ case 0x01: /* LDXC1 */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->fpr.modified |= REGFLAG_CPR1(FDREG);
+ desc->flags |= OPFLAG_READS_MEMORY;
+ return TRUE;
+
+ case 0x08: /* SWXC1 */
+ case 0x09: /* SDXC1 */
+ desc->gpr.used |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
+ desc->fpr.used |= REGFLAG_CPR1(FDREG);
+ desc->flags |= OPFLAG_WRITES_MEMORY;
+ return TRUE;
+
+ case 0x0f: /* PREFX */
+ /* effective no-op */
+ return TRUE;
+
+ case 0x20: case 0x21: /* MADD */
+ case 0x28: case 0x29: /* MSUB */
+ case 0x30: case 0x31: /* NMADD */
+ case 0x38: case 0x39: /* NMSUB */
+ desc->fpr.used |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG) | REGFLAG_CPR1(FRREG);
+ desc->fpr.modified |= REGFLAG_CPR1(FDREG);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_cop2 - build a
+ description of a single instruction in the
+ COP2 group
+-------------------------------------------------*/
+
+static int describe_instruction_cop2(mips3_state *mips, UINT32 op, opcode_desc *desc)
+{
+ /* any COP2 instruction can potentially cause an exception */
+ desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */
+ case 0x01: /* DMFCz */
+ case 0x02: /* CFCz */
+ desc->gpr.modified |= REGFLAG_R(RTREG);
+ return TRUE;
+
+ case 0x04: /* MTCz */
+ case 0x05: /* DMTCz */
+ case 0x06: /* CTCz */
+ desc->gpr.used |= REGFLAG_R(RTREG);
+ return TRUE;
+
+ case 0x08: /* BC */
+ switch (RTREG)
+ {
+ case 0x00: /* BCzF */
+ case 0x01: /* BCzT */
+ desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc->targetpc = desc->pc + 4 + (SIMMVAL << 2);
+ desc->delayslots = 1;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ return FALSE;
+}
diff --git a/src/emu/cpu/mips/mips3fe.h b/src/emu/cpu/mips/mips3fe.h
new file mode 100644
index 00000000000..a6f76759e9b
--- /dev/null
+++ b/src/emu/cpu/mips/mips3fe.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+
+ mips3fe.h
+
+ Front-end for MIPS3 recompiler
+
+ Copyright (c) 2007, Aaron Giles
+ Released for general use under the MAME license
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __MIPS3FE_H__
+#define __MIPS3FE_H__
+
+#include "cpu/drcfe.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* register flags */
+#define REGFLAG_R(n) (((n) == 0) ? 0 : ((UINT64)1 << (n)))
+#define REGFLAG_LO (REGFLAG_R(REG_LO))
+#define REGFLAG_HI (REGFLAG_R(REG_HI))
+#define REGFLAG_CPR1(n) ((UINT64)1 << (n))
+#define REGFLAG_FCC (REGFLAG_CPR1(32))
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* this defines a branch targetpc that is dynamic at runtime */
+#define BRANCH_TARGET_DYNAMIC (~0)
+
+
+/* opcode branch flags */
+#define OPFLAG_IS_UNCONDITIONAL_BRANCH 0x00000001 /* instruction is unconditional branch */
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+int mips3fe_describe(void *param, opcode_desc *desc);
+
+#endif
diff --git a/src/emu/cpu/mips/mipsdasm.c b/src/emu/cpu/mips/mipsdasm.c
new file mode 100644
index 00000000000..10297b8e439
--- /dev/null
+++ b/src/emu/cpu/mips/mipsdasm.c
@@ -0,0 +1,620 @@
+/*
+ * MIPS disassembler for the MAME project written by smf
+ *
+ */
+
+#include "psx.h"
+
+static char *make_signed_hex_str_16( UINT32 value )
+{
+ static char s_hex[ 20 ];
+
+ value &= 0xffff;
+ if( value & 0x8000 )
+ {
+ sprintf( s_hex, "-$%x", ( 0 - value ) & 0x7fff );
+ }
+ else
+ {
+ sprintf( s_hex, "$%x", value & 0x7fff );
+ }
+ return s_hex;
+}
+
+static const char *s_cpugenreg[] =
+{
+ "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
+};
+
+static const char *s_cp0genreg[] =
+{
+ "Index", "Random", "EntryLo", "cp0r3", "Context", "cp0r5", "cp0r6", "cp0r7",
+ "BadVAddr", "cp0r9", "EntryHi", "cp0r11", "SR", "Cause", "EPC", "PRId",
+ "cp0r16", "cp0r17", "cp0r18", "cp0r19", "cp0r20", "cp0r21", "cp0r22", "cp0r23",
+ "cp0r24", "cp0r25", "cp0r26", "cp0r27", "cp0r28", "cp0r29", "cp0r30", "cp0r31"
+};
+
+static const char *s_cp1genreg[] =
+{
+ "cp1r0", "cp1r1", "cp1r2", "cp1r3", "cp1r4", "cp1r5", "cp1r6", "cp1r7",
+ "cp1r8", "cp1r9", "cp1r10", "cp1r11", "cp1r12", "cp1r13", "cp1r14", "cp1r15",
+ "cp1r16", "cp1r17", "cp1r18", "cp1r19", "cp1r20", "cp1r21", "cp1r22", "cp1r22",
+ "cp1r23", "cp1r24", "cp1r25", "cp1r26", "cp1r27", "cp1r28", "cp1r29", "cp1r30"
+};
+
+static const char *s_cp1ctlreg[] =
+{
+ "cp1cr0", "cp1cr1", "cp1cr2", "cp1cr3", "cp1cr4", "cp1cr5", "cp1cr6", "cp1cr7",
+ "cp1cr8", "cp1cr9", "cp1cr10", "cp1cr11", "cp1cr12", "cp1cr13", "cp1cr14", "cp1cr15",
+ "cp1cr16", "cp1cr17", "cp1cr18", "cp1cr19", "cp1cr20", "cp1cr21", "cp1cr22", "cp1cr23",
+ "cp1cr24", "cp1cr25", "cp1cr26", "cp1cr27", "cp1cr28", "cp1cr29", "cp1cr30", "cp1cr31"
+};
+
+static const char *s_cp2genreg[] =
+{
+ "vxy0", "vz0", "vxy1", "vz1", "vxy2", "vz2", "rgb", "otz",
+ "ir0", "ir1", "ir2", "ir3", "sxy0", "sxy1", "sxy2", "sxyp",
+ "sz0", "sz1", "sz2", "sz3", "rgb0", "rgb1", "rgb2", "cp2cr23",
+ "mac0", "mac1", "mac2", "mac3", "irgb", "orgb", "lzcs", "lzcr"
+};
+
+static const char *s_cp2ctlreg[] =
+{
+ "r11r12", "r13r21", "r22r23", "r31r32", "r33", "trx", "try", "trz",
+ "l11l12", "l13l21", "l22l23", "l31l32", "l33", "rbk", "gbk", "bbk",
+ "lr1lr2", "lr3lg1", "lg2lg3", "lb1lb2", "lb3", "rfc", "gfc", "bfc",
+ "ofx", "ofy", "h", "dqa", "dqb", "zsf3", "zsf4", "flag"
+};
+
+static const char *s_gtesf[] =
+{
+ "0", "12"
+};
+
+static const char *s_gtemx[] =
+{
+ "rm", "lm", "cm", "0"
+};
+
+static const char *s_gtev[] =
+{
+ "v0", "v1", "v2", "ir"
+};
+
+static const char *s_gtecv[] =
+{
+ "tr", "bk", "fc", "0"
+};
+
+static const char *s_gtelm[] =
+{
+ "0", "1"
+};
+
+static char *make_address( UINT32 pc, UINT32 op )
+{
+ static char s_address[ 20 ];
+#ifndef STANDALONE
+ if( pc == activecpu_get_pc() )
+ {
+ sprintf( s_address, "%s(%s) ; 0x%08x", make_signed_hex_str_16( INS_IMMEDIATE( op ) ), s_cpugenreg[ INS_RS( op ) ],
+ (UINT32)( activecpu_get_reg( MIPS_R0 + INS_RS( op ) ) + (INT16)INS_IMMEDIATE( op ) ) );
+ return s_address;
+ }
+#endif
+ sprintf( s_address, "%s(%s)", make_signed_hex_str_16( INS_IMMEDIATE( op ) ), s_cpugenreg[ INS_RS( op ) ] );
+ return s_address;
+}
+
+unsigned DasmMIPS( char *buffer, UINT32 pc, const UINT8 *opram )
+{
+ UINT32 op;
+ const UINT8 *oldopram;
+
+ oldopram = opram;
+ op = ( opram[ 3 ] << 24 ) | ( opram[ 2 ] << 16 ) | ( opram[ 1 ] << 8 ) | ( opram[ 0 ] << 0 );
+ opram += 4;
+
+ sprintf( buffer, "dw $%08x", op );
+
+ switch( INS_OP( op ) )
+ {
+ case OP_SPECIAL:
+ switch( INS_FUNCT( op ) )
+ {
+ case FUNCT_SLL:
+ if( op == 0 )
+ {
+ /* the standard nop is "sll zero,zero,$0000" */
+ sprintf( buffer, "nop" );
+ }
+ else
+ {
+ sprintf( buffer, "sll %s,%s,$%02x", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], INS_SHAMT( op ) );
+ }
+ break;
+ case FUNCT_SRL:
+ sprintf( buffer, "srl %s,%s,$%02x", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], INS_SHAMT( op ) );
+ break;
+ case FUNCT_SRA:
+ sprintf( buffer, "sra %s,%s,$%02x", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], INS_SHAMT( op ) );
+ break;
+ case FUNCT_SLLV:
+ sprintf( buffer, "sllv %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ] );
+ break;
+ case FUNCT_SRLV:
+ sprintf( buffer, "srlv %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ] );
+ break;
+ case FUNCT_SRAV:
+ sprintf( buffer, "srav %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ] );
+ break;
+ case FUNCT_JR:
+ if( INS_RD( op ) == 0 )
+ {
+ sprintf( buffer, "jr %s", s_cpugenreg[ INS_RS( op ) ] );
+ }
+ break;
+ case FUNCT_JALR:
+ sprintf( buffer, "jalr %s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ] );
+ break;
+ case FUNCT_SYSCALL:
+ sprintf( buffer, "syscall $%05x", INS_CODE( op ) );
+ break;
+ case FUNCT_BREAK:
+ sprintf( buffer, "break $%05x", INS_CODE( op ) );
+ break;
+ case FUNCT_MFHI:
+ sprintf( buffer, "mfhi %s", s_cpugenreg[ INS_RD( op ) ] );
+ break;
+ case FUNCT_MTHI:
+ if( INS_RD( op ) == 0 )
+ {
+ sprintf( buffer, "mthi %s", s_cpugenreg[ INS_RS( op ) ] );
+ }
+ break;
+ case FUNCT_MFLO:
+ sprintf( buffer, "mflo %s", s_cpugenreg[ INS_RD( op ) ] );
+ break;
+ case FUNCT_MTLO:
+ if( INS_RD( op ) == 0 )
+ {
+ sprintf( buffer, "mtlo %s", s_cpugenreg[ INS_RS( op ) ] );
+ }
+ break;
+ case FUNCT_MULT:
+ if( INS_RD( op ) == 0 )
+ {
+ sprintf( buffer, "mult %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ }
+ break;
+ case FUNCT_MULTU:
+ if( INS_RD( op ) == 0 )
+ {
+ sprintf( buffer, "multu %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ }
+ break;
+ case FUNCT_DIV:
+ if( INS_RD( op ) == 0 )
+ {
+ sprintf( buffer, "div %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ }
+ break;
+ case FUNCT_DIVU:
+ if( INS_RD( op ) == 0 )
+ {
+ sprintf( buffer, "divu %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ }
+ break;
+ case FUNCT_ADD:
+ sprintf( buffer, "add %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ case FUNCT_ADDU:
+ sprintf( buffer, "addu %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ case FUNCT_SUB:
+ sprintf( buffer, "sub %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ case FUNCT_SUBU:
+ sprintf( buffer, "subu %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ case FUNCT_AND:
+ sprintf( buffer, "and %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ case FUNCT_OR:
+ sprintf( buffer, "or %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ case FUNCT_XOR:
+ sprintf( buffer, "xor %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ case FUNCT_NOR:
+ sprintf( buffer, "nor %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ case FUNCT_SLT:
+ sprintf( buffer, "slt %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ case FUNCT_SLTU:
+ sprintf( buffer, "sltu %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
+ break;
+ }
+ break;
+ case OP_REGIMM:
+ switch( INS_RT( op ) )
+ {
+ case RT_BLTZ:
+ sprintf( buffer, "bltz %s,$%08x", s_cpugenreg[ INS_RS( op ) ], pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ case RT_BGEZ:
+ sprintf( buffer, "bgez %s,$%08x", s_cpugenreg[ INS_RS( op ) ], pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ case RT_BLTZAL:
+ sprintf( buffer, "bltzal %s,$%08x", s_cpugenreg[ INS_RS( op ) ], pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ case RT_BGEZAL:
+ sprintf( buffer, "bgezal %s,$%08x", s_cpugenreg[ INS_RS( op ) ], pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ }
+ break;
+ case OP_J:
+ sprintf( buffer, "j $%08x", ( ( pc + 4 ) & 0xF0000000 ) + ( INS_TARGET( op ) << 2 ) );
+ break;
+ case OP_JAL:
+ sprintf( buffer, "jal $%08x", ( ( pc + 4 ) & 0xF0000000 ) + ( INS_TARGET( op ) << 2 ) );
+ break;
+ case OP_BEQ:
+ sprintf( buffer, "beq %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ case OP_BNE:
+ sprintf( buffer, "bne %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ case OP_BLEZ:
+ if( INS_RT( op ) == 0 )
+ {
+ sprintf( buffer, "blez %s,$%08x", s_cpugenreg[ INS_RS( op ) ], pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ }
+ break;
+ case OP_BGTZ:
+ if( INS_RT( op ) == 0 )
+ {
+ sprintf( buffer, "bgtz %s,$%08x", s_cpugenreg[ INS_RS( op ) ], pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ }
+ break;
+ case OP_ADDI:
+ sprintf( buffer, "addi %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) );
+ break;
+ case OP_ADDIU:
+ sprintf( buffer, "addiu %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) );
+ break;
+ case OP_SLTI:
+ sprintf( buffer, "slti %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) );
+ break;
+ case OP_SLTIU:
+ sprintf( buffer, "sltiu %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) );
+ break;
+ case OP_ANDI:
+ sprintf( buffer, "andi %s,%s,$%04x", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], INS_IMMEDIATE( op ) );
+ break;
+ case OP_ORI:
+ sprintf( buffer, "ori %s,%s,$%04x", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], INS_IMMEDIATE( op ) );
+ break;
+ case OP_XORI:
+ sprintf( buffer, "xori %s,%s,$%04x", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], INS_IMMEDIATE( op ) );
+ break;
+ case OP_LUI:
+ sprintf( buffer, "lui %s,$%04x", s_cpugenreg[ INS_RT( op ) ], INS_IMMEDIATE( op ) );
+ break;
+ case OP_COP0:
+ switch( INS_RS( op ) )
+ {
+ case RS_MFC:
+ sprintf( buffer, "mfc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0genreg[ INS_RD( op ) ] );
+ break;
+ case RS_MTC:
+ sprintf( buffer, "mtc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0genreg[ INS_RD( op ) ] );
+ break;
+ case RS_BC:
+ switch( INS_RT( op ) )
+ {
+ case RT_BCF:
+ sprintf( buffer, "bc0f $%08x", pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ case RT_BCT:
+ sprintf( buffer, "bc0t $%08x", pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ }
+ break;
+ default:
+ switch( INS_CO( op ) )
+ {
+ case 1:
+ sprintf( buffer, "cop0 $%07x", INS_COFUN( op ) );
+
+ switch( INS_CF( op ) )
+ {
+ case 1:
+ sprintf( buffer, "tlbr" );
+ break;
+ case 4:
+ sprintf( buffer, "tlbwi" );
+ break;
+ case 6:
+ sprintf( buffer, "tlbwr" );
+ break;
+ case 8:
+ sprintf( buffer, "tlbp" );
+ break;
+ case 16:
+ sprintf( buffer, "rfe" );
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case OP_COP1:
+ switch( INS_RS( op ) )
+ {
+ case RS_MFC:
+ sprintf( buffer, "mfc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1genreg[ INS_RD( op ) ] );
+ break;
+ case RS_CFC:
+ sprintf( buffer, "cfc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1ctlreg[ INS_RD( op ) ] );
+ break;
+ case RS_MTC:
+ sprintf( buffer, "mtc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1genreg[ INS_RD( op ) ] );
+ break;
+ case RS_CTC:
+ sprintf( buffer, "ctc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1ctlreg[ INS_RD( op ) ] );
+ break;
+ case RS_BC:
+ switch( INS_RT( op ) )
+ {
+ case RT_BCF:
+ sprintf( buffer, "bc1f $%08x", pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ case RT_BCT:
+ sprintf( buffer, "bc1t $%08x", pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ }
+ break;
+ default:
+ switch( INS_CO( op ) )
+ {
+ case 1:
+ sprintf( buffer, "cop1 $%07x", INS_COFUN( op ) );
+ break;
+ }
+ break;
+ }
+ break;
+ case OP_COP2:
+ switch( INS_RS( op ) )
+ {
+ case RS_MFC:
+ sprintf( buffer, "mfc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2genreg[ INS_RD( op ) ] );
+ break;
+ case RS_CFC:
+ sprintf( buffer, "cfc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2ctlreg[ INS_RD( op ) ] );
+ break;
+ case RS_MTC:
+ sprintf( buffer, "mtc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2genreg[ INS_RD( op ) ] );
+ break;
+ case RS_CTC:
+ sprintf( buffer, "ctc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2ctlreg[ INS_RD( op ) ] );
+ break;
+ case RS_BC:
+ switch( INS_RT( op ) )
+ {
+ case RT_BCF:
+ sprintf( buffer, "bc2f $%08x", pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ case RT_BCT:
+ sprintf( buffer, "bc2t $%08x", pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ) );
+ break;
+ }
+ break;
+ default:
+ switch( INS_CO( op ) )
+ {
+ case 1:
+ sprintf( buffer, "cop2 $%07x", INS_COFUN( op ) );
+
+ switch( GTE_FUNCT( op ) )
+ {
+ case 0x01:
+ if( INS_COFUN( op ) == 0x0180001 )
+ {
+ sprintf( buffer, "rtps" );
+ }
+ break;
+ case 0x06:
+ if( INS_COFUN( op ) == 0x0400006 ||
+ INS_COFUN( op ) == 0x1400006 ||
+ INS_COFUN( op ) == 0x0155cc6 )
+ {
+ sprintf( buffer, "nclip" );
+ }
+ break;
+ case 0x0c:
+ if( GTE_OP( op ) == 0x17 )
+ {
+ sprintf( buffer, "op%s", s_gtesf[ GTE_SF( op ) ] );
+ }
+ break;
+ case 0x10:
+ if( INS_COFUN( op ) == 0x0780010 )
+ {
+ sprintf( buffer, "dpcs" );
+ }
+ break;
+ case 0x11:
+ if( INS_COFUN( op ) == 0x0980011 )
+ {
+ sprintf( buffer, "intpl" );
+ }
+ break;
+ case 0x12:
+ if( GTE_OP( op ) == 0x04 )
+ {
+ sprintf( buffer, "mvmva%s %s + %s * %s (lm=%s)",
+ s_gtesf[ GTE_SF( op ) ], s_gtecv[ GTE_CV( op ) ], s_gtemx[ GTE_MX( op ) ],
+ s_gtev[ GTE_V( op ) ], s_gtelm[ GTE_LM( op ) ] );
+ }
+ break;
+ case 0x13:
+ if( INS_COFUN( op ) == 0x0e80413 )
+ {
+ sprintf( buffer, "ncds" );
+ }
+ break;
+ case 0x14:
+ if( INS_COFUN( op ) == 0x1280414 )
+ {
+ sprintf( buffer, "cdp" );
+ }
+ break;
+ case 0x16:
+ if( INS_COFUN( op ) == 0x0f80416 )
+ {
+ sprintf( buffer, "ncdt" );
+ }
+ break;
+ case 0x1b:
+ if( INS_COFUN( op ) == 0x108041b )
+ {
+ sprintf( buffer, "nccs" );
+ }
+ break;
+ case 0x1c:
+ if( INS_COFUN( op ) == 0x138041c )
+ {
+ sprintf( buffer, "cc" );
+ }
+ break;
+ case 0x1e:
+ if( INS_COFUN( op ) == 0x0c8041e )
+ {
+ sprintf( buffer, "ncs" );
+ }
+ break;
+ case 0x20:
+ if( INS_COFUN( op ) == 0x0d80420 )
+ {
+ sprintf( buffer, "nct" );
+ }
+ break;
+ case 0x28:
+ if( GTE_OP( op ) == 0x0a && GTE_LM( op ) == 1 )
+ {
+ sprintf( buffer, "sqr%s", s_gtesf[ GTE_SF( op ) ] );
+ }
+ break;
+ case 0x29:
+ if( INS_COFUN( op ) == 0x0680029 )
+ {
+ sprintf( buffer, "dcpl" );
+ }
+ break;
+ case 0x2a:
+ if( INS_COFUN( op ) == 0x0f8002a )
+ {
+ sprintf( buffer, "dpct" );
+ }
+ break;
+ case 0x2d:
+ if( INS_COFUN( op ) == 0x158002d )
+ {
+ sprintf( buffer, "avsz3" );
+ }
+ break;
+ case 0x2e:
+ if( INS_COFUN( op ) == 0x168002e )
+ {
+ sprintf( buffer, "avsz4" );
+ }
+ break;
+ case 0x30:
+ if( INS_COFUN( op ) == 0x0280030 )
+ {
+ sprintf( buffer, "rtpt" );
+ }
+ break;
+ case 0x3d:
+ if( GTE_OP( op ) == 0x09 ||
+ GTE_OP( op ) == 0x19 )
+ {
+ sprintf( buffer, "gpf%s", s_gtesf[ GTE_SF( op ) ] );
+ }
+ break;
+ case 0x3e:
+ if( GTE_OP( op ) == 0x1a )
+ {
+ sprintf( buffer, "gpl%s", s_gtesf[ GTE_SF( op ) ] );
+ }
+ break;
+ case 0x3f:
+ if( INS_COFUN( op ) == 0x108043f ||
+ INS_COFUN( op ) == 0x118043f )
+ {
+ sprintf( buffer, "ncct" );
+ }
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case OP_LB:
+ sprintf( buffer, "lb %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_LH:
+ sprintf( buffer, "lh %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_LWL:
+ sprintf( buffer, "lwl %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_LW:
+ sprintf( buffer, "lw %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_LBU:
+ sprintf( buffer, "lbu %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_LHU:
+ sprintf( buffer, "lhu %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_LWR:
+ sprintf( buffer, "lwr %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_SB:
+ sprintf( buffer, "sb %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_SH:
+ sprintf( buffer, "sh %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_SWL:
+ sprintf( buffer, "swl %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_SW:
+ sprintf( buffer, "sw %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_SWR:
+ sprintf( buffer, "swr %s,%s", s_cpugenreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_LWC1:
+ sprintf( buffer, "lwc1 %s,%s", s_cp1genreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_LWC2:
+ sprintf( buffer, "lwc2 %s,%s", s_cp2genreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_SWC1:
+ sprintf( buffer, "swc1 %s,%s", s_cp1genreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ case OP_SWC2:
+ sprintf( buffer, "swc2 %s,%s", s_cp2genreg[ INS_RT( op ) ], make_address( pc, op ) );
+ break;
+ }
+ return ( opram - oldopram ) | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/mips/psx.c b/src/emu/cpu/mips/psx.c
new file mode 100644
index 00000000000..4b304da268f
--- /dev/null
+++ b/src/emu/cpu/mips/psx.c
@@ -0,0 +1,3645 @@
+/*
+ * Sony CXD8530AQ/CXD8530BQ/CXD8530CQ/CXD8661R
+ *
+ * PSX CPU emulator for the MAME project written by smf
+ * Thanks to Farfetch'd for information on the delay slot bug
+ *
+ * The PSX CPU is a custom r3000a with a built in
+ * geometry transform engine, no mmu & no data cache.
+ *
+ * There is a stall circuit for load delays, but
+ * it doesn't work if the load occurs in a branch
+ * delay slot.
+ *
+ */
+
+#include "ui.h"
+#include "debugger.h"
+#include "psx.h"
+#include "osd_cpu.h"
+
+#define LOG_BIOSCALL ( 0 )
+
+#define EXC_INT ( 0 )
+#define EXC_ADEL ( 4 )
+#define EXC_ADES ( 5 )
+#define EXC_SYS ( 8 )
+#define EXC_BP ( 9 )
+#define EXC_RI ( 10 )
+#define EXC_CPU ( 11 )
+#define EXC_OVF ( 12 )
+
+#define CP0_RANDOM ( 1 )
+#define CP0_BADVADDR ( 8 )
+#define CP0_SR ( 12 )
+#define CP0_CAUSE ( 13 )
+#define CP0_EPC ( 14 )
+#define CP0_PRID ( 15 )
+
+#define SR_IEC ( 1L << 0 )
+#define SR_KUC ( 1L << 1 )
+#define SR_ISC ( 1L << 16 )
+#define SR_SWC ( 1L << 17 )
+#define SR_TS ( 1L << 21 )
+#define SR_BEV ( 1L << 22 )
+#define SR_RE ( 1L << 25 )
+#define SR_CU0 ( 1L << 28 )
+#define SR_CU1 ( 1L << 29 )
+#define SR_CU2 ( 1L << 30 )
+#define SR_CU3 ( 1L << 31 )
+
+#define CAUSE_EXC ( 31L << 2 )
+#define CAUSE_IP ( 255L << 8 )
+#define CAUSE_IP2 ( 1L << 10 )
+#define CAUSE_IP3 ( 1L << 11 )
+#define CAUSE_IP4 ( 1L << 12 )
+#define CAUSE_IP5 ( 1L << 13 )
+#define CAUSE_IP6 ( 1L << 14 )
+#define CAUSE_IP7 ( 1L << 15 )
+#define CAUSE_CE ( 3L << 28 )
+#define CAUSE_CE0 ( 0L << 28 )
+#define CAUSE_CE1 ( 1L << 28 )
+#define CAUSE_CE2 ( 2L << 28 )
+#define CAUSE_BD ( 1L << 31 )
+
+static const char *delayn[] =
+{
+ "pc", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra",
+ "pc"
+};
+
+#define REGPC ( 32 )
+
+typedef struct
+{
+ UINT32 op;
+ UINT32 pc;
+ UINT32 delayv;
+ UINT32 delayr;
+ UINT32 hi;
+ UINT32 lo;
+ UINT32 r[ 32 ];
+ UINT32 cp0r[ 32 ];
+ PAIR cp2cr[ 32 ];
+ PAIR cp2dr[ 32 ];
+ int (*irq_callback)(int irqline);
+} mips_cpu_context;
+
+static mips_cpu_context mipscpu;
+
+static int mips_ICount = 0;
+
+static UINT32 mips_mtc0_writemask[]=
+{
+ 0xffffffff, /* INDEX */
+ 0x00000000, /* RANDOM */
+ 0xffffff00, /* ENTRYLO */
+ 0x00000000,
+ 0xffe00000, /* CONTEXT */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000, /* BADVADDR */
+ 0x00000000,
+ 0xffffffc0, /* ENTRYHI */
+ 0x00000000,
+ 0xf27fff3f, /* SR */
+ 0x00000300, /* CAUSE */
+ 0x00000000, /* EPC */
+ 0x00000000, /* PRID */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000
+};
+
+#if 0
+void GTELOG(const char *a,...)
+{
+ va_list va;
+ char s_text[ 1024 ];
+ va_start( va, a );
+ vsprintf( s_text, a, va );
+ va_end( va );
+ logerror( "%08x: GTE: %08x %s\n", mipscpu.pc, INS_COFUN( mipscpu.op ), s_text );
+}
+#else
+INLINE void GTELOG(const char *a, ...) {}
+#endif
+
+static UINT32 getcp2dr( int n_reg );
+static void setcp2dr( int n_reg, UINT32 n_value );
+static UINT32 getcp2cr( int n_reg );
+static void setcp2cr( int n_reg, UINT32 n_value );
+static void docop2( int gteop );
+static void mips_exception( int exception );
+
+static void mips_stop( void )
+{
+ DEBUGGER_BREAK;
+ CALL_MAME_DEBUG;
+}
+
+#if LOG_BIOSCALL
+
+static const struct
+{
+ int address;
+ int operation;
+ const char *prototype;
+} bioscalls[] =
+{
+ { 0xa0, 0x00, "int open(const char *name, int mode)" },
+ { 0xa0, 0x01, "int lseek(int fd, int offset, int whence)" },
+ { 0xa0, 0x02, "int read(int fd, void *buf, int nbytes)" },
+ { 0xa0, 0x03, "int write(int fd, void *buf, int nbytes)" },
+ { 0xa0, 0x04, "int close(int fd)" },
+ { 0xa0, 0x05, "int ioctl(int fd, int cmd, int arg)" },
+ { 0xa0, 0x06, "void exit(int code)" },
+ { 0xa0, 0x07, "sys_a0_07()" },
+ { 0xa0, 0x08, "char getc(int fd)" },
+ { 0xa0, 0x09, "void putc(char c, int fd)" },
+ { 0xa0, 0x0a, "todigit()" },
+ { 0xa0, 0x0b, "double atof(const char *s)" },
+ { 0xa0, 0x0c, "long strtoul(const char *s, char **ptr, int base)" },
+ { 0xa0, 0x0d, "unsigned long strtol(const char *s, char **ptr, int base)" },
+ { 0xa0, 0x0e, "int abs(int val)" },
+ { 0xa0, 0x0f, "long labs(long lval)" },
+ { 0xa0, 0x10, "long atoi(const char *s)" },
+ { 0xa0, 0x11, "int atol(const char *s)" },
+ { 0xa0, 0x12, "atob()" },
+ { 0xa0, 0x13, "int setjmp(jmp_buf *ctx)" },
+ { 0xa0, 0x14, "void longjmp(jmp_buf *ctx, int value)" },
+ { 0xa0, 0x15, "char *strcat(char *dst, const char *src)" },
+ { 0xa0, 0x16, "char *strncat(char *dst, const char *src, size_t n)" },
+ { 0xa0, 0x17, "int strcmp(const char *dst, const char *src)" },
+ { 0xa0, 0x18, "int strncmp(const char *dst, const char *src, size_t n)" },
+ { 0xa0, 0x19, "char *strcpy(char *dst, const char *src)" },
+ { 0xa0, 0x1a, "char *strncpy(char *dst, const char *src, size_t n)" },
+ { 0xa0, 0x1b, "size_t strlen(const char *s)" },
+ { 0xa0, 0x1c, "int index(const char *s, int c)" },
+ { 0xa0, 0x1d, "int rindex(const char *s, int c)" },
+ { 0xa0, 0x1e, "char *strchr(const char *s, int c)" },
+ { 0xa0, 0x1f, "char *strrchr(const char *s, int c)" },
+ { 0xa0, 0x20, "char *strpbrk(const char *dst, const char *src)" },
+ { 0xa0, 0x21, "size_t strspn(const char *s, const char *set)" },
+ { 0xa0, 0x22, "size_t strcspn(const char *s, const char *set)" },
+ { 0xa0, 0x23, "char *strtok(char *s, const char *set)" },
+ { 0xa0, 0x24, "char *strstr(const char *s, const char *set)" },
+ { 0xa0, 0x25, "int toupper(int c)" },
+ { 0xa0, 0x26, "int tolower(int c)" },
+ { 0xa0, 0x27, "void bcopy(const void *src, void *dst, size_t len)" },
+ { 0xa0, 0x28, "void bzero(void *ptr, size_t len)" },
+ { 0xa0, 0x29, "int bcmp(const void *ptr1, const void *ptr2, int len)" },
+ { 0xa0, 0x2a, "void *memcpy(void *dst, const void *src, size_t n)" },
+ { 0xa0, 0x2b, "void *memset(void *dst, char c, size_t n)" },
+ { 0xa0, 0x2c, "void *memmove(void *dst, const void *src, size_t n)" },
+ { 0xa0, 0x2d, "int memcmp(const void *dst, const void *src, size_t n)" },
+ { 0xa0, 0x2e, "void *memchr(const void *s, int c, size_t n)" },
+ { 0xa0, 0x2f, "int rand()" },
+ { 0xa0, 0x30, "void srand(unsigned int seed)" },
+ { 0xa0, 0x31, "void qsort(void *base, int nel, int width, int (*cmp)(void *, void *))" },
+ { 0xa0, 0x32, "double strtod(const char *s, char **endptr)" },
+ { 0xa0, 0x33, "void *malloc(int size)" },
+ { 0xa0, 0x34, "void free(void *buf)" },
+ { 0xa0, 0x35, "void *lsearch(void *key, void *base, int belp, int width, int (*cmp)(void *, void *))" },
+ { 0xa0, 0x36, "void *bsearch(void *key, void *base, int nel, int size, int (*cmp)(void *, void *))" },
+ { 0xa0, 0x37, "void *calloc(int size, int n)" },
+ { 0xa0, 0x38, "void *realloc(void *buf, int n)" },
+ { 0xa0, 0x39, "InitHeap(void *block, int size)" },
+ { 0xa0, 0x3a, "void _exit(int code)" },
+ { 0xa0, 0x3b, "char getchar(void)" },
+ { 0xa0, 0x3c, "void putchar(char c)" },
+ { 0xa0, 0x3d, "char *gets(char *s)" },
+ { 0xa0, 0x3e, "void puts(const char *s)" },
+ { 0xa0, 0x3f, "int printf(const char *fmt, ...)" },
+ { 0xa0, 0x40, "sys_a0_40()" },
+ { 0xa0, 0x41, "int LoadTest(const char *name, struct EXEC *header)" },
+ { 0xa0, 0x42, "int Load(const char *name, struct EXEC *header)" },
+ { 0xa0, 0x43, "int Exec(struct EXEC *header, int argc, char **argv)" },
+ { 0xa0, 0x44, "void FlushCache()" },
+ { 0xa0, 0x45, "void InstallInterruptHandler()" },
+ { 0xa0, 0x46, "GPU_dw(int x, int y, int w, int h, long *data)" },
+ { 0xa0, 0x47, "mem2vram(int x, int y, int w, int h, long *data)" },
+ { 0xa0, 0x48, "SendGPU(int status)" },
+ { 0xa0, 0x49, "GPU_cw(long cw)" },
+ { 0xa0, 0x4a, "GPU_cwb(long *pkt, int len)" },
+ { 0xa0, 0x4b, "SendPackets(void *ptr)" },
+ { 0xa0, 0x4c, "sys_a0_4c()" },
+ { 0xa0, 0x4d, "int GetGPUStatus()" },
+ { 0xa0, 0x4e, "GPU_sync()" },
+ { 0xa0, 0x4f, "sys_a0_4f()" },
+ { 0xa0, 0x50, "sys_a0_50()" },
+ { 0xa0, 0x51, "int LoadExec(const char *name, int, int)" },
+ { 0xa0, 0x52, "GetSysSp()" },
+ { 0xa0, 0x53, "sys_a0_53()" },
+ { 0xa0, 0x54, "_96_init()" },
+ { 0xa0, 0x55, "_bu_init()" },
+ { 0xa0, 0x56, "_96_remove()" },
+ { 0xa0, 0x57, "sys_a0_57()" },
+ { 0xa0, 0x58, "sys_a0_58()" },
+ { 0xa0, 0x59, "sys_a0_59()" },
+ { 0xa0, 0x5a, "sys_a0_5a()" },
+ { 0xa0, 0x5b, "dev_tty_init()" },
+ { 0xa0, 0x5c, "dev_tty_open()" },
+ { 0xa0, 0x5d, "dev_tty_5d()" },
+ { 0xa0, 0x5e, "dev_tty_ioctl()" },
+ { 0xa0, 0x5f, "dev_cd_open()" },
+ { 0xa0, 0x60, "dev_cd_read()" },
+ { 0xa0, 0x61, "dev_cd_close()" },
+ { 0xa0, 0x62, "dev_cd_firstfile()" },
+ { 0xa0, 0x63, "dev_cd_nextfile()" },
+ { 0xa0, 0x64, "dev_cd_chdir()" },
+ { 0xa0, 0x65, "dev_card_open()" },
+ { 0xa0, 0x66, "dev_card_read()" },
+ { 0xa0, 0x67, "dev_card_write()" },
+ { 0xa0, 0x68, "dev_card_close()" },
+ { 0xa0, 0x69, "dev_card_firstfile()" },
+ { 0xa0, 0x6a, "dev_card_nextfile()" },
+ { 0xa0, 0x6b, "dev_card_erase()" },
+ { 0xa0, 0x6c, "dev_card_undelete()" },
+ { 0xa0, 0x6d, "dev_card_format()" },
+ { 0xa0, 0x6e, "dev_card_rename()" },
+ { 0xa0, 0x6f, "dev_card_6f()" },
+ { 0xa0, 0x70, "_bu_init()" },
+ { 0xa0, 0x71, "_96_init()" },
+ { 0xa0, 0x72, "_96_remove()" },
+ { 0xa0, 0x73, "sys_a0_73()" },
+ { 0xa0, 0x74, "sys_a0_74()" },
+ { 0xa0, 0x75, "sys_a0_75()" },
+ { 0xa0, 0x76, "sys_a0_76()" },
+ { 0xa0, 0x77, "sys_a0_77()" },
+ { 0xa0, 0x78, "_96_CdSeekL()" },
+ { 0xa0, 0x79, "sys_a0_79()" },
+ { 0xa0, 0x7a, "sys_a0_7a()" },
+ { 0xa0, 0x7b, "sys_a0_7b()" },
+ { 0xa0, 0x7c, "_96_CdGetStatus()" },
+ { 0xa0, 0x7d, "sys_a0_7d()" },
+ { 0xa0, 0x7e, "_96_CdRead()" },
+ { 0xa0, 0x7f, "sys_a0_7f()" },
+ { 0xa0, 0x80, "sys_a0_80()" },
+ { 0xa0, 0x81, "sys_a0_81()" },
+ { 0xa0, 0x82, "sys_a0_82()" },
+ { 0xa0, 0x83, "sys_a0_83()" },
+ { 0xa0, 0x84, "sys_a0_84()" },
+ { 0xa0, 0x85, "_96_CdStop()" },
+ { 0xa0, 0x84, "sys_a0_84()" },
+ { 0xa0, 0x85, "sys_a0_85()" },
+ { 0xa0, 0x86, "sys_a0_86()" },
+ { 0xa0, 0x87, "sys_a0_87()" },
+ { 0xa0, 0x88, "sys_a0_88()" },
+ { 0xa0, 0x89, "sys_a0_89()" },
+ { 0xa0, 0x8a, "sys_a0_8a()" },
+ { 0xa0, 0x8b, "sys_a0_8b()" },
+ { 0xa0, 0x8c, "sys_a0_8c()" },
+ { 0xa0, 0x8d, "sys_a0_8d()" },
+ { 0xa0, 0x8e, "sys_a0_8e()" },
+ { 0xa0, 0x8f, "sys_a0_8f()" },
+ { 0xa0, 0x90, "sys_a0_90()" },
+ { 0xa0, 0x91, "sys_a0_91()" },
+ { 0xa0, 0x92, "sys_a0_92()" },
+ { 0xa0, 0x93, "sys_a0_93()" },
+ { 0xa0, 0x94, "sys_a0_94()" },
+ { 0xa0, 0x95, "sys_a0_95()" },
+ { 0xa0, 0x96, "AddCDROMDevice()" },
+ { 0xa0, 0x97, "AddMemCardDevice()" },
+ { 0xa0, 0x98, "DisableKernelIORedirection()" },
+ { 0xa0, 0x99, "EnableKernelIORedirection()" },
+ { 0xa0, 0x9a, "sys_a0_9a()" },
+ { 0xa0, 0x9b, "sys_a0_9b()" },
+ { 0xa0, 0x9c, "void SetConf(int Event, int TCB, int Stack)" },
+ { 0xa0, 0x9d, "void GetConf(int *Event, int *TCB, int *Stack)" },
+ { 0xa0, 0x9e, "sys_a0_9e()" },
+ { 0xa0, 0x9f, "void SetMem(int size)" },
+ { 0xa0, 0xa0, "_boot()" },
+ { 0xa0, 0xa1, "SystemError()" },
+ { 0xa0, 0xa2, "EnqueueCdIntr()" },
+ { 0xa0, 0xa3, "DequeueCdIntr()" },
+ { 0xa0, 0xa4, "sys_a0_a4()" },
+ { 0xa0, 0xa5, "ReadSector(int count, int sector, void *buffer)" },
+ { 0xa0, 0xa6, "get_cd_status()" },
+ { 0xa0, 0xa7, "bufs_cb_0()" },
+ { 0xa0, 0xa8, "bufs_cb_1()" },
+ { 0xa0, 0xa9, "bufs_cb_2()" },
+ { 0xa0, 0xaa, "bufs_cb_3()" },
+ { 0xa0, 0xab, "_card_info()" },
+ { 0xa0, 0xac, "_card_load()" },
+ { 0xa0, 0xad, "_card_auto()" },
+ { 0xa0, 0xae, "bufs_cb_4()" },
+ { 0xa0, 0xaf, "sys_a0_af()" },
+ { 0xa0, 0xb0, "sys_a0_b0()" },
+ { 0xa0, 0xb1, "sys_a0_b1()" },
+ { 0xa0, 0xb2, "do_a_long_jmp()" },
+ { 0xa0, 0xb3, "sys_a0_b3()" },
+ { 0xa0, 0xb4, "GetKernelInfo(int sub_function)" },
+ { 0xb0, 0x00, "SysMalloc()" },
+ { 0xb0, 0x01, "sys_b0_01()" },
+ { 0xb0, 0x02, "sys_b0_02()" },
+ { 0xb0, 0x03, "sys_b0_03()" },
+ { 0xb0, 0x04, "sys_b0_04()" },
+ { 0xb0, 0x05, "sys_b0_05()" },
+ { 0xb0, 0x06, "sys_b0_06()" },
+ { 0xb0, 0x07, "void DeliverEvent(u_long class, u_long event)" },
+ { 0xb0, 0x08, "long OpenEvent(u_long class, long spec, long mode, long (*func)())" },
+ { 0xb0, 0x09, "long CloseEvent(long event)" },
+ { 0xb0, 0x0a, "long WaitEvent(long event)" },
+ { 0xb0, 0x0b, "long TestEvent(long event)" },
+ { 0xb0, 0x0c, "long EnableEvent(long event)" },
+ { 0xb0, 0x0d, "long DisableEvent(long event)" },
+ { 0xb0, 0x0e, "OpenTh()" },
+ { 0xb0, 0x0f, "CloseTh()" },
+ { 0xb0, 0x10, "ChangeTh()" },
+ { 0xb0, 0x11, "sys_b0_11()" },
+ { 0xb0, 0x12, "int InitPAD(char *buf1, int len1, char *buf2, int len2)" },
+ { 0xb0, 0x13, "int StartPAD(void)" },
+ { 0xb0, 0x14, "int StopPAD(void)" },
+ { 0xb0, 0x15, "PAD_init(u_long nazo, u_long *pad_buf)" },
+ { 0xb0, 0x16, "u_long PAD_dr()" },
+ { 0xb0, 0x17, "void ReturnFromException(void)" },
+ { 0xb0, 0x18, "ResetEntryInt()" },
+ { 0xb0, 0x19, "HookEntryInt()" },
+ { 0xb0, 0x1a, "sys_b0_1a()" },
+ { 0xb0, 0x1b, "sys_b0_1b()" },
+ { 0xb0, 0x1c, "sys_b0_1c()" },
+ { 0xb0, 0x1d, "sys_b0_1d()" },
+ { 0xb0, 0x1e, "sys_b0_1e()" },
+ { 0xb0, 0x1f, "sys_b0_1f()" },
+ { 0xb0, 0x20, "UnDeliverEvent(int class, int event)" },
+ { 0xb0, 0x21, "sys_b0_21()" },
+ { 0xb0, 0x22, "sys_b0_22()" },
+ { 0xb0, 0x23, "sys_b0_23()" },
+ { 0xb0, 0x24, "sys_b0_24()" },
+ { 0xb0, 0x25, "sys_b0_25()" },
+ { 0xb0, 0x26, "sys_b0_26()" },
+ { 0xb0, 0x27, "sys_b0_27()" },
+ { 0xb0, 0x28, "sys_b0_28()" },
+ { 0xb0, 0x29, "sys_b0_29()" },
+ { 0xb0, 0x2a, "sys_b0_2a()" },
+ { 0xb0, 0x2b, "sys_b0_2b()" },
+ { 0xb0, 0x2c, "sys_b0_2c()" },
+ { 0xb0, 0x2d, "sys_b0_2d()" },
+ { 0xb0, 0x2e, "sys_b0_2e()" },
+ { 0xb0, 0x2f, "sys_b0_2f()" },
+ { 0xb0, 0x2f, "sys_b0_30()" },
+ { 0xb0, 0x31, "sys_b0_31()" },
+ { 0xb0, 0x32, "int open(const char *name, int access)" },
+ { 0xb0, 0x33, "int lseek(int fd, long pos, int seektype)" },
+ { 0xb0, 0x34, "int read(int fd, void *buf, int nbytes)" },
+ { 0xb0, 0x35, "int write(int fd, void *buf, int nbytes)" },
+ { 0xb0, 0x36, "close(int fd)" },
+ { 0xb0, 0x37, "int ioctl(int fd, int cmd, int arg)" },
+ { 0xb0, 0x38, "exit(int exitcode)" },
+ { 0xb0, 0x39, "sys_b0_39()" },
+ { 0xb0, 0x3a, "char getc(int fd)" },
+ { 0xb0, 0x3b, "putc(int fd, char ch)" },
+ { 0xb0, 0x3c, "char getchar(void)" },
+ { 0xb0, 0x3d, "putchar(char ch)" },
+ { 0xb0, 0x3e, "char *gets(char *s)" },
+ { 0xb0, 0x3f, "puts(const char *s)" },
+ { 0xb0, 0x40, "int cd(const char *path)" },
+ { 0xb0, 0x41, "int format(const char *fs)" },
+ { 0xb0, 0x42, "struct DIRENTRY* firstfile(const char *name, struct DIRENTRY *dir)" },
+ { 0xb0, 0x43, "struct DIRENTRY* nextfile(struct DIRENTRY *dir)" },
+ { 0xb0, 0x44, "int rename(const char *oldname, const char *newname)" },
+ { 0xb0, 0x45, "int delete(const char *name)" },
+ { 0xb0, 0x46, "undelete()" },
+ { 0xb0, 0x47, "AddDevice()" },
+ { 0xb0, 0x48, "RemoveDevice()" },
+ { 0xb0, 0x49, "PrintInstalledDevices()" },
+ { 0xb0, 0x4a, "InitCARD()" },
+ { 0xb0, 0x4b, "StartCARD()" },
+ { 0xb0, 0x4c, "StopCARD()" },
+ { 0xb0, 0x4d, "sys_b0_4d()" },
+ { 0xb0, 0x4e, "_card_write()" },
+ { 0xb0, 0x4f, "_card_read()" },
+ { 0xb0, 0x50, "_new_card()" },
+ { 0xb0, 0x51, "void *Krom2RawAdd(int code)" },
+ { 0xb0, 0x52, "sys_b0_52()" },
+ { 0xb0, 0x53, "sys_b0_53()" },
+ { 0xb0, 0x54, "long _get_errno(void)" },
+ { 0xb0, 0x55, "long _get_error(long fd)" },
+ { 0xb0, 0x56, "GetC0Table()" },
+ { 0xb0, 0x57, "GetB0Table()" },
+ { 0xb0, 0x58, "_card_chan()" },
+ { 0xb0, 0x59, "sys_b0_59()" },
+ { 0xb0, 0x5a, "sys_b0_5a()" },
+ { 0xb0, 0x5b, "ChangeClearPAD(int, int)" },
+ { 0xb0, 0x5c, "_card_status()" },
+ { 0xb0, 0x5d, "_card_wait()" },
+ { 0xc0, 0x00, "InitRCnt()" },
+ { 0xc0, 0x01, "InitException()" },
+ { 0xc0, 0x02, "SysEnqIntRP(int index, long *queue)" },
+ { 0xc0, 0x03, "SysDeqIntRP(int index, long *queue)" },
+ { 0xc0, 0x04, "int get_free_EvCB_slot(void)" },
+ { 0xc0, 0x05, "get_free_TCB_slot()" },
+ { 0xc0, 0x06, "ExceptionHandler()" },
+ { 0xc0, 0x07, "InstallExceptionHandlers()" },
+ { 0xc0, 0x08, "SysInitMemory()" },
+ { 0xc0, 0x09, "SysInitKMem()" },
+ { 0xc0, 0x0a, "ChangeClearRCnt()" },
+ { 0xc0, 0x0b, "SystemError()" },
+ { 0xc0, 0x0c, "InitDefInt()" },
+ { 0xc0, 0x0d, "sys_c0_0d()" },
+ { 0xc0, 0x0e, "sys_c0_0e()" },
+ { 0xc0, 0x0f, "sys_c0_0f()" },
+ { 0xc0, 0x10, "sys_c0_10()" },
+ { 0xc0, 0x11, "sys_c0_11()" },
+ { 0xc0, 0x12, "InstallDevices()" },
+ { 0xc0, 0x13, "FlushStdInOutPut()" },
+ { 0xc0, 0x14, "sys_c0_14()" },
+ { 0xc0, 0x15, "_cdevinput()" },
+ { 0xc0, 0x16, "_cdevscan()" },
+ { 0xc0, 0x17, "char _circgetc(struct device_buf *circ)" },
+ { 0xc0, 0x18, "_circputc(char c, struct device_buf *circ)" },
+ { 0xc0, 0x19, "ioabort(const char *str)" },
+ { 0xc0, 0x1a, "sys_c0_1a()" },
+ { 0xc0, 0x1b, "KernelRedirect(int flag)" },
+ { 0xc0, 0x1c, "PatchA0Table()" },
+ { 0x00, 0x00, NULL }
+};
+
+static UINT32 log_bioscall_parameter( int parm )
+{
+ if( parm < 4 )
+ {
+ return activecpu_get_reg( MIPS_R4 + parm );
+ }
+ else
+ {
+ return program_read_dword_32le( activecpu_get_reg( MIPS_R29 ) + ( parm * 4 ) );
+ }
+}
+
+static const char *log_bioscall_string( int parm )
+{
+ int pos;
+ UINT32 address;
+ static char string[ 1024 ];
+
+ address = log_bioscall_parameter( parm );
+ if( address == 0 )
+ {
+ return "NULL";
+ }
+
+ pos = 0;
+ string[ pos++ ] = '\"';
+
+ for( ;; )
+ {
+ UINT8 c = program_read_byte_32le( address );
+ if( c == 0 )
+ {
+ break;
+ }
+ else if( c == '\t' )
+ {
+ string[ pos++ ] = '\\';
+ string[ pos++ ] = 't';
+ }
+ else if( c == '\r' )
+ {
+ string[ pos++ ] = '\\';
+ string[ pos++ ] = 'r';
+ }
+ else if( c == '\n' )
+ {
+ string[ pos++ ] = '\\';
+ string[ pos++ ] = 'n';
+ }
+ else if( c < 32 || c > 127 )
+ {
+ string[ pos++ ] = '\\';
+ string[ pos++ ] = ( ( c / 64 ) % 8 ) + '0';
+ string[ pos++ ] = ( ( c / 8 ) % 8 ) + '0';
+ string[ pos++ ] = ( ( c / 1 ) % 8 ) + '0';
+ }
+ else
+ {
+ string[ pos++ ] = c;
+ }
+ address++;
+ }
+
+ string[ pos++ ] = '\"';
+ string[ pos++ ] = 0;
+
+ return string;
+}
+
+static const char *log_bioscall_hex( int parm )
+{
+ static char string[ 1024 ];
+
+ sprintf( string, "0x%08x", log_bioscall_parameter( parm ) );
+
+ return string;
+}
+
+static const char *log_bioscall_char( int parm )
+{
+ int c;
+ static char string[ 1024 ];
+
+ c = log_bioscall_parameter( parm );
+ if( c < 32 || c > 127 )
+ {
+ sprintf( string, "0x%02x", c );
+ }
+ else
+ {
+ sprintf( string, "'%c'", c );
+ }
+
+ return string;
+}
+
+static void log_bioscall( void )
+{
+ int address = activecpu_get_reg( MIPS_PC ) - 0x04;
+ if( address == 0xa0 ||
+ address == 0xb0 ||
+ address == 0xc0 )
+ {
+ char buf[ 1024 ];
+ int operation = activecpu_get_reg( MIPS_R9 ) & 0xff;
+ int bioscall = 0;
+
+ if( ( address == 0xa0 && operation == 0x3c ) ||
+ ( address == 0xb0 && operation == 0x3d ) )
+ {
+ putchar( log_bioscall_parameter( 0 ) );
+ }
+
+ if( ( address == 0xa0 && operation == 0x03 ) ||
+ ( address == 0xb0 && operation == 0x35 ) )
+ {
+ int fd = log_bioscall_parameter( 0 );
+ int buf = log_bioscall_parameter( 1 );
+ int nbytes = log_bioscall_parameter( 2 );
+ if( fd == 1 )
+ {
+ while( nbytes > 0 )
+ {
+ UINT8 c = program_read_byte_32le( buf );
+ putchar( c );
+ nbytes--;
+ buf++;
+ }
+ }
+ }
+
+ while( bioscalls[ bioscall ].prototype != NULL &&
+ ( bioscalls[ bioscall ].address != address ||
+ bioscalls[ bioscall ].operation != operation ) )
+ {
+ bioscall++;
+ }
+
+ if( bioscalls[ bioscall ].prototype != NULL )
+ {
+ const char *prototype = bioscalls[ bioscall ].prototype;
+ const char *parmstart = NULL;
+ int parm = 0;
+ int parmlen = -1;
+ int brackets = 0;
+ int pos = 0;
+
+ while( *( prototype ) != 0 )
+ {
+ int ch = *( prototype );
+ switch( ch )
+ {
+ case '(':
+ brackets++;
+ prototype++;
+ if( brackets == 1 )
+ {
+ buf[ pos++ ] = ch;
+ parmstart = prototype;
+ }
+ break;
+ case ')':
+ if( brackets == 1 )
+ {
+ parmlen = prototype - parmstart;
+ }
+ prototype++;
+ brackets--;
+ break;
+ case ',':
+ if( brackets == 1 )
+ {
+ parmlen = prototype - parmstart;
+ }
+ prototype++;
+ break;
+ default:
+ if( brackets == 0 )
+ {
+ buf[ pos++ ] = ch;
+ }
+ prototype++;
+ break;
+ }
+
+ if( parmlen >= 0 )
+ {
+ while( parmlen > 0 && parmstart[ 0 ] == ' ' )
+ {
+ parmstart++;
+ parmlen--;
+ }
+ while( parmlen > 0 && parmstart[ parmlen - 1 ] == ' ' )
+ {
+ parmlen--;
+ }
+
+ if( parmlen == 0 ||
+ ( parmlen == 4 && memcmp( parmstart, "void", 4 ) == 0 ) )
+ {
+ parm = -1;
+ }
+ else if( parmlen == 3 && memcmp( parmstart, "...", 3 ) == 0 )
+ {
+ if( parm > 0 )
+ {
+ UINT32 format = log_bioscall_parameter( parm - 1 );
+ const char *parmstr = NULL;
+ int percent = 0;
+ for( ;; )
+ {
+ UINT8 c = program_read_byte_32le( format );
+ if( c == 0 )
+ {
+ break;
+ }
+ if( percent == 0 )
+ {
+ if( c == '%' )
+ {
+ percent = 1;
+ }
+ }
+ else
+ {
+ if( c == '%' )
+ {
+ percent = 0;
+ }
+ else if( c == '*' )
+ {
+ parmstr = log_bioscall_hex( parm );
+ }
+ else if( c == 's' )
+ {
+ parmstr = log_bioscall_string( parm );
+ percent = 0;
+ }
+ else if( c == 'c' )
+ {
+ parmstr = log_bioscall_char( parm );
+ percent = 0;
+ }
+ else if( c != '-' && c != '.' && c != 'l' && ( c < '0' || c > '9' ) )
+ {
+ parmstr = log_bioscall_hex( parm );
+ percent = 0;
+ }
+ }
+
+ if( parmstr != NULL )
+ {
+ if( parm > 0 )
+ {
+ buf[ pos++ ] = ',';
+ }
+ buf[ pos++ ] = ' ';
+
+ strcpy( &buf[ pos ], parmstr );
+ pos += strlen( parmstr );
+ parmstr = NULL;
+
+ parm++;
+ }
+ format++;
+ }
+ }
+ }
+ else if( parmlen > 0 )
+ {
+ const char *parmstr;
+
+ int typelen = parmlen;
+ while( typelen > 0 && parmstart[ typelen - 1 ] != ' ' && parmstart[ typelen - 1 ] != '*' )
+ {
+ typelen--;
+ }
+
+ if( typelen == 5 && memcmp( parmstart, "char ", 5 ) == 0 )
+ {
+ parmstr = log_bioscall_char( parm );
+ }
+ else if( typelen == 12 && memcmp( parmstart, "const char *", 12 ) == 0 )
+ {
+ parmstr = log_bioscall_string( parm );
+ }
+ else
+ {
+ parmstr = log_bioscall_hex( parm );
+ }
+
+ if( parm > 0 )
+ {
+ buf[ pos++ ] = ',';
+ }
+ buf[ pos++ ] = ' ';
+
+ strcpy( &buf[ pos ], parmstr );
+ pos += strlen( parmstr );
+ }
+
+ parmlen = -1;
+ parm++;
+
+ if( ch == ',' )
+ {
+ parmstart = prototype;
+ }
+ else
+ {
+ if( parm > 0 )
+ {
+ buf[ pos++ ] = ' ';
+ }
+ buf[ pos++ ] = ch;
+ }
+ }
+ }
+ buf[ pos ] = 0;
+ }
+ else
+ {
+ sprintf( buf, "unknown_%02x_%02x", address, operation );
+ }
+ logerror( "%08x: bioscall %s\n", (unsigned int)activecpu_get_reg( MIPS_R31 ) - 8, buf );
+ }
+}
+
+static void log_syscall( void )
+{
+ char buf[ 1024 ];
+ int operation = activecpu_get_reg( MIPS_R4 );
+ switch( operation )
+ {
+ case 0:
+ strcpy( buf, "void Exception()" );
+ break;
+ case 1:
+ strcpy( buf, "void EnterCriticalSection()" );
+ break;
+ case 2:
+ strcpy( buf, "void ExitCriticalSection()" );
+ break;
+ default:
+ sprintf( buf, "unknown_%02x", operation );
+ break;
+ }
+ logerror( "%08x: syscall %s\n", (unsigned int)activecpu_get_reg( MIPS_R31 ) - 8, buf );
+}
+
+#endif
+
+INLINE void mips_set_cp0r( int reg, UINT32 value )
+{
+ mipscpu.cp0r[ reg ] = value;
+ if( reg == CP0_SR || reg == CP0_CAUSE )
+ {
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_IEC ) != 0 && ( mipscpu.cp0r[ CP0_SR ] & mipscpu.cp0r[ CP0_CAUSE ] & CAUSE_IP ) != 0 )
+ {
+ mips_exception( EXC_INT );
+ }
+ else if( mipscpu.delayr != REGPC && ( mipscpu.pc & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 3 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, mipscpu.pc );
+ }
+ }
+}
+
+INLINE void mips_commit_delayed_load( void )
+{
+ if( mipscpu.delayr != 0 )
+ {
+ mipscpu.r[ mipscpu.delayr ] = mipscpu.delayv;
+ mipscpu.delayr = 0;
+ mipscpu.delayv = 0;
+ }
+}
+
+INLINE void mips_delayed_branch( UINT32 n_adr )
+{
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 3 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else if( mipscpu.delayr == REGPC )
+ {
+ mipscpu.pc = mipscpu.delayv;
+ change_pc( mipscpu.delayv );
+ mipscpu.delayv = n_adr;
+ }
+ else
+ {
+ mips_commit_delayed_load();
+ mipscpu.delayr = REGPC;
+ mipscpu.delayv = n_adr;
+ mipscpu.pc += 4;
+ }
+}
+
+INLINE void mips_set_pc( unsigned val )
+{
+ mipscpu.pc = val;
+
+ change_pc( val );
+ mipscpu.delayr = 0;
+ mipscpu.delayv = 0;
+}
+
+INLINE void mips_advance_pc( void )
+{
+ if( mipscpu.delayr == REGPC )
+ {
+ mips_set_pc( mipscpu.delayv );
+ }
+ else
+ {
+ mips_commit_delayed_load();
+ mipscpu.pc += 4;
+ }
+}
+
+INLINE void mips_load( UINT32 n_r, UINT32 n_v )
+{
+ mips_advance_pc();
+ if( n_r != 0 )
+ {
+ mipscpu.r[ n_r ] = n_v;
+ }
+}
+
+INLINE void mips_delayed_load( UINT32 n_r, UINT32 n_v )
+{
+ if( mipscpu.delayr == REGPC )
+ {
+ mips_set_pc( mipscpu.delayv );
+ mipscpu.delayr = n_r;
+ mipscpu.delayv = n_v;
+ }
+ else
+ {
+ mips_commit_delayed_load();
+ mipscpu.pc += 4;
+ if( n_r != 0 )
+ {
+ mipscpu.r[ n_r ] = n_v;
+ }
+ }
+}
+
+static void mips_exception( int exception )
+{
+ mips_set_cp0r( CP0_SR, ( mipscpu.cp0r[ CP0_SR ] & ~0x3f ) | ( ( mipscpu.cp0r[ CP0_SR ] << 2 ) & 0x3f ) );
+ if( mipscpu.delayr == REGPC )
+ {
+ mips_set_cp0r( CP0_EPC, mipscpu.pc - 4 );
+ mips_set_cp0r( CP0_CAUSE, ( mipscpu.cp0r[ CP0_CAUSE ] & ~CAUSE_EXC ) | CAUSE_BD | ( exception << 2 ) );
+ }
+ else
+ {
+ mips_commit_delayed_load();
+ mips_set_cp0r( CP0_EPC, mipscpu.pc );
+ mips_set_cp0r( CP0_CAUSE, ( mipscpu.cp0r[ CP0_CAUSE ] & ~( CAUSE_EXC | CAUSE_BD ) ) | ( exception << 2 ) );
+ }
+ if( mipscpu.cp0r[ CP0_SR ] & SR_BEV )
+ {
+ mips_set_pc( 0xbfc00180 );
+ }
+ else
+ {
+ mips_set_pc( 0x80000080 );
+ }
+}
+
+static void mips_init( int index, int clock, const void *config, int (*irqcallback)(int) )
+{
+ mipscpu.irq_callback = irqcallback;
+
+ state_save_register_item( "psxcpu", index, mipscpu.op );
+ state_save_register_item( "psxcpu", index, mipscpu.pc );
+ state_save_register_item( "psxcpu", index, mipscpu.delayv );
+ state_save_register_item( "psxcpu", index, mipscpu.delayr );
+ state_save_register_item( "psxcpu", index, mipscpu.hi );
+ state_save_register_item( "psxcpu", index, mipscpu.lo );
+ state_save_register_item_array( "psxcpu", index, mipscpu.r );
+ state_save_register_item_array( "psxcpu", index, mipscpu.cp0r );
+ state_save_register_item_array( "psxcpu", index, mipscpu.cp2cr );
+ state_save_register_item_array( "psxcpu", index, mipscpu.cp2dr );
+}
+
+static void mips_reset( void )
+{
+ mips_set_cp0r( CP0_SR, ( mipscpu.cp0r[ CP0_SR ] & ~( SR_TS | SR_SWC | SR_KUC | SR_IEC ) ) | SR_BEV );
+ mips_set_cp0r( CP0_RANDOM, 63 ); /* todo: */
+ mips_set_cp0r( CP0_PRID, 0x00000200 ); /* todo: */
+ mips_set_pc( 0xbfc00000 );
+}
+
+static void mips_exit( void )
+{
+}
+
+static int mips_execute( int cycles )
+{
+ UINT32 n_res;
+
+ mips_ICount = cycles;
+ do
+ {
+#if LOG_BIOSCALL
+ log_bioscall();
+#endif
+
+ CALL_MAME_DEBUG;
+
+ mipscpu.op = cpu_readop32( mipscpu.pc );
+ switch( INS_OP( mipscpu.op ) )
+ {
+ case OP_SPECIAL:
+ switch( INS_FUNCT( mipscpu.op ) )
+ {
+ case FUNCT_SLL:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RT( mipscpu.op ) ] << INS_SHAMT( mipscpu.op ) );
+ break;
+ case FUNCT_SRL:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RT( mipscpu.op ) ] >> INS_SHAMT( mipscpu.op ) );
+ break;
+ case FUNCT_SRA:
+ mips_load( INS_RD( mipscpu.op ), (INT32)mipscpu.r[ INS_RT( mipscpu.op ) ] >> INS_SHAMT( mipscpu.op ) );
+ break;
+ case FUNCT_SLLV:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RT( mipscpu.op ) ] << ( mipscpu.r[ INS_RS( mipscpu.op ) ] & 31 ) );
+ break;
+ case FUNCT_SRLV:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RT( mipscpu.op ) ] >> ( mipscpu.r[ INS_RS( mipscpu.op ) ] & 31 ) );
+ break;
+ case FUNCT_SRAV:
+ mips_load( INS_RD( mipscpu.op ), (INT32)mipscpu.r[ INS_RT( mipscpu.op ) ] >> ( mipscpu.r[ INS_RS( mipscpu.op ) ] & 31 ) );
+ break;
+ case FUNCT_JR:
+ if( INS_RD( mipscpu.op ) != 0 )
+ {
+ mips_exception( EXC_RI );
+ }
+ else
+ {
+ mips_delayed_branch( mipscpu.r[ INS_RS( mipscpu.op ) ] );
+ }
+ break;
+ case FUNCT_JALR:
+ n_res = mipscpu.pc + 8;
+ mips_delayed_branch( mipscpu.r[ INS_RS( mipscpu.op ) ] );
+ if( INS_RD( mipscpu.op ) != 0 )
+ {
+ mipscpu.r[ INS_RD( mipscpu.op ) ] = n_res;
+ }
+ break;
+ case FUNCT_SYSCALL:
+#if LOG_BIOSCALL
+ log_syscall();
+#endif
+ mips_exception( EXC_SYS );
+ break;
+ case FUNCT_BREAK:
+ mips_exception( EXC_BP );
+ break;
+ case FUNCT_MFHI:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.hi );
+ break;
+ case FUNCT_MTHI:
+ if( INS_RD( mipscpu.op ) != 0 )
+ {
+ mips_exception( EXC_RI );
+ }
+ else
+ {
+ mips_advance_pc();
+ mipscpu.hi = mipscpu.r[ INS_RS( mipscpu.op ) ];
+ }
+ break;
+ case FUNCT_MFLO:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.lo );
+ break;
+ case FUNCT_MTLO:
+ if( INS_RD( mipscpu.op ) != 0 )
+ {
+ mips_exception( EXC_RI );
+ }
+ else
+ {
+ mips_advance_pc();
+ mipscpu.lo = mipscpu.r[ INS_RS( mipscpu.op ) ];
+ }
+ break;
+ case FUNCT_MULT:
+ if( INS_RD( mipscpu.op ) != 0 )
+ {
+ mips_exception( EXC_RI );
+ }
+ else
+ {
+ INT64 n_res64;
+ n_res64 = MUL_64_32_32( (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ], (INT32)mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ mips_advance_pc();
+ mipscpu.lo = LO32_32_64( n_res64 );
+ mipscpu.hi = HI32_32_64( n_res64 );
+ }
+ break;
+ case FUNCT_MULTU:
+ if( INS_RD( mipscpu.op ) != 0 )
+ {
+ mips_exception( EXC_RI );
+ }
+ else
+ {
+ UINT64 n_res64;
+ n_res64 = MUL_U64_U32_U32( mipscpu.r[ INS_RS( mipscpu.op ) ], mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ mips_advance_pc();
+ mipscpu.lo = LO32_U32_U64( n_res64 );
+ mipscpu.hi = HI32_U32_U64( n_res64 );
+ }
+ break;
+ case FUNCT_DIV:
+ if( INS_RD( mipscpu.op ) != 0 )
+ {
+ mips_exception( EXC_RI );
+ }
+ else
+ {
+ UINT32 n_div;
+ UINT32 n_mod;
+ if( mipscpu.r[ INS_RT( mipscpu.op ) ] != 0 )
+ {
+ n_div = (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] / (INT32)mipscpu.r[ INS_RT( mipscpu.op ) ];
+ n_mod = (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] % (INT32)mipscpu.r[ INS_RT( mipscpu.op ) ];
+ mips_advance_pc();
+ mipscpu.lo = n_div;
+ mipscpu.hi = n_mod;
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ }
+ break;
+ case FUNCT_DIVU:
+ if( INS_RD( mipscpu.op ) != 0 )
+ {
+ mips_exception( EXC_RI );
+ }
+ else
+ {
+ UINT32 n_div;
+ UINT32 n_mod;
+ if( mipscpu.r[ INS_RT( mipscpu.op ) ] != 0 )
+ {
+ n_div = mipscpu.r[ INS_RS( mipscpu.op ) ] / mipscpu.r[ INS_RT( mipscpu.op ) ];
+ n_mod = mipscpu.r[ INS_RS( mipscpu.op ) ] % mipscpu.r[ INS_RT( mipscpu.op ) ];
+ mips_advance_pc();
+ mipscpu.lo = n_div;
+ mipscpu.hi = n_mod;
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ }
+ break;
+ case FUNCT_ADD:
+ {
+ n_res = mipscpu.r[ INS_RS( mipscpu.op ) ] + mipscpu.r[ INS_RT( mipscpu.op ) ];
+ if( (INT32)( ~( mipscpu.r[ INS_RS( mipscpu.op ) ] ^ mipscpu.r[ INS_RT( mipscpu.op ) ] ) & ( mipscpu.r[ INS_RS( mipscpu.op ) ] ^ n_res ) ) < 0 )
+ {
+ mips_exception( EXC_OVF );
+ }
+ else
+ {
+ mips_load( INS_RD( mipscpu.op ), n_res );
+ }
+ }
+ break;
+ case FUNCT_ADDU:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] + mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case FUNCT_SUB:
+ n_res = mipscpu.r[ INS_RS( mipscpu.op ) ] - mipscpu.r[ INS_RT( mipscpu.op ) ];
+ if( (INT32)( ( mipscpu.r[ INS_RS( mipscpu.op ) ] ^ mipscpu.r[ INS_RT( mipscpu.op ) ] ) & ( mipscpu.r[ INS_RS( mipscpu.op ) ] ^ n_res ) ) < 0 )
+ {
+ mips_exception( EXC_OVF );
+ }
+ else
+ {
+ mips_load( INS_RD( mipscpu.op ), n_res );
+ }
+ break;
+ case FUNCT_SUBU:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] - mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case FUNCT_AND:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] & mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case FUNCT_OR:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] | mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case FUNCT_XOR:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] ^ mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case FUNCT_NOR:
+ mips_load( INS_RD( mipscpu.op ), ~( mipscpu.r[ INS_RS( mipscpu.op ) ] | mipscpu.r[ INS_RT( mipscpu.op ) ] ) );
+ break;
+ case FUNCT_SLT:
+ mips_load( INS_RD( mipscpu.op ), (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] < (INT32)mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case FUNCT_SLTU:
+ mips_load( INS_RD( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] < mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ default:
+ mips_exception( EXC_RI );
+ break;
+ }
+ break;
+ case OP_REGIMM:
+ switch( INS_RT( mipscpu.op ) )
+ {
+ case RT_BLTZ:
+ if( (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] < 0 )
+ {
+ mips_delayed_branch( mipscpu.pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) << 2 ) );
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ break;
+ case RT_BGEZ:
+ if( (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] >= 0 )
+ {
+ mips_delayed_branch( mipscpu.pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) << 2 ) );
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ break;
+ case RT_BLTZAL:
+ n_res = mipscpu.pc + 8;
+ if( (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] < 0 )
+ {
+ mips_delayed_branch( mipscpu.pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) << 2 ) );
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ mipscpu.r[ 31 ] = n_res;
+ break;
+ case RT_BGEZAL:
+ n_res = mipscpu.pc + 8;
+ if( (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] >= 0 )
+ {
+ mips_delayed_branch( mipscpu.pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) << 2 ) );
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ mipscpu.r[ 31 ] = n_res;
+ break;
+ }
+ break;
+ case OP_J:
+ mips_delayed_branch( ( ( mipscpu.pc + 4 ) & 0xf0000000 ) + ( INS_TARGET( mipscpu.op ) << 2 ) );
+ break;
+ case OP_JAL:
+ n_res = mipscpu.pc + 8;
+ mips_delayed_branch( ( ( mipscpu.pc + 4 ) & 0xf0000000 ) + ( INS_TARGET( mipscpu.op ) << 2 ) );
+ mipscpu.r[ 31 ] = n_res;
+ break;
+ case OP_BEQ:
+ if( mipscpu.r[ INS_RS( mipscpu.op ) ] == mipscpu.r[ INS_RT( mipscpu.op ) ] )
+ {
+ mips_delayed_branch( mipscpu.pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) << 2 ) );
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ break;
+ case OP_BNE:
+ if( mipscpu.r[ INS_RS( mipscpu.op ) ] != mipscpu.r[ INS_RT( mipscpu.op ) ] )
+ {
+ mips_delayed_branch( mipscpu.pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) << 2 ) );
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ break;
+ case OP_BLEZ:
+ if( INS_RT( mipscpu.op ) != 0 )
+ {
+ mips_exception( EXC_RI );
+ }
+ else if( (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] <= 0 )
+ {
+ mips_delayed_branch( mipscpu.pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) << 2 ) );
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ break;
+ case OP_BGTZ:
+ if( INS_RT( mipscpu.op ) != 0 )
+ {
+ mips_exception( EXC_RI );
+ }
+ else if( (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] > 0 )
+ {
+ mips_delayed_branch( mipscpu.pc + 4 + ( MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) << 2 ) );
+ }
+ else
+ {
+ mips_advance_pc();
+ }
+ break;
+ case OP_ADDI:
+ {
+ UINT32 n_imm;
+ n_imm = MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ n_res = mipscpu.r[ INS_RS( mipscpu.op ) ] + n_imm;
+ if( (INT32)( ~( mipscpu.r[ INS_RS( mipscpu.op ) ] ^ n_imm ) & ( mipscpu.r[ INS_RS( mipscpu.op ) ] ^ n_res ) ) < 0 )
+ {
+ mips_exception( EXC_OVF );
+ }
+ else
+ {
+ mips_load( INS_RT( mipscpu.op ), n_res );
+ }
+ }
+ break;
+ case OP_ADDIU:
+ mips_load( INS_RT( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) );
+ break;
+ case OP_SLTI:
+ mips_load( INS_RT( mipscpu.op ), (INT32)mipscpu.r[ INS_RS( mipscpu.op ) ] < MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) );
+ break;
+ case OP_SLTIU:
+ mips_load( INS_RT( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] < (UINT32)MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) ) );
+ break;
+ case OP_ANDI:
+ mips_load( INS_RT( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] & INS_IMMEDIATE( mipscpu.op ) );
+ break;
+ case OP_ORI:
+ mips_load( INS_RT( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] | INS_IMMEDIATE( mipscpu.op ) );
+ break;
+ case OP_XORI:
+ mips_load( INS_RT( mipscpu.op ), mipscpu.r[ INS_RS( mipscpu.op ) ] ^ INS_IMMEDIATE( mipscpu.op ) );
+ break;
+ case OP_LUI:
+ mips_load( INS_RT( mipscpu.op ), INS_IMMEDIATE( mipscpu.op ) << 16 );
+ break;
+ case OP_COP0:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) != 0 && ( mipscpu.cp0r[ CP0_SR ] & SR_CU0 ) == 0 )
+ {
+ mips_exception( EXC_CPU );
+ mips_set_cp0r( CP0_CAUSE, ( mipscpu.cp0r[ CP0_CAUSE ] & ~CAUSE_CE ) | CAUSE_CE0 );
+ }
+ else
+ {
+ switch( INS_RS( mipscpu.op ) )
+ {
+ case RS_MFC:
+ mips_delayed_load( INS_RT( mipscpu.op ), mipscpu.cp0r[ INS_RD( mipscpu.op ) ] );
+ break;
+ case RS_CFC:
+ /* todo: */
+ logerror( "%08x: COP0 CFC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case RS_MTC:
+ n_res = ( mipscpu.cp0r[ INS_RD( mipscpu.op ) ] & ~mips_mtc0_writemask[ INS_RD( mipscpu.op ) ] ) |
+ ( mipscpu.r[ INS_RT( mipscpu.op ) ] & mips_mtc0_writemask[ INS_RD( mipscpu.op ) ] );
+ mips_advance_pc();
+ mips_set_cp0r( INS_RD( mipscpu.op ), n_res );
+ break;
+ case RS_CTC:
+ /* todo: */
+ logerror( "%08x: COP0 CTC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case RS_BC:
+ switch( INS_RT( mipscpu.op ) )
+ {
+ case RT_BCF:
+ /* todo: */
+ logerror( "%08x: COP0 BCF not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case RT_BCT:
+ /* todo: */
+ logerror( "%08x: COP0 BCT not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ default:
+ /* todo: */
+ logerror( "%08x: COP0 unknown command %08x\n", mipscpu.pc, mipscpu.op );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ }
+ break;
+ default:
+ switch( INS_CO( mipscpu.op ) )
+ {
+ case 1:
+ switch( INS_CF( mipscpu.op ) )
+ {
+ case CF_RFE:
+ mips_advance_pc();
+ mips_set_cp0r( CP0_SR, ( mipscpu.cp0r[ CP0_SR ] & ~0xf ) | ( ( mipscpu.cp0r[ CP0_SR ] >> 2 ) & 0xf ) );
+ break;
+ default:
+ /* todo: */
+ logerror( "%08x: COP0 unknown command %08x\n", mipscpu.pc, mipscpu.op );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ }
+ break;
+ default:
+ /* todo: */
+ logerror( "%08x: COP0 unknown command %08x\n", mipscpu.pc, mipscpu.op );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ case OP_COP1:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_CU1 ) == 0 )
+ {
+ mips_exception( EXC_CPU );
+ mips_set_cp0r( CP0_CAUSE, ( mipscpu.cp0r[ CP0_CAUSE ] & ~CAUSE_CE ) | CAUSE_CE1 );
+ }
+ else
+ {
+ switch( INS_RS( mipscpu.op ) )
+ {
+ case RS_MFC:
+ /* todo: */
+ logerror( "%08x: COP1 BCT not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case RS_CFC:
+ /* todo: */
+ logerror( "%08x: COP1 CFC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case RS_MTC:
+ /* todo: */
+ logerror( "%08x: COP1 MTC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case RS_CTC:
+ /* todo: */
+ logerror( "%08x: COP1 CTC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case RS_BC:
+ switch( INS_RT( mipscpu.op ) )
+ {
+ case RT_BCF:
+ /* todo: */
+ logerror( "%08x: COP1 BCF not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case RT_BCT:
+ /* todo: */
+ logerror( "%08x: COP1 BCT not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ default:
+ /* todo: */
+ logerror( "%08x: COP1 unknown command %08x\n", mipscpu.pc, mipscpu.op );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ }
+ break;
+ default:
+ switch( INS_CO( mipscpu.op ) )
+ {
+ case 1:
+ /* todo: */
+ logerror( "%08x: COP1 unknown command %08x\n", mipscpu.pc, mipscpu.op );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ default:
+ /* todo: */
+ logerror( "%08x: COP1 unknown command %08x\n", mipscpu.pc, mipscpu.op );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ case OP_COP2:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_CU2 ) == 0 )
+ {
+ mips_exception( EXC_CPU );
+ mips_set_cp0r( CP0_CAUSE, ( mipscpu.cp0r[ CP0_CAUSE ] & ~CAUSE_CE ) | CAUSE_CE2 );
+ }
+ else
+ {
+ switch( INS_RS( mipscpu.op ) )
+ {
+ case RS_MFC:
+ mips_delayed_load( INS_RT( mipscpu.op ), getcp2dr( INS_RD( mipscpu.op ) ) );
+ break;
+ case RS_CFC:
+ mips_delayed_load( INS_RT( mipscpu.op ), getcp2cr( INS_RD( mipscpu.op ) ) );
+ break;
+ case RS_MTC:
+ setcp2dr( INS_RD( mipscpu.op ), mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ mips_advance_pc();
+ break;
+ case RS_CTC:
+ setcp2cr( INS_RD( mipscpu.op ), mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ mips_advance_pc();
+ break;
+ case RS_BC:
+ switch( INS_RT( mipscpu.op ) )
+ {
+ case RT_BCF:
+ /* todo: */
+ logerror( "%08x: COP2 BCF not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case RT_BCT:
+ /* todo: */
+ logerror( "%08x: COP2 BCT not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ default:
+ /* todo: */
+ logerror( "%08x: COP2 unknown command %08x\n", mipscpu.pc, mipscpu.op );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ }
+ break;
+ default:
+ switch( INS_CO( mipscpu.op ) )
+ {
+ case 1:
+ docop2( INS_COFUN( mipscpu.op ) );
+ mips_advance_pc();
+ break;
+ default:
+ /* todo: */
+ logerror( "%08x: COP2 unknown command %08x\n", mipscpu.pc, mipscpu.op );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ case OP_LB:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: LB SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ mips_delayed_load( INS_RT( mipscpu.op ), MIPS_BYTE_EXTEND( program_read_byte_32le( n_adr ^ 3 ) ) );
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ mips_delayed_load( INS_RT( mipscpu.op ), MIPS_BYTE_EXTEND( program_read_byte_32le( n_adr ) ) );
+ }
+ }
+ break;
+ case OP_LH:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: LH SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 1 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ mips_delayed_load( INS_RT( mipscpu.op ), MIPS_WORD_EXTEND( program_read_word_32le( n_adr ^ 2 ) ) );
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 1 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ mips_delayed_load( INS_RT( mipscpu.op ), MIPS_WORD_EXTEND( program_read_word_32le( n_adr ) ) );
+ }
+ }
+ break;
+ case OP_LWL:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: LWL SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ switch( n_adr & 3 )
+ {
+ case 0:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0x00ffffff ) | ( (UINT32)program_read_byte_32le( n_adr + 3 ) << 24 );
+ break;
+ case 1:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0x0000ffff ) | ( (UINT32)program_read_word_32le( n_adr + 1 ) << 16 );
+ break;
+ case 2:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0x000000ff ) | ( (UINT32)program_read_byte_32le( n_adr - 1 ) << 8 ) | ( (UINT32)program_read_word_32le( n_adr ) << 16 );
+ break;
+ default:
+ n_res = program_read_dword_32le( n_adr - 3 );
+ break;
+ }
+ mips_delayed_load( INS_RT( mipscpu.op ), n_res );
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ switch( n_adr & 3 )
+ {
+ case 0:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0x00ffffff ) | ( (UINT32)program_read_byte_32le( n_adr ) << 24 );
+ break;
+ case 1:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0x0000ffff ) | ( (UINT32)program_read_word_32le( n_adr - 1 ) << 16 );
+ break;
+ case 2:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0x000000ff ) | ( (UINT32)program_read_word_32le( n_adr - 2 ) << 8 ) | ( (UINT32)program_read_byte_32le( n_adr ) << 24 );
+ break;
+ default:
+ n_res = program_read_dword_32le( n_adr - 3 );
+ break;
+ }
+ mips_delayed_load( INS_RT( mipscpu.op ), n_res );
+ }
+ }
+ break;
+ case OP_LW:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: LW SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 3 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ mips_delayed_load( INS_RT( mipscpu.op ), program_read_dword_32le( n_adr ) );
+ }
+ }
+ break;
+ case OP_LBU:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: LBU SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ mips_delayed_load( INS_RT( mipscpu.op ), program_read_byte_32le( n_adr ^ 3 ) );
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ mips_delayed_load( INS_RT( mipscpu.op ), program_read_byte_32le( n_adr ) );
+ }
+ }
+ break;
+ case OP_LHU:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: LHU SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 1 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ mips_delayed_load( INS_RT( mipscpu.op ), program_read_word_32le( n_adr ^ 2 ) );
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 1 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ mips_delayed_load( INS_RT( mipscpu.op ), program_read_word_32le( n_adr ) );
+ }
+ }
+ break;
+ case OP_LWR:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: LWR SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ switch( n_adr & 3 )
+ {
+ case 3:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0xffffff00 ) | program_read_byte_32le( n_adr - 3 );
+ break;
+ case 2:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0xffff0000 ) | program_read_word_32le( n_adr - 2 );
+ break;
+ case 1:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0xff000000 ) | program_read_word_32le( n_adr - 1 ) | ( (UINT32)program_read_byte_32le( n_adr + 1 ) << 16 );
+ break;
+ default:
+ n_res = program_read_dword_32le( n_adr );
+ break;
+ }
+ mips_delayed_load( INS_RT( mipscpu.op ), n_res );
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ switch( n_adr & 3 )
+ {
+ case 3:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0xffffff00 ) | program_read_byte_32le( n_adr );
+ break;
+ case 2:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0xffff0000 ) | program_read_word_32le( n_adr );
+ break;
+ case 1:
+ n_res = ( mipscpu.r[ INS_RT( mipscpu.op ) ] & 0xff000000 ) | program_read_byte_32le( n_adr ) | ( (UINT32)program_read_word_32le( n_adr + 1 ) << 8 );
+ break;
+ default:
+ n_res = program_read_dword_32le( n_adr );
+ break;
+ }
+ mips_delayed_load( INS_RT( mipscpu.op ), n_res );
+ }
+ }
+ break;
+ case OP_SB:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: SB SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ program_write_byte_32le( n_adr ^ 3, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ mips_advance_pc();
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ program_write_byte_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ mips_advance_pc();
+ }
+ }
+ break;
+ case OP_SH:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: SH SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 1 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ program_write_word_32le( n_adr ^ 2, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ mips_advance_pc();
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 1 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ program_write_word_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ mips_advance_pc();
+ }
+ }
+ break;
+ case OP_SWL:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: SWL SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ switch( n_adr & 3 )
+ {
+ case 0:
+ program_write_byte_32le( n_adr + 3, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 24 );
+ break;
+ case 1:
+ program_write_word_32le( n_adr + 1, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 16 );
+ break;
+ case 2:
+ program_write_byte_32le( n_adr - 1, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 8 );
+ program_write_word_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 16 );
+ break;
+ case 3:
+ program_write_dword_32le( n_adr - 3, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ }
+ mips_advance_pc();
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ switch( n_adr & 3 )
+ {
+ case 0:
+ program_write_byte_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 24 );
+ break;
+ case 1:
+ program_write_word_32le( n_adr - 1, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 16 );
+ break;
+ case 2:
+ program_write_word_32le( n_adr - 2, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 8 );
+ program_write_byte_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 24 );
+ break;
+ case 3:
+ program_write_dword_32le( n_adr - 3, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ }
+ mips_advance_pc();
+ }
+ }
+ break;
+ case OP_SW:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+/* used by bootstrap
+ logerror( "%08x: SW SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+*/
+ mips_advance_pc();
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 3 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ program_write_dword_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ mips_advance_pc();
+ }
+ }
+ break;
+ case OP_SWR:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: SWR SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & ( SR_RE | SR_KUC ) ) == ( SR_RE | SR_KUC ) )
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ switch( n_adr & 3 )
+ {
+ case 0:
+ program_write_dword_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case 1:
+ program_write_word_32le( n_adr - 1, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ program_write_byte_32le( n_adr + 1, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 16 );
+ break;
+ case 2:
+ program_write_word_32le( n_adr - 2, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case 3:
+ program_write_byte_32le( n_adr - 3, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ }
+ mips_advance_pc();
+ }
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ switch( n_adr & 3 )
+ {
+ case 0:
+ program_write_dword_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case 1:
+ program_write_byte_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ program_write_word_32le( n_adr + 1, mipscpu.r[ INS_RT( mipscpu.op ) ] >> 8 );
+ break;
+ case 2:
+ program_write_word_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ case 3:
+ program_write_byte_32le( n_adr, mipscpu.r[ INS_RT( mipscpu.op ) ] );
+ break;
+ }
+ mips_advance_pc();
+ }
+ }
+ break;
+ case OP_LWC1:
+ /* todo: */
+ logerror( "%08x: COP1 LWC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case OP_LWC2:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_CU2 ) == 0 )
+ {
+ mips_exception( EXC_CPU );
+ mips_set_cp0r( CP0_CAUSE, ( mipscpu.cp0r[ CP0_CAUSE ] & ~CAUSE_CE ) | CAUSE_CE2 );
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: LWC2 SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 3 ) ) != 0 )
+ {
+ mips_exception( EXC_ADEL );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ /* todo: delay? */
+ setcp2dr( INS_RT( mipscpu.op ), program_read_dword_32le( n_adr ) );
+ mips_advance_pc();
+ }
+ }
+ break;
+ case OP_SWC1:
+ /* todo: */
+ logerror( "%08x: COP1 SWC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ break;
+ case OP_SWC2:
+ if( ( mipscpu.cp0r[ CP0_SR ] & SR_CU2 ) == 0 )
+ {
+ mips_exception( EXC_CPU );
+ mips_set_cp0r( CP0_CAUSE, ( mipscpu.cp0r[ CP0_CAUSE ] & ~CAUSE_CE ) | CAUSE_CE2 );
+ }
+ else if( ( mipscpu.cp0r[ CP0_SR ] & SR_ISC ) != 0 )
+ {
+ /* todo: */
+ logerror( "%08x: SWC2 SR_ISC not supported\n", mipscpu.pc );
+ mips_stop();
+ mips_advance_pc();
+ }
+ else
+ {
+ UINT32 n_adr;
+ n_adr = mipscpu.r[ INS_RS( mipscpu.op ) ] + MIPS_WORD_EXTEND( INS_IMMEDIATE( mipscpu.op ) );
+ if( ( n_adr & ( ( ( mipscpu.cp0r[ CP0_SR ] & SR_KUC ) << 30 ) | 3 ) ) != 0 )
+ {
+ mips_exception( EXC_ADES );
+ mips_set_cp0r( CP0_BADVADDR, n_adr );
+ }
+ else
+ {
+ program_write_dword_32le( n_adr, getcp2dr( INS_RT( mipscpu.op ) ) );
+ mips_advance_pc();
+ }
+ }
+ break;
+ default:
+ logerror( "%08x: unknown opcode %08x\n", mipscpu.pc, mipscpu.op );
+ mips_stop();
+ mips_exception( EXC_RI );
+ break;
+ }
+ mips_ICount--;
+ } while( mips_ICount > 0 );
+
+ return cycles - mips_ICount;
+}
+
+static void mips_get_context( void *dst )
+{
+ if( dst )
+ {
+ *(mips_cpu_context *)dst = mipscpu;
+ }
+}
+
+static void mips_set_context( void *src )
+{
+ if( src )
+ {
+ mipscpu = *(mips_cpu_context *)src;
+ change_pc( mipscpu.pc );
+ }
+}
+
+static void set_irq_line( int irqline, int state )
+{
+ UINT32 ip;
+
+ switch( irqline )
+ {
+ case MIPS_IRQ0:
+ ip = CAUSE_IP2;
+ break;
+ case MIPS_IRQ1:
+ ip = CAUSE_IP3;
+ break;
+ case MIPS_IRQ2:
+ ip = CAUSE_IP4;
+ break;
+ case MIPS_IRQ3:
+ ip = CAUSE_IP5;
+ break;
+ case MIPS_IRQ4:
+ ip = CAUSE_IP6;
+ break;
+ case MIPS_IRQ5:
+ ip = CAUSE_IP7;
+ break;
+ default:
+ return;
+ }
+
+ switch( state )
+ {
+ case CLEAR_LINE:
+ mips_set_cp0r( CP0_CAUSE, mipscpu.cp0r[ CP0_CAUSE ] & ~ip );
+ break;
+ case ASSERT_LINE:
+ mips_set_cp0r( CP0_CAUSE, mipscpu.cp0r[ CP0_CAUSE ] |= ip );
+ if( mipscpu.irq_callback )
+ {
+ /* HOLD_LINE interrupts are not supported by the architecture.
+ By acknowledging the interupt here they are treated like PULSE_LINE
+ interrupts, so if the interrupt isn't enabled it will be ignored.
+ There is also a problem with PULSE_LINE interrupts as the interrupt
+ pending bits aren't latched the emulated code won't know what caused
+ the interrupt. */
+ (*mipscpu.irq_callback)( irqline );
+ }
+ break;
+ }
+}
+
+/****************************************************************************
+ * Return a formatted string for a register
+ ****************************************************************************/
+
+#ifdef MAME_DEBUG
+static offs_t mips_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return DasmMIPS( buffer, pc, opram );
+}
+#endif /* MAME_DEBUG */
+
+/* preliminary gte code */
+
+#define VXY0 ( mipscpu.cp2dr[ 0 ].d )
+#define VX0 ( mipscpu.cp2dr[ 0 ].w.l )
+#define VY0 ( mipscpu.cp2dr[ 0 ].w.h )
+#define VZ0 ( mipscpu.cp2dr[ 1 ].w.l )
+#define VXY1 ( mipscpu.cp2dr[ 2 ].d )
+#define VX1 ( mipscpu.cp2dr[ 2 ].w.l )
+#define VY1 ( mipscpu.cp2dr[ 2 ].w.h )
+#define VZ1 ( mipscpu.cp2dr[ 3 ].w.l )
+#define VXY2 ( mipscpu.cp2dr[ 4 ].d )
+#define VX2 ( mipscpu.cp2dr[ 4 ].w.l )
+#define VY2 ( mipscpu.cp2dr[ 4 ].w.h )
+#define VZ2 ( mipscpu.cp2dr[ 5 ].w.l )
+#define RGB ( mipscpu.cp2dr[ 6 ].d )
+#define R ( mipscpu.cp2dr[ 6 ].b.l )
+#define G ( mipscpu.cp2dr[ 6 ].b.h )
+#define B ( mipscpu.cp2dr[ 6 ].b.h2 )
+#define CODE ( mipscpu.cp2dr[ 6 ].b.h3 )
+#define OTZ ( mipscpu.cp2dr[ 7 ].w.l )
+#define IR0 ( mipscpu.cp2dr[ 8 ].d )
+#define IR1 ( mipscpu.cp2dr[ 9 ].d )
+#define IR2 ( mipscpu.cp2dr[ 10 ].d )
+#define IR3 ( mipscpu.cp2dr[ 11 ].d )
+#define SXY0 ( mipscpu.cp2dr[ 12 ].d )
+#define SX0 ( mipscpu.cp2dr[ 12 ].w.l )
+#define SY0 ( mipscpu.cp2dr[ 12 ].w.h )
+#define SXY1 ( mipscpu.cp2dr[ 13 ].d )
+#define SX1 ( mipscpu.cp2dr[ 13 ].w.l )
+#define SY1 ( mipscpu.cp2dr[ 13 ].w.h )
+#define SXY2 ( mipscpu.cp2dr[ 14 ].d )
+#define SX2 ( mipscpu.cp2dr[ 14 ].w.l )
+#define SY2 ( mipscpu.cp2dr[ 14 ].w.h )
+#define SXYP ( mipscpu.cp2dr[ 15 ].d )
+#define SXP ( mipscpu.cp2dr[ 15 ].w.l )
+#define SYP ( mipscpu.cp2dr[ 15 ].w.h )
+#define SZ0 ( mipscpu.cp2dr[ 16 ].w.l )
+#define SZ1 ( mipscpu.cp2dr[ 17 ].w.l )
+#define SZ2 ( mipscpu.cp2dr[ 18 ].w.l )
+#define SZ3 ( mipscpu.cp2dr[ 19 ].w.l )
+#define RGB0 ( mipscpu.cp2dr[ 20 ].d )
+#define R0 ( mipscpu.cp2dr[ 20 ].b.l )
+#define G0 ( mipscpu.cp2dr[ 20 ].b.h )
+#define B0 ( mipscpu.cp2dr[ 20 ].b.h2 )
+#define CD0 ( mipscpu.cp2dr[ 20 ].b.h3 )
+#define RGB1 ( mipscpu.cp2dr[ 21 ].d )
+#define R1 ( mipscpu.cp2dr[ 21 ].b.l )
+#define G1 ( mipscpu.cp2dr[ 21 ].b.h )
+#define B1 ( mipscpu.cp2dr[ 21 ].b.h2 )
+#define CD1 ( mipscpu.cp2dr[ 21 ].b.h3 )
+#define RGB2 ( mipscpu.cp2dr[ 22 ].d )
+#define R2 ( mipscpu.cp2dr[ 22 ].b.l )
+#define G2 ( mipscpu.cp2dr[ 22 ].b.h )
+#define B2 ( mipscpu.cp2dr[ 22 ].b.h2 )
+#define CD2 ( mipscpu.cp2dr[ 22 ].b.h3 )
+#define RES1 ( mipscpu.cp2dr[ 23 ].d )
+#define MAC0 ( mipscpu.cp2dr[ 24 ].d )
+#define MAC1 ( mipscpu.cp2dr[ 25 ].d )
+#define MAC2 ( mipscpu.cp2dr[ 26 ].d )
+#define MAC3 ( mipscpu.cp2dr[ 27 ].d )
+#define IRGB ( mipscpu.cp2dr[ 28 ].d )
+#define ORGB ( mipscpu.cp2dr[ 29 ].d )
+#define LZCS ( mipscpu.cp2dr[ 30 ].d )
+#define LZCR ( mipscpu.cp2dr[ 31 ].d )
+
+#define D1 ( mipscpu.cp2cr[ 0 ].d )
+#define R11 ( mipscpu.cp2cr[ 0 ].w.l )
+#define R12 ( mipscpu.cp2cr[ 0 ].w.h )
+#define R13 ( mipscpu.cp2cr[ 1 ].w.l )
+#define R21 ( mipscpu.cp2cr[ 1 ].w.h )
+#define D2 ( mipscpu.cp2cr[ 2 ].d )
+#define R22 ( mipscpu.cp2cr[ 2 ].w.l )
+#define R23 ( mipscpu.cp2cr[ 2 ].w.h )
+#define R31 ( mipscpu.cp2cr[ 3 ].w.l )
+#define R32 ( mipscpu.cp2cr[ 3 ].w.h )
+#define D3 ( mipscpu.cp2cr[ 4 ].d )
+#define R33 ( mipscpu.cp2cr[ 4 ].w.l )
+#define TRX ( mipscpu.cp2cr[ 5 ].d )
+#define TRY ( mipscpu.cp2cr[ 6 ].d )
+#define TRZ ( mipscpu.cp2cr[ 7 ].d )
+#define L11 ( mipscpu.cp2cr[ 8 ].w.l )
+#define L12 ( mipscpu.cp2cr[ 8 ].w.h )
+#define L13 ( mipscpu.cp2cr[ 9 ].w.l )
+#define L21 ( mipscpu.cp2cr[ 9 ].w.h )
+#define L22 ( mipscpu.cp2cr[ 10 ].w.l )
+#define L23 ( mipscpu.cp2cr[ 10 ].w.h )
+#define L31 ( mipscpu.cp2cr[ 11 ].w.l )
+#define L32 ( mipscpu.cp2cr[ 11 ].w.h )
+#define L33 ( mipscpu.cp2cr[ 12 ].w.l )
+#define RBK ( mipscpu.cp2cr[ 13 ].d )
+#define GBK ( mipscpu.cp2cr[ 14 ].d )
+#define BBK ( mipscpu.cp2cr[ 15 ].d )
+#define LR1 ( mipscpu.cp2cr[ 16 ].w.l )
+#define LR2 ( mipscpu.cp2cr[ 16 ].w.h )
+#define LR3 ( mipscpu.cp2cr[ 17 ].w.l )
+#define LG1 ( mipscpu.cp2cr[ 17 ].w.h )
+#define LG2 ( mipscpu.cp2cr[ 18 ].w.l )
+#define LG3 ( mipscpu.cp2cr[ 18 ].w.h )
+#define LB1 ( mipscpu.cp2cr[ 19 ].w.l )
+#define LB2 ( mipscpu.cp2cr[ 19 ].w.h )
+#define LB3 ( mipscpu.cp2cr[ 20 ].w.l )
+#define RFC ( mipscpu.cp2cr[ 21 ].d )
+#define GFC ( mipscpu.cp2cr[ 22 ].d )
+#define BFC ( mipscpu.cp2cr[ 23 ].d )
+#define OFX ( mipscpu.cp2cr[ 24 ].d )
+#define OFY ( mipscpu.cp2cr[ 25 ].d )
+#define H ( mipscpu.cp2cr[ 26 ].w.l )
+#define DQA ( mipscpu.cp2cr[ 27 ].w.l )
+#define DQB ( mipscpu.cp2cr[ 28 ].d )
+#define ZSF3 ( mipscpu.cp2cr[ 29 ].w.l )
+#define ZSF4 ( mipscpu.cp2cr[ 30 ].w.l )
+#define FLAG ( mipscpu.cp2cr[ 31 ].d )
+
+static UINT32 getcp2dr( int n_reg )
+{
+ if( n_reg == 1 || n_reg == 3 || n_reg == 5 || n_reg == 8 || n_reg == 9 || n_reg == 10 || n_reg == 11 )
+ {
+ mipscpu.cp2dr[ n_reg ].d = (INT32)(INT16)mipscpu.cp2dr[ n_reg ].d;
+ }
+ else if( n_reg == 17 || n_reg == 18 || n_reg == 19 )
+ {
+ mipscpu.cp2dr[ n_reg ].d = (UINT32)(UINT16)mipscpu.cp2dr[ n_reg ].d;
+ }
+ else if( n_reg == 29 )
+ {
+ ORGB = ( ( IR1 >> 7 ) & 0x1f ) | ( ( IR2 >> 2 ) & 0x3e0 ) | ( ( IR3 << 3 ) & 0x7c00 );
+ }
+ GTELOG( "get CP2DR%u=%08x", n_reg, mipscpu.cp2dr[ n_reg ].d );
+ return mipscpu.cp2dr[ n_reg ].d;
+}
+
+static void setcp2dr( int n_reg, UINT32 n_value )
+{
+ GTELOG( "set CP2DR%u=%08x", n_reg, n_value );
+ mipscpu.cp2dr[ n_reg ].d = n_value;
+
+ if( n_reg == 15 )
+ {
+ SXY0 = SXY1;
+ SXY1 = SXY2;
+ SXY2 = SXYP;
+ }
+ else if( n_reg == 28 )
+ {
+ IR1 = ( IRGB & 0x1f ) << 4;
+ IR2 = ( IRGB & 0x3e0 ) >> 1;
+ IR3 = ( IRGB & 0x7c00 ) >> 6;
+ }
+ else if( n_reg == 30 )
+ {
+ UINT32 n_lzcs = LZCS;
+ UINT32 n_lzcr = 0;
+
+ if( ( n_lzcs & 0x80000000 ) == 0 )
+ {
+ n_lzcs = ~n_lzcs;
+ }
+ while( ( n_lzcs & 0x80000000 ) != 0 )
+ {
+ n_lzcr++;
+ n_lzcs <<= 1;
+ }
+ LZCR = n_lzcr;
+ }
+}
+
+static UINT32 getcp2cr( int n_reg )
+{
+ GTELOG( "get CP2CR%u=%08x", n_reg, mipscpu.cp2cr[ n_reg ].d );
+ return mipscpu.cp2cr[ n_reg ].d;
+}
+
+static void setcp2cr( int n_reg, UINT32 n_value )
+{
+ GTELOG( "set CP2CR%u=%08x", n_reg, n_value );
+ mipscpu.cp2cr[ n_reg ].d = n_value;
+}
+
+INLINE INT32 LIM( INT32 n_value, INT32 n_max, INT32 n_min, UINT32 n_flag )
+{
+ if( n_value > n_max )
+ {
+ FLAG |= n_flag;
+ return n_max;
+ }
+ else if( n_value < n_min )
+ {
+ FLAG |= n_flag;
+ return n_min;
+ }
+ return n_value;
+}
+
+INLINE INT64 BOUNDS( INT64 n_value, INT64 n_max, int n_maxflag, INT64 n_min, int n_minflag )
+{
+ if( n_value > n_max )
+ {
+ FLAG |= 1 << n_maxflag;
+ }
+ else if( n_value < n_min )
+ {
+ FLAG |= 1 << n_minflag;
+ }
+ return n_value;
+}
+
+#define A1( a ) BOUNDS( ( a ), 0x7fffffff, 30, -(INT64)0x80000000, 27 )
+#define A2( a ) BOUNDS( ( a ), 0x7fffffff, 29, -(INT64)0x80000000, 26 )
+#define A3( a ) BOUNDS( ( a ), 0x7fffffff, 28, -(INT64)0x80000000, 25 )
+#define Lm_B1( a, l ) LIM( ( a ), 0x7fff, -0x8000 * !l, ( 1 << 31 ) | ( 1 << 24 ) )
+#define Lm_B2( a, l ) LIM( ( a ), 0x7fff, -0x8000 * !l, ( 1 << 31 ) | ( 1 << 23 ) )
+#define Lm_B3( a, l ) LIM( ( a ), 0x7fff, -0x8000 * !l, ( 1 << 31 ) | ( 1 << 22 ) )
+#define Lm_C1( a ) LIM( ( a ), 0x00ff, 0x0000, ( 1 << 21 ) )
+#define Lm_C2( a ) LIM( ( a ), 0x00ff, 0x0000, ( 1 << 20 ) )
+#define Lm_C3( a ) LIM( ( a ), 0x00ff, 0x0000, ( 1 << 19 ) )
+#define Lm_D( a ) LIM( ( a ), 0xffff, 0x0000, ( 1 << 31 ) | ( 1 << 18 ) )
+
+INLINE UINT32 Lm_E( UINT32 n_z )
+{
+ if( n_z <= H / 2 )
+ {
+ n_z = H / 2;
+ FLAG |= ( 1 << 31 ) | ( 1 << 17 );
+ }
+ if( n_z == 0 )
+ {
+ n_z = 1;
+ }
+ return n_z;
+}
+
+#define F( a ) BOUNDS( ( a ), 0x7fffffff, ( 1 << 31 ) | ( 1 << 16 ), -(INT64)0x80000000, ( 1 << 31 ) | ( 1 << 15 ) )
+#define Lm_G1( a ) LIM( ( a ), 0x3ff, -0x400, ( 1 << 31 ) | ( 1 << 14 ) )
+#define Lm_G2( a ) LIM( ( a ), 0x3ff, -0x400, ( 1 << 31 ) | ( 1 << 13 ) )
+#define Lm_H( a ) LIM( ( a ), 0xfff, 0x000, ( 1 << 12 ) )
+
+static void docop2( int gteop )
+{
+ int n_sf;
+ int n_v;
+ int n_lm;
+ int n_pass;
+ UINT16 n_v1;
+ UINT16 n_v2;
+ UINT16 n_v3;
+ const UINT16 **p_n_mx;
+ const UINT32 **p_n_cv;
+ static const UINT16 n_zm = 0;
+ static const UINT32 n_zc = 0;
+ static const UINT16 *p_n_vx[] = { &VX0, &VX1, &VX2 };
+ static const UINT16 *p_n_vy[] = { &VY0, &VY1, &VY2 };
+ static const UINT16 *p_n_vz[] = { &VZ0, &VZ1, &VZ2 };
+ static const UINT16 *p_n_rm[] = { &R11, &R12, &R13, &R21, &R22, &R23, &R31, &R32, &R33 };
+ static const UINT16 *p_n_lm[] = { &L11, &L12, &L13, &L21, &L22, &L23, &L31, &L32, &L33 };
+ static const UINT16 *p_n_cm[] = { &LR1, &LR2, &LR3, &LG1, &LG2, &LG3, &LB1, &LB2, &LB3 };
+ static const UINT16 *p_n_zm[] = { &n_zm, &n_zm, &n_zm, &n_zm, &n_zm, &n_zm, &n_zm, &n_zm, &n_zm };
+ static const UINT16 **p_p_n_mx[] = { p_n_rm, p_n_lm, p_n_cm, p_n_zm };
+ static const UINT32 *p_n_tr[] = { &TRX, &TRY, &TRZ };
+ static const UINT32 *p_n_bk[] = { &RBK, &GBK, &BBK };
+ static const UINT32 *p_n_fc[] = { &RFC, &GFC, &BFC };
+ static const UINT32 *p_n_zc[] = { &n_zc, &n_zc, &n_zc };
+ static const UINT32 **p_p_n_cv[] = { p_n_tr, p_n_bk, p_n_fc, p_n_zc };
+
+ switch( GTE_FUNCT( gteop ) )
+ {
+ case 0x01:
+ if( gteop == 0x0180001 )
+ {
+ GTELOG( "RTPS" );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)(INT32)TRX << 12 ) + ( (INT16)R11 * (INT16)VX0 ) + ( (INT16)R12 * (INT16)VY0 ) + ( (INT16)R13 * (INT16)VZ0 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)(INT32)TRY << 12 ) + ( (INT16)R21 * (INT16)VX0 ) + ( (INT16)R22 * (INT16)VY0 ) + ( (INT16)R23 * (INT16)VZ0 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)(INT32)TRZ << 12 ) + ( (INT16)R31 * (INT16)VX0 ) + ( (INT16)R32 * (INT16)VY0 ) + ( (INT16)R33 * (INT16)VZ0 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 0 );
+ IR2 = Lm_B2( (INT32)MAC2, 0 );
+ IR3 = Lm_B3( (INT32)MAC3, 0 );
+ SZ0 = SZ1;
+ SZ1 = SZ2;
+ SZ2 = SZ3;
+ SZ3 = Lm_D( (INT32)MAC3 );
+ SXY0 = SXY1;
+ SXY1 = SXY2;
+ SX2 = Lm_G1( F( (INT64)(INT32)OFX + ( (INT64)(INT16)IR1 * ( ( (UINT32)H << 16 ) / Lm_E( SZ3 ) ) ) ) >> 16 );
+ SY2 = Lm_G2( F( (INT64)(INT32)OFY + ( (INT64)(INT16)IR2 * ( ( (UINT32)H << 16 ) / Lm_E( SZ3 ) ) ) ) >> 16 );
+ MAC0 = F( (INT64)(INT32)DQB + ( (INT64)(INT16)DQA * ( ( (UINT32)H << 16 ) / Lm_E( SZ3 ) ) ) );
+ IR0 = Lm_H( (INT32)MAC0 >> 12 );
+ return;
+ }
+ break;
+ case 0x06:
+ if( gteop == 0x0400006 ||
+ gteop == 0x1400006 ||
+ gteop == 0x0155cc6 )
+ {
+ GTELOG( "NCLIP" );
+ FLAG = 0;
+
+ MAC0 = F( ( (INT64)(INT16)SX0 * (INT16)SY1 ) + ( (INT16)SX1 * (INT16)SY2 ) + ( (INT16)SX2 * (INT16)SY0 ) - ( (INT16)SX0 * (INT16)SY2 ) - ( (INT16)SX1 * (INT16)SY0 ) - ( (INT16)SX2 * (INT16)SY1 ) );
+ return;
+ }
+ break;
+ case 0x0c:
+ if( GTE_OP( gteop ) == 0x17 )
+ {
+ GTELOG( "OP" );
+ n_sf = 12 * GTE_SF( gteop );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)(INT32)D2 * (INT16)IR3 ) - ( (INT64)(INT32)D3 * (INT16)IR2 ) ) >> n_sf );
+ MAC2 = A2( ( ( (INT64)(INT32)D3 * (INT16)IR1 ) - ( (INT64)(INT32)D1 * (INT16)IR3 ) ) >> n_sf );
+ MAC3 = A3( ( ( (INT64)(INT32)D1 * (INT16)IR2 ) - ( (INT64)(INT32)D2 * (INT16)IR1 ) ) >> n_sf );
+ IR1 = Lm_B1( (INT32)MAC1, 0 );
+ IR2 = Lm_B2( (INT32)MAC2, 0 );
+ IR3 = Lm_B3( (INT32)MAC3, 0 );
+ return;
+ }
+ break;
+ case 0x10:
+ if( gteop == 0x0780010 )
+ {
+ GTELOG( "DPCS" );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)R << 16 ) + ( (INT64)(INT16)IR0 * ( Lm_B1( (INT32)RFC - ( R << 4 ), 0 ) ) ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)G << 16 ) + ( (INT64)(INT16)IR0 * ( Lm_B1( (INT32)GFC - ( G << 4 ), 0 ) ) ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)B << 16 ) + ( (INT64)(INT16)IR0 * ( Lm_B1( (INT32)BFC - ( B << 4 ), 0 ) ) ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 0 );
+ IR2 = Lm_B2( (INT32)MAC2, 0 );
+ IR3 = Lm_B3( (INT32)MAC3, 0 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ return;
+ }
+ break;
+ case 0x11:
+ if( gteop == 0x0980011 )
+ {
+ GTELOG( "INTPL" );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)(INT16)IR1 << 12 ) + ( (INT64)(INT16)IR0 * ( Lm_B1( (INT32)RFC - (INT16)IR1, 0 ) ) ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)(INT16)IR2 << 12 ) + ( (INT64)(INT16)IR0 * ( Lm_B1( (INT32)GFC - (INT16)IR2, 0 ) ) ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)(INT16)IR3 << 12 ) + ( (INT64)(INT16)IR0 * ( Lm_B1( (INT32)BFC - (INT16)IR3, 0 ) ) ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 0 );
+ IR2 = Lm_B2( (INT32)MAC2, 0 );
+ IR3 = Lm_B3( (INT32)MAC3, 0 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 );
+ return;
+ }
+ break;
+ case 0x12:
+ if( GTE_OP( gteop ) == 0x04 )
+ {
+ GTELOG( "MVMVA" );
+ n_sf = 12 * GTE_SF( gteop );
+ p_n_mx = p_p_n_mx[ GTE_MX( gteop ) ];
+ n_v = GTE_V( gteop );
+ if( n_v < 3 )
+ {
+ n_v1 = *p_n_vx[ n_v ];
+ n_v2 = *p_n_vy[ n_v ];
+ n_v3 = *p_n_vz[ n_v ];
+ }
+ else
+ {
+ n_v1 = IR1;
+ n_v2 = IR2;
+ n_v3 = IR3;
+ }
+ p_n_cv = p_p_n_cv[ GTE_CV( gteop ) ];
+ n_lm = GTE_LM( gteop );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)(INT32)*p_n_cv[ 0 ] << 12 ) + ( (INT16)*p_n_mx[ 0 ] * (INT16)n_v1 ) + ( (INT16)*p_n_mx[ 1 ] * (INT16)n_v2 ) + ( (INT16)*p_n_mx[ 2 ] * (INT16)n_v3 ) ) >> n_sf );
+ MAC2 = A2( ( ( (INT64)(INT32)*p_n_cv[ 1 ] << 12 ) + ( (INT16)*p_n_mx[ 3 ] * (INT16)n_v1 ) + ( (INT16)*p_n_mx[ 4 ] * (INT16)n_v2 ) + ( (INT16)*p_n_mx[ 5 ] * (INT16)n_v3 ) ) >> n_sf );
+ MAC3 = A3( ( ( (INT64)(INT32)*p_n_cv[ 2 ] << 12 ) + ( (INT16)*p_n_mx[ 6 ] * (INT16)n_v1 ) + ( (INT16)*p_n_mx[ 7 ] * (INT16)n_v2 ) + ( (INT16)*p_n_mx[ 8 ] * (INT16)n_v3 ) ) >> n_sf );
+
+ IR1 = Lm_B1( (INT32)MAC1, n_lm );
+ IR2 = Lm_B2( (INT32)MAC2, n_lm );
+ IR3 = Lm_B3( (INT32)MAC3, n_lm );
+ return;
+ }
+ break;
+ case 0x13:
+ if( gteop == 0x0e80413 )
+ {
+ GTELOG( "NCDS" );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)(INT16)L11 * (INT16)VX0 ) + ( (INT16)L12 * (INT16)VY0 ) + ( (INT16)L13 * (INT16)VZ0 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)(INT16)L21 * (INT16)VX0 ) + ( (INT16)L22 * (INT16)VY0 ) + ( (INT16)L23 * (INT16)VZ0 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)(INT16)L31 * (INT16)VX0 ) + ( (INT16)L32 * (INT16)VY0 ) + ( (INT16)L33 * (INT16)VZ0 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( ( (INT64)RBK << 12 ) + ( (INT16)LR1 * (INT16)IR1 ) + ( (INT16)LR2 * (INT16)IR2 ) + ( (INT16)LR3 * (INT16)IR3 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)GBK << 12 ) + ( (INT16)LG1 * (INT16)IR1 ) + ( (INT16)LG2 * (INT16)IR2 ) + ( (INT16)LG3 * (INT16)IR3 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)BBK << 12 ) + ( (INT16)LB1 * (INT16)IR1 ) + ( (INT16)LB2 * (INT16)IR2 ) + ( (INT16)LB3 * (INT16)IR3 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( ( ( (INT64)R << 4 ) * (INT16)IR1 ) + ( (INT16)IR0 * Lm_B1( (INT32)RFC - ( ( R * (INT16)IR1 ) >> 8 ), 0 ) ) ) >> 12 );
+ MAC2 = A2( ( ( ( (INT64)G << 4 ) * (INT16)IR2 ) + ( (INT16)IR0 * Lm_B2( (INT32)GFC - ( ( G * (INT16)IR2 ) >> 8 ), 0 ) ) ) >> 12 );
+ MAC3 = A3( ( ( ( (INT64)B << 4 ) * (INT16)IR3 ) + ( (INT16)IR0 * Lm_B3( (INT32)BFC - ( ( B * (INT16)IR3 ) >> 8 ), 0 ) ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ return;
+ }
+ break;
+ case 0x14:
+ if( gteop == 0x1280414 )
+ {
+ GTELOG( "CDP" );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)RBK << 12 ) + ( (INT16)LR1 * (INT16)IR1 ) + ( (INT16)LR2 * (INT16)IR2 ) + ( (INT16)LR3 * (INT16)IR3 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)GBK << 12 ) + ( (INT16)LG1 * (INT16)IR1 ) + ( (INT16)LG2 * (INT16)IR2 ) + ( (INT16)LG3 * (INT16)IR3 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)BBK << 12 ) + ( (INT16)LB1 * (INT16)IR1 ) + ( (INT16)LB2 * (INT16)IR2 ) + ( (INT16)LB3 * (INT16)IR3 ) ) >> 12 );
+ IR1 = Lm_B1( MAC1, 1 );
+ IR2 = Lm_B2( MAC2, 1 );
+ IR3 = Lm_B3( MAC3, 1 );
+ MAC1 = A1( ( ( ( (INT64)R << 4 ) * (INT16)IR1 ) + ( (INT16)IR0 * Lm_B1( (INT32)RFC - ( ( R * (INT16)IR1 ) >> 8 ), 0 ) ) ) >> 12 );
+ MAC2 = A2( ( ( ( (INT64)G << 4 ) * (INT16)IR2 ) + ( (INT16)IR0 * Lm_B2( (INT32)GFC - ( ( G * (INT16)IR2 ) >> 8 ), 0 ) ) ) >> 12 );
+ MAC3 = A3( ( ( ( (INT64)B << 4 ) * (INT16)IR3 ) + ( (INT16)IR0 * Lm_B3( (INT32)BFC - ( ( B * (INT16)IR3 ) >> 8 ), 0 ) ) ) >> 12 );
+ IR1 = Lm_B1( MAC1, 1 );
+ IR2 = Lm_B2( MAC2, 1 );
+ IR3 = Lm_B3( MAC3, 1 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ return;
+ }
+ break;
+ case 0x16:
+ if( gteop == 0x0f80416 )
+ {
+ GTELOG( "NCDT" );
+ FLAG = 0;
+
+ for( n_v = 0; n_v < 3; n_v++ )
+ {
+ MAC1 = A1( ( ( (INT64)(INT16)L11 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)L12 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)L13 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)(INT16)L21 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)L22 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)L23 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)(INT16)L31 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)L32 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)L33 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( ( (INT64)RBK << 12 ) + ( (INT16)LR1 * (INT16)IR1 ) + ( (INT16)LR2 * (INT16)IR2 ) + ( (INT16)LR3 * (INT16)IR3 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)GBK << 12 ) + ( (INT16)LG1 * (INT16)IR1 ) + ( (INT16)LG2 * (INT16)IR2 ) + ( (INT16)LG3 * (INT16)IR3 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)BBK << 12 ) + ( (INT16)LB1 * (INT16)IR1 ) + ( (INT16)LB2 * (INT16)IR2 ) + ( (INT16)LB3 * (INT16)IR3 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( ( ( (INT64)R << 4 ) * (INT16)IR1 ) + ( (INT16)IR0 * Lm_B1( (INT32)RFC - ( ( R * (INT16)IR1 ) >> 8 ), 0 ) ) ) >> 12 );
+ MAC2 = A2( ( ( ( (INT64)G << 4 ) * (INT16)IR2 ) + ( (INT16)IR0 * Lm_B2( (INT32)GFC - ( ( G * (INT16)IR2 ) >> 8 ), 0 ) ) ) >> 12 );
+ MAC3 = A3( ( ( ( (INT64)B << 4 ) * (INT16)IR3 ) + ( (INT16)IR0 * Lm_B3( (INT32)BFC - ( ( B * (INT16)IR3 ) >> 8 ), 0 ) ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ }
+ return;
+ }
+ break;
+ case 0x1b:
+ if( gteop == 0x108041b )
+ {
+ GTELOG( "NCCS" );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)(INT16)L11 * (INT16)VX0 ) + ( (INT16)L12 * (INT16)VY0 ) + ( (INT16)L13 * (INT16)VZ0 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)(INT16)L21 * (INT16)VX0 ) + ( (INT16)L22 * (INT16)VY0 ) + ( (INT16)L23 * (INT16)VZ0 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)(INT16)L31 * (INT16)VX0 ) + ( (INT16)L32 * (INT16)VY0 ) + ( (INT16)L33 * (INT16)VZ0 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( ( (INT64)RBK << 12 ) + ( (INT16)LR1 * (INT16)IR1 ) + ( (INT16)LR2 * (INT16)IR2 ) + ( (INT16)LR3 * (INT16)IR3 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)GBK << 12 ) + ( (INT16)LG1 * (INT16)IR1 ) + ( (INT16)LG2 * (INT16)IR2 ) + ( (INT16)LG3 * (INT16)IR3 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)BBK << 12 ) + ( (INT16)LB1 * (INT16)IR1 ) + ( (INT16)LB2 * (INT16)IR2 ) + ( (INT16)LB3 * (INT16)IR3 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( (INT64)R * (INT16)IR1 ) >> 8 );
+ MAC2 = A2( ( (INT64)G * (INT16)IR2 ) >> 8 );
+ MAC3 = A3( ( (INT64)B * (INT16)IR3 ) >> 8 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ return;
+ }
+ break;
+ case 0x1c:
+ if( gteop == 0x138041c )
+ {
+ GTELOG( "CC" );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)RBK << 12 ) + ( (INT16)LR1 * (INT16)IR1 ) + ( (INT16)LR2 * (INT16)IR2 ) + ( (INT16)LR3 * (INT16)IR3 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)GBK << 12 ) + ( (INT16)LG1 * (INT16)IR1 ) + ( (INT16)LG2 * (INT16)IR2 ) + ( (INT16)LG3 * (INT16)IR3 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)BBK << 12 ) + ( (INT16)LB1 * (INT16)IR1 ) + ( (INT16)LB2 * (INT16)IR2 ) + ( (INT16)LB3 * (INT16)IR3 ) ) >> 12 );
+ IR1 = Lm_B1( MAC1, 1 );
+ IR2 = Lm_B2( MAC2, 1 );
+ IR3 = Lm_B3( MAC3, 1 );
+ MAC1 = A1( ( (INT64)R * (INT16)IR1 ) >> 8 );
+ MAC2 = A2( ( (INT64)G * (INT16)IR2 ) >> 8 );
+ MAC3 = A3( ( (INT64)B * (INT16)IR3 ) >> 8 );
+ IR1 = Lm_B1( MAC1, 1 );
+ IR2 = Lm_B2( MAC2, 1 );
+ IR3 = Lm_B3( MAC3, 1 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ return;
+ }
+ break;
+ case 0x1e:
+ if( gteop == 0x0c8041e )
+ {
+ GTELOG( "NCS" );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)(INT16)L11 * (INT16)VX0 ) + ( (INT16)L12 * (INT16)VY0 ) + ( (INT16)L13 * (INT16)VZ0 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)(INT16)L21 * (INT16)VX0 ) + ( (INT16)L22 * (INT16)VY0 ) + ( (INT16)L23 * (INT16)VZ0 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)(INT16)L31 * (INT16)VX0 ) + ( (INT16)L32 * (INT16)VY0 ) + ( (INT16)L33 * (INT16)VZ0 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( ( (INT64)RBK << 12 ) + ( (INT16)LR1 * (INT16)IR1 ) + ( (INT16)LR2 * (INT16)IR2 ) + ( (INT16)LR3 * (INT16)IR3 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)GBK << 12 ) + ( (INT16)LG1 * (INT16)IR1 ) + ( (INT16)LG2 * (INT16)IR2 ) + ( (INT16)LG3 * (INT16)IR3 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)BBK << 12 ) + ( (INT16)LB1 * (INT16)IR1 ) + ( (INT16)LB2 * (INT16)IR2 ) + ( (INT16)LB3 * (INT16)IR3 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ return;
+ }
+ break;
+ case 0x20:
+ if( gteop == 0x0d80420 )
+ {
+ GTELOG( "NCT" );
+ FLAG = 0;
+
+ for( n_v = 0; n_v < 3; n_v++ )
+ {
+ MAC1 = A1( ( ( (INT64)(INT16)L11 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)L12 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)L13 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)(INT16)L21 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)L22 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)L23 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)(INT16)L31 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)L32 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)L33 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( ( (INT64)RBK << 12 ) + ( (INT16)LR1 * (INT16)IR1 ) + ( (INT16)LR2 * (INT16)IR2 ) + ( (INT16)LR3 * (INT16)IR3 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)GBK << 12 ) + ( (INT16)LG1 * (INT16)IR1 ) + ( (INT16)LG2 * (INT16)IR2 ) + ( (INT16)LG3 * (INT16)IR3 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)BBK << 12 ) + ( (INT16)LB1 * (INT16)IR1 ) + ( (INT16)LB2 * (INT16)IR2 ) + ( (INT16)LB3 * (INT16)IR3 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ }
+ return;
+ }
+ break;
+ case 0x28:
+ if( GTE_OP( gteop ) == 0x0a && GTE_LM( gteop ) == 1 )
+ {
+ GTELOG( "SQR" );
+ n_sf = 12 * GTE_SF( gteop );
+ FLAG = 0;
+
+ MAC1 = A1( ( (INT64)(INT16)IR1 * (INT16)IR1 ) >> n_sf );
+ MAC2 = A2( ( (INT64)(INT16)IR2 * (INT16)IR2 ) >> n_sf );
+ MAC3 = A3( ( (INT64)(INT16)IR3 * (INT16)IR3 ) >> n_sf );
+ IR1 = Lm_B1( MAC1, 1 );
+ IR2 = Lm_B2( MAC2, 1 );
+ IR3 = Lm_B3( MAC3, 1 );
+ return;
+ }
+ break;
+ // DCPL 0x29
+ case 0x2a:
+ if( gteop == 0x0f8002a )
+ {
+ GTELOG( "DPCT" );
+ FLAG = 0;
+
+ for( n_pass = 0; n_pass < 3; n_pass++ )
+ {
+ MAC1 = A1( ( ( (INT64)R0 << 16 ) + ( (INT64)(INT16)IR0 * ( Lm_B1( (INT32)RFC - ( R0 << 4 ), 0 ) ) ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)G0 << 16 ) + ( (INT64)(INT16)IR0 * ( Lm_B1( (INT32)GFC - ( G0 << 4 ), 0 ) ) ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)B0 << 16 ) + ( (INT64)(INT16)IR0 * ( Lm_B1( (INT32)BFC - ( B0 << 4 ), 0 ) ) ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 0 );
+ IR2 = Lm_B2( (INT32)MAC2, 0 );
+ IR3 = Lm_B3( (INT32)MAC3, 0 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ }
+ return;
+ }
+ break;
+ case 0x2d:
+ if( gteop == 0x158002d )
+ {
+ GTELOG( "AVSZ3" );
+ FLAG = 0;
+
+ MAC0 = F( ( (INT64)(INT16)ZSF3 * SZ1 ) + ( (INT16)ZSF3 * SZ2 ) + ( (INT16)ZSF3 * SZ3 ) );
+ OTZ = Lm_D( (INT32)MAC0 >> 12 );
+ return;
+ }
+ break;
+ case 0x2e:
+ if( gteop == 0x168002e )
+ {
+ GTELOG( "AVSZ4" );
+ FLAG = 0;
+
+ MAC0 = F( ( (INT64)(INT16)ZSF4 * SZ0 ) + ( (INT16)ZSF4 * SZ1 ) + ( (INT16)ZSF4 * SZ2 ) + ( (INT16)ZSF4 * SZ3 ) );
+ OTZ = Lm_D( (INT32)MAC0 >> 12 );
+ return;
+ }
+ break;
+ case 0x30:
+ if( gteop == 0x0280030 )
+ {
+ GTELOG( "RTPT" );
+ FLAG = 0;
+
+ for( n_v = 0; n_v < 3; n_v++ )
+ {
+ MAC1 = A1( ( ( (INT64)(INT32)TRX << 12 ) + ( (INT16)R11 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)R12 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)R13 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)(INT32)TRY << 12 ) + ( (INT16)R21 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)R22 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)R23 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)(INT32)TRZ << 12 ) + ( (INT16)R31 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)R32 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)R33 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 0 );
+ IR2 = Lm_B2( (INT32)MAC2, 0 );
+ IR3 = Lm_B3( (INT32)MAC3, 0 );
+ SZ0 = SZ1;
+ SZ1 = SZ2;
+ SZ2 = SZ3;
+ SZ3 = Lm_D( (INT32)MAC3 );
+ SXY0 = SXY1;
+ SXY1 = SXY2;
+ SX2 = Lm_G1( F( ( (INT64)(INT32)OFX + ( (INT64)(INT16)IR1 * ( ( (UINT32)H << 16 ) / Lm_E( SZ3 ) ) ) ) >> 16 ) );
+ SY2 = Lm_G2( F( ( (INT64)(INT32)OFY + ( (INT64)(INT16)IR2 * ( ( (UINT32)H << 16 ) / Lm_E( SZ3 ) ) ) ) >> 16 ) );
+ MAC0 = F( (INT64)(INT32)DQB + ( (INT64)(INT16)DQA * ( ( (UINT32)H << 16 ) / Lm_E( SZ3 ) ) ) );
+ IR0 = Lm_H( (INT32)MAC0 >> 12 );
+ }
+ return;
+ }
+ break;
+ case 0x3d:
+ if( GTE_OP( gteop ) == 0x09 ||
+ GTE_OP( gteop ) == 0x19 )
+ {
+ GTELOG( "GPF" );
+ n_sf = 12 * GTE_SF( gteop );
+ FLAG = 0;
+
+ MAC1 = A1( ( (INT64)(INT16)IR0 * (INT16)IR1 ) >> n_sf );
+ MAC2 = A2( ( (INT64)(INT16)IR0 * (INT16)IR2 ) >> n_sf );
+ MAC3 = A3( ( (INT64)(INT16)IR0 * (INT16)IR3 ) >> n_sf );
+ IR1 = Lm_B1( (INT32)MAC1, 0 );
+ IR2 = Lm_B2( (INT32)MAC2, 0 );
+ IR3 = Lm_B3( (INT32)MAC3, 0 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ return;
+ }
+ break;
+ case 0x3e:
+ if( GTE_OP( gteop ) == 0x1a )
+ {
+ GTELOG( "GPL" );
+ n_sf = 12 * GTE_SF( gteop );
+ FLAG = 0;
+
+ MAC1 = A1( ( ( (INT64)(INT32)MAC1 << n_sf ) + ( (INT16)IR0 * (INT16)IR1 ) ) >> n_sf );
+ MAC2 = A2( ( ( (INT64)(INT32)MAC2 << n_sf ) + ( (INT16)IR0 * (INT16)IR2 ) ) >> n_sf );
+ MAC3 = A3( ( ( (INT64)(INT32)MAC3 << n_sf ) + ( (INT16)IR0 * (INT16)IR3 ) ) >> n_sf );
+ IR1 = Lm_B1( (INT32)MAC1, 0 );
+ IR2 = Lm_B2( (INT32)MAC2, 0 );
+ IR3 = Lm_B3( (INT32)MAC3, 0 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ return;
+ }
+ break;
+ case 0x3f:
+ if( gteop == 0x108043f ||
+ gteop == 0x118043f )
+ {
+ GTELOG( "NCCT" );
+ FLAG = 0;
+
+ for( n_v = 0; n_v < 3; n_v++ )
+ {
+ MAC1 = A1( ( ( (INT64)(INT16)L11 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)L12 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)L13 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)(INT16)L21 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)L22 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)L23 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)(INT16)L31 * (INT16)*p_n_vx[ n_v ] ) + ( (INT16)L32 * (INT16)*p_n_vy[ n_v ] ) + ( (INT16)L33 * (INT16)*p_n_vz[ n_v ] ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( ( (INT64)RBK << 12 ) + ( (INT16)LR1 * (INT16)IR1 ) + ( (INT16)LR2 * (INT16)IR2 ) + ( (INT16)LR3 * (INT16)IR3 ) ) >> 12 );
+ MAC2 = A2( ( ( (INT64)GBK << 12 ) + ( (INT16)LG1 * (INT16)IR1 ) + ( (INT16)LG2 * (INT16)IR2 ) + ( (INT16)LG3 * (INT16)IR3 ) ) >> 12 );
+ MAC3 = A3( ( ( (INT64)BBK << 12 ) + ( (INT16)LB1 * (INT16)IR1 ) + ( (INT16)LB2 * (INT16)IR2 ) + ( (INT16)LB3 * (INT16)IR3 ) ) >> 12 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ MAC1 = A1( ( (INT64)R * (INT16)IR1 ) >> 8 );
+ MAC2 = A2( ( (INT64)G * (INT16)IR2 ) >> 8 );
+ MAC3 = A3( ( (INT64)B * (INT16)IR3 ) >> 8 );
+ IR1 = Lm_B1( (INT32)MAC1, 1 );
+ IR2 = Lm_B2( (INT32)MAC2, 1 );
+ IR3 = Lm_B3( (INT32)MAC3, 1 );
+ CD0 = CD1;
+ CD1 = CD2;
+ CD2 = CODE;
+ R0 = R1;
+ R1 = R2;
+ R2 = Lm_C1( (INT32)MAC1 >> 4 );
+ G0 = G1;
+ G1 = G2;
+ G2 = Lm_C2( (INT32)MAC2 >> 4 );
+ B0 = B1;
+ B1 = B2;
+ B2 = Lm_C3( (INT32)MAC3 >> 4 );
+ }
+ return;
+ }
+ break;
+ }
+ ui_popup_time( 1, "unknown GTE op %08x", gteop );
+ logerror( "%08x: unknown GTE op %08x\n", mipscpu.pc, gteop );
+ mips_stop();
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void mips_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ0: set_irq_line(MIPS_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ1: set_irq_line(MIPS_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ2: set_irq_line(MIPS_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ3: set_irq_line(MIPS_IRQ3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ4: set_irq_line(MIPS_IRQ4, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ5: set_irq_line(MIPS_IRQ5, info->i); break;
+
+ case CPUINFO_INT_PC: mips_set_pc( info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_PC: mips_set_pc( info->i ); break;
+ case CPUINFO_INT_SP: /* no stack */ break;
+ case CPUINFO_INT_REGISTER + MIPS_DELAYV: mipscpu.delayv = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_DELAYR: if( info->i <= REGPC ) mipscpu.delayr = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_HI: mipscpu.hi = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_LO: mipscpu.lo = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R0: mipscpu.r[ 0 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R1: mipscpu.r[ 1 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R2: mipscpu.r[ 2 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R3: mipscpu.r[ 3 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R4: mipscpu.r[ 4 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R5: mipscpu.r[ 5 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R6: mipscpu.r[ 6 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R7: mipscpu.r[ 7 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R8: mipscpu.r[ 8 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R9: mipscpu.r[ 9 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R10: mipscpu.r[ 10 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R11: mipscpu.r[ 11 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R12: mipscpu.r[ 12 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R13: mipscpu.r[ 13 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R14: mipscpu.r[ 14 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R15: mipscpu.r[ 15 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R16: mipscpu.r[ 16 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R17: mipscpu.r[ 17 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R18: mipscpu.r[ 18 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R19: mipscpu.r[ 19 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R20: mipscpu.r[ 20 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R21: mipscpu.r[ 21 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R22: mipscpu.r[ 22 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R23: mipscpu.r[ 23 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R24: mipscpu.r[ 24 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R25: mipscpu.r[ 25 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R26: mipscpu.r[ 26 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R27: mipscpu.r[ 27 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R28: mipscpu.r[ 28 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R29: mipscpu.r[ 29 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R30: mipscpu.r[ 30 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_R31: mipscpu.r[ 31 ] = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R0: mips_set_cp0r( 0, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R1: mips_set_cp0r( 1, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R2: mips_set_cp0r( 2, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R3: mips_set_cp0r( 3, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R4: mips_set_cp0r( 4, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R5: mips_set_cp0r( 5, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R6: mips_set_cp0r( 6, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R7: mips_set_cp0r( 7, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R8: mips_set_cp0r( 8, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R9: mips_set_cp0r( 9, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R10: mips_set_cp0r( 10, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R11: mips_set_cp0r( 11, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R12: mips_set_cp0r( 12, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R13: mips_set_cp0r( 13, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R14: mips_set_cp0r( 14, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R15: mips_set_cp0r( 15, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R16: mips_set_cp0r( 16, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R17: mips_set_cp0r( 17, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R18: mips_set_cp0r( 18, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R19: mips_set_cp0r( 19, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R20: mips_set_cp0r( 20, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R21: mips_set_cp0r( 21, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R22: mips_set_cp0r( 22, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R23: mips_set_cp0r( 23, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R24: mips_set_cp0r( 24, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R25: mips_set_cp0r( 25, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R26: mips_set_cp0r( 26, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R27: mips_set_cp0r( 27, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R28: mips_set_cp0r( 28, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R29: mips_set_cp0r( 29, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R30: mips_set_cp0r( 30, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R31: mips_set_cp0r( 31, info->i ); break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR0: mipscpu.cp2dr[ 0 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR1: mipscpu.cp2dr[ 1 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR2: mipscpu.cp2dr[ 2 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR3: mipscpu.cp2dr[ 3 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR4: mipscpu.cp2dr[ 4 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR5: mipscpu.cp2dr[ 5 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR6: mipscpu.cp2dr[ 6 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR7: mipscpu.cp2dr[ 7 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR8: mipscpu.cp2dr[ 8 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR9: mipscpu.cp2dr[ 9 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR10: mipscpu.cp2dr[ 10 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR11: mipscpu.cp2dr[ 11 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR12: mipscpu.cp2dr[ 12 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR13: mipscpu.cp2dr[ 13 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR14: mipscpu.cp2dr[ 14 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR15: mipscpu.cp2dr[ 15 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR16: mipscpu.cp2dr[ 16 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR17: mipscpu.cp2dr[ 17 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR18: mipscpu.cp2dr[ 18 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR19: mipscpu.cp2dr[ 19 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR20: mipscpu.cp2dr[ 20 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR21: mipscpu.cp2dr[ 21 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR22: mipscpu.cp2dr[ 22 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR23: mipscpu.cp2dr[ 23 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR24: mipscpu.cp2dr[ 24 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR25: mipscpu.cp2dr[ 25 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR26: mipscpu.cp2dr[ 26 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR27: mipscpu.cp2dr[ 27 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR28: mipscpu.cp2dr[ 28 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR29: mipscpu.cp2dr[ 29 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR30: mipscpu.cp2dr[ 30 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR31: mipscpu.cp2dr[ 31 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR0: mipscpu.cp2cr[ 0 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR1: mipscpu.cp2cr[ 1 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR2: mipscpu.cp2cr[ 2 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR3: mipscpu.cp2cr[ 3 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR4: mipscpu.cp2cr[ 4 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR5: mipscpu.cp2cr[ 5 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR6: mipscpu.cp2cr[ 6 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR7: mipscpu.cp2cr[ 7 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR8: mipscpu.cp2cr[ 8 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR9: mipscpu.cp2cr[ 9 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR10: mipscpu.cp2cr[ 10 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR11: mipscpu.cp2cr[ 11 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR12: mipscpu.cp2cr[ 12 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR13: mipscpu.cp2cr[ 13 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR14: mipscpu.cp2cr[ 14 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR15: mipscpu.cp2cr[ 15 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR16: mipscpu.cp2cr[ 16 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR17: mipscpu.cp2cr[ 17 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR18: mipscpu.cp2cr[ 18 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR19: mipscpu.cp2cr[ 19 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR20: mipscpu.cp2cr[ 20 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR21: mipscpu.cp2cr[ 21 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR22: mipscpu.cp2cr[ 22 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR23: mipscpu.cp2cr[ 23 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR24: mipscpu.cp2cr[ 24 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR25: mipscpu.cp2cr[ 25 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR26: mipscpu.cp2cr[ 26 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR27: mipscpu.cp2cr[ 27 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR28: mipscpu.cp2cr[ 28 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR29: mipscpu.cp2cr[ 29 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR30: mipscpu.cp2cr[ 30 ].d = info->i; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR31: mipscpu.cp2cr[ 31 ].d = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void mips_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(mipscpu); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 6; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ0: info->i = (mipscpu.cp0r[ CP0_CAUSE ] & 0x400) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ1: info->i = (mipscpu.cp0r[ CP0_CAUSE ] & 0x800) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ2: info->i = (mipscpu.cp0r[ CP0_CAUSE ] & 0x1000) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ3: info->i = (mipscpu.cp0r[ CP0_CAUSE ] & 0x2000) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ4: info->i = (mipscpu.cp0r[ CP0_CAUSE ] & 0x4000) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + MIPS_IRQ5: info->i = (mipscpu.cp0r[ CP0_CAUSE ] & 0x8000) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC: info->i = mipscpu.pc; break;
+ case CPUINFO_INT_REGISTER + MIPS_PC: info->i = mipscpu.pc; break;
+ case CPUINFO_INT_SP:
+ /* because there is no hardware stack and the pipeline causes the cpu to execute the
+ instruction after a subroutine call before the subroutine is executed there is little
+ chance of cmd_step_over() in mamedbg.c working. */
+ info->i = 0; break;
+ case CPUINFO_INT_REGISTER + MIPS_DELAYV: info->i = mipscpu.delayv; break;
+ case CPUINFO_INT_REGISTER + MIPS_DELAYR: info->i = mipscpu.delayr; break;
+ case CPUINFO_INT_REGISTER + MIPS_HI: info->i = mipscpu.hi; break;
+ case CPUINFO_INT_REGISTER + MIPS_LO: info->i = mipscpu.lo; break;
+ case CPUINFO_INT_REGISTER + MIPS_R0: info->i = mipscpu.r[ 0 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R1: info->i = mipscpu.r[ 1 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R2: info->i = mipscpu.r[ 2 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R3: info->i = mipscpu.r[ 3 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R4: info->i = mipscpu.r[ 4 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R5: info->i = mipscpu.r[ 5 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R6: info->i = mipscpu.r[ 6 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R7: info->i = mipscpu.r[ 7 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R8: info->i = mipscpu.r[ 8 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R9: info->i = mipscpu.r[ 9 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R10: info->i = mipscpu.r[ 10 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R11: info->i = mipscpu.r[ 11 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R12: info->i = mipscpu.r[ 12 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R13: info->i = mipscpu.r[ 13 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R14: info->i = mipscpu.r[ 14 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R15: info->i = mipscpu.r[ 15 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R16: info->i = mipscpu.r[ 16 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R17: info->i = mipscpu.r[ 17 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R18: info->i = mipscpu.r[ 18 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R19: info->i = mipscpu.r[ 19 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R20: info->i = mipscpu.r[ 20 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R21: info->i = mipscpu.r[ 21 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R22: info->i = mipscpu.r[ 22 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R23: info->i = mipscpu.r[ 23 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R24: info->i = mipscpu.r[ 24 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R25: info->i = mipscpu.r[ 25 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R26: info->i = mipscpu.r[ 26 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R27: info->i = mipscpu.r[ 27 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R28: info->i = mipscpu.r[ 28 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R29: info->i = mipscpu.r[ 29 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R30: info->i = mipscpu.r[ 30 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_R31: info->i = mipscpu.r[ 31 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R0: info->i = mipscpu.cp0r[ 0 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R1: info->i = mipscpu.cp0r[ 1 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R2: info->i = mipscpu.cp0r[ 2 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R3: info->i = mipscpu.cp0r[ 3 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R4: info->i = mipscpu.cp0r[ 4 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R5: info->i = mipscpu.cp0r[ 5 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R6: info->i = mipscpu.cp0r[ 6 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R7: info->i = mipscpu.cp0r[ 7 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R8: info->i = mipscpu.cp0r[ 8 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R9: info->i = mipscpu.cp0r[ 9 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R10: info->i = mipscpu.cp0r[ 10 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R11: info->i = mipscpu.cp0r[ 11 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R12: info->i = mipscpu.cp0r[ 12 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R13: info->i = mipscpu.cp0r[ 13 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R14: info->i = mipscpu.cp0r[ 14 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R15: info->i = mipscpu.cp0r[ 15 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R16: info->i = mipscpu.cp0r[ 16 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R17: info->i = mipscpu.cp0r[ 17 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R18: info->i = mipscpu.cp0r[ 18 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R19: info->i = mipscpu.cp0r[ 19 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R20: info->i = mipscpu.cp0r[ 20 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R21: info->i = mipscpu.cp0r[ 21 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R22: info->i = mipscpu.cp0r[ 22 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R23: info->i = mipscpu.cp0r[ 23 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R24: info->i = mipscpu.cp0r[ 24 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R25: info->i = mipscpu.cp0r[ 25 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R26: info->i = mipscpu.cp0r[ 26 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R27: info->i = mipscpu.cp0r[ 27 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R28: info->i = mipscpu.cp0r[ 28 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R29: info->i = mipscpu.cp0r[ 29 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R30: info->i = mipscpu.cp0r[ 30 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP0R31: info->i = mipscpu.cp0r[ 31 ]; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR0: info->i = mipscpu.cp2dr[ 0 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR1: info->i = mipscpu.cp2dr[ 1 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR2: info->i = mipscpu.cp2dr[ 2 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR3: info->i = mipscpu.cp2dr[ 3 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR4: info->i = mipscpu.cp2dr[ 4 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR5: info->i = mipscpu.cp2dr[ 5 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR6: info->i = mipscpu.cp2dr[ 6 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR7: info->i = mipscpu.cp2dr[ 7 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR8: info->i = mipscpu.cp2dr[ 8 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR9: info->i = mipscpu.cp2dr[ 9 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR10: info->i = mipscpu.cp2dr[ 10 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR11: info->i = mipscpu.cp2dr[ 11 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR12: info->i = mipscpu.cp2dr[ 12 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR13: info->i = mipscpu.cp2dr[ 13 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR14: info->i = mipscpu.cp2dr[ 14 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR15: info->i = mipscpu.cp2dr[ 15 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR16: info->i = mipscpu.cp2dr[ 16 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR17: info->i = mipscpu.cp2dr[ 17 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR18: info->i = mipscpu.cp2dr[ 18 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR19: info->i = mipscpu.cp2dr[ 19 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR20: info->i = mipscpu.cp2dr[ 20 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR21: info->i = mipscpu.cp2dr[ 21 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR22: info->i = mipscpu.cp2dr[ 22 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR23: info->i = mipscpu.cp2dr[ 23 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR24: info->i = mipscpu.cp2dr[ 24 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR25: info->i = mipscpu.cp2dr[ 25 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR26: info->i = mipscpu.cp2dr[ 26 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR27: info->i = mipscpu.cp2dr[ 27 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR28: info->i = mipscpu.cp2dr[ 28 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR29: info->i = mipscpu.cp2dr[ 29 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR30: info->i = mipscpu.cp2dr[ 30 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2DR31: info->i = mipscpu.cp2dr[ 31 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR0: info->i = mipscpu.cp2cr[ 0 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR1: info->i = mipscpu.cp2cr[ 1 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR2: info->i = mipscpu.cp2cr[ 2 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR3: info->i = mipscpu.cp2cr[ 3 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR4: info->i = mipscpu.cp2cr[ 4 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR5: info->i = mipscpu.cp2cr[ 5 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR6: info->i = mipscpu.cp2cr[ 6 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR7: info->i = mipscpu.cp2cr[ 7 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR8: info->i = mipscpu.cp2cr[ 8 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR9: info->i = mipscpu.cp2cr[ 9 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR10: info->i = mipscpu.cp2cr[ 10 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR11: info->i = mipscpu.cp2cr[ 11 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR12: info->i = mipscpu.cp2cr[ 12 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR13: info->i = mipscpu.cp2cr[ 13 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR14: info->i = mipscpu.cp2cr[ 14 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR15: info->i = mipscpu.cp2cr[ 15 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR16: info->i = mipscpu.cp2cr[ 16 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR17: info->i = mipscpu.cp2cr[ 17 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR18: info->i = mipscpu.cp2cr[ 18 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR19: info->i = mipscpu.cp2cr[ 19 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR20: info->i = mipscpu.cp2cr[ 20 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR21: info->i = mipscpu.cp2cr[ 21 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR22: info->i = mipscpu.cp2cr[ 22 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR23: info->i = mipscpu.cp2cr[ 23 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR24: info->i = mipscpu.cp2cr[ 24 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR25: info->i = mipscpu.cp2cr[ 25 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR26: info->i = mipscpu.cp2cr[ 26 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR27: info->i = mipscpu.cp2cr[ 27 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR28: info->i = mipscpu.cp2cr[ 28 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR29: info->i = mipscpu.cp2cr[ 29 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR30: info->i = mipscpu.cp2cr[ 30 ].d; break;
+ case CPUINFO_INT_REGISTER + MIPS_CP2CR31: info->i = mipscpu.cp2cr[ 31 ].d; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mips_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = mips_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = mips_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = mips_init; break;
+ case CPUINFO_PTR_RESET: info->reset = mips_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = mips_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = mips_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = mips_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &mips_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PSX CPU"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "mipscpu"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.5"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright 2005 smf"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + MIPS_PC: sprintf( info->s, "pc :%08x", mipscpu.pc ); break;
+ case CPUINFO_STR_REGISTER + MIPS_DELAYV: sprintf( info->s, "delay :%08x", mipscpu.delayv ); break;
+ case CPUINFO_STR_REGISTER + MIPS_DELAYR: sprintf( info->s, "delay %s:%02x", delayn[ mipscpu.delayr ], mipscpu.delayr ); break;
+ case CPUINFO_STR_REGISTER + MIPS_HI: sprintf( info->s, "hi :%08x", mipscpu.hi ); break;
+ case CPUINFO_STR_REGISTER + MIPS_LO: sprintf( info->s, "lo :%08x", mipscpu.lo ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R0: sprintf( info->s, "zero :%08x", mipscpu.r[ 0 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R1: sprintf( info->s, "at :%08x", mipscpu.r[ 1 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R2: sprintf( info->s, "v0 :%08x", mipscpu.r[ 2 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R3: sprintf( info->s, "v1 :%08x", mipscpu.r[ 3 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R4: sprintf( info->s, "a0 :%08x", mipscpu.r[ 4 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R5: sprintf( info->s, "a1 :%08x", mipscpu.r[ 5 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R6: sprintf( info->s, "a2 :%08x", mipscpu.r[ 6 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R7: sprintf( info->s, "a3 :%08x", mipscpu.r[ 7 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R8: sprintf( info->s, "t0 :%08x", mipscpu.r[ 8 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R9: sprintf( info->s, "t1 :%08x", mipscpu.r[ 9 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R10: sprintf( info->s, "t2 :%08x", mipscpu.r[ 10 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R11: sprintf( info->s, "t3 :%08x", mipscpu.r[ 11 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R12: sprintf( info->s, "t4 :%08x", mipscpu.r[ 12 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R13: sprintf( info->s, "t5 :%08x", mipscpu.r[ 13 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R14: sprintf( info->s, "t6 :%08x", mipscpu.r[ 14 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R15: sprintf( info->s, "t7 :%08x", mipscpu.r[ 15 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R16: sprintf( info->s, "s0 :%08x", mipscpu.r[ 16 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R17: sprintf( info->s, "s1 :%08x", mipscpu.r[ 17 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R18: sprintf( info->s, "s2 :%08x", mipscpu.r[ 18 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R19: sprintf( info->s, "s3 :%08x", mipscpu.r[ 19 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R20: sprintf( info->s, "s4 :%08x", mipscpu.r[ 20 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R21: sprintf( info->s, "s5 :%08x", mipscpu.r[ 21 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R22: sprintf( info->s, "s6 :%08x", mipscpu.r[ 22 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R23: sprintf( info->s, "s7 :%08x", mipscpu.r[ 23 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R24: sprintf( info->s, "t8 :%08x", mipscpu.r[ 24 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R25: sprintf( info->s, "t9 :%08x", mipscpu.r[ 25 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R26: sprintf( info->s, "k0 :%08x", mipscpu.r[ 26 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R27: sprintf( info->s, "k1 :%08x", mipscpu.r[ 27 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R28: sprintf( info->s, "gp :%08x", mipscpu.r[ 28 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R29: sprintf( info->s, "sp :%08x", mipscpu.r[ 29 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R30: sprintf( info->s, "fp :%08x", mipscpu.r[ 30 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_R31: sprintf( info->s, "ra :%08x", mipscpu.r[ 31 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R0: sprintf( info->s, "Index :%08x", mipscpu.cp0r[ 0 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R1: sprintf( info->s, "Random :%08x", mipscpu.cp0r[ 1 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R2: sprintf( info->s, "EntryLo :%08x", mipscpu.cp0r[ 2 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R3: sprintf( info->s, "cp0r3 :%08x", mipscpu.cp0r[ 3 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R4: sprintf( info->s, "Context :%08x", mipscpu.cp0r[ 4 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R5: sprintf( info->s, "cp0r5 :%08x", mipscpu.cp0r[ 5 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R6: sprintf( info->s, "cp0r6 :%08x", mipscpu.cp0r[ 6 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R7: sprintf( info->s, "cp0r7 :%08x", mipscpu.cp0r[ 7 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R8: sprintf( info->s, "BadVAddr:%08x", mipscpu.cp0r[ 8 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R9: sprintf( info->s, "cp0r9 :%08x", mipscpu.cp0r[ 9 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R10: sprintf( info->s, "EntryHi :%08x", mipscpu.cp0r[ 10 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R11: sprintf( info->s, "cp0r11 :%08x", mipscpu.cp0r[ 11 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R12: sprintf( info->s, "SR :%08x", mipscpu.cp0r[ 12 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R13: sprintf( info->s, "Cause :%08x", mipscpu.cp0r[ 13 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R14: sprintf( info->s, "EPC :%08x", mipscpu.cp0r[ 14 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R15: sprintf( info->s, "PRId :%08x", mipscpu.cp0r[ 15 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R16: sprintf( info->s, "cp0r16 :%08x", mipscpu.cp0r[ 16 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R17: sprintf( info->s, "cp0r17 :%08x", mipscpu.cp0r[ 17 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R18: sprintf( info->s, "cp0r18 :%08x", mipscpu.cp0r[ 18 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R19: sprintf( info->s, "cp0r19 :%08x", mipscpu.cp0r[ 19 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R20: sprintf( info->s, "cp0r20 :%08x", mipscpu.cp0r[ 20 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R21: sprintf( info->s, "cp0r21 :%08x", mipscpu.cp0r[ 21 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R22: sprintf( info->s, "cp0r22 :%08x", mipscpu.cp0r[ 22 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R23: sprintf( info->s, "cp0r23 :%08x", mipscpu.cp0r[ 23 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R24: sprintf( info->s, "cp0r24 :%08x", mipscpu.cp0r[ 24 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R25: sprintf( info->s, "cp0r25 :%08x", mipscpu.cp0r[ 25 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R26: sprintf( info->s, "cp0r26 :%08x", mipscpu.cp0r[ 26 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R27: sprintf( info->s, "cp0r27 :%08x", mipscpu.cp0r[ 27 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R28: sprintf( info->s, "cp0r28 :%08x", mipscpu.cp0r[ 28 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R29: sprintf( info->s, "cp0r29 :%08x", mipscpu.cp0r[ 29 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R30: sprintf( info->s, "cp0r30 :%08x", mipscpu.cp0r[ 30 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP0R31: sprintf( info->s, "cp0r31 :%08x", mipscpu.cp0r[ 31 ] ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR0: sprintf( info->s, "vxy0 :%08x", mipscpu.cp2dr[ 0 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR1: sprintf( info->s, "vz0 :%08x", mipscpu.cp2dr[ 1 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR2: sprintf( info->s, "vxy1 :%08x", mipscpu.cp2dr[ 2 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR3: sprintf( info->s, "vz1 :%08x", mipscpu.cp2dr[ 3 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR4: sprintf( info->s, "vxy2 :%08x", mipscpu.cp2dr[ 4 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR5: sprintf( info->s, "vz2 :%08x", mipscpu.cp2dr[ 5 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR6: sprintf( info->s, "rgb :%08x", mipscpu.cp2dr[ 6 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR7: sprintf( info->s, "otz :%08x", mipscpu.cp2dr[ 7 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR8: sprintf( info->s, "ir0 :%08x", mipscpu.cp2dr[ 8 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR9: sprintf( info->s, "ir1 :%08x", mipscpu.cp2dr[ 9 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR10: sprintf( info->s, "ir2 :%08x", mipscpu.cp2dr[ 10 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR11: sprintf( info->s, "ir3 :%08x", mipscpu.cp2dr[ 11 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR12: sprintf( info->s, "sxy0 :%08x", mipscpu.cp2dr[ 12 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR13: sprintf( info->s, "sxy1 :%08x", mipscpu.cp2dr[ 13 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR14: sprintf( info->s, "sxy2 :%08x", mipscpu.cp2dr[ 14 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR15: sprintf( info->s, "sxyp :%08x", mipscpu.cp2dr[ 15 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR16: sprintf( info->s, "sz0 :%08x", mipscpu.cp2dr[ 16 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR17: sprintf( info->s, "sz1 :%08x", mipscpu.cp2dr[ 17 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR18: sprintf( info->s, "sz2 :%08x", mipscpu.cp2dr[ 18 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR19: sprintf( info->s, "sz3 :%08x", mipscpu.cp2dr[ 19 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR20: sprintf( info->s, "rgb0 :%08x", mipscpu.cp2dr[ 20 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR21: sprintf( info->s, "rgb1 :%08x", mipscpu.cp2dr[ 21 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR22: sprintf( info->s, "rgb2 :%08x", mipscpu.cp2dr[ 22 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR23: sprintf( info->s, "res1 :%08x", mipscpu.cp2dr[ 23 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR24: sprintf( info->s, "mac0 :%08x", mipscpu.cp2dr[ 24 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR25: sprintf( info->s, "mac1 :%08x", mipscpu.cp2dr[ 25 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR26: sprintf( info->s, "mac2 :%08x", mipscpu.cp2dr[ 26 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR27: sprintf( info->s, "mac3 :%08x", mipscpu.cp2dr[ 27 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR28: sprintf( info->s, "irgb :%08x", mipscpu.cp2dr[ 28 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR29: sprintf( info->s, "orgb :%08x", mipscpu.cp2dr[ 29 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR30: sprintf( info->s, "lzcs :%08x", mipscpu.cp2dr[ 30 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2DR31: sprintf( info->s, "lzcr :%08x", mipscpu.cp2dr[ 31 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR0: sprintf( info->s, "r11r12 :%08x", mipscpu.cp2cr[ 0 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR1: sprintf( info->s, "r13r21 :%08x", mipscpu.cp2cr[ 1 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR2: sprintf( info->s, "r22r23 :%08x", mipscpu.cp2cr[ 2 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR3: sprintf( info->s, "r31r32 :%08x", mipscpu.cp2cr[ 3 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR4: sprintf( info->s, "r33 :%08x", mipscpu.cp2cr[ 4 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR5: sprintf( info->s, "trx :%08x", mipscpu.cp2cr[ 5 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR6: sprintf( info->s, "try :%08x", mipscpu.cp2cr[ 6 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR7: sprintf( info->s, "trz :%08x", mipscpu.cp2cr[ 7 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR8: sprintf( info->s, "l11l12 :%08x", mipscpu.cp2cr[ 8 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR9: sprintf( info->s, "l13l21 :%08x", mipscpu.cp2cr[ 9 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR10: sprintf( info->s, "l22l23 :%08x", mipscpu.cp2cr[ 10 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR11: sprintf( info->s, "l31l32 :%08x", mipscpu.cp2cr[ 11 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR12: sprintf( info->s, "l33 :%08x", mipscpu.cp2cr[ 12 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR13: sprintf( info->s, "rbk :%08x", mipscpu.cp2cr[ 13 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR14: sprintf( info->s, "gbk :%08x", mipscpu.cp2cr[ 14 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR15: sprintf( info->s, "bbk :%08x", mipscpu.cp2cr[ 15 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR16: sprintf( info->s, "lr1lr2 :%08x", mipscpu.cp2cr[ 16 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR17: sprintf( info->s, "lr31g1 :%08x", mipscpu.cp2cr[ 17 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR18: sprintf( info->s, "lg2lg3 :%08x", mipscpu.cp2cr[ 18 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR19: sprintf( info->s, "lb1lb2 :%08x", mipscpu.cp2cr[ 19 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR20: sprintf( info->s, "lb3 :%08x", mipscpu.cp2cr[ 20 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR21: sprintf( info->s, "rfc :%08x", mipscpu.cp2cr[ 21 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR22: sprintf( info->s, "gfc :%08x", mipscpu.cp2cr[ 22 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR23: sprintf( info->s, "bfc :%08x", mipscpu.cp2cr[ 23 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR24: sprintf( info->s, "ofx :%08x", mipscpu.cp2cr[ 24 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR25: sprintf( info->s, "ofy :%08x", mipscpu.cp2cr[ 25 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR26: sprintf( info->s, "h :%08x", mipscpu.cp2cr[ 26 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR27: sprintf( info->s, "dqa :%08x", mipscpu.cp2cr[ 27 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR28: sprintf( info->s, "dqb :%08x", mipscpu.cp2cr[ 28 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR29: sprintf( info->s, "zsf3 :%08x", mipscpu.cp2cr[ 29 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR30: sprintf( info->s, "zsf4 :%08x", mipscpu.cp2cr[ 30 ].d ); break;
+ case CPUINFO_STR_REGISTER + MIPS_CP2CR31: sprintf( info->s, "flag :%08x", mipscpu.cp2cr[ 31 ].d ); break;
+ }
+}
+
+
+#if (HAS_PSXCPU)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void psxcpu_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PSX CPU"); break;
+
+ default:
+ mips_get_info(state, info);
+ break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/mips/psx.h b/src/emu/cpu/mips/psx.h
new file mode 100644
index 00000000000..e341480a3aa
--- /dev/null
+++ b/src/emu/cpu/mips/psx.h
@@ -0,0 +1,206 @@
+#ifndef _MIPS_H
+#define _MIPS_H
+
+#include "cpuintrf.h"
+
+enum
+{
+ MIPS_PC = 1,
+ MIPS_DELAYV, MIPS_DELAYR,
+ MIPS_HI, MIPS_LO,
+ MIPS_R0, MIPS_R1,
+ MIPS_R2, MIPS_R3,
+ MIPS_R4, MIPS_R5,
+ MIPS_R6, MIPS_R7,
+ MIPS_R8, MIPS_R9,
+ MIPS_R10, MIPS_R11,
+ MIPS_R12, MIPS_R13,
+ MIPS_R14, MIPS_R15,
+ MIPS_R16, MIPS_R17,
+ MIPS_R18, MIPS_R19,
+ MIPS_R20, MIPS_R21,
+ MIPS_R22, MIPS_R23,
+ MIPS_R24, MIPS_R25,
+ MIPS_R26, MIPS_R27,
+ MIPS_R28, MIPS_R29,
+ MIPS_R30, MIPS_R31,
+ MIPS_CP0R0, MIPS_CP0R1,
+ MIPS_CP0R2, MIPS_CP0R3,
+ MIPS_CP0R4, MIPS_CP0R5,
+ MIPS_CP0R6, MIPS_CP0R7,
+ MIPS_CP0R8, MIPS_CP0R9,
+ MIPS_CP0R10, MIPS_CP0R11,
+ MIPS_CP0R12, MIPS_CP0R13,
+ MIPS_CP0R14, MIPS_CP0R15,
+ MIPS_CP0R16, MIPS_CP0R17,
+ MIPS_CP0R18, MIPS_CP0R19,
+ MIPS_CP0R20, MIPS_CP0R21,
+ MIPS_CP0R22, MIPS_CP0R23,
+ MIPS_CP0R24, MIPS_CP0R25,
+ MIPS_CP0R26, MIPS_CP0R27,
+ MIPS_CP0R28, MIPS_CP0R29,
+ MIPS_CP0R30, MIPS_CP0R31,
+ MIPS_CP2DR0, MIPS_CP2DR1,
+ MIPS_CP2DR2, MIPS_CP2DR3,
+ MIPS_CP2DR4, MIPS_CP2DR5,
+ MIPS_CP2DR6, MIPS_CP2DR7,
+ MIPS_CP2DR8, MIPS_CP2DR9,
+ MIPS_CP2DR10, MIPS_CP2DR11,
+ MIPS_CP2DR12, MIPS_CP2DR13,
+ MIPS_CP2DR14, MIPS_CP2DR15,
+ MIPS_CP2DR16, MIPS_CP2DR17,
+ MIPS_CP2DR18, MIPS_CP2DR19,
+ MIPS_CP2DR20, MIPS_CP2DR21,
+ MIPS_CP2DR22, MIPS_CP2DR23,
+ MIPS_CP2DR24, MIPS_CP2DR25,
+ MIPS_CP2DR26, MIPS_CP2DR27,
+ MIPS_CP2DR28, MIPS_CP2DR29,
+ MIPS_CP2DR30, MIPS_CP2DR31,
+ MIPS_CP2CR0, MIPS_CP2CR1,
+ MIPS_CP2CR2, MIPS_CP2CR3,
+ MIPS_CP2CR4, MIPS_CP2CR5,
+ MIPS_CP2CR6, MIPS_CP2CR7,
+ MIPS_CP2CR8, MIPS_CP2CR9,
+ MIPS_CP2CR10, MIPS_CP2CR11,
+ MIPS_CP2CR12, MIPS_CP2CR13,
+ MIPS_CP2CR14, MIPS_CP2CR15,
+ MIPS_CP2CR16, MIPS_CP2CR17,
+ MIPS_CP2CR18, MIPS_CP2CR19,
+ MIPS_CP2CR20, MIPS_CP2CR21,
+ MIPS_CP2CR22, MIPS_CP2CR23,
+ MIPS_CP2CR24, MIPS_CP2CR25,
+ MIPS_CP2CR26, MIPS_CP2CR27,
+ MIPS_CP2CR28, MIPS_CP2CR29,
+ MIPS_CP2CR30, MIPS_CP2CR31
+};
+
+#define MIPS_INT_NONE ( -1 )
+
+#define MIPS_IRQ0 ( 0 )
+#define MIPS_IRQ1 ( 1 )
+#define MIPS_IRQ2 ( 2 )
+#define MIPS_IRQ3 ( 3 )
+#define MIPS_IRQ4 ( 4 )
+#define MIPS_IRQ5 ( 5 )
+
+#define MIPS_BYTE_EXTEND( a ) ( (INT32)(INT8)a )
+#define MIPS_WORD_EXTEND( a ) ( (INT32)(INT16)a )
+
+#define INS_OP( op ) ( ( op >> 26 ) & 63 )
+#define INS_RS( op ) ( ( op >> 21 ) & 31 )
+#define INS_RT( op ) ( ( op >> 16 ) & 31 )
+#define INS_IMMEDIATE( op ) ( op & 0xffff )
+#define INS_TARGET( op ) ( op & 0x3ffffff )
+#define INS_RD( op ) ( ( op >> 11 ) & 31 )
+#define INS_SHAMT( op ) ( ( op >> 6 ) & 31 )
+#define INS_FUNCT( op ) ( op & 63 )
+#define INS_CODE( op ) ( ( op >> 6 ) & 0xfffff )
+#define INS_CO( op ) ( ( op >> 25 ) & 1 )
+#define INS_COFUN( op ) ( op & 0x1ffffff )
+#define INS_CF( op ) ( op & 63 )
+
+#define GTE_OP( op ) ( ( op >> 20 ) & 31 )
+#define GTE_SF( op ) ( ( op >> 19 ) & 1 )
+#define GTE_MX( op ) ( ( op >> 17 ) & 3 )
+#define GTE_V( op ) ( ( op >> 15 ) & 3 )
+#define GTE_CV( op ) ( ( op >> 13 ) & 3 )
+#define GTE_CD( op ) ( ( op >> 11 ) & 3 ) /* not used */
+#define GTE_LM( op ) ( ( op >> 10 ) & 1 )
+#define GTE_CT( op ) ( ( op >> 6 ) & 15 ) /* not used */
+#define GTE_FUNCT( op ) ( op & 63 )
+
+#define OP_SPECIAL ( 0 )
+#define OP_REGIMM ( 1 )
+#define OP_J ( 2 )
+#define OP_JAL ( 3 )
+#define OP_BEQ ( 4 )
+#define OP_BNE ( 5 )
+#define OP_BLEZ ( 6 )
+#define OP_BGTZ ( 7 )
+#define OP_ADDI ( 8 )
+#define OP_ADDIU ( 9 )
+#define OP_SLTI ( 10 )
+#define OP_SLTIU ( 11 )
+#define OP_ANDI ( 12 )
+#define OP_ORI ( 13 )
+#define OP_XORI ( 14 )
+#define OP_LUI ( 15 )
+#define OP_COP0 ( 16 )
+#define OP_COP1 ( 17 )
+#define OP_COP2 ( 18 )
+#define OP_LB ( 32 )
+#define OP_LH ( 33 )
+#define OP_LWL ( 34 )
+#define OP_LW ( 35 )
+#define OP_LBU ( 36 )
+#define OP_LHU ( 37 )
+#define OP_LWR ( 38 )
+#define OP_SB ( 40 )
+#define OP_SH ( 41 )
+#define OP_SWL ( 42 )
+#define OP_SW ( 43 )
+#define OP_SWR ( 46 )
+#define OP_LWC1 ( 49 )
+#define OP_LWC2 ( 50 )
+#define OP_SWC1 ( 57 )
+#define OP_SWC2 ( 58 )
+
+/* OP_SPECIAL */
+#define FUNCT_SLL ( 0 )
+#define FUNCT_SRL ( 2 )
+#define FUNCT_SRA ( 3 )
+#define FUNCT_SLLV ( 4 )
+#define FUNCT_SRLV ( 6 )
+#define FUNCT_SRAV ( 7 )
+#define FUNCT_JR ( 8 )
+#define FUNCT_JALR ( 9 )
+#define FUNCT_SYSCALL ( 12 )
+#define FUNCT_BREAK ( 13 )
+#define FUNCT_MFHI ( 16 )
+#define FUNCT_MTHI ( 17 )
+#define FUNCT_MFLO ( 18 )
+#define FUNCT_MTLO ( 19 )
+#define FUNCT_MULT ( 24 )
+#define FUNCT_MULTU ( 25 )
+#define FUNCT_DIV ( 26 )
+#define FUNCT_DIVU ( 27 )
+#define FUNCT_ADD ( 32 )
+#define FUNCT_ADDU ( 33 )
+#define FUNCT_SUB ( 34 )
+#define FUNCT_SUBU ( 35 )
+#define FUNCT_AND ( 36 )
+#define FUNCT_OR ( 37 )
+#define FUNCT_XOR ( 38 )
+#define FUNCT_NOR ( 39 )
+#define FUNCT_SLT ( 42 )
+#define FUNCT_SLTU ( 43 )
+
+/* OP_REGIMM */
+#define RT_BLTZ ( 0 )
+#define RT_BGEZ ( 1 )
+#define RT_BLTZAL ( 16 )
+#define RT_BGEZAL ( 17 )
+
+/* OP_COP0/OP_COP1/OP_COP2 */
+#define RS_MFC ( 0 )
+#define RS_CFC ( 2 )
+#define RS_MTC ( 4 )
+#define RS_CTC ( 6 )
+#define RS_BC ( 8 )
+
+/* RS_BC */
+#define RT_BCF ( 0 )
+#define RT_BCT ( 1 )
+
+/* OP_COP0 */
+#define CF_RFE ( 16 )
+
+#ifdef MAME_DEBUG
+extern unsigned DasmMIPS( char *buffer, UINT32 pc, const UINT8 *opram );
+#endif
+
+#if (HAS_PSXCPU)
+extern void psxcpu_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#endif
diff --git a/src/emu/cpu/mips/r3000.c b/src/emu/cpu/mips/r3000.c
new file mode 100644
index 00000000000..afc2595869b
--- /dev/null
+++ b/src/emu/cpu/mips/r3000.c
@@ -0,0 +1,1379 @@
+/***************************************************************************
+
+ r3000.c
+ Core implementation for the portable MIPS R3000 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#include "debugger.h"
+#include "r3000.h"
+
+
+#define ENABLE_OVERFLOWS 0
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define COP0_Index 0
+#define COP0_Random 1
+#define COP0_EntryLo 2
+#define COP0_Context 4
+#define COP0_BadVAddr 8
+#define COP0_Status 12
+#define COP0_Cause 13
+#define COP0_EPC 14
+#define COP0_PRId 15
+
+#define SR_IEc 0x00000001
+#define SR_KUc 0x00000002
+#define SR_IEp 0x00000004
+#define SR_KUp 0x00000008
+#define SR_IEo 0x00000010
+#define SR_KUo 0x00000020
+#define SR_IMSW0 0x00000100
+#define SR_IMSW1 0x00000200
+#define SR_IMEX0 0x00000400
+#define SR_IMEX1 0x00000800
+#define SR_IMEX2 0x00001000
+#define SR_IMEX3 0x00002000
+#define SR_IMEX4 0x00004000
+#define SR_IMEX5 0x00008000
+#define SR_IsC 0x00010000
+#define SR_SwC 0x00020000
+#define SR_PZ 0x00040000
+#define SR_CM 0x00080000
+#define SR_PE 0x00100000
+#define SR_TS 0x00200000
+#define SR_BEV 0x00400000
+#define SR_RE 0x02000000
+#define SR_COP0 0x10000000
+#define SR_COP1 0x20000000
+#define SR_COP2 0x40000000
+#define SR_COP3 0x80000000
+
+#define EXCEPTION_INTERRUPT 0
+#define EXCEPTION_TLBMOD 1
+#define EXCEPTION_TLBLOAD 2
+#define EXCEPTION_TLBSTORE 3
+#define EXCEPTION_ADDRLOAD 4
+#define EXCEPTION_ADDRSTORE 5
+#define EXCEPTION_BUSINST 6
+#define EXCEPTION_BUSDATA 7
+#define EXCEPTION_SYSCALL 8
+#define EXCEPTION_BREAK 9
+#define EXCEPTION_INVALIDOP 10
+#define EXCEPTION_BADCOP 11
+#define EXCEPTION_OVERFLOW 12
+#define EXCEPTION_TRAP 13
+
+
+
+/***************************************************************************
+ HELPER MACROS
+***************************************************************************/
+
+#define RSREG ((op >> 21) & 31)
+#define RTREG ((op >> 16) & 31)
+#define RDREG ((op >> 11) & 31)
+#define SHIFT ((op >> 6) & 31)
+
+#define RSVAL (r3000.r[RSREG])
+#define RTVAL (r3000.r[RTREG])
+#define RDVAL (r3000.r[RDREG])
+
+#define SIMMVAL ((INT16)op)
+#define UIMMVAL ((UINT16)op)
+#define LIMMVAL (op & 0x03ffffff)
+
+#define ADDPC(x) r3000.nextpc = r3000.pc + ((x) << 2)
+#define ADDPCL(x,l) { r3000.nextpc = r3000.pc + ((x) << 2); r3000.r[l] = r3000.pc + 4; }
+#define ABSPC(x) r3000.nextpc = (r3000.pc & 0xf0000000) | ((x) << 2)
+#define ABSPCL(x,l) { r3000.nextpc = (r3000.pc & 0xf0000000) | ((x) << 2); r3000.r[l] = r3000.pc + 4; }
+#define SETPC(x) r3000.nextpc = (x)
+#define SETPCL(x,l) { r3000.nextpc = (x); r3000.r[l] = r3000.pc + 4; }
+
+#define RBYTE(x) (*r3000.cur.readbyte)(x)
+#define RWORD(x) (*r3000.cur.readword)(x)
+#define RLONG(x) (*r3000.cur.readlong)(x)
+
+#define WBYTE(x,v) (*r3000.cur.writebyte)(x,v)
+#define WWORD(x,v) (*r3000.cur.writeword)(x,v)
+#define WLONG(x,v) (*r3000.cur.writelong)(x,v)
+
+#define HIVAL r3000.hi
+#define LOVAL r3000.lo
+#define SR r3000.cpr[0][COP0_Status]
+#define CAUSE r3000.cpr[0][COP0_Cause]
+
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+/* memory access function table */
+typedef struct
+{
+ UINT8 (*readbyte)(offs_t);
+ UINT16 (*readword)(offs_t);
+ UINT32 (*readlong)(offs_t);
+ void (*writebyte)(offs_t, UINT8);
+ void (*writeword)(offs_t, UINT16);
+ void (*writelong)(offs_t, UINT32);
+} memory_handlers;
+
+/* R3000 Registers */
+typedef struct
+{
+ /* core registers */
+ UINT32 pc;
+ UINT32 hi;
+ UINT32 lo;
+ UINT32 r[32];
+
+ /* COP registers */
+ UINT32 cpr[4][32];
+ UINT32 ccr[4][32];
+ UINT8 cf[4];
+
+ /* internal stuff */
+ UINT32 ppc;
+ UINT32 nextpc;
+ int op;
+ int interrupt_cycles;
+ int hasfpu;
+ int (*irq_callback)(int irqline);
+
+ /* endian-dependent load/store */
+ void (*lwl)(UINT32 op);
+ void (*lwr)(UINT32 op);
+ void (*swl)(UINT32 op);
+ void (*swr)(UINT32 op);
+
+ /* memory accesses */
+ UINT8 bigendian;
+ memory_handlers cur;
+ const memory_handlers *memory_hand;
+ const memory_handlers *cache_hand;
+
+ /* cache memory */
+ UINT32 * cache;
+ UINT32 * icache;
+ UINT32 * dcache;
+ size_t cache_size;
+ size_t icache_size;
+ size_t dcache_size;
+} r3000_regs;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void lwl_be(UINT32 op);
+static void lwr_be(UINT32 op);
+static void swl_be(UINT32 op);
+static void swr_be(UINT32 op);
+
+static void lwl_le(UINT32 op);
+static void lwr_le(UINT32 op);
+static void swl_le(UINT32 op);
+static void swr_le(UINT32 op);
+
+static UINT8 readcache_be(offs_t offset);
+static UINT16 readcache_be_word(offs_t offset);
+static UINT32 readcache_be_dword(offs_t offset);
+static void writecache_be(offs_t offset, UINT8 data);
+static void writecache_be_word(offs_t offset, UINT16 data);
+static void writecache_be_dword(offs_t offset, UINT32 data);
+
+static UINT8 readcache_le(offs_t offset);
+static UINT16 readcache_le_word(offs_t offset);
+static UINT32 readcache_le_dword(offs_t offset);
+static void writecache_le(offs_t offset, UINT8 data);
+static void writecache_le_word(offs_t offset, UINT16 data);
+static void writecache_le_dword(offs_t offset, UINT32 data);
+
+
+/***************************************************************************
+ PUBLIC GLOBAL VARIABLES
+***************************************************************************/
+
+static int r3000_icount;
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static r3000_regs r3000;
+
+
+static const memory_handlers be_memory =
+{
+ program_read_byte_32be, program_read_word_32be, program_read_dword_32be,
+ program_write_byte_32be, program_write_word_32be, program_write_dword_32be
+};
+
+static const memory_handlers le_memory =
+{
+ program_read_byte_32le, program_read_word_32le, program_read_dword_32le,
+ program_write_byte_32le, program_write_word_32le, program_write_dword_32le
+};
+
+static const memory_handlers be_cache =
+{
+ readcache_be, readcache_be_word, readcache_be_dword,
+ writecache_be, writecache_be_word, writecache_be_dword
+};
+
+static const memory_handlers le_cache =
+{
+ readcache_le, readcache_le_word, readcache_le_dword,
+ writecache_le, writecache_le_word, writecache_le_dword
+};
+
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(pc) cpu_readop32(pc)
+
+
+
+/***************************************************************************
+ EXECEPTION HANDLING
+***************************************************************************/
+
+INLINE void generate_exception(int exception)
+{
+ /* set the exception PC */
+ r3000.cpr[0][COP0_EPC] = r3000.pc;
+
+ /* put the cause in the low 8 bits and clear the branch delay flag */
+ CAUSE = (CAUSE & ~0x800000ff) | (exception << 2);
+
+ /* if we were in a branch delay slot, adjust */
+ if (r3000.nextpc != ~0)
+ {
+ r3000.nextpc = ~0;
+ r3000.cpr[0][COP0_EPC] -= 4;
+ CAUSE |= 0x80000000;
+ }
+
+ /* shift the exception bits */
+ SR = (SR & 0xffffffc0) | ((SR << 2) & 0x3c);
+
+ /* based on the BEV bit, we either go to ROM or RAM */
+ r3000.pc = (SR & SR_BEV) ? 0xbfc00000 : 0x80000000;
+
+ /* most exceptions go to offset 0x180, except for TLB stuff */
+ if (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE)
+ r3000.pc += 0x80;
+ else
+ r3000.pc += 0x180;
+
+ /* swap to the new space */
+ change_pc(r3000.pc);
+}
+
+
+INLINE void invalid_instruction(UINT32 op)
+{
+ generate_exception(EXCEPTION_INVALIDOP);
+}
+
+
+
+/***************************************************************************
+ IRQ HANDLING
+***************************************************************************/
+
+static void check_irqs(void)
+{
+ if ((CAUSE & SR & 0xff00) && (SR & SR_IEc))
+ generate_exception(EXCEPTION_INTERRUPT);
+}
+
+
+static void set_irq_line(int irqline, int state)
+{
+ if (state != CLEAR_LINE)
+ CAUSE |= 0x400 << irqline;
+ else
+ CAUSE &= ~(0x400 << irqline);
+ check_irqs();
+}
+
+
+
+/***************************************************************************
+ CONTEXT SWITCHING
+***************************************************************************/
+
+static void r3000_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(r3000_regs *)dst = r3000;
+}
+
+
+static void r3000_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ r3000 = *(r3000_regs *)src;
+
+ change_pc(r3000.pc);
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+static void r3000_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const struct r3000_config *config = _config;
+
+ /* allocate memory */
+ r3000.icache = auto_malloc(config->icache);
+ r3000.dcache = auto_malloc(config->dcache);
+
+ r3000.icache_size = config->icache;
+ r3000.dcache_size = config->dcache;
+ r3000.hasfpu = config->hasfpu;
+
+ r3000.irq_callback = irqcallback;
+}
+
+
+static void r3000_reset(int bigendian)
+{
+ /* set up the endianness */
+ r3000.bigendian = bigendian;
+ if (r3000.bigendian)
+ {
+ r3000.memory_hand = &be_memory;
+ r3000.cache_hand = &be_cache;
+ r3000.lwl = lwl_be;
+ r3000.lwr = lwr_be;
+ r3000.swl = swl_be;
+ r3000.swr = swr_be;
+ }
+ else
+ {
+ r3000.memory_hand = &le_memory;
+ r3000.cache_hand = &le_cache;
+ r3000.lwl = lwl_le;
+ r3000.lwr = lwr_le;
+ r3000.swl = swl_le;
+ r3000.swr = swr_le;
+ }
+
+ /* initialize the rest of the config */
+ r3000.cur = *r3000.memory_hand;
+ r3000.cache = r3000.dcache;
+ r3000.cache_size = r3000.dcache_size;
+
+ /* initialize the state */
+ r3000.pc = 0xbfc00000;
+ r3000.nextpc = ~0;
+ r3000.cpr[0][COP0_PRId] = 0x0200;
+ r3000.cpr[0][COP0_Status] = 0x0000;
+ change_pc(r3000.pc);
+}
+
+static void r3000be_reset(void)
+{
+ r3000_reset(1);
+}
+
+static void r3000le_reset(void)
+{
+ r3000_reset(0);
+}
+
+
+static void r3000_exit(void)
+{
+}
+
+
+
+/***************************************************************************
+ COP0 (SYSTEM) EXECUTION HANDLING
+***************************************************************************/
+
+INLINE UINT32 get_cop0_reg(int idx)
+{
+ return r3000.cpr[0][idx];
+}
+
+INLINE void set_cop0_reg(int idx, UINT32 val)
+{
+ if (idx == COP0_Cause)
+ {
+ CAUSE = (CAUSE & 0xfc00) | (val & ~0xfc00);
+
+ /* update interrupts -- software ints can occur this way */
+ check_irqs();
+ }
+ else if (idx == COP0_Status)
+ {
+ UINT32 oldsr = r3000.cpr[0][idx];
+ UINT32 diff = oldsr ^ val;
+
+ /* handle cache isolation */
+ if (diff & SR_IsC)
+ {
+ if (val & SR_IsC)
+ r3000.cur = *r3000.cache_hand;
+ else
+ r3000.cur = *r3000.memory_hand;
+ }
+
+ /* handle cache switching */
+ if (diff & SR_SwC)
+ {
+ if (val & SR_SwC)
+ r3000.cache = r3000.icache, r3000.cache_size = r3000.icache_size;
+ else
+ r3000.cache = r3000.dcache, r3000.cache_size = r3000.dcache_size;
+ }
+ r3000.cpr[0][idx] = val;
+
+ /* update interrupts */
+ check_irqs();
+ }
+ else
+ r3000.cpr[0][idx] = val;
+}
+
+INLINE UINT32 get_cop0_creg(int idx)
+{
+ return r3000.ccr[0][idx];
+}
+
+INLINE void set_cop0_creg(int idx, UINT32 val)
+{
+ r3000.ccr[0][idx] = val;
+}
+
+INLINE void handle_cop0(UINT32 op)
+{
+ if (!(SR & SR_COP0) && (SR & SR_KUc))
+ generate_exception(EXCEPTION_BADCOP);
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break;
+ case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop0_creg(RDREG); break;
+ case 0x04: /* MTCz */ set_cop0_reg(RDREG, RTVAL); break;
+ case 0x06: /* CTCz */ set_cop0_creg(RDREG, RTVAL); break;
+ case 0x08: /* BC */
+ switch (RTREG)
+ {
+ case 0x00: /* BCzF */ if (!r3000.cf[0]) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzF */ if (r3000.cf[0]) ADDPC(SIMMVAL); break;
+ case 0x02: /* BCzFL */ invalid_instruction(op); break;
+ case 0x03: /* BCzTL */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+ break;
+ 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: /* COP */
+ switch (op & 0x01ffffff)
+ {
+ case 0x01: /* TLBR */ break;
+ case 0x02: /* TLBWI */ break;
+ case 0x06: /* TLBWR */ break;
+ case 0x08: /* TLBP */ break;
+ case 0x10: /* RFE */ SR = (SR & 0xfffffff0) | ((SR >> 2) & 0x0f); break;
+ case 0x18: /* ERET */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+ break;
+ default: invalid_instruction(op); break;
+ }
+}
+
+
+
+/***************************************************************************
+ COP1 (FPU) EXECUTION HANDLING
+***************************************************************************/
+
+INLINE UINT32 get_cop1_reg(int idx)
+{
+ return r3000.cpr[1][idx];
+}
+
+INLINE void set_cop1_reg(int idx, UINT32 val)
+{
+ r3000.cpr[1][idx] = val;
+}
+
+INLINE UINT32 get_cop1_creg(int idx)
+{
+ return r3000.ccr[1][idx];
+}
+
+INLINE void set_cop1_creg(int idx, UINT32 val)
+{
+ r3000.ccr[1][idx] = val;
+}
+
+INLINE void handle_cop1(UINT32 op)
+{
+ if (!(SR & SR_COP1))
+ generate_exception(EXCEPTION_BADCOP);
+ if (!r3000.hasfpu)
+ return;
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop1_reg(RDREG); break;
+ case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop1_creg(RDREG); break;
+ case 0x04: /* MTCz */ set_cop1_reg(RDREG, RTVAL); break;
+ case 0x06: /* CTCz */ set_cop1_creg(RDREG, RTVAL); break;
+ case 0x08: /* BC */
+ switch (RTREG)
+ {
+ case 0x00: /* BCzF */ if (!r3000.cf[1]) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzF */ if (r3000.cf[1]) ADDPC(SIMMVAL); break;
+ case 0x02: /* BCzFL */ invalid_instruction(op); break;
+ case 0x03: /* BCzTL */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+ break;
+ 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: /* COP */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+}
+
+
+
+/***************************************************************************
+ COP2 (CUSTOM) EXECUTION HANDLING
+***************************************************************************/
+
+INLINE UINT32 get_cop2_reg(int idx)
+{
+ return r3000.cpr[2][idx];
+}
+
+INLINE void set_cop2_reg(int idx, UINT32 val)
+{
+ r3000.cpr[2][idx] = val;
+}
+
+INLINE UINT32 get_cop2_creg(int idx)
+{
+ return r3000.ccr[2][idx];
+}
+
+INLINE void set_cop2_creg(int idx, UINT32 val)
+{
+ r3000.ccr[2][idx] = val;
+}
+
+INLINE void handle_cop2(UINT32 op)
+{
+ if (!(SR & SR_COP2))
+ generate_exception(EXCEPTION_BADCOP);
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop2_reg(RDREG); break;
+ case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop2_creg(RDREG); break;
+ case 0x04: /* MTCz */ set_cop2_reg(RDREG, RTVAL); break;
+ case 0x06: /* CTCz */ set_cop2_creg(RDREG, RTVAL); break;
+ case 0x08: /* BC */
+ switch (RTREG)
+ {
+ case 0x00: /* BCzF */ if (!r3000.cf[2]) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzF */ if (r3000.cf[2]) ADDPC(SIMMVAL); break;
+ case 0x02: /* BCzFL */ invalid_instruction(op); break;
+ case 0x03: /* BCzTL */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+ break;
+ 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: /* COP */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+}
+
+
+
+/***************************************************************************
+ COP3 (CUSTOM) EXECUTION HANDLING
+***************************************************************************/
+
+INLINE UINT32 get_cop3_reg(int idx)
+{
+ return r3000.cpr[3][idx];
+}
+
+INLINE void set_cop3_reg(int idx, UINT32 val)
+{
+ r3000.cpr[3][idx] = val;
+}
+
+INLINE UINT32 get_cop3_creg(int idx)
+{
+ return r3000.ccr[3][idx];
+}
+
+INLINE void set_cop3_creg(int idx, UINT32 val)
+{
+ r3000.ccr[3][idx] = val;
+}
+
+INLINE void handle_cop3(UINT32 op)
+{
+ if (!(SR & SR_COP3))
+ generate_exception(EXCEPTION_BADCOP);
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop3_reg(RDREG); break;
+ case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop3_creg(RDREG); break;
+ case 0x04: /* MTCz */ set_cop3_reg(RDREG, RTVAL); break;
+ case 0x06: /* CTCz */ set_cop3_creg(RDREG, RTVAL); break;
+ case 0x08: /* BC */
+ switch (RTREG)
+ {
+ case 0x00: /* BCzF */ if (!r3000.cf[3]) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzF */ if (r3000.cf[3]) ADDPC(SIMMVAL); break;
+ case 0x02: /* BCzFL */ invalid_instruction(op); break;
+ case 0x03: /* BCzTL */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+ break;
+ 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: /* COP */ invalid_instruction(op); break;
+ default: invalid_instruction(op); break;
+ }
+}
+
+
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+static int r3000_execute(int cycles)
+{
+ /* count cycles and interrupt cycles */
+ r3000_icount = cycles;
+ r3000_icount -= r3000.interrupt_cycles;
+ r3000.interrupt_cycles = 0;
+ change_pc(r3000.pc);
+
+ /* core execution loop */
+ do
+ {
+ UINT32 op;
+ UINT64 temp64;
+ int temp;
+
+ /* debugging */
+ r3000.ppc = r3000.pc;
+ CALL_MAME_DEBUG;
+
+ /* instruction fetch */
+ op = ROPCODE(r3000.pc);
+
+ /* adjust for next PC */
+ if (r3000.nextpc != ~0)
+ {
+ r3000.pc = r3000.nextpc;
+ r3000.nextpc = ~0;
+ change_pc(r3000.pc);
+ }
+ else
+ r3000.pc += 4;
+
+ /* parse the instruction */
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ switch (op & 63)
+ {
+ case 0x00: /* SLL */ if (RDREG) RDVAL = RTVAL << SHIFT; break;
+ case 0x02: /* SRL */ if (RDREG) RDVAL = RTVAL >> SHIFT; break;
+ case 0x03: /* SRA */ if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break;
+ case 0x04: /* SLLV */ if (RDREG) RDVAL = RTVAL << (RSVAL & 31); break;
+ case 0x06: /* SRLV */ if (RDREG) RDVAL = RTVAL >> (RSVAL & 31); break;
+ case 0x07: /* SRAV */ if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 31); break;
+ case 0x08: /* JR */ SETPC(RSVAL); break;
+ case 0x09: /* JALR */ SETPCL(RSVAL,RDREG); break;
+ case 0x0c: /* SYSCALL */ generate_exception(EXCEPTION_SYSCALL); break;
+ case 0x0d: /* BREAK */ generate_exception(EXCEPTION_BREAK); break;
+ case 0x0f: /* SYNC */ invalid_instruction(op); break;
+ case 0x10: /* MFHI */ if (RDREG) RDVAL = HIVAL; break;
+ case 0x11: /* MTHI */ HIVAL = RSVAL; break;
+ case 0x12: /* MFLO */ if (RDREG) RDVAL = LOVAL; break;
+ case 0x13: /* MTLO */ LOVAL = RSVAL; break;
+ case 0x18: /* MULT */
+ temp64 = (INT64)(INT32)RSVAL * (INT64)(INT32)RTVAL;
+ LOVAL = (UINT32)temp64;
+ HIVAL = (UINT32)(temp64 >> 32);
+ r3000_icount -= 11;
+ break;
+ case 0x19: /* MULTU */
+ temp64 = (UINT64)RSVAL * (UINT64)RTVAL;
+ LOVAL = (UINT32)temp64;
+ HIVAL = (UINT32)(temp64 >> 32);
+ r3000_icount -= 11;
+ break;
+ case 0x1a: /* DIV */
+ if (RTVAL)
+ {
+ LOVAL = (INT32)RSVAL / (INT32)RTVAL;
+ HIVAL = (INT32)RSVAL % (INT32)RTVAL;
+ }
+ r3000_icount -= 34;
+ break;
+ case 0x1b: /* DIVU */
+ if (RTVAL)
+ {
+ LOVAL = RSVAL / RTVAL;
+ HIVAL = RSVAL % RTVAL;
+ }
+ r3000_icount -= 34;
+ break;
+ case 0x20: /* ADD */
+ if (ENABLE_OVERFLOWS && RSVAL > ~RTVAL) generate_exception(EXCEPTION_OVERFLOW);
+ else RDVAL = RSVAL + RTVAL;
+ break;
+ case 0x21: /* ADDU */ if (RDREG) RDVAL = RSVAL + RTVAL; break;
+ case 0x22: /* SUB */
+ if (ENABLE_OVERFLOWS && RSVAL < RTVAL) generate_exception(EXCEPTION_OVERFLOW);
+ else RDVAL = RSVAL - RTVAL;
+ break;
+ case 0x23: /* SUBU */ if (RDREG) RDVAL = RSVAL - RTVAL; break;
+ case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break;
+ case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break;
+ case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break;
+ case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break;
+ case 0x2a: /* SLT */ if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break;
+ case 0x2b: /* SLTU */ if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break;
+ case 0x30: /* TEQ */ invalid_instruction(op); break;
+ case 0x31: /* TGEU */ invalid_instruction(op); break;
+ case 0x32: /* TLT */ invalid_instruction(op); break;
+ case 0x33: /* TLTU */ invalid_instruction(op); break;
+ case 0x34: /* TGE */ invalid_instruction(op); break;
+ case 0x36: /* TNE */ invalid_instruction(op); break;
+ default: /* ??? */ invalid_instruction(op); break;
+ }
+ break;
+
+ case 0x01: /* REGIMM */
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */ if ((INT32)RSVAL < 0) ADDPC(SIMMVAL); break;
+ case 0x01: /* BGEZ */ if ((INT32)RSVAL >= 0) ADDPC(SIMMVAL); break;
+ case 0x02: /* BLTZL */ invalid_instruction(op); break;
+ case 0x03: /* BGEZL */ invalid_instruction(op); break;
+ case 0x08: /* TGEI */ invalid_instruction(op); break;
+ case 0x09: /* TGEIU */ invalid_instruction(op); break;
+ case 0x0a: /* TLTI */ invalid_instruction(op); break;
+ case 0x0b: /* TLTIU */ invalid_instruction(op); break;
+ case 0x0c: /* TEQI */ invalid_instruction(op); break;
+ case 0x0e: /* TNEI */ invalid_instruction(op); break;
+ case 0x10: /* BLTZAL */ if ((INT32)RSVAL < 0) ADDPCL(SIMMVAL,31); break;
+ case 0x11: /* BGEZAL */ if ((INT32)RSVAL >= 0) ADDPCL(SIMMVAL,31); break;
+ case 0x12: /* BLTZALL */ invalid_instruction(op); break;
+ case 0x13: /* BGEZALL */ invalid_instruction(op); break;
+ default: /* ??? */ invalid_instruction(op); break;
+ }
+ break;
+
+ case 0x02: /* J */ ABSPC(LIMMVAL); break;
+ case 0x03: /* JAL */ ABSPCL(LIMMVAL,31); break;
+ case 0x04: /* BEQ */ if (RSVAL == RTVAL) ADDPC(SIMMVAL); break;
+ case 0x05: /* BNE */ if (RSVAL != RTVAL) ADDPC(SIMMVAL); break;
+ case 0x06: /* BLEZ */ if ((INT32)RSVAL <= 0) ADDPC(SIMMVAL); break;
+ case 0x07: /* BGTZ */ if ((INT32)RSVAL > 0) ADDPC(SIMMVAL); break;
+ case 0x08: /* ADDI */
+ if (ENABLE_OVERFLOWS && RSVAL > ~SIMMVAL) generate_exception(EXCEPTION_OVERFLOW);
+ else if (RTREG) RTVAL = RSVAL + SIMMVAL;
+ break;
+ case 0x09: /* ADDIU */ if (RTREG) RTVAL = RSVAL + SIMMVAL; break;
+ case 0x0a: /* SLTI */ if (RTREG) RTVAL = (INT32)RSVAL < (INT32)SIMMVAL; break;
+ case 0x0b: /* SLTIU */ if (RTREG) RTVAL = (UINT32)RSVAL < (UINT32)SIMMVAL; break;
+ case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMMVAL; break;
+ case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMMVAL; break;
+ case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMMVAL; break;
+ case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMMVAL << 16; break;
+ case 0x10: /* COP0 */ handle_cop0(op); break;
+ case 0x11: /* COP1 */ handle_cop1(op); break;
+ case 0x12: /* COP2 */ handle_cop2(op); break;
+ case 0x13: /* COP3 */ handle_cop3(op); break;
+ case 0x14: /* BEQL */ invalid_instruction(op); break;
+ case 0x15: /* BNEL */ invalid_instruction(op); break;
+ case 0x16: /* BLEZL */ invalid_instruction(op); break;
+ case 0x17: /* BGTZL */ invalid_instruction(op); break;
+ case 0x20: /* LB */ temp = RBYTE(SIMMVAL+RSVAL); if (RTREG) RTVAL = (INT8)temp; break;
+ case 0x21: /* LH */ temp = RWORD(SIMMVAL+RSVAL); if (RTREG) RTVAL = (INT16)temp; break;
+ case 0x22: /* LWL */ (*r3000.lwl)(op); break;
+ case 0x23: /* LW */ temp = RLONG(SIMMVAL+RSVAL); if (RTREG) RTVAL = temp; break;
+ case 0x24: /* LBU */ temp = RBYTE(SIMMVAL+RSVAL); if (RTREG) RTVAL = (UINT8)temp; break;
+ case 0x25: /* LHU */ temp = RWORD(SIMMVAL+RSVAL); if (RTREG) RTVAL = (UINT16)temp; break;
+ case 0x26: /* LWR */ (*r3000.lwr)(op); break;
+ case 0x28: /* SB */ WBYTE(SIMMVAL+RSVAL, RTVAL); break;
+ case 0x29: /* SH */ WWORD(SIMMVAL+RSVAL, RTVAL); break;
+ case 0x2a: /* SWL */ (*r3000.swl)(op); break;
+ case 0x2b: /* SW */ WLONG(SIMMVAL+RSVAL, RTVAL); break;
+ case 0x2e: /* SWR */ (*r3000.swr)(op); break;
+ case 0x2f: /* CACHE */ invalid_instruction(op); break;
+ case 0x30: /* LL */ invalid_instruction(op); break;
+ case 0x31: /* LWC1 */ set_cop1_reg(RTREG, RLONG(SIMMVAL+RSVAL)); break;
+ case 0x32: /* LWC2 */ set_cop2_reg(RTREG, RLONG(SIMMVAL+RSVAL)); break;
+ case 0x33: /* LWC3 */ set_cop3_reg(RTREG, RLONG(SIMMVAL+RSVAL)); break;
+ case 0x34: /* LDC0 */ invalid_instruction(op); break;
+ case 0x35: /* LDC1 */ invalid_instruction(op); break;
+ case 0x36: /* LDC2 */ invalid_instruction(op); break;
+ case 0x37: /* LDC3 */ invalid_instruction(op); break;
+ case 0x38: /* SC */ invalid_instruction(op); break;
+ case 0x39: /* LWC1 */ WLONG(SIMMVAL+RSVAL, get_cop1_reg(RTREG)); break;
+ case 0x3a: /* LWC2 */ WLONG(SIMMVAL+RSVAL, get_cop2_reg(RTREG)); break;
+ case 0x3b: /* LWC3 */ WLONG(SIMMVAL+RSVAL, get_cop3_reg(RTREG)); break;
+ case 0x3c: /* SDC0 */ invalid_instruction(op); break;
+ case 0x3d: /* SDC1 */ invalid_instruction(op); break;
+ case 0x3e: /* SDC2 */ invalid_instruction(op); break;
+ case 0x3f: /* SDC3 */ invalid_instruction(op); break;
+ default: /* ??? */ invalid_instruction(op); break;
+ }
+ r3000_icount--;
+
+ } while (r3000_icount > 0 || r3000.nextpc != ~0);
+
+ r3000_icount -= r3000.interrupt_cycles;
+ r3000.interrupt_cycles = 0;
+ return cycles - r3000_icount;
+}
+
+
+
+/***************************************************************************
+ DISASSEMBLY HOOK
+***************************************************************************/
+
+#ifdef MAME_DEBUG
+static offs_t r3000_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ extern unsigned dasmr3k(char *, unsigned, UINT32);
+ UINT32 op = *(UINT32 *)oprom;
+ if (r3000.bigendian)
+ op = BIG_ENDIANIZE_INT32(op);
+ else
+ op = LITTLE_ENDIANIZE_INT32(op);
+
+ return dasmr3k(buffer, pc, op);
+}
+#endif /* MAME_DEBUG */
+
+
+
+/***************************************************************************
+ CACHE I/O
+***************************************************************************/
+
+static UINT8 readcache_be(offs_t offset)
+{
+ offset &= 0x1fffffff;
+ return (offset * 4 < r3000.cache_size) ? r3000.cache[BYTE4_XOR_BE(offset)] : 0xff;
+}
+
+static UINT16 readcache_be_word(offs_t offset)
+{
+ offset &= 0x1fffffff;
+ return (offset * 4 < r3000.cache_size) ? *(UINT16 *)&r3000.cache[WORD_XOR_BE(offset)] : 0xffff;
+}
+
+static UINT32 readcache_be_dword(offs_t offset)
+{
+ offset &= 0x1fffffff;
+ return (offset * 4 < r3000.cache_size) ? *(UINT32 *)&r3000.cache[offset] : 0xffffffff;
+}
+
+static void writecache_be(offs_t offset, UINT8 data)
+{
+ offset &= 0x1fffffff;
+ if (offset * 4 < r3000.cache_size) r3000.cache[BYTE4_XOR_BE(offset)] = data;
+}
+
+static void writecache_be_word(offs_t offset, UINT16 data)
+{
+ offset &= 0x1fffffff;
+ if (offset * 4 < r3000.cache_size) *(UINT16 *)&r3000.cache[WORD_XOR_BE(offset)] = data;
+}
+
+static void writecache_be_dword(offs_t offset, UINT32 data)
+{
+ offset &= 0x1fffffff;
+ if (offset * 4 < r3000.cache_size) *(UINT32 *)&r3000.cache[offset] = data;
+}
+
+static UINT8 readcache_le(offs_t offset)
+{
+ offset &= 0x1fffffff;
+ return (offset * 4 < r3000.cache_size) ? r3000.cache[BYTE4_XOR_LE(offset)] : 0xff;
+}
+
+static UINT16 readcache_le_word(offs_t offset)
+{
+ offset &= 0x1fffffff;
+ return (offset * 4 < r3000.cache_size) ? *(UINT16 *)&r3000.cache[WORD_XOR_LE(offset)] : 0xffff;
+}
+
+static UINT32 readcache_le_dword(offs_t offset)
+{
+ offset &= 0x1fffffff;
+ return (offset * 4 < r3000.cache_size) ? *(UINT32 *)&r3000.cache[offset] : 0xffffffff;
+}
+
+static void writecache_le(offs_t offset, UINT8 data)
+{
+ offset &= 0x1fffffff;
+ if (offset * 4 < r3000.cache_size) r3000.cache[BYTE4_XOR_LE(offset)] = data;
+}
+
+static void writecache_le_word(offs_t offset, UINT16 data)
+{
+ offset &= 0x1fffffff;
+ if (offset * 4 < r3000.cache_size) *(UINT16 *)&r3000.cache[WORD_XOR_LE(offset)] = data;
+}
+
+static void writecache_le_dword(offs_t offset, UINT32 data)
+{
+ offset &= 0x1fffffff;
+ if (offset * 4 < r3000.cache_size) *(UINT32 *)&r3000.cache[offset] = data;
+}
+
+
+
+/***************************************************************************
+ COMPLEX OPCODE IMPLEMENTATIONS
+***************************************************************************/
+
+static void lwl_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL;
+ UINT32 temp = RLONG(offs & ~3);
+ if (RTREG)
+ {
+ if (!(offs & 3)) RTVAL = temp;
+ else
+ {
+ int shift = 8 * (offs & 3);
+ RTVAL = (RTVAL & (0x00ffffff >> (24 - shift))) | (temp << shift);
+ }
+ }
+}
+
+static void lwr_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL;
+ UINT32 temp = RLONG(offs & ~3);
+ if (RTREG)
+ {
+ if ((offs & 3) == 3) RTVAL = temp;
+ else
+ {
+ int shift = 8 * (offs & 3);
+ RTVAL = (RTVAL & (0xffffff00 << shift)) | (temp >> (24 - shift));
+ }
+ }
+}
+
+static void swl_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL;
+ if (!(offs & 3)) WLONG(offs, RTVAL);
+ else
+ {
+ UINT32 temp = RLONG(offs & ~3);
+ int shift = 8 * (offs & 3);
+ WLONG(offs & ~3, (temp & (0xffffff00 << (24 - shift))) | (RTVAL >> shift));
+ }
+}
+
+
+static void swr_be(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL;
+ if ((offs & 3) == 3) WLONG(offs & ~3, RTVAL);
+ else
+ {
+ UINT32 temp = RLONG(offs & ~3);
+ int shift = 8 * (offs & 3);
+ WLONG(offs & ~3, (temp & (0x00ffffff >> shift)) | (RTVAL << (24 - shift)));
+ }
+}
+
+
+
+static void lwl_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL;
+ UINT32 temp = RLONG(offs & ~3);
+ if (RTREG)
+ {
+ if (!(offs & 3)) RTVAL = temp;
+ else
+ {
+ int shift = 8 * (offs & 3);
+ RTVAL = (RTVAL & (0xffffff00 << (24 - shift))) | (temp >> shift);
+ }
+ }
+}
+
+static void lwr_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL;
+ UINT32 temp = RLONG(offs & ~3);
+ if (RTREG)
+ {
+ if ((offs & 3) == 3) RTVAL = temp;
+ else
+ {
+ int shift = 8 * (offs & 3);
+ RTVAL = (RTVAL & (0x00ffffff >> shift)) | (temp << (24 - shift));
+ }
+ }
+}
+
+static void swl_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL;
+ if (!(offs & 3)) WLONG(offs, RTVAL);
+ else
+ {
+ UINT32 temp = RLONG(offs & ~3);
+ int shift = 8 * (offs & 3);
+ WLONG(offs & ~3, (temp & (0x00ffffff >> (24 - shift))) | (RTVAL << shift));
+ }
+}
+
+static void swr_le(UINT32 op)
+{
+ offs_t offs = SIMMVAL + RSVAL;
+ if ((offs & 3) == 3) WLONG(offs & ~3, RTVAL);
+ else
+ {
+ UINT32 temp = RLONG(offs & ~3);
+ int shift = 8 * (offs & 3);
+ WLONG(offs & ~3, (temp & (0xffffff00 << shift)) | (RTVAL >> (24 - shift)));
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void r3000_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ0: set_irq_line(R3000_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ1: set_irq_line(R3000_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ2: set_irq_line(R3000_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ3: set_irq_line(R3000_IRQ3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ4: set_irq_line(R3000_IRQ4, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ5: set_irq_line(R3000_IRQ5, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + R3000_PC: r3000.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_SR: SR = info->i; break;
+
+ case CPUINFO_INT_REGISTER + R3000_R0: r3000.r[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R1: r3000.r[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R2: r3000.r[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R3: r3000.r[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R4: r3000.r[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R5: r3000.r[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R6: r3000.r[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R7: r3000.r[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R8: r3000.r[8] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R9: r3000.r[9] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R10: r3000.r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R11: r3000.r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R12: r3000.r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R13: r3000.r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R14: r3000.r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R15: r3000.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R16: r3000.r[16] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R17: r3000.r[17] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R18: r3000.r[18] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R19: r3000.r[19] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R20: r3000.r[20] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R21: r3000.r[21] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R22: r3000.r[22] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R23: r3000.r[23] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R24: r3000.r[24] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R25: r3000.r[25] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R26: r3000.r[26] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R27: r3000.r[27] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R28: r3000.r[28] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R29: r3000.r[29] = info->i; break;
+ case CPUINFO_INT_REGISTER + R3000_R30: r3000.r[30] = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + R3000_R31: r3000.r[31] = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void r3000_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(r3000); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 6; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 29; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ0: info->i = (r3000.cpr[0][COP0_Cause] & 0x400) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ1: info->i = (r3000.cpr[0][COP0_Cause] & 0x800) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ2: info->i = (r3000.cpr[0][COP0_Cause] & 0x1000) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ3: info->i = (r3000.cpr[0][COP0_Cause] & 0x2000) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ4: info->i = (r3000.cpr[0][COP0_Cause] & 0x4000) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + R3000_IRQ5: info->i = (r3000.cpr[0][COP0_Cause] & 0x8000) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = r3000.ppc; break;
+
+ case CPUINFO_INT_PC: info->i = r3000.pc & 0x1fffffff; break;
+ case CPUINFO_INT_REGISTER + R3000_PC: info->i = r3000.pc; break;
+ case CPUINFO_INT_REGISTER + R3000_SR: info->i = SR; break;
+
+ case CPUINFO_INT_REGISTER + R3000_R0: info->i = r3000.r[0]; break;
+ case CPUINFO_INT_REGISTER + R3000_R1: info->i = r3000.r[1]; break;
+ case CPUINFO_INT_REGISTER + R3000_R2: info->i = r3000.r[2]; break;
+ case CPUINFO_INT_REGISTER + R3000_R3: info->i = r3000.r[3]; break;
+ case CPUINFO_INT_REGISTER + R3000_R4: info->i = r3000.r[4]; break;
+ case CPUINFO_INT_REGISTER + R3000_R5: info->i = r3000.r[5]; break;
+ case CPUINFO_INT_REGISTER + R3000_R6: info->i = r3000.r[6]; break;
+ case CPUINFO_INT_REGISTER + R3000_R7: info->i = r3000.r[7]; break;
+ case CPUINFO_INT_REGISTER + R3000_R8: info->i = r3000.r[8]; break;
+ case CPUINFO_INT_REGISTER + R3000_R9: info->i = r3000.r[9]; break;
+ case CPUINFO_INT_REGISTER + R3000_R10: info->i = r3000.r[10]; break;
+ case CPUINFO_INT_REGISTER + R3000_R11: info->i = r3000.r[11]; break;
+ case CPUINFO_INT_REGISTER + R3000_R12: info->i = r3000.r[12]; break;
+ case CPUINFO_INT_REGISTER + R3000_R13: info->i = r3000.r[13]; break;
+ case CPUINFO_INT_REGISTER + R3000_R14: info->i = r3000.r[14]; break;
+ case CPUINFO_INT_REGISTER + R3000_R15: info->i = r3000.r[15]; break;
+ case CPUINFO_INT_REGISTER + R3000_R16: info->i = r3000.r[16]; break;
+ case CPUINFO_INT_REGISTER + R3000_R17: info->i = r3000.r[17]; break;
+ case CPUINFO_INT_REGISTER + R3000_R18: info->i = r3000.r[18]; break;
+ case CPUINFO_INT_REGISTER + R3000_R19: info->i = r3000.r[19]; break;
+ case CPUINFO_INT_REGISTER + R3000_R20: info->i = r3000.r[20]; break;
+ case CPUINFO_INT_REGISTER + R3000_R21: info->i = r3000.r[21]; break;
+ case CPUINFO_INT_REGISTER + R3000_R22: info->i = r3000.r[22]; break;
+ case CPUINFO_INT_REGISTER + R3000_R23: info->i = r3000.r[23]; break;
+ case CPUINFO_INT_REGISTER + R3000_R24: info->i = r3000.r[24]; break;
+ case CPUINFO_INT_REGISTER + R3000_R25: info->i = r3000.r[25]; break;
+ case CPUINFO_INT_REGISTER + R3000_R26: info->i = r3000.r[26]; break;
+ case CPUINFO_INT_REGISTER + R3000_R27: info->i = r3000.r[27]; break;
+ case CPUINFO_INT_REGISTER + R3000_R28: info->i = r3000.r[28]; break;
+ case CPUINFO_INT_REGISTER + R3000_R29: info->i = r3000.r[29]; break;
+ case CPUINFO_INT_REGISTER + R3000_R30: info->i = r3000.r[30]; break;
+ case CPUINFO_INT_SP: info->i = r3000.r[31] & 0x1fffffff; break;
+ case CPUINFO_INT_REGISTER + R3000_R31: info->i = r3000.r[31]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = r3000_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = r3000_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = r3000_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = r3000_init; break;
+ case CPUINFO_PTR_RESET: /* provided per-CPU */ break;
+ case CPUINFO_PTR_EXIT: info->exit = r3000_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = r3000_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = r3000_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &r3000_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R3000"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "MIPS II"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) Aaron Giles 2000-2002"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + R3000_PC: sprintf(info->s, "PC: %08X", r3000.pc); break;
+ case CPUINFO_STR_REGISTER + R3000_SR: sprintf(info->s, "SR: %08X", r3000.cpr[0][COP0_Status]); break;
+
+ case CPUINFO_STR_REGISTER + R3000_R0: sprintf(info->s, "R0: %08X", r3000.r[0]); break;
+ case CPUINFO_STR_REGISTER + R3000_R1: sprintf(info->s, "R1: %08X", r3000.r[1]); break;
+ case CPUINFO_STR_REGISTER + R3000_R2: sprintf(info->s, "R2: %08X", r3000.r[2]); break;
+ case CPUINFO_STR_REGISTER + R3000_R3: sprintf(info->s, "R3: %08X", r3000.r[3]); break;
+ case CPUINFO_STR_REGISTER + R3000_R4: sprintf(info->s, "R4: %08X", r3000.r[4]); break;
+ case CPUINFO_STR_REGISTER + R3000_R5: sprintf(info->s, "R5: %08X", r3000.r[5]); break;
+ case CPUINFO_STR_REGISTER + R3000_R6: sprintf(info->s, "R6: %08X", r3000.r[6]); break;
+ case CPUINFO_STR_REGISTER + R3000_R7: sprintf(info->s, "R7: %08X", r3000.r[7]); break;
+ case CPUINFO_STR_REGISTER + R3000_R8: sprintf(info->s, "R8: %08X", r3000.r[8]); break;
+ case CPUINFO_STR_REGISTER + R3000_R9: sprintf(info->s, "R9: %08X", r3000.r[9]); break;
+ case CPUINFO_STR_REGISTER + R3000_R10: sprintf(info->s, "R10:%08X", r3000.r[10]); break;
+ case CPUINFO_STR_REGISTER + R3000_R11: sprintf(info->s, "R11:%08X", r3000.r[11]); break;
+ case CPUINFO_STR_REGISTER + R3000_R12: sprintf(info->s, "R12:%08X", r3000.r[12]); break;
+ case CPUINFO_STR_REGISTER + R3000_R13: sprintf(info->s, "R13:%08X", r3000.r[13]); break;
+ case CPUINFO_STR_REGISTER + R3000_R14: sprintf(info->s, "R14:%08X", r3000.r[14]); break;
+ case CPUINFO_STR_REGISTER + R3000_R15: sprintf(info->s, "R15:%08X", r3000.r[15]); break;
+ case CPUINFO_STR_REGISTER + R3000_R16: sprintf(info->s, "R16:%08X", r3000.r[16]); break;
+ case CPUINFO_STR_REGISTER + R3000_R17: sprintf(info->s, "R17:%08X", r3000.r[17]); break;
+ case CPUINFO_STR_REGISTER + R3000_R18: sprintf(info->s, "R18:%08X", r3000.r[18]); break;
+ case CPUINFO_STR_REGISTER + R3000_R19: sprintf(info->s, "R19:%08X", r3000.r[19]); break;
+ case CPUINFO_STR_REGISTER + R3000_R20: sprintf(info->s, "R20:%08X", r3000.r[20]); break;
+ case CPUINFO_STR_REGISTER + R3000_R21: sprintf(info->s, "R21:%08X", r3000.r[21]); break;
+ case CPUINFO_STR_REGISTER + R3000_R22: sprintf(info->s, "R22:%08X", r3000.r[22]); break;
+ case CPUINFO_STR_REGISTER + R3000_R23: sprintf(info->s, "R23:%08X", r3000.r[23]); break;
+ case CPUINFO_STR_REGISTER + R3000_R24: sprintf(info->s, "R24:%08X", r3000.r[24]); break;
+ case CPUINFO_STR_REGISTER + R3000_R25: sprintf(info->s, "R25:%08X", r3000.r[25]); break;
+ case CPUINFO_STR_REGISTER + R3000_R26: sprintf(info->s, "R26:%08X", r3000.r[26]); break;
+ case CPUINFO_STR_REGISTER + R3000_R27: sprintf(info->s, "R27:%08X", r3000.r[27]); break;
+ case CPUINFO_STR_REGISTER + R3000_R28: sprintf(info->s, "R28:%08X", r3000.r[28]); break;
+ case CPUINFO_STR_REGISTER + R3000_R29: sprintf(info->s, "R29:%08X", r3000.r[29]); break;
+ case CPUINFO_STR_REGISTER + R3000_R30: sprintf(info->s, "R30:%08X", r3000.r[30]); break;
+ case CPUINFO_STR_REGISTER + R3000_R31: sprintf(info->s, "R31:%08X", r3000.r[31]); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void r3000be_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_RESET: info->reset = r3000be_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R3000 (big)"); break;
+
+ default: r3000_get_info(state, info); break;
+ }
+}
+
+
+void r3000le_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_RESET: info->reset = r3000le_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "R3000 (little)"); break;
+
+ default: r3000_get_info(state, info); break;
+ }
+}
diff --git a/src/emu/cpu/mips/r3000.h b/src/emu/cpu/mips/r3000.h
new file mode 100644
index 00000000000..0a897274ffd
--- /dev/null
+++ b/src/emu/cpu/mips/r3000.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+
+ r3000.h
+ Interface file for the portable MIPS R3000 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#ifndef _R3000_H
+#define _R3000_H
+
+#include "cpuintrf.h"
+
+
+/***************************************************************************
+ COMPILE-TIME DEFINITIONS
+***************************************************************************/
+
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ R3000_PC=1,R3000_SR,
+ R3000_R0,R3000_R1,R3000_R2,R3000_R3,R3000_R4,R3000_R5,R3000_R6,R3000_R7,
+ R3000_R8,R3000_R9,R3000_R10,R3000_R11,R3000_R12,R3000_R13,R3000_R14,R3000_R15,
+ R3000_R16,R3000_R17,R3000_R18,R3000_R19,R3000_R20,R3000_R21,R3000_R22,R3000_R23,
+ R3000_R24,R3000_R25,R3000_R26,R3000_R27,R3000_R28,R3000_R29,R3000_R30,R3000_R31
+};
+
+
+/***************************************************************************
+ INTERRUPT CONSTANTS
+***************************************************************************/
+
+#define R3000_IRQ0 0 /* IRQ0 */
+#define R3000_IRQ1 1 /* IRQ1 */
+#define R3000_IRQ2 2 /* IRQ2 */
+#define R3000_IRQ3 3 /* IRQ3 */
+#define R3000_IRQ4 4 /* IRQ4 */
+#define R3000_IRQ5 5 /* IRQ5 */
+
+
+/***************************************************************************
+ STRUCTURES
+***************************************************************************/
+
+struct r3000_config
+{
+ UINT8 hasfpu; /* 1 if we have an FPU, 0 otherwise */
+ size_t icache; /* code cache size */
+ size_t dcache; /* data cache size */
+};
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+extern void r3000be_get_info(UINT32 state, cpuinfo *info);
+extern void r3000le_get_info(UINT32 state, cpuinfo *info);
+
+#endif /* _JAGUAR_H */
diff --git a/src/emu/cpu/mips/r3kdasm.c b/src/emu/cpu/mips/r3kdasm.c
new file mode 100644
index 00000000000..f695fcf7dc4
--- /dev/null
+++ b/src/emu/cpu/mips/r3kdasm.c
@@ -0,0 +1,295 @@
+/***************************************************************************
+
+ r3kdasm.c
+ Disassembler for the portable R3000 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#include "cpuintrf.h"
+
+
+static const char *reg[32] =
+{
+ "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+
+static const char *cpreg[4][32] =
+{
+ {
+ "Index","Random","EntryLo","cpr3", "Context", "cpr5", "cpr6", "cpr7",
+ "BadVAddr", "cpr9", "cpr10","cpr11","SR","Cause","EPC","PRId",
+ "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23",
+ "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31"
+ },
+ {
+ "cpr0", "cpr1", "cpr2", "cpr3", "cpr4", "cpr5", "cpr6", "cpr7",
+ "cpr8", "cpr9", "cpr10","cpr11","cpr12","cpr13","cpr14","cpr15",
+ "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23",
+ "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31"
+ },
+ {
+ "cpr0", "cpr1", "cpr2", "cpr3", "cpr4", "cpr5", "cpr6", "cpr7",
+ "cpr8", "cpr9", "cpr10","cpr11","cpr12","cpr13","cpr14","cpr15",
+ "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23",
+ "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31"
+ },
+ {
+ "cpr0", "cpr1", "cpr2", "cpr3", "cpr4", "cpr5", "cpr6", "cpr7",
+ "cpr8", "cpr9", "cpr10","cpr11","cpr12","cpr13","cpr14","cpr15",
+ "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23",
+ "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31"
+ }
+};
+
+
+static const char *ccreg[4][32] =
+{
+ {
+ "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7",
+ "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15",
+ "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23",
+ "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31"
+ },
+ {
+ "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7",
+ "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15",
+ "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23",
+ "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31"
+ },
+ {
+ "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7",
+ "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15",
+ "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23",
+ "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31"
+ },
+ {
+ "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7",
+ "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15",
+ "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23",
+ "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31"
+ }
+};
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(pc) cpu_readop32(pc)
+
+
+/***************************************************************************
+ CODE CODE
+***************************************************************************/
+
+INLINE char *signed_16bit(INT16 val)
+{
+ static char temp[10];
+ if (val < 0)
+ sprintf(temp, "-$%x", -val);
+ else
+ sprintf(temp, "$%x", val);
+ return temp;
+}
+
+static UINT32 dasm_cop(UINT32 pc, int cop, UINT32 op, char *buffer)
+{
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ UINT32 flags = 0;
+
+ switch ((op >> 21) & 31)
+ {
+ case 0x00: sprintf(buffer, "mfc%d %s,%s", cop, reg[rt], cpreg[cop][rd]); break;
+ case 0x02: sprintf(buffer, "cfc%d %s,%s", cop, reg[rt], ccreg[cop][rd]); break;
+ case 0x04: sprintf(buffer, "mtc%d %s,%s", cop, reg[rt], cpreg[cop][rd]); break;
+ case 0x06: sprintf(buffer, "ctc%d %s,%s", cop, reg[rt], ccreg[cop][rd]); break;
+ case 0x08: /* BC */
+ switch (rt)
+ {
+ case 0x00: sprintf(buffer, "bc%df $%08x", cop, pc + 4 + ((INT16)op << 2)); break;
+ case 0x01: sprintf(buffer, "bc%dt $%08x", cop, pc + 4 + ((INT16)op << 2)); break;
+ case 0x02: sprintf(buffer, "bc%dfl [invalid]", cop); break;
+ case 0x03: sprintf(buffer, "bc%dtl [invalid]", cop); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ break;
+ 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: /* COP */
+ if (cop == 0)
+ {
+ switch (op & 0x01ffffff)
+ {
+ case 0x01: sprintf(buffer, "tlbr"); break;
+ case 0x02: sprintf(buffer, "tlbwi"); break;
+ case 0x06: sprintf(buffer, "tlbwr"); break;
+ case 0x08: sprintf(buffer, "tlbp"); break;
+ case 0x10: sprintf(buffer, "rfe"); break;
+ case 0x18: sprintf(buffer, "eret [invalid]"); break;
+ default: sprintf(buffer, "cop%d $%07x", cop, op & 0x01ffffff); break;
+ }
+ }
+ else
+ sprintf(buffer, "cop%d $%07x", cop, op & 0x01ffffff); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+
+ return flags;
+}
+
+unsigned dasmr3k(char *buffer, unsigned pc, UINT32 op)
+{
+ int rs = (op >> 21) & 31;
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ int shift = (op >> 6) & 31;
+ UINT32 flags = 0;
+
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ switch (op & 63)
+ {
+ case 0x00: if (op == 0)
+ sprintf(buffer, "nop");
+ else
+ sprintf(buffer, "sll %s,%s,%d", reg[rd], reg[rt], shift); break;
+ case 0x02: sprintf(buffer, "srl %s,%s,%d", reg[rd], reg[rt], shift); break;
+ case 0x03: sprintf(buffer, "sra %s,%s,%d", reg[rd], reg[rt], shift); break;
+ case 0x04: sprintf(buffer, "sllv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x06: sprintf(buffer, "srlv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x07: sprintf(buffer, "srav %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x08: sprintf(buffer, "jr %s", reg[rs]); if (rs == 31) flags = DASMFLAG_STEP_OUT; break;
+ case 0x09: if (rd == 31)
+ sprintf(buffer, "jalr %s", reg[rs]);
+ else
+ sprintf(buffer, "jalr %s,%s", reg[rs], reg[rd]); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x0c: sprintf(buffer, "syscall"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x0d: sprintf(buffer, "break"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x0f: sprintf(buffer, "sync [invalid]"); break;
+ case 0x10: sprintf(buffer, "mfhi %s", reg[rd]); break;
+ case 0x11: sprintf(buffer, "mthi %s", reg[rs]); break;
+ case 0x12: sprintf(buffer, "mflo %s", reg[rd]); break;
+ case 0x13: sprintf(buffer, "mtlo %s", reg[rs]); break;
+ case 0x18: sprintf(buffer, "mult %s,%s", reg[rs], reg[rt]); break;
+ case 0x19: sprintf(buffer, "multu %s,%s", reg[rs], reg[rt]); break;
+ case 0x1a: sprintf(buffer, "div %s,%s", reg[rs], reg[rt]); break;
+ case 0x1b: sprintf(buffer, "divu %s,%s", reg[rs], reg[rt]); break;
+ case 0x20: sprintf(buffer, "add %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x21: sprintf(buffer, "addu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x22: sprintf(buffer, "sub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x23: sprintf(buffer, "subu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x24: sprintf(buffer, "and %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x25: sprintf(buffer, "or %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x26: sprintf(buffer, "xor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x27: sprintf(buffer, "nor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2a: sprintf(buffer, "slt %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2b: sprintf(buffer, "sltu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x30: sprintf(buffer, "teq [invalid]"); break;
+ case 0x31: sprintf(buffer, "tgeu [invalid]"); break;
+ case 0x32: sprintf(buffer, "tlt [invalid]"); break;
+ case 0x33: sprintf(buffer, "tltu [invalid]"); break;
+ case 0x34: sprintf(buffer, "tge [invalid]"); break;
+ case 0x36: sprintf(buffer, "tne [invalid]"); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ break;
+
+ case 0x01: /* REGIMM */
+ switch ((op >> 16) & 31)
+ {
+ case 0x00: sprintf(buffer, "bltz %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x01: sprintf(buffer, "bgez %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x02: sprintf(buffer, "bltzl [invalid]"); break;
+ case 0x03: sprintf(buffer, "bgezl [invalid]"); break;
+ case 0x08: sprintf(buffer, "tgei [invalid]"); break;
+ case 0x09: sprintf(buffer, "tgeiu [invalid]"); break;
+ case 0x0a: sprintf(buffer, "tlti [invalid]"); break;
+ case 0x0b: sprintf(buffer, "tltiu [invalid]"); break;
+ case 0x0c: sprintf(buffer, "teqi [invalid]"); break;
+ case 0x0e: sprintf(buffer, "tnei [invalid]"); break;
+ case 0x10: sprintf(buffer, "bltzal %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x11: sprintf(buffer, "bgezal %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x12: sprintf(buffer, "bltzall [invalid]"); break;
+ case 0x13: sprintf(buffer, "bgezall [invalid]"); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ break;
+
+ case 0x02: sprintf(buffer, "j $%08x", (pc & 0xf0000000) | ((op & 0x0fffffff) << 2)); break;
+ case 0x03: sprintf(buffer, "jal $%08x", (pc & 0xf0000000) | ((op & 0x0fffffff) << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break;
+ case 0x04: if (rs == 0 && rt == 0)
+ sprintf(buffer, "b $%08x", pc + 4 + ((INT16)op << 2));
+ else
+ sprintf(buffer, "beq %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break;
+ case 0x05: sprintf(buffer, "bne %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break;
+ case 0x06: sprintf(buffer, "blez %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x07: sprintf(buffer, "bgtz %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x08: sprintf(buffer, "addi %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x09: sprintf(buffer, "addiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x0a: sprintf(buffer, "slti %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x0b: sprintf(buffer, "sltiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x0c: sprintf(buffer, "andi %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break;
+ case 0x0d: sprintf(buffer, "ori %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break;
+ case 0x0e: sprintf(buffer, "xori %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break;
+ case 0x0f: sprintf(buffer, "lui %s,$%04x", reg[rt], (UINT16)op); break;
+ case 0x10: flags = dasm_cop(pc, 0, op, buffer); break;
+ case 0x11: flags = dasm_cop(pc, 1, op, buffer); break;
+ case 0x12: flags = dasm_cop(pc, 2, op, buffer); break;
+ case 0x13: flags = dasm_cop(pc, 3, op, buffer); break;
+ case 0x14: sprintf(buffer, "beql [invalid]"); break;
+ case 0x15: sprintf(buffer, "bnel [invalid]"); break;
+ case 0x16: sprintf(buffer, "blezl [invalid]"); break;
+ case 0x17: sprintf(buffer, "bgtzl [invalid]"); break;
+ case 0x20: sprintf(buffer, "lb %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x21: sprintf(buffer, "lh %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x22: sprintf(buffer, "lwl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x23: sprintf(buffer, "lw %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x24: sprintf(buffer, "lbu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x25: sprintf(buffer, "lhu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x26: sprintf(buffer, "lwr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x28: sprintf(buffer, "sb %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x29: sprintf(buffer, "sh %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2a: sprintf(buffer, "swl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2b: sprintf(buffer, "sw %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2e: sprintf(buffer, "swr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
+ case 0x2f: sprintf(buffer, "cache [invalid]"); break;
+ case 0x30: sprintf(buffer, "ll [invalid]"); break;
+ case 0x31: sprintf(buffer, "lwc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
+ case 0x32: sprintf(buffer, "lwc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
+ case 0x33: sprintf(buffer, "lwc3 %s,%s(%s)", cpreg[3][rt], signed_16bit(op), reg[rs]); break;
+ case 0x34: sprintf(buffer, "ldc0 [invalid]"); break;
+ case 0x35: sprintf(buffer, "ldc1 [invalid]"); break;
+ case 0x36: sprintf(buffer, "ldc2 [invalid]"); break;
+ case 0x37: sprintf(buffer, "ldc3 [invalid]"); break;
+ case 0x38: sprintf(buffer, "sc [invalid]"); break;
+ case 0x39: sprintf(buffer, "swc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
+ case 0x3a: sprintf(buffer, "swc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
+ case 0x3b: sprintf(buffer, "swc3 %s,%s(%s)", cpreg[3][rt], signed_16bit(op), reg[rs]); break;
+ case 0x3c: sprintf(buffer, "sdc0 [invalid]"); break;
+ case 0x3d: sprintf(buffer, "sdc1 [invalid]"); break;
+ case 0x3e: sprintf(buffer, "sdc2 [invalid]"); break;
+ case 0x3f: sprintf(buffer, "sdc3 [invalid]"); break;
+ default: sprintf(buffer, "dc.l $%08x [invalid]", op); break;
+ }
+ return 4 | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/nec/nec.c b/src/emu/cpu/nec/nec.c
new file mode 100644
index 00000000000..3dfc82a160e
--- /dev/null
+++ b/src/emu/cpu/nec/nec.c
@@ -0,0 +1,1533 @@
+/****************************************************************************
+
+ NEC V20/V30/V33 emulator
+
+ ---------------------------------------------
+
+ V20 = uPD70108 = 8-bit data bus @ 5MHz or 8MHz
+ V20HL = uPD70108H = V20 with EMS support (24-bit address bus)
+
+ V25 = uPD70320 = V20 with on-chip features:
+ - 256 bytes on-chip RAM
+ - 8 register banks
+ - 4-bit input port
+ - 20-bit I/O port
+ - 2 channel serial interface
+ - interrupt controller
+ - 2 channel DMA controller
+ - 2 channel 16-bit timer
+ - new instructions: BTCLR, RETRBI, STOP, BRKCS, TSKSW,
+ MOVSPA, MOVSPB
+
+ V25+ = uPD70325 = V25 @ 8MHz or 10MHz plus changes:
+ - faster DMA
+ - improved serial interface
+
+ ---------------------------------------------
+
+ V30 = uPD70116 = 16-bit data bus version of V20
+ V30HL = uPD70116H = 16-bit data bus version of V20HL
+ V30MX = V30HL with separate address and data busses
+
+ V35 = uPD70330 = 16-bit data bus version of V25
+
+ V35+ = uPD70335 = 16-bit data bus version of V25+
+
+ ---------------------------------------------
+
+ V40 = uPD70208 = 8-bit data bus @ 10MHz
+ V40HL = uPD70208H = V40 with support up to 20Mhz
+
+ ---------------------------------------------
+
+ V50 = uPD70216 = 16-bit data bus version of V40
+ V50HL = uPD70216H = 16-bit data bus version of V40HL
+
+ ---------------------------------------------
+
+ V41 = uPD70270
+
+ V51 = uPD70280
+
+
+
+ V33A = uPD70136A
+
+ V53A = uPD70236A
+
+
+
+ Instruction differences:
+ V20, V30, V40, V50 have dedicated emulation instructions
+ (BRKEM, RETEM, CALLN)
+
+ V33A, V53A has dedicated address mode instructions
+ (BRKXA, RETXA)
+
+
+
+ (Re)Written June-September 2000 by Bryan McPhail (mish@tendril.co.uk) based
+ on code by Oliver Bergmann (Raul_Bloodworth@hotmail.com) who based code
+ on the i286 emulator by Fabrice Frances which had initial work based on
+ David Hedley's pcemu(!).
+
+ This new core features 99% accurate cycle counts for each processor,
+ there are still some complex situations where cycle counts are wrong,
+ typically where a few instructions have differing counts for odd/even
+ source and odd/even destination memory operands.
+
+ Flag settings are also correct for the NEC processors rather than the
+ I86 versions.
+
+ Changelist:
+
+ 22/02/2003:
+ Removed cycle counts from memory accesses - they are certainly wrong,
+ and there is already a memory access cycle penalty in the opcodes
+ using them.
+
+ Fixed save states.
+
+ Fixed ADJBA/ADJBS/ADJ4A/ADJ4S flags/return values for all situations.
+ (Fixes bugs in Geostorm and Thunderblaster)
+
+ Fixed carry flag on NEG (I thought this had been fixed circa Mame 0.58,
+ but it seems I never actually submitted the fix).
+
+ Fixed many cycle counts in instructions and bug in cycle count
+ macros (odd word cases were testing for odd instruction word address
+ not data address).
+
+ Todo!
+ Double check cycle timing is 100%.
+
+****************************************************************************/
+
+#include "debugger.h"
+
+typedef UINT8 BOOLEAN;
+typedef UINT8 BYTE;
+typedef UINT16 WORD;
+typedef UINT32 DWORD;
+
+#include "nec.h"
+#include "necintrf.h"
+
+extern int necv_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom);
+
+/* NEC registers */
+typedef union
+{ /* eight general registers */
+ UINT16 w[8]; /* viewed as 16 bits registers */
+ UINT8 b[16]; /* or as 8 bit registers */
+} necbasicregs;
+
+typedef struct
+{
+ offs_t fetch_xor;
+
+ UINT8 (*rbyte)(offs_t);
+ UINT16 (*rword)(offs_t);
+ void (*wbyte)(offs_t, UINT8);
+ void (*wword)(offs_t, UINT16);
+
+ UINT8 (*rbyte_port)(offs_t);
+ UINT16 (*rword_port)(offs_t);
+ void (*wbyte_port)(offs_t, UINT8);
+ void (*wword_port)(offs_t, UINT16);
+} memory_interface;
+
+typedef struct
+{
+ necbasicregs regs;
+ UINT16 sregs[4];
+
+ UINT16 ip;
+
+ INT32 SignVal;
+ UINT32 AuxVal, OverVal, ZeroVal, CarryVal, ParityVal; /* 0 or non-0 valued flags */
+ UINT8 TF, IF, DF, MF; /* 0 or 1 valued flags */ /* OB[19.07.99] added Mode Flag V30 */
+ UINT32 int_vector;
+ UINT32 pending_irq;
+ UINT32 nmi_state;
+ UINT32 irq_state;
+ UINT8 no_interrupt;
+
+ int (*irq_callback)(int irqline);
+
+ memory_interface mem;
+} nec_Regs;
+
+/***************************************************************************/
+/* cpu state */
+/***************************************************************************/
+
+static int nec_ICount;
+
+static nec_Regs I;
+
+static UINT32 chip_type;
+static UINT32 prefix_base; /* base address of the latest prefix segment */
+static char seg_prefix; /* prefix segment indicator */
+
+
+/* The interrupt number of a pending external interrupt pending NMI is 2. */
+/* For INTR interrupts, the level is caught on the bus during an INTA cycle */
+
+#define INT_IRQ 0x01
+#define NMI_IRQ 0x02
+
+#include "necinstr.h"
+#include "necea.h"
+#include "necmodrm.h"
+
+static UINT8 parity_table[256];
+
+/***************************************************************************/
+
+static void nec_reset (void)
+{
+ unsigned int i,j,c;
+ static const BREGS reg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH };
+ int (*save_irqcallback)(int);
+ memory_interface save_mem;
+
+ save_irqcallback = I.irq_callback;
+ save_mem = I.mem;
+ memset( &I, 0, sizeof(I) );
+ I.irq_callback = save_irqcallback;
+ I.mem = save_mem;
+
+ I.sregs[PS] = 0xffff;
+
+ CHANGE_PC;
+
+ for (i = 0;i < 256; i++)
+ {
+ for (j = i, c = 0; j > 0; j >>= 1)
+ if (j & 1) c++;
+ parity_table[i] = !(c & 1);
+ }
+
+ I.ZeroVal = I.ParityVal = 1;
+ SetMD(1); /* set the mode-flag = native mode */
+
+ for (i = 0; i < 256; i++)
+ {
+ Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3];
+ Mod_RM.reg.w[i] = (WREGS) ( (i & 0x38) >> 3) ;
+ }
+
+ for (i = 0xc0; i < 0x100; i++)
+ {
+ Mod_RM.RM.w[i] = (WREGS)( i & 7 );
+ Mod_RM.RM.b[i] = (BREGS)reg_name[i & 7];
+ }
+}
+
+static void nec_exit (void)
+{
+
+}
+
+static void nec_interrupt(unsigned int_num,BOOLEAN md_flag)
+{
+ UINT32 dest_seg, dest_off;
+
+ i_pushf();
+ I.TF = I.IF = 0;
+ if (md_flag) SetMD(0); /* clear Mode-flag = start 8080 emulation mode */
+
+ if (int_num == -1)
+ {
+ int_num = (*I.irq_callback)(0);
+
+ I.irq_state = CLEAR_LINE;
+ I.pending_irq &= ~INT_IRQ;
+ }
+
+ dest_off = read_word(int_num*4);
+ dest_seg = read_word(int_num*4+2);
+
+ PUSH(I.sregs[PS]);
+ PUSH(I.ip);
+ I.ip = (WORD)dest_off;
+ I.sregs[PS] = (WORD)dest_seg;
+ CHANGE_PC;
+}
+
+static void nec_trap(void)
+{
+ nec_instruction[FETCHOP]();
+ nec_interrupt(1,0);
+}
+
+static void external_int(void)
+{
+ if( I.pending_irq & NMI_IRQ )
+ {
+ nec_interrupt(NEC_NMI_INT_VECTOR,0);
+ I.pending_irq &= ~NMI_IRQ;
+ }
+ else if( I.pending_irq )
+ {
+ /* the actual vector is retrieved after pushing flags */
+ /* and clearing the IF */
+ nec_interrupt(-1,0);
+ }
+}
+
+/****************************************************************************/
+/* OPCODES */
+/****************************************************************************/
+
+#define OP(num,func_name) static void func_name(void)
+
+OP( 0x00, i_add_br8 ) { DEF_br8; ADDB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,13,7); }
+OP( 0x01, i_add_wr16 ) { DEF_wr16; ADDW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,EA);}
+OP( 0x02, i_add_r8b ) { DEF_r8b; ADDB; RegByte(ModRM)=dst; CLKM(2,2,2,11,10,6); }
+OP( 0x03, i_add_r16w ) { DEF_r16w; ADDW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,EA); }
+OP( 0x04, i_add_ald8 ) { DEF_ald8; ADDB; I.regs.b[AL]=dst; CLKS(4,4,2); }
+OP( 0x05, i_add_axd16) { DEF_axd16; ADDW; I.regs.w[AW]=dst; CLKS(4,4,2); }
+OP( 0x06, i_push_es ) { PUSH(I.sregs[DS1]); CLKS(12,8,3); }
+OP( 0x07, i_pop_es ) { POP(I.sregs[DS1]); CLKS(12,8,5); }
+
+OP( 0x08, i_or_br8 ) { DEF_br8; ORB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,13,7); }
+OP( 0x09, i_or_wr16 ) { DEF_wr16; ORW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,EA);}
+OP( 0x0a, i_or_r8b ) { DEF_r8b; ORB; RegByte(ModRM)=dst; CLKM(2,2,2,11,10,6); }
+OP( 0x0b, i_or_r16w ) { DEF_r16w; ORW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,EA); }
+OP( 0x0c, i_or_ald8 ) { DEF_ald8; ORB; I.regs.b[AL]=dst; CLKS(4,4,2); }
+OP( 0x0d, i_or_axd16 ) { DEF_axd16; ORW; I.regs.w[AW]=dst; CLKS(4,4,2); }
+OP( 0x0e, i_push_cs ) { PUSH(I.sregs[PS]); CLKS(12,8,5); }
+OP( 0x0f, i_pre_nec ) { UINT32 ModRM, tmp, tmp2;
+ switch (FETCH) {
+ case 0x10 : BITOP_BYTE; CLKS(3,3,4); tmp2 = I.regs.b[CL] & 0x7; I.ZeroVal = (tmp & (1<<tmp2)) ? 1 : 0; I.CarryVal=I.OverVal=0; break; /* Test */
+ case 0x11 : BITOP_WORD; CLKS(3,3,4); tmp2 = I.regs.b[CL] & 0xf; I.ZeroVal = (tmp & (1<<tmp2)) ? 1 : 0; I.CarryVal=I.OverVal=0; break; /* Test */
+ case 0x12 : BITOP_BYTE; CLKS(5,5,4); tmp2 = I.regs.b[CL] & 0x7; tmp &= ~(1<<tmp2); PutbackRMByte(ModRM,tmp); break; /* Clr */
+ case 0x13 : BITOP_WORD; CLKS(5,5,4); tmp2 = I.regs.b[CL] & 0xf; tmp &= ~(1<<tmp2); PutbackRMWord(ModRM,tmp); break; /* Clr */
+ case 0x14 : BITOP_BYTE; CLKS(4,4,4); tmp2 = I.regs.b[CL] & 0x7; tmp |= (1<<tmp2); PutbackRMByte(ModRM,tmp); break; /* Set */
+ case 0x15 : BITOP_WORD; CLKS(4,4,4); tmp2 = I.regs.b[CL] & 0xf; tmp |= (1<<tmp2); PutbackRMWord(ModRM,tmp); break; /* Set */
+ case 0x16 : BITOP_BYTE; CLKS(4,4,4); tmp2 = I.regs.b[CL] & 0x7; BIT_NOT; PutbackRMByte(ModRM,tmp); break; /* Not */
+ case 0x17 : BITOP_WORD; CLKS(4,4,4); tmp2 = I.regs.b[CL] & 0xf; BIT_NOT; PutbackRMWord(ModRM,tmp); break; /* Not */
+
+ case 0x18 : BITOP_BYTE; CLKS(4,4,4); tmp2 = (FETCH) & 0x7; I.ZeroVal = (tmp & (1<<tmp2)) ? 1 : 0; I.CarryVal=I.OverVal=0; break; /* Test */
+ case 0x19 : BITOP_WORD; CLKS(4,4,4); tmp2 = (FETCH) & 0xf; I.ZeroVal = (tmp & (1<<tmp2)) ? 1 : 0; I.CarryVal=I.OverVal=0; break; /* Test */
+ case 0x1a : BITOP_BYTE; CLKS(6,6,4); tmp2 = (FETCH) & 0x7; tmp &= ~(1<<tmp2); PutbackRMByte(ModRM,tmp); break; /* Clr */
+ case 0x1b : BITOP_WORD; CLKS(6,6,4); tmp2 = (FETCH) & 0xf; tmp &= ~(1<<tmp2); PutbackRMWord(ModRM,tmp); break; /* Clr */
+ case 0x1c : BITOP_BYTE; CLKS(5,5,4); tmp2 = (FETCH) & 0x7; tmp |= (1<<tmp2); PutbackRMByte(ModRM,tmp); break; /* Set */
+ case 0x1d : BITOP_WORD; CLKS(5,5,4); tmp2 = (FETCH) & 0xf; tmp |= (1<<tmp2); PutbackRMWord(ModRM,tmp); break; /* Set */
+ case 0x1e : BITOP_BYTE; CLKS(5,5,4); tmp2 = (FETCH) & 0x7; BIT_NOT; PutbackRMByte(ModRM,tmp); break; /* Not */
+ case 0x1f : BITOP_WORD; CLKS(5,5,4); tmp2 = (FETCH) & 0xf; BIT_NOT; PutbackRMWord(ModRM,tmp); break; /* Not */
+
+ case 0x20 : ADD4S; CLKS(7,7,2); break;
+ case 0x22 : SUB4S; CLKS(7,7,2); break;
+ case 0x26 : CMP4S; CLKS(7,7,2); break;
+ case 0x28 : ModRM = FETCH; tmp = GetRMByte(ModRM); tmp <<= 4; tmp |= I.regs.b[AL] & 0xf; I.regs.b[AL] = (I.regs.b[AL] & 0xf0) | ((tmp>>8)&0xf); tmp &= 0xff; PutbackRMByte(ModRM,tmp); CLKM(13,13,9,28,28,15); break;
+ case 0x2a : ModRM = FETCH; tmp = GetRMByte(ModRM); tmp2 = (I.regs.b[AL] & 0xf)<<4; I.regs.b[AL] = (I.regs.b[AL] & 0xf0) | (tmp&0xf); tmp = tmp2 | (tmp>>4); PutbackRMByte(ModRM,tmp); CLKM(17,17,13,32,32,19); break;
+ case 0x31 : ModRM = FETCH; ModRM=0; logerror("%06x: Unimplemented bitfield INS\n",activecpu_get_pc()); break;
+ case 0x33 : ModRM = FETCH; ModRM=0; logerror("%06x: Unimplemented bitfield EXT\n",activecpu_get_pc()); break;
+ case 0x92 : CLK(2); break; /* V25/35 FINT */
+ case 0xe0 : ModRM = FETCH; ModRM=0; logerror("%06x: V33 unimplemented BRKXA (break to expansion address)\n",activecpu_get_pc()); break;
+ case 0xf0 : ModRM = FETCH; ModRM=0; logerror("%06x: V33 unimplemented RETXA (return from expansion address)\n",activecpu_get_pc()); break;
+ case 0xff : ModRM = FETCH; ModRM=0; logerror("%06x: unimplemented BRKEM (break to 8080 emulation mode)\n",activecpu_get_pc()); break;
+ default: logerror("%06x: Unknown V20 instruction\n",activecpu_get_pc()); break;
+ }
+}
+
+OP( 0x10, i_adc_br8 ) { DEF_br8; src+=CF; ADDB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,13,7); }
+OP( 0x11, i_adc_wr16 ) { DEF_wr16; src+=CF; ADDW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,EA);}
+OP( 0x12, i_adc_r8b ) { DEF_r8b; src+=CF; ADDB; RegByte(ModRM)=dst; CLKM(2,2,2,11,10,6); }
+OP( 0x13, i_adc_r16w ) { DEF_r16w; src+=CF; ADDW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,EA); }
+OP( 0x14, i_adc_ald8 ) { DEF_ald8; src+=CF; ADDB; I.regs.b[AL]=dst; CLKS(4,4,2); }
+OP( 0x15, i_adc_axd16) { DEF_axd16; src+=CF; ADDW; I.regs.w[AW]=dst; CLKS(4,4,2); }
+OP( 0x16, i_push_ss ) { PUSH(I.sregs[SS]); CLKS(12,8,3); }
+OP( 0x17, i_pop_ss ) { POP(I.sregs[SS]); CLKS(12,8,5); I.no_interrupt=1; }
+
+OP( 0x18, i_sbb_br8 ) { DEF_br8; src+=CF; SUBB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,13,7); }
+OP( 0x19, i_sbb_wr16 ) { DEF_wr16; src+=CF; SUBW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,EA);}
+OP( 0x1a, i_sbb_r8b ) { DEF_r8b; src+=CF; SUBB; RegByte(ModRM)=dst; CLKM(2,2,2,11,10,6); }
+OP( 0x1b, i_sbb_r16w ) { DEF_r16w; src+=CF; SUBW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,EA); }
+OP( 0x1c, i_sbb_ald8 ) { DEF_ald8; src+=CF; SUBB; I.regs.b[AL]=dst; CLKS(4,4,2); }
+OP( 0x1d, i_sbb_axd16) { DEF_axd16; src+=CF; SUBW; I.regs.w[AW]=dst; CLKS(4,4,2); }
+OP( 0x1e, i_push_ds ) { PUSH(I.sregs[DS0]); CLKS(12,8,3); }
+OP( 0x1f, i_pop_ds ) { POP(I.sregs[DS0]); CLKS(12,8,5); }
+
+OP( 0x20, i_and_br8 ) { DEF_br8; ANDB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,13,7); }
+OP( 0x21, i_and_wr16 ) { DEF_wr16; ANDW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,EA);}
+OP( 0x22, i_and_r8b ) { DEF_r8b; ANDB; RegByte(ModRM)=dst; CLKM(2,2,2,11,10,6); }
+OP( 0x23, i_and_r16w ) { DEF_r16w; ANDW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,EA); }
+OP( 0x24, i_and_ald8 ) { DEF_ald8; ANDB; I.regs.b[AL]=dst; CLKS(4,4,2); }
+OP( 0x25, i_and_axd16) { DEF_axd16; ANDW; I.regs.w[AW]=dst; CLKS(4,4,2); }
+OP( 0x26, i_es ) { seg_prefix=TRUE; prefix_base=I.sregs[DS1]<<4; CLK(2); nec_instruction[FETCHOP](); seg_prefix=FALSE; }
+OP( 0x27, i_daa ) { ADJ4(6,0x60); CLKS(3,3,2); }
+
+OP( 0x28, i_sub_br8 ) { DEF_br8; SUBB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,13,7); }
+OP( 0x29, i_sub_wr16 ) { DEF_wr16; SUBW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,EA);}
+OP( 0x2a, i_sub_r8b ) { DEF_r8b; SUBB; RegByte(ModRM)=dst; CLKM(2,2,2,11,10,6); }
+OP( 0x2b, i_sub_r16w ) { DEF_r16w; SUBW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,EA); }
+OP( 0x2c, i_sub_ald8 ) { DEF_ald8; SUBB; I.regs.b[AL]=dst; CLKS(4,4,2); }
+OP( 0x2d, i_sub_axd16) { DEF_axd16; SUBW; I.regs.w[AW]=dst; CLKS(4,4,2); }
+OP( 0x2e, i_cs ) { seg_prefix=TRUE; prefix_base=I.sregs[PS]<<4; CLK(2); nec_instruction[FETCHOP](); seg_prefix=FALSE; }
+OP( 0x2f, i_das ) { ADJ4(-6,-0x60); CLKS(3,3,2); }
+
+OP( 0x30, i_xor_br8 ) { DEF_br8; XORB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,13,7); }
+OP( 0x31, i_xor_wr16 ) { DEF_wr16; XORW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,EA);}
+OP( 0x32, i_xor_r8b ) { DEF_r8b; XORB; RegByte(ModRM)=dst; CLKM(2,2,2,11,10,6); }
+OP( 0x33, i_xor_r16w ) { DEF_r16w; XORW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,EA); }
+OP( 0x34, i_xor_ald8 ) { DEF_ald8; XORB; I.regs.b[AL]=dst; CLKS(4,4,2); }
+OP( 0x35, i_xor_axd16) { DEF_axd16; XORW; I.regs.w[AW]=dst; CLKS(4,4,2); }
+OP( 0x36, i_ss ) { seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; CLK(2); nec_instruction[FETCHOP](); seg_prefix=FALSE; }
+OP( 0x37, i_aaa ) { ADJB(6, (I.regs.b[AL] > 0xf9) ? 2 : 1); CLKS(7,7,4); }
+
+OP( 0x38, i_cmp_br8 ) { DEF_br8; SUBB; CLKM(2,2,2,11,10,6); }
+OP( 0x39, i_cmp_wr16 ) { DEF_wr16; SUBW; CLKR(15,15,8,15,11,6,2,EA);}
+OP( 0x3a, i_cmp_r8b ) { DEF_r8b; SUBB; CLKM(2,2,2,11,10,6); }
+OP( 0x3b, i_cmp_r16w ) { DEF_r16w; SUBW; CLKR(15,15,8,15,11,6,2,EA); }
+OP( 0x3c, i_cmp_ald8 ) { DEF_ald8; SUBB; CLKS(4,4,2); }
+OP( 0x3d, i_cmp_axd16) { DEF_axd16; SUBW; CLKS(4,4,2); }
+OP( 0x3e, i_ds ) { seg_prefix=TRUE; prefix_base=I.sregs[DS0]<<4; CLK(2); nec_instruction[FETCHOP](); seg_prefix=FALSE; }
+OP( 0x3f, i_aas ) { ADJB(-6, (I.regs.b[AL] < 6) ? -2 : -1); CLKS(7,7,4); }
+
+OP( 0x40, i_inc_ax ) { IncWordReg(AW); CLK(2); }
+OP( 0x41, i_inc_cx ) { IncWordReg(CW); CLK(2); }
+OP( 0x42, i_inc_dx ) { IncWordReg(DW); CLK(2); }
+OP( 0x43, i_inc_bx ) { IncWordReg(BW); CLK(2); }
+OP( 0x44, i_inc_sp ) { IncWordReg(SP); CLK(2); }
+OP( 0x45, i_inc_bp ) { IncWordReg(BP); CLK(2); }
+OP( 0x46, i_inc_si ) { IncWordReg(IX); CLK(2); }
+OP( 0x47, i_inc_di ) { IncWordReg(IY); CLK(2); }
+
+OP( 0x48, i_dec_ax ) { DecWordReg(AW); CLK(2); }
+OP( 0x49, i_dec_cx ) { DecWordReg(CW); CLK(2); }
+OP( 0x4a, i_dec_dx ) { DecWordReg(DW); CLK(2); }
+OP( 0x4b, i_dec_bx ) { DecWordReg(BW); CLK(2); }
+OP( 0x4c, i_dec_sp ) { DecWordReg(SP); CLK(2); }
+OP( 0x4d, i_dec_bp ) { DecWordReg(BP); CLK(2); }
+OP( 0x4e, i_dec_si ) { DecWordReg(IX); CLK(2); }
+OP( 0x4f, i_dec_di ) { DecWordReg(IY); CLK(2); }
+
+OP( 0x50, i_push_ax ) { PUSH(I.regs.w[AW]); CLKS(12,8,3); }
+OP( 0x51, i_push_cx ) { PUSH(I.regs.w[CW]); CLKS(12,8,3); }
+OP( 0x52, i_push_dx ) { PUSH(I.regs.w[DW]); CLKS(12,8,3); }
+OP( 0x53, i_push_bx ) { PUSH(I.regs.w[BW]); CLKS(12,8,3); }
+OP( 0x54, i_push_sp ) { PUSH(I.regs.w[SP]); CLKS(12,8,3); }
+OP( 0x55, i_push_bp ) { PUSH(I.regs.w[BP]); CLKS(12,8,3); }
+OP( 0x56, i_push_si ) { PUSH(I.regs.w[IX]); CLKS(12,8,3); }
+OP( 0x57, i_push_di ) { PUSH(I.regs.w[IY]); CLKS(12,8,3); }
+
+OP( 0x58, i_pop_ax ) { POP(I.regs.w[AW]); CLKS(12,8,5); }
+OP( 0x59, i_pop_cx ) { POP(I.regs.w[CW]); CLKS(12,8,5); }
+OP( 0x5a, i_pop_dx ) { POP(I.regs.w[DW]); CLKS(12,8,5); }
+OP( 0x5b, i_pop_bx ) { POP(I.regs.w[BW]); CLKS(12,8,5); }
+OP( 0x5c, i_pop_sp ) { POP(I.regs.w[SP]); CLKS(12,8,5); }
+OP( 0x5d, i_pop_bp ) { POP(I.regs.w[BP]); CLKS(12,8,5); }
+OP( 0x5e, i_pop_si ) { POP(I.regs.w[IX]); CLKS(12,8,5); }
+OP( 0x5f, i_pop_di ) { POP(I.regs.w[IY]); CLKS(12,8,5); }
+
+OP( 0x60, i_pusha ) {
+ unsigned tmp=I.regs.w[SP];
+ PUSH(I.regs.w[AW]);
+ PUSH(I.regs.w[CW]);
+ PUSH(I.regs.w[DW]);
+ PUSH(I.regs.w[BW]);
+ PUSH(tmp);
+ PUSH(I.regs.w[BP]);
+ PUSH(I.regs.w[IX]);
+ PUSH(I.regs.w[IY]);
+ CLKS(67,35,20);
+}
+OP( 0x61, i_popa ) {
+ unsigned tmp;
+ POP(I.regs.w[IY]);
+ POP(I.regs.w[IX]);
+ POP(I.regs.w[BP]);
+ POP(tmp);
+ POP(I.regs.w[BW]);
+ POP(I.regs.w[DW]);
+ POP(I.regs.w[CW]);
+ POP(I.regs.w[AW]);
+ CLKS(75,43,22);
+}
+OP( 0x62, i_chkind ) {
+ UINT32 low,high,tmp;
+ GetModRM;
+ low = GetRMWord(ModRM);
+ high= GetnextRMWord;
+ tmp= RegWord(ModRM);
+ if (tmp<low || tmp>high) {
+ nec_interrupt(5,0);
+ }
+ nec_ICount-=20;
+ logerror("%06x: bound %04x high %04x low %04x tmp\n",activecpu_get_pc(),high,low,tmp);
+}
+OP( 0x64, i_repnc ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW];
+ switch(next) { /* Segments */
+ case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[DS1]<<4; next = FETCHOP; CLK(2); break;
+ case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[PS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS0]<<4; next = FETCHOP; CLK(2); break;
+ }
+
+ switch(next) {
+ case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ default: logerror("%06x: REPNC invalid\n",activecpu_get_pc()); nec_instruction[next]();
+ }
+ seg_prefix=FALSE;
+}
+
+OP( 0x65, i_repc ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW];
+ switch(next) { /* Segments */
+ case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[DS1]<<4; next = FETCHOP; CLK(2); break;
+ case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[PS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS0]<<4; next = FETCHOP; CLK(2); break;
+ }
+
+ switch(next) {
+ case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ default: logerror("%06x: REPC invalid\n",activecpu_get_pc()); nec_instruction[next]();
+ }
+ seg_prefix=FALSE;
+}
+
+OP( 0x68, i_push_d16 ) { UINT32 tmp; FETCHWORD(tmp); PUSH(tmp); CLKW(12,12,5,12,8,5,I.regs.w[SP]); }
+OP( 0x69, i_imul_d16 ) { UINT32 tmp; DEF_r16w; FETCHWORD(tmp); dst = (INT32)((INT16)src)*(INT32)((INT16)tmp); I.CarryVal = I.OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1); RegWord(ModRM)=(WORD)dst; nec_ICount-=(ModRM >=0xc0 )?38:47;}
+OP( 0x6a, i_push_d8 ) { UINT32 tmp = (WORD)((INT16)((INT8)FETCH)); PUSH(tmp); CLKW(11,11,5,11,7,3,I.regs.w[SP]); }
+OP( 0x6b, i_imul_d8 ) { UINT32 src2; DEF_r16w; src2= (WORD)((INT16)((INT8)FETCH)); dst = (INT32)((INT16)src)*(INT32)((INT16)src2); I.CarryVal = I.OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1); RegWord(ModRM)=(WORD)dst; nec_ICount-=(ModRM >=0xc0 )?31:39; }
+OP( 0x6c, i_insb ) { PutMemB(DS1,I.regs.w[IY],read_port_byte(I.regs.w[DW])); I.regs.w[IY]+= -2 * I.DF + 1; CLK(8); }
+OP( 0x6d, i_insw ) { PutMemW(DS1,I.regs.w[IY],read_port_word(I.regs.w[DW])); I.regs.w[IY]+= -4 * I.DF + 2; CLKS(18,10,8); }
+OP( 0x6e, i_outsb ) { write_port_byte(I.regs.w[DW],GetMemB(DS0,I.regs.w[IX])); I.regs.w[IX]+= -2 * I.DF + 1; CLK(8); }
+OP( 0x6f, i_outsw ) { write_port_word(I.regs.w[DW],GetMemW(DS0,I.regs.w[IX])); I.regs.w[IX]+= -4 * I.DF + 2; CLKS(18,10,8); }
+
+OP( 0x70, i_jo ) { JMP( OF); CLKS(4,4,3); }
+OP( 0x71, i_jno ) { JMP(!OF); CLKS(4,4,3); }
+OP( 0x72, i_jc ) { JMP( CF); CLKS(4,4,3); }
+OP( 0x73, i_jnc ) { JMP(!CF); CLKS(4,4,3); }
+OP( 0x74, i_jz ) { JMP( ZF); CLKS(4,4,3); }
+OP( 0x75, i_jnz ) { JMP(!ZF); CLKS(4,4,3); }
+OP( 0x76, i_jce ) { JMP(CF || ZF); CLKS(4,4,3); }
+OP( 0x77, i_jnce ) { JMP(!(CF || ZF)); CLKS(4,4,3); }
+OP( 0x78, i_js ) { JMP( SF); CLKS(4,4,3); }
+OP( 0x79, i_jns ) { JMP(!SF); CLKS(4,4,3); }
+OP( 0x7a, i_jp ) { JMP( PF); CLKS(4,4,3); }
+OP( 0x7b, i_jnp ) { JMP(!PF); CLKS(4,4,3); }
+OP( 0x7c, i_jl ) { JMP((SF!=OF)&&(!ZF)); CLKS(4,4,3); }
+OP( 0x7d, i_jnl ) { JMP((ZF)||(SF==OF)); CLKS(4,4,3); }
+OP( 0x7e, i_jle ) { JMP((ZF)||(SF!=OF)); CLKS(4,4,3); }
+OP( 0x7f, i_jnle ) { JMP((SF==OF)&&(!ZF)); CLKS(4,4,3); }
+
+OP( 0x80, i_80pre ) { UINT32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = FETCH;
+ if (ModRM >=0xc0 ) CLKS(4,4,2) else if ((ModRM & 0x38)==0x38) CLKS(13,13,6) else CLKS(18,18,7)
+ switch (ModRM & 0x38) {
+ case 0x00: ADDB; PutbackRMByte(ModRM,dst); break;
+ case 0x08: ORB; PutbackRMByte(ModRM,dst); break;
+ case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break;
+ case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break;
+ case 0x20: ANDB; PutbackRMByte(ModRM,dst); break;
+ case 0x28: SUBB; PutbackRMByte(ModRM,dst); break;
+ case 0x30: XORB; PutbackRMByte(ModRM,dst); break;
+ case 0x38: SUBB; break; /* CMP */
+ }
+}
+
+OP( 0x81, i_81pre ) { UINT32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = FETCH; src+= (FETCH << 8);
+ if (ModRM >=0xc0 ) CLKS(4,4,2) else if ((ModRM & 0x38)==0x38) CLKW(17,17,8,17,13,6,EA) else CLKW(26,26,11,26,18,7,EA)
+ switch (ModRM & 0x38) {
+ case 0x00: ADDW; PutbackRMWord(ModRM,dst); break;
+ case 0x08: ORW; PutbackRMWord(ModRM,dst); break;
+ case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break;
+ case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break;
+ case 0x20: ANDW; PutbackRMWord(ModRM,dst); break;
+ case 0x28: SUBW; PutbackRMWord(ModRM,dst); break;
+ case 0x30: XORW; PutbackRMWord(ModRM,dst); break;
+ case 0x38: SUBW; break; /* CMP */
+ }
+}
+
+OP( 0x82, i_82pre ) { UINT32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = (BYTE)((INT8)FETCH);
+ if (ModRM >=0xc0 ) CLKS(4,4,2) else if ((ModRM & 0x38)==0x38) CLKS(13,13,6) else CLKS(18,18,7)
+ switch (ModRM & 0x38) {
+ case 0x00: ADDB; PutbackRMByte(ModRM,dst); break;
+ case 0x08: ORB; PutbackRMByte(ModRM,dst); break;
+ case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break;
+ case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break;
+ case 0x20: ANDB; PutbackRMByte(ModRM,dst); break;
+ case 0x28: SUBB; PutbackRMByte(ModRM,dst); break;
+ case 0x30: XORB; PutbackRMByte(ModRM,dst); break;
+ case 0x38: SUBB; break; /* CMP */
+ }
+}
+
+OP( 0x83, i_83pre ) { UINT32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = (WORD)((INT16)((INT8)FETCH));
+ if (ModRM >=0xc0 ) CLKS(4,4,2) else if ((ModRM & 0x38)==0x38) CLKW(17,17,8,17,13,6,EA) else CLKW(26,26,11,26,18,7,EA)
+ switch (ModRM & 0x38) {
+ case 0x00: ADDW; PutbackRMWord(ModRM,dst); break;
+ case 0x08: ORW; PutbackRMWord(ModRM,dst); break;
+ case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break;
+ case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break;
+ case 0x20: ANDW; PutbackRMWord(ModRM,dst); break;
+ case 0x28: SUBW; PutbackRMWord(ModRM,dst); break;
+ case 0x30: XORW; PutbackRMWord(ModRM,dst); break;
+ case 0x38: SUBW; break; /* CMP */
+ }
+}
+
+OP( 0x84, i_test_br8 ) { DEF_br8; ANDB; CLKM(2,2,2,10,10,6); }
+OP( 0x85, i_test_wr16 ) { DEF_wr16; ANDW; CLKR(14,14,8,14,10,6,2,EA); }
+OP( 0x86, i_xchg_br8 ) { DEF_br8; RegByte(ModRM)=dst; PutbackRMByte(ModRM,src); CLKM(3,3,3,16,18,8); }
+OP( 0x87, i_xchg_wr16 ) { DEF_wr16; RegWord(ModRM)=dst; PutbackRMWord(ModRM,src); CLKR(24,24,12,24,16,8,3,EA); }
+
+OP( 0x88, i_mov_br8 ) { UINT8 src; GetModRM; src = RegByte(ModRM); PutRMByte(ModRM,src); CLKM(2,2,2,9,9,3); }
+OP( 0x89, i_mov_wr16 ) { UINT16 src; GetModRM; src = RegWord(ModRM); PutRMWord(ModRM,src); CLKR(13,13,5,13,9,3,2,EA); }
+OP( 0x8a, i_mov_r8b ) { UINT8 src; GetModRM; src = GetRMByte(ModRM); RegByte(ModRM)=src; CLKM(2,2,2,11,11,5); }
+OP( 0x8b, i_mov_r16w ) { UINT16 src; GetModRM; src = GetRMWord(ModRM); RegWord(ModRM)=src; CLKR(15,15,7,15,11,5,2,EA); }
+OP( 0x8c, i_mov_wsreg ) { GetModRM; PutRMWord(ModRM,I.sregs[(ModRM & 0x38) >> 3]); CLKR(14,14,5,14,10,3,2,EA); }
+OP( 0x8d, i_lea ) { UINT16 ModRM = FETCH; (void)(*GetEA[ModRM])(); RegWord(ModRM)=EO; CLKS(4,4,2); }
+OP( 0x8e, i_mov_sregw ) { UINT16 src; GetModRM; src = GetRMWord(ModRM); CLKR(15,15,7,15,11,5,2,EA);
+ switch (ModRM & 0x38) {
+ case 0x00: I.sregs[DS1] = src; break; /* mov es,ew */
+ case 0x08: I.sregs[PS] = src; break; /* mov cs,ew */
+ case 0x10: I.sregs[SS] = src; break; /* mov ss,ew */
+ case 0x18: I.sregs[DS0] = src; break; /* mov ds,ew */
+ default: logerror("%06x: Mov Sreg - Invalid register\n",activecpu_get_pc());
+ }
+ I.no_interrupt=1;
+}
+OP( 0x8f, i_popw ) { UINT16 tmp; GetModRM; POP(tmp); PutRMWord(ModRM,tmp); nec_ICount-=21; }
+OP( 0x90, i_nop ) { CLK(3);
+ /* Cycle skip for idle loops (0: NOP 1: JMP 0) */
+ if (I.no_interrupt==0 && nec_ICount>0 && (I.pending_irq==0) && (PEEKOP((I.sregs[PS]<<4)+I.ip))==0xeb && (PEEK((I.sregs[PS]<<4)+I.ip+1))==0xfd)
+ nec_ICount%=15;
+}
+OP( 0x91, i_xchg_axcx ) { XchgAWReg(CW); CLK(3); }
+OP( 0x92, i_xchg_axdx ) { XchgAWReg(DW); CLK(3); }
+OP( 0x93, i_xchg_axbx ) { XchgAWReg(BW); CLK(3); }
+OP( 0x94, i_xchg_axsp ) { XchgAWReg(SP); CLK(3); }
+OP( 0x95, i_xchg_axbp ) { XchgAWReg(BP); CLK(3); }
+OP( 0x96, i_xchg_axsi ) { XchgAWReg(IX); CLK(3); }
+OP( 0x97, i_xchg_axdi ) { XchgAWReg(IY); CLK(3); }
+
+OP( 0x98, i_cbw ) { I.regs.b[AH] = (I.regs.b[AL] & 0x80) ? 0xff : 0; CLK(2); }
+OP( 0x99, i_cwd ) { I.regs.w[DW] = (I.regs.b[AH] & 0x80) ? 0xffff : 0; CLK(4); }
+OP( 0x9a, i_call_far ) { UINT32 tmp, tmp2; FETCHWORD(tmp); FETCHWORD(tmp2); PUSH(I.sregs[PS]); PUSH(I.ip); I.ip = (WORD)tmp; I.sregs[PS] = (WORD)tmp2; CHANGE_PC; CLKW(29,29,13,29,21,9,I.regs.w[SP]); }
+OP( 0x9b, i_wait ) { logerror("%06x: Hardware POLL\n",activecpu_get_pc()); }
+OP( 0x9c, i_pushf ) { UINT16 tmp = CompressFlags(); PUSH( tmp ); CLKS(12,8,3); }
+OP( 0x9d, i_popf ) { UINT32 tmp; POP(tmp); ExpandFlags(tmp); CLKS(12,8,5); if (I.TF) nec_trap(); }
+OP( 0x9e, i_sahf ) { UINT32 tmp = (CompressFlags() & 0xff00) | (I.regs.b[AH] & 0xd5); ExpandFlags(tmp); CLKS(3,3,2); }
+OP( 0x9f, i_lahf ) { I.regs.b[AH] = CompressFlags() & 0xff; CLKS(3,3,2); }
+
+OP( 0xa0, i_mov_aldisp ) { UINT32 addr; FETCHWORD(addr); I.regs.b[AL] = GetMemB(DS0, addr); CLKS(10,10,5); }
+OP( 0xa1, i_mov_axdisp ) { UINT32 addr; FETCHWORD(addr); I.regs.w[AW] = GetMemW(DS0, addr); CLKW(14,14,7,14,10,5,addr); }
+OP( 0xa2, i_mov_dispal ) { UINT32 addr; FETCHWORD(addr); PutMemB(DS0, addr, I.regs.b[AL]); CLKS(9,9,3); }
+OP( 0xa3, i_mov_dispax ) { UINT32 addr; FETCHWORD(addr); PutMemW(DS0, addr, I.regs.w[AW]); CLKW(13,13,5,13,9,3,addr); }
+OP( 0xa4, i_movsb ) { UINT32 tmp = GetMemB(DS0,I.regs.w[IX]); PutMemB(DS1,I.regs.w[IY], tmp); I.regs.w[IY] += -2 * I.DF + 1; I.regs.w[IX] += -2 * I.DF + 1; CLKS(8,8,6); }
+OP( 0xa5, i_movsw ) { UINT32 tmp = GetMemW(DS0,I.regs.w[IX]); PutMemW(DS1,I.regs.w[IY], tmp); I.regs.w[IY] += -4 * I.DF + 2; I.regs.w[IX] += -4 * I.DF + 2; CLKS(16,16,10); }
+OP( 0xa6, i_cmpsb ) { UINT32 src = GetMemB(DS1, I.regs.w[IY]); UINT32 dst = GetMemB(DS0, I.regs.w[IX]); SUBB; I.regs.w[IY] += -2 * I.DF + 1; I.regs.w[IX] += -2 * I.DF + 1; CLKS(14,14,14); }
+OP( 0xa7, i_cmpsw ) { UINT32 src = GetMemW(DS1, I.regs.w[IY]); UINT32 dst = GetMemW(DS0, I.regs.w[IX]); SUBW; I.regs.w[IY] += -4 * I.DF + 2; I.regs.w[IX] += -4 * I.DF + 2; CLKS(14,14,14); }
+
+OP( 0xa8, i_test_ald8 ) { DEF_ald8; ANDB; CLKS(4,4,2); }
+OP( 0xa9, i_test_axd16 ) { DEF_axd16; ANDW; CLKS(4,4,2); }
+OP( 0xaa, i_stosb ) { PutMemB(DS1,I.regs.w[IY],I.regs.b[AL]); I.regs.w[IY] += -2 * I.DF + 1; CLKS(4,4,3); }
+OP( 0xab, i_stosw ) { PutMemW(DS1,I.regs.w[IY],I.regs.w[AW]); I.regs.w[IY] += -4 * I.DF + 2; CLKW(8,8,5,8,4,3,I.regs.w[IY]); }
+OP( 0xac, i_lodsb ) { I.regs.b[AL] = GetMemB(DS0,I.regs.w[IX]); I.regs.w[IX] += -2 * I.DF + 1; CLKS(4,4,3); }
+OP( 0xad, i_lodsw ) { I.regs.w[AW] = GetMemW(DS0,I.regs.w[IX]); I.regs.w[IX] += -4 * I.DF + 2; CLKW(8,8,5,8,4,3,I.regs.w[IX]); }
+OP( 0xae, i_scasb ) { UINT32 src = GetMemB(DS1, I.regs.w[IY]); UINT32 dst = I.regs.b[AL]; SUBB; I.regs.w[IY] += -2 * I.DF + 1; CLKS(4,4,3); }
+OP( 0xaf, i_scasw ) { UINT32 src = GetMemW(DS1, I.regs.w[IY]); UINT32 dst = I.regs.w[AW]; SUBW; I.regs.w[IY] += -4 * I.DF + 2; CLKW(8,8,5,8,4,3,I.regs.w[IY]); }
+
+OP( 0xb0, i_mov_ald8 ) { I.regs.b[AL] = FETCH; CLKS(4,4,2); }
+OP( 0xb1, i_mov_cld8 ) { I.regs.b[CL] = FETCH; CLKS(4,4,2); }
+OP( 0xb2, i_mov_dld8 ) { I.regs.b[DL] = FETCH; CLKS(4,4,2); }
+OP( 0xb3, i_mov_bld8 ) { I.regs.b[BL] = FETCH; CLKS(4,4,2); }
+OP( 0xb4, i_mov_ahd8 ) { I.regs.b[AH] = FETCH; CLKS(4,4,2); }
+OP( 0xb5, i_mov_chd8 ) { I.regs.b[CH] = FETCH; CLKS(4,4,2); }
+OP( 0xb6, i_mov_dhd8 ) { I.regs.b[DH] = FETCH; CLKS(4,4,2); }
+OP( 0xb7, i_mov_bhd8 ) { I.regs.b[BH] = FETCH; CLKS(4,4,2); }
+
+OP( 0xb8, i_mov_axd16 ) { I.regs.b[AL] = FETCH; I.regs.b[AH] = FETCH; CLKS(4,4,2); }
+OP( 0xb9, i_mov_cxd16 ) { I.regs.b[CL] = FETCH; I.regs.b[CH] = FETCH; CLKS(4,4,2); }
+OP( 0xba, i_mov_dxd16 ) { I.regs.b[DL] = FETCH; I.regs.b[DH] = FETCH; CLKS(4,4,2); }
+OP( 0xbb, i_mov_bxd16 ) { I.regs.b[BL] = FETCH; I.regs.b[BH] = FETCH; CLKS(4,4,2); }
+OP( 0xbc, i_mov_spd16 ) { I.regs.b[SPL] = FETCH; I.regs.b[SPH] = FETCH; CLKS(4,4,2); }
+OP( 0xbd, i_mov_bpd16 ) { I.regs.b[BPL] = FETCH; I.regs.b[BPH] = FETCH; CLKS(4,4,2); }
+OP( 0xbe, i_mov_sid16 ) { I.regs.b[IXL] = FETCH; I.regs.b[IXH] = FETCH; CLKS(4,4,2); }
+OP( 0xbf, i_mov_did16 ) { I.regs.b[IYL] = FETCH; I.regs.b[IYH] = FETCH; CLKS(4,4,2); }
+
+OP( 0xc0, i_rotshft_bd8 ) {
+ UINT32 src, dst; UINT8 c;
+ GetModRM; src = (unsigned)GetRMByte(ModRM); dst=src;
+ c=FETCH;
+ CLKM(7,7,2,19,19,6);
+ if (c) switch (ModRM & 0x38) {
+ case 0x00: do { ROL_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x08: do { ROR_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x10: do { ROLC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x18: do { RORC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x20: SHL_BYTE(c); break;
+ case 0x28: SHR_BYTE(c); break;
+ case 0x30: logerror("%06x: Undefined opcode 0xc0 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_BYTE(c); break;
+ }
+}
+
+OP( 0xc1, i_rotshft_wd8 ) {
+ UINT32 src, dst; UINT8 c;
+ GetModRM; src = (unsigned)GetRMWord(ModRM); dst=src;
+ c=FETCH;
+ CLKM(7,7,2,27,19,6);
+ if (c) switch (ModRM & 0x38) {
+ case 0x00: do { ROL_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x08: do { ROR_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x10: do { ROLC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x18: do { RORC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x20: SHL_WORD(c); break;
+ case 0x28: SHR_WORD(c); break;
+ case 0x30: logerror("%06x: Undefined opcode 0xc1 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_WORD(c); break;
+ }
+}
+
+OP( 0xc2, i_ret_d16 ) { UINT32 count = FETCH; count += FETCH << 8; POP(I.ip); I.regs.w[SP]+=count; CHANGE_PC; CLKS(24,24,10); }
+OP( 0xc3, i_ret ) { POP(I.ip); CHANGE_PC; CLKS(19,19,10); }
+OP( 0xc4, i_les_dw ) { GetModRM; WORD tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; I.sregs[DS1] = GetnextRMWord; CLKW(26,26,14,26,18,10,EA); }
+OP( 0xc5, i_lds_dw ) { GetModRM; WORD tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; I.sregs[DS0] = GetnextRMWord; CLKW(26,26,14,26,18,10,EA); }
+OP( 0xc6, i_mov_bd8 ) { GetModRM; PutImmRMByte(ModRM); nec_ICount-=(ModRM >=0xc0 )?4:11; }
+OP( 0xc7, i_mov_wd16 ) { GetModRM; PutImmRMWord(ModRM); nec_ICount-=(ModRM >=0xc0 )?4:15; }
+
+OP( 0xc8, i_enter ) {
+ UINT32 nb = FETCH;
+ UINT32 i,level;
+
+ nec_ICount-=23;
+ nb += FETCH << 8;
+ level = FETCH;
+ PUSH(I.regs.w[BP]);
+ I.regs.w[BP]=I.regs.w[SP];
+ I.regs.w[SP] -= nb;
+ for (i=1;i<level;i++) {
+ PUSH(GetMemW(SS,I.regs.w[BP]-i*2));
+ nec_ICount-=16;
+ }
+ if (level) PUSH(I.regs.w[BP]);
+}
+OP( 0xc9, i_leave ) {
+ I.regs.w[SP]=I.regs.w[BP];
+ POP(I.regs.w[BP]);
+ nec_ICount-=8;
+}
+OP( 0xca, i_retf_d16 ) { UINT32 count = FETCH; count += FETCH << 8; POP(I.ip); POP(I.sregs[PS]); I.regs.w[SP]+=count; CHANGE_PC; CLKS(32,32,16); }
+OP( 0xcb, i_retf ) { POP(I.ip); POP(I.sregs[PS]); CHANGE_PC; CLKS(29,29,16); }
+OP( 0xcc, i_int3 ) { nec_interrupt(3,0); CLKS(50,50,24); }
+OP( 0xcd, i_int ) { nec_interrupt(FETCH,0); CLKS(50,50,24); }
+OP( 0xce, i_into ) { if (OF) { nec_interrupt(4,0); CLKS(52,52,26); } else CLK(3); }
+OP( 0xcf, i_iret ) { POP(I.ip); POP(I.sregs[PS]); i_popf(); CHANGE_PC; CLKS(39,39,19); }
+
+OP( 0xd0, i_rotshft_b ) {
+ UINT32 src, dst; GetModRM; src = (UINT32)GetRMByte(ModRM); dst=src;
+ CLKM(6,6,2,16,16,7);
+ switch (ModRM & 0x38) {
+ case 0x00: ROL_BYTE; PutbackRMByte(ModRM,(BYTE)dst); I.OverVal = (src^dst)&0x80; break;
+ case 0x08: ROR_BYTE; PutbackRMByte(ModRM,(BYTE)dst); I.OverVal = (src^dst)&0x80; break;
+ case 0x10: ROLC_BYTE; PutbackRMByte(ModRM,(BYTE)dst); I.OverVal = (src^dst)&0x80; break;
+ case 0x18: RORC_BYTE; PutbackRMByte(ModRM,(BYTE)dst); I.OverVal = (src^dst)&0x80; break;
+ case 0x20: SHL_BYTE(1); I.OverVal = (src^dst)&0x80; break;
+ case 0x28: SHR_BYTE(1); I.OverVal = (src^dst)&0x80; break;
+ case 0x30: logerror("%06x: Undefined opcode 0xd0 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_BYTE(1); I.OverVal = 0; break;
+ }
+}
+
+OP( 0xd1, i_rotshft_w ) {
+ UINT32 src, dst; GetModRM; src = (UINT32)GetRMWord(ModRM); dst=src;
+ CLKM(6,6,2,24,16,7);
+ switch (ModRM & 0x38) {
+ case 0x00: ROL_WORD; PutbackRMWord(ModRM,(WORD)dst); I.OverVal = (src^dst)&0x8000; break;
+ case 0x08: ROR_WORD; PutbackRMWord(ModRM,(WORD)dst); I.OverVal = (src^dst)&0x8000; break;
+ case 0x10: ROLC_WORD; PutbackRMWord(ModRM,(WORD)dst); I.OverVal = (src^dst)&0x8000; break;
+ case 0x18: RORC_WORD; PutbackRMWord(ModRM,(WORD)dst); I.OverVal = (src^dst)&0x8000; break;
+ case 0x20: SHL_WORD(1); I.OverVal = (src^dst)&0x8000; break;
+ case 0x28: SHR_WORD(1); I.OverVal = (src^dst)&0x8000; break;
+ case 0x30: logerror("%06x: Undefined opcode 0xd1 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_WORD(1); I.OverVal = 0; break;
+ }
+}
+
+OP( 0xd2, i_rotshft_bcl ) {
+ UINT32 src, dst; UINT8 c; GetModRM; src = (UINT32)GetRMByte(ModRM); dst=src;
+ c=I.regs.b[CL];
+ CLKM(7,7,2,19,19,6);
+ if (c) switch (ModRM & 0x38) {
+ case 0x00: do { ROL_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x08: do { ROR_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x10: do { ROLC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x18: do { RORC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x20: SHL_BYTE(c); break;
+ case 0x28: SHR_BYTE(c); break;
+ case 0x30: logerror("%06x: Undefined opcode 0xd2 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_BYTE(c); break;
+ }
+}
+
+OP( 0xd3, i_rotshft_wcl ) {
+ UINT32 src, dst; UINT8 c; GetModRM; src = (UINT32)GetRMWord(ModRM); dst=src;
+ c=I.regs.b[CL];
+ CLKM(7,7,2,27,19,6);
+ if (c) switch (ModRM & 0x38) {
+ case 0x00: do { ROL_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x08: do { ROR_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x10: do { ROLC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x18: do { RORC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x20: SHL_WORD(c); break;
+ case 0x28: SHR_WORD(c); break;
+ case 0x30: logerror("%06x: Undefined opcode 0xd3 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_WORD(c); break;
+ }
+}
+
+OP( 0xd4, i_aam ) { UINT32 mult=FETCH; mult=0; I.regs.b[AH] = I.regs.b[AL] / 10; I.regs.b[AL] %= 10; SetSZPF_Word(I.regs.w[AW]); CLKS(15,15,12); }
+OP( 0xd5, i_aad ) { UINT32 mult=FETCH; mult=0; I.regs.b[AL] = I.regs.b[AH] * 10 + I.regs.b[AL]; I.regs.b[AH] = 0; SetSZPF_Byte(I.regs.b[AL]); CLKS(7,7,8); }
+OP( 0xd6, i_setalc ) { I.regs.b[AL] = (CF)?0xff:0x00; nec_ICount-=3; logerror("%06x: Undefined opcode (SETALC)\n",activecpu_get_pc()); }
+OP( 0xd7, i_trans ) { UINT32 dest = (I.regs.w[BW]+I.regs.b[AL])&0xffff; I.regs.b[AL] = GetMemB(DS0, dest); CLKS(9,9,5); }
+OP( 0xd8, i_fpo ) { GetModRM; nec_ICount-=2; logerror("%06x: Unimplemented floating point control %04x\n",activecpu_get_pc(),ModRM); }
+
+OP( 0xe0, i_loopne ) { INT8 disp = (INT8)FETCH; I.regs.w[CW]--; if (!ZF && I.regs.w[CW]) { I.ip = (WORD)(I.ip+disp); /*CHANGE_PC;*/ CLKS(14,14,6); } else CLKS(5,5,3); }
+OP( 0xe1, i_loope ) { INT8 disp = (INT8)FETCH; I.regs.w[CW]--; if ( ZF && I.regs.w[CW]) { I.ip = (WORD)(I.ip+disp); /*CHANGE_PC;*/ CLKS(14,14,6); } else CLKS(5,5,3); }
+OP( 0xe2, i_loop ) { INT8 disp = (INT8)FETCH; I.regs.w[CW]--; if (I.regs.w[CW]) { I.ip = (WORD)(I.ip+disp); /*CHANGE_PC;*/ CLKS(13,13,6); } else CLKS(5,5,3); }
+OP( 0xe3, i_jcxz ) { INT8 disp = (INT8)FETCH; if (I.regs.w[CW] == 0) { I.ip = (WORD)(I.ip+disp); /*CHANGE_PC;*/ CLKS(13,13,6); } else CLKS(5,5,3); }
+OP( 0xe4, i_inal ) { UINT8 port = FETCH; I.regs.b[AL] = read_port_byte(port); CLKS(9,9,5); }
+OP( 0xe5, i_inax ) { UINT8 port = FETCH; I.regs.w[AW] = read_port_word(port); CLKW(13,13,7,13,9,5,port); }
+OP( 0xe6, i_outal ) { UINT8 port = FETCH; write_port_byte(port, I.regs.b[AL]); CLKS(8,8,3); }
+OP( 0xe7, i_outax ) { UINT8 port = FETCH; write_port_word(port, I.regs.w[AW]); CLKW(12,12,5,12,8,3,port); }
+
+OP( 0xe8, i_call_d16 ) { UINT32 tmp; FETCHWORD(tmp); PUSH(I.ip); I.ip = (WORD)(I.ip+(INT16)tmp); CHANGE_PC; nec_ICount-=24; }
+OP( 0xe9, i_jmp_d16 ) { UINT32 tmp; FETCHWORD(tmp); I.ip = (WORD)(I.ip+(INT16)tmp); CHANGE_PC; nec_ICount-=15; }
+OP( 0xea, i_jmp_far ) { UINT32 tmp,tmp1; FETCHWORD(tmp); FETCHWORD(tmp1); I.sregs[PS] = (WORD)tmp1; I.ip = (WORD)tmp; CHANGE_PC; nec_ICount-=27; }
+OP( 0xeb, i_jmp_d8 ) { int tmp = (int)((INT8)FETCH); nec_ICount-=12;
+ if (tmp==-2 && I.no_interrupt==0 && (I.pending_irq==0) && nec_ICount>0) nec_ICount%=12; /* cycle skip */
+ I.ip = (WORD)(I.ip+tmp);
+}
+OP( 0xec, i_inaldx ) { I.regs.b[AL] = read_port_byte(I.regs.w[DW]); CLKS(8,8,5);}
+OP( 0xed, i_inaxdx ) { I.regs.w[AW] = read_port_word(I.regs.w[DW]); CLKW(12,12,7,12,8,5,I.regs.w[DW]); }
+OP( 0xee, i_outdxal ) { write_port_byte(I.regs.w[DW], I.regs.b[AL]); CLKS(8,8,3); }
+OP( 0xef, i_outdxax ) { write_port_word(I.regs.w[DW], I.regs.w[AW]); CLKW(12,12,5,12,8,3,I.regs.w[DW]); }
+
+OP( 0xf0, i_lock ) { logerror("%06x: Warning - BUSLOCK\n",activecpu_get_pc()); I.no_interrupt=1; CLK(2); }
+OP( 0xf2, i_repne ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW];
+ switch(next) { /* Segments */
+ case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[DS1]<<4; next = FETCHOP; CLK(2); break;
+ case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[PS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS0]<<4; next = FETCHOP; CLK(2); break;
+ }
+
+ switch(next) {
+ case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && ZF==0); I.regs.w[CW]=c; break;
+ case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && ZF==0); I.regs.w[CW]=c; break;
+ case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && ZF==0); I.regs.w[CW]=c; break;
+ case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && ZF==0); I.regs.w[CW]=c; break;
+ default: logerror("%06x: REPNE invalid\n",activecpu_get_pc()); nec_instruction[next]();
+ }
+ seg_prefix=FALSE;
+}
+OP( 0xf3, i_repe ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW];
+ switch(next) { /* Segments */
+ case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[DS1]<<4; next = FETCHOP; CLK(2); break;
+ case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[PS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS0]<<4; next = FETCHOP; CLK(2); break;
+ }
+
+ switch(next) {
+ case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && ZF==1); I.regs.w[CW]=c; break;
+ case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && ZF==1); I.regs.w[CW]=c; break;
+ case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && ZF==1); I.regs.w[CW]=c; break;
+ case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && ZF==1); I.regs.w[CW]=c; break;
+ default: logerror("%06x: REPE invalid\n",activecpu_get_pc()); nec_instruction[next]();
+ }
+ seg_prefix=FALSE;
+}
+OP( 0xf4, i_hlt ) { logerror("%06x: HALT\n",activecpu_get_pc()); nec_ICount=0; }
+OP( 0xf5, i_cmc ) { I.CarryVal = !CF; CLK(2); }
+OP( 0xf6, i_f6pre ) { UINT32 tmp; UINT32 uresult,uresult2; INT32 result,result2;
+ GetModRM; tmp = GetRMByte(ModRM);
+ switch (ModRM & 0x38) {
+ case 0x00: tmp &= FETCH; I.CarryVal = I.OverVal = 0; SetSZPF_Byte(tmp); nec_ICount-=(ModRM >=0xc0 )?4:11; break; /* TEST */
+ case 0x08: logerror("%06x: Undefined opcode 0xf6 0x08\n",activecpu_get_pc()); break;
+ case 0x10: PutbackRMByte(ModRM,~tmp); nec_ICount-=(ModRM >=0xc0 )?2:16; break; /* NOT */
+ case 0x18: I.CarryVal=(tmp!=0); tmp=(~tmp)+1; SetSZPF_Byte(tmp); PutbackRMByte(ModRM,tmp&0xff); nec_ICount-=(ModRM >=0xc0 )?2:16; break; /* NEG */
+ case 0x20: uresult = I.regs.b[AL]*tmp; I.regs.w[AW]=(WORD)uresult; I.CarryVal=I.OverVal=(I.regs.b[AH]!=0); nec_ICount-=(ModRM >=0xc0 )?30:36; break; /* MULU */
+ case 0x28: result = (INT16)((INT8)I.regs.b[AL])*(INT16)((INT8)tmp); I.regs.w[AW]=(WORD)result; I.CarryVal=I.OverVal=(I.regs.b[AH]!=0); nec_ICount-=(ModRM >=0xc0 )?30:36; break; /* MUL */
+ case 0x30: if (tmp) { DIVUB; } else nec_interrupt(0,0); nec_ICount-=(ModRM >=0xc0 )?43:53; break;
+ case 0x38: if (tmp) { DIVB; } else nec_interrupt(0,0); nec_ICount-=(ModRM >=0xc0 )?43:53; break;
+ }
+}
+
+OP( 0xf7, i_f7pre ) { UINT32 tmp,tmp2; UINT32 uresult,uresult2; INT32 result,result2;
+ GetModRM; tmp = GetRMWord(ModRM);
+ switch (ModRM & 0x38) {
+ case 0x00: FETCHWORD(tmp2); tmp &= tmp2; I.CarryVal = I.OverVal = 0; SetSZPF_Word(tmp); nec_ICount-=(ModRM >=0xc0 )?4:11; break; /* TEST */
+ case 0x08: logerror("%06x: Undefined opcode 0xf7 0x08\n",activecpu_get_pc()); break;
+ case 0x10: PutbackRMWord(ModRM,~tmp); nec_ICount-=(ModRM >=0xc0 )?2:16; break; /* NOT */
+ case 0x18: I.CarryVal=(tmp!=0); tmp=(~tmp)+1; SetSZPF_Word(tmp); PutbackRMWord(ModRM,tmp&0xffff); nec_ICount-=(ModRM >=0xc0 )?2:16; break; /* NEG */
+ case 0x20: uresult = I.regs.w[AW]*tmp; I.regs.w[AW]=uresult&0xffff; I.regs.w[DW]=((UINT32)uresult)>>16; I.CarryVal=I.OverVal=(I.regs.w[DW]!=0); nec_ICount-=(ModRM >=0xc0 )?30:36; break; /* MULU */
+ case 0x28: result = (INT32)((INT16)I.regs.w[AW])*(INT32)((INT16)tmp); I.regs.w[AW]=result&0xffff; I.regs.w[DW]=result>>16; I.CarryVal=I.OverVal=(I.regs.w[DW]!=0); nec_ICount-=(ModRM >=0xc0 )?30:36; break; /* MUL */
+ case 0x30: if (tmp) { DIVUW; } else nec_interrupt(0,0); nec_ICount-=(ModRM >=0xc0 )?43:53; break;
+ case 0x38: if (tmp) { DIVW; } else nec_interrupt(0,0); nec_ICount-=(ModRM >=0xc0 )?43:53; break;
+ }
+}
+
+OP( 0xf8, i_clc ) { I.CarryVal = 0; CLK(2); }
+OP( 0xf9, i_stc ) { I.CarryVal = 1; CLK(2); }
+OP( 0xfa, i_di ) { SetIF(0); CLK(2); }
+OP( 0xfb, i_ei ) { SetIF(1); CLK(2); }
+OP( 0xfc, i_cld ) { SetDF(0); CLK(2); }
+OP( 0xfd, i_std ) { SetDF(1); CLK(2); }
+OP( 0xfe, i_fepre ) { UINT32 tmp, tmp1; GetModRM; tmp=GetRMByte(ModRM);
+ switch(ModRM & 0x38) {
+ case 0x00: tmp1 = tmp+1; I.OverVal = (tmp==0x7f); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(BYTE)tmp1); CLKM(2,2,2,16,16,7); break; /* INC */
+ case 0x08: tmp1 = tmp-1; I.OverVal = (tmp==0x80); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(BYTE)tmp1); CLKM(2,2,2,16,16,7); break; /* DEC */
+ default: logerror("%06x: FE Pre with unimplemented mod\n",activecpu_get_pc());
+ }
+}
+OP( 0xff, i_ffpre ) { UINT32 tmp, tmp1; GetModRM; tmp=GetRMWord(ModRM);
+ switch(ModRM & 0x38) {
+ case 0x00: tmp1 = tmp+1; I.OverVal = (tmp==0x7fff); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(WORD)tmp1); CLKM(2,2,2,24,16,7); break; /* INC */
+ case 0x08: tmp1 = tmp-1; I.OverVal = (tmp==0x8000); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(WORD)tmp1); CLKM(2,2,2,24,16,7); break; /* DEC */
+ case 0x10: PUSH(I.ip); I.ip = (WORD)tmp; CHANGE_PC; nec_ICount-=(ModRM >=0xc0 )?16:20; break; /* CALL */
+ case 0x18: tmp1 = I.sregs[PS]; I.sregs[PS] = GetnextRMWord; PUSH(tmp1); PUSH(I.ip); I.ip = tmp; CHANGE_PC; nec_ICount-=(ModRM >=0xc0 )?16:26; break; /* CALL FAR */
+ case 0x20: I.ip = tmp; CHANGE_PC; nec_ICount-=13; break; /* JMP */
+ case 0x28: I.ip = tmp; I.sregs[PS] = GetnextRMWord; CHANGE_PC; nec_ICount-=15; break; /* JMP FAR */
+ case 0x30: PUSH(tmp); nec_ICount-=4; break;
+ default: logerror("%06x: FF Pre with unimplemented mod\n",activecpu_get_pc());
+ }
+}
+
+static void i_invalid(void)
+{
+ nec_ICount-=10;
+ logerror("%06x: Invalid Opcode\n",activecpu_get_pc());
+}
+
+/*****************************************************************************/
+
+static void nec_get_context(void *dst)
+{
+ if( dst )
+ *(nec_Regs*)dst = I;
+}
+
+static void nec_set_context(void *src)
+{
+ if( src )
+ {
+ I = *(nec_Regs*)src;
+ CHANGE_PC;
+ }
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if( I.nmi_state == state ) return;
+ I.nmi_state = state;
+ if (state != CLEAR_LINE)
+ {
+ I.pending_irq |= NMI_IRQ;
+ }
+ }
+ else
+ {
+ I.irq_state = state;
+ if (state == CLEAR_LINE)
+ {
+ // if (!I.IF) NS010718 fix interrupt request loss
+ I.pending_irq &= ~INT_IRQ;
+ }
+ else
+ {
+ // if (I.IF) NS010718 fix interrupt request loss
+ I.pending_irq |= INT_IRQ;
+ }
+ }
+}
+
+#ifdef MAME_DEBUG
+static offs_t nec_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return necv_dasm_one(buffer, pc, oprom);
+}
+#endif /* MAME_DEBUG */
+
+static void nec_init(int index, int clock, const void *config, int (*irqcallback)(int), int type)
+{
+ static const char *names[]={"V20","V30","V33"};
+
+ state_save_register_item_array(names[type], index, I.regs.w);
+ state_save_register_item_array(names[type], index, I.sregs);
+
+ state_save_register_item(names[type], index, I.ip);
+ state_save_register_item(names[type], index, I.TF);
+ state_save_register_item(names[type], index, I.IF);
+ state_save_register_item(names[type], index, I.DF);
+ state_save_register_item(names[type], index, I.MF);
+ state_save_register_item(names[type], index, I.SignVal);
+ state_save_register_item(names[type], index, I.int_vector);
+ state_save_register_item(names[type], index, I.pending_irq);
+ state_save_register_item(names[type], index, I.nmi_state);
+ state_save_register_item(names[type], index, I.irq_state);
+ state_save_register_item(names[type], index, I.AuxVal);
+ state_save_register_item(names[type], index, I.OverVal);
+ state_save_register_item(names[type], index, I.ZeroVal);
+ state_save_register_item(names[type], index, I.CarryVal);
+ state_save_register_item(names[type], index, I.ParityVal);
+
+ I.irq_callback = irqcallback;
+}
+
+
+/*****************************************************************************
+ 8-bit memory accessors
+ *****************************************************************************/
+
+#if (HAS_V20||HAS_V25)
+static UINT16 read_word_8(offs_t addr)
+{
+ UINT16 result = program_read_byte_8(addr);
+ return result | (program_read_byte_8(addr + 1) << 8);
+}
+
+static void write_word_8(offs_t addr, UINT16 data)
+{
+ program_write_byte_8(addr, data);
+ program_write_byte_8(addr + 1, data >> 8);
+}
+
+static UINT16 read_port_word_8(offs_t addr)
+{
+ UINT16 result = io_read_byte_8(addr);
+ return result | (io_read_byte_8(addr + 1) << 8);
+}
+
+static void write_port_word_8(offs_t addr, UINT16 data)
+{
+ io_write_byte_8(addr, data);
+ io_write_byte_8(addr + 1, data >> 8);
+}
+
+static void configure_memory_8bit(void)
+{
+ I.mem.fetch_xor = 0;
+
+ I.mem.rbyte = program_read_byte_8;
+ I.mem.rword = read_word_8;
+ I.mem.wbyte = program_write_byte_8;
+ I.mem.wword = write_word_8;
+
+ I.mem.rbyte_port = io_read_byte_8;
+ I.mem.rword_port = read_port_word_8;
+ I.mem.wbyte_port = io_write_byte_8;
+ I.mem.wword_port = write_port_word_8;
+}
+#endif
+
+
+/*****************************************************************************
+ 16-bit memory accessors
+ *****************************************************************************/
+
+#if (HAS_V30||HAS_V33||HAS_V35)
+static UINT16 read_word_16le(offs_t addr)
+{
+ if (!(addr & 1))
+ return program_read_word_16le(addr);
+ else
+ {
+ UINT16 result = program_read_byte_16le(addr);
+ return result | (program_read_byte_16le(addr + 1) << 8);
+ }
+}
+
+static void write_word_16le(offs_t addr, UINT16 data)
+{
+ if (!(addr & 1))
+ program_write_word_16le(addr, data);
+ else
+ {
+ program_write_byte_16le(addr, data);
+ program_write_byte_16le(addr + 1, data >> 8);
+ }
+}
+
+static UINT16 read_port_word_16le(offs_t addr)
+{
+ if (!(addr & 1))
+ return io_read_word_16le(addr);
+ else
+ {
+ UINT16 result = io_read_byte_16le(addr);
+ return result | (io_read_byte_16le(addr + 1) << 8);
+ }
+}
+
+static void write_port_word_16le(offs_t addr, UINT16 data)
+{
+ if (!(addr & 1))
+ io_write_word_16le(addr, data);
+ else
+ {
+ io_write_byte_16le(addr, data);
+ io_write_byte_16le(addr + 1, data >> 8);
+ }
+}
+
+static void configure_memory_16bit(void)
+{
+ I.mem.fetch_xor = BYTE_XOR_LE(0);
+
+ I.mem.rbyte = program_read_byte_16le;
+ I.mem.rword = read_word_16le;
+ I.mem.wbyte = program_write_byte_16le;
+ I.mem.wword = write_word_16le;
+
+ I.mem.rbyte_port = io_read_byte_16le;
+ I.mem.rword_port = read_port_word_16le;
+ I.mem.wbyte_port = io_write_byte_16le;
+ I.mem.wword_port = write_port_word_16le;
+}
+#endif
+
+
+/* Wrappers for the different CPU types */
+#if (HAS_V20||HAS_V25)
+void v20_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ nec_init(index, clock, config, irqcallback, 0);
+ configure_memory_8bit();
+}
+int v20_execute(int cycles)
+{
+ nec_ICount=cycles;
+ chip_type=V20;
+
+ while(nec_ICount>0) {
+ /* Dispatch IRQ */
+ if (I.pending_irq && I.no_interrupt==0)
+ {
+ if (I.pending_irq & NMI_IRQ)
+ external_int();
+ else if (I.IF)
+ external_int();
+ }
+
+ /* No interrupt allowed between last instruction and this one */
+ if (I.no_interrupt)
+ I.no_interrupt--;
+
+ CALL_MAME_DEBUG;
+ nec_instruction[FETCHOP]();
+ }
+ return cycles - nec_ICount;
+}
+#endif
+
+#if (HAS_V30||HAS_V35)
+void v30_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ nec_init(index, clock, config, irqcallback, 1);
+ configure_memory_16bit();
+}
+int v30_execute(int cycles) {
+ nec_ICount=cycles;
+ chip_type=V30;
+
+ while(nec_ICount>0) {
+ /* Dispatch IRQ */
+ if (I.pending_irq && I.no_interrupt==0)
+ {
+ if (I.pending_irq & NMI_IRQ)
+ external_int();
+ else if (I.IF)
+ external_int();
+ }
+
+ /* No interrupt allowed between last instruction and this one */
+ if (I.no_interrupt)
+ I.no_interrupt--;
+
+ CALL_MAME_DEBUG;
+ nec_instruction[FETCHOP]();
+ }
+ return cycles - nec_ICount;
+}
+#endif
+
+#if (HAS_V33)
+void v33_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ nec_init(index, clock, config, irqcallback, 2);
+ configure_memory_16bit();
+}
+int v33_execute(int cycles)
+{
+ nec_ICount=cycles;
+ chip_type=V33;
+
+ while(nec_ICount>0) {
+ /* Dispatch IRQ */
+ if (I.pending_irq && I.no_interrupt==0)
+ {
+ if (I.pending_irq & NMI_IRQ)
+ external_int();
+ else if (I.IF)
+ external_int();
+ }
+
+ /* No interrupt allowed between last instruction and this one */
+ if (I.no_interrupt)
+ I.no_interrupt--;
+
+ CALL_MAME_DEBUG;
+ nec_instruction[FETCHOP]();
+ }
+
+ return cycles - nec_ICount;
+}
+#endif
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void nec_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + NEC_PC:
+ if( info->i - (I.sregs[PS]<<4) < 0x10000 )
+ {
+ I.ip = info->i - (I.sregs[PS]<<4);
+ }
+ else
+ {
+ I.sregs[PS] = info->i >> 4;
+ I.ip = info->i & 0x0000f;
+ }
+ break;
+ case CPUINFO_INT_REGISTER + NEC_IP: I.ip = info->i; break;
+ case CPUINFO_INT_SP:
+ if( info->i - (I.sregs[SS]<<4) < 0x10000 )
+ {
+ I.regs.w[SP] = info->i - (I.sregs[SS]<<4);
+ }
+ else
+ {
+ I.sregs[SS] = info->i >> 4;
+ I.regs.w[SP] = info->i & 0x0000f;
+ }
+ break;
+ case CPUINFO_INT_REGISTER + NEC_SP: I.regs.w[SP] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_FLAGS: ExpandFlags(info->i); break;
+ case CPUINFO_INT_REGISTER + NEC_AW: I.regs.w[AW] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_CW: I.regs.w[CW] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_DW: I.regs.w[DW] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_BW: I.regs.w[BW] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_BP: I.regs.w[BP] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_IX: I.regs.w[IX] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_IY: I.regs.w[IY] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_ES: I.sregs[DS1] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_CS: I.sregs[PS] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_SS: I.sregs[SS] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_DS: I.sregs[DS0] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_VECTOR: I.int_vector = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void nec_get_info(UINT32 state, cpuinfo *info)
+{
+ int flags;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(I); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 15; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 80; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 20; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = (I.pending_irq & INT_IRQ) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = I.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not supported */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + NEC_PC: info->i = ((I.sregs[PS]<<4) + I.ip); break;
+ case CPUINFO_INT_REGISTER + NEC_IP: info->i = I.ip; break;
+ case CPUINFO_INT_SP: info->i = (I.sregs[SS]<<4) + I.regs.w[SP]; break;
+ case CPUINFO_INT_REGISTER + NEC_SP: info->i = I.regs.w[SP]; break;
+ case CPUINFO_INT_REGISTER + NEC_FLAGS: info->i = CompressFlags(); break;
+ case CPUINFO_INT_REGISTER + NEC_AW: info->i = I.regs.w[AW]; break;
+ case CPUINFO_INT_REGISTER + NEC_CW: info->i = I.regs.w[CW]; break;
+ case CPUINFO_INT_REGISTER + NEC_DW: info->i = I.regs.w[DW]; break;
+ case CPUINFO_INT_REGISTER + NEC_BW: info->i = I.regs.w[BW]; break;
+ case CPUINFO_INT_REGISTER + NEC_BP: info->i = I.regs.w[BP]; break;
+ case CPUINFO_INT_REGISTER + NEC_IX: info->i = I.regs.w[IX]; break;
+ case CPUINFO_INT_REGISTER + NEC_IY: info->i = I.regs.w[IY]; break;
+ case CPUINFO_INT_REGISTER + NEC_ES: info->i = I.sregs[DS1]; break;
+ case CPUINFO_INT_REGISTER + NEC_CS: info->i = I.sregs[PS]; break;
+ case CPUINFO_INT_REGISTER + NEC_SS: info->i = I.sregs[SS]; break;
+ case CPUINFO_INT_REGISTER + NEC_DS: info->i = I.sregs[DS0]; break;
+ case CPUINFO_INT_REGISTER + NEC_VECTOR: info->i = I.int_vector; break;
+ case CPUINFO_INT_REGISTER + NEC_PENDING: info->i = I.pending_irq; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = nec_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = nec_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = nec_set_context; break;
+ case CPUINFO_PTR_INIT: /* set per-CPU */ break;
+ case CPUINFO_PTR_RESET: info->reset = nec_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = nec_exit; break;
+ case CPUINFO_PTR_EXECUTE: /* set per-CPU */ break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = nec_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &nec_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "NEC"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "NEC V-Series"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.5"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "NEC emulator v1.5 by Bryan McPhail"); break;
+
+ case CPUINFO_STR_FLAGS:
+ flags = CompressFlags();
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ flags & 0x8000 ? 'M':'.',
+ flags & 0x4000 ? '?':'.',
+ flags & 0x2000 ? '?':'.',
+ flags & 0x1000 ? '?':'.',
+ flags & 0x0800 ? 'O':'.',
+ flags & 0x0400 ? 'D':'.',
+ flags & 0x0200 ? 'I':'.',
+ flags & 0x0100 ? 'T':'.',
+ flags & 0x0080 ? 'S':'.',
+ flags & 0x0040 ? 'Z':'.',
+ flags & 0x0020 ? '?':'.',
+ flags & 0x0010 ? 'A':'.',
+ flags & 0x0008 ? '?':'.',
+ flags & 0x0004 ? 'P':'.',
+ flags & 0x0002 ? 'N':'.',
+ flags & 0x0001 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + NEC_PC: sprintf(info->s, "PC:%04X", (I.sregs[PS]<<4) + I.ip); break;
+ case CPUINFO_STR_REGISTER + NEC_IP: sprintf(info->s, "IP:%04X", I.ip); break;
+ case CPUINFO_STR_REGISTER + NEC_SP: sprintf(info->s, "SP:%04X", I.regs.w[SP]); break;
+ case CPUINFO_STR_REGISTER + NEC_FLAGS: sprintf(info->s, "F:%04X", CompressFlags()); break;
+ case CPUINFO_STR_REGISTER + NEC_AW: sprintf(info->s, "AW:%04X", I.regs.w[AW]); break;
+ case CPUINFO_STR_REGISTER + NEC_CW: sprintf(info->s, "CW:%04X", I.regs.w[CW]); break;
+ case CPUINFO_STR_REGISTER + NEC_DW: sprintf(info->s, "DW:%04X", I.regs.w[DW]); break;
+ case CPUINFO_STR_REGISTER + NEC_BW: sprintf(info->s, "BW:%04X", I.regs.w[BW]); break;
+ case CPUINFO_STR_REGISTER + NEC_BP: sprintf(info->s, "BP:%04X", I.regs.w[BP]); break;
+ case CPUINFO_STR_REGISTER + NEC_IX: sprintf(info->s, "IX:%04X", I.regs.w[IX]); break;
+ case CPUINFO_STR_REGISTER + NEC_IY: sprintf(info->s, "IY:%04X", I.regs.w[IY]); break;
+ case CPUINFO_STR_REGISTER + NEC_ES: sprintf(info->s, "DS1:%04X", I.sregs[DS1]); break;
+ case CPUINFO_STR_REGISTER + NEC_CS: sprintf(info->s, "PS:%04X", I.sregs[PS]); break;
+ case CPUINFO_STR_REGISTER + NEC_SS: sprintf(info->s, "SS:%04X", I.sregs[SS]); break;
+ case CPUINFO_STR_REGISTER + NEC_DS: sprintf(info->s, "DS0:%04X", I.sregs[DS0]); break;
+ case CPUINFO_STR_REGISTER + NEC_VECTOR: sprintf(info->s, "V:%02X", I.int_vector); break;
+ }
+}
+
+
+#if (HAS_V20)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void v20_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = v20_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = v20_execute; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "V20"); break;
+
+ default: nec_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_V25)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void v25_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = v20_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = v20_execute; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "V25"); break;
+
+ default: nec_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_V30)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void v30_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = v30_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = v30_execute; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "V30"); break;
+
+ default: nec_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_V33)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void v33_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = v33_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = v33_execute; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "V33"); break;
+
+ default: nec_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_V35)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void v35_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = v30_init; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = v30_execute; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "V35"); break;
+
+ default: nec_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/nec/nec.h b/src/emu/cpu/nec/nec.h
new file mode 100644
index 00000000000..b97251ccddc
--- /dev/null
+++ b/src/emu/cpu/nec/nec.h
@@ -0,0 +1,370 @@
+#include "cpuintrf.h"
+
+typedef enum { DS1, PS, SS, DS0 } SREGS;
+typedef enum { AW, CW, DW, BW, SP, BP, IX, IY } WREGS;
+
+#define NEC_NMI_INT_VECTOR 2
+
+/* Cpu types, steps of 8 to help the cycle count calculation */
+#define V33 0
+#define V30 8
+#define V20 16
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+#ifdef LSB_FIRST
+typedef enum { AL,AH,CL,CH,DL,DH,BL,BH,SPL,SPH,BPL,BPH,IXL,IXH,IYL,IYH } BREGS;
+#else
+typedef enum { AH,AL,CH,CL,DH,DL,BH,BL,SPH,SPL,BPH,BPL,IXH,IXL,IYH,IYL } BREGS;
+#endif
+
+/* parameter x = result, y = source 1, z = source 2 */
+
+#define SetTF(x) (I.TF = (x))
+#define SetIF(x) (I.IF = (x))
+#define SetDF(x) (I.DF = (x))
+#define SetMD(x) (I.MF = (x)) /* OB [19.07.99] Mode Flag V30 */
+
+#define SetCFB(x) (I.CarryVal = (x) & 0x100)
+#define SetCFW(x) (I.CarryVal = (x) & 0x10000)
+#define SetAF(x,y,z) (I.AuxVal = ((x) ^ ((y) ^ (z))) & 0x10)
+#define SetSF(x) (I.SignVal = (x))
+#define SetZF(x) (I.ZeroVal = (x))
+#define SetPF(x) (I.ParityVal = (x))
+
+#define SetSZPF_Byte(x) (I.SignVal=I.ZeroVal=I.ParityVal=(INT8)(x))
+#define SetSZPF_Word(x) (I.SignVal=I.ZeroVal=I.ParityVal=(INT16)(x))
+
+#define SetOFW_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x8000)
+#define SetOFB_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x80)
+#define SetOFW_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x8000)
+#define SetOFB_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x80)
+
+#define ADDB { UINT32 res=dst+src; SetCFB(res); SetOFB_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; }
+#define ADDW { UINT32 res=dst+src; SetCFW(res); SetOFW_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; }
+
+#define SUBB { UINT32 res=dst-src; SetCFB(res); SetOFB_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; }
+#define SUBW { UINT32 res=dst-src; SetCFW(res); SetOFW_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; }
+
+#define ORB dst|=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst)
+#define ORW dst|=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst)
+
+#define ANDB dst&=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst)
+#define ANDW dst&=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst)
+
+#define XORB dst^=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst)
+#define XORW dst^=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst)
+
+#define CF (I.CarryVal!=0)
+#define SF (I.SignVal<0)
+#define ZF (I.ZeroVal==0)
+#define PF parity_table[(BYTE)I.ParityVal]
+#define AF (I.AuxVal!=0)
+#define OF (I.OverVal!=0)
+#define MD (I.MF!=0)
+
+/************************************************************************/
+
+#define read_byte(a) (*I.mem.rbyte)(a)
+#define read_word(a) (*I.mem.rword)(a)
+#define write_byte(a,d) (*I.mem.wbyte)((a),(d))
+#define write_word(a,d) (*I.mem.wword)((a),(d))
+
+#define read_port_byte(a) (*I.mem.rbyte_port)(a)
+#define read_port_word(a) (*I.mem.rword_port)(a)
+#define write_port_byte(a,d) (*I.mem.wbyte_port)((a),(d))
+#define write_port_word(a,d) (*I.mem.wword_port)((a),(d))
+
+/************************************************************************/
+
+#define CHANGE_PC change_pc((I.sregs[PS]<<4) + I.ip)
+
+#define SegBase(Seg) (I.sregs[Seg] << 4)
+
+#define DefaultBase(Seg) ((seg_prefix && (Seg==DS0 || Seg==SS)) ? prefix_base : I.sregs[Seg] << 4)
+
+#define GetMemB(Seg,Off) (read_byte(DefaultBase(Seg) + (Off)))
+#define GetMemW(Seg,Off) (read_word(DefaultBase(Seg) + (Off)))
+
+#define PutMemB(Seg,Off,x) { write_byte(DefaultBase(Seg) + (Off), (x)); }
+#define PutMemW(Seg,Off,x) { write_word(DefaultBase(Seg) + (Off), (x)); }
+
+#define FETCH_XOR(a) ((a) ^ I.mem.fetch_xor)
+#define FETCH (cpu_readop_arg(FETCH_XOR((I.sregs[PS]<<4)+I.ip++)))
+#define FETCHOP (cpu_readop(FETCH_XOR((I.sregs[PS]<<4)+I.ip++)))
+#define FETCHWORD(var) { var=cpu_readop_arg(FETCH_XOR((I.sregs[PS]<<4)+I.ip))+(cpu_readop_arg(FETCH_XOR((I.sregs[PS]<<4)+I.ip+1))<<8); I.ip+=2; }
+#define PUSH(val) { I.regs.w[SP]-=2; write_word((((I.sregs[SS]<<4)+I.regs.w[SP])),val); }
+#define POP(var) { var = read_word((((I.sregs[SS]<<4)+I.regs.w[SP]))); I.regs.w[SP]+=2; }
+#define PEEK(addr) ((BYTE)cpu_readop_arg(FETCH_XOR(addr)))
+#define PEEKOP(addr) ((BYTE)cpu_readop(FETCH_XOR(addr)))
+
+#define GetModRM UINT32 ModRM=cpu_readop_arg(FETCH_XOR((I.sregs[PS]<<4)+I.ip++))
+
+/* Cycle count macros:
+ CLK - cycle count is the same on all processors
+ CLKS - cycle count differs between processors, list all counts
+ CLKW - cycle count for word read/write differs for odd/even source/destination address
+ CLKM - cycle count for reg/mem instructions
+ CLKR - cycle count for reg/mem instructions with different counts for odd/even addresses
+
+
+ Prefetch & buswait time is not emulated.
+ Extra cycles for PUSH'ing or POP'ing registers to odd addresses is not emulated.
+*/
+
+#define CLK(all) nec_ICount-=all
+#define CLKS(v20,v30,v33) { const UINT32 ccount=(v20<<16)|(v30<<8)|v33; nec_ICount-=(ccount>>chip_type)&0x7f; }
+#define CLKW(v20o,v30o,v33o,v20e,v30e,v33e,addr) { const UINT32 ocount=(v20o<<16)|(v30o<<8)|v33o, ecount=(v20e<<16)|(v30e<<8)|v33e; nec_ICount-=(addr&1)?((ocount>>chip_type)&0x7f):((ecount>>chip_type)&0x7f); }
+#define CLKM(v20,v30,v33,v20m,v30m,v33m) { const UINT32 ccount=(v20<<16)|(v30<<8)|v33, mcount=(v20m<<16)|(v30m<<8)|v33m; nec_ICount-=( ModRM >=0xc0 )?((ccount>>chip_type)&0x7f):((mcount>>chip_type)&0x7f); }
+#define CLKR(v20o,v30o,v33o,v20e,v30e,v33e,vall,addr) { const UINT32 ocount=(v20o<<16)|(v30o<<8)|v33o, ecount=(v20e<<16)|(v30e<<8)|v33e; if (ModRM >=0xc0) nec_ICount-=vall; else nec_ICount-=(addr&1)?((ocount>>chip_type)&0x7f):((ecount>>chip_type)&0x7f); }
+
+/************************************************************************/
+#define CompressFlags() (WORD)(CF | (PF << 2) | (AF << 4) | (ZF << 6) \
+ | (SF << 7) | (I.TF << 8) | (I.IF << 9) \
+ | (I.DF << 10) | (OF << 11)| (MD << 15))
+
+#define ExpandFlags(f) \
+{ \
+ I.CarryVal = (f) & 1; \
+ I.ParityVal = !((f) & 4); \
+ I.AuxVal = (f) & 16; \
+ I.ZeroVal = !((f) & 64); \
+ I.SignVal = (f) & 128 ? -1 : 0; \
+ I.TF = ((f) & 256) == 256; \
+ I.IF = ((f) & 512) == 512; \
+ I.DF = ((f) & 1024) == 1024; \
+ I.OverVal = (f) & 2048; \
+ I.MF = ((f) & 0x8000) == 0x8000; \
+}
+
+#define IncWordReg(Reg) \
+ unsigned tmp = (unsigned)I.regs.w[Reg]; \
+ unsigned tmp1 = tmp+1; \
+ I.OverVal = (tmp == 0x7fff); \
+ SetAF(tmp1,tmp,1); \
+ SetSZPF_Word(tmp1); \
+ I.regs.w[Reg]=tmp1
+
+#define DecWordReg(Reg) \
+ unsigned tmp = (unsigned)I.regs.w[Reg]; \
+ unsigned tmp1 = tmp-1; \
+ I.OverVal = (tmp == 0x8000); \
+ SetAF(tmp1,tmp,1); \
+ SetSZPF_Word(tmp1); \
+ I.regs.w[Reg]=tmp1
+
+#define JMP(flag) \
+ int tmp = (int)((INT8)FETCH); \
+ if (flag) \
+ { \
+ static const UINT8 table[3]={3,10,10}; \
+ I.ip = (WORD)(I.ip+tmp); \
+ nec_ICount-=table[chip_type/8]; \
+ CHANGE_PC; \
+ return; \
+ }
+
+#define ADJ4(param1,param2) \
+ if (AF || ((I.regs.b[AL] & 0xf) > 9)) \
+ { \
+ UINT16 tmp; \
+ tmp = I.regs.b[AL] + param1; \
+ I.regs.b[AL] = tmp; \
+ I.AuxVal = 1; \
+ I.CarryVal |= tmp & 0x100; \
+ } \
+ if (CF || (I.regs.b[AL]>0x9f)) \
+ { \
+ I.regs.b[AL] += param2; \
+ I.CarryVal = 1; \
+ } \
+ SetSZPF_Byte(I.regs.b[AL])
+
+#define ADJB(param1,param2) \
+ if (AF || ((I.regs.b[AL] & 0xf) > 9)) \
+ { \
+ I.regs.b[AL] += param1; \
+ I.regs.b[AH] += param2; \
+ I.AuxVal = 1; \
+ I.CarryVal = 1; \
+ } \
+ else \
+ { \
+ I.AuxVal = 0; \
+ I.CarryVal = 0; \
+ } \
+ I.regs.b[AL] &= 0x0F
+
+#define BITOP_BYTE \
+ ModRM = FETCH; \
+ if (ModRM >= 0xc0) { \
+ tmp=I.regs.b[Mod_RM.RM.b[ModRM]]; \
+ } \
+ else { \
+ (*GetEA[ModRM])(); \
+ tmp=read_byte(EA); \
+ }
+
+#define BITOP_WORD \
+ ModRM = FETCH; \
+ if (ModRM >= 0xc0) { \
+ tmp=I.regs.w[Mod_RM.RM.w[ModRM]]; \
+ } \
+ else { \
+ (*GetEA[ModRM])(); \
+ tmp=read_word(EA); \
+ }
+
+#define BIT_NOT \
+ if (tmp & (1<<tmp2)) \
+ tmp &= ~(1<<tmp2); \
+ else \
+ tmp |= (1<<tmp2)
+
+#define XchgAWReg(Reg) \
+ WORD tmp; \
+ tmp = I.regs.w[Reg]; \
+ I.regs.w[Reg] = I.regs.w[AW]; \
+ I.regs.w[AW] = tmp
+
+#define ROL_BYTE I.CarryVal = dst & 0x80; dst = (dst << 1)+CF
+#define ROL_WORD I.CarryVal = dst & 0x8000; dst = (dst << 1)+CF
+#define ROR_BYTE I.CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<7)
+#define ROR_WORD I.CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<15)
+#define ROLC_BYTE dst = (dst << 1) + CF; SetCFB(dst)
+#define ROLC_WORD dst = (dst << 1) + CF; SetCFW(dst)
+#define RORC_BYTE dst = (CF<<8)+dst; I.CarryVal = dst & 0x01; dst >>= 1
+#define RORC_WORD dst = (CF<<16)+dst; I.CarryVal = dst & 0x01; dst >>= 1
+#define SHL_BYTE(c) nec_ICount-=c; dst <<= c; SetCFB(dst); SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst)
+#define SHL_WORD(c) nec_ICount-=c; dst <<= c; SetCFW(dst); SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst)
+#define SHR_BYTE(c) nec_ICount-=c; dst >>= c-1; I.CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst)
+#define SHR_WORD(c) nec_ICount-=c; dst >>= c-1; I.CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst)
+#define SHRA_BYTE(c) nec_ICount-=c; dst = ((INT8)dst) >> (c-1); I.CarryVal = dst & 0x1; dst = ((INT8)((BYTE)dst)) >> 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst)
+#define SHRA_WORD(c) nec_ICount-=c; dst = ((INT16)dst) >> (c-1); I.CarryVal = dst & 0x1; dst = ((INT16)((WORD)dst)) >> 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst)
+
+#define DIVUB \
+ uresult = I.regs.w[AW]; \
+ uresult2 = uresult % tmp; \
+ if ((uresult /= tmp) > 0xff) { \
+ nec_interrupt(0,0); break; \
+ } else { \
+ I.regs.b[AL] = uresult; \
+ I.regs.b[AH] = uresult2; \
+ }
+
+#define DIVB \
+ result = (INT16)I.regs.w[AW]; \
+ result2 = result % (INT16)((INT8)tmp); \
+ if ((result /= (INT16)((INT8)tmp)) > 0xff) { \
+ nec_interrupt(0,0); break; \
+ } else { \
+ I.regs.b[AL] = result; \
+ I.regs.b[AH] = result2; \
+ }
+
+#define DIVUW \
+ uresult = (((UINT32)I.regs.w[DW]) << 16) | I.regs.w[AW];\
+ uresult2 = uresult % tmp; \
+ if ((uresult /= tmp) > 0xffff) { \
+ nec_interrupt(0,0); break; \
+ } else { \
+ I.regs.w[AW]=uresult; \
+ I.regs.w[DW]=uresult2; \
+ }
+
+#define DIVW \
+ result = ((UINT32)I.regs.w[DW] << 16) + I.regs.w[AW]; \
+ result2 = result % (INT32)((INT16)tmp); \
+ if ((result /= (INT32)((INT16)tmp)) > 0xffff) { \
+ nec_interrupt(0,0); break; \
+ } else { \
+ I.regs.w[AW]=result; \
+ I.regs.w[DW]=result2; \
+ }
+
+#define ADD4S { \
+ int i,v1,v2,result; \
+ int count = (I.regs.b[CL]+1)/2; \
+ unsigned di = I.regs.w[IY]; \
+ unsigned si = I.regs.w[IX]; \
+ static const UINT8 table[3]={18,19,19}; \
+ if (seg_prefix) logerror("%06x: Warning: seg_prefix defined for add4s\n",activecpu_get_pc()); \
+ I.ZeroVal = I.CarryVal = 0; \
+ for (i=0;i<count;i++) { \
+ nec_ICount-=table[chip_type/8]; \
+ tmp = GetMemB(DS0, si); \
+ tmp2 = GetMemB(DS1, di); \
+ v1 = (tmp>>4)*10 + (tmp&0xf); \
+ v2 = (tmp2>>4)*10 + (tmp2&0xf); \
+ result = v1+v2+I.CarryVal; \
+ I.CarryVal = result > 99 ? 1 : 0; \
+ result = result % 100; \
+ v1 = ((result/10)<<4) | (result % 10); \
+ PutMemB(DS1, di,v1); \
+ if (v1) I.ZeroVal = 1; \
+ si++; \
+ di++; \
+ } \
+}
+
+#define SUB4S { \
+ int count = (I.regs.b[CL]+1)/2; \
+ int i,v1,v2,result; \
+ unsigned di = I.regs.w[IY]; \
+ unsigned si = I.regs.w[IX]; \
+ static const UINT8 table[3]={18,19,19}; \
+ if (seg_prefix) logerror("%06x: Warning: seg_prefix defined for sub4s\n",activecpu_get_pc()); \
+ I.ZeroVal = I.CarryVal = 0; \
+ for (i=0;i<count;i++) { \
+ nec_ICount-=table[chip_type/8]; \
+ tmp = GetMemB(DS1, di); \
+ tmp2 = GetMemB(DS0, si); \
+ v1 = (tmp>>4)*10 + (tmp&0xf); \
+ v2 = (tmp2>>4)*10 + (tmp2&0xf); \
+ if (v1 < (v2+I.CarryVal)) { \
+ v1+=100; \
+ result = v1-(v2+I.CarryVal); \
+ I.CarryVal = 1; \
+ } else { \
+ result = v1-(v2+I.CarryVal); \
+ I.CarryVal = 0; \
+ } \
+ v1 = ((result/10)<<4) | (result % 10); \
+ PutMemB(DS1, di,v1); \
+ if (v1) I.ZeroVal = 1; \
+ si++; \
+ di++; \
+ } \
+}
+
+#define CMP4S { \
+ int count = (I.regs.b[CL]+1)/2; \
+ int i,v1,v2,result; \
+ unsigned di = I.regs.w[IY]; \
+ unsigned si = I.regs.w[IX]; \
+ static const UINT8 table[3]={14,19,19}; \
+ if (seg_prefix) logerror("%06x: Warning: seg_prefix defined for cmp4s\n",activecpu_get_pc()); \
+ I.ZeroVal = I.CarryVal = 0; \
+ for (i=0;i<count;i++) { \
+ nec_ICount-=table[chip_type/8]; \
+ tmp = GetMemB(DS1, di); \
+ tmp2 = GetMemB(DS0, si); \
+ v1 = (tmp>>4)*10 + (tmp&0xf); \
+ v2 = (tmp2>>4)*10 + (tmp2&0xf); \
+ if (v1 < (v2+I.CarryVal)) { \
+ v1+=100; \
+ result = v1-(v2+I.CarryVal); \
+ I.CarryVal = 1; \
+ } else { \
+ result = v1-(v2+I.CarryVal); \
+ I.CarryVal = 0; \
+ } \
+ v1 = ((result/10)<<4) | (result % 10); \
+ if (v1) I.ZeroVal = 1; \
+ si++; \
+ di++; \
+ } \
+}
diff --git a/src/emu/cpu/nec/necdasm.c b/src/emu/cpu/nec/necdasm.c
new file mode 100644
index 00000000000..9869d12fdcd
--- /dev/null
+++ b/src/emu/cpu/nec/necdasm.c
@@ -0,0 +1,1522 @@
+/*
+ NEC V-series Disassembler
+
+ Originally Written for i386 by Ville Linde
+ Converted to NEC-V by Aaron Giles
+*/
+
+#include "cpuintrf.h"
+
+enum {
+ PARAM_REG8 = 1, /* 8-bit register */
+ PARAM_REG16, /* 16-bit register */
+ PARAM_REG2_8, /* 8-bit register */
+ PARAM_REG2_16, /* 16-bit register */
+ PARAM_RM8, /* 8-bit memory or register */
+ PARAM_RM16, /* 16-bit memory or register */
+ PARAM_I4, /* 4-bit signed immediate */
+ PARAM_I8, /* 8-bit signed immediate */
+ PARAM_I16, /* 16-bit signed immediate */
+ PARAM_UI8, /* 8-bit unsigned immediate */
+ PARAM_UI16, /* 16-bit unsigned immediate */
+ PARAM_IMM, /* 16-bit immediate */
+ PARAM_ADDR, /* 16:16 address */
+ PARAM_REL8, /* 8-bit PC-relative displacement */
+ PARAM_REL16, /* 16-bit PC-relative displacement */
+ PARAM_MEM_OFFS_B, /* 8-bit mem offset */
+ PARAM_MEM_OFFS_W, /* 16-bit mem offset */
+ PARAM_SREG, /* segment register */
+ PARAM_RBANK, /* register bank (V25) */
+ PARAM_1, /* used by shift/rotate instructions */
+ PARAM_AL,
+ PARAM_CL,
+ PARAM_DL,
+ PARAM_BL,
+ PARAM_AH,
+ PARAM_CH,
+ PARAM_DH,
+ PARAM_BH,
+ PARAM_AW,
+ PARAM_CW,
+ PARAM_DW,
+ PARAM_BW,
+ PARAM_SP,
+ PARAM_BP,
+ PARAM_IX,
+ PARAM_IY
+};
+
+enum {
+ MODRM = 1,
+ GROUP,
+ FPU,
+ TWO_BYTE,
+ PREFIX,
+ SEG_PS,
+ SEG_DS0,
+ SEG_DS1,
+ SEG_SS
+};
+
+typedef struct {
+ char mnemonic[32];
+ UINT32 flags;
+ UINT32 param1;
+ UINT32 param2;
+ UINT32 param3;
+ offs_t dasm_flags;
+} I386_OPCODE;
+
+typedef struct {
+ char mnemonic[32];
+ const I386_OPCODE *opcode;
+} GROUP_OP;
+
+static const UINT8 *opcode_ptr;
+static const UINT8 *opcode_ptr_base;
+
+static const I386_OPCODE necv_opcode_table1[256] =
+{
+ // 0x00
+ {"add", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"add", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"add", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"add", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"add", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"add", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"push ds1", 0, 0, 0, 0 },
+ {"pop ds1", 0, 0, 0, 0 },
+ {"or", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"or", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"or", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"or", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"or", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"or", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"push ps", 0, 0, 0, 0 },
+ {"two_byte", TWO_BYTE, 0, 0, 0 },
+ // 0x10
+ {"addc", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"addc", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"addc", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"addc", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"addc", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"addc", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"push ss", 0, 0, 0, 0 },
+ {"pop ss", 0, 0, 0, 0 },
+ {"subc", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"subc", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"subc", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"subc", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"subc", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"subc", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"push ds0", 0, 0, 0, 0 },
+ {"pop ds0", 0, 0, 0, 0 },
+ // 0x20
+ {"and", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"and", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"and", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"and", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"and", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"and", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"ds1:", SEG_DS1, 0, 0, 0 },
+ {"adj4a", 0, 0, 0, 0 },
+ {"sub", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"sub", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"sub", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"sub", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"sub", 0, PARAM_AL, PARAM_I8, 0 },
+ {"sub", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"ps:", SEG_PS, 0, 0, 0 },
+ {"adj4s", 0, 0, 0, 0 },
+ // 0x30
+ {"xor", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"xor", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"xor", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"xor", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"xor", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"xor", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"ss:", SEG_SS, 0, 0, 0 },
+ {"adjba", 0, 0, 0, 0 },
+ {"cmp", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"cmp", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"cmp", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"cmp", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"cmp", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"cmp", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"ds0:", SEG_DS0, 0, 0, 0 },
+ {"adjbs", 0, 0, 0, 0 },
+ // 0x40
+ {"inc", 0, PARAM_AW, 0, 0 },
+ {"inc", 0, PARAM_CW, 0, 0 },
+ {"inc", 0, PARAM_DW, 0, 0 },
+ {"inc", 0, PARAM_BW, 0, 0 },
+ {"inc", 0, PARAM_SP, 0, 0 },
+ {"inc", 0, PARAM_BP, 0, 0 },
+ {"inc", 0, PARAM_IX, 0, 0 },
+ {"inc", 0, PARAM_IY, 0, 0 },
+ {"dec", 0, PARAM_AW, 0, 0 },
+ {"dec", 0, PARAM_CW, 0, 0 },
+ {"dec", 0, PARAM_DW, 0, 0 },
+ {"dec", 0, PARAM_BW, 0, 0 },
+ {"dec", 0, PARAM_SP, 0, 0 },
+ {"dec", 0, PARAM_BP, 0, 0 },
+ {"dec", 0, PARAM_IX, 0, 0 },
+ {"dec", 0, PARAM_IY, 0, 0 },
+ // 0x50
+ {"push", 0, PARAM_AW, 0, 0 },
+ {"push", 0, PARAM_CW, 0, 0 },
+ {"push", 0, PARAM_DW, 0, 0 },
+ {"push", 0, PARAM_BW, 0, 0 },
+ {"push", 0, PARAM_SP, 0, 0 },
+ {"push", 0, PARAM_BP, 0, 0 },
+ {"push", 0, PARAM_IX, 0, 0 },
+ {"push", 0, PARAM_IY, 0, 0 },
+ {"pop", 0, PARAM_AW, 0, 0 },
+ {"pop", 0, PARAM_CW, 0, 0 },
+ {"pop", 0, PARAM_DW, 0, 0 },
+ {"pop", 0, PARAM_BW, 0, 0 },
+ {"pop", 0, PARAM_SP, 0, 0 },
+ {"pop", 0, PARAM_BP, 0, 0 },
+ {"pop", 0, PARAM_IX, 0, 0 },
+ {"pop", 0, PARAM_IY, 0, 0 },
+ // 0x60
+ {"push r", 0, 0, 0, 0 },
+ {"pop r", 0, 0, 0, 0 },
+ {"chkind", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"brkn", MODRM, PARAM_RM16, PARAM_REG16, 0 }, /* break into native */
+ {"repnc", PREFIX, 0, 0, 0 },
+ {"repc", PREFIX, 0, 0, 0 },
+ {"fpo2 0", 0,/*OP_SIZE*/ 0, 0, 0 },
+ {"fpo2 1", 0,/*ADDR_SIZE*/ 0, 0, 0 },
+ {"push", 0, PARAM_IMM, 0, 0 },
+ {"mul", MODRM, PARAM_REG16, PARAM_RM16, PARAM_IMM },
+ {"push", 0, PARAM_I8, 0, 0 },
+ {"mul", MODRM, PARAM_REG16, PARAM_RM16, PARAM_I8 },
+ {"inmb", 0, 0, 0, 0 },
+ {"inmw", 0, 0, 0, 0 },
+ {"outmb", 0, 0, 0, 0 },
+ {"outmw", 0, 0, 0, 0 },
+ // 0x70
+ {"bv", 0, PARAM_REL8, 0, 0 },
+ {"bnv", 0, PARAM_REL8, 0, 0 },
+ {"bc", 0, PARAM_REL8, 0, 0 },
+ {"bnc", 0, PARAM_REL8, 0, 0 },
+ {"be", 0, PARAM_REL8, 0, 0 },
+ {"bne", 0, PARAM_REL8, 0, 0 },
+ {"bnh", 0, PARAM_REL8, 0, 0 },
+ {"bh", 0, PARAM_REL8, 0, 0 },
+ {"bn", 0, PARAM_REL8, 0, 0 },
+ {"bp", 0, PARAM_REL8, 0, 0 },
+ {"bpe", 0, PARAM_REL8, 0, 0 },
+ {"bpo", 0, PARAM_REL8, 0, 0 },
+ {"blt", 0, PARAM_REL8, 0, 0 },
+ {"bge", 0, PARAM_REL8, 0, 0 },
+ {"ble", 0, PARAM_REL8, 0, 0 },
+ {"bgt", 0, PARAM_REL8, 0, 0 },
+ // 0x80
+ {"immb", GROUP, 0, 0, 0 },
+ {"immw", GROUP, 0, 0, 0 },
+ {"immb", GROUP, 0, 0, 0 },
+ {"immws", GROUP, 0, 0, 0 },
+ {"test", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"test", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"xch", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"xch", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"mov", MODRM, PARAM_RM8, PARAM_REG8, 0 },
+ {"mov", MODRM, PARAM_RM16, PARAM_REG16, 0 },
+ {"mov", MODRM, PARAM_REG8, PARAM_RM8, 0 },
+ {"mov", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"mov", MODRM, PARAM_RM16, PARAM_SREG, 0 },
+ {"ldea", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"mov", MODRM, PARAM_SREG, PARAM_RM16, 0 },
+ {"pop", MODRM, PARAM_RM16, 0, 0 },
+ // 0x90
+ {"nop", 0, 0, 0, 0 },
+ {"xch", 0, PARAM_AW, PARAM_CW, 0 },
+ {"xch", 0, PARAM_AW, PARAM_DW, 0 },
+ {"xch", 0, PARAM_AW, PARAM_BW, 0 },
+ {"xch", 0, PARAM_AW, PARAM_SP, 0 },
+ {"xch", 0, PARAM_AW, PARAM_BP, 0 },
+ {"xch", 0, PARAM_AW, PARAM_IX, 0 },
+ {"xch", 0, PARAM_AW, PARAM_IY, 0 },
+ {"cvtbw", 0, 0, 0, 0 },
+ {"cvtwl", 0, 0, 0, 0 },
+ {"call", 0, PARAM_ADDR, 0, 0, DASMFLAG_STEP_OVER},
+ {"poll", 0, 0, 0, 0 },
+ {"push psw", 0, 0, 0, 0 },
+ {"pop psw", 0, 0, 0, 0 },
+ {"mov psw,ah", 0, 0, 0, 0 },
+ {"mov ah,psw", 0, 0, 0, 0 },
+ // 0xa0
+ {"mov", 0, PARAM_AL, PARAM_MEM_OFFS_W, 0 },
+ {"mov", 0, PARAM_AW, PARAM_MEM_OFFS_W, 0 },
+ {"mov", 0, PARAM_MEM_OFFS_W, PARAM_AL, 0 },
+ {"mov", 0, PARAM_MEM_OFFS_W, PARAM_AW, 0 },
+ {"movbkb", 0, 0, 0, 0 },
+ {"movbkw", 0, 0, 0, 0 },
+ {"cmpbkb", 0, 0, 0, 0 },
+ {"cmpbkw", 0, 0, 0, 0 },
+ {"test", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"test", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"stmb", 0, 0, 0, 0 },
+ {"stmw", 0, 0, 0, 0 },
+ {"ldmb", 0, 0, 0, 0 },
+ {"ldmw", 0, 0, 0, 0 },
+ {"cmpmb", 0, 0, 0, 0 },
+ {"cmpmw", 0, 0, 0, 0 },
+ // 0xb0
+ {"mov", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_CL, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_DL, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_BL, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_AH, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_CH, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_DH, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_BH, PARAM_UI8, 0 },
+ {"mov", 0, PARAM_AW, PARAM_IMM, 0 },
+ {"mov", 0, PARAM_CW, PARAM_IMM, 0 },
+ {"mov", 0, PARAM_DW, PARAM_IMM, 0 },
+ {"mov", 0, PARAM_BW, PARAM_IMM, 0 },
+ {"mov", 0, PARAM_SP, PARAM_IMM, 0 },
+ {"mov", 0, PARAM_BP, PARAM_IMM, 0 },
+ {"mov", 0, PARAM_IX, PARAM_IMM, 0 },
+ {"mov", 0, PARAM_IY, PARAM_IMM, 0 },
+ // 0xc0
+ {"shiftbi", GROUP, 0, 0, 0 },
+ {"shiftwi", GROUP, 0, 0, 0 },
+ {"ret", 0, PARAM_I16, 0, 0, DASMFLAG_STEP_OUT},
+ {"ret", 0, 0, 0, 0, DASMFLAG_STEP_OUT},
+ {"mov ds1,", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"mov ds0,", MODRM, PARAM_REG16, PARAM_RM16, 0 },
+ {"mov", MODRM, PARAM_RM8, PARAM_UI8, 0 },
+ {"mov", MODRM, PARAM_RM16, PARAM_IMM, 0 },
+ {"prepare", 0, PARAM_I16, PARAM_UI8, 0 },
+ {"dispose", 0, 0, 0, 0 },
+ {"retf", 0, PARAM_I16, 0, 0, DASMFLAG_STEP_OUT},
+ {"retf", 0, 0, 0, 0, DASMFLAG_STEP_OUT},
+ {"brk 3", 0, 0, 0, 0, DASMFLAG_STEP_OVER},
+ {"brk", 0, PARAM_UI8, 0, 0, DASMFLAG_STEP_OVER},
+ {"brkv", 0, 0, 0, 0 },
+ {"reti", 0, 0, 0, 0, DASMFLAG_STEP_OUT},
+ // 0xd0
+ {"shiftb", GROUP, 0, 0, 0 },
+ {"shiftw", GROUP, 0, 0, 0 },
+ {"shiftbv", GROUP, 0, 0, 0 },
+ {"shiftwv", GROUP, 0, 0, 0 },
+ {"cvtbd", 0, PARAM_I8, 0, 0 },
+ {"cvtdb", 0, PARAM_I8, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"trans", 0, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ {"escape", FPU, 0, 0, 0 },
+ // 0xe0
+ {"dbnzne", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER},
+ {"dbnze", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER},
+ {"dbnz", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER},
+ {"bcwz", 0, PARAM_REL8, 0, 0 },
+ {"in", 0, PARAM_AL, PARAM_UI8, 0 },
+ {"in", 0, PARAM_AW, PARAM_UI8, 0 },
+ {"out", 0, PARAM_UI8, PARAM_AL, 0 },
+ {"out", 0, PARAM_UI8, PARAM_AW, 0 },
+ {"call", 0, PARAM_REL16, 0, 0, DASMFLAG_STEP_OVER},
+ {"br", 0, PARAM_REL16, 0, 0 },
+ {"br", 0, PARAM_ADDR, 0, 0 },
+ {"br", 0, PARAM_REL8, 0, 0 },
+ {"in", 0, PARAM_AL, PARAM_DW, 0 },
+ {"in", 0, PARAM_AW, PARAM_DW, 0 },
+ {"out", 0, PARAM_DW, PARAM_AL, 0 },
+ {"out", 0, PARAM_DW, PARAM_AW, 0 },
+ // 0xf0
+ {"buslock", PREFIX, 0, 0, 0 },
+ {"brks", 0, 0, 0, 0 }, /* break into secure mode */
+ {"repne", PREFIX, 0, 0, 0 },
+ {"rep", PREFIX, 0, 0, 0 },
+ {"halt", 0, 0, 0, 0 },
+ {"not1 cy", 0, 0, 0, 0 },
+ {"group1b", GROUP, 0, 0, 0 },
+ {"group1w", GROUP, 0, 0, 0 },
+ {"clr1 cy", 0, 0, 0, 0 },
+ {"set1 cy", 0, 0, 0, 0 },
+ {"di", 0, 0, 0, 0 },
+ {"ei", 0, 0, 0, 0 },
+ {"clr1 dir", 0, 0, 0, 0 },
+ {"set1 dir", 0, 0, 0, 0 },
+ {"group2b", GROUP, 0, 0, 0 },
+ {"group2w", GROUP, 0, 0, 0 }
+};
+
+static const I386_OPCODE necv_opcode_table2[256] =
+{
+ // 0x00
+ {"???", 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 },
+ // 0x10 - NEC V series only
+ {"test1", MODRM, PARAM_RM8, PARAM_1, 0 },
+ {"test1", MODRM, PARAM_RM16, PARAM_1, 0 },
+ {"clr1", MODRM, PARAM_RM8, PARAM_1, 0 },
+ {"clr1", MODRM, PARAM_RM16, PARAM_1, 0 },
+ {"set1", MODRM, PARAM_RM8, PARAM_1, 0 },
+ {"set1", MODRM, PARAM_RM16, PARAM_1, 0 },
+ {"not1", MODRM, PARAM_RM8, PARAM_1, 0 },
+ {"not1", MODRM, PARAM_RM16, PARAM_1, 0 },
+ {"test1", MODRM, PARAM_RM8, PARAM_I8, 0 },
+ {"test1", MODRM, PARAM_RM16, PARAM_I8, 0 },
+ {"clr1", MODRM, PARAM_RM8, PARAM_I8, 0 },
+ {"clr1", MODRM, PARAM_RM16, PARAM_I8, 0 },
+ {"set1", MODRM, PARAM_RM8, PARAM_I8, 0 },
+ {"set1", MODRM, PARAM_RM16, PARAM_I8, 0 },
+ {"not1", MODRM, PARAM_RM8, PARAM_I8, 0 },
+ {"not1", MODRM, PARAM_RM16, PARAM_I8, 0 },
+ // 0x20
+ {"add4s", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"sub4s", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"movspa", 0, 0, 0, 0 }, /* V25/35 only */
+ {"cmp4s", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"rol4", MODRM, PARAM_RM8, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"ror4", MODRM, PARAM_RM8, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"brkcs", MODRM, PARAM_REG2_8, 0, 0 }, /* V25/35 only */
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ // 0x30
+ {"???", 0, 0, 0, 0 },
+ {"ins", MODRM, PARAM_REG2_8, PARAM_REG8, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"ext", MODRM, PARAM_REG2_8, PARAM_REG8, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"ins", MODRM, PARAM_REG2_8, PARAM_I4, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"ext", MODRM, PARAM_REG2_8, PARAM_I4, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ // 0x40
+ {"???", 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 },
+ // 0x50
+ {"???", 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 },
+ // 0x60
+ {"???", 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 },
+ // 0x70
+ {"???", 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 },
+ // 0x80
+ {"???", 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 },
+ // 0x90
+ {"???", 0, 0, 0, 0 },
+ {"retrbi", 0, 0, 0, 0 }, /* V25/35 only */
+ {"fint", 0, 0, 0, 0 }, /* V25/35 only */
+ {"???", 0, 0, 0, 0 },
+ {"tsksw", MODRM, PARAM_REG2_8, 0, 0 }, /* V25/35 only */
+ {"movspb", 0, PARAM_RBANK, 0, 0 }, /* V25/35 only */
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"btclr", MODRM, PARAM_REG2_8, PARAM_I8, PARAM_REL8 }, /* V25/35 only */
+ {"???", 0, 0, 0, 0 },
+ {"stop", 0, 0, 0, 0 }, /* V25/35 only */
+ {"???", 0, 0, 0, 0 },
+ // 0xa0
+ {"???", 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 },
+ // 0xb0
+ {"???", 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 },
+ // 0xc0
+ {"???", 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 },
+ // 0xd0
+ {"???", 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 },
+ // 0xe0
+ {"brkxa", 0, PARAM_UI8, 0, 0 }, /* V33,53 only */
+ {"???", 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 },
+ // 0xf0
+ {"retxa", 0, PARAM_UI8, 0, 0 }, /* V33,53 only */
+ {"???", 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 },
+ {"brkem", 0, PARAM_UI8, 0, 0 } /* V20,30,40,50 only */
+};
+
+static const I386_OPCODE immb_table[8] =
+{
+ {"add", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"or", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"addc", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"subc", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"and", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"sub", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"xor", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"cmp", 0, PARAM_RM8, PARAM_I8, 0 }
+};
+
+static const I386_OPCODE immw_table[8] =
+{
+ {"add", 0, PARAM_RM16, PARAM_IMM, 0 },
+ {"or", 0, PARAM_RM16, PARAM_IMM, 0 },
+ {"addc", 0, PARAM_RM16, PARAM_IMM, 0 },
+ {"subc", 0, PARAM_RM16, PARAM_IMM, 0 },
+ {"and", 0, PARAM_RM16, PARAM_IMM, 0 },
+ {"sub", 0, PARAM_RM16, PARAM_IMM, 0 },
+ {"xor", 0, PARAM_RM16, PARAM_IMM, 0 },
+ {"cmp", 0, PARAM_RM16, PARAM_IMM, 0 }
+};
+
+static const I386_OPCODE immws_table[8] =
+{
+ {"add", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"or", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"addc", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"subc", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"and", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"sub", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"xor", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"cmp", 0, PARAM_RM16, PARAM_I8, 0 }
+};
+
+static const I386_OPCODE shiftbi_table[8] =
+{
+ {"rol", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"ror", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"rolc", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"rorc", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"shl", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"shr", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"???", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"shra", 0, PARAM_RM8, PARAM_I8, 0 }
+};
+
+static const I386_OPCODE shiftwi_table[8] =
+{
+ {"rol", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"ror", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"rolc", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"rorc", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"shl", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"shr", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"???", 0, PARAM_RM16, PARAM_I8, 0 },
+ {"shra", 0, PARAM_RM16, PARAM_I8, 0 }
+};
+
+static const I386_OPCODE shiftb_table[8] =
+{
+ {"rol", 0, PARAM_RM8, PARAM_1, 0 },
+ {"ror", 0, PARAM_RM8, PARAM_1, 0 },
+ {"rolc", 0, PARAM_RM8, PARAM_1, 0 },
+ {"rorc", 0, PARAM_RM8, PARAM_1, 0 },
+ {"shl", 0, PARAM_RM8, PARAM_1, 0 },
+ {"shr", 0, PARAM_RM8, PARAM_1, 0 },
+ {"???", 0, PARAM_RM8, PARAM_1, 0 },
+ {"shra", 0, PARAM_RM8, PARAM_1, 0 }
+};
+
+static const I386_OPCODE shiftw_table[8] =
+{
+ {"rol", 0, PARAM_RM16, PARAM_1, 0 },
+ {"ror", 0, PARAM_RM16, PARAM_1, 0 },
+ {"rolc", 0, PARAM_RM16, PARAM_1, 0 },
+ {"rorc", 0, PARAM_RM16, PARAM_1, 0 },
+ {"shl", 0, PARAM_RM16, PARAM_1, 0 },
+ {"shr", 0, PARAM_RM16, PARAM_1, 0 },
+ {"???", 0, PARAM_RM16, PARAM_1, 0 },
+ {"shra", 0, PARAM_RM16, PARAM_1, 0 }
+};
+
+static const I386_OPCODE shiftbv_table[8] =
+{
+ {"rol", 0, PARAM_RM8, PARAM_CL, 0 },
+ {"ror", 0, PARAM_RM8, PARAM_CL, 0 },
+ {"rolc", 0, PARAM_RM8, PARAM_CL, 0 },
+ {"rorc", 0, PARAM_RM8, PARAM_CL, 0 },
+ {"shl", 0, PARAM_RM8, PARAM_CL, 0 },
+ {"shr", 0, PARAM_RM8, PARAM_CL, 0 },
+ {"???", 0, PARAM_RM8, PARAM_CL, 0 },
+ {"shra", 0, PARAM_RM8, PARAM_CL, 0 }
+};
+
+static const I386_OPCODE shiftwv_table[8] =
+{
+ {"rol", 0, PARAM_RM16, PARAM_CL, 0 },
+ {"ror", 0, PARAM_RM16, PARAM_CL, 0 },
+ {"rolc", 0, PARAM_RM16, PARAM_CL, 0 },
+ {"rorc", 0, PARAM_RM16, PARAM_CL, 0 },
+ {"shl", 0, PARAM_RM16, PARAM_CL, 0 },
+ {"shr", 0, PARAM_RM16, PARAM_CL, 0 },
+ {"???", 0, PARAM_RM16, PARAM_CL, 0 },
+ {"shra", 0, PARAM_RM16, PARAM_CL, 0 }
+};
+
+static const I386_OPCODE group1b_table[8] =
+{
+ {"test", 0, PARAM_RM8, PARAM_I8, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"not", 0, PARAM_RM8, 0, 0 },
+ {"neg", 0, PARAM_RM8, 0, 0 },
+ {"mulu", 0, PARAM_RM8, 0, 0 },
+ {"mul", 0, PARAM_RM8, 0, 0 },
+ {"divu", 0, PARAM_RM8, 0, 0 },
+ {"div", 0, PARAM_RM8, 0, 0 }
+};
+
+static const I386_OPCODE group1w_table[8] =
+{
+ {"test", 0, PARAM_RM16, PARAM_IMM, 0 },
+ {"???", 0, 0, 0, 0 },
+ {"not", 0, PARAM_RM16, 0, 0 },
+ {"neg", 0, PARAM_RM16, 0, 0 },
+ {"mulu", 0, PARAM_RM16, 0, 0 },
+ {"mul", 0, PARAM_RM16, 0, 0 },
+ {"divu", 0, PARAM_RM16, 0, 0 },
+ {"div", 0, PARAM_RM16, 0, 0 }
+};
+
+static const I386_OPCODE group2b_table[8] =
+{
+ {"inc", 0, PARAM_RM8, 0, 0 },
+ {"dec", 0, PARAM_RM8, 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 I386_OPCODE group2w_table[8] =
+{
+ {"inc", 0, PARAM_RM16, 0, 0 },
+ {"dec", 0, PARAM_RM16, 0, 0 },
+ {"call", 0, PARAM_RM16, 0, 0, DASMFLAG_STEP_OVER},
+ {"call far ptr ",0, PARAM_RM16, 0, 0, DASMFLAG_STEP_OVER},
+ {"br", 0, PARAM_RM16, 0, 0 },
+ {"br far ptr ",0, PARAM_RM16, 0, 0 },
+ {"push", 0, PARAM_RM16, 0, 0 },
+ {"???", 0, 0, 0, 0 }
+};
+
+static const GROUP_OP group_op_table[] =
+{
+ { "immb", immb_table },
+ { "immw", immw_table },
+ { "immws", immws_table },
+ { "shiftbi", shiftbi_table },
+ { "shiftwi", shiftwi_table },
+ { "shiftb", shiftb_table },
+ { "shiftw", shiftw_table },
+ { "shiftbv", shiftbv_table },
+ { "shiftwv", shiftwv_table },
+ { "group1b", group1b_table },
+ { "group1w", group1w_table },
+ { "group2b", group2b_table },
+ { "group2w", group2w_table }
+};
+
+
+
+static const char *nec_reg[8] = { "aw", "cw", "dw", "bw", "sp", "bp", "ix", "iy" };
+static const char *neg_reg8[8] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" };
+static const char *nec_sreg[8] = { "ds1", "ps", "ss", "ds0", "???", "???", "???", "???" };
+
+static UINT32 pc;
+static UINT8 modrm;
+static UINT32 segment;
+static offs_t dasm_flags;
+static char modrm_string[256];
+
+#define MODRM_REG1 ((modrm >> 3) & 0x7)
+#define MODRM_REG2 (modrm & 0x7)
+
+INLINE UINT8 FETCH(void)
+{
+ if ((opcode_ptr - opcode_ptr_base) + 1 > 15)
+ return 0xff;
+ pc++;
+ return *opcode_ptr++;
+}
+
+INLINE UINT16 FETCH16(void)
+{
+ UINT16 d;
+ if ((opcode_ptr - opcode_ptr_base) + 2 > 15)
+ return 0xffff;
+ d = opcode_ptr[0] | (opcode_ptr[1] << 8);
+ opcode_ptr += 2;
+ pc += 2;
+ return d;
+}
+
+INLINE UINT8 FETCHD(void)
+{
+ if ((opcode_ptr - opcode_ptr_base) + 1 > 15)
+ return 0xff;
+ pc++;
+ return *opcode_ptr++;
+}
+
+INLINE UINT16 FETCHD16(void)
+{
+ UINT16 d;
+ if ((opcode_ptr - opcode_ptr_base) + 2 > 15)
+ return 0xffff;
+ d = opcode_ptr[0] | (opcode_ptr[1] << 8);
+ opcode_ptr += 2;
+ pc += 2;
+ return d;
+}
+
+static char *hexstring(UINT32 value, int digits)
+{
+ static char buffer[20];
+ buffer[0] = '0';
+ if (digits)
+ sprintf(&buffer[1], "%0*Xh", digits, value);
+ else
+ sprintf(&buffer[1], "%Xh", value);
+ return (buffer[1] >= '0' && buffer[1] <= '9') ? &buffer[1] : &buffer[0];
+}
+
+static char *shexstring(UINT32 value, int digits, int always)
+{
+ static char buffer[20];
+ if (value >= 0x80000000)
+ sprintf(buffer, "-%s", hexstring(-value, digits));
+ else if (always)
+ sprintf(buffer, "+%s", hexstring(value, digits));
+ else
+ return hexstring(value, digits);
+ return buffer;
+}
+
+static void handle_modrm(char* s)
+{
+ INT8 disp8;
+ INT16 disp16;
+ UINT8 mod, rm;
+
+ modrm = FETCHD();
+ mod = (modrm >> 6) & 0x3;
+ rm = (modrm & 0x7);
+
+ if( modrm >= 0xc0 )
+ return;
+
+ switch(segment)
+ {
+ case SEG_PS: s += sprintf( s, "ps:" ); break;
+ case SEG_DS0: s += sprintf( s, "ds0:" ); break;
+ case SEG_DS1: s += sprintf( s, "ds1:" ); break;
+ case SEG_SS: s += sprintf( s, "ss:" ); break;
+ }
+
+ s += sprintf( s, "[" );
+ switch( rm )
+ {
+ case 0: s += sprintf( s, "bw+ix" ); break;
+ case 1: s += sprintf( s, "bw+iy" ); break;
+ case 2: s += sprintf( s, "bw+ix" ); break;
+ case 3: s += sprintf( s, "bw+iy" ); break;
+ case 4: s += sprintf( s, "ix" ); break;
+ case 5: s += sprintf( s, "iy" ); break;
+ case 6:
+ if( mod == 0 ) {
+ disp16 = FETCHD16();
+ s += sprintf( s, "%s", hexstring((unsigned) (UINT16) disp16, 0) );
+ } else {
+ s += sprintf( s, "bp" );
+ }
+ break;
+ case 7: s += sprintf( s, "bw" ); break;
+ }
+ if( mod == 1 ) {
+ disp8 = FETCHD();
+ s += sprintf( s, "%s", shexstring((INT32)disp8, 0, TRUE) );
+ } else if( mod == 2 ) {
+ disp16 = FETCHD16();
+ s += sprintf( s, "%s", shexstring((INT32)disp16, 0, TRUE) );
+ }
+ s += sprintf( s, "]" );
+}
+
+static char* handle_param(char* s, UINT32 param)
+{
+ UINT8 i8;
+ UINT16 i16;
+ UINT16 ptr;
+ UINT32 addr;
+ INT8 d8;
+ INT16 d16;
+
+ switch(param)
+ {
+ case PARAM_REG8:
+ s += sprintf( s, "%s", neg_reg8[MODRM_REG1] );
+ break;
+
+ case PARAM_REG16:
+ s += sprintf( s, "%s", nec_reg[MODRM_REG1] );
+ break;
+
+ case PARAM_REG2_8:
+ s += sprintf( s, "%s", neg_reg8[MODRM_REG2] );
+ break;
+
+ case PARAM_REG2_16:
+ s += sprintf( s, "%s", nec_reg[MODRM_REG2] );
+ break;
+
+ case PARAM_RM8:
+ if( modrm >= 0xc0 ) {
+ s += sprintf( s, "%s", neg_reg8[MODRM_REG2] );
+ } else {
+ s += sprintf( s, "byte ptr " );
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_RM16:
+ if( modrm >= 0xc0 ) {
+ s += sprintf( s, "%s", nec_reg[MODRM_REG2] );
+ } else {
+ s += sprintf( s, "word ptr " );
+ s += sprintf( s, "%s", modrm_string );
+ }
+ break;
+
+ case PARAM_I4:
+ i8 = FETCHD();
+ s += sprintf( s, "%d", i8 & 0x0f );
+ break;
+
+ case PARAM_I8:
+ i8 = FETCHD();
+ s += sprintf( s, "%s", shexstring((INT8)i8, 0, FALSE) );
+ break;
+
+ case PARAM_I16:
+ i16 = FETCHD16();
+ s += sprintf( s, "%s", shexstring((INT16)i16, 0, FALSE) );
+ break;
+
+ case PARAM_UI8:
+ i8 = FETCHD();
+ s += sprintf( s, "%s", shexstring((UINT8)i8, 0, FALSE) );
+ break;
+
+ case PARAM_UI16:
+ i16 = FETCHD16();
+ s += sprintf( s, "%s", shexstring((UINT16)i16, 0, FALSE) );
+ break;
+
+ case PARAM_IMM:
+ i16 = FETCHD16();
+ s += sprintf( s, "%s", hexstring(i16, 0) );
+ break;
+
+ case PARAM_ADDR:
+ addr = FETCHD16();
+ ptr = FETCHD16();
+ s += sprintf( s, "%s:", hexstring(ptr, 4) );
+ s += sprintf( s, "%s", hexstring(addr, 0) );
+ break;
+
+ case PARAM_REL16:
+ /* make sure to keep the relative offset within the segment */
+ d16 = FETCHD16();
+ s += sprintf( s, "%s", hexstring((pc & 0xFFFF0000) | ((pc + d16) & 0x0000FFFF), 0) );
+ break;
+
+ case PARAM_REL8:
+ d8 = FETCHD();
+ s += sprintf( s, "%s", hexstring(pc + d8, 0) );
+ break;
+
+ case PARAM_MEM_OFFS_B:
+ d8 = FETCHD();
+ s += sprintf( s, "[%s]", hexstring(d8, 0) );
+ break;
+
+ case PARAM_MEM_OFFS_W:
+ d16 = FETCHD16();
+ s += sprintf( s, "[%s]", hexstring(d16, 0) );
+ break;
+
+ case PARAM_SREG:
+ s += sprintf( s, "%s", nec_sreg[MODRM_REG1] );
+ break;
+
+ case PARAM_1:
+ s += sprintf( s, "1" );
+ break;
+
+ case PARAM_RBANK:
+ s += sprintf( s, "%d", FETCHD() & 7 );
+ break;
+
+ case PARAM_AL: s += sprintf( s, "al" ); break;
+ case PARAM_CL: s += sprintf( s, "cl" ); break;
+ case PARAM_DL: s += sprintf( s, "dl" ); break;
+ case PARAM_BL: s += sprintf( s, "bl" ); break;
+ case PARAM_AH: s += sprintf( s, "ah" ); break;
+ case PARAM_CH: s += sprintf( s, "ch" ); break;
+ case PARAM_DH: s += sprintf( s, "dh" ); break;
+ case PARAM_BH: s += sprintf( s, "bh" ); break;
+
+ case PARAM_AW: s += sprintf( s, "aw" ); break;
+ case PARAM_CW: s += sprintf( s, "cw" ); break;
+ case PARAM_DW: s += sprintf( s, "dw" ); break;
+ case PARAM_BW: s += sprintf( s, "bw" ); break;
+ case PARAM_SP: s += sprintf( s, "sp" ); break;
+ case PARAM_BP: s += sprintf( s, "bp" ); break;
+ case PARAM_IX: s += sprintf( s, "ix" ); break;
+ case PARAM_IY: s += sprintf( s, "iy" ); break;
+ }
+ return s;
+}
+
+static void handle_fpu(char *s, UINT8 op1, UINT8 op2)
+{
+ switch (op1 & 0x7)
+ {
+ case 0: // Group D8
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fadd dword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "fmul dword ptr %s", modrm_string); break;
+ case 2: sprintf(s, "fcom dword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fcomp dword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fsub dword ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fsubr dword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fdiv dword ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fdivr dword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fadd st(0),st(%d)", op2 & 0x7); break;
+ case 1: sprintf(s, "fcom st(0),st(%d)", op2 & 0x7); break;
+ case 2: sprintf(s, "fsub st(0),st(%d)", op2 & 0x7); break;
+ case 3: sprintf(s, "fdiv st(0),st(%d)", op2 & 0x7); break;
+ case 4: sprintf(s, "fmul st(0),st(%d)", op2 & 0x7); break;
+ case 5: sprintf(s, "fcomp st(0),st(%d)", op2 & 0x7); break;
+ case 6: sprintf(s, "fsubr st(0),st(%d)", op2 & 0x7); break;
+ case 7: sprintf(s, "fdivr st(0),st(%d)", op2 & 0x7); break;
+ }
+ }
+ break;
+ }
+
+ case 1: // Group D9
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fld dword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "??? (FPU)"); break;
+ case 2: sprintf(s, "fst dword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fstp dword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fldenv word ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fldcw word ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fstenv word ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fstcw word ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "fld st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fxch st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x10: sprintf(s, "fnop"); break;
+ case 0x20: sprintf(s, "fchs"); break;
+ case 0x21: sprintf(s, "fabs"); break;
+ case 0x24: sprintf(s, "ftst"); break;
+ case 0x25: sprintf(s, "fxam"); break;
+ case 0x28: sprintf(s, "fld1"); break;
+ case 0x29: sprintf(s, "fldl2t"); break;
+ case 0x2a: sprintf(s, "fldl2e"); break;
+ case 0x2b: sprintf(s, "fldpi"); break;
+ case 0x2c: sprintf(s, "fldlg2"); break;
+ case 0x2d: sprintf(s, "fldln2"); break;
+ case 0x2e: sprintf(s, "fldz"); break;
+ case 0x30: sprintf(s, "f2xm1"); break;
+ case 0x31: sprintf(s, "fyl2x"); break;
+ case 0x32: sprintf(s, "fptan"); break;
+ case 0x33: sprintf(s, "fpatan"); break;
+ case 0x34: sprintf(s, "fxtract"); break;
+ case 0x35: sprintf(s, "fprem1"); break;
+ case 0x36: sprintf(s, "fdecstp"); break;
+ case 0x37: sprintf(s, "fincstp"); break;
+ case 0x38: sprintf(s, "fprem"); break;
+ case 0x39: sprintf(s, "fyl2xp1"); break;
+ case 0x3a: sprintf(s, "fsqrt"); break;
+ case 0x3b: sprintf(s, "fsincos"); break;
+ case 0x3c: sprintf(s, "frndint"); break;
+ case 0x3d: sprintf(s, "fscale"); break;
+ case 0x3e: sprintf(s, "fsin"); break;
+ case 0x3f: sprintf(s, "fcos"); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 2: // Group DA
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fiadd dword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "fimul dword ptr %s", modrm_string); break;
+ case 2: sprintf(s, "ficom dword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "ficomp dword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fisub dword ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fisubr dword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fidiv dword ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fidivr dword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "fcmovb st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fcmove st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ sprintf(s, "fcmovbe st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ sprintf(s, "fcmovu st(0),st(%d)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+
+ }
+ }
+ break;
+ }
+
+ case 3: // Group DB
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fild dword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "??? (FPU)"); break;
+ case 2: sprintf(s, "fist dword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fistp dword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "??? (FPU)"); break;
+ case 5: sprintf(s, "fld tword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "??? (FPU)"); break;
+ case 7: sprintf(s, "fstp tword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "fcmovnb st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fcmovne st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ sprintf(s, "fcmovnbe st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ sprintf(s, "fcmovnu st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x22: sprintf(s, "fclex"); break;
+ case 0x23: sprintf(s, "finit"); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fucomi st(0),st(%d)", op2 & 0x7); break;
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ sprintf(s, "fcomi st(0),st(%d)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 4: // Group DC
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fadd qword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "fmul qword ptr %s", modrm_string); break;
+ case 2: sprintf(s, "fcom qword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fcomp qword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fsub qword ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fsubr qword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fdiv qword ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fdivr qword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "fadd st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fmul st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+ sprintf(s, "fsubr st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fsub st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ sprintf(s, "fdivr st(%d),st(0)", op2 & 0x7); break;
+
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ sprintf(s, "fdiv st(%d),st(0)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 5: // Group DD
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fld qword ptr %s", modrm_string); break;
+ case 1: sprintf(s, "??? (FPU)"); break;
+ case 2: sprintf(s, "fst qword ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fstp qword ptr %s", modrm_string); break;
+ case 4: sprintf(s, "frstor %s", modrm_string); break;
+ case 5: sprintf(s, "??? (FPU)"); break;
+ case 6: sprintf(s, "fsave %s", modrm_string); break;
+ case 7: sprintf(s, "fstsw word ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "ffree st(%d)", op2 & 0x7); break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ sprintf(s, "fst st(%d)", op2 & 0x7); break;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ sprintf(s, "fstp st(%d)", op2 & 0x7); break;
+
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+ sprintf(s, "fucom st(%d), st(0)", op2 & 0x7); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fucomp st(%d)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 6: // Group DE
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fiadd word ptr %s", modrm_string); break;
+ case 1: sprintf(s, "fimul word ptr %s", modrm_string); break;
+ case 2: sprintf(s, "ficom word ptr %s", modrm_string); break;
+ case 3: sprintf(s, "ficomp word ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fisub word ptr %s", modrm_string); break;
+ case 5: sprintf(s, "fisubr word ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fidiv word ptr %s", modrm_string); break;
+ case 7: sprintf(s, "fidivr word ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
+ sprintf(s, "faddp st(%d)", op2 & 0x7); break;
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ sprintf(s, "fmulp st(%d)", op2 & 0x7); break;
+
+ case 0x19: sprintf(s, "fcompp"); break;
+
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+ sprintf(s, "fsubrp st(%d)", op2 & 0x7); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fsubp st(%d)", op2 & 0x7); break;
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ sprintf(s, "fdivrp st(%d), st(0)", op2 & 0x7); break;
+
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ sprintf(s, "fdivp st(%d)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+
+ case 7: // Group DF
+ {
+ if (op2 < 0xc0)
+ {
+ pc--; // adjust fetch pointer, so modrm byte read again
+ opcode_ptr--;
+ handle_modrm( modrm_string );
+ switch ((op2 >> 3) & 0x7)
+ {
+ case 0: sprintf(s, "fild word ptr %s", modrm_string); break;
+ case 1: sprintf(s, "??? (FPU)"); break;
+ case 2: sprintf(s, "fist word ptr %s", modrm_string); break;
+ case 3: sprintf(s, "fistp word ptr %s", modrm_string); break;
+ case 4: sprintf(s, "fbld %s", modrm_string); break;
+ case 5: sprintf(s, "fild qword ptr %s", modrm_string); break;
+ case 6: sprintf(s, "fbstp %s", modrm_string); break;
+ case 7: sprintf(s, "fistp qword ptr %s", modrm_string); break;
+ }
+ }
+ else
+ {
+ switch (op2 & 0x3f)
+ {
+ case 0x20: sprintf(s, "fstsw aw"); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ sprintf(s, "fucomip st(%d)", op2 & 0x7); break;
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ sprintf(s, "fcomip st(%d),st(0)", op2 & 0x7); break;
+
+ default: sprintf(s, "??? (FPU)"); break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void decode_opcode(char *s, const I386_OPCODE *op, UINT8 op1)
+{
+ int i;
+ UINT8 op2;
+
+ switch( op->flags )
+ {
+ case TWO_BYTE:
+ op2 = FETCHD();
+ decode_opcode( s, &necv_opcode_table2[op2], op1 );
+ return;
+
+ case SEG_PS:
+ case SEG_DS0:
+ case SEG_DS1:
+ case SEG_SS:
+ segment = op->flags;
+ op2 = FETCH();
+ decode_opcode( s, &necv_opcode_table1[op2], op1 );
+ return;
+
+ case PREFIX:
+ s += sprintf( s, "%-8s", op->mnemonic );
+ op2 = FETCH();
+ decode_opcode( s, &necv_opcode_table1[op2], op1 );
+ return;
+
+ case GROUP:
+ handle_modrm( modrm_string );
+ for( i=0; i < ARRAY_LENGTH(group_op_table); i++ ) {
+ if( mame_stricmp(op->mnemonic, group_op_table[i].mnemonic) == 0 ) {
+ decode_opcode( s, &group_op_table[i].opcode[MODRM_REG1], op1 );
+ return;
+ }
+ }
+ goto handle_unknown;
+
+ case FPU:
+ op2 = FETCHD();
+ handle_fpu( s, op1, op2);
+ return;
+
+ case MODRM:
+ handle_modrm( modrm_string );
+ break;
+ }
+
+ s += sprintf( s, "%-8s", op->mnemonic );
+ dasm_flags = op->dasm_flags;
+
+ if( op->param1 != 0 ) {
+ s = handle_param( s, op->param1 );
+ }
+
+ if( op->param2 != 0 ) {
+ s += sprintf( s, "," );
+ s = handle_param( s, op->param2 );
+ }
+
+ if( op->param3 != 0 ) {
+ s += sprintf( s, "," );
+ s = handle_param( s, op->param3 );
+ }
+ return;
+
+handle_unknown:
+ sprintf(s, "???");
+}
+
+int necv_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom)
+{
+ UINT8 op;
+
+ opcode_ptr = opcode_ptr_base = oprom;
+ pc = eip;
+ dasm_flags = 0;
+ segment = 0;
+
+ op = FETCH();
+
+ decode_opcode( buffer, &necv_opcode_table1[op], op );
+ return (pc-eip) | dasm_flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/nec/necea.h b/src/emu/cpu/nec/necea.h
new file mode 100644
index 00000000000..f754523805e
--- /dev/null
+++ b/src/emu/cpu/nec/necea.h
@@ -0,0 +1,60 @@
+
+static UINT32 EA;
+static UINT16 EO;
+static UINT16 E16;
+
+static unsigned EA_000(void) { EO=I.regs.w[BW]+I.regs.w[IX]; EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_001(void) { EO=I.regs.w[BW]+I.regs.w[IY]; EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_002(void) { EO=I.regs.w[BP]+I.regs.w[IX]; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_003(void) { EO=I.regs.w[BP]+I.regs.w[IY]; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_004(void) { EO=I.regs.w[IX]; EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_005(void) { EO=I.regs.w[IY]; EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_006(void) { EO=FETCH; EO+=FETCH<<8; EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_007(void) { EO=I.regs.w[BW]; EA=DefaultBase(DS0)+EO; return EA; }
+
+static unsigned EA_100(void) { EO=(I.regs.w[BW]+I.regs.w[IX]+(INT8)FETCH); EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_101(void) { EO=(I.regs.w[BW]+I.regs.w[IY]+(INT8)FETCH); EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_102(void) { EO=(I.regs.w[BP]+I.regs.w[IX]+(INT8)FETCH); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_103(void) { EO=(I.regs.w[BP]+I.regs.w[IY]+(INT8)FETCH); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_104(void) { EO=(I.regs.w[IX]+(INT8)FETCH); EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_105(void) { EO=(I.regs.w[IY]+(INT8)FETCH); EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_106(void) { EO=(I.regs.w[BP]+(INT8)FETCH); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_107(void) { EO=(I.regs.w[BW]+(INT8)FETCH); EA=DefaultBase(DS0)+EO; return EA; }
+
+static unsigned EA_200(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+I.regs.w[IX]+(INT16)E16; EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_201(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+I.regs.w[IY]+(INT16)E16; EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_202(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+I.regs.w[IX]+(INT16)E16; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_203(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+I.regs.w[IY]+(INT16)E16; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_204(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[IX]+(INT16)E16; EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_205(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[IY]+(INT16)E16; EA=DefaultBase(DS0)+EO; return EA; }
+static unsigned EA_206(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+(INT16)E16; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_207(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+(INT16)E16; EA=DefaultBase(DS0)+EO; return EA; }
+
+static unsigned (*GetEA[192])(void)={
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207
+};
diff --git a/src/emu/cpu/nec/nechost.h b/src/emu/cpu/nec/nechost.h
new file mode 100644
index 00000000000..5752551f948
--- /dev/null
+++ b/src/emu/cpu/nec/nechost.h
@@ -0,0 +1,12 @@
+/*****************************************************************************/
+/* host dependent types */
+
+#define BIGCASE
+
+#include "cpuintrf.h"
+
+typedef char BOOLEAN;
+
+typedef UINT8 BYTE;
+typedef UINT16 WORD;
+typedef UINT32 DWORD;
diff --git a/src/emu/cpu/nec/necinstr.h b/src/emu/cpu/nec/necinstr.h
new file mode 100644
index 00000000000..f07fe442c0c
--- /dev/null
+++ b/src/emu/cpu/nec/necinstr.h
@@ -0,0 +1,507 @@
+static void i_add_br8(void);
+static void i_add_wr16(void);
+static void i_add_r8b(void);
+static void i_add_r16w(void);
+static void i_add_ald8(void);
+static void i_add_axd16(void);
+static void i_push_es(void);
+static void i_pop_es(void);
+static void i_or_br8(void);
+static void i_or_r8b(void);
+static void i_or_wr16(void);
+static void i_or_r16w(void);
+static void i_or_ald8(void);
+static void i_or_axd16(void);
+static void i_push_cs(void);
+static void i_pre_nec(void);
+static void i_adc_br8(void);
+static void i_adc_wr16(void);
+static void i_adc_r8b(void);
+static void i_adc_r16w(void);
+static void i_adc_ald8(void);
+static void i_adc_axd16(void);
+static void i_push_ss(void);
+static void i_pop_ss(void);
+static void i_sbb_br8(void);
+static void i_sbb_wr16(void);
+static void i_sbb_r8b(void);
+static void i_sbb_r16w(void);
+static void i_sbb_ald8(void);
+static void i_sbb_axd16(void);
+static void i_push_ds(void);
+static void i_pop_ds(void);
+static void i_and_br8(void);
+static void i_and_r8b(void);
+static void i_and_wr16(void);
+static void i_and_r16w(void);
+static void i_and_ald8(void);
+static void i_and_axd16(void);
+static void i_es(void);
+static void i_daa(void);
+static void i_sub_br8(void);
+static void i_sub_wr16(void);
+static void i_sub_r8b(void);
+static void i_sub_r16w(void);
+static void i_sub_ald8(void);
+static void i_sub_axd16(void);
+static void i_cs(void);
+static void i_das(void);
+static void i_xor_br8(void);
+static void i_xor_r8b(void);
+static void i_xor_wr16(void);
+static void i_xor_r16w(void);
+static void i_xor_ald8(void);
+static void i_xor_axd16(void);
+static void i_ss(void);
+static void i_aaa(void);
+static void i_cmp_br8(void);
+static void i_cmp_wr16(void);
+static void i_cmp_r8b(void);
+static void i_cmp_r16w(void);
+static void i_cmp_ald8(void);
+static void i_cmp_axd16(void);
+static void i_ds(void);
+static void i_aas(void);
+static void i_inc_ax(void);
+static void i_inc_cx(void);
+static void i_inc_dx(void);
+static void i_inc_bx(void);
+static void i_inc_sp(void);
+static void i_inc_bp(void);
+static void i_inc_si(void);
+static void i_inc_di(void);
+static void i_dec_ax(void);
+static void i_dec_cx(void);
+static void i_dec_dx(void);
+static void i_dec_bx(void);
+static void i_dec_sp(void);
+static void i_dec_bp(void);
+static void i_dec_si(void);
+static void i_dec_di(void);
+static void i_push_ax(void);
+static void i_push_cx(void);
+static void i_push_dx(void);
+static void i_push_bx(void);
+static void i_push_sp(void);
+static void i_push_bp(void);
+static void i_push_si(void);
+static void i_push_di(void);
+static void i_pop_ax(void);
+static void i_pop_cx(void);
+static void i_pop_dx(void);
+static void i_pop_bx(void);
+static void i_pop_sp(void);
+static void i_pop_bp(void);
+static void i_pop_si(void);
+static void i_pop_di(void);
+static void i_pusha(void);
+static void i_popa(void);
+static void i_chkind(void);
+static void i_repnc(void);
+static void i_repc(void);
+static void i_push_d16(void);
+static void i_imul_d16(void);
+static void i_push_d8(void);
+static void i_imul_d8(void);
+static void i_insb(void);
+static void i_insw(void);
+static void i_outsb(void);
+static void i_outsw(void);
+static void i_jo(void);
+static void i_jno(void);
+static void i_jc(void);
+static void i_jnc(void);
+static void i_jz(void);
+static void i_jnz(void);
+static void i_jce(void);
+static void i_jnce(void);
+static void i_js(void);
+static void i_jns(void);
+static void i_jp(void);
+static void i_jnp(void);
+static void i_jl(void);
+static void i_jnl(void);
+static void i_jle(void);
+static void i_jnle(void);
+static void i_80pre(void);
+static void i_82pre(void);
+static void i_81pre(void);
+static void i_83pre(void);
+static void i_test_br8(void);
+static void i_test_wr16(void);
+static void i_xchg_br8(void);
+static void i_xchg_wr16(void);
+static void i_mov_br8(void);
+static void i_mov_r8b(void);
+static void i_mov_wr16(void);
+static void i_mov_r16w(void);
+static void i_mov_wsreg(void);
+static void i_lea(void);
+static void i_mov_sregw(void);
+static void i_invalid(void);
+static void i_popw(void);
+static void i_nop(void);
+static void i_xchg_axcx(void);
+static void i_xchg_axdx(void);
+static void i_xchg_axbx(void);
+static void i_xchg_axsp(void);
+static void i_xchg_axbp(void);
+static void i_xchg_axsi(void);
+static void i_xchg_axdi(void);
+static void i_cbw(void);
+static void i_cwd(void);
+static void i_call_far(void);
+static void i_pushf(void);
+static void i_popf(void);
+static void i_sahf(void);
+static void i_lahf(void);
+static void i_mov_aldisp(void);
+static void i_mov_axdisp(void);
+static void i_mov_dispal(void);
+static void i_mov_dispax(void);
+static void i_movsb(void);
+static void i_movsw(void);
+static void i_cmpsb(void);
+static void i_cmpsw(void);
+static void i_test_ald8(void);
+static void i_test_axd16(void);
+static void i_stosb(void);
+static void i_stosw(void);
+static void i_lodsb(void);
+static void i_lodsw(void);
+static void i_scasb(void);
+static void i_scasw(void);
+static void i_mov_ald8(void);
+static void i_mov_cld8(void);
+static void i_mov_dld8(void);
+static void i_mov_bld8(void);
+static void i_mov_ahd8(void);
+static void i_mov_chd8(void);
+static void i_mov_dhd8(void);
+static void i_mov_bhd8(void);
+static void i_mov_axd16(void);
+static void i_mov_cxd16(void);
+static void i_mov_dxd16(void);
+static void i_mov_bxd16(void);
+static void i_mov_spd16(void);
+static void i_mov_bpd16(void);
+static void i_mov_sid16(void);
+static void i_mov_did16(void);
+static void i_rotshft_bd8(void);
+static void i_rotshft_wd8(void);
+static void i_ret_d16(void);
+static void i_ret(void);
+static void i_les_dw(void);
+static void i_lds_dw(void);
+static void i_mov_bd8(void);
+static void i_mov_wd16(void);
+static void i_enter(void);
+static void i_leave(void);
+static void i_retf_d16(void);
+static void i_retf(void);
+static void i_int3(void);
+static void i_int(void);
+static void i_into(void);
+static void i_iret(void);
+static void i_rotshft_b(void);
+static void i_rotshft_w(void);
+static void i_rotshft_bcl(void);
+static void i_rotshft_wcl(void);
+static void i_aam(void);
+static void i_aad(void);
+static void i_setalc(void);
+static void i_trans(void);
+static void i_fpo(void);
+static void i_loopne(void);
+static void i_loope(void);
+static void i_loop(void);
+static void i_jcxz(void);
+static void i_inal(void);
+static void i_inax(void);
+static void i_outal(void);
+static void i_outax(void);
+static void i_call_d16(void);
+static void i_jmp_d16(void);
+static void i_jmp_far(void);
+static void i_jmp_d8(void);
+static void i_inaldx(void);
+static void i_inaxdx(void);
+static void i_outdxal(void);
+static void i_outdxax(void);
+static void i_lock(void);
+static void i_repne(void);
+static void i_repe(void);
+static void i_hlt(void);
+static void i_cmc(void);
+static void i_f6pre(void);
+static void i_f7pre(void);
+static void i_clc(void);
+static void i_stc(void);
+static void i_di(void);
+static void i_ei(void);
+static void i_cld(void);
+static void i_std(void);
+static void i_fepre(void);
+static void i_ffpre(void);
+
+static void i_wait(void);
+
+static void (*nec_instruction[256])(void) =
+{
+ i_add_br8, /* 0x00 */
+ i_add_wr16, /* 0x01 */
+ i_add_r8b, /* 0x02 */
+ i_add_r16w, /* 0x03 */
+ i_add_ald8, /* 0x04 */
+ i_add_axd16, /* 0x05 */
+ i_push_es, /* 0x06 */
+ i_pop_es, /* 0x07 */
+ i_or_br8, /* 0x08 */
+ i_or_wr16, /* 0x09 */
+ i_or_r8b, /* 0x0a */
+ i_or_r16w, /* 0x0b */
+ i_or_ald8, /* 0x0c */
+ i_or_axd16, /* 0x0d */
+ i_push_cs, /* 0x0e */
+ i_pre_nec /* 0x0f */,
+ i_adc_br8, /* 0x10 */
+ i_adc_wr16, /* 0x11 */
+ i_adc_r8b, /* 0x12 */
+ i_adc_r16w, /* 0x13 */
+ i_adc_ald8, /* 0x14 */
+ i_adc_axd16, /* 0x15 */
+ i_push_ss, /* 0x16 */
+ i_pop_ss, /* 0x17 */
+ i_sbb_br8, /* 0x18 */
+ i_sbb_wr16, /* 0x19 */
+ i_sbb_r8b, /* 0x1a */
+ i_sbb_r16w, /* 0x1b */
+ i_sbb_ald8, /* 0x1c */
+ i_sbb_axd16, /* 0x1d */
+ i_push_ds, /* 0x1e */
+ i_pop_ds, /* 0x1f */
+ i_and_br8, /* 0x20 */
+ i_and_wr16, /* 0x21 */
+ i_and_r8b, /* 0x22 */
+ i_and_r16w, /* 0x23 */
+ i_and_ald8, /* 0x24 */
+ i_and_axd16, /* 0x25 */
+ i_es, /* 0x26 */
+ i_daa, /* 0x27 */
+ i_sub_br8, /* 0x28 */
+ i_sub_wr16, /* 0x29 */
+ i_sub_r8b, /* 0x2a */
+ i_sub_r16w, /* 0x2b */
+ i_sub_ald8, /* 0x2c */
+ i_sub_axd16, /* 0x2d */
+ i_cs, /* 0x2e */
+ i_das, /* 0x2f */
+ i_xor_br8, /* 0x30 */
+ i_xor_wr16, /* 0x31 */
+ i_xor_r8b, /* 0x32 */
+ i_xor_r16w, /* 0x33 */
+ i_xor_ald8, /* 0x34 */
+ i_xor_axd16, /* 0x35 */
+ i_ss, /* 0x36 */
+ i_aaa, /* 0x37 */
+ i_cmp_br8, /* 0x38 */
+ i_cmp_wr16, /* 0x39 */
+ i_cmp_r8b, /* 0x3a */
+ i_cmp_r16w, /* 0x3b */
+ i_cmp_ald8, /* 0x3c */
+ i_cmp_axd16, /* 0x3d */
+ i_ds, /* 0x3e */
+ i_aas, /* 0x3f */
+ i_inc_ax, /* 0x40 */
+ i_inc_cx, /* 0x41 */
+ i_inc_dx, /* 0x42 */
+ i_inc_bx, /* 0x43 */
+ i_inc_sp, /* 0x44 */
+ i_inc_bp, /* 0x45 */
+ i_inc_si, /* 0x46 */
+ i_inc_di, /* 0x47 */
+ i_dec_ax, /* 0x48 */
+ i_dec_cx, /* 0x49 */
+ i_dec_dx, /* 0x4a */
+ i_dec_bx, /* 0x4b */
+ i_dec_sp, /* 0x4c */
+ i_dec_bp, /* 0x4d */
+ i_dec_si, /* 0x4e */
+ i_dec_di, /* 0x4f */
+ i_push_ax, /* 0x50 */
+ i_push_cx, /* 0x51 */
+ i_push_dx, /* 0x52 */
+ i_push_bx, /* 0x53 */
+ i_push_sp, /* 0x54 */
+ i_push_bp, /* 0x55 */
+ i_push_si, /* 0x56 */
+ i_push_di, /* 0x57 */
+ i_pop_ax, /* 0x58 */
+ i_pop_cx, /* 0x59 */
+ i_pop_dx, /* 0x5a */
+ i_pop_bx, /* 0x5b */
+ i_pop_sp, /* 0x5c */
+ i_pop_bp, /* 0x5d */
+ i_pop_si, /* 0x5e */
+ i_pop_di, /* 0x5f */
+ i_pusha, /* 0x60 */
+ i_popa, /* 0x61 */
+ i_chkind, /* 0x62 */
+ i_invalid, /* 0x63 */
+ i_repnc, /* 0x64 */
+ i_repc, /* 0x65 */
+ i_invalid, /* 0x66 */
+ i_invalid, /* 0x67 */
+ i_push_d16, /* 0x68 */
+ i_imul_d16, /* 0x69 */
+ i_push_d8, /* 0x6a */
+ i_imul_d8, /* 0x6b */
+ i_insb, /* 0x6c */
+ i_insw, /* 0x6d */
+ i_outsb, /* 0x6e */
+ i_outsw, /* 0x6f */
+ i_jo, /* 0x70 */
+ i_jno, /* 0x71 */
+ i_jc, /* 0x72 */
+ i_jnc, /* 0x73 */
+ i_jz, /* 0x74 */
+ i_jnz, /* 0x75 */
+ i_jce, /* 0x76 */
+ i_jnce, /* 0x77 */
+ i_js, /* 0x78 */
+ i_jns, /* 0x79 */
+ i_jp, /* 0x7a */
+ i_jnp, /* 0x7b */
+ i_jl, /* 0x7c */
+ i_jnl, /* 0x7d */
+ i_jle, /* 0x7e */
+ i_jnle, /* 0x7f */
+ i_80pre, /* 0x80 */
+ i_81pre, /* 0x81 */
+ i_82pre, /* 0x82 */
+ i_83pre, /* 0x83 */
+ i_test_br8, /* 0x84 */
+ i_test_wr16, /* 0x85 */
+ i_xchg_br8, /* 0x86 */
+ i_xchg_wr16, /* 0x87 */
+ i_mov_br8, /* 0x88 */
+ i_mov_wr16, /* 0x89 */
+ i_mov_r8b, /* 0x8a */
+ i_mov_r16w, /* 0x8b */
+ i_mov_wsreg, /* 0x8c */
+ i_lea, /* 0x8d */
+ i_mov_sregw, /* 0x8e */
+ i_popw, /* 0x8f */
+ i_nop, /* 0x90 */
+ i_xchg_axcx, /* 0x91 */
+ i_xchg_axdx, /* 0x92 */
+ i_xchg_axbx, /* 0x93 */
+ i_xchg_axsp, /* 0x94 */
+ i_xchg_axbp, /* 0x95 */
+ i_xchg_axsi, /* 0x97 */
+ i_xchg_axdi, /* 0x97 */
+ i_cbw, /* 0x98 */
+ i_cwd, /* 0x99 */
+ i_call_far, /* 0x9a */
+ i_wait, /* 0x9b */
+ i_pushf, /* 0x9c */
+ i_popf, /* 0x9d */
+ i_sahf, /* 0x9e */
+ i_lahf, /* 0x9f */
+ i_mov_aldisp, /* 0xa0 */
+ i_mov_axdisp, /* 0xa1 */
+ i_mov_dispal, /* 0xa2 */
+ i_mov_dispax, /* 0xa3 */
+ i_movsb, /* 0xa4 */
+ i_movsw, /* 0xa5 */
+ i_cmpsb, /* 0xa6 */
+ i_cmpsw, /* 0xa7 */
+ i_test_ald8, /* 0xa8 */
+ i_test_axd16, /* 0xa9 */
+ i_stosb, /* 0xaa */
+ i_stosw, /* 0xab */
+ i_lodsb, /* 0xac */
+ i_lodsw, /* 0xad */
+ i_scasb, /* 0xae */
+ i_scasw, /* 0xaf */
+ i_mov_ald8, /* 0xb0 */
+ i_mov_cld8, /* 0xb1 */
+ i_mov_dld8, /* 0xb2 */
+ i_mov_bld8, /* 0xb3 */
+ i_mov_ahd8, /* 0xb4 */
+ i_mov_chd8, /* 0xb5 */
+ i_mov_dhd8, /* 0xb6 */
+ i_mov_bhd8, /* 0xb7 */
+ i_mov_axd16, /* 0xb8 */
+ i_mov_cxd16, /* 0xb9 */
+ i_mov_dxd16, /* 0xba */
+ i_mov_bxd16, /* 0xbb */
+ i_mov_spd16, /* 0xbc */
+ i_mov_bpd16, /* 0xbd */
+ i_mov_sid16, /* 0xbe */
+ i_mov_did16, /* 0xbf */
+ i_rotshft_bd8, /* 0xc0 */
+ i_rotshft_wd8, /* 0xc1 */
+ i_ret_d16, /* 0xc2 */
+ i_ret, /* 0xc3 */
+ i_les_dw, /* 0xc4 */
+ i_lds_dw, /* 0xc5 */
+ i_mov_bd8, /* 0xc6 */
+ i_mov_wd16, /* 0xc7 */
+ i_enter, /* 0xc8 */
+ i_leave, /* 0xc9 */
+ i_retf_d16, /* 0xca */
+ i_retf, /* 0xcb */
+ i_int3, /* 0xcc */
+ i_int, /* 0xcd */
+ i_into, /* 0xce */
+ i_iret, /* 0xcf */
+ i_rotshft_b, /* 0xd0 */
+ i_rotshft_w, /* 0xd1 */
+ i_rotshft_bcl, /* 0xd2 */
+ i_rotshft_wcl, /* 0xd3 */
+ i_aam, /* 0xd4 */
+ i_aad, /* 0xd5 */
+ i_setalc,
+ i_trans, /* 0xd7 */
+ i_fpo, /* 0xd8 */
+ i_fpo, /* 0xd9 */
+ i_fpo, /* 0xda */
+ i_fpo, /* 0xdb */
+ i_fpo, /* 0xdc */
+ i_fpo, /* 0xdd */
+ i_fpo, /* 0xde */
+ i_fpo, /* 0xdf */
+ i_loopne, /* 0xe0 */
+ i_loope, /* 0xe1 */
+ i_loop, /* 0xe2 */
+ i_jcxz, /* 0xe3 */
+ i_inal, /* 0xe4 */
+ i_inax, /* 0xe5 */
+ i_outal, /* 0xe6 */
+ i_outax, /* 0xe7 */
+ i_call_d16, /* 0xe8 */
+ i_jmp_d16, /* 0xe9 */
+ i_jmp_far, /* 0xea */
+ i_jmp_d8, /* 0xeb */
+ i_inaldx, /* 0xec */
+ i_inaxdx, /* 0xed */
+ i_outdxal, /* 0xee */
+ i_outdxax, /* 0xef */
+ i_lock, /* 0xf0 */
+ i_invalid, /* 0xf1 */
+ i_repne, /* 0xf2 */
+ i_repe, /* 0xf3 */
+ i_hlt, /* 0xf4 */
+ i_cmc, /* 0xf5 */
+ i_f6pre, /* 0xf6 */
+ i_f7pre, /* 0xf7 */
+ i_clc, /* 0xf8 */
+ i_stc, /* 0xf9 */
+ i_di, /* 0xfa */
+ i_ei, /* 0xfb */
+ i_cld, /* 0xfc */
+ i_std, /* 0xfd */
+ i_fepre, /* 0xfe */
+ i_ffpre /* 0xff */
+};
diff --git a/src/emu/cpu/nec/necintrf.h b/src/emu/cpu/nec/necintrf.h
new file mode 100644
index 00000000000..d9978755f24
--- /dev/null
+++ b/src/emu/cpu/nec/necintrf.h
@@ -0,0 +1,18 @@
+/* ASG 971222 -- rewrote this interface */
+#ifndef __NEC_H_
+#define __NEC_H_
+
+#include "cpuintrf.h"
+
+enum {
+ NEC_PC=0,
+ NEC_IP, NEC_AW, NEC_CW, NEC_DW, NEC_BW, NEC_SP, NEC_BP, NEC_IX, NEC_IY,
+ NEC_FLAGS, NEC_ES, NEC_CS, NEC_SS, NEC_DS,
+ NEC_VECTOR, NEC_PENDING };
+
+/* Public functions */
+extern void v20_get_info(UINT32 state, cpuinfo *info);
+extern void v30_get_info(UINT32 state, cpuinfo *info);
+extern void v33_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/nec/necmodrm.h b/src/emu/cpu/nec/necmodrm.h
new file mode 100644
index 00000000000..b48556d6f74
--- /dev/null
+++ b/src/emu/cpu/nec/necmodrm.h
@@ -0,0 +1,104 @@
+static struct {
+ struct {
+ WREGS w[256];
+ BREGS b[256];
+ } reg;
+ struct {
+ WREGS w[256];
+ BREGS b[256];
+ } RM;
+} Mod_RM;
+
+#define RegWord(ModRM) I.regs.w[Mod_RM.reg.w[ModRM]]
+#define RegByte(ModRM) I.regs.b[Mod_RM.reg.b[ModRM]]
+
+#define GetRMWord(ModRM) \
+ ((ModRM) >= 0xc0 ? I.regs.w[Mod_RM.RM.w[ModRM]] : ( (*GetEA[ModRM])(), read_word( EA ) ))
+
+#define PutbackRMWord(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) I.regs.w[Mod_RM.RM.w[ModRM]]=val; \
+ else write_word(EA,val); \
+}
+
+#define GetnextRMWord read_word((EA&0xf0000)|((EA+2)&0xffff))
+
+#define PutRMWord(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.w[Mod_RM.RM.w[ModRM]]=val; \
+ else { \
+ (*GetEA[ModRM])(); \
+ write_word( EA ,val); \
+ } \
+}
+
+#define PutImmRMWord(ModRM) \
+{ \
+ WORD val; \
+ if (ModRM >= 0xc0) \
+ FETCHWORD(I.regs.w[Mod_RM.RM.w[ModRM]]) \
+ else { \
+ (*GetEA[ModRM])(); \
+ FETCHWORD(val) \
+ write_word( EA , val); \
+ } \
+}
+
+#define GetRMByte(ModRM) \
+ ((ModRM) >= 0xc0 ? I.regs.b[Mod_RM.RM.b[ModRM]] : read_byte( (*GetEA[ModRM])() ))
+
+#define PutRMByte(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.b[Mod_RM.RM.b[ModRM]]=val; \
+ else \
+ write_byte( (*GetEA[ModRM])() ,val); \
+}
+
+#define PutImmRMByte(ModRM) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.b[Mod_RM.RM.b[ModRM]]=FETCH; \
+ else { \
+ (*GetEA[ModRM])(); \
+ write_byte( EA , FETCH ); \
+ } \
+}
+
+#define PutbackRMByte(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.b[Mod_RM.RM.b[ModRM]]=val; \
+ else \
+ write_byte(EA,val); \
+}
+
+#define DEF_br8 \
+ UINT32 ModRM = FETCH,src,dst; \
+ src = RegByte(ModRM); \
+ dst = GetRMByte(ModRM)
+
+#define DEF_wr16 \
+ UINT32 ModRM = FETCH,src,dst; \
+ src = RegWord(ModRM); \
+ dst = GetRMWord(ModRM)
+
+#define DEF_r8b \
+ UINT32 ModRM = FETCH,src,dst; \
+ dst = RegByte(ModRM); \
+ src = GetRMByte(ModRM)
+
+#define DEF_r16w \
+ UINT32 ModRM = FETCH,src,dst; \
+ dst = RegWord(ModRM); \
+ src = GetRMWord(ModRM)
+
+#define DEF_ald8 \
+ UINT32 src = FETCH; \
+ UINT32 dst = I.regs.b[AL]
+
+#define DEF_axd16 \
+ UINT32 src = FETCH; \
+ UINT32 dst = I.regs.w[AW]; \
+ src += (FETCH << 8)
diff --git a/src/emu/cpu/pdp1/pdp1.c b/src/emu/cpu/pdp1/pdp1.c
new file mode 100644
index 00000000000..fbe0d9bfe43
--- /dev/null
+++ b/src/emu/cpu/pdp1/pdp1.c
@@ -0,0 +1,1893 @@
+/*
+ * Note: Original Java source written by:
+ *
+ * Barry Silverman mailto:barry@disus.com or mailto:bss@media.mit.edu
+ * Vadim Gerasimov mailto:vadim@media.mit.edu
+ *
+ * Basically, it has been rewritten entirely in order to perform cycle-level simulation
+ * (with only a few flip-flops being set one cycle too early or too late). I don't know if
+ * it is a good thing or a bad thing (it makes emulation more accurate, but slower, and
+ * code is more complex and less readable), but it appears to be the only way we could emulate
+ * mid-instruction sequence break. And it enables us to emulate the control panel fairly
+ * accurately.
+ *
+ * Additionnally, IOT functions have been modified to be external: IOT callback pointers are set
+ * at emulation initiation, and most IOT callback functions are part of the machine emulation.
+ *
+ *
+ * for the runnable java applet, with applet and Spacewar! source, go to:
+ * http://lcs.www.media.mit.edu/groups/el/projects/spacewar/
+ *
+ * for a complete html version of the pdp1 handbook go to:
+ * http://www.dbit.com/~greeng3/pdp1/index.html
+ *
+ * there is another java simulator (by the same people) which runs the
+ * original pdp1 LISP interpreter, go to:
+ * http://lcs.www.media.mit.edu/groups/el/projects/pdp1
+ *
+ * Another PDP1 emulator (or simulator) is at:
+ * ftp://minnie.cs.adfa.oz.au/pub/PDP-11/Sims/Supnik_2.3
+ * It seems to emulate pdp1 I/O more accurately than we do.
+ * However, there is no CRT emulation.
+ *
+ * and finally, there is a nice article about SPACEWAR!, go to:
+ * http://ars-www.uchicago.edu/~eric/lore/spacewar/spacewar.html
+ *
+ * some extra documentation is available on spies:
+ * http://www.spies.com/~aek/pdf/dec/pdp1/
+ * The file "F17_PDP1Maint.pdf" explains operation procedures and much of the internals of pdp-1.
+ * It was the main reference for this emulator.
+ * The file "F25_PDP1_IO.pdf" has interesting information on the I/O system, too.
+ *
+ * Following is an extract from the handbook:
+ *
+ * INTRODUCTION
+ *
+ * The Programmed Data Processor (PDP-1) is a high speed, solid state digital computer designed to
+ * operate with many types of input-output devices with no internal machine changes. It is a single
+ * address, single instruction, stored program computer with powerful program features. Five-megacycle
+ * circuits, a magnetic core memory and fully parallel processing make possible a computation rate of
+ * 100,000 additions per second. The PDP-1 is unusually versatile. It is easy to install, operate and
+ * maintain. Conventional 110-volt power is used, neither air conditioning nor floor reinforcement is
+ * necessary, and preventive maintenance is provided for by built-in marginal checking circuits.
+ *
+ * PDP-1 circuits are based on the designs of DEC's highly successful and reliable System Modules.
+ * Flip-flops and most switches use saturating transistors. Primary active elements are
+ * Micro-Alloy-Diffused transistors.
+ *
+ * The entire computer occupies only 17 square feet of floor space. It consists of four equipment frames,
+ * one of which is used as the operating station.
+ *
+ * CENTRAL PROCESSOR
+ *
+ * The Central Processor contains the control, arithmetic and memory addressing elements, and the memory
+ * buffer register. The word length is 18 binary digits. Instructions are performed in multiples of the
+ * memory cycle time of five microseconds. Add, subtract, deposit, and load, for example, are two-cycle
+ * instructions requiring 10 microseconds. Multiplication requires and average of 20 microseconds.
+ * Program features include: single address instructions, multiple step indirect addressing and logical
+ * arithmetic commands. Console features include: flip-flop indicators grouped for convenient octal
+ * reading, six program flags for automatic setting and computer sensing, and six sense switches for
+ * manual setting and computer sensing.
+ *
+ * MEMORY SYSTEM
+ *
+ * The coincident-current, magnetic core memory of a standard PDP-1 holds 4096 words of 18 bits each.
+ * Memory capacity may be readily expanded, in increments of 4096 words, to a maximum of 65,536 words.
+ * The read-rewrite time of the memory is five microseconds, the basic computer rate. Driving currents
+ * are automatically adjusted to compensate for temperature variations between 50 and 110 degrees
+ * Fahrenheit. The core memory storage may be supplemented by up to 24 magnetic tape transports.
+ *
+ * INPUT-OUTPUT
+ *
+ * PDP-1 is designed to operate a variety of buffered input-output devices. Standard equipment consistes
+ * of a perforated tape reader with a read speed of 400 lines per second, and alphanuermic typewriter for
+ * on-line operation in both input and output, and a perforated tape punch (alphanumeric or binary) with
+ * a speed of 63 lines per second. A variety of optional equipment is available, including the following:
+ *
+ * Precision CRT Display Type 30
+ * Ultra-Precision CRT Display Type 31
+ * Symbol Generator Type 33
+ * Light Pen Type 32
+ * Oscilloscope Display Type 34
+ * Card Punch Control Type 40-1
+ * Card Reader and Control Type 421
+ * Magnetic Tape Transport Type 50
+ * Programmed Magnetic Tape Control Type 51
+ * Automatic Magnetic Tape Control Type 52
+ * Automatic Magnetic Tape Control Type 510
+ * Parallel Drum Type 23
+ * Automatic Line Printer and Control Type 64
+ * 18-bit Real Time Clock
+ * 18-bit Output Relay Buffer Type 140
+ * Multiplexed A-D Converter Type 138/139
+ *
+ * All in-out operations are performed through the In-Out Register or through the high speed input-output
+ * channels.
+ *
+ * The PDP-1 is also available with the optional Sequence Break System. This is a multi-channel priority
+ * interrupt feature which permits concurrent operation of several in-out devices. A one-channel Sequence
+ * Break System is included in the standard PDP-1. Optional Sequence Break Systems consist of 16, 32, 64,
+ * 128, and 256 channels.
+ *
+ * ...
+ *
+ * BASIC INSTRUCTIONS
+ *
+ * OPER. TIME
+ * INSTRUCTION CODE # EXPLANATION (usec)
+ * ------------------------------------------------------------------------------
+ * add Y 40 Add C(Y) to C(AC) 10
+ * and Y 02 Logical AND C(Y) with C(AC) 10
+ * cal Y 16 Equals jda 100 10
+ * dac Y 24 Deposit C(AC) in Y 10
+ * dap Y 26 Deposit contents of address part of AC in Y 10
+ * dio Y 32 Deposit C(IO) in Y 10
+ * dip Y 30 Deposit contents of instruction part of AC in Y 10
+ * div Y 56 Divide 40 max
+ * dzm Y 34 Deposit zero in Y 10
+ * idx Y 44 Index (add one) C(Y), leave in Y & AC 10
+ * ior Y 04 Inclusive OR C(Y) with C(AC) 10
+ * iot Y 72 In-out transfer, see below
+ * isp Y 46 Index and skip if result is positive 10
+ * jda Y 17 Equals dac Y and jsp Y+1 10
+ * jmp Y 60 Take next instruction from Y 5
+ * jsp Y 62 Jump to Y and save program counter in AC 5
+ * lac Y 20 Load the AC with C(Y) 10
+ * law N 70 Load the AC with the number N 5
+ * law-N 71 Load the AC with the number -N 5
+ * lio Y 22 Load IO with C(Y) 10
+ * mul Y 54 Multiply 25 max
+ * opr 76 Operate, see below 5
+ * sad Y 50 Skip next instruction if C(AC) <> C(Y) 10
+ * sas Y 52 Skip next instruction if C(AC) = C(Y) 10
+ * sft 66 Shift, see below 5
+ * skp 64 Skip, see below 5
+ * sub Y 42 Subtract C(Y) from C(AC) 10
+ * xct Y 10 Execute instruction in Y 5+
+ * xor Y 06 Exclusive OR C(Y) with C(AC) 10
+ *
+ * OPERATE GROUP
+ *
+ * OPER. TIME
+ * INSTRUCTION CODE # EXPLANATION (usec)
+ * ------------------------------------------------------------------------------
+ * cla 760200 Clear AC 5
+ * clf 76000f Clear selected Program Flag (f = flag #) 5
+ * cli 764000 Clear IO 5
+ * cma 761000 Complement AC 5
+ * hlt 760400 Halt 5
+ * lap 760100 Load AC with Program Counter 5
+ * lat 762200 Load AC from Test Word switches 5
+ * nop 760000 No operation 5
+ * stf 76001f Set selected Program Flag 5
+ *
+ * IN-OUT TRANSFER GROUP
+ *
+ * PERFORATED TAPE READER
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * rpa 720001 Read Perforated Tape Alphanumeric
+ * rpb 720002 Read Perforated Tape Binary
+ * rrb 720030 Read Reader Buffer
+ *
+ * PERFORATED TAPE PUNCH
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * ppa 720005 Punch Perforated Tape Alphanumeric
+ * ppb 720006 Punch Perforated Tape Binary
+ *
+ * ALPHANUMERIC ON-LINE TYPEWRITER
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * tyo 720003 Type Out
+ * tyi 720004 Type In
+ *
+ * SEQUENCE BREAK SYSTEM TYPE 120
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * esm 720055 Enter Sequence Break Mode
+ * lsm 720054 Leave Sequence Break Mode
+ * cbs 720056 Clear Sequence Break System
+ * dsc 72kn50 Deactivate Sequence Break Channel
+ * asc 72kn51 Activate Sequence Break Channel
+ * isb 72kn52 Initiate Sequence Break
+ * cac 720053 Clear All Channels
+ *
+ * HIGH SPEED DATA CONTROL TYPE 131
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * swc 72x046 Set Word Counter
+ * sia 720346 Set Location Counter
+ * sdf 720146 Stop Data Flow
+ * rlc 720366 Read Location Counter
+ * shr 720446 Set High Speed Channel Request
+ *
+ * PRECISION CRT DISPLAY TYPE 30
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * dpy 720007 Display One Point
+ *
+ * SYMBOL GENERATOR TYPE 33
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * gpl 722027 Generator Plot Left
+ * gpr 720027 Generator Plot Right
+ * glf 722026 Load Format
+ * gsp 720026 Space
+ * sdb 722007 Load Buffer, No Intensity
+ *
+ * ULTRA-PRECISION CRT DISPLAY TYPE 31
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * dpp 720407 Display One Point on Ultra Precision CRT
+ *
+ * CARD PUNCH CONTROL TYPE 40-1
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * lag 720044 Load a Group
+ * pac 720043 Punch a Card
+ *
+ * CARD READER TYPE 421
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * rac 720041 Read Card Alpha
+ * rbc 720042 Read Card Binary
+ * rcc 720032 Read Card Column
+ *
+ * PROGRAMMED MAGNETIC TAPE CONTROL TYPE 51
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * msm 720073 Select Mode
+ * mcs 720034 Check Status
+ * mcb 720070 Clear Buffer
+ * mwc 720071 Write a Character
+ * mrc 720072 Read Character
+ *
+ * AUTOMATIC MAGNETIC TAPE CONTROL TYPE 52
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * muf 72ue76 Tape Unit and FinalT
+ * mic 72ue75 Initial and Command
+ * mrf 72u067 Reset Final
+ * mri 72ug66 Reset Initial
+ * mes 72u035 Examine States
+ * mel 72u036 Examine Location
+ * inr 72ur67 Initiate a High Speed Channel Request
+ * ccr 72s067 Clear Command Register
+ *
+ * AUTOMATIC MAGNETIC TAPE CONTROL TYPE 510
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * sfc 720072 Skip if Tape Control Free
+ * rsr 720172 Read State Register
+ * crf 720272 Clear End-of-Record Flip-Flop
+ * cpm 720472 Clear Proceed Mode
+ * dur 72xx70 Load Density, Unit, Rewind
+ * mtf 73xx71 Load Tape Function Register
+ * cgo 720073 Clear Go
+ *
+ * MULTIPLEXED A-D CONVERTER TYPE 138/139
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * rcb 720031 Read Converter Buffer
+ * cad 720040 Convert a Voltage
+ * scv 72mm47 Select Multiplexer (1 of 64 Channels)
+ * icv 720060 Index Multiplexer
+ *
+ * AUTOMATIC LINE PRINTER TYPE 64
+ *
+ * INSTRUCTION CODE # EXPLANATION
+ * ------------------------------------------------------------------------------
+ * clrbuf 722045 Clear Buffer
+ * lpb 720045 Load Printer Buffer
+ * pas 721x45 Print and Space
+ *
+ * SKIP GROUP
+ *
+ * OPER. TIME
+ * INSTRUCTION CODE # EXPLANATION (usec)
+ * ------------------------------------------------------------------------------
+ * sma 640400 Dkip on minus AC 5
+ * spa 640200 Skip on plus AC 5
+ * spi 642000 Skip on plus IO 5
+ * sza 640100 Skip on ZERO (+0) AC 5
+ * szf 6400f Skip on ZERO flag 5
+ * szo 641000 Skip on ZERO overflow (and clear overflow) 5
+ * szs 6400s0 Skip on ZERO sense switch 5
+ *
+ * SHIFT/ROTATE GROUP
+ *
+ * OPER. TIME
+ * INSTRUCTION CODE # EXPLANATION (usec)
+ * ------------------------------------------------------------------------------
+ * ral 661 Rotate AC left 5
+ * rar 671 Rotate AC right 5
+ * rcl 663 Rotate Combined AC & IO left 5
+ * rcr 673 Rotate Combined AC & IO right 5
+ * ril 662 Rotate IO left 5
+ * rir 672 Rotate IO right 5
+ * sal 665 Shift AC left 5
+ * sar 675 Shift AC right 5
+ * scl 667 Shift Combined AC & IO left 5
+ * scr 677 Shift Combined AC & IO right 5
+ * sil 666 Shift IO left 5
+ * sir 676 Shift IO right 5
+ */
+
+
+/*
+ TODO:
+ * support other extensions as time permits
+*/
+
+
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "pdp1.h"
+
+#define LOG 0
+#define LOG_EXTRA 0
+
+#ifndef LOG_IOT_EXTRA
+#define LOG_IOT_EXTRA 0
+#endif
+
+
+static void execute_instruction(void);
+static void null_iot (int op2, int nac, int mb, int *io, int ac);
+static void lem_eem_iot(int op2, int nac, int mb, int *io, int ac);
+static void sbs_iot(int op2, int nac, int mb, int *io, int ac);
+static void type_20_sbs_iot(int op2, int nac, int mb, int *io, int ac);
+static void pulse_start_clear(void);
+
+
+/* PDP1 Registers */
+typedef struct
+{
+ /* processor registers */
+ UINT32 pc; /* program counter (12, 15 or 16 bits) */
+ int ir; /* basic operation code of current instruction (5 bits) */
+ int mb; /* memory buffer (used for holding the current instruction only) (18 bits) */
+ int ma; /* memory address (12, 15 or 16 bits) */
+ int ac; /* accumulator (18 bits) */
+ int io; /* i/o register (18 bits) */
+ int pf; /* program flag register (6 bits) */
+
+ /* operator panel switches */
+ int ta; /* current state of the 12 or 16 address switches */
+ int tw; /* current state of the 18 test word switches */
+ int ss; /* current state of the 6 sense switches on the operator panel (6 bits) */
+ unsigned int sngl_step : 1; /* stop every memory cycle */
+ unsigned int sngl_inst : 1; /* stop every instruction */
+ unsigned int extend_sw : 1; /* extend switch (loaded into the extend flip-flop on start/read-in) */
+
+ /* processor state flip-flops */
+ unsigned int run : 1; /* processor is running */
+ unsigned int cycle : 1; /* processor is in the midst of an instruction */
+ unsigned int defer : 1; /* processor is handling deferred (i.e. indirect) addressing */
+ unsigned int brk_ctr : 2; /* break counter */
+ unsigned int ov; /* overflow flip-flop */
+ unsigned int rim : 1; /* processor is in read-in mode */
+
+ unsigned int sbm : 1; /* processor is in sequence break mode (i.e. interrupts are enabled) */
+
+ unsigned int exd : 1; /* extend mode: processor is in extend mode */
+ unsigned int exc : 1; /* extend-mode cycle: current instruction cycle is done in extend mode */
+ unsigned int ioc : 1; /* i-o commands: seems to be equivalent to (! ioh) */
+ unsigned int ioh : 1; /* i-o halt: processor is executing an Input-Output Transfer wait */
+ unsigned int ios : 1; /* i-o synchronizer: set on i-o operation completion */
+
+ /* sequence break system */
+ unsigned int irq_state : 16; /* mirrors the state of the interrupt pins */
+ unsigned int b1 : 16; /* interrupt enable */
+ unsigned int b2 : 16; /* interrupt pulse request pending - asynchronous with computer operation (set by pulses on irq_state, cleared when interrupt is taken) */
+ /*unsigned int b3 : 16;*/ /* interrupt request pending - synchronous with computer operation (logical or of irq_state and b2???) */
+ unsigned int b4 : 16; /* interrupt in progress */
+
+ /* additional emulator state variables */
+ int rim_step; /* current step in rim execution */
+ int sbs_request; /* interrupt request (i.e. (b3 & (~ b4)) && (! sbm)) */
+ int sbs_level; /* interrupt request level (first bit in (b3 & (~ b4)) */
+ int sbs_restore; /* set when a jump instruction is an interrupt return */
+ int no_sequence_break; /* disable sequence break recognition for one cycle */
+
+ /* callback for the iot instruction */
+ void (*extern_iot[64])(int op2, int nac, int mb, int *io, int ac);
+ /* read a word from the perforated tape reader */
+ void (*read_binary_word)(void);
+ /* called when sc is pulsed: IO devices should reset */
+ void (*io_sc_callback)(void);
+
+ /* 0: no extend support, 1: extend with 15-bit address, 2: extend with 16-bit address */
+ int extend_support;
+
+ int extended_address_mask; /* 07777 with no extend support, 077777 or 0177777 with extend support */
+ int address_extension_mask; /* 00000 with no extend support, 070000 or 0170000 with extend support */
+
+ /* 1 to use hardware multiply/divide (MUL, DIV) instead of MUS, DIS */
+ int hw_mul_div;
+
+ /* 1 for 16-line sequence break system, 0 for default break system */
+ int type_20_sbs;
+}
+pdp1_Regs;
+
+
+static pdp1_Regs pdp1;
+
+#define PC pdp1.pc
+#define IR pdp1.ir
+#define MB pdp1.mb
+#define MA pdp1.ma
+#define AC pdp1.ac
+#define IO pdp1.io
+#define OV pdp1.ov
+#define EXD pdp1.exd
+/* note that we start counting flags/sense switches at 1, therefore n is in [1,6] */
+#define FLAGS pdp1.pf
+#define READFLAG(n) ((pdp1.pf >> (6-(n))) & 1)
+#define WRITEFLAG(n, data) (pdp1.pf = (pdp1.pf & ~(1 << (6-(n)))) | (((data) & 1) << (6-(n))))
+#define SENSE_SW pdp1.ss
+#define READSENSE(n) ((pdp1.ss >> (6-(n))) & 1)
+#define WRITESENSE(n, data) (pdp1.ss = (pdp1.ss & ~(1 << (6-(n)))) | (((data) & 1) << (6-(n))))
+
+#define EXTENDED_ADDRESS_MASK pdp1.extended_address_mask
+#define ADDRESS_EXTENSION_MASK pdp1.address_extension_mask
+#define BASE_ADDRESS_MASK 0007777
+
+#define INCREMENT_PC (PC = (PC & ADDRESS_EXTENSION_MASK) | ((PC+1) & BASE_ADDRESS_MASK))
+#define DECREMENT_PC (PC = (PC & ADDRESS_EXTENSION_MASK) | ((PC-1) & BASE_ADDRESS_MASK))
+#define INCREMENT_MA (MA = (MA & ADDRESS_EXTENSION_MASK) | ((MA+1) & BASE_ADDRESS_MASK))
+#define PREVIOUS_PC ((PC & ADDRESS_EXTENSION_MASK) | ((PC-1) & BASE_ADDRESS_MASK))
+
+/* public globals */
+static signed int pdp1_ICount;
+
+
+
+/*
+ Interrupts are called "sequence break" in pdp1, but the general idea is the same.
+
+ There are several interrupt lines. With the standard sequence break system, all lines
+ are logically or'ed to trigger a single interrupt level. Interrupts can be triggered
+ by either a pulse or a level on the interrupt lines. With the optional type 120 sequence
+ break system, each of 16 lines triggers is wired to a different priority level: additionnally,
+ each interrupt line can be masked out, and interrupt can be triggered through software.
+
+ Also, instructions can be interrupted in the middle of execution. This is done by
+ decrementing the PC register: therefore the instruction is re-executed from start.
+
+ Interrupt routines should not execute most IOT, as the interrupt may interrupt another.
+
+ More details can be found in the handbook and the maintenance manual.
+*/
+/*
+ This function MUST be called every time pdp1.sbm, pdp1.b4, pdp1.irq_state or pdp1.b2 change.
+*/
+static void field_interrupt(void)
+{
+ /* current_irq: 1 bit for each active pending interrupt request
+ Pending interrupts are in b3 (simulated by (pdp1.irq_state & pdp1.b1) | pdp1.b2)), but they
+ are only honored if no higher priority interrupt routine is in execution (one bit set in b4
+ for each routine in execution). The revelant mask is created with (pdp1.b4 | (- pdp1.b4)),
+ as the carry chain (remember that -b4 = (~ b4) + 1) does precisely what we want.
+ b4: 0001001001000
+ -b4: 1110110111000
+ b4|-b4:1111111111000
+ Neat, uh?
+ */
+ int current_irq = ((pdp1.irq_state & pdp1.b1) | pdp1.b2) & ~ (pdp1.b4 | (- pdp1.b4));
+ int i;
+
+ if (pdp1.sbm && current_irq)
+ {
+ pdp1.sbs_request = 1;
+ for (i=0; /*i<16 &&*/ (! ((current_irq >> i) & 1)); i++)
+ ;
+ pdp1.sbs_level = i;
+ }
+ else
+ pdp1.sbs_request = 0;
+}
+
+static void pdp1_set_irq_line (int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ /* no specific NMI line */
+ }
+ else if ((irqline >= 0) && (irqline < (pdp1.type_20_sbs ? 1 : 16)))
+ {
+ unsigned int new_state = state ? 1 : 0;
+
+ if (((pdp1.irq_state >> irqline) & 1) != new_state)
+ {
+ pdp1.irq_state = (pdp1.irq_state & ~ (1 << irqline)) | (new_state << irqline);
+
+ if ((new_state) && ((pdp1.b1 >> irqline) & 1))
+ pdp1.b2 |= (new_state << irqline);
+
+ /*pdp1.b3 = pdp1.irq_state | pdp1.b2;*/
+
+ field_interrupt(); /* interrupt state has changed */
+ }
+ }
+}
+
+
+static void pdp1_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ const pdp1_reset_param_t *param = config;
+ int i;
+
+ /* clean-up */
+ memset (&pdp1, 0, sizeof (pdp1));
+
+ /* set up params and callbacks */
+ for (i=0; i<64; i++)
+ {
+ pdp1.extern_iot[i] = (param && param->extern_iot[i])
+ ? param->extern_iot[i]
+ : null_iot;
+ }
+ pdp1.read_binary_word = (param) ? param->read_binary_word : NULL;
+ pdp1.io_sc_callback = (param) ? param->io_sc_callback : NULL;
+ pdp1.extend_support = (param) ? param->extend_support : 0;
+ pdp1.hw_mul_div = (param) ? param->hw_mul_div : 0;
+ pdp1.type_20_sbs = (param) ? param->type_20_sbs : 0;
+
+ switch (pdp1.extend_support)
+ {
+ default:
+ pdp1.extend_support = 0;
+ case 0: /* no extension */
+ pdp1.extended_address_mask = 07777;
+ pdp1.address_extension_mask = 00000;
+ break;
+ case 1: /* 15-bit extension */
+ pdp1.extended_address_mask = 077777;
+ pdp1.address_extension_mask = 070000;
+ break;
+ case 2: /* 16-bit extension */
+ pdp1.extended_address_mask = 0177777;
+ pdp1.address_extension_mask = 0170000;
+ break;
+ }
+
+ if (pdp1.extend_support)
+ {
+ pdp1.extern_iot[074] = lem_eem_iot;
+ }
+ pdp1.extern_iot[054] = pdp1.extern_iot[055] = pdp1.extern_iot[056] = sbs_iot;
+ if (pdp1.type_20_sbs)
+ {
+ pdp1.extern_iot[050] = pdp1.extern_iot[051] = pdp1.extern_iot[052] = pdp1.extern_iot[053]
+ = type_20_sbs_iot;
+ }
+
+ /* reset CPU flip-flops */
+ pulse_start_clear();
+}
+
+static void pdp1_reset (void)
+{
+ /* nothing to do */
+}
+
+static void pdp1_get_context (void *dst)
+{
+ if (dst)
+ *(pdp1_Regs *) dst = pdp1;
+}
+
+static void pdp1_set_context (void *src)
+{
+ if (src)
+ pdp1 = *(pdp1_Regs *) src;
+}
+
+
+/*
+ flags:
+ * 1 for each instruction which supports indirect addressing (memory reference instructions,
+ except cal and jda, and with the addition of jmp and jsp)
+ * 2 for memory reference instructions
+*/
+static const char instruction_kind[32] =
+{
+/* and ior xor xct cal/jda */
+ 0, 3, 3, 3, 3, 0, 0, 2,
+/* lac lio dac dap dip dio dzm */
+ 3, 3, 3, 3, 3, 3, 3, 0,
+/* add sub idx isp sad sas mus dis */
+ 3, 3, 3, 3, 3, 3, 3, 3,
+/* jmp jsp skp sft law iot opr */
+ 1, 1, 0, 0, 0, 0, 0, 0
+};
+
+
+/* execute instructions on this CPU until icount expires */
+static int pdp1_execute(int cycles)
+{
+ pdp1_ICount = cycles;
+
+ do
+ {
+ CALL_MAME_DEBUG;
+
+
+ /* ioh should be cleared at the end of the instruction cycle, and ios at the
+ start of next instruction cycle, but who cares? */
+ if (pdp1.ioh && pdp1.ios)
+ {
+ pdp1.ioh = 0;
+ pdp1.ios = 0;
+ }
+
+
+ if ((! pdp1.run) && (! pdp1.rim))
+ pdp1_ICount = 0; /* if processor is stopped, just burn cycles */
+ else if (pdp1.rim)
+ {
+ switch (pdp1.rim_step)
+ {
+ case 0:
+ /* read first word as instruction */
+ if (pdp1.read_binary_word)
+ (*pdp1.read_binary_word)(); /* data will be transferred to IO register */
+ pdp1.rim_step = 1;
+ break;
+
+ case 1:
+ if (! pdp1.ios)
+ { /* transfer incomplete: wait some more */
+ pdp1_ICount = 0;
+ }
+ else
+ { /* data transfer complete */
+ pdp1.ios = 0;
+
+ MB = IO;
+ IR = MB >> 13; /* basic opcode */
+ if (IR == JMP) /* jmp instruction ? */
+ {
+ PC = (MA & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK);
+ pdp1.rim = 0; /* exit read-in mode */
+ pdp1.run = 1;
+ pdp1.rim_step = 0;
+ }
+ else if ((IR == DIO) || (IR == DAC)) /* dio or dac instruction ? */
+ { /* there is a discrepancy: the pdp1 handbook tells that only dio should be used,
+ but the lisp tape uses the dac instruction instead */
+ /* Yet maintainance manual p. 6-25 states clearly that the data is located
+ in IO and transfered to MB, so DAC is likely to be a mistake. */
+ pdp1.rim_step = 2;
+ }
+ else
+ {
+ /* what the heck? */
+ if (LOG)
+ logerror("It seems this tape should not be operated in read-in mode\n");
+
+ pdp1.rim = 0; /* exit read-in mode (right???) */
+ pdp1.rim_step = 0;
+ }
+ }
+ break;
+
+ case 2:
+ /* read second word as data */
+ if (pdp1.read_binary_word)
+ (*pdp1.read_binary_word)(); /* data will be transferred to IO register */
+ pdp1.rim_step = 3;
+ break;
+
+ case 3:
+ if (! pdp1.ios)
+ { /* transfer incomplete: wait some more */
+ pdp1_ICount = 0;
+ }
+ else
+ { /* data transfer complete */
+ pdp1.ios = 0;
+
+ MA = (PC & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK);
+
+ MB = IO;
+ WRITE_PDP_18BIT(MA, MB);
+
+ pdp1.rim_step = 0;
+ }
+ break;
+ }
+ }
+ else
+ {
+ /* yes, interrupt can occur in the midst of an instruction (impressing, huh?) */
+ /* Note that break cannot occur during a one-cycle jump that is deferred only once,
+ or another break cycle. Also, it cannot interrupt the long cycle 1 of automatic
+ multiply/divide. (maintainance manual 6-19) */
+ if (pdp1.sbs_request && (! pdp1.no_sequence_break) && (! pdp1.brk_ctr))
+ { /* begin sequence break */
+ pdp1.brk_ctr = 1;
+ }
+ if (pdp1.brk_ctr)
+ { /* sequence break in progress */
+ switch (pdp1.brk_ctr)
+ {
+ case 1:
+ if (pdp1.cycle)
+ DECREMENT_PC; /* set PC to point to aborted instruction, so that it can be re-run */
+
+ pdp1.b4 |= (1 << pdp1.sbs_level); /* set "interrupt in progress" flag */
+ pdp1.b2 &= ~(1 << pdp1.sbs_level); /* clear interrupt request */
+ field_interrupt();
+ MA = pdp1.sbs_level << 2; /* always 0 with standard sequence break system */
+ MB = AC; /* save AC to MB */
+ AC = (OV << 17) | (EXD << 16) | PC; /* save OV/EXD/PC to AC */
+ EXD = OV = 0; /* according to maintainance manual p. 8-17 and ?-?? */
+ pdp1.cycle = pdp1.defer = pdp1.exc = 0; /* mere guess */
+ WRITE_PDP_18BIT(MA, MB); /* save former AC to memory */
+ INCREMENT_MA;
+ pdp1_ICount -= 5;
+ pdp1.brk_ctr++;
+ break;
+
+ case 2:
+ WRITE_PDP_18BIT(MA, MB = AC); /* save former OV/EXD/PC to memory */
+ INCREMENT_MA;
+ pdp1_ICount -= 5;
+ pdp1.brk_ctr++;
+ break;
+
+ case 3:
+ WRITE_PDP_18BIT(MA, MB = IO); /* save IO to memory */
+ INCREMENT_MA;
+ PC = MA;
+ pdp1_ICount -= 5;
+ pdp1.brk_ctr = 0;
+ break;
+ }
+ }
+ else
+ {
+ if (pdp1.no_sequence_break)
+ pdp1.no_sequence_break = 0;
+
+ if (! pdp1.cycle)
+ { /* no instruction in progress: time to fetch a new instruction, I guess */
+ MB = READ_PDP_18BIT(MA = PC);
+ INCREMENT_PC;
+ IR = MB >> 13; /* basic opcode */
+
+ if ((instruction_kind[IR] & 1) && (MB & 010000))
+ {
+ pdp1.defer = 1;
+ pdp1.cycle = 1; /* instruction shall be executed later */
+
+ /* detect deferred one-cycle jumps */
+ if ((IR == JMP) || (IR == JSP))
+ {
+ pdp1.no_sequence_break = 1;
+ /* detect JMP *(4*n+1) to memory module 0 if in sequence break mode */
+ if (((MB & 0777703) == 0610001) && (pdp1.sbm) && ! (MA & 0170000))
+ {
+ int level = (MB & 0000074) >> 2;
+
+ if ((pdp1.type_20_sbs) || (level == 0))
+ {
+ pdp1.b4 &= ~(1 << level);
+ field_interrupt();
+ if (pdp1.extend_support)
+ EXD = 1; /* according to maintainance manual p. 6-33 */
+ pdp1.sbs_restore = 1;
+ }
+ }
+ }
+ }
+ else if (instruction_kind[IR] & 2)
+ pdp1.cycle = 1; /* instruction shall be executed later */
+ else
+ execute_instruction(); /* execute instruction at once */
+
+ pdp1_ICount -= 5;
+ }
+ else if (pdp1.defer)
+ { /* defer cycle : handle indirect addressing */
+ MA = (PC & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK);
+
+ MB = READ_PDP_18BIT(MA);
+
+ /* determinate new value of pdp1.defer */
+ if (EXD)
+ {
+ pdp1.defer = 0;
+ pdp1.exc = 1;
+ }
+ else
+ pdp1.defer = (MB & 010000) ? 1 : 0;
+
+ /* execute JMP and JSP immediately if applicable */
+ if ((! pdp1.defer) && (! (instruction_kind[IR] & 2)))
+ {
+ execute_instruction(); /* execute instruction at once */
+ /*pdp1.cycle = 0;*/
+ pdp1.exc = 0;
+
+ if (pdp1.sbs_restore)
+ { /* interrupt return: according to maintainance manual p. 6-33 */
+ if (pdp1.extend_support)
+ EXD = (MB >> 16) & 1;
+ OV = (MB >> 17) & 1;
+ pdp1.sbs_restore = 0;
+ }
+ }
+
+ pdp1_ICount -= 5;
+ }
+ else
+ { /* memory reference instruction in cycle 1 */
+ if (pdp1.exc)
+ {
+ MA = MB & EXTENDED_ADDRESS_MASK;
+ pdp1.exc = 0;
+ }
+ else
+ MA = (PC & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK);
+
+ execute_instruction(); /* execute instruction */
+
+ pdp1_ICount -= 5;
+ }
+
+ if ((pdp1.sngl_inst) && (! pdp1.cycle))
+ pdp1.run = 0;
+ }
+ if (pdp1.sngl_step)
+ pdp1.run = 0;
+ }
+ }
+ while (pdp1_ICount > 0);
+
+ return cycles - pdp1_ICount;
+}
+
+
+static void pdp1_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0:
+ case CPUINFO_INT_INPUT_STATE + 1:
+ case CPUINFO_INT_INPUT_STATE + 2:
+ case CPUINFO_INT_INPUT_STATE + 3:
+ case CPUINFO_INT_INPUT_STATE + 4:
+ case CPUINFO_INT_INPUT_STATE + 5:
+ case CPUINFO_INT_INPUT_STATE + 6:
+ case CPUINFO_INT_INPUT_STATE + 7:
+ case CPUINFO_INT_INPUT_STATE + 8:
+ case CPUINFO_INT_INPUT_STATE + 9:
+ case CPUINFO_INT_INPUT_STATE + 10:
+ case CPUINFO_INT_INPUT_STATE + 11:
+ case CPUINFO_INT_INPUT_STATE + 12:
+ case CPUINFO_INT_INPUT_STATE + 13:
+ case CPUINFO_INT_INPUT_STATE + 14:
+ case CPUINFO_INT_INPUT_STATE + 15: pdp1_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); break;
+
+ case CPUINFO_INT_SP: (void) info->i; /* no SP */ break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + PDP1_PC: PC = info->i & EXTENDED_ADDRESS_MASK; break;
+ case CPUINFO_INT_REGISTER + PDP1_IR: IR = info->i & 037; /* weird idea */ break;
+ case CPUINFO_INT_REGISTER + PDP1_MB: MB = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + PDP1_MA: MA = info->i & EXTENDED_ADDRESS_MASK; break;
+ case CPUINFO_INT_REGISTER + PDP1_AC: AC = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + PDP1_IO: IO = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + PDP1_OV: OV = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + PDP1_PF: FLAGS = info->i & 077; break;
+ case CPUINFO_INT_REGISTER + PDP1_PF1: WRITEFLAG(1, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF2: WRITEFLAG(2, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF3: WRITEFLAG(3, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF4: WRITEFLAG(4, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF5: WRITEFLAG(5, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF6: WRITEFLAG(6, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_TA: pdp1.ta = info->i & 0177777 /*07777 with simpler control panel*/; break;
+ case CPUINFO_INT_REGISTER + PDP1_TW: pdp1.tw = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + PDP1_SS: SENSE_SW = info->i & 077; break;
+ case CPUINFO_INT_REGISTER + PDP1_SS1: WRITESENSE(1, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS2: WRITESENSE(2, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS3: WRITESENSE(3, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS4: WRITESENSE(4, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS5: WRITESENSE(5, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS6: WRITESENSE(6, info->i ? 1 : 0); break;
+ case CPUINFO_INT_REGISTER + PDP1_SNGL_STEP: pdp1.sngl_step = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + PDP1_SNGL_INST: pdp1.sngl_inst = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + PDP1_EXTEND_SW: pdp1.extend_sw = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + PDP1_RUN: pdp1.run = info->i ? 1 : 0; break;
+#if LOG
+ case CPUINFO_INT_REGISTER + PDP1_CYC: logerror("pdp1_set_reg to cycle flip-flop ignored\n");/* no way!*/ break;
+ case CPUINFO_INT_REGISTER + PDP1_DEFER: logerror("pdp1_set_reg to defer flip-flop ignored\n");/* no way!*/ break;
+ case CPUINFO_INT_REGISTER + PDP1_BRK_CTR: logerror("pdp1_set_reg to break counter ignored\n");/* no way!*/ break;
+#endif
+ case CPUINFO_INT_REGISTER + PDP1_RIM: pdp1.rim = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + PDP1_SBM: pdp1.sbm = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + PDP1_EXD: EXD = (pdp1.extend_support && info->i) ? 1 : 0; break;
+#if LOG
+ case CPUINFO_INT_REGISTER + PDP1_IOC: logerror("pdp1_set_reg to ioc flip-flop ignored\n");/* no way!*/ break;
+ case CPUINFO_INT_REGISTER + PDP1_IOH: logerror("pdp1_set_reg to ioh flip-flop ignored\n");/* no way!*/ break;
+ case CPUINFO_INT_REGISTER + PDP1_IOS: logerror("pdp1_set_reg to ios flip-flop ignored\n");/* no way!*/ break;
+#endif
+ case CPUINFO_INT_REGISTER + PDP1_START_CLEAR: pulse_start_clear(); break;
+ case CPUINFO_INT_REGISTER + PDP1_IO_COMPLETE: pdp1.ios = 1; break;
+ }
+}
+
+
+void pdp1_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(pdp1); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 16; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; /*don't care*/ break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 5; /* 5us cycle time */ break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 31; /* we emulate individual 5us cycle, but MUL/DIV have longer timings */ break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 18; /*16+2 ignored bits to make double word address*/ break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_SP: info->i = 0; /* no SP */ break;
+ case CPUINFO_INT_PC: info->i = PC; break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* TODO??? */ break;
+
+ case CPUINFO_INT_INPUT_STATE + 0:
+ case CPUINFO_INT_INPUT_STATE + 1:
+ case CPUINFO_INT_INPUT_STATE + 2:
+ case CPUINFO_INT_INPUT_STATE + 3:
+ case CPUINFO_INT_INPUT_STATE + 4:
+ case CPUINFO_INT_INPUT_STATE + 5:
+ case CPUINFO_INT_INPUT_STATE + 6:
+ case CPUINFO_INT_INPUT_STATE + 7:
+ case CPUINFO_INT_INPUT_STATE + 8:
+ case CPUINFO_INT_INPUT_STATE + 9:
+ case CPUINFO_INT_INPUT_STATE + 10:
+ case CPUINFO_INT_INPUT_STATE + 11:
+ case CPUINFO_INT_INPUT_STATE + 12:
+ case CPUINFO_INT_INPUT_STATE + 13:
+ case CPUINFO_INT_INPUT_STATE + 14:
+ case CPUINFO_INT_INPUT_STATE + 15: info->i = (pdp1.irq_state >> (state-CPUINFO_INT_INPUT_STATE)) & 1; break;
+
+ case CPUINFO_INT_REGISTER + PDP1_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + PDP1_IR: info->i = IR; break;
+ case CPUINFO_INT_REGISTER + PDP1_MB: info->i = MB; break;
+ case CPUINFO_INT_REGISTER + PDP1_MA: info->i = MA; break;
+ case CPUINFO_INT_REGISTER + PDP1_AC: info->i = AC; break;
+ case CPUINFO_INT_REGISTER + PDP1_IO: info->i = IO; break;
+ case CPUINFO_INT_REGISTER + PDP1_OV: info->i = OV; break;
+ case CPUINFO_INT_REGISTER + PDP1_PF: info->i = FLAGS; break;
+ case CPUINFO_INT_REGISTER + PDP1_PF1: info->i = READFLAG(1); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF2: info->i = READFLAG(2); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF3: info->i = READFLAG(3); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF4: info->i = READFLAG(4); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF5: info->i = READFLAG(5); break;
+ case CPUINFO_INT_REGISTER + PDP1_PF6: info->i = READFLAG(6); break;
+ case CPUINFO_INT_REGISTER + PDP1_TA: info->i = pdp1.ta; break;
+ case CPUINFO_INT_REGISTER + PDP1_TW: info->i = pdp1.tw; break;
+ case CPUINFO_INT_REGISTER + PDP1_SS: info->i = SENSE_SW; break;
+ case CPUINFO_INT_REGISTER + PDP1_SS1: info->i = READSENSE(1); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS2: info->i = READSENSE(2); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS3: info->i = READSENSE(3); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS4: info->i = READSENSE(4); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS5: info->i = READSENSE(5); break;
+ case CPUINFO_INT_REGISTER + PDP1_SS6: info->i = READSENSE(6); break;
+ case CPUINFO_INT_REGISTER + PDP1_SNGL_STEP: info->i = pdp1.sngl_step; break;
+ case CPUINFO_INT_REGISTER + PDP1_SNGL_INST: info->i = pdp1.sngl_inst; break;
+ case CPUINFO_INT_REGISTER + PDP1_EXTEND_SW: info->i = pdp1.extend_sw; break;
+ case CPUINFO_INT_REGISTER + PDP1_RUN: info->i = pdp1.run; break;
+ case CPUINFO_INT_REGISTER + PDP1_CYC: info->i = pdp1.cycle; break;
+ case CPUINFO_INT_REGISTER + PDP1_DEFER: info->i = pdp1.defer; break;
+ case CPUINFO_INT_REGISTER + PDP1_BRK_CTR: info->i = pdp1.brk_ctr; break;
+ case CPUINFO_INT_REGISTER + PDP1_RIM: info->i = pdp1.rim; break;
+ case CPUINFO_INT_REGISTER + PDP1_SBM: info->i = pdp1.sbm; break;
+ case CPUINFO_INT_REGISTER + PDP1_EXD: info->i = EXD; break;
+ case CPUINFO_INT_REGISTER + PDP1_IOC: info->i = pdp1.ioc; break;
+ case CPUINFO_INT_REGISTER + PDP1_IOH: info->i = pdp1.ioh; break;
+ case CPUINFO_INT_REGISTER + PDP1_IOS: info->i = pdp1.ios; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = pdp1_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = pdp1_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = pdp1_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = pdp1_init; break;
+ case CPUINFO_PTR_RESET: info->reset = pdp1_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = pdp1_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = pdp1_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &pdp1_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "PDP1"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "DEC PDP-1"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "2.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(),
+ "Brian Silverman (original Java Source)\n"
+ "Vadim Gerasimov (original Java Source)\n"
+ "Chris Salomon (MESS driver)\n"
+ "Raphael Nabet (MESS driver)\n");
+ break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s = cpuintrf_temp_str(), "%c%c%c%c%c%c-%c%c%c%c%c%c",
+ (FLAGS & 040) ? '1' : '.',
+ (FLAGS & 020) ? '2' : '.',
+ (FLAGS & 010) ? '3' : '.',
+ (FLAGS & 004) ? '4' : '.',
+ (FLAGS & 002) ? '5' : '.',
+ (FLAGS & 001) ? '6' : '.',
+ (SENSE_SW & 040) ? '1' : '.',
+ (SENSE_SW & 020) ? '2' : '.',
+ (SENSE_SW & 010) ? '3' : '.',
+ (SENSE_SW & 004) ? '4' : '.',
+ (SENSE_SW & 002) ? '5' : '.',
+ (SENSE_SW & 001) ? '6' : '.');
+ break;
+
+
+ case CPUINFO_STR_REGISTER + PDP1_PC: sprintf(info->s = cpuintrf_temp_str(), "PC:0%06o", PC); break;
+ case CPUINFO_STR_REGISTER + PDP1_IR: sprintf(info->s = cpuintrf_temp_str(), "IR:0%02o", IR); break;
+ case CPUINFO_STR_REGISTER + PDP1_MB: sprintf(info->s = cpuintrf_temp_str(), "MB:0%06o", MB); break;
+ case CPUINFO_STR_REGISTER + PDP1_MA: sprintf(info->s = cpuintrf_temp_str(), "MA:0%06o", MA); break;
+ case CPUINFO_STR_REGISTER + PDP1_AC: sprintf(info->s = cpuintrf_temp_str(), "AC:0%06o", AC); break;
+ case CPUINFO_STR_REGISTER + PDP1_IO: sprintf(info->s = cpuintrf_temp_str(), "IO:0%06o", IO); break;
+ case CPUINFO_STR_REGISTER + PDP1_OV: sprintf(info->s = cpuintrf_temp_str(), "OV:%X", OV); break;
+ case CPUINFO_STR_REGISTER + PDP1_PF: sprintf(info->s = cpuintrf_temp_str(), "FLAGS:0%02o", FLAGS); break;
+ case CPUINFO_STR_REGISTER + PDP1_PF1: sprintf(info->s = cpuintrf_temp_str(), "FLAG1:%X", READFLAG(1)); break;
+ case CPUINFO_STR_REGISTER + PDP1_PF2: sprintf(info->s = cpuintrf_temp_str(), "FLAG2:%X", READFLAG(2)); break;
+ case CPUINFO_STR_REGISTER + PDP1_PF3: sprintf(info->s = cpuintrf_temp_str(), "FLAG3:%X", READFLAG(3)); break;
+ case CPUINFO_STR_REGISTER + PDP1_PF4: sprintf(info->s = cpuintrf_temp_str(), "FLAG4:%X", READFLAG(4)); break;
+ case CPUINFO_STR_REGISTER + PDP1_PF5: sprintf(info->s = cpuintrf_temp_str(), "FLAG5:%X", READFLAG(5)); break;
+ case CPUINFO_STR_REGISTER + PDP1_PF6: sprintf(info->s = cpuintrf_temp_str(), "FLAG6:%X", READFLAG(6)); break;
+ case CPUINFO_STR_REGISTER + PDP1_TA: sprintf(info->s = cpuintrf_temp_str(), "TA:0%06o", pdp1.ta); break;
+ case CPUINFO_STR_REGISTER + PDP1_TW: sprintf(info->s = cpuintrf_temp_str(), "TW:0%06o", pdp1.tw); break;
+ case CPUINFO_STR_REGISTER + PDP1_SS: sprintf(info->s = cpuintrf_temp_str(), "SS:0%02o", SENSE_SW); break;
+ case CPUINFO_STR_REGISTER + PDP1_SS1: sprintf(info->s = cpuintrf_temp_str(), "SENSE1:%X", READSENSE(1)); break;
+ case CPUINFO_STR_REGISTER + PDP1_SS2: sprintf(info->s = cpuintrf_temp_str(), "SENSE2:%X", READSENSE(2)); break;
+ case CPUINFO_STR_REGISTER + PDP1_SS3: sprintf(info->s = cpuintrf_temp_str(), "SENSE3:%X", READSENSE(3)); break;
+ case CPUINFO_STR_REGISTER + PDP1_SS4: sprintf(info->s = cpuintrf_temp_str(), "SENSE4:%X", READSENSE(4)); break;
+ case CPUINFO_STR_REGISTER + PDP1_SS5: sprintf(info->s = cpuintrf_temp_str(), "SENSE5:%X", READSENSE(5)); break;
+ case CPUINFO_STR_REGISTER + PDP1_SS6: sprintf(info->s = cpuintrf_temp_str(), "SENSE6:%X", READSENSE(6)); break;
+ case CPUINFO_STR_REGISTER + PDP1_SNGL_STEP: sprintf(info->s = cpuintrf_temp_str(), "SNGLSTEP:%X", pdp1.sngl_step); break;
+ case CPUINFO_STR_REGISTER + PDP1_SNGL_INST: sprintf(info->s = cpuintrf_temp_str(), "SNGLINST:%X", pdp1.sngl_inst); break;
+ case CPUINFO_STR_REGISTER + PDP1_EXTEND_SW: sprintf(info->s = cpuintrf_temp_str(), "EXS:%X", pdp1.extend_sw); break;
+ case CPUINFO_STR_REGISTER + PDP1_RUN: sprintf(info->s = cpuintrf_temp_str(), "RUN:%X", pdp1.run); break;
+ case CPUINFO_STR_REGISTER + PDP1_CYC: sprintf(info->s = cpuintrf_temp_str(), "CYC:%X", pdp1.cycle); break;
+ case CPUINFO_STR_REGISTER + PDP1_DEFER: sprintf(info->s = cpuintrf_temp_str(), "DF:%X", pdp1.defer); break;
+ case CPUINFO_STR_REGISTER + PDP1_BRK_CTR: sprintf(info->s = cpuintrf_temp_str(), "BRKCTR:%X", pdp1.brk_ctr); break;
+ case CPUINFO_STR_REGISTER + PDP1_RIM: sprintf(info->s = cpuintrf_temp_str(), "RIM:%X", pdp1.rim); break;
+ case CPUINFO_STR_REGISTER + PDP1_SBM: sprintf(info->s = cpuintrf_temp_str(), "SBM:%X", pdp1.sbm); break;
+ case CPUINFO_STR_REGISTER + PDP1_EXD: sprintf(info->s = cpuintrf_temp_str(), "EXD:%X", EXD); break;
+ case CPUINFO_STR_REGISTER + PDP1_IOC: sprintf(info->s = cpuintrf_temp_str(), "IOC:%X", pdp1.ioc); break;
+ case CPUINFO_STR_REGISTER + PDP1_IOH: sprintf(info->s = cpuintrf_temp_str(), "IOH:%X", pdp1.ioh); break;
+ case CPUINFO_STR_REGISTER + PDP1_IOS: sprintf(info->s = cpuintrf_temp_str(), "IOS:%X", pdp1.ios); break;
+ }
+}
+
+
+/* execute one instruction */
+static void execute_instruction(void)
+{
+ switch (IR)
+ {
+ case AND: /* Logical And */
+ AC &= (MB = READ_PDP_18BIT(MA));
+ break;
+ case IOR: /* Inclusive Or */
+ AC |= (MB = READ_PDP_18BIT(MA));
+ break;
+ case XOR: /* Exclusive Or */
+ AC ^= (MB = READ_PDP_18BIT(MA));
+ break;
+ case XCT: /* Execute */
+ MB = READ_PDP_18BIT(MA);
+ IR = MB >> 13; /* basic opcode */
+ if ((instruction_kind[IR] & 1) && (MB & 010000))
+ {
+ pdp1.defer = 1;
+ /*pdp1.cycle = 1;*/ /* instruction shall be executed later */
+ goto no_fetch; /* fall through to next instruction */
+ }
+ else if (instruction_kind[IR] & 2)
+ {
+ /*pdp1.cycle = 1;*/ /* instruction shall be executed later */
+ goto no_fetch; /* fall through to next instruction */
+ }
+ else
+ execute_instruction(); /* execute instruction at once */
+ break;
+ case CALJDA: /* Call subroutine and Jump and Deposit Accumulator instructions */
+ if (MB & 010000)
+ /* JDA */
+ MA = (PC & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK);
+ else
+ /* CAL: equivalent to JDA 100 */
+ /* Note that I cannot tell for sure what happens to extension bits, but I did notice
+ that setting the extension bits to 0 would make cal basically useless, since
+ there would be no simple way the call routine could return to the callee
+ if it were located in another module with extend mode off (i.e. exd == 0). */
+ MA = (PC & ADDRESS_EXTENSION_MASK) | 0100;
+
+ WRITE_PDP_18BIT(MA, (MB = AC));
+ INCREMENT_MA;
+ AC = (OV << 17) | (EXD << 16) | PC;
+ PC = MA;
+ break;
+ case LAC: /* Load Accumulator */
+ AC = (MB = READ_PDP_18BIT(MA));
+ break;
+ case LIO: /* Load i/o register */
+ IO = (MB = READ_PDP_18BIT(MA));
+ break;
+ case DAC: /* Deposit Accumulator */
+ WRITE_PDP_18BIT(MA, (MB = AC));
+ break;
+ case DAP: /* Deposit Address Part */
+ WRITE_PDP_18BIT(MA, (MB = ((READ_PDP_18BIT(MA) & 0770000) | (AC & 0007777))));
+ break;
+ case DIP: /* Deposit Instruction Part */
+ WRITE_PDP_18BIT(MA, (MB = ((READ_PDP_18BIT(MA) & 0007777) | (AC & 0770000))));
+ break;
+ case DIO: /* Deposit I/O Register */
+ WRITE_PDP_18BIT(MA, (MB = IO));
+ break;
+ case DZM: /* Deposit Zero in Memory */
+ WRITE_PDP_18BIT(MA, (MB = 0));
+ break;
+ case ADD: /* Add */
+ {
+ /* overflow is set if the 2 operands have the same sign and the final result has another */
+ int ov2; /* 1 if the operands have the same sign*/
+
+ MB = READ_PDP_18BIT(MA);
+
+ ov2 = ((AC & 0400000) == (MB & 0400000));
+
+ AC = AC + MB;
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+
+ /* I think we need to check for overflow before checking for -0,
+ because the sum -0+-0 = -0 = +0 would generate an overflow
+ otherwise. */
+ if (ov2 && ((AC & 0400000) != (MB & 0400000)))
+ OV = 1;
+
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+
+ break;
+ }
+ case SUB: /* Subtract */
+ { /* maintainance manual 7-14 seems to imply that substract does not test for -0.
+ The sim 2.3 source says so explicitely, though they do not give a reference.
+ It sounds a bit weird, but the reason is probably that doing so would
+ require additionnal logic that does not exist. */
+ /* overflow is set if the 2 operands have the same sign and the final result has another */
+ int ov2; /* 1 if the operands have the same sign*/
+
+ AC ^= 0777777;
+
+ MB = READ_PDP_18BIT(MA);
+
+ ov2 = ((AC & 0400000) == (MB & 0400000));
+
+ AC = AC + MB;
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+
+ if (ov2 && ((AC & 0400000) != (MB & 0400000)))
+ OV = 1;
+
+ AC ^= 0777777;
+
+ break;
+ }
+ case IDX: /* Index */
+ AC = READ_PDP_18BIT(MA) + 1;
+
+ #if 0
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+ #else
+ if (AC >= 0777777)
+ AC = (AC + 1) & 0777777;
+ #endif
+
+ WRITE_PDP_18BIT(MA, (MB = AC));
+ break;
+ case ISP: /* Index and Skip if Positive */
+ AC = READ_PDP_18BIT(MA) + 1;
+
+ #if 0
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+ #else
+ if (AC >= 0777777)
+ AC = (AC + 1) & 0777777;
+ #endif
+
+ WRITE_PDP_18BIT(MA, (MB = AC));
+ if ((AC & 0400000) == 0)
+ INCREMENT_PC;
+ break;
+ case SAD: /* Skip if Accumulator and Y differ */
+ if (AC != (MB = READ_PDP_18BIT(MA)))
+ INCREMENT_PC;
+ break;
+ case SAS: /* Skip if Accumulator and Y are the same */
+ if (AC == (MB = READ_PDP_18BIT(MA)))
+ INCREMENT_PC;
+ break;
+ case MUS_MUL: /* Multiply Step or Multiply */
+ if (pdp1.hw_mul_div)
+ { /* MUL */
+ int scr;
+ int smb, srm;
+ double etime = 4.; /* approximative */
+
+ IO = MB = AC;
+ MB = READ_PDP_18BIT(MA);
+ scr = 0;
+ if (MB & 0400000)
+ {
+ smb = 1;
+ MB = MB ^ 0777777;
+ }
+ else
+ smb = 0;
+ if (IO & 0400000)
+ {
+ srm = 1;
+ IO = IO ^ 0777777;
+ }
+ else
+ srm = 0;
+ AC = 0;
+ scr++;
+ while (scr < 022)
+ {
+ if (IO & 1)
+ {
+ /*assert(! (AC & 0400000));*/
+ AC = AC + MB;
+ /* we can save carry around since both numbers are positive */
+ /*AC = (AC + (AC >> 18)) & 0777777;*/
+ etime += .65; /* approximative */
+ }
+ IO = (IO >> 1) | ((AC & 1) << 17);
+ AC = AC >> 1;
+ scr++;
+ }
+ if (smb ^ srm)
+ {
+ AC = AC ^ 0777777;
+ IO = IO ^ 0777777;
+ }
+
+ pdp1_ICount -= etime+.5; /* round to closest */
+ }
+ else
+ { /* MUS */
+ /* should we check for -0??? (Maintainance manual 7-14 seems to imply we should not:
+ as a matter of fact, since the MUS instruction is supposed to have positive operands,
+ there is no need to check for -0, therefore such a simplification does not sound
+ absurd.) */
+ if ((IO & 1) == 1)
+ {
+ AC = AC + (MB = READ_PDP_18BIT(MA));
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+ }
+ IO = (IO >> 1 | AC << 17) & 0777777;
+ AC >>= 1;
+ }
+ break;
+ case DIS_DIV: /* Divide Step or Divide */
+ if (pdp1.hw_mul_div)
+ { /* DIV */
+ /* As a side note, the order of -0 detection and overflow checking does not matter,
+ because the sum of two positive number cannot give 0777777 (since positive
+ numbers are 0377777 at most, their sum is 0777776 at most).
+ Additionnally, we cannot have carry set and a result equal to 0777777 (since numbers
+ are 0777777 at most, their sum is 01777776 at most): this is nice, because it makes
+ the sequence:
+ AC = (AC + (AC >> 18)) & 0777777; // propagate carry around
+ if (AC == 0777777) // check for -0
+ AC = 0;
+ equivalent to:
+ if (AC >= 0777777)
+ AC = (AC + 1) & 0777777;
+ which is a bit more efficient. */
+ int acl;
+ int scr;
+ int smb, srm;
+ double etime = 0; /* approximative */
+
+ MB = READ_PDP_18BIT(MA);
+ scr = 0;
+ if (MB & 0400000)
+ {
+ smb = 1;
+ }
+ else
+ {
+ smb = 0;
+ MB = MB ^ 0777777;
+ }
+ if (AC & 0400000)
+ {
+ srm = 1;
+ AC = AC ^ 0777777;
+ IO = IO ^ 0777777;
+ }
+ else
+ srm = 0;
+ while (1)
+ {
+ AC = (AC + MB);
+ #if 1
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+ #else
+ if (AC >= 0777777)
+ AC = (AC + 1) & 0777777;
+ #endif
+ if (MB & 0400000)
+ MB = MB ^ 0777777;
+
+ if (((scr == 0) && ! (AC & 0400000))
+ || (scr == 022))
+ break;
+
+ scr++;
+
+ if (! (AC & 0400000))
+ MB = MB ^ 0777777;
+
+ acl = AC >> 17;
+ AC = (AC << 1 | IO >> 17) & 0777777;
+ IO = ((IO << 1 | acl) & 0777777) ^ 1;
+ if (acl)
+ {
+ AC++;
+ AC = (AC + (AC >> 18)) & 0777777;
+ etime += .6; /* approximative */
+ }
+ }
+
+ AC = (AC + MB);
+ #if 1
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+ #else
+ if (AC >= 0777777)
+ AC = (AC + 1) & 0777777;
+ #endif
+
+ if (scr)
+ {
+ INCREMENT_PC;
+ AC = AC >> 1;
+ }
+
+ if (srm && (AC != 0))
+ AC = AC ^ 0777777;
+
+ if (((! scr) && (srm))
+ || (scr && (srm ^ smb) && (IO != 0)))
+ IO = IO ^ 0777777;
+
+ if (scr)
+ {
+ MB = AC;
+ AC = IO;
+ IO = MB;
+ }
+ if (scr)
+ etime += 20; /* approximative */
+ else
+ etime += 2; /* approximative */
+
+ pdp1_ICount -= etime+.5; /* round to closest */
+ }
+ else
+ { /* DIS */
+ int acl;
+
+ acl = AC >> 17;
+ AC = (AC << 1 | IO >> 17) & 0777777;
+ IO = ((IO << 1 | acl) & 0777777) ^ 1;
+ MB = READ_PDP_18BIT(MA);
+ if (IO & 1)
+ AC += (MB ^ 0777777);
+ else
+ /* Note that if AC+MB = 0777777, we are in trouble. I don't
+ know how a real PDP-1 behaves in this case. */
+ AC += MB + 1;
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+ }
+ break;
+ case JMP: /* Jump */
+ if (pdp1.exc)
+ PC = MB & EXTENDED_ADDRESS_MASK;
+ else
+ PC = (MA & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK);
+ break;
+ case JSP: /* Jump and Save Program Counter */
+ AC = (OV << 17) | (EXD << 16) | PC;
+ if (pdp1.exc)
+ PC = MB & EXTENDED_ADDRESS_MASK;
+ else
+ PC = (MA & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK);
+ break;
+ case SKP: /* Skip Instruction Group */
+ {
+ int cond = ((MB & 0100) && (AC == 0)) /* ZERO Accumulator */
+ || ((MB & 0200) && (AC >> 17 == 0)) /* Plus Accumulator */
+ || ((MB & 0400) && (AC >> 17 == 1)) /* Minus Accumulator */
+ || ((MB & 01000) && (OV == 0)) /* ZERO Overflow */
+ || ((MB & 02000) && (IO >> 17 == 0)) /* Plus I/O Register */
+ || (((MB & 7) != 0) && (((MB & 7) == 7) ? ! FLAGS : ! READFLAG(MB & 7))) /* ZERO Flag (deleted by mistake in PDP-1 handbook) */
+ || (((MB & 070) != 0) && (((MB & 070) == 070) ? ! SENSE_SW : ! READSENSE((MB & 070) >> 3))); /* ZERO Switch */
+
+ if (! (MB & 010000))
+ {
+ if (cond)
+ INCREMENT_PC;
+ }
+ else
+ {
+ if (!cond)
+ INCREMENT_PC;
+ }
+ if (MB & 01000)
+ OV = 0;
+ break;
+ }
+ case SFT: /* Shift Instruction Group */
+ {
+ /* Bit 5 specifies direction of shift, Bit 6 specifies the character of the shift
+ (arithmetic or logical), Bits 7 and 8 enable the registers (01 = AC, 10 = IO,
+ and 11 = both) and Bits 9 through 17 specify the number of steps. */
+ int nshift = 0;
+ int mask = MB & 0777;
+
+ while (mask != 0)
+ {
+ nshift += mask & 1;
+ mask >>= 1;
+ }
+ switch ((MB >> 9) & 017)
+ {
+ int i;
+
+ case 1: /* ral rotate accumulator left */
+ for (i = 0; i < nshift; i++)
+ AC = (AC << 1 | AC >> 17) & 0777777;
+ break;
+ case 2: /* ril rotate i/o register left */
+ for (i = 0; i < nshift; i++)
+ IO = (IO << 1 | IO >> 17) & 0777777;
+ break;
+ case 3: /* rcl rotate AC and IO left */
+ for (i = 0; i < nshift; i++)
+ {
+ int tmp = AC;
+
+ AC = (AC << 1 | IO >> 17) & 0777777;
+ IO = (IO << 1 | tmp >> 17) & 0777777;
+ }
+ break;
+ case 5: /* sal shift accumulator left */
+ for (i = 0; i < nshift; i++)
+ AC = ((AC << 1 | AC >> 17) & 0377777) + (AC & 0400000);
+ break;
+ case 6: /* sil shift i/o register left */
+ for (i = 0; i < nshift; i++)
+ IO = ((IO << 1 | IO >> 17) & 0377777) + (IO & 0400000);
+ break;
+ case 7: /* scl shift AC and IO left */
+ for (i = 0; i < nshift; i++)
+ {
+ int tmp = AC;
+
+ AC = ((AC << 1 | IO >> 17) & 0377777) + (AC & 0400000); /* shouldn't that be IO?, no it is the sign! */
+ IO = (IO << 1 | tmp >> 17) & 0777777;
+ }
+ break;
+ case 9: /* rar rotate accumulator right */
+ for (i = 0; i < nshift; i++)
+ AC = (AC >> 1 | AC << 17) & 0777777;
+ break;
+ case 10: /* rir rotate i/o register right */
+ for (i = 0; i < nshift; i++)
+ IO = (IO >> 1 | IO << 17) & 0777777;
+ break;
+ case 11: /* rcr rotate AC and IO right */
+ for (i = 0; i < nshift; i++)
+ {
+ int tmp = AC;
+
+ AC = (AC >> 1 | IO << 17) & 0777777;
+ IO = (IO >> 1 | tmp << 17) & 0777777;
+ }
+ break;
+ case 13: /* sar shift accumulator right */
+ for (i = 0; i < nshift; i++)
+ AC = (AC >> 1) + (AC & 0400000);
+ break;
+ case 14: /* sir shift i/o register right */
+ for (i = 0; i < nshift; i++)
+ IO = (IO >> 1) + (IO & 0400000);
+ break;
+ case 15: /* scr shift AC and IO right */
+ for (i = 0; i < nshift; i++)
+ {
+ int tmp = AC;
+
+ AC = (AC >> 1) + (AC & 0400000); /* shouldn't that be IO, no it is the sign */
+ IO = (IO >> 1 | tmp << 17) & 0777777;
+ }
+ break;
+ default:
+ if (LOG)
+ logerror("Undefined shift: 0%06o at 0%06o\n", MB, PREVIOUS_PC);
+ break;
+ }
+ break;
+ }
+ case LAW: /* Load Accumulator with N */
+ AC = MB & 07777;
+ if (MB & 010000)
+ AC ^= 0777777;
+ break;
+ case IOT: /* In-Out Transfer Instruction Group */
+ /*
+ The variations within this group of instructions perform all the in-out control
+ and information transfer functions. If Bit 5 (normally the Indirect Address bit)
+ is a ONE, the computer will enter a special waiting state until the completion pulse
+ from the activated device has returned. When this device delivers its completion,
+ the computer will resume operation of the instruction sequence.
+
+ The computer may be interrupted from the special waiting state to serve a sequence
+ break request or a high speed channel request.
+
+ Most in-out operations require a known minimum time before completion. This time
+ may be utilized for programming. The appropriate In-Out Transfer can be given with
+ no in-out wait (Bit 5 a ZERO and Bit 6 a ONE). The instruction sequence then
+ continues. This sequence must include an iot instruction 730000 which performs
+ nothing but the in-out wait. The computer will then enter the special waiting state
+ until the device returns the in-out restart pulse. If the device has already
+ returned the completion pulse before the instruction 730000, the computer will
+ proceed immediately.
+
+ Bit 6 determines whether a completion pulse will or will not be received from
+ the in-out device. When it is different than Bit 5, a completion pulse will be
+ received. When it is the same as Bit 5, a completion pulse will not be received.
+
+ In addition to the control function of Bits 5 and 6, Bits 7 through 11 are also
+ used as control bits serving to extend greatly the power of the iot instructions.
+ For example, Bits 12 through 17, which are used to designate a class of input or
+ output devices such as typewriters, may be further defined by Bits 7 through 11
+ as referring to Typewriter 1, 2, 3, etc. In several of the optional in-out devices,
+ in particular the magnetic tape, Bits 7 through 11 specify particular functions
+ such as forward, backward etc. If a large number of specialized devices are to
+ be attached, these bits may be used to further the in-out transfer instruction
+ to perform totally distinct functions.
+
+ Note that ioc is supposed to be set at the beggining of the memory cycle after
+ ioh is cleared.
+ However, we cannot set ioc at the beggining of every memory cycle as we
+ did before, because it breaks in the following case:
+ a) IOT instruction enables IO wait
+ b) sequence break in the middle of IO-halt
+ c) ioh is cleared in middle of sequence break routine
+ d) re-execute IOT instruction. Unfortunately, ioc has been cleared, therefore
+ we perform an IOT command pulse and IO wait again, which is completely WRONG.
+ Therefore ioc is cleared only after a IOT with wait is executed.
+ */
+ if (MB & 010000)
+ { /* IOT with IO wait */
+ if (pdp1.ioc)
+ { /* the iot command line is pulsed only if ioc is asserted */
+ (*pdp1.extern_iot[MB & 0000077])(MB & 0000077, (MB & 0004000) == 0, MB, &IO, AC);
+
+ pdp1.ioh = 1; /* enable io wait */
+
+ pdp1.ioc = 0; /* actually happens at the start of next memory cycle */
+
+ /* test ios now in case the IOT callback has sent a completion pulse immediately */
+ if (pdp1.ioh && pdp1.ios)
+ {
+ /* ioh should be cleared at the end of the instruction cycle, and ios at the
+ start of next instruction cycle, but who cares? */
+ pdp1.ioh = 0;
+ pdp1.ios = 0;
+ }
+ }
+
+ if (pdp1.ioh)
+ DECREMENT_PC;
+ else
+ pdp1.ioc = 1; /* actually happens at the start of next memory cycle */
+ }
+ else
+ { /* IOT with no IO wait */
+ (*pdp1.extern_iot[MB & 0000077])(MB & 0000077, (MB & 0004000) != 0, MB, &IO, AC);
+ }
+ break;
+ case OPR: /* Operate Instruction Group */
+ {
+ int nflag;
+
+ if (MB & 00200) /* clear AC */
+ AC = 0;
+ if (MB & 04000) /* clear I/O register */
+ IO = 0;
+ if (MB & 02000) /* load Accumulator from Test Word */
+ AC |= pdp1.tw;
+ if (MB & 00100) /* load Accumulator with Program Counter */
+ AC |= (OV << 17) | (EXD << 16) | PC;
+ nflag = MB & 7;
+ if (nflag)
+ {
+ if (nflag == 7)
+ FLAGS = (MB & 010) ? 077 : 000;
+ else
+ WRITEFLAG(nflag, (MB & 010) ? 1 : 0);
+ }
+ if (MB & 01000) /* Complement AC */
+ AC ^= 0777777;
+ if (MB & 00400) /* Halt */
+ {
+ if (LOG_EXTRA)
+ logerror("PDP1 Program executed HALT: at 0%06o\n", PREVIOUS_PC);
+
+ pdp1.run = 0;
+ }
+ break;
+ }
+ default:
+ if (LOG)
+ logerror("Illegal instruction: 0%06o at 0%06o\n", MB, PREVIOUS_PC);
+
+ /* let us stop the CPU, like a real pdp-1 */
+ pdp1.run = 0;
+
+ break;
+ }
+ pdp1.cycle = 0;
+no_fetch:
+ ;
+}
+
+
+/*
+ Handle unimplemented IOT
+*/
+static void null_iot(int op2, int nac, int mb, int *io, int ac)
+{
+ /* Note that the dummy IOT 0 is used to wait for the completion pulse
+ generated by the a pending IOT (IOT with completion pulse but no IO wait) */
+ if (LOG_IOT_EXTRA)
+ {
+ if (op2 == 000)
+ logerror("IOT sync instruction: mb=0%06o, pc=0%06o\n", (unsigned) mb, (unsigned) cpunum_get_reg(0, PDP1_PC));
+ }
+ if (LOG)
+ {
+ if (op2 != 000)
+ logerror("Not supported IOT command (no external IOT function given) 0%06o at 0%06o\n", mb, PREVIOUS_PC);
+ }
+}
+
+
+/*
+ Memory expansion control (type 15)
+
+ IOT 74: LEM/EEM
+*/
+static void lem_eem_iot(int op2, int nac, int mb, int *io, int ac)
+{
+ if (! pdp1.extend_support) /* extend mode supported? */
+ {
+ if (LOG)
+ logerror("Ignoring internal error in file " __FILE__ " line %d.\n", __LINE__);
+ return;
+ }
+ if (LOG_EXTRA)
+ {
+ logerror("EEM/LEM instruction: mb=0%06o, pc=0%06o\n", mb, pdp1.pc);
+ }
+ EXD = (mb & 0004000) ? 1 : 0;
+}
+
+
+/*
+ Standard sequence break system
+
+ IOT 54: lsm
+ IOT 55: esm
+ IOT 56: cbs
+*/
+static void sbs_iot(int op2, int nac, int mb, int *io, int ac)
+{
+ switch (op2)
+ {
+ case 054: /* LSM */
+ if (LOG_EXTRA)
+ logerror("LSM instruction: mb=0%06o, pc=0%06o\n", mb, pdp1.pc);
+
+ pdp1.sbm = 0;
+ field_interrupt();
+ break;
+ case 055: /* ESM */
+ if (LOG_EXTRA)
+ logerror("ESM instruction: mb=0%06o, pc=0%06o\n", mb, pdp1.pc);
+
+ pdp1.sbm = 1;
+ field_interrupt();
+ break;
+ case 056: /* CBS */
+ if (LOG_EXTRA)
+ logerror("CBS instruction: mb=0%06o, pc=0%06o\n", mb, pdp1.pc);
+
+ /*pdp1.b3 = 0;*/
+ pdp1.b4 = 0;
+ field_interrupt();
+ break;
+ default:
+ if (LOG)
+ logerror("Ignoring internal error in file " __FILE__ " line %d.\n", __LINE__);
+
+ break;
+ }
+}
+
+
+/*
+ type 20 sequence break system
+
+ IOT 50: dsc
+ IOT 51: asc
+ IOT 52: isb
+ IOT 53: cac
+*/
+static void type_20_sbs_iot(int op2, int nac, int mb, int *io, int ac)
+{
+ int channel, mask;
+ if (! pdp1.type_20_sbs) /* type 20 sequence break system supported? */
+ {
+ if (LOG)
+ logerror("Ignoring internal error in file " __FILE__ " line %d.\n", __LINE__);
+ return;
+ }
+ channel = (mb >> 6) & 017;
+ mask = 1 << channel;
+ switch (op2)
+ {
+ case 050: /* DSC */
+ if (LOG_EXTRA)
+ logerror("DSC instruction: mb=0%06o, pc=0%06o\n", mb, pdp1.pc);
+
+ pdp1.b1 &= ~mask;
+ field_interrupt();
+ break;
+ case 051: /* ASC */
+ if (LOG_EXTRA)
+ logerror("ASC instruction: mb=0%06o, pc=0%06o\n", mb, pdp1.pc);
+
+ pdp1.b1 |= mask;
+ field_interrupt();
+ break;
+ case 052: /* ISB */
+ if (LOG_EXTRA)
+ logerror("ISB instruction: mb=0%06o, pc=0%06o\n", mb, pdp1.pc);
+
+ pdp1.b2 |= mask;
+ field_interrupt();
+ break;
+ case 053: /* CAC */
+ if (LOG_EXTRA)
+ logerror("CAC instruction: mb=0%06o, pc=0%06o\n", mb, pdp1.pc);
+
+ pdp1.b1 = 0;
+ field_interrupt();
+ break;
+ default:
+ if (LOG)
+ logerror("Ignoring internal error in file " __FILE__ " line %d.\n", __LINE__);
+
+ break;
+ }
+
+}
+
+
+/*
+ Simulate a pulse on start/clear line:
+ reset most registers and flip-flops, and initialize a few emulator state
+ variables.
+*/
+static void pulse_start_clear(void)
+{
+ /* processor registers */
+ PC = 0; /* according to maintainance manual p. 6-17 */
+ IR = 0; /* according to maintainance manual p. 6-13 */
+ /*MB = 0;*/ /* ??? */
+ /*MA = 0;*/ /* ??? */
+ /*AC = 0;*/ /* ??? */
+ /*IO = 0;*/ /* ??? */
+ /*PF = 0;*/ /* ??? */
+
+ /* processor state flip-flops */
+ pdp1.run = 0; /* ??? */
+ pdp1.cycle = 0; /* mere guess */
+ pdp1.defer = 0; /* mere guess */
+ pdp1.brk_ctr = 0; /* mere guess */
+ pdp1.ov = 0; /* according to maintainance manual p. 7-18 */
+ pdp1.rim = 0; /* ??? */
+ pdp1.sbm = 0; /* ??? */
+ EXD = 0; /* according to maintainance manual p. 8-16 */
+ pdp1.exc = 0; /* according to maintainance manual p. 8-16 */
+ pdp1.ioc = 1; /* according to maintainance manual p. 6-10 */
+ pdp1.ioh = 0; /* according to maintainance manual p. 6-10 */
+ pdp1.ios = 0; /* according to maintainance manual p. 6-10 */
+
+ pdp1.b1 = pdp1.type_20_sbs ? 0 : 1; /* mere guess */
+ pdp1.b2 = 0; /* mere guess */
+ pdp1.b4 = 0; /* mere guess */
+
+
+ pdp1.rim_step = 0;
+ pdp1.sbs_restore = 0; /* mere guess */
+ pdp1.no_sequence_break = 0; /* mere guess */
+
+ field_interrupt();
+
+ /* now, we kindly ask IO devices to reset, too */
+ if (pdp1.io_sc_callback)
+ (*pdp1.io_sc_callback)();
+}
diff --git a/src/emu/cpu/pdp1/pdp1.h b/src/emu/cpu/pdp1/pdp1.h
new file mode 100644
index 00000000000..e4cf7d12afb
--- /dev/null
+++ b/src/emu/cpu/pdp1/pdp1.h
@@ -0,0 +1,81 @@
+#ifndef _PDP1_H
+#define _PDP1_H
+
+#include "cpuintrf.h"
+
+
+/* register ids for pdp1_get_reg/pdp1_set_reg */
+enum
+{
+ PDP1_PC=1, PDP1_IR, PDP1_MB, PDP1_MA, PDP1_AC, PDP1_IO,
+ PDP1_PF, PDP1_PF1, PDP1_PF2, PDP1_PF3, PDP1_PF4, PDP1_PF5, PDP1_PF6,
+ PDP1_TA, PDP1_TW,
+ PDP1_SS, PDP1_SS1, PDP1_SS2, PDP1_SS3, PDP1_SS4, PDP1_SS5, PDP1_SS6,
+ PDP1_SNGL_STEP, PDP1_SNGL_INST, PDP1_EXTEND_SW,
+ PDP1_RUN, PDP1_CYC, PDP1_DEFER, PDP1_BRK_CTR, PDP1_OV, PDP1_RIM, PDP1_SBM, PDP1_EXD,
+ PDP1_IOC, PDP1_IOH, PDP1_IOS,
+ PDP1_START_CLEAR, /* hack, do not use directly, use pdp1_pulse_start_clear instead */
+ PDP1_IO_COMPLETE /* hack, do not use directly, use pdp1_pulse_iot_done instead */
+};
+
+#define pdp1_pulse_start_clear() cpunum_set_reg(0, PDP1_START_CLEAR, 0)
+#define pdp1_pulse_iot_done() cpunum_set_reg(0, PDP1_IO_COMPLETE, 0)
+
+typedef struct pdp1_reset_param_t
+{
+ /* callbacks for iot instructions (required for any I/O) */
+ void (*extern_iot[64])(int op2, int nac, int mb, int *io, int ac);
+ /* read a word from the perforated tape reader (required for read-in mode) */
+ void (*read_binary_word)(void);
+ /* callback called when sc is pulsed: IO devices should reset */
+ void (*io_sc_callback)(void);
+
+ /* 0: no extend support, 1: extend with 15-bit address, 2: extend with 16-bit address */
+ int extend_support;
+ /* 1 to use hardware multiply/divide (MUL, DIV) instead of MUS, DIS */
+ int hw_mul_div;
+ /* 0: standard sequence break system 1: type 20 sequence break system */
+ int type_20_sbs;
+} pdp1_reset_param_t;
+
+#define IOT_NO_COMPLETION_PULSE -1
+
+/* PUBLIC FUNCTIONS */
+void pdp1_get_info(UINT32 state, cpuinfo *info);
+
+#define READ_PDP_18BIT(A) ((signed)program_read_dword_32be((A)<<2))
+#define WRITE_PDP_18BIT(A,V) (program_write_dword_32be((A)<<2,(V)))
+
+#define AND 001
+#define IOR 002
+#define XOR 003
+#define XCT 004
+#define CALJDA 007
+#define LAC 010
+#define LIO 011
+#define DAC 012
+#define DAP 013
+#define DIP 014
+#define DIO 015
+#define DZM 016
+#define ADD 020
+#define SUB 021
+#define IDX 022
+#define ISP 023
+#define SAD 024
+#define SAS 025
+#define MUS_MUL 026
+#define DIS_DIV 027
+#define JMP 030
+#define JSP 031
+#define SKP 032
+#define SFT 033
+#define LAW 034
+#define IOT 035
+#define OPR 037
+
+#ifdef MAME_DEBUG
+unsigned pdp1_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+#endif /* _PDP1_H */
diff --git a/src/emu/cpu/pdp1/pdp1dasm.c b/src/emu/cpu/pdp1/pdp1dasm.c
new file mode 100644
index 00000000000..dc9aa19f16f
--- /dev/null
+++ b/src/emu/cpu/pdp1/pdp1dasm.c
@@ -0,0 +1,293 @@
+#include <stdio.h>
+#include <string.h>
+#include "cpu/pdp1/pdp1.h"
+
+/* PDP1 registers */
+static int ib;
+static int y;
+
+INLINE void ea (void)
+{
+ while (1)
+ {
+ if (ib == 0)
+ return;
+ ib = (READ_PDP_18BIT (y) >> 12) & 1;
+ y = READ_PDP_18BIT (y) & 07777;
+ }
+}
+
+#define IN if (ib) sprintf(buffer+strlen(buffer)," i")
+
+unsigned pdp1_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int md;
+ int etime = 0;
+
+ md = *((UINT32 *) oprom);
+
+ y = md & 07777;
+ ib = (md >> 12) & 1; /* */
+ switch (md >> 13)
+ {
+ case AND:
+ ea ();
+ sprintf (buffer, "AND (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case IOR:
+ ea ();
+ sprintf (buffer, "IOR (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case XOR:
+ ea ();
+ sprintf (buffer, "XOR (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case XCT:
+ ea ();
+ sprintf (buffer, "XCT (0%06o)", y);
+ IN;
+ etime = 5;
+ break;
+ case CALJDA:
+ {
+ if (ib == 1)
+ sprintf (buffer, "JDA 0%06o ", y);
+ if (ib == 0)
+ sprintf (buffer, "CAL ");
+ etime = 10;
+ break;
+ }
+ case LAC:
+ ea ();
+ sprintf (buffer, "LAC (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case LIO:
+ ea ();
+ sprintf (buffer, "LIO (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case DAC:
+ ea ();
+ sprintf (buffer, "DAC 0%06o ", y);
+ IN;
+ etime = 10;
+ break;
+ case DAP:
+ ea ();
+ sprintf (buffer, "DAP 0%06o ", y);
+ IN;
+ etime = 10;
+ break;
+ case DIP:
+ ea ();
+ sprintf (buffer, "DIP 0%06o ", y);
+ IN;
+ etime = 10;
+ break;
+ case DIO:
+ ea ();
+ sprintf (buffer, "DIO 0%06o ", y);
+ IN;
+ etime = 10;
+ break;
+ case DZM:
+ ea ();
+ sprintf (buffer, "DZM 0%06o ", y);
+ IN;
+ etime = 10;
+ break;
+ case ADD:
+ ea ();
+ sprintf (buffer, "ADD (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case SUB:
+ ea ();
+ sprintf (buffer, "SUB (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case IDX:
+ ea ();
+ sprintf (buffer, "IDX (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case ISP:
+ ea ();
+ sprintf (buffer, "ISP (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case SAD:
+ ea ();
+ sprintf (buffer, "SAD (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case SAS:
+ ea ();
+ sprintf (buffer, "SAS (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case MUS_MUL:
+ ea ();
+ sprintf (buffer, "MUS (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case DIS_DIV:
+ ea ();
+ sprintf (buffer, "DIS (0%06o)", y);
+ IN;
+ etime = 10;
+ break;
+ case JMP:
+ ea ();
+ sprintf (buffer, "JMP 0%06o ", y);
+ IN;
+ etime = 5;
+ break;
+ case JSP:
+ ea ();
+ sprintf (buffer, "JSP 0%06o ", y);
+ IN;
+ etime = 5;
+ break;
+ case SKP:
+ {
+ buffer[0] = 0;
+ if ((y & 0100) == 0100)
+ sprintf (buffer, "SZA ");
+ if ((y & 0200) == 0200)
+ sprintf (buffer + strlen (buffer), "SPA ");
+ if ((y & 0400) == 0400)
+ sprintf (buffer + strlen (buffer), "SMA ");
+ if ((y & 01000) == 01000)
+ sprintf (buffer + strlen (buffer), "SZO ");
+ if ((y & 02000) == 02000)
+ sprintf (buffer + strlen (buffer), "SPI ");
+ if (y & 070)
+ sprintf (buffer + strlen (buffer), "SZS 0%01o ", (y & 070));
+ if (y & 7)
+ sprintf (buffer + strlen (buffer), "SZF 0%01o ", (y & 7));
+ IN;
+ etime = 5;
+ break;
+ }
+ case SFT:
+ {
+ int nshift = 0;
+ int mask = md & 0777;
+
+ while (mask != 0)
+ {
+ nshift += mask & 1;
+ mask = mask >> 1;
+ }
+ switch ((md >> 9) & 017)
+ {
+ case 1:
+ sprintf (buffer, "RAL 0%02o", nshift);
+ etime = 5;
+ break;
+ case 2:
+ sprintf (buffer, "RIL 0%02o", nshift);
+ etime = 5;
+ break;
+ case 3:
+ sprintf (buffer, "RCL 0%02o", nshift);
+ etime = 5;
+ break;
+ case 5:
+ sprintf (buffer, "SAL 0%02o", nshift);
+ etime = 5;
+ break;
+ case 6:
+ sprintf (buffer, "SIL 0%02o", nshift);
+ etime = 5;
+ break;
+ case 7:
+ sprintf (buffer, "SCL 0%02o", nshift);
+ etime = 5;
+ break;
+ case 9:
+ sprintf (buffer, "RAR 0%02o", nshift);
+ etime = 5;
+ break;
+ case 10:
+ sprintf (buffer, "RIR 0%02o", nshift);
+ etime = 5;
+ break;
+ case 11:
+ sprintf (buffer, "RCR 0%02o", nshift);
+ etime = 5;
+ break;
+ case 13:
+ sprintf (buffer, "SAR 0%02o", nshift);
+ etime = 5;
+ break;
+ case 14:
+ sprintf (buffer, "SIR 0%02o", nshift);
+ etime = 5;
+ break;
+ case 15:
+ sprintf (buffer, "SCR 0%02o", nshift);
+ etime = 5;
+ break;
+ default:
+ sprintf (buffer, "SKP ???");
+ etime = 5;
+ break;
+ }
+ break;
+ }
+ case LAW:
+ sprintf (buffer, "LAW 0%06o", y);
+ IN;
+ etime = 5;
+ break;
+ case IOT:
+ sprintf (buffer, "IOT 0%06o", md);
+ etime = 10;
+ break;
+ case OPR:
+ {
+ buffer[0] = 0;
+ if ((y & 04000) == 04000)
+ sprintf (buffer + strlen (buffer), "CLI ");
+ if ((y & 02000) == 02000)
+ sprintf (buffer + strlen (buffer), "LAT ");
+ if ((y & 01000) == 01000)
+ sprintf (buffer + strlen (buffer), "CMA ");
+ if ((y & 0400) == 0400)
+ sprintf (buffer + strlen (buffer), "HLT ");
+ if ((y & 0100) == 0100)
+ sprintf (buffer + strlen (buffer), "LAP ");
+ if ((y & 010) && (y & 7))
+ sprintf (buffer + strlen (buffer), "STF 0%01o ", (y & 7));
+ if ((!(y & 010)) && (y & 7))
+ sprintf (buffer + strlen (buffer), "CLF 0%01o ", (y & 7));
+ if (!(y))
+ sprintf (buffer + strlen (buffer), "NOP ");
+ etime = 5;
+ break;
+ }
+ default:
+ sprintf (buffer, "ILLEGAL");
+ etime = 5;
+ break;
+ }
+ return 4;
+}
diff --git a/src/emu/cpu/pdp1/tx0.c b/src/emu/cpu/pdp1/tx0.c
new file mode 100644
index 00000000000..c1ffe8b4688
--- /dev/null
+++ b/src/emu/cpu/pdp1/tx0.c
@@ -0,0 +1,1318 @@
+/*
+ TX-0 emulator
+
+ Two variants:
+ * initial model 64kWord RAM
+ * later model 8kWord RAM
+
+ Raphael Nabet 2004
+*/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "tx0.h"
+
+#define LOG 0
+#define LOG_EXTRA 0
+
+static void execute_instruction_64kw(void);
+static void execute_instruction_8kw(void);
+static void pulse_reset(void);
+
+
+/* TX-0 Registers */
+typedef struct
+{
+ /* processor registers */
+ int mbr; /* memory buffer register (18 bits) */
+ int ac; /* accumulator (18 bits) */
+ int mar; /* memory address register (16 (64kW) or 13 (8kW) bits) */
+ int pc; /* program counter (16 (64kW) or 13 (8kW) bits) */
+ int ir; /* instruction register (2 (64kW) or 5 (8kW) bits) */
+ int lr; /* live register (18 bits) */
+ int xr; /* index register (14 bits) (8kW only) */
+ int pf; /* program flags (6 bits expandable to 10) (8kW only) */
+
+ /* operator panel switches */
+ int tbr; /* toggle switch buffer register (18 bits) */
+ int tac; /* toggle switch accumulator (18 bits) */
+ int tss[16]; /* toggle switch storage (18 bits * 16) */
+ unsigned int cm_sel : 16; /* individual cm select (1 bit * 16) */
+ unsigned int lr_sel : 16; /* individual lr select (1 bit * 16) */
+ unsigned int gbl_cm_sel : 1;/* global cm select (1 bit) */
+ unsigned int stop_cyc0 : 1; /* stop on cycle 0 */
+ unsigned int stop_cyc1 : 1; /* stop on cycle 1 */
+
+ /* processor state flip-flops */
+ unsigned int run : 1; /* processor is running */
+ unsigned int rim : 1; /* processor is in read-in mode */
+ unsigned int cycle : 2; /* 0 -> fetch */
+ /* 1 -> execute (except for taken branches) */
+ /* 2 -> extra execute cycle for SXA and ADO */
+
+ unsigned int ioh : 1; /* i-o halt: processor is executing an Input-Output Transfer wait */
+ unsigned int ios : 1; /* i-o synchronizer: set on i-o operation completion */
+
+ /* additional emulator state variables */
+ int rim_step; /* current step in rim execution */
+
+ int address_mask; /* address mask */
+ int ir_mask; /* IR mask */
+
+ /* 8 standard I/O handlers:
+ 0: cpy (8kW only)
+ 1: r1l
+ 2: dis
+ 3: r3l
+ 4: prt
+ 5: reserved
+ 6: p6h
+ 7: p7h */
+ void (*io_handlers[8])(void);
+ /* select instruction handler */
+ void (*sel_handler)(void);
+ /* called when reset line is pulsed: IO devices should reset */
+ void (*io_reset_callback)(void);
+}
+tx0_Regs;
+
+#define io_handler_rim 3
+
+static tx0_Regs tx0;
+
+#define PC tx0.pc
+#define IR tx0.ir
+#define MBR tx0.mbr
+#define MAR tx0.mar
+#define AC tx0.ac
+#define LR tx0.lr
+#define XR tx0.xr
+#define PF tx0.pf
+
+#define ADDRESS_MASK_64KW 0177777
+#define ADDRESS_MASK_8KW 0017777
+
+#define INCREMENT_PC_64KW (PC = (PC+1) & ADDRESS_MASK_64KW)
+#define INCREMENT_PC_8KW (PC = (PC+1) & ADDRESS_MASK_8KW)
+
+/* public globals */
+static signed int tx0_ICount;
+
+
+static int tx0_read(offs_t address)
+{
+ if ((address >= 16) || (tx0.gbl_cm_sel) || ((tx0.cm_sel >> address) & 1))
+ /* core memory (CM) */
+ return READ_TX0_18BIT(address);
+ else if ((tx0.lr_sel >> address) & 1)
+ /* live register (LR) */
+ return LR;
+ else
+ /* toggle switch storage (TSS) */
+ return tx0.tss[address];
+}
+
+static void tx0_write(offs_t address, int data)
+{
+ if ((address >= 16) || (tx0.gbl_cm_sel) || ((tx0.cm_sel >> address) & 1))
+ /* core memory (CM) */
+ WRITE_TX0_18BIT(address, data);
+ else if ((tx0.lr_sel >> address) & 1)
+ /* live register (LR) */
+ LR = data;
+ else
+ /* toggle switch storage (TSS) */
+ /* TSS is read-only */
+ ;
+}
+
+static void tx0_init_common(int is_64kw, int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int i;
+ tx0_reset_param_t *param = (tx0_reset_param_t *) config;
+
+ /* clean-up */
+ memset (&tx0, 0, sizeof (tx0));
+
+ /* set up params and callbacks */
+ for (i=0; i<8; i++)
+ tx0.io_handlers[i] = (param) ? param->io_handlers[i] : NULL;
+ tx0.sel_handler = (param) ? param->sel_handler : NULL;
+ tx0.io_reset_callback = (param) ? param->io_reset_callback : NULL;
+
+ tx0.address_mask = is_64kw ? ADDRESS_MASK_64KW : ADDRESS_MASK_8KW;
+ tx0.ir_mask = is_64kw ? 03 : 037;
+}
+
+static void tx0_init_64kw(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ tx0_init_common(1, index, clock, config, irqcallback);
+}
+
+static void tx0_init_8kw(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ tx0_init_common(0, index, clock, config, irqcallback);
+}
+
+static void tx0_reset(void)
+{
+ /* reset CPU flip-flops */
+ pulse_reset();
+
+ tx0.gbl_cm_sel = 1; /* HACK */
+}
+
+static void tx0_get_context(void *dst)
+{
+ if (dst)
+ *(tx0_Regs *) dst = tx0;
+}
+
+static void tx0_set_context(void *src)
+{
+ if (src)
+ tx0 = *(tx0_Regs *) src;
+}
+
+
+/* execute instructions on this CPU until icount expires */
+static int tx0_execute_64kw(int cycles)
+{
+ tx0_ICount = cycles;
+
+ do
+ {
+ CALL_MAME_DEBUG;
+
+
+ if (tx0.ioh && tx0.ios)
+ {
+ tx0.ioh = 0;
+ tx0.ios = 0;
+ }
+
+
+ if ((! tx0.run) && (! tx0.rim))
+ tx0_ICount = 0; /* if processor is stopped, just burn cycles */
+ else if (tx0.rim)
+ {
+ switch (tx0.rim_step)
+ {
+ case 0:
+ /* read first word as instruction */
+ AC = 0;
+ if (tx0.io_handlers[io_handler_rim])
+ (*tx0.io_handlers[io_handler_rim])(); /* data will be transferred to AC */
+ tx0.rim_step = 1;
+ break;
+
+ case 1:
+ if (! tx0.ios)
+ { /* transfer incomplete: wait some more */
+ tx0_ICount = 0;
+ }
+ else
+ { /* data transfer complete */
+ tx0.ios = 0;
+
+ MBR = AC;
+ IR = MBR >> 16; /* basic opcode */
+ if ((IR == 2) || (IR == 1)) /* trn or add instruction? */
+ {
+ PC = MBR & ADDRESS_MASK_64KW;
+ tx0.rim = 0; /* exit read-in mode */
+ tx0.run = (IR == 2) ? 1 : 0; /* stop if add instruction */
+ tx0.rim_step = 0;
+ }
+ else if ((IR == 0) || (IR == 3)) /* sto or opr instruction? */
+ {
+ MAR = MBR & ADDRESS_MASK_64KW;
+ tx0.rim_step = 2;
+ }
+ }
+ break;
+
+ case 2:
+ /* read second word as data */
+ AC = 0;
+ if (tx0.io_handlers[io_handler_rim])
+ (*tx0.io_handlers[io_handler_rim])(); /* data will be transferred to AC */
+ tx0.rim_step = 3;
+ break;
+
+ case 3:
+ if (! tx0.ios)
+ { /* transfer incomplete: wait some more */
+ tx0_ICount = 0;
+ }
+ else
+ { /* data transfer complete */
+ tx0.ios = 0;
+
+ tx0_write(MAR, MBR = AC);
+
+ tx0.rim_step = 0;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (tx0.cycle == 0)
+ { /* fetch new instruction */
+ MBR = tx0_read(MAR = PC);
+ INCREMENT_PC_64KW;
+ IR = MBR >> 16; /* basic opcode */
+ MAR = MBR & ADDRESS_MASK_64KW;
+ }
+
+ if (! tx0.ioh)
+ {
+ if ((tx0.stop_cyc0 && (tx0.cycle == 0))
+ || (tx0.stop_cyc1 && (tx0.cycle == 1)))
+ tx0.run = 0;
+
+ execute_instruction_64kw(); /* execute instruction */
+ }
+
+ tx0_ICount --;
+ }
+ }
+ while (tx0_ICount > 0);
+
+ return cycles - tx0_ICount;
+}
+
+/* execute instructions on this CPU until icount expires */
+static int tx0_execute_8kw(int cycles)
+{
+ tx0_ICount = cycles;
+
+ do
+ {
+ CALL_MAME_DEBUG;
+
+
+ if (tx0.ioh && tx0.ios)
+ {
+ tx0.ioh = 0;
+ tx0.ios = 0;
+ }
+
+
+ if ((! tx0.run) && (! tx0.rim))
+ tx0_ICount = 0; /* if processor is stopped, just burn cycles */
+ else if (tx0.rim)
+ {
+ switch (tx0.rim_step)
+ {
+ case 0:
+ /* read first word as instruction */
+ AC = 0;
+ if (tx0.io_handlers[io_handler_rim])
+ (*tx0.io_handlers[io_handler_rim])(); /* data will be transferred to AC */
+ tx0.rim_step = 1;
+ break;
+
+ case 1:
+ if (! tx0.ios)
+ { /* transfer incomplete: wait some more */
+ tx0_ICount = 0;
+ }
+ else
+ { /* data transfer complete */
+ tx0.ios = 0;
+
+ MBR = AC;
+ IR = MBR >> 13; /* basic opcode */
+ if ((IR == 16) || (IR == 8)) /* trn or add instruction? */
+ {
+ PC = MBR & ADDRESS_MASK_8KW;
+ tx0.rim = 0; /* exit read-in mode */
+ tx0.run = (IR == 16) ? 1 : 0; /* stop if add instruction */
+ tx0.rim_step = 0;
+ }
+ else if ((IR == 0) || (IR == 24)) /* sto or opr instruction? */
+ {
+ MAR = MBR & ADDRESS_MASK_8KW;
+ tx0.rim_step = 2;
+ }
+ }
+ break;
+
+ case 2:
+ /* read second word as data */
+ AC = 0;
+ if (tx0.io_handlers[io_handler_rim])
+ (*tx0.io_handlers[io_handler_rim])(); /* data will be transferred to AC */
+ tx0.rim_step = 3;
+ break;
+
+ case 3:
+ if (! tx0.ios)
+ { /* transfer incomplete: wait some more */
+ tx0_ICount = 0;
+ }
+ else
+ { /* data transfer complete */
+ tx0.ios = 0;
+
+ tx0_write(MAR, MBR = AC);
+
+ tx0.rim_step = 0;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (tx0.cycle == 0)
+ { /* fetch new instruction */
+ MBR = tx0_read(MAR = PC);
+ INCREMENT_PC_8KW;
+ IR = MBR >> 13; /* basic opcode */
+ MAR = MBR & ADDRESS_MASK_8KW;
+ }
+
+ if (! tx0.ioh)
+ {
+ if ((tx0.stop_cyc0 && (tx0.cycle == 0))
+ || (tx0.stop_cyc1 && (tx0.cycle == 1)))
+ tx0.run = 0;
+
+ execute_instruction_8kw(); /* execute instruction */
+ }
+
+ tx0_ICount -= 1;
+ }
+ }
+ while (tx0_ICount > 0);
+
+ return cycles - tx0_ICount;
+}
+
+
+static void tx0_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_SP: (void) info->i; /* no SP */ break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TX0_PC: PC = info->i & tx0.address_mask; break;
+ case CPUINFO_INT_REGISTER + TX0_IR: IR = info->i & tx0.ir_mask; /* weird idea */break;
+ case CPUINFO_INT_REGISTER + TX0_MBR: MBR = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + TX0_MAR: MAR = info->i & tx0.address_mask; break;
+ case CPUINFO_INT_REGISTER + TX0_AC: AC = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + TX0_LR: LR = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + TX0_XR: XR = info->i & 0037777; break;
+ case CPUINFO_INT_REGISTER + TX0_PF: PF = info->i & 077; break;
+ case CPUINFO_INT_REGISTER + TX0_TBR: tx0.tbr = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + TX0_TAC: tx0.tac = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + TX0_TSS00:
+ case CPUINFO_INT_REGISTER + TX0_TSS01:
+ case CPUINFO_INT_REGISTER + TX0_TSS02:
+ case CPUINFO_INT_REGISTER + TX0_TSS03:
+ case CPUINFO_INT_REGISTER + TX0_TSS04:
+ case CPUINFO_INT_REGISTER + TX0_TSS05:
+ case CPUINFO_INT_REGISTER + TX0_TSS06:
+ case CPUINFO_INT_REGISTER + TX0_TSS07:
+ case CPUINFO_INT_REGISTER + TX0_TSS10:
+ case CPUINFO_INT_REGISTER + TX0_TSS11:
+ case CPUINFO_INT_REGISTER + TX0_TSS12:
+ case CPUINFO_INT_REGISTER + TX0_TSS13:
+ case CPUINFO_INT_REGISTER + TX0_TSS14:
+ case CPUINFO_INT_REGISTER + TX0_TSS15:
+ case CPUINFO_INT_REGISTER + TX0_TSS16:
+ case CPUINFO_INT_REGISTER + TX0_TSS17: tx0.tss[state-(CPUINFO_INT_REGISTER + TX0_TSS00)] = info->i & 0777777; break;
+ case CPUINFO_INT_REGISTER + TX0_CM_SEL: tx0.cm_sel = info->i & 0177777; break;
+ case CPUINFO_INT_REGISTER + TX0_LR_SEL: tx0.lr_sel = info->i & 0177777; break;
+ case CPUINFO_INT_REGISTER + TX0_GBL_CM_SEL: tx0.gbl_cm_sel = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + TX0_STOP_CYC0: tx0.stop_cyc0 = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + TX0_STOP_CYC1: tx0.stop_cyc1 = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + TX0_RUN: tx0.run = info->i ? 1 : 0; break;
+ case CPUINFO_INT_REGISTER + TX0_RIM: tx0.rim = info->i ? 1 : 0; break;
+#if LOG
+ case CPUINFO_INT_REGISTER + TX0_CYCLE: logerror("tx0_set_reg to cycle counter ignored\n");/* no way!*/ break;
+ case CPUINFO_INT_REGISTER + TX0_IOH: logerror("tx0_set_reg to ioh flip-flop ignored\n");/* no way!*/ break;
+ case CPUINFO_INT_REGISTER + TX0_IOS: logerror("tx0_set_reg to ios flip-flop ignored\n");/* no way!*/ break;
+#endif
+ case CPUINFO_INT_REGISTER + TX0_RESET: pulse_reset(); break;
+ case CPUINFO_INT_REGISTER + TX0_IO_COMPLETE:tx0.ios = 1; break;
+ }
+}
+
+
+void tx0_64kw_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(tx0); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; /*don't care*/ break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 3; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -2; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_SP: info->i = 0; /* no SP */ break;
+ case CPUINFO_INT_PC: info->i = PC; break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* TODO??? */ break;
+
+ case CPUINFO_INT_REGISTER + TX0_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + TX0_IR: info->i = IR; break;
+ case CPUINFO_INT_REGISTER + TX0_MBR: info->i = MBR; break;
+ case CPUINFO_INT_REGISTER + TX0_MAR: info->i = MAR; break;
+ case CPUINFO_INT_REGISTER + TX0_AC: info->i = AC; break;
+ case CPUINFO_INT_REGISTER + TX0_LR: info->i = LR; break;
+ case CPUINFO_INT_REGISTER + TX0_XR: info->i = XR; break;
+ case CPUINFO_INT_REGISTER + TX0_PF: info->i = PF; break;
+ case CPUINFO_INT_REGISTER + TX0_TBR: info->i = tx0.tbr; break;
+ case CPUINFO_INT_REGISTER + TX0_TAC: info->i = tx0.tac; break;
+ case CPUINFO_INT_REGISTER + TX0_TSS00:
+ case CPUINFO_INT_REGISTER + TX0_TSS01:
+ case CPUINFO_INT_REGISTER + TX0_TSS02:
+ case CPUINFO_INT_REGISTER + TX0_TSS03:
+ case CPUINFO_INT_REGISTER + TX0_TSS04:
+ case CPUINFO_INT_REGISTER + TX0_TSS05:
+ case CPUINFO_INT_REGISTER + TX0_TSS06:
+ case CPUINFO_INT_REGISTER + TX0_TSS07:
+ case CPUINFO_INT_REGISTER + TX0_TSS10:
+ case CPUINFO_INT_REGISTER + TX0_TSS11:
+ case CPUINFO_INT_REGISTER + TX0_TSS12:
+ case CPUINFO_INT_REGISTER + TX0_TSS13:
+ case CPUINFO_INT_REGISTER + TX0_TSS14:
+ case CPUINFO_INT_REGISTER + TX0_TSS15:
+ case CPUINFO_INT_REGISTER + TX0_TSS16:
+ case CPUINFO_INT_REGISTER + TX0_TSS17: info->i = tx0.tss[state-(CPUINFO_INT_REGISTER + TX0_TSS00)]; break;
+ case CPUINFO_INT_REGISTER + TX0_CM_SEL: info->i = tx0.cm_sel; break;
+ case CPUINFO_INT_REGISTER + TX0_LR_SEL: info->i = tx0.lr_sel; break;
+ case CPUINFO_INT_REGISTER + TX0_GBL_CM_SEL: info->i = tx0.gbl_cm_sel; break;
+ case CPUINFO_INT_REGISTER + TX0_STOP_CYC0: info->i = tx0.stop_cyc0; break;
+ case CPUINFO_INT_REGISTER + TX0_STOP_CYC1: info->i = tx0.stop_cyc1; break;
+ case CPUINFO_INT_REGISTER + TX0_RUN: info->i = tx0.run; break;
+ case CPUINFO_INT_REGISTER + TX0_RIM: info->i = tx0.rim; break;
+ case CPUINFO_INT_REGISTER + TX0_CYCLE: info->i = tx0.cycle; break;
+ case CPUINFO_INT_REGISTER + TX0_IOH: info->i = tx0.ioh; break;
+ case CPUINFO_INT_REGISTER + TX0_IOS: info->i = tx0.ios; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = tx0_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tx0_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tx0_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = tx0_init_64kw; break;
+ case CPUINFO_PTR_RESET: info->reset = tx0_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = tx0_execute_64kw; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tx0_dasm_64kw; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &tx0_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "TX-0"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "TX-0"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "Raphael Nabet"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s = cpuintrf_temp_str(), ""); break;
+
+ case CPUINFO_STR_REGISTER + TX0_PC: sprintf(info->s = cpuintrf_temp_str(), "PC:0%06o", PC); break;
+ case CPUINFO_STR_REGISTER + TX0_IR: sprintf(info->s = cpuintrf_temp_str(), "IR:0%02o", IR); break;
+ case CPUINFO_STR_REGISTER + TX0_MBR: sprintf(info->s = cpuintrf_temp_str(), "MBR:0%06o", MBR); break;
+ case CPUINFO_STR_REGISTER + TX0_MAR: sprintf(info->s = cpuintrf_temp_str(), "MAR:0%06o", MAR); break;
+ case CPUINFO_STR_REGISTER + TX0_AC: sprintf(info->s = cpuintrf_temp_str(), "AC:0%06o", AC); break;
+ case CPUINFO_STR_REGISTER + TX0_LR: sprintf(info->s = cpuintrf_temp_str(), "LR:0%06o", LR); break;
+ case CPUINFO_STR_REGISTER + TX0_XR: sprintf(info->s = cpuintrf_temp_str(), "XR:0%05o", XR); break;
+ case CPUINFO_STR_REGISTER + TX0_PF: sprintf(info->s = cpuintrf_temp_str(), "PF:0%02o", PF); break; break;
+ case CPUINFO_STR_REGISTER + TX0_TBR: sprintf(info->s = cpuintrf_temp_str(), "TBR:0%06o", tx0.tbr); break;
+ case CPUINFO_STR_REGISTER + TX0_TAC: sprintf(info->s = cpuintrf_temp_str(), "TAC:0%06o", tx0.tac); break;
+ case CPUINFO_STR_REGISTER + TX0_TSS00:
+ case CPUINFO_STR_REGISTER + TX0_TSS01:
+ case CPUINFO_STR_REGISTER + TX0_TSS02:
+ case CPUINFO_STR_REGISTER + TX0_TSS03:
+ case CPUINFO_STR_REGISTER + TX0_TSS04:
+ case CPUINFO_STR_REGISTER + TX0_TSS05:
+ case CPUINFO_STR_REGISTER + TX0_TSS06:
+ case CPUINFO_STR_REGISTER + TX0_TSS07:
+ case CPUINFO_STR_REGISTER + TX0_TSS10:
+ case CPUINFO_STR_REGISTER + TX0_TSS11:
+ case CPUINFO_STR_REGISTER + TX0_TSS12:
+ case CPUINFO_STR_REGISTER + TX0_TSS13:
+ case CPUINFO_STR_REGISTER + TX0_TSS14:
+ case CPUINFO_STR_REGISTER + TX0_TSS15:
+ case CPUINFO_STR_REGISTER + TX0_TSS16:
+ case CPUINFO_STR_REGISTER + TX0_TSS17: sprintf(info->s = cpuintrf_temp_str(), "TSS%02o:0%06o", state-(CPUINFO_STR_REGISTER + TX0_TSS00), tx0.tss[state-(CPUINFO_STR_REGISTER + TX0_TSS00)]); break;
+ case CPUINFO_STR_REGISTER + TX0_CM_SEL: sprintf(info->s = cpuintrf_temp_str(), "CMSEL:0%06o", tx0.cm_sel); break;
+ case CPUINFO_STR_REGISTER + TX0_LR_SEL: sprintf(info->s = cpuintrf_temp_str(), "LRSEL:0%06o", tx0.lr_sel); break;
+ case CPUINFO_STR_REGISTER + TX0_GBL_CM_SEL: sprintf(info->s = cpuintrf_temp_str(), "GBLCMSEL:%X", tx0.gbl_cm_sel); break;
+ case CPUINFO_STR_REGISTER + TX0_STOP_CYC0: sprintf(info->s = cpuintrf_temp_str(), "STOPCYC0:%X", tx0.stop_cyc0); break;
+ case CPUINFO_STR_REGISTER + TX0_STOP_CYC1: sprintf(info->s = cpuintrf_temp_str(), "STOPCYC1:%X", tx0.stop_cyc1); break;
+ case CPUINFO_STR_REGISTER + TX0_RUN: sprintf(info->s = cpuintrf_temp_str(), "RUN:%X", tx0.run); break;
+ case CPUINFO_STR_REGISTER + TX0_RIM: sprintf(info->s = cpuintrf_temp_str(), "RIM:%X", tx0.rim); break;
+ case CPUINFO_STR_REGISTER + TX0_CYCLE: sprintf(info->s = cpuintrf_temp_str(), "CYCLE:%X", tx0.cycle); break;
+ case CPUINFO_STR_REGISTER + TX0_IOH: sprintf(info->s = cpuintrf_temp_str(), "IOH:%X", tx0.ioh); break;
+ case CPUINFO_STR_REGISTER + TX0_IOS: sprintf(info->s = cpuintrf_temp_str(), "IOS:%X", tx0.ios); break;
+ }
+}
+
+void tx0_8kw_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(tx0); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; /*don't care*/ break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 3; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 13; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -2; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_SP: info->i = 0; /* no SP */ break;
+ case CPUINFO_INT_PC: info->i = PC; break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* TODO??? */ break;
+
+ case CPUINFO_INT_REGISTER + TX0_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + TX0_IR: info->i = IR; break;
+ case CPUINFO_INT_REGISTER + TX0_MBR: info->i = MBR; break;
+ case CPUINFO_INT_REGISTER + TX0_MAR: info->i = MAR; break;
+ case CPUINFO_INT_REGISTER + TX0_AC: info->i = AC; break;
+ case CPUINFO_INT_REGISTER + TX0_LR: info->i = LR; break;
+ case CPUINFO_INT_REGISTER + TX0_XR: info->i = XR; break;
+ case CPUINFO_INT_REGISTER + TX0_PF: info->i = PF; break;
+ case CPUINFO_INT_REGISTER + TX0_TBR: info->i = tx0.tbr; break;
+ case CPUINFO_INT_REGISTER + TX0_TAC: info->i = tx0.tac; break;
+ case CPUINFO_INT_REGISTER + TX0_TSS00:
+ case CPUINFO_INT_REGISTER + TX0_TSS01:
+ case CPUINFO_INT_REGISTER + TX0_TSS02:
+ case CPUINFO_INT_REGISTER + TX0_TSS03:
+ case CPUINFO_INT_REGISTER + TX0_TSS04:
+ case CPUINFO_INT_REGISTER + TX0_TSS05:
+ case CPUINFO_INT_REGISTER + TX0_TSS06:
+ case CPUINFO_INT_REGISTER + TX0_TSS07:
+ case CPUINFO_INT_REGISTER + TX0_TSS10:
+ case CPUINFO_INT_REGISTER + TX0_TSS11:
+ case CPUINFO_INT_REGISTER + TX0_TSS12:
+ case CPUINFO_INT_REGISTER + TX0_TSS13:
+ case CPUINFO_INT_REGISTER + TX0_TSS14:
+ case CPUINFO_INT_REGISTER + TX0_TSS15:
+ case CPUINFO_INT_REGISTER + TX0_TSS16:
+ case CPUINFO_INT_REGISTER + TX0_TSS17: info->i = tx0.tss[state-(CPUINFO_INT_REGISTER + TX0_TSS00)]; break;
+ case CPUINFO_INT_REGISTER + TX0_CM_SEL: info->i = tx0.cm_sel; break;
+ case CPUINFO_INT_REGISTER + TX0_LR_SEL: info->i = tx0.lr_sel; break;
+ case CPUINFO_INT_REGISTER + TX0_GBL_CM_SEL: info->i = tx0.gbl_cm_sel; break;
+ case CPUINFO_INT_REGISTER + TX0_STOP_CYC0: info->i = tx0.stop_cyc0; break;
+ case CPUINFO_INT_REGISTER + TX0_STOP_CYC1: info->i = tx0.stop_cyc1; break;
+ case CPUINFO_INT_REGISTER + TX0_RUN: info->i = tx0.run; break;
+ case CPUINFO_INT_REGISTER + TX0_RIM: info->i = tx0.rim; break;
+ case CPUINFO_INT_REGISTER + TX0_CYCLE: info->i = tx0.cycle; break;
+ case CPUINFO_INT_REGISTER + TX0_IOH: info->i = tx0.ioh; break;
+ case CPUINFO_INT_REGISTER + TX0_IOS: info->i = tx0.ios; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = tx0_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tx0_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tx0_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = tx0_init_8kw; break;
+ case CPUINFO_PTR_RESET: info->reset = tx0_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = tx0_execute_8kw; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tx0_dasm_8kw; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &tx0_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "TX-0"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "TX-0"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "Raphael Nabet"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s = cpuintrf_temp_str(), ""); break;
+
+ case CPUINFO_STR_REGISTER + TX0_PC: sprintf(info->s = cpuintrf_temp_str(), "PC:0%06o", PC); break;
+ case CPUINFO_STR_REGISTER + TX0_IR: sprintf(info->s = cpuintrf_temp_str(), "IR:0%02o", IR); break;
+ case CPUINFO_STR_REGISTER + TX0_MBR: sprintf(info->s = cpuintrf_temp_str(), "MBR:0%06o", MBR); break;
+ case CPUINFO_STR_REGISTER + TX0_MAR: sprintf(info->s = cpuintrf_temp_str(), "MAR:0%06o", MAR); break;
+ case CPUINFO_STR_REGISTER + TX0_AC: sprintf(info->s = cpuintrf_temp_str(), "AC:0%06o", AC); break;
+ case CPUINFO_STR_REGISTER + TX0_LR: sprintf(info->s = cpuintrf_temp_str(), "LR:0%06o", LR); break;
+ case CPUINFO_STR_REGISTER + TX0_XR: sprintf(info->s = cpuintrf_temp_str(), "XR:0%05o", XR); break;
+ case CPUINFO_STR_REGISTER + TX0_PF: sprintf(info->s = cpuintrf_temp_str(), "PF:0%02o", PF); break; break;
+ case CPUINFO_STR_REGISTER + TX0_TBR: sprintf(info->s = cpuintrf_temp_str(), "TBR:0%06o", tx0.tbr); break;
+ case CPUINFO_STR_REGISTER + TX0_TAC: sprintf(info->s = cpuintrf_temp_str(), "TAC:0%06o", tx0.tac); break;
+ case CPUINFO_STR_REGISTER + TX0_TSS00:
+ case CPUINFO_STR_REGISTER + TX0_TSS01:
+ case CPUINFO_STR_REGISTER + TX0_TSS02:
+ case CPUINFO_STR_REGISTER + TX0_TSS03:
+ case CPUINFO_STR_REGISTER + TX0_TSS04:
+ case CPUINFO_STR_REGISTER + TX0_TSS05:
+ case CPUINFO_STR_REGISTER + TX0_TSS06:
+ case CPUINFO_STR_REGISTER + TX0_TSS07:
+ case CPUINFO_STR_REGISTER + TX0_TSS10:
+ case CPUINFO_STR_REGISTER + TX0_TSS11:
+ case CPUINFO_STR_REGISTER + TX0_TSS12:
+ case CPUINFO_STR_REGISTER + TX0_TSS13:
+ case CPUINFO_STR_REGISTER + TX0_TSS14:
+ case CPUINFO_STR_REGISTER + TX0_TSS15:
+ case CPUINFO_STR_REGISTER + TX0_TSS16:
+ case CPUINFO_STR_REGISTER + TX0_TSS17: sprintf(info->s = cpuintrf_temp_str(), "TSS%02o:0%06o", state-(CPUINFO_STR_REGISTER + TX0_TSS00), tx0.tss[state-(CPUINFO_STR_REGISTER + TX0_TSS00)]); break;
+ case CPUINFO_STR_REGISTER + TX0_CM_SEL: sprintf(info->s = cpuintrf_temp_str(), "CMSEL:0%06o", tx0.cm_sel); break;
+ case CPUINFO_STR_REGISTER + TX0_LR_SEL: sprintf(info->s = cpuintrf_temp_str(), "LRSEL:0%06o", tx0.lr_sel); break;
+ case CPUINFO_STR_REGISTER + TX0_GBL_CM_SEL: sprintf(info->s = cpuintrf_temp_str(), "GBLCMSEL:%X", tx0.gbl_cm_sel); break;
+ case CPUINFO_STR_REGISTER + TX0_STOP_CYC0: sprintf(info->s = cpuintrf_temp_str(), "STOPCYC0:%X", tx0.stop_cyc0); break;
+ case CPUINFO_STR_REGISTER + TX0_STOP_CYC1: sprintf(info->s = cpuintrf_temp_str(), "STOPCYC1:%X", tx0.stop_cyc1); break;
+ case CPUINFO_STR_REGISTER + TX0_RUN: sprintf(info->s = cpuintrf_temp_str(), "RUN:%X", tx0.run); break;
+ case CPUINFO_STR_REGISTER + TX0_RIM: sprintf(info->s = cpuintrf_temp_str(), "RIM:%X", tx0.rim); break;
+ case CPUINFO_STR_REGISTER + TX0_CYCLE: sprintf(info->s = cpuintrf_temp_str(), "CYCLE:%X", tx0.cycle); break;
+ case CPUINFO_STR_REGISTER + TX0_IOH: sprintf(info->s = cpuintrf_temp_str(), "IOH:%X", tx0.ioh); break;
+ case CPUINFO_STR_REGISTER + TX0_IOS: sprintf(info->s = cpuintrf_temp_str(), "IOS:%X", tx0.ios); break;
+ }
+}
+
+
+/* execute one instruction */
+static void execute_instruction_64kw(void)
+{
+ if (! tx0.cycle)
+ {
+ tx0.cycle = 1; /* most frequent case */
+ switch (IR)
+ {
+ case 0: /* STOre */
+ case 1: /* ADD */
+ break;
+
+ case 2: /* TRansfer on Negative */
+ if (AC & 0400000)
+ {
+ PC = MAR & ADDRESS_MASK_64KW;
+ tx0.cycle = 0; /* instruction only takes one cycle if branch
+ is taken */
+ }
+ break;
+
+ case 3: /* OPeRate */
+ if (MAR & 0100000)
+ /* (0.8) CLL = Clear the left nine digital positions of the AC */
+ AC &= 0000777;
+
+ if (MAR & 0040000)
+ /* (0.8) CLR = Clear the right nine digital positions of the AC */
+ AC &= 0777000;
+
+ if (((MAR & 0030000) >> 12) == 1)
+ /* (0.8) IOS In-Out Stop = Stop machine so that an In-Out command
+ (specified by digits 6 7 8 of MAR) may be executed */
+ tx0.ioh = 1;
+
+ if (((MAR & 0007000) >> 9) != 0)
+ {
+ /* ((MAR & 0007000) >> 9) is device ID */
+ /* 7: */
+ /* (0.8) P7H = Punch holes 1-6 in flexo tape specified by AC
+ digital positions 2, 5, 8, 11, 14, and 17. Also punches a 7th
+ hole on tape. */
+ /* 6: */
+ /* (0.8) P6H = Same as P7H but no seventh hole */
+ /* 4: */
+ /* (0.8) PNT = Print one flexowriter character specified by AC
+ digits 2, 5, 8, 11, 14, and 17. */
+ /* 1: */
+ /* (0.8) R1C = Read one line of flexo tape so that tape positions
+ 1, 2, 3, 4, 5, and 6 will be put in the AC digital positions 0,
+ 3, 6, 9, 12 and 15. */
+ /* 3: */
+ /* (0.8) R3C = Read one line of flexo tape into AC digits 0, 3, 6,
+ 9, 12 and 15. Then cycle the AC one digital position; read the
+ next line on tape into AC digits 0, 3, 6, 9, 12 and 15, cycle
+ the AC right one digital position and read the third and last
+ line into AC digits 0, 3, 6, 9, 12 and 15. (This command is
+ equal to a triple CYR-R1C.) */
+ /* 2: */
+ /* (0.8) DIS = Intensify a point on the scope with x and y
+ coordinates where x is specified by AC digits 0-8 with digit 0
+ being used as the sign and y is specified by AC digits 9-17
+ with digit 9 being used as the sign for y. The complement
+ system is in effect when the signs are negative. */
+ /* (5 is undefined) */
+ int index = (MAR & 0007000) >> 9;
+
+ if (tx0.io_handlers[index])
+ (*tx0.io_handlers[index])();
+ tx0.ioh = 1;
+ }
+ break;
+ }
+ }
+ else
+ {
+ tx0.cycle = 0; /* always true */
+ switch (IR)
+ {
+ case 0: /* STOre */
+ tx0_write(MAR, (MBR = AC));
+ break;
+
+ case 1: /* ADD */
+ MBR = tx0_read(MAR);
+
+ AC = AC + MBR;
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+ break;
+
+ case 2: /* TRansfer on Negative */
+ break;
+
+ case 3: /* OPeRate */
+ if ((MAR & 0000104) == 0000100)
+ /* (1.1) PEN = Read the light pen flip-flops 1 and 2 into AC(0) and
+ AC(1). */
+ /*...*/;
+
+ if ((MAR & 0000104) == 0000004)
+ /* (1.1) TAC = Insert a one in each digital position of the AC
+ wherever there is a one in the corresponding digital position
+ of the TAC. */
+ /*...*/;
+
+ if (MAR & 0000040)
+ /* (1.2) COM = Complement every digit in the accumulator */
+ AC ^= 0777777;
+
+ if ((MAR & 0000003) == 1)
+ /* (1.2) AMB = Store the contents of the AC in the MBR. */
+ MBR = AC;
+
+ if ((MAR & 0000003) == 3)
+ /* (1.2) TBR = Store the contents of the TBR in the MBR. */
+ /*...*/;
+
+ if ((MAR & 0000003) == 2)
+ /* (1.3) LMB = Store the contents of the LR in the MBR. */
+ MBR = LR;
+ break;
+
+ if (((MAR & 0000600) >> 7) == 1)
+ /* (1.3) MLR = Store the contents of the MBR (memory buffer
+ register) in the live reg. */
+ LR = MBR;
+
+ if (((MAR & 0000600) >> 7) == 2)
+ /* (1.4) SHR = Shift the AC right one place, i.e. multiply the AC
+ by 2^-1 */
+ AC >>= 1;
+
+ if (((MAR & 0000600) >> 7) == 3)
+ /* (1.4) CYR = Cycle the AC right one digital position (AC(17) will
+ become AC(0)) */
+ AC = (AC >> 1) | ((AC & 1) << 17);
+
+ if (MAR & 0000020)
+ /* (1.4) PAD = Partial add AC to MBR, that is, for every digital
+ position of the MBR that contains a one, complement the digit
+ in the corresponding digital position of the AC. This is also
+ called a half add. */
+ AC ^= MBR;
+
+ if (MAR & 0000010)
+ { /* (1.7) CRY = Partial add the 18 digits of the AC to the
+ corresponding 18 digits of the carry.
+
+ To determine what the 18 digits of the carry are, use the
+ following rule:
+
+ "Grouping the AC and MBR digits into pairs and proceeding from
+ right to left, assign the carry digit of the next pair to a one
+ if in the present pair MBR = 1 and AC = 0 or if in the present
+ pair AC = 1 and carry 1.
+
+ (Note: the 0th digit pair determines the 17th pair's carry
+ digit)" */
+ AC ^= MBR;
+
+ AC = AC + MBR;
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+ }
+
+ if (((MAR & 0030000) >> 12) == 3)
+ /* (1.8) Hlt = Halt the computer */
+ tx0.run = 0;
+
+ break;
+ }
+ }
+}
+
+static void indexed_address_eval(void)
+{
+ MAR = MAR + XR;
+ MAR = (MAR + (MAR >> 14)) & 0037777; /* propagate carry around */
+ //if (MAR == 0037777) /* check for -0 */
+ // MAR = 0;
+ if (MAR & 0020000) /* fix negative (right???) */
+ MAR = (MAR + 1) & 0017777;
+}
+
+/* execute one instruction */
+static void execute_instruction_8kw(void)
+{
+ if (! tx0.cycle)
+ {
+ tx0.cycle = 1; /* most frequent case */
+ switch (IR)
+ {
+ case 0: /* STOre */
+ case 1: /* STore indeXed */
+ case 2: /* Store indeX in Address */
+ case 3: /* ADd One */
+ case 4: /* Store LR */
+ case 5: /* Store Lr indeXed */
+ case 6: /* STore Zero */
+ case 8: /* ADD */
+ case 9: /* ADd indeXed */
+ case 10: /* LoaD indeX */
+ case 11: /* AUgment indeX */
+ case 12: /* Load LR */
+ case 13: /* Load Lr indeXed */
+ case 14: /* LoaD Ac */
+ case 15: /* Load Ac indeXed */
+ break;
+
+ case 16: /* TRansfer on Negative */
+ if (AC & 0400000)
+ {
+ PC = MAR & 0017777;
+ tx0.cycle = 0; /* instruction only takes one cycle if branch
+ is taken */
+ }
+ break;
+
+ case 17: /* Transfer on ZEro */
+ if ((AC == 0000000) || (AC == 0777777))
+ {
+ PC = MAR & 0017777;
+ tx0.cycle = 0; /* instruction only takes one cycle if branch
+ is taken */
+ }
+ break;
+
+ case 18: /* Transfer and Set indeX */
+ XR = PC;
+ PC = MAR & 0017777;
+ tx0.cycle = 0; /* instruction only takes one cycle if branch
+ is taken */
+ break;
+
+ case 19: /* Transfer and IndeX */
+ if ((XR != 0000000) && (XR != 0037777))
+ {
+ if (XR & 0020000)
+ XR ++;
+ else
+ XR--;
+ PC = MAR & 0017777;
+ tx0.cycle = 0; /* instruction only takes one cycle if branch
+ is taken */
+ }
+ break;
+
+ case 21: /* TRansfer indeXed */
+ indexed_address_eval();
+ case 20: /* TRAnsfer */
+ PC = MAR & 0017777;
+ tx0.cycle = 0; /* instruction only takes one cycle if branch
+ is taken */
+ break;
+
+ case 22: /* Transfer on external LeVel */
+ /*if (...)
+ {
+ PC = MAR & 0017777;
+ tx0.cycle = 0;*/ /* instruction only takes one cycle if branch
+ is taken */
+ /*}*/
+ break;
+
+ case 24: /* OPeRate */
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ if (((IR & 001) == 00) && ((MAR & 017000) == 004000))
+ { /* Select class instruction */
+ if (IR & 004)
+ /* (0.8???) CLA = CLear Ac */
+ AC = 0;
+
+ /* (IOS???) SEL = SELect */
+ if (tx0.sel_handler)
+ (*tx0.sel_handler)();
+ }
+ else
+ { /* Normal operate class instruction */
+ if (((IR & 001) == 01) && ((MAR & 017000) == 011000))
+ /* (0.6) CLL = CLear Left 9 bits of ac */
+ AC &= 0000777;
+
+ if (((IR & 001) == 01) && ((MAR & 017000) == 012000))
+ /* (0.6) CLR = CLear Right 9 bits of ac */
+ AC &= 0777000;
+
+ if (IR & 002)
+ /* (0.7) AMB = transfer Ac to MBr */
+ MBR = AC;
+
+ if (IR & 004)
+ /* (0.8) CLA = CLear Ac */
+ AC = 0;
+
+ if (((IR & 001) == 01) && ((MAR & 010000) == 000000))
+ { /* (IOS) In-Out group commands */
+ /* ((MAR & 0007000) >> 9) is device ID */
+ /* 0: */
+ /* (***) CPY = CoPY synchronizes transmission of information
+ between in-out equipment and computer. */
+ /* 1: */
+ /* (IOS) R1L = Read 1 Line of tape from PETR into AC bits 0, 3,
+ 6, 9, 12, 15, with CYR before read (inclusive or) */
+ /* 3: */
+ /* (IOS) R3L = Read 3 Lines of tape from PETR into AC bits 0,
+ 3, 6, 9, 12, 15, with CYR before each read (inclusive or) */
+ /* 2: */
+ /* (IOS) DIS = DISplay a point on scope (AC bits 0-8 specify x
+ coordinate, AC bits 9-17 specify y coordinate). The
+ coordinate (0, 0) is usually at the lower left hand corner
+ of the scope. A console switch is available to relocate
+ (0,0) to the center. */
+ /* 6: */
+ /* (IOS) P6H = Punch one 6-bit line of flexo tape (without 7th
+ hole) from ac bits 2, 5, 8, 11, 14, 17. Note: lines
+ without 7th hole are ignored by PETR. */
+ /* 7: */
+ /* (IOS) P7H = same as P6H, but with 7th hole */
+ /* 4: */
+ /* (IOS) PRT = Print one six bit flexo character from AC bits
+ 2, 5, 8, 11, 14, 17. */
+ /* (5 is undefined) */
+ int index = (MAR & 0007000) >> 9;
+
+ if (tx0.io_handlers[index])
+ (*tx0.io_handlers[index])();
+ tx0.ioh = 1;
+ }
+
+ if (((IR & 001) == 00) && ((MAR & 010000) == 010000))
+ { /* (IOS) EX0 through EX7 = operate user's EXternal equipment. */
+ switch ((MAR & 0007000) >> 9)
+ {
+ /* ... */
+ }
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (((IR != 2) && (IR != 3)) || (tx0.cycle == 2))
+ tx0.cycle = 0;
+ else
+ tx0.cycle = 2; /* SXA and ADO have an extra cycle 2 */
+ switch (IR)
+ {
+ case 1: /* STore indeXed */
+ indexed_address_eval();
+ case 0: /* STOre */
+ tx0_write(MAR, (MBR = AC));
+ break;
+
+ case 2: /* Store indeX in Address */
+ if (tx0.cycle)
+ { /* cycle 1 */
+ MBR = tx0_read(MAR);
+ MBR = (MBR & 0760000) | (XR & 0017777);
+ }
+ else
+ { /* cycle 2 */
+ tx0_write(MAR, MBR);
+ }
+ break;
+
+ case 3: /* ADd One */
+ if (tx0.cycle)
+ { /* cycle 1 */
+ AC = tx0_read(MAR) + 1;
+
+ #if 0
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+ if (AC == 0777777) /* check for -0 (right???) */
+ AC = 0;
+ #else
+ if (AC >= 0777777)
+ AC = (AC + 1) & 0777777;
+ #endif
+ }
+ else
+ { /* cycle 2 */
+ tx0_write(MAR, (MBR = AC));
+ }
+ break;
+
+ case 5: /* Store Lr indeXed */
+ indexed_address_eval();
+ case 4: /* Store LR */
+ tx0_write(MAR, (MBR = LR));
+ break;
+
+ case 6: /* STore Zero */
+ tx0_write(MAR, (MBR = 0));
+ break;
+
+ case 9: /* ADd indeXed */
+ indexed_address_eval();
+ case 8: /* ADD */
+ MBR = tx0_read(MAR);
+
+ AC = AC + MBR;
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+ break;
+
+ case 10: /* LoaD indeX */
+ MBR = tx0_read(MAR);
+ XR = (MBR & 0017777) | ((MBR >> 4) & 0020000);
+ break;
+
+ case 11: /* AUgment indeX */
+ MBR = tx0_read(MAR);
+
+ XR = XR + ((MBR & 0017777) | ((MBR >> 4) & 0020000));
+ XR = (XR + (XR >> 14)) & 0037777; /* propagate carry around */
+
+ //if (XR == 0037777) /* check for -0 */
+ // XR = 0;
+ break;
+
+ case 13: /* Load Lr indeXed */
+ indexed_address_eval();
+ case 12: /* Load LR */
+ LR = MBR = tx0_read(MAR);
+ break;
+
+ case 15: /* Load Ac indeXed */
+ indexed_address_eval();
+ case 14: /* LoaD Ac */
+ AC = MBR = tx0_read(MAR);
+ break;
+
+ case 16: /* TRansfer on Negative */
+ case 17: /* Transfer on ZEro */
+ case 18: /* Transfer and Set indeX */
+ case 19: /* Transfer and IndeX */
+ case 20: /* TRAnsfer */
+ case 21: /* TRansfer indeXed */
+ case 22: /* Transfer on external LeVel */
+ break;
+
+ case 24: /* OPeRate */
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ if (((IR & 001) == 00) && ((MAR & 017000) == 004000))
+ { /* Select class instruction */
+ }
+ else
+ { /* Normal operate class instruction */
+ if (((IR & 001) == 00) && ((MAR & 017000) == 003000))
+ { /* (1.1) PEN = set ac bit 0 from light PEN ff, and ac bit 1 from
+ light gun ff. (ffs contain one if pen or gun saw displayed
+ point.) Then clear both light pen and light gun ffs */
+ /*AC = (AC & 0177777) |?...;*/
+ /*... = 0;*/
+ }
+
+ if (((IR & 001) == 00) && ((MAR & 017000) == 001000))
+ /* (1.1) TAC = transfer TAC into ac (inclusive or) */
+ AC |= tx0.tac;
+
+ if (((IR & 001) == 00) && ((MAR & 017000) == 002000))
+ /* (1.2) TBR = transfer TBR into mbr (inclusive or) */
+ MBR |= tx0.tbr;
+
+ if (((IR & 001) == 00) && ((MAR & 017000) == 006000))
+ /* (1.2) RPF = Read Program Flag register into mbr (inclusive or) */
+ MBR |= PF << 8;
+
+ if (MAR & 0000040)
+ /* (1.2) COM = COMplement ac */
+ AC ^= 0777777;
+
+ if ((! (MAR & 0000400)) && (MAR & 0000100))
+ { /* (1.2) XMB = Transfer XR contents to MBR */
+ MBR = XR;
+ if (XR & 0020000)
+ MBR |= 0740000;
+ }
+
+ if (MAR & 0000004)
+ {
+ switch (MAR & 0000003)
+ {
+ case 0000003: /* (1.2) And LR and MBR */
+ MBR &= LR;
+ break;
+
+ case 0000001: /* (1.3) Or LR into MBR */
+ MBR |= LR;
+ break;
+
+ default:
+ if (LOG)
+ logerror("unrecognized instruction");
+ break;
+ }
+ }
+
+ if (((! (MAR & 0000400)) && (MAR & 0000200)) && ((! (MAR & 0000004)) && (MAR & 0000002)))
+ { /* LMB and MBL used simultaneously interchange LR and MBR */
+ int tmp = MBR;
+ MBR = LR;
+ LR = tmp;
+ }
+ else if ((! (MAR & 0000400)) && (MAR & 0000200))
+ /* (1.4) MBL = Transfer MBR contents to LR */
+ LR = MBR;
+ else if ((! (MAR & 0000004)) && (MAR & 0000002))
+ /* (1.4) LMB = Store the contents of the LR in the MBR. */
+ MBR = LR;
+
+ if (MAR & 0000020)
+ /* (1.5) PAD = Partial ADd mbr to ac */
+ AC ^= MBR;
+
+ if (MAR & 0000400)
+ {
+ switch (MAR & 0000300)
+ {
+ case 0000000: /* (1.6) CYR = CYcle ac contents Right one binary
+ position (AC(17) -> AC(0)) */
+ AC = (AC >> 1) | ((AC & 1) << 17);
+ break;
+
+ case 0000200: /* (1.6) CYcle ac contents Right one binary
+ position (AC(0) unchanged) */
+ AC = (AC >> 1) | (AC & 0400000);
+ break;
+
+ default:
+ if (LOG)
+ logerror("unrecognized instruction");
+ break;
+ }
+ }
+
+ if (((IR & 001) == 00) && ((MAR & 017000) == 007000))
+ /* (1.6) SPF = Set Program Flag register from mbr */
+ PF = (MBR >> 8) & 077;
+
+ if (MAR & 0000010)
+ { /* (1.7?) CRY = Partial ADd the 18 digits of the AC to the
+ corresponding 18 digits of the carry. */
+ AC ^= MBR;
+
+ AC = AC + MBR;
+ AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */
+
+ if (AC == 0777777) /* check for -0 */
+ AC = 0;
+ }
+
+ if ((! (MAR & 0000004)) && (MAR & 0000001))
+ /* (1.8) MBX = Transfer MBR contents to XR */
+ XR = (MBR & 0017777) | ((MBR >> 4) & 0020000);
+
+ if (((IR & 001) == 01) && ((MAR & 017000) == 010000))
+ /* (1.8) HLT = HaLT the computer and sound chime */
+ tx0.run = 0;
+ }
+ break;
+
+ default: /* Illegal */
+ /* ... */
+ break;
+ }
+ }
+}
+
+/*
+ Simulate a pulse on reset line:
+ reset most registers and flip-flops, and initialize a few emulator state
+ variables.
+*/
+static void pulse_reset(void)
+{
+ /* processor registers */
+ PC = 0; /* ??? */
+ IR = 0; /* ??? */
+ /*MBR = 0;*/ /* ??? */
+ /*MAR = 0;*/ /* ??? */
+ /*AC = 0;*/ /* ??? */
+ /*LR = 0;*/ /* ??? */
+
+ /* processor state flip-flops */
+ tx0.run = 0; /* ??? */
+ tx0.rim = 0; /* ??? */
+ tx0.ioh = 0; /* ??? */
+ tx0.ios = 0; /* ??? */
+
+ tx0.rim_step = 0;
+
+ /* now, we kindly ask IO devices to reset, too */
+ if (tx0.io_reset_callback)
+ (*tx0.io_reset_callback)();
+}
diff --git a/src/emu/cpu/pdp1/tx0.h b/src/emu/cpu/pdp1/tx0.h
new file mode 100644
index 00000000000..e1b7acdcdca
--- /dev/null
+++ b/src/emu/cpu/pdp1/tx0.h
@@ -0,0 +1,50 @@
+#include "cpuintrf.h"
+
+
+/* register ids for tx0_get_reg/tx0_set_reg */
+enum
+{
+ TX0_MBR=1, TX0_AC, TX0_MAR, TX0_PC, TX0_IR, TX0_LR, TX0_XR, TX0_PF,
+ TX0_TBR, TX0_TAC,
+ TX0_TSS00, TX0_TSS01, TX0_TSS02, TX0_TSS03, TX0_TSS04, TX0_TSS05, TX0_TSS06, TX0_TSS07,
+ TX0_TSS10, TX0_TSS11, TX0_TSS12, TX0_TSS13, TX0_TSS14, TX0_TSS15, TX0_TSS16, TX0_TSS17,
+ TX0_CM_SEL, TX0_LR_SEL, TX0_GBL_CM_SEL,
+ TX0_STOP_CYC0, TX0_STOP_CYC1,
+ TX0_RUN, TX0_RIM,
+ TX0_CYCLE, TX0_IOH, TX0_IOS,
+ TX0_RESET, /* hack, do not use directly, use tx0_pulse_reset instead */
+ TX0_IO_COMPLETE /* hack, do not use directly, use tx0_pulse_io_complete instead */
+};
+
+#define tx0_pulse_reset() cpunum_set_reg(0, TX0_RESET, 0)
+#define tx0_pulse_io_complete() cpunum_set_reg(0, TX0_IO_COMPLETE, 0)
+
+typedef struct tx0_reset_param_t
+{
+ /* 8 standard I/O handlers:
+ 0: cpy (8kW only)
+ 1: r1l
+ 2: dis
+ 3: r3l
+ 4: prt
+ 5: reserved (for unimplemented typ instruction?)
+ 6: p6h
+ 7: p7h */
+ void (*io_handlers[8])(void);
+ /* select instruction handler */
+ void (*sel_handler)(void);
+ /* callback called when reset line is pulsed: IO devices should reset */
+ void (*io_reset_callback)(void);
+} tx0_reset_param_t;
+
+/* PUBLIC FUNCTIONS */
+void tx0_64kw_get_info(UINT32 state, cpuinfo *info);
+void tx0_8kw_get_info(UINT32 state, cpuinfo *info);
+
+#define READ_TX0_18BIT(A) ((signed)program_read_dword_32be((A)<<2))
+#define WRITE_TX0_18BIT(A,V) (program_write_dword_32be((A)<<2,(V)))
+
+#ifdef MAME_DEBUG
+unsigned tx0_dasm_64kw(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+unsigned tx0_dasm_8kw(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
diff --git a/src/emu/cpu/pdp1/tx0dasm.c b/src/emu/cpu/pdp1/tx0dasm.c
new file mode 100644
index 00000000000..46ca60334da
--- /dev/null
+++ b/src/emu/cpu/pdp1/tx0dasm.c
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <string.h>
+#include "cpu/pdp1/tx0.h"
+
+unsigned tx0_dasm_64kw(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int md;
+ int x;
+
+ md = *((UINT32 *) oprom);
+
+ x = md & 0177777;
+ switch (md >> 16)
+ {
+ case 0:
+ sprintf (buffer, "sto 0%06o", x);
+ break;
+ case 1:
+ sprintf (buffer, "add 0%06o", x);
+ break;
+ case 2:
+ sprintf (buffer, "trn 0%06o", x);
+ break;
+ case 3:
+ sprintf (buffer, "opr 0%06o", x);
+ break;
+ }
+ return 1;
+}
+
+unsigned tx0_dasm_8kw(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int md;
+ int x;
+
+ md = *((UINT32 *) oprom);
+
+ x = md & 0017777;
+ switch (md >> 13)
+ {
+ case 0:
+ sprintf (buffer, "sto 0%05o", x);
+ break;
+ case 1:
+ sprintf (buffer, "stx 0%05o", x);
+ break;
+ case 2:
+ sprintf (buffer, "sxa 0%05o", x);
+ break;
+ case 3:
+ sprintf (buffer, "ado 0%05o", x);
+ break;
+ case 4:
+ sprintf (buffer, "slr 0%05o", x);
+ break;
+ case 5:
+ sprintf (buffer, "slx 0%05o", x);
+ break;
+ case 6:
+ sprintf (buffer, "stz 0%05o", x);
+ break;
+ case 8:
+ sprintf (buffer, "add 0%05o", x);
+ break;
+ case 9:
+ sprintf (buffer, "adx 0%05o", x);
+ break;
+ case 10:
+ sprintf (buffer, "ldx 0%05o", x);
+ break;
+ case 11:
+ sprintf (buffer, "aux 0%05o", x);
+ break;
+ case 12:
+ sprintf (buffer, "llr 0%05o", x);
+ break;
+ case 13:
+ sprintf (buffer, "llx 0%05o", x);
+ break;
+ case 14:
+ sprintf (buffer, "lda 0%05o", x);
+ break;
+ case 15:
+ sprintf (buffer, "lax 0%05o", x);
+ break;
+ case 16:
+ sprintf (buffer, "trn 0%05o", x);
+ break;
+ case 17:
+ sprintf (buffer, "tze 0%05o", x);
+ break;
+ case 18:
+ sprintf (buffer, "tsx 0%05o", x);
+ break;
+ case 19:
+ sprintf (buffer, "tix 0%05o", x);
+ break;
+ case 20:
+ sprintf (buffer, "tra 0%05o", x);
+ break;
+ case 21:
+ sprintf (buffer, "trx 0%05o", x);
+ break;
+ case 22:
+ sprintf (buffer, "tlv 0%05o", x);
+ break;
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ sprintf (buffer, "opr 0%06o", md & 0177777);
+ break;
+ default:
+ sprintf (buffer, "illegal");
+ break;
+ }
+ return 1;
+}
diff --git a/src/emu/cpu/pic16c5x/16c5xdsm.c b/src/emu/cpu/pic16c5x/16c5xdsm.c
new file mode 100644
index 00000000000..3094347b9e4
--- /dev/null
+++ b/src/emu/cpu/pic16c5x/16c5xdsm.c
@@ -0,0 +1,267 @@
+ /**************************************************************************\
+ * Microchip PIC16C5x Emulator *
+ * *
+ * Copyright (C) 2003+ Tony La Porta *
+ * Originally written for the MAME project. *
+ * *
+ * *
+ * Addressing architecture is based on the Harvard addressing scheme. *
+ * *
+ * Many thanks to those involved in the i8039 Disassembler *
+ * as this was based on it. *
+ * *
+ * *
+ * *
+ * A Address to jump to. *
+ * B Bit address within an 8-bit file register. *
+ * D Destination select (0 = store result in W (accumulator)) *
+ * (1 = store result in file register) *
+ * F Register file address (00-1F). *
+ * K Literal field, constant data. *
+ * *
+ \**************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef MAME_DEBUG /* Compile interface to MAME */
+#include "cpuintrf.h"
+static const UINT8 *rombase;
+static const UINT8 *rambase;
+static offs_t pcbase;
+#define READOP16(A) (rombase[(A) - pcbase] | (rombase[(A) + 1 - pcbase] << 8))
+#define READARG16(A) (rambase[(A) - pcbase] | (rambase[(A) + 1 - pcbase] << 8))
+#else /* Compile interface for standalone */
+extern unsigned char *Buffer;
+#ifdef MSB_FIRST
+#define READOP16(A) ( ((Buffer[A]<<8) | Buffer[A+1]) )
+#define READARG16(A) ( ((Buffer[A]<<8) | Buffer[A+1]) )
+#else
+#define READOP16(A) ( ((Buffer[A+1]<<8) | Buffer[A]) )
+#define READARG16(A) ( ((Buffer[A+1]<<8) | Buffer[A]) )
+#endif
+#endif
+
+
+
+typedef unsigned char byte;
+typedef unsigned short int word;
+
+#define FMT(a,b) a, b
+#define PTRS_PER_FORMAT 2
+
+static const char *regfile[32] = { "Reg$00 (IND)", "Reg$01 (TMR)", "Reg$02 (PCL)", "Reg$03 (ST)", "Reg$04 (FSR)", "Reg$05 (PTA)", "Reg$06 (PTB)", "Reg$07 (PTC)",
+ "Reg$08", "Reg$09", "Reg$0A", "Reg$0B", "Reg$0C", "Reg$0D", "Reg$0E", "Reg$0F",
+ "Reg$10", "Reg$11", "Reg$12", "Reg$13", "Reg$14", "Reg$15", "Reg$16", "Reg$17",
+ "Reg$18", "Reg$19", "Reg$1A", "Reg$1B", "Reg$1C", "Reg$1D", "Reg$1E", "Reg$1F" };
+
+static const char *dest[2] = { "W", "Reg" };
+
+static const char *PIC16C5xFormats[] = {
+ FMT("000000000000", "nop"),
+ FMT("000000000010", "option"),
+ FMT("000000000011", "sleep"),
+ FMT("000000000100", "clrwdt"),
+ FMT("000000000101", "tris Port A"),
+ FMT("000000000110", "tris Port B"),
+ FMT("000000000111", "tris Port C"),
+ FMT("0000001fffff", "movwf %F"),
+ FMT("000001000000", "clrw"),
+ FMT("0000011fffff", "clrf %F"),
+ FMT("000010dfffff", "subwf %F,%D"),
+ FMT("000011dfffff", "decf %F,%D"),
+ FMT("000100dfffff", "iorwf %F,%D"),
+ FMT("000101dfffff", "andwf %F,%D"),
+ FMT("000110dfffff", "xorwf %F,%D"),
+ FMT("000111dfffff", "addwf %F,%D"),
+ FMT("001000dfffff", "movf %F,%D"),
+ FMT("001001dfffff", "comf %F,%D"),
+ FMT("001010dfffff", "incf %F,%D"),
+ FMT("001011dfffff", "decfsz %F,%D"),
+ FMT("001100dfffff", "rrf %F,%D"),
+ FMT("001101dfffff", "rlf %F,%D"),
+ FMT("001110dfffff", "swapf %F,%D"),
+ FMT("001111dfffff", "incfsz %F,%D"),
+ FMT("0100bbbfffff", "bcf %F,%B"),
+ FMT("0101bbbfffff", "bsf %F,%B"),
+ FMT("0110bbbfffff", "btfsc %F,%B"),
+ FMT("0111bbbfffff", "btfss %F,%B"),
+ FMT("1000kkkkkkkk", "retlw %K"),
+ FMT("1001aaaaaaaa", "call %A"),
+ FMT("101aaaaaaaaa", "goto %A"),
+ FMT("1100kkkkkkkk", "movlw %K"),
+ FMT("1101kkkkkkkk", "iorlw %K"),
+ FMT("1110kkkkkkkk", "andlw %K"),
+ FMT("1111kkkkkkkk", "xorlw %K"),
+ NULL
+};
+
+#define MAX_OPS (((sizeof(PIC16C5xFormats) / sizeof(PIC16C5xFormats[0])) - 1) / PTRS_PER_FORMAT)
+
+typedef struct opcode {
+ word mask; /* instruction mask */
+ word bits; /* constant bits */
+ word extcode; /* value that gets extension code */
+ const char *parse; /* how to parse bits */
+ const char *fmt; /* instruction format */
+} PIC16C5xOpcode;
+
+static PIC16C5xOpcode Op[MAX_OPS+1];
+static int OpInizialized = 0;
+
+static void InitDasm16C5x(void)
+{
+ const char *p, **ops;
+ word mask, bits;
+ int bit;
+ int i;
+
+ ops = PIC16C5xFormats; i = 0;
+ while (*ops)
+ {
+ p = *ops;
+ mask = 0; bits = 0; bit = 11;
+ while (*p && bit >= 0)
+ {
+ switch (*p++)
+ {
+ case '1': mask |= 1<<bit; bits |= 1<<bit; bit--; break;
+ case '0': mask |= 1<<bit; bit--; break;
+ case ' ': break;
+ case 'a':
+ case 'b':
+ case 'd':
+ case 'f':
+ case 'k':
+ bit --;
+ break;
+ default: fatalerror("Invalid instruction encoding '%s %s'",
+ ops[0],ops[1]);
+ }
+ }
+ if (bit != -1 )
+ {
+ fatalerror("not enough bits in encoding '%s %s' %d",
+ ops[0],ops[1],bit);
+ }
+ while (isspace(*p)) p++;
+ if (*p) Op[i].extcode = *p;
+ Op[i].bits = bits;
+ Op[i].mask = mask;
+ Op[i].fmt = ops[1];
+ Op[i].parse = ops[0];
+
+ ops += PTRS_PER_FORMAT;
+ i++;
+ }
+
+ OpInizialized = 1;
+}
+
+offs_t pic16C5x_dasm(char *str, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int a, b, d, f, k; /* these can all be filled in by parsing an instruction */
+ int i;
+ int op;
+ int cnt = 1;
+ int code;
+ int bit;
+ char *strtmp;
+ const char *cp; /* character pointer in OpFormats */
+ UINT32 flags = 0;
+
+ rombase = oprom;
+ rambase = opram;
+ pcbase = 2*pc;
+
+ if (!OpInizialized) InitDasm16C5x();
+
+ op = -1; /* no matching opcode */
+ code = READOP16(2*pc);
+ for ( i = 0; i < MAX_OPS; i++)
+ {
+ if ((code & Op[i].mask) == Op[i].bits)
+ {
+ if (op != -1)
+ {
+ mame_printf_debug("Error: opcode %04Xh matches %d (%s) and %d (%s)\n",
+ code,i,Op[i].fmt,op,Op[op].fmt);
+ }
+ op = i;
+ }
+ }
+ if (op == -1)
+ {
+ sprintf(str,"???? dw %04Xh",code);
+ return cnt;
+ }
+ strtmp = str;
+ if (Op[op].extcode) /* Actually, theres no double length opcodes */
+ {
+ bit = 27;
+ code <<= 16;
+ code |= READARG16(2*(pc+cnt));
+ cnt++;
+ }
+ else
+ {
+ bit = 11;
+ }
+
+ /* shift out operands */
+ cp = Op[op].parse;
+ a = b = d = f = k = 0;
+
+ while (bit >= 0)
+ {
+ /* mame_printf_debug("{%c/%d}",*cp,bit); */
+ switch(*cp)
+ {
+ case 'a': a <<=1; a |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'b': b <<=1; b |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'd': d <<=1; d |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'f': f <<=1; f |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'k': k <<=1; k |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case ' ': break;
+ case '1': case '0': bit--; break;
+ case '\0': fatalerror("premature end of parse string, opcode %x, bit = %d",code,bit);
+ }
+ cp++;
+ }
+
+ /* now traverse format string */
+ cp = Op[op].fmt;
+ if (!strncmp(cp, "call", 4))
+ flags = DASMFLAG_STEP_OVER;
+ else if (!strncmp(cp, "ret", 3))
+ flags = DASMFLAG_STEP_OUT;
+
+ while (*cp)
+ {
+ if (*cp == '%')
+ {
+ char num[30], *q;
+ cp++;
+ switch (*cp++)
+ {
+ case 'A': sprintf(num,"$%03X",a); break;
+ case 'B': sprintf(num,"%d",b); break;
+ case 'D': sprintf(num,"%s",dest[d]); break;
+ case 'F': sprintf(num,"%s",regfile[f]); break;
+ case 'K': sprintf(num,"%02Xh",k); break;
+ default:
+ fatalerror("illegal escape character in format '%s'",Op[op].fmt);
+ }
+ q = num; while (*q) *str++ = *q++;
+ *str = '\0';
+ }
+ else
+ {
+ *str++ = *cp++;
+ *str = '\0';
+ }
+ }
+ return cnt | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/pic16c5x/dis16c5x.c b/src/emu/cpu/pic16c5x/dis16c5x.c
new file mode 100644
index 00000000000..08e0c901c54
--- /dev/null
+++ b/src/emu/cpu/pic16c5x/dis16c5x.c
@@ -0,0 +1,134 @@
+ /**************************************************************************\
+ * Microchip PIC16C5x Emulator *
+ * *
+ * Copyright (C) 2003+ Tony La Porta *
+ * Originally written for the MAME project. *
+ * *
+ * *
+ * Notes : Data is expected to be read from source file as LSB first. *
+ * *
+ \**************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "16c5xdsm.c"
+
+
+unsigned char *Buffer;
+
+
+int main(int argc,char *argv[])
+{
+ int length=0, length_to_dump=0, offset=0, disasm_words=0;
+ int filelength=0, bytes_read;
+ int Counter=0;
+
+ FILE *F;
+ char *String_Output;
+
+ if(argc<2)
+ {
+ printf("\n");
+ printf("PIC16C5x Disassembler 1.0 by Tony La Porta (C)2003+\n\n");
+ printf("Usage: dis16c5x <input-file> [ <start-addr> [ <num-of-addr> ] ]\n");
+ printf(" <input-file> source file data must be MSB first\n");
+ printf(" <start-addr> starting address to disassemble from (decimal)\n");
+ printf(" <num-of-addr> number of addresses to disassemble (decimal)\n");
+ printf(" Preceed values with 0x if HEX values preffered\n");
+ exit(1);
+ }
+
+ if(!(F=fopen(argv[1],"rb")))
+ {
+ printf("\n%s: Can't open file %s\n",argv[0],argv[1]);
+ exit(2);
+ }
+ argv++; argc--;
+ if (argv[1])
+ {
+ offset = strtol(argv[1],NULL,0);
+ argv++; argc--;
+ }
+ if (argv[1])
+ {
+ length = strtol(argv[1],NULL,0);
+ argv++; argc--;
+ }
+
+ fseek(F,0, SEEK_END);
+ filelength = ftell(F);
+
+ length *= 2;
+
+ if ((length > (filelength - (offset*2))) || (length == 0)) length = filelength - (offset*2);
+ printf("Length=%04Xh(words) Offset=$%04Xh filelength=%04Xh(words) %04Xh(bytes)\n",length/2,offset,filelength/2,filelength);
+ length_to_dump = length;
+ printf("Starting from %d, dumping %d opcodes (word size)\n",offset,length/2);
+ Buffer = calloc((filelength+1),sizeof(char));
+ if (Buffer==NULL)
+ {
+ printf("Out of Memory !!!");
+ fclose(F);
+ exit(3);
+ }
+ String_Output = calloc(80,sizeof(char));
+ if (String_Output==NULL)
+ {
+ printf("Out of Memory !!!");
+ free(Buffer);
+ fclose(F);
+ exit(4);
+ }
+
+ if (fseek(F,0,SEEK_SET) != 0)
+ {
+ printf("Error seeking to beginning of file\n");
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ exit(5);
+ }
+
+ Counter = offset;
+ bytes_read = fread(Buffer,sizeof(char),filelength,F);
+ if (bytes_read >= length)
+ {
+ for (; length > 0; length -= (disasm_words*2))
+ {
+ int ii;
+ disasm_words = Dasm16C5x(String_Output,Counter);
+ printf("$%03X: ",Counter);
+ for (ii = 0; ii < disasm_words; ii++)
+ {
+ if (((Counter*2) + ii) > filelength) /* Past end of length to dump ? */
+ {
+ sprintf(String_Output,"???? dw %02.2X%02.2Xh (Past end of disassembly !)",Buffer[((Counter-1)*2)+1],Buffer[((Counter-1)*2)]);
+ }
+ else
+ {
+ printf("%02.2x%02.2x ",Buffer[(Counter*2)+1],Buffer[(Counter*2)]);
+ }
+ Counter++ ;
+ }
+ for (; ii < 4; ii++)
+ {
+ printf(" ");
+ }
+ printf("\t%s\n",String_Output);
+ }
+ }
+ else
+ {
+ printf("ERROR length to dump was %d ", length_to_dump/2);
+ printf(", but bytes read from file were %d\n", bytes_read/2);
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ exit(7);
+ }
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ return(0);
+}
diff --git a/src/emu/cpu/pic16c5x/pic16c5x.c b/src/emu/cpu/pic16c5x/pic16c5x.c
new file mode 100644
index 00000000000..7daee53b009
--- /dev/null
+++ b/src/emu/cpu/pic16c5x/pic16c5x.c
@@ -0,0 +1,1334 @@
+ /**************************************************************************\
+ * Microchip PIC16C5x Emulator *
+ * *
+ * Copyright (C) 2003+ Tony La Porta *
+ * Originally written for the MAME project. *
+ * *
+ * *
+ * Addressing architecture is based on the Harvard addressing scheme. *
+ * *
+ * *
+ * **** Change Log **** *
+ * TLP (06-Apr-2003) *
+ * - First Public release. *
+ * BO (07-Apr-2003) Ver 1.01 *
+ * - Renamed 'sleep' function to 'sleepic' to avoid C conflicts. *
+ * TLP (09-Apr-2003) Ver 1.10 *
+ * - Fixed modification of file register $03 (Status). *
+ * - Corrected support for 7FFh (12-bit) size ROMs. *
+ * - The 'call' and 'goto' instructions weren't correctly handling the *
+ * STATUS page info correctly. *
+ * - The FSR register was incorrectly oring the data with 0xe0 when read. *
+ * - Prescaler masking information was set to 3 instead of 7. *
+ * - Prescaler assign bit was set to 4 instead of 8. *
+ * - Timer source and edge select flags/masks were wrong. *
+ * - Corrected the memory bank selection in GET/SET_REGFILE and also the *
+ * indirect register addressing. *
+ * BMP (18-May-2003) Ver 1.11 *
+ * - pic16c5x_get_reg functions were missing 'returns'. *
+ * TLP (27-May-2003) Ver 1.12 *
+ * - Fixed the WatchDog timer count. *
+ * - The Prescaler rate was incorrectly being zeroed, instead of the *
+ * actual Prescaler counter in the CLRWDT and SLEEP instructions. *
+ * - Added masking to the FSR register. Upper unused bits are always 1. *
+ * *
+ * *
+ * **** Notes: **** *
+ * PIC WatchDog Timer has a seperate internal clock. For the moment, we're *
+ * basing the count on a 4MHz input clock, since 4MHz is the typical *
+ * input frequency (but by no means always). *
+ * A single scaler is available for the Counter/Timer or WatchDog Timer. *
+ * When connected to the Counter/Timer, it functions as a Prescaler, *
+ * hence prescale overflows, tick the Counter/Timer. *
+ * When connected to the WatchDog Timer, it functions as a Postscaler *
+ * hence WatchDog Timer overflows, tick the Postscaler. This scenario *
+ * means that the WatchDog timeout occurs when the Postscaler has *
+ * reached the scaler rate value, not when the WatchDog reaches zero. *
+ * CLRWDT should prevent the WatchDog Timer from timing out and generating *
+ * a device reset, but how is not known. The manual also mentions that *
+ * the WatchDog Timer can only be disabled during ROM programming, and *
+ * no other means seem to exist??? *
+ * *
+ \**************************************************************************/
+
+
+
+#include "debugger.h"
+#include "pic16c5x.h"
+
+
+#define CLK 1 /* 1 cycle equals 4 Q-clock ticks */
+
+
+#ifndef INLINE
+#define INLINE static inline
+#endif
+
+
+#define M_RDRAM(A) (((A) < 8) ? R.internalram[A] : PIC16C5x_RAM_RDMEM(A))
+#define M_WRTRAM(A,V) do { if ((A) < 8) R.internalram[A] = (V); else PIC16C5x_RAM_WRMEM(A,V); } while (0)
+#define M_RDOP(A) PIC16C5x_RDOP(A)
+#define M_RDOP_ARG(A) PIC16C5x_RDOP_ARG(A)
+#define P_IN(A) PIC16C5x_In(A)
+#define P_OUT(A,V) PIC16C5x_Out(A,V)
+#define S_T0_IN PIC16C5x_T0_In
+#define ADDR_MASK 0x7ff
+
+
+
+
+typedef struct
+{
+ /******************** CPU Internal Registers *******************/
+ UINT16 PC;
+ UINT16 PREVPC; /* previous program counter */
+ UINT8 W;
+ UINT8 OPTION;
+ UINT16 CONFIG;
+ UINT8 ALU;
+ UINT16 WDT;
+ UINT8 TRISA;
+ UINT8 TRISB;
+ UINT8 TRISC;
+ UINT16 STACK[2];
+ UINT16 prescaler; /* Note: this is really an 8-bit register */
+ PAIR opcode;
+ UINT8 internalram[8];
+} pic16C5x_Regs;
+
+static pic16C5x_Regs R;
+static UINT16 temp_config;
+static UINT8 old_T0;
+static INT8 old_data;
+static UINT8 picRAMmask;
+static int inst_cycles;
+static int delay_timer;
+static int picmodel;
+static int pic16C5x_reset_vector;
+static int pic16C5x_icount;
+typedef void (*opcode_fn) (void);
+static unsigned cycles_000_other[16];
+
+
+#define TMR0 internalram[1]
+#define PCL internalram[2]
+#define STATUS internalram[3]
+#define FSR internalram[4]
+#define PORTA internalram[5]
+#define PORTB internalram[6]
+#define PORTC internalram[7]
+#define INDF M_RDRAM(R.FSR)
+
+#define ADDR (R.opcode.b.l & 0x1f)
+
+#define POSITIVE_EDGE_T0 (( (int)(T0_in-old_T0) > 0) ? 1 : 0)
+#define NEGATIVE_EDGE_T0 (( (int)(old_T0-T0_in) > 0) ? 1 : 0)
+
+
+/******** The following is the Status Flag register definition. *********/
+ /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */
+ /* | PA | TO | PD | Z | DC | C | */
+#define PA_REG 0xe0 /* PA Program Page Preselect - bit 8 is unused here */
+#define TO_FLAG 0x10 /* TO Time Out flag (WatchDog) */
+#define PD_FLAG 0x08 /* PD Power Down flag */
+#define Z_FLAG 0x04 /* Z Zero Flag */
+#define DC_FLAG 0x02 /* DC Digit Carry/Borrow flag (Nibble) */
+#define C_FLAG 0x01 /* C Carry/Borrow Flag (Byte) */
+
+#define PA (R.STATUS & PA_REG)
+#define TO (R.STATUS & TO_FLAG)
+#define PD (R.STATUS & PD_FLAG)
+#define ZERO (R.STATUS & Z_FLAG)
+#define DC (R.STATUS & DC_FLAG)
+#define CARRY (R.STATUS & C_FLAG)
+
+
+/******** The following is the Option Flag register definition. *********/
+ /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */
+ /* | 0 | 0 | TOCS | TOSE | PSA | PS | */
+#define T0CS_FLAG 0x20 /* TOCS Timer 0 clock source select */
+#define T0SE_FLAG 0x10 /* TOSE Timer 0 clock source edge select */
+#define PSA_FLAG 0x08 /* PSA Prescaler Assignment bit */
+#define PS_REG 0x07 /* PS Prescaler Rate select */
+
+#define T0CS (R.OPTION & T0CS_FLAG)
+#define T0SE (R.OPTION & T0SE_FLAG)
+#define PSA (R.OPTION & PSA_FLAG)
+#define PS (R.OPTION & PS_REG)
+
+
+/******** The following is the Config Flag register definition. *********/
+ /* | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */
+ /* | CP | WDTE | FOSC | */
+ /* CP Code Protect (ROM read protect) */
+#define WDTE_FLAG 0x04 /* WDTE WatchDog Timer enable */
+#define FOSC_FLAG 0x03 /* FOSC Oscillator source select */
+
+#define WDTE (R.CONFIG & WDTE_FLAG)
+#define FOSC (R.CONFIG & FOSC_FLAG)
+
+
+/************************************************************************
+ * Shortcuts
+ ************************************************************************/
+
+/* Easy bit position selectors */
+#define POS ((R.opcode.b.l >> 5) & 7)
+static unsigned int bit_clr[8] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };
+static unsigned int bit_set[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+
+
+INLINE void CLR(UINT16 flag) { R.STATUS &= ~flag; }
+INLINE void SET(UINT16 flag) { R.STATUS |= flag; }
+
+
+
+INLINE void CALCULATE_Z_FLAG(void)
+{
+ if (R.ALU == 0) SET(Z_FLAG);
+ else CLR(Z_FLAG);
+}
+
+INLINE void CALCULATE_ADD_CARRY(void)
+{
+ if ((UINT8)(old_data) > (UINT8)(R.ALU)) {
+ SET(C_FLAG);
+ }
+ else {
+ CLR(C_FLAG);
+ }
+}
+
+INLINE void CALCULATE_ADD_DIGITCARRY(void)
+{
+ if (((UINT8)(old_data) & 0x0f) > ((UINT8)(R.ALU) & 0x0f)) {
+ SET(DC_FLAG);
+ }
+ else {
+ CLR(DC_FLAG);
+ }
+}
+
+INLINE void CALCULATE_SUB_CARRY(void)
+{
+ if ((UINT8)(old_data) < (UINT8)(R.ALU)) {
+ CLR(C_FLAG);
+ }
+ else {
+ SET(C_FLAG);
+ }
+}
+
+INLINE void CALCULATE_SUB_DIGITCARRY(void)
+{
+ if (((UINT8)(old_data) & 0x0f) < ((UINT8)(R.ALU) & 0x0f)) {
+ CLR(DC_FLAG);
+ }
+ else {
+ SET(DC_FLAG);
+ }
+}
+
+
+
+INLINE UINT16 POP_STACK(void)
+{
+ UINT16 data = R.STACK[1];
+ R.STACK[1] = R.STACK[0];
+ return (data & ADDR_MASK);
+}
+INLINE void PUSH_STACK(UINT16 data)
+{
+ R.STACK[0] = R.STACK[1];
+ R.STACK[1] = (data & ADDR_MASK);
+}
+
+
+INLINE UINT8 GET_REGFILE(offs_t addr) /* Read from internal memory */
+{
+ UINT8 data;
+
+ if ((picmodel == 0x16C57) || (picmodel == 0x16C58))
+ {
+ addr |= (R.FSR & 0x60); /* FSR used for banking */
+ }
+ if ((addr & 0x10) == 0) addr &= 0x0f;
+
+ switch(addr)
+ {
+ case 00: addr = (R.FSR & picRAMmask);
+ if (addr == 0) { data = 0; break; }
+ if ((addr & 0x10) == 0) addr &= 0x0f;
+ data = M_RDRAM(addr); /* Indirect address */
+ break;
+ case 04: data = (R.FSR | (~picRAMmask)); break;
+ case 05: data = P_IN(0);
+ data &= R.TRISA;
+ data |= (~R.TRISA & R.PORTA);
+ data &= 0xf; /* 4-bit port (only lower 4 bits used) */
+ break;
+ case 06: data = P_IN(1);
+ data &= R.TRISB;
+ data |= (~R.TRISB & R.PORTB);
+ break;
+ case 07: if ((picmodel == 0x16C55) || (picmodel == 0x16C57)) {
+ data = P_IN(2);
+ data &= R.TRISC;
+ data |= (~R.TRISC & R.PORTC);
+ }
+ else { /* PIC16C54, PIC16C56, PIC16C58 */
+ data = M_RDRAM(addr);
+ }
+ break;
+ default: data = M_RDRAM(addr); break;
+ }
+
+ return data;
+}
+
+INLINE void STORE_REGFILE(offs_t addr, UINT8 data) /* Write to internal memory */
+{
+ if ((picmodel == 0x16C57) || (picmodel == 0x16C58))
+ {
+ addr |= (R.FSR & 0x60);
+ }
+ if ((addr & 0x10) == 0) addr &= 0x0f;
+
+ switch(addr)
+ {
+ case 00: addr = (R.FSR & picRAMmask);
+ if (addr == 0) break;
+ if ((addr & 0x10) == 0) addr &= 0x0f;
+ M_WRTRAM(addr, data); break; /* Indirect address */
+ case 01: delay_timer = 2; /* Timer starts after next two instructions */
+ if (PSA == 0) R.prescaler = 0; /* Must clear the Prescaler */
+ R.TMR0 = data; break;
+ case 02: R.PCL = data;
+ R.PC = ((R.STATUS & PA_REG) << 4) | data; break;
+ case 03: R.STATUS &= ~PA_REG; R.STATUS |= (data & PA_REG); break;
+ case 04: R.FSR = (data | (~picRAMmask)); break;
+ case 05: data &= 0xf; /* 4-bit port (only lower 4 bits used) */
+ P_OUT(0,data & (~R.TRISA)); R.PORTA = data; break;
+ case 06: P_OUT(1,data & (~R.TRISB)); R.PORTB = data; break;
+ case 07: if ((picmodel == 0x16C55) || (picmodel == 0x16C57)) {
+ P_OUT(2,data & (~R.TRISC));
+ R.PORTC = data;
+ }
+ else { /* PIC16C54, PIC16C56, PIC16C58 */
+ M_WRTRAM(addr, data);
+ }
+ break;
+ default: M_WRTRAM(addr, data); break;
+ }
+}
+
+
+INLINE void STORE_RESULT(offs_t addr, UINT8 data)
+{
+ if (R.opcode.b.l & 0x20)
+ {
+ STORE_REGFILE(addr, data);
+ }
+ else
+ {
+ R.W = data;
+ }
+}
+
+
+/************************************************************************
+ * Emulate the Instructions
+ ************************************************************************/
+
+/* This following function is here to fill in the void for */
+/* the opcode call function. This function is never called. */
+
+
+static void illegal(void)
+{
+ logerror("PIC16C5x: PC=%03x, Illegal opcode = %04x\n", (R.PC-1), R.opcode.w.l);
+}
+
+
+static void addwf(void)
+{
+ old_data = GET_REGFILE(ADDR);
+ R.ALU = old_data + R.W;
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+ CALCULATE_ADD_CARRY();
+ CALCULATE_ADD_DIGITCARRY();
+}
+
+static void andwf(void)
+{
+ R.ALU = GET_REGFILE(ADDR) & R.W;
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+}
+
+static void andlw(void)
+{
+ R.ALU = R.opcode.b.l & R.W;
+ R.W = R.ALU;
+ CALCULATE_Z_FLAG();
+}
+
+static void bcf(void)
+{
+ R.ALU = GET_REGFILE(ADDR);
+ R.ALU &= bit_clr[POS];
+ STORE_REGFILE(ADDR, R.ALU);
+}
+
+static void bsf(void)
+{
+ R.ALU = GET_REGFILE(ADDR);
+ R.ALU |= bit_set[POS];
+ STORE_REGFILE(ADDR, R.ALU);
+}
+
+static void btfss(void)
+{
+ if ((GET_REGFILE(ADDR) & bit_set[POS]) == bit_set[POS])
+ {
+ R.PC++ ;
+ R.PCL = R.PC & 0xff;
+ inst_cycles += cycles_000_other[0]; /* Add NOP cycles */
+ }
+}
+
+static void btfsc(void)
+{
+ if ((GET_REGFILE(ADDR) & bit_set[POS]) == 0)
+ {
+ R.PC++ ;
+ R.PCL = R.PC & 0xff;
+ inst_cycles += cycles_000_other[0]; /* Add NOP cycles */
+ }
+}
+
+static void call(void)
+{
+ PUSH_STACK(R.PC);
+ R.PC = ((R.STATUS & PA_REG) << 4) | R.opcode.b.l;
+ R.PC &= 0x6ff;
+ R.PCL = R.PC & 0xff;
+}
+
+static void clrw(void)
+{
+ R.W = 0;
+ SET(Z_FLAG);
+}
+
+static void clrf(void)
+{
+ STORE_REGFILE(ADDR, 0);
+ SET(Z_FLAG);
+}
+
+static void clrwdt(void)
+{
+ R.WDT = 0;
+ if (PSA) R.prescaler = 0;
+ SET(TO_FLAG);
+ SET(PD_FLAG);
+}
+
+static void comf(void)
+{
+ R.ALU = ~(GET_REGFILE(ADDR));
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+}
+
+static void decf(void)
+{
+ R.ALU = GET_REGFILE(ADDR) - 1;
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+}
+
+static void decfsz(void)
+{
+ R.ALU = GET_REGFILE(ADDR) - 1;
+ STORE_RESULT(ADDR, R.ALU);
+ if (R.ALU == 0)
+ {
+ R.PC++ ;
+ R.PCL = R.PC & 0xff;
+ inst_cycles += cycles_000_other[0]; /* Add NOP cycles */
+ }
+}
+
+static void goto_op(void)
+{
+ R.PC = ((R.STATUS & PA_REG) << 4) | (R.opcode.w.l & 0x1ff);
+ R.PC &= ADDR_MASK;
+ R.PCL = R.PC & 0xff;
+}
+
+static void incf(void)
+{
+ R.ALU = GET_REGFILE(ADDR) + 1;
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+}
+
+static void incfsz(void)
+{
+ R.ALU = GET_REGFILE(ADDR) + 1;
+ STORE_RESULT(ADDR, R.ALU);
+ if (R.ALU == 0)
+ {
+ R.PC++ ;
+ R.PCL = R.PC & 0xff;
+ inst_cycles += cycles_000_other[0]; /* Add NOP cycles */
+ }
+}
+
+static void iorlw(void)
+{
+ R.ALU = R.opcode.b.l | R.W;
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+}
+
+static void iorwf(void)
+{
+ R.ALU = GET_REGFILE(ADDR) | R.W;
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+}
+
+static void movf(void)
+{
+ R.ALU = GET_REGFILE(ADDR);
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+}
+
+static void movlw(void)
+{
+ R.W = R.opcode.b.l;
+}
+
+static void movwf(void)
+{
+ STORE_REGFILE(ADDR, R.W);
+}
+
+static void nop(void)
+{
+ /* Do nothing */
+}
+
+static void option(void)
+{
+ R.OPTION = R.W & 0x3f;
+}
+
+static void retlw(void)
+{
+ R.W = R.opcode.b.l;
+ R.PC = POP_STACK();
+ R.PCL = R.PC & 0xff;
+}
+
+static void rlf(void)
+{
+ R.ALU = GET_REGFILE(ADDR);
+ R.ALU <<= 1;
+ if (R.STATUS & C_FLAG) R.ALU |= 1;
+ if (GET_REGFILE(ADDR) & 0x80) SET(C_FLAG);
+ else CLR(C_FLAG);
+ STORE_RESULT(ADDR, R.ALU);
+}
+
+static void rrf(void)
+{
+ R.ALU = GET_REGFILE(ADDR);
+ R.ALU >>= 1;
+ if (R.STATUS & C_FLAG) R.ALU |= 0x80;
+ if (GET_REGFILE(ADDR) & 1) SET(C_FLAG);
+ else CLR(C_FLAG);
+ STORE_RESULT(ADDR, R.ALU);
+}
+
+static void sleepic(void)
+{
+ if (WDTE) R.WDT = 0;
+ if (PSA) R.prescaler = 0;
+ SET(TO_FLAG);
+ CLR(PD_FLAG);
+}
+
+static void subwf(void)
+{
+ old_data = GET_REGFILE(ADDR);
+ R.ALU = old_data - R.W;
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+ CALCULATE_SUB_CARRY();
+ CALCULATE_SUB_DIGITCARRY();
+}
+
+static void swapf(void)
+{
+ R.ALU = ((GET_REGFILE(ADDR) << 4) & 0xf0);
+ R.ALU |= ((GET_REGFILE(ADDR) >> 4) & 0x0f);
+ STORE_RESULT(ADDR, R.ALU);
+}
+
+static void tris(void)
+{
+ switch(R.opcode.b.l & 0x7)
+ {
+ case 05: if (R.TRISA == R.W) break;
+ else R.TRISA = R.W; P_OUT(0,R.PORTA & (~R.TRISA) & 0xf); break;
+ case 06: if (R.TRISB == R.W) break;
+ else R.TRISB = R.W; P_OUT(1,R.PORTB & (~R.TRISB)); break;
+ case 07: if (R.TRISC == R.W) break;
+ else R.TRISC = R.W; P_OUT(2,R.PORTC & (~R.TRISC)); break;
+ default: illegal(); break;
+ }
+}
+
+static void xorlw(void)
+{
+ R.ALU = R.W ^ R.opcode.b.l;
+ R.W = R.ALU;
+ CALCULATE_Z_FLAG();
+}
+
+static void xorwf(void)
+{
+ R.ALU = GET_REGFILE(ADDR) ^ R.W;
+ STORE_RESULT(ADDR, R.ALU);
+ CALCULATE_Z_FLAG();
+}
+
+
+
+/***********************************************************************
+ * Cycle Timings
+ ***********************************************************************/
+
+static unsigned cycles_main[256]=
+{
+/*00*/ 1*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*10*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*20*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*30*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*40*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*50*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*60*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*70*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*80*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*90*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*A0*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*B0*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*C0*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*D0*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*E0*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*F0*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK
+};
+
+static opcode_fn opcode_main[256]=
+{
+/*00*/ nop, illegal,movwf, movwf, clrw, illegal,clrf, clrf,
+/*08*/ subwf, subwf, subwf, subwf, decf, decf, decf, decf,
+/*10*/ iorwf, iorwf, iorwf, iorwf, andwf, andwf, andwf, andwf,
+/*18*/ xorwf, xorwf, xorwf, xorwf, addwf, addwf, addwf, addwf,
+/*20*/ movf, movf, movf, movf, comf, comf, comf, comf,
+/*28*/ incf, incf, incf, incf, decfsz, decfsz, decfsz, decfsz,
+/*30*/ rrf, rrf, rrf, rrf, rlf, rlf, rlf, rlf,
+/*38*/ swapf, swapf, swapf, swapf, incfsz, incfsz, incfsz, incfsz,
+/*40*/ bcf, bcf, bcf, bcf, bcf, bcf, bcf, bcf,
+/*48*/ bcf, bcf, bcf, bcf, bcf, bcf, bcf, bcf,
+/*50*/ bsf, bsf, bsf, bsf, bsf, bsf, bsf, bsf,
+/*58*/ bsf, bsf, bsf, bsf, bsf, bsf, bsf, bsf,
+/*60*/ btfsc, btfsc, btfsc, btfsc, btfsc, btfsc, btfsc, btfsc,
+/*68*/ btfsc, btfsc, btfsc, btfsc, btfsc, btfsc, btfsc, btfsc,
+/*70*/ btfss, btfss, btfss, btfss, btfss, btfss, btfss, btfss,
+/*78*/ btfss, btfss, btfss, btfss, btfss, btfss, btfss, btfss,
+/*80*/ retlw, retlw, retlw, retlw, retlw, retlw, retlw, retlw,
+/*88*/ retlw, retlw, retlw, retlw, retlw, retlw, retlw, retlw,
+/*90*/ call, call, call, call, call, call, call, call,
+/*98*/ call, call, call, call, call, call, call, call,
+/*A0*/ goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
+/*A8*/ goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
+/*B0*/ goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
+/*B8*/ goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
+/*C0*/ movlw, movlw, movlw, movlw, movlw, movlw, movlw, movlw,
+/*C8*/ movlw, movlw, movlw, movlw, movlw, movlw, movlw, movlw,
+/*D0*/ iorlw, iorlw, iorlw, iorlw, iorlw, iorlw, iorlw, iorlw,
+/*D8*/ iorlw, iorlw, iorlw, iorlw, iorlw, iorlw, iorlw, iorlw,
+/*E0*/ andlw, andlw, andlw, andlw, andlw, andlw, andlw, andlw,
+/*E8*/ andlw, andlw, andlw, andlw, andlw, andlw, andlw, andlw,
+/*F0*/ xorlw, xorlw, xorlw, xorlw, xorlw, xorlw, xorlw, xorlw,
+/*F8*/ xorlw, xorlw, xorlw, xorlw, xorlw, xorlw, xorlw, xorlw
+};
+
+
+static unsigned cycles_000_other[16]=
+{
+/*00*/ 1*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK
+};
+
+static opcode_fn opcode_000_other[16]=
+{
+/*00*/ nop, illegal,option, sleepic,clrwdt, tris, tris, tris,
+/*08*/ illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal
+};
+
+
+
+/****************************************************************************
+ * Inits CPU emulation
+ ****************************************************************************/
+
+static void pic16C5x_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ state_save_register_item("pic16C5x", index, old_data);
+ state_save_register_item("pic16C5x", index, R.W);
+ state_save_register_item("pic16C5x", index, R.ALU);
+ state_save_register_item("pic16C5x", index, R.OPTION);
+ state_save_register_item("pic16C5x", index, R.TMR0);
+ state_save_register_item("pic16C5x", index, R.PCL);
+ state_save_register_item("pic16C5x", index, R.STATUS);
+ state_save_register_item("pic16C5x", index, R.FSR);
+ state_save_register_item("pic16C5x", index, R.PORTA);
+ state_save_register_item("pic16C5x", index, R.PORTB);
+ state_save_register_item("pic16C5x", index, R.PORTC);
+ state_save_register_item("pic16C5x", index, R.TRISA);
+ state_save_register_item("pic16C5x", index, R.TRISB);
+ state_save_register_item("pic16C5x", index, R.TRISC);
+ state_save_register_item("pic16C5x", index, old_T0);
+ state_save_register_item("pic16C5x", index, picRAMmask);
+ state_save_register_item("pic16C5x", index, R.WDT);
+ state_save_register_item("pic16C5x", index, R.prescaler);
+ state_save_register_item("pic16C5x", index, R.STACK[0]);
+ state_save_register_item("pic16C5x", index, R.STACK[1]);
+ state_save_register_item("pic16C5x", index, R.PC);
+ state_save_register_item("pic16C5x", index, R.PREVPC);
+ state_save_register_item("pic16C5x", index, R.CONFIG);
+ state_save_register_item("pic16C5x", index, R.opcode.d);
+ state_save_register_item("pic16C5x", index, delay_timer);
+ state_save_register_item("pic16C5x", index, picmodel);
+ state_save_register_item("pic16C5x", index, pic16C5x_reset_vector);
+}
+
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+
+static void pic16C5x_reset_regs(void)
+{
+ R.PC = pic16C5x_reset_vector;
+ R.CONFIG = temp_config;
+ R.TRISA = 0xff;
+ R.TRISB = 0xff;
+ R.TRISC = 0xff;
+ R.OPTION = 0x3f;
+ R.PCL = 0xff;
+ R.FSR |= (~picRAMmask);
+ R.PORTA &= 0x0f;
+ R.prescaler = 0;
+ delay_timer = 0;
+ old_T0 = 0;
+ inst_cycles = 0;
+}
+
+static void pic16C5x_soft_reset(void)
+{
+ R.STATUS &= 0x1f;
+ pic16C5x_reset_regs();
+}
+
+void pic16c5x_config(int data)
+{
+ logerror("Writing %04x to the PIC16C5x config register\n",data);
+ temp_config = (data & 0xfff);
+}
+
+
+/****************************************************************************
+ * Shut down CPU emulation
+ ****************************************************************************/
+
+static void pic16C5x_exit (void)
+{
+ /* nothing to do */
+}
+
+
+/****************************************************************************
+ * WatchDog
+ ****************************************************************************/
+
+static void pic16C5x_update_watchdog(int counts)
+{
+ /* WatchDog is set up to count 18,000 (0x464f hex) ticks to provide */
+ /* the timeout period of 0.018ms based on a 4MHz input clock. */
+ /* Note: the 4MHz clock should be divided by the PIC16C5x_CLOCK_DIVIDER */
+ /* which effectively makes the PIC run at 1MHz internally. */
+
+ /* If the current instruction is CLRWDT or SLEEP, don't update the WDT */
+
+ if ((R.opcode.w.l != 3) && (R.opcode.w.l != 4))
+ {
+ UINT16 old_WDT = R.WDT;
+
+ R.WDT -= counts;
+
+ if (R.WDT > 0x464f) {
+ R.WDT = 0x464f - (0xffff - R.WDT);
+ }
+
+ if (((old_WDT != 0) && (old_WDT < R.WDT)) || (R.WDT == 0))
+ {
+ if (PSA) {
+ R.prescaler++;
+ if (R.prescaler >= (1 << PS)) { /* Prescale values from 1 to 128 */
+ R.prescaler = 0;
+ CLR(TO_FLAG);
+ pic16C5x_soft_reset();
+ }
+ }
+ else {
+ CLR(TO_FLAG);
+ pic16C5x_soft_reset();
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ * Update Timer
+ ****************************************************************************/
+
+static void pic16C5x_update_timer(int counts)
+{
+ if (PSA == 0) {
+ R.prescaler += counts;
+ if (R.prescaler >= (2 << PS)) { /* Prescale values from 2 to 256 */
+ R.TMR0 += (R.prescaler / (2 << PS));
+ R.prescaler %= (2 << PS); /* Overflow prescaler */
+ }
+ }
+ else {
+ R.TMR0 += counts;
+ }
+}
+
+
+/****************************************************************************
+ * Execute IPeriod. Return 0 if emulation should be stopped
+ ****************************************************************************/
+
+static int pic16C5x_execute(int cycles)
+{
+ int T0_in;
+ pic16C5x_icount = cycles;
+
+ do
+ {
+ if (PD == 0) /* Sleep Mode */
+ {
+ inst_cycles = (1*CLK);
+ CALL_MAME_DEBUG;
+ if (WDTE) {
+ pic16C5x_update_watchdog(1*CLK);
+ }
+ }
+ else
+ {
+ R.PREVPC = R.PC;
+
+ CALL_MAME_DEBUG;
+
+ R.opcode.d = M_RDOP(R.PC);
+ R.PC++;
+ R.PCL++;
+
+ if ((R.opcode.w.l & 0xff0) != 0x000) { /* Do all opcodes except the 00? ones */
+ inst_cycles = cycles_main[((R.opcode.w.l >> 4) & 0xff)];
+ (*(opcode_main[((R.opcode.w.l >> 4) & 0xff)]))();
+ }
+ else { /* Opcode 0x00? has many opcodes in its minor nibble */
+ inst_cycles = cycles_000_other[(R.opcode.b.l & 0x1f)];
+ (*(opcode_000_other[(R.opcode.b.l & 0x1f)]))();
+ }
+
+ if (T0CS) { /* Count mode */
+ T0_in = S_T0_IN;
+ if (T0SE) { /* Count rising edge */
+ if (POSITIVE_EDGE_T0) {
+ pic16C5x_update_timer(1);
+ }
+ }
+ else { /* Count falling edge */
+ if (NEGATIVE_EDGE_T0) {
+ pic16C5x_update_timer(1);
+ }
+ }
+ old_T0 = T0_in;
+ }
+ else { /* Timer mode */
+ if (delay_timer) {
+ delay_timer--;
+ }
+ else {
+ pic16C5x_update_timer((inst_cycles/CLK));
+ }
+ }
+ if (WDTE) {
+ pic16C5x_update_watchdog((inst_cycles/CLK));
+ }
+ }
+
+ pic16C5x_icount -= inst_cycles;
+
+ } while (pic16C5x_icount>0);
+
+ return cycles - pic16C5x_icount;
+}
+
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+
+static void pic16C5x_get_context (void *dst)
+{
+ if( dst )
+ *(pic16C5x_Regs*)dst = R;
+}
+
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+
+static void pic16C5x_set_context (void *src)
+{
+ if (src)
+ R = *(pic16C5x_Regs*)src;
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void pic16C5x_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + PIC16C5x_PC: R.PC = info->i; R.PCL = info->i & 0xff ;break;
+ /* This is actually not a stack pointer, but the stack contents */
+ /* Stack is a 2 level First In Last Out stack */
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + PIC16C5x_STK1: R.STACK[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_STK0: R.STACK[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_W: R.W = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_ALU: R.ALU = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_STR: R.STATUS = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_OPT: R.OPTION = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_TMR0: R.TMR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_WDT: R.WDT = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_PSCL: R.prescaler = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_PRTA: R.PORTA = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_PRTB: R.PORTB = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_PRTC: R.PORTC = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_FSR: R.FSR = (info->i & picRAMmask); break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void pic16C5x_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(R); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = PIC16C5x_CLOCK_DIVIDER; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1*CLK; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 10*CLK; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 9; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 5; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 5; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = R.PREVPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + PIC16C5x_PC: info->i = R.PC; break;
+ /* This is actually not a stack pointer, but the stack contents */
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + PIC16C5x_STK1: info->i = R.STACK[1]; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_STK0: info->i = R.STACK[0]; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_W: info->i = R.W; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_ALU: info->i = R.ALU; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_STR: info->i = R.STATUS; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_OPT: info->i = R.OPTION; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_TMR0: info->i = R.TMR0; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_WDT: info->i = R.WDT; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_PSCL: info->i = R.prescaler; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_PRTA: info->i = R.PORTA; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_PRTB: info->i = R.PORTB; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_PRTC: info->i = R.PORTC; break;
+ case CPUINFO_INT_REGISTER + PIC16C5x_FSR: info->i = (R.FSR & picRAMmask); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = pic16C5x_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = pic16C5x_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = pic16C5x_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = pic16C5x_init; break;
+ case CPUINFO_PTR_RESET: /* set per-CPU */ break;
+ case CPUINFO_PTR_EXIT: info->exit = pic16C5x_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = pic16C5x_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = pic16C5x_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &pic16C5x_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PIC16C5x"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Microchip"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.12"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C)2003+ by Tony La Porta"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%01x%c%c%c%c%c %c%c%c%03x",
+ (R.STATUS & 0xe0) >> 5,
+ R.STATUS & 0x10 ? '.':'O', /* WDT Overflow */
+ R.STATUS & 0x08 ? 'P':'D', /* Power/Down */
+ R.STATUS & 0x04 ? 'Z':'.', /* Zero */
+ R.STATUS & 0x02 ? 'c':'b', /* Nibble Carry/Borrow */
+ R.STATUS & 0x01 ? 'C':'B', /* Carry/Borrow */
+
+ R.OPTION & 0x20 ? 'C':'T', /* Counter/Timer */
+ R.OPTION & 0x10 ? 'N':'P', /* Negative/Positive */
+ R.OPTION & 0x08 ? 'W':'T', /* WatchDog/Timer */
+ R.OPTION & 0x08 ? (1<<(R.OPTION&7)) : (2<<(R.OPTION&7)) );
+ break;
+
+ case CPUINFO_STR_REGISTER + PIC16C5x_PC: sprintf(info->s, "PC:%03X", R.PC); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_W: sprintf(info->s, "W:%02X", R.W); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_ALU: sprintf(info->s, "ALU:%02X", R.ALU); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_STR: sprintf(info->s, "STR:%02X", R.STATUS); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_TMR0: sprintf(info->s, "TMR:%02X", R.TMR0); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_WDT: sprintf(info->s, "WDT:%04X", R.WDT); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_OPT: sprintf(info->s, "OPT:%02X", R.OPTION); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_STK0: sprintf(info->s, "STK0:%03X", R.STACK[0]); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_STK1: sprintf(info->s, "STK1:%03X", R.STACK[1]); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_PRTA: sprintf(info->s, "PRTA:%01X", ((R.PORTA) & 0xf)); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_PRTB: sprintf(info->s, "PRTB:%02X", R.PORTB); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_PRTC: sprintf(info->s, "PRTC:%02X", R.PORTC); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_TRSA: sprintf(info->s, "TRSA:%01X", ((R.TRISA) & 0xf)); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_TRSB: sprintf(info->s, "TRSB:%02X", R.TRISB); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_TRSC: sprintf(info->s, "TRSC:%02X", R.TRISC); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_FSR: sprintf(info->s, "FSR:%02X", ((R.FSR) & picRAMmask)); break;
+ case CPUINFO_STR_REGISTER + PIC16C5x_PSCL: sprintf(info->s, "PSCL:%c%02X", ((R.OPTION & 0x08) ? 'W':'T'), R.prescaler); break;
+ }
+}
+
+
+
+#if (HAS_PIC16C54)
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c54_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x1ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c54_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x1f) AM_RAM
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C54 Reset
+ ****************************************************************************/
+
+void pic16C54_reset(void)
+{
+ picmodel = 0x16C54;
+ picRAMmask = 0x1f;
+ pic16C5x_reset_vector = 0x1ff;
+ pic16C5x_reset_regs();
+ R.STATUS = 0x00;
+ SET(TO_FLAG);
+ SET(PD_FLAG);
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+void pic16C54_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_RESET: info->reset = pic16C54_reset; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_pic16c54_rom; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = construct_map_pic16c54_ram; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PIC16C54"); break;
+
+ default: pic16C5x_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_PIC16C55)
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c55_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x1ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c55_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x1f) AM_RAM
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C55 Reset
+ ****************************************************************************/
+
+void pic16C55_reset(void)
+{
+ picmodel = 0x16C55;
+ picRAMmask = 0x1f;
+ pic16C5x_reset_vector = 0x1ff;
+ pic16C5x_reset_regs();
+ R.STATUS = 0x00;
+ SET(TO_FLAG);
+ SET(PD_FLAG);
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+void pic16C55_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_RESET: info->reset = pic16C55_reset; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_pic16c55_rom; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = construct_map_pic16c55_ram; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PIC16C55"); break;
+
+ default: pic16C5x_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_PIC16C56)
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c56_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x3ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c56_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x1f) AM_RAM
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C56 Reset
+ ****************************************************************************/
+
+void pic16C56_reset(void)
+{
+ picmodel = 0x16C56;
+ picRAMmask = 0x1f;
+ pic16C5x_reset_vector = 0x3ff;
+ pic16C5x_reset_regs();
+ R.STATUS = 0x00;
+ SET(TO_FLAG);
+ SET(PD_FLAG);
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+void pic16C56_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_RESET: info->reset = pic16C56_reset; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_pic16c56_rom; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = construct_map_pic16c56_ram; break;
+
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 10; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PIC16C56"); break;
+
+ default: pic16C5x_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_PIC16C57)
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c57_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x7ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c57_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x1f) AM_RAM
+ AM_RANGE(0x30, 0x3f) AM_RAM
+ AM_RANGE(0x50, 0x5f) AM_RAM
+ AM_RANGE(0x70, 0x7f) AM_RAM
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C57 Reset
+ ****************************************************************************/
+
+void pic16C57_reset(void)
+{
+ picmodel = 0x16C57;
+ picRAMmask = 0x7f;
+ pic16C5x_reset_vector = 0x7ff;
+ pic16C5x_reset_regs();
+ R.STATUS = 0x00;
+ SET(TO_FLAG);
+ SET(PD_FLAG);
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+void pic16C57_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_RESET: info->reset = pic16C57_reset; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_pic16c57_rom; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = construct_map_pic16c57_ram; break;
+
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 11; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 7; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PIC16C57"); break;
+
+ default: pic16C5x_get_info(state, info); break;
+ }
+}
+#endif
+
+
+#if (HAS_PIC16C58)
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c58_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x7ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c58_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x1f) AM_RAM
+ AM_RANGE(0x30, 0x3f) AM_RAM
+ AM_RANGE(0x50, 0x5f) AM_RAM
+ AM_RANGE(0x70, 0x7f) AM_RAM
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C58 Reset
+ ****************************************************************************/
+
+void pic16C58_reset(void)
+{
+ picmodel = 0x16C58;
+ picRAMmask = 0x7f;
+ pic16C5x_reset_vector = 0x7ff;
+ pic16C5x_reset_regs();
+ R.STATUS = 0x00;
+ SET(TO_FLAG);
+ SET(PD_FLAG);
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+void pic16C58_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_RESET: info->reset = pic16C58_reset; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_pic16c58_rom; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = construct_map_pic16c58_ram; break;
+
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 11; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 7; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PIC16C58"); break;
+
+ default: pic16C5x_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/pic16c5x/pic16c5x.h b/src/emu/cpu/pic16c5x/pic16c5x.h
new file mode 100644
index 00000000000..bbe6f4a4baa
--- /dev/null
+++ b/src/emu/cpu/pic16c5x/pic16c5x.h
@@ -0,0 +1,137 @@
+ /**************************************************************************\
+ * Microchip PIC16C5x Emulator *
+ * *
+ * Copyright (C) 2003+ Tony La Porta *
+ * Originally written for the MAME project. *
+ * *
+ * *
+ * Addressing architecture is based on the Harvard addressing scheme. *
+ * *
+ \**************************************************************************/
+
+#ifndef _PIC16C5X_H
+#define _PIC16C5X_H
+
+
+#include "cpuintrf.h"
+
+
+/**************************************************************************
+ * Internal Clock divisor
+ *
+ * External Clock is divided internally by 4 for the instruction cycle
+ * times. (Each instruction cycle passes through 4 machine states).
+ */
+
+#define PIC16C5x_CLOCK_DIVIDER 4
+
+
+enum {
+ PIC16C5x_PC=1, PIC16C5x_STK0, PIC16C5x_STK1, PIC16C5x_FSR,
+ PIC16C5x_W, PIC16C5x_ALU, PIC16C5x_STR, PIC16C5x_OPT,
+ PIC16C5x_TMR0, PIC16C5x_PRTA, PIC16C5x_PRTB, PIC16C5x_PRTC,
+ PIC16C5x_WDT, PIC16C5x_TRSA, PIC16C5x_TRSB, PIC16C5x_TRSC,
+ PIC16C5x_PSCL
+};
+
+
+/****************************************************************************
+ * Function to configure the CONFIG register. This is actually hard-wired
+ * during ROM programming, so should be called in the driver INIT, with
+ * the value if known (available in HEX dumps of the ROM).
+ */
+
+void pic16c5x_config(int data);
+
+
+/****************************************************************************
+ * Read the state of the T0 Clock input signal
+ */
+
+#define PIC16C5x_T0 0x10
+#define PIC16C5x_T0_In (io_read_byte_8(PIC16C5x_T0))
+
+
+/****************************************************************************
+ * Input a word from given I/O port
+ */
+
+#define PIC16C5x_In(Port) ((UINT8)io_read_byte_8((Port)))
+
+
+/****************************************************************************
+ * Output a word to given I/O port
+ */
+
+#define PIC16C5x_Out(Port,Value) (io_write_byte_8((Port),Value))
+
+
+
+/****************************************************************************
+ * Read a word from given RAM memory location
+ */
+
+#define PIC16C5x_RAM_RDMEM(A) ((UINT8)data_read_byte_8(A))
+
+
+/****************************************************************************
+ * Write a word to given RAM memory location
+ */
+
+#define PIC16C5x_RAM_WRMEM(A,V) (data_write_byte_8(A,V))
+
+
+
+/****************************************************************************
+ * PIC16C5X_RDOP() is identical to PIC16C5X_RDMEM() except it is used for
+ * reading opcodes. In case of system with memory mapped I/O, this function
+ * can be used to greatly speed up emulation
+ */
+
+#define PIC16C5x_RDOP(A) (cpu_readop16((A)<<1))
+
+
+/****************************************************************************
+ * PIC16C5X_RDOP_ARG() is identical to PIC16C5X_RDOP() except it is used
+ * for reading opcode arguments. This difference can be used to support systems
+ * that use different encoding mechanisms for opcodes and opcode arguments
+ */
+
+#define PIC16C5x_RDOP_ARG(A) (cpu_readop_arg16((A)<<1))
+
+
+
+
+#if (HAS_PIC16C54)
+void pic16C54_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+
+#if (HAS_PIC16C55)
+void pic16C55_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+
+#if (HAS_PIC16C56)
+void pic16C56_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+
+#if (HAS_PIC16C57)
+void pic16C57_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+
+#if (HAS_PIC16C58)
+void pic16C58_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+
+#if (HAS_PIC16C54) || (HAS_PIC16C55) || (HAS_PIC16C56) || (HAS_PIC16C57) || (HAS_PIC16C58)
+#ifdef MAME_DEBUG
+offs_t pic16C5x_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+#endif
+
+
+#endif /* _PIC16C5X_H */
diff --git a/src/emu/cpu/powerpc/drc_ops.c b/src/emu/cpu/powerpc/drc_ops.c
new file mode 100644
index 00000000000..4dea2b561e5
--- /dev/null
+++ b/src/emu/cpu/powerpc/drc_ops.c
@@ -0,0 +1,3802 @@
+/* PowerPC common opcodes */
+
+// it really seems like this should be elsewhere - like maybe the floating point checks can hang out someplace else
+#include <math.h>
+
+#define USE_SSE2 0
+#define COMPILE_FPU 0
+
+/* recompiler flags */
+#define RECOMPILE_UNIMPLEMENTED 0x0000
+#define RECOMPILE_SUCCESSFUL 0x0001
+#define RECOMPILE_SUCCESSFUL_CP(c,p) (RECOMPILE_SUCCESSFUL | (((c) & 0xff) << 16) | (((p) & 0xff) << 24))
+#define RECOMPILE_END_OF_STRING 0x0002
+#define RECOMPILE_ADD_DISPATCH 0x0004
+
+INLINE void emit_mov_r64_m64(x86code **emitptr, UINT8 reghi, UINT8 reglo, DECLARE_MEMPARAMS)
+{
+ emit_mov_r32_m32(emitptr, reglo, MEMPARAMS);
+ emit_mov_r32_m32(emitptr, reghi, base, index, scale, disp+4);
+}
+
+INLINE void emit_mov_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 reghi, UINT8 reglo)
+{
+ emit_mov_m32_r32(emitptr, MEMPARAMS, reglo);
+ emit_mov_m32_r32(emitptr, base, index, scale, disp+4, reghi);
+}
+
+
+static UINT32 compile_one(drc_core *drc, UINT32 pc);
+
+static void append_generate_exception(drc_core *drc, UINT8 exception);
+static void append_check_interrupts(drc_core *drc, int inline_generate);
+static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 *opptr);
+
+static UINT32 temp_ppc_pc;
+
+static void ppcdrc_init(void)
+{
+ drc_config drconfig;
+
+ /* fill in the config */
+ memset(&drconfig, 0, sizeof(drconfig));
+ drconfig.cache_size = CACHE_SIZE;
+ drconfig.max_instructions = MAX_INSTRUCTIONS;
+ drconfig.address_bits = 32;
+ drconfig.lsbs_to_ignore = 2;
+ drconfig.uses_fp = 1;
+ drconfig.uses_sse = USE_SSE2;
+ drconfig.pc_in_memory = 0;
+ drconfig.icount_in_memory = 0;
+ drconfig.pcptr = (UINT32 *)&ppc.pc;
+ drconfig.icountptr = (UINT32 *)&ppc_icount;
+ drconfig.esiptr = NULL;
+ drconfig.cb_reset = ppcdrc_reset;
+ drconfig.cb_recompile = ppcdrc_recompile;
+ drconfig.cb_entrygen = ppcdrc_entrygen;
+
+ /* initialize the compiler */
+ ppc.drc = drc_init(cpu_getactivecpu(), &drconfig);
+ ppc.drcoptions = 0;
+}
+
+static void ppcdrc_reset(drc_core *drc)
+{
+ code_log_reset();
+
+ code_log("entry_point:", (x86code *)drc->entry_point, drc->out_of_cycles);
+ code_log("out_of_cycles:", drc->out_of_cycles, drc->recompile);
+ code_log("recompile:", drc->recompile, drc->dispatch);
+ code_log("dispatch:", drc->dispatch, drc->flush);
+ code_log("flush:", drc->flush, drc->cache_top);
+
+ ppc.invoke_exception_handler = drc->cache_top;
+ drc_append_restore_volatiles(drc);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4));
+ emit_mov_r32_m32(DRCTOP, REG_ESP, MABS(&ppc.host_esp));
+ emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */
+ emit_jmp_r32(DRCTOP, REG_EAX);
+ code_log("invoke_exception_handler:", ppc.invoke_exception_handler, drc->cache_top);
+
+ ppc.generate_interrupt_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_IRQ);
+ code_log("generate_interrupt_exception:", ppc.generate_interrupt_exception, drc->cache_top);
+
+ ppc.generate_syscall_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_SYSTEM_CALL);
+ code_log("generate_syscall_exception:", ppc.generate_syscall_exception, drc->cache_top);
+
+ ppc.generate_decrementer_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_DECREMENTER);
+ code_log("generate_decrementer_exception:", ppc.generate_decrementer_exception, drc->cache_top);
+
+ ppc.generate_trap_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_TRAP);
+ code_log("generate_trap_exception:", ppc.generate_trap_exception, drc->cache_top);
+
+ ppc.generate_dsi_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_DSI);
+ code_log("generate_dsi_exception:", ppc.generate_dsi_exception, drc->cache_top);
+
+ ppc.generate_isi_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_ISI);
+ code_log("generate_isi_exception:", ppc.generate_isi_exception, drc->cache_top);
+
+ if (!ppc.is603 && !ppc.is602)
+ {
+ ppc.generate_fit_exception = drc->cache_top;
+ append_generate_exception(drc, EXCEPTION_FIXED_INTERVAL_TIMER);
+ code_log("generate_fit_exception:", ppc.generate_fit_exception, drc->cache_top);
+ }
+}
+
+static UINT32 *ppcdrc_getopptr(UINT32 address)
+{
+ UINT32 *result;
+ UINT32 offset = 0;
+
+ if (ppc.is603 || ppc.is602)
+ {
+ if (MSR & MSR_IR)
+ {
+ if (!ppc_translate_address(&address, PPC_TRANSLATE_CODE | PPC_TRANSLATE_READ | PPC_TRANSLATE_NOEXCEPTION))
+ return NULL;
+ }
+ address = DWORD_XOR_BE(address);
+ offset = (address & 0x07) / sizeof(*result);
+ address &= ~0x07;
+ }
+
+ result = (UINT32 *) memory_get_op_ptr(cpu_getactivecpu(), address, 0);
+ if (result)
+ result += offset;
+ return result;
+}
+
+static void ppcdrc_recompile(drc_core *drc)
+{
+ int remaining = MAX_INSTRUCTIONS;
+ x86code *start = drc->cache_top;
+ UINT32 pc = ppc.pc;
+ UINT32 *opptr;
+
+ (void)start;
+
+ /* begin the sequence */
+ drc_begin_sequence(drc, pc);
+ code_log_reset();
+
+ /* loose verification case: one verification here only */
+ if (!(ppc.drcoptions & PPCDRC_OPTIONS_CHECK_SELFMOD_CODE))
+ {
+ opptr = ppcdrc_getopptr(pc);
+ if (opptr)
+ drc_append_verify_code(drc, opptr, 4);
+ }
+
+ /* loop until we hit an unconditional branch */
+ while (--remaining != 0)
+ {
+ UINT32 result;
+
+ /* compile one instruction */
+ result = compile_one(drc, pc);
+ pc += (INT8)(result >> 24);
+ if (result & RECOMPILE_END_OF_STRING)
+ break;
+
+ /* do not recompile across MMU page boundaries */
+ if ((pc & 0x0FFF) == 0)
+ {
+ remaining = 0;
+ break;
+ }
+ }
+
+ /* add dispatcher just in case */
+ if (remaining == 0)
+ drc_append_dispatcher(drc);
+
+ /* end the sequence */
+ drc_end_sequence(drc);
+
+#if LOG_CODE
+{
+ char label[40];
+ sprintf(label, "Code @ %08X", ppc.pc);
+ code_log(label, start, drc->cache_top);
+}
+#endif
+}
+
+static void update_counters(drc_core *drc)
+{
+ emit_link link1;
+
+ /* decrementer */
+ if (ppc.is603 || ppc.is602)
+ {
+ emit_cmp_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_dec_trigger_cycle));
+ emit_jcc_short_link(DRCTOP, COND_NZ, &link1);
+ emit_or_m32_imm(DRCTOP, MABS(&ppc.exception_pending), 0x2);
+ resolve_link(DRCTOP, &link1);
+ }
+
+ /* FIT */
+ if (!ppc.is603 && !ppc.is602)
+ {
+ emit_link link2;
+ emit_cmp_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_fit_trigger_cycle));
+ emit_jcc_short_link(DRCTOP, COND_NZ, &link1);
+ emit_cmp_r32_m32(DRCTOP, REG_EBP, MABS(&ppc.fit_int_enable));
+ emit_jcc_short_link(DRCTOP, COND_Z, &link2);
+ emit_or_m32_imm(DRCTOP, MABS(&ppc.exception_pending), 0x4);
+ resolve_link(DRCTOP, &link1);
+ resolve_link(DRCTOP, &link2);
+ }
+}
+
+static void ppcdrc_entrygen(drc_core *drc)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc.host_esp), REG_ESP);
+ append_check_interrupts(drc, 0);
+}
+
+static UINT32 compile_one(drc_core *drc, UINT32 pc)
+{
+ int pcdelta, cycles;
+ UINT32 *opptr;
+ UINT32 result;
+
+ /* register this instruction */
+ drc_register_code_at_cache_top(drc, pc);
+
+ /* get a pointer to the current instruction */
+ opptr = ppcdrc_getopptr(pc);
+
+ //log_symbol(drc, ~2);
+ //log_symbol(drc, pc);
+
+ /* emit debugging call */
+ drc_append_call_debugger(drc);
+
+ /* null opptr? if legit, we need to generate an ISI exception */
+ if (!opptr)
+ {
+ /* first check to see if the code is up to date; if not, recompile */
+ emit_push_imm(DRCTOP, pc);
+ emit_call(DRCTOP, (x86code *)ppcdrc_getopptr);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_cmp_r32_imm(DRCTOP, REG_EAX, 0);
+ emit_jcc(DRCTOP, COND_NZ, drc->recompile);
+
+ /* code is up to date; do the exception */
+ emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_isi_exception));
+ emit_jmp_r32(DRCTOP, REG_EAX);
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+ }
+
+ /* emit self-modifying code checks */
+ if (ppc.drcoptions & PPCDRC_OPTIONS_CHECK_SELFMOD_CODE)
+ {
+ drc_append_verify_code(drc, opptr, 4);
+ }
+
+ /* compile the instruction */
+ result = recompile_instruction(drc, pc, opptr);
+
+ /* handle the results */
+ if (!(result & RECOMPILE_SUCCESSFUL))
+ fatalerror("Unimplemented op %08X", *opptr);
+
+ pcdelta = (INT8)(result >> 24);
+ cycles = (INT8)(result >> 16);
+
+ /* epilogue */
+ update_counters(drc);
+ drc_append_standard_epilogue(drc, cycles, pcdelta, 1);
+
+ if (result & RECOMPILE_ADD_DISPATCH)
+ drc_append_dispatcher(drc);
+
+ return (result & 0xffff) | ((UINT8)cycles << 16) | ((UINT8)pcdelta << 24);
+}
+
+static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 *opptr)
+{
+ UINT32 opcode;
+ temp_ppc_pc = pc;
+
+ opcode = *opptr;
+
+ code_log_add_entry(pc, opcode, drc->cache_top);
+
+ if (opcode != 0) { // this is a little workaround for VF3
+ switch(opcode >> 26)
+ {
+ case 19: return optable19[(opcode >> 1) & 0x3ff](drc, opcode);
+ case 31: return optable31[(opcode >> 1) & 0x3ff](drc, opcode);
+ case 59: return optable59[(opcode >> 1) & 0x3ff](drc, opcode);
+ case 63: return optable63[(opcode >> 1) & 0x3ff](drc, opcode);
+ default: return optable[opcode >> 26](drc, opcode);
+ }
+ }
+ return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
+}
+
+
+static const UINT32 exception_vector[32] =
+{
+ 0x0000, 0x0500, 0x0900, 0x0700, 0x0c00, 0x1400, 0x0300, 0x0400,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x1010, 0x1020
+};
+
+static void append_generate_exception(drc_core *drc, UINT8 exception)
+{
+ emit_link link1, link2, link3;
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.msr));
+ emit_and_r32_imm(DRCTOP, REG_EAX, 0xff73);
+ emit_mov_m32_r32(DRCTOP, MABS(&SRR1), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.msr));
+
+ // Clear POW, EE, PR, FP, FE0, SE, BE, FE1, IR, DR, RI
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI));
+ // Set LE to ILE
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~MSR_LE); // clear LE first
+ emit_test_r32_imm(DRCTOP, REG_EAX, MSR_ILE);
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); // if Z == 0, bit == 1
+ emit_or_r32_imm(DRCTOP, REG_EAX, MSR_LE); // set LE
+ resolve_link(DRCTOP, &link1);
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)ppc_set_msr);
+ emit_pop_r32(DRCTOP, REG_EDX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ if (ppc.is603)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_EDI, exception_vector[exception]); // first move the exception handler offset
+ emit_test_r32_imm(DRCTOP, REG_EDX, MSR_IP); // test if the base should be 0xfff0 or EVPR
+ emit_jcc_short_link(DRCTOP, COND_Z, &link2); // if Z == 1, bit == 0 means base == 0x00000000
+ emit_or_r32_imm(DRCTOP, REG_EDI, 0xfff00000); // else base == 0xfff00000
+ resolve_link(DRCTOP, &link2);
+ }
+ else if (ppc.is602)
+ {
+ emit_mov_r32_imm(DRCTOP, REG_EDI, exception_vector[exception]); // first move the exception handler offset
+ emit_test_r32_imm(DRCTOP, REG_EDX, MSR_IP); // test if the base should be 0xfff0 or IBR
+ emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // if Z == 0, bit == 1 means base == 0xfff00000
+ emit_or_r32_m32(DRCTOP, REG_EDI, MABS(&ppc.ibr)); // else base == IBR
+ emit_jmp_short_link(DRCTOP, &link3);
+ resolve_link(DRCTOP, &link2);
+ emit_or_r32_imm(DRCTOP, REG_EDI, 0xfff00000);
+ resolve_link(DRCTOP, &link3);
+ }
+ else
+ {
+ emit_mov_r32_imm(DRCTOP, REG_EDI, exception_vector[exception]); // first move the exception handler offset
+ emit_test_r32_imm(DRCTOP, REG_EDX, MSR_IP); // test if the base should be 0xfff0 or EVPR
+ emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // if Z == 0, bit == 1 means base == 0xfff00000
+ emit_or_r32_m32(DRCTOP, REG_EDI, MABS(&EVPR)); // else base == EVPR
+ emit_jmp_short_link(DRCTOP, &link3);
+ resolve_link(DRCTOP, &link2);
+ emit_or_r32_imm(DRCTOP, REG_EDI, 0xfff00000);
+ resolve_link(DRCTOP, &link3);
+ }
+
+ if (exception == EXCEPTION_IRQ)
+ {
+ emit_and_m32_imm(DRCTOP, MABS(&ppc.exception_pending), ~0x1); // clear pending irq
+ }
+ if (exception == EXCEPTION_DECREMENTER)
+ {
+ emit_and_m32_imm(DRCTOP, MABS(&ppc.exception_pending), ~0x2); // clear pending decrementer exception
+ }
+ if (exception == EXCEPTION_FIXED_INTERVAL_TIMER)
+ {
+ emit_and_m32_imm(DRCTOP, MABS(&ppc.exception_pending), ~0x4); // clear pending fit exception
+ }
+
+ drc_append_dispatcher(drc);
+}
+
+static void append_check_interrupts(drc_core *drc, int inline_generate)
+{
+ if (ppc.is602 || ppc.is603)
+ {
+ emit_link link1, link2, link3, link4;
+ emit_test_m32_imm(DRCTOP, MABS(&ppc.msr), MSR_EE); /* no interrupt if external interrupts are not enabled */
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); /* ZF = 1 if bit == 0 */
+
+ /* else check if any interrupt are pending */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.exception_pending));
+ emit_cmp_r32_imm(DRCTOP, REG_EAX, 0);
+ emit_jcc_short_link(DRCTOP, COND_Z, &link2); /* reg == 0, no exceptions are pending */
+
+ /* else handle the first pending exception */
+ emit_test_r32_imm(DRCTOP, REG_EAX, 0x1); /* is it a IRQ? */
+ emit_jcc_short_link(DRCTOP, COND_Z, &link3);
+
+ emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_interrupt_exception));
+ emit_jmp_r32(DRCTOP, REG_EAX);
+ resolve_link(DRCTOP, &link3);
+
+ emit_test_r32_imm(DRCTOP, REG_EAX, 0x2); /* is it a decrementer exception */
+ emit_jcc_short_link(DRCTOP, COND_Z, &link4);
+ emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_decrementer_exception));
+ emit_jmp_r32(DRCTOP, REG_EAX);
+ resolve_link(DRCTOP, &link4);
+
+ resolve_link(DRCTOP, &link1);
+ resolve_link(DRCTOP, &link2);
+ }
+ else
+ {
+ emit_link link1, link2, link3, link4, link5, link6;
+ emit_test_m32_imm(DRCTOP, MABS(&ppc.msr), MSR_EE); /* no interrupt if external interrupts are not enabled */
+ emit_jcc_short_link(DRCTOP, COND_Z, &link1); /* ZF = 1 if bit == 0 */
+
+ /* else check if any interrupt are pending */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.exception_pending));
+ emit_cmp_r32_imm(DRCTOP, REG_EAX, 0);
+ emit_jcc_short_link(DRCTOP, COND_Z, &link2); /* reg == 0, no exceptions are pending */
+
+ /* else handle the first pending exception */
+ emit_test_r32_imm(DRCTOP, REG_EAX, 0x1); /* is it a IRQ? */
+ emit_jcc_short_link(DRCTOP, COND_Z, &link3);
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.exisr));
+ emit_and_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.exier));
+ emit_cmp_r32_imm(DRCTOP, REG_EAX, 0);
+ emit_jcc_short_link(DRCTOP, COND_Z, &link4);
+
+ emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_interrupt_exception));
+ emit_jmp_r32(DRCTOP, REG_EAX);
+
+ /* check if it's FIT exception */
+ resolve_link(DRCTOP, &link3);
+ emit_test_r32_imm(DRCTOP, REG_EAX, 0x4);
+ emit_jcc_short_link(DRCTOP, COND_Z, &link5);
+
+ // check if FIT interrupts are enabled
+ emit_test_m32_imm(DRCTOP, MABS(&ppc.fit_int_enable), 0x1);
+ emit_jcc_short_link(DRCTOP, COND_Z, &link6);
+
+ // calculate the next trigger cycle for FIT
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc_fit_trigger_cycle));
+ emit_sub_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.fit_bit));
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_fit_trigger_cycle), REG_EAX);
+
+ emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_fit_exception));
+ emit_jmp_r32(DRCTOP, REG_EAX);
+
+ resolve_link(DRCTOP, &link1);
+ resolve_link(DRCTOP, &link2);
+ resolve_link(DRCTOP, &link4);
+ resolve_link(DRCTOP, &link5);
+ resolve_link(DRCTOP, &link6);
+ }
+}
+
+static void append_branch_or_dispatch(drc_core *drc, UINT32 newpc, int cycles)
+{
+ void *code = drc_get_code_at_pc(drc, newpc);
+ emit_mov_r32_imm(DRCTOP, REG_EDI, newpc);
+
+ update_counters(drc);
+ append_check_interrupts(drc, 0);
+
+ drc_append_standard_epilogue(drc, cycles, 0, 1);
+
+
+ if (code)
+ emit_jmp(DRCTOP, code);
+ else
+ drc_append_tentative_fixed_dispatcher(drc, newpc);
+}
+
+/*
+// this table translates x86 SF and ZF flags to PPC CR values
+static UINT8 condition_table[4] =
+{
+ 0x4, // x86 SF == 0, ZF == 0 --> PPC GT (positive)
+ 0x2, // x86 SF == 0, ZF == 1 --> PPC EQ (zero)
+ 0x8, // x86 SF == 1, ZF == 0 --> PPC LT (negative)
+ 0x0, // x86 SF == 1, ZF == 1 (impossible)
+};
+*/
+
+// expects the result value in EDX!!!
+static void append_set_cr0(drc_core *drc)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX);
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_cmp_r32_imm(DRCTOP, REG_EDX, 0);
+/*
+ _lahf();
+
+ _shr_r32_imm(REG_EAX, 14);
+
+ _add_r32_imm(REG_EAX, &condition_table);
+ _mov_r8_m8bd(REG_BL, REG_EAX, 0);
+*/
+ emit_setcc_r8(DRCTOP, COND_Z, REG_AL);
+ emit_setcc_r8(DRCTOP, COND_L, REG_AH);
+ emit_setcc_r8(DRCTOP, COND_G, REG_BL);
+ emit_shl_r8_imm(DRCTOP, REG_AL, 1);
+ emit_shl_r8_imm(DRCTOP, REG_AH, 3);
+ emit_shl_r8_imm(DRCTOP, REG_BL, 2);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AH);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AL);
+
+ emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry
+ emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry
+
+ emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[0]), REG_BL);
+}
+
+#ifdef UNUSED_FUNCTION
+static void append_set_cr1(drc_core *drc)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.fpscr));
+ emit_shr_r32_imm(DRCTOP, REG_EAX, 28);
+ emit_and_r32_imm(DRCTOP, REG_EAX, 0xf);
+ emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[1]), REG_AL);
+}
+#endif
+
+static UINT32 recompile_addx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+
+ if (OEBIT) {
+ mame_printf_debug("recompile_addx: OE bit set !\n");
+ return RECOMPILE_UNIMPLEMENTED;
+ }
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_addcx(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER));
+ emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+
+ emit_setcc_r8(DRCTOP, COND_C, REG_AL); // carry to AL
+ emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // shift to carry bit
+ emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX);
+ emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX);
+
+ if (OEBIT) {
+ mame_printf_debug("recompile_addcx: OE bit set !\n");
+ return RECOMPILE_UNIMPLEMENTED;
+ }
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_addex(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_addex);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_addi(drc_core *drc, UINT32 op)
+{
+ if (RA == 0)
+ {
+ emit_mov_m32_imm(DRCTOP, MABS(&REG(RT)), SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_addic(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER));
+ emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry bit
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+
+ emit_setcc_r8(DRCTOP, COND_C, REG_AL); // carry to AL
+ emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // shift to carry bit
+ emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX);
+ emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_addic_rc(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER));
+ emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry bit
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+
+ emit_setcc_r8(DRCTOP, COND_C, REG_AL); // carry to AL
+ emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // shift to carry bit
+ emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX);
+ emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX);
+
+ append_set_cr0(drc);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_addis(drc_core *drc, UINT32 op)
+{
+ if (RA == 0)
+ {
+ emit_mov_m32_imm(DRCTOP, MABS(&REG(RT)), UIMM16 << 16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, UIMM16 << 16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_addmex(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_addmex);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_addzex(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_addzex);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_andx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_and_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_andcx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ emit_not_r32(DRCTOP, REG_EAX);
+ emit_and_r32_r32(DRCTOP, REG_EDX, REG_EAX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_andi_rc(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_and_r32_imm(DRCTOP, REG_EDX, UIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ append_set_cr0(drc);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_andis_rc(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_and_r32_imm(DRCTOP, REG_EDX, UIMM16 << 16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ append_set_cr0(drc);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_bx(drc_core *drc, UINT32 op)
+{
+ UINT32 newpc;
+ INT32 li = op & 0x3fffffc;
+ if( li & 0x2000000 )
+ li |= 0xfc000000;
+
+ if( AABIT ) {
+ newpc = li;
+ } else {
+ newpc = temp_ppc_pc + li;
+ }
+
+ if( LKBIT ) {
+ emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4);
+ }
+
+ append_branch_or_dispatch(drc, newpc, 1);
+
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+}
+
+static UINT32 recompile_bcx(drc_core *drc, UINT32 op)
+{
+ emit_link link1 = {0}, link2 = {0};
+ int do_link1 = 0, do_link2 = 0;
+ UINT32 newpc;
+
+ if( AABIT ) {
+ newpc = SIMM16 & ~0x3;
+ } else {
+ newpc = temp_ppc_pc + (SIMM16 & ~0x3);
+ }
+
+ if( LKBIT ) {
+ emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4);
+ }
+
+ if (BO == 20) /* condition is always true, so the basic block ends here */
+ {
+ append_branch_or_dispatch(drc, newpc, 1);
+
+ return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
+ }
+ else
+ {
+ // if BO[2] == 0, update CTR and check CTR condition
+ if ((BO & 0x4) == 0)
+ {
+ do_link1 = 1;
+ //_dec_m32abs(&CTR);
+ emit_sub_m32_imm(DRCTOP, MABS(&CTR), 1);
+
+ // if BO[1] == 0, branch if CTR != 0
+ if ((BO & 0x2) == 0)
+ {
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1);
+ }
+ else
+ {
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1);
+ }
+ }
+
+ // if BO[0] == 0, check condition
+ if ((BO & 0x10) == 0)
+ {
+ do_link2 = 1;
+ emit_movzx_r32_m8(DRCTOP, REG_EAX, MABS(&ppc.cr[(BI)/4]));
+ emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (3 - ((BI) & 0x3))); // test if condition register bit is set
+
+ // if BO[3] == 0, branch if condition == FALSE (bit zero)
+ if ((BO & 0x8) == 0)
+ {
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link2); // bit not zero, skip branch
+ }
+ // if BO[3] == 1, branch if condition == TRUE (bit not zero)
+ else
+ {
+ emit_jcc_near_link(DRCTOP, COND_Z, &link2); // bit zero, skip branch
+ }
+ }
+
+ // take the branch
+ append_branch_or_dispatch(drc, newpc, 1);
+
+ // skip the branch
+ if (do_link1) {
+ resolve_link(DRCTOP, &link1);
+ }
+ if (do_link2) {
+ resolve_link(DRCTOP, &link2);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ }
+}
+
+static UINT32 recompile_bcctrx(drc_core *drc, UINT32 op)
+{
+ emit_link link1 = {0} ,link2 = {0};
+ int do_link1 = 0, do_link2 = 0;
+
+ if (BO == 20) /* condition is always true, so the basic block ends here */
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&CTR)); // mov edi, CTR
+
+ if( LKBIT ) {
+ emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4);
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
+ }
+ else
+ {
+ // if BO[2] == 0, update CTR and check CTR condition
+ if ((BO & 0x4) == 0)
+ {
+ do_link1 = 1;
+ //_dec_m32abs(&CTR);
+ emit_sub_m32_imm(DRCTOP, MABS(&CTR), 1);
+
+ // if BO[1] == 0, branch if CTR != 0
+ if ((BO & 0x2) == 0)
+ {
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1);
+ }
+ else
+ {
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1);
+ }
+ }
+
+ // if BO[0] == 0, check condition
+ if ((BO & 0x10) == 0)
+ {
+ do_link2 = 1;
+ emit_movzx_r32_m8(DRCTOP, REG_EAX, MABS(&ppc.cr[(BI)/4]));
+ emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (3 - ((BI) & 0x3))); // test if condition register bit is set
+
+ // if BO[3] == 0, branch if condition == FALSE (bit zero)
+ if ((BO & 0x8) == 0)
+ {
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link2); // bit not zero, skip branch
+ }
+ // if BO[3] == 1, branch if condition == TRUE (bit not zero)
+ else
+ {
+ emit_jcc_near_link(DRCTOP, COND_Z, &link2); // bit zero, skip branch
+ }
+ }
+
+ // take the branch
+ emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&CTR)); // mov edi, CTR
+ if( LKBIT ) {
+ emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4);
+ }
+ append_check_interrupts(drc, 0);
+ drc_append_standard_epilogue(drc, 1, 0, 1);
+ drc_append_dispatcher(drc);
+
+ // skip the branch
+ if (do_link1) {
+ resolve_link(DRCTOP, &link1);
+ }
+ if (do_link2) {
+ resolve_link(DRCTOP, &link2);
+ }
+ if( LKBIT ) {
+ emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ }
+}
+
+static UINT32 recompile_bclrx(drc_core *drc, UINT32 op)
+{
+ emit_link link1 = {0}, link2 = {0};
+ int do_link1 = 0, do_link2 = 0;
+
+ if (BO == 20) /* condition is always true, so the basic block ends here */
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&LR)); // mov edi, LR
+
+ if( LKBIT ) {
+ emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4);
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
+ }
+ else
+ {
+ // if BO[2] == 0, update CTR and check CTR condition
+ if ((BO & 0x4) == 0)
+ {
+ do_link1 = 1;
+ //_dec_m32abs(&CTR);
+ emit_sub_m32_imm(DRCTOP, MABS(&CTR), 1);
+
+ // if BO[1] == 0, branch if CTR != 0
+ if ((BO & 0x2) == 0)
+ {
+ emit_jcc_near_link(DRCTOP, COND_Z, &link1);
+ }
+ else
+ {
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link1);
+ }
+ }
+
+ // if BO[0] == 0, check condition
+ if ((BO & 0x10) == 0)
+ {
+ do_link2 = 1;
+ emit_movzx_r32_m8(DRCTOP, REG_EAX, MABS(&ppc.cr[(BI)/4]));
+ emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (3 - ((BI) & 0x3))); // test if condition register bit is set
+
+ // if BO[3] == 0, branch if condition == FALSE (bit zero)
+ if ((BO & 0x8) == 0)
+ {
+ emit_jcc_near_link(DRCTOP, COND_NZ, &link2); // bit not zero, skip branch
+ }
+ // if BO[3] == 1, branch if condition == TRUE (bit not zero)
+ else
+ {
+ emit_jcc_near_link(DRCTOP, COND_Z, &link2); // bit zero, skip branch
+ }
+ }
+
+ // take the branch
+ emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&LR)); // mov edi, LR
+ if( LKBIT ) {
+ emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4);
+ }
+ append_check_interrupts(drc, 0);
+ drc_append_standard_epilogue(drc, 1, 0, 1);
+ drc_append_dispatcher(drc);
+
+ // skip the branch
+ if (do_link1) {
+ resolve_link(DRCTOP, &link1);
+ }
+ if (do_link2) {
+ resolve_link(DRCTOP, &link2);
+ }
+ if( LKBIT ) {
+ emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+ }
+}
+
+static UINT32 recompile_cmp(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX);
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RA)));
+ emit_cmp_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RB)));
+
+ emit_setcc_r8(DRCTOP, COND_Z, REG_AL);
+ emit_setcc_r8(DRCTOP, COND_L, REG_AH);
+ emit_setcc_r8(DRCTOP, COND_G, REG_BL);
+ emit_shl_r8_imm(DRCTOP, REG_AL, 1);
+ emit_shl_r8_imm(DRCTOP, REG_AH, 3);
+ emit_shl_r8_imm(DRCTOP, REG_BL, 2);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AH);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AL);
+
+ emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry
+ emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry
+ emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[CRFD]), REG_BL);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_cmpi(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX);
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RA)));
+ emit_cmp_r32_imm(DRCTOP, REG_ECX, SIMM16);
+
+ emit_setcc_r8(DRCTOP, COND_Z, REG_AL);
+ emit_setcc_r8(DRCTOP, COND_L, REG_AH);
+ emit_setcc_r8(DRCTOP, COND_G, REG_BL);
+ emit_shl_r8_imm(DRCTOP, REG_AL, 1);
+ emit_shl_r8_imm(DRCTOP, REG_AH, 3);
+ emit_shl_r8_imm(DRCTOP, REG_BL, 2);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AH);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AL);
+
+ emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry
+ emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry
+ emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[CRFD]), REG_BL);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_cmpl(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX);
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RA)));
+ emit_cmp_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RB)));
+
+ emit_setcc_r8(DRCTOP, COND_Z, REG_AL);
+ emit_setcc_r8(DRCTOP, COND_B, REG_AH);
+ emit_setcc_r8(DRCTOP, COND_A, REG_BL);
+ emit_shl_r8_imm(DRCTOP, REG_AL, 1);
+ emit_shl_r8_imm(DRCTOP, REG_AH, 3);
+ emit_shl_r8_imm(DRCTOP, REG_BL, 2);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AH);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AL);
+
+ emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry
+ emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry
+ emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[CRFD]), REG_BL);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_cmpli(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX);
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RA)));
+ emit_cmp_r32_imm(DRCTOP, REG_ECX, UIMM16);
+
+ emit_setcc_r8(DRCTOP, COND_Z, REG_AL);
+ emit_setcc_r8(DRCTOP, COND_B, REG_AH);
+ emit_setcc_r8(DRCTOP, COND_A, REG_BL);
+ emit_shl_r8_imm(DRCTOP, REG_AL, 1);
+ emit_shl_r8_imm(DRCTOP, REG_AH, 3);
+ emit_shl_r8_imm(DRCTOP, REG_BL, 2);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AH);
+ emit_or_r8_r8(DRCTOP, REG_BL, REG_AL);
+
+ emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry
+ emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry
+ emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[CRFD]), REG_BL);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_cntlzw(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX);
+ emit_mov_r32_imm(DRCTOP, REG_EDX, 31);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RT)));
+ emit_bsr_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_setcc_r8(DRCTOP, COND_Z, REG_BL); // if all zeros, set BL to 1, so result becomes 32
+ emit_sub_r32_r32(DRCTOP, REG_EDX, REG_EAX);
+ emit_add_r32_r32(DRCTOP, REG_EDX, REG_EBX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_crand(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_crand);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_crandc(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_crandc);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_creqv(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_creqv);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_crnand(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_crnand);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_crnor(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_crnor);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_cror(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_cror);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_crorc(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_crorc);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_crxor(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_crxor);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_dcbf(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_dcbi(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_dcbst(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_dcbt(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_dcbtst(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_dcbz(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_divwx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_divwx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_divwux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_divwux);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_eieio(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_eqvx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_xor_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_not_r32(DRCTOP, REG_EDX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_extsbx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_movsx_r32_r8(DRCTOP, REG_EDX, REG_DL);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_extshx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_movsx_r32_r16(DRCTOP, REG_EDX, REG_DX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_icbi(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_isync(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lbz(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (x86code *)READ8);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lbzu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ8);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lbzux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ8);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lbzx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)READ8);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lha(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (x86code *)READ16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lhau(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lhaux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lhax(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)READ16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lhbrx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)READ16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_imm(DRCTOP, REG_ECX, 8);
+ emit_rol_r16_cl(DRCTOP, REG_AX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lhz(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (x86code *)READ16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lhzu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lhzux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lhzx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)READ16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lmw(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_lmw);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lswi(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_lswi);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lswx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_lswx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lwarx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_lwarx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lwbrx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)READ32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_bswap_r32(DRCTOP, REG_EAX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lwz(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (x86code *)READ32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lwzu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lwzux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lwzx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)READ32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mcrf(drc_core *drc, UINT32 op)
+{
+ emit_mov_r8_m8(DRCTOP, REG_AL, MABS(&ppc.cr[RA >> 2]));
+ emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[RT >> 2]), REG_AL);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mcrxr(drc_core *drc, UINT32 op)
+{
+ mame_printf_debug("PPCDRC: recompile mcrxr\n");
+ return RECOMPILE_UNIMPLEMENTED;
+}
+
+static UINT32 recompile_mfcr(drc_core *drc, UINT32 op)
+{
+ int i;
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+
+ // generate code for each condition register
+ for (i=0; i < 8; i++)
+ {
+ emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX);
+ emit_mov_r8_m8(DRCTOP, REG_DL, MABS(&ppc.cr[i]));
+ emit_shl_r32_imm(DRCTOP, REG_EDX, ((7-i) * 4));
+ emit_or_r32_r32(DRCTOP, REG_EAX, REG_EDX);
+ }
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mfmsr(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.msr));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mfspr(drc_core *drc, UINT32 op)
+{
+ if (SPR == SPR_LR) // optimized case, LR
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&LR));
+ }
+ else if(SPR == SPR_CTR) // optimized case, CTR
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&CTR));
+ }
+ else
+ {
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, SPR);
+ emit_call(DRCTOP, (x86code *)ppc_get_spr);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ }
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtcrf(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mtcrf);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtmsr(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)ppc_set_msr);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtspr(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ if (SPR == SPR_LR) // optimized case, LR
+ {
+ emit_mov_m32_r32(DRCTOP, MABS(&LR), REG_EAX);
+ }
+ else if(SPR == SPR_CTR) // optimized case, CTR
+ {
+ emit_mov_m32_r32(DRCTOP, MABS(&CTR), REG_EAX);
+ }
+ else
+ {
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_push_imm(DRCTOP, SPR);
+ emit_call(DRCTOP, (x86code *)ppc_set_spr);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mulhwx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&REG(RB)));
+ emit_imul_r32(DRCTOP, REG_EBX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mulhwux(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&REG(RB)));
+ emit_mul_r32(DRCTOP, REG_EBX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mulli(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_mov_r32_imm(DRCTOP, REG_EBX, SIMM16);
+ emit_imul_r32(DRCTOP, REG_EBX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EAX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mullwx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&REG(RB)));
+ emit_mul_r32(DRCTOP, REG_EBX);
+ emit_mov_r32_r32(DRCTOP, REG_EDX, REG_EAX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+
+ if (OEBIT) {
+ mame_printf_debug("recompile_mullwx: OEBIT set!\n");
+ return RECOMPILE_UNIMPLEMENTED;
+ }
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_nandx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_and_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_not_r32(DRCTOP, REG_EDX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_negx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_neg_r32(DRCTOP, REG_EDX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_norx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_or_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_not_r32(DRCTOP, REG_EDX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_orx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_or_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_orcx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_not_r32(DRCTOP, REG_EDX);
+ emit_or_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_ori(drc_core *drc, UINT32 op)
+{
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_or_r32_imm(DRCTOP, REG_EAX, UIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EAX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_oris(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_or_r32_imm(DRCTOP, REG_EAX, UIMM16 << 16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EAX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_rfi(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&ppc.srr0)); /* get saved PC from SRR0 */
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.srr1)); /* get saved MSR from SRR1 */
+
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)ppc_set_msr); /* set MSR */
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
+}
+
+static UINT32 recompile_rlwimix(drc_core *drc, UINT32 op)
+{
+ UINT32 mask = GET_ROTATE_MASK(MB, ME);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_rol_r32_imm(DRCTOP, REG_EDX, (SH));
+ emit_and_r32_imm(DRCTOP, REG_EDX, mask);
+ emit_and_r32_imm(DRCTOP, REG_EAX, ~mask);
+ emit_or_r32_r32(DRCTOP, REG_EDX, REG_EAX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_rlwinmx(drc_core *drc, UINT32 op)
+{
+ UINT32 mask = GET_ROTATE_MASK(MB, ME);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_rol_r32_imm(DRCTOP, REG_EDX, (SH));
+ emit_and_r32_imm(DRCTOP, REG_EDX, mask);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_rlwnmx(drc_core *drc, UINT32 op)
+{
+ UINT32 mask = GET_ROTATE_MASK(MB, ME);
+
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RB))); // x86 rotate instruction use only 5 bits, so no need to mask this
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_rol_r32_cl(DRCTOP, REG_EDX);
+ emit_and_r32_imm(DRCTOP, REG_EDX, mask);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_sc(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_imm(DRCTOP, MABS(&SRR0), temp_ppc_pc + 4);
+ emit_jmp(DRCTOP, ppc.generate_syscall_exception);
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_slwx(drc_core *drc, UINT32 op)
+{
+#if USE_SSE2
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RB)));
+ emit_and_r32_imm(DRCTOP, REG_ECX, 0x3f);
+ emit_movd_r128_m32(DRCTOP, REG_XMM0, MABS(&REG(RS)));
+ emit_movd_r128_r32(DRCTOP, REG_XMM1, REG_ECX);
+ emit_psllq_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movd_r32_r128(DRCTOP, REG_EDX, REG_XMM0);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+#else
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_slwx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_srawx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_srawx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_srawix(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_srawix);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_srwx(drc_core *drc, UINT32 op)
+{
+#if USE_SSE2
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RB)));
+ emit_and_r32_imm(DRCTOP, REG_ECX, 0x3f);
+ emit_movd_r128_m32(DRCTOP, REG_XMM0, MABS(&REG(RS)));
+ emit_movd_r128_r32(DRCTOP, REG_XMM1, REG_ECX);
+ emit_psrlq_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movd_r32_r128(DRCTOP, REG_EDX, REG_XMM0);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+#else
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_srwx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stb(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (x86code *)WRITE8);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stbu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)WRITE8);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stbux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)WRITE8);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stbx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)WRITE8);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_sth(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EDX);
+ }
+ emit_call(DRCTOP, (x86code *)WRITE16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_sthbrx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX);
+ emit_mov_r32_imm(DRCTOP, REG_ECX, 8);
+ emit_rol_r16_cl(DRCTOP, REG_AX);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)WRITE16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_sthu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)WRITE16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_sthux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)WRITE16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_sthx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)WRITE16);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stmw(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stmw);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stswi(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stswi);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stswx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stswx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stw(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_m32(DRCTOP, MABS(&REG(RS)));
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stwbrx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RS)));
+ emit_bswap_r32(DRCTOP, REG_EAX);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stwcx_rc(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stwcx_rc);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stwu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_m32(DRCTOP, MABS(&REG(RS)));
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EAX);
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stwux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_m32(DRCTOP, MABS(&REG(RS)));
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EAX);
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stwx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_m32(DRCTOP, MABS(&REG(RS)));
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_subfx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_sub_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+
+ if (OEBIT) {
+ mame_printf_debug("recompile_subfx: OEBIT set !\n");
+ return RECOMPILE_UNIMPLEMENTED;
+ }
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_subfcx(drc_core *drc, UINT32 op)
+{
+ if (OEBIT)
+ {
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_subfcx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+ }
+ else
+ {
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER));
+ emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_sub_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+ emit_setcc_r8(DRCTOP, COND_NC, REG_AL); // subtract carry is inverse
+ emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // move carry to correct location in XER
+ emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX); // insert carry to XER
+ emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX);
+
+ //if (OEBIT) {
+ // mame_printf_debug("recompile_subfcx: OEBIT set !\n");
+ // return RECOMPILE_UNIMPLEMENTED;
+ //}
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+ }
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_subfex(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER));
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(&REG(RA)));
+ emit_bt_r32_imm(DRCTOP, REG_EBX, 29); // XER carry to carry flag
+ emit_cmc(DRCTOP); // invert carry
+ emit_adc_r32_imm(DRCTOP, REG_ECX, 0);
+ emit_sub_r32_r32(DRCTOP, REG_EDX, REG_ECX);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+ emit_setcc_r8(DRCTOP, COND_NC, REG_AL); // subtract carry is inverse
+ emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry
+ emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // move carry to correct location in XER
+ emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX); // insert carry to XER
+ emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX);
+
+ if (OEBIT) {
+ mame_printf_debug("recompile_subfex: OEBIT set !\n");
+ return RECOMPILE_UNIMPLEMENTED;
+ }
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_subfic(drc_core *drc, UINT32 op)
+{
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER));
+ emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry
+ emit_mov_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_sub_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RT)), REG_EDX);
+ emit_setcc_r8(DRCTOP, COND_NC, REG_AL); // subtract carry is inverse
+ emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // move carry to correct location in XER
+ emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX); // insert carry to XER
+ emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_subfmex(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_subfmex);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_subfzex(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_subfzex);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_sync(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_tw(drc_core *drc, UINT32 op)
+{
+ emit_link link1 = {0}, link2 = {0}, link3 = {0}, link4 = {0}, link5 = {0}, link6 = {0};
+ int do_link1 = 0;
+ int do_link2 = 0;
+ int do_link3 = 0;
+ int do_link4 = 0;
+ int do_link5 = 0;
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_cmp_r32_r32(DRCTOP, REG_EAX, REG_EDX);
+
+ if (RT & 0x10) {
+ emit_jcc_near_link(DRCTOP, COND_L, &link1); // less than = signed <
+ do_link1 = 1;
+ }
+ if (RT & 0x08) {
+ emit_jcc_near_link(DRCTOP, COND_G, &link2); // greater = signed >
+ do_link2 = 1;
+ }
+ if (RT & 0x04) {
+ emit_jcc_near_link(DRCTOP, COND_E, &link3); // equal
+ do_link3 = 1;
+ }
+ if (RT & 0x02) {
+ emit_jcc_near_link(DRCTOP, COND_B, &link4); // below = unsigned <
+ do_link4 = 1;
+ }
+ if (RT & 0x01) {
+ emit_jcc_near_link(DRCTOP, COND_A, &link5); // above = unsigned >
+ do_link5 = 1;
+ }
+ emit_jmp_near_link(DRCTOP, &link6);
+
+ if (do_link1) {
+ resolve_link(DRCTOP, &link1);
+ }
+ if (do_link2) {
+ resolve_link(DRCTOP, &link2);
+ }
+ if (do_link3) {
+ resolve_link(DRCTOP, &link3);
+ }
+ if (do_link4) {
+ resolve_link(DRCTOP, &link4);
+ }
+ if (do_link5) {
+ resolve_link(DRCTOP, &link5);
+ }
+ // generate exception
+ emit_mov_m32_imm(DRCTOP, MABS(&SRR0), temp_ppc_pc + 4);
+ emit_jmp(DRCTOP, ppc.generate_trap_exception);
+
+ // no exception
+ resolve_link(DRCTOP, &link6);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_twi(drc_core *drc, UINT32 op)
+{
+ emit_link link1 = {0}, link2 = {0}, link3 = {0}, link4 = {0}, link5 = {0}, link6 = {0};
+ int do_link1 = 0;
+ int do_link2 = 0;
+ int do_link3 = 0;
+ int do_link4 = 0;
+ int do_link5 = 0;
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_mov_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_cmp_r32_r32(DRCTOP, REG_EAX, REG_EDX);
+
+ if (RT & 0x10) {
+ emit_jcc_near_link(DRCTOP, COND_L, &link1); // less than = signed <
+ do_link1 = 1;
+ }
+ if (RT & 0x08) {
+ emit_jcc_near_link(DRCTOP, COND_G, &link2); // greater = signed >
+ do_link2 = 1;
+ }
+ if (RT & 0x04) {
+ emit_jcc_near_link(DRCTOP, COND_E, &link3); // equal
+ do_link3 = 1;
+ }
+ if (RT & 0x02) {
+ emit_jcc_near_link(DRCTOP, COND_B, &link4); // below = unsigned <
+ do_link4 = 1;
+ }
+ if (RT & 0x01) {
+ emit_jcc_near_link(DRCTOP, COND_A, &link5); // above = unsigned >
+ do_link5 = 1;
+ }
+ emit_jmp_near_link(DRCTOP, &link6);
+
+ if (do_link1) {
+ resolve_link(DRCTOP, &link1);
+ }
+ if (do_link2) {
+ resolve_link(DRCTOP, &link2);
+ }
+ if (do_link3) {
+ resolve_link(DRCTOP, &link3);
+ }
+ if (do_link4) {
+ resolve_link(DRCTOP, &link4);
+ }
+ if (do_link5) {
+ resolve_link(DRCTOP, &link5);
+ }
+ // generate exception
+ emit_mov_m32_imm(DRCTOP, MABS(&SRR0), temp_ppc_pc + 4);
+ emit_jmp(DRCTOP, ppc.generate_trap_exception);
+
+ // no exception
+ resolve_link(DRCTOP, &link6);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_xorx(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_xor_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ if (RCBIT) {
+ append_set_cr0(drc);
+ }
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_xori(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_xor_r32_imm(DRCTOP, REG_EDX, UIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_xoris(drc_core *drc, UINT32 op)
+{
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RS)));
+ emit_xor_r32_imm(DRCTOP, REG_EDX, UIMM16 << 16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+#if HAS_PPC403
+static UINT32 recompile_dccci(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_dcread(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_icbt(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_iccci(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_icread(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_rfci(drc_core *drc, UINT32 op)
+{
+ mame_printf_debug("PPCDRC: recompile rfci\n");
+ return RECOMPILE_UNIMPLEMENTED;
+}
+
+static UINT32 recompile_mfdcr(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mfdcr);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtdcr(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mtdcr);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_wrtee(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_wrtee);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_wrteei(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_wrteei);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+#endif
+
+
+
+static UINT32 recompile_invalid(drc_core *drc, UINT32 op)
+{
+ mame_printf_debug("PPCDRC: Invalid opcode %08X PC : %X\n", op, ppc.pc);
+ return RECOMPILE_UNIMPLEMENTED;
+}
+
+
+
+/* PowerPC 60x Recompilers */
+
+#if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_MPC8240)
+static UINT32 recompile_lfs(drc_core *drc,UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+#if USE_SSE2
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (genf*)READ32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movd_r128_r32(DRCTOP, REG_XMM0, REG_EAX);
+ emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert float to double
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM1);
+#else
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_lfs);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+#endif
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lfsu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+#if USE_SSE2
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movd_r128_r32(DRCTOP, REG_XMM0, REG_EAX);
+ emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert float to double
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM1);
+#else
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_lfsu);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+#endif
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lfd(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (x86code *)READ64);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lfdu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ64);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stfs(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+#if USE_SSE2
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT)));
+ emit_cvtsd2ss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert double to float
+ emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM1);
+ emit_push_r32(DRCTOP, REG_EAX);
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+#else
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stfs);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+#endif
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stfsu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+#if USE_SSE2
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT)));
+ emit_cvtsd2ss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert double to float
+ emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM1);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EAX);
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+#else
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stfsu);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+#endif
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stfd(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RT)));
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_push_r32(DRCTOP, REG_EAX);
+ if (RA == 0)
+ {
+ emit_push_imm(DRCTOP, SIMM16);
+ }
+ else
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_push_r32(DRCTOP, REG_EAX);
+ }
+ emit_call(DRCTOP, (x86code *)WRITE64);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stfdu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RT)));
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16);
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EAX);
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE64);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lfdux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ64);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lfdx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)READ64);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lfsux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+#if USE_SSE2
+ emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EDX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EDX);
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_call(DRCTOP, (x86code *)READ32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movd_r128_r32(DRCTOP, REG_XMM0, REG_EAX);
+ emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert float to double
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM1);
+#else
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_lfsux);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+#endif
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_lfsx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+#if USE_SSE2
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)READ32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_movd_r128_r32(DRCTOP, REG_XMM0, REG_EAX);
+ emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert float to double
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM1);
+#else
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_lfsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+#endif
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mfsr(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mfsr);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mfsrin(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mfsrin);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mftb(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mftb);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtsr(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mtsr);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtsrin(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mtsrin);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_dcba(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stfdux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RT)));
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EAX);
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE64);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stfdx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RT)));
+ emit_push_r32(DRCTOP, REG_EDX);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE64);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 12);
+
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stfdx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stfiwx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+#if USE_SSE2
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT)));
+ emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM0);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+#else
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stfiwx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+#endif
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stfsux(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+#if USE_SSE2
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT)));
+ emit_cvtsd2ss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert double to float
+ emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM1);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ emit_mov_m32_r32(DRCTOP, MABS(&REG(RA)), REG_EAX);
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+#else
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stfsux);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+#endif
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_stfsx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+#if USE_SSE2
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT)));
+ emit_cvtsd2ss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert double to float
+ emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM1);
+ emit_push_r32(DRCTOP, REG_EAX);
+
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RB)));
+ if (RA != 0)
+ {
+ emit_add_r32_m32(DRCTOP, REG_EAX, MABS(&REG(RA)));
+ }
+ emit_push_r32(DRCTOP, REG_EAX);
+ emit_call(DRCTOP, (x86code *)WRITE32);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 8);
+#else
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_stfsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+#endif
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_tlbia(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_tlbie(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_tlbsync(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_eciwx(drc_core *drc, UINT32 op)
+{
+ mame_printf_debug("PPCDRC: eciwx unimplemented\n");
+ return RECOMPILE_UNIMPLEMENTED;
+}
+
+static UINT32 recompile_ecowx(drc_core *drc, UINT32 op)
+{
+ mame_printf_debug("PPCDRC: ecowx unimplemented\n");
+ return RECOMPILE_UNIMPLEMENTED;
+}
+
+static UINT32 recompile_fabsx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fabsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RB)));
+ emit_and_r32_imm(DRCTOP, REG_EDX, 0x7fffffff);
+ emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_faddx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_faddx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB)));
+ emit_addsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fcmpo(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fcmpo);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fcmpu(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fcmpu);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fctiwx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fctiwx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fctiwzx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fctiwzx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fdivx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fdivx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB)));
+ emit_divsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fmrx(drc_core *drc, UINT32 op)
+{
+#if USE_SSE2
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RB)));
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#else
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fmrx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fnabsx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fnabsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RB)));
+ emit_or_r32_imm(DRCTOP, REG_EDX, 0x80000000);
+ emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fnegx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fnegx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RB)));
+ emit_xor_r32_imm(DRCTOP, REG_EDX, 0x80000000);
+ emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_frspx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_frspx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+/*
+ _movq_r128_m64(REG_XMM0, MABS(&FPR(RB)));
+ _movq_m64abs_r128(&FPR(RT), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+*/
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_frsqrtex(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_frsqrtex);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fsqrtx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fsqrtx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fsubx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fsubx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB)));
+ emit_subsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mffsx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mffsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtfsb0x(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mtfsb0x);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtfsb1x(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mtfsb1x);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtfsfx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mtfsfx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mtfsfix(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mtfsfix);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_mcrfs(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_mcrfs);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_faddsx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_faddsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB)));
+ emit_addsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fdivsx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fdivsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB)));
+ emit_divsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fresx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fresx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fsqrtsx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fsqrtsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fsubsx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fsubsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB)));
+ emit_subsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fmaddx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fmaddx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM2, MABS(&FPR(RB)));
+ emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_addsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM2);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fmsubx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fmsubx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM2, MABS(&FPR(RB)));
+ emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_subsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM2);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fmulx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fmulx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC)));
+ emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fnmaddx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fnmaddx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fnmsubx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fnmsubx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fselx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fselx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fmaddsx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fmaddsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM2, MABS(&FPR(RB)));
+ emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_addsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM2);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fmsubsx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fmsubsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM2, MABS(&FPR(RB)));
+ emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_subsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM2);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fmulsx(drc_core *drc, UINT32 op)
+{
+#if !COMPILE_FPU || !USE_SSE2
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fmulsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+#else
+ emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA)));
+ emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC)));
+ emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1);
+ emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0);
+
+ if (RCBIT) {
+ append_set_cr1(drc);
+ }
+#endif
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fnmaddsx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fnmaddsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_fnmsubsx(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_fnmsubsx);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+#endif
+
+// PPC602
+
+#if (HAS_PPC602)
+static UINT32 recompile_esa(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_esa);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_dsa(drc_core *drc, UINT32 op)
+{
+ emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP);
+ emit_push_imm(DRCTOP, op);
+ emit_call(DRCTOP, (x86code *)ppc_dsa);
+ emit_add_r32_imm(DRCTOP, REG_ESP, 4);
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount));
+
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+#endif /* HAS_PPC602 */
+
+#if (HAS_PPC602 || HAS_MPC8240)
+static UINT32 recompile_tlbli(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+
+static UINT32 recompile_tlbld(drc_core *drc, UINT32 op)
+{
+ return RECOMPILE_SUCCESSFUL_CP(1,4);
+}
+#endif
+
diff --git a/src/emu/cpu/powerpc/drc_ops.h b/src/emu/cpu/powerpc/drc_ops.h
new file mode 100644
index 00000000000..1bb7b29c517
--- /dev/null
+++ b/src/emu/cpu/powerpc/drc_ops.h
@@ -0,0 +1,143 @@
+static PPC_OPCODE ppcdrc_opcode_common[] =
+{
+ /*code subcode handler */
+ { 31, 266, recompile_addx },
+ { 31, 266 | 512, recompile_addx },
+ { 31, 10, recompile_addcx },
+ { 31, 10 | 512, recompile_addcx },
+ { 31, 138, recompile_addex },
+ { 31, 138 | 512, recompile_addex },
+ { 14, -1, recompile_addi },
+ { 12, -1, recompile_addic },
+ { 13, -1, recompile_addic_rc },
+ { 15, -1, recompile_addis },
+ { 31, 234, recompile_addmex },
+ { 31, 234 | 512, recompile_addmex },
+ { 31, 202, recompile_addzex },
+ { 31, 202 | 512, recompile_addzex },
+ { 31, 28, recompile_andx },
+ { 31, 28 | 512, recompile_andx },
+ { 31, 60, recompile_andcx },
+ { 28, -1, recompile_andi_rc },
+ { 29, -1, recompile_andis_rc },
+ { 18, -1, recompile_bx },
+ { 16, -1, recompile_bcx },
+ { 19, 528, recompile_bcctrx },
+ { 19, 16, recompile_bclrx },
+ { 31, 0, recompile_cmp },
+ { 11, -1, recompile_cmpi },
+ { 31, 32, recompile_cmpl },
+ { 10, -1, recompile_cmpli },
+ { 31, 26, recompile_cntlzw },
+ { 19, 257, recompile_crand },
+ { 19, 129, recompile_crandc },
+ { 19, 289, recompile_creqv },
+ { 19, 225, recompile_crnand },
+ { 19, 33, recompile_crnor },
+ { 19, 449, recompile_cror },
+ { 19, 417, recompile_crorc },
+ { 19, 193, recompile_crxor },
+ { 31, 86, recompile_dcbf },
+ { 31, 470, recompile_dcbi },
+ { 31, 54, recompile_dcbst },
+ { 31, 278, recompile_dcbt },
+ { 31, 246, recompile_dcbtst },
+ { 31, 1014, recompile_dcbz },
+ { 31, 491, recompile_divwx },
+ { 31, 491 | 512, recompile_divwx },
+ { 31, 459, recompile_divwux },
+ { 31, 459 | 512, recompile_divwux },
+ { 31, 854, recompile_eieio },
+ { 31, 284, recompile_eqvx },
+ { 31, 954, recompile_extsbx },
+ { 31, 922, recompile_extshx },
+ { 31, 982, recompile_icbi },
+ { 19, 150, recompile_isync },
+ { 34, -1, recompile_lbz },
+ { 35, -1, recompile_lbzu },
+ { 31, 119, recompile_lbzux },
+ { 31, 87, recompile_lbzx },
+ { 42, -1, recompile_lha },
+ { 43, -1, recompile_lhau },
+ { 31, 375, recompile_lhaux },
+ { 31, 343, recompile_lhax },
+ { 31, 790, recompile_lhbrx },
+ { 40, -1, recompile_lhz },
+ { 41, -1, recompile_lhzu },
+ { 31, 311, recompile_lhzux },
+ { 31, 279, recompile_lhzx },
+ { 46, -1, recompile_lmw },
+ { 31, 597, recompile_lswi },
+ { 31, 533, recompile_lswx },
+ { 31, 20, recompile_lwarx },
+ { 31, 534, recompile_lwbrx },
+ { 32, -1, recompile_lwz },
+ { 33, -1, recompile_lwzu },
+ { 31, 55, recompile_lwzux },
+ { 31, 23, recompile_lwzx },
+ { 19, 0, recompile_mcrf },
+ { 31, 512, recompile_mcrxr },
+ { 31, 19, recompile_mfcr },
+ { 31, 83, recompile_mfmsr },
+ { 31, 339, recompile_mfspr },
+ { 31, 144, recompile_mtcrf },
+ { 31, 146, recompile_mtmsr },
+ { 31, 467, recompile_mtspr },
+ { 31, 75, recompile_mulhwx },
+ { 31, 11, recompile_mulhwux },
+ { 7, -1, recompile_mulli },
+ { 31, 235, recompile_mullwx },
+ { 31, 235 | 512, recompile_mullwx },
+ { 31, 476, recompile_nandx },
+ { 31, 104, recompile_negx },
+ { 31, 104 | 512, recompile_negx },
+ { 31, 124, recompile_norx },
+ { 31, 444, recompile_orx },
+ { 31, 412, recompile_orcx },
+ { 24, -1, recompile_ori },
+ { 25, -1, recompile_oris },
+ { 19, 50, recompile_rfi },
+ { 20, -1, recompile_rlwimix },
+ { 21, -1, recompile_rlwinmx },
+ { 23, -1, recompile_rlwnmx },
+ { 17, -1, recompile_sc },
+ { 31, 24, recompile_slwx },
+ { 31, 792, recompile_srawx },
+ { 31, 824, recompile_srawix },
+ { 31, 536, recompile_srwx },
+ { 38, -1, recompile_stb },
+ { 39, -1, recompile_stbu },
+ { 31, 247, recompile_stbux },
+ { 31, 215, recompile_stbx },
+ { 44, -1, recompile_sth },
+ { 31, 918, recompile_sthbrx },
+ { 45, -1, recompile_sthu },
+ { 31, 439, recompile_sthux },
+ { 31, 407, recompile_sthx },
+ { 47, -1, recompile_stmw },
+ { 31, 725, recompile_stswi },
+ { 31, 661, recompile_stswx },
+ { 36, -1, recompile_stw },
+ { 31, 662, recompile_stwbrx },
+ { 31, 150, recompile_stwcx_rc },
+ { 37, -1, recompile_stwu },
+ { 31, 183, recompile_stwux },
+ { 31, 151, recompile_stwx },
+ { 31, 40, recompile_subfx },
+ { 31, 40 | 512, recompile_subfx },
+ { 31, 8, recompile_subfcx },
+ { 31, 8 | 512, recompile_subfcx },
+ { 31, 136, recompile_subfex },
+ { 31, 136 | 512, recompile_subfex },
+ { 8, -1, recompile_subfic },
+ { 31, 232, recompile_subfmex },
+ { 31, 232 | 512, recompile_subfmex },
+ { 31, 200, recompile_subfzex },
+ { 31, 200 | 512, recompile_subfzex },
+ { 31, 598, recompile_sync },
+ { 31, 4, recompile_tw },
+ { 3, -1, recompile_twi },
+ { 31, 316, recompile_xorx },
+ { 26, -1, recompile_xori },
+ { 27, -1, recompile_xoris }
+};
diff --git a/src/emu/cpu/powerpc/ppc.c b/src/emu/cpu/powerpc/ppc.c
new file mode 100644
index 00000000000..ff371fda52a
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppc.c
@@ -0,0 +1,1938 @@
+/* IBM/Motorola PowerPC 4xx/6xx Emulator */
+
+#include <setjmp.h>
+#include "ppc.h"
+#include "debugger.h"
+
+#if (HAS_PPC603 || HAS_PPC601)
+void ppc603_exception(int exception);
+#endif
+#if (HAS_PPC602)
+void ppc602_exception(int exception);
+#endif
+#if (HAS_PPC403)
+void ppc403_exception(int exception);
+UINT8 ppc403_spu_r(UINT32 a);
+void ppc403_spu_w(UINT32 a, UINT8 d);
+#endif
+
+#define RD ((op >> 21) & 0x1F)
+#define RT ((op >> 21) & 0x1f)
+#define RS ((op >> 21) & 0x1f)
+#define RA ((op >> 16) & 0x1f)
+#define RB ((op >> 11) & 0x1f)
+#define RC ((op >> 6) & 0x1f)
+
+#define MB ((op >> 6) & 0x1f)
+#define ME ((op >> 1) & 0x1f)
+#define SH ((op >> 11) & 0x1f)
+#define BO ((op >> 21) & 0x1f)
+#define BI ((op >> 16) & 0x1f)
+#define CRFD ((op >> 23) & 0x7)
+#define CRFA ((op >> 18) & 0x7)
+#define FXM ((op >> 12) & 0xff)
+#define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0))
+
+#define SIMM16 (INT32)(INT16)(op & 0xffff)
+#define UIMM16 (UINT32)(op & 0xffff)
+
+#define RCBIT (op & 0x1)
+#define OEBIT (op & 0x400)
+#define AABIT (op & 0x2)
+#define LKBIT (op & 0x1)
+
+#define REG(x) (ppc.r[x])
+#define LR (ppc.lr)
+#define CTR (ppc.ctr)
+#define XER (ppc.xer)
+#define CR(x) (ppc.cr[x])
+#define MSR (ppc.msr)
+#define SRR0 (ppc.srr0)
+#define SRR1 (ppc.srr1)
+#define SRR2 (ppc.srr2)
+#define SRR3 (ppc.srr3)
+#define EVPR (ppc.evpr)
+#define EXIER (ppc.exier)
+#define EXISR (ppc.exisr)
+#define DEC (ppc.dec)
+
+
+// Stuff added for the 6xx
+#define FPR(x) (ppc.fpr[x])
+#define FM ((op >> 17) & 0xFF)
+#define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F))
+
+
+#define CHECK_SUPERVISOR() \
+ if((ppc.msr & 0x4000) != 0){ \
+ }
+
+#define CHECK_FPU_AVAILABLE() \
+ if((ppc.msr & 0x2000) == 0){ \
+ }
+
+#if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_MPC8240)
+static UINT32 ppc_field_xlat[256];
+#endif
+
+
+
+#define FPSCR_FX 0x80000000
+#define FPSCR_FEX 0x40000000
+#define FPSCR_VX 0x20000000
+#define FPSCR_OX 0x10000000
+#define FPSCR_UX 0x08000000
+#define FPSCR_ZX 0x04000000
+#define FPSCR_XX 0x02000000
+
+
+
+#define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1)
+#define CRBIT(x) ((ppc.cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0)
+#define _BIT(n) (1 << (n))
+#define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me])
+#define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a)
+#define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b))
+#define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000)
+#define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000)
+
+#define XER_SO 0x80000000
+#define XER_OV 0x40000000
+#define XER_CA 0x20000000
+
+#define MSR_AP 0x00800000 /* Access privilege state (PPC602) */
+#define MSR_SA 0x00400000 /* Supervisor access mode (PPC602) */
+#define MSR_POW 0x00040000 /* Power Management Enable */
+#define MSR_WE 0x00040000
+#define MSR_CE 0x00020000
+#define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */
+#define MSR_EE 0x00008000 /* External Interrupt Enable */
+#define MSR_PR 0x00004000 /* Problem State */
+#define MSR_FP 0x00002000 /* Floating Point Available */
+#define MSR_ME 0x00001000 /* Machine Check Enable */
+#define MSR_FE0 0x00000800
+#define MSR_SE 0x00000400 /* Single Step Trace Enable */
+#define MSR_BE 0x00000200 /* Branch Trace Enable */
+#define MSR_DE 0x00000200
+#define MSR_FE1 0x00000100
+#define MSR_IP 0x00000040 /* Interrupt Prefix */
+#define MSR_IR 0x00000020 /* Instruction Relocate */
+#define MSR_DR 0x00000010 /* Data Relocate */
+#define MSR_PE 0x00000008
+#define MSR_PX 0x00000004
+#define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */
+#define MSR_LE 0x00000001
+
+#define TSR_ENW 0x80000000
+#define TSR_WIS 0x40000000
+
+#define BYTE_REVERSE16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
+#define BYTE_REVERSE32(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000))
+
+typedef struct {
+ UINT32 cr;
+ UINT32 da;
+ UINT32 sa;
+ UINT32 ct;
+ UINT32 cc;
+} DMA_REGS;
+
+typedef struct {
+ UINT8 spls;
+ UINT8 sphs;
+ UINT16 brd;
+ UINT8 spctl;
+ UINT8 sprc;
+ UINT8 sptc;
+ UINT8 sprb;
+ UINT8 sptb;
+ emu_timer *rx_timer;
+ emu_timer *tx_timer;
+} SPU_REGS;
+
+typedef union {
+ UINT64 id;
+ double fd;
+} FPR;
+
+typedef union {
+ UINT32 i;
+ float f;
+} FPR32;
+
+typedef struct {
+ UINT32 u;
+ UINT32 l;
+} BATENT;
+
+
+typedef struct {
+ UINT32 r[32];
+ UINT32 pc;
+ UINT32 npc;
+
+ UINT32 lr;
+ UINT32 ctr;
+ UINT32 xer;
+ UINT32 msr;
+ UINT8 cr[8];
+ UINT32 pvr;
+ UINT32 srr0;
+ UINT32 srr1;
+ UINT32 srr2;
+ UINT32 srr3;
+ UINT32 hid0;
+ UINT32 hid1;
+ UINT32 hid2;
+ UINT32 sdr1;
+ UINT32 sprg[4];
+
+ UINT32 dsisr;
+ UINT32 dar;
+ UINT32 ear;
+ UINT32 dmiss;
+ UINT32 dcmp;
+ UINT32 hash1;
+ UINT32 hash2;
+ UINT32 imiss;
+ UINT32 icmp;
+ UINT32 rpa;
+
+
+ BATENT ibat[4];
+ BATENT dbat[4];
+
+ UINT32 evpr;
+ UINT32 exier;
+ UINT32 exisr;
+ UINT32 bear;
+ UINT32 besr;
+ UINT32 iocr;
+ UINT32 br[8];
+ UINT32 iabr;
+ UINT32 esr;
+ UINT32 iccr;
+ UINT32 dccr;
+ UINT32 pit;
+ UINT32 pit_counter;
+ UINT32 pit_int_enable;
+ UINT32 tsr;
+ UINT32 dbsr;
+ UINT32 sgr;
+ UINT32 pid;
+ UINT32 pbl1, pbl2, pbu1, pbu2;
+ UINT32 fit_bit;
+ UINT32 fit_int_enable;
+ UINT32 wdt_bit;
+ UINT32 wdt_int_enable;
+ UINT32 dac1, dac2;
+ UINT32 iac1, iac2;
+
+ SPU_REGS spu;
+ DMA_REGS dma[4];
+ UINT32 dmasr;
+
+ int reserved;
+ UINT32 reserved_address;
+
+ int interrupt_pending;
+
+ UINT64 tb; /* 56-bit timebase register */
+
+ int (*irq_callback)(int irqline);
+
+
+ // STUFF added for the 6xx series
+ UINT32 dec, dec_frac;
+ UINT32 fpscr;
+
+ FPR fpr[32];
+ UINT32 sr[16];
+
+#if HAS_PPC603 || HAS_PPC601 || HAS_MPC8240
+ int is603;
+#endif
+#if HAS_PPC602
+ int is602;
+#endif
+
+ /* PowerPC 602 specific registers */
+ UINT32 lt;
+ UINT32 sp;
+ UINT32 tcr;
+ UINT32 ibr;
+ UINT32 esasrr;
+ UINT32 sebr;
+ UINT32 ser;
+
+ /* PowerPC function pointers for memory accesses/exceptions */
+ jmp_buf exception_jmpbuf;
+ UINT8 (*read8)(offs_t address);
+ UINT16 (*read16)(offs_t address);
+ UINT32 (*read32)(offs_t address);
+ UINT64 (*read64)(offs_t address);
+ void (*write8)(offs_t address, UINT8 data);
+ void (*write16)(offs_t address, UINT16 data);
+ void (*write32)(offs_t address, UINT32 data);
+ void (*write64)(offs_t address, UINT64 data);
+ UINT16 (*read16_unaligned)(offs_t address);
+ UINT32 (*read32_unaligned)(offs_t address);
+ UINT64 (*read64_unaligned)(offs_t address);
+ void (*write16_unaligned)(offs_t address, UINT16 data);
+ void (*write32_unaligned)(offs_t address, UINT32 data);
+ void (*write64_unaligned)(offs_t address, UINT64 data);
+} PPC_REGS;
+
+
+
+typedef struct {
+ int code;
+ int subcode;
+ void (* handler)(UINT32);
+} PPC_OPCODE;
+
+
+
+static int ppc_icount;
+static int ppc_tb_base_icount;
+static int ppc_dec_base_icount;
+static int ppc_dec_trigger_cycle;
+static int bus_freq_multiplier = 1;
+static PPC_REGS ppc;
+static UINT32 ppc_rotate_mask[32][32];
+
+#define ROPCODE(pc) cpu_readop32(pc)
+#define ROPCODE64(pc) cpu_readop64(DWORD_XOR_BE(pc))
+
+/*********************************************************************/
+
+INLINE int IS_PPC602(void)
+{
+#if HAS_PPC602
+ return ppc.is602;
+#else
+ return 0;
+#endif
+}
+
+INLINE int IS_PPC603(void)
+{
+#if HAS_PPC603 || HAS_PPC601
+ return ppc.is603;
+#else
+ return 0;
+#endif
+}
+
+INLINE int IS_PPC403(void)
+{
+#if HAS_PPC403
+ return !IS_PPC602() && !IS_PPC603();
+#else
+ return 0;
+#endif
+}
+
+/*********************************************************************/
+
+
+INLINE void SET_CR0(INT32 rd)
+{
+ if( rd < 0 ) {
+ CR(0) = 0x8;
+ } else if( rd > 0 ) {
+ CR(0) = 0x4;
+ } else {
+ CR(0) = 0x2;
+ }
+
+ if( XER & XER_SO )
+ CR(0) |= 0x1;
+}
+
+INLINE void SET_CR1(void)
+{
+ CR(1) = (ppc.fpscr >> 28) & 0xf;
+}
+
+INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb)
+{
+ if( ADD_OV(rd, ra, rb) )
+ XER |= XER_SO | XER_OV;
+ else
+ XER &= ~XER_OV;
+}
+
+INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb)
+{
+ if( SUB_OV(rd, ra, rb) )
+ XER |= XER_SO | XER_OV;
+ else
+ XER &= ~XER_OV;
+}
+
+INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb)
+{
+ if( ADD_CA(rd, ra, rb) )
+ XER |= XER_CA;
+ else
+ XER &= ~XER_CA;
+}
+
+INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb)
+{
+ if( SUB_CA(rd, ra, rb) )
+ XER |= XER_CA;
+ else
+ XER &= ~XER_CA;
+}
+
+INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi)
+{
+ UINT32 ctr_ok;
+ UINT32 condition_ok;
+ UINT32 bo0 = (bo & 0x10) ? 1 : 0;
+ UINT32 bo1 = (bo & 0x08) ? 1 : 0;
+ UINT32 bo2 = (bo & 0x04) ? 1 : 0;
+ UINT32 bo3 = (bo & 0x02) ? 1 : 0;
+
+ if( bo2 == 0 )
+ --CTR;
+
+ ctr_ok = bo2 | ((CTR != 0) ^ bo3);
+ condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1));
+
+ return ctr_ok && condition_ok;
+}
+
+INLINE UINT64 ppc_read_timebase(void)
+{
+ int cycles = ppc_tb_base_icount - ppc_icount;
+
+ if (IS_PPC603() || IS_PPC602())
+ {
+ // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly
+ return ppc.tb + (cycles / 4);
+ }
+ else
+ {
+ // timebase is incremented once every core cycle on PPC403
+ return ppc.tb + cycles;
+ }
+}
+
+INLINE void ppc_write_timebase_l(UINT32 tbl)
+{
+ ppc_tb_base_icount = ppc_icount;
+
+ ppc.tb &= ~0xffffffff;
+ ppc.tb |= tbl;
+}
+
+INLINE void ppc_write_timebase_h(UINT32 tbh)
+{
+ ppc_tb_base_icount = ppc_icount;
+
+ ppc.tb &= 0xffffffff;
+ ppc.tb |= (UINT64)(tbh) << 32;
+}
+
+INLINE UINT32 read_decrementer(void)
+{
+ int cycles = ppc_dec_base_icount - ppc_icount;
+
+ // decrementer is decremented once every four bus clock cycles, so adjust the cycles accordingly
+ return DEC - (cycles / (bus_freq_multiplier * 2));
+}
+
+INLINE void write_decrementer(UINT32 value)
+{
+ ppc_dec_base_icount = ppc_icount + (ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2);
+
+ DEC = value;
+
+ // check if decrementer exception occurs during execution
+ if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC))
+ {
+ ppc_dec_trigger_cycle = ppc_icount - DEC;
+ }
+ else
+ {
+ ppc_dec_trigger_cycle = 0x7fffffff;
+ }
+}
+
+/*********************************************************************/
+
+INLINE void ppc_set_spr(int spr, UINT32 value)
+{
+ switch (spr)
+ {
+ case SPR_LR: LR = value; return;
+ case SPR_CTR: CTR = value; return;
+ case SPR_XER: XER = value; return;
+ case SPR_SRR0: ppc.srr0 = value; return;
+ case SPR_SRR1: ppc.srr1 = value; return;
+ case SPR_SPRG0: ppc.sprg[0] = value; return;
+ case SPR_SPRG1: ppc.sprg[1] = value; return;
+ case SPR_SPRG2: ppc.sprg[2] = value; return;
+ case SPR_SPRG3: ppc.sprg[3] = value; return;
+ case SPR_PVR: return;
+ }
+
+#if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601)
+ if(IS_PPC602() || IS_PPC603()) {
+ switch(spr)
+ {
+ case SPR603E_DEC:
+ if((value & 0x80000000) && !(DEC & 0x80000000))
+ {
+ /* trigger interrupt */
+#if HAS_PPC602
+ if (IS_PPC602())
+ ppc602_exception(EXCEPTION_DECREMENTER);
+#endif
+#if HAS_PPC603 || HAS_PPC601
+ if (IS_PPC603())
+ ppc603_exception(EXCEPTION_DECREMENTER);
+#endif
+ }
+ write_decrementer(value);
+ return;
+
+ case SPR603E_TBL_W:
+ case SPR603E_TBL_R: // special 603e case
+ ppc_write_timebase_l(value);
+ return;
+
+ case SPR603E_TBU_R:
+ case SPR603E_TBU_W: // special 603e case
+ ppc_write_timebase_h(value);
+ return;
+
+ case SPR603E_HID0: ppc.hid0 = value; return;
+ case SPR603E_HID1: ppc.hid1 = value; return;
+ case SPR603E_HID2: ppc.hid2 = value; return;
+
+ case SPR603E_DSISR: ppc.dsisr = value; return;
+ case SPR603E_DAR: ppc.dar = value; return;
+ case SPR603E_EAR: ppc.ear = value; return;
+ case SPR603E_DMISS: ppc.dmiss = value; return;
+ case SPR603E_DCMP: ppc.dcmp = value; return;
+ case SPR603E_HASH1: ppc.hash1 = value; return;
+ case SPR603E_HASH2: ppc.hash2 = value; return;
+ case SPR603E_IMISS: ppc.imiss = value; return;
+ case SPR603E_ICMP: ppc.icmp = value; return;
+ case SPR603E_RPA: ppc.rpa = value; return;
+
+ case SPR603E_IBAT0L: ppc.ibat[0].l = value; return;
+ case SPR603E_IBAT0U: ppc.ibat[0].u = value; return;
+ case SPR603E_IBAT1L: ppc.ibat[1].l = value; return;
+ case SPR603E_IBAT1U: ppc.ibat[1].u = value; return;
+ case SPR603E_IBAT2L: ppc.ibat[2].l = value; return;
+ case SPR603E_IBAT2U: ppc.ibat[2].u = value; return;
+ case SPR603E_IBAT3L: ppc.ibat[3].l = value; return;
+ case SPR603E_IBAT3U: ppc.ibat[3].u = value; return;
+ case SPR603E_DBAT0L: ppc.dbat[0].l = value; return;
+ case SPR603E_DBAT0U: ppc.dbat[0].u = value; return;
+ case SPR603E_DBAT1L: ppc.dbat[1].l = value; return;
+ case SPR603E_DBAT1U: ppc.dbat[1].u = value; return;
+ case SPR603E_DBAT2L: ppc.dbat[2].l = value; return;
+ case SPR603E_DBAT2U: ppc.dbat[2].u = value; return;
+ case SPR603E_DBAT3L: ppc.dbat[3].l = value; return;
+ case SPR603E_DBAT3U: ppc.dbat[3].u = value; return;
+
+ case SPR603E_SDR1:
+ ppc.sdr1 = value;
+ return;
+
+ case SPR603E_IABR: ppc.iabr = value; return;
+ }
+ }
+#endif
+
+#if (HAS_PPC602)
+ if (ppc.is602) {
+ switch(spr)
+ {
+ case SPR602_LT: ppc.lt = value; return;
+ case SPR602_IBR: ppc.ibr = value; return;
+ case SPR602_SEBR: ppc.sebr = value; return;
+ case SPR602_SER: ppc.ser = value; return;
+ case SPR602_SP: ppc.sp = value; return;
+ case SPR602_TCR: ppc.tcr = value; return;
+ }
+ }
+#endif
+
+#if (HAS_PPC403)
+ if (IS_PPC403()) {
+ switch(spr)
+ {
+ case SPR403_TBHI: ppc_write_timebase_h(value); return;
+ case SPR403_TBLO: ppc_write_timebase_l(value); return;
+
+ case SPR403_TSR:
+ ppc.tsr &= ~value; // 1 clears, 0 does nothing
+ return;
+
+ case SPR403_TCR:
+ switch((value >> 24) & 0x3)
+ {
+ case 0: ppc.fit_bit = 1 << 8; break;
+ case 1: ppc.fit_bit = 1 << 12; break;
+ case 2: ppc.fit_bit = 1 << 16; break;
+ case 3: ppc.fit_bit = 1 << 20; break;
+ }
+ switch((value >> 30) & 0x3)
+ {
+ case 0: ppc.wdt_bit = 1 << 16; break;
+ case 1: ppc.wdt_bit = 1 << 20; break;
+ case 2: ppc.wdt_bit = 1 << 24; break;
+ case 3: ppc.wdt_bit = 1 << 28; break;
+ }
+ ppc.fit_int_enable = (value >> 23) & 0x1;
+ ppc.wdt_int_enable = (value >> 27) & 0x1;
+ ppc.tcr = value;
+
+ if (!ppc.fit_int_enable)
+ {
+ ppc.interrupt_pending &= ~0x4;
+ }
+ return;
+
+ case SPR403_ESR: ppc.esr = value; return;
+ case SPR403_ICCR: ppc.iccr = value; return;
+ case SPR403_DCCR: ppc.dccr = value; return;
+ case SPR403_EVPR: EVPR = value & 0xffff0000; return;
+ case SPR403_PIT: ppc.pit = value; return;
+ case SPR403_SGR: ppc.sgr = value; return;
+ case SPR403_DBSR: ppc.dbsr = value; return;
+ case SPR403_DCWR: return;
+ case SPR403_PID: ppc.pid = value; return;
+ case SPR403_PBL1: ppc.pbl1 = value; return;
+ case SPR403_PBU1: ppc.pbu1 = value; return;
+ case SPR403_PBL2: ppc.pbl2 = value; return;
+ case SPR403_PBU2: ppc.pbu2 = value; return;
+ case SPR403_SRR2: ppc.srr2 = value; return;
+ case SPR403_SRR3: ppc.srr3 = value; return;
+ case SPR403_DAC1: ppc.dac1 = value; return;
+ case SPR403_DAC2: ppc.dac2 = value; return;
+ case SPR403_IAC1: ppc.iac1 = value; return;
+ case SPR403_IAC2: ppc.iac2 = value; return;
+ }
+ }
+#endif
+
+ fatalerror("ppc: set_spr: unknown spr %d (%03X) !", spr, spr);
+}
+
+INLINE UINT32 ppc_get_spr(int spr)
+{
+ switch(spr)
+ {
+ case SPR_LR: return LR;
+ case SPR_CTR: return CTR;
+ case SPR_XER: return XER;
+ case SPR_SRR0: return ppc.srr0;
+ case SPR_SRR1: return ppc.srr1;
+ case SPR_SPRG0: return ppc.sprg[0];
+ case SPR_SPRG1: return ppc.sprg[1];
+ case SPR_SPRG2: return ppc.sprg[2];
+ case SPR_SPRG3: return ppc.sprg[3];
+ case SPR_PVR: return ppc.pvr;
+ }
+
+#if (HAS_PPC403)
+ if (IS_PPC403())
+ {
+ switch (spr)
+ {
+ case SPR403_TBLU:
+ case SPR403_TBLO: return (UINT32)(ppc_read_timebase());
+ case SPR403_TBHU:
+ case SPR403_TBHI: return (UINT32)(ppc_read_timebase() >> 32);
+
+ case SPR403_EVPR: return EVPR;
+ case SPR403_ESR: return ppc.esr;
+ case SPR403_TCR: return ppc.tcr;
+ case SPR403_ICCR: return ppc.iccr;
+ case SPR403_DCCR: return ppc.dccr;
+ case SPR403_PIT: return ppc.pit;
+ case SPR403_DBSR: return ppc.dbsr;
+ case SPR403_SGR: return ppc.sgr;
+ case SPR403_TSR: return ppc.tsr;
+ case SPR403_PBL1: return ppc.pbl1;
+ case SPR403_PBU1: return ppc.pbu1;
+ case SPR403_PBL2: return ppc.pbl2;
+ case SPR403_PBU2: return ppc.pbu2;
+ case SPR403_SRR2: return ppc.srr2;
+ case SPR403_SRR3: return ppc.srr3;
+ case SPR403_DAC1: return ppc.dac1;
+ case SPR403_DAC2: return ppc.dac2;
+ case SPR403_IAC1: return ppc.iac1;
+ case SPR403_IAC2: return ppc.iac2;
+ }
+ }
+#endif
+
+#if (HAS_PPC602)
+ if (ppc.is602) {
+ switch(spr)
+ {
+ case SPR602_LT: return ppc.lt;
+ case SPR602_IBR: return ppc.ibr;
+ case SPR602_ESASRR: return ppc.esasrr;
+ case SPR602_SEBR: return ppc.sebr;
+ case SPR602_SER: return ppc.ser;
+ case SPR602_SP: return ppc.sp;
+ case SPR602_TCR: return ppc.tcr;
+ }
+ }
+#endif
+
+#if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601)
+ if (IS_PPC603() || IS_PPC602())
+ {
+ switch (spr)
+ {
+ case SPR603E_TBL_R:
+ fatalerror("ppc: get_spr: TBL_R ");
+ break;
+
+ case SPR603E_TBU_R:
+ fatalerror("ppc: get_spr: TBU_R ");
+ break;
+
+ case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase());
+ case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32);
+ case SPR603E_HID0: return ppc.hid0;
+ case SPR603E_HID1: return ppc.hid1;
+ case SPR603E_HID2: return ppc.hid2;
+ case SPR603E_DEC: return read_decrementer();
+ case SPR603E_SDR1: return ppc.sdr1;
+ case SPR603E_DSISR: return ppc.dsisr;
+ case SPR603E_DAR: return ppc.dar;
+ case SPR603E_EAR: return ppc.ear;
+ case SPR603E_DMISS: return ppc.dmiss;
+ case SPR603E_DCMP: return ppc.dcmp;
+ case SPR603E_HASH1: return ppc.hash1;
+ case SPR603E_HASH2: return ppc.hash2;
+ case SPR603E_IMISS: return ppc.imiss;
+ case SPR603E_ICMP: return ppc.icmp;
+ case SPR603E_RPA: return ppc.rpa;
+ case SPR603E_IBAT0L: return ppc.ibat[0].l;
+ case SPR603E_IBAT0U: return ppc.ibat[0].u;
+ case SPR603E_IBAT1L: return ppc.ibat[1].l;
+ case SPR603E_IBAT1U: return ppc.ibat[1].u;
+ case SPR603E_IBAT2L: return ppc.ibat[2].l;
+ case SPR603E_IBAT2U: return ppc.ibat[2].u;
+ case SPR603E_IBAT3L: return ppc.ibat[3].l;
+ case SPR603E_IBAT3U: return ppc.ibat[3].u;
+ case SPR603E_DBAT0L: return ppc.dbat[0].l;
+ case SPR603E_DBAT0U: return ppc.dbat[0].u;
+ case SPR603E_DBAT1L: return ppc.dbat[1].l;
+ case SPR603E_DBAT1U: return ppc.dbat[1].u;
+ case SPR603E_DBAT2L: return ppc.dbat[2].l;
+ case SPR603E_DBAT2U: return ppc.dbat[2].u;
+ case SPR603E_DBAT3L: return ppc.dbat[3].l;
+ case SPR603E_DBAT3U: return ppc.dbat[3].u;
+ }
+ }
+#endif
+
+ fatalerror("ppc: get_spr: unknown spr %d (%03X) !", spr, spr);
+ return 0;
+}
+
+static UINT8 ppc_read8_translated(offs_t address);
+static UINT16 ppc_read16_translated(offs_t address);
+static UINT32 ppc_read32_translated(offs_t address);
+static UINT64 ppc_read64_translated(offs_t address);
+static void ppc_write8_translated(offs_t address, UINT8 data);
+static void ppc_write16_translated(offs_t address, UINT16 data);
+static void ppc_write32_translated(offs_t address, UINT32 data);
+static void ppc_write64_translated(offs_t address, UINT64 data);
+
+INLINE void ppc_set_msr(UINT32 value)
+{
+ if( value & (MSR_ILE | MSR_LE) )
+ fatalerror("ppc: set_msr: little_endian mode not supported !");
+
+ MSR = value;
+
+ if (IS_PPC603() || IS_PPC602())
+ {
+ if (!(MSR & MSR_DR))
+ {
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ }
+ else
+ {
+ ppc.read8 = ppc_read8_translated;
+ ppc.read16 = ppc_read16_translated;
+ ppc.read32 = ppc_read32_translated;
+ ppc.read64 = ppc_read64_translated;
+ ppc.write8 = ppc_write8_translated;
+ ppc.write16 = ppc_write16_translated;
+ ppc.write32 = ppc_write32_translated;
+ ppc.write64 = ppc_write64_translated;
+ }
+ }
+}
+
+INLINE UINT32 ppc_get_msr(void)
+{
+ return MSR;
+}
+
+INLINE void ppc_set_cr(UINT32 value)
+{
+ CR(0) = (value >> 28) & 0xf;
+ CR(1) = (value >> 24) & 0xf;
+ CR(2) = (value >> 20) & 0xf;
+ CR(3) = (value >> 16) & 0xf;
+ CR(4) = (value >> 12) & 0xf;
+ CR(5) = (value >> 8) & 0xf;
+ CR(6) = (value >> 4) & 0xf;
+ CR(7) = (value >> 0) & 0xf;
+}
+
+INLINE UINT32 ppc_get_cr(void)
+{
+ return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7);
+}
+
+INLINE void ppc_exception(int exception_type)
+{
+ longjmp(ppc.exception_jmpbuf, exception_type);
+}
+
+/***********************************************************************/
+
+static void (* optable19[1024])(UINT32);
+static void (* optable31[1024])(UINT32);
+static void (* optable59[1024])(UINT32);
+static void (* optable63[1024])(UINT32);
+static void (* optable[64])(UINT32);
+
+#include "ppc_mem.c"
+
+#if (HAS_PPC403)
+#include "ppc403.c"
+#endif
+
+#if (HAS_PPC602)
+#include "ppc602.c"
+#endif
+
+#if (HAS_PPC603 || HAS_PPC601 || HAS_MPC8240)
+#include "ppc603.c"
+#endif
+
+/********************************************************************/
+
+#include "ppc_ops.c"
+#include "ppc_ops.h"
+
+/* Initialization and shutdown */
+
+void ppc_init(void)
+{
+ int i,j;
+
+ memset(&ppc, 0, sizeof(ppc));
+
+ for( i=0; i < 64; i++ ) {
+ optable[i] = ppc_invalid;
+ }
+ for( i=0; i < 1024; i++ ) {
+ optable19[i] = ppc_invalid;
+ optable31[i] = ppc_invalid;
+ optable59[i] = ppc_invalid;
+ optable63[i] = ppc_invalid;
+ }
+
+ /* Fill the opcode tables */
+ for( i=0; i < (sizeof(ppc_opcode_common) / sizeof(PPC_OPCODE)); i++ ) {
+
+ switch(ppc_opcode_common[i].code)
+ {
+ case 19:
+ optable19[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler;
+ break;
+
+ case 31:
+ optable31[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler;
+ break;
+
+ case 59:
+ case 63:
+ break;
+
+ default:
+ optable[ppc_opcode_common[i].code] = ppc_opcode_common[i].handler;
+ }
+
+ }
+
+ /* Calculate rotate mask table */
+ for( i=0; i < 32; i++ ) {
+ for( j=0; j < 32; j++ ) {
+ UINT32 mask;
+ int mb = i;
+ int me = j;
+ mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1)));
+ if( mb > me )
+ mask = ~mask;
+
+ ppc_rotate_mask[i][j] = mask;
+ }
+ }
+}
+
+
+// !!! probably should move this stuff elsewhere !!!
+#if HAS_PPC403
+static void ppc403_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const ppc_config *config = _config;
+
+ ppc_init();
+
+ /* PPC403 specific opcodes */
+ optable31[454] = ppc_dccci;
+ optable31[486] = ppc_dcread;
+ optable31[262] = ppc_icbt;
+ optable31[966] = ppc_iccci;
+ optable31[998] = ppc_icread;
+ optable31[323] = ppc_mfdcr;
+ optable31[451] = ppc_mtdcr;
+ optable31[131] = ppc_wrtee;
+ optable31[163] = ppc_wrteei;
+
+ // !!! why is rfci here !!!
+ optable19[51] = ppc_rfci;
+
+ ppc.spu.rx_timer = timer_alloc(ppc403_spu_rx_callback);
+ ppc.spu.tx_timer = timer_alloc(ppc403_spu_tx_callback);
+
+ ppc.read8 = ppc403_read8;
+ ppc.read16 = ppc403_read16;
+ ppc.read32 = ppc403_read32;
+ ppc.write8 = ppc403_write8;
+ ppc.write16 = ppc403_write16;
+ ppc.write32 = ppc403_write32;
+ ppc.read16_unaligned = ppc403_read16_unaligned;
+ ppc.read32_unaligned = ppc403_read32_unaligned;
+ ppc.write16_unaligned = ppc403_write16_unaligned;
+ ppc.write32_unaligned = ppc403_write32_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+}
+
+static void ppc403_exit(void)
+{
+
+}
+#endif /* HAS_PPC403 */
+
+
+#if (HAS_PPC603)
+static void ppc603_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const ppc_config *config = _config;
+ int pll_config = 0;
+ float multiplier;
+ int i ;
+
+ ppc_init() ;
+
+ optable[48] = ppc_lfs;
+ optable[49] = ppc_lfsu;
+ optable[50] = ppc_lfd;
+ optable[51] = ppc_lfdu;
+ optable[52] = ppc_stfs;
+ optable[53] = ppc_stfsu;
+ optable[54] = ppc_stfd;
+ optable[55] = ppc_stfdu;
+ optable31[631] = ppc_lfdux;
+ optable31[599] = ppc_lfdx;
+ optable31[567] = ppc_lfsux;
+ optable31[535] = ppc_lfsx;
+ optable31[595] = ppc_mfsr;
+ optable31[659] = ppc_mfsrin;
+ optable31[371] = ppc_mftb;
+ optable31[210] = ppc_mtsr;
+ optable31[242] = ppc_mtsrin;
+ optable31[758] = ppc_dcba;
+ optable31[759] = ppc_stfdux;
+ optable31[727] = ppc_stfdx;
+ optable31[983] = ppc_stfiwx;
+ optable31[695] = ppc_stfsux;
+ optable31[663] = ppc_stfsx;
+ optable31[370] = ppc_tlbia;
+ optable31[306] = ppc_tlbie;
+ optable31[566] = ppc_tlbsync;
+ optable31[310] = ppc_eciwx;
+ optable31[438] = ppc_ecowx;
+
+ optable63[264] = ppc_fabsx;
+ optable63[21] = ppc_faddx;
+ optable63[32] = ppc_fcmpo;
+ optable63[0] = ppc_fcmpu;
+ optable63[14] = ppc_fctiwx;
+ optable63[15] = ppc_fctiwzx;
+ optable63[18] = ppc_fdivx;
+ optable63[72] = ppc_fmrx;
+ optable63[136] = ppc_fnabsx;
+ optable63[40] = ppc_fnegx;
+ optable63[12] = ppc_frspx;
+ optable63[26] = ppc_frsqrtex;
+ optable63[22] = ppc_fsqrtx;
+ optable63[20] = ppc_fsubx;
+ optable63[583] = ppc_mffsx;
+ optable63[70] = ppc_mtfsb0x;
+ optable63[38] = ppc_mtfsb1x;
+ optable63[711] = ppc_mtfsfx;
+ optable63[134] = ppc_mtfsfix;
+ optable63[64] = ppc_mcrfs;
+
+ optable59[21] = ppc_faddsx;
+ optable59[18] = ppc_fdivsx;
+ optable59[24] = ppc_fresx;
+ optable59[22] = ppc_fsqrtsx;
+ optable59[20] = ppc_fsubsx;
+
+ for(i = 0; i < 32; i++)
+ {
+ optable63[i * 32 | 29] = ppc_fmaddx;
+ optable63[i * 32 | 28] = ppc_fmsubx;
+ optable63[i * 32 | 25] = ppc_fmulx;
+ optable63[i * 32 | 31] = ppc_fnmaddx;
+ optable63[i * 32 | 30] = ppc_fnmsubx;
+ optable63[i * 32 | 23] = ppc_fselx;
+
+ optable59[i * 32 | 29] = ppc_fmaddsx;
+ optable59[i * 32 | 28] = ppc_fmsubsx;
+ optable59[i * 32 | 25] = ppc_fmulsx;
+ optable59[i * 32 | 31] = ppc_fnmaddsx;
+ optable59[i * 32 | 30] = ppc_fnmsubsx;
+ }
+
+ for(i = 0; i < 256; i++)
+ {
+ ppc_field_xlat[i] =
+ ((i & 0x80) ? 0xF0000000 : 0) |
+ ((i & 0x40) ? 0x0F000000 : 0) |
+ ((i & 0x20) ? 0x00F00000 : 0) |
+ ((i & 0x10) ? 0x000F0000 : 0) |
+ ((i & 0x08) ? 0x0000F000 : 0) |
+ ((i & 0x04) ? 0x00000F00 : 0) |
+ ((i & 0x02) ? 0x000000F0 : 0) |
+ ((i & 0x01) ? 0x0000000F : 0);
+ }
+
+ ppc.is603 = 1;
+
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ ppc.read16_unaligned = ppc_read16_unaligned;
+ ppc.read32_unaligned = ppc_read32_unaligned;
+ ppc.read64_unaligned = ppc_read64_unaligned;
+ ppc.write16_unaligned = ppc_write16_unaligned;
+ ppc.write32_unaligned = ppc_write32_unaligned;
+ ppc.write64_unaligned = ppc_write64_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+
+ multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) +
+ (float)(config->bus_frequency_multiplier & 0xf) / 10.0f;
+ bus_freq_multiplier = (int)(multiplier * 2);
+
+ switch(config->pvr)
+ {
+ case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
+ case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
+ case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
+ default: break;
+ }
+
+ if (pll_config == -1)
+ {
+ fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier);
+ }
+
+ ppc.hid1 = pll_config << 28;
+}
+
+static void ppc603_exit(void)
+{
+
+}
+#endif
+
+#if (HAS_PPC602)
+static void ppc602_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ float multiplier;
+ const ppc_config *config = _config;
+
+ int i ;
+
+ ppc_init() ;
+
+ optable[48] = ppc_lfs;
+ optable[49] = ppc_lfsu;
+ optable[50] = ppc_lfd;
+ optable[51] = ppc_lfdu;
+ optable[52] = ppc_stfs;
+ optable[53] = ppc_stfsu;
+ optable[54] = ppc_stfd;
+ optable[55] = ppc_stfdu;
+ optable31[631] = ppc_lfdux;
+ optable31[599] = ppc_lfdx;
+ optable31[567] = ppc_lfsux;
+ optable31[535] = ppc_lfsx;
+ optable31[595] = ppc_mfsr;
+ optable31[659] = ppc_mfsrin;
+ optable31[371] = ppc_mftb;
+ optable31[210] = ppc_mtsr;
+ optable31[242] = ppc_mtsrin;
+ optable31[758] = ppc_dcba;
+ optable31[759] = ppc_stfdux;
+ optable31[727] = ppc_stfdx;
+ optable31[983] = ppc_stfiwx;
+ optable31[695] = ppc_stfsux;
+ optable31[663] = ppc_stfsx;
+ optable31[370] = ppc_tlbia;
+ optable31[306] = ppc_tlbie;
+ optable31[566] = ppc_tlbsync;
+ optable31[310] = ppc_eciwx;
+ optable31[438] = ppc_ecowx;
+
+ optable63[264] = ppc_fabsx;
+ optable63[21] = ppc_faddx;
+ optable63[32] = ppc_fcmpo;
+ optable63[0] = ppc_fcmpu;
+ optable63[14] = ppc_fctiwx;
+ optable63[15] = ppc_fctiwzx;
+ optable63[18] = ppc_fdivx;
+ optable63[72] = ppc_fmrx;
+ optable63[136] = ppc_fnabsx;
+ optable63[40] = ppc_fnegx;
+ optable63[12] = ppc_frspx;
+ optable63[26] = ppc_frsqrtex;
+ optable63[22] = ppc_fsqrtx;
+ optable63[20] = ppc_fsubx;
+ optable63[583] = ppc_mffsx;
+ optable63[70] = ppc_mtfsb0x;
+ optable63[38] = ppc_mtfsb1x;
+ optable63[711] = ppc_mtfsfx;
+ optable63[134] = ppc_mtfsfix;
+ optable63[64] = ppc_mcrfs;
+
+ optable59[21] = ppc_faddsx;
+ optable59[18] = ppc_fdivsx;
+ optable59[24] = ppc_fresx;
+ optable59[22] = ppc_fsqrtsx;
+ optable59[20] = ppc_fsubsx;
+
+ for(i = 0; i < 32; i++)
+ {
+ optable63[i * 32 | 29] = ppc_fmaddx;
+ optable63[i * 32 | 28] = ppc_fmsubx;
+ optable63[i * 32 | 25] = ppc_fmulx;
+ optable63[i * 32 | 31] = ppc_fnmaddx;
+ optable63[i * 32 | 30] = ppc_fnmsubx;
+ optable63[i * 32 | 23] = ppc_fselx;
+
+ optable59[i * 32 | 29] = ppc_fmaddsx;
+ optable59[i * 32 | 28] = ppc_fmsubsx;
+ optable59[i * 32 | 25] = ppc_fmulsx;
+ optable59[i * 32 | 31] = ppc_fnmaddsx;
+ optable59[i * 32 | 30] = ppc_fnmsubsx;
+ }
+
+ for(i = 0; i < 256; i++)
+ {
+ ppc_field_xlat[i] =
+ ((i & 0x80) ? 0xF0000000 : 0) |
+ ((i & 0x40) ? 0x0F000000 : 0) |
+ ((i & 0x20) ? 0x00F00000 : 0) |
+ ((i & 0x10) ? 0x000F0000 : 0) |
+ ((i & 0x08) ? 0x0000F000 : 0) |
+ ((i & 0x04) ? 0x00000F00 : 0) |
+ ((i & 0x02) ? 0x000000F0 : 0) |
+ ((i & 0x01) ? 0x0000000F : 0);
+ }
+
+ // PPC602 specific opcodes
+ optable31[596] = ppc_esa;
+ optable31[628] = ppc_dsa;
+ optable31[1010] = ppc_tlbli;
+ optable31[978] = ppc_tlbld;
+
+ ppc.is602 = 1;
+
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ ppc.read16_unaligned = ppc_read16_unaligned;
+ ppc.read32_unaligned = ppc_read32_unaligned;
+ ppc.read64_unaligned = ppc_read64_unaligned;
+ ppc.write16_unaligned = ppc_write16_unaligned;
+ ppc.write32_unaligned = ppc_write32_unaligned;
+ ppc.write64_unaligned = ppc_write64_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+
+ multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) +
+ (float)(config->bus_frequency_multiplier & 0xf) / 10.0f;
+ bus_freq_multiplier = (int)(multiplier * 2);
+}
+
+static void ppc602_exit(void)
+{
+
+}
+#endif
+
+#if (HAS_MPC8240)
+
+static void mpc8240_tlbli(UINT32 op)
+{
+
+}
+
+static void mpc8240_tlbld(UINT32 op)
+{
+
+}
+
+static void mpc8240_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ float multiplier;
+ const ppc_config *config = _config;
+
+ int i ;
+
+ ppc_init();
+
+ optable[48] = ppc_lfs;
+ optable[49] = ppc_lfsu;
+ optable[50] = ppc_lfd;
+ optable[51] = ppc_lfdu;
+ optable[52] = ppc_stfs;
+ optable[53] = ppc_stfsu;
+ optable[54] = ppc_stfd;
+ optable[55] = ppc_stfdu;
+ optable31[631] = ppc_lfdux;
+ optable31[599] = ppc_lfdx;
+ optable31[567] = ppc_lfsux;
+ optable31[535] = ppc_lfsx;
+ optable31[595] = ppc_mfsr;
+ optable31[659] = ppc_mfsrin;
+ optable31[371] = ppc_mftb;
+ optable31[210] = ppc_mtsr;
+ optable31[242] = ppc_mtsrin;
+ optable31[758] = ppc_dcba;
+ optable31[759] = ppc_stfdux;
+ optable31[727] = ppc_stfdx;
+ optable31[983] = ppc_stfiwx;
+ optable31[695] = ppc_stfsux;
+ optable31[663] = ppc_stfsx;
+ optable31[370] = ppc_tlbia;
+ optable31[306] = ppc_tlbie;
+ optable31[566] = ppc_tlbsync;
+ optable31[310] = ppc_eciwx;
+ optable31[438] = ppc_ecowx;
+
+ optable63[264] = ppc_fabsx;
+ optable63[21] = ppc_faddx;
+ optable63[32] = ppc_fcmpo;
+ optable63[0] = ppc_fcmpu;
+ optable63[14] = ppc_fctiwx;
+ optable63[15] = ppc_fctiwzx;
+ optable63[18] = ppc_fdivx;
+ optable63[72] = ppc_fmrx;
+ optable63[136] = ppc_fnabsx;
+ optable63[40] = ppc_fnegx;
+ optable63[12] = ppc_frspx;
+ optable63[26] = ppc_frsqrtex;
+ optable63[22] = ppc_fsqrtx;
+ optable63[20] = ppc_fsubx;
+ optable63[583] = ppc_mffsx;
+ optable63[70] = ppc_mtfsb0x;
+ optable63[38] = ppc_mtfsb1x;
+ optable63[711] = ppc_mtfsfx;
+ optable63[134] = ppc_mtfsfix;
+ optable63[64] = ppc_mcrfs;
+
+ optable59[21] = ppc_faddsx;
+ optable59[18] = ppc_fdivsx;
+ optable59[24] = ppc_fresx;
+ optable59[22] = ppc_fsqrtsx;
+ optable59[20] = ppc_fsubsx;
+
+ for(i = 0; i < 32; i++)
+ {
+ optable63[i * 32 | 29] = ppc_fmaddx;
+ optable63[i * 32 | 28] = ppc_fmsubx;
+ optable63[i * 32 | 25] = ppc_fmulx;
+ optable63[i * 32 | 31] = ppc_fnmaddx;
+ optable63[i * 32 | 30] = ppc_fnmsubx;
+ optable63[i * 32 | 23] = ppc_fselx;
+
+ optable59[i * 32 | 29] = ppc_fmaddsx;
+ optable59[i * 32 | 28] = ppc_fmsubsx;
+ optable59[i * 32 | 25] = ppc_fmulsx;
+ optable59[i * 32 | 31] = ppc_fnmaddsx;
+ optable59[i * 32 | 30] = ppc_fnmsubsx;
+ }
+
+ for(i = 0; i < 256; i++)
+ {
+ ppc_field_xlat[i] =
+ ((i & 0x80) ? 0xF0000000 : 0) |
+ ((i & 0x40) ? 0x0F000000 : 0) |
+ ((i & 0x20) ? 0x00F00000 : 0) |
+ ((i & 0x10) ? 0x000F0000 : 0) |
+ ((i & 0x08) ? 0x0000F000 : 0) |
+ ((i & 0x04) ? 0x00000F00 : 0) |
+ ((i & 0x02) ? 0x000000F0 : 0) |
+ ((i & 0x01) ? 0x0000000F : 0);
+ }
+
+ // MPC8240 specific opcodes
+ optable31[978] = mpc8240_tlbld;
+ optable31[1010] = mpc8240_tlbli;
+
+ ppc.is603 = 1;
+
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ ppc.read16_unaligned = ppc_read16_unaligned;
+ ppc.read32_unaligned = ppc_read32_unaligned;
+ ppc.read64_unaligned = ppc_read64_unaligned;
+ ppc.write16_unaligned = ppc_write16_unaligned;
+ ppc.write32_unaligned = ppc_write32_unaligned;
+ ppc.write64_unaligned = ppc_write64_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+
+ multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) +
+ (float)(config->bus_frequency_multiplier & 0xf) / 10.0f;
+ bus_freq_multiplier = (int)(multiplier * 2);
+}
+
+static void mpc8240_exit(void)
+{
+
+}
+#endif
+
+
+#if (HAS_PPC601)
+static void ppc601_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const ppc_config *config = _config;
+ float multiplier;
+ int i ;
+
+ ppc_init() ;
+
+ optable[48] = ppc_lfs;
+ optable[49] = ppc_lfsu;
+ optable[50] = ppc_lfd;
+ optable[51] = ppc_lfdu;
+ optable[52] = ppc_stfs;
+ optable[53] = ppc_stfsu;
+ optable[54] = ppc_stfd;
+ optable[55] = ppc_stfdu;
+ optable31[631] = ppc_lfdux;
+ optable31[599] = ppc_lfdx;
+ optable31[567] = ppc_lfsux;
+ optable31[535] = ppc_lfsx;
+ optable31[595] = ppc_mfsr;
+ optable31[659] = ppc_mfsrin;
+ optable31[371] = ppc_mftb;
+ optable31[210] = ppc_mtsr;
+ optable31[242] = ppc_mtsrin;
+ optable31[758] = ppc_dcba;
+ optable31[759] = ppc_stfdux;
+ optable31[727] = ppc_stfdx;
+ optable31[983] = ppc_stfiwx;
+ optable31[695] = ppc_stfsux;
+ optable31[663] = ppc_stfsx;
+ optable31[370] = ppc_tlbia;
+ optable31[306] = ppc_tlbie;
+ optable31[566] = ppc_tlbsync;
+ optable31[310] = ppc_eciwx;
+ optable31[438] = ppc_ecowx;
+
+ optable63[264] = ppc_fabsx;
+ optable63[21] = ppc_faddx;
+ optable63[32] = ppc_fcmpo;
+ optable63[0] = ppc_fcmpu;
+ optable63[14] = ppc_fctiwx;
+ optable63[15] = ppc_fctiwzx;
+ optable63[18] = ppc_fdivx;
+ optable63[72] = ppc_fmrx;
+ optable63[136] = ppc_fnabsx;
+ optable63[40] = ppc_fnegx;
+ optable63[12] = ppc_frspx;
+ optable63[26] = ppc_frsqrtex;
+ optable63[22] = ppc_fsqrtx;
+ optable63[20] = ppc_fsubx;
+ optable63[583] = ppc_mffsx;
+ optable63[70] = ppc_mtfsb0x;
+ optable63[38] = ppc_mtfsb1x;
+ optable63[711] = ppc_mtfsfx;
+ optable63[134] = ppc_mtfsfix;
+ optable63[64] = ppc_mcrfs;
+
+ optable59[21] = ppc_faddsx;
+ optable59[18] = ppc_fdivsx;
+ optable59[24] = ppc_fresx;
+ optable59[22] = ppc_fsqrtsx;
+ optable59[20] = ppc_fsubsx;
+
+ for(i = 0; i < 32; i++)
+ {
+ optable63[i * 32 | 29] = ppc_fmaddx;
+ optable63[i * 32 | 28] = ppc_fmsubx;
+ optable63[i * 32 | 25] = ppc_fmulx;
+ optable63[i * 32 | 31] = ppc_fnmaddx;
+ optable63[i * 32 | 30] = ppc_fnmsubx;
+ optable63[i * 32 | 23] = ppc_fselx;
+
+ optable59[i * 32 | 29] = ppc_fmaddsx;
+ optable59[i * 32 | 28] = ppc_fmsubsx;
+ optable59[i * 32 | 25] = ppc_fmulsx;
+ optable59[i * 32 | 31] = ppc_fnmaddsx;
+ optable59[i * 32 | 30] = ppc_fnmsubsx;
+ }
+
+ for(i = 0; i < 256; i++)
+ {
+ ppc_field_xlat[i] =
+ ((i & 0x80) ? 0xF0000000 : 0) |
+ ((i & 0x40) ? 0x0F000000 : 0) |
+ ((i & 0x20) ? 0x00F00000 : 0) |
+ ((i & 0x10) ? 0x000F0000 : 0) |
+ ((i & 0x08) ? 0x0000F000 : 0) |
+ ((i & 0x04) ? 0x00000F00 : 0) |
+ ((i & 0x02) ? 0x000000F0 : 0) |
+ ((i & 0x01) ? 0x0000000F : 0);
+ }
+
+ ppc.is603 = 1;
+
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ ppc.read16_unaligned = ppc_read16_unaligned;
+ ppc.read32_unaligned = ppc_read32_unaligned;
+ ppc.read64_unaligned = ppc_read64_unaligned;
+ ppc.write16_unaligned = ppc_write16_unaligned;
+ ppc.write32_unaligned = ppc_write32_unaligned;
+ ppc.write64_unaligned = ppc_write64_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+
+ multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) +
+ (float)(config->bus_frequency_multiplier & 0xf) / 10.0f;
+ bus_freq_multiplier = (int)(multiplier * 2);
+
+ ppc.hid1 = 0;
+}
+
+static void ppc601_exit(void)
+{
+
+}
+#endif
+
+
+
+static void ppc_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(PPC_REGS *)dst = ppc;
+}
+
+
+static void ppc_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ ppc = *(PPC_REGS *)src;
+
+ change_pc(ppc.pc);
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void ppc_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + PPC_PC: ppc.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_MSR: ppc_set_msr(info->i); break;
+ case CPUINFO_INT_REGISTER + PPC_CR: ppc_set_cr(info->i); break;
+ case CPUINFO_INT_REGISTER + PPC_LR: LR = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_CTR: CTR = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_XER: XER = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_SRR0: SRR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_SRR1: SRR1 = info->i; break;
+
+ case CPUINFO_INT_REGISTER + PPC_R0: ppc.r[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R1: ppc.r[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R2: ppc.r[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R3: ppc.r[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R4: ppc.r[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R5: ppc.r[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R6: ppc.r[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R7: ppc.r[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R8: ppc.r[8] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R9: ppc.r[9] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R10: ppc.r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R11: ppc.r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R12: ppc.r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R13: ppc.r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R14: ppc.r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R15: ppc.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R16: ppc.r[16] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R17: ppc.r[17] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R18: ppc.r[18] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R19: ppc.r[19] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R20: ppc.r[20] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R21: ppc.r[21] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R22: ppc.r[22] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R23: ppc.r[23] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R24: ppc.r[24] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R25: ppc.r[25] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R26: ppc.r[26] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R27: ppc.r[27] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R28: ppc.r[28] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R29: ppc.r[29] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R30: ppc.r[30] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R31: ppc.r[31] = info->i; break;
+ }
+}
+
+#if (HAS_PPC403)
+static void ppc403_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 8)
+ {
+ ppc403_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ case CPUINFO_INT_REGISTER + PPC_EXIER: EXIER = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_EXISR: EXISR = info->i; break;
+ default: ppc_set_info(state, info); break;
+ }
+}
+#endif
+
+#if (HAS_PPC603)
+static void ppc603_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ ppc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ case CPUINFO_INT_REGISTER + PPC_DEC: write_decrementer(info->i); break;
+ case CPUINFO_INT_INPUT_STATE + PPC_INPUT_LINE_SMI: ppc603_set_smi_line(info->i); break;
+ default: ppc_set_info(state, info); break;
+ }
+}
+#endif
+
+void ppc_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ppc); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC: /* intentional fallthrough */
+ case CPUINFO_INT_REGISTER + PPC_PC: info->i = ppc.pc; break;
+ case CPUINFO_INT_REGISTER + PPC_MSR: info->i = ppc_get_msr(); break;
+ case CPUINFO_INT_REGISTER + PPC_CR: info->i = ppc_get_cr(); break;
+ case CPUINFO_INT_REGISTER + PPC_LR: info->i = LR; break;
+ case CPUINFO_INT_REGISTER + PPC_CTR: info->i = CTR; break;
+ case CPUINFO_INT_REGISTER + PPC_XER: info->i = XER; break;
+ case CPUINFO_INT_REGISTER + PPC_SRR0: info->i = SRR0; break;
+ case CPUINFO_INT_REGISTER + PPC_SRR1: info->i = SRR1; break;
+
+ case CPUINFO_INT_REGISTER + PPC_R0: info->i = ppc.r[0]; break;
+ case CPUINFO_INT_REGISTER + PPC_R1: info->i = ppc.r[1]; break;
+ case CPUINFO_INT_REGISTER + PPC_R2: info->i = ppc.r[2]; break;
+ case CPUINFO_INT_REGISTER + PPC_R3: info->i = ppc.r[3]; break;
+ case CPUINFO_INT_REGISTER + PPC_R4: info->i = ppc.r[4]; break;
+ case CPUINFO_INT_REGISTER + PPC_R5: info->i = ppc.r[5]; break;
+ case CPUINFO_INT_REGISTER + PPC_R6: info->i = ppc.r[6]; break;
+ case CPUINFO_INT_REGISTER + PPC_R7: info->i = ppc.r[7]; break;
+ case CPUINFO_INT_REGISTER + PPC_R8: info->i = ppc.r[8]; break;
+ case CPUINFO_INT_REGISTER + PPC_R9: info->i = ppc.r[9]; break;
+ case CPUINFO_INT_REGISTER + PPC_R10: info->i = ppc.r[10]; break;
+ case CPUINFO_INT_REGISTER + PPC_R11: info->i = ppc.r[11]; break;
+ case CPUINFO_INT_REGISTER + PPC_R12: info->i = ppc.r[12]; break;
+ case CPUINFO_INT_REGISTER + PPC_R13: info->i = ppc.r[13]; break;
+ case CPUINFO_INT_REGISTER + PPC_R14: info->i = ppc.r[14]; break;
+ case CPUINFO_INT_REGISTER + PPC_R15: info->i = ppc.r[15]; break;
+ case CPUINFO_INT_REGISTER + PPC_R16: info->i = ppc.r[16]; break;
+ case CPUINFO_INT_REGISTER + PPC_R17: info->i = ppc.r[17]; break;
+ case CPUINFO_INT_REGISTER + PPC_R18: info->i = ppc.r[18]; break;
+ case CPUINFO_INT_REGISTER + PPC_R19: info->i = ppc.r[19]; break;
+ case CPUINFO_INT_REGISTER + PPC_R20: info->i = ppc.r[20]; break;
+ case CPUINFO_INT_REGISTER + PPC_R21: info->i = ppc.r[21]; break;
+ case CPUINFO_INT_REGISTER + PPC_R22: info->i = ppc.r[22]; break;
+ case CPUINFO_INT_REGISTER + PPC_R23: info->i = ppc.r[23]; break;
+ case CPUINFO_INT_REGISTER + PPC_R24: info->i = ppc.r[24]; break;
+ case CPUINFO_INT_REGISTER + PPC_R25: info->i = ppc.r[25]; break;
+ case CPUINFO_INT_REGISTER + PPC_R26: info->i = ppc.r[26]; break;
+ case CPUINFO_INT_REGISTER + PPC_R27: info->i = ppc.r[27]; break;
+ case CPUINFO_INT_REGISTER + PPC_R28: info->i = ppc.r[28]; break;
+ case CPUINFO_INT_REGISTER + PPC_R29: info->i = ppc.r[29]; break;
+ case CPUINFO_INT_REGISTER + PPC_R30: info->i = ppc.r[30]; break;
+ case CPUINFO_INT_REGISTER + PPC_R31: info->i = ppc.r[31]; break;
+
+
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ppc_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ppc_set_context; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ppc_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ppc_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "PowerPC"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2004"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + PPC_PC: sprintf(info->s, "PC: %08X", ppc.pc); break;
+ case CPUINFO_STR_REGISTER + PPC_MSR: sprintf(info->s, "MSR: %08X", ppc_get_msr()); break;
+ case CPUINFO_STR_REGISTER + PPC_CR: sprintf(info->s, "CR: %08X", ppc_get_cr()); break;
+ case CPUINFO_STR_REGISTER + PPC_LR: sprintf(info->s, "LR: %08X", LR); break;
+ case CPUINFO_STR_REGISTER + PPC_CTR: sprintf(info->s, "CTR: %08X", CTR); break;
+ case CPUINFO_STR_REGISTER + PPC_XER: sprintf(info->s, "XER: %08X", XER); break;
+ case CPUINFO_STR_REGISTER + PPC_SRR0: sprintf(info->s, "SRR0: %08X", SRR0); break;
+ case CPUINFO_STR_REGISTER + PPC_SRR1: sprintf(info->s, "SRR1: %08X", SRR1); break;
+
+ case CPUINFO_STR_REGISTER + PPC_R0: sprintf(info->s, "R0: %08X", ppc.r[0]); break;
+ case CPUINFO_STR_REGISTER + PPC_R1: sprintf(info->s, "R1: %08X", ppc.r[1]); break;
+ case CPUINFO_STR_REGISTER + PPC_R2: sprintf(info->s, "R2: %08X", ppc.r[2]); break;
+ case CPUINFO_STR_REGISTER + PPC_R3: sprintf(info->s, "R3: %08X", ppc.r[3]); break;
+ case CPUINFO_STR_REGISTER + PPC_R4: sprintf(info->s, "R4: %08X", ppc.r[4]); break;
+ case CPUINFO_STR_REGISTER + PPC_R5: sprintf(info->s, "R5: %08X", ppc.r[5]); break;
+ case CPUINFO_STR_REGISTER + PPC_R6: sprintf(info->s, "R6: %08X", ppc.r[6]); break;
+ case CPUINFO_STR_REGISTER + PPC_R7: sprintf(info->s, "R7: %08X", ppc.r[7]); break;
+ case CPUINFO_STR_REGISTER + PPC_R8: sprintf(info->s, "R8: %08X", ppc.r[8]); break;
+ case CPUINFO_STR_REGISTER + PPC_R9: sprintf(info->s, "R9: %08X", ppc.r[9]); break;
+ case CPUINFO_STR_REGISTER + PPC_R10: sprintf(info->s, "R10: %08X", ppc.r[10]); break;
+ case CPUINFO_STR_REGISTER + PPC_R11: sprintf(info->s, "R11: %08X", ppc.r[11]); break;
+ case CPUINFO_STR_REGISTER + PPC_R12: sprintf(info->s, "R12: %08X", ppc.r[12]); break;
+ case CPUINFO_STR_REGISTER + PPC_R13: sprintf(info->s, "R13: %08X", ppc.r[13]); break;
+ case CPUINFO_STR_REGISTER + PPC_R14: sprintf(info->s, "R14: %08X", ppc.r[14]); break;
+ case CPUINFO_STR_REGISTER + PPC_R15: sprintf(info->s, "R15: %08X", ppc.r[15]); break;
+ case CPUINFO_STR_REGISTER + PPC_R16: sprintf(info->s, "R16: %08X", ppc.r[16]); break;
+ case CPUINFO_STR_REGISTER + PPC_R17: sprintf(info->s, "R17: %08X", ppc.r[17]); break;
+ case CPUINFO_STR_REGISTER + PPC_R18: sprintf(info->s, "R18: %08X", ppc.r[18]); break;
+ case CPUINFO_STR_REGISTER + PPC_R19: sprintf(info->s, "R19: %08X", ppc.r[19]); break;
+ case CPUINFO_STR_REGISTER + PPC_R20: sprintf(info->s, "R20: %08X", ppc.r[20]); break;
+ case CPUINFO_STR_REGISTER + PPC_R21: sprintf(info->s, "R21: %08X", ppc.r[21]); break;
+ case CPUINFO_STR_REGISTER + PPC_R22: sprintf(info->s, "R22: %08X", ppc.r[22]); break;
+ case CPUINFO_STR_REGISTER + PPC_R23: sprintf(info->s, "R23: %08X", ppc.r[23]); break;
+ case CPUINFO_STR_REGISTER + PPC_R24: sprintf(info->s, "R24: %08X", ppc.r[24]); break;
+ case CPUINFO_STR_REGISTER + PPC_R25: sprintf(info->s, "R25: %08X", ppc.r[25]); break;
+ case CPUINFO_STR_REGISTER + PPC_R26: sprintf(info->s, "R26: %08X", ppc.r[26]); break;
+ case CPUINFO_STR_REGISTER + PPC_R27: sprintf(info->s, "R27: %08X", ppc.r[27]); break;
+ case CPUINFO_STR_REGISTER + PPC_R28: sprintf(info->s, "R28: %08X", ppc.r[28]); break;
+ case CPUINFO_STR_REGISTER + PPC_R29: sprintf(info->s, "R29: %08X", ppc.r[29]); break;
+ case CPUINFO_STR_REGISTER + PPC_R30: sprintf(info->s, "R30: %08X", ppc.r[30]); break;
+ case CPUINFO_STR_REGISTER + PPC_R31: sprintf(info->s, "R31: %08X", ppc.r[31]); break;
+ }
+}
+
+#if (HAS_PPC403)
+void ppc403_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 8; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_REGISTER + PPC_EXIER: info->i = EXIER; break;
+ case CPUINFO_INT_REGISTER + PPC_EXISR: info->i = EXISR; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ppc403_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = ppc403_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppc403_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ppc403_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppc403_execute; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break;
+ case CPUINFO_STR_REGISTER + PPC_EXIER: sprintf(info->s, "EXIER: %08X", EXIER); break;
+ case CPUINFO_STR_REGISTER + PPC_EXISR: sprintf(info->s, "EXISR: %08X", EXISR); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
+
+#if (HAS_PPC603)
+void ppc603_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 17; break;
+ case CPUINFO_INT_REGISTER + PPC_DEC: info->i = read_decrementer(); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ppc603_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = ppc603_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppc603_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ppc603_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppc603_execute; break;
+ case CPUINFO_PTR_READ: info->read = ppc_read; break;
+ case CPUINFO_PTR_WRITE: info->write = ppc_write; break;
+ case CPUINFO_PTR_READOP: info->readop = ppc_readop; break;
+ case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC603"); break;
+ case CPUINFO_STR_REGISTER + PPC_DEC: sprintf(info->s, "DEC: %08X", read_decrementer()); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
+
+/* PowerPC 602 */
+
+#if (HAS_PPC602)
+static void ppc602_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ ppc602_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ case CPUINFO_INT_INPUT_STATE + PPC_INPUT_LINE_SMI: ppc602_set_smi_line(info->i); break;
+ default: ppc_set_info(state, info); break;
+ }
+}
+
+void ppc602_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_REGISTER + PPC_IBR: info->i = ppc.ibr; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ppc602_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = ppc602_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppc602_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ppc602_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppc602_execute; break;
+ case CPUINFO_PTR_READ: info->read = ppc_read; break;
+ case CPUINFO_PTR_WRITE: info->write = ppc_write; break;
+ case CPUINFO_PTR_READOP: info->readop = ppc_readop; break;
+ case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC602"); break;
+ case CPUINFO_STR_REGISTER + PPC_IBR: sprintf(info->s, "IBR: %08X", ppc.ibr); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
+
+/* Motorola MPC8240 */
+
+#if (HAS_MPC8240)
+static void mpc8240_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ ppc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ default: ppc_set_info(state, info); break;
+ }
+}
+
+void mpc8240_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mpc8240_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = mpc8240_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppc603_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = mpc8240_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppc603_execute; break;
+ case CPUINFO_PTR_READ: info->read = ppc_read; break;
+ case CPUINFO_PTR_WRITE: info->write = ppc_write; break;
+ case CPUINFO_PTR_READOP: info->readop = ppc_readop; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MPC8240"); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
+
+/* PPC601 */
+
+#if (HAS_PPC601)
+static void ppc601_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ ppc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ default: ppc_set_info(state, info); break;
+ }
+}
+
+void ppc601_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ppc601_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = ppc601_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppc603_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ppc601_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppc603_execute; break;
+ case CPUINFO_PTR_READ: info->read = ppc_read; break;
+ case CPUINFO_PTR_WRITE: info->write = ppc_write; break;
+ case CPUINFO_PTR_READOP: info->readop = ppc_readop; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC601"); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/powerpc/ppc.h b/src/emu/cpu/powerpc/ppc.h
new file mode 100644
index 00000000000..0a3ab6640f2
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppc.h
@@ -0,0 +1,367 @@
+#ifndef _PPC_H
+#define _PPC_H
+
+#include "cpuintrf.h"
+
+#define SPR_XER 1 /* Fixed Point Exception Register Read / Write */
+#define SPR_LR 8 /* Link Register Read / Write */
+#define SPR_CTR 9 /* Count Register Read / Write */
+#define SPR_SRR0 26 /* Save/Restore Register 0 Read / Write */
+#define SPR_SRR1 27 /* Save/Restore Register 1 Read / Write */
+#define SPR_SPRG0 272 /* SPR General 0 Read / Write */
+#define SPR_SPRG1 273 /* SPR General 1 Read / Write */
+#define SPR_SPRG2 274 /* SPR General 2 Read / Write */
+#define SPR_SPRG3 275 /* SPR General 3 Read / Write */
+#define SPR_PVR 287 /* Processor Version Number Read Only */
+
+#define SPR403_ICDBDR 0x3D3 /* 406GA Instruction Cache Debug Data Register Rad Only */
+#define SPR403_ESR 0x3D4 /* 406GA Exception Syndrome Register Read / Write */
+#define SPR403_DEAR 0x3D5 /* 406GA Data Exception Address Register Read Only */
+#define SPR403_EVPR 0x3D6 /* 406GA Exception Vector Prefix Register Read / Write */
+#define SPR403_CDBCR 0x3D7 /* 406GA Cache Debug Control Register Read/Write */
+#define SPR403_TSR 0x3D8 /* 406GA Timer Status Register Read / Clear */
+#define SPR403_TCR 0x3DA /* 406GA Timer Control Register Read / Write */
+#define SPR403_PIT 0x3DB /* 406GA Programmable Interval Timer Read / Write */
+#define SPR403_TBHI 988 /* 406GA Time Base High Read / Write */
+#define SPR403_TBLO 989 /* 406GA Time Base Low Read / Write */
+#define SPR403_SRR2 0x3DE /* 406GA Save/Restore Register 2 Read / Write */
+#define SPR403_SRR3 0x3DF /* 406GA Save/Restore Register 3 Read / Write */
+#define SPR403_DBSR 0x3F0 /* 406GA Debug Status Register Read / Clear */
+#define SPR403_DBCR 0x3F2 /* 406GA Debug Control Register Read / Write */
+#define SPR403_IAC1 0x3F4 /* 406GA Instruction Address Compare 1 Read / Write */
+#define SPR403_IAC2 0x3F5 /* 406GA Instruction Address Compare 2 Read / Write */
+#define SPR403_DAC1 0x3F6 /* 406GA Data Address Compare 1 Read / Write */
+#define SPR403_DAC2 0x3F7 /* 406GA Data Address Compare 2 Read / Write */
+#define SPR403_DCCR 0x3FA /* 406GA Data Cache Cacheability Register Read / Write */
+#define SPR403_ICCR 0x3FB /* 406GA I Cache Cacheability Registe Read / Write */
+#define SPR403_PBL1 0x3FC /* 406GA Protection Bound Lower 1 Read / Write */
+#define SPR403_PBU1 0x3FD /* 406GA Protection Bound Upper 1 Read / Write */
+#define SPR403_PBL2 0x3FE /* 406GA Protection Bound Lower 2 Read / Write */
+#define SPR403_PBU2 0x3FF /* 406GA Protection Bound Upper 2 Read / Write */
+
+#define SPR403_SGR 0x3b9 /* 403GCX Storage Guarded Register */
+#define SPR403_DCWR 0x3ba /* 403GCX Data Cache Write Through */
+#define SPR403_PID 0x3b1 /* 403GCX Process ID */
+#define SPR403_TBHU 0x3cc /* 403GCX Time Base High User-mode */
+#define SPR403_TBLU 0x3cd /* 403GCX Time Base Low User-mode */
+
+#define SPR603E_DSISR 18 /* 603E */
+#define SPR603E_DAR 19 /* 603E */
+#define SPR603E_DEC 22 /* 603E */
+#define SPR603E_SDR1 25 /* 603E */
+#define SPR603E_TBL_R 268 /* 603E Time Base Low (Read-only) */
+#define SPR603E_TBU_R 269 /* 603E Time Base High (Read-only) */
+#define SPR603E_TBL_W 284 /* 603E Time Base Low (Write-only) */
+#define SPR603E_TBU_W 285 /* 603E Time Base Hight (Write-only) */
+#define SPR603E_EAR 282 /* 603E */
+#define SPR603E_IBAT0U 528 /* 603E */
+#define SPR603E_IBAT0L 529 /* 603E */
+#define SPR603E_IBAT1U 530 /* 603E */
+#define SPR603E_IBAT1L 531 /* 603E */
+#define SPR603E_IBAT2U 532 /* 603E */
+#define SPR603E_IBAT2L 533 /* 603E */
+#define SPR603E_IBAT3U 534 /* 603E */
+#define SPR603E_IBAT3L 535 /* 603E */
+#define SPR603E_DBAT0U 536 /* 603E */
+#define SPR603E_DBAT0L 537 /* 603E */
+#define SPR603E_DBAT1U 538 /* 603E */
+#define SPR603E_DBAT1L 539 /* 603E */
+#define SPR603E_DBAT2U 540 /* 603E */
+#define SPR603E_DBAT2L 541 /* 603E */
+#define SPR603E_DBAT3U 542 /* 603E */
+#define SPR603E_DBAT3L 543 /* 603E */
+#define SPR603E_DABR 1013 /* 603E */
+#define SPR603E_DMISS 0x3d0 /* 603E */
+#define SPR603E_DCMP 0x3d1 /* 603E */
+#define SPR603E_HASH1 0x3d2 /* 603E */
+#define SPR603E_HASH2 0x3d3 /* 603E */
+#define SPR603E_IMISS 0x3d4 /* 603E */
+#define SPR603E_ICMP 0x3d5 /* 603E */
+#define SPR603E_RPA 0x3d6 /* 603E */
+#define SPR603E_HID0 1008 /* 603E */
+#define SPR603E_HID1 1009 /* 603E */
+#define SPR603E_IABR 1010 /* 603E */
+#define SPR603E_HID2 1011 /* 603E */
+
+#define SPR602_TCR 984 /* 602 */
+#define SPR602_IBR 986 /* 602 */
+#define SPR602_ESASRR 987 /* 602 */
+#define SPR602_SEBR 990 /* 602 */
+#define SPR602_SER 991 /* 602 */
+#define SPR602_SP 1021 /* 602 */
+#define SPR602_LT 1022 /* 602 */
+
+
+#define DCR_BEAR 0x90 /* bus error address */
+#define DCR_BESR 0x91 /* bus error syndrome */
+#define DCR_BR0 0x80 /* bank */
+#define DCR_BR1 0x81 /* bank */
+#define DCR_BR2 0x82 /* bank */
+#define DCR_BR3 0x83 /* bank */
+#define DCR_BR4 0x84 /* bank */
+#define DCR_BR5 0x85 /* bank */
+#define DCR_BR6 0x86 /* bank */
+#define DCR_BR7 0x87 /* bank */
+#define DCR_DMACC0 0xc4 /* dma chained count */
+#define DCR_DMACC1 0xcc /* dma chained count */
+#define DCR_DMACC2 0xd4 /* dma chained count */
+#define DCR_DMACC3 0xdc /* dma chained count */
+#define DCR_DMACR0 0xc0 /* dma channel control */
+#define DCR_DMACR1 0xc8 /* dma channel control */
+#define DCR_DMACR2 0xd0 /* dma channel control */
+#define DCR_DMACR3 0xd8 /* dma channel control */
+#define DCR_DMACT0 0xc1 /* dma destination address */
+#define DCR_DMACT1 0xc9 /* dma destination address */
+#define DCR_DMACT2 0xd1 /* dma destination address */
+#define DCR_DMACT3 0xd9 /* dma destination address */
+#define DCR_DMADA0 0xc2 /* dma destination address */
+#define DCR_DMADA1 0xca /* dma destination address */
+#define DCR_DMADA2 0xd2 /* dma source address */
+#define DCR_DMADA3 0xda /* dma source address */
+#define DCR_DMASA0 0xc3 /* dma source address */
+#define DCR_DMASA1 0xcb /* dma source address */
+#define DCR_DMASA2 0xd3 /* dma source address */
+#define DCR_DMASA3 0xdb /* dma source address */
+#define DCR_DMASR 0xe0 /* dma status */
+#define DCR_EXIER 0x42 /* external interrupt enable */
+#define DCR_EXISR 0x40 /* external interrupt status */
+#define DCR_IOCR 0xa0 /* io configuration */
+
+enum {
+ EXCEPTION_IRQ = 1,
+ EXCEPTION_DECREMENTER = 2,
+ EXCEPTION_TRAP = 3,
+ EXCEPTION_SYSTEM_CALL = 4,
+ EXCEPTION_SMI = 5,
+ EXCEPTION_DSI = 6,
+ EXCEPTION_ISI = 7,
+ EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER = 20,
+ EXCEPTION_FIXED_INTERVAL_TIMER = 21,
+ EXCEPTION_WATCHDOG_TIMER = 22,
+ EXCEPTION_CRITICAL_INTERRUPT = 23,
+};
+
+enum {
+ PPC_INPUT_LINE_SMI = 10,
+ PPC_INPUT_LINE_TLBISYNC
+};
+
+enum {
+ PPC_PC=1,
+ PPC_MSR,
+ PPC_CR,
+ PPC_LR,
+ PPC_CTR,
+ PPC_XER,
+ PPC_DEC,
+ PPC_SRR0,
+ PPC_SRR1,
+ PPC_EXIER,
+ PPC_EXISR,
+ PPC_IBR,
+ PPC_R0,
+ PPC_R1,
+ PPC_R2,
+ PPC_R3,
+ PPC_R4,
+ PPC_R5,
+ PPC_R6,
+ PPC_R7,
+ PPC_R8,
+ PPC_R9,
+ PPC_R10,
+ PPC_R11,
+ PPC_R12,
+ PPC_R13,
+ PPC_R14,
+ PPC_R15,
+ PPC_R16,
+ PPC_R17,
+ PPC_R18,
+ PPC_R19,
+ PPC_R20,
+ PPC_R21,
+ PPC_R22,
+ PPC_R23,
+ PPC_R24,
+ PPC_R25,
+ PPC_R26,
+ PPC_R27,
+ PPC_R28,
+ PPC_R29,
+ PPC_R30,
+ PPC_R31
+};
+
+typedef enum {
+ PPC_MODEL_403GA = 0x00200000,
+ PPC_MODEL_403GB = 0x00200100,
+ PPC_MODEL_403GC = 0x00200200,
+ PPC_MODEL_403GCX = 0x00201400,
+ PPC_MODEL_405GP = 0x40110000,
+ PPC_MODEL_601 = 0x00010000,
+ PPC_MODEL_603 = 0x00030000, /* "Wart" */
+ PPC_MODEL_604 = 0x00040000, /* "Zephyr" */
+ PPC_MODEL_602 = 0x00050200, /* "Galahad" */
+ PPC_MODEL_603E = 0x00060103, /* "Stretch", version 1.3 */
+ PPC_MODEL_603EV = 0x00070000, /* "Valiant" */
+ PPC_MODEL_603R = 0x00071202, /* "Goldeneye", version 2.1 */
+ PPC_MODEL_740 = 0x00080301, /* "Arthur", version 3.1 */
+ PPC_MODEL_750 = PPC_MODEL_740,
+ PPC_MODEL_740P = 0x00080202, /* "Conan Doyle", version 1.2 */
+ PPC_MODEL_750P = PPC_MODEL_740P,
+ PPC_MODEL_755 = 0x00083203, /* "Goldfinger", version 2.3 */
+ PPC_MODEL_7400 = 0x000c0209, /* "Max", version 2.9 */
+ PPC_MODEL_7410 = 0x800c1104, /* "Nitro", version 3.4 */
+ PPC_MODEL_7450 = 0x80000201, /* "Vger", version 2.1 */
+ PPC_MODEL_7451 = 0x80000203, /* "Vger", version 2.3 */
+ PPC_MODEL_7441 = PPC_MODEL_7451,
+ PPC_MODEL_7455 = 0x80010303, /* "Apollo 6", version 3.3 */
+ PPC_MODEL_7445 = PPC_MODEL_7455,
+ PPC_MODEL_7457 = 0x80020101, /* "Apollo 7", version 1.1 */
+ PPC_MODEL_MPC8240 = 0x00810101, /* "Kahlua" */
+ PPC_MODEL_MPC8241 = 0x80811014, /* "Kahlua Lt" */
+ PPC_MODEL_MPC8245 = 0x80811014, /* "Kahlua II" */
+} PPC_MODEL;
+
+typedef enum {
+ BUS_FREQUENCY_16MHZ = 0,
+ BUS_FREQUENCY_20MHZ,
+ BUS_FREQUENCY_25MHZ,
+ BUS_FREQUENCY_33MHZ,
+ BUS_FREQUENCY_40MHZ,
+ BUS_FREQUENCY_50MHZ,
+ BUS_FREQUENCY_60MHZ,
+ BUS_FREQUENCY_66MHZ,
+ BUS_FREQUENCY_75MHZ,
+} PPC_BUS_FREQUENCY;
+
+// PLL Configuration based on the table in MPC603EUM page 7-31
+static const int mpc603e_pll_config[12][9] =
+{
+ // 16, 20, 25, 33, 40, 50, 60, 66, 75
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ { 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, -1, 0x0, -1 },
+ { -1, -1, -1, -1, -1, 0xc, -1, 0xc, -1 },
+ { 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, -1, -1, -1 },
+ { -1, -1, -1, 0x6, 0x6, -1, -1, -1, -1 },
+ { -1, -1, 0x8, 0x8, -1, -1, -1, -1, -1 },
+ { -1, 0xe, 0xe, -1, -1, -1, -1, -1, -1 },
+ { 0xa, 0xa, 0xa, -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, -1, -1, -1, -1, -1, -1, -1 },
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+};
+
+// PLL Configuration based on the table in MPC603E7VEC page 29
+static const int mpc603ev_pll_config[12][9] =
+{
+ // 16, 20, 25, 33, 40, 50, 60, 66, 75
+ { -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, -1 },
+ // 2:1
+ { -1, -1, -1, -1, -1, -1, -1, 0x4, 0x4 },
+ // 2.5:1
+ { -1, -1, -1, -1, -1, 0x6, 0x6, 0x6, 0x6 },
+ // 3:1
+ { -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8, 0x8 },
+ // 3.5:1
+ { -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe, -1 },
+ // 4:1
+ { -1, -1, -1, 0xa, 0xa, 0xa, 0xa, -1, -1 },
+ // 4.5:1
+ { -1, -1, -1, 0x7, 0x7, 0x7, -1, -1, -1 },
+ // 5:1
+ { -1, -1, 0xb, 0xb, 0xb, -1, -1, -1, -1 },
+ // 5.5:1
+ { -1, -1, 0x9, 0x9, 0x9, -1, -1, -1, -1 },
+ // 6:1
+ { -1, -1, 0xd, 0xd, 0xd, -1, -1, -1, -1 }
+};
+
+// PLL Configuration based on the table in MPC603E7TEC page 23
+static const int mpc603r_pll_config[12][9] =
+{
+ // 16, 20, 25, 33, 40, 50, 60, 66, 75
+ { -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, -1 },
+ // 2:1
+ { -1, -1, -1, -1, 0x5, 0x5, 0x5, 0x5, 0x5 },
+ // 2.5:1
+ { -1, -1, -1, -1, -1, -1, 0x6, 0x6, 0x6 },
+ // 3:1
+ { -1, -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8 },
+ // 3.5:1
+ { -1, -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe },
+ // 4:1
+ { -1, -1, -1, -1, 0xa, 0xa, 0xa, 0xa, 0xa },
+ // 4.5:1
+ { -1, -1, -1, 0x7, 0x7, 0x7, 0x7, 0x7, -1 },
+ // 5:1
+ { -1, -1, -1, 0xb, 0xb, 0xb, 0xb, -1, -1 },
+ // 5.5:1
+ { -1, -1, -1, 0x9, 0x9, 0x9, -1, -1, -1 },
+ // 6:1
+ { -1, -1, 0xd, 0xd, 0xd, 0xd, -1, -1, -1 },
+};
+
+#define PPCDRC_OPTIONS_CHECK_SELFMOD_CODE 0x1
+
+enum
+{
+ CPUINFO_INT_PPC_DRC_OPTIONS = CPUINFO_INT_CPU_SPECIFIC,
+};
+
+typedef struct {
+ PPC_MODEL pvr;
+ int bus_frequency_multiplier;
+ PPC_BUS_FREQUENCY bus_frequency;
+} ppc_config;
+
+#if (HAS_PPC403)
+typedef UINT8 (* SPU_RX_HANDLER)(void);
+typedef void (* SPU_TX_HANDLER)(UINT8);
+typedef void (* PPC_DMA_HANDLER)(int);
+
+void ppc403_spu_rx(UINT8 data);
+void ppc403_install_spu_rx_handler(SPU_RX_HANDLER rx_handler);
+void ppc403_install_spu_tx_handler(SPU_TX_HANDLER tx_handler);
+void ppc403_install_spu_rx_dma_handler(PPC_DMA_HANDLER rx_dma_handler, UINT8 *buffer);
+void ppc403_install_spu_tx_dma_handler(PPC_DMA_HANDLER tx_dma_handler, UINT8 *buffer);
+void ppc403_install_dma_read_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer);
+void ppc403_install_dma_write_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer);
+
+#define PPC403_SPU_RX 5
+#define PPC403_SPU_TX 6
+#define PPC403_CRITICAL_IRQ 7
+
+#endif
+
+#if (HAS_PPC403)
+void ppc403_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_PPC602)
+void ppc602_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_PPC603)
+void ppc603_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_MPC8240)
+void mpc8240_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#if (HAS_PPC601)
+void ppc601_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#ifdef MAME_DEBUG
+extern offs_t ppc_dasm_one(char *buffer, offs_t pc, UINT32 op);
+#endif
+
+#endif /* _PPC_H */
diff --git a/src/emu/cpu/powerpc/ppc403.c b/src/emu/cpu/powerpc/ppc403.c
new file mode 100644
index 00000000000..d4370e9fdeb
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppc403.c
@@ -0,0 +1,964 @@
+/* PowerPC 403 specific functions */
+
+static void ppc403_dma_exec(int ch);
+
+#define DMA_CE 0x80000000
+#define DMA_CIE 0x40000000
+#define DMA_TD 0x20000000
+#define DMA_PL 0x10000000
+#define DMA_DAI 0x02000000
+#define DMA_SAI 0x01000000
+#define DMA_CP 0x00800000
+#define DMA_ETD 0x00000200
+#define DMA_TCE 0x00000100
+#define DMA_CH 0x00000080
+#define DMA_BME 0x00000040
+#define DMA_ECE 0x00000020
+#define DMA_TCD 0x00000010
+#define DMA_PCE 0x00000008
+
+static SPU_RX_HANDLER spu_rx_handler;
+static SPU_TX_HANDLER spu_tx_handler;
+static TIMER_CALLBACK( ppc403_spu_rx_callback );
+static TIMER_CALLBACK( ppc403_spu_tx_callback );
+
+static PPC_DMA_HANDLER spu_rx_dma_handler;
+static PPC_DMA_HANDLER spu_tx_dma_handler;
+static UINT8 *spu_rx_dma_ptr;
+static UINT8 *spu_tx_dma_ptr;
+
+static PPC_DMA_HANDLER dma_read_handler[4];
+static PPC_DMA_HANDLER dma_write_handler[4];
+static UINT8 *dma_read_ptr[4];
+static UINT8 *dma_write_ptr[4];
+
+INLINE void ppc_set_dcr(int dcr, UINT32 value)
+{
+ switch(dcr)
+ {
+ case DCR_BEAR: ppc.bear = value; break;
+ case DCR_BESR: ppc.besr = value; break;
+ case DCR_BR0: ppc.br[0] = value; break;
+ case DCR_BR1: ppc.br[1] = value; break;
+ case DCR_BR2: ppc.br[2] = value; break;
+ case DCR_BR3: ppc.br[3] = value; break;
+ case DCR_BR4: ppc.br[4] = value; break;
+ case DCR_BR5: ppc.br[5] = value; break;
+ case DCR_BR6: ppc.br[6] = value; break;
+ case DCR_BR7: ppc.br[7] = value; break;
+
+ case DCR_EXISR: ppc.exisr &= ~value; break;
+ case DCR_EXIER: EXIER = value; ppc.exisr &= EXIER; break;
+ case DCR_IOCR: ppc.iocr = value; break;
+ case DCR_DMASR: break; /* TODO */
+ case DCR_DMADA0: ppc.dma[0].da = value; break;
+ case DCR_DMADA1: ppc.dma[1].da = value; break;
+ case DCR_DMADA2: ppc.dma[2].da = value; break;
+ case DCR_DMADA3: ppc.dma[3].da = value; break;
+ case DCR_DMASA0: ppc.dma[0].sa = value; break;
+ case DCR_DMASA1: ppc.dma[1].sa = value; break;
+ case DCR_DMASA2: ppc.dma[2].sa = value; break;
+ case DCR_DMASA3: ppc.dma[3].sa = value; break;
+ case DCR_DMACT0: ppc.dma[0].ct = value; break;
+ case DCR_DMACT1: ppc.dma[1].ct = value; break;
+ case DCR_DMACT2: ppc.dma[2].ct = value; break;
+ case DCR_DMACT3: ppc.dma[3].ct = value; break;
+ case DCR_DMACR0: ppc.dma[0].cr = value; ppc403_dma_exec(0); break;
+ case DCR_DMACR1: ppc.dma[1].cr = value; ppc403_dma_exec(1); break;
+ case DCR_DMACR2: ppc.dma[2].cr = value; ppc403_dma_exec(2); break;
+ case DCR_DMACR3: ppc.dma[3].cr = value; ppc403_dma_exec(3); break;
+
+ default:
+ fatalerror("ppc: set_dcr: Unimplemented DCR %X", dcr);
+ break;
+ }
+}
+
+INLINE UINT32 ppc_get_dcr(int dcr)
+{
+ switch(dcr)
+ {
+ case DCR_BEAR: return ppc.bear;
+ case DCR_BESR: return ppc.besr;
+ case DCR_BR0: return ppc.br[0];
+ case DCR_BR1: return ppc.br[1];
+ case DCR_BR2: return ppc.br[2];
+ case DCR_BR3: return ppc.br[3];
+ case DCR_BR4: return ppc.br[4];
+ case DCR_BR5: return ppc.br[5];
+ case DCR_BR6: return ppc.br[6];
+ case DCR_BR7: return ppc.br[7];
+ case DCR_EXISR: return EXISR;
+ case DCR_EXIER: return EXIER;
+ case DCR_IOCR: return ppc.iocr;
+ case DCR_DMASR: return ppc.dmasr;
+ case DCR_DMADA0: return ppc.dma[0].da;
+ case DCR_DMADA1: return ppc.dma[1].da;
+ case DCR_DMADA2: return ppc.dma[2].da;
+ case DCR_DMADA3: return ppc.dma[3].da;
+ case DCR_DMASA0: return ppc.dma[0].sa;
+ case DCR_DMASA1: return ppc.dma[1].sa;
+ case DCR_DMASA2: return ppc.dma[2].sa;
+ case DCR_DMASA3: return ppc.dma[3].sa;
+ case DCR_DMACT0: return ppc.dma[0].ct;
+ case DCR_DMACT1: return ppc.dma[1].ct;
+ case DCR_DMACT2: return ppc.dma[2].ct;
+ case DCR_DMACT3: return ppc.dma[3].ct;
+ case DCR_DMACR0: return ppc.dma[0].cr;
+ case DCR_DMACR1: return ppc.dma[1].cr;
+ case DCR_DMACR2: return ppc.dma[2].cr;
+ case DCR_DMACR3: return ppc.dma[3].cr;
+
+ default:
+ fatalerror("ppc: get_dcr: Unimplemented DCR %X", dcr);
+ break;
+ }
+}
+
+
+
+#ifndef PPC_DRC
+INLINE void ppc403_check_interrupts(void)
+{
+ if (MSR & MSR_EE)
+ {
+ if (ppc.interrupt_pending != 0)
+ {
+ if (ppc.interrupt_pending & 0x1)
+ {
+ ppc403_exception(EXCEPTION_IRQ);
+ }
+ else if (ppc.interrupt_pending & 0x2)
+ {
+ ppc403_exception(EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER);
+ }
+ else if (ppc.interrupt_pending & 0x4)
+ {
+ ppc403_exception(EXCEPTION_FIXED_INTERVAL_TIMER);
+ }
+ }
+ }
+}
+
+static void ppc403_reset(void)
+{
+ ppc.pc = ppc.npc = 0xfffffffc;
+
+ ppc_set_msr(0);
+ change_pc(ppc.pc);
+}
+
+static int ppc403_execute(int cycles)
+{
+ UINT32 fit_trigger_cycle;
+ ppc_icount = cycles;
+ ppc_tb_base_icount = cycles;
+ change_pc(ppc.npc);
+
+ fit_trigger_cycle = 0x7fffffff;
+
+ if (ppc.fit_int_enable)
+ {
+ UINT32 tb = (UINT32)ppc.tb;
+ UINT32 fit_cycles = 0;
+
+ if (ppc.tb & ppc.fit_bit)
+ {
+ fit_cycles += ppc.fit_bit;
+ tb += fit_cycles;
+ }
+
+ fit_cycles += ppc.fit_bit - (tb & (ppc.fit_bit-1));
+
+ fit_trigger_cycle = ppc_icount - fit_cycles;
+ }
+
+ while( ppc_icount > 0 )
+ {
+ UINT32 opcode;
+
+ CALL_MAME_DEBUG;
+ ppc.pc = ppc.npc;
+ ppc.npc += 4;
+ opcode = ROPCODE(ppc.pc);
+
+ switch(opcode >> 26)
+ {
+ case 19: optable19[(opcode >> 1) & 0x3ff](opcode); break;
+ case 31: optable31[(opcode >> 1) & 0x3ff](opcode); break;
+ case 59: optable59[(opcode >> 1) & 0x3ff](opcode); break;
+ case 63: optable63[(opcode >> 1) & 0x3ff](opcode); break;
+ default: optable[opcode >> 26](opcode); break;
+ }
+
+ ppc_icount--;
+
+ /* Programmable Interval Timer (PIT) */
+ if (ppc.pit_counter > 0)
+ {
+ ppc.pit_counter--;
+ if (ppc.pit_counter == 0)
+ {
+ if (ppc.pit_int_enable) {
+ ppc.interrupt_pending |= 0x2;
+ }
+ if (ppc.tcr & 0x00400000) // Automatic reload
+ {
+ ppc.pit_counter = ppc.pit;
+ }
+ }
+ }
+
+ /* Fixed Interval Timer */
+ if (fit_trigger_cycle != 0x7fffffff)
+ {
+ if (ppc_icount == fit_trigger_cycle)
+ {
+ if (ppc.fit_int_enable)
+ {
+ fit_trigger_cycle -= ppc.fit_bit;
+ ppc.interrupt_pending |= 0x4;
+ }
+ }
+ }
+
+#if 0
+ /* Watchdog Timer */
+ if (((UINT32)(ppc.tb) & ppc.wdt_bit) && (tblo & ppc.wdt_bit) == 0) {
+ switch((ppc.tsr >> 28) & 0x3)
+ {
+ case 0: ppc.tsr |= TSR_ENW; break;
+ case 1: ppc.tsr |= TSR_ENW; break;
+ case 2:
+ if (ppc.wdt_int_enable && (ppc.msr & MSR_CE)) {
+ ppc403_exception(EXCEPTION_WATCHDOG_TIMER);
+ }
+ break;
+ case 3:
+ fatalerror("PPC: Watchdog Timer caused reset");
+ break;
+ }
+ }
+#endif
+
+ ppc403_check_interrupts();
+ }
+
+ // update timebase
+ ppc.tb += (ppc_tb_base_icount - ppc_icount);
+
+ return cycles - ppc_icount;
+}
+
+void ppc403_exception(int exception)
+{
+ switch( exception )
+ {
+ case EXCEPTION_IRQ: /* External Interrupt */
+ {
+ if( ppc_get_msr() & MSR_EE ) {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr;
+
+ msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR
+ if( msr & MSR_LE )
+ msr |= MSR_ILE;
+ else
+ msr &= ~MSR_ILE;
+ ppc_set_msr(msr);
+
+ ppc.npc = EVPR | 0x0500;
+ change_pc(ppc.npc);
+
+ ppc.interrupt_pending &= ~0x1;
+ }
+ break;
+ }
+
+ case EXCEPTION_TRAP: /* Program exception / Trap */
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.pc;
+ SRR1 = msr;
+
+ msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0700;
+ else
+ ppc.npc = EVPR | 0x0700;
+ change_pc(ppc.npc);
+ break;
+ }
+
+ case EXCEPTION_SYSTEM_CALL: /* System call */
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr;
+
+ msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0c00;
+ else
+ ppc.npc = EVPR | 0x0c00;
+ change_pc(ppc.npc);
+ break;
+ }
+
+ case EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER:
+ {
+ if( ppc_get_msr() & MSR_EE ) {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr;
+
+ msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR
+ if( msr & MSR_LE )
+ msr |= MSR_ILE;
+ else
+ msr &= ~MSR_ILE;
+ ppc_set_msr(msr);
+
+ ppc.npc = EVPR | 0x1000;
+ change_pc(ppc.npc);
+
+ ppc.tsr |= 0x08000000; // PIT interrupt
+ ppc.interrupt_pending &= ~0x2;
+ }
+ break;
+ }
+
+ case EXCEPTION_FIXED_INTERVAL_TIMER: /* Fixed Interval Timer */
+ {
+ if( ppc_get_msr() & MSR_EE ) {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr;
+
+ msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR
+ if( msr & MSR_LE )
+ msr |= MSR_ILE;
+ else
+ msr &= ~MSR_ILE;
+ ppc_set_msr(msr);
+
+ ppc.npc = EVPR | 0x1010;
+ change_pc(ppc.npc);
+ ppc.interrupt_pending &= ~0x4;
+ }
+ break;
+ }
+
+ case EXCEPTION_WATCHDOG_TIMER: /* Watchdog Timer */
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR2 = ppc.npc;
+ SRR3 = msr;
+
+ msr &= ~(MSR_WE | MSR_PR | MSR_CE | MSR_EE | MSR_DE | MSR_PE | MSR_DR | MSR_IR);
+ if (msr & MSR_LE)
+ msr |= MSR_ILE;
+ else
+ msr &= ~MSR_ILE;
+ ppc_set_msr(msr);
+
+ ppc.npc = EVPR | 0x1020;
+ change_pc(ppc.npc);
+ break;
+ }
+
+ case EXCEPTION_CRITICAL_INTERRUPT:
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR2 = ppc.npc;
+ SRR3 = msr;
+
+ msr &= ~(MSR_WE | MSR_PR | MSR_CE | MSR_EE | MSR_DE | MSR_PE | MSR_DR | MSR_IR);
+ if (msr & MSR_LE)
+ msr |= MSR_ILE;
+ else
+ msr &= ~MSR_ILE;
+ ppc_set_msr(msr);
+
+ EXISR |= 0x80000000;
+ ppc.npc = EVPR | 0x100;
+ change_pc(ppc.npc);
+ break;
+ }
+
+ default:
+ fatalerror("ppc: Unhandled exception %d", exception);
+ break;
+ }
+}
+
+static void ppc403_set_irq_line(int irqline, int state)
+{
+ if (irqline >= INPUT_LINE_IRQ0 && irqline <= INPUT_LINE_IRQ4)
+ {
+ UINT32 mask = (1 << (4 - irqline));
+ if( state == ASSERT_LINE) {
+ if( EXIER & mask ) {
+ ppc.exisr |= mask;
+ ppc.interrupt_pending |= 0x1;
+
+ if (ppc.irq_callback)
+ {
+ ppc.irq_callback(irqline);
+ }
+ }
+ }
+ // clear line is used to clear the interrupt when the interrupts are level-sensitive
+ else if (state == CLEAR_LINE)
+ {
+ ppc.exisr &= ~mask;
+ }
+ }
+ else if (irqline == PPC403_SPU_RX)
+ {
+ UINT32 mask = 0x08000000;
+ if (state) {
+ if( EXIER & mask ) {
+ ppc.exisr |= mask;
+ ppc.interrupt_pending |= 0x1;
+ }
+ }
+ }
+ else if (irqline == PPC403_SPU_TX)
+ {
+ UINT32 mask = 0x04000000;
+ if (state) {
+ if( EXIER & mask ) {
+ ppc.exisr |= mask;
+ ppc.interrupt_pending |= 0x1;
+ }
+ }
+ }
+ else if (irqline == PPC403_CRITICAL_IRQ)
+ {
+ if (state) {
+ if (EXIER & 0x80000000) {
+ ppc403_exception(EXCEPTION_CRITICAL_INTERRUPT);
+ }
+ }
+ }
+ else
+ {
+ fatalerror("PPC: Unknown IRQ line %d", irqline);
+ }
+}
+
+static void ppc403_dma_set_irq_line(int dma, int state)
+{
+ UINT32 mask = (1 << (3 - dma)) << 20;
+ if( state ) {
+ if( EXIER & mask ) {
+ ppc.exisr |= mask;
+ ppc.interrupt_pending |= 0x1;
+ }
+ }
+}
+#endif
+
+#ifdef PPC_DRC
+static void ppc403_dma_set_irq_line(int dma, int state)
+{
+ UINT32 mask = (1 << (3 - dma)) << 20;
+ if( state ) {
+ if( EXIER & mask ) {
+ ppc.exisr |= mask;
+ ppc.exception_pending |= 0x1;
+ }
+ }
+}
+#endif
+
+
+
+
+
+
+#ifndef PPC_DRC
+static void ppc_dccci(UINT32 op)
+{
+
+}
+
+static void ppc_dcread(UINT32 op)
+{
+
+}
+
+static void ppc_icbt(UINT32 op)
+{
+
+}
+
+static void ppc_iccci(UINT32 op)
+{
+
+}
+
+static void ppc_icread(UINT32 op)
+{
+
+}
+
+static void ppc_rfci(UINT32 op)
+{
+ UINT32 msr;
+ ppc.npc = ppc.srr2;
+ msr = ppc.srr3;
+ ppc_set_msr( msr );
+
+ change_pc(ppc.npc);
+}
+#endif
+
+static void ppc_mfdcr(UINT32 op)
+{
+ REG(RT) = ppc_get_dcr(SPR);
+}
+
+static void ppc_mtdcr(UINT32 op)
+{
+ ppc_set_dcr(SPR, REG(RS));
+}
+
+static void ppc_wrtee(UINT32 op)
+{
+ if( REG(RS) & 0x8000 )
+ ppc_set_msr( ppc_get_msr() | MSR_EE);
+ else
+ ppc_set_msr( ppc_get_msr() & ~MSR_EE);
+}
+
+static void ppc_wrteei(UINT32 op)
+{
+ if( op & 0x8000 )
+ ppc_set_msr( ppc_get_msr() | MSR_EE);
+ else
+ ppc_set_msr( ppc_get_msr() & ~MSR_EE);
+}
+
+
+
+/**************************************************************************/
+/* PPC403 Serial Port */
+
+UINT8 ppc403_spu_r(UINT32 a)
+{
+ switch(a & 0xf)
+ {
+ case 0x0: return ppc.spu.spls | 0x6; /* transmit buffer is always empty */
+ case 0x2: return ppc.spu.sphs;
+ case 0x4: return (ppc.spu.brd >> 8) & 0xf;
+ case 0x5: return (ppc.spu.brd & 0xff);
+ case 0x6: return ppc.spu.spctl;
+ case 0x7: return ppc.spu.sprc;
+ case 0x8: return ppc.spu.sptc;
+ case 0x9: return ppc.spu.sprb;
+ default: fatalerror("ppc: spu_r: %02X", a & 0xf);
+ }
+}
+
+void ppc403_spu_w(UINT32 a, UINT8 d)
+{
+ switch(a & 0xf)
+ {
+ case 0x0:
+ if( d & 0x80 ) ppc.spu.spls &= ~0x80;
+ if( d & 0x40 ) ppc.spu.spls &= ~0x40;
+ if( d & 0x20 ) ppc.spu.spls &= ~0x20;
+ if( d & 0x10 ) ppc.spu.spls &= ~0x10;
+ if( d & 0x08 ) ppc.spu.spls &= ~0x08;
+ break;
+
+ case 0x2:
+ ppc.spu.sphs = d;
+ break;
+
+ case 0x4:
+ ppc.spu.brd &= 0xff;
+ ppc.spu.brd |= (d << 8);
+ break;
+
+ case 0x5:
+ ppc.spu.brd &= 0xff00;
+ ppc.spu.brd |= d;
+ if (ppc.iocr & 0x2) {
+ mame_printf_debug("ppc: SPU Baud rate: %d\n", (3686400 / (ppc.spu.brd + 1)) / 16);
+ } else {
+ mame_printf_debug("ppc: SPU Baud rate: %d\n", (33333333 / (ppc.spu.brd + 1)) / 16);
+ }
+ break;
+
+ case 0x6:
+ ppc.spu.spctl = d;
+ break;
+
+ case 0x7:
+ ppc.spu.sprc = d;
+ if (ppc.spu.sprc & 0x80) /* enable RX */
+ {
+ int baud_rate;
+ if (ppc.iocr & 0x2) {
+ baud_rate = (3686400 / (ppc.spu.brd + 1)) / 16;
+ } else {
+ baud_rate = (33333333 / (ppc.spu.brd + 1)) / 16;
+ }
+
+ /* check if serial port is hooked to a DMA channel */
+ /* if so, do a DMA operation */
+ if( ((((ppc.spu.sprc >> 5) & 0x3) == 2) && (ppc.dma[2].cr & DMA_CE)) ||
+ ((((ppc.spu.sprc >> 5) & 0x3) == 3) && (ppc.dma[3].cr & DMA_CE)) )
+ {
+ int i;
+ int ch = (ppc.spu.sprc >> 5) & 0x3;
+ // mame_printf_debug("ppc: DMA from serial port on channel %d (DA: %08X)\n", ch, ppc.dma[ch].da);
+
+ if (spu_rx_dma_handler)
+ {
+ int length = ppc.dma[ch].ct;
+
+ spu_rx_dma_handler(length);
+
+ for (i=0; i < length; i++)
+ {
+ program_write_byte_32be(ppc.dma[ch].da++, spu_rx_dma_ptr[i]);
+ }
+ }
+
+ ppc.dmasr |= (1 << (27 - ch));
+
+ /* generate interrupts */
+ if( ppc.dma[ch].cr & DMA_CIE )
+ {
+ ppc403_dma_set_irq_line( ch, PULSE_LINE );
+ }
+
+ /* set receive buffer full */
+ ppc.spu.spls = 0x80;
+
+#ifndef PPC_DRC
+ ppc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE);
+#else
+ ppcdrc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE);
+#endif
+ }
+ }
+ else /* disable RX */
+ {
+ }
+ break;
+
+ case 0x8:
+ ppc.spu.sptc = d;
+ break;
+
+ case 0x9:
+ ppc.spu.sptb = d;
+ ppc403_spu_tx_callback(Machine, cpu_getactivecpu());
+ break;
+
+ default:
+ fatalerror("ppc: spu_w: %02X, %02X", a & 0xf, d);
+ break;
+ }
+ //mame_printf_debug("spu_w: %02X, %02X at %08X\n", a & 0xf, d, ppc.pc);
+}
+
+void ppc403_spu_rx(UINT8 data)
+{
+ ppc.spu.sprb = data;
+
+ /* set receive buffer full */
+ ppc.spu.spls = 0x80;
+
+ /* generate interrupt if DMA is disabled and RBR interrupt is enabled */
+ if (((ppc.spu.sprc >> 5) & 0x3) == 0x01) {
+#ifndef PPC_DRC
+ ppc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE);
+#else
+ ppcdrc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE);
+#endif
+ }
+}
+
+static TIMER_CALLBACK( ppc403_spu_rx_callback )
+{
+ if (spu_rx_handler != NULL)
+ {
+ ppc403_spu_rx(spu_rx_handler());
+ }
+}
+
+static TIMER_CALLBACK( ppc403_spu_tx_callback )
+{
+ if (spu_tx_handler != NULL)
+ {
+ spu_tx_handler(ppc.spu.sptb);
+
+ /* generate interrupt if DMA is disabled and TBR interrupt is enabled */
+ if (((ppc.spu.sptc >> 5) & 0x3) == 0x01) {
+#ifndef PPC_DRC
+ ppc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE);
+#else
+ ppcdrc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE);
+#endif
+ }
+ }
+}
+
+void ppc403_install_spu_rx_handler(SPU_RX_HANDLER rx_handler)
+{
+ spu_rx_handler = rx_handler;
+}
+
+void ppc403_install_spu_tx_handler(SPU_TX_HANDLER tx_handler)
+{
+ spu_tx_handler = tx_handler;
+}
+
+
+void ppc403_spu_rx_dma(UINT8 *data, int length)
+{
+
+}
+
+void ppc403_install_spu_rx_dma_handler(PPC_DMA_HANDLER rx_dma_handler, UINT8 *buffer)
+{
+ spu_rx_dma_handler = rx_dma_handler;
+ spu_rx_dma_ptr = buffer;
+}
+
+void ppc403_install_spu_tx_dma_handler(PPC_DMA_HANDLER tx_dma_handler, UINT8 *buffer)
+{
+ spu_tx_dma_handler = tx_dma_handler;
+ spu_tx_dma_ptr = buffer;
+}
+
+/*********************************************************************************/
+
+/* PPC 403 DMA */
+
+static const int dma_transfer_width[4] = { 1, 2, 4, 16 };
+
+void ppc403_install_dma_read_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer)
+{
+ dma_read_handler[ch] = dma_handler;
+ dma_read_ptr[ch] = buffer;
+}
+
+void ppc403_install_dma_write_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer)
+{
+ dma_write_handler[ch] = dma_handler;
+ dma_write_ptr[ch] = buffer;
+}
+
+static void ppc403_dma_exec(int ch)
+{
+ int i;
+ int dai, sai, width;
+
+ /* Is the DMA channel enabled ? */
+ if( ppc.dma[ch].cr & DMA_CE )
+ {
+ /* transfer width */
+ width = dma_transfer_width[(ppc.dma[ch].cr >> 26) & 0x3];
+
+ if( ppc.dma[ch].cr & DMA_DAI )
+ dai = width;
+ else
+ dai = 0; /* DA not incremented */
+
+ if( ppc.dma[ch].cr & DMA_SAI )
+ sai = width;
+ else
+ sai = 0; /* SA not incremented */
+
+
+ /* transfer mode */
+ switch( (ppc.dma[ch].cr >> 21) & 0x3 )
+ {
+ case 0: /* buffered DMA */
+ if( ppc.dma[ch].cr & DMA_TD ) /* peripheral to mem */
+ {
+ // nothing to do for now */
+ }
+ else /* mem to peripheral */
+ {
+
+ /* check if the serial port is hooked to channel 2 or 3 */
+ if( (ch == 2 && ((ppc.spu.sptc >> 5) & 0x3) == 2) ||
+ (ch == 3 && ((ppc.spu.sptc >> 5) & 0x3) == 3) )
+ {
+ mame_printf_debug("ppc: dma_exec: DMA to serial port on channel %d (DA: %08X)\n", ch, ppc.dma[ch].da);
+
+ if (spu_tx_dma_handler)
+ {
+ int length = ppc.dma[ch].ct;
+
+ for( i=0; i < length; i++ ) {
+ spu_tx_dma_ptr[i] = program_read_byte_32be(ppc.dma[ch].da++);
+ }
+ spu_tx_dma_handler(length);
+ }
+
+#ifndef PPC_DRC
+ ppc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE);
+#else
+ ppcdrc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE);
+#endif
+ }
+ else {
+ fatalerror("ppc: dma_exec: buffered DMA to unknown peripheral ! (channel %d)", ch);
+ }
+
+ }
+ break;
+
+ case 1: /* fly-by DMA */
+ fatalerror("ppc: dma_exec: fly-by DMA not implemented");
+ break;
+
+ case 2: /* software initiated mem-to-mem DMA */
+ //mame_printf_debug("ppc: DMA (%d, SW mem-to-mem): SA = %08X, DA = %08X, CT = %08X\n", ch, ppc.dma[ch].sa, ppc.dma[ch].da, ppc.dma[ch].ct);
+
+ switch(width)
+ {
+ case 1: /* Byte transfer */
+ for (i=0; i < ppc.dma[ch].ct; i++)
+ {
+ UINT8 b = READ8(ppc.dma[ch].sa);
+ WRITE8(ppc.dma[ch].da, b);
+ ppc.dma[ch].sa += sai;
+ ppc.dma[ch].da += dai;
+ }
+ break;
+ case 2: /* Word transfer */
+ for (i=0; i < ppc.dma[ch].ct; i++)
+ {
+ UINT16 w = READ16(ppc.dma[ch].sa);
+ WRITE16(ppc.dma[ch].da, w);
+ ppc.dma[ch].sa += sai;
+ ppc.dma[ch].da += dai;
+ }
+ break;
+ case 4: /* Double word transfer */
+ for (i=0; i < ppc.dma[ch].ct; i++)
+ {
+ UINT32 d = READ32(ppc.dma[ch].sa);
+ WRITE32(ppc.dma[ch].da, d);
+ ppc.dma[ch].sa += sai;
+ ppc.dma[ch].da += dai;
+ }
+ break;
+ case 16: /* 16-byte transfer */
+ for (i=0; i < ppc.dma[ch].ct; i++)
+ {
+ UINT32 d1 = READ32(ppc.dma[ch].sa+0);
+ UINT32 d2 = READ32(ppc.dma[ch].sa+4);
+ UINT32 d3 = READ32(ppc.dma[ch].sa+8);
+ UINT32 d4 = READ32(ppc.dma[ch].sa+12);
+ WRITE32(ppc.dma[ch].da+0, d1);
+ WRITE32(ppc.dma[ch].da+4, d2);
+ WRITE32(ppc.dma[ch].da+8, d3);
+ WRITE32(ppc.dma[ch].da+12, d4);
+ ppc.dma[ch].sa += 16;
+ ppc.dma[ch].da += 16;
+ }
+ break;
+ default:
+ fatalerror("dma: dma_exec: SW mem-to-mem DMA, width = %d", width);
+ }
+ break;
+
+ case 3: /* hardware initiated mem-to-mem DMA */
+ fatalerror("ppc: dma_exec: HW mem-to-mem DMA not implemented");
+ break;
+ }
+
+ ppc.dmasr |= (1 << (27 - ch));
+
+ /* DEBUG: check for not yet supported features */
+ if( (ppc.dma[ch].cr & DMA_TCE) == 0 )
+ fatalerror("ppc: dma_exec: DMA_TCE == 0");
+
+ if( ppc.dma[ch].cr & DMA_CH )
+ fatalerror("ppc: dma_exec: DMA chaining not implemented");
+
+ /* generate interrupts */
+ if( ppc.dma[ch].cr & DMA_CIE )
+ ppc403_dma_set_irq_line( ch, PULSE_LINE );
+
+ }
+}
+
+/*********************************************************************************/
+
+static UINT8 ppc403_read8(UINT32 a)
+{
+ if(a >= 0x40000000 && a <= 0x4000000f) /* Serial Port */
+ return ppc403_spu_r(a);
+ return program_read_byte_32be(a);
+}
+
+#define ppc403_read16 program_read_word_32be
+#define ppc403_read32 program_read_dword_32be
+
+static void ppc403_write8(UINT32 a, UINT8 d)
+{
+ if( a >= 0x40000000 && a <= 0x4000000f ) /* Serial Port */
+ {
+ ppc403_spu_w(a, d);
+ return;
+ }
+ program_write_byte_32be(a, d);
+}
+
+#define ppc403_write16 program_write_word_32be
+#define ppc403_write32 program_write_dword_32be
+
+static UINT16 ppc403_read16_unaligned(UINT32 a)
+{
+ fatalerror("ppc: Unaligned read16 %08X at %08X", a, ppc.pc);
+ return 0;
+}
+
+static UINT32 ppc403_read32_unaligned(UINT32 a)
+{
+ fatalerror("ppc: Unaligned read32 %08X at %08X", a, ppc.pc);
+ return 0;
+}
+
+static void ppc403_write16_unaligned(UINT32 a, UINT16 d)
+{
+ fatalerror("ppc: Unaligned write16 %08X, %04X at %08X", a, d, ppc.pc);
+}
+
+static void ppc403_write32_unaligned(UINT32 a, UINT32 d)
+{
+ fatalerror("ppc: Unaligned write32 %08X, %08X at %08X", a, d, ppc.pc);
+}
+
diff --git a/src/emu/cpu/powerpc/ppc602.c b/src/emu/cpu/powerpc/ppc602.c
new file mode 100644
index 00000000000..a53b08850af
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppc602.c
@@ -0,0 +1,293 @@
+static void ppc_dsa(UINT32 op)
+{
+ UINT32 msr = ppc_get_msr();
+
+ msr &= ~(MSR_SA | MSR_EE | MSR_PR | MSR_AP);
+ if (ppc.esasrr & 0x8) msr |= MSR_PR;
+ if (ppc.esasrr & 0x4) msr |= MSR_AP;
+ if (ppc.esasrr & 0x2) msr |= MSR_SA;
+ if (ppc.esasrr & 0x1) msr |= MSR_EE;
+
+ ppc_set_msr(msr);
+}
+
+static void ppc_esa(UINT32 op)
+{
+ int sa, ee, pr, ap;
+ UINT32 msr = ppc_get_msr();
+
+ sa = (msr & MSR_SA) ? 1 : 0;
+ ee = (msr & MSR_EE) ? 1 : 0;
+ pr = (msr & MSR_PR) ? 1 : 0;
+ ap = (msr & MSR_AP) ? 1 : 0;
+
+ ppc.esasrr = (pr << 3) | (ap << 2) | (sa << 1) | (ee);
+
+ msr &= ~(MSR_EE | MSR_PR | MSR_AP);
+ msr |= MSR_SA;
+
+ ppc_set_msr(msr);
+}
+
+#ifndef PPC_DRC
+static void ppc_tlbli(UINT32 op)
+{
+
+}
+
+static void ppc_tlbld(UINT32 op)
+{
+
+}
+#endif
+
+#ifndef PPC_DRC
+void ppc602_exception(int exception)
+{
+ switch( exception )
+ {
+ case EXCEPTION_IRQ: /* External Interrupt */
+ if( ppc_get_msr() & MSR_EE ) {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr & 0xff73;
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0500;
+ else
+ ppc.npc = ppc.ibr | 0x0500;
+
+ ppc.interrupt_pending &= ~0x1;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_DECREMENTER: /* Decrementer overflow exception */
+ if( ppc_get_msr() & MSR_EE ) {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr & 0xff73;
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0900;
+ else
+ ppc.npc = ppc.ibr | 0x0900;
+
+ ppc.interrupt_pending &= ~0x2;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_TRAP: /* Program exception / Trap */
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.pc;
+ SRR1 = (msr & 0xff73) | 0x20000; /* 0x20000 = TRAP bit */
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0700;
+ else
+ ppc.npc = ppc.ibr | 0x0700;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_SYSTEM_CALL: /* System call */
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = (msr & 0xff73);
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0c00;
+ else
+ ppc.npc = ppc.ibr | 0x0c00;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_SMI:
+ if( ppc_get_msr() & MSR_EE ) {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr & 0xff73;
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x1400;
+ else
+ ppc.npc = ppc.ibr | 0x1400;
+
+ ppc.interrupt_pending &= ~0x4;
+ change_pc(ppc.npc);
+ }
+ break;
+
+
+ default:
+ fatalerror("ppc: Unhandled exception %d", exception);
+ break;
+ }
+}
+
+static void ppc602_set_irq_line(int irqline, int state)
+{
+ if( state ) {
+ ppc.interrupt_pending |= 0x1;
+ if (ppc.irq_callback)
+ {
+ ppc.irq_callback(irqline);
+ }
+ }
+}
+
+static void ppc602_set_smi_line(int state)
+{
+ if( state ) {
+ ppc.interrupt_pending |= 0x4;
+ }
+}
+
+INLINE void ppc602_check_interrupts(void)
+{
+ if (MSR & MSR_EE)
+ {
+ if (ppc.interrupt_pending != 0)
+ {
+ if (ppc.interrupt_pending & 0x1)
+ {
+ ppc602_exception(EXCEPTION_IRQ);
+ }
+ else if (ppc.interrupt_pending & 0x2)
+ {
+ ppc602_exception(EXCEPTION_DECREMENTER);
+ }
+ else if (ppc.interrupt_pending & 0x4)
+ {
+ ppc602_exception(EXCEPTION_SMI);
+ }
+ }
+ }
+}
+
+static void ppc602_reset(void)
+{
+ ppc.pc = ppc.npc = 0xfff00100;
+
+ ppc_set_msr(0x40);
+ change_pc(ppc.pc);
+
+ ppc.hid0 = 1;
+
+ ppc.interrupt_pending = 0;
+}
+
+static int ppc602_execute(int cycles)
+{
+ int exception_type;
+ UINT32 opcode;
+ ppc_icount = cycles;
+ ppc_tb_base_icount = cycles;
+ ppc_dec_base_icount = cycles;
+
+ // check if decrementer exception occurs during execution
+ if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC))
+ {
+ ppc_dec_trigger_cycle = ppc_icount - DEC;
+ }
+ else
+ {
+ ppc_dec_trigger_cycle = 0x7fffffff;
+ }
+
+ change_pc(ppc.npc);
+
+#ifdef __GNUC__
+ // MinGW's optimizer kills setjmp()/longjmp()
+ (void)__builtin_return_address(1);
+#endif
+
+ exception_type = setjmp(ppc.exception_jmpbuf);
+ if (exception_type)
+ {
+ ppc.npc = ppc.pc;
+ ppc602_exception(exception_type);
+ }
+
+ while( ppc_icount > 0 )
+ {
+ ppc.pc = ppc.npc;
+ CALL_MAME_DEBUG;
+
+ if (MSR & MSR_IR)
+ opcode = ppc_readop_translated(ppc.pc);
+ else
+ opcode = ROPCODE64(ppc.pc);
+
+ ppc.npc = ppc.pc + 4;
+ switch(opcode >> 26)
+ {
+ case 19: optable19[(opcode >> 1) & 0x3ff](opcode); break;
+ case 31: optable31[(opcode >> 1) & 0x3ff](opcode); break;
+ case 59: optable59[(opcode >> 1) & 0x3ff](opcode); break;
+ case 63: optable63[(opcode >> 1) & 0x3ff](opcode); break;
+ default: optable[opcode >> 26](opcode); break;
+ }
+
+ ppc_icount--;
+
+ if(ppc_icount == ppc_dec_trigger_cycle) {
+ ppc.interrupt_pending |= 0x2;
+ }
+
+ ppc602_check_interrupts();
+ }
+
+ // update timebase
+ // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly
+ ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4);
+
+ // update decrementer
+ DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2));
+
+
+ return cycles - ppc_icount;
+}
+#endif // PPC_DRC
diff --git a/src/emu/cpu/powerpc/ppc603.c b/src/emu/cpu/powerpc/ppc603.c
new file mode 100644
index 00000000000..b03affe7062
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppc603.c
@@ -0,0 +1,300 @@
+void ppc603_exception(int exception)
+{
+ switch( exception )
+ {
+ case EXCEPTION_IRQ: /* External Interrupt */
+ if( ppc_get_msr() & MSR_EE ) {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr & 0xff73;
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0500;
+ else
+ ppc.npc = 0x00000000 | 0x0500;
+
+ ppc.interrupt_pending &= ~0x1;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_DECREMENTER: /* Decrementer overflow exception */
+ if( ppc_get_msr() & MSR_EE ) {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr & 0xff73;
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0900;
+ else
+ ppc.npc = 0x00000000 | 0x0900;
+
+ ppc.interrupt_pending &= ~0x2;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_TRAP: /* Program exception / Trap */
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.pc;
+ SRR1 = (msr & 0xff73) | 0x20000; /* 0x20000 = TRAP bit */
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0700;
+ else
+ ppc.npc = 0x00000000 | 0x0700;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_SYSTEM_CALL: /* System call */
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = (msr & 0xff73);
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0c00;
+ else
+ ppc.npc = 0x00000000 | 0x0c00;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_SMI:
+ if( ppc_get_msr() & MSR_EE ) {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr & 0xff73;
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x1400;
+ else
+ ppc.npc = 0x00000000 | 0x1400;
+
+ ppc.interrupt_pending &= ~0x4;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_DSI:
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr & 0xff73;
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0300;
+ else
+ ppc.npc = 0x00000000 | 0x0300;
+
+ ppc.interrupt_pending &= ~0x4;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ case EXCEPTION_ISI:
+ {
+ UINT32 msr = ppc_get_msr();
+
+ SRR0 = ppc.npc;
+ SRR1 = msr & 0xff73;
+
+ msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
+ if( msr & MSR_ILE )
+ msr |= MSR_LE;
+ else
+ msr &= ~MSR_LE;
+ ppc_set_msr(msr);
+
+ if( msr & MSR_IP )
+ ppc.npc = 0xfff00000 | 0x0400;
+ else
+ ppc.npc = 0x00000000 | 0x0400;
+
+ ppc.interrupt_pending &= ~0x4;
+ change_pc(ppc.npc);
+ }
+ break;
+
+ default:
+ fatalerror("ppc: Unhandled exception %d", exception);
+ break;
+ }
+}
+
+static void ppc603_set_irq_line(int irqline, int state)
+{
+ if( state ) {
+ ppc.interrupt_pending |= 0x1;
+ if (ppc.irq_callback)
+ {
+ ppc.irq_callback(irqline);
+ }
+ }
+}
+
+#if HAS_PPC603
+static void ppc603_set_smi_line(int state)
+{
+ if( state ) {
+ ppc.interrupt_pending |= 0x4;
+ }
+}
+#endif
+
+INLINE void ppc603_check_interrupts(void)
+{
+ if (MSR & MSR_EE)
+ {
+ if (ppc.interrupt_pending != 0)
+ {
+ if (ppc.interrupt_pending & 0x1)
+ {
+ ppc603_exception(EXCEPTION_IRQ);
+ }
+ else if (ppc.interrupt_pending & 0x2)
+ {
+ ppc603_exception(EXCEPTION_DECREMENTER);
+ }
+ else if (ppc.interrupt_pending & 0x4)
+ {
+ ppc603_exception(EXCEPTION_SMI);
+ }
+ }
+ }
+}
+
+static void ppc603_reset(void)
+{
+ ppc.pc = ppc.npc = 0xfff00100;
+
+ ppc_set_msr(0x40);
+ change_pc(ppc.pc);
+
+ ppc.hid0 = 1;
+
+ ppc.interrupt_pending = 0;
+}
+
+
+static int ppc603_execute(int cycles)
+{
+ int exception_type;
+ UINT32 opcode;
+ ppc_icount = cycles;
+ ppc_tb_base_icount = cycles;
+ ppc_dec_base_icount = cycles + ppc.dec_frac;
+
+ // check if decrementer exception occurs during execution
+ if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC))
+ {
+ ppc_dec_trigger_cycle = ppc_icount - DEC;
+ }
+ else
+ {
+ ppc_dec_trigger_cycle = 0x7fffffff;
+ }
+
+ change_pc(ppc.npc);
+
+#ifdef __GNUC__
+ // MinGW's optimizer kills setjmp()/longjmp()
+ (void)__builtin_return_address(1);
+#endif
+
+ exception_type = setjmp(ppc.exception_jmpbuf);
+ if (exception_type)
+ {
+ ppc.npc = ppc.pc;
+ ppc603_exception(exception_type);
+ }
+
+ while( ppc_icount > 0 )
+ {
+ ppc.pc = ppc.npc;
+ CALL_MAME_DEBUG;
+
+ if (MSR & MSR_IR)
+ opcode = ppc_readop_translated(ppc.pc);
+ else
+ opcode = ROPCODE64(ppc.pc);
+
+ ppc.npc = ppc.pc + 4;
+ switch(opcode >> 26)
+ {
+ case 19: optable19[(opcode >> 1) & 0x3ff](opcode); break;
+ case 31: optable31[(opcode >> 1) & 0x3ff](opcode); break;
+ case 59: optable59[(opcode >> 1) & 0x3ff](opcode); break;
+ case 63: optable63[(opcode >> 1) & 0x3ff](opcode); break;
+ default: optable[opcode >> 26](opcode); break;
+ }
+
+ ppc_icount--;
+
+ if(ppc_icount == ppc_dec_trigger_cycle) {
+ ppc.interrupt_pending |= 0x2;
+ }
+
+ ppc603_check_interrupts();
+ }
+
+ // update timebase
+ // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly
+ ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4);
+
+ // update decrementer
+ ppc.dec_frac = ((ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2));
+ DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2));
+
+ return cycles - ppc_icount;
+}
diff --git a/src/emu/cpu/powerpc/ppc_dasm.c b/src/emu/cpu/powerpc/ppc_dasm.c
new file mode 100644
index 00000000000..4d30f9987d1
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppc_dasm.c
@@ -0,0 +1,1166 @@
+/*
+ * disasm.c
+ *
+ * PowerPC 603e disassembler.
+ *
+ * When possible, invalid forms of instructions are checked for. To the best
+ * of my knowledge, all appropriate load/store instructions are checked. I'm
+ * not sure whether any other kinds of instructions need checking.
+ */
+
+/* Originally written by Bart Trzynadlowski for Supermodel project
+ *
+ * PowerPC 403 opcodes and MAME conversion by Ville Linde
+ */
+
+#include "cpuintrf.h"
+#include "debugger.h"
+
+/*
+ * Masks
+ *
+ * These masks isolate fields in an instruction word.
+ */
+
+#define M_LI 0x03fffffc
+#define M_AA 0x00000002
+#define M_LK 0x00000001
+#define M_BO 0x03e00000
+#define M_BI 0x001f0000
+#define M_BD 0x0000fffc
+#define M_RT 0x03e00000
+#define M_RA 0x001f0000
+#define M_RB 0x0000f800
+#define M_CRFD 0x03800000
+#define M_L 0x00200000
+#define M_TO 0x03e00000
+#define M_D 0x0000ffff
+#define M_SIMM 0x0000ffff
+#define M_UIMM 0x0000ffff
+#define M_NB 0x0000f800
+#define M_SR 0x000f0000
+#define M_SH 0x0000f800
+#define M_CRFS 0x001c0000
+#define M_IMM 0x0000f000
+#define M_CRBD 0x03e00000
+#define M_RC 0x00000001
+#define M_CRBA 0x001f0000
+#define M_CRBB 0x0000f800
+#define M_SPR 0x001FF800
+#define M_TBR 0x001FF800
+#define M_CRM 0x000FF000
+#define M_DCR 0x001FF800
+#define M_FM 0x01FE0000
+#define M_OE 0x00000400
+#define M_REGC 0x000007c0
+#define M_MB 0x000007c0
+#define M_ME 0x0000003e
+#define M_XO 0x000007fe
+
+/*
+ * Field Defining Macros
+ *
+ * These macros generate instruction words with their associated fields filled
+ * in with the passed value.
+ */
+
+#define D_OP(op) ((op & 0x3f) << 26)
+#define D_XO(xo) ((xo & 0x3ff) << 1)
+#define D_RT(r) ((r & 0x1f) << (31 - 10))
+#define D_RA(r) ((r & 0x1f) << (31 - 15))
+#define D_UIMM(u) (u & 0xffff)
+
+/*
+ * Macros to Get Field Values
+ *
+ * These macros return the values of fields in an opcode. They all return
+ * unsigned values and do not perform any sign extensions.
+ */
+
+#define G_RT(op) ((op & M_RT) >> (31 - 10))
+#define G_RA(op) ((op & M_RA) >> (31 - 15))
+#define G_RB(op) ((op & M_RB) >> (31 - 20))
+#define G_SIMM(op) (op & M_SIMM)
+#define G_UIMM(op) (op & M_UIMM)
+#define G_LI(op) ((op & M_LI) >> 2)
+#define G_BO(op) ((op & M_BO) >> (31 - 10))
+#define G_BI(op) ((op & M_BI) >> (31 - 15))
+#define G_BD(op) ((op & M_BD) >> 2)
+#define G_CRFD(op) ((op & M_CRFD) >> (31 - 8))
+#define G_L(op) ((op & M_L) >> (31 - 10))
+#define G_CRBD(op) ((op & M_CRBD) >> (31 - 10))
+#define G_CRBA(op) ((op & M_CRBA) >> (31 - 15))
+#define G_CRBB(op) ((op & M_CRBB) >> (31 - 20))
+#define G_REGC(op) ((op & M_REGC) >> (31 - 25))
+#define G_D(op) (op & M_D)
+#define G_NB(op) ((op & M_NB) >> (31 - 20))
+#define G_CRFS(op) ((op & M_CRFS) >> (31 - 13))
+#define G_SPR(op) ((op & M_SPR) >> (31 - 20))
+#define G_DCR(op) ((op & M_DCR) >> (31 - 20))
+#define G_SR(op) ((op & M_SR) >> (31 - 15))
+#define G_CRM(op) ((op & M_CRM) >> (31 - 19))
+#define G_FM(op) ((op & M_FM) >> (31 - 14))
+#define G_IMM(op) ((op & M_IMM) >> (31 - 19))
+#define G_SH(op) ((op & M_SH) >> (31 - 20))
+#define G_MB(op) ((op & M_MB) >> (31 - 25))
+#define G_ME(op) ((op & M_ME) >> 1)
+#define G_TO(op) ((op & M_TO) >> (31 - 10))
+
+/*
+ * Operand Formats
+ *
+ * These convey information on what operand fields are present and how they
+ * ought to be printed.
+ *
+ * I'm fairly certain all of these are used, but that is not guaranteed.
+ */
+
+enum
+{
+ F_NONE, // <no operands>
+ F_LI, // LI*4+PC if AA=0 else LI*4
+ F_BCx, // BO, BI, target_addr used only by BCx
+ F_RT_RA_0_SIMM, // rT, rA|0, SIMM rA|0 means if rA == 0, print 0
+ F_ADDIS, // rT, rA, SIMM (printed as unsigned) only used by ADDIS
+ F_RT_RA_SIMM, // rT, rA, SIMM
+ F_RA_RT_UIMM, // rA, rT, UIMM
+ F_CMP_SIMM, // crfD, L, A, SIMM
+ F_CMP_UIMM, // crfD, L, A, UIMM
+ F_RT_RA_0_RB, // rT, rA|0, rB
+ F_RT_RA_RB, // rT, rA, rB
+ F_RT_D_RA_0, // rT, d(rA|0)
+ F_RT_D_RA, // rT, d(rA)
+ F_RA_RT_RB, // rA, rT, rB
+ F_FRT_D_RA_0, // frT, d(RA|0)
+ F_FRT_D_RA, // frT, d(RA)
+ F_FRT_RA_0_RB, // frT, rA|0, rB
+ F_FRT_RA_RB, // frT, rA, rB
+ F_TWI, // TO, rA, SIMM only used by TWI instruction
+ F_CMP, // crfD, L, rA, rB
+ F_RA_RT, // rA, rT
+ F_RA_0_RB, // rA|0, rB
+ F_FRT_FRB, // frT, frB
+ F_FCMP, // crfD, frA, frB
+ F_CRFD_CRFS, // crfD, crfS
+ F_MCRXR, // crfD only used by MCRXR
+ F_RT, // rT
+ F_MFSR, // rT, SR only used by MFSR
+ F_MTSR, // SR, rT only used by MTSR
+ F_MFFSx, // frT only used by MFFSx
+ F_FCRBD, // crbD FPSCR[crbD]
+ F_MTFSFIx, // crfD, IMM only used by MTFSFIx
+ F_RB, // rB
+ F_TW, // TO, rA, rB only used by TW
+ F_RT_RA_0_NB, // rT, rA|0, NB print 32 if NB == 0
+ F_SRAWIx, // rA, rT, SH only used by SRAWIx
+ F_BO_BI, // BO, BI
+ F_CRBD_CRBA_CRBB, // crbD, crbA, crbB
+ F_RT_SPR, // rT, SPR and TBR
+ F_MTSPR, // SPR, rT only used by MTSPR
+ F_MTCRF, // CRM, rT only used by MTCRF
+ F_MTFSFx, // FM, frB only used by MTFSFx
+ F_RT_DCR, // rT, DCR
+ F_MTDCR, // DCR, rT
+ F_RT_RA, // rT, rA
+ F_FRT_FRA_FRC_FRB, // frT, frA, frC, frB
+ F_FRT_FRA_FRB, // frT, frA, frB
+ F_FRT_FRA_FRC, // frT, frA, frC
+ F_RA_RT_SH_MB_ME, // rA, rT, SH, MB, ME
+ F_RLWNMx, // rT, rA, rB, MB, ME only used by RLWNMx
+ F_RT_RB, // rT, rB
+};
+
+/*
+ * Flags
+ */
+
+#define FL_OE (1 << 0) // if there is an OE field
+#define FL_RC (1 << 1) // if there is an RC field
+#define FL_LK (1 << 2) // if there is an LK field
+#define FL_AA (1 << 3) // if there is an AA field
+#define FL_CHECK_RA_RT (1 << 4) // assert rA!=0 and rA!=rT
+#define FL_CHECK_RA (1 << 5) // assert rA!=0
+#define FL_CHECK_LSWI (1 << 6) // specific check for LSWI validity
+#define FL_CHECK_LSWX (1 << 7) // specific check for LSWX validity
+#define FL_SO (1 << 8) // use DASMFLAG_STEP_OUT
+
+
+/*
+ * Instruction Descriptor
+ *
+ * Describes the layout of an instruction.
+ */
+
+typedef struct
+{
+ char mnem[32]; // mnemonic
+ UINT32 match; // bit pattern of instruction after it has been masked
+ UINT32 mask; // mask of variable fields (AND with ~mask to compare w/
+ // bit pattern to determine a match)
+ int format; // operand format
+ int flags; // flags
+} IDESCR;
+
+/*
+ * Instruction Table
+ *
+ * Table of instruction descriptors which allows the disassembler to decode
+ * and print instructions.
+ */
+
+static IDESCR itab[] =
+{
+ { "add", D_OP(31)|D_XO(266), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC },
+ { "addc", D_OP(31)|D_XO(10), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC },
+ { "adde", D_OP(31)|D_XO(138), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC },
+ { "addi", D_OP(14), M_RT|M_RA|M_SIMM, F_RT_RA_0_SIMM, 0 },
+ { "addic", D_OP(12), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 },
+ { "addic.", D_OP(13), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 },
+ { "addis", D_OP(15), M_RT|M_RA|M_SIMM, F_ADDIS, 0 },
+ { "addme", D_OP(31)|D_XO(234), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC },
+ { "addze", D_OP(31)|D_XO(202), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC },
+ { "and", D_OP(31)|D_XO(28), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "andc", D_OP(31)|D_XO(60), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "andi.", D_OP(28), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 },
+ { "andis.", D_OP(29), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 },
+ { "b", D_OP(18), M_LI|M_AA|M_LK, F_LI, FL_AA|FL_LK },
+ { "bc", D_OP(16), M_BO|M_BI|M_BD|M_AA|M_LK, F_BCx, FL_AA|FL_LK },
+ { "bcctr", D_OP(19)|D_XO(528), M_BO|M_BI|M_LK, F_BO_BI, FL_LK },
+ { "bclr", D_OP(19)|D_XO(16), M_BO|M_BI|M_LK, F_BO_BI, FL_LK|FL_SO },
+ { "cmp", D_OP(31)|D_XO(0), M_CRFD|M_L|M_RA|M_RB, F_CMP, 0 },
+ { "cmpi", D_OP(11), M_CRFD|M_L|M_RA|M_SIMM, F_CMP_SIMM, 0 },
+ { "cmpl", D_OP(31)|D_XO(32), M_CRFD|M_L|M_RA|M_RB, F_CMP, 0 },
+ { "cmpli", D_OP(10), M_CRFD|M_L|M_RA|M_UIMM, F_CMP_UIMM, 0 },
+ { "cntlzw", D_OP(31)|D_XO(26), M_RT|M_RA|M_RC, F_RA_RT, FL_RC },
+ { "crand", D_OP(19)|D_XO(257), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 },
+ { "crandc", D_OP(19)|D_XO(129), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 },
+ { "creqv", D_OP(19)|D_XO(289), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 },
+ { "crnand", D_OP(19)|D_XO(225), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 },
+ { "crnor", D_OP(19)|D_XO(33), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 },
+ { "cror", D_OP(19)|D_XO(449), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 },
+ { "crorc", D_OP(19)|D_XO(417), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 },
+ { "crxor", D_OP(19)|D_XO(193), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 },
+ { "dcba", D_OP(31)|D_XO(758), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "dcbf", D_OP(31)|D_XO(86), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "dcbi", D_OP(31)|D_XO(470), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "dcbst", D_OP(31)|D_XO(54), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "dcbt", D_OP(31)|D_XO(278), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "dcbtst", D_OP(31)|D_XO(246), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "dcbz", D_OP(31)|D_XO(1014),M_RA|M_RB, F_RA_0_RB, 0 },
+ { "dccci", D_OP(31)|D_XO(454), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "dcread", D_OP(31)|D_XO(486), M_RA|M_RB, F_RT_RA_RB, 0 },
+ { "divw", D_OP(31)|D_XO(491), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC },
+ { "divwu", D_OP(31)|D_XO(459), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC },
+ { "eciwx", D_OP(31)|D_XO(310), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "ecowx", D_OP(31)|D_XO(438), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "eieio", D_OP(31)|D_XO(854), 0, F_NONE, 0 },
+ { "eqv", D_OP(31)|D_XO(284), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "extsb", D_OP(31)|D_XO(954), M_RT|M_RA|M_RC, F_RA_RT, FL_RC },
+ { "extsh", D_OP(31)|D_XO(922), M_RT|M_RA|M_RC, F_RA_RT, FL_RC },
+ { "fabs", D_OP(63)|D_XO(264), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "fadd", D_OP(63)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC },
+ { "fadds", D_OP(59)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC },
+ { "fcmpo", D_OP(63)|D_XO(32), M_CRFD|M_RA|M_RB, F_FCMP, 0 },
+ { "fcmpu", D_OP(63)|D_XO(0), M_CRFD|M_RA|M_RB, F_FCMP, 0 },
+ { "fctiw", D_OP(63)|D_XO(14), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "fctiwz", D_OP(63)|D_XO(15), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "fdiv", D_OP(63)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC },
+ { "fdivs", D_OP(59)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC },
+ { "fmadd", D_OP(63)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC },
+ { "fmadds", D_OP(59)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC },
+ { "fmr", D_OP(63)|D_XO(72), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "fmsub", D_OP(63)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC },
+ { "fmsubs", D_OP(59)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC },
+ { "fmul", D_OP(63)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC },
+ { "fmuls", D_OP(59)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC },
+ { "fnabs", D_OP(63)|D_XO(136), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "fneg", D_OP(63)|D_XO(40), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "fnmadd", D_OP(63)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC },
+ { "fnmadds",D_OP(59)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC },
+ { "fnmsub", D_OP(63)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC },
+ { "fnmsubs",D_OP(59)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC },
+ { "fres", D_OP(59)|D_XO(24), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "frsp", D_OP(63)|D_XO(12), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "frsqrte",D_OP(63)|D_XO(26), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "fsel", D_OP(63)|D_XO(23), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC },
+ { "fsqrt", D_OP(63)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "fsqrts", D_OP(59)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC },
+ { "fsub", D_OP(63)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC },
+ { "fsubs", D_OP(59)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC },
+ { "icbi", D_OP(31)|D_XO(982), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "icbt", D_OP(31)|D_XO(262), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "iccci", D_OP(31)|D_XO(966), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "icread", D_OP(31)|D_XO(998), M_RA|M_RB, F_RA_0_RB, 0 },
+ { "isync", D_OP(19)|D_XO(150), 0, F_NONE, 0 },
+ { "lbz", D_OP(34), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 },
+ { "lbzu", D_OP(35), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT },
+ { "lbzux", D_OP(31)|D_XO(119), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT },
+ { "lbzx", D_OP(31)|D_XO(87), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "lfd", D_OP(50), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 },
+ { "lfdu", D_OP(51), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA },
+ { "lfdux", D_OP(31)|D_XO(631), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA },
+ { "lfdx", D_OP(31)|D_XO(599), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 },
+ { "lfs", D_OP(48), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 },
+ { "lfsu", D_OP(49), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA },
+ { "lfsux", D_OP(31)|D_XO(567), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA },
+ { "lfsx", D_OP(31)|D_XO(535), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 },
+ { "lha", D_OP(42), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 },
+ { "lhau", D_OP(43), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT },
+ { "lhaux", D_OP(31)|D_XO(375), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT },
+ { "lhax", D_OP(31)|D_XO(343), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "lhbrx", D_OP(31)|D_XO(790), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "lhz", D_OP(40), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 },
+ { "lhzu", D_OP(41), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT },
+ { "lhzux", D_OP(31)|D_XO(311), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT },
+ { "lhzx", D_OP(31)|D_XO(279), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "lmw", D_OP(46), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 },
+ { "lswi", D_OP(31)|D_XO(597), M_RT|M_RA|M_NB, F_RT_RA_0_NB, FL_CHECK_LSWI },
+ { "lswx", D_OP(31)|D_XO(533), M_RT|M_RA|M_RB, F_RT_RA_0_RB, FL_CHECK_LSWX },
+ { "lwarx", D_OP(31)|D_XO(20), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "lwbrx", D_OP(31)|D_XO(534), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "lwz", D_OP(32), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 },
+ { "lwzu", D_OP(33), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT },
+ { "lwzux", D_OP(31)|D_XO(55), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT },
+ { "lwzx", D_OP(31)|D_XO(23), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "mcrf", D_OP(19)|D_XO(0), M_CRFD|M_CRFS, F_CRFD_CRFS, 0 },
+ { "mcrfs", D_OP(63)|D_XO(64), M_CRFD|M_CRFS, F_CRFD_CRFS, 0 },
+ { "mcrxr", D_OP(31)|D_XO(512), M_CRFD, F_MCRXR, 0 },
+ { "mfcr", D_OP(31)|D_XO(19), M_RT, F_RT, 0 },
+ { "mfdcr", D_OP(31)|D_XO(323), M_RT|M_DCR, F_RT_DCR, 0 },
+ { "mffs", D_OP(63)|D_XO(583), M_RT|M_RC, F_MFFSx, FL_RC },
+ { "mfmsr", D_OP(31)|D_XO(83), M_RT, F_RT, 0 },
+ { "mfspr", D_OP(31)|D_XO(339), M_RT|M_SPR, F_RT_SPR, 0 },
+ { "mfsr", D_OP(31)|D_XO(595), M_RT|M_SR, F_MFSR, 0 },
+ { "mfsrin", D_OP(31)|D_XO(659), M_RT|M_RB, F_RT_RB, 0 },
+ { "mftb", D_OP(31)|D_XO(371), M_RT|M_TBR, F_RT_SPR, 0 },
+ { "mtcrf", D_OP(31)|D_XO(144), M_RT|M_CRM, F_MTCRF, 0 },
+ { "mtdcr", D_OP(31)|D_XO(451), M_RT|M_DCR, F_MTDCR, 0 },
+ { "mtfsb0", D_OP(63)|D_XO(70), M_CRBD|M_RC, F_FCRBD, FL_RC },
+ { "mtfsb1", D_OP(63)|D_XO(38), M_CRBD|M_RC, F_FCRBD, FL_RC },
+ { "mtfsf", D_OP(63)|D_XO(711), M_FM|M_RB|M_RC, F_MTFSFx, FL_RC },
+ { "mtfsfi", D_OP(63)|D_XO(134), M_CRFD|M_IMM|M_RC, F_MTFSFIx, FL_RC },
+ { "mtmsr", D_OP(31)|D_XO(146), M_RT, F_RT, 0 },
+ { "mtspr", D_OP(31)|D_XO(467), M_RT|M_SPR, F_MTSPR, 0 },
+ { "mtsr", D_OP(31)|D_XO(210), M_RT|M_SR, F_MTSR, 0 },
+ { "mtsrin", D_OP(31)|D_XO(242), M_RT|M_RB, F_RT_RB, 0 },
+ { "mulhw", D_OP(31)|D_XO(75), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC },
+ { "mulhwu", D_OP(31)|D_XO(11), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC },
+ { "mulli", D_OP(7), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 },
+ { "mullw", D_OP(31)|D_XO(235), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC },
+ { "nand", D_OP(31)|D_XO(476), M_RA|M_RT|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "neg", D_OP(31)|D_XO(104), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC },
+ { "nor", D_OP(31)|D_XO(124), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "or", D_OP(31)|D_XO(444), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "orc", D_OP(31)|D_XO(412), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "ori", D_OP(24), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 },
+ { "oris", D_OP(25), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 },
+ { "rfi", D_OP(19)|D_XO(50), 0, F_NONE, 0 },
+ { "rfci", D_OP(19)|D_XO(51), 0, F_NONE, 0 },
+ { "rlwimi", D_OP(20), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC },
+ { "rlwinm", D_OP(21), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC },
+ { "rlwnm", D_OP(23), M_RT|M_RA|M_RB|M_MB|M_ME|M_RC, F_RLWNMx, FL_RC },
+ { "sc", D_OP(17)|2, 0, F_NONE, 0 },
+ { "slw", D_OP(31)|D_XO(24), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "sraw", D_OP(31)|D_XO(792), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "srawi", D_OP(31)|D_XO(824), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC },
+ { "srw", D_OP(31)|D_XO(536), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "stb", D_OP(38), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 },
+ { "stbu", D_OP(39), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA },
+ { "stbux", D_OP(31)|D_XO(247), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA },
+ { "stbx", D_OP(31)|D_XO(215), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "stfd", D_OP(54), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 },
+ { "stfdu", D_OP(55), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA },
+ { "stfdux", D_OP(31)|D_XO(759), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA },
+ { "stfdx", D_OP(31)|D_XO(727), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 },
+ { "stfiwx", D_OP(31)|D_XO(983), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 },
+ { "stfs", D_OP(52), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 },
+ { "stfsu", D_OP(53), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA },
+ { "stfsux", D_OP(31)|D_XO(695), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA },
+ { "stfsx", D_OP(31)|D_XO(663), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 },
+ { "sth", D_OP(44), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 },
+ { "sthbrx", D_OP(31)|D_XO(918), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "sthu", D_OP(45), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA },
+ { "sthux", D_OP(31)|D_XO(439), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA },
+ { "sthx", D_OP(31)|D_XO(407), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "stmw", D_OP(47), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 },
+ { "stswi", D_OP(31)|D_XO(725), M_RT|M_RA|M_NB, F_RT_RA_0_NB, 0 },
+ { "stswx", D_OP(31)|D_XO(661), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "stw", D_OP(36), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 },
+ { "stwbrx", D_OP(31)|D_XO(662), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "stwcx.", D_OP(31)|D_XO(150)|1, M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "stwu", D_OP(37), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA },
+ { "stwux", D_OP(31)|D_XO(183), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA },
+ { "stwx", D_OP(31)|D_XO(151), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 },
+ { "subf", D_OP(31)|D_XO(40), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC },
+ { "subfc", D_OP(31)|D_XO(8), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC },
+ { "subfe", D_OP(31)|D_XO(136), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC },
+ { "subfic", D_OP(8), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 },
+ { "subfme", D_OP(31)|D_XO(232), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC },
+ { "subfze", D_OP(31)|D_XO(200), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC },
+ { "sync", D_OP(31)|D_XO(598), 0, F_NONE, 0 },
+ { "tlbia", D_OP(31)|D_XO(370), 0, F_NONE, 0 },
+ { "tlbie", D_OP(31)|D_XO(306), M_RB, F_RB, 0 },
+ { "tlbsync",D_OP(31)|D_XO(566), 0, F_NONE, 0 },
+ { "tw", D_OP(31)|D_XO(4), M_TO|M_RA|M_RB, F_TW, 0 },
+ { "twi", D_OP(3), M_TO|M_RA|M_SIMM, F_TWI, 0 },
+ { "wrtee", D_OP(31)|D_XO(131), M_RT, F_RT, 0 },
+ { "wrteei", D_OP(31)|D_XO(163), 0, 0, 0 },
+ { "xor", D_OP(31)|D_XO(316), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC },
+ { "xori", D_OP(26), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 },
+ { "xoris", D_OP(27), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 },
+
+ /*
+ * PowerPC 603e/EC603e-specific instructions
+ */
+
+ { "tlbld", D_OP(31)|D_XO(978), M_RB, F_RB, 0 },
+ { "tlbli", D_OP(31)|D_XO(1010),M_RB, F_RB, 0 }
+};
+
+/*
+ * CR Bits
+ *
+ * Use an index of BI&3 into this table to obtain the CR field bit name.
+ */
+
+static char crbit[][4] = { "lt", "gt", "eq", "so" };
+
+
+/*
+ * SPR():
+ *
+ * Decode the SPR (or TBR) field and append the register name to dest. If
+ * no name is associated with the field value, the value itself is printed.
+ */
+
+static void SPR(char *dest, int spr_field)
+{
+ int spr;
+
+ /*
+ * Construct the SPR number -- SPR field is 2 5-bit fields
+ */
+
+ spr = (spr_field >> 5) & 0x1f;
+ spr |= (spr_field & 0x1f) << 5;
+
+ /*
+ * Append the SPR name to the destination string using strcat()
+ */
+
+ switch (spr)
+ {
+ case 1: strcat(dest, "xer"); break;
+ case 8: strcat(dest, "lr"); break;
+ case 9: strcat(dest, "ctr"); break;
+ case 18: strcat(dest, "dsisr"); break;
+ case 19: strcat(dest, "dar"); break;
+ case 22: strcat(dest, "dec"); break;
+ case 25: strcat(dest, "sdr1"); break;
+ case 26: strcat(dest, "srr0"); break;
+ case 27: strcat(dest, "srr1"); break;
+ case 272: strcat(dest, "sprg0"); break;
+ case 273: strcat(dest, "sprg1"); break;
+ case 274: strcat(dest, "sprg2"); break;
+ case 275: strcat(dest, "sprg3"); break;
+ case 282: strcat(dest, "ear"); break;
+ case 287: strcat(dest, "pvr"); break;
+ case 528: strcat(dest, "ibat0u"); break;
+ case 529: strcat(dest, "ibat0l"); break;
+ case 530: strcat(dest, "ibat1u"); break;
+ case 531: strcat(dest, "ibat1l"); break;
+ case 532: strcat(dest, "ibat2u"); break;
+ case 533: strcat(dest, "ibat2l"); break;
+ case 534: strcat(dest, "ibat3u"); break;
+ case 535: strcat(dest, "ibat3l"); break;
+ case 536: strcat(dest, "dbat0u"); break;
+ case 537: strcat(dest, "dbat0l"); break;
+ case 538: strcat(dest, "dbat1u"); break;
+ case 539: strcat(dest, "dbat1l"); break;
+ case 540: strcat(dest, "dbat2u"); break;
+ case 541: strcat(dest, "dbat2l"); break;
+ case 542: strcat(dest, "dbat3u"); break;
+ case 543: strcat(dest, "dbat3l"); break;
+ case 1013: strcat(dest, "dabr"); break; // unsupported on 603e/EC603e
+
+ /*
+ * Some PowerPC implementations may implement MFTB and MFSPR identically,
+ * therefore TBR registers are also decoded here
+ */
+
+ case 268: strcat(dest, "tbl"); break;
+ case 269: strcat(dest, "tbu"); break;
+
+ /*
+ * PowerPC 603e/EC603e-specific registers
+ */
+
+ case 1008: strcat(dest, "hid0"); break;
+ case 1009: strcat(dest, "hid1"); break;
+ case 976: strcat(dest, "dmiss"); break;
+ case 977: strcat(dest, "dcmp"); break;
+ case 978: strcat(dest, "hash2"); break;
+ case 979: strcat(dest, "hash2"); break;
+ case 980: strcat(dest, "imiss"); break;
+ case 981: strcat(dest, "icmp"); break;
+ case 982: strcat(dest, "rpa"); break;
+ case 1010: strcat(dest, "iabr"); break;
+
+ default: sprintf(dest, "%s%d", dest, spr); break;
+ }
+}
+
+static void DCR(char *dest, int dcr_field)
+{
+ int dcr;
+
+ /*
+ * Construct the DCR number -- DCR field is 2 5-bit fields
+ */
+
+ dcr = (dcr_field >> 5) & 0x1f;
+ dcr |= (dcr_field & 0x1f) << 5;
+
+ /*
+ * Append the DCR name to the destination string using strcat()
+ */
+
+ switch (dcr)
+ {
+ case 144: strcat(dest, "bear"); break;
+ case 145: strcat(dest, "besr"); break;
+ case 128: strcat(dest, "br0"); break;
+ case 129: strcat(dest, "br1"); break;
+ case 130: strcat(dest, "br2"); break;
+ case 131: strcat(dest, "br3"); break;
+ case 132: strcat(dest, "br4"); break;
+ case 133: strcat(dest, "br5"); break;
+ case 134: strcat(dest, "br6"); break;
+ case 135: strcat(dest, "br7"); break;
+ case 112: strcat(dest, "brh0"); break;
+ case 113: strcat(dest, "brh1"); break;
+ case 114: strcat(dest, "brh2"); break;
+ case 115: strcat(dest, "brh3"); break;
+ case 116: strcat(dest, "brh4"); break;
+ case 117: strcat(dest, "brh5"); break;
+ case 118: strcat(dest, "brh6"); break;
+ case 119: strcat(dest, "brh7"); break;
+ case 196: strcat(dest, "dmacc0"); break;
+ case 204: strcat(dest, "dmacc1"); break;
+ case 212: strcat(dest, "dmacc2"); break;
+ case 220: strcat(dest, "dmacc3"); break;
+ case 192: strcat(dest, "dmacr0"); break;
+ case 200: strcat(dest, "dmacr1"); break;
+ case 208: strcat(dest, "dmacr2"); break;
+ case 216: strcat(dest, "dmacr3"); break;
+ case 193: strcat(dest, "dmact0"); break;
+ case 201: strcat(dest, "dmact1"); break;
+ case 209: strcat(dest, "dmact2"); break;
+ case 217: strcat(dest, "dmact3"); break;
+ case 194: strcat(dest, "dmada0"); break;
+ case 202: strcat(dest, "dmada1"); break;
+ case 210: strcat(dest, "dmada2"); break;
+ case 218: strcat(dest, "dmada3"); break;
+ case 195: strcat(dest, "dmasa0"); break;
+ case 203: strcat(dest, "dmasa1"); break;
+ case 211: strcat(dest, "dmasa2"); break;
+ case 219: strcat(dest, "dmasa3"); break;
+ case 224: strcat(dest, "dmasr"); break;
+ case 66: strcat(dest, "exier"); break;
+ case 64: strcat(dest, "exisr"); break;
+ case 160: strcat(dest, "iocr"); break;
+
+ default: sprintf(dest, "%s%d", dest, dcr); break;
+ }
+}
+
+
+/*
+ * DecodeSigned16():
+ *
+ * Predecodes the SIMM field for us. If do_unsigned, it is printed as an
+ * unsigned 16-bit integer.
+ */
+
+static void DecodeSigned16(char *outbuf, UINT32 op, int do_unsigned)
+{
+ INT16 s;
+
+ s = G_SIMM(op);
+ if (do_unsigned) // sign extend to unsigned 32-bits
+ sprintf(outbuf, "0x%04X", (UINT32) s);
+ else // print as signed 16 bits
+ {
+ if (s < 0)
+ {
+ s *= -1;
+ sprintf(outbuf, "-0x%04X", s);
+ }
+ else
+ sprintf(outbuf, "0x%04X",s);
+ }
+}
+
+/*
+ * Mask():
+ *
+ * Generate a mask from bit MB through ME (PPC-style backwards bit numbering.)
+ */
+
+static UINT32 Mask(int mb, int me)
+{
+ UINT32 i, mask;
+
+ mb &= 31;
+ me &= 31;
+
+ i = mb;
+ mask = 0;
+ while (1)
+ {
+ mask |= (1 << (31 - i));
+ if (i == me)
+ break;
+ i = (i + 1) & 31;
+ }
+
+ return mask;
+}
+
+/*
+ * Check():
+ *
+ * Perform checks on the instruction as required by the flags. Returns 1 if
+ * the instruction failed.
+ */
+
+#if 0
+static int Check(UINT32 op, int flags)
+{
+ int nb, rt, ra;
+
+ if( !flags ) return 0; // nothing to check for!
+
+ rt = G_RT(op);
+ ra = G_RA(op);
+
+ if (flags & FL_CHECK_RA_RT) // invalid if rA==0 or rA==rT
+ {
+ if ((G_RA(op) == 0) || (G_RA(op) == G_RT(op)))
+ return 1;
+ }
+
+ if (flags & FL_CHECK_RA) // invalid if rA==0
+ {
+ if (G_RA(op) == 0)
+ return 1;
+ }
+
+ if (flags & FL_CHECK_LSWI)
+ {
+ /*
+ * Check that rA is not in the range of registers to be loaded (even
+ * if rA == 0)
+ */
+
+ nb = G_NB(op);
+
+ if (ra >= rt && ra <= (rt + nb - 1)) return 1;
+ if ((rt + nb - 1) > 31) // register wrap-around!
+ {
+ if (ra < ((rt + nb - 1) - 31))
+ return 1;
+ }
+ }
+
+ if (flags & FL_CHECK_LSWX)
+ {
+ /*
+ * Check that rT != rA, rT != rB, and rD and rA both do not specify
+ * R0.
+ *
+ * We cannot check fully whether rA or rB are in the range of
+ * registers specified to be loaded because that depends on XER.
+ */
+
+ if (rt == ra || rt == G_RB(op) || ((rt == 0) && (ra == 0)))
+ return 1;
+ }
+
+ return 0; // passed checks
+}
+#endif
+/*
+ * Simplified():
+ *
+ * Handles all simplified instruction forms. Returns 1 if one was decoded,
+ * otherwise 0 to indicate disassembly should carry on as normal.
+ */
+
+static int Simplified(UINT32 op, UINT32 vpc, char *signed16, char *mnem, char *oprs)
+{
+ UINT32 value, disp;
+
+ value = G_SIMM(op); // value is fully sign-extended SIMM field
+ if (value & 0x8000)
+ value |= 0xffff0000;
+
+ if (op == (D_OP(24)|D_RT(0)|D_RA(0)|D_UIMM(0)))
+ strcat(mnem, "nop"); // ori r0,r0,0 -> nop
+ else if ((op & ~(M_RT|M_RA|M_RB|M_RC)) == (D_OP(31)|D_XO(444)))
+ {
+ if (G_RT(op) == G_RB(op))
+ {
+ strcat(mnem, "mr"); // orx rA,rT,rT -> mrx rA,rT
+ if (op & M_RC) strcat(mnem, ".");
+ sprintf(oprs, "r%d,r%d", G_RA(op), G_RT(op));
+ }
+ else
+ return 0;
+ }
+ else if ((op & ~(M_RT|M_RA|M_RB|M_RC)) == (D_OP(31)|D_XO(124)))
+ {
+ if (G_RT(op) == G_RB(op))
+ {
+ strcat(mnem, "not"); // nor rA,rT,rT -> not rA,rT
+ if (op & M_RC) strcat(mnem, ".");
+ sprintf(oprs, "r%d,r%d", G_RA(op), G_RT(op));
+ }
+ else
+ return 0;
+ }
+ else if ((op & ~(M_RT|M_RA|M_SIMM)) == D_OP(14))
+ {
+ if (G_RA(op) == 0)
+ {
+ strcat(mnem, "li"); // addi rT,0,value -> li rT,value
+ sprintf(oprs, "r%d,0x%08X", G_RT(op), value);
+ }
+ else
+ return 0;
+ }
+ else if ((op & ~(M_RT|M_RA|M_SIMM)) == D_OP(15))
+ {
+ if (G_RA(op) == 0)
+ {
+ strcat(mnem, "li"); // addis rT,0,value -> li rT,(value<<16)
+ sprintf(oprs, "r%d,0x%08X", G_RT(op), value << 16);
+ }
+ else
+ {
+ strcat(mnem, "addi"); // addis rT,rA,SIMM -> addi rT,rA,SIMM<<16
+ sprintf(oprs, "r%d,r%d,0x%08X", G_RT(op), G_RA(op), value << 16);
+ }
+ }
+ else if ((op & ~(M_RT|M_RA|M_UIMM)) == D_OP(29))
+ {
+ strcat(mnem, "andi."); // andis. rA,rT,UIMM -> andi. rA,rT,UIMM<<16
+ sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16);
+ }
+ else if ((op & ~(M_RT|M_RA|M_UIMM)) == D_OP(25))
+ {
+ strcat(mnem, "ori"); // oris rA,rT,UIMM -> ori rA,rT,UIMM<<16
+ sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16);
+ }
+ else if ((op & ~(M_RT|M_RA|M_UIMM)) == D_OP(27))
+ {
+ strcat(mnem, "xori"); // xoris rA,rT,UIMM -> xori rA,rT,UIMM<<16
+ sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16);
+ }
+ else if ((op & ~(M_RT|M_RA|M_SH|M_MB|M_ME|M_RC)) == D_OP(20))
+ {
+ value = Mask(G_MB(op), G_ME(op));
+ strcat(mnem, "rlwimi"); // rlwimi[.] rA,rT,SH,MB,ME -> rlwimi[.] rA,rT,SH,MASK
+ if (op & M_RC) strcat(mnem, ".");
+ sprintf(oprs, "r%d,r%d,%d,0x%08X", G_RA(op), G_RT(op), G_SH(op), value);
+ }
+ else if ((op & ~(M_RT|M_RA|M_SH|M_MB|M_ME|M_RC)) == D_OP(21))
+ {
+ value = Mask(G_MB(op), G_ME(op));
+ if (G_SH(op) == 0) // rlwinm[.] rA,rT,0,MB,ME -> and[.] rA,rT,MASK
+ {
+ strcat(mnem, "and");
+ if (op & M_RC) strcat(mnem, ".");
+ sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), value);
+ }
+ else // rlwinm[.] rA,rT,SH,MASK
+ {
+ strcat(mnem, "rlwinm");
+ if (op & M_RC) strcat(mnem, ".");
+ sprintf(oprs, "r%d,r%d,%d,0x%08X", G_RA(op), G_RT(op), G_SH(op), value);
+ }
+ }
+ else if ((op & ~(M_RT|M_RA|M_RB|M_MB|M_ME|M_RC)) == D_OP(23))
+ {
+ value = Mask(G_MB(op), G_ME(op));
+ strcat(mnem, "rlwnm"); // rlwnm[.] rA,rT,SH,MB,ME -> rlwnm[.] rA,rT,SH,MASK
+ if (op & M_RC) strcat(mnem, ".");
+ sprintf(oprs, "r%d,r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_RB(op), value);
+ }
+ else if ((op & ~(M_BO|M_BI|M_BD|M_AA|M_LK)) == D_OP(16))
+ {
+ disp = G_BD(op) * 4;
+ if (disp & 0x00008000)
+ disp |= 0xffff0000;
+
+ switch (G_BO(op))
+ {
+ case 0x04: // branch if condition is false
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ strcat(mnem, "bf");
+ break;
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ strcat(mnem, "bt");
+ break;
+ default:
+ return 0;
+ }
+
+ if (op & M_LK) strcat(mnem, "l");
+ if (op & M_AA) strcat(mnem, "a");
+
+ sprintf(oprs, "cr%d[%s],0x%08X", G_BI(op) / 4, crbit[G_BI(op) & 3], disp + ((op & M_AA) ? 0 : vpc));
+ }
+ else if ((op & ~(M_RT|M_RA|M_RB|M_OE|M_RC)) == (D_OP(31)|D_XO(40)))
+ {
+ strcat(mnem, "sub");
+ if (op & M_OE) strcat(mnem, "o");
+ if (op & M_RC) strcat(mnem, ".");
+ sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RB(op), G_RA(op));
+ }
+ else if ((op & ~(M_RT|M_RA|M_RB|M_OE|M_RC)) == (D_OP(31)|D_XO(8)))
+ {
+ strcat(mnem, "subc");
+ if (op & M_OE) strcat(mnem, "o");
+ if (op & M_RC) strcat(mnem, ".");
+ sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RB(op), G_RA(op));
+ }
+ else
+ return 0; // no match
+
+ return 1;
+}
+
+offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op)
+{
+ char signed16[12];
+ UINT32 disp;
+ int i,j;
+ char mnem[200];
+ char oprs[200];
+ offs_t flags = DASMFLAG_SUPPORTED;
+
+ mnem[0] = '\0'; // so we can use strcat()
+ oprs[0] = '\0';
+
+ /*
+ * Decode signed 16-bit fields (SIMM and d) to spare us the work later
+ */
+
+ DecodeSigned16(signed16, op, 0);
+
+ /*
+ * Try simplified forms first, then real instructions
+ */
+
+ if( Simplified(op, pc, signed16, mnem, oprs) ) {
+ buffer += sprintf(buffer, "%s", mnem);
+ for( j = strlen(mnem); j < 10; j++ ) {
+ buffer += sprintf(buffer, " ");
+ }
+ buffer += sprintf(buffer, "%s", oprs);
+ return 4 | flags;
+ }
+
+ /*
+ * Search for the instruction in the list and print it if there's a match
+ */
+
+ for (i = 0; i < sizeof(itab) / sizeof(IDESCR); i++)
+ {
+ if ((op & ~itab[i].mask) == itab[i].match) // check for match
+ {
+ /*
+ * Base mnemonic followed be O, ., L, A
+ */
+
+ strcat(mnem, itab[i].mnem);
+ if (itab[i].flags & FL_OE) if (op & M_OE) strcat(mnem, "o");
+ if (itab[i].flags & FL_RC) if (op & M_RC) strcat(mnem, ".");
+ if (itab[i].flags & FL_LK) if (op & M_LK) strcat(mnem, "l");
+ if (itab[i].flags & FL_AA) if (op & M_AA) strcat(mnem, "a");
+
+ /*
+ * Print operands
+ */
+
+ switch (itab[i].format)
+ {
+ case F_RT_RA_RB:
+ sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op));
+ break;
+
+ case F_RT_RA_0_SIMM:
+ if (G_RA(op))
+ sprintf(oprs, "r%d,r%d,%s", G_RT(op), G_RA(op), signed16);
+ else
+ sprintf(oprs, "r%d,0,%s", G_RT(op), signed16);
+ break;
+
+ case F_ADDIS:
+ if (G_RA(op))
+ sprintf(oprs, "r%d,r%d,0x%04X", G_RT(op), G_RA(op), G_SIMM(op));
+ else
+ sprintf(oprs, "r%d,0,0x%04X", G_RT(op), G_SIMM(op));
+ break;
+
+ case F_RT_RA_SIMM:
+ sprintf(oprs, "r%d,r%d,%s", G_RT(op), G_RA(op), signed16);
+ break;
+
+ case F_RT_RA:
+ sprintf(oprs, "r%d,r%d", G_RT(op), G_RA(op));
+ break;
+
+ case F_RA_RT_RB:
+ sprintf(oprs, "r%d,r%d,r%d", G_RA(op), G_RT(op), G_RB(op));
+ break;
+
+ case F_RA_RT_UIMM:
+ sprintf(oprs, "r%d,r%d,0x%04X", G_RA(op), G_RT(op), G_UIMM(op));
+ break;
+
+ case F_LI:
+ disp = G_LI(op) * 4;
+ if (disp & 0x02000000) // sign extend
+ disp |= 0xfc000000;
+ sprintf(oprs, "0x%08X", disp + ((op & M_AA) ? 0 : pc));
+ break;
+
+ case F_BCx:
+ disp = G_BD(op) * 4;
+ if (disp & 0x00008000)
+ disp |= 0xffff0000;
+
+ if (G_BO(op) & 0x10) // BI is ignored (don't print CR bit)
+ sprintf(oprs, "0x%02X,%d,0x%08X", G_BO(op), G_BI(op), disp + ((op & M_AA) ? 0 : pc));
+ else // BI gives us the condition bit
+ sprintf(oprs, "0x%02X,cr%d[%s],0x%08X", G_BO(op), G_BI(op) / 4, crbit[G_BI(op) & 3], disp + ((op & M_AA) ? 0 : pc));
+ break;
+
+ case F_BO_BI:
+ if (G_BO(op) & 0x10) // BI is ignored (don't print CR bit)
+ sprintf(oprs, "0x%02X,%d", G_BO(op), G_BI(op));
+ else
+ sprintf(oprs, "0x%02X,cr%d[%s]", G_BO(op), G_BI(op) / 4, crbit[G_BI(op) & 3]);
+ break;
+
+ case F_CMP:
+ sprintf(oprs, "cr%d,%d,r%d,r%d", G_CRFD(op), G_L(op), G_RA(op), G_RB(op));
+ break;
+
+ case F_CMP_SIMM:
+ sprintf(oprs, "cr%d,%d,r%d,%s", G_CRFD(op), G_L(op), G_RA(op), signed16);
+ break;
+
+ case F_CMP_UIMM:
+ sprintf(oprs, "cr%d,%d,r%d,0x%04X", G_CRFD(op), G_L(op), G_RA(op), G_UIMM(op));
+ break;
+
+ case F_RA_RT:
+ sprintf(oprs, "r%d,r%d", G_RA(op), G_RT(op));
+ break;
+
+ case F_CRBD_CRBA_CRBB:
+ sprintf(oprs, "cr%d[%s],cr%d[%s],cr%d[%s]", G_CRBD(op) / 4, crbit[G_CRBD(op) & 3], G_CRBA(op) / 4, crbit[G_CRBA(op) & 3], G_CRBB(op) / 4, crbit[G_CRBB(op) & 3]);
+ break;
+
+ case F_RA_0_RB:
+ if (G_RA(op))
+ sprintf(oprs, "r%d,r%d", G_RA(op), G_RB(op));
+ else
+ sprintf(oprs, "0,r%d", G_RB(op));
+ break;
+
+ case F_RT_RA_0_RB:
+ if (G_RA(op))
+ sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op));
+ else
+ sprintf(oprs, "r%d,0,r%d", G_RT(op), G_RB(op));
+ break;
+
+ case F_FRT_FRB:
+ sprintf(oprs, "f%d,f%d", G_RT(op), G_RB(op));
+ break;
+
+ case F_FRT_FRA_FRB:
+ sprintf(oprs, "f%d,f%d,f%d", G_RT(op), G_RA(op), G_RB(op));
+ break;
+
+ case F_FCMP:
+ sprintf(oprs, "cr%d,f%d,f%d", G_CRFD(op), G_RA(op), G_RB(op));
+ break;
+
+ case F_FRT_FRA_FRC_FRB:
+ sprintf(oprs, "f%d,f%d,f%d,f%d", G_RT(op), G_RA(op), G_REGC(op), G_RB(op));
+ break;
+
+ case F_FRT_FRA_FRC:
+ sprintf(oprs, "f%d,f%d,f%d", G_RT(op), G_RA(op), G_REGC(op));
+ break;
+
+ case F_RT_D_RA_0:
+ if (G_RA(op))
+ sprintf(oprs, "r%d,%s(r%d)", G_RT(op), signed16, G_RA(op));
+ else
+ sprintf(oprs, "r%d,0x%08X", G_RT(op), (UINT32) ((INT16) G_D(op)));
+ break;
+
+ case F_RT_D_RA:
+ sprintf(oprs, "r%d,%s(r%d)", G_RT(op), signed16, G_RA(op));
+ break;
+
+ case F_FRT_D_RA_0:
+ if (G_RA(op))
+ sprintf(oprs, "f%d,%s(r%d)", G_RT(op), signed16, G_RA(op));
+ else
+ sprintf(oprs, "f%d,0x%08X", G_RT(op), (UINT32) ((INT16) G_D(op)));
+ break;
+
+ case F_FRT_D_RA:
+ sprintf(oprs, "f%d,%s(r%d)", G_RT(op), signed16, G_RA(op));
+ break;
+
+ case F_FRT_RA_RB:
+ sprintf(oprs, "f%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op));
+ break;
+
+ case F_FRT_RA_0_RB:
+ if (G_RA(op))
+ sprintf(oprs, "f%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op));
+ else
+ sprintf(oprs, "f%d,0,r%d", G_RT(op), G_RB(op));
+ break;
+
+ case F_RT_RA_0_NB:
+ if (G_RA(op))
+ sprintf(oprs, "r%d,r%d,%d", G_RT(op), G_RA(op), G_NB(op) ? G_NB(op) : 32);
+ else
+ sprintf(oprs, "r%d,0,%d", G_RT(op), G_NB(op) ? G_NB(op) : 32);
+ break;
+
+ case F_CRFD_CRFS:
+ sprintf(oprs, "cr%d,cr%d", G_CRFD(op), G_CRFS(op));
+ break;
+
+ case F_MCRXR:
+ sprintf(oprs, "cr%d", G_CRFD(op));
+ break;
+
+ case F_RT:
+ sprintf(oprs, "r%d", G_RT(op));
+ break;
+
+ case F_MFFSx:
+ sprintf(oprs, "f%d", G_RT(op));
+ break;
+
+ case F_FCRBD:
+ sprintf(oprs, "fpscr[%d]", G_CRBD(op));
+ break;
+
+ case F_RT_SPR:
+ sprintf(oprs, "r%d,", G_RT(op));
+ SPR(oprs, G_SPR(op));
+ break;
+
+ case F_RT_DCR:
+ sprintf(oprs, "r%d,", G_RT(op));
+ DCR(oprs, G_DCR(op));
+ break;
+
+ case F_MFSR:
+ sprintf(oprs, "r%d,sr%d", G_RT(op), G_SR(op));
+ break;
+
+ case F_MTCRF:
+ sprintf(oprs, "0x%02X,r%d", G_CRM(op), G_RT(op));
+ break;
+
+ case F_MTFSFx:
+ sprintf(oprs, "0x%02X,f%d", G_FM(op), G_RB(op));
+ break;
+
+ case F_MTFSFIx:
+ sprintf(oprs, "cr%d,0x%X", G_CRFD(op), G_IMM(op));
+ break;
+
+ case F_MTSPR:
+ SPR(oprs, G_SPR(op));
+ sprintf(oprs, "%s,r%d", oprs, G_RT(op));
+ break;
+
+ case F_MTDCR:
+ DCR(oprs, G_DCR(op));
+ sprintf(oprs, "%s,r%d", oprs, G_RT(op));
+ break;
+
+ case F_MTSR:
+ sprintf(oprs, "sr%d,r%d", G_SR(op), G_RT(op));
+ break;
+
+ case F_RT_RB:
+ sprintf(oprs, "r%d,r%d", G_RT(op), G_RB(op));
+ break;
+
+ case F_RA_RT_SH_MB_ME:
+ sprintf(oprs, "r%d,r%d,%d,%d,%d", G_RA(op), G_RT(op), G_SH(op), G_MB(op), G_ME(op));
+ break;
+
+ case F_RLWNMx:
+ sprintf(oprs, "r%d,r%d,r%d,%d,%d", G_RA(op), G_RT(op), G_RB(op), G_MB(op), G_ME(op));
+ break;
+
+ case F_SRAWIx:
+ sprintf(oprs, "r%d,r%d,%d", G_RA(op), G_RT(op), G_SH(op));
+ break;
+
+ case F_RB:
+ sprintf(oprs, "r%d", G_RB(op));
+ break;
+
+ case F_TW:
+ sprintf(oprs, "%d,r%d,r%d", G_TO(op), G_RA(op), G_RB(op));
+ break;
+
+ case F_TWI:
+ sprintf(oprs, "%d,r%d,%s", G_TO(op), G_RA(op), signed16);
+ break;
+
+ case F_NONE:
+ default:
+ break;
+ }
+
+ if ((itab[i].flags & FL_LK) && (op & M_LK))
+ flags |= DASMFLAG_STEP_OVER;
+ else if (itab[i].flags & FL_SO)
+ flags |= DASMFLAG_STEP_OUT;
+
+ buffer += sprintf(buffer, "%s", mnem);
+ for( j = strlen(mnem); j < 10; j++ ) {
+ buffer += sprintf(buffer, " ");
+ }
+ buffer += sprintf(buffer, "%s", oprs);
+ return 4 | flags;
+ }
+ }
+
+ sprintf(buffer, "?");
+ return 4 | flags;
+}
diff --git a/src/emu/cpu/powerpc/ppc_mem.c b/src/emu/cpu/powerpc/ppc_mem.c
new file mode 100644
index 00000000000..c4ed0fe4b16
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppc_mem.c
@@ -0,0 +1,436 @@
+#define DUMP_PAGEFAULTS 0
+
+INLINE UINT8 READ8(UINT32 a)
+{
+ return ppc.read8(a);
+}
+
+INLINE UINT16 READ16(UINT32 a)
+{
+ if( a & 0x1 )
+ return ppc.read16_unaligned(a);
+ else
+ return ppc.read16(a);
+}
+
+INLINE UINT32 READ32(UINT32 a)
+{
+ if( a & 0x3 )
+ return ppc.read32_unaligned(a);
+ else
+ return ppc.read32(a);
+}
+
+INLINE UINT64 READ64(UINT32 a)
+{
+ if( a & 0x7 )
+ return ppc.read64_unaligned(a);
+ else
+ return ppc.read64(a);
+}
+
+INLINE void WRITE8(UINT32 a, UINT8 d)
+{
+ ppc.write8(a, d);
+}
+
+INLINE void WRITE16(UINT32 a, UINT16 d)
+{
+ if( a & 0x1 )
+ ppc.write16_unaligned(a, d);
+ else
+ ppc.write16(a, d);
+}
+
+INLINE void WRITE32(UINT32 a, UINT32 d)
+{
+ if( ppc.reserved ) {
+ if( a == ppc.reserved_address ) {
+ ppc.reserved = 0;
+ }
+ }
+
+ if( a & 0x3 )
+ ppc.write32_unaligned(a, d);
+ else
+ ppc.write32(a, d);
+}
+
+INLINE void WRITE64(UINT32 a, UINT64 d)
+{
+ if( a & 0x7 )
+ ppc.write64_unaligned(a, d);
+ else
+ ppc.write64(a, d);
+}
+
+/***********************************************************************/
+
+#if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_MPC8240)
+static UINT16 ppc_read16_unaligned(UINT32 a)
+{
+ return ((UINT16)ppc.read8(a+0) << 8) | ((UINT16)ppc.read8(a+1) << 0);
+}
+
+static UINT32 ppc_read32_unaligned(UINT32 a)
+{
+ return ((UINT32)ppc.read8(a+0) << 24) | ((UINT32)ppc.read8(a+1) << 16) |
+ ((UINT32)ppc.read8(a+2) << 8) | ((UINT32)ppc.read8(a+3) << 0);
+}
+
+static UINT64 ppc_read64_unaligned(UINT32 a)
+{
+ return ((UINT64)READ32(a+0) << 32) | (UINT64)(READ32(a+4));
+}
+
+static void ppc_write16_unaligned(UINT32 a, UINT16 d)
+{
+ ppc.write8(a+0, (UINT8)(d >> 8));
+ ppc.write8(a+1, (UINT8)(d));
+}
+
+static void ppc_write32_unaligned(UINT32 a, UINT32 d)
+{
+ ppc.write8(a+0, (UINT8)(d >> 24));
+ ppc.write8(a+1, (UINT8)(d >> 16));
+ ppc.write8(a+2, (UINT8)(d >> 8));
+ ppc.write8(a+3, (UINT8)(d >> 0));
+}
+
+static void ppc_write64_unaligned(UINT32 a, UINT64 d)
+{
+ ppc.write32(a+0, (UINT32)(d >> 32));
+ ppc.write32(a+4, (UINT32)(d));
+}
+#endif
+
+/***********************************************************************/
+
+#define DSISR_PAGE 0x40000000
+#define DSISR_PROT 0x08000000
+#define DSISR_STORE 0x02000000
+
+enum
+{
+ PPC_TRANSLATE_DATA = 0x0000,
+ PPC_TRANSLATE_CODE = 0x0001,
+
+ PPC_TRANSLATE_READ = 0x0000,
+ PPC_TRANSLATE_WRITE = 0x0002,
+
+ PPC_TRANSLATE_NOEXCEPTION = 0x0004
+};
+
+#ifdef MESS
+static int ppc_is_protected(UINT32 pp, int flags)
+{
+ if (flags & PPC_TRANSLATE_WRITE)
+ {
+ if ((pp & 0x00000003) != 0x00000002)
+ return TRUE;
+ }
+ else
+ {
+ if ((pp & 0x00000003) == 0x00000000)
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+static int ppc_translate_address(offs_t *addr_ptr, int flags)
+{
+#ifdef MESS
+ const BATENT *bat;
+ UINT32 address;
+ UINT32 sr, vsid, hash;
+ UINT32 pteg_address;
+ UINT32 target_pte, bl, mask;
+ UINT64 pte;
+ UINT64 *pteg_ptr[2];
+ int i, hash_type;
+ UINT32 dsisr = DSISR_PROT;
+
+ bat = (flags & PPC_TRANSLATE_CODE) ? ppc.ibat : ppc.dbat;
+
+ address = *addr_ptr;
+
+ /* first check the block address translation table */
+ for (i = 0; i < 4; i++)
+ {
+ if (bat[i].u & ((MSR & MSR_PR) ? 0x00000001 : 0x00000002))
+ {
+ bl = bat[i].u & 0x00001FFC;
+ mask = (~bl << 15) & 0xFFFE0000;
+
+ if ((address & mask) == (bat[i].u & 0xFFFE0000))
+ {
+ if (ppc_is_protected(bat[i].l, flags))
+ goto exception;
+
+ *addr_ptr = (bat[i].l & 0xFFFE0000)
+ | (address & ((bl << 15) | 0x0001FFFF));
+ return 1;
+ }
+ }
+ }
+
+ /* now try page address translation */
+ sr = ppc.sr[(address >> 28) & 0x0F];
+ if (sr & 0x80000000)
+ {
+ /* direct store translation */
+ if ((flags & PPC_TRANSLATE_NOEXCEPTION) == 0)
+ fatalerror("ppc: direct store translation not yet implemented");
+ return 0;
+ }
+ else
+ {
+ /* is no execute is set? */
+ if ((flags & PPC_TRANSLATE_CODE) && (sr & 0x10000000))
+ goto exception;
+
+ vsid = sr & 0x00FFFFFF;
+ hash = (vsid & 0x0007FFFF) ^ ((address >> 12) & 0xFFFF);
+ target_pte = (vsid << 7) | ((address >> 22) & 0x3F) | 0x80000000;
+
+ /* we have to try both types of hashes */
+ for (hash_type = 0; hash_type <= 1; hash_type++)
+ {
+ pteg_address = (ppc.sdr1 & 0xFFFF0000)
+ | (((ppc.sdr1 & 0x01FF) & (hash >> 10)) << 16)
+ | ((hash & 0x03FF) << 6);
+
+ pteg_ptr[hash_type] = memory_get_read_ptr(cpu_getactivecpu(), ADDRESS_SPACE_PROGRAM, pteg_address);
+ if (pteg_ptr[hash_type])
+ {
+ for (i = 0; i < 8; i++)
+ {
+ pte = pteg_ptr[hash_type][i];
+
+ /* is valid? */
+ if (((pte >> 32) & 0xFFFFFFFF) == target_pte)
+ {
+ if (ppc_is_protected((UINT32) pte, flags))
+ goto exception;
+
+ *addr_ptr = ((UINT32) (pte & 0xFFFFF000))
+ | (address & 0x0FFF);
+ return 1;
+ }
+ }
+ }
+
+ hash ^= 0x7FFFF;
+ target_pte ^= 0x40;
+ }
+
+ if (DUMP_PAGEFAULTS)
+ {
+ mame_printf_debug("PAGE FAULT: address=%08X PC=%08X SDR1=%08X MSR=%08X\n", address, ppc.pc, ppc.sdr1, ppc.msr);
+ mame_printf_debug("\n");
+
+ for (i = 0; i < 4; i++)
+ {
+ bl = bat[i].u & 0x00001FFC;
+ mask = (~bl << 15) & 0xFFFE0000;
+ mame_printf_debug(" BAT[%d]=%08X%08X (A & %08X = %08X)\n", i, bat[i].u, bat[i].l,
+ mask, bat[i].u & 0xFFFE0000);
+ }
+ mame_printf_debug("\n");
+ mame_printf_debug(" VSID=%06X HASH=%05X HASH\'=%05X\n", vsid, hash, hash ^ 0x7FFFF);
+
+ for (hash_type = 0; hash_type <= 1; hash_type++)
+ {
+ if (pteg_ptr[hash_type])
+ {
+ for (i = 0; i < 8; i++)
+ {
+ pte = pteg_ptr[hash_type][i];
+ mame_printf_debug(" PTE[%i%c]=%08X%08X\n",
+ i,
+ hash_type ? '\'' : ' ',
+ (unsigned) (pte >> 32),
+ (unsigned) (pte >> 0));
+ }
+ }
+ }
+ }
+ }
+
+ dsisr = DSISR_PAGE;
+
+exception:
+ /* lookup failure - exception */
+ if ((flags & PPC_TRANSLATE_NOEXCEPTION) == 0)
+ {
+ if (flags & PPC_TRANSLATE_CODE)
+ {
+ ppc_exception(EXCEPTION_ISI);
+ }
+ else
+ {
+ ppc.dar = address;
+ if (flags & PPC_TRANSLATE_WRITE)
+ ppc.dsisr = dsisr | DSISR_STORE;
+ else
+ ppc.dsisr = dsisr;
+
+ ppc_exception(EXCEPTION_DSI);
+ }
+ }
+ return 0;
+#else
+ /* MMU not enabled in MAME; model3 drivers don't work properly */
+ return 1;
+#endif
+}
+
+#if (HAS_PPC602||HAS_PPC603)
+static int ppc_translate_address_cb(int space, offs_t *addr)
+{
+ int success = 1;
+
+ if (space == ADDRESS_SPACE_PROGRAM)
+ {
+ if (MSR & MSR_DR)
+ success = ppc_translate_address(addr, PPC_TRANSLATE_CODE | PPC_TRANSLATE_READ | PPC_TRANSLATE_NOEXCEPTION);
+ }
+ return success;
+}
+#endif
+
+static UINT8 ppc_read8_translated(offs_t address)
+{
+ ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ);
+ return program_read_byte_64be(address);
+}
+
+static UINT16 ppc_read16_translated(offs_t address)
+{
+ ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ);
+ return program_read_word_64be(address);
+}
+
+static UINT32 ppc_read32_translated(offs_t address)
+{
+ ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ);
+ return program_read_dword_64be(address);
+}
+
+static UINT64 ppc_read64_translated(offs_t address)
+{
+ ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ);
+ return program_read_qword_64be(address);
+}
+
+static void ppc_write8_translated(offs_t address, UINT8 data)
+{
+ ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE);
+ program_write_byte_64be(address, data);
+}
+
+static void ppc_write16_translated(offs_t address, UINT16 data)
+{
+ ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE);
+ program_write_word_64be(address, data);
+}
+
+static void ppc_write32_translated(offs_t address, UINT32 data)
+{
+ ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE);
+ program_write_dword_64be(address, data);
+}
+
+static void ppc_write64_translated(offs_t address, UINT64 data)
+{
+ ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE);
+ program_write_qword_64be(address, data);
+}
+
+#ifndef PPC_DRC
+#if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_MPC8240)
+static UINT32 ppc_readop_translated(offs_t address)
+{
+ ppc_translate_address(&address, PPC_TRANSLATE_CODE | PPC_TRANSLATE_READ);
+ return program_read_dword_64be(address);
+}
+#endif
+#endif
+
+/***********************************************************************/
+
+
+#ifdef MAME_DEBUG
+static offs_t ppc_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 op;
+ op = BIG_ENDIANIZE_INT32(*((UINT32 *) oprom));
+ return ppc_dasm_one(buffer, pc, op);
+}
+#endif /* MAME_DEBUG */
+
+/***********************************************************************/
+
+#if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_MPC8240)
+static int ppc_readop(UINT32 offset, int size, UINT64 *value)
+{
+ if (!(ppc.msr & MSR_IR))
+ return 0;
+
+ *value = 0;
+
+ if (ppc_translate_address(&offset, PPC_TRANSLATE_CODE | PPC_TRANSLATE_READ | PPC_TRANSLATE_NOEXCEPTION))
+ {
+ switch(size)
+ {
+ case 1: *value = program_read_byte(offset); break;
+ case 2: *value = program_read_word(offset); break;
+ case 4: *value = program_read_dword(offset); break;
+ case 8: *value = program_read_qword(offset); break;
+ }
+ }
+
+ return 1;
+}
+
+static int ppc_read(int space, UINT32 offset, int size, UINT64 *value)
+{
+ if (!(ppc.msr & MSR_DR))
+ return 0;
+
+ *value = 0;
+
+ if (ppc_translate_address(&offset, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ | PPC_TRANSLATE_NOEXCEPTION))
+ {
+ switch(size)
+ {
+ case 1: *value = program_read_byte(offset); break;
+ case 2: *value = program_read_word(offset); break;
+ case 4: *value = program_read_dword(offset); break;
+ case 8: *value = program_read_qword(offset); break;
+ }
+ }
+
+ return 1;
+}
+
+static int ppc_write(int space, UINT32 offset, int size, UINT64 value)
+{
+ if (!(ppc.msr & MSR_DR))
+ return 0;
+
+ if (ppc_translate_address(&offset, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE | PPC_TRANSLATE_NOEXCEPTION))
+ {
+ switch(size)
+ {
+ case 1: program_write_byte(offset, value); break;
+ case 2: program_write_word(offset, value); break;
+ case 4: program_write_dword(offset, value); break;
+ case 8: program_write_qword(offset, value); break;
+ }
+ }
+
+ return 1;
+}
+#endif
diff --git a/src/emu/cpu/powerpc/ppc_ops.c b/src/emu/cpu/powerpc/ppc_ops.c
new file mode 100644
index 00000000000..dbef5e65813
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppc_ops.c
@@ -0,0 +1,2848 @@
+/* PowerPC common opcodes */
+
+// it really seems like this should be elsewhere - like maybe the floating point checks can hang out someplace else
+#include <math.h>
+
+#ifndef PPC_DRC
+#if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_MPC8240)
+static void ppc_unimplemented(UINT32 op)
+{
+ fatalerror("ppc: Unimplemented opcode %08X at %08X", op, ppc.pc);
+}
+#endif
+
+static void ppc_addx(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 rb = REG(RB);
+
+ REG(RT) = ra + rb;
+
+ if( OEBIT ) {
+ SET_ADD_OV(REG(RT), ra, rb);
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+static void ppc_addcx(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 rb = REG(RB);
+
+ REG(RT) = ra + rb;
+
+ SET_ADD_CA(REG(RT), ra, rb);
+
+ if( OEBIT ) {
+ SET_ADD_OV(REG(RT), ra, rb);
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+#endif
+
+static void ppc_addex(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 rb = REG(RB);
+ UINT32 carry = (XER >> 29) & 0x1;
+ UINT32 tmp;
+
+ tmp = rb + carry;
+ REG(RT) = ra + tmp;
+
+ if( ADD_CA(tmp, rb, carry) || ADD_CA(REG(RT), ra, tmp) )
+ XER |= XER_CA;
+ else
+ XER &= ~XER_CA;
+
+ if( OEBIT ) {
+ SET_ADD_OV(REG(RT), ra, rb);
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+#ifndef PPC_DRC
+static void ppc_addi(UINT32 op)
+{
+ UINT32 i = SIMM16;
+ UINT32 a = RA;
+
+ if( a )
+ i += REG(a);
+
+ REG(RT) = i;
+}
+
+static void ppc_addic(UINT32 op)
+{
+ UINT32 i = SIMM16;
+ UINT32 ra = REG(RA);
+
+ REG(RT) = ra + i;
+
+ if( ADD_CA(REG(RT), ra, i) )
+ XER |= XER_CA;
+ else
+ XER &= ~XER_CA;
+}
+
+static void ppc_addic_rc(UINT32 op)
+{
+ UINT32 i = SIMM16;
+ UINT32 ra = REG(RA);
+
+ REG(RT) = ra + i;
+
+ if( ADD_CA(REG(RT), ra, i) )
+ XER |= XER_CA;
+ else
+ XER &= ~XER_CA;
+
+ SET_CR0(REG(RT));
+}
+
+static void ppc_addis(UINT32 op)
+{
+ UINT32 i = UIMM16 << 16;
+ UINT32 a = RA;
+
+ if( a )
+ i += REG(a);
+
+ REG(RT) = i;
+}
+#endif
+
+static void ppc_addmex(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 carry = (XER >> 29) & 0x1;
+ UINT32 tmp;
+
+ tmp = ra + carry;
+ REG(RT) = tmp + -1;
+
+ if( ADD_CA(tmp, ra, carry) || ADD_CA(REG(RT), tmp, -1) )
+ XER |= XER_CA;
+ else
+ XER &= ~XER_CA;
+
+ if( OEBIT ) {
+ SET_ADD_OV(REG(RT), ra, carry - 1);
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+static void ppc_addzex(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 carry = (XER >> 29) & 0x1;
+
+ REG(RT) = ra + carry;
+
+ if( ADD_CA(REG(RT), ra, carry) )
+ XER |= XER_CA;
+ else
+ XER &= ~XER_CA;
+
+ if( OEBIT ) {
+ SET_ADD_OV(REG(RT), ra, carry);
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+#ifndef PPC_DRC
+static void ppc_andx(UINT32 op)
+{
+ REG(RA) = REG(RS) & REG(RB);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_andcx(UINT32 op)
+{
+ REG(RA) = REG(RS) & ~REG(RB);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_andi_rc(UINT32 op)
+{
+ UINT32 i = UIMM16;
+
+ REG(RA) = REG(RS) & i;
+
+ SET_CR0(REG(RA));
+}
+
+static void ppc_andis_rc(UINT32 op)
+{
+ UINT32 i = UIMM16 << 16;
+
+ REG(RA) = REG(RS) & i;
+
+ SET_CR0(REG(RA));
+}
+
+static void ppc_bx(UINT32 op)
+{
+ INT32 li = op & 0x3fffffc;
+ if( li & 0x2000000 )
+ li |= 0xfc000000;
+
+ if( AABIT ) {
+ ppc.npc = li;
+ } else {
+ ppc.npc = ppc.pc + li;
+ }
+
+ if( LKBIT ) {
+ LR = ppc.pc + 4;
+ }
+
+ change_pc(ppc.npc);
+}
+
+static void ppc_bcx(UINT32 op)
+{
+ int condition = check_condition_code(BO, BI);
+
+ if( condition ) {
+ if( AABIT ) {
+ ppc.npc = SIMM16 & ~0x3;
+ } else {
+ ppc.npc = ppc.pc + (SIMM16 & ~0x3);
+ }
+
+ change_pc(ppc.npc);
+ }
+
+ if( LKBIT ) {
+ LR = ppc.pc + 4;
+ }
+}
+
+static void ppc_bcctrx(UINT32 op)
+{
+ int condition = check_condition_code(BO, BI);
+
+ if( condition ) {
+ ppc.npc = CTR & ~0x3;
+ change_pc(ppc.npc);
+ }
+
+ if( LKBIT ) {
+ LR = ppc.pc + 4;
+ }
+}
+
+static void ppc_bclrx(UINT32 op)
+{
+ int condition = check_condition_code(BO, BI);
+
+ if( condition ) {
+ ppc.npc = LR & ~0x3;
+ change_pc(ppc.npc);
+ }
+
+ if( LKBIT ) {
+ LR = ppc.pc + 4;
+ }
+}
+
+static void ppc_cmp(UINT32 op)
+{
+ INT32 ra = REG(RA);
+ INT32 rb = REG(RB);
+ int d = CRFD;
+
+ if( ra < rb )
+ CR(d) = 0x8;
+ else if( ra > rb )
+ CR(d) = 0x4;
+ else
+ CR(d) = 0x2;
+
+ if( XER & XER_SO )
+ CR(d) |= 0x1;
+}
+
+static void ppc_cmpi(UINT32 op)
+{
+ INT32 ra = REG(RA);
+ INT32 i = SIMM16;
+ int d = CRFD;
+
+ if( ra < i )
+ CR(d) = 0x8;
+ else if( ra > i )
+ CR(d) = 0x4;
+ else
+ CR(d) = 0x2;
+
+ if( XER & XER_SO )
+ CR(d) |= 0x1;
+}
+
+static void ppc_cmpl(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 rb = REG(RB);
+ int d = CRFD;
+
+ if( ra < rb )
+ CR(d) = 0x8;
+ else if( ra > rb )
+ CR(d) = 0x4;
+ else
+ CR(d) = 0x2;
+
+ if( XER & XER_SO )
+ CR(d) |= 0x1;
+}
+
+static void ppc_cmpli(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 i = UIMM16;
+ int d = CRFD;
+
+ if( ra < i )
+ CR(d) = 0x8;
+ else if( ra > i )
+ CR(d) = 0x4;
+ else
+ CR(d) = 0x2;
+
+ if( XER & XER_SO )
+ CR(d) |= 0x1;
+}
+
+static void ppc_cntlzw(UINT32 op)
+{
+ int n = 0;
+ int t = RT;
+ UINT32 m = 0x80000000;
+
+ while(n < 32)
+ {
+ if( REG(t) & m )
+ break;
+ m >>= 1;
+ n++;
+ }
+
+ REG(RA) = n;
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+#endif
+
+static void ppc_crand(UINT32 op)
+{
+ int bit = RT;
+ int b = CRBIT(RA) & CRBIT(RB);
+ if( b & 0x1 )
+ CR(bit / 4) |= _BIT(3-(bit % 4));
+ else
+ CR(bit / 4) &= ~_BIT(3-(bit % 4));
+}
+
+static void ppc_crandc(UINT32 op)
+{
+ int bit = RT;
+ int b = CRBIT(RA) & ~CRBIT(RB);
+ if( b & 0x1 )
+ CR(bit / 4) |= _BIT(3-(bit % 4));
+ else
+ CR(bit / 4) &= ~_BIT(3-(bit % 4));
+}
+
+static void ppc_creqv(UINT32 op)
+{
+ int bit = RT;
+ int b = ~(CRBIT(RA) ^ CRBIT(RB));
+ if( b & 0x1 )
+ CR(bit / 4) |= _BIT(3-(bit % 4));
+ else
+ CR(bit / 4) &= ~_BIT(3-(bit % 4));
+}
+
+static void ppc_crnand(UINT32 op)
+{
+ int bit = RT;
+ int b = ~(CRBIT(RA) & CRBIT(RB));
+ if( b & 0x1 )
+ CR(bit / 4) |= _BIT(3-(bit % 4));
+ else
+ CR(bit / 4) &= ~_BIT(3-(bit % 4));
+}
+
+static void ppc_crnor(UINT32 op)
+{
+ int bit = RT;
+ int b = ~(CRBIT(RA) | CRBIT(RB));
+ if( b & 0x1 )
+ CR(bit / 4) |= _BIT(3-(bit % 4));
+ else
+ CR(bit / 4) &= ~_BIT(3-(bit % 4));
+}
+
+static void ppc_cror(UINT32 op)
+{
+ int bit = RT;
+ int b = CRBIT(RA) | CRBIT(RB);
+ if( b & 0x1 )
+ CR(bit / 4) |= _BIT(3-(bit % 4));
+ else
+ CR(bit / 4) &= ~_BIT(3-(bit % 4));
+}
+
+static void ppc_crorc(UINT32 op)
+{
+ int bit = RT;
+ int b = CRBIT(RA) | ~CRBIT(RB);
+ if( b & 0x1 )
+ CR(bit / 4) |= _BIT(3-(bit % 4));
+ else
+ CR(bit / 4) &= ~_BIT(3-(bit % 4));
+}
+
+static void ppc_crxor(UINT32 op)
+{
+ int bit = RT;
+ int b = CRBIT(RA) ^ CRBIT(RB);
+ if( b & 0x1 )
+ CR(bit / 4) |= _BIT(3-(bit % 4));
+ else
+ CR(bit / 4) &= ~_BIT(3-(bit % 4));
+}
+
+#ifndef PPC_DRC
+static void ppc_dcbf(UINT32 op)
+{
+
+}
+
+static void ppc_dcbi(UINT32 op)
+{
+
+}
+
+static void ppc_dcbst(UINT32 op)
+{
+
+}
+
+static void ppc_dcbt(UINT32 op)
+{
+
+}
+
+static void ppc_dcbtst(UINT32 op)
+{
+
+}
+
+static void ppc_dcbz(UINT32 op)
+{
+
+}
+#endif
+
+static void ppc_divwx(UINT32 op)
+{
+ if( REG(RB) == 0 && REG(RA) < 0x80000000 )
+ {
+ REG(RT) = 0;
+ if( OEBIT ) {
+ XER |= XER_SO | XER_OV;
+ }
+ }
+ else if( REG(RB) == 0 || (REG(RB) == 0xffffffff && REG(RA) == 0x80000000) )
+ {
+ REG(RT) = 0xffffffff;
+ if( OEBIT ) {
+ XER |= XER_SO | XER_OV;
+ }
+ }
+ else
+ {
+ REG(RT) = (INT32)REG(RA) / (INT32)REG(RB);
+ if( OEBIT ) {
+ XER &= ~XER_OV;
+ }
+ }
+
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+static void ppc_divwux(UINT32 op)
+{
+ if( REG(RB) == 0 )
+ {
+ REG(RT) = 0;
+ if( OEBIT ) {
+ XER |= XER_SO | XER_OV;
+ }
+ }
+ else
+ {
+ REG(RT) = (UINT32)REG(RA) / (UINT32)REG(RB);
+ if( OEBIT ) {
+ XER &= ~XER_OV;
+ }
+ }
+
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+#ifndef PPC_DRC
+static void ppc_eieio(UINT32 op)
+{
+
+}
+
+static void ppc_eqvx(UINT32 op)
+{
+ REG(RA) = ~(REG(RS) ^ REG(RB));
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_extsbx(UINT32 op)
+{
+ REG(RA) = (INT32)(INT8)REG(RS);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_extshx(UINT32 op)
+{
+ REG(RA) = (INT32)(INT16)REG(RS);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_icbi(UINT32 op)
+{
+
+}
+
+static void ppc_isync(UINT32 op)
+{
+
+}
+
+static void ppc_lbz(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = SIMM16;
+ else
+ ea = REG(RA) + SIMM16;
+
+ REG(RT) = (UINT32)READ8(ea);
+}
+
+static void ppc_lbzu(UINT32 op)
+{
+ UINT32 ea = REG(RA) + SIMM16;
+
+ REG(RT) = (UINT32)READ8(ea);
+ REG(RA) = ea;
+}
+
+static void ppc_lbzux(UINT32 op)
+{
+ UINT32 ea = REG(RA) + REG(RB);
+
+ REG(RT) = (UINT32)READ8(ea);
+ REG(RA) = ea;
+}
+
+static void ppc_lbzx(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ REG(RT) = (UINT32)READ8(ea);
+}
+
+static void ppc_lha(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = SIMM16;
+ else
+ ea = REG(RA) + SIMM16;
+
+ REG(RT) = (INT32)(INT16)READ16(ea);
+}
+
+static void ppc_lhau(UINT32 op)
+{
+ UINT32 ea = REG(RA) + SIMM16;
+
+ REG(RT) = (INT32)(INT16)READ16(ea);
+ REG(RA) = ea;
+}
+
+static void ppc_lhaux(UINT32 op)
+{
+ UINT32 ea = REG(RA) + REG(RB);
+
+ REG(RT) = (INT32)(INT16)READ16(ea);
+ REG(RA) = ea;
+}
+
+static void ppc_lhax(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ REG(RT) = (INT32)(INT16)READ16(ea);
+}
+
+static void ppc_lhbrx(UINT32 op)
+{
+ UINT32 ea;
+ UINT16 w;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ w = READ16(ea);
+ REG(RT) = (UINT32)BYTE_REVERSE16(w);
+}
+
+static void ppc_lhz(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = SIMM16;
+ else
+ ea = REG(RA) + SIMM16;
+
+ REG(RT) = (UINT32)READ16(ea);
+}
+
+static void ppc_lhzu(UINT32 op)
+{
+ UINT32 ea = REG(RA) + SIMM16;
+
+ REG(RT) = (UINT32)READ16(ea);
+ REG(RA) = ea;
+}
+
+static void ppc_lhzux(UINT32 op)
+{
+ UINT32 ea = REG(RA) + REG(RB);
+
+ REG(RT) = (UINT32)READ16(ea);
+ REG(RA) = ea;
+}
+
+static void ppc_lhzx(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ REG(RT) = (UINT32)READ16(ea);
+}
+#endif
+
+static void ppc_lmw(UINT32 op)
+{
+ int r = RT;
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = SIMM16;
+ else
+ ea = REG(RA) + SIMM16;
+
+ while( r <= 31 )
+ {
+ REG(r) = READ32(ea);
+ ea += 4;
+ r++;
+ }
+}
+
+static void ppc_lswi(UINT32 op)
+{
+ int n, r, i;
+ UINT32 ea = 0;
+ if( RA != 0 )
+ ea = REG(RA);
+
+ if( RB == 0 )
+ n = 32;
+ else
+ n = RB;
+
+ r = RT - 1;
+ i = 0;
+
+ while(n > 0)
+ {
+ if (i == 0) {
+ r = (r + 1) % 32;
+ REG(r) = 0;
+ }
+ REG(r) |= ((READ8(ea) & 0xff) << (24 - i));
+ i += 8;
+ if (i == 32) {
+ i = 0;
+ }
+ ea++;
+ n--;
+ }
+}
+
+static void ppc_lswx(UINT32 op)
+{
+ int n, r, i;
+ UINT32 ea = 0;
+ if( RA != 0 )
+ ea = REG(RA);
+
+ ea += REG(RB);
+
+ n = ppc.xer & 0x7f;
+
+ r = RT - 1;
+ i = 0;
+
+ while(n > 0)
+ {
+ if (i == 0) {
+ r = (r + 1) % 32;
+ REG(r) = 0;
+ }
+ REG(r) |= ((READ8(ea) & 0xff) << (24 - i));
+ i += 8;
+ if (i == 32) {
+ i = 0;
+ }
+ ea++;
+ n--;
+ }
+}
+
+static void ppc_lwarx(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ ppc.reserved_address = ea;
+ ppc.reserved = 1;
+
+ REG(RT) = READ32(ea);
+}
+
+#ifndef PPC_DRC
+static void ppc_lwbrx(UINT32 op)
+{
+ UINT32 ea;
+ UINT32 w;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ w = READ32(ea);
+ REG(RT) = BYTE_REVERSE32(w);
+}
+
+static void ppc_lwz(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = SIMM16;
+ else
+ ea = REG(RA) + SIMM16;
+
+ REG(RT) = READ32(ea);
+}
+
+static void ppc_lwzu(UINT32 op)
+{
+ UINT32 ea = REG(RA) + SIMM16;
+
+ REG(RT) = READ32(ea);
+ REG(RA) = ea;
+}
+
+static void ppc_lwzux(UINT32 op)
+{
+ UINT32 ea = REG(RA) + REG(RB);
+
+ REG(RT) = READ32(ea);
+ REG(RA) = ea;
+}
+
+static void ppc_lwzx(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ REG(RT) = READ32(ea);
+}
+
+static void ppc_mcrf(UINT32 op)
+{
+ CR(RT >> 2) = CR(RA >> 2);
+}
+
+static void ppc_mcrxr(UINT32 op)
+{
+ CR(RT >> 2) = (XER >> 28) & 0x0F;
+ XER &= ~0xf0000000;
+}
+
+static void ppc_mfcr(UINT32 op)
+{
+ REG(RT) = ppc_get_cr();
+}
+
+static void ppc_mfmsr(UINT32 op)
+{
+ REG(RT) = ppc_get_msr();
+}
+
+static void ppc_mfspr(UINT32 op)
+{
+ REG(RT) = ppc_get_spr(SPR);
+}
+#endif
+
+static void ppc_mtcrf(UINT32 op)
+{
+ int fxm = FXM;
+ int t = RT;
+
+ if( fxm & 0x80 ) CR(0) = (REG(t) >> 28) & 0xf;
+ if( fxm & 0x40 ) CR(1) = (REG(t) >> 24) & 0xf;
+ if( fxm & 0x20 ) CR(2) = (REG(t) >> 20) & 0xf;
+ if( fxm & 0x10 ) CR(3) = (REG(t) >> 16) & 0xf;
+ if( fxm & 0x08 ) CR(4) = (REG(t) >> 12) & 0xf;
+ if( fxm & 0x04 ) CR(5) = (REG(t) >> 8) & 0xf;
+ if( fxm & 0x02 ) CR(6) = (REG(t) >> 4) & 0xf;
+ if( fxm & 0x01 ) CR(7) = (REG(t) >> 0) & 0xf;
+}
+
+#ifndef PPC_DRC
+static void ppc_mtmsr(UINT32 op)
+{
+ ppc_set_msr(REG(RS));
+}
+
+static void ppc_mtspr(UINT32 op)
+{
+ ppc_set_spr(SPR, REG(RS));
+}
+
+static void ppc_mulhwx(UINT32 op)
+{
+ INT64 ra = (INT64)(INT32)REG(RA);
+ INT64 rb = (INT64)(INT32)REG(RB);
+
+ REG(RT) = (UINT32)((ra * rb) >> 32);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+static void ppc_mulhwux(UINT32 op)
+{
+ UINT64 ra = (UINT64)REG(RA);
+ UINT64 rb = (UINT64)REG(RB);
+
+ REG(RT) = (UINT32)((ra * rb) >> 32);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+static void ppc_mulli(UINT32 op)
+{
+ INT32 ra = (INT32)REG(RA);
+ INT32 i = SIMM16;
+
+ REG(RT) = ra * i;
+}
+
+static void ppc_mullwx(UINT32 op)
+{
+ INT64 ra = (INT64)(INT32)REG(RA);
+ INT64 rb = (INT64)(INT32)REG(RB);
+ INT64 r;
+
+ r = ra * rb;
+ REG(RT) = (UINT32)r;
+
+ if( OEBIT ) {
+ XER &= ~XER_OV;
+
+ if( r != (INT64)(INT32)r )
+ XER |= XER_OV | XER_SO;
+ }
+
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+static void ppc_nandx(UINT32 op)
+{
+ REG(RA) = ~(REG(RS) & REG(RB));
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_negx(UINT32 op)
+{
+ REG(RT) = -REG(RA);
+
+ if( OEBIT ) {
+ if( REG(RT) == 0x80000000 )
+ XER |= XER_OV | XER_SO;
+ else
+ XER &= ~XER_OV;
+ }
+
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+static void ppc_norx(UINT32 op)
+{
+ REG(RA) = ~(REG(RS) | REG(RB));
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_orx(UINT32 op)
+{
+ REG(RA) = REG(RS) | REG(RB);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_orcx(UINT32 op)
+{
+ REG(RA) = REG(RS) | ~REG(RB);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_ori(UINT32 op)
+{
+ REG(RA) = REG(RS) | UIMM16;
+}
+
+static void ppc_oris(UINT32 op)
+{
+ REG(RA) = REG(RS) | (UIMM16 << 16);
+}
+
+static void ppc_rfi(UINT32 op)
+{
+ UINT32 msr;
+ ppc.npc = ppc_get_spr(SPR_SRR0);
+ msr = ppc_get_spr(SPR_SRR1);
+ ppc_set_msr( msr );
+
+ change_pc(ppc.npc);
+}
+
+static void ppc_rlwimix(UINT32 op)
+{
+ UINT32 r;
+ UINT32 mask = GET_ROTATE_MASK(MB, ME);
+ UINT32 rs = REG(RS);
+ int sh = SH;
+
+ r = (rs << sh) | (rs >> (32-sh));
+ REG(RA) = (REG(RA) & ~mask) | (r & mask);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_rlwinmx(UINT32 op)
+{
+ UINT32 r;
+ UINT32 mask = GET_ROTATE_MASK(MB, ME);
+ UINT32 rs = REG(RS);
+ int sh = SH;
+
+ r = (rs << sh) | (rs >> (32-sh));
+ REG(RA) = r & mask;
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_rlwnmx(UINT32 op)
+{
+ UINT32 r;
+ UINT32 mask = GET_ROTATE_MASK(MB, ME);
+ UINT32 rs = REG(RS);
+ int sh = REG(RB) & 0x1f;
+
+ r = (rs << sh) | (rs >> (32-sh));
+ REG(RA) = r & mask;
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+#endif
+
+#ifndef PPC_DRC
+static void ppc_sc(UINT32 op)
+{
+#if (HAS_PPC603 || HAS_PPC601)
+ if (ppc.is603) {
+ ppc603_exception(EXCEPTION_SYSTEM_CALL);
+ }
+#endif
+#if (HAS_PPC602)
+ if (ppc.is602) {
+ ppc602_exception(EXCEPTION_SYSTEM_CALL);
+ }
+#endif
+#if (HAS_PPC403)
+ if (IS_PPC403()) {
+ ppc403_exception(EXCEPTION_SYSTEM_CALL);
+ }
+#endif
+}
+#endif
+
+static void ppc_slwx(UINT32 op)
+{
+ int sh = REG(RB) & 0x3f;
+
+ if( sh > 31 ) {
+ REG(RA) = 0;
+ }
+ else {
+ REG(RA) = REG(RS) << sh;
+ }
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_srawx(UINT32 op)
+{
+ int sh = REG(RB) & 0x3f;
+
+ XER &= ~XER_CA;
+
+ if( sh > 31 ) {
+ if (REG(RS) & 0x80000000)
+ REG(RA) = 0xffffffff;
+ else
+ REG(RA) = 0;
+ if( REG(RA) )
+ XER |= XER_CA;
+ }
+ else {
+ REG(RA) = (INT32)(REG(RS)) >> sh;
+ if( ((INT32)(REG(RS)) < 0) && (REG(RS) & BITMASK_0(sh)) )
+ XER |= XER_CA;
+ }
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_srawix(UINT32 op)
+{
+ int sh = SH;
+
+ XER &= ~XER_CA;
+ if( ((INT32)(REG(RS)) < 0) && (REG(RS) & BITMASK_0(sh)) )
+ XER |= XER_CA;
+
+ REG(RA) = (INT32)(REG(RS)) >> sh;
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_srwx(UINT32 op)
+{
+ int sh = REG(RB) & 0x3f;
+
+ if( sh > 31 ) {
+ REG(RA) = 0;
+ }
+ else {
+ REG(RA) = REG(RS) >> sh;
+ }
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+#ifndef PPC_DRC
+static void ppc_stb(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = SIMM16;
+ else
+ ea = REG(RA) + SIMM16;
+
+ WRITE8(ea, (UINT8)REG(RS));
+}
+
+static void ppc_stbu(UINT32 op)
+{
+ UINT32 ea = REG(RA) + SIMM16;
+
+ WRITE8(ea, (UINT8)REG(RS));
+ REG(RA) = ea;
+}
+
+static void ppc_stbux(UINT32 op)
+{
+ UINT32 ea = REG(RA) + REG(RB);
+
+ WRITE8(ea, (UINT8)REG(RS));
+ REG(RA) = ea;
+}
+
+static void ppc_stbx(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ WRITE8(ea, (UINT8)REG(RS));
+}
+
+static void ppc_sth(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = SIMM16;
+ else
+ ea = REG(RA) + SIMM16;
+
+ WRITE16(ea, (UINT16)REG(RS));
+}
+
+static void ppc_sthbrx(UINT32 op)
+{
+ UINT32 ea;
+ UINT16 w;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ w = REG(RS);
+ WRITE16(ea, (UINT16)BYTE_REVERSE16(w));
+}
+
+static void ppc_sthu(UINT32 op)
+{
+ UINT32 ea = REG(RA) + SIMM16;
+
+ WRITE16(ea, (UINT16)REG(RS));
+ REG(RA) = ea;
+}
+
+static void ppc_sthux(UINT32 op)
+{
+ UINT32 ea = REG(RA) + REG(RB);
+
+ WRITE16(ea, (UINT16)REG(RS));
+ REG(RA) = ea;
+}
+
+static void ppc_sthx(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ WRITE16(ea, (UINT16)REG(RS));
+}
+#endif
+
+static void ppc_stmw(UINT32 op)
+{
+ UINT32 ea;
+ int r = RS;
+
+ if( RA == 0 )
+ ea = SIMM16;
+ else
+ ea = REG(RA) + SIMM16;
+
+ while( r <= 31 )
+ {
+ WRITE32(ea, REG(r));
+ ea += 4;
+ r++;
+ }
+}
+
+static void ppc_stswi(UINT32 op)
+{
+ int n, r, i;
+ UINT32 ea = 0;
+ if( RA != 0 )
+ ea = REG(RA);
+
+ if( RB == 0 )
+ n = 32;
+ else
+ n = RB;
+
+ r = RT - 1;
+ i = 0;
+
+ while(n > 0)
+ {
+ if (i == 0) {
+ r = (r + 1) % 32;
+ }
+ WRITE8(ea, (REG(r) >> (24-i)) & 0xff);
+ i += 8;
+ if (i == 32) {
+ i = 0;
+ }
+ ea++;
+ n--;
+ }
+}
+
+static void ppc_stswx(UINT32 op)
+{
+ int n, r, i;
+ UINT32 ea = 0;
+ if( RA != 0 )
+ ea = REG(RA);
+
+ ea += REG(RB);
+
+ n = ppc.xer & 0x7f;
+
+ r = RT - 1;
+ i = 0;
+
+ while(n > 0)
+ {
+ if (i == 0) {
+ r = (r + 1) % 32;
+ }
+ WRITE8(ea, (REG(r) >> (24-i)) & 0xff);
+ i += 8;
+ if (i == 32) {
+ i = 0;
+ }
+ ea++;
+ n--;
+ }
+}
+
+#ifndef PPC_DRC
+static void ppc_stw(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = SIMM16;
+ else
+ ea = REG(RA) + SIMM16;
+
+ WRITE32(ea, REG(RS));
+}
+
+static void ppc_stwbrx(UINT32 op)
+{
+ UINT32 ea;
+ UINT32 w;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ w = REG(RS);
+ WRITE32(ea, BYTE_REVERSE32(w));
+}
+#endif
+
+static void ppc_stwcx_rc(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ if( ppc.reserved ) {
+ WRITE32(ea, REG(RS));
+
+ ppc.reserved = 0;
+ ppc.reserved_address = 0;
+
+ CR(0) = 0x2;
+ if( XER & XER_SO )
+ CR(0) |= 0x1;
+ } else {
+ CR(0) = 0;
+ if( XER & XER_SO )
+ CR(0) |= 0x1;
+ }
+}
+
+#ifndef PPC_DRC
+static void ppc_stwu(UINT32 op)
+{
+ UINT32 ea = REG(RA) + SIMM16;
+
+ WRITE32(ea, REG(RS));
+ REG(RA) = ea;
+}
+
+static void ppc_stwux(UINT32 op)
+{
+ UINT32 ea = REG(RA) + REG(RB);
+
+ WRITE32(ea, REG(RS));
+ REG(RA) = ea;
+}
+
+static void ppc_stwx(UINT32 op)
+{
+ UINT32 ea;
+
+ if( RA == 0 )
+ ea = REG(RB);
+ else
+ ea = REG(RA) + REG(RB);
+
+ WRITE32(ea, REG(RS));
+}
+
+static void ppc_subfx(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 rb = REG(RB);
+ REG(RT) = rb - ra;
+
+ if( OEBIT ) {
+ SET_SUB_OV(REG(RT), rb, ra);
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+#endif
+
+static void ppc_subfcx(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 rb = REG(RB);
+ REG(RT) = rb - ra;
+
+ SET_SUB_CA(REG(RT), rb, ra);
+
+ if( OEBIT ) {
+ SET_SUB_OV(REG(RT), rb, ra);
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+#ifndef PPC_DRC
+static void ppc_subfex(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 rb = REG(RB);
+ UINT32 carry = (XER >> 29) & 0x1;
+ UINT32 r;
+
+ r = ~ra + carry;
+ REG(RT) = rb + r;
+
+ SET_ADD_CA(r, ~ra, carry); /* step 1 carry */
+ if( REG(RT) < r ) /* step 2 carry */
+ XER |= XER_CA;
+
+ if( OEBIT ) {
+ SET_SUB_OV(REG(RT), rb, ra);
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+static void ppc_subfic(UINT32 op)
+{
+ UINT32 i = SIMM16;
+ UINT32 ra = REG(RA);
+
+ REG(RT) = i - ra;
+
+ SET_SUB_CA(REG(RT), i, ra);
+}
+#endif
+
+static void ppc_subfmex(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 carry = (XER >> 29) & 0x1;
+ UINT32 r;
+
+ r = ~ra + carry;
+ REG(RT) = r - 1;
+
+ SET_SUB_CA(r, ~ra, carry); /* step 1 carry */
+ if( REG(RT) < r )
+ XER |= XER_CA; /* step 2 carry */
+
+ if( OEBIT ) {
+ SET_SUB_OV(REG(RT), -1, ra);
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+static void ppc_subfzex(UINT32 op)
+{
+ UINT32 ra = REG(RA);
+ UINT32 carry = (XER >> 29) & 0x1;
+
+ REG(RT) = ~ra + carry;
+
+ SET_ADD_CA(REG(RT), ~ra, carry);
+
+ if( OEBIT ) {
+ SET_SUB_OV(REG(RT), 0, REG(RA));
+ }
+ if( RCBIT ) {
+ SET_CR0(REG(RT));
+ }
+}
+
+#ifndef PPC_DRC
+static void ppc_sync(UINT32 op)
+{
+
+}
+#endif
+
+#ifndef PPC_DRC
+static void ppc_tw(UINT32 op)
+{
+ int exception = 0;
+ INT32 a = REG(RA);
+ INT32 b = REG(RB);
+ int to = RT;
+
+ if( (a < b) && (to & 0x10) ) {
+ exception = 1;
+ }
+ if( (a > b) && (to & 0x08) ) {
+ exception = 1;
+ }
+ if( (a == b) && (to & 0x04) ) {
+ exception = 1;
+ }
+ if( ((UINT32)a < (UINT32)b) && (to & 0x02) ) {
+ exception = 1;
+ }
+ if( ((UINT32)a > (UINT32)b) && (to & 0x01) ) {
+ exception = 1;
+ }
+
+ if (exception) {
+#if (HAS_PPC603 || HAS_PPC601)
+ if (ppc.is603) {
+ ppc603_exception(EXCEPTION_TRAP);
+ }
+#endif
+#if (HAS_PPC602)
+ if (ppc.is602) {
+ ppc602_exception(EXCEPTION_TRAP);
+ }
+#endif
+#if (HAS_PPC403)
+ if (IS_PPC403()) {
+ ppc403_exception(EXCEPTION_TRAP);
+ }
+#endif
+ }
+}
+#endif
+
+#ifndef PPC_DRC
+static void ppc_twi(UINT32 op)
+{
+ int exception = 0;
+ INT32 a = REG(RA);
+ INT32 i = SIMM16;
+ int to = RT;
+
+ if( (a < i) && (to & 0x10) ) {
+ exception = 1;
+ }
+ if( (a > i) && (to & 0x08) ) {
+ exception = 1;
+ }
+ if( (a == i) && (to & 0x04) ) {
+ exception = 1;
+ }
+ if( ((UINT32)a < (UINT32)i) && (to & 0x02) ) {
+ exception = 1;
+ }
+ if( ((UINT32)a > (UINT32)i) && (to & 0x01) ) {
+ exception = 1;
+ }
+
+ if (exception) {
+#if (HAS_PPC603 || HAS_PPC601)
+ if (ppc.is603) {
+ ppc603_exception(EXCEPTION_TRAP);
+ }
+#endif
+#if (HAS_PPC602)
+ if (ppc.is602) {
+ ppc602_exception(EXCEPTION_TRAP);
+ }
+#endif
+#if (HAS_PPC403)
+ if (IS_PPC403()) {
+ ppc403_exception(EXCEPTION_TRAP);
+ }
+#endif
+ }
+}
+#endif
+
+#ifndef PPC_DRC
+static void ppc_xorx(UINT32 op)
+{
+ REG(RA) = REG(RS) ^ REG(RB);
+
+ if( RCBIT ) {
+ SET_CR0(REG(RA));
+ }
+}
+
+static void ppc_xori(UINT32 op)
+{
+ REG(RA) = REG(RS) ^ UIMM16;
+}
+
+static void ppc_xoris(UINT32 op)
+{
+ REG(RA) = REG(RS) ^ (UIMM16 << 16);
+}
+
+
+
+static void ppc_invalid(UINT32 op)
+{
+ fatalerror("ppc: Invalid opcode %08X PC : %X", op, ppc.pc);
+}
+#endif
+
+
+// Everything below is new from AJG
+
+////////////////////////////
+// !here are the 6xx ops! //
+////////////////////////////
+
+#define DOUBLE_SIGN (U64(0x8000000000000000))
+#define DOUBLE_EXP (U64(0x7ff0000000000000))
+#define DOUBLE_FRAC (U64(0x000fffffffffffff))
+#define DOUBLE_ZERO (0)
+
+/*
+ Floating point operations.
+*/
+
+INLINE int is_nan_double(FPR x)
+{
+ return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) &&
+ ((x.id & DOUBLE_FRAC) != DOUBLE_ZERO) );
+}
+
+INLINE int is_qnan_double(FPR x)
+{
+ return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) &&
+ ((x.id & U64(0x0007fffffffffff)) == U64(0x000000000000000)) &&
+ ((x.id & U64(0x000800000000000)) == U64(0x000800000000000)) );
+}
+
+INLINE int is_snan_double(FPR x)
+{
+ return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) &&
+ ((x.id & DOUBLE_FRAC) != DOUBLE_ZERO) &&
+ ((x.id & U64(0x0008000000000000)) == DOUBLE_ZERO) );
+}
+
+INLINE int is_infinity_double(FPR x)
+{
+ return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) &&
+ ((x.id & DOUBLE_FRAC) == DOUBLE_ZERO) );
+}
+
+INLINE int is_normalized_double(FPR x)
+{
+ UINT64 exp;
+
+ exp = (x.id & DOUBLE_EXP) >> 52;
+
+ return (exp >= 1) && (exp <= 2046);
+}
+
+INLINE int is_denormalized_double(FPR x)
+{
+ return( ((x.id & DOUBLE_EXP) == 0) &&
+ ((x.id & DOUBLE_FRAC) != DOUBLE_ZERO) );
+}
+
+INLINE int sign_double(FPR x)
+{
+ return ((x.id & DOUBLE_SIGN) != 0);
+}
+
+INLINE INT64 round_to_nearest(FPR f)
+{
+ if (f.fd >= 0)
+ {
+ return (INT64)(f.fd + 0.5);
+ }
+ else
+ {
+ return -(INT64)(-f.fd + 0.5);
+ }
+}
+
+INLINE INT64 round_toward_zero(FPR f)
+{
+ return (INT64)(f.fd);
+}
+
+INLINE INT64 round_toward_positive_infinity(FPR f)
+{
+ double r = ceil(f.fd);
+ return (INT64)(r);
+}
+
+INLINE INT64 round_toward_negative_infinity(FPR f)
+{
+ double r = floor(f.fd);
+ return (INT64)(r);
+}
+
+
+INLINE void set_fprf(FPR f)
+{
+ UINT32 fprf;
+
+ // see page 3-30, 3-31
+
+ if (is_qnan_double(f))
+ {
+ fprf = 0x11;
+ }
+ else if (is_infinity_double(f))
+ {
+ if (sign_double(f)) // -INF
+ fprf = 0x09;
+ else // +INF
+ fprf = 0x05;
+ }
+ else if (is_normalized_double(f))
+ {
+ if (sign_double(f)) // -Normalized
+ fprf = 0x08;
+ else // +Normalized
+ fprf = 0x04;
+ }
+ else if (is_denormalized_double(f))
+ {
+ if (sign_double(f)) // -Denormalized
+ fprf = 0x18;
+ else // +Denormalized
+ fprf = 0x14;
+ }
+ else // Zero
+ {
+ if (sign_double(f)) // -Zero
+ fprf = 0x12;
+ else // +Zero
+ fprf = 0x02;
+ }
+
+ ppc.fpscr &= ~0x0001f000;
+ ppc.fpscr |= (fprf << 12);
+}
+
+
+
+#define SET_VXSNAN(a, b) if (is_snan_double(a) || is_snan_double(b)) ppc.fpscr |= 0x80000000
+#define SET_VXSNAN_1(c) if (is_snan_double(c)) ppc.fpscr |= 0x80000000
+
+
+
+
+#if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_MPC8240)
+static void ppc_lfs(UINT32 op)
+{
+ UINT32 ea = SIMM16;
+ UINT32 a = RA;
+ UINT32 t = RT;
+ FPR32 f;
+
+ if(a)
+ ea += REG(a);
+
+ f.i = READ32(ea);
+ FPR(t).fd = (double)(f.f);
+}
+
+static void ppc_lfsu(UINT32 op)
+{
+ UINT32 ea = SIMM16;
+ UINT32 a = RA;
+ UINT32 t = RT;
+ FPR32 f;
+
+ ea += REG(a);
+
+ f.i = READ32(ea);
+ FPR(t).fd = (double)(f.f);
+
+ REG(a) = ea;
+}
+
+#ifndef PPC_DRC
+static void ppc_lfd(UINT32 op)
+{
+ UINT32 ea = SIMM16;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ if(a)
+ ea += REG(a);
+
+ FPR(t).id = READ64(ea);
+}
+
+static void ppc_lfdu(UINT32 op)
+{
+ UINT32 ea = SIMM16;
+ UINT32 a = RA;
+ UINT32 d = RD;
+
+ ea += REG(a);
+
+ FPR(d).id = READ64(ea);
+
+ REG(a) = ea;
+}
+#endif
+
+static void ppc_stfs(UINT32 op)
+{
+ UINT32 ea = SIMM16;
+ UINT32 a = RA;
+ UINT32 t = RT;
+ FPR32 f;
+
+ if(a)
+ ea += REG(a);
+
+ f.f = (float)(FPR(t).fd);
+ WRITE32(ea, f.i);
+}
+
+static void ppc_stfsu(UINT32 op)
+{
+ UINT32 ea = SIMM16;
+ UINT32 a = RA;
+ UINT32 t = RT;
+ FPR32 f;
+
+ ea += REG(a);
+
+ f.f = (float)(FPR(t).fd);
+ WRITE32(ea, f.i);
+
+ REG(a) = ea;
+}
+
+#ifndef PPC_DRC
+static void ppc_stfd(UINT32 op)
+{
+ UINT32 ea = SIMM16;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ if(a)
+ ea += REG(a);
+
+ WRITE64(ea, FPR(t).id);
+}
+
+static void ppc_stfdu(UINT32 op)
+{
+ UINT32 ea = SIMM16;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ ea += REG(a);
+
+ WRITE64(ea, FPR(t).id);
+
+ REG(a) = ea;
+}
+
+static void ppc_lfdux(UINT32 op)
+{
+ UINT32 ea = REG(RB);
+ UINT32 a = RA;
+ UINT32 d = RD;
+
+ ea += REG(a);
+
+ FPR(d).id = READ64(ea);
+
+ REG(a) = ea;
+}
+
+static void ppc_lfdx(UINT32 op)
+{
+ UINT32 ea = REG(RB);
+ UINT32 a = RA;
+ UINT32 d = RD;
+
+ if(a)
+ ea += REG(a);
+
+ FPR(d).id = READ64(ea);
+}
+#endif
+
+static void ppc_lfsux(UINT32 op)
+{
+ UINT32 ea = REG(RB);
+ UINT32 a = RA;
+ UINT32 t = RT;
+ FPR32 f;
+
+ ea += REG(a);
+
+ f.i = READ32(ea);
+ FPR(t).fd = (double)(f.f);
+
+ REG(a) = ea;
+}
+
+static void ppc_lfsx(UINT32 op)
+{
+ UINT32 ea = REG(RB);
+ UINT32 a = RA;
+ UINT32 t = RT;
+ FPR32 f;
+
+ if(a)
+ ea += REG(a);
+
+ f.i = READ32(ea);
+ FPR(t).fd = (double)(f.f);
+}
+
+static void ppc_mfsr(UINT32 op)
+{
+ UINT32 sr = (op >> 16) & 15;
+ UINT32 t = RT;
+
+ CHECK_SUPERVISOR();
+
+ REG(t) = ppc.sr[sr];
+}
+
+static void ppc_mfsrin(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_SUPERVISOR();
+
+ REG(t) = ppc.sr[REG(b) >> 28];
+}
+
+static void ppc_mftb(UINT32 op)
+{
+ UINT32 x = SPRF;
+
+ switch(x)
+ {
+ case 268: REG(RT) = (UINT32)(ppc_read_timebase()); break;
+ case 269: REG(RT) = (UINT32)(ppc_read_timebase() >> 32); break;
+ default: fatalerror("ppc: Invalid timebase register %d at %08X", x, ppc.pc); break;
+ }
+}
+
+static void ppc_mtsr(UINT32 op)
+{
+ UINT32 sr = (op >> 16) & 15;
+ UINT32 t = RT;
+
+ CHECK_SUPERVISOR();
+
+ ppc.sr[sr] = REG(t);
+}
+
+static void ppc_mtsrin(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_SUPERVISOR();
+
+ ppc.sr[REG(b) >> 28] = REG(t);
+}
+
+#ifndef PPC_DRC
+static void ppc_dcba(UINT32 op)
+{
+ /* TODO: Cache not emulated so this opcode doesn't need to be implemented */
+}
+
+static void ppc_stfdux(UINT32 op)
+{
+ UINT32 ea = REG(RB);
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ ea += REG(a);
+
+ WRITE64(ea, FPR(t).id);
+
+ REG(a) = ea;
+}
+#endif
+
+static void ppc_stfdx(UINT32 op)
+{
+ UINT32 ea = REG(RB);
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ if(a)
+ ea += REG(a);
+
+ WRITE64(ea, FPR(t).id);
+}
+
+static void ppc_stfiwx(UINT32 op)
+{
+ UINT32 ea = REG(RB);
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ if(a)
+ ea += REG(a);
+
+ WRITE32(ea, (UINT32)FPR(t).id);
+}
+
+static void ppc_stfsux(UINT32 op)
+{
+ UINT32 ea = REG(RB);
+ UINT32 a = RA;
+ UINT32 t = RT;
+ FPR32 f;
+
+ ea += REG(a);
+
+ f.f = (float)(FPR(t).fd);
+ WRITE32(ea, f.i);
+
+ REG(a) = ea;
+}
+
+static void ppc_stfsx(UINT32 op)
+{
+ UINT32 ea = REG(RB);
+ UINT32 a = RA;
+ UINT32 t = RT;
+ FPR32 f;
+
+ if(a)
+ ea += REG(a);
+
+ f.f = (float)(FPR(t).fd);
+
+ WRITE32(ea, f.i);
+}
+
+#ifndef PPC_DRC
+static void ppc_tlbia(UINT32 op)
+{
+ /* TODO: TLB not emulated so this opcode doesn't need to implemented */
+}
+
+static void ppc_tlbie(UINT32 op)
+{
+ /* TODO: TLB not emulated so this opcode doesn't need to implemented */
+}
+
+static void ppc_tlbsync(UINT32 op)
+{
+ /* TODO: TLB not emulated so this opcode doesn't need to implemented */
+}
+
+static void ppc_eciwx(UINT32 op)
+{
+ ppc_unimplemented(op);
+}
+
+static void ppc_ecowx(UINT32 op)
+{
+ ppc_unimplemented(op);
+}
+#endif
+
+static void ppc_fabsx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ FPR(t).id = FPR(b).id & ~DOUBLE_SIGN;
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_faddx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+
+ FPR(t).fd = FPR(a).fd + FPR(b).fd;
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fcmpo(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = (RT >> 2);
+ UINT32 c;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+
+ if(is_nan_double(FPR(a)) || is_nan_double(FPR(b)))
+ {
+ c = 1; /* OX */
+ if(is_snan_double(FPR(a)) || is_snan_double(FPR(b))) {
+ ppc.fpscr |= 0x01000000; /* VXSNAN */
+
+ if(!(ppc.fpscr & 0x40000000) || is_qnan_double(FPR(a)) || is_qnan_double(FPR(b)))
+ ppc.fpscr |= 0x00080000; /* VXVC */
+ }
+ }
+ else if(FPR(a).fd < FPR(b).fd){
+ c = 8; /* FX */
+ }
+ else if(FPR(a).fd > FPR(b).fd){
+ c = 4; /* FEX */
+ }
+ else {
+ c = 2; /* VX */
+ }
+
+ CR(t) = c;
+
+ ppc.fpscr &= ~0x0001F000;
+ ppc.fpscr |= (c << 12);
+}
+
+static void ppc_fcmpu(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = (RT >> 2);
+ UINT32 c;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+
+ if(is_nan_double(FPR(a)) || is_nan_double(FPR(b)))
+ {
+ c = 1; /* OX */
+ if(is_snan_double(FPR(a)) || is_snan_double(FPR(b))) {
+ ppc.fpscr |= 0x01000000; /* VXSNAN */
+ }
+ }
+ else if(FPR(a).fd < FPR(b).fd){
+ c = 8; /* FX */
+ }
+ else if(FPR(a).fd > FPR(b).fd){
+ c = 4; /* FEX */
+ }
+ else {
+ c = 2; /* VX */
+ }
+
+ CR(t) = c;
+
+ ppc.fpscr &= ~0x0001F000;
+ ppc.fpscr |= (c << 12);
+}
+
+static void ppc_fctiwx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+ INT64 r = 0;
+
+ // TODO: fix FPSCR flags FX,VXSNAN,VXCVI
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN_1(FPR(b));
+
+ switch(ppc.fpscr & 3)
+ {
+ case 0: r = (INT64)round_to_nearest(FPR(b)); break;
+ case 1: r = (INT64)round_toward_zero(FPR(b)); break;
+ case 2: r = (INT64)round_toward_positive_infinity(FPR(b)); break;
+ case 3: r = (INT64)round_toward_negative_infinity(FPR(b)); break;
+ }
+
+ if(r > (INT64)((INT32)0x7FFFFFFF))
+ {
+ FPR(t).id = 0x7FFFFFFF;
+ // FPSCR[FR] = 0
+ // FPSCR[FI] = 1
+ // FPSCR[XX] = 1
+ }
+ else if(FPR(b).fd < (INT64)((INT32)0x80000000))
+ {
+ FPR(t).id = 0x80000000;
+ // FPSCR[FR] = 1
+ // FPSCR[FI] = 1
+ // FPSCR[XX] = 1
+ }
+ else
+ {
+ FPR(t).id = (UINT32)r;
+ // FPSCR[FR] = t.iw > t.fd
+ // FPSCR[FI] = t.iw == t.fd
+ // FPSCR[XX] = ?
+ }
+
+ // FPSCR[FPRF] = undefined (leave it as is)
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fctiwzx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+ INT64 r;
+
+ // TODO: fix FPSCR flags FX,VXSNAN,VXCVI
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN_1(FPR(b));
+ r = round_toward_zero(FPR(b));
+
+ if(r > (INT64)((INT32)0x7fffffff))
+ {
+ FPR(t).id = 0x7fffffff;
+ // FPSCR[FR] = 0
+ // FPSCR[FI] = 1
+ // FPSCR[XX] = 1
+
+ }
+ else if(r < (INT64)((INT32)0x80000000))
+ {
+ FPR(t).id = 0x80000000;
+ // FPSCR[FR] = 1
+ // FPSCR[FI] = 1
+ // FPSCR[XX] = 1
+ }
+ else
+ {
+ FPR(t).id = (UINT32)r;
+ // FPSCR[FR] = t.iw > t.fd
+ // FPSCR[FI] = t.iw == t.fd
+ // FPSCR[XX] = ?
+ }
+
+ // FPSCR[FPRF] = undefined (leave it as is)
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fdivx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+
+ FPR(t).fd = FPR(a).fd / FPR(b).fd;
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fmrx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ FPR(t).fd = FPR(b).fd;
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fnabsx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ FPR(t).id = FPR(b).id | DOUBLE_SIGN;
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fnegx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ FPR(t).id = FPR(b).id ^ DOUBLE_SIGN;
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_frspx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN_1(FPR(b));
+
+ FPR(t).fd = (float)FPR(b).fd;
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_frsqrtex(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN_1(FPR(b));
+
+ FPR(t).fd = 1.0 / sqrt(FPR(b).fd); /* verify this */
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fsqrtx(UINT32 op)
+{
+ /* NOTE: PPC603e doesn't support this opcode */
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN_1(FPR(b));
+
+ FPR(t).fd = (double)(sqrt(FPR(b).fd));
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fsubx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+
+ FPR(t).fd = FPR(a).fd - FPR(b).fd;
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_mffsx(UINT32 op)
+{
+ FPR(RT).id = (UINT32)ppc.fpscr;
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_mtfsb0x(UINT32 op)
+{
+ UINT32 crbD;
+
+ crbD = (op >> 21) & 0x1F;
+
+ if (crbD != 1 && crbD != 2) // these bits cannot be explicitly cleared
+ ppc.fpscr &= ~(1 << (31 - crbD));
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_mtfsb1x(UINT32 op)
+{
+ UINT32 crbD;
+
+ crbD = (op >> 21) & 0x1F;
+
+ if (crbD != 1 && crbD != 2) // these bits cannot be explicitly cleared
+ ppc.fpscr |= (1 << (31 - crbD));
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_mtfsfx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 f = FM;
+
+ f = ppc_field_xlat[FM];
+
+ ppc.fpscr &= (~f) | ~(FPSCR_FEX | FPSCR_VX);
+ ppc.fpscr |= (UINT32)(FPR(b).id) & ~(FPSCR_FEX | FPSCR_VX);
+
+ // FEX, VX
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_mtfsfix(UINT32 op)
+{
+ UINT32 crfd = CRFD;
+ UINT32 imm = (op >> 12) & 0xF;
+
+ /*
+ * According to the manual:
+ *
+ * If bits 0 and 3 of FPSCR are to be modified, they take the immediate
+ * value specified. Bits 1 and 2 (FEX and VX) are set according to the
+ * "usual rule" and not from IMM[1-2].
+ *
+ * The "usual rule" is not emulated, so these bits simply aren't modified
+ * at all here.
+ */
+
+ crfd = (7 - crfd) * 4; // calculate LSB position of field
+
+ if (crfd == 28) // field containing FEX and VX is special...
+ { // bits 1 and 2 of FPSCR must not be altered
+ ppc.fpscr &= 0x9fffffff;
+ ppc.fpscr |= (imm & 0x9fffffff);
+ }
+
+ ppc.fpscr &= ~(0xf << crfd); // clear field
+ ppc.fpscr |= (imm << crfd); // insert new data
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_mcrfs(UINT32 op)
+{
+ UINT32 crfs, f;
+ crfs = CRFA;
+
+ f = ppc.fpscr >> ((7 - crfs) * 4); // get crfS field from FPSCR
+ f &= 0xf;
+
+ switch(crfs) // determine which exception bits to clear in FPSCR
+ {
+ case 0: // FX, OX
+ ppc.fpscr &= ~0x90000000;
+ break;
+ case 1: // UX, ZX, XX, VXSNAN
+ ppc.fpscr &= ~0x0f000000;
+ break;
+ case 2: // VXISI, VXIDI, VXZDZ, VXIMZ
+ ppc.fpscr &= ~0x00F00000;
+ break;
+ case 3: // VXVC
+ ppc.fpscr &= ~0x00080000;
+ break;
+ case 5: // VXSOFT, VXSQRT, VXCVI
+ ppc.fpscr &= ~0x00000e00;
+ break;
+ default:
+ break;
+ }
+
+ CR(CRFD) = f;
+}
+
+static void ppc_faddsx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+
+ FPR(t).fd = (float)(FPR(a).fd + FPR(b).fd);
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fdivsx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+
+ FPR(t).fd = (float)(FPR(a).fd / FPR(b).fd);
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fresx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN_1(FPR(b));
+
+ FPR(t).fd = 1.0 / FPR(b).fd; /* ??? */
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fsqrtsx(UINT32 op)
+{
+ /* NOTE: This opcode is not supported in PPC603e */
+ UINT32 b = RB;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN_1(FPR(b));
+
+ FPR(t).fd = (float)(sqrt(FPR(b).fd));
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fsubsx(UINT32 op)
+{
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+
+ FPR(t).fd = (float)(FPR(a).fd - FPR(b).fd);
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fmaddx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+ SET_VXSNAN_1(FPR(c));
+
+ FPR(t).fd = ((FPR(a).fd * FPR(c).fd) + FPR(b).fd);
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fmsubx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+ SET_VXSNAN_1(FPR(c));
+
+ FPR(t).fd = ((FPR(a).fd * FPR(c).fd) - FPR(b).fd);
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fmulx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(c));
+
+ FPR(t).fd = (FPR(a).fd * FPR(c).fd);
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fnmaddx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+ SET_VXSNAN_1(FPR(c));
+
+ FPR(t).fd = (-((FPR(a).fd * FPR(c).fd) + FPR(b).fd));
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fnmsubx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+ SET_VXSNAN_1(FPR(c));
+
+ FPR(t).fd = (-((FPR(a).fd * FPR(c).fd) - FPR(b).fd));
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fselx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ FPR(t).fd = (FPR(a).fd >= 0.0) ? FPR(c).fd : FPR(b).fd;
+
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fmaddsx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+ SET_VXSNAN_1(FPR(c));
+
+ FPR(t).fd = (float)((FPR(a).fd * FPR(c).fd) + FPR(b).fd);
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fmsubsx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+ SET_VXSNAN_1(FPR(c));
+
+ FPR(t).fd = (float)((FPR(a).fd * FPR(c).fd) - FPR(b).fd);
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fmulsx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+ SET_VXSNAN(FPR(a), FPR(c));
+
+ FPR(t).fd = (float)(FPR(a).fd * FPR(c).fd);
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fnmaddsx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+ SET_VXSNAN_1(FPR(c));
+
+ FPR(t).fd = (float)(-((FPR(a).fd * FPR(c).fd) + FPR(b).fd));
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+
+static void ppc_fnmsubsx(UINT32 op)
+{
+ UINT32 c = RC;
+ UINT32 b = RB;
+ UINT32 a = RA;
+ UINT32 t = RT;
+
+ CHECK_FPU_AVAILABLE();
+
+ SET_VXSNAN(FPR(a), FPR(b));
+ SET_VXSNAN_1(FPR(c));
+
+ FPR(t).fd = (float)(-((FPR(a).fd * FPR(c).fd) - FPR(b).fd));
+
+ set_fprf(FPR(t));
+ if( RCBIT ) {
+ SET_CR1();
+ }
+}
+#endif
diff --git a/src/emu/cpu/powerpc/ppc_ops.h b/src/emu/cpu/powerpc/ppc_ops.h
new file mode 100644
index 00000000000..d87bac5a27d
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppc_ops.h
@@ -0,0 +1,143 @@
+static PPC_OPCODE ppc_opcode_common[] =
+{
+ /*code subcode handler */
+ { 31, 266, ppc_addx },
+ { 31, 266 | 512, ppc_addx },
+ { 31, 10, ppc_addcx },
+ { 31, 10 | 512, ppc_addcx },
+ { 31, 138, ppc_addex },
+ { 31, 138 | 512, ppc_addex },
+ { 14, -1, ppc_addi },
+ { 12, -1, ppc_addic },
+ { 13, -1, ppc_addic_rc },
+ { 15, -1, ppc_addis },
+ { 31, 234, ppc_addmex },
+ { 31, 234 | 512, ppc_addmex },
+ { 31, 202, ppc_addzex },
+ { 31, 202 | 512, ppc_addzex },
+ { 31, 28, ppc_andx },
+ { 31, 28 | 512, ppc_andx },
+ { 31, 60, ppc_andcx },
+ { 28, -1, ppc_andi_rc },
+ { 29, -1, ppc_andis_rc },
+ { 18, -1, ppc_bx },
+ { 16, -1, ppc_bcx },
+ { 19, 528, ppc_bcctrx },
+ { 19, 16, ppc_bclrx },
+ { 31, 0, ppc_cmp },
+ { 11, -1, ppc_cmpi },
+ { 31, 32, ppc_cmpl },
+ { 10, -1, ppc_cmpli },
+ { 31, 26, ppc_cntlzw },
+ { 19, 257, ppc_crand },
+ { 19, 129, ppc_crandc },
+ { 19, 289, ppc_creqv },
+ { 19, 225, ppc_crnand },
+ { 19, 33, ppc_crnor },
+ { 19, 449, ppc_cror },
+ { 19, 417, ppc_crorc },
+ { 19, 193, ppc_crxor },
+ { 31, 86, ppc_dcbf },
+ { 31, 470, ppc_dcbi },
+ { 31, 54, ppc_dcbst },
+ { 31, 278, ppc_dcbt },
+ { 31, 246, ppc_dcbtst },
+ { 31, 1014, ppc_dcbz },
+ { 31, 491, ppc_divwx },
+ { 31, 491 | 512, ppc_divwx },
+ { 31, 459, ppc_divwux },
+ { 31, 459 | 512, ppc_divwux },
+ { 31, 854, ppc_eieio },
+ { 31, 284, ppc_eqvx },
+ { 31, 954, ppc_extsbx },
+ { 31, 922, ppc_extshx },
+ { 31, 982, ppc_icbi },
+ { 19, 150, ppc_isync },
+ { 34, -1, ppc_lbz },
+ { 35, -1, ppc_lbzu },
+ { 31, 119, ppc_lbzux },
+ { 31, 87, ppc_lbzx },
+ { 42, -1, ppc_lha },
+ { 43, -1, ppc_lhau },
+ { 31, 375, ppc_lhaux },
+ { 31, 343, ppc_lhax },
+ { 31, 790, ppc_lhbrx },
+ { 40, -1, ppc_lhz },
+ { 41, -1, ppc_lhzu },
+ { 31, 311, ppc_lhzux },
+ { 31, 279, ppc_lhzx },
+ { 46, -1, ppc_lmw },
+ { 31, 597, ppc_lswi },
+ { 31, 533, ppc_lswx },
+ { 31, 20, ppc_lwarx },
+ { 31, 534, ppc_lwbrx },
+ { 32, -1, ppc_lwz },
+ { 33, -1, ppc_lwzu },
+ { 31, 55, ppc_lwzux },
+ { 31, 23, ppc_lwzx },
+ { 19, 0, ppc_mcrf },
+ { 31, 512, ppc_mcrxr },
+ { 31, 19, ppc_mfcr },
+ { 31, 83, ppc_mfmsr },
+ { 31, 339, ppc_mfspr },
+ { 31, 144, ppc_mtcrf },
+ { 31, 146, ppc_mtmsr },
+ { 31, 467, ppc_mtspr },
+ { 31, 75, ppc_mulhwx },
+ { 31, 11, ppc_mulhwux },
+ { 7, -1, ppc_mulli },
+ { 31, 235, ppc_mullwx },
+ { 31, 235 | 512, ppc_mullwx },
+ { 31, 476, ppc_nandx },
+ { 31, 104, ppc_negx },
+ { 31, 104 | 512, ppc_negx },
+ { 31, 124, ppc_norx },
+ { 31, 444, ppc_orx },
+ { 31, 412, ppc_orcx },
+ { 24, -1, ppc_ori },
+ { 25, -1, ppc_oris },
+ { 19, 50, ppc_rfi },
+ { 20, -1, ppc_rlwimix },
+ { 21, -1, ppc_rlwinmx },
+ { 23, -1, ppc_rlwnmx },
+ { 17, -1, ppc_sc },
+ { 31, 24, ppc_slwx },
+ { 31, 792, ppc_srawx },
+ { 31, 824, ppc_srawix },
+ { 31, 536, ppc_srwx },
+ { 38, -1, ppc_stb },
+ { 39, -1, ppc_stbu },
+ { 31, 247, ppc_stbux },
+ { 31, 215, ppc_stbx },
+ { 44, -1, ppc_sth },
+ { 31, 918, ppc_sthbrx },
+ { 45, -1, ppc_sthu },
+ { 31, 439, ppc_sthux },
+ { 31, 407, ppc_sthx },
+ { 47, -1, ppc_stmw },
+ { 31, 725, ppc_stswi },
+ { 31, 661, ppc_stswx },
+ { 36, -1, ppc_stw },
+ { 31, 662, ppc_stwbrx },
+ { 31, 150, ppc_stwcx_rc },
+ { 37, -1, ppc_stwu },
+ { 31, 183, ppc_stwux },
+ { 31, 151, ppc_stwx },
+ { 31, 40, ppc_subfx },
+ { 31, 40 | 512, ppc_subfx },
+ { 31, 8, ppc_subfcx },
+ { 31, 8 | 512, ppc_subfcx },
+ { 31, 136, ppc_subfex },
+ { 31, 136 | 512, ppc_subfex },
+ { 8, -1, ppc_subfic },
+ { 31, 232, ppc_subfmex },
+ { 31, 232 | 512, ppc_subfmex },
+ { 31, 200, ppc_subfzex },
+ { 31, 200 | 512, ppc_subfzex },
+ { 31, 598, ppc_sync },
+ { 31, 4, ppc_tw },
+ { 3, -1, ppc_twi },
+ { 31, 316, ppc_xorx },
+ { 26, -1, ppc_xori },
+ { 27, -1, ppc_xoris }
+};
diff --git a/src/emu/cpu/powerpc/ppcdrc.c b/src/emu/cpu/powerpc/ppcdrc.c
new file mode 100644
index 00000000000..4a44b7a7e9d
--- /dev/null
+++ b/src/emu/cpu/powerpc/ppcdrc.c
@@ -0,0 +1,2302 @@
+/*
+ PowerPC 4xx/6xx Dynamic Recompiler for x86
+
+ Written by Ville Linde
+*/
+
+#include "ppc.h"
+#include "debugger.h"
+#include "cpu/x86drc.h"
+
+
+#define PPC_DRC
+#define LOG_CODE (0)
+
+#define CACHE_SIZE (16 * 1024 * 1024)
+#define MAX_INSTRUCTIONS 512
+
+
+#if (HAS_PPC603)
+static void ppcdrc603_init(int index, int clock, const void *_config, int (*irqcallback)(int));
+static void ppcdrc603_exit(void);
+#endif
+#if (HAS_PPC601 || HAS_PPC603 || HAS_MPC8240)
+static void ppcdrc603_reset(void);
+static int ppcdrc603_execute(int cycles);
+static void ppcdrc603_set_irq_line(int irqline, int state);
+#endif
+#if (HAS_PPC602)
+static void ppcdrc602_init(int index, int clock, const void *_config, int (*irqcallback)(int));
+static void ppcdrc602_exit(void);
+static void ppcdrc602_reset(void);
+static int ppcdrc602_execute(int cycles);
+static void ppcdrc602_set_irq_line(int irqline, int state);
+#endif
+#if (HAS_PPC403)
+UINT8 ppc403_spu_r(UINT32 a);
+void ppc403_spu_w(UINT32 a, UINT8 d);
+static void ppcdrc403_init(int index, int clock, const void *_config, int (*irqcallback)(int));
+static void ppcdrc403_exit(void);
+static void ppcdrc403_reset(void);
+static int ppcdrc403_execute(int cycles);
+static void ppcdrc403_set_irq_line(int irqline, int state);
+#endif
+
+static void ppcdrc_init(void);
+static void ppcdrc_reset(drc_core *drc);
+static void ppcdrc_recompile(drc_core *drc);
+static void ppcdrc_entrygen(drc_core *drc);
+
+#define RD ((op >> 21) & 0x1F)
+#define RT ((op >> 21) & 0x1f)
+#define RS ((op >> 21) & 0x1f)
+#define RA ((op >> 16) & 0x1f)
+#define RB ((op >> 11) & 0x1f)
+#define RC ((op >> 6) & 0x1f)
+
+#define MB ((op >> 6) & 0x1f)
+#define ME ((op >> 1) & 0x1f)
+#define SH ((op >> 11) & 0x1f)
+#define BO ((op >> 21) & 0x1f)
+#define BI ((op >> 16) & 0x1f)
+#define CRFD ((op >> 23) & 0x7)
+#define CRFA ((op >> 18) & 0x7)
+#define FXM ((op >> 12) & 0xff)
+#define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0))
+
+#define SIMM16 (INT32)(INT16)(op & 0xffff)
+#define UIMM16 (UINT32)(op & 0xffff)
+
+#define RCBIT (op & 0x1)
+#define OEBIT (op & 0x400)
+#define AABIT (op & 0x2)
+#define LKBIT (op & 0x1)
+
+#define REG(x) (ppc.r[x])
+#define LR (ppc.lr)
+#define CTR (ppc.ctr)
+#define XER (ppc.xer)
+#define CR(x) (ppc.cr[x])
+#define MSR (ppc.msr)
+#define SRR0 (ppc.srr0)
+#define SRR1 (ppc.srr1)
+#define SRR2 (ppc.srr2)
+#define SRR3 (ppc.srr3)
+#define EVPR (ppc.evpr)
+#define EXIER (ppc.exier)
+#define EXISR (ppc.exisr)
+#define DEC (ppc.dec)
+
+
+// Stuff added for the 6xx
+#define FPR(x) (ppc.fpr[x])
+#define FM ((op >> 17) & 0xFF)
+#define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F))
+
+
+#define CHECK_SUPERVISOR() \
+ if((ppc.msr & 0x4000) != 0){ \
+ }
+
+#define CHECK_FPU_AVAILABLE() \
+ if((ppc.msr & 0x2000) == 0){ \
+ }
+
+#if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_MPC8240)
+static UINT32 ppc_field_xlat[256];
+#endif
+
+
+
+#define FPSCR_FX 0x80000000
+#define FPSCR_FEX 0x40000000
+#define FPSCR_VX 0x20000000
+#define FPSCR_OX 0x10000000
+#define FPSCR_UX 0x08000000
+#define FPSCR_ZX 0x04000000
+#define FPSCR_XX 0x02000000
+
+
+
+#define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1)
+#define CRBIT(x) ((ppc.cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0)
+#define _BIT(n) (1 << (n))
+#define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me])
+#define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a)
+#define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b))
+#define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000)
+#define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000)
+
+#define XER_SO 0x80000000
+#define XER_OV 0x40000000
+#define XER_CA 0x20000000
+
+#define MSR_AP 0x00800000 /* Access privilege state (PPC602) */
+#define MSR_SA 0x00400000 /* Supervisor access mode (PPC602) */
+#define MSR_POW 0x00040000 /* Power Management Enable */
+#define MSR_WE 0x00040000
+#define MSR_CE 0x00020000
+#define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */
+#define MSR_EE 0x00008000 /* External Interrupt Enable */
+#define MSR_PR 0x00004000 /* Problem State */
+#define MSR_FP 0x00002000 /* Floating Point Available */
+#define MSR_ME 0x00001000 /* Machine Check Enable */
+#define MSR_FE0 0x00000800
+#define MSR_SE 0x00000400 /* Single Step Trace Enable */
+#define MSR_BE 0x00000200 /* Branch Trace Enable */
+#define MSR_DE 0x00000200
+#define MSR_FE1 0x00000100
+#define MSR_IP 0x00000040 /* Interrupt Prefix */
+#define MSR_IR 0x00000020 /* Instruction Relocate */
+#define MSR_DR 0x00000010 /* Data Relocate */
+#define MSR_PE 0x00000008
+#define MSR_PX 0x00000004
+#define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */
+#define MSR_LE 0x00000001
+
+#define TSR_ENW 0x80000000
+#define TSR_WIS 0x40000000
+
+#define BYTE_REVERSE16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
+#define BYTE_REVERSE32(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000))
+
+typedef struct {
+ UINT32 cr;
+ UINT32 da;
+ UINT32 sa;
+ UINT32 ct;
+ UINT32 cc;
+} DMA_REGS;
+
+typedef struct {
+ UINT8 spls;
+ UINT8 sphs;
+ UINT16 brd;
+ UINT8 spctl;
+ UINT8 sprc;
+ UINT8 sptc;
+ UINT8 sprb;
+ UINT8 sptb;
+ emu_timer *rx_timer;
+ emu_timer *tx_timer;
+} SPU_REGS;
+
+typedef union {
+ UINT64 id;
+ double fd;
+} FPR;
+
+typedef union {
+ UINT32 i;
+ float f;
+} FPR32;
+
+typedef struct {
+ UINT32 u;
+ UINT32 l;
+} BATENT;
+
+
+typedef struct {
+ UINT32 r[32];
+ UINT32 pc;
+ UINT32 npc;
+
+ UINT32 lr;
+ UINT32 ctr;
+ UINT32 xer;
+ UINT32 msr;
+ UINT8 cr[8];
+ UINT32 pvr;
+ UINT32 srr0;
+ UINT32 srr1;
+ UINT32 srr2;
+ UINT32 srr3;
+ UINT32 hid0;
+ UINT32 hid1;
+ UINT32 hid2;
+ UINT32 sdr1;
+ UINT32 sprg[4];
+
+ UINT32 dsisr;
+ UINT32 dar;
+ UINT32 ear;
+ UINT32 dmiss;
+ UINT32 dcmp;
+ UINT32 hash1;
+ UINT32 hash2;
+ UINT32 imiss;
+ UINT32 icmp;
+ UINT32 rpa;
+
+ BATENT ibat[4];
+ BATENT dbat[4];
+
+ UINT32 evpr;
+ UINT32 exier;
+ UINT32 exisr;
+ UINT32 bear;
+ UINT32 besr;
+ UINT32 iocr;
+ UINT32 br[8];
+ UINT32 iabr;
+ UINT32 esr;
+ UINT32 iccr;
+ UINT32 dccr;
+ UINT32 pit;
+ UINT32 tsr;
+ UINT32 tcr;
+ UINT32 dbsr;
+ UINT32 sgr;
+ UINT32 pid;
+ UINT32 pbl1, pbl2, pbu1, pbu2;
+ UINT32 fit_bit;
+ UINT32 fit_int_enable;
+ UINT32 wdt_bit;
+ UINT32 wdt_int_enable;
+ UINT32 dac1, dac2;
+ UINT32 iac1, iac2;
+
+ SPU_REGS spu;
+ DMA_REGS dma[4];
+ UINT32 dmasr;
+
+ int reserved;
+ UINT32 reserved_address;
+
+ int exception_pending;
+
+ UINT64 tb; /* 56-bit timebase register */
+
+ int (*irq_callback)(int irqline);
+ drc_core *drc;
+ UINT32 drcoptions;
+
+ x86code * invoke_exception_handler;
+ x86code * generate_interrupt_exception;
+ x86code * generate_syscall_exception;
+ x86code * generate_decrementer_exception;
+ x86code * generate_trap_exception;
+ x86code * generate_dsi_exception;
+ x86code * generate_isi_exception;
+ x86code * generate_fit_exception;
+
+ // PowerPC 60x specific registers */
+ UINT32 dec, dec_frac;
+ UINT32 fpscr;
+
+ FPR fpr[32];
+ UINT32 sr[16];
+
+ int is603;
+ int is602;
+
+ /* PowerPC 602 specific registers */
+ UINT32 lt;
+ UINT32 sp;
+ UINT32 ibr;
+ UINT32 esasrr;
+ UINT32 sebr;
+ UINT32 ser;
+
+ /* PowerPC function pointers for memory accesses/exceptions */
+ UINT8 (*read8)(offs_t address);
+ UINT16 (*read16)(offs_t address);
+ UINT32 (*read32)(offs_t address);
+ UINT64 (*read64)(offs_t address);
+ void (*write8)(offs_t address, UINT8 data);
+ void (*write16)(offs_t address, UINT16 data);
+ void (*write32)(offs_t address, UINT32 data);
+ void (*write64)(offs_t address, UINT64 data);
+ UINT16 (*read16_unaligned)(offs_t address);
+ UINT32 (*read32_unaligned)(offs_t address);
+ UINT64 (*read64_unaligned)(offs_t address);
+ void (*write16_unaligned)(offs_t address, UINT16 data);
+ void (*write32_unaligned)(offs_t address, UINT32 data);
+ void (*write64_unaligned)(offs_t address, UINT64 data);
+
+ /* saved ESP when entering entry point */
+ UINT32 host_esp;
+} PPC_REGS;
+
+
+
+typedef struct {
+ int code;
+ int subcode;
+ UINT32 (* handler)(drc_core *, UINT32);
+} PPC_OPCODE;
+
+
+/* code logging info */
+typedef struct _code_log_entry code_log_entry;
+struct _code_log_entry
+{
+ UINT32 pc;
+ UINT32 op;
+ void * base;
+};
+
+
+
+static int ppc_icount;
+static int ppc_tb_base_icount;
+static int ppc_dec_base_icount;
+static int ppc_dec_trigger_cycle;
+static int bus_freq_multiplier = 1;
+static int ppc_fit_trigger_cycle;
+static PPC_REGS ppc;
+static UINT32 ppc_rotate_mask[32][32];
+
+#define ROPCODE(pc) cpu_readop32(pc)
+#define ROPCODE64(pc) cpu_readop64(DWORD_XOR_BE(pc))
+
+INLINE void SET_CR0(INT32 rd)
+{
+ if( rd < 0 ) {
+ CR(0) = 0x8;
+ } else if( rd > 0 ) {
+ CR(0) = 0x4;
+ } else {
+ CR(0) = 0x2;
+ }
+
+ if( XER & XER_SO )
+ CR(0) |= 0x1;
+}
+
+INLINE void SET_CR1(void)
+{
+ CR(1) = (ppc.fpscr >> 28) & 0xf;
+}
+
+INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb)
+{
+ if( ADD_OV(rd, ra, rb) )
+ XER |= XER_SO | XER_OV;
+ else
+ XER &= ~XER_OV;
+}
+
+INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb)
+{
+ if( SUB_OV(rd, ra, rb) )
+ XER |= XER_SO | XER_OV;
+ else
+ XER &= ~XER_OV;
+}
+
+INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb)
+{
+ if( ADD_CA(rd, ra, rb) )
+ XER |= XER_CA;
+ else
+ XER &= ~XER_CA;
+}
+
+INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb)
+{
+ if( SUB_CA(rd, ra, rb) )
+ XER |= XER_CA;
+ else
+ XER &= ~XER_CA;
+}
+
+INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi)
+{
+ UINT32 ctr_ok;
+ UINT32 condition_ok;
+ UINT32 bo0 = (bo & 0x10) ? 1 : 0;
+ UINT32 bo1 = (bo & 0x08) ? 1 : 0;
+ UINT32 bo2 = (bo & 0x04) ? 1 : 0;
+ UINT32 bo3 = (bo & 0x02) ? 1 : 0;
+
+ if( bo2 == 0 )
+ --CTR;
+
+ ctr_ok = bo2 | ((CTR != 0) ^ bo3);
+ condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1));
+
+ return ctr_ok && condition_ok;
+}
+
+INLINE UINT64 ppc_read_timebase(void)
+{
+ int cycles = ppc_tb_base_icount - ppc_icount;
+
+ if (ppc.is603 || ppc.is602)
+ {
+ // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly
+ return ppc.tb + (cycles / 4);
+ }
+ else
+ {
+ // timebase is incremented once every core cycle on PPC403
+ return ppc.tb + cycles;
+ }
+}
+
+INLINE void ppc_write_timebase_l(UINT32 tbl)
+{
+ ppc_tb_base_icount = ppc_icount;
+
+ ppc.tb &= ~0xffffffff;
+ ppc.tb |= tbl;
+}
+
+INLINE void ppc_write_timebase_h(UINT32 tbh)
+{
+ ppc_tb_base_icount = ppc_icount;
+
+ ppc.tb &= 0xffffffff;
+ ppc.tb |= (UINT64)(tbh) << 32;
+}
+
+INLINE UINT32 read_decrementer(void)
+{
+ int cycles = ppc_dec_base_icount - ppc_icount;
+
+ // decrementer is decremented once every four bus clock cycles, so adjust the cycles accordingly
+ return DEC - (cycles / (bus_freq_multiplier * 2));
+}
+
+INLINE void write_decrementer(UINT32 value)
+{
+ ppc_dec_base_icount = ppc_icount + (ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2);
+
+ DEC = value;
+
+ // check if decrementer exception occurs during execution
+ if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC))
+ {
+ ppc_dec_trigger_cycle = ppc_icount - DEC;
+ }
+ else
+ {
+ ppc_dec_trigger_cycle = 0x7fffffff;
+ }
+}
+
+/*********************************************************************/
+
+INLINE void ppc_exception(int exception_type)
+{
+ void *exception_code = NULL;
+ void (*invoke_exception_handler)(void *handler);
+
+ switch(exception_type)
+ {
+ case EXCEPTION_DECREMENTER:
+ exception_code = ppc.generate_decrementer_exception;
+ break;
+ case EXCEPTION_DSI:
+ exception_code = ppc.generate_dsi_exception;
+ break;
+ case EXCEPTION_ISI:
+ exception_code = ppc.generate_isi_exception;
+ break;
+ default:
+ fatalerror("Unknown exception %d", exception_type);
+ break;
+ }
+
+ memcpy(&invoke_exception_handler, &ppc.invoke_exception_handler, sizeof(invoke_exception_handler));
+ invoke_exception_handler(exception_code);
+}
+
+/*********************************************************************/
+
+INLINE void ppc_set_spr(int spr, UINT32 value)
+{
+ switch (spr)
+ {
+ case SPR_LR: LR = value; return;
+ case SPR_CTR: CTR = value; return;
+ case SPR_XER: XER = value; return;
+ case SPR_SRR0: ppc.srr0 = value; return;
+ case SPR_SRR1: ppc.srr1 = value; return;
+ case SPR_SPRG0: ppc.sprg[0] = value; return;
+ case SPR_SPRG1: ppc.sprg[1] = value; return;
+ case SPR_SPRG2: ppc.sprg[2] = value; return;
+ case SPR_SPRG3: ppc.sprg[3] = value; return;
+ case SPR_PVR: return;
+ }
+
+#if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601)
+ if(ppc.is603 || ppc.is602) {
+ switch(spr)
+ {
+ case SPR603E_DEC:
+ if((value & 0x80000000) && !(DEC & 0x80000000))
+ {
+ /* trigger interrupt */
+ if( MSR & MSR_EE )
+ ppc_exception(EXCEPTION_DECREMENTER);
+ }
+ write_decrementer(value);
+ return;
+
+ case SPR603E_TBL_W:
+ case SPR603E_TBL_R: // special 603e case
+ ppc_write_timebase_l(value);
+ return;
+
+ case SPR603E_TBU_R:
+ case SPR603E_TBU_W: // special 603e case
+ ppc_write_timebase_h(value);
+ return;
+
+ case SPR603E_HID0:
+ ppc.hid0 = value;
+ return;
+
+ case SPR603E_HID1:
+ ppc.hid1 = value;
+ return;
+
+ case SPR603E_HID2:
+ ppc.hid1 = value;
+ return;
+
+ case SPR603E_DSISR: ppc.dsisr = value; return;
+ case SPR603E_DAR: ppc.dar = value; return;
+ case SPR603E_EAR: ppc.ear = value; return;
+ case SPR603E_DMISS: ppc.dmiss = value; return;
+ case SPR603E_DCMP: ppc.dcmp = value; return;
+ case SPR603E_HASH1: ppc.hash1 = value; return;
+ case SPR603E_HASH2: ppc.hash2 = value; return;
+ case SPR603E_IMISS: ppc.imiss = value; return;
+ case SPR603E_ICMP: ppc.icmp = value; return;
+ case SPR603E_RPA: ppc.rpa = value; return;
+
+ case SPR603E_IBAT0L: ppc.ibat[0].l = value; return;
+ case SPR603E_IBAT0U: ppc.ibat[0].u = value; return;
+ case SPR603E_IBAT1L: ppc.ibat[1].l = value; return;
+ case SPR603E_IBAT1U: ppc.ibat[1].u = value; return;
+ case SPR603E_IBAT2L: ppc.ibat[2].l = value; return;
+ case SPR603E_IBAT2U: ppc.ibat[2].u = value; return;
+ case SPR603E_IBAT3L: ppc.ibat[3].l = value; return;
+ case SPR603E_IBAT3U: ppc.ibat[3].u = value; return;
+ case SPR603E_DBAT0L: ppc.dbat[0].l = value; return;
+ case SPR603E_DBAT0U: ppc.dbat[0].u = value; return;
+ case SPR603E_DBAT1L: ppc.dbat[1].l = value; return;
+ case SPR603E_DBAT1U: ppc.dbat[1].u = value; return;
+ case SPR603E_DBAT2L: ppc.dbat[2].l = value; return;
+ case SPR603E_DBAT2U: ppc.dbat[2].u = value; return;
+ case SPR603E_DBAT3L: ppc.dbat[3].l = value; return;
+ case SPR603E_DBAT3U: ppc.dbat[3].u = value; return;
+
+ case SPR603E_SDR1:
+ ppc.sdr1 = value;
+ return;
+
+ case SPR603E_IABR: ppc.iabr = value; return;
+ }
+ }
+#endif
+
+#if (HAS_PPC602)
+ if (ppc.is602) {
+ switch(spr)
+ {
+ case SPR602_LT: ppc.lt = value; return;
+ case SPR602_IBR: ppc.ibr = value; return;
+ case SPR602_SP: ppc.sp = value; return;
+ case SPR602_SEBR: ppc.sebr = value; return;
+ case SPR602_SER: ppc.ser = value; return;
+ case SPR602_TCR: ppc.tcr = value; return;
+ }
+ }
+#endif
+
+#if (HAS_PPC403)
+ if (!ppc.is603 && !ppc.is602) {
+ switch(spr)
+ {
+ case SPR403_TBHI: ppc_write_timebase_h(value); return;
+ case SPR403_TBLO: ppc_write_timebase_l(value); return;
+
+ case SPR403_TSR:
+ ppc.tsr &= ~value; // 1 clears, 0 does nothing
+ return;
+
+ case SPR403_TCR:
+ switch((value >> 24) & 0x3)
+ {
+ case 0: ppc.fit_bit = 1 << 8; break;
+ case 1: ppc.fit_bit = 1 << 12; break;
+ case 2: ppc.fit_bit = 1 << 16; break;
+ case 3: ppc.fit_bit = 1 << 20; break;
+ }
+ switch((value >> 30) & 0x3)
+ {
+ case 0: ppc.wdt_bit = 1 << 16; break;
+ case 1: ppc.wdt_bit = 1 << 20; break;
+ case 2: ppc.wdt_bit = 1 << 24; break;
+ case 3: ppc.wdt_bit = 1 << 28; break;
+ }
+ ppc.fit_int_enable = (value >> 23) & 0x1;
+ ppc.wdt_int_enable = (value >> 27) & 0x1;
+ ppc.tcr = value;
+
+ if (!ppc.fit_int_enable)
+ {
+ ppc.exception_pending &= ~0x4;
+ }
+ return;
+
+ case SPR403_ESR: ppc.esr = value; return;
+ case SPR403_ICCR: ppc.iccr = value; return;
+ case SPR403_DCCR: ppc.dccr = value; return;
+ case SPR403_EVPR: EVPR = value & 0xffff0000; return;
+ case SPR403_PIT: ppc.pit = value; return;
+ case SPR403_SGR: ppc.sgr = value; return;
+ case SPR403_DBSR: ppc.dbsr = value; return;
+ case SPR403_DCWR: return;
+ case SPR403_PID: ppc.pid = value; return;
+ case SPR403_PBL1: ppc.pbl1 = value; return;
+ case SPR403_PBU1: ppc.pbu1 = value; return;
+ case SPR403_PBL2: ppc.pbl2 = value; return;
+ case SPR403_PBU2: ppc.pbu2 = value; return;
+ case SPR403_SRR2: ppc.srr2 = value; return;
+ case SPR403_SRR3: ppc.srr3 = value; return;
+ case SPR403_DAC1: ppc.dac1 = value; return;
+ case SPR403_DAC2: ppc.dac2 = value; return;
+ case SPR403_IAC1: ppc.iac1 = value; return;
+ case SPR403_IAC2: ppc.iac2 = value; return;
+ }
+ }
+#endif
+
+ fatalerror("ppc: set_spr: unknown spr %d (%03X) !", spr, spr);
+}
+
+INLINE UINT32 ppc_get_spr(int spr)
+{
+ switch(spr)
+ {
+ case SPR_LR: return LR;
+ case SPR_CTR: return CTR;
+ case SPR_XER: return XER;
+ case SPR_SRR0: return ppc.srr0;
+ case SPR_SRR1: return ppc.srr1;
+ case SPR_SPRG0: return ppc.sprg[0];
+ case SPR_SPRG1: return ppc.sprg[1];
+ case SPR_SPRG2: return ppc.sprg[2];
+ case SPR_SPRG3: return ppc.sprg[3];
+ case SPR_PVR: return ppc.pvr;
+ }
+
+#if (HAS_PPC403)
+ if (!ppc.is603 && !ppc.is602)
+ {
+ switch (spr)
+ {
+ case SPR403_TBLU:
+ case SPR403_TBLO: return (UINT32)(ppc_read_timebase());
+ case SPR403_TBHU:
+ case SPR403_TBHI: return (UINT32)(ppc_read_timebase() >> 32);
+
+ case SPR403_EVPR: return EVPR;
+ case SPR403_ESR: return ppc.esr;
+ case SPR403_TCR: return ppc.tcr;
+ case SPR403_ICCR: return ppc.iccr;
+ case SPR403_DCCR: return ppc.dccr;
+ case SPR403_PIT: return ppc.pit;
+ case SPR403_DBSR: return ppc.dbsr;
+ case SPR403_SGR: return ppc.sgr;
+ case SPR403_TSR: return ppc.tsr;
+ case SPR403_PBL1: return ppc.pbl1;
+ case SPR403_PBU1: return ppc.pbu1;
+ case SPR403_PBL2: return ppc.pbl2;
+ case SPR403_PBU2: return ppc.pbu2;
+ case SPR403_SRR2: return ppc.srr2;
+ case SPR403_SRR3: return ppc.srr3;
+ case SPR403_DAC1: return ppc.dac1;
+ case SPR403_DAC2: return ppc.dac2;
+ case SPR403_IAC1: return ppc.iac1;
+ case SPR403_IAC2: return ppc.iac2;
+ }
+ }
+#endif
+
+#if (HAS_PPC602)
+ if (ppc.is602) {
+ switch(spr)
+ {
+ case SPR602_LT: return ppc.lt;
+ case SPR602_IBR: return ppc.ibr;
+ case SPR602_ESASRR: return ppc.esasrr;
+ case SPR602_SEBR: return ppc.sebr;
+ case SPR602_SER: return ppc.ser;
+ case SPR602_SP: return ppc.sp;
+ case SPR602_TCR: return ppc.tcr;
+ }
+ }
+#endif
+
+#if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601)
+ if (ppc.is603 || ppc.is602)
+ {
+ switch (spr)
+ {
+ case SPR603E_TBL_R:
+ fatalerror("ppc: get_spr: TBL_R ");
+ break;
+
+ case SPR603E_TBU_R:
+ fatalerror("ppc: get_spr: TBU_R ");
+ break;
+
+ case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase());
+ case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32);
+ case SPR603E_HID0: return ppc.hid0;
+ case SPR603E_HID1: return ppc.hid1;
+ case SPR603E_HID2: return ppc.hid2;
+ case SPR603E_DEC: return read_decrementer();
+ case SPR603E_SDR1: return ppc.sdr1;
+ case SPR603E_DSISR: return ppc.dsisr;
+ case SPR603E_DAR: return ppc.dar;
+ case SPR603E_EAR: return ppc.ear;
+ case SPR603E_IBAT0L: return ppc.ibat[0].l;
+ case SPR603E_IBAT0U: return ppc.ibat[0].u;
+ case SPR603E_IBAT1L: return ppc.ibat[1].l;
+ case SPR603E_IBAT1U: return ppc.ibat[1].u;
+ case SPR603E_IBAT2L: return ppc.ibat[2].l;
+ case SPR603E_IBAT2U: return ppc.ibat[2].u;
+ case SPR603E_IBAT3L: return ppc.ibat[3].l;
+ case SPR603E_IBAT3U: return ppc.ibat[3].u;
+ case SPR603E_DBAT0L: return ppc.dbat[0].l;
+ case SPR603E_DBAT0U: return ppc.dbat[0].u;
+ case SPR603E_DBAT1L: return ppc.dbat[1].l;
+ case SPR603E_DBAT1U: return ppc.dbat[1].u;
+ case SPR603E_DBAT2L: return ppc.dbat[2].l;
+ case SPR603E_DBAT2U: return ppc.dbat[2].u;
+ case SPR603E_DBAT3L: return ppc.dbat[3].l;
+ case SPR603E_DBAT3U: return ppc.dbat[3].u;
+ }
+ }
+#endif
+
+ fatalerror("ppc: get_spr: unknown spr %d (%03X) !", spr, spr);
+ return 0;
+}
+
+static UINT8 ppc_read8_translated(offs_t address);
+static UINT16 ppc_read16_translated(offs_t address);
+static UINT32 ppc_read32_translated(offs_t address);
+static UINT64 ppc_read64_translated(offs_t address);
+static void ppc_write8_translated(offs_t address, UINT8 data);
+static void ppc_write16_translated(offs_t address, UINT16 data);
+static void ppc_write32_translated(offs_t address, UINT32 data);
+static void ppc_write64_translated(offs_t address, UINT64 data);
+
+INLINE void ppc_set_msr(UINT32 value)
+{
+ if( value & (MSR_ILE | MSR_LE) )
+ fatalerror("ppc: set_msr: little_endian mode not supported !");
+
+ MSR = value;
+
+ if (ppc.is603 || ppc.is602)
+ {
+ if (!(MSR & MSR_DR))
+ {
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ }
+ else
+ {
+ ppc.read8 = ppc_read8_translated;
+ ppc.read16 = ppc_read16_translated;
+ ppc.read32 = ppc_read32_translated;
+ ppc.read64 = ppc_read64_translated;
+ ppc.write8 = ppc_write8_translated;
+ ppc.write16 = ppc_write16_translated;
+ ppc.write32 = ppc_write32_translated;
+ ppc.write64 = ppc_write64_translated;
+ }
+ }
+}
+
+INLINE UINT32 ppc_get_msr(void)
+{
+ return MSR;
+}
+
+INLINE void ppc_set_cr(UINT32 value)
+{
+ CR(0) = (value >> 28) & 0xf;
+ CR(1) = (value >> 24) & 0xf;
+ CR(2) = (value >> 20) & 0xf;
+ CR(3) = (value >> 16) & 0xf;
+ CR(4) = (value >> 12) & 0xf;
+ CR(5) = (value >> 8) & 0xf;
+ CR(6) = (value >> 4) & 0xf;
+ CR(7) = (value >> 0) & 0xf;
+}
+
+INLINE UINT32 ppc_get_cr(void)
+{
+ return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7);
+}
+
+#ifdef UNUSED_FUNCTION
+static void log_code(drc_core *drc)
+{
+#if LOG_CODE
+ FILE *temp;
+ temp = fopen("code.bin", "wb");
+ fwrite(drc->cache_base, 1, drc->cache_top - drc->cache_base, temp);
+ fclose(temp);
+#endif
+}
+#endif
+
+/***********************************************************************/
+
+static UINT32 (* optable19[1024])(drc_core *, UINT32);
+static UINT32 (* optable31[1024])(drc_core *, UINT32);
+static UINT32 (* optable59[1024])(drc_core *, UINT32);
+static UINT32 (* optable63[1024])(drc_core *, UINT32);
+static UINT32 (* optable[64])(drc_core *, UINT32);
+
+#include "ppc_mem.c"
+
+#if (HAS_PPC403)
+#include "ppc403.c"
+#endif
+
+#if (HAS_PPC602)
+#include "ppc602.c"
+#endif
+
+/***************************************************************************
+ CODE LOGGING
+***************************************************************************/
+
+#if LOG_CODE
+
+static code_log_entry code_log_buffer[MAX_INSTRUCTIONS*2];
+static int code_log_index;
+static FILE *logfile;
+
+
+/*-------------------------------------------------
+ open_logfile - open the log file if it is
+ not already opened
+-------------------------------------------------*/
+
+INLINE int open_logfile(void)
+{
+ if (logfile == NULL)
+ logfile = fopen("ppcdrc.asm", "w");
+ return (logfile != NULL);
+}
+
+
+/*-------------------------------------------------
+ code_log_reset - reset the logging index
+-------------------------------------------------*/
+
+INLINE void code_log_reset(void)
+{
+ code_log_index = 0;
+}
+
+
+/*-------------------------------------------------
+ code_log_add_entry - add an entry to the log
+-------------------------------------------------*/
+
+INLINE void code_log_add_entry(UINT32 pc, UINT32 op, void *base)
+{
+ code_log_buffer[code_log_index].pc = pc;
+ code_log_buffer[code_log_index].op = op;
+ code_log_buffer[code_log_index].base = base;
+ code_log_index++;
+}
+
+
+/*-------------------------------------------------
+ code_log - actually log some code
+-------------------------------------------------*/
+
+static void code_log(const char *label, x86code *start, x86code *stop)
+{
+ extern int i386_dasm_one(char *buffer, UINT32 eip, UINT8 *oprom, int mode);
+ offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op);
+ UINT8 *cur = start;
+
+ /* open the file, creating it if necessary */
+ if (!open_logfile())
+ return;
+ fprintf(logfile, "\n%s\n", label);
+
+ /* loop from the start until the cache top */
+ while (cur < stop)
+ {
+ char buffer[100];
+ int bytes;
+ int op;
+
+ /* skip filler opcodes */
+ if (*cur == 0xcc)
+ {
+ cur++;
+ continue;
+ }
+
+ /* disassemble this instruction */
+#ifdef PTR64
+ bytes = i386_dasm_one(buffer, (UINT32)(FPTR)cur, cur, 64) & DASMFLAG_LENGTHMASK;
+#else
+ bytes = i386_dasm_one(buffer, (UINT32)cur, cur, 32) & DASMFLAG_LENGTHMASK;
+#endif
+
+ /* look for a match in the registered opcodes */
+ for (op = 0; op < code_log_index; op++)
+ if (code_log_buffer[op].base == (void *)cur)
+ break;
+
+ /* if no match, just output the current instruction */
+ if (op == code_log_index)
+ fprintf(logfile, "%p: %s\n", cur, buffer);
+
+ /* otherwise, output with the original instruction to the right */
+ else
+ {
+ char buffer2[100];
+ ppc_dasm_one(buffer2, code_log_buffer[op].pc, code_log_buffer[op].op);
+ fprintf(logfile, "%p: %-50s %08X: %s\n", cur, buffer, code_log_buffer[op].pc, buffer2);
+ }
+
+ /* advance past this instruction */
+ cur += bytes;
+ }
+
+ /* flush the file */
+ fflush(logfile);
+}
+
+#else
+
+#define code_log_reset()
+#define code_log_add_entry(a,b,c)
+#define code_log(a,b,c)
+
+#endif
+
+
+/********************************************************************/
+
+#include "ppc_ops.c"
+#include "drc_ops.c"
+#include "drc_ops.h"
+
+/* Initialization and shutdown */
+
+void ppc_init(void)
+{
+ int i,j;
+
+ for( i=0; i < 64; i++ ) {
+ optable[i] = recompile_invalid;
+ }
+ for( i=0; i < 1024; i++ ) {
+ optable19[i] = recompile_invalid;
+ optable31[i] = recompile_invalid;
+ optable59[i] = recompile_invalid;
+ optable63[i] = recompile_invalid;
+ }
+
+ /* Fill the opcode tables */
+ for( i=0; i < (sizeof(ppcdrc_opcode_common) / sizeof(PPC_OPCODE)); i++ ) {
+
+ switch(ppcdrc_opcode_common[i].code)
+ {
+ case 19:
+ optable19[ppcdrc_opcode_common[i].subcode] = ppcdrc_opcode_common[i].handler;
+ break;
+
+ case 31:
+ optable31[ppcdrc_opcode_common[i].subcode] = ppcdrc_opcode_common[i].handler;
+ break;
+
+ case 59:
+ case 63:
+ break;
+
+ default:
+ optable[ppcdrc_opcode_common[i].code] = ppcdrc_opcode_common[i].handler;
+ }
+
+ }
+
+ /* Calculate rotate mask table */
+ for( i=0; i < 32; i++ ) {
+ for( j=0; j < 32; j++ ) {
+ UINT32 mask;
+ int mb = i;
+ int me = j;
+ mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1)));
+ if( mb > me )
+ mask = ~mask;
+
+ ppc_rotate_mask[i][j] = mask;
+ }
+ }
+}
+
+#if (HAS_PPC403)
+static void ppcdrc403_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const ppc_config *config = _config;
+
+ ppc_init();
+ ppcdrc_init();
+
+ /* PPC403 specific opcodes */
+ optable31[454] = recompile_dccci;
+ optable31[486] = recompile_dcread;
+ optable31[262] = recompile_icbt;
+ optable31[966] = recompile_iccci;
+ optable31[998] = recompile_icread;
+ optable31[323] = recompile_mfdcr;
+ optable31[451] = recompile_mtdcr;
+ optable31[131] = recompile_wrtee;
+ optable31[163] = recompile_wrteei;
+ optable19[51] = recompile_rfci;
+
+ ppc.spu.rx_timer = timer_alloc(ppc403_spu_rx_callback);
+ ppc.spu.tx_timer = timer_alloc(ppc403_spu_tx_callback);
+
+ ppc.is603 = 0;
+ ppc.is602 = 0;
+
+ ppc.read8 = ppc403_read8;
+ ppc.read16 = ppc403_read16;
+ ppc.read32 = ppc403_read32;
+ ppc.write8 = ppc403_write8;
+ ppc.write16 = ppc403_write16;
+ ppc.write32 = ppc403_write32;
+ ppc.read16_unaligned = ppc403_read16_unaligned;
+ ppc.read32_unaligned = ppc403_read32_unaligned;
+ ppc.write16_unaligned = ppc403_write16_unaligned;
+ ppc.write32_unaligned = ppc403_write32_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+}
+
+static void ppcdrc403_exit(void)
+{
+#if LOG_CODE
+ //if (symfile) fclose(symfile);
+#endif
+ drc_exit(ppc.drc);
+}
+
+static void ppcdrc403_reset(void)
+{
+ ppc.pc = ppc.npc = 0xfffffffc;
+
+ ppc_set_msr(0);
+ change_pc(ppc.pc);
+
+ /* reset the DRC */
+ drc_cache_reset(ppc.drc);
+}
+
+static int ppcdrc403_execute(int cycles)
+{
+ /* count cycles and interrupt cycles */
+ ppc_icount = cycles;
+ ppc_tb_base_icount = cycles;
+
+ ppc_fit_trigger_cycle = 0x7fffffff;
+
+ if (ppc.fit_int_enable)
+ {
+ UINT32 tb = (UINT32)ppc.tb;
+ UINT32 fit_cycles = 0;
+
+ if (ppc.tb & ppc.fit_bit)
+ {
+ fit_cycles += ppc.fit_bit;
+ tb += fit_cycles;
+ }
+
+ fit_cycles += ppc.fit_bit - (tb & (ppc.fit_bit-1));
+
+ ppc_fit_trigger_cycle = ppc_icount - fit_cycles;
+ }
+
+ drc_execute(ppc.drc);
+
+ // update timebase
+ ppc.tb += (ppc_tb_base_icount - ppc_icount);
+
+ return cycles - ppc_icount;
+}
+
+static void ppcdrc403_set_irq_line(int irqline, int state)
+{
+ if (irqline >= INPUT_LINE_IRQ0 && irqline <= INPUT_LINE_IRQ4)
+ {
+ UINT32 mask = (1 << (4 - irqline));
+ if( state == ASSERT_LINE) {
+ if (EXIER & mask)
+ {
+ ppc.exisr |= mask;
+ ppc.exception_pending |= 0x1;
+
+ if (ppc.irq_callback)
+ {
+ ppc.irq_callback(irqline);
+ }
+ }
+ }
+ // clear line is used to clear the interrupt when the interrupts are level-sensitive
+ else if (state == CLEAR_LINE)
+ {
+ ppc.exisr &= ~mask;
+ }
+ }
+ else if (irqline == PPC403_SPU_RX)
+ {
+ UINT32 mask = 0x08000000;
+ if (state) {
+ if( EXIER & mask ) {
+ ppc.exisr |= mask;
+ ppc.exception_pending |= 0x1;
+ }
+ }
+ }
+ else if (irqline == PPC403_SPU_TX)
+ {
+ UINT32 mask = 0x04000000;
+ if (state) {
+ if( EXIER & mask ) {
+ ppc.exisr |= mask;
+ ppc.exception_pending |= 0x1;
+ }
+ }
+ }
+ else
+ {
+ fatalerror("PPC: Unknown IRQ line %d", irqline);
+ }
+}
+#endif
+
+#if (HAS_PPC603)
+static void ppcdrc603_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ int pll_config = 0;
+ float multiplier;
+ const ppc_config *config = _config;
+ int i;
+
+ ppc_init();
+ ppcdrc_init();
+
+ optable[48] = recompile_lfs;
+ optable[49] = recompile_lfsu;
+ optable[50] = recompile_lfd;
+ optable[51] = recompile_lfdu;
+ optable[52] = recompile_stfs;
+ optable[53] = recompile_stfsu;
+ optable[54] = recompile_stfd;
+ optable[55] = recompile_stfdu;
+ optable31[631] = recompile_lfdux;
+ optable31[599] = recompile_lfdx;
+ optable31[567] = recompile_lfsux;
+ optable31[535] = recompile_lfsx;
+ optable31[595] = recompile_mfsr;
+ optable31[659] = recompile_mfsrin;
+ optable31[371] = recompile_mftb;
+ optable31[210] = recompile_mtsr;
+ optable31[242] = recompile_mtsrin;
+ optable31[758] = recompile_dcba;
+ optable31[759] = recompile_stfdux;
+ optable31[727] = recompile_stfdx;
+ optable31[983] = recompile_stfiwx;
+ optable31[695] = recompile_stfsux;
+ optable31[663] = recompile_stfsx;
+ optable31[370] = recompile_tlbia;
+ optable31[306] = recompile_tlbie;
+ optable31[566] = recompile_tlbsync;
+ optable31[310] = recompile_eciwx;
+ optable31[438] = recompile_ecowx;
+
+ optable63[264] = recompile_fabsx;
+ optable63[21] = recompile_faddx;
+ optable63[32] = recompile_fcmpo;
+ optable63[0] = recompile_fcmpu;
+ optable63[14] = recompile_fctiwx;
+ optable63[15] = recompile_fctiwzx;
+ optable63[18] = recompile_fdivx;
+ optable63[72] = recompile_fmrx;
+ optable63[136] = recompile_fnabsx;
+ optable63[40] = recompile_fnegx;
+ optable63[12] = recompile_frspx;
+ optable63[26] = recompile_frsqrtex;
+ optable63[22] = recompile_fsqrtx;
+ optable63[20] = recompile_fsubx;
+ optable63[583] = recompile_mffsx;
+ optable63[70] = recompile_mtfsb0x;
+ optable63[38] = recompile_mtfsb1x;
+ optable63[711] = recompile_mtfsfx;
+ optable63[134] = recompile_mtfsfix;
+ optable63[64] = recompile_mcrfs;
+
+ optable59[21] = recompile_faddsx;
+ optable59[18] = recompile_fdivsx;
+ optable59[24] = recompile_fresx;
+ optable59[22] = recompile_fsqrtsx;
+ optable59[20] = recompile_fsubsx;
+
+ for(i = 0; i < 32; i++)
+ {
+ optable63[i * 32 | 29] = recompile_fmaddx;
+ optable63[i * 32 | 28] = recompile_fmsubx;
+ optable63[i * 32 | 25] = recompile_fmulx;
+ optable63[i * 32 | 31] = recompile_fnmaddx;
+ optable63[i * 32 | 30] = recompile_fnmsubx;
+ optable63[i * 32 | 23] = recompile_fselx;
+
+ optable59[i * 32 | 29] = recompile_fmaddsx;
+ optable59[i * 32 | 28] = recompile_fmsubsx;
+ optable59[i * 32 | 25] = recompile_fmulsx;
+ optable59[i * 32 | 31] = recompile_fnmaddsx;
+ optable59[i * 32 | 30] = recompile_fnmsubsx;
+ }
+
+ for(i = 0; i < 256; i++)
+ {
+ ppc_field_xlat[i] =
+ ((i & 0x80) ? 0xF0000000 : 0) |
+ ((i & 0x40) ? 0x0F000000 : 0) |
+ ((i & 0x20) ? 0x00F00000 : 0) |
+ ((i & 0x10) ? 0x000F0000 : 0) |
+ ((i & 0x08) ? 0x0000F000 : 0) |
+ ((i & 0x04) ? 0x00000F00 : 0) |
+ ((i & 0x02) ? 0x000000F0 : 0) |
+ ((i & 0x01) ? 0x0000000F : 0);
+ }
+
+ ppc.is603 = 1;
+
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ ppc.read16_unaligned = ppc_read16_unaligned;
+ ppc.read32_unaligned = ppc_read32_unaligned;
+ ppc.read64_unaligned = ppc_read64_unaligned;
+ ppc.write16_unaligned = ppc_write16_unaligned;
+ ppc.write32_unaligned = ppc_write32_unaligned;
+ ppc.write64_unaligned = ppc_write64_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+
+ multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) +
+ (float)(config->bus_frequency_multiplier & 0xf) / 10.0f;
+ bus_freq_multiplier = (int)(multiplier * 2);
+
+ switch(config->pvr)
+ {
+ case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
+ case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
+ case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
+ default: break;
+ }
+
+ if (pll_config == -1)
+ {
+ fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier);
+ }
+
+ ppc.hid1 = pll_config << 28;
+}
+
+static void ppcdrc603_exit(void)
+{
+#if LOG_CODE
+ //if (symfile) fclose(symfile);
+#endif
+ drc_exit(ppc.drc);
+}
+#endif
+
+#if (HAS_PPC601 || HAS_PPC603 || HAS_MPC8240)
+static void ppcdrc603_reset(void)
+{
+ ppc.pc = ppc.npc = 0xfff00100;
+
+ ppc_set_msr(0x40);
+ change_pc(ppc.pc);
+
+ /* reset the DRC */
+ drc_cache_reset(ppc.drc);
+}
+
+static int ppcdrc603_execute(int cycles)
+{
+ /* count cycles and interrupt cycles */
+ ppc_icount = cycles;
+ ppc_tb_base_icount = cycles;
+ ppc_dec_base_icount = cycles + ppc.dec_frac;
+
+ // check if decrementer exception occurs during execution
+ if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC))
+ {
+ ppc_dec_trigger_cycle = ppc_icount - DEC;
+ }
+ else
+ {
+ ppc_dec_trigger_cycle = 0x7fffffff;
+ }
+
+ drc_execute(ppc.drc);
+
+ // update timebase
+ // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly
+ ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4);
+
+ // update decrementer
+ ppc.dec_frac = ((ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2));
+ DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2));
+
+ return cycles - ppc_icount;
+}
+
+static void ppcdrc603_set_irq_line(int irqline, int state)
+{
+ if( state ) {
+ ppc.exception_pending |= 0x1;
+ if (ppc.irq_callback)
+ {
+ ppc.irq_callback(irqline);
+ }
+ }
+}
+#endif
+
+#if (HAS_PPC602)
+static void ppcdrc602_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ float multiplier;
+ const ppc_config *config = _config;
+ int i;
+
+ ppc_init();
+ ppcdrc_init();
+
+ optable[48] = recompile_lfs;
+ optable[49] = recompile_lfsu;
+ optable[50] = recompile_lfd;
+ optable[51] = recompile_lfdu;
+ optable[52] = recompile_stfs;
+ optable[53] = recompile_stfsu;
+ optable[54] = recompile_stfd;
+ optable[55] = recompile_stfdu;
+ optable31[631] = recompile_lfdux;
+ optable31[599] = recompile_lfdx;
+ optable31[567] = recompile_lfsux;
+ optable31[535] = recompile_lfsx;
+ optable31[595] = recompile_mfsr;
+ optable31[659] = recompile_mfsrin;
+ optable31[371] = recompile_mftb;
+ optable31[210] = recompile_mtsr;
+ optable31[242] = recompile_mtsrin;
+ optable31[758] = recompile_dcba;
+ optable31[759] = recompile_stfdux;
+ optable31[727] = recompile_stfdx;
+ optable31[983] = recompile_stfiwx;
+ optable31[695] = recompile_stfsux;
+ optable31[663] = recompile_stfsx;
+ optable31[370] = recompile_tlbia;
+ optable31[306] = recompile_tlbie;
+ optable31[566] = recompile_tlbsync;
+ optable31[310] = recompile_eciwx;
+ optable31[438] = recompile_ecowx;
+
+ optable63[264] = recompile_fabsx;
+ optable63[21] = recompile_faddx;
+ optable63[32] = recompile_fcmpo;
+ optable63[0] = recompile_fcmpu;
+ optable63[14] = recompile_fctiwx;
+ optable63[15] = recompile_fctiwzx;
+ optable63[18] = recompile_fdivx;
+ optable63[72] = recompile_fmrx;
+ optable63[136] = recompile_fnabsx;
+ optable63[40] = recompile_fnegx;
+ optable63[12] = recompile_frspx;
+ optable63[26] = recompile_frsqrtex;
+ optable63[22] = recompile_fsqrtx;
+ optable63[20] = recompile_fsubx;
+ optable63[583] = recompile_mffsx;
+ optable63[70] = recompile_mtfsb0x;
+ optable63[38] = recompile_mtfsb1x;
+ optable63[711] = recompile_mtfsfx;
+ optable63[134] = recompile_mtfsfix;
+ optable63[64] = recompile_mcrfs;
+
+ optable59[21] = recompile_faddsx;
+ optable59[18] = recompile_fdivsx;
+ optable59[24] = recompile_fresx;
+ optable59[22] = recompile_fsqrtsx;
+ optable59[20] = recompile_fsubsx;
+
+ for(i = 0; i < 32; i++)
+ {
+ optable63[i * 32 | 29] = recompile_fmaddx;
+ optable63[i * 32 | 28] = recompile_fmsubx;
+ optable63[i * 32 | 25] = recompile_fmulx;
+ optable63[i * 32 | 31] = recompile_fnmaddx;
+ optable63[i * 32 | 30] = recompile_fnmsubx;
+ optable63[i * 32 | 23] = recompile_fselx;
+
+ optable59[i * 32 | 29] = recompile_fmaddsx;
+ optable59[i * 32 | 28] = recompile_fmsubsx;
+ optable59[i * 32 | 25] = recompile_fmulsx;
+ optable59[i * 32 | 31] = recompile_fnmaddsx;
+ optable59[i * 32 | 30] = recompile_fnmsubsx;
+ }
+
+ for(i = 0; i < 256; i++)
+ {
+ ppc_field_xlat[i] =
+ ((i & 0x80) ? 0xF0000000 : 0) |
+ ((i & 0x40) ? 0x0F000000 : 0) |
+ ((i & 0x20) ? 0x00F00000 : 0) |
+ ((i & 0x10) ? 0x000F0000 : 0) |
+ ((i & 0x08) ? 0x0000F000 : 0) |
+ ((i & 0x04) ? 0x00000F00 : 0) |
+ ((i & 0x02) ? 0x000000F0 : 0) |
+ ((i & 0x01) ? 0x0000000F : 0);
+ }
+
+ // PPC602 specific opcodes
+ optable31[596] = recompile_esa;
+ optable31[628] = recompile_dsa;
+ optable31[1010] = recompile_tlbli;
+ optable31[978] = recompile_tlbld;
+
+ ppc.is603 = 0;
+ ppc.is602 = 1;
+
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ ppc.read16_unaligned = ppc_read16_unaligned;
+ ppc.read32_unaligned = ppc_read32_unaligned;
+ ppc.read64_unaligned = ppc_read64_unaligned;
+ ppc.write16_unaligned = ppc_write16_unaligned;
+ ppc.write32_unaligned = ppc_write32_unaligned;
+ ppc.write64_unaligned = ppc_write64_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+
+ multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) +
+ (float)(config->bus_frequency_multiplier & 0xf) / 10.0f;
+ bus_freq_multiplier = (int)(multiplier * 2);
+}
+
+static void ppcdrc602_exit(void)
+{
+#if LOG_CODE
+ //if (symfile) fclose(symfile);
+#endif
+ drc_exit(ppc.drc);
+}
+
+static void ppcdrc602_reset(void)
+{
+ ppc.pc = ppc.npc = 0xfff00100;
+
+ ppc_set_msr(0x40);
+ change_pc(ppc.pc);
+
+ ppc.hid0 = 1;
+
+ /* reset the DRC */
+ drc_cache_reset(ppc.drc);
+}
+
+static int ppcdrc602_execute(int cycles)
+{
+ /* count cycles and interrupt cycles */
+ ppc_icount = cycles;
+ ppc_tb_base_icount = cycles;
+ ppc_dec_base_icount = cycles;
+
+ // check if decrementer exception occurs during execution
+ if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC))
+ {
+ ppc_dec_trigger_cycle = ppc_icount - DEC;
+ }
+ else
+ {
+ ppc_dec_trigger_cycle = 0x7fffffff;
+ }
+
+ drc_execute(ppc.drc);
+
+ // update timebase
+ // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly
+ ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4);
+
+ // update decrementer
+ DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2));
+
+ return cycles - ppc_icount;
+}
+
+static void ppcdrc602_set_irq_line(int irqline, int state)
+{
+ if( state ) {
+ ppc.exception_pending |= 0x1;
+ if (ppc.irq_callback)
+ {
+ ppc.irq_callback(irqline);
+ }
+ }
+}
+#endif
+
+#if (HAS_MPC8240)
+static void mpc8240drc_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ float multiplier;
+ const ppc_config *config = _config;
+ int i;
+
+ ppc_init();
+ ppcdrc_init();
+
+ optable[48] = recompile_lfs;
+ optable[49] = recompile_lfsu;
+ optable[50] = recompile_lfd;
+ optable[51] = recompile_lfdu;
+ optable[52] = recompile_stfs;
+ optable[53] = recompile_stfsu;
+ optable[54] = recompile_stfd;
+ optable[55] = recompile_stfdu;
+ optable31[631] = recompile_lfdux;
+ optable31[599] = recompile_lfdx;
+ optable31[567] = recompile_lfsux;
+ optable31[535] = recompile_lfsx;
+ optable31[595] = recompile_mfsr;
+ optable31[659] = recompile_mfsrin;
+ optable31[371] = recompile_mftb;
+ optable31[210] = recompile_mtsr;
+ optable31[242] = recompile_mtsrin;
+ optable31[758] = recompile_dcba;
+ optable31[759] = recompile_stfdux;
+ optable31[727] = recompile_stfdx;
+ optable31[983] = recompile_stfiwx;
+ optable31[695] = recompile_stfsux;
+ optable31[663] = recompile_stfsx;
+ optable31[370] = recompile_tlbia;
+ optable31[306] = recompile_tlbie;
+ optable31[566] = recompile_tlbsync;
+ optable31[310] = recompile_eciwx;
+ optable31[438] = recompile_ecowx;
+
+ optable63[264] = recompile_fabsx;
+ optable63[21] = recompile_faddx;
+ optable63[32] = recompile_fcmpo;
+ optable63[0] = recompile_fcmpu;
+ optable63[14] = recompile_fctiwx;
+ optable63[15] = recompile_fctiwzx;
+ optable63[18] = recompile_fdivx;
+ optable63[72] = recompile_fmrx;
+ optable63[136] = recompile_fnabsx;
+ optable63[40] = recompile_fnegx;
+ optable63[12] = recompile_frspx;
+ optable63[26] = recompile_frsqrtex;
+ optable63[22] = recompile_fsqrtx;
+ optable63[20] = recompile_fsubx;
+ optable63[583] = recompile_mffsx;
+ optable63[70] = recompile_mtfsb0x;
+ optable63[38] = recompile_mtfsb1x;
+ optable63[711] = recompile_mtfsfx;
+ optable63[134] = recompile_mtfsfix;
+ optable63[64] = recompile_mcrfs;
+
+ optable59[21] = recompile_faddsx;
+ optable59[18] = recompile_fdivsx;
+ optable59[24] = recompile_fresx;
+ optable59[22] = recompile_fsqrtsx;
+ optable59[20] = recompile_fsubsx;
+
+ for(i = 0; i < 32; i++)
+ {
+ optable63[i * 32 | 29] = recompile_fmaddx;
+ optable63[i * 32 | 28] = recompile_fmsubx;
+ optable63[i * 32 | 25] = recompile_fmulx;
+ optable63[i * 32 | 31] = recompile_fnmaddx;
+ optable63[i * 32 | 30] = recompile_fnmsubx;
+ optable63[i * 32 | 23] = recompile_fselx;
+
+ optable59[i * 32 | 29] = recompile_fmaddsx;
+ optable59[i * 32 | 28] = recompile_fmsubsx;
+ optable59[i * 32 | 25] = recompile_fmulsx;
+ optable59[i * 32 | 31] = recompile_fnmaddsx;
+ optable59[i * 32 | 30] = recompile_fnmsubsx;
+ }
+
+ for(i = 0; i < 256; i++)
+ {
+ ppc_field_xlat[i] =
+ ((i & 0x80) ? 0xF0000000 : 0) |
+ ((i & 0x40) ? 0x0F000000 : 0) |
+ ((i & 0x20) ? 0x00F00000 : 0) |
+ ((i & 0x10) ? 0x000F0000 : 0) |
+ ((i & 0x08) ? 0x0000F000 : 0) |
+ ((i & 0x04) ? 0x00000F00 : 0) |
+ ((i & 0x02) ? 0x000000F0 : 0) |
+ ((i & 0x01) ? 0x0000000F : 0);
+ }
+
+ // MPC8240 specific opcodes
+ optable31[978] = recompile_tlbld;
+ optable31[1010] = recompile_tlbli;
+
+ ppc.is603 = 1;
+
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ ppc.read16_unaligned = ppc_read16_unaligned;
+ ppc.read32_unaligned = ppc_read32_unaligned;
+ ppc.read64_unaligned = ppc_read64_unaligned;
+ ppc.write16_unaligned = ppc_write16_unaligned;
+ ppc.write32_unaligned = ppc_write32_unaligned;
+ ppc.write64_unaligned = ppc_write64_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+
+ multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) +
+ (float)(config->bus_frequency_multiplier & 0xf) / 10.0f;
+ bus_freq_multiplier = (int)(multiplier * 2);
+}
+
+static void mpc8240drc_exit(void)
+{
+
+}
+#endif
+
+
+#if (HAS_PPC601)
+static void ppc601drc_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ int pll_config = 0;
+ float multiplier;
+ const ppc_config *config = _config;
+ int i;
+
+ ppc_init();
+ ppcdrc_init();
+
+ optable[48] = recompile_lfs;
+ optable[49] = recompile_lfsu;
+ optable[50] = recompile_lfd;
+ optable[51] = recompile_lfdu;
+ optable[52] = recompile_stfs;
+ optable[53] = recompile_stfsu;
+ optable[54] = recompile_stfd;
+ optable[55] = recompile_stfdu;
+ optable31[631] = recompile_lfdux;
+ optable31[599] = recompile_lfdx;
+ optable31[567] = recompile_lfsux;
+ optable31[535] = recompile_lfsx;
+ optable31[595] = recompile_mfsr;
+ optable31[659] = recompile_mfsrin;
+ optable31[371] = recompile_mftb;
+ optable31[210] = recompile_mtsr;
+ optable31[242] = recompile_mtsrin;
+ optable31[758] = recompile_dcba;
+ optable31[759] = recompile_stfdux;
+ optable31[727] = recompile_stfdx;
+ optable31[983] = recompile_stfiwx;
+ optable31[695] = recompile_stfsux;
+ optable31[663] = recompile_stfsx;
+ optable31[370] = recompile_tlbia;
+ optable31[306] = recompile_tlbie;
+ optable31[566] = recompile_tlbsync;
+ optable31[310] = recompile_eciwx;
+ optable31[438] = recompile_ecowx;
+
+ optable63[264] = recompile_fabsx;
+ optable63[21] = recompile_faddx;
+ optable63[32] = recompile_fcmpo;
+ optable63[0] = recompile_fcmpu;
+ optable63[14] = recompile_fctiwx;
+ optable63[15] = recompile_fctiwzx;
+ optable63[18] = recompile_fdivx;
+ optable63[72] = recompile_fmrx;
+ optable63[136] = recompile_fnabsx;
+ optable63[40] = recompile_fnegx;
+ optable63[12] = recompile_frspx;
+ optable63[26] = recompile_frsqrtex;
+ optable63[22] = recompile_fsqrtx;
+ optable63[20] = recompile_fsubx;
+ optable63[583] = recompile_mffsx;
+ optable63[70] = recompile_mtfsb0x;
+ optable63[38] = recompile_mtfsb1x;
+ optable63[711] = recompile_mtfsfx;
+ optable63[134] = recompile_mtfsfix;
+ optable63[64] = recompile_mcrfs;
+
+ optable59[21] = recompile_faddsx;
+ optable59[18] = recompile_fdivsx;
+ optable59[24] = recompile_fresx;
+ optable59[22] = recompile_fsqrtsx;
+ optable59[20] = recompile_fsubsx;
+
+ for(i = 0; i < 32; i++)
+ {
+ optable63[i * 32 | 29] = recompile_fmaddx;
+ optable63[i * 32 | 28] = recompile_fmsubx;
+ optable63[i * 32 | 25] = recompile_fmulx;
+ optable63[i * 32 | 31] = recompile_fnmaddx;
+ optable63[i * 32 | 30] = recompile_fnmsubx;
+ optable63[i * 32 | 23] = recompile_fselx;
+
+ optable59[i * 32 | 29] = recompile_fmaddsx;
+ optable59[i * 32 | 28] = recompile_fmsubsx;
+ optable59[i * 32 | 25] = recompile_fmulsx;
+ optable59[i * 32 | 31] = recompile_fnmaddsx;
+ optable59[i * 32 | 30] = recompile_fnmsubsx;
+ }
+
+ for(i = 0; i < 256; i++)
+ {
+ ppc_field_xlat[i] =
+ ((i & 0x80) ? 0xF0000000 : 0) |
+ ((i & 0x40) ? 0x0F000000 : 0) |
+ ((i & 0x20) ? 0x00F00000 : 0) |
+ ((i & 0x10) ? 0x000F0000 : 0) |
+ ((i & 0x08) ? 0x0000F000 : 0) |
+ ((i & 0x04) ? 0x00000F00 : 0) |
+ ((i & 0x02) ? 0x000000F0 : 0) |
+ ((i & 0x01) ? 0x0000000F : 0);
+ }
+
+ ppc.is603 = 1;
+
+ ppc.read8 = program_read_byte_64be;
+ ppc.read16 = program_read_word_64be;
+ ppc.read32 = program_read_dword_64be;
+ ppc.read64 = program_read_qword_64be;
+ ppc.write8 = program_write_byte_64be;
+ ppc.write16 = program_write_word_64be;
+ ppc.write32 = program_write_dword_64be;
+ ppc.write64 = program_write_qword_64be;
+ ppc.read16_unaligned = ppc_read16_unaligned;
+ ppc.read32_unaligned = ppc_read32_unaligned;
+ ppc.read64_unaligned = ppc_read64_unaligned;
+ ppc.write16_unaligned = ppc_write16_unaligned;
+ ppc.write32_unaligned = ppc_write32_unaligned;
+ ppc.write64_unaligned = ppc_write64_unaligned;
+
+ ppc.irq_callback = irqcallback;
+
+ ppc.pvr = config->pvr;
+
+ multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) +
+ (float)(config->bus_frequency_multiplier & 0xf) / 10.0f;
+ bus_freq_multiplier = (int)(multiplier * 2);
+
+ switch(config->pvr)
+ {
+ case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
+ case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
+ case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
+ default: break;
+ }
+
+ if (pll_config == -1)
+ {
+ fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier);
+ }
+
+ ppc.hid1 = pll_config << 28;
+}
+
+static void ppc601drc_exit(void)
+{
+#if LOG_CODE
+ //if (symfile) fclose(symfile);
+#endif
+ drc_exit(ppc.drc);
+}
+#endif
+
+
+static void ppc_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(PPC_REGS *)dst = ppc;
+}
+
+
+static void ppc_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ ppc = *(PPC_REGS *)src;
+
+ change_pc(ppc.pc);
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void ppc_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + PPC_PC: ppc.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_MSR: ppc_set_msr(info->i); break;
+ case CPUINFO_INT_REGISTER + PPC_CR: ppc_set_cr(info->i); break;
+ case CPUINFO_INT_REGISTER + PPC_LR: LR = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_CTR: CTR = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_XER: XER = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_SRR0: SRR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_SRR1: SRR1 = info->i; break;
+
+ case CPUINFO_INT_REGISTER + PPC_R0: ppc.r[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R1: ppc.r[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R2: ppc.r[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R3: ppc.r[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R4: ppc.r[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R5: ppc.r[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R6: ppc.r[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R7: ppc.r[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R8: ppc.r[8] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R9: ppc.r[9] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R10: ppc.r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R11: ppc.r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R12: ppc.r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R13: ppc.r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R14: ppc.r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R15: ppc.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R16: ppc.r[16] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R17: ppc.r[17] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R18: ppc.r[18] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R19: ppc.r[19] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R20: ppc.r[20] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R21: ppc.r[21] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R22: ppc.r[22] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R23: ppc.r[23] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R24: ppc.r[24] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R25: ppc.r[25] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R26: ppc.r[26] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R27: ppc.r[27] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R28: ppc.r[28] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R29: ppc.r[29] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R30: ppc.r[30] = info->i; break;
+ case CPUINFO_INT_REGISTER + PPC_R31: ppc.r[31] = info->i; break;
+
+ case CPUINFO_INT_PPC_DRC_OPTIONS: ppc.drcoptions = info->i; break;
+ }
+}
+
+void ppc_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ppc); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC: /* intentional fallthrough */
+ case CPUINFO_INT_REGISTER + PPC_PC: info->i = ppc.pc; break;
+ case CPUINFO_INT_REGISTER + PPC_MSR: info->i = ppc_get_msr(); break;
+ case CPUINFO_INT_REGISTER + PPC_CR: info->i = ppc_get_cr(); break;
+ case CPUINFO_INT_REGISTER + PPC_LR: info->i = LR; break;
+ case CPUINFO_INT_REGISTER + PPC_CTR: info->i = CTR; break;
+ case CPUINFO_INT_REGISTER + PPC_XER: info->i = XER; break;
+ case CPUINFO_INT_REGISTER + PPC_SRR0: info->i = SRR0; break;
+ case CPUINFO_INT_REGISTER + PPC_SRR1: info->i = SRR1; break;
+
+ case CPUINFO_INT_REGISTER + PPC_R0: info->i = ppc.r[0]; break;
+ case CPUINFO_INT_REGISTER + PPC_R1: info->i = ppc.r[1]; break;
+ case CPUINFO_INT_REGISTER + PPC_R2: info->i = ppc.r[2]; break;
+ case CPUINFO_INT_REGISTER + PPC_R3: info->i = ppc.r[3]; break;
+ case CPUINFO_INT_REGISTER + PPC_R4: info->i = ppc.r[4]; break;
+ case CPUINFO_INT_REGISTER + PPC_R5: info->i = ppc.r[5]; break;
+ case CPUINFO_INT_REGISTER + PPC_R6: info->i = ppc.r[6]; break;
+ case CPUINFO_INT_REGISTER + PPC_R7: info->i = ppc.r[7]; break;
+ case CPUINFO_INT_REGISTER + PPC_R8: info->i = ppc.r[8]; break;
+ case CPUINFO_INT_REGISTER + PPC_R9: info->i = ppc.r[9]; break;
+ case CPUINFO_INT_REGISTER + PPC_R10: info->i = ppc.r[10]; break;
+ case CPUINFO_INT_REGISTER + PPC_R11: info->i = ppc.r[11]; break;
+ case CPUINFO_INT_REGISTER + PPC_R12: info->i = ppc.r[12]; break;
+ case CPUINFO_INT_REGISTER + PPC_R13: info->i = ppc.r[13]; break;
+ case CPUINFO_INT_REGISTER + PPC_R14: info->i = ppc.r[14]; break;
+ case CPUINFO_INT_REGISTER + PPC_R15: info->i = ppc.r[15]; break;
+ case CPUINFO_INT_REGISTER + PPC_R16: info->i = ppc.r[16]; break;
+ case CPUINFO_INT_REGISTER + PPC_R17: info->i = ppc.r[17]; break;
+ case CPUINFO_INT_REGISTER + PPC_R18: info->i = ppc.r[18]; break;
+ case CPUINFO_INT_REGISTER + PPC_R19: info->i = ppc.r[19]; break;
+ case CPUINFO_INT_REGISTER + PPC_R20: info->i = ppc.r[20]; break;
+ case CPUINFO_INT_REGISTER + PPC_R21: info->i = ppc.r[21]; break;
+ case CPUINFO_INT_REGISTER + PPC_R22: info->i = ppc.r[22]; break;
+ case CPUINFO_INT_REGISTER + PPC_R23: info->i = ppc.r[23]; break;
+ case CPUINFO_INT_REGISTER + PPC_R24: info->i = ppc.r[24]; break;
+ case CPUINFO_INT_REGISTER + PPC_R25: info->i = ppc.r[25]; break;
+ case CPUINFO_INT_REGISTER + PPC_R26: info->i = ppc.r[26]; break;
+ case CPUINFO_INT_REGISTER + PPC_R27: info->i = ppc.r[27]; break;
+ case CPUINFO_INT_REGISTER + PPC_R28: info->i = ppc.r[28]; break;
+ case CPUINFO_INT_REGISTER + PPC_R29: info->i = ppc.r[29]; break;
+ case CPUINFO_INT_REGISTER + PPC_R30: info->i = ppc.r[30]; break;
+ case CPUINFO_INT_REGISTER + PPC_R31: info->i = ppc.r[31]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ppc_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ppc_set_context; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ppc_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ppc_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "PowerPC"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2004"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + PPC_PC: sprintf(info->s, "PC: %08X", ppc.pc); break;
+ case CPUINFO_STR_REGISTER + PPC_MSR: sprintf(info->s, "MSR: %08X", ppc_get_msr()); break;
+ case CPUINFO_STR_REGISTER + PPC_CR: sprintf(info->s, "CR: %08X", ppc_get_cr()); break;
+ case CPUINFO_STR_REGISTER + PPC_LR: sprintf(info->s, "LR: %08X", LR); break;
+ case CPUINFO_STR_REGISTER + PPC_CTR: sprintf(info->s, "CTR: %08X", CTR); break;
+ case CPUINFO_STR_REGISTER + PPC_XER: sprintf(info->s, "XER: %08X", XER); break;
+ case CPUINFO_STR_REGISTER + PPC_SRR0: sprintf(info->s, "SRR0: %08X", SRR0); break;
+ case CPUINFO_STR_REGISTER + PPC_SRR1: sprintf(info->s, "SRR1: %08X", SRR1); break;
+
+ case CPUINFO_STR_REGISTER + PPC_R0: sprintf(info->s, "R0: %08X", ppc.r[0]); break;
+ case CPUINFO_STR_REGISTER + PPC_R1: sprintf(info->s, "R1: %08X", ppc.r[1]); break;
+ case CPUINFO_STR_REGISTER + PPC_R2: sprintf(info->s, "R2: %08X", ppc.r[2]); break;
+ case CPUINFO_STR_REGISTER + PPC_R3: sprintf(info->s, "R3: %08X", ppc.r[3]); break;
+ case CPUINFO_STR_REGISTER + PPC_R4: sprintf(info->s, "R4: %08X", ppc.r[4]); break;
+ case CPUINFO_STR_REGISTER + PPC_R5: sprintf(info->s, "R5: %08X", ppc.r[5]); break;
+ case CPUINFO_STR_REGISTER + PPC_R6: sprintf(info->s, "R6: %08X", ppc.r[6]); break;
+ case CPUINFO_STR_REGISTER + PPC_R7: sprintf(info->s, "R7: %08X", ppc.r[7]); break;
+ case CPUINFO_STR_REGISTER + PPC_R8: sprintf(info->s, "R8: %08X", ppc.r[8]); break;
+ case CPUINFO_STR_REGISTER + PPC_R9: sprintf(info->s, "R9: %08X", ppc.r[9]); break;
+ case CPUINFO_STR_REGISTER + PPC_R10: sprintf(info->s, "R10: %08X", ppc.r[10]); break;
+ case CPUINFO_STR_REGISTER + PPC_R11: sprintf(info->s, "R11: %08X", ppc.r[11]); break;
+ case CPUINFO_STR_REGISTER + PPC_R12: sprintf(info->s, "R12: %08X", ppc.r[12]); break;
+ case CPUINFO_STR_REGISTER + PPC_R13: sprintf(info->s, "R13: %08X", ppc.r[13]); break;
+ case CPUINFO_STR_REGISTER + PPC_R14: sprintf(info->s, "R14: %08X", ppc.r[14]); break;
+ case CPUINFO_STR_REGISTER + PPC_R15: sprintf(info->s, "R15: %08X", ppc.r[15]); break;
+ case CPUINFO_STR_REGISTER + PPC_R16: sprintf(info->s, "R16: %08X", ppc.r[16]); break;
+ case CPUINFO_STR_REGISTER + PPC_R17: sprintf(info->s, "R17: %08X", ppc.r[17]); break;
+ case CPUINFO_STR_REGISTER + PPC_R18: sprintf(info->s, "R18: %08X", ppc.r[18]); break;
+ case CPUINFO_STR_REGISTER + PPC_R19: sprintf(info->s, "R19: %08X", ppc.r[19]); break;
+ case CPUINFO_STR_REGISTER + PPC_R20: sprintf(info->s, "R20: %08X", ppc.r[20]); break;
+ case CPUINFO_STR_REGISTER + PPC_R21: sprintf(info->s, "R21: %08X", ppc.r[21]); break;
+ case CPUINFO_STR_REGISTER + PPC_R22: sprintf(info->s, "R22: %08X", ppc.r[22]); break;
+ case CPUINFO_STR_REGISTER + PPC_R23: sprintf(info->s, "R23: %08X", ppc.r[23]); break;
+ case CPUINFO_STR_REGISTER + PPC_R24: sprintf(info->s, "R24: %08X", ppc.r[24]); break;
+ case CPUINFO_STR_REGISTER + PPC_R25: sprintf(info->s, "R25: %08X", ppc.r[25]); break;
+ case CPUINFO_STR_REGISTER + PPC_R26: sprintf(info->s, "R26: %08X", ppc.r[26]); break;
+ case CPUINFO_STR_REGISTER + PPC_R27: sprintf(info->s, "R27: %08X", ppc.r[27]); break;
+ case CPUINFO_STR_REGISTER + PPC_R28: sprintf(info->s, "R28: %08X", ppc.r[28]); break;
+ case CPUINFO_STR_REGISTER + PPC_R29: sprintf(info->s, "R29: %08X", ppc.r[29]); break;
+ case CPUINFO_STR_REGISTER + PPC_R30: sprintf(info->s, "R30: %08X", ppc.r[30]); break;
+ case CPUINFO_STR_REGISTER + PPC_R31: sprintf(info->s, "R31: %08X", ppc.r[31]); break;
+ }
+}
+
+
+
+/* PowerPC 403 */
+#if (HAS_PPC403)
+void ppc403_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ ppcdrc403_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ default: ppc_set_info(state, info); break;
+ }
+}
+
+void ppc403_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 7; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ppc403_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = ppcdrc403_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppcdrc403_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ppcdrc403_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc403_execute; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
+
+/* PowerPC 603 */
+#if (HAS_PPC603)
+void ppc603_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ case CPUINFO_INT_REGISTER + PPC_DEC: write_decrementer(info->i); break;
+ default: ppc_set_info(state, info); break;
+ }
+}
+
+void ppc603_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_REGISTER + PPC_DEC: info->i = read_decrementer(); break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 17; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ppc603_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = ppcdrc603_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ppcdrc603_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break;
+ case CPUINFO_PTR_READ: info->read = ppc_read; break;
+ case CPUINFO_PTR_WRITE: info->write = ppc_write; break;
+ case CPUINFO_PTR_READOP: info->readop = ppc_readop; break;
+ case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC603"); break;
+ case CPUINFO_STR_REGISTER + PPC_DEC: sprintf(info->s, "DEC: %08X", read_decrementer()); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
+
+/* PowerPC 602 */
+#if (HAS_PPC602)
+void ppc602_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ ppcdrc602_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ default: ppc_set_info(state, info); break;
+ }
+}
+
+void ppc602_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 17; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ppc602_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = ppcdrc602_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppcdrc602_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ppcdrc602_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc602_execute; break;
+ case CPUINFO_PTR_READ: info->read = ppc_read; break;
+ case CPUINFO_PTR_WRITE: info->write = ppc_write; break;
+ case CPUINFO_PTR_READOP: info->readop = ppc_readop; break;
+ case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC602"); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
+
+/* Motorola MPC8240 */
+
+#if (HAS_MPC8240)
+static void mpc8240_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ default: ppc_set_info(state, info); break;
+ }
+}
+
+void mpc8240_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mpc8240_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = mpc8240drc_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = mpc8240drc_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break;
+ case CPUINFO_PTR_READ: info->read = ppc_read; break;
+ case CPUINFO_PTR_WRITE: info->write = ppc_write; break;
+ case CPUINFO_PTR_READOP: info->readop = ppc_readop; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MPC8240"); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
+
+
+/* PPC601 */
+
+#if (HAS_PPC601)
+static void ppc601_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ switch(state)
+ {
+ default: ppc_set_info(state, info); break;
+ }
+}
+
+void ppc601_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ppc601_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = ppc601drc_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ppc601drc_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break;
+ case CPUINFO_PTR_READ: info->read = ppc_read; break;
+ case CPUINFO_PTR_WRITE: info->write = ppc_write; break;
+ case CPUINFO_PTR_READOP: info->readop = ppc_readop; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "PPC601"); break;
+
+ default: ppc_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/rsp/rsp.c b/src/emu/cpu/rsp/rsp.c
new file mode 100644
index 00000000000..2116d65faed
--- /dev/null
+++ b/src/emu/cpu/rsp/rsp.c
@@ -0,0 +1,3008 @@
+/*
+ Nintendo/SGI Reality Signal Processor (RSP) emulator
+
+ Written by Ville Linde
+*/
+
+#include "cpuintrf.h"
+#include "rsp.h"
+#include "debugger.h"
+#include <math.h> // sqrt
+
+#define LOG_INSTRUCTION_EXECUTION 0
+#define SAVE_DISASM 0
+#define SAVE_DMEM 0
+#define RSP_TEST_SYNC 0
+
+#define PRINT_VECREG(x) mame_printf_debug("V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X\n", (x), \
+ (UINT16)R_VREG_S((x),0), (UINT16)R_VREG_S((x),1), \
+ (UINT16)R_VREG_S((x),2), (UINT16)R_VREG_S((x),3), \
+ (UINT16)R_VREG_S((x),4), (UINT16)R_VREG_S((x),5), \
+ (UINT16)R_VREG_S((x),6), (UINT16)R_VREG_S((x),7))
+
+#define PRINT_ACCUM(x) mame_printf_debug("A%d: %08X|%08X\n", (x), \
+ (UINT32)( ( ACCUM(x) >> 32 ) & 0x00000000ffffffff ), \
+ (UINT32)( ACCUM(x) & 0x00000000ffffffff ))
+
+extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op);
+
+#if LOG_INSTRUCTION_EXECUTION
+static FILE *exec_output;
+#endif
+
+
+extern UINT32 sp_read_reg(UINT32 reg);
+extern void sp_write_reg(UINT32 reg, UINT32 data);
+extern READ32_HANDLER( n64_dp_reg_r );
+extern WRITE32_HANDLER( n64_dp_reg_w );
+extern void sp_set_status(UINT32 status);
+
+
+typedef struct
+{
+ UINT64 d[2];
+ //UINT32 l[4];
+ //INT16 s[8];
+ //UINT8 b[16];
+} VECTOR_REG;
+
+typedef struct
+{
+ UINT32 pc;
+ UINT32 r[32];
+ VECTOR_REG v[32];
+ UINT16 flag[4];
+ UINT32 sr;
+
+ INT64 accum[8];
+ INT32 square_root_res;
+ INT32 square_root_high;
+ INT32 reciprocal_res;
+ INT32 reciprocal_high;
+
+ UINT32 ppc;
+ UINT32 nextpc;
+
+ int (*irq_callback)(int irqline);
+} RSP_REGS;
+
+
+
+#define RSREG ((op >> 21) & 0x1f)
+#define RTREG ((op >> 16) & 0x1f)
+#define RDREG ((op >> 11) & 0x1f)
+#define SHIFT ((op >> 6) & 0x1f)
+
+#define RSVAL (rsp.r[RSREG])
+#define RTVAL (rsp.r[RTREG])
+#define RDVAL (rsp.r[RDREG])
+
+#define SIMM16 ((INT32)(INT16)(op))
+#define UIMM16 ((UINT16)(op))
+#define UIMM26 (op & 0x03ffffff)
+
+
+#define JUMP_ABS(addr) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); }
+#define JUMP_ABS_L(addr,l) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); rsp.r[l] = rsp.pc + 4; }
+#define JUMP_REL(offset) { rsp.nextpc = 0x04001000 | ((rsp.pc + ((offset) << 2)) & 0xfff); }
+#define JUMP_REL_L(offset,l) { rsp.nextpc = 0x04001000 | ((rsp.pc + ((offset) << 2)) & 0xfff); rsp.r[l] = rsp.pc + 4; }
+#define JUMP_PC(addr) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); }
+#define JUMP_PC_L(addr,l) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); rsp.r[l] = rsp.pc + 4; }
+
+
+#define VDREG ((op >> 6) & 0x1f)
+#define VS1REG ((op >> 11) & 0x1f)
+#define VS2REG ((op >> 16) & 0x1f)
+#define EL ((op >> 21) & 0xf)
+
+
+#define S_VREG_B(offset) (((15 - (offset)) & 0x07) << 3)
+#define S_VREG_S(offset) (((7 - (offset)) & 0x03) << 4)
+#define S_VREG_L(offset) (((3 - (offset)) & 0x01) << 5)
+
+#define M_VREG_B(offset) ((UINT64)0x00FF << S_VREG_B(offset))
+#define M_VREG_S(offset) ((UINT64)0x0000FFFFul << S_VREG_S(offset))
+#define M_VREG_L(offset) ((UINT64)0x00000000FFFFFFFFull << S_VREG_L(offset))
+
+#define R_VREG_B(reg, offset) ((rsp.v[(reg)].d[(15 - (offset)) >> 3] >> S_VREG_B(offset)) & 0x00FF)
+#define R_VREG_S(reg, offset) (INT16)((rsp.v[(reg)].d[(7 - (offset)) >> 2] >> S_VREG_S(offset)) & 0x0000FFFFul)
+#define R_VREG_L(reg, offset) ((rsp.v[(reg)].d[(3 - (offset)) >> 1] >> S_VREG_L(offset)) & 0x00000000FFFFFFFFull)
+
+#define W_VREG_B(reg, offset, val) (rsp.v[(reg)].d[(15 - (offset)) >> 3] = (rsp.v[(reg)].d[(15 - (offset)) >> 3] & ~M_VREG_B(offset)) | (M_VREG_B(offset) & ((UINT64)(val) << S_VREG_B(offset))))
+#define W_VREG_S(reg, offset, val) (rsp.v[(reg)].d[(7 - (offset)) >> 2] = (rsp.v[(reg)].d[(7 - (offset)) >> 2] & ~M_VREG_S(offset)) | (M_VREG_S(offset) & ((UINT64)(val) << S_VREG_S(offset))))
+#define W_VREG_L(reg, offset, val) (rsp.v[(reg)].d[(3 - (offset)) >> 1] = (rsp.v[(reg)].d[(3 - (offset)) >> 1] & ~M_VREG_L(offset)) | (M_VREG_L(offset) & ((UINT64)(val) << S_VREG_L(offset))))
+
+
+#define VEC_EL_1(x,z) (vector_elements_1[(x)][(z)])
+#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)])
+
+
+#define ACCUM(x) (rsp.accum[(7-(x))])
+
+#define S_ACCUM_H (3 << 4)
+#define S_ACCUM_M (2 << 4)
+#define S_ACCUM_L (1 << 4)
+
+#define M_ACCUM_H ((INT64)0x0000FFFFll << S_ACCUM_H)
+#define M_ACCUM_M ((INT64)0x0000FFFFll << S_ACCUM_M)
+#define M_ACCUM_L ((INT64)0x0000FFFFll << S_ACCUM_L)
+
+#define R_ACCUM_H(x) ((INT16)((ACCUM(x) >> S_ACCUM_H) & 0x00FFFF))
+#define R_ACCUM_M(x) ((INT16)((ACCUM(x) >> S_ACCUM_M) & 0x00FFFF))
+#define R_ACCUM_L(x) ((INT16)((ACCUM(x) >> S_ACCUM_L) & 0x00FFFF))
+
+#define W_ACCUM_H(x, y) (ACCUM(x) = (ACCUM(x) & ~M_ACCUM_H) | (M_ACCUM_H & ((INT64)(y) << S_ACCUM_H)))
+#define W_ACCUM_M(x, y) (ACCUM(x) = (ACCUM(x) & ~M_ACCUM_M) | (M_ACCUM_M & ((INT64)(y) << S_ACCUM_M)))
+#define W_ACCUM_L(x, y) (ACCUM(x) = (ACCUM(x) & ~M_ACCUM_L) | (M_ACCUM_L & ((INT64)(y) << S_ACCUM_L)))
+
+#define CARRY_FLAG(x) ((rsp.flag[0] & (1 << ((x)))) ? 1 : 0)
+#define CLEAR_CARRY_FLAGS() { rsp.flag[0] &= ~0xff; }
+#define SET_CARRY_FLAG(x) { rsp.flag[0] |= (1 << ((x))); }
+#define CLEAR_CARRY_FLAG(x) { rsp.flag[0] &= ~(1 << ((x))); }
+
+#define COMPARE_FLAG(x) ((rsp.flag[1] & (1 << ((x)))) ? 1 : 0)
+#define CLEAR_COMPARE_FLAGS() { rsp.flag[1] &= ~0xff; }
+#define SET_COMPARE_FLAG(x) { rsp.flag[1] |= (1 << ((x))); }
+#define CLEAR_COMPARE_FLAG(x) { rsp.flag[1] &= ~(1 << ((x))); }
+
+#define ZERO_FLAG(x) ((rsp.flag[0] & (1 << (8+(x)))) ? 1 : 0)
+#define CLEAR_ZERO_FLAGS() { rsp.flag[0] &= ~0xff00; }
+#define SET_ZERO_FLAG(x) { rsp.flag[0] |= (1 << (8+(x))); }
+#define CLEAR_ZERO_FLAG(x) { rsp.flag[0] &= ~(1 << (8+(x))); }
+
+
+static RSP_REGS rsp;
+static int rsp_icount;
+
+#define ROPCODE(pc) cpu_readop32(pc)
+
+INLINE UINT8 READ8(UINT32 address)
+{
+ address = 0x04000000 | (address & 0xfff);
+ return program_read_byte_32be(address);
+}
+
+INLINE UINT16 READ16(UINT32 address)
+{
+ address = 0x04000000 | (address & 0xfff);
+
+ if (address & 1)
+ {
+ //osd_die("RSP: READ16: unaligned %08X at %08X\n", address, rsp.ppc);
+ return ((program_read_byte_32be(address+0) & 0xff) << 8) | (program_read_byte_32be(address+1) & 0xff);
+ }
+
+ return program_read_word_32be(address);
+}
+
+INLINE UINT32 READ32(UINT32 address)
+{
+ address = 0x04000000 | (address & 0xfff);
+
+ if (address & 3)
+ {
+ //osd_die("RSP: READ32: unaligned %08X at %08X\n", address, rsp.ppc);
+ return ((program_read_byte_32be(address + 0) & 0xff) << 24) |
+ ((program_read_byte_32be(address + 1) & 0xff) << 16) |
+ ((program_read_byte_32be(address + 2) & 0xff) << 8) |
+ ((program_read_byte_32be(address + 3) & 0xff) << 0);
+ }
+
+ return program_read_dword_32be(address);
+}
+
+INLINE void WRITE8(UINT32 address, UINT8 data)
+{
+ address = 0x04000000 | (address & 0xfff);
+ program_write_byte_32be(address, data);
+}
+
+INLINE void WRITE16(UINT32 address, UINT16 data)
+{
+ address = 0x04000000 | (address & 0xfff);
+
+ if (address & 1)
+ {
+ //fatalerror("RSP: WRITE16: unaligned %08X, %04X at %08X\n", address, data, rsp.ppc);
+ program_write_byte_32be(address + 0, (data >> 8) & 0xff);
+ program_write_byte_32be(address + 1, (data >> 0) & 0xff);
+ return;
+ }
+
+ program_write_word_32be(address, data);
+}
+
+INLINE void WRITE32(UINT32 address, UINT32 data)
+{
+ address = 0x04000000 | (address & 0xfff);
+
+ if (address & 3)
+ {
+ //osd_die("RSP: WRITE32: unaligned %08X, %08X at %08X\n", address, data, rsp.ppc);
+ program_write_byte_32be(address + 0, (data >> 24) & 0xff);
+ program_write_byte_32be(address + 1, (data >> 16) & 0xff);
+ program_write_byte_32be(address + 2, (data >> 8) & 0xff);
+ program_write_byte_32be(address + 3, (data >> 0) & 0xff);
+ return;
+ }
+
+ program_write_dword_32be(address, data);
+}
+
+/*****************************************************************************/
+
+static UINT32 get_cop0_reg(int reg)
+{
+ if (reg >= 0 && reg < 8)
+ {
+ return sp_read_reg(reg);
+ }
+ else if (reg >= 8 && reg < 16)
+ {
+ return n64_dp_reg_r(reg - 8, 0x00000000);
+ }
+ else
+ {
+ fatalerror("RSP: get_cop0_reg: %d", reg);
+ }
+}
+
+static void set_cop0_reg(int reg, UINT32 data)
+{
+ if (reg >= 0 && reg < 8)
+ {
+ sp_write_reg(reg, data);
+ }
+ else if (reg >= 8 && reg < 16)
+ {
+ n64_dp_reg_w(reg - 8, data, 0x00000000);
+ }
+ else
+ {
+ fatalerror("RSP: set_cop0_reg: %d, %08X\n", reg, data);
+ }
+}
+
+static void unimplemented_opcode(UINT32 op)
+{
+#ifdef MAME_DEBUG
+ char string[200];
+ rsp_dasm_one(string, rsp.ppc, op);
+ mame_printf_debug("%08X: %s\n", rsp.ppc, string);
+#endif
+
+#if SAVE_DISASM
+ {
+ char string[200];
+ int i;
+ FILE *dasm;
+ dasm = fopen("rsp_disasm.txt", "wt");
+
+ for (i=0; i < 0x1000; i+=4)
+ {
+ UINT32 opcode = ROPCODE(0x04001000 + i);
+ rsp_dasm_one(string, 0x04001000 + i, opcode);
+ fprintf(dasm, "%08X: %08X %s\n", 0x04001000 + i, opcode, string);
+ }
+ fclose(dasm);
+ }
+#endif
+#if SAVE_DMEM
+ {
+ int i;
+ FILE *dmem;
+ dmem = fopen("rsp_dmem.bin", "wb");
+
+ for (i=0; i < 0x1000; i++)
+ {
+ fputc(READ8(0x04000000 + i), dmem);
+ }
+ fclose(dmem);
+ }
+#endif
+
+ fatalerror("RSP: unknown opcode %02X (%08X) at %08X\n", op >> 26, op, rsp.ppc);
+}
+
+/*****************************************************************************/
+
+static const int vector_elements_1[16][8] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // none
+ { 0, 1, 2, 3, 4, 5, 6 ,7 }, // ???
+ { 1, 3, 5, 7, 0, 2, 4, 6 }, // 0q
+ { 0, 2, 4, 6, 1, 3, 5, 7 }, // 1q
+ { 1, 2, 3, 5, 6, 7, 0, 4 }, // 0h
+ { 0, 2, 3, 4, 6, 7, 1, 5 }, // 1h
+ { 0, 1, 3, 4, 5, 7, 2, 6 }, // 2h
+ { 0, 1, 2, 4, 5, 6, 3, 7 }, // 3h
+ { 1, 2, 3, 4, 5, 6, 7, 0 }, // 0
+ { 0, 2, 3, 4, 5, 6, 7, 1 }, // 1
+ { 0, 1, 3, 4, 5, 6, 7, 2 }, // 2
+ { 0, 1, 2, 4, 5, 6, 7, 3 }, // 3
+ { 0, 1, 2, 3, 5, 6, 7, 4 }, // 4
+ { 0, 1, 2, 3, 4, 6, 7, 5 }, // 5
+ { 0, 1, 2, 3, 4, 5, 7, 6 }, // 6
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // 7
+};
+
+static const int vector_elements_2[16][8] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // none
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // ???
+ { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q
+ { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q
+ { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h
+ { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h
+ { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h
+ { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0
+ { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1
+ { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2
+ { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3
+ { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4
+ { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5
+ { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6
+ { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7
+};
+
+static void rsp_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ //int regIdx, accumIdx;
+#if LOG_INSTRUCTION_EXECUTION
+ exec_output = fopen("rsp_execute.txt", "wt");
+#endif
+
+ rsp.irq_callback = irqcallback;
+ /*
+ for(regIdx = 0; regIdx < 32; regIdx++ )
+ {
+ rsp.r[regIdx] = 0;
+ rsp.v[regIdx].d[0] = 0;
+ rsp.v[regIdx].d[1] = 0;
+ }
+ for(accumIdx = 0; accumIdx < 8; accumIdx++ )
+ {
+ rsp.accum[accumIdx] = 0;
+ }
+ rsp.flag[0] = 0;
+ rsp.flag[1] = 0;
+ rsp.flag[2] = 0;
+ rsp.flag[3] = 0;
+ rsp.square_root_res = 0;
+ rsp.square_root_high = 0;
+ rsp.reciprocal_res = 0;
+ rsp.reciprocal_high = 0;
+ */
+ rsp.sr = RSP_STATUS_HALT;
+}
+
+static void rsp_exit(void)
+{
+#if SAVE_DISASM
+ {
+ char string[200];
+ int i;
+ FILE *dasm;
+ dasm = fopen("rsp_disasm.txt", "wt");
+
+ for (i=0; i < 0x1000; i+=4)
+ {
+ UINT32 opcode = ROPCODE(0x04001000 + i);
+ rsp_dasm_one(string, 0x04001000 + i, opcode);
+ fprintf(dasm, "%08X: %08X %s\n", 0x04001000 + i, opcode, string);
+ }
+ fclose(dasm);
+ }
+#endif
+#if SAVE_DMEM
+ {
+ /*int i;
+ FILE *dmem;
+ dmem = fopen("rsp_dmem.txt", "wt");
+
+ for (i=0; i < 0x1000; i+=4)
+ {
+ fprintf(dmem, "%08X: %08X\n", 0x04000000 + i, READ32(0x04000000 + i));
+ }
+ fclose(dmem);*/
+
+ int i;
+ FILE *dmem;
+ dmem = fopen("rsp_dmem.bin", "wb");
+
+ for (i=0; i < 0x1000; i++)
+ {
+ fputc(READ8(0x04000000 + i), dmem);
+ }
+ fclose(dmem);
+ }
+#endif
+
+#if LOG_INSTRUCTION_EXECUTION
+ fclose(exec_output);
+#endif
+}
+
+static void rsp_reset(void)
+{
+ rsp.nextpc = ~0;
+}
+
+static void handle_lwc2(UINT32 op)
+{
+ int i, end;
+ UINT32 ea;
+ int dest = (op >> 16) & 0x1f;
+ int base = (op >> 21) & 0x1f;
+ int index = (op >> 7) & 0xf;
+ int offset = (op & 0x7f);
+ if (offset & 0x40)
+ offset |= 0xffffffc0;
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: /* LBV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Load 1 byte to vector byte index
+
+ ea = (base) ? rsp.r[base] + offset : offset;
+ W_VREG_B(dest, index, READ8(ea));
+ break;
+ }
+ case 0x01: /* LSV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads 2 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 2) : (offset * 2);
+
+ end = index + 2;
+
+ for (i=index; i < end; i++)
+ {
+ W_VREG_B(dest, i, READ8(ea));
+ ea++;
+ }
+ break;
+ }
+ case 0x02: /* LLV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads 4 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 4) : (offset * 4);
+
+ end = index + 4;
+
+ for (i=index; i < end; i++)
+ {
+ W_VREG_B(dest, i, READ8(ea));
+ ea++;
+ }
+ break;
+ }
+ case 0x03: /* LDV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads 8 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+
+ end = index + 8;
+
+ for (i=index; i < end; i++)
+ {
+ W_VREG_B(dest, i, READ8(ea));
+ ea++;
+ }
+ break;
+ }
+ case 0x04: /* LQV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads up to 16 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ end = index + (16 - (ea & 0xf));
+ if (end > 16) end = 16;
+
+ for (i=index; i < end; i++)
+ {
+ W_VREG_B(dest, i, READ8(ea));
+ ea++;
+ }
+ break;
+ }
+ case 0x05: /* LRV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores up to 16 bytes starting from right side until 16-byte boundary
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ index = 16 - ((ea & 0xf) - index);
+ end = 16;
+ ea &= ~0xf;
+
+ for (i=index; i < end; i++)
+ {
+ W_VREG_B(dest, i, READ8(ea));
+ ea++;
+ }
+ break;
+ }
+ case 0x06: /* LPV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the upper 8 bits of each element
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+
+ for (i=0; i < 8; i++)
+ {
+ W_VREG_S(dest, i, READ8(ea + (((16-index) + i) & 0xf)) << 8);
+ }
+ break;
+ }
+ case 0x07: /* LUV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the bits 14-7 of each element
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+
+ for (i=0; i < 8; i++)
+ {
+ W_VREG_S(dest, i, READ8(ea + (((16-index) + i) & 0xf)) << 7);
+ }
+ break;
+ }
+ case 0x08: /* LHV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the bits 14-7 of each element, with 2-byte stride
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ for (i=0; i < 8; i++)
+ {
+ W_VREG_S(dest, i, READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7);
+ }
+ break;
+ }
+ case 0x09: /* LFV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride
+
+ fatalerror("RSP: LFV\n");
+
+ if (index & 0x7) fatalerror("RSP: LFV: index = %d at %08X\n", index, rsp.ppc);
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ // not sure what happens if 16-byte boundary is crossed...
+ if ((ea & 0xf) > 0) fatalerror("RSP: LFV: 16-byte boundary crossing at %08X, recheck this!\n", rsp.ppc);
+
+ end = (index >> 1) + 4;
+
+ for (i=index >> 1; i < end; i++)
+ {
+ W_VREG_S(dest, i, READ8(ea) << 7);
+ ea += 4;
+ }
+ break;
+ }
+ case 0x0a: /* LWV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads the full 128-bit vector starting from vector byte index and wrapping to index 0
+ // after byte index 15
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ // not sure what happens if 16-byte boundary is crossed...
+ if ((ea & 0xf) > 0) fatalerror("RSP: LWV: 16-byte boundary crossing at %08X, recheck this!\n", rsp.ppc);
+
+ end = (16 - index) + 16;
+
+ for (i=(16 - index); i < end; i++)
+ {
+ W_VREG_B(dest, i & 0xf, READ8(ea));
+ ea += 4;
+ }
+ break;
+ }
+ case 0x0b: /* LTV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads one element to maximum of 8 vectors, while incrementing element index
+
+ // FIXME: has a small problem with odd indices
+
+ int element;
+ int vs = dest;
+ int ve = dest + 8;
+ if (ve > 32)
+ ve = 32;
+
+ element = 7 - (index >> 1);
+
+ if (index & 1) fatalerror("RSP: LTV: index = %d\n", index);
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ ea = ((ea + 8) & ~0xf) + (index & 1);
+ for (i=vs; i < ve; i++)
+ {
+ element = ((8 - (index >> 1) + (i-vs)) << 1);
+ W_VREG_B(i, (element & 0xf), READ8(ea));
+ W_VREG_B(i, ((element+1) & 0xf), READ8(ea+1));
+
+ ea += 2;
+ }
+ break;
+ }
+
+ default:
+ {
+ unimplemented_opcode(op);
+ break;
+ }
+ }
+}
+
+static void handle_swc2(UINT32 op)
+{
+ int i, end;
+ int eaoffset;
+ UINT32 ea;
+ int dest = (op >> 16) & 0x1f;
+ int base = (op >> 21) & 0x1f;
+ int index = (op >> 7) & 0xf;
+ int offset = (op & 0x7f);
+ if (offset & 0x40)
+ offset |= 0xffffffc0;
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: /* SBV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 1 byte from vector byte index
+
+ ea = (base) ? rsp.r[base] + offset : offset;
+ WRITE8(ea, R_VREG_B(dest, index));
+ break;
+ }
+ case 0x01: /* SSV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 2 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 2) : (offset * 2);
+
+ end = index + 2;
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, R_VREG_B(dest, i));
+ ea++;
+ }
+ break;
+ }
+ case 0x02: /* SLV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 4 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 4) : (offset * 4);
+
+ end = index + 4;
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, R_VREG_B(dest, i));
+ ea++;
+ }
+ break;
+ }
+ case 0x03: /* SDV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 8 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+
+ end = index + 8;
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, R_VREG_B(dest, i));
+ ea++;
+ }
+ break;
+ }
+ case 0x04: /* SQV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores up to 16 bytes starting from vector byte index until 16-byte boundary
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ end = index + (16 - (ea & 0xf));
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, R_VREG_B(dest, i & 0xf));
+ ea++;
+ }
+ break;
+ }
+ case 0x05: /* SRV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores up to 16 bytes starting from right side until 16-byte boundary
+
+ int o;
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ end = index + (ea & 0xf);
+ o = (16 - (ea & 0xf)) & 0xf;
+ ea &= ~0xf;
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, R_VREG_B(dest, ((i + o) & 0xf)));
+ ea++;
+ }
+ break;
+ }
+ case 0x06: /* SPV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores upper 8 bits of each element
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+ end = index + 8;
+
+ for (i=index; i < end; i++)
+ {
+ if ((i & 0xf) < 8)
+ {
+ WRITE8(ea, R_VREG_B(dest, ((i & 0xf) << 1)));
+ }
+ else
+ {
+ WRITE8(ea, R_VREG_S(dest, (i & 0x7)) >> 7);
+ }
+ ea++;
+ }
+ break;
+ }
+ case 0x07: /* SUV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores bits 14-7 of each element
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+ end = index + 8;
+
+ for (i=index; i < end; i++)
+ {
+ if ((i & 0xf) < 8)
+ {
+ WRITE8(ea, R_VREG_S(dest, (i & 0x7)) >> 7);
+ }
+ else
+ {
+ WRITE8(ea, R_VREG_B(dest, ((i & 0x7) << 1)));
+ }
+ ea++;
+ }
+ break;
+ }
+ case 0x08: /* SHV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores bits 14-7 of each element, with 2-byte stride
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ for (i=0; i < 8; i++)
+ {
+ UINT8 d = ((R_VREG_B(dest, ((index + (i << 1) + 0) & 0xf))) << 1) |
+ ((R_VREG_B(dest, ((index + (i << 1) + 1) & 0xf))) >> 7);
+
+ WRITE8(ea, d);
+ ea += 2;
+ }
+ break;
+ }
+ case 0x09: /* SFV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores bits 14-7 of upper or lower quad, with 4-byte stride
+
+ // FIXME: only works for index 0 and index 8
+
+ if (index & 0x7) mame_printf_debug("RSP: SFV: index = %d at %08X\n", index, rsp.ppc);
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ eaoffset = ea & 0xf;
+ ea &= ~0xf;
+
+ end = (index >> 1) + 4;
+
+ for (i=index >> 1; i < end; i++)
+ {
+ WRITE8(ea + (eaoffset & 0xf), R_VREG_S(dest, i) >> 7);
+ eaoffset += 4;
+ }
+ break;
+ }
+ case 0x0a: /* SWV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores the full 128-bit vector starting from vector byte index and wrapping to index 0
+ // after byte index 15
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ eaoffset = ea & 0xf;
+ ea &= ~0xf;
+
+ end = index + 16;
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea + (eaoffset & 0xf), R_VREG_B(dest, i & 0xf));
+ eaoffset++;
+ }
+ break;
+ }
+ case 0x0b: /* STV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores one element from maximum of 8 vectors, while incrementing element index
+
+ int element, eaoffset;
+ int vs = dest;
+ int ve = dest + 8;
+ if (ve > 32)
+ ve = 32;
+
+ element = 8 - (index >> 1);
+ if (index & 0x1) fatalerror("RSP: STV: index = %d at %08X\n", index, rsp.ppc);
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ if (ea & 0x1) fatalerror("RSP: STV: ea = %08X at %08X\n", ea, rsp.ppc);
+
+ eaoffset = (ea & 0xf) + (element * 2);
+ ea &= ~0xf;
+
+ for (i=vs; i < ve; i++)
+ {
+ WRITE16(ea + (eaoffset & 0xf), R_VREG_S(i, element & 0x7));
+ eaoffset += 2;
+ element++;
+ }
+ break;
+ }
+
+ default:
+ {
+ unimplemented_opcode(op);
+ break;
+ }
+ }
+}
+
+INLINE UINT16 SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive)
+{
+ if ((INT16)R_ACCUM_H(accum) < 0)
+ {
+ if ((UINT16)(R_ACCUM_H(accum)) != 0xffff)
+ {
+ return negative;
+ }
+ else
+ {
+ if ((INT16)R_ACCUM_M(accum) >= 0)
+ {
+ return negative;
+ }
+ else
+ {
+ if (slice == 0)
+ {
+ return R_ACCUM_L(accum);
+ }
+ else if (slice == 1)
+ {
+ return R_ACCUM_M(accum);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((UINT16)(R_ACCUM_H(accum)) != 0)
+ {
+ return positive;
+ }
+ else
+ {
+ if ((INT16)R_ACCUM_M(accum) < 0)
+ {
+ return positive;
+ }
+ else
+ {
+ if (slice == 0)
+ {
+ return R_ACCUM_L(accum);
+ }
+ else
+ {
+ return R_ACCUM_M(accum);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+#define WRITEBACK_RESULT() \
+ do { \
+ W_VREG_S(VDREG, 0, vres[0]); \
+ W_VREG_S(VDREG, 1, vres[1]); \
+ W_VREG_S(VDREG, 2, vres[2]); \
+ W_VREG_S(VDREG, 3, vres[3]); \
+ W_VREG_S(VDREG, 4, vres[4]); \
+ W_VREG_S(VDREG, 5, vres[5]); \
+ W_VREG_S(VDREG, 6, vres[6]); \
+ W_VREG_S(VDREG, 7, vres[7]); \
+ } while(0)
+
+#if 0
+static float float_round(float input)
+{
+ INT32 integer = (INT32)input;
+ float fraction = input - (float)integer;
+ float output = 0.0f;
+ if( fraction >= 0.5f )
+ {
+ output = (float)( integer + 1 );
+ }
+ else
+ {
+ output = (float)integer;
+ }
+ return output;
+}
+#endif
+
+static void handle_vector_ops(UINT32 op)
+{
+ int i;
+ INT16 vres[8];
+
+ // Opcode legend:
+ // E = VS2 element type
+ // S = VS1, Source vector 1
+ // T = VS2, Source vector 2
+ // D = Destination vector
+
+ switch (op & 0x3f)
+ {
+ case 0x00: /* VMULF */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer * 2
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ if (s1 == -32768 && s2 == -32768)
+ {
+ // overflow
+ W_ACCUM_H(del, 0);
+ W_ACCUM_M(del, -32768);
+ W_ACCUM_L(del, -32768);
+ vres[del] = 0x7fff;
+ }
+ else
+ {
+ INT64 r = s1 * s2 * 2;
+ r += 0x8000; // rounding ?
+ W_ACCUM_H(del, (r < 0) ? 0xffff : 0); // sign-extend to 48-bit
+ W_ACCUM_M(del, (INT16)(r >> 16));
+ W_ACCUM_L(del, (UINT16)(r));
+ vres[del] = R_ACCUM_M(del);
+ }
+ }
+ WRITEBACK_RESULT();
+
+ break;
+ }
+
+ case 0x01: /* VMULU */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 |
+ // ------------------------------------------------------
+ //
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ INT64 r = s1 * s2 * 2;
+ r += 0x8000; // rounding ?
+
+ W_ACCUM_H(del, (UINT16)(r >> 32));
+ W_ACCUM_M(del, (UINT16)(r >> 16));
+ W_ACCUM_L(del, (UINT16)(r));
+
+ if (r < 0)
+ {
+ vres[del] = 0;
+ }
+ else if (((INT16)(R_ACCUM_H(del)) ^ (INT16)(R_ACCUM_M(del))) < 0)
+ {
+ vres[del] = -1;
+ }
+ else
+ {
+ vres[del] = R_ACCUM_M(del);
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x04: /* VMUDL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000100 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by unsigned fraction
+ // Stores the higher 16 bits of the 32-bit result to accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ UINT32 s1 = (UINT32)(UINT16)R_VREG_S(VS1REG, del);
+ UINT32 s2 = (UINT32)(UINT16)R_VREG_S(VS2REG, sel);
+ UINT32 r = s1 * s2;
+
+ W_ACCUM_H(del, 0);
+ W_ACCUM_M(del, 0);
+ W_ACCUM_L(del, (UINT16)(r >> 16));
+
+ vres[del] = R_ACCUM_L(del);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x05: /* VMUDM */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by unsigned fraction
+ // The result is stored into accumulator
+ // The middle slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (UINT16)R_VREG_S(VS2REG, sel); // not sign-extended
+ INT32 r = s1 * s2;
+
+ W_ACCUM_H(del, (r < 0) ? 0xffff : 0); // sign-extend to 48-bit
+ W_ACCUM_M(del, (INT16)(r >> 16));
+ W_ACCUM_L(del, (UINT16)(r));
+
+ vres[del] = R_ACCUM_M(del);
+ }
+ WRITEBACK_RESULT();
+ break;
+
+ }
+
+ case 0x06: /* VMUDN */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by signed integer
+ // The result is stored into accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (UINT16)R_VREG_S(VS1REG, del); // not sign-extended
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ INT32 r = s1 * s2;
+
+ W_ACCUM_H(del, (r < 0) ? 0xffff : 0); // sign-extend to 48-bit
+ W_ACCUM_M(del, (INT16)(r >> 16));
+ W_ACCUM_L(del, (UINT16)(r));
+
+ vres[del] = R_ACCUM_L(del);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x07: /* VMUDH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer
+ // The result is stored into highest 32 bits of accumulator, the low slice is zero
+ // The highest 32 bits of accumulator is saturated into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ INT32 r = s1 * s2;
+
+ W_ACCUM_H(del, (INT16)(r >> 16));
+ W_ACCUM_M(del, (UINT16)(r));
+ W_ACCUM_L(del, 0);
+
+ if (r < -32768) r = -32768;
+ if (r > 32767) r = 32767;
+ vres[del] = (INT16)(r);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x08: /* VMACF */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer * 2
+ // The result is added to accumulator
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ INT32 r = s1 * s2;
+
+ ACCUM(del) += (INT64)(r) << 17;
+ res = SATURATE_ACCUM(del, 1, 0x8000, 0x7fff);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x09: /* VMACU */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 |
+ // ------------------------------------------------------
+ //
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ INT32 r1 = s1 * s2;
+ UINT32 r2 = (UINT16)R_ACCUM_L(del) + ((UINT16)(r1) * 2);
+ UINT32 r3 = (UINT16)R_ACCUM_M(del) + (UINT16)((r1 >> 16) * 2) + (UINT16)(r2 >> 16);
+
+ W_ACCUM_L(del, (UINT16)(r2));
+ W_ACCUM_M(del, (UINT16)(r3));
+ W_ACCUM_H(del, (UINT16)R_ACCUM_H(del) + (UINT16)(r3 >> 16) + (UINT16)(r1 >> 31));
+
+ //res = SATURATE_ACCUM(del, 1, 0x0000, 0xffff);
+ if ((INT16)R_ACCUM_H(del) < 0)
+ {
+ res = 0;
+ }
+ else
+ {
+ if (R_ACCUM_H(del) != 0)
+ {
+ res = 0xffff;
+ }
+ else
+ {
+ if ((INT16)R_ACCUM_M(del) < 0)
+ {
+ res = 0xffff;
+ }
+ else
+ {
+ res = R_ACCUM_M(del);
+ }
+ }
+ }
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0c: /* VMADL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by unsigned fraction
+ // Adds the higher 16 bits of the 32-bit result to accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ UINT32 s1 = (UINT32)(UINT16)R_VREG_S(VS1REG, del);
+ UINT32 s2 = (UINT32)(UINT16)R_VREG_S(VS2REG, sel);
+ UINT32 r1 = s1 * s2;
+ UINT32 r2 = (UINT16)R_ACCUM_L(del) + (r1 >> 16);
+ UINT32 r3 = (UINT16)R_ACCUM_M(del) + (r2 >> 16);
+
+ W_ACCUM_L(del, (UINT16)(r2));
+ W_ACCUM_M(del, (UINT16)(r3));
+ W_ACCUM_H(del, (INT16)R_ACCUM_H(del) + (INT16)(r3 >> 16));
+
+ res = SATURATE_ACCUM(del, 0, 0x0000, 0xffff);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0d: /* VMADM */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by unsigned fraction
+ // The result is added into accumulator
+ // The middle slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ UINT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ UINT32 s2 = (UINT16)R_VREG_S(VS2REG, sel); // not sign-extended
+ UINT32 r1 = s1 * s2;
+ UINT32 r2 = (UINT16)R_ACCUM_L(del) + (UINT16)(r1);
+ UINT32 r3 = (UINT16)R_ACCUM_M(del) + (r1 >> 16) + (r2 >> 16);
+
+ W_ACCUM_L(del, (UINT16)(r2));
+ W_ACCUM_M(del, (UINT16)(r3));
+ W_ACCUM_H(del, (UINT16)R_ACCUM_H(del) + (UINT16)(r3 >> 16));
+ if ((INT32)(r1) < 0)
+ W_ACCUM_H(del, (UINT16)R_ACCUM_H(del) - 1);
+
+ res = SATURATE_ACCUM(del, 1, 0x8000, 0x7fff);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0e: /* VMADN */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001110 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by signed integer
+ // The result is added into accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (UINT16)R_VREG_S(VS1REG, del); // not sign-extended
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ UINT32 r1 = s1 * s2;
+ UINT32 r2 = (UINT16)R_ACCUM_L(del) + (UINT16)(r1);
+ UINT32 r3 = (UINT16)R_ACCUM_M(del) + (r1 >> 16) + (r2 >> 16);
+
+ W_ACCUM_L(del, (UINT16)(r2));
+ W_ACCUM_M(del, (UINT16)(r3));
+ W_ACCUM_H(del, (UINT16)R_ACCUM_H(del) + (UINT16)(r3 >> 16));
+ if ((INT32)(r1) < 0)
+ W_ACCUM_H(del, (UINT16)R_ACCUM_H(del) - 1);
+
+ res = SATURATE_ACCUM(del, 0, 0x0000, 0xffff);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0f: /* VMADH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer
+ // The result is added into highest 32 bits of accumulator, the low slice is zero
+ // The highest 32 bits of accumulator is saturated into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ INT64 r = s1 * s2;
+
+ ACCUM(del) += (INT64)(r) << 32;
+
+ res = SATURATE_ACCUM(del, 1, 0x8000, 0x7fff);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x10: /* VADD */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 |
+ // ------------------------------------------------------
+ //
+ // Adds two vector registers and carry flag, the result is saturated to 32767
+
+ // TODO: check VS2REG == VDREG
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ INT32 r = s1 + s2 + CARRY_FLAG(del);
+
+ W_ACCUM_L(del, (INT16)(r));
+
+ if (r > 32767) r = 32767;
+ if (r < -32768) r = -32768;
+ vres[del] = (INT16)(r);
+ }
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x11: /* VSUB */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 |
+ // ------------------------------------------------------
+ //
+ // Subtracts two vector registers and carry flag, the result is saturated to -32768
+
+ // TODO: check VS2REG == VDREG
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)R_VREG_S(VS2REG, sel);
+ INT32 r = s1 - s2 - CARRY_FLAG(del);
+
+ W_ACCUM_L(del, (INT16)(r));
+
+ if (r > 32767) r = 32767;
+ if (r < -32768) r = -32768;
+
+ vres[del] = (INT16)(r);
+ }
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x13: /* VABS */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 |
+ // ------------------------------------------------------
+ //
+ // Changes the sign of source register 2 if source register 1 is negative and stores
+ // the result to destination register
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT16 s1 = (INT16)R_VREG_S(VS1REG, del);
+ INT16 s2 = (INT16)R_VREG_S(VS2REG, sel);
+
+ if (s1 < 0)
+ {
+ if (s2 == -32768)
+ {
+ vres[del] = 32767;
+ }
+ else
+ {
+ vres[del] = -s2;
+ }
+ }
+ else if (s1 > 0)
+ {
+ vres[del] = s2;
+ }
+ else
+ {
+ vres[del] = 0;
+ }
+
+ W_ACCUM_L(del, vres[del]);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x14: /* VADDC */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 |
+ // ------------------------------------------------------
+ //
+ // Adds two vector registers, the carry out is stored into carry register
+
+ // TODO: check VS2REG = VDREG
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (UINT32)(UINT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (UINT32)(UINT16)R_VREG_S(VS2REG, sel);
+ INT32 r = s1 + s2;
+
+ vres[del] = (INT16)(r);
+ W_ACCUM_L(del, (INT16)(r));
+
+ if (r & 0xffff0000)
+ {
+ SET_CARRY_FLAG(del);
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x15: /* VSUBC */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 |
+ // ------------------------------------------------------
+ //
+ // Subtracts two vector registers, the carry out is stored into carry register
+
+ // TODO: check VS2REG = VDREG
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (UINT32)(UINT16)R_VREG_S(VS1REG, del);
+ INT32 s2 = (UINT32)(UINT16)R_VREG_S(VS2REG, sel);
+ INT32 r = s1 - s2;
+
+ vres[del] = (INT16)(r);
+ W_ACCUM_L(del, (UINT16)(r));
+
+ if ((UINT16)(r) != 0)
+ {
+ SET_ZERO_FLAG(del);
+ }
+ if (r & 0xffff0000)
+ {
+ SET_CARRY_FLAG(del);
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x1d: /* VSAW */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 |
+ // ------------------------------------------------------
+ //
+ // Stores high, middle or low slice of accumulator to destination vector
+
+ switch (EL)
+ {
+ case 0x08: // VSAWH
+ {
+ for (i=0; i < 8; i++)
+ {
+ W_VREG_S(VDREG, i, R_ACCUM_H(i));
+ }
+ break;
+ }
+ case 0x09: // VSAWM
+ {
+ for (i=0; i < 8; i++)
+ {
+ W_VREG_S(VDREG, i, R_ACCUM_M(i));
+ }
+ break;
+ }
+ case 0x0a: // VSAWL
+ {
+ for (i=0; i < 8; i++)
+ {
+ W_VREG_S(VDREG, i, R_ACCUM_L(i));
+ }
+ break;
+ }
+ default: fatalerror("RSP: VSAW: el = %d\n", EL);
+ }
+ break;
+ }
+
+ case 0x20: /* VLT */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are less than VS2
+ // Moves the element in VS2 to destination vector
+
+ rsp.flag[1] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+
+ if (R_VREG_S(VS1REG, del) < R_VREG_S(VS2REG, sel))
+ {
+ vres[del] = R_VREG_S(VS1REG, del);
+ SET_COMPARE_FLAG(del);
+ }
+ else if (R_VREG_S(VS1REG, del) == R_VREG_S(VS2REG, sel))
+ {
+ vres[del] = R_VREG_S(VS1REG, del);
+ if (ZERO_FLAG(del) != 0 && CARRY_FLAG(del) != 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ else
+ {
+ vres[del] = R_VREG_S(VS2REG, sel);
+ }
+
+ W_ACCUM_L(del, vres[del]);
+ }
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x21: /* VEQ */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are equal with VS2
+ // Moves the element in VS2 to destination vector
+
+ rsp.flag[1] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+
+ vres[del] = R_VREG_S(VS2REG, sel);
+ W_ACCUM_L(del, vres[del]);
+
+ if (R_VREG_S(VS1REG, del) == R_VREG_S(VS2REG, sel))
+ {
+ if (ZERO_FLAG(del) == 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ }
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x22: /* VNE */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are not equal with VS2
+ // Moves the element in VS2 to destination vector
+
+ rsp.flag[1] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+
+ vres[del] = R_VREG_S(VS1REG, del);
+ W_ACCUM_L(del, vres[del]);
+
+ if (R_VREG_S(VS1REG, del) != R_VREG_S(VS2REG, sel))
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ else
+ {
+ if (ZERO_FLAG(del) != 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ }
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x23: /* VGE */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are greater or equal with VS2
+ // Moves the element in VS2 to destination vector
+
+ rsp.flag[1] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+
+ if (R_VREG_S(VS1REG, del) == R_VREG_S(VS2REG, sel))
+ {
+ if (ZERO_FLAG(del) == 0 || CARRY_FLAG(del) == 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ else if (R_VREG_S(VS1REG, del) > R_VREG_S(VS2REG, sel))
+ {
+ SET_COMPARE_FLAG(del);
+ }
+
+ if (COMPARE_FLAG(del) != 0)
+ {
+ vres[del] = R_VREG_S(VS1REG, del);
+ }
+ else
+ {
+ vres[del] = R_VREG_S(VS2REG, sel);
+ }
+
+ W_ACCUM_L(del, vres[del]);
+ }
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x24: /* VCL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 |
+ // ------------------------------------------------------
+ //
+ // Vector clip low
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT16 s1 = R_VREG_S(VS1REG, del);
+ INT16 s2 = R_VREG_S(VS2REG, sel);
+
+ if (CARRY_FLAG(del) != 0)
+ {
+ if (ZERO_FLAG(del) != 0)
+ {
+ if (COMPARE_FLAG(del) != 0)
+ {
+ W_ACCUM_L(del, -(UINT16)s2);
+ }
+ else
+ {
+ W_ACCUM_L(del, s1);
+ }
+ }
+ else
+ {
+ if (rsp.flag[2] & (1 << (del)))
+ {
+ if (((UINT32)(INT16)(s1) + (UINT32)(INT16)(s2)) > 0x10000)
+ {
+ W_ACCUM_L(del, s1);
+ CLEAR_COMPARE_FLAG(del);
+ }
+ else
+ {
+ W_ACCUM_L(del, -((UINT16)s2));
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ else
+ {
+ if (((UINT32)(INT16)(s1) + (UINT32)(INT16)(s2)) != 0)
+ {
+ W_ACCUM_L(del, s1);
+ CLEAR_COMPARE_FLAG(del);
+ }
+ else
+ {
+ W_ACCUM_L(del, -((UINT16)s2));
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (ZERO_FLAG(del) != 0)
+ {
+ if (rsp.flag[1] & (1 << (8+del)))
+ {
+ W_ACCUM_L(del, s2);
+ }
+ else
+ {
+ W_ACCUM_L(del, s1);
+ }
+ }
+ else
+ {
+ if (((INT32)(UINT16)s1 - (INT32)(UINT16)s2) >= 0)
+ {
+ W_ACCUM_L(del, s2);
+ rsp.flag[1] |= (1 << (8+del));
+ }
+ else
+ {
+ W_ACCUM_L(del, s1);
+ rsp.flag[1] &= ~(1 << (8+del));
+ }
+ }
+ }
+
+ vres[del] = R_ACCUM_L(del);
+ }
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ rsp.flag[2] = 0;
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x25: /* VCH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 |
+ // ------------------------------------------------------
+ //
+ // Vector clip high
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ rsp.flag[1] = 0;
+ rsp.flag[2] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT16 s1 = R_VREG_S(VS1REG, del);
+ INT16 s2 = R_VREG_S(VS2REG, sel);
+
+ if ((s1 ^ s2) < 0)
+ {
+ SET_CARRY_FLAG(del);
+ if (s2 < 0)
+ {
+ rsp.flag[1] |= (1 << (8+del));
+ }
+
+ if (s1 + s2 <= 0)
+ {
+ if (s1 + s2 == -1)
+ {
+ rsp.flag[2] |= (1 << (del));
+ }
+ SET_COMPARE_FLAG(del);
+ vres[del] = -((UINT16)s2);
+ }
+ else
+ {
+ vres[del] = s1;
+ }
+
+ if (s1 + s2 != 0)
+ {
+ if (s1 != ~s2)
+ {
+ SET_ZERO_FLAG(del);
+ }
+ }
+ }
+ else
+ {
+ if (s2 < 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ if (s1 - s2 >= 0)
+ {
+ rsp.flag[1] |= (1 << (8+del));
+ vres[del] = s2;
+ }
+ else
+ {
+ vres[del] = s1;
+ }
+
+ if ((s1 - s2) != 0)
+ {
+ if (s1 != ~s2)
+ {
+ SET_ZERO_FLAG(del);
+ }
+ }
+ }
+
+ W_ACCUM_L(del, vres[del]);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x26: /* VCR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 |
+ // ------------------------------------------------------
+ //
+ // Vector clip reverse
+
+ rsp.flag[0] = 0;
+ rsp.flag[1] = 0;
+ rsp.flag[2] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT16 s1 = R_VREG_S(VS1REG, del);
+ INT16 s2 = R_VREG_S(VS2REG, sel);
+
+ if ((INT16)(s1 ^ s2) < 0)
+ {
+ if (s2 < 0)
+ {
+ rsp.flag[1] |= (1 << (8+del));
+ }
+ if ((s1 + s2) <= 0)
+ {
+ W_ACCUM_L(del, ~((UINT16)s2));
+ SET_COMPARE_FLAG(del);
+ }
+ else
+ {
+ W_ACCUM_L(del, s1);
+ }
+ }
+ else
+ {
+ if (s2 < 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ if ((s1 - s2) >= 0)
+ {
+ W_ACCUM_L(del, s2);
+ rsp.flag[1] |= (1 << (8+del));
+ }
+ else
+ {
+ W_ACCUM_L(del, s1);
+ }
+ }
+
+ vres[del] = R_ACCUM_L(del);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x27: /* VMRG */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 |
+ // ------------------------------------------------------
+ //
+ // Merges two vectors according to compare flags
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ if (COMPARE_FLAG(del) != 0)
+ {
+ vres[del] = R_VREG_S(VS1REG, del);
+ }
+ else
+ {
+ vres[del] = R_VREG_S(VS2REG, VEC_EL_2(EL, sel));
+ }
+
+ W_ACCUM_L(del, vres[del]);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x28: /* VAND */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 |
+ // ------------------------------------------------------
+ //
+ // Bitwise AND of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = R_VREG_S(VS1REG, del) & R_VREG_S(VS2REG, sel);
+ W_ACCUM_L(del, vres[del]);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x29: /* VNAND */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 |
+ // ------------------------------------------------------
+ //
+ // Bitwise NOT AND of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = ~((R_VREG_S(VS1REG, del) & R_VREG_S(VS2REG, sel)));
+ W_ACCUM_L(del, vres[del]);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x2a: /* VOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 |
+ // ------------------------------------------------------
+ //
+ // Bitwise OR of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = R_VREG_S(VS1REG, del) | R_VREG_S(VS2REG, sel);
+ W_ACCUM_L(del, vres[del]);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x2b: /* VNOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 |
+ // ------------------------------------------------------
+ //
+ // Bitwise NOT OR of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = ~((R_VREG_S(VS1REG, del) | R_VREG_S(VS2REG, sel)));
+ W_ACCUM_L(del, vres[del]);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x2c: /* VXOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 |
+ // ------------------------------------------------------
+ //
+ // Bitwise XOR of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = R_VREG_S(VS1REG, del) ^ R_VREG_S(VS2REG, sel);
+ W_ACCUM_L(del, vres[del]);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x2d: /* VNXOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 |
+ // ------------------------------------------------------
+ //
+ // Bitwise NOT XOR of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = ~((R_VREG_S(VS1REG, del) ^ R_VREG_S(VS2REG, sel)));
+ W_ACCUM_L(del, vres[del]);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x30: /* VRCP */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal
+
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+ INT32 rec;
+
+ rec = (INT16)(R_VREG_S(VS2REG, sel));
+
+ if (rec == 0)
+ {
+ // divide by zero -> overflow
+ rec = 0x7fffffff;
+ }
+ else
+ {
+ int negative = 0;
+ if (rec < 0)
+ {
+ rec = ~rec+1;
+ negative = 1;
+ }
+ for (i = 15; i > 0; i--)
+ {
+ if (rec & (1 << i))
+ {
+ rec &= ((0xffc0) >> (15 - i));
+ i = 0;
+ }
+ }
+ rec = (INT32)(0x7fffffff / (double)rec);
+ for (i = 31; i > 0; i--)
+ {
+ if (rec & (1 << i))
+ {
+ rec &= ((0xffff8000) >> (31 - i));
+ i = 0;
+ }
+ }
+ if (negative)
+ {
+ rec = ~rec;
+ }
+ }
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ W_ACCUM_L(i, R_VREG_S(VS2REG, element));
+ }
+
+ rsp.reciprocal_res = rec;
+
+ W_VREG_S(VDREG, del, (UINT16)(rsp.reciprocal_res)); // store low part
+ break;
+ }
+
+ case 0x31: /* VRCPL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal low part
+
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+ INT32 rec;
+
+ rec = ((UINT16)(R_VREG_S(VS2REG, sel)) | ((UINT32)(rsp.reciprocal_high) << 16));
+
+ if (rec == 0)
+ {
+ // divide by zero -> overflow
+ rec = 0x7fffffff;
+ }
+ else
+ {
+ int negative = 0;
+ if (rec < 0)
+ {
+ if (((UINT32)(rec & 0xffff0000) == 0xffff0000) && ((INT16)(rec & 0xffff) < 0))
+ {
+ rec = ~rec+1;
+ }
+ else
+ {
+ rec = ~rec;
+ }
+ negative = 1;
+ }
+ for (i = 31; i > 0; i--)
+ {
+ if (rec & (1 << i))
+ {
+ rec &= ((0xffc00000) >> (31 - i));
+ i = 0;
+ }
+ }
+ rec = (0x7fffffff / rec);
+ for (i = 31; i > 0; i--)
+ {
+ if (rec & (1 << i))
+ {
+ rec &= ((0xffff8000) >> (31 - i));
+ i = 0;
+ }
+ }
+ if (negative)
+ {
+ rec = ~rec;
+ }
+ }
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ W_ACCUM_L(i, R_VREG_S(VS2REG, element));
+ }
+
+ rsp.reciprocal_res = rec;
+
+ W_VREG_S(VDREG, del, (UINT16)(rsp.reciprocal_res)); // store low part
+ break;
+ }
+
+ case 0x32: /* VRCPH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal high part
+
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+
+ rsp.reciprocal_high = R_VREG_S(VS2REG, sel);
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ W_ACCUM_L(i, R_VREG_S(VS2REG, element)); // perhaps accumulator is used to store the intermediate values ?
+ }
+
+ W_VREG_S(VDREG, del, (INT16)(rsp.reciprocal_res >> 16)); // store high part
+ break;
+ }
+
+ case 0x33: /* VMOV */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 |
+ // ------------------------------------------------------
+ //
+ // Moves element from vector to destination vector
+
+ int element = VS1REG & 7;
+ W_VREG_S(VDREG, element, R_VREG_S(VS2REG, VEC_EL_2(EL, 7-element)));
+ break;
+ }
+
+ case 0x35: /* VRSQL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal square-root low part
+
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+ INT32 sqr;
+
+ sqr = (UINT16)(R_VREG_S(VS2REG, sel)) | ((UINT32)(rsp.square_root_high) << 16);
+
+ if (sqr == 0)
+ {
+ // square root on 0 -> overflow
+ sqr = 0x7fffffff;
+ }
+ else if (sqr == 0xffff8000)
+ {
+ // overflow ?
+ sqr = 0xffff8000;
+ }
+ else
+ {
+ int negative = 0;
+ if (sqr < 0)
+ {
+ if (((UINT32)(sqr & 0xffff0000) == 0xffff0000) && ((INT16)(sqr & 0xffff) < 0))
+ {
+ sqr = ~sqr+1;
+ }
+ else
+ {
+ sqr = ~sqr;
+ }
+ negative = 1;
+ }
+ for (i = 31; i > 0; i--)
+ {
+ if (sqr & (1 << i))
+ {
+ sqr &= (0xff800000 >> (31 - i));
+ i = 0;
+ }
+ }
+ sqr = (INT32)(0x7fffffff / sqrt(sqr));
+ for (i = 31; i > 0; i--)
+ {
+ if (sqr & (1 << i))
+ {
+ sqr &= (0xffff8000 >> (31 - i));
+ i = 0;
+ }
+ }
+ if (negative)
+ {
+ sqr = ~sqr;
+ }
+ }
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ W_ACCUM_L(i, R_VREG_S(VS2REG, element));
+ }
+
+ rsp.square_root_res = sqr;
+
+ W_VREG_S(VDREG, del, (UINT16)(rsp.square_root_res)); // store low part
+ break;
+ }
+
+ case 0x36: /* VRSQH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal square-root high part
+
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+
+ rsp.square_root_high = R_VREG_S(VS2REG, sel);
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ W_ACCUM_L(i, R_VREG_S(VS2REG, element)); // perhaps accumulator is used to store the intermediate values ?
+ }
+
+ W_VREG_S(VDREG, del, (INT16)(rsp.square_root_res >> 16)); // store high part
+ break;
+ }
+
+ default: unimplemented_opcode(op); break;
+ }
+}
+
+static int rsp_execute(int cycles)
+{
+ UINT32 op;
+
+ rsp_icount = cycles;
+
+ rsp.pc = 0x4001000 | (rsp.pc & 0xfff);
+
+ if( rsp.sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) )
+ {
+ rsp_icount = 0;
+ }
+
+ while (rsp_icount > 0)
+ {
+ rsp.ppc = rsp.pc;
+ CALL_MAME_DEBUG;
+
+ op = ROPCODE(rsp.pc);
+ if (rsp.nextpc != ~0)
+ {
+ rsp.pc = rsp.nextpc;
+ rsp.nextpc = ~0;
+ }
+ else
+ {
+ rsp.pc += 4;
+ }
+
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ {
+ switch (op & 0x3f)
+ {
+ case 0x00: /* SLL */ if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break;
+ case 0x02: /* SRL */ if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break;
+ case 0x03: /* SRA */ if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break;
+ case 0x04: /* SLLV */ if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break;
+ case 0x06: /* SRLV */ if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break;
+ case 0x07: /* SRAV */ if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break;
+ case 0x08: /* JR */ JUMP_PC(RSVAL); break;
+ case 0x09: /* JALR */ JUMP_PC_L(RSVAL, RDREG); break;
+ case 0x0d: /* BREAK */
+ {
+ sp_set_status(0x3);
+ rsp_icount = 1;
+
+#if LOG_INSTRUCTION_EXECUTION
+ fprintf(exec_output, "\n---------- break ----------\n\n");
+#endif
+ break;
+ }
+ case 0x20: /* ADD */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
+ case 0x21: /* ADDU */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
+ case 0x22: /* SUB */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
+ case 0x23: /* SUBU */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
+ case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break;
+ case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break;
+ case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break;
+ case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break;
+ case 0x2a: /* SLT */ if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break;
+ case 0x2b: /* SLTU */ if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break;
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x01: /* REGIMM */
+ {
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */ if ((INT32)(RSVAL) < 0) JUMP_REL(SIMM16); break;
+ case 0x01: /* BGEZ */ if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); break;
+ case 0x11: /* BGEZAL */ if ((INT32)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break;
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x02: /* J */ JUMP_ABS(UIMM26); break;
+ case 0x03: /* JAL */ JUMP_ABS_L(UIMM26, 31); break;
+ case 0x04: /* BEQ */ if (RSVAL == RTVAL) JUMP_REL(SIMM16); break;
+ case 0x05: /* BNE */ if (RSVAL != RTVAL) JUMP_REL(SIMM16); break;
+ case 0x06: /* BLEZ */ if ((INT32)RSVAL <= 0) JUMP_REL(SIMM16); break;
+ case 0x07: /* BGTZ */ if ((INT32)RSVAL > 0) JUMP_REL(SIMM16); break;
+ case 0x08: /* ADDI */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
+ case 0x09: /* ADDIU */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
+ case 0x0a: /* SLTI */ if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break;
+ case 0x0b: /* SLTIU */ if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break;
+ case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMM16; break;
+ case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMM16; break;
+ case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMM16; break;
+ case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMM16 << 16; break;
+
+ case 0x10: /* COP0 */
+ {
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC0 */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break;
+ case 0x04: /* MTC0 */ set_cop0_reg(RDREG, RTVAL); break;
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x12: /* COP2 */
+ {
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+
+ int el = (op >> 7) & 0xf;
+ UINT16 b1 = R_VREG_B(VS1REG, (el+0) & 0xf);
+ UINT16 b2 = R_VREG_B(VS1REG, (el+1) & 0xf);
+ if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2));
+ break;
+ }
+ case 0x02: /* CFC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ if (RTREG) RTVAL = rsp.flag[RDREG];
+ break;
+ }
+ case 0x04: /* MTC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+
+ int el = (op >> 7) & 0xf;
+ W_VREG_B(VS1REG, (el+0) & 0xf, (RTVAL >> 8) & 0xff);
+ W_VREG_B(VS1REG, (el+1) & 0xf, (RTVAL >> 0) & 0xff);
+ break;
+ }
+ case 0x06: /* CTC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ rsp.flag[RDREG] = RTVAL & 0xffff;
+ break;
+ }
+
+ 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:
+ {
+ handle_vector_ops(op);
+ break;
+ }
+
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x20: /* LB */ if (RTREG) RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); break;
+ case 0x21: /* LH */ if (RTREG) RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); break;
+ case 0x23: /* LW */ if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break;
+ case 0x24: /* LBU */ if (RTREG) RTVAL = (UINT8)READ8(RSVAL + SIMM16); break;
+ case 0x25: /* LHU */ if (RTREG) RTVAL = (UINT16)READ16(RSVAL + SIMM16); break;
+ case 0x28: /* SB */ WRITE8(RSVAL + SIMM16, RTVAL); break;
+ case 0x29: /* SH */ WRITE16(RSVAL + SIMM16, RTVAL); break;
+ case 0x2b: /* SW */ WRITE32(RSVAL + SIMM16, RTVAL); break;
+ case 0x32: /* LWC2 */ handle_lwc2(op); break;
+ case 0x3a: /* SWC2 */ handle_swc2(op); break;
+
+ default:
+ {
+ unimplemented_opcode(op);
+ break;
+ }
+ }
+
+#if LOG_INSTRUCTION_EXECUTION
+ {
+ int i, l;
+ static UINT32 prev_regs[32];
+ static VECTOR_REG prev_vecs[32];
+ char string[200];
+ rsp_dasm_one(string, rsp.ppc, op);
+
+ fprintf(exec_output, "%08X: %s", rsp.ppc, string);
+
+ l = strlen(string);
+ if (l < 36)
+ {
+ for (i=l; i < 36; i++)
+ {
+ fprintf(exec_output, " ");
+ }
+ }
+
+ fprintf(exec_output, "| ");
+
+ for (i=0; i < 32; i++)
+ {
+ if (rsp.r[i] != prev_regs[i])
+ {
+ fprintf(exec_output, "R%d: %08X ", i, rsp.r[i]);
+ }
+ prev_regs[i] = rsp.r[i];
+ }
+
+ for (i=0; i < 32; i++)
+ {
+ if (rsp.v[i].d[0] != prev_vecs[i].d[0] || rsp.v[i].d[1] != prev_vecs[i].d[1])
+ {
+ fprintf(exec_output, "V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X ", i,
+ (UINT16)R_VREG_S(i,0), (UINT16)R_VREG_S(i,1), (UINT16)R_VREG_S(i,2), (UINT16)R_VREG_S(i,3), (UINT16)R_VREG_S(i,4), (UINT16)R_VREG_S(i,5), (UINT16)R_VREG_S(i,6), (UINT16)R_VREG_S(i,7));
+ }
+ prev_vecs[i].d[0] = rsp.v[i].d[0];
+ prev_vecs[i].d[1] = rsp.v[i].d[1];
+ }
+
+ fprintf(exec_output, "\n");
+
+ }
+#endif
+
+ --rsp_icount;
+
+ if( rsp.sr & RSP_STATUS_SSTEP )
+ {
+ rsp.sr |= RSP_STATUS_BROKE;
+ }
+
+ if( rsp.sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) )
+ {
+ rsp_icount = 0;
+ }
+
+ }
+
+ return cycles - rsp_icount;
+}
+
+
+
+
+/*****************************************************************************/
+
+static void rsp_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(RSP_REGS *)dst = rsp;
+}
+
+
+static void rsp_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ rsp = *(RSP_REGS *)src;
+}
+
+
+/*****************************************************************************/
+
+#ifdef MAME_DEBUG
+static offs_t rsp_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 op = LITTLE_ENDIANIZE_INT32(*(UINT32 *)opram);
+ return rsp_dasm_one(buffer, pc, op);
+}
+#endif /* MAME_DEBUG */
+
+/*****************************************************************************/
+
+static void rsp_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + RSP_PC: rsp.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R0: rsp.r[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R1: rsp.r[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R2: rsp.r[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R3: rsp.r[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R4: rsp.r[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R5: rsp.r[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R6: rsp.r[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R7: rsp.r[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R8: rsp.r[8] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R9: rsp.r[9] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R10: rsp.r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R11: rsp.r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R12: rsp.r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R13: rsp.r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R14: rsp.r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R15: rsp.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R16: rsp.r[16] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R17: rsp.r[17] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R18: rsp.r[18] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R19: rsp.r[19] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R20: rsp.r[20] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R21: rsp.r[21] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R22: rsp.r[22] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R23: rsp.r[23] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R24: rsp.r[24] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R25: rsp.r[25] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R26: rsp.r[26] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R27: rsp.r[27] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R28: rsp.r[28] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R29: rsp.r[29] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_R30: rsp.r[30] = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + RSP_R31: rsp.r[31] = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_SR: rsp.sr = info->i; break;
+ case CPUINFO_INT_REGISTER + RSP_NEXTPC: rsp.nextpc = info->i; break;
+ }
+}
+
+void rsp_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(rsp); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = rsp.ppc; break;
+
+ case CPUINFO_INT_PC: /* intentional fallthrough */
+ case CPUINFO_INT_REGISTER + RSP_PC: info->i = rsp.pc; break;
+
+ case CPUINFO_INT_REGISTER + RSP_R0: info->i = rsp.r[0]; break;
+ case CPUINFO_INT_REGISTER + RSP_R1: info->i = rsp.r[1]; break;
+ case CPUINFO_INT_REGISTER + RSP_R2: info->i = rsp.r[2]; break;
+ case CPUINFO_INT_REGISTER + RSP_R3: info->i = rsp.r[3]; break;
+ case CPUINFO_INT_REGISTER + RSP_R4: info->i = rsp.r[4]; break;
+ case CPUINFO_INT_REGISTER + RSP_R5: info->i = rsp.r[5]; break;
+ case CPUINFO_INT_REGISTER + RSP_R6: info->i = rsp.r[6]; break;
+ case CPUINFO_INT_REGISTER + RSP_R7: info->i = rsp.r[7]; break;
+ case CPUINFO_INT_REGISTER + RSP_R8: info->i = rsp.r[8]; break;
+ case CPUINFO_INT_REGISTER + RSP_R9: info->i = rsp.r[9]; break;
+ case CPUINFO_INT_REGISTER + RSP_R10: info->i = rsp.r[10]; break;
+ case CPUINFO_INT_REGISTER + RSP_R11: info->i = rsp.r[11]; break;
+ case CPUINFO_INT_REGISTER + RSP_R12: info->i = rsp.r[12]; break;
+ case CPUINFO_INT_REGISTER + RSP_R13: info->i = rsp.r[13]; break;
+ case CPUINFO_INT_REGISTER + RSP_R14: info->i = rsp.r[14]; break;
+ case CPUINFO_INT_REGISTER + RSP_R15: info->i = rsp.r[15]; break;
+ case CPUINFO_INT_REGISTER + RSP_R16: info->i = rsp.r[16]; break;
+ case CPUINFO_INT_REGISTER + RSP_R17: info->i = rsp.r[17]; break;
+ case CPUINFO_INT_REGISTER + RSP_R18: info->i = rsp.r[18]; break;
+ case CPUINFO_INT_REGISTER + RSP_R19: info->i = rsp.r[19]; break;
+ case CPUINFO_INT_REGISTER + RSP_R20: info->i = rsp.r[20]; break;
+ case CPUINFO_INT_REGISTER + RSP_R21: info->i = rsp.r[21]; break;
+ case CPUINFO_INT_REGISTER + RSP_R22: info->i = rsp.r[22]; break;
+ case CPUINFO_INT_REGISTER + RSP_R23: info->i = rsp.r[23]; break;
+ case CPUINFO_INT_REGISTER + RSP_R24: info->i = rsp.r[24]; break;
+ case CPUINFO_INT_REGISTER + RSP_R25: info->i = rsp.r[25]; break;
+ case CPUINFO_INT_REGISTER + RSP_R26: info->i = rsp.r[26]; break;
+ case CPUINFO_INT_REGISTER + RSP_R27: info->i = rsp.r[27]; break;
+ case CPUINFO_INT_REGISTER + RSP_R28: info->i = rsp.r[28]; break;
+ case CPUINFO_INT_REGISTER + RSP_R29: info->i = rsp.r[29]; break;
+ case CPUINFO_INT_REGISTER + RSP_R30: info->i = rsp.r[30]; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + RSP_R31: info->i = rsp.r[31]; break;
+ case CPUINFO_INT_REGISTER + RSP_SR: info->i = rsp.sr; break;
+ case CPUINFO_INT_REGISTER + RSP_NEXTPC: info->i = rsp.nextpc; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = rsp_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = rsp_set_context; break;
+ case CPUINFO_PTR_SET_INFO: info->setinfo = rsp_set_info; break;
+ case CPUINFO_PTR_INIT: info->init = rsp_init; break;
+ case CPUINFO_PTR_RESET: info->reset = rsp_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = rsp_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = rsp_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = rsp_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &rsp_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "RSP"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "RSP"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2005"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + RSP_PC: sprintf(info->s, "PC: %08X", rsp.pc); break;
+
+ case CPUINFO_STR_REGISTER + RSP_R0: sprintf(info->s, "R0: %08X", rsp.r[0]); break;
+ case CPUINFO_STR_REGISTER + RSP_R1: sprintf(info->s, "R1: %08X", rsp.r[1]); break;
+ case CPUINFO_STR_REGISTER + RSP_R2: sprintf(info->s, "R2: %08X", rsp.r[2]); break;
+ case CPUINFO_STR_REGISTER + RSP_R3: sprintf(info->s, "R3: %08X", rsp.r[3]); break;
+ case CPUINFO_STR_REGISTER + RSP_R4: sprintf(info->s, "R4: %08X", rsp.r[4]); break;
+ case CPUINFO_STR_REGISTER + RSP_R5: sprintf(info->s, "R5: %08X", rsp.r[5]); break;
+ case CPUINFO_STR_REGISTER + RSP_R6: sprintf(info->s, "R6: %08X", rsp.r[6]); break;
+ case CPUINFO_STR_REGISTER + RSP_R7: sprintf(info->s, "R7: %08X", rsp.r[7]); break;
+ case CPUINFO_STR_REGISTER + RSP_R8: sprintf(info->s, "R8: %08X", rsp.r[8]); break;
+ case CPUINFO_STR_REGISTER + RSP_R9: sprintf(info->s, "R9: %08X", rsp.r[9]); break;
+ case CPUINFO_STR_REGISTER + RSP_R10: sprintf(info->s, "R10: %08X", rsp.r[10]); break;
+ case CPUINFO_STR_REGISTER + RSP_R11: sprintf(info->s, "R11: %08X", rsp.r[11]); break;
+ case CPUINFO_STR_REGISTER + RSP_R12: sprintf(info->s, "R12: %08X", rsp.r[12]); break;
+ case CPUINFO_STR_REGISTER + RSP_R13: sprintf(info->s, "R13: %08X", rsp.r[13]); break;
+ case CPUINFO_STR_REGISTER + RSP_R14: sprintf(info->s, "R14: %08X", rsp.r[14]); break;
+ case CPUINFO_STR_REGISTER + RSP_R15: sprintf(info->s, "R15: %08X", rsp.r[15]); break;
+ case CPUINFO_STR_REGISTER + RSP_R16: sprintf(info->s, "R16: %08X", rsp.r[16]); break;
+ case CPUINFO_STR_REGISTER + RSP_R17: sprintf(info->s, "R17: %08X", rsp.r[17]); break;
+ case CPUINFO_STR_REGISTER + RSP_R18: sprintf(info->s, "R18: %08X", rsp.r[18]); break;
+ case CPUINFO_STR_REGISTER + RSP_R19: sprintf(info->s, "R19: %08X", rsp.r[19]); break;
+ case CPUINFO_STR_REGISTER + RSP_R20: sprintf(info->s, "R20: %08X", rsp.r[20]); break;
+ case CPUINFO_STR_REGISTER + RSP_R21: sprintf(info->s, "R21: %08X", rsp.r[21]); break;
+ case CPUINFO_STR_REGISTER + RSP_R22: sprintf(info->s, "R22: %08X", rsp.r[22]); break;
+ case CPUINFO_STR_REGISTER + RSP_R23: sprintf(info->s, "R23: %08X", rsp.r[23]); break;
+ case CPUINFO_STR_REGISTER + RSP_R24: sprintf(info->s, "R24: %08X", rsp.r[24]); break;
+ case CPUINFO_STR_REGISTER + RSP_R25: sprintf(info->s, "R25: %08X", rsp.r[25]); break;
+ case CPUINFO_STR_REGISTER + RSP_R26: sprintf(info->s, "R26: %08X", rsp.r[26]); break;
+ case CPUINFO_STR_REGISTER + RSP_R27: sprintf(info->s, "R27: %08X", rsp.r[27]); break;
+ case CPUINFO_STR_REGISTER + RSP_R28: sprintf(info->s, "R28: %08X", rsp.r[28]); break;
+ case CPUINFO_STR_REGISTER + RSP_R29: sprintf(info->s, "R29: %08X", rsp.r[29]); break;
+ case CPUINFO_STR_REGISTER + RSP_R30: sprintf(info->s, "R30: %08X", rsp.r[30]); break;
+ case CPUINFO_STR_REGISTER + RSP_R31: sprintf(info->s, "R31: %08X", rsp.r[31]); break;
+ case CPUINFO_STR_REGISTER + RSP_SR: sprintf(info->s, "SR: %08X", rsp.sr); break;
+ case CPUINFO_STR_REGISTER + RSP_NEXTPC: sprintf(info->s, "NPC: %08X", rsp.nextpc);break;
+ }
+}
diff --git a/src/emu/cpu/rsp/rsp.h b/src/emu/cpu/rsp/rsp.h
new file mode 100644
index 00000000000..345e7ae1543
--- /dev/null
+++ b/src/emu/cpu/rsp/rsp.h
@@ -0,0 +1,65 @@
+#ifndef _RSP_H
+#define _RSP_H
+
+enum
+{
+ RSP_PC = 1,
+ RSP_R0,
+ RSP_R1,
+ RSP_R2,
+ RSP_R3,
+ RSP_R4,
+ RSP_R5,
+ RSP_R6,
+ RSP_R7,
+ RSP_R8,
+ RSP_R9,
+ RSP_R10,
+ RSP_R11,
+ RSP_R12,
+ RSP_R13,
+ RSP_R14,
+ RSP_R15,
+ RSP_R16,
+ RSP_R17,
+ RSP_R18,
+ RSP_R19,
+ RSP_R20,
+ RSP_R21,
+ RSP_R22,
+ RSP_R23,
+ RSP_R24,
+ RSP_R25,
+ RSP_R26,
+ RSP_R27,
+ RSP_R28,
+ RSP_R29,
+ RSP_R30,
+ RSP_R31,
+ RSP_SR,
+ RSP_NEXTPC,
+};
+
+#define RSP_STATUS_HALT 0x0001
+#define RSP_STATUS_BROKE 0x0002
+#define RSP_STATUS_DMABUSY 0x0004
+#define RSP_STATUS_DMAFULL 0x0008
+#define RSP_STATUS_IOFULL 0x0010
+#define RSP_STATUS_SSTEP 0x0020
+#define RSP_STATUS_INTR_BREAK 0x0040
+#define RSP_STATUS_SIGNAL0 0x0080
+#define RSP_STATUS_SIGNAL1 0x0100
+#define RSP_STATUS_SIGNAL2 0x0200
+#define RSP_STATUS_SIGNAL3 0x0400
+#define RSP_STATUS_SIGNAL4 0x0800
+#define RSP_STATUS_SIGNAL5 0x1000
+#define RSP_STATUS_SIGNAL6 0x2000
+#define RSP_STATUS_SIGNAL7 0x4000
+
+void rsp_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op);
+#endif
+
+#endif
diff --git a/src/emu/cpu/rsp/rsp_dasm.c b/src/emu/cpu/rsp/rsp_dasm.c
new file mode 100644
index 00000000000..b78e818482b
--- /dev/null
+++ b/src/emu/cpu/rsp/rsp_dasm.c
@@ -0,0 +1,345 @@
+/*
+ Nintendo/SGI RSP Disassembler
+
+ Written by Ville Linde
+*/
+
+#include "cpuintrf.h"
+#include <stdarg.h>
+
+static const char *reg[32] =
+{
+ "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+static const char *vreg[32] =
+{
+ " v0", " v1", " v2", " v3", " v4", " v5", " v6", " v7",
+ " v8", " v9", "v10", "v11", "v12", "v13", "v14", "v15",
+ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
+};
+
+static const char *cop0_regs[32] =
+{
+ "SP_MEM_ADDR", "SP_DRAM_ADDR", "SP_RD_LEN", "SP_WR_LEN",
+ "SP_STATUS", "SP_DMA_FULL", "SP_DMA_BUSY", "SP_SEMAPHORE",
+ "DPC_START", "DPC_END", "DPC_CURRENT", "DPC_STATUS",
+ "DPC_CLOCK", "DPC_BUFBUSY", "DPC_PIPEBUSY", "DPC_TMEM",
+ "???", "???", "???", "???",
+ "???", "???", "???", "???",
+ "???", "???", "???", "???",
+ "???", "???", "???", "???"
+};
+
+static const char *element[16] =
+{
+ "", "[???]", "[00224466]", "[11335577]", "[00004444]", "[11115555]", "[22226666]", "[33337777]",
+ "[00000000]", "[11111111]", "[22222222]", "[33333333]", "[44444444]", "[55555555]", "[66666666]", "[77777777]"
+};
+
+static const char *element2[16] =
+{
+ "01234567", "????????", "00224466", "11335577", "00004444", "11115555", "22226666", "33337777",
+ "00000000", "11111111", "22222222", "33333333", "44444444", "55555555", "66666666", "77777777"
+};
+
+INLINE char *signed_imm16(UINT32 op)
+{
+ static char temp[10];
+ INT16 value = op & 0xffff;
+
+ if (value < 0)
+ {
+ sprintf(temp, "-$%04x", -value);
+ }
+ else
+ {
+ sprintf(temp, "$%04x", value);
+ }
+ return temp;
+}
+
+
+static char *output;
+
+static void print(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ output += vsprintf(output, fmt, vl);
+ va_end(vl);
+}
+
+static void disasm_cop0(UINT32 op)
+{
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: print("mfc0 %s, %s", reg[rt], cop0_regs[rd]); break;
+ case 0x04: print("mtc0 %s, %s", reg[rt], cop0_regs[rd]); break;
+
+ default: print("??? (COP0)"); break;
+ }
+}
+
+static void disasm_cop2(UINT32 op)
+{
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ int el = (op >> 21) & 0xf;
+ int dest = (op >> 6) & 0x1f;
+ int s1 = rd;
+ int s2 = rt;
+
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: print("mfc2 %s, %s[%d]", reg[rt], vreg[rd], dest); break;
+ case 0x02: print("cfc2 %s, FLAG%d", reg[rt], rd); break;
+ case 0x04: print("mtc2 %s, %s[%d]", reg[rt], vreg[rd], dest); break;
+ case 0x06: print("ctc2 %s, FLAG%d", reg[rt], rd); break;
+
+ 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:
+ {
+ switch (op & 0x3f)
+ {
+ case 0x00: print("vmulf %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x01: print("vmulu %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x02: print("vrndp %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x03: print("vmulq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x04: print("vmudl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x05: print("vmudm %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x06: print("vmudn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x07: print("vmudh %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x08: print("vmacf %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x09: print("vmacu %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0a: print("vrndn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0b: print("vmacq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0c: print("vmadl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0d: print("vmadm %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0e: print("vmadn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0f: print("vmadh %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x10: print("vadd %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x11: print("vsub %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x12: print("vsut???"); break;
+ case 0x13: print("vabs %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x14: print("vaddc %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x15: print("vsubc %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+
+ case 0x1d:
+ {
+ switch (el)
+ {
+ case 8: print("vsaw %s, ACCUM_H", vreg[dest]); break;
+ case 9: print("vsaw %s, ACCUM_M", vreg[dest]); break;
+ case 10: print("vsaw %s, ACCUM_L", vreg[dest]); break;
+ default: print("vsaw %s, ???", vreg[dest]); break;
+ }
+ break;
+ }
+
+ case 0x20: print("vlt %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x21: print("veq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x22: print("vne %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x23: print("vge %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x24: print("vcl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x25: print("vch %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x26: print("vcr %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x27: print("vmrg %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x28: print("vand %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x29: print("vnand %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x2a: print("vor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x2b: print("vnor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x2c: print("vxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x2d: print("vnxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x30: print("vrcp %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x31: print("vrcpl %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x32: print("vrcph %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x33: print("vmov %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x34: print("vrsq %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x35: print("vrsql %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x36: print("vrsqh %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x37: print("vnop"); break;
+ default: print("??? (VECTOR OP)"); break;
+ }
+ break;
+ }
+
+ default: print("??? (COP2)"); break;
+ }
+}
+
+static void disasm_lwc2(UINT32 op)
+{
+ int dest = (op >> 16) & 0x1f;
+ int base = (op >> 21) & 0x1f;
+ int del = (op >> 7) & 0xf;
+ int offset = (op & 0x7f);
+ if (offset & 0x40)
+ offset |= 0xffffff80;
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: print("lbv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 1), reg[base]); break;
+ case 0x01: print("lsv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 2), reg[base]); break;
+ case 0x02: print("llv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 4), reg[base]); break;
+ case 0x03: print("ldv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x04: print("lqv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x05: print("lrv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x06: print("lpv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x07: print("luv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x08: print("lhv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x09: print("lfv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x0a: print("lwv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x0b: print("ltv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ default: print("??? (LWC2)"); break;
+ }
+}
+
+static void disasm_swc2(UINT32 op)
+{
+ int dest = (op >> 16) & 0x1f;
+ int base = (op >> 21) & 0x1f;
+ int del = (op >> 7) & 0xf;
+ int offset = (op & 0x7f);
+ if (offset & 0x40)
+ offset |= 0xffffff80;
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: print("sbv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 1), reg[base]); break;
+ case 0x01: print("ssv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 2), reg[base]); break;
+ case 0x02: print("slv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 4), reg[base]); break;
+ case 0x03: print("sdv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x04: print("sqv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x05: print("srv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x06: print("spv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x07: print("suv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x08: print("shv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x09: print("sfv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x0a: print("swv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x0b: print("stv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ default: print("??? (SWC2)"); break;
+ }
+}
+
+offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op)
+{
+ int rs = (op >> 21) & 31;
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ int shift = (op >> 6) & 31;
+ UINT32 flags = 0;
+
+ output = buffer;
+
+ switch (op >> 26)
+ {
+ case 0x00: // SPECIAL
+ {
+ switch (op & 0x3f)
+ {
+ case 0x00:
+ {
+ if (op == 0)
+ {
+ print("nop");
+ }
+ else
+ {
+ print("sll %s, %s, %d", reg[rd], reg[rt], shift);
+ }
+ break;
+ }
+ case 0x02: print("srl %s, %s, %d", reg[rd], reg[rt], shift); break;
+ case 0x03: print("sra %s, %s, %d", reg[rd], reg[rt], shift); break;
+ case 0x04: print("sllv %s, %s, %s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x06: print("srlv %s, %s, %s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x07: print("srav %s, %s, %s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x08: print("jr %s", reg[rs]); if (rs == 31) flags = DASMFLAG_STEP_OUT; break;
+ case 0x09:
+ {
+ if (rd == 31)
+ {
+ print("jalr %s", reg[rs]);
+ }
+ else
+ {
+ print("jalr %s, %s", reg[rs], reg[rd]);
+ }
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ break;
+ }
+ case 0x0d: print("break"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x20: print("add %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x21: print("addu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x22: print("sub %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x23: print("subu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x24: print("and %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x25: print("or %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x26: print("xor %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x27: print("nor %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2a: print("slt %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2b: print("sltu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+
+ default: print("???"); break;
+ }
+ break;
+ }
+
+ case 0x01: // REGIMM
+ {
+ switch ((op >> 16) & 0x1f)
+ {
+ case 0x00: print("bltz %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x01: print("bgez %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x10: print("bltzal %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x11: print("bgezal %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+
+ default: print("???"); break;
+ }
+ break;
+ }
+
+ case 0x02: print("j $%08X", (op & 0x03ffffff) << 2); break;
+ case 0x03: print("jal $%08X", (op & 0x03ffffff) << 2); break;
+ case 0x04: print("beq %s, %s, $%08X", reg[rs], reg[rt], pc + 4 + ((INT16)(op) << 2)); break;
+ case 0x05: print("bne %s, %s, $%08X", reg[rs], reg[rt], pc + 4 + ((INT16)(op) << 2)); break;
+ case 0x06: print("blez %s, $%08X", reg[rs], pc + 4 + ((INT16)(op) << 2)); break;
+ case 0x07: print("bgtz %s, $%08X", reg[rs], pc + 4 + ((INT16)(op) << 2)); break;
+ case 0x08: print("addi %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break;
+ case 0x09: print("addiu %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break;
+ case 0x0a: print("slti %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break;
+ case 0x0b: print("sltiu %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break;
+ case 0x0c: print("andi %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break;
+ case 0x0d: print("ori %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break;
+ case 0x0e: print("xori %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break;
+ case 0x0f: print("lui %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break;
+
+ case 0x10: disasm_cop0(op); break;
+ case 0x12: disasm_cop2(op); break;
+
+ case 0x20: print("lb %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x21: print("lh %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x23: print("lw %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x24: print("lbu %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x25: print("lhu %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x28: print("sb %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x29: print("sh %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x2b: print("sw %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+
+ case 0x32: disasm_lwc2(op); break;
+ case 0x3a: disasm_swc2(op); break;
+
+ default: print("???"); break;
+ }
+
+ return 4 | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/s2650/2650dasm.c b/src/emu/cpu/s2650/2650dasm.c
new file mode 100644
index 00000000000..3248b5bbdd8
--- /dev/null
+++ b/src/emu/cpu/s2650/2650dasm.c
@@ -0,0 +1,852 @@
+/***************************************************************************
+ *
+ * Portable Signetics 2650 disassembler
+ *
+ * Written by J. Buchmueller (pullmoll@t-online.de)
+ * for the MAME project
+ *
+ **************************************************************************/
+
+#include "cpuintrf.h"
+
+static const UINT8 *rambase;
+static offs_t pcbase;
+
+#define readarg(A) (rambase[(A) - pcbase])
+
+/* Set this to 1 to disassemble using Z80 style mnemonics */
+#define HJB 0
+
+/* Set this to 1 to give names to condition codes and flag bits */
+#define MNEMO 1
+
+/* handy table to build relative offsets from HR (holding register) */
+static int rel[0x100] = {
+ 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,
+ -64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,
+ -48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,
+ -32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,
+ -16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
+ 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,
+ -64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,
+ -48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,
+ -32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,
+ -16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
+};
+
+typedef char* (*callback) (int addr);
+static callback find_symbol = 0;
+
+static char *SYM(int addr)
+{
+ static char buff[8+1];
+ char * s = NULL;
+
+ if (find_symbol) s = (*find_symbol)(addr);
+ if (s) return s;
+
+ sprintf(buff, "$%04x", addr);
+ return buff;
+}
+
+/* format an immediate */
+static char *IMM(int pc)
+{
+ static char buff[32];
+
+ sprintf(buff, "$%02x", readarg(pc));
+ return buff;
+}
+
+#if MNEMO
+static char cc[4] = { 'z', 'p', 'm', 'a' };
+
+/* format an immediate for PSL */
+static char *IMM_PSL(int pc)
+{
+ static char buff[32];
+ char *p = buff;
+ int v = readarg(pc);
+
+ if (v == 0xff) {
+ p += sprintf(p, "all");
+ } else {
+ switch (v & 0xc0)
+ {
+ case 0x40: p += sprintf(p, "p+"); break;
+ case 0x80: p += sprintf(p, "m+"); break;
+ case 0xc0: p += sprintf(p, "cc+"); break;
+ }
+ if (v & 0x20) /* inter digit carry */
+ p += sprintf(p, "idc+");
+ if (v & 0x10) /* register select */
+ p += sprintf(p, "rs+");
+ if (v & 0x08) /* with carry */
+ p += sprintf(p, "wc+");
+ if (v & 0x04) /* overflow */
+ p += sprintf(p, "ovf+");
+ if (v & 0x02) /* 2's complement comparisons */
+ p += sprintf(p, "com+");
+ if (v & 0x01) /* carry */
+ p += sprintf(p, "c+");
+ if (p > buff)
+ *--p = '\0';
+ }
+ return buff;
+}
+
+/* format an immediate for PSU (processor status upper) */
+static char *IMM_PSU(int pc)
+{
+ static char buff[32];
+ char *p = buff;
+ int v = readarg(pc);
+
+ if (v == 0xff) {
+
+ p += sprintf(p, "all");
+
+ } else {
+
+ if (v & 0x80) /* sign */
+ p += sprintf(p, "m+");
+ if (v & 0x40)
+ p += sprintf(p, "p+");
+ if (v & 0x20) /* interrupt inhibit */
+ p += sprintf(p, "ii+");
+ if (v & 0x10) /* unused bit 4 */
+ p += sprintf(p, "4+");
+ if (v & 0x08) /* unused bit 3 */
+ p += sprintf(p, "3+");
+ if (v & 0x04) /* stack pointer bit 2 */
+ p += sprintf(p, "sp2+");
+ if (v & 0x02) /* stack pointer bit 1 */
+ p += sprintf(p, "sp1+");
+ if (v & 0x01) /* stack pointer bit 0 */
+ p += sprintf(p, "sp0+");
+ if (p > buff)
+ *--p = '\0';
+ }
+ return buff;
+}
+#else
+static char cc[4] = { '0', '1', '2', '3' };
+#define IMM_PSL IMM
+#define IMM_PSU IMM
+#endif
+
+/* format an relative address */
+static char *REL(int pc)
+{
+static char buff[32];
+int o = readarg(pc);
+ sprintf(buff, "%s%s", (o&0x80)?"*":"", SYM((pc&0x6000)+((pc+1+rel[o])&0x1fff)));
+ return buff;
+}
+
+/* format an relative address (implicit page 0) */
+static char *REL0(int pc)
+{
+static char buff[32];
+int o = readarg(pc);
+ sprintf(buff, "%s%s", (o&0x80)?"*":"", SYM((rel[o]) & 0x1fff));
+ return buff;
+}
+
+/* format a destination register and an absolute address */
+static char *ABS(int load, int r, int pc)
+{
+ static char buff[32];
+ int h = readarg(pc);
+ int l = readarg((pc&0x6000)+((pc+1)&0x1fff));
+ int a = (pc & 0x6000) + ((h & 0x1f) << 8) + l;
+
+#if HJB
+ if (load) {
+ switch (h >> 5) {
+ case 0: sprintf(buff, "r%d,(%s)", r, SYM(a)); break;
+ case 1: sprintf(buff, "r0,(%s,r%d++)", SYM(a), r); break;
+ case 2: sprintf(buff, "r0,(%s,r%d--)", SYM(a), r); break;
+ case 3: sprintf(buff, "r0,(%s,r%d)", SYM(a), r); break;
+ case 4: sprintf(buff, "r%d,*(%s)", r, SYM(a)); break;
+ case 5: sprintf(buff, "r0,*(%s,r%d++)", SYM(a), r); break;
+ case 6: sprintf(buff, "r0,*(%s,r%d--)", SYM(a), r); break;
+ case 7: sprintf(buff, "r0,*(%s,r%d)", SYM(a), r); break;
+ }
+ } else {
+ switch (h >> 5) {
+ case 0: sprintf(buff, "(%s),r%d", SYM(a), r); break;
+ case 1: sprintf(buff, "(%s,r%d++),r0", SYM(a), r); break;
+ case 2: sprintf(buff, "(%s,r%d--),r0", SYM(a), r); break;
+ case 3: sprintf(buff, "(%s,r%d),r0", SYM(a), r); break;
+ case 4: sprintf(buff, "*(%s),r%d", SYM(a), r); break;
+ case 5: sprintf(buff, "*(%s,r%d++),r0", SYM(a), r); break;
+ case 6: sprintf(buff, "*(%s,r%d--),r0", SYM(a), r); break;
+ case 7: sprintf(buff, "*(%s,r%d),r0", SYM(a), r); break;
+ }
+ }
+#else
+ switch (h >> 5) {
+ case 0: sprintf(buff, "%d %s", r, SYM(a)); break;
+ case 1: sprintf(buff, "0 %s,r%d+", SYM(a), r); break;
+ case 2: sprintf(buff, "0 %s,r%d-", SYM(a), r); break;
+ case 3: sprintf(buff, "0 %s,r%d", SYM(a), r); break;
+ case 4: sprintf(buff, "%d *%s", r, SYM(a)); break;
+ case 5: sprintf(buff, "0 *%s,r%d+", SYM(a), r); break;
+ case 6: sprintf(buff, "0 *%s,r%d-", SYM(a), r); break;
+ case 7: sprintf(buff, "0 *%s,r%d", SYM(a), r); break;
+ }
+#endif
+ return buff;
+}
+
+/* format an (branch) absolute address */
+static char *ADR(int pc)
+{
+ static char buff[32];
+ int h = readarg(pc);
+ int l = readarg((pc&0x6000)+((pc+1)&0x1fff));
+ int a = ((h & 0x7f) << 8) + l;
+ if (h & 0x80)
+ sprintf(buff, "*%s", SYM(a));
+ else
+ sprintf(buff, "%s", SYM(a));
+ return buff;
+}
+
+/* disassemble one instruction at PC into buff. return byte size of instr */
+offs_t s2650_dasm(char *buff, offs_t PC, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ int pc = PC;
+ int op = oprom[0];
+ int rv = op & 3;
+
+ rambase = opram;
+ pcbase = PC;
+
+ pc += 1;
+ switch (op)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+#if HJB
+ sprintf(buff, "ld r0,r%d", rv);
+#else
+ sprintf(buff, "lodz,%d", rv);
+#endif
+ break;
+ case 0x04: case 0x05: case 0x06: case 0x07:
+#if HJB
+ sprintf(buff, "ld r%d,%s", rv, IMM(pc));
+#else
+ sprintf(buff, "lodi,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+#if HJB
+ sprintf(buff, "ld r%d,(%s)", rv, REL(pc));
+#else
+ sprintf(buff, "lodr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+#if HJB
+ sprintf(buff, "ld %s", ABS(1,rv,pc));
+#else
+ sprintf(buff, "loda,%s", ABS(1,rv,pc));
+#endif
+ pc+=2;
+ break;
+ case 0x10: case 0x11:
+ sprintf(buff, "**** %02X",op);
+ break;
+ case 0x12:
+#if HJB
+ sprintf(buff, "ld psu,r0");
+#else
+ sprintf(buff, "spsu");
+#endif
+ break;
+ case 0x13:
+#if HJB
+ sprintf(buff, "ld psl,r0");
+#else
+ sprintf(buff, "spsl");
+#endif
+ break;
+ case 0x14: case 0x15: case 0x16: case 0x17:
+#if HJB
+ if (rv == 3)
+ sprintf(buff, "ret");
+ else
+ sprintf(buff, "ret %c", cc[rv]);
+#else
+ sprintf(buff, "retc %c", cc[rv]);
+#endif
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+#if HJB
+ if (rv == 3)
+ sprintf(buff, "jr %s", REL(pc));
+ else
+ sprintf(buff, "jr %c,%s", cc[rv], REL(pc));
+#else
+ sprintf(buff, "bctr,%c %s", cc[rv], REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+#if HJB
+ if (rv == 3)
+ sprintf(buff, "jp %s", ADR(pc));
+ else
+ sprintf(buff, "jp %c,%s", cc[rv], ADR(pc));
+#else
+ sprintf(buff, "bcta,%c %s", cc[rv], ADR(pc));
+#endif
+ pc+=2;
+ break;
+ case 0x20: case 0x21: case 0x22: case 0x23:
+#if HJB
+ sprintf(buff, "xor r0,r%d", rv);
+#else
+ sprintf(buff, "eorz,%d", rv);
+#endif
+ break;
+ case 0x24: case 0x25: case 0x26: case 0x27:
+#if HJB
+ sprintf(buff, "xor r%d,%s", rv, IMM(pc));
+#else
+ sprintf(buff, "eori,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+#if HJB
+ sprintf(buff, "xor r%d,(%s)", rv, REL(pc));
+#else
+ sprintf(buff, "eorr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+#if HJB
+ sprintf(buff, "xor %s", ABS(1,rv,pc));
+#else
+ sprintf(buff, "eora,%s", ABS(1,rv,pc));
+#endif
+ pc+=2;
+ break;
+ case 0x30: case 0x31: case 0x32: case 0x33:
+#if HJB
+ sprintf(buff, "in r%d,(ctrl)", rv);
+#else
+ sprintf(buff, "redc,%d", rv);
+#endif
+ break;
+ case 0x34: case 0x35: case 0x36: case 0x37:
+#if HJB
+ if (rv == 3)
+ sprintf(buff, "iret");
+ else
+ sprintf(buff, "iret %c", cc[rv]);
+#else
+ sprintf(buff, "rete %c", cc[rv]);
+#endif
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ case 0x38: case 0x39: case 0x3a: case 0x3b:
+#if HJB
+ if (rv == 3)
+ sprintf(buff, "calr %s", REL(pc));
+ else
+ sprintf(buff, "calr %c,%s", cc[rv], REL(pc));
+#else
+ sprintf(buff, "bstr,%c %s", cc[rv], REL(pc));
+#endif
+ pc+=1;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+#if HJB
+ if (rv == 3)
+ sprintf(buff, "call %s", ADR(pc));
+ else
+ sprintf(buff, "call %c,%s", cc[rv], ADR(pc));
+#else
+ sprintf(buff, "bsta,%c %s", cc[rv], ADR(pc));
+#endif
+ pc+=2;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0x40:
+ sprintf(buff, "halt");
+ break;
+ case 0x41: case 0x42: case 0x43:
+#if HJB
+ sprintf(buff, "and r0,r%d", rv);
+#else
+ sprintf(buff, "andz,%d", rv);
+#endif
+ break;
+ case 0x44: case 0x45: case 0x46: case 0x47:
+#if HJB
+ sprintf(buff, "and r%d,%s", rv, IMM(pc));
+#else
+ sprintf(buff, "andi,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x48: case 0x49: case 0x4a: case 0x4b:
+#if HJB
+ sprintf(buff, "and r%d,(%s)", rv, REL(pc));
+#else
+ sprintf(buff, "andr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+#if HJB
+ sprintf(buff, "and %s", ABS(1,rv,pc));
+#else
+ sprintf(buff, "anda,%s", ABS(1,rv,pc));
+#endif
+ pc+=2;
+ break;
+ case 0x50: case 0x51: case 0x52: case 0x53:
+#if HJB
+ sprintf(buff, "ror r%d", rv);
+#else
+ sprintf(buff, "rrr,%d", rv);
+#endif
+ break;
+ case 0x54: case 0x55: case 0x56: case 0x57:
+#if HJB
+ sprintf(buff, "in r%d,(%s)", rv, IMM(pc));
+#else
+ sprintf(buff, "rede,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x58: case 0x59: case 0x5a: case 0x5b:
+#if HJB
+ sprintf(buff, "jrnz r%d,%s", rv, REL(pc));
+#else
+ sprintf(buff, "brnr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x5c: case 0x5d: case 0x5e: case 0x5f:
+#if HJB
+ sprintf(buff, "jpnz r%d,%s", rv, ADR(pc));
+#else
+ sprintf(buff, "brna,%d %s", rv, ADR(pc));
+#endif
+ pc+=2;
+ break;
+ case 0x60: case 0x61: case 0x62: case 0x63:
+#if HJB
+ sprintf(buff, "or r0,r%d", rv);
+#else
+ sprintf(buff, "iorz,%d", rv);
+#endif
+ break;
+ case 0x64: case 0x65: case 0x66: case 0x67:
+#if HJB
+ sprintf(buff, "or r%d,%s", rv, IMM(pc));
+#else
+ sprintf(buff, "iori,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x68: case 0x69: case 0x6a: case 0x6b:
+#if HJB
+ sprintf(buff, "or r%d,(%s)", rv, REL(pc));
+#else
+ sprintf(buff, "iorr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+#if HJB
+ sprintf(buff, "or %s", ABS(1,rv,pc));
+#else
+ sprintf(buff, "iora,%s", ABS(1,rv,pc));
+#endif
+ pc+=2;
+ break;
+ case 0x70: case 0x71: case 0x72: case 0x73:
+#if HJB
+ sprintf(buff, "in r%d,(data)", rv);
+#else
+ sprintf(buff, "redd,%d", rv);
+#endif
+ break;
+ case 0x74:
+#if HJB
+ sprintf(buff, "res psu,%s", IMM_PSU(pc));
+#else
+ sprintf(buff, "cpsu %s", IMM_PSU(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x75:
+#if HJB
+ sprintf(buff, "res psl,%s", IMM_PSL(pc));
+#else
+ sprintf(buff, "cpsl %s", IMM_PSL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x76:
+#if HJB
+ sprintf(buff, "set psu,%s", IMM_PSU(pc));
+#else
+ sprintf(buff, "ppsu %s", IMM_PSU(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x77:
+#if HJB
+ sprintf(buff, "set psl,%s", IMM_PSL(pc));
+#else
+ sprintf(buff, "ppsl %s", IMM_PSL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x78: case 0x79: case 0x7a: case 0x7b:
+#if HJB
+ sprintf(buff, "call r%d-nz,%s", rv, REL(pc));
+#else
+ sprintf(buff, "bsnr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+#if HJB
+ sprintf(buff, "call r%d-nz,%s", rv, ADR(pc));
+#else
+ sprintf(buff, "bsna,%d %s", rv, ADR(pc));
+#endif
+ pc+=2;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0x80: case 0x81: case 0x82: case 0x83:
+#if HJB
+ sprintf(buff, "add r0,r%d", rv);
+#else
+ sprintf(buff, "addz,%d", rv);
+#endif
+ break;
+ case 0x84: case 0x85: case 0x86: case 0x87:
+#if HJB
+ sprintf(buff, "add r%d,%s", rv, IMM(pc));
+#else
+ sprintf(buff, "addi,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x88: case 0x89: case 0x8a: case 0x8b:
+#if HJB
+ sprintf(buff, "add r%d,(%s)", rv, REL(pc));
+#else
+ sprintf(buff, "addr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x8c: case 0x8d: case 0x8e: case 0x8f:
+#if HJB
+ sprintf(buff, "add %s", ABS(1,rv,pc));
+#else
+ sprintf(buff, "adda,%s", ABS(1,rv,pc));
+#endif
+ pc+=2;
+ break;
+ case 0x90: case 0x91:
+ sprintf(buff, "**** %02X",op);
+ break;
+ case 0x92:
+#if HJB
+ sprintf(buff, "ld r0,psu");
+#else
+ sprintf(buff, "lpsu");
+#endif
+ break;
+ case 0x93:
+#if HJB
+ sprintf(buff, "ld r0,psl");
+#else
+ sprintf(buff, "lpsl");
+#endif
+ break;
+ case 0x94: case 0x95: case 0x96: case 0x97:
+#if HJB
+ sprintf(buff, "daa r%d", rv);
+#else
+ sprintf(buff, "dar,%d", rv);
+#endif
+ break;
+ case 0x98: case 0x99: case 0x9a:
+#if HJB
+ sprintf(buff, "jr n%c,%s", cc[rv], REL(pc));
+#else
+ sprintf(buff, "bcfr,%c %s", cc[rv], REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x9b:
+#if HJB
+ sprintf(buff, "jr0 %s", REL0(pc));
+#else
+ sprintf(buff, "zbrr %s", REL0(pc));
+#endif
+ pc+=1;
+ break;
+ case 0x9c: case 0x9d: case 0x9e:
+#if HJB
+ sprintf(buff, "jp n%c,%s", cc[rv], ADR(pc));
+#else
+ sprintf(buff, "bcfa,%c %s", cc[rv], ADR(pc));
+#endif
+ pc+=2;
+ break;
+ case 0x9f:
+#if HJB
+ sprintf(buff, "jp %s+r3", ADR(pc));
+#else
+ sprintf(buff, "bxa %s", ADR(pc));
+#endif
+ pc+=2;
+ break;
+ case 0xa0: case 0xa1: case 0xa2: case 0xa3:
+#if HJB
+ sprintf(buff, "sub r0,r%d", rv);
+#else
+ sprintf(buff, "subz,%d", rv);
+#endif
+ break;
+ case 0xa4: case 0xa5: case 0xa6: case 0xa7:
+#if HJB
+ sprintf(buff, "sub r%d,%s", rv, IMM(pc));
+#else
+ sprintf(buff, "subi,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0xa8: case 0xa9: case 0xaa: case 0xab:
+#if HJB
+ sprintf(buff, "sub r%d,(%s)", rv, REL(pc));
+#else
+ sprintf(buff, "subr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0xac: case 0xad: case 0xae: case 0xaf:
+#if HJB
+ sprintf(buff, "sub %s", ABS(1,rv,pc));
+#else
+ sprintf(buff, "suba,%s", ABS(1,rv,pc));
+#endif
+ pc+=2;
+ break;
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3:
+#if HJB
+ sprintf(buff, "out (ctrl),r%d", rv);
+#else
+ sprintf(buff, "wrtc,%d", rv);
+#endif
+ break;
+ case 0xb4:
+#if HJB
+ sprintf(buff, "bit psu,%s", IMM_PSU(pc));
+#else
+ sprintf(buff, "tpsu %s", IMM_PSU(pc));
+#endif
+ pc+=1;
+ break;
+ case 0xb5:
+#if HJB
+ sprintf(buff, "bit psl,%s", IMM_PSL(pc));
+#else
+ sprintf(buff, "tpsl %s", IMM_PSL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0xb6: case 0xb7:
+ sprintf(buff, "**** %02X", op);
+ break;
+ case 0xb8: case 0xb9: case 0xba:
+#if HJB
+ sprintf(buff, "calr n%c,%s", cc[rv], REL(pc));
+#else
+ sprintf(buff, "bsfr,%c %s", cc[rv], REL(pc));
+#endif
+ pc+=1;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0xbb:
+#if HJB
+ sprintf(buff, "cal0 %s", REL0(pc));
+#else
+ sprintf(buff, "zbsr %s", REL0(pc));
+#endif
+ pc+=1;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0xbc: case 0xbd: case 0xbe:
+#if HJB
+ sprintf(buff, "call n%c,%s", cc[rv], ADR(pc));
+#else
+ sprintf(buff, "bsfa,%c %s", cc[rv], ADR(pc));
+#endif
+ pc+=2;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0xbf:
+#if HJB
+ sprintf(buff, "call %s+r3", ADR(pc));
+#else
+ sprintf(buff, "bsxa %s", ADR(pc));
+#endif
+ pc+=2;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0xc0:
+ sprintf(buff, "nop");
+ break;
+ case 0xc1: case 0xc2: case 0xc3:
+#if HJB
+ sprintf(buff, "ld r%d,r0", rv);
+#else
+ sprintf(buff, "strz,%d", rv);
+#endif
+ break;
+ case 0xc4: case 0xc5: case 0xc6: case 0xc7:
+ sprintf(buff, "**** %02X", op);
+ break;
+ case 0xc8: case 0xc9: case 0xca: case 0xcb:
+#if HJB
+ sprintf(buff, "ld (%s),r%d", REL(pc), rv);
+#else
+ sprintf(buff, "strr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0xcc: case 0xcd: case 0xce: case 0xcf:
+#if HJB
+ sprintf(buff, "ld %s", ABS(0,rv,pc));
+#else
+ sprintf(buff, "stra,%s", ABS(1,rv,pc));
+#endif
+ pc+=2;
+ break;
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3:
+#if HJB
+ sprintf(buff, "rol r%d", rv);
+#else
+ sprintf(buff, "rrl,%d", rv);
+#endif
+ break;
+ case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+#if HJB
+ sprintf(buff, "out r%d,(%s)", rv, IMM(pc));
+#else
+ sprintf(buff, "wrte,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0xd8: case 0xd9: case 0xda: case 0xdb:
+#if HJB
+ sprintf(buff, "ijnz r%d,%s", rv, REL(pc));
+#else
+ sprintf(buff, "birr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0xdc: case 0xdd: case 0xde: case 0xdf:
+#if HJB
+ sprintf(buff, "ijnz r%d,%s", rv, ADR(pc));
+#else
+ sprintf(buff, "bira,%d %s", rv, ADR(pc));
+#endif
+ pc+=2;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0xe0: case 0xe1: case 0xe2: case 0xe3:
+#if HJB
+ sprintf(buff, "cp r0,%d", rv);
+#else
+ sprintf(buff, "comz,%d", rv);
+#endif
+ break;
+ case 0xe4: case 0xe5: case 0xe6: case 0xe7:
+#if HJB
+ sprintf(buff, "cp r%d,%s", rv, IMM(pc));
+#else
+ sprintf(buff, "comi,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0xe8: case 0xe9: case 0xea: case 0xeb:
+#if HJB
+ sprintf(buff, "cp r%d,(%s)", rv, REL(pc));
+#else
+ sprintf(buff, "comr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ break;
+ case 0xec: case 0xed: case 0xee: case 0xef:
+#if HJB
+ sprintf(buff, "cp %s", ABS(1,rv,pc));
+#else
+ sprintf(buff, "coma,%s", ABS(1,rv,pc));
+#endif
+ pc+=2;
+ break;
+ case 0xf0: case 0xf1: case 0xf2: case 0xf3:
+#if HJB
+ sprintf(buff, "out (data),r%d", rv);
+#else
+ sprintf(buff, "wrtd,%d", rv);
+#endif
+ break;
+ case 0xf4: case 0xf5: case 0xf6: case 0xf7:
+#if HJB
+ sprintf(buff, "test r%d,%s", rv, IMM(pc));
+#else
+ sprintf(buff, "tmi,%d %s", rv, IMM(pc));
+#endif
+ pc+=1;
+ break;
+ case 0xf8: case 0xf9: case 0xfa: case 0xfb:
+#if HJB
+ sprintf(buff, "djnz r%d,%s", rv, REL(pc));
+#else
+ sprintf(buff, "bdrr,%d %s", rv, REL(pc));
+#endif
+ pc+=1;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0xfc: case 0xfd: case 0xfe: case 0xff:
+#if HJB
+ sprintf(buff, "djnz r%d,%s", rv, ADR(pc));
+#else
+ sprintf(buff, "bdra,%d %s", rv, ADR(pc));
+#endif
+ pc+=2;
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ }
+ return (pc - PC) | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/s2650/s2650.c b/src/emu/cpu/s2650/s2650.c
new file mode 100644
index 00000000000..ef819bb397f
--- /dev/null
+++ b/src/emu/cpu/s2650/s2650.c
@@ -0,0 +1,1619 @@
+/*************************************************************************
+ *
+ * Portable Signetics 2650 cpu emulation
+ *
+ * Written by Juergen Buchmueller for use with MAME
+ *
+ * Version 1.2
+ * - changed to clock cycle counts from machine cycles
+ * - replaced cycle table with inline code (M_RET conditional case)
+ * - removed wrong distinct add/sub CC and OVF handling
+ * - cosmetics, readability
+ *
+ *************************************************************************/
+
+#include "debugger.h"
+#include "s2650.h"
+#include "s2650cpu.h"
+
+/* define this to have some interrupt information logged */
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+/* define this to expand all EA calculations inline */
+#define INLINE_EA 1
+
+int s2650_ICount = 0;
+
+typedef struct {
+ UINT16 ppc; /* previous program counter (page + iar) */
+ UINT16 page; /* 8K page select register (A14..A13) */
+ UINT16 iar; /* instruction address register (A12..A0) */
+ UINT16 ea; /* effective address (A14..A0) */
+ UINT8 psl; /* processor status lower */
+ UINT8 psu; /* processor status upper */
+ UINT8 r; /* absolute addressing dst/src register */
+ UINT8 reg[7]; /* 7 general purpose registers */
+ UINT8 halt; /* 1 if cpu is halted */
+ UINT8 ir; /* instruction register */
+ UINT16 ras[8]; /* 8 return address stack entries */
+ UINT8 irq_state;
+ int (*irq_callback)(int irqline);
+} s2650_Regs;
+
+static s2650_Regs S;
+
+/* condition code changes for a byte */
+static const UINT8 ccc[0x200] = {
+ 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x04,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+ 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84
+};
+
+static void s2650_set_sense(int state);
+
+
+#define CHECK_IRQ_LINE \
+ if (S.irq_state != CLEAR_LINE) \
+ { \
+ if( (S.psu & II) == 0 ) \
+ { \
+ int vector; \
+ if (S.halt) \
+ { \
+ S.halt = 0; \
+ S.iar = (S.iar + 1) & PMSK; \
+ } \
+ vector = (*S.irq_callback)(0) & 0xff; \
+ /* build effective address within first 8K page */ \
+ S.ea = S2650_relative[vector] & PMSK; \
+ if (vector & 0x80) /* indirect bit set ? */ \
+ { \
+ int addr = S.ea; \
+ s2650_ICount -= 6; \
+ /* build indirect 32K address */ \
+ S.ea = RDMEM(addr) << 8; \
+ if (!(++addr & PMSK)) addr -= PLEN; \
+ S.ea = (S.ea + RDMEM(addr)) & AMSK; \
+ } \
+ LOG(("S2650 interrupt to $%04x\n", S.ea));\
+ S.psu = (S.psu & ~SP) | ((S.psu + 1) & SP) | II; \
+ S.ras[S.psu & SP] = S.page + S.iar; \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ } \
+ }
+
+/***************************************************************
+ *
+ * set condition code (zero,plus,minus) from result
+ ***************************************************************/
+#define SET_CC(result) \
+ S.psl = (S.psl & ~CC) | ccc[result]
+
+/***************************************************************
+ *
+ * set condition code (zero,plus,minus) and overflow
+ ***************************************************************/
+#define SET_CC_OVF(result,value) \
+ S.psl = (S.psl & ~(OVF+CC)) | \
+ ccc[result + (((value) & 0x80) << 1)]
+
+#define SET_CC_OVF_ADD(result,value1,value2) SET_CC_OVF(result,~((value1) ^ (value2)) & ((value1) ^ (result)))
+#define SET_CC_OVF_SUB(result,value1,value2) SET_CC_OVF(result,~((value1) ^ (value2)) & ((value1) ^ (result)))
+
+/***************************************************************
+ * ROP
+ * read next opcode
+ ***************************************************************/
+INLINE UINT8 ROP(void)
+{
+ UINT8 result = cpu_readop(S.page + S.iar);
+ S.iar = (S.iar + 1) & PMSK;
+ return result;
+}
+
+/***************************************************************
+ * ARG
+ * read next opcode argument
+ ***************************************************************/
+INLINE UINT8 ARG(void)
+{
+ UINT8 result = cpu_readop_arg(S.page + S.iar);
+ S.iar = (S.iar + 1) & PMSK;
+ return result;
+}
+
+/***************************************************************
+ * RDMEM
+ * read memory byte from addr
+ ***************************************************************/
+#define RDMEM(addr) program_read_byte_8(addr)
+
+/***************************************************************
+ * handy table to build PC relative offsets
+ * from HR (holding register)
+ ***************************************************************/
+static int S2650_relative[0x100] =
+{
+ 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,
+ -64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,
+ -48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,
+ -32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,
+ -16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
+ 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,
+ -64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,
+ -48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,
+ -32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,
+ -16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
+};
+
+/***************************************************************
+ * _REL_EA
+ * build effective address with relative addressing
+ ***************************************************************/
+#define _REL_EA(page) \
+{ \
+ UINT8 hr = ARG(); /* get 'holding register' */ \
+ /* build effective address within current 8K page */ \
+ S.ea = page + ((S.iar + S2650_relative[hr]) & PMSK); \
+ if (hr & 0x80) { /* indirect bit set ? */ \
+ int addr = S.ea; \
+ s2650_ICount -= 6; \
+ /* build indirect 32K address */ \
+ S.ea = RDMEM(addr) << 8; \
+ if( (++addr & PMSK) == 0 ) addr -= PLEN; /* page wrap */\
+ S.ea = (S.ea + RDMEM(addr)) & AMSK; \
+ } \
+}
+
+/***************************************************************
+ * _REL_ZERO
+ * build effective address with zero relative addressing
+ ***************************************************************/
+#define _REL_ZERO(page) \
+{ \
+ UINT8 hr = ARG(); /* get 'holding register' */ \
+ /* build effective address from 0 */ \
+ S.ea = (S2650_relative[hr] & PMSK); \
+ if (hr & 0x80) { /* indirect bit set ? */ \
+ int addr = S.ea; \
+ s2650_ICount -= 6; \
+ /* build indirect 32K address */ \
+ S.ea = RDMEM(addr) << 8; \
+ if( (++addr & PMSK) == 0 ) addr -= PLEN; /* page wrap */\
+ S.ea = (S.ea + RDMEM(addr)) & AMSK; \
+ } \
+}
+
+/***************************************************************
+ * _ABS_EA
+ * build effective address with absolute addressing
+ ***************************************************************/
+#define _ABS_EA() \
+{ \
+ UINT8 hr, dr; \
+ hr = ARG(); /* get 'holding register' */ \
+ dr = ARG(); /* get 'data bus register' */ \
+ /* build effective address within current 8K page */ \
+ S.ea = S.page + (((hr << 8) + dr) & PMSK); \
+ /* indirect addressing ? */ \
+ if (hr & 0x80) { \
+ int addr = S.ea; \
+ s2650_ICount -= 6; \
+ /* build indirect 32K address */ \
+ /* build indirect 32K address */ \
+ S.ea = RDMEM(addr) << 8; \
+ if( (++addr & PMSK) == 0 ) addr -= PLEN; /* page wrap */\
+ S.ea = (S.ea + RDMEM(addr)) & AMSK; \
+ } \
+ /* check indexed addressing modes */ \
+ switch (hr & 0x60) { \
+ case 0x00: /* not indexed */ \
+ break; \
+ case 0x20: /* auto increment indexed */ \
+ S.reg[S.r] += 1; \
+ S.ea = (S.ea & PAGE)+((S.ea+S.reg[S.r]) & PMSK); \
+ S.r = 0; /* absolute addressing reg is R0 */ \
+ break; \
+ case 0x40: /* auto decrement indexed */ \
+ S.reg[S.r] -= 1; \
+ S.ea = (S.ea & PAGE)+((S.ea+S.reg[S.r]) & PMSK); \
+ S.r = 0; /* absolute addressing reg is R0 */ \
+ break; \
+ case 0x60: /* indexed */ \
+ S.ea = (S.ea & PAGE)+((S.ea+S.reg[S.r]) & PMSK); \
+ S.r = 0; /* absolute addressing reg is R0 */ \
+ break; \
+ } \
+}
+
+/***************************************************************
+ * _BRA_EA
+ * build effective address with absolute addressing (branch)
+ ***************************************************************/
+#define _BRA_EA() \
+{ \
+ UINT8 hr, dr; \
+ hr = ARG(); /* get 'holding register' */ \
+ dr = ARG(); /* get 'data bus register' */ \
+ /* build address in 32K address space */ \
+ S.ea = ((hr << 8) + dr) & AMSK; \
+ /* indirect addressing ? */ \
+ if (hr & 0x80) { \
+ int addr = S.ea; \
+ s2650_ICount -= 6; \
+ /* build indirect 32K address */ \
+ S.ea = RDMEM(addr) << 8; \
+ if( (++addr & PMSK) == 0 ) addr -= PLEN; /* page wrap */\
+ S.ea = (S.ea + RDMEM(addr)) & AMSK; \
+ } \
+}
+
+/***************************************************************
+ * SWAP_REGS
+ * Swap registers r1-r3 with r4-r6 (the second set)
+ * This is done everytime the RS bit in PSL changes
+ ***************************************************************/
+#define SWAP_REGS \
+{ \
+ UINT8 tmp; \
+ tmp = S.reg[1]; \
+ S.reg[1] = S.reg[4]; \
+ S.reg[4] = tmp; \
+ tmp = S.reg[2]; \
+ S.reg[2] = S.reg[5]; \
+ S.reg[5] = tmp; \
+ tmp = S.reg[3]; \
+ S.reg[3] = S.reg[6]; \
+ S.reg[6] = tmp; \
+}
+
+/***************************************************************
+ * M_BRR
+ * Branch relative if cond is true
+ ***************************************************************/
+#define M_BRR(cond) \
+{ \
+ if (cond) \
+ { \
+ REL_EA( S.page ); \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+ } else S.iar = (S.iar + 1) & PMSK; \
+}
+
+/***************************************************************
+ * M_ZBRR
+ * Branch relative to page zero
+ ***************************************************************/
+#define M_ZBRR() \
+{ \
+ REL_ZERO( 0 ); \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+}
+
+/***************************************************************
+ * M_BRA
+ * Branch absolute if cond is true
+ ***************************************************************/
+#define M_BRA(cond) \
+{ \
+ if( cond ) \
+ { \
+ BRA_EA(); \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+ } else S.iar = (S.iar + 2) & PMSK; \
+}
+
+/***************************************************************
+ * M_BXA
+ * Branch indexed absolute (EA + R3)
+ ***************************************************************/
+#define M_BXA() \
+{ \
+ BRA_EA(); \
+ S.ea = (S.ea + S.reg[3]) & AMSK; \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+}
+
+/***************************************************************
+ * M_BSR
+ * Branch to subroutine relative if cond is true
+ ***************************************************************/
+#define M_BSR(cond) \
+{ \
+ if( cond ) \
+ { \
+ REL_EA(S.page); \
+ S.psu = (S.psu & ~SP) | ((S.psu + 1) & SP); \
+ S.ras[S.psu & SP] = S.page + S.iar; \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+ } else S.iar = (S.iar + 1) & PMSK; \
+}
+
+/***************************************************************
+ * M_ZBSR
+ * Branch to subroutine relative to page zero
+ ***************************************************************/
+#define M_ZBSR() \
+{ \
+ REL_ZERO(0); \
+ S.psu = (S.psu & ~SP) | ((S.psu + 1) & SP); \
+ S.ras[S.psu & SP] = S.page + S.iar; \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+}
+
+/***************************************************************
+ * M_BSA
+ * Branch to subroutine absolute
+ ***************************************************************/
+#define M_BSA(cond) \
+{ \
+ if( cond ) \
+ { \
+ BRA_EA(); \
+ S.psu = (S.psu & ~SP) | ((S.psu + 1) & SP); \
+ S.ras[S.psu & SP] = S.page + S.iar; \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+ } else S.iar = (S.iar + 2) & PMSK; \
+}
+
+/***************************************************************
+ * M_BSXA
+ * Branch to subroutine indexed absolute (EA + R3)
+ ***************************************************************/
+#define M_BSXA() \
+{ \
+ BRA_EA(); \
+ S.ea = (S.ea + S.reg[3]) & AMSK; \
+ S.psu = (S.psu & ~SP) | ((S.psu + 1) & SP); \
+ S.ras[S.psu & SP] = S.page + S.iar; \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+}
+
+/***************************************************************
+ * M_RET
+ * Return from subroutine if cond is true
+ ***************************************************************/
+#define M_RET(cond) \
+{ \
+ if( cond ) \
+ { \
+ s2650_ICount -= 6; \
+ S.ea = S.ras[S.psu & SP]; \
+ S.psu = (S.psu & ~SP) | ((S.psu - 1) & SP); \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+ } \
+}
+
+/***************************************************************
+ * M_RETE
+ * Return from subroutine if cond is true
+ * and enable interrupts; afterwards check IRQ line
+ * state and eventually take next interrupt
+ ***************************************************************/
+#define M_RETE(cond) \
+{ \
+ if( cond ) \
+ { \
+ S.ea = S.ras[S.psu & SP]; \
+ S.psu = (S.psu & ~SP) | ((S.psu - 1) & SP); \
+ S.page = S.ea & PAGE; \
+ S.iar = S.ea & PMSK; \
+ change_pc(S.ea); \
+ S.psu &= ~II; \
+ CHECK_IRQ_LINE; \
+ } \
+}
+
+/***************************************************************
+ * M_LOD
+ * Load destination with source register
+ ***************************************************************/
+#define M_LOD(dest,source) \
+{ \
+ dest = source; \
+ SET_CC(dest); \
+}
+
+/***************************************************************
+ * M_STR
+ * Store source register to memory addr (CC unchanged)
+ ***************************************************************/
+#define M_STR(address,source) \
+ program_write_byte_8(address, source)
+
+/***************************************************************
+ * M_AND
+ * Logical and destination with source
+ ***************************************************************/
+#define M_AND(dest,source) \
+{ \
+ dest &= source; \
+ SET_CC(dest); \
+}
+
+/***************************************************************
+ * M_IOR
+ * Logical inclusive or destination with source
+ ***************************************************************/
+#define M_IOR(dest,source) \
+{ \
+ dest |= source; \
+ SET_CC(dest); \
+}
+
+/***************************************************************
+ * M_EOR
+ * Logical exclusive or destination with source
+ ***************************************************************/
+#define M_EOR(dest,source) \
+{ \
+ dest ^= source; \
+ SET_CC(dest); \
+}
+
+/***************************************************************
+ * M_ADD
+ * Add source to destination
+ * Add with carry if WC flag of PSL is set
+ ***************************************************************/
+#define M_ADD(dest,_source) \
+{ \
+ UINT8 source = _source; \
+ UINT8 before = dest; \
+ /* add source; carry only if WC is set */ \
+ UINT16 res = dest + source + ((S.psl >> 3) & S.psl & C); \
+ S.psl &= ~(C | OVF | IDC); \
+ if(res & 0x100) S.psl |= C; \
+ dest = res & 0xff; \
+ if( (dest & 15) < (before & 15) ) S.psl |= IDC; \
+ SET_CC_OVF_ADD(dest,before,source); \
+}
+
+/***************************************************************
+ * M_SUB
+ * Subtract source from destination
+ * Subtract with borrow if WC flag of PSL is set
+ ***************************************************************/
+#define M_SUB(dest,_source) \
+{ \
+ UINT8 source = _source; \
+ UINT8 before = dest; \
+ /* subtract source; borrow only if WC is set */ \
+ UINT16 res = dest - source - ((S.psl >> 3) & (S.psl ^ C) & C); \
+ S.psl &= ~(C | OVF | IDC); \
+ if((res & 0x100)==0) S.psl |= C; \
+ dest = res & 0xff; \
+ if( (dest & 15) <= (before & 15) ) S.psl |= IDC; \
+ SET_CC_OVF_SUB(dest,before,source); \
+}
+
+/***************************************************************
+ * M_COM
+ * Compare register against value. If COM of PSL is set,
+ * use unsigned, else signed comparison
+ ***************************************************************/
+#define M_COM(reg,val) \
+{ \
+ int d; \
+ S.psl &= ~CC; \
+ if (S.psl & COM) d = (UINT8)reg - (UINT8)val; \
+ else d = (INT8)reg - (INT8)val; \
+ if( d < 0 ) S.psl |= 0x80; \
+ else \
+ if( d > 0 ) S.psl |= 0x40; \
+}
+
+/***************************************************************
+ * M_DAR
+ * Decimal adjust register
+ ***************************************************************/
+#define M_DAR(dest) \
+{ \
+ if ((S.psl & C) == 0) dest += 0xA0; \
+ if ((S.psl & IDC) == 0) dest = (dest & 0xF0) | ((dest + 0x0A) & 0x0F);\
+}
+
+/***************************************************************
+ * M_RRL
+ * Rotate register left; If WC of PSL is set, rotate
+ * through carry, else rotate circular
+ ***************************************************************/
+#define M_RRL(dest) \
+{ \
+ UINT8 before = dest; \
+ if( S.psl & WC ) \
+ { \
+ UINT8 c = S.psl & C; \
+ S.psl &= ~(C + IDC); \
+ dest = (before << 1) | c; \
+ S.psl |= (before >> 7) + (dest & IDC); \
+ } \
+ else \
+ { \
+ dest = (before << 1) | (before >> 7); \
+ } \
+ SET_CC(dest); \
+ S.psl = (S.psl & ~OVF) | (((dest ^ before) >> 5) & OVF); \
+}
+
+/***************************************************************
+ * M_RRR
+ * Rotate register right; If WC of PSL is set, rotate
+ * through carry, else rotate circular
+ ***************************************************************/
+#define M_RRR(dest) \
+{ \
+ UINT8 before = dest; \
+ if (S.psl & WC) \
+ { \
+ UINT8 c = S.psl & C; \
+ S.psl &= ~(C + IDC); \
+ dest = (before >> 1) | (c << 7); \
+ S.psl |= (before & C) + (dest & IDC); \
+ } else dest = (before >> 1) | (before << 7); \
+ SET_CC(dest); \
+ S.psl = (S.psl & ~OVF) | (((dest ^ before) >> 5) & OVF); \
+}
+
+// bxd() not necessary
+
+/***************************************************************
+ * M_SPSU
+ * Store processor status upper (PSU) to register R0
+ * Checks for External Sense IO port
+ ***************************************************************/
+#define M_SPSU() \
+{ \
+ R0 = ((S.psu & ~PSU34) | (io_read_byte_8(S2650_SENSE_PORT) & SI)); \
+ SET_CC(R0); \
+}
+
+/***************************************************************
+ * M_SPSL
+ * Store processor status lower (PSL) to register R0
+ ***************************************************************/
+#define M_SPSL() \
+{ \
+ R0 = S.psl; \
+ SET_CC(R0); \
+}
+
+/***************************************************************
+ * M_CPSU
+ * Clear processor status upper (PSU), selective
+ ***************************************************************/
+#define M_CPSU() \
+{ \
+ UINT8 cpsu = ARG(); \
+ S.psu = S.psu & ~cpsu; \
+ CHECK_IRQ_LINE; \
+}
+
+/***************************************************************
+ * M_CPSL
+ * Clear processor status lower (PSL), selective
+ ***************************************************************/
+#define M_CPSL() \
+{ \
+ UINT8 cpsl = ARG(); \
+ /* select other register set now ? */ \
+ if( (cpsl & RS) && (S.psl & RS) ) \
+ SWAP_REGS; \
+ S.psl = S.psl & ~cpsl; \
+ CHECK_IRQ_LINE; \
+}
+
+/***************************************************************
+ * M_PPSU
+ * Preset processor status upper (PSU), selective
+ * Unused bits 3 and 4 can't be set
+ ***************************************************************/
+#define M_PPSU() \
+{ \
+ UINT8 ppsu = (ARG() & ~PSU34) & ~SI; \
+ S.psu = S.psu | ppsu; \
+}
+
+/***************************************************************
+ * M_PPSL
+ * Preset processor status lower (PSL), selective
+ ***************************************************************/
+#define M_PPSL() \
+{ \
+ UINT8 ppsl = ARG(); \
+ /* select 2nd register set now ? */ \
+ if ((ppsl & RS) && !(S.psl & RS)) \
+ SWAP_REGS; \
+ S.psl = S.psl | ppsl; \
+}
+
+/***************************************************************
+ * M_TPSU
+ * Test processor status upper (PSU)
+ ***************************************************************/
+#define M_TPSU() \
+{ \
+ UINT8 tpsu = ARG(); \
+ UINT8 rpsu = (S.psu | (io_read_byte_8(S2650_SENSE_PORT) & SI)); \
+ S.psl &= ~CC; \
+ if( (rpsu & tpsu) != tpsu ) \
+ S.psl |= 0x80; \
+}
+
+/***************************************************************
+ * M_TPSL
+ * Test processor status lower (PSL)
+ ***************************************************************/
+#define M_TPSL() \
+{ \
+ UINT8 tpsl = ARG(); \
+ if( (S.psl & tpsl) != tpsl ) \
+ S.psl = (S.psl & ~CC) | 0x80; \
+ else \
+ S.psl &= ~CC; \
+}
+
+/***************************************************************
+ * M_TMI
+ * Test under mask immediate
+ ***************************************************************/
+#define M_TMI(value) \
+{ \
+ UINT8 tmi = ARG(); \
+ S.psl &= ~CC; \
+ if( (value & tmi) != tmi ) \
+ S.psl |= 0x80; \
+}
+
+#if INLINE_EA
+#define REL_EA(page) _REL_EA(page)
+#define REL_ZERO(page) _REL_ZERO(page)
+#define ABS_EA() _ABS_EA()
+#define BRA_EA() _BRA_EA()
+#else
+static void REL_EA(unsigned short page) _REL_EA(page)
+static void REL_ZERO(unsigned short page) _REL_ZERO(page)
+static void ABS_EA(void) _ABS_EA()
+static void BRA_EA(void) _BRA_EA()
+#endif
+
+static void s2650_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ S.irq_callback = irqcallback;
+
+ state_save_register_item("s2650", index, S.ppc);
+ state_save_register_item("s2650", index, S.page);
+ state_save_register_item("s2650", index, S.iar);
+ state_save_register_item("s2650", index, S.ea);
+ state_save_register_item("s2650", index, S.psl);
+ state_save_register_item("s2650", index, S.psu);
+ state_save_register_item("s2650", index, S.r);
+ state_save_register_item_array("s2650", index, S.reg);
+ state_save_register_item("s2650", index, S.halt);
+ state_save_register_item("s2650", index, S.ir);
+ state_save_register_item_array("s2650", index, S.ras);
+ state_save_register_item("s2650", index, S.irq_state);
+}
+
+static void s2650_reset(void)
+{
+ int (*save_irqcallback)(int) = S.irq_callback;
+ memset(&S, 0, sizeof(S));
+ S.irq_callback = save_irqcallback;
+ S.psl = COM | WC;
+ S.psu = 0;
+}
+
+static void s2650_exit(void)
+{
+ /* nothing to do */
+}
+
+static void s2650_get_context(void *dst)
+{
+ if( dst )
+ *(s2650_Regs*)dst = S;
+}
+
+static void s2650_set_context(void *src)
+{
+ if( src )
+ {
+ S = *(s2650_Regs*)src;
+ S.page = S.page & PAGE;
+ S.iar = S.iar & PMSK;
+ change_pc(S.page + S.iar);
+ }
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == 1)
+ {
+ if (state == CLEAR_LINE)
+ s2650_set_sense(0);
+ else
+ s2650_set_sense(1);
+ return;
+ }
+
+ S.irq_state = state;
+ CHECK_IRQ_LINE;
+}
+
+static void s2650_set_flag(int state)
+{
+ if (state)
+ S.psu |= FO;
+ else
+ S.psu &= ~FO;
+}
+
+static int s2650_get_flag(void)
+{
+ return (S.psu & FO) ? 1 : 0;
+}
+
+static void s2650_set_sense(int state)
+{
+ if (state)
+ S.psu |= SI;
+ else
+ S.psu &= ~SI;
+}
+
+static int s2650_get_sense(void)
+{
+ /* OR'd with Input to allow for external connections */
+
+ return (((S.psu & SI) ? 1 : 0) | ((io_read_byte_8(S2650_SENSE_PORT) & SI) ? 1 : 0));
+}
+
+static int s2650_execute(int cycles)
+{
+ s2650_ICount = cycles;
+ do
+ {
+ S.ppc = S.page + S.iar;
+
+ CALL_MAME_DEBUG;
+
+ S.ir = ROP();
+ S.r = S.ir & 3; /* register / value */
+ switch (S.ir) {
+ case 0x00: /* LODZ,0 */
+ case 0x01: /* LODZ,1 */
+ case 0x02: /* LODZ,2 */
+ case 0x03: /* LODZ,3 */
+ s2650_ICount -= 6;
+ M_LOD( R0, S.reg[S.r] );
+ break;
+
+ case 0x04: /* LODI,0 v */
+ case 0x05: /* LODI,1 v */
+ case 0x06: /* LODI,2 v */
+ case 0x07: /* LODI,3 v */
+ s2650_ICount -= 6;
+ M_LOD( S.reg[S.r], ARG() );
+ break;
+
+ case 0x08: /* LODR,0 (*)a */
+ case 0x09: /* LODR,1 (*)a */
+ case 0x0a: /* LODR,2 (*)a */
+ case 0x0b: /* LODR,3 (*)a */
+ s2650_ICount -= 9;
+ REL_EA( S.page );
+ M_LOD( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0x0c: /* LODA,0 (*)a(,X) */
+ case 0x0d: /* LODA,1 (*)a(,X) */
+ case 0x0e: /* LODA,2 (*)a(,X) */
+ case 0x0f: /* LODA,3 (*)a(,X) */
+ s2650_ICount -= 12;
+ ABS_EA();
+ M_LOD( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0x10: /* illegal */
+ case 0x11: /* illegal */
+ s2650_ICount -= 7;
+ break;
+ case 0x12: /* SPSU */
+ s2650_ICount -= 6;
+ M_SPSU();
+ break;
+ case 0x13: /* SPSL */
+ s2650_ICount -= 6;
+ M_SPSL();
+ break;
+
+ case 0x14: /* RETC,0 (zero) */
+ case 0x15: /* RETC,1 (plus) */
+ case 0x16: /* RETC,2 (minus) */
+ s2650_ICount -= 9; /* +2 cycles if condition is true */
+ M_RET( (S.psl >> 6) == S.r );
+ break;
+ case 0x17: /* RETC,3 (always) */
+ s2650_ICount -= 9; /* +2 cycles if condition is true */
+ M_RET( 1 );
+ break;
+
+ case 0x18: /* BCTR,0 (*)a */
+ case 0x19: /* BCTR,1 (*)a */
+ case 0x1a: /* BCTR,2 (*)a */
+ s2650_ICount -= 9;
+ M_BRR( (S.psl >> 6) == S.r );
+ break;
+ case 0x1b: /* BCTR,3 (*)a */
+ s2650_ICount -= 9;
+ M_BRR( 1 );
+ break;
+
+ case 0x1c: /* BCTA,0 (*)a */
+ case 0x1d: /* BCTA,1 (*)a */
+ case 0x1e: /* BCTA,2 (*)a */
+ s2650_ICount -= 9;
+ M_BRA( (S.psl >> 6) == S.r );
+ break;
+ case 0x1f: /* BCTA,3 (*)a */
+ s2650_ICount -= 9;
+ M_BRA( 1 );
+ break;
+
+ case 0x20: /* EORZ,0 */
+ case 0x21: /* EORZ,1 */
+ case 0x22: /* EORZ,2 */
+ case 0x23: /* EORZ,3 */
+ s2650_ICount -= 6;
+ M_EOR( R0, S.reg[S.r] );
+ break;
+
+ case 0x24: /* EORI,0 v */
+ case 0x25: /* EORI,1 v */
+ case 0x26: /* EORI,2 v */
+ case 0x27: /* EORI,3 v */
+ s2650_ICount -= 6;
+ M_EOR( S.reg[S.r], ARG() );
+ break;
+
+ case 0x28: /* EORR,0 (*)a */
+ case 0x29: /* EORR,1 (*)a */
+ case 0x2a: /* EORR,2 (*)a */
+ case 0x2b: /* EORR,3 (*)a */
+ s2650_ICount -= 9;
+ REL_EA( S.page );
+ M_EOR( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0x2c: /* EORA,0 (*)a(,X) */
+ case 0x2d: /* EORA,1 (*)a(,X) */
+ case 0x2e: /* EORA,2 (*)a(,X) */
+ case 0x2f: /* EORA,3 (*)a(,X) */
+ s2650_ICount -= 12;
+ ABS_EA();
+ M_EOR( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0x30: /* REDC,0 */
+ case 0x31: /* REDC,1 */
+ case 0x32: /* REDC,2 */
+ case 0x33: /* REDC,3 */
+ s2650_ICount -= 6;
+ S.reg[S.r] = io_read_byte_8(S2650_CTRL_PORT);
+ SET_CC( S.reg[S.r] );
+ break;
+
+ case 0x34: /* RETE,0 */
+ case 0x35: /* RETE,1 */
+ case 0x36: /* RETE,2 */
+ s2650_ICount -= 9;
+ M_RETE( (S.psl >> 6) == S.r );
+ break;
+ case 0x37: /* RETE,3 */
+ s2650_ICount -= 9;
+ M_RETE( 1 );
+ break;
+
+ case 0x38: /* BSTR,0 (*)a */
+ case 0x39: /* BSTR,1 (*)a */
+ case 0x3a: /* BSTR,2 (*)a */
+ s2650_ICount -= 9;
+ M_BSR( (S.psl >> 6) == S.r );
+ break;
+ case 0x3b: /* BSTR,R3 (*)a */
+ s2650_ICount -= 9;
+ M_BSR( 1 );
+ break;
+
+ case 0x3c: /* BSTA,0 (*)a */
+ case 0x3d: /* BSTA,1 (*)a */
+ case 0x3e: /* BSTA,2 (*)a */
+ s2650_ICount -= 9;
+ M_BSA( (S.psl >> 6) == S.r );
+ break;
+ case 0x3f: /* BSTA,3 (*)a */
+ s2650_ICount -= 9;
+ M_BSA( 1 );
+ break;
+
+ case 0x40: /* HALT */
+ s2650_ICount -= 6;
+ S.iar = (S.iar - 1) & PMSK;
+ S.halt = 1;
+ if (s2650_ICount > 0)
+ s2650_ICount = 0;
+ break;
+ case 0x41: /* ANDZ,1 */
+ case 0x42: /* ANDZ,2 */
+ case 0x43: /* ANDZ,3 */
+ s2650_ICount -= 6;
+ M_AND( R0, S.reg[S.r] );
+ break;
+
+ case 0x44: /* ANDI,0 v */
+ case 0x45: /* ANDI,1 v */
+ case 0x46: /* ANDI,2 v */
+ case 0x47: /* ANDI,3 v */
+ s2650_ICount -= 6;
+ M_AND( S.reg[S.r], ARG() );
+ break;
+
+ case 0x48: /* ANDR,0 (*)a */
+ case 0x49: /* ANDR,1 (*)a */
+ case 0x4a: /* ANDR,2 (*)a */
+ case 0x4b: /* ANDR,3 (*)a */
+ s2650_ICount -= 9;
+ REL_EA( S.page );
+ M_AND( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0x4c: /* ANDA,0 (*)a(,X) */
+ case 0x4d: /* ANDA,1 (*)a(,X) */
+ case 0x4e: /* ANDA,2 (*)a(,X) */
+ case 0x4f: /* ANDA,3 (*)a(,X) */
+ s2650_ICount -= 12;
+ ABS_EA();
+ M_AND( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0x50: /* RRR,0 */
+ case 0x51: /* RRR,1 */
+ case 0x52: /* RRR,2 */
+ case 0x53: /* RRR,3 */
+ s2650_ICount -= 6;
+ M_RRR( S.reg[S.r] );
+ break;
+
+ case 0x54: /* REDE,0 v */
+ case 0x55: /* REDE,1 v */
+ case 0x56: /* REDE,2 v */
+ case 0x57: /* REDE,3 v */
+ s2650_ICount -= 9;
+ S.reg[S.r] = io_read_byte_8( ARG() );
+ SET_CC(S.reg[S.r]);
+ break;
+
+ case 0x58: /* BRNR,0 (*)a */
+ case 0x59: /* BRNR,1 (*)a */
+ case 0x5a: /* BRNR,2 (*)a */
+ case 0x5b: /* BRNR,3 (*)a */
+ s2650_ICount -= 9;
+ M_BRR( S.reg[S.r] );
+ break;
+
+ case 0x5c: /* BRNA,0 (*)a */
+ case 0x5d: /* BRNA,1 (*)a */
+ case 0x5e: /* BRNA,2 (*)a */
+ case 0x5f: /* BRNA,3 (*)a */
+ s2650_ICount -= 9;
+ M_BRA( S.reg[S.r] );
+ break;
+
+ case 0x60: /* IORZ,0 */
+ case 0x61: /* IORZ,1 */
+ case 0x62: /* IORZ,2 */
+ case 0x63: /* IORZ,3 */
+ s2650_ICount -= 6;
+ M_IOR( R0, S.reg[S.r] );
+ break;
+
+ case 0x64: /* IORI,0 v */
+ case 0x65: /* IORI,1 v */
+ case 0x66: /* IORI,2 v */
+ case 0x67: /* IORI,3 v */
+ s2650_ICount -= 6;
+ M_IOR( S.reg[S.r], ARG() );
+ break;
+
+ case 0x68: /* IORR,0 (*)a */
+ case 0x69: /* IORR,1 (*)a */
+ case 0x6a: /* IORR,2 (*)a */
+ case 0x6b: /* IORR,3 (*)a */
+ s2650_ICount -= 9;
+ REL_EA( S.page );
+ M_IOR( S.reg[S. r],RDMEM(S.ea) );
+ break;
+
+ case 0x6c: /* IORA,0 (*)a(,X) */
+ case 0x6d: /* IORA,1 (*)a(,X) */
+ case 0x6e: /* IORA,2 (*)a(,X) */
+ case 0x6f: /* IORA,3 (*)a(,X) */
+ s2650_ICount -= 12;
+ ABS_EA();
+ M_IOR( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0x70: /* REDD,0 */
+ case 0x71: /* REDD,1 */
+ case 0x72: /* REDD,2 */
+ case 0x73: /* REDD,3 */
+ s2650_ICount -= 6;
+ S.reg[S.r] = io_read_byte_8(S2650_DATA_PORT);
+ SET_CC(S.reg[S.r]);
+ break;
+
+ case 0x74: /* CPSU */
+ s2650_ICount -= 9;
+ M_CPSU();
+ break;
+ case 0x75: /* CPSL */
+ s2650_ICount -= 9;
+ M_CPSL();
+ break;
+ case 0x76: /* PPSU */
+ s2650_ICount -= 9;
+ M_PPSU();
+ break;
+ case 0x77: /* PPSL */
+ s2650_ICount -= 9;
+ M_PPSL();
+ break;
+
+ case 0x78: /* BSNR,0 (*)a */
+ case 0x79: /* BSNR,1 (*)a */
+ case 0x7a: /* BSNR,2 (*)a */
+ case 0x7b: /* BSNR,3 (*)a */
+ s2650_ICount -= 9;
+ M_BSR( S.reg[S.r] );
+ break;
+
+ case 0x7c: /* BSNA,0 (*)a */
+ case 0x7d: /* BSNA,1 (*)a */
+ case 0x7e: /* BSNA,2 (*)a */
+ case 0x7f: /* BSNA,3 (*)a */
+ s2650_ICount -= 9;
+ M_BSA( S.reg[S.r] );
+ break;
+
+ case 0x80: /* ADDZ,0 */
+ case 0x81: /* ADDZ,1 */
+ case 0x82: /* ADDZ,2 */
+ case 0x83: /* ADDZ,3 */
+ s2650_ICount -= 6;
+ M_ADD( R0,S.reg[S.r] );
+ break;
+
+ case 0x84: /* ADDI,0 v */
+ case 0x85: /* ADDI,1 v */
+ case 0x86: /* ADDI,2 v */
+ case 0x87: /* ADDI,3 v */
+ s2650_ICount -= 6;
+ M_ADD( S.reg[S.r], ARG() );
+ break;
+
+ case 0x88: /* ADDR,0 (*)a */
+ case 0x89: /* ADDR,1 (*)a */
+ case 0x8a: /* ADDR,2 (*)a */
+ case 0x8b: /* ADDR,3 (*)a */
+ s2650_ICount -= 9;
+ REL_EA(S.page);
+ M_ADD( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0x8c: /* ADDA,0 (*)a(,X) */
+ case 0x8d: /* ADDA,1 (*)a(,X) */
+ case 0x8e: /* ADDA,2 (*)a(,X) */
+ case 0x8f: /* ADDA,3 (*)a(,X) */
+ s2650_ICount -= 12;
+ ABS_EA();
+ M_ADD( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0x90: /* illegal */
+ case 0x91: /* illegal */
+ s2650_ICount -= 7;
+ break;
+ case 0x92: /* LPSU */
+ s2650_ICount -= 6;
+ S.psu = (R0 & ~PSU34) & ~SI;
+ break;
+ case 0x93: /* LPSL */
+ s2650_ICount -= 6;
+ /* change register set ? */
+ if ((S.psl ^ R0) & RS)
+ SWAP_REGS;
+ S.psl = R0;
+ break;
+
+ case 0x94: /* DAR,0 */
+ case 0x95: /* DAR,1 */
+ case 0x96: /* DAR,2 */
+ case 0x97: /* DAR,3 */
+ s2650_ICount -= 9;
+ M_DAR( S.reg[S.r] );
+ break;
+
+ case 0x98: /* BCFR,0 (*)a */
+ case 0x99: /* BCFR,1 (*)a */
+ case 0x9a: /* BCFR,2 (*)a */
+ s2650_ICount -= 9;
+ M_BRR( (S.psl >> 6) != S.r );
+ break;
+ case 0x9b: /* ZBRR (*)a */
+ s2650_ICount -= 9;
+ M_ZBRR();
+ break;
+
+ case 0x9c: /* BCFA,0 (*)a */
+ case 0x9d: /* BCFA,1 (*)a */
+ case 0x9e: /* BCFA,2 (*)a */
+ s2650_ICount -= 9;
+ M_BRA( (S.psl >> 6) != S.r );
+ break;
+ case 0x9f: /* BXA (*)a */
+ s2650_ICount -= 9;
+ M_BXA();
+ break;
+
+ case 0xa0: /* SUBZ,0 */
+ case 0xa1: /* SUBZ,1 */
+ case 0xa2: /* SUBZ,2 */
+ case 0xa3: /* SUBZ,3 */
+ s2650_ICount -= 6;
+ M_SUB( R0, S.reg[S.r] );
+ break;
+
+ case 0xa4: /* SUBI,0 v */
+ case 0xa5: /* SUBI,1 v */
+ case 0xa6: /* SUBI,2 v */
+ case 0xa7: /* SUBI,3 v */
+ s2650_ICount -= 6;
+ M_SUB( S.reg[S.r], ARG() );
+ break;
+
+ case 0xa8: /* SUBR,0 (*)a */
+ case 0xa9: /* SUBR,1 (*)a */
+ case 0xaa: /* SUBR,2 (*)a */
+ case 0xab: /* SUBR,3 (*)a */
+ s2650_ICount -= 9;
+ REL_EA(S.page);
+ M_SUB( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0xac: /* SUBA,0 (*)a(,X) */
+ case 0xad: /* SUBA,1 (*)a(,X) */
+ case 0xae: /* SUBA,2 (*)a(,X) */
+ case 0xaf: /* SUBA,3 (*)a(,X) */
+ s2650_ICount -= 12;
+ ABS_EA();
+ M_SUB( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0xb0: /* WRTC,0 */
+ case 0xb1: /* WRTC,1 */
+ case 0xb2: /* WRTC,2 */
+ case 0xb3: /* WRTC,3 */
+ s2650_ICount -= 6;
+ io_write_byte_8(S2650_CTRL_PORT,S.reg[S.r]);
+ break;
+
+ case 0xb4: /* TPSU */
+ s2650_ICount -= 9;
+ M_TPSU();
+ break;
+ case 0xb5: /* TPSL */
+ s2650_ICount -= 9;
+ M_TPSL();
+ break;
+ case 0xb6: /* illegal */
+ case 0xb7: /* illegal */
+ s2650_ICount -= 7;
+ break;
+
+ case 0xb8: /* BSFR,0 (*)a */
+ case 0xb9: /* BSFR,1 (*)a */
+ case 0xba: /* BSFR,2 (*)a */
+ s2650_ICount -= 9;
+ M_BSR( (S.psl >> 6) != S.r );
+ break;
+ case 0xbb: /* ZBSR (*)a */
+ s2650_ICount -= 9;
+ M_ZBSR();
+ break;
+
+ case 0xbc: /* BSFA,0 (*)a */
+ case 0xbd: /* BSFA,1 (*)a */
+ case 0xbe: /* BSFA,2 (*)a */
+ s2650_ICount -= 9;
+ M_BSA( (S.psl >> 6) != S.r );
+ break;
+ case 0xbf: /* BSXA (*)a */
+ s2650_ICount -= 9;
+ M_BSXA();
+ break;
+
+ case 0xc0: /* NOP */
+ s2650_ICount -= 6;
+ break;
+ case 0xc1: /* STRZ,1 */
+ case 0xc2: /* STRZ,2 */
+ case 0xc3: /* STRZ,3 */
+ s2650_ICount -= 6;
+ M_LOD( S.reg[S.r], R0 );
+ break;
+
+ case 0xc4: /* illegal */
+ case 0xc5: /* illegal */
+ case 0xc6: /* illegal */
+ case 0xc7: /* illegal */
+ s2650_ICount -= 7;
+ break;
+
+ case 0xc8: /* STRR,0 (*)a */
+ case 0xc9: /* STRR,1 (*)a */
+ case 0xca: /* STRR,2 (*)a */
+ case 0xcb: /* STRR,3 (*)a */
+ s2650_ICount -= 9;
+ REL_EA(S.page);
+ M_STR( S.ea, S.reg[S.r] );
+ break;
+
+ case 0xcc: /* STRA,0 (*)a(,X) */
+ case 0xcd: /* STRA,1 (*)a(,X) */
+ case 0xce: /* STRA,2 (*)a(,X) */
+ case 0xcf: /* STRA,3 (*)a(,X) */
+ s2650_ICount -= 12;
+ ABS_EA();
+ M_STR( S.ea, S.reg[S.r] );
+ break;
+
+ case 0xd0: /* RRL,0 */
+ case 0xd1: /* RRL,1 */
+ case 0xd2: /* RRL,2 */
+ case 0xd3: /* RRL,3 */
+ s2650_ICount -= 6;
+ M_RRL( S.reg[S.r] );
+ break;
+
+ case 0xd4: /* WRTE,0 v */
+ case 0xd5: /* WRTE,1 v */
+ case 0xd6: /* WRTE,2 v */
+ case 0xd7: /* WRTE,3 v */
+ s2650_ICount -= 9;
+ io_write_byte_8( ARG(), S.reg[S.r] );
+ break;
+
+ case 0xd8: /* BIRR,0 (*)a */
+ case 0xd9: /* BIRR,1 (*)a */
+ case 0xda: /* BIRR,2 (*)a */
+ case 0xdb: /* BIRR,3 (*)a */
+ s2650_ICount -= 9;
+ M_BRR( ++S.reg[S.r] );
+ break;
+
+ case 0xdc: /* BIRA,0 (*)a */
+ case 0xdd: /* BIRA,1 (*)a */
+ case 0xde: /* BIRA,2 (*)a */
+ case 0xdf: /* BIRA,3 (*)a */
+ s2650_ICount -= 9;
+ M_BRA( ++S.reg[S.r] );
+ break;
+
+ case 0xe0: /* COMZ,0 */
+ case 0xe1: /* COMZ,1 */
+ case 0xe2: /* COMZ,2 */
+ case 0xe3: /* COMZ,3 */
+ s2650_ICount -= 6;
+ M_COM( R0, S.reg[S.r] );
+ break;
+
+ case 0xe4: /* COMI,0 v */
+ case 0xe5: /* COMI,1 v */
+ case 0xe6: /* COMI,2 v */
+ case 0xe7: /* COMI,3 v */
+ s2650_ICount -= 6;
+ M_COM( S.reg[S.r], ARG() );
+ break;
+
+ case 0xe8: /* COMR,0 (*)a */
+ case 0xe9: /* COMR,1 (*)a */
+ case 0xea: /* COMR,2 (*)a */
+ case 0xeb: /* COMR,3 (*)a */
+ s2650_ICount -= 9;
+ REL_EA(S.page);
+ M_COM( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0xec: /* COMA,0 (*)a(,X) */
+ case 0xed: /* COMA,1 (*)a(,X) */
+ case 0xee: /* COMA,2 (*)a(,X) */
+ case 0xef: /* COMA,3 (*)a(,X) */
+ s2650_ICount -= 12;
+ ABS_EA();
+ M_COM( S.reg[S.r], RDMEM(S.ea) );
+ break;
+
+ case 0xf0: /* WRTD,0 */
+ case 0xf1: /* WRTD,1 */
+ case 0xf2: /* WRTD,2 */
+ case 0xf3: /* WRTD,3 */
+ s2650_ICount -= 6;
+ io_write_byte_8(S2650_DATA_PORT, S.reg[S.r]);
+ break;
+
+ case 0xf4: /* TMI,0 v */
+ case 0xf5: /* TMI,1 v */
+ case 0xf6: /* TMI,2 v */
+ case 0xf7: /* TMI,3 v */
+ s2650_ICount -= 9;
+ M_TMI( S.reg[S.r] );
+ break;
+
+ case 0xf8: /* BDRR,0 (*)a */
+ case 0xf9: /* BDRR,1 (*)a */
+ case 0xfa: /* BDRR,2 (*)a */
+ case 0xfb: /* BDRR,3 (*)a */
+ s2650_ICount -= 9;
+ M_BRR( --S.reg[S.r] );
+ break;
+
+ case 0xfc: /* BDRA,0 (*)a */
+ case 0xfd: /* BDRA,1 (*)a */
+ case 0xfe: /* BDRA,2 (*)a */
+ case 0xff: /* BDRA,3 (*)a */
+ s2650_ICount -= 9;
+ M_BRA( --S.reg[S.r] );
+ break;
+ }
+ } while( s2650_ICount > 0 );
+
+ return cycles - s2650_ICount;
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void s2650_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+
+ case CPUINFO_INT_PC:
+ S.page = info->i & PAGE;
+ S.iar = info->i & PMSK;
+ change_pc(S.page + S.iar);
+ break;
+
+ case CPUINFO_INT_REGISTER + S2650_PC: S.page = info->i & PAGE; S.iar = info->i & PMSK; break;
+ case CPUINFO_INT_SP: S.psu = (S.psu & ~SP) | (info->i & SP); break;
+ case CPUINFO_INT_REGISTER + S2650_PS: S.psl = info->i & 0xff; S.psu = info->i >> 8; break;
+ case CPUINFO_INT_REGISTER + S2650_R0: S.reg[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + S2650_R1: S.reg[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + S2650_R2: S.reg[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + S2650_R3: S.reg[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + S2650_R1A: S.reg[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + S2650_R2A: S.reg[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + S2650_R3A: S.reg[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + S2650_HALT: S.halt = info->i; break;
+ case CPUINFO_INT_REGISTER + S2650_SI: s2650_set_sense(info->i); break;
+ case CPUINFO_INT_REGISTER + S2650_FO: s2650_set_flag(info->i); break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void s2650_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(S); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 5; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 13; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 15; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 9; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = S.irq_state; break;
+ case CPUINFO_INT_INPUT_STATE + 1: info->i = s2650_get_sense() ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = S.ppc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + S2650_PC: info->i = S.page + S.iar; break;
+
+ case CPUINFO_INT_SP: info->i = S.psu & SP; break;
+ case CPUINFO_INT_REGISTER + S2650_PS: info->i = (S.psu << 8) | S.psl; break;
+ case CPUINFO_INT_REGISTER + S2650_R0: info->i = S.reg[0]; break;
+ case CPUINFO_INT_REGISTER + S2650_R1: info->i = S.reg[1]; break;
+ case CPUINFO_INT_REGISTER + S2650_R2: info->i = S.reg[2]; break;
+ case CPUINFO_INT_REGISTER + S2650_R3: info->i = S.reg[3]; break;
+ case CPUINFO_INT_REGISTER + S2650_R1A: info->i = S.reg[4]; break;
+ case CPUINFO_INT_REGISTER + S2650_R2A: info->i = S.reg[5]; break;
+ case CPUINFO_INT_REGISTER + S2650_R3A: info->i = S.reg[6]; break;
+ case CPUINFO_INT_REGISTER + S2650_HALT: info->i = S.halt; break;
+ case CPUINFO_INT_REGISTER + S2650_SI: info->i = s2650_get_sense(); break;
+ case CPUINFO_INT_REGISTER + S2650_FO: info->i = s2650_get_flag(); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = s2650_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = s2650_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = s2650_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = s2650_init; break;
+ case CPUINFO_PTR_RESET: info->reset = s2650_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = s2650_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = s2650_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = s2650_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &s2650_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "S2650"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Signetics 2650"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.2"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Written by Juergen Buchmueller for use with MAME"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ S.psu & 0x80 ? 'S':'.',
+ S.psu & 0x40 ? 'O':'.',
+ S.psu & 0x20 ? 'I':'.',
+ S.psu & 0x10 ? '?':'.',
+ S.psu & 0x08 ? '?':'.',
+ S.psu & 0x04 ? 's':'.',
+ S.psu & 0x02 ? 's':'.',
+ S.psu & 0x01 ? 's':'.',
+ S.psl & 0x80 ? 'M':'.',
+ S.psl & 0x40 ? 'P':'.',
+ S.psl & 0x20 ? 'H':'.',
+ S.psl & 0x10 ? 'R':'.',
+ S.psl & 0x08 ? 'W':'.',
+ S.psl & 0x04 ? 'V':'.',
+ S.psl & 0x02 ? '2':'.',
+ S.psl & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + S2650_PC: sprintf(info->s, "PC:%04X", S.page + S.iar); break;
+ case CPUINFO_STR_REGISTER + S2650_PS: sprintf(info->s, "PS:%02X%02X", S.psu, S.psl); break;
+ case CPUINFO_STR_REGISTER + S2650_R0: sprintf(info->s, "R0:%02X", S.reg[0]); break;
+ case CPUINFO_STR_REGISTER + S2650_R1: sprintf(info->s, "R1:%02X", S.reg[1]); break;
+ case CPUINFO_STR_REGISTER + S2650_R2: sprintf(info->s, "R2:%02X", S.reg[2]); break;
+ case CPUINFO_STR_REGISTER + S2650_R3: sprintf(info->s, "R3:%02X", S.reg[3]); break;
+ case CPUINFO_STR_REGISTER + S2650_R1A: sprintf(info->s, "R1'%02X", S.reg[4]); break;
+ case CPUINFO_STR_REGISTER + S2650_R2A: sprintf(info->s, "R2'%02X", S.reg[5]); break;
+ case CPUINFO_STR_REGISTER + S2650_R3A: sprintf(info->s, "R3'%02X", S.reg[6]); break;
+ case CPUINFO_STR_REGISTER + S2650_HALT: sprintf(info->s, "HALT:%X", S.halt); break;
+ case CPUINFO_STR_REGISTER + S2650_SI: sprintf(info->s, "SI:%X", (S.psu & SI) ? 1 : 0); break;
+ case CPUINFO_STR_REGISTER + S2650_FO: sprintf(info->s, "FO:%X", (S.psu & FO) ? 1 : 0); break;
+ }
+}
diff --git a/src/emu/cpu/s2650/s2650.h b/src/emu/cpu/s2650/s2650.h
new file mode 100644
index 00000000000..36fcfd6dd3e
--- /dev/null
+++ b/src/emu/cpu/s2650/s2650.h
@@ -0,0 +1,30 @@
+#ifndef S2650_H
+#define S2650_H
+
+#include "cpuintrf.h"
+
+enum {
+ S2650_PC=1, S2650_PS, S2650_R0, S2650_R1, S2650_R2, S2650_R3,
+ S2650_R1A, S2650_R2A, S2650_R3A,
+ S2650_HALT, S2650_SI, S2650_FO
+};
+
+/* fake control port M/~IO=0 D/~C=0 E/~NE=0 */
+#define S2650_CTRL_PORT 0x100
+
+/* fake data port M/~IO=0 D/~C=1 E/~NE=0 */
+#define S2650_DATA_PORT 0x101
+
+/* extended i/o ports M/~IO=0 D/~C=x E/~NE=1 */
+#define S2650_EXT_PORT 0xff
+
+/* Fake Sense Line */
+#define S2650_SENSE_PORT 0x102
+
+extern void s2650_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern offs_t s2650_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif
diff --git a/src/emu/cpu/s2650/s2650cpu.h b/src/emu/cpu/s2650/s2650cpu.h
new file mode 100644
index 00000000000..5a61e5d4cb1
--- /dev/null
+++ b/src/emu/cpu/s2650/s2650cpu.h
@@ -0,0 +1,35 @@
+/*******************************************************
+ *
+ * Portable Signetics 2650 cpu emulation
+ *
+ * Written by Juergen Buchmueller for use with MAME
+ *
+ *******************************************************/
+
+#define PMSK 0x1fff /* mask page offset */
+#define PLEN 0x2000 /* page length */
+#define PAGE 0x6000 /* mask page */
+#define AMSK 0x7fff /* mask address range */
+
+/* processor status lower */
+#define C 0x01 /* carry flag */
+#define COM 0x02 /* compare: 0 binary, 1 2s complement */
+#define OVF 0x04 /* 2s complement overflow */
+#define WC 0x08 /* with carry: use carry in arithmetic / rotate ops */
+#define RS 0x10 /* register select 0: R0/R1/R2/R3 1: R0/R4/R5/R6 */
+#define IDC 0x20 /* inter digit carry: bit-3-to-bit-4 carry */
+#define CC 0xc0 /* condition code */
+
+/* processor status upper */
+#define SP 0x07 /* stack pointer: indexing 8 15bit words */
+#define PSU34 0x18 /* unused bits */
+#define II 0x20 /* interrupt inhibit 0: allow, 1: inhibit */
+#define FO 0x40 /* flag output */
+#define SI 0x80 /* sense input */
+
+#define R0 S.reg[0]
+#define R1 S.reg[1]
+#define R2 S.reg[2]
+#define R3 S.reg[3]
+
+
diff --git a/src/emu/cpu/saturn/sat.h b/src/emu/cpu/saturn/sat.h
new file mode 100644
index 00000000000..8632468dc04
--- /dev/null
+++ b/src/emu/cpu/saturn/sat.h
@@ -0,0 +1,22 @@
+enum {
+ SATURN_A=1, SATURN_B, SATURN_C, SATURN_D,
+ SATURN_R0, SATURN_R1, SATURN_R2, SATURN_R3, SATURN_R4,
+ SATURN_RSTK0, SATURN_RSTK1, SATURN_RSTK2, SATURN_RSTK3,
+ SATURN_RSTK4, SATURN_RSTK5, SATURN_RSTK6, SATURN_RSTK7,
+ SATURN_PC, SATURN_D0, SATURN_D1,
+
+ SATURN_P,
+ SATURN_IN,
+ SATURN_OUT,
+ SATURN_CARRY,
+ SATURN_ST,
+ SATURN_HST,
+
+ SATURN_EA,
+ SATURN_NMI_STATE,
+ SATURN_IRQ_STATE
+};
+
+#define PEEK_OP(pc) cpu_readop(pc)
+#define PEEK_NIBBLE(adr) cpu_readmem_20(adr)
+
diff --git a/src/emu/cpu/saturn/satops.c b/src/emu/cpu/saturn/satops.c
new file mode 100644
index 00000000000..578e3036994
--- /dev/null
+++ b/src/emu/cpu/saturn/satops.c
@@ -0,0 +1,1209 @@
+#define IRQ_ADDRESS 0xf
+
+INLINE int READ_OP(void)
+{
+ saturn_ICount-=3;
+ return cpu_readop(saturn.pc++);
+}
+
+INLINE int READ_OP_ARG(void)
+{
+ saturn_ICount-=3;
+ return cpu_readop_arg(saturn.pc++);
+}
+
+INLINE int READ_OP_ARG8(void)
+{
+ return READ_OP_ARG()|(READ_OP_ARG()<<4);
+}
+
+INLINE INT8 READ_OP_DIS8(void)
+{
+ return READ_OP_ARG()|(READ_OP_ARG()<<4);
+}
+
+INLINE int READ_OP_ARG12(void)
+{
+ return READ_OP_ARG()|(READ_OP_ARG()<<4)|(READ_OP_ARG()<<8);
+}
+
+INLINE int READ_OP_DIS12(void)
+{
+ int temp=READ_OP_ARG()|(READ_OP_ARG()<<4)|(READ_OP_ARG()<<8);
+ if (temp&0x800) return -0x1000+temp;
+ else return temp;
+}
+
+INLINE int READ_OP_ARG16(void)
+{
+ return READ_OP_ARG()|(READ_OP_ARG()<<4)|(READ_OP_ARG()<<8)|(READ_OP_ARG()<<12);
+}
+
+INLINE INT16 READ_OP_DIS16(void)
+{
+ return READ_OP_ARG()|(READ_OP_ARG()<<4)|(READ_OP_ARG()<<8)|(READ_OP_ARG()<<12);
+}
+
+INLINE int READ_OP_ARG20(void)
+{
+ return READ_OP_ARG()|(READ_OP_ARG()<<4)|(READ_OP_ARG()<<8)
+ |(READ_OP_ARG()<<12)|(READ_OP_ARG()<<16);
+}
+
+INLINE int READ_NIBBLE(SaturnAdr adr)
+{
+ int data;
+ saturn_ICount-=3;
+ data = program_read_byte(adr);
+ if (saturn.config&&saturn.config->crc) saturn.config->crc(adr, data);
+ return data;
+}
+
+INLINE int READ_8(SaturnAdr adr)
+{
+ return READ_NIBBLE(adr)|(READ_NIBBLE(adr+1)<<4);
+}
+
+INLINE int READ_12(SaturnAdr adr)
+{
+ return READ_NIBBLE(adr)|(READ_NIBBLE(adr+1)<<4)|(READ_NIBBLE(adr+2)<<8);
+}
+
+INLINE int READ_16(SaturnAdr adr)
+{
+ return READ_NIBBLE(adr)|(READ_NIBBLE(adr+1)<<4)
+ |(READ_NIBBLE(adr+2)<<8)|(READ_NIBBLE(adr+3)<<12);
+}
+
+INLINE int READ_20(SaturnAdr adr)
+{
+ return READ_NIBBLE(adr)|(READ_NIBBLE(adr+1)<<4)
+ |(READ_NIBBLE(adr+2)<<8)|(READ_NIBBLE(adr+3)<<12)|(READ_NIBBLE(adr+4)<<16);
+}
+
+INLINE void WRITE_NIBBLE(SaturnAdr adr, SaturnNib nib)
+{
+ saturn_ICount -= 3;
+ program_write_byte(adr, nib);
+}
+
+#ifdef LSB_FIRST
+#define S64_BYTE(r, x) saturn.reg[r].b[x]
+#define S64_WORD(r, x) saturn.reg[r].w[x]
+#define S64_DOUBLE(r, x) saturn.reg[r].d[x]
+#else
+#define S64_BYTE(r, x) saturn.reg[r].b[7-x]
+#define S64_WORD(r, x) saturn.reg[r].w[3-x]
+#define S64_DOUBLE(r, x) saturn.reg[r].d[1-x]
+#endif
+
+#define S64_QUAD(r) saturn.reg[r].q
+
+#define BEGIN_B 0
+#define COUNT_B 2
+#define BEGIN_X 0
+#define COUNT_X 3
+#define BEGIN_XS 2
+#define COUNT_XS 1
+#define BEGIN_A 0
+#define COUNT_A 5
+#define BEGIN_M 3
+#define COUNT_M 12
+#define BEGIN_S 15
+#define COUNT_S 1
+#define BEGIN_W 0
+#define COUNT_W 16
+
+#define S64_READ_NIBBLE(r, x) (((x)&1) ? (S64_BYTE(r, ((x)>>1))>>4) : (S64_BYTE(r, ((x)>>1))&0xf) )
+#define S64_WRITE_NIBBLE(r, x, v) \
+ (S64_BYTE(r, ((x)>>1)) = ((x)&1) \
+ ?(S64_BYTE(r, ((x)>>1))&0xf)|((v)<<4) \
+ :(S64_BYTE(r, ((x)>>1))&0xf0)|(v) )
+
+#define S64_READ_B(r) S64_BYTE(r,0)
+#define S64_WRITE_B(r,v) (S64_BYTE(r,0)=v)
+
+#define S64_READ_XS(r) S64_READ_NIBBLE(r,2)
+#define S64_WRITE_XS(r,v) S64_WRITE_NIBBLE(r,2,v)
+
+#define S64_READ_S(r) S64_READ_NIBBLE(r,15)
+#define S64_WRITE_S(r,v) S64_WRITE_NIBBLE(r,15,v)
+
+#define S64_READ_P(r) S64_READ_NIBBLE(r,saturn.p)
+#define S64_WRITE_P(r,v) S64_WRITE_NIBBLE(r,saturn.p,v)
+
+#define S64_READ_X(r) (S64_WORD(r,0)&0xfff)
+#define S64_WRITE_X(r,v) (S64_WORD(r,0)=(S64_WORD(r,0)&~0xfff)|(v))
+
+// for address reg operations
+#define S64_READ_WORD(r,nr) S64_WORD(r,nr)
+#define S64_WRITE_WORD(r,nr,v) (S64_WORD(r,nr)=v)
+
+#define S64_READ_A(r) (S64_DOUBLE(r,0)&0xfffff)
+#define S64_WRITE_A(r,v) (S64_DOUBLE(r,0)=(S64_DOUBLE(r,0)&~0xfffff)|(v))
+
+#define S64_READ_M(r) ((S64_QUAD(r)>>12)&0xffffffffffffULL)
+#define S64_WRITE_M(r,v) (S64_QUAD(r)=(S64_QUAD(r)&~0xffffffffffff000ULL)|((v)<<12))
+
+#define S64_READ_W(r) S64_QUAD(r)
+#define S64_WRITE_W(r,v) (S64_QUAD(r)=(v))
+
+INLINE SaturnAdr saturn_pop(void)
+{
+ SaturnAdr temp=saturn.rstk[0];
+ memmove(saturn.rstk, saturn.rstk+1, sizeof(saturn.rstk)-sizeof(saturn.rstk[0]));
+ saturn.rstk[7]=0;
+ saturn.stackpointer--;
+ return temp;
+}
+
+INLINE void saturn_push(SaturnAdr adr)
+{
+ memmove(saturn.rstk+1, saturn.rstk, sizeof(saturn.rstk)-sizeof(saturn.rstk[0]));
+ saturn.rstk[0]=adr;
+ saturn.stackpointer++;
+}
+
+INLINE void saturn_interrupt_on(void)
+{
+
+}
+
+INLINE void saturn_interrupt_off(void)
+{
+
+}
+
+INLINE void saturn_reset_interrupt(void)
+{
+
+}
+
+INLINE void saturn_mem_reset(void)
+{
+ if (saturn.config->reset) saturn.config->reset();
+}
+
+INLINE void saturn_mem_config(void)
+{
+ if (saturn.config->config) saturn.config->config(S64_READ_A(C));
+}
+
+INLINE void saturn_mem_unconfig(void)
+{
+ if (saturn.config->unconfig) saturn.config->unconfig(S64_READ_A(C));
+}
+
+INLINE int saturn_mem_id(void)
+{
+ if (saturn.config->id) return saturn.config->id();
+ return 0;
+}
+
+INLINE void saturn_shutdown(void)
+{
+}
+
+INLINE void saturn_bus_command_b(void)
+{
+}
+
+INLINE void saturn_bus_command_c(void)
+{
+}
+
+INLINE void saturn_bus_command_d(void)
+{
+}
+
+INLINE void saturn_serial_request(void)
+{
+}
+
+INLINE void saturn_out_c(void)
+{
+ if (saturn.config&&saturn.config->out) saturn.config->out(S64_READ_X(C));
+}
+
+INLINE void saturn_out_cs(void)
+{
+ if (saturn.config&&saturn.config->out)
+ saturn.config->out(S64_READ_NIBBLE(C,0)|(saturn.out&0xff0));
+}
+
+INLINE void saturn_in(int reg)
+{
+ if (saturn.config&&saturn.config->in) S64_WORD(reg,0)=saturn.config->in();
+}
+
+INLINE void saturn_sethex(void) { saturn.decimal=0; }
+INLINE void saturn_setdec(void) { saturn.decimal=1; }
+
+/* st related */
+INLINE void saturn_clear_st(void)
+{
+ saturn.st=0;
+}
+
+INLINE void saturn_st_to_c(void)
+{
+ S64_WRITE_X(C, saturn.st&0xfff);
+}
+
+INLINE void saturn_c_to_st(void)
+{
+ saturn.st=(saturn.st&~0xfff)|S64_READ_X(C);
+}
+
+INLINE void saturn_exchange_c_st(void)
+{
+ int t=saturn.st&0xfff;
+ saturn.st=(saturn.st&~0xfff)|S64_READ_X(C);
+ S64_WRITE_X(C, t);
+}
+
+INLINE void saturn_st_clear_bit(void)
+{
+ switch(READ_OP_ARG()) {
+ case 0: saturn.st&=~1;break;
+ case 1: saturn.st&=~2;break;
+ case 2: saturn.st&=~4;break;
+ case 3: saturn.st&=~8;break;
+ case 4: saturn.st&=~0x10;break;
+ case 5: saturn.st&=~0x20;break;
+ case 6: saturn.st&=~0x40;break;
+ case 7: saturn.st&=~0x80;break;
+ case 8: saturn.st&=~0x100;break;
+ case 9: saturn.st&=~0x200;break;
+ case 0xa: saturn.st&=~0x400;break;
+ case 0xb: saturn.st&=~0x800;break;
+ case 0xc: saturn.st&=~0x1000;break;
+ case 0xd: saturn.st&=~0x2000;break;
+ case 0xe: saturn.st&=~0x4000;break;
+ case 0xf: saturn.st&=~0x8000;break;
+ }
+}
+
+INLINE void saturn_st_set_bit(void)
+{
+ switch(READ_OP_ARG()) {
+ case 0: saturn.st|=1;break;
+ case 1: saturn.st|=2;break;
+ case 2: saturn.st|=4;break;
+ case 3: saturn.st|=8;break;
+ case 4: saturn.st|=0x10;break;
+ case 5: saturn.st|=0x20;break;
+ case 6: saturn.st|=0x40;break;
+ case 7: saturn.st|=0x80;break;
+ case 8: saturn.st|=0x100;break;
+ case 9: saturn.st|=0x200;break;
+ case 0xa: saturn.st|=0x400;break;
+ case 0xb: saturn.st|=0x800;break;
+ case 0xc: saturn.st|=0x1000;break;
+ case 0xd: saturn.st|=0x2000;break;
+ case 0xe: saturn.st|=0x4000;break;
+ case 0xf: saturn.st|=0x8000;break;
+ }
+}
+
+INLINE void saturn_st_jump_bit_clear(void)
+{
+ int adr;
+ switch(READ_OP_ARG()) {
+ case 0: saturn.carry=!saturn.st&1;break;
+ case 1: saturn.carry=!saturn.st&2;break;
+ case 2: saturn.carry=!saturn.st&4;break;
+ case 3: saturn.carry=!saturn.st&8;break;
+ case 4: saturn.carry=!saturn.st&0x10;break;
+ case 5: saturn.carry=!saturn.st&0x20;break;
+ case 6: saturn.carry=!saturn.st&0x40;break;
+ case 7: saturn.carry=!saturn.st&0x80;break;
+ case 8: saturn.carry=!saturn.st&0x100;break;
+ case 9: saturn.carry=!saturn.st&0x200;break;
+ case 0xa: saturn.carry=!saturn.st&0x400;break;
+ case 0xb: saturn.carry=!saturn.st&0x800;break;
+ case 0xc: saturn.carry=!saturn.st&0x1000;break;
+ case 0xd: saturn.carry=!saturn.st&0x2000;break;
+ case 0xe: saturn.carry=!saturn.st&0x4000;break;
+ case 0xf: saturn.carry=!saturn.st&0x8000;break;
+ }
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_st_jump_bit_set(void)
+{
+ int adr;
+ switch(READ_OP_ARG()) {
+ case 0: saturn.carry=saturn.st&1;break;
+ case 1: saturn.carry=saturn.st&2;break;
+ case 2: saturn.carry=saturn.st&4;break;
+ case 3: saturn.carry=saturn.st&8;break;
+ case 4: saturn.carry=saturn.st&0x10;break;
+ case 5: saturn.carry=saturn.st&0x20;break;
+ case 6: saturn.carry=saturn.st&0x40;break;
+ case 7: saturn.carry=saturn.st&0x80;break;
+ case 8: saturn.carry=saturn.st&0x100;break;
+ case 9: saturn.carry=saturn.st&0x200;break;
+ case 0xa: saturn.carry=saturn.st&0x400;break;
+ case 0xb: saturn.carry=saturn.st&0x800;break;
+ case 0xc: saturn.carry=saturn.st&0x1000;break;
+ case 0xd: saturn.carry=saturn.st&0x2000;break;
+ case 0xe: saturn.carry=saturn.st&0x4000;break;
+ case 0xf: saturn.carry=saturn.st&0x8000;break;
+ }
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_hst_clear_bits(void)
+{
+ saturn.hst&=~READ_OP_ARG();
+}
+
+INLINE void saturn_hst_bits_cleared(void)
+{
+ saturn.carry=!(saturn.hst&READ_OP_ARG());
+}
+
+/* p related */
+INLINE void saturn_exchange_p(void)
+{
+ int nr=READ_OP_ARG();
+ int t=saturn.p;
+ saturn.p=S64_READ_NIBBLE(C,nr);
+ S64_WRITE_NIBBLE(C,nr,t);
+}
+
+INLINE void saturn_p_to_c(void)
+{
+ int nr=READ_OP_ARG();
+ S64_WRITE_NIBBLE(C,nr,saturn.p);
+}
+
+INLINE void saturn_c_to_p(void)
+{
+ int nr=READ_OP_ARG();
+ saturn.p=S64_READ_NIBBLE(C,nr);
+}
+
+INLINE void saturn_dec_p(void)
+{
+ saturn.carry=saturn.p==0;
+ saturn.p=saturn.p-1;
+}
+
+INLINE void saturn_inc_p(void)
+{
+ saturn.p=saturn.p+1;
+ saturn.carry=saturn.p==0;
+}
+
+INLINE void saturn_load_p(void)
+{
+ saturn.p=READ_OP_ARG();
+}
+
+INLINE void saturn_p_equals(void)
+{
+ int nr=READ_OP_ARG();
+ int adr;
+ saturn.carry=saturn.p==nr;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_p_not_equals(void)
+{
+ int nr=READ_OP_ARG();
+ int adr;
+ saturn.carry=saturn.p!=nr;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_ca_p_1(void)
+{
+ int a=S64_READ_A(C)+1+saturn.p;
+ saturn.carry=a>=0x100000;
+ S64_WRITE_A(C,a&0xfffff);
+}
+
+INLINE void saturn_load_reg(int reg)
+{
+ int count=READ_OP_ARG();
+ int pos=saturn.p;
+ for (; count>=0; count--, pos=(pos+1)&0xf ) {
+ S64_WRITE_NIBBLE( reg, pos, READ_OP_ARG());
+ }
+}
+
+INLINE void saturn_jump(int adr, int jump)
+{
+ if (jump) {
+ saturn.pc=adr;
+ saturn_ICount-=10;
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_call(int adr)
+{
+ saturn_push(saturn.pc);
+ saturn.pc=adr;
+// saturn_ICount-=10;
+ change_pc(saturn.pc);
+}
+
+INLINE void saturn_return(int yes)
+{
+ if (yes) {
+ saturn.pc=saturn_pop();
+// saturn_ICount-=10;
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_return_carry_set(void)
+{
+ saturn.pc=saturn_pop();
+// saturn_ICount-=10;
+ change_pc(saturn.pc);
+ saturn.carry=1;
+}
+
+INLINE void saturn_return_carry_clear(void)
+{
+ saturn.pc=saturn_pop();
+// saturn_ICount-=10;
+ change_pc(saturn.pc);
+ saturn.carry=0;
+}
+
+INLINE void saturn_return_interrupt(void)
+{
+ saturn.pc=saturn_pop();
+// saturn_ICount-=10;
+ change_pc(saturn.pc);
+}
+
+INLINE void saturn_return_xm_set(void)
+{
+ saturn.pc=saturn_pop();
+ saturn.hst|=XM;
+// saturn_ICount-=10;
+ change_pc(saturn.pc);
+}
+
+INLINE void saturn_pop_c(void)
+{
+ S64_WRITE_A(C,saturn_pop());
+}
+
+INLINE void saturn_push_c(void)
+{
+ saturn_push(S64_READ_A(C));
+}
+
+INLINE void saturn_indirect_jump(int reg)
+{
+ saturn.pc=READ_20(S64_READ_A(reg));
+ change_pc(saturn.pc);
+}
+
+INLINE void saturn_equals_zero(int reg, int begin, int count)
+{
+ int i, t,adr;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ if (t!=0) break;
+ saturn_ICount-=2;
+ }
+ saturn.carry=i==count;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_equals(int reg, int begin, int count, int right)
+{
+ int i, t,t2,adr;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t2=S64_READ_NIBBLE(right, (begin+i)&0xf );
+ if (t!=t2) break;
+ saturn_ICount-=2;
+ }
+ saturn.carry=i==count;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_not_equals_zero(int reg, int begin, int count)
+{
+ int i, t,adr;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ if (t==0) break;
+ saturn_ICount-=2;
+ }
+ saturn.carry=i==count;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_not_equals(int reg, int begin, int count, int right)
+{
+ int i, t,t2,adr;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t2=S64_READ_NIBBLE(right, (begin+i)&0xf );
+ if (t==t2) break;
+ saturn_ICount-=2;
+ }
+ saturn.carry=i==count;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_greater(int reg, int begin, int count, int right)
+{
+ int i, t,t2,adr;
+ for (i=count; i>=0; i--) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t2=S64_READ_NIBBLE(right, (begin+i)&0xf );
+ if (t<=t2) break;
+ saturn_ICount-=2;
+ }
+ saturn.carry=i<0;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_greater_equals(int reg, int begin, int count, int right)
+{
+ int i, t,t2,adr;
+ for (i=count; i>=0; i--) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t2=S64_READ_NIBBLE(right, (begin+i)&0xf );
+ if (t<t2) break;
+ saturn_ICount-=2;
+ }
+ saturn.carry=i<0;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_smaller_equals(int reg, int begin, int count, int right)
+{
+ int i, t,t2,adr;
+ for (i=count; i>=0; i--) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t2=S64_READ_NIBBLE(right, (begin+i)&0xf );
+ if (t>t2) break;
+ saturn_ICount-=2;
+ }
+ saturn.carry=i<0;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_smaller(int reg, int begin, int count, int right)
+{
+ int i, t,t2,adr;
+ for (i=count; i>=0; i--) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t2=S64_READ_NIBBLE(right, (begin+i)&0xf );
+ if (t>=t2) break;
+ saturn_ICount-=2;
+ }
+ saturn.carry=i<0;
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_jump_bit_clear(int reg)
+{
+ int adr;
+ switch(READ_OP_ARG()) {
+ case 0: saturn.carry=!(S64_BYTE( reg, 0)&1);break;
+ case 1: saturn.carry=!(S64_BYTE( reg, 0)&2);break;
+ case 2: saturn.carry=!(S64_BYTE( reg, 0)&4);break;
+ case 3: saturn.carry=!(S64_BYTE( reg, 0)&8);break;
+ case 4: saturn.carry=!(S64_BYTE( reg, 0)&0x10);break;
+ case 5: saturn.carry=!(S64_BYTE( reg, 0)&0x20);break;
+ case 6: saturn.carry=!(S64_BYTE( reg, 0)&0x40);break;
+ case 7: saturn.carry=!(S64_BYTE( reg, 0)&0x80);break;
+ case 8: saturn.carry=!(S64_BYTE( reg, 1)&1);break;
+ case 9: saturn.carry=!(S64_BYTE( reg, 1)&2);break;
+ case 0xa: saturn.carry=!(S64_BYTE( reg, 1)&4);break;
+ case 0xb: saturn.carry=!(S64_BYTE( reg, 1)&8);break;
+ case 0xc: saturn.carry=!(S64_BYTE( reg, 1)&0x10);break;
+ case 0xd: saturn.carry=!(S64_BYTE( reg, 1)&0x20);break;
+ case 0xe: saturn.carry=!(S64_BYTE( reg, 1)&0x40);break;
+ case 0xf: saturn.carry=!(S64_BYTE( reg, 1)&0x80);break;
+ }
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_jump_bit_set(int reg)
+{
+ int adr;
+ switch(READ_OP_ARG()) {
+ case 0: saturn.carry=S64_BYTE( reg, 0)&1;break;
+ case 1: saturn.carry=S64_BYTE( reg, 0)&2;break;
+ case 2: saturn.carry=S64_BYTE( reg, 0)&4;break;
+ case 3: saturn.carry=S64_BYTE( reg, 0)&8;break;
+ case 4: saturn.carry=S64_BYTE( reg, 0)&0x10;break;
+ case 5: saturn.carry=S64_BYTE( reg, 0)&0x20;break;
+ case 6: saturn.carry=S64_BYTE( reg, 0)&0x40;break;
+ case 7: saturn.carry=S64_BYTE( reg, 0)&0x80;break;
+ case 8: saturn.carry=S64_BYTE( reg, 1)&1;break;
+ case 9: saturn.carry=S64_BYTE( reg, 1)&2;break;
+ case 0xa: saturn.carry=S64_BYTE( reg, 1)&4;break;
+ case 0xb: saturn.carry=S64_BYTE( reg, 1)&8;break;
+ case 0xc: saturn.carry=S64_BYTE( reg, 1)&0x10;break;
+ case 0xd: saturn.carry=S64_BYTE( reg, 1)&0x20;break;
+ case 0xe: saturn.carry=S64_BYTE( reg, 1)&0x40;break;
+ case 0xf: saturn.carry=S64_BYTE( reg, 1)&0x80;break;
+ }
+ adr=READ_OP_DIS8();
+ if (saturn.carry) {
+ if (adr==0) {
+ saturn.pc=saturn_pop();
+ } else {
+ saturn.pc=(saturn.pc+adr-2)&0xfffff;
+ }
+ change_pc(saturn.pc);
+ }
+}
+
+INLINE void saturn_load_pc(int reg)
+{
+ saturn.pc=S64_READ_A(reg);
+ change_pc(saturn.pc);
+}
+
+INLINE void saturn_store_pc(int reg)
+{
+ S64_WRITE_A(reg,saturn.pc);
+}
+
+INLINE void saturn_exchange_pc(int reg)
+{
+ int temp=saturn.pc;
+ saturn.pc=S64_READ_A(reg);
+ change_pc(saturn.pc);
+ S64_WRITE_A(reg, temp);
+}
+
+/*************************************************************************************
+ address register related
+*************************************************************************************/
+INLINE void saturn_load_adr(int reg, int nibbles)
+{
+ switch (nibbles) {
+ case 5:
+ saturn.d[reg]=READ_OP_ARG20();
+ break;
+ case 4:
+ saturn.d[reg]=(saturn.d[reg]&0xf0000)|READ_OP_ARG16();
+ break;
+ case 2:
+ saturn.d[reg]=(saturn.d[reg]&0xfff00)|READ_OP_ARG8();
+ break;
+ }
+}
+
+INLINE void saturn_add_adr(int reg)
+{
+ int t=saturn.d[reg]+READ_OP_ARG()+1;
+ saturn.d[reg]=t&0xfffff;
+ saturn.carry=t>=0x100000;
+}
+
+INLINE void saturn_sub_adr(int reg)
+{
+ int t=saturn.d[reg]-READ_OP_ARG()-1;
+ saturn.d[reg]=t&0xfffff;
+ saturn.carry=t<0;
+}
+
+INLINE void saturn_adr_to_reg(int adr, int reg)
+{
+ S64_WRITE_A(reg,saturn.d[adr]);
+}
+
+INLINE void saturn_reg_to_adr(int reg, int adr)
+{
+ saturn.d[adr]=S64_READ_A(reg);
+}
+
+INLINE void saturn_adr_to_reg_word(int adr, int reg)
+{
+ S64_WRITE_WORD(reg,0,saturn.d[adr]&0xffff);
+}
+
+INLINE void saturn_reg_to_adr_word(int reg, int adr)
+{
+ saturn.d[adr]=(saturn.d[adr]&0xf0000)|S64_READ_WORD(reg,0);
+}
+
+INLINE void saturn_exchange_adr_reg(int adr, int reg)
+{
+ int temp=saturn.d[adr];
+ saturn.d[adr]=S64_READ_A(reg);
+ S64_WRITE_A(reg,temp);
+}
+
+INLINE void saturn_exchange_adr_reg_word(int adr, int reg)
+{
+ int temp=saturn.d[adr]&0xffff;
+ saturn.d[adr]=(saturn.d[adr]&0xf0000)|S64_READ_WORD(reg,0);
+ S64_WRITE_WORD(reg,0,temp);
+}
+
+INLINE void saturn_load_nibbles(int reg, int begin, int count, int adr)
+{
+ int i;
+ for (i=0; i<count; i++) {
+ S64_WRITE_NIBBLE(reg,(begin+i)&0xf,READ_NIBBLE(saturn.d[adr]+i) );
+ saturn_ICount-=2;
+ }
+}
+
+INLINE void saturn_store_nibbles(int reg, int begin, int count, int adr)
+{
+ int i;
+ for (i=0; i<count; i++) {
+ WRITE_NIBBLE(saturn.d[adr]+i,S64_READ_NIBBLE(reg,(begin+i)&0xf) );
+ saturn_ICount-=2;
+ }
+}
+
+INLINE void saturn_clear_bit(int reg)
+{
+ switch(READ_OP_ARG()) {
+ case 0: S64_BYTE( reg, 0)&=~1;break;
+ case 1: S64_BYTE( reg, 0)&=~2;break;
+ case 2: S64_BYTE( reg, 0)&=~4;break;
+ case 3: S64_BYTE( reg, 0)&=~8;break;
+ case 4: S64_BYTE( reg, 0)&=~0x10;break;
+ case 5: S64_BYTE( reg, 0)&=~0x20;break;
+ case 6: S64_BYTE( reg, 0)&=~0x40;break;
+ case 7: S64_BYTE( reg, 0)&=~0x80;break;
+ case 8: S64_BYTE( reg, 1)&=~1;break;
+ case 9: S64_BYTE( reg, 1)&=~2;break;
+ case 0xa: S64_BYTE( reg, 1)&=~4;break;
+ case 0xb: S64_BYTE( reg, 1)&=~8;break;
+ case 0xc: S64_BYTE( reg, 1)&=~0x10;break;
+ case 0xd: S64_BYTE( reg, 1)&=~0x20;break;
+ case 0xe: S64_BYTE( reg, 1)&=~0x40;break;
+ case 0xf: S64_BYTE( reg, 1)&=~0x80;break;
+ }
+}
+
+INLINE void saturn_set_bit(int reg)
+{
+ switch(READ_OP_ARG()) {
+ case 0: S64_BYTE( reg, 0)|=1;break;
+ case 1: S64_BYTE( reg, 0)|=2;break;
+ case 2: S64_BYTE( reg, 0)|=4;break;
+ case 3: S64_BYTE( reg, 0)|=8;break;
+ case 4: S64_BYTE( reg, 0)|=0x10;break;
+ case 5: S64_BYTE( reg, 0)|=0x20;break;
+ case 6: S64_BYTE( reg, 0)|=0x40;break;
+ case 7: S64_BYTE( reg, 0)|=0x80;break;
+ case 8: S64_BYTE( reg, 1)|=1;break;
+ case 9: S64_BYTE( reg, 1)|=2;break;
+ case 0xa: S64_BYTE( reg, 1)|=4;break;
+ case 0xb: S64_BYTE( reg, 1)|=8;break;
+ case 0xc: S64_BYTE( reg, 1)|=0x10;break;
+ case 0xd: S64_BYTE( reg, 1)|=0x20;break;
+ case 0xe: S64_BYTE( reg, 1)|=0x40;break;
+ case 0xf: S64_BYTE( reg, 1)|=0x80;break;
+ }
+}
+
+/****************************************************************************
+ clear opers
+ ****************************************************************************/
+INLINE void saturn_clear(int reg, int begin, int count)
+{
+ int i;
+ for (i=0; i<count; i++) {
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, 0);
+ saturn_ICount-=2;
+ }
+}
+
+/****************************************************************************
+ exchange opers
+ ****************************************************************************/
+INLINE void saturn_exchange(int left, int begin, int count, int right)
+{
+ int i;
+ SaturnNib temp;
+ for (i=0; i<count; i++) {
+ temp=S64_READ_NIBBLE(left,(begin+i)&0xf);
+ S64_WRITE_NIBBLE(left, (begin+i)&0xf, S64_READ_NIBBLE(right,(begin+i)&0xf));
+ S64_WRITE_NIBBLE(right, (begin+i)&0xf, temp);
+ saturn_ICount-=2;
+ }
+}
+
+/****************************************************************************
+ copy opers
+ ****************************************************************************/
+INLINE void saturn_copy(int dest, int begin, int count, int src)
+{
+ int i;
+ for (i=0; i<count; i++) {
+ S64_WRITE_NIBBLE(dest, (begin+i)&0xf, S64_READ_NIBBLE(src, (begin+i)&0xf));
+ saturn_ICount-=2;
+ }
+}
+
+/****************************************************************************
+ add opers
+ ****************************************************************************/
+INLINE void saturn_add(int reg, int begin, int count, int right)
+{
+ int i, t=0;
+ for (i=0; i<count; i++) {
+ if (t>0x10) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf)+1;
+ } else {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf);
+ }
+ t+=S64_READ_NIBBLE(right, (begin+i)&0xf );
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf , t&0x0f);
+ saturn_ICount-=2;
+ }
+ saturn.carry=t==0x10;
+}
+
+INLINE void saturn_add_const(int reg, int begin, int count, SaturnNib right)
+{
+ int i, t=0;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf);
+ t+=right;
+ right=(right>>4)+1;
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, t&0x0f);
+ saturn_ICount-=2;
+ if (t<0x10) break;
+ }
+ saturn.carry=t>=0x10;
+}
+
+/****************************************************************************
+ sub opers
+ ****************************************************************************/
+INLINE void saturn_sub(int reg, int begin, int count, int right)
+{
+ int i, t=0;
+ for (i=0; i<count; i++) {
+ if (t>0x10) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf)-1;
+ } else {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ }
+ t-=S64_READ_NIBBLE(right, (begin+i)&0xf );
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, t&0x0f);
+ saturn_ICount-=2;
+ }
+ saturn.carry=t<0;
+}
+
+INLINE void saturn_sub_const(int reg, int begin, int count, int right)
+{
+ int i, t=0;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t-=right;
+ right=(right>>4)+1;
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, t&0x0f);
+ saturn_ICount-=2;
+ if (t>=0) break;
+ }
+ saturn.carry=t<0;
+}
+
+/****************************************************************************
+ sub2 opers (a=b-a)
+ ****************************************************************************/
+INLINE void saturn_sub2(int reg, int begin, int count, int right)
+{
+ int i, t=0;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t=S64_READ_NIBBLE(right, i)-t;
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, t&0x0f);
+ saturn_ICount-=2;
+ if (t>=0) break;
+ }
+ saturn.carry=t<0;
+}
+
+/****************************************************************************
+ increment opers
+ ****************************************************************************/
+INLINE void saturn_increment(int reg, int begin, int count)
+{
+ int i, t=0;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t++;
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, t&0x0f);
+ saturn_ICount-=2;
+ if (t!=0x10) break;
+ }
+}
+
+/****************************************************************************
+ decrement opers
+ ****************************************************************************/
+INLINE void saturn_decrement(int reg, int begin, int count)
+{
+ int i, t=0;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ t=(t-1)&0xf;
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, t);
+ saturn_ICount-=2;
+ if (t!=0) break;
+ }
+ saturn.carry=t==0;
+}
+
+/****************************************************************************
+ invert (1 complement) opers
+ ****************************************************************************/
+INLINE void saturn_invert(int reg, int begin, int count)
+{
+ int i;
+ SaturnNib n;
+ saturn.carry=1;
+ for (i=0; i<count; i++) {
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, (n=S64_READ_NIBBLE(reg,(begin+i)&0xf)) ^ 0xf);
+ saturn.carry=saturn.carry && (n==0);
+ saturn_ICount-=2;
+ }
+}
+
+/****************************************************************************
+ negate (2 complement) opers
+ ****************************************************************************/
+INLINE void saturn_negate(int reg, int begin, int count)
+{
+ int i;
+ SaturnNib n;
+ saturn.carry=1;
+ for (i=0; i<count; i++) {
+ n=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ saturn.carry=saturn.carry && (n==0);
+ n=((n ^ 0xf)+1)&0xf;
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, n);
+ saturn_ICount-=2;
+ }
+}
+
+/****************************************************************************
+ or opers
+ ****************************************************************************/
+INLINE void saturn_or(int dest, int begin, int count, int src)
+{
+ int i;
+ for (i=0; i<count; i++) {
+ S64_WRITE_NIBBLE(dest, (begin+i)&0xf,
+ S64_READ_NIBBLE(dest,(begin+i)&0xf)|S64_READ_NIBBLE(src,(begin+i)&0xf));
+ saturn_ICount-=2;
+ }
+}
+
+/****************************************************************************
+ and opers
+ ****************************************************************************/
+INLINE void saturn_and(int dest, int begin, int count, int src)
+{
+ int i;
+ for (i=0; i<count; i++) {
+ S64_WRITE_NIBBLE(dest, (begin+i)&0xf,
+ S64_READ_NIBBLE(dest,(begin+i)&0xf)&S64_READ_NIBBLE(src,(begin+i)&0xf));
+ saturn_ICount-=2;
+ }
+}
+
+/****************************************************************************
+ shift nibbles left opers
+ ****************************************************************************/
+INLINE void saturn_shift_nibble_left(int reg, int begin, int count)
+{
+ int i;
+ for (i=count; i>1; i--) {
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, S64_READ_NIBBLE(reg,(begin+i-1)&0xf) );
+ saturn_ICount-=2;
+ }
+ S64_WRITE_NIBBLE(reg, begin, 0);
+ saturn_ICount-=2;
+}
+
+/****************************************************************************
+ shift nibbles right opers
+ ****************************************************************************/
+INLINE void saturn_shift_nibble_right(int reg, int begin, int count)
+{
+ int i;
+ for (i=1; i<count; i++) {
+ S64_WRITE_NIBBLE(reg, (begin+i-1)&0xf, S64_READ_NIBBLE(reg,(begin+i)&0xf) );
+ saturn_ICount-=2;
+ }
+ S64_WRITE_NIBBLE(reg, (begin+i-1)&0xf, 0);
+ saturn_ICount-=2;
+}
+
+/****************************************************************************
+ rotate nibble left opers
+ ****************************************************************************/
+INLINE void saturn_rotate_nibble_left_w(int reg)
+{
+ SaturnNib a=S64_READ_NIBBLE(reg, 15);
+ S64_WRITE_W(reg, S64_READ_W(reg)<<4);
+ S64_WRITE_NIBBLE(reg,0,a);
+ saturn_ICount-=32;
+}
+
+INLINE void saturn_rotate_nibble_right_w(int reg)
+{
+ SaturnNib a=S64_READ_NIBBLE(reg,0);
+ if (a) saturn.hst|=SB;
+ S64_WRITE_W(reg, S64_READ_W(reg)>>4);
+ S64_WRITE_NIBBLE(reg,15,a);
+ saturn_ICount-=32;
+}
+
+/****************************************************************************
+ shift right opers
+ ****************************************************************************/
+INLINE void saturn_shift_right(int reg, int begin, int count)
+{
+ int i, t, c=0;
+ for (i=count; i>=count; i--) {
+ t=S64_READ_NIBBLE(reg, (begin+i)&0xf );
+ if (c) t|=0x10;
+ c=t&1;
+ S64_WRITE_NIBBLE(reg, (begin+i-1)&0xf, t>>1);
+ saturn_ICount-=2;
+ }
+ if (c) saturn.hst|=SB;
+ saturn_ICount-=2;
+}
+
+
+/****************************************************************************
+ shift left opers, sets carry!
+ ****************************************************************************/
+INLINE void saturn_shift_left(int reg, int begin, int count)
+{
+ SaturnNib t;
+ int i;
+ saturn.carry=0;
+ for (i=0; i<count; i++) {
+ t=S64_READ_NIBBLE(reg,(begin+i)&0xf);
+ S64_WRITE_NIBBLE(reg, (begin+i)&0xf, ((t<<1)&0xf)|saturn.carry);
+ saturn.carry=t&8?1:0;
+ saturn_ICount-=2;
+ }
+}
diff --git a/src/emu/cpu/saturn/sattable.c b/src/emu/cpu/saturn/sattable.c
new file mode 100644
index 00000000000..3eb06fd986d
--- /dev/null
+++ b/src/emu/cpu/saturn/sattable.c
@@ -0,0 +1,921 @@
+static const int adr_a_begin[]={
+-1, -1, BEGIN_XS, BEGIN_X, BEGIN_S, BEGIN_M, BEGIN_B, BEGIN_W,
+};
+
+static const int adr_a_count[]={
+-1, -1, COUNT_XS, COUNT_X, COUNT_S, COUNT_M, COUNT_B, COUNT_W,
+};
+
+static const int adr_b_begin[]={
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, BEGIN_XS, BEGIN_X, BEGIN_S, BEGIN_M, BEGIN_B, BEGIN_W,
+};
+
+static const int adr_b_count[]={
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, COUNT_XS, COUNT_X, COUNT_S, COUNT_M, COUNT_B, COUNT_W,
+};
+
+static const int adr_af_begin[]={
+-1, -1, BEGIN_XS, BEGIN_X, BEGIN_S, BEGIN_M, BEGIN_B, BEGIN_W,
+-1, -1, -1, -1, -1, -1, -1, BEGIN_A
+};
+
+static const int adr_af_count[]={
+-1, -1, COUNT_XS, COUNT_X, COUNT_S, COUNT_M, COUNT_B, COUNT_W,
+-1, -1, -1, -1, -1, -1, -1, COUNT_A
+};
+
+static const int reg_left[]={A,B,C,D,B,C,A,C};
+static const int reg_right[]={B,C,A,C,A,B,C,D};
+static const int add_left[]={ A,B,C,D, 0,0,0,0, B,C,A,C };
+static const int add_right[]={ B,C,A,C, 0,0,0,0, A,B,C,D };
+static const int sub_left[]={A,B,C,D, 0,0,0,0, B,C,A,C, A,B,C,D};
+static const int sub_right[]={B,C,A,C, 0,0,0,0, A,B,C,D, A,B,C,D };
+
+INLINE void saturn_instruction_0e(void)
+{
+ int reg, adr;
+
+ switch(adr=READ_OP()) {
+ case 0:
+ switch(reg=READ_OP()){
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ saturn_and(reg_left[reg], saturn.p, 1, reg_right[reg]);
+ break; //A=A&B p
+ case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_or(reg_left[reg&7], saturn.p, 1, reg_right[reg&7]);
+ break; //A=A!B p
+ }
+ break;
+ case 1:
+ switch(reg=READ_OP()){
+ case 0: case 1: case 2: case 3:case 4: case 5: case 6: case 7:
+ saturn_and(reg_left[reg], 0, saturn.p+1, reg_right[reg]);
+ break; //A=A&B wp
+ case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_or(reg_left[reg&7], 0, saturn.p+1, reg_right[reg&7]);
+ break; //A=A!B wp
+ }
+ break;
+ case 2: case 3: case 4: case 5: case 6: case 7: case 0xf:
+ switch(reg=READ_OP()){
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ saturn_and(reg_left[reg], adr_af_begin[adr], adr_af_count[adr], reg_right[reg]);
+ break; //A=A&B xs
+ case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_or(reg_left[reg&7], adr_af_begin[adr], adr_af_count[adr], reg_right[reg&7]);
+ break; //A=A!B xs
+ }
+ break;
+ }
+}
+
+static void saturn_instruction_1(void)
+{
+ int reg, adr, oper;
+
+ switch (adr=READ_OP()) {
+ case 0:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_copy(R0+reg, BEGIN_W, COUNT_W, A);
+ break; // r0=a w
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_copy(R0+(reg&7), BEGIN_W, COUNT_W, C);
+ break; // r0=c w
+ }
+ break;
+ case 1:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_copy(A, BEGIN_W, COUNT_W, R0+reg);
+ break; // a=r0 w
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_copy(C, BEGIN_W, COUNT_W, R0+(reg&7));
+ break; // c=r0 w
+ }
+ break;
+ case 2:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_exchange(A, BEGIN_W, COUNT_W, R0+reg);
+ break; // ar0ex w
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_exchange(C, BEGIN_W, COUNT_W, R0+(reg&7));
+ break; // cr0ex w
+ }
+ break;
+ case 3:
+ switch (READ_OP()) {
+ case 0: saturn_reg_to_adr(A,0);break;
+ case 1: saturn_reg_to_adr(A,1);break;
+ case 2: saturn_exchange_adr_reg(0,A);break;
+ case 3: saturn_exchange_adr_reg(1,A);break;
+ case 4: saturn_reg_to_adr(C,0);break;
+ case 5: saturn_reg_to_adr(C,1);break;
+ case 6: saturn_exchange_adr_reg(0,C);break;
+ case 7: saturn_exchange_adr_reg(1,C);break;
+ case 8: saturn_reg_to_adr_word(A,0);break;
+ case 9: saturn_reg_to_adr_word(A,1);break;
+ case 0xa: saturn_exchange_adr_reg_word(0,A);break;
+ case 0xb: saturn_exchange_adr_reg_word(1,A);break;
+ case 0xc: saturn_reg_to_adr_word(C,0);break;
+ case 0xd: saturn_reg_to_adr_word(C,1);break;
+ case 0xe: saturn_exchange_adr_reg_word(0,C);break;
+ case 0xf: saturn_exchange_adr_reg_word(1,C);break;
+ }
+ break;
+ case 4:
+ switch (READ_OP()) {
+ case 0: saturn_store_nibbles(A, BEGIN_A, COUNT_A, 0); break;
+ case 1: saturn_store_nibbles(A, BEGIN_A, COUNT_A, 1); break;
+ case 2: saturn_load_nibbles(A, BEGIN_A, COUNT_A, 0); break;
+ case 3: saturn_load_nibbles(A, BEGIN_A, COUNT_A, 1); break;
+ case 4: saturn_store_nibbles(C, BEGIN_A, COUNT_A, 0); break;
+ case 5: saturn_store_nibbles(C, BEGIN_A, COUNT_A, 1); break;
+ case 6: saturn_load_nibbles(C, BEGIN_A, COUNT_A, 0); break;
+ case 7: saturn_load_nibbles(C, BEGIN_A, COUNT_A, 1); break;
+ case 8: saturn_store_nibbles(A, BEGIN_B, COUNT_B, 0); break;
+ case 9: saturn_store_nibbles(A, BEGIN_B, COUNT_B, 1); break;
+ case 0xa: saturn_load_nibbles(A, BEGIN_B, COUNT_B, 0); break;
+ case 0xb: saturn_load_nibbles(A, BEGIN_B, COUNT_B, 1); break;
+ case 0xc: saturn_store_nibbles(C, BEGIN_B, COUNT_B, 0); break;
+ case 0xd: saturn_store_nibbles(C, BEGIN_B, COUNT_B, 1); break;
+ case 0xe: saturn_load_nibbles(C, BEGIN_B, COUNT_B, 0); break;
+ case 0xf: saturn_load_nibbles(C, BEGIN_B, COUNT_B, 1); break;
+ }
+ break;
+ case 5:
+ switch (oper=READ_OP()) {
+ case 0: case 1: case 4: case 5:
+ switch (adr=READ_OP()) {
+ case 0:
+ saturn_store_nibbles(oper&4?C:A,saturn.p,1,oper&1);
+ break;
+ case 1:
+ saturn_store_nibbles(oper&4?C:A,0,saturn.p+1,oper&1);
+ break;
+ case 2: case 3: case 4: case 5: case 6: case 7:
+ saturn_store_nibbles(oper&4?C:A,adr_a_begin[adr],adr_a_count[adr],oper&1);
+ break;
+ }
+ break;
+ case 2: case 3: case 6: case 7:
+ switch (adr=READ_OP()) {
+ case 0:
+ saturn_load_nibbles(oper&4?C:A,saturn.p,1,oper&1);
+ break;
+ case 1:
+ saturn_load_nibbles(oper&4?C:A,0,saturn.p+1,oper&1);
+ break;
+ case 2: case 3: case 4: case 5: case 6: case 7:
+ saturn_load_nibbles(oper&4?C:A,adr_a_begin[adr],adr_a_count[adr],oper&1);
+ break;
+ }
+ break;
+ case 8: saturn_store_nibbles(A, 0, READ_OP()+1, 0); break;
+ case 9: saturn_store_nibbles(A, 0, READ_OP()+1, 1); break;
+ case 0xa: saturn_load_nibbles(A, 0, READ_OP()+1, 0); break;
+ case 0xb: saturn_load_nibbles(A, 0, READ_OP()+1, 1); break;
+ case 0xc: saturn_store_nibbles(C, 0, READ_OP()+1, 0); break;
+ case 0xd: saturn_store_nibbles(C, 0, READ_OP()+1, 1); break;
+ case 0xe: saturn_load_nibbles(C, 0, READ_OP()+1, 0); break;
+ case 0xf: saturn_load_nibbles(C, 0, READ_OP()+1, 1); break;
+ }
+ break;
+ case 9: saturn_load_adr(0,2);break;
+ case 0xa: saturn_load_adr(0,4);break;
+ case 0xb: saturn_load_adr(0,5);break;
+ case 0xd: saturn_load_adr(1,2);break;
+ case 0xe: saturn_load_adr(1,4);break;
+ case 0xf: saturn_load_adr(1,5);break;
+ case 6: saturn_add_adr(0);break;
+ case 7: saturn_add_adr(1);break;
+ case 8: saturn_sub_adr(0);break;
+ case 0xc: saturn_sub_adr(1);break;
+ }
+}
+
+static void saturn_instruction_80(void)
+{
+ switch(READ_OP()) {
+ case 0: saturn_out_cs();break;
+ case 1: saturn_out_c();break;
+ case 2: saturn_in(A);break;
+ case 3: saturn_in(C);break;
+ case 4: saturn_mem_unconfig();break;
+ case 5: saturn_mem_config();break;
+ case 6: saturn_mem_id();break;
+ case 7: saturn_shutdown();break;
+ case 8:
+ switch(READ_OP()) {
+ case 0: saturn_interrupt_on();break;
+ case 1:
+ switch(READ_OP()) {
+ case 0: saturn_reset_interrupt();break;
+ }
+ break;
+ case 2: saturn_load_reg(A);break; //la
+ case 3: saturn_bus_command_c();break;
+ case 4: saturn_clear_bit(A);break; // abit=0
+ case 5: saturn_set_bit(A);break; // abit=1
+ case 6: saturn_jump_bit_clear(A);break;
+ case 7: saturn_jump_bit_set(A);break;
+ case 8: saturn_clear_bit(C);break; // cbit=0
+ case 9: saturn_set_bit(C);break; // cbit=1
+ case 0xa: saturn_jump_bit_clear(C);break;
+ case 0xb: saturn_jump_bit_set(C);break;
+ case 0xc: saturn_indirect_jump(A);break;
+ case 0xd: saturn_bus_command_d();break;
+ case 0xe: saturn_indirect_jump(C);break;
+ case 0xf: saturn_interrupt_off();break;
+ }
+ break;
+ case 9: saturn_ca_p_1();break;//C+P+1
+ case 0xa: saturn_mem_reset();break;
+ case 0xb: saturn_bus_command_b();break;
+ case 0xc: saturn_p_to_c();break;
+ case 0xd: saturn_c_to_p();break;
+ case 0xe: saturn_serial_request();break;
+ case 0xf: saturn_exchange_p();break;
+ }
+}
+
+static void saturn_instruction_81a(void)
+{
+ int reg, adr;
+ switch(adr=READ_OP()) {
+ case 0:
+ switch(READ_OP()) {
+ case 0:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_copy(R0+reg,saturn.p,1,A);
+ break; //r0=a p
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_copy(R0+(reg&7),saturn.p,1,C);
+ break; //r0=c p
+ }
+ break;
+ case 1:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_copy(A,saturn.p,1,R0+reg);
+ break; //a=r0 p
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_copy(C,saturn.p,1,R0+(reg&7));
+ break; //c=r0 p
+ }
+ break;
+ case 2:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_exchange(A, saturn.p,1,R0+reg);
+ break; // ar0ex p
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_exchange(C, saturn.p,1,R0+(reg&7));
+ break; // cr0ex p
+ }
+ break;
+ }
+ break;
+ case 1:
+ switch(READ_OP()) {
+ case 0:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_copy(R0+reg,0,saturn.p+1,A);
+ break; //r0=a wp
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_copy(R0+(reg&7),0,saturn.p+1,C);
+ break; //r0=c wp
+ }
+ break;
+ case 1:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_copy(A,0,saturn.p+1,R0+reg);
+ break; //a=r0 wp
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_copy(C,0,saturn.p+1,R0+(reg&7));
+ break; //c=r0 wp
+ }
+ break;
+ case 2:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_exchange(A, 0, saturn.p+1, R0+reg);
+ break; // ar0ex wp
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_exchange(C, 0, saturn.p+1, R0+(reg&7));
+ break; // cr0ex wp
+ }
+ break;
+ }
+ break;
+ case 2: case 3: case 4: case 5: case 6: case 7: case 0xf:
+ switch(READ_OP()) {
+ case 0:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_copy(R0+reg,adr_af_begin[adr],adr_af_count[adr],A);
+ break; //r0=a xs
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_copy(R0+(reg&7),adr_af_begin[adr], adr_af_count[adr],C);
+ break; //r0=c xs
+ }
+ break;
+ case 1:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_copy(A,adr_af_begin[adr],adr_af_count[adr],R0+reg);
+ break; //a=r0 xs
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_copy(C,adr_af_begin[adr],adr_af_count[adr],R0+(reg&7));
+ break; //c=r0 xs
+ }
+ break;
+ case 2:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3: case 4:
+ saturn_exchange(A, adr_af_begin[adr], adr_af_count[adr], R0+reg);
+ break; // ar0ex xs
+ case 8: case 9: case 0xa: case 0xb: case 0xc:
+ saturn_exchange(C, adr_af_begin[adr], adr_af_count[adr], R0+(reg&7));
+ break; // cr0ex xs
+ }
+ break;
+ }
+ break;
+ }
+}
+
+static void saturn_instruction_81(void)
+{
+ int reg, adr;
+
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_rotate_nibble_left_w(A+reg); break; // aslc w
+ case 4: case 5: case 6: case 7:
+ saturn_rotate_nibble_right_w(A+(reg&3)); break; // asrc w
+ case 8:
+ switch(adr=READ_OP()) {
+ case 0:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_add_const(A+reg, saturn.p, 1, READ_OP()+1);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_sub_const(A+reg, saturn.p, 1, READ_OP()+1);
+ break;
+ }
+ break;
+ case 1:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_add_const(A+reg, 1, saturn.p+1, READ_OP()+1);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_sub_const(A+reg, 1, saturn.p+1, READ_OP()+1);
+ break;
+ }
+ break;
+ case 2: case 3: case 4: case 5: case 6: case 7: case 0xf:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_add_const(A+reg, adr_af_begin[adr], adr_af_count[adr], READ_OP()+1);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_sub_const(A+reg, adr_af_begin[adr], adr_af_count[adr], READ_OP()+1);
+ break;
+ }
+ break;
+ }
+ break;
+ case 9:
+ switch(adr=READ_OP()) {
+ case 0:
+ switch(reg=READ_OP()){
+ case 0: case 1: case 2: case 3:
+ saturn_shift_right(A+reg,saturn.p,1);
+ break; // asrb p
+ }
+ break;
+ case 1:
+ switch(reg=READ_OP()){
+ case 0: case 1: case 2: case 3:
+ saturn_shift_right(A+reg, 0,saturn.p+1);
+ break; // asrb wp
+ }
+ break;
+ case 2: /*case 3:*/ case 4: case 5: case 6:/* case 7:*/case 0xf:
+ switch(reg=READ_OP()){
+ case 0: case 1: case 2: case 3:
+ saturn_shift_right(A+reg, adr_af_begin[adr], adr_af_count[adr]);
+ break; // asrb xs
+ }
+ break;
+ }
+ break;
+ case 0xa:
+ saturn_instruction_81a();
+ break;
+ case 0xb:
+ switch(READ_OP()) {
+ case 2: saturn_load_pc(A);break;
+ case 3: saturn_load_pc(C);break;
+ case 4: saturn_store_pc(A);break;
+ case 5: saturn_store_pc(C);break;
+ case 6: saturn_exchange_pc(A);break;
+ case 7: saturn_exchange_pc(C);break;
+ }
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_shift_right(A+(reg&3), BEGIN_W, COUNT_W);
+ break; // asrb w
+ }
+}
+
+static void saturn_instruction_8(void)
+{
+ int oper;
+
+ switch(READ_OP()) {
+ case 0:
+ saturn_instruction_80();
+ break;
+ case 1:
+ saturn_instruction_81();
+ break;
+ case 2: saturn_hst_clear_bits();break;
+ case 3: saturn_hst_bits_cleared();break;
+ case 4: saturn_st_clear_bit();break;
+ case 5: saturn_st_set_bit();break;
+ case 6: saturn_st_jump_bit_clear();break;
+ case 7: saturn_st_jump_bit_set();break;
+ case 8: saturn_p_not_equals(); break;
+ case 9: saturn_p_equals(); break;
+ case 0xa:
+ switch(oper=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_equals(reg_left[oper&3] , BEGIN_A, COUNT_A, reg_right[oper&3]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_not_equals(reg_left[oper&3] , BEGIN_A, COUNT_A, reg_right[oper&3]);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_equals_zero(A+(oper&3), BEGIN_A, COUNT_A);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_not_equals_zero(A+(oper&3), BEGIN_A, COUNT_A);
+ break;
+ }
+ break;
+ case 0xb:
+ switch(oper=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_greater(reg_left[oper&3] , BEGIN_A, COUNT_A, reg_right[oper&3]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_smaller(reg_left[oper&3] , BEGIN_A, COUNT_A, reg_right[oper&3]);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_greater_equals(reg_left[oper&3], BEGIN_A, COUNT_A, reg_right[oper&3]);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_smaller_equals(reg_left[oper&3], BEGIN_A, COUNT_A, reg_right[oper&3]);
+ break;
+ }
+ break;
+ case 0xc: saturn_jump((READ_OP_DIS16()+saturn.pc-4)&0xfffff,1);break;
+ case 0xd: saturn_jump(READ_OP_ARG20(),1);break;
+ case 0xe: saturn_call((READ_OP_DIS16()+saturn.pc)&0xfffff);break;
+ case 0xf: saturn_call(READ_OP_ARG20());break;
+ }
+}
+
+static void saturn_instruction_9(void)
+{
+ int adr, oper;
+
+ switch(adr=READ_OP()) {
+ case 0:
+ switch(oper=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_equals(reg_left[oper&3] , saturn.p, 1, reg_right[oper&3]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_not_equals(reg_left[oper&3] ,saturn.p, 1, reg_right[oper&3]);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_equals_zero(A+(oper&3), saturn.p, 1);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_not_equals_zero(A+(oper&3), saturn.p, 1);
+ break;
+ }
+ break;
+ case 1:
+ switch(oper=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_equals(reg_left[oper&3] , 0, saturn.p+1, reg_right[oper&3]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_not_equals(reg_left[oper&3] , 0, saturn.p+1, reg_right[oper&3]);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_equals_zero(A+(oper&3), 0, saturn.p+1);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_not_equals_zero(A+(oper&3), 0, saturn.p+1);
+ break;
+ }
+ break;
+ case 2: case 3: case 4: case 5:
+ case 6: case 7:
+ switch(oper=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_equals(reg_left[oper&3] ,adr_a_begin[adr], adr_a_count[adr], reg_right[oper&3]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_not_equals(reg_left[oper&3] ,adr_a_begin[adr], adr_a_count[adr], reg_right[oper&3]);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_equals_zero(A+(oper&3),adr_a_begin[adr], adr_a_count[adr]);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_not_equals_zero(A+(oper&3) ,adr_a_begin[adr], adr_a_count[adr]);
+ break;
+ }
+ break;
+ case 8:
+ switch(oper=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_greater(reg_left[oper&3] ,saturn.p, 1, reg_right[oper&3]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_smaller(reg_left[oper&3] ,saturn.p, 1, reg_right[oper&3]);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_greater_equals(reg_left[oper&3] ,saturn.p, 1, reg_right[oper&3]);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_smaller_equals(reg_left[oper&3] ,saturn.p, 1, reg_right[oper&3]);
+ break;
+ }
+ break;
+ case 9:
+ switch(oper=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_greater(reg_left[oper&3] , 0, saturn.p+1, reg_right[oper&3]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_smaller(reg_left[oper&3] , 0, saturn.p+1, reg_right[oper&3]);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_greater_equals(reg_left[oper&3], 0, saturn.p+1, reg_right[oper&3]);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_smaller_equals(reg_left[oper&3], 0, saturn.p+1, reg_right[oper&3]);
+ break;
+ }
+ break;
+ case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf:
+ switch(oper=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_greater(reg_left[oper&3] ,adr_b_begin[adr], adr_b_count[adr], reg_right[oper&3]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_smaller(reg_left[oper&3] ,adr_b_begin[adr], adr_b_count[adr], reg_right[oper&3]);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_greater_equals(reg_left[oper&3] ,adr_b_begin[adr], adr_b_count[adr], reg_right[oper&3]);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_smaller_equals(reg_left[oper&3] ,adr_b_begin[adr], adr_b_count[adr], reg_right[oper&3]);
+ break;
+ }
+ break;
+ }
+}
+
+static void saturn_instruction_a(void)
+{
+ int reg, adr;
+
+ switch(adr=READ_OP()) {
+ case 0:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_add(add_left[reg], saturn.p, 1, add_right[reg]);
+ break;
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_shift_left(A+(reg&3), saturn.p, 1);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_decrement(A+(reg&3), saturn.p, 1);
+ break;
+ }
+ break;
+ case 1:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_add(add_left[reg], 1, saturn.p+1, add_right[reg]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_shift_left(A+(reg&3), 1, saturn.p+1);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_decrement(A+(reg&3), 1, saturn.p+1);
+ break;
+ }
+ break;
+ case 2: case 3: case 4: case 5: case 6: case 7:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_add(add_left[reg], adr_a_begin[adr], adr_a_count[adr], add_right[reg]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_shift_left(A+(reg&3), adr_a_begin[adr], adr_a_count[adr]);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_decrement(A+(reg&3), adr_a_begin[adr], adr_a_count[adr]);
+ break;
+ }
+ break;
+ case 8:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_clear(A+reg, saturn.p,1);
+ break; // a=0 p
+ case 4: case 5: case 6: case 7:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_copy(reg_right[reg&7], saturn.p,1,reg_left[reg&7]); //!correct
+ break; // a=b p
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_exchange(reg_left[reg&3], saturn.p,1,reg_right[reg&3]);
+ break; // abex p
+ }
+ break;
+ case 9:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_clear(A+reg,0,saturn.p+1);
+ break; // a=0 wp
+ case 4: case 5: case 6: case 7:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_copy(reg_right[reg&7], 0, saturn.p+1, reg_left[reg&7]); //!correct
+ break; // a=b wp
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_exchange(reg_left[reg&3], 0, saturn.p+1, reg_right[reg&3]);
+ break; // abex wp
+ }
+ break;
+ case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_clear(A+reg, adr_b_begin[adr], adr_b_count[adr]);
+ break; // a=0 xs
+ case 4: case 5: case 6: case 7:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_copy(reg_right[reg&7], adr_b_begin[adr], adr_b_count[adr],
+ reg_left[reg&7]); //correct
+ break; // a=b xs
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_exchange(reg_left[reg&3], adr_b_begin[adr], adr_b_count[adr],
+ reg_right[reg&3]);
+ break; // abex xs
+ }
+ break;
+ }
+}
+
+static void saturn_instruction_b(void)
+{
+ int adr, reg;
+
+ switch(adr=READ_OP()) {
+ case 0:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_sub(sub_left[reg], saturn.p, 1, S64_READ_P(sub_right[reg]));
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_increment(A+(reg&3), saturn.p, 1); break; // a=a+1 p
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_sub2(sub_left[reg], saturn.p, 1, S64_READ_P(sub_right[reg]));
+ break;
+ }
+ break;
+ case 1:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_sub(sub_left[reg], 1, saturn.p+1, sub_right[reg]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_increment(A+(reg&3), 1, saturn.p+1); break; // a=a+1 wp
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_sub2(sub_left[reg], 1, saturn.p+1, sub_right[reg]);
+ break;
+ }
+ break;
+ case 2: case 3: case 4: case 5: case 6: case 7:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_sub(sub_left[reg], adr_a_begin[adr], adr_a_count[adr],
+ sub_right[reg]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_increment(A+(reg&3), adr_a_begin[adr], adr_a_count[adr]);
+ break; // a=a+1 xs
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_sub2(sub_left[reg], adr_a_begin[adr], adr_a_count[adr],
+ sub_right[reg]);
+ break;
+ }
+ break;
+ case 8:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_shift_nibble_left(A+reg, saturn.p, 1); break; // asl p
+ case 4: case 5: case 6: case 7:
+ saturn_shift_nibble_right(A+(reg&3), saturn.p, 1); break; // asr p
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_invert(A+(reg&3), saturn.p, 1); break; // A=-A p
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_negate(A+(reg&3), saturn.p, 1); break; // A=-A-1 p
+ }
+ break;
+ case 9:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_shift_nibble_left(A+reg,0,saturn.p+1); break; // asl wp
+ case 4: case 5: case 6: case 7:
+ saturn_shift_nibble_right(A+(reg&3),0,saturn.p+1); break; // asr wp
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_invert(A+(reg&3),0,saturn.p+1); break; // A=-A wp
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_negate(A+(reg&3),0,saturn.p+1); break; // A=-A-1 wp
+ }
+ break;
+ case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_shift_nibble_left(A+reg,adr_b_begin[adr], adr_b_count[adr]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_shift_nibble_right(A+(reg&3), adr_b_begin[adr], adr_b_count[adr]);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_invert(A+(reg&3), adr_b_begin[adr], adr_b_count[adr]);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_negate(A+(reg&3), adr_b_begin[adr], adr_b_count[adr]);
+ break;
+ }
+ break;
+ }
+}
+
+
+static void saturn_instruction(void)
+{
+ int reg, adr;
+
+ switch(READ_OP()) {
+ case 0:
+ switch(READ_OP()) {
+ case 0: saturn_return_xm_set();break;
+ case 1: saturn_return(1);break;
+ case 2: saturn_return_carry_set();break;
+ case 3: saturn_return_carry_clear();break;
+ case 4: saturn_sethex();break;
+ case 5: saturn_setdec();break;
+ case 6: saturn_push_c();break;
+ case 7: saturn_pop_c();break;
+ case 8: saturn_clear_st();break;
+ case 9: saturn_st_to_c();break;
+ case 0xa: saturn_c_to_st();break;
+ case 0xb: saturn_exchange_c_st();break;
+ case 0xc:
+ saturn_inc_p();
+ break;
+ case 0xd:
+ saturn_dec_p();
+ break;
+ case 0xf: saturn_return_interrupt();break;
+ case 0xe:
+ saturn_instruction_0e();
+ break;
+ }
+ break;
+ case 1:
+ saturn_instruction_1();
+ break;
+ case 2:
+ saturn_load_p();
+ break;
+ case 3: saturn_load_reg(C);break; // lc
+ case 4:
+ adr=READ_OP_DIS8();
+ if (adr==0) {
+ saturn_return(saturn.carry);
+ } else {
+ saturn_jump((saturn.pc+adr-2)&0xfffff, saturn.carry);
+ }
+ break;
+ case 5:
+ adr=READ_OP_DIS8();
+ if (adr==0) {
+ saturn_return(!saturn.carry);
+ } else {
+ saturn_jump((saturn.pc+adr-2)&0xfffff,!saturn.carry);
+ }
+ break;
+ case 6:
+ adr=READ_OP_DIS12();
+ saturn_jump((saturn.pc+adr-3)&0xfffff,1); break;
+ case 7:
+ adr=READ_OP_DIS12();
+ saturn_call((adr+saturn.pc)&0xfffff); break;
+ case 8:
+ saturn_instruction_8();
+ break;
+ case 9:
+ saturn_instruction_9();
+ break;
+ case 0xa:
+ saturn_instruction_a();
+ break;
+ case 0xb:
+ saturn_instruction_b();
+ break;
+ case 0xc:
+ switch (reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_add(add_left[reg], BEGIN_A, COUNT_A, add_right[reg]);
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_shift_left(A+(reg&3), BEGIN_A, COUNT_A);
+ break;
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_decrement(A+(reg&3), BEGIN_A, COUNT_A);
+ break;
+ }
+ break;
+ case 0xd:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_clear(A+reg, BEGIN_A, COUNT_A);
+ break; // a=0 a
+ case 4: case 5: case 6: case 7:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_copy(reg_right[reg&7], BEGIN_A, COUNT_A, reg_left[reg&7]); //correct
+ break; // a=b a
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_exchange(reg_left[reg&3], BEGIN_A, COUNT_A, reg_right[reg&3]);
+ break; // abex a
+ }
+ break;
+ case 0xe:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_sub(sub_left[reg], BEGIN_A, COUNT_A, S64_READ_A(sub_right[reg]));
+ break;
+ case 4: case 5: case 6: case 7:
+ saturn_increment(A+(reg&3), BEGIN_A, COUNT_A);
+ break; // a=a+1 a
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_sub2(sub_left[reg], BEGIN_A, COUNT_A, S64_READ_A(sub_right[reg]));
+ break;
+ }
+ break;
+ case 0xf:
+ switch(reg=READ_OP()) {
+ case 0: case 1: case 2: case 3:
+ saturn_shift_nibble_left(A+reg,BEGIN_A, COUNT_A);
+ break; // asl a
+ case 4: case 5: case 6: case 7:
+ saturn_shift_nibble_right(A+(reg&3),BEGIN_A, COUNT_A);
+ break; // asr a
+ case 8: case 9: case 0xa: case 0xb:
+ saturn_invert(A+(reg&3),BEGIN_A, COUNT_A);
+ break; // A=-A a
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ saturn_negate(A+(reg&3),BEGIN_A, COUNT_A);
+ break; // A=-A-1 a
+ }
+ break;
+ }
+}
diff --git a/src/emu/cpu/saturn/saturn.c b/src/emu/cpu/saturn/saturn.c
new file mode 100644
index 00000000000..e18ec06dc9b
--- /dev/null
+++ b/src/emu/cpu/saturn/saturn.c
@@ -0,0 +1,422 @@
+/*****************************************************************************
+ *
+ * saturn.c
+ * portable saturn emulator interface
+ * (hp calculators)
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+#include "cpuintrf.h"
+#include "debugger.h"
+
+#include "saturn.h"
+#include "sat.h"
+
+#define R0 0
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define A 5
+#define B 6
+#define C 7
+#define D 8
+
+typedef int SaturnAdr; // 20 bit
+typedef UINT8 SaturnNib; // 4 bit
+typedef short SaturnX; // 12 bit
+typedef INT64 SaturnM; // 48 bit
+
+typedef union {
+ UINT8 b[8];
+ UINT16 w[4];
+ UINT32 d[2];
+ UINT64 q;
+} Saturn64;
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+/****************************************************************************
+ * The 6502 registers.
+ ****************************************************************************/
+typedef struct
+{
+ SATURN_CONFIG *config;
+ Saturn64 reg[9]; //r0,r1,r2,r3,r4,a,b,c,d;
+
+ SaturnAdr d[2], pc, oldpc, rstk[8]; // 20 bit addresses
+
+ int stackpointer; // this is only for debugger stepover support!
+
+ SaturnNib p; // 4 bit pointer
+
+ UINT16 in;
+ int out; // 12
+ int carry, decimal;
+ UINT16 st; // status 16 bit
+#define XM 1
+#define SR 2
+#define SB 4
+#define MP 8
+ int hst; // hardware status 4 bit
+ /* XM external Modules missing
+ SR Service Request
+ SB Sticky bit
+ MP Module Pulled */
+
+ int irq_state;
+
+ UINT8 pending_irq; /* nonzero if an IRQ is pending */
+ UINT8 after_cli; /* pending IRQ and last insn cleared I */
+ UINT8 nmi_state;
+ int (*irq_callback)(int irqline); /* IRQ callback */
+} Saturn_Regs;
+
+static int saturn_ICount = 0;
+
+static Saturn_Regs saturn;
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+#include "satops.c"
+#include "sattable.c"
+
+/*****************************************************************************
+ *
+ * Saturn CPU interface functions
+ *
+ *****************************************************************************/
+
+static void saturn_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ saturn.config = (SATURN_CONFIG *) config;
+}
+
+static void saturn_reset(void)
+{
+ saturn.stackpointer=0;
+ saturn.pc=0;
+ change_pc(saturn.pc);
+}
+
+static void saturn_get_context (void *dst)
+{
+ if( dst )
+ *(Saturn_Regs*)dst = saturn;
+}
+
+static void saturn_set_context (void *src)
+{
+ if( src )
+ {
+ saturn = *(Saturn_Regs*)src;
+ change_pc(saturn.pc);
+ }
+}
+
+
+
+INLINE void saturn_take_irq(void)
+{
+ {
+ saturn_ICount -= 7;
+
+ saturn_push(saturn.pc);
+ saturn.pc=IRQ_ADDRESS;
+
+ LOG(("Saturn#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), saturn.pc));
+ /* call back the cpuintrf to let it clear the line */
+ if (saturn.irq_callback) (*saturn.irq_callback)(0);
+ change_pc(saturn.pc);
+ }
+ saturn.pending_irq = 0;
+}
+
+int saturn_execute(int cycles)
+{
+ saturn_ICount = cycles;
+
+ change_pc(saturn.pc);
+
+ do
+ {
+ saturn.oldpc = saturn.pc;
+
+ CALL_MAME_DEBUG;
+
+ /* if an irq is pending, take it now */
+ if( saturn.pending_irq )
+ saturn_take_irq();
+
+ saturn_instruction();
+
+ /* check if the I flag was just reset (interrupts enabled) */
+ if( saturn.after_cli )
+ {
+ LOG(("M6502#%d after_cli was >0", cpu_getactivecpu()));
+ saturn.after_cli = 0;
+ if (saturn.irq_state != CLEAR_LINE)
+ {
+ LOG((": irq line is asserted: set pending IRQ\n"));
+ saturn.pending_irq = 1;
+ }
+ else
+ {
+ LOG((": irq line is clear\n"));
+ }
+ }
+ else
+ if( saturn.pending_irq )
+ saturn_take_irq();
+
+ } while (saturn_ICount > 0);
+
+ return cycles - saturn_ICount;
+}
+
+void saturn_set_nmi_line(int state)
+{
+ if (saturn.nmi_state == state) return;
+ saturn.nmi_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(( "M6502#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
+ saturn_ICount -= 7;
+ saturn_push(saturn.pc);
+ saturn.pc=IRQ_ADDRESS;
+
+ LOG(("M6502#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PC));
+ change_pc(saturn.pc);
+ }
+}
+
+void saturn_set_irq_line(int irqline, int state)
+{
+ saturn.irq_state = state;
+ if( state != CLEAR_LINE )
+ {
+ LOG(( "M6502#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
+ saturn.pending_irq = 1;
+ }
+}
+
+void saturn_set_irq_callback(int (*callback)(int))
+{
+ saturn.irq_callback = callback;
+}
+
+#if 0
+static void saturn_state_save(void *file)
+{
+ int cpu = cpu_getactivecpu();
+ state_save_UINT16(file,"m6502",cpu,"PC",&m6502.pc.w.l,2);
+ state_save_UINT16(file,"m6502",cpu,"SP",&m6502.sp.w.l,2);
+ state_save_UINT8(file,"m6502",cpu,"P",&m6502.p,1);
+ state_save_UINT8(file,"m6502",cpu,"A",&m6502.a,1);
+ state_save_UINT8(file,"m6502",cpu,"X",&m6502.x,1);
+ state_save_UINT8(file,"m6502",cpu,"Y",&m6502.y,1);
+ state_save_UINT8(file,"m6502",cpu,"PENDING",&m6502.pending_irq,1);
+ state_save_UINT8(file,"m6502",cpu,"AFTER_CLI",&m6502.after_cli,1);
+ state_save_UINT8(file,"m6502",cpu,"NMI_STATE",&m6502.nmi_state,1);
+ state_save_UINT8(file,"m6502",cpu,"IRQ_STATE",&m6502.irq_state,1);
+ state_save_UINT8(file,"m6502",cpu,"SO_STATE",&m6502.so_state,1);
+}
+
+static void saturn_state_load(void *file)
+{
+ int cpu = cpu_getactivecpu();
+ state_load_UINT16(file,"m6502",cpu,"PC",&m6502.pc.w.l,2);
+ state_load_UINT16(file,"m6502",cpu,"SP",&m6502.sp.w.l,2);
+ state_load_UINT8(file,"m6502",cpu,"P",&m6502.p,1);
+ state_load_UINT8(file,"m6502",cpu,"A",&m6502.a,1);
+ state_load_UINT8(file,"m6502",cpu,"X",&m6502.x,1);
+ state_load_UINT8(file,"m6502",cpu,"Y",&m6502.y,1);
+ state_load_UINT8(file,"m6502",cpu,"PENDING",&m6502.pending_irq,1);
+ state_load_UINT8(file,"m6502",cpu,"AFTER_CLI",&m6502.after_cli,1);
+ state_load_UINT8(file,"m6502",cpu,"NMI_STATE",&m6502.nmi_state,1);
+ state_load_UINT8(file,"m6502",cpu,"IRQ_STATE",&m6502.irq_state,1);
+ state_load_UINT8(file,"m6502",cpu,"SO_STATE",&m6502.so_state,1);
+}
+#endif
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void saturn_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + SATURN_NMI_STATE: saturn.nmi_state = info->i; break;
+ case CPUINFO_INT_INPUT_STATE + SATURN_IRQ_STATE: saturn.irq_state = info->i; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SATURN_PC: saturn.pc = info->i; change_pc(saturn.pc); break;
+ case CPUINFO_INT_SP: saturn.stackpointer = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_D0: saturn.d[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_D1: saturn.d[1] = info->i; break;
+#if 0
+ case CPUINFO_INT_REGISTER + SATURN_A: saturn.reg[A] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_B: saturn.reg[B] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_C: saturn.reg[C] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_D: saturn.reg[D] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_R0: saturn.reg[R0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_R1: saturn.reg[R1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_R2: saturn.reg[R2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_R3: saturn.reg[R3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_R4: saturn.reg[R4] = info->i; break;
+#endif
+ case CPUINFO_INT_REGISTER + SATURN_P: saturn.p = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_IN: saturn.in = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_OUT: saturn.out = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_CARRY: saturn.carry = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_ST: saturn.st = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_HST: saturn.hst = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK0: saturn.rstk[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK1: saturn.rstk[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK2: saturn.rstk[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK3: saturn.rstk[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK4: saturn.rstk[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK5: saturn.rstk[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK6: saturn.rstk[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK7: saturn.rstk[7] = info->i; break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void saturn_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(saturn); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 20; /* 20 nibbles max */ break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 21; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 20; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + SATURN_NMI_STATE: info->i = saturn.nmi_state; break;
+ case CPUINFO_INT_INPUT_STATE + SATURN_IRQ_STATE: info->i = saturn.irq_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = saturn.oldpc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SATURN_PC: info->i = saturn.pc; break;
+ case CPUINFO_INT_SP: info->i = saturn.stackpointer; break;
+ case CPUINFO_INT_REGISTER + SATURN_D0: info->i = saturn.d[0]; break;
+ case CPUINFO_INT_REGISTER + SATURN_D1: info->i = saturn.d[1]; break;
+#if 0
+ case CPUINFO_INT_REGISTER + SATURN_A: info->i = saturn.reg[A]; break;
+ case CPUINFO_INT_REGISTER + SATURN_B: info->i = saturn.reg[B]; break;
+ case CPUINFO_INT_REGISTER + SATURN_C: info->i = saturn.reg[C]; break;
+ case CPUINFO_INT_REGISTER + SATURN_D: info->i = saturn.reg[D]; break;
+ case CPUINFO_INT_REGISTER + SATURN_R0: info->i = saturn.reg[R0]; break;
+ case CPUINFO_INT_REGISTER + SATURN_R1: info->i = saturn.reg[R1]; break;
+ case CPUINFO_INT_REGISTER + SATURN_R2: info->i = saturn.reg[R2]; break;
+ case CPUINFO_INT_REGISTER + SATURN_R3: info->i = saturn.reg[R3]; break;
+ case CPUINFO_INT_REGISTER + SATURN_R4: info->i = saturn.reg[R4]; break;
+#endif
+ case CPUINFO_INT_REGISTER + SATURN_P: info->i = saturn.p; break;
+ case CPUINFO_INT_REGISTER + SATURN_IN: info->i = saturn.in; break;
+ case CPUINFO_INT_REGISTER + SATURN_OUT: info->i = saturn.out; break;
+ case CPUINFO_INT_REGISTER + SATURN_CARRY: info->i = saturn.carry; break;
+ case CPUINFO_INT_REGISTER + SATURN_ST: info->i = saturn.st; break;
+ case CPUINFO_INT_REGISTER + SATURN_HST: info->i = saturn.hst; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK0: info->i = saturn.rstk[0]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK1: info->i = saturn.rstk[1]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK2: info->i = saturn.rstk[2]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK3: info->i = saturn.rstk[3]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK4: info->i = saturn.rstk[4]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK5: info->i = saturn.rstk[5]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK6: info->i = saturn.rstk[6]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK7: info->i = saturn.rstk[7]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = saturn_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = saturn_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = saturn_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = saturn_init; break;
+ case CPUINFO_PTR_RESET: info->reset = saturn_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = saturn_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = saturn_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &saturn_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "Saturn"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "Saturn"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0alpha"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "Copyright (c) 2000 Peter Trauner, all rights reserved."); break;
+
+ case CPUINFO_STR_REGISTER + SATURN_PC: sprintf(info->s = cpuintrf_temp_str(), "PC: %.5x", saturn.pc);break;
+ case CPUINFO_STR_REGISTER + SATURN_D0: sprintf(info->s = cpuintrf_temp_str(), "D0: %.5x", saturn.d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_D1: sprintf(info->s = cpuintrf_temp_str(), "D1: %.5x", saturn.d[1]);break;
+ case CPUINFO_STR_REGISTER + SATURN_A: sprintf(info->s = cpuintrf_temp_str(), "A: %.8x %.8x", saturn.reg[A].d[1], saturn.reg[A].d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_B: sprintf(info->s = cpuintrf_temp_str(), "B: %.8x %.8x", saturn.reg[B].d[1], saturn.reg[B].d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_C: sprintf(info->s = cpuintrf_temp_str(), "C: %.8x %.8x", saturn.reg[C].d[1], saturn.reg[C].d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_D: sprintf(info->s = cpuintrf_temp_str(), "D: %.8x %.8x", saturn.reg[D].d[1], saturn.reg[D].d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_R0: sprintf(info->s = cpuintrf_temp_str(), "R0:%.8x %.8x", saturn.reg[R0].d[1], saturn.reg[R0].d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_R1: sprintf(info->s = cpuintrf_temp_str(), "R1:%.8x %.8x", saturn.reg[R1].d[1], saturn.reg[R1].d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_R2: sprintf(info->s = cpuintrf_temp_str(), "R2:%.8x %.8x", saturn.reg[R2].d[1], saturn.reg[R2].d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_R3: sprintf(info->s = cpuintrf_temp_str(), "R3:%.8x %.8x", saturn.reg[R3].d[1], saturn.reg[R3].d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_R4: sprintf(info->s = cpuintrf_temp_str(), "R4:%.8x %.8x", saturn.reg[R4].d[1], saturn.reg[R4].d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_P: sprintf(info->s = cpuintrf_temp_str(), "P:%x", saturn.p);break;
+ case CPUINFO_STR_REGISTER + SATURN_IN: sprintf(info->s = cpuintrf_temp_str(), "IN:%.4x", saturn.in);break;
+ case CPUINFO_STR_REGISTER + SATURN_OUT: sprintf(info->s = cpuintrf_temp_str(), "OUT:%.3x", saturn.out);break;
+ case CPUINFO_STR_REGISTER + SATURN_CARRY: sprintf(info->s = cpuintrf_temp_str(), "Carry: %d", saturn.carry);break;
+ case CPUINFO_STR_REGISTER + SATURN_ST: sprintf(info->s = cpuintrf_temp_str(), "ST:%.4x", saturn.st);break;
+ case CPUINFO_STR_REGISTER + SATURN_HST: sprintf(info->s = cpuintrf_temp_str(), "HST:%x", saturn.hst);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK0: sprintf(info->s = cpuintrf_temp_str(), "RSTK0:%.5x", saturn.rstk[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK1: sprintf(info->s = cpuintrf_temp_str(), "RSTK1:%.5x", saturn.rstk[1]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK2: sprintf(info->s = cpuintrf_temp_str(), "RSTK2:%.5x", saturn.rstk[2]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK3: sprintf(info->s = cpuintrf_temp_str(), "RSTK3:%.5x", saturn.rstk[3]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK4: sprintf(info->s = cpuintrf_temp_str(), "RSTK4:%.5x", saturn.rstk[4]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK5: sprintf(info->s = cpuintrf_temp_str(), "RSTK5:%.5x", saturn.rstk[5]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK6: sprintf(info->s = cpuintrf_temp_str(), "RSTK6:%.5x", saturn.rstk[6]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK7: sprintf(info->s = cpuintrf_temp_str(), "RSTK7:%.5x", saturn.rstk[7]);break;
+ case CPUINFO_STR_REGISTER + SATURN_IRQ_STATE: sprintf(info->s = cpuintrf_temp_str(), "IRQ:%.4x", saturn.pending_irq);break;
+ case CPUINFO_STR_FLAGS: sprintf(info->s = cpuintrf_temp_str(), "%c%c", saturn.decimal?'D':'.', saturn.carry ? 'C':'.'); break;
+ }
+}
diff --git a/src/emu/cpu/saturn/saturn.h b/src/emu/cpu/saturn/saturn.h
new file mode 100644
index 00000000000..85e66a68536
--- /dev/null
+++ b/src/emu/cpu/saturn/saturn.h
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ *
+ * saturn.h
+ * portable saturn emulator interface
+ * (hp calculators)
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+/*
+Calculator Release Date Chip Version Analog/Digital IC
+HP71B (early) 02/01/84 1LF2 -
+HP71B (later) ??/??/?? 1LK7 -
+HP18C 06/01/86 1LK7 -
+HP28C 01/05/87 1LK7 -
+HP17B 01/04/88 1LT8 Lewis
+HP19B 01/04/88 1LT8 Lewis
+HP27S 01/04/88 1LT8 Lewis
+HP28S 01/04/88 1LT8 Lewis
+HP48SX 03/16/91 1LT8 Clarke
+HP48S 04/02/91 1LT8 Clarke
+HP48GX 06/01/93 1LT8 Yorke
+HP48G 06/01/93 1LT8 Yorke
+HP38G 09/??/95 1LT8 Yorke
+*/
+/* 4 bit processor
+ 20 address lines */
+
+#ifndef _SATURN_H
+#define _SATURN_H
+
+#include "cpuintrf.h"
+
+#define SATURN_INT_NONE 0
+#define SATURN_INT_IRQ 1
+#define SATURN_INT_NMI 2
+
+typedef struct
+{
+ void (*out)(int);
+ int (*in)(void);
+ void (*reset)(void);
+ void (*config)(int v);
+ void (*unconfig)(int v);
+ int (*id)(void);
+ void (*crc)(int addr, int data);
+} SATURN_CONFIG;
+
+#ifdef MAME_DEBUG
+unsigned saturn_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+void saturn_get_info(UINT32 state, cpuinfo *info);
+
+#endif
+
diff --git a/src/emu/cpu/saturn/saturnds.c b/src/emu/cpu/saturn/saturnds.c
new file mode 100644
index 00000000000..cf6005ffa62
--- /dev/null
+++ b/src/emu/cpu/saturn/saturnds.c
@@ -0,0 +1,1454 @@
+/*****************************************************************************
+ *
+ * saturn.c
+ * portable saturn emulator interface
+ * (hp calculators)
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+
+#include "saturn.h"
+#include "sat.h"
+
+#if defined SATURN_HP_MNEMONICS
+// class/hp mnemonics
+static int set=0;
+#else
+// readable/normal mnemonics
+static int set=1;
+#endif
+
+#define P "P"
+#define WP "WP"
+#define XS "XS"
+#define X "X"
+#define S "S"
+#define M "M"
+#define B "B"
+#define W "W"
+#define A "A"
+
+static const char *adr_b[]=
+{ P, WP, XS, X, S, M, B, W };
+
+static const char *adr_af[]=
+{ P, WP, XS, X, S, M, B, W, 0, 0, 0, 0, 0, 0, 0, A };
+
+static const char *adr_a[]=
+{ P, WP, XS, X, S, M, B, W };
+
+static const char number_2_hex[]=
+{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+#define SATURN_PEEKOP_DIS8(v) v = (INT8)( oprom[pos] | ( oprom[pos+1] << 4 ) ); pos+= 2;
+
+#define SATURN_PEEKOP_DIS12(v) v = oprom[pos] | ( oprom[pos+1] << 4 ) | ( oprom[pos+2] << 8 ); \
+ pos += 3; \
+ if ( v & 0x0800 ) v = -0x1000 + v;
+
+#define SATURN_PEEKOP_DIS16(v) v = (INT16)( oprom[pos] | ( oprom[pos+1] << 4 ) | ( oprom[pos+2] << 8 ) | ( oprom[pos+3] << 12 ) ); pos += 4;
+
+#define SATURN_PEEKOP_ADR(v) v = oprom[pos] | ( oprom[pos+1] << 4 ) | ( oprom[pos+2] << 8 ) | ( oprom[pos+3] << 12 ) | ( oprom[pos+4] << 16 ); pos += 5;
+
+
+// don't split branch and return, source relies on this ordering
+typedef enum {
+ Return, ReturnSetXM, ReturnSetCarry, ReturnClearCarry, ReturnFromInterrupt,
+ jump3,jump4,jump,
+ call3,call4,call,
+ branchCarrySet, returnCarrySet,
+ branchCarryClear, returnCarryClear,
+
+ outCS, outC, inA, inC,
+ unconfig, config, Cid, shutdown, cp1, reset, buscc,
+ CcopyP, PcopyC, sreq, CswapP,
+
+ inton, AloadImm, buscb,
+ clearAbit, setAbit, Abitclear, Abitset,
+ clearCbit, setCbit, Cbitclear, Cbitset,
+ PCloadA, buscd, PCloadC, intoff, rsi,
+
+ jumpA, jumpC, PCcopyA, PCcopyC, AcopyPC, CcopyPC,
+
+ clearHST,
+ branchHSTclear, returnHSTclear,
+
+ clearBitST, setBitST,
+ branchSTclear, returnSTclear,
+ branchSTset, returnSTset,
+
+
+ branchPdiffers, returnPdiffers,
+ branchPequals, returnPequals,
+
+ branchAequalsB, returnAequalsB,
+ branchBequalsC, returnBequalsC,
+ branchAequalsC, returnAequalsC,
+ branchCequalsD, returnCequalsD,
+ branchAdiffersB, returnAdiffersB,
+ branchBdiffersC, returnBdiffersC,
+ branchAdiffersC, returnAdiffersC,
+ branchCdiffersD, returnCdiffersD,
+ branchAzero, returnAzero,
+ branchBzero, returnBzero,
+ branchCzero, returnCzero,
+ branchDzero, returnDzero,
+ branchAnotzero, returnAnotzero,
+ branchBnotzero, returnBnotzero,
+ branchCnotzero, returnCnotzero,
+ branchDnotzero, returnDnotzero,
+
+ branchAgreaterB, returnAgreaterB,
+ branchBgreaterC, returnBgreaterC,
+ branchCgreaterA, returnCgreaterA,
+ branchDgreaterC, returnDgreaterC,
+ branchAlowerB, returnAlowerB,
+ branchBlowerC, returnBlowerC,
+ branchClowerA, returnClowerA,
+ branchDlowerC, returnDlowerC,
+ branchAnotlowerB, returnAnotlowerB,
+ branchBnotlowerC, returnBnotlowerC,
+ branchCnotlowerA, returnCnotlowerA,
+ branchDnotlowerC, returnDnotlowerC,
+ branchAnotgreaterB, returnAnotgreaterB,
+ branchBnotgreaterC, returnBnotgreaterC,
+ branchCnotgreaterA, returnCnotgreaterA,
+ branchDnotgreaterC, returnDnotgreaterC,
+
+ SetHexMode, SetDecMode,
+ PopC, PushC,
+
+ D0loadImm2, D0loadImm4, D0loadImm5,
+ D1loadImm2, D1loadImm4, D1loadImm5,
+ PloadImm, CloadImm,
+
+ clearST,
+ CcopyST, STcopyC,
+ swapCST,
+
+ incP, decP,
+
+ R0copyA, R1copyA, R2copyA, R3copyA, R4copyA,
+ R0copyC, R1copyC, R2copyC, R3copyC, R4copyC,
+
+ AcopyR0, AcopyR1, AcopyR2, AcopyR3, AcopyR4,
+ CcopyR0, CcopyR1, CcopyR2, CcopyR3, CcopyR4,
+
+ D0copyA, D1copyA, D0copyC, D1copyC,
+ D0copyAShort, D1copyAShort, D0copyCShort, D1copyCShort, // other class mnemonic
+
+ SwapAR0, SwapAR1, SwapAR2, SwapAR3, SwapAR4,
+ SwapCR0, SwapCR1, SwapCR2, SwapCR3, SwapCR4,
+
+ SwapAD0, SwapAD1, SwapCD0, SwapCD1,
+ SwapAD0Short, SwapAD1Short, SwapCD0Short, SwapCD1Short, // other class mnemonic
+
+ D0storeA, D1storeA, D0storeC, D1storeC,
+ AloadD0, AloadD1, CloadD0, CloadD1,
+
+ D0addImm, D1addImm, D0subImm, D1subImm,
+ AaddImm, BaddImm, CaddImm, DaddImm,
+ AsubImm, BsubImm, CsubImm, DsubImm,
+
+ AandB, BandC, CandA, DandC, BandA, CandB, AandC, CandD,
+ AorB, BorC, CorA, DorC, BorA, CorB, AorC, CorD,
+
+ Ashiftrightbit, Bshiftrightbit, Cshiftrightbit, Dshiftrightbit,
+
+ AshiftleftCarry, BshiftleftCarry, CshiftleftCarry, DshiftleftCarry,
+ AshiftrightCarry, BshiftrightCarry, CshiftrightCarry, DshiftrightCarry,
+
+ AaddB, BaddC, CaddA, DaddC, AaddA, BaddB, CaddC, DaddD,
+ BaddA, CaddB, AaddC, CaddD, decA, decB, decC, decD,
+
+ AsubB, BsubC, CsubA, DsubC, incA, incB, incC, incD,
+ BsubA, CsubB, AsubC, CsubD, AsubnB, BsubnC, CsubnA, DsubnC,
+
+ clearA, clearB, clearC, clearD,
+ AcopyB, BcopyC, CcopyA, DcopyC, BcopyA, CcopyB, AcopyC, CcopyD,
+ AswapB, BswapC, CswapA, DswapC,
+
+ Ashiftleft, Bshiftleft, Cshiftleft, Dshiftleft,
+ Ashiftright, Bshiftright, Cshiftright, Dshiftright,
+ negateA, negateB, negateC, negateD,
+ notA, notB, notC, notD
+
+} MNEMONICS;
+
+static struct {
+ const char *name[2];
+} mnemonics[]={
+ { { "rtn", "RET" } },
+ { { "rtnsXM", "RETSETXM" } },
+ { { "rtnsC", "RETSETC" } },
+ { { "rtncC", "RETCLRC" } },
+ { { "rti", "RETI" } },
+ { { "goto %05x", "JUMP.3 %05x" } },
+ { { "goto %05x", "JUMP.4 %05x" } },
+ { { "goto %05x", "JUMP %05x" } },
+ { { "gosub %05x", "CALL.3 %05x" } },
+ { { "gosub %05x", "CALL.4 %05x" } },
+ { { "gosub %05x", "CALL %05x" } },
+ { { "goC %05x", "BRCS %05x" } },
+ { { "rtnC", "RETCS" } },
+ { { "gonC %05x", "BRCC %05x" } },
+ { { "rtnnC", "RETCC" } },
+
+ { { "OUT=CS", "OUT.S C" } },
+ { { "OUT=C", "OUT.X C" } },
+ { { "A=IN", "IN.4 A" } },
+ { { "C=IN", "IN.4 C" } },
+ { { "uncnfg", "UNCNFG" } },
+ { { "config", "CONFIG" } },
+ { { "C=id", "MOVE.A ID,C" } },
+ { { "!shutdn", "!SHUTDN" } },
+ { { "C+P+1", "ADD.A P+1,C" } },
+ { { "reset", "RESET" } },
+ { { "!buscc", "!BUSCC" } },
+ { { "C=P %x", "MOVE.1 P,C,%x" } },
+ { { "P=C %x", "MOVE.1 C,%x,P" } },
+ { { "!sreq?", "!SREQ" } },
+ { { "CPex %x", "SWAP.1 P,C,%x" } },
+
+ { { "!inton", "!INTON" } },
+ { { "LA %-2x %s", "MOVE.P%-2x %s,A" } },
+ { { "!buscb", "!BUSCB" } },
+ { { "Abit=0 %x", "CLRB %x,A" } },
+ { { "Abit=1 %x", "SETB %x,A" } },
+ { { "?Abit=0 %x,%05x", "BRBC %x,A,%05x" } },
+ { { "?Abit=1 %x,%05x", "BRBS %x,A,%05x" } },
+ { { "Cbit=0 %x", "CLRB %x,C" } },
+ { { "Cbit=1 %x", "SETB %x,C" } },
+ { { "?Cbit=0 %x,%05x", "BRBC %x,C,%05x" } },
+ { { "?Cbit=1 %x,%05x", "BRBS %x,C,%05x" } },
+ { { "PC=(A)", "JUMP.A @A" } },
+ { { "!buscd", "!BUSCD" } },
+ { { "PC=(C)", "JUMP.A @C" } },
+ { { "!intoff", "!INTOFF" } },
+ { { "!rsi", "!RSI" } },
+
+ { { "PC=A", "JUMP.A A" } },
+ { { "PC=C", "JUMP.A C" } },
+ { { "A=PC", "MOVE.A PC,A" } },
+ { { "C=PC", "MOVE.A PC,C" } },
+ { { "APCex", "SWAP.A A,PC" } },
+ { { "CPCex", "SWAP.A C,PC" } },
+
+ { { "HST=0 %x", "CLRHST %x" } },
+ { { "?HST=0 %x,%05x", "BRBCHST %x,%05x" } },
+ { { "?HST=0 %x", "RETBCHST %x" } },
+ { { "ST=0 %x", "CLRB %x,ST" } },
+ { { "ST=1 %x", "SETB %x,ST" } },
+ { { "?ST=0 %x,%05x", "BRBC ST,%x,%05x" } },
+ { { "?ST=0 %x", "RETBC ST,%x" } },
+ { { "?ST=1 %x,%05x", "BRBS ST,%x,%05x" } },
+ { { "?ST=1 %x", "RETBS ST,%x" } },
+ { { "?P# %x,%05x", "BRNE P,%x,%05x" } },
+ { { "?P# %x", "RETNE P,%x" } },
+ { { "?P= %x,%05x", "BREQ P,%x,%05x" } },
+ { { "?P= %x", "RETEQ P,%x" } },
+
+ { { "?A=B %x,%05x", "BREQ.%-2s A,B,%05x" } },
+ { { "?A=B %x", "RETEQ.%-2s A,B" } },
+ { { "?B=C %x,%05x", "BREQ.%-2s B,C,%05x" } },
+ { { "?B=C %x", "RETEQ.%-2s B,C" } },
+ { { "?A=C %x,%05x", "BREQ.%-2s A,C,%05x" } },
+ { { "?A=C %x", "RETEQ.%-2s A,C" } },
+ { { "?C=D %x,%05x", "BREQ.%-2s C,D,%05x" } },
+ { { "?C=D %x", "RETEQ.%-2s C,D" } },
+ { { "?A#B %x,%05x", "BRNE.%-2s A,B,%05x" } },
+ { { "?A#B %x", "RETNE.%-2s A,B" } },
+ { { "?B#C %x,%05x", "BRNE.%-2s B,C,%05x" } },
+ { { "?B#C %x", "RETNE.%-2s B,C" } },
+ { { "?A#C %x,%05x", "BRNE.%-2s A,C,%05x" } },
+ { { "?A#C %x", "RETNE.%-2s A,C" } },
+ { { "?C#D %x,%05x", "BRNE.%-2s C,D,%05x" } },
+ { { "?C#D %x", "RETNE.%-2s C,D" } },
+ { { "?A=0 %x,%05x", "BRZ.%-2s A,%05x" } },
+ { { "?A=0 %x", "RETZ.%-2s A" } },
+ { { "?B=0 %x,%05x", "BRZ.%-2s B,%05x" } },
+ { { "?B=0 %x", "RETZ.%-2s B" } },
+ { { "?C=0 %x,%05x", "BRZ.%-2s C,%05x" } },
+ { { "?C=0 %x", "RETZ.%-2s C" } },
+ { { "?D=0 %x,%05x", "BRZ.%-2s D,%05x" } },
+ { { "?D=0 %x", "RETZ.%-2s D" } },
+ { { "?A#0 %x,%05x", "BRNZ.%-2s A,%05x" } },
+ { { "?A#0 %x", "RETNZ.%-2s A" } },
+ { { "?B#0 %x,%05x", "BRNZ.%-2s B,%05x" } },
+ { { "?B#0 %x", "RETNZ.%-2s B" } },
+ { { "?C#0 %x,%05x", "BRNZ.%-2s C,%05x" } },
+ { { "?C#0 %x", "RETNZ.%-2s C" } },
+ { { "?D#0 %x,%05x", "BRNZ.%-2s D,%05x" } },
+ { { "?D#0 %x", "RETNZ.%-2s D" } },
+
+ { { "?A>B %x,%05x", "BRGT.%-2s A,B,%05x" } },
+ { { "?A>B %x", "RETGT.%-2s A,B" } },
+ { { "?B>C %x,%05x", "BRGT.%-2s B,C,%05x" } },
+ { { "?B>C %x", "RETGT.%-2s B,C" } },
+ { { "?C>A %x,%05x", "BRGT.%-2s C,A,%05x" } },
+ { { "?C>A %x", "RETGT.%-2s C,A" } },
+ { { "?D>C %x,%05x", "BRGT.%-2s D,C,%05x" } },
+ { { "?D>C %x", "RETGT.%-2s D,C" } },
+ { { "?A<B %x,%05x", "BRLT.%-2s A,B,%05x" } },
+ { { "?A<B %x", "RETLT.%-2s A,B" } },
+ { { "?B<C %x,%05x", "BRLT.%-2s B,C,%05x" } },
+ { { "?B<C %x", "RETLT.%-2s B,C" } },
+ { { "?C<A %x,%05x", "BRLT.%-2s C,A,%05x" } },
+ { { "?C<A %x", "RETLT.%-2s C,A" } },
+ { { "?D<C %x,%05x", "BRLT.%-2s D,C,%05x" } },
+ { { "?D<C %x", "RETLT.%-2s D,C" } },
+ { { "?A>=B %x,%05x", "BRGE.%-2s A,B,%05x" } },
+ { { "?A>=B %x", "RETGE.%-2s A,B" } },
+ { { "?B>=C %x,%05x", "BRGE.%-2s B,C,%05x" } },
+ { { "?B>=C %x", "RETGE.%-2s B,C" } },
+ { { "?C>=A %x,%05x", "BRGE.%-2s C,A,%05x" } },
+ { { "?C>=A %x", "RETGE.%-2s C,A" } },
+ { { "?D>=C %x,%05x", "BRGE.%-2s D,C,%05x" } },
+ { { "?D>=C %x", "RETGE.%-2s D,C" } },
+ { { "?A<=B %x,%05x", "BRLE.%-2s A,B,%05x" } },
+ { { "?A<=B %x", "RETLE.%-2s A,B" } },
+ { { "?B<=C %x,%05x", "BRLE.%-2s B,C,%05x" } },
+ { { "?B<=C %x", "RETLE.%-2s B,C" } },
+ { { "?C<=A %x,%05x", "BRLE.%-2s C,A,%05x" } },
+ { { "?C<=A %x", "RETLE.%-2s C,A" } },
+ { { "?D<=C %x,%05x", "BRLE.%-2s D,C,%05x" } },
+ { { "?D<=C %x", "RETLE.%-2s D,C" } },
+
+ { { "sethex", "SETHEX" } },
+ { { "setdec", "SETDEC" } },
+ { { "RSTK=C", "PUSH.A C" } },
+ { { "C=RSTK", "POP.A C" } },
+
+ // load immediate
+ { { "D0= %02x", "MOVE.2 %02x,D0" } },
+ { { "D0= %04x", "MOVE.4 %04x,D0" } },
+ { { "D0= %05x", "MOVE.5 %05x,D0" } },
+
+ { { "D1= %02x", "MOVE.2 %02x,D1" } },
+ { { "D1= %04x", "MOVE.4 %04x,D1" } },
+ { { "D1= %05x", "MOVE.5 %05x,D1" } },
+
+ { { "P= %x", "MOVE %x,P" } },
+ { { "lC %-2x %s", "MOVE.P%-2x %s,C" } },
+
+ { { "clrST", "CLR.X ST" } },
+ { { "C=ST", "MOVE.X ST,C" } },
+ { { "ST=C", "MOVE.X C,ST" } },
+ { { "CSTex", "SWAP.X C,ST" } },
+
+ { { "P=P+1", "INC P" } },
+ { { "P=P-1", "DEC P" } },
+
+ // copy
+ { { "R0=A %s", "MOVE.%-2s A,R0" } },
+ { { "R1=A %s", "MOVE.%-2s A,R1" } },
+ { { "R2=A %s", "MOVE.%-2s A,R2" } },
+ { { "R3=A %s", "MOVE.%-2s A,R3" } },
+ { { "R4=A %s", "MOVE.%-2s A,R4" } },
+
+ { { "R0=C %s", "MOVE.%-2s C,R0" } },
+ { { "R1=C %s", "MOVE.%-2s C,R1" } },
+ { { "R2=C %s", "MOVE.%-2s C,R2" } },
+ { { "R3=C %s", "MOVE.%-2s C,R3" } },
+ { { "R4=C %s", "MOVE.%-2s C,R4" } },
+
+ { { "A=R0 %s", "MOVE.%-2s R0,A" } },
+ { { "A=R1 %s", "MOVE.%-2s R1,A" } },
+ { { "A=R2 %s", "MOVE.%-2s R2,A" } },
+ { { "A=R3 %s", "MOVE.%-2s R3,A" } },
+ { { "A=R4 %s", "MOVE.%-2s R4,A" } },
+
+ { { "C=R0 %s", "MOVE.%-2s R0,C" } },
+ { { "C=R1 %s", "MOVE.%-2s R1,C" } },
+ { { "C=R2 %s", "MOVE.%-2s R2,C" } },
+ { { "C=R3 %s", "MOVE.%-2s R3,C" } },
+ { { "C=R4 %s", "MOVE.%-2s R4,C" } },
+
+ { { "D0=A", "MOVE.A A,D0" } },
+ { { "D1=A", "MOVE.A A,D1" } },
+ { { "D0=C", "MOVE.A C,D0" } },
+ { { "D1=C", "MOVE.A C,D1" } },
+ { { "D0=As", "MOVE.S A,D0" } },
+ { { "D1=As", "MOVE.S A,D1" } },
+ { { "D0=Cs", "MOVE.S C,D0" } },
+ { { "D1=Cs", "MOVE.S C,D1" } },
+
+ // swap operations
+ { { "AR0ex %s", "SWAP.%-2s A,R0" } },
+ { { "AR1ex %s", "SWAP.%-2s A,R1" } },
+ { { "AR2ex %s", "SWAP.%-2s A,R2" } },
+ { { "AR3ex %s", "SWAP.%-2s A,R3" } },
+ { { "AR4ex %s", "SWAP.%-2s A,R4" } },
+
+ { { "CR0ex %s", "SWAP.%-2s C,R0" } },
+ { { "CR1ex %s", "SWAP.%-2s C,R1" } },
+ { { "CR2ex %s", "SWAP.%-2s C,R2" } },
+ { { "CR3ex %s", "SWAP.%-2s C,R3" } },
+ { { "CR4ex %s", "SWAP.%-2s C,R4" } },
+
+ { { "AD0ex", "SWAP.A A,D0" } },
+ { { "AD1ex", "SWAP.A A,D1" } },
+ { { "CD0ex", "SWAP.A C,D0" } },
+ { { "CD1ex", "SWAP.A C,D1" } },
+ { { "AD0xs", "SWAP.S A,D0" } },
+ { { "AD1xs", "SWAP.S A,D1" } },
+ { { "CD0xs", "SWAP.S C,D0" } },
+ { { "CD1xs", "SWAP.S C,D1" } },
+
+ // store
+ { { "Dat0=A %s", "MOVE.%-2s A,@D0" } },
+ { { "Dat1=A %s", "MOVE.%-2s A,@D0" } },
+ { { "Dat0=C %s", "MOVE.%-2s C,@D0" } },
+ { { "Dat1=C %s", "MOVE.%-2s C,@D0" } },
+
+ // load
+ { { "A=Dat0 %s", "MOVE.%-2s @D0,A" } },
+ { { "A=Dat1 %s", "MOVE.%-2s @D0,A" } },
+ { { "C=Dat0 %s", "MOVE.%-2s @D0,C" } },
+ { { "C=Dat1 %s", "MOVE.%-2s @D0,C" } },
+
+ // add/sub immediate
+ { { "D0=D0+ %x", "ADD.A %x,D0" } },
+ { { "D1=D1+ %x", "ADD.A %x,D1" } },
+ { { "D0=D0- %x", "SUB.A %x,D0" } },
+ { { "D1=D1- %x", "SUB.A %x,D1" } },
+
+ { { "A=A+ %s,%x", "ADD.%-2s %x,A" } },
+ { { "B=B+ %s,%x", "ADD.%-2s %x,B" } },
+ { { "C=C+ %s,%x", "ADD.%-2s %x,C" } },
+ { { "D=D+ %s,%x", "ADD.%-2s %x,D" } },
+ { { "A=A- %s,%x", "SUB.%-2s %x,A" } },
+ { { "B=B- %s,%x", "SUB.%-2s %x,B" } },
+ { { "C=C- %s,%x", "SUB.%-2s %x,C" } },
+ { { "D=D- %s,%x", "SUB.%-2s %x,D" } },
+
+ { { "A=A&B %s", "AND.%-2s B,A" } },
+ { { "B=B&C %s", "AND.%-2s C,B" } },
+ { { "C=C&A %s", "AND.%-2s A,C" } },
+ { { "D=D&C %s", "AND.%-2s C,D" } },
+ { { "B=B&A %s", "AND.%-2s A,B" } },
+ { { "C=C&B %s", "AND.%-2s B,C" } },
+ { { "A=A&C %s", "AND.%-2s C,A" } },
+ { { "C=C&D %s", "AND.%-2s D,C" } },
+
+ { { "A=A!B %s", "OR.%-2s B,A" } },
+ { { "B=B!C %s", "OR.%-2s C,B" } },
+ { { "C=C!A %s", "OR.%-2s A,C" } },
+ { { "D=D!C %s", "OR.%-2s C,D" } },
+ { { "B=B!A %s", "OR.%-2s A,B" } },
+ { { "C=C!B %s", "OR.%-2s B,C" } },
+ { { "A=A!C %s", "OR.%-2s C,A" } },
+ { { "C=C!D %s", "OR.%-2s D,C" } },
+
+ { { "Asrb %x", "SRB.%-2s A" } },
+ { { "Bsrb %x", "SRB.%-2s B" } },
+ { { "Csrb %x", "SRB.%-2s C" } },
+ { { "Dsrb %x", "SRB.%-2s D" } },
+
+ { { "Aslc %s", "RLN.%-2s A" } },
+ { { "Bslc %s", "RLN.%-2s B" } },
+ { { "Cslc %s", "RLN.%-2s C" } },
+ { { "Dslc %s", "RLN.%-2s D" } },
+ { { "Aslc %s", "RRN.%-2s A" } },
+ { { "Bslc %s", "RRN.%-2s B" } },
+ { { "Cslc %s", "RRN.%-2s C" } },
+ { { "Dslc %s", "RRN.%-2s D" } },
+
+ { { "A=A+B %s", "ADD.%-2s B,A" } },
+ { { "B=B+C %s", "ADD.%-2s C,B" } },
+ { { "C=C+A %s", "ADD.%-2s A,C" } },
+ { { "D=D+C %s", "ADD.%-2s C,D" } },
+ { { "A=A+A %s", "ADD.%-2s A,A" } },
+ { { "B=B+B %s", "ADD.%-2s B,B" } },
+ { { "C=C+C %s", "ADD.%-2s C,C" } },
+ { { "D=D+C %s", "ADD.%-2s D,D" } },
+ { { "B=B+A %s", "ADD.%-2s A,B" } },
+ { { "C=C+B %s", "ADD.%-2s B,C" } },
+ { { "A=A+C %s", "ADD.%-2s C,A" } },
+ { { "C=C+D %s", "ADD.%-2s D,C" } },
+ { { "A=A-1 %s", "DEC.%-2s A" } },
+ { { "B=B-1 %s", "DEC.%-2s B" } },
+ { { "C=C-1 %s", "DEC.%-2s C" } },
+ { { "D=D-1 %s", "DEC.%-2s D" } },
+
+ { { "A=A-B %s", "ADD.%-2s B,A" } },
+ { { "B=B-C %s", "ADD.%-2s C,B" } },
+ { { "C=C-A %s", "ADD.%-2s A,C" } },
+ { { "D=D-C %s", "ADD.%-2s C,D" } },
+ { { "A=A+1 %s", "INC.%-2s A" } },
+ { { "B=B+1 %s", "INC.%-2s B" } },
+ { { "C=C+1 %s", "INC.%-2s C" } },
+ { { "D=D+1 %s", "INC.%-2s D" } },
+ { { "B=B-A %s", "SUB.%-2s A,B" } },
+ { { "C=C-B %s", "SUB.%-2s B,C" } },
+ { { "A=A-C %s", "SUB.%-2s C,A" } },
+ { { "C=C-D %s", "SUB.%-2s D,C" } },
+ { { "A=B-A %s", "SUBN.%-2s B,A" } },
+ { { "B=C-B %s", "SUBN.%-2s C,B" } },
+ { { "C=A-C %s", "SUBN.%-2s A,C" } },
+ { { "D=C-D %s", "SUBN.%-2s C,D" } },
+
+ { { "A=0 %s", "CLR.%-2s A" } },
+ { { "B=0 %s", "CLR.%-2s B" } },
+ { { "C=0 %s", "CLR.%-2s C" } },
+ { { "D=0 %s", "CLR.%-2s D" } },
+ { { "A=B %s", "MOVE.%-2s B,A" } },
+ { { "B=C %s", "MOVE.%-2s C,B" } },
+ { { "C=A %s", "MOVE.%-2s A,C" } },
+ { { "D=C %s", "MOVE.%-2s C,D" } },
+ { { "B=A %s", "MOVE.%-2s A,B" } },
+ { { "C=B %s", "MOVE.%-2s B,C" } },
+ { { "A=C %s", "MOVE.%-2s C,A" } },
+ { { "C=D %s", "MOVE.%-2s D,C" } },
+ { { "ABex %s", "SWAP.%-2s A,B" } },
+ { { "BCex %s", "SWAP.%-2s B,C" } },
+ { { "ACex %s", "SWAP.%-2s A,C" } },
+ { { "CDex %s", "SWAP.%-2s C,D" } },
+
+ { { "Asl %s", "SLN.%-2s A" } },
+ { { "Bsl %s", "SLN.%-2s B" } },
+ { { "Csl %s", "SLN.%-2s C" } },
+ { { "Dsl %s", "SLN.%-2s D" } },
+ { { "Asr %s", "SRN.%-2s A" } },
+ { { "Bsr %s", "SRN.%-2s B" } },
+ { { "Csr %s", "SRN.%-2s C" } },
+ { { "Dsr %s", "SRN.%-2s D" } },
+ { { "A=-A %s", "NEG.%-2s A" } },
+ { { "B=-B %s", "NEG.%-2s B" } },
+ { { "C=-C %s", "NEG.%-2s C" } },
+ { { "D=-D %s", "NEG.%-2s D" } },
+ { { "A=-A-1 %s", "NOT.%-2s A" } },
+ { { "B=-B-1 %s", "NOT.%-2s B" } },
+ { { "C=-C-1 %s", "NOT.%-2s C" } },
+ { { "D=-D-1 %s", "NOT.%-2s D" } }
+
+};
+
+typedef struct {
+ enum {
+ Complete=-1,
+ Illegal,
+ Opcode0, Opcode0E, Opcode0Ea,
+ Opcode1, Opcode10, Opcode11, Opcode12, Opcode13, Opcode14, Opcode15,
+ Opcode8, Opcode80, Opcode808, Opcode8081,
+ Opcode81, Opcode818, Opcode818a, Opcode819, Opcode819a,
+ Opcode81A, Opcode81Aa, Opcode81Aa0,Opcode81Aa1, Opcode81Aa2, Opcode81B,
+ Opcode8A, Opcode8B,
+ Opcode9, Opcode9a, Opcode9b,
+ OpcodeA, OpcodeAa, OpcodeAb,
+ OpcodeB, OpcodeBa, OpcodeBb,
+ OpcodeC,
+ OpcodeD,
+ OpcodeE,
+ OpcodeF
+ } sel;
+ enum {
+ AdrNone,
+ AdrAF, AdrA, AdrB, AdrCount,
+ BranchReturn, TestBranchRet, ImmBranch,
+ ABranchReturn, // address field A
+ xBranchReturn, // address field specified in previous opcode entry
+ Imm, ImmCount, ImmCload, Imm2, Imm4, Imm5,
+ Dis3, Dis3Call, Dis4, Dis4Call, Abs,
+ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW, FieldA
+ } adr;
+ MNEMONICS mnemonic;
+} OPCODE;
+
+static const char *field_2_string(int adr_enum)
+{
+ switch (adr_enum) {
+ case FieldP: return P;
+ case FieldWP: return WP;
+ case FieldXS: return XS;
+ case FieldX: return X;
+ case FieldS: return S;
+ case FieldM: return M;
+ case FieldB: return B;
+ case FieldW: return W;
+ case FieldA: return A;
+ }
+ return 0;
+}
+
+static OPCODE opcodes[][0x10]= {
+ {
+ // first digit
+ { Opcode0 },
+ { Opcode1 },
+ { Complete, Imm, PloadImm },
+ { Complete, ImmCload, CloadImm },
+ { Complete, BranchReturn, branchCarrySet},
+ { Complete, BranchReturn, branchCarryClear },
+ { Complete, Dis3, jump3 },
+ { Complete, Dis3Call, call3 },
+ { Opcode8 },
+ { Opcode9 },
+ { OpcodeA },
+ { OpcodeB },
+ { OpcodeC },
+ { OpcodeD },
+ { OpcodeE },
+ { OpcodeF }
+ }, { // 0
+ { Complete, AdrNone, ReturnSetXM },
+ { Complete, AdrNone, Return },
+ { Complete, AdrNone, ReturnSetCarry },
+ { Complete, AdrNone, ReturnClearCarry },
+ { Complete, AdrNone, SetHexMode },
+ { Complete, AdrNone, SetDecMode },
+ { Complete, AdrNone, PopC },
+ { Complete, AdrNone, PushC },
+ { Complete, AdrNone, clearST },
+ { Complete, AdrNone, CcopyST },
+ { Complete, AdrNone, STcopyC },
+ { Complete, AdrNone, swapCST },
+ { Complete, AdrNone, incP },
+ { Complete, AdrNone, decP },
+ { Opcode0E },
+ { Complete, AdrNone, ReturnFromInterrupt }
+ }, { //0E
+ { Opcode0Ea, AdrAF },
+ { Opcode0Ea, AdrAF },
+ { Opcode0Ea, AdrAF },
+ { Opcode0Ea, AdrAF },
+ { Opcode0Ea, AdrAF },
+ { Opcode0Ea, AdrAF },
+ { Opcode0Ea, AdrAF },
+ { Opcode0Ea, AdrAF },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Opcode0Ea, AdrAF }
+ }, { //0Ea
+ { Complete, AdrNone, AandB },
+ { Complete, AdrNone, BandC },
+ { Complete, AdrNone, CandA },
+ { Complete, AdrNone, DandC },
+ { Complete, AdrNone, BandA },
+ { Complete, AdrNone, CandB },
+ { Complete, AdrNone, AandC },
+ { Complete, AdrNone, CandD },
+ { Complete, AdrNone, AorB },
+ { Complete, AdrNone, BorC },
+ { Complete, AdrNone, CorA },
+ { Complete, AdrNone, DorC },
+ { Complete, AdrNone, BorA },
+ { Complete, AdrNone, CorB },
+ { Complete, AdrNone, AorC },
+ { Complete, AdrNone, CorD }
+ }, { //1
+ { Opcode10 },
+ { Opcode11 },
+ { Opcode12 },
+ { Opcode13 },
+ { Opcode14 },
+ { Opcode15 },
+ { Complete, ImmCount, D0addImm },
+ { Complete, ImmCount, D1addImm },
+ { Complete, ImmCount, D0subImm },
+ { Complete, Imm2, D0loadImm2 },
+ { Complete, Imm4, D0loadImm4 },
+ { Complete, Imm5, D0loadImm5 },
+ { Complete, ImmCount, D1subImm },
+ { Complete, Imm2, D1loadImm2 },
+ { Complete, Imm4, D1loadImm4 },
+ { Complete, Imm5, D1loadImm5 }
+ }, { //10
+ { Complete, FieldW, R0copyA },
+ { Complete, FieldW, R1copyA },
+ { Complete, FieldW, R2copyA },
+ { Complete, FieldW, R3copyA },
+ { Complete, FieldW, R4copyA },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Complete, FieldW, R0copyC },
+ { Complete, FieldW, R1copyC },
+ { Complete, FieldW, R2copyC },
+ { Complete, FieldW, R3copyC },
+ { Complete, FieldW, R4copyC },
+ { Illegal },
+ { Illegal },
+ { Illegal }
+ }, { //11
+ { Complete, FieldW, AcopyR0 },
+ { Complete, FieldW, AcopyR1 },
+ { Complete, FieldW, AcopyR2 },
+ { Complete, FieldW, AcopyR3 },
+ { Complete, FieldW, AcopyR4 },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Complete, FieldW, CcopyR0 },
+ { Complete, FieldW, CcopyR1 },
+ { Complete, FieldW, CcopyR2 },
+ { Complete, FieldW, CcopyR3 },
+ { Complete, FieldW, CcopyR4 },
+ { Illegal },
+ { Illegal },
+ { Illegal }
+ }, { //12
+ { Complete, FieldW, SwapAR0 },
+ { Complete, FieldW, SwapAR1 },
+ { Complete, FieldW, SwapAR2 },
+ { Complete, FieldW, SwapAR3 },
+ { Complete, FieldW, SwapAR4 },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Complete, FieldW, SwapCR0 },
+ { Complete, FieldW, SwapCR1 },
+ { Complete, FieldW, SwapCR2 },
+ { Complete, FieldW, SwapCR3 },
+ { Complete, FieldW, SwapCR4 },
+ { Illegal },
+ { Illegal },
+ { Illegal }
+ }, { //13
+ { Complete, FieldA, D0copyA },
+ { Complete, FieldA, D1copyA },
+ { Complete, FieldA, SwapAD0 },
+ { Complete, FieldA, SwapAD1 },
+ { Complete, FieldA, D0copyC },
+ { Complete, FieldA, D1copyC },
+ { Complete, FieldA, SwapCD0 },
+ { Complete, FieldA, SwapCD1 },
+ { Complete, FieldS, D0copyAShort },
+ { Complete, FieldS, D1copyAShort },
+ { Complete, FieldS, SwapAD0Short },
+ { Complete, FieldS, SwapAD1Short },
+ { Complete, FieldS, D0copyCShort },
+ { Complete, FieldS, D1copyCShort },
+ { Complete, FieldS, SwapCD0Short },
+ { Complete, FieldS, SwapCD1Short }
+ }, { //14
+ { Complete, FieldA, D0storeA },
+ { Complete, FieldA, D1storeA },
+ { Complete, FieldA, AloadD0 },
+ { Complete, FieldA, AloadD1 },
+ { Complete, FieldA, D0storeC },
+ { Complete, FieldA, D1storeC },
+ { Complete, FieldA, CloadD0 },
+ { Complete, FieldA, CloadD1 },
+ { Complete, FieldB, D0storeA },
+ { Complete, FieldB, D1storeA },
+ { Complete, FieldB, AloadD0 },
+ { Complete, FieldB, AloadD1 },
+ { Complete, FieldB, D0storeC },
+ { Complete, FieldB, D1storeC },
+ { Complete, FieldB, CloadD0 },
+ { Complete, FieldB, CloadD1 }
+ }, { //15
+ { Complete, AdrA, D0storeA },
+ { Complete, AdrA, D1storeA },
+ { Complete, AdrA, AloadD0 },
+ { Complete, AdrA, AloadD1 },
+ { Complete, AdrA, D0storeC },
+ { Complete, AdrA, D1storeC },
+ { Complete, AdrA, CloadD0 },
+ { Complete, AdrA, CloadD1 },
+ { Complete, AdrCount, D0storeA },
+ { Complete, AdrCount, D1storeA },
+ { Complete, AdrCount, AloadD0 },
+ { Complete, AdrCount, AloadD1 },
+ { Complete, AdrCount, D0storeC },
+ { Complete, AdrCount, D1storeC },
+ { Complete, AdrCount, CloadD0 },
+ { Complete, AdrCount, CloadD1 },
+ }, { //8
+ { Opcode80 },
+ { Opcode81 },
+ { Complete, Imm, clearHST },
+ { Complete, TestBranchRet, branchHSTclear },
+ { Complete, Imm, clearBitST },
+ { Complete, Imm, setBitST },
+ { Complete, TestBranchRet, branchSTclear },
+ { Complete, TestBranchRet, branchSTset },
+ { Complete, TestBranchRet, branchPdiffers},
+ { Complete, TestBranchRet, branchPequals},
+ { Opcode8A },
+ { Opcode8B },
+ { Complete, Dis4, jump4 },
+ { Complete, Abs, jump },
+ { Complete, Dis4Call, call4 },
+ { Complete, Abs, call }
+ }, { //80
+ { Complete, AdrNone, outCS },
+ { Complete, AdrNone, outC },
+ { Complete, AdrNone, inA },
+ { Complete, AdrNone, inC },
+ { Complete, AdrNone, unconfig },
+ { Complete, AdrNone, config },
+ { Complete, AdrNone, Cid },
+ { Complete, AdrNone, shutdown },
+ { Opcode808 },
+ { Complete, AdrNone, cp1 },
+ { Complete, AdrNone, reset },
+ { Complete, AdrNone, buscc },
+ { Complete, Imm, CcopyP },
+ { Complete, Imm, PcopyC },
+ { Complete, AdrNone, sreq },
+ { Complete, Imm, CswapP }
+ }, { //808
+ { Complete, AdrNone, inton },
+ { Opcode8081 },
+ { Complete, ImmCload, AloadImm },
+ { Complete, AdrNone, buscb },
+ { Complete, Imm, clearAbit },
+ { Complete, Imm, setAbit },
+ { Complete, ImmBranch, Abitclear },
+ { Complete, ImmBranch, Abitset },
+ { Complete, Imm, clearCbit },
+ { Complete, Imm, setCbit },
+ { Complete, ImmBranch, Cbitclear },
+ { Complete, ImmBranch, Cbitset },
+ { Complete, AdrNone, PCloadA },
+ { Complete, AdrNone, buscd },
+ { Complete, AdrNone, PCloadC },
+ { Complete, AdrNone, intoff }
+ }, { //8081
+ { Complete, AdrNone, rsi },
+ //! rest illegal
+ }, { //81
+ { Complete, FieldW, AshiftleftCarry },
+ { Complete, FieldW, BshiftleftCarry },
+ { Complete, FieldW, DshiftleftCarry },
+ { Complete, FieldW, DshiftleftCarry },
+ { Complete, FieldW, AshiftrightCarry },
+ { Complete, FieldW, AshiftrightCarry },
+ { Complete, FieldW, AshiftrightCarry },
+ { Complete, FieldW, AshiftrightCarry },
+ { Opcode818 },
+ { Opcode819 },
+ { Opcode81A },
+ { Opcode81B },
+ { Complete, FieldW, Ashiftrightbit },
+ { Complete, FieldW, Bshiftrightbit },
+ { Complete, FieldW, Cshiftrightbit },
+ { Complete, FieldW, Dshiftrightbit }
+ }, { //818
+ { Opcode818a, AdrAF },
+ { Opcode818a, AdrAF },
+ { Opcode818a, AdrAF },
+ { Opcode818a, AdrAF },
+ { Opcode818a, AdrAF },
+ { Opcode818a, AdrAF },
+ { Opcode818a, AdrAF },
+ { Opcode818a, AdrAF },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Opcode818a, AdrAF },
+ }, { //818a
+ { Complete, AdrNone, AaddImm },
+ { Complete, AdrNone, BaddImm },
+ { Complete, AdrNone, CaddImm },
+ { Complete, AdrNone, DaddImm },
+ { Complete, AdrNone, AsubImm },
+ { Complete, AdrNone, BsubImm },
+ { Complete, AdrNone, CsubImm },
+ { Complete, AdrNone, DsubImm }
+ //! rest illegal
+ }, { //819
+ { Opcode819a, AdrAF },
+ { Opcode819a, AdrAF },
+ { Opcode819a, AdrAF },
+ { Opcode819a, AdrAF },
+ { Opcode819a, AdrAF },
+ { Opcode819a, AdrAF },
+ { Opcode819a, AdrAF },
+ { Opcode819a, AdrAF }, //?
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Opcode819a, AdrAF },
+ }, { //819a }
+ { Complete, AdrNone, Ashiftright },
+ { Complete, AdrNone, Bshiftright },
+ { Complete, AdrNone, Cshiftright },
+ { Complete, AdrNone, Dshiftright },
+ //! rest illegal
+ }, { //81A
+ { Opcode81Aa, AdrAF },
+ { Opcode81Aa, AdrAF },
+ { Opcode81Aa, AdrAF },
+ { Opcode81Aa, AdrAF },
+ { Opcode81Aa, AdrAF },
+ { Opcode81Aa, AdrAF },
+ { Opcode81Aa, AdrAF },
+ { Opcode81Aa, AdrAF },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Opcode81Aa, AdrAF },
+ }, { //81Aa
+ { Opcode81Aa0 },
+ { Opcode81Aa1 },
+ { Opcode81Aa2 },
+ //! rest illegal
+ }, { //81Aa0
+ { Complete, AdrNone, R0copyA },
+ { Complete, AdrNone, R1copyA },
+ { Complete, AdrNone, R2copyA },
+ { Complete, AdrNone, R3copyA },
+ { Complete, AdrNone, R4copyA },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Complete, AdrNone, R0copyC },
+ { Complete, AdrNone, R1copyC },
+ { Complete, AdrNone, R2copyC },
+ { Complete, AdrNone, R3copyC },
+ { Complete, AdrNone, R4copyC },
+ { Illegal },
+ { Illegal },
+ { Illegal }
+ }, { //81Aa1
+ { Complete, AdrNone, AcopyR0 },
+ { Complete, AdrNone, AcopyR1 },
+ { Complete, AdrNone, AcopyR2 },
+ { Complete, AdrNone, AcopyR3 },
+ { Complete, AdrNone, AcopyR4 },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Complete, AdrNone, CcopyR0 },
+ { Complete, AdrNone, CcopyR1 },
+ { Complete, AdrNone, CcopyR2 },
+ { Complete, AdrNone, CcopyR3 },
+ { Complete, AdrNone, CcopyR4 },
+ { Illegal },
+ { Illegal },
+ { Illegal }
+ }, { //81Aa2
+ { Complete, AdrNone, SwapAR0 },
+ { Complete, AdrNone, SwapAR1 },
+ { Complete, AdrNone, SwapAR2 },
+ { Complete, AdrNone, SwapAR3 },
+ { Complete, AdrNone, SwapAR4 },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Complete, AdrNone, SwapCR0 },
+ { Complete, AdrNone, SwapCR1 },
+ { Complete, AdrNone, SwapCR2 },
+ { Complete, AdrNone, SwapCR3 },
+ { Complete, AdrNone, SwapCR4 },
+ { Illegal },
+ { Illegal },
+ { Illegal }
+ }, { //81B
+ { Illegal },
+ { Illegal },
+ { Complete, AdrNone, jumpA },
+ { Complete, AdrNone, jumpC },
+ { Complete, AdrNone, PCcopyA },
+ { Complete, AdrNone, PCcopyC },
+ { Complete, AdrNone, AcopyPC },
+ { Complete, AdrNone, CcopyPC },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal },
+ { Illegal }
+ }, { //8A
+ { Complete, ABranchReturn, branchAequalsB },
+ { Complete, ABranchReturn, branchBequalsC },
+ { Complete, ABranchReturn, branchAequalsC },
+ { Complete, ABranchReturn, branchCequalsD },
+ { Complete, ABranchReturn, branchAdiffersB },
+ { Complete, ABranchReturn, branchBdiffersC },
+ { Complete, ABranchReturn, branchAdiffersC },
+ { Complete, ABranchReturn, branchCdiffersD },
+ { Complete, ABranchReturn, branchAzero },
+ { Complete, ABranchReturn, branchBzero },
+ { Complete, ABranchReturn, branchCzero },
+ { Complete, ABranchReturn, branchDzero },
+ { Complete, ABranchReturn, branchAnotzero },
+ { Complete, ABranchReturn, branchBnotzero },
+ { Complete, ABranchReturn, branchCnotzero },
+ { Complete, ABranchReturn, branchDnotzero }
+ }, { //8B
+ { Complete, ABranchReturn, branchAgreaterB },
+ { Complete, ABranchReturn, branchBgreaterC },
+ { Complete, ABranchReturn, branchCgreaterA },
+ { Complete, ABranchReturn, branchDgreaterC },
+ { Complete, ABranchReturn, branchAlowerB },
+ { Complete, ABranchReturn, branchBlowerC },
+ { Complete, ABranchReturn, branchClowerA },
+ { Complete, ABranchReturn, branchDlowerC },
+ { Complete, ABranchReturn, branchAnotlowerB },
+ { Complete, ABranchReturn, branchBnotlowerC },
+ { Complete, ABranchReturn, branchCnotlowerA },
+ { Complete, ABranchReturn, branchDnotlowerC },
+ { Complete, ABranchReturn, branchAnotgreaterB },
+ { Complete, ABranchReturn, branchBnotgreaterC },
+ { Complete, ABranchReturn, branchCnotgreaterA },
+ { Complete, ABranchReturn, branchDnotgreaterC }
+ }, { //9
+ { Opcode9a, AdrA },
+ { Opcode9a, AdrA },
+ { Opcode9a, AdrA },
+ { Opcode9a, AdrA },
+ { Opcode9a, AdrA },
+ { Opcode9a, AdrA },
+ { Opcode9a, AdrA },
+ { Opcode9a, AdrA },
+ { Opcode9b, AdrB },
+ { Opcode9b, AdrB },
+ { Opcode9b, AdrB },
+ { Opcode9b, AdrB },
+ { Opcode9b, AdrB },
+ { Opcode9b, AdrB },
+ { Opcode9b, AdrB },
+ { Opcode9b, AdrB },
+ }, { //9a
+ { Complete, xBranchReturn, branchAequalsB },
+ { Complete, xBranchReturn, branchBequalsC },
+ { Complete, xBranchReturn, branchAequalsC },
+ { Complete, xBranchReturn, branchCequalsD },
+ { Complete, xBranchReturn, branchAdiffersB },
+ { Complete, xBranchReturn, branchBdiffersC },
+ { Complete, xBranchReturn, branchAdiffersC },
+ { Complete, xBranchReturn, branchCdiffersD },
+ { Complete, xBranchReturn, branchAzero },
+ { Complete, xBranchReturn, branchBzero },
+ { Complete, xBranchReturn, branchCzero },
+ { Complete, xBranchReturn, branchDzero },
+ { Complete, xBranchReturn, branchAnotzero },
+ { Complete, xBranchReturn, branchBnotzero },
+ { Complete, xBranchReturn, branchCnotzero },
+ { Complete, xBranchReturn, branchDnotzero }
+ }, { //9b
+ { Complete, xBranchReturn, branchAgreaterB },
+ { Complete, xBranchReturn, branchBgreaterC },
+ { Complete, xBranchReturn, branchCgreaterA },
+ { Complete, xBranchReturn, branchDgreaterC },
+ { Complete, xBranchReturn, branchAlowerB },
+ { Complete, xBranchReturn, branchBlowerC },
+ { Complete, xBranchReturn, branchClowerA },
+ { Complete, xBranchReturn, branchDlowerC },
+ { Complete, xBranchReturn, branchAnotlowerB },
+ { Complete, xBranchReturn, branchBnotlowerC },
+ { Complete, xBranchReturn, branchCnotlowerA },
+ { Complete, xBranchReturn, branchDnotlowerC },
+ { Complete, xBranchReturn, branchAnotgreaterB },
+ { Complete, xBranchReturn, branchBnotgreaterC },
+ { Complete, xBranchReturn, branchCnotgreaterA },
+ { Complete, xBranchReturn, branchDnotgreaterC }
+ }, { //A
+ { OpcodeAa, AdrA },
+ { OpcodeAa, AdrA },
+ { OpcodeAa, AdrA },
+ { OpcodeAa, AdrA },
+ { OpcodeAa, AdrA },
+ { OpcodeAa, AdrA },
+ { OpcodeAa, AdrA },
+ { OpcodeAa, AdrA },
+ { OpcodeAb, AdrB },
+ { OpcodeAb, AdrB },
+ { OpcodeAb, AdrB },
+ { OpcodeAb, AdrB },
+ { OpcodeAb, AdrB },
+ { OpcodeAb, AdrB },
+ { OpcodeAb, AdrB },
+ { OpcodeAb, AdrB },
+ }, { //Aa
+ { Complete, AdrNone, AaddB },
+ { Complete, AdrNone, BaddC },
+ { Complete, AdrNone, CaddA },
+ { Complete, AdrNone, DaddC },
+ { Complete, AdrNone, AaddA },
+ { Complete, AdrNone, BaddB },
+ { Complete, AdrNone, CaddC },
+ { Complete, AdrNone, DaddD },
+ { Complete, AdrNone, BaddA },
+ { Complete, AdrNone, CaddB },
+ { Complete, AdrNone, AaddC },
+ { Complete, AdrNone, CaddD },
+ { Complete, AdrNone, decA },
+ { Complete, AdrNone, decB },
+ { Complete, AdrNone, decC },
+ { Complete, AdrNone, decD },
+ }, { //Ab
+ { Complete, AdrNone, clearA },
+ { Complete, AdrNone, clearB },
+ { Complete, AdrNone, clearC },
+ { Complete, AdrNone, clearD },
+ { Complete, AdrNone, AcopyB },
+ { Complete, AdrNone, BcopyC },
+ { Complete, AdrNone, CcopyA },
+ { Complete, AdrNone, DcopyC },
+ { Complete, AdrNone, BcopyA },
+ { Complete, AdrNone, CcopyB },
+ { Complete, AdrNone, AcopyC },
+ { Complete, AdrNone, CcopyD },
+ { Complete, AdrNone, AswapB },
+ { Complete, AdrNone, BswapC },
+ { Complete, AdrNone, CswapA },
+ { Complete, AdrNone, DswapC }
+ }, { //B
+ { OpcodeBa, AdrA },
+ { OpcodeBa, AdrA },
+ { OpcodeBa, AdrA },
+ { OpcodeBa, AdrA },
+ { OpcodeBa, AdrA },
+ { OpcodeBa, AdrA },
+ { OpcodeBa, AdrA },
+ { OpcodeBa, AdrA },
+ { OpcodeBb, AdrB },
+ { OpcodeBb, AdrB },
+ { OpcodeBb, AdrB },
+ { OpcodeBb, AdrB },
+ { OpcodeBb, AdrB },
+ { OpcodeBb, AdrB },
+ { OpcodeBb, AdrB },
+ { OpcodeBb, AdrB },
+ }, { //Ba
+ { Complete, AdrNone, AsubB },
+ { Complete, AdrNone, BsubC },
+ { Complete, AdrNone, CsubA },
+ { Complete, AdrNone, DsubC },
+ { Complete, AdrNone, incA },
+ { Complete, AdrNone, incB },
+ { Complete, AdrNone, incC },
+ { Complete, AdrNone, incD },
+ { Complete, AdrNone, BsubA },
+ { Complete, AdrNone, CsubB },
+ { Complete, AdrNone, AsubC },
+ { Complete, AdrNone, CsubD },
+ { Complete, AdrNone, AsubnB },
+ { Complete, AdrNone, BsubnC },
+ { Complete, AdrNone, CsubnA },
+ { Complete, AdrNone, DsubnC },
+ }, { //Bb
+ { Complete, AdrNone, Ashiftleft },
+ { Complete, AdrNone, Bshiftleft },
+ { Complete, AdrNone, Cshiftleft },
+ { Complete, AdrNone, Dshiftleft },
+ { Complete, AdrNone, Ashiftright },
+ { Complete, AdrNone, Bshiftright },
+ { Complete, AdrNone, Cshiftright },
+ { Complete, AdrNone, Dshiftright },
+ { Complete, AdrNone, negateA },
+ { Complete, AdrNone, negateB },
+ { Complete, AdrNone, negateC },
+ { Complete, AdrNone, negateD },
+ { Complete, AdrNone, notA },
+ { Complete, AdrNone, notB },
+ { Complete, AdrNone, notC },
+ { Complete, AdrNone, notD }
+ }, { //C
+ { Complete, FieldA, AaddB },
+ { Complete, FieldA, BaddC },
+ { Complete, FieldA, CaddA },
+ { Complete, FieldA, DaddC },
+ { Complete, FieldA, AaddA },
+ { Complete, FieldA, BaddB },
+ { Complete, FieldA, CaddC },
+ { Complete, FieldA, DaddD },
+ { Complete, FieldA, BaddA },
+ { Complete, FieldA, CaddB },
+ { Complete, FieldA, AaddC },
+ { Complete, FieldA, CaddD },
+ { Complete, FieldA, decA },
+ { Complete, FieldA, decB },
+ { Complete, FieldA, decC },
+ { Complete, FieldA, decD }
+ }, { //D
+ { Complete, FieldA, clearA },
+ { Complete, FieldA, clearB },
+ { Complete, FieldA, clearC },
+ { Complete, FieldA, clearD },
+ { Complete, FieldA, AcopyB },
+ { Complete, FieldA, BcopyC },
+ { Complete, FieldA, CcopyA },
+ { Complete, FieldA, DcopyC },
+ { Complete, FieldA, BcopyA },
+ { Complete, FieldA, CcopyB },
+ { Complete, FieldA, AcopyC },
+ { Complete, FieldA, CcopyD },
+ { Complete, FieldA, AswapB },
+ { Complete, FieldA, BswapC },
+ { Complete, FieldA, CswapA },
+ { Complete, FieldA, DswapC }
+ }, { //E
+ { Complete, FieldA, AsubB },
+ { Complete, FieldA, BsubC },
+ { Complete, FieldA, CsubA },
+ { Complete, FieldA, DsubC },
+ { Complete, FieldA, incA },
+ { Complete, FieldA, incB },
+ { Complete, FieldA, incC },
+ { Complete, FieldA, incD },
+ { Complete, FieldA, BsubA },
+ { Complete, FieldA, CsubB },
+ { Complete, FieldA, AsubC },
+ { Complete, FieldA, CsubD },
+ { Complete, FieldA, AsubnB },
+ { Complete, FieldA, BsubnC },
+ { Complete, FieldA, CsubnA },
+ { Complete, FieldA, DsubnC }
+ }, { //F
+ { Complete, FieldA, Ashiftleft },
+ { Complete, FieldA, Bshiftleft },
+ { Complete, FieldA, Cshiftleft },
+ { Complete, FieldA, Dshiftleft },
+ { Complete, FieldA, Ashiftright },
+ { Complete, FieldA, Bshiftright },
+ { Complete, FieldA, Cshiftright },
+ { Complete, FieldA, Dshiftright },
+ { Complete, FieldA, negateA },
+ { Complete, FieldA, negateB },
+ { Complete, FieldA, negateC },
+ { Complete, FieldA, negateD },
+ { Complete, FieldA, notA },
+ { Complete, FieldA, notB },
+ { Complete, FieldA, notC },
+ { Complete, FieldA, notD }
+ }
+};
+
+static const int field_adr_af[]=
+{ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW, 0, 0, 0, 0, 0, 0, 0, FieldA };
+
+static const int field_adr_a[]=
+{ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW};
+
+static const int field_adr_b[]=
+{ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW };
+
+unsigned saturn_dasm(char *dst, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int adr=0;
+
+ int cont=1; // operation still not complete disassembled
+ char bin[10]; int binsize=0; // protocollizing fetched nibbles
+ char number[17];
+ OPCODE *level=opcodes[0]; //pointer to current digit
+ int op; // currently fetched nibble
+ int pos = 0;
+
+ int i,c,v;
+
+ while (cont)
+ {
+ op = oprom[pos++];
+ level+=op;
+ switch (level->sel) {
+ case Illegal:
+ cont=0;
+ bin[binsize++]=number_2_hex[op];
+ bin[binsize]=0;
+ sprintf(dst, "???%s",bin);
+ break;
+ default:
+ bin[binsize++]=number_2_hex[op];
+ switch (level->adr) {
+ case AdrNone: break;
+ case AdrA:
+ adr=field_adr_a[op];
+ break;
+ case AdrAF:
+ adr=field_adr_af[op];
+ break;
+ case AdrB:
+ adr=field_adr_b[op&7];
+ break;
+ default:
+ cont = 0;
+ bin[binsize++]=number_2_hex[op];
+ bin[binsize]=0;
+ sprintf(dst, "???%s",bin);
+ break;
+ }
+ break;
+ case Complete:
+ cont=0;
+ switch (level->adr==AdrNone?adr:level->adr) {
+ case AdrNone:
+ strcpy(dst, mnemonics[level->mnemonic].name[set]);
+ break;
+ case Imm:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], oprom[pos++]);
+ break;
+ case ImmCount:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], oprom[pos++]+1);
+ break;
+ case AdrCount: // mnemonics have string %s for address field
+ snprintf(number,sizeof(number),"%x",oprom[pos++]+1);
+ sprintf(dst, mnemonics[level->mnemonic].name[set], number);
+ break;
+ case Imm2:
+ v=oprom[pos++];
+ v|=oprom[pos++]<<4;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], v);
+ break;
+ case Imm4:
+ v=oprom[pos++];
+ v|=oprom[pos++]<<4;
+ v|=oprom[pos++]<<8;
+ v|=oprom[pos++]<<12;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], v);
+ break;
+ case Imm5:
+ v=oprom[pos++];
+ v|=oprom[pos++]<<4;
+ v|=oprom[pos++]<<8;
+ v|=oprom[pos++]<<12;
+ v|=oprom[pos++]<<16;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], v);
+ break;
+ case ImmCload:
+ c=i=oprom[pos++];
+ number[i+1]=0;
+ for (;i>=0; i--) number[i]=number_2_hex[oprom[pos++]];
+ sprintf(dst, mnemonics[level->mnemonic].name[set], c+1, number);
+ break;
+ case Dis3:
+ SATURN_PEEKOP_DIS12(v);
+ c=(pc+pos-3+v)%0xfffff;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], c );
+ break;
+ case Dis3Call:
+ SATURN_PEEKOP_DIS12(v);
+ c=(pc+pos-3+v)%0xfffff;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], c );
+ break;
+ case Dis4:
+ SATURN_PEEKOP_DIS16(v);
+ c=(pc+pos-4+v)%0xfffff;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], c );
+ break;
+ case Dis4Call:
+ SATURN_PEEKOP_DIS16(v);
+ c=(pc+pos-4+v)%0xfffff;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], c );
+ break;
+ case Abs:
+ SATURN_PEEKOP_ADR(v);
+ sprintf(dst, mnemonics[level->mnemonic].name[set], v );
+ break;
+ case BranchReturn:
+ SATURN_PEEKOP_DIS8(v);
+ if (v==0) {
+ strcpy(dst, mnemonics[level->mnemonic+1].name[set]);
+ } else {
+ c=(pc+pos-2+v)&0xfffff;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], c);
+ }
+ break;
+ case ABranchReturn:
+ SATURN_PEEKOP_DIS8(v);
+ if (v==0) {
+ sprintf(dst, mnemonics[level->mnemonic+1].name[set], A);
+ } else {
+ c=(pc+pos-2+v)&0xfffff;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], A, c);
+ }
+ break;
+ case xBranchReturn:
+ SATURN_PEEKOP_DIS8(v);
+ if (v==0) {
+ sprintf(dst, mnemonics[level->mnemonic+1].name[set], field_2_string(adr));
+ } else {
+ c=(pc+pos-2+v)&0xfffff;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], field_2_string(adr), c);
+ }
+ break;
+ case TestBranchRet:
+ i=oprom[pos++];
+ SATURN_PEEKOP_DIS8(v);
+ if (v==0) {
+ sprintf(dst, mnemonics[level->mnemonic+1].name[set], i);
+ } else {
+ c=(pc+pos-2+v)&0xfffff;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], i, c);
+ }
+ break;
+ case ImmBranch:
+ i=oprom[pos++];
+ SATURN_PEEKOP_DIS8(v);
+ c=(pc+pos-2+v)&0xfffff;
+ sprintf(dst, mnemonics[level->mnemonic].name[set], i, c);
+ break;
+ case FieldP:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], P );
+ break;
+ case FieldWP:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], WP );
+ break;
+ case FieldXS:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], XS );
+ break;
+ case FieldX:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], X );
+ break;
+ case FieldS:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], S );
+ break;
+ case FieldM:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], M );
+ break;
+ case FieldB:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], B );
+ break;
+ case FieldA:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], A );
+ break;
+ case FieldW:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], W );
+ break;
+ case AdrA:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], adr_a[oprom[pos++]] );
+ break;
+ case AdrAF:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], adr_af[oprom[pos++]] );
+ break;
+ case AdrB:
+ sprintf(dst, mnemonics[level->mnemonic].name[set], adr_b[oprom[pos++]&0x7] );
+ break;
+ }
+ break;
+ }
+ level = opcodes[level->sel];
+ }
+
+ return pos;
+}
diff --git a/src/emu/cpu/sc61860/readpc.c b/src/emu/cpu/sc61860/readpc.c
new file mode 100644
index 00000000000..b3808bc4880
--- /dev/null
+++ b/src/emu/cpu/sc61860/readpc.c
@@ -0,0 +1,195 @@
+#if 0
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/io.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <dos.h>
+
+// gcc -O
+// important because of inb, outb
+
+/*
+ dumps data sent form sharp pc1401 into file
+ at sharp the following program must be started after
+ this dos program was started
+ simple dos utility
+ first arg (filename of file to be written) must be specified
+
+ ct eprop needed
+ changing to parallel port should be easy
+
+nearly all sharp pocket pc's system roms should be readable
+this way.
+
+for some early pocket pc's it would be neccessary to load
+this program into memory.
+(they don't have poke/peek/call instructions,
+so this program can't be typed in)
+
+adapter sharp - cteprommer
+
+1
+2 6v
+3 gnd 8 bit textool gnd pin 20
+4 f0 data--> 8 bit textool data 0 pin 17
+5 f1 handshake --> 8 bit textool data 1 pin 18
+6 save
+7 load
+8 ib7 <--handshake 8 bit textool adress 0 pin 16
+9 ib9
+10
+11
+
+problems with the handshake in at the sharp
+so I didn't use the handshake in the sharp side
+but the pc side must not be interrupted with interrupt
+(pure dos needed?)
+
+*/
+
+
+#define outb(v,adr) outportb(adr,v)
+#define inb(adr) inportb(adr)
+
+#if 0
+ /* this routine dump the memory (start 0)
+ in an endless loop,
+ the pc side must be started before this
+ actual version should be in mess/machine/pocketc.c
+ */
+
+1 restore: for i=16384 to 16455:read a: poke i,a: next i
+10 call 16384
+100 data
+#if 1
+ 18,4,//lip xl
+ 2,0,//lia 0 startaddress low
+ 219,//exam
+ 18,5,//lip xh
+ 2,0,//lia 0 startaddress high
+ 219,//exam
+//400f x:
+ // dump internal rom
+ 18,5,//lip 4
+ 89,//ldm
+ 218,//exab
+ 18,4,//lip 5
+ 89,//ldm
+ 4,//ix for increasing x
+ 0,0,//lii,0
+ 18,20,//lip 20
+ 53, //
+ 18,20,// lip 20
+ 219,//exam
+#else
+ 18,4,//lip xl
+ 2,255,//lia 0
+ 219,//exam
+ 18,5,//lip xh
+ 2,255,//lia 0
+ 219,//exam
+//400f x:
+ // dump external memory
+ 4, //ix
+ 87,// ldd
+#endif
+ 218,//exab
+
+
+
+ 0,4,//lii 4
+
+ //a:
+ 218,// exab
+ 90,// sl
+ 218,// exab
+ 18,94,// lip 94
+ 96,252,// anma 252
+ 2,2, //lia 2
+ 196,// adcm
+ 95,// outf
+ //b:
+ 204,//inb
+ 102,128,//tsia 0x80
+#if 0
+ 41,4,// jnzm b
+#else
+ // input not working reliable!
+ // so handshake removed, PC side must run with disabled
+ // interrupt to not lose data
+ 78,20, //wait 20
+#endif
+
+ 218,// exab
+ 90,// sl
+ 218,// exab
+ 18,94,// lip 94
+ 96,252,//anma 252
+ 2,0,// lia 0
+ 196,//adcm
+ 95,// outf
+ //c:
+ 204,//inb
+ 102,128,//tsia 0x80
+#if 0
+ 57,4,// jzm c
+#else
+ 78,20, //wait 20
+#endif
+
+ 65,//deci
+ 41,34,//jnzm a
+
+ 41,41,//jnzm x:
+
+ 55,// rtn
+// fill up with several 55
+// so you don't have to calculate the exact end in the loop
+#endif
+
+#define PORT_BASE 0x3e0
+
+int main(int argc, char *argv[])
+{
+ unsigned i,v,j,a;
+ char buffer[32768];
+ FILE *out=fopen(argv[1],"wb");
+
+#if 0
+ ioperm(PORT_BASE,8,1);
+ nice(-256);
+#endif
+ asm { cli }
+
+ outb(0x18,PORT_BASE+3); // VCC ON
+ outb(0xc0, PORT_BASE+2);
+ outb(7,PORT_BASE+6); // VPP 12.5, reset off
+
+ outb(0,PORT_BASE);
+ for(j=0;j<0x8000;j++) {
+ for (i=0,v=0;i<4;i++) {
+ for(;((a=inb(PORT_BASE+4))&2)==0; ) ;
+ v=(v<<1)|(a&1);
+ outb(1,PORT_BASE);
+ for(;((a=inb(PORT_BASE+4))&2)!=0; ) ;
+ v=(v<<1)|(a&1);
+ outb(0,PORT_BASE);
+ }
+ buffer[j]=v;
+// printf("%.2x\n",v);
+ }
+ asm { sti }
+ fwrite(buffer,2,0x4000,out);
+ fclose(out);
+
+#if 0
+ outb(8,PORT_BASE+2); // led off
+ outb(0,PORT_BASE+3); //VCC off
+ outb(0,PORT_BASE+6); //VPP off
+#endif
+ return 0;
+}
+
diff --git a/src/emu/cpu/sc61860/sc.h b/src/emu/cpu/sc61860/sc.h
new file mode 100644
index 00000000000..8f7d843a365
--- /dev/null
+++ b/src/emu/cpu/sc61860/sc.h
@@ -0,0 +1,34 @@
+#define I 0
+#define J 1
+#define A 2
+#define B 3
+#define XL 4
+#define XH 5
+#define YL 6
+#define YH 7
+#define K 8
+#define L 9
+#define V 10 // some docus m
+#define W 11 // some docus n
+#define IA 92
+#define IB 93
+#define F0 94
+#define C 95
+
+enum {
+ SC61860_PC=1, SC61860_DP,
+ SC61860_P, SC61860_Q, SC61860_R,
+ SC61860_CARRY,
+ SC61860_ZERO,
+ // the following are in the internal ram!
+ SC61860_BA,
+ SC61860_X, SC61860_Y,
+ SC61860_I, SC61860_J, SC61860_K, SC61860_L, SC61860_V, SC61860_W,
+ SC61860_H
+
+// SC61860_NMI_STATE,
+// SC61860_IRQ_STATE
+};
+
+#define PEEK_OP(pc) cpu_readop(pc)
+#define PEEK_NIBBLE(adr) cpu_readmem_16(adr)
diff --git a/src/emu/cpu/sc61860/sc61860.c b/src/emu/cpu/sc61860/sc61860.c
new file mode 100644
index 00000000000..ef62727d1ad
--- /dev/null
+++ b/src/emu/cpu/sc61860/sc61860.c
@@ -0,0 +1,255 @@
+/*****************************************************************************
+ *
+ * sc61860.c
+ * portable sharp 61860 emulator interface
+ * (sharp pocket computers)
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * History of changes:
+ * 29.7.2001 Several changes listed below taken by Mario Konegger
+ * (konegger@itp.tu-graz.ac.at)
+ * Added 0x7f to set_reg, to prevent p,q,r, overflow.
+ * Changed 512ms timerinterval from 256 to 128, thus the
+ * duration of one period is 512ms.
+ * Extended execute procudure with HLT-mode of CPU.
+ *****************************************************************************/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+
+#include "sc61860.h"
+#include "sc.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+/****************************************************************************
+ * The 61860 registers.
+ ****************************************************************************/
+typedef struct
+{
+ SC61860_CONFIG *config;
+ UINT8 ram[0x60]; // internal special ram
+ UINT8 p, q, r; //7 bits only?
+
+ UINT8 c; // port c, used for HLT.
+ UINT8 d, h;
+ UINT16 oldpc, pc, dp;
+
+ int carry, zero;
+
+ struct { int t2ms, t512ms; int count;} timer;
+} SC61860_Regs;
+
+static int sc61860_ICount = 0;
+
+static SC61860_Regs sc61860;
+
+UINT8 *sc61860_internal_ram(void) { return sc61860.ram; }
+
+static TIMER_CALLBACK(sc61860_2ms_tick)
+{
+ if (--sc61860.timer.count == 0)
+ {
+ sc61860.timer.count = 128;
+ sc61860.timer.t512ms = !sc61860.timer.t512ms;
+ }
+ sc61860.timer.t2ms = !sc61860.timer.t2ms;
+}
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+#include "scops.c"
+#include "sctable.c"
+
+static void sc61860_reset(void)
+{
+ sc61860.timer.t2ms=0;
+ sc61860.timer.t512ms=0;
+ sc61860.timer.count=256;
+ sc61860.pc=0;
+ change_pc(sc61860.pc);
+}
+
+static void sc61860_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ sc61860.config = (SC61860_CONFIG *) config;
+ timer_pulse(ATTOTIME_IN_HZ(500), 0, sc61860_2ms_tick);
+}
+
+static void sc61860_get_context (void *dst)
+{
+ if( dst )
+ *(SC61860_Regs*)dst = sc61860;
+}
+
+static void sc61860_set_context (void *src)
+{
+ if( src )
+ {
+ sc61860 = *(SC61860_Regs*)src;
+ change_pc(sc61860.pc);
+ }
+}
+
+static int sc61860_execute(int cycles)
+{
+ sc61860_ICount = cycles;
+
+ change_pc(sc61860.pc);
+
+ do
+ {
+ sc61860.oldpc = sc61860.pc;
+
+ CALL_MAME_DEBUG;
+
+ sc61860_instruction();
+
+ /* Are we in HLT-mode? */
+ /*if (sc61860.c & 4)
+ {
+ if ((sc61860.config && sc61860.config->ina && (sc61860.config->ina()!=0)) || sc61860.timer.t512ms)
+ {
+ sc61860.c&=0xfb;
+ if (sc61860.config->outc) sc61860.config->outc(sc61860.c);
+ }
+ sc61860_ICount-=4;
+ }
+ else if(sc61860.c & 8) {}
+
+ else sc61860_instruction();*/
+
+ } while (sc61860_ICount > 0);
+
+ return cycles - sc61860_ICount;
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void sc61860_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SC61860_PC: sc61860.pc = info->i; change_pc(sc61860.pc); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + SC61860_R: sc61860.r = info->i & 0x7F; break;
+ case CPUINFO_INT_REGISTER + SC61860_DP: sc61860.dp = info->i; break;
+ case CPUINFO_INT_REGISTER + SC61860_P: sc61860.p = info->i & 0x7F; break;
+ case CPUINFO_INT_REGISTER + SC61860_Q: sc61860.q = info->i & 0x7F; break;
+ case CPUINFO_INT_REGISTER + SC61860_CARRY: sc61860.carry = info->i; break;
+ case CPUINFO_INT_REGISTER + SC61860_ZERO: sc61860.zero = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void sc61860_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(sc61860); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 4; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = sc61860.oldpc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SC61860_PC: info->i = sc61860.pc; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + SC61860_R: info->i = sc61860.r; break;
+ case CPUINFO_INT_REGISTER + SC61860_DP: info->i = sc61860.dp; break;
+ case CPUINFO_INT_REGISTER + SC61860_P: info->i = sc61860.p; break;
+ case CPUINFO_INT_REGISTER + SC61860_Q: info->i = sc61860.q; break;
+ case CPUINFO_INT_REGISTER + SC61860_CARRY: info->i = sc61860.carry; break;
+ case CPUINFO_INT_REGISTER + SC61860_ZERO: info->i = sc61860.zero; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = sc61860_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = sc61860_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = sc61860_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = sc61860_init; break;
+ case CPUINFO_PTR_RESET: info->reset = sc61860_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = sc61860_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = sc61860_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &sc61860_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "SC61860"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "SC61860"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0beta"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "Copyright (c) 2000,2001 Peter Trauner, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s = cpuintrf_temp_str(), "%c%c", sc61860.zero?'Z':'.', sc61860.carry ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + SC61860_PC: sprintf(info->s = cpuintrf_temp_str(), "PC:%.4x", sc61860.pc);break;
+ case CPUINFO_STR_REGISTER + SC61860_DP: sprintf(info->s = cpuintrf_temp_str(), "DP:%.4x", sc61860.dp);break;
+ case CPUINFO_STR_REGISTER + SC61860_P: sprintf(info->s = cpuintrf_temp_str(), "P:%.2x", sc61860.p);break;
+ case CPUINFO_STR_REGISTER + SC61860_Q: sprintf(info->s = cpuintrf_temp_str(), "Q:%.2x", sc61860.q);break;
+ case CPUINFO_STR_REGISTER + SC61860_R: sprintf(info->s = cpuintrf_temp_str(), "R:%.2x", sc61860.r);break;
+ case CPUINFO_STR_REGISTER + SC61860_I: sprintf(info->s = cpuintrf_temp_str(), "I:%.2x", sc61860.ram[I]);break;
+ case CPUINFO_STR_REGISTER + SC61860_J: sprintf(info->s = cpuintrf_temp_str(), "J:%.2x", sc61860.ram[J]);break;
+ case CPUINFO_STR_REGISTER + SC61860_K: sprintf(info->s = cpuintrf_temp_str(), "K:%.2x", sc61860.ram[K]);break;
+ case CPUINFO_STR_REGISTER + SC61860_L: sprintf(info->s = cpuintrf_temp_str(), "L:%.2x", sc61860.ram[L]);break;
+ case CPUINFO_STR_REGISTER + SC61860_V: sprintf(info->s = cpuintrf_temp_str(), "V:%.2x", sc61860.ram[V]);break;
+ case CPUINFO_STR_REGISTER + SC61860_W: sprintf(info->s = cpuintrf_temp_str(), "W:%.2x", sc61860.ram[W]);break;
+ case CPUINFO_STR_REGISTER + SC61860_H: sprintf(info->s = cpuintrf_temp_str(), "W:%.2x", sc61860.h);break;
+ case CPUINFO_STR_REGISTER + SC61860_BA: sprintf(info->s = cpuintrf_temp_str(), "BA:%.2x%.2x", sc61860.ram[B], sc61860.ram[A]);break;
+ case CPUINFO_STR_REGISTER + SC61860_X: sprintf(info->s = cpuintrf_temp_str(), "X: %.2x%.2x", sc61860.ram[XH], sc61860.ram[XL]);break;
+ case CPUINFO_STR_REGISTER + SC61860_Y: sprintf(info->s = cpuintrf_temp_str(), "Y: %.2x%.2x", sc61860.ram[YH], sc61860.ram[YL]);break;
+ case CPUINFO_STR_REGISTER + SC61860_CARRY: sprintf(info->s = cpuintrf_temp_str(), "Carry: %d", sc61860.carry);break;
+ case CPUINFO_STR_REGISTER + SC61860_ZERO: sprintf(info->s = cpuintrf_temp_str(), "Zero: %d", sc61860.zero);break;
+ }
+}
diff --git a/src/emu/cpu/sc61860/sc61860.h b/src/emu/cpu/sc61860/sc61860.h
new file mode 100644
index 00000000000..2da8cb00648
--- /dev/null
+++ b/src/emu/cpu/sc61860/sc61860.h
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ *
+ * sc61860.h
+ * portable sharp 61860 emulator interface
+ * (sharp pocket computers)
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+#ifndef _SC61860_H
+#define _SC61860_H
+
+/*
+ official names seam to be
+ ESR-H, ESR-J
+ (ESR-L SC62015 ist complete different)
+ */
+
+/* unsolved problems
+ the processor has 8 kbyte internal rom
+ only readable with special instructions and program execution
+ 64 kb external ram (first 8kbyte not seen for program execution?) */
+
+#include "cpuintrf.h"
+
+typedef struct {
+ int (*reset)(void);
+ int (*brk)(void);
+ int (*x)(void);
+ int (*ina)(void);
+ void (*outa)(int);
+ int (*inb)(void);
+ void (*outb)(int);
+ void (*outc)(int);
+} SC61860_CONFIG;
+
+#ifdef MAME_DEBUG
+unsigned sc61860_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+/* this is though for power on/off of the sharps */
+UINT8 *sc61860_internal_ram(void);
+
+void sc61860_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/sc61860/scdasm.c b/src/emu/cpu/sc61860/scdasm.c
new file mode 100644
index 00000000000..5111ddcf56f
--- /dev/null
+++ b/src/emu/cpu/sc61860/scdasm.c
@@ -0,0 +1,220 @@
+/*****************************************************************************
+ *
+ * scdasm.c
+ * portable sharp 61860 emulator interface
+ * (sharp pocket computers)
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+
+#include "sc61860.h"
+#include "sc.h"
+
+/*
+ new:
+ clra 0x23
+ nopt 0x33
+ nopt 0x68
+ nopt 0x6a
+ rz n 0x72, 0x73, 0x76, 0x77
+ tsma 0xc6
+ nopw 0xcd
+ nopw 0xd3
+ sz n 0xd7
+ nopw 0xda
+
+! writ 211 nopw?
+*/
+
+/* explanations for the sharp mnemonics
+ d data: external memory
+ m memory: internal memory (address in p register)
+ p register (internal memory adress)
+ q register (internal memory adress), internally used in several opcodes!?
+ r stack pointer (internal memory)
+ c carry flag
+ z zero flag
+
+ the following are special internal memory registers
+ a akkumulator: (2)
+ b b register: (3)
+ i,j,k,l,v,w counter
+ x external memory address
+ y external memory address
+ ia input/output (92)
+ ib input/output (93)
+ f0 output (94)
+ c output(95)
+
+ li load immediate
+ ld load accu
+ st store accu
+ or
+ an and
+ inc
+ dec
+ ad add
+ sb sub
+ cp compare
+ jr jump relativ
+ jp jump absolut
+ mv move
+ ex exchange
+*/
+
+
+typedef enum {
+ Ill,
+ Imp,
+ Imm, ImmW,
+ RelP, RelM,
+ Abs,
+ Ptc,
+ Etc,
+ Cal,
+ Lp
+} Adr;
+
+static const struct { const char *mnemonic; Adr adr; } table[]={
+ { "LII", Imm }, { "LIJ", Imm }, { "LIA", Imm }, { "LIB", Imm },
+ { "IX", Imp }, { "DX", Imp }, { "IY", Imp }, { "DY", Imp },
+ { "MVW", Imp }, { "EXW", Imp }, { "MVB", Imp }, { "EXB", Imp },
+ { "ADN", Imp }, { "SBN", Imp }, { "ADW", Imp }, { "SBW", Imp },
+
+ { "LIDP", ImmW}, { "LIDL", Imm }, { "LIP", Imm }, { "LIQ", Imm },
+ { "ADB", Imp }, { "SBB", Imp }, { "LIDP", ImmW}, { "LIDL", Imm },
+ { "MVWD", Imp }, { "EXWD", Imp }, { "MVBD", Imp }, { "EXBD", Imp },
+ { "SRW", Imp }, { "SLW", Imp }, { "FILM", Imp }, { "FILD", Imp },
+
+ { "LDP", Imp }, { "LPQ", Imp }, { "LPR", Imp }, { 0, Ill },
+ { "IXL", Imp }, { "DXL", Imp }, { "IYS", Imp }, { "DYS", Imp },
+ { "JRNZP", RelP}, { "JRNZM", RelM}, { "JRNCP", RelP}, { "JRNCM", RelM},
+ { "JRP", RelP}, { "JRM", RelM}, { 0, Ill }, { "LOOP", RelM},
+
+ { "STP", Imp }, { "STQ", Imp }, { "STR", Imp }, { 0, Ill },
+ { "PUSH", Imp }, { "DATA", Imp }, { 0, Ill }, { "RTN", Imp },
+ { "JRZP", RelP}, { "JRZM", RelM}, { "JRCP", RelP}, { "JRCM", RelM},
+ { 0, Ill }, { 0, Ill }, { 0, Ill }, { 0, Ill },
+
+ { "INCI", Imp }, { "DECI", Imp }, { "INCA", Imp }, { "DECA", Imp },
+ { "ADM", Imp }, { "SBM", Imp }, { "ANMA", Imp }, { "ORMA", Imp },
+ { "INCK", Imp }, { "DECK", Imp }, { "INCV", Imp }, { "DECV", Imp },
+ { "INA", Imp }, { "NOPW", Imp }, { "WAIT", Imm }, { "IPXL"/*CDN, lxn*/, Imp },
+
+ { "INCP", Imp }, { "DECP", Imp }, { "STD", Imp }, { "MVDM", Imp },
+ { "READM",/*mvmp*/ Imp }, { "MVMD", Imp }, { "READ"/*ldpc*/, Imp }, { "LDD", Imp },
+ { "SWP", Imp }, { "LDM", Imp }, { "SL", Imp }, { "POP", Imp },
+ { 0, Ill }, { "OUTA", Imp }, { 0, Ill }, { "OUTF", Imp },
+
+ { "ANIM", Imm }, { "ORIM", Imm }, { "TSIM", Imm }, { "CPIM", Imm },
+ { "ANIA", Imm }, { "ORIA", Imm }, { "TSIA", Imm }, { "CPIA", Imm },
+ { 0, Ill }, { "ETC", Etc }, { 0, Ill }, { "TEST", Imm },
+ { 0, Ill }, { 0, Ill }, { 0, Ill }, { "IPXH"/*CDN,lxp*/, Imp },
+
+ { "ADIM", Imm }, { "SBIM", Imm }, { 0, Ill }, { 0, Ill },
+ { "ADIA", Imm }, { "SBIA", Imm }, { 0, Ill }, { 0, Ill },
+ { "CALL", Abs }, { "JP", Abs }, { "PTC", Ptc }, { 0, Ill },
+ { "JPNZ", Abs }, { "JPNC", Abs }, { "JPZ", Abs }, { "JPC", Abs },
+
+
+ { "LP", Lp }, { 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 },
+
+ { "INCJ", Imp }, { "DECJ", Imp }, { "INCB", Imp }, { "DECB", Imp },
+ { "ACDM", Imp }, { "SBCM", Imp }, { 0, Ill }, { "CPMA", Imp },
+ { "INCL", Imp }, { "DECL", Imp }, { "INCW", Imp }, { "DECW", Imp },
+ { "INB", Imp }, { 0, Ill }, { "NOPT", Imp }, { 0, Ill },
+
+ { "SC", Imp }, { "RC", Imp }, { "SR", Imp }, { 0, Ill },
+ { "ANID", Imm }, { "ORID", Imm }, { "TSID", Imm }, { 0, Ill },
+ { "LEAVE", Imp }, { 0, Ill }, { "EXAB", Imp }, { "EXAM", Imp },
+ { 0, Ill }, { "OUTB", Imp }, { 0, Ill }, { "OUTC", Imp },
+
+ { "CAL", Imp }, { 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 },
+};
+
+unsigned sc61860_dasm(char *dst, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ const UINT8 *base_oprom = oprom;
+ int oper=*(oprom++);
+ int t;
+ UINT16 adr;
+
+ switch(oper&0xc0) {
+ case 0x80:
+ sprintf(dst,"%-6s%.2x",table[oper&0x80].mnemonic, oper&0x3f);
+ break;
+ default:
+ switch(oper&0xe0) {
+ case 0xe0:
+ sprintf(dst,"%-6s%.4x",table[oper&0xe0].mnemonic,
+ *(oprom++)|((oper&0x1f)<<8));
+ break;
+ default:
+ switch (table[oper].adr) {
+ case Ill: sprintf(dst,"?%.2x",oper);break;
+ case Imp: sprintf(dst,"%s",table[oper].mnemonic); break;
+ case Imm: sprintf(dst,"%-6s%.2x",table[oper].mnemonic, *(oprom++)); break;
+ case ImmW:
+ adr=(oprom[0]<<8)|oprom[1];oprom+=2;
+ sprintf(dst,"%-6s%.4x",table[oper].mnemonic, adr);
+ break;
+ case Abs:
+ adr=(oprom[0]<<8)|oprom[1];oprom+=2;
+ sprintf(dst,"%-6s%.4x",table[oper].mnemonic, adr);
+ break;
+ case RelM:
+ adr=pc-*(oprom++);
+ sprintf(dst,"%-6s%.4x",table[oper].mnemonic, adr&0xffff);
+ break;
+ case RelP:
+ adr=pc+*(oprom++);
+ sprintf(dst,"%-6s%.4x",table[oper].mnemonic, adr&0xffff);
+ break;
+ case Ptc:
+ t=*(oprom++);
+ adr=(oprom[0]<<8)|oprom[1];oprom+=2;
+ sprintf(dst,"%-6s%.2x,%.4x",table[oper].mnemonic,t, adr);
+ break;
+ case Etc:
+ sprintf(dst,"%-6s",table[oper].mnemonic);
+ /*H imm, abs */
+ /* abs */
+ break;
+ case Cal: case Lp: break;
+ }
+ break;
+ }
+ break;
+ }
+ return oprom - base_oprom;
+}
diff --git a/src/emu/cpu/sc61860/scops.c b/src/emu/cpu/sc61860/scops.c
new file mode 100644
index 00000000000..889dd56f6f6
--- /dev/null
+++ b/src/emu/cpu/sc61860/scops.c
@@ -0,0 +1,734 @@
+/*****************************************************************************
+ *
+ * scops.c
+ * portable sharp 61860 emulator interface
+ * (sharp pocket computers)
+ *
+ * Copyright (c) 2000 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * History of changes:
+ * 21.07.2001 Several changes listed below were made by Mario Konegger
+ * (konegger@itp.tu-graz.ac.at)
+ * replaced buggy BCD-commands add_bcd, sub_bcd, add_bcd_a,
+ * sub_bcd_a and changed out_c, to implement HLT-mode of the CPU.
+ *
+ *****************************************************************************/
+
+INLINE UINT8 READ_OP(void)
+{
+ return cpu_readop(sc61860.pc++);
+}
+
+INLINE UINT8 READ_OP_ARG(void)
+{
+ return cpu_readop_arg(sc61860.pc++);
+}
+
+INLINE UINT16 READ_OP_ARG_WORD(void)
+{
+ UINT16 t=cpu_readop(sc61860.pc++)<<8;
+ t|=cpu_readop(sc61860.pc++);
+ return t;
+}
+
+INLINE UINT8 READ_BYTE(UINT16 adr)
+{
+ return program_read_byte(adr);
+}
+
+INLINE void WRITE_BYTE(UINT16 a,UINT8 v)
+{
+ program_write_byte(a,v);
+}
+
+#define PUSH(v) sc61860.ram[--sc61860.r]=v
+#define POP() sc61860.ram[sc61860.r++]
+
+INLINE void sc61860_load_imm(int r, UINT8 v)
+{
+ sc61860.ram[r]=v;
+}
+
+INLINE void sc61860_load(void)
+{
+ sc61860.ram[A]=sc61860.ram[sc61860.p];
+}
+
+INLINE void sc61860_load_imm_p(UINT8 v)
+{
+ sc61860.p=v&0x7f;
+}
+
+INLINE void sc61860_load_imm_q(UINT8 v)
+{
+ sc61860.q=v&0x7f;
+}
+
+INLINE void sc61860_load_r(void)
+{
+ sc61860.r=sc61860.ram[A]&0x7f;
+}
+
+INLINE void sc61860_load_ext(int r)
+{
+ sc61860.ram[r]=READ_BYTE(sc61860.dp);
+}
+
+INLINE void sc61860_load_dp(void)
+{
+ sc61860.dp=READ_OP_ARG_WORD();
+}
+
+INLINE void sc61860_load_dl(void)
+{
+ sc61860.dp=(sc61860.dp&~0xff)|READ_OP_ARG();
+}
+
+INLINE void sc61860_store_p(void)
+{
+ sc61860.ram[A]=sc61860.p;
+}
+
+INLINE void sc61860_store_q(void)
+{
+ sc61860.ram[A]=sc61860.q;
+}
+
+INLINE void sc61860_store_r(void)
+{
+ sc61860.ram[A]=sc61860.r;
+}
+
+INLINE void sc61860_store_ext(int r)
+{
+ WRITE_BYTE(sc61860.dp, sc61860.ram[r]);
+}
+
+INLINE void sc61860_exam(int a, int b)
+{
+ UINT8 t=sc61860.ram[a];
+ sc61860.ram[a]=sc61860.ram[b];
+ sc61860.ram[b]=t;
+}
+
+INLINE void sc61860_test(int reg, UINT8 value)
+{
+ sc61860.zero=(sc61860.ram[reg]&value)==0;
+}
+
+INLINE void sc61860_test_ext(void)
+{
+ sc61860.zero=(READ_BYTE(sc61860.dp)&READ_OP_ARG())==0;
+}
+
+INLINE void sc61860_and(int reg, UINT8 value)
+{
+ sc61860.zero=(sc61860.ram[reg]&=value)==0;
+}
+
+INLINE void sc61860_and_ext(void)
+{
+ UINT8 t=READ_BYTE(sc61860.dp)&READ_OP_ARG();
+ sc61860.zero=t==0;
+ WRITE_BYTE(sc61860.dp,t);
+}
+
+INLINE void sc61860_or(int reg, UINT8 value)
+{
+ sc61860.zero=(sc61860.ram[reg]|=value)==0;
+}
+
+INLINE void sc61860_or_ext(void)
+{
+ UINT8 t=READ_BYTE(sc61860.dp)|READ_OP_ARG();
+ sc61860.zero=t==0;
+ WRITE_BYTE(sc61860.dp,t);
+}
+
+INLINE void sc61860_rotate_right(void)
+{
+ int t=sc61860.ram[A];
+ if (sc61860.carry) t|=0x100;
+ sc61860.carry=t&1;
+ sc61860.ram[A]=t>>1;
+}
+
+INLINE void sc61860_rotate_left(void)
+{
+ int t=sc61860.ram[A]<<1;
+ if (sc61860.carry) t|=1;
+ sc61860.carry=t&0x100;
+ sc61860.ram[A]=t;
+}
+
+INLINE void sc61860_swap(void)
+{
+ int t=sc61860.ram[A];
+ sc61860.ram[A]=(t<<4)|((t>>4)&0xf);
+}
+
+// q=reg sideeffect
+INLINE void sc61860_inc(int reg)
+{
+ sc61860.q=reg;
+ sc61860.ram[reg]++;
+ sc61860.zero=sc61860.carry=sc61860.ram[reg]==0;
+}
+
+INLINE void sc61860_inc_p(void)
+{
+ sc61860.p++;
+}
+
+// q=reg sideeffect
+INLINE void sc61860_dec(int reg)
+{
+ sc61860.q=reg;
+ sc61860.ram[reg]--;
+ sc61860.zero=sc61860.ram[reg]==0;
+ sc61860.carry=sc61860.ram[reg]==0xff;
+}
+
+INLINE void sc61860_dec_p(void)
+{
+ sc61860.p--;
+}
+
+INLINE void sc61860_add(int reg, UINT8 value)
+{
+ int t=sc61860.ram[reg]+value;
+ sc61860.zero=(sc61860.ram[reg]=t)==0;
+ sc61860.carry=t>=0x100;
+}
+
+INLINE void sc61860_add_carry(void)
+{
+ int t=sc61860.ram[sc61860.p]+sc61860.ram[A];
+ if (sc61860.carry) t++;
+ sc61860.zero=(sc61860.ram[sc61860.p]=t)==0;
+ sc61860.carry=t>=0x100;
+}
+
+// p++ sideeffect
+INLINE void sc61860_add_word(void)
+{
+ int t=sc61860.ram[sc61860.p]+sc61860.ram[A],t2;
+ sc61860.ram[sc61860.p]=t;
+ sc61860.p++;
+ t2=sc61860.ram[sc61860.p]+sc61860.ram[B];
+ if (t>=0x100) t2++;
+ sc61860.ram[sc61860.p]=t2;
+ sc61860.zero=(t2&0xff)==0 &&(t&0xff)==0;
+ sc61860.carry=t2>=0x100;
+}
+
+
+INLINE void sc61860_sub(int reg, UINT8 value)
+{
+ int t=sc61860.ram[reg]-value;
+ sc61860.zero=(sc61860.ram[reg]=t)==0;
+ sc61860.carry=t<0;
+}
+
+INLINE void sc61860_sub_carry(void)
+{
+ int t=sc61860.ram[sc61860.p]-sc61860.ram[A];
+ if (sc61860.carry) t--;
+ sc61860.zero=(sc61860.ram[sc61860.p]=t)==0;
+ sc61860.carry=t<0;
+}
+
+
+// p++ sideeffect
+INLINE void sc61860_sub_word(void)
+{
+ int t=sc61860.ram[sc61860.p]-sc61860.ram[A],t2;
+ sc61860.ram[sc61860.p]=t;
+ sc61860.p++;
+ t2=sc61860.ram[sc61860.p]-sc61860.ram[B];
+ if (t<0) t2--;
+ sc61860.ram[sc61860.p]=t2;
+ sc61860.zero=(t2&0xff)==0 && (t&0xff)==0;
+ sc61860.carry=t2<0;
+}
+
+INLINE void sc61860_cmp(int reg, UINT8 value)
+{
+ int t=sc61860.ram[reg]-value;
+ sc61860.zero=t==0;
+ sc61860.carry=t<0;
+}
+
+INLINE void sc61860_pop(void)
+{
+ sc61860.ram[A]=POP();
+}
+
+INLINE void sc61860_push(void)
+{
+ PUSH(sc61860.ram[A]);
+}
+
+INLINE void sc61860_prepare_table_call(void)
+{
+ int adr;
+ sc61860.h=READ_OP();
+ adr=READ_OP_ARG_WORD();
+ PUSH(adr>>8);
+ PUSH(adr&0xff);
+}
+
+INLINE void sc61860_execute_table_call(void)
+{
+ int i, v, adr;
+ for (i=0; i<sc61860.h; i++) {
+ v=READ_OP();
+ adr=READ_OP_ARG_WORD();
+ sc61860.zero=v==sc61860.ram[A];
+ if (sc61860.zero) {
+ sc61860.pc=adr;
+ change_pc(sc61860.pc);
+ return;
+ }
+ }
+ sc61860.pc=READ_OP_ARG_WORD();
+ change_pc(sc61860.pc);
+}
+
+
+INLINE void sc61860_call(UINT16 adr)
+{
+ PUSH(sc61860.pc>>8);
+ PUSH(sc61860.pc&0xff);
+ sc61860.pc=adr;
+ change_pc(sc61860.pc);
+}
+
+INLINE void sc61860_return(void)
+{
+ UINT16 t=POP();
+ t|=POP()<<8;
+ sc61860.pc=t;
+ change_pc(sc61860.pc);
+}
+
+INLINE void sc61860_jump(int yes)
+{
+ UINT16 adr=READ_OP_ARG_WORD();
+ if (yes) {
+ sc61860.pc=adr;
+ change_pc(sc61860.pc);
+ }
+}
+
+INLINE void sc61860_jump_rel_plus(int yes)
+{
+ UINT16 adr=sc61860.pc;
+ adr+=READ_OP_ARG();
+ if (yes) {
+ sc61860.pc=adr;
+ change_pc(sc61860.pc);
+ sc61860_ICount-=3;
+ }
+}
+
+INLINE void sc61860_jump_rel_minus(int yes)
+{
+ UINT16 adr=sc61860.pc;
+ adr-=READ_OP_ARG();
+ if (yes) {
+ sc61860.pc=adr;
+ change_pc(sc61860.pc);
+ sc61860_ICount-=3;
+ }
+}
+
+INLINE void sc61860_loop(void)
+{
+ UINT16 adr=sc61860.pc;
+ adr-=READ_OP_ARG();
+ sc61860.ram[sc61860.r]--;
+ sc61860.zero=sc61860.ram[sc61860.r]==0;
+ sc61860.carry=sc61860.ram[sc61860.r]==0xff;
+ if (!sc61860.carry) {
+ sc61860.pc=adr;
+ adr=POP();
+ change_pc(sc61860.pc);
+ sc61860_ICount-=3;
+ }
+}
+
+INLINE void sc61860_leave(void)
+{
+ sc61860.ram[sc61860.r]=0;
+}
+
+INLINE void sc61860_wait(void)
+{
+ int t=READ_OP();
+ sc61860_ICount-=t;
+ sc61860_ICount-=t;
+ sc61860_ICount-=3;
+}
+
+INLINE void sc61860_set_carry(void)
+{
+ sc61860.carry=1;
+ sc61860.zero=1;
+}
+
+INLINE void sc61860_reset_carry(void)
+{
+ sc61860.carry=0;
+ sc61860.zero=1;
+}
+
+INLINE void sc61860_out_a(void)
+{
+ sc61860.q=IA;
+ if (sc61860.config&&sc61860.config->outa)
+ sc61860.config->outa(sc61860.ram[IA]);
+}
+
+INLINE void sc61860_out_b(void)
+{
+ sc61860.q=IB;
+ if (sc61860.config&&sc61860.config->outb)
+ sc61860.config->outb(sc61860.ram[IB]);
+}
+
+INLINE void sc61860_out_f(void)
+{
+ sc61860.q=F0;
+ /*sc61860.ram[F0]; */
+}
+
+
+/* c0 display on
+ c1 counter reset
+ c2 cpu halt
+ c3 computer off
+ c4 beeper frequency (1 4khz, 0 2khz), or (c5=0) membran pos1/pos2
+ c5 beeper on
+ c6 beeper steuerung*/
+INLINE void sc61860_out_c(void)
+{
+ sc61860.q=C;
+ if (sc61860.config&&sc61860.config->outc)
+ sc61860.config->outc(sc61860.ram[C]);
+ sc61860.c=sc61860.ram[C];
+}
+
+INLINE void sc61860_in_a(void)
+{
+ int data=0;
+ if (sc61860.config&&sc61860.config->ina) data=sc61860.config->ina();
+ sc61860.ram[A]=data;
+ sc61860.zero=data==0;
+}
+
+INLINE void sc61860_in_b(void)
+{
+ int data=0;
+ if (sc61860.config&&sc61860.config->inb) data=sc61860.config->inb();
+ sc61860.ram[A]=data;
+ sc61860.zero=data==0;
+}
+
+/* 0 systemclock 512ms
+ 1 systemclock 2ms
+ 2 ?
+ 3 brk/on key
+ 4 ?
+ 5 ?
+ 6 reset
+ 7 cassette input */
+INLINE void sc61860_test_special(void)
+{
+ int t=0;
+ if (sc61860.timer.t512ms) t|=1;
+ if (sc61860.timer.t2ms) t|=2;
+ if (sc61860.config&&sc61860.config->brk&&sc61860.config->brk()) t|=8;
+ if (sc61860.config&&sc61860.config->reset&&sc61860.config->reset()) t|=0x40;
+ if (sc61860.config&&sc61860.config->x&&sc61860.config->x()) t|=0x80;
+
+ sc61860.zero=(t&READ_OP())==0;
+}
+
+/************************************************************************************
+ "string" operations
+***********************************************************************************/
+
+// p-=I+1 sideeffect
+INLINE void sc61860_add_bcd_a(void)
+{
+ UINT8 help = sc61860.ram[A];
+ int i, hlp, hlp1 = 0; sc61860.zero=1;
+ for ( i=0; i <= sc61860.ram[I]; i++)
+ {
+ hlp1 = (sc61860.ram[sc61860.p] & 0x0f) + (help & 0x0f ) + hlp1;
+ if (hlp1 > 9) { hlp = hlp1 - 0x0a; hlp1 = 0x10; }
+ else {hlp = hlp1; hlp1 = 0x00;}
+ hlp1 = (sc61860.ram[sc61860.p] & 0xf0) + (help & 0xf0) + hlp1;
+ if (hlp1 > 0x90) { sc61860.ram[sc61860.p] = hlp1 - 0xa0 + hlp; hlp1 = 1; }
+ else {sc61860.ram[sc61860.p] = hlp1 + hlp; hlp1 = 0;}
+ if ( sc61860.ram[sc61860.p--] != 0 ) sc61860.zero = 0;
+ help = 0;
+ }
+ sc61860.carry= ( hlp1 ) ? 1 : 0;
+ sc61860_ICount-=3*(sc61860.ram[I]+1);
+}
+
+
+// p-=I+1, q-=I+2 sideeffect
+INLINE void sc61860_add_bcd(void)
+{
+ int i, hlp, hlp1 = 0; sc61860.zero=1;
+ for ( i=0; i <= sc61860.ram[I]; i++)
+ {
+ hlp1 = (sc61860.ram[sc61860.p] & 0x0f) + (sc61860.ram[sc61860.q] & 0x0f ) +
+hlp1;
+ if (hlp1 > 9) { hlp = hlp1 - 0x0a; hlp1 = 0x10; }
+ else {hlp = hlp1; hlp1 = 0x00;}
+ hlp1 = (sc61860.ram[sc61860.p] & 0xf0) + (sc61860.ram[sc61860.q--] & 0xf0) +
+hlp1;
+ if (hlp1 > 0x90) { sc61860.ram[sc61860.p] = hlp1 - 0xa0 + hlp; hlp1 = 1; }
+ else {sc61860.ram[sc61860.p] = hlp1 + hlp; hlp1 = 0;}
+ if ( sc61860.ram[sc61860.p--] != 0 ) sc61860.zero = 0;
+ }
+ sc61860.carry= ( hlp1 ) ? 1 : 0;
+ sc61860_ICount-=3*(sc61860.ram[I]+1);
+ sc61860.q--;
+}
+
+
+// p-=I+1 sideeffect
+INLINE void sc61860_sub_bcd_a(void)
+{
+ UINT8 help = sc61860.ram[A];
+ int i, hlp, hlp1 = 0; sc61860.zero=1;
+ for ( i=0; i <= sc61860.ram[I]; i++)
+ {
+ hlp1 = (sc61860.ram[sc61860.p]&0x0f) - (help&0x0f) - hlp1;
+ if ( hlp1 < 0 ) { hlp = hlp1 + 0x0a; hlp1 = 0x10;}
+ else { hlp = hlp1; hlp1 = 0x00;}
+ hlp1 = (sc61860.ram[sc61860.p]&0xf0) - (help&0xf0) - hlp1;
+ if ( hlp1 < 0 ) { sc61860.ram[sc61860.p] = hlp1 + 0xa0 + hlp; hlp1 = 1;}
+ else {sc61860.ram[sc61860.p] = hlp1 + hlp; hlp1 = 0;}
+ if ( sc61860.ram[sc61860.p--] != 0 ) sc61860.zero = 0;
+ help = 0;
+ }
+ sc61860.carry= ( hlp1 ) ? 1 : 0;
+ sc61860_ICount-=3*(sc61860.ram[I]+1);
+}
+
+
+// p-=I+1, q-=I+2 sideeffect
+INLINE void sc61860_sub_bcd(void)
+{
+ int i, hlp, hlp1 = 0; sc61860.zero=1;
+ for ( i=0; i <= sc61860.ram[I]; i++)
+ {
+ hlp1 = (sc61860.ram[sc61860.p]&0x0f) - (sc61860.ram[sc61860.q]&0x0f) - hlp1;
+ if ( hlp1 < 0 ) { hlp = hlp1 + 0x0a; hlp1 = 0x10;}
+ else { hlp = hlp1; hlp1 = 0x00;}
+ hlp1 = (sc61860.ram[sc61860.p]&0xf0) - (sc61860.ram[sc61860.q--]&0xf0) -
+hlp1;
+ if ( hlp1 < 0 ) { sc61860.ram[sc61860.p] = hlp1 + 0xa0 + hlp; hlp1 = 1;}
+ else {sc61860.ram[sc61860.p] = hlp1 + hlp; hlp1 = 0;}
+ if ( sc61860.ram[sc61860.p--] != 0 ) sc61860.zero = 0;
+ }
+ sc61860.carry= ( hlp1 ) ? 1 : 0;
+ sc61860_ICount-=3*(sc61860.ram[I]+1);
+ sc61860.q--;
+}
+
+/* side effect p-i-1 -> p correct! */
+INLINE void sc61860_shift_left_nibble(void)
+{
+ int i,t=0;
+ for (i=0; i<=sc61860.ram[I]; i++) {
+ t|=sc61860.ram[sc61860.p]<<4;
+ sc61860.ram[sc61860.p--]=t;
+ t>>=8;
+ sc61860_ICount--;
+ }
+}
+
+/* side effect p+i+1 -> p correct! */
+INLINE void sc61860_shift_right_nibble(void)
+{
+ int i,t=0;
+ for (i=0; i<=sc61860.ram[I]; i++) {
+ t|=sc61860.ram[sc61860.p];
+ sc61860.ram[sc61860.p++]=t>>4;
+ t=(t<<8)&0xf00;
+ sc61860_ICount--;
+ }
+}
+
+// q=reg+1 sideeffect
+INLINE void sc61860_inc_load_dp(int reg)
+{
+ if (++sc61860.ram[reg]==0) sc61860.ram[reg+1]++;
+ sc61860.dp=sc61860.ram[reg]|(sc61860.ram[reg+1]<<8);
+ sc61860.q=reg+1;
+}
+
+// q=reg+1 sideeffect
+INLINE void sc61860_dec_load_dp(int reg)
+{
+ if (--sc61860.ram[reg]==0xff) sc61860.ram[reg+1]--;
+ sc61860.dp=sc61860.ram[reg]|(sc61860.ram[reg+1]<<8);
+ sc61860.q=reg+1;
+}
+
+// q=XH sideeffect
+INLINE void sc61860_inc_load_dp_load(void)
+{
+ if (++sc61860.ram[XL]==0) sc61860.ram[XH]++;
+ sc61860.dp=sc61860.ram[XL]|(sc61860.ram[XH]<<8);
+ sc61860.q=XH; // hopefully correct before real read
+ sc61860.ram[A]=READ_BYTE(sc61860.dp);
+}
+
+// q=XH sideeffect
+INLINE void sc61860_dec_load_dp_load(void)
+{
+ if (--sc61860.ram[XL]==0xff) sc61860.ram[XH]--;
+ sc61860.dp=sc61860.ram[XL]|(sc61860.ram[XH]<<8);
+ sc61860.q=XH; // hopefully correct before real read
+ sc61860.ram[A]=READ_BYTE(sc61860.dp);
+}
+
+// q=YH sideeffect
+INLINE void sc61860_inc_load_dp_store(void)
+{
+ if (++sc61860.ram[YL]==0) sc61860.ram[YH]++;
+ sc61860.dp=sc61860.ram[YL]|(sc61860.ram[YH]<<8);
+ sc61860.q=YH; // hopefully correct before real write!
+ WRITE_BYTE(sc61860.dp,sc61860.ram[A]);
+}
+
+// q=YH sideeffect
+INLINE void sc61860_dec_load_dp_store(void)
+{
+ if (--sc61860.ram[YL]==0xff) sc61860.ram[YH]--;
+ sc61860.dp=sc61860.ram[YL]|(sc61860.ram[YH]<<8);
+ sc61860.q=XH; // hopefully correct before real write!
+ WRITE_BYTE(sc61860.dp,sc61860.ram[A]);
+}
+
+INLINE void sc61860_fill(void)
+{
+ int i;
+ for (i=0;i<=sc61860.ram[I];i++) {
+ sc61860.ram[sc61860.p++]=sc61860.ram[A]; /* could be overwritten? */
+ sc61860_ICount--;
+ }
+}
+
+INLINE void sc61860_fill_ext(void)
+{
+ int i;
+ for (i=0;i<=sc61860.ram[I];i++) {
+ WRITE_BYTE(sc61860.dp, sc61860.ram[A]);
+ if (i!=sc61860.ram[I]) sc61860.dp++;
+ sc61860_ICount-=3;
+ }
+}
+
+// p+=count+1, q+=count+1 sideeffects
+INLINE void sc61860_copy(int count)
+{
+ int i;
+ for (i=0; i<=count; i++) {
+ sc61860.ram[sc61860.p++]=sc61860.ram[sc61860.q++];
+ sc61860_ICount-=2;
+ }
+
+}
+
+// p+=count+1, dp+=count sideeffects
+INLINE void sc61860_copy_ext(int count)
+{
+ int i;
+ for (i=0; i<=count; i++) {
+ sc61860.ram[sc61860.p++]=READ_BYTE(sc61860.dp);
+ if (i!=count) sc61860.dp++;
+ sc61860_ICount-=4;
+ }
+}
+
+INLINE void sc61860_copy_int(int count)
+{
+ int i;
+ for (i=0; i<=count; i++) {
+ sc61860.ram[sc61860.p++]=
+ READ_BYTE((sc61860.ram[A]|(sc61860.ram[B]<<8)) ); /* internal rom! */
+ if (i!=count) {
+ if (++sc61860.ram[A]==0) sc61860.ram[B]++;
+ }
+ sc61860_ICount-=4;
+ }
+}
+
+INLINE void sc61860_exchange(int count)
+{
+ int i;
+ UINT8 t;
+ for (i=0; i<=count; i++) {
+ t=sc61860.ram[sc61860.p];
+ sc61860.ram[sc61860.p++]=sc61860.ram[sc61860.q];
+ sc61860.ram[sc61860.q++]=t;
+ sc61860_ICount-=3;
+ }
+}
+
+INLINE void sc61860_exchange_ext(int count)
+{
+ int i;
+ UINT8 t;
+ for (i=0; i<=count; i++) {
+ t=sc61860.ram[sc61860.p];
+ sc61860.ram[sc61860.p++]=READ_BYTE(sc61860.dp);
+ WRITE_BYTE(sc61860.dp, t);
+ if (i!=count) sc61860.dp++;
+ sc61860_ICount-=6;
+ }
+}
+
+// undocumented
+// only 1 opcode working in pc1403
+// both opcodes working in pc1350
+INLINE void sc61860_wait_x(int level)
+{
+ int c;
+ sc61860.zero=level;
+
+ if (sc61860.config&&sc61860.config->x) {
+ for (c=sc61860.ram[I]; c>=0; c--) {
+// sc61860.ram[sc61860.p]=(sc61860.ram[sc61860.p]+1)%0x60;
+ sc61860.ram[sc61860.p]=(sc61860.ram[sc61860.p]+1)&0x7f;
+ sc61860.zero=sc61860.config->x();
+ sc61860_ICount-=4;
+ if ( level != sc61860.zero) break;
+ }
+ }
+}
+
+
+
+
diff --git a/src/emu/cpu/sc61860/sctable.c b/src/emu/cpu/sc61860/sctable.c
new file mode 100644
index 00000000000..38d42bc168c
--- /dev/null
+++ b/src/emu/cpu/sc61860/sctable.c
@@ -0,0 +1,144 @@
+
+static void sc61860_instruction(void)
+{
+ int oper=READ_OP();
+ if ((oper&0xc0)==0x80) {
+ sc61860_load_imm_p(oper&0x3f);sc61860_ICount-=2;
+ } else if ((oper&0xe0)==0xe0) {
+ sc61860_call(READ_OP()|((oper&0x1f)<<8));sc61860_ICount-=7;
+ } else {
+ switch(oper) {
+ case 0: sc61860_load_imm(I, READ_OP());sc61860_ICount-=4;break;
+ case 1: sc61860_load_imm(J, READ_OP());sc61860_ICount-=4;break;
+ case 2: sc61860_load_imm(A, READ_OP());sc61860_ICount-=4;break;
+ case 3: sc61860_load_imm(B, READ_OP());sc61860_ICount-=4;break;
+ case 4: sc61860_inc_load_dp(XL);sc61860_ICount-=6;break;
+ case 5: sc61860_dec_load_dp(XL);sc61860_ICount-=6;break;
+ case 6: sc61860_inc_load_dp(YL);sc61860_ICount-=6;break;
+ case 7: sc61860_dec_load_dp(YL);sc61860_ICount-=6;break;
+ case 8: sc61860_copy(sc61860.ram[I]);break;
+ case 9: sc61860_exchange(sc61860.ram[I]);break;
+ case 10: sc61860_copy(sc61860.ram[J]);break;
+ case 11: sc61860_exchange(sc61860.ram[J]);break;
+ case 12: sc61860_add_bcd_a();sc61860_ICount-=7;break;
+ case 13: sc61860_sub_bcd_a();sc61860_ICount-=7;break;
+ case 14: sc61860_add_bcd();sc61860_ICount-=7;break;
+ case 15: sc61860_sub_bcd();sc61860_ICount-=7;break;
+ case 16: sc61860_load_dp();sc61860_ICount-=8;break;
+ case 17: sc61860_load_dl();sc61860_ICount-=5;break;
+ case 18: sc61860_load_imm_p(READ_OP());sc61860_ICount-=4;break;
+ case 19: sc61860_load_imm_q(READ_OP());sc61860_ICount-=4;break;
+ case 20: sc61860_add_word();sc61860_ICount-=5;break;
+ case 21: sc61860_sub_word();sc61860_ICount-=5;break;
+ case 24: sc61860_copy_ext(sc61860.ram[I]);break;
+ case 25: sc61860_exchange_ext(sc61860.ram[I]);break;
+ case 26: sc61860_copy_ext(sc61860.ram[J]);break;
+ case 27: sc61860_exchange_ext(sc61860.ram[J]);break;
+ case 28: sc61860_shift_right_nibble();sc61860_ICount-=5;break;
+ case 29: sc61860_shift_left_nibble();sc61860_ICount-=5;break;
+ case 30: sc61860_fill();sc61860_ICount-=5;break;
+ case 31: sc61860_fill_ext();sc61860_ICount-=4;break;
+ case 32: sc61860_store_p();sc61860_ICount-=2;break;
+ case 33: sc61860_store_q();sc61860_ICount-=2;break;
+ case 34: sc61860_store_r();sc61860_ICount-=2;break;
+ case 36: sc61860_inc_load_dp_load();sc61860_ICount-=7;break;
+ case 37: sc61860_dec_load_dp_load();sc61860_ICount-=7;break;
+ case 38: sc61860_inc_load_dp_store();sc61860_ICount-=7;break;
+ case 39: sc61860_dec_load_dp_store();sc61860_ICount-=7;break;
+ case 40: sc61860_jump_rel_plus(!sc61860.zero);sc61860_ICount-=4;break;
+ case 41: sc61860_jump_rel_minus(!sc61860.zero);sc61860_ICount-=4;break;
+ case 42: sc61860_jump_rel_plus(!sc61860.carry);sc61860_ICount-=4;break;
+ case 43: sc61860_jump_rel_minus(!sc61860.carry);sc61860_ICount-=4;break;
+ case 44: sc61860_jump_rel_plus(TRUE);sc61860_ICount-=4;break;
+ case 45: sc61860_jump_rel_minus(TRUE);sc61860_ICount-=4;break;
+ case 47: sc61860_loop();sc61860_ICount-=7;break;
+ case 48: sc61860_load_imm_p(sc61860.ram[A]);sc61860_ICount-=2;break;
+ case 49: sc61860_load_imm_q(sc61860.ram[A]);sc61860_ICount-=2;break;
+ case 50: sc61860_load_r();sc61860_ICount-=2;break;
+ case 52: sc61860_push();sc61860_ICount-=3;break;
+ case 53: sc61860_copy_int(sc61860.ram[I]);break;
+ case 55: sc61860_return();sc61860_ICount-=4;break;
+ case 56: sc61860_jump_rel_plus(sc61860.zero);sc61860_ICount-=4;break;
+ case 57: sc61860_jump_rel_minus(sc61860.zero);sc61860_ICount-=4;break;
+ case 58: sc61860_jump_rel_plus(sc61860.carry);sc61860_ICount-=4;break;
+ case 59: sc61860_jump_rel_minus(sc61860.carry);sc61860_ICount-=4;break;
+ case 64: sc61860_inc(I);sc61860_ICount-=4;break;
+ case 65: sc61860_dec(I);sc61860_ICount-=4;break;
+ case 66: sc61860_inc(A);sc61860_ICount-=4;break;
+ case 67: sc61860_dec(A);sc61860_ICount-=4;break;
+ case 68: sc61860_add(sc61860.p,sc61860.ram[A]);sc61860_ICount-=3;break;
+ case 69: sc61860_sub(sc61860.p,sc61860.ram[A]);sc61860_ICount-=3;break;
+ case 70: sc61860_and(sc61860.p,sc61860.ram[A]);sc61860_ICount-=3;break;
+ case 71: sc61860_or(sc61860.p,sc61860.ram[A]);sc61860_ICount-=3;break;
+ case 72: sc61860_inc(K);sc61860_ICount-=4;break;
+ case 73: sc61860_dec(K);sc61860_ICount-=4;break;
+ case 74: sc61860_inc(V);sc61860_ICount-=4;break;
+ case 75: sc61860_dec(V);sc61860_ICount-=4;break;
+ case 76: sc61860_in_a();sc61860_ICount-=2;break;
+ case 77: /*nopw*/;sc61860_ICount-=2;break;
+ case 78: sc61860_wait();sc61860_ICount-=6;break;
+ case 79: sc61860_wait_x(FALSE);sc61860_ICount-=1;break;
+ case 80: sc61860_inc_p();sc61860_ICount-=2;break;
+ case 81: sc61860_dec_p();sc61860_ICount-=2;break;
+ case 82: sc61860_store_ext(A);sc61860_ICount-=2;break;
+ case 83: sc61860_store_ext(sc61860.p);sc61860_ICount-=2;break;
+ case 84: sc61860_load_imm(sc61860.p, READ_OP());sc61860_ICount-=3/*?*/;break; // undocumented
+ case 85: sc61860_load_ext(sc61860.p);sc61860_ICount-=3;break;
+ case 86: sc61860_load_imm(sc61860.p, READ_OP());sc61860_ICount-=3/*?*/;break; // undocumented
+ case 87: sc61860_load_ext(A);sc61860_ICount-=3;break;
+ case 88: sc61860_swap();sc61860_ICount-=2;break;
+ case 89: sc61860_load();sc61860_ICount-=2;break;
+ case 90: sc61860_rotate_left();sc61860_ICount-=2;break;
+ case 91: sc61860_pop();sc61860_ICount-=2;break;
+ case 93: sc61860_out_a();sc61860_ICount-=3;break;
+ case 95: sc61860_out_f();sc61860_ICount-=3;break;
+ case 96: sc61860_and(sc61860.p,READ_OP());sc61860_ICount-=4;break;
+ case 97: sc61860_or(sc61860.p,READ_OP());sc61860_ICount-=4;break;
+ case 98: sc61860_test(sc61860.p,READ_OP());sc61860_ICount-=4;break;
+ case 99: sc61860_cmp(sc61860.p,READ_OP());sc61860_ICount-=4;break;
+ case 100: sc61860_and(A,READ_OP());sc61860_ICount-=4;break;
+ case 101: sc61860_or(A,READ_OP());sc61860_ICount-=4;break;
+ case 102: sc61860_test(A,READ_OP());sc61860_ICount-=4;break;
+ case 103: sc61860_cmp(A,READ_OP());sc61860_ICount-=4;break;
+ case 105: sc61860_execute_table_call();sc61860_ICount-=3;break;
+ case 107: sc61860_test_special();sc61860_ICount-=4;break;
+ case 111: sc61860_wait_x(TRUE);sc61860_ICount-=1;break;
+ case 112: sc61860_add(sc61860.p,READ_OP());sc61860_ICount-=4;break;
+ case 113: sc61860_sub(sc61860.p,READ_OP());sc61860_ICount-=4;break;
+ case 116: sc61860_add(A,READ_OP());sc61860_ICount-=4;break;
+ case 117: sc61860_sub(A,READ_OP());sc61860_ICount-=4;break;
+ case 120: sc61860_call(READ_OP_ARG_WORD());sc61860_ICount-=8;break;
+ case 121: sc61860_jump(1);sc61860_ICount-=6;break;
+ case 122: sc61860_prepare_table_call();sc61860_ICount-=9;break;
+ case 124: sc61860_jump(!sc61860.zero);sc61860_ICount-=6;break;
+ case 125: sc61860_jump(!sc61860.carry);sc61860_ICount-=6;break;
+ case 126: sc61860_jump(sc61860.zero);sc61860_ICount-=6;break;
+ case 127: sc61860_jump(sc61860.carry);sc61860_ICount-=6;break;
+ case 192: sc61860_inc(J);sc61860_ICount-=4;break;
+ case 193: sc61860_dec(J);sc61860_ICount-=4;break;
+ case 194: sc61860_inc(B);sc61860_ICount-=4;break;
+ case 195: sc61860_dec(B);sc61860_ICount-=4;break;
+ case 196: sc61860_add_carry();sc61860_ICount-=3;break;
+ case 197: sc61860_sub_carry();sc61860_ICount-=3;break;
+ case 199: sc61860_cmp(sc61860.p,sc61860.ram[A]);sc61860_ICount-=3;break;
+ case 200: sc61860_inc(L);sc61860_ICount-=4;break;
+ case 201: sc61860_dec(L);sc61860_ICount-=4;break;
+ case 202: sc61860_inc(W);sc61860_ICount-=4;break;
+ case 203: sc61860_dec(W);sc61860_ICount-=4;break;
+ case 204: sc61860_in_b();sc61860_ICount-=2;break;
+ case 206: /*nopt*/;sc61860_ICount-=3;break;
+ case 208: sc61860_set_carry();sc61860_ICount-=2;break;
+ case 209: sc61860_reset_carry();sc61860_ICount-=4;break;
+ case 210: sc61860_rotate_right();sc61860_ICount-=2;break;
+ case 212: sc61860_and_ext();sc61860_ICount-=6;break;
+ case 213: sc61860_or_ext();sc61860_ICount-=6;break;
+ case 214: sc61860_test_ext();sc61860_ICount-=6;break;
+ case 216: sc61860_leave();sc61860_ICount-=2;break;
+ case 218: sc61860_exam(A, B);sc61860_ICount-=3;break;
+ case 219: sc61860_exam(A, sc61860.p);sc61860_ICount-=3;break;
+ case 221: sc61860_out_b();sc61860_ICount-=2;break;
+ case 223: sc61860_out_c();sc61860_ICount-=2;break;
+ default: logerror("sc61860 illegal opcode at %.4x %.2x\n",sc61860.pc-1, oper);
+ }
+ }
+}
diff --git a/src/emu/cpu/se3208/se3208.c b/src/emu/cpu/se3208/se3208.c
new file mode 100644
index 00000000000..684c6150e48
--- /dev/null
+++ b/src/emu/cpu/se3208/se3208.c
@@ -0,0 +1,1952 @@
+#include "debugger.h"
+#include "se3208.h"
+
+/*
+ SE3208 CPU Emulator by ElSemi
+
+ For information about this CPU:
+ www.adc.co.kr
+
+*/
+
+typedef struct
+{
+ //GPR
+ UINT32 R[8];
+ //SPR
+ UINT32 PC;
+ UINT32 SR;
+ UINT32 SP;
+ UINT32 ER;
+ UINT32 PPC;
+
+ int (*irq_callback)(int irqline);
+ UINT8 IRQ;
+ UINT8 NMI;
+} _SE3208Context;
+
+#define FLAG_C 0x0080
+#define FLAG_V 0x0010
+#define FLAG_S 0x0020
+#define FLAG_Z 0x0040
+
+#define FLAG_M 0x0200
+#define FLAG_E 0x0800
+#define FLAG_AUT 0x1000
+#define FLAG_ENI 0x2000
+#define FLAG_NMI 0x4000
+
+static _SE3208Context Context;
+static int SE3208_ICount;
+
+#define CLRFLAG(f) Context.SR&=~(f);
+#define SETFLAG(f) Context.SR|=(f);
+#define TESTFLAG(f) (Context.SR&(f))
+
+#define EXTRACT(val,sbit,ebit) (((val)>>sbit)&((1<<((ebit-sbit)+1))-1))
+#define SEX8(val) ((val&0x80)?(val|0xFFFFFF00):(val&0xFF))
+#define SEX16(val) ((val&0x8000)?(val|0xFFFF0000):(val&0xFFFF))
+#define ZEX8(val) ((val)&0xFF)
+#define ZEX16(val) ((val)&0xFFFF)
+#define SEX(bits,val) ((val)&(1<<(bits-1))?((val)|(~((1<<bits)-1))):(val&((1<<bits)-1)))
+
+//Precompute the instruction decoding in a big table
+typedef void (*_OP)(UINT16 Opcode);
+#define INST(a) static void a(UINT16 Opcode)
+static _OP *OpTable=NULL;
+
+INLINE UINT32 read_dword_unaligned(UINT32 address)
+{
+ if (address & 3)
+ return program_read_byte_32le(address) | program_read_byte_32le(address+1)<<8 | program_read_byte_32le(address+2)<<16 | program_read_byte_32le(address+3)<<24;
+ else
+ return program_read_dword_32le(address);
+}
+
+INLINE UINT16 read_word_unaligned(UINT32 address)
+{
+ if (address & 1)
+ return program_read_byte_32le(address) | program_read_byte_32le(address+1)<<8;
+ else
+ return program_read_word_32le(address);
+}
+
+INLINE void write_dword_unaligned(UINT32 address, UINT32 data)
+{
+ if (address & 3)
+ {
+ program_write_byte_32le(address, data & 0xff);
+ program_write_byte_32le(address+1, (data>>8)&0xff);
+ program_write_byte_32le(address+2, (data>>16)&0xff);
+ program_write_byte_32le(address+3, (data>>24)&0xff);
+ }
+ else
+ {
+ program_write_dword_32le(address, data);
+ }
+}
+
+INLINE void write_word_unaligned(UINT32 address, UINT16 data)
+{
+ if (address & 1)
+ {
+ program_write_byte_32le(address, data & 0xff);
+ program_write_byte_32le(address+1, (data>>8)&0xff);
+ }
+ else
+ {
+ program_write_word_32le(address, data);
+ }
+}
+
+
+INLINE UINT8 SE3208_Read8(UINT32 addr)
+{
+ return program_read_byte_32le(addr);
+}
+
+INLINE UINT16 SE3208_Read16(UINT32 addr)
+{
+ return read_word_unaligned(addr);
+}
+
+INLINE UINT32 SE3208_Read32(UINT32 addr)
+{
+ return read_dword_unaligned(addr);
+}
+
+INLINE void SE3208_Write8(UINT32 addr,UINT8 val)
+{
+ program_write_byte_32le(addr,val);
+}
+
+INLINE void SE3208_Write16(UINT32 addr,UINT16 val)
+{
+ write_word_unaligned(addr,val);
+}
+
+INLINE void SE3208_Write32(UINT32 addr,UINT32 val)
+{
+ write_dword_unaligned(addr,val);
+}
+
+
+
+INLINE UINT32 AddWithFlags(UINT32 a,UINT32 b)
+{
+ UINT32 r=a+b;
+ CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S);
+ if(!r)
+ SETFLAG(FLAG_Z);
+ if(r&0x80000000)
+ SETFLAG(FLAG_S);
+ if(((((a&b)|(~r&(a|b)))>>31))&1)
+ SETFLAG(FLAG_C);
+ if(((((a^r)&(b^r))>>31))&1)
+ SETFLAG(FLAG_V);
+ return r;
+}
+
+INLINE UINT32 SubWithFlags(UINT32 a,UINT32 b) //a-b
+{
+ UINT32 r=a-b;
+ CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S);
+ if(!r)
+ SETFLAG(FLAG_Z);
+ if(r&0x80000000)
+ SETFLAG(FLAG_S);
+ if((((b&r)|(~a&(b|r)))>>31)&1)
+ SETFLAG(FLAG_C);
+ if((((b^a)&(r^a))>>31)&1)
+ SETFLAG(FLAG_V);
+ return r;
+}
+
+INLINE UINT32 AdcWithFlags(UINT32 a,UINT32 b)
+{
+ UINT32 C=(Context.SR&FLAG_C)?1:0;
+ UINT32 r=a+b+C;
+ CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S);
+ if(!r)
+ SETFLAG(FLAG_Z);
+ if(r&0x80000000)
+ SETFLAG(FLAG_S);
+ if(((((a&b)|(~r&(a|b)))>>31))&1)
+ SETFLAG(FLAG_C);
+ if(((((a^r)&(b^r))>>31))&1)
+ SETFLAG(FLAG_V);
+ return r;
+
+}
+
+INLINE UINT32 SbcWithFlags(UINT32 a,UINT32 b)
+{
+ UINT32 C=(Context.SR&FLAG_C)?1:0;
+ UINT32 r=a-b-C;
+ CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S);
+ if(!r)
+ SETFLAG(FLAG_Z);
+ if(r&0x80000000)
+ SETFLAG(FLAG_S);
+ if((((b&r)|(~a&(b|r)))>>31)&1)
+ SETFLAG(FLAG_C);
+ if((((b^a)&(r^a))>>31)&1)
+ SETFLAG(FLAG_V);
+ return r;
+}
+
+INLINE UINT32 MulWithFlags(UINT32 a,UINT32 b)
+{
+ INT64 r=(INT64) a*(INT64) b;
+ CLRFLAG(FLAG_V);
+ if(r>>32)
+ SETFLAG(FLAG_V);
+ return (UINT32) (r&0xffffffff);
+}
+
+INLINE UINT32 NegWithFlags(UINT32 a)
+{
+ return SubWithFlags(0,a);
+}
+
+INLINE UINT32 AsrWithFlags(UINT32 Val, UINT8 By)
+{
+ signed int v=(signed int) Val;
+ v>>=By;
+ CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S);
+ if(!v)
+ SETFLAG(FLAG_Z);
+ if(v&0x80000000)
+ SETFLAG(FLAG_S);
+ if(Val&(1<<(By-1)))
+ SETFLAG(FLAG_C);
+ return (UINT32) v;
+}
+
+INLINE UINT32 LsrWithFlags(UINT32 Val, UINT8 By)
+{
+ UINT32 v=Val;
+ v>>=By;
+ CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S);
+ if(!v)
+ SETFLAG(FLAG_Z);
+ if(v&0x80000000)
+ SETFLAG(FLAG_S);
+ if(Val&(1<<(By-1)))
+ SETFLAG(FLAG_C);
+ return v;
+}
+
+INLINE UINT32 AslWithFlags(UINT32 Val, UINT8 By)
+{
+ UINT32 v=Val;
+ v<<=By;
+ CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S);
+ if(!v)
+ SETFLAG(FLAG_Z);
+ if(v&0x80000000)
+ SETFLAG(FLAG_S);
+ if(Val&(1<<(32-By)))
+ SETFLAG(FLAG_C);
+ return v;
+}
+
+
+INST(INVALIDOP)
+{
+ //assert(false);
+}
+
+INST(LDB)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+ UINT32 Val;
+
+ if(Index)
+ Index=Context.R[Index];
+ else
+ Index=0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Val=SE3208_Read8(Index+Offset);
+ Context.R[SrcDst]=SEX8(Val);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(STB)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ if(Index)
+ Index=Context.R[Index];
+ else
+ Index=0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ SE3208_Write8(Index+Offset,ZEX8(Context.R[SrcDst]));
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LDS)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+ UINT32 Val;
+
+ Offset<<=1;
+
+ if(Index)
+ Index=Context.R[Index];
+ else
+ Index=0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Val=SE3208_Read16(Index+Offset);
+ Context.R[SrcDst]=SEX16(Val);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(STS)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=1;
+
+ if(Index)
+ Index=Context.R[Index];
+ else
+ Index=0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ SE3208_Write16(Index+Offset,ZEX16(Context.R[SrcDst]));
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LD)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=2;
+
+ if(Index)
+ Index=Context.R[Index];
+ else
+ Index=0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Context.R[SrcDst]=SE3208_Read32(Index+Offset);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(ST)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=2;
+
+ if(Index)
+ Index=Context.R[Index];
+ else
+ Index=0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ SE3208_Write32(Index+Offset,Context.R[SrcDst]);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LDBU)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+ UINT32 Val;
+
+ if(Index)
+ Index=Context.R[Index];
+ else
+ Index=0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Val=SE3208_Read8(Index+Offset);
+ Context.R[SrcDst]=ZEX8(Val);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LDSU)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+ UINT32 Val;
+
+ Offset<<=1;
+
+ if(Index)
+ Index=Context.R[Index];
+ else
+ Index=0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Val=SE3208_Read16(Index+Offset);
+ Context.R[SrcDst]=ZEX16(Val);
+
+ CLRFLAG(FLAG_E);
+}
+
+
+INST(LERI)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,13);
+ if(TESTFLAG(FLAG_E))
+ Context.ER=(EXTRACT(Context.ER,0,17)<<14)|Imm;
+ else
+ Context.ER=SEX(14,Imm);
+
+
+ SETFLAG(FLAG_E);
+}
+
+INST(LDSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Index=Context.SP;
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Context.R[SrcDst]=SE3208_Read32(Index+Offset);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(STSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Index=Context.SP;
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ SE3208_Write32(Index+Offset,Context.R[SrcDst]);
+
+ CLRFLAG(FLAG_E);
+}
+
+static void PushVal(UINT32 Val)
+{
+ Context.SP-=4;
+ SE3208_Write32(Context.SP,Val);
+}
+
+static UINT32 PopVal(void)
+{
+ UINT32 Val=SE3208_Read32(Context.SP);
+ Context.SP+=4;
+ return Val;
+}
+
+INST(PUSH)
+{
+ UINT32 Set=EXTRACT(Opcode,0,10);
+ if(Set&(1<<10))
+ PushVal(Context.PC);
+ if(Set&(1<<9))
+ PushVal(Context.SR);
+ if(Set&(1<<8))
+ PushVal(Context.ER);
+ if(Set&(1<<7))
+ PushVal(Context.R[7]);
+ if(Set&(1<<6))
+ PushVal(Context.R[6]);
+ if(Set&(1<<5))
+ PushVal(Context.R[5]);
+ if(Set&(1<<4))
+ PushVal(Context.R[4]);
+ if(Set&(1<<3))
+ PushVal(Context.R[3]);
+ if(Set&(1<<2))
+ PushVal(Context.R[2]);
+ if(Set&(1<<1))
+ PushVal(Context.R[1]);
+ if(Set&(1<<0))
+ PushVal(Context.R[0]);
+}
+
+INST(POP)
+{
+ UINT32 Set=EXTRACT(Opcode,0,10);
+ if(Set&(1<<0))
+ Context.R[0]=PopVal();
+ if(Set&(1<<1))
+ Context.R[1]=PopVal();
+ if(Set&(1<<2))
+ Context.R[2]=PopVal();
+ if(Set&(1<<3))
+ Context.R[3]=PopVal();
+ if(Set&(1<<4))
+ Context.R[4]=PopVal();
+ if(Set&(1<<5))
+ Context.R[5]=PopVal();
+ if(Set&(1<<6))
+ Context.R[6]=PopVal();
+ if(Set&(1<<7))
+ Context.R[7]=PopVal();
+ if(Set&(1<<8))
+ Context.ER=PopVal();
+ if(Set&(1<<9))
+ Context.SR=PopVal();
+ if(Set&(1<<10))
+ {
+ Context.PC=PopVal()-2; //PC automatically incresases by 2
+ change_pc(Context.PC+2);
+ }
+}
+
+INST(LEATOSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,9,12);
+ UINT32 Index=EXTRACT(Opcode,3,5);
+
+ if(Index)
+ Index=Context.R[Index];
+ else
+ Index=0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+ else
+ Offset=SEX(4,Offset);
+
+ Context.SP=Index+Offset;
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LEAFROMSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,9,12);
+ UINT32 Index=EXTRACT(Opcode,3,5);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+ else
+ Offset=SEX(4,Offset);
+
+ Context.R[Index]=Context.SP+Offset;
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LEASPTOSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ Offset<<=2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,23)<<8)|(Offset&0xff);
+ else
+ Offset=SEX(10,Offset);
+
+ Context.SP=Context.SP+Offset;
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(MOV)
+{
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,9,11);
+
+ Context.R[Dst]=Context.R[Src];
+}
+
+INST(LDI)
+{
+ UINT32 Dst=EXTRACT(Opcode,8,10);
+ UINT32 Imm=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX8(Imm);
+
+ Context.R[Dst]=Imm;
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LDBSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 Index=Context.SP;
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+ UINT32 Val;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Val=SE3208_Read8(Index+Offset);
+ Context.R[SrcDst]=SEX8(Val);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(STBSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 Index=Context.SP;
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ SE3208_Write8(Index+Offset,ZEX8(Context.R[SrcDst]));
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LDSSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 Index=Context.SP;
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+ UINT32 Val;
+
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Val=SE3208_Read16(Index+Offset);
+ Context.R[SrcDst]=SEX16(Val);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(STSSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 Index=Context.SP;
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ SE3208_Write16(Index+Offset,ZEX16(Context.R[SrcDst]));
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LDBUSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 Index=Context.SP;
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+ UINT32 Val;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Val=SE3208_Read8(Index+Offset);
+ Context.R[SrcDst]=ZEX8(Val);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LDSUSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 Index=Context.SP;
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+ UINT32 Val;
+
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ Val=SE3208_Read16(Index+Offset);
+ Context.R[SrcDst]=ZEX16(Val);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(ADDI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX(4,Imm);
+
+ Context.R[Dst]=AddWithFlags(Context.R[Src],Imm);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(SUBI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX(4,Imm);
+
+ Context.R[Dst]=SubWithFlags(Context.R[Src],Imm);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(ADCI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX(4,Imm);
+
+ Context.R[Dst]=AdcWithFlags(Context.R[Src],Imm);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(SBCI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX(4,Imm);
+
+ Context.R[Dst]=SbcWithFlags(Context.R[Src],Imm);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(ANDI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX(4,Imm);
+
+ Context.R[Dst]=Context.R[Src]&Imm;
+
+ CLRFLAG(FLAG_S|FLAG_Z|FLAG_E);
+ if(!Context.R[Dst])
+ SETFLAG(FLAG_Z);
+ if(Context.R[Dst]&0x80000000)
+ SETFLAG(FLAG_S);
+}
+
+INST(ORI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX(4,Imm);
+
+ Context.R[Dst]=Context.R[Src]|Imm;
+
+ CLRFLAG(FLAG_S|FLAG_Z|FLAG_E);
+ if(!Context.R[Dst])
+ SETFLAG(FLAG_Z);
+ if(Context.R[Dst]&0x80000000)
+ SETFLAG(FLAG_S);
+}
+
+INST(XORI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX(4,Imm);
+
+ Context.R[Dst]=Context.R[Src]^Imm;
+
+ CLRFLAG(FLAG_S|FLAG_Z|FLAG_E);
+ if(!Context.R[Dst])
+ SETFLAG(FLAG_Z);
+ if(Context.R[Dst]&0x80000000)
+ SETFLAG(FLAG_S);
+}
+
+INST(CMPI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX(4,Imm);
+
+ SubWithFlags(Context.R[Src],Imm);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(TSTI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst;
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX(4,Imm);
+
+ Dst=Context.R[Src]&Imm;
+
+ CLRFLAG(FLAG_S|FLAG_Z|FLAG_E);
+ if(!Dst)
+ SETFLAG(FLAG_Z);
+ if(Dst&0x80000000)
+ SETFLAG(FLAG_S);
+}
+
+INST(ADD)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ Context.R[Dst]=AddWithFlags(Context.R[Src1],Context.R[Src2]);
+}
+
+INST(SUB)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ Context.R[Dst]=SubWithFlags(Context.R[Src1],Context.R[Src2]);
+}
+
+INST(ADC)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ Context.R[Dst]=AdcWithFlags(Context.R[Src1],Context.R[Src2]);
+}
+
+INST(SBC)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ Context.R[Dst]=SbcWithFlags(Context.R[Src1],Context.R[Src2]);
+}
+
+INST(AND)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ Context.R[Dst]=Context.R[Src1]&Context.R[Src2];
+
+ CLRFLAG(FLAG_S|FLAG_Z);
+ if(!Context.R[Dst])
+ SETFLAG(FLAG_Z);
+ if(Context.R[Dst]&0x80000000)
+ SETFLAG(FLAG_S);
+}
+
+INST(OR)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ Context.R[Dst]=Context.R[Src1]|Context.R[Src2];
+
+ CLRFLAG(FLAG_S|FLAG_Z);
+ if(!Context.R[Dst])
+ SETFLAG(FLAG_Z);
+ if(Context.R[Dst]&0x80000000)
+ SETFLAG(FLAG_S);
+
+}
+
+INST(XOR)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ Context.R[Dst]=Context.R[Src1]^Context.R[Src2];
+
+ CLRFLAG(FLAG_S|FLAG_Z);
+ if(!Context.R[Dst])
+ SETFLAG(FLAG_Z);
+ if(Context.R[Dst]&0x80000000)
+ SETFLAG(FLAG_S);
+
+}
+
+INST(CMP)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+
+ SubWithFlags(Context.R[Src1],Context.R[Src2]);
+}
+
+INST(TST)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst;
+
+ Dst=Context.R[Src1]&Context.R[Src2];
+
+ CLRFLAG(FLAG_S|FLAG_Z);
+ if(!Dst)
+ SETFLAG(FLAG_Z);
+ if(Dst&0x80000000)
+ SETFLAG(FLAG_S);
+}
+
+INST(MULS)
+{
+ UINT32 Src2=EXTRACT(Opcode,6,8);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ Context.R[Dst]=MulWithFlags(Context.R[Src1],Context.R[Src2]);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(NEG)
+{
+ UINT32 Dst=EXTRACT(Opcode,9,11);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+
+ Context.R[Dst]=NegWithFlags(Context.R[Src]);
+}
+
+INST(CALL)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+ PushVal(Context.PC+2);
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JV)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_V))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+
+}
+
+INST(JNV)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(!TESTFLAG(FLAG_V))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JC)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_C))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JNC)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(!TESTFLAG(FLAG_C))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(!TESTFLAG(FLAG_S))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JM)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_S))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JNZ)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(!TESTFLAG(FLAG_Z))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JZ)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_Z))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JGE)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 S=TESTFLAG(FLAG_S)?1:0;
+ UINT32 V=TESTFLAG(FLAG_V)?1:0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(!(S^V))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JLE)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 S=TESTFLAG(FLAG_S)?1:0;
+ UINT32 V=TESTFLAG(FLAG_V)?1:0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_Z) || (S^V))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+ CLRFLAG(FLAG_E);
+}
+
+INST(JHI)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(!(TESTFLAG(FLAG_Z) || TESTFLAG(FLAG_C)))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JLS)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_Z) || TESTFLAG(FLAG_C))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JGT)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 S=TESTFLAG(FLAG_S)?1:0;
+ UINT32 V=TESTFLAG(FLAG_V)?1:0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(!(TESTFLAG(FLAG_Z) || (S^V)))
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JLT)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 S=TESTFLAG(FLAG_S)?1:0;
+ UINT32 V=TESTFLAG(FLAG_V)?1:0;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+ Offset<<=1;
+
+ if(S^V)
+ {
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+ }
+
+ CLRFLAG(FLAG_E);
+}
+
+
+
+INST(JMP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset=SEX(8,Offset);
+
+ Offset<<=1;
+
+ Context.PC=Context.PC+Offset;
+ change_pc(Context.PC+2);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(JR)
+{
+ UINT32 Src=EXTRACT(Opcode,0,3);
+
+ Context.PC=Context.R[Src]-2;
+ change_pc(Context.PC+2);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(CALLR)
+{
+ UINT32 Src=EXTRACT(Opcode,0,3);
+ PushVal(Context.PC+2);
+ Context.PC=Context.R[Src]-2;
+ change_pc(Context.PC+2);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(ASR)
+{
+ UINT32 CS=Opcode&(1<<10);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm=EXTRACT(Opcode,5,9);
+ UINT32 Cnt=EXTRACT(Opcode,5,7);
+
+ if(CS)
+ Context.R[Dst]=AsrWithFlags(Context.R[Dst],Context.R[Cnt]&0x1f);
+ else
+ Context.R[Dst]=AsrWithFlags(Context.R[Dst],Imm&0x1f);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(LSR)
+{
+ UINT32 CS=Opcode&(1<<10);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm=EXTRACT(Opcode,5,9);
+ UINT32 Cnt=EXTRACT(Opcode,5,7);
+
+ if(CS)
+ Context.R[Dst]=LsrWithFlags(Context.R[Dst],Context.R[Cnt]&0x1f);
+ else
+ Context.R[Dst]=LsrWithFlags(Context.R[Dst],Imm&0x1f);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(ASL)
+{
+ UINT32 CS=Opcode&(1<<10);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm=EXTRACT(Opcode,5,9);
+ UINT32 Cnt=EXTRACT(Opcode,5,7);
+
+ if(CS)
+ Context.R[Dst]=AslWithFlags(Context.R[Dst],Context.R[Cnt]&0x1f);
+ else
+ Context.R[Dst]=AslWithFlags(Context.R[Dst],Imm&0x1f);
+
+ CLRFLAG(FLAG_E);
+}
+
+INST(EXTB)
+{
+ UINT32 Dst=EXTRACT(Opcode,0,3);
+ UINT32 Val=Context.R[Dst];
+
+ Context.R[Dst]=SEX8(Val);
+
+ CLRFLAG(FLAG_S|FLAG_Z|FLAG_E);
+ if(!Context.R[Dst])
+ SETFLAG(FLAG_Z);
+ if(Context.R[Dst]&0x80000000)
+ SETFLAG(FLAG_S);
+
+}
+
+INST(EXTS)
+{
+ UINT32 Dst=EXTRACT(Opcode,0,3);
+ UINT32 Val=Context.R[Dst];
+
+ Context.R[Dst]=SEX16(Val);
+
+ CLRFLAG(FLAG_S|FLAG_Z|FLAG_E);
+ if(!Context.R[Dst])
+ SETFLAG(FLAG_Z);
+ if(Context.R[Dst]&0x80000000)
+ SETFLAG(FLAG_S);
+}
+
+INST(SET)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,3);
+
+ Context.SR|=(1<<Imm);
+}
+
+INST(CLR)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,3);
+
+ Context.SR&=~(1<<Imm);
+}
+
+INST(SWI)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,3);
+
+ if(!TESTFLAG(FLAG_ENI))
+ return;
+ PushVal(Context.PC);
+ PushVal(Context.SR);
+
+ CLRFLAG(FLAG_ENI|FLAG_E|FLAG_M);
+
+ Context.PC=SE3208_Read32(4*Imm+0x40)-2;
+ change_pc(Context.PC+2);
+}
+
+INST(HALT)
+{
+// UINT32 Imm=EXTRACT(Opcode,0,3);
+
+// DEBUGMESSAGE("HALT\t0x%x",Imm);
+}
+
+INST(MVTC)
+{
+// UINT32 Imm=EXTRACT(Opcode,0,3);
+
+// DEBUGMESSAGE("MVTC\t%%R0,%%CR%d",Imm);
+}
+
+INST(MVFC)
+{
+// UINT32 Imm=EXTRACT(Opcode,0,3);
+
+// DEBUGMESSAGE("MVFC\t%%CR0%d,%%R0",Imm);
+}
+
+
+static _OP DecodeOp(UINT16 Opcode)
+{
+ switch(EXTRACT(Opcode,14,15))
+ {
+ case 0x0:
+ {
+ UINT8 Op=EXTRACT(Opcode,11,13);
+ switch(Op)
+ {
+ case 0x0:
+ return LDB;
+ case 0x1:
+ return LDS;
+ case 0x2:
+ return LD;
+ case 0x3:
+ return LDBU;
+ case 0x4:
+ return STB;
+ case 0x5:
+ return STS;
+ case 0x6:
+ return ST;
+ case 0x7:
+ return LDSU;
+ }
+ }
+ break;
+ case 0x1:
+ return LERI;
+ break;
+ case 0x2:
+ {
+ switch(EXTRACT(Opcode,11,13))
+ {
+ case 0:
+ return LDSP;
+ case 1:
+ return STSP;
+ case 2:
+ return PUSH;
+ case 3:
+ return POP;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8: //arith
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ switch(EXTRACT(Opcode,6,8))
+ {
+ case 0:
+ return ADDI;
+ case 1:
+ return ADCI;
+ case 2:
+ return SUBI;
+ case 3:
+ return SBCI;
+ case 4:
+ return ANDI;
+ case 5:
+ return ORI;
+ case 6:
+ return XORI;
+ case 7:
+ switch(EXTRACT(Opcode,0,2))
+ {
+ case 0:
+ return CMPI;
+ case 1:
+ return TSTI;
+ case 2:
+ return LEATOSP;
+ case 3:
+ return LEAFROMSP;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ case 3:
+ switch(EXTRACT(Opcode,12,13))
+ {
+ case 0:
+ switch(EXTRACT(Opcode,6,8))
+ {
+ case 0:
+ return ADD;
+ case 1:
+ return ADC;
+ case 2:
+ return SUB;
+ case 3:
+ return SBC;
+ case 4:
+ return AND;
+ case 5:
+ return OR;
+ case 6:
+ return XOR;
+ case 7:
+ switch(EXTRACT(Opcode,0,2))
+ {
+ case 0:
+ return CMP;
+ case 1:
+ return TST;
+ case 2:
+ return MOV;
+ case 3:
+ return NEG;
+ }
+ break;
+ }
+ break;
+ case 1: //Jumps
+ switch(EXTRACT(Opcode,8,11))
+ {
+ case 0x0:
+ return JNV;
+ case 0x1:
+ return JV;
+ case 0x2:
+ return JP;
+ case 0x3:
+ return JM;
+ case 0x4:
+ return JNZ;
+ case 0x5:
+ return JZ;
+ case 0x6:
+ return JNC;
+ case 0x7:
+ return JC;
+ case 0x8:
+ return JGT;
+ case 0x9:
+ return JLT;
+ case 0xa:
+ return JGE;
+ case 0xb:
+ return JLE;
+ case 0xc:
+ return JHI;
+ case 0xd:
+ return JLS;
+ case 0xe:
+ return JMP;
+ case 0xf:
+ return CALL;
+ }
+ break;
+ case 2:
+ if(Opcode&(1<<11))
+ return LDI;
+ else //SP Ops
+ {
+ if(Opcode&(1<<10))
+ {
+ switch(EXTRACT(Opcode,7,9))
+ {
+ case 0:
+ return LDBSP;
+ case 1:
+ return LDSSP;
+ case 3:
+ return LDBUSP;
+ case 4:
+ return STBSP;
+ case 5:
+ return STSSP;
+ case 7:
+ return LDSUSP;
+ }
+ }
+ else
+ {
+ if(Opcode&(1<<9))
+ {
+ return LEASPTOSP;
+ }
+ else
+ {
+ if(Opcode&(1<<8))
+ {
+
+ }
+ else
+ {
+ switch(EXTRACT(Opcode,4,7))
+ {
+ case 0:
+ return EXTB;
+ case 1:
+ return EXTS;
+ case 8:
+ return JR;
+ case 9:
+ return CALLR;
+ case 10:
+ return SET;
+ case 11:
+ return CLR;
+ case 12:
+ return SWI;
+ case 13:
+ return HALT;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 3:
+ switch(EXTRACT(Opcode,9,11))
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ switch(EXTRACT(Opcode,3,4))
+ {
+ case 0:
+ return ASR;
+ case 1:
+ return LSR;
+ case 2:
+ return ASL;
+ //case 3:
+ // return LSL;
+ }
+ break;
+ case 4:
+ return MULS;
+ case 6:
+ if(Opcode&(1<<3))
+ return MVFC;
+ else
+ return MVTC;
+ break;
+ }
+ break;
+ }
+ break;
+
+ }
+ return INVALIDOP;
+}
+
+
+static void BuildTable(void)
+{
+ int i;
+ if(!OpTable)
+ OpTable=malloc_or_die(sizeof(_OP)*0x10000);
+ for(i=0;i<0x10000;++i)
+ OpTable[i]=DecodeOp(i);
+}
+
+static void SE3208_Reset(void)
+{
+ int (*save_irqcallback)(int) = Context.irq_callback;
+ memset(&Context,0,sizeof(_SE3208Context));
+ Context.irq_callback = save_irqcallback;
+ Context.PC=SE3208_Read32(0);
+ Context.SR=0;
+ Context.IRQ=CLEAR_LINE;
+ Context.NMI=CLEAR_LINE;
+ change_pc(Context.PC+2);
+}
+
+static void SE3208_NMI(void)
+{
+ PushVal(Context.PC);
+ PushVal(Context.SR);
+
+ CLRFLAG(FLAG_NMI|FLAG_ENI|FLAG_E|FLAG_M);
+
+ Context.PC=SE3208_Read32(4);
+ change_pc(Context.PC+2);
+}
+
+static void SE3208_Interrupt(void)
+{
+ if(!TESTFLAG(FLAG_ENI))
+ return;
+
+ PushVal(Context.PC);
+ PushVal(Context.SR);
+
+ CLRFLAG(FLAG_ENI|FLAG_E|FLAG_M);
+
+
+ if(!(TESTFLAG(FLAG_AUT)))
+ Context.PC=SE3208_Read32(8);
+ else
+ Context.PC=SE3208_Read32(4*Context.irq_callback(0));
+ change_pc(Context.PC+2);
+}
+
+
+static int SE3208_Run(int cycles)
+{
+ SE3208_ICount=cycles;
+ do
+ {
+ UINT16 Opcode=cpu_readop16(WORD_XOR_LE(Context.PC));
+
+ CALL_MAME_DEBUG;
+
+ OpTable[Opcode](Opcode);
+ Context.PPC=Context.PC;
+ Context.PC+=2;
+ //Check interrupts
+ if(Context.NMI==ASSERT_LINE)
+ {
+ SE3208_NMI();
+ Context.NMI=CLEAR_LINE;
+ }
+ else if(Context.IRQ==ASSERT_LINE && TESTFLAG(FLAG_ENI))
+ {
+ SE3208_Interrupt();
+ }
+ --SE3208_ICount;
+ } while(SE3208_ICount>0);
+
+ return cycles-SE3208_ICount;
+}
+
+static void SE3208_Init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ BuildTable();
+
+ Context.irq_callback = irqcallback;
+}
+
+static void SE3208_Exit(void)
+{
+ if(OpTable)
+ free(OpTable);
+}
+
+
+static void SE3208_get_context(void *dst)
+{
+ if(dst)
+ memcpy(dst,&Context,sizeof(Context));
+}
+
+static void SE3208_set_context(void *src)
+{
+ if(src)
+ memcpy(&Context,src,sizeof(Context));
+}
+
+static void set_irq_line(int line,int state)
+{
+ if(line==INPUT_LINE_NMI) //NMI
+ Context.NMI=state;
+ else
+ Context.IRQ=state;
+}
+
+
+static void SE3208_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + SE3208_INT: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_REGISTER + SE3208_PC:
+ case CPUINFO_INT_PC: Context.PC = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_SP:
+ case CPUINFO_INT_SP: Context.SP = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_ER: Context.ER = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_SR: Context.SR = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_R0: Context.R[ 0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_R1: Context.R[ 1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_R2: Context.R[ 2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_R3: Context.R[ 3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_R4: Context.R[ 4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_R5: Context.R[ 5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_R6: Context.R[ 6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SE3208_R7: Context.R[ 7] = info->i; break;
+ }
+}
+
+
+void SE3208_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(Context); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + SE3208_INT: info->i = Context.IRQ; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = Context.NMI; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = Context.PPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SE3208_PC: info->i = Context.PC; break;
+ case CPUINFO_INT_REGISTER + SE3208_SP:
+ case CPUINFO_INT_SP: info->i = Context.SP; break;
+ case CPUINFO_INT_REGISTER + SE3208_SR: info->i = Context.SR; break;
+ case CPUINFO_INT_REGISTER + SE3208_ER: info->i = Context.ER; break;
+ case CPUINFO_INT_REGISTER + SE3208_R0: info->i = Context.R[ 0]; break;
+ case CPUINFO_INT_REGISTER + SE3208_R1: info->i = Context.R[ 1]; break;
+ case CPUINFO_INT_REGISTER + SE3208_R2: info->i = Context.R[ 2]; break;
+ case CPUINFO_INT_REGISTER + SE3208_R3: info->i = Context.R[ 3]; break;
+ case CPUINFO_INT_REGISTER + SE3208_R4: info->i = Context.R[ 4]; break;
+ case CPUINFO_INT_REGISTER + SE3208_R5: info->i = Context.R[ 5]; break;
+ case CPUINFO_INT_REGISTER + SE3208_R6: info->i = Context.R[ 6]; break;
+ case CPUINFO_INT_REGISTER + SE3208_R7: info->i = Context.R[ 7]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = SE3208_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = SE3208_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = SE3208_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = SE3208_Init; break;
+ case CPUINFO_PTR_RESET: info->reset = SE3208_Reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = SE3208_Exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = SE3208_Run; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = SE3208_Dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &SE3208_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "SE3208"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Advanced Digital Chips Inc."); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.00"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2005 ElSemi, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c %c%c%c%c%c",
+ Context.SR&FLAG_C?'C':'.',
+ Context.SR&FLAG_V?'V':'.',
+ Context.SR&FLAG_S?'S':'.',
+ Context.SR&FLAG_Z?'Z':'.',
+
+ Context.SR&FLAG_M?'M':'.',
+ Context.SR&FLAG_E?'E':'.',
+ Context.SR&FLAG_AUT?'A':'.',
+ Context.SR&FLAG_ENI?'I':'.',
+ Context.SR&FLAG_NMI?'N':'.'
+
+ );
+
+ break;
+
+ case CPUINFO_STR_REGISTER + SE3208_PC: sprintf(info->s, "PC :%08X", Context.PC); break;
+ case CPUINFO_STR_REGISTER + SE3208_SR: sprintf(info->s, "SR :%08X", Context.SR); break;
+ case CPUINFO_STR_REGISTER + SE3208_ER: sprintf(info->s, "ER :%08X", Context.ER); break;
+ case CPUINFO_STR_REGISTER + SE3208_SP: sprintf(info->s, "SP :%08X", Context.SP); break;
+ case CPUINFO_STR_REGISTER + SE3208_R0: sprintf(info->s, "R0 :%08X", Context.R[ 0]); break;
+ case CPUINFO_STR_REGISTER + SE3208_R1: sprintf(info->s, "R1 :%08X", Context.R[ 1]); break;
+ case CPUINFO_STR_REGISTER + SE3208_R2: sprintf(info->s, "R2 :%08X", Context.R[ 2]); break;
+ case CPUINFO_STR_REGISTER + SE3208_R3: sprintf(info->s, "R3 :%08X", Context.R[ 3]); break;
+ case CPUINFO_STR_REGISTER + SE3208_R4: sprintf(info->s, "R4 :%08X", Context.R[ 4]); break;
+ case CPUINFO_STR_REGISTER + SE3208_R5: sprintf(info->s, "R5 :%08X", Context.R[ 5]); break;
+ case CPUINFO_STR_REGISTER + SE3208_R6: sprintf(info->s, "R6 :%08X", Context.R[ 6]); break;
+ case CPUINFO_STR_REGISTER + SE3208_R7: sprintf(info->s, "R7 :%08X", Context.R[ 7]); break;
+ case CPUINFO_STR_REGISTER + SE3208_PPC: sprintf(info->s, "PPC :%08X", Context.PPC); break;
+ }
+}
+
diff --git a/src/emu/cpu/se3208/se3208.h b/src/emu/cpu/se3208/se3208.h
new file mode 100644
index 00000000000..90f6dfdad1f
--- /dev/null
+++ b/src/emu/cpu/se3208/se3208.h
@@ -0,0 +1,14 @@
+#include "cpuintrf.h"
+
+enum {
+ SE3208_PC=1, SE3208_SR, SE3208_ER, SE3208_SP,SE3208_PPC,
+ SE3208_R0, SE3208_R1, SE3208_R2, SE3208_R3, SE3208_R4, SE3208_R5, SE3208_R6, SE3208_R7
+};
+
+#define SE3208_INT 0
+
+extern void SE3208_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+offs_t SE3208_Dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
diff --git a/src/emu/cpu/se3208/se3208dis.c b/src/emu/cpu/se3208/se3208dis.c
new file mode 100644
index 00000000000..03b344d0564
--- /dev/null
+++ b/src/emu/cpu/se3208/se3208dis.c
@@ -0,0 +1,1413 @@
+#include "debugger.h"
+#include "se3208.h"
+
+
+static struct _DisSE3208
+{
+ UINT32 PC;
+ UINT32 SR;
+ UINT32 ER;
+} Context;
+
+#define FLAG_E 0x0800
+
+#define CLRFLAG(f) Context.SR&=~(f);
+#define SETFLAG(f) Context.SR|=(f);
+#define TESTFLAG(f) (Context.SR&(f))
+
+#define EXTRACT(val,sbit,ebit) (((val)>>sbit)&((1<<((ebit-sbit)+1))-1))
+#define SEX8(val) ((val&0x80)?(val|0xFFFFFF00):(val&0xFF))
+#define SEX16(val) ((val&0x8000)?(val|0xFFFF0000):(val&0xFFFF))
+#define ZEX8(val) ((val)&0xFF)
+#define ZEX16(val) ((val)&0xFFFF)
+#define SEX(bits,val) ((val)&(1<<(bits-1))?((val)|(~((1<<bits)-1))):(val&((1<<bits)-1)))
+
+typedef UINT32 (*_OP)(UINT16 Opcode,char *dst);
+#define INST(a) static UINT32 a(UINT16 Opcode,char *dst)
+
+
+INST(INVALIDOP)
+{
+ sprintf(dst,"INVALID");
+ return 0;
+}
+
+INST(LDB)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ if(Index)
+ sprintf(dst,"LDB (%%R%d,0x%x),%%R%d",Index,Offset,SrcDst);
+ else
+ sprintf(dst,"LDB (0x%x),%%R%d",Index+Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(STB)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ if(Index)
+ sprintf(dst,"STB %%R%d,(%%R%d,0x%x)",SrcDst,Index,Offset);
+ else
+ sprintf(dst,"STB %%R%d,(0x%x)",SrcDst,Index+Offset);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LDS)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ if(Index)
+ sprintf(dst,"LDS (%%R%d,0x%x),%%R%d",Index,Offset,SrcDst);
+ else
+ sprintf(dst,"LDS (0x%x),%%R%d",Index+Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(STS)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ if(Index)
+ sprintf(dst,"STS %%R%d,(%%R%d,0x%x)",SrcDst,Index,Offset);
+ else
+ sprintf(dst,"STS %%R%d,(0x%x)",SrcDst,Index+Offset);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LD)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ if(Index)
+ sprintf(dst,"LD (%%R%d,0x%x),%%R%d",Index,Offset,SrcDst);
+ else
+ sprintf(dst,"LD (0x%x),%%R%d",Index+Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(ST)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ if(Index)
+ sprintf(dst,"ST %%R%d,(%%R%d,0x%x)",SrcDst,Index,Offset);
+ else
+ sprintf(dst,"ST %%R%d,(0x%x)",SrcDst,Index+Offset);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LDBU)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ if(Index)
+ sprintf(dst,"LDBU (%%R%d,0x%x),%%R%d",Index,Offset,SrcDst);
+ else
+ sprintf(dst,"LDBU (0x%x),%%R%d",Index+Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LDSU)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,4);
+ UINT32 Index=EXTRACT(Opcode,5,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ if(Index)
+ sprintf(dst,"LDSU (%%R%d,0x%x),%%R%d",Index,Offset,SrcDst);
+ else
+ sprintf(dst,"LDSU (0x%x),%%R%d",Index+Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+
+INST(LERI)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,13);
+
+ if(TESTFLAG(FLAG_E))
+ Context.ER=(EXTRACT(Context.ER,0,17)<<14)|Imm;
+ else
+ Context.ER=SEX(14,Imm);
+
+ //sprintf(dst,"LERI 0x%x\t\tER=%08X",Imm,Context.ER);
+ sprintf(dst,"LERI 0x%x",Imm/*,Context.ER*/);
+
+ SETFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LDSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ sprintf(dst,"LD (%%SP,0x%x),%%R%d",Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(STSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 SrcDst=EXTRACT(Opcode,8,10);
+
+ Offset<<=2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ sprintf(dst,"ST %%R%d,(%%SP,0x%x)",SrcDst,Offset);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(PUSH)
+{
+ UINT32 Set=EXTRACT(Opcode,0,10);
+ char str[1024];
+ strcpy(str,"PUSH ");
+ if(Set&(1<<10))
+ strcat(str,"%PC-");
+ if(Set&(1<<9))
+ strcat(str,"%SR-");
+ if(Set&(1<<8))
+ strcat(str,"%ER-");
+ if(Set&(1<<7))
+ strcat(str,"%R7-");
+ if(Set&(1<<6))
+ strcat(str,"%R6-");
+ if(Set&(1<<5))
+ strcat(str,"%R5-");
+ if(Set&(1<<4))
+ strcat(str,"%R4-");
+ if(Set&(1<<3))
+ strcat(str,"%R3-");
+ if(Set&(1<<2))
+ strcat(str,"%R2-");
+ if(Set&(1<<1))
+ strcat(str,"%R1-");
+ if(Set&(1<<0))
+ strcat(str,"%R0-");
+ str[strlen(str)-1]=0;
+ strcpy(dst,str);
+ return 0;
+}
+
+INST(POP)
+{
+ UINT32 Set=EXTRACT(Opcode,0,10);
+ char str[1024];
+ int Ret=0;
+ strcpy(str,"POP ");
+ if(Set&(1<<0))
+ strcat(str,"%R0-");
+ if(Set&(1<<1))
+ strcat(str,"%R1-");
+ if(Set&(1<<2))
+ strcat(str,"%R2-");
+ if(Set&(1<<3))
+ strcat(str,"%R3-");
+ if(Set&(1<<4))
+ strcat(str,"%R4-");
+ if(Set&(1<<5))
+ strcat(str,"%R5-");
+ if(Set&(1<<6))
+ strcat(str,"%R6-");
+ if(Set&(1<<7))
+ strcat(str,"%R7-");
+ if(Set&(1<<8))
+ strcat(str,"%ER-");
+ if(Set&(1<<9))
+ strcat(str,"%SR-");
+ if(Set&(1<<10))
+ {
+ strcat(str,"%PC-");
+ CLRFLAG(FLAG_E); //Clear the flag, this is a ret so disassemble will start a new E block
+ Ret=1;
+ }
+ str[strlen(str)-1]=0;
+ if(Ret)
+ strcat(str,"\n");
+ strcpy(dst,str);
+ return Ret ? DASMFLAG_STEP_OUT : 0;
+}
+
+INST(LEATOSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,9,12);
+ UINT32 Index=EXTRACT(Opcode,3,5);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+ else
+ Offset=SEX(4,Offset);
+
+ if(Index)
+ sprintf(dst,"LEA (%%R%d,0x%x),%%SP",Index,Offset);
+ else
+ sprintf(dst,"LEA (0x%x),%%SP",Index+Offset);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LEAFROMSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,9,12);
+ UINT32 Index=EXTRACT(Opcode,3,5);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+ else
+ Offset=SEX(4,Offset);
+
+ sprintf(dst,"LEA (%%SP,0x%x),%%R%d",Offset,Index);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LEASPTOSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+
+ Offset<<=2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,23)<<8)|(Offset&0xff);
+ else
+ Offset=SEX(10,Offset);
+
+
+ sprintf(dst,"LEA (%%SP,0x%x),%%SP",Offset);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(MOV)
+{
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,9,11);
+
+ if(Src==0 && Dst==0)
+ sprintf(dst,"NOP");
+ else
+ sprintf(dst,"MOV %%SR%d,%%DR%d",Src,Dst);
+ return 0;
+}
+
+INST(LDI)
+{
+ UINT32 Dst=EXTRACT(Opcode,8,10);
+ UINT32 Imm=EXTRACT(Opcode,0,7);
+
+ if(TESTFLAG(FLAG_E))
+ Imm=(EXTRACT(Context.ER,0,27)<<4)|(Imm&0xf);
+ else
+ Imm=SEX8(Imm);
+
+ sprintf(dst,"LDI 0x%x,%%R%d",Imm,Dst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LDBSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ sprintf(dst,"LDB (%%SP,0x%x),%%R%d",Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(STBSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ sprintf(dst,"STB %%R%d,(%%SP,0x%x)",SrcDst,Offset);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LDSSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ sprintf(dst,"LDS (%%SP,0x%x),%%R%d",Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(STSSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ sprintf(dst,"STS %%R%d,(%%SP,0x%x)",SrcDst,Offset);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LDBUSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ sprintf(dst,"LDBU (%%SP,0x%x),%%R%d",Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LDSUSP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,3);
+ UINT32 SrcDst=EXTRACT(Opcode,4,6);
+
+ Offset<<=1;
+
+ if(TESTFLAG(FLAG_E))
+ Offset=(EXTRACT(Context.ER,0,27)<<4)|(Offset&0xf);
+
+ sprintf(dst,"LDSU (%%SP,0x%x),%%R%d",Offset,SrcDst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(ADDI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm2=Imm;
+
+ if(TESTFLAG(FLAG_E))
+ Imm2=(EXTRACT(Context.ER,0,27)<<4)|(Imm2&0xf);
+ else
+ Imm2=SEX(4,Imm2);
+
+ sprintf(dst,"ADD %%SR%d,0x%x,%%DR%d",Src,Imm2,Dst/*,Imm2*/);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(SUBI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm2=Imm;
+
+ if(TESTFLAG(FLAG_E))
+ Imm2=(EXTRACT(Context.ER,0,27)<<4)|(Imm2&0xf);
+ else
+ Imm2=SEX(4,Imm2);
+
+ sprintf(dst,"SUB %%SR%d,0x%x,%%DR%d",Src,Imm2,Dst/*,Imm2*/);
+
+ CLRFLAG(FLAG_E);
+
+ return 0;
+}
+
+INST(ADCI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm2=Imm;
+
+ if(TESTFLAG(FLAG_E))
+ Imm2=(EXTRACT(Context.ER,0,27)<<4)|(Imm2&0xf);
+ else
+ Imm2=SEX(4,Imm2);
+
+ sprintf(dst,"ADC %%SR%d,0x%x,%%DR%d",Src,Imm2,Dst/*,Imm2*/);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(SBCI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm2=Imm;
+
+ if(TESTFLAG(FLAG_E))
+ Imm2=(EXTRACT(Context.ER,0,27)<<4)|(Imm2&0xf);
+ else
+ Imm2=SEX(4,Imm2);
+
+ sprintf(dst,"SBC %%SR%d,0x%x,%%DR%d",Src,Imm2,Dst/*,Imm2*/);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(ANDI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm2=Imm;
+
+ if(TESTFLAG(FLAG_E))
+ Imm2=(EXTRACT(Context.ER,0,27)<<4)|(Imm2&0xf);
+ else
+ Imm2=SEX(4,Imm2);
+
+ sprintf(dst,"AND %%SR%d,0x%x,%%DR%d",Src,Imm2,Dst/*,Imm2*/);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(ORI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm2=Imm;
+
+ if(TESTFLAG(FLAG_E))
+ Imm2=(EXTRACT(Context.ER,0,27)<<4)|(Imm2&0xf);
+ else
+ Imm2=SEX(4,Imm2);
+
+ sprintf(dst,"OR %%SR%d,0x%x,%%DR%d",Src,Imm2,Dst/*,Imm2*/);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(XORI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm2=Imm;
+
+ if(TESTFLAG(FLAG_E))
+ Imm2=(EXTRACT(Context.ER,0,27)<<4)|(Imm2&0xf);
+ else
+ Imm2=SEX(4,Imm2);
+
+ sprintf(dst,"XOR %%SR%d,0x%x,%%DR%d",Src,Imm2,Dst/*,Imm2*/);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(CMPI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Imm2=Imm;
+
+ if(TESTFLAG(FLAG_E))
+ Imm2=(EXTRACT(Context.ER,0,27)<<4)|(Imm2&0xf);
+ else
+ Imm2=SEX(4,Imm2);
+
+ sprintf(dst,"CMP %%SR%d,0x%x",Src,Imm2/*,Imm2*/);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(TSTI)
+{
+ UINT32 Imm=EXTRACT(Opcode,9,12);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+ UINT32 Imm2=Imm;
+
+ if(TESTFLAG(FLAG_E))
+ Imm2=(EXTRACT(Context.ER,0,27)<<4)|(Imm2&0xf);
+ else
+ Imm2=SEX(4,Imm2);
+
+ sprintf(dst,"TST %%SR%d,0x%x",Src,Imm2/*,Imm2*/);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(ADD)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ sprintf(dst,"ADD %%SR%d,%%SR%d,%%DR%d",Src1,Src2,Dst);
+ return 0;
+}
+
+INST(SUB)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ sprintf(dst,"SUB %%SR%d,%%SR%d,%%DR%d",Src1,Src2,Dst);
+ return 0;
+}
+
+INST(ADC)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ sprintf(dst,"ADC %%SR%d,%%SR%d,%%DR%d",Src1,Src2,Dst);
+ return 0;
+}
+
+INST(SBC)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ sprintf(dst,"SBC %%SR%d,%%SR%d,%%DR%d",Src1,Src2,Dst);
+ return 0;
+}
+
+INST(AND)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ sprintf(dst,"AND %%SR%d,%%SR%d,%%DR%d",Src1,Src2,Dst);
+ return 0;
+}
+
+INST(OR)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ sprintf(dst,"OR %%SR%d,%%SR%d,%%DR%d",Src1,Src2,Dst);
+ return 0;
+}
+
+INST(XOR)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ sprintf(dst,"XOR %%SR%d,%%SR%d,%%DR%d",Src1,Src2,Dst);
+ return 0;
+}
+
+INST(CMP)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+
+ sprintf(dst,"CMP %%SR%d,%%SR%d",Src1,Src2);
+ return 0;
+}
+
+INST(TST)
+{
+ UINT32 Src2=EXTRACT(Opcode,9,11);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+
+ sprintf(dst,"TST %%SR%d,%%SR%d",Src1,Src2);
+ return 0;
+}
+
+INST(MULS)
+{
+ UINT32 Src2=EXTRACT(Opcode,6,8);
+ UINT32 Src1=EXTRACT(Opcode,3,5);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+
+ sprintf(dst,"MUL %%SR%d,%%SR%d,%%DR%d",Src1,Src2,Dst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(NEG)
+{
+ UINT32 Dst=EXTRACT(Opcode,9,11);
+ UINT32 Src=EXTRACT(Opcode,3,5);
+
+ sprintf(dst,"NEG %%SR%d,%%DR%d",Src,Dst);
+ return 0;
+}
+
+INST(CALL)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"CALL 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return DASMFLAG_STEP_OVER;
+}
+
+INST(JV)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JV 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JNV)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JNV 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JC)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JC 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JNC)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JNC 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JP 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JM)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JM 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JNZ)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JNZ 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JZ)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JZ 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JGE)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JGE 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JLE)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JLE 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JHI)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JHI 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JLS)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JLS 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JGT)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JGT 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JLT)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JLT 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+
+
+INST(JMP)
+{
+ UINT32 Offset=EXTRACT(Opcode,0,7);
+ UINT32 Offset2;
+
+ if(TESTFLAG(FLAG_E))
+ Offset2=(EXTRACT(Context.ER,0,22)<<8)|Offset;
+ else
+ Offset2=SEX(8,Offset);
+ Offset2<<=1;
+ sprintf(dst,"JMP 0x%x",Context.PC+2+Offset2);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(JR)
+{
+ UINT32 Src=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"JR %%R%d",Src);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(CALLR)
+{
+ UINT32 Src=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"CALLR %%R%d",Src);
+
+ CLRFLAG(FLAG_E);
+ return DASMFLAG_STEP_OVER;
+}
+
+INST(ASR)
+{
+ UINT32 CS=Opcode&(1<<10);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm=EXTRACT(Opcode,5,9);
+ UINT32 Cnt=EXTRACT(Opcode,5,7);
+
+ if(CS)
+ sprintf(dst,"ASR %%R%d,%%R%d",Cnt,Dst);
+ else
+ sprintf(dst,"ASR %x,%%R%d",Imm,Dst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(LSR)
+{
+ UINT32 CS=Opcode&(1<<10);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm=EXTRACT(Opcode,5,9);
+ UINT32 Cnt=EXTRACT(Opcode,5,7);
+
+ if(CS)
+ sprintf(dst,"LSR %%R%d,%%R%d",Cnt,Dst);
+ else
+ sprintf(dst,"LSR %x,%%R%d",Imm,Dst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(ASL)
+{
+ UINT32 CS=Opcode&(1<<10);
+ UINT32 Dst=EXTRACT(Opcode,0,2);
+ UINT32 Imm=EXTRACT(Opcode,5,9);
+ UINT32 Cnt=EXTRACT(Opcode,5,7);
+
+ if(CS)
+ sprintf(dst,"ASL %%R%d,%%R%d",Cnt,Dst);
+ else
+ sprintf(dst,"ASL %x,%%R%d",Imm,Dst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(EXTB)
+{
+ UINT32 Dst=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"EXTB %%R%d",Dst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(EXTS)
+{
+ UINT32 Dst=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"EXTS %%R%d",Dst);
+
+ CLRFLAG(FLAG_E);
+ return 0;
+}
+
+INST(SET)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"SET 0x%x",Imm);
+ return 0;
+}
+
+INST(CLR)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"CLR 0x%x",Imm);
+ return 0;
+}
+
+INST(SWI)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"SWI 0x%x",Imm);
+ return 0;
+}
+
+INST(HALT)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"HALT 0x%x",Imm);
+ return 0;
+}
+
+INST(MVTC)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"MVTC %%R0,%%CR%d",Imm);
+ return 0;
+}
+
+INST(MVFC)
+{
+ UINT32 Imm=EXTRACT(Opcode,0,3);
+
+ sprintf(dst,"MVFC %%CR0%d,%%R0",Imm);
+ return 0;
+}
+
+static _OP DecodeOp(UINT16 Opcode)
+{
+ switch(EXTRACT(Opcode,14,15))
+ {
+ case 0x0:
+ {
+ UINT8 Op=EXTRACT(Opcode,11,13);
+ switch(Op)
+ {
+ case 0x0:
+ return LDB;
+ case 0x1:
+ return LDS;
+ case 0x2:
+ return LD;
+ case 0x3:
+ return LDBU;
+ case 0x4:
+ return STB;
+ case 0x5:
+ return STS;
+ case 0x6:
+ return ST;
+ case 0x7:
+ return LDSU;
+ }
+ }
+ break;
+ case 0x1:
+ return LERI;
+ break;
+ case 0x2:
+ {
+ switch(EXTRACT(Opcode,11,13))
+ {
+ case 0:
+ return LDSP;
+ case 1:
+ return STSP;
+ case 2:
+ return PUSH;
+ case 3:
+ return POP;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8: //arith
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ switch(EXTRACT(Opcode,6,8))
+ {
+ case 0:
+ return ADDI;
+ case 1:
+ return ADCI;
+ case 2:
+ return SUBI;
+ case 3:
+ return SBCI;
+ case 4:
+ return ANDI;
+ case 5:
+ return ORI;
+ case 6:
+ return XORI;
+ case 7:
+ switch(EXTRACT(Opcode,0,2))
+ {
+ case 0:
+ return CMPI;
+ case 1:
+ return TSTI;
+ case 2:
+ return LEATOSP;
+ case 3:
+ return LEAFROMSP;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ case 3:
+ switch(EXTRACT(Opcode,12,13))
+ {
+ case 0:
+ switch(EXTRACT(Opcode,6,8))
+ {
+ case 0:
+ return ADD;
+ case 1:
+ return ADC;
+ case 2:
+ return SUB;
+ case 3:
+ return SBC;
+ case 4:
+ return AND;
+ case 5:
+ return OR;
+ case 6:
+ return XOR;
+ case 7:
+ switch(EXTRACT(Opcode,0,2))
+ {
+ case 0:
+ return CMP;
+ case 1:
+ return TST;
+ case 2:
+ return MOV;
+ case 3:
+ return NEG;
+ }
+ break;
+ }
+ break;
+ case 1: //Jumps
+ switch(EXTRACT(Opcode,8,11))
+ {
+ case 0x0:
+ return JNV;
+ case 0x1:
+ return JV;
+ case 0x2:
+ return JP;
+ case 0x3:
+ return JM;
+ case 0x4:
+ return JNZ;
+ case 0x5:
+ return JZ;
+ case 0x6:
+ return JNC;
+ case 0x7:
+ return JC;
+ case 0x8:
+ return JGT;
+ case 0x9:
+ return JLT;
+ case 0xa:
+ return JGE;
+ case 0xb:
+ return JLE;
+ case 0xc:
+ return JHI;
+ case 0xd:
+ return JLS;
+ case 0xe:
+ return JMP;
+ case 0xf:
+ return CALL;
+ }
+ break;
+ case 2:
+ if(Opcode&(1<<11))
+ return LDI;
+ else //SP Ops
+ {
+ if(Opcode&(1<<10))
+ {
+ switch(EXTRACT(Opcode,7,9))
+ {
+ case 0:
+ return LDBSP;
+ case 1:
+ return LDSSP;
+ case 3:
+ return LDBUSP;
+ case 4:
+ return STBSP;
+ case 5:
+ return STSSP;
+ case 7:
+ return LDSUSP;
+ }
+ }
+ else
+ {
+ if(Opcode&(1<<9))
+ {
+ return LEASPTOSP;
+ }
+ else
+ {
+ if(Opcode&(1<<8))
+ {
+
+ }
+ else
+ {
+ switch(EXTRACT(Opcode,4,7))
+ {
+ case 0:
+ return EXTB;
+ case 1:
+ return EXTS;
+ case 8:
+ return JR;
+ case 9:
+ return CALLR;
+ case 10:
+ return SET;
+ case 11:
+ return CLR;
+ case 12:
+ return SWI;
+ case 13:
+ return HALT;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 3:
+ switch(EXTRACT(Opcode,9,11))
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ switch(EXTRACT(Opcode,3,4))
+ {
+ case 0:
+ return ASR;
+ case 1:
+ return LSR;
+ case 2:
+ return ASL;
+ //case 3:
+ // return LSL;
+ }
+ break;
+ case 4:
+ return MULS;
+ case 6:
+ if(Opcode&(1<<3))
+ return MVFC;
+ else
+ return MVTC;
+ break;
+ }
+ break;
+ }
+ break;
+
+ }
+ return INVALIDOP;
+}
+
+
+offs_t SE3208_Dasm(char *Buffer, offs_t PC, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT16 Opcode;
+
+ CLRFLAG(FLAG_E);
+ Context.ER=0;
+
+ Context.PC=PC;
+ Opcode=oprom[0] | (oprom[1] << 8);
+ return 2 | ((*DecodeOp(Opcode))(Opcode,Buffer)) | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/sh2/sh2.c b/src/emu/cpu/sh2/sh2.c
new file mode 100644
index 00000000000..e6d486cfd77
--- /dev/null
+++ b/src/emu/cpu/sh2/sh2.c
@@ -0,0 +1,3181 @@
+/*****************************************************************************
+ *
+ * sh2.c
+ * Portable Hitachi SH-2 (SH7600 family) emulator
+ *
+ * Copyright (c) 2000 Juergen Buchmueller <pullmoll@t-online.de>,
+ * all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on <tiraniddo@hotmail.com> C/C++ implementation of
+ * the SH-2 CPU core and was adapted to the MAME CPU core requirements.
+ * Thanks also go to Chuck Mason <chukjr@sundail.net> and Olivier Galibert
+ * <galibert@pobox.com> for letting me peek into their SEMU code :-)
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ Changes
+ 20051129 Mariusz Wojcieszek
+ - introduced cpu_readop16() for opcode fetching
+
+ 20050813 Mariusz Wojcieszek
+ - fixed 64 bit / 32 bit division in division unit
+
+ 20031015 O. Galibert
+ - dma fixes, thanks to sthief
+
+ 20031013 O. Galibert, A. Giles
+ - timer fixes
+ - multi-cpu simplifications
+
+ 20030915 O. Galibert
+ - fix DMA1 irq vector
+ - ignore writes to DRCRx
+ - fix cpu number issues
+ - fix slave/master recognition
+ - fix wrong-cpu-in-context problem with the timers
+
+ 20021020 O. Galibert
+ - DMA implementation, lightly tested
+ - change_pc() crap fixed
+ - delay slot in debugger fixed
+ - add divide box mirrors
+ - Nicola-ify the indentation
+ - Uncrapify sh2_internal_*
+ - Put back nmi support that had been lost somehow
+
+ 20020914 R. Belmont
+ - Initial SH2 internal timers implementation, based on code by O. Galibert.
+ Makes music work in galspanic4/s/s2, panic street, cyvern, other SKNS games.
+ - Fix to external division, thanks to "spice" on the E2J board.
+ Corrects behavior of s1945ii turret boss.
+
+ 20020302 Olivier Galibert (galibert@mame.net)
+ - Fixed interrupt in delay slot
+ - Fixed rotcr
+ - Fixed div1
+ - Fixed mulu
+ - Fixed negc
+
+ 20020301 R. Belmont
+ - Fixed external division
+
+ 20020225 Olivier Galibert (galibert@mame.net)
+ - Fixed interrupt handling
+
+ 20010207 Sylvain Glaize (mokona@puupuu.org)
+
+ - Bug fix in INLINE void MOVBM(UINT32 m, UINT32 n) (see comment)
+ - Support of full 32 bit addressing (RB, RW, RL and WB, WW, WL functions)
+ reason : when the two high bits of the address are set, access is
+ done directly in the cache data array. The SUPER KANEKO NOVA SYSTEM
+ sets the stack pointer here, using these addresses as usual RAM access.
+
+ No real cache support has been added.
+ - Read/Write memory format correction (_bew to _bedw) (see also SH2
+ definition in cpuintrf.c and DasmSH2(..) in sh2dasm.c )
+
+ 20010623 James Forshaw (TyRaNiD@totalise.net)
+
+ - Modified operation of sh2_exception. Done cause mame irq system is stupid, and
+ doesnt really seem designed for any more than 8 interrupt lines.
+
+ 20010701 James Forshaw (TyRaNiD@totalise.net)
+
+ - Fixed DIV1 operation. Q bit now correctly generated
+
+ 20020218 Added save states (mokona@puupuu.org)
+
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "sh2.h"
+
+/* speed up delay loops, bail out of tight loops */
+#define BUSY_LOOP_HACKS 1
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+typedef struct
+{
+ int irq_vector;
+ int irq_priority;
+} irq_entry;
+
+typedef struct
+{
+ UINT32 ppc;
+ UINT32 pc;
+ UINT32 pr;
+ UINT32 sr;
+ UINT32 gbr, vbr;
+ UINT32 mach, macl;
+ UINT32 r[16];
+ UINT32 ea;
+ UINT32 delay;
+ UINT32 cpu_off;
+ UINT32 dvsr, dvdnth, dvdntl, dvcr;
+ UINT32 pending_irq;
+ UINT32 test_irq;
+ irq_entry irq_queue[16];
+
+ INT8 irq_line_state[17];
+ int (*irq_callback)(int irqline);
+ UINT32 *m;
+ INT8 nmi_line_state;
+
+ UINT16 frc;
+ UINT16 ocra, ocrb, icr;
+ UINT32 frc_base;
+
+ int frt_input;
+ int internal_irq_level;
+ int internal_irq_vector;
+
+ emu_timer *timer;
+ emu_timer *dma_timer[2];
+ int dma_timer_active[2];
+
+ int is_slave, cpu_number;
+
+ void (*ftcsr_read_callback)(UINT32 data);
+} SH2;
+
+static int sh2_icount;
+static SH2 sh2;
+
+// Atrocious hack that makes the soldivid music correct
+
+//static const int div_tab[4] = { 3, 5, 7, 0 };
+static const int div_tab[4] = { 3, 5, 3, 0 };
+
+enum {
+ ICF = 0x00800000,
+ OCFA = 0x00080000,
+ OCFB = 0x00040000,
+ OVF = 0x00020000
+};
+
+static TIMER_CALLBACK( sh2_timer_callback );
+
+#define T 0x00000001
+#define S 0x00000002
+#define I 0x000000f0
+#define Q 0x00000100
+#define M 0x00000200
+
+#define AM 0xc7ffffff
+
+#define FLAGS (M|Q|I|S|T)
+
+#define Rn ((opcode>>8)&15)
+#define Rm ((opcode>>4)&15)
+
+INLINE UINT8 RB(offs_t A)
+{
+ if (A >= 0xe0000000)
+ return sh2_internal_r((A & 0x1fc)>>2, ~(0xff << (((~A) & 3)*8))) >> (((~A) & 3)*8);
+
+ if (A >= 0xc0000000)
+ return program_read_byte_32be(A);
+
+ if (A >= 0x40000000)
+ return 0xa5;
+
+ return program_read_byte_32be(A & AM);
+}
+
+INLINE UINT16 RW(offs_t A)
+{
+ if (A >= 0xe0000000)
+ return sh2_internal_r((A & 0x1fc)>>2, ~(0xffff << (((~A) & 2)*8))) >> (((~A) & 2)*8);
+
+ if (A >= 0xc0000000)
+ return program_read_word_32be(A);
+
+ if (A >= 0x40000000)
+ return 0xa5a5;
+
+ return program_read_word_32be(A & AM);
+}
+
+INLINE UINT32 RL(offs_t A)
+{
+ if (A >= 0xe0000000)
+ return sh2_internal_r((A & 0x1fc)>>2, 0);
+
+ if (A >= 0xc0000000)
+ return program_read_dword_32be(A);
+
+ if (A >= 0x40000000)
+ return 0xa5a5a5a5;
+
+ return program_read_dword_32be(A & AM);
+}
+
+INLINE void WB(offs_t A, UINT8 V)
+{
+
+ if (A >= 0xe0000000)
+ {
+ sh2_internal_w((A & 0x1fc)>>2, V << (((~A) & 3)*8), ~(0xff << (((~A) & 3)*8)));
+ return;
+ }
+
+ if (A >= 0xc0000000)
+ {
+ program_write_byte_32be(A,V);
+ return;
+ }
+
+ if (A >= 0x40000000)
+ return;
+
+ program_write_byte_32be(A & AM,V);
+}
+
+INLINE void WW(offs_t A, UINT16 V)
+{
+ if (A >= 0xe0000000)
+ {
+ sh2_internal_w((A & 0x1fc)>>2, V << (((~A) & 2)*8), ~(0xffff << (((~A) & 2)*8)));
+ return;
+ }
+
+ if (A >= 0xc0000000)
+ {
+ program_write_word_32be(A,V);
+ return;
+ }
+
+ if (A >= 0x40000000)
+ return;
+
+ program_write_word_32be(A & AM,V);
+}
+
+INLINE void WL(offs_t A, UINT32 V)
+{
+ if (A >= 0xe0000000)
+ {
+ sh2_internal_w((A & 0x1fc)>>2, V, 0);
+ return;
+ }
+
+ if (A >= 0xc0000000)
+ {
+ program_write_dword_32be(A,V);
+ return;
+ }
+
+ if (A >= 0x40000000)
+ return;
+
+ program_write_dword_32be(A & AM,V);
+}
+
+INLINE void sh2_exception(const char *message, int irqline)
+{
+ int vector;
+
+ if (irqline != 16)
+ {
+ if (irqline <= ((sh2.sr >> 4) & 15)) /* If the cpu forbids this interrupt */
+ return;
+
+ // if this is an sh2 internal irq, use its vector
+ if (sh2.internal_irq_level == irqline)
+ {
+ vector = sh2.internal_irq_vector;
+ LOG(("SH-2 #%d exception #%d (internal vector: $%x) after [%s]\n", cpu_getactivecpu(), irqline, vector, message));
+ }
+ else
+ {
+ if(sh2.m[0x38] & 0x00010000)
+ {
+ vector = sh2.irq_callback(irqline);
+ LOG(("SH-2 #%d exception #%d (external vector: $%x) after [%s]\n", cpu_getactivecpu(), irqline, vector, message));
+ }
+ else
+ {
+ sh2.irq_callback(irqline);
+ vector = 64 + irqline/2;
+ LOG(("SH-2 #%d exception #%d (autovector: $%x) after [%s]\n", cpu_getactivecpu(), irqline, vector, message));
+ }
+ }
+ }
+ else
+ {
+ vector = 11;
+ LOG(("SH-2 #%d nmi exception (autovector: $%x) after [%s]\n", cpu_getactivecpu(), vector, message));
+ }
+
+ sh2.r[15] -= 4;
+ WL( sh2.r[15], sh2.sr ); /* push SR onto stack */
+ sh2.r[15] -= 4;
+ WL( sh2.r[15], sh2.pc ); /* push PC onto stack */
+
+ /* set I flags in SR */
+ if (irqline > SH2_INT_15)
+ sh2.sr = sh2.sr | I;
+ else
+ sh2.sr = (sh2.sr & ~I) | (irqline << 4);
+
+ /* fetch PC */
+ sh2.pc = RL( sh2.vbr + vector * 4 );
+ change_pc(sh2.pc & AM);
+}
+
+#define CHECK_PENDING_IRQ(message) \
+do { \
+ int irq = -1; \
+ if (sh2.pending_irq & (1 << 0)) irq = 0; \
+ if (sh2.pending_irq & (1 << 1)) irq = 1; \
+ if (sh2.pending_irq & (1 << 2)) irq = 2; \
+ if (sh2.pending_irq & (1 << 3)) irq = 3; \
+ if (sh2.pending_irq & (1 << 4)) irq = 4; \
+ if (sh2.pending_irq & (1 << 5)) irq = 5; \
+ if (sh2.pending_irq & (1 << 6)) irq = 6; \
+ if (sh2.pending_irq & (1 << 7)) irq = 7; \
+ if (sh2.pending_irq & (1 << 8)) irq = 8; \
+ if (sh2.pending_irq & (1 << 9)) irq = 9; \
+ if (sh2.pending_irq & (1 << 10)) irq = 10; \
+ if (sh2.pending_irq & (1 << 11)) irq = 11; \
+ if (sh2.pending_irq & (1 << 12)) irq = 12; \
+ if (sh2.pending_irq & (1 << 13)) irq = 13; \
+ if (sh2.pending_irq & (1 << 14)) irq = 14; \
+ if (sh2.pending_irq & (1 << 15)) irq = 15; \
+ if ((sh2.internal_irq_level != -1) && (sh2.internal_irq_level > irq)) irq = sh2.internal_irq_level; \
+ if (irq >= 0) \
+ sh2_exception(message,irq); \
+} while(0)
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1100 1 -
+ * ADD Rm,Rn
+ */
+INLINE void ADD(UINT32 m, UINT32 n)
+{
+ sh2.r[n] += sh2.r[m];
+}
+
+/* code cycles t-bit
+ * 0111 nnnn iiii iiii 1 -
+ * ADD #imm,Rn
+ */
+INLINE void ADDI(UINT32 i, UINT32 n)
+{
+ sh2.r[n] += (INT32)(INT16)(INT8)i;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1110 1 carry
+ * ADDC Rm,Rn
+ */
+INLINE void ADDC(UINT32 m, UINT32 n)
+{
+ UINT32 tmp0, tmp1;
+
+ tmp1 = sh2.r[n] + sh2.r[m];
+ tmp0 = sh2.r[n];
+ sh2.r[n] = tmp1 + (sh2.sr & T);
+ if (tmp0 > tmp1)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ if (tmp1 > sh2.r[n])
+ sh2.sr |= T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1111 1 overflow
+ * ADDV Rm,Rn
+ */
+INLINE void ADDV(UINT32 m, UINT32 n)
+{
+ INT32 dest, src, ans;
+
+ if ((INT32) sh2.r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((INT32) sh2.r[m] >= 0)
+ src = 0;
+ else
+ src = 1;
+ src += dest;
+ sh2.r[n] += sh2.r[m];
+ if ((INT32) sh2.r[n] >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (src == 0 || src == 2)
+ {
+ if (ans == 1)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ }
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 1001 1 -
+ * AND Rm,Rn
+ */
+INLINE void AND(UINT32 m, UINT32 n)
+{
+ sh2.r[n] &= sh2.r[m];
+}
+
+
+/* code cycles t-bit
+ * 1100 1001 iiii iiii 1 -
+ * AND #imm,R0
+ */
+INLINE void ANDI(UINT32 i)
+{
+ sh2.r[0] &= i;
+}
+
+/* code cycles t-bit
+ * 1100 1101 iiii iiii 1 -
+ * AND.B #imm,@(R0,GBR)
+ */
+INLINE void ANDM(UINT32 i)
+{
+ UINT32 temp;
+
+ sh2.ea = sh2.gbr + sh2.r[0];
+ temp = i & RB( sh2.ea );
+ WB( sh2.ea, temp );
+ sh2_icount -= 2;
+}
+
+/* code cycles t-bit
+ * 1000 1011 dddd dddd 3/1 -
+ * BF disp8
+ */
+INLINE void BF(UINT32 d)
+{
+ if ((sh2.sr & T) == 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ change_pc(sh2.pc & AM);
+ sh2_icount -= 2;
+ }
+}
+
+/* code cycles t-bit
+ * 1000 1111 dddd dddd 3/1 -
+ * BFS disp8
+ */
+INLINE void BFS(UINT32 d)
+{
+ if ((sh2.sr & T) == 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2_icount--;
+ }
+}
+
+/* code cycles t-bit
+ * 1010 dddd dddd dddd 2 -
+ * BRA disp12
+ */
+INLINE void BRA(UINT32 d)
+{
+ INT32 disp = ((INT32)d << 20) >> 20;
+
+#if BUSY_LOOP_HACKS
+ if (disp == -2)
+ {
+ UINT32 next_opcode = RW(sh2.ppc & AM);
+ /* BRA $
+ * NOP
+ */
+ if (next_opcode == 0x0009)
+ sh2_icount %= 3; /* cycles for BRA $ and NOP taken (3) */
+ }
+#endif
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2_icount--;
+}
+
+/* code cycles t-bit
+ * 0000 mmmm 0010 0011 2 -
+ * BRAF Rm
+ */
+INLINE void BRAF(UINT32 m)
+{
+ sh2.delay = sh2.pc;
+ sh2.pc += sh2.r[m] + 2;
+ sh2_icount--;
+}
+
+/* code cycles t-bit
+ * 1011 dddd dddd dddd 2 -
+ * BSR disp12
+ */
+INLINE void BSR(UINT32 d)
+{
+ INT32 disp = ((INT32)d << 20) >> 20;
+
+ sh2.pr = sh2.pc + 2;
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2_icount--;
+}
+
+/* code cycles t-bit
+ * 0000 mmmm 0000 0011 2 -
+ * BSRF Rm
+ */
+INLINE void BSRF(UINT32 m)
+{
+ sh2.pr = sh2.pc + 2;
+ sh2.delay = sh2.pc;
+ sh2.pc += sh2.r[m] + 2;
+ sh2_icount--;
+}
+
+/* code cycles t-bit
+ * 1000 1001 dddd dddd 3/1 -
+ * BT disp8
+ */
+INLINE void BT(UINT32 d)
+{
+ if ((sh2.sr & T) != 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ change_pc(sh2.pc & AM);
+ sh2_icount -= 2;
+ }
+}
+
+/* code cycles t-bit
+ * 1000 1101 dddd dddd 2/1 -
+ * BTS disp8
+ */
+INLINE void BTS(UINT32 d)
+{
+ if ((sh2.sr & T) != 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2_icount--;
+ }
+}
+
+/* code cycles t-bit
+ * 0000 0000 0010 1000 1 -
+ * CLRMAC
+ */
+INLINE void CLRMAC(void)
+{
+ sh2.mach = 0;
+ sh2.macl = 0;
+}
+
+/* code cycles t-bit
+ * 0000 0000 0000 1000 1 -
+ * CLRT
+ */
+INLINE void CLRT(void)
+{
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0000 1 comparison result
+ * CMP_EQ Rm,Rn
+ */
+INLINE void CMPEQ(UINT32 m, UINT32 n)
+{
+ if (sh2.r[n] == sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0011 1 comparison result
+ * CMP_GE Rm,Rn
+ */
+INLINE void CMPGE(UINT32 m, UINT32 n)
+{
+ if ((INT32) sh2.r[n] >= (INT32) sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0111 1 comparison result
+ * CMP_GT Rm,Rn
+ */
+INLINE void CMPGT(UINT32 m, UINT32 n)
+{
+ if ((INT32) sh2.r[n] > (INT32) sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0110 1 comparison result
+ * CMP_HI Rm,Rn
+ */
+INLINE void CMPHI(UINT32 m, UINT32 n)
+{
+ if ((UINT32) sh2.r[n] > (UINT32) sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0010 1 comparison result
+ * CMP_HS Rm,Rn
+ */
+INLINE void CMPHS(UINT32 m, UINT32 n)
+{
+ if ((UINT32) sh2.r[n] >= (UINT32) sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+
+/* code cycles t-bit
+ * 0100 nnnn 0001 0101 1 comparison result
+ * CMP_PL Rn
+ */
+INLINE void CMPPL(UINT32 n)
+{
+ if ((INT32) sh2.r[n] > 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0100 nnnn 0001 0001 1 comparison result
+ * CMP_PZ Rn
+ */
+INLINE void CMPPZ(UINT32 n)
+{
+ if ((INT32) sh2.r[n] >= 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 1100 1 comparison result
+ * CMP_STR Rm,Rn
+ */
+INLINE void CMPSTR(UINT32 m, UINT32 n)
+ {
+ UINT32 temp;
+ INT32 HH, HL, LH, LL;
+ temp = sh2.r[n] ^ sh2.r[m];
+ HH = (temp >> 24) & 0xff;
+ HL = (temp >> 16) & 0xff;
+ LH = (temp >> 8) & 0xff;
+ LL = temp & 0xff;
+ if (HH && HL && LH && LL)
+ sh2.sr &= ~T;
+ else
+ sh2.sr |= T;
+ }
+
+
+/* code cycles t-bit
+ * 1000 1000 iiii iiii 1 comparison result
+ * CMP/EQ #imm,R0
+ */
+INLINE void CMPIM(UINT32 i)
+{
+ UINT32 imm = (UINT32)(INT32)(INT16)(INT8)i;
+
+ if (sh2.r[0] == imm)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 0111 1 calculation result
+ * DIV0S Rm,Rn
+ */
+INLINE void DIV0S(UINT32 m, UINT32 n)
+{
+ if ((sh2.r[n] & 0x80000000) == 0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ if ((sh2.r[m] & 0x80000000) == 0)
+ sh2.sr &= ~M;
+ else
+ sh2.sr |= M;
+ if ((sh2.r[m] ^ sh2.r[n]) & 0x80000000)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0000 0000 0001 1001 1 0
+ * DIV0U
+ */
+INLINE void DIV0U(void)
+{
+ sh2.sr &= ~(M | Q | T);
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0100 1 calculation result
+ * DIV1 Rm,Rn
+ */
+INLINE void DIV1(UINT32 m, UINT32 n)
+{
+ UINT32 tmp0;
+ UINT32 old_q;
+
+ old_q = sh2.sr & Q;
+ if (0x80000000 & sh2.r[n])
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+
+ sh2.r[n] = (sh2.r[n] << 1) | (sh2.sr & T);
+
+ if (!old_q)
+ {
+ if (!(sh2.sr & M))
+ {
+ tmp0 = sh2.r[n];
+ sh2.r[n] -= sh2.r[m];
+ if(!(sh2.sr & Q))
+ if(sh2.r[n] > tmp0)
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+ else
+ if(sh2.r[n] > tmp0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ }
+ else
+ {
+ tmp0 = sh2.r[n];
+ sh2.r[n] += sh2.r[m];
+ if(!(sh2.sr & Q))
+ {
+ if(sh2.r[n] < tmp0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ }
+ else
+ {
+ if(sh2.r[n] < tmp0)
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+ }
+ }
+ }
+ else
+ {
+ if (!(sh2.sr & M))
+ {
+ tmp0 = sh2.r[n];
+ sh2.r[n] += sh2.r[m];
+ if(!(sh2.sr & Q))
+ if(sh2.r[n] < tmp0)
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+ else
+ if(sh2.r[n] < tmp0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ }
+ else
+ {
+ tmp0 = sh2.r[n];
+ sh2.r[n] -= sh2.r[m];
+ if(!(sh2.sr & Q))
+ if(sh2.r[n] > tmp0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ else
+ if(sh2.r[n] > tmp0)
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+ }
+ }
+
+ tmp0 = (sh2.sr & (Q | M));
+ if((!tmp0) || (tmp0 == 0x300)) /* if Q == M set T else clear T */
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* DMULS.L Rm,Rn */
+INLINE void DMULS(UINT32 m, UINT32 n)
+{
+ UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ UINT32 temp0, temp1, temp2, temp3;
+ INT32 tempm, tempn, fnLmL;
+
+ tempn = (INT32) sh2.r[n];
+ tempm = (INT32) sh2.r[m];
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ if ((INT32) (sh2.r[n] ^ sh2.r[m]) < 0)
+ fnLmL = -1;
+ else
+ fnLmL = 0;
+ temp1 = (UINT32) tempn;
+ temp2 = (UINT32) tempm;
+ RnL = temp1 & 0x0000ffff;
+ RnH = (temp1 >> 16) & 0x0000ffff;
+ RmL = temp2 & 0x0000ffff;
+ RmH = (temp2 >> 16) & 0x0000ffff;
+ temp0 = RmL * RnL;
+ temp1 = RmH * RnL;
+ temp2 = RmL * RnH;
+ temp3 = RmH * RnH;
+ Res2 = 0;
+ Res1 = temp1 + temp2;
+ if (Res1 < temp1)
+ Res2 += 0x00010000;
+ temp1 = (Res1 << 16) & 0xffff0000;
+ Res0 = temp0 + temp1;
+ if (Res0 < temp0)
+ Res2++;
+ Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3;
+ if (fnLmL < 0)
+ {
+ Res2 = ~Res2;
+ if (Res0 == 0)
+ Res2++;
+ else
+ Res0 = (~Res0) + 1;
+ }
+ sh2.mach = Res2;
+ sh2.macl = Res0;
+ sh2_icount--;
+}
+
+/* DMULU.L Rm,Rn */
+INLINE void DMULU(UINT32 m, UINT32 n)
+{
+ UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ UINT32 temp0, temp1, temp2, temp3;
+
+ RnL = sh2.r[n] & 0x0000ffff;
+ RnH = (sh2.r[n] >> 16) & 0x0000ffff;
+ RmL = sh2.r[m] & 0x0000ffff;
+ RmH = (sh2.r[m] >> 16) & 0x0000ffff;
+ temp0 = RmL * RnL;
+ temp1 = RmH * RnL;
+ temp2 = RmL * RnH;
+ temp3 = RmH * RnH;
+ Res2 = 0;
+ Res1 = temp1 + temp2;
+ if (Res1 < temp1)
+ Res2 += 0x00010000;
+ temp1 = (Res1 << 16) & 0xffff0000;
+ Res0 = temp0 + temp1;
+ if (Res0 < temp0)
+ Res2++;
+ Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3;
+ sh2.mach = Res2;
+ sh2.macl = Res0;
+ sh2_icount--;
+}
+
+/* DT Rn */
+INLINE void DT(UINT32 n)
+{
+ sh2.r[n]--;
+ if (sh2.r[n] == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+#if BUSY_LOOP_HACKS
+ {
+ UINT32 next_opcode = RW(sh2.ppc & AM);
+ /* DT Rn
+ * BF $-2
+ */
+ if (next_opcode == 0x8bfd)
+ {
+ while (sh2.r[n] > 1 && sh2_icount > 4)
+ {
+ sh2.r[n]--;
+ sh2_icount -= 4; /* cycles for DT (1) and BF taken (3) */
+ }
+ }
+ }
+#endif
+}
+
+/* EXTS.B Rm,Rn */
+INLINE void EXTSB(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = ((INT32)sh2.r[m] << 24) >> 24;
+}
+
+/* EXTS.W Rm,Rn */
+INLINE void EXTSW(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = ((INT32)sh2.r[m] << 16) >> 16;
+}
+
+/* EXTU.B Rm,Rn */
+INLINE void EXTUB(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = sh2.r[m] & 0x000000ff;
+}
+
+/* EXTU.W Rm,Rn */
+INLINE void EXTUW(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = sh2.r[m] & 0x0000ffff;
+}
+
+/* JMP @Rm */
+INLINE void JMP(UINT32 m)
+{
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.r[m];
+}
+
+/* JSR @Rm */
+INLINE void JSR(UINT32 m)
+{
+ sh2.delay = sh2.pc;
+ sh2.pr = sh2.pc + 2;
+ sh2.pc = sh2.ea = sh2.r[m];
+ sh2_icount--;
+}
+
+
+/* LDC Rm,SR */
+INLINE void LDCSR(UINT32 m)
+{
+ sh2.sr = sh2.r[m] & FLAGS;
+ sh2.test_irq = 1;
+}
+
+/* LDC Rm,GBR */
+INLINE void LDCGBR(UINT32 m)
+{
+ sh2.gbr = sh2.r[m];
+}
+
+/* LDC Rm,VBR */
+INLINE void LDCVBR(UINT32 m)
+{
+ sh2.vbr = sh2.r[m];
+}
+
+/* LDC.L @Rm+,SR */
+INLINE void LDCMSR(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.sr = RL( sh2.ea ) & FLAGS;
+ sh2.r[m] += 4;
+ sh2_icount -= 2;
+ sh2.test_irq = 1;
+}
+
+/* LDC.L @Rm+,GBR */
+INLINE void LDCMGBR(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.gbr = RL( sh2.ea );
+ sh2.r[m] += 4;
+ sh2_icount -= 2;
+}
+
+/* LDC.L @Rm+,VBR */
+INLINE void LDCMVBR(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.vbr = RL( sh2.ea );
+ sh2.r[m] += 4;
+ sh2_icount -= 2;
+}
+
+/* LDS Rm,MACH */
+INLINE void LDSMACH(UINT32 m)
+{
+ sh2.mach = sh2.r[m];
+}
+
+/* LDS Rm,MACL */
+INLINE void LDSMACL(UINT32 m)
+{
+ sh2.macl = sh2.r[m];
+}
+
+/* LDS Rm,PR */
+INLINE void LDSPR(UINT32 m)
+{
+ sh2.pr = sh2.r[m];
+}
+
+/* LDS.L @Rm+,MACH */
+INLINE void LDSMMACH(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.mach = RL( sh2.ea );
+ sh2.r[m] += 4;
+}
+
+/* LDS.L @Rm+,MACL */
+INLINE void LDSMMACL(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.macl = RL( sh2.ea );
+ sh2.r[m] += 4;
+}
+
+/* LDS.L @Rm+,PR */
+INLINE void LDSMPR(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.pr = RL( sh2.ea );
+ sh2.r[m] += 4;
+}
+
+/* MAC.L @Rm+,@Rn+ */
+INLINE void MAC_L(UINT32 m, UINT32 n)
+{
+ UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ UINT32 temp0, temp1, temp2, temp3;
+ INT32 tempm, tempn, fnLmL;
+
+ tempn = (INT32) RL( sh2.r[n] );
+ sh2.r[n] += 4;
+ tempm = (INT32) RL( sh2.r[m] );
+ sh2.r[m] += 4;
+ if ((INT32) (tempn ^ tempm) < 0)
+ fnLmL = -1;
+ else
+ fnLmL = 0;
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ temp1 = (UINT32) tempn;
+ temp2 = (UINT32) tempm;
+ RnL = temp1 & 0x0000ffff;
+ RnH = (temp1 >> 16) & 0x0000ffff;
+ RmL = temp2 & 0x0000ffff;
+ RmH = (temp2 >> 16) & 0x0000ffff;
+ temp0 = RmL * RnL;
+ temp1 = RmH * RnL;
+ temp2 = RmL * RnH;
+ temp3 = RmH * RnH;
+ Res2 = 0;
+ Res1 = temp1 + temp2;
+ if (Res1 < temp1)
+ Res2 += 0x00010000;
+ temp1 = (Res1 << 16) & 0xffff0000;
+ Res0 = temp0 + temp1;
+ if (Res0 < temp0)
+ Res2++;
+ Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3;
+ if (fnLmL < 0)
+ {
+ Res2 = ~Res2;
+ if (Res0 == 0)
+ Res2++;
+ else
+ Res0 = (~Res0) + 1;
+ }
+ if (sh2.sr & S)
+ {
+ Res0 = sh2.macl + Res0;
+ if (sh2.macl > Res0)
+ Res2++;
+ Res2 += (sh2.mach & 0x0000ffff);
+ if (((INT32) Res2 < 0) && (Res2 < 0xffff8000))
+ {
+ Res2 = 0x00008000;
+ Res0 = 0x00000000;
+ }
+ else if (((INT32) Res2 > 0) && (Res2 > 0x00007fff))
+ {
+ Res2 = 0x00007fff;
+ Res0 = 0xffffffff;
+ }
+ sh2.mach = Res2;
+ sh2.macl = Res0;
+ }
+ else
+ {
+ Res0 = sh2.macl + Res0;
+ if (sh2.macl > Res0)
+ Res2++;
+ Res2 += sh2.mach;
+ sh2.mach = Res2;
+ sh2.macl = Res0;
+ }
+ sh2_icount -= 2;
+}
+
+/* MAC.W @Rm+,@Rn+ */
+INLINE void MAC_W(UINT32 m, UINT32 n)
+{
+ INT32 tempm, tempn, dest, src, ans;
+ UINT32 templ;
+
+ tempn = (INT32) RW( sh2.r[n] );
+ sh2.r[n] += 2;
+ tempm = (INT32) RW( sh2.r[m] );
+ sh2.r[m] += 2;
+ templ = sh2.macl;
+ tempm = ((INT32) (short) tempn * (INT32) (short) tempm);
+ if ((INT32) sh2.macl >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((INT32) tempm >= 0)
+ {
+ src = 0;
+ tempn = 0;
+ }
+ else
+ {
+ src = 1;
+ tempn = 0xffffffff;
+ }
+ src += dest;
+ sh2.macl += tempm;
+ if ((INT32) sh2.macl >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (sh2.sr & S)
+ {
+ if (ans == 1)
+ {
+ if (src == 0)
+ sh2.macl = 0x7fffffff;
+ if (src == 2)
+ sh2.macl = 0x80000000;
+ }
+ }
+ else
+ {
+ sh2.mach += tempn;
+ if (templ > sh2.macl)
+ sh2.mach += 1;
+ }
+ sh2_icount -= 2;
+}
+
+/* MOV Rm,Rn */
+INLINE void MOV(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = sh2.r[m];
+}
+
+/* MOV.B Rm,@Rn */
+INLINE void MOVBS(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n];
+ WB( sh2.ea, sh2.r[m] & 0x000000ff);
+}
+
+/* MOV.W Rm,@Rn */
+INLINE void MOVWS(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n];
+ WW( sh2.ea, sh2.r[m] & 0x0000ffff);
+}
+
+/* MOV.L Rm,@Rn */
+INLINE void MOVLS(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.r[m] );
+}
+
+/* MOV.B @Rm,Rn */
+INLINE void MOVBL(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m];
+ sh2.r[n] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.ea );
+}
+
+/* MOV.W @Rm,Rn */
+INLINE void MOVWL(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m];
+ sh2.r[n] = (UINT32)(INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @Rm,Rn */
+INLINE void MOVLL(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m];
+ sh2.r[n] = RL( sh2.ea );
+}
+
+/* MOV.B Rm,@-Rn */
+INLINE void MOVBM(UINT32 m, UINT32 n)
+{
+ /* SMG : bug fix, was reading sh2.r[n] */
+ UINT32 data = sh2.r[m] & 0x000000ff;
+
+ sh2.r[n] -= 1;
+ WB( sh2.r[n], data );
+}
+
+/* MOV.W Rm,@-Rn */
+INLINE void MOVWM(UINT32 m, UINT32 n)
+{
+ UINT32 data = sh2.r[m] & 0x0000ffff;
+
+ sh2.r[n] -= 2;
+ WW( sh2.r[n], data );
+}
+
+/* MOV.L Rm,@-Rn */
+INLINE void MOVLM(UINT32 m, UINT32 n)
+{
+ UINT32 data = sh2.r[m];
+
+ sh2.r[n] -= 4;
+ WL( sh2.r[n], data );
+}
+
+/* MOV.B @Rm+,Rn */
+INLINE void MOVBP(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.r[m] );
+ if (n != m)
+ sh2.r[m] += 1;
+}
+
+/* MOV.W @Rm+,Rn */
+INLINE void MOVWP(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = (UINT32)(INT32)(INT16) RW( sh2.r[m] );
+ if (n != m)
+ sh2.r[m] += 2;
+}
+
+/* MOV.L @Rm+,Rn */
+INLINE void MOVLP(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = RL( sh2.r[m] );
+ if (n != m)
+ sh2.r[m] += 4;
+}
+
+/* MOV.B Rm,@(R0,Rn) */
+INLINE void MOVBS0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n] + sh2.r[0];
+ WB( sh2.ea, sh2.r[m] & 0x000000ff );
+}
+
+/* MOV.W Rm,@(R0,Rn) */
+INLINE void MOVWS0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n] + sh2.r[0];
+ WW( sh2.ea, sh2.r[m] & 0x0000ffff );
+}
+
+/* MOV.L Rm,@(R0,Rn) */
+INLINE void MOVLS0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n] + sh2.r[0];
+ WL( sh2.ea, sh2.r[m] );
+}
+
+/* MOV.B @(R0,Rm),Rn */
+INLINE void MOVBL0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m] + sh2.r[0];
+ sh2.r[n] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.ea );
+}
+
+/* MOV.W @(R0,Rm),Rn */
+INLINE void MOVWL0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m] + sh2.r[0];
+ sh2.r[n] = (UINT32)(INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @(R0,Rm),Rn */
+INLINE void MOVLL0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m] + sh2.r[0];
+ sh2.r[n] = RL( sh2.ea );
+}
+
+/* MOV #imm,Rn */
+INLINE void MOVI(UINT32 i, UINT32 n)
+{
+ sh2.r[n] = (UINT32)(INT32)(INT16)(INT8) i;
+}
+
+/* MOV.W @(disp8,PC),Rn */
+INLINE void MOVWI(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2.r[n] = (UINT32)(INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @(disp8,PC),Rn */
+INLINE void MOVLI(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = ((sh2.pc + 2) & ~3) + disp * 4;
+ sh2.r[n] = RL( sh2.ea );
+}
+
+/* MOV.B @(disp8,GBR),R0 */
+INLINE void MOVBLG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp;
+ sh2.r[0] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.ea );
+}
+
+/* MOV.W @(disp8,GBR),R0 */
+INLINE void MOVWLG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp * 2;
+ sh2.r[0] = (INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @(disp8,GBR),R0 */
+INLINE void MOVLLG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp * 4;
+ sh2.r[0] = RL( sh2.ea );
+}
+
+/* MOV.B R0,@(disp8,GBR) */
+INLINE void MOVBSG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp;
+ WB( sh2.ea, sh2.r[0] & 0x000000ff );
+}
+
+/* MOV.W R0,@(disp8,GBR) */
+INLINE void MOVWSG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp * 2;
+ WW( sh2.ea, sh2.r[0] & 0x0000ffff );
+}
+
+/* MOV.L R0,@(disp8,GBR) */
+INLINE void MOVLSG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp * 4;
+ WL( sh2.ea, sh2.r[0] );
+}
+
+/* MOV.B R0,@(disp4,Rn) */
+INLINE void MOVBS4(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[n] + disp;
+ WB( sh2.ea, sh2.r[0] & 0x000000ff );
+}
+
+/* MOV.W R0,@(disp4,Rn) */
+INLINE void MOVWS4(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[n] + disp * 2;
+ WW( sh2.ea, sh2.r[0] & 0x0000ffff );
+}
+
+/* MOV.L Rm,@(disp4,Rn) */
+INLINE void MOVLS4(UINT32 m, UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[n] + disp * 4;
+ WL( sh2.ea, sh2.r[m] );
+}
+
+/* MOV.B @(disp4,Rm),R0 */
+INLINE void MOVBL4(UINT32 m, UINT32 d)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[m] + disp;
+ sh2.r[0] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.ea );
+}
+
+/* MOV.W @(disp4,Rm),R0 */
+INLINE void MOVWL4(UINT32 m, UINT32 d)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[m] + disp * 2;
+ sh2.r[0] = (UINT32)(INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @(disp4,Rm),Rn */
+INLINE void MOVLL4(UINT32 m, UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[m] + disp * 4;
+ sh2.r[n] = RL( sh2.ea );
+}
+
+/* MOVA @(disp8,PC),R0 */
+INLINE void MOVA(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = ((sh2.pc + 2) & ~3) + disp * 4;
+ sh2.r[0] = sh2.ea;
+}
+
+/* MOVT Rn */
+INLINE void MOVT(UINT32 n)
+{
+ sh2.r[n] = sh2.sr & T;
+}
+
+/* MUL.L Rm,Rn */
+INLINE void MULL(UINT32 m, UINT32 n)
+{
+ sh2.macl = sh2.r[n] * sh2.r[m];
+ sh2_icount--;
+}
+
+/* MULS Rm,Rn */
+INLINE void MULS(UINT32 m, UINT32 n)
+{
+ sh2.macl = (INT16) sh2.r[n] * (INT16) sh2.r[m];
+}
+
+/* MULU Rm,Rn */
+INLINE void MULU(UINT32 m, UINT32 n)
+{
+ sh2.macl = (UINT16) sh2.r[n] * (UINT16) sh2.r[m];
+}
+
+/* NEG Rm,Rn */
+INLINE void NEG(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = 0 - sh2.r[m];
+}
+
+/* NEGC Rm,Rn */
+INLINE void NEGC(UINT32 m, UINT32 n)
+{
+ UINT32 temp;
+
+ temp = sh2.r[m];
+ sh2.r[n] = -temp - (sh2.sr & T);
+ if (temp || (sh2.sr & T))
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* NOP */
+INLINE void NOP(void)
+{
+}
+
+/* NOT Rm,Rn */
+INLINE void NOT(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = ~sh2.r[m];
+}
+
+/* OR Rm,Rn */
+INLINE void OR(UINT32 m, UINT32 n)
+{
+ sh2.r[n] |= sh2.r[m];
+}
+
+/* OR #imm,R0 */
+INLINE void ORI(UINT32 i)
+{
+ sh2.r[0] |= i;
+ sh2_icount -= 2;
+}
+
+/* OR.B #imm,@(R0,GBR) */
+INLINE void ORM(UINT32 i)
+{
+ UINT32 temp;
+
+ sh2.ea = sh2.gbr + sh2.r[0];
+ temp = RB( sh2.ea );
+ temp |= i;
+ WB( sh2.ea, temp );
+}
+
+/* ROTCL Rn */
+INLINE void ROTCL(UINT32 n)
+{
+ UINT32 temp;
+
+ temp = (sh2.r[n] >> 31) & T;
+ sh2.r[n] = (sh2.r[n] << 1) | (sh2.sr & T);
+ sh2.sr = (sh2.sr & ~T) | temp;
+}
+
+/* ROTCR Rn */
+INLINE void ROTCR(UINT32 n)
+{
+ UINT32 temp;
+ temp = (sh2.sr & T) << 31;
+ if (sh2.r[n] & T)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ sh2.r[n] = (sh2.r[n] >> 1) | temp;
+}
+
+/* ROTL Rn */
+INLINE void ROTL(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | ((sh2.r[n] >> 31) & T);
+ sh2.r[n] = (sh2.r[n] << 1) | (sh2.r[n] >> 31);
+}
+
+/* ROTR Rn */
+INLINE void ROTR(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | (sh2.r[n] & T);
+ sh2.r[n] = (sh2.r[n] >> 1) | (sh2.r[n] << 31);
+}
+
+/* RTE */
+INLINE void RTE(void)
+{
+ sh2.ea = sh2.r[15];
+ sh2.delay = sh2.pc;
+ sh2.pc = RL( sh2.ea );
+ sh2.r[15] += 4;
+ sh2.ea = sh2.r[15];
+ sh2.sr = RL( sh2.ea ) & FLAGS;
+ sh2.r[15] += 4;
+ sh2_icount -= 3;
+ sh2.test_irq = 1;
+}
+
+/* RTS */
+INLINE void RTS(void)
+{
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pr;
+ sh2_icount--;
+}
+
+/* SETT */
+INLINE void SETT(void)
+{
+ sh2.sr |= T;
+}
+
+/* SHAL Rn (same as SHLL) */
+INLINE void SHAL(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | ((sh2.r[n] >> 31) & T);
+ sh2.r[n] <<= 1;
+}
+
+/* SHAR Rn */
+INLINE void SHAR(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | (sh2.r[n] & T);
+ sh2.r[n] = (UINT32)((INT32)sh2.r[n] >> 1);
+}
+
+/* SHLL Rn (same as SHAL) */
+INLINE void SHLL(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | ((sh2.r[n] >> 31) & T);
+ sh2.r[n] <<= 1;
+}
+
+/* SHLL2 Rn */
+INLINE void SHLL2(UINT32 n)
+{
+ sh2.r[n] <<= 2;
+}
+
+/* SHLL8 Rn */
+INLINE void SHLL8(UINT32 n)
+{
+ sh2.r[n] <<= 8;
+}
+
+/* SHLL16 Rn */
+INLINE void SHLL16(UINT32 n)
+{
+ sh2.r[n] <<= 16;
+}
+
+/* SHLR Rn */
+INLINE void SHLR(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | (sh2.r[n] & T);
+ sh2.r[n] >>= 1;
+}
+
+/* SHLR2 Rn */
+INLINE void SHLR2(UINT32 n)
+{
+ sh2.r[n] >>= 2;
+}
+
+/* SHLR8 Rn */
+INLINE void SHLR8(UINT32 n)
+{
+ sh2.r[n] >>= 8;
+}
+
+/* SHLR16 Rn */
+INLINE void SHLR16(UINT32 n)
+{
+ sh2.r[n] >>= 16;
+}
+
+/* SLEEP */
+INLINE void SLEEP(void)
+{
+ sh2.pc -= 2;
+ sh2_icount -= 2;
+ /* Wait_for_exception; */
+}
+
+/* STC SR,Rn */
+INLINE void STCSR(UINT32 n)
+{
+ sh2.r[n] = sh2.sr;
+}
+
+/* STC GBR,Rn */
+INLINE void STCGBR(UINT32 n)
+{
+ sh2.r[n] = sh2.gbr;
+}
+
+/* STC VBR,Rn */
+INLINE void STCVBR(UINT32 n)
+{
+ sh2.r[n] = sh2.vbr;
+}
+
+/* STC.L SR,@-Rn */
+INLINE void STCMSR(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.sr );
+ sh2_icount--;
+}
+
+/* STC.L GBR,@-Rn */
+INLINE void STCMGBR(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.gbr );
+ sh2_icount--;
+}
+
+/* STC.L VBR,@-Rn */
+INLINE void STCMVBR(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.vbr );
+ sh2_icount--;
+}
+
+/* STS MACH,Rn */
+INLINE void STSMACH(UINT32 n)
+{
+ sh2.r[n] = sh2.mach;
+}
+
+/* STS MACL,Rn */
+INLINE void STSMACL(UINT32 n)
+{
+ sh2.r[n] = sh2.macl;
+}
+
+/* STS PR,Rn */
+INLINE void STSPR(UINT32 n)
+{
+ sh2.r[n] = sh2.pr;
+}
+
+/* STS.L MACH,@-Rn */
+INLINE void STSMMACH(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.mach );
+}
+
+/* STS.L MACL,@-Rn */
+INLINE void STSMMACL(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.macl );
+}
+
+/* STS.L PR,@-Rn */
+INLINE void STSMPR(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.pr );
+}
+
+/* SUB Rm,Rn */
+INLINE void SUB(UINT32 m, UINT32 n)
+{
+ sh2.r[n] -= sh2.r[m];
+}
+
+/* SUBC Rm,Rn */
+INLINE void SUBC(UINT32 m, UINT32 n)
+{
+ UINT32 tmp0, tmp1;
+
+ tmp1 = sh2.r[n] - sh2.r[m];
+ tmp0 = sh2.r[n];
+ sh2.r[n] = tmp1 - (sh2.sr & T);
+ if (tmp0 < tmp1)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ if (tmp1 < sh2.r[n])
+ sh2.sr |= T;
+}
+
+/* SUBV Rm,Rn */
+INLINE void SUBV(UINT32 m, UINT32 n)
+{
+ INT32 dest, src, ans;
+
+ if ((INT32) sh2.r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((INT32) sh2.r[m] >= 0)
+ src = 0;
+ else
+ src = 1;
+ src += dest;
+ sh2.r[n] -= sh2.r[m];
+ if ((INT32) sh2.r[n] >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (src == 1)
+ {
+ if (ans == 1)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ }
+ else
+ sh2.sr &= ~T;
+}
+
+/* SWAP.B Rm,Rn */
+INLINE void SWAPB(UINT32 m, UINT32 n)
+{
+ UINT32 temp0, temp1;
+
+ temp0 = sh2.r[m] & 0xffff0000;
+ temp1 = (sh2.r[m] & 0x000000ff) << 8;
+ sh2.r[n] = (sh2.r[m] >> 8) & 0x000000ff;
+ sh2.r[n] = sh2.r[n] | temp1 | temp0;
+}
+
+/* SWAP.W Rm,Rn */
+INLINE void SWAPW(UINT32 m, UINT32 n)
+{
+ UINT32 temp;
+
+ temp = (sh2.r[m] >> 16) & 0x0000ffff;
+ sh2.r[n] = (sh2.r[m] << 16) | temp;
+}
+
+/* TAS.B @Rn */
+INLINE void TAS(UINT32 n)
+{
+ UINT32 temp;
+ sh2.ea = sh2.r[n];
+ /* Bus Lock enable */
+ temp = RB( sh2.ea );
+ if (temp == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ temp |= 0x80;
+ /* Bus Lock disable */
+ WB( sh2.ea, temp );
+ sh2_icount -= 3;
+}
+
+/* TRAPA #imm */
+INLINE void TRAPA(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+
+ sh2.ea = sh2.vbr + imm * 4;
+
+ sh2.r[15] -= 4;
+ WL( sh2.r[15], sh2.sr );
+ sh2.r[15] -= 4;
+ WL( sh2.r[15], sh2.pc );
+
+ sh2.pc = RL( sh2.ea );
+ change_pc(sh2.pc & AM);
+
+ sh2_icount -= 7;
+}
+
+/* TST Rm,Rn */
+INLINE void TST(UINT32 m, UINT32 n)
+{
+ if ((sh2.r[n] & sh2.r[m]) == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* TST #imm,R0 */
+INLINE void TSTI(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+
+ if ((imm & sh2.r[0]) == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* TST.B #imm,@(R0,GBR) */
+INLINE void TSTM(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+
+ sh2.ea = sh2.gbr + sh2.r[0];
+ if ((imm & RB( sh2.ea )) == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ sh2_icount -= 2;
+}
+
+/* XOR Rm,Rn */
+INLINE void XOR(UINT32 m, UINT32 n)
+{
+ sh2.r[n] ^= sh2.r[m];
+}
+
+/* XOR #imm,R0 */
+INLINE void XORI(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+ sh2.r[0] ^= imm;
+}
+
+/* XOR.B #imm,@(R0,GBR) */
+INLINE void XORM(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+ UINT32 temp;
+
+ sh2.ea = sh2.gbr + sh2.r[0];
+ temp = RB( sh2.ea );
+ temp ^= imm;
+ WB( sh2.ea, temp );
+ sh2_icount -= 2;
+}
+
+/* XTRCT Rm,Rn */
+INLINE void XTRCT(UINT32 m, UINT32 n)
+{
+ UINT32 temp;
+
+ temp = (sh2.r[m] << 16) & 0xffff0000;
+ sh2.r[n] = (sh2.r[n] >> 16) & 0x0000ffff;
+ sh2.r[n] |= temp;
+}
+
+/*****************************************************************************
+ * OPCODE DISPATCHERS
+ *****************************************************************************/
+
+INLINE void op0000(UINT16 opcode)
+{
+ switch (opcode & 0x3F)
+ {
+ case 0x00: NOP(); break;
+ case 0x01: NOP(); break;
+ case 0x02: STCSR(Rn); break;
+ case 0x03: BSRF(Rn); break;
+ case 0x04: MOVBS0(Rm, Rn); break;
+ case 0x05: MOVWS0(Rm, Rn); break;
+ case 0x06: MOVLS0(Rm, Rn); break;
+ case 0x07: MULL(Rm, Rn); break;
+ case 0x08: CLRT(); break;
+ case 0x09: NOP(); break;
+ case 0x0a: STSMACH(Rn); break;
+ case 0x0b: RTS(); break;
+ case 0x0c: MOVBL0(Rm, Rn); break;
+ case 0x0d: MOVWL0(Rm, Rn); break;
+ case 0x0e: MOVLL0(Rm, Rn); break;
+ case 0x0f: MAC_L(Rm, Rn); break;
+
+ case 0x10: NOP(); break;
+ case 0x11: NOP(); break;
+ case 0x12: STCGBR(Rn); break;
+ case 0x13: NOP(); break;
+ case 0x14: MOVBS0(Rm, Rn); break;
+ case 0x15: MOVWS0(Rm, Rn); break;
+ case 0x16: MOVLS0(Rm, Rn); break;
+ case 0x17: MULL(Rm, Rn); break;
+ case 0x18: SETT(); break;
+ case 0x19: DIV0U(); break;
+ case 0x1a: STSMACL(Rn); break;
+ case 0x1b: SLEEP(); break;
+ case 0x1c: MOVBL0(Rm, Rn); break;
+ case 0x1d: MOVWL0(Rm, Rn); break;
+ case 0x1e: MOVLL0(Rm, Rn); break;
+ case 0x1f: MAC_L(Rm, Rn); break;
+
+ case 0x20: NOP(); break;
+ case 0x21: NOP(); break;
+ case 0x22: STCVBR(Rn); break;
+ case 0x23: BRAF(Rn); break;
+ case 0x24: MOVBS0(Rm, Rn); break;
+ case 0x25: MOVWS0(Rm, Rn); break;
+ case 0x26: MOVLS0(Rm, Rn); break;
+ case 0x27: MULL(Rm, Rn); break;
+ case 0x28: CLRMAC(); break;
+ case 0x29: MOVT(Rn); break;
+ case 0x2a: STSPR(Rn); break;
+ case 0x2b: RTE(); break;
+ case 0x2c: MOVBL0(Rm, Rn); break;
+ case 0x2d: MOVWL0(Rm, Rn); break;
+ case 0x2e: MOVLL0(Rm, Rn); break;
+ case 0x2f: MAC_L(Rm, Rn); break;
+
+ case 0x30: NOP(); break;
+ case 0x31: NOP(); break;
+ case 0x32: NOP(); break;
+ case 0x33: NOP(); break;
+ case 0x34: MOVBS0(Rm, Rn); break;
+ case 0x35: MOVWS0(Rm, Rn); break;
+ case 0x36: MOVLS0(Rm, Rn); break;
+ case 0x37: MULL(Rm, Rn); break;
+ case 0x38: NOP(); break;
+ case 0x39: NOP(); break;
+ case 0x3c: MOVBL0(Rm, Rn); break;
+ case 0x3d: MOVWL0(Rm, Rn); break;
+ case 0x3e: MOVLL0(Rm, Rn); break;
+ case 0x3f: MAC_L(Rm, Rn); break;
+ case 0x3a: NOP(); break;
+ case 0x3b: NOP(); break;
+
+
+
+ }
+}
+
+INLINE void op0001(UINT16 opcode)
+{
+ MOVLS4(Rm, opcode & 0x0f, Rn);
+}
+
+INLINE void op0010(UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: MOVBS(Rm, Rn); break;
+ case 1: MOVWS(Rm, Rn); break;
+ case 2: MOVLS(Rm, Rn); break;
+ case 3: NOP(); break;
+ case 4: MOVBM(Rm, Rn); break;
+ case 5: MOVWM(Rm, Rn); break;
+ case 6: MOVLM(Rm, Rn); break;
+ case 7: DIV0S(Rm, Rn); break;
+ case 8: TST(Rm, Rn); break;
+ case 9: AND(Rm, Rn); break;
+ case 10: XOR(Rm, Rn); break;
+ case 11: OR(Rm, Rn); break;
+ case 12: CMPSTR(Rm, Rn); break;
+ case 13: XTRCT(Rm, Rn); break;
+ case 14: MULU(Rm, Rn); break;
+ case 15: MULS(Rm, Rn); break;
+ }
+}
+
+INLINE void op0011(UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: CMPEQ(Rm, Rn); break;
+ case 1: NOP(); break;
+ case 2: CMPHS(Rm, Rn); break;
+ case 3: CMPGE(Rm, Rn); break;
+ case 4: DIV1(Rm, Rn); break;
+ case 5: DMULU(Rm, Rn); break;
+ case 6: CMPHI(Rm, Rn); break;
+ case 7: CMPGT(Rm, Rn); break;
+ case 8: SUB(Rm, Rn); break;
+ case 9: NOP(); break;
+ case 10: SUBC(Rm, Rn); break;
+ case 11: SUBV(Rm, Rn); break;
+ case 12: ADD(Rm, Rn); break;
+ case 13: DMULS(Rm, Rn); break;
+ case 14: ADDC(Rm, Rn); break;
+ case 15: ADDV(Rm, Rn); break;
+ }
+}
+
+INLINE void op0100(UINT16 opcode)
+{
+ switch (opcode & 0x3F)
+ {
+ case 0x00: SHLL(Rn); break;
+ case 0x01: SHLR(Rn); break;
+ case 0x02: STSMMACH(Rn); break;
+ case 0x03: STCMSR(Rn); break;
+ case 0x04: ROTL(Rn); break;
+ case 0x05: ROTR(Rn); break;
+ case 0x06: LDSMMACH(Rn); break;
+ case 0x07: LDCMSR(Rn); break;
+ case 0x08: SHLL2(Rn); break;
+ case 0x09: SHLR2(Rn); break;
+ case 0x0a: LDSMACH(Rn); break;
+ case 0x0b: JSR(Rn); break;
+ case 0x0c: NOP(); break;
+ case 0x0d: NOP(); break;
+ case 0x0e: LDCSR(Rn); break;
+ case 0x0f: MAC_W(Rm, Rn); break;
+
+ case 0x10: DT(Rn); break;
+ case 0x11: CMPPZ(Rn); break;
+ case 0x12: STSMMACL(Rn); break;
+ case 0x13: STCMGBR(Rn); break;
+ case 0x14: NOP(); break;
+ case 0x15: CMPPL(Rn); break;
+ case 0x16: LDSMMACL(Rn); break;
+ case 0x17: LDCMGBR(Rn); break;
+ case 0x18: SHLL8(Rn); break;
+ case 0x19: SHLR8(Rn); break;
+ case 0x1a: LDSMACL(Rn); break;
+ case 0x1b: TAS(Rn); break;
+ case 0x1c: NOP(); break;
+ case 0x1d: NOP(); break;
+ case 0x1e: LDCGBR(Rn); break;
+ case 0x1f: MAC_W(Rm, Rn); break;
+
+ case 0x20: SHAL(Rn); break;
+ case 0x21: SHAR(Rn); break;
+ case 0x22: STSMPR(Rn); break;
+ case 0x23: STCMVBR(Rn); break;
+ case 0x24: ROTCL(Rn); break;
+ case 0x25: ROTCR(Rn); break;
+ case 0x26: LDSMPR(Rn); break;
+ case 0x27: LDCMVBR(Rn); break;
+ case 0x28: SHLL16(Rn); break;
+ case 0x29: SHLR16(Rn); break;
+ case 0x2a: LDSPR(Rn); break;
+ case 0x2b: JMP(Rn); break;
+ case 0x2c: NOP(); break;
+ case 0x2d: NOP(); break;
+ case 0x2e: LDCVBR(Rn); break;
+ case 0x2f: MAC_W(Rm, Rn); break;
+
+ case 0x30: NOP(); break;
+ case 0x31: NOP(); break;
+ case 0x32: NOP(); break;
+ case 0x33: NOP(); break;
+ case 0x34: NOP(); break;
+ case 0x35: NOP(); break;
+ case 0x36: NOP(); break;
+ case 0x37: NOP(); break;
+ case 0x38: NOP(); break;
+ case 0x39: NOP(); break;
+ case 0x3a: NOP(); break;
+ case 0x3b: NOP(); break;
+ case 0x3c: NOP(); break;
+ case 0x3d: NOP(); break;
+ case 0x3e: NOP(); break;
+ case 0x3f: MAC_W(Rm, Rn); break;
+
+ }
+}
+
+INLINE void op0101(UINT16 opcode)
+{
+ MOVLL4(Rm, opcode & 0x0f, Rn);
+}
+
+INLINE void op0110(UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: MOVBL(Rm, Rn); break;
+ case 1: MOVWL(Rm, Rn); break;
+ case 2: MOVLL(Rm, Rn); break;
+ case 3: MOV(Rm, Rn); break;
+ case 4: MOVBP(Rm, Rn); break;
+ case 5: MOVWP(Rm, Rn); break;
+ case 6: MOVLP(Rm, Rn); break;
+ case 7: NOT(Rm, Rn); break;
+ case 8: SWAPB(Rm, Rn); break;
+ case 9: SWAPW(Rm, Rn); break;
+ case 10: NEGC(Rm, Rn); break;
+ case 11: NEG(Rm, Rn); break;
+ case 12: EXTUB(Rm, Rn); break;
+ case 13: EXTUW(Rm, Rn); break;
+ case 14: EXTSB(Rm, Rn); break;
+ case 15: EXTSW(Rm, Rn); break;
+ }
+}
+
+INLINE void op0111(UINT16 opcode)
+{
+ ADDI(opcode & 0xff, Rn);
+}
+
+INLINE void op1000(UINT16 opcode)
+{
+ switch ( opcode & (15<<8) )
+ {
+ case 0 << 8: MOVBS4(opcode & 0x0f, Rm); break;
+ case 1 << 8: MOVWS4(opcode & 0x0f, Rm); break;
+ case 2<< 8: NOP(); break;
+ case 3<< 8: NOP(); break;
+ case 4<< 8: MOVBL4(Rm, opcode & 0x0f); break;
+ case 5<< 8: MOVWL4(Rm, opcode & 0x0f); break;
+ case 6<< 8: NOP(); break;
+ case 7<< 8: NOP(); break;
+ case 8<< 8: CMPIM(opcode & 0xff); break;
+ case 9<< 8: BT(opcode & 0xff); break;
+ case 10<< 8: NOP(); break;
+ case 11<< 8: BF(opcode & 0xff); break;
+ case 12<< 8: NOP(); break;
+ case 13<< 8: BTS(opcode & 0xff); break;
+ case 14<< 8: NOP(); break;
+ case 15<< 8: BFS(opcode & 0xff); break;
+ }
+}
+
+
+INLINE void op1001(UINT16 opcode)
+{
+ MOVWI(opcode & 0xff, Rn);
+}
+
+INLINE void op1010(UINT16 opcode)
+{
+ BRA(opcode & 0xfff);
+}
+
+INLINE void op1011(UINT16 opcode)
+{
+ BSR(opcode & 0xfff);
+}
+
+INLINE void op1100(UINT16 opcode)
+{
+ switch (opcode & (15<<8))
+ {
+ case 0<<8: MOVBSG(opcode & 0xff); break;
+ case 1<<8: MOVWSG(opcode & 0xff); break;
+ case 2<<8: MOVLSG(opcode & 0xff); break;
+ case 3<<8: TRAPA(opcode & 0xff); break;
+ case 4<<8: MOVBLG(opcode & 0xff); break;
+ case 5<<8: MOVWLG(opcode & 0xff); break;
+ case 6<<8: MOVLLG(opcode & 0xff); break;
+ case 7<<8: MOVA(opcode & 0xff); break;
+ case 8<<8: TSTI(opcode & 0xff); break;
+ case 9<<8: ANDI(opcode & 0xff); break;
+ case 10<<8: XORI(opcode & 0xff); break;
+ case 11<<8: ORI(opcode & 0xff); break;
+ case 12<<8: TSTM(opcode & 0xff); break;
+ case 13<<8: ANDM(opcode & 0xff); break;
+ case 14<<8: XORM(opcode & 0xff); break;
+ case 15<<8: ORM(opcode & 0xff); break;
+ }
+}
+
+INLINE void op1101(UINT16 opcode)
+{
+ MOVLI(opcode & 0xff, Rn);
+}
+
+INLINE void op1110(UINT16 opcode)
+{
+ MOVI(opcode & 0xff, Rn);
+}
+
+INLINE void op1111(UINT16 opcode)
+{
+ NOP();
+}
+
+/*****************************************************************************
+ * MAME CPU INTERFACE
+ *****************************************************************************/
+
+static void sh2_reset(void)
+{
+ void *tsave, *tsaved0, *tsaved1;
+ UINT32 *m;
+ int cpunum;
+ int save_is_slave;
+
+ void (*f)(UINT32 data);
+ int (*save_irqcallback)(int);
+
+ cpunum = sh2.cpu_number;
+ m = sh2.m;
+ tsave = sh2.timer;
+ tsaved0 = sh2.dma_timer[0];
+ tsaved1 = sh2.dma_timer[1];
+
+ f = sh2.ftcsr_read_callback;
+ save_irqcallback = sh2.irq_callback;
+ save_is_slave = sh2.is_slave;
+ memset(&sh2, 0, sizeof(SH2));
+ sh2.is_slave = save_is_slave;
+ sh2.ftcsr_read_callback = f;
+ sh2.irq_callback = save_irqcallback;
+
+ sh2.timer = tsave;
+ sh2.dma_timer[0] = tsaved0;
+ sh2.dma_timer[1] = tsaved1;
+ sh2.cpu_number = cpunum;
+ sh2.m = m;
+ memset(sh2.m, 0, 0x200);
+
+ sh2.pc = RL(0);
+ sh2.r[15] = RL(4);
+ sh2.sr = I;
+ change_pc(sh2.pc & AM);
+
+ sh2.internal_irq_level = -1;
+}
+
+/* Execute cycles - returns number of cycles actually run */
+static int sh2_execute(int cycles)
+{
+ sh2_icount = cycles;
+
+ if (sh2.cpu_off)
+ return 0;
+
+ do
+ {
+ UINT32 opcode;
+
+ if (sh2.delay)
+ {
+ opcode = cpu_readop16(WORD_XOR_BE((UINT32)(sh2.delay & AM)));
+ change_pc(sh2.pc & AM);
+ sh2.pc -= 2;
+ }
+ else
+ opcode = cpu_readop16(WORD_XOR_BE((UINT32)(sh2.pc & AM)));
+
+ CALL_MAME_DEBUG;
+
+ sh2.delay = 0;
+ sh2.pc += 2;
+ sh2.ppc = sh2.pc;
+
+ switch (opcode & ( 15 << 12))
+ {
+ case 0<<12: op0000(opcode); break;
+ case 1<<12: op0001(opcode); break;
+ case 2<<12: op0010(opcode); break;
+ case 3<<12: op0011(opcode); break;
+ case 4<<12: op0100(opcode); break;
+ case 5<<12: op0101(opcode); break;
+ case 6<<12: op0110(opcode); break;
+ case 7<<12: op0111(opcode); break;
+ case 8<<12: op1000(opcode); break;
+ case 9<<12: op1001(opcode); break;
+ case 10<<12: op1010(opcode); break;
+ case 11<<12: op1011(opcode); break;
+ case 12<<12: op1100(opcode); break;
+ case 13<<12: op1101(opcode); break;
+ case 14<<12: op1110(opcode); break;
+ default: op1111(opcode); break;
+ }
+
+ if(sh2.test_irq && !sh2.delay)
+ {
+ CHECK_PENDING_IRQ("mame_sh2_execute");
+ sh2.test_irq = 0;
+ }
+ sh2_icount--;
+ } while( sh2_icount > 0 );
+
+ return cycles - sh2_icount;
+}
+
+/* Get registers, return context size */
+static void sh2_get_context(void *dst)
+{
+ if( dst )
+ memcpy(dst, &sh2, sizeof(SH2));
+}
+
+/* Set registers */
+static void sh2_set_context(void *src)
+{
+ if( src )
+ memcpy(&sh2, src, sizeof(SH2));
+}
+
+static void sh2_timer_resync(void)
+{
+ int divider = div_tab[(sh2.m[5] >> 8) & 3];
+ UINT32 cur_time = cpunum_gettotalcycles(sh2.cpu_number);
+
+ if(divider)
+ sh2.frc += (cur_time - sh2.frc_base) >> divider;
+ sh2.frc_base = cur_time;
+}
+
+static void sh2_timer_activate(void)
+{
+ int max_delta = 0xfffff;
+ UINT16 frc;
+
+ timer_adjust(sh2.timer, attotime_never, 0, attotime_zero);
+
+ frc = sh2.frc;
+ if(!(sh2.m[4] & OCFA)) {
+ UINT16 delta = sh2.ocra - frc;
+ if(delta < max_delta)
+ max_delta = delta;
+ }
+
+ if(!(sh2.m[4] & OCFB) && (sh2.ocra <= sh2.ocrb || !(sh2.m[4] & 0x010000))) {
+ UINT16 delta = sh2.ocrb - frc;
+ if(delta < max_delta)
+ max_delta = delta;
+ }
+
+ if(!(sh2.m[4] & OVF) && !(sh2.m[4] & 0x010000)) {
+ int delta = 0x10000 - frc;
+ if(delta < max_delta)
+ max_delta = delta;
+ }
+
+ if(max_delta != 0xfffff) {
+ int divider = div_tab[(sh2.m[5] >> 8) & 3];
+ if(divider) {
+ max_delta <<= divider;
+ sh2.frc_base = cpunum_gettotalcycles(sh2.cpu_number);
+ timer_adjust(sh2.timer, ATTOTIME_IN_CYCLES(max_delta, sh2.cpu_number), sh2.cpu_number, attotime_zero);
+ } else {
+ logerror("SH2.%d: Timer event in %d cycles of external clock", sh2.cpu_number, max_delta);
+ }
+ }
+}
+
+static void sh2_recalc_irq(void)
+{
+ int irq = 0, vector = -1;
+ int level;
+
+ // Timer irqs
+ if((sh2.m[4]>>8) & sh2.m[4] & (ICF|OCFA|OCFB|OVF))
+ {
+ level = (sh2.m[0x18] >> 24) & 15;
+ if(level > irq)
+ {
+ int mask = (sh2.m[4]>>8) & sh2.m[4];
+ irq = level;
+ if(mask & ICF)
+ vector = (sh2.m[0x19] >> 8) & 0x7f;
+ else if(mask & (OCFA|OCFB))
+ vector = sh2.m[0x19] & 0x7f;
+ else
+ vector = (sh2.m[0x1a] >> 24) & 0x7f;
+ }
+ }
+
+ // DMA irqs
+ if((sh2.m[0x63] & 6) == 6) {
+ level = (sh2.m[0x38] >> 8) & 15;
+ if(level > irq) {
+ irq = level;
+ vector = (sh2.m[0x68] >> 24) & 0x7f;
+ }
+ }
+
+ if((sh2.m[0x67] & 6) == 6) {
+ level = (sh2.m[0x38] >> 8) & 15;
+ if(level > irq) {
+ irq = level;
+ vector = (sh2.m[0x6a] >> 24) & 0x7f;
+ }
+ }
+
+
+ sh2.internal_irq_level = irq;
+ sh2.internal_irq_vector = vector;
+ sh2.test_irq = 1;
+}
+
+static TIMER_CALLBACK( sh2_timer_callback )
+{
+ UINT16 frc;
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ sh2_timer_resync();
+
+ frc = sh2.frc;
+
+ if(frc == sh2.ocrb)
+ sh2.m[4] |= OCFB;
+
+ if(frc == 0x0000)
+ sh2.m[4] |= OVF;
+
+ if(frc == sh2.ocra)
+ {
+ sh2.m[4] |= OCFA;
+
+ if(sh2.m[4] & 0x010000)
+ sh2.frc = 0;
+ }
+
+ sh2_recalc_irq();
+ sh2_timer_activate();
+
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( sh2_dmac_callback )
+{
+ int cpunum = param >> 1;
+ int dma = param & 1;
+
+ cpuintrf_push_context(cpunum);
+ LOG(("SH2.%d: DMA %d complete\n", cpunum, dma));
+ sh2.m[0x63+4*dma] |= 2;
+ sh2.dma_timer_active[dma] = 0;
+ sh2_recalc_irq();
+ cpuintrf_pop_context();
+}
+
+static void sh2_dmac_check(int dma)
+{
+ if(sh2.m[0x63+4*dma] & sh2.m[0x6c] & 1)
+ {
+ if(!sh2.dma_timer_active[dma] && !(sh2.m[0x63+4*dma] & 2))
+ {
+ int incs, incd, size;
+ UINT32 src, dst, count;
+ incd = (sh2.m[0x63+4*dma] >> 14) & 3;
+ incs = (sh2.m[0x63+4*dma] >> 12) & 3;
+ size = (sh2.m[0x63+4*dma] >> 10) & 3;
+ if(incd == 3 || incs == 3)
+ {
+ logerror("SH2: DMA: bad increment values (%d, %d, %d, %04x)\n", incd, incs, size, sh2.m[0x63+4*dma]);
+ return;
+ }
+ src = sh2.m[0x60+4*dma];
+ dst = sh2.m[0x61+4*dma];
+ count = sh2.m[0x62+4*dma];
+ if(!count)
+ count = 0x1000000;
+
+ LOG(("SH2: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", dma, src, dst, count, sh2.m[0x63+4*dma], incs, incd, size));
+
+ sh2.dma_timer_active[dma] = 1;
+ timer_adjust(sh2.dma_timer[dma], ATTOTIME_IN_CYCLES(2*count+1, sh2.cpu_number), (sh2.cpu_number<<1)|dma, attotime_zero);
+
+ src &= AM;
+ dst &= AM;
+
+ switch(size)
+ {
+ case 0:
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src --;
+ if(incd == 2)
+ dst --;
+ program_write_byte_32be(dst, program_read_byte_32be(src));
+ if(incs == 1)
+ src ++;
+ if(incd == 1)
+ dst ++;
+ }
+ break;
+ case 1:
+ src &= ~1;
+ dst &= ~1;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 2;
+ if(incd == 2)
+ dst -= 2;
+ program_write_word_32be(dst, program_read_word_32be(src));
+ if(incs == 1)
+ src += 2;
+ if(incd == 1)
+ dst += 2;
+ }
+ break;
+ case 2:
+ src &= ~3;
+ dst &= ~3;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 4;
+ if(incd == 2)
+ dst -= 4;
+ program_write_dword_32be(dst, program_read_dword_32be(src));
+ if(incs == 1)
+ src += 4;
+ if(incd == 1)
+ dst += 4;
+
+ }
+ break;
+ case 3:
+ src &= ~3;
+ dst &= ~3;
+ count &= ~3;
+ for(;count > 0; count -= 4)
+ {
+ if(incd == 2)
+ dst -= 16;
+ program_write_dword_32be(dst, program_read_dword_32be(src));
+ program_write_dword_32be(dst+4, program_read_dword_32be(src+4));
+ program_write_dword_32be(dst+8, program_read_dword_32be(src+8));
+ program_write_dword_32be(dst+12, program_read_dword_32be(src+12));
+ src += 16;
+ if(incd == 1)
+ dst += 16;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ if(sh2.dma_timer_active[dma])
+ {
+ logerror("SH2: DMA %d cancelled in-flight", dma);
+ timer_adjust(sh2.dma_timer[dma], attotime_never, 0, attotime_zero);
+ sh2.dma_timer_active[dma] = 0;
+ }
+ }
+}
+
+WRITE32_HANDLER( sh2_internal_w )
+{
+ UINT32 old = sh2.m[offset];
+ COMBINE_DATA(sh2.m+offset);
+
+ // if(offset != 0x20)
+ // logerror("sh2_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfffffe00+offset*4, offset, data, mem_mask);
+
+ switch( offset )
+ {
+ // Timers
+ case 0x04: // TIER, FTCSR, FRC
+ if((mem_mask & 0x00ffffff) != 0xffffff)
+ sh2_timer_resync();
+ logerror("SH2.%d: TIER write %04x @ %04x\n", sh2.cpu_number, data >> 16, mem_mask>>16);
+ sh2.m[4] = (sh2.m[4] & ~(ICF|OCFA|OCFB|OVF)) | (old & sh2.m[4] & (ICF|OCFA|OCFB|OVF));
+ COMBINE_DATA(&sh2.frc);
+ if((mem_mask & 0x00ffffff) != 0xffffff)
+ sh2_timer_activate();
+ sh2_recalc_irq();
+ break;
+ case 0x05: // OCRx, TCR, TOCR
+ logerror("SH2.%d: TCR write %08x @ %08x\n", sh2.cpu_number, data, mem_mask);
+ sh2_timer_resync();
+ if(sh2.m[5] & 0x10)
+ sh2.ocrb = (sh2.ocrb & (mem_mask >> 16)) | ((data & ~mem_mask) >> 16);
+ else
+ sh2.ocra = (sh2.ocra & (mem_mask >> 16)) | ((data & ~mem_mask) >> 16);
+ sh2_timer_activate();
+ break;
+
+ case 0x06: // ICR
+ break;
+
+ // Interrupt vectors
+ case 0x18: // IPRB, VCRA
+ case 0x19: // VCRB, VCRC
+ case 0x1a: // VCRD
+ sh2_recalc_irq();
+ break;
+
+ // DMA
+ case 0x1c: // DRCR0, DRCR1
+ break;
+
+ // Watchdog
+ case 0x20: // WTCNT, RSTCSR
+ break;
+
+ // Standby and cache
+ case 0x24: // SBYCR, CCR
+ break;
+
+ // Interrupt vectors cont.
+ case 0x38: // ICR, IRPA
+ break;
+ case 0x39: // VCRWDT
+ break;
+
+ // Division box
+ case 0x40: // DVSR
+ break;
+ case 0x41: // DVDNT
+ {
+ INT32 a = sh2.m[0x41];
+ INT32 b = sh2.m[0x40];
+ LOG(("SH2 #%d div+mod %d/%d\n", cpu_getactivecpu(), a, b));
+ if (b)
+ {
+ sh2.m[0x45] = a / b;
+ sh2.m[0x44] = a % b;
+ }
+ else
+ {
+ sh2.m[0x42] |= 0x00010000;
+ sh2.m[0x45] = 0x7fffffff;
+ sh2.m[0x44] = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ break;
+ }
+ case 0x42: // DVCR
+ sh2.m[0x42] = (sh2.m[0x42] & ~0x00001000) | (old & sh2.m[0x42] & 0x00010000);
+ sh2_recalc_irq();
+ break;
+ case 0x43: // VCRDIV
+ sh2_recalc_irq();
+ break;
+ case 0x44: // DVDNTH
+ break;
+ case 0x45: // DVDNTL
+ {
+ INT64 a = sh2.m[0x45] | ((UINT64)(sh2.m[0x44]) << 32);
+ INT64 b = (INT32)sh2.m[0x40];
+ LOG(("SH2 #%d div+mod %lld/%lld\n", cpu_getactivecpu(), a, b));
+ if (b)
+ {
+ INT64 q = a / b;
+ if (q != (INT32)q)
+ {
+ sh2.m[0x42] |= 0x00010000;
+ sh2.m[0x45] = 0x7fffffff;
+ sh2.m[0x44] = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ else
+ {
+ sh2.m[0x45] = q;
+ sh2.m[0x44] = a % b;
+ }
+ }
+ else
+ {
+ sh2.m[0x42] |= 0x00010000;
+ sh2.m[0x45] = 0x7fffffff;
+ sh2.m[0x44] = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ break;
+ }
+
+ // DMA controller
+ case 0x60: // SAR0
+ case 0x61: // DAR0
+ break;
+ case 0x62: // DTCR0
+ sh2.m[0x62] &= 0xffffff;
+ break;
+ case 0x63: // CHCR0
+ sh2.m[0x63] = (sh2.m[0x63] & ~2) | (old & sh2.m[0x63] & 2);
+ sh2_dmac_check(0);
+ break;
+ case 0x64: // SAR1
+ case 0x65: // DAR1
+ break;
+ case 0x66: // DTCR1
+ sh2.m[0x66] &= 0xffffff;
+ break;
+ case 0x67: // CHCR1
+ sh2.m[0x67] = (sh2.m[0x67] & ~2) | (old & sh2.m[0x67] & 2);
+ sh2_dmac_check(1);
+ break;
+ case 0x68: // VCRDMA0
+ case 0x6a: // VCRDMA1
+ sh2_recalc_irq();
+ break;
+ case 0x6c: // DMAOR
+ sh2.m[0x6c] = (sh2.m[0x6c] & ~6) | (old & sh2.m[0x6c] & 6);
+ sh2_dmac_check(0);
+ sh2_dmac_check(1);
+ break;
+
+ // Bus controller
+ case 0x78: // BCR1
+ case 0x79: // BCR2
+ case 0x7a: // WCR
+ case 0x7b: // MCR
+ case 0x7c: // RTCSR
+ case 0x7d: // RTCNT
+ case 0x7e: // RTCOR
+ break;
+
+ default:
+ logerror("sh2_internal_w: Unmapped write %08x, %08x @ %08x\n", 0xfffffe00+offset*4, data, mem_mask);
+ break;
+ }
+}
+
+READ32_HANDLER( sh2_internal_r )
+{
+ // logerror("sh2_internal_r: Read %08x (%x) @ %08x\n", 0xfffffe00+offset*4, offset, mem_mask);
+ switch( offset )
+ {
+ case 0x04: // TIER, FTCSR, FRC
+ if ( mem_mask == 0xff00ffff )
+ if ( sh2.ftcsr_read_callback != NULL )
+ sh2.ftcsr_read_callback( (sh2.m[4] & 0xffff0000) | sh2.frc );
+ sh2_timer_resync();
+ return (sh2.m[4] & 0xffff0000) | sh2.frc;
+ case 0x05: // OCRx, TCR, TOCR
+ if(sh2.m[5] & 0x10)
+ return (sh2.ocrb << 16) | (sh2.m[5] & 0xffff);
+ else
+ return (sh2.ocra << 16) | (sh2.m[5] & 0xffff);
+ case 0x06: // ICR
+ return sh2.icr << 16;
+
+ case 0x38: // ICR, IPRA
+ return (sh2.m[0x38] & 0x7fffffff) | (sh2.nmi_line_state == ASSERT_LINE ? 0 : 0x80000000);
+
+ case 0x78: // BCR1
+ return sh2.is_slave ? 0x00008000 : 0;
+
+ case 0x41: // dvdntl mirrors
+ case 0x47:
+ return sh2.m[0x45];
+
+ case 0x46: // dvdnth mirror
+ return sh2.m[0x44];
+ }
+ return sh2.m[offset];
+}
+
+void sh2_set_frt_input(int cpunum, int state)
+{
+ if(state == PULSE_LINE)
+ {
+ sh2_set_frt_input(cpunum, ASSERT_LINE);
+ sh2_set_frt_input(cpunum, CLEAR_LINE);
+ return;
+ }
+
+ cpuintrf_push_context(cpunum);
+
+ if(sh2.frt_input == state) {
+ cpuintrf_pop_context();
+ return;
+ }
+
+ sh2.frt_input = state;
+
+ if(sh2.m[5] & 0x8000) {
+ if(state == CLEAR_LINE) {
+ cpuintrf_pop_context();
+ return;
+ }
+ } else {
+ if(state == ASSERT_LINE) {
+ cpuintrf_pop_context();
+ return;
+ }
+ }
+
+ sh2_timer_resync();
+ sh2.icr = sh2.frc;
+ sh2.m[4] |= ICF;
+ logerror("SH2.%d: ICF activated (%x)\n", sh2.cpu_number, sh2.pc & AM);
+ sh2_recalc_irq();
+ cpuintrf_pop_context();
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (sh2.nmi_line_state == state)
+ return;
+ sh2.nmi_line_state = state;
+
+ if( state == CLEAR_LINE )
+ LOG(("SH-2 #%d cleared nmi\n", cpu_getactivecpu()));
+ else
+ {
+ LOG(("SH-2 #%d assert nmi\n", cpu_getactivecpu()));
+ sh2_exception("sh2_set_irq_line/nmi", 16);
+ }
+ }
+ else
+ {
+ if (sh2.irq_line_state[irqline] == state)
+ return;
+ sh2.irq_line_state[irqline] = state;
+
+ if( state == CLEAR_LINE )
+ {
+ LOG(("SH-2 #%d cleared irq #%d\n", cpu_getactivecpu(), irqline));
+ sh2.pending_irq &= ~(1 << irqline);
+ }
+ else
+ {
+ LOG(("SH-2 #%d assert irq #%d\n", cpu_getactivecpu(), irqline));
+ sh2.pending_irq |= 1 << irqline;
+ if(sh2.delay)
+ sh2.test_irq = 1;
+ else
+ CHECK_PENDING_IRQ("sh2_set_irq_line");
+ }
+ }
+}
+
+#ifdef MAME_DEBUG
+static offs_t sh2_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return DasmSH2( buffer, pc, (oprom[0] << 8) | oprom[1] );
+}
+#endif /* MAME_DEBUG */
+
+static void sh2_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ const struct sh2_config *conf = config;
+
+ sh2.timer = timer_alloc(sh2_timer_callback);
+ timer_adjust(sh2.timer, attotime_never, 0, attotime_zero);
+
+ sh2.dma_timer[0] = timer_alloc(sh2_dmac_callback);
+ timer_adjust(sh2.dma_timer[0], attotime_never, 0, attotime_zero);
+
+ sh2.dma_timer[1] = timer_alloc(sh2_dmac_callback);
+ timer_adjust(sh2.dma_timer[1], attotime_never, 0, attotime_zero);
+
+ sh2.m = auto_malloc(0x200);
+
+ if(conf)
+ sh2.is_slave = conf->is_slave;
+ else
+ sh2.is_slave = 0;
+
+ sh2.cpu_number = index;
+ sh2.irq_callback = irqcallback;
+
+ state_save_register_item("sh2", index, sh2.pc);
+ state_save_register_item("sh2", index, sh2.r[15]);
+ state_save_register_item("sh2", index, sh2.sr);
+ state_save_register_item("sh2", index, sh2.pr);
+ state_save_register_item("sh2", index, sh2.gbr);
+ state_save_register_item("sh2", index, sh2.vbr);
+ state_save_register_item("sh2", index, sh2.mach);
+ state_save_register_item("sh2", index, sh2.macl);
+ state_save_register_item("sh2", index, sh2.r[ 0]);
+ state_save_register_item("sh2", index, sh2.r[ 1]);
+ state_save_register_item("sh2", index, sh2.r[ 2]);
+ state_save_register_item("sh2", index, sh2.r[ 3]);
+ state_save_register_item("sh2", index, sh2.r[ 4]);
+ state_save_register_item("sh2", index, sh2.r[ 5]);
+ state_save_register_item("sh2", index, sh2.r[ 6]);
+ state_save_register_item("sh2", index, sh2.r[ 7]);
+ state_save_register_item("sh2", index, sh2.r[ 8]);
+ state_save_register_item("sh2", index, sh2.r[ 9]);
+ state_save_register_item("sh2", index, sh2.r[10]);
+ state_save_register_item("sh2", index, sh2.r[11]);
+ state_save_register_item("sh2", index, sh2.r[12]);
+ state_save_register_item("sh2", index, sh2.r[13]);
+ state_save_register_item("sh2", index, sh2.r[14]);
+ state_save_register_item("sh2", index, sh2.ea);
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void sh2_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_VBLIN: set_irq_line(SH2_INT_VBLIN, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_VBLOUT: set_irq_line(SH2_INT_VBLOUT, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_HBLIN: set_irq_line(SH2_INT_HBLIN, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_TIMER0: set_irq_line(SH2_INT_TIMER0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_TIMER1: set_irq_line(SH2_INT_TIMER1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DSP: set_irq_line(SH2_INT_DSP, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SOUND: set_irq_line(SH2_INT_SOUND, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SMPC: set_irq_line(SH2_INT_SMPC, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_PAD: set_irq_line(SH2_INT_PAD, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA2: set_irq_line(SH2_INT_DMA2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA1: set_irq_line(SH2_INT_DMA1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA0: set_irq_line(SH2_INT_DMA0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMAILL: set_irq_line(SH2_INT_DMAILL, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SPRITE: set_irq_line(SH2_INT_SPRITE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_14: set_irq_line(SH2_INT_14, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_15: set_irq_line(SH2_INT_15, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_ABUS: set_irq_line(SH2_INT_ABUS, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_REGISTER + SH2_PC:
+ case CPUINFO_INT_PC: sh2.pc = info->i; sh2.delay = 0; break;
+ case CPUINFO_INT_SP: sh2.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_PR: sh2.pr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_SR: sh2.sr = info->i; CHECK_PENDING_IRQ("sh2_set_reg"); break;
+ case CPUINFO_INT_REGISTER + SH2_GBR: sh2.gbr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_VBR: sh2.vbr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_MACH: sh2.mach = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_MACL: sh2.macl = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R0: sh2.r[ 0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R1: sh2.r[ 1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R2: sh2.r[ 2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R3: sh2.r[ 3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R4: sh2.r[ 4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R5: sh2.r[ 5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R6: sh2.r[ 6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R7: sh2.r[ 7] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R8: sh2.r[ 8] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R9: sh2.r[ 9] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R10: sh2.r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R11: sh2.r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R12: sh2.r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R13: sh2.r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R14: sh2.r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R15: sh2.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_EA: sh2.ea = info->i; break;
+
+ case CPUINFO_INT_SH2_FRT_INPUT: sh2_set_frt_input(cpu_getactivecpu(), info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_SH2_FTCSR_READ_CALLBACK: sh2.ftcsr_read_callback = (void (*) (UINT32 ))info->f; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void sh2_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(sh2); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 16; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 4; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_VBLIN: info->i = sh2.irq_line_state[SH2_INT_VBLIN]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_VBLOUT: info->i = sh2.irq_line_state[SH2_INT_VBLOUT]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_HBLIN: info->i = sh2.irq_line_state[SH2_INT_HBLIN]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_TIMER0: info->i = sh2.irq_line_state[SH2_INT_TIMER0]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_TIMER1: info->i = sh2.irq_line_state[SH2_INT_TIMER1]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DSP: info->i = sh2.irq_line_state[SH2_INT_DSP]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SOUND: info->i = sh2.irq_line_state[SH2_INT_SOUND]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SMPC: info->i = sh2.irq_line_state[SH2_INT_SMPC]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_PAD: info->i = sh2.irq_line_state[SH2_INT_PAD]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA2: info->i = sh2.irq_line_state[SH2_INT_DMA2]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA1: info->i = sh2.irq_line_state[SH2_INT_DMA1]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA0: info->i = sh2.irq_line_state[SH2_INT_DMA0]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMAILL: info->i = sh2.irq_line_state[SH2_INT_DMAILL]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SPRITE: info->i = sh2.irq_line_state[SH2_INT_SPRITE]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_14: info->i = sh2.irq_line_state[SH2_INT_14]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_15: info->i = sh2.irq_line_state[SH2_INT_15]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_ABUS: info->i = sh2.irq_line_state[SH2_INT_ABUS]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = sh2.nmi_line_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = sh2.ppc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SH2_PC: info->i = (sh2.delay) ? (sh2.delay & AM) : (sh2.pc & AM); break;
+ case CPUINFO_INT_SP: info->i = sh2.r[15]; break;
+ case CPUINFO_INT_REGISTER + SH2_PR: info->i = sh2.pr; break;
+ case CPUINFO_INT_REGISTER + SH2_SR: info->i = sh2.sr; break;
+ case CPUINFO_INT_REGISTER + SH2_GBR: info->i = sh2.gbr; break;
+ case CPUINFO_INT_REGISTER + SH2_VBR: info->i = sh2.vbr; break;
+ case CPUINFO_INT_REGISTER + SH2_MACH: info->i = sh2.mach; break;
+ case CPUINFO_INT_REGISTER + SH2_MACL: info->i = sh2.macl; break;
+ case CPUINFO_INT_REGISTER + SH2_R0: info->i = sh2.r[ 0]; break;
+ case CPUINFO_INT_REGISTER + SH2_R1: info->i = sh2.r[ 1]; break;
+ case CPUINFO_INT_REGISTER + SH2_R2: info->i = sh2.r[ 2]; break;
+ case CPUINFO_INT_REGISTER + SH2_R3: info->i = sh2.r[ 3]; break;
+ case CPUINFO_INT_REGISTER + SH2_R4: info->i = sh2.r[ 4]; break;
+ case CPUINFO_INT_REGISTER + SH2_R5: info->i = sh2.r[ 5]; break;
+ case CPUINFO_INT_REGISTER + SH2_R6: info->i = sh2.r[ 6]; break;
+ case CPUINFO_INT_REGISTER + SH2_R7: info->i = sh2.r[ 7]; break;
+ case CPUINFO_INT_REGISTER + SH2_R8: info->i = sh2.r[ 8]; break;
+ case CPUINFO_INT_REGISTER + SH2_R9: info->i = sh2.r[ 9]; break;
+ case CPUINFO_INT_REGISTER + SH2_R10: info->i = sh2.r[10]; break;
+ case CPUINFO_INT_REGISTER + SH2_R11: info->i = sh2.r[11]; break;
+ case CPUINFO_INT_REGISTER + SH2_R12: info->i = sh2.r[12]; break;
+ case CPUINFO_INT_REGISTER + SH2_R13: info->i = sh2.r[13]; break;
+ case CPUINFO_INT_REGISTER + SH2_R14: info->i = sh2.r[14]; break;
+ case CPUINFO_INT_REGISTER + SH2_R15: info->i = sh2.r[15]; break;
+ case CPUINFO_INT_REGISTER + SH2_EA: info->i = sh2.ea; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = sh2_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = sh2_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = sh2_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = sh2_init; break;
+ case CPUINFO_PTR_RESET: info->reset = sh2_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = sh2_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = sh2_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &sh2_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "SH-2"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Hitachi SH7600"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.01"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2000 Juergen Buchmueller, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%d%c%c",
+ sh2.sr & M ? 'M':'.',
+ sh2.sr & Q ? 'Q':'.',
+ (sh2.sr & I) >> 4,
+ sh2.sr & S ? 'S':'.',
+ sh2.sr & T ? 'T':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + SH2_PC: sprintf(info->s, "PC :%08X", sh2.pc); break;
+ case CPUINFO_STR_REGISTER + SH2_SR: sprintf(info->s, "SR :%08X", sh2.sr); break;
+ case CPUINFO_STR_REGISTER + SH2_PR: sprintf(info->s, "PR :%08X", sh2.pr); break;
+ case CPUINFO_STR_REGISTER + SH2_GBR: sprintf(info->s, "GBR :%08X", sh2.gbr); break;
+ case CPUINFO_STR_REGISTER + SH2_VBR: sprintf(info->s, "VBR :%08X", sh2.vbr); break;
+ case CPUINFO_STR_REGISTER + SH2_MACH: sprintf(info->s, "MACH:%08X", sh2.mach); break;
+ case CPUINFO_STR_REGISTER + SH2_MACL: sprintf(info->s, "MACL:%08X", sh2.macl); break;
+ case CPUINFO_STR_REGISTER + SH2_R0: sprintf(info->s, "R0 :%08X", sh2.r[ 0]); break;
+ case CPUINFO_STR_REGISTER + SH2_R1: sprintf(info->s, "R1 :%08X", sh2.r[ 1]); break;
+ case CPUINFO_STR_REGISTER + SH2_R2: sprintf(info->s, "R2 :%08X", sh2.r[ 2]); break;
+ case CPUINFO_STR_REGISTER + SH2_R3: sprintf(info->s, "R3 :%08X", sh2.r[ 3]); break;
+ case CPUINFO_STR_REGISTER + SH2_R4: sprintf(info->s, "R4 :%08X", sh2.r[ 4]); break;
+ case CPUINFO_STR_REGISTER + SH2_R5: sprintf(info->s, "R5 :%08X", sh2.r[ 5]); break;
+ case CPUINFO_STR_REGISTER + SH2_R6: sprintf(info->s, "R6 :%08X", sh2.r[ 6]); break;
+ case CPUINFO_STR_REGISTER + SH2_R7: sprintf(info->s, "R7 :%08X", sh2.r[ 7]); break;
+ case CPUINFO_STR_REGISTER + SH2_R8: sprintf(info->s, "R8 :%08X", sh2.r[ 8]); break;
+ case CPUINFO_STR_REGISTER + SH2_R9: sprintf(info->s, "R9 :%08X", sh2.r[ 9]); break;
+ case CPUINFO_STR_REGISTER + SH2_R10: sprintf(info->s, "R10 :%08X", sh2.r[10]); break;
+ case CPUINFO_STR_REGISTER + SH2_R11: sprintf(info->s, "R11 :%08X", sh2.r[11]); break;
+ case CPUINFO_STR_REGISTER + SH2_R12: sprintf(info->s, "R12 :%08X", sh2.r[12]); break;
+ case CPUINFO_STR_REGISTER + SH2_R13: sprintf(info->s, "R13 :%08X", sh2.r[13]); break;
+ case CPUINFO_STR_REGISTER + SH2_R14: sprintf(info->s, "R14 :%08X", sh2.r[14]); break;
+ case CPUINFO_STR_REGISTER + SH2_R15: sprintf(info->s, "R15 :%08X", sh2.r[15]); break;
+ case CPUINFO_STR_REGISTER + SH2_EA: sprintf(info->s, "EA :%08X", sh2.ea); break;
+
+ case CPUINFO_PTR_SH2_FTCSR_READ_CALLBACK: info->f = (genf*)sh2.ftcsr_read_callback; break;
+
+ }
+}
diff --git a/src/emu/cpu/sh2/sh2.h b/src/emu/cpu/sh2/sh2.h
new file mode 100644
index 00000000000..5a093dcf826
--- /dev/null
+++ b/src/emu/cpu/sh2/sh2.h
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ *
+ * sh2.h
+ * Portable Hitachi SH-2 (SH7600 family) emulator interface
+ *
+ * Copyright (c) 2000 Juergen Buchmueller <pullmoll@t-online.de>,
+ * all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on <tiraniddo@hotmail.com> C/C++ implementation of
+ * the SH-2 CPU core and was heavily changed to the MAME CPU requirements.
+ * Thanks also go to Chuck Mason <chukjr@sundail.net> and Olivier Galibert
+ * <galibert@pobox.com> for letting me peek into their SEMU code :-)
+ *
+ *****************************************************************************/
+
+#ifndef _SH2_H
+#define _SH2_H
+
+#include "cpuintrf.h"
+
+#define SH2_INT_NONE -1
+#define SH2_INT_VBLIN 0
+#define SH2_INT_VBLOUT 1
+#define SH2_INT_HBLIN 2
+#define SH2_INT_TIMER0 3
+#define SH2_INT_TIMER1 4
+#define SH2_INT_DSP 5
+#define SH2_INT_SOUND 6
+#define SH2_INT_SMPC 7
+#define SH2_INT_PAD 8
+#define SH2_INT_DMA2 9
+#define SH2_INT_DMA1 10
+#define SH2_INT_DMA0 11
+#define SH2_INT_DMAILL 12
+#define SH2_INT_SPRITE 13
+#define SH2_INT_14 14
+#define SH2_INT_15 15
+#define SH2_INT_ABUS 16
+
+enum {
+ SH2_PC=1, SH2_SR, SH2_PR, SH2_GBR, SH2_VBR, SH2_MACH, SH2_MACL,
+ SH2_R0, SH2_R1, SH2_R2, SH2_R3, SH2_R4, SH2_R5, SH2_R6, SH2_R7,
+ SH2_R8, SH2_R9, SH2_R10, SH2_R11, SH2_R12, SH2_R13, SH2_R14, SH2_R15, SH2_EA
+};
+
+enum
+{
+ CPUINFO_INT_SH2_FRT_INPUT = CPUINFO_INT_CPU_SPECIFIC
+};
+
+enum
+{
+ CPUINFO_PTR_SH2_FTCSR_READ_CALLBACK = CPUINFO_PTR_CPU_SPECIFIC,
+};
+
+struct sh2_config
+{
+ int is_slave;
+};
+
+extern void sh2_get_info(UINT32 state, cpuinfo *info);
+
+WRITE32_HANDLER( sh2_internal_w );
+READ32_HANDLER( sh2_internal_r );
+
+#ifdef MAME_DEBUG
+extern unsigned DasmSH2( char *dst, unsigned pc, UINT16 opcode );
+#endif
+
+#endif /* _SH2_H */
+
diff --git a/src/emu/cpu/sh2/sh2dasm.c b/src/emu/cpu/sh2/sh2dasm.c
new file mode 100644
index 00000000000..8d66e230b99
--- /dev/null
+++ b/src/emu/cpu/sh2/sh2dasm.c
@@ -0,0 +1,602 @@
+#include "debugger.h"
+#include "sh2.h"
+
+#define SIGNX8(x) (((INT32)(x) << 24) >> 24)
+#define SIGNX12(x) (((INT32)(x) << 20) >> 20)
+
+#define Rn ((opcode >> 8) & 15)
+#define Rm ((opcode >> 4) & 15)
+
+static const char *regname[16] = {
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10","R11","R12","R13","R14","SP"
+};
+
+static UINT32 op0000(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ UINT32 flags = 0;
+ switch(opcode & 0x3f)
+ {
+ case 0x02:
+ sprintf(buffer,"STC SR,%s", regname[Rn]);
+ break;
+ case 0x03:
+ sprintf(buffer,"BSRF %s", regname[Rn]);
+ break;
+ case 0x08:
+ sprintf(buffer,"CLRT");
+ break;
+ case 0x09:
+ sprintf(buffer,"NOP");
+ break;
+ case 0x0A:
+ sprintf(buffer,"STS MACH,%s", regname[Rn]);
+ break;
+ case 0x0B:
+ sprintf(buffer,"RTS");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ case 0x12:
+ sprintf(buffer,"STS GBR,%s", regname[Rn]);
+ break;
+ case 0x18:
+ sprintf(buffer,"SETT");
+ break;
+ case 0x19:
+ sprintf(buffer,"DIV0U");
+ break;
+ case 0x1A:
+ sprintf(buffer,"STS MACL,%s", regname[Rn]);
+ break;
+ case 0x1B:
+ sprintf(buffer,"SLEEP");
+ break;
+ case 0x22:
+ sprintf(buffer,"STC VBR,%s", regname[Rn]);
+ break;
+ case 0x23:
+ sprintf(buffer,"BRAF %s", regname[Rn]);
+ break;
+ case 0x28:
+ sprintf(buffer,"CLRMAC");
+ break;
+ case 0x29:
+ sprintf(buffer,"MOVT %s", regname[Rn]);
+ break;
+ case 0x2A:
+ sprintf(buffer,"STS PR,%s", regname[Rn]);
+ break;
+ case 0x2B:
+ sprintf(buffer,"RTE");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ default:
+ switch(opcode & 15)
+ {
+ case 0:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 1:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 2:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 3:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 4:
+ sprintf(buffer, "MOV.B %s,@(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ sprintf(buffer, "MOV.W %s,@(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ sprintf(buffer, "MOV.L %s,@(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ sprintf(buffer, "MUL.L %s,%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 9:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 10:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 11:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 12:
+ sprintf(buffer, "MOV.B @(R0,%s),%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ sprintf(buffer, "MOV.W @(R0,%s),%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ sprintf(buffer, "MOV.L @(R0,%s),%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ sprintf(buffer, "MAC.L @%s+,@%s+", regname[Rn], regname[Rm]);
+ break;
+ }
+ }
+ return flags;
+}
+
+static UINT32 op0001(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV.L %s,@($%02X,%s)\n", regname[Rm], (opcode & 15) * 4, regname[Rn]);
+ return 0;
+}
+
+static UINT32 op0010(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0:
+ sprintf(buffer, "MOV.B %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ sprintf(buffer, "MOV.W %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ sprintf(buffer, "MOV.L %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 4:
+ sprintf(buffer, "MOV.B %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ sprintf(buffer, "MOV.W %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ sprintf(buffer, "MOV.L %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ sprintf(buffer, "DIV0S %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ sprintf(buffer, "TST %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ sprintf(buffer, "AND %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ sprintf(buffer, "XOR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ sprintf(buffer, "OR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ sprintf(buffer, "CMP/STR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ sprintf(buffer, "XTRCT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ sprintf(buffer, "MULU.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ sprintf(buffer, "MULS.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static UINT32 op0011(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0:
+ sprintf(buffer, "CMP/EQ %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ sprintf(buffer, "?????? %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ sprintf(buffer, "CMP/HS %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ sprintf(buffer, "CMP/GE %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 4:
+ sprintf(buffer, "DIV1 %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ sprintf(buffer, "DMULU.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ sprintf(buffer, "CMP/HI %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ sprintf(buffer, "CMP/GT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ sprintf(buffer, "SUB %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ sprintf(buffer, "?????? %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ sprintf(buffer, "SUBC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ sprintf(buffer, "SUBV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ sprintf(buffer, "ADD %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ sprintf(buffer, "DMULS.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ sprintf(buffer, "ADDC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ sprintf(buffer, "ADDV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static UINT32 op0100(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ UINT32 flags = 0;
+ switch(opcode & 0x3F)
+ {
+ case 0x00:
+ sprintf(buffer, "SHLL %s", regname[Rn]);
+ break;
+ case 0x01:
+ sprintf(buffer, "SHLR %s", regname[Rn]);
+ break;
+ case 0x02:
+ sprintf(buffer, "STS.L MACH,@-%s", regname[Rn]);
+ break;
+ case 0x03:
+ sprintf(buffer, "STC.L SR,@-%s", regname[Rn]);
+ break;
+ case 0x04:
+ sprintf(buffer, "ROTL %s", regname[Rn]);
+ break;
+ case 0x05:
+ sprintf(buffer, "ROTR %s", regname[Rn]);
+ break;
+ case 0x06:
+ sprintf(buffer, "LDS.L @%s+,MACH", regname[Rn]);
+ break;
+ case 0x07:
+ sprintf(buffer, "LDC.L @%s+,SR", regname[Rn]);
+ break;
+ case 0x08:
+ sprintf(buffer, "SHLL2 %s", regname[Rn]);
+ break;
+ case 0x09:
+ sprintf(buffer, "SHLR2 %s", regname[Rn]);
+ break;
+ case 0x0a:
+ sprintf(buffer, "LDS %s,MACH", regname[Rn]);
+ break;
+ case 0x0b:
+ sprintf(buffer, "JSR %s", regname[Rn]);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ break;
+ case 0x0e:
+ sprintf(buffer, "LDC %s,SR", regname[Rn]);
+ break;
+ case 0x10:
+ sprintf(buffer, "DT %s", regname[Rn]);
+ break;
+ case 0x11:
+ sprintf(buffer, "CMP/PZ %s", regname[Rn]);
+ break;
+ case 0x12:
+ sprintf(buffer, "STS.L MACL,@-%s", regname[Rn]);
+ break;
+ case 0x13:
+ sprintf(buffer, "STC.L GBR,@-%s", regname[Rn]);
+ break;
+ case 0x15:
+ sprintf(buffer, "CMP/PL %s", regname[Rn]);
+ break;
+ case 0x16:
+ sprintf(buffer, "LDS.L @%s+,MACL", regname[Rn]);
+ break;
+ case 0x17:
+ sprintf(buffer, "LDC.L @%s+,GBR", regname[Rn]);
+ break;
+ case 0x18:
+ sprintf(buffer, "SHLL8 %s", regname[Rn]);
+ break;
+ case 0x19:
+ sprintf(buffer, "SHLR8 %s", regname[Rn]);
+ break;
+ case 0x1a:
+ sprintf(buffer, "LDS %s,MACL", regname[Rn]);
+ break;
+ case 0x1b:
+ sprintf(buffer, "TAS %s", regname[Rn]);
+ break;
+ case 0x1e:
+ sprintf(buffer, "LDC %s,GBR", regname[Rn]);
+ break;
+ case 0x20:
+ sprintf(buffer, "SHAL %s", regname[Rn]);
+ break;
+ case 0x21:
+ sprintf(buffer, "SHAR %s", regname[Rn]);
+ break;
+ case 0x22:
+ sprintf(buffer, "STS.L PR,@-%s", regname[Rn]);
+ break;
+ case 0x23:
+ sprintf(buffer, "STC.L VBR,@-%s", regname[Rn]);
+ break;
+ case 0x24:
+ sprintf(buffer, "ROTCL %s", regname[Rn]);
+ break;
+ case 0x25:
+ sprintf(buffer, "ROTCR %s", regname[Rn]);
+ break;
+ case 0x26:
+ sprintf(buffer, "LDS.L @%s+,PR", regname[Rn]);
+ break;
+ case 0x27:
+ sprintf(buffer, "LDC.L @%s+,VBR", regname[Rn]);
+ break;
+ case 0x28:
+ sprintf(buffer, "SHLL16 %s", regname[Rn]);
+ break;
+ case 0x29:
+ sprintf(buffer, "SHLR16 %s", regname[Rn]);
+ break;
+ case 0x2a:
+ sprintf(buffer, "LDS %s,PR", regname[Rn]);
+ break;
+ case 0x2b:
+ sprintf(buffer, "JMP %s", regname[Rn]);
+ break;
+ case 0x2e:
+ sprintf(buffer, "LDC %s,VBR", regname[Rn]);
+ break;
+ default:
+ if ((opcode & 15) == 15)
+ sprintf(buffer, "MAC.W @%s+,@%s+", regname[Rm], regname[Rn]);
+ else
+ sprintf(buffer, "?????? $%04X", opcode);
+ }
+ return flags;
+}
+
+static UINT32 op0101(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV.L @($%02X,%s),%s\n", (opcode & 15) * 4, regname[Rm], regname[Rn]);
+ return 0;
+}
+
+static UINT32 op0110(char *buffer, UINT32 pc, UINT16 opcode)
+
+{
+ switch(opcode & 0xF)
+ {
+ case 0x00:
+ sprintf(buffer, "MOV.B @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x01:
+ sprintf(buffer, "MOV.W @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x02:
+ sprintf(buffer, "MOV.L @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x03:
+ sprintf(buffer, "MOV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x04:
+ sprintf(buffer, "MOV.B @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x05:
+ sprintf(buffer, "MOV.W @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x06:
+ sprintf(buffer, "MOV.L @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x07:
+ sprintf(buffer, "NOT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x08:
+ sprintf(buffer, "SWAP.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x09:
+ sprintf(buffer, "SWAP.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0a:
+ sprintf(buffer, "NEGC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0b:
+ sprintf(buffer, "NEG %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0c:
+ sprintf(buffer, "EXTU.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0d:
+ sprintf(buffer, "EXTU.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0e:
+ sprintf(buffer, "EXTS.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0f:
+ sprintf(buffer, "EXTS.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static UINT32 op0111(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "ADD #$%02X,%s\n", opcode & 0xff, regname[Rn]);
+ return 0;
+}
+
+static UINT32 op1000(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ switch((opcode >> 8) & 15)
+ {
+ case 0:
+ sprintf(buffer, "MOV.B R0,@($%02X,%s)", (opcode & 15), regname[Rm]);
+ break;
+ case 1:
+ sprintf(buffer, "MOV.W R0,@($%02X,%s)", (opcode & 15) * 2, regname[Rm]);
+ break;
+ case 4:
+ sprintf(buffer, "MOV.B @($%02X,%s),R0", (opcode & 15), regname[Rm]);
+ break;
+ case 5:
+ sprintf(buffer, "MOV.W @($%02X,%s),R0", (opcode & 15), regname[Rm]);
+ break;
+ case 8:
+ sprintf(buffer, "CMP/EQ #$%02X,R0", (opcode & 0xff));
+ break;
+ case 9:
+ sprintf(buffer, "BT $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 11:
+ sprintf(buffer, "BF $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 13:
+ sprintf(buffer, "BTS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 15:
+ sprintf(buffer, "BFS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ default :
+ sprintf(buffer, "invalid $%04X\n", opcode);
+ }
+ return 0;
+}
+
+static UINT32 op1001(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV.W @($%04X,PC),%s", (opcode & 0xff) * 2, regname[Rn]);
+ return 0;
+}
+
+static UINT32 op1010(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "BRA $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2);
+ return 0;
+}
+
+static UINT32 op1011(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "BSR $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2);
+ return DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+}
+
+static UINT32 op1100(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ UINT32 flags = 0;
+ switch((opcode >> 8) & 15)
+ {
+ case 0:
+ sprintf(buffer, "MOV.B R0,@($%02X,GBR)", opcode & 0xff);
+ break;
+ case 1:
+ sprintf(buffer, "MOV.W R0,@($%04X,GBR)", (opcode & 0xff) * 2);
+ break;
+ case 2:
+ sprintf(buffer, "MOV.L R0,@($%04X,GBR)", (opcode & 0xff) * 4);
+ break;
+ case 3:
+ sprintf(buffer, "TRAPA #$%02X", opcode & 0xff);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 4:
+ sprintf(buffer, "MOV.B @($%02X,GBR),R0", opcode & 0xff);
+ break;
+ case 5:
+ sprintf(buffer, "MOV.W @($%04X,GBR),R0", (opcode & 0xff) * 2);
+ break;
+ case 6:
+ sprintf(buffer, "MOV.L @($%04X,GBR),R0", (opcode & 0xff) * 4);
+ break;
+ case 7:
+ sprintf(buffer, "MOVA @($%04X,PC),R0", (opcode & 0xff) * 4);
+ break;
+ case 8:
+ sprintf(buffer, "TST #$%02X,R0", opcode & 0xff);
+ break;
+ case 9:
+ sprintf(buffer, "AND #$%02X,R0", opcode & 0xff);
+ break;
+ case 10:
+ sprintf(buffer, "XOR #$%02X,R0", opcode & 0xff);
+ break;
+ case 11:
+ sprintf(buffer, "OR #$%02X,R0", opcode & 0xff);
+ break;
+ case 12:
+ sprintf(buffer, "TST.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 13:
+ sprintf(buffer, "AND.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 14:
+ sprintf(buffer, "XOR.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 15:
+ sprintf(buffer, "OR.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ }
+ return flags;
+}
+
+static UINT32 op1101(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV.L @($%02X,PC),%s", (opcode * 4) & 0xff, regname[Rn]);
+ return 0;
+}
+
+static UINT32 op1110(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV #$%02X,%s", (opcode & 0xff), regname[Rn]);
+ return 0;
+}
+
+static UINT32 op1111(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "unknown $%04X", opcode);
+ return 0;
+}
+
+unsigned DasmSH2(char *buffer, unsigned pc, UINT16 opcode)
+{
+ UINT32 flags;
+
+ pc += 2;
+
+ switch((opcode >> 12) & 15)
+ {
+ case 0: flags = op0000(buffer,pc,opcode); break;
+ case 1: flags = op0001(buffer,pc,opcode); break;
+ case 2: flags = op0010(buffer,pc,opcode); break;
+ case 3: flags = op0011(buffer,pc,opcode); break;
+ case 4: flags = op0100(buffer,pc,opcode); break;
+ case 5: flags = op0101(buffer,pc,opcode); break;
+ case 6: flags = op0110(buffer,pc,opcode); break;
+ case 7: flags = op0111(buffer,pc,opcode); break;
+ case 8: flags = op1000(buffer,pc,opcode); break;
+ case 9: flags = op1001(buffer,pc,opcode); break;
+ case 10: flags = op1010(buffer,pc,opcode); break;
+ case 11: flags = op1011(buffer,pc,opcode); break;
+ case 12: flags = op1100(buffer,pc,opcode); break;
+ case 13: flags = op1101(buffer,pc,opcode); break;
+ case 14: flags = op1110(buffer,pc,opcode); break;
+ default: flags = op1111(buffer,pc,opcode); break;
+ }
+ return 2 | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/sh4/sh4.c b/src/emu/cpu/sh4/sh4.c
new file mode 100644
index 00000000000..75967883d3d
--- /dev/null
+++ b/src/emu/cpu/sh4/sh4.c
@@ -0,0 +1,4637 @@
+/*****************************************************************************
+ *
+ * sh4.c
+ * Portable Hitachi SH-4 (SH7750 family) emulator
+ *
+ * By R. Belmont, based on sh2.c by Juergen Buchmueller, Mariusz Wojcieszek,
+ * Olivier Galibert, Sylvain Glaize, and James Forshaw.
+ *
+ *
+ * TODO: FPU
+ * DMA
+ * on-board peripherals
+ *
+ * DONE: boot/reset setup
+ * 64-bit data bus
+ * banked registers
+ * additional registers for supervisor mode
+ * FPU status and data registers
+ * state save for the new registers
+ * interrupts
+ * store queues
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "sh4.h"
+#include "sh4regs.h"
+
+/* speed up delay loops, bail out of tight loops */
+#define BUSY_LOOP_HACKS 0
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+#define EXPPRI(pl,po,p,n) (((4-(pl)) << 24) | ((15-(po)) << 16) | ((p) << 8) | (255-(n)))
+#define NMIPRI() EXPPRI(3,0,16,SH4_INTC_NMI)
+#define INTPRI(p,n) EXPPRI(4,2,p,n)
+
+typedef struct
+{
+ UINT32 ppc;
+ UINT32 pc, spc;
+ UINT32 pr;
+ UINT32 sr, ssr;
+ UINT32 gbr, vbr;
+ UINT32 mach, macl;
+ UINT32 r[16], rbnk[2][8], sgr;
+ UINT32 fr[16], xf[16];
+ UINT32 ea;
+ UINT32 delay;
+ UINT32 cpu_off;
+ UINT32 pending_irq;
+ UINT32 test_irq;
+ UINT32 fpscr;
+ UINT32 fpul;
+ UINT32 dbr;
+
+ UINT32 exception_priority[128];
+ int exception_requesting[128];
+
+ INT8 irq_line_state[17];
+ int (*irq_callback)(int irqline);
+ UINT32 *m;
+ INT8 nmi_line_state;
+
+ int frt_input;
+ int irln;
+ int internal_irq_level;
+ int internal_irq_vector;
+
+ emu_timer *dma_timer[4];
+ emu_timer *refresh_timer;
+ emu_timer *rtc_timer;
+ emu_timer *timer0;
+ emu_timer *timer1;
+ emu_timer *timer2;
+ UINT32 refresh_timer_base;
+ int dma_timer_active[2];
+
+ int is_slave, cpu_number;
+ int cpu_clock, bus_clock, pm_clock;
+
+ void (*ftcsr_read_callback)(UINT32 data);
+} SH4;
+
+static int sh4_icount;
+static SH4 sh4;
+
+static const int tcnt_div[8] = { 4, 16, 64, 256, 1024, 1, 1, 1 };
+static const int rtcnt_div[8] = { 0, 4, 16, 64, 256, 1024, 2048, 4096 };
+static const int daysmonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static const int dmasize[8] = { 8, 1, 2, 4, 32, 0, 0, 0 };
+static const UINT32 exception_priority_default[] = { EXPPRI(1,1,0,0), EXPPRI(1,2,0,1), EXPPRI(1,1,0,2), EXPPRI(1,3,0,3), EXPPRI(1,4,0,4),
+ EXPPRI(2,0,0,5), EXPPRI(2,1,0,6), EXPPRI(2,2,0,7), EXPPRI(2,3,0,8), EXPPRI(2,4,0,9), EXPPRI(2,4,0,10), EXPPRI(2,4,0,11), EXPPRI(2,4,0,12),
+ EXPPRI(2,5,0,13), EXPPRI(2,5,0,14), EXPPRI(2,6,0,15), EXPPRI(2,6,0,16), EXPPRI(2,7,0,17), EXPPRI(2,7,0,18), EXPPRI(2,8,0,19),
+ EXPPRI(2,9,0,20), EXPPRI(2,4,0,21), EXPPRI(2,10,0,22), EXPPRI(3,0,16,SH4_INTC_NMI) };
+static const int exception_codes[] = { 0x000, 0x020, 0x000, 0x140, 0x140, 0x1E0, 0x0E0, 0x040, 0x0A0, 0x180, 0x1A0, 0x800, 0x820, 0x0E0,
+ 0x100, 0x040, 0x060, 0x0A0, 0x0C0, 0x120, 0x080, 0x160, 0x1E0, 0x1C0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300,
+ 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x240, 0x2A0, 0x300, 0x360, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6A0, 0x780, 0x7A0, 0x7C0,
+ 0x7E0, 0x6C0, 0xB00, 0xB80, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4A0, 0x4C0, 0x4E0, 0x500, 0x520, 0x540, 0x700, 0x720, 0x740, 0x760,
+ 0x560, 0x580, 0x5A0 };
+
+enum {
+ ICF = 0x00800000,
+ OCFA = 0x00080000,
+ OCFB = 0x00040000,
+ OVF = 0x00020000
+};
+
+static void set_irq_line(int irqline, int state);
+
+/* Bits in SR */
+#define T 0x00000001
+#define S 0x00000002
+#define I 0x000000f0
+#define Q 0x00000100
+#define M 0x00000200
+#define FD 0x00008000
+#define BL 0x10000000
+#define sRB 0x20000000
+#define MD 0x40000000
+
+/* 29 bits */
+#define AM 0x1fffffff
+
+#define FLAGS (MD|sRB|BL|FD|M|Q|I|S|T)
+
+/* Bits in FPSCR */
+#define RM 0x00000003
+#define DN 0x00040000
+#define PR 0x00080000
+#define SZ 0x00100000
+#define FR 0x00200000
+
+#define Rn ((opcode>>8)&15)
+#define Rm ((opcode>>4)&15)
+
+/* Called for unimplemented opcodes */
+static void TODO(void)
+{
+}
+
+INLINE UINT8 RB(offs_t A)
+{
+ if (A >= 0xfe000000)
+ return sh4_internal_r(((A & 0x0fc) >> 2) | ((A & 0x1fe0000) >> 11), ~(0xff << ((A & 3)*8))) >> ((A & 3)*8);
+
+ if (A >= 0xe0000000)
+ return program_read_byte_64le(A);
+
+/* if (A >= 0x40000000)
+ return 0xa5;*/
+
+ return program_read_byte_64le(A & AM);
+}
+
+INLINE UINT16 RW(offs_t A)
+{
+ if (A >= 0xfe000000)
+ return sh4_internal_r(((A & 0x0fc) >> 2) | ((A & 0x1fe0000) >> 11), ~(0xffff << ((A & 2)*8))) >> ((A & 2)*8);
+
+ if (A >= 0xe0000000)
+ return program_read_word_64le(A);
+
+/* if (A >= 0x40000000)
+ return 0xa5a5;*/
+
+ return program_read_word_64le(A & AM);
+}
+
+INLINE UINT32 RL(offs_t A)
+{
+ if (A >= 0xfe000000)
+ return sh4_internal_r(((A & 0x0fc) >> 2) | ((A & 0x1fe0000) >> 11), 0);
+
+ if (A >= 0xe0000000)
+ return program_read_dword_64le(A);
+
+/* if (A >= 0x40000000)
+ return 0xa5a5a5a5;*/
+
+ return program_read_dword_64le(A & AM);
+}
+
+INLINE void WB(offs_t A, UINT8 V)
+{
+
+ if (A >= 0xfe000000)
+ {
+ sh4_internal_w(((A & 0x0fc) >> 2) | ((A & 0x1fe0000) >> 11), V << ((A & 3)*8), ~(0xff << ((A & 3)*8)));
+ return;
+ }
+
+ if (A >= 0xe0000000)
+ {
+ program_write_byte_64le(A,V);
+ return;
+ }
+
+/* if (A >= 0x40000000)
+ return;*/
+
+ program_write_byte_64le(A & AM,V);
+}
+
+INLINE void WW(offs_t A, UINT16 V)
+{
+ if (A >= 0xfe000000)
+ {
+ sh4_internal_w(((A & 0x0fc) >> 2) | ((A & 0x1fe0000) >> 11), V << ((A & 2)*8), ~(0xffff << ((A & 2)*8)));
+ return;
+ }
+
+ if (A >= 0xe0000000)
+ {
+ program_write_word_64le(A,V);
+ return;
+ }
+
+/* if (A >= 0x40000000)
+ return;*/
+
+ program_write_word_64le(A & AM,V);
+}
+
+INLINE void WL(offs_t A, UINT32 V)
+{
+ if (A >= 0xfe000000)
+ {
+ sh4_internal_w(((A & 0x0fc) >> 2) | ((A & 0x1fe0000) >> 11), V, 0);
+ return;
+ }
+
+ if (A >= 0xe0000000)
+ {
+ program_write_dword_64le(A,V);
+ return;
+ }
+
+/* if (A >= 0x40000000)
+ return;*/
+
+ program_write_dword_64le(A & AM,V);
+}
+
+static void sh4_change_register_bank(int to)
+{
+int s;
+
+ if (to) // 0 -> 1
+ {
+ for (s = 0;s < 8;s++)
+ {
+ sh4.rbnk[0][s] = sh4.r[s];
+ sh4.r[s] = sh4.rbnk[1][s];
+ }
+ }
+ else // 1 -> 0
+ {
+ for (s = 0;s < 8;s++)
+ {
+ sh4.rbnk[1][s] = sh4.r[s];
+ sh4.r[s] = sh4.rbnk[0][s];
+ }
+ }
+}
+
+#ifdef MAME_DEBUG
+static void sh4_syncronize_register_bank(int to)
+{
+int s;
+
+ for (s = 0;s < 8;s++)
+ {
+ sh4.rbnk[to][s] = sh4.r[s];
+ }
+}
+#endif
+
+static void sh4_default_exception_priorities(void) // setup default priorities for exceptions
+{
+int a;
+
+ for (a=0;a <= SH4_INTC_NMI;a++)
+ sh4.exception_priority[a] = exception_priority_default[a];
+ for (a=SH4_INTC_IRLn0;a <= SH4_INTC_IRLnE;a++)
+ sh4.exception_priority[a] = INTPRI(15-(a-SH4_INTC_IRLn0), a);
+ sh4.exception_priority[SH4_INTC_IRL0] = INTPRI(13, SH4_INTC_IRL0);
+ sh4.exception_priority[SH4_INTC_IRL1] = INTPRI(10, SH4_INTC_IRL1);
+ sh4.exception_priority[SH4_INTC_IRL2] = INTPRI(7, SH4_INTC_IRL2);
+ sh4.exception_priority[SH4_INTC_IRL3] = INTPRI(4, SH4_INTC_IRL3);
+ for (a=SH4_INTC_HUDI;a <= SH4_INTC_ROVI;a++)
+ sh4.exception_priority[a] = INTPRI(0, a);
+}
+
+static void sh4_exception_recompute(void) // checks if there is any interrupt with high enough priority
+{
+int a,z;
+
+ sh4.test_irq = 0;
+ if ((!sh4.pending_irq) || ((sh4.sr & BL) && (sh4.exception_requesting[SH4_INTC_NMI] == 0)))
+ return;
+ z = (sh4.sr >> 4) & 15;
+ for (a=0;a <= SH4_INTC_ROVI;a++)
+ {
+ if (sh4.exception_requesting[a])
+ if ((((int)sh4.exception_priority[a] >> 8) & 255) > z)
+ {
+ sh4.test_irq = 1; // will check for exception at end of instructions
+ break;
+ }
+ }
+}
+
+INLINE void sh4_exception_request(int exception) // start requesting an exception
+{
+ if (!sh4.exception_requesting[exception])
+ {
+ sh4.exception_requesting[exception] = 1;
+ sh4.pending_irq++;
+ sh4_exception_recompute();
+ }
+}
+
+INLINE void sh4_exception_unrequest(int exception) // stop requesting an exception
+{
+ if (sh4.exception_requesting[exception])
+ {
+ sh4.exception_requesting[exception] = 0;
+ sh4.pending_irq--;
+ sh4_exception_recompute();
+ }
+}
+
+INLINE void sh4_exception_checkunrequest(int exception)
+{
+ if (exception == SH4_INTC_NMI)
+ sh4_exception_unrequest(exception);
+ if ((exception == SH4_INTC_DMTE0) || (exception == SH4_INTC_DMTE1) ||
+ (exception == SH4_INTC_DMTE2) || (exception == SH4_INTC_DMTE3))
+ sh4_exception_unrequest(exception);
+}
+
+INLINE void sh4_exception(const char *message, int exception) // handle exception
+{
+ UINT32 vector;
+
+ if (exception < SH4_INTC_NMI)
+ return; // Not yet supported
+ if (exception == SH4_INTC_NMI) {
+ if ((sh4.sr & BL) && (!(sh4.m[ICR] & 0x200)))
+ return;
+ sh4.m[ICR] &= ~0x200;
+ sh4.m[INTEVT] = 0x1c0;
+ vector = 0x600;
+ sh4.irq_callback(INPUT_LINE_NMI);
+ LOG(("SH-4 #%d nmi exception after [%s]\n", cpu_getactivecpu(), message));
+ } else {
+// if ((sh4.m[ICR] & 0x4000) && (sh4.nmi_line_state == ASSERT_LINE))
+// return;
+ if (sh4.sr & BL)
+ return;
+ if (((sh4.exception_priority[exception] >> 8) & 255) <= ((sh4.sr >> 4) & 15))
+ return;
+ sh4.m[INTEVT] = exception_codes[exception];
+ vector = 0x600;
+ if ((exception >= SH4_INTC_IRL0) && (exception <= SH4_INTC_IRL3))
+ sh4.irq_callback(SH4_INTC_IRL0-exception+SH4_IRL0);
+ else
+ sh4.irq_callback(SH4_IRL3+1);
+ LOG(("SH-4 #%d interrupt exception #%d after [%s]\n", cpu_getactivecpu(), exception, message));
+ }
+ sh4_exception_checkunrequest(exception);
+
+ sh4.spc = sh4.pc;
+ sh4.ssr = sh4.sr;
+ sh4.sgr = sh4.r[15];
+
+ sh4.sr |= MD;
+#ifdef MAME_DEBUG
+ sh4_syncronize_register_bank((sh4.sr & sRB) >> 29);
+#endif
+ if (!(sh4.sr & sRB))
+ sh4_change_register_bank(1);
+ sh4.sr |= sRB;
+ sh4.sr |= BL;
+ sh4_exception_recompute();
+
+ /* fetch PC */
+ sh4.pc = sh4.vbr + vector;
+ change_pc(sh4.pc & AM);
+}
+
+INLINE void sh4_check_pending_irq(const char *message) // look for highest priority active exception and handle it
+{
+int a,irq,z;
+
+ irq = 0;
+ z = -1;
+ for (a=0;a <= SH4_INTC_ROVI;a++)
+ {
+ if (sh4.exception_requesting[a])
+ if ((int)sh4.exception_priority[a] > z)
+ {
+ z = sh4.exception_priority[a];
+ irq = a;
+ }
+ }
+ if (z >= 0)
+ sh4_exception(message, irq);
+}
+
+static void sh4_swap_fp_registers(void)
+{
+int s;
+UINT32 z;
+
+ for (s = 0;s <= 15;s++)
+ {
+ z = sh4.fr[s];
+ sh4.fr[s] = sh4.xf[s];
+ sh4.xf[s] = z;
+ }
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1100 1 -
+ * ADD Rm,Rn
+ */
+INLINE void ADD(UINT32 m, UINT32 n)
+{
+ sh4.r[n] += sh4.r[m];
+}
+
+/* code cycles t-bit
+ * 0111 nnnn iiii iiii 1 -
+ * ADD #imm,Rn
+ */
+INLINE void ADDI(UINT32 i, UINT32 n)
+{
+ sh4.r[n] += (INT32)(INT16)(INT8)i;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1110 1 carry
+ * ADDC Rm,Rn
+ */
+INLINE void ADDC(UINT32 m, UINT32 n)
+{
+ UINT32 tmp0, tmp1;
+
+ tmp1 = sh4.r[n] + sh4.r[m];
+ tmp0 = sh4.r[n];
+ sh4.r[n] = tmp1 + (sh4.sr & T);
+ if (tmp0 > tmp1)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+ if (tmp1 > sh4.r[n])
+ sh4.sr |= T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1111 1 overflow
+ * ADDV Rm,Rn
+ */
+INLINE void ADDV(UINT32 m, UINT32 n)
+{
+ INT32 dest, src, ans;
+
+ if ((INT32) sh4.r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((INT32) sh4.r[m] >= 0)
+ src = 0;
+ else
+ src = 1;
+ src += dest;
+ sh4.r[n] += sh4.r[m];
+ if ((INT32) sh4.r[n] >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (src == 0 || src == 2)
+ {
+ if (ans == 1)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+ }
+ else
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 1001 1 -
+ * AND Rm,Rn
+ */
+INLINE void AND(UINT32 m, UINT32 n)
+{
+ sh4.r[n] &= sh4.r[m];
+}
+
+
+/* code cycles t-bit
+ * 1100 1001 iiii iiii 1 -
+ * AND #imm,R0
+ */
+INLINE void ANDI(UINT32 i)
+{
+ sh4.r[0] &= i;
+}
+
+/* code cycles t-bit
+ * 1100 1101 iiii iiii 1 -
+ * AND.B #imm,@(R0,GBR)
+ */
+INLINE void ANDM(UINT32 i)
+{
+ UINT32 temp;
+
+ sh4.ea = sh4.gbr + sh4.r[0];
+ temp = i & RB( sh4.ea );
+ WB( sh4.ea, temp );
+ sh4_icount -= 2;
+}
+
+/* code cycles t-bit
+ * 1000 1011 dddd dddd 3/1 -
+ * BF disp8
+ */
+INLINE void BF(UINT32 d)
+{
+ if ((sh4.sr & T) == 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh4.pc = sh4.ea = sh4.pc + disp * 2 + 2;
+ change_pc(sh4.pc & AM);
+ sh4_icount -= 2;
+ }
+}
+
+/* code cycles t-bit
+ * 1000 1111 dddd dddd 3/1 -
+ * BFS disp8
+ */
+INLINE void BFS(UINT32 d)
+{
+ if ((sh4.sr & T) == 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh4.delay = sh4.pc;
+ sh4.pc = sh4.ea = sh4.pc + disp * 2 + 2;
+ sh4_icount--;
+ }
+}
+
+/* code cycles t-bit
+ * 1010 dddd dddd dddd 2 -
+ * BRA disp12
+ */
+INLINE void BRA(UINT32 d)
+{
+ INT32 disp = ((INT32)d << 20) >> 20;
+
+#if BUSY_LOOP_HACKS
+ if (disp == -2)
+ {
+ UINT32 next_opcode = RW(sh4.ppc & AM);
+ /* BRA $
+ * NOP
+ */
+ if (next_opcode == 0x0009)
+ sh4_icount %= 3; /* cycles for BRA $ and NOP taken (3) */
+ }
+#endif
+ sh4.delay = sh4.pc;
+ sh4.pc = sh4.ea = sh4.pc + disp * 2 + 2;
+ sh4_icount--;
+}
+
+/* code cycles t-bit
+ * 0000 mmmm 0010 0011 2 -
+ * BRAF Rm
+ */
+INLINE void BRAF(UINT32 m)
+{
+ sh4.delay = sh4.pc;
+ sh4.pc += sh4.r[m] + 2;
+ sh4_icount--;
+}
+
+/* code cycles t-bit
+ * 1011 dddd dddd dddd 2 -
+ * BSR disp12
+ */
+INLINE void BSR(UINT32 d)
+{
+ INT32 disp = ((INT32)d << 20) >> 20;
+
+ sh4.pr = sh4.pc + 2;
+ sh4.delay = sh4.pc;
+ sh4.pc = sh4.ea = sh4.pc + disp * 2 + 2;
+ sh4_icount--;
+}
+
+/* code cycles t-bit
+ * 0000 mmmm 0000 0011 2 -
+ * BSRF Rm
+ */
+INLINE void BSRF(UINT32 m)
+{
+ sh4.pr = sh4.pc + 2;
+ sh4.delay = sh4.pc;
+ sh4.pc += sh4.r[m] + 2;
+ sh4_icount--;
+}
+
+/* code cycles t-bit
+ * 1000 1001 dddd dddd 3/1 -
+ * BT disp8
+ */
+INLINE void BT(UINT32 d)
+{
+ if ((sh4.sr & T) != 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh4.pc = sh4.ea = sh4.pc + disp * 2 + 2;
+ change_pc(sh4.pc & AM);
+ sh4_icount -= 2;
+ }
+}
+
+/* code cycles t-bit
+ * 1000 1101 dddd dddd 2/1 -
+ * BTS disp8
+ */
+INLINE void BTS(UINT32 d)
+{
+ if ((sh4.sr & T) != 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh4.delay = sh4.pc;
+ sh4.pc = sh4.ea = sh4.pc + disp * 2 + 2;
+ sh4_icount--;
+ }
+}
+
+/* code cycles t-bit
+ * 0000 0000 0010 1000 1 -
+ * CLRMAC
+ */
+INLINE void CLRMAC(void)
+{
+ sh4.mach = 0;
+ sh4.macl = 0;
+}
+
+/* code cycles t-bit
+ * 0000 0000 0000 1000 1 -
+ * CLRT
+ */
+INLINE void CLRT(void)
+{
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0000 1 comparison result
+ * CMP_EQ Rm,Rn
+ */
+INLINE void CMPEQ(UINT32 m, UINT32 n)
+{
+ if (sh4.r[n] == sh4.r[m])
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0011 1 comparison result
+ * CMP_GE Rm,Rn
+ */
+INLINE void CMPGE(UINT32 m, UINT32 n)
+{
+ if ((INT32) sh4.r[n] >= (INT32) sh4.r[m])
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0111 1 comparison result
+ * CMP_GT Rm,Rn
+ */
+INLINE void CMPGT(UINT32 m, UINT32 n)
+{
+ if ((INT32) sh4.r[n] > (INT32) sh4.r[m])
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0110 1 comparison result
+ * CMP_HI Rm,Rn
+ */
+INLINE void CMPHI(UINT32 m, UINT32 n)
+{
+ if ((UINT32) sh4.r[n] > (UINT32) sh4.r[m])
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0010 1 comparison result
+ * CMP_HS Rm,Rn
+ */
+INLINE void CMPHS(UINT32 m, UINT32 n)
+{
+ if ((UINT32) sh4.r[n] >= (UINT32) sh4.r[m])
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+
+/* code cycles t-bit
+ * 0100 nnnn 0001 0101 1 comparison result
+ * CMP_PL Rn
+ */
+INLINE void CMPPL(UINT32 n)
+{
+ if ((INT32) sh4.r[n] > 0)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0100 nnnn 0001 0001 1 comparison result
+ * CMP_PZ Rn
+ */
+INLINE void CMPPZ(UINT32 n)
+{
+ if ((INT32) sh4.r[n] >= 0)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 1100 1 comparison result
+ * CMP_STR Rm,Rn
+ */
+INLINE void CMPSTR(UINT32 m, UINT32 n)
+ {
+ UINT32 temp;
+ INT32 HH, HL, LH, LL;
+ temp = sh4.r[n] ^ sh4.r[m];
+ HH = (temp >> 24) & 0xff;
+ HL = (temp >> 16) & 0xff;
+ LH = (temp >> 8) & 0xff;
+ LL = temp & 0xff;
+ if (HH && HL && LH && LL)
+ sh4.sr &= ~T;
+ else
+ sh4.sr |= T;
+ }
+
+
+/* code cycles t-bit
+ * 1000 1000 iiii iiii 1 comparison result
+ * CMP/EQ #imm,R0
+ */
+INLINE void CMPIM(UINT32 i)
+{
+ UINT32 imm = (UINT32)(INT32)(INT16)(INT8)i;
+
+ if (sh4.r[0] == imm)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 0111 1 calculation result
+ * DIV0S Rm,Rn
+ */
+INLINE void DIV0S(UINT32 m, UINT32 n)
+{
+ if ((sh4.r[n] & 0x80000000) == 0)
+ sh4.sr &= ~Q;
+ else
+ sh4.sr |= Q;
+ if ((sh4.r[m] & 0x80000000) == 0)
+ sh4.sr &= ~M;
+ else
+ sh4.sr |= M;
+ if ((sh4.r[m] ^ sh4.r[n]) & 0x80000000)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0000 0000 0001 1001 1 0
+ * DIV0U
+ */
+INLINE void DIV0U(void)
+{
+ sh4.sr &= ~(M | Q | T);
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0100 1 calculation result
+ * DIV1 Rm,Rn
+ */
+INLINE void DIV1(UINT32 m, UINT32 n)
+{
+ UINT32 tmp0;
+ UINT32 old_q;
+
+ old_q = sh4.sr & Q;
+ if (0x80000000 & sh4.r[n])
+ sh4.sr |= Q;
+ else
+ sh4.sr &= ~Q;
+
+ sh4.r[n] = (sh4.r[n] << 1) | (sh4.sr & T);
+
+ if (!old_q)
+ {
+ if (!(sh4.sr & M))
+ {
+ tmp0 = sh4.r[n];
+ sh4.r[n] -= sh4.r[m];
+ if(!(sh4.sr & Q))
+ if(sh4.r[n] > tmp0)
+ sh4.sr |= Q;
+ else
+ sh4.sr &= ~Q;
+ else
+ if(sh4.r[n] > tmp0)
+ sh4.sr &= ~Q;
+ else
+ sh4.sr |= Q;
+ }
+ else
+ {
+ tmp0 = sh4.r[n];
+ sh4.r[n] += sh4.r[m];
+ if(!(sh4.sr & Q))
+ {
+ if(sh4.r[n] < tmp0)
+ sh4.sr &= ~Q;
+ else
+ sh4.sr |= Q;
+ }
+ else
+ {
+ if(sh4.r[n] < tmp0)
+ sh4.sr |= Q;
+ else
+ sh4.sr &= ~Q;
+ }
+ }
+ }
+ else
+ {
+ if (!(sh4.sr & M))
+ {
+ tmp0 = sh4.r[n];
+ sh4.r[n] += sh4.r[m];
+ if(!(sh4.sr & Q))
+ if(sh4.r[n] < tmp0)
+ sh4.sr |= Q;
+ else
+ sh4.sr &= ~Q;
+ else
+ if(sh4.r[n] < tmp0)
+ sh4.sr &= ~Q;
+ else
+ sh4.sr |= Q;
+ }
+ else
+ {
+ tmp0 = sh4.r[n];
+ sh4.r[n] -= sh4.r[m];
+ if(!(sh4.sr & Q))
+ if(sh4.r[n] > tmp0)
+ sh4.sr &= ~Q;
+ else
+ sh4.sr |= Q;
+ else
+ if(sh4.r[n] > tmp0)
+ sh4.sr |= Q;
+ else
+ sh4.sr &= ~Q;
+ }
+ }
+
+ tmp0 = (sh4.sr & (Q | M));
+ if((!tmp0) || (tmp0 == 0x300)) /* if Q == M set T else clear T */
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* DMULS.L Rm,Rn */
+INLINE void DMULS(UINT32 m, UINT32 n)
+{
+ UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ UINT32 temp0, temp1, temp2, temp3;
+ INT32 tempm, tempn, fnLmL;
+
+ tempn = (INT32) sh4.r[n];
+ tempm = (INT32) sh4.r[m];
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ if ((INT32) (sh4.r[n] ^ sh4.r[m]) < 0)
+ fnLmL = -1;
+ else
+ fnLmL = 0;
+ temp1 = (UINT32) tempn;
+ temp2 = (UINT32) tempm;
+ RnL = temp1 & 0x0000ffff;
+ RnH = (temp1 >> 16) & 0x0000ffff;
+ RmL = temp2 & 0x0000ffff;
+ RmH = (temp2 >> 16) & 0x0000ffff;
+ temp0 = RmL * RnL;
+ temp1 = RmH * RnL;
+ temp2 = RmL * RnH;
+ temp3 = RmH * RnH;
+ Res2 = 0;
+ Res1 = temp1 + temp2;
+ if (Res1 < temp1)
+ Res2 += 0x00010000;
+ temp1 = (Res1 << 16) & 0xffff0000;
+ Res0 = temp0 + temp1;
+ if (Res0 < temp0)
+ Res2++;
+ Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3;
+ if (fnLmL < 0)
+ {
+ Res2 = ~Res2;
+ if (Res0 == 0)
+ Res2++;
+ else
+ Res0 = (~Res0) + 1;
+ }
+ sh4.mach = Res2;
+ sh4.macl = Res0;
+ sh4_icount--;
+}
+
+/* DMULU.L Rm,Rn */
+INLINE void DMULU(UINT32 m, UINT32 n)
+{
+ UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ UINT32 temp0, temp1, temp2, temp3;
+
+ RnL = sh4.r[n] & 0x0000ffff;
+ RnH = (sh4.r[n] >> 16) & 0x0000ffff;
+ RmL = sh4.r[m] & 0x0000ffff;
+ RmH = (sh4.r[m] >> 16) & 0x0000ffff;
+ temp0 = RmL * RnL;
+ temp1 = RmH * RnL;
+ temp2 = RmL * RnH;
+ temp3 = RmH * RnH;
+ Res2 = 0;
+ Res1 = temp1 + temp2;
+ if (Res1 < temp1)
+ Res2 += 0x00010000;
+ temp1 = (Res1 << 16) & 0xffff0000;
+ Res0 = temp0 + temp1;
+ if (Res0 < temp0)
+ Res2++;
+ Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3;
+ sh4.mach = Res2;
+ sh4.macl = Res0;
+ sh4_icount--;
+}
+
+/* DT Rn */
+INLINE void DT(UINT32 n)
+{
+ sh4.r[n]--;
+ if (sh4.r[n] == 0)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+#if BUSY_LOOP_HACKS
+ {
+ UINT32 next_opcode = RW(sh4.ppc & AM);
+ /* DT Rn
+ * BF $-2
+ */
+ if (next_opcode == 0x8bfd)
+ {
+ while (sh4.r[n] > 1 && sh4_icount > 4)
+ {
+ sh4.r[n]--;
+ sh4_icount -= 4; /* cycles for DT (1) and BF taken (3) */
+ }
+ }
+ }
+#endif
+}
+
+/* EXTS.B Rm,Rn */
+INLINE void EXTSB(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = ((INT32)sh4.r[m] << 24) >> 24;
+}
+
+/* EXTS.W Rm,Rn */
+INLINE void EXTSW(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = ((INT32)sh4.r[m] << 16) >> 16;
+}
+
+/* EXTU.B Rm,Rn */
+INLINE void EXTUB(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = sh4.r[m] & 0x000000ff;
+}
+
+/* EXTU.W Rm,Rn */
+INLINE void EXTUW(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = sh4.r[m] & 0x0000ffff;
+}
+
+/* JMP @Rm */
+INLINE void JMP(UINT32 m)
+{
+ sh4.delay = sh4.pc;
+ sh4.pc = sh4.ea = sh4.r[m];
+}
+
+/* JSR @Rm */
+INLINE void JSR(UINT32 m)
+{
+ sh4.delay = sh4.pc;
+ sh4.pr = sh4.pc + 2;
+ sh4.pc = sh4.ea = sh4.r[m];
+ sh4_icount--;
+}
+
+
+/* LDC Rm,SR */
+INLINE void LDCSR(UINT32 m)
+{
+#ifdef MAME_DEBUG
+ sh4_syncronize_register_bank((sh4.sr & sRB) >> 29);
+#endif
+ if ((sh4.r[m] & sRB) != (sh4.sr & sRB))
+ sh4_change_register_bank(sh4.r[m] & sRB ? 1 : 0);
+ sh4.sr = sh4.r[m] & FLAGS;
+ sh4_exception_recompute();
+}
+
+/* LDC Rm,GBR */
+INLINE void LDCGBR(UINT32 m)
+{
+ sh4.gbr = sh4.r[m];
+}
+
+/* LDC Rm,VBR */
+INLINE void LDCVBR(UINT32 m)
+{
+ sh4.vbr = sh4.r[m];
+}
+
+/* LDC.L @Rm+,SR */
+INLINE void LDCMSR(UINT32 m)
+{
+UINT32 old;
+
+ old = sh4.sr;
+ sh4.ea = sh4.r[m];
+ sh4.sr = RL( sh4.ea ) & FLAGS;
+#ifdef MAME_DEBUG
+ sh4_syncronize_register_bank((old & sRB) >> 29);
+#endif
+ if ((old & sRB) != (sh4.sr & sRB))
+ sh4_change_register_bank(sh4.sr & sRB ? 1 : 0);
+ sh4.r[m] += 4;
+ sh4_icount -= 2;
+ sh4_exception_recompute();
+}
+
+/* LDC.L @Rm+,GBR */
+INLINE void LDCMGBR(UINT32 m)
+{
+ sh4.ea = sh4.r[m];
+ sh4.gbr = RL( sh4.ea );
+ sh4.r[m] += 4;
+ sh4_icount -= 2;
+}
+
+/* LDC.L @Rm+,VBR */
+INLINE void LDCMVBR(UINT32 m)
+{
+ sh4.ea = sh4.r[m];
+ sh4.vbr = RL( sh4.ea );
+ sh4.r[m] += 4;
+ sh4_icount -= 2;
+}
+
+/* LDS Rm,MACH */
+INLINE void LDSMACH(UINT32 m)
+{
+ sh4.mach = sh4.r[m];
+}
+
+/* LDS Rm,MACL */
+INLINE void LDSMACL(UINT32 m)
+{
+ sh4.macl = sh4.r[m];
+}
+
+/* LDS Rm,PR */
+INLINE void LDSPR(UINT32 m)
+{
+ sh4.pr = sh4.r[m];
+}
+
+/* LDS.L @Rm+,MACH */
+INLINE void LDSMMACH(UINT32 m)
+{
+ sh4.ea = sh4.r[m];
+ sh4.mach = RL( sh4.ea );
+ sh4.r[m] += 4;
+}
+
+/* LDS.L @Rm+,MACL */
+INLINE void LDSMMACL(UINT32 m)
+{
+ sh4.ea = sh4.r[m];
+ sh4.macl = RL( sh4.ea );
+ sh4.r[m] += 4;
+}
+
+/* LDS.L @Rm+,PR */
+INLINE void LDSMPR(UINT32 m)
+{
+ sh4.ea = sh4.r[m];
+ sh4.pr = RL( sh4.ea );
+ sh4.r[m] += 4;
+}
+
+/* MAC.L @Rm+,@Rn+ */
+INLINE void MAC_L(UINT32 m, UINT32 n)
+{
+ UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ UINT32 temp0, temp1, temp2, temp3;
+ INT32 tempm, tempn, fnLmL;
+
+ tempn = (INT32) RL( sh4.r[n] );
+ sh4.r[n] += 4;
+ tempm = (INT32) RL( sh4.r[m] );
+ sh4.r[m] += 4;
+ if ((INT32) (tempn ^ tempm) < 0)
+ fnLmL = -1;
+ else
+ fnLmL = 0;
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ temp1 = (UINT32) tempn;
+ temp2 = (UINT32) tempm;
+ RnL = temp1 & 0x0000ffff;
+ RnH = (temp1 >> 16) & 0x0000ffff;
+ RmL = temp2 & 0x0000ffff;
+ RmH = (temp2 >> 16) & 0x0000ffff;
+ temp0 = RmL * RnL;
+ temp1 = RmH * RnL;
+ temp2 = RmL * RnH;
+ temp3 = RmH * RnH;
+ Res2 = 0;
+ Res1 = temp1 + temp2;
+ if (Res1 < temp1)
+ Res2 += 0x00010000;
+ temp1 = (Res1 << 16) & 0xffff0000;
+ Res0 = temp0 + temp1;
+ if (Res0 < temp0)
+ Res2++;
+ Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3;
+ if (fnLmL < 0)
+ {
+ Res2 = ~Res2;
+ if (Res0 == 0)
+ Res2++;
+ else
+ Res0 = (~Res0) + 1;
+ }
+ if (sh4.sr & S)
+ {
+ Res0 = sh4.macl + Res0;
+ if (sh4.macl > Res0)
+ Res2++;
+ Res2 += (sh4.mach & 0x0000ffff);
+ if (((INT32) Res2 < 0) && (Res2 < 0xffff8000))
+ {
+ Res2 = 0x00008000;
+ Res0 = 0x00000000;
+ }
+ else if (((INT32) Res2 > 0) && (Res2 > 0x00007fff))
+ {
+ Res2 = 0x00007fff;
+ Res0 = 0xffffffff;
+ }
+ sh4.mach = Res2;
+ sh4.macl = Res0;
+ }
+ else
+ {
+ Res0 = sh4.macl + Res0;
+ if (sh4.macl > Res0)
+ Res2++;
+ Res2 += sh4.mach;
+ sh4.mach = Res2;
+ sh4.macl = Res0;
+ }
+ sh4_icount -= 2;
+}
+
+/* MAC.W @Rm+,@Rn+ */
+INLINE void MAC_W(UINT32 m, UINT32 n)
+{
+ INT32 tempm, tempn, dest, src, ans;
+ UINT32 templ;
+
+ tempn = (INT32) RW( sh4.r[n] );
+ sh4.r[n] += 2;
+ tempm = (INT32) RW( sh4.r[m] );
+ sh4.r[m] += 2;
+ templ = sh4.macl;
+ tempm = ((INT32) (short) tempn * (INT32) (short) tempm);
+ if ((INT32) sh4.macl >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((INT32) tempm >= 0)
+ {
+ src = 0;
+ tempn = 0;
+ }
+ else
+ {
+ src = 1;
+ tempn = 0xffffffff;
+ }
+ src += dest;
+ sh4.macl += tempm;
+ if ((INT32) sh4.macl >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (sh4.sr & S)
+ {
+ if (ans == 1)
+ {
+ if (src == 0)
+ sh4.macl = 0x7fffffff;
+ if (src == 2)
+ sh4.macl = 0x80000000;
+ }
+ }
+ else
+ {
+ sh4.mach += tempn;
+ if (templ > sh4.macl)
+ sh4.mach += 1;
+ }
+ sh4_icount -= 2;
+}
+
+/* MOV Rm,Rn */
+INLINE void MOV(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = sh4.r[m];
+}
+
+/* MOV.B Rm,@Rn */
+INLINE void MOVBS(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[n];
+ WB( sh4.ea, sh4.r[m] & 0x000000ff);
+}
+
+/* MOV.W Rm,@Rn */
+INLINE void MOVWS(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[n];
+ WW( sh4.ea, sh4.r[m] & 0x0000ffff);
+}
+
+/* MOV.L Rm,@Rn */
+INLINE void MOVLS(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.r[m] );
+}
+
+/* MOV.B @Rm,Rn */
+INLINE void MOVBL(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[m];
+ sh4.r[n] = (UINT32)(INT32)(INT16)(INT8) RB( sh4.ea );
+}
+
+/* MOV.W @Rm,Rn */
+INLINE void MOVWL(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[m];
+ sh4.r[n] = (UINT32)(INT32)(INT16) RW( sh4.ea );
+}
+
+/* MOV.L @Rm,Rn */
+INLINE void MOVLL(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[m];
+ sh4.r[n] = RL( sh4.ea );
+}
+
+/* MOV.B Rm,@-Rn */
+INLINE void MOVBM(UINT32 m, UINT32 n)
+{
+ /* SMG : bug fix, was reading sh4.r[n] */
+ UINT32 data = sh4.r[m] & 0x000000ff;
+
+ sh4.r[n] -= 1;
+ WB( sh4.r[n], data );
+}
+
+/* MOV.W Rm,@-Rn */
+INLINE void MOVWM(UINT32 m, UINT32 n)
+{
+ UINT32 data = sh4.r[m] & 0x0000ffff;
+
+ sh4.r[n] -= 2;
+ WW( sh4.r[n], data );
+}
+
+/* MOV.L Rm,@-Rn */
+INLINE void MOVLM(UINT32 m, UINT32 n)
+{
+ UINT32 data = sh4.r[m];
+
+ sh4.r[n] -= 4;
+ WL( sh4.r[n], data );
+}
+
+/* MOV.B @Rm+,Rn */
+INLINE void MOVBP(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = (UINT32)(INT32)(INT16)(INT8) RB( sh4.r[m] );
+ if (n != m)
+ sh4.r[m] += 1;
+}
+
+/* MOV.W @Rm+,Rn */
+INLINE void MOVWP(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = (UINT32)(INT32)(INT16) RW( sh4.r[m] );
+ if (n != m)
+ sh4.r[m] += 2;
+}
+
+/* MOV.L @Rm+,Rn */
+INLINE void MOVLP(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = RL( sh4.r[m] );
+ if (n != m)
+ sh4.r[m] += 4;
+}
+
+/* MOV.B Rm,@(R0,Rn) */
+INLINE void MOVBS0(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[n] + sh4.r[0];
+ WB( sh4.ea, sh4.r[m] & 0x000000ff );
+}
+
+/* MOV.W Rm,@(R0,Rn) */
+INLINE void MOVWS0(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[n] + sh4.r[0];
+ WW( sh4.ea, sh4.r[m] & 0x0000ffff );
+}
+
+/* MOV.L Rm,@(R0,Rn) */
+INLINE void MOVLS0(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[n] + sh4.r[0];
+ WL( sh4.ea, sh4.r[m] );
+}
+
+/* MOV.B @(R0,Rm),Rn */
+INLINE void MOVBL0(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[m] + sh4.r[0];
+ sh4.r[n] = (UINT32)(INT32)(INT16)(INT8) RB( sh4.ea );
+}
+
+/* MOV.W @(R0,Rm),Rn */
+INLINE void MOVWL0(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[m] + sh4.r[0];
+ sh4.r[n] = (UINT32)(INT32)(INT16) RW( sh4.ea );
+}
+
+/* MOV.L @(R0,Rm),Rn */
+INLINE void MOVLL0(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[m] + sh4.r[0];
+ sh4.r[n] = RL( sh4.ea );
+}
+
+/* MOV #imm,Rn */
+INLINE void MOVI(UINT32 i, UINT32 n)
+{
+ sh4.r[n] = (UINT32)(INT32)(INT16)(INT8) i;
+}
+
+/* MOV.W @(disp8,PC),Rn */
+INLINE void MOVWI(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0xff;
+ sh4.ea = sh4.pc + disp * 2 + 2;
+ sh4.r[n] = (UINT32)(INT32)(INT16) RW( sh4.ea );
+}
+
+/* MOV.L @(disp8,PC),Rn */
+INLINE void MOVLI(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0xff;
+ sh4.ea = ((sh4.pc + 2) & ~3) + disp * 4;
+ sh4.r[n] = RL( sh4.ea );
+}
+
+/* MOV.B @(disp8,GBR),R0 */
+INLINE void MOVBLG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh4.ea = sh4.gbr + disp;
+ sh4.r[0] = (UINT32)(INT32)(INT16)(INT8) RB( sh4.ea );
+}
+
+/* MOV.W @(disp8,GBR),R0 */
+INLINE void MOVWLG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh4.ea = sh4.gbr + disp * 2;
+ sh4.r[0] = (INT32)(INT16) RW( sh4.ea );
+}
+
+/* MOV.L @(disp8,GBR),R0 */
+INLINE void MOVLLG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh4.ea = sh4.gbr + disp * 4;
+ sh4.r[0] = RL( sh4.ea );
+}
+
+/* MOV.B R0,@(disp8,GBR) */
+INLINE void MOVBSG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh4.ea = sh4.gbr + disp;
+ WB( sh4.ea, sh4.r[0] & 0x000000ff );
+}
+
+/* MOV.W R0,@(disp8,GBR) */
+INLINE void MOVWSG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh4.ea = sh4.gbr + disp * 2;
+ WW( sh4.ea, sh4.r[0] & 0x0000ffff );
+}
+
+/* MOV.L R0,@(disp8,GBR) */
+INLINE void MOVLSG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh4.ea = sh4.gbr + disp * 4;
+ WL( sh4.ea, sh4.r[0] );
+}
+
+/* MOV.B R0,@(disp4,Rn) */
+INLINE void MOVBS4(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh4.ea = sh4.r[n] + disp;
+ WB( sh4.ea, sh4.r[0] & 0x000000ff );
+}
+
+/* MOV.W R0,@(disp4,Rn) */
+INLINE void MOVWS4(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh4.ea = sh4.r[n] + disp * 2;
+ WW( sh4.ea, sh4.r[0] & 0x0000ffff );
+}
+
+/* MOV.L Rm,@(disp4,Rn) */
+INLINE void MOVLS4(UINT32 m, UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh4.ea = sh4.r[n] + disp * 4;
+ WL( sh4.ea, sh4.r[m] );
+}
+
+/* MOV.B @(disp4,Rm),R0 */
+INLINE void MOVBL4(UINT32 m, UINT32 d)
+{
+ UINT32 disp = d & 0x0f;
+ sh4.ea = sh4.r[m] + disp;
+ sh4.r[0] = (UINT32)(INT32)(INT16)(INT8) RB( sh4.ea );
+}
+
+/* MOV.W @(disp4,Rm),R0 */
+INLINE void MOVWL4(UINT32 m, UINT32 d)
+{
+ UINT32 disp = d & 0x0f;
+ sh4.ea = sh4.r[m] + disp * 2;
+ sh4.r[0] = (UINT32)(INT32)(INT16) RW( sh4.ea );
+}
+
+/* MOV.L @(disp4,Rm),Rn */
+INLINE void MOVLL4(UINT32 m, UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh4.ea = sh4.r[m] + disp * 4;
+ sh4.r[n] = RL( sh4.ea );
+}
+
+/* MOVA @(disp8,PC),R0 */
+INLINE void MOVA(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh4.ea = ((sh4.pc + 2) & ~3) + disp * 4;
+ sh4.r[0] = sh4.ea;
+}
+
+/* MOVT Rn */
+INLINE void MOVT(UINT32 n)
+{
+ sh4.r[n] = sh4.sr & T;
+}
+
+/* MUL.L Rm,Rn */
+INLINE void MULL(UINT32 m, UINT32 n)
+{
+ sh4.macl = sh4.r[n] * sh4.r[m];
+ sh4_icount--;
+}
+
+/* MULS Rm,Rn */
+INLINE void MULS(UINT32 m, UINT32 n)
+{
+ sh4.macl = (INT16) sh4.r[n] * (INT16) sh4.r[m];
+}
+
+/* MULU Rm,Rn */
+INLINE void MULU(UINT32 m, UINT32 n)
+{
+ sh4.macl = (UINT16) sh4.r[n] * (UINT16) sh4.r[m];
+}
+
+/* NEG Rm,Rn */
+INLINE void NEG(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = 0 - sh4.r[m];
+}
+
+/* NEGC Rm,Rn */
+INLINE void NEGC(UINT32 m, UINT32 n)
+{
+ UINT32 temp;
+
+ temp = sh4.r[m];
+ sh4.r[n] = -temp - (sh4.sr & T);
+ if (temp || (sh4.sr & T))
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* NOP */
+INLINE void NOP(void)
+{
+}
+
+/* NOT Rm,Rn */
+INLINE void NOT(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = ~sh4.r[m];
+}
+
+/* OR Rm,Rn */
+INLINE void OR(UINT32 m, UINT32 n)
+{
+ sh4.r[n] |= sh4.r[m];
+}
+
+/* OR #imm,R0 */
+INLINE void ORI(UINT32 i)
+{
+ sh4.r[0] |= i;
+ sh4_icount -= 2;
+}
+
+/* OR.B #imm,@(R0,GBR) */
+INLINE void ORM(UINT32 i)
+{
+ UINT32 temp;
+
+ sh4.ea = sh4.gbr + sh4.r[0];
+ temp = RB( sh4.ea );
+ temp |= i;
+ WB( sh4.ea, temp );
+}
+
+/* ROTCL Rn */
+INLINE void ROTCL(UINT32 n)
+{
+ UINT32 temp;
+
+ temp = (sh4.r[n] >> 31) & T;
+ sh4.r[n] = (sh4.r[n] << 1) | (sh4.sr & T);
+ sh4.sr = (sh4.sr & ~T) | temp;
+}
+
+/* ROTCR Rn */
+INLINE void ROTCR(UINT32 n)
+{
+ UINT32 temp;
+ temp = (sh4.sr & T) << 31;
+ if (sh4.r[n] & T)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+ sh4.r[n] = (sh4.r[n] >> 1) | temp;
+}
+
+/* ROTL Rn */
+INLINE void ROTL(UINT32 n)
+{
+ sh4.sr = (sh4.sr & ~T) | ((sh4.r[n] >> 31) & T);
+ sh4.r[n] = (sh4.r[n] << 1) | (sh4.r[n] >> 31);
+}
+
+/* ROTR Rn */
+INLINE void ROTR(UINT32 n)
+{
+ sh4.sr = (sh4.sr & ~T) | (sh4.r[n] & T);
+ sh4.r[n] = (sh4.r[n] >> 1) | (sh4.r[n] << 31);
+}
+
+/* RTE */
+INLINE void RTE(void)
+{
+ sh4.delay = sh4.pc;
+ sh4.pc = sh4.ea = sh4.spc;
+#ifdef MAME_DEBUG
+ sh4_syncronize_register_bank((sh4.sr & sRB) >> 29);
+#endif
+ if ((sh4.ssr & sRB) != (sh4.sr & sRB))
+ sh4_change_register_bank(sh4.ssr & sRB ? 1 : 0);
+ sh4.sr = sh4.ssr;
+ sh4_icount--;
+ sh4_exception_recompute();
+}
+
+/* RTS */
+INLINE void RTS(void)
+{
+ sh4.delay = sh4.pc;
+ sh4.pc = sh4.ea = sh4.pr;
+ sh4_icount--;
+}
+
+/* SETT */
+INLINE void SETT(void)
+{
+ sh4.sr |= T;
+}
+
+/* SHAL Rn (same as SHLL) */
+INLINE void SHAL(UINT32 n)
+{
+ sh4.sr = (sh4.sr & ~T) | ((sh4.r[n] >> 31) & T);
+ sh4.r[n] <<= 1;
+}
+
+/* SHAR Rn */
+INLINE void SHAR(UINT32 n)
+{
+ sh4.sr = (sh4.sr & ~T) | (sh4.r[n] & T);
+ sh4.r[n] = (UINT32)((INT32)sh4.r[n] >> 1);
+}
+
+/* SHLL Rn (same as SHAL) */
+INLINE void SHLL(UINT32 n)
+{
+ sh4.sr = (sh4.sr & ~T) | ((sh4.r[n] >> 31) & T);
+ sh4.r[n] <<= 1;
+}
+
+/* SHLL2 Rn */
+INLINE void SHLL2(UINT32 n)
+{
+ sh4.r[n] <<= 2;
+}
+
+/* SHLL8 Rn */
+INLINE void SHLL8(UINT32 n)
+{
+ sh4.r[n] <<= 8;
+}
+
+/* SHLL16 Rn */
+INLINE void SHLL16(UINT32 n)
+{
+ sh4.r[n] <<= 16;
+}
+
+/* SHLR Rn */
+INLINE void SHLR(UINT32 n)
+{
+ sh4.sr = (sh4.sr & ~T) | (sh4.r[n] & T);
+ sh4.r[n] >>= 1;
+}
+
+/* SHLR2 Rn */
+INLINE void SHLR2(UINT32 n)
+{
+ sh4.r[n] >>= 2;
+}
+
+/* SHLR8 Rn */
+INLINE void SHLR8(UINT32 n)
+{
+ sh4.r[n] >>= 8;
+}
+
+/* SHLR16 Rn */
+INLINE void SHLR16(UINT32 n)
+{
+ sh4.r[n] >>= 16;
+}
+
+/* SLEEP */
+INLINE void SLEEP(void)
+{
+ sh4.pc -= 2;
+ sh4_icount -= 2;
+ /* Wait_for_exception; */
+}
+
+/* STC SR,Rn */
+INLINE void STCSR(UINT32 n)
+{
+ sh4.r[n] = sh4.sr;
+}
+
+/* STC GBR,Rn */
+INLINE void STCGBR(UINT32 n)
+{
+ sh4.r[n] = sh4.gbr;
+}
+
+/* STC VBR,Rn */
+INLINE void STCVBR(UINT32 n)
+{
+ sh4.r[n] = sh4.vbr;
+}
+
+/* STC.L SR,@-Rn */
+INLINE void STCMSR(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.sr );
+ sh4_icount--;
+}
+
+/* STC.L GBR,@-Rn */
+INLINE void STCMGBR(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.gbr );
+ sh4_icount--;
+}
+
+/* STC.L VBR,@-Rn */
+INLINE void STCMVBR(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.vbr );
+ sh4_icount--;
+}
+
+/* STS MACH,Rn */
+INLINE void STSMACH(UINT32 n)
+{
+ sh4.r[n] = sh4.mach;
+}
+
+/* STS MACL,Rn */
+INLINE void STSMACL(UINT32 n)
+{
+ sh4.r[n] = sh4.macl;
+}
+
+/* STS PR,Rn */
+INLINE void STSPR(UINT32 n)
+{
+ sh4.r[n] = sh4.pr;
+}
+
+/* STS.L MACH,@-Rn */
+INLINE void STSMMACH(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.mach );
+}
+
+/* STS.L MACL,@-Rn */
+INLINE void STSMMACL(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.macl );
+}
+
+/* STS.L PR,@-Rn */
+INLINE void STSMPR(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.pr );
+}
+
+/* SUB Rm,Rn */
+INLINE void SUB(UINT32 m, UINT32 n)
+{
+ sh4.r[n] -= sh4.r[m];
+}
+
+/* SUBC Rm,Rn */
+INLINE void SUBC(UINT32 m, UINT32 n)
+{
+ UINT32 tmp0, tmp1;
+
+ tmp1 = sh4.r[n] - sh4.r[m];
+ tmp0 = sh4.r[n];
+ sh4.r[n] = tmp1 - (sh4.sr & T);
+ if (tmp0 < tmp1)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+ if (tmp1 < sh4.r[n])
+ sh4.sr |= T;
+}
+
+/* SUBV Rm,Rn */
+INLINE void SUBV(UINT32 m, UINT32 n)
+{
+ INT32 dest, src, ans;
+
+ if ((INT32) sh4.r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((INT32) sh4.r[m] >= 0)
+ src = 0;
+ else
+ src = 1;
+ src += dest;
+ sh4.r[n] -= sh4.r[m];
+ if ((INT32) sh4.r[n] >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (src == 1)
+ {
+ if (ans == 1)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+ }
+ else
+ sh4.sr &= ~T;
+}
+
+/* SWAP.B Rm,Rn */
+INLINE void SWAPB(UINT32 m, UINT32 n)
+{
+ UINT32 temp0, temp1;
+
+ temp0 = sh4.r[m] & 0xffff0000;
+ temp1 = (sh4.r[m] & 0x000000ff) << 8;
+ sh4.r[n] = (sh4.r[m] >> 8) & 0x000000ff;
+ sh4.r[n] = sh4.r[n] | temp1 | temp0;
+}
+
+/* SWAP.W Rm,Rn */
+INLINE void SWAPW(UINT32 m, UINT32 n)
+{
+ UINT32 temp;
+
+ temp = (sh4.r[m] >> 16) & 0x0000ffff;
+ sh4.r[n] = (sh4.r[m] << 16) | temp;
+}
+
+/* TAS.B @Rn */
+INLINE void TAS(UINT32 n)
+{
+ UINT32 temp;
+ sh4.ea = sh4.r[n];
+ /* Bus Lock enable */
+ temp = RB( sh4.ea );
+ if (temp == 0)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+ temp |= 0x80;
+ /* Bus Lock disable */
+ WB( sh4.ea, temp );
+ sh4_icount -= 3;
+}
+
+/* TRAPA #imm */
+INLINE void TRAPA(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+
+ sh4.ea = sh4.vbr + imm * 4;
+
+ sh4.r[15] -= 4;
+ WL( sh4.r[15], sh4.sr );
+ sh4.r[15] -= 4;
+ WL( sh4.r[15], sh4.pc );
+
+ sh4.pc = RL( sh4.ea );
+ change_pc(sh4.pc & AM);
+
+ sh4_icount -= 7;
+}
+
+/* TST Rm,Rn */
+INLINE void TST(UINT32 m, UINT32 n)
+{
+ if ((sh4.r[n] & sh4.r[m]) == 0)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* TST #imm,R0 */
+INLINE void TSTI(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+
+ if ((imm & sh4.r[0]) == 0)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+}
+
+/* TST.B #imm,@(R0,GBR) */
+INLINE void TSTM(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+
+ sh4.ea = sh4.gbr + sh4.r[0];
+ if ((imm & RB( sh4.ea )) == 0)
+ sh4.sr |= T;
+ else
+ sh4.sr &= ~T;
+ sh4_icount -= 2;
+}
+
+/* XOR Rm,Rn */
+INLINE void XOR(UINT32 m, UINT32 n)
+{
+ sh4.r[n] ^= sh4.r[m];
+}
+
+/* XOR #imm,R0 */
+INLINE void XORI(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+ sh4.r[0] ^= imm;
+}
+
+/* XOR.B #imm,@(R0,GBR) */
+INLINE void XORM(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+ UINT32 temp;
+
+ sh4.ea = sh4.gbr + sh4.r[0];
+ temp = RB( sh4.ea );
+ temp ^= imm;
+ WB( sh4.ea, temp );
+ sh4_icount -= 2;
+}
+
+/* XTRCT Rm,Rn */
+INLINE void XTRCT(UINT32 m, UINT32 n)
+{
+ UINT32 temp;
+
+ temp = (sh4.r[m] << 16) & 0xffff0000;
+ sh4.r[n] = (sh4.r[n] >> 16) & 0x0000ffff;
+ sh4.r[n] |= temp;
+}
+
+/* STC SSR,Rn */
+INLINE void STCSSR(UINT32 n)
+{
+ sh4.r[n] = sh4.ssr;
+}
+
+/* STC SPC,Rn */
+INLINE void STCSPC(UINT32 n)
+{
+ sh4.r[n] = sh4.spc;
+}
+
+/* STC SGR,Rn */
+INLINE void STCSGR(UINT32 n)
+{
+ sh4.r[n] = sh4.sgr;
+}
+
+/* STS FPUL,Rn */
+INLINE void STSFPUL(UINT32 n)
+{
+ sh4.r[n] = sh4.fpul;
+}
+
+/* STS FPSCR,Rn */
+INLINE void STSFPSCR(UINT32 n)
+{
+ sh4.r[n] = sh4.fpscr & 0x003FFFFF;
+}
+
+/* STC DBR,Rn */
+INLINE void STCDBR(UINT32 n)
+{
+ sh4.r[n] = sh4.dbr;
+}
+
+/* STCRBANK Rm_BANK,Rn */
+INLINE void STCRBANK(UINT32 m, UINT32 n)
+{
+ sh4.r[n] = sh4.rbnk[sh4.sr&sRB ? 0 : 1][m & 7];
+}
+
+/* STCMRBANK Rm_BANK,@-Rn */
+INLINE void STCMRBANK(UINT32 m, UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.rbnk[sh4.sr&sRB ? 0 : 1][m & 7]);
+ sh4_icount--;
+}
+
+/* MOVCA.L R0,@Rn */
+INLINE void MOVCAL(UINT32 n)
+{
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.r[0] );
+}
+
+INLINE void CLRS(void)
+{
+ sh4.sr &= ~S;
+}
+
+INLINE void SETS(void)
+{
+ sh4.sr |= S;
+}
+
+/* STS.L SGR,@-Rn */
+INLINE void STCMSGR(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.sgr );
+}
+
+/* STS.L FPUL,@-Rn */
+INLINE void STSMFPUL(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.fpul );
+}
+
+/* STS.L FPSCR,@-Rn */
+INLINE void STSMFPSCR(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.fpscr & 0x003FFFFF);
+}
+
+/* STC.L DBR,@-Rn */
+INLINE void STCMDBR(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.dbr );
+}
+
+/* STC.L SSR,@-Rn */
+INLINE void STCMSSR(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.ssr );
+}
+
+/* STC.L SPC,@-Rn */
+INLINE void STCMSPC(UINT32 n)
+{
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea, sh4.spc );
+}
+
+/* LDS.L @Rm+,FPUL */
+INLINE void LDSMFPUL(UINT32 m)
+{
+ sh4.ea = sh4.r[m];
+ sh4.fpul = RL( sh4.ea );
+ sh4.r[m] += 4;
+}
+
+/* LDS.L @Rm+,FPSCR */
+INLINE void LDSMFPSCR(UINT32 m)
+{
+UINT32 s;
+
+ s = sh4.fpscr;
+ sh4.ea = sh4.r[m];
+ sh4.fpscr = RL( sh4.ea );
+ sh4.fpscr &= 0x003FFFFF;
+ sh4.r[m] += 4;
+ if ((s & FR) != (sh4.fpscr & FR))
+ sh4_swap_fp_registers();
+}
+
+/* LDC.L @Rm+,DBR */
+INLINE void LDCMDBR(UINT32 m)
+{
+ sh4.ea = sh4.r[m];
+ sh4.dbr = RL( sh4.ea );
+ sh4.r[m] += 4;
+}
+
+/* LDC.L @Rn+,Rm_BANK */
+INLINE void LDCMRBANK(UINT32 m, UINT32 n)
+{
+ sh4.ea = sh4.r[n];
+ sh4.rbnk[sh4.sr&sRB ? 0 : 1][m & 7] = RL( sh4.ea );
+ sh4.r[n] += 4;
+}
+
+/* LDC.L @Rm+,SSR */
+INLINE void LDCMSSR(UINT32 m)
+{
+ sh4.ea = sh4.r[m];
+ sh4.ssr = RL( sh4.ea );
+ sh4.r[m] += 4;
+}
+
+/* LDC.L @Rm+,SPC */
+INLINE void LDCMSPC(UINT32 m)
+{
+ sh4.ea = sh4.r[m];
+ sh4.spc = RL( sh4.ea );
+ sh4.r[m] += 4;
+}
+
+/* LDS Rm,FPUL */
+INLINE void LDSFPUL(UINT32 m)
+{
+ sh4.fpul = sh4.r[m];
+}
+
+/* LDS Rm,FPSCR */
+INLINE void LDSFPSCR(UINT32 m)
+{
+UINT32 s;
+
+ s = sh4.fpscr;
+ sh4.fpscr = sh4.r[m] & 0x003FFFFF;
+ if ((s & FR) != (sh4.fpscr & FR))
+ sh4_swap_fp_registers();
+}
+
+/* LDC Rm,DBR */
+INLINE void LDCDBR(UINT32 m)
+{
+ sh4.dbr = sh4.r[m];
+}
+
+/* SHAD Rm,Rn */
+INLINE void SHAD(UINT32 m,UINT32 n)
+{
+ if ((sh4.r[m] & 0x80000000) == 0)
+ sh4.r[n] = sh4.r[n] << (sh4.r[m] & 0x1F);
+ else if ((sh4.r[m] & 0x1F) == 0) {
+ if ((sh4.r[n] & 0x80000000) == 0)
+ sh4.r[n] = 0;
+ else
+ sh4.r[n] = 0xFFFFFFFF;
+ } else
+ sh4.r[n]=(INT32)sh4.r[n] >> ((~sh4.r[m] & 0x1F)+1);
+}
+
+/* SHLD Rm,Rn */
+INLINE void SHLD(UINT32 m,UINT32 n)
+{
+ if ((sh4.r[m] & 0x80000000) == 0)
+ sh4.r[n] = sh4.r[n] << (sh4.r[m] & 0x1F);
+ else if ((sh4.r[m] & 0x1F) == 0)
+ sh4.r[n] = 0;
+ else
+ sh4.r[n] = sh4.r[n] >> ((~sh4.r[m] & 0x1F)+1);
+}
+
+/* LDCRBANK Rn,Rm_BANK */
+INLINE void LDCRBANK(UINT32 m, UINT32 n)
+{
+ sh4.rbnk[sh4.sr&sRB ? 0 : 1][m & 7] = sh4.r[n];
+}
+
+/* LDC Rm,SSR */
+INLINE void LDCSSR(UINT32 m)
+{
+ sh4.ssr = sh4.r[m];
+}
+
+/* LDC Rm,SPC */
+INLINE void LDCSPC(UINT32 m)
+{
+ sh4.spc = sh4.r[m];
+}
+
+/* PREF @Rn */
+INLINE void PREFM(UINT32 n)
+{
+int a;
+UINT32 addr,dest,sq;
+
+ addr = sh4.r[n]; // address
+ if ((addr >= 0xE0000000) && (addr <= 0xE3FFFFFF))
+ {
+ sq = (addr & 0x20) >> 5;
+ dest = addr & 0x03FFFFE0;
+ if (sq == 0)
+ dest |= (sh4.m[QACR0] & 0x1C) << 24;
+ else
+ dest |= (sh4.m[QACR1] & 0x1C) << 24;
+ addr = addr & 0xFFFFFFE0;
+ for (a = 0;a < 8;a++)
+ {
+ program_write_dword_64le(dest, program_read_dword_64le(addr));
+ addr += 4;
+ dest += 4;
+ }
+ }
+}
+
+/*****************************************************************************
+ * OPCODE DISPATCHERS
+ *****************************************************************************/
+INLINE void op0000(UINT16 opcode)
+{
+ switch (opcode & 0xF)
+ {
+ case 0x0:
+ case 0x1:
+ break;
+ case 0x2:
+ if (opcode & 0x80) {
+ STCRBANK(Rm, Rn); return;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ STCSR(Rn); break;
+ case 0x10:
+ STCGBR(Rn); break;
+ case 0x20:
+ STCVBR(Rn); break;
+ case 0x30:
+ STCSSR(Rn); break;
+ case 0x40:
+ STCSPC(Rn); break;
+ }
+ break;
+ case 0x3:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ BSRF(Rn); break;
+ case 0x20:
+ BRAF(Rn); break;
+ case 0x80:
+ PREFM(Rn); break;
+ case 0x90:
+ TODO(); break;
+ case 0xA0:
+ TODO(); break;
+ case 0xB0:
+ TODO(); break;
+ case 0xC0:
+ MOVCAL(Rn); break;
+ }
+ break;
+ case 0x4:
+ MOVBS0(Rm, Rn); break;
+ case 0x5:
+ MOVWS0(Rm, Rn); break;
+ case 0x6:
+ MOVLS0(Rm, Rn); break;
+ case 0x7:
+ MULL(Rm, Rn); break;
+ case 0x8:
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ CLRT(); break;
+ case 0x10:
+ SETT(); break;
+ case 0x20:
+ CLRMAC(); break;
+ case 0x30:
+ TODO(); break;
+ case 0x40:
+ CLRS(); break;
+ case 0x50:
+ SETS(); break;
+ }
+ break;
+ case 0x9:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ NOP(); break;
+ case 0x10:
+ DIV0U(); break;
+ case 0x20:
+ MOVT(Rn); break;
+ }
+ break;
+ case 0xA:
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ STSMACH(Rn); break;
+ case 0x10:
+ STSMACL(Rn); break;
+ case 0x20:
+ STSPR(Rn); break;
+ case 0x30:
+ STCSGR(Rn); break;
+ case 0x50:
+ STSFPUL(Rn); break;
+ case 0x60:
+ STSFPSCR(Rn); break;
+ case 0x70:
+ STCDBR(Rn); break;
+ }
+ break;
+ case 0xB:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ RTS(); break;
+ case 0x10:
+ SLEEP(); break;
+ case 0x20:
+ RTE(); break;
+ }
+ break;
+ case 0xC:
+ MOVBL0(Rm, Rn); break;
+ case 0xD:
+ MOVWL0(Rm, Rn); break;
+ case 0xE:
+ MOVLL0(Rm, Rn); break;
+ case 0xF:
+ MAC_L(Rm, Rn); break;
+ }
+}
+
+INLINE void op0001(UINT16 opcode)
+{
+ MOVLS4(Rm, opcode & 0x0f, Rn);
+}
+
+INLINE void op0010(UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: MOVBS(Rm, Rn); break;
+ case 1: MOVWS(Rm, Rn); break;
+ case 2: MOVLS(Rm, Rn); break;
+ case 3: NOP(); break;
+ case 4: MOVBM(Rm, Rn); break;
+ case 5: MOVWM(Rm, Rn); break;
+ case 6: MOVLM(Rm, Rn); break;
+ case 7: DIV0S(Rm, Rn); break;
+ case 8: TST(Rm, Rn); break;
+ case 9: AND(Rm, Rn); break;
+ case 10: XOR(Rm, Rn); break;
+ case 11: OR(Rm, Rn); break;
+ case 12: CMPSTR(Rm, Rn); break;
+ case 13: XTRCT(Rm, Rn); break;
+ case 14: MULU(Rm, Rn); break;
+ case 15: MULS(Rm, Rn); break;
+ }
+}
+
+INLINE void op0011(UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: CMPEQ(Rm, Rn); break;
+ case 1: NOP(); break;
+ case 2: CMPHS(Rm, Rn); break;
+ case 3: CMPGE(Rm, Rn); break;
+ case 4: DIV1(Rm, Rn); break;
+ case 5: DMULU(Rm, Rn); break;
+ case 6: CMPHI(Rm, Rn); break;
+ case 7: CMPGT(Rm, Rn); break;
+ case 8: SUB(Rm, Rn); break;
+ case 9: NOP(); break;
+ case 10: SUBC(Rm, Rn); break;
+ case 11: SUBV(Rm, Rn); break;
+ case 12: ADD(Rm, Rn); break;
+ case 13: DMULS(Rm, Rn); break;
+ case 14: ADDC(Rm, Rn); break;
+ case 15: ADDV(Rm, Rn); break;
+ }
+}
+
+INLINE void op0100(UINT16 opcode)
+{
+ switch (opcode & 0xF)
+ {
+ case 0x0:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ SHLL(Rn); break;
+ case 0x10:
+ DT(Rn); break;
+ case 0x20:
+ SHAL(Rn); break;
+ }
+ break;
+ case 0x1:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ SHLR(Rn); break;
+ case 0x10:
+ CMPPZ(Rn); break;
+ case 0x20:
+ SHAR(Rn); break;
+ }
+ break;
+ case 0x2:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ STSMMACH(Rn); break;
+ case 0x10:
+ STSMMACL(Rn); break;
+ case 0x20:
+ STSMPR(Rn); break;
+ case 0x30:
+ STCMSGR(Rn); break;
+ case 0x50:
+ STSMFPUL(Rn); break;
+ case 0x60:
+ STSMFPSCR(Rn); break;
+ case 0xF0:
+ STCMDBR(Rn); break;
+ }
+ break;
+ case 0x3:
+ if (opcode & 0x80) {
+ STCMRBANK(Rm, Rn); return;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ STCMSR(Rn); break;
+ case 0x10:
+ STCMGBR(Rn); break;
+ case 0x20:
+ STCMVBR(Rn); break;
+ case 0x30:
+ STCMSSR(Rn); break;
+ case 0x40:
+ STCMSPC(Rn); break;
+ }
+ break;
+ case 0x4:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ ROTL(Rn); break;
+ case 0x20:
+ ROTCL(Rn); break;
+ }
+ break;
+ case 0x5:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ ROTR(Rn); break;
+ case 0x10:
+ CMPPL(Rn); break;
+ case 0x20:
+ ROTCR(Rn); break;
+ }
+ break;
+ case 0x6:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ LDSMMACH(Rn); break;
+ case 0x10:
+ LDSMMACL(Rn); break;
+ case 0x20:
+ LDSMPR(Rn); break;
+ case 0x50:
+ LDSMFPUL(Rn); break;
+ case 0x60:
+ LDSMFPSCR(Rn); break;
+ case 0xF0:
+ LDCMDBR(Rn); break;
+ }
+ break;
+ case 0x7:
+ if (opcode & 0x80) {
+ LDCMRBANK(Rm,Rn); return;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ LDCMSR(Rn); break;
+ case 0x10:
+ LDCMGBR(Rn); break;
+ case 0x20:
+ LDCMVBR(Rn); break;
+ case 0x30:
+ LDCMSSR(Rn); break;
+ case 0x40:
+ LDCMSPC(Rn); break;
+ }
+ break;
+ case 0x8:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ SHLL2(Rn); break;
+ case 0x10:
+ SHLL8(Rn); break;
+ case 0x20:
+ SHLL16(Rn); break;
+ }
+ break;
+ case 0x9:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ SHLR2(Rn); break;
+ case 0x10:
+ SHLR8(Rn); break;
+ case 0x20:
+ SHLR16(Rn); break;
+ }
+ break;
+ case 0xA:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ LDSMACH(Rn); break;
+ case 0x10:
+ LDSMACL(Rn); break;
+ case 0x20:
+ LDSPR(Rn); break;
+ case 0x50:
+ LDSFPUL(Rn); break;
+ case 0x60:
+ LDSFPSCR(Rn); break;
+ case 0xF0:
+ LDCDBR(Rn); break;
+ }
+ break;
+ case 0xB:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ JSR(Rn); break;
+ case 0x10:
+ TAS(Rn); break;
+ case 0x20:
+ JMP(Rn); break;
+ }
+ break;
+ case 0xC:
+ SHAD(Rm,Rn); break;
+ case 0xD:
+ SHLD(Rm,Rn); break;
+ case 0xE:
+ if (opcode & 0x80) {
+ LDCRBANK(Rm,Rn); return;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ LDCSR(Rn); break;
+ case 0x10:
+ LDCGBR(Rn); break;
+ case 0x20:
+ LDCVBR(Rn); break;
+ case 0x30:
+ LDCSSR(Rn); break;
+ case 0x40:
+ LDCSPC(Rn); break;
+ }
+ break;
+ case 0xF:
+ MAC_W(Rm, Rn); break;
+ }
+}
+
+INLINE void op0101(UINT16 opcode)
+{
+ MOVLL4(Rm, opcode & 0x0f, Rn);
+}
+
+INLINE void op0110(UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: MOVBL(Rm, Rn); break;
+ case 1: MOVWL(Rm, Rn); break;
+ case 2: MOVLL(Rm, Rn); break;
+ case 3: MOV(Rm, Rn); break;
+ case 4: MOVBP(Rm, Rn); break;
+ case 5: MOVWP(Rm, Rn); break;
+ case 6: MOVLP(Rm, Rn); break;
+ case 7: NOT(Rm, Rn); break;
+ case 8: SWAPB(Rm, Rn); break;
+ case 9: SWAPW(Rm, Rn); break;
+ case 10: NEGC(Rm, Rn); break;
+ case 11: NEG(Rm, Rn); break;
+ case 12: EXTUB(Rm, Rn); break;
+ case 13: EXTUW(Rm, Rn); break;
+ case 14: EXTSB(Rm, Rn); break;
+ case 15: EXTSW(Rm, Rn); break;
+ }
+}
+
+INLINE void op0111(UINT16 opcode)
+{
+ ADDI(opcode & 0xff, Rn);
+}
+
+INLINE void op1000(UINT16 opcode)
+{
+ switch ( opcode & (15<<8) )
+ {
+ case 0 << 8: MOVBS4(opcode & 0x0f, Rm); break;
+ case 1 << 8: MOVWS4(opcode & 0x0f, Rm); break;
+ case 2<< 8: NOP(); break;
+ case 3<< 8: NOP(); break;
+ case 4<< 8: MOVBL4(Rm, opcode & 0x0f); break;
+ case 5<< 8: MOVWL4(Rm, opcode & 0x0f); break;
+ case 6<< 8: NOP(); break;
+ case 7<< 8: NOP(); break;
+ case 8<< 8: CMPIM(opcode & 0xff); break;
+ case 9<< 8: BT(opcode & 0xff); break;
+ case 10<< 8: NOP(); break;
+ case 11<< 8: BF(opcode & 0xff); break;
+ case 12<< 8: NOP(); break;
+ case 13<< 8: BTS(opcode & 0xff); break;
+ case 14<< 8: NOP(); break;
+ case 15<< 8: BFS(opcode & 0xff); break;
+ }
+}
+
+
+INLINE void op1001(UINT16 opcode)
+{
+ MOVWI(opcode & 0xff, Rn);
+}
+
+INLINE void op1010(UINT16 opcode)
+{
+ BRA(opcode & 0xfff);
+}
+
+INLINE void op1011(UINT16 opcode)
+{
+ BSR(opcode & 0xfff);
+}
+
+INLINE void op1100(UINT16 opcode)
+{
+ switch (opcode & (15<<8))
+ {
+ case 0<<8: MOVBSG(opcode & 0xff); break;
+ case 1<<8: MOVWSG(opcode & 0xff); break;
+ case 2<<8: MOVLSG(opcode & 0xff); break;
+ case 3<<8: TRAPA(opcode & 0xff); break;
+ case 4<<8: MOVBLG(opcode & 0xff); break;
+ case 5<<8: MOVWLG(opcode & 0xff); break;
+ case 6<<8: MOVLLG(opcode & 0xff); break;
+ case 7<<8: MOVA(opcode & 0xff); break;
+ case 8<<8: TSTI(opcode & 0xff); break;
+ case 9<<8: ANDI(opcode & 0xff); break;
+ case 10<<8: XORI(opcode & 0xff); break;
+ case 11<<8: ORI(opcode & 0xff); break;
+ case 12<<8: TSTM(opcode & 0xff); break;
+ case 13<<8: ANDM(opcode & 0xff); break;
+ case 14<<8: XORM(opcode & 0xff); break;
+ case 15<<8: ORM(opcode & 0xff); break;
+ }
+}
+
+INLINE void op1101(UINT16 opcode)
+{
+ MOVLI(opcode & 0xff, Rn);
+}
+
+INLINE void op1110(UINT16 opcode)
+{
+ MOVI(opcode & 0xff, Rn);
+}
+
+/* FMOV @Rm+,DRn PR=0 SZ=1 1111nnn0mmmm1001 */
+/* FMOV @Rm+,XDn PR=1 1111nnn1mmmm1001 */
+/* FMOV.S @Rm+,FRn PR=0 SZ=0 1111nnnnmmmm1001 */
+INLINE void FMOVMRIFR(UINT32 m,UINT32 n)
+{
+ if (sh4.fpscr & PR) { /* PR = 1 */
+ n = n & 14;
+ sh4.ea = sh4.r[m];
+ sh4.xf[n] = RL( sh4.ea );
+ sh4.r[m] += 4;
+ sh4.xf[n+1] = RL( sh4.r[m] );
+ sh4.r[m] += 4;
+ } else { /* PR = 0 */
+ if (sh4.fpscr & SZ) { /* SZ = 1 */
+ n = n & 14;
+ sh4.ea = sh4.r[m];
+ sh4.fr[n] = RL( sh4.ea );
+ sh4.r[m] += 4;
+ sh4.fr[n+1] = RL( sh4.r[m] );
+ sh4.r[m] += 4;
+ } else { /* SZ = 0 */
+ sh4.ea = sh4.r[m];
+ sh4.fr[n] = RL( sh4.ea );
+ sh4.r[m] += 4;
+ }
+ }
+}
+
+/* FMOV XDm,@Rn PR=1 1111nnnnmmm11010 */
+/* FMOV.S FRm,@Rn PR=0 SZ=0 1111nnnnmmmm1010 */
+/* FMOV DRm,@Rn PR=0 SZ=1 1111nnnnmmm01010 */
+INLINE void FMOVFRMR(UINT32 m,UINT32 n)
+{
+ if (sh4.fpscr & PR) { /* PR = 1 */
+ m= m & 14;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea,sh4.xf[m] );
+ WL( sh4.ea+4,sh4.xf[m+1] );
+ } else { /* PR = 0 */
+ if (sh4.fpscr & SZ) { /* SZ = 1 */
+ m= m & 14;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea,sh4.fr[m] );
+ WL( sh4.ea+4,sh4.fr[m+1] );
+ } else { /* SZ = 0 */
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea,sh4.fr[m] );
+ }
+ }
+}
+
+/* FMOV XDm,@-Rn PR=1 1111nnnnmmm11011 */
+/* FMOV.S FRm,@-Rn PR=0 SZ=0 1111nnnnmmmm1011 */
+/* FMOV DRm,@-Rn PR=0 SZ=1 1111nnnnmmm01011 */
+INLINE void FMOVFRMDR(UINT32 m,UINT32 n)
+{
+ if (sh4.fpscr & PR) { /* PR = 1 */
+ m= m & 14;
+ sh4.r[n] -= 8;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea,sh4.xf[m] );
+ WL( sh4.ea+4,sh4.xf[m+1] );
+ } else { /* PR = 0 */
+ if (sh4.fpscr & SZ) { /* SZ = 1 */
+ m= m & 14;
+ sh4.r[n] -= 8;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea,sh4.fr[m] );
+ WL( sh4.ea+4,sh4.fr[m+1] );
+ } else { /* SZ = 0 */
+ sh4.r[n] -= 4;
+ sh4.ea = sh4.r[n];
+ WL( sh4.ea,sh4.fr[m] );
+ }
+ }
+}
+
+/* FLDI1 FRn 1111nnnn10011101 */
+INLINE void FLDI1(UINT32 n)
+{
+ sh4.fr[n] = 0x3F800000;
+}
+
+/* FLDI0 FRn 1111nnnn10001101 */
+INLINE void FLDI0(UINT32 n)
+{
+ sh4.fr[n] = 0;
+}
+
+/* FMOV XDm,@(R0,Rn) PR=1 1111nnnnmmm10111 */
+/* FMOV.S FRm,@(R0,Rn) PR=0 SZ=0 1111nnnnmmmm0111 */
+/* FMOV DRm,@(R0,Rn) PR=0 SZ=1 1111nnnnmmm00111 */
+INLINE void FMOVFRS0(UINT32 m,UINT32 n)
+{
+ if (sh4.fpscr & PR) { /* PR = 1 */
+ m= m & 14;
+ sh4.ea = sh4.r[0] + sh4.r[n];
+ WL( sh4.ea,sh4.xf[m] );
+ WL( sh4.ea+4,sh4.xf[m+1] );
+ } else { /* PR = 0 */
+ if (sh4.fpscr & SZ) { /* SZ = 1 */
+ m= m & 14;
+ sh4.ea = sh4.r[0] + sh4.r[n];
+ WL( sh4.ea,sh4.fr[m] );
+ WL( sh4.ea+4,sh4.fr[m+1] );
+ } else { /* SZ = 0 */
+ sh4.ea = sh4.r[0] + sh4.r[n];
+ WL( sh4.ea,sh4.fr[m] );
+ }
+ }
+}
+
+/* FMOV @(R0,Rm),XDn PR=1 1111nnn1mmmm0110 */
+/* FMOV.S @(R0,Rm),FRn PR=0 SZ=0 1111nnnnmmmm0110 */
+/* FMOV @(R0,Rm),DRn PR=0 SZ=1 1111nnn0mmmm0110 */
+INLINE void FMOVS0FR(UINT32 m,UINT32 n)
+{
+ if (sh4.fpscr & PR) { /* PR = 1 */
+ n= n & 14;
+ sh4.ea = sh4.r[0] + sh4.r[m];
+ sh4.xf[n] = RL( sh4.ea );
+ sh4.xf[n+1] = RL( sh4.ea+4 );
+ } else { /* PR = 0 */
+ if (sh4.fpscr & SZ) { /* SZ = 1 */
+ n= n & 14;
+ sh4.ea = sh4.r[0] + sh4.r[m];
+ sh4.fr[n] = RL( sh4.ea );
+ sh4.fr[n+1] = RL( sh4.ea+4 );
+ } else { /* SZ = 0 */
+ sh4.ea = sh4.r[0] + sh4.r[m];
+ sh4.fr[n] = RL( sh4.ea );
+ }
+ }
+}
+
+/* FMOV @Rm,XDn PR=1 1111nnn1mmmm1000 */
+/* FMOV.S @Rm,FRn PR=0 SZ=0 1111nnnnmmmm1000 */
+/* FMOV @Rm,DRn PR=0 SZ=1 1111nnn0mmmm1000 */
+INLINE void FMOVMRFR(UINT32 m,UINT32 n)
+{
+ if (sh4.fpscr & PR) { /* PR = 1 */
+ n= n & 14;
+ sh4.ea = sh4.r[m];
+ sh4.xf[n] = RL( sh4.ea );
+ sh4.xf[n+1] = RL( sh4.ea+4 );
+ } else { /* PR = 0 */
+ if (sh4.fpscr & SZ) { /* SZ = 1 */
+ n= n & 14;
+ sh4.ea = sh4.r[m];
+ sh4.fr[n] = RL( sh4.ea );
+ sh4.fr[n+1] = RL( sh4.ea+4 );
+ } else { /* SZ = 0 */
+ sh4.ea = sh4.r[m];
+ sh4.fr[n] = RL( sh4.ea );
+ }
+ }
+}
+
+/* FRCHG 1111101111111101 */
+INLINE void FRCHG(void)
+{
+ sh4.fpscr ^= FR;
+ sh4_swap_fp_registers();
+}
+
+/* FSCHG 1111001111111101 */
+INLINE void FSCHG(void)
+{
+ sh4.fpscr ^= SZ;
+}
+
+INLINE void op1111(UINT16 opcode)
+{
+ switch (opcode & 0xf)
+ {
+ case 0:
+ TODO();
+ break;
+ case 1:
+ TODO();
+ break;
+ case 2:
+ TODO();
+ break;
+ case 3:
+ TODO();
+ break;
+ case 4:
+ TODO();
+ break;
+ case 5:
+ TODO();
+ break;
+ case 6:
+ FMOVS0FR(Rm,Rn);
+ break;
+ case 7:
+ FMOVFRS0(Rm,Rn);
+ break;
+ case 8:
+ FMOVMRFR(Rm,Rn);
+ break;
+ case 9:
+ FMOVMRIFR(Rm,Rn);
+ break;
+ case 10:
+ FMOVFRMR(Rm,Rn);
+ break;
+ case 11:
+ FMOVFRMDR(Rm,Rn);
+ break;
+ case 12:
+ TODO();
+ break;
+ case 13:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ TODO();
+ break;
+ case 0x10:
+ TODO();
+ break;
+ case 0x20:
+ TODO();
+ break;
+ case 0x30:
+ TODO();
+ break;
+ case 0x40:
+ TODO();
+ break;
+ case 0x50:
+ TODO();
+ break;
+ case 0x60:
+ TODO();
+ break;
+ case 0x80:
+ FLDI0(Rn);
+ break;
+ case 0x90:
+ FLDI1(Rn);
+ break;
+ case 0xA0:
+ TODO();
+ break;
+ case 0xB0:
+ TODO();
+ break;
+ case 0xE0:
+ TODO();
+ break;
+ case 0xF0:
+ if (opcode == 0xF3FD)
+ FSCHG();
+ else if (opcode == 0xFBFD)
+ FRCHG();
+ else if ((opcode & 0x300) == 0x100)
+ TODO();
+ break;
+ }
+ break;
+ case 14:
+ TODO();
+ break;
+ }
+}
+
+/*****************************************************************************
+ * MAME CPU INTERFACE
+ *****************************************************************************/
+
+static void sh4_reset(void)
+{
+ void *tsaved[4];
+ emu_timer *tsave[5];
+ UINT32 *m;
+ int cpunum;
+ int save_is_slave;
+ int savecpu_clock, savebus_clock, savepm_clock;
+
+ void (*f)(UINT32 data);
+ int (*save_irqcallback)(int);
+
+ cpunum = sh4.cpu_number;
+ m = sh4.m;
+ tsaved[0] = sh4.dma_timer[0];
+ tsaved[1] = sh4.dma_timer[1];
+ tsaved[2] = sh4.dma_timer[2];
+ tsaved[3] = sh4.dma_timer[3];
+ tsave[0] = sh4.refresh_timer;
+ tsave[1] = sh4.rtc_timer;
+ tsave[2] = sh4.timer0;
+ tsave[3] = sh4.timer1;
+ tsave[4] = sh4.timer2;
+
+ f = sh4.ftcsr_read_callback;
+ save_irqcallback = sh4.irq_callback;
+ save_is_slave = sh4.is_slave;
+ savecpu_clock = sh4.cpu_clock;
+ savebus_clock = sh4.bus_clock;
+ savepm_clock = sh4.pm_clock;
+ memset(&sh4, 0, sizeof(SH4));
+ sh4.is_slave = save_is_slave;
+ sh4.cpu_clock = savecpu_clock;
+ sh4.bus_clock = savebus_clock;
+ sh4.pm_clock = savepm_clock;
+ sh4.ftcsr_read_callback = f;
+ sh4.irq_callback = save_irqcallback;
+
+ sh4.dma_timer[0] = tsaved[0];
+ sh4.dma_timer[1] = tsaved[1];
+ sh4.dma_timer[2] = tsaved[2];
+ sh4.dma_timer[3] = tsaved[3];
+ sh4.refresh_timer = tsave[0];
+ sh4.rtc_timer = tsave[1];
+ sh4.timer0 = tsave[2];
+ sh4.timer1 = tsave[3];
+ sh4.timer2 = tsave[4];
+ sh4.cpu_number = cpunum;
+ sh4.m = m;
+ memset(sh4.m, 0, 16384*4);
+ sh4_default_exception_priorities();
+ memset(sh4.exception_requesting, 0, sizeof(sh4.exception_requesting));
+
+ timer_adjust(sh4.rtc_timer, ATTOTIME_IN_HZ(128), cpunum, attotime_zero);
+ sh4.m[RCR2] = 0x09;
+ sh4.m[TCOR0] = 0xffffffff;
+ sh4.m[TCNT0] = 0xffffffff;
+ sh4.m[TCOR1] = 0xffffffff;
+ sh4.m[TCNT1] = 0xffffffff;
+ sh4.m[TCOR2] = 0xffffffff;
+ sh4.m[TCNT2] = 0xffffffff;
+
+ sh4.pc = 0xa0000000;
+ sh4.r[15] = RL(4);
+ sh4.sr = 0x700000f0;
+ sh4.fpscr = 0x00040001;
+ sh4.fpul = 0;
+ sh4.dbr = 0;
+ change_pc(sh4.pc & AM);
+
+ sh4.internal_irq_level = -1;
+ sh4.irln = 15;
+}
+
+/* Execute cycles - returns number of cycles actually run */
+static int sh4_execute(int cycles)
+{
+ sh4_icount = cycles;
+
+ if (sh4.cpu_off)
+ return 0;
+
+ do
+ {
+ UINT32 opcode;
+
+ if (sh4.delay)
+ {
+ opcode = cpu_readop16(WORD2_XOR_LE((UINT32)(sh4.delay & AM)));
+ change_pc(sh4.pc & AM);
+ sh4.pc -= 2;
+ }
+ else
+ opcode = cpu_readop16(WORD2_XOR_LE((UINT32)(sh4.pc & AM)));
+
+ CALL_MAME_DEBUG;
+
+ sh4.delay = 0;
+ sh4.pc += 2;
+ sh4.ppc = sh4.pc;
+
+ switch (opcode & ( 15 << 12))
+ {
+ case 0<<12: op0000(opcode); break;
+ case 1<<12: op0001(opcode); break;
+ case 2<<12: op0010(opcode); break;
+ case 3<<12: op0011(opcode); break;
+ case 4<<12: op0100(opcode); break;
+ case 5<<12: op0101(opcode); break;
+ case 6<<12: op0110(opcode); break;
+ case 7<<12: op0111(opcode); break;
+ case 8<<12: op1000(opcode); break;
+ case 9<<12: op1001(opcode); break;
+ case 10<<12: op1010(opcode); break;
+ case 11<<12: op1011(opcode); break;
+ case 12<<12: op1100(opcode); break;
+ case 13<<12: op1101(opcode); break;
+ case 14<<12: op1110(opcode); break;
+ default: op1111(opcode); break;
+ }
+
+ if (sh4.test_irq && !sh4.delay)
+ {
+ sh4_check_pending_irq("mame_sh4_execute");
+ }
+ sh4_icount--;
+ } while( sh4_icount > 0 );
+
+ return cycles - sh4_icount;
+}
+
+/* Get registers, return context size */
+static void sh4_get_context(void *dst)
+{
+ if( dst )
+ memcpy(dst, &sh4, sizeof(SH4));
+}
+
+/* Set registers */
+static void sh4_set_context(void *src)
+{
+ if( src )
+ memcpy(&sh4, src, sizeof(SH4));
+}
+
+static UINT32 compute_ticks_refresh_timer(emu_timer *timer, int hertz, int base, int divisor)
+{
+ // elapsed:total = x : ticks
+ // x=elapsed*tics/total -> x=elapsed*(double)100000000/rtcnt_div[(sh4.m[RTCSR] >> 3) & 7]
+ // ticks/total=ticks / ((rtcnt_div[(sh4.m[RTCSR] >> 3) & 7] * ticks) / 100000000)=1/((rtcnt_div[(sh4.m[RTCSR] >> 3) & 7] / 100000000)=100000000/rtcnt_div[(sh4.m[RTCSR] >> 3) & 7]
+ return base + (UINT32)((attotime_to_double(timer_timeelapsed(timer)) * (double)hertz) / (double)divisor);
+}
+
+static void sh4_refresh_timer_recompute(void)
+{
+UINT32 ticks;
+
+ //if rtcnt < rtcor then rtcor-rtcnt
+ //if rtcnt >= rtcor then 256-rtcnt+rtcor=256+rtcor-rtcnt
+ ticks = sh4.m[RTCOR]-sh4.m[RTCNT];
+ if (ticks < 0)
+ ticks = 256 + ticks;
+ //((double)rtcnt_div[(sh4.m[RTCSR] >> 3) & 7] / (double)100000000)*ticks
+ timer_adjust(sh4.refresh_timer, attotime_mul(attotime_mul(ATTOTIME_IN_HZ(sh4.bus_clock), rtcnt_div[(sh4.m[RTCSR] >> 3) & 7]), ticks), sh4.cpu_number, attotime_zero);
+ sh4.refresh_timer_base = sh4.m[RTCNT];
+}
+
+/*-------------------------------------------------
+ sh4_scale_up_mame_time - multiply a attotime by
+ a (constant+1) where 0 <= constant < 2^32
+-------------------------------------------------*/
+
+INLINE attotime sh4_scale_up_mame_time(attotime _time1, UINT32 factor1)
+{
+ if (factor1 == 0)
+ return attotime_zero;
+ return attotime_mul(_time1, factor1 + 1);
+}
+
+static UINT32 compute_ticks_timer(emu_timer *timer, int hertz, int divisor)
+{
+ double ret;
+
+ ret=((attotime_to_double(timer_timeleft(timer)) * (double)hertz) / (double)divisor) - 1;
+ return (UINT32)ret;
+}
+
+static void sh4_timer0_recompute(void)
+{
+ double ticks;
+
+ ticks = sh4.m[TCNT0];
+ timer_adjust(sh4.timer0, sh4_scale_up_mame_time(attotime_mul(ATTOTIME_IN_HZ(sh4.pm_clock), tcnt_div[sh4.m[TCR0] & 7]), ticks), sh4.cpu_number, attotime_zero);
+}
+
+static void sh4_timer1_recompute(void)
+{
+ double ticks;
+
+ ticks = sh4.m[TCNT1];
+ timer_adjust(sh4.timer1, sh4_scale_up_mame_time(attotime_mul(ATTOTIME_IN_HZ(sh4.pm_clock), tcnt_div[sh4.m[TCR1] & 7]), ticks), sh4.cpu_number, attotime_zero);
+}
+
+static void sh4_timer2_recompute(void)
+{
+ double ticks;
+
+ ticks = sh4.m[TCNT2];
+ timer_adjust(sh4.timer2, sh4_scale_up_mame_time(attotime_mul(ATTOTIME_IN_HZ(sh4.pm_clock), tcnt_div[sh4.m[TCR2] & 7]), ticks), sh4.cpu_number, attotime_zero);
+}
+
+static TIMER_CALLBACK( sh4_refresh_timer_callback )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ sh4.m[RTCNT] = 0;
+ sh4_refresh_timer_recompute();
+ sh4.m[RTCSR] |= 128;
+ if ((sh4.m[MCR] & 4) && !(sh4.m[MCR] & 2))
+ {
+ sh4.m[RFCR] = (sh4.m[RFCR] + 1) & 1023;
+ if (((sh4.m[RTCSR] & 1) && (sh4.m[RFCR] == 512)) || (sh4.m[RFCR] == 0))
+ {
+ sh4.m[RFCR] = 0;
+ sh4.m[RTCSR] |= 4;
+ }
+ }
+ cpuintrf_pop_context();
+}
+
+static void increment_rtc_time(int mode)
+{
+ int carry, year, leap, days;
+
+ if (mode == 0)
+ {
+ carry = 0;
+ sh4.m[RSECCNT] = sh4.m[RSECCNT] + 1;
+ if ((sh4.m[RSECCNT] & 0xf) == 0xa)
+ sh4.m[RSECCNT] = sh4.m[RSECCNT] + 6;
+ if (sh4.m[RSECCNT] == 0x60)
+ {
+ sh4.m[RSECCNT] = 0;
+ carry=1;
+ }
+ else
+ return;
+ }
+ else
+ carry = 1;
+
+ sh4.m[RMINCNT] = sh4.m[RMINCNT] + carry;
+ if ((sh4.m[RMINCNT] & 0xf) == 0xa)
+ sh4.m[RMINCNT] = sh4.m[RMINCNT] + 6;
+ carry=0;
+ if (sh4.m[RMINCNT] == 0x60)
+ {
+ sh4.m[RMINCNT] = 0;
+ carry = 1;
+ }
+
+ sh4.m[RHRCNT] = sh4.m[RHRCNT] + carry;
+ if ((sh4.m[RHRCNT] & 0xf) == 0xa)
+ sh4.m[RHRCNT] = sh4.m[RHRCNT] + 6;
+ carry = 0;
+ if (sh4.m[RHRCNT] == 0x24)
+ {
+ sh4.m[RHRCNT] = 0;
+ carry = 1;
+ }
+
+ sh4.m[RWKCNT] = sh4.m[RWKCNT] + carry;
+ if (sh4.m[RWKCNT] == 0x7)
+ {
+ sh4.m[RWKCNT] = 0;
+ }
+
+ year = (sh4.m[RYRCNT] & 0xf) + ((sh4.m[RYRCNT] & 0xf0) >> 4)*10 + ((sh4.m[RYRCNT] & 0xf00) >> 8)*100 + ((sh4.m[RYRCNT] & 0xf000) >> 12)*1000;
+ leap = 0;
+ if (!(year%100))
+ {
+ if (!(year%400))
+ leap = 1;
+ }
+ else if (!(year%4))
+ leap = 1;
+ if (sh4.m[RMONCNT] != 2)
+ leap = 0;
+ days = daysmonth[(sh4.m[RMONCNT] & 0xf) + ((sh4.m[RMONCNT] & 0xf0) >> 4)*10 - 1];
+
+ sh4.m[RDAYCNT] = sh4.m[RDAYCNT] + carry;
+ if ((sh4.m[RDAYCNT] & 0xf) == 0xa)
+ sh4.m[RDAYCNT] = sh4.m[RDAYCNT] + 6;
+ carry = 0;
+ if (sh4.m[RDAYCNT] > (days+leap))
+ {
+ sh4.m[RDAYCNT] = 1;
+ carry = 1;
+ }
+
+ sh4.m[RMONCNT] = sh4.m[RMONCNT] + carry;
+ if ((sh4.m[RMONCNT] & 0xf) == 0xa)
+ sh4.m[RMONCNT] = sh4.m[RMONCNT] + 6;
+ carry=0;
+ if (sh4.m[RMONCNT] == 0x13)
+ {
+ sh4.m[RMONCNT] = 1;
+ carry = 1;
+ }
+
+ sh4.m[RYRCNT] = sh4.m[RYRCNT] + carry;
+ if ((sh4.m[RYRCNT] & 0xf) >= 0xa)
+ sh4.m[RYRCNT] = sh4.m[RYRCNT] + 6;
+ if ((sh4.m[RYRCNT] & 0xf0) >= 0xa0)
+ sh4.m[RYRCNT] = sh4.m[RYRCNT] + 0x60;
+ if ((sh4.m[RYRCNT] & 0xf00) >= 0xa00)
+ sh4.m[RYRCNT] = sh4.m[RYRCNT] + 0x600;
+ if ((sh4.m[RYRCNT] & 0xf000) >= 0xa000)
+ sh4.m[RYRCNT] = 0;
+}
+
+static TIMER_CALLBACK( sh4_rtc_timer_callback )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ timer_adjust(sh4.rtc_timer, ATTOTIME_IN_HZ(128), cpunum, attotime_zero);
+ sh4.m[R64CNT] = (sh4.m[R64CNT]+1) & 0x7f;
+ if (sh4.m[R64CNT] == 64)
+ {
+ sh4.m[RCR1] |= 0x80;
+ increment_rtc_time(0);
+ //sh4_exception_request(SH4_INTC_NMI); // TEST
+ }
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( sh4_timer0_callback )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ sh4.m[TCNT0] = sh4.m[TCOR0];
+ sh4_timer0_recompute();
+ sh4.m[TCR0] = sh4.m[TCR0] | 0x100;
+ if (sh4.m[TCR0] & 0x20)
+ sh4_exception_request(SH4_INTC_TUNI0);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( sh4_timer1_callback )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ sh4.m[TCNT1] = sh4.m[TCOR1];
+ sh4_timer1_recompute();
+ sh4.m[TCR1] = sh4.m[TCR1] | 0x100;
+ if (sh4.m[TCR1] & 0x20)
+ sh4_exception_request(SH4_INTC_TUNI1);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( sh4_timer2_callback )
+{
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ sh4.m[TCNT2] = sh4.m[TCOR2];
+ sh4_timer2_recompute();
+ sh4.m[TCR2] = sh4.m[TCR2] | 0x100;
+ if (sh4.m[TCR2] & 0x20)
+ sh4_exception_request(SH4_INTC_TUNI2);
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( sh4_dmac_callback )
+{
+ int cpunum = param >> 8;
+ int channel = param & 255;
+
+ cpuintrf_push_context(cpunum);
+ LOG(("SH4.%d: DMA %d complete\n", cpunum, channel));
+ sh4.dma_timer_active[channel] = 0;
+ switch (channel)
+ {
+ case 0:
+ sh4.m[DMATCR0] = 0;
+ sh4.m[CHCR0] |= 2;
+ if (sh4.m[CHCR0] & 4)
+ sh4_exception_request(SH4_INTC_DMTE0);
+ break;
+ case 1:
+ sh4.m[DMATCR1] = 0;
+ sh4.m[CHCR1] |= 2;
+ if (sh4.m[CHCR1] & 4)
+ sh4_exception_request(SH4_INTC_DMTE1);
+ break;
+ case 2:
+ sh4.m[DMATCR2] = 0;
+ sh4.m[CHCR2] |= 2;
+ if (sh4.m[CHCR2] & 4)
+ sh4_exception_request(SH4_INTC_DMTE2);
+ break;
+ case 3:
+ sh4.m[DMATCR3] = 0;
+ sh4.m[CHCR3] |= 2;
+ if (sh4.m[CHCR3] & 4)
+ sh4_exception_request(SH4_INTC_DMTE3);
+ break;
+ }
+ cpuintrf_pop_context();
+}
+
+static int sh4_dma_transfer(int channel, int timermode, UINT32 chcr, UINT32 *sar, UINT32 *dar, UINT32 *dmatcr)
+{
+ int incs, incd, size;
+ UINT32 src, dst, count;
+
+ incd = (chcr >> 14) & 3;
+ incs = (chcr >> 12) & 3;
+ size = dmasize[(chcr >> 4) & 7];
+ if(incd == 3 || incs == 3)
+ {
+ logerror("SH4: DMA: bad increment values (%d, %d, %d, %04x)\n", incd, incs, size, chcr);
+ return 0;
+ }
+ src = *sar;
+ dst = *dar;
+ count = *dmatcr;
+ if (!count)
+ count = 0x1000000;
+
+ LOG(("SH4: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", channel, src, dst, count, chcr, incs, incd, size));
+
+ if (timermode == 1)
+ {
+ sh4.dma_timer_active[channel] = 1;
+ timer_adjust(sh4.dma_timer[channel], ATTOTIME_IN_CYCLES(2*count+1, sh4.cpu_number), (sh4.cpu_number << 8) | channel, attotime_zero);
+ }
+ else if (timermode == 2)
+ {
+ sh4.dma_timer_active[channel] = 1;
+ timer_adjust(sh4.dma_timer[channel], attotime_zero, (sh4.cpu_number << 8) | channel, attotime_zero);
+ }
+
+ src &= AM;
+ dst &= AM;
+
+ switch(size)
+ {
+ case 1:
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src --;
+ if(incd == 2)
+ dst --;
+ program_write_byte_64le(dst, program_read_byte_64le(src));
+ if(incs == 1)
+ src ++;
+ if(incd == 1)
+ dst ++;
+ }
+ break;
+ case 2:
+ src &= ~1;
+ dst &= ~1;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 2;
+ if(incd == 2)
+ dst -= 2;
+ program_write_word_64le(dst, program_read_word_64le(src));
+ if(incs == 1)
+ src += 2;
+ if(incd == 1)
+ dst += 2;
+ }
+ break;
+ case 8:
+ src &= ~7;
+ dst &= ~7;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 8;
+ if(incd == 2)
+ dst -= 8;
+ program_write_qword_64le(dst, program_read_qword_64le(src));
+ if(incs == 1)
+ src += 8;
+ if(incd == 1)
+ dst += 8;
+
+ }
+ break;
+ case 4:
+ src &= ~3;
+ dst &= ~3;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 4;
+ if(incd == 2)
+ dst -= 4;
+ program_write_dword_64le(dst, program_read_dword_64le(src));
+ if(incs == 1)
+ src += 4;
+ if(incd == 1)
+ dst += 4;
+
+ }
+ break;
+ case 32:
+ src &= ~31;
+ dst &= ~31;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 32;
+ if(incd == 2)
+ dst -= 32;
+ program_write_qword_64le(dst, program_read_qword_64le(src));
+ program_write_qword_64le(dst+8, program_read_qword_64le(src+8));
+ program_write_qword_64le(dst+16, program_read_qword_64le(src+16));
+ program_write_qword_64le(dst+24, program_read_qword_64le(src+24));
+ if(incs == 1)
+ src += 32;
+ if(incd == 1)
+ dst += 32;
+ }
+ break;
+ }
+ *sar = (*sar & !AM) | src;
+ *dar = (*dar & !AM) | dst;
+ *dmatcr = count;
+ return 1;
+}
+
+static void sh4_dmac_check(int channel)
+{
+UINT32 dmatcr,chcr,sar,dar;
+
+ switch (channel)
+ {
+ case 0:
+ sar = sh4.m[SAR0];
+ dar = sh4.m[DAR0];
+ chcr = sh4.m[CHCR0];
+ dmatcr = sh4.m[DMATCR0];
+ break;
+ case 1:
+ sar = sh4.m[SAR1];
+ dar = sh4.m[DAR1];
+ chcr = sh4.m[CHCR1];
+ dmatcr = sh4.m[DMATCR1];
+ break;
+ case 2:
+ sar = sh4.m[SAR2];
+ dar = sh4.m[DAR2];
+ chcr = sh4.m[CHCR2];
+ dmatcr = sh4.m[DMATCR2];
+ break;
+ case 3:
+ sar = sh4.m[SAR3];
+ dar = sh4.m[DAR3];
+ chcr = sh4.m[CHCR3];
+ dmatcr = sh4.m[DMATCR3];
+ break;
+ default:
+ return;
+ }
+ if (chcr & sh4.m[DMAOR] & 1)
+ {
+ if ((((chcr >> 8) & 15) < 4) || (((chcr >> 8) & 15) > 6))
+ return;
+ if (!sh4.dma_timer_active[channel] && !(chcr & 2) && !(sh4.m[DMAOR] & 6))
+ sh4_dma_transfer(channel, 1, chcr, &sar, &dar, &dmatcr);
+ }
+ else
+ {
+ if (sh4.dma_timer_active[channel])
+ {
+ logerror("SH4: DMA %d cancelled in-flight but all data transferred", channel);
+ timer_adjust(sh4.dma_timer[channel], attotime_never, 0, attotime_zero);
+ sh4.dma_timer_active[channel] = 0;
+ }
+ }
+}
+
+static void sh4_dmac_nmi(void) // manage dma when nmi
+{
+int s;
+
+ sh4.m[DMAOR] |= 2; // nmif = 1
+ for (s = 0;s < 4;s++)
+ {
+ if (sh4.dma_timer_active[s])
+ {
+ logerror("SH4: DMA %d cancelled due to NMI but all data transferred", s);
+ timer_adjust(sh4.dma_timer[s], attotime_never, 0, attotime_zero);
+ sh4.dma_timer_active[s] = 0;
+ }
+ }
+}
+
+WRITE32_HANDLER( sh4_internal_w )
+{
+ UINT32 old = sh4.m[offset];
+ COMBINE_DATA(sh4.m+offset);
+
+ // logerror("sh4_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfe000000+((offset & 0x3fc0) << 11)+((offset & 0x3f) << 2), offset, data, mem_mask);
+
+ switch( offset )
+ {
+ // Memory refresh
+ case RTCSR:
+ sh4.m[RTCSR] &= 255;
+ if ((old >> 3) & 7)
+ sh4.m[RTCNT] = compute_ticks_refresh_timer(sh4.refresh_timer, sh4.bus_clock, sh4.refresh_timer_base, rtcnt_div[(old >> 3) & 7]) & 0xff;
+ if ((sh4.m[RTCSR] >> 3) & 7)
+ { // activated
+ sh4_refresh_timer_recompute();
+ }
+ else
+ {
+ timer_adjust(sh4.refresh_timer, attotime_never, 0, attotime_zero);
+ }
+ break;
+
+ case RTCNT:
+ sh4.m[RTCNT] &= 255;
+ if ((sh4.m[RTCSR] >> 3) & 7)
+ { // active
+ sh4_refresh_timer_recompute();
+ }
+ break;
+
+ case RTCOR:
+ sh4.m[RTCOR] &= 255;
+ if ((sh4.m[RTCSR] >> 3) & 7)
+ { // active
+ sh4.m[RTCNT] = compute_ticks_refresh_timer(sh4.refresh_timer, sh4.bus_clock, sh4.refresh_timer_base, rtcnt_div[(sh4.m[RTCSR] >> 3) & 7]) & 0xff;
+ sh4_refresh_timer_recompute();
+ }
+ break;
+
+ case RFCR:
+ sh4.m[RFCR] &= 1023;
+ break;
+
+ // RTC
+ case RCR1:
+ if ((sh4.m[RCR1] & 8) && (~old & 8)) // 0 -> 1
+ sh4.m[RCR1] ^= 1;
+ break;
+
+ case RCR2:
+ if (sh4.m[RCR2] & 2)
+ {
+ sh4.m[R64CNT] = 0;
+ sh4.m[RCR2] ^= 2;
+ }
+ if (sh4.m[RCR2] & 4)
+ {
+ sh4.m[R64CNT] = 0;
+ if (sh4.m[RSECCNT] >= 30)
+ increment_rtc_time(1);
+ sh4.m[RSECCNT] = 0;
+ }
+ if ((sh4.m[RCR2] & 8) && (~old & 8))
+ { // 0 -> 1
+ timer_adjust(sh4.rtc_timer, ATTOTIME_IN_HZ(128), sh4.cpu_number, attotime_zero);
+ }
+ else if (~(sh4.m[RCR2]) & 8)
+ { // 0
+ timer_adjust(sh4.rtc_timer, attotime_never, 0, attotime_zero);
+ }
+ break;
+
+ // TMU
+ case TSTR:
+ if (old & 1)
+ sh4.m[TCNT0] = compute_ticks_timer(sh4.timer0, sh4.pm_clock, tcnt_div[sh4.m[TCR0] & 7]);
+ if ((sh4.m[TSTR] & 1) == 0) {
+ timer_adjust(sh4.timer0, attotime_never, 0, attotime_zero);
+ } else
+ sh4_timer0_recompute();
+
+ if (old & 2)
+ sh4.m[TCNT1] = compute_ticks_timer(sh4.timer1, sh4.pm_clock, tcnt_div[sh4.m[TCR1] & 7]);
+ if ((sh4.m[TSTR] & 2) == 0) {
+ timer_adjust(sh4.timer1, attotime_never, 0, attotime_zero);
+ } else
+ sh4_timer1_recompute();
+
+ if (old & 4)
+ sh4.m[TCNT2] = compute_ticks_timer(sh4.timer2, sh4.pm_clock, tcnt_div[sh4.m[TCR2] & 7]);
+ if ((sh4.m[TSTR] & 4) == 0) {
+ timer_adjust(sh4.timer2, attotime_never, 0, attotime_zero);
+ } else
+ sh4_timer2_recompute();
+ break;
+
+ case TCR0:
+ if (sh4.m[TSTR] & 1)
+ {
+ sh4.m[TCNT0] = compute_ticks_timer(sh4.timer0, sh4.pm_clock, tcnt_div[old & 7]);
+ sh4_timer0_recompute();
+ }
+ if (!(sh4.m[TCR0] & 0x20) || !(sh4.m[TCR0] & 0x100))
+ sh4_exception_unrequest(SH4_INTC_TUNI0);
+ break;
+ case TCR1:
+ if (sh4.m[TSTR] & 2)
+ {
+ sh4.m[TCNT1] = compute_ticks_timer(sh4.timer1, sh4.pm_clock, tcnt_div[old & 7]);
+ sh4_timer1_recompute();
+ }
+ if (!(sh4.m[TCR1] & 0x20) || !(sh4.m[TCR1] & 0x100))
+ sh4_exception_unrequest(SH4_INTC_TUNI1);
+ break;
+ case TCR2:
+ if (sh4.m[TSTR] & 4)
+ {
+ sh4.m[TCNT2] = compute_ticks_timer(sh4.timer2, sh4.pm_clock, tcnt_div[old & 7]);
+ sh4_timer2_recompute();
+ }
+ if (!(sh4.m[TCR2] & 0x20) || !(sh4.m[TCR2] & 0x100))
+ sh4_exception_unrequest(SH4_INTC_TUNI2);
+ break;
+
+ case TCOR0:
+ if (sh4.m[TSTR] & 1)
+ {
+ sh4.m[TCNT0] = compute_ticks_timer(sh4.timer0, sh4.pm_clock, tcnt_div[sh4.m[TCR0] & 7]);
+ sh4_timer0_recompute();
+ }
+ break;
+ case TCNT0:
+ if (sh4.m[TSTR] & 1)
+ sh4_timer0_recompute();
+ break;
+ case TCOR1:
+ if (sh4.m[TSTR] & 2)
+ {
+ sh4.m[TCNT1] = compute_ticks_timer(sh4.timer1, sh4.pm_clock, tcnt_div[sh4.m[TCR1] & 7]);
+ sh4_timer1_recompute();
+ }
+ break;
+ case TCNT1:
+ if (sh4.m[TSTR] & 2)
+ sh4_timer1_recompute();
+ break;
+ case TCOR2:
+ if (sh4.m[TSTR] & 4)
+ {
+ sh4.m[TCNT2] = compute_ticks_timer(sh4.timer2, sh4.pm_clock, tcnt_div[sh4.m[TCR2] & 7]);
+ sh4_timer2_recompute();
+ }
+ break;
+ case TCNT2:
+ if (sh4.m[TSTR] & 4)
+ sh4_timer2_recompute();
+ break;
+
+ // INTC
+ case ICR:
+ sh4.m[ICR] = (sh4.m[ICR] & 0x7fff) | (old & 0x8000);
+ break;
+ case IPRA:
+ sh4.exception_priority[SH4_INTC_ATI] = INTPRI(sh4.m[IPRA] & 0x000f, SH4_INTC_ATI);
+ sh4.exception_priority[SH4_INTC_PRI] = INTPRI(sh4.m[IPRA] & 0x000f, SH4_INTC_PRI);
+ sh4.exception_priority[SH4_INTC_CUI] = INTPRI(sh4.m[IPRA] & 0x000f, SH4_INTC_CUI);
+ sh4.exception_priority[SH4_INTC_TUNI2] = INTPRI((sh4.m[IPRA] & 0x00f0) >> 4, SH4_INTC_TUNI2);
+ sh4.exception_priority[SH4_INTC_TICPI2] = INTPRI((sh4.m[IPRA] & 0x00f0) >> 4, SH4_INTC_TICPI2);
+ sh4.exception_priority[SH4_INTC_TUNI1] = INTPRI((sh4.m[IPRA] & 0x0f00) >> 8, SH4_INTC_TUNI1);
+ sh4.exception_priority[SH4_INTC_TUNI0] = INTPRI((sh4.m[IPRA] & 0xf000) >> 12, SH4_INTC_TUNI0);
+ sh4_exception_recompute();
+ break;
+ case IPRB:
+ sh4.exception_priority[SH4_INTC_SCI1ERI] = INTPRI((sh4.m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1ERI);
+ sh4.exception_priority[SH4_INTC_SCI1RXI] = INTPRI((sh4.m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1RXI);
+ sh4.exception_priority[SH4_INTC_SCI1TXI] = INTPRI((sh4.m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1TXI);
+ sh4.exception_priority[SH4_INTC_SCI1TEI] = INTPRI((sh4.m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1TEI);
+ sh4.exception_priority[SH4_INTC_RCMI] = INTPRI((sh4.m[IPRB] & 0x0f00) >> 8, SH4_INTC_RCMI);
+ sh4.exception_priority[SH4_INTC_ROVI] = INTPRI((sh4.m[IPRB] & 0x0f00) >> 8, SH4_INTC_ROVI);
+ sh4.exception_priority[SH4_INTC_ITI] = INTPRI((sh4.m[IPRB] & 0xf000) >> 12, SH4_INTC_ITI);
+ sh4_exception_recompute();
+ break;
+ case IPRC:
+ sh4.exception_priority[SH4_INTC_HUDI] = INTPRI(sh4.m[IPRC] & 0x000f, SH4_INTC_HUDI);
+ sh4.exception_priority[SH4_INTC_SCIFERI] = INTPRI((sh4.m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFERI);
+ sh4.exception_priority[SH4_INTC_SCIFRXI] = INTPRI((sh4.m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFRXI);
+ sh4.exception_priority[SH4_INTC_SCIFBRI] = INTPRI((sh4.m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFBRI);
+ sh4.exception_priority[SH4_INTC_SCIFTXI] = INTPRI((sh4.m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFTXI);
+ sh4.exception_priority[SH4_INTC_DMTE0] = INTPRI((sh4.m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE0);
+ sh4.exception_priority[SH4_INTC_DMTE1] = INTPRI((sh4.m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE1);
+ sh4.exception_priority[SH4_INTC_DMTE2] = INTPRI((sh4.m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE2);
+ sh4.exception_priority[SH4_INTC_DMTE3] = INTPRI((sh4.m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE3);
+ sh4.exception_priority[SH4_INTC_DMAE] = INTPRI((sh4.m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMAE);
+ sh4.exception_priority[SH4_INTC_GPOI] = INTPRI((sh4.m[IPRC] & 0xf000) >> 12, SH4_INTC_GPOI);
+ sh4_exception_recompute();
+ break;
+
+ // DMA
+ case SAR0:
+ case SAR1:
+ case SAR2:
+ case SAR3:
+ case DAR0:
+ case DAR1:
+ case DAR2:
+ case DAR3:
+ case DMATCR0:
+ case DMATCR1:
+ case DMATCR2:
+ case DMATCR3:
+ break;
+ case CHCR0:
+ sh4_dmac_check(0);
+ break;
+ case CHCR1:
+ sh4_dmac_check(1);
+ break;
+ case CHCR2:
+ sh4_dmac_check(2);
+ break;
+ case CHCR3:
+ sh4_dmac_check(3);
+ break;
+ case DMAOR:
+ if ((sh4.m[DMAOR] & 4) && (~old & 4))
+ sh4.m[DMAOR] &= ~4;
+ if ((sh4.m[DMAOR] & 2) && (~old & 2))
+ sh4.m[DMAOR] &= ~2;
+ sh4_dmac_check(0);
+ sh4_dmac_check(1);
+ sh4_dmac_check(2);
+ sh4_dmac_check(3);
+ break;
+
+ // Store Queues
+ case QACR0:
+ case QACR1:
+ break;
+
+ case SCBRR2:
+ break;
+
+ default:
+ logerror("sh4_internal_w: Unmapped write %08x, %08x @ %08x\n", 0xfe000000+((offset & 0x3fc0) << 11)+((offset & 0x3f) << 2), data, mem_mask);
+ break;
+ }
+}
+
+READ32_HANDLER( sh4_internal_r )
+{
+ // logerror("sh4_internal_r: Read %08x (%x) @ %08x\n", 0xfe000000+((offset & 0x3fc0) << 11)+((offset & 0x3f) << 2), offset, mem_mask);
+ switch( offset )
+ {
+ case RTCNT:
+ if ((sh4.m[RTCSR] >> 3) & 7)
+ { // activated
+ //((double)rtcnt_div[(sh4.m[RTCSR] >> 3) & 7] / (double)100000000)
+ //return (refresh_timer_base + (timer_timeelapsed(sh4.refresh_timer) * (double)100000000) / (double)rtcnt_div[(sh4.m[RTCSR] >> 3) & 7]) & 0xff;
+ return compute_ticks_refresh_timer(sh4.refresh_timer, sh4.bus_clock, sh4.refresh_timer_base, rtcnt_div[(sh4.m[RTCSR] >> 3) & 7]) & 0xff;
+ }
+ else
+ return sh4.m[RTCNT];
+ break;
+
+ case TCNT0:
+ if (sh4.m[TSTR] & 1)
+ return compute_ticks_timer(sh4.timer0, sh4.pm_clock, tcnt_div[sh4.m[TCR0] & 7]);
+ else
+ return sh4.m[TCNT0];
+ break;
+ case TCNT1:
+ if (sh4.m[TSTR] & 2)
+ return compute_ticks_timer(sh4.timer1, sh4.pm_clock, tcnt_div[sh4.m[TCR1] & 7]);
+ else
+ return sh4.m[TCNT1];
+ break;
+ case TCNT2:
+ if (sh4.m[TSTR] & 4)
+ return compute_ticks_timer(sh4.timer2, sh4.pm_clock, tcnt_div[sh4.m[TCR2] & 7]);
+ else
+ return sh4.m[TCNT2];
+ break;
+ }
+ return sh4.m[offset];
+}
+
+void sh4_set_frt_input(int cpunum, int state)
+{
+ if(state == PULSE_LINE)
+ {
+ sh4_set_frt_input(cpunum, ASSERT_LINE);
+ sh4_set_frt_input(cpunum, CLEAR_LINE);
+ return;
+ }
+
+ cpuintrf_push_context(cpunum);
+
+ if(sh4.frt_input == state) {
+ cpuintrf_pop_context();
+ return;
+ }
+
+ sh4.frt_input = state;
+
+ if(sh4.m[5] & 0x8000) {
+ if(state == CLEAR_LINE) {
+ cpuintrf_pop_context();
+ return;
+ }
+ } else {
+ if(state == ASSERT_LINE) {
+ cpuintrf_pop_context();
+ return;
+ }
+ }
+
+#if 0
+ sh4_timer_resync();
+ sh4.icr = sh4.frc;
+ sh4.m[4] |= ICF;
+ logerror("SH4.%d: ICF activated (%x)\n", sh4.cpu_number, sh4.pc & AM);
+ sh4_recalc_irq();
+#endif
+ cpuintrf_pop_context();
+}
+
+void sh4_set_irln_input(int cpunum, int value)
+{
+ if (sh4.irln == value)
+ return;
+ sh4.irln = value;
+ cpunum_set_input_line(cpunum, SH4_IRLn, PULSE_LINE);
+}
+
+static void set_irq_line(int irqline, int state) // set state of external interrupt line
+{
+int s;
+
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (sh4.nmi_line_state == state)
+ return;
+ if (sh4.m[ICR] & 0x100)
+ {
+ if ((state == CLEAR_LINE) && (sh4.nmi_line_state == ASSERT_LINE)) // rising
+ {
+ LOG(("SH-4 #%d assert nmi\n", cpu_getactivecpu()));
+ sh4_exception_request(SH4_INTC_NMI);
+ sh4_dmac_nmi();
+ }
+ }
+ else
+ {
+ if ((state == ASSERT_LINE) && (sh4.nmi_line_state == CLEAR_LINE)) // falling
+ {
+ LOG(("SH-4 #%d assert nmi\n", cpu_getactivecpu()));
+ sh4_exception_request(SH4_INTC_NMI);
+ sh4_dmac_nmi();
+ }
+ }
+ if (state == CLEAR_LINE)
+ sh4.m[ICR] ^= 0x8000;
+ else
+ sh4.m[ICR] |= 0x8000;
+ sh4.nmi_line_state = state;
+ }
+ else
+ {
+ if (sh4.m[ICR] & 0x80) // four independent external interrupt sources
+ {
+ if (irqline > SH4_IRL3)
+ return;
+ if (sh4.irq_line_state[irqline] == state)
+ return;
+ sh4.irq_line_state[irqline] = state;
+
+ if( state == CLEAR_LINE )
+ {
+ LOG(("SH-4 #%d cleared external irq IRL%d\n", cpu_getactivecpu(), irqline));
+ sh4_exception_unrequest(SH4_INTC_IRL0+irqline-SH4_IRL0);
+ }
+ else
+ {
+ LOG(("SH-4 #%d assert external irq IRL%d\n", cpu_getactivecpu(), irqline));
+ sh4_exception_request(SH4_INTC_IRL0+irqline-SH4_IRL0);
+ }
+ }
+ else // level-encoded interrupt
+ {
+ if (irqline != SH4_IRLn)
+ return;
+ if ((sh4.irln > 15) || (sh4.irln < 0))
+ return;
+ for (s = 0; s < 15; s++)
+ sh4_exception_unrequest(SH4_INTC_IRLn0+s);
+ if (sh4.irln < 15)
+ sh4_exception_request(SH4_INTC_IRLn0+sh4.irln);
+ LOG(("SH-4 #%d IRLn0-IRLn3 level #%d\n", cpu_getactivecpu(), sh4.irln));
+ }
+ }
+ if (sh4.test_irq && (!sh4.delay))
+ sh4_check_pending_irq("sh4_set_irq_line");
+}
+
+static void sh4_parse_configuration(const struct sh4_config *conf)
+{
+ if(conf)
+ {
+ switch((conf->md2 << 2) | (conf->md1 << 1) | (conf->md0))
+ {
+ case 0:
+ sh4.cpu_clock = conf->clock;
+ sh4.bus_clock = conf->clock / 4;
+ sh4.pm_clock = conf->clock / 4;
+ break;
+ case 1:
+ sh4.cpu_clock = conf->clock;
+ sh4.bus_clock = conf->clock / 6;
+ sh4.pm_clock = conf->clock / 6;
+ break;
+ case 2:
+ sh4.cpu_clock = conf->clock;
+ sh4.bus_clock = conf->clock / 3;
+ sh4.pm_clock = conf->clock / 6;
+ break;
+ case 3:
+ sh4.cpu_clock = conf->clock;
+ sh4.bus_clock = conf->clock / 3;
+ sh4.pm_clock = conf->clock / 6;
+ break;
+ case 4:
+ sh4.cpu_clock = conf->clock;
+ sh4.bus_clock = conf->clock / 2;
+ sh4.pm_clock = conf->clock / 4;
+ break;
+ case 5:
+ sh4.cpu_clock = conf->clock;
+ sh4.bus_clock = conf->clock / 2;
+ sh4.pm_clock = conf->clock / 4;
+ break;
+ }
+ sh4.is_slave = (~(conf->md7)) & 1;
+ }
+ else
+ {
+ sh4.cpu_clock = 200000000;
+ sh4.bus_clock = 100000000;
+ sh4.pm_clock = 50000000;
+ sh4.is_slave = 0;
+ }
+}
+
+#ifdef MAME_DEBUG
+static offs_t sh4_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return DasmSH4( buffer, pc, (oprom[1] << 8) | oprom[0] );
+}
+#endif /* MAME_DEBUG */
+
+static void sh4_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ const struct sh4_config *conf = config;
+
+ sh4.timer0 = timer_alloc(sh4_timer0_callback);
+ timer_adjust(sh4.timer0, attotime_never, 0, attotime_zero);
+ sh4.timer1 = timer_alloc(sh4_timer1_callback);
+ timer_adjust(sh4.timer1, attotime_never, 0, attotime_zero);
+ sh4.timer2 = timer_alloc(sh4_timer2_callback);
+ timer_adjust(sh4.timer2, attotime_never, 0, attotime_zero);
+
+ sh4.dma_timer[0] = timer_alloc(sh4_dmac_callback);
+ timer_adjust(sh4.dma_timer[0], attotime_never, 0, attotime_zero);
+ sh4.dma_timer[1] = timer_alloc(sh4_dmac_callback);
+ timer_adjust(sh4.dma_timer[1], attotime_never, 0, attotime_zero);
+ sh4.dma_timer[2] = timer_alloc(sh4_dmac_callback);
+ timer_adjust(sh4.dma_timer[2], attotime_never, 0, attotime_zero);
+ sh4.dma_timer[3] = timer_alloc(sh4_dmac_callback);
+ timer_adjust(sh4.dma_timer[3], attotime_never, 0, attotime_zero);
+
+ sh4.refresh_timer = timer_alloc(sh4_refresh_timer_callback);
+ timer_adjust(sh4.refresh_timer, attotime_never, 0, attotime_zero);
+ sh4.refresh_timer_base = 0;
+
+ sh4.rtc_timer = timer_alloc(sh4_rtc_timer_callback);
+ timer_adjust(sh4.rtc_timer, attotime_never, 0, attotime_zero);
+
+ sh4.m = auto_malloc(16384*4);
+
+ sh4_parse_configuration(conf);
+
+ sh4.cpu_number = index;
+ sh4.irq_callback = irqcallback;
+ sh4_default_exception_priorities();
+ sh4.irln = 15;
+ sh4.test_irq = 0;
+
+ state_save_register_item("sh4", index, sh4.pc);
+ state_save_register_item("sh4", index, sh4.r[15]);
+ state_save_register_item("sh4", index, sh4.sr);
+ state_save_register_item("sh4", index, sh4.pr);
+ state_save_register_item("sh4", index, sh4.gbr);
+ state_save_register_item("sh4", index, sh4.vbr);
+ state_save_register_item("sh4", index, sh4.mach);
+ state_save_register_item("sh4", index, sh4.macl);
+ state_save_register_item("sh4", index, sh4.spc);
+ state_save_register_item("sh4", index, sh4.ssr);
+ state_save_register_item("sh4", index, sh4.sgr);
+ state_save_register_item("sh4", index, sh4.fpscr);
+ state_save_register_item("sh4", index, sh4.r[ 0]);
+ state_save_register_item("sh4", index, sh4.r[ 1]);
+ state_save_register_item("sh4", index, sh4.r[ 2]);
+ state_save_register_item("sh4", index, sh4.r[ 3]);
+ state_save_register_item("sh4", index, sh4.r[ 4]);
+ state_save_register_item("sh4", index, sh4.r[ 5]);
+ state_save_register_item("sh4", index, sh4.r[ 6]);
+ state_save_register_item("sh4", index, sh4.r[ 7]);
+ state_save_register_item("sh4", index, sh4.r[ 8]);
+ state_save_register_item("sh4", index, sh4.r[ 9]);
+ state_save_register_item("sh4", index, sh4.r[10]);
+ state_save_register_item("sh4", index, sh4.r[11]);
+ state_save_register_item("sh4", index, sh4.r[12]);
+ state_save_register_item("sh4", index, sh4.r[13]);
+ state_save_register_item("sh4", index, sh4.r[14]);
+ state_save_register_item("sh4", index, sh4.fr[ 0]);
+ state_save_register_item("sh4", index, sh4.fr[ 1]);
+ state_save_register_item("sh4", index, sh4.fr[ 2]);
+ state_save_register_item("sh4", index, sh4.fr[ 3]);
+ state_save_register_item("sh4", index, sh4.fr[ 4]);
+ state_save_register_item("sh4", index, sh4.fr[ 5]);
+ state_save_register_item("sh4", index, sh4.fr[ 6]);
+ state_save_register_item("sh4", index, sh4.fr[ 7]);
+ state_save_register_item("sh4", index, sh4.fr[ 8]);
+ state_save_register_item("sh4", index, sh4.fr[ 9]);
+ state_save_register_item("sh4", index, sh4.fr[10]);
+ state_save_register_item("sh4", index, sh4.fr[11]);
+ state_save_register_item("sh4", index, sh4.fr[12]);
+ state_save_register_item("sh4", index, sh4.fr[13]);
+ state_save_register_item("sh4", index, sh4.fr[14]);
+ state_save_register_item("sh4", index, sh4.fr[15]);
+ state_save_register_item("sh4", index, sh4.xf[ 0]);
+ state_save_register_item("sh4", index, sh4.xf[ 1]);
+ state_save_register_item("sh4", index, sh4.xf[ 2]);
+ state_save_register_item("sh4", index, sh4.xf[ 3]);
+ state_save_register_item("sh4", index, sh4.xf[ 4]);
+ state_save_register_item("sh4", index, sh4.xf[ 5]);
+ state_save_register_item("sh4", index, sh4.xf[ 6]);
+ state_save_register_item("sh4", index, sh4.xf[ 7]);
+ state_save_register_item("sh4", index, sh4.xf[ 8]);
+ state_save_register_item("sh4", index, sh4.xf[ 9]);
+ state_save_register_item("sh4", index, sh4.xf[10]);
+ state_save_register_item("sh4", index, sh4.xf[11]);
+ state_save_register_item("sh4", index, sh4.xf[12]);
+ state_save_register_item("sh4", index, sh4.xf[13]);
+ state_save_register_item("sh4", index, sh4.xf[14]);
+ state_save_register_item("sh4", index, sh4.xf[15]);
+ state_save_register_item("sh4", index, sh4.ea);
+ state_save_register_item("sh4", index, sh4.fpul);
+ state_save_register_item("sh4", index, sh4.dbr);
+ state_save_register_item_array("sh4", index, sh4.exception_priority);
+ state_save_register_item_array("sh4", index, sh4.exception_requesting);
+
+}
+
+void sh4_dma_ddt(struct sh4_ddt_dma *s)
+{
+UINT32 chcr;
+UINT32 *p32bits;
+UINT32 pos,len,siz;
+
+ if (sh4.dma_timer_active[s->channel])
+ return;
+ if (s->mode >= 0) {
+ switch (s->channel)
+ {
+ case 0:
+ if (s->mode & 1)
+ s->source = sh4.m[SAR0];
+ if (s->mode & 2)
+ sh4.m[SAR0] = s->source;
+ if (s->mode & 4)
+ s->destination = sh4.m[DAR0];
+ if (s->mode & 8)
+ sh4.m[DAR0] = s->destination;
+ break;
+ case 1:
+ if (s->mode & 1)
+ s->source = sh4.m[SAR1];
+ if (s->mode & 2)
+ sh4.m[SAR1] = s->source;
+ if (s->mode & 4)
+ s->destination = sh4.m[DAR1];
+ if (s->mode & 8)
+ sh4.m[DAR1] = s->destination;
+ break;
+ case 2:
+ if (s->mode & 1)
+ s->source = sh4.m[SAR2];
+ if (s->mode & 2)
+ sh4.m[SAR2] = s->source;
+ if (s->mode & 4)
+ s->destination = sh4.m[DAR2];
+ if (s->mode & 8)
+ sh4.m[DAR2] = s->destination;
+ break;
+ case 3:
+ default:
+ if (s->mode & 1)
+ s->source = sh4.m[SAR3];
+ if (s->mode & 2)
+ sh4.m[SAR3] = s->source;
+ if (s->mode & 4)
+ s->destination = sh4.m[DAR3];
+ if (s->mode & 8)
+ sh4.m[DAR3] = s->destination;
+ break;
+ }
+ switch (s->channel)
+ {
+ case 0:
+ chcr = sh4.m[CHCR0];
+ len = sh4.m[DMATCR0];
+ break;
+ case 1:
+ chcr = sh4.m[CHCR1];
+ len = sh4.m[DMATCR1];
+ break;
+ case 2:
+ chcr = sh4.m[CHCR2];
+ len = sh4.m[DMATCR2];
+ break;
+ case 3:
+ default:
+ chcr = sh4.m[CHCR3];
+ len = sh4.m[DMATCR3];
+ break;
+ }
+ if ((s->direction) == 0) {
+ chcr = (chcr & 0xffff3fff) | ((s->mode & 0x30) << 10);
+ } else {
+ chcr = (chcr & 0xffffcfff) | ((s->mode & 0x30) << 8);
+ }
+ siz = dmasize[(chcr >> 4) & 7];
+ if (siz && (s->size))
+ if ((len * siz) != (s->length * s->size))
+ return;
+ sh4_dma_transfer(s->channel, 0, chcr, &s->source, &s->destination, &len);
+ } else {
+ if ((s->direction) == 0) {
+ len = s->length;
+ p32bits = (UINT32 *)(s->buffer);
+ for (pos = 0;pos < len;pos++) {
+ *p32bits = program_read_dword_64le(s->source);
+ p32bits++;
+ s->source = s->source + 4;
+ }
+ } else {
+ len = s->length;
+ p32bits = (UINT32 *)(s->buffer);
+ for (pos = 0;pos < len;pos++) {
+ program_write_dword_64le(s->destination, *p32bits);
+ p32bits++;
+ s->destination = s->destination + 4;
+ }
+ }
+ }
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void sh4_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + SH4_IRL0: set_irq_line(SH4_IRL0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH4_IRL1: set_irq_line(SH4_IRL1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH4_IRL2: set_irq_line(SH4_IRL2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH4_IRL3: set_irq_line(SH4_IRL3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH4_IRLn: set_irq_line(SH4_IRLn, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_REGISTER + SH4_PC:
+ case CPUINFO_INT_PC: sh4.pc = info->i; sh4.delay = 0; break;
+ case CPUINFO_INT_SP: sh4.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_PR: sh4.pr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_SR:
+ sh4.sr = info->i;
+ sh4_exception_recompute();
+ sh4_check_pending_irq("sh4_set_info");
+ break;
+ case CPUINFO_INT_REGISTER + SH4_GBR: sh4.gbr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_VBR: sh4.vbr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_DBR: sh4.dbr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_MACH: sh4.mach = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_MACL: sh4.macl = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R0: sh4.r[ 0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R1: sh4.r[ 1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R2: sh4.r[ 2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R3: sh4.r[ 3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R4: sh4.r[ 4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R5: sh4.r[ 5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R6: sh4.r[ 6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R7: sh4.r[ 7] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R8: sh4.r[ 8] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R9: sh4.r[ 9] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R10: sh4.r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R11: sh4.r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R12: sh4.r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R13: sh4.r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R14: sh4.r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_R15: sh4.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH4_EA: sh4.ea = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R0_BK0: sh4.rbnk[0][0] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R1_BK0: sh4.rbnk[0][1] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R2_BK0: sh4.rbnk[0][2] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R3_BK0: sh4.rbnk[0][3] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R4_BK0: sh4.rbnk[0][4] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R5_BK0: sh4.rbnk[0][5] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R6_BK0: sh4.rbnk[0][6] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R7_BK0: sh4.rbnk[0][7] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R0_BK1: sh4.rbnk[1][0] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R1_BK1: sh4.rbnk[1][1] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R2_BK1: sh4.rbnk[1][2] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R3_BK1: sh4.rbnk[1][3] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R4_BK1: sh4.rbnk[1][4] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R5_BK1: sh4.rbnk[1][5] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R6_BK1: sh4.rbnk[1][6] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_R7_BK1: sh4.rbnk[1][7] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_SPC: sh4.spc = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_SSR: sh4.ssr = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_SGR: sh4.sgr = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FPSCR: sh4.fpscr = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FPUL: sh4.fpul = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR0: sh4.fr[ 0] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR1: sh4.fr[ 1] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR2: sh4.fr[ 2] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR3: sh4.fr[ 3] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR4: sh4.fr[ 4] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR5: sh4.fr[ 5] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR6: sh4.fr[ 6] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR7: sh4.fr[ 7] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR8: sh4.fr[ 8] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR9: sh4.fr[ 9] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR10: sh4.fr[10] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR11: sh4.fr[11] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR12: sh4.fr[12] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR13: sh4.fr[13] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR14: sh4.fr[14] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_FR15: sh4.fr[15] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF0: sh4.xf[ 0] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF1: sh4.xf[ 1] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF2: sh4.xf[ 2] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF3: sh4.xf[ 3] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF4: sh4.xf[ 4] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF5: sh4.xf[ 5] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF6: sh4.xf[ 6] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF7: sh4.xf[ 7] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF8: sh4.xf[ 8] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF9: sh4.xf[ 9] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF10: sh4.xf[10] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF11: sh4.xf[11] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF12: sh4.xf[12] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF13: sh4.xf[13] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF14: sh4.xf[14] = info->i; break;
+ case CPUINFO_STR_REGISTER + SH4_XF15: sh4.xf[15] = info->i; break;
+
+ case CPUINFO_INT_SH4_IRLn_INPUT: sh4_set_irln_input(cpu_getactivecpu(), info->i); break;
+ case CPUINFO_INT_SH4_FRT_INPUT: sh4_set_frt_input(cpu_getactivecpu(), info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_SH4_FTCSR_READ_CALLBACK: sh4.ftcsr_read_callback = (void (*) (UINT32 ))info->f; break;
+ case CPUINFO_PTR_SH4_EXTERNAL_DDT_DMA: sh4_dma_ddt((struct sh4_ddt_dma *)info->f); break;
+ }
+}
+
+#if 0
+/*When OC index mode is off (CCR.OIX = 0)*/
+static ADDRESS_MAP_START( sh4_internal_map, ADDRESS_SPACE_PROGRAM, 64 )
+ AM_RANGE(0x1C000000, 0x1C000FFF) AM_RAM AM_MIRROR(0x03FFD000)
+ AM_RANGE(0x1C002000, 0x1C002FFF) AM_RAM AM_MIRROR(0x03FFD000)
+ AM_RANGE(0xE0000000, 0xE000003F) AM_RAM AM_MIRROR(0x03FFFFC0)
+ADDRESS_MAP_END
+#endif
+
+/*When OC index mode is on (CCR.OIX = 1)*/
+static ADDRESS_MAP_START( sh4_internal_map, ADDRESS_SPACE_PROGRAM, 64 )
+ AM_RANGE(0x1C000000, 0x1C000FFF) AM_RAM AM_MIRROR(0x01FFF000)
+ AM_RANGE(0x1E000000, 0x1E000FFF) AM_RAM AM_MIRROR(0x01FFF000)
+ AM_RANGE(0xE0000000, 0xE000003F) AM_RAM AM_MIRROR(0x03FFFFC0)
+ADDRESS_MAP_END
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void sh4_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(sh4); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 4; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_sh4_internal_map; break;
+
+ case CPUINFO_INT_INPUT_STATE + SH4_IRL0: info->i = sh4.irq_line_state[SH4_IRL0]; break;
+ case CPUINFO_INT_INPUT_STATE + SH4_IRL1: info->i = sh4.irq_line_state[SH4_IRL1]; break;
+ case CPUINFO_INT_INPUT_STATE + SH4_IRL2: info->i = sh4.irq_line_state[SH4_IRL2]; break;
+ case CPUINFO_INT_INPUT_STATE + SH4_IRL3: info->i = sh4.irq_line_state[SH4_IRL3]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = sh4.nmi_line_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = sh4.ppc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SH4_PC: info->i = (sh4.delay) ? (sh4.delay & AM) : (sh4.pc & AM); break;
+ case CPUINFO_INT_SP: info->i = sh4.r[15]; break;
+ case CPUINFO_INT_REGISTER + SH4_PR: info->i = sh4.pr; break;
+ case CPUINFO_INT_REGISTER + SH4_SR: info->i = sh4.sr; break;
+ case CPUINFO_INT_REGISTER + SH4_GBR: info->i = sh4.gbr; break;
+ case CPUINFO_INT_REGISTER + SH4_VBR: info->i = sh4.vbr; break;
+ case CPUINFO_INT_REGISTER + SH4_DBR: info->i = sh4.dbr; break;
+ case CPUINFO_INT_REGISTER + SH4_MACH: info->i = sh4.mach; break;
+ case CPUINFO_INT_REGISTER + SH4_MACL: info->i = sh4.macl; break;
+ case CPUINFO_INT_REGISTER + SH4_R0: info->i = sh4.r[ 0]; break;
+ case CPUINFO_INT_REGISTER + SH4_R1: info->i = sh4.r[ 1]; break;
+ case CPUINFO_INT_REGISTER + SH4_R2: info->i = sh4.r[ 2]; break;
+ case CPUINFO_INT_REGISTER + SH4_R3: info->i = sh4.r[ 3]; break;
+ case CPUINFO_INT_REGISTER + SH4_R4: info->i = sh4.r[ 4]; break;
+ case CPUINFO_INT_REGISTER + SH4_R5: info->i = sh4.r[ 5]; break;
+ case CPUINFO_INT_REGISTER + SH4_R6: info->i = sh4.r[ 6]; break;
+ case CPUINFO_INT_REGISTER + SH4_R7: info->i = sh4.r[ 7]; break;
+ case CPUINFO_INT_REGISTER + SH4_R8: info->i = sh4.r[ 8]; break;
+ case CPUINFO_INT_REGISTER + SH4_R9: info->i = sh4.r[ 9]; break;
+ case CPUINFO_INT_REGISTER + SH4_R10: info->i = sh4.r[10]; break;
+ case CPUINFO_INT_REGISTER + SH4_R11: info->i = sh4.r[11]; break;
+ case CPUINFO_INT_REGISTER + SH4_R12: info->i = sh4.r[12]; break;
+ case CPUINFO_INT_REGISTER + SH4_R13: info->i = sh4.r[13]; break;
+ case CPUINFO_INT_REGISTER + SH4_R14: info->i = sh4.r[14]; break;
+ case CPUINFO_INT_REGISTER + SH4_R15: info->i = sh4.r[15]; break;
+ case CPUINFO_INT_REGISTER + SH4_EA: info->i = sh4.ea; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = sh4_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = sh4_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = sh4_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = sh4_init; break;
+ case CPUINFO_PTR_RESET: info->reset = sh4_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = sh4_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = sh4_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &sh4_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "SH-4"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Hitachi SH7750"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2007 R. Belmont"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%s%s%s%s%c%c%d%c%c",
+ sh4.sr & MD ? "MD ":" ",
+ sh4.sr & sRB ? "RB ":" ",
+ sh4.sr & BL ? "BL ":" ",
+ sh4.sr & FD ? "FD ":" ",
+ sh4.sr & M ? 'M':'.',
+ sh4.sr & Q ? 'Q':'.',
+ (sh4.sr & I) >> 4,
+ sh4.sr & S ? 'S':'.',
+ sh4.sr & T ? 'T':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + SH4_PC: sprintf(info->s, "PC :%08X", sh4.pc); break;
+ case CPUINFO_STR_REGISTER + SH4_SR: sprintf(info->s, "SR :%08X", sh4.sr); break;
+ case CPUINFO_STR_REGISTER + SH4_PR: sprintf(info->s, "PR :%08X", sh4.pr); break;
+ case CPUINFO_STR_REGISTER + SH4_GBR: sprintf(info->s, "GBR :%08X", sh4.gbr); break;
+ case CPUINFO_STR_REGISTER + SH4_VBR: sprintf(info->s, "VBR :%08X", sh4.vbr); break;
+ case CPUINFO_STR_REGISTER + SH4_DBR: sprintf(info->s, "DBR :%08X", sh4.dbr); break;
+ case CPUINFO_STR_REGISTER + SH4_MACH: sprintf(info->s, "MACH:%08X", sh4.mach); break;
+ case CPUINFO_STR_REGISTER + SH4_MACL: sprintf(info->s, "MACL:%08X", sh4.macl); break;
+ case CPUINFO_STR_REGISTER + SH4_R0: sprintf(info->s, "R0 :%08X", sh4.r[ 0]); break;
+ case CPUINFO_STR_REGISTER + SH4_R1: sprintf(info->s, "R1 :%08X", sh4.r[ 1]); break;
+ case CPUINFO_STR_REGISTER + SH4_R2: sprintf(info->s, "R2 :%08X", sh4.r[ 2]); break;
+ case CPUINFO_STR_REGISTER + SH4_R3: sprintf(info->s, "R3 :%08X", sh4.r[ 3]); break;
+ case CPUINFO_STR_REGISTER + SH4_R4: sprintf(info->s, "R4 :%08X", sh4.r[ 4]); break;
+ case CPUINFO_STR_REGISTER + SH4_R5: sprintf(info->s, "R5 :%08X", sh4.r[ 5]); break;
+ case CPUINFO_STR_REGISTER + SH4_R6: sprintf(info->s, "R6 :%08X", sh4.r[ 6]); break;
+ case CPUINFO_STR_REGISTER + SH4_R7: sprintf(info->s, "R7 :%08X", sh4.r[ 7]); break;
+ case CPUINFO_STR_REGISTER + SH4_R8: sprintf(info->s, "R8 :%08X", sh4.r[ 8]); break;
+ case CPUINFO_STR_REGISTER + SH4_R9: sprintf(info->s, "R9 :%08X", sh4.r[ 9]); break;
+ case CPUINFO_STR_REGISTER + SH4_R10: sprintf(info->s, "R10 :%08X", sh4.r[10]); break;
+ case CPUINFO_STR_REGISTER + SH4_R11: sprintf(info->s, "R11 :%08X", sh4.r[11]); break;
+ case CPUINFO_STR_REGISTER + SH4_R12: sprintf(info->s, "R12 :%08X", sh4.r[12]); break;
+ case CPUINFO_STR_REGISTER + SH4_R13: sprintf(info->s, "R13 :%08X", sh4.r[13]); break;
+ case CPUINFO_STR_REGISTER + SH4_R14: sprintf(info->s, "R14 :%08X", sh4.r[14]); break;
+ case CPUINFO_STR_REGISTER + SH4_R15: sprintf(info->s, "R15 :%08X", sh4.r[15]); break;
+ case CPUINFO_STR_REGISTER + SH4_EA: sprintf(info->s, "EA :%08X", sh4.ea); break;
+ case CPUINFO_STR_REGISTER + SH4_R0_BK0: sprintf(info->s, "R0 BK 0 :%08X", sh4.rbnk[0][0]); break;
+ case CPUINFO_STR_REGISTER + SH4_R1_BK0: sprintf(info->s, "R1 BK 0 :%08X", sh4.rbnk[0][1]); break;
+ case CPUINFO_STR_REGISTER + SH4_R2_BK0: sprintf(info->s, "R2 BK 0 :%08X", sh4.rbnk[0][2]); break;
+ case CPUINFO_STR_REGISTER + SH4_R3_BK0: sprintf(info->s, "R3 BK 0 :%08X", sh4.rbnk[0][3]); break;
+ case CPUINFO_STR_REGISTER + SH4_R4_BK0: sprintf(info->s, "R4 BK 0 :%08X", sh4.rbnk[0][4]); break;
+ case CPUINFO_STR_REGISTER + SH4_R5_BK0: sprintf(info->s, "R5 BK 0 :%08X", sh4.rbnk[0][5]); break;
+ case CPUINFO_STR_REGISTER + SH4_R6_BK0: sprintf(info->s, "R6 BK 0 :%08X", sh4.rbnk[0][6]); break;
+ case CPUINFO_STR_REGISTER + SH4_R7_BK0: sprintf(info->s, "R7 BK 0 :%08X", sh4.rbnk[0][7]); break;
+ case CPUINFO_STR_REGISTER + SH4_R0_BK1: sprintf(info->s, "R0 BK 1 :%08X", sh4.rbnk[1][0]); break;
+ case CPUINFO_STR_REGISTER + SH4_R1_BK1: sprintf(info->s, "R1 BK 1 :%08X", sh4.rbnk[1][1]); break;
+ case CPUINFO_STR_REGISTER + SH4_R2_BK1: sprintf(info->s, "R2 BK 1 :%08X", sh4.rbnk[1][2]); break;
+ case CPUINFO_STR_REGISTER + SH4_R3_BK1: sprintf(info->s, "R3 BK 1 :%08X", sh4.rbnk[1][3]); break;
+ case CPUINFO_STR_REGISTER + SH4_R4_BK1: sprintf(info->s, "R4 BK 1 :%08X", sh4.rbnk[1][4]); break;
+ case CPUINFO_STR_REGISTER + SH4_R5_BK1: sprintf(info->s, "R5 BK 1 :%08X", sh4.rbnk[1][5]); break;
+ case CPUINFO_STR_REGISTER + SH4_R6_BK1: sprintf(info->s, "R6 BK 1 :%08X", sh4.rbnk[1][6]); break;
+ case CPUINFO_STR_REGISTER + SH4_R7_BK1: sprintf(info->s, "R7 BK 1 :%08X", sh4.rbnk[1][7]); break;
+ case CPUINFO_STR_REGISTER + SH4_SPC: sprintf(info->s, "SPC :%08X", sh4.spc); break;
+ case CPUINFO_STR_REGISTER + SH4_SSR: sprintf(info->s, "SSR :%08X", sh4.ssr); break;
+ case CPUINFO_STR_REGISTER + SH4_SGR: sprintf(info->s, "SGR :%08X", sh4.sgr); break;
+ case CPUINFO_STR_REGISTER + SH4_FPSCR: sprintf(info->s, "FPSCR :%08X", sh4.fpscr); break;
+ case CPUINFO_STR_REGISTER + SH4_FPUL: sprintf(info->s, "FPUL :%08X", sh4.fpul); break;
+ case CPUINFO_STR_REGISTER + SH4_FR0: sprintf(info->s, "FR0 :%08X", sh4.fr[ 0]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR1: sprintf(info->s, "FR1 :%08X", sh4.fr[ 1]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR2: sprintf(info->s, "FR2 :%08X", sh4.fr[ 2]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR3: sprintf(info->s, "FR3 :%08X", sh4.fr[ 3]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR4: sprintf(info->s, "FR4 :%08X", sh4.fr[ 4]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR5: sprintf(info->s, "FR5 :%08X", sh4.fr[ 5]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR6: sprintf(info->s, "FR6 :%08X", sh4.fr[ 6]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR7: sprintf(info->s, "FR7 :%08X", sh4.fr[ 7]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR8: sprintf(info->s, "FR8 :%08X", sh4.fr[ 8]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR9: sprintf(info->s, "FR9 :%08X", sh4.fr[ 9]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR10: sprintf(info->s, "FR10 :%08X", sh4.fr[10]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR11: sprintf(info->s, "FR11 :%08X", sh4.fr[11]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR12: sprintf(info->s, "FR12 :%08X", sh4.fr[12]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR13: sprintf(info->s, "FR13 :%08X", sh4.fr[13]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR14: sprintf(info->s, "FR14 :%08X", sh4.fr[14]); break;
+ case CPUINFO_STR_REGISTER + SH4_FR15: sprintf(info->s, "FR15 :%08X", sh4.fr[15]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF0: sprintf(info->s, "XF0 :%08X", sh4.xf[ 0]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF1: sprintf(info->s, "XF1 :%08X", sh4.xf[ 1]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF2: sprintf(info->s, "XF2 :%08X", sh4.xf[ 2]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF3: sprintf(info->s, "XF3 :%08X", sh4.xf[ 3]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF4: sprintf(info->s, "XF4 :%08X", sh4.xf[ 4]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF5: sprintf(info->s, "XF5 :%08X", sh4.xf[ 5]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF6: sprintf(info->s, "XF6 :%08X", sh4.xf[ 6]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF7: sprintf(info->s, "XF7 :%08X", sh4.xf[ 7]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF8: sprintf(info->s, "XF8 :%08X", sh4.xf[ 8]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF9: sprintf(info->s, "XF9 :%08X", sh4.xf[ 9]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF10: sprintf(info->s, "XF10 :%08X", sh4.xf[10]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF11: sprintf(info->s, "XF11 :%08X", sh4.xf[11]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF12: sprintf(info->s, "XF12 :%08X", sh4.xf[12]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF13: sprintf(info->s, "XF13 :%08X", sh4.xf[13]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF14: sprintf(info->s, "XF14 :%08X", sh4.xf[14]); break;
+ case CPUINFO_STR_REGISTER + SH4_XF15: sprintf(info->s, "XF15 :%08X", sh4.xf[15]); break;
+ case CPUINFO_PTR_SH4_FTCSR_READ_CALLBACK: info->f = (genf*)sh4.ftcsr_read_callback; break;
+
+ }
+}
diff --git a/src/emu/cpu/sh4/sh4.h b/src/emu/cpu/sh4/sh4.h
new file mode 100644
index 00000000000..f209e206db7
--- /dev/null
+++ b/src/emu/cpu/sh4/sh4.h
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ *
+ * sh4.h
+ * Portable Hitachi SH-4 (SH7750 family) emulator interface
+ *
+ * By R. Belmont, based on sh2.c by Juergen Buchmueller, Mariusz Wojcieszek,
+ * Olivier Galibert, Sylvain Glaize, and James Forshaw.
+ *
+ *****************************************************************************/
+
+#ifndef _SH4_H
+#define _SH4_H
+
+#include "cpuintrf.h"
+
+#define SH4_INT_NONE -1
+enum {
+ SH4_IRL0=0, SH4_IRL1, SH4_IRL2, SH4_IRL3, SH4_IRLn
+};
+
+enum {
+ SH4_PC=1, SH4_SR, SH4_PR, SH4_GBR, SH4_VBR, SH4_DBR, SH4_MACH, SH4_MACL,
+ SH4_R0, SH4_R1, SH4_R2, SH4_R3, SH4_R4, SH4_R5, SH4_R6, SH4_R7,
+ SH4_R8, SH4_R9, SH4_R10, SH4_R11, SH4_R12, SH4_R13, SH4_R14, SH4_R15, SH4_EA,
+ SH4_R0_BK0, SH4_R1_BK0, SH4_R2_BK0, SH4_R3_BK0, SH4_R4_BK0, SH4_R5_BK0, SH4_R6_BK0, SH4_R7_BK0,
+ SH4_R0_BK1, SH4_R1_BK1, SH4_R2_BK1, SH4_R3_BK1, SH4_R4_BK1, SH4_R5_BK1, SH4_R6_BK1, SH4_R7_BK1,
+ SH4_SPC, SH4_SSR, SH4_SGR, SH4_FPSCR, SH4_FPUL, SH4_FR0, SH4_FR1, SH4_FR2, SH4_FR3, SH4_FR4, SH4_FR5,
+ SH4_FR6, SH4_FR7, SH4_FR8, SH4_FR9, SH4_FR10, SH4_FR11, SH4_FR12, SH4_FR13, SH4_FR14, SH4_FR15,
+ SH4_XF0, SH4_XF1, SH4_XF2, SH4_XF3, SH4_XF4, SH4_XF5, SH4_XF6, SH4_XF7,
+ SH4_XF8, SH4_XF9, SH4_XF10, SH4_XF11, SH4_XF12, SH4_XF13, SH4_XF14, SH4_XF15
+};
+
+enum {
+ SH4_INTC_NMI=23, SH4_INTC_IRLn0, SH4_INTC_IRLn1, SH4_INTC_IRLn2, SH4_INTC_IRLn3, SH4_INTC_IRLn4,
+ SH4_INTC_IRLn5, SH4_INTC_IRLn6, SH4_INTC_IRLn7, SH4_INTC_IRLn8, SH4_INTC_IRLn9, SH4_INTC_IRLnA,
+ SH4_INTC_IRLnB, SH4_INTC_IRLnC, SH4_INTC_IRLnD, SH4_INTC_IRLnE, SH4_INTC_IRL0, SH4_INTC_IRL1,
+ SH4_INTC_IRL2, SH4_INTC_IRL3, SH4_INTC_HUDI, SH4_INTC_GPOI, SH4_INTC_DMTE0, SH4_INTC_DMTE1,
+ SH4_INTC_DMTE2, SH4_INTC_DMTE3, SH4_INTC_DMTE4, SH4_INTC_DMTE5, SH4_INTC_DMTE6, SH4_INTC_DMTE7,
+ SH4_INTC_DMAE, SH4_INTC_TUNI3, SH4_INTC_TUNI4, SH4_INTC_TUNI0, SH4_INTC_TUNI1, SH4_INTC_TUNI2,
+ SH4_INTC_TICPI2, SH4_INTC_ATI, SH4_INTC_PRI, SH4_INTC_CUI, SH4_INTC_SCI1ERI, SH4_INTC_SCI1RXI,
+ SH4_INTC_SCI1TXI, SH4_INTC_SCI1TEI, SH4_INTC_SCIFERI, SH4_INTC_SCIFRXI, SH4_INTC_SCIFBRI,
+ SH4_INTC_SCIFTXI, SH4_INTC_ITI, SH4_INTC_RCMI, SH4_INTC_ROVI
+};
+
+enum
+{
+ CPUINFO_INT_SH4_IRLn_INPUT = CPUINFO_INT_CPU_SPECIFIC,
+ CPUINFO_INT_SH4_FRT_INPUT
+};
+
+enum
+{
+ CPUINFO_PTR_SH4_FTCSR_READ_CALLBACK = CPUINFO_PTR_CPU_SPECIFIC,
+ CPUINFO_PTR_SH4_EXTERNAL_DDT_DMA,
+};
+
+struct sh4_config
+{
+ int md2;
+ int md1;
+ int md0;
+ int md6;
+ int md4;
+ int md3;
+ int md5;
+ int md7;
+ int md8;
+ int clock;
+};
+
+struct sh4_ddt_dma
+{
+ UINT32 source;
+ UINT32 length;
+ UINT32 size;
+ UINT32 destination;
+ void *buffer;
+ int direction;
+ int channel;
+ int mode;
+};
+
+extern void sh4_get_info(UINT32 state, cpuinfo *info);
+
+WRITE32_HANDLER( sh4_internal_w );
+READ32_HANDLER( sh4_internal_r );
+
+#ifdef MAME_DEBUG
+extern unsigned DasmSH4( char *dst, unsigned pc, UINT16 opcode );
+#endif
+
+#endif /* _SH4_H */
+
diff --git a/src/emu/cpu/sh4/sh4dasm.c b/src/emu/cpu/sh4/sh4dasm.c
new file mode 100644
index 00000000000..50675b0dd57
--- /dev/null
+++ b/src/emu/cpu/sh4/sh4dasm.c
@@ -0,0 +1,792 @@
+#include "debugger.h"
+#include "sh4.h"
+
+#define SIGNX8(x) (((INT32)(x) << 24) >> 24)
+#define SIGNX12(x) (((INT32)(x) << 20) >> 20)
+
+#define Rn ((opcode >> 8) & 15)
+#define Rm ((opcode >> 4) & 15)
+
+static const char *regname[16] = {
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10","R11","R12","R13","R14","SP"
+};
+
+static UINT32 op0000(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ UINT32 flags = 0;
+ switch (opcode & 0xF)
+ {
+ case 0x0:
+ case 0x1:
+ sprintf(buffer, "?????? $%04X", opcode); break;
+ case 0x2:
+ if (opcode & 0x80) {
+ sprintf(buffer,"STC %s_BANK,%s", regname[(Rm) & 7],regname[Rn]);
+ return flags;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ sprintf(buffer,"STC SR,%s", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer,"STC GBR,%s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer,"STC VBR,%s", regname[Rn]); break;
+ case 0x30:
+ sprintf(buffer,"STC SSR,%s", regname[Rn]); break;
+ case 0x40:
+ sprintf(buffer,"STC SPC,%s", regname[Rn]); break;
+ }
+ break;
+ case 0x3:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ sprintf(buffer,"BSRF %s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer,"BRAF %s", regname[Rn]); break;
+ case 0x80:
+ sprintf(buffer,"PREF @%s", regname[Rn]); break;
+ case 0x90:
+ sprintf(buffer,"OCBI @%s", regname[Rn]); break;
+ case 0xA0:
+ sprintf(buffer,"OCBP @%s", regname[Rn]); break;
+ case 0xB0:
+ sprintf(buffer,"OCBWB @%s", regname[Rn]); break;
+ case 0xC0:
+ sprintf(buffer,"MOVCA.L R0,@%s", regname[Rn]); break;
+ }
+ break;
+ case 0x4:
+ sprintf(buffer, "MOV.B %s,@(R0,%s)", regname[Rm], regname[Rn]); break;
+ case 0x5:
+ sprintf(buffer, "MOV.W %s,@(R0,%s)", regname[Rm], regname[Rn]); break;
+ case 0x6:
+ sprintf(buffer, "MOV.L %s,@(R0,%s)", regname[Rm], regname[Rn]); break;
+ case 0x7:
+ sprintf(buffer, "MUL.L %s,%s", regname[Rm], regname[Rn]); break;
+ case 0x8:
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ sprintf(buffer,"CLRT"); break;
+ case 0x10:
+ sprintf(buffer,"SETT"); break;
+ case 0x20:
+ sprintf(buffer,"CLRMAC"); break;
+ case 0x30:
+ sprintf(buffer,"LDTLB"); break;
+ case 0x40:
+ sprintf(buffer,"CLRS"); break;
+ case 0x50:
+ sprintf(buffer,"SETS"); break;
+ }
+ break;
+ case 0x9:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ sprintf(buffer,"NOP"); break;
+ case 0x10:
+ sprintf(buffer,"DIV0U"); break;
+ case 0x20:
+ sprintf(buffer,"MOVT %s", regname[Rn]); break;
+ }
+ break;
+ case 0xA:
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ sprintf(buffer,"STS MACH,%s", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer,"STS MACL,%s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer,"STS PR,%s", regname[Rn]); break;
+ case 0x30:
+ sprintf(buffer,"STC SGR,%s", regname[Rn]); break;
+ case 0x50:
+ sprintf(buffer,"STS FPUL,%s", regname[Rn]); break;
+ case 0x60:
+ sprintf(buffer,"STS FPSCR,%s", regname[Rn]); break;
+ case 0x70:
+ sprintf(buffer,"STC DBR,%s", regname[Rn]); break;
+ }
+ break;
+ case 0xB:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ sprintf(buffer,"RTS");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ case 0x10:
+ sprintf(buffer,"SLEEP"); break;
+ case 0x20:
+ sprintf(buffer,"RTE");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ }
+ break;
+ case 0xC:
+ sprintf(buffer, "MOV.B @(R0,%s),%s", regname[Rm], regname[Rn]); break;
+ case 0xD:
+ sprintf(buffer, "MOV.W @(R0,%s),%s", regname[Rm], regname[Rn]); break;
+ case 0xE:
+ sprintf(buffer, "MOV.L @(R0,%s),%s", regname[Rm], regname[Rn]); break;
+ case 0xF:
+ sprintf(buffer, "MAC.L @%s+,@%s+", regname[Rn], regname[Rm]); break;
+ }
+ return flags;
+}
+
+static UINT32 op0001(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV.L %s,@($%02X,%s)\n", regname[Rm], (opcode & 15) * 4, regname[Rn]);
+ return 0;
+}
+
+static UINT32 op0010(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0:
+ sprintf(buffer, "MOV.B %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ sprintf(buffer, "MOV.W %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ sprintf(buffer, "MOV.L %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ sprintf(buffer, "?????? $%04X", opcode);
+ break;
+ case 4:
+ sprintf(buffer, "MOV.B %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ sprintf(buffer, "MOV.W %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ sprintf(buffer, "MOV.L %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ sprintf(buffer, "DIV0S %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ sprintf(buffer, "TST %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ sprintf(buffer, "AND %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ sprintf(buffer, "XOR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ sprintf(buffer, "OR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ sprintf(buffer, "CMP/STR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ sprintf(buffer, "XTRCT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ sprintf(buffer, "MULU.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ sprintf(buffer, "MULS.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static UINT32 op0011(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0:
+ sprintf(buffer, "CMP/EQ %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ sprintf(buffer, "?????? %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ sprintf(buffer, "CMP/HS %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ sprintf(buffer, "CMP/GE %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 4:
+ sprintf(buffer, "DIV1 %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ sprintf(buffer, "DMULU.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ sprintf(buffer, "CMP/HI %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ sprintf(buffer, "CMP/GT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ sprintf(buffer, "SUB %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ sprintf(buffer, "?????? %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ sprintf(buffer, "SUBC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ sprintf(buffer, "SUBV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ sprintf(buffer, "ADD %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ sprintf(buffer, "DMULS.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ sprintf(buffer, "ADDC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ sprintf(buffer, "ADDV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static UINT32 op0100(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ UINT32 flags = 0;
+ switch (opcode & 0xF)
+ {
+ case 0x0:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ sprintf(buffer, "SHLL %s", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "DT %s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "SHAL %s", regname[Rn]); break;
+ }
+ break;
+ case 0x1:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ sprintf(buffer, "SHLR %s", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "CMP/PZ %s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "SHAR %s", regname[Rn]); break;
+ }
+ break;
+ case 0x2:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ sprintf(buffer, "STS.L MACH,@-%s", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "STS.L MACL,@-%s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "STS.L PR,@-%s", regname[Rn]); break;
+ case 0x30:
+ sprintf(buffer, "STC.L SGR,@-%s", regname[Rn]); break;
+ case 0x50:
+ sprintf(buffer, "STS.L FPUL,@-%s", regname[Rn]); break;
+ case 0x60:
+ sprintf(buffer, "STS.L FPSCR,@-%s", regname[Rn]); break;
+ case 0xF0:
+ sprintf(buffer, "STC.L DBR,@-%s", regname[Rn]); break;
+ }
+ break;
+ case 0x3:
+ if (opcode & 0x80) {
+ sprintf(buffer, "STC.L %s_BANK,@-%s", regname[(Rm) & 7],regname[Rn]);
+ return flags;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ sprintf(buffer, "STC.L SR,@-%s", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "STC.L GBR,@-%s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "STC.L VBR,@-%s", regname[Rn]); break;
+ case 0x30:
+ sprintf(buffer, "STC.L SSR,@-%s", regname[Rn]); break;
+ case 0x40:
+ sprintf(buffer, "STC.L SPC,@-%s", regname[Rn]); break;
+ }
+ break;
+ case 0x4:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ sprintf(buffer, "ROTL %s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "ROTCL %s", regname[Rn]); break;
+ }
+ break;
+ case 0x5:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ sprintf(buffer, "ROTR %s", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "CMP/PL %s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "ROTCR %s", regname[Rn]); break;
+ }
+ break;
+ case 0x6:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ sprintf(buffer, "LDS.L @%s+,MACH", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "LDS.L @%s+,MACL", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "LDS.L @%s+,PR", regname[Rn]); break;
+ case 0x50:
+ sprintf(buffer, "LDS.L @%s+,FPUL", regname[Rn]); break;
+ case 0x60:
+ sprintf(buffer, "LDS.L @%s+,FPSCR", regname[Rn]); break;
+ case 0xF0:
+ sprintf(buffer, "LDC.L @%s+,DBR", regname[Rn]); break;
+ }
+ break;
+ case 0x7:
+ if (opcode & 0x80) {
+ sprintf(buffer, "LDC.L @%s+,%s_BANK", regname[Rn],regname[(Rm) & 7]);
+ return flags;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ sprintf(buffer, "LDC.L @%s+,SR", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "LDC.L @%s+,GBR", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "LDC.L @%s+,VBR", regname[Rn]); break;
+ case 0x30:
+ sprintf(buffer, "LDC.L @%s+,SSR", regname[Rn]); break;
+ case 0x40:
+ sprintf(buffer, "LDC.L @%s+,SPC", regname[Rn]); break;
+ }
+ break;
+ case 0x8:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ sprintf(buffer, "SHLL2 %s", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "SHLL8 %s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "SHLL16 %s", regname[Rn]); break;
+ }
+ break;
+ case 0x9:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ sprintf(buffer, "SHLR2 %s", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "SHLR8 %s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "SHLR16 %s", regname[Rn]); break;
+ }
+ break;
+ case 0xA:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ sprintf(buffer, "LDS %s,MACH", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "LDS %s,MACL", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "LDS %s,PR", regname[Rn]); break;
+ case 0x50:
+ sprintf(buffer, "LDS %s,FPUL", regname[Rn]); break;
+ case 0x60:
+ sprintf(buffer, "LDS %s,FPSCR", regname[Rn]); break;
+ case 0xF0:
+ sprintf(buffer, "LDC %s,DBR", regname[Rn]); break;
+ }
+ break;
+ case 0xB:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ sprintf(buffer, "JSR %s", regname[Rn]);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ break;
+ case 0x10:
+ sprintf(buffer, "TAS %s", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "JMP %s", regname[Rn]); break;
+ }
+ break;
+ case 0xC:
+ sprintf(buffer, "SHAD %s,%s", regname[Rm], regname[Rn]); break;
+ case 0xD:
+ sprintf(buffer, "SHLD %s,%s", regname[Rm], regname[Rn]); break;
+ case 0xE:
+ if (opcode & 0x80) {
+ sprintf(buffer, "LDC %s,%s_BANK", regname[Rn],regname[(Rm) & 7]);
+ return flags;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ sprintf(buffer, "LDC %s,SR", regname[Rn]); break;
+ case 0x10:
+ sprintf(buffer, "LDC %s,GBR", regname[Rn]); break;
+ case 0x20:
+ sprintf(buffer, "LDC %s,VBR", regname[Rn]); break;
+ case 0x30:
+ sprintf(buffer, "LDC %s,SSR", regname[Rn]); break;
+ case 0x40:
+ sprintf(buffer, "LDC %s,SPC", regname[Rn]); break;
+ }
+ break;
+ case 0xF:
+ sprintf(buffer, "MAC.W @%s+,@%s+", regname[Rm], regname[Rn]); break;
+ }
+ return flags;
+}
+
+static UINT32 op0101(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV.L @($%02X,%s),%s\n", (opcode & 15) * 4, regname[Rm], regname[Rn]);
+ return 0;
+}
+
+static UINT32 op0110(char *buffer, UINT32 pc, UINT16 opcode)
+
+{
+ switch(opcode & 0xF)
+ {
+ case 0x00:
+ sprintf(buffer, "MOV.B @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x01:
+ sprintf(buffer, "MOV.W @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x02:
+ sprintf(buffer, "MOV.L @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x03:
+ sprintf(buffer, "MOV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x04:
+ sprintf(buffer, "MOV.B @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x05:
+ sprintf(buffer, "MOV.W @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x06:
+ sprintf(buffer, "MOV.L @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x07:
+ sprintf(buffer, "NOT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x08:
+ sprintf(buffer, "SWAP.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x09:
+ sprintf(buffer, "SWAP.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0a:
+ sprintf(buffer, "NEGC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0b:
+ sprintf(buffer, "NEG %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0c:
+ sprintf(buffer, "EXTU.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0d:
+ sprintf(buffer, "EXTU.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0e:
+ sprintf(buffer, "EXTS.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0f:
+ sprintf(buffer, "EXTS.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static UINT32 op0111(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "ADD #$%02X,%s\n", opcode & 0xff, regname[Rn]);
+ return 0;
+}
+
+static UINT32 op1000(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ switch((opcode >> 8) & 15)
+ {
+ case 0:
+ sprintf(buffer, "MOV.B R0,@($%02X,%s)", (opcode & 15), regname[Rm]);
+ break;
+ case 1:
+ sprintf(buffer, "MOV.W R0,@($%02X,%s)", (opcode & 15) * 2, regname[Rm]);
+ break;
+ case 4:
+ sprintf(buffer, "MOV.B @($%02X,%s),R0", (opcode & 15), regname[Rm]);
+ break;
+ case 5:
+ sprintf(buffer, "MOV.W @($%02X,%s),R0", (opcode & 15), regname[Rm]);
+ break;
+ case 8:
+ sprintf(buffer, "CMP/EQ #$%02X,R0", (opcode & 0xff));
+ break;
+ case 9:
+ sprintf(buffer, "BT $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 11:
+ sprintf(buffer, "BF $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 13:
+ sprintf(buffer, "BTS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 15:
+ sprintf(buffer, "BFS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ default :
+ sprintf(buffer, "invalid $%04X\n", opcode);
+ }
+ return 0;
+}
+
+static UINT32 op1001(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV.W @($%04X,PC),%s", (opcode & 0xff) * 2, regname[Rn]);
+ return 0;
+}
+
+static UINT32 op1010(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "BRA $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2);
+ return 0;
+}
+
+static UINT32 op1011(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "BSR $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2);
+ return DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+}
+
+static UINT32 op1100(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ UINT32 flags = 0;
+ switch((opcode >> 8) & 15)
+ {
+ case 0:
+ sprintf(buffer, "MOV.B R0,@($%02X,GBR)", opcode & 0xff);
+ break;
+ case 1:
+ sprintf(buffer, "MOV.W R0,@($%04X,GBR)", (opcode & 0xff) * 2);
+ break;
+ case 2:
+ sprintf(buffer, "MOV.L R0,@($%04X,GBR)", (opcode & 0xff) * 4);
+ break;
+ case 3:
+ sprintf(buffer, "TRAPA #$%02X", opcode & 0xff);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 4:
+ sprintf(buffer, "MOV.B @($%02X,GBR),R0", opcode & 0xff);
+ break;
+ case 5:
+ sprintf(buffer, "MOV.W @($%04X,GBR),R0", (opcode & 0xff) * 2);
+ break;
+ case 6:
+ sprintf(buffer, "MOV.L @($%04X,GBR),R0", (opcode & 0xff) * 4);
+ break;
+ case 7:
+ sprintf(buffer, "MOVA @($%04X,PC),R0", (opcode & 0xff) * 4);
+ break;
+ case 8:
+ sprintf(buffer, "TST #$%02X,R0", opcode & 0xff);
+ break;
+ case 9:
+ sprintf(buffer, "AND #$%02X,R0", opcode & 0xff);
+ break;
+ case 10:
+ sprintf(buffer, "XOR #$%02X,R0", opcode & 0xff);
+ break;
+ case 11:
+ sprintf(buffer, "OR #$%02X,R0", opcode & 0xff);
+ break;
+ case 12:
+ sprintf(buffer, "TST.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 13:
+ sprintf(buffer, "AND.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 14:
+ sprintf(buffer, "XOR.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 15:
+ sprintf(buffer, "OR.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ }
+ return flags;
+}
+
+static UINT32 op1101(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV.L @($%02X,PC),%s", (opcode * 4) & 0xff, regname[Rn]);
+ return 0;
+}
+
+static UINT32 op1110(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ sprintf(buffer, "MOV #$%02X,%s", (opcode & 0xff), regname[Rn]);
+ return 0;
+}
+
+static UINT32 op1111(char *buffer, UINT32 pc, UINT16 opcode)
+{
+ switch (opcode & 0xf)
+ {
+ case 0:
+ sprintf(buffer, "FADD F%s, F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ sprintf(buffer, "FSUB F%s, F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ sprintf(buffer, "FMUL F%s, F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ sprintf(buffer, "FDIV F%s, F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 4:
+ sprintf(buffer, "FCMP/EQ F%s, F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ sprintf(buffer, "FCMP/GT F%s, F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ sprintf(buffer, "FMOV.S @(R0,%s),F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ sprintf(buffer, "FMOV.S F%s, @(R0,%s)\n", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ sprintf(buffer, "FMOV.S @%s, F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ sprintf(buffer, "FMOV.S @%s+, F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ sprintf(buffer, "FMOV.S F%s, @%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ sprintf(buffer, "FMOV.S F%s, @-%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ sprintf(buffer, "FMOV.S F%s, F%s\n", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ sprintf(buffer, "FSTS FPUL, F%s\n", regname[Rn]);
+ break;
+ case 0x10:
+ sprintf(buffer, "FLDS F%s, FPUL\n", regname[Rn]);
+ break;
+ case 0x20:
+ sprintf(buffer, "FLOAT FPUL, F%s\n", regname[Rn]);
+ break;
+ case 0x30:
+ sprintf(buffer, "FTRC F%s, FPUL\n", regname[Rn]);
+ break;
+ case 0x40:
+ sprintf(buffer, "FNEG F%s\n", regname[Rn]);
+ break;
+ case 0x50:
+ sprintf(buffer, "FABS F%s\n", regname[Rn]);
+ break;
+ case 0x60:
+ sprintf(buffer, "FSQRT F%s\n", regname[Rn]);
+ break;
+ case 0x80:
+ sprintf(buffer, "FLDI0 F%s\n", regname[Rn]);
+ break;
+ case 0x90:
+ sprintf(buffer, "FLDI1 F%s\n", regname[Rn]);
+ break;
+ case 0xA0:
+ sprintf(buffer, "FCNVSD FPUL, D%s\n", regname[Rn]);
+ break;
+ case 0xB0:
+ sprintf(buffer, "FCNVDS D%s, FPUL\n", regname[Rn]);
+ break;
+ case 0xE0:
+ sprintf(buffer, "FIPR FV%d, FV%d\n", Rn << 2, Rn & 12);
+ break;
+ case 0xF0:
+ if (opcode == 0xF3FD)
+ sprintf(buffer, "FSCHG\n");
+ else if (opcode == 0xFBFD)
+ sprintf(buffer, "FRCHG\n");
+ else if ((opcode & 0x300) == 0x100)
+ sprintf(buffer, "FTRV XMTRX, FV%d\n", Rn & 12);
+ else
+ sprintf(buffer, "Funknown $%04X", opcode);
+ break;
+ default:
+ sprintf(buffer, "Funknown $%04X", opcode);
+ break;
+ }
+ break;
+ case 14:
+ sprintf(buffer, "FMAC FR0, F%s,F%s\n", regname[Rm], regname[Rn]);
+ break;
+ default:
+ sprintf(buffer, "Funknown $%04X", opcode);
+ break;
+
+ }
+
+ return 0;
+}
+
+unsigned DasmSH4(char *buffer, unsigned pc, UINT16 opcode)
+{
+ UINT32 flags;
+
+ pc += 2;
+
+ switch((opcode >> 12) & 15)
+ {
+ case 0: flags = op0000(buffer,pc,opcode); break;
+ case 1: flags = op0001(buffer,pc,opcode); break;
+ case 2: flags = op0010(buffer,pc,opcode); break;
+ case 3: flags = op0011(buffer,pc,opcode); break;
+ case 4: flags = op0100(buffer,pc,opcode); break;
+ case 5: flags = op0101(buffer,pc,opcode); break;
+ case 6: flags = op0110(buffer,pc,opcode); break;
+ case 7: flags = op0111(buffer,pc,opcode); break;
+ case 8: flags = op1000(buffer,pc,opcode); break;
+ case 9: flags = op1001(buffer,pc,opcode); break;
+ case 10: flags = op1010(buffer,pc,opcode); break;
+ case 11: flags = op1011(buffer,pc,opcode); break;
+ case 12: flags = op1100(buffer,pc,opcode); break;
+ case 13: flags = op1101(buffer,pc,opcode); break;
+ case 14: flags = op1110(buffer,pc,opcode); break;
+ default: flags = op1111(buffer,pc,opcode); break;
+ }
+ return 2 | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/sh4/sh4regs.h b/src/emu/cpu/sh4/sh4regs.h
new file mode 100644
index 00000000000..a53ad7e0c18
--- /dev/null
+++ b/src/emu/cpu/sh4/sh4regs.h
@@ -0,0 +1,157 @@
+#ifndef _SH4REGS_H
+#define _SH4REGS_H
+
+/* 00000001111111100000000011111100 */
+#define PTEH 0x2000 /* FF000000 */
+#define PTEL 0x2001 /* FF000004 */
+#define TTB 0x2002 /* FF000008 */
+#define TEA 0x2003 /* FF00000C */
+#define MMUCR 0x2004 /* FF000010 */
+#define BASRA 0x2005 /* FF000014 */
+#define BASRB 0x2006 /* FF000018 */
+#define CCR 0x2007 /* FF00001C */
+#define TRA 0x2008 /* FF000020 */
+#define EXPEVT 0x2009 /* FF000024 */
+#define INTEVT 0x200A /* FF000028 */
+#define PTEA 0x200D /* FF000034 */
+#define QACR0 0x200E /* FF000038 */
+#define QACR1 0x200F /* FF00003C */
+#define BARA 0x2400 /* FF200000 */
+#define BAMRA 0x2401 /* FF200004 */
+#define BBRA 0x2402 /* FF200008 */
+#define BARB 0x2403 /* FF20000C */
+#define BAMRB 0x2404 /* FF200010 */
+#define BBRB 0x2405 /* FF200014 */
+#define BDRB 0x2406 /* FF200018 */
+#define BDMRB 0x2407 /* FF20001C */
+#define BRCR 0x2408 /* FF200020 */
+#define BCR1 0x3000 /* FF800000 */
+#define BCR2 0x3001 /* FF800004 */
+#define BCR3 0x3014 /* FF800050 */
+#define BCR4 0x17C /* FE0A00F0 */
+#define WCR1 0x3002 /* FF800008 */
+#define WCR2 0x3003 /* FF80000C */
+#define WCR3 0x3004 /* FF800010 */
+#define MCR 0x3005 /* FF800014 */
+#define PCR 0x3006 /* FF800018 */
+#define RTCSR 0x3007 /* FF80001C */
+#define RTCNT 0x3008 /* FF800020 */
+#define RTCOR 0x3009 /* FF800024 */
+#define RFCR 0x300A /* FF800028 */
+#define PCTRA 0x300B /* FF80002C */
+#define PDTRA 0x300C /* FF800030 */
+#define PCTRB 0x3010 /* FF800040 */
+#define PDTRB 0x3011 /* FF800044 */
+#define GPIOIC 0x3012 /* FF800048 */
+#define SDMR2 0x3200 /* FF900000 */
+#define SDMR3 0x3280 /* FF940000 */
+#define SAR0 0x3400 /* FFA00000 */
+#define DAR0 0x3401 /* FFA00004 */
+#define DMATCR0 0x3402 /* FFA00008 */
+#define CHCR0 0x3403 /* FFA0000C */
+#define SAR1 0x3404 /* FFA00010 */
+#define DAR1 0x3405 /* FFA00014 */
+#define DMATCR1 0x3406 /* FFA00018 */
+#define CHCR1 0x3407 /* FFA0001C */
+#define SAR2 0x3408 /* FFA00020 */
+#define DAR2 0x3409 /* FFA00024 */
+#define DMATCR2 0x340A /* FFA00028 */
+#define CHCR2 0x340B /* FFA0002C */
+#define SAR3 0x340C /* FFA00030 */
+#define DAR3 0x340D /* FFA00034 */
+#define DMATCR3 0x340E /* FFA00038 */
+#define CHCR3 0x340F /* FFA0003C */
+#define DMAOR 0x3410 /* FFA00040 */
+#define SAR4 0x3414 /* FFA00050 */
+#define DAR4 0x3415 /* FFA00054 */
+#define DMATCR4 0x3416 /* FFA00058 */
+#define CHCR4 0x3417 /* FFA0005C */
+#define SAR5 0x3418 /* FFA00060 */
+#define DAR5 0x3419 /* FFA00064 */
+#define DMATCR5 0x341A /* FFA00068 */
+#define CHCR5 0x341B /* FFA0006C */
+#define SAR6 0x341C /* FFA00070 */
+#define DAR6 0x341D /* FFA00074 */
+#define DMATCR6 0x341E /* FFA00078 */
+#define CHCR6 0x341F /* FFA0007C */
+#define SAR7 0x3420 /* FFA00080 */
+#define DAR7 0x3421 /* FFA00084 */
+#define DMATCR7 0x3422 /* FFA00088 */
+#define CHCR7 0x3423 /* FFA0008C */
+#define FRQCR 0x3800 /* FFC00000 */
+#define STBCR 0x3801 /* FFC00004 */
+#define WTCNT 0x3802 /* FFC00008 */
+#define WTCSR 0x3803 /* FFC0000C */
+#define STBCR2 0x3804 /* FFC00010 */
+#define R64CNT 0x3900 /* FFC80000 */
+#define RSECCNT 0x3901 /* FFC80004 */
+#define RMINCNT 0x3902 /* FFC80008 */
+#define RHRCNT 0x3903 /* FFC8000C */
+#define RWKCNT 0x3904 /* FFC80010 */
+#define RDAYCNT 0x3905 /* FFC80014 */
+#define RMONCNT 0x3906 /* FFC80018 */
+#define RYRCNT 0x3907 /* FFC8001C */
+#define RSECAR 0x3908 /* FFC80020 */
+#define RMINAR 0x3909 /* FFC80024 */
+#define RHRAR 0x390A /* FFC80028 */
+#define RWKAR 0x390B /* FFC8002C */
+#define RDAYAR 0x390C /* FFC80030 */
+#define RMONAR 0x390D /* FFC80034 */
+#define RCR1 0x390E /* FFC80038 */
+#define RCR2 0x390F /* FFC8003C */
+#define RCR3 0x3914 /* FFC80050 */
+#define RYRAR 0x3915 /* FFC80054 */
+#define ICR 0x3A00 /* FFD00000 */
+#define IPRA 0x3A01 /* FFD00004 */
+#define IPRB 0x3A02 /* FFD00008 */
+#define IPRC 0x3A03 /* FFD0000C */
+#define IPRD 0x3A04 /* FFD00010 */
+#define INTPRI00 0x100 /* FE080000 */
+#define INTREQ00 0x108 /* FE080020 */
+#define INTMSK00 0x110 /* FE080040 */
+#define INTMSKCLR00 0x118 /* FE080060 */
+#define CLKSTP00 0x140 /* FE0A0000 */
+#define CLKSTPCLR00 0x142 /* FE0A0008 */
+#define TSTR2 0x201 /* FE100004 */
+#define TCOR3 0x202 /* FE100008 */
+#define TCNT3 0x203 /* FE10000C */
+#define TCR3 0x204 /* FE100010 */
+#define TCOR4 0x205 /* FE100014 */
+#define TCNT4 0x206 /* FE100018 */
+#define TCR4 0x207 /* FE10001C */
+#define TOCR 0x3B00 /* FFD80000 */
+#define TSTR 0x3B01 /* FFD80004 */
+#define TCOR0 0x3B02 /* FFD80008 */
+#define TCNT0 0x3B03 /* FFD8000C */
+#define TCR0 0x3B04 /* FFD80010 */
+#define TCOR1 0x3B05 /* FFD80014 */
+#define TCNT1 0x3B06 /* FFD80018 */
+#define TCR1 0x3B07 /* FFD8001C */
+#define TCOR2 0x3B08 /* FFD80020 */
+#define TCNT2 0x3B09 /* FFD80024 */
+#define TCR2 0x3B0A /* FFD80028 */
+#define TCPR2 0x3B0B /* FFD8002C */
+#define SCSMR1 0x3C00 /* FFE00000 */
+#define SCBRR1 0x3C01 /* FFE00004 */
+#define SCSCR1 0x3C02 /* FFE00008 */
+#define SCTDR1 0x3C03 /* FFE0000C */
+#define SCSSR1 0x3C04 /* FFE00010 */
+#define SCRDR1 0x3C05 /* FFE00014 */
+#define SCSCMR1 0x3C06 /* FFE00018 */
+#define SCSPTR1 0x3C07 /* FFE0001C */
+#define SCSMR2 0x3D00 /* FFE80000 */
+#define SCBRR2 0x3D01 /* FFE80004 */
+#define SCSCR2 0x3D02 /* FFE80008 */
+#define SCFTDR2 0x3D03 /* FFE8000C */
+#define SCFSR2 0x3D04 /* FFE80010 */
+#define SCFRDR2 0x3D05 /* FFE80014 */
+#define SCFCR2 0x3D06 /* FFE80018 */
+#define SCFDR2 0x3D07 /* FFE8001C */
+#define SCSPTR2 0x3D08 /* FFE80020 */
+#define SCLSR2 0x3D09 /* FFE80024 */
+#define SDIR 0x3E00 /* FFF00000 */
+#define SDDR 0x3E02 /* FFF00008 */
+#define SDINT 0x3E05 /* FFF00014 */
+#define SIZEREGS 15878
+
+#endif
diff --git a/src/emu/cpu/sharc/compute.c b/src/emu/cpu/sharc/compute.c
new file mode 100644
index 00000000000..e286a4bf046
--- /dev/null
+++ b/src/emu/cpu/sharc/compute.c
@@ -0,0 +1,1338 @@
+/* compute operations */
+
+#include <math.h>
+
+#define CLEAR_ALU_FLAGS() (sharc.astat &= ~(AZ|AN|AV|AC|AS|AI))
+
+#define SET_FLAG_AZ(r) { sharc.astat |= (((r) == 0) ? AZ : 0); }
+#define SET_FLAG_AN(r) { sharc.astat |= (((r) & 0x80000000) ? AN : 0); }
+#define SET_FLAG_AC_ADD(r,a,b) { sharc.astat |= (((UINT32)r < (UINT32)a) ? AC : 0); }
+#define SET_FLAG_AV_ADD(r,a,b) { sharc.astat |= (((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) ? AV : 0); }
+#define SET_FLAG_AC_SUB(r,a,b) { sharc.astat |= ((!((UINT32)a < (UINT32)b)) ? AC : 0); }
+#define SET_FLAG_AV_SUB(r,a,b) { sharc.astat |= ((( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) ? AV : 0); }
+
+#define IS_FLOAT_ZERO(r) ((((r) & 0x7fffffff) == 0))
+#define IS_FLOAT_DENORMAL(r) ((((r) & 0x7f800000) == 0) && (((r) & 0x7fffff) != 0))
+#define IS_FLOAT_NAN(r) ((((r) & 0x7f800000) == 0x7f800000) && (((r) & 0x7fffff) != 0))
+#define IS_FLOAT_INFINITY(r) (((r) & 0x7fffffff) == 0x7f800000)
+
+#define CLEAR_MULTIPLIER_FLAGS() (sharc.astat &= ~(MN|MV|MU|MI))
+
+#define SET_FLAG_MN(r) { sharc.astat |= (((r) & 0x80000000) ? MN : 0); }
+#define SET_FLAG_MV(r) { sharc.astat |= ((((UINT32)((r) >> 32) != 0) && ((UINT32)((r) >> 32) != 0xffffffff)) ? MV : 0); }
+
+/* TODO: MU needs 80-bit result */
+#define SET_FLAG_MU(r) { sharc.astat |= ((((UINT32)((r) >> 32) == 0) && ((UINT32)(r)) != 0) ? MU : 0); }
+
+
+#define FLOAT_SIGN 0x80000000
+#define FLOAT_INFINITY 0x7f800000
+#define FLOAT_MANTISSA 0x007fffff
+
+/*****************************************************************************/
+
+// Mantissa lookup-table for RECIPS opcode
+static const UINT32 recips_mantissa_lookup[128] =
+{
+ 0x007F8000, 0x007E0000, 0x007C0000, 0x007A0000,
+ 0x00780000, 0x00760000, 0x00740000, 0x00720000,
+ 0x00700000, 0x006F0000, 0x006D0000, 0x006B0000,
+ 0x006A0000, 0x00680000, 0x00660000, 0x00650000,
+ 0x00630000, 0x00610000, 0x00600000, 0x005E0000,
+ 0x005D0000, 0x005B0000, 0x005A0000, 0x00590000,
+ 0x00570000, 0x00560000, 0x00540000, 0x00530000,
+ 0x00520000, 0x00500000, 0x004F0000, 0x004E0000,
+ 0x004C0000, 0x004B0000, 0x004A0000, 0x00490000,
+ 0x00470000, 0x00460000, 0x00450000, 0x00440000,
+ 0x00430000, 0x00410000, 0x00400000, 0x003F0000,
+ 0x003E0000, 0x003D0000, 0x003C0000, 0x003B0000,
+ 0x003A0000, 0x00390000, 0x00380000, 0x00370000,
+ 0x00360000, 0x00350000, 0x00340000, 0x00330000,
+ 0x00320000, 0x00310000, 0x00300000, 0x002F0000,
+ 0x002E0000, 0x002D0000, 0x002C0000, 0x002B0000,
+ 0x002A0000, 0x00290000, 0x00280000, 0x00280000,
+ 0x00270000, 0x00260000, 0x00250000, 0x00240000,
+ 0x00230000, 0x00230000, 0x00220000, 0x00210000,
+ 0x00200000, 0x001F0000, 0x001F0000, 0x001E0000,
+ 0x001D0000, 0x001C0000, 0x001C0000, 0x001B0000,
+ 0x001A0000, 0x00190000, 0x00190000, 0x00180000,
+ 0x00170000, 0x00170000, 0x00160000, 0x00150000,
+ 0x00140000, 0x00140000, 0x00130000, 0x00120000,
+ 0x00120000, 0x00110000, 0x00100000, 0x00100000,
+ 0x000F0000, 0x000F0000, 0x000E0000, 0x000D0000,
+ 0x000D0000, 0x000C0000, 0x000C0000, 0x000B0000,
+ 0x000A0000, 0x000A0000, 0x00090000, 0x00090000,
+ 0x00080000, 0x00070000, 0x00070000, 0x00060000,
+ 0x00060000, 0x00050000, 0x00050000, 0x00040000,
+ 0x00040000, 0x00030000, 0x00030000, 0x00020000,
+ 0x00020000, 0x00010000, 0x00010000, 0x00000000,
+};
+
+// Mantissa lookup-table for RSQRTS opcode
+static const UINT32 rsqrts_mantissa_lookup[128] =
+{
+ 0x00350000, 0x00330000, 0x00320000, 0x00300000,
+ 0x002F0000, 0x002E0000, 0x002D0000, 0x002B0000,
+ 0x002A0000, 0x00290000, 0x00280000, 0x00270000,
+ 0x00260000, 0x00250000, 0x00230000, 0x00220000,
+ 0x00210000, 0x00200000, 0x001F0000, 0x001E0000,
+ 0x001E0000, 0x001D0000, 0x001C0000, 0x001B0000,
+ 0x001A0000, 0x00190000, 0x00180000, 0x00170000,
+ 0x00160000, 0x00160000, 0x00150000, 0x00140000,
+ 0x00130000, 0x00130000, 0x00120000, 0x00110000,
+ 0x00100000, 0x00100000, 0x000F0000, 0x000E0000,
+ 0x000E0000, 0x000D0000, 0x000C0000, 0x000B0000,
+ 0x000B0000, 0x000A0000, 0x000A0000, 0x00090000,
+ 0x00080000, 0x00080000, 0x00070000, 0x00070000,
+ 0x00060000, 0x00050000, 0x00050000, 0x00040000,
+ 0x00040000, 0x00030000, 0x00030000, 0x00020000,
+ 0x00020000, 0x00010000, 0x00010000, 0x00000000,
+ 0x007F8000, 0x007E0000, 0x007C0000, 0x007A0000,
+ 0x00780000, 0x00760000, 0x00740000, 0x00730000,
+ 0x00710000, 0x006F0000, 0x006E0000, 0x006C0000,
+ 0x006A0000, 0x00690000, 0x00670000, 0x00660000,
+ 0x00640000, 0x00630000, 0x00620000, 0x00600000,
+ 0x005F0000, 0x005E0000, 0x005C0000, 0x005B0000,
+ 0x005A0000, 0x00590000, 0x00570000, 0x00560000,
+ 0x00550000, 0x00540000, 0x00530000, 0x00520000,
+ 0x00510000, 0x004F0000, 0x004E0000, 0x004D0000,
+ 0x004C0000, 0x004B0000, 0x004A0000, 0x00490000,
+ 0x00480000, 0x00470000, 0x00460000, 0x00450000,
+ 0x00450000, 0x00440000, 0x00430000, 0x00420000,
+ 0x00410000, 0x00400000, 0x003F0000, 0x003E0000,
+ 0x003E0000, 0x003D0000, 0x003C0000, 0x003B0000,
+ 0x003A0000, 0x003A0000, 0x00390000, 0x00380000,
+ 0x00370000, 0x00370000, 0x00360000, 0x00350000,
+};
+
+/*****************************************************************************/
+/* Integer ALU operations */
+
+/* Rn = Rx + Ry */
+INLINE void compute_add(int rn, int rx, int ry)
+{
+ UINT32 r = REG(rx) + REG(ry);
+
+ if (sharc.mode1 & MODE1_ALUSAT)
+ fatalerror("SHARC: compute_add: ALU saturation not implemented !");
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ SET_FLAG_AV_ADD(r, REG(rx), REG(ry));
+ SET_FLAG_AC_ADD(r, REG(rx), REG(ry));
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = Rx - Ry */
+INLINE void compute_sub(int rn, int rx, int ry)
+{
+ UINT32 r = REG(rx) - REG(ry);
+
+ if (sharc.mode1 & MODE1_ALUSAT)
+ fatalerror("SHARC: compute_sub: ALU saturation not implemented !");
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ SET_FLAG_AV_SUB(r, REG(rx), REG(ry));
+ SET_FLAG_AC_SUB(r, REG(rx), REG(ry));
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = Rx + Ry + CI */
+INLINE void compute_add_ci(int rn, int rx, int ry)
+{
+ int c = (sharc.astat & AC) ? 1 : 0;
+ UINT32 r = REG(rx) + REG(ry) + c;
+
+ if (sharc.mode1 & MODE1_ALUSAT)
+ fatalerror("SHARC: compute_add_ci: ALU saturation not implemented !");
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ SET_FLAG_AV_ADD(r, REG(rx), REG(ry)+c);
+ SET_FLAG_AC_ADD(r, REG(rx), REG(ry)+c);
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = Rx - Ry + CI - 1 */
+INLINE void compute_sub_ci(int rn, int rx, int ry)
+{
+ int c = (sharc.astat & AC) ? 1 : 0;
+ UINT32 r = REG(rx) - REG(ry) + c - 1;
+
+ if (sharc.mode1 & MODE1_ALUSAT)
+ fatalerror("SHARC: compute_sub_ci: ALU saturation not implemented !");
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ SET_FLAG_AV_SUB(r, REG(rx), REG(ry)+c-1);
+ SET_FLAG_AC_SUB(r, REG(rx), REG(ry)+c-1);
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = Rx AND Ry */
+INLINE void compute_and(int rn, int rx, int ry)
+{
+ UINT32 r = REG(rx) & REG(ry);
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* COMP(Rx, Ry) */
+INLINE void compute_comp(int rx, int ry)
+{
+ UINT32 comp_accum;
+
+ CLEAR_ALU_FLAGS();
+ if( REG(rx) == REG(ry) )
+ sharc.astat |= AZ;
+ if( (INT32)REG(rx) < (INT32)REG(ry) )
+ sharc.astat |= AN;
+
+ // Update ASTAT compare accumulation register
+ comp_accum = (sharc.astat >> 24) & 0xff;
+ comp_accum >>= 1;
+ if ((sharc.astat & (AZ|AN)) == 0)
+ {
+ comp_accum |= 0x80;
+ }
+ sharc.astat &= 0xffffff;
+ sharc.astat |= comp_accum << 24;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = PASS Rx */
+INLINE void compute_pass(int rn, int rx)
+{
+ CLEAR_ALU_FLAGS();
+ /* TODO: floating-point extension field is set to 0 */
+
+ REG(rn) = REG(rx);
+ if (REG(rn) == 0)
+ sharc.astat |= AZ;
+ if (REG(rn) & 0x80000000)
+ sharc.astat |= AN;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = Rx XOR Ry */
+INLINE void compute_xor(int rn, int rx, int ry)
+{
+ UINT32 r = REG(rx) ^ REG(ry);
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = Rx OR Ry */
+INLINE void compute_or(int rn, int rx, int ry)
+{
+ UINT32 r = REG(rx) | REG(ry);
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = Rx + 1 */
+INLINE void compute_inc(int rn, int rx)
+{
+ UINT32 r = REG(rx) + 1;
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ SET_FLAG_AV_ADD(r, REG(rx), 1);
+ SET_FLAG_AC_ADD(r, REG(rx), 1);
+
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = Rx - 1 */
+INLINE void compute_dec(int rn, int rx)
+{
+ UINT32 r = REG(rx) - 1;
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ SET_FLAG_AV_SUB(r, REG(rx), 1);
+ SET_FLAG_AC_SUB(r, REG(rx), 1);
+
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = MIN(Rx, Ry) */
+INLINE void compute_min(int rn, int rx, int ry)
+{
+ UINT32 r = MIN((INT32)REG(rx), (INT32)REG(ry));
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = MAX(Rx, Ry) */
+INLINE void compute_max(int rn, int rx, int ry)
+{
+ UINT32 r = MAX((INT32)REG(rx), (INT32)REG(ry));
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = -Rx */
+INLINE void compute_neg(int rn, int rx)
+{
+ UINT32 r = -(INT32)(REG(rx));
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ SET_FLAG_AV_SUB(r, 0, REG(rx));
+ SET_FLAG_AC_SUB(r, 0, REG(rx));
+
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rn = NOT Rx */
+INLINE void compute_not(int rn, int rx)
+{
+ UINT32 r = ~REG(rx);
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+
+ REG(rn) = r;
+
+ sharc.astat &= ~AF;
+}
+
+/*****************************************************************************/
+/* Floating-point ALU operations */
+
+INLINE UINT32 SCALB(SHARC_REG rx, int ry)
+{
+ UINT32 mantissa = rx.r & FLOAT_MANTISSA;
+ UINT32 sign = rx.r & FLOAT_SIGN;
+
+ int exponent = ((rx.r >> 23) & 0xff) - 127;
+ exponent += (INT32)(REG(ry));
+
+ if (exponent > 127)
+ {
+ // overflow
+ sharc.astat |= AV;
+ return sign | FLOAT_INFINITY;
+ }
+ else if (exponent < -126)
+ {
+ // denormal
+ sharc.astat |= AZ;
+ return sign;
+ }
+ else
+ {
+ return sign | (((exponent + 127) & 0xff) << 23) | mantissa;
+ }
+}
+
+/* Fn = FLOAT Rx */
+INLINE void compute_float(int rn, int rx)
+{
+ // verified
+ FREG(rn) = (float)(INT32)REG(rx);
+
+ CLEAR_ALU_FLAGS();
+ // AN
+ SET_FLAG_AN(REG(rn));
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(REG(rn)) || IS_FLOAT_ZERO(REG(rn))) ? AZ : 0;
+ // AUS
+ sharc.stky |= (IS_FLOAT_DENORMAL(REG(rn))) ? AUS : 0;
+ /* TODO: AV flag */
+
+ sharc.astat |= AF;
+}
+
+/* Rn = FIX Fx */
+INLINE void compute_fix(int rn, int rx)
+{
+ INT32 alu_i;
+ SHARC_REG r_alu;
+
+ r_alu.f = FREG(rx);
+ if (sharc.mode1 & MODE1_TRUNCATE)
+ {
+ alu_i = (INT32)(r_alu.f);
+ }
+ else
+ {
+ alu_i = (INT32)(r_alu.f < 0 ? (r_alu.f - 0.5f) : (r_alu.f + 0.5f));
+ }
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(alu_i);
+ // AZ
+ SET_FLAG_AZ(alu_i);
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0;
+ /* TODO: AV flag */
+
+ REG(rn) = alu_i;
+ sharc.astat |= AF;
+}
+
+/* Rn = FIX Fx BY Ry */
+INLINE void compute_fix_scaled(int rn, int rx, int ry)
+{
+ INT32 alu_i;
+ SHARC_REG r_alu;
+
+ r_alu.r = SCALB(sharc.r[rx], ry);
+ if (sharc.mode1 & MODE1_TRUNCATE)
+ {
+ alu_i = (INT32)(r_alu.f);
+ }
+ else
+ {
+ alu_i = (INT32)(r_alu.f < 0 ? (r_alu.f - 0.5f) : (r_alu.f + 0.5f));
+ }
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(alu_i);
+ // AZ
+ SET_FLAG_AZ(alu_i);
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0;
+ /* TODO: AV flag */
+
+ REG(rn) = alu_i;
+ sharc.astat |= AF;
+}
+
+/* Fn = FLOAT Rx BY Ry */
+INLINE void compute_float_scaled(int rn, int rx, int ry)
+{
+ SHARC_REG x;
+ x.f = (float)(INT32)(REG(rx));
+
+ // verified
+ CLEAR_ALU_FLAGS();
+
+ REG(rn) = SCALB(x, ry);
+
+ // AN
+ SET_FLAG_AN(REG(rn));
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(REG(rn)) || IS_FLOAT_ZERO(REG(rn))) ? AZ : 0;
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(REG(rn))) ? AUS : 0;
+
+ sharc.astat |= AF;
+}
+
+/* Rn = LOGB Fx */
+INLINE void compute_logb(int rn, int rx)
+{
+ // verified
+ UINT32 r = REG(rx);
+
+ CLEAR_ALU_FLAGS();
+
+ if (IS_FLOAT_INFINITY(REG(rx)))
+ {
+ REG(rn) = FLOAT_INFINITY;
+
+ sharc.astat |= AV;
+ }
+ else if (IS_FLOAT_ZERO(REG(rx)))
+ {
+ REG(rn) = FLOAT_SIGN | FLOAT_INFINITY;
+
+ sharc.astat |= AV;
+ }
+ else if (IS_FLOAT_NAN(REG(rx)))
+ {
+ REG(rn) = 0xffffffff;
+
+ sharc.astat |= AI;
+ sharc.stky |= AIS;
+ }
+ else
+ {
+ int exponent = (r >> 23) & 0xff;
+ exponent -= 127;
+
+ // AN
+ SET_FLAG_AN(exponent);
+ // AZ
+ SET_FLAG_AZ(exponent);
+
+ REG(rn) = exponent;
+ }
+ sharc.astat |= AF;
+}
+
+/* Fn = SCALB Fx BY Fy */
+INLINE void compute_scalb(int rn, int rx, int ry)
+{
+ // verified
+ SHARC_REG r;
+ CLEAR_ALU_FLAGS();
+
+ if (IS_FLOAT_NAN(REG(rx)))
+ {
+ sharc.astat |= AI;
+ sharc.stky |= AIS;
+
+ REG(rn) = 0xffffffff;
+ }
+ else
+ {
+ r.r = SCALB(sharc.r[rx], ry);
+
+ // AN
+ SET_FLAG_AN(r.r);
+ // AZ
+ sharc.astat |= IS_FLOAT_ZERO(r.r) ? AZ : 0;
+ // AUS
+ sharc.stky |= (IS_FLOAT_DENORMAL(r.r)) ? AUS : 0;
+
+ FREG(rn) = r.f;
+ }
+ sharc.astat |= AF;
+}
+
+/* Fn = Fx + Fy */
+INLINE void compute_fadd(int rn, int rx, int ry)
+{
+ SHARC_REG r;
+ r.f = FREG(rx) + FREG(ry);
+
+ CLEAR_ALU_FLAGS();
+ // AN
+ sharc.astat |= (r.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(r.r) || IS_FLOAT_ZERO(r.r)) ? AZ : 0;
+ // AUS
+ sharc.stky |= (IS_FLOAT_DENORMAL(r.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0;
+ /* TODO: AV flag */
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+
+ FREG(rn) = r.f;
+ sharc.astat |= AF;
+}
+
+/* Fn = Fx - Fy */
+INLINE void compute_fsub(int rn, int rx, int ry)
+{
+ SHARC_REG r;
+ r.f = FREG(rx) - FREG(ry);
+
+ CLEAR_ALU_FLAGS();
+ // AN
+ sharc.astat |= (r.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(r.r) || IS_FLOAT_ZERO(r.r)) ? AZ : 0;
+ // AUS
+ sharc.stky |= (IS_FLOAT_DENORMAL(r.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0;
+ /* TODO: AV flag */
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+
+ FREG(rn) = r.f;
+ sharc.astat |= AF;
+}
+
+/* Fn = -Fx */
+INLINE void compute_fneg(int rn, int rx)
+{
+ SHARC_REG r;
+ r.f = -FREG(rx);
+
+ CLEAR_ALU_FLAGS();
+ // AZ
+ sharc.astat |= (IS_FLOAT_ZERO(r.r)) ? AZ : 0;
+ // AN
+ sharc.astat |= (r.f < 0.0f) ? AN : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0;
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+
+ FREG(rn) = r.f;
+ sharc.astat |= AF;
+}
+
+/* COMP(Fx, Fy) */
+INLINE void compute_fcomp(int rx, int ry)
+{
+ UINT32 comp_accum;
+
+ CLEAR_ALU_FLAGS();
+ // AZ
+ if( FREG(rx) == FREG(ry) )
+ sharc.astat |= AZ;
+ // AN
+ if( FREG(rx) < FREG(ry) )
+ sharc.astat |= AN;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0;
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+
+ // Update ASTAT compare accumulation register
+ comp_accum = (sharc.astat >> 24) & 0xff;
+ comp_accum >>= 1;
+ if ((sharc.astat & (AZ|AN)) == 0)
+ {
+ comp_accum |= 0x80;
+ }
+ sharc.astat &= 0xffffff;
+ sharc.astat |= comp_accum << 24;
+ sharc.astat |= AF;
+}
+
+/* Fn = ABS(Fx + Fy) */
+INLINE void compute_fabs_plus(int rn, int rx, int ry)
+{
+ SHARC_REG r;
+ r.f = fabs(FREG(rx) + FREG(ry));
+
+ CLEAR_ALU_FLAGS();
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(r.r) || IS_FLOAT_ZERO(r.r)) ? AZ : 0;
+ // AUS
+ sharc.stky |= (IS_FLOAT_DENORMAL(r.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0;
+ /* TODO: AV flag */
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+
+ FREG(rn) = r.f;
+ sharc.astat |= AF;
+}
+
+/* Fn = MAX(Fx, Fy) */
+INLINE void compute_fmax(int rn, int rx, int ry)
+{
+ SHARC_REG r_alu;
+
+ r_alu.f = MAX(FREG(rx), FREG(ry));
+
+ CLEAR_ALU_FLAGS();
+ sharc.astat |= (r_alu.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0;
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0;
+ /* TODO: AV flag */
+
+ FREG(rn) = r_alu.f;
+ sharc.astat |= AF;
+}
+
+/* Fn = MIN(Fx, Fy) */
+INLINE void compute_fmin(int rn, int rx, int ry)
+{
+ SHARC_REG r_alu;
+
+ r_alu.f = MIN(FREG(rx), FREG(ry));
+
+ CLEAR_ALU_FLAGS();
+ sharc.astat |= (r_alu.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0;
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0;
+ /* TODO: AV flag */
+
+ FREG(rn) = r_alu.f;
+ sharc.astat |= AF;
+}
+
+/* Fn = CLIP Fx BY Fy */
+INLINE void compute_fclip(int rn, int rx, int ry)
+{
+ SHARC_REG r_alu;
+
+ if (FREG(rx) < fabs(FREG(ry)))
+ {
+ r_alu.f = FREG(rx);
+ }
+ else
+ {
+ if (FREG(rx) >= 0.0f)
+ {
+ r_alu.f = fabs(FREG(ry));
+ }
+ else
+ {
+ r_alu.f = -fabs(FREG(ry));
+ }
+ }
+
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r_alu.r);
+ // AZ
+ sharc.astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0;
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0;
+
+ FREG(rn) = r_alu.f;
+ sharc.astat |= AF;
+}
+
+/* Fn = RECIPS Fx */
+INLINE void compute_recips(int rn, int rx)
+{
+ // verified
+ UINT32 r;
+
+ CLEAR_ALU_FLAGS();
+
+ if (IS_FLOAT_NAN(REG(rx)))
+ {
+ // NaN
+ r = 0xffffffff;
+
+ // AI
+ sharc.astat |= AI;
+
+ // AIS
+ sharc.stky |= AIS;
+ }
+ else if (IS_FLOAT_ZERO(REG(rx)))
+ {
+ // +- Zero
+ r = (REG(rx) & FLOAT_SIGN) | FLOAT_INFINITY;
+
+ sharc.astat |= AZ;
+ }
+ else
+ {
+ UINT32 mantissa = REG(rx) & 0x7fffff;
+ UINT32 exponent = (REG(rx) >> 23) & 0xff;
+ UINT32 sign = REG(rx) & FLOAT_SIGN;
+
+ UINT32 res_mantissa = recips_mantissa_lookup[mantissa >> 16];
+
+ int res_exponent = -(exponent - 127) - 1;
+ if (res_exponent > 125 || res_exponent < -126)
+ {
+ res_exponent = 0;
+ res_mantissa = 0;
+ }
+ else
+ {
+ res_exponent = (res_exponent + 127) & 0xff;
+ }
+
+ r = sign | (res_exponent << 23) | res_mantissa;
+
+ SET_FLAG_AN(REG(rx));
+ // AZ & AV
+ sharc.astat |= (IS_FLOAT_ZERO(r)) ? AZ : 0;
+ sharc.astat |= (IS_FLOAT_ZERO(REG(rx))) ? AV : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0;
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+ }
+
+ // AF
+ sharc.astat |= AF;
+
+ REG(rn) = r;
+}
+
+/* Fn = RSQRTS Fx */
+INLINE void compute_rsqrts(int rn, int rx)
+{
+ // verified
+ UINT32 r;
+
+ if ((UINT32)(REG(rx)) > 0x80000000)
+ {
+ // non-zero negative
+ r = 0xffffffff;
+ }
+ else if (IS_FLOAT_NAN(REG(rx)))
+ {
+ // NaN
+ r = 0xffffffff;
+ }
+ else
+ {
+ UINT32 mantissa = REG(rx) & 0xffffff; // mantissa + LSB of biased exponent
+ UINT32 exponent = (REG(rx) >> 23) & 0xff;
+ UINT32 sign = REG(rx) & FLOAT_SIGN;
+
+ UINT32 res_mantissa = rsqrts_mantissa_lookup[mantissa >> 17];
+
+ int res_exponent = -((exponent - 127) / 2) - 1;
+ res_exponent = (res_exponent + 127) & 0xff;
+
+ r = sign | (res_exponent << 23) | res_mantissa;
+ }
+
+ CLEAR_ALU_FLAGS();
+ // AN
+ sharc.astat |= (REG(rx) == 0x80000000) ? AN : 0;
+ // AZ & AV
+ sharc.astat |= (IS_FLOAT_ZERO(r)) ? AZ : 0;
+ sharc.astat |= (IS_FLOAT_ZERO(REG(rx))) ? AV : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx)) || (REG(rx) & 0x80000000)) ? AI : 0;
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+ // AF
+ sharc.astat |= AF;
+
+ REG(rn) = r;
+}
+
+
+/* Fn = PASS Fx */
+INLINE void compute_fpass(int rn, int rx)
+{
+ SHARC_REG r;
+ r.f = FREG(rx);
+
+ CLEAR_ALU_FLAGS();
+ // AN
+ sharc.astat |= (r.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_ZERO(r.r)) ? AZ : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0;
+
+ FREG(rn) = r.f;
+ sharc.astat |= AF;
+}
+
+/* Fn = ABS Fx */
+INLINE void compute_fabs(int rn, int rx)
+{
+ SHARC_REG r;
+ r.f = fabs(FREG(rx));
+
+ CLEAR_ALU_FLAGS();
+ // AN
+ sharc.astat |= (r.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_ZERO(r.r)) ? AZ : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0;
+
+ FREG(rn) = r.f;
+ sharc.astat |= AF;
+}
+
+/*****************************************************************************/
+/* Multiplier opcodes */
+
+/* Rn = (unsigned)Rx * (unsigned)Ry, integer, no rounding */
+INLINE void compute_mul_uuin(int rn, int rx, int ry)
+{
+ UINT64 r = (UINT64)(UINT32)REG(rx) * (UINT64)(UINT32)REG(ry);
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN((UINT32)r);
+ SET_FLAG_MV(r);
+ SET_FLAG_MU(r);
+
+ REG(rn) = (UINT32)(r);
+}
+
+/* Rn = (signed)Rx * (signed)Ry, integer, no rounding */
+INLINE void compute_mul_ssin(int rn, int rx, int ry)
+{
+ UINT64 r = (INT64)(INT32)REG(rx) * (INT64)(INT32)REG(ry);
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN((UINT32)r);
+ SET_FLAG_MV(r);
+ SET_FLAG_MU(r);
+
+ REG(rn) = (UINT32)(r);
+}
+
+/* MRF + (signed)Rx * (signed)Ry, integer, no rounding */
+INLINE UINT32 compute_mrf_plus_mul_ssin(int rx, int ry)
+{
+ UINT64 r = sharc.mrf + ((INT64)(INT32)REG(rx) * (INT64)(INT32)REG(ry));
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN((UINT32)r);
+ SET_FLAG_MV(r);
+ SET_FLAG_MU(r);
+
+ return (UINT32)(r);
+}
+
+/* MRB + (signed)Rx * (signed)Ry, integer, no rounding */
+INLINE UINT32 compute_mrb_plus_mul_ssin(int rx, int ry)
+{
+ INT64 r = sharc.mrb + ((INT64)(INT32)REG(rx) * (INT64)(INT32)REG(ry));
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN((UINT32)r);
+ SET_FLAG_MV(r);
+ SET_FLAG_MU(r);
+
+ return (UINT32)(r);
+}
+
+/* Fn = Fx * Fy */
+INLINE void compute_fmul(int rn, int rx, int ry)
+{
+ FREG(rn) = FREG(rx) * FREG(ry);
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(REG(rn));
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+}
+
+/*****************************************************************************/
+
+/* multi function opcodes */
+
+/* integer*/
+INLINE void compute_multi_mr_to_reg(int ai, int rk)
+{
+ switch(ai)
+ {
+ case 0: SET_UREG(rk, (UINT32)(sharc.mrf)); break;
+ case 1: SET_UREG(rk, (UINT32)(sharc.mrf >> 32)); break;
+ case 2: fatalerror("SHARC: tried to load MR2F"); break;
+ case 4: SET_UREG(rk, (UINT32)(sharc.mrb)); break;
+ case 5: SET_UREG(rk, (UINT32)(sharc.mrb >> 32)); break;
+ case 6: fatalerror("SHARC: tried to load MR2B"); break;
+ default: fatalerror("SHARC: unknown ai %d in mr_to_reg", ai);
+ }
+
+ CLEAR_MULTIPLIER_FLAGS();
+}
+
+INLINE void compute_multi_reg_to_mr(int ai, int rk)
+{
+ switch(ai)
+ {
+ case 0: sharc.mrf &= ~0xffffffff; sharc.mrf |= GET_UREG(rk); break;
+ case 1: sharc.mrf &= 0xffffffff; sharc.mrf |= (UINT64)(GET_UREG(rk)) << 32; break;
+ case 2: fatalerror("SHARC: tried to write MR2F"); break;
+ case 4: sharc.mrb &= ~0xffffffff; sharc.mrb |= GET_UREG(rk); break;
+ case 5: sharc.mrb &= 0xffffffff; sharc.mrb |= (UINT64)(GET_UREG(rk)) << 32; break;
+ case 6: fatalerror("SHARC: tried to write MR2B"); break;
+ default: fatalerror("SHARC: unknown ai %d in reg_to_mr", ai);
+ }
+
+ CLEAR_MULTIPLIER_FLAGS();
+}
+
+/* Ra = Rx + Ry, Rs = Rx - Ry */
+INLINE void compute_dual_add_sub(int ra, int rs, int rx, int ry)
+{
+ UINT32 r_add = REG(rx) + REG(ry);
+ UINT32 r_sub = REG(rx) - REG(ry);
+
+ CLEAR_ALU_FLAGS();
+ if (r_add == 0 || r_sub == 0)
+ {
+ sharc.astat |= AZ;
+ }
+ if (r_add & 0x80000000 || r_sub & 0x80000000)
+ {
+ sharc.astat |= AN;
+ }
+ if (((~(REG(rx) ^ REG(ry)) & (REG(rx) ^ r_add)) & 0x80000000) ||
+ (( (REG(rx) ^ REG(ry)) & (REG(rx) ^ r_sub)) & 0x80000000))
+ {
+ sharc.astat |= AV;
+ }
+ if (((UINT32)r_add < (UINT32)REG(rx)) ||
+ (!((UINT32)r_sub < (UINT32)REG(rx))))
+ {
+ sharc.astat |= AC;
+ }
+
+ REG(ra) = r_add;
+ REG(rs) = r_sub;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rm = (signed)Rxm * (signed)Rym, fractional, rounding, Ra = Rxa + Rya */
+INLINE void compute_mul_ssfr_add(int rm, int rxm, int rym, int ra, int rxa, int rya)
+{
+ UINT32 r_mul = (UINT32)(((INT64)(REG(rxm)) * (INT64)(REG(rym))) >> 31);
+ UINT32 r_add = REG(rxa) + REG(rya);
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(r_mul);
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r_add);
+ SET_FLAG_AZ(r_add);
+ SET_FLAG_AV_ADD(r_add, REG(rxa), REG(rya));
+ SET_FLAG_AC_ADD(r_add, REG(rxa), REG(rya));
+
+
+ REG(rm) = r_mul;
+ REG(ra) = r_add;
+
+ sharc.astat &= ~AF;
+}
+
+/* Rm = (signed)Rxm * (signed)Rym, fractional, rounding, Ra = Rxa - Rya */
+INLINE void compute_mul_ssfr_sub(int rm, int rxm, int rym, int ra, int rxa, int rya)
+{
+ UINT32 r_mul = (UINT32)(((INT64)(REG(rxm)) * (INT64)(REG(rym))) >> 31);
+ UINT32 r_sub = REG(rxa) - REG(rya);
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(r_mul);
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r_sub);
+ SET_FLAG_AZ(r_sub);
+ SET_FLAG_AV_SUB(r_sub, REG(rxa), REG(rya));
+ SET_FLAG_AC_SUB(r_sub, REG(rxa), REG(rya));
+
+
+ REG(rm) = r_mul;
+ REG(ra) = r_sub;
+
+ sharc.astat &= ~AF;
+}
+
+
+/* floating-point */
+
+/* Fa = Fx + Fy, Fs = Fx - Fy */
+INLINE void compute_dual_fadd_fsub(int ra, int rs, int rx, int ry)
+{
+ SHARC_REG r_add, r_sub;
+ r_add.f = FREG(rx) + FREG(ry);
+ r_sub.f = FREG(rx) - FREG(ry);
+
+ CLEAR_ALU_FLAGS();
+ // AN
+ sharc.astat |= ((r_add.f < 0.0f) || (r_sub.f < 0.0f)) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_ZERO(r_add.r) ||
+ IS_FLOAT_DENORMAL(r_sub.r) || IS_FLOAT_ZERO(r_sub.r)) ? AZ : 0;
+ // AUS
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_DENORMAL(r_sub.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0;
+ /* TODO: AV flag */
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+
+ FREG(ra) = r_add.f;
+ FREG(rs) = r_sub.f;
+ sharc.astat |= AF;
+}
+
+/* Fm = Fxm * Fym, Fa = Fxa + Fya */
+INLINE void compute_fmul_fadd(int fm, int fxm, int fym, int fa, int fxa, int fya)
+{
+ SHARC_REG r_mul, r_add;
+ r_mul.f = FREG(fxm) * FREG(fym);
+ r_add.f = FREG(fxa) + FREG(fya);
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(r_mul.r);
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+
+ CLEAR_ALU_FLAGS();
+ sharc.astat |= (r_add.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_ZERO(r_add.r)) ? AZ : 0;
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_add.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0;
+ /* TODO: AV flag */
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+
+ FREG(fm) = r_mul.f;
+ FREG(fa) = r_add.f;
+ sharc.astat |= AF;
+}
+
+/* Fm = Fxm * Fym, Fa = Fxa - Fya */
+INLINE void compute_fmul_fsub(int fm, int fxm, int fym, int fa, int fxa, int fya)
+{
+ SHARC_REG r_mul, r_sub;
+ r_mul.f = FREG(fxm) * FREG(fym);
+ r_sub.f = FREG(fxa) - FREG(fya);
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(r_mul.r);
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+
+ CLEAR_ALU_FLAGS();
+ sharc.astat |= (r_sub.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(r_sub.r) || IS_FLOAT_ZERO(r_sub.r)) ? AZ : 0;
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_sub.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0;
+ /* TODO: AV flag */
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+
+ FREG(fm) = r_mul.f;
+ FREG(fa) = r_sub.f;
+ sharc.astat |= AF;
+}
+
+/* Fm = Fxm * Fym, Fa = FLOAT Fxa BY Fya */
+INLINE void compute_fmul_float_scaled(int fm, int fxm, int fym, int fa, int fxa, int fya)
+{
+ SHARC_REG x;
+ SHARC_REG r_mul, r_alu;
+ r_mul.f = FREG(fxm) * FREG(fym);
+
+ x.f = (float)(INT32)REG(fxa);
+
+ r_alu.r = SCALB(x, fya);
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(r_mul.r);
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+
+ CLEAR_ALU_FLAGS();
+ sharc.astat |= (r_alu.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(r_alu.r) || IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0;
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0;
+ /* TODO: set AV if overflowed */
+
+ FREG(fm) = r_mul.f;
+ FREG(fa) = r_alu.f;
+ sharc.astat |= AF;
+}
+
+/* Fm = Fxm * Fym, Fa = FIX Fxa BY Fya */
+INLINE void compute_fmul_fix_scaled(int fm, int fxm, int fym, int fa, int fxa, int fya)
+{
+ INT32 alu_i;
+ SHARC_REG r_mul, r_alu;
+ r_mul.f = FREG(fxm) * FREG(fym);
+
+ r_alu.r = SCALB(sharc.r[fxa], fya);
+
+ if (sharc.mode1 & MODE1_TRUNCATE)
+ {
+ alu_i = (INT32)(r_alu.f);
+ }
+ else
+ {
+ alu_i = (INT32)(r_alu.f < 0 ? (r_alu.f - 0.5f) : (r_alu.f + 0.5f));
+ }
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(r_mul.r);
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(alu_i);
+ // AZ
+ SET_FLAG_AZ(alu_i);
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(fxa))) ? AI : 0;
+ /* TODO: AV flag */
+
+ FREG(fm) = r_mul.f;
+ REG(fa) = alu_i;
+ sharc.astat |= AF;
+}
+
+
+/* Fm = Fxm * Fym, Fa = MAX(Fxa, Fya) */
+INLINE void compute_fmul_fmax(int fm, int fxm, int fym, int fa, int fxa, int fya)
+{
+ SHARC_REG r_mul, r_alu;
+ r_mul.f = FREG(fxm) * FREG(fym);
+
+ r_alu.f = MAX(FREG(fxa), FREG(fya));
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(r_mul.r);
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+
+ CLEAR_ALU_FLAGS();
+ sharc.astat |= (r_alu.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0;
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0;
+ /* TODO: AV flag */
+
+ FREG(fm) = r_mul.f;
+ FREG(fa) = r_alu.f;
+ sharc.astat |= AF;
+}
+
+
+/* Fm = Fxm * Fym, Fa = MIN(Fxa, Fya) */
+INLINE void compute_fmul_fmin(int fm, int fxm, int fym, int fa, int fxa, int fya)
+{
+ SHARC_REG r_mul, r_alu;
+ r_mul.f = FREG(fxm) * FREG(fym);
+
+ r_alu.f = MIN(FREG(fxa), FREG(fya));
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(r_mul.r);
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+
+ CLEAR_ALU_FLAGS();
+ sharc.astat |= (r_alu.f < 0.0f) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0;
+ // AU
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0;
+ /* TODO: AV flag */
+
+ FREG(fm) = r_mul.f;
+ FREG(fa) = r_alu.f;
+ sharc.astat |= AF;
+}
+
+
+
+/* Fm = Fxm * Fym, Fa = Fxa + Fya, Fs = Fxa - Fya */
+INLINE void compute_fmul_dual_fadd_fsub(int fm, int fxm, int fym, int fa, int fs, int fxa, int fya)
+{
+ SHARC_REG r_mul, r_add, r_sub;
+ r_mul.f = FREG(fxm) * FREG(fym);
+ r_add.f = FREG(fxa) + FREG(fya);
+ r_sub.f = FREG(fxa) - FREG(fya);
+
+ CLEAR_MULTIPLIER_FLAGS();
+ SET_FLAG_MN(r_mul.r);
+ /* TODO: MV flag */
+ /* TODO: MU flag */
+ /* TODO: MI flag */
+
+ CLEAR_ALU_FLAGS();
+ // AN
+ sharc.astat |= ((r_add.r < 0.0f) || (r_sub.r < 0.0f)) ? AN : 0;
+ // AZ
+ sharc.astat |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_ZERO(r_add.r) ||
+ IS_FLOAT_DENORMAL(r_sub.r) || IS_FLOAT_ZERO(r_sub.r)) ? AZ : 0;
+ // AUS
+ sharc.stky |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_DENORMAL(r_sub.r)) ? AUS : 0;
+ // AI
+ sharc.astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0;
+ /* TODO: AV flag */
+
+ // AIS
+ if (sharc.astat & AI) sharc.stky |= AIS;
+
+ FREG(fm) = r_mul.f;
+ FREG(fa) = r_add.f;
+ FREG(fs) = r_sub.f;
+ sharc.astat |= AF;
+}
diff --git a/src/emu/cpu/sharc/sharc.c b/src/emu/cpu/sharc/sharc.c
new file mode 100644
index 00000000000..fea1374e454
--- /dev/null
+++ b/src/emu/cpu/sharc/sharc.c
@@ -0,0 +1,1229 @@
+/* Analog Devices ADSP-2106x SHARC emulator v2.0
+
+ Written by Ville Linde
+*/
+
+#include "sharc.h"
+#include "debugger.h"
+
+#ifdef MAME_DEBUG
+static offs_t sharc_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+static void sharc_dma_exec(int channel);
+static void check_interrupts(void);
+
+enum
+{
+ SHARC_PC=1, SHARC_PCSTK, SHARC_MODE1, SHARC_MODE2,
+ SHARC_ASTAT, SHARC_STKY, SHARC_IRPTL, SHARC_IMASK,
+ SHARC_IMASKP, SHARC_USTAT1, SHARC_USTAT2, SHARC_LCNTR,
+ SHARC_R0, SHARC_R1, SHARC_R2, SHARC_R3,
+ SHARC_R4, SHARC_R5, SHARC_R6, SHARC_R7,
+ SHARC_R8, SHARC_R9, SHARC_R10, SHARC_R11,
+ SHARC_R12, SHARC_R13, SHARC_R14, SHARC_R15,
+ SHARC_SYSCON, SHARC_SYSSTAT, SHARC_MRF, SHARC_MRB,
+ SHARC_STSTKP, SHARC_PCSTKP, SHARC_LSTKP,
+ SHARC_FADDR, SHARC_DADDR,
+ SHARC_I0, SHARC_I1, SHARC_I2, SHARC_I3,
+ SHARC_I4, SHARC_I5, SHARC_I6, SHARC_I7,
+ SHARC_I8, SHARC_I9, SHARC_I10, SHARC_I11,
+ SHARC_I12, SHARC_I13, SHARC_I14, SHARC_I15,
+ SHARC_M0, SHARC_M1, SHARC_M2, SHARC_M3,
+ SHARC_M4, SHARC_M5, SHARC_M6, SHARC_M7,
+ SHARC_M8, SHARC_M9, SHARC_M10, SHARC_M11,
+ SHARC_M12, SHARC_M13, SHARC_M14, SHARC_M15,
+ SHARC_L0, SHARC_L1, SHARC_L2, SHARC_L3,
+ SHARC_L4, SHARC_L5, SHARC_L6, SHARC_L7,
+ SHARC_L8, SHARC_L9, SHARC_L10, SHARC_L11,
+ SHARC_L12, SHARC_L13, SHARC_L14, SHARC_L15,
+ SHARC_B0, SHARC_B1, SHARC_B2, SHARC_B3,
+ SHARC_B4, SHARC_B5, SHARC_B6, SHARC_B7,
+ SHARC_B8, SHARC_B9, SHARC_B10, SHARC_B11,
+ SHARC_B12, SHARC_B13, SHARC_B14, SHARC_B15,
+};
+
+typedef struct
+{
+ UINT32 i[8];
+ UINT32 m[8];
+ UINT32 b[8];
+ UINT32 l[8];
+} SHARC_DAG;
+
+typedef union
+{
+ INT32 r;
+ float f;
+} SHARC_REG;
+
+typedef struct
+{
+ UINT32 control;
+ UINT32 int_index;
+ UINT32 int_modifier;
+ UINT32 int_count;
+ UINT32 chain_ptr;
+ UINT32 gen_purpose;
+ UINT32 ext_index;
+ UINT32 ext_modifier;
+ UINT32 ext_count;
+} DMA_REGS;
+
+typedef struct
+{
+ UINT32 pc;
+ SHARC_REG r[16];
+ SHARC_REG reg_alt[16];
+ UINT64 mrf;
+ UINT64 mrb;
+
+ UINT32 pcstack[32];
+ UINT32 lcstack[6];
+ UINT32 lastack[6];
+ UINT32 lstkp;
+
+ UINT32 faddr;
+ UINT32 daddr;
+ UINT32 pcstk;
+ UINT32 pcstkp;
+ UINT32 laddr;
+ UINT32 curlcntr;
+ UINT32 lcntr;
+
+ /* Data Address Generator (DAG) */
+ SHARC_DAG dag1; // (DM bus)
+ SHARC_DAG dag2; // (PM bus)
+ SHARC_DAG dag1_alt;
+ SHARC_DAG dag2_alt;
+
+ DMA_REGS dma[12];
+
+ /* System registers */
+ UINT32 mode1;
+ UINT32 mode2;
+ UINT32 astat;
+ UINT32 stky;
+ UINT32 irptl;
+ UINT32 imask;
+ UINT32 imaskp;
+ UINT32 ustat1;
+ UINT32 ustat2;
+
+ UINT32 flag[4];
+
+ UINT32 syscon;
+ UINT32 sysstat;
+
+ struct
+ {
+ UINT32 mode1;
+ UINT32 astat;
+ } status_stack[5];
+ int status_stkp;
+
+ UINT64 px;
+
+ UINT16 *internal_ram;
+ UINT16 *internal_ram_block0, *internal_ram_block1;
+ int internal_ram_size;
+
+ int (*irq_callback)(int irqline);
+ void (*opcode_handler)(void);
+ UINT64 opcode;
+ UINT64 fetch_opcode;
+ UINT64 decode_opcode;
+
+ UINT32 nfaddr;
+
+ int idle;
+ int irq_active;
+ int active_irq_num;
+
+ SHARC_BOOT_MODE boot_mode;
+
+ UINT32 dmaop_src;
+ UINT32 dmaop_dst;
+ UINT32 dmaop_chain_ptr;
+ int dmaop_src_modifier;
+ int dmaop_dst_modifier;
+ int dmaop_src_count;
+ int dmaop_dst_count;
+ int dmaop_pmode;
+ int dmaop_cycles;
+ int dmaop_channel;
+ int dmaop_chained_direction;
+
+ int interrupt_active;
+
+ int iop_latency_cycles;
+ int iop_latency_reg;
+ UINT32 iop_latency_data;
+
+ UINT32 delay_slot1, delay_slot2;
+
+ int systemreg_latency_cycles;
+ int systemreg_latency_reg;
+ UINT32 systemreg_latency_data;
+ UINT32 systemreg_previous_data;
+
+ UINT32 astat_old;
+ UINT32 astat_old_old;
+ UINT32 astat_old_old_old;
+} SHARC_REGS;
+
+
+static SHARC_REGS sharc;
+static int sharc_icount;
+
+static void (* sharc_op[512])(void);
+
+
+
+#define ROPCODE(pc) ((UINT64)(sharc.internal_ram[((pc-0x20000) * 3) + 0]) << 32) | \
+ ((UINT64)(sharc.internal_ram[((pc-0x20000) * 3) + 1]) << 16) | \
+ ((UINT64)(sharc.internal_ram[((pc-0x20000) * 3) + 2]) << 0)
+
+INLINE void CHANGE_PC(UINT32 newpc)
+{
+ sharc.pc = newpc;
+ sharc.daddr = newpc;
+ sharc.faddr = newpc+1;
+ sharc.nfaddr = newpc+2;
+
+ // next instruction to be executed
+ sharc.decode_opcode = ROPCODE(sharc.daddr);
+ // next instruction to be decoded
+ sharc.fetch_opcode = ROPCODE(sharc.faddr);
+}
+
+INLINE void CHANGE_PC_DELAYED(UINT32 newpc)
+{
+ sharc.nfaddr = newpc;
+
+ sharc.delay_slot1 = sharc.pc;
+ sharc.delay_slot2 = sharc.daddr;
+}
+
+
+
+static void add_iop_write_latency_effect(int iop_reg, UINT32 data, int latency)
+{
+ sharc.iop_latency_cycles = latency+1;
+ sharc.iop_latency_reg = iop_reg;
+ sharc.iop_latency_data = data;
+}
+
+static void iop_write_latency_effect(void)
+{
+ UINT32 data = sharc.iop_latency_data;
+
+ switch (sharc.iop_latency_reg)
+ {
+ case 0x1c:
+ {
+ if (data & 0x1)
+ {
+ sharc_dma_exec(6);
+ }
+ break;
+ }
+
+ case 0x1d:
+ {
+ if (data & 0x1)
+ {
+ sharc_dma_exec(7);
+ }
+ break;
+ }
+
+ default: fatalerror("SHARC: iop_write_latency_effect: unknown IOP register %02X", sharc.iop_latency_reg);
+ }
+}
+
+
+
+/* IOP registers */
+static UINT32 sharc_iop_r(UINT32 address)
+{
+ switch (address)
+ {
+ case 0x00: return 0; // System configuration
+
+ case 0x37: // DMA status
+ {
+ UINT32 r = 0;
+ if (sharc.dmaop_cycles > 0)
+ {
+ r |= 1 << sharc.dmaop_channel;
+ }
+ return r;
+ }
+ default: fatalerror("sharc_iop_r: Unimplemented IOP reg %02X at %08X", address, sharc.pc);
+ }
+ return 0;
+}
+
+static void sharc_iop_w(UINT32 address, UINT32 data)
+{
+ switch (address)
+ {
+ case 0x00: break; // System configuration
+ case 0x02: break; // External Memory Wait State Configuration
+
+ case 0x08: break; // Message Register 0
+ case 0x09: break; // Message Register 1
+ case 0x0a: break; // Message Register 2
+ case 0x0b: break; // Message Register 3
+ case 0x0c: break; // Message Register 4
+ case 0x0d: break; // Message Register 5
+ case 0x0e: break; // Message Register 6
+ case 0x0f: break; // Message Register 7
+
+ // DMA 6
+ case 0x1c:
+ {
+ sharc.dma[6].control = data;
+ add_iop_write_latency_effect(0x1c, data, 1);
+ break;
+ }
+
+ case 0x20: break;
+
+ case 0x40: sharc.dma[6].int_index = data; return;
+ case 0x41: sharc.dma[6].int_modifier = data; return;
+ case 0x42: sharc.dma[6].int_count = data; return;
+ case 0x43: sharc.dma[6].chain_ptr = data; return;
+ case 0x44: sharc.dma[6].gen_purpose = data; return;
+ case 0x45: sharc.dma[6].ext_index = data; return;
+ case 0x46: sharc.dma[6].ext_modifier = data; return;
+ case 0x47: sharc.dma[6].ext_count = data; return;
+
+ // DMA 7
+ case 0x1d:
+ {
+ sharc.dma[7].control = data;
+ add_iop_write_latency_effect(0x1d, data, 30);
+ break;
+ }
+
+ case 0x48: sharc.dma[7].int_index = data; return;
+ case 0x49: sharc.dma[7].int_modifier = data; return;
+ case 0x4a: sharc.dma[7].int_count = data; return;
+ case 0x4b: sharc.dma[7].chain_ptr = data; return;
+ case 0x4c: sharc.dma[7].gen_purpose = data; return;
+ case 0x4d: sharc.dma[7].ext_index = data; return;
+ case 0x4e: sharc.dma[7].ext_modifier = data; return;
+ case 0x4f: sharc.dma[7].ext_count = data; return;
+
+ default: fatalerror("sharc_iop_w: Unimplemented IOP reg %02X, %08X at %08X", address, data, sharc.pc);
+ }
+}
+
+
+#include "sharcmem.c"
+#include "sharcdma.c"
+#include "sharcops.c"
+#include "sharcops.h"
+
+
+
+static void build_opcode_table(void)
+{
+ int i, j;
+ int num_ops = sizeof(sharc_opcode_table) / sizeof(SHARC_OP);
+
+ for (i=0; i < 512; i++)
+ {
+ sharc_op[i] = sharcop_unimplemented;
+ }
+
+ for (i=0; i < 512; i++)
+ {
+ UINT16 op = i << 7;
+
+ for (j=0; j < num_ops; j++)
+ {
+ if ((sharc_opcode_table[j].op_mask & op) == sharc_opcode_table[j].op_bits)
+ {
+ if (sharc_op[i] != sharcop_unimplemented)
+ {
+ fatalerror("build_opcode_table: table already filled! (i=%04X, j=%d)\n", i, j);
+ }
+ else
+ {
+ sharc_op[i] = sharc_opcode_table[j].handler;
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+void sharc_external_iop_write(UINT32 address, UINT32 data)
+{
+ if (address == 0x1c)
+ {
+ if (data != 0)
+ {
+ sharc.dma[6].control = data;
+ }
+ }
+ else
+ {
+ mame_printf_debug("SHARC IOP write %08X, %08X\n", address, data);
+ sharc_iop_w(address, data);
+ }
+}
+
+void sharc_external_dma_write(UINT32 address, UINT64 data)
+{
+ switch ((sharc.dma[6].control >> 6) & 0x3)
+ {
+ case 2: // 16/48 packing
+ {
+ int shift = address % 3;
+ UINT64 r = pm_read48(sharc.dma[6].int_index);
+
+ r &= ~((UINT64)(0xffff) << (shift*16));
+ r |= (data & 0xffff) << (shift*16);
+
+ pm_write48(sharc.dma[6].int_index, r);
+
+ if (shift == 2)
+ {
+
+ sharc.dma[6].int_index += sharc.dma[6].int_modifier;
+ }
+ break;
+ }
+ default:
+ {
+ fatalerror("sharc_external_dma_write: unimplemented packing mode %d\n", (sharc.dma[6].control >> 6) & 0x3);
+ }
+ }
+}
+
+#ifdef MAME_DEBUG
+static offs_t sharc_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT64 op = 0;
+ UINT32 flags = 0;
+
+ op = ((UINT64)oprom[0] << 0) | ((UINT64)oprom[1] << 8) |
+ ((UINT64)oprom[2] << 16) | ((UINT64)oprom[3] << 24) |
+ ((UINT64)oprom[4] << 32) | ((UINT64)oprom[5] << 40);
+
+ flags = sharc_dasm_one(buffer, pc, op);
+ return 1 | flags | DASMFLAG_SUPPORTED;
+}
+#endif /* MAME_DEBUG */
+
+
+static void sharc_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ const sharc_config *cfg = config;
+ sharc.boot_mode = cfg->boot_mode;
+
+ sharc.irq_callback = irqcallback;
+
+ build_opcode_table();
+
+ sharc.internal_ram = auto_malloc(2 * 0x10000 * sizeof(UINT16)); // 2x 128KB
+ sharc.internal_ram_block0 = &sharc.internal_ram[0];
+ sharc.internal_ram_block1 = &sharc.internal_ram[0x20000/2];
+}
+
+static void sharc_reset(void)
+{
+ memset(sharc.internal_ram, 0, 2 * 0x10000 * sizeof(UINT16));
+
+ switch(sharc.boot_mode)
+ {
+ case BOOT_MODE_EPROM:
+ {
+ sharc.dma[6].int_index = 0x20000;
+ sharc.dma[6].int_modifier = 1;
+ sharc.dma[6].int_count = 0x100;
+ sharc.dma[6].ext_index = 0x400000;
+ sharc.dma[6].ext_modifier = 1;
+ sharc.dma[6].ext_count = 0x600;
+ sharc.dma[6].control = 0x2a1;
+
+ sharc_dma_exec(6);
+ dma_op(sharc.dmaop_src, sharc.dmaop_dst, sharc.dmaop_src_modifier, sharc.dmaop_dst_modifier,
+ sharc.dmaop_src_count, sharc.dmaop_dst_count, sharc.dmaop_pmode);
+ sharc.dmaop_cycles = 0;
+
+ break;
+ }
+
+ case BOOT_MODE_HOST:
+ break;
+
+ default:
+ fatalerror("SHARC: Unimplemented boot mode %d", sharc.boot_mode);
+ }
+
+ sharc.pc = 0x20004;
+ sharc.daddr = sharc.pc + 1;
+ sharc.faddr = sharc.daddr + 1;
+ sharc.nfaddr = sharc.faddr+1;
+
+ sharc.idle = 0;
+ sharc.stky = 0x5400000;
+
+ sharc.interrupt_active = 0;
+}
+
+static void sharc_exit(void)
+{
+ /* TODO */
+}
+
+static void sharc_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ {
+ *(SHARC_REGS *)dst = sharc;
+ }
+}
+
+static void sharc_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ {
+ sharc = *(SHARC_REGS *)src;
+ }
+
+ change_pc(sharc.pc);
+}
+
+static void sharc_set_irq_line(int irqline, int state)
+{
+ if (state)
+ {
+ sharc.irq_active |= 1 << (8-irqline);
+ }
+}
+
+void sharc_set_flag_input(int flag_num, int state)
+{
+ if (flag_num >= 0 && flag_num < 4)
+ {
+ // Check if flag is set to input in MODE2 (bit == 0)
+ if ((sharc.mode2 & (1 << (flag_num+15))) == 0)
+ {
+ sharc.flag[flag_num] = state ? 1 : 0;
+ }
+ else
+ {
+ fatalerror("sharc_set_flag_input: flag %d is set output!", flag_num);
+ }
+ }
+}
+
+static void check_interrupts(void)
+{
+ int i;
+ if ((sharc.imask & sharc.irq_active) && (sharc.mode1 & MODE1_IRPTEN) && !sharc.interrupt_active &&
+ sharc.pc != sharc.delay_slot1 && sharc.pc != sharc.delay_slot2)
+ {
+ int which = 0;
+ for (i=0; i < 32; i++)
+ {
+ if (sharc.irq_active & (1 << i))
+ {
+ break;
+ }
+ which++;
+ }
+
+ if (sharc.idle)
+ {
+ PUSH_PC(sharc.pc+1);
+ }
+ else
+ {
+ PUSH_PC(sharc.daddr);
+ }
+
+ sharc.irptl |= 1 << which;
+
+ if (which >= 6 && which <= 8)
+ {
+ PUSH_STATUS_STACK();
+ }
+
+ CHANGE_PC(0x20000 + (which * 0x4));
+
+ /* TODO: alter IMASKP */
+
+ sharc.active_irq_num = which;
+ sharc.irq_active &= ~(1 << which);
+
+ sharc.interrupt_active = 1;
+ }
+}
+
+static int sharc_execute(int cycles)
+{
+ sharc_icount = cycles;
+
+ if (sharc.idle && sharc.irq_active == 0)
+ {
+ // handle pending DMA transfers
+ if (sharc.dmaop_cycles > 0)
+ {
+ sharc.dmaop_cycles -= cycles;
+ if (sharc.dmaop_cycles <= 0)
+ {
+ sharc.dmaop_cycles = 0;
+ dma_op(sharc.dmaop_src, sharc.dmaop_dst, sharc.dmaop_src_modifier, sharc.dmaop_dst_modifier, sharc.dmaop_src_count, sharc.dmaop_dst_count, sharc.dmaop_pmode);
+ if (sharc.dmaop_chain_ptr != 0)
+ {
+ schedule_chained_dma_op(sharc.dmaop_channel, sharc.dmaop_chain_ptr, sharc.dmaop_chained_direction);
+ }
+ }
+ }
+
+ sharc_icount = 0;
+ CALL_MAME_DEBUG;
+
+ return cycles;
+ }
+ if (sharc.irq_active != 0)
+ {
+ check_interrupts();
+ sharc.idle = 0;
+ }
+
+ // fill the initial pipeline
+
+ // next executed instruction
+ sharc.opcode = ROPCODE(sharc.daddr);
+ sharc.opcode_handler = sharc_op[(sharc.opcode >> 39) & 0x1ff];
+
+ // next decoded instruction
+ sharc.fetch_opcode = ROPCODE(sharc.faddr);
+
+ while (sharc_icount > 0 && !sharc.idle)
+ {
+ sharc.pc = sharc.daddr;
+ sharc.daddr = sharc.faddr;
+ sharc.faddr = sharc.nfaddr;
+ sharc.nfaddr++;
+
+ sharc.astat_old_old_old = sharc.astat_old_old;
+ sharc.astat_old_old = sharc.astat_old;
+ sharc.astat_old = sharc.astat;
+
+ sharc.decode_opcode = sharc.fetch_opcode;
+
+ // fetch next instruction
+ sharc.fetch_opcode = ROPCODE(sharc.faddr);
+
+ CALL_MAME_DEBUG;
+
+ // handle looping
+ if (sharc.pc == (sharc.laddr & 0xffffff))
+ {
+ switch (sharc.laddr >> 30)
+ {
+ case 0: // arithmetic condition-based
+ {
+ int condition = (sharc.laddr >> 24) & 0x1f;
+
+ {
+ UINT32 looptop = TOP_PC();
+ if (sharc.pc - looptop > 2)
+ {
+ sharc.astat = sharc.astat_old_old_old;
+ }
+ }
+
+ if (DO_CONDITION_CODE(condition))
+ {
+ POP_LOOP();
+ POP_PC();
+ }
+ else
+ {
+ CHANGE_PC(TOP_PC());
+ }
+
+ sharc.astat = sharc.astat_old;
+ break;
+ }
+ case 1: // counter-based, length 1
+ {
+ //fatalerror("SHARC: counter-based loop, length 1 at %08X", sharc.pc);
+ //break;
+ }
+ case 2: // counter-based, length 2
+ {
+ //fatalerror("SHARC: counter-based loop, length 2 at %08X", sharc.pc);
+ //break;
+ }
+ case 3: // counter-based, length >2
+ {
+ --sharc.lcstack[sharc.lstkp];
+ --sharc.curlcntr;
+ if (sharc.curlcntr == 0)
+ {
+ POP_LOOP();
+ POP_PC();
+ }
+ else
+ {
+ CHANGE_PC(TOP_PC());
+ }
+ }
+ }
+ }
+
+ // execute current instruction
+ sharc.opcode_handler();
+
+ // decode next instruction
+ sharc.opcode = sharc.decode_opcode;
+ sharc.opcode_handler = sharc_op[(sharc.opcode >> 39) & 0x1ff];
+
+
+
+
+ // System register latency effect
+ if (sharc.systemreg_latency_cycles > 0)
+ {
+ --sharc.systemreg_latency_cycles;
+ if (sharc.systemreg_latency_cycles <= 0)
+ {
+ systemreg_write_latency_effect();
+ }
+ }
+
+ // IOP register latency effect
+ if (sharc.iop_latency_cycles > 0)
+ {
+ --sharc.iop_latency_cycles;
+ if (sharc.iop_latency_cycles <= 0)
+ {
+ iop_write_latency_effect();
+ }
+ }
+
+ // DMA transfer
+ if (sharc.dmaop_cycles > 0)
+ {
+ --sharc.dmaop_cycles;
+ if (sharc.dmaop_cycles <= 0)
+ {
+ sharc.irptl |= (1 << (sharc.dmaop_channel+10));
+
+ /* DMA interrupt */
+ if (sharc.imask & (1 << (sharc.dmaop_channel+10)))
+ {
+ sharc.irq_active |= 1 << (sharc.dmaop_channel+10);
+ }
+
+ dma_op(sharc.dmaop_src, sharc.dmaop_dst, sharc.dmaop_src_modifier, sharc.dmaop_dst_modifier, sharc.dmaop_src_count, sharc.dmaop_dst_count, sharc.dmaop_pmode);
+ if (sharc.dmaop_chain_ptr != 0)
+ {
+ schedule_chained_dma_op(sharc.dmaop_channel, sharc.dmaop_chain_ptr, sharc.dmaop_chained_direction);
+ }
+ }
+ }
+
+ --sharc_icount;
+ };
+
+ return cycles - sharc_icount;
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void sharc_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SHARC_PC: sharc.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_FADDR: sharc.faddr = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_DADDR: sharc.daddr = info->i; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_R0: sharc.r[0].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R1: sharc.r[1].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R2: sharc.r[2].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R3: sharc.r[3].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R4: sharc.r[4].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R5: sharc.r[5].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R6: sharc.r[6].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R7: sharc.r[7].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R8: sharc.r[8].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R9: sharc.r[9].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R10: sharc.r[10].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R11: sharc.r[11].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R12: sharc.r[12].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R13: sharc.r[13].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R14: sharc.r[14].r = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_R15: sharc.r[15].r = info->i; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_I0: sharc.dag1.i[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I1: sharc.dag1.i[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I2: sharc.dag1.i[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I3: sharc.dag1.i[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I4: sharc.dag1.i[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I5: sharc.dag1.i[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I6: sharc.dag1.i[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I7: sharc.dag1.i[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I8: sharc.dag2.i[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I9: sharc.dag2.i[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I10: sharc.dag2.i[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I11: sharc.dag2.i[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I12: sharc.dag2.i[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I13: sharc.dag2.i[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I14: sharc.dag2.i[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_I15: sharc.dag2.i[7] = info->i; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_M0: sharc.dag1.m[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M1: sharc.dag1.m[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M2: sharc.dag1.m[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M3: sharc.dag1.m[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M4: sharc.dag1.m[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M5: sharc.dag1.m[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M6: sharc.dag1.m[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M7: sharc.dag1.m[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M8: sharc.dag2.m[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M9: sharc.dag2.m[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M10: sharc.dag2.m[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M11: sharc.dag2.m[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M12: sharc.dag2.m[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M13: sharc.dag2.m[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M14: sharc.dag2.m[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_M15: sharc.dag2.m[7] = info->i; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_L0: sharc.dag1.l[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L1: sharc.dag1.l[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L2: sharc.dag1.l[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L3: sharc.dag1.l[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L4: sharc.dag1.l[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L5: sharc.dag1.l[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L6: sharc.dag1.l[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L7: sharc.dag1.l[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L8: sharc.dag2.l[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L9: sharc.dag2.l[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L10: sharc.dag2.l[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L11: sharc.dag2.l[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L12: sharc.dag2.l[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L13: sharc.dag2.l[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L14: sharc.dag2.l[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_L15: sharc.dag2.m[7] = info->i; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_B0: sharc.dag1.b[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B1: sharc.dag1.b[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B2: sharc.dag1.b[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B3: sharc.dag1.b[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B4: sharc.dag1.b[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B5: sharc.dag1.b[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B6: sharc.dag1.b[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B7: sharc.dag1.b[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B8: sharc.dag2.b[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B9: sharc.dag2.b[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B10: sharc.dag2.b[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B11: sharc.dag2.b[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B12: sharc.dag2.b[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B13: sharc.dag2.b[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B14: sharc.dag2.b[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SHARC_B15: sharc.dag2.b[7] = info->i; break;
+ }
+}
+
+#if (HAS_ADSP21062)
+void adsp21062_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 2)
+ {
+ sharc_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i);
+ return;
+ }
+ else if (state >= CPUINFO_INT_INPUT_STATE + SHARC_INPUT_FLAG0 && state <= CPUINFO_INT_INPUT_STATE + SHARC_INPUT_FLAG3)
+ {
+ sharc_set_flag_input(state-(CPUINFO_INT_INPUT_STATE + SHARC_INPUT_FLAG0), info->i);
+ return;
+ }
+ switch(state)
+ {
+ default: sharc_set_info(state, info); break;
+ }
+}
+#endif
+
+
+static int sharc_debug_read(int space, UINT32 offset, int size, UINT64 *value)
+{
+ if (space == ADDRESS_SPACE_PROGRAM)
+ {
+ int address = offset >> 3;
+
+ if (address >= 0x20000 && address < 0x30000)
+ {
+ switch (size)
+ {
+ case 1:
+ {
+ int frac = offset & 7;
+ *value = (pm_read48(offset >> 3) >> ((frac^7) * 8)) & 0xff;
+ break;
+ }
+ case 8:
+ {
+ *value = pm_read48(offset >> 3);
+ break;
+ }
+ }
+ }
+ else
+ {
+ *value = 0;
+ }
+ }
+ else if (space == ADDRESS_SPACE_DATA)
+ {
+ int address = offset >> 2;
+ if (address >= 0x20000)
+ {
+ switch (size)
+ {
+ case 1:
+ {
+ int frac = offset & 3;
+ *value = (dm_read32(offset >> 2) >> ((frac^3) * 8)) & 0xff;
+ break;
+ }
+ case 2:
+ {
+ int frac = (offset >> 1) & 1;
+ *value = (dm_read32(offset >> 2) >> ((frac^1) * 16)) & 0xffff;
+ break;
+ }
+ case 4:
+ {
+ *value = dm_read32(offset >> 2);
+ break;
+ }
+ }
+ }
+ else
+ {
+ *value = 0;
+ }
+ }
+ return 1;
+}
+
+static int sharc_debug_readop(UINT32 offset, int size, UINT64 *value)
+{
+ UINT64 mask = (size < 8) ? (((UINT64)1 << (8 * size)) - 1) : ~(UINT64)0;
+ int shift = 8 * (offset & 7);
+ offset >>= 3;
+
+ if (offset >= 0x20000 && offset < 0x28000)
+ {
+ UINT64 op = ((UINT64)(sharc.internal_ram_block0[((offset-0x20000) * 3) + 0]) << 32) |
+ ((UINT64)(sharc.internal_ram_block0[((offset-0x20000) * 3) + 1]) << 16) |
+ ((UINT64)(sharc.internal_ram_block0[((offset-0x20000) * 3) + 2]) << 0);
+ *value = (op >> shift) & mask;
+ }
+ else if (offset >= 0x28000 && offset < 0x30000)
+ {
+ UINT64 op = ((UINT64)(sharc.internal_ram_block1[((offset-0x28000) * 3) + 0]) << 32) |
+ ((UINT64)(sharc.internal_ram_block1[((offset-0x28000) * 3) + 1]) << 16) |
+ ((UINT64)(sharc.internal_ram_block1[((offset-0x28000) * 3) + 2]) << 0);
+ *value = (op >> shift) & mask;
+ }
+
+ return 1;
+}
+
+// This is just used to stop the debugger from complaining about executing from I/O space
+static ADDRESS_MAP_START( internal_pgm, ADDRESS_SPACE_PROGRAM, 64 )
+ AM_RANGE(0x20000, 0x7ffff) AM_RAM
+ADDRESS_MAP_END
+
+void sharc_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(sharc); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 32; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 8; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -3; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = -2; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SHARC_PC: info->i = sharc.pc; break;
+ case CPUINFO_INT_REGISTER + SHARC_PCSTK: info->i = sharc.pcstk; break;
+ case CPUINFO_INT_REGISTER + SHARC_PCSTKP: info->i = sharc.pcstkp; break;
+ case CPUINFO_INT_REGISTER + SHARC_LSTKP: info->i = sharc.lstkp; break;
+ case CPUINFO_INT_REGISTER + SHARC_FADDR: info->i = sharc.faddr; break;
+ case CPUINFO_INT_REGISTER + SHARC_DADDR: info->i = sharc.daddr; break;
+ case CPUINFO_INT_REGISTER + SHARC_MODE1: info->i = sharc.mode1; break;
+ case CPUINFO_INT_REGISTER + SHARC_MODE2: info->i = sharc.mode2; break;
+ case CPUINFO_INT_REGISTER + SHARC_ASTAT: info->i = sharc.astat; break;
+ case CPUINFO_INT_REGISTER + SHARC_IRPTL: info->i = sharc.irptl; break;
+ case CPUINFO_INT_REGISTER + SHARC_IMASK: info->i = sharc.imask; break;
+ case CPUINFO_INT_REGISTER + SHARC_USTAT1: info->i = sharc.ustat1; break;
+ case CPUINFO_INT_REGISTER + SHARC_USTAT2: info->i = sharc.ustat2; break;
+ case CPUINFO_INT_REGISTER + SHARC_STSTKP: info->i = sharc.status_stkp; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_R0: info->i = sharc.r[0].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R1: info->i = sharc.r[1].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R2: info->i = sharc.r[2].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R3: info->i = sharc.r[3].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R4: info->i = sharc.r[4].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R5: info->i = sharc.r[5].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R6: info->i = sharc.r[6].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R7: info->i = sharc.r[7].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R8: info->i = sharc.r[8].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R9: info->i = sharc.r[9].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R10: info->i = sharc.r[10].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R11: info->i = sharc.r[11].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R12: info->i = sharc.r[12].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R13: info->i = sharc.r[13].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R14: info->i = sharc.r[14].r; break;
+ case CPUINFO_INT_REGISTER + SHARC_R15: info->i = sharc.r[15].r; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_I0: info->i = sharc.dag1.i[0]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I1: info->i = sharc.dag1.i[1]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I2: info->i = sharc.dag1.i[2]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I3: info->i = sharc.dag1.i[3]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I4: info->i = sharc.dag1.i[4]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I5: info->i = sharc.dag1.i[5]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I6: info->i = sharc.dag1.i[6]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I7: info->i = sharc.dag1.i[7]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I8: info->i = sharc.dag2.i[0]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I9: info->i = sharc.dag2.i[1]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I10: info->i = sharc.dag2.i[2]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I11: info->i = sharc.dag2.i[3]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I12: info->i = sharc.dag2.i[4]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I13: info->i = sharc.dag2.i[5]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I14: info->i = sharc.dag2.i[6]; break;
+ case CPUINFO_INT_REGISTER + SHARC_I15: info->i = sharc.dag2.i[7]; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_M0: info->i = sharc.dag1.m[0]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M1: info->i = sharc.dag1.m[1]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M2: info->i = sharc.dag1.m[2]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M3: info->i = sharc.dag1.m[3]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M4: info->i = sharc.dag1.m[4]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M5: info->i = sharc.dag1.m[5]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M6: info->i = sharc.dag1.m[6]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M7: info->i = sharc.dag1.m[7]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M8: info->i = sharc.dag2.m[0]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M9: info->i = sharc.dag2.m[1]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M10: info->i = sharc.dag2.m[2]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M11: info->i = sharc.dag2.m[3]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M12: info->i = sharc.dag2.m[4]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M13: info->i = sharc.dag2.m[5]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M14: info->i = sharc.dag2.m[6]; break;
+ case CPUINFO_INT_REGISTER + SHARC_M15: info->i = sharc.dag2.m[7]; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_L0: info->i = sharc.dag1.l[0]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L1: info->i = sharc.dag1.l[1]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L2: info->i = sharc.dag1.l[2]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L3: info->i = sharc.dag1.l[3]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L4: info->i = sharc.dag1.l[4]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L5: info->i = sharc.dag1.l[5]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L6: info->i = sharc.dag1.l[6]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L7: info->i = sharc.dag1.l[7]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L8: info->i = sharc.dag2.l[0]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L9: info->i = sharc.dag2.l[1]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L10: info->i = sharc.dag2.l[2]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L11: info->i = sharc.dag2.l[3]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L12: info->i = sharc.dag2.l[4]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L13: info->i = sharc.dag2.l[5]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L14: info->i = sharc.dag2.l[6]; break;
+ case CPUINFO_INT_REGISTER + SHARC_L15: info->i = sharc.dag2.l[7]; break;
+
+ case CPUINFO_INT_REGISTER + SHARC_B0: info->i = sharc.dag1.b[0]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B1: info->i = sharc.dag1.b[1]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B2: info->i = sharc.dag1.b[2]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B3: info->i = sharc.dag1.b[3]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B4: info->i = sharc.dag1.b[4]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B5: info->i = sharc.dag1.b[5]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B6: info->i = sharc.dag1.b[6]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B7: info->i = sharc.dag1.b[7]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B8: info->i = sharc.dag2.b[0]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B9: info->i = sharc.dag2.b[1]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B10: info->i = sharc.dag2.b[2]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B11: info->i = sharc.dag2.b[3]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B12: info->i = sharc.dag2.b[4]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B13: info->i = sharc.dag2.b[5]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B14: info->i = sharc.dag2.b[6]; break;
+ case CPUINFO_INT_REGISTER + SHARC_B15: info->i = sharc.dag2.b[7]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = sharc_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = sharc_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = sharc_init; break;
+ case CPUINFO_PTR_RESET: info->reset = sharc_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = sharc_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = sharc_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = sharc_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &sharc_icount; break;
+ case CPUINFO_PTR_READ: info->read = sharc_debug_read; break;
+ case CPUINFO_PTR_READOP: info->readop = sharc_debug_readop; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_internal_pgm; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "SHARC"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "2.01"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2004-2006 Ville Linde"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + SHARC_PC: sprintf(info->s, "PC: %08X", sharc.pc); break;
+ case CPUINFO_STR_REGISTER + SHARC_PCSTK: sprintf(info->s, "PCSTK: %08X", sharc.pcstk); break;
+ case CPUINFO_STR_REGISTER + SHARC_PCSTKP: sprintf(info->s, "PCSTKP: %08X", sharc.pcstkp); break;
+ case CPUINFO_STR_REGISTER + SHARC_LSTKP: sprintf(info->s, "LSTKP: %08X", sharc.lstkp); break;
+ case CPUINFO_STR_REGISTER + SHARC_FADDR: sprintf(info->s, "FADDR: %08X", sharc.faddr); break;
+ case CPUINFO_STR_REGISTER + SHARC_DADDR: sprintf(info->s, "DADDR: %08X", sharc.daddr); break;
+ case CPUINFO_STR_REGISTER + SHARC_MODE1: sprintf(info->s, "MODE1: %08X", sharc.mode1); break;
+ case CPUINFO_STR_REGISTER + SHARC_MODE2: sprintf(info->s, "MODE2: %08X", sharc.mode2); break;
+ case CPUINFO_STR_REGISTER + SHARC_ASTAT: sprintf(info->s, "ASTAT: %08X", sharc.astat); break;
+ case CPUINFO_STR_REGISTER + SHARC_IRPTL: sprintf(info->s, "IRPTL: %08X", sharc.irptl); break;
+ case CPUINFO_STR_REGISTER + SHARC_IMASK: sprintf(info->s, "IMASK: %08X", sharc.imask); break;
+ case CPUINFO_STR_REGISTER + SHARC_USTAT1: sprintf(info->s, "USTAT1: %08X", sharc.ustat1); break;
+ case CPUINFO_STR_REGISTER + SHARC_USTAT2: sprintf(info->s, "USTAT2: %08X", sharc.ustat2); break;
+ case CPUINFO_STR_REGISTER + SHARC_STSTKP: sprintf(info->s, "STSTKP: %08X", sharc.status_stkp); break;
+
+ case CPUINFO_STR_REGISTER + SHARC_R0: sprintf(info->s, "R0: %08X", (UINT32)sharc.r[0].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R1: sprintf(info->s, "R1: %08X", (UINT32)sharc.r[1].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R2: sprintf(info->s, "R2: %08X", (UINT32)sharc.r[2].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R3: sprintf(info->s, "R3: %08X", (UINT32)sharc.r[3].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R4: sprintf(info->s, "R4: %08X", (UINT32)sharc.r[4].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R5: sprintf(info->s, "R5: %08X", (UINT32)sharc.r[5].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R6: sprintf(info->s, "R6: %08X", (UINT32)sharc.r[6].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R7: sprintf(info->s, "R7: %08X", (UINT32)sharc.r[7].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R8: sprintf(info->s, "R8: %08X", (UINT32)sharc.r[8].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R9: sprintf(info->s, "R9: %08X", (UINT32)sharc.r[9].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R10: sprintf(info->s, "R10: %08X", (UINT32)sharc.r[10].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R11: sprintf(info->s, "R11: %08X", (UINT32)sharc.r[11].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R12: sprintf(info->s, "R12: %08X", (UINT32)sharc.r[12].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R13: sprintf(info->s, "R13: %08X", (UINT32)sharc.r[13].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R14: sprintf(info->s, "R14: %08X", (UINT32)sharc.r[14].r); break;
+ case CPUINFO_STR_REGISTER + SHARC_R15: sprintf(info->s, "R15: %08X", (UINT32)sharc.r[15].r); break;
+
+ case CPUINFO_STR_REGISTER + SHARC_I0: sprintf(info->s, "I0: %08X", (UINT32)sharc.dag1.i[0]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I1: sprintf(info->s, "I1: %08X", (UINT32)sharc.dag1.i[1]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I2: sprintf(info->s, "I2: %08X", (UINT32)sharc.dag1.i[2]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I3: sprintf(info->s, "I3: %08X", (UINT32)sharc.dag1.i[3]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I4: sprintf(info->s, "I4: %08X", (UINT32)sharc.dag1.i[4]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I5: sprintf(info->s, "I5: %08X", (UINT32)sharc.dag1.i[5]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I6: sprintf(info->s, "I6: %08X", (UINT32)sharc.dag1.i[6]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I7: sprintf(info->s, "I7: %08X", (UINT32)sharc.dag1.i[7]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I8: sprintf(info->s, "I8: %08X", (UINT32)sharc.dag2.i[0]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I9: sprintf(info->s, "I9: %08X", (UINT32)sharc.dag2.i[1]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I10: sprintf(info->s, "I10: %08X", (UINT32)sharc.dag2.i[2]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I11: sprintf(info->s, "I11: %08X", (UINT32)sharc.dag2.i[3]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I12: sprintf(info->s, "I12: %08X", (UINT32)sharc.dag2.i[4]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I13: sprintf(info->s, "I13: %08X", (UINT32)sharc.dag2.i[5]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I14: sprintf(info->s, "I14: %08X", (UINT32)sharc.dag2.i[6]); break;
+ case CPUINFO_STR_REGISTER + SHARC_I15: sprintf(info->s, "I15: %08X", (UINT32)sharc.dag2.i[7]); break;
+
+ case CPUINFO_STR_REGISTER + SHARC_M0: sprintf(info->s, "M0: %08X", (UINT32)sharc.dag1.m[0]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M1: sprintf(info->s, "M1: %08X", (UINT32)sharc.dag1.m[1]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M2: sprintf(info->s, "M2: %08X", (UINT32)sharc.dag1.m[2]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M3: sprintf(info->s, "M3: %08X", (UINT32)sharc.dag1.m[3]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M4: sprintf(info->s, "M4: %08X", (UINT32)sharc.dag1.m[4]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M5: sprintf(info->s, "M5: %08X", (UINT32)sharc.dag1.m[5]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M6: sprintf(info->s, "M6: %08X", (UINT32)sharc.dag1.m[6]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M7: sprintf(info->s, "M7: %08X", (UINT32)sharc.dag1.m[7]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M8: sprintf(info->s, "M8: %08X", (UINT32)sharc.dag2.m[0]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M9: sprintf(info->s, "M9: %08X", (UINT32)sharc.dag2.m[1]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M10: sprintf(info->s, "M10: %08X", (UINT32)sharc.dag2.m[2]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M11: sprintf(info->s, "M11: %08X", (UINT32)sharc.dag2.m[3]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M12: sprintf(info->s, "M12: %08X", (UINT32)sharc.dag2.m[4]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M13: sprintf(info->s, "M13: %08X", (UINT32)sharc.dag2.m[5]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M14: sprintf(info->s, "M14: %08X", (UINT32)sharc.dag2.m[6]); break;
+ case CPUINFO_STR_REGISTER + SHARC_M15: sprintf(info->s, "M15: %08X", (UINT32)sharc.dag2.m[7]); break;
+
+ case CPUINFO_STR_REGISTER + SHARC_L0: sprintf(info->s, "L0: %08X", (UINT32)sharc.dag1.l[0]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L1: sprintf(info->s, "L1: %08X", (UINT32)sharc.dag1.l[1]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L2: sprintf(info->s, "L2: %08X", (UINT32)sharc.dag1.l[2]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L3: sprintf(info->s, "L3: %08X", (UINT32)sharc.dag1.l[3]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L4: sprintf(info->s, "L4: %08X", (UINT32)sharc.dag1.l[4]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L5: sprintf(info->s, "L5: %08X", (UINT32)sharc.dag1.l[5]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L6: sprintf(info->s, "L6: %08X", (UINT32)sharc.dag1.l[6]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L7: sprintf(info->s, "L7: %08X", (UINT32)sharc.dag1.l[7]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L8: sprintf(info->s, "L8: %08X", (UINT32)sharc.dag2.l[0]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L9: sprintf(info->s, "L9: %08X", (UINT32)sharc.dag2.l[1]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L10: sprintf(info->s, "L10: %08X", (UINT32)sharc.dag2.l[2]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L11: sprintf(info->s, "L11: %08X", (UINT32)sharc.dag2.l[3]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L12: sprintf(info->s, "L12: %08X", (UINT32)sharc.dag2.l[4]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L13: sprintf(info->s, "L13: %08X", (UINT32)sharc.dag2.l[5]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L14: sprintf(info->s, "L14: %08X", (UINT32)sharc.dag2.l[6]); break;
+ case CPUINFO_STR_REGISTER + SHARC_L15: sprintf(info->s, "L15: %08X", (UINT32)sharc.dag2.l[7]); break;
+
+ case CPUINFO_STR_REGISTER + SHARC_B0: sprintf(info->s, "B0: %08X", (UINT32)sharc.dag1.b[0]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B1: sprintf(info->s, "B1: %08X", (UINT32)sharc.dag1.b[1]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B2: sprintf(info->s, "B2: %08X", (UINT32)sharc.dag1.b[2]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B3: sprintf(info->s, "B3: %08X", (UINT32)sharc.dag1.b[3]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B4: sprintf(info->s, "B4: %08X", (UINT32)sharc.dag1.b[4]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B5: sprintf(info->s, "B5: %08X", (UINT32)sharc.dag1.b[5]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B6: sprintf(info->s, "B6: %08X", (UINT32)sharc.dag1.b[6]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B7: sprintf(info->s, "B7: %08X", (UINT32)sharc.dag1.b[7]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B8: sprintf(info->s, "B8: %08X", (UINT32)sharc.dag2.b[0]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B9: sprintf(info->s, "B9: %08X", (UINT32)sharc.dag2.b[1]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B10: sprintf(info->s, "B10: %08X", (UINT32)sharc.dag2.b[2]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B11: sprintf(info->s, "B11: %08X", (UINT32)sharc.dag2.b[3]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B12: sprintf(info->s, "B12: %08X", (UINT32)sharc.dag2.b[4]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B13: sprintf(info->s, "B13: %08X", (UINT32)sharc.dag2.b[5]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B14: sprintf(info->s, "B14: %08X", (UINT32)sharc.dag2.b[6]); break;
+ case CPUINFO_STR_REGISTER + SHARC_B15: sprintf(info->s, "B15: %08X", (UINT32)sharc.dag2.b[7]); break;
+ }
+}
+
+#if (HAS_ADSP21062)
+void adsp21062_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = adsp21062_set_info; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "ADSP21062"); break;
+
+ default: sharc_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/sharc/sharc.h b/src/emu/cpu/sharc/sharc.h
new file mode 100644
index 00000000000..d07aebc0d09
--- /dev/null
+++ b/src/emu/cpu/sharc/sharc.h
@@ -0,0 +1,35 @@
+#ifndef _SHARC_H
+#define _SHARC_H
+
+#include "cpuintrf.h"
+
+#define SHARC_INPUT_FLAG0 3
+#define SHARC_INPUT_FLAG1 4
+#define SHARC_INPUT_FLAG2 5
+#define SHARC_INPUT_FLAG3 6
+
+typedef enum {
+ BOOT_MODE_EPROM,
+ BOOT_MODE_HOST,
+ BOOT_MODE_LINK,
+ BOOT_MODE_NOBOOT
+} SHARC_BOOT_MODE;
+
+typedef struct {
+ SHARC_BOOT_MODE boot_mode;
+} sharc_config;
+
+extern void sharc_set_flag_input(int flag_num, int state);
+
+extern void sharc_external_iop_write(UINT32 address, UINT32 data);
+extern void sharc_external_dma_write(UINT32 address, UINT64 data);
+
+#if (HAS_ADSP21062)
+void adsp21062_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#ifdef MAME_DEBUG
+extern UINT32 sharc_dasm_one(char *buffer, offs_t pc, UINT64 opcode);
+#endif
+
+#endif /* _SHARC_H */
diff --git a/src/emu/cpu/sharc/sharcdma.c b/src/emu/cpu/sharc/sharcdma.c
new file mode 100644
index 00000000000..720bd9538c0
--- /dev/null
+++ b/src/emu/cpu/sharc/sharcdma.c
@@ -0,0 +1,204 @@
+/* SHARC DMA operations */
+
+#define DMA_PMODE_NO_PACKING 0
+#define DMA_PMODE_16_32 1
+#define DMA_PMODE_16_48 2
+#define DMA_PMODE_32_48 3
+#define DMA_PMODE_8_48 4
+
+static void schedule_chained_dma_op(int channel, UINT32 dma_chain_ptr, int chained_direction)
+{
+ UINT32 op_ptr = 0x20000 + dma_chain_ptr;
+
+ UINT32 int_index = dm_read32(op_ptr - 0);
+ UINT32 int_modifier = dm_read32(op_ptr - 1);
+ UINT32 int_count = dm_read32(op_ptr - 2);
+ UINT32 chain_ptr = dm_read32(op_ptr - 3);
+ //UINT32 gen_purpose = dm_read32(op_ptr - 4);
+ UINT32 ext_index = dm_read32(op_ptr - 5);
+ UINT32 ext_modifier = dm_read32(op_ptr - 6);
+ UINT32 ext_count = dm_read32(op_ptr - 7);
+
+ if (sharc.dmaop_cycles > 0)
+ {
+ fatalerror("schedule_chained_dma_op: DMA operation already scheduled at %08X!", sharc.pc);
+ }
+
+ if (chained_direction) // Transmit to external
+ {
+ sharc.dmaop_dst = ext_index;
+ sharc.dmaop_dst_modifier = ext_modifier;
+ sharc.dmaop_dst_count = ext_count;
+ sharc.dmaop_src = int_index;
+ sharc.dmaop_src_modifier = int_modifier;
+ sharc.dmaop_src_count = int_count;
+ }
+ else // Receive from external
+ {
+ sharc.dmaop_src = ext_index;
+ sharc.dmaop_src_modifier = ext_modifier;
+ sharc.dmaop_src_count = ext_count;
+ sharc.dmaop_dst = int_index;
+ sharc.dmaop_dst_modifier = int_modifier;
+ sharc.dmaop_dst_count = int_count;
+ }
+
+ sharc.dmaop_pmode = 0;
+ sharc.dmaop_channel = channel;
+ sharc.dmaop_cycles = sharc.dmaop_src_count / 4;
+ sharc.dmaop_chain_ptr = chain_ptr;
+ sharc.dmaop_chained_direction = chained_direction;
+}
+
+static void schedule_dma_op(int channel, UINT32 src, UINT32 dst, int src_modifier, int dst_modifier, int src_count, int dst_count, int pmode)
+{
+ if (sharc.dmaop_cycles > 0)
+ {
+ fatalerror("schedule_dma_op: DMA operation already scheduled at %08X!", sharc.pc);
+ }
+
+ sharc.dmaop_channel = channel;
+ sharc.dmaop_src = src;
+ sharc.dmaop_dst = dst;
+ sharc.dmaop_src_modifier = src_modifier;
+ sharc.dmaop_dst_modifier = dst_modifier;
+ sharc.dmaop_src_count = src_count;
+ sharc.dmaop_dst_count = dst_count;
+ sharc.dmaop_pmode = pmode;
+ sharc.dmaop_chain_ptr = 0;
+ sharc.dmaop_cycles = src_count / 4;
+}
+
+static void dma_op(UINT32 src, UINT32 dst, int src_modifier, int dst_modifier, int src_count, int dst_count, int pmode)
+{
+ int i;
+ //printf("dma_op: %08X, %08X, %08X, %08X, %08X, %08X, %d\n", src, dst, src_modifier, dst_modifier, src_count, dst_count, pmode);
+
+ switch (pmode)
+ {
+ case DMA_PMODE_NO_PACKING:
+ {
+ for (i=0; i < src_count; i++)
+ {
+ UINT32 data = dm_read32(src);
+ dm_write32(dst, data);
+ src += src_modifier;
+ dst += dst_modifier;
+ }
+ break;
+ }
+ case DMA_PMODE_16_32:
+ {
+ int length = src_count/2;
+ for (i=0; i < length; i++)
+ {
+ UINT32 data = ((dm_read32(src+0) & 0xffff) << 16) | (dm_read32(src+1) & 0xffff);
+
+ dm_write32(dst, data);
+ src += src_modifier * 2;
+ dst += dst_modifier;
+ }
+ break;
+ }
+ case DMA_PMODE_8_48:
+ {
+ int length = src_count/6;
+ for (i=0; i < length; i++)
+ {
+ UINT64 data = ((UINT64)(dm_read32(src+0) & 0xff) << 0) |
+ ((UINT64)(dm_read32(src+1) & 0xff) << 8) |
+ ((UINT64)(dm_read32(src+2) & 0xff) << 16) |
+ ((UINT64)(dm_read32(src+3) & 0xff) << 24) |
+ ((UINT64)(dm_read32(src+4) & 0xff) << 32) |
+ ((UINT64)(dm_read32(src+5) & 0xff) << 40);
+
+ pm_write48(dst, data);
+ src += src_modifier * 6;
+ dst += dst_modifier;
+ }
+ break;
+ }
+ default:
+ {
+ fatalerror("SHARC: dma_op: unimplemented packing mode %d\n", pmode);
+ }
+ }
+
+ if (sharc.dmaop_channel == 6)
+ {
+ sharc.irptl |= (1 << (sharc.dmaop_channel+10));
+
+ /* DMA interrupt */
+ if (sharc.imask & (1 << (sharc.dmaop_channel+10)))
+ {
+ sharc.irq_active |= 1 << (sharc.dmaop_channel+10);
+ }
+ }
+}
+
+static void sharc_dma_exec(int channel)
+{
+ UINT32 src, dst;
+ UINT32 src_count, dst_count;
+ UINT32 src_modifier, dst_modifier;
+ int chen, tran, dtype, pmode, mswf, master, ishake, intio, ext, flsh;
+
+ chen = (sharc.dma[channel].control >> 1) & 0x1;
+ tran = (sharc.dma[channel].control >> 2) & 0x1;
+ dtype = (sharc.dma[channel].control >> 5) & 0x1;
+ pmode = (sharc.dma[channel].control >> 6) & 0x3;
+ mswf = (sharc.dma[channel].control >> 8) & 0x1;
+ master = (sharc.dma[channel].control >> 9) & 0x1;
+ ishake = (sharc.dma[channel].control >> 10) & 0x1;
+ intio = (sharc.dma[channel].control >> 11) & 0x1;
+ ext = (sharc.dma[channel].control >> 12) & 0x1;
+ flsh = (sharc.dma[channel].control >> 13) & 0x1;
+
+ if (ishake)
+ fatalerror("SHARC: dma_exec: handshake not supported");
+ if (intio)
+ fatalerror("SHARC: dma_exec: single-word interrupt enable not supported");
+
+
+
+ if (chen) // Chained DMA
+ {
+ UINT32 dma_chain_ptr = sharc.dma[channel].chain_ptr & 0x1ffff;
+
+ schedule_chained_dma_op(channel, dma_chain_ptr, tran);
+ }
+ else
+ {
+ if (tran) // Transmit to external
+ {
+ dst = sharc.dma[channel].ext_index;
+ dst_modifier = sharc.dma[channel].ext_modifier;
+ dst_count = sharc.dma[channel].ext_count;
+ src = sharc.dma[channel].int_index;
+ src_modifier = sharc.dma[channel].int_modifier;
+ src_count = sharc.dma[channel].int_count;
+ }
+ else // Receive from external
+ {
+ src = sharc.dma[channel].ext_index;
+ src_modifier = sharc.dma[channel].ext_modifier;
+ src_count = sharc.dma[channel].ext_count;
+ dst = sharc.dma[channel].int_index;
+ dst_modifier = sharc.dma[channel].int_modifier;
+ dst_count = sharc.dma[channel].int_count;
+
+ if (dst < 0x20000)
+ {
+ dst |= 0x20000;
+ }
+ }
+
+ if (dtype)
+ //if (src_count != dst_count)
+ {
+ pmode = DMA_PMODE_8_48;
+ }
+
+ schedule_dma_op(channel, src, dst, src_modifier, dst_modifier, src_count, dst_count, pmode);
+ }
+}
diff --git a/src/emu/cpu/sharc/sharcdsm.c b/src/emu/cpu/sharc/sharcdsm.c
new file mode 100644
index 00000000000..a796d0dcd68
--- /dev/null
+++ b/src/emu/cpu/sharc/sharcdsm.c
@@ -0,0 +1,1183 @@
+/*
+ Analog Devices ADSP-2106x SHARC Disassembler
+
+ Written by Ville Linde for use in MAME
+*/
+
+#include "cpuintrf.h"
+#include "sharcdsm.h"
+#include <stdarg.h>
+
+static UINT32 (* sharcdasm_table[256])(UINT32, UINT64);
+static int dasm_table_built = 0;
+
+#define GET_UREG(x) (ureg_names[x])
+#define GET_SREG(x) (GET_UREG(0x70 | (x & 0xf)))
+#define GET_DREG(x) (GET_UREG(0x00 | (x & 0xf)))
+#define GET_DAG1_I(x) (GET_UREG(0x10 | (x & 0x7)))
+#define GET_DAG1_M(x) (GET_UREG(0x20 | (x & 0x7)))
+#define GET_DAG1_L(x) (GET_UREG(0x30 | (x & 0x7)))
+#define GET_DAG1_B(x) (GET_UREG(0x40 | (x & 0x7)))
+#define GET_DAG2_I(x) (GET_UREG(0x10 | (8 + (x & 0x7))))
+#define GET_DAG2_M(x) (GET_UREG(0x20 | (8 + (x & 0x7))))
+#define GET_DAG2_L(x) (GET_UREG(0x30 | (8 + (x & 0x7))))
+#define GET_DAG2_B(x) (GET_UREG(0x40 | (8 + (x & 0x7))))
+
+#define SIGN_EXTEND6(x) ((x & 0x20) ? (0xffffffc0 | x) : x)
+#define SIGN_EXTEND24(x) ((x & 0x800000) ? (0xff000000 | x) : x)
+
+
+static char *output;
+static void print(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ output += vsprintf(output, fmt, vl);
+ va_end(vl);
+}
+
+
+
+static void compute(UINT32 opcode)
+{
+ int op = (opcode >> 12) & 0xff;
+ int cu = (opcode >> 20) & 0x3;
+ int rn = (opcode >> 8) & 0xf;
+ int rx = (opcode >> 4) & 0xf;
+ int ry = (opcode >> 0) & 0xf;
+ int rs = (opcode >> 12) & 0xf;
+ int ra = rn;
+ int rm = rs;
+
+ if (opcode & 0x400000) /* Multi-function opcode */
+ {
+ int multiop = (opcode >> 16) & 0x3f;
+ int rxm = (opcode >> 6) & 0x3;
+ int rym = (opcode >> 4) & 0x3;
+ int rxa = (opcode >> 2) & 0x3;
+ int rya = (opcode >> 0) & 0x3;
+
+ switch(multiop)
+ {
+ case 0x04: print("R%d = R%d * R%d (SSFR), R%d = R%d + R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x05: print("R%d = R%d * R%d (SSFR), R%d = R%d - R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x06: print("R%d = R%d * R%d (SSFR), R%d = (R%d + R%d)/2", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x08: print("MRF = MRF + R%d * R%d (SSF), R%d = R%d + R%d", rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x09: print("MRF = MRF + R%d * R%d (SSF), R%d = R%d - R%d", rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x0a: print("MRF = MRF + R%d * R%d (SSF), R%d = (R%d + R%d)/2", rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x0c: print("R%d = MRF + R%d * R%d (SSFR), R%d = R%d + R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x0d: print("R%d = MRF + R%d * R%d (SSFR), R%d = R%d - R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x0e: print("R%d = MRF + R%d * R%d (SSFR), R%d = (R%d + R%d)/2", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x10: print("MRF = MRF - R%d * R%d (SSF), R%d = R%d + R%d", rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x11: print("MRF = MRF - R%d * R%d (SSF), R%d = R%d - R%d", rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x12: print("MRF = MRF - R%d * R%d (SSF), R%d = (R%d + R%d)/2", rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x14: print("R%d = MRF - R%d * R%d (SSFR), R%d = R%d + R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x15: print("R%d = MRF - R%d * R%d (SSFR), R%d = R%d - R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x16: print("R%d = MRF - R%d * R%d (SSFR), R%d = (R%d + R%d)/2", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x18: print("F%d = F%d * F%d, F%d = F%d + F%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x19: print("F%d = F%d * F%d, F%d = F%d - F%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x1a: print("F%d = F%d * F%d, F%d = FLOAT F%d BY F%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x1b: print("F%d = F%d * F%d, F%d = FIX F%d BY F%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x1c: print("F%d = F%d * F%d, F%d = (F%d + F%d)/2", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x1d: print("F%d = F%d * F%d, F%d = ABS F%d", rm, rxm, rym+4, ra, rxa+8); break;
+ case 0x1e: print("F%d = F%d * F%d, F%d = MAX(F%d, F%d)", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+ case 0x1f: print("F%d = F%d * F%d, F%d = MIN(F%d, F%d)", rm, rxm, rym+4, ra, rxa+8, rya+12); break;
+
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ {
+ print("R%d = R%d * R%d (SSFR), R%d = R%d + R%d, R%d = R%d - R%d", rm, rxm, rym+4, ra, rxa+8, rya+12, rs, rxa+8, rya+12);
+ break;
+ }
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ {
+ print("F%d = F%d * F%d, F%d = F%d + F%d, F%d = F%d - F%d", rm, rxm, rym+4, ra, rxa+8, rya+12, rs, rxa+8, rya+12);
+ break;
+ }
+
+ case 0x00:
+ {
+ int rk = (opcode >> 8) & 0xf;
+ int ai = (opcode >> 12) & 0xf;
+ print("R%d = %s", rk, mr_regnames[ai]);
+ break;
+ }
+ case 0x01:
+ {
+ int rk = (opcode >> 8) & 0xf;
+ int ai = (opcode >> 12) & 0xf;
+ print("%s = R%d", mr_regnames[ai], rk);
+ break;
+ }
+
+ default:
+ {
+ print("??? (COMPUTE, MULTIOP)");
+ break;
+ }
+ }
+ }
+ else /* Single-function */
+ {
+ switch(cu)
+ {
+ /******************/
+ /* ALU operations */
+ /******************/
+ case 0:
+ {
+ switch(op)
+ {
+ /* Fixed-point */
+ case 0x01: print("R%d = R%d + R%d", rn, rx, ry); break;
+ case 0x02: print("R%d = R%d - R%d", rn, rx, ry); break;
+ case 0x05: print("R%d = R%d + R%d + CI", rn, rx, ry); break;
+ case 0x06: print("R%d = R%d - R%d + CI - 1", rn, rx, ry); break;
+ case 0x09: print("R%d = (R%d + R%d)/2", rn, rx, ry); break;
+ case 0x0a: print("COMP(R%d, R%d)", rx, ry); break;
+ case 0x25: print("R%d = R%d + CI", rn, rx); break;
+ case 0x26: print("R%d = R%d + CI - 1", rn, rx); break;
+ case 0x29: print("R%d = R%d + 1", rn, rx); break;
+ case 0x2a: print("R%d = R%d - 1", rn, rx); break;
+ case 0x22: print("R%d = -R%d", rn, rx); break;
+ case 0x30: print("R%d = ABS R%d", rn, rx); break;
+ case 0x21: print("R%d = PASS R%d", rn, rx); break;
+ case 0x40: print("R%d = R%d AND R%d", rn, rx, ry); break;
+ case 0x41: print("R%d = R%d OR R%d", rn, rx, ry); break;
+ case 0x42: print("R%d = R%d XOR R%d", rn, rx, ry); break;
+ case 0x43: print("R%d = NOT R%d", rn, rx); break;
+ case 0x61: print("R%d = MIN(R%d, R%d)", rn, rx, ry); break;
+ case 0x62: print("R%d = MAX(R%d, R%d)", rn, rx, ry); break;
+ case 0x63: print("R%d = CLIP R%d BY R%d", rn, rx, ry); break;
+ /* Floating-point */
+ case 0x81: print("F%d = F%d + F%d", rn, rx, ry); break;
+ case 0x82: print("F%d = F%d - F%d", rn, rx, ry); break;
+ case 0x91: print("F%d = ABS(F%d + F%d)", rn, rx, ry); break;
+ case 0x92: print("F%d = ABS(F%d - F%d)", rn, rx, ry); break;
+ case 0x89: print("F%d = (F%d + F%d)/2", rn, rx, ry); break;
+ case 0x8a: print("COMP(F%d, F%d)", rx, ry); break;
+ case 0xa2: print("F%d = -F%d", rn, rx); break;
+ case 0xb0: print("F%d = ABS F%d", rn, rx); break;
+ case 0xa1: print("F%d = PASS F%d", rn, rx); break;
+ case 0xa5: print("F%d = RND R%d", rn, rx); break;
+ case 0xbd: print("F%d = SCALB F%d BY R%d", rn, rx, ry); break;
+ case 0xad: print("R%d = MANT F%d", rn, rx); break;
+ case 0xc1: print("R%d = LOGB F%d", rn, rx); break;
+ case 0xd9: print("R%d = FIX F%d BY R%d", rn, rx, ry); break;
+ case 0xc9: print("R%d = FIX F%d", rn, rx); break;
+ case 0xdd: print("R%d = TRUNC F%d BY R%d", rn, rx, ry); break;
+ case 0xcd: print("R%d = TRUNC F%d", rn, rx); break;
+ case 0xda: print("F%d = FLOAT R%d BY R%d", rn, rx, ry); break;
+ case 0xca: print("F%d = FLOAT R%d", rn, rx); break;
+ case 0xc4: print("F%d = RECIPS F%d", rn, rx); break;
+ case 0xc5: print("F%d = RSQRTS F%d", rn, rx); break;
+ case 0xe0: print("F%d = F%d COPYSIGN F%d", rn, rx, ry); break;
+ case 0xe1: print("F%d = MIN(F%d, F%d)", rn, rx, ry); break;
+ case 0xe2: print("F%d = MAX(F%d, F%d)", rn, rx, ry); break;
+ case 0xe3: print("F%d = CLIP F%d BY F%d", rn, rx, ry); break;
+
+ case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+ {
+ print("R%d = R%d + R%d, R%d = R%d - R%d", ra, rx, ry, rs, rx, ry);
+ break;
+ }
+ case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
+ case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
+ {
+ print("F%d = F%d + F%d, F%d = F%d - F%d", ra, rx, ry, rs, rx, ry);
+ break;
+ }
+ default:
+ {
+ print("??? (COMPUTE, ALU)");
+ break;
+ }
+ }
+ break;
+ }
+
+ /*************************/
+ /* Multiplier operations */
+ /*************************/
+ case 1:
+ {
+ if( op == 0x30 ) {
+ print("F%d = F%d * F%d", rn, rx, ry);
+ return;
+ }
+
+ switch((op >> 1) & 0x3)
+ {
+ case 0:
+ case 1: print("R%d = ", rn); break;
+ case 2: print("MRF = "); break;
+ case 3: print("MRB = "); break;
+ }
+ switch((op >> 6) & 0x3)
+ {
+ case 0:
+ switch((op >> 4) & 0x3)
+ {
+ case 0: print("SAT %s", (op & 0x2) ? "MRB" : "MRF"); break;
+ case 1:
+ if (op & 0x8)
+ {
+ print("RND %s", (op & 0x2) ? "MRB" : "MRF");
+ }
+ else
+ {
+ print("0");
+ }
+ break;
+ }
+ break;
+
+ case 1:
+ print("R%d * R%d", rx, ry); break;
+
+ case 2:
+ print("%s +(R%d * R%d)", (op & 0x2) ? "MRB" : "MRF", rx, ry); break;
+
+ case 3:
+ print("%s -(R%d * R%d)", (op & 0x2) ? "MRB" : "MRF", rx, ry); break;
+ }
+ break;
+ }
+
+ /**********************/
+ /* Shifter operations */
+ /**********************/
+ case 2:
+ {
+ switch(op)
+ {
+ case 0x00: print("R%d = LSHIFT R%d BY R%d", rn, rx, ry); break;
+ case 0x20: print("R%d = R%d OR LSHIFT R%d BY R%d", rn, rn, rx, ry); break;
+ case 0x04: print("R%d = ASHIFT R%d BY R%d", rn, rx, ry); break;
+ case 0x24: print("R%d = R%d OR ASHIFT R%d BY R%d", rn, rn, rx, ry); break;
+ case 0x08: print("R%d = ROT R%d BY R%d", rn, rx, ry); break;
+ case 0xc4: print("R%d = BCLR R%d BY R%d", rn, rx, ry); break;
+ case 0xc0: print("R%d = BSET R%d BY R%d", rn, rx, ry); break;
+ case 0xc8: print("R%d = BTGL R%d BY R%d", rn, rx, ry); break;
+ case 0xcc: print("BTST R%d BY R%d", rx, ry); break;
+ case 0x44: print("R%d = FDEP R%d BY R%d", rn, rx, ry); break;
+ case 0x64: print("R%d = R%d OR FDEP R%d BY R%d", rn, rn, rx, ry); break;
+ case 0x4c: print("R%d = FDEP R%d BY R%d (SE)", rn, rx, ry); break;
+ case 0x6c: print("R%d = R%d OR FDEP R%d BY R%d (SE)", rn, rn, rx, ry); break;
+ case 0x40: print("R%d = FEXT R%d BY R%d", rn, rx, ry); break;
+ case 0x48: print("R%d = FEXT R%d BY R%d (SE)", rn, rx, ry); break;
+ case 0x80: print("R%d = EXP R%d", rn, rx); break;
+ case 0x84: print("R%d = EXP R%d (EX)", rn, rx); break;
+ case 0x88: print("R%d = LEFTZ R%d", rn, rx); break;
+ case 0x8c: print("R%d = LEFTO R%d", rn, rx); break;
+ case 0x90: print("R%d = FPACK F%d", rn, rx); break;
+ case 0x94: print("F%d = FUNPACK R%d", rn, rx); break;
+ default: print("??? (COMPUTE, SHIFT)"); break;
+ }
+ break;
+ }
+
+ default:
+ {
+ print("??? (COMPUTE)");
+ break;
+ }
+ }
+ }
+}
+
+static void get_if_condition(int cond)
+{
+ if (cond != 31)
+ {
+ print("IF %s, ", condition_codes_if[cond]);
+ }
+}
+
+void pm_dm_ureg(int g, int d, int i, int m, int ureg, int update)
+{
+ if (update) // post-modify
+ {
+ if (d)
+ {
+ if (g)
+ {
+ print("PM(%s, %s) = %s", GET_DAG2_I(i), GET_DAG2_M(m), GET_UREG(ureg));
+ }
+ else
+ {
+ print("DM(%s, %s) = %s", GET_DAG1_I(i), GET_DAG1_M(m), GET_UREG(ureg));
+ }
+ }
+ else
+ {
+ if (g)
+ {
+ print("%s = PM(%s, %s)", GET_UREG(ureg), GET_DAG2_I(i), GET_DAG2_M(m));
+ }
+ else
+ {
+ print("%s = DM(%s, %s)", GET_UREG(ureg), GET_DAG1_I(i), GET_DAG1_M(m));
+ }
+ }
+
+ }
+ else // pre-modify
+ {
+ if (d)
+ {
+ if (g)
+ {
+ print("PM(%s, %s) = %s", GET_DAG2_M(m), GET_DAG2_I(i), GET_UREG(ureg));
+ }
+ else
+ {
+ print("DM(%s, %s) = %s", GET_DAG1_M(m), GET_DAG1_I(i), GET_UREG(ureg));
+ }
+ }
+ else
+ {
+ if (g)
+ {
+ print("%s = PM(%s, %s)", GET_UREG(ureg), GET_DAG2_M(m), GET_DAG2_I(i));
+ }
+ else
+ {
+ print("%s = DM(%s, %s)", GET_UREG(ureg), GET_DAG1_M(m), GET_DAG1_I(i));
+ }
+ }
+ }
+}
+
+void pm_dm_imm_dreg(int g, int d, int i, int data, int dreg, int update)
+{
+ if (update) // post-modify
+ {
+ if (d)
+ {
+ if (g)
+ {
+ print("PM(%s, 0x%02X) = %s", GET_DAG2_I(i), data, GET_DREG(dreg));
+ }
+ else
+ {
+ print("DM(%s, 0x%02X) = %s", GET_DAG1_I(i), data, GET_DREG(dreg));
+ }
+ }
+ else
+ {
+ if (g)
+ {
+ print("%s = PM(%s, 0x%02X)", GET_DREG(dreg), GET_DAG2_I(i), data);
+ }
+ else
+ {
+ print("%s = DM(%s, 0x%02X)", GET_DREG(dreg), GET_DAG1_I(i), data);
+ }
+ }
+ }
+ else // pre-modify
+ {
+ if (d)
+ {
+ if (g)
+ {
+ print("PM(0x%02X, %s) = %s", data, GET_DAG2_I(i), GET_DREG(dreg));
+ }
+ else
+ {
+ print("DM(0x%02X, %s) = %s", data, GET_DAG1_I(i), GET_DREG(dreg));
+ }
+ }
+ else
+ {
+ if (g)
+ {
+ print("%s = PM(0x%02X, %s)", GET_DREG(dreg), data, GET_DAG2_I(i));
+ }
+ else
+ {
+ print("%s = DM(0x%02X, %s)", GET_DREG(dreg), data, GET_DAG1_I(i));
+ }
+ }
+ }
+}
+
+void pm_dm_dreg(int g, int d, int i, int m, int dreg)
+{
+ if (d)
+ {
+ if (g)
+ {
+ print("PM(%s, %s) = %s", GET_DAG2_I(i), GET_DAG2_M(m), GET_DREG(dreg));
+ }
+ else
+ {
+ print("DM(%s, %s) = %s", GET_DAG1_I(i), GET_DAG1_M(m), GET_DREG(dreg));
+ }
+ }
+ else
+ {
+ if (g)
+ {
+ print("%s = PM(%s, %s)", GET_DREG(dreg), GET_DAG2_I(i), GET_DAG2_M(m));
+ }
+ else
+ {
+ print("%s = DM(%s, %s)", GET_DREG(dreg), GET_DAG1_I(i), GET_DAG1_M(m));
+ }
+ }
+}
+
+void shiftop(int shift, int data, int rn, int rx)
+{
+ INT8 data8 = data & 0xff;
+ int bit6 = data & 0x3f;
+ int len = (data >> 6) & 0x3f;
+
+ switch(shift)
+ {
+ case 0x00: print("R%d = LSHIFT R%d BY %d", rn, rx, data8); break;
+ case 0x08: print("R%d = R%d OR LSHIFT R%d BY %d", rn, rn, rx, data8); break;
+ case 0x01: print("R%d = ASHIFT R%d BY %d", rn, rx, data8); break;
+ case 0x09: print("R%d = R%d OR ASHIFT R%d BY %d", rn, rn, rx, data8); break;
+ case 0x02: print("R%d = ROT R%d BY %d", rn, rx, data8); break;
+ case 0x31: print("R%d = BCLR R%d BY %d", rn, rx, data8); break;
+ case 0x30: print("R%d = BSET R%d BY %d", rn, rx, data8); break;
+ case 0x32: print("R%d = BTGL R%d BY %d", rn, rx, data8); break;
+ case 0x33: print("BTST R%d BY %d", rx, data8); break;
+ case 0x11: print("R%d = FDEP R%d BY %d:%d", rn, rx, bit6, len); break;
+ case 0x19: print("R%d = R%d OR FDEP R%d BY %d:%d", rn, rn, rx, bit6, len); break;
+ case 0x13: print("R%d = FDEP R%d BY %d:%d (SE)", rn, rx, bit6, len); break;
+ case 0x1b: print("R%d = R%d OR FDEP R%d BY %d:%d (SE)", rn, rn, rx, bit6, len); break;
+ case 0x10: print("R%d = FEXT R%d BY %d:%d", rn, rx, bit6, len); break;
+ case 0x12: print("R%d = FEXT R%d BY %d:%d (SE)", rn, rx, bit6, len); break;
+ case 0x20: print("R%d = EXP R%d", rn, rx); break;
+ case 0x21: print("R%d = EXP R%d (EX)", rn, rx); break;
+ case 0x22: print("R%d = LEFTZ R%d", rn, rx); break;
+ case 0x23: print("R%d = LEFTO R%d", rn, rx); break;
+ case 0x24: print("R%d = FPACK F%d", rn, rx); break;
+ case 0x25: print("F%d = FUNPACK R%d", rn, rx); break;
+ default: print("??? (SHIFTOP)"); break;
+ }
+}
+
+
+
+
+
+static UINT32 dasm_compute_dreg_dmpm(UINT32 pc, UINT64 opcode)
+{
+ int dmi = (opcode >> 41) & 0x7;
+ int dmm = (opcode >> 38) & 0x7;
+ int pmi = (opcode >> 30) & 0x7;
+ int pmm = (opcode >> 27) & 0x7;
+ int dmdreg = (opcode >> 33) & 0xf;
+ int pmdreg = (opcode >> 23) & 0xf;
+ int comp = opcode & 0x7fffff;
+
+ if (comp)
+ {
+ compute(comp);
+ print(", ");
+ }
+ print("DM(%s, %s) = R%d, ", GET_DAG1_I(dmi), GET_DAG1_M(dmm), dmdreg);
+ print("PM(%s, %s) = R%d", GET_DAG2_I(pmi), GET_DAG2_M(pmm), pmdreg);
+ return 0;
+}
+
+static UINT32 dasm_compute(UINT32 pc, UINT64 opcode)
+{
+ int cond = (opcode >> 33) & 0x1f;
+ int comp = opcode & 0x7fffff;
+
+ if (comp)
+ {
+ get_if_condition(cond);
+ compute(comp);
+ }
+ return 0;
+}
+
+static UINT32 dasm_compute_uregdmpm_regmod(UINT32 pc, UINT64 opcode)
+{
+ int cond = (opcode >> 33) & 0x1f;
+ int g = (opcode >> 32) & 0x1;
+ int d = (opcode >> 31) & 0x1;
+ int i = (opcode >> 41) & 0x7;
+ int m = (opcode >> 38) & 0x7;
+ int u = (opcode >> 44) & 0x1;
+ int ureg = (opcode >> 23) & 0xff;
+ int comp = opcode & 0x7fffff;
+
+ get_if_condition(cond);
+ if (comp)
+ {
+ compute(comp);
+ print(", ");
+ }
+ pm_dm_ureg(g,d,i,m, ureg, u);
+ return 0;
+}
+
+static UINT32 dasm_compute_dregdmpm_immmod(UINT32 pc, UINT64 opcode)
+{
+ int cond = (opcode >> 33) & 0x1f;
+ int g = (opcode >> 40) & 0x1;
+ int d = (opcode >> 39) & 0x1;
+ int i = (opcode >> 41) & 0x7;
+ int u = (opcode >> 38) & 0x1;
+ int dreg = (opcode >> 23) & 0xf;
+ int data = (opcode >> 27) & 0x3f;
+ int comp = opcode & 0x7fffff;
+
+ get_if_condition(cond);
+ if (comp)
+ {
+ compute(comp);
+ print(", ");
+ }
+ pm_dm_imm_dreg(g,d,i, data, dreg, u);
+ return 0;
+}
+
+static UINT32 dasm_compute_ureg_ureg(UINT32 pc, UINT64 opcode)
+{
+ int cond = (opcode >> 31) & 0x1f;
+ int uregs = (opcode >> 36) & 0xff;
+ int uregd = (opcode >> 23) & 0xff;
+ int comp = opcode & 0x7fffff;
+
+ get_if_condition(cond);
+ if (comp)
+ {
+ compute(comp);
+ print(", ");
+ }
+ print("%s = %s", GET_UREG(uregd), GET_UREG(uregs));
+ return 0;
+}
+
+static UINT32 dasm_immshift_dregdmpm(UINT32 pc, UINT64 opcode)
+{
+ int cond = (opcode >> 33) & 0x1f;
+ int g = (opcode >> 32) & 0x1;
+ int d = (opcode >> 31) & 0x1;
+ int i = (opcode >> 41) & 0x7;
+ int m = (opcode >> 38) & 0x7;
+ int rn = (opcode >> 4) & 0xf;
+ int rx = (opcode >> 0) & 0xf;
+ int shift = (opcode >> 16) & 0x3f;
+ int dreg = (opcode >> 23) & 0xf;
+ int data = (((opcode >> 27) & 0xf) << 8) | ((opcode >> 8) & 0xff);
+
+ get_if_condition(cond);
+ shiftop(shift, data, rn, rx);
+ print(", ");
+ pm_dm_dreg(g,d,i,m, dreg);
+ return 0;
+}
+
+static UINT32 dasm_immshift_dregdmpm_nodata(UINT32 pc, UINT64 opcode)
+{
+ int cond = (opcode >> 33) & 0x1f;
+ int rn = (opcode >> 4) & 0xf;
+ int rx = (opcode >> 0) & 0xf;
+ int shift = (opcode >> 16) & 0x3f;
+ int data = (((opcode >> 27) & 0xf) << 8) | ((opcode >> 8) & 0xff);
+
+ get_if_condition(cond);
+ shiftop(shift, data, rn, rx);
+ return 0;
+}
+
+static UINT32 dasm_compute_modify(UINT32 pc, UINT64 opcode)
+{
+ int cond = (opcode >> 33) & 0x1f;
+ int g = (opcode >> 38) & 0x7;
+ int i = (opcode >> 30) & 0x7;
+ int m = (opcode >> 27) & 0x7;
+ int comp = opcode & 0x7fffff;
+
+ get_if_condition(cond);
+ if (comp)
+ {
+ compute(comp);
+ print(", ");
+ }
+ print("MODIFY(I%d, M%d)", (g ? 8+i : i), (g ? 8+m : m));
+ return 0;
+}
+
+static UINT32 dasm_direct_jump(UINT32 pc, UINT64 opcode)
+{
+ int j = (opcode >> 26) & 0x1;
+ int cond = (opcode >> 33) & 0x1f;
+ int ci = (opcode >> 24) & 0x1;
+ UINT32 addr = opcode & 0xffffff;
+ UINT32 flags = 0;
+
+ get_if_condition(cond);
+ if (opcode & U64(0x8000000000))
+ {
+ print("CALL");
+ flags = DASMFLAG_STEP_OVER;
+ }
+ else
+ {
+ print("JUMP");
+ }
+
+ if (opcode & U64(0x10000000000)) /* PC-relative branch */
+ {
+ print(" (0x%08X)", pc + SIGN_EXTEND24(addr));
+ }
+ else /* Indirect branch */
+ {
+ print(" (0x%08X)", addr);
+ }
+ if (j)
+ {
+ print(" (DB)");
+ }
+ if (ci)
+ {
+ print(" (CI)");
+ }
+ return flags;
+}
+
+static UINT32 dasm_indirect_jump_compute(UINT32 pc, UINT64 opcode)
+{
+ int b = (opcode >> 39) & 0x1;
+ int j = (opcode >> 26) & 0x1;
+ int e = (opcode >> 25) & 0x1;
+ int ci = (opcode >> 24) & 0x1;
+ int cond = (opcode >> 33) & 0x1f;
+ int pmi = (opcode >> 30) & 0x7;
+ int pmm = (opcode >> 27) & 0x7;
+ int reladdr = (opcode >> 27) & 0x3f;
+ int comp = opcode & 0x7fffff;
+ UINT32 flags = 0;
+
+ get_if_condition(cond);
+ if (b)
+ {
+ print("CALL");
+ flags = DASMFLAG_STEP_OVER;
+ }
+ else
+ {
+ print("JUMP");
+ }
+
+ if (opcode & U64(0x10000000000)) /* PC-relative branch */
+ {
+ print(" (0x%08X)", pc + SIGN_EXTEND6(reladdr));
+ }
+ else /* Indirect branch */
+ {
+ print(" (%s, %s)", GET_DAG2_M(pmm), GET_DAG2_I(pmi));
+ }
+ if (j)
+ {
+ print(" (DB)");
+ }
+ if (ci)
+ {
+ print(" (CI)");
+ }
+
+ if (comp)
+ {
+ print(", ");
+ if (e)
+ {
+ print("ELSE ");
+ }
+
+ compute(comp);
+ }
+ return flags;
+}
+
+static UINT32 dasm_indirect_jump_compute_dregdm(UINT32 pc, UINT64 opcode)
+{
+ int d = (opcode >> 44) & 0x1;
+ int cond = (opcode >> 33) & 0x1f;
+ int pmi = (opcode >> 30) & 0x7;
+ int pmm = (opcode >> 27) & 0x7;
+ int dmi = (opcode >> 41) & 0x7;
+ int dmm = (opcode >> 38) & 0x7;
+ int reladdr = (opcode >> 27) & 0x3f;
+ int dreg = (opcode >> 23) & 0xf;
+ int comp = opcode & 0x7fffff;
+
+ get_if_condition(cond);
+ print("JUMP");
+
+ if (opcode & U64(0x200000000000)) /* PC-relative branch */
+ {
+ print(" (0x%08X)", pc + SIGN_EXTEND6(reladdr));
+ }
+ else /* Indirect branch */
+ {
+ print(" (%s, %s)", GET_DAG2_M(pmm), GET_DAG2_I(pmi));
+ }
+ print(", ELSE ");
+
+ if (comp)
+ {
+ compute(comp);
+ print(", ");
+ }
+ if (d)
+ {
+ print("%s = DM(%s, %s)", GET_DREG(dreg), GET_DAG1_I(dmi), GET_DAG1_M(dmm));
+ }
+ else
+ {
+ print("DM(%s, %s) = %s", GET_DAG1_I(dmi), GET_DAG1_M(dmm), GET_DREG(dreg));
+ }
+ return 0;
+}
+
+static UINT32 dasm_rts_compute(UINT32 pc, UINT64 opcode)
+{
+ int j = (opcode >> 26) & 0x1;
+ int e = (opcode >> 25) & 0x1;
+ int lr = (opcode >> 24) & 0x1;
+ int cond = (opcode >> 33) & 0x1f;
+ int comp = opcode & 0x7fffff;
+
+ get_if_condition(cond);
+
+ if (opcode & U64(0x10000000000))
+ {
+ print("RTI");
+ }
+ else
+ {
+ print("RTS");
+ }
+
+ if (j)
+ {
+ print(" (DB)");
+ }
+ if (lr)
+ {
+ print(" (LR)");
+ }
+
+ if (comp)
+ {
+ print(", ");
+ if (e)
+ {
+ print("ELSE ");
+ }
+
+ compute(comp);
+ }
+ return DASMFLAG_STEP_OUT;
+}
+
+static UINT32 dasm_do_until_counter(UINT32 pc, UINT64 opcode)
+{
+ int data = (opcode >> 24) & 0xffff;
+ int ureg = (opcode >> 32) & 0xff;
+ UINT32 addr = opcode & 0xffffff;
+
+ if (opcode & U64(0x10000000000)) /* Loop counter from universal register */
+ {
+ print("LCNTR = %s, ", GET_UREG(ureg));
+ print("DO (0x%08X)", pc + SIGN_EXTEND24(addr));
+ }
+ else /* Loop counter from immediate */
+ {
+ print("LCNTR = 0x%04X, ", data);
+ print("DO (0x%08X) UNTIL LCE", pc + SIGN_EXTEND24(addr));
+ }
+ return 0;
+}
+
+static UINT32 dasm_do_until(UINT32 pc, UINT64 opcode)
+{
+ int term = (opcode >> 33) & 0x1f;
+ UINT32 addr = opcode & 0xffffff;
+
+ print("DO (0x%08X) UNTIL %s", pc + SIGN_EXTEND24(addr), condition_codes_do[term]);
+ return 0;
+}
+
+static UINT32 dasm_immmove_uregdmpm(UINT32 pc, UINT64 opcode)
+{
+ int d = (opcode >> 40) & 0x1;
+ int g = (opcode >> 41) & 0x1;
+ int ureg = (opcode >> 32) & 0xff;
+ UINT32 addr = opcode & 0xffffffff;
+
+ if (g)
+ {
+ if (d)
+ {
+ print("PM(0x%08X) = %s", addr, GET_UREG(ureg));
+ }
+ else
+ {
+ print("%s = PM(0x%08X)", GET_UREG(ureg), addr);
+ }
+ }
+ else
+ {
+ if (d)
+ {
+ print("DM(0x%08X) = %s", addr, GET_UREG(ureg));
+ }
+ else
+ {
+ print("%s = DM(0x%08X)", GET_UREG(ureg), addr);
+ }
+ }
+ return 0;
+}
+
+static UINT32 dasm_immmove_uregdmpm_indirect(UINT32 pc, UINT64 opcode)
+{
+ int d = (opcode >> 40) & 0x1;
+ int g = (opcode >> 44) & 0x1;
+ int i = (opcode >> 41) & 0x7;
+ int ureg = (opcode >> 32) & 0xff;
+ UINT32 addr = opcode & 0xffffffff;
+
+ if (g)
+ {
+ if (d)
+ {
+ print("PM(0x%08X, %s) = %s", addr, GET_DAG2_I(i), GET_UREG(ureg));
+ }
+ else
+ {
+ print("%s = PM(0x%08X, %s)", GET_UREG(ureg), addr, GET_DAG2_I(i));
+ }
+ }
+ else
+ {
+ if (d)
+ {
+ print("DM(0x%08X, %s) = %s", addr, GET_DAG1_I(i), GET_UREG(ureg));
+ }
+ else
+ {
+ print("%s = DM(0x%08X, %s)", GET_UREG(ureg), addr, GET_DAG1_I(i));
+ }
+ }
+ return 0;
+}
+
+static UINT32 dasm_immmove_immdata_dmpm(UINT32 pc, UINT64 opcode)
+{
+ int g = (opcode >> 37) & 0x1;
+ int i = (opcode >> 41) & 0x7;
+ int m = (opcode >> 38) & 0x7;
+ UINT32 data = opcode & 0xffffffff;
+
+ if (g)
+ {
+ print("PM(%s, %s) = 0x%08X", GET_DAG2_I(i), GET_DAG2_M(m), data);
+ }
+ else
+ {
+ print("DM(%s, %s) = 0x%08X", GET_DAG1_I(i), GET_DAG1_M(m), data);
+ }
+ return 0;
+}
+
+static UINT32 dasm_immmove_immdata_ureg(UINT32 pc, UINT64 opcode)
+{
+ int ureg = (opcode >> 32) & 0xff;
+ UINT32 data = opcode & 0xffffffff;
+
+ print("%s = 0x%08X", GET_UREG(ureg), data);
+ return 0;
+}
+
+static UINT32 dasm_sysreg_bitop(UINT32 pc, UINT64 opcode)
+{
+ int bop = (opcode >> 37) & 0x7;
+ int sreg = (opcode >> 32) & 0xf;
+ UINT32 data = opcode & 0xffffffff;
+
+ print("BIT ");
+ print("%s ", bopnames[bop]);
+ print("%s ", GET_SREG(sreg));
+ print("0x%08X", data);
+ return 0;
+}
+
+static UINT32 dasm_ireg_modify(UINT32 pc, UINT64 opcode)
+{
+ int g = (opcode >> 38) & 0x1;
+ int i = (opcode >> 32) & 0x7;
+ UINT32 data = opcode & 0xffffffff;
+
+ if (opcode & U64(0x8000000000)) /* with bit-reverse */
+ {
+ if (g)
+ {
+ print("BITREV (%s, 0x%08X)", GET_DAG2_I(i), data);
+ }
+ else
+ {
+ print("BITREV (%s, 0x%08X)", GET_DAG1_I(i), data);
+ }
+ }
+ else /* without bit-reverse */
+ {
+ if (g)
+ {
+ print("MODIFY (%s, 0x%08X)", GET_DAG2_I(i), data);
+ }
+ else
+ {
+ print("MODIFY (%s, 0x%08X)", GET_DAG1_I(i), data);
+ }
+ }
+ return 0;
+}
+
+static UINT32 dasm_misc(UINT32 pc, UINT64 opcode)
+{
+ int bits = (opcode >> 33) & 0x7f;
+ int lpu = (opcode >> 39) & 0x1;
+ int lpo = (opcode >> 38) & 0x1;
+ int spu = (opcode >> 37) & 0x1;
+ int spo = (opcode >> 36) & 0x1;
+ int ppu = (opcode >> 35) & 0x1;
+ int ppo = (opcode >> 34) & 0x1;
+ int fc = (opcode >> 33) & 0x1;
+
+ if (lpu)
+ {
+ print("PUSH LOOP");
+ if (bits & 0x3f)
+ {
+ print(", ");
+ }
+ }
+ if (lpo)
+ {
+ print("POP LOOP");
+ if (bits & 0x1f)
+ {
+ print(", ");
+ }
+ }
+ if (spu)
+ {
+ print("PUSH STS");
+ if (bits & 0xf)
+ {
+ print(", ");
+ }
+ }
+ if (spo)
+ {
+ print("POP STS");
+ if (bits & 0x7)
+ {
+ print(", ");
+ }
+ }
+ if (ppu)
+ {
+ print("PUSH PCSTK");
+ if (bits & 0x3)
+ {
+ print(", ");
+ }
+ }
+ if (ppo)
+ {
+ print("POP PCSTK");
+ if (bits & 0x1)
+ {
+ print(", ");
+ }
+ }
+ if (fc)
+ {
+ print("FLUSH CACHE");
+ }
+ return 0;
+}
+
+static UINT32 dasm_idlenop(UINT32 pc, UINT64 opcode)
+{
+ if (opcode & U64(0x8000000000))
+ {
+ print("IDLE");
+ }
+ else
+ {
+ print("NOP");
+ }
+ return 0;
+}
+
+#ifdef UNUSED_FUNCTION
+static UINT32 dasm_cjump_rframe(UINT32 pc, UINT64 opcode)
+{
+ /* TODO */
+ if (opcode & U64(0x10000000000)) /* RFRAME */
+ {
+ print("TODO: RFRAME");
+ }
+ else
+ {
+ print("TODO: CJUMP");
+ }
+ return 0;
+}
+#endif
+
+static UINT32 dasm_invalid(UINT32 pc, UINT64 opcode)
+{
+ print("?");
+ return 0;
+}
+
+static SHARC_DASM_OP sharc_dasm_ops[] =
+{
+ // |0 0 1|
+ { 0xe000, 0x2000, dasm_compute_dreg_dmpm },
+
+ // |0 0 0|0 0 0 0 1|
+ { 0xff00, 0x0100, dasm_compute },
+
+ // |0 1 0|
+ { 0xe000, 0x4000, dasm_compute_uregdmpm_regmod },
+
+ // |0 1 1|0|
+ { 0xf000, 0x6000, dasm_compute_dregdmpm_immmod },
+
+ // |0 1 1|1|
+ { 0xf000, 0x7000, dasm_compute_ureg_ureg },
+
+ // |1 0 0|0|
+ { 0xf000, 0x8000, dasm_immshift_dregdmpm },
+
+ // |0 0 0|0 0 0 1 0|
+ { 0xff00, 0x0200, dasm_immshift_dregdmpm_nodata },
+
+ // |0 0 0|0 0 1 0 0|
+ { 0xff00, 0x0400, dasm_compute_modify },
+
+ // |0 0 0|0 0 1 1 x|
+ { 0xfe00, 0x0600, dasm_direct_jump },
+
+ // |0 0 0|0 1 0 0 x|
+ { 0xfe00, 0x0800, dasm_indirect_jump_compute },
+
+ // |1 1 x|
+ { 0xc000, 0xc000, dasm_indirect_jump_compute_dregdm },
+
+ // |0 0 0|0 1 0 1 x|
+ { 0xfe00, 0x0a00, dasm_rts_compute },
+
+ // |0 0 0|0 1 1 0 x|
+ { 0xfe00, 0x0c00, dasm_do_until_counter },
+
+ // |0 0 0|0 1 1 1 0|
+ { 0xff00, 0x0e00, dasm_do_until },
+
+ // |0 0 0|1 0 0|x|x|
+ { 0xfc00, 0x1000, dasm_immmove_uregdmpm },
+
+ // |1 0 1|x|x x x|x|
+ { 0xe000, 0xa000, dasm_immmove_uregdmpm_indirect },
+
+ // |1 0 0|1|
+ { 0xf000, 0x9000, dasm_immmove_immdata_dmpm },
+
+ // |0 0 0|0 1 1 1 1|
+ { 0xff00, 0x0f00, dasm_immmove_immdata_ureg },
+
+ // |0 0 0|1 0 1 0 0|
+ { 0xff00, 0x1400, dasm_sysreg_bitop },
+
+ // |0 0 0|1 0 1 1 0|
+ { 0xff00, 0x1600, dasm_ireg_modify },
+
+ // |0 0 0|1 0 1 1 1|
+ { 0xff00, 0x1700, dasm_misc },
+
+ // |0 0 0|0 0 0 0 0|
+ { 0xff00, 0x0000, dasm_idlenop },
+};
+
+static void build_dasm_table(void)
+{
+ int i, j;
+ int num_ops = sizeof(sharc_dasm_ops) / sizeof(SHARC_DASM_OP);
+
+ for (i=0; i < 256; i++)
+ {
+ sharcdasm_table[i] = dasm_invalid;
+ }
+
+ for (i=0; i < 256; i++)
+ {
+ UINT16 op = i << 8;
+
+ for (j=0; j < num_ops; j++)
+ {
+ if ((sharc_dasm_ops[j].op_mask & op) == sharc_dasm_ops[j].op_bits)
+ {
+ if (sharcdasm_table[i] != dasm_invalid)
+ {
+ fatalerror("build_dasm_table: table already filled! (i=%04X, j=%d)\n", i, j);
+ }
+ else
+ {
+ sharcdasm_table[i] = sharc_dasm_ops[j].handler;
+ }
+ }
+ }
+ }
+}
+
+UINT32 sharc_dasm_one(char *buffer, offs_t pc, UINT64 opcode)
+{
+ #define DEFAULT_DASM_WIDTH (64)
+
+ char dasm_buffer[2000];
+ int i;
+ int op = (opcode >> 40) & 0xff;
+ UINT32 flags;
+
+ if (!dasm_table_built)
+ {
+ build_dasm_table();
+ dasm_table_built = 1;
+ }
+
+ memset(dasm_buffer, 0, sizeof(dasm_buffer));
+
+ /* set buffer for print */
+ output = dasm_buffer;
+
+ flags = (*sharcdasm_table[op])(pc, opcode);
+
+ for (i=0; i < DEFAULT_DASM_WIDTH; i++)
+ {
+ buffer[i] = dasm_buffer[i];
+ }
+ return flags;
+}
+
diff --git a/src/emu/cpu/sharc/sharcdsm.h b/src/emu/cpu/sharc/sharcdsm.h
new file mode 100644
index 00000000000..04364f5f096
--- /dev/null
+++ b/src/emu/cpu/sharc/sharcdsm.h
@@ -0,0 +1,77 @@
+static const char ureg_names[256][16] =
+{
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+ "I0", "I1", "I2", "I3", "I4", "I5", "I6", "I7",
+ "I8", "I9", "I10", "I11", "I12", "I13", "I14", "I15",
+ "M0", "M1", "M2", "M3", "M4", "M5", "M6", "M7",
+ "M8", "M9", "M10", "M11", "M12", "M13", "M14", "M15",
+ "L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7",
+ "L8", "L9", "L10", "L11", "L12", "L13", "L14", "L15",
+ "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
+ "B8", "B9", "B10", "B11", "B12", "B13", "B14", "B15",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "FADDR", "DADDR", "???", "PC", "PCSTK", "PCSTKP", "LADDR", "CURLCNTR",
+ "LCNTR", "???", "???", "???", "???", "???", "???", "???",
+ "USTAT1", "USTAT2", "???", "???", "???", "???", "???", "???",
+ "???", "IRPTL", "MODE2", "MODE1", "ASTAT", "IMASK", "STKY", "IMASKP",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "PX", "PX1", "PX2", "TPERIOD", "TCOUNT",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???"
+};
+
+static const char bopnames[8][8] =
+{
+ "SET", "CLEAR", "TOGGLE", "???", "TEST", "XOR", "???", "???"
+};
+
+static const char condition_codes_if[32][32] =
+{
+ "EQ", "LT", "LE", "AC",
+ "AV", "MV", "MS", "SV",
+ "SZ", "FLAG0_IN", "FLAG1_IN", "FLAG2_IN",
+ "FLAG3_IN", "TF", "BM", "NOT LCE",
+ "NE", "GE", "GT", "NOT AC",
+ "NOT AV", "NOT MV", "NOT MS", "NOT SV",
+ "NOT SZ", "NOT FLAG0_IN", "NOT FLAG1_IN", "NOT FLAG2_IN",
+ "NOT FLAG3_IN", "NOT TF", "NBM", ""
+};
+
+static const char condition_codes_do[32][32] =
+{
+ "EQ", "LT", "LE", "AC",
+ "AV", "MV", "MS", "SV",
+ "SZ", "FLAG0_IN", "FLAG1_IN", "FLAG2_IN",
+ "FLAG3_IN", "TF", "BM", "LCE",
+ "NE", "GE", "GT", "NOT AC",
+ "NOT AV", "NOT MV", "NOT MS", "NOT SV",
+ "NOT SZ", "NOT FLAG0_IN", "NOT FLAG1_IN", "NOT FLAG2_IN",
+ "NOT FLAG3_IN", "NOT TF", "NBM", "FOREVER"
+};
+
+static const char mr_regnames[16][8] =
+{
+ "MR0F", "MR1F", "MR2F", "MR0B", "MR1B", "MR2B", "???", "???",
+ "???", "???", "???", "???", "???", "???", "???", "???"
+};
+
+typedef struct
+{
+ UINT32 op_mask;
+ UINT32 op_bits;
+ UINT32 (* handler)(UINT32, UINT64);
+} SHARC_DASM_OP;
diff --git a/src/emu/cpu/sharc/sharcmem.c b/src/emu/cpu/sharc/sharcmem.c
new file mode 100644
index 00000000000..d0ff3428983
--- /dev/null
+++ b/src/emu/cpu/sharc/sharcmem.c
@@ -0,0 +1,202 @@
+/* SHARC memory operations */
+
+static UINT32 pm_read32(UINT32 address)
+{
+ if (address >= 0x20000 && address < 0x28000)
+ {
+ UINT32 addr = (address & 0x7fff) * 3;
+
+ return (UINT32)(sharc.internal_ram_block0[addr + 0] << 16) |
+ (sharc.internal_ram_block0[addr + 1]);
+ }
+ else if (address >= 0x28000 && address < 0x40000)
+ {
+ // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff
+ UINT32 addr = (address & 0x7fff) * 3;
+
+ return (UINT32)(sharc.internal_ram_block1[addr + 0] << 16) |
+ (sharc.internal_ram_block1[addr + 1]);
+ }
+ else {
+ fatalerror("SHARC: PM Bus Read %08X at %08X", address, sharc.pc);
+ }
+}
+
+static void pm_write32(UINT32 address, UINT32 data)
+{
+ if (address >= 0x20000 && address < 0x28000)
+ {
+ UINT32 addr = (address & 0x7fff) * 3;
+
+ sharc.internal_ram_block0[addr + 0] = (UINT16)(data >> 16);
+ sharc.internal_ram_block0[addr + 1] = (UINT16)(data);
+ return;
+ }
+ else if (address >= 0x28000 && address < 0x40000)
+ {
+ // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff
+ UINT32 addr = (address & 0x7fff) * 3;
+
+ sharc.internal_ram_block1[addr + 0] = (UINT16)(data >> 16);
+ sharc.internal_ram_block1[addr + 1] = (UINT16)(data);
+ return;
+ }
+ else {
+ fatalerror("SHARC: PM Bus Write %08X, %08X at %08X", address, data, sharc.pc);
+ }
+}
+
+static UINT64 pm_read48(UINT32 address)
+{
+ if (address >= 0x20000 && address < 0x28000)
+ {
+ UINT32 addr = (address & 0x7fff) * 3;
+
+ return ((UINT64)(sharc.internal_ram_block0[addr + 0]) << 32) |
+ ((UINT64)(sharc.internal_ram_block0[addr + 1]) << 16) |
+ ((UINT64)(sharc.internal_ram_block0[addr + 2]) << 0);
+ }
+ else if (address >= 0x28000 && address < 0x40000)
+ {
+ // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff
+ UINT32 addr = (address & 0x7fff) * 3;
+
+ return ((UINT64)(sharc.internal_ram_block1[addr + 0]) << 32) |
+ ((UINT64)(sharc.internal_ram_block1[addr + 1]) << 16) |
+ ((UINT64)(sharc.internal_ram_block1[addr + 2]) << 0);
+ }
+ else {
+ fatalerror("SHARC: PM Bus Read %08X at %08X", address, sharc.pc);
+ }
+
+ return 0;
+}
+
+static void pm_write48(UINT32 address, UINT64 data)
+{
+ if (address >= 0x20000 && address < 0x28000)
+ {
+ UINT32 addr = (address & 0x7fff) * 3;
+
+ sharc.internal_ram_block0[addr + 0] = (UINT16)(data >> 32);
+ sharc.internal_ram_block0[addr + 1] = (UINT16)(data >> 16);
+ sharc.internal_ram_block0[addr + 2] = (UINT16)(data);
+ return;
+ }
+ else if (address >= 0x28000 && address < 0x40000)
+ {
+ // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff
+ UINT32 addr = (address & 0x7fff) * 3;
+
+ sharc.internal_ram_block1[addr + 0] = (UINT16)(data >> 32);
+ sharc.internal_ram_block1[addr + 1] = (UINT16)(data >> 16);
+ sharc.internal_ram_block1[addr + 2] = (UINT16)(data);
+ return;
+ }
+ else {
+ fatalerror("SHARC: PM Bus Write %08X, %04X%08X at %08X", address, (UINT16)(data >> 32),(UINT32)data, sharc.pc);
+ }
+}
+
+static UINT32 dm_read32(UINT32 address)
+{
+ if (address < 0x100)
+ {
+ return sharc_iop_r(address);
+ }
+ else if (address >= 0x20000 && address < 0x28000)
+ {
+ UINT32 addr = (address & 0x7fff) * 2;
+
+ return (UINT32)(sharc.internal_ram_block0[addr + 0] << 16) |
+ (sharc.internal_ram_block0[addr + 1]);
+ }
+ else if (address >= 0x28000 && address < 0x40000)
+ {
+ // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff
+ UINT32 addr = (address & 0x7fff) * 2;
+
+ return (UINT32)(sharc.internal_ram_block1[addr + 0] << 16) |
+ (sharc.internal_ram_block1[addr + 1]);
+ }
+
+ // short word addressing
+ else if (address >= 0x40000 && address < 0x50000)
+ {
+ UINT32 addr = address & 0xffff;
+
+ UINT16 r = sharc.internal_ram_block0[addr ^ 1];
+ if (sharc.mode1 & 0x4000)
+ {
+ // sign-extend
+ return (INT32)(INT16)(r);
+ }
+ else
+ {
+ return (UINT32)(r);
+ }
+ }
+ else if (address >= 0x50000 && address < 0x80000)
+ {
+ // block 1 is mirrored in 0x50000...5ffff, 0x60000...0x6ffff and 0x70000...7ffff
+ UINT32 addr = address & 0xffff;
+
+ UINT16 r = sharc.internal_ram_block1[addr ^ 1];
+ if (sharc.mode1 & 0x4000)
+ {
+ // sign-extend
+ return (INT32)(INT16)(r);
+ }
+ else
+ {
+ return (UINT32)(r);
+ }
+ }
+
+ return data_read_dword_32le(address << 2);
+}
+
+static void dm_write32(UINT32 address, UINT32 data)
+{
+ if (address < 0x100)
+ {
+ sharc_iop_w(address, data);
+ return;
+ }
+ else if (address >= 0x20000 && address < 0x28000)
+ {
+ UINT32 addr = (address & 0x7fff) * 2;
+
+ sharc.internal_ram_block0[addr + 0] = (UINT16)(data >> 16);
+ sharc.internal_ram_block0[addr + 1] = (UINT16)(data);
+ return;
+ }
+ else if (address >= 0x28000 && address < 0x40000)
+ {
+ // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff
+ UINT32 addr = (address & 0x7fff) * 2;
+
+ sharc.internal_ram_block1[addr + 0] = (UINT16)(data >> 16);
+ sharc.internal_ram_block1[addr + 1] = (UINT16)(data);
+ return;
+ }
+
+ // short word addressing
+ else if (address >= 0x40000 && address < 0x50000)
+ {
+ UINT32 addr = address & 0xffff;
+
+ sharc.internal_ram_block0[addr ^ 1] = data;
+ return;
+ }
+ else if (address >= 0x50000 && address < 0x80000)
+ {
+ // block 1 is mirrored in 0x50000...5ffff, 0x60000...0x6ffff and 0x70000...7ffff
+ UINT32 addr = address & 0xffff;
+
+ sharc.internal_ram_block1[addr ^ 1] = data;
+ return;
+ }
+
+ data_write_dword_32le(address << 2, data);
+}
diff --git a/src/emu/cpu/sharc/sharcops.c b/src/emu/cpu/sharc/sharcops.c
new file mode 100644
index 00000000000..1d1c7879866
--- /dev/null
+++ b/src/emu/cpu/sharc/sharcops.c
@@ -0,0 +1,2758 @@
+#define SIGN_EXTEND6(x) (((x) & 0x20) ? (0xffffffc0 | (x)) : (x))
+#define SIGN_EXTEND24(x) (((x) & 0x800000) ? (0xff000000 | (x)) : (x))
+
+#define PM_REG_I(x) (sharc.dag2.i[x])
+#define PM_REG_M(x) (sharc.dag2.m[x])
+#define PM_REG_B(x) (sharc.dag2.b[x])
+#define PM_REG_L(x) (sharc.dag2.l[x])
+#define DM_REG_I(x) (sharc.dag1.i[x])
+#define DM_REG_M(x) (sharc.dag1.m[x])
+#define DM_REG_B(x) (sharc.dag1.b[x])
+#define DM_REG_L(x) (sharc.dag1.l[x])
+
+// ASTAT flags
+#define AZ 0x1 /* ALU result zero */
+#define AV 0x2 /* ALU overflow */
+#define AN 0x4 /* ALU result negative */
+#define AC 0x8 /* ALU fixed-point carry */
+#define AS 0x10 /* ALU X input sign */
+#define AI 0x20 /* ALU floating-point invalid operation */
+#define MN 0x40 /* Multiplier result negative */
+#define MV 0x80 /* Multiplier overflow */
+#define MU 0x100 /* Multiplier underflow */
+#define MI 0x200 /* Multiplier floating-point invalid operation */
+#define AF 0x400
+#define SV 0x800 /* Shifter overflow */
+#define SZ 0x1000 /* Shifter result zero */
+#define SS 0x2000 /* Shifter input sign */
+#define BTF 0x40000 /* Bit Test Flag */
+#define FLG0 0x80000 /* FLAG0 */
+#define FLG1 0x100000 /* FLAG1 */
+#define FLG2 0x200000 /* FLAG2 */
+#define FLG3 0x400000 /* FLAG3 */
+
+// STKY flags
+#define AUS 0x1 /* ALU floating-point underflow */
+#define AVS 0x2 /* ALU floating-point overflow */
+#define AOS 0x4 /* ALU fixed-point overflow */
+#define AIS 0x20 /* ALU floating-point invalid operation */
+
+// MODE1 flags
+#define MODE1_BR8 0x1 /* Bit-reverse for I8 */
+#define MODE1_BR0 0x2 /* Bit-reverse for I0 */
+#define MODE1_SRCU 0x4 /* Alternate register select for computational units */
+#define MODE1_SRD1H 0x8 /* DAG alternate register select (7-4) */
+#define MODE1_SRD1L 0x10 /* DAG alternate register select (3-0) */
+#define MODE1_SRD2H 0x20 /* DAG alternate register select (15-12) */
+#define MODE1_SRD2L 0x40 /* DAG alternate register select (11-8) */
+#define MODE1_SRRFH 0x80 /* Register file alternate select for R(15-8) */
+#define MODE1_SRRFL 0x400 /* Register file alternate select for R(7-0) */
+#define MODE1_NESTM 0x800 /* Interrupt nesting enable */
+#define MODE1_IRPTEN 0x1000 /* Global interrupt enable */
+#define MODE1_ALUSAT 0x2000 /* Enable ALU fixed-point saturation */
+#define MODE1_SSE 0x4000 /* Enable short word sign extension */
+#define MODE1_TRUNCATE 0x8000 /* (1) Floating-point truncation / (0) round to nearest */
+#define MODE1_RND32 0x10000 /* (1) 32-bit floating-point rounding / (0) 40-bit rounding */
+#define MODE1_CSEL 0x60000 /* CSelect */
+
+// MODE2 flags
+#define MODE2_IRQ0E 0x1 /* IRQ0 (1) Edge sens. / (0) Level sens. */
+#define MODE2_IRQ1E 0x2 /* IRQ1 (1) Edge sens. / (0) Level sens. */
+#define MODE2_IRQ2E 0x4 /* IRQ2 (1) Edge sens. / (0) Level sens. */
+#define MODE2_CADIS 0x10 /* Cache disable */
+#define MODE2_TIMEN 0x20 /* Timer enable */
+#define MODE2_BUSLK 0x40 /* External bus lock */
+#define MODE2_FLG0O 0x8000 /* FLAG0 (1) Output / (0) Input */
+#define MODE2_FLG1O 0x10000 /* FLAG1 (1) Output / (0) Input */
+#define MODE2_FLG2O 0x20000 /* FLAG2 (1) Output / (0) Input */
+#define MODE2_FLG3O 0x40000 /* FLAG3 (1) Output / (0) Input */
+#define MODE2_CAFRZ 0x80000 /* Cache freeze */
+
+
+#define REG_PC 0x63
+#define REG_PCSTK 0x64
+#define REG_PCSTKP 0x65
+#define REG_LADDR 0x66
+#define REG_CURLCNTR 0x67
+#define REG_LCNTR 0x68
+#define REG_USTAT1 0x70
+#define REG_USTAT2 0x71
+#define REG_IRPTL 0x79
+#define REG_MODE2 0x7a
+#define REG_MODE1 0x7b
+#define REG_ASTAT 0x7c
+#define REG_IMASK 0x7d
+#define REG_STKY 0x7e
+#define REG_IMASKP 0x7f
+
+
+
+#define REG(x) (sharc.r[x].r)
+#define FREG(x) (sharc.r[x].f)
+
+#define UPDATE_CIRCULAR_BUFFER_PM(x) \
+ { \
+ if (PM_REG_L(x) != 0) \
+ { \
+ if (PM_REG_I(x) > PM_REG_B(x)+PM_REG_L(x)) \
+ { \
+ PM_REG_I(x) -= PM_REG_L(x); \
+ } \
+ else if (PM_REG_I(x) < PM_REG_B(x)) \
+ { \
+ PM_REG_I(x) += PM_REG_L(x); \
+ } \
+ } \
+ }
+
+#define UPDATE_CIRCULAR_BUFFER_DM(x) \
+ { \
+ if (DM_REG_L(x) != 0) \
+ { \
+ if (DM_REG_I(x) > DM_REG_B(x)+DM_REG_L(x)) \
+ { \
+ DM_REG_I(x) -= DM_REG_L(x); \
+ } \
+ else if (DM_REG_I(x) < DM_REG_B(x)) \
+ { \
+ DM_REG_I(x) += DM_REG_L(x); \
+ } \
+ } \
+ }
+
+
+/*****************************************************************************/
+
+static void systemreg_write_latency_effect(void);
+
+static void add_systemreg_write_latency_effect(int sysreg, UINT32 data, UINT32 prev_data)
+{
+ if (sharc.systemreg_latency_cycles > 0)
+ {
+ //fatalerror("SHARC: add_systemreg_write_latency_effect: already scheduled! (reg: %02X, data: %08X, PC: %08X)\n", systemreg_latency_reg, systemreg_latency_data, sharc.pc);
+ systemreg_write_latency_effect();
+ }
+
+ sharc.systemreg_latency_cycles = 2;
+ sharc.systemreg_latency_reg = sysreg;
+ sharc.systemreg_latency_data = data;
+ sharc.systemreg_previous_data = prev_data;
+}
+
+INLINE void swap_register(UINT32 *a, UINT32 *b)
+{
+ UINT32 temp = *a;
+ *a = *b;
+ *b = temp;
+}
+
+static void systemreg_write_latency_effect(void)
+{
+ int i;
+ UINT32 data = sharc.systemreg_latency_data;
+ UINT32 old_data = sharc.systemreg_previous_data;
+
+ switch(sharc.systemreg_latency_reg)
+ {
+ case 0xb: /* MODE1 */
+ {
+ UINT32 oldreg = old_data;
+ sharc.mode1 = data;
+
+ if ((data & 0x1) != (oldreg & 0x1))
+ {
+ fatalerror("SHARC: systemreg_latency_op: enable I8 bit-reversing");
+ }
+ if ((data & 0x2) != (oldreg & 0x2))
+ {
+ fatalerror("SHARC: systemreg_latency_op: enable I0 bit-reversing");
+ }
+ if ((data & 0x4) != (oldreg & 0x4))
+ {
+ fatalerror("SHARC: systemreg_latency_op: enable MR alternate");
+ }
+
+ if ((data & 0x8) != (oldreg & 0x8)) /* Switch DAG1 7-4 */
+ {
+ swap_register(&sharc.dag1.i[4], &sharc.dag1_alt.i[4]);
+ swap_register(&sharc.dag1.i[5], &sharc.dag1_alt.i[5]);
+ swap_register(&sharc.dag1.i[6], &sharc.dag1_alt.i[6]);
+ swap_register(&sharc.dag1.i[7], &sharc.dag1_alt.i[7]);
+ swap_register(&sharc.dag1.m[4], &sharc.dag1_alt.m[4]);
+ swap_register(&sharc.dag1.m[5], &sharc.dag1_alt.m[5]);
+ swap_register(&sharc.dag1.m[6], &sharc.dag1_alt.m[6]);
+ swap_register(&sharc.dag1.m[7], &sharc.dag1_alt.m[7]);
+ swap_register(&sharc.dag1.l[4], &sharc.dag1_alt.l[4]);
+ swap_register(&sharc.dag1.l[5], &sharc.dag1_alt.l[5]);
+ swap_register(&sharc.dag1.l[6], &sharc.dag1_alt.l[6]);
+ swap_register(&sharc.dag1.l[7], &sharc.dag1_alt.l[7]);
+ swap_register(&sharc.dag1.b[4], &sharc.dag1_alt.b[4]);
+ swap_register(&sharc.dag1.b[5], &sharc.dag1_alt.b[5]);
+ swap_register(&sharc.dag1.b[6], &sharc.dag1_alt.b[6]);
+ swap_register(&sharc.dag1.b[7], &sharc.dag1_alt.b[7]);
+ }
+ if ((data & 0x10) != (oldreg & 0x10)) /* Switch DAG1 3-0 */
+ {
+ swap_register(&sharc.dag1.i[0], &sharc.dag1_alt.i[0]);
+ swap_register(&sharc.dag1.i[1], &sharc.dag1_alt.i[1]);
+ swap_register(&sharc.dag1.i[2], &sharc.dag1_alt.i[2]);
+ swap_register(&sharc.dag1.i[3], &sharc.dag1_alt.i[3]);
+ swap_register(&sharc.dag1.m[0], &sharc.dag1_alt.m[0]);
+ swap_register(&sharc.dag1.m[1], &sharc.dag1_alt.m[1]);
+ swap_register(&sharc.dag1.m[2], &sharc.dag1_alt.m[2]);
+ swap_register(&sharc.dag1.m[3], &sharc.dag1_alt.m[3]);
+ swap_register(&sharc.dag1.l[0], &sharc.dag1_alt.l[0]);
+ swap_register(&sharc.dag1.l[1], &sharc.dag1_alt.l[1]);
+ swap_register(&sharc.dag1.l[2], &sharc.dag1_alt.l[2]);
+ swap_register(&sharc.dag1.l[3], &sharc.dag1_alt.l[3]);
+ swap_register(&sharc.dag1.b[0], &sharc.dag1_alt.b[0]);
+ swap_register(&sharc.dag1.b[1], &sharc.dag1_alt.b[1]);
+ swap_register(&sharc.dag1.b[2], &sharc.dag1_alt.b[2]);
+ swap_register(&sharc.dag1.b[3], &sharc.dag1_alt.b[3]);
+ }
+ if ((data & 0x20) != (oldreg & 0x20)) /* Switch DAG2 15-12 */
+ {
+ swap_register(&sharc.dag2.i[4], &sharc.dag2_alt.i[4]);
+ swap_register(&sharc.dag2.i[5], &sharc.dag2_alt.i[5]);
+ swap_register(&sharc.dag2.i[6], &sharc.dag2_alt.i[6]);
+ swap_register(&sharc.dag2.i[7], &sharc.dag2_alt.i[7]);
+ swap_register(&sharc.dag2.m[4], &sharc.dag2_alt.m[4]);
+ swap_register(&sharc.dag2.m[5], &sharc.dag2_alt.m[5]);
+ swap_register(&sharc.dag2.m[6], &sharc.dag2_alt.m[6]);
+ swap_register(&sharc.dag2.m[7], &sharc.dag2_alt.m[7]);
+ swap_register(&sharc.dag2.l[4], &sharc.dag2_alt.l[4]);
+ swap_register(&sharc.dag2.l[5], &sharc.dag2_alt.l[5]);
+ swap_register(&sharc.dag2.l[6], &sharc.dag2_alt.l[6]);
+ swap_register(&sharc.dag2.l[7], &sharc.dag2_alt.l[7]);
+ swap_register(&sharc.dag2.b[4], &sharc.dag2_alt.b[4]);
+ swap_register(&sharc.dag2.b[5], &sharc.dag2_alt.b[5]);
+ swap_register(&sharc.dag2.b[6], &sharc.dag2_alt.b[6]);
+ swap_register(&sharc.dag2.b[7], &sharc.dag2_alt.b[7]);
+ }
+ if ((data & 0x40) != (oldreg & 0x40)) /* Switch DAG2 11-8 */
+ {
+ swap_register(&sharc.dag2.i[0], &sharc.dag2_alt.i[0]);
+ swap_register(&sharc.dag2.i[1], &sharc.dag2_alt.i[1]);
+ swap_register(&sharc.dag2.i[2], &sharc.dag2_alt.i[2]);
+ swap_register(&sharc.dag2.i[3], &sharc.dag2_alt.i[3]);
+ swap_register(&sharc.dag2.m[0], &sharc.dag2_alt.m[0]);
+ swap_register(&sharc.dag2.m[1], &sharc.dag2_alt.m[1]);
+ swap_register(&sharc.dag2.m[2], &sharc.dag2_alt.m[2]);
+ swap_register(&sharc.dag2.m[3], &sharc.dag2_alt.m[3]);
+ swap_register(&sharc.dag2.l[0], &sharc.dag2_alt.l[0]);
+ swap_register(&sharc.dag2.l[1], &sharc.dag2_alt.l[1]);
+ swap_register(&sharc.dag2.l[2], &sharc.dag2_alt.l[2]);
+ swap_register(&sharc.dag2.l[3], &sharc.dag2_alt.l[3]);
+ swap_register(&sharc.dag2.b[0], &sharc.dag2_alt.b[0]);
+ swap_register(&sharc.dag2.b[1], &sharc.dag2_alt.b[1]);
+ swap_register(&sharc.dag2.b[2], &sharc.dag2_alt.b[2]);
+ swap_register(&sharc.dag2.b[3], &sharc.dag2_alt.b[3]);
+ }
+ if ((data & 0x80) != (oldreg & 0x80))
+ {
+ for (i=8; i<16; i++)
+ swap_register((UINT32*)&sharc.r[i].r, (UINT32*)&sharc.reg_alt[i].r);
+ }
+ if ((data & 0x400) != (oldreg & 0x400))
+ {
+ for (i=0; i<8; i++)
+ swap_register((UINT32*)&sharc.r[i].r, (UINT32*)&sharc.reg_alt[i].r);
+ }
+ break;
+ }
+ default: fatalerror("SHARC: systemreg_latency_op: unknown register %02X at %08X", sharc.systemreg_latency_reg, sharc.pc);
+ }
+
+ sharc.systemreg_latency_reg = -1;
+}
+
+static UINT32 GET_UREG(int ureg)
+{
+ int reg = ureg & 0xf;
+ switch((ureg >> 4) & 0xf)
+ {
+ case 0x0: /* R0 - R15 */
+ {
+ return sharc.r[reg].r;
+ }
+
+ case 0x1:
+ {
+ if (reg & 0x8) /* I8 - I15 */
+ {
+ return sharc.dag2.i[reg & 0x7];
+ }
+ else /* I0 - I7 */
+ {
+ return sharc.dag1.i[reg & 0x7];
+ }
+ }
+
+ case 0x2:
+ {
+ if (reg & 0x8) /* M8 - M15 */
+ {
+ INT32 r = sharc.dag2.m[reg & 0x7];
+ if (r & 0x800000) r |= 0xff000000;
+
+ return r;
+ }
+ else /* M0 - M7 */
+ {
+ return sharc.dag1.m[reg & 0x7];
+ }
+ }
+
+ case 0x3:
+ {
+ if (reg & 0x8) /* L8 - L15 */
+ {
+ return sharc.dag2.l[reg & 0x7];
+ }
+ else /* L0 - L7 */
+ {
+ return sharc.dag1.l[reg & 0x7];
+ }
+ }
+
+ case 0x4:
+ {
+ if (reg & 0x8) /* B8 - B15 */
+ {
+ return sharc.dag2.b[reg & 0x7];
+ }
+ else /* B0 - B7 */
+ {
+ return sharc.dag1.b[reg & 0x7];
+ }
+ }
+
+ case 0x6:
+ {
+ switch(reg)
+ {
+ case 0x4: return sharc.pcstack[sharc.pcstkp]; /* PCSTK */
+ default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X", ureg, sharc.pc);
+ }
+ break;
+ }
+
+ case 0x7:
+ {
+ switch(reg)
+ {
+ case 0x0: return sharc.ustat1; /* USTAT1 */
+ case 0x1: return sharc.ustat2; /* USTAT2 */
+ case 0x9: return sharc.irptl; /* IRPTL */
+ case 0xa: return sharc.mode2; /* MODE2 */
+ case 0xb: return sharc.mode1; /* MODE1 */
+ case 0xc: /* ASTAT */
+ {
+ UINT32 r = sharc.astat;
+ r &= ~0x00780000;
+ r |= (sharc.flag[0] << 19);
+ r |= (sharc.flag[1] << 20);
+ r |= (sharc.flag[2] << 21);
+ r |= (sharc.flag[3] << 22);
+ return r;
+ }
+ case 0xd: return sharc.imask; /* IMASK */
+ case 0xe: return sharc.stky; /* STKY */
+ default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X", ureg, sharc.pc);
+ }
+ break;
+ }
+
+ case 0xd:
+ {
+ switch(reg)
+ {
+ /* PX needs to be handled separately if the whole 48 bits are needed */
+ case 0xb: return (UINT32)(sharc.px); /* PX */
+ case 0xc: return (UINT16)(sharc.px); /* PX1 */
+ case 0xd: return (UINT32)(sharc.px >> 16); /* PX2 */
+ default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X", ureg, sharc.pc);
+ }
+ break;
+ }
+
+ default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X", ureg, sharc.pc);
+ }
+}
+
+static void SET_UREG(int ureg, UINT32 data)
+{
+ int reg = ureg & 0xf;
+ switch((ureg >> 4) & 0xf)
+ {
+ case 0x0: /* R0 - R15 */
+ sharc.r[reg].r = data;
+ break;
+
+ case 0x1:
+ if (reg & 0x8) /* I8 - I15 */
+ {
+ sharc.dag2.i[reg & 0x7] = data;
+ }
+ else /* I0 - I7 */
+ {
+ sharc.dag1.i[reg & 0x7] = data;
+ }
+ break;
+
+ case 0x2:
+ if (reg & 0x8) /* M8 - M15 */
+ {
+ sharc.dag2.m[reg & 0x7] = data;
+ }
+ else /* M0 - M7 */
+ {
+ sharc.dag1.m[reg & 0x7] = data;
+ }
+ break;
+
+ case 0x3:
+ if (reg & 0x8) /* L8 - L15 */
+ {
+ sharc.dag2.l[reg & 0x7] = data;
+ }
+ else /* L0 - L7 */
+ {
+ sharc.dag1.l[reg & 0x7] = data;
+ }
+ break;
+
+ case 0x4:
+ // Note: loading B also loads the same value in I
+ if (reg & 0x8) /* B8 - B15 */
+ {
+ sharc.dag2.b[reg & 0x7] = data;
+ sharc.dag2.i[reg & 0x7] = data;
+ }
+ else /* B0 - B7 */
+ {
+ sharc.dag1.b[reg & 0x7] = data;
+ sharc.dag1.i[reg & 0x7] = data;
+ }
+ break;
+
+ case 0x6:
+ switch (reg)
+ {
+ case 0x5: sharc.pcstkp = data; break; /* PCSTKP */
+ case 0x8: sharc.lcntr = data; break; /* LCNTR */
+ default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X", ureg, sharc.pc);
+ }
+ break;
+
+ case 0x7: /* system regs */
+ switch(reg)
+ {
+ case 0x0: sharc.ustat1 = data; break; /* USTAT1 */
+ case 0x1: sharc.ustat2 = data; break; /* USTAT2 */
+
+ case 0x9: sharc.irptl = data; break; /* IRPTL */
+ case 0xa: sharc.mode2 = data; break; /* MODE2 */
+
+ case 0xb: /* MODE1 */
+ {
+ add_systemreg_write_latency_effect(reg, data, sharc.mode1);
+ sharc.mode1 = data;
+ break;
+ }
+
+ case 0xc: sharc.astat = data; break; /* ASTAT */
+
+ case 0xd: /* IMASK */
+ {
+ check_interrupts();
+ sharc.imask = data;
+ break;
+ }
+
+ case 0xe: sharc.stky = data; break; /* STKY */
+ default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X", ureg, sharc.pc);
+ }
+ break;
+
+ case 0xd:
+ switch(reg)
+ {
+ case 0xc: sharc.px &= U64(0xffffffffffff0000); sharc.px |= (data & 0xffff); break; /* PX1 */
+ case 0xd: sharc.px &= U64(0x000000000000ffff); sharc.px |= (UINT64)data << 16; break; /* PX2 */
+ default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X", ureg, sharc.pc);
+ }
+ break;
+
+ default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X", ureg, sharc.pc);
+ }
+}
+
+/*****************************************************************************/
+#define SET_FLAG_SV_LSHIFT(x, shift) if((x) & ((UINT32)0xffffffff << shift)) sharc.astat |= SV
+#define SET_FLAG_SV_RSHIFT(x, shift) if((x) & ((UINT32)0xffffffff >> shift)) sharc.astat |= SV
+
+#define SET_FLAG_SZ(x) if((x) == 0) sharc.astat |= SZ
+
+#define MAKE_EXTRACT_MASK(start_bit, length) ((0xffffffff << start_bit) & (((UINT32)0xffffffff) >> (32 - (start_bit + length))))
+
+static void SHIFT_OPERATION_IMM(int shiftop, int data, int rn, int rx)
+{
+ INT8 shift = data & 0xff;
+ int bit = data & 0x3f;
+ int len = (data >> 6) & 0x3f;
+
+ sharc.astat &= ~(SZ|SV|SS);
+
+ switch(shiftop)
+ {
+ case 0x00: /* LSHIFT Rx BY <data8>*/
+ {
+ if(shift < 0) {
+ REG(rn) = (shift > -32 ) ? (REG(rx) >> -shift) : 0;
+ } else {
+ REG(rn) = (shift < 32) ? (REG(rx) << shift) : 0;
+ if (shift > 0)
+ {
+ sharc.astat |= SV;
+ }
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x01: /* ASHIFT Rx BY <data8> */
+ {
+ if (shift < 0)
+ {
+ REG(rn) = (shift > -32) ? ((INT32)REG(rx) >> -shift) : ((REG(rx) & 0x80000000) ? 0xffffffff : 0);
+ }
+ else
+ {
+ REG(rn) = (shift < 32) ? ((INT32)REG(rx) << shift) : 0;
+ if (shift > 0)
+ {
+ sharc.astat |= SV;
+ }
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x02: /* ROT Rx BY <data8> */
+ {
+ if (shift < 0)
+ {
+ int s = (-shift) & 0x1f;
+ REG(rn) = (((UINT32)REG(rx) >> s) & ((UINT32)(0xffffffff) >> s)) |
+ (((UINT32)REG(rx) << (32-s)) & ((UINT32)(0xffffffff) << (32-s)));
+ }
+ else
+ {
+ int s = shift & 0x1f;
+ REG(rn) = (((UINT32)REG(rx) << s) & ((UINT32)(0xffffffff) << s)) |
+ (((UINT32)REG(rx) >> (32-s)) & ((UINT32)(0xffffffff) >> (32-s)));
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x08: /* Rn = Rn OR LSHIFT Rx BY <data8> */
+ {
+ UINT32 r = 0;
+ if(shift < 0) {
+ r = (shift > -32 ) ? (REG(rx) >> -shift) : 0;
+ } else {
+ r = (shift < 32) ? (REG(rx) << shift) : 0;
+ if (shift > 0)
+ {
+ sharc.astat |= SV;
+ }
+ }
+ SET_FLAG_SZ(r);
+
+ REG(rn) = REG(rn) | r;
+ break;
+ }
+
+ case 0x10: /* FEXT Rx BY <bit6>:<len6> */
+ {
+ UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(bit, len);
+ REG(rn) = ext >> bit;
+
+ SET_FLAG_SZ(REG(rn));
+ if (bit+len > 32)
+ {
+ sharc.astat |= SV;
+ }
+ break;
+ }
+
+ case 0x12: /* FEXT Rx BY <bit6>:<len6> (Sign Extended) */
+ {
+ UINT32 ext = (REG(rx) & MAKE_EXTRACT_MASK(bit, len)) >> bit;
+ if (ext & (1 << (len-1))) {
+ ext |= (UINT32)0xffffffff << (len-1);
+ }
+ REG(rn) = ext;
+
+ SET_FLAG_SZ(REG(rn));
+ if (bit+len > 32)
+ {
+ sharc.astat |= SV;
+ }
+ break;
+ }
+
+ case 0x13: /* FDEP Rx BY Ry <bit6>:<len6> (Sign Extended) */
+ {
+ UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(0, len);
+ if (ext & (1 << (len-1))) {
+ ext |= (UINT32)0xffffffff << (len-1);
+ }
+ REG(rn) = ext << bit;
+
+ SET_FLAG_SZ(REG(rn));
+ if (bit+len > 32)
+ {
+ sharc.astat |= SV;
+ }
+ break;
+ }
+
+ case 0x19: /* Rn = Rn OR FDEP Rx BY <bit6>:<len6> */
+ {
+ UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(0, len);
+
+ REG(rn) |= ext << bit;
+
+ SET_FLAG_SZ(REG(rn));
+ if (bit+len > 32)
+ {
+ sharc.astat |= SV;
+ }
+ break;
+ }
+
+ case 0x30: /* BSET Rx BY <data8> */
+ {
+ REG(rn) = REG(rx);
+ if (data >= 0 && data < 32)
+ {
+ REG(rn) |= (1 << data);
+ }
+ else
+ {
+ sharc.astat |= SV;
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x31: /* BCLR Rx BY <data8> */
+ {
+ REG(rn) = REG(rx);
+ if (data >= 0 && data < 32)
+ {
+ REG(rn) &= ~(1 << data);
+ }
+ else
+ {
+ sharc.astat |= SV;
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x32: /* BTGL Rx BY <data8> */
+ {
+ REG(rn) = REG(rx);
+ if (data >= 0 && data < 32)
+ {
+ REG(rn) ^= (1 << data);
+ }
+ else
+ {
+ sharc.astat |= SV;
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x33: /* BTST Rx BY <data8> */
+ {
+ if (data < 32)
+ {
+ UINT32 r = REG(rx) & (1 << data);
+
+ SET_FLAG_SZ(r);
+ }
+ else
+ {
+ sharc.astat |= SZ | SV;
+ }
+ break;
+ }
+
+ default: fatalerror("SHARC: unimplemented shift operation %02X at %08X", shiftop, sharc.pc);
+ }
+}
+
+#include "compute.c"
+
+static void COMPUTE(UINT32 opcode)
+{
+ int multiop;
+ int op = (opcode >> 12) & 0xff;
+ int cu = (opcode >> 20) & 0x3;
+ int rn = (opcode >> 8) & 0xf;
+ int rx = (opcode >> 4) & 0xf;
+ int ry = (opcode >> 0) & 0xf;
+ //int rs = (opcode >> 12) & 0xf;
+ //int ra = rn;
+ //int rm = rs;
+
+ if(opcode & 0x400000) /* Multi-function opcode */
+ {
+ int fm = (opcode >> 12) & 0xf;
+ int fa = (opcode >> 8) & 0xf;
+ int fxm = (opcode >> 6) & 0x3; // registers 0 - 3
+ int fym = ((opcode >> 4) & 0x3) + 4; // registers 4 - 7
+ int fxa = ((opcode >> 2) & 0x3) + 8; // registers 8 - 11
+ int fya = (opcode & 0x3) + 12; // registers 12 - 15
+
+ multiop = (opcode >> 16) & 0x3f;
+ switch(multiop)
+ {
+ case 0x00: compute_multi_mr_to_reg(op & 0xf, rn); break;
+ case 0x01: compute_multi_reg_to_mr(op & 0xf, rn); break;
+
+ case 0x04: /* Rm = Rxm * Rym (SSFR), Ra = Rxa + Rya */
+ {
+ compute_mul_ssfr_add(fm, fxm, fym, fa, fxa, fya);
+ break;
+ }
+
+ case 0x05: /* Rm = Rxm * Rym (SSFR), Ra = Rxa - Rya */
+ {
+ compute_mul_ssfr_sub(fm, fxm, fym, fa, fxa, fya);
+ break;
+ }
+
+ case 0x18: /* Fm = Fxm * Fym, Fa = Fxa + Fya */
+ {
+ compute_fmul_fadd(fm, fxm, fym, fa, fxa, fya);
+ break;
+ }
+
+ case 0x19: /* Fm = Fxm * Fym, Fa = Fxa - Fya */
+ {
+ compute_fmul_fsub(fm, fxm, fym, fa, fxa, fya);
+ break;
+ }
+
+ case 0x1a: /* Fm = Fxm * Fym, Fa = FLOAT Fxa BY Fya */
+ {
+ compute_fmul_float_scaled(fm, fxm, fym, fa, fxa, fya);
+ break;
+ }
+
+ case 0x1b: /* Fm = Fxm * Fym, Fa = FIX Fxa BY Fya */
+ {
+ compute_fmul_fix_scaled(fm, fxm, fym, fa, fxa, fya);
+ break;
+ }
+
+ case 0x1e: /* Fm = Fxm * Fym, Fa = MAX(Fxa, Fya) */
+ {
+ compute_fmul_fmax(fm, fxm, fym, fa, fxa, fya);
+ break;
+ }
+
+ case 0x1f: /* Fm = Fxm * Fym, Fa = MIN(Fxa, Fya) */
+ {
+ compute_fmul_fmin(fm, fxm, fym, fa, fxa, fya);
+ break;
+ }
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ {
+ /* Parallel Multiplier & Dual Add/Subtract */
+ /* Floating-point */
+ int fs = (opcode >> 16) & 0xf;
+ compute_fmul_dual_fadd_fsub(fm, fxm, fym, fa, fs, fxa, fya);
+ break;
+ }
+
+ default:
+ fatalerror("SHARC: compute: multi-function opcode %02X not implemented ! (%08X, %08X)", multiop, sharc.pc, opcode);
+ break;
+ }
+ }
+ else /* Single-function opcode */
+ {
+ switch(cu)
+ {
+ /* ALU operations */
+ case 0:
+ {
+ switch(op)
+ {
+ case 0x01: compute_add(rn, rx, ry); break;
+ case 0x02: compute_sub(rn, rx, ry); break;
+ case 0x05: compute_add_ci(rn, rx, ry); break;
+ case 0x06: compute_sub_ci(rn, rx, ry); break;
+ case 0x0a: compute_comp(rx, ry); break;
+ case 0x21: compute_pass(rn, rx); break;
+ case 0x22: compute_neg(rn, rx); break;
+ case 0x29: compute_inc(rn, rx); break;
+ case 0x2a: compute_dec(rn, rx); break;
+ case 0x40: compute_and(rn, rx, ry); break;
+ case 0x41: compute_or(rn, rx, ry); break;
+ case 0x42: compute_xor(rn, rx, ry); break;
+ case 0x43: compute_not(rn, rx); break;
+ case 0x61: compute_min(rn, rx, ry); break;
+ case 0x62: compute_max(rn, rx, ry); break;
+ case 0x81: compute_fadd(rn, rx, ry); break;
+ case 0x82: compute_fsub(rn, rx, ry); break;
+ case 0x8a: compute_fcomp(rx, ry); break;
+ case 0x91: compute_fabs_plus(rn, rx, ry); break;
+ case 0xa1: compute_fpass(rn, rx); break;
+ case 0xa2: compute_fneg(rn, rx); break;
+ case 0xb0: compute_fabs(rn, rx); break;
+ case 0xbd: compute_scalb(rn, rx, ry); break;
+ case 0xc1: compute_logb(rn, rx); break;
+ case 0xc4: compute_recips(rn, rx); break;
+ case 0xc5: compute_rsqrts(rn, rx); break;
+ case 0xc9: compute_fix(rn, rx); break;
+ case 0xca: compute_float(rn, rx); break;
+ case 0xd9: compute_fix_scaled(rn, rx, ry); break;
+ case 0xda: compute_float_scaled(rn, rx, ry); break;
+ case 0xe1: compute_fmin(rn, rx, ry); break;
+ case 0xe2: compute_fmax(rn, rx, ry); break;
+ case 0xe3: compute_fclip(rn, rx, ry); break;
+
+ case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+ {
+ /* Fixed-point Dual Add/Subtract */
+ int rs = (opcode >> 12) & 0xf;
+ int ra = (opcode >> 8) & 0xf;
+ compute_dual_add_sub(ra, rs, rx, ry);
+ break;
+ }
+
+ case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
+ case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
+ {
+ /* Floating-point Dual Add/Subtract */
+ int rs = (opcode >> 12) & 0xf;
+ int ra = (opcode >> 8) & 0xf;
+ compute_dual_fadd_fsub(ra, rs, rx, ry);
+ break;
+ }
+
+ default: fatalerror("SHARC: compute: unimplemented ALU operation %02X (%08X, %08X)", op, sharc.pc, opcode);
+ }
+ break;
+ }
+
+
+ /* Multiplier operations */
+ case 1:
+ {
+ switch(op)
+ {
+ case 0x14: sharc.mrf = 0; break;
+ case 0x16: sharc.mrb = 0; break;
+
+ case 0x30: compute_fmul(rn, rx, ry); break;
+ case 0x40: compute_mul_uuin(rn, rx, ry); break;
+ case 0x70: compute_mul_ssin(rn, rx, ry); break;
+
+ case 0xb0: REG(rn) = compute_mrf_plus_mul_ssin(rx, ry); break;
+ case 0xb2: REG(rn) = compute_mrb_plus_mul_ssin(rx, ry); break;
+
+ default:
+ fatalerror("SHARC: compute: multiplier operation %02X not implemented ! (%08X, %08X)", op, sharc.pc, opcode);
+ break;
+ }
+ break;
+ }
+
+
+ /* Shifter operations */
+ case 2:
+ {
+ sharc.astat &= ~(SZ|SV|SS);
+
+ op >>= 2;
+ switch(op)
+ {
+ case 0x00: /* LSHIFT Rx BY Ry*/
+ {
+ int shift = REG(ry);
+ if(shift < 0)
+ {
+ REG(rn) = (shift > -32 ) ? (REG(rx) >> -shift) : 0;
+ }
+ else
+ {
+ REG(rn) = (shift < 32) ? (REG(rx) << shift) : 0;
+ if (shift > 0)
+ {
+ sharc.astat |= SV;
+ }
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x02: /* ROT Rx BY Ry */
+ {
+ int shift = REG(ry);
+ if (shift < 0)
+ {
+ int s = (-shift) & 0x1f;
+ REG(rn) = (((UINT32)REG(rx) >> s) & ((UINT32)(0xffffffff) >> s)) |
+ (((UINT32)REG(rx) << (32-s)) & ((UINT32)(0xffffffff) << (32-s)));
+ }
+ else
+ {
+ int s = shift & 0x1f;
+ REG(rn) = (((UINT32)REG(rx) << s) & ((UINT32)(0xffffffff) << s)) |
+ (((UINT32)REG(rx) >> (32-s)) & ((UINT32)(0xffffffff) >> (32-s)));
+ if (shift > 0)
+ {
+ sharc.astat |= SV;
+ }
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x08: /* Rn = Rn OR LSHIFT Rx BY Ry*/
+ {
+ INT8 shift = REG(ry);
+ if(shift < 0) {
+ REG(rn) = REG(rn) | ((shift > -32 ) ? (REG(rx) >> -shift) : 0);
+ } else {
+ REG(rn) = REG(rn) | ((shift < 32) ? (REG(rx) << shift) : 0);
+ if (shift > 0)
+ {
+ sharc.astat |= SV;
+ }
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x10: /* FEXT Rx BY Ry */
+ {
+ int bit = REG(ry) & 0x3f;
+ int len = (REG(ry) >> 6) & 0x3f;
+ UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(bit, len);
+ REG(rn) = ext >> bit;
+
+ SET_FLAG_SZ(REG(rn));
+ if (bit+len > 32)
+ {
+ sharc.astat |= SV;
+ }
+ break;
+ }
+
+ case 0x12: /* FEXT Rx BY Ry (Sign Extended) */
+ {
+ int bit = REG(ry) & 0x3f;
+ int len = (REG(ry) >> 6) & 0x3f;
+ UINT32 ext = (REG(rx) & MAKE_EXTRACT_MASK(bit, len)) >> bit;
+ if (ext & (1 << (len-1))) {
+ ext |= (UINT32)0xffffffff << (len-1);
+ }
+ REG(rn) = ext;
+
+ SET_FLAG_SZ(REG(rn));
+ if (bit+len > 32)
+ {
+ sharc.astat |= SV;
+ }
+ break;
+ }
+
+ case 0x19: /* Rn = Rn OR FDEP Rx BY Ry */
+ {
+ int bit = REG(ry) & 0x3f;
+ int len = (REG(ry) >> 6) & 0x3f;
+ UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(0, len);
+
+ REG(rn) |= ext << bit;
+
+ SET_FLAG_SZ(REG(rn));
+ if (bit+len > 32)
+ {
+ sharc.astat |= SV;
+ }
+ break;
+ }
+
+ case 0x30: /* BSET Rx BY Ry */
+ {
+ UINT32 shift = REG(ry);
+ REG(rn) = REG(rx);
+ if (shift >= 0 && shift < 32)
+ {
+ REG(rn) |= (1 << shift);
+ }
+ else
+ {
+ sharc.astat |= SV;
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x31: /* BCLR Rx BY Ry */
+ {
+ UINT32 shift = REG(ry);
+ REG(rn) = REG(rx);
+ if (shift >= 0 && shift < 32)
+ {
+ REG(rn) &= ~(1 << shift);
+ }
+ else
+ {
+ sharc.astat |= SV;
+ }
+ SET_FLAG_SZ(REG(rn));
+ break;
+ }
+
+ case 0x33: /* BTST Rx BY Ry */
+ {
+ UINT32 shift = REG(ry);
+ if (shift < 32)
+ {
+ UINT32 r = REG(rx) & (1 << shift);
+
+ SET_FLAG_SZ(r);
+ }
+ else
+ {
+ sharc.astat |= SZ | SV;
+ }
+ break;
+ }
+
+ default:
+ fatalerror("SHARC: compute: shift operation %02X not implemented ! (%08X, %08X)", op, sharc.pc, opcode);
+ }
+ break;
+ }
+
+ default:
+ fatalerror("SHARC: compute: invalid single-function operation %02X", cu);
+ }
+ }
+}
+
+INLINE void PUSH_PC(UINT32 pc)
+{
+ sharc.pcstkp++;
+ if(sharc.pcstkp >= 32)
+ {
+ fatalerror("SHARC: PC Stack overflow !");
+ }
+
+ if (sharc.pcstkp == 0)
+ {
+ sharc.stky |= 0x400000;
+ }
+ else
+ {
+ sharc.stky &= ~0x400000;
+ }
+
+ sharc.pcstk = pc;
+ sharc.pcstack[sharc.pcstkp] = pc;
+}
+
+INLINE UINT32 POP_PC(void)
+{
+ sharc.pcstk = sharc.pcstack[sharc.pcstkp];
+
+ if(sharc.pcstkp == 0)
+ {
+ fatalerror("SHARC: PC Stack underflow !");
+ }
+
+ sharc.pcstkp--;
+
+ if (sharc.pcstkp == 0)
+ {
+ sharc.stky |= 0x400000;
+ }
+ else
+ {
+ sharc.stky &= ~0x400000;
+ }
+
+ return sharc.pcstk;
+}
+
+INLINE UINT32 TOP_PC(void)
+{
+ return sharc.pcstack[sharc.pcstkp];
+}
+
+INLINE void PUSH_LOOP(UINT32 pc, UINT32 count)
+{
+ sharc.lstkp++;
+ if(sharc.lstkp >= 6)
+ {
+ fatalerror("SHARC: Loop Stack overflow !");
+ }
+
+ if (sharc.lstkp == 0)
+ {
+ sharc.stky |= 0x4000000;
+ }
+ else
+ {
+ sharc.stky &= ~0x4000000;
+ }
+
+ sharc.lcstack[sharc.lstkp] = count;
+ sharc.lastack[sharc.lstkp] = pc;
+ sharc.curlcntr = count;
+ sharc.laddr = pc;
+}
+
+INLINE void POP_LOOP(void)
+{
+ if(sharc.lstkp == 0)
+ {
+ fatalerror("SHARC: Loop Stack underflow !");
+ }
+
+ sharc.lstkp--;
+
+ if (sharc.lstkp == 0)
+ {
+ sharc.stky |= 0x4000000;
+ }
+ else
+ {
+ sharc.stky &= ~0x4000000;
+ }
+
+ sharc.curlcntr = sharc.lcstack[sharc.lstkp];
+ sharc.laddr = sharc.lastack[sharc.lstkp];
+}
+
+INLINE void PUSH_STATUS_STACK(void)
+{
+ sharc.status_stkp++;
+ if (sharc.status_stkp >= 5)
+ {
+ fatalerror("SHARC: Status stack overflow !");
+ }
+
+ if (sharc.status_stkp == 0)
+ {
+ sharc.stky |= 0x1000000;
+ }
+ else
+ {
+ sharc.stky &= ~0x1000000;
+ }
+
+ sharc.status_stack[sharc.status_stkp].mode1 = GET_UREG(REG_MODE1);
+ sharc.status_stack[sharc.status_stkp].astat = GET_UREG(REG_ASTAT);
+}
+
+INLINE void POP_STATUS_STACK(void)
+{
+ SET_UREG(REG_MODE1, sharc.status_stack[sharc.status_stkp].mode1);
+ SET_UREG(REG_ASTAT, sharc.status_stack[sharc.status_stkp].astat);
+
+ sharc.status_stkp--;
+ if (sharc.status_stkp < 0)
+ {
+ fatalerror("SHARC: Status stack underflow !");
+ }
+
+ if (sharc.status_stkp == 0)
+ {
+ sharc.stky |= 0x1000000;
+ }
+ else
+ {
+ sharc.stky &= ~0x1000000;
+ }
+}
+
+INLINE int IF_CONDITION_CODE(int cond)
+{
+ switch(cond)
+ {
+ case 0x00: return sharc.astat & AZ; /* EQ */
+ case 0x01: return !(sharc.astat & AZ) && (sharc.astat & AN); /* LT */
+ case 0x02: return (sharc.astat & AZ) || (sharc.astat & AN); /* LE */
+ case 0x03: return (sharc.astat & AC); /* AC */
+ case 0x04: return (sharc.astat & AV); /* AV */
+ case 0x05: return (sharc.astat & MV); /* MV */
+ case 0x06: return (sharc.astat & MN); /* MS */
+ case 0x07: return (sharc.astat & SV); /* SV */
+ case 0x08: return (sharc.astat & SZ); /* SZ */
+ case 0x09: return (sharc.flag[0] != 0); /* FLAG0 */
+ case 0x0a: return (sharc.flag[1] != 0); /* FLAG1 */
+ case 0x0b: return (sharc.flag[2] != 0); /* FLAG2 */
+ case 0x0c: return (sharc.flag[3] != 0); /* FLAG3 */
+ case 0x0d: return (sharc.astat & BTF); /* TF */
+ case 0x0e: return 0; /* BM */
+ case 0x0f: return (sharc.curlcntr!=1); /* NOT LCE */
+ case 0x10: return !(sharc.astat & AZ); /* NOT EQUAL */
+ case 0x11: return (sharc.astat & AZ) || !(sharc.astat & AN); /* GE */
+ case 0x12: return !(sharc.astat & AZ) && !(sharc.astat & AN); /* GT */
+ case 0x13: return !(sharc.astat & AC); /* NOT AC */
+ case 0x14: return !(sharc.astat & AV); /* NOT AV */
+ case 0x15: return !(sharc.astat & MV); /* NOT MV */
+ case 0x16: return !(sharc.astat & MN); /* NOT MS */
+ case 0x17: return !(sharc.astat & SV); /* NOT SV */
+ case 0x18: return !(sharc.astat & SZ); /* NOT SZ */
+ case 0x19: return (sharc.flag[0] == 0); /* NOT FLAG0 */
+ case 0x1a: return (sharc.flag[1] == 0); /* NOT FLAG1 */
+ case 0x1b: return (sharc.flag[2] == 0); /* NOT FLAG2 */
+ case 0x1c: return (sharc.flag[3] == 0); /* NOT FLAG3 */
+ case 0x1d: return !(sharc.astat & BTF); /* NOT TF */
+ case 0x1e: return 1; /* NOT BM */
+ case 0x1f: return 1; /* TRUE */
+ }
+ return 1;
+}
+
+INLINE int DO_CONDITION_CODE(int cond)
+{
+ switch(cond)
+ {
+ case 0x00: return sharc.astat & AZ; /* EQ */
+ case 0x01: return !(sharc.astat & AZ) && (sharc.astat & AN); /* LT */
+ case 0x02: return (sharc.astat & AZ) || (sharc.astat & AN); /* LE */
+ case 0x03: return (sharc.astat & AC); /* AC */
+ case 0x04: return (sharc.astat & AV); /* AV */
+ case 0x05: return (sharc.astat & MV); /* MV */
+ case 0x06: return (sharc.astat & MN); /* MS */
+ case 0x07: return (sharc.astat & SV); /* SV */
+ case 0x08: return (sharc.astat & SZ); /* SZ */
+ case 0x09: return (sharc.flag[0] != 0); /* FLAG0 */
+ case 0x0a: return (sharc.flag[1] != 0); /* FLAG1 */
+ case 0x0b: return (sharc.flag[2] != 0); /* FLAG2 */
+ case 0x0c: return (sharc.flag[3] != 0); /* FLAG3 */
+ case 0x0d: return (sharc.astat & BTF); /* TF */
+ case 0x0e: return 0; /* BM */
+ case 0x0f: return (sharc.curlcntr==1); /* LCE */
+ case 0x10: return !(sharc.astat & AZ); /* NOT EQUAL */
+ case 0x11: return (sharc.astat & AZ) || !(sharc.astat & AN); /* GE */
+ case 0x12: return !(sharc.astat & AZ) && !(sharc.astat & AN); /* GT */
+ case 0x13: return !(sharc.astat & AC); /* NOT AC */
+ case 0x14: return !(sharc.astat & AV); /* NOT AV */
+ case 0x15: return !(sharc.astat & MV); /* NOT MV */
+ case 0x16: return !(sharc.astat & MN); /* NOT MS */
+ case 0x17: return !(sharc.astat & SV); /* NOT SV */
+ case 0x18: return !(sharc.astat & SZ); /* NOT SZ */
+ case 0x19: return (sharc.flag[0] == 0); /* NOT FLAG0 */
+ case 0x1a: return (sharc.flag[1] == 0); /* NOT FLAG1 */
+ case 0x1b: return (sharc.flag[2] == 0); /* NOT FLAG2 */
+ case 0x1c: return (sharc.flag[3] == 0); /* NOT FLAG3 */
+ case 0x1d: return !(sharc.astat & BTF); /* NOT TF */
+ case 0x1e: return 1; /* NOT BM */
+ case 0x1f: return 0; /* FALSE (FOREVER) */
+ }
+ return 1;
+}
+
+/*****************************************************************************/
+/* | 001xxxxxx | */
+
+/* compute / dreg <-> DM / dreg <-> PM */
+static void sharcop_compute_dreg_dm_dreg_pm(void)
+{
+ int pm_dreg = (sharc.opcode >> 23) & 0xf;
+ int pmm = (sharc.opcode >> 27) & 0x7;
+ int pmi = (sharc.opcode >> 30) & 0x7;
+ int dm_dreg = (sharc.opcode >> 33) & 0xf;
+ int dmm = (sharc.opcode >> 38) & 0x7;
+ int dmi = (sharc.opcode >> 41) & 0x7;
+ int pmd = (sharc.opcode >> 37) & 0x1;
+ int dmd = (sharc.opcode >> 44) & 0x1;
+ int compute = sharc.opcode & 0x7fffff;
+
+ /* due to parallelity issues, source DREGs must be saved */
+ /* because the compute operation may change them */
+ UINT32 parallel_pm_dreg = REG(pm_dreg);
+ UINT32 parallel_dm_dreg = REG(dm_dreg);
+
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (pmd) // dreg -> PM
+ {
+ pm_write32(PM_REG_I(pmi), parallel_pm_dreg);
+ PM_REG_I(pmi) += PM_REG_M(pmm);
+ UPDATE_CIRCULAR_BUFFER_PM(pmi);
+ }
+ else // PM -> dreg
+ {
+ REG(pm_dreg) = pm_read32(PM_REG_I(pmi));
+ PM_REG_I(pmi) += PM_REG_M(pmm);
+ UPDATE_CIRCULAR_BUFFER_PM(pmi);
+ }
+
+ if (dmd) // dreg -> DM
+ {
+ dm_write32(DM_REG_I(dmi), parallel_dm_dreg);
+ DM_REG_I(dmi) += DM_REG_M(dmm);
+ UPDATE_CIRCULAR_BUFFER_DM(dmi);
+ }
+ else // DM -> dreg
+ {
+ REG(dm_dreg) = dm_read32(DM_REG_I(dmi));
+ DM_REG_I(dmi) += DM_REG_M(dmm);
+ UPDATE_CIRCULAR_BUFFER_DM(dmi);
+ }
+}
+
+/*****************************************************************************/
+/* | 00000001x | */
+
+/* compute */
+static void sharcop_compute(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int compute = sharc.opcode & 0x7fffff;
+
+ if (IF_CONDITION_CODE(cond) && compute != 0)
+ {
+ COMPUTE(compute);
+ }
+}
+
+/*****************************************************************************/
+/* | 010xxxxxx | */
+
+/* compute / ureg <-> DM|PM, pre-modify */
+static void sharcop_compute_ureg_dmpm_premod(void)
+{
+ int i = (sharc.opcode >> 41) & 0x7;
+ int m = (sharc.opcode >> 38) & 0x7;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int g = (sharc.opcode >> 32) & 0x1;
+ int d = (sharc.opcode >> 31) & 0x1;
+ int ureg = (sharc.opcode >> 23) & 0xff;
+ int compute = sharc.opcode & 0x7fffff;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ /* due to parallelity issues, source UREG must be saved */
+ /* because the compute operation may change it */
+ UINT32 parallel_ureg = GET_UREG(ureg);
+
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (g) /* PM */
+ {
+ if (d) /* ureg -> PM */
+ {
+ if (ureg == 0xdb) /* PX register access is always 48-bit */
+ {
+ pm_write48(PM_REG_I(i)+PM_REG_M(m), sharc.px);
+ }
+ else
+ {
+ pm_write32(PM_REG_I(i)+PM_REG_M(m), parallel_ureg);
+ }
+ }
+ else /* PM <- ureg */
+ {
+ if (ureg == 0xdb) /* PX register access is always 48-bit */
+ {
+ sharc.px = pm_read48(PM_REG_I(i)+PM_REG_M(m));
+ }
+ else
+ {
+ SET_UREG(ureg, pm_read32(PM_REG_I(i)+PM_REG_M(m)));
+ }
+ }
+ }
+ else /* DM */
+ {
+ if (d) /* ureg -> DM */
+ {
+ dm_write32(DM_REG_I(i)+DM_REG_M(m), parallel_ureg);
+ }
+ else /* DM <- ureg */
+ {
+ SET_UREG(ureg, dm_read32(DM_REG_I(i)+DM_REG_M(m)));
+ }
+ }
+ }
+}
+
+/* compute / ureg <-> DM|PM, post-modify */
+static void sharcop_compute_ureg_dmpm_postmod(void)
+{
+ int i = (sharc.opcode >> 41) & 0x7;
+ int m = (sharc.opcode >> 38) & 0x7;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int g = (sharc.opcode >> 32) & 0x1;
+ int d = (sharc.opcode >> 31) & 0x1;
+ int ureg = (sharc.opcode >> 23) & 0xff;
+ int compute = sharc.opcode & 0x7fffff;
+
+ if(IF_CONDITION_CODE(cond))
+ {
+ /* due to parallelity issues, source UREG must be saved */
+ /* because the compute operation may change it */
+ UINT32 parallel_ureg = GET_UREG(ureg);
+
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (g) /* PM */
+ {
+ if (d) /* ureg -> PM */
+ {
+ if (ureg == 0xdb) /* PX register access is always 48-bit */
+ {
+ pm_write48(PM_REG_I(i), sharc.px);
+ }
+ else
+ {
+ pm_write32(PM_REG_I(i), parallel_ureg);
+ }
+ PM_REG_I(i) += PM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_PM(i);
+ }
+ else /* PM <- ureg */
+ {
+ if (ureg == 0xdb) /* PX register access is always 48-bit */
+ {
+ sharc.px = pm_read48(PM_REG_I(i));
+ }
+ else
+ {
+ SET_UREG(ureg, pm_read32(PM_REG_I(i)));
+ }
+ PM_REG_I(i) += PM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_PM(i);
+ }
+ }
+ else /* DM */
+ {
+ if (d) /* ureg -> DM */
+ {
+ dm_write32(DM_REG_I(i), parallel_ureg);
+ DM_REG_I(i) += DM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_DM(i);
+ }
+ else /* DM <- ureg */
+ {
+ SET_UREG(ureg, dm_read32(DM_REG_I(i)));
+ DM_REG_I(i) += DM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_DM(i);
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 0110xxxxx | */
+
+/* compute / dreg <- DM, immediate modify */
+static void sharcop_compute_dm_to_dreg_immmod(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int u = (sharc.opcode >> 38) & 0x1;
+ int dreg = (sharc.opcode >> 23) & 0xf;
+ int i = (sharc.opcode >> 41) & 0x7;
+ int mod = SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f);
+ int compute = sharc.opcode & 0x7fffff;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute != 0)
+ {
+ COMPUTE(compute);
+ }
+
+ if (u) /* post-modify with update */
+ {
+ REG(dreg) = dm_read32(DM_REG_I(i));
+ DM_REG_I(i) += mod;
+ UPDATE_CIRCULAR_BUFFER_DM(i);
+ }
+ else /* pre-modify, no update */
+ {
+ REG(dreg) = dm_read32(DM_REG_I(i) + mod);
+ }
+ }
+}
+
+/* compute / dreg -> DM, immediate modify */
+static void sharcop_compute_dreg_to_dm_immmod(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int u = (sharc.opcode >> 38) & 0x1;
+ int dreg = (sharc.opcode >> 23) & 0xf;
+ int i = (sharc.opcode >> 41) & 0x7;
+ int mod = SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f);
+ int compute = sharc.opcode & 0x7fffff;
+
+ /* due to parallelity issues, source REG must be saved */
+ /* because the shift operation may change it */
+ UINT32 parallel_dreg = REG(dreg);
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute != 0)
+ {
+ COMPUTE(compute);
+ }
+
+ if (u) /* post-modify with update */
+ {
+ dm_write32(DM_REG_I(i), parallel_dreg);
+ DM_REG_I(i) += mod;
+ UPDATE_CIRCULAR_BUFFER_DM(i);
+ }
+ else /* pre-modify, no update */
+ {
+ dm_write32(DM_REG_I(i) + mod, parallel_dreg);
+ }
+ }
+}
+
+/* compute / dreg <- PM, immediate modify */
+static void sharcop_compute_pm_to_dreg_immmod(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int u = (sharc.opcode >> 38) & 0x1;
+ int dreg = (sharc.opcode >> 23) & 0xf;
+ int i = (sharc.opcode >> 41) & 0x7;
+ int mod = SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f);
+ int compute = sharc.opcode & 0x7fffff;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute != 0)
+ {
+ COMPUTE(compute);
+ }
+
+ if (u) /* post-modify with update */
+ {
+ REG(dreg) = pm_read32(PM_REG_I(i));
+ PM_REG_I(i) += mod;
+ UPDATE_CIRCULAR_BUFFER_PM(i);
+ }
+ else /* pre-modify, no update */
+ {
+ REG(dreg) = pm_read32(PM_REG_I(i) + mod);
+ }
+ }
+}
+
+/* compute / dreg -> PM, immediate modify */
+static void sharcop_compute_dreg_to_pm_immmod(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int u = (sharc.opcode >> 38) & 0x1;
+ int dreg = (sharc.opcode >> 23) & 0xf;
+ int i = (sharc.opcode >> 41) & 0x7;
+ int mod = SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f);
+ int compute = sharc.opcode & 0x7fffff;
+
+ /* due to parallelity issues, source REG must be saved */
+ /* because the compute operation may change it */
+ UINT32 parallel_dreg = REG(dreg);
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute != 0)
+ {
+ COMPUTE(compute);
+ }
+
+ if (u) /* post-modify with update */
+ {
+ pm_write32(PM_REG_I(i), parallel_dreg);
+ PM_REG_I(i) += mod;
+ UPDATE_CIRCULAR_BUFFER_PM(i);
+ }
+ else /* pre-modify, no update */
+ {
+ pm_write32(PM_REG_I(i) + mod, parallel_dreg);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 0111xxxxx | */
+
+/* compute / ureg <-> ureg */
+static void sharcop_compute_ureg_to_ureg(void)
+{
+ int src_ureg = (sharc.opcode >> 36) & 0xff;
+ int dst_ureg = (sharc.opcode >> 23) & 0xff;
+ int cond = (sharc.opcode >> 31) & 0x1f;
+ int compute = sharc.opcode & 0x7fffff;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ /* due to parallelity issues, source UREG must be saved */
+ /* because the compute operation may change it */
+ UINT32 parallel_ureg = GET_UREG(src_ureg);
+
+ if (compute != 0)
+ {
+ COMPUTE(compute);
+ }
+
+ SET_UREG(dst_ureg, parallel_ureg);
+ }
+}
+
+/*****************************************************************************/
+/* | 1000xxxxx | */
+
+/* immediate shift / dreg <-> DM|PM */
+static void sharcop_imm_shift_dreg_dmpm(void)
+{
+ int i = (sharc.opcode >> 41) & 0x7;
+ int m = (sharc.opcode >> 38) & 0x7;
+ int g = (sharc.opcode >> 32) & 0x1;
+ int d = (sharc.opcode >> 31) & 0x1;
+ int dreg = (sharc.opcode >> 23) & 0xf;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int data = ((sharc.opcode >> 8) & 0xff) | ((sharc.opcode >> 19) & 0xf00);
+ int shiftop = (sharc.opcode >> 16) & 0x3f;
+ int rn = (sharc.opcode >> 4) & 0xf;
+ int rx = (sharc.opcode & 0xf);
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ /* due to parallelity issues, source REG must be saved */
+ /* because the shift operation may change it */
+ UINT32 parallel_dreg = REG(dreg);
+
+ SHIFT_OPERATION_IMM(shiftop, data, rn, rx);
+
+ if (g) /* PM */
+ {
+ if (d) /* dreg -> PM */
+ {
+ pm_write32(PM_REG_I(i), parallel_dreg);
+ PM_REG_I(i) += PM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_PM(i);
+ }
+ else /* PM <- dreg */
+ {
+ REG(dreg) = pm_read32(PM_REG_I(i));
+ PM_REG_I(i) += PM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_PM(i);
+ }
+ }
+ else /* DM */
+ {
+ if (d) /* dreg -> DM */
+ {
+ dm_write32(DM_REG_I(i), parallel_dreg);
+ DM_REG_I(i) += DM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_DM(i);
+ }
+ else /* DM <- dreg */
+ {
+ REG(dreg) = dm_read32(DM_REG_I(i));
+ DM_REG_I(i) += DM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_DM(i);
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 00000010x | */
+
+/* immediate shift */
+static void sharcop_imm_shift(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int data = ((sharc.opcode >> 8) & 0xff) | ((sharc.opcode >> 19) & 0xf00);
+ int shiftop = (sharc.opcode >> 16) & 0x3f;
+ int rn = (sharc.opcode >> 4) & 0xf;
+ int rx = (sharc.opcode & 0xf);
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ SHIFT_OPERATION_IMM(shiftop, data, rn, rx);
+ }
+}
+
+/*****************************************************************************/
+/* | 00000100x | */
+
+/* compute / modify */
+static void sharcop_compute_modify(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int compute = sharc.opcode & 0x7fffff;
+ int g = (sharc.opcode >> 38) & 0x1;
+ int m = (sharc.opcode >> 27) & 0x7;
+ int i = (sharc.opcode >> 30) & 0x7;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute != 0)
+ {
+ COMPUTE(compute);
+ }
+
+ if (g) /* Modify PM */
+ {
+ PM_REG_I(i) += PM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_PM(i);
+ }
+ else /* Modify DM */
+ {
+ DM_REG_I(i) += DM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_DM(i);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 00000110x | */
+
+/* direct call to absolute address */
+static void sharcop_direct_call(void)
+{
+ int j = (sharc.opcode >> 26) & 0x1;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ UINT32 address = sharc.opcode & 0xffffff;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (j)
+ {
+ //PUSH_PC(sharc.pc+3); /* 1 instruction + 2 delayed instructions */
+ PUSH_PC(sharc.nfaddr); /* 1 instruction + 2 delayed instructions */
+ CHANGE_PC_DELAYED(address);
+ }
+ else
+ {
+ //PUSH_PC(sharc.pc+1);
+ PUSH_PC(sharc.daddr);
+ CHANGE_PC(address);
+ }
+ }
+}
+
+/* direct jump to absolute address */
+static void sharcop_direct_jump(void)
+{
+ int la = (sharc.opcode >> 38) & 0x1;
+ int ci = (sharc.opcode >> 24) & 0x1;
+ int j = (sharc.opcode >> 26) & 0x1;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ UINT32 address = sharc.opcode & 0xffffff;
+
+ if(IF_CONDITION_CODE(cond))
+ {
+ // Clear Interrupt
+ if (ci)
+ {
+ // TODO: anything else?
+ if (sharc.status_stkp > 0)
+ {
+ POP_STATUS_STACK();
+ }
+
+ sharc.interrupt_active = 0;
+ sharc.irptl &= ~(1 << sharc.active_irq_num);
+ }
+
+ if (la)
+ {
+ POP_PC();
+ POP_LOOP();
+ }
+
+ if (j)
+ {
+ CHANGE_PC_DELAYED(address);
+ }
+ else
+ {
+ CHANGE_PC(address);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 00000111x | */
+
+/* direct call to relative address */
+static void sharcop_relative_call(void)
+{
+ int j = (sharc.opcode >> 26) & 0x1;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ UINT32 address = sharc.opcode & 0xffffff;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (j)
+ {
+ PUSH_PC(sharc.pc+3); /* 1 instruction + 2 delayed instructions */
+ CHANGE_PC_DELAYED(sharc.pc + SIGN_EXTEND24(address));
+ }
+ else
+ {
+ PUSH_PC(sharc.pc+1);
+ CHANGE_PC(sharc.pc + SIGN_EXTEND24(address));
+ }
+ }
+}
+
+/* direct jump to relative address */
+static void sharcop_relative_jump(void)
+{
+ int la = (sharc.opcode >> 38) & 0x1;
+ int ci = (sharc.opcode >> 24) & 0x1;
+ int j = (sharc.opcode >> 26) & 0x1;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ UINT32 address = sharc.opcode & 0xffffff;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ // Clear Interrupt
+ if (ci)
+ {
+ // TODO: anything else?
+ if (sharc.status_stkp > 0)
+ {
+ POP_STATUS_STACK();
+ }
+
+ sharc.interrupt_active = 0;
+ sharc.irptl &= ~(1 << sharc.active_irq_num);
+ }
+
+ if (la)
+ {
+ POP_PC();
+ POP_LOOP();
+ }
+
+ if (j)
+ {
+ CHANGE_PC_DELAYED(sharc.pc + SIGN_EXTEND24(address));
+ }
+ else
+ {
+ CHANGE_PC(sharc.pc + SIGN_EXTEND24(address));
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 00001000x | */
+
+/* indirect jump */
+static void sharcop_indirect_jump(void)
+{
+ int la = (sharc.opcode >> 38) & 0x1;
+ int ci = (sharc.opcode >> 24) & 0x1;
+ int j = (sharc.opcode >> 26) & 0x1;
+ int e = (sharc.opcode >> 25) & 0x1;
+ int pmi = (sharc.opcode >> 30) & 0x7;
+ int pmm = (sharc.opcode >> 27) & 0x7;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int compute = sharc.opcode & 0x7fffff;
+
+ // Clear Interrupt
+ if (ci)
+ {
+ // TODO: anything else?
+ if (sharc.status_stkp > 0)
+ {
+ POP_STATUS_STACK();
+ }
+
+ sharc.interrupt_active = 0;
+ sharc.irptl &= ~(1 << sharc.active_irq_num);
+ }
+
+ if (e) /* IF...ELSE */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (la)
+ {
+ POP_PC();
+ POP_LOOP();
+ }
+
+ if(j)
+ {
+ CHANGE_PC_DELAYED(PM_REG_I(pmi) + PM_REG_M(pmm));
+ }
+ else
+ {
+ CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm));
+ }
+ }
+ else
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+ }
+ }
+ else /* IF */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (la)
+ {
+ POP_PC();
+ POP_LOOP();
+ }
+
+ if(j)
+ {
+ CHANGE_PC_DELAYED(PM_REG_I(pmi) + PM_REG_M(pmm));
+ }
+ else
+ {
+ CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm));
+ }
+ }
+ }
+}
+
+/* indirect call */
+static void sharcop_indirect_call(void)
+{
+ int j = (sharc.opcode >> 26) & 0x1;
+ int e = (sharc.opcode >> 25) & 0x1;
+ int pmi = (sharc.opcode >> 30) & 0x7;
+ int pmm = (sharc.opcode >> 27) & 0x7;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int compute = sharc.opcode & 0x7fffff;
+
+ if (e) /* IF...ELSE */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (j)
+ {
+ //PUSH_PC(sharc.pc+3); /* 1 instruction + 2 delayed instructions */
+ PUSH_PC(sharc.nfaddr); /* 1 instruction + 2 delayed instructions */
+ CHANGE_PC_DELAYED(PM_REG_I(pmi) + PM_REG_M(pmm));
+ }
+ else
+ {
+ //PUSH_PC(sharc.pc+1);
+ PUSH_PC(sharc.daddr);
+ CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm));
+ }
+ }
+ else
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+ }
+ }
+ else /* IF */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (j)
+ {
+ //PUSH_PC(sharc.pc+3); /* 1 instruction + 2 delayed instructions */
+ PUSH_PC(sharc.nfaddr); /* 1 instruction + 2 delayed instructions */
+ CHANGE_PC_DELAYED(PM_REG_I(pmi) + PM_REG_M(pmm));
+ }
+ else
+ {
+ //PUSH_PC(sharc.pc+1);
+ PUSH_PC(sharc.daddr);
+ CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm));
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 00001001x | */
+
+/* indirect jump to relative address */
+static void sharcop_relative_jump_compute(void)
+{
+ int la = (sharc.opcode >> 38) & 0x1;
+ int ci = (sharc.opcode >> 24) & 0x1;
+ int j = (sharc.opcode >> 26) & 0x1;
+ int e = (sharc.opcode >> 25) & 0x1;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int compute = sharc.opcode & 0x7fffff;
+
+ // Clear Interrupt
+ if (ci)
+ {
+ // TODO: anything else?
+ if (sharc.status_stkp > 0)
+ {
+ POP_STATUS_STACK();
+ }
+
+ sharc.interrupt_active = 0;
+ sharc.irptl &= ~(1 << sharc.active_irq_num);
+ }
+
+ if (e) /* IF...ELSE */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (la)
+ {
+ POP_PC();
+ POP_LOOP();
+ }
+
+ if (j)
+ {
+ CHANGE_PC_DELAYED(sharc.pc + SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f));
+ }
+ else
+ {
+ CHANGE_PC(sharc.pc + SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f));
+ }
+ }
+ else
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+ }
+ }
+ else /* IF */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (la)
+ {
+ POP_PC();
+ POP_LOOP();
+ }
+
+ if (j)
+ {
+ CHANGE_PC_DELAYED(sharc.pc + SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f));
+ }
+ else
+ {
+ CHANGE_PC(sharc.pc + SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f));
+ }
+ }
+ }
+}
+
+/* indirect call to relative address */
+static void sharcop_relative_call_compute(void)
+{
+ int j = (sharc.opcode >> 26) & 0x1;
+ int e = (sharc.opcode >> 25) & 0x1;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int compute = sharc.opcode & 0x7fffff;
+
+ if (e) /* IF...ELSE */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (j)
+ {
+ //PUSH_PC(sharc.pc+3); /* 1 instruction + 2 delayed instructions */
+ PUSH_PC(sharc.nfaddr); /* 1 instruction + 2 delayed instructions */
+ CHANGE_PC_DELAYED(sharc.pc + SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f));
+ }
+ else
+ {
+ //PUSH_PC(sharc.pc+1);
+ PUSH_PC(sharc.daddr);
+ CHANGE_PC(sharc.pc + SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f));
+ }
+ }
+ else
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+ }
+ }
+ else /* IF */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (j)
+ {
+ //PUSH_PC(sharc.pc+3); /* 1 instruction + 2 delayed instructions */
+ PUSH_PC(sharc.nfaddr); /* 1 instruction + 2 delayed instructions */
+ CHANGE_PC_DELAYED(sharc.pc + SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f));
+ }
+ else
+ {
+ //PUSH_PC(sharc.pc+1);
+ PUSH_PC(sharc.daddr);
+ CHANGE_PC(sharc.pc + SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f));
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 110xxxxxx | */
+
+/* indirect jump / compute / dreg <-> DM */
+static void sharcop_indirect_jump_compute_dreg_dm(void)
+{
+ int d = (sharc.opcode >> 44) & 0x1;
+ int dmi = (sharc.opcode >> 41) & 0x7;
+ int dmm = (sharc.opcode >> 38) & 0x7;
+ int pmi = (sharc.opcode >> 30) & 0x7;
+ int pmm = (sharc.opcode >> 27) & 0x7;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int dreg = (sharc.opcode >> 23) & 0xf;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm));
+ }
+ else
+ {
+ UINT32 compute = sharc.opcode & 0x7fffff;
+ /* due to parallelity issues, source REG must be saved */
+ /* because the compute operation may change it */
+ UINT32 parallel_dreg = REG(dreg);
+
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (d) /* dreg -> DM */
+ {
+ dm_write32(DM_REG_I(dmi), parallel_dreg);
+ DM_REG_I(dmi) += DM_REG_M(dmm);
+ UPDATE_CIRCULAR_BUFFER_DM(dmi);
+ }
+ else /* DM <- dreg */
+ {
+ REG(dreg) = dm_read32(DM_REG_I(dmi));
+ DM_REG_I(dmi) += DM_REG_M(dmm);
+ UPDATE_CIRCULAR_BUFFER_DM(dmi);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 111xxxxxx | */
+
+/* relative jump / compute / dreg <-> DM */
+static void sharcop_relative_jump_compute_dreg_dm(void)
+{
+ int d = (sharc.opcode >> 44) & 0x1;
+ int dmi = (sharc.opcode >> 41) & 0x7;
+ int dmm = (sharc.opcode >> 38) & 0x7;
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int dreg = (sharc.opcode >> 23) & 0xf;
+
+ if (IF_CONDITION_CODE(cond))
+ {
+ CHANGE_PC(sharc.pc + SIGN_EXTEND6((sharc.opcode >> 27) & 0x3f));
+ }
+ else
+ {
+ UINT32 compute = sharc.opcode & 0x7fffff;
+ /* due to parallelity issues, source REG must be saved */
+ /* because the compute operation may change it */
+ UINT32 parallel_dreg = REG(dreg);
+
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (d) /* dreg -> DM */
+ {
+ dm_write32(DM_REG_I(dmi), parallel_dreg);
+ DM_REG_I(dmi) += DM_REG_M(dmm);
+ UPDATE_CIRCULAR_BUFFER_DM(dmi);
+ }
+ else /* DM <- dreg */
+ {
+ REG(dreg) = dm_read32(DM_REG_I(dmi));
+ DM_REG_I(dmi) += DM_REG_M(dmm);
+ UPDATE_CIRCULAR_BUFFER_DM(dmi);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 00001010x | */
+
+/* return from subroutine / compute */
+static void sharcop_rts(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int j = (sharc.opcode >> 26) & 0x1;
+ int e = (sharc.opcode >> 25) & 0x1;
+ //int lr = (sharc.opcode >> 24) & 0x1;
+ int compute = sharc.opcode & 0x7fffff;
+
+ //if(lr)
+ // fatalerror("SHARC: rts: loop reentry not implemented !");
+
+ if (e) /* IF...ELSE */
+ {
+ if(IF_CONDITION_CODE(cond))
+ {
+ if (j)
+ {
+ CHANGE_PC_DELAYED(POP_PC());
+ }
+ else
+ {
+ CHANGE_PC(POP_PC());
+ }
+ }
+ else
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+ }
+ }
+ else /* IF */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (j)
+ {
+ CHANGE_PC_DELAYED(POP_PC());
+ }
+ else
+ {
+ CHANGE_PC(POP_PC());
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+/* | 00001011x | */
+
+/* return from interrupt / compute */
+static void sharcop_rti(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int j = (sharc.opcode >> 26) & 0x1;
+ int e = (sharc.opcode >> 25) & 0x1;
+ int compute = sharc.opcode & 0x7fffff;
+
+ sharc.irptl &= ~(1 << sharc.active_irq_num);
+
+ if(e) /* IF...ELSE */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (j)
+ {
+ CHANGE_PC_DELAYED(POP_PC());
+ }
+ else
+ {
+ CHANGE_PC(POP_PC());
+ }
+ }
+ else
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+ }
+ }
+ else /* IF */
+ {
+ if (IF_CONDITION_CODE(cond))
+ {
+ if (compute)
+ {
+ COMPUTE(compute);
+ }
+
+ if (j)
+ {
+ CHANGE_PC_DELAYED(POP_PC());
+ }
+ else
+ {
+ CHANGE_PC(POP_PC());
+ }
+ }
+ }
+
+ if (sharc.status_stkp > 0)
+ {
+ POP_STATUS_STACK();
+ }
+
+ sharc.interrupt_active = 0;
+ check_interrupts();
+}
+
+/*****************************************************************************/
+/* | 00001100x | */
+
+/* do until counter expired, LCNTR immediate */
+static void sharcop_do_until_counter_imm(void)
+{
+ UINT16 data = (UINT16)(sharc.opcode >> 24);
+ int offset = SIGN_EXTEND24(sharc.opcode & 0xffffff);
+ UINT32 address = sharc.pc + offset;
+ int type;
+ int cond = 0xf; /* until LCE (loop counter expired */
+ int distance = abs(offset);
+
+ if (distance == 1)
+ {
+ type = 1;
+ }
+ else if (distance == 2)
+ {
+ type = 2;
+ }
+ else
+ {
+ type = 3;
+ }
+
+ sharc.lcntr = data;
+ if (sharc.lcntr > 0)
+ {
+ PUSH_PC(sharc.pc+1);
+ PUSH_LOOP(address | (type << 30) | (cond << 24), sharc.lcntr);
+ }
+}
+
+/*****************************************************************************/
+/* | 00001101x | */
+
+/* do until counter expired, LCNTR from UREG */
+static void sharcop_do_until_counter_ureg(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ int offset = SIGN_EXTEND24(sharc.opcode & 0xffffff);
+ UINT32 address = sharc.pc + offset;
+ int type;
+ int cond = 0xf; /* until LCE (loop counter expired */
+ int distance = abs(offset);
+
+ if (distance == 1)
+ {
+ type = 1;
+ }
+ else if (distance == 2)
+ {
+ type = 2;
+ }
+ else
+ {
+ type = 3;
+ }
+
+ sharc.lcntr = GET_UREG(ureg);
+ if (sharc.lcntr > 0)
+ {
+ PUSH_PC(sharc.pc+1);
+ PUSH_LOOP(address | (type << 30) | (cond << 24), sharc.lcntr);
+ }
+}
+
+/*****************************************************************************/
+/* | 00001110x | */
+
+/* do until */
+static void sharcop_do_until(void)
+{
+ int cond = (sharc.opcode >> 33) & 0x1f;
+ int offset = SIGN_EXTEND24(sharc.opcode & 0xffffff);
+ UINT32 address = (sharc.pc + offset);
+
+ PUSH_PC(sharc.pc+1);
+ PUSH_LOOP(address | (cond << 24), 0);
+}
+
+/*****************************************************************************/
+/* | 000100 | G | D | */
+
+/* ureg <- DM (direct addressing) */
+static void sharcop_dm_to_ureg_direct(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ UINT32 address = (UINT32)(sharc.opcode);
+
+ SET_UREG(ureg, dm_read32(address));
+}
+
+/* ureg -> DM (direct addressing) */
+static void sharcop_ureg_to_dm_direct(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ UINT32 address = (UINT32)(sharc.opcode);
+
+ dm_write32(address, GET_UREG(ureg));
+}
+
+/* ureg <- PM (direct addressing) */
+static void sharcop_pm_to_ureg_direct(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ UINT32 address = (UINT32)(sharc.opcode);
+
+ if (ureg == 0xdb) // PX is 48-bit
+ {
+ sharc.px = pm_read48(address);
+ }
+ else
+ {
+ SET_UREG(ureg, pm_read32(address));
+ }
+}
+
+/* ureg -> PM (direct addressing) */
+static void sharcop_ureg_to_pm_direct(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ UINT32 address = (UINT32)(sharc.opcode);
+
+ if (ureg == 0xdb) // PX is 48-bit
+ {
+ pm_write48(address, sharc.px);
+ }
+ else
+ {
+ pm_write32(address, GET_UREG(ureg));
+ }
+}
+
+/*****************************************************************************/
+/* | 101 | G | III | D | */
+
+/* ureg <- DM (indirect addressing) */
+static void sharcop_dm_to_ureg_indirect(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ UINT32 offset = (UINT32)sharc.opcode;
+ int i = (sharc.opcode >> 41) & 0x7;
+
+ SET_UREG(ureg, dm_read32(DM_REG_I(i) + offset));
+}
+
+/* ureg -> DM (indirect addressing) */
+static void sharcop_ureg_to_dm_indirect(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ UINT32 offset = (UINT32)sharc.opcode;
+ int i = (sharc.opcode >> 41) & 0x7;
+
+ dm_write32(DM_REG_I(i) + offset, GET_UREG(ureg));
+}
+
+/* ureg <- PM (indirect addressing) */
+static void sharcop_pm_to_ureg_indirect(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ UINT32 offset = sharc.opcode & 0xffffff;
+ int i = (sharc.opcode >> 41) & 0x7;
+
+ if (ureg == 0xdb) /* PX is 48-bit */
+ {
+ sharc.px = pm_read48(PM_REG_I(i) + offset);
+ }
+ else
+ {
+ SET_UREG(ureg, pm_read32(PM_REG_I(i) + offset));
+ }
+}
+
+/* ureg -> PM (indirect addressing) */
+static void sharcop_ureg_to_pm_indirect(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ UINT32 offset = (UINT32)sharc.opcode;
+ int i = (sharc.opcode >> 41) & 0x7;
+
+ if (ureg == 0xdb) /* PX is 48-bit */
+ {
+ pm_write48(PM_REG_I(i) + offset, sharc.px);
+ }
+ else
+ {
+ pm_write32(PM_REG_I(i) + offset, GET_UREG(ureg));
+ }
+}
+
+/*****************************************************************************/
+/* | 1001xxxxx | */
+
+/* immediate data -> DM|PM */
+static void sharcop_imm_to_dmpm(void)
+{
+ int i = (sharc.opcode >> 41) & 0x7;
+ int m = (sharc.opcode >> 38) & 0x7;
+ int g = (sharc.opcode >> 37) & 0x1;
+ UINT32 data = (UINT32)sharc.opcode;
+
+ if (g)
+ {
+ /* program memory (PM) */
+ pm_write32(PM_REG_I(i), data);
+ PM_REG_I(i) += PM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_PM(i);
+ }
+ else
+ {
+ /* data memory (DM) */
+ dm_write32(DM_REG_I(i), data);
+ DM_REG_I(i) += DM_REG_M(m);
+ UPDATE_CIRCULAR_BUFFER_DM(i);
+ }
+}
+
+/*****************************************************************************/
+/* | 00001111x | */
+
+/* immediate data -> ureg */
+static void sharcop_imm_to_ureg(void)
+{
+ int ureg = (sharc.opcode >> 32) & 0xff;
+ UINT32 data = (UINT32)sharc.opcode;
+
+ SET_UREG(ureg, data);
+}
+
+/*****************************************************************************/
+/* | 00010100x | */
+
+/* system register bit manipulation */
+static void sharcop_sysreg_bitop(void)
+{
+ int bop = (sharc.opcode >> 37) & 0x7;
+ int sreg = (sharc.opcode >> 32) & 0xf;
+ UINT32 data = (UINT32)sharc.opcode;
+
+ UINT32 src = GET_UREG(0x70 | sreg);
+
+ switch(bop)
+ {
+ case 0: /* SET */
+ {
+ src |= data;
+ break;
+ }
+ case 1: /* CLEAR */
+ {
+ src &= ~data;
+ break;
+ }
+ case 2: /* TOGGLE */
+ {
+ src ^= data;
+ break;
+ }
+ case 4: /* TEST */
+ {
+ if ((src & data) == data)
+ {
+ sharc.astat |= BTF;
+ }
+ else
+ {
+ sharc.astat &= ~BTF;
+ }
+ break;
+ }
+ case 5: /* XOR */
+ {
+ if (src == data)
+ {
+ sharc.astat |= BTF;
+ }
+ else
+ {
+ sharc.astat &= ~BTF;
+ }
+ break;
+ }
+ default:
+ fatalerror("SHARC: sysreg_bitop: invalid bitop %d", bop);
+ break;
+ }
+
+ SET_UREG(0x70 | sreg, src);
+}
+
+/*****************************************************************************/
+/* | 000101100 | */
+
+/* I register modify */
+static void sharcop_modify(void)
+{
+ int g = (sharc.opcode >> 38) & 0x1;
+ int i = (sharc.opcode >> 32) & 0x7;
+ INT32 data = (sharc.opcode);
+
+ if (g) // PM
+ {
+ PM_REG_I(i) += data;
+ UPDATE_CIRCULAR_BUFFER_PM(i);
+ }
+ else // DM
+ {
+ DM_REG_I(i) += data;
+ UPDATE_CIRCULAR_BUFFER_DM(i);
+ }
+}
+
+/*****************************************************************************/
+/* | 000101101 | */
+
+/* I register bit-reverse */
+static void sharcop_bit_reverse(void)
+{
+ fatalerror("SHARC: sharcop_bit_reverse unimplemented");
+}
+
+/*****************************************************************************/
+/* | 00010111x | */
+
+/* push/pop stacks / flush cache */
+static void sharcop_push_pop_stacks(void)
+{
+ if (sharc.opcode & U64(0x008000000000))
+ {
+ fatalerror("sharcop_push_pop_stacks: push loop not implemented");
+ }
+ if (sharc.opcode & U64(0x004000000000))
+ {
+ fatalerror("sharcop_push_pop_stacks: pop loop not implemented");
+ }
+ if (sharc.opcode & U64(0x002000000000))
+ {
+ //fatalerror("sharcop_push_pop_stacks: push sts not implemented");
+ PUSH_STATUS_STACK();
+ }
+ if (sharc.opcode & U64(0x001000000000))
+ {
+ //fatalerror("sharcop_push_pop_stacks: pop sts not implemented");
+ POP_STATUS_STACK();
+ }
+ if (sharc.opcode & U64(0x000800000000))
+ {
+ PUSH_PC(sharc.pcstk);
+ }
+ if (sharc.opcode & U64(0x000400000000))
+ {
+ POP_PC();
+ }
+}
+
+/*****************************************************************************/
+/* | 000000000 | */
+
+static void sharcop_nop(void)
+{
+
+}
+
+/*****************************************************************************/
+/* | 000000001 | */
+
+static void sharcop_idle(void)
+{
+ //CHANGE_PC(sharc.pc);
+
+ sharc.daddr = sharc.pc;
+ sharc.faddr = sharc.pc+1;
+ sharc.nfaddr = sharc.pc+2;
+
+ sharc.decode_opcode = ROPCODE(sharc.daddr);
+ sharc.fetch_opcode = ROPCODE(sharc.faddr);
+
+ sharc.idle = 1;
+}
+
+/*****************************************************************************/
+
+static void sharcop_unimplemented(void)
+{
+#ifdef MAME_DEBUG
+ char dasm[1000];
+ sharc_dasm(dasm, sharc.pc, NULL, NULL);
+ mame_printf_debug("SHARC: %08X: %s\n", sharc.pc, dasm);
+ fatalerror("SHARC: Unimplemented opcode %04X%08X at %08X", (UINT16)(sharc.opcode >> 32), (UINT32)(sharc.opcode), sharc.pc);
+#else
+ fatalerror("SHARC: Unimplemented opcode %04X%08X at %08X", (UINT16)(sharc.opcode >> 32), (UINT32)(sharc.opcode), sharc.pc);
+#endif
+}
diff --git a/src/emu/cpu/sharc/sharcops.h b/src/emu/cpu/sharc/sharcops.h
new file mode 100644
index 00000000000..77f1a400074
--- /dev/null
+++ b/src/emu/cpu/sharc/sharcops.h
@@ -0,0 +1,138 @@
+typedef struct
+{
+ UINT32 op_mask;
+ UINT32 op_bits;
+ void (* handler)(void);
+} SHARC_OP;
+
+static SHARC_OP sharc_opcode_table[] =
+{
+ // |0 0 1|
+ { 0xe000, 0x2000, sharcop_compute_dreg_dm_dreg_pm },
+
+ // |0 0 0|0 0 0 0 1|
+ { 0xff00, 0x0100, sharcop_compute },
+
+ // |0 1 0|0|
+ { 0xf000, 0x4000, sharcop_compute_ureg_dmpm_premod },
+
+ // |0 1 0|1|
+ { 0xf000, 0x5000, sharcop_compute_ureg_dmpm_postmod },
+
+ // |0 1 1|0|x x x|0|0|
+ { 0xf180, 0x6000, sharcop_compute_dm_to_dreg_immmod },
+
+ // |0 1 1|0|x x x|0|1|
+ { 0xf180, 0x6080, sharcop_compute_dreg_to_dm_immmod },
+
+ // |0 1 1|0|x x x|1|0|
+ { 0xf180, 0x6100, sharcop_compute_pm_to_dreg_immmod },
+
+ // |0 1 1|0|x x x|1|1|
+ { 0xf180, 0x6180, sharcop_compute_dreg_to_pm_immmod },
+
+ // |0 1 1|1|
+ { 0xf000, 0x7000, sharcop_compute_ureg_to_ureg },
+
+ // |1 0 0|0|
+ { 0xf000, 0x8000, sharcop_imm_shift_dreg_dmpm },
+
+ // |0 0 0|0 0 0 1 0|
+ { 0xff00, 0x0200, sharcop_imm_shift },
+
+ // |0 0 0|0 0 1 0 0|
+ { 0xff00, 0x0400, sharcop_compute_modify },
+
+ // |0 0 0|0 0 1 1 0|0|
+ { 0xff80, 0x0600, sharcop_direct_jump },
+
+ // |0 0 0|0 0 1 1 0|1|
+ { 0xff80, 0x0680, sharcop_direct_call },
+
+ // |0 0 0|0 0 1 1 1|0|
+ { 0xff80, 0x0700, sharcop_relative_jump },
+
+ // |0 0 0|0 0 1 1 1|1|
+ { 0xff80, 0x0780, sharcop_relative_call },
+
+ // |0 0 0|0 1 0 0 0|0|
+ { 0xff80, 0x0800, sharcop_indirect_jump },
+
+ // |0 0 0|0 1 0 0 0|1|
+ { 0xff80, 0x0880, sharcop_indirect_call },
+
+ // |0 0 0|0 1 0 0 1|0|
+ { 0xff80, 0x0900, sharcop_relative_jump_compute },
+
+ // |0 0 0|0 1 0 0 1|1|
+ { 0xff80, 0x0980, sharcop_relative_call_compute },
+
+ // |1 1 0|
+ { 0xe000, 0xc000, sharcop_indirect_jump_compute_dreg_dm },
+
+ // |1 1 1|
+ { 0xe000, 0xe000, sharcop_relative_jump_compute_dreg_dm },
+
+ // |0 0 0|0 1 0 1 0|
+ { 0xff00, 0x0a00, sharcop_rts },
+
+ // |0 0 0|0 1 0 1 1|
+ { 0xff00, 0x0b00, sharcop_rti },
+
+ // |0 0 0|0 1 1 0 0|
+ { 0xff00, 0x0c00, sharcop_do_until_counter_imm },
+
+ // |0 0 0|0 1 1 0 1|
+ { 0xff00, 0x0d00, sharcop_do_until_counter_ureg },
+
+ // |0 0 0|0 1 1 1 0|
+ { 0xff00, 0x0e00, sharcop_do_until },
+
+ // |0 0 0|1 0 0|0|0|
+ { 0xff00, 0x1000, sharcop_dm_to_ureg_direct },
+
+ // |0 0 0|1 0 0|0|1|
+ { 0xff00, 0x1100, sharcop_ureg_to_dm_direct },
+
+ // |0 0 0|1 0 0|1|0|
+ { 0xff00, 0x1200, sharcop_pm_to_ureg_direct },
+
+ // |0 0 0|1 0 0|1|1|
+ { 0xff00, 0x1300, sharcop_ureg_to_pm_direct },
+
+ // |1 0 1|0|x x x|0|
+ { 0xf100, 0xa000, sharcop_dm_to_ureg_indirect },
+
+ // |1 0 1|0|x x x|1|
+ { 0xf100, 0xa100, sharcop_ureg_to_dm_indirect },
+
+ // |1 0 1|1|x x x|0|
+ { 0xf100, 0xb000, sharcop_pm_to_ureg_indirect },
+
+ // |1 0 1|1|x x x|1|
+ { 0xf100, 0xb100, sharcop_ureg_to_pm_indirect },
+
+ // |1 0 0|1|
+ { 0xf000, 0x9000, sharcop_imm_to_dmpm },
+
+ // |0 0 0|0 1 1 1 1|
+ { 0xff00, 0x0f00, sharcop_imm_to_ureg },
+
+ // |0 0 0|1 0 1 0 0|
+ { 0xff00, 0x1400, sharcop_sysreg_bitop },
+
+ // |0 0 0|1 0 1 1 0|0|
+ { 0xff80, 0x1600, sharcop_modify },
+
+ // |0 0 0|1 0 1 1 0|1|
+ { 0xff80, 0x1680, sharcop_bit_reverse },
+
+ // |0 0 0|1 0 1 1 1|
+ { 0xff00, 0x1700, sharcop_push_pop_stacks },
+
+ // |0 0 0|0 0 0 0 0|0|
+ { 0xff80, 0x0000, sharcop_nop },
+
+ // |0 0 0|0 0 0 0 0|1|
+ { 0xff80, 0x0080, sharcop_idle },
+};
diff --git a/src/emu/cpu/sm8500/sm8500.c b/src/emu/cpu/sm8500/sm8500.c
new file mode 100644
index 00000000000..2c12d232f99
--- /dev/null
+++ b/src/emu/cpu/sm8500/sm8500.c
@@ -0,0 +1,533 @@
+/*
+ Implementation for Sharp sm8500 cpu. There is hardly any information available
+ on this cpu. Currently we've only found documentation on the microcontroller
+ parts of the cpu, but nothing on the cpu itself.
+
+ Through looking at binary data we have attempted to figure out the opcodes for
+ this cpu, and made educated guesses on the number of cycles for each instruction.
+
+ Code by Wilbert Pol
+*/
+
+#include "sm8500.h"
+#include "debugger.h"
+
+#define FLAG_C 0x80
+#define FLAG_Z 0x40
+#define FLAG_S 0x20
+#define FLAG_V 0x10
+#define FLAG_D 0x08
+#define FLAG_H 0x04
+#define FLAG_B 0x02
+#define FLAG_I 0x01
+
+typedef struct {
+ SM8500_CONFIG config;
+ UINT16 PC;
+ UINT8 *register_base;
+ UINT8 IE0;
+ UINT8 IE1;
+ UINT8 IR0;
+ UINT8 IR1;
+ UINT8 P0;
+ UINT8 P1;
+ UINT8 P2;
+ UINT8 P3;
+ UINT8 SYS;
+ UINT8 CKC;
+ UINT8 clock_changed;
+ UINT16 SP;
+ UINT8 PS0;
+ UINT8 PS1;
+ UINT8 P0C;
+ UINT8 P1C;
+ UINT8 P2C;
+ UINT8 P3C;
+ UINT8 IFLAGS;
+ UINT8 CheckInterrupts;
+ int halted;
+ int (*irq_callback)(int irqline);
+ UINT8 internal_ram[0x500];
+} sm8500_regs;
+
+static sm8500_regs regs;
+
+/* nr of cycles to run */
+int sm8500_icount;
+
+static UINT8 sm8500_b2w[8] = {
+ 0, 8, 2, 10, 4, 12, 6, 14
+};
+
+UINT8 sm85cpu_mem_readbyte( UINT32 offset ) {
+ return ( offset < 0x10 ) ? regs.register_base[offset] : program_read_byte_8( offset );
+}
+
+void sm85cpu_mem_writebyte( UINT32 offset, UINT8 data ) {
+ if ( offset < 0x10 ) {
+ regs.register_base[offset] = data;
+ } else {
+ program_write_byte_8( offset, data );
+ }
+}
+
+UINT8* sm8500_internal_ram( void )
+{
+ return regs.internal_ram;
+}
+
+static void sm8500_init(int index, int clock, const void *config, int (*irqcallback)(int)) {
+ regs.irq_callback = irqcallback;
+ if ( config != NULL ) {
+ regs.config.handle_dma = ((SM8500_CONFIG *)config)->handle_dma;
+ regs.config.handle_timers = ((SM8500_CONFIG *)config)->handle_timers;
+ } else {
+ regs.config.handle_dma = NULL;
+ regs.config.handle_timers = NULL;
+ }
+ regs.register_base = regs.internal_ram;
+}
+
+static void sm8500_reset( void )
+{
+ regs.PC = 0x1020;
+ regs.IE0 = 0;
+ regs.IE1 = 0;
+ regs.IR0 = 0;
+ regs.IR1 = 0;
+ regs.P0 = 0xFF;
+ regs.P1 = 0xFF;
+ regs.P2 = 0xFF;
+ regs.P3 = 0;
+ regs.SYS = 0;
+ regs.CKC = 0; regs.clock_changed = 0;
+ regs.PS1 = 0;
+ regs.register_base = regs.internal_ram;
+ regs.halted = 0;
+}
+
+static void sm8500_exit( void )
+{
+}
+
+#define PUSH_BYTE(X) regs.SP = regs.SP - 1; \
+ if ( ( regs.SYS & 0x40 ) == 0 ) { \
+ regs.SP = regs.SP & 0xFF; \
+ } \
+ sm85cpu_mem_writebyte( regs.SP, X );
+
+INLINE void sm8500_do_interrupt(UINT16 vector) {
+ /* Push PC */
+ PUSH_BYTE( regs.PC & 0xFF );
+ PUSH_BYTE( regs.PC >> 8 );
+ /* Push PS1 */
+ PUSH_BYTE( regs.PS1 );
+ /* Clear I flag */
+ regs.PS1 &= ~ 0x01;
+ /* Change PC to address stored at "vector" */
+ regs.PC = sm85cpu_mem_readword( vector );
+}
+
+INLINE void sm8500_process_interrupts(void) {
+ if ( regs.CheckInterrupts ) {
+ int irqline = 0;
+ while( irqline < 11 ) {
+ if ( regs.IFLAGS & ( 1 << irqline ) ) {
+ regs.halted = 0;
+ switch( irqline ) {
+ case ILL_INT:
+ sm8500_do_interrupt( 0x101C );
+ break;
+ case WDT_INT:
+ sm8500_do_interrupt( 0x101E );
+ break;
+ case NMI_INT:
+ sm8500_do_interrupt( 0x101E );
+ break;
+ case DMA_INT:
+ regs.IR0 |= 0x80;
+ if ( ( regs.IE0 & 0x80 ) && ( ( regs.PS0 & 0x07 ) < 8 ) && ( regs.PS1 & 0x01 ) ) {
+ sm8500_do_interrupt( 0x1000 );
+ }
+ break;
+ case TIM0_INT:
+ regs.IR0 |= 0x40;
+ if ( ( regs.IE0 & 0x40 ) && ( ( regs.PS0 & 0x07 ) < 8 ) && ( regs.PS1 & 0x01 ) ) {
+ sm8500_do_interrupt( 0x1002 );
+ }
+ break;
+ case EXT_INT:
+ regs.IR0 |= 0x10;
+ if ( ( regs.IE0 & 0x10 ) && ( ( regs.PS0 & 0x07 ) < 7 ) && ( regs.PS1 & 0x01 ) ) {
+ sm8500_do_interrupt( 0x1006 );
+ }
+ break;
+ case UART_INT:
+ regs.IR0 |= 0x08;
+ if ( ( regs.IE0 & 0x08 ) && ( ( regs.PS0 & 0x07 ) < 6 ) && ( regs.PS1 & 0x01 ) ) {
+ sm8500_do_interrupt( 0x1008 );
+ }
+ break;
+ case LCDC_INT:
+ regs.IR0 |= 0x01;
+ if ( ( regs.IE0 & 0x01 ) && ( ( regs.PS0 & 0x07 ) < 5 ) && ( regs.PS1 & 0x01 ) ) {
+ sm8500_do_interrupt( 0x100E );
+ }
+ break;
+ case TIM1_INT:
+ regs.IR1 |= 0x40;
+ if ( ( regs.IE1 & 0x40 ) && ( ( regs.PS0 & 0x07 ) < 4 ) && ( regs.PS1 & 0x01 ) ) {
+ sm8500_do_interrupt( 0x1012 );
+ }
+ break;
+ case CK_INT:
+ regs.IR1 |= 0x10;
+ if ( ( regs.IE1 & 0x10 ) && ( ( regs.PS0 & 0x07 ) < 3 ) && ( regs.PS1 & 0x01 ) ) {
+ sm8500_do_interrupt( 0x1016 );
+ }
+ break;
+ case PIO_INT:
+ regs.IR1 |= 0x04;
+ if ( ( regs.IE1 & 0x04 ) && ( ( regs.PS0 & 0x07 ) < 2 ) && ( regs.PS1 & 0x01 ) ) {
+ sm8500_do_interrupt( 0x101A );
+ }
+ break;
+ }
+ regs.IFLAGS &= ~ ( 1 << irqline );
+ }
+ irqline++;
+ }
+ }
+}
+
+static int sm8500_execute( int cycles )
+{
+ UINT8 op;
+ UINT16 oldpc;
+ int mycycles;
+
+ sm8500_icount = cycles;
+
+ do
+ {
+ UINT8 r1,r2;
+ UINT16 s1,s2;
+ UINT32 d1,d2;
+ UINT32 res;
+
+ CALL_MAME_DEBUG;
+ oldpc = regs.PC;
+ mycycles = 0;
+ sm8500_process_interrupts();
+ if ( !regs.halted ) {
+ op = sm85cpu_mem_readbyte( regs.PC++ );
+ switch( op )
+ {
+#include "sm85ops.h"
+ }
+ } else {
+ mycycles = 4;
+ if ( regs.config.handle_dma ) {
+ regs.config.handle_dma( mycycles );
+ }
+ }
+ if ( regs.config.handle_timers ) {
+ regs.config.handle_timers( mycycles );
+ }
+ sm8500_icount -= mycycles;
+ } while ( sm8500_icount > 0 );
+
+ return cycles - sm8500_icount;
+}
+
+static void sm8500_burn( int cycles )
+{
+ if ( cycles > 0 ) {
+ /* burn a number of 4 cycles */
+ int n = ( cycles + 3 ) / 4;
+ sm8500_icount -= 4 * n;
+ }
+}
+
+static void sm8500_set_context( void *src )
+{
+}
+
+static void sm8500_get_context( void *dst )
+{
+}
+
+unsigned sm8500_get_reg( int regnum )
+{
+ switch( regnum )
+ {
+ case REG_PC:
+ case SM8500_PC: return regs.PC;
+ case REG_SP:
+ case SM8500_SP: return ( regs.SYS & 0x40 ) ? regs.SP : regs.SP & 0xFF ;
+ case SM8500_PS: return ( regs.PS0 << 8 ) | regs.PS1;
+ case SM8500_SYS16: return regs.SYS;
+ case SM8500_RR0: return sm85cpu_mem_readword( 0x00 );
+ case SM8500_RR2: return sm85cpu_mem_readword( 0x02 );
+ case SM8500_RR4: return sm85cpu_mem_readword( 0x04 );
+ case SM8500_RR6: return sm85cpu_mem_readword( 0x06 );
+ case SM8500_RR8: return sm85cpu_mem_readword( 0x08 );
+ case SM8500_RR10: return sm85cpu_mem_readword( 0x0A );
+ case SM8500_RR12: return sm85cpu_mem_readword( 0x0C );
+ case SM8500_RR14: return sm85cpu_mem_readword( 0x0E );
+ case SM8500_IE0: return regs.IE0;
+ case SM8500_IE1: return regs.IE1;
+ case SM8500_IR0: return regs.IR0;
+ case SM8500_IR1: return regs.IR1;
+ case SM8500_P0: return regs.P0;
+ case SM8500_P1: return regs.P1;
+ case SM8500_P2: return regs.P2;
+ case SM8500_P3: return regs.P3;
+ case SM8500_SYS: return regs.SYS;
+ case SM8500_CKC: return regs.CKC;
+ case SM8500_SPH: return (regs.SP >> 8);
+ case SM8500_SPL: return regs.SP & 0xFF;
+ case SM8500_PS0: return regs.PS0;
+ case SM8500_PS1: return regs.PS1;
+ case SM8500_P0C: return regs.P0C;
+ case SM8500_P1C: return regs.P1C;
+ case SM8500_P2C: return regs.P2C;
+ case SM8500_P3C: return regs.P3C;
+ }
+ return 0;
+}
+
+static void sm8500_set_reg( int regnum, unsigned val )
+{
+ switch( regnum )
+ {
+ case REG_PC:
+ case SM8500_PC: regs.PC = val; break;
+ case REG_SP:
+ case SM8500_SP: regs.SP = val; break;
+ case SM8500_PS: sm8500_set_reg( SM8500_PS0, ( val >> 8 ) & 0xFF ); sm8500_set_reg( SM8500_PS1, val & 0xFF ); break;
+ case SM8500_SYS16: regs.SYS = val; break;
+ case SM8500_RR0: sm85cpu_mem_writeword( 0x00, val); break;
+ case SM8500_RR2: sm85cpu_mem_writeword( 0x02, val); break;
+ case SM8500_RR4: sm85cpu_mem_writeword( 0x04, val); break;
+ case SM8500_RR6: sm85cpu_mem_writeword( 0x06, val); break;
+ case SM8500_RR8: sm85cpu_mem_writeword( 0x08, val); break;
+ case SM8500_RR10: sm85cpu_mem_writeword( 0x0A, val); break;
+ case SM8500_RR12: sm85cpu_mem_writeword( 0x0C, val); break;
+ case SM8500_RR14: sm85cpu_mem_writeword( 0x0E, val); break;
+ case SM8500_IE0: regs.IE0 = val; break;
+ case SM8500_IE1: regs.IE1 = val; break;
+ case SM8500_IR0: regs.IR0 = val; break;
+ case SM8500_IR1: regs.IR1 = val; break;
+ case SM8500_P0: regs.P0 = val; break;
+ case SM8500_P1: regs.P1 = val; break;
+ case SM8500_P2: regs.P2 = val; break;
+ case SM8500_P3: regs.P3 = val; break;
+ case SM8500_SYS: regs.SYS = val; break;
+ case SM8500_CKC: regs.CKC = val; if ( val & 0x80 ) { regs.clock_changed = 1; }; break;
+ case SM8500_SPH: regs.SP = ( ( val & 0xFF ) << 8 ) | ( regs.SP & 0xFF ); break;
+ case SM8500_SPL: regs.SP = ( regs.SP & 0xFF00 ) | ( val & 0xFF ); break;
+ case SM8500_PS0: regs.PS0 = val; regs.register_base = regs.internal_ram + ( val & 0xF8 ); break;
+ case SM8500_PS1: regs.PS1 = val; break;
+ case SM8500_P0C: regs.P0C = val; break;
+ case SM8500_P1C: regs.P1C = val; break;
+ case SM8500_P2C: regs.P2C = val; break;
+ case SM8500_P3C: regs.P3C = val; break;
+ }
+}
+
+static void sm8500_set_irq_line( int irqline, int state )
+{
+ if ( state == ASSERT_LINE ) {
+ regs.IFLAGS |= ( 0x01 << irqline );
+ regs.CheckInterrupts = 1;
+ switch( irqline ) {
+ case DMA_INT: regs.IR0 |= 0x80; break;
+ case TIM0_INT: regs.IR0 |= 0x40; break;
+ case EXT_INT: regs.IR0 |= 0x10; break;
+ case UART_INT: regs.IR0 |= 0x08; break;
+ case LCDC_INT: regs.IR0 |= 0x01; break;
+ case TIM1_INT: regs.IR1 |= 0x40; break;
+ case CK_INT: regs.IR1 |= 0x10; break;
+ case PIO_INT: regs.IR1 |= 0x04; break;
+ }
+ } else {
+ regs.IFLAGS &= ~( 0x01 << irqline );
+ switch( irqline ) {
+ case DMA_INT: regs.IR0 &= ~0x80; break;
+ case TIM0_INT: regs.IR0 &= ~0x40; break;
+ case EXT_INT: regs.IR0 &= ~0x10; break;
+ case UART_INT: regs.IR0 &= ~0x08; break;
+ case LCDC_INT: regs.IR0 &= ~0x01; break;
+ case TIM1_INT: regs.IR1 &= ~0x40; break;
+ case CK_INT: regs.IR1 &= ~0x10; break;
+ case PIO_INT: regs.IR1 &= ~0x04; break;
+ }
+ if ( 0 == regs.IFLAGS ) {
+ regs.CheckInterrupts = 0;
+ }
+ }
+}
+
+static void sm8500_set_info( UINT32 state, cpuinfo *info )
+{
+ switch(state)
+ {
+ case CPUINFO_INT_INPUT_STATE + 0:
+ case CPUINFO_INT_INPUT_STATE + 1:
+ case CPUINFO_INT_INPUT_STATE + 2:
+ case CPUINFO_INT_INPUT_STATE + 3:
+ case CPUINFO_INT_INPUT_STATE + 4:
+ case CPUINFO_INT_INPUT_STATE + 5:
+ case CPUINFO_INT_INPUT_STATE + 6:
+ case CPUINFO_INT_INPUT_STATE + 7:
+ case CPUINFO_INT_INPUT_STATE + 8:
+ case CPUINFO_INT_INPUT_STATE + 9:
+ case CPUINFO_INT_INPUT_STATE + 10:
+ sm8500_set_irq_line( state - CPUINFO_INT_INPUT_STATE, info->i ); break;
+
+ case CPUINFO_INT_REGISTER + SM8500_RR0:
+ case CPUINFO_INT_REGISTER + SM8500_RR2:
+ case CPUINFO_INT_REGISTER + SM8500_RR4:
+ case CPUINFO_INT_REGISTER + SM8500_RR6:
+ case CPUINFO_INT_REGISTER + SM8500_RR8:
+ case CPUINFO_INT_REGISTER + SM8500_RR10:
+ case CPUINFO_INT_REGISTER + SM8500_RR12:
+ case CPUINFO_INT_REGISTER + SM8500_RR14:
+ case CPUINFO_INT_REGISTER + SM8500_PC:
+ case CPUINFO_INT_REGISTER + SM8500_SP:
+ case CPUINFO_INT_REGISTER + SM8500_PS:
+ case CPUINFO_INT_REGISTER + SM8500_SYS16:
+ case CPUINFO_INT_REGISTER + SM8500_SYS:
+ case CPUINFO_INT_REGISTER + SM8500_IE0:
+ case CPUINFO_INT_REGISTER + SM8500_IE1:
+ case CPUINFO_INT_REGISTER + SM8500_IR0:
+ case CPUINFO_INT_REGISTER + SM8500_IR1:
+ case CPUINFO_INT_REGISTER + SM8500_P0:
+ case CPUINFO_INT_REGISTER + SM8500_P1:
+ case CPUINFO_INT_REGISTER + SM8500_P2:
+ case CPUINFO_INT_REGISTER + SM8500_P3:
+ case CPUINFO_INT_REGISTER + SM8500_CKC:
+ case CPUINFO_INT_REGISTER + SM8500_SPH:
+ case CPUINFO_INT_REGISTER + SM8500_SPL:
+ case CPUINFO_INT_REGISTER + SM8500_PS0:
+ case CPUINFO_INT_REGISTER + SM8500_PS1:
+ case CPUINFO_INT_REGISTER + SM8500_P0C:
+ case CPUINFO_INT_REGISTER + SM8500_P1C:
+ case CPUINFO_INT_REGISTER + SM8500_P2C:
+ case CPUINFO_INT_REGISTER + SM8500_P3C:
+ sm8500_set_reg( state - CPUINFO_INT_REGISTER, info->i ); break;
+
+ }
+}
+
+void sm8500_get_info( UINT32 state, cpuinfo *info )
+{
+ switch(state)
+ {
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(sm8500_regs); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 8; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 16; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + 0:
+ case CPUINFO_INT_INPUT_STATE + 1:
+ case CPUINFO_INT_INPUT_STATE + 2:
+ case CPUINFO_INT_INPUT_STATE + 3:
+ case CPUINFO_INT_INPUT_STATE + 4:
+ case CPUINFO_INT_INPUT_STATE + 5:
+ case CPUINFO_INT_INPUT_STATE + 6:
+ case CPUINFO_INT_INPUT_STATE + 7: info->i = regs.IFLAGS & ( 1 << (state - CPUINFO_INT_INPUT_STATE)); break;
+ case CPUINFO_INT_REGISTER + SM8500_RR0:
+ case CPUINFO_INT_REGISTER + SM8500_RR2:
+ case CPUINFO_INT_REGISTER + SM8500_RR4:
+ case CPUINFO_INT_REGISTER + SM8500_RR6:
+ case CPUINFO_INT_REGISTER + SM8500_RR8:
+ case CPUINFO_INT_REGISTER + SM8500_RR10:
+ case CPUINFO_INT_REGISTER + SM8500_RR12:
+ case CPUINFO_INT_REGISTER + SM8500_RR14:
+ case CPUINFO_INT_REGISTER + SM8500_PC:
+ case CPUINFO_INT_REGISTER + SM8500_SP:
+ case CPUINFO_INT_REGISTER + SM8500_PS:
+ case CPUINFO_INT_REGISTER + SM8500_SYS16:
+ case CPUINFO_INT_REGISTER + SM8500_SYS:
+ case CPUINFO_INT_REGISTER + SM8500_IE0:
+ case CPUINFO_INT_REGISTER + SM8500_IE1:
+ case CPUINFO_INT_REGISTER + SM8500_IR0:
+ case CPUINFO_INT_REGISTER + SM8500_IR1:
+ case CPUINFO_INT_REGISTER + SM8500_P0:
+ case CPUINFO_INT_REGISTER + SM8500_P1:
+ case CPUINFO_INT_REGISTER + SM8500_P2:
+ case CPUINFO_INT_REGISTER + SM8500_P3:
+ case CPUINFO_INT_REGISTER + SM8500_CKC:
+ case CPUINFO_INT_REGISTER + SM8500_SPH:
+ case CPUINFO_INT_REGISTER + SM8500_SPL:
+ case CPUINFO_INT_REGISTER + SM8500_PS0:
+ case CPUINFO_INT_REGISTER + SM8500_PS1:
+ case CPUINFO_INT_REGISTER + SM8500_P0C:
+ case CPUINFO_INT_REGISTER + SM8500_P1C:
+ case CPUINFO_INT_REGISTER + SM8500_P2C:
+ case CPUINFO_INT_REGISTER + SM8500_P3C:
+ info->i = sm8500_get_reg( state - CPUINFO_INT_REGISTER ); break;
+ case CPUINFO_INT_REGISTER + REG_PC: info->i = sm8500_get_reg( SM8500_PC ); break;
+ case CPUINFO_INT_REGISTER + REG_SP: info->i = sm8500_get_reg( SM8500_SP ); break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0x0000; break;
+
+
+ case CPUINFO_PTR_SET_INFO: info->setinfo = sm8500_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = sm8500_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = sm8500_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = sm8500_init; break;
+ case CPUINFO_PTR_RESET: info->reset = sm8500_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = sm8500_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = sm8500_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = sm8500_burn; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = sm8500_dasm; break;
+#endif
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &sm8500_icount; break;
+
+ case CPUINFO_STR_NAME: strcpy( info->s = cpuintrf_temp_str(), "sm8500" ); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy( info->s = cpuintrf_temp_str(), "Sharp SM8500" ); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy( info->s = cpuintrf_temp_str(), "0.1" ); break;
+ case CPUINFO_STR_CORE_FILE: strcpy( info->s = cpuintrf_temp_str(), __FILE__ ); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy( info->s = cpuintrf_temp_str(), "Copyright (C) 2005 by The MESS Team." ); break;
+ case CPUINFO_STR_FLAGS:
+ sprintf( info->s = cpuintrf_temp_str(), "%c%c%c%c%c%c%c%c",
+ regs.PS1 & FLAG_C ? 'C' : '.',
+ regs.PS1 & FLAG_Z ? 'Z' : '.',
+ regs.PS1 & FLAG_S ? 'S' : '.',
+ regs.PS1 & FLAG_V ? 'V' : '.',
+ regs.PS1 & FLAG_D ? 'D' : '.',
+ regs.PS1 & FLAG_H ? 'H' : '.',
+ regs.PS1 & FLAG_B ? 'B' : '.',
+ regs.PS1 & FLAG_I ? 'I' : '.' );
+ break;
+ case CPUINFO_STR_REGISTER + SM8500_RR0: sprintf(info->s = cpuintrf_temp_str(), "RR0:%04X", sm85cpu_mem_readword( 0x00 ) ); break;
+ case CPUINFO_STR_REGISTER + SM8500_RR2: sprintf(info->s = cpuintrf_temp_str(), "RR2:%04X", sm85cpu_mem_readword( 0x02 ) ); break;
+ case CPUINFO_STR_REGISTER + SM8500_RR4: sprintf(info->s = cpuintrf_temp_str(), "RR4:%04X", sm85cpu_mem_readword( 0x04 ) ); break;
+ case CPUINFO_STR_REGISTER + SM8500_RR6: sprintf(info->s = cpuintrf_temp_str(), "RR6:%04X", sm85cpu_mem_readword( 0x06 ) ); break;
+ case CPUINFO_STR_REGISTER + SM8500_RR8: sprintf(info->s = cpuintrf_temp_str(), "RR8:%04X", sm85cpu_mem_readword( 0x08 ) ); break;
+ case CPUINFO_STR_REGISTER + SM8500_RR10: sprintf(info->s = cpuintrf_temp_str(), "RR10:%04X", sm85cpu_mem_readword( 0x0A ) ); break;
+ case CPUINFO_STR_REGISTER + SM8500_RR12: sprintf(info->s = cpuintrf_temp_str(), "RR12:%04X", sm85cpu_mem_readword( 0x0C ) ); break;
+ case CPUINFO_STR_REGISTER + SM8500_RR14: sprintf(info->s = cpuintrf_temp_str(), "RR14:%04X", sm85cpu_mem_readword( 0x0E ) ); break;
+ case CPUINFO_STR_REGISTER + SM8500_PC: sprintf(info->s = cpuintrf_temp_str(), "PC:%04X", regs.PC); break;
+ case CPUINFO_STR_REGISTER + SM8500_SP: sprintf(info->s = cpuintrf_temp_str(), "SP:%04X", regs.SP); break;
+ case CPUINFO_STR_REGISTER + SM8500_PS: sprintf(info->s = cpuintrf_temp_str(), "PS:%04X", ( regs.PS0 << 8 ) | regs.PS1 ); break;
+ case CPUINFO_STR_REGISTER + SM8500_SYS16: sprintf(info->s = cpuintrf_temp_str(), "SYS:%04X", regs.SYS ); break;
+ }
+}
+
diff --git a/src/emu/cpu/sm8500/sm8500.h b/src/emu/cpu/sm8500/sm8500.h
new file mode 100644
index 00000000000..4d11727d6c3
--- /dev/null
+++ b/src/emu/cpu/sm8500/sm8500.h
@@ -0,0 +1,59 @@
+#ifndef sm8500_H
+#define sm8500_H
+#include "cpuintrf.h"
+
+typedef struct {
+ void (*handle_dma)(int cycles);
+ void (*handle_timers)(int cycles);
+} SM8500_CONFIG;
+
+/* interrupts */
+#define ILL_INT 0
+#define DMA_INT 1
+#define TIM0_INT 2
+#define EXT_INT 3
+#define UART_INT 4
+#define LCDC_INT 5
+#define TIM1_INT 6
+#define CK_INT 7
+#define PIO_INT 8
+#define WDT_INT 9
+#define NMI_INT 10
+
+extern int sm8500_icount;
+
+enum {
+ /* "main" 16 bit register */
+ SM8500_PC=1, SM8500_SP, SM8500_PS, SM8500_SYS16, SM8500_RR0, SM8500_RR2, SM8500_RR4, SM8500_RR6, SM8500_RR8, SM8500_RR10,
+ SM8500_RR12, SM8500_RR14,
+ /* additional internal 8 bit registers */
+ SM8500_IE0, SM8500_IE1, SM8500_IR0, SM8500_IR1, SM8500_P0, SM8500_P1, SM8500_P2, SM8500_P3, SM8500_SYS, SM8500_CKC,
+ SM8500_SPH, SM8500_SPL, SM8500_PS0, SM8500_PS1, SM8500_P0C, SM8500_P1C, SM8500_P2C, SM8500_P3C,
+};
+
+extern UINT8* sm8500_internal_ram( void ) ;
+extern unsigned sm8500_get_reg( int regnum );
+extern void sm8500_get_info(UINT32 state, cpuinfo *info);
+
+UINT8 sm85cpu_mem_readbyte( UINT32 offset );
+void sm85cpu_mem_writebyte( UINT32 offset, UINT8 data );
+
+INLINE UINT16 sm85cpu_mem_readword( UINT32 address )
+{
+ UINT16 value = (UINT16) sm85cpu_mem_readbyte( address ) << 8;
+ value |= sm85cpu_mem_readbyte( ( address + 1 ) & 0xffff );
+ return value;
+}
+
+INLINE void sm85cpu_mem_writeword( UINT32 address, UINT16 value )
+{
+ sm85cpu_mem_writebyte( address, value >> 8 );
+ sm85cpu_mem_writebyte( ( address + 1 ) & 0xffff, value & 0xff );
+}
+
+#ifdef MAME_DEBUG
+extern unsigned sm8500_dasm( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram );
+#endif /* MAME_DEBUG */
+
+#endif
+
diff --git a/src/emu/cpu/sm8500/sm8500d.c b/src/emu/cpu/sm8500/sm8500d.c
new file mode 100644
index 00000000000..4d8a2c0ba85
--- /dev/null
+++ b/src/emu/cpu/sm8500/sm8500d.c
@@ -0,0 +1,581 @@
+/*******************************************************************
+
+sm8500d.c
+Sharp sm8500 CPU disassembly
+
+
+
+*******************************************************************/
+
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "sm8500.h"
+
+enum e_mnemonics
+{
+ zADC=0, zADCW, zADD, zADDW, zAND, zANDW, zBAND, zBBC, zBBS,
+ zBCLR, zBCMP, zBMOV, zBOR, zBR, zBTST, zBSET, zBXOR, zCALL, zCALS, zCLR,
+ zCLRC, zCMP, zCMPW, zCOM, zCOMC, zDA, zDBNZ, zDEC,
+ zDECW, zDI, zDIV, zEI, zEXTS, zHALT, zINC, zINCW,
+ zIRET, zJMP, zMOV, zMOVM, zMOVW, zMULT, zNEG, zNOP, zOR,
+ zORW, zPOP, zPOPW, zPUSH, zPUSHW, zRET, zRL, zRLC,
+ zRR, zRRC, zSBC, zSBCW, zSETC, zSLL, zSRA, zSRL, zSTOP,
+ zSUB, zSUBW, zSWAP, zXOR, zXORW, zMOVPS0, zINVLD, zDM,
+/* unknowns */
+z5A, z5B,
+
+/* more complicated instructions */
+z1A, z1B, z4F,
+};
+
+/* instructions not found:
+5A, 5B,
+*/
+
+static const char *s_mnemonic[] =
+{
+ "adc", "adcw", "add", "addw", "and", "andw", "band", "bbc", "bbs",
+ "bclr", "bcmp", "bmov", "bor", "br", "btst", "bset", "bxor", "call", "cals", "clr",
+ "clrc", "cmp", "cmpw", "com", "comc", "da", "dbnz", "dec",
+ "decw", "di", "div", "ei", "exts", "halt", "inc", "incw",
+ "iret", "jmp", "mov", "movm", "movw", "mult", "neg", "nop", "or",
+ "orw", "pop", "popw", "push", "pushw", "ret", "rl", "rlc",
+ "rr", "rrc", "sbc", "sbcw", "setc", "sll", "sra", "srl", "stop",
+ "sub", "subw", "swap", "xor", "xorw", "mov PS0,", "invalid", "dm?",
+/* unknowns */
+"unk5A", "unk5B",
+
+/* more complicated instructions */
+"comp1A", "comp1B", "comp4F",
+};
+
+#define _OVER DASMFLAG_STEP_OVER
+#define _OUT DASMFLAG_STEP_OUT
+
+static const UINT32 s_flags[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, _OVER, _OVER, 0,
+ 0, 0, 0, 0, 0, 0, _OVER, 0,
+ 0, 0, 0, 0, 0, _OVER, 0, 0,
+ _OUT, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, _OUT, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0
+};
+
+typedef struct
+{
+ UINT8 mnemonic;
+ UINT8 arguments;
+} sm8500dasm;
+
+static const char *sm8500_cond[16] = {
+ "F", "LT", "LE", "ULE", "OV", "MI", "Z", "C",
+ "T", "GE", "GT", "UGT", "NOV", "PL", "NZ", "NC"
+};
+
+static const UINT8 sm8500_b2w[8] = {
+ 0, 8, 2, 10, 4, 12, 6, 14
+};
+
+enum e_addrmodes {
+ AM_R=1, AM_rr, AM_r1, AM_S, AM_rmb, AM_mbr, AM_Ri, AM_rmw, AM_mwr, AM_smw, AM_mws,
+ AM_Sw, AM_iR, AM_rbr, AM_riw, AM_cjp, AM_rib, AM_pi, AM_cbr, AM_i, AM_ii,
+ AM_ss, AM_RR, AM_2, AM_SS, AM_bR, AM_Rbr, AM_Rb, AM_rR, AM_Rr, AM_Rii, AM_RiR,
+ AM_riB, AM_iS, AM_CALS, AM_bid, AM_1A, AM_1B, AM_4F,
+};
+
+static const sm8500dasm mnemonic[256] = {
+ /* 00 - 0F */
+ {zCLR, AM_R}, {zNEG,AM_R}, {zCOM,AM_R}, {zRR,AM_R},
+ {zRL, AM_R}, {zRRC,AM_R}, {zRLC,AM_R}, {zSRL,AM_R},
+ {zINC, AM_R}, {zDEC,AM_R}, {zSRA,AM_R}, {zSLL,AM_R},
+ {zDA, AM_R}, {zSWAP,AM_R}, {zPUSH,AM_R}, {zPOP,AM_R},
+ /* 10 - 1F */
+ {zCMP,AM_rr}, {zADD,AM_rr}, {zSUB,AM_rr}, {zADC,AM_rr},
+ {zSBC,AM_rr}, {zAND,AM_rr}, {zOR,AM_rr}, {zXOR,AM_rr},
+ {zINCW,AM_S}, {zDECW,AM_S}, {z1A,AM_1A}, {z1B,AM_1B},
+ {zBCLR,AM_riB}, {zBSET,AM_riB}, {zPUSHW,AM_S}, {zPOPW,AM_S},
+ /* 20 - 2F */
+ {zCMP,AM_rmb}, {zADD,AM_rmb}, {zSUB,AM_rmb}, {zADC,AM_rmb},
+ {zSBC,AM_rmb}, {zAND,AM_rmb}, {zOR,AM_rmb}, {zXOR,AM_rmb},
+ {zMOV,AM_rmb}, {zMOV,AM_mbr}, {zBBC,AM_bid}, {zBBS,AM_bid},
+ {zEXTS,AM_R}, {zDM,AM_i}, {zMOVPS0,AM_i}, {zBTST,AM_Ri},
+ /* 30 - 3F */
+ {zCMP,AM_rmw}, {zADD,AM_rmw}, {zSUB,AM_rmw}, {zADC,AM_rmw},
+ {zSBC,AM_rmw}, {zAND,AM_rmw}, {zOR,AM_rmw}, {zXOR,AM_rmw},
+ {zMOV,AM_rmw}, {zMOV,AM_mwr}, {zMOVW,AM_smw}, {zMOVW,AM_mws},
+ {zMOVW,AM_ss}, {zDM,AM_R}, {zJMP,AM_2}, {zCALL,AM_2},
+ /* 40 - 4F */
+ {zCMP,AM_RR}, {zADD,AM_RR}, {zSUB,AM_RR}, {zADC,AM_RR},
+ {zSBC,AM_RR}, {zAND,AM_RR}, {zOR,AM_RR}, {zXOR,AM_RR},
+ {zMOV,AM_RR}, {zCALL,AM_ii}, {zMOVW,AM_SS}, {zMOVW,AM_Sw},
+ {zMULT,AM_RR}, {zMULT,AM_iR}, {zBMOV,AM_bR}, {z4F,AM_4F},
+ /* 50 - 5F */
+ {zCMP,AM_iR}, {zADD,AM_iR}, {zSUB,AM_iR}, {zADC,AM_iR},
+ {zSBC,AM_iR}, {zAND,AM_iR}, {zOR,AM_iR}, {zXOR,AM_iR},
+ {zMOV, AM_iR}, {zINVLD,0}, {z5A,AM_ii}, {z5B,AM_ii},
+ {zDIV,AM_SS}, {zDIV,AM_iS}, {zMOVM,AM_RiR}, {zMOVM,AM_Rii},
+ /* 60 - 6F */
+ {zCMPW,AM_SS}, {zADDW,AM_SS}, {zSUBW,AM_SS}, {zADCW,AM_SS},
+ {zSBCW,AM_SS}, {zANDW,AM_SS}, {zORW,AM_SS}, {zXORW,AM_SS},
+ {zCMPW,AM_Sw}, {zADDW,AM_Sw}, {zSUBW,AM_Sw}, {zADCW,AM_Sw},
+ {zSBCW,AM_Sw}, {zANDW,AM_Sw}, {zORW,AM_Sw}, {zXORW,AM_Sw},
+ /* 70 - 7F */
+ {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr},
+ {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr},
+ {zMOVW,AM_riw}, {zMOVW,AM_riw}, {zMOVW,AM_riw}, {zMOVW,AM_riw},
+ {zMOVW,AM_riw}, {zMOVW,AM_riw}, {zMOVW,AM_riw}, {zMOVW,AM_riw},
+ /* 80 - 8F */
+ {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, {zBBC,AM_Rbr},
+ {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, {zBBC,AM_Rbr},
+ {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, {zBBS,AM_Rbr},
+ {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, {zBBS,AM_Rbr},
+ /* 90 - 9F */
+ {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp},
+ {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp},
+ {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp},
+ {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp},
+ /* A0 - AF */
+ {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, {zBCLR,AM_Rb},
+ {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, {zBCLR,AM_Rb},
+ {zBSET,AM_Rb}, {zBSET,AM_Rb}, {zBSET,AM_Rb}, {zBSET,AM_Rb},
+ {zBSET,AM_Rb}, {zBSET,AM_Rb}, {zBSET,AM_Rb}, {zBSET,AM_Rb},
+ /* B0 - BF */
+ {zMOV,AM_rR}, {zMOV,AM_rR}, {zMOV,AM_rR}, {zMOV,AM_rR},
+ {zMOV,AM_rR}, {zMOV,AM_rR}, {zMOV,AM_rR}, {zMOV,AM_rR},
+ {zMOV,AM_Rr}, {zMOV,AM_Rr}, {zMOV,AM_Rr}, {zMOV,AM_Rr},
+ {zMOV,AM_Rr}, {zMOV,AM_Rr}, {zMOV,AM_Rr}, {zMOV,AM_Rr},
+ /* C0 - CF */
+ {zMOV,AM_rib}, {zMOV,AM_rib}, {zMOV,AM_rib}, {zMOV,AM_rib},
+ {zMOV,AM_rib}, {zMOV,AM_rib}, {zMOV,AM_rib}, {zMOV,AM_rib},
+ {zMOV,AM_pi}, {zMOV,AM_pi}, {zMOV,AM_pi}, {zMOV,AM_pi},
+ {zMOV,AM_pi}, {zMOV,AM_pi}, {zMOV,AM_pi}, {zMOV,AM_pi},
+ /* D0 - DF */
+ {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr},
+ {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr},
+ {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr},
+ {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr},
+ /* E0 - EF */
+ {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS},
+ {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS},
+ {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS},
+ {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS},
+ /* F0 - FF */
+ {zSTOP,0}, {zHALT,0}, {zINVLD,0}, {zINVLD,0},
+ {zINVLD,0}, {zINVLD,0}, {zINVLD,0}, {zINVLD,0},
+ {zRET,0}, {zIRET,0}, {zCLRC,0}, {zCOMC,0},
+ {zSETC,0}, {zEI,0}, {zDI,0}, {zNOP,0},
+
+};
+
+unsigned sm8500_dasm( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram )
+{
+ const sm8500dasm *instr;
+ char *dst;
+ UINT8 op;
+ INT8 offset = 0;
+ UINT16 ea = 0, ea2 = 0;
+ int pos = 0;
+
+ dst = buffer;
+
+ op = oprom[pos++];
+
+ instr = &mnemonic[op];
+
+ if ( instr->arguments )
+ {
+ if ( instr->arguments != AM_1A || instr->arguments != AM_1B || instr->arguments != AM_4F ) {
+ dst += sprintf( dst, "%-4s ", s_mnemonic[ instr->mnemonic ] );
+ }
+ switch( instr->arguments ) {
+ case AM_R:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "R%02Xh", ea );
+ break;
+ case AM_iR:
+ dst += sprintf( dst, "R%02Xh, $%02X", oprom[pos + 1], oprom[pos + 0]);
+ pos += 2;
+ break;
+ case AM_iS:
+ dst += sprintf( dst, "RR%02Xh, $%02X", oprom[pos + 1], oprom[pos + 0]);
+ pos += 2;
+ break;
+ case AM_Sw:
+ ea2 = oprom[pos++];
+ ea = oprom[pos++] << 8;
+ ea += oprom[pos++];
+ dst+= sprintf( dst, "RR%02Xh, $%04X", ea2, ea );
+ break;
+ case AM_rib:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "r%02Xh, $%02X", op & 0x07, ea );
+ break;
+ case AM_riw:
+ ea = oprom[pos++] << 8;
+ ea += oprom[pos++];
+ dst += sprintf( dst, "rr%02Xh, $%04X", sm8500_b2w[op & 0x07], ea );
+ break;
+ case AM_rmb:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "r%02Xh,", ( ea >> 3 ) & 0x07 );
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "@r%02Xh", ea & 0x07 ); break;
+ case 0x40:
+ dst += sprintf( dst, "(r%02Xh)+", ea & 0x07 ); break;
+ case 0x80:
+ ea2 = oprom[pos++];
+ if ( ea & 0x07 ) {
+ dst += sprintf( dst, "$%02X(r%02Xh)", ea2, ea & 0x07 );
+ } else {
+ dst += sprintf( dst, "@$%02X", ea2 );
+ }
+ break;
+ case 0xC0:
+ dst += sprintf( dst, "-(r%02Xh)", ea & 0x07 ); break;
+ }
+ break;
+ case AM_mbr:
+ ea = oprom[pos++];
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "@r%02Xh", ea & 0x07 ); break;
+ case 0x40:
+ dst += sprintf( dst, "(r%02Xh)+", ea & 0x07 ); break;
+ case 0x80:
+ ea2 = oprom[pos++];
+ if ( ea & 0x07 ) {
+ dst += sprintf( dst, "$%02X(r%02Xh)", ea2, ea & 0x07 );
+ } else {
+ dst += sprintf( dst, "@$%02X", ea2 );
+ }
+ break;
+ case 0xC0:
+ dst += sprintf( dst, "-(r%02Xh)", ea & 0x07 ); break;
+ }
+ dst += sprintf( dst, ",r%02Xh", ( ea >> 3 ) & 0x07 );
+ break;
+ case AM_rmw:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "r%02Xh,", ( ea >> 3 ) & 0x07 );
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "@rr%02Xh", sm8500_b2w[ea & 0x07] ); break;
+ case 0x40:
+ dst += sprintf( dst, "(rr%02Xh)+", sm8500_b2w[ea & 0x07] ); break;
+ case 0x80:
+ ea2 = oprom[pos++] << 8;
+ ea2 += oprom[pos++];
+ if ( ea & 0x07 ) {
+ dst += sprintf( dst, "$%04X(rr%02Xh)", ea2, sm8500_b2w[ea & 0x07] );
+ } else {
+ dst += sprintf( dst, "@$%04X", ea2 );
+ }
+ break;
+ case 0xC0:
+ dst += sprintf( dst, "-(rr%02Xh)", sm8500_b2w[ea & 0x07] ); break;
+ }
+ break;
+ case AM_mwr:
+ ea = oprom[pos++];
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "@rr%02Xh", sm8500_b2w[ea & 0x07] ); break;
+ case 0x40:
+ dst += sprintf( dst, "(rr%02Xh)+", sm8500_b2w[ea & 0x07] ); break;
+ case 0x80:
+ ea2 = oprom[pos++] << 8;
+ ea2 += oprom[pos++];
+ if ( ea & 0x07 ) {
+ dst += sprintf( dst, "$%04X(rr%02Xh)", ea2, sm8500_b2w[ea & 0x07] );
+ } else {
+ dst += sprintf( dst, "@$%04X", ea2 );
+ }
+ break;
+ case 0xC0:
+ dst += sprintf( dst, "-(rr%02Xh)", sm8500_b2w[ea & 0x07] ); break;
+ }
+ dst += sprintf( dst, ",r%02Xh", ( ea >> 3 ) & 0x07 );
+ break;
+ case AM_smw:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "rr%02Xh,", sm8500_b2w[( ea >> 3 ) & 0x07] );
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "@rr%02Xh", sm8500_b2w[ea & 0x07] ); break;
+ case 0x40:
+ dst += sprintf( dst, "(rr%02Xh)+", sm8500_b2w[ea & 0x07] ); break;
+ case 0x80:
+ ea2 = oprom[pos++] << 8;
+ ea2 += oprom[pos++];
+ if ( ea & 0x07 ) {
+ dst += sprintf( dst, "$%04X(rr%02Xh)", ea2, sm8500_b2w[ea & 0x07] );
+ } else {
+ dst += sprintf( dst, "@$%04X", ea2 );
+ }
+ break;
+ case 0xC0:
+ dst += sprintf( dst, "-(rr%02Xh)", sm8500_b2w[ea & 0x07] ); break;
+ }
+ break;
+ case AM_mws:
+ ea = oprom[pos++];
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "@rr%02Xh", sm8500_b2w[ea & 0x07] ); break;
+ case 0x40:
+ dst += sprintf( dst, "(rr%02Xh)+", sm8500_b2w[ea & 0x07] ); break;
+ case 0x80:
+ ea2 = oprom[pos++] << 8;
+ ea2 += oprom[pos++];
+ if ( ea & 0x07 ) {
+ dst += sprintf( dst, "$%04X(rr%02Xh)", ea2, sm8500_b2w[ea & 0x07] );
+ } else {
+ dst += sprintf( dst, "@$%04X", ea2 );
+ }
+ break;
+ case 0xC0:
+ dst += sprintf( dst, "-(rr%02Xh)", sm8500_b2w[ea & 0x07] ); break;
+ }
+ dst += sprintf( dst, ",rr%02Xh", sm8500_b2w[( ea >> 3 ) & 0x07] );
+ break;
+ case AM_cbr:
+ offset = (INT8) oprom[pos++];
+ dst += sprintf( dst, "%s,$%04X", sm8500_cond[ op & 0x0F ], pc + pos + offset );
+ break;
+ case AM_rbr:
+ offset = (INT8) oprom[pos++];
+ dst += sprintf( dst, "r%02Xh,$%04X", op & 0x07, pc + pos + offset );
+ break;
+ case AM_cjp:
+ ea = oprom[pos++] << 8;
+ ea += oprom[pos++];
+ dst += sprintf( dst, "%s,$%04X", sm8500_cond[ op & 0x0F], ea );
+ break;
+ case AM_rr:
+ ea = oprom[pos++];
+ switch( ea & 0xc0 ) {
+ case 0x00:
+ dst += sprintf( dst, "r%02Xh,r%02Xh", (ea >> 3 ) & 0x07, ea & 0x07 );
+ break;
+ case 0x40:
+ case 0x80:
+ case 0xC0:
+ dst += sprintf( dst, "undef" );
+ break;
+ }
+ break;
+ case AM_r1:
+ ea = oprom[pos++];
+ switch( ea & 0xC0 ) {
+ dst += sprintf( dst, "@r%02Xh", (ea >> 3 ) & 0x07 );
+ break;
+ case 0x40:
+ case 0x80:
+ case 0xC0:
+ dst += sprintf( dst, "undef" );
+ break;
+ }
+ break;
+ case AM_S:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "RR%02Xh", ea );
+ break;
+ case AM_pi:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "r%02Xh, $%02X", 0x10 + (op & 0x07), ea );
+ break;
+ case AM_Ri:
+ ea = oprom[pos++];
+ ea2 = oprom[pos++];
+ dst += sprintf( dst, "R%02Xh,$%02X", ea, ea2 );
+ break;
+ case AM_i:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case AM_ii:
+ ea = oprom[pos++] << 8;
+ ea += oprom[pos++];
+ dst += sprintf( dst, "$%04X", ea );
+ break;
+ case AM_ss:
+ ea = oprom[pos++];
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "rr%02Xh,rr%02Xh", sm8500_b2w[( ea >> 3 ) & 0x07], sm8500_b2w[ea & 0x07] ); break;
+ case 0x40:
+ dst += sprintf( dst, "undef" ); break;
+ case 0x80:
+ dst += sprintf( dst, "undef" ); break;
+ case 0xC0:
+ dst += sprintf( dst, "undef" ); break;
+ }
+ break;
+ case AM_RR:
+ ea = oprom[pos++];
+ ea2 = oprom[pos++];
+ dst += sprintf( dst, "R%02Xh,R%02Xh", ea2, ea );
+ break;
+ case AM_2:
+ ea = oprom[pos++];
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "rr%02Xh", sm8500_b2w[ea & 0x07] ); break;
+ case 0x40:
+ ea2 = oprom[pos++] << 8;
+ ea2 += oprom[pos++];
+ if ( ea & 0x38 ) {
+ dst += sprintf( dst, "@$%04X(r%02Xh)", ea2, ( ea >> 3 ) & 0x07 );
+ } else {
+ dst += sprintf( dst, "@$%04X", ea2 );
+ }
+ break;
+ case 0x80:
+ dst += sprintf( dst, "undef" ); break;
+ case 0xC0:
+ dst += sprintf( dst, "undef" ); break;
+ }
+ break;
+ case AM_SS:
+ ea = oprom[pos++];
+ ea2 = oprom[pos++];
+ dst += sprintf( dst, "RR%02Xh,RR%02Xh", ea2, ea );
+ break;
+ case AM_bR:
+ ea = oprom[pos++];
+ ea2 = oprom[pos++];
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "BF,R%02Xh,#%d", ea2, ea & 0x07 ); break;
+ case 0x40:
+ dst += sprintf( dst, "R%02Xh,#%d,BF", ea2, ea & 0x07 ); break;
+ case 0x80:
+ dst += sprintf( dst, "undef" ); break;
+ case 0xC0:
+ dst += sprintf( dst, "undef" ); break;
+ }
+ break;
+ case AM_Rbr:
+ ea = oprom[pos++];
+ offset = (INT8) oprom[pos++];
+ dst += sprintf( dst, "R%02Xh,#%d,$%04X", ea, op & 0x07, pc + pos + offset );
+ break;
+ case AM_Rb:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "R%02Xh,#%d", ea, op&0x07 );
+ break;
+ case AM_rR:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "r%02Xh,R%02Xh", op & 0x07, ea );
+ break;
+ case AM_Rr:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "R%02Xh,r%02Xh", ea, op & 0x07 );
+ break;
+ case AM_Rii:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "R%02Xh,", ea );
+ ea = oprom[pos++];
+ dst += sprintf( dst, "$%02X,", ea );
+ ea = oprom[pos++];
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case AM_RiR:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "R%02Xh,", ea );
+ ea = oprom[pos++];
+ dst += sprintf( dst, "$%02X,", ea );
+ ea = oprom[pos++];
+ dst += sprintf( dst, "R%02Xh", ea );
+ break;
+ case AM_riB:
+ ea = oprom[pos++];
+ ea2 = oprom[pos++];
+ switch( ea & 0xC0 ) {
+ case 0x00:
+ dst += sprintf( dst, "#%2x(r%02Xh),#%d", ea2, ea >> 3, ea & 0x07 );
+ break;
+ case 0x40:
+ dst += sprintf( dst, "undef" ); break;
+ case 0x80:
+ dst += sprintf( dst, "undef" ); break;
+ case 0xC0:
+ dst += sprintf( dst, "undef" ); break;
+ }
+ break;
+ case AM_CALS:
+ ea = oprom[pos++];
+ dst += sprintf( dst, "$%04X", 0x1000 | ( ( op & 0x0f ) << 8 ) | ea );
+ break;
+ case AM_bid:
+ ea = oprom[pos++];
+ ea2 = oprom[pos++];
+ if ( ea & 0x38 ) {
+ dst += sprintf( dst, "$%02X(r%02Xh)", ea2, ( ea >> 3 ) & 0x07 );
+ } else {
+ dst += sprintf( dst, "$%04X", 0xFF00 + ea2 );
+ }
+ dst += sprintf( dst, ",#%d,", ea & 0x07 );
+ offset = (INT8) oprom[pos++];
+ dst += sprintf( dst, "$%04X", pc + pos + offset );
+ break;
+ case AM_1A:
+ ea = oprom[pos++];
+ switch( ea & 0x07 ) {
+ case 0x00: dst += sprintf( dst, "%-4s ", s_mnemonic[ zCLR ] ); break;
+ case 0x01: dst += sprintf( dst, "%-4s ", s_mnemonic[ zNEG ] ); break;
+ case 0x02: dst += sprintf( dst, "%-4s ", s_mnemonic[ zCOM ] ); break;
+ case 0x03: dst += sprintf( dst, "%-4s ", s_mnemonic[ zRR ] ); break;
+ case 0x04: dst += sprintf( dst, "%-4s ", s_mnemonic[ zRL ] ); break;
+ case 0x05: dst += sprintf( dst, "%-4s ", s_mnemonic[ zRRC ] ); break;
+ case 0x06: dst += sprintf( dst, "%-4s ", s_mnemonic[ zRLC ] ); break;
+ case 0x07: dst += sprintf( dst, "%-4s ", s_mnemonic[ zSRL ] ); break;
+ }
+ dst += sprintf( dst, "@r%02Xh", ( ea >> 3 ) & 0x07 );
+ break;
+ case AM_1B:
+ ea = oprom[pos++];
+ switch( ea & 0x07 ) {
+ case 0x00: dst += sprintf( dst, "%-4s ", s_mnemonic[ zINC ] ); break;
+ case 0x01: dst += sprintf( dst, "%-4s ", s_mnemonic[ zDEC ] ); break;
+ case 0x02: dst += sprintf( dst, "%-4s ", s_mnemonic[ zSRA ] ); break;
+ case 0x03: dst += sprintf( dst, "%-4s ", s_mnemonic[ zSLL ] ); break;
+ case 0x04: dst += sprintf( dst, "%-4s ", s_mnemonic[ zDA ] ); break;
+ case 0x05: dst += sprintf( dst, "%-4s ", s_mnemonic[ zSWAP ] ); break;
+ case 0x06: dst += sprintf( dst, "%-4s ", s_mnemonic[ zPUSH ] ); break;
+ case 0x07: dst += sprintf( dst, "%-4s ", s_mnemonic[ zPOP ] ); break;
+ }
+ dst += sprintf( dst, "@r%02Xh", ( ea >> 3 ) & 0x07 );
+ break;
+ case AM_4F:
+ ea = oprom[pos++];
+ ea2 = oprom[pos++];
+ switch( ea & 0xc0 ) {
+ case 0x00: dst += sprintf( dst, "%-4s ", s_mnemonic[ zBCMP ] ); break;
+ case 0x40: dst += sprintf( dst, "%-4s ", s_mnemonic[ zBAND ] ); break;
+ case 0x80: dst += sprintf( dst, "%-4s ", s_mnemonic[ zBOR ] ); break;
+ case 0xC0: dst += sprintf( dst, "%-4s ", s_mnemonic[ zBXOR ] ); break;
+ }
+ if ( ! ( ea & 0x80 ) ) {
+ dst += sprintf( dst, "BF," );
+ }
+ dst += sprintf( dst, "R%02Xh,$%02X", ea2, ea & 0x07 );
+ if ( ea & 0x80 ) {
+ dst += sprintf( dst, ",BF" );
+ }
+ break;
+ }
+ }
+ else
+ {
+ dst += sprintf( dst, "%s", s_mnemonic[ instr->mnemonic ] );
+ }
+
+ return pos | s_flags[instr->mnemonic] | DASMFLAG_SUPPORTED;
+}
+
diff --git a/src/emu/cpu/sm8500/sm85ops.h b/src/emu/cpu/sm8500/sm85ops.h
new file mode 100644
index 00000000000..0f8faf97ff2
--- /dev/null
+++ b/src/emu/cpu/sm8500/sm85ops.h
@@ -0,0 +1,1686 @@
+
+#define ARG_R r1 = sm85cpu_mem_readbyte( regs.PC++ );
+
+#define ARG_RR r2 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ r1 = sm85cpu_mem_readbyte( regs.PC++ );
+
+#define ARG_rR r1 = op & 0x07; \
+ r2 = sm85cpu_mem_readbyte( regs.PC++ );
+
+#define ARG_iR r2 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ r1 = sm85cpu_mem_readbyte( regs.PC++ );
+
+#define ARG_Sw r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ s2 = sm85cpu_mem_readword( regs.PC ); regs.PC += 2;
+
+#define ARG_rrw r1 = sm8500_b2w[op & 0x07]; \
+ s2 = sm85cpu_mem_readword( regs.PC ); regs.PC += 2;
+
+#define ARG_ri r1 = op & 0x07; \
+ r2 = sm85cpu_mem_readbyte( regs.PC++ );
+
+#define ARG_pi r1 = 0x10 + ( op & 0x07 ); \
+ r2 = sm85cpu_mem_readbyte( regs.PC++ );
+
+#define ARG_rmb r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ s2 = 0; \
+ switch( r1 & 0xC0 ) { \
+ case 0x00: \
+ s2 = sm85cpu_mem_readbyte( r1 & 0x07 ); \
+ break; \
+ case 0x40: \
+ s2 = sm85cpu_mem_readbyte( r1 & 0x07 ); \
+ sm85cpu_mem_writebyte( r1 & 0x07, s2 + 1 ); \
+ break; \
+ case 0x80: \
+ s2 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ if ( r1 & 0x07 ) { \
+ s2 = s2 + sm85cpu_mem_readbyte( r1 & 0x07 ); \
+ } \
+ break; \
+ case 0xC0: \
+ s2 = sm85cpu_mem_readbyte( r1 & 0x07 ); \
+ sm85cpu_mem_writebyte( r1 & 0x07, s2 - 1 ); \
+ break; \
+ } \
+ r2 = r1; \
+ r1 = ( r1 >> 3 ) & 0x07;
+
+#define ARG_rmw r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ s2 = 0; \
+ switch( r1 & 0xC0 ) { \
+ case 0x00: \
+ s2 = sm85cpu_mem_readword( sm8500_b2w[r1 & 0x07] ); \
+ break; \
+ case 0x40: \
+ s2 = sm85cpu_mem_readword( sm8500_b2w[r1 & 0x07] ); \
+ sm85cpu_mem_writeword( sm8500_b2w[r1 & 0x07], s2 + 1 ); \
+ break; \
+ case 0x80: \
+ s2 = sm85cpu_mem_readword( regs.PC ); regs.PC += 2; \
+ if ( r1 & 0x07 ) { \
+ s2 = s2 + sm85cpu_mem_readword( sm8500_b2w[r1 & 0x07] ); \
+ } \
+ break; \
+ case 0xC0: \
+ s2 = sm85cpu_mem_readword( sm8500_b2w[r1 & 0x07] ); \
+ sm85cpu_mem_writeword( sm8500_b2w[r1 & 0x07], s2 - 1 ); \
+ break; \
+ } \
+ r2 = r1; \
+ r1 = ( r1 >> 3 ) & 0x07;
+
+#define ARG_smw r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ s2 = 0; \
+ switch( r1 & 0xC0 ) { \
+ case 0x00: \
+ s2 = sm85cpu_mem_readword( sm8500_b2w[r1 & 0x07] ); \
+ break; \
+ case 0x40: \
+ s2 = sm85cpu_mem_readword( sm8500_b2w[r1 & 0x07] ); \
+ sm85cpu_mem_writeword( sm8500_b2w[r1 & 0x07], s2 + 1 ); \
+ break; \
+ case 0x80: \
+ s2 = sm85cpu_mem_readword( regs.PC ); regs.PC += 2; \
+ if ( r1 & 0x07 ) { \
+ s2 = s2 + sm85cpu_mem_readword( sm8500_b2w[r1 & 0x07] ); \
+ } \
+ break; \
+ case 0xC0: \
+ s2 = sm85cpu_mem_readword( sm8500_b2w[ r1 & 0x07] ); \
+ sm85cpu_mem_writeword( sm8500_b2w[r1 & 0x07], s2 - 1 ); \
+ break; \
+ } \
+ r2 = r1; \
+ r1 = sm8500_b2w[ ( r1 >> 3 ) & 0x07 ];
+
+#define ARG_d8 r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ s2 = regs.PC + ((INT8)r1);
+
+#define ARG_Rbr r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ r2 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ s2 = regs.PC + ((INT8)r2);
+
+#define ARG_ad16 s2 = sm85cpu_mem_readword( regs.PC ); \
+ regs.PC += 2;
+
+#define ARG_rr r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ r2 = 0x00; \
+ switch( r1 & 0xC0 ) { \
+ case 0x00: \
+ r2 = r1 & 0x07; \
+ r1 = ( r1 >> 3 ) & 0x07; \
+ break; \
+ case 0x40: \
+ case 0x80: \
+ case 0xC0: \
+ break; \
+ }
+
+#define ARG_ss r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ r2 = 0x00; \
+ switch( r1 & 0xC0 ) { \
+ case 0x00: \
+ r2 = sm8500_b2w[r1 & 0x07]; \
+ r1 = sm8500_b2w[( r1 >> 3 ) & 0x07]; \
+ break; \
+ case 0x40: \
+ case 0x80: \
+ case 0xC0: \
+ break; \
+ }
+
+#define ARG_2 r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ s2 = 0; \
+ switch( r1 & 0xC0 ) { \
+ case 0x00: \
+ s2 = sm85cpu_mem_readword( sm8500_b2w[ r1 & 0x07 ] ); \
+ break; \
+ case 0x40: \
+ s2 = sm85cpu_mem_readword( regs.PC ); regs.PC += 2; \
+ if ( r1 & 0x38 ) { \
+ s2 = s2 + sm85cpu_mem_readbyte( ( r1 >> 3 ) & 0x07 ); \
+ } \
+ s2 = sm85cpu_mem_readword( s2 ); \
+ case 0x80: \
+ case 0xC0: \
+ break; \
+ }
+
+#define ARG_RiR r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ d1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ r2 = sm85cpu_mem_readbyte( regs.PC++ );
+
+#define ARG_Rii r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ d1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ r2 = sm85cpu_mem_readbyte( regs.PC++ );
+
+#define ARG_riB r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ s2 = 1 << ( r1 & 0x07 ); \
+ d1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ if ( r1 & 0x38 ) { \
+ s1 = d1 + sm85cpu_mem_readbyte( ( r1 >> 3 ) & 0x07 ); \
+ } else { \
+ s1 = 0xFF00 + d1; \
+ }
+
+#define ARG_riBd r1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ s2 = 1 << ( r1 & 0x07 ); \
+ d1 = sm85cpu_mem_readbyte( regs.PC++ ); \
+ if ( r1 & 0x38 ) { \
+ s1 = d1 + sm85cpu_mem_readbyte( ( r1 >> 3 ) & 0x07 ); \
+ } else { \
+ s1 = 0xFF00 + d1; \
+ } \
+ d1 = sm85cpu_mem_readbyte( regs.PC++ );
+
+#define OP_INTSUB8(X,Y,MASK) d1 = X; \
+ d2 = Y; \
+ res = d1 - d2; \
+ regs.PS1 = regs.PS1 & ( MASK ); \
+ regs.PS1 = regs.PS1 | ( ( res > 0xFF ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d2 ^ d1 ) & ( res ^ d1 ) ) & 0x80 ) ? FLAG_V : 0 );
+
+#define OP_CMP8(X,Y) OP_INTSUB8( X, Y, (FLAG_B | FLAG_I | FLAG_H | FLAG_D ) );
+
+#define OP_SUB8(X,Y) OP_INTSUB8( X, Y, (FLAG_B | FLAG_I ) ); \
+ regs.PS1 = regs.PS1 | FLAG_D; \
+ regs.PS1 = regs.PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 );
+
+#define OP_INTSUB16(X,Y,MASK) d1 = X; \
+ d2 = Y; \
+ res = d1 - d2; \
+ regs.PS1 = regs.PS1 & ( MASK ); \
+ regs.PS1 = regs.PS1 | ( ( res > 0xFFFF ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d2 ^ d1 ) & (res ^ d1) ) & 0x8000 ) ? FLAG_V : 0 );
+
+#define OP_CMP16(X,Y) OP_INTSUB16( X, Y, ( FLAG_B | FLAG_I | FLAG_H | FLAG_D ) );
+
+#define OP_SUB16(X,Y) OP_INTSUB16( X, Y, ( FLAG_B | FLAG_I ) ); \
+ regs.PS1 = regs.PS1 | FLAG_D; \
+ regs.PS1 = regs.PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x0010 ) ? FLAG_H : 0 );
+
+#define OP_SBC8(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 - d2 - ((regs.PS1 & FLAG_C) ? 1 : 0); \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( res > 0xFF ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d2 ^ d1 ) & (res ^ d1) ) & 0x80 ) ? FLAG_V : 0 ); \
+ regs.PS1 = regs.PS1 | FLAG_D; \
+ regs.PS1 = regs.PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 );
+
+#define OP_SBC16(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 - d2 - ((regs.PS1 & FLAG_C) ? 1 : 0); \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( res > 0xFFFF ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d2 ^ d1 ) & ( res ^ d1 ) ) & 0x8000 ) ? FLAG_V : 0 ); \
+ regs.PS1 = regs.PS1 | FLAG_D; \
+ regs.PS1 = regs.PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 );
+
+#define OP_ADD8(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 + d2; \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( res > 0xFF ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d2 ^ d1 ^ 0x80 ) & (res ^ d1) ) & 0x80 ) ? FLAG_V : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 );
+
+#define OP_ADD16(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 + d2; \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( res > 0xFFFF ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d2 ^ d1 ) & ( res ^ d1 ) ) & 0x8000 ) ? FLAG_V : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( d2 ^ d1 ^ res ) & 0x0010 ) ? FLAG_H : 0 );
+
+#define OP_ADC8(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 + d2 + ((regs.PS1 & FLAG_C) ? 1 : 0); \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( res > 0xFF ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d2 ^ d1 ) & (res ^ d1) ) & 0x80 ) ? FLAG_V : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 );
+
+#define OP_ADC16(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 + d2 + ((regs.PS1 & FLAG_C) ? 1 : 0); \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( res > 0xFFFF ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d2 ^ d1 ) & ( res ^ d1) ) & 0x8000 ) ? FLAG_V : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 );
+
+#define OP_NEG8(X) res = -X; \
+ regs.PS1 = regs.PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_C | FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0x80 ) ? FLAG_V : 0 );
+
+#define OP_COM8(X) res = ~X; \
+ regs.PS1 = regs.PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 );
+
+#define OP_RR8(X) d1 = X; \
+ res = d1 >> 1; \
+ if ( d1 & 0x01 ) { \
+ res |= 0x80; \
+ } \
+ regs.PS1 = regs.PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( d1 & 0x01 ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d1 ^ res ) & 0x80 ) && ! ( res & 0x80 ) ) ? FLAG_V : 0 );
+
+#define OP_RL8(X) d1 = X; \
+ res = d1 << 1; \
+ if ( d1 & 0x80 ) { \
+ res |= 0x01; \
+ } \
+ regs.PS1 = regs.PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( d1 & 0x80 ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( d1 ^ res ) & 0x80 ) ? FLAG_V : 0 );
+
+#define OP_RRC8(X) d1 = X; \
+ res = d1 >> 1; \
+ if ( regs.PS1 & FLAG_C ) { \
+ res |= 0x80; \
+ } \
+ regs.PS1 = regs.PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( d1 & 0x01 ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d1 ^ res ) & 0x80 ) && ! ( res & 0x80 ) ) ? FLAG_V : 0 );
+
+#define OP_RLC8(X) d1 = X; \
+ res = d1 << 1; \
+ if ( regs.PS1 & FLAG_C ) { \
+ res |= 0x01; \
+ } \
+ regs.PS1 = regs.PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( d1 & 0x80 ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( d1 ^ res ) & 0x80 ) ? FLAG_V : 0 );
+
+#define OP_SRL8(X) d1 = X; \
+ res = d1 >> 1; \
+ regs.PS1 = regs.PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( d1 & 0x01 ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 );
+
+#define OP_SRA8(X) d1 = X; \
+ res = d1 >> 1; \
+ if ( d1 & 0x80 ) { \
+ res |= 0x80; \
+ } \
+ regs.PS1 = regs.PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( d1 & 0x01 ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 );
+
+#define OP_SLL8(X) d1 = X; \
+ res = d1 << 1; \
+ regs.PS1 = regs.PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( d1 & 0x80 ) ? FLAG_C : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 );
+
+#define OP_INC8(X) d1 = X; \
+ res = d1 + 1; \
+ regs.PS1 = regs.PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d1 ^ res ) & 0x80 ) && ! ( res & 0x80 ) ) ? FLAG_V : 0 );
+
+#define OP_INC16(X) d1 = X; \
+ res = d1 + 1; \
+ regs.PS1 = regs.PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d1 ^ res ) & 0x8000 ) && ! ( res & 0x8000 ) ) ? FLAG_V : 0 );
+
+#define OP_DEC8(X) d1 = X; \
+ res = d1 - 1; \
+ regs.PS1 = regs.PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d1 ^ res ) & 0x80 ) && ( res & 0x80 ) ) ? FLAG_V : 0 );
+
+#define OP_DEC16(X) d1 = X; \
+ res = d1 - 1; \
+ regs.PS1 = regs.PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( ( ( d1 ^ res ) & 0x8000 ) && ( res & 0x8000 ) ) ? FLAG_V : 0 );
+
+#define OP_AND8(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 & d2; \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 );
+
+#define OP_AND16(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 & d2; \
+ regs.PS1 = regs.PS1 & ( FLAG_C | FLAG_S | FLAG_B | FLAG_I | FLAG_H | FLAG_D ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 );
+
+#define OP_OR8(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 | d2; \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 );
+
+#define OP_OR16(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 | d2; \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D | FLAG_C | FLAG_S ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 );
+
+#define OP_XOR8(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 ^ d2; \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 );
+
+#define OP_XOR16(X,Y) d1 = X; \
+ d2 = Y; \
+ res = d1 ^ d2; \
+ regs.PS1 = regs.PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D | FLAG_C | FLAG_S ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 );
+
+#define OP_DA8(X) d1 = X; \
+ res = d1; \
+ if ( regs.PS1 & FLAG_D ) { \
+ if ( regs.PS1 & FLAG_C ) { \
+ if ( regs.PS1 & FLAG_H ) { \
+ res += 0x9A; \
+ } else { \
+ res += 0xA0; \
+ } \
+ } else { \
+ if ( regs.PS1 & FLAG_H ) { \
+ res += 0xFA; \
+ } \
+ } \
+ } else { \
+ if ( regs.PS1 & FLAG_C ) { \
+ if ( regs.PS1 & FLAG_H ) { \
+ res += 0x66; \
+ } else { \
+ if ( ( res & 0x0F ) < 10 ) { \
+ res += 0x60; \
+ } else { \
+ res += 0x66; \
+ } \
+ } \
+ } else { \
+ if ( regs.PS1 & FLAG_H ) { \
+ if ( ( res & 0xF0 ) < 0xA0 ) { \
+ res += 0x06; \
+ } else { \
+ res += 0x66; \
+ regs.PS1 = regs.PS1 | FLAG_C; \
+ } \
+ } else { \
+ if ( ( res & 0x0F ) < 10 ) { \
+ if ( ( res & 0xF0 ) >= 0xA0 ) { \
+ res += 0x60; \
+ regs.PS1 = regs.PS1 | FLAG_C; \
+ } \
+ } else { \
+ if ( ( res & 0xF0 ) < 0x90 ) { \
+ res += 0x06; \
+ } else { \
+ res += 0x66; \
+ regs.PS1 = regs.PS1 | FLAG_C; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ regs.PS1 = regs.PS1 & ~ ( FLAG_Z | FLAG_S ); \
+ regs.PS1 = regs.PS1 | ( ( ( res & 0xFF ) == 0x00 ) ? FLAG_Z : 0 ); \
+ regs.PS1 = regs.PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 );
+
+#define OP_SWAP8(X) d1 = X; \
+ res = ( d1 << 4 ) | ( d1 >> 4 );
+
+#define CHECK_CC res = 0; \
+ switch( op & 0x0F ) { \
+ case 0x00: /* F */ res = 0; break; \
+ case 0x01: /* LT */ if ( ( regs.PS1 & FLAG_S ) ^ ( ( regs.PS1 & FLAG_V ) << 1 ) ) res = 1; break; \
+ case 0x02: /* LE */ if ( ( ( regs.PS1 & FLAG_S ) && ! ( regs.PS1 & FLAG_V ) ) || ( ( regs.PS1 & FLAG_S ) && ( regs.PS1 & FLAG_V ) && ( regs.PS1 & FLAG_Z ) ) || ( ! ( regs.PS1 & FLAG_S ) && ( ( regs.PS1 & FLAG_Z ) || (regs.PS1 & FLAG_V ) ) ) ) res = 1; break; \
+ case 0x03: /* ULE */ if ( regs.PS1 & FLAG_Z || regs.PS1 & FLAG_C ) res = 1; break; \
+ case 0x04: /* OV */ if ( regs.PS1 & FLAG_V ) res = 1; break; \
+ case 0x05: /* MI */ if ( regs.PS1 & FLAG_S ) res = 1; break; \
+ case 0x06: /* Z */ if ( regs.PS1 & FLAG_Z ) res = 1; break; \
+ case 0x07: /* C */ if ( regs.PS1 & FLAG_C ) res = 1; break; \
+ case 0x08: /* T */ res = 1; break; \
+ case 0x09: /* GE */ if ( ! ( ( regs.PS1 & FLAG_S ) ^ ( ( regs.PS1 & FLAG_V ) << 1 ) ) ) res = 1; break; \
+ case 0x0A: /* GT */ if ( ( ! ( regs.PS1 & FLAG_Z ) && ( regs.PS1 & FLAG_S ) && ( regs.PS1 & FLAG_V ) ) || ( ! ( regs.PS1 & FLAG_Z ) && ! ( regs.PS1 & FLAG_V ) && ! ( regs.PS1 & FLAG_S ) ) ) res = 1; break; \
+ case 0x0B: /* UGT */ if ( ! ( regs.PS1 & FLAG_Z || regs.PS1 & FLAG_C ) ) res = 1; break; \
+ case 0x0C: /* NOV */ if ( ! (regs.PS1 & FLAG_V) ) res = 1; break; \
+ case 0x0D: /* PL */ if ( ! (regs.PS1 & FLAG_S) ) res = 1; break; \
+ case 0x0E: /* NZ */ if ( ! (regs.PS1 & FLAG_Z) ) res = 1; break; \
+ case 0x0F: /* NC */ if ( ! (regs.PS1 & FLAG_C) ) res = 1; break; \
+ }
+
+#define PUSH8(X) regs.SP = regs.SP - 1; \
+ if ( ( regs.SYS & 0x40 ) == 0 ) { \
+ regs.SP = regs.SP & 0xFF; \
+ } \
+ sm85cpu_mem_writebyte( regs.SP, X );
+
+#define POP8(X) X = sm85cpu_mem_readbyte( regs.SP ); \
+ regs.SP = regs.SP + 1; \
+ if ( ( regs.SYS & 0x40 ) == 0 ) { \
+ regs.SP = regs.SP & 0xFF; \
+ }
+
+case 0x00: /* CLR R - 4 cycles - Flags affected: -------- */
+ ARG_R;
+ sm85cpu_mem_writebyte( r1, 0 );
+ mycycles += 4;
+ break;
+case 0x01: /* NEG R - 5 cycles - Flags affected: CZSV---- */
+ ARG_R;
+ OP_NEG8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1 , res & 0xFF );
+ mycycles += 5;
+ break;
+case 0x02: /* COM R - 4 cycles - Flags affected: -ZS0---- */
+ ARG_R;
+ OP_COM8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x03: /* RR R - 4 cycles - Flags affected: CZSV---- */
+ ARG_R;
+ OP_RR8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x04: /* RL R - 4 cycles - Flags affected: CZSV---- */
+ ARG_R;
+ OP_RL8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1 , res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x05: /* RRC R - 4 cycles - Flags affected: CZSV---- */
+ ARG_R;
+ OP_RRC8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x06: /* RLC R - 4 cycles - Flags affected: CZSV---- */
+ ARG_R;
+ OP_RLC8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x07: /* SRL R - 4 cycles - Flags affected: CZ00---- */
+ ARG_R;
+ OP_SRL8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x08: /* INC R - 4 cycles - Flags affected: -ZSV---- */
+ ARG_R;
+ OP_INC8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x09: /* DEC R - 4 cycles - Flags affected: -ZSV---- */
+ ARG_R;
+ OP_DEC8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x0A: /* SRA R - 4 cycles - Flags affected: CZS0---- */
+ ARG_R;
+ OP_SRA8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x0B: /* SLL R - 4 cycles - Flags affected: CZS0---- */
+ ARG_R;
+ OP_SLL8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x0C: /* DA R - 4 cycles - Flags affected: CZS----- */
+ ARG_R;
+ OP_DA8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 4;
+ break;
+case 0x0D: /* SWAP R - 7 cycles - Flags affected: -------- */
+ ARG_R;
+ OP_SWAP8( sm85cpu_mem_readbyte( r1 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 7;
+ break;
+case 0x0E: /* PUSH R - 5?/12? (8bit SP),10 (16bit SP) cycles */
+ ARG_R;
+ PUSH8( sm85cpu_mem_readbyte( r1 ) );
+ mycycles += ( ( regs.SYS & 0x40 ) ? 12 : 10 );
+ break;
+case 0x0F: /* POP R - 9,8 cycles */
+ ARG_R;
+ POP8( r2 );
+ sm85cpu_mem_writebyte( r1, r2 );
+ mycycles += ( ( regs.SYS & 0x40 ) ? 9 : 8 );
+ break;
+case 0x10: /* CMP Rr,Rs - 5 cycles - Flags affected: CZSV---- */
+ ARG_rr;
+ OP_CMP8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ mycycles += 5;
+ break;
+case 0x11: /* ADD Rr,Rs - 5 cycles - Flags affected: CZSV0H-- */
+ ARG_rr;
+ OP_ADD8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 5;
+ break;
+case 0x12: /* SUB Rr,Rs - 5 cycles - Flags affected: CZSV1H-- */
+ ARG_rr;
+ OP_SUB8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 5;
+ break;
+case 0x13: /* ADC Rr,Rs - 5 cycles - Flags affected: CZSV0H-- */
+ ARG_rr;
+ OP_ADC8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 5;
+ break;
+case 0x14: /* SBC Rr,Rs - 5 cycles - Flags affected: CZSV1H-- */
+ ARG_rr;
+ OP_SBC8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 5;
+ break;
+case 0x15: /* AND Rr,Rs - 5 cycles - Flags affected: -ZS0---- */
+ ARG_rr;
+ OP_AND8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 5;
+ break;
+case 0x16: /* OR Rr,Rs - 5 cycles - Flags affected: -ZS0---- */
+ ARG_rr;
+ OP_OR8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 5;
+ break;
+case 0x17: /* XOR Rr,Rs - 5 cycles - Flags affected: -ZS0---- */
+ ARG_rr;
+ OP_XOR8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 5;
+ break;
+case 0x18: /* INCW S - 8 cycles - Flags affected: -ZSV---- */
+ ARG_R;
+ OP_INC16( sm85cpu_mem_readword( r1 ) );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 8;
+ break;
+case 0x19: /* DECW S - 8 cycles - Flags affected: -ZSV---- */
+ ARG_R;
+ OP_DEC16( sm85cpu_mem_readword( r1 ) );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 8;
+ break;
+case 0x1A: /* CLR/NEG/COM/RR/RL/RRC/RLC/SRL @Rr - 7/8/7/7/7/7/7/6 cycles */
+ ARG_rr;
+ res = 0;
+ s1 = sm85cpu_mem_readbyte( r1 );
+ switch( r2 ) {
+ case 0x00: /* Flags affected: -------- */
+ res = 0;
+ mycycles += 7;
+ break;
+ case 0x01: /* Flags affected: CZSV---- */
+ OP_NEG8( sm85cpu_mem_readbyte( s1 ) );
+ mycycles += 8;
+ break;
+ case 0x02: /* Flags affected: -ZS0---- */
+ OP_COM8( sm85cpu_mem_readbyte( s1 ) );
+ mycycles += 7;
+ break;
+ case 0x03: /* Flags affected: CZSV---- */
+ OP_RR8( sm85cpu_mem_readbyte( s1 ) );
+ mycycles += 7;
+ break;
+ case 0x04: /* Flags affected: CZSV---- */
+ OP_RL8( sm85cpu_mem_readbyte( s1 ) );
+ mycycles += 7;
+ break;
+ case 0x05: /* Flags affected: CZSV---- */
+ OP_RRC8( sm85cpu_mem_readbyte( s1 ) );
+ mycycles += 7;
+ break;
+ case 0x06: /* Flags affected: CZSV---- */
+ OP_RLC8( sm85cpu_mem_readbyte( s1 ) );
+ mycycles += 7;
+ break;
+ case 0x07: /* Flags affected: CZ00---- */
+ OP_SRL8( sm85cpu_mem_readbyte( s1 ) );
+ mycycles += 6;
+ break;
+ }
+ sm85cpu_mem_writebyte( s1, res & 0xFF );
+ break;
+case 0x1B: /* INC/DEC/SRA/SLL/DA/SWAP/PUSH/POP @Rr - 7,7,6,7,9,13,8,12,11 cycles */
+ ARG_rr;
+ s1 = sm85cpu_mem_readbyte( r1 );
+ switch( r2 ) {
+ case 0x00: /* Flags affected: -ZSV---- */
+ OP_INC8( sm85cpu_mem_readbyte( s1 ) );
+ sm85cpu_mem_writebyte( s1, res & 0xFF );
+ mycycles += 7;
+ break;
+ case 0x01: /* Flags affected: -ZSV---- */
+ OP_DEC8( sm85cpu_mem_readbyte( s1 ) );
+ sm85cpu_mem_writebyte( s1, res & 0xFF );
+ mycycles += 7;
+ break;
+ case 0x02: /* Flags affected: CZS0---- */
+ OP_SRA8( sm85cpu_mem_readbyte( s1 ) );
+ sm85cpu_mem_writebyte( s1, res & 0xFF );
+ mycycles += 6;
+ break;
+ case 0x03: /* Flags affected: CZS0---- */
+ OP_SLL8( sm85cpu_mem_readbyte( s1 ) );
+ sm85cpu_mem_writebyte( s1, res & 0xFF );
+ mycycles += 6;
+ break;
+ case 0x04: /* Flags affected: CZS----- */
+ OP_DA8( sm85cpu_mem_readbyte( s1 ) );
+ sm85cpu_mem_writebyte( s1, res & 0xFF );
+ mycycles += 7;
+ break;
+ case 0x05: /* Flags affected: -------- */
+ OP_SWAP8( sm85cpu_mem_readbyte( s1 ) );
+ sm85cpu_mem_writebyte( s1, res & 0xFF );
+ mycycles += 9;
+ break;
+ case 0x06: /* Flags affected: -------- */
+ PUSH8( sm85cpu_mem_readbyte( s1 ) );
+ mycycles += ( ( regs.SYS & 0x40 ) ? 13 : 8 );
+ break;
+ case 0x07: /* Flags affected: -------- */
+ POP8( res );
+ sm85cpu_mem_writebyte( s1, res );
+ mycycles += ( ( regs.SYS & 0x40 ) ? 12 : 11 );
+ break;
+ }
+ break;
+case 0x1C: /* BCLR 0xFFdd/d8(r),#b - 12,8 cycles - Flags affected: -------- */
+ ARG_riB;
+ sm85cpu_mem_writebyte( s1, sm85cpu_mem_readbyte( s1 ) & ~s2 );
+ mycycles += ( ( r1 & 0x38 ) ? 8 : 12 );
+ break;
+case 0x1D: /* BSET 0xFFdd/d8(r),#b - 12,8 cycles - Flags affected: -------- */
+ ARG_riB;
+ sm85cpu_mem_writebyte( s1, sm85cpu_mem_readbyte( s1 ) | s2 );
+ mycycles += ( ( r1 & 0x38 ) ? 8 : 12 );
+ break;
+case 0x1E: /* PUSHW S - 12,9 cycles - Flags affected: -------- */
+ ARG_R;
+ PUSH8( sm85cpu_mem_readbyte( r1 + 1 ) );
+ PUSH8( sm85cpu_mem_readbyte( r1 ) );
+ mycycles += ( ( regs.SYS & 0x40 ) ? 12 : 9 );
+ break;
+case 0x1F: /* POPW S - 12,13 cycles - Flags affected: -------- */
+ ARG_R;
+ POP8( r2 );
+ sm85cpu_mem_writebyte( r1, r2 );
+ POP8( r2 );
+ sm85cpu_mem_writebyte( r1 + 1, r2 );
+ mycycles += ( ( regs.SYS & 0x40 ) ? 12 : 13 );
+ break;
+case 0x20: /* CMP r,@r / CMP r,(r)+ / CMP r,@w / CMP r,w(r) / CMP r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV---- */
+ ARG_rmb;
+ OP_CMP8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 7; break;
+ case 0x40: mycycles += 8; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break;
+ case 0xC0: mycycles += 9; break;
+ }
+ break;
+case 0x21: /* ADD r,@r / ADD r,(r)+ / ADD r,@w / ADD r,w(r) / ADD r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV0H-- */
+ ARG_rmb;
+ OP_ADD8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 7; break;
+ case 0x40: mycycles += 8; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break;
+ case 0xC0: mycycles += 9; break;
+ }
+ break;
+case 0x22: /* SUB r,@r / SUB r,(r)+ / SUB r,@w / SUB r,w(r) / SUB r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV1H-- */
+ ARG_rmb;
+ OP_SUB8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 7; break;
+ case 0x40: mycycles += 8; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break;
+ case 0xC0: mycycles += 9; break;
+ }
+ break;
+case 0x23: /* ADC r,@r / ADC r,(r)+ / ADC r,@w / ADC r,w(r) / ADC r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV0H-- */
+ ARG_rmb;
+ OP_ADC8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 7; break;
+ case 0x40: mycycles += 8; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break;
+ case 0xC0: mycycles += 9; break;
+ }
+ break;
+case 0x24: /* SBC r,@r / SBC r,(r)+ / SBC r,@w / SBC r,w(r) / SBC r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV1H-- */
+ ARG_rmb;
+ OP_SBC8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 7; break;
+ case 0x40: mycycles += 8; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break;
+ case 0xC0: mycycles += 9; break;
+ }
+ break;
+case 0x25: /* AND r,@r / AND r,(r)+ / AND r,@w / AND r,w(r) / AND r,-(r) - 7,8,10,8,9 cycles - Flags affected: -ZS0---- */
+ ARG_rmb;
+ OP_AND8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 7; break;
+ case 0x40: mycycles += 8; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break;
+ case 0xC0: mycycles += 9; break;
+ }
+ break;
+case 0x26: /* OR r,@r / OR r,(r)+ / OR r,@w / OR r,w(r) / OR r,-(r) - 7,8,10,8,9 cycles - Flags affected: -ZS0---- */
+ ARG_rmb;
+ OP_OR8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 7; break;
+ case 0x40: mycycles += 8; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break;
+ case 0xC0: mycycles += 9; break;
+ }
+ break;
+case 0x27: /* XOR r,@r / XOR r,(r)+ / XOR r,@w / XOR r,w(r) / XOR r,-(r) - 7,8,10,8,9 cycles - Flags affected: -ZS0---- */
+ ARG_rmb;
+ OP_XOR8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 7; break;
+ case 0x40: mycycles += 8; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break;
+ case 0xC0: mycycles += 9; break;
+ }
+ break;
+case 0x28: /* MOV r,@r / MOV r,(r)+ / MOV r,@w / MOV r,w(r) / MOV r,-(r) - 6,7,10,7,8 cycles - Flags affected: -------- */
+ ARG_rmb;
+ sm85cpu_mem_writebyte( r1, sm85cpu_mem_readbyte( s2 ) );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 6; break;
+ case 0x40: mycycles += 7; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 7 : 10 ); break;
+ case 0xC0: mycycles += 8; break;
+ }
+ break;
+case 0x29: /* MOV @r,r / MOV (r)+,r / MOV @w,r / MOV w(r),r / MOV -(r),r - 8,8,10,9,9 cycles - Flags affected: -------- */
+ ARG_rmb;
+ sm85cpu_mem_writebyte( s2, sm85cpu_mem_readbyte( r1 ) );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 8; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 9 : 10 ); break;
+ case 0xC0: mycycles += 9; break;
+ }
+ break;
+case 0x2A: /* BBC FFii/i(Rr),#b,d8 - 16,12/14,10 cycles - Flags affected: -------- */
+ ARG_riBd;
+ if ( sm85cpu_mem_readbyte( s1 ) & s2 ) {
+ mycycles += 10;
+ } else {
+ regs.PC = regs.PC + ((INT8)d1);
+ mycycles += 14;
+ }
+ if ( ( r1 & 0x38 ) == 0 ) {
+ mycycles += 2;
+ }
+ break;
+case 0x2B: /* BBS FFii/i(Rr),#b,d8 - 16,12/14,10 cycles - Flags affected: -------- */
+ ARG_riBd;
+ if ( sm85cpu_mem_readbyte( s1 ) & s2 ) {
+ regs.PC = regs.PC + ((INT8)d1);
+ mycycles += 14;
+ } else {
+ mycycles += 10;
+ }
+ if ( ( r1 & 0x38 ) == 0 ) {
+ mycycles += 2;
+ }
+ break;
+case 0x2C: /* EXTS Rr - 6 cycles - Flags affected: -------- */
+ ARG_R;
+ res = sm85cpu_mem_readword( r1 );
+ if ( res & 0x80 ) {
+ res = res | 0xFF00;
+ } else {
+ res = res & 0x00FF;
+ }
+ sm85cpu_mem_writeword( r1, res );
+ mycycles += 6;
+ break;
+case 0x2D: /* unk2D - 4 cycles */
+logerror( "%04X: unk%02x\n", regs.PC-1,op );
+ mycycles += 4;
+ break;
+case 0x2E: /* MOV PS0,#00 - 4 cycles - Flags affected: -------- */
+ ARG_R;
+ regs.PS0 = r1; regs.register_base = regs.internal_ram + ( r1 & 0xF8 );
+ mycycles += 4;
+ break;
+case 0x2F: /* BTST R,i - 6 cycles - Flags affected: -Z-0---- */
+ ARG_RR;
+ regs.PS1 = regs.PS1 & ~ FLAG_V;
+ if ( ( sm85cpu_mem_readbyte( r2 ) & r1 ) == 0x00 ) {
+ regs.PS1 = regs.PS1 | FLAG_Z;
+ } else {
+ regs.PS1 = regs.PS1 & ( ~ FLAG_Z );
+ }
+ mycycles += 6;
+ break;
+case 0x30: /* CMP r,@rr / CMP r,(rr)+ / CMP r,@ww / CMP r,ww(rr) / CMP r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV---- */
+ ARG_rmw;
+ OP_CMP8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x31: /* ADD r,@rr / ADD r,(rr)+ / ADD r,@ww / ADD r,ww(rr) / ADD r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV0H-- */
+ ARG_rmw;
+ OP_ADD8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x32: /* SUB r,@rr / SUB r,(rr)+ / SUB r,@ww / SUB r,ww(rr) / SUB r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV1H-- */
+ ARG_rmw;
+ OP_SUB8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x33: /* ADC r,@rr / ADC r,(rr)+ / ADC r,@ww / ADC r,ww(rr) / ADC r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV0H-- */
+ ARG_rmw;
+ OP_ADC8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x34: /* SBC r,@rr / SBC r,(rr)+ / SBC r,@ww / SBC r,ww(rr) / SBC r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV1H-- */
+ ARG_rmw;
+ OP_SBC8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x35: /* AND r,@rr / AND r,(rr)+ / AND r,@ww / AND r,ww(rr) / AND r,-(rr) - 8,13,11,15,13 cycles - Flags affected: -ZS0---- */
+ ARG_rmw;
+ OP_AND8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x36: /* OR r,@rr / OR r,(rr)+ / OR r,@ww / OR r,ww(rr) / OR r,-(rr) - 8,13,11,15,13 cycles - Flags affected: -ZS0---- */
+ ARG_rmw;
+ OP_OR8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x37: /* XOR? r,@rr / XOR r,(rr)+ / XOR r,@ww / XOR r,ww(rr) / XOR r,-(rr) - 8,13,11,15,13 cycles - Flagsaffected: -ZS0---- */
+ ARG_rmw;
+ OP_XOR8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( s2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x38: /* MOV r,@rr / MOV r,(rr)+ / MOV r,@ww / MOV r,ww(rr) / MOV r,-(rr) - 8,13,11,15,13 cycles - Flags affected: -------- */
+ ARG_rmw;
+ sm85cpu_mem_writebyte( r1, sm85cpu_mem_readbyte( s2 ) );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x39: /* MOV @rr,r / MOV (rr)+,r / MOV @ww,r / MOV ww(rr),r / MOV -(rr),r - 8,13,11,15,13 cycles - Flags affected: -------- */
+ ARG_rmw;
+ sm85cpu_mem_writebyte( s2, sm85cpu_mem_readbyte( r1 ) );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 8; break;
+ case 0x40: mycycles += 13; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break;
+ case 0xC0: mycycles += 13; break;
+ }
+ break;
+case 0x3A: /* MOVW rr,@rr / MOV rr,(rr)+ / MOV rr,@ww / MOV rr,ww(rr) / MOV rr,-(rr) - 11,16,14,18,16 cycles - Flags affected: -------- */
+ ARG_smw;
+ sm85cpu_mem_writeword( r1, sm85cpu_mem_readword( s2 ) );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 11; break;
+ case 0x40: mycycles += 16; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 18 : 14 ); break;
+ case 0xC0: mycycles += 16; break;
+ }
+ break;
+case 0x3B: /* MOVW @rr,rr / MOV (rr)+,rr / MOV @ww,rr / MOV ww(rr),rr / MOV -(rr),rr - 11,16,14,18,16 cycles - Flags affected: -------- */
+ ARG_smw;
+ sm85cpu_mem_writeword( s2, sm85cpu_mem_readword( r1 ) );
+ switch( r2 & 0xC0 ) {
+ case 0x00: mycycles += 11; break;
+ case 0x40: mycycles += 16; break;
+ case 0x80: mycycles += ( ( r2 & 0x07 ) ? 18 : 14 ); break;
+ case 0xC0: mycycles += 16; break;
+ }
+ break;
+case 0x3C: /* MOVW RRr,RRs - 7 cycles - Flags affected: -------- */
+ ARG_ss;
+ sm85cpu_mem_writeword( r1, sm85cpu_mem_readword( r2 ) );
+ mycycles += 7;
+ break;
+case 0x3D: /* unk3D DM??? 3D 0E -> DM R0Eh ?? - 4,4 cycles */
+logerror( "%04X: unk%02x\n", regs.PC-1,op );
+ mycycles += 4;
+ break;
+case 0x3E: /* JMP RRr/@ww/ww(RRr) - 7/15/19 cycles - Flags affected: -------- */
+ ARG_2;
+ regs.PC = s2;
+ switch( r1 & 0xc0 ) {
+ case 0x00: mycycles += 7; break;
+ case 0x40: mycycles += ( ( r1 & 0x38 ) ? 19 : 15 ); break;
+ default: mycycles += 4;
+ }
+ break;
+case 0x3F: /* CALL RRr/@ww/ww(RRr) - 11,14/22,19/26,23 cycles - Flags affected: -------- */
+ ARG_2;
+ PUSH8( regs.PC & 0xFF );
+ PUSH8( regs.PC >> 8 );
+ regs.PC = s2;
+ switch( r1 & 0xc0 ) {
+ case 0x00: mycycles += ( ( regs.SYS & 0x40 ) ? 14 : 11 ); break;
+ case 0x40: mycycles += ( ( r1 & 0x38 ) ? ( ( regs.SYS & 0x40 ) ? 26 : 23 ) : ( ( regs.SYS & 0x40 ) ? 22 : 19 ) );break;
+ default: mycycles += 4;
+ }
+ break;
+case 0x40: /* CMP Rr,Rs - 6 cycles - Flags affected: CZSV---- */
+ ARG_RR;
+ OP_CMP8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ mycycles += 6;
+ break;
+case 0x41: /* ADD Rr,Rs - 6 cycles - Flags affected: CZSV0H-- */
+ ARG_RR;
+ OP_ADD8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x42: /* SUB Rr,Rs - 6 cycles - Flags affected: CZSV1H-- */
+ ARG_RR;
+ OP_SUB8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x43: /* ADC Rr,Rs - 6 cycles - Flags affected: CZSV0H-- */
+ ARG_RR;
+ OP_ADC8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x44: /* SBC Rr,Rs - 6 cycles - Flags affected: CZSV1H-- */
+ ARG_RR;
+ OP_SBC8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x45: /* AND Rr,Rs - 6 cycles - Flags affected: -ZS0---- */
+ ARG_RR;
+ OP_AND8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x46: /* OR Rr,Rs - 6 cycles - Flags affected: -ZS0---- */
+ ARG_RR;
+ OP_OR8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x47: /* XOR Rr,Rs - 6 cycles - Flags affected: -ZS0---- */
+ ARG_RR;
+ OP_XOR8( sm85cpu_mem_readbyte( r1 ), sm85cpu_mem_readbyte( r2 ) );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x48: /* MOV Rr,Rs - 6 cycles - Flags affected: -------- */
+ ARG_RR;
+ sm85cpu_mem_writebyte( r1, sm85cpu_mem_readbyte( r2 ) );
+ mycycles += 6;
+ break;
+case 0x49: /* CALL ad16 - 12,10 - Flags affected: -------- */
+ ARG_ad16;
+ PUSH8( regs.PC & 0xFF );
+ PUSH8( regs.PC >> 8 );
+ regs.PC = s2;
+ mycycles += ( ( regs.SYS & 0x40 ) ? 12 : 10 );
+ break;
+case 0x4A: /* MOVW RRr,RRs - 8 cycles - Flags affected: -------- */
+ ARG_RR;
+ sm85cpu_mem_writeword( r1, sm85cpu_mem_readword( r2 ) );
+ mycycles += 8;
+ break;
+case 0x4B: /* MOVW RRr,ww - 9 cycles - Flags affected: -------- */
+ ARG_Sw;
+ sm85cpu_mem_writeword( r1, s2 );
+ mycycles += 9;
+ break;
+case 0x4C: /* MULT Rrr,Rs - 24 cycles - Flags affected: -Z-0---- */
+ ARG_RR;
+ res = sm85cpu_mem_readword( r1 ) * sm85cpu_mem_readbyte( r2 );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ regs.PS1 = regs.PS1 & ~ ( FLAG_Z | FLAG_V );
+ regs.PS1 |= ( ( res & 0xFFFF ) == 0x00 ? FLAG_Z : 0 );
+ mycycles += 24;
+ break;
+case 0x4D: /* MULT RRr,i - 24 cycles - Flags affected: -Z-0---- */
+ ARG_iR;
+ res = sm85cpu_mem_readbyte( r1 + 1 ) * r2;
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ regs.PS1 = regs.PS1 & ~ ( FLAG_Z | FLAG_V );
+ regs.PS1 |= ( ( res & 0xFFFF ) == 0x00 ? FLAG_Z : 0 );
+ mycycles += 24;
+ break;
+case 0x4E: /* BMOV Rr,#b,BF/BF,Rr,#b - 6 cycles - Flags affected: --------/-Z-0--B- */
+ r2 = sm85cpu_mem_readbyte( regs.PC++ );
+ r1 = sm85cpu_mem_readbyte( regs.PC++ );
+ switch( r2 & 0xC0 ) {
+ case 0x00:
+ res = sm85cpu_mem_readbyte( r1 );
+ if ( regs.PS1 & FLAG_B ) {
+ res = res | ( 1 << ( r2 & 0x07 ) );
+ } else {
+ res = res & ~( 1 << ( r2 & 0x07 ) );
+ }
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ break;
+ case 0x40:
+ regs.PS1 = regs.PS1 & ( FLAG_C | FLAG_S | FLAG_D | FLAG_H | FLAG_I );
+ if ( sm85cpu_mem_readbyte( r1 ) & ( 1 << ( r2 & 0x07 ) ) ) {
+ regs.PS1 = regs.PS1 | FLAG_B;
+ } else {
+ regs.PS1 = regs.PS1 | FLAG_Z;
+ }
+ break;
+ case 0x80:
+ case 0xC0:
+ break;
+ }
+ mycycles += 6;
+ break;
+case 0x4F: /* BCMP/BAND/BOR/BXOR BF,Rr,#b - 6 cycles - Flags affected: -Z-0---- / -Z-0--B- */
+ r2 = sm85cpu_mem_readbyte( regs.PC++ );
+ r1 = sm85cpu_mem_readbyte( regs.PC++ );
+ s1 = sm85cpu_mem_readbyte( r1 ) & ( 1 << ( r2 & 0x07 ) );
+ s2 = ( ( regs.PS1 & FLAG_B ) >> 1 ) << ( r2 & 0x07 );
+ switch( r2 & 0xC0 ) {
+ case 0x00:
+ regs.PS1 = regs.PS1 & ~ ( FLAG_Z | FLAG_V );
+ if ( s1 == s2 ) {
+ regs.PS1 = regs.PS1 | FLAG_Z;
+ }
+ break;
+ case 0x40:
+ regs.PS1 = regs.PS1 & ~ ( FLAG_Z | FLAG_V | FLAG_B );
+ regs.PS1 = regs.PS1 | ( ( s1 & s2 ) ? FLAG_B : FLAG_Z );
+ break;
+ case 0x80:
+ regs.PS1 = regs.PS1 & ~ ( FLAG_Z | FLAG_V | FLAG_B );
+ regs.PS1 = regs.PS1 | ( ( s1 | s2 ) ? FLAG_B : FLAG_Z );
+ break;
+ case 0xC0:
+ regs.PS1 = regs.PS1 & ~ ( FLAG_Z | FLAG_V | FLAG_B );
+ regs.PS1 = regs.PS1 | ( ( s1 ^ s2 ) ? FLAG_B : FLAG_Z );
+ break;
+ }
+ mycycles += 6;
+ break;
+case 0x50: /* CMP Rr,i - 6 cycles - Flags affected: CZSV---- */
+ ARG_iR;
+ OP_CMP8( sm85cpu_mem_readbyte( r1 ), r2 );
+ mycycles += 6;
+ break;
+case 0x51: /* ADD Rr,i - 6 cycles - Flags affected: CZSV0H-- */
+ ARG_iR;
+ OP_ADD8( sm85cpu_mem_readbyte( r1 ), r2 );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x52: /* SUB Rr,i - 6 cycles - Flags affected: CZSV1H-- */
+ ARG_iR;
+ OP_SUB8( sm85cpu_mem_readbyte( r1 ), r2 );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x53: /* ADC Rr,i - 6 cycles - Flags affected: CZSV0H-- */
+ ARG_iR;
+ OP_ADC8( sm85cpu_mem_readbyte( r1 ), r2 );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x54: /* SBC Rr,i - 6 cycles - Flags affected: CZSV1H-- */
+ ARG_iR;
+ OP_SBC8( sm85cpu_mem_readbyte( r1 ), r2 );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x55: /* AND Rr,i - 6 cycles - Flags affected: -ZS0---- */
+ ARG_iR;
+ OP_AND8( sm85cpu_mem_readbyte( r1 ), r2 );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x56: /* OR Rr,i - 6 cycles - Flags affected: -ZS0---- */
+ ARG_iR;
+ OP_OR8( sm85cpu_mem_readbyte( r1 ), r2 );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x57: /* XOR Rr,i - 6 cycles - Flags affected: -ZS0---- */
+ ARG_iR;
+ OP_XOR8( sm85cpu_mem_readbyte( r1 ), r2 );
+ sm85cpu_mem_writebyte( r1, res & 0xFF );
+ mycycles += 6;
+ break;
+case 0x58: /* MOV Rr,i - 6 cycles - Flags affected: -------- */
+ ARG_iR;
+ sm85cpu_mem_writebyte( r1, r2 );
+ mycycles += 6;
+ break;
+case 0x59: /* Invalid - 2? cycles - Flags affected: --------? */
+ logerror( "%04X: 59h: Invalid instruction\n", regs.PC-1 );
+ mycycles += 2;
+ break;
+case 0x5A: /* unk5A - 7,8,12,9,8 cycles */
+logerror( "%04X: unk%02x\n", regs.PC-1,op );
+ ARG_ad16;
+ mycycles += 7;
+ break;
+case 0x5B: /* unk5B - 6,7,11,8,7 cycles */
+logerror( "%04X: unk%02x\n", regs.PC-1,op );
+ ARG_ad16;
+ mycycles += 6;
+ break;
+case 0x5C: /* DIV RRr,RRs - 47 cycles - Flags affected: -Z-V---- */
+ /* lower 8 bits of RRs is used to divide */
+ /* remainder in stored upper 8 bits of RRs */
+logerror( "%04X: DIV RRr,Rs!\n", regs.PC-1 );
+ ARG_RR;
+ regs.PS1 = regs.PS1 & ~ ( FLAG_Z | FLAG_V );
+ s1 = sm85cpu_mem_readbyte( r2 + 1 );
+ if ( s1 ) {
+ UINT16 div = sm85cpu_mem_readword( r1 );
+ res = div / s1;
+ sm85cpu_mem_writebyte( r2, div % s1 );
+ sm85cpu_mem_writeword( r1, res );
+ regs.PS1 = regs.PS1 | ( ( res == 0 ) ? FLAG_Z : 0 );
+ } else {
+ regs.PS1 = regs.PS1 | FLAG_V;
+ }
+ mycycles += 47;
+ break;
+case 0x5D: /* DIV RRr,i - 44 cycles - Flags affected: -Z-V---- */
+logerror( "%04X: DIV RRr,i!\n", regs.PC-1 );
+ ARG_iR;
+ regs.PS1 = regs.PS1 & ~ ( FLAG_Z | FLAG_V );
+ if ( r2 ) {
+ res = sm85cpu_mem_readword( r1 ) / r2;
+ sm85cpu_mem_writeword( r1, res );
+ regs.PS1 = regs.PS1 | ( ( res == 0 ) ? FLAG_Z : 0 );
+ } else {
+ regs.PS1 = regs.PS1 | FLAG_V;
+ }
+ mycycles += 44;
+ break;
+case 0x5E: /* MOVM Rr,i,Rs - 9 cycles - Flags affected: -------- */
+ ARG_RiR;
+ sm85cpu_mem_writebyte( r1, ( sm85cpu_mem_readbyte( r1 ) & d1 ) | sm85cpu_mem_readbyte( r2 ) );
+ mycycles += 9;
+ break;
+case 0x5F: /* MOVM Rr,i,j - 8 cycles - Flags affected: -------- */
+ ARG_Rii;
+ sm85cpu_mem_writebyte( r1, ( sm85cpu_mem_readbyte( r1 ) & d1 ) | r2 );
+ mycycles += 8;
+ break;
+case 0x60: /* CMPW RRr,RRs - 9 cycles - Flags affected: CZSV---- */
+ ARG_RR;
+ OP_CMP16( sm85cpu_mem_readword( r1 ), sm85cpu_mem_readword( r2 ) );
+ mycycles += 9;
+ break;
+case 0x61: /* ADDW RRr,RRs - 10 cycles - Flags affected: CZSV0H-- */
+ ARG_RR;
+ OP_ADD16( sm85cpu_mem_readword( r1 ), sm85cpu_mem_readword( r2 ) );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 10;
+ break;
+case 0x62: /* SUBW RRr,RRs - 10 cycles - Flags affected: CZSV1H-- */
+ ARG_RR;
+ OP_SUB16( sm85cpu_mem_readword( r1 ), sm85cpu_mem_readword( r2 ) );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 10;
+ break;
+case 0x63: /* ADCW RRr,RRs - 10 cycles - Flags affected: CZSV0H-- */
+ ARG_RR;
+ OP_ADC16( sm85cpu_mem_readword( r1 ), sm85cpu_mem_readword( r2 ) );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 10;
+ break;
+case 0x64: /* SBCW RRr,RRs - 10 cycles - Flags affected: CZSV1H-- */
+ ARG_RR;
+ OP_SBC16( sm85cpu_mem_readword( r1 ), sm85cpu_mem_readword( r2 ) );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 10;
+ break;
+case 0x65: /* ANDW RRr,RRs - 14 cycles - Flags affected: -Z-0---- */
+ ARG_RR;
+ OP_AND16( sm85cpu_mem_readword( r1 ), sm85cpu_mem_readword( r2 ) );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 14;
+ break;
+case 0x66: /* ORW RRr,RRs - 14 cycles - Flags affected: -Z-0---- */
+ ARG_RR;
+ OP_OR16( sm85cpu_mem_readword( r1 ), sm85cpu_mem_readword( r2 ) );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 14;
+ break;
+case 0x67: /* XORW RRr,RRs - 14 cycles - Flags affected: -Z-0---- */
+ ARG_RR;
+ OP_XOR16( sm85cpu_mem_readword( r1 ), sm85cpu_mem_readword( r2 ) );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 14;
+ break;
+case 0x68: /* CMPW RRr,w - 9 cycles - Flags affected: CZSV---- */
+ ARG_Sw;
+ OP_CMP16( sm85cpu_mem_readword( r1 ), s2 );
+ mycycles += 9;
+ break;
+case 0x69: /* ADDW RRr,w - 10 cycles - Flags affected: CZSV0H-- */
+ ARG_Sw;
+ OP_ADD16( sm85cpu_mem_readword( r1 ), s2 );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 10;
+ break;
+case 0x6A: /* SUBW RRr,w - 10 cycles - Flags affected: CZSV1H-- */
+ ARG_Sw;
+ OP_SUB16( sm85cpu_mem_readword( r1 ), s2 );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 10;
+ break;
+case 0x6B: /* ADCW RRr,w - 10 cycles - Flags affected: CZSV0H-- */
+ ARG_Sw;
+ OP_ADC16( sm85cpu_mem_readword( r1 ), s2 );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 10;
+ break;
+case 0x6C: /* SBCW RRr,w - 10 cycles - Flags affected: CZSV1H-- */
+ ARG_Sw;
+ OP_SBC16( sm85cpu_mem_readword( r1 ), s2 );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 10;
+ break;
+case 0x6D: /* ANDW RRr,w - 13 cycles - Flags affected: -Z-0---- */
+ ARG_Sw;
+ OP_AND16( sm85cpu_mem_readword( r1 ), s2 );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 13;
+ break;
+case 0x6E: /* ORW RRr,w - 13 cycles - Flags affected: -Z-0---- */
+ ARG_Sw;
+ OP_OR16( sm85cpu_mem_readword( r1 ), s2 );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF );
+ mycycles += 13;
+ break;
+case 0x6F: /* XORW RRr,w - 13 cycles - Flags affected: -Z-0---- */
+ ARG_Sw;
+ OP_XOR16( sm85cpu_mem_readword( r1 ), s2 );
+ sm85cpu_mem_writeword( r1, res & 0xFFFF);
+ mycycles += 13;
+ break;
+case 0x70: /* DBNZ r,rel8 - 10,6 cycles - Flags affected: -------- */
+case 0x71:
+case 0x72:
+case 0x73:
+case 0x74:
+case 0x75:
+case 0x76:
+case 0x77:
+ ARG_d8;
+ r1 = sm85cpu_mem_readbyte( op & 0x07 );
+ r1--;
+ sm85cpu_mem_writebyte( op & 0x07, r1 );
+ if ( r1 != 0 ) {
+ regs.PC = s2;
+ mycycles += 10;
+ } else {
+ mycycles += 6;
+ }
+ break;
+case 0x78: /* MOVW RRx,w - 6 cycles - Flags affected: -------- */
+case 0x79:
+case 0x7A:
+case 0x7B:
+case 0x7C:
+case 0x7D:
+case 0x7E:
+case 0x7F:
+ ARG_rrw;
+ sm85cpu_mem_writeword( r1, s2 );
+ mycycles += 6;
+ break;
+case 0x80: /* BBC R,#b,d8 - 10,6 cycles - Flags affected: -------- */
+case 0x81:
+case 0x82:
+case 0x83:
+case 0x84:
+case 0x85:
+case 0x86:
+case 0x87:
+ ARG_Rbr;
+ if ( ( sm85cpu_mem_readbyte( r1 ) & ( 1 << (op & 0x07) ) ) == 0 ) {
+ regs.PC = s2;
+ mycycles += 10;
+ } else {
+ mycycles += 6;
+ }
+ break;
+case 0x88: /* BBS R,#b,d8 - 10,6 cycles - Flags affected: -------- */
+case 0x89:
+case 0x8A:
+case 0x8B:
+case 0x8C:
+case 0x8D:
+case 0x8E:
+case 0x8F:
+ ARG_Rbr;
+ if ( ( sm85cpu_mem_readbyte( r1 ) & ( 1 << (op & 0x07) ) ) ) {
+ regs.PC = s2;
+ mycycles += 10;
+ } else {
+ mycycles += 6;
+ }
+ break;
+case 0x90: /* JMP cc,ad16 - 6 cycles - Flags affected: -------- */
+case 0x91:
+case 0x92:
+case 0x93:
+case 0x94:
+case 0x95:
+case 0x96:
+case 0x97:
+case 0x98:
+case 0x99:
+case 0x9A:
+case 0x9B:
+case 0x9C:
+case 0x9D:
+case 0x9E:
+case 0x9F:
+ ARG_ad16;
+ CHECK_CC;
+ if ( res ) {
+ regs.PC = s2;
+ }
+ mycycles += 6;
+ break;
+case 0xA0: /* BCLR R,#b - 4 cycles - Flags affected: -------- */
+case 0xA1:
+case 0xA2:
+case 0xA3:
+case 0xA4:
+case 0xA5:
+case 0xA6:
+case 0xA7:
+ ARG_R;
+ sm85cpu_mem_writebyte( r1, sm85cpu_mem_readbyte( r1 ) & ~ ( 1 << (op & 0x07) ) );
+ mycycles += 4;
+ break;
+case 0xA8: /* BSET R,#b - 4 cycles - Flags affected: -------- */
+case 0xA9:
+case 0xAA:
+case 0xAB:
+case 0xAC:
+case 0xAD:
+case 0xAE:
+case 0xAF:
+ ARG_R;
+ sm85cpu_mem_writebyte( r1, sm85cpu_mem_readbyte( r1 ) | ( 1 << (op & 0x07) ) );
+ mycycles += 4;
+ break;
+case 0xB0: /* MOV Rx,Rr - 4 cycles - Flags affected: -------- */
+case 0xB1:
+case 0xB2:
+case 0xB3:
+case 0xB4:
+case 0xB5:
+case 0xB6:
+case 0xB7:
+ ARG_rR;
+ sm85cpu_mem_writebyte( r1, sm85cpu_mem_readbyte( r2 ) );
+ mycycles += 4;
+ break;
+case 0xB8: /* MOV Rr,Rx - 4 cycles - Flags affected: -------- */
+case 0xB9:
+case 0xBA:
+case 0xBB:
+case 0xBC:
+case 0xBD:
+case 0xBE:
+case 0xBF:
+ ARG_rR;
+ sm85cpu_mem_writebyte( r2, sm85cpu_mem_readbyte( r1 ) );
+ mycycles += 4;
+ break;
+case 0xC0: /* MOV Rx,i - 4 cycles - Flags affected: -------- */
+case 0xC1:
+case 0xC2:
+case 0xC3:
+case 0xC4:
+case 0xC5:
+case 0xC6:
+case 0xC7:
+ ARG_ri;
+ sm85cpu_mem_writebyte( r1, r2 );
+ mycycles += 4;
+ break;
+case 0xC8: /* MOV IE0/IE1/IR0/IR1/P0/P1/P2/P3,i - 4 cycles - Flags affected: -------- */
+case 0xC9:
+case 0xCA:
+case 0xCB:
+case 0xCC:
+case 0xCD:
+case 0xCE:
+case 0xCF:
+ ARG_pi;
+ sm85cpu_mem_writebyte( r1, r2 );
+ mycycles += 4;
+ break;
+case 0xD0: /* BR cc,rel8 - 8,4 cycles - Flags affected: -------- */
+case 0xD1:
+case 0xD2:
+case 0xD3:
+case 0xD4:
+case 0xD5:
+case 0xD6:
+case 0xD7:
+case 0xD8:
+case 0xD9:
+case 0xDA:
+case 0xDB:
+case 0xDC:
+case 0xDD:
+case 0xDE:
+case 0xDF:
+ ARG_d8;
+ CHECK_CC;
+ if ( res ) {
+ regs.PC = s2;
+ mycycles += 8;
+ } else {
+ mycycles += 4;
+ }
+ break;
+case 0xE0: /* CALS - 12,9 cycles */
+case 0xE1:
+case 0xE2:
+case 0xE3:
+case 0xE4:
+case 0xE5:
+case 0xE6:
+case 0xE7:
+case 0xE8:
+case 0xE9:
+case 0xEA:
+case 0xEB:
+case 0xEC:
+case 0xED:
+case 0xEE:
+case 0xEF: /* CALS 1xWW - 12,9 cycles - Flags affected: -------- */
+ ARG_R;
+ s2 = 0x1000 + ( ( op & 0x0F ) << 8 ) + r1;
+ PUSH8( regs.PC & 0xFF );
+ PUSH8( regs.PC >> 8 );
+ regs.PC = s2;
+ mycycles += ( ( regs.SYS & 0x40 ) ? 12 : 9 );
+ break;
+case 0xF0: /* STOP - 2 cycles - Flags affected: -------- */
+ mycycles += 2;
+ if ( regs.clock_changed ) {
+ /* TODO: Set system clock divider */
+ /* TODO: Add a bunch of additional cycles */
+ regs.clock_changed = 0;
+ }
+ break;
+case 0xF1: /* HALT - 2 cycles - Flags affected: -------- */
+ regs.halted = 1;
+ mycycles += 2;
+ break;
+case 0xF2: /* Invalid - 2? cycles - Flags affected: --------? */
+case 0xF3:
+case 0xF4:
+case 0xF5:
+case 0xF6:
+case 0xF7:
+ mycycles += 2;
+ break;
+case 0xF8: /* RET - 10,8 cycles - Flags affected: -------- */
+ POP8( r1 );
+ POP8( r2 );
+ regs.PC = ( r1 << 8 ) | r2;
+ mycycles += ( ( regs.SYS & 0x40 ) ? 10 : 8 );
+ break;
+case 0xF9: /* IRET - 12,10 cycles - Flags affected: CZSVDHBI */
+ POP8( regs.PS1 );
+ POP8( r1 );
+ POP8( r2 );
+ regs.PC = ( r1 << 8 ) | r2;
+ mycycles += ( ( regs.SYS & 0x40 ) ? 12 : 10 );
+ break;
+case 0xFA: /* CLRC - 2 cycles - Flags affected: C------- */
+ regs.PS1 = regs.PS1 & ~ ( FLAG_C );
+ mycycles += 2;
+ break;
+case 0xFB: /* COMC - 2 cycles - Flags affected: C------- */
+ regs.PS1 = regs.PS1 ^ FLAG_C;
+ mycycles += 2;
+ break;
+case 0xFC: /* SETC - 2 cycles - Flags affected: C------- */
+ regs.PS1 = regs.PS1 | FLAG_C;
+ mycycles += 2;
+ break;
+case 0xFD: /* EI - 2 cycles - Flags affected: -------I */
+ regs.PS1 = regs.PS1 | FLAG_I;
+ mycycles += 2;
+ break;
+case 0xFE: /* DI - 2 cycles - Flags affected: -------I */
+ regs.PS1 = regs.PS1 & ~ ( FLAG_I );
+ mycycles += 2;
+ break;
+case 0xFF: /* NOP - 2 cycles - Flags affected: -------- */
+ mycycles += 2;
+ break;
+default:
+ mycycles += 2;
+ break;
+
diff --git a/src/emu/cpu/spc700/spc700.c b/src/emu/cpu/spc700/spc700.c
new file mode 100644
index 00000000000..8e9c1aca272
--- /dev/null
+++ b/src/emu/cpu/spc700/spc700.c
@@ -0,0 +1,1828 @@
+/* ======================================================================== */
+/* =============================== COPYRIGHT ============================== */
+/* ======================================================================== */
+/*
+
+ Sony/Nintendo SPC700 CPU Emulator
+
+ The SPC700 is 6502-based at heart but contains a lot of the extended
+ opcodes of the Mitsubishi 770 and 7700 series 65xxx-based MCUs, plus
+ a few special twists borrowed from the 68000.
+
+ It was designed by Sony's Ken Kutaragi, later the "father of the PlayStation".
+
+ Original emulation by Anthony Kruize and Lee Hammerton.
+ Substantially revised by R. Belmont.
+
+ Thanks to Anonymous, TRAC, Brad Martin, anomie, Blargg, and everyone
+ else on ZSNES Technical for probing the darker corners of the SNES
+ with test programs so we have a chance at getting things accurate.
+
+ MESS Bugzilla bugs:
+ - 804 ADC sets carry too late (FIXED)
+ - 805 ADDW/SUBW set V wrongly (FIXED)
+ - 806 BRK should modify PSW (FIXED)
+ - 807 DAA/DAS problem (FIXED)
+
+
+*/
+/* ======================================================================== */
+/* ================================= NOTES ================================ */
+/* ======================================================================== */
+/*
+
+snes mapped ports: f0-ff
+Address Function Register R/W When Reset Remarks
+
+00F0H (test) --- ------ Installed in sound-CPU
+00F1H Control W Control = "00-000"
+00F2H Register Add. R/W Indeterminate Installed in DSP
+00F3H Register Data R/W Indeterminate Installed in DSP
+00F4H Port-0 R/W Port0r = "00" Installed in sound-CPU
+ Port0w = "00"
+00F5H Port-1 R/W Port1r = "00" Installed in sound-CPU
+ Port1w = "00"
+00F6H Port-2 R/W Port2r = "00" Installed in sound-CPU
+ Port2w = "00"
+00F7H Port-3 R/W Port3r = "00" Installed in sound-CPU
+ Port3w = "00"
+00F8H ------ --- ---------- -------------------
+00F9H ------ --- ---------- -------------------
+00FAH Timer-0 W Indeterminate Installed in sound-CPU
+00FBH Timer-1 W Indeterminate Installed in sound-CPU
+00FCH Timer-2 W Indeterminate Installed in sound-CPU
+00FDH Counter-0 W Indeterminate Installed in sound-CPU
+00FEH Counter-1 W Indeterminate Installed in sound-CPU
+00FFH Counter-2 W Indeterminate Installed in sound-CPU
+
+*/
+/* ======================================================================== */
+/* ================================ INCLUDES ============================== */
+/* ======================================================================== */
+
+#include <limits.h>
+#include "spc700.h"
+#include "debugger.h"
+
+/* ======================================================================== */
+/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */
+/* ======================================================================== */
+
+/* Fallback on static if we don't have inline */
+#ifndef INLINE
+#define INLINE static
+#endif
+
+/* This should be set to the default size of your processor (min 16 bit) */
+#undef uint
+#define uint unsigned int
+
+#undef uint8
+#define uint8 unsigned char
+
+#undef int8
+
+/* Allow for architectures that don't have 8-bit sizes */
+#if UCHAR_MAX == 0xff
+#define int8 char
+#define MAKE_INT_8(A) (int8)((A)&0xff)
+#else
+#define int8 int
+INLINE int MAKE_INT_8(int A) {return (A & 0x80) ? A | ~0xff : A & 0xff;}
+#endif /* UCHAR_MAX == 0xff */
+
+#define MAKE_UINT_8(A) ((A)&0xff)
+#define MAKE_UINT_16(A) ((A)&0xffff)
+
+
+
+/* ======================================================================== */
+/* =============================== PROTOTYPES ============================= */
+/* ======================================================================== */
+
+/* CPU Structure */
+typedef struct
+{
+ uint a; /* Accumulator */
+ uint x; /* Index Register X */
+ uint y; /* Index Register Y */
+ uint s; /* Stack Pointer */
+ uint pc; /* Program Counter */
+ uint ppc; /* Previous Program Counter */
+ uint flag_n; /* Negative Flag */
+ uint flag_z; /* Zero flag */
+ uint flag_v; /* Overflow Flag */
+ uint flag_p; /* Direct Page Flag */
+ uint flag_b; /* BRK Instruction Flag */
+ uint flag_h; /* Half-carry Flag */
+ uint flag_i; /* Interrupt Mask Flag */
+ uint flag_c; /* Carry Flag */
+ uint line_irq; /* Status of the IRQ line */
+ uint line_nmi; /* Status of the NMI line */
+ uint line_rst; /* Status of the RESET line */
+ uint ir; /* Instruction Register */
+ int (*int_ack)(int); /* Interrupt Acknowledge */
+ uint stopped; /* stopped status */
+} spc700i_cpu_struct;
+
+
+
+/* ======================================================================== */
+/* ================================= DATA ================================= */
+/* ======================================================================== */
+
+/* Our CPU structure */
+static spc700i_cpu_struct spc700i_cpu = {0};
+
+int spc700_ICount = 0;
+
+/* Temporary Variables */
+static uint spc700i_source;
+static uint spc700i_destination;
+static uint spc700i_temp1, spc700i_temp2, spc700i_temp3;
+static short spc_int16;
+static int spc_int32;
+
+/* ======================================================================== */
+/* ============================ GENERAL DEFINES =========================== */
+/* ======================================================================== */
+
+/* Bits */
+#define BIT_0 0x01
+#define BIT_1 0x02
+#define BIT_2 0x04
+#define BIT_3 0x08
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+#define BIT_8 0x100
+
+/* Flag positions in Processor Status Register */
+#define FLAGPOS_N BIT_7 /* Negative */
+#define FLAGPOS_V BIT_6 /* Overflow */
+#define FLAGPOS_P BIT_5 /* Direct Page Selector */
+#define FLAGPOS_B BIT_4 /* Break */
+#define FLAGPOS_H BIT_3 /* Half-carry */
+#define FLAGPOS_I BIT_2 /* Interrupt */
+#define FLAGPOS_Z BIT_1 /* Zero */
+#define FLAGPOS_C BIT_0 /* Carry */
+
+#define NFLAG_SET FLAGPOS_N
+#define VFLAG_SET BIT_7
+#define PFLAG_SET BIT_8
+#define BFLAG_SET FLAGPOS_B
+#define HFLAG_SET BIT_3
+#define IFLAG_SET FLAGPOS_I
+#define ZFLAG_SET 0
+#define CFLAG_SET BIT_8
+#define NZFLAG_CLEAR 1
+#define VFLAG_CLEAR 0
+#define PFLAG_CLEAR 0
+#define BFLAG_CLEAR 0
+#define HFLAG_CLEAR 0
+#define IFLAG_CLEAR 0
+#define CFLAG_CLEAR 0
+
+#define NMI_SET 1
+#define NMI_CLEAR 0
+#define IRQ_SET IFLAG_CLEAR
+#define IRQ_CLEAR IFLAG_SET
+
+#define STACK_PAGE 0x100 /* Stack Page Offset */
+
+#define VECTOR_RST 0xfffe /* Reset */
+#define VECTOR_BRK 0xffde /* Break Instruction */
+#define VECTOR_IRQ 0xfffc /* IRQ ??? what is real vector? */
+#define VECTOR_NMI 0xfffa /* NMI ??? what is real vector? */
+
+#define REG_A spc700i_cpu.a /* Accumulator */
+#define REG_X spc700i_cpu.x /* Index X Register */
+#define REG_Y spc700i_cpu.y /* Index Y Register */
+#define REG_S spc700i_cpu.s /* Stack Pointer */
+#define REG_PC spc700i_cpu.pc /* Program Counter */
+#define REG_PPC spc700i_cpu.ppc /* Previous Program Counter */
+#define REG_P spc700i_cpu.p /* Processor Status Register */
+#define FLAG_NZ spc700i_cpu.flag_n = spc700i_cpu.flag_z /* Negative Flag and inverted Zero flag */
+#define FLAG_N spc700i_cpu.flag_n /* Negative flag */
+#define FLAG_Z spc700i_cpu.flag_z /* Inverted Zero flag */
+#define FLAG_V spc700i_cpu.flag_v /* Overflow Flag */
+#define FLAG_P spc700i_cpu.flag_p /* Direct Page Flag */
+#define FLAG_B spc700i_cpu.flag_b /* BRK Instruction Flag */
+#define FLAG_H spc700i_cpu.flag_h /* Decimal Mode Flag */
+#define FLAG_I spc700i_cpu.flag_i /* Interrupt Mask Flag */
+#define FLAG_C spc700i_cpu.flag_c /* Carry Flag */
+#define LINE_IRQ spc700i_cpu.line_irq /* Status of the IRQ line */
+#define LINE_NMI spc700i_cpu.line_nmi /* Status of the NMI line */
+#define REG_IR spc700i_cpu.ir /* Instruction Register */
+#define INT_ACK spc700i_cpu.int_ack /* Interrupt Acknowledge function pointer */
+#define CLOCKS spc700_ICount /* Clock cycles remaining */
+#define CPU_STOPPED spc700i_cpu.stopped /* Stopped status */
+
+#define SRC spc700i_source /* Source Operand */
+#define DST spc700i_destination /* Destination Operand */
+#define TMP1 spc700i_temp1 /* temporary result 1 */
+#define TMP2 spc700i_temp2 /* temporary result 2 */
+#define TMP3 spc700i_temp3 /* temporary result 3 */
+
+#define STOP_LEVEL_STOP 1
+#define STOP_LEVEL_SLEEP 2
+
+
+/* ======================================================================== */
+/* ============================ GENERAL MACROS ============================ */
+/* ======================================================================== */
+
+/* Codition code tests */
+#define COND_CC() (!(FLAG_C&0x100)) /* Carry Clear */
+#define COND_CS() (FLAG_C&0x100) /* Carry Set */
+#define COND_EQ() (!FLAG_Z) /* Equal */
+#define COND_NE() (FLAG_Z) /* Not Equal */
+#define COND_MI() (FLAG_N&0x80) /* Minus */
+#define COND_PL() (!(FLAG_N&0x80)) /* Plus */
+#define COND_VC() (!(FLAG_V&0x80)) /* Overflow Clear */
+#define COND_VS() (FLAG_V&0x80) /* Overflow Set */
+
+/* Set Overflow flag in math operations */
+#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R))
+#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8)
+#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D))
+#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8)
+
+#define CFLAG_AS_1() ((FLAG_C>>8)&1)
+#define CFLAG_AS_NOT_1() (!(FLAG_C&CFLAG_SET))
+
+#define NZFLAG_16(A) (((A)&0x7f) | (((A)>>1)&0x40) | (((A)>>8)&0xff))
+#define CFLAG_16(A) ((A)>>8)
+
+/* ======================================================================== */
+/* ============================ UTILITY MACROS ============================ */
+/* ======================================================================== */
+
+/* Use up clock cycles */
+#define CLK(A) CLOCKS -= (A)
+#define CLK_ALL() CLOCKS = 0
+
+#define BREAKOUT break
+
+INLINE uint read_8_normal(uint address)
+{
+ address = MAKE_UINT_16(address);
+ return spc700_read_8(address);
+}
+
+INLINE uint read_8_immediate(uint address)
+{
+ address = MAKE_UINT_16(address);
+ return spc700_read_8_immediate(address);
+}
+
+INLINE uint read_8_instruction(uint address)
+{
+ address = MAKE_UINT_16(address);
+ return spc700_read_instruction(address);
+}
+
+INLINE uint read_8_direct(uint address)
+{
+ address = MAKE_UINT_8(address) | FLAG_P;
+ return spc700_read_8_direct(address);
+}
+
+INLINE void write_8_normal(uint address, uint value)
+{
+ address = MAKE_UINT_16(address);
+ value = MAKE_UINT_8(value);
+ spc700_write_8(address, value);
+}
+
+INLINE void write_8_direct(uint address, uint value)
+{
+ address = MAKE_UINT_8(address) | FLAG_P;
+ value = MAKE_UINT_8(value);
+ spc700_write_8_direct(address, value);
+}
+
+
+INLINE uint read_16_normal(uint address)
+{
+ return read_8_normal(address) | (read_8_normal(address+1)<<8);
+}
+
+INLINE uint read_16_immediate(uint address)
+{
+ return read_8_immediate(address) | (read_8_immediate(address+1)<<8);
+}
+
+INLINE uint read_16_direct(uint address)
+{
+ return read_8_direct(address) | (read_8_direct(address+1)<<8);
+}
+
+INLINE void write_16_direct(uint address, uint value)
+{
+ write_8_direct(address, value);
+ write_8_direct(address+1, value>>8);
+}
+
+/* Low level memory access macros */
+#define read_8_NORM(A) read_8_normal(A)
+#define read_8_IMM(A) read_8_immediate(A)
+#define read_8_ABS(A) read_8_normal(A)
+#define read_8_ABX(A) read_8_normal(A)
+#define read_8_ABY(A) read_8_normal(A)
+#define read_8_AXI(A) read_8_normal(A)
+#define read_8_DP(A) read_8_direct(A)
+#define read_8_DPX(A) read_8_direct(A)
+#define read_8_DPY(A) read_8_direct(A)
+#define read_8_DPI(A) read_8_normal(A)
+#define read_8_DXI(A) read_8_normal(A)
+#define read_8_DIY(A) read_8_normal(A)
+#define read_8_STK(A) read_8_normal(A)
+#define read_8_XI(A) read_8_direct(A)
+#define read_8_XII(A) read_8_direct(A)
+#define read_8_YI(A) read_8_direct(A)
+
+
+#define read_16_NORM(A) read_16_normal(A)
+#define read_16_IMM(A) read_16_immediate(A)
+#define read_16_ABS(A) read_16_absolute(A)
+#define read_16_ABX(A) read_16_normal(A)
+#define read_16_DP(A) read_16_direct(A)
+#define read_16_DPX(A) read_16_direct(A)
+#define read_16_DPY(A) read_16_direct(A)
+#define read_16_DPI(A) read_16_normal(A)
+#define read_16_VEC(A) read_16_normal(A)
+#define read_16_XI(A) read_16_direct(A)
+#define read_16_XII(A) read_16_direct(A)
+#define read_16_YI(A) read_16_direct(A)
+
+#define write_8_NORM(A, V) write_8_normal(A, V)
+#define write_8_IMM(A, V) write_8_normal(A, V)
+#define write_8_ABS(A, V) write_8_normal(A, V)
+#define write_8_ABX(A, V) write_8_normal(A, V)
+#define write_8_ABY(A, V) write_8_normal(A, V)
+#define write_8_AXI(A, V) write_8_normal(A, V)
+#define write_8_DP(A, V) write_8_direct(A, V)
+#define write_8_DPX(A, V) write_8_direct(A, V)
+#define write_8_DPY(A, V) write_8_direct(A, V)
+#define write_8_DPI(A, V) write_8_normal(A, V)
+#define write_8_DXI(A, V) write_8_normal(A, V)
+#define write_8_DIY(A, V) write_8_normal(A, V)
+#define write_8_STK(A, V) write_8_normal(A, V)
+#define write_8_XI(A, V) write_8_direct(A, V)
+#define write_8_XII(A, V) write_8_direct(A, V)
+#define write_8_YI(A, V) write_8_direct(A, V)
+
+#define write_16_NORM(A, V) write_16_normal(A, V)
+#define write_16_ABS(A, V) write_16_normal(A, V)
+#define write_16_ABX(A, V) write_16_normal(A, V)
+#define write_16_ABY(A, V) write_16_normal(A, V)
+#define write_16_AXI(A, V) write_16_normal(A, V)
+#define write_16_DP(A, V) write_16_direct(A, V)
+#define write_16_DPX(A, V) write_16_direct(A, V)
+#define write_16_DPY(A, V) write_16_direct(A, V)
+#define write_16_DPI(A, V) write_16_normal(A, V)
+#define write_16_DXI(A, V) write_16_normal(A, V)
+#define write_16_DIY(A, V) write_16_normal(A, V)
+#define write_16_STK(A, V) write_16_normal(A, V)
+#define write_16_XI(A, V) write_16_direct(A, V)
+#define write_16_XII(A, V) write_16_direct(A, V)
+#define write_16_YI(A, V) write_16_direct(A, V)
+
+
+#define OPER_8_IMM() read_8_IMM(EA_IMM())
+#define OPER_8_ABS() read_8_ABS(EA_ABS())
+#define OPER_8_ABX() read_8_ABX(EA_ABX())
+#define OPER_8_ABY() read_8_ABY(EA_ABY())
+#define OPER_8_AXI() read_8_IND(EA_IND())
+#define OPER_8_DP() read_8_DP(EA_DP())
+#define OPER_8_DPX() read_8_DPX(EA_DPX())
+#define OPER_8_DPY() read_8_DPY(EA_DPY())
+#define OPER_8_DPI() read_8_DPI(EA_DPI())
+#define OPER_8_DXI() read_8_DXI(EA_DXI())
+#define OPER_8_DIY() read_8_DIY(EA_DIY())
+#define OPER_8_XI() read_8_XI(EA_XI())
+#define OPER_8_XII() read_8_XI(EA_XII())
+#define OPER_8_YI() read_8_YI(EA_YI())
+
+#define OPER_16_IMM() read_16_IMM(EA_IMM16())
+#define OPER_16_ABS() read_16_ABS(EA_ABS())
+#define OPER_16_ABX() read_16_ABX(EA_ABX())
+#define OPER_16_ABY() read_16_ABY(EA_ABY())
+#define OPER_16_AXI() read_16_IND(EA_IND())
+#define OPER_16_DP() read_16_DP(EA_DP())
+#define OPER_16_DPX() read_16_DPX(EA_DPX())
+#define OPER_16_DPY() read_16_DPY(EA_DPY())
+#define OPER_16_DPI() read_16_DPI(EA_DXI())
+#define OPER_16_DXI() read_16_DXI(EA_DXI())
+#define OPER_16_DIY() read_16_DIY(EA_DIY())
+#define OPER_16_XI() read_16_XI(EA_XI())
+#define OPER_16_XII() read_16_XI(EA_XII())
+#define OPER_16_YI() read_16_YI(EA_YI())
+
+/* Effective Address Caluclations */
+INLINE uint EA_IMM(void) {return REG_PC++;}
+INLINE uint EA_IMM16(void) {REG_PC += 2; return REG_PC-2;}
+INLINE uint EA_ABS(void) {return OPER_16_IMM();}
+INLINE uint EA_ABX(void) {return EA_ABS() + REG_X;}
+INLINE uint EA_ABY(void) {return EA_ABS() + REG_Y;}
+INLINE uint EA_AXI(void) {return OPER_16_ABX();}
+INLINE uint EA_DP(void) {return OPER_8_IMM();}
+INLINE uint EA_DPX(void) {return (EA_DP() + REG_X)&0xff;}
+INLINE uint EA_DPY(void) {return (EA_DP() + REG_Y)&0xff;}
+INLINE uint EA_DPI(void) {return OPER_16_DP();}
+INLINE uint EA_DXI(void) {return OPER_16_DPX();}
+INLINE uint EA_DIY(void) {uint addr = OPER_16_DP(); if((addr&0xff00) != ((addr+REG_Y)&0xff00)) CLK(1); return addr + REG_Y;}
+INLINE uint EA_XI(void) {return REG_X;}
+INLINE uint EA_XII(void) {uint val = REG_X;REG_X = MAKE_UINT_8(REG_X+1);return val;}
+INLINE uint EA_YI(void) {return REG_Y;}
+
+
+
+/* Change the Program Counter */
+INLINE void JUMP(uint address)
+{
+ REG_PC = address;
+ spc700_jumping(REG_PC);
+}
+
+INLINE void BRANCH(uint offset)
+{
+ REG_PC = MAKE_UINT_16(REG_PC + MAKE_INT_8(offset));
+ spc700_branching(REG_PC);
+}
+
+
+#define GET_REG_YA() (REG_A | (REG_Y<<8))
+
+INLINE void SET_REG_YA(uint value)
+{
+ REG_A = MAKE_UINT_8(value);
+ REG_Y = MAKE_UINT_8(value>>8);
+}
+
+/* Get the Processor Status Register */
+#define GET_REG_P() \
+ ((FLAG_N & 0x80) | \
+ ((FLAG_V & 0x80) >> 1) | \
+ (FLAG_P>>3) | \
+ FLAG_B | \
+ (FLAG_H& HFLAG_SET) | \
+ FLAG_I | \
+ ((!FLAG_Z) << 1) | \
+ CFLAG_AS_1())
+
+/* Get Processor Status Register with B flag set (when executing BRK instruction) */
+#define GET_REG_P_BRK() \
+ ((FLAG_N & 0x80) | \
+ ((FLAG_V & 0x80) >> 1) | \
+ (FLAG_P>>3) | \
+ FLAGPOS_B | \
+ (FLAG_H & HFLAG_SET) | \
+ FLAG_I | \
+ ((!FLAG_Z) << 1) | \
+ CFLAG_AS_1())
+
+/* Get Processor Status Register with B flag cleared (when servicing an interrupt) */
+#define GET_REG_P_INT() \
+ ((FLAG_N & 0x80) | \
+ ((FLAG_V & 0x80) >> 1) | \
+ (FLAG_P>>3) | \
+ (FLAG_H & HFLAG_SET) | \
+ FLAG_I | \
+ ((!FLAG_Z) << 1) | \
+ CFLAG_AS_1())
+
+INLINE void SET_FLAG_I(uint value);
+
+/* Set the Process Status Register */
+INLINE void SET_REG_P(uint value)
+{
+ FLAG_N = (value & 0x80);
+ FLAG_Z = !(value & 2);
+ FLAG_V = value<<1;
+ FLAG_P = (value & FLAGPOS_P) << 3;
+ FLAG_B = value & FLAGPOS_B;
+ FLAG_H = value & HFLAG_SET;
+ FLAG_C = value << 8;
+ SET_FLAG_I(value);
+}
+
+/* Push/Pull data to/from the stack */
+INLINE void PUSH_8(uint value)
+{
+ write_8_STK(REG_S+STACK_PAGE, value);
+ REG_S = MAKE_UINT_8(REG_S - 1);
+}
+
+INLINE uint PULL_8(void)
+{
+ REG_S = MAKE_UINT_8(REG_S + 1);
+ return read_8_STK(REG_S+STACK_PAGE);
+}
+
+INLINE void PUSH_16(uint value)
+{
+ PUSH_8(value>>8);
+ PUSH_8(value);
+}
+
+INLINE uint PULL_16(void)
+{
+ uint value = PULL_8();
+ return value | (PULL_8()<<8);
+}
+
+INLINE void SERVICE_IRQ(void)
+{
+ CLK(7);
+ PUSH_16(REG_PC);
+ PUSH_8(GET_REG_P_INT());
+ FLAG_I = IFLAG_SET;
+ if(INT_ACK)
+ INT_ACK(0);
+ JUMP(read_16_VEC(VECTOR_IRQ));
+}
+
+#if !SPC700_OPTIMIZE_SNES
+INLINE void CHECK_IRQ(void)
+{
+ if(FLAG_I & LINE_IRQ)
+ SERVICE_IRQ();
+}
+#else
+#define CHECK_IRQ()
+#endif /* SPC700_OPTIMIZE_SNES */
+
+INLINE void SET_FLAG_I(uint value)
+{
+ FLAG_I = value & IFLAG_SET;
+ CHECK_IRQ();
+}
+
+/* ======================================================================== */
+/* =========================== OPERATION MACROS =========================== */
+/* ======================================================================== */
+
+#define SUBOP_ADC(A, B) \
+ spc_int16 = (A) + (B) + CFLAG_AS_1(); \
+ TMP1 = ((A) & 0x0f) + (CFLAG_AS_1()); \
+ FLAG_C = (spc_int16 > 0xff) ? CFLAG_SET : 0; \
+ FLAG_V = (~((A) ^ (B))) & (((A) ^ spc_int16) & 0x80); \
+ FLAG_H = (((spc_int16 & 0x0f) - TMP1) & 0x10) >> 1; \
+ FLAG_NZ = (UINT8)spc_int16
+
+
+/* Add With Carry */
+#define OP_ADC(BCLK, MODE) \
+ CLK(BCLK); \
+ SRC = OPER_8_##MODE(); \
+ SUBOP_ADC(SRC, REG_A); \
+ REG_A = (UINT8)spc_int16;
+
+
+/* Add With Carry to memory */
+#define OP_ADCM(BCLK, SMODE, DMODE) \
+ CLK(BCLK); \
+ SRC = OPER_8_##SMODE(); \
+ DST = EA_##DMODE(); \
+ SUBOP_ADC(SRC, read_8_##DMODE(DST)); \
+ write_8_##DMODE(DST, (UINT8)spc_int16)
+
+/* Add word */
+#define OP_ADDW(BCLK) \
+ CLK(BCLK); \
+ SRC = OPER_16_DP(); \
+ DST = GET_REG_YA(); \
+ TMP1 = ((SRC) & 0xff) + ((DST) & 0xff); \
+ TMP2 = (TMP1 > 0xff) ? 1 : 0; \
+ TMP3 = ((SRC) >> 8) + ((DST) >> 8) + TMP2; \
+ spc_int16 = ((TMP1 & 0xff) + (TMP3 << 8)) & 0xffff; \
+ FLAG_C = (TMP3 > 0xff) ? CFLAG_SET : 0; \
+ FLAG_H = ((unsigned) ((((DST) >> 8) & 0x0F) + \
+ (((SRC) >> 8) & 0x0F) + TMP2)) > 0x0F ? HFLAG_SET : 0; \
+ FLAG_V = (~((DST) ^ (SRC)) & ((SRC) ^ (UINT16) spc_int16) & 0x8000) ? VFLAG_SET : 0; \
+ FLAG_Z = (spc_int16 != 0); \
+ FLAG_N = (spc_int16>>8); \
+ SET_REG_YA(spc_int16);
+
+/* Logical AND with accumulator */
+#define OP_AND(BCLK, MODE) \
+ CLK(BCLK); \
+ FLAG_NZ = REG_A &= OPER_8_##MODE()
+
+/* Logical AND operand */
+#define OP_ANDM(BCLK, SMODE, DMODE) \
+ CLK(BCLK); \
+ FLAG_NZ = OPER_8_##SMODE(); \
+ DST = EA_##DMODE(); \
+ FLAG_NZ &= read_8_##DMODE(DST); \
+ write_8_##DMODE(DST, FLAG_NZ)
+
+/* Logical AND bit to C */
+#define OP_AND1(BCLK) \
+ CLK(BCLK); \
+ DST = EA_IMM16(); \
+ if(FLAG_C & CFLAG_SET) \
+ { \
+ DST = read_16_IMM(DST); \
+ SRC = 1 << (DST >> 13); \
+ DST &= 0x1fff; \
+ if(!(read_8_NORM(DST) & SRC)) \
+ FLAG_C = CFLAG_CLEAR; \
+ }
+
+/* AND negated bit to C */
+#define OP_ANDN1(BCLK) \
+ CLK(BCLK); \
+ DST = EA_IMM16(); \
+ if(FLAG_C & CFLAG_SET) \
+ { \
+ DST = read_16_IMM(DST); \
+ SRC = 1 << (DST >> 13); \
+ DST &= 0x1fff; \
+ if(read_8_NORM(DST) & SRC) \
+ FLAG_C = CFLAG_CLEAR; \
+ }
+
+/* Arithmetic Shift Left accumulator */
+#define OP_ASL(BCLK) \
+ CLK(BCLK); \
+ FLAG_C = REG_A << 1; \
+ FLAG_NZ = REG_A = MAKE_UINT_8(FLAG_C)
+
+/* Arithmetic Shift Left operand */
+#define OP_ASLM(BCLK, MODE) \
+ CLK(BCLK); \
+ DST = EA_##MODE(); \
+ FLAG_C = read_8_##MODE(DST) << 1; \
+ FLAG_NZ = MAKE_UINT_8(FLAG_C); \
+ write_8_##MODE(DST, FLAG_NZ)
+
+/* Branch if Bit Reset */
+#define OP_BBC(BCLK, BIT) \
+ CLK(BCLK); \
+ SRC = OPER_8_DP(); \
+ DST = OPER_8_IMM(); \
+ if(!(SRC & BIT)) \
+ { \
+ CLK(1); \
+ BRANCH(DST); \
+ }
+
+/* Branch if Bit Set */
+#define OP_BBS(BCLK, BIT) \
+ CLK(BCLK); \
+ SRC = OPER_8_DP(); \
+ DST = OPER_8_IMM(); \
+ if(SRC & BIT) \
+ { \
+ CLK(1); \
+ BRANCH(DST); \
+ }
+
+/* Branch on Condition Code */
+#define OP_BCC(BCLK, COND) \
+ CLK(BCLK); \
+ DST = OPER_8_IMM(); \
+ if(COND) \
+ { \
+ CLK(1); \
+ BRANCH(DST); \
+ }
+
+/* Branch Unconditional */
+/* speed up busy loops */
+#define OP_BRA(BCLK) \
+ CLK(BCLK); \
+ BRANCH(OPER_8_IMM()); \
+ if(REG_PC == REG_PPC) \
+ CLK_ALL()
+
+/* Cause a Break interrupt */
+#define OP_BRK(BCLK) \
+ CLK(BCLK); \
+ PUSH_16(REG_PC); \
+ PUSH_8(GET_REG_P_BRK()); \
+ FLAG_B |= FLAGPOS_B; \
+ FLAG_I = IFLAG_CLEAR; \
+ JUMP(read_16_VEC(VECTOR_BRK))
+
+/* Call subroutine */
+#define OP_CALL(BCLK) \
+ CLK(BCLK); \
+ DST = EA_ABS(); \
+ PUSH_16(REG_PC); \
+ JUMP(DST)
+
+/* Compare accumulator and branch if not equal */
+#define OP_CBNE(BCLK, MODE) \
+ CLK(BCLK); \
+ SRC = OPER_8_##MODE(); \
+ DST = EA_IMM(); \
+ if(SRC != REG_A) \
+ { \
+ CLK(1); \
+ BRANCH(read_8_IMM(DST)); \
+ }
+
+/* Clear Carry flag */
+#define OP_CLRC(BCLK) \
+ CLK(BCLK); \
+ FLAG_C = CFLAG_CLEAR
+
+/* Clear Memory Bit */
+#define OP_CLR(BCLK, BIT) \
+ CLK(BCLK); \
+ DST = EA_DP(); \
+ SRC = read_8_DP(DST) & ~BIT; \
+ write_8_DP(DST, SRC)
+
+/* Clear Overflow flag (also clears half-carry) */
+#define OP_CLRV(BCLK) \
+ CLK(BCLK); \
+ FLAG_V = VFLAG_CLEAR; \
+ FLAG_H = 0;
+
+/* Clear the Page flag */
+#define OP_CLRP(BCLK) \
+ CLK(BCLK); \
+ FLAG_P = PFLAG_CLEAR
+
+/* Compare operand to register */
+#define OP_CMPR(BCLK, REG, MODE) \
+ CLK(BCLK); \
+ SRC = OPER_8_##MODE(); \
+ spc_int16 = (short)REG - (short)SRC; \
+ FLAG_C = (spc_int16 >= 0) ? CFLAG_SET : 0; \
+ FLAG_NZ = MAKE_UINT_8(spc_int16);
+
+/* Compare memory */
+#define OP_CMPM(BCLK, SMODE, DMODE) \
+ CLK(BCLK); \
+ SRC = OPER_8_##SMODE(); \
+ spc_int16 = (short)OPER_8_##DMODE() - (short)SRC; \
+ FLAG_C = (spc_int16 >= 0) ? CFLAG_SET : 0; \
+ FLAG_NZ = MAKE_UINT_8(spc_int16);
+
+/* Compare word */
+#define OP_CMPW(BCLK, MODE) \
+ CLK(BCLK); \
+ SRC = OPER_16_##MODE(); \
+ spc_int32 = (int)GET_REG_YA() - (int)SRC; \
+ FLAG_C = (spc_int32 >= 0) ? CFLAG_SET : 0; \
+ FLAG_NZ = NZFLAG_16(spc_int32);
+
+/* Decimal adjust for addition */
+#define OP_DAA(BCLK) \
+ CLK(BCLK); \
+ SRC = REG_A; \
+ if (((SRC & 0x0f) > 9) || (FLAG_H & HFLAG_SET)) \
+ { \
+ REG_A += 6; \
+ if (REG_A < 6) \
+ { \
+ FLAG_C = CFLAG_SET; \
+ } \
+ } \
+ if ((SRC > 0x99) || (FLAG_C & CFLAG_SET)) \
+ { \
+ REG_A += 0x60; \
+ FLAG_C = CFLAG_SET; \
+ } \
+ FLAG_NZ = REG_A = MAKE_UINT_8(REG_A);
+
+/* Decimal adjust for subtraction */
+#define OP_DAS(BCLK) \
+ CLK(BCLK); \
+ SRC = REG_A; \
+ if (!(FLAG_H & HFLAG_SET) || ((SRC & 0xf) > 9)) \
+ { \
+ REG_A -= 6; \
+ } \
+ if (!(FLAG_C & CFLAG_SET) || (SRC > 0x99)) \
+ { \
+ REG_A -= 0x60; \
+ FLAG_C = 0; \
+ } \
+ FLAG_NZ = REG_A = MAKE_UINT_8(REG_A)
+
+/* Decrement register and branch if not zero */
+/* speed up busy loops */
+#define OP_DBNZR(BCLK) \
+ CLK(BCLK); \
+ REG_Y = MAKE_UINT_8(REG_Y - 1); \
+ DST = EA_IMM(); \
+ if(REG_Y != 0) \
+ { \
+ CLK(1); \
+ BRANCH(read_8_IMM(DST)); \
+ }
+
+/* Decrement operand and branch if not zero */
+/* Speed up busy loops but do reads/writes for compatibility */
+#define OP_DBNZM(BCLK) \
+ CLK(BCLK); \
+ DST = EA_DP(); \
+ SRC = MAKE_UINT_8(read_8_DP(DST) - 1); \
+ write_8_DP(DST, SRC); \
+ DST = EA_IMM(); \
+ if(SRC != 0) \
+ { \
+ CLK(1); \
+ BRANCH(read_8_IMM(DST)); \
+ }
+
+/* Decrement register */
+#define OP_DECR(BCLK, REG) \
+ CLK(BCLK); \
+ FLAG_NZ = REG = MAKE_UINT_8(REG - 1)
+
+/* Decrement operand */
+#define OP_DECM(BCLK, MODE) \
+ CLK(BCLK); \
+ DST = EA_##MODE(); \
+ FLAG_NZ = MAKE_UINT_8(read_8_##MODE(DST) - 1); \
+ write_8_##MODE(DST, FLAG_NZ)
+
+/* Decrement word */
+#define OP_DECW(BCLK) \
+ CLK(BCLK); \
+ DST = EA_DP(); \
+ FLAG_NZ = MAKE_UINT_16(read_16_DP(DST) - 1); \
+ write_16_DP(DST, FLAG_NZ); \
+ FLAG_NZ = NZFLAG_16(FLAG_NZ)
+
+/* Disable interrupts */
+#define OP_DI(BCLK) \
+ CLK(BCLK); \
+ FLAG_I = IFLAG_CLEAR
+
+/* Divide - should be almost exactly how the hardware works */
+#define OP_DIV(BCLK) \
+ CLK(BCLK); \
+ TMP1 = SRC = GET_REG_YA(); \
+ TMP2 = (REG_X << 9); \
+ FLAG_H = 0; \
+ if ((REG_Y & 0xf) >= (REG_X & 0xf)) FLAG_H = HFLAG_SET; \
+ for (TMP3 = 0; TMP3 < 9; TMP3++) \
+ { \
+ TMP1 <<= 1; \
+ if (TMP1 & 0x20000) TMP1 = (TMP1 & 0x1ffff) | 1; \
+ if (TMP1 >= TMP2) TMP1 ^= 1; \
+ if (TMP1 & 1) TMP1 = ((TMP1 - TMP2) & 0x1ffff); \
+ } \
+ FLAG_V = (TMP1 & 0x100) ? VFLAG_SET : 0; \
+ SET_REG_YA((((TMP1 >> 9) & 0xff) << 8) + (TMP1 & 0xff)); \
+ FLAG_NZ = MAKE_UINT_8(GET_REG_YA());
+
+/* Enable interrupts */
+#define OP_EI(BCLK) \
+ CLK(BCLK); \
+ FLAG_I = IFLAG_SET
+
+/* Exclusive Or operand to accumulator */
+#define OP_EOR(BCLK, MODE) \
+ CLK(BCLK); \
+ FLAG_NZ = REG_A ^= OPER_8_##MODE()
+
+/* Logical EOR operand */
+#define OP_EORM(BCLK, SMODE, DMODE) \
+ CLK(BCLK); \
+ FLAG_NZ = OPER_8_##SMODE(); \
+ DST = EA_##DMODE(); \
+ FLAG_NZ ^= read_8_##DMODE(DST); \
+ write_8_##DMODE(DST, FLAG_NZ)
+
+/* Exclusive OR bit to C */
+#define OP_EOR1(BCLK) \
+ CLK(BCLK); \
+ DST = OPER_16_IMM(); \
+ SRC = 1 << (DST >> 13); \
+ DST &= 0x1fff; \
+ if(read_8_NORM(DST) & SRC) \
+ FLAG_C = ~FLAG_C
+
+/* Increment register */
+#define OP_INCR(BCLK, REG) \
+ CLK(BCLK); \
+ FLAG_NZ = REG = MAKE_UINT_8(REG + 1)
+
+/* Increment operand */
+#define OP_INCM(BCLK, MODE) \
+ CLK(BCLK); \
+ DST = EA_##MODE(); \
+ FLAG_NZ = MAKE_UINT_8(read_8_##MODE(DST) + 1); \
+ write_8_##MODE(DST, FLAG_NZ)
+
+/* Increment word */
+#define OP_INCW(BCLK) \
+ CLK(BCLK); \
+ DST = EA_DP(); \
+ FLAG_NZ = MAKE_UINT_16(read_16_DP(DST) + 1); \
+ write_16_DP(DST, FLAG_NZ); \
+ FLAG_NZ = NZFLAG_16(FLAG_NZ)
+
+/* Jump */
+/* If we're in a busy loop, eat all clock cycles */
+#define OP_JMP(BCLK, MODE) \
+ CLK(BCLK); \
+ JUMP(EA_##MODE()); \
+ if(REG_PC == REG_PPC) \
+ CLK_ALL()
+
+/* Jump to Subroutine */
+#define OP_JSR(BCLK, MODE) \
+ CLK(BCLK); \
+ PUSH_16(REG_PC); \
+ JUMP(EA_##MODE())
+
+/* Logical Shift Right accumulator */
+#define OP_LSR(BCLK) \
+ CLK(BCLK); \
+ FLAG_C = REG_A << 8; \
+ FLAG_NZ = REG_A >>= 1
+
+/* Logical Shift Right operand */
+#define OP_LSRM(BCLK, MODE) \
+ CLK(BCLK); \
+ DST = EA_##MODE(); \
+ FLAG_NZ = read_8_##MODE(DST); \
+ FLAG_C = FLAG_NZ << 8; \
+ FLAG_NZ >>= 1; \
+ write_8_##MODE(DST, FLAG_NZ)
+
+/* Move from register to register */
+#define OP_MOVRR(BCLK, SREG, DREG) \
+ CLK(BCLK); \
+ FLAG_NZ = DREG = SREG
+
+/* Move from register to memory */
+#define OP_MOVRM(BCLK, SREG, DMODE) \
+ CLK(BCLK); \
+ write_8_##DMODE(EA_##DMODE(), SREG)
+
+/* Move from memory to register */
+#define OP_MOVMR(BCLK, SMODE, DREG) \
+ CLK(BCLK); \
+ FLAG_NZ = DREG = OPER_8_##SMODE()
+
+/* Move from memory to memory */
+#define OP_MOVMM(BCLK, SMODE, DMODE) \
+ CLK(BCLK); \
+ SRC = OPER_8_##SMODE(); \
+ DST = EA_##DMODE(); \
+ write_8_##DMODE(DST, SRC)
+
+/* Move word register to memory */
+#define OP_MOVWRM(BCLK) \
+ CLK(BCLK); \
+ write_16_DP(EA_DP(), GET_REG_YA())
+
+/* Move word memory to register */
+#define OP_MOVWMR(BCLK) \
+ CLK(BCLK); \
+ FLAG_NZ = OPER_16_DP(); \
+ SET_REG_YA(FLAG_NZ); \
+ FLAG_NZ = NZFLAG_16(FLAG_NZ)
+
+/* Move from Stack pointer to X */
+#define OP_MOVSX(BCLK) \
+ CLK(BCLK); \
+ FLAG_NZ = REG_X = REG_S
+
+/* Move from X to Stack pointer */
+#define OP_MOVXS(BCLK) \
+ CLK(BCLK); \
+ REG_S = REG_X
+
+/* Move bit from memory to C */
+#define OP_MOV1C(BCLK) \
+ CLK(BCLK); \
+ DST = OPER_16_IMM(); \
+ SRC = 1 << (DST >> 13); \
+ DST &= 0x1fff; \
+ FLAG_C = ((read_8_NORM(DST) & SRC) != 0) << 8
+
+/* Move bit from C to memory */
+#define OP_MOV1M(BCLK) \
+ CLK(BCLK); \
+ DST = OPER_16_IMM(); \
+ SRC = 1 << (DST >> 13); \
+ DST &= 0x1fff; \
+ if(FLAG_C & CFLAG_SET) \
+ write_8_NORM(DST, read_8_NORM(DST) | SRC); \
+ else \
+ write_8_NORM(DST, read_8_NORM(DST) & ~SRC)
+
+
+/* Multiply A and Y and store result in YA */
+#define OP_MUL(BCLK) \
+ CLK(BCLK); \
+ SRC = REG_Y * REG_A; \
+ REG_A = MAKE_UINT_8(SRC); \
+ FLAG_NZ = REG_Y = SRC >> 8;
+
+/* No Operation */
+#define OP_NOP(BCLK) \
+ CLK(BCLK)
+
+/* Invert the C flag */
+#define OP_NOTC(BCLK) \
+ CLK(BCLK); \
+ FLAG_C = ~FLAG_C
+
+/* NOT bit */
+#define OP_NOT1(BCLK) \
+ CLK(BCLK); \
+ DST = OPER_16_IMM(); \
+ SRC = 1 << (DST >> 13); \
+ DST &= 0x1fff; \
+ write_8_NORM(DST, read_8_NORM(DST) ^ SRC)
+
+/* Logical OR operand to accumulator */
+#define OP_OR(BCLK, MODE) \
+ CLK(BCLK); \
+ FLAG_NZ = REG_A |= OPER_8_##MODE()
+
+/* Logical OR operand */
+#define OP_ORM(BCLK, SMODE, DMODE) \
+ CLK(BCLK); \
+ FLAG_NZ = OPER_8_##SMODE(); \
+ DST = EA_##DMODE(); \
+ FLAG_NZ |= read_8_##DMODE(DST); \
+ write_8_##DMODE(DST, FLAG_NZ)
+
+/* Logical OR bit to C */
+#define OP_OR1(BCLK) \
+ CLK(BCLK); \
+ DST = EA_IMM16(); \
+ if(!(FLAG_C & CFLAG_SET)) \
+ { \
+ DST = read_16_IMM(DST); \
+ SRC = 1 << (DST >> 13); \
+ DST &= 0x1fff; \
+ if(read_8_NORM(DST) & SRC) \
+ FLAG_C = CFLAG_SET; \
+ }
+
+/* OR negated bit to C */
+#define OP_ORN1(BCLK) \
+ CLK(BCLK); \
+ DST = EA_IMM16(); \
+ if(!(FLAG_C & CFLAG_SET)) \
+ { \
+ DST = read_16_IMM(DST); \
+ SRC = 1 << (DST >> 13); \
+ DST &= 0x1fff; \
+ if(!(read_8_NORM(DST) & SRC)) \
+ FLAG_C = CFLAG_SET; \
+ }
+
+/* UPage Call */
+#define OP_PCALL(BCLK) \
+ CLK(BCLK); \
+ DST = EA_DP(); \
+ PUSH_16(REG_PC); \
+ JUMP(0xff00 | DST)
+
+/* Push a register to the stack */
+#define OP_PUSH(BCLK, REG) \
+ CLK(BCLK); \
+ PUSH_8(REG)
+
+/* Push the Processor Status Register to the stack */
+#define OP_PHP(BCLK) \
+ CLK(BCLK); \
+ PUSH_8(GET_REG_P())
+
+/* Pull a register from the stack */
+#define OP_PULL(BCLK, REG) \
+ CLK(BCLK); \
+ REG = PULL_8()
+
+/* Pull the Processor Status Register from the stack */
+#define OP_PLP(BCLK) \
+ CLK(BCLK); \
+ SET_REG_P(PULL_8())
+
+/* Return from Subroutine */
+#define OP_RET(BCLK) \
+ CLK(BCLK); \
+ JUMP(PULL_16())
+
+/* Return from Interrupt */
+#define OP_RETI(BCLK) \
+ CLK(BCLK); \
+ SET_REG_P(PULL_8()); \
+ JUMP(PULL_16())
+
+/* Rotate Left the accumulator */
+#define OP_ROL(BCLK) \
+ CLK(BCLK); \
+ FLAG_C = (REG_A<<1) | CFLAG_AS_1(); \
+ FLAG_NZ = REG_A = MAKE_UINT_8(FLAG_C)
+
+/* Rotate Left an operand */
+#define OP_ROLM(BCLK, MODE) \
+ CLK(BCLK); \
+ DST = EA_##MODE(); \
+ FLAG_C = (read_8_##MODE(DST)<<1) | CFLAG_AS_1(); \
+ FLAG_NZ = MAKE_UINT_8(FLAG_C); \
+ write_8_##MODE(DST, FLAG_NZ)
+
+/* Rotate Right the accumulator */
+#define OP_ROR(BCLK) \
+ CLK(BCLK); \
+ REG_A |= FLAG_C & 0x100; \
+ FLAG_C = REG_A << 8; \
+ FLAG_NZ = REG_A >>= 1
+
+/* Rotate Right an operand */
+#define OP_RORM(BCLK, MODE) \
+ CLK(BCLK); \
+ DST = EA_##MODE(); \
+ FLAG_NZ = read_8_##MODE(DST) | (FLAG_C & 0x100); \
+ FLAG_C = FLAG_NZ << 8; \
+ FLAG_NZ >>= 1; \
+ write_8_##MODE(DST, FLAG_NZ)
+
+/* Subtract with Carry */
+#define OP_SBC(BCLK, MODE) \
+ CLK(BCLK); \
+ SRC = OPER_8_##MODE(); \
+ TMP2 = REG_A - SRC - (CFLAG_AS_1() ^ 1); \
+ SUBOP_ADC(REG_A, ~SRC); \
+ FLAG_C = (TMP2 <= 0xff) ? CFLAG_SET : 0; \
+ REG_A = (UINT8)spc_int16;
+
+/* Subtract With Carry to memory */
+#define OP_SBCM(BCLK, SMODE, DMODE) \
+ CLK(BCLK); \
+ SRC = OPER_8_##SMODE(); \
+ DST = EA_##DMODE(); \
+ TMP3 = read_8_##DMODE(DST); \
+ TMP2 = TMP3 - SRC - (CFLAG_AS_1() ^ 1); \
+ SUBOP_ADC(~SRC, TMP3); \
+ FLAG_C = (TMP2 <= 0xff) ? CFLAG_SET : 0; \
+ write_8_##DMODE(DST, (UINT8)spc_int16)
+
+/* Set Carry flag */
+#define OP_SETC(BCLK) \
+ CLK(BCLK); \
+ FLAG_C = CFLAG_SET
+
+/* Set Page flag */
+#define OP_SETP(BCLK) \
+ CLK(BCLK); \
+ FLAG_P = PFLAG_SET
+
+/* Set Memory Bit */
+#define OP_SET(BCLK, BIT) \
+ CLK(BCLK); \
+ DST = EA_DP(); \
+ SRC = read_8_DP(DST) | BIT; \
+ write_8_DP(DST, SRC)
+
+/* Put the CPU to sleep */
+#define OP_SLEEP(BCLK) \
+ CLK(BCLK); \
+ CPU_STOPPED |= STOP_LEVEL_SLEEP; \
+ CLK_ALL()
+
+/* Stop the CPU */
+#define OP_STOP(BCLK) \
+ CLK(BCLK); \
+ CPU_STOPPED |= STOP_LEVEL_STOP; \
+ CLK_ALL()
+
+/* Subtract word */
+#define OP_SUBW(BCLK) \
+ CLK(BCLK); \
+ SRC = OPER_16_DP(); \
+ DST = GET_REG_YA(); \
+ TMP1 = ((DST) & 0xff) - ((SRC) & 0xff); \
+ TMP2 = (TMP1 > 0xff) ? 1 : 0; \
+ TMP3 = ((DST) >> 8) - ((SRC) >> 8) - TMP2; \
+ spc_int16 = ((TMP1 & 0xff) + (TMP3 << 8)) & 0xffff; \
+ FLAG_C = (TMP3 <= 0xff) ? CFLAG_SET : 0; \
+ FLAG_H = ((unsigned) ((((DST) >> 8) & 0x0F) - \
+ (((SRC) >> 8) & 0x0F) - TMP2)) > 0x0F ? 0: HFLAG_SET; \
+ FLAG_V = (((DST) ^ (SRC)) & ((DST) ^ (UINT16) spc_int16) & 0x8000) ? VFLAG_SET : 0; \
+ FLAG_Z = (spc_int16 != 0); \
+ FLAG_N = (spc_int16>>8); \
+ SET_REG_YA(spc_int16);
+
+/* Table Call */
+#define OP_TCALL(BCLK, NUM) \
+ CLK(BCLK); \
+ PUSH_16(REG_PC); \
+ JUMP(read_16_NORM(0xffc0 + ((15-NUM)<<1)))
+
+/* Test and Clear Bits */
+#define OP_TCLR1(BCLK, MODE) \
+ CLK(BCLK); \
+ DST = EA_##MODE(); \
+ FLAG_NZ = read_8_##MODE(DST); \
+ write_8_##MODE(DST, FLAG_NZ & ~REG_A); \
+ FLAG_NZ &= REG_A
+
+/* Test and Set Bits */
+#define OP_TSET1(BCLK, MODE) \
+ CLK(BCLK); \
+ DST = EA_##MODE(); \
+ FLAG_NZ = read_8_##MODE(DST); \
+ write_8_##MODE(DST, FLAG_NZ | REG_A); \
+ FLAG_NZ &= REG_A
+
+/* Exchange high and low nybbles of accumulator */
+#define OP_XCN(BCLK) \
+ CLK(BCLK); \
+ FLAG_NZ = REG_A = MAKE_UINT_8((REG_A<<4) | (REG_A>>4))
+
+#define OP_ILLEGAL(BCLK) \
+ CLK(BCLK)
+
+
+/* ======================================================================== */
+/* ================================= API ================================== */
+/* ======================================================================== */
+
+void spc700_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ INT_ACK = irqcallback;
+}
+
+
+void spc700_reset(void)
+{
+ CPU_STOPPED = 0;
+#if !SPC700_OPTIMIZE_SNES
+ LINE_IRQ = 0;
+ LINE_NMI = 0;
+#endif /* SPC700_OPTIMIZE_SNES */
+ REG_S = 0;
+ FLAG_NZ = NZFLAG_CLEAR;
+ FLAG_V = VFLAG_CLEAR;
+ FLAG_P = PFLAG_CLEAR;
+ FLAG_B = BFLAG_CLEAR;
+ FLAG_H = HFLAG_CLEAR;
+ FLAG_I = IFLAG_CLEAR;
+ FLAG_C = CFLAG_CLEAR;
+ JUMP(read_16_VEC(VECTOR_RST));
+}
+
+/* Exit and clean up */
+void spc700_exit(void)
+{
+ /* nothing to do yet */
+}
+
+
+/* Get the current CPU context */
+unsigned spc700_get_context(void *dst_context)
+{
+ if(dst_context)
+ *(spc700i_cpu_struct*)dst_context = spc700i_cpu;
+ return sizeof(spc700i_cpu);
+}
+
+static void spc700_get_context_mame(void *dst_context)
+{
+ spc700_get_context(dst_context);
+}
+
+/* Set the current CPU context */
+void spc700_set_context(void *src_context)
+{
+ if(src_context)
+ {
+ spc700i_cpu = *(spc700i_cpu_struct*)src_context;
+ JUMP(REG_PC);
+ }
+}
+
+/* Get the current Program Counter */
+unsigned spc700_get_pc(void)
+{
+ return REG_PC;
+}
+
+/* Set the Program Counter */
+void spc700_set_pc(unsigned val)
+{
+ JUMP(val);
+}
+
+/* Get the current Stack Pointer */
+unsigned spc700_get_sp(void)
+{
+ return REG_S + STACK_PAGE;
+}
+
+/* Set the Stack Pointer */
+void spc700_set_sp(unsigned val)
+{
+ REG_S = MAKE_UINT_8(val);
+}
+
+/* Assert or clear the NMI line of the CPU */
+void spc700_set_nmi_line(int state)
+{
+#if !SPC700_OPTIMIZE_SNES
+ if(state == CLEAR_LINE)
+ LINE_NMI = 0;
+ else if(!LINE_NMI)
+ {
+ LINE_NMI = 1;
+ CLK(7);
+ PUSH_16(REG_PC);
+ PUSH_8(GET_REG_P_INT());
+ JUMP(read_16_VEC(VECTOR_NMI));
+ }
+#endif /* SPC700_OPTIMIZE_SNES */
+}
+
+/* Assert or clear the IRQ line of the CPU */
+void spc700_set_irq_line(int line, int state)
+{
+#if !SPC700_OPTIMIZE_SNES
+ LINE_IRQ = (state != CLEAR_LINE) ? IRQ_SET : IRQ_CLEAR;
+ CHECK_IRQ();
+#endif /* SPC700_OPTIMIZE_SNES */
+}
+
+/* Set the callback that is called when servicing an interrupt */
+void spc700_set_irq_callback(int (*callback)(int))
+{
+ INT_ACK = callback;
+}
+
+/* Save the current CPU state to disk */
+void spc700_state_save(void *file)
+{
+#if 0
+ int cpu = cpu_getactivecpu();
+ uint p = GET_REG_P();
+ state_save_UINT16(file,"spc700",cpu,"PC",&REG_PC,2);
+ state_save_UINT16(file,"spc700",cpu,"PPC",&REG_PPC,2);
+ state_save_UINT8(file,"spc700",cpu,"SP",&REG_SP,1);
+ state_save_UINT8(file,"spc700",cpu,"P",&p,1);
+ state_save_UINT8(file,"spc700",cpu,"A",&REG_A,1);
+ state_save_UINT8(file,"spc700",cpu,"X",&REG_X,1);
+ state_save_UINT8(file,"spc700",cpu,"Y",&REG_Y,1);
+ state_save_UINT8(file,"spc700",cpu,"IRQ",&LINE_IRQ,1);
+ state_save_UINT8(file,"spc700",cpu,"NMI",&LINE_NMI,1);
+#endif
+}
+
+/* Load a CPU state from disk */
+void spc700_state_load(void *file)
+{
+#if 0
+ int cpu = cpu_getactivecpu();
+ uint p;
+ state_load_UINT16(file,"spc700",cpu,"PC",&REG_PC,2);
+ state_load_UINT16(file,"spc700",cpu,"PPC",&REG_PPC,2);
+ state_load_UINT8(file,"spc700",cpu,"SP",&REG_SP,1);
+ state_load_UINT8(file,"spc700",cpu,"P",&p,1);
+ state_load_UINT8(file,"spc700",cpu,"A",&REG_A,1);
+ state_load_UINT8(file,"spc700",cpu,"X",&REG_X,1);
+ state_load_UINT8(file,"spc700",cpu,"Y",&REG_Y,1);
+ state_load_UINT8(file,"spc700",cpu,"IRQ",&LINE_IRQ,1);
+ state_load_UINT8(file,"spc700",cpu,"NMI",&LINE_NMI,1);
+ SET_REG_P(p);
+#endif
+}
+
+
+#ifdef MAME_DEBUG
+#include "spc700ds.h"
+#endif
+
+//int dump_flag = 0;
+
+/* Execute instructions for <clocks> cycles */
+int spc700_execute(int clocks)
+{
+ CLOCKS = CPU_STOPPED ? 0 : clocks;
+ while(CLOCKS > 0)
+ {
+ REG_PPC = REG_PC;
+ CALL_MAME_DEBUG;
+ REG_PC++;
+
+#if 0
+// if ((!(REG_PPC & 0xf000)) && (dump_flag == 0)) { dump_flag = 1; mame_printf_debug("Dump started\n"); }
+
+ if (dump_flag && 0)
+ {
+ uint p = ((spc700i_cpu.flag_n & 0x80) |
+ ((spc700i_cpu.flag_v & 0x80) >> 1) |
+ spc700i_cpu.flag_p>>3 |
+ spc700i_cpu.flag_b |
+ (spc700i_cpu.flag_h & HFLAG_SET) |
+ spc700i_cpu.flag_i |
+ ((!spc700i_cpu.flag_z) << 1) |
+ ((spc700i_cpu.flag_c >> 8)&1));
+
+ mame_printf_debug("[%04x]: A%02x X%02x Y%02x P%02x SP%02x - %c%c%c%c%c%c%c%c\n", REG_PPC, REG_A, REG_X, REG_Y, p, REG_S,
+ p & 0x80 ? 'N':'.',
+ p & 0x40 ? 'V':'.',
+ p & 0x20 ? 'P':'.',
+ p & 0x10 ? 'B':'.',
+ p & 0x08 ? 'H':'.',
+ p & 0x04 ? 'I':'.',
+ p & 0x02 ? 'Z':'.',
+ p & 0x01 ? 'C':'.');
+
+ dump_flag--;
+ }
+#endif
+ switch(REG_IR = read_8_immediate(REG_PPC))
+ {
+ case 0x00: OP_NOP ( 2 ); break; /* NOP */
+ case 0x01: OP_TCALL ( 8, 0 ); break; /* TCALL 0 */
+ case 0x02: OP_SET ( 4, BIT_0 ); break; /* SET 0 */
+ case 0x03: OP_BBS ( 5, BIT_0 ); break; /* BBS 0 */
+ case 0x04: OP_OR ( 3, DP ); break; /* ORA dp */
+ case 0x05: OP_OR ( 4, ABS ); break; /* ORA abs */
+ case 0x06: OP_OR ( 3, XI ); break; /* ORA xi */
+ case 0x07: OP_OR ( 6, DXI ); break; /* ORA dxi */
+ case 0x08: OP_OR ( 2, IMM ); break; /* ORA imm */
+ case 0x09: OP_ORM ( 6, DP , DP ); break; /* ORM dp dp */
+ case 0x0a: OP_OR1 ( 5 ); break; /* OR1 bit */
+ case 0x0b: OP_ASLM ( 4, DP ); break; /* ASL dp */
+ case 0x0c: OP_ASLM ( 4, ABS ); break; /* ASL abs */
+ case 0x0d: OP_PHP ( 4 ); break; /* PHP */
+ case 0x0e: OP_TSET1 ( 6, ABS ); break; /* TSET1 abs */
+ case 0x0f: OP_BRK ( 8 ); break; /* BRK */
+ case 0x10: OP_BCC ( 2, COND_PL() ); break; /* BPL */
+ case 0x11: OP_TCALL ( 8, 1 ); break; /* TCALL 1 */
+ case 0x12: OP_CLR ( 4, BIT_0 ); break; /* CLR 0 */
+ case 0x13: OP_BBC ( 5, BIT_0 ); break; /* BBC 0 */
+ case 0x14: OP_OR ( 4, DPX ); break; /* ORA dpx */
+ case 0x15: OP_OR ( 5, ABX ); break; /* ORA abx */
+ case 0x16: OP_OR ( 5, ABY ); break; /* ORA aby */
+ case 0x17: OP_OR ( 6, DIY ); break; /* ORA diy */
+ case 0x18: OP_ORM ( 6, IMM, DP ); break; /* ORM dp, imm */
+ case 0x19: OP_ORM ( 6, YI, XI ); break; /* ORM xi, yi */
+ case 0x1a: OP_DECW ( 6 ); break; /* DECW di */
+ case 0x1b: OP_ASLM ( 5, DPX ); break; /* ASL dpx */
+ case 0x1c: OP_ASL ( 2 ); break; /* ASL a */
+ case 0x1d: OP_DECR ( 2, REG_X ); break; /* DEC x */
+ case 0x1e: OP_CMPR ( 4, REG_X, ABS ); break; /* CMP x, abs */
+ case 0x1f: OP_JMP ( 6, AXI ); break; /* JMP axi */
+ case 0x20: OP_CLRP ( 2 ); break; /* CLRP */
+ case 0x21: OP_TCALL ( 8, 2 ); break; /* TCALL 2 */
+ case 0x22: OP_SET ( 4, BIT_1 ); break; /* SET 1 */
+ case 0x23: OP_BBS ( 5, BIT_1 ); break; /* BBS 1 */
+ case 0x24: OP_AND ( 3, DP ); break; /* AND dp */
+ case 0x25: OP_AND ( 4, ABS ); break; /* AND abs */
+ case 0x26: OP_AND ( 3, XI ); break; /* AND xi */
+ case 0x27: OP_AND ( 6, DXI ); break; /* AND dxi */
+ case 0x28: OP_AND ( 2, IMM ); break; /* AND imm */
+ case 0x29: OP_ANDM ( 6, DP , DP ); break; /* AND dp, dp */
+ case 0x2a: OP_ORN1 ( 5 ); break; /* OR1 !bit */
+ case 0x2b: OP_ROLM ( 4, DP ); break; /* ROL dp */
+ case 0x2c: OP_ROLM ( 5, ABS ); break; /* ROL abs */
+ case 0x2d: OP_PUSH ( 4, REG_A ); break; /* PUSH a */
+ case 0x2e: OP_CBNE ( 5, DP ); break; /* CBNE dp */
+ case 0x2f: OP_BRA ( 4 ); break; /* BRA */
+ case 0x30: OP_BCC ( 2, COND_MI() ); break; /* BMI */
+ case 0x31: OP_TCALL ( 8, 3 ); break; /* TCALL 3 */
+ case 0x32: OP_CLR ( 4, BIT_1 ); break; /* CLR 1 */
+ case 0x33: OP_BBC ( 5, BIT_1 ); break; /* BBC 1 */
+ case 0x34: OP_AND ( 4, DPX ); break; /* AND dpx */
+ case 0x35: OP_AND ( 5, ABX ); break; /* AND abx */
+ case 0x36: OP_AND ( 5, ABY ); break; /* AND aby */
+ case 0x37: OP_AND ( 6, DIY ); break; /* AND diy */
+ case 0x38: OP_ANDM ( 5, IMM, DP ); break; /* AND dp, imm */
+ case 0x39: OP_ANDM ( 5, YI , XI ); break; /* AND xi, yi */
+ case 0x3a: OP_INCW ( 6 ); break; /* INCW di */
+ case 0x3b: OP_ROLM ( 5, DPX ); break; /* ROL dpx */
+ case 0x3c: OP_ROL ( 2 ); break; /* ROL acc */
+ case 0x3d: OP_INCR ( 2, REG_X ); break; /* INC x */
+ case 0x3e: OP_CMPR ( 3, REG_X, DP ); break; /* CMP x, dp */
+ case 0x3f: OP_CALL ( 8 ); break; /* CALL abs */
+ case 0x40: OP_SETP ( 2 ); break; /* RTI */
+ case 0x41: OP_TCALL ( 8, 4 ); break; /* TCALL 4 */
+ case 0x42: OP_SET ( 4, BIT_2 ); break; /* SET 2 */
+ case 0x43: OP_BBS ( 5, BIT_2 ); break; /* BBS 2 */
+ case 0x44: OP_EOR ( 3, DP ); break; /* EOR dp */
+ case 0x45: OP_EOR ( 4, ABS ); break; /* EOR abs */
+ case 0x46: OP_EOR ( 3, XI ); break; /* EOR xi */
+ case 0x47: OP_EOR ( 6, DXI ); break; /* EOR dxi */
+ case 0x48: OP_EOR ( 2, IMM ); break; /* EOR imm */
+ case 0x49: OP_EORM ( 6, DP, DP ); break; /* EOR dp, dp */
+ case 0x4a: OP_AND1 ( 5 ); break; /* AND1 bit */
+ case 0x4b: OP_LSRM ( 4, DP ); break; /* LSR dp */
+ case 0x4c: OP_LSRM ( 5, ABS ); break; /* LSR abs */
+ case 0x4d: OP_PUSH ( 4, REG_X ); break; /* PUSH x */
+ case 0x4e: OP_TCLR1 ( 6, ABS ); break; /* TCLR1 abs */
+ case 0x4f: OP_PCALL ( 6 ); break; /* PCALL */
+ case 0x50: OP_BCC ( 2, COND_VC() ); break; /* BVC */
+ case 0x51: OP_TCALL ( 8, 5 ); break; /* TCALL 5 */
+ case 0x52: OP_CLR ( 4, BIT_2 ); break; /* CLR 2 */
+ case 0x53: OP_BBC ( 5, BIT_2 ); break; /* BBC 2 */
+ case 0x54: OP_EOR ( 4, DPX ); break; /* EOR dpx */
+ case 0x55: OP_EOR ( 5, ABX ); break; /* EOR abx */
+ case 0x56: OP_EOR ( 5, ABY ); break; /* EOR aby */
+ case 0x57: OP_EOR ( 6, DIY ); break; /* EOR diy */
+ case 0x58: OP_EORM ( 5, IMM, DP ); break; /* EOR dp, imm */
+ case 0x59: OP_EORM ( 5, YI , XI ); break; /* EOR xi, yi */
+ case 0x5a: OP_CMPW ( 4, DP ); break; /* CMPW dp */
+ case 0x5b: OP_LSRM ( 5, DPX ); break; /* LSR dpx */
+ case 0x5c: OP_LSR ( 2 ); break; /* LSR */
+ case 0x5d: OP_MOVRR ( 2, REG_A, REG_X ); break; /* MOV X, A */
+ case 0x5e: OP_CMPR ( 4, REG_Y, ABS ); break; /* CMP Y, abs */
+ case 0x5f: OP_JMP ( 3, ABS ); break; /* JMP abs */
+ case 0x60: OP_CLRC ( 2 ); break; /* CLRC */
+ case 0x61: OP_TCALL ( 8, 6 ); break; /* TCALL 6 */
+ case 0x62: OP_SET ( 4, BIT_3 ); break; /* SET 3 */
+ case 0x63: OP_BBS ( 5, BIT_3 ); break; /* BBS 3 */
+ case 0x64: OP_CMPR ( 3, REG_A, DP ); break; /* CMP A, dp */
+ case 0x65: OP_CMPR ( 4, REG_A, ABS ); break; /* CMP A, abs */
+ case 0x66: OP_CMPR ( 3, REG_A, XI ); break; /* CMP A, xi */
+ case 0x67: OP_CMPR ( 6, REG_A, DXI ); break; /* CMP A, dxi */
+ case 0x68: OP_CMPR ( 2, REG_A, IMM ); break; /* CMP A, imm */
+ case 0x69: OP_CMPM ( 6, DP, DP ); break; /* CMP dp, dp */
+ case 0x6a: OP_ANDN1 ( 4 ); break; /* AND1 !bit */
+ case 0x6b: OP_RORM ( 4, DP ); break; /* ROR dp */
+ case 0x6c: OP_RORM ( 5, ABS ); break; /* ROR abs */
+ case 0x6d: OP_PUSH ( 4, REG_Y ); break; /* PUSH Y */
+ case 0x6e: OP_DBNZM ( 5 ); break; /* DBNZ dp */
+ case 0x6f: OP_RET ( 5 ); break; /* RET */
+ case 0x70: OP_BCC ( 2, COND_VS() ); break; /* BVS */
+ case 0x71: OP_TCALL ( 8, 7 ); break; /* TCALL 7 */
+ case 0x72: OP_CLR ( 4, BIT_3 ); break; /* CLR 3 */
+ case 0x73: OP_BBC ( 5, BIT_3 ); break; /* BBC 3 */
+ case 0x74: OP_CMPR ( 4, REG_A, DPX ); break; /* CMP A, dpx */
+ case 0x75: OP_CMPR ( 5, REG_A, ABX ); break; /* CMP A, abx */
+ case 0x76: OP_CMPR ( 5, REG_A, ABY ); break; /* CMP A, aby */
+ case 0x77: OP_CMPR ( 6, REG_A, DIY ); break; /* CMP A, diy */
+ case 0x78: OP_CMPM ( 5, IMM, DP ); break; /* CMP dp, imm */
+ case 0x79: OP_CMPM ( 5, YI, XI ); break; /* CMP xi, yi */
+ case 0x7a: OP_ADDW ( 5 ); break; /* ADDW di */
+ case 0x7b: OP_RORM ( 5, DPX ); break; /* ROR dpx */
+ case 0x7c: OP_ROR ( 2 ); break; /* ROR A */
+ case 0x7d: OP_MOVRR ( 2, REG_X, REG_A ); break; /* MOV A, X */
+ case 0x7e: OP_CMPR ( 3, REG_Y, DP ); break; /* CMP Y, dp */
+ case 0x7f: OP_RETI ( 6 ); break; /* RETI */
+ case 0x80: OP_SETC ( 2 ); break; /* SETC */
+ case 0x81: OP_TCALL ( 8, 8 ); break; /* TCALL 8 */
+ case 0x82: OP_SET ( 4, BIT_4 ); break; /* SET 4 */
+ case 0x83: OP_BBS ( 5, BIT_4 ); break; /* BBS 4 */
+ case 0x84: OP_ADC ( 3, DP ); break; /* ADC dp */
+ case 0x85: OP_ADC ( 4, ABS ); break; /* ADC abs */
+ case 0x86: OP_ADC ( 3, XI ); break; /* ADC xi */
+ case 0x87: OP_ADC ( 6, DXI ); break; /* ADC dxi */
+ case 0x88: OP_ADC ( 2, IMM ); break; /* ADC imm */
+ case 0x89: OP_ADCM ( 6, DP, DP ); break; /* ADC dp, dp */
+ case 0x8a: OP_EOR1 ( 4 ); break; /* EOR1 bit */
+ case 0x8b: OP_DECM ( 4, DP ); break; /* DEC dp */
+ case 0x8c: OP_DECM ( 5, ABS ); break; /* DEC abs */
+ case 0x8d: OP_MOVMR ( 2, IMM, REG_Y ); break; /* MOV Y, imm */
+ case 0x8e: OP_PLP ( 4 ); break; /* POP PSW */
+ case 0x8f: OP_MOVMM ( 5, IMM, DP ); break; /* MOV dp, imm */
+ case 0x90: OP_BCC ( 2, COND_CC() ); break; /* BCC */
+ case 0x91: OP_TCALL ( 8, 9 ); break; /* TCALL 9 */
+ case 0x92: OP_CLR ( 4, BIT_4 ); break; /* CLR 4 */
+ case 0x93: OP_BBC ( 5, BIT_4 ); break; /* BBC 4 */
+ case 0x94: OP_ADC ( 4, DPX ); break; /* ADC dpx */
+ case 0x95: OP_ADC ( 5, ABX ); break; /* ADC abx */
+ case 0x96: OP_ADC ( 5, ABY ); break; /* ADC aby */
+ case 0x97: OP_ADC ( 6, DIY ); break; /* ADC diy */
+ case 0x98: OP_ADCM ( 5, IMM, DP ); break; /* ADC dp, imm */
+ case 0x99: OP_ADCM ( 5, YI, XI ); break; /* ADC xi, yi */
+ case 0x9a: OP_SUBW ( 5 ); break; /* SUBW dp */
+ case 0x9b: OP_DECM ( 5, DPX ); break; /* DEC dpx */
+ case 0x9c: OP_DECR ( 2, REG_A ); break; /* DEC A */
+ case 0x9d: OP_MOVSX ( 2 ); break; /* MOV X, SP */
+ case 0x9e: OP_DIV (12 ); break; /* DIV YA, X */
+ case 0x9f: OP_XCN ( 5 ); break; /* XCN A */
+ case 0xa0: OP_EI ( 3 ); break; /* EI */
+ case 0xa1: OP_TCALL ( 8, 10 ); break; /* TCALL 10 */
+ case 0xa2: OP_SET ( 4, BIT_5 ); break; /* SET 5 */
+ case 0xa3: OP_BBS ( 5, BIT_5 ); break; /* BBS 5 */
+ case 0xa4: OP_SBC ( 3, DP ); break; /* SBC dp */
+ case 0xa5: OP_SBC ( 4, ABS ); break; /* SBC abs */
+ case 0xa6: OP_SBC ( 3, XI ); break; /* SBC xi */
+ case 0xa7: OP_SBC ( 6, DXI ); break; /* SBC dxi */
+ case 0xa8: OP_SBC ( 2, IMM ); break; /* SBC imm */
+ case 0xa9: OP_SBCM ( 6, DP, DP ); break; /* SBC dp, dp */
+ case 0xaa: OP_MOV1C ( 4 ); break; /* MOV1 bit->C */
+ case 0xab: OP_INCM ( 4, DP ); break; /* INC dp */
+ case 0xac: OP_INCM ( 5, ABS ); break; /* INC abs */
+ case 0xad: OP_CMPR ( 2, REG_Y, IMM ); break; /* CMP Y, imm */
+ case 0xae: OP_PULL ( 4, REG_A ); break; /* POP A */
+ case 0xaf: OP_MOVRM ( 4, REG_A, XII ); break; /* MOV xii, A */
+ case 0xb0: OP_BCC ( 2, COND_CS() ); break; /* BCS */
+ case 0xb1: OP_TCALL ( 8, 11 ); break; /* TCALL 11 */
+ case 0xb2: OP_CLR ( 4, BIT_5 ); break; /* CLR 5 */
+ case 0xb3: OP_BBC ( 5, BIT_5 ); break; /* BBC 5 */
+ case 0xb4: OP_SBC ( 4, DPX ); break; /* SBC dpx */
+ case 0xb5: OP_SBC ( 5, ABX ); break; /* SBC abx */
+ case 0xb6: OP_SBC ( 5, ABY ); break; /* SBC aby */
+ case 0xb7: OP_SBC ( 6, DIY ); break; /* SBC diy */
+ case 0xb8: OP_SBCM ( 5, IMM, DP ); break; /* SBC dp, imm */
+ case 0xb9: OP_SBCM ( 5, YI, XI ); break; /* SBC xi, yi */
+ case 0xba: OP_MOVWMR( 5 ); break; /* MOVW YA, dp */
+ case 0xbb: OP_INCM ( 5, DPX ); break; /* INC dpx */
+ case 0xbc: OP_INCR ( 2, REG_A ); break; /* INC A */
+ case 0xbd: OP_MOVXS ( 2 ); break; /* MOV SP, X */
+ case 0xbe: OP_DAS ( 3 ); break; /* DAS A */
+ case 0xbf: OP_MOVMR ( 4, XII, REG_A ); break; /* MOV A, xii */
+ case 0xc0: OP_DI ( 3 ); break; /* DI */
+ case 0xc1: OP_TCALL ( 8, 12 ); break; /* TCALL 12 */
+ case 0xc2: OP_SET ( 4, BIT_6 ); break; /* SET 6 */
+ case 0xc3: OP_BBS ( 5, BIT_6 ); break; /* BBS 6 */
+ case 0xc4: OP_MOVRM ( 4, REG_A, DP ); break; /* MOV dp, A */
+ case 0xc5: OP_MOVRM ( 5, REG_A, ABS ); break; /* MOV abs, A */
+ case 0xc6: OP_MOVRM ( 4, REG_A, XI ); break; /* MOV xi, A */
+ case 0xc7: OP_MOVRM ( 7, REG_A, DXI ); break; /* MOV dxi, A */
+ case 0xc8: OP_CMPR ( 2, REG_X, IMM ); break; /* CMP X, imm */
+ case 0xc9: OP_MOVRM ( 5, REG_X, ABS ); break; /* MOV abs, X */
+ case 0xca: OP_MOV1M ( 6 ); break; /* MOV1 C->bit */
+ case 0xcb: OP_MOVRM ( 4, REG_Y, DP ); break; /* MOV dp, Y */
+ case 0xcc: OP_MOVRM ( 5, REG_Y, ABS ); break; /* MOV abs, Y */
+ case 0xcd: OP_MOVMR ( 2, IMM, REG_X ); break; /* MOV X, imm */
+ case 0xce: OP_PULL ( 4, REG_X ); break; /* POP X */
+ case 0xcf: OP_MUL ( 9 ); break; /* MUL YA */
+ case 0xd0: OP_BCC ( 2, COND_NE() ); break; /* BNE */
+ case 0xd1: OP_TCALL ( 8, 13 ); break; /* TCALL 13 */
+ case 0xd2: OP_CLR ( 4, BIT_6 ); break; /* CLR 6 */
+ case 0xd3: OP_BBC ( 5, BIT_6 ); break; /* BBC 6 */
+ case 0xd4: OP_MOVRM ( 5, REG_A, DPX ); break; /* MOV dpx, A */
+ case 0xd5: OP_MOVRM ( 6, REG_A, ABX ); break; /* MOV abx, A */
+ case 0xd6: OP_MOVRM ( 6, REG_A, ABY ); break; /* MOV aby, A */
+ case 0xd7: OP_MOVRM ( 7, REG_A, DIY ); break; /* MOV diy, A */
+ case 0xd8: OP_MOVRM ( 4, REG_X, DP ); break; /* MOV dp, X */
+ case 0xd9: OP_MOVRM ( 5, REG_X, DPY ); break; /* MOV dpy, X */
+ case 0xda: OP_MOVWRM( 5 ); break; /* MOVW dp, YA */
+ case 0xdb: OP_MOVRM ( 5, REG_Y, DPX ); break; /* MOV dpx, Y */
+ case 0xdc: OP_DECR ( 2, REG_Y ); break; /* DEC Y */
+ case 0xdd: OP_MOVRR ( 2, REG_Y, REG_A ); break; /* MOV A, Y */
+ case 0xde: OP_CBNE ( 6, DPX ); break; /* CBNE dpx */
+ case 0xdf: OP_DAA ( 3 ); break; /* DAA */
+ case 0xe0: OP_CLRV ( 2 ); break; /* CLRV */
+ case 0xe1: OP_TCALL ( 8, 14 ); break; /* TCALL 14 */
+ case 0xe2: OP_SET ( 4, BIT_7 ); break; /* SET 7 */
+ case 0xe3: OP_BBS ( 5, BIT_7 ); break; /* BBS 7 */
+ case 0xe4: OP_MOVMR ( 3, DP, REG_A ); break; /* MOV A, dp */
+ case 0xe5: OP_MOVMR ( 4, ABS, REG_A ); break; /* MOV A, abs */
+ case 0xe6: OP_MOVMR ( 3, XI, REG_A ); break; /* MOV A, xi */
+ case 0xe7: OP_MOVMR ( 6, DXI, REG_A ); break; /* MOV A, dxi */
+ case 0xe8: OP_MOVMR ( 2, IMM, REG_A ); break; /* CMP A, imm */
+ case 0xe9: OP_MOVMR ( 4, ABS, REG_X ); break; /* MOV X, abs */
+ case 0xea: OP_NOT1 ( 5 ); break; /* NOT1 */
+ case 0xeb: OP_MOVMR ( 3, DP, REG_Y ); break; /* MOV Y, dp */
+ case 0xec: OP_MOVMR ( 4, ABS, REG_Y ); break; /* MOV Y, abs */
+ case 0xed: OP_NOTC ( 3 ); break; /* NOTC */
+ case 0xee: OP_PULL ( 4, REG_Y ); break; /* POP Y */
+ case 0xef: OP_SLEEP ( 3 ); break; /* SLEEP */
+ case 0xf0: OP_BCC ( 2, COND_EQ() ); break; /* BEQ */
+ case 0xf1: OP_TCALL ( 8, 15 ); break; /* TCALL1 5 */
+ case 0xf2: OP_CLR ( 4, BIT_7 ); break; /* CLR 7 */
+ case 0xf3: OP_BBC ( 5, BIT_7 ); break; /* BBC 7 */
+ case 0xf4: OP_MOVMR ( 4, DPX, REG_A ); break; /* MOV A, dpx */
+ case 0xf5: OP_MOVMR ( 5, ABX, REG_A ); break; /* MOV A, abx */
+ case 0xf6: OP_MOVMR ( 5, ABY, REG_A ); break; /* MOV A, aby */
+ case 0xf7: OP_MOVMR ( 6, DIY, REG_A ); break; /* MOV A, diy */
+ case 0xf8: OP_MOVMR ( 3, DP, REG_X ); break; /* MOV X, dp */
+ case 0xf9: OP_MOVMR ( 4, DPY, REG_X ); break; /* MOV X, dpy */
+ case 0xfa: OP_MOVMM ( 5, DP, DP ); break; /* MOV dp, dp */
+ case 0xfb: OP_MOVMR ( 4, DPX, REG_Y ); break; /* MOV Y, DPX */
+ case 0xfc: OP_INCR ( 2, REG_Y ); break; /* INC Y */
+ case 0xfd: OP_MOVRR ( 2, REG_A, REG_Y ); break; /* MOV Y, A */
+ case 0xfe: OP_DBNZR ( 4 ); break; /* DBNZ Y */
+ case 0xff: OP_STOP ( 3 ); break; /* STOP */
+ }
+ }
+ return clocks - CLOCKS;
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void spc700_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: spc700_set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: spc700_set_nmi_line(info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SPC700_PC: REG_PC = MAKE_UINT_16(info->i); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + SPC700_S: REG_S = MAKE_UINT_8(info->i); break;
+ case CPUINFO_INT_REGISTER + SPC700_P: SET_REG_P(info->i); break;
+ case CPUINFO_INT_REGISTER + SPC700_A: REG_A = MAKE_UINT_8(info->i); break;
+ case CPUINFO_INT_REGISTER + SPC700_X: REG_X = MAKE_UINT_8(info->i); break;
+ case CPUINFO_INT_REGISTER + SPC700_Y: REG_Y = MAKE_UINT_8(info->i); break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void spc700_get_info(UINT32 state, cpuinfo *info)
+{
+ uint p = ((spc700i_cpu.flag_n & 0x80) |
+ ((spc700i_cpu.flag_v & 0x80) >> 1) |
+ spc700i_cpu.flag_p>>3 |
+ spc700i_cpu.flag_b |
+ (spc700i_cpu.flag_h & HFLAG_SET) |
+ spc700i_cpu.flag_i |
+ ((!spc700i_cpu.flag_z) << 1) |
+ ((spc700i_cpu.flag_c >> 8)&1));
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(spc700i_cpu); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 8; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = (LINE_IRQ == IRQ_SET) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = REG_PPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SPC700_PC: info->i = REG_PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + SPC700_S: info->i = REG_S + STACK_PAGE; break;
+ case CPUINFO_INT_REGISTER + SPC700_P: info->i = GET_REG_P(); break;
+ case CPUINFO_INT_REGISTER + SPC700_A: info->i = REG_A; break;
+ case CPUINFO_INT_REGISTER + SPC700_X: info->i = REG_X; break;
+ case CPUINFO_INT_REGISTER + SPC700_Y: info->i = REG_Y; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = spc700_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = spc700_get_context_mame; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = spc700_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = spc700_init; break;
+ case CPUINFO_PTR_RESET: info->reset = spc700_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = spc700_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = spc700_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = spc700_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &spc700_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "SPC700"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Sony SPC700"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) , all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ p & 0x80 ? 'N':'.',
+ p & 0x40 ? 'V':'.',
+ p & 0x20 ? 'P':'.',
+ p & 0x10 ? 'B':'.',
+ p & 0x08 ? 'H':'.',
+ p & 0x04 ? 'I':'.',
+ p & 0x02 ? 'Z':'.',
+ p & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + SPC700_PC: sprintf(info->s, "PC:%04X", spc700i_cpu.pc); break;
+ case CPUINFO_STR_REGISTER + SPC700_S: sprintf(info->s, "S:%02X", spc700i_cpu.s); break;
+ case CPUINFO_STR_REGISTER + SPC700_P: sprintf(info->s, "P:%02X", p); break;
+ case CPUINFO_STR_REGISTER + SPC700_A: sprintf(info->s, "A:%02X", spc700i_cpu.a); break;
+ case CPUINFO_STR_REGISTER + SPC700_X: sprintf(info->s, "X:%02X", spc700i_cpu.x); break;
+ case CPUINFO_STR_REGISTER + SPC700_Y: sprintf(info->s, "Y:%02X", spc700i_cpu.y); break;
+ }
+}
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
diff --git a/src/emu/cpu/spc700/spc700.h b/src/emu/cpu/spc700/spc700.h
new file mode 100644
index 00000000000..41407488485
--- /dev/null
+++ b/src/emu/cpu/spc700/spc700.h
@@ -0,0 +1,154 @@
+#ifndef SPC700__HEADER
+#define SPC700__HEADER
+
+/* ======================================================================== */
+/* ============================= Configuration ============================ */
+/* ======================================================================== */
+
+#ifndef INLINE
+#define INLINE static
+#endif
+
+/* Turn on optimizations for SNES since it doesn't hook up the interrupt lines */
+#define SPC700_OPTIMIZE_SNES 1
+
+
+/* ======================================================================== */
+/* ============================== PROTOTYPES ============================== */
+/* ======================================================================== */
+
+enum
+{
+ SPC700_PC=1, SPC700_S, SPC700_P, SPC700_A, SPC700_X, SPC700_Y
+};
+
+#define SPC700_INT_NONE 0
+#define SPC700_INT_IRQ 1
+#define SPC700_INT_NMI 2
+
+
+
+/* ======================================================================== */
+/* ============================= INTERFACE API ============================ */
+/* ======================================================================== */
+
+/* This is the interface, not the implementation. Please call the */
+/* implementation APIs below. */
+
+
+void spc700_init(int index, int clock, const void *config, int (*irqcallback)(int));
+
+/* Pulse the RESET pin on the CPU */
+void spc700_reset(void);
+
+/* Set the RESET line on the CPU */
+void spc700_set_reset_line(int state, void* param);
+
+/* Clean up after the emulation core - Not used in this core - */
+void spc700_exit(void);
+
+/* Get the current CPU context */
+unsigned spc700_get_context(void *dst);
+
+/* Set the current CPU context */
+void spc700_set_context(void *src);
+
+/* Get the current Program Counter */
+unsigned spc700_get_pc(void);
+
+/* Set the current Program Counter */
+void spc700_set_pc(unsigned val);
+
+/* Get the current Stack Pointer */
+unsigned spc700_get_sp(void);
+
+/* Set the current Stack Pointer */
+void spc700_set_sp(unsigned val);
+
+/* Get a register from the core */
+unsigned spc700_get_reg(int regnum);
+
+/* Set a register in the core */
+void spc700_set_reg(int regnum, unsigned val);
+
+/* Note about NMI:
+ * NMI is a one-shot trigger. In order to trigger NMI again, you must
+ * clear NMI and then assert it again.
+ */
+void spc700_set_nmi_line(int state);
+
+/* Assert or clear the IRQ pin */
+void spc700_set_irq_line(int line, int state);
+
+/* Set the callback that will be called when an interrupt is serviced */
+void spc700_set_irq_callback(int (*callback)(int));
+
+/* Save the current CPU state to disk */
+void spc700_state_save(void *file);
+
+/* Load a CPU state from disk */
+void spc700_state_load(void *file);
+
+/* Get a formatted string representing a register and its contents */
+const char *spc700_info(void *context, int regnum);
+
+
+/* Pulse the SO (Set Overflow) pin on the CPU */
+void spc700_pulse_so(void);
+
+extern int spc700_ICount; /* cycle count */
+
+int spc700_execute(int clocks);
+
+
+/* ======================================================================== */
+/* =================== Functions Implemented by the Host ================== */
+/* ======================================================================== */
+
+/* Read data from RAM */
+unsigned int spc700_read_8(unsigned int address);
+
+/* Read data from the direct page */
+unsigned int spc700_read_8_direct(unsigned int address);
+
+/* Read data from ROM */
+unsigned int spc700_read_8_immediate(unsigned int address);
+unsigned int spc700_read_8_instruction(unsigned int address);
+
+/* Write data to RAM */
+void spc700_write_8(unsigned int address, unsigned int value);
+void spc700_write_8_direct(unsigned int address, unsigned int value);
+
+void spc700_jumping(unsigned int new_pc);
+void spc700_branching(unsigned int new_pc);
+
+
+
+/* ======================================================================== */
+/* ================================= MAME ================================= */
+/* ======================================================================== */
+
+#include "cpuintrf.h"
+
+extern void spc700_get_info(UINT32 state, cpuinfo *info);
+
+#define spc700_read_8(addr) program_read_byte_8(addr)
+#define spc700_write_8(addr,data) program_write_byte_8(addr,data)
+
+#define spc700_read_8_direct(A) spc700_read_8(A)
+#define spc700_write_8_direct(A, V) spc700_write_8(A, V)
+//#define spc700_read_instruction(A) cpu_readop(A)
+//#define spc700_read_8_immediate(A) cpu_readop_arg(A)
+#define spc700_read_instruction(A) program_read_byte_8(A)
+#define spc700_read_8_immediate(A) program_read_byte_8(A)
+#define spc700_jumping(A) change_pc(A)
+#define spc700_branching(A) change_pc(A)
+
+
+
+/* ======================================================================== */
+/* ============================== END OF FILE ============================= */
+/* ======================================================================== */
+
+#endif /* SPC700__HEADER */
+
diff --git a/src/emu/cpu/spc700/spc700ds.c b/src/emu/cpu/spc700/spc700ds.c
new file mode 100644
index 00000000000..373832a210a
--- /dev/null
+++ b/src/emu/cpu/spc700/spc700ds.c
@@ -0,0 +1,437 @@
+/* ======================================================================== */
+/* =============================== COPYRIGHT ============================== */
+/* ======================================================================== */
+/*
+
+SPC700 CPU Emulator V0.90
+
+Copyright (c) 2000 Karl Stenerud
+All rights reserved.
+
+Permission is granted to use this source code for non-commercial purposes.
+To use this code for commercial purposes, you must get permission from the
+author (Karl Stenerud) at karl@higashiyama-unet.ocn.ne.jp.
+
+
+*/
+
+
+#include "spc700ds.h"
+
+
+#ifndef INLINE
+#define INLINE static
+#endif
+
+
+typedef struct
+{
+ unsigned char name;
+ unsigned char args[2];
+} opcode_struct;
+
+enum
+{
+ IMP , A , X , Y , YA , SP , PSW , C , REL , UPAG, IMM , XI ,
+ XII , YI , DP , DPX , DPY , DPI , DXI , DIY , ABS , ABX , ABY , AXI , N0 ,
+ N1 , N2 , N3 , N4 , N5 , N6 , N7 , N8 , N9 , N10 , N11 , N12 ,
+ N13 , N14 , N15 , DP0 , DP1 , DP2 , DP3 , DP4 , DP5 , DP6 , DP7 , MEMN,
+ MEMI
+};
+
+
+enum
+{
+ ADC , ADDW , AND , AND1 , ASL , BBC , BBS , BCC ,
+ BCS , BEQ , BMI , BNE , BPL , BRA , BRK , BVC ,
+ BVS , CALL , CBNE , CLR1 , CLRC , CLRP , CLRV , CMP ,
+ CMPW , DAA , DAS , DBNZ , DEC , DECW , DI , DIV ,
+ EI , EOR , EOR1 , INC , INCW , JMP , LSR , MOV ,
+ MOV1 , MOVW , MUL , NOP , NOT1 , NOTQ , NOTC , OR ,
+ OR1 , PCALL , POP , PUSH , RET , RETI , ROL , ROR ,
+ SBC , SET1 , SETC , SETP , SLEEP , STOP , SUBW , TCALL ,
+ TCLR1 , TSET1 , XCN
+};
+
+
+static const char* g_opnames[] =
+{
+ "ADC ", "ADDW ", "AND ", "AND1 ", "ASL ", "BBC ", "BBS ", "BCC ",
+ "BCS ", "BEQ ", "BMI ", "BNE ", "BPL ", "BRA ", "BRK ", "BVC ",
+ "BVS ", "CALL ", "CBNE ", "CLR1 ", "CLRC ", "CLRP ", "CLRV ", "CMP ",
+ "CMPW ", "DAA ", "DAS ", "DBNZ ", "DEC ", "DECW ", "DI ", "DIV ",
+ "EI ", "EOR ", "EOR1 ", "INC ", "INCW ", "JMP ", "LSR ", "MOV ",
+ "MOV1 ", "MOVW ", "MUL ", "NOP ", "NOT1 ", "NOTQ ", "NOTC ", "OR ",
+ "OR1 ", "PCALL", "POP ", "PUSH ", "RET ", "RETI ", "ROL ", "ROR ",
+ "SBC ", "SET1 ", "SETC ", "SETP ", "SLEEP", "STOP ", "SUBW ", "TCALL",
+ "TCLR1", "TSET1", "XCN "
+};
+
+static opcode_struct g_opcodes[256] =
+{
+/* 00 */ {NOP , {IMP , IMP }},
+/* 01 */ {TCALL , {N0 , IMP }},
+/* 02 */ {SET1 , {DP0 , IMP }},
+/* 03 */ {BBS , {DP0 , REL }},
+/* 04 */ {OR , {A , DP }},
+/* 05 */ {OR , {A , ABS }},
+/* 06 */ {OR , {A , XI }},
+/* 07 */ {OR , {A , DXI }},
+/* 08 */ {OR , {A , IMM }},
+/* 09 */ {OR , {DP , DP }},
+/* 0A */ {OR1 , {C , MEMN}},
+/* 0B */ {ASL , {DP , IMP }},
+/* 0C */ {ASL , {ABS , IMP }},
+/* 0D */ {PUSH , {PSW , IMP }},
+/* 0E */ {TSET1 , {ABS , IMP }},
+/* 0F */ {BRK , {IMM , IMP }},
+/* 10 */ {BPL , {REL , IMP }},
+/* 11 */ {TCALL , {N1 , IMP }},
+/* 12 */ {CLR1 , {DP0 , IMP }},
+/* 13 */ {BBC , {DP0 , REL }},
+/* 14 */ {OR , {A , DPX }},
+/* 15 */ {OR , {A , ABX }},
+/* 16 */ {OR , {A , ABY }},
+/* 17 */ {OR , {A , DIY }},
+/* 18 */ {OR , {DP , IMM }},
+/* 19 */ {OR , {XI , YI }},
+/* 1A */ {DECW , {DP , IMP }},
+/* 1B */ {ASL , {DPX , IMP }},
+/* 1C */ {ASL , {A , IMP }},
+/* 1D */ {DEC , {X , IMP }},
+/* 1E */ {CMP , {X , ABS }},
+/* 1F */ {JMP , {AXI , IMP }},
+/* 20 */ {CLRP , {IMP , IMP }},
+/* 21 */ {TCALL , {N2 , IMP }},
+/* 22 */ {SET1 , {DP1 , IMP }},
+/* 23 */ {BBS , {DP1 , REL }},
+/* 24 */ {AND , {A , DP }},
+/* 25 */ {AND , {A , ABS }},
+/* 26 */ {AND , {A , XI }},
+/* 27 */ {AND , {A , DXI }},
+/* 28 */ {AND , {A , IMM }},
+/* 29 */ {AND , {DP , DP }},
+/* 2A */ {OR1 , {C , MEMI}},
+/* 2B */ {ROL , {DP , IMP }},
+/* 2C */ {ROL , {ABS , IMP }},
+/* 2D */ {PUSH , {A , IMP }},
+/* 2E */ {CBNE , {DP , REL }},
+/* 2F */ {BRA , {REL , IMP }},
+/* 30 */ {BMI , {REL , IMP }},
+/* 31 */ {TCALL , {N3 , IMP }},
+/* 32 */ {CLR1 , {DP1 , IMP }},
+/* 33 */ {BBC , {DP1 , REL }},
+/* 34 */ {AND , {A , DPX }},
+/* 35 */ {AND , {A , ABX }},
+/* 36 */ {AND , {A , ABY }},
+/* 37 */ {AND , {A , DIY }},
+/* 38 */ {AND , {DP , IMM }},
+/* 39 */ {AND , {XI , YI }},
+/* 3A */ {INCW , {DI , IMP }},
+/* 3B */ {ROL , {DPX , IMP }},
+/* 3C */ {ROL , {A , IMP }},
+/* 3D */ {INC , {X , IMP }},
+/* 3E */ {CMP , {X , DP }},
+/* 3F */ {CALL , {ABS , IMP }},
+/* 40 */ {SETP , {IMP , IMP }},
+/* 41 */ {TCALL , {N4 , IMP }},
+/* 42 */ {SET1 , {DP2 , IMP }},
+/* 43 */ {BBS , {DP2 , REL }},
+/* 44 */ {EOR , {A , DP }},
+/* 45 */ {EOR , {A , ABS }},
+/* 46 */ {EOR , {A , XI }},
+/* 47 */ {EOR , {A , DXI }},
+/* 48 */ {EOR , {A , IMM }},
+/* 49 */ {EOR , {DP , DP }},
+/* 4A */ {AND1 , {C , MEMN}},
+/* 4B */ {LSR , {DP , IMP }},
+/* 4C */ {LSR , {ABS , IMP }},
+/* 4D */ {PUSH , {X , IMP }},
+/* 4E */ {TCLR1 , {ABS , IMP }},
+/* 4F */ {PCALL , {UPAG, IMP }},
+/* 50 */ {BVC , {REL , IMP }},
+/* 51 */ {TCALL , {N5 , IMP }},
+/* 52 */ {CLR1 , {DP2 , IMP }},
+/* 53 */ {BBC , {DP2 , REL }},
+/* 54 */ {EOR , {A , DPX }},
+/* 55 */ {EOR , {A , ABX }},
+/* 56 */ {EOR , {A , ABY }},
+/* 57 */ {EOR , {A , DIY }},
+/* 58 */ {EOR , {DP , IMM }},
+/* 59 */ {EOR , {XI , YI }},
+/* 5A */ {CMPW , {DP , IMP }},
+/* 5B */ {LSR , {DPX , IMP }},
+/* 5C */ {LSR , {A , IMP }},
+/* 5D */ {MOV , {X , A }},
+/* 5E */ {CMP , {Y , ABS }},
+/* 5F */ {JMP , {ABS , IMP }},
+/* 60 */ {CLRC , {IMP , IMP }},
+/* 61 */ {TCALL , {N6 , IMP }},
+/* 62 */ {SET1 , {DP3 , IMP }},
+/* 63 */ {BBS , {DP3 , REL }},
+/* 64 */ {CMP , {A , DP }},
+/* 65 */ {CMP , {A , ABS }},
+/* 66 */ {CMP , {A , XI }},
+/* 67 */ {CMP , {A , DXI }},
+/* 68 */ {CMP , {A , IMM }},
+/* 69 */ {CMP , {DP , DP }},
+/* 6A */ {AND1 , {C , MEMI}},
+/* 6B */ {ROR , {DP , IMP }},
+/* 6C */ {ROR , {ABS , IMP }},
+/* 6D */ {PUSH , {Y , IMP }},
+/* 6E */ {DBNZ , {DP , REL }},
+/* 6F */ {RET , {IMP , IMP }},
+/* 70 */ {BVS , {REL , IMP }},
+/* 71 */ {TCALL , {N7 , IMP }},
+/* 72 */ {CLR1 , {DP3 , IMP }},
+/* 73 */ {BBC , {DP3 , REL }},
+/* 74 */ {CMP , {A , DPX }},
+/* 75 */ {CMP , {A , ABX }},
+/* 76 */ {CMP , {A , ABY }},
+/* 77 */ {CMP , {A , DIY }},
+/* 78 */ {CMP , {IMM , DP }},
+/* 79 */ {CMP , {XI , YI }},
+/* 7A */ {ADDW , {DI , IMP }},
+/* 7B */ {ROR , {DPX , IMP }},
+/* 7C */ {ROR , {A , IMP }},
+/* 7D */ {MOV , {A , X }},
+/* 7E */ {CMP , {Y , DP }},
+/* 7F */ {RETI , {IMP , IMP }},
+/* 80 */ {SETC , {IMP , IMP }},
+/* 81 */ {TCALL , {N8 , IMP }},
+/* 82 */ {SET1 , {DP4 , IMP }},
+/* 83 */ {BBS , {DP4 , REL }},
+/* 84 */ {ADC , {A , DP }},
+/* 85 */ {ADC , {A , ABS }},
+/* 86 */ {ADC , {A , XI }},
+/* 87 */ {ADC , {A , DXI }},
+/* 88 */ {ADC , {A , IMM }},
+/* 89 */ {ADC , {DP , DP }},
+/* 8A */ {EOR1 , {C , MEMN}},
+/* 8B */ {DEC , {DP , IMP }},
+/* 8C */ {DEC , {ABS , IMP }},
+/* 8D */ {MOV , {Y , IMM }},
+/* 8E */ {POP , {PSW , IMP }},
+/* 8F */ {MOV , {IMM , DP }},
+/* 90 */ {BCC , {REL , IMP }},
+/* 91 */ {TCALL , {N9 , IMP }},
+/* 92 */ {CLR1 , {DP4 , IMP }},
+/* 93 */ {BBC , {DP4 , REL }},
+/* 94 */ {ADC , {A , DPX }},
+/* 95 */ {ADC , {A , ABX }},
+/* 96 */ {ADC , {A , ABY }},
+/* 97 */ {ADC , {A , DIY }},
+/* 98 */ {ADC , {DP , IMM }},
+/* 99 */ {ADC , {XI , YI }},
+/* 9A */ {SUBW , {DP , IMP }},
+/* 9B */ {DEC , {DPX , IMP }},
+/* 9C */ {DEC , {A , IMP }},
+/* 9D */ {MOV , {X , SP }},
+/* 9E */ {DIV , {YA , X }},
+/* 9F */ {XCN , {A , IMP }},
+/* A0 */ {EI , {IMP , IMP }},
+/* A1 */ {TCALL , {N10 , IMP }},
+/* A2 */ {SET1 , {DP5 , IMP }},
+/* A3 */ {BBS , {DP5 , REL }},
+/* A4 */ {SBC , {A , DP }},
+/* A5 */ {SBC , {A , ABS }},
+/* A6 */ {SBC , {A , XI }},
+/* A7 */ {SBC , {A , DXI }},
+/* A8 */ {SBC , {A , IMM }},
+/* A9 */ {SBC , {DP , DP }},
+/* AA */ {MOV1 , {C , MEMN}},
+/* AB */ {INC , {DP , IMP }},
+/* AC */ {INC , {ABS , IMP }},
+/* AD */ {CMP , {Y , IMM }},
+/* AE */ {POP , {A , IMP }},
+/* AF */ {MOV , {XII , A }},
+/* B0 */ {BCS , {REL , IMP }},
+/* B1 */ {TCALL , {N11 , IMP }},
+/* B2 */ {CLR1 , {DP5 , IMP }},
+/* B3 */ {BBC , {DP5 , REL }},
+/* B4 */ {SBC , {A , DPX }},
+/* B5 */ {SBC , {A , ABX }},
+/* B6 */ {SBC , {A , ABY }},
+/* B7 */ {SBC , {A , DIY }},
+/* B8 */ {SBC , {DP , IMM }},
+/* B9 */ {SBC , {XI , YI }},
+/* BA */ {MOVW , {YA , DP }},
+/* BB */ {INC , {DPX , IMP }},
+/* BC */ {INC , {A , IMP }},
+/* BD */ {MOV , {SP , X }},
+/* BE */ {DAS , {A , IMP }},
+/* BF */ {MOV , {A , XII }},
+/* C0 */ {DI , {IMP , IMP }},
+/* C1 */ {TCALL , {N12 , IMP }},
+/* C2 */ {SET1 , {DP6 , IMP }},
+/* C3 */ {BBS , {DP6 , REL }},
+/* C4 */ {MOV , {DP , A }},
+/* C5 */ {MOV , {ABS , A }},
+/* C6 */ {MOV , {XI , A }},
+/* C7 */ {MOV , {DXI , A }},
+/* C8 */ {CMP , {X , IMM }},
+/* C9 */ {MOV , {ABS , X }},
+/* CA */ {MOV1 , {MEMN, C }},
+/* CB */ {MOV , {DP , Y }},
+/* CC */ {MOV , {ABS , Y }},
+/* CD */ {MOV , {X , IMM }},
+/* CE */ {POP , {X , IMP }},
+/* CF */ {MUL , {YA , IMP }},
+/* D0 */ {BNE , {REL , IMP }},
+/* D1 */ {TCALL , {N13 , IMP }},
+/* D2 */ {CLR1 , {DP6 , IMP }},
+/* D3 */ {BBC , {DP6 , REL }},
+/* D4 */ {MOV , {DPX , A }},
+/* D5 */ {MOV , {ABX , A }},
+/* D6 */ {MOV , {ABY , A }},
+/* D7 */ {MOV , {DIY , A }},
+/* D8 */ {MOV , {DP , X }},
+/* D9 */ {MOV , {DPY , X }},
+/* DA */ {MOVW , {DP , YA }},
+/* DB */ {MOV , {DPX , Y }},
+/* DC */ {DEC , {Y , IMP }},
+/* DD */ {MOV , {A , Y }},
+/* DE */ {CBNE , {DPX , REL }},
+/* DF */ {DAA , {IMP , IMP }},
+/* E0 */ {CLRV , {IMP , IMP }},
+/* E1 */ {TCALL , {N14 , IMP }},
+/* E2 */ {SET1 , {DP7 , IMP }},
+/* E3 */ {BBS , {DP7 , REL }},
+/* E4 */ {MOV , {A , DP }},
+/* E5 */ {MOV , {A , ABS }},
+/* E6 */ {MOV , {A , XI }},
+/* E7 */ {MOV , {A , DXI }},
+/* E8 */ {MOV , {A , IMM }},
+/* E9 */ {MOV , {X , ABS }},
+/* EA */ {NOT1 , {IMP , IMP }},
+/* EB */ {MOV , {Y , DP }},
+/* EC */ {MOV , {Y , ABS }},
+/* ED */ {NOTC , {IMP , IMP }},
+/* EE */ {POP , {Y , IMP }},
+/* EF */ {SLEEP , {IMP , IMP }},
+/* F0 */ {BEQ , {REL , IMP }},
+/* F1 */ {TCALL , {N15 , IMP }},
+/* F2 */ {CLR1 , {DP7 , IMP }},
+/* F3 */ {BBC , {DP7 , REL }},
+/* F4 */ {MOV , {A , DPX }},
+/* F5 */ {MOV , {A , ABX }},
+/* F6 */ {MOV , {A , ABY }},
+/* F7 */ {MOV , {A , DIY }},
+/* F8 */ {MOV , {X , DP }},
+/* F9 */ {MOV , {X , DPY }},
+/* FA */ {MOV , {DP , DP }},
+/* FB */ {MOV , {Y , DPX }},
+/* FC */ {INC , {Y , IMP }},
+/* FD */ {MOV , {Y , A }},
+/* FE */ {DBNZ , {Y , REL }},
+/* FF */ {STOP , {IMP , IMP }},
+};
+
+static unsigned int g_pc;
+static const UINT8 *rombase;
+
+INLINE unsigned int read_8_immediate(void)
+{
+ g_pc++;
+ return *rombase++;
+}
+
+INLINE unsigned int read_16_immediate(void)
+{
+ unsigned int result;
+ g_pc += 2;
+ result = *rombase++;
+ return result | (*rombase++ << 8);
+}
+
+offs_t spc700_dasm(char *buff, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ opcode_struct* opcode;
+ UINT32 flags = 0;
+ char* ptr;
+ int var;
+ int i;
+
+ g_pc = pc;
+ rombase = oprom;
+ opcode = g_opcodes + read_8_immediate();
+
+ sprintf(buff, "%s ", g_opnames[opcode->name]);
+ ptr = buff + strlen(buff);
+
+ if (opcode->name == CALL)
+ flags = DASMFLAG_STEP_OVER;
+ else if (opcode->name == RET || opcode->name == RETI)
+ flags = DASMFLAG_STEP_OUT;
+
+ for(i=0;i<2;i++)
+ {
+ if(i == 1 && opcode->args[0] != IMP && opcode->args[1] != IMP)
+ {
+ sprintf(ptr, ",");
+ ptr += strlen(ptr);
+ }
+
+ switch(opcode->args[i])
+ {
+ case IMP: break;
+ case A: sprintf(ptr, "A"); break;
+ case X: sprintf(ptr, "X"); break;
+ case Y: sprintf(ptr, "Y"); break;
+ case YA: sprintf(ptr, "YA"); break;
+ case SP: sprintf(ptr, "SP"); break;
+ case PSW: sprintf(ptr, "PSW"); break;
+ case C: sprintf(ptr, "C"); break;
+ case REL: sprintf(ptr, "%04x", ((g_pc + (char)read_8_immediate())&0xffff)); break;
+ case UPAG: sprintf(ptr, "$%02x", read_8_immediate()); break;
+ case IMM: sprintf(ptr, "#$%02x", read_8_immediate()); break;
+ case XI: sprintf(ptr, "(X)"); break;
+ case XII: sprintf(ptr, "(X)+"); break;
+ case YI: sprintf(ptr, "(Y)"); break;
+ case DP: sprintf(ptr, "$%02x", read_8_immediate()); break;
+ case DPX: sprintf(ptr, "$%02x+X", read_8_immediate()); break;
+ case DPY: sprintf(ptr, "$%02x+Y", read_8_immediate()); break;
+ case DPI: sprintf(ptr, "($%02x)", read_8_immediate()); break;
+ case DXI: sprintf(ptr, "($%02x+X)", read_8_immediate()); break;
+ case DIY: sprintf(ptr, "($%02x)+Y", read_8_immediate()); break;
+ case ABS: sprintf(ptr, "$%04x", read_16_immediate()); break;
+ case ABX: sprintf(ptr, "$%04x+X", read_16_immediate()); break;
+ case ABY: sprintf(ptr, "$%04x+Y", read_16_immediate()); break;
+ case AXI: sprintf(ptr, "($%04x+X)", read_16_immediate()); break;
+ case N0: sprintf(ptr, "0"); break;
+ case N1: sprintf(ptr, "1"); break;
+ case N2: sprintf(ptr, "2"); break;
+ case N3: sprintf(ptr, "3"); break;
+ case N4: sprintf(ptr, "4"); break;
+ case N5: sprintf(ptr, "5"); break;
+ case N6: sprintf(ptr, "6"); break;
+ case N7: sprintf(ptr, "7"); break;
+ case N8: sprintf(ptr, "8"); break;
+ case N9: sprintf(ptr, "9"); break;
+ case N10: sprintf(ptr, "10"); break;
+ case N11: sprintf(ptr, "11"); break;
+ case N12: sprintf(ptr, "12"); break;
+ case N13: sprintf(ptr, "13"); break;
+ case N14: sprintf(ptr, "14"); break;
+ case N15: sprintf(ptr, "15"); break;
+ case DP0: sprintf(ptr, "$%02x.0", read_8_immediate()); break;
+ case DP1: sprintf(ptr, "$%02x.1", read_8_immediate()); break;
+ case DP2: sprintf(ptr, "$%02x.2", read_8_immediate()); break;
+ case DP3: sprintf(ptr, "$%02x.3", read_8_immediate()); break;
+ case DP4: sprintf(ptr, "$%02x.4", read_8_immediate()); break;
+ case DP5: sprintf(ptr, "$%02x.5", read_8_immediate()); break;
+ case DP6: sprintf(ptr, "$%02x.6", read_8_immediate()); break;
+ case DP7: sprintf(ptr, "$%02x.7", read_8_immediate()); break;
+ case MEMN:
+ var = read_16_immediate();
+ sprintf(ptr, "%04x.%d", var&0x1fff, var>>13);
+ break;
+ case MEMI:
+ var = read_16_immediate();
+ sprintf(ptr, "/%04x.%d", var&0x1fff, var>>13);
+ break;
+ }
+ ptr += strlen(ptr);
+ }
+ return (g_pc - pc) | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/spc700/spc700ds.h b/src/emu/cpu/spc700/spc700ds.h
new file mode 100644
index 00000000000..a0972449764
--- /dev/null
+++ b/src/emu/cpu/spc700/spc700ds.h
@@ -0,0 +1,27 @@
+#ifndef HEADER__SPC700DS
+#define HEADER__SPC700DS
+/* ======================================================================== */
+/* =============================== COPYRIGHT ============================== */
+/* ======================================================================== */
+/*
+
+Sony SPC700 CPU Emulator V1.0
+
+Copyright (c) 2000 Karl Stenerud
+All rights reserved.
+
+Permission is granted to use this source code for non-commercial purposes.
+To use this code for commercial purposes, you must get permission from the
+author (Karl Stenerud) at karl@higashiyama-unet.ocn.ne.jp.
+
+
+*/
+
+#include "cpuintrf.h"
+
+offs_t spc700_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+
+#define spc700_read_8_disassembler(addr) program_read_byte_8(addr)
+
+
+#endif /* HEADER__SPC700DS */
diff --git a/src/emu/cpu/ssp1610/ssp1610.c b/src/emu/cpu/ssp1610/ssp1610.c
new file mode 100644
index 00000000000..c2b2a22758e
--- /dev/null
+++ b/src/emu/cpu/ssp1610/ssp1610.c
@@ -0,0 +1,869 @@
+/********************************************************************
+ SSP1610 cpu emulator
+ written by Pierpaolo Prazzoli
+
+ Very very preliminary. Still working on it...
+
+*********************************************************************/
+
+#include "debugger.h"
+#include "ssp1610.h"
+#include "osd_cpu.h"
+
+#define READ_OP(addr) (cpu_readop16(addr<<1))
+
+static int ssp1610_ICount;
+
+/* Registers */
+
+enum
+{
+ SSP1610_REG0 = 1, SSP1610_X, SSP1610_Y, SSP1610_A, SSP1610_ST, SSP1610_STACK, SSP1610_PC,
+ SSP1610_P, SSP1610_AL, SSP1610_XST, SSP1610_PL, SSP1610_SRCR, SSP1610_BRCR, SSP1610_BRER,
+ SSP1610_XRD0, SSP1610_XRD1, SSP1610_AE, SSP1610_DIOR, SSP1610_GR22, SSP1610_GR23,
+ SSP1610_EXT0, SSP1610_EXT1, SSP1610_EXT2, SSP1610_EXT3, SSP1610_EXT4, SSP1610_EXT5, SSP1610_EXT6, SSP1610_EXT7
+};
+
+/* Internal registers */
+typedef struct
+{
+ UINT32 regs[32]; // some are 8bits, some 16bits and some 32bits
+
+ UINT16 ppc;
+
+} ssp1610_regs;
+
+static ssp1610_regs ssp1610;
+
+// number of bits of each register
+static const UINT8 regs_width[] =
+{
+ 16, 16, 16, 32, 16, 16, 16, 32, 16, 0, 0, 16, 16, 0, 0, 8,
+ 8, 16, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
+};
+
+// REGISTERS
+
+#define PPC ssp1610.ppc
+
+#define REG0 ssp1610.regs[0]
+#define X ssp1610.regs[1]
+#define Y ssp1610.regs[2]
+#define A ssp1610.regs[3]
+#define ST ssp1610.regs[4]
+//swapped stack and pc (docs wrong...)
+#define STACK ssp1610.regs[5]
+#define PC ssp1610.regs[6]
+#define P ssp1610.regs[7]
+#define AL ssp1610.regs[8]
+// 9
+// 10
+#define XST ssp1610.regs[11]
+#define PL ssp1610.regs[12]
+// 13
+// 14
+#define SRCR ssp1610.regs[15]
+#define BRCR ssp1610.regs[16]
+#define BRER ssp1610.regs[17]
+#define XRD0 ssp1610.regs[18]
+#define XRD1 ssp1610.regs[19]
+#define AE ssp1610.regs[20]
+#define DIOR ssp1610.regs[21]
+#define GR22 ssp1610.regs[22]
+#define GR23 ssp1610.regs[23]
+#define EXT0 ssp1610.regs[24]
+#define EXT1 ssp1610.regs[25]
+#define EXT2 ssp1610.regs[26]
+#define EXT3 ssp1610.regs[27]
+#define EXT4 ssp1610.regs[28]
+#define EXT5 ssp1610.regs[29]
+#define EXT6 ssp1610.regs[30]
+#define EXT7 ssp1610.regs[31]
+
+// CONDITIONS
+
+#define IS_PC 6
+
+// CONTROL bits
+
+
+#define RPL ((ST >> 0) & 7)
+#define RB ((ST >> 3) & 3)
+#define GP0_0 ((ST >> 5) & 1)
+#define GP0_1 ((ST >> 6) & 1)
+#define IE ((ST >> 7) & 1)
+#define OP ((ST >> 8) & 1)
+#define MACS ((ST >> 9) & 1)
+
+
+// FLAG bits
+
+
+#define GPI_0 ((ST >> 10) & 1)
+#define GPI_1 ((ST >> 11) & 1)
+
+
+#define L ((ST >> 12) & 1)
+#define Z ((ST >> 13) & 1)
+#define OV ((ST >> 14) & 1)
+#define N ((ST >> 15) & 1)
+
+#define SET_L(value) ST = (ST & ~(1 << 12)) | ((value) << 12)
+#define SET_Z(value) ST = (ST & ~(1 << 13)) | ((value) << 13)
+#define SET_OV(value) ST = (ST & ~(1 << 14)) | ((value) << 14)
+#define SET_N(value) ST = (ST & ~(1 << 15)) | ((value) << 15)
+
+#define SET_OVSUB(x,y,z)(ST = (ST & ~(1 << 14)) | ((((z) ^ (y)) & ((y) ^ (x)) & 0x80000000) ? (1 << 14): 0))
+
+static void ssp1610_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ REG0 = 0xffff; // read-only register
+}
+
+static void ssp1610_reset(void)
+{
+ ST = 0;
+
+ // latch it from 0 but it's selectable (hard-coded for now)
+ PC = 0x400;
+}
+
+static void ssp1610_exit(void)
+{
+ // nothing to do
+}
+
+static int ssp1610_execute(int cycles)
+{
+ ssp1610_ICount = cycles;
+
+ do
+ {
+ UINT16 op;
+
+ PPC = PC; /* copy PC to previous PC */
+
+ CALL_MAME_DEBUG;
+
+ op = READ_OP(PC);
+
+ PC++;
+
+ switch((op >> 9))
+ {
+ case 0x00:
+
+ if(op == 0) // right?
+ {
+ // nop
+
+ }
+ else if((op & 0xff) == 0x65)
+ {
+ // ret
+
+ }
+ else
+ {
+ // ld d, s
+
+ int s = op & 0xf;
+ int d = (op >> 4) & 0xf;
+
+ // TODO: handle special cases... and complete ALU operations
+
+ if(regs_width[d] == 16 && (regs_width[s] == 16 || regs_width[s] == 8))
+ {
+ ssp1610.regs[d] = ssp1610.regs[s];
+ }
+ else if(regs_width[d] == 16 && regs_width[s] == 32)
+ {
+ ssp1610.regs[d] = (ssp1610.regs[s] >> 16);
+ }
+ else if(regs_width[d] == 32 && (regs_width[s] == 16 || regs_width[s] == 8))
+ {
+ ssp1610.regs[d] = (ssp1610.regs[s] << 16) | (ssp1610.regs[d] & 0xffff);
+ }
+ else if(regs_width[d] == 32 && regs_width[s] == 32)
+ {
+ // wrong! if P is s then only the top 16bits are transferred
+ ssp1610.regs[d] = (ssp1610.regs[s] & 0xffff0000) | (ssp1610.regs[d] & 0xffff);
+ }
+
+ if(d == IS_PC) // if d is PC one more cycle
+ {
+ ssp1610_ICount--;
+ change_pc(PC);
+ }
+
+ }
+
+ break;
+
+ // ld d, (ri) -> probably right
+ case 0x01: // or ldi simm ?
+
+ break;
+
+ // ld (ri), s
+ case 0x02:
+
+ break;
+
+ // ld a, addr
+ case 0x03:
+
+ break;
+
+ // ldi d, imm
+ case 0x04:
+
+
+ break;
+
+ // ld d, ((ri))
+ case 0x05:
+
+ break;
+
+ // ldi (ri), imm
+ case 0x06:
+
+ break;
+
+ // ld addr, a -> almost sure it's this one. some of the 1st 4 bits are set in the code
+ case 0x07: // or ld d, (a) ?
+
+ break;
+
+ // ld d, ri
+ case 0x09:
+
+ break;
+
+ // ld ri, s
+ case 0x0a:
+
+ break;
+
+ // mpys (rj), (ri), b
+ case 0x0b:
+
+ break;
+
+ // ldi ri, simm
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+
+
+ break;
+
+ // sub a, s
+ case 0x10:
+
+ break;
+
+ // sub a, (ri)
+ case 0x11:
+
+ break;
+
+ // mpys s, (ri), b
+ case 0x12:
+
+ break;
+
+ // sub a, adr
+ case 0x13:
+
+ break;
+
+ // subi a, imm
+ case 0x14:
+
+ break;
+
+ // sub a, ((ri))
+ case 0x15:
+
+ break;
+
+ // sub a, ri
+ case 0x19:
+
+ break;
+
+ // mset reg, (ri), s
+ case 0x1a:
+ case 0x1b:
+
+ break;
+
+ // subi simm
+ case 0x1c:
+
+ break;
+
+ // sub a, erij
+ case 0x23:
+
+ break;
+
+ // call cond, addr
+ case 0x24: //f bit?
+
+ break;
+
+ // bra cond, addr
+ case 0x26: //f bit?
+ {
+ UINT16 new_pc = READ_OP(PC);
+ UINT8 f = (op >> 8) & 1;
+ UINT8 cond = 0;
+ PC++;
+
+ switch((op >> 4) & 0xf)
+ {
+ case 0x0:
+ case 0x1:
+ cond = f; // to jump always
+ break;
+
+ case 0x2:
+ case 0x3:
+ // reserved
+ break;
+
+ case 0x4:
+ cond = GPI_0 == 0;
+ break;
+
+ case 0x5:
+ cond = GPI_0 == 1;
+ break;
+
+ case 0x6:
+ cond = GPI_1 == 0;
+ break;
+
+ case 0x7:
+ cond = GPI_1 == 1;
+ break;
+
+ case 0x8:
+ cond = L == 0;
+ break;
+
+ case 0x9:
+ cond = L == 1;
+ break;
+
+ case 0xa:
+ cond = Z == 0;
+ break;
+
+ case 0xb:
+ cond = Z == 1;
+ break;
+
+ case 0xc:
+ cond = OV == 0;
+ break;
+
+ case 0xd:
+ cond = OV == 1;
+ break;
+
+ case 0xe:
+ cond = N == 0;
+ break;
+
+ case 0xf:
+ cond = N == 1;
+ break;
+ }
+
+ if((cond && f) || (!cond && !f))
+ {
+ PPC = PC;
+ PC = new_pc;
+ change_pc(PC);
+ }
+
+ ssp1610_ICount--;
+ }
+
+ break;
+
+
+ case 0x28:
+
+ if(op & 0x100)
+ {
+ // slow imm
+
+ }
+ else
+ {
+ // stop
+
+ }
+
+ break;
+
+ // cmp a, s
+ case 0x30:
+
+ break;
+
+ // cmp a, (ri)
+ case 0x31:
+
+ break;
+
+ // cmp a, adr
+ case 0x33:
+
+ break;
+
+ // cmpi a, imm
+ case 0x34:
+ {
+ UINT16 imm = READ_OP(PC) << 16;
+#if 0
+ UINT64 tmp = (UINT64)A - (UINT64)imm;
+#else
+ // The previous line causes a bus error in Apple's GCC as of 10.4.9:
+ // i686-apple-darwin8-gcc-4.0.1 (GCC) 4.0.1 (Apple Computer, Inc. build 5367)
+ // The gcc included with the Leopard Beta fixes this error.
+ // Using the volatile tempA works around the bus error.
+ volatile UINT32 tempA = A;
+ UINT64 tmp = (UINT64)tempA - (UINT64)imm;
+#endif
+ PC++;
+
+ // right flags?
+
+ SET_L(A < imm);
+ SET_Z((A & 0xffff0000) == imm);
+ SET_N(((INT32) A) < ((INT32)imm));
+ SET_OVSUB(imm,A,tmp);
+
+ // A = saturated value
+ if(OP && OV)
+ {
+ if((INT64)tmp > 0x7fffff)
+ A = 0x7fffff;
+ else if((INT64)tmp < -0x800000)
+ A = 0x800000;
+ }
+ }
+ break;
+
+ // cmp a, ((ri))
+ case 0x35:
+
+ break;
+
+ // cmp a, ri
+ case 0x39:
+
+ break;
+
+ // cmpi simm
+ case 0x3c:
+
+ break;
+
+ // add a, s
+ case 0x40:
+
+ break;
+
+ // add a, (ri)
+ case 0x41:
+
+ break;
+
+ // mpya s, (ri), b
+ case 0x42:
+
+ break;
+
+ // add a, adr
+ case 0x43:
+
+ break;
+
+ // addi a, imm
+ case 0x44:
+
+
+ break;
+
+ // add a, ((ri))
+ case 0x45:
+
+ break;
+
+ // mod cond, op
+ case 0x48:
+
+ break;
+
+ // add a, ri
+ case 0x49:
+
+ break;
+
+ // mod f, op
+ case 0x4a:
+
+ break;
+
+ // mpya (rj), (ri), b
+ case 0x4b:
+
+ break;
+
+ // addi simm
+ case 0x4c: // docs show a wrong opcode value
+
+ break;
+
+ // ld reg, erij
+ case 0x4e:
+ case 0x4f:
+
+ break;
+
+ // and a, s
+ case 0x50:
+
+ break;
+
+ // and a, (ri)
+ case 0x51:
+
+ break;
+
+ // mld s, (ri), b
+ case 0x52:
+ break;
+
+ // and a, adr
+ case 0x53:
+
+ break;
+
+ // andi a, imm
+ case 0x54:
+
+
+ break;
+
+ // and a, ((ri))
+ case 0x55:
+
+ break;
+
+ // and a, ri
+ case 0x59:
+
+ break;
+
+ // mld (rj), (ri), b
+ case 0x5b:
+
+ break;
+
+ // andi simm
+ case 0x5c:
+ A = (A & ~0x00ff0000) | (A & ((op & 0xff) << 16));
+// SET_L();
+ SET_Z(A == 0);
+ SET_N(A >> 31);
+ SET_OV(0);
+ break;
+
+ // ld erij, reg
+ case 0x5e:
+ case 0x5f:
+
+ break;
+
+ // or a, s
+ case 0x60:
+
+ break;
+
+ // or a, (ri)
+ case 0x61:
+
+ break;
+
+ // or a, adr
+ case 0x63:
+
+ break;
+
+ // ori a, imm
+ case 0x64:
+
+ break;
+
+ // or a, ((ri))
+ case 0x65:
+
+ break;
+
+ // or a, ri
+ case 0x69:
+
+ break;
+
+ // ori simm
+ case 0x6c:
+
+ break;
+
+ // eor a, s
+ case 0x70:
+
+ break;
+
+ // eor a, (ri)
+ case 0x71:
+
+ break;
+
+ // eor a, adr
+ case 0x73:
+
+ break;
+
+ // eori a, imm
+ case 0x74:
+
+ break;
+
+ // eor a, ((ri))
+ case 0x75:
+
+ break;
+
+ // eor a, ri
+ case 0x79:
+
+ break;
+
+ // eori simm
+ case 0x7c:
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ ssp1610_ICount--;
+
+ } while( ssp1610_ICount > 0 );
+
+ return cycles - ssp1610_ICount;
+}
+
+static void ssp1610_get_context(void *regs)
+{
+ /* copy the context */
+ if( regs )
+ *(ssp1610_regs *)regs = ssp1610;
+}
+
+static void ssp1610_set_context(void *regs)
+{
+ /* copy the context */
+ if (regs)
+ ssp1610 = *(ssp1610_regs *)regs;
+}
+
+#ifdef MAME_DEBUG
+static offs_t ssp1610_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return dasm_ssp1610( buffer, pc, oprom);
+}
+#endif /* MAME_DEBUG */
+
+#if (HAS_SSP1610)
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void ssp1610_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+
+// case CPUINFO_INT_REGISTER + SSP1610_REG0: REG0 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_X: X = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_Y: Y = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_A: A = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_ST: ST = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_STACK: STACK = info->i; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SSP1610_PC: PC = info->i; change_pc(PC); break;
+ case CPUINFO_INT_REGISTER + SSP1610_P: P = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_AL: AL = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_XST: XST = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_PL: PL = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_SRCR: SRCR = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_BRCR: BRCR = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_BRER: BRER = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_XRD0: XRD0 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_XRD1: XRD1 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_AE: AE = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_DIOR: DIOR = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_GR22: GR22 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_GR23: GR23 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT0: EXT0 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT1: EXT1 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT2: EXT2 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT3: EXT3 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT4: EXT4 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT5: EXT5 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT6: EXT6 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT7: EXT7 = info->i; break;
+
+// case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+// case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+// case CPUINFO_INT_INPUT_STATE + 2: set_irq_line(2, info->i); break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void ssp1610_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ssp1610_regs); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 3; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: /* not implemented */ break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+
+ case CPUINFO_INT_REGISTER + SSP1610_REG0: info->i = REG0; break;
+ case CPUINFO_INT_REGISTER + SSP1610_X: info->i = X; break;
+ case CPUINFO_INT_REGISTER + SSP1610_Y: info->i = Y; break;
+ case CPUINFO_INT_REGISTER + SSP1610_A: info->i = A; break;
+ case CPUINFO_INT_REGISTER + SSP1610_ST: info->i = ST; break;
+ case CPUINFO_INT_REGISTER + SSP1610_STACK: info->i = STACK; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SSP1610_PC: info->i = PC; change_pc(PC); break;
+ case CPUINFO_INT_REGISTER + SSP1610_P: info->i = P; break;
+ case CPUINFO_INT_REGISTER + SSP1610_AL: info->i = AL; break;
+ case CPUINFO_INT_REGISTER + SSP1610_XST: info->i = XST; break;
+ case CPUINFO_INT_REGISTER + SSP1610_PL: info->i = PL; break;
+ case CPUINFO_INT_REGISTER + SSP1610_SRCR: info->i = SRCR; break;
+ case CPUINFO_INT_REGISTER + SSP1610_BRCR: info->i = BRCR; break;
+ case CPUINFO_INT_REGISTER + SSP1610_BRER: info->i = BRER; break;
+ case CPUINFO_INT_REGISTER + SSP1610_XRD0: info->i = XRD0; break;
+ case CPUINFO_INT_REGISTER + SSP1610_XRD1: info->i = XRD1; break;
+ case CPUINFO_INT_REGISTER + SSP1610_AE: info->i = AE; break;
+ case CPUINFO_INT_REGISTER + SSP1610_DIOR: info->i = DIOR; break;
+ case CPUINFO_INT_REGISTER + SSP1610_GR22: info->i = GR22; break;
+ case CPUINFO_INT_REGISTER + SSP1610_GR23: info->i = GR23; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT0: info->i = EXT0; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT1: info->i = EXT1; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT2: info->i = EXT2; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT3: info->i = EXT3; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT4: info->i = EXT4; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT5: info->i = EXT5; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT6: info->i = EXT6; break;
+ case CPUINFO_INT_REGISTER + SSP1610_EXT7: info->i = EXT7; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = ssp1610_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ssp1610_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ssp1610_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = ssp1610_init; break;
+ case CPUINFO_PTR_RESET: info->reset = ssp1610_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = ssp1610_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = ssp1610_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ssp1610_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ssp1610_ICount; break;
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = 0; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO: info->internal_map = 0; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "SSP1610 CPU"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.1"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Pierpaolo Prazzoli"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "_flags_");
+ break;
+
+ case CPUINFO_STR_REGISTER + SSP1610_REG0: sprintf(info->s, "REG0 :%04X", REG0); break;
+ case CPUINFO_STR_REGISTER + SSP1610_X: sprintf(info->s, "X :%04X", X); break;
+ case CPUINFO_STR_REGISTER + SSP1610_Y: sprintf(info->s, "Y :%04X", Y); break;
+ case CPUINFO_STR_REGISTER + SSP1610_A: sprintf(info->s, "A :%08X", A); break;
+ case CPUINFO_STR_REGISTER + SSP1610_ST: sprintf(info->s, "ST :%04X", ST); break;
+ case CPUINFO_STR_REGISTER + SSP1610_STACK: sprintf(info->s, "STACK :%04X", STACK); break;
+ case CPUINFO_STR_REGISTER + SSP1610_PC: sprintf(info->s, "PC :%04X", PC); break;
+ case CPUINFO_STR_REGISTER + SSP1610_P: sprintf(info->s, "P :%08X", P); break;
+ case CPUINFO_STR_REGISTER + SSP1610_AL: sprintf(info->s, "AL :%04X", AL); break;
+ case CPUINFO_STR_REGISTER + SSP1610_XST: sprintf(info->s, "XST :%04X", XST); break;
+ case CPUINFO_STR_REGISTER + SSP1610_PL: sprintf(info->s, "PL :%04X", PL); break;
+ case CPUINFO_STR_REGISTER + SSP1610_SRCR: sprintf(info->s, "SRCR :%02X", SRCR); break;
+ case CPUINFO_STR_REGISTER + SSP1610_BRCR: sprintf(info->s, "BRCR :%02X", BRCR); break;
+ case CPUINFO_STR_REGISTER + SSP1610_BRER: sprintf(info->s, "BRER :%04X", BRER); break;
+ case CPUINFO_STR_REGISTER + SSP1610_XRD0: sprintf(info->s, "XRD0 :%02X", XRD0); break;
+ case CPUINFO_STR_REGISTER + SSP1610_XRD1: sprintf(info->s, "XRD1 :%02X", XRD1); break;
+ case CPUINFO_STR_REGISTER + SSP1610_AE: sprintf(info->s, "AE :%02X", AE); break;
+ case CPUINFO_STR_REGISTER + SSP1610_DIOR: sprintf(info->s, "DIOR :%04X", DIOR); break;
+ case CPUINFO_STR_REGISTER + SSP1610_GR22: sprintf(info->s, "GR22 :%04X", GR22); break;
+ case CPUINFO_STR_REGISTER + SSP1610_GR23: sprintf(info->s, "GR23 :%04X", GR23); break;
+ case CPUINFO_STR_REGISTER + SSP1610_EXT0: sprintf(info->s, "EXT0 :%04X", EXT0); break;
+ case CPUINFO_STR_REGISTER + SSP1610_EXT1: sprintf(info->s, "EXT1 :%04X", EXT1); break;
+ case CPUINFO_STR_REGISTER + SSP1610_EXT2: sprintf(info->s, "EXT2 :%04X", EXT2); break;
+ case CPUINFO_STR_REGISTER + SSP1610_EXT3: sprintf(info->s, "EXT3 :%04X", EXT3); break;
+ case CPUINFO_STR_REGISTER + SSP1610_EXT4: sprintf(info->s, "EXT4 :%04X", EXT4); break;
+ case CPUINFO_STR_REGISTER + SSP1610_EXT5: sprintf(info->s, "EXT5 :%04X", EXT5); break;
+ case CPUINFO_STR_REGISTER + SSP1610_EXT6: sprintf(info->s, "EXT6 :%04X", EXT6); break;
+ case CPUINFO_STR_REGISTER + SSP1610_EXT7: sprintf(info->s, "EXT7 :%04X", EXT7); break;
+
+ }
+}
+#endif
diff --git a/src/emu/cpu/ssp1610/ssp1610.h b/src/emu/cpu/ssp1610/ssp1610.h
new file mode 100644
index 00000000000..fe31d4d5cad
--- /dev/null
+++ b/src/emu/cpu/ssp1610/ssp1610.h
@@ -0,0 +1,16 @@
+#ifndef SSP1610_H
+#define SSP1610_H
+
+#include "cpuintrf.h"
+
+/* Functions */
+
+#if (HAS_SSP1610)
+void e116t_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#ifdef MAME_DEBUG
+extern unsigned dasm_ssp1610(char *buffer, unsigned pc, const UINT8 *oprom);
+#endif
+
+#endif /* SSP1610_H */
diff --git a/src/emu/cpu/ssp1610/ssp1610d.c b/src/emu/cpu/ssp1610/ssp1610d.c
new file mode 100644
index 00000000000..a22a16e4e7f
--- /dev/null
+++ b/src/emu/cpu/ssp1610/ssp1610d.c
@@ -0,0 +1,532 @@
+/*
+
+ SSP1610 disassembler
+ written by Pierpaolo Prazzoli
+
+*/
+
+#include <math.h>
+#include "debugger.h"
+#include "cpuintrf.h"
+
+
+static const char* reg[] =
+{
+ "-", "X", "Y", "A", "ST", "STACK", "PC", "P", "AL", "?", "?", "XST", "PL", "?", "?", "SRCR", "BRCR", "BRER",
+ "XRD0", "XRD1", "AE", "DIOR", "GR22", "GR23", "EXT0", "EXT1", "EXT2", "EXT3", "EXT4", "EXT5", "EXT6", "EXT7"
+};
+
+static const char* rij[] =
+{
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"
+};
+
+static const char* erij[] =
+{
+ "er0", "er1", "er2", "er3", "er4", "er5", "er6", "er7"
+};
+
+static const char* modifier[] =
+{
+ "", "+!", "-", "+"
+};
+
+static const char* cond[] =
+{
+ "always", "always", "RESERVED", "RESERVED", "gpi0=0", "gpi0=1", "gpi1=0", "gpi1=1", "l=0", "l=1", "z=0", "z=1", "ov=0", "ov=1", "n=0", "n=1",
+ "diof=0", "diof=1", "gpi2=0", "gpi2=1", "gpi3=0", "gpi3=1", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED"
+};
+
+static const char* acc_op[] =
+{
+ "ror", "rol", "shr", "shl", "inc", "dec", "neg", "abs"
+};
+
+// pag. 81 uses different addresses!
+static const char* flag_op[] =
+{
+ "?", "?", "resl", "setl", "resie", "setie", "?", "?", "resop", "setop", "?", "?", "?", "?", "res", "set"
+};
+
+
+static const char* st_mod[] =
+{
+ "macs", "rpl", "gpo", "rb", "gpo0", "gpo1", "gpo2", "gpo3", "wte", "diof", "bre", "reserved", "reserved", "reserved", "reserved", "reserved"
+};
+
+
+#define BIT_B ((op >> 8) & 1)
+#define RIJ rij[(BIT_B << 2) + (op & 3)]
+#define RI(i) rij[(i) & 3]
+#define RJ(i) rij[((i) & 3) + 4]
+#define MODIFIER(i) modifier[(i) & 3]
+#define MODIFIER_LOW MODIFIER(op >> 2)
+#define MODIFIER_HIGH MODIFIER(op >> 6)
+#define COND cond[(op >> 4) & 0xf]
+
+static offs_t base_pc;
+static const UINT8 *base_oprom;
+#define READ_OP_DASM(p) ((base_oprom[(p) - base_pc] << 8) | base_oprom[(p) + 1 - base_pc])
+
+//TODO:
+// - add special Short-form Direct Addressing for r3 and r7
+// - support DASM flags
+
+unsigned dasm_ssp1610(char *buffer, unsigned pc, const UINT8 *oprom)
+{
+ UINT16 op;
+ UINT8 op_num;
+ int size = 1;
+ int flags = 0;
+
+ base_pc = pc;
+ base_oprom = oprom;
+
+ op = READ_OP_DASM(pc);
+ op_num = op >> 9;
+
+ // .....overlapping opcodes....
+ //
+ // ldi simm ?
+ // ld d, (a) ?
+ // mset reg, (ri), b ? overlaps other opcodes
+ // mset (rj), (ri), b ?
+ // repb simm/srcr, imm ?
+ // reps simm/srcr ?
+ // subi (rij)/erij/reg,imm,t ?
+ /*
+ // mod x, nimm, n
+ case 0x11:
+ sprintf(buffer, "mod x, %X, %d", op & 0xf, (op >> 4) & 1);
+ break;
+
+ // mset (rj), (ri), ss
+ case 0x18, 0x19: // ss order?
+ sprintf(buffer, "mset (%s%s), (%s%s), %d%d", RJ(op >> 5), MODIFIER(op >> 7), RI(op), MODIFIER_LOW, (op >> 9) & 1, (op >> 4) & 1);
+ break;
+
+ // mod st, bs, nimm
+ case 0x28: //? docs say 0x24
+ sprintf(buffer, "mod st, %s, %x", st_mod[(op >> 5) & 0xf], op & 0xf);
+ break;
+ */
+
+ switch( op_num )
+ {
+
+ //????????????????????
+
+ // ldi simm
+// case 0x08:
+// sprintf(buffer, "ldi %X", op & 0xff);
+// break;
+
+ // maybe
+ // mod st, bs, nimm
+ case 0x25: //? docs say 0x24
+ sprintf(buffer, "mod st, %s, %x", st_mod[(op >> 5) & 0xf], op & 0xf);
+ break;
+
+ //????????????????????
+
+ case 0x00:
+
+ if(op == 0) // right?
+ {
+ // nop
+ sprintf(buffer, "nop");
+ }
+ else if((op & 0xff) == 0x65)
+ {
+ // ret
+ sprintf(buffer, "ret");
+ }
+ else
+ {
+ // ld d, s
+ sprintf(buffer, "ld %s, %s", reg[(op >> 4) & 0xf], reg[0xf]);
+ }
+
+ break;
+
+ // ld d, (ri) -> probably right
+ case 0x01: // or ldi simm ?
+ sprintf(buffer, "ld %s, (%s%s)", reg[(op >> 4) & 0xf], RIJ, MODIFIER_LOW);
+ break;
+
+ // ld (ri), s
+ case 0x02:
+ sprintf(buffer, "ld (%s%s), %s", RIJ, MODIFIER_LOW, reg[(op >> 4) & 0xf]);
+ break;
+
+ // ld a, addr
+ case 0x03:
+ sprintf(buffer, "ld a, %X", op & 0x1ff);
+ break;
+
+ // ldi d, imm
+ case 0x04:
+ sprintf(buffer, "ld %s, %X", reg[(op >> 4) & 0xf], READ_OP_DASM(pc+2));
+ size = 2;
+ break;
+
+ // ld d, ((ri))
+ case 0x05:
+ sprintf(buffer, "ld %s, ((%s%s))", reg[(op >> 4) & 0xf], RIJ, MODIFIER_LOW);
+ break;
+
+ // ldi (ri), imm
+ case 0x06:
+ sprintf(buffer, "ld (%s%s), %X", RIJ, MODIFIER_LOW, READ_OP_DASM(pc+2));
+ size = 2;
+ break;
+
+ // ld addr, a -> almost sure it's this one. some of the 1st 4 bits are set in the code
+ case 0x07: // or ld d, (a) ?
+ sprintf(buffer, "ld %X, a", op & 0x1ff);
+ break;
+
+ // ld d, ri
+ case 0x09:
+ sprintf(buffer, "ld %s, %s%s", reg[(op >> 4) & 0xf], RIJ, MODIFIER_LOW);
+ break;
+
+ // ld ri, s
+ case 0x0a:
+ sprintf(buffer, "ld %s%s, %s", RIJ, MODIFIER_LOW, reg[(op >> 4) & 0xf]);
+ break;
+
+ // mpys (rj), (ri), b
+ case 0x0b:
+ sprintf(buffer, "mpya (%s%s), (%s%s), %d", RJ(op >> 4), MODIFIER_HIGH, RI(op), MODIFIER_LOW, BIT_B);
+ break;
+
+ // ldi ri, simm
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ sprintf(buffer, "ldi %s, %X", rij[(op >> 7) & 7], op & 0xff);
+ break;
+
+ // sub a, s
+ case 0x10:
+ sprintf(buffer, "sub a, %s", reg[op & 0xf]);
+ break;
+
+ // sub a, (ri)
+ case 0x11:
+ sprintf(buffer, "sub a, (%s%s)", RIJ, MODIFIER_LOW);
+ break;
+
+ // mpys s, (ri), b
+ case 0x12:
+ sprintf(buffer, "mpya %s, (%s%s), %d", reg[(op >> 4) & 0xf], RI(op), MODIFIER_LOW, BIT_B);
+ break;
+
+ // sub a, adr
+ case 0x13:
+ sprintf(buffer, "sub a, %X", op & 0xff);
+ break;
+
+ // subi a, imm
+ case 0x14:
+ sprintf(buffer, "subi a, %X", READ_OP_DASM(pc+2));
+ size = 2;
+ break;
+
+ // sub a, ((ri))
+ case 0x15:
+ sprintf(buffer, "sub a, ((%s%s))", RIJ, MODIFIER_LOW);
+ break;
+
+ // sub a, ri
+ case 0x19:
+ sprintf(buffer, "sub a, %s%s", RIJ, MODIFIER_LOW);
+ break;
+
+ // mset reg, (ri), s
+ case 0x1a:
+ case 0x1b:
+ sprintf(buffer, "mset %s, (%s%s), %d", reg[(op >> 5) & 0x1f], RI(op), MODIFIER_LOW, (op >> 4) & 1);
+ break;
+
+ // subi simm
+ case 0x1c:
+ sprintf(buffer, "subi %X", op & 0xff);
+ break;
+
+ // sub a, erij
+ case 0x23:
+ sprintf(buffer, "sub a, %s%s", erij[(op >> 2) & 7], MODIFIER(op));
+ break;
+
+ // call cond, addr
+ case 0x24: //f bit?
+ sprintf(buffer, "call %s, %X", COND, READ_OP_DASM(pc+2));
+ size = 2;
+ break;
+
+ // bra cond, addr
+ case 0x26: //f bit?
+ sprintf(buffer, "bra %s, %X", COND, READ_OP_DASM(pc+2));
+ size = 2;
+ break;
+
+
+ case 0x28:
+
+ if(op & 0x100)
+ {
+ // slow imm
+ sprintf(buffer, "slow %X", op & 0xf);
+ }
+ else
+ {
+ // stop
+ sprintf(buffer, "stop");
+ }
+
+ break;
+
+ // cmp a, s
+ case 0x30:
+ sprintf(buffer, "cmp a, %s", reg[op & 0xf]);
+ break;
+
+ // cmp a, (ri)
+ case 0x31:
+ sprintf(buffer, "cmp a, (%s%s)", RIJ, MODIFIER_LOW);
+ break;
+
+ // cmp a, adr
+ case 0x33:
+ sprintf(buffer, "cmp a, %X", op & 0xff);
+ break;
+
+ // cmpi a, imm
+ case 0x34:
+ sprintf(buffer, "cmpi a, %X", READ_OP_DASM(pc+2));
+ size = 2;
+ break;
+
+ // cmp a, ((ri))
+ case 0x35:
+ sprintf(buffer, "cmp a, ((%s%s))", RIJ, MODIFIER_LOW);
+ break;
+
+ // cmp a, ri
+ case 0x39:
+ sprintf(buffer, "cmp a, %s%s", RIJ, MODIFIER_LOW);
+ break;
+
+ // cmpi simm
+ case 0x3c:
+ sprintf(buffer, "cmpi %X", op & 0xff);
+ break;
+
+ // add a, s
+ case 0x40:
+ sprintf(buffer, "add a, %s", reg[op & 0xf]);
+ break;
+
+ // add a, (ri)
+ case 0x41:
+ sprintf(buffer, "add a, (%s%s)", RIJ, MODIFIER_LOW);
+ break;
+
+ // mpya s, (ri), b
+ case 0x42:
+ sprintf(buffer, "mpya %s, (%s%s), %d", reg[(op >> 4) & 0xf], RI(op), MODIFIER_LOW, BIT_B);
+ break;
+
+ // add a, adr
+ case 0x43:
+ sprintf(buffer, "add a, %X", op & 0xff);
+ break;
+
+ // addi a, imm
+ case 0x44:
+ //sprintf(buffer, "addi a, %X", READ_OP_DASM(pc+2));
+ size = 2;
+
+ if(op & 0x1ff)
+ sprintf(buffer, "addi a, %X (CHECK ME!)", READ_OP_DASM(pc+2));
+ else
+ sprintf(buffer, "addi a, %X", READ_OP_DASM(pc+2));
+
+ break;
+
+ // add a, ((ri))
+ case 0x45:
+ sprintf(buffer, "add a, ((%s%s))", RIJ, MODIFIER_LOW);
+ break;
+
+ // mod cond, op
+ case 0x48:
+ sprintf(buffer, "mod %s, %s", COND, acc_op[op & 7]);
+ break;
+
+ // add a, ri
+ case 0x49:
+ sprintf(buffer, "add a, %s%s", RIJ, MODIFIER_LOW);
+ break;
+
+ // mod f, op
+ case 0x4a:
+ sprintf(buffer, "%s", flag_op[op & 0xf]);
+ break;
+
+ // mpya (rj), (ri), b
+ case 0x4b:
+ sprintf(buffer, "mpya (%s%s), (%s%s), %d", RJ(op >> 4), MODIFIER_HIGH, RI(op), MODIFIER_LOW, BIT_B);
+ break;
+
+ // addi simm
+ case 0x4c: // docs show a wrong opcode value
+ sprintf(buffer, "addi %X", op & 0xff);
+ break;
+
+ // ld reg, erij
+ case 0x4e:
+ case 0x4f:
+ sprintf(buffer, "ld %s, %s%s", reg[(op >> 5) & 0x1f], erij[(op >> 2) & 7], MODIFIER(op));
+ break;
+
+ // and a, s
+ case 0x50:
+ sprintf(buffer, "and a, %s", reg[op & 0xf]);
+ break;
+
+ // and a, (ri)
+ case 0x51:
+ sprintf(buffer, "and a, (%s%s)", RIJ, MODIFIER_LOW);
+ break;
+
+ // mld s, (ri), b
+ case 0x52:
+ sprintf(buffer, "mld %s, (%s%s), %d", reg[(op >> 4) & 0xf], RI(op), MODIFIER_LOW, BIT_B);
+ break;
+
+ // and a, adr
+ case 0x53:
+ sprintf(buffer, "and a, %X", op & 0xff);
+ break;
+
+ // andi a, imm
+ case 0x54:
+// sprintf(buffer, "andi a, %X", READ_OP_DASM(pc+2));
+ size = 2;
+
+ if(op & 0x1ff)
+ sprintf(buffer, "andi a, %X (CHECK ME!)", READ_OP_DASM(pc+2));
+ else
+ sprintf(buffer, "andi a, %X", READ_OP_DASM(pc+2));
+
+ break;
+
+ // and a, ((ri))
+ case 0x55:
+ sprintf(buffer, "and a, ((%s%s))", RIJ, MODIFIER_LOW);
+ break;
+
+ // and a, ri
+ case 0x59:
+ sprintf(buffer, "and a, %s%s", RIJ, MODIFIER_LOW);
+ break;
+
+ // mld (rj), (ri), b
+ case 0x5b:
+ sprintf(buffer, "mld (%s%s), (%s%s), %d", RJ(op >> 4), MODIFIER_HIGH, RI(op), MODIFIER_LOW, BIT_B);
+ break;
+
+ // andi simm
+ case 0x5c:
+ sprintf(buffer, "andi %X", op & 0xff);
+ break;
+
+ // ld erij, reg
+ case 0x5e:
+ case 0x5f:
+ sprintf(buffer, "ld %s%s, %s", erij[(op >> 2) & 7], MODIFIER(op), reg[(op >> 5) & 0x1f]);
+ break;
+
+ // or a, s
+ case 0x60:
+ sprintf(buffer, "or a, %s", reg[op & 0xf]);
+ break;
+
+ // or a, (ri)
+ case 0x61:
+ sprintf(buffer, "or a, (%s%s)", RIJ, MODIFIER_LOW);
+ break;
+
+ // or a, adr
+ case 0x63:
+ sprintf(buffer, "or a, %X", op & 0xff);
+ break;
+
+ // ori a, imm
+ case 0x64:
+ sprintf(buffer, "ori a, %X", READ_OP_DASM(pc+2));
+ size = 2;
+ break;
+
+ // or a, ((ri))
+ case 0x65:
+ sprintf(buffer, "or a, ((%s%s))", RIJ, MODIFIER_LOW);
+ break;
+
+ // or a, ri
+ case 0x69:
+ sprintf(buffer, "or a, %s%s", RIJ, MODIFIER_LOW);
+ break;
+
+ // ori simm
+ case 0x6c:
+ sprintf(buffer, "ori %X", op & 0xff);
+ break;
+
+ // eor a, s
+ case 0x70:
+ sprintf(buffer, "eor a, %s", reg[op & 0xf]);
+ break;
+
+ // eor a, (ri)
+ case 0x71:
+ sprintf(buffer, "eor a, (%s%s)", RIJ, MODIFIER_LOW);
+ break;
+
+ // eor a, adr
+ case 0x73:
+ sprintf(buffer, "eor a, %X", op & 0xff);
+ break;
+
+ // eori a, imm
+ case 0x74:
+ sprintf(buffer, "eori a, %X", READ_OP_DASM(pc+2));
+ size = 2;
+ break;
+
+ // eor a, ((ri))
+ case 0x75:
+ sprintf(buffer, "eor a, ((%s%s))", RIJ, MODIFIER_LOW);
+ break;
+
+ // eor a, ri
+ case 0x79:
+ sprintf(buffer, "eor a, %s%s", RIJ, MODIFIER_LOW);
+ break;
+
+ // eori simm
+ case 0x7c:
+ sprintf(buffer, "eori %X", op & 0xff);
+ break;
+
+ default:
+ sprintf(buffer, "OP = %02X",op_num);
+ break;
+ }
+
+ return size | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/t11/t11.c b/src/emu/cpu/t11/t11.c
new file mode 100644
index 00000000000..a80425787d8
--- /dev/null
+++ b/src/emu/cpu/t11/t11.c
@@ -0,0 +1,540 @@
+/*** t11: Portable DEC T-11 emulator ******************************************
+
+ Copyright (C) Aaron Giles 1998-2001
+
+ System dependencies: long must be at least 32 bits
+ word must be 16 bit unsigned int
+ byte must be 8 bit unsigned int
+ long must be more than 16 bits
+ arrays up to 65536 bytes must be supported
+ machine must be twos complement
+
+*****************************************************************************/
+
+#include "debugger.h"
+#include "t11.h"
+
+
+/*************************************
+ *
+ * Internal state representation
+ *
+ *************************************/
+
+typedef struct
+{
+ PAIR ppc; /* previous program counter */
+ PAIR reg[8];
+ PAIR psw;
+ UINT16 op;
+ UINT16 initial_pc;
+ UINT8 wait_state;
+ UINT8 irq_state;
+ INT32 interrupt_cycles;
+ int (*irq_callback)(int irqline);
+} t11_Regs;
+
+static t11_Regs t11;
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+static int t11_ICount;
+
+
+
+/*************************************
+ *
+ * Macro shortcuts
+ *
+ *************************************/
+
+/* registers of various sizes */
+#define REGD(x) t11.reg[x].d
+#define REGW(x) t11.reg[x].w.l
+#define REGB(x) t11.reg[x].b.l
+
+/* PC, SP, and PSW definitions */
+#define SP REGW(6)
+#define PC REGW(7)
+#define SPD REGD(6)
+#define PCD REGD(7)
+#define PSW t11.psw.b.l
+
+
+
+/*************************************
+ *
+ * Low-level memory operations
+ *
+ *************************************/
+
+INLINE int ROPCODE(void)
+{
+ int val = cpu_readop16(PC);
+ PC += 2;
+ return val;
+}
+
+
+INLINE int RBYTE(int addr)
+{
+ return T11_RDMEM(addr);
+}
+
+
+INLINE void WBYTE(int addr, int data)
+{
+ T11_WRMEM(addr, data);
+}
+
+
+INLINE int RWORD(int addr)
+{
+ return T11_RDMEM_WORD(addr & 0xfffe);
+}
+
+
+INLINE void WWORD(int addr, int data)
+{
+ T11_WRMEM_WORD(addr & 0xfffe, data);
+}
+
+
+
+/*************************************
+ *
+ * Low-level stack operations
+ *
+ *************************************/
+
+INLINE void PUSH(int val)
+{
+ SP -= 2;
+ WWORD(SPD, val);
+}
+
+
+INLINE int POP(void)
+{
+ int result = RWORD(SPD);
+ SP += 2;
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Flag definitions and operations
+ *
+ *************************************/
+
+/* flag definitions */
+#define CFLAG 1
+#define VFLAG 2
+#define ZFLAG 4
+#define NFLAG 8
+
+/* extracts flags */
+#define GET_C (PSW & CFLAG)
+#define GET_V (PSW & VFLAG)
+#define GET_Z (PSW & ZFLAG)
+#define GET_N (PSW & NFLAG)
+
+/* clears flags */
+#define CLR_C (PSW &= ~CFLAG)
+#define CLR_V (PSW &= ~VFLAG)
+#define CLR_Z (PSW &= ~ZFLAG)
+#define CLR_N (PSW &= ~NFLAG)
+
+/* sets flags */
+#define SET_C (PSW |= CFLAG)
+#define SET_V (PSW |= VFLAG)
+#define SET_Z (PSW |= ZFLAG)
+#define SET_N (PSW |= NFLAG)
+
+
+
+/*************************************
+ *
+ * Interrupt handling
+ *
+ *************************************/
+
+struct irq_table_entry
+{
+ UINT8 priority;
+ UINT8 vector;
+};
+
+static const struct irq_table_entry irq_table[] =
+{
+ { 0<<5, 0x00 },
+ { 4<<5, 0x38 },
+ { 4<<5, 0x34 },
+ { 4<<5, 0x30 },
+ { 5<<5, 0x5c },
+ { 5<<5, 0x58 },
+ { 5<<5, 0x54 },
+ { 5<<5, 0x50 },
+ { 6<<5, 0x4c },
+ { 6<<5, 0x48 },
+ { 6<<5, 0x44 },
+ { 6<<5, 0x40 },
+ { 7<<5, 0x6c },
+ { 7<<5, 0x68 },
+ { 7<<5, 0x64 },
+ { 7<<5, 0x60 }
+};
+
+static void t11_check_irqs(void)
+{
+ const struct irq_table_entry *irq = &irq_table[t11.irq_state & 15];
+ int priority = PSW & 0xe0;
+
+ /* compare the priority of the interrupt to the PSW */
+ if (irq->priority > priority)
+ {
+ /* get the priority of this interrupt */
+ int new_pc = RWORD(irq->vector);
+ int new_psw = RWORD(irq->vector + 2);
+
+ /* call the callback */
+ if (t11.irq_callback)
+ {
+ int vector = 0;
+
+ if (t11.irq_state & 8) vector = 3;
+ else if (t11.irq_state & 4) vector = 2;
+ else if (t11.irq_state & 2) vector = 1;
+ (*t11.irq_callback)(vector);
+ }
+
+ /* kludge for 720 - fix me! */
+ if (new_pc == 0)
+ return;
+
+ /* push the old state, set the new one */
+ PUSH(PSW);
+ PUSH(PC);
+ PCD = new_pc;
+ PSW = new_psw;
+ change_pc(PC);
+ t11_check_irqs();
+
+ /* count cycles and clear the WAIT flag */
+ t11.interrupt_cycles += 114;
+ t11.wait_state = 0;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Core opcodes
+ *
+ *************************************/
+
+/* includes the static function prototypes and the master opcode table */
+#include "t11table.c"
+
+/* includes the actual opcode implementations */
+#include "t11ops.c"
+
+
+
+/*************************************
+ *
+ * Fetch current context into buffer
+ *
+ *************************************/
+
+static void t11_get_context(void *dst)
+{
+ if (dst)
+ *(t11_Regs *)dst = t11;
+}
+
+
+
+/*************************************
+ *
+ * Retrieve context from buffer
+ *
+ *************************************/
+
+static void t11_set_context(void *src)
+{
+ if (src)
+ t11 = *(t11_Regs *)src;
+ change_pc(PC);
+ t11_check_irqs();
+}
+
+
+
+/*************************************
+ *
+ * Low-level initialization/cleanup
+ *
+ *************************************/
+
+static void t11_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ static const UINT16 initial_pc[] =
+ {
+ 0xc000, 0x8000, 0x4000, 0x2000,
+ 0x1000, 0x0000, 0xf600, 0xf400
+ };
+ const struct t11_setup *setup = config;
+
+ t11.initial_pc = initial_pc[setup->mode >> 13];
+ t11.irq_callback = irqcallback;
+
+ state_save_register_item("t11", index, t11.ppc.w.l);
+ state_save_register_item("t11", index, t11.reg[0].w.l);
+ state_save_register_item("t11", index, t11.reg[1].w.l);
+ state_save_register_item("t11", index, t11.reg[2].w.l);
+ state_save_register_item("t11", index, t11.reg[3].w.l);
+ state_save_register_item("t11", index, t11.reg[4].w.l);
+ state_save_register_item("t11", index, t11.reg[5].w.l);
+ state_save_register_item("t11", index, t11.reg[6].w.l);
+ state_save_register_item("t11", index, t11.reg[7].w.l);
+ state_save_register_item("t11", index, t11.psw.w.l);
+ state_save_register_item("t11", index, t11.op);
+ state_save_register_item("t11", index, t11.wait_state);
+ state_save_register_item("t11", index, t11.irq_state);
+ state_save_register_item("t11", index, t11.interrupt_cycles);
+}
+
+
+static void t11_exit(void)
+{
+ /* nothing to do */
+}
+
+
+
+/*************************************
+ *
+ * CPU reset
+ *
+ *************************************/
+
+static void t11_reset(void)
+{
+ /* initial SP is 376 octal, or 0xfe */
+ SP = 0x00fe;
+
+ /* initial PC comes from the setup word */
+ PC = t11.initial_pc;
+ change_pc(PC);
+
+ /* PSW starts off at highest priority */
+ PSW = 0xe0;
+
+ /* initialize the IRQ state */
+ t11.irq_state = 0;
+
+ /* reset the remaining state */
+ REGD(0) = 0;
+ REGD(1) = 0;
+ REGD(2) = 0;
+ REGD(3) = 0;
+ REGD(4) = 0;
+ REGD(5) = 0;
+ t11.ppc.d = 0;
+ t11.wait_state = 0;
+ t11.interrupt_cycles = 0;
+}
+
+
+
+/*************************************
+ *
+ * Interrupt handling
+ *
+ *************************************/
+
+static void set_irq_line(int irqline, int state)
+{
+ /* set the appropriate bit */
+ if (state == CLEAR_LINE)
+ t11.irq_state &= ~(1 << irqline);
+ else
+ t11.irq_state |= 1 << irqline;
+
+ /* recheck for interrupts */
+ t11_check_irqs();
+}
+
+
+
+/*************************************
+ *
+ * Core execution
+ *
+ *************************************/
+
+static int t11_execute(int cycles)
+{
+ t11_ICount = cycles;
+ t11_ICount -= t11.interrupt_cycles;
+ t11.interrupt_cycles = 0;
+
+ if (t11.wait_state)
+ {
+ t11_ICount = 0;
+ goto getout;
+ }
+
+ do
+ {
+ t11.ppc = t11.reg[7]; /* copy PC to previous PC */
+
+ CALL_MAME_DEBUG;
+
+ t11.op = ROPCODE();
+ (*opcode_table[t11.op >> 3])();
+
+ } while (t11_ICount > 0);
+
+getout:
+
+ t11_ICount -= t11.interrupt_cycles;
+ t11.interrupt_cycles = 0;
+
+ return cycles - t11_ICount;
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void t11_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + T11_IRQ0: set_irq_line(T11_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + T11_IRQ1: set_irq_line(T11_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + T11_IRQ2: set_irq_line(T11_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + T11_IRQ3: set_irq_line(T11_IRQ3, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + T11_PC: PC = info->i; change_pc(PC); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + T11_SP: SP = info->i; break;
+ case CPUINFO_INT_REGISTER + T11_PSW: PSW = info->i; break;
+ case CPUINFO_INT_REGISTER + T11_R0: REGW(0) = info->i; break;
+ case CPUINFO_INT_REGISTER + T11_R1: REGW(1) = info->i; break;
+ case CPUINFO_INT_REGISTER + T11_R2: REGW(2) = info->i; break;
+ case CPUINFO_INT_REGISTER + T11_R3: REGW(3) = info->i; break;
+ case CPUINFO_INT_REGISTER + T11_R4: REGW(4) = info->i; break;
+ case CPUINFO_INT_REGISTER + T11_R5: REGW(5) = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void t11_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(t11); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 4; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 12; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 110; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + T11_IRQ0: info->i = (t11.irq_state & 1) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + T11_IRQ1: info->i = (t11.irq_state & 2) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + T11_IRQ2: info->i = (t11.irq_state & 4) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + T11_IRQ3: info->i = (t11.irq_state & 8) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = t11.ppc.w.l; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + T11_PC: info->i = PCD; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + T11_SP: info->i = SPD; break;
+ case CPUINFO_INT_REGISTER + T11_PSW: info->i = PSW; break;
+ case CPUINFO_INT_REGISTER + T11_R0: info->i = REGD(0); break;
+ case CPUINFO_INT_REGISTER + T11_R1: info->i = REGD(1); break;
+ case CPUINFO_INT_REGISTER + T11_R2: info->i = REGD(2); break;
+ case CPUINFO_INT_REGISTER + T11_R3: info->i = REGD(3); break;
+ case CPUINFO_INT_REGISTER + T11_R4: info->i = REGD(4); break;
+ case CPUINFO_INT_REGISTER + T11_R5: info->i = REGD(5); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = t11_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = t11_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = t11_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = t11_init; break;
+ case CPUINFO_PTR_RESET: info->reset = t11_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = t11_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = t11_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = t11_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &t11_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "T11"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "DEC T-11"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) Aaron Giles 1998"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ t11.psw.b.l & 0x80 ? '?':'.',
+ t11.psw.b.l & 0x40 ? 'I':'.',
+ t11.psw.b.l & 0x20 ? 'I':'.',
+ t11.psw.b.l & 0x10 ? 'T':'.',
+ t11.psw.b.l & 0x08 ? 'N':'.',
+ t11.psw.b.l & 0x04 ? 'Z':'.',
+ t11.psw.b.l & 0x02 ? 'V':'.',
+ t11.psw.b.l & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + T11_PC: sprintf(info->s, "PC:%04X", t11.reg[7].w.l); break;
+ case CPUINFO_STR_REGISTER + T11_SP: sprintf(info->s, "SP:%04X", t11.reg[6].w.l); break;
+ case CPUINFO_STR_REGISTER + T11_PSW: sprintf(info->s, "PSW:%02X", t11.psw.b.l); break;
+ case CPUINFO_STR_REGISTER + T11_R0: sprintf(info->s, "R0:%04X", t11.reg[0].w.l); break;
+ case CPUINFO_STR_REGISTER + T11_R1: sprintf(info->s, "R1:%04X", t11.reg[1].w.l); break;
+ case CPUINFO_STR_REGISTER + T11_R2: sprintf(info->s, "R2:%04X", t11.reg[2].w.l); break;
+ case CPUINFO_STR_REGISTER + T11_R3: sprintf(info->s, "R3:%04X", t11.reg[3].w.l); break;
+ case CPUINFO_STR_REGISTER + T11_R4: sprintf(info->s, "R4:%04X", t11.reg[4].w.l); break;
+ case CPUINFO_STR_REGISTER + T11_R5: sprintf(info->s, "R5:%04X", t11.reg[5].w.l); break;
+ }
+}
diff --git a/src/emu/cpu/t11/t11.h b/src/emu/cpu/t11/t11.h
new file mode 100644
index 00000000000..e8204b8f288
--- /dev/null
+++ b/src/emu/cpu/t11/t11.h
@@ -0,0 +1,50 @@
+/*** T-11: Portable DEC T-11 emulator ******************************************/
+
+#ifndef _T11_H
+#define _T11_H
+
+#include "cpuintrf.h"
+
+enum {
+ T11_R0=1, T11_R1, T11_R2, T11_R3, T11_R4, T11_R5, T11_SP, T11_PC, T11_PSW };
+
+#define T11_IRQ0 0 /* IRQ0 */
+#define T11_IRQ1 1 /* IRQ1 */
+#define T11_IRQ2 2 /* IRQ2 */
+#define T11_IRQ3 3 /* IRQ3 */
+
+#define T11_RESERVED 0x000 /* Reserved vector */
+#define T11_TIMEOUT 0x004 /* Time-out/system error vector */
+#define T11_ILLINST 0x008 /* Illegal and reserved instruction vector */
+#define T11_BPT 0x00C /* BPT instruction vector */
+#define T11_IOT 0x010 /* IOT instruction vector */
+#define T11_PWRFAIL 0x014 /* Power fail vector */
+#define T11_EMT 0x018 /* EMT instruction vector */
+#define T11_TRAP 0x01C /* TRAP instruction vector */
+
+
+struct t11_setup
+{
+ UINT16 mode; /* initial processor mode */
+};
+
+
+extern void t11_get_info(UINT32 state, cpuinfo *info);
+
+/****************************************************************************/
+/* Read a byte from given memory location */
+/****************************************************************************/
+#define T11_RDMEM(A) ((unsigned)program_read_byte_16le(A))
+#define T11_RDMEM_WORD(A) ((unsigned)program_read_word_16le(A))
+
+/****************************************************************************/
+/* Write a byte to given memory location */
+/****************************************************************************/
+#define T11_WRMEM(A,V) (program_write_byte_16le(A,V))
+#define T11_WRMEM_WORD(A,V) (program_write_word_16le(A,V))
+
+#ifdef MAME_DEBUG
+offs_t t11_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _T11_H */
diff --git a/src/emu/cpu/t11/t11dasm.c b/src/emu/cpu/t11/t11dasm.c
new file mode 100644
index 00000000000..0564b6bffcb
--- /dev/null
+++ b/src/emu/cpu/t11/t11dasm.c
@@ -0,0 +1,517 @@
+/*
+ * A T11 disassembler
+ *
+ * Note: this is probably not the most efficient disassembler in the world :-)
+ *
+ * This code written by Aaron Giles (agiles@sirius.com) for the MAME project
+ *
+ */
+
+#include "debugger.h"
+#include "t11.h"
+
+static const char *regs[8] = { "R0", "R1", "R2", "R3", "R4", "R5", "SP", "PC" };
+
+static const UINT8 *rombase;
+static offs_t pcbase;
+
+#define PARAM_WORD(v) ((v) = rombase[pc - pcbase] | (rombase[pc + 1 - pcbase] << 8), pc += 2)
+
+unsigned MakeEA (char **ea, int lo, unsigned pc, int width)
+{
+ char *buffer = cpuintrf_temp_str();
+ int reg, pm;
+
+ assert (width == 2 || width == 4);
+
+ reg = lo & 7;
+
+ switch ((lo >> 3) & 7)
+ {
+ case 0:
+ sprintf (buffer, "%s", regs[reg]);
+ break;
+ case 1:
+ sprintf (buffer, "(%s)", regs[reg]);
+ break;
+ case 2:
+ if (reg == 7)
+ {
+ PARAM_WORD (pm);
+ sprintf (buffer, "#$%0*X", width, pm & ((width == 2) ? 0xff : 0xffff));
+ }
+ else
+ {
+ sprintf (buffer, "(%s)+", regs[reg]);
+ }
+ break;
+ case 3:
+ if (reg == 7)
+ {
+ PARAM_WORD (pm);
+ sprintf (buffer, "$%04X", pm &= 0xffff);
+ }
+ else
+ {
+ sprintf (buffer, "@(%s)+", regs[reg]);
+ }
+ break;
+ case 4:
+ sprintf (buffer, "-(%s)", regs[reg]);
+ break;
+ case 5:
+ sprintf (buffer, "@-(%s)", regs[reg]);
+ break;
+ case 6:
+ PARAM_WORD (pm);
+ sprintf(buffer, "%s$%X(%s)",
+ (pm&0x8000)?"-":"",
+ (pm&0x8000)?-(signed short)pm:pm,
+ regs[reg]);
+ break;
+ case 7:
+ PARAM_WORD (pm);
+ sprintf(buffer, "@%s$%X(%s)",
+ (pm&0x8000)?"-":"",
+ (pm&0x8000)?-(signed short)pm:pm,
+ regs[reg]);
+ break;
+ }
+
+ *ea = buffer;
+ return pc;
+}
+
+
+offs_t t11_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ char *ea1, *ea2;
+ unsigned PC = pc;
+ UINT16 op, lo, hi, addr;
+ INT16 offset;
+ UINT32 flags = 0;
+
+ rombase = oprom;
+ pcbase = pc;
+
+ PARAM_WORD(op);
+ lo = op & 077;
+ hi = (op >> 6) & 077;
+
+ switch (op & 0xffc0)
+ {
+ case 0x0000:
+ switch (lo)
+ {
+ case 0x00: sprintf (buffer, "HALT"); break;
+ case 0x01: sprintf (buffer, "WAIT"); break;
+ case 0x02: sprintf (buffer, "RTI"); flags = DASMFLAG_STEP_OUT; break;
+ case 0x03: sprintf (buffer, "BPT"); break;
+ case 0x04: sprintf (buffer, "IOT"); break;
+ case 0x05: sprintf (buffer, "RESET"); break;
+ case 0x06: sprintf (buffer, "RTT"); break;
+ default: sprintf (buffer, "???? (%04X)", op); break;
+ }
+ break;
+ case 0x0040:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "JMP %s", ea1);
+ break;
+ case 0x0080:
+ switch (lo & 070)
+ {
+ case 000:
+ if( (lo & 7) == 7 )
+ sprintf (buffer, "RTS");
+ else
+ sprintf (buffer, "RTS %s", regs[lo & 7]);
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ case 040:
+ case 050:
+ switch( lo & 15 )
+ {
+ case 0x00: sprintf (buffer, "NOP"); break;
+ case 0x0f: sprintf (buffer, "CCC"); break;
+ case 0x01: sprintf (buffer, "CEC"); break;
+ case 0x02: sprintf (buffer, "CEV"); break;
+ case 0x04: sprintf (buffer, "CEZ"); break;
+ case 0x08: sprintf (buffer, "CEN"); break;
+ default: sprintf (buffer, "Ccc #$%X", lo & 15); break;
+ }
+ break;
+ case 060:
+ case 070:
+ switch( lo & 15 )
+ {
+ case 0x00: sprintf (buffer, "NOP"); break;
+ case 0x0f: sprintf (buffer, "SCC"); break;
+ case 0x01: sprintf (buffer, "SEC"); break;
+ case 0x02: sprintf (buffer, "SEV"); break;
+ case 0x04: sprintf (buffer, "SEZ"); break;
+ case 0x08: sprintf (buffer, "SEN"); break;
+ default: sprintf (buffer, "Scc #$%X", lo & 15); break;
+ }
+ break;
+ }
+ break;
+ case 0x00c0:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "SWAB %s", ea1);
+ break;
+ case 0x0100: case 0x0140: case 0x0180: case 0x01c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BR $%04X", pc + offset);
+ break;
+ case 0x0200: case 0x0240: case 0x0280: case 0x02c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BNE $%04X", pc + offset);
+ break;
+ case 0x0300: case 0x0340: case 0x0380: case 0x03c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BEQ $%04X", pc + offset);
+ break;
+ case 0x0400: case 0x0440: case 0x0480: case 0x04c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BGE $%04X", pc + offset);
+ break;
+ case 0x0500: case 0x0540: case 0x0580: case 0x05c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BLT $%04X", pc + offset);
+ break;
+ case 0x0600: case 0x0640: case 0x0680: case 0x06c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BGT $%04X", pc + offset);
+ break;
+ case 0x0700: case 0x0740: case 0x0780: case 0x07c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BLE $%04X", pc + offset);
+ break;
+ case 0x0800: case 0x0840: case 0x0880: case 0x08c0:
+ case 0x0900: case 0x0940: case 0x0980: case 0x09c0:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ if ( (hi & 7) == 7 )
+ sprintf (buffer, "JSR %s", ea1);
+ else
+ sprintf (buffer, "JSR %s,%s", regs[hi & 7], ea1);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 0x0a00:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "CLR %s", ea1);
+ break;
+ case 0x0a40:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "COM %s", ea1);
+ break;
+ case 0x0a80:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "INC %s", ea1);
+ break;
+ case 0x0ac0:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "DEC %s", ea1);
+ break;
+ case 0x0b00:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "NEG %s", ea1);
+ break;
+ case 0x0b40:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "ADC %s", ea1);
+ break;
+ case 0x0b80:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "SBC %s", ea1);
+ break;
+ case 0x0bc0:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "TST %s", ea1);
+ break;
+ case 0x0c00:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "ROR %s", ea1);
+ break;
+ case 0x0c40:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "ROL %s", ea1);
+ break;
+ case 0x0c80:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "ASR %s", ea1);
+ break;
+ case 0x0cc0:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "ASL %s", ea1);
+ break;
+/* case 0x0d00:
+ sprintf (buffer, "MARK #$%X", lo);
+ break;*/
+ case 0x0dc0:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "SXT %s", ea1);
+ break;
+ case 0x1000: case 0x1040: case 0x1080: case 0x10c0: case 0x1100: case 0x1140: case 0x1180: case 0x11c0:
+ case 0x1200: case 0x1240: case 0x1280: case 0x12c0: case 0x1300: case 0x1340: case 0x1380: case 0x13c0:
+ case 0x1400: case 0x1440: case 0x1480: case 0x14c0: case 0x1500: case 0x1540: case 0x1580: case 0x15c0:
+ case 0x1600: case 0x1640: case 0x1680: case 0x16c0: case 0x1700: case 0x1740: case 0x1780: case 0x17c0:
+ case 0x1800: case 0x1840: case 0x1880: case 0x18c0: case 0x1900: case 0x1940: case 0x1980: case 0x19c0:
+ case 0x1a00: case 0x1a40: case 0x1a80: case 0x1ac0: case 0x1b00: case 0x1b40: case 0x1b80: case 0x1bc0:
+ case 0x1c00: case 0x1c40: case 0x1c80: case 0x1cc0: case 0x1d00: case 0x1d40: case 0x1d80: case 0x1dc0:
+ case 0x1e00: case 0x1e40: case 0x1e80: case 0x1ec0: case 0x1f00: case 0x1f40: case 0x1f80: case 0x1fc0:
+ pc = MakeEA (&ea1, hi, pc, 4);
+ pc = MakeEA (&ea2, lo, pc, 4);
+ if (lo == 046) /* MOV src,-(SP) */
+ sprintf (buffer, "PUSH %s", ea1);
+ else
+ if (hi == 026) /* MOV (SP)+,buffer */
+ sprintf (buffer, "POP %s", ea2);
+ else /* all other */
+ sprintf (buffer, "MOV %s,%s", ea1, ea2);
+ break;
+ case 0x2000: case 0x2040: case 0x2080: case 0x20c0: case 0x2100: case 0x2140: case 0x2180: case 0x21c0:
+ case 0x2200: case 0x2240: case 0x2280: case 0x22c0: case 0x2300: case 0x2340: case 0x2380: case 0x23c0:
+ case 0x2400: case 0x2440: case 0x2480: case 0x24c0: case 0x2500: case 0x2540: case 0x2580: case 0x25c0:
+ case 0x2600: case 0x2640: case 0x2680: case 0x26c0: case 0x2700: case 0x2740: case 0x2780: case 0x27c0:
+ case 0x2800: case 0x2840: case 0x2880: case 0x28c0: case 0x2900: case 0x2940: case 0x2980: case 0x29c0:
+ case 0x2a00: case 0x2a40: case 0x2a80: case 0x2ac0: case 0x2b00: case 0x2b40: case 0x2b80: case 0x2bc0:
+ case 0x2c00: case 0x2c40: case 0x2c80: case 0x2cc0: case 0x2d00: case 0x2d40: case 0x2d80: case 0x2dc0:
+ case 0x2e00: case 0x2e40: case 0x2e80: case 0x2ec0: case 0x2f00: case 0x2f40: case 0x2f80: case 0x2fc0:
+ pc = MakeEA (&ea1, hi, pc, 4);
+ pc = MakeEA (&ea2, lo, pc, 4);
+ sprintf (buffer, "CMP %s,%s", ea1, ea2);
+ break;
+ case 0x3000: case 0x3040: case 0x3080: case 0x30c0: case 0x3100: case 0x3140: case 0x3180: case 0x31c0:
+ case 0x3200: case 0x3240: case 0x3280: case 0x32c0: case 0x3300: case 0x3340: case 0x3380: case 0x33c0:
+ case 0x3400: case 0x3440: case 0x3480: case 0x34c0: case 0x3500: case 0x3540: case 0x3580: case 0x35c0:
+ case 0x3600: case 0x3640: case 0x3680: case 0x36c0: case 0x3700: case 0x3740: case 0x3780: case 0x37c0:
+ case 0x3800: case 0x3840: case 0x3880: case 0x38c0: case 0x3900: case 0x3940: case 0x3980: case 0x39c0:
+ case 0x3a00: case 0x3a40: case 0x3a80: case 0x3ac0: case 0x3b00: case 0x3b40: case 0x3b80: case 0x3bc0:
+ case 0x3c00: case 0x3c40: case 0x3c80: case 0x3cc0: case 0x3d00: case 0x3d40: case 0x3d80: case 0x3dc0:
+ case 0x3e00: case 0x3e40: case 0x3e80: case 0x3ec0: case 0x3f00: case 0x3f40: case 0x3f80: case 0x3fc0:
+ pc = MakeEA (&ea1, hi, pc, 4);
+ pc = MakeEA (&ea2, lo, pc, 4);
+ sprintf (buffer, "BIT %s,%s", ea1, ea2);
+ break;
+ case 0x4000: case 0x4040: case 0x4080: case 0x40c0: case 0x4100: case 0x4140: case 0x4180: case 0x41c0:
+ case 0x4200: case 0x4240: case 0x4280: case 0x42c0: case 0x4300: case 0x4340: case 0x4380: case 0x43c0:
+ case 0x4400: case 0x4440: case 0x4480: case 0x44c0: case 0x4500: case 0x4540: case 0x4580: case 0x45c0:
+ case 0x4600: case 0x4640: case 0x4680: case 0x46c0: case 0x4700: case 0x4740: case 0x4780: case 0x47c0:
+ case 0x4800: case 0x4840: case 0x4880: case 0x48c0: case 0x4900: case 0x4940: case 0x4980: case 0x49c0:
+ case 0x4a00: case 0x4a40: case 0x4a80: case 0x4ac0: case 0x4b00: case 0x4b40: case 0x4b80: case 0x4bc0:
+ case 0x4c00: case 0x4c40: case 0x4c80: case 0x4cc0: case 0x4d00: case 0x4d40: case 0x4d80: case 0x4dc0:
+ case 0x4e00: case 0x4e40: case 0x4e80: case 0x4ec0: case 0x4f00: case 0x4f40: case 0x4f80: case 0x4fc0:
+ pc = MakeEA (&ea1, hi, pc, 4);
+ pc = MakeEA (&ea2, lo, pc, 4);
+ sprintf (buffer, "BIC %s,%s", ea1, ea2);
+ break;
+ case 0x5000: case 0x5040: case 0x5080: case 0x50c0: case 0x5100: case 0x5140: case 0x5180: case 0x51c0:
+ case 0x5200: case 0x5240: case 0x5280: case 0x52c0: case 0x5300: case 0x5340: case 0x5380: case 0x53c0:
+ case 0x5400: case 0x5440: case 0x5480: case 0x54c0: case 0x5500: case 0x5540: case 0x5580: case 0x55c0:
+ case 0x5600: case 0x5640: case 0x5680: case 0x56c0: case 0x5700: case 0x5740: case 0x5780: case 0x57c0:
+ case 0x5800: case 0x5840: case 0x5880: case 0x58c0: case 0x5900: case 0x5940: case 0x5980: case 0x59c0:
+ case 0x5a00: case 0x5a40: case 0x5a80: case 0x5ac0: case 0x5b00: case 0x5b40: case 0x5b80: case 0x5bc0:
+ case 0x5c00: case 0x5c40: case 0x5c80: case 0x5cc0: case 0x5d00: case 0x5d40: case 0x5d80: case 0x5dc0:
+ case 0x5e00: case 0x5e40: case 0x5e80: case 0x5ec0: case 0x5f00: case 0x5f40: case 0x5f80: case 0x5fc0:
+ pc = MakeEA (&ea1, hi, pc, 4);
+ pc = MakeEA (&ea2, lo, pc, 4);
+ sprintf (buffer, "BIS %s,%s", ea1, ea2);
+ break;
+ case 0x6000: case 0x6040: case 0x6080: case 0x60c0: case 0x6100: case 0x6140: case 0x6180: case 0x61c0:
+ case 0x6200: case 0x6240: case 0x6280: case 0x62c0: case 0x6300: case 0x6340: case 0x6380: case 0x63c0:
+ case 0x6400: case 0x6440: case 0x6480: case 0x64c0: case 0x6500: case 0x6540: case 0x6580: case 0x65c0:
+ case 0x6600: case 0x6640: case 0x6680: case 0x66c0: case 0x6700: case 0x6740: case 0x6780: case 0x67c0:
+ case 0x6800: case 0x6840: case 0x6880: case 0x68c0: case 0x6900: case 0x6940: case 0x6980: case 0x69c0:
+ case 0x6a00: case 0x6a40: case 0x6a80: case 0x6ac0: case 0x6b00: case 0x6b40: case 0x6b80: case 0x6bc0:
+ case 0x6c00: case 0x6c40: case 0x6c80: case 0x6cc0: case 0x6d00: case 0x6d40: case 0x6d80: case 0x6dc0:
+ case 0x6e00: case 0x6e40: case 0x6e80: case 0x6ec0: case 0x6f00: case 0x6f40: case 0x6f80: case 0x6fc0:
+ pc = MakeEA (&ea1, hi, pc, 4);
+ pc = MakeEA (&ea2, lo, pc, 4);
+ sprintf (buffer, "ADD %s,%s", ea1, ea2);
+ break;
+
+ case 0x7800: case 0x7840: case 0x7880: case 0x78c0: case 0x7900: case 0x7940: case 0x7980: case 0x79c0:
+ pc = MakeEA (&ea1, lo, pc, 4);
+ sprintf (buffer, "XOR %s,%s", regs[hi & 7], ea1);
+ break;
+
+ case 0x7e00: case 0x7e40: case 0x7e80: case 0x7ec0: case 0x7f00: case 0x7f40: case 0x7f80: case 0x7fc0:
+ addr = (pc + 2 - 2 * lo) & 0xffff;
+ sprintf (buffer, "SOB %s,$%X", regs[hi & 7], addr);
+ break;
+
+ case 0x8000: case 0x8040: case 0x8080: case 0x80c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BPL $%04X", pc + offset);
+ break;
+ case 0x8100: case 0x8140: case 0x8180: case 0x81c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BMI $%04X", pc + offset);
+ break;
+ case 0x8200: case 0x8240: case 0x8280: case 0x82c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BHI $%04X", pc + offset);
+ break;
+ case 0x8300: case 0x8340: case 0x8380: case 0x83c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BLOS $%04X", pc + offset);
+ break;
+ case 0x8400: case 0x8440: case 0x8480: case 0x84c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BVC $%04X", pc + offset);
+ break;
+ case 0x8500: case 0x8540: case 0x8580: case 0x85c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BVS $%04X", pc + offset);
+ break;
+ case 0x8600: case 0x8640: case 0x8680: case 0x86c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BCC $%04X", pc + offset);
+ break;
+ case 0x8700: case 0x8740: case 0x8780: case 0x87c0:
+ offset = 2 * (INT8)(op & 0xff);
+ sprintf (buffer, "BCS $%04X", pc + offset);
+ break;
+ case 0x8800: case 0x8840: case 0x8880: case 0x88c0:
+ sprintf (buffer, "EMT #$%02X", op & 0xff);
+ break;
+ case 0x8900: case 0x8940: case 0x8980: case 0x89c0:
+ sprintf (buffer, "TRAP #$%02X", op & 0xff);
+ break;
+
+ case 0x8a00:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "CLRB %s", ea1);
+ break;
+ case 0x8a40:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "COMB %s", ea1);
+ break;
+ case 0x8a80:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "INCB %s", ea1);
+ break;
+ case 0x8ac0:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "DECB %s", ea1);
+ break;
+ case 0x8b00:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "NEGB %s", ea1);
+ break;
+ case 0x8b40:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "ADCB %s", ea1);
+ break;
+ case 0x8b80:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "SBCB %s", ea1);
+ break;
+ case 0x8bc0:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "TSTB %s", ea1);
+ break;
+ case 0x8c00:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "RORB %s", ea1);
+ break;
+ case 0x8c40:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "ROLB %s", ea1);
+ break;
+ case 0x8c80:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "ASRB %s", ea1);
+ break;
+ case 0x8cc0:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "ASLB %s", ea1);
+ break;
+ case 0x8d00:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "MTPS %s", ea1);
+ break;
+ case 0x8dc0:
+ pc = MakeEA (&ea1, lo, pc, 2);
+ sprintf (buffer, "MFPS %s", ea1);
+ break;
+ case 0x9000: case 0x9040: case 0x9080: case 0x90c0: case 0x9100: case 0x9140: case 0x9180: case 0x91c0:
+ case 0x9200: case 0x9240: case 0x9280: case 0x92c0: case 0x9300: case 0x9340: case 0x9380: case 0x93c0:
+ case 0x9400: case 0x9440: case 0x9480: case 0x94c0: case 0x9500: case 0x9540: case 0x9580: case 0x95c0:
+ case 0x9600: case 0x9640: case 0x9680: case 0x96c0: case 0x9700: case 0x9740: case 0x9780: case 0x97c0:
+ case 0x9800: case 0x9840: case 0x9880: case 0x98c0: case 0x9900: case 0x9940: case 0x9980: case 0x99c0:
+ case 0x9a00: case 0x9a40: case 0x9a80: case 0x9ac0: case 0x9b00: case 0x9b40: case 0x9b80: case 0x9bc0:
+ case 0x9c00: case 0x9c40: case 0x9c80: case 0x9cc0: case 0x9d00: case 0x9d40: case 0x9d80: case 0x9dc0:
+ case 0x9e00: case 0x9e40: case 0x9e80: case 0x9ec0: case 0x9f00: case 0x9f40: case 0x9f80: case 0x9fc0:
+ pc = MakeEA (&ea1, hi, pc, 2);
+ pc = MakeEA (&ea2, lo, pc, 2);
+ sprintf (buffer, "MOVB %s,%s", ea1, ea2);
+ break;
+ case 0xa000: case 0xa040: case 0xa080: case 0xa0c0: case 0xa100: case 0xa140: case 0xa180: case 0xa1c0:
+ case 0xa200: case 0xa240: case 0xa280: case 0xa2c0: case 0xa300: case 0xa340: case 0xa380: case 0xa3c0:
+ case 0xa400: case 0xa440: case 0xa480: case 0xa4c0: case 0xa500: case 0xa540: case 0xa580: case 0xa5c0:
+ case 0xa600: case 0xa640: case 0xa680: case 0xa6c0: case 0xa700: case 0xa740: case 0xa780: case 0xa7c0:
+ case 0xa800: case 0xa840: case 0xa880: case 0xa8c0: case 0xa900: case 0xa940: case 0xa980: case 0xa9c0:
+ case 0xaa00: case 0xaa40: case 0xaa80: case 0xaac0: case 0xab00: case 0xab40: case 0xab80: case 0xabc0:
+ case 0xac00: case 0xac40: case 0xac80: case 0xacc0: case 0xad00: case 0xad40: case 0xad80: case 0xadc0:
+ case 0xae00: case 0xae40: case 0xae80: case 0xaec0: case 0xaf00: case 0xaf40: case 0xaf80: case 0xafc0:
+ pc = MakeEA (&ea1, hi, pc, 2);
+ pc = MakeEA (&ea2, lo, pc, 2);
+ sprintf (buffer, "CMPB %s,%s", ea1, ea2);
+ break;
+ case 0xb000: case 0xb040: case 0xb080: case 0xb0c0: case 0xb100: case 0xb140: case 0xb180: case 0xb1c0:
+ case 0xb200: case 0xb240: case 0xb280: case 0xb2c0: case 0xb300: case 0xb340: case 0xb380: case 0xb3c0:
+ case 0xb400: case 0xb440: case 0xb480: case 0xb4c0: case 0xb500: case 0xb540: case 0xb580: case 0xb5c0:
+ case 0xb600: case 0xb640: case 0xb680: case 0xb6c0: case 0xb700: case 0xb740: case 0xb780: case 0xb7c0:
+ case 0xb800: case 0xb840: case 0xb880: case 0xb8c0: case 0xb900: case 0xb940: case 0xb980: case 0xb9c0:
+ case 0xba00: case 0xba40: case 0xba80: case 0xbac0: case 0xbb00: case 0xbb40: case 0xbb80: case 0xbbc0:
+ case 0xbc00: case 0xbc40: case 0xbc80: case 0xbcc0: case 0xbd00: case 0xbd40: case 0xbd80: case 0xbdc0:
+ case 0xbe00: case 0xbe40: case 0xbe80: case 0xbec0: case 0xbf00: case 0xbf40: case 0xbf80: case 0xbfc0:
+ pc = MakeEA (&ea1, hi, pc, 2);
+ pc = MakeEA (&ea2, lo, pc, 2);
+ sprintf (buffer, "BITB %s,%s", ea1, ea2);
+ break;
+ case 0xc000: case 0xc040: case 0xc080: case 0xc0c0: case 0xc100: case 0xc140: case 0xc180: case 0xc1c0:
+ case 0xc200: case 0xc240: case 0xc280: case 0xc2c0: case 0xc300: case 0xc340: case 0xc380: case 0xc3c0:
+ case 0xc400: case 0xc440: case 0xc480: case 0xc4c0: case 0xc500: case 0xc540: case 0xc580: case 0xc5c0:
+ case 0xc600: case 0xc640: case 0xc680: case 0xc6c0: case 0xc700: case 0xc740: case 0xc780: case 0xc7c0:
+ case 0xc800: case 0xc840: case 0xc880: case 0xc8c0: case 0xc900: case 0xc940: case 0xc980: case 0xc9c0:
+ case 0xca00: case 0xca40: case 0xca80: case 0xcac0: case 0xcb00: case 0xcb40: case 0xcb80: case 0xcbc0:
+ case 0xcc00: case 0xcc40: case 0xcc80: case 0xccc0: case 0xcd00: case 0xcd40: case 0xcd80: case 0xcdc0:
+ case 0xce00: case 0xce40: case 0xce80: case 0xcec0: case 0xcf00: case 0xcf40: case 0xcf80: case 0xcfc0:
+ pc = MakeEA (&ea1, hi, pc, 2);
+ pc = MakeEA (&ea2, lo, pc, 2);
+ sprintf (buffer, "BICB %s,%s", ea1, ea2);
+ break;
+ case 0xd000: case 0xd040: case 0xd080: case 0xd0c0: case 0xd100: case 0xd140: case 0xd180: case 0xd1c0:
+ case 0xd200: case 0xd240: case 0xd280: case 0xd2c0: case 0xd300: case 0xd340: case 0xd380: case 0xd3c0:
+ case 0xd400: case 0xd440: case 0xd480: case 0xd4c0: case 0xd500: case 0xd540: case 0xd580: case 0xd5c0:
+ case 0xd600: case 0xd640: case 0xd680: case 0xd6c0: case 0xd700: case 0xd740: case 0xd780: case 0xd7c0:
+ case 0xd800: case 0xd840: case 0xd880: case 0xd8c0: case 0xd900: case 0xd940: case 0xd980: case 0xd9c0:
+ case 0xda00: case 0xda40: case 0xda80: case 0xdac0: case 0xdb00: case 0xdb40: case 0xdb80: case 0xdbc0:
+ case 0xdc00: case 0xdc40: case 0xdc80: case 0xdcc0: case 0xdd00: case 0xdd40: case 0xdd80: case 0xddc0:
+ case 0xde00: case 0xde40: case 0xde80: case 0xdec0: case 0xdf00: case 0xdf40: case 0xdf80: case 0xdfc0:
+ pc = MakeEA (&ea1, hi, pc, 2);
+ pc = MakeEA (&ea2, lo, pc, 2);
+ sprintf (buffer, "BISB %s,%s", ea1, ea2);
+ break;
+ case 0xe000: case 0xe040: case 0xe080: case 0xe0c0: case 0xe100: case 0xe140: case 0xe180: case 0xe1c0:
+ case 0xe200: case 0xe240: case 0xe280: case 0xe2c0: case 0xe300: case 0xe340: case 0xe380: case 0xe3c0:
+ case 0xe400: case 0xe440: case 0xe480: case 0xe4c0: case 0xe500: case 0xe540: case 0xe580: case 0xe5c0:
+ case 0xe600: case 0xe640: case 0xe680: case 0xe6c0: case 0xe700: case 0xe740: case 0xe780: case 0xe7c0:
+ case 0xe800: case 0xe840: case 0xe880: case 0xe8c0: case 0xe900: case 0xe940: case 0xe980: case 0xe9c0:
+ case 0xea00: case 0xea40: case 0xea80: case 0xeac0: case 0xeb00: case 0xeb40: case 0xeb80: case 0xebc0:
+ case 0xec00: case 0xec40: case 0xec80: case 0xecc0: case 0xed00: case 0xed40: case 0xed80: case 0xedc0:
+ case 0xee00: case 0xee40: case 0xee80: case 0xeec0: case 0xef00: case 0xef40: case 0xef80: case 0xefc0:
+ pc = MakeEA (&ea1, hi, pc, 4);
+ pc = MakeEA (&ea2, lo, pc, 4);
+ sprintf (buffer, "SUB %s,%s", ea1, ea2);
+ break;
+
+ default:
+ sprintf (buffer, "???? (%06o)", op);
+ break;
+ }
+
+ return (pc - PC) | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/t11/t11ops.c b/src/emu/cpu/t11/t11ops.c
new file mode 100644
index 00000000000..71b31d74142
--- /dev/null
+++ b/src/emu/cpu/t11/t11ops.c
@@ -0,0 +1,1400 @@
+/*** t11: Portable DEC T-11 emulator ******************************************
+
+ Copyright (C) Aaron Giles 1998
+
+ Actual opcode implementation. Excuse the excessive use of macros, it
+ was the only way I could bear to type all this in!
+
+*****************************************************************************/
+
+
+/* given a register index 'r', this computes the effective address for a byte-sized operation
+ and puts the result in 'ea' */
+#define MAKE_EAB_RGD(r) ea = REGD(r)
+#define MAKE_EAB_IN(r) ea = REGD(r); REGW(r) += ((r) < 6 ? 1 : 2)
+#define MAKE_EAB_INS(r) ea = REGD(r); REGW(r) += ((r) < 6 ? 1 : 2)
+#define MAKE_EAB_IND(r) ea = REGD(r); REGW(r) += 2; ea = RWORD(ea)
+#define MAKE_EAB_DE(r) REGW(r) -= ((r) < 6 ? 1 : 2); ea = REGD(r)
+#define MAKE_EAB_DED(r) REGW(r) -= 2; ea = REGD(r); ea = RWORD(ea)
+#define MAKE_EAB_IX(r) ea = ROPCODE(); ea = (ea + REGD(r)) & 0xffff
+#define MAKE_EAB_IXD(r) ea = ROPCODE(); ea = (ea + REGD(r)) & 0xffff; ea = RWORD(ea)
+
+/* given a register index 'r', this computes the effective address for a word-sized operation
+ and puts the result in 'ea' */
+/* note that word accesses ignore the low bit!! this fixes APB! */
+#define MAKE_EAW_RGD(r) MAKE_EAB_RGD(r)
+#define MAKE_EAW_IN(r) ea = REGD(r); REGW(r) += 2
+#define MAKE_EAW_IND(r) MAKE_EAB_IND(r)
+#define MAKE_EAW_DE(r) REGW(r) -= 2; ea = REGD(r)
+#define MAKE_EAW_DED(r) MAKE_EAB_DED(r)
+#define MAKE_EAW_IX(r) MAKE_EAB_IX(r)
+#define MAKE_EAW_IXD(r) MAKE_EAB_IXD(r)
+
+/* extracts the source/destination register index from the opcode into 'sreg' or 'dreg' */
+#define GET_SREG sreg = (t11.op >> 6) & 7
+#define GET_DREG dreg = t11.op & 7
+
+/* for a byte-sized source operand: extracts 'sreg', computes 'ea', and loads the value into 'source' */
+#define GET_SB_RG GET_SREG; source = REGB(sreg)
+#define GET_SB_RGD GET_SREG; MAKE_EAB_RGD(sreg); source = RBYTE(ea)
+#define GET_SB_IN GET_SREG; if (sreg == 7) { source = ROPCODE(); } else { MAKE_EAB_IN(sreg); source = RBYTE(ea); }
+#define GET_SB_IND GET_SREG; if (sreg == 7) { ea = ROPCODE(); } else { MAKE_EAB_IND(sreg); } source = RBYTE(ea)
+#define GET_SB_DE GET_SREG; MAKE_EAB_DE(sreg); source = RBYTE(ea)
+#define GET_SB_DED GET_SREG; MAKE_EAB_DED(sreg); source = RBYTE(ea)
+#define GET_SB_IX GET_SREG; MAKE_EAB_IX(sreg); source = RBYTE(ea)
+#define GET_SB_IXD GET_SREG; MAKE_EAB_IXD(sreg); source = RBYTE(ea)
+
+/* for a word-sized source operand: extracts 'sreg', computes 'ea', and loads the value into 'source' */
+#define GET_SW_RG GET_SREG; source = REGD(sreg)
+#define GET_SW_RGD GET_SREG; MAKE_EAW_RGD(sreg); source = RWORD(ea)
+#define GET_SW_IN GET_SREG; if (sreg == 7) { source = ROPCODE(); } else { MAKE_EAW_IN(sreg); source = RWORD(ea); }
+#define GET_SW_IND GET_SREG; if (sreg == 7) { ea = ROPCODE(); } else { MAKE_EAW_IND(sreg); } source = RWORD(ea)
+#define GET_SW_DE GET_SREG; MAKE_EAW_DE(sreg); source = RWORD(ea)
+#define GET_SW_DED GET_SREG; MAKE_EAW_DED(sreg); source = RWORD(ea)
+#define GET_SW_IX GET_SREG; MAKE_EAW_IX(sreg); source = RWORD(ea)
+#define GET_SW_IXD GET_SREG; MAKE_EAW_IXD(sreg); source = RWORD(ea)
+
+/* for a byte-sized destination operand: extracts 'dreg', computes 'ea', and loads the value into 'dest' */
+#define GET_DB_RG GET_DREG; dest = REGB(dreg)
+#define GET_DB_RGD GET_DREG; MAKE_EAB_RGD(dreg); dest = RBYTE(ea)
+#define GET_DB_IN GET_DREG; MAKE_EAB_IN(dreg); dest = RBYTE(ea)
+#define GET_DB_IND GET_DREG; if (dreg == 7) { ea = ROPCODE(); } else { MAKE_EAB_IND(dreg); } dest = RBYTE(ea)
+#define GET_DB_DE GET_DREG; MAKE_EAB_DE(dreg); dest = RBYTE(ea)
+#define GET_DB_DED GET_DREG; MAKE_EAB_DED(dreg); dest = RBYTE(ea)
+#define GET_DB_IX GET_DREG; MAKE_EAB_IX(dreg); dest = RBYTE(ea)
+#define GET_DB_IXD GET_DREG; MAKE_EAB_IXD(dreg); dest = RBYTE(ea)
+
+/* for a word-sized destination operand: extracts 'dreg', computes 'ea', and loads the value into 'dest' */
+#define GET_DW_RG GET_DREG; dest = REGD(dreg)
+#define GET_DW_RGD GET_DREG; MAKE_EAW_RGD(dreg); dest = RWORD(ea)
+#define GET_DW_IN GET_DREG; MAKE_EAW_IN(dreg); dest = RWORD(ea)
+#define GET_DW_IND GET_DREG; if (dreg == 7) { ea = ROPCODE(); } else { MAKE_EAW_IND(dreg); } dest = RWORD(ea)
+#define GET_DW_DE GET_DREG; MAKE_EAW_DE(dreg); dest = RWORD(ea)
+#define GET_DW_DED GET_DREG; MAKE_EAW_DED(dreg); dest = RWORD(ea)
+#define GET_DW_IX GET_DREG; MAKE_EAW_IX(dreg); dest = RWORD(ea)
+#define GET_DW_IXD GET_DREG; MAKE_EAW_IXD(dreg); dest = RWORD(ea)
+
+/* writes a value to a previously computed 'ea' */
+#define PUT_DB_EA(v) WBYTE(ea, (v))
+#define PUT_DW_EA(v) WWORD(ea, (v))
+
+/* writes a value to a previously computed 'dreg' register */
+#define PUT_DB_DREG(v) REGB(dreg) = (v)
+#define PUT_DW_DREG(v) REGW(dreg) = (v)
+
+/* for a byte-sized destination operand: extracts 'dreg', computes 'ea', and writes 'v' to it */
+#define PUT_DB_RG(v) GET_DREG; REGB(dreg) = (v)
+#define PUT_DB_RGD(v) GET_DREG; MAKE_EAB_RGD(dreg); WBYTE(ea, (v))
+#define PUT_DB_IN(v) GET_DREG; MAKE_EAB_IN(dreg); WBYTE(ea, (v))
+#define PUT_DB_IND(v) GET_DREG; if (dreg == 7) { ea = ROPCODE(); } else { MAKE_EAB_IND(dreg); } WBYTE(ea, (v))
+#define PUT_DB_DE(v) GET_DREG; MAKE_EAB_DE(dreg); WBYTE(ea, (v))
+#define PUT_DB_DED(v) GET_DREG; MAKE_EAB_DED(dreg); WBYTE(ea, (v))
+#define PUT_DB_IX(v) GET_DREG; MAKE_EAB_IX(dreg); WBYTE(ea, (v))
+#define PUT_DB_IXD(v) GET_DREG; MAKE_EAB_IXD(dreg); WBYTE(ea, (v))
+
+/* for a word-sized destination operand: extracts 'dreg', computes 'ea', and writes 'v' to it */
+#define PUT_DW_RG(v) GET_DREG; REGW(dreg) = (v)
+#define PUT_DW_RGD(v) GET_DREG; MAKE_EAW_RGD(dreg); WWORD(ea, (v))
+#define PUT_DW_IN(v) GET_DREG; MAKE_EAW_IN(dreg); WWORD(ea, (v))
+#define PUT_DW_IND(v) GET_DREG; if (dreg == 7) { ea = ROPCODE(); } else { MAKE_EAW_IND(dreg); } WWORD(ea, (v))
+#define PUT_DW_DE(v) GET_DREG; MAKE_EAW_DE(dreg); WWORD(ea, (v))
+#define PUT_DW_DED(v) GET_DREG; MAKE_EAW_DED(dreg); WWORD(ea, (v))
+#define PUT_DW_IX(v) GET_DREG; MAKE_EAW_IX(dreg); WWORD(ea, (v))
+#define PUT_DW_IXD(v) GET_DREG; MAKE_EAW_IXD(dreg); WWORD(ea, (v))
+
+/* flag clearing; must be done before setting */
+#define CLR_ZV (PSW &= ~(ZFLAG | VFLAG))
+#define CLR_NZV (PSW &= ~(NFLAG | ZFLAG | VFLAG))
+#define CLR_NZVC (PSW &= ~(NFLAG | ZFLAG | VFLAG | CFLAG))
+
+/* set individual flags byte-sized */
+#define SETB_N (PSW |= (result >> 4) & 0x08)
+#define SETB_Z (PSW |= ((result & 0xff) == 0) << 2)
+#define SETB_V (PSW |= ((source ^ dest ^ result ^ (result >> 1)) >> 6) & 0x02)
+#define SETB_C (PSW |= (result >> 8) & 0x01)
+#define SETB_NZ SETB_N; SETB_Z
+#define SETB_NZV SETB_N; SETB_Z; SETB_V
+#define SETB_NZVC SETB_N; SETB_Z; SETB_V; SETB_C
+
+/* set individual flags word-sized */
+#define SETW_N (PSW |= (result >> 12) & 0x08)
+#define SETW_Z (PSW |= ((result & 0xffff) == 0) << 2)
+#define SETW_V (PSW |= ((source ^ dest ^ result ^ (result >> 1)) >> 14) & 0x02)
+#define SETW_C (PSW |= (result >> 16) & 0x01)
+#define SETW_NZ SETW_N; SETW_Z
+#define SETW_NZV SETW_N; SETW_Z; SETW_V
+#define SETW_NZVC SETW_N; SETW_Z; SETW_V; SETW_C
+
+/* operations */
+/* ADC: dst += C */
+#define ADC_R(d) int dreg, source, dest, result; source = GET_C; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_DREG(result)
+#define ADC_M(d) int dreg, source, dest, result, ea; source = GET_C; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_EA(result)
+#define ADCB_R(d) int dreg, source, dest, result; source = GET_C; GET_DB_##d; CLR_NZVC; result = dest + source; SETB_NZVC; PUT_DB_DREG(result)
+#define ADCB_M(d) int dreg, source, dest, result, ea; source = GET_C; GET_DB_##d; CLR_NZVC; result = dest + source; SETB_NZVC; PUT_DB_EA(result)
+/* ADD: dst += src */
+#define ADD_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_DREG(result)
+#define ADD_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_DREG(result)
+#define ADD_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_EA(result)
+/* ASL: dst = (dst << 1); C = (dst >> 7) */
+#define ASL_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = dest << 1; SETW_NZ; PSW |= (dest >> 15) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_DREG(result)
+#define ASL_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = dest << 1; SETW_NZ; PSW |= (dest >> 15) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_EA(result)
+#define ASLB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = dest << 1; SETB_NZ; PSW |= (dest >> 7) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_DREG(result)
+#define ASLB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = dest << 1; SETB_NZ; PSW |= (dest >> 7) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_EA(result)
+/* ASR: dst = (dst << 1); C = (dst >> 7) */
+#define ASR_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = (dest >> 1) | (dest & 0x8000); SETW_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_DREG(result)
+#define ASR_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = (dest >> 1) | (dest & 0x8000); SETW_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_EA(result)
+#define ASRB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = (dest >> 1) | (dest & 0x80); SETB_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_DREG(result)
+#define ASRB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = (dest >> 1) | (dest & 0x80); SETB_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_EA(result)
+/* BIC: dst &= ~src */
+#define BIC_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & ~source; SETW_NZ; PUT_DW_DREG(result)
+#define BIC_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & ~source; SETW_NZ; PUT_DW_DREG(result)
+#define BIC_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & ~source; SETW_NZ; PUT_DW_EA(result)
+#define BICB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & ~source; SETB_NZ; PUT_DB_DREG(result)
+#define BICB_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & ~source; SETB_NZ; PUT_DB_DREG(result)
+#define BICB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & ~source; SETB_NZ; PUT_DB_EA(result)
+/* BIS: dst |= src */
+#define BIS_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest | source; SETW_NZ; PUT_DW_DREG(result)
+#define BIS_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest | source; SETW_NZ; PUT_DW_DREG(result)
+#define BIS_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest | source; SETW_NZ; PUT_DW_EA(result)
+#define BISB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest | source; SETB_NZ; PUT_DB_DREG(result)
+#define BISB_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest | source; SETB_NZ; PUT_DB_DREG(result)
+#define BISB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest | source; SETB_NZ; PUT_DB_EA(result)
+/* BIT: flags = dst & src */
+#define BIT_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & source; SETW_NZ;
+#define BIT_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & source; SETW_NZ;
+#define BITB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & source; SETB_NZ;
+#define BITB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & source; SETB_NZ;
+/* BR: if (condition) branch */
+#define BR(c) if (c) { PC += 2 * (signed char)(t11.op & 0xff); }
+/* CLR: dst = 0 */
+#define CLR_R(d) int dreg; PUT_DW_##d(0); CLR_NZVC; SET_Z
+#define CLR_M(d) int dreg, ea; PUT_DW_##d(0); CLR_NZVC; SET_Z
+#define CLRB_R(d) int dreg; PUT_DB_##d(0); CLR_NZVC; SET_Z
+#define CLRB_M(d) int dreg, ea; PUT_DB_##d(0); CLR_NZVC; SET_Z
+/* CMP: flags = src - dst */
+#define CMP_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = source - dest; SETW_NZVC;
+#define CMP_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = source - dest; SETW_NZVC;
+#define CMPB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = source - dest; SETB_NZVC;
+#define CMPB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = source - dest; SETB_NZVC;
+/* COM: dst = ~dst */
+#define COM_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = ~dest; SETW_NZ; SET_C; PUT_DW_DREG(result)
+#define COM_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = ~dest; SETW_NZ; SET_C; PUT_DW_EA(result)
+#define COMB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = ~dest; SETB_NZ; SET_C; PUT_DB_DREG(result)
+#define COMB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = ~dest; SETB_NZ; SET_C; PUT_DB_EA(result)
+/* DEC: dst -= 1 */
+#define DEC_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZV; result = dest - 1; SETW_NZ; if (dest == 0x8000) SET_V; PUT_DW_DREG(result)
+#define DEC_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZV; result = dest - 1; SETW_NZ; if (dest == 0x8000) SET_V; PUT_DW_EA(result)
+#define DECB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZV; result = dest - 1; SETB_NZ; if (dest == 0x80) SET_V; PUT_DB_DREG(result)
+#define DECB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZV; result = dest - 1; SETB_NZ; if (dest == 0x80) SET_V; PUT_DB_EA(result)
+/* INC: dst += 1 */
+#define INC_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZV; result = dest + 1; SETW_NZ; if (dest == 0x7fff) SET_V; PUT_DW_DREG(result)
+#define INC_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZV; result = dest + 1; SETW_NZ; if (dest == 0x7fff) SET_V; PUT_DW_EA(result)
+#define INCB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZV; result = dest + 1; SETB_NZ; if (dest == 0x7f) SET_V; PUT_DB_DREG(result)
+#define INCB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZV; result = dest + 1; SETB_NZ; if (dest == 0x7f) SET_V; PUT_DB_EA(result)
+/* JMP: PC = ea */
+#define JMP(d) int dreg, ea; GET_DREG; MAKE_EAW_##d(dreg); PC = ea; change_pc(PC)
+/* JSR: PUSH src, src = PC, PC = ea */
+#define JSR(d) int sreg, dreg, ea; GET_SREG; GET_DREG; MAKE_EAW_##d(dreg); PUSH(REGW(sreg)); REGW(sreg) = PC; PC = ea; change_pc(PC)
+/* MFPS: dst = flags */
+#define MFPS_R(d) int dreg, result; result = PSW; CLR_NZV; SETB_NZ; PUT_DW_##d((signed char)result)
+#define MFPS_M(d) int dreg, result, ea; result = PSW; CLR_NZV; SETB_NZ; PUT_DB_##d(result)
+/* MOV: dst = src */
+#define MOV_R(s,d) int sreg, dreg, source, result; GET_SW_##s; CLR_NZV; result = source; SETW_NZ; PUT_DW_##d(result)
+#define MOV_M(s,d) int sreg, dreg, source, result, ea; GET_SW_##s; CLR_NZV; result = source; SETW_NZ; PUT_DW_##d(result)
+#define MOVB_R(s,d) int sreg, dreg, source, result; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DW_##d((signed char)result)
+#define MOVB_X(s,d) int sreg, dreg, source, result, ea; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DW_##d((signed char)result)
+#define MOVB_M(s,d) int sreg, dreg, source, result, ea; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DB_##d(result)
+/* MTPS: flags = src */
+#define MTPS_R(d) int dreg, dest; GET_DW_##d; PSW = (PSW & ~0xef) | (dest & 0xef); t11_check_irqs()
+#define MTPS_M(d) int dreg, dest, ea; GET_DW_##d; PSW = (PSW & ~0xef) | (dest & 0xef); t11_check_irqs()
+/* NEG: dst = -dst */
+#define NEG_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = -dest; SETW_NZ; if (dest == 0x8000) SET_V; if (result) SET_C; PUT_DW_DREG(result)
+#define NEG_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = -dest; SETW_NZ; if (dest == 0x8000) SET_V; if (result) SET_C; PUT_DW_EA(result)
+#define NEGB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = -dest; SETB_NZ; if (dest == 0x80) SET_V; if (result) SET_C; PUT_DB_DREG(result)
+#define NEGB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = -dest; SETB_NZ; if (dest == 0x80) SET_V; if (result) SET_C; PUT_DB_EA(result)
+/* ROL: dst = (dst << 1) | C; C = (dst >> 7) */
+#define ROL_R(d) int dreg, dest, result; GET_DW_##d; result = (dest << 1) | GET_C; CLR_NZVC; SETW_NZ; PSW |= (dest >> 15) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_DREG(result)
+#define ROL_M(d) int dreg, dest, result, ea; GET_DW_##d; result = (dest << 1) | GET_C; CLR_NZVC; SETW_NZ; PSW |= (dest >> 15) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_EA(result)
+#define ROLB_R(d) int dreg, dest, result; GET_DB_##d; result = (dest << 1) | GET_C; CLR_NZVC; SETB_NZ; PSW |= (dest >> 7) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_DREG(result)
+#define ROLB_M(d) int dreg, dest, result, ea; GET_DB_##d; result = (dest << 1) | GET_C; CLR_NZVC; SETB_NZ; PSW |= (dest >> 7) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_EA(result)
+/* ROR: dst = (dst >> 1) | (C << 7); C = dst & 1 */
+#define ROR_R(d) int dreg, dest, result; GET_DW_##d; result = (dest >> 1) | (GET_C << 15); CLR_NZVC; SETW_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_DREG(result)
+#define ROR_M(d) int dreg, dest, result, ea; GET_DW_##d; result = (dest >> 1) | (GET_C << 15); CLR_NZVC; SETW_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_EA(result)
+#define RORB_R(d) int dreg, dest, result; GET_DB_##d; result = (dest >> 1) | (GET_C << 7); CLR_NZVC; SETB_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_DREG(result)
+#define RORB_M(d) int dreg, dest, result, ea; GET_DB_##d; result = (dest >> 1) | (GET_C << 7); CLR_NZVC; SETB_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_EA(result)
+/* SBC: dst -= C */
+#define SBC_R(d) int dreg, source, dest, result; source = GET_C; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_DREG(result)
+#define SBC_M(d) int dreg, source, dest, result, ea; source = GET_C; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_EA(result)
+#define SBCB_R(d) int dreg, source, dest, result; source = GET_C; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_DREG(result)
+#define SBCB_M(d) int dreg, source, dest, result, ea; source = GET_C; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_EA(result)
+/* SUB: dst -= src */
+#define SUB_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_DREG(result)
+#define SUB_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_DREG(result)
+#define SUB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_EA(result)
+#define SUBB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_DREG(result)
+#define SUBB_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_DREG(result)
+#define SUBB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_EA(result)
+/* SWAB: dst = (dst >> 8) + (dst << 8) */
+#define SWAB_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = ((dest >> 8) & 0xff) + (dest << 8); SETB_NZ; PUT_DW_DREG(result)
+#define SWAB_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = ((dest >> 8) & 0xff) + (dest << 8); SETB_NZ; PUT_DW_EA(result)
+/* SXT: dst = sign-extend dst */
+#define SXT_R(d) int dreg, result; CLR_ZV; if (GET_N) result = -1; else { result = 0; SET_Z; } PUT_DW_##d(result)
+#define SXT_M(d) int dreg, result, ea; CLR_ZV; if (GET_N) result = -1; else { result = 0; SET_Z; } PUT_DW_##d(result)
+/* TST: dst = ~dst */
+#define TST_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = dest; SETW_NZ;
+#define TST_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = dest; SETW_NZ;
+#define TSTB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = dest; SETB_NZ;
+#define TSTB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = dest; SETB_NZ;
+/* XOR: dst ^= src */
+#define XOR_R(d) int sreg, dreg, source, dest, result; GET_SREG; source = REGW(sreg); GET_DW_##d; CLR_NZV; result = dest ^ source; SETW_NZ; PUT_DW_DREG(result)
+#define XOR_M(d) int sreg, dreg, source, dest, result, ea; GET_SREG; source = REGW(sreg); GET_DW_##d; CLR_NZV; result = dest ^ source; SETW_NZ; PUT_DW_EA(result)
+
+
+
+static void op_0000(void)
+{
+ switch (t11.op & 0x3f)
+ {
+ case 0x00: /* HALT */ t11_ICount = 0; break;
+ case 0x01: /* WAIT */ t11_ICount = 0; t11.wait_state = 1; break;
+ case 0x02: /* RTI */ t11_ICount -= 24; PC = POP(); PSW = POP(); change_pc(PC); t11_check_irqs(); break;
+ case 0x03: /* BPT */ t11_ICount -= 48; PUSH(PSW); PUSH(PC); PC = RWORD(0x0c); PSW = RWORD(0x0e); change_pc(PC); t11_check_irqs(); break;
+ case 0x04: /* IOT */ t11_ICount -= 48; PUSH(PSW); PUSH(PC); PC = RWORD(0x10); PSW = RWORD(0x12); change_pc(PC); t11_check_irqs(); break;
+ case 0x05: /* RESET */ t11_ICount -= 110; break;
+ case 0x06: /* RTT */ t11_ICount -= 33; PC = POP(); PSW = POP(); change_pc(PC); t11_check_irqs(); break;
+ default: illegal(); break;
+ }
+}
+
+static void illegal(void)
+{
+ t11_ICount -= 48;
+ PUSH(PSW);
+ PUSH(PC);
+ PC = RWORD(0x08);
+ PSW = RWORD(0x0a);
+ change_pc(PC);
+ t11_check_irqs();
+PC = 0;
+}
+
+static void jmp_rgd(void) { t11_ICount -= 15; { JMP(RGD); } }
+static void jmp_in(void) { t11_ICount -= 18; { JMP(IN); } }
+static void jmp_ind(void) { t11_ICount -= 18; { JMP(IND); } }
+static void jmp_de(void) { t11_ICount -= 18; { JMP(DE); } }
+static void jmp_ded(void) { t11_ICount -= 21; { JMP(DED); } }
+static void jmp_ix(void) { t11_ICount -= 21; { JMP(IX); } }
+static void jmp_ixd(void) { t11_ICount -= 27; { JMP(IXD); } }
+
+static void rts(void)
+{
+ int dreg;
+ t11_ICount -= 21;
+ GET_DREG;
+ PC = REGD(dreg);
+ REGW(dreg) = POP();
+ change_pc(PC);
+}
+
+static void ccc(void) { t11_ICount -= 18; { PSW &= ~(t11.op & 15); } }
+static void scc(void) { t11_ICount -= 18; { PSW |= (t11.op & 15); } }
+
+static void swab_rg(void) { t11_ICount -= 12; { SWAB_R(RG); } }
+static void swab_rgd(void) { t11_ICount -= 21; { SWAB_M(RGD); } }
+static void swab_in(void) { t11_ICount -= 21; { SWAB_M(IN); } }
+static void swab_ind(void) { t11_ICount -= 27; { SWAB_M(IND); } }
+static void swab_de(void) { t11_ICount -= 24; { SWAB_M(DE); } }
+static void swab_ded(void) { t11_ICount -= 30; { SWAB_M(DED); } }
+static void swab_ix(void) { t11_ICount -= 30; { SWAB_M(IX); } }
+static void swab_ixd(void) { t11_ICount -= 36; { SWAB_M(IXD); } }
+
+static void br(void) { t11_ICount -= 12; { BR(1); } }
+static void bne(void) { t11_ICount -= 12; { BR(!GET_Z); } }
+static void beq(void) { t11_ICount -= 12; { BR( GET_Z); } }
+static void bge(void) { t11_ICount -= 12; { BR(!((GET_N >> 2) ^ GET_V)); } }
+static void blt(void) { t11_ICount -= 12; { BR(((GET_N >> 2) ^ GET_V)); } }
+static void bgt(void) { t11_ICount -= 12; { BR(!GET_Z && !((GET_N >> 2) ^ GET_V)); } }
+static void ble(void) { t11_ICount -= 12; { BR( GET_Z || ((GET_N >> 2) ^ GET_V)); } }
+
+static void jsr_rgd(void) { t11_ICount -= 27; { JSR(RGD); } }
+static void jsr_in(void) { t11_ICount -= 30; { JSR(IN); } }
+static void jsr_ind(void) { t11_ICount -= 30; { JSR(IND); } }
+static void jsr_de(void) { t11_ICount -= 30; { JSR(DE); } }
+static void jsr_ded(void) { t11_ICount -= 33; { JSR(DED); } }
+static void jsr_ix(void) { t11_ICount -= 33; { JSR(IX); } }
+static void jsr_ixd(void) { t11_ICount -= 39; { JSR(IXD); } }
+
+static void clr_rg(void) { t11_ICount -= 12; { CLR_R(RG); } }
+static void clr_rgd(void) { t11_ICount -= 21; { CLR_M(RGD); } }
+static void clr_in(void) { t11_ICount -= 21; { CLR_M(IN); } }
+static void clr_ind(void) { t11_ICount -= 27; { CLR_M(IND); } }
+static void clr_de(void) { t11_ICount -= 24; { CLR_M(DE); } }
+static void clr_ded(void) { t11_ICount -= 30; { CLR_M(DED); } }
+static void clr_ix(void) { t11_ICount -= 30; { CLR_M(IX); } }
+static void clr_ixd(void) { t11_ICount -= 36; { CLR_M(IXD); } }
+
+static void com_rg(void) { t11_ICount -= 12; { COM_R(RG); } }
+static void com_rgd(void) { t11_ICount -= 21; { COM_M(RGD); } }
+static void com_in(void) { t11_ICount -= 21; { COM_M(IN); } }
+static void com_ind(void) { t11_ICount -= 27; { COM_M(IND); } }
+static void com_de(void) { t11_ICount -= 24; { COM_M(DE); } }
+static void com_ded(void) { t11_ICount -= 30; { COM_M(DED); } }
+static void com_ix(void) { t11_ICount -= 30; { COM_M(IX); } }
+static void com_ixd(void) { t11_ICount -= 36; { COM_M(IXD); } }
+
+static void inc_rg(void) { t11_ICount -= 12; { INC_R(RG); } }
+static void inc_rgd(void) { t11_ICount -= 21; { INC_M(RGD); } }
+static void inc_in(void) { t11_ICount -= 21; { INC_M(IN); } }
+static void inc_ind(void) { t11_ICount -= 27; { INC_M(IND); } }
+static void inc_de(void) { t11_ICount -= 24; { INC_M(DE); } }
+static void inc_ded(void) { t11_ICount -= 30; { INC_M(DED); } }
+static void inc_ix(void) { t11_ICount -= 30; { INC_M(IX); } }
+static void inc_ixd(void) { t11_ICount -= 36; { INC_M(IXD); } }
+
+static void dec_rg(void) { t11_ICount -= 12; { DEC_R(RG); } }
+static void dec_rgd(void) { t11_ICount -= 21; { DEC_M(RGD); } }
+static void dec_in(void) { t11_ICount -= 21; { DEC_M(IN); } }
+static void dec_ind(void) { t11_ICount -= 27; { DEC_M(IND); } }
+static void dec_de(void) { t11_ICount -= 24; { DEC_M(DE); } }
+static void dec_ded(void) { t11_ICount -= 30; { DEC_M(DED); } }
+static void dec_ix(void) { t11_ICount -= 30; { DEC_M(IX); } }
+static void dec_ixd(void) { t11_ICount -= 36; { DEC_M(IXD); } }
+
+static void neg_rg(void) { t11_ICount -= 12; { NEG_R(RG); } }
+static void neg_rgd(void) { t11_ICount -= 21; { NEG_M(RGD); } }
+static void neg_in(void) { t11_ICount -= 21; { NEG_M(IN); } }
+static void neg_ind(void) { t11_ICount -= 27; { NEG_M(IND); } }
+static void neg_de(void) { t11_ICount -= 24; { NEG_M(DE); } }
+static void neg_ded(void) { t11_ICount -= 30; { NEG_M(DED); } }
+static void neg_ix(void) { t11_ICount -= 30; { NEG_M(IX); } }
+static void neg_ixd(void) { t11_ICount -= 36; { NEG_M(IXD); } }
+
+static void adc_rg(void) { t11_ICount -= 12; { ADC_R(RG); } }
+static void adc_rgd(void) { t11_ICount -= 21; { ADC_M(RGD); } }
+static void adc_in(void) { t11_ICount -= 21; { ADC_M(IN); } }
+static void adc_ind(void) { t11_ICount -= 27; { ADC_M(IND); } }
+static void adc_de(void) { t11_ICount -= 24; { ADC_M(DE); } }
+static void adc_ded(void) { t11_ICount -= 30; { ADC_M(DED); } }
+static void adc_ix(void) { t11_ICount -= 30; { ADC_M(IX); } }
+static void adc_ixd(void) { t11_ICount -= 36; { ADC_M(IXD); } }
+
+static void sbc_rg(void) { t11_ICount -= 12; { SBC_R(RG); } }
+static void sbc_rgd(void) { t11_ICount -= 21; { SBC_M(RGD); } }
+static void sbc_in(void) { t11_ICount -= 21; { SBC_M(IN); } }
+static void sbc_ind(void) { t11_ICount -= 27; { SBC_M(IND); } }
+static void sbc_de(void) { t11_ICount -= 24; { SBC_M(DE); } }
+static void sbc_ded(void) { t11_ICount -= 30; { SBC_M(DED); } }
+static void sbc_ix(void) { t11_ICount -= 30; { SBC_M(IX); } }
+static void sbc_ixd(void) { t11_ICount -= 36; { SBC_M(IXD); } }
+
+static void tst_rg(void) { t11_ICount -= 12; { TST_R(RG); } }
+static void tst_rgd(void) { t11_ICount -= 18; { TST_M(RGD); } }
+static void tst_in(void) { t11_ICount -= 18; { TST_M(IN); } }
+static void tst_ind(void) { t11_ICount -= 24; { TST_M(IND); } }
+static void tst_de(void) { t11_ICount -= 21; { TST_M(DE); } }
+static void tst_ded(void) { t11_ICount -= 27; { TST_M(DED); } }
+static void tst_ix(void) { t11_ICount -= 27; { TST_M(IX); } }
+static void tst_ixd(void) { t11_ICount -= 33; { TST_M(IXD); } }
+
+static void ror_rg(void) { t11_ICount -= 12; { ROR_R(RG); } }
+static void ror_rgd(void) { t11_ICount -= 21; { ROR_M(RGD); } }
+static void ror_in(void) { t11_ICount -= 21; { ROR_M(IN); } }
+static void ror_ind(void) { t11_ICount -= 27; { ROR_M(IND); } }
+static void ror_de(void) { t11_ICount -= 24; { ROR_M(DE); } }
+static void ror_ded(void) { t11_ICount -= 30; { ROR_M(DED); } }
+static void ror_ix(void) { t11_ICount -= 30; { ROR_M(IX); } }
+static void ror_ixd(void) { t11_ICount -= 36; { ROR_M(IXD); } }
+
+static void rol_rg(void) { t11_ICount -= 12; { ROL_R(RG); } }
+static void rol_rgd(void) { t11_ICount -= 21; { ROL_M(RGD); } }
+static void rol_in(void) { t11_ICount -= 21; { ROL_M(IN); } }
+static void rol_ind(void) { t11_ICount -= 27; { ROL_M(IND); } }
+static void rol_de(void) { t11_ICount -= 24; { ROL_M(DE); } }
+static void rol_ded(void) { t11_ICount -= 30; { ROL_M(DED); } }
+static void rol_ix(void) { t11_ICount -= 30; { ROL_M(IX); } }
+static void rol_ixd(void) { t11_ICount -= 36; { ROL_M(IXD); } }
+
+static void asr_rg(void) { t11_ICount -= 12; { ASR_R(RG); } }
+static void asr_rgd(void) { t11_ICount -= 21; { ASR_M(RGD); } }
+static void asr_in(void) { t11_ICount -= 21; { ASR_M(IN); } }
+static void asr_ind(void) { t11_ICount -= 27; { ASR_M(IND); } }
+static void asr_de(void) { t11_ICount -= 24; { ASR_M(DE); } }
+static void asr_ded(void) { t11_ICount -= 30; { ASR_M(DED); } }
+static void asr_ix(void) { t11_ICount -= 30; { ASR_M(IX); } }
+static void asr_ixd(void) { t11_ICount -= 36; { ASR_M(IXD); } }
+
+static void asl_rg(void) { t11_ICount -= 12; { ASL_R(RG); } }
+static void asl_rgd(void) { t11_ICount -= 21; { ASL_M(RGD); } }
+static void asl_in(void) { t11_ICount -= 21; { ASL_M(IN); } }
+static void asl_ind(void) { t11_ICount -= 27; { ASL_M(IND); } }
+static void asl_de(void) { t11_ICount -= 24; { ASL_M(DE); } }
+static void asl_ded(void) { t11_ICount -= 30; { ASL_M(DED); } }
+static void asl_ix(void) { t11_ICount -= 30; { ASL_M(IX); } }
+static void asl_ixd(void) { t11_ICount -= 36; { ASL_M(IXD); } }
+
+static void sxt_rg(void) { t11_ICount -= 12; { SXT_R(RG); } }
+static void sxt_rgd(void) { t11_ICount -= 21; { SXT_M(RGD); } }
+static void sxt_in(void) { t11_ICount -= 21; { SXT_M(IN); } }
+static void sxt_ind(void) { t11_ICount -= 27; { SXT_M(IND); } }
+static void sxt_de(void) { t11_ICount -= 24; { SXT_M(DE); } }
+static void sxt_ded(void) { t11_ICount -= 30; { SXT_M(DED); } }
+static void sxt_ix(void) { t11_ICount -= 30; { SXT_M(IX); } }
+static void sxt_ixd(void) { t11_ICount -= 36; { SXT_M(IXD); } }
+
+static void mov_rg_rg(void) { t11_ICount -= 9+ 3; { MOV_R(RG,RG); } }
+static void mov_rg_rgd(void) { t11_ICount -= 9+12; { MOV_M(RG,RGD); } }
+static void mov_rg_in(void) { t11_ICount -= 9+12; { MOV_M(RG,IN); } }
+static void mov_rg_ind(void) { t11_ICount -= 9+18; { MOV_M(RG,IND); } }
+static void mov_rg_de(void) { t11_ICount -= 9+15; { MOV_M(RG,DE); } }
+static void mov_rg_ded(void) { t11_ICount -= 9+21; { MOV_M(RG,DED); } }
+static void mov_rg_ix(void) { t11_ICount -= 9+21; { MOV_M(RG,IX); } }
+static void mov_rg_ixd(void) { t11_ICount -= 9+27; { MOV_M(RG,IXD); } }
+static void mov_rgd_rg(void) { t11_ICount -= 15+ 3; { MOV_M(RGD,RG); } }
+static void mov_rgd_rgd(void) { t11_ICount -= 15+12; { MOV_M(RGD,RGD); } }
+static void mov_rgd_in(void) { t11_ICount -= 15+12; { MOV_M(RGD,IN); } }
+static void mov_rgd_ind(void) { t11_ICount -= 15+18; { MOV_M(RGD,IND); } }
+static void mov_rgd_de(void) { t11_ICount -= 15+15; { MOV_M(RGD,DE); } }
+static void mov_rgd_ded(void) { t11_ICount -= 15+21; { MOV_M(RGD,DED); } }
+static void mov_rgd_ix(void) { t11_ICount -= 15+21; { MOV_M(RGD,IX); } }
+static void mov_rgd_ixd(void) { t11_ICount -= 15+27; { MOV_M(RGD,IXD); } }
+static void mov_in_rg(void) { t11_ICount -= 15+ 3; { MOV_M(IN,RG); } }
+static void mov_in_rgd(void) { t11_ICount -= 15+12; { MOV_M(IN,RGD); } }
+static void mov_in_in(void) { t11_ICount -= 15+12; { MOV_M(IN,IN); } }
+static void mov_in_ind(void) { t11_ICount -= 15+18; { MOV_M(IN,IND); } }
+static void mov_in_de(void) { t11_ICount -= 15+15; { MOV_M(IN,DE); } }
+static void mov_in_ded(void) { t11_ICount -= 15+21; { MOV_M(IN,DED); } }
+static void mov_in_ix(void) { t11_ICount -= 15+21; { MOV_M(IN,IX); } }
+static void mov_in_ixd(void) { t11_ICount -= 15+27; { MOV_M(IN,IXD); } }
+static void mov_ind_rg(void) { t11_ICount -= 21+ 3; { MOV_M(IND,RG); } }
+static void mov_ind_rgd(void) { t11_ICount -= 21+12; { MOV_M(IND,RGD); } }
+static void mov_ind_in(void) { t11_ICount -= 21+12; { MOV_M(IND,IN); } }
+static void mov_ind_ind(void) { t11_ICount -= 21+18; { MOV_M(IND,IND); } }
+static void mov_ind_de(void) { t11_ICount -= 21+15; { MOV_M(IND,DE); } }
+static void mov_ind_ded(void) { t11_ICount -= 21+21; { MOV_M(IND,DED); } }
+static void mov_ind_ix(void) { t11_ICount -= 21+21; { MOV_M(IND,IX); } }
+static void mov_ind_ixd(void) { t11_ICount -= 21+27; { MOV_M(IND,IXD); } }
+static void mov_de_rg(void) { t11_ICount -= 18+ 3; { MOV_M(DE,RG); } }
+static void mov_de_rgd(void) { t11_ICount -= 18+12; { MOV_M(DE,RGD); } }
+static void mov_de_in(void) { t11_ICount -= 18+12; { MOV_M(DE,IN); } }
+static void mov_de_ind(void) { t11_ICount -= 18+18; { MOV_M(DE,IND); } }
+static void mov_de_de(void) { t11_ICount -= 18+15; { MOV_M(DE,DE); } }
+static void mov_de_ded(void) { t11_ICount -= 18+21; { MOV_M(DE,DED); } }
+static void mov_de_ix(void) { t11_ICount -= 18+21; { MOV_M(DE,IX); } }
+static void mov_de_ixd(void) { t11_ICount -= 18+27; { MOV_M(DE,IXD); } }
+static void mov_ded_rg(void) { t11_ICount -= 24+ 3; { MOV_M(DED,RG); } }
+static void mov_ded_rgd(void) { t11_ICount -= 24+12; { MOV_M(DED,RGD); } }
+static void mov_ded_in(void) { t11_ICount -= 24+12; { MOV_M(DED,IN); } }
+static void mov_ded_ind(void) { t11_ICount -= 24+18; { MOV_M(DED,IND); } }
+static void mov_ded_de(void) { t11_ICount -= 24+15; { MOV_M(DED,DE); } }
+static void mov_ded_ded(void) { t11_ICount -= 24+21; { MOV_M(DED,DED); } }
+static void mov_ded_ix(void) { t11_ICount -= 24+21; { MOV_M(DED,IX); } }
+static void mov_ded_ixd(void) { t11_ICount -= 24+27; { MOV_M(DED,IXD); } }
+static void mov_ix_rg(void) { t11_ICount -= 24+ 3; { MOV_M(IX,RG); } }
+static void mov_ix_rgd(void) { t11_ICount -= 24+12; { MOV_M(IX,RGD); } }
+static void mov_ix_in(void) { t11_ICount -= 24+12; { MOV_M(IX,IN); } }
+static void mov_ix_ind(void) { t11_ICount -= 24+18; { MOV_M(IX,IND); } }
+static void mov_ix_de(void) { t11_ICount -= 24+15; { MOV_M(IX,DE); } }
+static void mov_ix_ded(void) { t11_ICount -= 24+21; { MOV_M(IX,DED); } }
+static void mov_ix_ix(void) { t11_ICount -= 24+21; { MOV_M(IX,IX); } }
+static void mov_ix_ixd(void) { t11_ICount -= 24+27; { MOV_M(IX,IXD); } }
+static void mov_ixd_rg(void) { t11_ICount -= 30+ 3; { MOV_M(IXD,RG); } }
+static void mov_ixd_rgd(void) { t11_ICount -= 30+12; { MOV_M(IXD,RGD); } }
+static void mov_ixd_in(void) { t11_ICount -= 30+12; { MOV_M(IXD,IN); } }
+static void mov_ixd_ind(void) { t11_ICount -= 30+18; { MOV_M(IXD,IND); } }
+static void mov_ixd_de(void) { t11_ICount -= 30+15; { MOV_M(IXD,DE); } }
+static void mov_ixd_ded(void) { t11_ICount -= 30+21; { MOV_M(IXD,DED); } }
+static void mov_ixd_ix(void) { t11_ICount -= 30+21; { MOV_M(IXD,IX); } }
+static void mov_ixd_ixd(void) { t11_ICount -= 30+27; { MOV_M(IXD,IXD); } }
+
+static void cmp_rg_rg(void) { t11_ICount -= 9+ 3; { CMP_R(RG,RG); } }
+static void cmp_rg_rgd(void) { t11_ICount -= 9+ 9; { CMP_M(RG,RGD); } }
+static void cmp_rg_in(void) { t11_ICount -= 9+ 9; { CMP_M(RG,IN); } }
+static void cmp_rg_ind(void) { t11_ICount -= 9+15; { CMP_M(RG,IND); } }
+static void cmp_rg_de(void) { t11_ICount -= 9+12; { CMP_M(RG,DE); } }
+static void cmp_rg_ded(void) { t11_ICount -= 9+18; { CMP_M(RG,DED); } }
+static void cmp_rg_ix(void) { t11_ICount -= 9+18; { CMP_M(RG,IX); } }
+static void cmp_rg_ixd(void) { t11_ICount -= 9+24; { CMP_M(RG,IXD); } }
+static void cmp_rgd_rg(void) { t11_ICount -= 15+ 3; { CMP_M(RGD,RG); } }
+static void cmp_rgd_rgd(void) { t11_ICount -= 15+ 9; { CMP_M(RGD,RGD); } }
+static void cmp_rgd_in(void) { t11_ICount -= 15+ 9; { CMP_M(RGD,IN); } }
+static void cmp_rgd_ind(void) { t11_ICount -= 15+15; { CMP_M(RGD,IND); } }
+static void cmp_rgd_de(void) { t11_ICount -= 15+12; { CMP_M(RGD,DE); } }
+static void cmp_rgd_ded(void) { t11_ICount -= 15+18; { CMP_M(RGD,DED); } }
+static void cmp_rgd_ix(void) { t11_ICount -= 15+18; { CMP_M(RGD,IX); } }
+static void cmp_rgd_ixd(void) { t11_ICount -= 15+24; { CMP_M(RGD,IXD); } }
+static void cmp_in_rg(void) { t11_ICount -= 15+ 3; { CMP_M(IN,RG); } }
+static void cmp_in_rgd(void) { t11_ICount -= 15+ 9; { CMP_M(IN,RGD); } }
+static void cmp_in_in(void) { t11_ICount -= 15+ 9; { CMP_M(IN,IN); } }
+static void cmp_in_ind(void) { t11_ICount -= 15+15; { CMP_M(IN,IND); } }
+static void cmp_in_de(void) { t11_ICount -= 15+12; { CMP_M(IN,DE); } }
+static void cmp_in_ded(void) { t11_ICount -= 15+18; { CMP_M(IN,DED); } }
+static void cmp_in_ix(void) { t11_ICount -= 15+18; { CMP_M(IN,IX); } }
+static void cmp_in_ixd(void) { t11_ICount -= 15+24; { CMP_M(IN,IXD); } }
+static void cmp_ind_rg(void) { t11_ICount -= 21+ 3; { CMP_M(IND,RG); } }
+static void cmp_ind_rgd(void) { t11_ICount -= 21+ 9; { CMP_M(IND,RGD); } }
+static void cmp_ind_in(void) { t11_ICount -= 21+ 9; { CMP_M(IND,IN); } }
+static void cmp_ind_ind(void) { t11_ICount -= 21+15; { CMP_M(IND,IND); } }
+static void cmp_ind_de(void) { t11_ICount -= 21+12; { CMP_M(IND,DE); } }
+static void cmp_ind_ded(void) { t11_ICount -= 21+18; { CMP_M(IND,DED); } }
+static void cmp_ind_ix(void) { t11_ICount -= 21+18; { CMP_M(IND,IX); } }
+static void cmp_ind_ixd(void) { t11_ICount -= 21+24; { CMP_M(IND,IXD); } }
+static void cmp_de_rg(void) { t11_ICount -= 18+ 3; { CMP_M(DE,RG); } }
+static void cmp_de_rgd(void) { t11_ICount -= 18+ 9; { CMP_M(DE,RGD); } }
+static void cmp_de_in(void) { t11_ICount -= 18+ 9; { CMP_M(DE,IN); } }
+static void cmp_de_ind(void) { t11_ICount -= 18+15; { CMP_M(DE,IND); } }
+static void cmp_de_de(void) { t11_ICount -= 18+12; { CMP_M(DE,DE); } }
+static void cmp_de_ded(void) { t11_ICount -= 18+18; { CMP_M(DE,DED); } }
+static void cmp_de_ix(void) { t11_ICount -= 18+18; { CMP_M(DE,IX); } }
+static void cmp_de_ixd(void) { t11_ICount -= 18+24; { CMP_M(DE,IXD); } }
+static void cmp_ded_rg(void) { t11_ICount -= 24+ 3; { CMP_M(DED,RG); } }
+static void cmp_ded_rgd(void) { t11_ICount -= 24+ 9; { CMP_M(DED,RGD); } }
+static void cmp_ded_in(void) { t11_ICount -= 24+ 9; { CMP_M(DED,IN); } }
+static void cmp_ded_ind(void) { t11_ICount -= 24+15; { CMP_M(DED,IND); } }
+static void cmp_ded_de(void) { t11_ICount -= 24+12; { CMP_M(DED,DE); } }
+static void cmp_ded_ded(void) { t11_ICount -= 24+18; { CMP_M(DED,DED); } }
+static void cmp_ded_ix(void) { t11_ICount -= 24+18; { CMP_M(DED,IX); } }
+static void cmp_ded_ixd(void) { t11_ICount -= 24+24; { CMP_M(DED,IXD); } }
+static void cmp_ix_rg(void) { t11_ICount -= 24+ 3; { CMP_M(IX,RG); } }
+static void cmp_ix_rgd(void) { t11_ICount -= 24+ 9; { CMP_M(IX,RGD); } }
+static void cmp_ix_in(void) { t11_ICount -= 24+ 9; { CMP_M(IX,IN); } }
+static void cmp_ix_ind(void) { t11_ICount -= 24+15; { CMP_M(IX,IND); } }
+static void cmp_ix_de(void) { t11_ICount -= 24+12; { CMP_M(IX,DE); } }
+static void cmp_ix_ded(void) { t11_ICount -= 24+18; { CMP_M(IX,DED); } }
+static void cmp_ix_ix(void) { t11_ICount -= 24+18; { CMP_M(IX,IX); } }
+static void cmp_ix_ixd(void) { t11_ICount -= 24+24; { CMP_M(IX,IXD); } }
+static void cmp_ixd_rg(void) { t11_ICount -= 30+ 3; { CMP_M(IXD,RG); } }
+static void cmp_ixd_rgd(void) { t11_ICount -= 30+ 9; { CMP_M(IXD,RGD); } }
+static void cmp_ixd_in(void) { t11_ICount -= 30+ 9; { CMP_M(IXD,IN); } }
+static void cmp_ixd_ind(void) { t11_ICount -= 30+15; { CMP_M(IXD,IND); } }
+static void cmp_ixd_de(void) { t11_ICount -= 30+12; { CMP_M(IXD,DE); } }
+static void cmp_ixd_ded(void) { t11_ICount -= 30+18; { CMP_M(IXD,DED); } }
+static void cmp_ixd_ix(void) { t11_ICount -= 30+18; { CMP_M(IXD,IX); } }
+static void cmp_ixd_ixd(void) { t11_ICount -= 30+24; { CMP_M(IXD,IXD); } }
+
+static void bit_rg_rg(void) { t11_ICount -= 9+ 3; { BIT_R(RG,RG); } }
+static void bit_rg_rgd(void) { t11_ICount -= 9+ 9; { BIT_M(RG,RGD); } }
+static void bit_rg_in(void) { t11_ICount -= 9+ 9; { BIT_M(RG,IN); } }
+static void bit_rg_ind(void) { t11_ICount -= 9+15; { BIT_M(RG,IND); } }
+static void bit_rg_de(void) { t11_ICount -= 9+12; { BIT_M(RG,DE); } }
+static void bit_rg_ded(void) { t11_ICount -= 9+18; { BIT_M(RG,DED); } }
+static void bit_rg_ix(void) { t11_ICount -= 9+18; { BIT_M(RG,IX); } }
+static void bit_rg_ixd(void) { t11_ICount -= 9+24; { BIT_M(RG,IXD); } }
+static void bit_rgd_rg(void) { t11_ICount -= 15+ 3; { BIT_M(RGD,RG); } }
+static void bit_rgd_rgd(void) { t11_ICount -= 15+ 9; { BIT_M(RGD,RGD); } }
+static void bit_rgd_in(void) { t11_ICount -= 15+ 9; { BIT_M(RGD,IN); } }
+static void bit_rgd_ind(void) { t11_ICount -= 15+15; { BIT_M(RGD,IND); } }
+static void bit_rgd_de(void) { t11_ICount -= 15+12; { BIT_M(RGD,DE); } }
+static void bit_rgd_ded(void) { t11_ICount -= 15+18; { BIT_M(RGD,DED); } }
+static void bit_rgd_ix(void) { t11_ICount -= 15+18; { BIT_M(RGD,IX); } }
+static void bit_rgd_ixd(void) { t11_ICount -= 15+24; { BIT_M(RGD,IXD); } }
+static void bit_in_rg(void) { t11_ICount -= 15+ 3; { BIT_M(IN,RG); } }
+static void bit_in_rgd(void) { t11_ICount -= 15+ 9; { BIT_M(IN,RGD); } }
+static void bit_in_in(void) { t11_ICount -= 15+ 9; { BIT_M(IN,IN); } }
+static void bit_in_ind(void) { t11_ICount -= 15+15; { BIT_M(IN,IND); } }
+static void bit_in_de(void) { t11_ICount -= 15+12; { BIT_M(IN,DE); } }
+static void bit_in_ded(void) { t11_ICount -= 15+18; { BIT_M(IN,DED); } }
+static void bit_in_ix(void) { t11_ICount -= 15+18; { BIT_M(IN,IX); } }
+static void bit_in_ixd(void) { t11_ICount -= 15+24; { BIT_M(IN,IXD); } }
+static void bit_ind_rg(void) { t11_ICount -= 21+ 3; { BIT_M(IND,RG); } }
+static void bit_ind_rgd(void) { t11_ICount -= 21+ 9; { BIT_M(IND,RGD); } }
+static void bit_ind_in(void) { t11_ICount -= 21+ 9; { BIT_M(IND,IN); } }
+static void bit_ind_ind(void) { t11_ICount -= 21+15; { BIT_M(IND,IND); } }
+static void bit_ind_de(void) { t11_ICount -= 21+12; { BIT_M(IND,DE); } }
+static void bit_ind_ded(void) { t11_ICount -= 21+18; { BIT_M(IND,DED); } }
+static void bit_ind_ix(void) { t11_ICount -= 21+18; { BIT_M(IND,IX); } }
+static void bit_ind_ixd(void) { t11_ICount -= 21+24; { BIT_M(IND,IXD); } }
+static void bit_de_rg(void) { t11_ICount -= 18+ 3; { BIT_M(DE,RG); } }
+static void bit_de_rgd(void) { t11_ICount -= 18+ 9; { BIT_M(DE,RGD); } }
+static void bit_de_in(void) { t11_ICount -= 18+ 9; { BIT_M(DE,IN); } }
+static void bit_de_ind(void) { t11_ICount -= 18+15; { BIT_M(DE,IND); } }
+static void bit_de_de(void) { t11_ICount -= 18+12; { BIT_M(DE,DE); } }
+static void bit_de_ded(void) { t11_ICount -= 18+18; { BIT_M(DE,DED); } }
+static void bit_de_ix(void) { t11_ICount -= 18+18; { BIT_M(DE,IX); } }
+static void bit_de_ixd(void) { t11_ICount -= 18+24; { BIT_M(DE,IXD); } }
+static void bit_ded_rg(void) { t11_ICount -= 24+ 3; { BIT_M(DED,RG); } }
+static void bit_ded_rgd(void) { t11_ICount -= 24+ 9; { BIT_M(DED,RGD); } }
+static void bit_ded_in(void) { t11_ICount -= 24+ 9; { BIT_M(DED,IN); } }
+static void bit_ded_ind(void) { t11_ICount -= 24+15; { BIT_M(DED,IND); } }
+static void bit_ded_de(void) { t11_ICount -= 24+12; { BIT_M(DED,DE); } }
+static void bit_ded_ded(void) { t11_ICount -= 24+18; { BIT_M(DED,DED); } }
+static void bit_ded_ix(void) { t11_ICount -= 24+18; { BIT_M(DED,IX); } }
+static void bit_ded_ixd(void) { t11_ICount -= 24+24; { BIT_M(DED,IXD); } }
+static void bit_ix_rg(void) { t11_ICount -= 24+ 3; { BIT_M(IX,RG); } }
+static void bit_ix_rgd(void) { t11_ICount -= 24+ 9; { BIT_M(IX,RGD); } }
+static void bit_ix_in(void) { t11_ICount -= 24+ 9; { BIT_M(IX,IN); } }
+static void bit_ix_ind(void) { t11_ICount -= 24+15; { BIT_M(IX,IND); } }
+static void bit_ix_de(void) { t11_ICount -= 24+12; { BIT_M(IX,DE); } }
+static void bit_ix_ded(void) { t11_ICount -= 24+18; { BIT_M(IX,DED); } }
+static void bit_ix_ix(void) { t11_ICount -= 24+18; { BIT_M(IX,IX); } }
+static void bit_ix_ixd(void) { t11_ICount -= 24+24; { BIT_M(IX,IXD); } }
+static void bit_ixd_rg(void) { t11_ICount -= 30+ 3; { BIT_M(IXD,RG); } }
+static void bit_ixd_rgd(void) { t11_ICount -= 30+ 9; { BIT_M(IXD,RGD); } }
+static void bit_ixd_in(void) { t11_ICount -= 30+ 9; { BIT_M(IXD,IN); } }
+static void bit_ixd_ind(void) { t11_ICount -= 30+15; { BIT_M(IXD,IND); } }
+static void bit_ixd_de(void) { t11_ICount -= 30+12; { BIT_M(IXD,DE); } }
+static void bit_ixd_ded(void) { t11_ICount -= 30+18; { BIT_M(IXD,DED); } }
+static void bit_ixd_ix(void) { t11_ICount -= 30+18; { BIT_M(IXD,IX); } }
+static void bit_ixd_ixd(void) { t11_ICount -= 30+24; { BIT_M(IXD,IXD); } }
+
+static void bic_rg_rg(void) { t11_ICount -= 9+ 3; { BIC_R(RG,RG); } }
+static void bic_rg_rgd(void) { t11_ICount -= 9+12; { BIC_M(RG,RGD); } }
+static void bic_rg_in(void) { t11_ICount -= 9+12; { BIC_M(RG,IN); } }
+static void bic_rg_ind(void) { t11_ICount -= 9+18; { BIC_M(RG,IND); } }
+static void bic_rg_de(void) { t11_ICount -= 9+15; { BIC_M(RG,DE); } }
+static void bic_rg_ded(void) { t11_ICount -= 9+21; { BIC_M(RG,DED); } }
+static void bic_rg_ix(void) { t11_ICount -= 9+21; { BIC_M(RG,IX); } }
+static void bic_rg_ixd(void) { t11_ICount -= 9+27; { BIC_M(RG,IXD); } }
+static void bic_rgd_rg(void) { t11_ICount -= 15+ 3; { BIC_X(RGD,RG); } }
+static void bic_rgd_rgd(void) { t11_ICount -= 15+12; { BIC_M(RGD,RGD); } }
+static void bic_rgd_in(void) { t11_ICount -= 15+12; { BIC_M(RGD,IN); } }
+static void bic_rgd_ind(void) { t11_ICount -= 15+18; { BIC_M(RGD,IND); } }
+static void bic_rgd_de(void) { t11_ICount -= 15+15; { BIC_M(RGD,DE); } }
+static void bic_rgd_ded(void) { t11_ICount -= 15+21; { BIC_M(RGD,DED); } }
+static void bic_rgd_ix(void) { t11_ICount -= 15+21; { BIC_M(RGD,IX); } }
+static void bic_rgd_ixd(void) { t11_ICount -= 15+27; { BIC_M(RGD,IXD); } }
+static void bic_in_rg(void) { t11_ICount -= 15+ 3; { BIC_X(IN,RG); } }
+static void bic_in_rgd(void) { t11_ICount -= 15+12; { BIC_M(IN,RGD); } }
+static void bic_in_in(void) { t11_ICount -= 15+12; { BIC_M(IN,IN); } }
+static void bic_in_ind(void) { t11_ICount -= 15+18; { BIC_M(IN,IND); } }
+static void bic_in_de(void) { t11_ICount -= 15+15; { BIC_M(IN,DE); } }
+static void bic_in_ded(void) { t11_ICount -= 15+21; { BIC_M(IN,DED); } }
+static void bic_in_ix(void) { t11_ICount -= 15+21; { BIC_M(IN,IX); } }
+static void bic_in_ixd(void) { t11_ICount -= 15+27; { BIC_M(IN,IXD); } }
+static void bic_ind_rg(void) { t11_ICount -= 21+ 3; { BIC_X(IND,RG); } }
+static void bic_ind_rgd(void) { t11_ICount -= 21+12; { BIC_M(IND,RGD); } }
+static void bic_ind_in(void) { t11_ICount -= 21+12; { BIC_M(IND,IN); } }
+static void bic_ind_ind(void) { t11_ICount -= 21+18; { BIC_M(IND,IND); } }
+static void bic_ind_de(void) { t11_ICount -= 21+15; { BIC_M(IND,DE); } }
+static void bic_ind_ded(void) { t11_ICount -= 21+21; { BIC_M(IND,DED); } }
+static void bic_ind_ix(void) { t11_ICount -= 21+21; { BIC_M(IND,IX); } }
+static void bic_ind_ixd(void) { t11_ICount -= 21+27; { BIC_M(IND,IXD); } }
+static void bic_de_rg(void) { t11_ICount -= 18+ 3; { BIC_X(DE,RG); } }
+static void bic_de_rgd(void) { t11_ICount -= 18+12; { BIC_M(DE,RGD); } }
+static void bic_de_in(void) { t11_ICount -= 18+12; { BIC_M(DE,IN); } }
+static void bic_de_ind(void) { t11_ICount -= 18+18; { BIC_M(DE,IND); } }
+static void bic_de_de(void) { t11_ICount -= 18+15; { BIC_M(DE,DE); } }
+static void bic_de_ded(void) { t11_ICount -= 18+21; { BIC_M(DE,DED); } }
+static void bic_de_ix(void) { t11_ICount -= 18+21; { BIC_M(DE,IX); } }
+static void bic_de_ixd(void) { t11_ICount -= 18+27; { BIC_M(DE,IXD); } }
+static void bic_ded_rg(void) { t11_ICount -= 24+ 3; { BIC_X(DED,RG); } }
+static void bic_ded_rgd(void) { t11_ICount -= 24+12; { BIC_M(DED,RGD); } }
+static void bic_ded_in(void) { t11_ICount -= 24+12; { BIC_M(DED,IN); } }
+static void bic_ded_ind(void) { t11_ICount -= 24+18; { BIC_M(DED,IND); } }
+static void bic_ded_de(void) { t11_ICount -= 24+15; { BIC_M(DED,DE); } }
+static void bic_ded_ded(void) { t11_ICount -= 24+21; { BIC_M(DED,DED); } }
+static void bic_ded_ix(void) { t11_ICount -= 24+21; { BIC_M(DED,IX); } }
+static void bic_ded_ixd(void) { t11_ICount -= 24+27; { BIC_M(DED,IXD); } }
+static void bic_ix_rg(void) { t11_ICount -= 24+ 3; { BIC_X(IX,RG); } }
+static void bic_ix_rgd(void) { t11_ICount -= 24+12; { BIC_M(IX,RGD); } }
+static void bic_ix_in(void) { t11_ICount -= 24+12; { BIC_M(IX,IN); } }
+static void bic_ix_ind(void) { t11_ICount -= 24+18; { BIC_M(IX,IND); } }
+static void bic_ix_de(void) { t11_ICount -= 24+15; { BIC_M(IX,DE); } }
+static void bic_ix_ded(void) { t11_ICount -= 24+21; { BIC_M(IX,DED); } }
+static void bic_ix_ix(void) { t11_ICount -= 24+21; { BIC_M(IX,IX); } }
+static void bic_ix_ixd(void) { t11_ICount -= 24+27; { BIC_M(IX,IXD); } }
+static void bic_ixd_rg(void) { t11_ICount -= 30+ 3; { BIC_X(IXD,RG); } }
+static void bic_ixd_rgd(void) { t11_ICount -= 30+12; { BIC_M(IXD,RGD); } }
+static void bic_ixd_in(void) { t11_ICount -= 30+12; { BIC_M(IXD,IN); } }
+static void bic_ixd_ind(void) { t11_ICount -= 30+18; { BIC_M(IXD,IND); } }
+static void bic_ixd_de(void) { t11_ICount -= 30+15; { BIC_M(IXD,DE); } }
+static void bic_ixd_ded(void) { t11_ICount -= 30+21; { BIC_M(IXD,DED); } }
+static void bic_ixd_ix(void) { t11_ICount -= 30+21; { BIC_M(IXD,IX); } }
+static void bic_ixd_ixd(void) { t11_ICount -= 30+27; { BIC_M(IXD,IXD); } }
+
+static void bis_rg_rg(void) { t11_ICount -= 9+ 3; { BIS_R(RG,RG); } }
+static void bis_rg_rgd(void) { t11_ICount -= 9+12; { BIS_M(RG,RGD); } }
+static void bis_rg_in(void) { t11_ICount -= 9+12; { BIS_M(RG,IN); } }
+static void bis_rg_ind(void) { t11_ICount -= 9+18; { BIS_M(RG,IND); } }
+static void bis_rg_de(void) { t11_ICount -= 9+15; { BIS_M(RG,DE); } }
+static void bis_rg_ded(void) { t11_ICount -= 9+21; { BIS_M(RG,DED); } }
+static void bis_rg_ix(void) { t11_ICount -= 9+21; { BIS_M(RG,IX); } }
+static void bis_rg_ixd(void) { t11_ICount -= 9+27; { BIS_M(RG,IXD); } }
+static void bis_rgd_rg(void) { t11_ICount -= 15+ 3; { BIS_X(RGD,RG); } }
+static void bis_rgd_rgd(void) { t11_ICount -= 15+12; { BIS_M(RGD,RGD); } }
+static void bis_rgd_in(void) { t11_ICount -= 15+12; { BIS_M(RGD,IN); } }
+static void bis_rgd_ind(void) { t11_ICount -= 15+18; { BIS_M(RGD,IND); } }
+static void bis_rgd_de(void) { t11_ICount -= 15+15; { BIS_M(RGD,DE); } }
+static void bis_rgd_ded(void) { t11_ICount -= 15+21; { BIS_M(RGD,DED); } }
+static void bis_rgd_ix(void) { t11_ICount -= 15+21; { BIS_M(RGD,IX); } }
+static void bis_rgd_ixd(void) { t11_ICount -= 15+27; { BIS_M(RGD,IXD); } }
+static void bis_in_rg(void) { t11_ICount -= 15+ 3; { BIS_X(IN,RG); } }
+static void bis_in_rgd(void) { t11_ICount -= 15+12; { BIS_M(IN,RGD); } }
+static void bis_in_in(void) { t11_ICount -= 15+12; { BIS_M(IN,IN); } }
+static void bis_in_ind(void) { t11_ICount -= 15+18; { BIS_M(IN,IND); } }
+static void bis_in_de(void) { t11_ICount -= 15+15; { BIS_M(IN,DE); } }
+static void bis_in_ded(void) { t11_ICount -= 15+21; { BIS_M(IN,DED); } }
+static void bis_in_ix(void) { t11_ICount -= 15+21; { BIS_M(IN,IX); } }
+static void bis_in_ixd(void) { t11_ICount -= 15+27; { BIS_M(IN,IXD); } }
+static void bis_ind_rg(void) { t11_ICount -= 21+ 3; { BIS_X(IND,RG); } }
+static void bis_ind_rgd(void) { t11_ICount -= 21+12; { BIS_M(IND,RGD); } }
+static void bis_ind_in(void) { t11_ICount -= 21+12; { BIS_M(IND,IN); } }
+static void bis_ind_ind(void) { t11_ICount -= 21+18; { BIS_M(IND,IND); } }
+static void bis_ind_de(void) { t11_ICount -= 21+15; { BIS_M(IND,DE); } }
+static void bis_ind_ded(void) { t11_ICount -= 21+21; { BIS_M(IND,DED); } }
+static void bis_ind_ix(void) { t11_ICount -= 21+21; { BIS_M(IND,IX); } }
+static void bis_ind_ixd(void) { t11_ICount -= 21+27; { BIS_M(IND,IXD); } }
+static void bis_de_rg(void) { t11_ICount -= 18+ 3; { BIS_X(DE,RG); } }
+static void bis_de_rgd(void) { t11_ICount -= 18+12; { BIS_M(DE,RGD); } }
+static void bis_de_in(void) { t11_ICount -= 18+12; { BIS_M(DE,IN); } }
+static void bis_de_ind(void) { t11_ICount -= 18+18; { BIS_M(DE,IND); } }
+static void bis_de_de(void) { t11_ICount -= 18+15; { BIS_M(DE,DE); } }
+static void bis_de_ded(void) { t11_ICount -= 18+21; { BIS_M(DE,DED); } }
+static void bis_de_ix(void) { t11_ICount -= 18+21; { BIS_M(DE,IX); } }
+static void bis_de_ixd(void) { t11_ICount -= 18+27; { BIS_M(DE,IXD); } }
+static void bis_ded_rg(void) { t11_ICount -= 24+ 3; { BIS_X(DED,RG); } }
+static void bis_ded_rgd(void) { t11_ICount -= 24+12; { BIS_M(DED,RGD); } }
+static void bis_ded_in(void) { t11_ICount -= 24+12; { BIS_M(DED,IN); } }
+static void bis_ded_ind(void) { t11_ICount -= 24+18; { BIS_M(DED,IND); } }
+static void bis_ded_de(void) { t11_ICount -= 24+15; { BIS_M(DED,DE); } }
+static void bis_ded_ded(void) { t11_ICount -= 24+21; { BIS_M(DED,DED); } }
+static void bis_ded_ix(void) { t11_ICount -= 24+21; { BIS_M(DED,IX); } }
+static void bis_ded_ixd(void) { t11_ICount -= 24+27; { BIS_M(DED,IXD); } }
+static void bis_ix_rg(void) { t11_ICount -= 24+ 3; { BIS_X(IX,RG); } }
+static void bis_ix_rgd(void) { t11_ICount -= 24+12; { BIS_M(IX,RGD); } }
+static void bis_ix_in(void) { t11_ICount -= 24+12; { BIS_M(IX,IN); } }
+static void bis_ix_ind(void) { t11_ICount -= 24+18; { BIS_M(IX,IND); } }
+static void bis_ix_de(void) { t11_ICount -= 24+15; { BIS_M(IX,DE); } }
+static void bis_ix_ded(void) { t11_ICount -= 24+21; { BIS_M(IX,DED); } }
+static void bis_ix_ix(void) { t11_ICount -= 24+21; { BIS_M(IX,IX); } }
+static void bis_ix_ixd(void) { t11_ICount -= 24+27; { BIS_M(IX,IXD); } }
+static void bis_ixd_rg(void) { t11_ICount -= 30+ 3; { BIS_X(IXD,RG); } }
+static void bis_ixd_rgd(void) { t11_ICount -= 30+12; { BIS_M(IXD,RGD); } }
+static void bis_ixd_in(void) { t11_ICount -= 30+12; { BIS_M(IXD,IN); } }
+static void bis_ixd_ind(void) { t11_ICount -= 30+18; { BIS_M(IXD,IND); } }
+static void bis_ixd_de(void) { t11_ICount -= 30+15; { BIS_M(IXD,DE); } }
+static void bis_ixd_ded(void) { t11_ICount -= 30+21; { BIS_M(IXD,DED); } }
+static void bis_ixd_ix(void) { t11_ICount -= 30+21; { BIS_M(IXD,IX); } }
+static void bis_ixd_ixd(void) { t11_ICount -= 30+27; { BIS_M(IXD,IXD); } }
+
+static void add_rg_rg(void) { t11_ICount -= 9+ 3; { ADD_R(RG,RG); } }
+static void add_rg_rgd(void) { t11_ICount -= 9+12; { ADD_M(RG,RGD); } }
+static void add_rg_in(void) { t11_ICount -= 9+12; { ADD_M(RG,IN); } }
+static void add_rg_ind(void) { t11_ICount -= 9+18; { ADD_M(RG,IND); } }
+static void add_rg_de(void) { t11_ICount -= 9+15; { ADD_M(RG,DE); } }
+static void add_rg_ded(void) { t11_ICount -= 9+21; { ADD_M(RG,DED); } }
+static void add_rg_ix(void) { t11_ICount -= 9+21; { ADD_M(RG,IX); } }
+static void add_rg_ixd(void) { t11_ICount -= 9+27; { ADD_M(RG,IXD); } }
+static void add_rgd_rg(void) { t11_ICount -= 15+ 3; { ADD_X(RGD,RG); } }
+static void add_rgd_rgd(void) { t11_ICount -= 15+12; { ADD_M(RGD,RGD); } }
+static void add_rgd_in(void) { t11_ICount -= 15+12; { ADD_M(RGD,IN); } }
+static void add_rgd_ind(void) { t11_ICount -= 15+18; { ADD_M(RGD,IND); } }
+static void add_rgd_de(void) { t11_ICount -= 15+15; { ADD_M(RGD,DE); } }
+static void add_rgd_ded(void) { t11_ICount -= 15+21; { ADD_M(RGD,DED); } }
+static void add_rgd_ix(void) { t11_ICount -= 15+21; { ADD_M(RGD,IX); } }
+static void add_rgd_ixd(void) { t11_ICount -= 15+27; { ADD_M(RGD,IXD); } }
+static void add_in_rg(void) { t11_ICount -= 15+ 3; { ADD_X(IN,RG); } }
+static void add_in_rgd(void) { t11_ICount -= 15+12; { ADD_M(IN,RGD); } }
+static void add_in_in(void) { t11_ICount -= 15+12; { ADD_M(IN,IN); } }
+static void add_in_ind(void) { t11_ICount -= 15+18; { ADD_M(IN,IND); } }
+static void add_in_de(void) { t11_ICount -= 15+15; { ADD_M(IN,DE); } }
+static void add_in_ded(void) { t11_ICount -= 15+21; { ADD_M(IN,DED); } }
+static void add_in_ix(void) { t11_ICount -= 15+21; { ADD_M(IN,IX); } }
+static void add_in_ixd(void) { t11_ICount -= 15+27; { ADD_M(IN,IXD); } }
+static void add_ind_rg(void) { t11_ICount -= 21+ 3; { ADD_X(IND,RG); } }
+static void add_ind_rgd(void) { t11_ICount -= 21+12; { ADD_M(IND,RGD); } }
+static void add_ind_in(void) { t11_ICount -= 21+12; { ADD_M(IND,IN); } }
+static void add_ind_ind(void) { t11_ICount -= 21+18; { ADD_M(IND,IND); } }
+static void add_ind_de(void) { t11_ICount -= 21+15; { ADD_M(IND,DE); } }
+static void add_ind_ded(void) { t11_ICount -= 21+21; { ADD_M(IND,DED); } }
+static void add_ind_ix(void) { t11_ICount -= 21+21; { ADD_M(IND,IX); } }
+static void add_ind_ixd(void) { t11_ICount -= 21+27; { ADD_M(IND,IXD); } }
+static void add_de_rg(void) { t11_ICount -= 18+ 3; { ADD_X(DE,RG); } }
+static void add_de_rgd(void) { t11_ICount -= 18+12; { ADD_M(DE,RGD); } }
+static void add_de_in(void) { t11_ICount -= 18+12; { ADD_M(DE,IN); } }
+static void add_de_ind(void) { t11_ICount -= 18+18; { ADD_M(DE,IND); } }
+static void add_de_de(void) { t11_ICount -= 18+15; { ADD_M(DE,DE); } }
+static void add_de_ded(void) { t11_ICount -= 18+21; { ADD_M(DE,DED); } }
+static void add_de_ix(void) { t11_ICount -= 18+21; { ADD_M(DE,IX); } }
+static void add_de_ixd(void) { t11_ICount -= 18+27; { ADD_M(DE,IXD); } }
+static void add_ded_rg(void) { t11_ICount -= 24+ 3; { ADD_X(DED,RG); } }
+static void add_ded_rgd(void) { t11_ICount -= 24+12; { ADD_M(DED,RGD); } }
+static void add_ded_in(void) { t11_ICount -= 24+12; { ADD_M(DED,IN); } }
+static void add_ded_ind(void) { t11_ICount -= 24+18; { ADD_M(DED,IND); } }
+static void add_ded_de(void) { t11_ICount -= 24+15; { ADD_M(DED,DE); } }
+static void add_ded_ded(void) { t11_ICount -= 24+21; { ADD_M(DED,DED); } }
+static void add_ded_ix(void) { t11_ICount -= 24+21; { ADD_M(DED,IX); } }
+static void add_ded_ixd(void) { t11_ICount -= 24+27; { ADD_M(DED,IXD); } }
+static void add_ix_rg(void) { t11_ICount -= 24+ 3; { ADD_X(IX,RG); } }
+static void add_ix_rgd(void) { t11_ICount -= 24+12; { ADD_M(IX,RGD); } }
+static void add_ix_in(void) { t11_ICount -= 24+12; { ADD_M(IX,IN); } }
+static void add_ix_ind(void) { t11_ICount -= 24+18; { ADD_M(IX,IND); } }
+static void add_ix_de(void) { t11_ICount -= 24+15; { ADD_M(IX,DE); } }
+static void add_ix_ded(void) { t11_ICount -= 24+21; { ADD_M(IX,DED); } }
+static void add_ix_ix(void) { t11_ICount -= 24+21; { ADD_M(IX,IX); } }
+static void add_ix_ixd(void) { t11_ICount -= 24+27; { ADD_M(IX,IXD); } }
+static void add_ixd_rg(void) { t11_ICount -= 30+ 3; { ADD_X(IXD,RG); } }
+static void add_ixd_rgd(void) { t11_ICount -= 30+12; { ADD_M(IXD,RGD); } }
+static void add_ixd_in(void) { t11_ICount -= 30+12; { ADD_M(IXD,IN); } }
+static void add_ixd_ind(void) { t11_ICount -= 30+18; { ADD_M(IXD,IND); } }
+static void add_ixd_de(void) { t11_ICount -= 30+15; { ADD_M(IXD,DE); } }
+static void add_ixd_ded(void) { t11_ICount -= 30+21; { ADD_M(IXD,DED); } }
+static void add_ixd_ix(void) { t11_ICount -= 30+21; { ADD_M(IXD,IX); } }
+static void add_ixd_ixd(void) { t11_ICount -= 30+27; { ADD_M(IXD,IXD); } }
+
+static void xor_rg(void) { t11_ICount -= 12; { XOR_R(RG); } }
+static void xor_rgd(void) { t11_ICount -= 21; { XOR_M(RGD); } }
+static void xor_in(void) { t11_ICount -= 21; { XOR_M(IN); } }
+static void xor_ind(void) { t11_ICount -= 27; { XOR_M(IND); } }
+static void xor_de(void) { t11_ICount -= 24; { XOR_M(DE); } }
+static void xor_ded(void) { t11_ICount -= 30; { XOR_M(DED); } }
+static void xor_ix(void) { t11_ICount -= 30; { XOR_M(IX); } }
+static void xor_ixd(void) { t11_ICount -= 36; { XOR_M(IXD); } }
+
+static void sob(void)
+{
+ int sreg, source;
+
+ t11_ICount -= 18;
+ GET_SREG; source = REGD(sreg);
+ source -= 1;
+ REGW(sreg) = source;
+ if (source)
+ PC -= 2 * (t11.op & 0x3f);
+}
+
+static void bpl(void) { t11_ICount -= 12; { BR(!GET_N); } }
+static void bmi(void) { t11_ICount -= 12; { BR( GET_N); } }
+static void bhi(void) { t11_ICount -= 12; { BR(!GET_C && !GET_Z); } }
+static void blos(void) { t11_ICount -= 12; { BR( GET_C || GET_Z); } }
+static void bvc(void) { t11_ICount -= 12; { BR(!GET_V); } }
+static void bvs(void) { t11_ICount -= 12; { BR( GET_V); } }
+static void bcc(void) { t11_ICount -= 12; { BR(!GET_C); } }
+static void bcs(void) { t11_ICount -= 12; { BR( GET_C); } }
+
+static void emt(void)
+{
+ t11_ICount -= 48;
+ PUSH(PSW);
+ PUSH(PC);
+ PC = RWORD(0x18);
+ PSW = RWORD(0x1a);
+ change_pc(PC);
+ t11_check_irqs();
+}
+
+static void trap(void)
+{
+ t11_ICount -= 48;
+ PUSH(PSW);
+ PUSH(PC);
+ PC = RWORD(0x1c);
+ PSW = RWORD(0x1e);
+ change_pc(PC);
+ t11_check_irqs();
+}
+
+static void clrb_rg(void) { t11_ICount -= 12; { CLRB_R(RG); } }
+static void clrb_rgd(void) { t11_ICount -= 21; { CLRB_M(RGD); } }
+static void clrb_in(void) { t11_ICount -= 21; { CLRB_M(IN); } }
+static void clrb_ind(void) { t11_ICount -= 27; { CLRB_M(IND); } }
+static void clrb_de(void) { t11_ICount -= 24; { CLRB_M(DE); } }
+static void clrb_ded(void) { t11_ICount -= 30; { CLRB_M(DED); } }
+static void clrb_ix(void) { t11_ICount -= 30; { CLRB_M(IX); } }
+static void clrb_ixd(void) { t11_ICount -= 36; { CLRB_M(IXD); } }
+
+static void comb_rg(void) { t11_ICount -= 12; { COMB_R(RG); } }
+static void comb_rgd(void) { t11_ICount -= 21; { COMB_M(RGD); } }
+static void comb_in(void) { t11_ICount -= 21; { COMB_M(IN); } }
+static void comb_ind(void) { t11_ICount -= 27; { COMB_M(IND); } }
+static void comb_de(void) { t11_ICount -= 24; { COMB_M(DE); } }
+static void comb_ded(void) { t11_ICount -= 30; { COMB_M(DED); } }
+static void comb_ix(void) { t11_ICount -= 30; { COMB_M(IX); } }
+static void comb_ixd(void) { t11_ICount -= 36; { COMB_M(IXD); } }
+
+static void incb_rg(void) { t11_ICount -= 12; { INCB_R(RG); } }
+static void incb_rgd(void) { t11_ICount -= 21; { INCB_M(RGD); } }
+static void incb_in(void) { t11_ICount -= 21; { INCB_M(IN); } }
+static void incb_ind(void) { t11_ICount -= 27; { INCB_M(IND); } }
+static void incb_de(void) { t11_ICount -= 24; { INCB_M(DE); } }
+static void incb_ded(void) { t11_ICount -= 30; { INCB_M(DED); } }
+static void incb_ix(void) { t11_ICount -= 30; { INCB_M(IX); } }
+static void incb_ixd(void) { t11_ICount -= 36; { INCB_M(IXD); } }
+
+static void decb_rg(void) { t11_ICount -= 12; { DECB_R(RG); } }
+static void decb_rgd(void) { t11_ICount -= 21; { DECB_M(RGD); } }
+static void decb_in(void) { t11_ICount -= 21; { DECB_M(IN); } }
+static void decb_ind(void) { t11_ICount -= 27; { DECB_M(IND); } }
+static void decb_de(void) { t11_ICount -= 24; { DECB_M(DE); } }
+static void decb_ded(void) { t11_ICount -= 30; { DECB_M(DED); } }
+static void decb_ix(void) { t11_ICount -= 30; { DECB_M(IX); } }
+static void decb_ixd(void) { t11_ICount -= 36; { DECB_M(IXD); } }
+
+static void negb_rg(void) { t11_ICount -= 12; { NEGB_R(RG); } }
+static void negb_rgd(void) { t11_ICount -= 21; { NEGB_M(RGD); } }
+static void negb_in(void) { t11_ICount -= 21; { NEGB_M(IN); } }
+static void negb_ind(void) { t11_ICount -= 27; { NEGB_M(IND); } }
+static void negb_de(void) { t11_ICount -= 24; { NEGB_M(DE); } }
+static void negb_ded(void) { t11_ICount -= 30; { NEGB_M(DED); } }
+static void negb_ix(void) { t11_ICount -= 30; { NEGB_M(IX); } }
+static void negb_ixd(void) { t11_ICount -= 36; { NEGB_M(IXD); } }
+
+static void adcb_rg(void) { t11_ICount -= 12; { ADCB_R(RG); } }
+static void adcb_rgd(void) { t11_ICount -= 21; { ADCB_M(RGD); } }
+static void adcb_in(void) { t11_ICount -= 21; { ADCB_M(IN); } }
+static void adcb_ind(void) { t11_ICount -= 27; { ADCB_M(IND); } }
+static void adcb_de(void) { t11_ICount -= 24; { ADCB_M(DE); } }
+static void adcb_ded(void) { t11_ICount -= 30; { ADCB_M(DED); } }
+static void adcb_ix(void) { t11_ICount -= 30; { ADCB_M(IX); } }
+static void adcb_ixd(void) { t11_ICount -= 36; { ADCB_M(IXD); } }
+
+static void sbcb_rg(void) { t11_ICount -= 12; { SBCB_R(RG); } }
+static void sbcb_rgd(void) { t11_ICount -= 21; { SBCB_M(RGD); } }
+static void sbcb_in(void) { t11_ICount -= 21; { SBCB_M(IN); } }
+static void sbcb_ind(void) { t11_ICount -= 27; { SBCB_M(IND); } }
+static void sbcb_de(void) { t11_ICount -= 24; { SBCB_M(DE); } }
+static void sbcb_ded(void) { t11_ICount -= 30; { SBCB_M(DED); } }
+static void sbcb_ix(void) { t11_ICount -= 30; { SBCB_M(IX); } }
+static void sbcb_ixd(void) { t11_ICount -= 36; { SBCB_M(IXD); } }
+
+static void tstb_rg(void) { t11_ICount -= 12; { TSTB_R(RG); } }
+static void tstb_rgd(void) { t11_ICount -= 18; { TSTB_M(RGD); } }
+static void tstb_in(void) { t11_ICount -= 18; { TSTB_M(IN); } }
+static void tstb_ind(void) { t11_ICount -= 24; { TSTB_M(IND); } }
+static void tstb_de(void) { t11_ICount -= 21; { TSTB_M(DE); } }
+static void tstb_ded(void) { t11_ICount -= 27; { TSTB_M(DED); } }
+static void tstb_ix(void) { t11_ICount -= 27; { TSTB_M(IX); } }
+static void tstb_ixd(void) { t11_ICount -= 33; { TSTB_M(IXD); } }
+
+static void rorb_rg(void) { t11_ICount -= 12; { RORB_R(RG); } }
+static void rorb_rgd(void) { t11_ICount -= 21; { RORB_M(RGD); } }
+static void rorb_in(void) { t11_ICount -= 21; { RORB_M(IN); } }
+static void rorb_ind(void) { t11_ICount -= 27; { RORB_M(IND); } }
+static void rorb_de(void) { t11_ICount -= 24; { RORB_M(DE); } }
+static void rorb_ded(void) { t11_ICount -= 30; { RORB_M(DED); } }
+static void rorb_ix(void) { t11_ICount -= 30; { RORB_M(IX); } }
+static void rorb_ixd(void) { t11_ICount -= 36; { RORB_M(IXD); } }
+
+static void rolb_rg(void) { t11_ICount -= 12; { ROLB_R(RG); } }
+static void rolb_rgd(void) { t11_ICount -= 21; { ROLB_M(RGD); } }
+static void rolb_in(void) { t11_ICount -= 21; { ROLB_M(IN); } }
+static void rolb_ind(void) { t11_ICount -= 27; { ROLB_M(IND); } }
+static void rolb_de(void) { t11_ICount -= 24; { ROLB_M(DE); } }
+static void rolb_ded(void) { t11_ICount -= 30; { ROLB_M(DED); } }
+static void rolb_ix(void) { t11_ICount -= 30; { ROLB_M(IX); } }
+static void rolb_ixd(void) { t11_ICount -= 36; { ROLB_M(IXD); } }
+
+static void asrb_rg(void) { t11_ICount -= 12; { ASRB_R(RG); } }
+static void asrb_rgd(void) { t11_ICount -= 21; { ASRB_M(RGD); } }
+static void asrb_in(void) { t11_ICount -= 21; { ASRB_M(IN); } }
+static void asrb_ind(void) { t11_ICount -= 27; { ASRB_M(IND); } }
+static void asrb_de(void) { t11_ICount -= 24; { ASRB_M(DE); } }
+static void asrb_ded(void) { t11_ICount -= 30; { ASRB_M(DED); } }
+static void asrb_ix(void) { t11_ICount -= 30; { ASRB_M(IX); } }
+static void asrb_ixd(void) { t11_ICount -= 36; { ASRB_M(IXD); } }
+
+static void aslb_rg(void) { t11_ICount -= 12; { ASLB_R(RG); } }
+static void aslb_rgd(void) { t11_ICount -= 21; { ASLB_M(RGD); } }
+static void aslb_in(void) { t11_ICount -= 21; { ASLB_M(IN); } }
+static void aslb_ind(void) { t11_ICount -= 27; { ASLB_M(IND); } }
+static void aslb_de(void) { t11_ICount -= 24; { ASLB_M(DE); } }
+static void aslb_ded(void) { t11_ICount -= 30; { ASLB_M(DED); } }
+static void aslb_ix(void) { t11_ICount -= 30; { ASLB_M(IX); } }
+static void aslb_ixd(void) { t11_ICount -= 36; { ASLB_M(IXD); } }
+
+static void mtps_rg(void) { t11_ICount -= 24; { MTPS_R(RG); } }
+static void mtps_rgd(void) { t11_ICount -= 30; { MTPS_M(RGD); } }
+static void mtps_in(void) { t11_ICount -= 30; { MTPS_M(IN); } }
+static void mtps_ind(void) { t11_ICount -= 36; { MTPS_M(IND); } }
+static void mtps_de(void) { t11_ICount -= 33; { MTPS_M(DE); } }
+static void mtps_ded(void) { t11_ICount -= 39; { MTPS_M(DED); } }
+static void mtps_ix(void) { t11_ICount -= 39; { MTPS_M(IX); } }
+static void mtps_ixd(void) { t11_ICount -= 45; { MTPS_M(IXD); } }
+
+static void mfps_rg(void) { t11_ICount -= 12; { MFPS_R(RG); } }
+static void mfps_rgd(void) { t11_ICount -= 21; { MFPS_M(RGD); } }
+static void mfps_in(void) { t11_ICount -= 21; { MFPS_M(IN); } }
+static void mfps_ind(void) { t11_ICount -= 27; { MFPS_M(IND); } }
+static void mfps_de(void) { t11_ICount -= 24; { MFPS_M(DE); } }
+static void mfps_ded(void) { t11_ICount -= 30; { MFPS_M(DED); } }
+static void mfps_ix(void) { t11_ICount -= 30; { MFPS_M(IX); } }
+static void mfps_ixd(void) { t11_ICount -= 36; { MFPS_M(IXD); } }
+
+static void movb_rg_rg(void) { t11_ICount -= 9+ 3; { MOVB_R(RG,RG); } }
+static void movb_rg_rgd(void) { t11_ICount -= 9+12; { MOVB_M(RG,RGD); } }
+static void movb_rg_in(void) { t11_ICount -= 9+12; { MOVB_M(RG,IN); } }
+static void movb_rg_ind(void) { t11_ICount -= 9+18; { MOVB_M(RG,IND); } }
+static void movb_rg_de(void) { t11_ICount -= 9+15; { MOVB_M(RG,DE); } }
+static void movb_rg_ded(void) { t11_ICount -= 9+21; { MOVB_M(RG,DED); } }
+static void movb_rg_ix(void) { t11_ICount -= 9+21; { MOVB_M(RG,IX); } }
+static void movb_rg_ixd(void) { t11_ICount -= 9+27; { MOVB_M(RG,IXD); } }
+static void movb_rgd_rg(void) { t11_ICount -= 15+ 3; { MOVB_X(RGD,RG); } }
+static void movb_rgd_rgd(void) { t11_ICount -= 15+12; { MOVB_M(RGD,RGD); } }
+static void movb_rgd_in(void) { t11_ICount -= 15+12; { MOVB_M(RGD,IN); } }
+static void movb_rgd_ind(void) { t11_ICount -= 15+18; { MOVB_M(RGD,IND); } }
+static void movb_rgd_de(void) { t11_ICount -= 15+15; { MOVB_M(RGD,DE); } }
+static void movb_rgd_ded(void) { t11_ICount -= 15+21; { MOVB_M(RGD,DED); } }
+static void movb_rgd_ix(void) { t11_ICount -= 15+21; { MOVB_M(RGD,IX); } }
+static void movb_rgd_ixd(void) { t11_ICount -= 15+27; { MOVB_M(RGD,IXD); } }
+static void movb_in_rg(void) { t11_ICount -= 15+ 3; { MOVB_X(IN,RG); } }
+static void movb_in_rgd(void) { t11_ICount -= 15+12; { MOVB_M(IN,RGD); } }
+static void movb_in_in(void) { t11_ICount -= 15+12; { MOVB_M(IN,IN); } }
+static void movb_in_ind(void) { t11_ICount -= 15+18; { MOVB_M(IN,IND); } }
+static void movb_in_de(void) { t11_ICount -= 15+15; { MOVB_M(IN,DE); } }
+static void movb_in_ded(void) { t11_ICount -= 15+21; { MOVB_M(IN,DED); } }
+static void movb_in_ix(void) { t11_ICount -= 15+21; { MOVB_M(IN,IX); } }
+static void movb_in_ixd(void) { t11_ICount -= 15+27; { MOVB_M(IN,IXD); } }
+static void movb_ind_rg(void) { t11_ICount -= 21+ 3; { MOVB_X(IND,RG); } }
+static void movb_ind_rgd(void) { t11_ICount -= 21+12; { MOVB_M(IND,RGD); } }
+static void movb_ind_in(void) { t11_ICount -= 21+12; { MOVB_M(IND,IN); } }
+static void movb_ind_ind(void) { t11_ICount -= 21+18; { MOVB_M(IND,IND); } }
+static void movb_ind_de(void) { t11_ICount -= 21+15; { MOVB_M(IND,DE); } }
+static void movb_ind_ded(void) { t11_ICount -= 21+21; { MOVB_M(IND,DED); } }
+static void movb_ind_ix(void) { t11_ICount -= 21+21; { MOVB_M(IND,IX); } }
+static void movb_ind_ixd(void) { t11_ICount -= 21+27; { MOVB_M(IND,IXD); } }
+static void movb_de_rg(void) { t11_ICount -= 18+ 3; { MOVB_X(DE,RG); } }
+static void movb_de_rgd(void) { t11_ICount -= 18+12; { MOVB_M(DE,RGD); } }
+static void movb_de_in(void) { t11_ICount -= 18+12; { MOVB_M(DE,IN); } }
+static void movb_de_ind(void) { t11_ICount -= 18+18; { MOVB_M(DE,IND); } }
+static void movb_de_de(void) { t11_ICount -= 18+15; { MOVB_M(DE,DE); } }
+static void movb_de_ded(void) { t11_ICount -= 18+21; { MOVB_M(DE,DED); } }
+static void movb_de_ix(void) { t11_ICount -= 18+21; { MOVB_M(DE,IX); } }
+static void movb_de_ixd(void) { t11_ICount -= 18+27; { MOVB_M(DE,IXD); } }
+static void movb_ded_rg(void) { t11_ICount -= 24+ 3; { MOVB_X(DED,RG); } }
+static void movb_ded_rgd(void) { t11_ICount -= 24+12; { MOVB_M(DED,RGD); } }
+static void movb_ded_in(void) { t11_ICount -= 24+12; { MOVB_M(DED,IN); } }
+static void movb_ded_ind(void) { t11_ICount -= 24+18; { MOVB_M(DED,IND); } }
+static void movb_ded_de(void) { t11_ICount -= 24+15; { MOVB_M(DED,DE); } }
+static void movb_ded_ded(void) { t11_ICount -= 24+21; { MOVB_M(DED,DED); } }
+static void movb_ded_ix(void) { t11_ICount -= 24+21; { MOVB_M(DED,IX); } }
+static void movb_ded_ixd(void) { t11_ICount -= 24+27; { MOVB_M(DED,IXD); } }
+static void movb_ix_rg(void) { t11_ICount -= 24+ 3; { MOVB_X(IX,RG); } }
+static void movb_ix_rgd(void) { t11_ICount -= 24+12; { MOVB_M(IX,RGD); } }
+static void movb_ix_in(void) { t11_ICount -= 24+12; { MOVB_M(IX,IN); } }
+static void movb_ix_ind(void) { t11_ICount -= 24+18; { MOVB_M(IX,IND); } }
+static void movb_ix_de(void) { t11_ICount -= 24+15; { MOVB_M(IX,DE); } }
+static void movb_ix_ded(void) { t11_ICount -= 24+21; { MOVB_M(IX,DED); } }
+static void movb_ix_ix(void) { t11_ICount -= 24+21; { MOVB_M(IX,IX); } }
+static void movb_ix_ixd(void) { t11_ICount -= 24+27; { MOVB_M(IX,IXD); } }
+static void movb_ixd_rg(void) { t11_ICount -= 30+ 3; { MOVB_X(IXD,RG); } }
+static void movb_ixd_rgd(void) { t11_ICount -= 30+12; { MOVB_M(IXD,RGD); } }
+static void movb_ixd_in(void) { t11_ICount -= 30+12; { MOVB_M(IXD,IN); } }
+static void movb_ixd_ind(void) { t11_ICount -= 30+18; { MOVB_M(IXD,IND); } }
+static void movb_ixd_de(void) { t11_ICount -= 30+15; { MOVB_M(IXD,DE); } }
+static void movb_ixd_ded(void) { t11_ICount -= 30+21; { MOVB_M(IXD,DED); } }
+static void movb_ixd_ix(void) { t11_ICount -= 30+21; { MOVB_M(IXD,IX); } }
+static void movb_ixd_ixd(void) { t11_ICount -= 30+27; { MOVB_M(IXD,IXD); } }
+
+static void cmpb_rg_rg(void) { t11_ICount -= 9+ 3; { CMPB_R(RG,RG); } }
+static void cmpb_rg_rgd(void) { t11_ICount -= 9+ 9; { CMPB_M(RG,RGD); } }
+static void cmpb_rg_in(void) { t11_ICount -= 9+ 9; { CMPB_M(RG,IN); } }
+static void cmpb_rg_ind(void) { t11_ICount -= 9+15; { CMPB_M(RG,IND); } }
+static void cmpb_rg_de(void) { t11_ICount -= 9+12; { CMPB_M(RG,DE); } }
+static void cmpb_rg_ded(void) { t11_ICount -= 9+18; { CMPB_M(RG,DED); } }
+static void cmpb_rg_ix(void) { t11_ICount -= 9+18; { CMPB_M(RG,IX); } }
+static void cmpb_rg_ixd(void) { t11_ICount -= 9+24; { CMPB_M(RG,IXD); } }
+static void cmpb_rgd_rg(void) { t11_ICount -= 15+ 3; { CMPB_M(RGD,RG); } }
+static void cmpb_rgd_rgd(void) { t11_ICount -= 15+ 9; { CMPB_M(RGD,RGD); } }
+static void cmpb_rgd_in(void) { t11_ICount -= 15+ 9; { CMPB_M(RGD,IN); } }
+static void cmpb_rgd_ind(void) { t11_ICount -= 15+15; { CMPB_M(RGD,IND); } }
+static void cmpb_rgd_de(void) { t11_ICount -= 15+12; { CMPB_M(RGD,DE); } }
+static void cmpb_rgd_ded(void) { t11_ICount -= 15+18; { CMPB_M(RGD,DED); } }
+static void cmpb_rgd_ix(void) { t11_ICount -= 15+18; { CMPB_M(RGD,IX); } }
+static void cmpb_rgd_ixd(void) { t11_ICount -= 15+24; { CMPB_M(RGD,IXD); } }
+static void cmpb_in_rg(void) { t11_ICount -= 15+ 3; { CMPB_M(IN,RG); } }
+static void cmpb_in_rgd(void) { t11_ICount -= 15+ 9; { CMPB_M(IN,RGD); } }
+static void cmpb_in_in(void) { t11_ICount -= 15+ 9; { CMPB_M(IN,IN); } }
+static void cmpb_in_ind(void) { t11_ICount -= 15+15; { CMPB_M(IN,IND); } }
+static void cmpb_in_de(void) { t11_ICount -= 15+12; { CMPB_M(IN,DE); } }
+static void cmpb_in_ded(void) { t11_ICount -= 15+18; { CMPB_M(IN,DED); } }
+static void cmpb_in_ix(void) { t11_ICount -= 15+18; { CMPB_M(IN,IX); } }
+static void cmpb_in_ixd(void) { t11_ICount -= 15+24; { CMPB_M(IN,IXD); } }
+static void cmpb_ind_rg(void) { t11_ICount -= 21+ 3; { CMPB_M(IND,RG); } }
+static void cmpb_ind_rgd(void) { t11_ICount -= 21+ 9; { CMPB_M(IND,RGD); } }
+static void cmpb_ind_in(void) { t11_ICount -= 21+ 9; { CMPB_M(IND,IN); } }
+static void cmpb_ind_ind(void) { t11_ICount -= 21+15; { CMPB_M(IND,IND); } }
+static void cmpb_ind_de(void) { t11_ICount -= 21+12; { CMPB_M(IND,DE); } }
+static void cmpb_ind_ded(void) { t11_ICount -= 21+18; { CMPB_M(IND,DED); } }
+static void cmpb_ind_ix(void) { t11_ICount -= 21+18; { CMPB_M(IND,IX); } }
+static void cmpb_ind_ixd(void) { t11_ICount -= 21+24; { CMPB_M(IND,IXD); } }
+static void cmpb_de_rg(void) { t11_ICount -= 18+ 3; { CMPB_M(DE,RG); } }
+static void cmpb_de_rgd(void) { t11_ICount -= 18+ 9; { CMPB_M(DE,RGD); } }
+static void cmpb_de_in(void) { t11_ICount -= 18+ 9; { CMPB_M(DE,IN); } }
+static void cmpb_de_ind(void) { t11_ICount -= 18+15; { CMPB_M(DE,IND); } }
+static void cmpb_de_de(void) { t11_ICount -= 18+12; { CMPB_M(DE,DE); } }
+static void cmpb_de_ded(void) { t11_ICount -= 18+18; { CMPB_M(DE,DED); } }
+static void cmpb_de_ix(void) { t11_ICount -= 18+18; { CMPB_M(DE,IX); } }
+static void cmpb_de_ixd(void) { t11_ICount -= 18+24; { CMPB_M(DE,IXD); } }
+static void cmpb_ded_rg(void) { t11_ICount -= 24+ 3; { CMPB_M(DED,RG); } }
+static void cmpb_ded_rgd(void) { t11_ICount -= 24+ 9; { CMPB_M(DED,RGD); } }
+static void cmpb_ded_in(void) { t11_ICount -= 24+ 9; { CMPB_M(DED,IN); } }
+static void cmpb_ded_ind(void) { t11_ICount -= 24+15; { CMPB_M(DED,IND); } }
+static void cmpb_ded_de(void) { t11_ICount -= 24+12; { CMPB_M(DED,DE); } }
+static void cmpb_ded_ded(void) { t11_ICount -= 24+18; { CMPB_M(DED,DED); } }
+static void cmpb_ded_ix(void) { t11_ICount -= 24+18; { CMPB_M(DED,IX); } }
+static void cmpb_ded_ixd(void) { t11_ICount -= 24+24; { CMPB_M(DED,IXD); } }
+static void cmpb_ix_rg(void) { t11_ICount -= 24+ 3; { CMPB_M(IX,RG); } }
+static void cmpb_ix_rgd(void) { t11_ICount -= 24+ 9; { CMPB_M(IX,RGD); } }
+static void cmpb_ix_in(void) { t11_ICount -= 24+ 9; { CMPB_M(IX,IN); } }
+static void cmpb_ix_ind(void) { t11_ICount -= 24+15; { CMPB_M(IX,IND); } }
+static void cmpb_ix_de(void) { t11_ICount -= 24+12; { CMPB_M(IX,DE); } }
+static void cmpb_ix_ded(void) { t11_ICount -= 24+18; { CMPB_M(IX,DED); } }
+static void cmpb_ix_ix(void) { t11_ICount -= 24+18; { CMPB_M(IX,IX); } }
+static void cmpb_ix_ixd(void) { t11_ICount -= 24+24; { CMPB_M(IX,IXD); } }
+static void cmpb_ixd_rg(void) { t11_ICount -= 30+ 3; { CMPB_M(IXD,RG); } }
+static void cmpb_ixd_rgd(void) { t11_ICount -= 30+ 9; { CMPB_M(IXD,RGD); } }
+static void cmpb_ixd_in(void) { t11_ICount -= 30+ 9; { CMPB_M(IXD,IN); } }
+static void cmpb_ixd_ind(void) { t11_ICount -= 30+15; { CMPB_M(IXD,IND); } }
+static void cmpb_ixd_de(void) { t11_ICount -= 30+12; { CMPB_M(IXD,DE); } }
+static void cmpb_ixd_ded(void) { t11_ICount -= 30+18; { CMPB_M(IXD,DED); } }
+static void cmpb_ixd_ix(void) { t11_ICount -= 30+18; { CMPB_M(IXD,IX); } }
+static void cmpb_ixd_ixd(void) { t11_ICount -= 30+24; { CMPB_M(IXD,IXD); } }
+
+static void bitb_rg_rg(void) { t11_ICount -= 9+ 3; { BITB_R(RG,RG); } }
+static void bitb_rg_rgd(void) { t11_ICount -= 9+ 9; { BITB_M(RG,RGD); } }
+static void bitb_rg_in(void) { t11_ICount -= 9+ 9; { BITB_M(RG,IN); } }
+static void bitb_rg_ind(void) { t11_ICount -= 9+15; { BITB_M(RG,IND); } }
+static void bitb_rg_de(void) { t11_ICount -= 9+12; { BITB_M(RG,DE); } }
+static void bitb_rg_ded(void) { t11_ICount -= 9+18; { BITB_M(RG,DED); } }
+static void bitb_rg_ix(void) { t11_ICount -= 9+18; { BITB_M(RG,IX); } }
+static void bitb_rg_ixd(void) { t11_ICount -= 9+24; { BITB_M(RG,IXD); } }
+static void bitb_rgd_rg(void) { t11_ICount -= 15+ 3; { BITB_M(RGD,RG); } }
+static void bitb_rgd_rgd(void) { t11_ICount -= 15+ 9; { BITB_M(RGD,RGD); } }
+static void bitb_rgd_in(void) { t11_ICount -= 15+ 9; { BITB_M(RGD,IN); } }
+static void bitb_rgd_ind(void) { t11_ICount -= 15+15; { BITB_M(RGD,IND); } }
+static void bitb_rgd_de(void) { t11_ICount -= 15+12; { BITB_M(RGD,DE); } }
+static void bitb_rgd_ded(void) { t11_ICount -= 15+18; { BITB_M(RGD,DED); } }
+static void bitb_rgd_ix(void) { t11_ICount -= 15+18; { BITB_M(RGD,IX); } }
+static void bitb_rgd_ixd(void) { t11_ICount -= 15+24; { BITB_M(RGD,IXD); } }
+static void bitb_in_rg(void) { t11_ICount -= 15+ 3; { BITB_M(IN,RG); } }
+static void bitb_in_rgd(void) { t11_ICount -= 15+ 9; { BITB_M(IN,RGD); } }
+static void bitb_in_in(void) { t11_ICount -= 15+ 9; { BITB_M(IN,IN); } }
+static void bitb_in_ind(void) { t11_ICount -= 15+15; { BITB_M(IN,IND); } }
+static void bitb_in_de(void) { t11_ICount -= 15+12; { BITB_M(IN,DE); } }
+static void bitb_in_ded(void) { t11_ICount -= 15+18; { BITB_M(IN,DED); } }
+static void bitb_in_ix(void) { t11_ICount -= 15+18; { BITB_M(IN,IX); } }
+static void bitb_in_ixd(void) { t11_ICount -= 15+24; { BITB_M(IN,IXD); } }
+static void bitb_ind_rg(void) { t11_ICount -= 21+ 3; { BITB_M(IND,RG); } }
+static void bitb_ind_rgd(void) { t11_ICount -= 21+ 9; { BITB_M(IND,RGD); } }
+static void bitb_ind_in(void) { t11_ICount -= 21+ 9; { BITB_M(IND,IN); } }
+static void bitb_ind_ind(void) { t11_ICount -= 21+15; { BITB_M(IND,IND); } }
+static void bitb_ind_de(void) { t11_ICount -= 21+12; { BITB_M(IND,DE); } }
+static void bitb_ind_ded(void) { t11_ICount -= 21+18; { BITB_M(IND,DED); } }
+static void bitb_ind_ix(void) { t11_ICount -= 21+18; { BITB_M(IND,IX); } }
+static void bitb_ind_ixd(void) { t11_ICount -= 21+24; { BITB_M(IND,IXD); } }
+static void bitb_de_rg(void) { t11_ICount -= 18+ 3; { BITB_M(DE,RG); } }
+static void bitb_de_rgd(void) { t11_ICount -= 18+ 9; { BITB_M(DE,RGD); } }
+static void bitb_de_in(void) { t11_ICount -= 18+ 9; { BITB_M(DE,IN); } }
+static void bitb_de_ind(void) { t11_ICount -= 18+15; { BITB_M(DE,IND); } }
+static void bitb_de_de(void) { t11_ICount -= 18+12; { BITB_M(DE,DE); } }
+static void bitb_de_ded(void) { t11_ICount -= 18+18; { BITB_M(DE,DED); } }
+static void bitb_de_ix(void) { t11_ICount -= 18+18; { BITB_M(DE,IX); } }
+static void bitb_de_ixd(void) { t11_ICount -= 18+24; { BITB_M(DE,IXD); } }
+static void bitb_ded_rg(void) { t11_ICount -= 24+ 3; { BITB_M(DED,RG); } }
+static void bitb_ded_rgd(void) { t11_ICount -= 24+ 9; { BITB_M(DED,RGD); } }
+static void bitb_ded_in(void) { t11_ICount -= 24+ 9; { BITB_M(DED,IN); } }
+static void bitb_ded_ind(void) { t11_ICount -= 24+15; { BITB_M(DED,IND); } }
+static void bitb_ded_de(void) { t11_ICount -= 24+12; { BITB_M(DED,DE); } }
+static void bitb_ded_ded(void) { t11_ICount -= 24+18; { BITB_M(DED,DED); } }
+static void bitb_ded_ix(void) { t11_ICount -= 24+18; { BITB_M(DED,IX); } }
+static void bitb_ded_ixd(void) { t11_ICount -= 24+24; { BITB_M(DED,IXD); } }
+static void bitb_ix_rg(void) { t11_ICount -= 24+ 3; { BITB_M(IX,RG); } }
+static void bitb_ix_rgd(void) { t11_ICount -= 24+ 9; { BITB_M(IX,RGD); } }
+static void bitb_ix_in(void) { t11_ICount -= 24+ 9; { BITB_M(IX,IN); } }
+static void bitb_ix_ind(void) { t11_ICount -= 24+15; { BITB_M(IX,IND); } }
+static void bitb_ix_de(void) { t11_ICount -= 24+12; { BITB_M(IX,DE); } }
+static void bitb_ix_ded(void) { t11_ICount -= 24+18; { BITB_M(IX,DED); } }
+static void bitb_ix_ix(void) { t11_ICount -= 24+18; { BITB_M(IX,IX); } }
+static void bitb_ix_ixd(void) { t11_ICount -= 24+24; { BITB_M(IX,IXD); } }
+static void bitb_ixd_rg(void) { t11_ICount -= 30+ 3; { BITB_M(IXD,RG); } }
+static void bitb_ixd_rgd(void) { t11_ICount -= 30+ 9; { BITB_M(IXD,RGD); } }
+static void bitb_ixd_in(void) { t11_ICount -= 30+ 9; { BITB_M(IXD,IN); } }
+static void bitb_ixd_ind(void) { t11_ICount -= 30+15; { BITB_M(IXD,IND); } }
+static void bitb_ixd_de(void) { t11_ICount -= 30+12; { BITB_M(IXD,DE); } }
+static void bitb_ixd_ded(void) { t11_ICount -= 30+18; { BITB_M(IXD,DED); } }
+static void bitb_ixd_ix(void) { t11_ICount -= 30+18; { BITB_M(IXD,IX); } }
+static void bitb_ixd_ixd(void) { t11_ICount -= 30+24; { BITB_M(IXD,IXD); } }
+
+static void bicb_rg_rg(void) { t11_ICount -= 9+ 3; { BICB_R(RG,RG); } }
+static void bicb_rg_rgd(void) { t11_ICount -= 9+12; { BICB_M(RG,RGD); } }
+static void bicb_rg_in(void) { t11_ICount -= 9+12; { BICB_M(RG,IN); } }
+static void bicb_rg_ind(void) { t11_ICount -= 9+18; { BICB_M(RG,IND); } }
+static void bicb_rg_de(void) { t11_ICount -= 9+15; { BICB_M(RG,DE); } }
+static void bicb_rg_ded(void) { t11_ICount -= 9+21; { BICB_M(RG,DED); } }
+static void bicb_rg_ix(void) { t11_ICount -= 9+21; { BICB_M(RG,IX); } }
+static void bicb_rg_ixd(void) { t11_ICount -= 9+27; { BICB_M(RG,IXD); } }
+static void bicb_rgd_rg(void) { t11_ICount -= 15+ 3; { BICB_X(RGD,RG); } }
+static void bicb_rgd_rgd(void) { t11_ICount -= 15+12; { BICB_M(RGD,RGD); } }
+static void bicb_rgd_in(void) { t11_ICount -= 15+12; { BICB_M(RGD,IN); } }
+static void bicb_rgd_ind(void) { t11_ICount -= 15+18; { BICB_M(RGD,IND); } }
+static void bicb_rgd_de(void) { t11_ICount -= 15+15; { BICB_M(RGD,DE); } }
+static void bicb_rgd_ded(void) { t11_ICount -= 15+21; { BICB_M(RGD,DED); } }
+static void bicb_rgd_ix(void) { t11_ICount -= 15+21; { BICB_M(RGD,IX); } }
+static void bicb_rgd_ixd(void) { t11_ICount -= 15+27; { BICB_M(RGD,IXD); } }
+static void bicb_in_rg(void) { t11_ICount -= 15+ 3; { BICB_X(IN,RG); } }
+static void bicb_in_rgd(void) { t11_ICount -= 15+12; { BICB_M(IN,RGD); } }
+static void bicb_in_in(void) { t11_ICount -= 15+12; { BICB_M(IN,IN); } }
+static void bicb_in_ind(void) { t11_ICount -= 15+18; { BICB_M(IN,IND); } }
+static void bicb_in_de(void) { t11_ICount -= 15+15; { BICB_M(IN,DE); } }
+static void bicb_in_ded(void) { t11_ICount -= 15+21; { BICB_M(IN,DED); } }
+static void bicb_in_ix(void) { t11_ICount -= 15+21; { BICB_M(IN,IX); } }
+static void bicb_in_ixd(void) { t11_ICount -= 15+27; { BICB_M(IN,IXD); } }
+static void bicb_ind_rg(void) { t11_ICount -= 21+ 3; { BICB_X(IND,RG); } }
+static void bicb_ind_rgd(void) { t11_ICount -= 21+12; { BICB_M(IND,RGD); } }
+static void bicb_ind_in(void) { t11_ICount -= 21+12; { BICB_M(IND,IN); } }
+static void bicb_ind_ind(void) { t11_ICount -= 21+18; { BICB_M(IND,IND); } }
+static void bicb_ind_de(void) { t11_ICount -= 21+15; { BICB_M(IND,DE); } }
+static void bicb_ind_ded(void) { t11_ICount -= 21+21; { BICB_M(IND,DED); } }
+static void bicb_ind_ix(void) { t11_ICount -= 21+21; { BICB_M(IND,IX); } }
+static void bicb_ind_ixd(void) { t11_ICount -= 21+27; { BICB_M(IND,IXD); } }
+static void bicb_de_rg(void) { t11_ICount -= 18+ 3; { BICB_X(DE,RG); } }
+static void bicb_de_rgd(void) { t11_ICount -= 18+12; { BICB_M(DE,RGD); } }
+static void bicb_de_in(void) { t11_ICount -= 18+12; { BICB_M(DE,IN); } }
+static void bicb_de_ind(void) { t11_ICount -= 18+18; { BICB_M(DE,IND); } }
+static void bicb_de_de(void) { t11_ICount -= 18+15; { BICB_M(DE,DE); } }
+static void bicb_de_ded(void) { t11_ICount -= 18+21; { BICB_M(DE,DED); } }
+static void bicb_de_ix(void) { t11_ICount -= 18+21; { BICB_M(DE,IX); } }
+static void bicb_de_ixd(void) { t11_ICount -= 18+27; { BICB_M(DE,IXD); } }
+static void bicb_ded_rg(void) { t11_ICount -= 24+ 3; { BICB_X(DED,RG); } }
+static void bicb_ded_rgd(void) { t11_ICount -= 24+12; { BICB_M(DED,RGD); } }
+static void bicb_ded_in(void) { t11_ICount -= 24+12; { BICB_M(DED,IN); } }
+static void bicb_ded_ind(void) { t11_ICount -= 24+18; { BICB_M(DED,IND); } }
+static void bicb_ded_de(void) { t11_ICount -= 24+15; { BICB_M(DED,DE); } }
+static void bicb_ded_ded(void) { t11_ICount -= 24+21; { BICB_M(DED,DED); } }
+static void bicb_ded_ix(void) { t11_ICount -= 24+21; { BICB_M(DED,IX); } }
+static void bicb_ded_ixd(void) { t11_ICount -= 24+27; { BICB_M(DED,IXD); } }
+static void bicb_ix_rg(void) { t11_ICount -= 24+ 3; { BICB_X(IX,RG); } }
+static void bicb_ix_rgd(void) { t11_ICount -= 24+12; { BICB_M(IX,RGD); } }
+static void bicb_ix_in(void) { t11_ICount -= 24+12; { BICB_M(IX,IN); } }
+static void bicb_ix_ind(void) { t11_ICount -= 24+18; { BICB_M(IX,IND); } }
+static void bicb_ix_de(void) { t11_ICount -= 24+15; { BICB_M(IX,DE); } }
+static void bicb_ix_ded(void) { t11_ICount -= 24+21; { BICB_M(IX,DED); } }
+static void bicb_ix_ix(void) { t11_ICount -= 24+21; { BICB_M(IX,IX); } }
+static void bicb_ix_ixd(void) { t11_ICount -= 24+27; { BICB_M(IX,IXD); } }
+static void bicb_ixd_rg(void) { t11_ICount -= 30+ 3; { BICB_X(IXD,RG); } }
+static void bicb_ixd_rgd(void) { t11_ICount -= 30+12; { BICB_M(IXD,RGD); } }
+static void bicb_ixd_in(void) { t11_ICount -= 30+12; { BICB_M(IXD,IN); } }
+static void bicb_ixd_ind(void) { t11_ICount -= 30+18; { BICB_M(IXD,IND); } }
+static void bicb_ixd_de(void) { t11_ICount -= 30+15; { BICB_M(IXD,DE); } }
+static void bicb_ixd_ded(void) { t11_ICount -= 30+21; { BICB_M(IXD,DED); } }
+static void bicb_ixd_ix(void) { t11_ICount -= 30+21; { BICB_M(IXD,IX); } }
+static void bicb_ixd_ixd(void) { t11_ICount -= 30+27; { BICB_M(IXD,IXD); } }
+
+static void bisb_rg_rg(void) { t11_ICount -= 9+ 3; { BISB_R(RG,RG); } }
+static void bisb_rg_rgd(void) { t11_ICount -= 9+12; { BISB_M(RG,RGD); } }
+static void bisb_rg_in(void) { t11_ICount -= 9+12; { BISB_M(RG,IN); } }
+static void bisb_rg_ind(void) { t11_ICount -= 9+18; { BISB_M(RG,IND); } }
+static void bisb_rg_de(void) { t11_ICount -= 9+15; { BISB_M(RG,DE); } }
+static void bisb_rg_ded(void) { t11_ICount -= 9+21; { BISB_M(RG,DED); } }
+static void bisb_rg_ix(void) { t11_ICount -= 9+21; { BISB_M(RG,IX); } }
+static void bisb_rg_ixd(void) { t11_ICount -= 9+27; { BISB_M(RG,IXD); } }
+static void bisb_rgd_rg(void) { t11_ICount -= 15+ 3; { BISB_X(RGD,RG); } }
+static void bisb_rgd_rgd(void) { t11_ICount -= 15+12; { BISB_M(RGD,RGD); } }
+static void bisb_rgd_in(void) { t11_ICount -= 15+12; { BISB_M(RGD,IN); } }
+static void bisb_rgd_ind(void) { t11_ICount -= 15+18; { BISB_M(RGD,IND); } }
+static void bisb_rgd_de(void) { t11_ICount -= 15+15; { BISB_M(RGD,DE); } }
+static void bisb_rgd_ded(void) { t11_ICount -= 15+21; { BISB_M(RGD,DED); } }
+static void bisb_rgd_ix(void) { t11_ICount -= 15+21; { BISB_M(RGD,IX); } }
+static void bisb_rgd_ixd(void) { t11_ICount -= 15+27; { BISB_M(RGD,IXD); } }
+static void bisb_in_rg(void) { t11_ICount -= 15+ 3; { BISB_X(IN,RG); } }
+static void bisb_in_rgd(void) { t11_ICount -= 15+12; { BISB_M(IN,RGD); } }
+static void bisb_in_in(void) { t11_ICount -= 15+12; { BISB_M(IN,IN); } }
+static void bisb_in_ind(void) { t11_ICount -= 15+18; { BISB_M(IN,IND); } }
+static void bisb_in_de(void) { t11_ICount -= 15+15; { BISB_M(IN,DE); } }
+static void bisb_in_ded(void) { t11_ICount -= 15+21; { BISB_M(IN,DED); } }
+static void bisb_in_ix(void) { t11_ICount -= 15+21; { BISB_M(IN,IX); } }
+static void bisb_in_ixd(void) { t11_ICount -= 15+27; { BISB_M(IN,IXD); } }
+static void bisb_ind_rg(void) { t11_ICount -= 21+ 3; { BISB_X(IND,RG); } }
+static void bisb_ind_rgd(void) { t11_ICount -= 21+12; { BISB_M(IND,RGD); } }
+static void bisb_ind_in(void) { t11_ICount -= 21+12; { BISB_M(IND,IN); } }
+static void bisb_ind_ind(void) { t11_ICount -= 21+18; { BISB_M(IND,IND); } }
+static void bisb_ind_de(void) { t11_ICount -= 21+15; { BISB_M(IND,DE); } }
+static void bisb_ind_ded(void) { t11_ICount -= 21+21; { BISB_M(IND,DED); } }
+static void bisb_ind_ix(void) { t11_ICount -= 21+21; { BISB_M(IND,IX); } }
+static void bisb_ind_ixd(void) { t11_ICount -= 21+27; { BISB_M(IND,IXD); } }
+static void bisb_de_rg(void) { t11_ICount -= 18+ 3; { BISB_X(DE,RG); } }
+static void bisb_de_rgd(void) { t11_ICount -= 18+12; { BISB_M(DE,RGD); } }
+static void bisb_de_in(void) { t11_ICount -= 18+12; { BISB_M(DE,IN); } }
+static void bisb_de_ind(void) { t11_ICount -= 18+18; { BISB_M(DE,IND); } }
+static void bisb_de_de(void) { t11_ICount -= 18+15; { BISB_M(DE,DE); } }
+static void bisb_de_ded(void) { t11_ICount -= 18+21; { BISB_M(DE,DED); } }
+static void bisb_de_ix(void) { t11_ICount -= 18+21; { BISB_M(DE,IX); } }
+static void bisb_de_ixd(void) { t11_ICount -= 18+27; { BISB_M(DE,IXD); } }
+static void bisb_ded_rg(void) { t11_ICount -= 24+ 3; { BISB_X(DED,RG); } }
+static void bisb_ded_rgd(void) { t11_ICount -= 24+12; { BISB_M(DED,RGD); } }
+static void bisb_ded_in(void) { t11_ICount -= 24+12; { BISB_M(DED,IN); } }
+static void bisb_ded_ind(void) { t11_ICount -= 24+18; { BISB_M(DED,IND); } }
+static void bisb_ded_de(void) { t11_ICount -= 24+15; { BISB_M(DED,DE); } }
+static void bisb_ded_ded(void) { t11_ICount -= 24+21; { BISB_M(DED,DED); } }
+static void bisb_ded_ix(void) { t11_ICount -= 24+21; { BISB_M(DED,IX); } }
+static void bisb_ded_ixd(void) { t11_ICount -= 24+27; { BISB_M(DED,IXD); } }
+static void bisb_ix_rg(void) { t11_ICount -= 24+ 3; { BISB_X(IX,RG); } }
+static void bisb_ix_rgd(void) { t11_ICount -= 24+12; { BISB_M(IX,RGD); } }
+static void bisb_ix_in(void) { t11_ICount -= 24+12; { BISB_M(IX,IN); } }
+static void bisb_ix_ind(void) { t11_ICount -= 24+18; { BISB_M(IX,IND); } }
+static void bisb_ix_de(void) { t11_ICount -= 24+15; { BISB_M(IX,DE); } }
+static void bisb_ix_ded(void) { t11_ICount -= 24+21; { BISB_M(IX,DED); } }
+static void bisb_ix_ix(void) { t11_ICount -= 24+21; { BISB_M(IX,IX); } }
+static void bisb_ix_ixd(void) { t11_ICount -= 24+27; { BISB_M(IX,IXD); } }
+static void bisb_ixd_rg(void) { t11_ICount -= 30+ 3; { BISB_X(IXD,RG); } }
+static void bisb_ixd_rgd(void) { t11_ICount -= 30+12; { BISB_M(IXD,RGD); } }
+static void bisb_ixd_in(void) { t11_ICount -= 30+12; { BISB_M(IXD,IN); } }
+static void bisb_ixd_ind(void) { t11_ICount -= 30+18; { BISB_M(IXD,IND); } }
+static void bisb_ixd_de(void) { t11_ICount -= 30+15; { BISB_M(IXD,DE); } }
+static void bisb_ixd_ded(void) { t11_ICount -= 30+21; { BISB_M(IXD,DED); } }
+static void bisb_ixd_ix(void) { t11_ICount -= 30+21; { BISB_M(IXD,IX); } }
+static void bisb_ixd_ixd(void) { t11_ICount -= 30+27; { BISB_M(IXD,IXD); } }
+
+static void sub_rg_rg(void) { t11_ICount -= 9+ 3; { SUB_R(RG,RG); } }
+static void sub_rg_rgd(void) { t11_ICount -= 9+12; { SUB_M(RG,RGD); } }
+static void sub_rg_in(void) { t11_ICount -= 9+12; { SUB_M(RG,IN); } }
+static void sub_rg_ind(void) { t11_ICount -= 9+18; { SUB_M(RG,IND); } }
+static void sub_rg_de(void) { t11_ICount -= 9+15; { SUB_M(RG,DE); } }
+static void sub_rg_ded(void) { t11_ICount -= 9+21; { SUB_M(RG,DED); } }
+static void sub_rg_ix(void) { t11_ICount -= 9+21; { SUB_M(RG,IX); } }
+static void sub_rg_ixd(void) { t11_ICount -= 9+27; { SUB_M(RG,IXD); } }
+static void sub_rgd_rg(void) { t11_ICount -= 15+ 3; { SUB_X(RGD,RG); } }
+static void sub_rgd_rgd(void) { t11_ICount -= 15+12; { SUB_M(RGD,RGD); } }
+static void sub_rgd_in(void) { t11_ICount -= 15+12; { SUB_M(RGD,IN); } }
+static void sub_rgd_ind(void) { t11_ICount -= 15+18; { SUB_M(RGD,IND); } }
+static void sub_rgd_de(void) { t11_ICount -= 15+15; { SUB_M(RGD,DE); } }
+static void sub_rgd_ded(void) { t11_ICount -= 15+21; { SUB_M(RGD,DED); } }
+static void sub_rgd_ix(void) { t11_ICount -= 15+21; { SUB_M(RGD,IX); } }
+static void sub_rgd_ixd(void) { t11_ICount -= 15+27; { SUB_M(RGD,IXD); } }
+static void sub_in_rg(void) { t11_ICount -= 15+ 3; { SUB_X(IN,RG); } }
+static void sub_in_rgd(void) { t11_ICount -= 15+12; { SUB_M(IN,RGD); } }
+static void sub_in_in(void) { t11_ICount -= 15+12; { SUB_M(IN,IN); } }
+static void sub_in_ind(void) { t11_ICount -= 15+18; { SUB_M(IN,IND); } }
+static void sub_in_de(void) { t11_ICount -= 15+15; { SUB_M(IN,DE); } }
+static void sub_in_ded(void) { t11_ICount -= 15+21; { SUB_M(IN,DED); } }
+static void sub_in_ix(void) { t11_ICount -= 15+21; { SUB_M(IN,IX); } }
+static void sub_in_ixd(void) { t11_ICount -= 15+27; { SUB_M(IN,IXD); } }
+static void sub_ind_rg(void) { t11_ICount -= 21+ 3; { SUB_X(IND,RG); } }
+static void sub_ind_rgd(void) { t11_ICount -= 21+12; { SUB_M(IND,RGD); } }
+static void sub_ind_in(void) { t11_ICount -= 21+12; { SUB_M(IND,IN); } }
+static void sub_ind_ind(void) { t11_ICount -= 21+18; { SUB_M(IND,IND); } }
+static void sub_ind_de(void) { t11_ICount -= 21+15; { SUB_M(IND,DE); } }
+static void sub_ind_ded(void) { t11_ICount -= 21+21; { SUB_M(IND,DED); } }
+static void sub_ind_ix(void) { t11_ICount -= 21+21; { SUB_M(IND,IX); } }
+static void sub_ind_ixd(void) { t11_ICount -= 21+27; { SUB_M(IND,IXD); } }
+static void sub_de_rg(void) { t11_ICount -= 18+ 3; { SUB_X(DE,RG); } }
+static void sub_de_rgd(void) { t11_ICount -= 18+12; { SUB_M(DE,RGD); } }
+static void sub_de_in(void) { t11_ICount -= 18+12; { SUB_M(DE,IN); } }
+static void sub_de_ind(void) { t11_ICount -= 18+18; { SUB_M(DE,IND); } }
+static void sub_de_de(void) { t11_ICount -= 18+15; { SUB_M(DE,DE); } }
+static void sub_de_ded(void) { t11_ICount -= 18+21; { SUB_M(DE,DED); } }
+static void sub_de_ix(void) { t11_ICount -= 18+21; { SUB_M(DE,IX); } }
+static void sub_de_ixd(void) { t11_ICount -= 18+27; { SUB_M(DE,IXD); } }
+static void sub_ded_rg(void) { t11_ICount -= 24+ 3; { SUB_X(DED,RG); } }
+static void sub_ded_rgd(void) { t11_ICount -= 24+12; { SUB_M(DED,RGD); } }
+static void sub_ded_in(void) { t11_ICount -= 24+12; { SUB_M(DED,IN); } }
+static void sub_ded_ind(void) { t11_ICount -= 24+18; { SUB_M(DED,IND); } }
+static void sub_ded_de(void) { t11_ICount -= 24+15; { SUB_M(DED,DE); } }
+static void sub_ded_ded(void) { t11_ICount -= 24+21; { SUB_M(DED,DED); } }
+static void sub_ded_ix(void) { t11_ICount -= 24+21; { SUB_M(DED,IX); } }
+static void sub_ded_ixd(void) { t11_ICount -= 24+27; { SUB_M(DED,IXD); } }
+static void sub_ix_rg(void) { t11_ICount -= 24+ 3; { SUB_X(IX,RG); } }
+static void sub_ix_rgd(void) { t11_ICount -= 24+12; { SUB_M(IX,RGD); } }
+static void sub_ix_in(void) { t11_ICount -= 24+12; { SUB_M(IX,IN); } }
+static void sub_ix_ind(void) { t11_ICount -= 24+18; { SUB_M(IX,IND); } }
+static void sub_ix_de(void) { t11_ICount -= 24+15; { SUB_M(IX,DE); } }
+static void sub_ix_ded(void) { t11_ICount -= 24+21; { SUB_M(IX,DED); } }
+static void sub_ix_ix(void) { t11_ICount -= 24+21; { SUB_M(IX,IX); } }
+static void sub_ix_ixd(void) { t11_ICount -= 24+27; { SUB_M(IX,IXD); } }
+static void sub_ixd_rg(void) { t11_ICount -= 30+ 3; { SUB_X(IXD,RG); } }
+static void sub_ixd_rgd(void) { t11_ICount -= 30+12; { SUB_M(IXD,RGD); } }
+static void sub_ixd_in(void) { t11_ICount -= 30+12; { SUB_M(IXD,IN); } }
+static void sub_ixd_ind(void) { t11_ICount -= 30+18; { SUB_M(IXD,IND); } }
+static void sub_ixd_de(void) { t11_ICount -= 30+15; { SUB_M(IXD,DE); } }
+static void sub_ixd_ded(void) { t11_ICount -= 30+21; { SUB_M(IXD,DED); } }
+static void sub_ixd_ix(void) { t11_ICount -= 30+21; { SUB_M(IXD,IX); } }
+static void sub_ixd_ixd(void) { t11_ICount -= 30+27; { SUB_M(IXD,IXD); } }
diff --git a/src/emu/cpu/t11/t11table.c b/src/emu/cpu/t11/t11table.c
new file mode 100644
index 00000000000..eeeb8007405
--- /dev/null
+++ b/src/emu/cpu/t11/t11table.c
@@ -0,0 +1,2409 @@
+/*** t11: Portable DEC T-11 emulator ******************************************
+
+ Copyright (C) Aaron Giles 1998
+
+ Opcode table plus function prototypes
+
+*****************************************************************************/
+
+/*
+
+modes:
+ rg = register
+ rgd = register deferred
+ in = increment
+ ind = increment deferred
+ de = decrement
+ ded = decrement deferred
+ ix = index
+ ixd = index deferred
+
+*/
+
+static void op_0000(void);
+static void illegal(void);
+
+static void jmp_rgd(void);
+static void jmp_in(void);
+static void jmp_ind(void);
+static void jmp_de(void);
+static void jmp_ded(void);
+static void jmp_ix(void);
+static void jmp_ixd(void);
+
+static void rts(void);
+static void ccc(void);
+static void scc(void);
+
+static void swab_rg(void);
+static void swab_rgd(void);
+static void swab_in(void);
+static void swab_ind(void);
+static void swab_de(void);
+static void swab_ded(void);
+static void swab_ix(void);
+static void swab_ixd(void);
+
+static void br(void);
+static void bne(void);
+static void beq(void);
+static void bge(void);
+static void blt(void);
+static void bgt(void);
+static void ble(void);
+
+static void jsr_rgd(void);
+static void jsr_in(void);
+static void jsr_ind(void);
+static void jsr_de(void);
+static void jsr_ded(void);
+static void jsr_ix(void);
+static void jsr_ixd(void);
+
+static void clr_rg(void);
+static void clr_rgd(void);
+static void clr_in(void);
+static void clr_ind(void);
+static void clr_de(void);
+static void clr_ded(void);
+static void clr_ix(void);
+static void clr_ixd(void);
+
+static void com_rg(void);
+static void com_rgd(void);
+static void com_in(void);
+static void com_ind(void);
+static void com_de(void);
+static void com_ded(void);
+static void com_ix(void);
+static void com_ixd(void);
+
+static void inc_rg(void);
+static void inc_rgd(void);
+static void inc_in(void);
+static void inc_ind(void);
+static void inc_de(void);
+static void inc_ded(void);
+static void inc_ix(void);
+static void inc_ixd(void);
+
+static void dec_rg(void);
+static void dec_rgd(void);
+static void dec_in(void);
+static void dec_ind(void);
+static void dec_de(void);
+static void dec_ded(void);
+static void dec_ix(void);
+static void dec_ixd(void);
+
+static void neg_rg(void);
+static void neg_rgd(void);
+static void neg_in(void);
+static void neg_ind(void);
+static void neg_de(void);
+static void neg_ded(void);
+static void neg_ix(void);
+static void neg_ixd(void);
+
+static void adc_rg(void);
+static void adc_rgd(void);
+static void adc_in(void);
+static void adc_ind(void);
+static void adc_de(void);
+static void adc_ded(void);
+static void adc_ix(void);
+static void adc_ixd(void);
+
+static void sbc_rg(void);
+static void sbc_rgd(void);
+static void sbc_in(void);
+static void sbc_ind(void);
+static void sbc_de(void);
+static void sbc_ded(void);
+static void sbc_ix(void);
+static void sbc_ixd(void);
+
+static void tst_rg(void);
+static void tst_rgd(void);
+static void tst_in(void);
+static void tst_ind(void);
+static void tst_de(void);
+static void tst_ded(void);
+static void tst_ix(void);
+static void tst_ixd(void);
+
+static void ror_rg(void);
+static void ror_rgd(void);
+static void ror_in(void);
+static void ror_ind(void);
+static void ror_de(void);
+static void ror_ded(void);
+static void ror_ix(void);
+static void ror_ixd(void);
+
+static void rol_rg(void);
+static void rol_rgd(void);
+static void rol_in(void);
+static void rol_ind(void);
+static void rol_de(void);
+static void rol_ded(void);
+static void rol_ix(void);
+static void rol_ixd(void);
+
+static void asr_rg(void);
+static void asr_rgd(void);
+static void asr_in(void);
+static void asr_ind(void);
+static void asr_de(void);
+static void asr_ded(void);
+static void asr_ix(void);
+static void asr_ixd(void);
+
+static void asl_rg(void);
+static void asl_rgd(void);
+static void asl_in(void);
+static void asl_ind(void);
+static void asl_de(void);
+static void asl_ded(void);
+static void asl_ix(void);
+static void asl_ixd(void);
+
+/*static void mark(void);*/
+
+static void sxt_rg(void);
+static void sxt_rgd(void);
+static void sxt_in(void);
+static void sxt_ind(void);
+static void sxt_de(void);
+static void sxt_ded(void);
+static void sxt_ix(void);
+static void sxt_ixd(void);
+
+static void mov_rg_rg(void);
+static void mov_rg_rgd(void);
+static void mov_rg_in(void);
+static void mov_rg_ind(void);
+static void mov_rg_de(void);
+static void mov_rg_ded(void);
+static void mov_rg_ix(void);
+static void mov_rg_ixd(void);
+static void mov_rgd_rg(void);
+static void mov_rgd_rgd(void);
+static void mov_rgd_in(void);
+static void mov_rgd_ind(void);
+static void mov_rgd_de(void);
+static void mov_rgd_ded(void);
+static void mov_rgd_ix(void);
+static void mov_rgd_ixd(void);
+static void mov_in_rg(void);
+static void mov_in_rgd(void);
+static void mov_in_in(void);
+static void mov_in_ind(void);
+static void mov_in_de(void);
+static void mov_in_ded(void);
+static void mov_in_ix(void);
+static void mov_in_ixd(void);
+static void mov_ind_rg(void);
+static void mov_ind_rgd(void);
+static void mov_ind_in(void);
+static void mov_ind_ind(void);
+static void mov_ind_de(void);
+static void mov_ind_ded(void);
+static void mov_ind_ix(void);
+static void mov_ind_ixd(void);
+static void mov_de_rg(void);
+static void mov_de_rgd(void);
+static void mov_de_in(void);
+static void mov_de_ind(void);
+static void mov_de_de(void);
+static void mov_de_ded(void);
+static void mov_de_ix(void);
+static void mov_de_ixd(void);
+static void mov_ded_rg(void);
+static void mov_ded_rgd(void);
+static void mov_ded_in(void);
+static void mov_ded_ind(void);
+static void mov_ded_de(void);
+static void mov_ded_ded(void);
+static void mov_ded_ix(void);
+static void mov_ded_ixd(void);
+static void mov_ix_rg(void);
+static void mov_ix_rgd(void);
+static void mov_ix_in(void);
+static void mov_ix_ind(void);
+static void mov_ix_de(void);
+static void mov_ix_ded(void);
+static void mov_ix_ix(void);
+static void mov_ix_ixd(void);
+static void mov_ixd_rg(void);
+static void mov_ixd_rgd(void);
+static void mov_ixd_in(void);
+static void mov_ixd_ind(void);
+static void mov_ixd_de(void);
+static void mov_ixd_ded(void);
+static void mov_ixd_ix(void);
+static void mov_ixd_ixd(void);
+
+static void cmp_rg_rg(void);
+static void cmp_rg_rgd(void);
+static void cmp_rg_in(void);
+static void cmp_rg_ind(void);
+static void cmp_rg_de(void);
+static void cmp_rg_ded(void);
+static void cmp_rg_ix(void);
+static void cmp_rg_ixd(void);
+static void cmp_rgd_rg(void);
+static void cmp_rgd_rgd(void);
+static void cmp_rgd_in(void);
+static void cmp_rgd_ind(void);
+static void cmp_rgd_de(void);
+static void cmp_rgd_ded(void);
+static void cmp_rgd_ix(void);
+static void cmp_rgd_ixd(void);
+static void cmp_in_rg(void);
+static void cmp_in_rgd(void);
+static void cmp_in_in(void);
+static void cmp_in_ind(void);
+static void cmp_in_de(void);
+static void cmp_in_ded(void);
+static void cmp_in_ix(void);
+static void cmp_in_ixd(void);
+static void cmp_ind_rg(void);
+static void cmp_ind_rgd(void);
+static void cmp_ind_in(void);
+static void cmp_ind_ind(void);
+static void cmp_ind_de(void);
+static void cmp_ind_ded(void);
+static void cmp_ind_ix(void);
+static void cmp_ind_ixd(void);
+static void cmp_de_rg(void);
+static void cmp_de_rgd(void);
+static void cmp_de_in(void);
+static void cmp_de_ind(void);
+static void cmp_de_de(void);
+static void cmp_de_ded(void);
+static void cmp_de_ix(void);
+static void cmp_de_ixd(void);
+static void cmp_ded_rg(void);
+static void cmp_ded_rgd(void);
+static void cmp_ded_in(void);
+static void cmp_ded_ind(void);
+static void cmp_ded_de(void);
+static void cmp_ded_ded(void);
+static void cmp_ded_ix(void);
+static void cmp_ded_ixd(void);
+static void cmp_ix_rg(void);
+static void cmp_ix_rgd(void);
+static void cmp_ix_in(void);
+static void cmp_ix_ind(void);
+static void cmp_ix_de(void);
+static void cmp_ix_ded(void);
+static void cmp_ix_ix(void);
+static void cmp_ix_ixd(void);
+static void cmp_ixd_rg(void);
+static void cmp_ixd_rgd(void);
+static void cmp_ixd_in(void);
+static void cmp_ixd_ind(void);
+static void cmp_ixd_de(void);
+static void cmp_ixd_ded(void);
+static void cmp_ixd_ix(void);
+static void cmp_ixd_ixd(void);
+
+static void bit_rg_rg(void);
+static void bit_rg_rgd(void);
+static void bit_rg_in(void);
+static void bit_rg_ind(void);
+static void bit_rg_de(void);
+static void bit_rg_ded(void);
+static void bit_rg_ix(void);
+static void bit_rg_ixd(void);
+static void bit_rgd_rg(void);
+static void bit_rgd_rgd(void);
+static void bit_rgd_in(void);
+static void bit_rgd_ind(void);
+static void bit_rgd_de(void);
+static void bit_rgd_ded(void);
+static void bit_rgd_ix(void);
+static void bit_rgd_ixd(void);
+static void bit_in_rg(void);
+static void bit_in_rgd(void);
+static void bit_in_in(void);
+static void bit_in_ind(void);
+static void bit_in_de(void);
+static void bit_in_ded(void);
+static void bit_in_ix(void);
+static void bit_in_ixd(void);
+static void bit_ind_rg(void);
+static void bit_ind_rgd(void);
+static void bit_ind_in(void);
+static void bit_ind_ind(void);
+static void bit_ind_de(void);
+static void bit_ind_ded(void);
+static void bit_ind_ix(void);
+static void bit_ind_ixd(void);
+static void bit_de_rg(void);
+static void bit_de_rgd(void);
+static void bit_de_in(void);
+static void bit_de_ind(void);
+static void bit_de_de(void);
+static void bit_de_ded(void);
+static void bit_de_ix(void);
+static void bit_de_ixd(void);
+static void bit_ded_rg(void);
+static void bit_ded_rgd(void);
+static void bit_ded_in(void);
+static void bit_ded_ind(void);
+static void bit_ded_de(void);
+static void bit_ded_ded(void);
+static void bit_ded_ix(void);
+static void bit_ded_ixd(void);
+static void bit_ix_rg(void);
+static void bit_ix_rgd(void);
+static void bit_ix_in(void);
+static void bit_ix_ind(void);
+static void bit_ix_de(void);
+static void bit_ix_ded(void);
+static void bit_ix_ix(void);
+static void bit_ix_ixd(void);
+static void bit_ixd_rg(void);
+static void bit_ixd_rgd(void);
+static void bit_ixd_in(void);
+static void bit_ixd_ind(void);
+static void bit_ixd_de(void);
+static void bit_ixd_ded(void);
+static void bit_ixd_ix(void);
+static void bit_ixd_ixd(void);
+
+static void bic_rg_rg(void);
+static void bic_rg_rgd(void);
+static void bic_rg_in(void);
+static void bic_rg_ind(void);
+static void bic_rg_de(void);
+static void bic_rg_ded(void);
+static void bic_rg_ix(void);
+static void bic_rg_ixd(void);
+static void bic_rgd_rg(void);
+static void bic_rgd_rgd(void);
+static void bic_rgd_in(void);
+static void bic_rgd_ind(void);
+static void bic_rgd_de(void);
+static void bic_rgd_ded(void);
+static void bic_rgd_ix(void);
+static void bic_rgd_ixd(void);
+static void bic_in_rg(void);
+static void bic_in_rgd(void);
+static void bic_in_in(void);
+static void bic_in_ind(void);
+static void bic_in_de(void);
+static void bic_in_ded(void);
+static void bic_in_ix(void);
+static void bic_in_ixd(void);
+static void bic_ind_rg(void);
+static void bic_ind_rgd(void);
+static void bic_ind_in(void);
+static void bic_ind_ind(void);
+static void bic_ind_de(void);
+static void bic_ind_ded(void);
+static void bic_ind_ix(void);
+static void bic_ind_ixd(void);
+static void bic_de_rg(void);
+static void bic_de_rgd(void);
+static void bic_de_in(void);
+static void bic_de_ind(void);
+static void bic_de_de(void);
+static void bic_de_ded(void);
+static void bic_de_ix(void);
+static void bic_de_ixd(void);
+static void bic_ded_rg(void);
+static void bic_ded_rgd(void);
+static void bic_ded_in(void);
+static void bic_ded_ind(void);
+static void bic_ded_de(void);
+static void bic_ded_ded(void);
+static void bic_ded_ix(void);
+static void bic_ded_ixd(void);
+static void bic_ix_rg(void);
+static void bic_ix_rgd(void);
+static void bic_ix_in(void);
+static void bic_ix_ind(void);
+static void bic_ix_de(void);
+static void bic_ix_ded(void);
+static void bic_ix_ix(void);
+static void bic_ix_ixd(void);
+static void bic_ixd_rg(void);
+static void bic_ixd_rgd(void);
+static void bic_ixd_in(void);
+static void bic_ixd_ind(void);
+static void bic_ixd_de(void);
+static void bic_ixd_ded(void);
+static void bic_ixd_ix(void);
+static void bic_ixd_ixd(void);
+
+static void bis_rg_rg(void);
+static void bis_rg_rgd(void);
+static void bis_rg_in(void);
+static void bis_rg_ind(void);
+static void bis_rg_de(void);
+static void bis_rg_ded(void);
+static void bis_rg_ix(void);
+static void bis_rg_ixd(void);
+static void bis_rgd_rg(void);
+static void bis_rgd_rgd(void);
+static void bis_rgd_in(void);
+static void bis_rgd_ind(void);
+static void bis_rgd_de(void);
+static void bis_rgd_ded(void);
+static void bis_rgd_ix(void);
+static void bis_rgd_ixd(void);
+static void bis_in_rg(void);
+static void bis_in_rgd(void);
+static void bis_in_in(void);
+static void bis_in_ind(void);
+static void bis_in_de(void);
+static void bis_in_ded(void);
+static void bis_in_ix(void);
+static void bis_in_ixd(void);
+static void bis_ind_rg(void);
+static void bis_ind_rgd(void);
+static void bis_ind_in(void);
+static void bis_ind_ind(void);
+static void bis_ind_de(void);
+static void bis_ind_ded(void);
+static void bis_ind_ix(void);
+static void bis_ind_ixd(void);
+static void bis_de_rg(void);
+static void bis_de_rgd(void);
+static void bis_de_in(void);
+static void bis_de_ind(void);
+static void bis_de_de(void);
+static void bis_de_ded(void);
+static void bis_de_ix(void);
+static void bis_de_ixd(void);
+static void bis_ded_rg(void);
+static void bis_ded_rgd(void);
+static void bis_ded_in(void);
+static void bis_ded_ind(void);
+static void bis_ded_de(void);
+static void bis_ded_ded(void);
+static void bis_ded_ix(void);
+static void bis_ded_ixd(void);
+static void bis_ix_rg(void);
+static void bis_ix_rgd(void);
+static void bis_ix_in(void);
+static void bis_ix_ind(void);
+static void bis_ix_de(void);
+static void bis_ix_ded(void);
+static void bis_ix_ix(void);
+static void bis_ix_ixd(void);
+static void bis_ixd_rg(void);
+static void bis_ixd_rgd(void);
+static void bis_ixd_in(void);
+static void bis_ixd_ind(void);
+static void bis_ixd_de(void);
+static void bis_ixd_ded(void);
+static void bis_ixd_ix(void);
+static void bis_ixd_ixd(void);
+
+static void add_rg_rg(void);
+static void add_rg_rgd(void);
+static void add_rg_in(void);
+static void add_rg_ind(void);
+static void add_rg_de(void);
+static void add_rg_ded(void);
+static void add_rg_ix(void);
+static void add_rg_ixd(void);
+static void add_rgd_rg(void);
+static void add_rgd_rgd(void);
+static void add_rgd_in(void);
+static void add_rgd_ind(void);
+static void add_rgd_de(void);
+static void add_rgd_ded(void);
+static void add_rgd_ix(void);
+static void add_rgd_ixd(void);
+static void add_in_rg(void);
+static void add_in_rgd(void);
+static void add_in_in(void);
+static void add_in_ind(void);
+static void add_in_de(void);
+static void add_in_ded(void);
+static void add_in_ix(void);
+static void add_in_ixd(void);
+static void add_ind_rg(void);
+static void add_ind_rgd(void);
+static void add_ind_in(void);
+static void add_ind_ind(void);
+static void add_ind_de(void);
+static void add_ind_ded(void);
+static void add_ind_ix(void);
+static void add_ind_ixd(void);
+static void add_de_rg(void);
+static void add_de_rgd(void);
+static void add_de_in(void);
+static void add_de_ind(void);
+static void add_de_de(void);
+static void add_de_ded(void);
+static void add_de_ix(void);
+static void add_de_ixd(void);
+static void add_ded_rg(void);
+static void add_ded_rgd(void);
+static void add_ded_in(void);
+static void add_ded_ind(void);
+static void add_ded_de(void);
+static void add_ded_ded(void);
+static void add_ded_ix(void);
+static void add_ded_ixd(void);
+static void add_ix_rg(void);
+static void add_ix_rgd(void);
+static void add_ix_in(void);
+static void add_ix_ind(void);
+static void add_ix_de(void);
+static void add_ix_ded(void);
+static void add_ix_ix(void);
+static void add_ix_ixd(void);
+static void add_ixd_rg(void);
+static void add_ixd_rgd(void);
+static void add_ixd_in(void);
+static void add_ixd_ind(void);
+static void add_ixd_de(void);
+static void add_ixd_ded(void);
+static void add_ixd_ix(void);
+static void add_ixd_ixd(void);
+
+static void xor_rg(void);
+static void xor_rgd(void);
+static void xor_in(void);
+static void xor_ind(void);
+static void xor_de(void);
+static void xor_ded(void);
+static void xor_ix(void);
+static void xor_ixd(void);
+
+static void sob(void);
+
+static void bpl(void);
+static void bmi(void);
+static void bhi(void);
+static void blos(void);
+static void bvc(void);
+static void bvs(void);
+static void bcc(void);
+static void bcs(void);
+static void emt(void);
+static void trap(void);
+
+static void clrb_rg(void);
+static void clrb_rgd(void);
+static void clrb_in(void);
+static void clrb_ind(void);
+static void clrb_de(void);
+static void clrb_ded(void);
+static void clrb_ix(void);
+static void clrb_ixd(void);
+
+static void comb_rg(void);
+static void comb_rgd(void);
+static void comb_in(void);
+static void comb_ind(void);
+static void comb_de(void);
+static void comb_ded(void);
+static void comb_ix(void);
+static void comb_ixd(void);
+
+static void incb_rg(void);
+static void incb_rgd(void);
+static void incb_in(void);
+static void incb_ind(void);
+static void incb_de(void);
+static void incb_ded(void);
+static void incb_ix(void);
+static void incb_ixd(void);
+
+static void decb_rg(void);
+static void decb_rgd(void);
+static void decb_in(void);
+static void decb_ind(void);
+static void decb_de(void);
+static void decb_ded(void);
+static void decb_ix(void);
+static void decb_ixd(void);
+
+static void negb_rg(void);
+static void negb_rgd(void);
+static void negb_in(void);
+static void negb_ind(void);
+static void negb_de(void);
+static void negb_ded(void);
+static void negb_ix(void);
+static void negb_ixd(void);
+
+static void adcb_rg(void);
+static void adcb_rgd(void);
+static void adcb_in(void);
+static void adcb_ind(void);
+static void adcb_de(void);
+static void adcb_ded(void);
+static void adcb_ix(void);
+static void adcb_ixd(void);
+
+static void sbcb_rg(void);
+static void sbcb_rgd(void);
+static void sbcb_in(void);
+static void sbcb_ind(void);
+static void sbcb_de(void);
+static void sbcb_ded(void);
+static void sbcb_ix(void);
+static void sbcb_ixd(void);
+
+static void tstb_rg(void);
+static void tstb_rgd(void);
+static void tstb_in(void);
+static void tstb_ind(void);
+static void tstb_de(void);
+static void tstb_ded(void);
+static void tstb_ix(void);
+static void tstb_ixd(void);
+
+static void rorb_rg(void);
+static void rorb_rgd(void);
+static void rorb_in(void);
+static void rorb_ind(void);
+static void rorb_de(void);
+static void rorb_ded(void);
+static void rorb_ix(void);
+static void rorb_ixd(void);
+
+static void rolb_rg(void);
+static void rolb_rgd(void);
+static void rolb_in(void);
+static void rolb_ind(void);
+static void rolb_de(void);
+static void rolb_ded(void);
+static void rolb_ix(void);
+static void rolb_ixd(void);
+
+static void asrb_rg(void);
+static void asrb_rgd(void);
+static void asrb_in(void);
+static void asrb_ind(void);
+static void asrb_de(void);
+static void asrb_ded(void);
+static void asrb_ix(void);
+static void asrb_ixd(void);
+
+static void aslb_rg(void);
+static void aslb_rgd(void);
+static void aslb_in(void);
+static void aslb_ind(void);
+static void aslb_de(void);
+static void aslb_ded(void);
+static void aslb_ix(void);
+static void aslb_ixd(void);
+
+static void mtps_rg(void);
+static void mtps_rgd(void);
+static void mtps_in(void);
+static void mtps_ind(void);
+static void mtps_de(void);
+static void mtps_ded(void);
+static void mtps_ix(void);
+static void mtps_ixd(void);
+
+static void mfps_rg(void);
+static void mfps_rgd(void);
+static void mfps_in(void);
+static void mfps_ind(void);
+static void mfps_de(void);
+static void mfps_ded(void);
+static void mfps_ix(void);
+static void mfps_ixd(void);
+
+static void movb_rg_rg(void);
+static void movb_rg_rgd(void);
+static void movb_rg_in(void);
+static void movb_rg_ind(void);
+static void movb_rg_de(void);
+static void movb_rg_ded(void);
+static void movb_rg_ix(void);
+static void movb_rg_ixd(void);
+static void movb_rgd_rg(void);
+static void movb_rgd_rgd(void);
+static void movb_rgd_in(void);
+static void movb_rgd_ind(void);
+static void movb_rgd_de(void);
+static void movb_rgd_ded(void);
+static void movb_rgd_ix(void);
+static void movb_rgd_ixd(void);
+static void movb_in_rg(void);
+static void movb_in_rgd(void);
+static void movb_in_in(void);
+static void movb_in_ind(void);
+static void movb_in_de(void);
+static void movb_in_ded(void);
+static void movb_in_ix(void);
+static void movb_in_ixd(void);
+static void movb_ind_rg(void);
+static void movb_ind_rgd(void);
+static void movb_ind_in(void);
+static void movb_ind_ind(void);
+static void movb_ind_de(void);
+static void movb_ind_ded(void);
+static void movb_ind_ix(void);
+static void movb_ind_ixd(void);
+static void movb_de_rg(void);
+static void movb_de_rgd(void);
+static void movb_de_in(void);
+static void movb_de_ind(void);
+static void movb_de_de(void);
+static void movb_de_ded(void);
+static void movb_de_ix(void);
+static void movb_de_ixd(void);
+static void movb_ded_rg(void);
+static void movb_ded_rgd(void);
+static void movb_ded_in(void);
+static void movb_ded_ind(void);
+static void movb_ded_de(void);
+static void movb_ded_ded(void);
+static void movb_ded_ix(void);
+static void movb_ded_ixd(void);
+static void movb_ix_rg(void);
+static void movb_ix_rgd(void);
+static void movb_ix_in(void);
+static void movb_ix_ind(void);
+static void movb_ix_de(void);
+static void movb_ix_ded(void);
+static void movb_ix_ix(void);
+static void movb_ix_ixd(void);
+static void movb_ixd_rg(void);
+static void movb_ixd_rgd(void);
+static void movb_ixd_in(void);
+static void movb_ixd_ind(void);
+static void movb_ixd_de(void);
+static void movb_ixd_ded(void);
+static void movb_ixd_ix(void);
+static void movb_ixd_ixd(void);
+
+static void cmpb_rg_rg(void);
+static void cmpb_rg_rgd(void);
+static void cmpb_rg_in(void);
+static void cmpb_rg_ind(void);
+static void cmpb_rg_de(void);
+static void cmpb_rg_ded(void);
+static void cmpb_rg_ix(void);
+static void cmpb_rg_ixd(void);
+static void cmpb_rgd_rg(void);
+static void cmpb_rgd_rgd(void);
+static void cmpb_rgd_in(void);
+static void cmpb_rgd_ind(void);
+static void cmpb_rgd_de(void);
+static void cmpb_rgd_ded(void);
+static void cmpb_rgd_ix(void);
+static void cmpb_rgd_ixd(void);
+static void cmpb_in_rg(void);
+static void cmpb_in_rgd(void);
+static void cmpb_in_in(void);
+static void cmpb_in_ind(void);
+static void cmpb_in_de(void);
+static void cmpb_in_ded(void);
+static void cmpb_in_ix(void);
+static void cmpb_in_ixd(void);
+static void cmpb_ind_rg(void);
+static void cmpb_ind_rgd(void);
+static void cmpb_ind_in(void);
+static void cmpb_ind_ind(void);
+static void cmpb_ind_de(void);
+static void cmpb_ind_ded(void);
+static void cmpb_ind_ix(void);
+static void cmpb_ind_ixd(void);
+static void cmpb_de_rg(void);
+static void cmpb_de_rgd(void);
+static void cmpb_de_in(void);
+static void cmpb_de_ind(void);
+static void cmpb_de_de(void);
+static void cmpb_de_ded(void);
+static void cmpb_de_ix(void);
+static void cmpb_de_ixd(void);
+static void cmpb_ded_rg(void);
+static void cmpb_ded_rgd(void);
+static void cmpb_ded_in(void);
+static void cmpb_ded_ind(void);
+static void cmpb_ded_de(void);
+static void cmpb_ded_ded(void);
+static void cmpb_ded_ix(void);
+static void cmpb_ded_ixd(void);
+static void cmpb_ix_rg(void);
+static void cmpb_ix_rgd(void);
+static void cmpb_ix_in(void);
+static void cmpb_ix_ind(void);
+static void cmpb_ix_de(void);
+static void cmpb_ix_ded(void);
+static void cmpb_ix_ix(void);
+static void cmpb_ix_ixd(void);
+static void cmpb_ixd_rg(void);
+static void cmpb_ixd_rgd(void);
+static void cmpb_ixd_in(void);
+static void cmpb_ixd_ind(void);
+static void cmpb_ixd_de(void);
+static void cmpb_ixd_ded(void);
+static void cmpb_ixd_ix(void);
+static void cmpb_ixd_ixd(void);
+
+static void bitb_rg_rg(void);
+static void bitb_rg_rgd(void);
+static void bitb_rg_in(void);
+static void bitb_rg_ind(void);
+static void bitb_rg_de(void);
+static void bitb_rg_ded(void);
+static void bitb_rg_ix(void);
+static void bitb_rg_ixd(void);
+static void bitb_rgd_rg(void);
+static void bitb_rgd_rgd(void);
+static void bitb_rgd_in(void);
+static void bitb_rgd_ind(void);
+static void bitb_rgd_de(void);
+static void bitb_rgd_ded(void);
+static void bitb_rgd_ix(void);
+static void bitb_rgd_ixd(void);
+static void bitb_in_rg(void);
+static void bitb_in_rgd(void);
+static void bitb_in_in(void);
+static void bitb_in_ind(void);
+static void bitb_in_de(void);
+static void bitb_in_ded(void);
+static void bitb_in_ix(void);
+static void bitb_in_ixd(void);
+static void bitb_ind_rg(void);
+static void bitb_ind_rgd(void);
+static void bitb_ind_in(void);
+static void bitb_ind_ind(void);
+static void bitb_ind_de(void);
+static void bitb_ind_ded(void);
+static void bitb_ind_ix(void);
+static void bitb_ind_ixd(void);
+static void bitb_de_rg(void);
+static void bitb_de_rgd(void);
+static void bitb_de_in(void);
+static void bitb_de_ind(void);
+static void bitb_de_de(void);
+static void bitb_de_ded(void);
+static void bitb_de_ix(void);
+static void bitb_de_ixd(void);
+static void bitb_ded_rg(void);
+static void bitb_ded_rgd(void);
+static void bitb_ded_in(void);
+static void bitb_ded_ind(void);
+static void bitb_ded_de(void);
+static void bitb_ded_ded(void);
+static void bitb_ded_ix(void);
+static void bitb_ded_ixd(void);
+static void bitb_ix_rg(void);
+static void bitb_ix_rgd(void);
+static void bitb_ix_in(void);
+static void bitb_ix_ind(void);
+static void bitb_ix_de(void);
+static void bitb_ix_ded(void);
+static void bitb_ix_ix(void);
+static void bitb_ix_ixd(void);
+static void bitb_ixd_rg(void);
+static void bitb_ixd_rgd(void);
+static void bitb_ixd_in(void);
+static void bitb_ixd_ind(void);
+static void bitb_ixd_de(void);
+static void bitb_ixd_ded(void);
+static void bitb_ixd_ix(void);
+static void bitb_ixd_ixd(void);
+
+static void bicb_rg_rg(void);
+static void bicb_rg_rgd(void);
+static void bicb_rg_in(void);
+static void bicb_rg_ind(void);
+static void bicb_rg_de(void);
+static void bicb_rg_ded(void);
+static void bicb_rg_ix(void);
+static void bicb_rg_ixd(void);
+static void bicb_rgd_rg(void);
+static void bicb_rgd_rgd(void);
+static void bicb_rgd_in(void);
+static void bicb_rgd_ind(void);
+static void bicb_rgd_de(void);
+static void bicb_rgd_ded(void);
+static void bicb_rgd_ix(void);
+static void bicb_rgd_ixd(void);
+static void bicb_in_rg(void);
+static void bicb_in_rgd(void);
+static void bicb_in_in(void);
+static void bicb_in_ind(void);
+static void bicb_in_de(void);
+static void bicb_in_ded(void);
+static void bicb_in_ix(void);
+static void bicb_in_ixd(void);
+static void bicb_ind_rg(void);
+static void bicb_ind_rgd(void);
+static void bicb_ind_in(void);
+static void bicb_ind_ind(void);
+static void bicb_ind_de(void);
+static void bicb_ind_ded(void);
+static void bicb_ind_ix(void);
+static void bicb_ind_ixd(void);
+static void bicb_de_rg(void);
+static void bicb_de_rgd(void);
+static void bicb_de_in(void);
+static void bicb_de_ind(void);
+static void bicb_de_de(void);
+static void bicb_de_ded(void);
+static void bicb_de_ix(void);
+static void bicb_de_ixd(void);
+static void bicb_ded_rg(void);
+static void bicb_ded_rgd(void);
+static void bicb_ded_in(void);
+static void bicb_ded_ind(void);
+static void bicb_ded_de(void);
+static void bicb_ded_ded(void);
+static void bicb_ded_ix(void);
+static void bicb_ded_ixd(void);
+static void bicb_ix_rg(void);
+static void bicb_ix_rgd(void);
+static void bicb_ix_in(void);
+static void bicb_ix_ind(void);
+static void bicb_ix_de(void);
+static void bicb_ix_ded(void);
+static void bicb_ix_ix(void);
+static void bicb_ix_ixd(void);
+static void bicb_ixd_rg(void);
+static void bicb_ixd_rgd(void);
+static void bicb_ixd_in(void);
+static void bicb_ixd_ind(void);
+static void bicb_ixd_de(void);
+static void bicb_ixd_ded(void);
+static void bicb_ixd_ix(void);
+static void bicb_ixd_ixd(void);
+
+static void bisb_rg_rg(void);
+static void bisb_rg_rgd(void);
+static void bisb_rg_in(void);
+static void bisb_rg_ind(void);
+static void bisb_rg_de(void);
+static void bisb_rg_ded(void);
+static void bisb_rg_ix(void);
+static void bisb_rg_ixd(void);
+static void bisb_rgd_rg(void);
+static void bisb_rgd_rgd(void);
+static void bisb_rgd_in(void);
+static void bisb_rgd_ind(void);
+static void bisb_rgd_de(void);
+static void bisb_rgd_ded(void);
+static void bisb_rgd_ix(void);
+static void bisb_rgd_ixd(void);
+static void bisb_in_rg(void);
+static void bisb_in_rgd(void);
+static void bisb_in_in(void);
+static void bisb_in_ind(void);
+static void bisb_in_de(void);
+static void bisb_in_ded(void);
+static void bisb_in_ix(void);
+static void bisb_in_ixd(void);
+static void bisb_ind_rg(void);
+static void bisb_ind_rgd(void);
+static void bisb_ind_in(void);
+static void bisb_ind_ind(void);
+static void bisb_ind_de(void);
+static void bisb_ind_ded(void);
+static void bisb_ind_ix(void);
+static void bisb_ind_ixd(void);
+static void bisb_de_rg(void);
+static void bisb_de_rgd(void);
+static void bisb_de_in(void);
+static void bisb_de_ind(void);
+static void bisb_de_de(void);
+static void bisb_de_ded(void);
+static void bisb_de_ix(void);
+static void bisb_de_ixd(void);
+static void bisb_ded_rg(void);
+static void bisb_ded_rgd(void);
+static void bisb_ded_in(void);
+static void bisb_ded_ind(void);
+static void bisb_ded_de(void);
+static void bisb_ded_ded(void);
+static void bisb_ded_ix(void);
+static void bisb_ded_ixd(void);
+static void bisb_ix_rg(void);
+static void bisb_ix_rgd(void);
+static void bisb_ix_in(void);
+static void bisb_ix_ind(void);
+static void bisb_ix_de(void);
+static void bisb_ix_ded(void);
+static void bisb_ix_ix(void);
+static void bisb_ix_ixd(void);
+static void bisb_ixd_rg(void);
+static void bisb_ixd_rgd(void);
+static void bisb_ixd_in(void);
+static void bisb_ixd_ind(void);
+static void bisb_ixd_de(void);
+static void bisb_ixd_ded(void);
+static void bisb_ixd_ix(void);
+static void bisb_ixd_ixd(void);
+
+static void sub_rg_rg(void);
+static void sub_rg_rgd(void);
+static void sub_rg_in(void);
+static void sub_rg_ind(void);
+static void sub_rg_de(void);
+static void sub_rg_ded(void);
+static void sub_rg_ix(void);
+static void sub_rg_ixd(void);
+static void sub_rgd_rg(void);
+static void sub_rgd_rgd(void);
+static void sub_rgd_in(void);
+static void sub_rgd_ind(void);
+static void sub_rgd_de(void);
+static void sub_rgd_ded(void);
+static void sub_rgd_ix(void);
+static void sub_rgd_ixd(void);
+static void sub_in_rg(void);
+static void sub_in_rgd(void);
+static void sub_in_in(void);
+static void sub_in_ind(void);
+static void sub_in_de(void);
+static void sub_in_ded(void);
+static void sub_in_ix(void);
+static void sub_in_ixd(void);
+static void sub_ind_rg(void);
+static void sub_ind_rgd(void);
+static void sub_ind_in(void);
+static void sub_ind_ind(void);
+static void sub_ind_de(void);
+static void sub_ind_ded(void);
+static void sub_ind_ix(void);
+static void sub_ind_ixd(void);
+static void sub_de_rg(void);
+static void sub_de_rgd(void);
+static void sub_de_in(void);
+static void sub_de_ind(void);
+static void sub_de_de(void);
+static void sub_de_ded(void);
+static void sub_de_ix(void);
+static void sub_de_ixd(void);
+static void sub_ded_rg(void);
+static void sub_ded_rgd(void);
+static void sub_ded_in(void);
+static void sub_ded_ind(void);
+static void sub_ded_de(void);
+static void sub_ded_ded(void);
+static void sub_ded_ix(void);
+static void sub_ded_ixd(void);
+static void sub_ix_rg(void);
+static void sub_ix_rgd(void);
+static void sub_ix_in(void);
+static void sub_ix_ind(void);
+static void sub_ix_de(void);
+static void sub_ix_ded(void);
+static void sub_ix_ix(void);
+static void sub_ix_ixd(void);
+static void sub_ixd_rg(void);
+static void sub_ixd_rgd(void);
+static void sub_ixd_in(void);
+static void sub_ixd_ind(void);
+static void sub_ixd_de(void);
+static void sub_ixd_ded(void);
+static void sub_ixd_ix(void);
+static void sub_ixd_ixd(void);
+
+
+
+static void (*opcode_table[65536 >> 3])(void) =
+{
+ /* 0x0000 */
+ op_0000, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, jmp_rgd, jmp_in, jmp_ind, jmp_de, jmp_ded, jmp_ix, jmp_ixd,
+ rts, illegal, illegal, illegal, ccc, ccc, scc, scc,
+ swab_rg, swab_rgd, swab_in, swab_ind, swab_de, swab_ded, swab_ix, swab_ixd,
+ /* 0x0100 */
+ br, br, br, br, br, br, br, br,
+ br, br, br, br, br, br, br, br,
+ br, br, br, br, br, br, br, br,
+ br, br, br, br, br, br, br, br,
+ /* 0x0200 */
+ bne, bne, bne, bne, bne, bne, bne, bne,
+ bne, bne, bne, bne, bne, bne, bne, bne,
+ bne, bne, bne, bne, bne, bne, bne, bne,
+ bne, bne, bne, bne, bne, bne, bne, bne,
+ /* 0x0300 */
+ beq, beq, beq, beq, beq, beq, beq, beq,
+ beq, beq, beq, beq, beq, beq, beq, beq,
+ beq, beq, beq, beq, beq, beq, beq, beq,
+ beq, beq, beq, beq, beq, beq, beq, beq,
+ /* 0x0400 */
+ bge, bge, bge, bge, bge, bge, bge, bge,
+ bge, bge, bge, bge, bge, bge, bge, bge,
+ bge, bge, bge, bge, bge, bge, bge, bge,
+ bge, bge, bge, bge, bge, bge, bge, bge,
+ /* 0x0500 */
+ blt, blt, blt, blt, blt, blt, blt, blt,
+ blt, blt, blt, blt, blt, blt, blt, blt,
+ blt, blt, blt, blt, blt, blt, blt, blt,
+ blt, blt, blt, blt, blt, blt, blt, blt,
+ /* 0x0600 */
+ bgt, bgt, bgt, bgt, bgt, bgt, bgt, bgt,
+ bgt, bgt, bgt, bgt, bgt, bgt, bgt, bgt,
+ bgt, bgt, bgt, bgt, bgt, bgt, bgt, bgt,
+ bgt, bgt, bgt, bgt, bgt, bgt, bgt, bgt,
+ /* 0x0700 */
+ ble, ble, ble, ble, ble, ble, ble, ble,
+ ble, ble, ble, ble, ble, ble, ble, ble,
+ ble, ble, ble, ble, ble, ble, ble, ble,
+ ble, ble, ble, ble, ble, ble, ble, ble,
+ /* 0x0800 */
+ illegal, jsr_rgd, jsr_in, jsr_ind, jsr_de, jsr_ded, jsr_ix, jsr_ixd,
+ illegal, jsr_rgd, jsr_in, jsr_ind, jsr_de, jsr_ded, jsr_ix, jsr_ixd,
+ illegal, jsr_rgd, jsr_in, jsr_ind, jsr_de, jsr_ded, jsr_ix, jsr_ixd,
+ illegal, jsr_rgd, jsr_in, jsr_ind, jsr_de, jsr_ded, jsr_ix, jsr_ixd,
+ /* 0x0900 */
+ illegal, jsr_rgd, jsr_in, jsr_ind, jsr_de, jsr_ded, jsr_ix, jsr_ixd,
+ illegal, jsr_rgd, jsr_in, jsr_ind, jsr_de, jsr_ded, jsr_ix, jsr_ixd,
+ illegal, jsr_rgd, jsr_in, jsr_ind, jsr_de, jsr_ded, jsr_ix, jsr_ixd,
+ illegal, jsr_rgd, jsr_in, jsr_ind, jsr_de, jsr_ded, jsr_ix, jsr_ixd,
+ /* 0x0a00 */
+ clr_rg, clr_rgd, clr_in, clr_ind, clr_de, clr_ded, clr_ix, clr_ixd,
+ com_rg, com_rgd, com_in, com_ind, com_de, com_ded, com_ix, com_ixd,
+ inc_rg, inc_rgd, inc_in, inc_ind, inc_de, inc_ded, inc_ix, inc_ixd,
+ dec_rg, dec_rgd, dec_in, dec_ind, dec_de, dec_ded, dec_ix, dec_ixd,
+ /* 0x0b00 */
+ neg_rg, neg_rgd, neg_in, neg_ind, neg_de, neg_ded, neg_ix, neg_ixd,
+ adc_rg, adc_rgd, adc_in, adc_ind, adc_de, adc_ded, adc_ix, adc_ixd,
+ sbc_rg, sbc_rgd, sbc_in, sbc_ind, sbc_de, sbc_ded, sbc_ix, sbc_ixd,
+ tst_rg, tst_rgd, tst_in, tst_ind, tst_de, tst_ded, tst_ix, tst_ixd,
+ /* 0x0c00 */
+ ror_rg, ror_rgd, ror_in, ror_ind, ror_de, ror_ded, ror_ix, ror_ixd,
+ rol_rg, rol_rgd, rol_in, rol_ind, rol_de, rol_ded, rol_ix, rol_ixd,
+ asr_rg, asr_rgd, asr_in, asr_ind, asr_de, asr_ded, asr_ix, asr_ixd,
+ asl_rg, asl_rgd, asl_in, asl_ind, asl_de, asl_ded, asl_ix, asl_ixd,
+ /* 0x0d00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ sxt_rg, sxt_rgd, sxt_in, sxt_ind, sxt_de, sxt_ded, sxt_ix, sxt_ixd,
+ /* 0x0e00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x0f00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+
+ /* 0x1000 */
+ mov_rg_rg, mov_rg_rgd, mov_rg_in, mov_rg_ind, mov_rg_de, mov_rg_ded, mov_rg_ix, mov_rg_ixd,
+ mov_rg_rg, mov_rg_rgd, mov_rg_in, mov_rg_ind, mov_rg_de, mov_rg_ded, mov_rg_ix, mov_rg_ixd,
+ mov_rg_rg, mov_rg_rgd, mov_rg_in, mov_rg_ind, mov_rg_de, mov_rg_ded, mov_rg_ix, mov_rg_ixd,
+ mov_rg_rg, mov_rg_rgd, mov_rg_in, mov_rg_ind, mov_rg_de, mov_rg_ded, mov_rg_ix, mov_rg_ixd,
+ /* 0x1100 */
+ mov_rg_rg, mov_rg_rgd, mov_rg_in, mov_rg_ind, mov_rg_de, mov_rg_ded, mov_rg_ix, mov_rg_ixd,
+ mov_rg_rg, mov_rg_rgd, mov_rg_in, mov_rg_ind, mov_rg_de, mov_rg_ded, mov_rg_ix, mov_rg_ixd,
+ mov_rg_rg, mov_rg_rgd, mov_rg_in, mov_rg_ind, mov_rg_de, mov_rg_ded, mov_rg_ix, mov_rg_ixd,
+ mov_rg_rg, mov_rg_rgd, mov_rg_in, mov_rg_ind, mov_rg_de, mov_rg_ded, mov_rg_ix, mov_rg_ixd,
+ /* 0x1200 */
+ mov_rgd_rg, mov_rgd_rgd,mov_rgd_in, mov_rgd_ind,mov_rgd_de, mov_rgd_ded,mov_rgd_ix, mov_rgd_ixd,
+ mov_rgd_rg, mov_rgd_rgd,mov_rgd_in, mov_rgd_ind,mov_rgd_de, mov_rgd_ded,mov_rgd_ix, mov_rgd_ixd,
+ mov_rgd_rg, mov_rgd_rgd,mov_rgd_in, mov_rgd_ind,mov_rgd_de, mov_rgd_ded,mov_rgd_ix, mov_rgd_ixd,
+ mov_rgd_rg, mov_rgd_rgd,mov_rgd_in, mov_rgd_ind,mov_rgd_de, mov_rgd_ded,mov_rgd_ix, mov_rgd_ixd,
+ /* 0x1300 */
+ mov_rgd_rg, mov_rgd_rgd,mov_rgd_in, mov_rgd_ind,mov_rgd_de, mov_rgd_ded,mov_rgd_ix, mov_rgd_ixd,
+ mov_rgd_rg, mov_rgd_rgd,mov_rgd_in, mov_rgd_ind,mov_rgd_de, mov_rgd_ded,mov_rgd_ix, mov_rgd_ixd,
+ mov_rgd_rg, mov_rgd_rgd,mov_rgd_in, mov_rgd_ind,mov_rgd_de, mov_rgd_ded,mov_rgd_ix, mov_rgd_ixd,
+ mov_rgd_rg, mov_rgd_rgd,mov_rgd_in, mov_rgd_ind,mov_rgd_de, mov_rgd_ded,mov_rgd_ix, mov_rgd_ixd,
+ /* 0x1400 */
+ mov_in_rg, mov_in_rgd, mov_in_in, mov_in_ind, mov_in_de, mov_in_ded, mov_in_ix, mov_in_ixd,
+ mov_in_rg, mov_in_rgd, mov_in_in, mov_in_ind, mov_in_de, mov_in_ded, mov_in_ix, mov_in_ixd,
+ mov_in_rg, mov_in_rgd, mov_in_in, mov_in_ind, mov_in_de, mov_in_ded, mov_in_ix, mov_in_ixd,
+ mov_in_rg, mov_in_rgd, mov_in_in, mov_in_ind, mov_in_de, mov_in_ded, mov_in_ix, mov_in_ixd,
+ /* 0x1500 */
+ mov_in_rg, mov_in_rgd, mov_in_in, mov_in_ind, mov_in_de, mov_in_ded, mov_in_ix, mov_in_ixd,
+ mov_in_rg, mov_in_rgd, mov_in_in, mov_in_ind, mov_in_de, mov_in_ded, mov_in_ix, mov_in_ixd,
+ mov_in_rg, mov_in_rgd, mov_in_in, mov_in_ind, mov_in_de, mov_in_ded, mov_in_ix, mov_in_ixd,
+ mov_in_rg, mov_in_rgd, mov_in_in, mov_in_ind, mov_in_de, mov_in_ded, mov_in_ix, mov_in_ixd,
+ /* 0x1600 */
+ mov_ind_rg, mov_ind_rgd,mov_ind_in, mov_ind_ind,mov_ind_de, mov_ind_ded,mov_ind_ix, mov_ind_ixd,
+ mov_ind_rg, mov_ind_rgd,mov_ind_in, mov_ind_ind,mov_ind_de, mov_ind_ded,mov_ind_ix, mov_ind_ixd,
+ mov_ind_rg, mov_ind_rgd,mov_ind_in, mov_ind_ind,mov_ind_de, mov_ind_ded,mov_ind_ix, mov_ind_ixd,
+ mov_ind_rg, mov_ind_rgd,mov_ind_in, mov_ind_ind,mov_ind_de, mov_ind_ded,mov_ind_ix, mov_ind_ixd,
+ /* 0x1700 */
+ mov_ind_rg, mov_ind_rgd,mov_ind_in, mov_ind_ind,mov_ind_de, mov_ind_ded,mov_ind_ix, mov_ind_ixd,
+ mov_ind_rg, mov_ind_rgd,mov_ind_in, mov_ind_ind,mov_ind_de, mov_ind_ded,mov_ind_ix, mov_ind_ixd,
+ mov_ind_rg, mov_ind_rgd,mov_ind_in, mov_ind_ind,mov_ind_de, mov_ind_ded,mov_ind_ix, mov_ind_ixd,
+ mov_ind_rg, mov_ind_rgd,mov_ind_in, mov_ind_ind,mov_ind_de, mov_ind_ded,mov_ind_ix, mov_ind_ixd,
+ /* 0x1800 */
+ mov_de_rg, mov_de_rgd, mov_de_in, mov_de_ind, mov_de_de, mov_de_ded, mov_de_ix, mov_de_ixd,
+ mov_de_rg, mov_de_rgd, mov_de_in, mov_de_ind, mov_de_de, mov_de_ded, mov_de_ix, mov_de_ixd,
+ mov_de_rg, mov_de_rgd, mov_de_in, mov_de_ind, mov_de_de, mov_de_ded, mov_de_ix, mov_de_ixd,
+ mov_de_rg, mov_de_rgd, mov_de_in, mov_de_ind, mov_de_de, mov_de_ded, mov_de_ix, mov_de_ixd,
+ /* 0x1900 */
+ mov_de_rg, mov_de_rgd, mov_de_in, mov_de_ind, mov_de_de, mov_de_ded, mov_de_ix, mov_de_ixd,
+ mov_de_rg, mov_de_rgd, mov_de_in, mov_de_ind, mov_de_de, mov_de_ded, mov_de_ix, mov_de_ixd,
+ mov_de_rg, mov_de_rgd, mov_de_in, mov_de_ind, mov_de_de, mov_de_ded, mov_de_ix, mov_de_ixd,
+ mov_de_rg, mov_de_rgd, mov_de_in, mov_de_ind, mov_de_de, mov_de_ded, mov_de_ix, mov_de_ixd,
+ /* 0x1a00 */
+ mov_ded_rg, mov_ded_rgd,mov_ded_in, mov_ded_ind,mov_ded_de, mov_ded_ded,mov_ded_ix, mov_ded_ixd,
+ mov_ded_rg, mov_ded_rgd,mov_ded_in, mov_ded_ind,mov_ded_de, mov_ded_ded,mov_ded_ix, mov_ded_ixd,
+ mov_ded_rg, mov_ded_rgd,mov_ded_in, mov_ded_ind,mov_ded_de, mov_ded_ded,mov_ded_ix, mov_ded_ixd,
+ mov_ded_rg, mov_ded_rgd,mov_ded_in, mov_ded_ind,mov_ded_de, mov_ded_ded,mov_ded_ix, mov_ded_ixd,
+ /* 0x1b00 */
+ mov_ded_rg, mov_ded_rgd,mov_ded_in, mov_ded_ind,mov_ded_de, mov_ded_ded,mov_ded_ix, mov_ded_ixd,
+ mov_ded_rg, mov_ded_rgd,mov_ded_in, mov_ded_ind,mov_ded_de, mov_ded_ded,mov_ded_ix, mov_ded_ixd,
+ mov_ded_rg, mov_ded_rgd,mov_ded_in, mov_ded_ind,mov_ded_de, mov_ded_ded,mov_ded_ix, mov_ded_ixd,
+ mov_ded_rg, mov_ded_rgd,mov_ded_in, mov_ded_ind,mov_ded_de, mov_ded_ded,mov_ded_ix, mov_ded_ixd,
+ /* 0x1c00 */
+ mov_ix_rg, mov_ix_rgd, mov_ix_in, mov_ix_ind, mov_ix_de, mov_ix_ded, mov_ix_ix, mov_ix_ixd,
+ mov_ix_rg, mov_ix_rgd, mov_ix_in, mov_ix_ind, mov_ix_de, mov_ix_ded, mov_ix_ix, mov_ix_ixd,
+ mov_ix_rg, mov_ix_rgd, mov_ix_in, mov_ix_ind, mov_ix_de, mov_ix_ded, mov_ix_ix, mov_ix_ixd,
+ mov_ix_rg, mov_ix_rgd, mov_ix_in, mov_ix_ind, mov_ix_de, mov_ix_ded, mov_ix_ix, mov_ix_ixd,
+ /* 0x1d00 */
+ mov_ix_rg, mov_ix_rgd, mov_ix_in, mov_ix_ind, mov_ix_de, mov_ix_ded, mov_ix_ix, mov_ix_ixd,
+ mov_ix_rg, mov_ix_rgd, mov_ix_in, mov_ix_ind, mov_ix_de, mov_ix_ded, mov_ix_ix, mov_ix_ixd,
+ mov_ix_rg, mov_ix_rgd, mov_ix_in, mov_ix_ind, mov_ix_de, mov_ix_ded, mov_ix_ix, mov_ix_ixd,
+ mov_ix_rg, mov_ix_rgd, mov_ix_in, mov_ix_ind, mov_ix_de, mov_ix_ded, mov_ix_ix, mov_ix_ixd,
+ /* 0x1e00 */
+ mov_ixd_rg, mov_ixd_rgd,mov_ixd_in, mov_ixd_ind,mov_ixd_de, mov_ixd_ded,mov_ixd_ix, mov_ixd_ixd,
+ mov_ixd_rg, mov_ixd_rgd,mov_ixd_in, mov_ixd_ind,mov_ixd_de, mov_ixd_ded,mov_ixd_ix, mov_ixd_ixd,
+ mov_ixd_rg, mov_ixd_rgd,mov_ixd_in, mov_ixd_ind,mov_ixd_de, mov_ixd_ded,mov_ixd_ix, mov_ixd_ixd,
+ mov_ixd_rg, mov_ixd_rgd,mov_ixd_in, mov_ixd_ind,mov_ixd_de, mov_ixd_ded,mov_ixd_ix, mov_ixd_ixd,
+ /* 0x1f00 */
+ mov_ixd_rg, mov_ixd_rgd,mov_ixd_in, mov_ixd_ind,mov_ixd_de, mov_ixd_ded,mov_ixd_ix, mov_ixd_ixd,
+ mov_ixd_rg, mov_ixd_rgd,mov_ixd_in, mov_ixd_ind,mov_ixd_de, mov_ixd_ded,mov_ixd_ix, mov_ixd_ixd,
+ mov_ixd_rg, mov_ixd_rgd,mov_ixd_in, mov_ixd_ind,mov_ixd_de, mov_ixd_ded,mov_ixd_ix, mov_ixd_ixd,
+ mov_ixd_rg, mov_ixd_rgd,mov_ixd_in, mov_ixd_ind,mov_ixd_de, mov_ixd_ded,mov_ixd_ix, mov_ixd_ixd,
+
+ /* 0x2000 */
+ cmp_rg_rg, cmp_rg_rgd, cmp_rg_in, cmp_rg_ind, cmp_rg_de, cmp_rg_ded, cmp_rg_ix, cmp_rg_ixd,
+ cmp_rg_rg, cmp_rg_rgd, cmp_rg_in, cmp_rg_ind, cmp_rg_de, cmp_rg_ded, cmp_rg_ix, cmp_rg_ixd,
+ cmp_rg_rg, cmp_rg_rgd, cmp_rg_in, cmp_rg_ind, cmp_rg_de, cmp_rg_ded, cmp_rg_ix, cmp_rg_ixd,
+ cmp_rg_rg, cmp_rg_rgd, cmp_rg_in, cmp_rg_ind, cmp_rg_de, cmp_rg_ded, cmp_rg_ix, cmp_rg_ixd,
+ /* 0x2100 */
+ cmp_rg_rg, cmp_rg_rgd, cmp_rg_in, cmp_rg_ind, cmp_rg_de, cmp_rg_ded, cmp_rg_ix, cmp_rg_ixd,
+ cmp_rg_rg, cmp_rg_rgd, cmp_rg_in, cmp_rg_ind, cmp_rg_de, cmp_rg_ded, cmp_rg_ix, cmp_rg_ixd,
+ cmp_rg_rg, cmp_rg_rgd, cmp_rg_in, cmp_rg_ind, cmp_rg_de, cmp_rg_ded, cmp_rg_ix, cmp_rg_ixd,
+ cmp_rg_rg, cmp_rg_rgd, cmp_rg_in, cmp_rg_ind, cmp_rg_de, cmp_rg_ded, cmp_rg_ix, cmp_rg_ixd,
+ /* 0x2200 */
+ cmp_rgd_rg, cmp_rgd_rgd,cmp_rgd_in, cmp_rgd_ind,cmp_rgd_de, cmp_rgd_ded,cmp_rgd_ix, cmp_rgd_ixd,
+ cmp_rgd_rg, cmp_rgd_rgd,cmp_rgd_in, cmp_rgd_ind,cmp_rgd_de, cmp_rgd_ded,cmp_rgd_ix, cmp_rgd_ixd,
+ cmp_rgd_rg, cmp_rgd_rgd,cmp_rgd_in, cmp_rgd_ind,cmp_rgd_de, cmp_rgd_ded,cmp_rgd_ix, cmp_rgd_ixd,
+ cmp_rgd_rg, cmp_rgd_rgd,cmp_rgd_in, cmp_rgd_ind,cmp_rgd_de, cmp_rgd_ded,cmp_rgd_ix, cmp_rgd_ixd,
+ /* 0x2300 */
+ cmp_rgd_rg, cmp_rgd_rgd,cmp_rgd_in, cmp_rgd_ind,cmp_rgd_de, cmp_rgd_ded,cmp_rgd_ix, cmp_rgd_ixd,
+ cmp_rgd_rg, cmp_rgd_rgd,cmp_rgd_in, cmp_rgd_ind,cmp_rgd_de, cmp_rgd_ded,cmp_rgd_ix, cmp_rgd_ixd,
+ cmp_rgd_rg, cmp_rgd_rgd,cmp_rgd_in, cmp_rgd_ind,cmp_rgd_de, cmp_rgd_ded,cmp_rgd_ix, cmp_rgd_ixd,
+ cmp_rgd_rg, cmp_rgd_rgd,cmp_rgd_in, cmp_rgd_ind,cmp_rgd_de, cmp_rgd_ded,cmp_rgd_ix, cmp_rgd_ixd,
+ /* 0x2400 */
+ cmp_in_rg, cmp_in_rgd, cmp_in_in, cmp_in_ind, cmp_in_de, cmp_in_ded, cmp_in_ix, cmp_in_ixd,
+ cmp_in_rg, cmp_in_rgd, cmp_in_in, cmp_in_ind, cmp_in_de, cmp_in_ded, cmp_in_ix, cmp_in_ixd,
+ cmp_in_rg, cmp_in_rgd, cmp_in_in, cmp_in_ind, cmp_in_de, cmp_in_ded, cmp_in_ix, cmp_in_ixd,
+ cmp_in_rg, cmp_in_rgd, cmp_in_in, cmp_in_ind, cmp_in_de, cmp_in_ded, cmp_in_ix, cmp_in_ixd,
+ /* 0x2500 */
+ cmp_in_rg, cmp_in_rgd, cmp_in_in, cmp_in_ind, cmp_in_de, cmp_in_ded, cmp_in_ix, cmp_in_ixd,
+ cmp_in_rg, cmp_in_rgd, cmp_in_in, cmp_in_ind, cmp_in_de, cmp_in_ded, cmp_in_ix, cmp_in_ixd,
+ cmp_in_rg, cmp_in_rgd, cmp_in_in, cmp_in_ind, cmp_in_de, cmp_in_ded, cmp_in_ix, cmp_in_ixd,
+ cmp_in_rg, cmp_in_rgd, cmp_in_in, cmp_in_ind, cmp_in_de, cmp_in_ded, cmp_in_ix, cmp_in_ixd,
+ /* 0x2600 */
+ cmp_ind_rg, cmp_ind_rgd,cmp_ind_in, cmp_ind_ind,cmp_ind_de, cmp_ind_ded,cmp_ind_ix, cmp_ind_ixd,
+ cmp_ind_rg, cmp_ind_rgd,cmp_ind_in, cmp_ind_ind,cmp_ind_de, cmp_ind_ded,cmp_ind_ix, cmp_ind_ixd,
+ cmp_ind_rg, cmp_ind_rgd,cmp_ind_in, cmp_ind_ind,cmp_ind_de, cmp_ind_ded,cmp_ind_ix, cmp_ind_ixd,
+ cmp_ind_rg, cmp_ind_rgd,cmp_ind_in, cmp_ind_ind,cmp_ind_de, cmp_ind_ded,cmp_ind_ix, cmp_ind_ixd,
+ /* 0x2700 */
+ cmp_ind_rg, cmp_ind_rgd,cmp_ind_in, cmp_ind_ind,cmp_ind_de, cmp_ind_ded,cmp_ind_ix, cmp_ind_ixd,
+ cmp_ind_rg, cmp_ind_rgd,cmp_ind_in, cmp_ind_ind,cmp_ind_de, cmp_ind_ded,cmp_ind_ix, cmp_ind_ixd,
+ cmp_ind_rg, cmp_ind_rgd,cmp_ind_in, cmp_ind_ind,cmp_ind_de, cmp_ind_ded,cmp_ind_ix, cmp_ind_ixd,
+ cmp_ind_rg, cmp_ind_rgd,cmp_ind_in, cmp_ind_ind,cmp_ind_de, cmp_ind_ded,cmp_ind_ix, cmp_ind_ixd,
+ /* 0x2800 */
+ cmp_de_rg, cmp_de_rgd, cmp_de_in, cmp_de_ind, cmp_de_de, cmp_de_ded, cmp_de_ix, cmp_de_ixd,
+ cmp_de_rg, cmp_de_rgd, cmp_de_in, cmp_de_ind, cmp_de_de, cmp_de_ded, cmp_de_ix, cmp_de_ixd,
+ cmp_de_rg, cmp_de_rgd, cmp_de_in, cmp_de_ind, cmp_de_de, cmp_de_ded, cmp_de_ix, cmp_de_ixd,
+ cmp_de_rg, cmp_de_rgd, cmp_de_in, cmp_de_ind, cmp_de_de, cmp_de_ded, cmp_de_ix, cmp_de_ixd,
+ /* 0x2900 */
+ cmp_de_rg, cmp_de_rgd, cmp_de_in, cmp_de_ind, cmp_de_de, cmp_de_ded, cmp_de_ix, cmp_de_ixd,
+ cmp_de_rg, cmp_de_rgd, cmp_de_in, cmp_de_ind, cmp_de_de, cmp_de_ded, cmp_de_ix, cmp_de_ixd,
+ cmp_de_rg, cmp_de_rgd, cmp_de_in, cmp_de_ind, cmp_de_de, cmp_de_ded, cmp_de_ix, cmp_de_ixd,
+ cmp_de_rg, cmp_de_rgd, cmp_de_in, cmp_de_ind, cmp_de_de, cmp_de_ded, cmp_de_ix, cmp_de_ixd,
+ /* 0x2a00 */
+ cmp_ded_rg, cmp_ded_rgd,cmp_ded_in, cmp_ded_ind,cmp_ded_de, cmp_ded_ded,cmp_ded_ix, cmp_ded_ixd,
+ cmp_ded_rg, cmp_ded_rgd,cmp_ded_in, cmp_ded_ind,cmp_ded_de, cmp_ded_ded,cmp_ded_ix, cmp_ded_ixd,
+ cmp_ded_rg, cmp_ded_rgd,cmp_ded_in, cmp_ded_ind,cmp_ded_de, cmp_ded_ded,cmp_ded_ix, cmp_ded_ixd,
+ cmp_ded_rg, cmp_ded_rgd,cmp_ded_in, cmp_ded_ind,cmp_ded_de, cmp_ded_ded,cmp_ded_ix, cmp_ded_ixd,
+ /* 0x2b00 */
+ cmp_ded_rg, cmp_ded_rgd,cmp_ded_in, cmp_ded_ind,cmp_ded_de, cmp_ded_ded,cmp_ded_ix, cmp_ded_ixd,
+ cmp_ded_rg, cmp_ded_rgd,cmp_ded_in, cmp_ded_ind,cmp_ded_de, cmp_ded_ded,cmp_ded_ix, cmp_ded_ixd,
+ cmp_ded_rg, cmp_ded_rgd,cmp_ded_in, cmp_ded_ind,cmp_ded_de, cmp_ded_ded,cmp_ded_ix, cmp_ded_ixd,
+ cmp_ded_rg, cmp_ded_rgd,cmp_ded_in, cmp_ded_ind,cmp_ded_de, cmp_ded_ded,cmp_ded_ix, cmp_ded_ixd,
+ /* 0x2c00 */
+ cmp_ix_rg, cmp_ix_rgd, cmp_ix_in, cmp_ix_ind, cmp_ix_de, cmp_ix_ded, cmp_ix_ix, cmp_ix_ixd,
+ cmp_ix_rg, cmp_ix_rgd, cmp_ix_in, cmp_ix_ind, cmp_ix_de, cmp_ix_ded, cmp_ix_ix, cmp_ix_ixd,
+ cmp_ix_rg, cmp_ix_rgd, cmp_ix_in, cmp_ix_ind, cmp_ix_de, cmp_ix_ded, cmp_ix_ix, cmp_ix_ixd,
+ cmp_ix_rg, cmp_ix_rgd, cmp_ix_in, cmp_ix_ind, cmp_ix_de, cmp_ix_ded, cmp_ix_ix, cmp_ix_ixd,
+ /* 0x2d00 */
+ cmp_ix_rg, cmp_ix_rgd, cmp_ix_in, cmp_ix_ind, cmp_ix_de, cmp_ix_ded, cmp_ix_ix, cmp_ix_ixd,
+ cmp_ix_rg, cmp_ix_rgd, cmp_ix_in, cmp_ix_ind, cmp_ix_de, cmp_ix_ded, cmp_ix_ix, cmp_ix_ixd,
+ cmp_ix_rg, cmp_ix_rgd, cmp_ix_in, cmp_ix_ind, cmp_ix_de, cmp_ix_ded, cmp_ix_ix, cmp_ix_ixd,
+ cmp_ix_rg, cmp_ix_rgd, cmp_ix_in, cmp_ix_ind, cmp_ix_de, cmp_ix_ded, cmp_ix_ix, cmp_ix_ixd,
+ /* 0x2e00 */
+ cmp_ixd_rg, cmp_ixd_rgd,cmp_ixd_in, cmp_ixd_ind,cmp_ixd_de, cmp_ixd_ded,cmp_ixd_ix, cmp_ixd_ixd,
+ cmp_ixd_rg, cmp_ixd_rgd,cmp_ixd_in, cmp_ixd_ind,cmp_ixd_de, cmp_ixd_ded,cmp_ixd_ix, cmp_ixd_ixd,
+ cmp_ixd_rg, cmp_ixd_rgd,cmp_ixd_in, cmp_ixd_ind,cmp_ixd_de, cmp_ixd_ded,cmp_ixd_ix, cmp_ixd_ixd,
+ cmp_ixd_rg, cmp_ixd_rgd,cmp_ixd_in, cmp_ixd_ind,cmp_ixd_de, cmp_ixd_ded,cmp_ixd_ix, cmp_ixd_ixd,
+ /* 0x2f00 */
+ cmp_ixd_rg, cmp_ixd_rgd,cmp_ixd_in, cmp_ixd_ind,cmp_ixd_de, cmp_ixd_ded,cmp_ixd_ix, cmp_ixd_ixd,
+ cmp_ixd_rg, cmp_ixd_rgd,cmp_ixd_in, cmp_ixd_ind,cmp_ixd_de, cmp_ixd_ded,cmp_ixd_ix, cmp_ixd_ixd,
+ cmp_ixd_rg, cmp_ixd_rgd,cmp_ixd_in, cmp_ixd_ind,cmp_ixd_de, cmp_ixd_ded,cmp_ixd_ix, cmp_ixd_ixd,
+ cmp_ixd_rg, cmp_ixd_rgd,cmp_ixd_in, cmp_ixd_ind,cmp_ixd_de, cmp_ixd_ded,cmp_ixd_ix, cmp_ixd_ixd,
+
+ /* 0x3000 */
+ bit_rg_rg, bit_rg_rgd, bit_rg_in, bit_rg_ind, bit_rg_de, bit_rg_ded, bit_rg_ix, bit_rg_ixd,
+ bit_rg_rg, bit_rg_rgd, bit_rg_in, bit_rg_ind, bit_rg_de, bit_rg_ded, bit_rg_ix, bit_rg_ixd,
+ bit_rg_rg, bit_rg_rgd, bit_rg_in, bit_rg_ind, bit_rg_de, bit_rg_ded, bit_rg_ix, bit_rg_ixd,
+ bit_rg_rg, bit_rg_rgd, bit_rg_in, bit_rg_ind, bit_rg_de, bit_rg_ded, bit_rg_ix, bit_rg_ixd,
+ /* 0x3100 */
+ bit_rg_rg, bit_rg_rgd, bit_rg_in, bit_rg_ind, bit_rg_de, bit_rg_ded, bit_rg_ix, bit_rg_ixd,
+ bit_rg_rg, bit_rg_rgd, bit_rg_in, bit_rg_ind, bit_rg_de, bit_rg_ded, bit_rg_ix, bit_rg_ixd,
+ bit_rg_rg, bit_rg_rgd, bit_rg_in, bit_rg_ind, bit_rg_de, bit_rg_ded, bit_rg_ix, bit_rg_ixd,
+ bit_rg_rg, bit_rg_rgd, bit_rg_in, bit_rg_ind, bit_rg_de, bit_rg_ded, bit_rg_ix, bit_rg_ixd,
+ /* 0x3200 */
+ bit_rgd_rg, bit_rgd_rgd,bit_rgd_in, bit_rgd_ind,bit_rgd_de, bit_rgd_ded,bit_rgd_ix, bit_rgd_ixd,
+ bit_rgd_rg, bit_rgd_rgd,bit_rgd_in, bit_rgd_ind,bit_rgd_de, bit_rgd_ded,bit_rgd_ix, bit_rgd_ixd,
+ bit_rgd_rg, bit_rgd_rgd,bit_rgd_in, bit_rgd_ind,bit_rgd_de, bit_rgd_ded,bit_rgd_ix, bit_rgd_ixd,
+ bit_rgd_rg, bit_rgd_rgd,bit_rgd_in, bit_rgd_ind,bit_rgd_de, bit_rgd_ded,bit_rgd_ix, bit_rgd_ixd,
+ /* 0x3300 */
+ bit_rgd_rg, bit_rgd_rgd,bit_rgd_in, bit_rgd_ind,bit_rgd_de, bit_rgd_ded,bit_rgd_ix, bit_rgd_ixd,
+ bit_rgd_rg, bit_rgd_rgd,bit_rgd_in, bit_rgd_ind,bit_rgd_de, bit_rgd_ded,bit_rgd_ix, bit_rgd_ixd,
+ bit_rgd_rg, bit_rgd_rgd,bit_rgd_in, bit_rgd_ind,bit_rgd_de, bit_rgd_ded,bit_rgd_ix, bit_rgd_ixd,
+ bit_rgd_rg, bit_rgd_rgd,bit_rgd_in, bit_rgd_ind,bit_rgd_de, bit_rgd_ded,bit_rgd_ix, bit_rgd_ixd,
+ /* 0x3400 */
+ bit_in_rg, bit_in_rgd, bit_in_in, bit_in_ind, bit_in_de, bit_in_ded, bit_in_ix, bit_in_ixd,
+ bit_in_rg, bit_in_rgd, bit_in_in, bit_in_ind, bit_in_de, bit_in_ded, bit_in_ix, bit_in_ixd,
+ bit_in_rg, bit_in_rgd, bit_in_in, bit_in_ind, bit_in_de, bit_in_ded, bit_in_ix, bit_in_ixd,
+ bit_in_rg, bit_in_rgd, bit_in_in, bit_in_ind, bit_in_de, bit_in_ded, bit_in_ix, bit_in_ixd,
+ /* 0x3500 */
+ bit_in_rg, bit_in_rgd, bit_in_in, bit_in_ind, bit_in_de, bit_in_ded, bit_in_ix, bit_in_ixd,
+ bit_in_rg, bit_in_rgd, bit_in_in, bit_in_ind, bit_in_de, bit_in_ded, bit_in_ix, bit_in_ixd,
+ bit_in_rg, bit_in_rgd, bit_in_in, bit_in_ind, bit_in_de, bit_in_ded, bit_in_ix, bit_in_ixd,
+ bit_in_rg, bit_in_rgd, bit_in_in, bit_in_ind, bit_in_de, bit_in_ded, bit_in_ix, bit_in_ixd,
+ /* 0x3600 */
+ bit_ind_rg, bit_ind_rgd,bit_ind_in, bit_ind_ind,bit_ind_de, bit_ind_ded,bit_ind_ix, bit_ind_ixd,
+ bit_ind_rg, bit_ind_rgd,bit_ind_in, bit_ind_ind,bit_ind_de, bit_ind_ded,bit_ind_ix, bit_ind_ixd,
+ bit_ind_rg, bit_ind_rgd,bit_ind_in, bit_ind_ind,bit_ind_de, bit_ind_ded,bit_ind_ix, bit_ind_ixd,
+ bit_ind_rg, bit_ind_rgd,bit_ind_in, bit_ind_ind,bit_ind_de, bit_ind_ded,bit_ind_ix, bit_ind_ixd,
+ /* 0x3700 */
+ bit_ind_rg, bit_ind_rgd,bit_ind_in, bit_ind_ind,bit_ind_de, bit_ind_ded,bit_ind_ix, bit_ind_ixd,
+ bit_ind_rg, bit_ind_rgd,bit_ind_in, bit_ind_ind,bit_ind_de, bit_ind_ded,bit_ind_ix, bit_ind_ixd,
+ bit_ind_rg, bit_ind_rgd,bit_ind_in, bit_ind_ind,bit_ind_de, bit_ind_ded,bit_ind_ix, bit_ind_ixd,
+ bit_ind_rg, bit_ind_rgd,bit_ind_in, bit_ind_ind,bit_ind_de, bit_ind_ded,bit_ind_ix, bit_ind_ixd,
+ /* 0x3800 */
+ bit_de_rg, bit_de_rgd, bit_de_in, bit_de_ind, bit_de_de, bit_de_ded, bit_de_ix, bit_de_ixd,
+ bit_de_rg, bit_de_rgd, bit_de_in, bit_de_ind, bit_de_de, bit_de_ded, bit_de_ix, bit_de_ixd,
+ bit_de_rg, bit_de_rgd, bit_de_in, bit_de_ind, bit_de_de, bit_de_ded, bit_de_ix, bit_de_ixd,
+ bit_de_rg, bit_de_rgd, bit_de_in, bit_de_ind, bit_de_de, bit_de_ded, bit_de_ix, bit_de_ixd,
+ /* 0x3900 */
+ bit_de_rg, bit_de_rgd, bit_de_in, bit_de_ind, bit_de_de, bit_de_ded, bit_de_ix, bit_de_ixd,
+ bit_de_rg, bit_de_rgd, bit_de_in, bit_de_ind, bit_de_de, bit_de_ded, bit_de_ix, bit_de_ixd,
+ bit_de_rg, bit_de_rgd, bit_de_in, bit_de_ind, bit_de_de, bit_de_ded, bit_de_ix, bit_de_ixd,
+ bit_de_rg, bit_de_rgd, bit_de_in, bit_de_ind, bit_de_de, bit_de_ded, bit_de_ix, bit_de_ixd,
+ /* 0x3a00 */
+ bit_ded_rg, bit_ded_rgd,bit_ded_in, bit_ded_ind,bit_ded_de, bit_ded_ded,bit_ded_ix, bit_ded_ixd,
+ bit_ded_rg, bit_ded_rgd,bit_ded_in, bit_ded_ind,bit_ded_de, bit_ded_ded,bit_ded_ix, bit_ded_ixd,
+ bit_ded_rg, bit_ded_rgd,bit_ded_in, bit_ded_ind,bit_ded_de, bit_ded_ded,bit_ded_ix, bit_ded_ixd,
+ bit_ded_rg, bit_ded_rgd,bit_ded_in, bit_ded_ind,bit_ded_de, bit_ded_ded,bit_ded_ix, bit_ded_ixd,
+ /* 0x3b00 */
+ bit_ded_rg, bit_ded_rgd,bit_ded_in, bit_ded_ind,bit_ded_de, bit_ded_ded,bit_ded_ix, bit_ded_ixd,
+ bit_ded_rg, bit_ded_rgd,bit_ded_in, bit_ded_ind,bit_ded_de, bit_ded_ded,bit_ded_ix, bit_ded_ixd,
+ bit_ded_rg, bit_ded_rgd,bit_ded_in, bit_ded_ind,bit_ded_de, bit_ded_ded,bit_ded_ix, bit_ded_ixd,
+ bit_ded_rg, bit_ded_rgd,bit_ded_in, bit_ded_ind,bit_ded_de, bit_ded_ded,bit_ded_ix, bit_ded_ixd,
+ /* 0x3c00 */
+ bit_ix_rg, bit_ix_rgd, bit_ix_in, bit_ix_ind, bit_ix_de, bit_ix_ded, bit_ix_ix, bit_ix_ixd,
+ bit_ix_rg, bit_ix_rgd, bit_ix_in, bit_ix_ind, bit_ix_de, bit_ix_ded, bit_ix_ix, bit_ix_ixd,
+ bit_ix_rg, bit_ix_rgd, bit_ix_in, bit_ix_ind, bit_ix_de, bit_ix_ded, bit_ix_ix, bit_ix_ixd,
+ bit_ix_rg, bit_ix_rgd, bit_ix_in, bit_ix_ind, bit_ix_de, bit_ix_ded, bit_ix_ix, bit_ix_ixd,
+ /* 0x3d00 */
+ bit_ix_rg, bit_ix_rgd, bit_ix_in, bit_ix_ind, bit_ix_de, bit_ix_ded, bit_ix_ix, bit_ix_ixd,
+ bit_ix_rg, bit_ix_rgd, bit_ix_in, bit_ix_ind, bit_ix_de, bit_ix_ded, bit_ix_ix, bit_ix_ixd,
+ bit_ix_rg, bit_ix_rgd, bit_ix_in, bit_ix_ind, bit_ix_de, bit_ix_ded, bit_ix_ix, bit_ix_ixd,
+ bit_ix_rg, bit_ix_rgd, bit_ix_in, bit_ix_ind, bit_ix_de, bit_ix_ded, bit_ix_ix, bit_ix_ixd,
+ /* 0x3e00 */
+ bit_ixd_rg, bit_ixd_rgd,bit_ixd_in, bit_ixd_ind,bit_ixd_de, bit_ixd_ded,bit_ixd_ix, bit_ixd_ixd,
+ bit_ixd_rg, bit_ixd_rgd,bit_ixd_in, bit_ixd_ind,bit_ixd_de, bit_ixd_ded,bit_ixd_ix, bit_ixd_ixd,
+ bit_ixd_rg, bit_ixd_rgd,bit_ixd_in, bit_ixd_ind,bit_ixd_de, bit_ixd_ded,bit_ixd_ix, bit_ixd_ixd,
+ bit_ixd_rg, bit_ixd_rgd,bit_ixd_in, bit_ixd_ind,bit_ixd_de, bit_ixd_ded,bit_ixd_ix, bit_ixd_ixd,
+ /* 0x3f00 */
+ bit_ixd_rg, bit_ixd_rgd,bit_ixd_in, bit_ixd_ind,bit_ixd_de, bit_ixd_ded,bit_ixd_ix, bit_ixd_ixd,
+ bit_ixd_rg, bit_ixd_rgd,bit_ixd_in, bit_ixd_ind,bit_ixd_de, bit_ixd_ded,bit_ixd_ix, bit_ixd_ixd,
+ bit_ixd_rg, bit_ixd_rgd,bit_ixd_in, bit_ixd_ind,bit_ixd_de, bit_ixd_ded,bit_ixd_ix, bit_ixd_ixd,
+ bit_ixd_rg, bit_ixd_rgd,bit_ixd_in, bit_ixd_ind,bit_ixd_de, bit_ixd_ded,bit_ixd_ix, bit_ixd_ixd,
+
+ /* 0x4000 */
+ bic_rg_rg, bic_rg_rgd, bic_rg_in, bic_rg_ind, bic_rg_de, bic_rg_ded, bic_rg_ix, bic_rg_ixd,
+ bic_rg_rg, bic_rg_rgd, bic_rg_in, bic_rg_ind, bic_rg_de, bic_rg_ded, bic_rg_ix, bic_rg_ixd,
+ bic_rg_rg, bic_rg_rgd, bic_rg_in, bic_rg_ind, bic_rg_de, bic_rg_ded, bic_rg_ix, bic_rg_ixd,
+ bic_rg_rg, bic_rg_rgd, bic_rg_in, bic_rg_ind, bic_rg_de, bic_rg_ded, bic_rg_ix, bic_rg_ixd,
+ /* 0x4100 */
+ bic_rg_rg, bic_rg_rgd, bic_rg_in, bic_rg_ind, bic_rg_de, bic_rg_ded, bic_rg_ix, bic_rg_ixd,
+ bic_rg_rg, bic_rg_rgd, bic_rg_in, bic_rg_ind, bic_rg_de, bic_rg_ded, bic_rg_ix, bic_rg_ixd,
+ bic_rg_rg, bic_rg_rgd, bic_rg_in, bic_rg_ind, bic_rg_de, bic_rg_ded, bic_rg_ix, bic_rg_ixd,
+ bic_rg_rg, bic_rg_rgd, bic_rg_in, bic_rg_ind, bic_rg_de, bic_rg_ded, bic_rg_ix, bic_rg_ixd,
+ /* 0x4200 */
+ bic_rgd_rg, bic_rgd_rgd,bic_rgd_in, bic_rgd_ind,bic_rgd_de, bic_rgd_ded,bic_rgd_ix, bic_rgd_ixd,
+ bic_rgd_rg, bic_rgd_rgd,bic_rgd_in, bic_rgd_ind,bic_rgd_de, bic_rgd_ded,bic_rgd_ix, bic_rgd_ixd,
+ bic_rgd_rg, bic_rgd_rgd,bic_rgd_in, bic_rgd_ind,bic_rgd_de, bic_rgd_ded,bic_rgd_ix, bic_rgd_ixd,
+ bic_rgd_rg, bic_rgd_rgd,bic_rgd_in, bic_rgd_ind,bic_rgd_de, bic_rgd_ded,bic_rgd_ix, bic_rgd_ixd,
+ /* 0x4300 */
+ bic_rgd_rg, bic_rgd_rgd,bic_rgd_in, bic_rgd_ind,bic_rgd_de, bic_rgd_ded,bic_rgd_ix, bic_rgd_ixd,
+ bic_rgd_rg, bic_rgd_rgd,bic_rgd_in, bic_rgd_ind,bic_rgd_de, bic_rgd_ded,bic_rgd_ix, bic_rgd_ixd,
+ bic_rgd_rg, bic_rgd_rgd,bic_rgd_in, bic_rgd_ind,bic_rgd_de, bic_rgd_ded,bic_rgd_ix, bic_rgd_ixd,
+ bic_rgd_rg, bic_rgd_rgd,bic_rgd_in, bic_rgd_ind,bic_rgd_de, bic_rgd_ded,bic_rgd_ix, bic_rgd_ixd,
+ /* 0x4400 */
+ bic_in_rg, bic_in_rgd, bic_in_in, bic_in_ind, bic_in_de, bic_in_ded, bic_in_ix, bic_in_ixd,
+ bic_in_rg, bic_in_rgd, bic_in_in, bic_in_ind, bic_in_de, bic_in_ded, bic_in_ix, bic_in_ixd,
+ bic_in_rg, bic_in_rgd, bic_in_in, bic_in_ind, bic_in_de, bic_in_ded, bic_in_ix, bic_in_ixd,
+ bic_in_rg, bic_in_rgd, bic_in_in, bic_in_ind, bic_in_de, bic_in_ded, bic_in_ix, bic_in_ixd,
+ /* 0x4500 */
+ bic_in_rg, bic_in_rgd, bic_in_in, bic_in_ind, bic_in_de, bic_in_ded, bic_in_ix, bic_in_ixd,
+ bic_in_rg, bic_in_rgd, bic_in_in, bic_in_ind, bic_in_de, bic_in_ded, bic_in_ix, bic_in_ixd,
+ bic_in_rg, bic_in_rgd, bic_in_in, bic_in_ind, bic_in_de, bic_in_ded, bic_in_ix, bic_in_ixd,
+ bic_in_rg, bic_in_rgd, bic_in_in, bic_in_ind, bic_in_de, bic_in_ded, bic_in_ix, bic_in_ixd,
+ /* 0x4600 */
+ bic_ind_rg, bic_ind_rgd,bic_ind_in, bic_ind_ind,bic_ind_de, bic_ind_ded,bic_ind_ix, bic_ind_ixd,
+ bic_ind_rg, bic_ind_rgd,bic_ind_in, bic_ind_ind,bic_ind_de, bic_ind_ded,bic_ind_ix, bic_ind_ixd,
+ bic_ind_rg, bic_ind_rgd,bic_ind_in, bic_ind_ind,bic_ind_de, bic_ind_ded,bic_ind_ix, bic_ind_ixd,
+ bic_ind_rg, bic_ind_rgd,bic_ind_in, bic_ind_ind,bic_ind_de, bic_ind_ded,bic_ind_ix, bic_ind_ixd,
+ /* 0x4700 */
+ bic_ind_rg, bic_ind_rgd,bic_ind_in, bic_ind_ind,bic_ind_de, bic_ind_ded,bic_ind_ix, bic_ind_ixd,
+ bic_ind_rg, bic_ind_rgd,bic_ind_in, bic_ind_ind,bic_ind_de, bic_ind_ded,bic_ind_ix, bic_ind_ixd,
+ bic_ind_rg, bic_ind_rgd,bic_ind_in, bic_ind_ind,bic_ind_de, bic_ind_ded,bic_ind_ix, bic_ind_ixd,
+ bic_ind_rg, bic_ind_rgd,bic_ind_in, bic_ind_ind,bic_ind_de, bic_ind_ded,bic_ind_ix, bic_ind_ixd,
+ /* 0x4800 */
+ bic_de_rg, bic_de_rgd, bic_de_in, bic_de_ind, bic_de_de, bic_de_ded, bic_de_ix, bic_de_ixd,
+ bic_de_rg, bic_de_rgd, bic_de_in, bic_de_ind, bic_de_de, bic_de_ded, bic_de_ix, bic_de_ixd,
+ bic_de_rg, bic_de_rgd, bic_de_in, bic_de_ind, bic_de_de, bic_de_ded, bic_de_ix, bic_de_ixd,
+ bic_de_rg, bic_de_rgd, bic_de_in, bic_de_ind, bic_de_de, bic_de_ded, bic_de_ix, bic_de_ixd,
+ /* 0x4900 */
+ bic_de_rg, bic_de_rgd, bic_de_in, bic_de_ind, bic_de_de, bic_de_ded, bic_de_ix, bic_de_ixd,
+ bic_de_rg, bic_de_rgd, bic_de_in, bic_de_ind, bic_de_de, bic_de_ded, bic_de_ix, bic_de_ixd,
+ bic_de_rg, bic_de_rgd, bic_de_in, bic_de_ind, bic_de_de, bic_de_ded, bic_de_ix, bic_de_ixd,
+ bic_de_rg, bic_de_rgd, bic_de_in, bic_de_ind, bic_de_de, bic_de_ded, bic_de_ix, bic_de_ixd,
+ /* 0x4a00 */
+ bic_ded_rg, bic_ded_rgd,bic_ded_in, bic_ded_ind,bic_ded_de, bic_ded_ded,bic_ded_ix, bic_ded_ixd,
+ bic_ded_rg, bic_ded_rgd,bic_ded_in, bic_ded_ind,bic_ded_de, bic_ded_ded,bic_ded_ix, bic_ded_ixd,
+ bic_ded_rg, bic_ded_rgd,bic_ded_in, bic_ded_ind,bic_ded_de, bic_ded_ded,bic_ded_ix, bic_ded_ixd,
+ bic_ded_rg, bic_ded_rgd,bic_ded_in, bic_ded_ind,bic_ded_de, bic_ded_ded,bic_ded_ix, bic_ded_ixd,
+ /* 0x4b00 */
+ bic_ded_rg, bic_ded_rgd,bic_ded_in, bic_ded_ind,bic_ded_de, bic_ded_ded,bic_ded_ix, bic_ded_ixd,
+ bic_ded_rg, bic_ded_rgd,bic_ded_in, bic_ded_ind,bic_ded_de, bic_ded_ded,bic_ded_ix, bic_ded_ixd,
+ bic_ded_rg, bic_ded_rgd,bic_ded_in, bic_ded_ind,bic_ded_de, bic_ded_ded,bic_ded_ix, bic_ded_ixd,
+ bic_ded_rg, bic_ded_rgd,bic_ded_in, bic_ded_ind,bic_ded_de, bic_ded_ded,bic_ded_ix, bic_ded_ixd,
+ /* 0x4c00 */
+ bic_ix_rg, bic_ix_rgd, bic_ix_in, bic_ix_ind, bic_ix_de, bic_ix_ded, bic_ix_ix, bic_ix_ixd,
+ bic_ix_rg, bic_ix_rgd, bic_ix_in, bic_ix_ind, bic_ix_de, bic_ix_ded, bic_ix_ix, bic_ix_ixd,
+ bic_ix_rg, bic_ix_rgd, bic_ix_in, bic_ix_ind, bic_ix_de, bic_ix_ded, bic_ix_ix, bic_ix_ixd,
+ bic_ix_rg, bic_ix_rgd, bic_ix_in, bic_ix_ind, bic_ix_de, bic_ix_ded, bic_ix_ix, bic_ix_ixd,
+ /* 0x4d00 */
+ bic_ix_rg, bic_ix_rgd, bic_ix_in, bic_ix_ind, bic_ix_de, bic_ix_ded, bic_ix_ix, bic_ix_ixd,
+ bic_ix_rg, bic_ix_rgd, bic_ix_in, bic_ix_ind, bic_ix_de, bic_ix_ded, bic_ix_ix, bic_ix_ixd,
+ bic_ix_rg, bic_ix_rgd, bic_ix_in, bic_ix_ind, bic_ix_de, bic_ix_ded, bic_ix_ix, bic_ix_ixd,
+ bic_ix_rg, bic_ix_rgd, bic_ix_in, bic_ix_ind, bic_ix_de, bic_ix_ded, bic_ix_ix, bic_ix_ixd,
+ /* 0x4e00 */
+ bic_ixd_rg, bic_ixd_rgd,bic_ixd_in, bic_ixd_ind,bic_ixd_de, bic_ixd_ded,bic_ixd_ix, bic_ixd_ixd,
+ bic_ixd_rg, bic_ixd_rgd,bic_ixd_in, bic_ixd_ind,bic_ixd_de, bic_ixd_ded,bic_ixd_ix, bic_ixd_ixd,
+ bic_ixd_rg, bic_ixd_rgd,bic_ixd_in, bic_ixd_ind,bic_ixd_de, bic_ixd_ded,bic_ixd_ix, bic_ixd_ixd,
+ bic_ixd_rg, bic_ixd_rgd,bic_ixd_in, bic_ixd_ind,bic_ixd_de, bic_ixd_ded,bic_ixd_ix, bic_ixd_ixd,
+ /* 0x4f00 */
+ bic_ixd_rg, bic_ixd_rgd,bic_ixd_in, bic_ixd_ind,bic_ixd_de, bic_ixd_ded,bic_ixd_ix, bic_ixd_ixd,
+ bic_ixd_rg, bic_ixd_rgd,bic_ixd_in, bic_ixd_ind,bic_ixd_de, bic_ixd_ded,bic_ixd_ix, bic_ixd_ixd,
+ bic_ixd_rg, bic_ixd_rgd,bic_ixd_in, bic_ixd_ind,bic_ixd_de, bic_ixd_ded,bic_ixd_ix, bic_ixd_ixd,
+ bic_ixd_rg, bic_ixd_rgd,bic_ixd_in, bic_ixd_ind,bic_ixd_de, bic_ixd_ded,bic_ixd_ix, bic_ixd_ixd,
+
+ /* 0x5000 */
+ bis_rg_rg, bis_rg_rgd, bis_rg_in, bis_rg_ind, bis_rg_de, bis_rg_ded, bis_rg_ix, bis_rg_ixd,
+ bis_rg_rg, bis_rg_rgd, bis_rg_in, bis_rg_ind, bis_rg_de, bis_rg_ded, bis_rg_ix, bis_rg_ixd,
+ bis_rg_rg, bis_rg_rgd, bis_rg_in, bis_rg_ind, bis_rg_de, bis_rg_ded, bis_rg_ix, bis_rg_ixd,
+ bis_rg_rg, bis_rg_rgd, bis_rg_in, bis_rg_ind, bis_rg_de, bis_rg_ded, bis_rg_ix, bis_rg_ixd,
+ /* 0x5100 */
+ bis_rg_rg, bis_rg_rgd, bis_rg_in, bis_rg_ind, bis_rg_de, bis_rg_ded, bis_rg_ix, bis_rg_ixd,
+ bis_rg_rg, bis_rg_rgd, bis_rg_in, bis_rg_ind, bis_rg_de, bis_rg_ded, bis_rg_ix, bis_rg_ixd,
+ bis_rg_rg, bis_rg_rgd, bis_rg_in, bis_rg_ind, bis_rg_de, bis_rg_ded, bis_rg_ix, bis_rg_ixd,
+ bis_rg_rg, bis_rg_rgd, bis_rg_in, bis_rg_ind, bis_rg_de, bis_rg_ded, bis_rg_ix, bis_rg_ixd,
+ /* 0x5200 */
+ bis_rgd_rg, bis_rgd_rgd,bis_rgd_in, bis_rgd_ind,bis_rgd_de, bis_rgd_ded,bis_rgd_ix, bis_rgd_ixd,
+ bis_rgd_rg, bis_rgd_rgd,bis_rgd_in, bis_rgd_ind,bis_rgd_de, bis_rgd_ded,bis_rgd_ix, bis_rgd_ixd,
+ bis_rgd_rg, bis_rgd_rgd,bis_rgd_in, bis_rgd_ind,bis_rgd_de, bis_rgd_ded,bis_rgd_ix, bis_rgd_ixd,
+ bis_rgd_rg, bis_rgd_rgd,bis_rgd_in, bis_rgd_ind,bis_rgd_de, bis_rgd_ded,bis_rgd_ix, bis_rgd_ixd,
+ /* 0x5300 */
+ bis_rgd_rg, bis_rgd_rgd,bis_rgd_in, bis_rgd_ind,bis_rgd_de, bis_rgd_ded,bis_rgd_ix, bis_rgd_ixd,
+ bis_rgd_rg, bis_rgd_rgd,bis_rgd_in, bis_rgd_ind,bis_rgd_de, bis_rgd_ded,bis_rgd_ix, bis_rgd_ixd,
+ bis_rgd_rg, bis_rgd_rgd,bis_rgd_in, bis_rgd_ind,bis_rgd_de, bis_rgd_ded,bis_rgd_ix, bis_rgd_ixd,
+ bis_rgd_rg, bis_rgd_rgd,bis_rgd_in, bis_rgd_ind,bis_rgd_de, bis_rgd_ded,bis_rgd_ix, bis_rgd_ixd,
+ /* 0x5400 */
+ bis_in_rg, bis_in_rgd, bis_in_in, bis_in_ind, bis_in_de, bis_in_ded, bis_in_ix, bis_in_ixd,
+ bis_in_rg, bis_in_rgd, bis_in_in, bis_in_ind, bis_in_de, bis_in_ded, bis_in_ix, bis_in_ixd,
+ bis_in_rg, bis_in_rgd, bis_in_in, bis_in_ind, bis_in_de, bis_in_ded, bis_in_ix, bis_in_ixd,
+ bis_in_rg, bis_in_rgd, bis_in_in, bis_in_ind, bis_in_de, bis_in_ded, bis_in_ix, bis_in_ixd,
+ /* 0x5500 */
+ bis_in_rg, bis_in_rgd, bis_in_in, bis_in_ind, bis_in_de, bis_in_ded, bis_in_ix, bis_in_ixd,
+ bis_in_rg, bis_in_rgd, bis_in_in, bis_in_ind, bis_in_de, bis_in_ded, bis_in_ix, bis_in_ixd,
+ bis_in_rg, bis_in_rgd, bis_in_in, bis_in_ind, bis_in_de, bis_in_ded, bis_in_ix, bis_in_ixd,
+ bis_in_rg, bis_in_rgd, bis_in_in, bis_in_ind, bis_in_de, bis_in_ded, bis_in_ix, bis_in_ixd,
+ /* 0x5600 */
+ bis_ind_rg, bis_ind_rgd,bis_ind_in, bis_ind_ind,bis_ind_de, bis_ind_ded,bis_ind_ix, bis_ind_ixd,
+ bis_ind_rg, bis_ind_rgd,bis_ind_in, bis_ind_ind,bis_ind_de, bis_ind_ded,bis_ind_ix, bis_ind_ixd,
+ bis_ind_rg, bis_ind_rgd,bis_ind_in, bis_ind_ind,bis_ind_de, bis_ind_ded,bis_ind_ix, bis_ind_ixd,
+ bis_ind_rg, bis_ind_rgd,bis_ind_in, bis_ind_ind,bis_ind_de, bis_ind_ded,bis_ind_ix, bis_ind_ixd,
+ /* 0x5700 */
+ bis_ind_rg, bis_ind_rgd,bis_ind_in, bis_ind_ind,bis_ind_de, bis_ind_ded,bis_ind_ix, bis_ind_ixd,
+ bis_ind_rg, bis_ind_rgd,bis_ind_in, bis_ind_ind,bis_ind_de, bis_ind_ded,bis_ind_ix, bis_ind_ixd,
+ bis_ind_rg, bis_ind_rgd,bis_ind_in, bis_ind_ind,bis_ind_de, bis_ind_ded,bis_ind_ix, bis_ind_ixd,
+ bis_ind_rg, bis_ind_rgd,bis_ind_in, bis_ind_ind,bis_ind_de, bis_ind_ded,bis_ind_ix, bis_ind_ixd,
+ /* 0x5800 */
+ bis_de_rg, bis_de_rgd, bis_de_in, bis_de_ind, bis_de_de, bis_de_ded, bis_de_ix, bis_de_ixd,
+ bis_de_rg, bis_de_rgd, bis_de_in, bis_de_ind, bis_de_de, bis_de_ded, bis_de_ix, bis_de_ixd,
+ bis_de_rg, bis_de_rgd, bis_de_in, bis_de_ind, bis_de_de, bis_de_ded, bis_de_ix, bis_de_ixd,
+ bis_de_rg, bis_de_rgd, bis_de_in, bis_de_ind, bis_de_de, bis_de_ded, bis_de_ix, bis_de_ixd,
+ /* 0x5900 */
+ bis_de_rg, bis_de_rgd, bis_de_in, bis_de_ind, bis_de_de, bis_de_ded, bis_de_ix, bis_de_ixd,
+ bis_de_rg, bis_de_rgd, bis_de_in, bis_de_ind, bis_de_de, bis_de_ded, bis_de_ix, bis_de_ixd,
+ bis_de_rg, bis_de_rgd, bis_de_in, bis_de_ind, bis_de_de, bis_de_ded, bis_de_ix, bis_de_ixd,
+ bis_de_rg, bis_de_rgd, bis_de_in, bis_de_ind, bis_de_de, bis_de_ded, bis_de_ix, bis_de_ixd,
+ /* 0x5a00 */
+ bis_ded_rg, bis_ded_rgd,bis_ded_in, bis_ded_ind,bis_ded_de, bis_ded_ded,bis_ded_ix, bis_ded_ixd,
+ bis_ded_rg, bis_ded_rgd,bis_ded_in, bis_ded_ind,bis_ded_de, bis_ded_ded,bis_ded_ix, bis_ded_ixd,
+ bis_ded_rg, bis_ded_rgd,bis_ded_in, bis_ded_ind,bis_ded_de, bis_ded_ded,bis_ded_ix, bis_ded_ixd,
+ bis_ded_rg, bis_ded_rgd,bis_ded_in, bis_ded_ind,bis_ded_de, bis_ded_ded,bis_ded_ix, bis_ded_ixd,
+ /* 0x5b00 */
+ bis_ded_rg, bis_ded_rgd,bis_ded_in, bis_ded_ind,bis_ded_de, bis_ded_ded,bis_ded_ix, bis_ded_ixd,
+ bis_ded_rg, bis_ded_rgd,bis_ded_in, bis_ded_ind,bis_ded_de, bis_ded_ded,bis_ded_ix, bis_ded_ixd,
+ bis_ded_rg, bis_ded_rgd,bis_ded_in, bis_ded_ind,bis_ded_de, bis_ded_ded,bis_ded_ix, bis_ded_ixd,
+ bis_ded_rg, bis_ded_rgd,bis_ded_in, bis_ded_ind,bis_ded_de, bis_ded_ded,bis_ded_ix, bis_ded_ixd,
+ /* 0x5c00 */
+ bis_ix_rg, bis_ix_rgd, bis_ix_in, bis_ix_ind, bis_ix_de, bis_ix_ded, bis_ix_ix, bis_ix_ixd,
+ bis_ix_rg, bis_ix_rgd, bis_ix_in, bis_ix_ind, bis_ix_de, bis_ix_ded, bis_ix_ix, bis_ix_ixd,
+ bis_ix_rg, bis_ix_rgd, bis_ix_in, bis_ix_ind, bis_ix_de, bis_ix_ded, bis_ix_ix, bis_ix_ixd,
+ bis_ix_rg, bis_ix_rgd, bis_ix_in, bis_ix_ind, bis_ix_de, bis_ix_ded, bis_ix_ix, bis_ix_ixd,
+ /* 0x5d00 */
+ bis_ix_rg, bis_ix_rgd, bis_ix_in, bis_ix_ind, bis_ix_de, bis_ix_ded, bis_ix_ix, bis_ix_ixd,
+ bis_ix_rg, bis_ix_rgd, bis_ix_in, bis_ix_ind, bis_ix_de, bis_ix_ded, bis_ix_ix, bis_ix_ixd,
+ bis_ix_rg, bis_ix_rgd, bis_ix_in, bis_ix_ind, bis_ix_de, bis_ix_ded, bis_ix_ix, bis_ix_ixd,
+ bis_ix_rg, bis_ix_rgd, bis_ix_in, bis_ix_ind, bis_ix_de, bis_ix_ded, bis_ix_ix, bis_ix_ixd,
+ /* 0x5e00 */
+ bis_ixd_rg, bis_ixd_rgd,bis_ixd_in, bis_ixd_ind,bis_ixd_de, bis_ixd_ded,bis_ixd_ix, bis_ixd_ixd,
+ bis_ixd_rg, bis_ixd_rgd,bis_ixd_in, bis_ixd_ind,bis_ixd_de, bis_ixd_ded,bis_ixd_ix, bis_ixd_ixd,
+ bis_ixd_rg, bis_ixd_rgd,bis_ixd_in, bis_ixd_ind,bis_ixd_de, bis_ixd_ded,bis_ixd_ix, bis_ixd_ixd,
+ bis_ixd_rg, bis_ixd_rgd,bis_ixd_in, bis_ixd_ind,bis_ixd_de, bis_ixd_ded,bis_ixd_ix, bis_ixd_ixd,
+ /* 0x5f00 */
+ bis_ixd_rg, bis_ixd_rgd,bis_ixd_in, bis_ixd_ind,bis_ixd_de, bis_ixd_ded,bis_ixd_ix, bis_ixd_ixd,
+ bis_ixd_rg, bis_ixd_rgd,bis_ixd_in, bis_ixd_ind,bis_ixd_de, bis_ixd_ded,bis_ixd_ix, bis_ixd_ixd,
+ bis_ixd_rg, bis_ixd_rgd,bis_ixd_in, bis_ixd_ind,bis_ixd_de, bis_ixd_ded,bis_ixd_ix, bis_ixd_ixd,
+ bis_ixd_rg, bis_ixd_rgd,bis_ixd_in, bis_ixd_ind,bis_ixd_de, bis_ixd_ded,bis_ixd_ix, bis_ixd_ixd,
+
+ /* 0x6000 */
+ add_rg_rg, add_rg_rgd, add_rg_in, add_rg_ind, add_rg_de, add_rg_ded, add_rg_ix, add_rg_ixd,
+ add_rg_rg, add_rg_rgd, add_rg_in, add_rg_ind, add_rg_de, add_rg_ded, add_rg_ix, add_rg_ixd,
+ add_rg_rg, add_rg_rgd, add_rg_in, add_rg_ind, add_rg_de, add_rg_ded, add_rg_ix, add_rg_ixd,
+ add_rg_rg, add_rg_rgd, add_rg_in, add_rg_ind, add_rg_de, add_rg_ded, add_rg_ix, add_rg_ixd,
+ /* 0x6100 */
+ add_rg_rg, add_rg_rgd, add_rg_in, add_rg_ind, add_rg_de, add_rg_ded, add_rg_ix, add_rg_ixd,
+ add_rg_rg, add_rg_rgd, add_rg_in, add_rg_ind, add_rg_de, add_rg_ded, add_rg_ix, add_rg_ixd,
+ add_rg_rg, add_rg_rgd, add_rg_in, add_rg_ind, add_rg_de, add_rg_ded, add_rg_ix, add_rg_ixd,
+ add_rg_rg, add_rg_rgd, add_rg_in, add_rg_ind, add_rg_de, add_rg_ded, add_rg_ix, add_rg_ixd,
+ /* 0x6200 */
+ add_rgd_rg, add_rgd_rgd,add_rgd_in, add_rgd_ind,add_rgd_de, add_rgd_ded,add_rgd_ix, add_rgd_ixd,
+ add_rgd_rg, add_rgd_rgd,add_rgd_in, add_rgd_ind,add_rgd_de, add_rgd_ded,add_rgd_ix, add_rgd_ixd,
+ add_rgd_rg, add_rgd_rgd,add_rgd_in, add_rgd_ind,add_rgd_de, add_rgd_ded,add_rgd_ix, add_rgd_ixd,
+ add_rgd_rg, add_rgd_rgd,add_rgd_in, add_rgd_ind,add_rgd_de, add_rgd_ded,add_rgd_ix, add_rgd_ixd,
+ /* 0x6300 */
+ add_rgd_rg, add_rgd_rgd,add_rgd_in, add_rgd_ind,add_rgd_de, add_rgd_ded,add_rgd_ix, add_rgd_ixd,
+ add_rgd_rg, add_rgd_rgd,add_rgd_in, add_rgd_ind,add_rgd_de, add_rgd_ded,add_rgd_ix, add_rgd_ixd,
+ add_rgd_rg, add_rgd_rgd,add_rgd_in, add_rgd_ind,add_rgd_de, add_rgd_ded,add_rgd_ix, add_rgd_ixd,
+ add_rgd_rg, add_rgd_rgd,add_rgd_in, add_rgd_ind,add_rgd_de, add_rgd_ded,add_rgd_ix, add_rgd_ixd,
+ /* 0x6400 */
+ add_in_rg, add_in_rgd, add_in_in, add_in_ind, add_in_de, add_in_ded, add_in_ix, add_in_ixd,
+ add_in_rg, add_in_rgd, add_in_in, add_in_ind, add_in_de, add_in_ded, add_in_ix, add_in_ixd,
+ add_in_rg, add_in_rgd, add_in_in, add_in_ind, add_in_de, add_in_ded, add_in_ix, add_in_ixd,
+ add_in_rg, add_in_rgd, add_in_in, add_in_ind, add_in_de, add_in_ded, add_in_ix, add_in_ixd,
+ /* 0x6500 */
+ add_in_rg, add_in_rgd, add_in_in, add_in_ind, add_in_de, add_in_ded, add_in_ix, add_in_ixd,
+ add_in_rg, add_in_rgd, add_in_in, add_in_ind, add_in_de, add_in_ded, add_in_ix, add_in_ixd,
+ add_in_rg, add_in_rgd, add_in_in, add_in_ind, add_in_de, add_in_ded, add_in_ix, add_in_ixd,
+ add_in_rg, add_in_rgd, add_in_in, add_in_ind, add_in_de, add_in_ded, add_in_ix, add_in_ixd,
+ /* 0x6600 */
+ add_ind_rg, add_ind_rgd,add_ind_in, add_ind_ind,add_ind_de, add_ind_ded,add_ind_ix, add_ind_ixd,
+ add_ind_rg, add_ind_rgd,add_ind_in, add_ind_ind,add_ind_de, add_ind_ded,add_ind_ix, add_ind_ixd,
+ add_ind_rg, add_ind_rgd,add_ind_in, add_ind_ind,add_ind_de, add_ind_ded,add_ind_ix, add_ind_ixd,
+ add_ind_rg, add_ind_rgd,add_ind_in, add_ind_ind,add_ind_de, add_ind_ded,add_ind_ix, add_ind_ixd,
+ /* 0x6700 */
+ add_ind_rg, add_ind_rgd,add_ind_in, add_ind_ind,add_ind_de, add_ind_ded,add_ind_ix, add_ind_ixd,
+ add_ind_rg, add_ind_rgd,add_ind_in, add_ind_ind,add_ind_de, add_ind_ded,add_ind_ix, add_ind_ixd,
+ add_ind_rg, add_ind_rgd,add_ind_in, add_ind_ind,add_ind_de, add_ind_ded,add_ind_ix, add_ind_ixd,
+ add_ind_rg, add_ind_rgd,add_ind_in, add_ind_ind,add_ind_de, add_ind_ded,add_ind_ix, add_ind_ixd,
+ /* 0x6800 */
+ add_de_rg, add_de_rgd, add_de_in, add_de_ind, add_de_de, add_de_ded, add_de_ix, add_de_ixd,
+ add_de_rg, add_de_rgd, add_de_in, add_de_ind, add_de_de, add_de_ded, add_de_ix, add_de_ixd,
+ add_de_rg, add_de_rgd, add_de_in, add_de_ind, add_de_de, add_de_ded, add_de_ix, add_de_ixd,
+ add_de_rg, add_de_rgd, add_de_in, add_de_ind, add_de_de, add_de_ded, add_de_ix, add_de_ixd,
+ /* 0x6900 */
+ add_de_rg, add_de_rgd, add_de_in, add_de_ind, add_de_de, add_de_ded, add_de_ix, add_de_ixd,
+ add_de_rg, add_de_rgd, add_de_in, add_de_ind, add_de_de, add_de_ded, add_de_ix, add_de_ixd,
+ add_de_rg, add_de_rgd, add_de_in, add_de_ind, add_de_de, add_de_ded, add_de_ix, add_de_ixd,
+ add_de_rg, add_de_rgd, add_de_in, add_de_ind, add_de_de, add_de_ded, add_de_ix, add_de_ixd,
+ /* 0x6a00 */
+ add_ded_rg, add_ded_rgd,add_ded_in, add_ded_ind,add_ded_de, add_ded_ded,add_ded_ix, add_ded_ixd,
+ add_ded_rg, add_ded_rgd,add_ded_in, add_ded_ind,add_ded_de, add_ded_ded,add_ded_ix, add_ded_ixd,
+ add_ded_rg, add_ded_rgd,add_ded_in, add_ded_ind,add_ded_de, add_ded_ded,add_ded_ix, add_ded_ixd,
+ add_ded_rg, add_ded_rgd,add_ded_in, add_ded_ind,add_ded_de, add_ded_ded,add_ded_ix, add_ded_ixd,
+ /* 0x6b00 */
+ add_ded_rg, add_ded_rgd,add_ded_in, add_ded_ind,add_ded_de, add_ded_ded,add_ded_ix, add_ded_ixd,
+ add_ded_rg, add_ded_rgd,add_ded_in, add_ded_ind,add_ded_de, add_ded_ded,add_ded_ix, add_ded_ixd,
+ add_ded_rg, add_ded_rgd,add_ded_in, add_ded_ind,add_ded_de, add_ded_ded,add_ded_ix, add_ded_ixd,
+ add_ded_rg, add_ded_rgd,add_ded_in, add_ded_ind,add_ded_de, add_ded_ded,add_ded_ix, add_ded_ixd,
+ /* 0x6c00 */
+ add_ix_rg, add_ix_rgd, add_ix_in, add_ix_ind, add_ix_de, add_ix_ded, add_ix_ix, add_ix_ixd,
+ add_ix_rg, add_ix_rgd, add_ix_in, add_ix_ind, add_ix_de, add_ix_ded, add_ix_ix, add_ix_ixd,
+ add_ix_rg, add_ix_rgd, add_ix_in, add_ix_ind, add_ix_de, add_ix_ded, add_ix_ix, add_ix_ixd,
+ add_ix_rg, add_ix_rgd, add_ix_in, add_ix_ind, add_ix_de, add_ix_ded, add_ix_ix, add_ix_ixd,
+ /* 0x6d00 */
+ add_ix_rg, add_ix_rgd, add_ix_in, add_ix_ind, add_ix_de, add_ix_ded, add_ix_ix, add_ix_ixd,
+ add_ix_rg, add_ix_rgd, add_ix_in, add_ix_ind, add_ix_de, add_ix_ded, add_ix_ix, add_ix_ixd,
+ add_ix_rg, add_ix_rgd, add_ix_in, add_ix_ind, add_ix_de, add_ix_ded, add_ix_ix, add_ix_ixd,
+ add_ix_rg, add_ix_rgd, add_ix_in, add_ix_ind, add_ix_de, add_ix_ded, add_ix_ix, add_ix_ixd,
+ /* 0x6e00 */
+ add_ixd_rg, add_ixd_rgd,add_ixd_in, add_ixd_ind,add_ixd_de, add_ixd_ded,add_ixd_ix, add_ixd_ixd,
+ add_ixd_rg, add_ixd_rgd,add_ixd_in, add_ixd_ind,add_ixd_de, add_ixd_ded,add_ixd_ix, add_ixd_ixd,
+ add_ixd_rg, add_ixd_rgd,add_ixd_in, add_ixd_ind,add_ixd_de, add_ixd_ded,add_ixd_ix, add_ixd_ixd,
+ add_ixd_rg, add_ixd_rgd,add_ixd_in, add_ixd_ind,add_ixd_de, add_ixd_ded,add_ixd_ix, add_ixd_ixd,
+ /* 0x6f00 */
+ add_ixd_rg, add_ixd_rgd,add_ixd_in, add_ixd_ind,add_ixd_de, add_ixd_ded,add_ixd_ix, add_ixd_ixd,
+ add_ixd_rg, add_ixd_rgd,add_ixd_in, add_ixd_ind,add_ixd_de, add_ixd_ded,add_ixd_ix, add_ixd_ixd,
+ add_ixd_rg, add_ixd_rgd,add_ixd_in, add_ixd_ind,add_ixd_de, add_ixd_ded,add_ixd_ix, add_ixd_ixd,
+ add_ixd_rg, add_ixd_rgd,add_ixd_in, add_ixd_ind,add_ixd_de, add_ixd_ded,add_ixd_ix, add_ixd_ixd,
+
+ /* 0x7000 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7100 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7200 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7300 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7400 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7500 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7600 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7700 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7800 */
+ xor_rg, xor_rgd, xor_in, xor_ind, xor_de, xor_ded, xor_ix, xor_ixd,
+ xor_rg, xor_rgd, xor_in, xor_ind, xor_de, xor_ded, xor_ix, xor_ixd,
+ xor_rg, xor_rgd, xor_in, xor_ind, xor_de, xor_ded, xor_ix, xor_ixd,
+ xor_rg, xor_rgd, xor_in, xor_ind, xor_de, xor_ded, xor_ix, xor_ixd,
+ /* 0x7900 */
+ xor_rg, xor_rgd, xor_in, xor_ind, xor_de, xor_ded, xor_ix, xor_ixd,
+ xor_rg, xor_rgd, xor_in, xor_ind, xor_de, xor_ded, xor_ix, xor_ixd,
+ xor_rg, xor_rgd, xor_in, xor_ind, xor_de, xor_ded, xor_ix, xor_ixd,
+ xor_rg, xor_rgd, xor_in, xor_ind, xor_de, xor_ded, xor_ix, xor_ixd,
+ /* 0x7a00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7b00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7c00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7d00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x7e00 */
+ sob, sob, sob, sob, sob, sob, sob, sob,
+ sob, sob, sob, sob, sob, sob, sob, sob,
+ sob, sob, sob, sob, sob, sob, sob, sob,
+ sob, sob, sob, sob, sob, sob, sob, sob,
+ /* 0x7f00 */
+ sob, sob, sob, sob, sob, sob, sob, sob,
+ sob, sob, sob, sob, sob, sob, sob, sob,
+ sob, sob, sob, sob, sob, sob, sob, sob,
+ sob, sob, sob, sob, sob, sob, sob, sob,
+
+ /* 0x8000 */
+ bpl, bpl, bpl, bpl, bpl, bpl, bpl, bpl,
+ bpl, bpl, bpl, bpl, bpl, bpl, bpl, bpl,
+ bpl, bpl, bpl, bpl, bpl, bpl, bpl, bpl,
+ bpl, bpl, bpl, bpl, bpl, bpl, bpl, bpl,
+ /* 0x8100 */
+ bmi, bmi, bmi, bmi, bmi, bmi, bmi, bmi,
+ bmi, bmi, bmi, bmi, bmi, bmi, bmi, bmi,
+ bmi, bmi, bmi, bmi, bmi, bmi, bmi, bmi,
+ bmi, bmi, bmi, bmi, bmi, bmi, bmi, bmi,
+ /* 0x8200 */
+ bhi, bhi, bhi, bhi, bhi, bhi, bhi, bhi,
+ bhi, bhi, bhi, bhi, bhi, bhi, bhi, bhi,
+ bhi, bhi, bhi, bhi, bhi, bhi, bhi, bhi,
+ bhi, bhi, bhi, bhi, bhi, bhi, bhi, bhi,
+ /* 0x8300 */
+ blos, blos, blos, blos, blos, blos, blos, blos,
+ blos, blos, blos, blos, blos, blos, blos, blos,
+ blos, blos, blos, blos, blos, blos, blos, blos,
+ blos, blos, blos, blos, blos, blos, blos, blos,
+ /* 0x8400 */
+ bvc, bvc, bvc, bvc, bvc, bvc, bvc, bvc,
+ bvc, bvc, bvc, bvc, bvc, bvc, bvc, bvc,
+ bvc, bvc, bvc, bvc, bvc, bvc, bvc, bvc,
+ bvc, bvc, bvc, bvc, bvc, bvc, bvc, bvc,
+ /* 0x8500 */
+ bvs, bvs, bvs, bvs, bvs, bvs, bvs, bvs,
+ bvs, bvs, bvs, bvs, bvs, bvs, bvs, bvs,
+ bvs, bvs, bvs, bvs, bvs, bvs, bvs, bvs,
+ bvs, bvs, bvs, bvs, bvs, bvs, bvs, bvs,
+ /* 0x8600 */
+ bcc, bcc, bcc, bcc, bcc, bcc, bcc, bcc,
+ bcc, bcc, bcc, bcc, bcc, bcc, bcc, bcc,
+ bcc, bcc, bcc, bcc, bcc, bcc, bcc, bcc,
+ bcc, bcc, bcc, bcc, bcc, bcc, bcc, bcc,
+ /* 0x8700 */
+ bcs, bcs, bcs, bcs, bcs, bcs, bcs, bcs,
+ bcs, bcs, bcs, bcs, bcs, bcs, bcs, bcs,
+ bcs, bcs, bcs, bcs, bcs, bcs, bcs, bcs,
+ bcs, bcs, bcs, bcs, bcs, bcs, bcs, bcs,
+ /* 0x8800 */
+ emt, emt, emt, emt, emt, emt, emt, emt,
+ emt, emt, emt, emt, emt, emt, emt, emt,
+ emt, emt, emt, emt, emt, emt, emt, emt,
+ emt, emt, emt, emt, emt, emt, emt, emt,
+ /* 0x8900 */
+ trap, trap, trap, trap, trap, trap, trap, trap,
+ trap, trap, trap, trap, trap, trap, trap, trap,
+ trap, trap, trap, trap, trap, trap, trap, trap,
+ trap, trap, trap, trap, trap, trap, trap, trap,
+ /* 0x8a00 */
+ clrb_rg, clrb_rgd, clrb_in, clrb_ind, clrb_de, clrb_ded, clrb_ix, clrb_ixd,
+ comb_rg, comb_rgd, comb_in, comb_ind, comb_de, comb_ded, comb_ix, comb_ixd,
+ incb_rg, incb_rgd, incb_in, incb_ind, incb_de, incb_ded, incb_ix, incb_ixd,
+ decb_rg, decb_rgd, decb_in, decb_ind, decb_de, decb_ded, decb_ix, decb_ixd,
+ /* 0x8b00 */
+ negb_rg, negb_rgd, negb_in, negb_ind, negb_de, negb_ded, negb_ix, negb_ixd,
+ adcb_rg, adcb_rgd, adcb_in, adcb_ind, adcb_de, adcb_ded, adcb_ix, adcb_ixd,
+ sbcb_rg, sbcb_rgd, sbcb_in, sbcb_ind, sbcb_de, sbcb_ded, sbcb_ix, sbcb_ixd,
+ tstb_rg, tstb_rgd, tstb_in, tstb_ind, tstb_de, tstb_ded, tstb_ix, tstb_ixd,
+ /* 0x8c00 */
+ rorb_rg, rorb_rgd, rorb_in, rorb_ind, rorb_de, rorb_ded, rorb_ix, rorb_ixd,
+ rolb_rg, rolb_rgd, rolb_in, rolb_ind, rolb_de, rolb_ded, rolb_ix, rolb_ixd,
+ asrb_rg, asrb_rgd, asrb_in, asrb_ind, asrb_de, asrb_ded, asrb_ix, asrb_ixd,
+ aslb_rg, aslb_rgd, aslb_in, aslb_ind, aslb_de, aslb_ded, aslb_ix, aslb_ixd,
+ /* 0x8d00 */
+ mtps_rg, mtps_rgd, mtps_in, mtps_ind, mtps_de, mtps_ded, mtps_ix, mtps_ixd,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ mfps_rg, mfps_rgd, mfps_in, mfps_ind, mfps_de, mfps_ded, mfps_ix, mfps_ixd,
+ /* 0x8e00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0x8f00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+
+ /* 0x9000 */
+ movb_rg_rg, movb_rg_rgd,movb_rg_in, movb_rg_ind,movb_rg_de, movb_rg_ded,movb_rg_ix, movb_rg_ixd,
+ movb_rg_rg, movb_rg_rgd,movb_rg_in, movb_rg_ind,movb_rg_de, movb_rg_ded,movb_rg_ix, movb_rg_ixd,
+ movb_rg_rg, movb_rg_rgd,movb_rg_in, movb_rg_ind,movb_rg_de, movb_rg_ded,movb_rg_ix, movb_rg_ixd,
+ movb_rg_rg, movb_rg_rgd,movb_rg_in, movb_rg_ind,movb_rg_de, movb_rg_ded,movb_rg_ix, movb_rg_ixd,
+ /* 0x9100 */
+ movb_rg_rg, movb_rg_rgd,movb_rg_in, movb_rg_ind,movb_rg_de, movb_rg_ded,movb_rg_ix, movb_rg_ixd,
+ movb_rg_rg, movb_rg_rgd,movb_rg_in, movb_rg_ind,movb_rg_de, movb_rg_ded,movb_rg_ix, movb_rg_ixd,
+ movb_rg_rg, movb_rg_rgd,movb_rg_in, movb_rg_ind,movb_rg_de, movb_rg_ded,movb_rg_ix, movb_rg_ixd,
+ movb_rg_rg, movb_rg_rgd,movb_rg_in, movb_rg_ind,movb_rg_de, movb_rg_ded,movb_rg_ix, movb_rg_ixd,
+ /* 0x9200 */
+ movb_rgd_rg,movb_rgd_rgd,movb_rgd_in,movb_rgd_ind,movb_rgd_de,movb_rgd_ded,movb_rgd_ix,movb_rgd_ixd,
+ movb_rgd_rg,movb_rgd_rgd,movb_rgd_in,movb_rgd_ind,movb_rgd_de,movb_rgd_ded,movb_rgd_ix,movb_rgd_ixd,
+ movb_rgd_rg,movb_rgd_rgd,movb_rgd_in,movb_rgd_ind,movb_rgd_de,movb_rgd_ded,movb_rgd_ix,movb_rgd_ixd,
+ movb_rgd_rg,movb_rgd_rgd,movb_rgd_in,movb_rgd_ind,movb_rgd_de,movb_rgd_ded,movb_rgd_ix,movb_rgd_ixd,
+ /* 0x9300 */
+ movb_rgd_rg,movb_rgd_rgd,movb_rgd_in,movb_rgd_ind,movb_rgd_de,movb_rgd_ded,movb_rgd_ix,movb_rgd_ixd,
+ movb_rgd_rg,movb_rgd_rgd,movb_rgd_in,movb_rgd_ind,movb_rgd_de,movb_rgd_ded,movb_rgd_ix,movb_rgd_ixd,
+ movb_rgd_rg,movb_rgd_rgd,movb_rgd_in,movb_rgd_ind,movb_rgd_de,movb_rgd_ded,movb_rgd_ix,movb_rgd_ixd,
+ movb_rgd_rg,movb_rgd_rgd,movb_rgd_in,movb_rgd_ind,movb_rgd_de,movb_rgd_ded,movb_rgd_ix,movb_rgd_ixd,
+ /* 0x9400 */
+ movb_in_rg, movb_in_rgd,movb_in_in, movb_in_ind,movb_in_de, movb_in_ded,movb_in_ix, movb_in_ixd,
+ movb_in_rg, movb_in_rgd,movb_in_in, movb_in_ind,movb_in_de, movb_in_ded,movb_in_ix, movb_in_ixd,
+ movb_in_rg, movb_in_rgd,movb_in_in, movb_in_ind,movb_in_de, movb_in_ded,movb_in_ix, movb_in_ixd,
+ movb_in_rg, movb_in_rgd,movb_in_in, movb_in_ind,movb_in_de, movb_in_ded,movb_in_ix, movb_in_ixd,
+ /* 0x9500 */
+ movb_in_rg, movb_in_rgd,movb_in_in, movb_in_ind,movb_in_de, movb_in_ded,movb_in_ix, movb_in_ixd,
+ movb_in_rg, movb_in_rgd,movb_in_in, movb_in_ind,movb_in_de, movb_in_ded,movb_in_ix, movb_in_ixd,
+ movb_in_rg, movb_in_rgd,movb_in_in, movb_in_ind,movb_in_de, movb_in_ded,movb_in_ix, movb_in_ixd,
+ movb_in_rg, movb_in_rgd,movb_in_in, movb_in_ind,movb_in_de, movb_in_ded,movb_in_ix, movb_in_ixd,
+ /* 0x9600 */
+ movb_ind_rg,movb_ind_rgd,movb_ind_in,movb_ind_ind,movb_ind_de,movb_ind_ded,movb_ind_ix,movb_ind_ixd,
+ movb_ind_rg,movb_ind_rgd,movb_ind_in,movb_ind_ind,movb_ind_de,movb_ind_ded,movb_ind_ix,movb_ind_ixd,
+ movb_ind_rg,movb_ind_rgd,movb_ind_in,movb_ind_ind,movb_ind_de,movb_ind_ded,movb_ind_ix,movb_ind_ixd,
+ movb_ind_rg,movb_ind_rgd,movb_ind_in,movb_ind_ind,movb_ind_de,movb_ind_ded,movb_ind_ix,movb_ind_ixd,
+ /* 0x9700 */
+ movb_ind_rg,movb_ind_rgd,movb_ind_in,movb_ind_ind,movb_ind_de,movb_ind_ded,movb_ind_ix,movb_ind_ixd,
+ movb_ind_rg,movb_ind_rgd,movb_ind_in,movb_ind_ind,movb_ind_de,movb_ind_ded,movb_ind_ix,movb_ind_ixd,
+ movb_ind_rg,movb_ind_rgd,movb_ind_in,movb_ind_ind,movb_ind_de,movb_ind_ded,movb_ind_ix,movb_ind_ixd,
+ movb_ind_rg,movb_ind_rgd,movb_ind_in,movb_ind_ind,movb_ind_de,movb_ind_ded,movb_ind_ix,movb_ind_ixd,
+ /* 0x9800 */
+ movb_de_rg, movb_de_rgd,movb_de_in, movb_de_ind,movb_de_de, movb_de_ded,movb_de_ix, movb_de_ixd,
+ movb_de_rg, movb_de_rgd,movb_de_in, movb_de_ind,movb_de_de, movb_de_ded,movb_de_ix, movb_de_ixd,
+ movb_de_rg, movb_de_rgd,movb_de_in, movb_de_ind,movb_de_de, movb_de_ded,movb_de_ix, movb_de_ixd,
+ movb_de_rg, movb_de_rgd,movb_de_in, movb_de_ind,movb_de_de, movb_de_ded,movb_de_ix, movb_de_ixd,
+ /* 0x9900 */
+ movb_de_rg, movb_de_rgd,movb_de_in, movb_de_ind,movb_de_de, movb_de_ded,movb_de_ix, movb_de_ixd,
+ movb_de_rg, movb_de_rgd,movb_de_in, movb_de_ind,movb_de_de, movb_de_ded,movb_de_ix, movb_de_ixd,
+ movb_de_rg, movb_de_rgd,movb_de_in, movb_de_ind,movb_de_de, movb_de_ded,movb_de_ix, movb_de_ixd,
+ movb_de_rg, movb_de_rgd,movb_de_in, movb_de_ind,movb_de_de, movb_de_ded,movb_de_ix, movb_de_ixd,
+ /* 0x9a00 */
+ movb_ded_rg,movb_ded_rgd,movb_ded_in,movb_ded_ind,movb_ded_de,movb_ded_ded,movb_ded_ix,movb_ded_ixd,
+ movb_ded_rg,movb_ded_rgd,movb_ded_in,movb_ded_ind,movb_ded_de,movb_ded_ded,movb_ded_ix,movb_ded_ixd,
+ movb_ded_rg,movb_ded_rgd,movb_ded_in,movb_ded_ind,movb_ded_de,movb_ded_ded,movb_ded_ix,movb_ded_ixd,
+ movb_ded_rg,movb_ded_rgd,movb_ded_in,movb_ded_ind,movb_ded_de,movb_ded_ded,movb_ded_ix,movb_ded_ixd,
+ /* 0x9b00 */
+ movb_ded_rg,movb_ded_rgd,movb_ded_in,movb_ded_ind,movb_ded_de,movb_ded_ded,movb_ded_ix,movb_ded_ixd,
+ movb_ded_rg,movb_ded_rgd,movb_ded_in,movb_ded_ind,movb_ded_de,movb_ded_ded,movb_ded_ix,movb_ded_ixd,
+ movb_ded_rg,movb_ded_rgd,movb_ded_in,movb_ded_ind,movb_ded_de,movb_ded_ded,movb_ded_ix,movb_ded_ixd,
+ movb_ded_rg,movb_ded_rgd,movb_ded_in,movb_ded_ind,movb_ded_de,movb_ded_ded,movb_ded_ix,movb_ded_ixd,
+ /* 0x9c00 */
+ movb_ix_rg, movb_ix_rgd,movb_ix_in, movb_ix_ind,movb_ix_de, movb_ix_ded,movb_ix_ix, movb_ix_ixd,
+ movb_ix_rg, movb_ix_rgd,movb_ix_in, movb_ix_ind,movb_ix_de, movb_ix_ded,movb_ix_ix, movb_ix_ixd,
+ movb_ix_rg, movb_ix_rgd,movb_ix_in, movb_ix_ind,movb_ix_de, movb_ix_ded,movb_ix_ix, movb_ix_ixd,
+ movb_ix_rg, movb_ix_rgd,movb_ix_in, movb_ix_ind,movb_ix_de, movb_ix_ded,movb_ix_ix, movb_ix_ixd,
+ /* 0x9d00 */
+ movb_ix_rg, movb_ix_rgd,movb_ix_in, movb_ix_ind,movb_ix_de, movb_ix_ded,movb_ix_ix, movb_ix_ixd,
+ movb_ix_rg, movb_ix_rgd,movb_ix_in, movb_ix_ind,movb_ix_de, movb_ix_ded,movb_ix_ix, movb_ix_ixd,
+ movb_ix_rg, movb_ix_rgd,movb_ix_in, movb_ix_ind,movb_ix_de, movb_ix_ded,movb_ix_ix, movb_ix_ixd,
+ movb_ix_rg, movb_ix_rgd,movb_ix_in, movb_ix_ind,movb_ix_de, movb_ix_ded,movb_ix_ix, movb_ix_ixd,
+ /* 0x9e00 */
+ movb_ixd_rg,movb_ixd_rgd,movb_ixd_in,movb_ixd_ind,movb_ixd_de,movb_ixd_ded,movb_ixd_ix,movb_ixd_ixd,
+ movb_ixd_rg,movb_ixd_rgd,movb_ixd_in,movb_ixd_ind,movb_ixd_de,movb_ixd_ded,movb_ixd_ix,movb_ixd_ixd,
+ movb_ixd_rg,movb_ixd_rgd,movb_ixd_in,movb_ixd_ind,movb_ixd_de,movb_ixd_ded,movb_ixd_ix,movb_ixd_ixd,
+ movb_ixd_rg,movb_ixd_rgd,movb_ixd_in,movb_ixd_ind,movb_ixd_de,movb_ixd_ded,movb_ixd_ix,movb_ixd_ixd,
+ /* 0x9f00 */
+ movb_ixd_rg,movb_ixd_rgd,movb_ixd_in,movb_ixd_ind,movb_ixd_de,movb_ixd_ded,movb_ixd_ix,movb_ixd_ixd,
+ movb_ixd_rg,movb_ixd_rgd,movb_ixd_in,movb_ixd_ind,movb_ixd_de,movb_ixd_ded,movb_ixd_ix,movb_ixd_ixd,
+ movb_ixd_rg,movb_ixd_rgd,movb_ixd_in,movb_ixd_ind,movb_ixd_de,movb_ixd_ded,movb_ixd_ix,movb_ixd_ixd,
+ movb_ixd_rg,movb_ixd_rgd,movb_ixd_in,movb_ixd_ind,movb_ixd_de,movb_ixd_ded,movb_ixd_ix,movb_ixd_ixd,
+
+ /* 0xa000 */
+ cmpb_rg_rg, cmpb_rg_rgd,cmpb_rg_in, cmpb_rg_ind,cmpb_rg_de, cmpb_rg_ded,cmpb_rg_ix, cmpb_rg_ixd,
+ cmpb_rg_rg, cmpb_rg_rgd,cmpb_rg_in, cmpb_rg_ind,cmpb_rg_de, cmpb_rg_ded,cmpb_rg_ix, cmpb_rg_ixd,
+ cmpb_rg_rg, cmpb_rg_rgd,cmpb_rg_in, cmpb_rg_ind,cmpb_rg_de, cmpb_rg_ded,cmpb_rg_ix, cmpb_rg_ixd,
+ cmpb_rg_rg, cmpb_rg_rgd,cmpb_rg_in, cmpb_rg_ind,cmpb_rg_de, cmpb_rg_ded,cmpb_rg_ix, cmpb_rg_ixd,
+ /* 0xa100 */
+ cmpb_rg_rg, cmpb_rg_rgd,cmpb_rg_in, cmpb_rg_ind,cmpb_rg_de, cmpb_rg_ded,cmpb_rg_ix, cmpb_rg_ixd,
+ cmpb_rg_rg, cmpb_rg_rgd,cmpb_rg_in, cmpb_rg_ind,cmpb_rg_de, cmpb_rg_ded,cmpb_rg_ix, cmpb_rg_ixd,
+ cmpb_rg_rg, cmpb_rg_rgd,cmpb_rg_in, cmpb_rg_ind,cmpb_rg_de, cmpb_rg_ded,cmpb_rg_ix, cmpb_rg_ixd,
+ cmpb_rg_rg, cmpb_rg_rgd,cmpb_rg_in, cmpb_rg_ind,cmpb_rg_de, cmpb_rg_ded,cmpb_rg_ix, cmpb_rg_ixd,
+ /* 0xa200 */
+ cmpb_rgd_rg,cmpb_rgd_rgd,cmpb_rgd_in,cmpb_rgd_ind,cmpb_rgd_de,cmpb_rgd_ded,cmpb_rgd_ix,cmpb_rgd_ixd,
+ cmpb_rgd_rg,cmpb_rgd_rgd,cmpb_rgd_in,cmpb_rgd_ind,cmpb_rgd_de,cmpb_rgd_ded,cmpb_rgd_ix,cmpb_rgd_ixd,
+ cmpb_rgd_rg,cmpb_rgd_rgd,cmpb_rgd_in,cmpb_rgd_ind,cmpb_rgd_de,cmpb_rgd_ded,cmpb_rgd_ix,cmpb_rgd_ixd,
+ cmpb_rgd_rg,cmpb_rgd_rgd,cmpb_rgd_in,cmpb_rgd_ind,cmpb_rgd_de,cmpb_rgd_ded,cmpb_rgd_ix,cmpb_rgd_ixd,
+ /* 0xa300 */
+ cmpb_rgd_rg,cmpb_rgd_rgd,cmpb_rgd_in,cmpb_rgd_ind,cmpb_rgd_de,cmpb_rgd_ded,cmpb_rgd_ix,cmpb_rgd_ixd,
+ cmpb_rgd_rg,cmpb_rgd_rgd,cmpb_rgd_in,cmpb_rgd_ind,cmpb_rgd_de,cmpb_rgd_ded,cmpb_rgd_ix,cmpb_rgd_ixd,
+ cmpb_rgd_rg,cmpb_rgd_rgd,cmpb_rgd_in,cmpb_rgd_ind,cmpb_rgd_de,cmpb_rgd_ded,cmpb_rgd_ix,cmpb_rgd_ixd,
+ cmpb_rgd_rg,cmpb_rgd_rgd,cmpb_rgd_in,cmpb_rgd_ind,cmpb_rgd_de,cmpb_rgd_ded,cmpb_rgd_ix,cmpb_rgd_ixd,
+ /* 0xa400 */
+ cmpb_in_rg, cmpb_in_rgd,cmpb_in_in, cmpb_in_ind,cmpb_in_de, cmpb_in_ded,cmpb_in_ix, cmpb_in_ixd,
+ cmpb_in_rg, cmpb_in_rgd,cmpb_in_in, cmpb_in_ind,cmpb_in_de, cmpb_in_ded,cmpb_in_ix, cmpb_in_ixd,
+ cmpb_in_rg, cmpb_in_rgd,cmpb_in_in, cmpb_in_ind,cmpb_in_de, cmpb_in_ded,cmpb_in_ix, cmpb_in_ixd,
+ cmpb_in_rg, cmpb_in_rgd,cmpb_in_in, cmpb_in_ind,cmpb_in_de, cmpb_in_ded,cmpb_in_ix, cmpb_in_ixd,
+ /* 0xa500 */
+ cmpb_in_rg, cmpb_in_rgd,cmpb_in_in, cmpb_in_ind,cmpb_in_de, cmpb_in_ded,cmpb_in_ix, cmpb_in_ixd,
+ cmpb_in_rg, cmpb_in_rgd,cmpb_in_in, cmpb_in_ind,cmpb_in_de, cmpb_in_ded,cmpb_in_ix, cmpb_in_ixd,
+ cmpb_in_rg, cmpb_in_rgd,cmpb_in_in, cmpb_in_ind,cmpb_in_de, cmpb_in_ded,cmpb_in_ix, cmpb_in_ixd,
+ cmpb_in_rg, cmpb_in_rgd,cmpb_in_in, cmpb_in_ind,cmpb_in_de, cmpb_in_ded,cmpb_in_ix, cmpb_in_ixd,
+ /* 0xa600 */
+ cmpb_ind_rg,cmpb_ind_rgd,cmpb_ind_in,cmpb_ind_ind,cmpb_ind_de,cmpb_ind_ded,cmpb_ind_ix,cmpb_ind_ixd,
+ cmpb_ind_rg,cmpb_ind_rgd,cmpb_ind_in,cmpb_ind_ind,cmpb_ind_de,cmpb_ind_ded,cmpb_ind_ix,cmpb_ind_ixd,
+ cmpb_ind_rg,cmpb_ind_rgd,cmpb_ind_in,cmpb_ind_ind,cmpb_ind_de,cmpb_ind_ded,cmpb_ind_ix,cmpb_ind_ixd,
+ cmpb_ind_rg,cmpb_ind_rgd,cmpb_ind_in,cmpb_ind_ind,cmpb_ind_de,cmpb_ind_ded,cmpb_ind_ix,cmpb_ind_ixd,
+ /* 0xa700 */
+ cmpb_ind_rg,cmpb_ind_rgd,cmpb_ind_in,cmpb_ind_ind,cmpb_ind_de,cmpb_ind_ded,cmpb_ind_ix,cmpb_ind_ixd,
+ cmpb_ind_rg,cmpb_ind_rgd,cmpb_ind_in,cmpb_ind_ind,cmpb_ind_de,cmpb_ind_ded,cmpb_ind_ix,cmpb_ind_ixd,
+ cmpb_ind_rg,cmpb_ind_rgd,cmpb_ind_in,cmpb_ind_ind,cmpb_ind_de,cmpb_ind_ded,cmpb_ind_ix,cmpb_ind_ixd,
+ cmpb_ind_rg,cmpb_ind_rgd,cmpb_ind_in,cmpb_ind_ind,cmpb_ind_de,cmpb_ind_ded,cmpb_ind_ix,cmpb_ind_ixd,
+ /* 0xa800 */
+ cmpb_de_rg, cmpb_de_rgd,cmpb_de_in, cmpb_de_ind,cmpb_de_de, cmpb_de_ded,cmpb_de_ix, cmpb_de_ixd,
+ cmpb_de_rg, cmpb_de_rgd,cmpb_de_in, cmpb_de_ind,cmpb_de_de, cmpb_de_ded,cmpb_de_ix, cmpb_de_ixd,
+ cmpb_de_rg, cmpb_de_rgd,cmpb_de_in, cmpb_de_ind,cmpb_de_de, cmpb_de_ded,cmpb_de_ix, cmpb_de_ixd,
+ cmpb_de_rg, cmpb_de_rgd,cmpb_de_in, cmpb_de_ind,cmpb_de_de, cmpb_de_ded,cmpb_de_ix, cmpb_de_ixd,
+ /* 0xa900 */
+ cmpb_de_rg, cmpb_de_rgd,cmpb_de_in, cmpb_de_ind,cmpb_de_de, cmpb_de_ded,cmpb_de_ix, cmpb_de_ixd,
+ cmpb_de_rg, cmpb_de_rgd,cmpb_de_in, cmpb_de_ind,cmpb_de_de, cmpb_de_ded,cmpb_de_ix, cmpb_de_ixd,
+ cmpb_de_rg, cmpb_de_rgd,cmpb_de_in, cmpb_de_ind,cmpb_de_de, cmpb_de_ded,cmpb_de_ix, cmpb_de_ixd,
+ cmpb_de_rg, cmpb_de_rgd,cmpb_de_in, cmpb_de_ind,cmpb_de_de, cmpb_de_ded,cmpb_de_ix, cmpb_de_ixd,
+ /* 0xaa00 */
+ cmpb_ded_rg,cmpb_ded_rgd,cmpb_ded_in,cmpb_ded_ind,cmpb_ded_de,cmpb_ded_ded,cmpb_ded_ix,cmpb_ded_ixd,
+ cmpb_ded_rg,cmpb_ded_rgd,cmpb_ded_in,cmpb_ded_ind,cmpb_ded_de,cmpb_ded_ded,cmpb_ded_ix,cmpb_ded_ixd,
+ cmpb_ded_rg,cmpb_ded_rgd,cmpb_ded_in,cmpb_ded_ind,cmpb_ded_de,cmpb_ded_ded,cmpb_ded_ix,cmpb_ded_ixd,
+ cmpb_ded_rg,cmpb_ded_rgd,cmpb_ded_in,cmpb_ded_ind,cmpb_ded_de,cmpb_ded_ded,cmpb_ded_ix,cmpb_ded_ixd,
+ /* 0xab00 */
+ cmpb_ded_rg,cmpb_ded_rgd,cmpb_ded_in,cmpb_ded_ind,cmpb_ded_de,cmpb_ded_ded,cmpb_ded_ix,cmpb_ded_ixd,
+ cmpb_ded_rg,cmpb_ded_rgd,cmpb_ded_in,cmpb_ded_ind,cmpb_ded_de,cmpb_ded_ded,cmpb_ded_ix,cmpb_ded_ixd,
+ cmpb_ded_rg,cmpb_ded_rgd,cmpb_ded_in,cmpb_ded_ind,cmpb_ded_de,cmpb_ded_ded,cmpb_ded_ix,cmpb_ded_ixd,
+ cmpb_ded_rg,cmpb_ded_rgd,cmpb_ded_in,cmpb_ded_ind,cmpb_ded_de,cmpb_ded_ded,cmpb_ded_ix,cmpb_ded_ixd,
+ /* 0xac00 */
+ cmpb_ix_rg, cmpb_ix_rgd,cmpb_ix_in, cmpb_ix_ind,cmpb_ix_de, cmpb_ix_ded,cmpb_ix_ix, cmpb_ix_ixd,
+ cmpb_ix_rg, cmpb_ix_rgd,cmpb_ix_in, cmpb_ix_ind,cmpb_ix_de, cmpb_ix_ded,cmpb_ix_ix, cmpb_ix_ixd,
+ cmpb_ix_rg, cmpb_ix_rgd,cmpb_ix_in, cmpb_ix_ind,cmpb_ix_de, cmpb_ix_ded,cmpb_ix_ix, cmpb_ix_ixd,
+ cmpb_ix_rg, cmpb_ix_rgd,cmpb_ix_in, cmpb_ix_ind,cmpb_ix_de, cmpb_ix_ded,cmpb_ix_ix, cmpb_ix_ixd,
+ /* 0xad00 */
+ cmpb_ix_rg, cmpb_ix_rgd,cmpb_ix_in, cmpb_ix_ind,cmpb_ix_de, cmpb_ix_ded,cmpb_ix_ix, cmpb_ix_ixd,
+ cmpb_ix_rg, cmpb_ix_rgd,cmpb_ix_in, cmpb_ix_ind,cmpb_ix_de, cmpb_ix_ded,cmpb_ix_ix, cmpb_ix_ixd,
+ cmpb_ix_rg, cmpb_ix_rgd,cmpb_ix_in, cmpb_ix_ind,cmpb_ix_de, cmpb_ix_ded,cmpb_ix_ix, cmpb_ix_ixd,
+ cmpb_ix_rg, cmpb_ix_rgd,cmpb_ix_in, cmpb_ix_ind,cmpb_ix_de, cmpb_ix_ded,cmpb_ix_ix, cmpb_ix_ixd,
+ /* 0xae00 */
+ cmpb_ixd_rg,cmpb_ixd_rgd,cmpb_ixd_in,cmpb_ixd_ind,cmpb_ixd_de,cmpb_ixd_ded,cmpb_ixd_ix,cmpb_ixd_ixd,
+ cmpb_ixd_rg,cmpb_ixd_rgd,cmpb_ixd_in,cmpb_ixd_ind,cmpb_ixd_de,cmpb_ixd_ded,cmpb_ixd_ix,cmpb_ixd_ixd,
+ cmpb_ixd_rg,cmpb_ixd_rgd,cmpb_ixd_in,cmpb_ixd_ind,cmpb_ixd_de,cmpb_ixd_ded,cmpb_ixd_ix,cmpb_ixd_ixd,
+ cmpb_ixd_rg,cmpb_ixd_rgd,cmpb_ixd_in,cmpb_ixd_ind,cmpb_ixd_de,cmpb_ixd_ded,cmpb_ixd_ix,cmpb_ixd_ixd,
+ /* 0xaf00 */
+ cmpb_ixd_rg,cmpb_ixd_rgd,cmpb_ixd_in,cmpb_ixd_ind,cmpb_ixd_de,cmpb_ixd_ded,cmpb_ixd_ix,cmpb_ixd_ixd,
+ cmpb_ixd_rg,cmpb_ixd_rgd,cmpb_ixd_in,cmpb_ixd_ind,cmpb_ixd_de,cmpb_ixd_ded,cmpb_ixd_ix,cmpb_ixd_ixd,
+ cmpb_ixd_rg,cmpb_ixd_rgd,cmpb_ixd_in,cmpb_ixd_ind,cmpb_ixd_de,cmpb_ixd_ded,cmpb_ixd_ix,cmpb_ixd_ixd,
+ cmpb_ixd_rg,cmpb_ixd_rgd,cmpb_ixd_in,cmpb_ixd_ind,cmpb_ixd_de,cmpb_ixd_ded,cmpb_ixd_ix,cmpb_ixd_ixd,
+
+ /* 0xb000 */
+ bitb_rg_rg, bitb_rg_rgd,bitb_rg_in, bitb_rg_ind,bitb_rg_de, bitb_rg_ded,bitb_rg_ix, bitb_rg_ixd,
+ bitb_rg_rg, bitb_rg_rgd,bitb_rg_in, bitb_rg_ind,bitb_rg_de, bitb_rg_ded,bitb_rg_ix, bitb_rg_ixd,
+ bitb_rg_rg, bitb_rg_rgd,bitb_rg_in, bitb_rg_ind,bitb_rg_de, bitb_rg_ded,bitb_rg_ix, bitb_rg_ixd,
+ bitb_rg_rg, bitb_rg_rgd,bitb_rg_in, bitb_rg_ind,bitb_rg_de, bitb_rg_ded,bitb_rg_ix, bitb_rg_ixd,
+ /* 0xb100 */
+ bitb_rg_rg, bitb_rg_rgd,bitb_rg_in, bitb_rg_ind,bitb_rg_de, bitb_rg_ded,bitb_rg_ix, bitb_rg_ixd,
+ bitb_rg_rg, bitb_rg_rgd,bitb_rg_in, bitb_rg_ind,bitb_rg_de, bitb_rg_ded,bitb_rg_ix, bitb_rg_ixd,
+ bitb_rg_rg, bitb_rg_rgd,bitb_rg_in, bitb_rg_ind,bitb_rg_de, bitb_rg_ded,bitb_rg_ix, bitb_rg_ixd,
+ bitb_rg_rg, bitb_rg_rgd,bitb_rg_in, bitb_rg_ind,bitb_rg_de, bitb_rg_ded,bitb_rg_ix, bitb_rg_ixd,
+ /* 0xb200 */
+ bitb_rgd_rg,bitb_rgd_rgd,bitb_rgd_in,bitb_rgd_ind,bitb_rgd_de,bitb_rgd_ded,bitb_rgd_ix,bitb_rgd_ixd,
+ bitb_rgd_rg,bitb_rgd_rgd,bitb_rgd_in,bitb_rgd_ind,bitb_rgd_de,bitb_rgd_ded,bitb_rgd_ix,bitb_rgd_ixd,
+ bitb_rgd_rg,bitb_rgd_rgd,bitb_rgd_in,bitb_rgd_ind,bitb_rgd_de,bitb_rgd_ded,bitb_rgd_ix,bitb_rgd_ixd,
+ bitb_rgd_rg,bitb_rgd_rgd,bitb_rgd_in,bitb_rgd_ind,bitb_rgd_de,bitb_rgd_ded,bitb_rgd_ix,bitb_rgd_ixd,
+ /* 0xb300 */
+ bitb_rgd_rg,bitb_rgd_rgd,bitb_rgd_in,bitb_rgd_ind,bitb_rgd_de,bitb_rgd_ded,bitb_rgd_ix,bitb_rgd_ixd,
+ bitb_rgd_rg,bitb_rgd_rgd,bitb_rgd_in,bitb_rgd_ind,bitb_rgd_de,bitb_rgd_ded,bitb_rgd_ix,bitb_rgd_ixd,
+ bitb_rgd_rg,bitb_rgd_rgd,bitb_rgd_in,bitb_rgd_ind,bitb_rgd_de,bitb_rgd_ded,bitb_rgd_ix,bitb_rgd_ixd,
+ bitb_rgd_rg,bitb_rgd_rgd,bitb_rgd_in,bitb_rgd_ind,bitb_rgd_de,bitb_rgd_ded,bitb_rgd_ix,bitb_rgd_ixd,
+ /* 0xb400 */
+ bitb_in_rg, bitb_in_rgd,bitb_in_in, bitb_in_ind,bitb_in_de, bitb_in_ded,bitb_in_ix, bitb_in_ixd,
+ bitb_in_rg, bitb_in_rgd,bitb_in_in, bitb_in_ind,bitb_in_de, bitb_in_ded,bitb_in_ix, bitb_in_ixd,
+ bitb_in_rg, bitb_in_rgd,bitb_in_in, bitb_in_ind,bitb_in_de, bitb_in_ded,bitb_in_ix, bitb_in_ixd,
+ bitb_in_rg, bitb_in_rgd,bitb_in_in, bitb_in_ind,bitb_in_de, bitb_in_ded,bitb_in_ix, bitb_in_ixd,
+ /* 0xb500 */
+ bitb_in_rg, bitb_in_rgd,bitb_in_in, bitb_in_ind,bitb_in_de, bitb_in_ded,bitb_in_ix, bitb_in_ixd,
+ bitb_in_rg, bitb_in_rgd,bitb_in_in, bitb_in_ind,bitb_in_de, bitb_in_ded,bitb_in_ix, bitb_in_ixd,
+ bitb_in_rg, bitb_in_rgd,bitb_in_in, bitb_in_ind,bitb_in_de, bitb_in_ded,bitb_in_ix, bitb_in_ixd,
+ bitb_in_rg, bitb_in_rgd,bitb_in_in, bitb_in_ind,bitb_in_de, bitb_in_ded,bitb_in_ix, bitb_in_ixd,
+ /* 0xb600 */
+ bitb_ind_rg,bitb_ind_rgd,bitb_ind_in,bitb_ind_ind,bitb_ind_de,bitb_ind_ded,bitb_ind_ix,bitb_ind_ixd,
+ bitb_ind_rg,bitb_ind_rgd,bitb_ind_in,bitb_ind_ind,bitb_ind_de,bitb_ind_ded,bitb_ind_ix,bitb_ind_ixd,
+ bitb_ind_rg,bitb_ind_rgd,bitb_ind_in,bitb_ind_ind,bitb_ind_de,bitb_ind_ded,bitb_ind_ix,bitb_ind_ixd,
+ bitb_ind_rg,bitb_ind_rgd,bitb_ind_in,bitb_ind_ind,bitb_ind_de,bitb_ind_ded,bitb_ind_ix,bitb_ind_ixd,
+ /* 0xb700 */
+ bitb_ind_rg,bitb_ind_rgd,bitb_ind_in,bitb_ind_ind,bitb_ind_de,bitb_ind_ded,bitb_ind_ix,bitb_ind_ixd,
+ bitb_ind_rg,bitb_ind_rgd,bitb_ind_in,bitb_ind_ind,bitb_ind_de,bitb_ind_ded,bitb_ind_ix,bitb_ind_ixd,
+ bitb_ind_rg,bitb_ind_rgd,bitb_ind_in,bitb_ind_ind,bitb_ind_de,bitb_ind_ded,bitb_ind_ix,bitb_ind_ixd,
+ bitb_ind_rg,bitb_ind_rgd,bitb_ind_in,bitb_ind_ind,bitb_ind_de,bitb_ind_ded,bitb_ind_ix,bitb_ind_ixd,
+ /* 0xb800 */
+ bitb_de_rg, bitb_de_rgd,bitb_de_in, bitb_de_ind,bitb_de_de, bitb_de_ded,bitb_de_ix, bitb_de_ixd,
+ bitb_de_rg, bitb_de_rgd,bitb_de_in, bitb_de_ind,bitb_de_de, bitb_de_ded,bitb_de_ix, bitb_de_ixd,
+ bitb_de_rg, bitb_de_rgd,bitb_de_in, bitb_de_ind,bitb_de_de, bitb_de_ded,bitb_de_ix, bitb_de_ixd,
+ bitb_de_rg, bitb_de_rgd,bitb_de_in, bitb_de_ind,bitb_de_de, bitb_de_ded,bitb_de_ix, bitb_de_ixd,
+ /* 0xb900 */
+ bitb_de_rg, bitb_de_rgd,bitb_de_in, bitb_de_ind,bitb_de_de, bitb_de_ded,bitb_de_ix, bitb_de_ixd,
+ bitb_de_rg, bitb_de_rgd,bitb_de_in, bitb_de_ind,bitb_de_de, bitb_de_ded,bitb_de_ix, bitb_de_ixd,
+ bitb_de_rg, bitb_de_rgd,bitb_de_in, bitb_de_ind,bitb_de_de, bitb_de_ded,bitb_de_ix, bitb_de_ixd,
+ bitb_de_rg, bitb_de_rgd,bitb_de_in, bitb_de_ind,bitb_de_de, bitb_de_ded,bitb_de_ix, bitb_de_ixd,
+ /* 0xba00 */
+ bitb_ded_rg,bitb_ded_rgd,bitb_ded_in,bitb_ded_ind,bitb_ded_de,bitb_ded_ded,bitb_ded_ix,bitb_ded_ixd,
+ bitb_ded_rg,bitb_ded_rgd,bitb_ded_in,bitb_ded_ind,bitb_ded_de,bitb_ded_ded,bitb_ded_ix,bitb_ded_ixd,
+ bitb_ded_rg,bitb_ded_rgd,bitb_ded_in,bitb_ded_ind,bitb_ded_de,bitb_ded_ded,bitb_ded_ix,bitb_ded_ixd,
+ bitb_ded_rg,bitb_ded_rgd,bitb_ded_in,bitb_ded_ind,bitb_ded_de,bitb_ded_ded,bitb_ded_ix,bitb_ded_ixd,
+ /* 0xbb00 */
+ bitb_ded_rg,bitb_ded_rgd,bitb_ded_in,bitb_ded_ind,bitb_ded_de,bitb_ded_ded,bitb_ded_ix,bitb_ded_ixd,
+ bitb_ded_rg,bitb_ded_rgd,bitb_ded_in,bitb_ded_ind,bitb_ded_de,bitb_ded_ded,bitb_ded_ix,bitb_ded_ixd,
+ bitb_ded_rg,bitb_ded_rgd,bitb_ded_in,bitb_ded_ind,bitb_ded_de,bitb_ded_ded,bitb_ded_ix,bitb_ded_ixd,
+ bitb_ded_rg,bitb_ded_rgd,bitb_ded_in,bitb_ded_ind,bitb_ded_de,bitb_ded_ded,bitb_ded_ix,bitb_ded_ixd,
+ /* 0xbc00 */
+ bitb_ix_rg, bitb_ix_rgd,bitb_ix_in, bitb_ix_ind,bitb_ix_de, bitb_ix_ded,bitb_ix_ix, bitb_ix_ixd,
+ bitb_ix_rg, bitb_ix_rgd,bitb_ix_in, bitb_ix_ind,bitb_ix_de, bitb_ix_ded,bitb_ix_ix, bitb_ix_ixd,
+ bitb_ix_rg, bitb_ix_rgd,bitb_ix_in, bitb_ix_ind,bitb_ix_de, bitb_ix_ded,bitb_ix_ix, bitb_ix_ixd,
+ bitb_ix_rg, bitb_ix_rgd,bitb_ix_in, bitb_ix_ind,bitb_ix_de, bitb_ix_ded,bitb_ix_ix, bitb_ix_ixd,
+ /* 0xbd00 */
+ bitb_ix_rg, bitb_ix_rgd,bitb_ix_in, bitb_ix_ind,bitb_ix_de, bitb_ix_ded,bitb_ix_ix, bitb_ix_ixd,
+ bitb_ix_rg, bitb_ix_rgd,bitb_ix_in, bitb_ix_ind,bitb_ix_de, bitb_ix_ded,bitb_ix_ix, bitb_ix_ixd,
+ bitb_ix_rg, bitb_ix_rgd,bitb_ix_in, bitb_ix_ind,bitb_ix_de, bitb_ix_ded,bitb_ix_ix, bitb_ix_ixd,
+ bitb_ix_rg, bitb_ix_rgd,bitb_ix_in, bitb_ix_ind,bitb_ix_de, bitb_ix_ded,bitb_ix_ix, bitb_ix_ixd,
+ /* 0xbe00 */
+ bitb_ixd_rg,bitb_ixd_rgd,bitb_ixd_in,bitb_ixd_ind,bitb_ixd_de,bitb_ixd_ded,bitb_ixd_ix,bitb_ixd_ixd,
+ bitb_ixd_rg,bitb_ixd_rgd,bitb_ixd_in,bitb_ixd_ind,bitb_ixd_de,bitb_ixd_ded,bitb_ixd_ix,bitb_ixd_ixd,
+ bitb_ixd_rg,bitb_ixd_rgd,bitb_ixd_in,bitb_ixd_ind,bitb_ixd_de,bitb_ixd_ded,bitb_ixd_ix,bitb_ixd_ixd,
+ bitb_ixd_rg,bitb_ixd_rgd,bitb_ixd_in,bitb_ixd_ind,bitb_ixd_de,bitb_ixd_ded,bitb_ixd_ix,bitb_ixd_ixd,
+ /* 0xbf00 */
+ bitb_ixd_rg,bitb_ixd_rgd,bitb_ixd_in,bitb_ixd_ind,bitb_ixd_de,bitb_ixd_ded,bitb_ixd_ix,bitb_ixd_ixd,
+ bitb_ixd_rg,bitb_ixd_rgd,bitb_ixd_in,bitb_ixd_ind,bitb_ixd_de,bitb_ixd_ded,bitb_ixd_ix,bitb_ixd_ixd,
+ bitb_ixd_rg,bitb_ixd_rgd,bitb_ixd_in,bitb_ixd_ind,bitb_ixd_de,bitb_ixd_ded,bitb_ixd_ix,bitb_ixd_ixd,
+ bitb_ixd_rg,bitb_ixd_rgd,bitb_ixd_in,bitb_ixd_ind,bitb_ixd_de,bitb_ixd_ded,bitb_ixd_ix,bitb_ixd_ixd,
+
+ /* 0xc000 */
+ bicb_rg_rg, bicb_rg_rgd,bicb_rg_in, bicb_rg_ind,bicb_rg_de, bicb_rg_ded,bicb_rg_ix, bicb_rg_ixd,
+ bicb_rg_rg, bicb_rg_rgd,bicb_rg_in, bicb_rg_ind,bicb_rg_de, bicb_rg_ded,bicb_rg_ix, bicb_rg_ixd,
+ bicb_rg_rg, bicb_rg_rgd,bicb_rg_in, bicb_rg_ind,bicb_rg_de, bicb_rg_ded,bicb_rg_ix, bicb_rg_ixd,
+ bicb_rg_rg, bicb_rg_rgd,bicb_rg_in, bicb_rg_ind,bicb_rg_de, bicb_rg_ded,bicb_rg_ix, bicb_rg_ixd,
+ /* 0xc100 */
+ bicb_rg_rg, bicb_rg_rgd,bicb_rg_in, bicb_rg_ind,bicb_rg_de, bicb_rg_ded,bicb_rg_ix, bicb_rg_ixd,
+ bicb_rg_rg, bicb_rg_rgd,bicb_rg_in, bicb_rg_ind,bicb_rg_de, bicb_rg_ded,bicb_rg_ix, bicb_rg_ixd,
+ bicb_rg_rg, bicb_rg_rgd,bicb_rg_in, bicb_rg_ind,bicb_rg_de, bicb_rg_ded,bicb_rg_ix, bicb_rg_ixd,
+ bicb_rg_rg, bicb_rg_rgd,bicb_rg_in, bicb_rg_ind,bicb_rg_de, bicb_rg_ded,bicb_rg_ix, bicb_rg_ixd,
+ /* 0xc200 */
+ bicb_rgd_rg,bicb_rgd_rgd,bicb_rgd_in,bicb_rgd_ind,bicb_rgd_de,bicb_rgd_ded,bicb_rgd_ix,bicb_rgd_ixd,
+ bicb_rgd_rg,bicb_rgd_rgd,bicb_rgd_in,bicb_rgd_ind,bicb_rgd_de,bicb_rgd_ded,bicb_rgd_ix,bicb_rgd_ixd,
+ bicb_rgd_rg,bicb_rgd_rgd,bicb_rgd_in,bicb_rgd_ind,bicb_rgd_de,bicb_rgd_ded,bicb_rgd_ix,bicb_rgd_ixd,
+ bicb_rgd_rg,bicb_rgd_rgd,bicb_rgd_in,bicb_rgd_ind,bicb_rgd_de,bicb_rgd_ded,bicb_rgd_ix,bicb_rgd_ixd,
+ /* 0xc300 */
+ bicb_rgd_rg,bicb_rgd_rgd,bicb_rgd_in,bicb_rgd_ind,bicb_rgd_de,bicb_rgd_ded,bicb_rgd_ix,bicb_rgd_ixd,
+ bicb_rgd_rg,bicb_rgd_rgd,bicb_rgd_in,bicb_rgd_ind,bicb_rgd_de,bicb_rgd_ded,bicb_rgd_ix,bicb_rgd_ixd,
+ bicb_rgd_rg,bicb_rgd_rgd,bicb_rgd_in,bicb_rgd_ind,bicb_rgd_de,bicb_rgd_ded,bicb_rgd_ix,bicb_rgd_ixd,
+ bicb_rgd_rg,bicb_rgd_rgd,bicb_rgd_in,bicb_rgd_ind,bicb_rgd_de,bicb_rgd_ded,bicb_rgd_ix,bicb_rgd_ixd,
+ /* 0xc400 */
+ bicb_in_rg, bicb_in_rgd,bicb_in_in, bicb_in_ind,bicb_in_de, bicb_in_ded,bicb_in_ix, bicb_in_ixd,
+ bicb_in_rg, bicb_in_rgd,bicb_in_in, bicb_in_ind,bicb_in_de, bicb_in_ded,bicb_in_ix, bicb_in_ixd,
+ bicb_in_rg, bicb_in_rgd,bicb_in_in, bicb_in_ind,bicb_in_de, bicb_in_ded,bicb_in_ix, bicb_in_ixd,
+ bicb_in_rg, bicb_in_rgd,bicb_in_in, bicb_in_ind,bicb_in_de, bicb_in_ded,bicb_in_ix, bicb_in_ixd,
+ /* 0xc500 */
+ bicb_in_rg, bicb_in_rgd,bicb_in_in, bicb_in_ind,bicb_in_de, bicb_in_ded,bicb_in_ix, bicb_in_ixd,
+ bicb_in_rg, bicb_in_rgd,bicb_in_in, bicb_in_ind,bicb_in_de, bicb_in_ded,bicb_in_ix, bicb_in_ixd,
+ bicb_in_rg, bicb_in_rgd,bicb_in_in, bicb_in_ind,bicb_in_de, bicb_in_ded,bicb_in_ix, bicb_in_ixd,
+ bicb_in_rg, bicb_in_rgd,bicb_in_in, bicb_in_ind,bicb_in_de, bicb_in_ded,bicb_in_ix, bicb_in_ixd,
+ /* 0xc600 */
+ bicb_ind_rg,bicb_ind_rgd,bicb_ind_in,bicb_ind_ind,bicb_ind_de,bicb_ind_ded,bicb_ind_ix,bicb_ind_ixd,
+ bicb_ind_rg,bicb_ind_rgd,bicb_ind_in,bicb_ind_ind,bicb_ind_de,bicb_ind_ded,bicb_ind_ix,bicb_ind_ixd,
+ bicb_ind_rg,bicb_ind_rgd,bicb_ind_in,bicb_ind_ind,bicb_ind_de,bicb_ind_ded,bicb_ind_ix,bicb_ind_ixd,
+ bicb_ind_rg,bicb_ind_rgd,bicb_ind_in,bicb_ind_ind,bicb_ind_de,bicb_ind_ded,bicb_ind_ix,bicb_ind_ixd,
+ /* 0xc700 */
+ bicb_ind_rg,bicb_ind_rgd,bicb_ind_in,bicb_ind_ind,bicb_ind_de,bicb_ind_ded,bicb_ind_ix,bicb_ind_ixd,
+ bicb_ind_rg,bicb_ind_rgd,bicb_ind_in,bicb_ind_ind,bicb_ind_de,bicb_ind_ded,bicb_ind_ix,bicb_ind_ixd,
+ bicb_ind_rg,bicb_ind_rgd,bicb_ind_in,bicb_ind_ind,bicb_ind_de,bicb_ind_ded,bicb_ind_ix,bicb_ind_ixd,
+ bicb_ind_rg,bicb_ind_rgd,bicb_ind_in,bicb_ind_ind,bicb_ind_de,bicb_ind_ded,bicb_ind_ix,bicb_ind_ixd,
+ /* 0xc800 */
+ bicb_de_rg, bicb_de_rgd,bicb_de_in, bicb_de_ind,bicb_de_de, bicb_de_ded,bicb_de_ix, bicb_de_ixd,
+ bicb_de_rg, bicb_de_rgd,bicb_de_in, bicb_de_ind,bicb_de_de, bicb_de_ded,bicb_de_ix, bicb_de_ixd,
+ bicb_de_rg, bicb_de_rgd,bicb_de_in, bicb_de_ind,bicb_de_de, bicb_de_ded,bicb_de_ix, bicb_de_ixd,
+ bicb_de_rg, bicb_de_rgd,bicb_de_in, bicb_de_ind,bicb_de_de, bicb_de_ded,bicb_de_ix, bicb_de_ixd,
+ /* 0xc900 */
+ bicb_de_rg, bicb_de_rgd,bicb_de_in, bicb_de_ind,bicb_de_de, bicb_de_ded,bicb_de_ix, bicb_de_ixd,
+ bicb_de_rg, bicb_de_rgd,bicb_de_in, bicb_de_ind,bicb_de_de, bicb_de_ded,bicb_de_ix, bicb_de_ixd,
+ bicb_de_rg, bicb_de_rgd,bicb_de_in, bicb_de_ind,bicb_de_de, bicb_de_ded,bicb_de_ix, bicb_de_ixd,
+ bicb_de_rg, bicb_de_rgd,bicb_de_in, bicb_de_ind,bicb_de_de, bicb_de_ded,bicb_de_ix, bicb_de_ixd,
+ /* 0xca00 */
+ bicb_ded_rg,bicb_ded_rgd,bicb_ded_in,bicb_ded_ind,bicb_ded_de,bicb_ded_ded,bicb_ded_ix,bicb_ded_ixd,
+ bicb_ded_rg,bicb_ded_rgd,bicb_ded_in,bicb_ded_ind,bicb_ded_de,bicb_ded_ded,bicb_ded_ix,bicb_ded_ixd,
+ bicb_ded_rg,bicb_ded_rgd,bicb_ded_in,bicb_ded_ind,bicb_ded_de,bicb_ded_ded,bicb_ded_ix,bicb_ded_ixd,
+ bicb_ded_rg,bicb_ded_rgd,bicb_ded_in,bicb_ded_ind,bicb_ded_de,bicb_ded_ded,bicb_ded_ix,bicb_ded_ixd,
+ /* 0xcb00 */
+ bicb_ded_rg,bicb_ded_rgd,bicb_ded_in,bicb_ded_ind,bicb_ded_de,bicb_ded_ded,bicb_ded_ix,bicb_ded_ixd,
+ bicb_ded_rg,bicb_ded_rgd,bicb_ded_in,bicb_ded_ind,bicb_ded_de,bicb_ded_ded,bicb_ded_ix,bicb_ded_ixd,
+ bicb_ded_rg,bicb_ded_rgd,bicb_ded_in,bicb_ded_ind,bicb_ded_de,bicb_ded_ded,bicb_ded_ix,bicb_ded_ixd,
+ bicb_ded_rg,bicb_ded_rgd,bicb_ded_in,bicb_ded_ind,bicb_ded_de,bicb_ded_ded,bicb_ded_ix,bicb_ded_ixd,
+ /* 0xcc00 */
+ bicb_ix_rg, bicb_ix_rgd,bicb_ix_in, bicb_ix_ind,bicb_ix_de, bicb_ix_ded,bicb_ix_ix, bicb_ix_ixd,
+ bicb_ix_rg, bicb_ix_rgd,bicb_ix_in, bicb_ix_ind,bicb_ix_de, bicb_ix_ded,bicb_ix_ix, bicb_ix_ixd,
+ bicb_ix_rg, bicb_ix_rgd,bicb_ix_in, bicb_ix_ind,bicb_ix_de, bicb_ix_ded,bicb_ix_ix, bicb_ix_ixd,
+ bicb_ix_rg, bicb_ix_rgd,bicb_ix_in, bicb_ix_ind,bicb_ix_de, bicb_ix_ded,bicb_ix_ix, bicb_ix_ixd,
+ /* 0xcd00 */
+ bicb_ix_rg, bicb_ix_rgd,bicb_ix_in, bicb_ix_ind,bicb_ix_de, bicb_ix_ded,bicb_ix_ix, bicb_ix_ixd,
+ bicb_ix_rg, bicb_ix_rgd,bicb_ix_in, bicb_ix_ind,bicb_ix_de, bicb_ix_ded,bicb_ix_ix, bicb_ix_ixd,
+ bicb_ix_rg, bicb_ix_rgd,bicb_ix_in, bicb_ix_ind,bicb_ix_de, bicb_ix_ded,bicb_ix_ix, bicb_ix_ixd,
+ bicb_ix_rg, bicb_ix_rgd,bicb_ix_in, bicb_ix_ind,bicb_ix_de, bicb_ix_ded,bicb_ix_ix, bicb_ix_ixd,
+ /* 0xce00 */
+ bicb_ixd_rg,bicb_ixd_rgd,bicb_ixd_in,bicb_ixd_ind,bicb_ixd_de,bicb_ixd_ded,bicb_ixd_ix,bicb_ixd_ixd,
+ bicb_ixd_rg,bicb_ixd_rgd,bicb_ixd_in,bicb_ixd_ind,bicb_ixd_de,bicb_ixd_ded,bicb_ixd_ix,bicb_ixd_ixd,
+ bicb_ixd_rg,bicb_ixd_rgd,bicb_ixd_in,bicb_ixd_ind,bicb_ixd_de,bicb_ixd_ded,bicb_ixd_ix,bicb_ixd_ixd,
+ bicb_ixd_rg,bicb_ixd_rgd,bicb_ixd_in,bicb_ixd_ind,bicb_ixd_de,bicb_ixd_ded,bicb_ixd_ix,bicb_ixd_ixd,
+ /* 0xcf00 */
+ bicb_ixd_rg,bicb_ixd_rgd,bicb_ixd_in,bicb_ixd_ind,bicb_ixd_de,bicb_ixd_ded,bicb_ixd_ix,bicb_ixd_ixd,
+ bicb_ixd_rg,bicb_ixd_rgd,bicb_ixd_in,bicb_ixd_ind,bicb_ixd_de,bicb_ixd_ded,bicb_ixd_ix,bicb_ixd_ixd,
+ bicb_ixd_rg,bicb_ixd_rgd,bicb_ixd_in,bicb_ixd_ind,bicb_ixd_de,bicb_ixd_ded,bicb_ixd_ix,bicb_ixd_ixd,
+ bicb_ixd_rg,bicb_ixd_rgd,bicb_ixd_in,bicb_ixd_ind,bicb_ixd_de,bicb_ixd_ded,bicb_ixd_ix,bicb_ixd_ixd,
+
+ /* 0xd000 */
+ bisb_rg_rg, bisb_rg_rgd,bisb_rg_in, bisb_rg_ind,bisb_rg_de, bisb_rg_ded,bisb_rg_ix, bisb_rg_ixd,
+ bisb_rg_rg, bisb_rg_rgd,bisb_rg_in, bisb_rg_ind,bisb_rg_de, bisb_rg_ded,bisb_rg_ix, bisb_rg_ixd,
+ bisb_rg_rg, bisb_rg_rgd,bisb_rg_in, bisb_rg_ind,bisb_rg_de, bisb_rg_ded,bisb_rg_ix, bisb_rg_ixd,
+ bisb_rg_rg, bisb_rg_rgd,bisb_rg_in, bisb_rg_ind,bisb_rg_de, bisb_rg_ded,bisb_rg_ix, bisb_rg_ixd,
+ /* 0xd100 */
+ bisb_rg_rg, bisb_rg_rgd,bisb_rg_in, bisb_rg_ind,bisb_rg_de, bisb_rg_ded,bisb_rg_ix, bisb_rg_ixd,
+ bisb_rg_rg, bisb_rg_rgd,bisb_rg_in, bisb_rg_ind,bisb_rg_de, bisb_rg_ded,bisb_rg_ix, bisb_rg_ixd,
+ bisb_rg_rg, bisb_rg_rgd,bisb_rg_in, bisb_rg_ind,bisb_rg_de, bisb_rg_ded,bisb_rg_ix, bisb_rg_ixd,
+ bisb_rg_rg, bisb_rg_rgd,bisb_rg_in, bisb_rg_ind,bisb_rg_de, bisb_rg_ded,bisb_rg_ix, bisb_rg_ixd,
+ /* 0xd200 */
+ bisb_rgd_rg,bisb_rgd_rgd,bisb_rgd_in,bisb_rgd_ind,bisb_rgd_de,bisb_rgd_ded,bisb_rgd_ix,bisb_rgd_ixd,
+ bisb_rgd_rg,bisb_rgd_rgd,bisb_rgd_in,bisb_rgd_ind,bisb_rgd_de,bisb_rgd_ded,bisb_rgd_ix,bisb_rgd_ixd,
+ bisb_rgd_rg,bisb_rgd_rgd,bisb_rgd_in,bisb_rgd_ind,bisb_rgd_de,bisb_rgd_ded,bisb_rgd_ix,bisb_rgd_ixd,
+ bisb_rgd_rg,bisb_rgd_rgd,bisb_rgd_in,bisb_rgd_ind,bisb_rgd_de,bisb_rgd_ded,bisb_rgd_ix,bisb_rgd_ixd,
+ /* 0xd300 */
+ bisb_rgd_rg,bisb_rgd_rgd,bisb_rgd_in,bisb_rgd_ind,bisb_rgd_de,bisb_rgd_ded,bisb_rgd_ix,bisb_rgd_ixd,
+ bisb_rgd_rg,bisb_rgd_rgd,bisb_rgd_in,bisb_rgd_ind,bisb_rgd_de,bisb_rgd_ded,bisb_rgd_ix,bisb_rgd_ixd,
+ bisb_rgd_rg,bisb_rgd_rgd,bisb_rgd_in,bisb_rgd_ind,bisb_rgd_de,bisb_rgd_ded,bisb_rgd_ix,bisb_rgd_ixd,
+ bisb_rgd_rg,bisb_rgd_rgd,bisb_rgd_in,bisb_rgd_ind,bisb_rgd_de,bisb_rgd_ded,bisb_rgd_ix,bisb_rgd_ixd,
+ /* 0xd400 */
+ bisb_in_rg, bisb_in_rgd,bisb_in_in, bisb_in_ind,bisb_in_de, bisb_in_ded,bisb_in_ix, bisb_in_ixd,
+ bisb_in_rg, bisb_in_rgd,bisb_in_in, bisb_in_ind,bisb_in_de, bisb_in_ded,bisb_in_ix, bisb_in_ixd,
+ bisb_in_rg, bisb_in_rgd,bisb_in_in, bisb_in_ind,bisb_in_de, bisb_in_ded,bisb_in_ix, bisb_in_ixd,
+ bisb_in_rg, bisb_in_rgd,bisb_in_in, bisb_in_ind,bisb_in_de, bisb_in_ded,bisb_in_ix, bisb_in_ixd,
+ /* 0xd500 */
+ bisb_in_rg, bisb_in_rgd,bisb_in_in, bisb_in_ind,bisb_in_de, bisb_in_ded,bisb_in_ix, bisb_in_ixd,
+ bisb_in_rg, bisb_in_rgd,bisb_in_in, bisb_in_ind,bisb_in_de, bisb_in_ded,bisb_in_ix, bisb_in_ixd,
+ bisb_in_rg, bisb_in_rgd,bisb_in_in, bisb_in_ind,bisb_in_de, bisb_in_ded,bisb_in_ix, bisb_in_ixd,
+ bisb_in_rg, bisb_in_rgd,bisb_in_in, bisb_in_ind,bisb_in_de, bisb_in_ded,bisb_in_ix, bisb_in_ixd,
+ /* 0xd600 */
+ bisb_ind_rg,bisb_ind_rgd,bisb_ind_in,bisb_ind_ind,bisb_ind_de,bisb_ind_ded,bisb_ind_ix,bisb_ind_ixd,
+ bisb_ind_rg,bisb_ind_rgd,bisb_ind_in,bisb_ind_ind,bisb_ind_de,bisb_ind_ded,bisb_ind_ix,bisb_ind_ixd,
+ bisb_ind_rg,bisb_ind_rgd,bisb_ind_in,bisb_ind_ind,bisb_ind_de,bisb_ind_ded,bisb_ind_ix,bisb_ind_ixd,
+ bisb_ind_rg,bisb_ind_rgd,bisb_ind_in,bisb_ind_ind,bisb_ind_de,bisb_ind_ded,bisb_ind_ix,bisb_ind_ixd,
+ /* 0xd700 */
+ bisb_ind_rg,bisb_ind_rgd,bisb_ind_in,bisb_ind_ind,bisb_ind_de,bisb_ind_ded,bisb_ind_ix,bisb_ind_ixd,
+ bisb_ind_rg,bisb_ind_rgd,bisb_ind_in,bisb_ind_ind,bisb_ind_de,bisb_ind_ded,bisb_ind_ix,bisb_ind_ixd,
+ bisb_ind_rg,bisb_ind_rgd,bisb_ind_in,bisb_ind_ind,bisb_ind_de,bisb_ind_ded,bisb_ind_ix,bisb_ind_ixd,
+ bisb_ind_rg,bisb_ind_rgd,bisb_ind_in,bisb_ind_ind,bisb_ind_de,bisb_ind_ded,bisb_ind_ix,bisb_ind_ixd,
+ /* 0xd800 */
+ bisb_de_rg, bisb_de_rgd,bisb_de_in, bisb_de_ind,bisb_de_de, bisb_de_ded,bisb_de_ix, bisb_de_ixd,
+ bisb_de_rg, bisb_de_rgd,bisb_de_in, bisb_de_ind,bisb_de_de, bisb_de_ded,bisb_de_ix, bisb_de_ixd,
+ bisb_de_rg, bisb_de_rgd,bisb_de_in, bisb_de_ind,bisb_de_de, bisb_de_ded,bisb_de_ix, bisb_de_ixd,
+ bisb_de_rg, bisb_de_rgd,bisb_de_in, bisb_de_ind,bisb_de_de, bisb_de_ded,bisb_de_ix, bisb_de_ixd,
+ /* 0xd900 */
+ bisb_de_rg, bisb_de_rgd,bisb_de_in, bisb_de_ind,bisb_de_de, bisb_de_ded,bisb_de_ix, bisb_de_ixd,
+ bisb_de_rg, bisb_de_rgd,bisb_de_in, bisb_de_ind,bisb_de_de, bisb_de_ded,bisb_de_ix, bisb_de_ixd,
+ bisb_de_rg, bisb_de_rgd,bisb_de_in, bisb_de_ind,bisb_de_de, bisb_de_ded,bisb_de_ix, bisb_de_ixd,
+ bisb_de_rg, bisb_de_rgd,bisb_de_in, bisb_de_ind,bisb_de_de, bisb_de_ded,bisb_de_ix, bisb_de_ixd,
+ /* 0xda00 */
+ bisb_ded_rg,bisb_ded_rgd,bisb_ded_in,bisb_ded_ind,bisb_ded_de,bisb_ded_ded,bisb_ded_ix,bisb_ded_ixd,
+ bisb_ded_rg,bisb_ded_rgd,bisb_ded_in,bisb_ded_ind,bisb_ded_de,bisb_ded_ded,bisb_ded_ix,bisb_ded_ixd,
+ bisb_ded_rg,bisb_ded_rgd,bisb_ded_in,bisb_ded_ind,bisb_ded_de,bisb_ded_ded,bisb_ded_ix,bisb_ded_ixd,
+ bisb_ded_rg,bisb_ded_rgd,bisb_ded_in,bisb_ded_ind,bisb_ded_de,bisb_ded_ded,bisb_ded_ix,bisb_ded_ixd,
+ /* 0xdb00 */
+ bisb_ded_rg,bisb_ded_rgd,bisb_ded_in,bisb_ded_ind,bisb_ded_de,bisb_ded_ded,bisb_ded_ix,bisb_ded_ixd,
+ bisb_ded_rg,bisb_ded_rgd,bisb_ded_in,bisb_ded_ind,bisb_ded_de,bisb_ded_ded,bisb_ded_ix,bisb_ded_ixd,
+ bisb_ded_rg,bisb_ded_rgd,bisb_ded_in,bisb_ded_ind,bisb_ded_de,bisb_ded_ded,bisb_ded_ix,bisb_ded_ixd,
+ bisb_ded_rg,bisb_ded_rgd,bisb_ded_in,bisb_ded_ind,bisb_ded_de,bisb_ded_ded,bisb_ded_ix,bisb_ded_ixd,
+ /* 0xdc00 */
+ bisb_ix_rg, bisb_ix_rgd,bisb_ix_in, bisb_ix_ind,bisb_ix_de, bisb_ix_ded,bisb_ix_ix, bisb_ix_ixd,
+ bisb_ix_rg, bisb_ix_rgd,bisb_ix_in, bisb_ix_ind,bisb_ix_de, bisb_ix_ded,bisb_ix_ix, bisb_ix_ixd,
+ bisb_ix_rg, bisb_ix_rgd,bisb_ix_in, bisb_ix_ind,bisb_ix_de, bisb_ix_ded,bisb_ix_ix, bisb_ix_ixd,
+ bisb_ix_rg, bisb_ix_rgd,bisb_ix_in, bisb_ix_ind,bisb_ix_de, bisb_ix_ded,bisb_ix_ix, bisb_ix_ixd,
+ /* 0xdd00 */
+ bisb_ix_rg, bisb_ix_rgd,bisb_ix_in, bisb_ix_ind,bisb_ix_de, bisb_ix_ded,bisb_ix_ix, bisb_ix_ixd,
+ bisb_ix_rg, bisb_ix_rgd,bisb_ix_in, bisb_ix_ind,bisb_ix_de, bisb_ix_ded,bisb_ix_ix, bisb_ix_ixd,
+ bisb_ix_rg, bisb_ix_rgd,bisb_ix_in, bisb_ix_ind,bisb_ix_de, bisb_ix_ded,bisb_ix_ix, bisb_ix_ixd,
+ bisb_ix_rg, bisb_ix_rgd,bisb_ix_in, bisb_ix_ind,bisb_ix_de, bisb_ix_ded,bisb_ix_ix, bisb_ix_ixd,
+ /* 0xde00 */
+ bisb_ixd_rg,bisb_ixd_rgd,bisb_ixd_in,bisb_ixd_ind,bisb_ixd_de,bisb_ixd_ded,bisb_ixd_ix,bisb_ixd_ixd,
+ bisb_ixd_rg,bisb_ixd_rgd,bisb_ixd_in,bisb_ixd_ind,bisb_ixd_de,bisb_ixd_ded,bisb_ixd_ix,bisb_ixd_ixd,
+ bisb_ixd_rg,bisb_ixd_rgd,bisb_ixd_in,bisb_ixd_ind,bisb_ixd_de,bisb_ixd_ded,bisb_ixd_ix,bisb_ixd_ixd,
+ bisb_ixd_rg,bisb_ixd_rgd,bisb_ixd_in,bisb_ixd_ind,bisb_ixd_de,bisb_ixd_ded,bisb_ixd_ix,bisb_ixd_ixd,
+ /* 0xdf00 */
+ bisb_ixd_rg,bisb_ixd_rgd,bisb_ixd_in,bisb_ixd_ind,bisb_ixd_de,bisb_ixd_ded,bisb_ixd_ix,bisb_ixd_ixd,
+ bisb_ixd_rg,bisb_ixd_rgd,bisb_ixd_in,bisb_ixd_ind,bisb_ixd_de,bisb_ixd_ded,bisb_ixd_ix,bisb_ixd_ixd,
+ bisb_ixd_rg,bisb_ixd_rgd,bisb_ixd_in,bisb_ixd_ind,bisb_ixd_de,bisb_ixd_ded,bisb_ixd_ix,bisb_ixd_ixd,
+ bisb_ixd_rg,bisb_ixd_rgd,bisb_ixd_in,bisb_ixd_ind,bisb_ixd_de,bisb_ixd_ded,bisb_ixd_ix,bisb_ixd_ixd,
+
+ /* 0xe000 */
+ sub_rg_rg, sub_rg_rgd, sub_rg_in, sub_rg_ind, sub_rg_de, sub_rg_ded, sub_rg_ix, sub_rg_ixd,
+ sub_rg_rg, sub_rg_rgd, sub_rg_in, sub_rg_ind, sub_rg_de, sub_rg_ded, sub_rg_ix, sub_rg_ixd,
+ sub_rg_rg, sub_rg_rgd, sub_rg_in, sub_rg_ind, sub_rg_de, sub_rg_ded, sub_rg_ix, sub_rg_ixd,
+ sub_rg_rg, sub_rg_rgd, sub_rg_in, sub_rg_ind, sub_rg_de, sub_rg_ded, sub_rg_ix, sub_rg_ixd,
+ /* 0xe100 */
+ sub_rg_rg, sub_rg_rgd, sub_rg_in, sub_rg_ind, sub_rg_de, sub_rg_ded, sub_rg_ix, sub_rg_ixd,
+ sub_rg_rg, sub_rg_rgd, sub_rg_in, sub_rg_ind, sub_rg_de, sub_rg_ded, sub_rg_ix, sub_rg_ixd,
+ sub_rg_rg, sub_rg_rgd, sub_rg_in, sub_rg_ind, sub_rg_de, sub_rg_ded, sub_rg_ix, sub_rg_ixd,
+ sub_rg_rg, sub_rg_rgd, sub_rg_in, sub_rg_ind, sub_rg_de, sub_rg_ded, sub_rg_ix, sub_rg_ixd,
+ /* 0xe200 */
+ sub_rgd_rg, sub_rgd_rgd,sub_rgd_in, sub_rgd_ind,sub_rgd_de, sub_rgd_ded,sub_rgd_ix, sub_rgd_ixd,
+ sub_rgd_rg, sub_rgd_rgd,sub_rgd_in, sub_rgd_ind,sub_rgd_de, sub_rgd_ded,sub_rgd_ix, sub_rgd_ixd,
+ sub_rgd_rg, sub_rgd_rgd,sub_rgd_in, sub_rgd_ind,sub_rgd_de, sub_rgd_ded,sub_rgd_ix, sub_rgd_ixd,
+ sub_rgd_rg, sub_rgd_rgd,sub_rgd_in, sub_rgd_ind,sub_rgd_de, sub_rgd_ded,sub_rgd_ix, sub_rgd_ixd,
+ /* 0xe300 */
+ sub_rgd_rg, sub_rgd_rgd,sub_rgd_in, sub_rgd_ind,sub_rgd_de, sub_rgd_ded,sub_rgd_ix, sub_rgd_ixd,
+ sub_rgd_rg, sub_rgd_rgd,sub_rgd_in, sub_rgd_ind,sub_rgd_de, sub_rgd_ded,sub_rgd_ix, sub_rgd_ixd,
+ sub_rgd_rg, sub_rgd_rgd,sub_rgd_in, sub_rgd_ind,sub_rgd_de, sub_rgd_ded,sub_rgd_ix, sub_rgd_ixd,
+ sub_rgd_rg, sub_rgd_rgd,sub_rgd_in, sub_rgd_ind,sub_rgd_de, sub_rgd_ded,sub_rgd_ix, sub_rgd_ixd,
+ /* 0xe400 */
+ sub_in_rg, sub_in_rgd, sub_in_in, sub_in_ind, sub_in_de, sub_in_ded, sub_in_ix, sub_in_ixd,
+ sub_in_rg, sub_in_rgd, sub_in_in, sub_in_ind, sub_in_de, sub_in_ded, sub_in_ix, sub_in_ixd,
+ sub_in_rg, sub_in_rgd, sub_in_in, sub_in_ind, sub_in_de, sub_in_ded, sub_in_ix, sub_in_ixd,
+ sub_in_rg, sub_in_rgd, sub_in_in, sub_in_ind, sub_in_de, sub_in_ded, sub_in_ix, sub_in_ixd,
+ /* 0xe500 */
+ sub_in_rg, sub_in_rgd, sub_in_in, sub_in_ind, sub_in_de, sub_in_ded, sub_in_ix, sub_in_ixd,
+ sub_in_rg, sub_in_rgd, sub_in_in, sub_in_ind, sub_in_de, sub_in_ded, sub_in_ix, sub_in_ixd,
+ sub_in_rg, sub_in_rgd, sub_in_in, sub_in_ind, sub_in_de, sub_in_ded, sub_in_ix, sub_in_ixd,
+ sub_in_rg, sub_in_rgd, sub_in_in, sub_in_ind, sub_in_de, sub_in_ded, sub_in_ix, sub_in_ixd,
+ /* 0xe600 */
+ sub_ind_rg, sub_ind_rgd,sub_ind_in, sub_ind_ind,sub_ind_de, sub_ind_ded,sub_ind_ix, sub_ind_ixd,
+ sub_ind_rg, sub_ind_rgd,sub_ind_in, sub_ind_ind,sub_ind_de, sub_ind_ded,sub_ind_ix, sub_ind_ixd,
+ sub_ind_rg, sub_ind_rgd,sub_ind_in, sub_ind_ind,sub_ind_de, sub_ind_ded,sub_ind_ix, sub_ind_ixd,
+ sub_ind_rg, sub_ind_rgd,sub_ind_in, sub_ind_ind,sub_ind_de, sub_ind_ded,sub_ind_ix, sub_ind_ixd,
+ /* 0xe700 */
+ sub_ind_rg, sub_ind_rgd,sub_ind_in, sub_ind_ind,sub_ind_de, sub_ind_ded,sub_ind_ix, sub_ind_ixd,
+ sub_ind_rg, sub_ind_rgd,sub_ind_in, sub_ind_ind,sub_ind_de, sub_ind_ded,sub_ind_ix, sub_ind_ixd,
+ sub_ind_rg, sub_ind_rgd,sub_ind_in, sub_ind_ind,sub_ind_de, sub_ind_ded,sub_ind_ix, sub_ind_ixd,
+ sub_ind_rg, sub_ind_rgd,sub_ind_in, sub_ind_ind,sub_ind_de, sub_ind_ded,sub_ind_ix, sub_ind_ixd,
+ /* 0xe800 */
+ sub_de_rg, sub_de_rgd, sub_de_in, sub_de_ind, sub_de_de, sub_de_ded, sub_de_ix, sub_de_ixd,
+ sub_de_rg, sub_de_rgd, sub_de_in, sub_de_ind, sub_de_de, sub_de_ded, sub_de_ix, sub_de_ixd,
+ sub_de_rg, sub_de_rgd, sub_de_in, sub_de_ind, sub_de_de, sub_de_ded, sub_de_ix, sub_de_ixd,
+ sub_de_rg, sub_de_rgd, sub_de_in, sub_de_ind, sub_de_de, sub_de_ded, sub_de_ix, sub_de_ixd,
+ /* 0xe900 */
+ sub_de_rg, sub_de_rgd, sub_de_in, sub_de_ind, sub_de_de, sub_de_ded, sub_de_ix, sub_de_ixd,
+ sub_de_rg, sub_de_rgd, sub_de_in, sub_de_ind, sub_de_de, sub_de_ded, sub_de_ix, sub_de_ixd,
+ sub_de_rg, sub_de_rgd, sub_de_in, sub_de_ind, sub_de_de, sub_de_ded, sub_de_ix, sub_de_ixd,
+ sub_de_rg, sub_de_rgd, sub_de_in, sub_de_ind, sub_de_de, sub_de_ded, sub_de_ix, sub_de_ixd,
+ /* 0xea00 */
+ sub_ded_rg, sub_ded_rgd,sub_ded_in, sub_ded_ind,sub_ded_de, sub_ded_ded,sub_ded_ix, sub_ded_ixd,
+ sub_ded_rg, sub_ded_rgd,sub_ded_in, sub_ded_ind,sub_ded_de, sub_ded_ded,sub_ded_ix, sub_ded_ixd,
+ sub_ded_rg, sub_ded_rgd,sub_ded_in, sub_ded_ind,sub_ded_de, sub_ded_ded,sub_ded_ix, sub_ded_ixd,
+ sub_ded_rg, sub_ded_rgd,sub_ded_in, sub_ded_ind,sub_ded_de, sub_ded_ded,sub_ded_ix, sub_ded_ixd,
+ /* 0xeb00 */
+ sub_ded_rg, sub_ded_rgd,sub_ded_in, sub_ded_ind,sub_ded_de, sub_ded_ded,sub_ded_ix, sub_ded_ixd,
+ sub_ded_rg, sub_ded_rgd,sub_ded_in, sub_ded_ind,sub_ded_de, sub_ded_ded,sub_ded_ix, sub_ded_ixd,
+ sub_ded_rg, sub_ded_rgd,sub_ded_in, sub_ded_ind,sub_ded_de, sub_ded_ded,sub_ded_ix, sub_ded_ixd,
+ sub_ded_rg, sub_ded_rgd,sub_ded_in, sub_ded_ind,sub_ded_de, sub_ded_ded,sub_ded_ix, sub_ded_ixd,
+ /* 0xec00 */
+ sub_ix_rg, sub_ix_rgd, sub_ix_in, sub_ix_ind, sub_ix_de, sub_ix_ded, sub_ix_ix, sub_ix_ixd,
+ sub_ix_rg, sub_ix_rgd, sub_ix_in, sub_ix_ind, sub_ix_de, sub_ix_ded, sub_ix_ix, sub_ix_ixd,
+ sub_ix_rg, sub_ix_rgd, sub_ix_in, sub_ix_ind, sub_ix_de, sub_ix_ded, sub_ix_ix, sub_ix_ixd,
+ sub_ix_rg, sub_ix_rgd, sub_ix_in, sub_ix_ind, sub_ix_de, sub_ix_ded, sub_ix_ix, sub_ix_ixd,
+ /* 0xed00 */
+ sub_ix_rg, sub_ix_rgd, sub_ix_in, sub_ix_ind, sub_ix_de, sub_ix_ded, sub_ix_ix, sub_ix_ixd,
+ sub_ix_rg, sub_ix_rgd, sub_ix_in, sub_ix_ind, sub_ix_de, sub_ix_ded, sub_ix_ix, sub_ix_ixd,
+ sub_ix_rg, sub_ix_rgd, sub_ix_in, sub_ix_ind, sub_ix_de, sub_ix_ded, sub_ix_ix, sub_ix_ixd,
+ sub_ix_rg, sub_ix_rgd, sub_ix_in, sub_ix_ind, sub_ix_de, sub_ix_ded, sub_ix_ix, sub_ix_ixd,
+ /* 0xee00 */
+ sub_ixd_rg, sub_ixd_rgd,sub_ixd_in, sub_ixd_ind,sub_ixd_de, sub_ixd_ded,sub_ixd_ix, sub_ixd_ixd,
+ sub_ixd_rg, sub_ixd_rgd,sub_ixd_in, sub_ixd_ind,sub_ixd_de, sub_ixd_ded,sub_ixd_ix, sub_ixd_ixd,
+ sub_ixd_rg, sub_ixd_rgd,sub_ixd_in, sub_ixd_ind,sub_ixd_de, sub_ixd_ded,sub_ixd_ix, sub_ixd_ixd,
+ sub_ixd_rg, sub_ixd_rgd,sub_ixd_in, sub_ixd_ind,sub_ixd_de, sub_ixd_ded,sub_ixd_ix, sub_ixd_ixd,
+ /* 0xef00 */
+ sub_ixd_rg, sub_ixd_rgd,sub_ixd_in, sub_ixd_ind,sub_ixd_de, sub_ixd_ded,sub_ixd_ix, sub_ixd_ixd,
+ sub_ixd_rg, sub_ixd_rgd,sub_ixd_in, sub_ixd_ind,sub_ixd_de, sub_ixd_ded,sub_ixd_ix, sub_ixd_ixd,
+ sub_ixd_rg, sub_ixd_rgd,sub_ixd_in, sub_ixd_ind,sub_ixd_de, sub_ixd_ded,sub_ixd_ix, sub_ixd_ixd,
+ sub_ixd_rg, sub_ixd_rgd,sub_ixd_in, sub_ixd_ind,sub_ixd_de, sub_ixd_ded,sub_ixd_ix, sub_ixd_ixd,
+
+ /* 0xf000 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xf100 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xf200 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xf300 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xf400 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xf500 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xf600 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xf700 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xf800 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xf900 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xfa00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xfb00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xfc00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xfd00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xfe00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ /* 0xff00 */
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal
+};
diff --git a/src/emu/cpu/tlcs90/tlcs90.c b/src/emu/cpu/tlcs90/tlcs90.c
new file mode 100644
index 00000000000..7cce9e8fd89
--- /dev/null
+++ b/src/emu/cpu/tlcs90/tlcs90.c
@@ -0,0 +1,2875 @@
+/*************************************************************************************************************
+
+ Toshiba TLCS-90 Series MCU's
+
+ emulation by Luca Elia, based on the Z80 core by Juergen Buchmueller
+
+*************************************************************************************************************/
+
+#include "debugger.h"
+#include "tlcs90.h"
+
+typedef struct
+{
+ PAIR prvpc,pc,sp,af,bc,de,hl,ix,iy;
+ PAIR af2,bc2,de2,hl2;
+ UINT8 halt, after_EI;
+ UINT16 irq_state, irq_mask;
+ int (*irq_callback)(int irqline);
+ int extra_cycles; // extra cycles for interrupts
+ UINT8 internal_registers[48];
+ UINT32 ixbase,iybase;
+
+ // Timers: 4 x 8-bit + 1 x 16-bit
+ emu_timer *timer[4+1];
+ UINT8 timer_value[4];
+ UINT16 timer4_value;
+ attotime timer_period;
+
+} t90_Regs;
+
+static t90_Regs T90;
+
+enum {
+ T90_B, T90_C, T90_D, T90_E, T90_H, T90_L, T90_A,
+ T90_BC, T90_DE, T90_HL, T90_XX, T90_IX, T90_IY, T90_SP,
+ T90_AF, T90_PC
+};
+
+static int t90_ICount;
+
+// Regs
+
+#define B 0
+#define C 1
+#define D 2
+#define E 3
+#define H 4
+#define L 5
+#define A 6
+
+#define BC 0
+#define DE 1
+#define HL 2
+// 3
+#define IX 4
+#define IY 5
+#define SP 6
+
+#define AF 7
+#define AF2 8
+#define PC 9
+
+typedef UINT16 e_r;
+#define F T90.af.b.l
+
+static const char *r8_names[] = { "b", "c", "d", "e", "h", "l", "a" };
+static const char *r16_names[] = { "bc", "de", "hl", "??", "ix", "iy", "sp", "af", "af'", "pc" };
+
+// Condition Codes
+
+#define FLS 0x0
+#define LT 0x1
+#define LE 0x2
+#define ULE 0x3
+#define OV 0x4
+#define PE 0x4
+#define MI 0x5
+#define Z 0x6
+#define EQ 0x6
+#define CR 0x7
+#define ULT 0x7
+#define T 0x8
+#define GE 0x9
+#define GT 0xa
+#define UGT 0xb
+#define NOV 0xc
+#define PO 0xc
+#define PL 0xd
+#define NZ 0xe
+#define NE 0xe
+#define NC 0xf
+#define UGE 0xf
+
+#define CF 0x01
+#define NF 0x02
+#define PF 0x04
+#define VF PF
+#define XCF 0x08
+#define HF 0x10
+#define IF 0x20
+#define ZF 0x40
+#define SF 0x80
+
+static UINT8 SZ[256]; /* zero and sign flags */
+static UINT8 SZ_BIT[256]; /* zero, sign and parity/overflow (=zero) flags for BIT opcode */
+static UINT8 SZP[256]; /* zero, sign and parity flags */
+static UINT8 SZHV_inc[256]; /* zero, sign, half carry and overflow flags INC r8 */
+static UINT8 SZHV_dec[256]; /* zero, sign, half carry and overflow flags DEC r8 */
+
+static const char *cc_names[] = { "f", "lt", "le", "ule", "ov", "mi", "z", "c", "", "ge", "gt", "ugt", "nov", "pl", "nz", "nc" };
+
+// Opcodes
+
+#define OP_16 0x80
+typedef enum { UNKNOWN, NOP, EX, EXX, LD, LDW, LDA, LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR, PUSH, POP, JP, JR, CALL, CALLR, RET, RETI, HALT, DI, EI, SWI, DAA, CPL, NEG, LDAR, RCF, SCF, CCF, TSET, BIT, SET, RES, INC, DEC, INCX, DECX, INCW, DECW, ADD, ADC, SUB, SBC, AND, XOR, OR, CP, RLC, RRC, RL, RR, SLA, SRA, SLL, SRL, RLD, RRD, DJNZ, MUL, DIV } e_op;
+static const char *op_names[] = { "??", "nop", "ex", "exx", "ld", "ldw", "lda", "ldi", "ldir", "ldd", "lddr", "cpi", "cpir", "cpd", "cpdr", "push", "pop", "jp", "jr", "call", "callr", "ret", "reti", "halt", "di", "ei", "swi", "daa", "cpl", "neg", "ldar", "rcf", "scf", "ccf", "tset", "bit", "set", "res", "inc", "dec", "incx", "decx", "incw", "decw", "add", "adc", "sub", "sbc", "and", "xor", "or", "cp", "rlc", "rrc", "rl", "rr", "sla", "sra", "sll", "srl", "rld", "rrd", "djnz", "mul", "div" };
+
+typedef enum {
+ MODE_NONE, MODE_BIT8, MODE_CC,
+ MODE_I8, MODE_D8, MODE_R8,
+ MODE_I16, MODE_D16, MODE_R16,
+ MODE_MI16, MODE_MR16, MODE_MR16D8, MODE_MR16R8,
+ MODE_R16D8, MODE_R16R8
+} e_mode;
+
+static e_op op;
+
+static e_mode mode1;
+static e_r r1,r1b;
+
+static e_mode mode2;
+static e_r r2,r2b;
+
+static int cyc_t,cyc_f;
+
+static UINT32 addr;
+
+#define OP( X,CT ) op = X; cyc_t = (CT*2);
+#define OP16( X,CT ) OP( (X)|OP_16,CT )
+
+#define OPCC( X,CF,CT ) OP( X, CT ) cyc_f = (CF*2);
+#define OPCC16( X,CF,CT ) OPCC( (X)|OP_16,CF,CT )
+
+#define BIT8( N,I ) mode##N = MODE_BIT8; r##N = I;
+#define I8( N,I ) mode##N = MODE_I8; r##N = I;
+#define D8( N,I ) mode##N = MODE_D8; r##N = I;
+#define I16( N,I ) mode##N = MODE_I16; r##N = I;
+#define D16( N,I ) mode##N = MODE_D16; r##N = I;
+#define R8( N,R ) mode##N = MODE_R8; r##N = R;
+#define R16( N,R ) mode##N = MODE_R16; r##N = R;
+#define Q16( N,R ) mode##N = MODE_R16; r##N = R; if (r##N == SP) r##N = AF;
+#define MI16( N,I ) mode##N = MODE_MI16; r##N = I;
+#define MR16( N,R ) mode##N = MODE_MR16; r##N = R;
+#define MR16D8( N,R,I ) mode##N = MODE_MR16D8; r##N = R; r##N##b = I;
+#define MR16R8( N,R,g ) mode##N = MODE_MR16R8; r##N = R; r##N##b = g;
+#define NONE( N ) mode##N = MODE_NONE;
+#define CC( N,cc ) mode##N = MODE_CC; r##N = cc;
+#define R16D8( N,R,I ) mode##N = MODE_R16D8; r##N = R; r##N##b = I;
+#define R16R8( N,R,g ) mode##N = MODE_R16R8; r##N = R; r##N##b = g;
+
+INLINE UINT8 RM8 (UINT32 a) { return program_read_byte_8( a ); }
+INLINE UINT16 RM16(UINT32 a) { return RM8(a) | (RM8( (a+1) & 0xffff ) << 8); }
+
+INLINE void WM8 (UINT32 a, UINT8 v) { program_write_byte_8( a, v ); }
+INLINE void WM16(UINT32 a, UINT16 v) { WM8(a,v); WM8( (a+1) & 0xffff, v >> 8); }
+
+INLINE UINT8 RX8 (UINT32 a, UINT32 base) { return program_read_byte_8( base | a ); }
+INLINE UINT16 RX16(UINT32 a, UINT32 base) { return RX8(a,base) | (RX8( (a+1) & 0xffff, base ) << 8); }
+
+INLINE void WX8 (UINT32 a, UINT8 v, UINT32 base) { program_write_byte_8( base | a, v ); }
+INLINE void WX16(UINT32 a, UINT16 v, UINT32 base) { WX8(a,v,base); WX8( (a+1) & 0xffff, v >> 8, base); }
+
+INLINE UINT8 READ8(void) { UINT8 b0 = RM8( addr++ ); addr &= 0xffff; return b0; }
+INLINE UINT16 READ16(void) { UINT8 b0 = READ8(); return b0 | (READ8() << 8); }
+
+static void decode(void)
+{
+ UINT8 b0, b1, b2, b3;
+ UINT16 imm16;
+
+ b0 = READ8();
+
+ switch ( b0 )
+ {
+ case 0x00:
+ OP( NOP,2 ) NONE( 1 ) NONE( 2 ) return; // NOP
+
+ case 0x01:
+ OP( HALT,4 ) NONE( 1 ) NONE( 2 ) return; // HALT
+ case 0x02:
+ OP( DI,2 ) NONE( 1 ) NONE( 2 ) return; // DI
+ case 0x03:
+ OP( EI,2 ) NONE( 1 ) NONE( 2 ) return; // EI
+
+ case 0x07:
+ OPCC( INCX,6,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // INCX ($FF00+n)
+
+ case 0x08:
+ OP( EX,2 ) R16( 1, DE ) R16( 2, HL ) return; // EX DE,HL
+ case 0x09:
+ OP( EX,2 ) R16( 1, AF ) R16( 2, AF2 ) return; // EX AF,AF'
+ case 0x0a:
+ OP( EXX,2 ) NONE( 1 ) NONE( 2 ) return; // EXX
+
+ case 0x0b:
+ OP( DAA,4 ) R8( 1, A ) NONE( 2 ) return; // DAA A
+
+ case 0x0c:
+ OP( RCF,2 ) NONE( 1 ) NONE( 2 ) return; // RCF
+ case 0x0d:
+ OP( SCF,2 ) NONE( 1 ) NONE( 2 ) return; // SCF
+ case 0x0e:
+ OP( CCF,2 ) NONE( 1 ) NONE( 2 ) return; // CCF
+
+ case 0x0f:
+ OPCC( DECX,6,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // DECX ($FF00+n)
+
+ case 0x10:
+ OP( CPL,2 ) R8( 1, A ) NONE( 2 ) return; // CPL A
+ case 0x11:
+ OP( NEG,2 ) R8( 1, A ) NONE( 2 ) return; // NEG A
+
+ case 0x12: // MUL HL,n
+ case 0x13: // DIV HL,n
+ OP( MUL+b0-0x12,16) R16( 1, HL ) I8( 2, READ8() ) return;
+
+ case 0x14: case 0x15: case 0x16:
+ OP16( ADD,6 ) R16( 1, IX+b0-0x14 ) I16( 2, READ16() ) return; // ADD ix,mn
+
+ case 0x17:
+ OP( LDAR,8 ) R16( 1, HL ) D16( 2, READ16() ) return; // LDAR HL,+cd
+
+ case 0x18:
+ OP( DJNZ,10 ) D8( 1, READ8() ) NONE( 2 ) return; // DJNZ +d
+ case 0x19:
+ OP16( DJNZ,10 ) R16( 1, BC ) D8( 2, READ8() ) return; // DJNZ BC,+d
+
+ case 0x1a:
+ OPCC( JP,8,8 ) CC( 1, T ) I16( 2, READ16() ) return; // JP T,mn
+ case 0x1b:
+ OPCC16( JR,10,10 ) CC( 1, T ) D16( 2, READ16() ) return; // JR T,+cd
+
+ case 0x1c:
+ OPCC( CALL,14,14 ) CC( 1, T ) I16( 2, READ16() ) return; // CALL T,mn
+ case 0x1d:
+ OP( CALLR,16 ) D16( 1, READ16() ) NONE( 2 ) return; // CALLR +cd
+
+ case 0x1e:
+ OPCC( RET,10,10 ) CC( 1, T ) NONE( 2 ) return; // RET T
+ case 0x1f:
+ OP( RETI,14 ) NONE( 1 ) NONE( 2 ) return; // RETI
+
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26:
+ OP( LD,2 ) R8( 1, A ) R8( 2, b0 - 0x20 ) return; // LD A,r
+
+ case 0x27:
+ OP( LD,8 ) R8( 1, A ) MI16( 2, 0xFF00|READ8() ) return; // LD A,($FF00+n)
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e:
+ OP( LD,2 ) R8( 1, b0 - 0x28 ) R8( 2, A ) return; // LD r,A
+
+ case 0x2f:
+ OP( LD,8 ) MI16( 1, 0xFF00|READ8() ) R8( 2, A ) return; // LD ($FF00+n), A
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36:
+ OP( LD,4 ) R8( 1, b0 - 0x30 ) I8( 2, READ8() ) return; // LD r,n
+
+ case 0x37:
+ OP( LD,10 ) MI16( 1, 0xFF00|READ8() ) I8( 2, READ8() ) return; // LD ($FF00+w),n
+
+ case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e:
+ OP16( LD,6 ) R16( 1, b0 - 0x38 ) I16( 2, READ16() ) return; // LD rr,nn
+
+ case 0x3f:
+ OP( LDW,14 ) MI16( 1, 0xFF00|READ8() ) I16( 2, READ16() ) return; // LDW ($FF00+w),mn
+
+ case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46:
+ OP16( LD,4 ) R16( 1, HL ) R16( 2, b0 - 0x40 ) return; // LD HL,rr
+
+ case 0x47:
+ OP16( LD,10 ) R16( 1, HL ) MI16( 2, 0xFF00|READ8() ) return; // LD HL,($FF00+n)
+
+ case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e:
+ OP16( LD,4 ) R16( 1, b0 - 0x48 ) R16( 2, HL ) return; // LD rr,HL
+
+ case 0x4f:
+ OP16( LD,10 ) MI16( 1, 0xFF00|READ8() ) R16( 2, HL ) return; // LD ($FF00+n), HL
+
+ case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56:
+ OP( PUSH,8 ) Q16( 1, b0 - 0x50 ) NONE( 2 ) return; // PUSH qq
+ case 0x58: case 0x59: case 0x5a: /*case 0x5b:*/ case 0x5c: case 0x5d: case 0x5e:
+ OP( POP,10 ) Q16( 1, b0 - 0x58 ) NONE( 2 ) return; // POP qq
+
+ case 0x60: // ADD A,($FF00+n)
+ case 0x61: // ADC A,($FF00+n)
+ case 0x62: // SUB A,($FF00+n)
+ case 0x63: // SBC A,($FF00+n)
+ case 0x64: // AND A,($FF00+n)
+ case 0x65: // XOR A,($FF00+n)
+ case 0x66: // OR A,($FF00+n)
+ case 0x67: // CP A,($FF00+n)
+ OP( ADD+b0-0x60,8 ) R8( 1, A ) MI16( 2, 0xFF00|READ8() ) return;
+
+ case 0x68: // ADD A,n
+ case 0x69: // ADC A,n
+ case 0x6a: // SUB A,n
+ case 0x6b: // SBC A,n
+ case 0x6c: // AND A,n
+ case 0x6d: // XOR A,n
+ case 0x6e: // OR A,n
+ case 0x6f: // CP A,n
+ OP( ADD+b0-0x68,4 ) R8( 1, A ) I8( 2, READ8() ) return;
+
+ case 0x70: // ADD HL,($FF00+n)
+ case 0x71: // ADC HL,($FF00+n)
+ case 0x72: // SUB HL,($FF00+n)
+ case 0x73: // SBC HL,($FF00+n)
+ case 0x74: // AND HL,($FF00+n)
+ case 0x75: // XOR HL,($FF00+n)
+ case 0x76: // OR HL,($FF00+n)
+ case 0x77: // CP HL,($FF00+n)
+ OP16( ADD+b0-0x70,10 ) R16( 1, HL ) MI16( 2, 0xFF00|READ8() ) return;
+
+ case 0x78: // ADD HL,mn
+ case 0x79: // ADC HL,mn
+ case 0x7a: // SUB HL,mn
+ case 0x7b: // SBC HL,mn
+ case 0x7c: // AND HL,mn
+ case 0x7d: // XOR HL,mn
+ case 0x7e: // OR HL,mn
+ case 0x7f: // CP HL,mn
+ OP16( ADD+b0-0x78,6 ) R16( 1, HL ) I16( 2, READ16() ) return;
+
+ case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86:
+ OP( INC,2 ) R8( 1, b0 - 0x80 ) NONE( 2 ) return; // INC r
+ case 0x87:
+ OP( INC,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // INC ($FF00+n)
+
+ case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e:
+ OP( DEC,2 ) R8( 1, b0 - 0x88 ) NONE( 2 ) return; // DEC r
+ case 0x8f:
+ OP( DEC,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // DEC ($FF00+n)
+
+ case 0x90: case 0x91: case 0x92: /*case 0x93:*/ case 0x94: case 0x95: case 0x96:
+ OP16( INC,4 ) R16( 1, b0 - 0x90 ) NONE( 2 ) return; // INC rr
+ case 0x97:
+ OP( INCW,14 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // INCW ($FF00+n)
+ case 0x98: case 0x99: case 0x9a: /*case 0x9b:*/ case 0x9c: case 0x9d: case 0x9e:
+ OP16( DEC,4 ) R16( 1, b0 - 0x98 ) NONE( 2 ) return; // DEC rr
+ case 0x9f:
+ OP( DECW,14 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // DECW ($FF00+n)
+
+ case 0xa0: // RLC A
+ case 0xa1: // RRC A
+ case 0xa2: // RL A
+ case 0xa3: // RR A
+ case 0xa4: // SLA A
+ case 0xa5: // SRA A
+ case 0xa6: // SLL A
+ case 0xa7: // SRL A
+ OP( RLC+b0-0xa0,2 ) R8( 1, A ) NONE( 2 ) return;
+
+ case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ OP( BIT,8 ) BIT8( 1, b0 - 0xa8 ) MI16( 2, 0xFF00|READ8() ) return; // BIT b,($FF00+n)
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ OP( RES,12 ) BIT8( 1, b0 - 0xb0 ) MI16( 2, 0xFF00|READ8() ) return; // RES b,($FF00+n)
+ case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ OP( SET,12 ) BIT8( 1, b0 - 0xb8 ) MI16( 2, 0xFF00|READ8() ) return; // SET b,($FF00+n)
+
+ case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
+ case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ OPCC( JR,4,8 ) CC( 1, b0 - 0xc0 ) D8( 2, READ8() ) return; // JR cc,+d
+
+ case 0xe0: case 0xe1: case 0xe2: /*case 0xe3:*/ case 0xe4: case 0xe5: case 0xe6:
+ b1 = READ8();
+ switch ( b1 ) {
+ case 0x10: // RLD (gg)
+ case 0x11: // RRD (gg)
+ OP( RLD+b1-0x10,12 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return;
+
+ case 0x12: // MUL HL,(gg)
+ case 0x13: // DIV HL,(gg)
+ OP( MUL+b1-0x12,18 ) R16( 1, HL ) MR16( 2, b0 - 0xe0 ) return;
+
+ case 0x14: case 0x15: case 0x16:
+ OP16( ADD,8 ) R16( 1, IX+b1-0x14 ) MR16( 2, b0 - 0xe0 ) return; // ADD ix,(gg)
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e:
+ OP( LD,6 ) R8( 1, b1 - 0x28 ) MR16( 2, b0 - 0xe0 ) return; // LD r,(gg)
+ case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e:
+ OP16( LD,8 ) R16( 1, b1 - 0x48 ) MR16( 2, b0 - 0xe0 ) return; // LD rr,(gg)
+
+ case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56:
+ OP( EX,14 ) MR16( 1, b0 - 0xe0 ) R16( 2, b1 - 0x50 ) return; // EX (gg),rr
+
+ case 0x60: // ADD A,(gg)
+ case 0x61: // ADC A,(gg)
+ case 0x62: // SUB A,(gg)
+ case 0x63: // SBC A,(gg)
+ case 0x64: // AND A,(gg)
+ case 0x65: // XOR A,(gg)
+ case 0x66: // OR A,(gg)
+ case 0x67: // CP A,(gg)
+ OP( ADD+b1-0x60,6 ) R8( 1, A ) MR16( 2, b0 - 0xe0 ) return;
+
+ case 0x70: // ADD HL,(gg)
+ case 0x71: // ADC HL,(gg)
+ case 0x72: // SUB HL,(gg)
+ case 0x73: // SBC HL,(gg)
+ case 0x74: // AND HL,(gg)
+ case 0x75: // XOR HL,(gg)
+ case 0x76: // OR HL,(gg)
+ case 0x77: // CP HL,(gg)
+ OP16( ADD+b1-0x70,8 ) R16( 1, HL ) MR16( 2, b0 - 0xe0 ) return;
+
+ case 0x87:
+ OP( INC,8 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // INC (gg)
+ case 0x8f:
+ OP( DEC,8 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // DEC (gg)
+
+ case 0x97:
+ OP( INCW,12 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // INCW (gg)
+ case 0x9f:
+ OP( DECW,12 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // DECW (gg)
+
+ case 0xa0: // RLC (gg)
+ case 0xa1: // RRC (gg)
+ case 0xa2: // RL (gg)
+ case 0xa3: // RR (gg)
+ case 0xa4: // SLA (gg)
+ case 0xa5: // SRA (gg)
+ case 0xa6: // SLL (gg)
+ case 0xa7: // SRL (gg)
+ OP( RLC+b1-0xa0,8 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ OP( TSET,12 ) BIT8( 1, b1 - 0x18 ) MR16( 2, b0 - 0xe0 ) return; // TSET b,(gg)
+ case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ OP( BIT,6 ) BIT8( 1, b1 - 0xa8 ) MR16( 2, b0 - 0xe0 ) return; // BIT b,(gg)
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ OP( RES,10 ) BIT8( 1, b1 - 0xb0 ) MR16( 2, b0 - 0xe0 ) return; // RES b,(gg)
+ case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ OP( SET,10 ) BIT8( 1, b1 - 0xb8 ) MR16( 2, b0 - 0xe0 ) return; // SET b,(gg)
+ } break;
+ case 0xe3:
+ imm16 = READ16();
+ b3 = READ8();
+ switch ( b3 ) {
+ case 0x10: // RLD (mn)
+ case 0x11: // RRD (mn)
+ OP( RLD+b3-0x10,16 ) MI16( 1, imm16 ) NONE( 2 ) return;
+
+ case 0x12: // MUL HL,(mn)
+ case 0x13: // DIV HL,(mn)
+ OP( MUL+b3-0x12,22 ) R16( 1, HL ) MI16( 2, imm16 ) return;
+
+ case 0x14: case 0x15: case 0x16:
+ OP16( ADD,12 ) R16( 1, IX+b3-0x14 ) MI16( 2, imm16 ) return; // ADD ix,(mn)
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e:
+ OP( LD,10 ) R8( 1, b3 - 0x28 ) MI16( 2, imm16 ) return; // LD r,(mn)
+ case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e:
+ OP16( LD,12 ) R16( 1, b3 - 0x48 ) MI16( 2, imm16 ) return; // LD rr,(mn)
+
+ case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56:
+ OP( EX,18 ) MI16( 1, imm16 ) R16( 2, b3 - 0x50 ) return; // EX (mn),rr
+
+ case 0x60: // ADD A,(mn)
+ case 0x61: // ADC A,(mn)
+ case 0x62: // SUB A,(mn)
+ case 0x63: // SBC A,(mn)
+ case 0x64: // AND A,(mn)
+ case 0x65: // XOR A,(mn)
+ case 0x66: // OR A,(mn)
+ case 0x67: // CP A,(mn)
+ OP( ADD+b3-0x60,10 ) R8( 1, A ) MI16( 2, imm16 ) return;
+
+ case 0x70: // ADD HL,(mn)
+ case 0x71: // ADC HL,(mn)
+ case 0x72: // SUB HL,(mn)
+ case 0x73: // SBC HL,(mn)
+ case 0x74: // AND HL,(mn)
+ case 0x75: // XOR HL,(mn)
+ case 0x76: // OR HL,(mn)
+ case 0x77: // CP HL,(mn)
+ OP16( ADD+b3-0x70,12 ) R16( 1, HL ) MI16( 2, imm16 ) return;
+
+ case 0x87:
+ OP( INC,12 ) MI16( 1, imm16 ) NONE( 2 ) return; // INC (mn)
+ case 0x8f:
+ OP( DEC,12 ) MI16( 1, imm16 ) NONE( 2 ) return; // DEC (mn)
+
+ case 0x97:
+ OP( INCW,16 ) MI16( 1, imm16 ) NONE( 2 ) return; // INCW (mn)
+ case 0x9f:
+ OP( DECW,16 ) MI16( 1, imm16 ) NONE( 2 ) return; // DECW (mn)
+
+ case 0xa0: // RLC (mn)
+ case 0xa1: // RRC (mn)
+ case 0xa2: // RL (mn)
+ case 0xa3: // RR (mn)
+ case 0xa4: // SLA (mn)
+ case 0xa5: // SRA (mn)
+ case 0xa6: // SLL (mn)
+ case 0xa7: // SRL (mn)
+ OP( RLC+b3-0xa0,12 ) MI16( 1, imm16 ) NONE( 2 ) return;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ OP( TSET,16 ) BIT8( 1, b3 - 0x18 ) MI16( 2, imm16 ) return; // TSET b,(mn)
+ case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ OP( BIT,10 ) BIT8( 1, b3 - 0xa8 ) MI16( 2, imm16 ) return; // BIT b,(mn)
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ OP( RES,14 ) BIT8( 1, b3 - 0xb0 ) MI16( 2, imm16 ) return; // RES b,(mn)
+ case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ OP( SET,14 ) BIT8( 1, b3 - 0xb8 ) MI16( 2, imm16 ) return; // SET b,(mn)
+ } break;
+
+ case 0xe7:
+ b1 = READ8();
+ b2 = READ8();
+ switch ( b2 ) {
+ case 0x10: // RLD ($FF00+n)
+ case 0x11: // RRD ($FF00+n)
+ OP( RLD+b2-0x10,14 ) MI16( 1, 0xFF00|b1 ) NONE( 2 ) return;
+
+ case 0x12: // MUL HL,($FF00+n)
+ case 0x13: // DIV HL,($FF00+n)
+ OP( MUL+b2-0x12,20 ) R16( 1, HL ) MI16( 2, 0xFF00|b1 ) return;
+
+ case 0x14: case 0x15: case 0x16:
+ OP16( ADD,10 ) R16( 1, IX+b2-0x14 ) MI16( 2, 0xFF00|b1 ) return; // ADD ix,($FF00+n)
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ OP( TSET,14 ) BIT8( 1, b2 - 0x18 ) MI16( 2, 0xFF00|b1 ) return; // TSET b,($FF00+n)
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e:
+ OP( LD,8 ) R8( 1, b2 - 0x28 ) MI16( 2, 0xFF00|b1 ) return; // LD r,($FF00+n)
+ case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e:
+ OP16( LD,10 ) R16( 1, b2 - 0x48 ) MI16( 2, 0xFF00|b1 ) return; // LD rr,($FF00+n)
+
+ case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56:
+ OP( EX,16 ) MI16( 1, 0xFF00|b1 ) R16( 2, b2 - 0x50 ) return; // EX ($FF00+n),rr
+
+ case 0xa0: // RLC ($FF00+n)
+ case 0xa1: // RRC ($FF00+n)
+ case 0xa2: // RL ($FF00+n)
+ case 0xa3: // RR ($FF00+n)
+ case 0xa4: // SLA ($FF00+n)
+ case 0xa5: // SRA ($FF00+n)
+ case 0xa6: // SLL ($FF00+n)
+ case 0xa7: // SRL ($FF00+n)
+ OP( RLC+b2-0xa0,10 ) MI16( 1, 0xFF00|b1 ) NONE( 2 ) return;
+ } break;
+
+ case 0xe8: case 0xe9: case 0xea: /*case 0xeb:*/ case 0xec: case 0xed: case 0xee:
+ b1 = READ8();
+ switch ( b1 ) {
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26:
+ OP( LD,6 ) MR16( 1, b0 - 0xe8 ) R8( 2, b1 - 0x20 ) return; // LD (gg),r
+ case 0x37:
+ OP( LD,8 ) MR16( 1, b0 - 0xe8 ) I8( 2, READ8() ) return; // LD (gg),n
+ case 0x3f:
+ OP( LDW,12 ) MR16( 1, b0 - 0xe8 ) I16( 2, READ16() ) return; // LDW (gg),mn
+ case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46:
+ OP16( LD,8 ) MR16( 1, b0 - 0xe8 ) R16( 2, b1 - 0x40 ) return; // LD (gg),rr
+
+ case 0x68: // ADD (gg),n
+ case 0x69: // ADC (gg),n
+ case 0x6a: // SUB (gg),n
+ case 0x6b: // SBC (gg),n
+ case 0x6c: // AND (gg),n
+ case 0x6d: // XOR (gg),n
+ case 0x6e: // OR (gg),n
+ OP( ADD+b1-0x68,10 ) MR16( 1, b0 - 0xe8 ) I8( 2, READ8() ) return;
+ case 0x6f: // CP (gg),n
+ OP( CP,8 ) MR16( 1, b0 - 0xe8 ) I8( 2, READ8() ) return;
+
+ case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
+ case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ OPCC( JP,6,8 ) CC( 1, b1 - 0xc0 ) R16( 2, b0 - 0xe8 ) return; // JP [cc,]gg
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+ case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ OPCC( CALL,6,14 ) CC( 1, b1 - 0xd0 ) R16( 2, b0 - 0xe8 ) return; // CALL [cc,]gg
+ } break;
+ case 0xeb:
+ imm16 = READ16();
+ b3 = READ8();
+ switch ( b3 ) {
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26:
+ OP( LD,10 ) MI16( 1, imm16 ) R8( 2, b3 - 0x20 ) return; // LD (mn),r
+ case 0x37:
+ OP( LD,12 ) MI16( 1, imm16 ) I8( 2, READ8() ) return; // LD (vw),n
+ case 0x3f:
+ OP( LDW,16 ) MI16( 1, imm16 ) I16( 2, READ16() ) return; // LDW (vw),mn
+ case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46:
+ OP16( LD,12 ) MI16( 1, imm16 ) R16( 2, b3 - 0x40 ) return; // LD (mn),rr
+
+ case 0x68: // ADD (vw),n
+ case 0x69: // ADC (vw),n
+ case 0x6a: // SUB (vw),n
+ case 0x6b: // SBC (vw),n
+ case 0x6c: // AND (vw),n
+ case 0x6d: // XOR (vw),n
+ case 0x6e: // OR (vw),n
+ OP( ADD+b3-0x68,14 ) MI16( 1, imm16 ) I8( 2, READ8() ) return;
+ case 0x6f: // CP (vw),n
+ OP( ADD+b3-0x68,12 ) MI16( 1, imm16 ) I8( 2, READ8() ) return;
+
+ case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
+ case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ OPCC( JP,10,12 ) CC( 1, b3 - 0xc0 ) I16( 2, imm16 ) return; // JP cc,mn
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+ case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ OPCC( CALL,10,18 ) CC( 1, b3 - 0xd0 ) I16( 2, imm16 ) return; // CALL cc,mn
+ } break;
+
+ case 0xef:
+ b1 = READ8();
+ b2 = READ8();
+ switch ( b2 ) {
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26:
+ OP( LD,8 ) MI16( 1, 0xFF00|b1 ) R8( 2, b2 - 0x20 ) return; // LD ($FF00+n),r
+ case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46:
+ OP16( LD,10 ) MI16( 1, 0xFF00|b1 ) R16( 2, b2 - 0x40 ) return; // LD ($FF00+n),rr
+
+ case 0x68: // ADD ($FF00+w),n
+ case 0x69: // ADC ($FF00+w),n
+ case 0x6a: // SUB ($FF00+w),n
+ case 0x6b: // SBC ($FF00+w),n
+ case 0x6c: // AND ($FF00+w),n
+ case 0x6d: // XOR ($FF00+w),n
+ case 0x6e: // OR ($FF00+w),n
+ OP( ADD+b2-0x68,12 ) MI16( 1, 0xFF00|b1 ) I8( 2, READ8() ) return;
+ case 0x6f: // CP ($FF00+w),n
+ OP( ADD+b2-0x68,10 ) MI16( 1, 0xFF00|b1 ) I8( 2, READ8() ) return;
+ } break;
+
+ case 0xf0: case 0xf1: case 0xf2:
+ b1 = READ8();
+ b2 = READ8();
+ switch ( b2 ) {
+ case 0x10: // RLD (ix+d)
+ case 0x11: // RRD (ix+d)
+ OP( RLD+b2-0x10,16 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return;
+
+ case 0x12: // MUL HL,(ix+d)
+ case 0x13: // DIV HL,(ix+d)
+ OP( MUL+b2-0x12,22 ) R16( 1, HL ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return;
+
+ case 0x14: case 0x15: case 0x16:
+ OP16( ADD,12 ) R16( 1, IX+b2-0x14 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // ADD ix,(jx+d)
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e:
+ OP( LD,10 ) R8( 1, b2 - 0x28 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // LD r,(ix+d)
+ case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e:
+ OP16( LD,12 ) R16( 1, b2 - 0x48 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // LD rr,(ix+d)
+
+ case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56:
+ OP( EX,18 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) R16( 2, b2 - 0x50 ) return; // EX (ix+d),rr
+
+ case 0x60: // ADD A,(ix+d)
+ case 0x61: // ADC A,(ix+d)
+ case 0x62: // SUB A,(ix+d)
+ case 0x63: // SBC A,(ix+d)
+ case 0x64: // AND A,(ix+d)
+ case 0x65: // XOR A,(ix+d)
+ case 0x66: // OR A,(ix+d)
+ case 0x67: // CP A,(ix+d)
+ OP( ADD+b2-0x60,10 ) R8( 1, A ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return;
+
+ case 0x70: // ADD HL,(ix+d)
+ case 0x71: // ADC HL,(ix+d)
+ case 0x72: // SUB HL,(ix+d)
+ case 0x73: // SBC HL,(ix+d)
+ case 0x74: // AND HL,(ix+d)
+ case 0x75: // XOR HL,(ix+d)
+ case 0x76: // OR HL,(ix+d)
+ case 0x77: // CP HL,(ix+d)
+ OP16( ADD+b2-0x70,12 ) R16( 1, HL ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return;
+
+ case 0x87:
+ OP( INC,12 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // INC (ix+d)
+ case 0x8f:
+ OP( DEC,12 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // DEC (ix+d)
+
+ case 0x97:
+ OP( INCW,16 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // INCW (ix+d)
+ case 0x9f:
+ OP( DECW,16 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // DECW (ix+d)
+
+ case 0xa0: // RLC (ix+d)
+ case 0xa1: // RRC (ix+d)
+ case 0xa2: // RL (ix+d)
+ case 0xa3: // RR (ix+d)
+ case 0xa4: // SLA (ix+d)
+ case 0xa5: // SRA (ix+d)
+ case 0xa6: // SLL (ix+d)
+ case 0xa7: // SRL (ix+d)
+ OP( RLC+b2-0xa0,12 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ OP( TSET,16 ) BIT8( 1, b2 - 0x18 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // TSET b,(ix+d)
+ case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ OP( BIT,10 ) BIT8( 1, b2 - 0xa8 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // BIT b,(ix+d)
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ OP( RES,14 ) BIT8( 1, b2 - 0xb0 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // RES b,(ix+d)
+ case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ OP( SET,14 ) BIT8( 1, b2 - 0xb8 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // SET b,(ix+d)
+ } break;
+
+ case 0xf3:
+ b1 = READ8();
+ switch ( b1 ) {
+ case 0x10: // RLD (HL+A)
+ case 0x11: // RRD (HL+A)
+ OP( RLD+b1-0x10,20 ) MR16R8( 1, HL, A ) NONE( 2 ) return;
+
+ case 0x12: // MUL HL,(HL+A)
+ case 0x13: // DIV HL,(HL+A)
+ OP( MUL+b1-0x12,26 ) R16( 1, HL ) MR16R8( 2, HL, A ) return;
+
+ case 0x14: case 0x15: case 0x16:
+ OP16( ADD,16 ) R16( 1, IX+b1-0x14 ) MR16R8( 2, HL, A ) return; // ADD ix,(HL+A)
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e:
+ OP( LD,14 ) R8( 1, b1 - 0x28 ) MR16R8( 2, HL, A ) return; // LD r,(HL+A)
+ case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e:
+ OP16( LD,16 ) R16( 1, b1 - 0x48 ) MR16R8( 2, HL, A ) return; // LD rr,(HL+A)
+
+ case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56:
+ OP( EX,22 ) MR16R8( 1, HL, A ) R16( 2, b1 - 0x50 ) return; // EX (HL+A),rr
+
+ case 0x60: // ADD A,(HL+A)
+ case 0x61: // ADC A,(HL+A)
+ case 0x62: // SUB A,(HL+A)
+ case 0x63: // SBC A,(HL+A)
+ case 0x64: // AND A,(HL+A)
+ case 0x65: // XOR A,(HL+A)
+ case 0x66: // OR A,(HL+A)
+ case 0x67: // CP A,(HL+A)
+ OP( ADD+b1-0x60,14 ) R8( 1, A ) MR16R8( 2, HL, A ) return;
+
+ case 0x70: // ADD HL,(HL+A)
+ case 0x71: // ADC HL,(HL+A)
+ case 0x72: // SUB HL,(HL+A)
+ case 0x73: // SBC HL,(HL+A)
+ case 0x74: // AND HL,(HL+A)
+ case 0x75: // XOR HL,(HL+A)
+ case 0x76: // OR HL,(HL+A)
+ case 0x77: // CP HL,(HL+A)
+ OP16( ADD+b1-0x70,16 ) R16( 1, HL ) MR16R8( 2, HL, A ) return;
+
+ case 0x87:
+ OP( INC,16 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // INC (HL+A)
+ case 0x8f:
+ OP( DEC,16 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // DEC (HL+A)
+
+ case 0x97:
+ OP( INCW,20 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // INCW (HL+A)
+ case 0x9f:
+ OP( DECW,20 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // DECW (HL+A)
+
+ case 0xa0: // RLC (HL+A)
+ case 0xa1: // RRC (HL+A)
+ case 0xa2: // RL (HL+A)
+ case 0xa3: // RR (HL+A)
+ case 0xa4: // SLA (HL+A)
+ case 0xa5: // SRA (HL+A)
+ case 0xa6: // SLL (HL+A)
+ case 0xa7: // SRL (HL+A)
+ OP( RLC+b1-0xa0,16 ) MR16R8( 1, HL, A ) NONE( 2 ) return;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ OP( TSET,20 ) BIT8( 1, b1 - 0x18 ) MR16R8( 2, HL, A ) return; // TSET b,(HL+A)
+ case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ OP( BIT,14 ) BIT8( 1, b1 - 0xa8 ) MR16R8( 2, HL, A ) return; // BIT b,(HL+A)
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ OP( RES,18 ) BIT8( 1, b1 - 0xb0 ) MR16R8( 2, HL, A ) return; // RES b,(HL+A)
+ case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ OP( SET,18 ) BIT8( 1, b1 - 0xb8 ) MR16R8( 2, HL, A ) return; // SET b,(HL+A)
+ } break;
+
+ case 0xf4: case 0xf5: case 0xf6:
+ b1 = READ8();
+ b2 = READ8();
+ switch ( b2 ) {
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26:
+ OP( LD,10 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) R8( 2, b2 - 0x20 ) return; // LD (ix+d),r
+ case 0x37:
+ OP( LD,12 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) I8( 2, READ8() ) return; // LD (ix+d),n
+ case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e:
+ OP( LDA,10 ) R16( 1, b2 - 0x38 ) R16D8( 2, IX + b0 - 0xf4, b1 ) return; // LDA rr,ix+d
+ case 0x3f:
+ OP( LDW,16 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) I16( 2, READ16() ) return; // LDW (ix+d),mn
+ case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46:
+ OP16( LD,12 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) R16( 2, b2 - 0x40 ) return; // LD (ix+d),rr
+
+ case 0x68: // ADD (ix+d),n
+ case 0x69: // ADC (ix+d),n
+ case 0x6a: // SUB (ix+d),n
+ case 0x6b: // SBC (ix+d),n
+ case 0x6c: // AND (ix+d),n
+ case 0x6d: // XOR (ix+d),n
+ case 0x6e: // OR (ix+d),n
+ OP( ADD+b2-0x68,14) MR16D8( 1, IX + b0 - 0xf4, b1 ) I8( 2, READ8() ) return;
+ case 0x6f: // CP (ix+d),n
+ OP( ADD+b2-0x68,12) MR16D8( 1, IX + b0 - 0xf4, b1 ) I8( 2, READ8() ) return;
+
+ case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
+ case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ OPCC( JP,10,12 ) CC( 1, b2 - 0xc0 ) R16D8( 2, IX + b0 - 0xf4, b1 ) return; // JP [cc,]ix+d
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+ case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ OPCC( CALL,10,18 ) CC( 1, b2 - 0xd0 ) R16D8( 2, IX + b0 - 0xf4, b1 ) return; // CALL [cc,]ix+d
+ } break;
+
+ case 0xf7:
+ b1 = READ8();
+ switch ( b1 ) {
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26:
+ OP( LD,14 ) MR16R8( 1, HL, A ) R8( 2, b1 - 0x20 ) return; // LD (HL+A),r
+ case 0x37:
+ OP( LD,16 ) MR16R8( 1, HL, A ) I8( 2, READ8() ) return; // LD (HL+A),n
+ case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e:
+ OP( LDA,14 ) R16( 1, b1 - 0x38 ) R16R8( 2, HL, A ) return; // LDA rr,HL+A
+ case 0x3f:
+ OP( LDW,20 ) MR16R8( 1, HL, A ) I16( 2, READ16() ) return; // LDW (HL+A),mn
+ case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46:
+ OP16( LD,16 ) MR16R8( 1, HL, A ) R16( 2, b1 - 0x40 ) return; // LD (HL+A),rr
+
+ case 0x68: // ADD (HL+A),n
+ case 0x69: // ADC (HL+A),n
+ case 0x6a: // SUB (HL+A),n
+ case 0x6b: // SBC (HL+A),n
+ case 0x6c: // AND (HL+A),n
+ case 0x6d: // XOR (HL+A),n
+ case 0x6e: // OR (HL+A),n
+ OP( ADD+b1-0x68,18) MR16R8( 1, HL, A ) I8( 2, READ8() ) return;
+ case 0x6f: // CP (HL+A),n
+ OP( ADD+b1-0x68,16) MR16R8( 1, HL, A ) I8( 2, READ8() ) return;
+
+ case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
+ case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ OPCC( JP,14,16 ) CC( 1, b1 - 0xc0 ) R16R8( 2, HL, A ) return; // JP [cc,]HL+A
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+ case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ OPCC( CALL,14,22 ) CC( 1, b1 - 0xd0 ) R16R8( 2, HL, A ) return; // CALL [cc,]HL+A
+ } break;
+
+ case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe:
+ b1 = READ8();
+ switch ( b1 ) {
+ case 0x12: // MUL HL,g
+ case 0x13: // DIV HL,g
+ OP( MUL+b1-0x12,18) R16( 1, HL ) R8( 2, b0 - 0xf8 ) return;
+
+ case 0x14: case 0x15: case 0x16:
+ OP16( ADD,8 ) R16( 1, IX+b1-0x14 ) R16( 2, b0 - 0xf8 ) return; // ADD ix,gg
+
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36:
+ OP( LD,4 ) R8( 1, b1 - 0x30 ) R8( 2, b0 - 0xf8 ) return; // LD r,g
+ case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e:
+ OP16( LD,6 ) R16( 1, b1 - 0x38 ) R16( 2, b0 - 0xf8 ) return; // LD rr,gg
+
+ case 0x58: // LDI
+ case 0x59: // LDIR
+ case 0x5a: // LDD
+ case 0x5b: // LDDR
+ case 0x5c: // CPI
+ case 0x5d: // CPIR
+ case 0x5e: // CPD
+ case 0x5f: // CPDR
+ if (b0 == 0xfe) {
+ OPCC( LDI+b1-0x58,14,18 ) NONE( 1 ) NONE( 2 ) return;
+ }
+
+ case 0x60: // ADD A,g
+ case 0x61: // ADC A,g
+ case 0x62: // SUB A,g
+ case 0x63: // SBC A,g
+ case 0x64: // AND A,g
+ case 0x65: // XOR A,g
+ case 0x66: // OR A,g
+ case 0x67: // CP A,g
+ OP( ADD+b1-0x60,4 ) R8( 1, A ) R8( 2, b0 - 0xf8 ) return;
+
+ case 0x68: // ADD g,n
+ case 0x69: // ADC g,n
+ case 0x6a: // SUB g,n
+ case 0x6b: // SBC g,n
+ case 0x6c: // AND g,n
+ case 0x6d: // XOR g,n
+ case 0x6e: // OR g,n
+ case 0x6f: // CP g,n
+ OP( ADD+b1-0x68,6 ) R8( 1, b0 - 0xf8 ) I8( 2, READ8() ) return;
+
+ case 0x70: // ADD HL,gg
+ case 0x71: // ADC HL,gg
+ case 0x72: // SUB HL,gg
+ case 0x73: // SBC HL,gg
+ case 0x74: // AND HL,gg
+ case 0x75: // XOR HL,gg
+ case 0x76: // OR HL,gg
+ case 0x77: // CP HL,gg
+ OP16( ADD+b1-0x70,8 ) R16( 1, HL ) R16( 2, b0 - 0xf8 ) return;
+
+ case 0xa0: // RLC g
+ case 0xa1: // RRC g
+ case 0xa2: // RL g
+ case 0xa3: // RR g
+ case 0xa4: // SLA g
+ case 0xa5: // SRA g
+ case 0xa6: // SLL g
+ case 0xa7: // SRL g
+ OP( RLC+b1-0xa0,4 ) R8( 1, b0 - 0xf8 ) NONE( 2 ) return;
+
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ OP( TSET,8 ) BIT8( 1, b1 - 0x18 ) R8( 2, b0 - 0xf8 ) return; // TSET b,g
+ case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ OP( BIT,4 ) BIT8( 1, b1 - 0xa8 ) R8( 2, b0 - 0xf8 ) return; // BIT b,g
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ OP( RES,4 ) BIT8( 1, b1 - 0xb0 ) R8( 2, b0 - 0xf8 ) return; // RES b,g
+ case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ OP( SET,4 ) BIT8( 1, b1 - 0xb8 ) R8( 2, b0 - 0xf8 ) return; // SET b,g
+
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+ case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ if (b0 == 0xfe) {
+ OPCC( RET,6,14 ) CC( 1, b1 - 0xd0 ) NONE( 2 ) return; // RET cc
+ }
+ } break;
+
+ case 0xff:
+ OP( SWI,20 ) NONE( 1 ) NONE( 2 ) return; // SWI
+ }
+
+ OP( UNKNOWN,2 ) NONE( 1 ) NONE( 2 )
+}
+
+static const char *ir_names[] = {
+ "P0", "P1", "P01CR/IRFL", "IRFH", "P2", "P2CR", "P3", "P3CR",
+ "P4", "P4CR", "P5", "SMMOD", "P6", "P7", "P67CR", "SMCR",
+ "P8", "P8CR", "WDMOD", "WDCR", "TREG0", "TREG1", "TREG2", "TREG3",
+ "TCLK", "TFFCR", "TMOD", "TRUN", "CAP1L", "CAP1H", "CAP2L", "CAL2H",
+ "TREG4L", "TREG4H", "TREG5L", "TREG5H", "T4MOD", "T4FFCR", "INTEL", "INTEH",
+ "DMAEH", "SCMOD", "SCCR", "SCBUF", "BX", "BY", "ADREG", "ADMOD"
+};
+
+static const char *internal_registers_names(UINT16 x)
+{
+ int ir = x - T90_IOBASE;
+ if ( ir >= 0 && ir <= sizeof(ir_names)/sizeof(ir_names[0]) )
+ return ir_names[ir];
+ return NULL;
+}
+static int sprint_arg(char *buffer, UINT32 pc, const char *pre, const e_mode mode, const e_r r, const e_r rb)
+{
+ const char *reg_name;
+ switch ( mode )
+ {
+ case MODE_NONE: return 0;
+
+ case MODE_BIT8: return sprintf( buffer, "%s%d", pre, r );
+ case MODE_I8: return sprintf( buffer, "%s$%02X", pre, r );
+ case MODE_D8: return sprintf( buffer, "%s$%04X", pre, (pc+2+(r&0x7f)-(r&0x80))&0xffff );
+ case MODE_I16: return sprintf( buffer, "%s$%04X", pre, r );
+ case MODE_D16: return sprintf( buffer, "%s$%04X", pre, (pc+2+(r&0x7fff)-(r&0x8000))&0xffff );
+ case MODE_MI16:
+ reg_name = internal_registers_names(r);
+ return (reg_name) ? sprintf( buffer, "%s(%s)", pre, reg_name ):
+ sprintf( buffer, "%s($%04X)", pre, r );
+ case MODE_R8: return sprintf( buffer, "%s%s", pre, r8_names[r] );
+ case MODE_R16: return sprintf( buffer, "%s%s", pre, r16_names[r] );
+ case MODE_MR16: return sprintf( buffer, "%s(%s)", pre, r16_names[r] );
+
+ case MODE_MR16R8: return sprintf( buffer, "%s(%s+%s)", pre, r16_names[r], r8_names[rb] );
+ case MODE_MR16D8: return sprintf( buffer, "%s(%s%c$%02X)", pre, r16_names[r], (rb&0x80)?'-':'+', (rb&0x80)?((rb^0xff)+1):rb );
+
+ case MODE_CC: return sprintf( buffer, "%s%s", pre, cc_names[r] );
+
+ case MODE_R16R8: return sprintf( buffer, "%s%s+%s", pre, r16_names[r], r8_names[rb] );
+ case MODE_R16D8: return sprintf( buffer, "%s%s%c$%02X", pre, r16_names[r], (rb&0x80)?'-':'+', (rb&0x80)?((rb^0xff)+1):rb );
+
+ default:
+ fatalerror("%04x: unimplemented addr mode = %d\n",activecpu_get_pc(),mode);
+ }
+
+ return 0;
+}
+
+unsigned t90_dasm(char *buffer, UINT32 oldpc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int len;
+
+ addr = oldpc;
+
+ decode();
+ op &= ~OP_16;
+
+ buffer += sprintf ( buffer, "%-5s", op_names[ op ] ); // strlen("callr") == 5
+ len = sprint_arg ( buffer, oldpc, " ", mode1, r1, r1b );
+ buffer += len;
+ buffer += sprint_arg ( buffer, oldpc, (len>1)?",":"", mode2, r2, r2b );
+
+ return (addr - oldpc) | DASMFLAG_SUPPORTED;
+}
+
+
+INLINE UINT16 r8( const e_r r )
+{
+ switch( r )
+ {
+ case A: return T90.af.b.h;
+ case B: return T90.bc.b.h;
+ case C: return T90.bc.b.l;
+ case D: return T90.de.b.h;
+ case E: return T90.de.b.l;
+ case H: return T90.hl.b.h;
+ case L: return T90.hl.b.l;
+
+ default:
+ fatalerror("%04x: unimplemented r8 register index = %d\n",activecpu_get_pc(),r);
+ }
+}
+
+INLINE void w8( const e_r r, UINT16 value )
+{
+ switch( r )
+ {
+ case A: T90.af.b.h = value; return;
+ case B: T90.bc.b.h = value; return;
+ case C: T90.bc.b.l = value; return;
+ case D: T90.de.b.h = value; return;
+ case E: T90.de.b.l = value; return;
+ case H: T90.hl.b.h = value; return;
+ case L: T90.hl.b.l = value; return;
+
+ default:
+ fatalerror("%04x: unimplemented w8 register index = %d\n",activecpu_get_pc(),r);
+ }
+}
+
+INLINE UINT16 r16( const e_r r )
+{
+ switch( r )
+ {
+ case BC: return T90.bc.w.l;
+ case DE: return T90.de.w.l;
+ case HL: return T90.hl.w.l;
+ case IX: return T90.ix.w.l;
+ case IY: return T90.iy.w.l;
+ case SP: return T90.sp.w.l;
+ case AF: return T90.af.w.l;
+// case AF2: return T90.af2.w.l;
+// one interrupt flip-flop? Needed by e.g. mjifb
+case AF2: return (T90.af2.w.l & (~IF)) | (T90.af.w.l & IF);
+ case PC: return T90.pc.w.l;
+
+ default:
+ fatalerror("%04x: unimplemented r16 register index = %d\n",activecpu_get_pc(),r);
+ }
+}
+
+INLINE void w16( const e_r r, UINT16 value )
+{
+ switch( r )
+ {
+ case BC: T90.bc.w.l = value; return;
+ case DE: T90.de.w.l = value; return;
+ case HL: T90.hl.w.l = value; return;
+ case IX: T90.ix.w.l = value; return;
+ case IY: T90.iy.w.l = value; return;
+ case SP: T90.sp.w.l = value; return;
+ case AF: T90.af.w.l = value; return;
+ case AF2: T90.af2.w.l = value; return;
+ case PC: change_pc( T90.pc.d = value ); return;
+
+ default:
+ fatalerror("%04x: unimplemented w16 register index = %d\n",activecpu_get_pc(),r);
+ }
+}
+
+
+#define READ_FN( N ) \
+INLINE UINT8 Read##N##_8(void) { \
+ switch ( mode##N ) { \
+ case MODE_CC: \
+ case MODE_BIT8: \
+ case MODE_I8: return (UINT8)r##N; \
+ case MODE_D8: return (UINT8)r##N; \
+ case MODE_R8: return (UINT8)r8(r##N); \
+ case MODE_MI16: return RM8(r##N); \
+ case MODE_MR16R8: return RM8((UINT16)(r16(r##N) + (INT8)r8(r##N##b))); \
+ case MODE_MR16: \
+ switch( r##N ) { \
+ case IX: return RX8(T90.ix.w.l,T90.ixbase); \
+ case IY: return RX8(T90.iy.w.l,T90.iybase); \
+ } \
+ return RM8(r16(r##N)); \
+ case MODE_MR16D8: \
+ switch( r##N ) { \
+ case IX: return RX8((UINT16)(T90.ix.w.l + (INT8)r##N##b),T90.ixbase); \
+ case IY: return RX8((UINT16)(T90.iy.w.l + (INT8)r##N##b),T90.iybase); \
+ } \
+ return RM8((UINT16)(r16(r##N) + (INT8)r##N##b)); \
+ default: \
+ fatalerror("%04x: unimplemented Read%d_8 mode = %d\n",activecpu_get_pc(),N,mode##N); \
+ } \
+ return 0; \
+} \
+INLINE UINT16 Read##N##_16(void) { \
+ switch ( mode##N ) { \
+ case MODE_I16: return r##N; \
+ case MODE_R16: return r16(r##N); \
+ case MODE_R16D8: return r16(r##N) + (INT8)r##N##b; \
+ case MODE_R16R8: return r16(r##N) + (INT8)r8(r##N##b); \
+ case MODE_MI16: return RM16(r##N); \
+ case MODE_MR16R8: return RM16((UINT16)(r16(r##N) + (INT8)r8(r##N##b))); \
+ case MODE_MR16: \
+ switch( r##N ) { \
+ case IX: return RX16(T90.ix.w.l,T90.ixbase); \
+ case IY: return RX16(T90.iy.w.l,T90.iybase); \
+ } \
+ return RM16(r16(r##N)); \
+ case MODE_MR16D8: \
+ switch( r##N ) { \
+ case IX: return RX16((UINT16)(T90.ix.w.l + (INT8)r##N##b),T90.ixbase); \
+ case IY: return RX16((UINT16)(T90.iy.w.l + (INT8)r##N##b),T90.iybase); \
+ } \
+ return RM16((UINT16)(r16(r##N) + (INT8)r##N##b)); \
+ default: \
+ fatalerror("%04x: unimplemented Read%d_16 modes = %d\n",activecpu_get_pc(),N,mode##N); \
+ } \
+ return 0; \
+}
+
+
+
+#define WRITE_FN( N ) \
+INLINE void Write##N##_8( UINT8 value ) { \
+ switch ( mode##N ) { \
+ case MODE_R8: w8(r##N,value); return; \
+ case MODE_MI16: WM8(r##N, value); return; \
+ case MODE_MR16R8: WM8((UINT16)(r16(r##N) + (INT8)r8(r##N##b)), value); return; \
+ case MODE_MR16: \
+ switch( r##N ) { \
+ case IX: WX8(T90.ix.w.l,value,T90.ixbase); return; \
+ case IY: WX8(T90.iy.w.l,value,T90.iybase); return; \
+ } \
+ WM8(r16(r##N), value); return; \
+ case MODE_MR16D8: \
+ switch( r##N ) { \
+ case IX: WX8((UINT16)(T90.ix.w.l + (INT8)r##N##b),value,T90.ixbase); return; \
+ case IY: WX8((UINT16)(T90.iy.w.l + (INT8)r##N##b),value,T90.iybase); return; \
+ } \
+ WM8((UINT16)(r16(r##N) + (INT8)r##N##b), value); return; \
+ default: \
+ fatalerror("%04x: unimplemented Write%d_8 mode = %d\n",activecpu_get_pc(),N,mode##N); \
+ } \
+} \
+INLINE void Write##N##_16( UINT16 value ) \
+{ \
+ switch ( mode##N ) { \
+ case MODE_R16: w16(r##N,value); return; \
+ case MODE_MI16: WM16(r##N, value); return; \
+ case MODE_MR16R8: WM16((UINT16)(r16(r##N) + (INT8)r8(r##N##b)), value); return; \
+ case MODE_MR16: \
+ switch( r##N ) { \
+ case IX: WX16(T90.ix.w.l,value,T90.ixbase); return; \
+ case IY: WX16(T90.iy.w.l,value,T90.iybase); return; \
+ } \
+ WM16(r16(r##N), value); return; \
+ case MODE_MR16D8: \
+ switch( r##N ) { \
+ case IX: WX16((UINT16)(T90.ix.w.l + (INT8)r##N##b),value,T90.ixbase); return; \
+ case IY: WX16((UINT16)(T90.iy.w.l + (INT8)r##N##b),value,T90.iybase); return; \
+ } \
+ WM16((UINT16)(r16(r##N) + (INT8)r##N##b), value); return; \
+ default: \
+ fatalerror("%04x: unimplemented Write%d_16 mode = %d\n",activecpu_get_pc(),N,mode##N); \
+ } \
+}
+
+READ_FN(1)
+READ_FN(2)
+WRITE_FN(1)
+WRITE_FN(2)
+
+INLINE int Test( UINT8 cond )
+{
+ int s,v;
+ switch ( cond )
+ {
+ case FLS: return 0;
+ case LT: s = F & SF; v = F & VF; return (s && !v) || (!s && v);
+ case LE: s = F & SF; v = F & VF; return (F & ZF) || (s && !v) || (!s && v);
+ case ULE: return (F & CF) || (F & ZF);
+ case OV: return F & VF;
+ case MI: return F & SF;
+ case Z: return F & ZF;
+ case CR: return F & CF;
+ case T: return 1;
+ case GE: s = F & SF; v = F & VF; return (s && v) || (!s && !v);
+ case GT: s = F & SF; v = F & VF; return !((F & ZF) || (s && !v) || (!s && v));
+ case UGT: return !(F & CF) && !(F & ZF);
+ case NOV: return !(F & VF);
+ case PL: return !(F & SF);
+ case NZ: return !(F & ZF);
+ case NC: return !(F & CF);
+ default:
+ fatalerror("%04x: unimplemented condition = %d\n",activecpu_get_pc(),cond);
+ }
+ return 0;
+}
+
+INLINE void Push( e_r rr )
+{
+ T90.sp.w.l -= 2;
+ WM16( T90.sp.w.l, r16(rr) );
+}
+INLINE void Pop( e_r rr )
+{
+ w16( rr, RM16( T90.sp.w.l ) );
+ T90.sp.w.l += 2;
+}
+
+/*************************************************************************************************************
+
+Interrupts
+
+----------------------------------------------------------------------------------------------------------------
+Priority Type Interrupt Source Vector/8 Vector Address uDMA Address
+----------------------------------------------------------------------------------------------------------------
+1 Non Maskable SWI - 10 0010 -
+2 "" NMI - 18 0018 -
+3 "" INTWD Watch Dog - 20 0020 -
+4 Maskable INT0 External 0 05 28 0028 FF28
+5 "" INTT0 Timer 0 06 30 0030 FF30
+6 "" INTT1 Timer 1 07 38 0038 FF38
+7 "" INTAD A/D 08 40 0040 FF48
+"" "" INTT2 Timer 2 "" "" "" ""
+8 "" INTT3 Timer 3 09 48 0048 FF48
+9 "" INTT4 Timer 4 0A 50 0050 FF50
+10 "" INT1 External 1 0B 58 0058 FF58
+11 "" INTT5 Timer 5 0C 60 0060 FF60
+12 "" INT2 External 2 0D 68 0068 FF68
+13 "" INTRX End Serial Receive 0E 70 0070 FF70
+14 "" INTTX End Serial Transmit 0F 78 0078 FF78
+
+----------------------------------------------------------------------------------------------------------------
+Interrupt Terminal Mode How To Set
+----------------------------------------------------------------------------------------------------------------
+NMI - Falling Edge -
+INT0 P80 Level P8CR<EDGE> = 0
+ Rising Edge P8CR<EDGE> = 1
+INT1 P81 Rising Edge T4MOD<CAPM1,0> = 0,0 or 0,1 or 1,1
+ Falling Edge T4MOD<CAPM1,0> = 1,0
+INT2 P82 Rising Edge -
+
+*************************************************************************************************************/
+
+typedef enum { INTSWI = 0, INTNMI, INTWD, INT0, INTT0, INTT1, INTT2, INTT3, INTT4, INT1, INTT5, INT2, INTRX, INTTX, INTMAX } e_irq;
+
+INLINE void leave_halt(void)
+{
+ if( T90.halt )
+ {
+ T90.halt = 0;
+ T90.pc.w.l++;
+ }
+}
+
+static void take_interrupt(e_irq irq)
+{
+ T90.irq_state &= ~(1 << irq);
+
+ leave_halt();
+
+ Push( PC );
+ Push( AF );
+
+ F &= ~IF;
+
+ T90.pc.w.l = 0x10 + irq * 8;
+ change_pc( T90.pc.d );
+
+ T90.extra_cycles += 20*2;
+}
+
+static void check_interrupts(void)
+{
+ e_irq irq;
+
+ if (!(F & IF))
+ return;
+
+ for (irq = INT0; irq < INTMAX; irq++)
+ if ( T90.irq_state & T90.irq_mask & (1 << irq) )
+ take_interrupt( irq );
+}
+
+static void set_irq_line(int irq, int state)
+{
+ if ( ((T90.irq_state >> irq)&1) == state ) return;
+
+ if (state)
+ {
+ T90.irq_state |= 1 << irq;
+ check_interrupts();
+ }
+ else
+ {
+ T90.irq_state &= ~(1 << irq);
+ }
+}
+
+INLINE void Cyc(void) { t90_ICount -= cyc_t; }
+INLINE void Cyc_f(void) { t90_ICount -= cyc_f; }
+
+static int t90_execute(int cycles)
+{
+ UINT8 a8,b8;
+ UINT16 a16,b16;
+ unsigned a32;
+ PAIR tmp;
+
+ t90_ICount = cycles - T90.extra_cycles;
+ T90.extra_cycles = 0;
+
+ do
+ {
+ T90.prvpc.d = T90.pc.d;
+ CALL_MAME_DEBUG;
+
+ check_interrupts();
+
+ addr = T90.pc.d;
+ decode();
+ T90.pc.d = addr;
+
+ switch ( op )
+ {
+ case NOP:
+ Cyc();
+ break;
+
+ case EX:
+ a16 = Read1_16();
+ Write1_16( Read2_16() );
+ Write2_16( a16 );
+ Cyc();
+ break;
+ case EXX:
+ tmp = T90.bc; T90.bc = T90.bc2; T90.bc2 = tmp;
+ tmp = T90.de; T90.de = T90.de2; T90.de2 = tmp;
+ tmp = T90.hl; T90.hl = T90.hl2; T90.hl2 = tmp;
+ Cyc();
+ break;
+
+ case LD:
+ Write1_8( Read2_8() );
+ Cyc();
+ break;
+ case LDW:
+ case LD | OP_16:
+ Write1_16( Read2_16() );
+ Cyc();
+ break;
+
+// case LDA:
+// Cyc();
+// break;
+
+ case LDI:
+#define _LDI \
+ WM8( T90.de.w.l, RM8(T90.hl.w.l) ); \
+ T90.de.w.l++; \
+ T90.hl.w.l++; \
+ T90.bc.w.l--; \
+ F &= SF | ZF | IF | XCF | CF; \
+ if ( T90.bc.w.l ) F |= VF;
+
+ _LDI
+ Cyc();
+ break;
+ case LDIR:
+ _LDI
+ if ( T90.bc.w.l )
+ {
+ T90.pc.w.l -= 2;
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+
+ case LDD:
+#define _LDD \
+ WM8( T90.de.w.l, RM8(T90.hl.w.l) ); \
+ T90.de.w.l--; \
+ T90.hl.w.l--; \
+ T90.bc.w.l--; \
+ F &= SF | ZF | IF | XCF | CF; \
+ if ( T90.bc.w.l ) F |= VF;
+
+ _LDD
+ Cyc();
+ break;
+ case LDDR:
+ _LDD
+ if ( T90.bc.w.l )
+ {
+ T90.pc.w.l -= 2;
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+
+
+// case CPD:
+// Cyc();
+// break;
+// case CPDR:
+// Cyc();
+// break;
+ case CPI:
+ a8 = RM8(T90.hl.w.l);
+ b8 = T90.af.b.h - a8;
+ T90.hl.w.l++;
+ T90.bc.w.l--;
+ F = (F & (IF | CF)) | SZ[b8] | ((T90.af.b.h^a8^b8)&HF) | NF;
+ if ( T90.bc.w.l ) F |= VF;
+ Cyc();
+ break;
+ case CPIR:
+ a8 = RM8(T90.hl.w.l);
+ b8 = T90.af.b.h - a8;
+ T90.hl.w.l++;
+ T90.bc.w.l--;
+ F = (F & (IF | CF)) | SZ[b8] | ((T90.af.b.h^a8^b8)&HF) | NF;
+ if ( T90.bc.w.l )
+ {
+ F |= VF;
+ T90.pc.w.l -= 2;
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+
+ case PUSH:
+ Push( r1 );
+ Cyc();
+ break;
+ case POP:
+ Pop( r1 );
+ Cyc();
+ break;
+
+ case JP:
+ if ( Test( Read1_8() ) )
+ {
+ T90.pc.w.l = Read2_16();
+ change_pc( T90.pc.d );
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+ case JR:
+ if ( Test( Read1_8() ) )
+ {
+ T90.pc.w.l += /*2 +*/ (INT8)Read2_8();
+ change_pc( T90.pc.d );
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+ case JR | OP_16:
+ if ( Test( Read1_8() ) )
+ {
+ T90.pc.w.l += /*2 +*/ Read2_16();
+ change_pc( T90.pc.d );
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+
+
+ case CALL:
+ if ( Test( Read1_8() ) )
+ {
+ Push( PC );
+ T90.pc.w.l = Read2_16();
+ change_pc( T90.pc.d );
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+ case CALLR:
+ Push( PC );
+ T90.pc.w.l += /*2 +*/ Read1_16();
+ change_pc( T90.pc.d );
+ Cyc();
+ break;
+
+ case RET:
+ if ( Test( Read1_8() ) )
+ {
+ Pop( PC );
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+ case RETI:
+ Pop( AF );
+ Pop( PC );
+ Cyc();
+ break;
+
+// case HALT:
+// Cyc();
+// break;
+ case DI:
+ T90.after_EI = 0;
+ F &= ~IF;
+ Cyc();
+ break;
+ case EI:
+ T90.after_EI = !(F & IF);
+ Cyc();
+ break;
+
+ case SWI:
+ Cyc();
+ take_interrupt( INTSWI );
+ break;
+
+ case DAA:
+ {
+ UINT8 cf, nf, hf, lo, hi, diff;
+ cf = F & CF;
+ nf = F & NF;
+ hf = F & HF;
+ lo = T90.af.b.h & 15;
+ hi = T90.af.b.h / 16;
+
+ if (cf)
+ {
+ diff = (lo <= 9 && !hf) ? 0x60 : 0x66;
+ }
+ else
+ {
+ if (lo >= 10)
+ {
+ diff = hi <= 8 ? 0x06 : 0x66;
+ }
+ else
+ {
+ if (hi >= 10)
+ {
+ diff = hf ? 0x66 : 0x60;
+ }
+ else
+ {
+ diff = hf ? 0x06 : 0x00;
+ }
+ }
+ }
+ if (nf) T90.af.b.h -= diff;
+ else T90.af.b.h += diff;
+
+ F = SZP[A] | (F & (IF | NF));
+ if (cf || (lo <= 9 ? hi >= 10 : hi >= 9)) F |= XCF | CF;
+ if (nf ? hf && lo <= 5 : lo >= 10) F |= HF;
+ }
+ Cyc();
+ break;
+
+
+ case CPL:
+ T90.af.b.h ^= 0xff;
+ F |= HF | NF;
+ Cyc();
+ break;
+ case NEG:
+ a8 = 0;
+ b8 = T90.af.b.h;
+ a32 = a8 - b8;
+ F = (F & IF) | SZ[(UINT8)a32] | NF;
+ if (a32 & 0x100) F |= CF | XCF; //X?
+ if ((a8 ^ a32 ^ b8) & 0x10) F |= HF;
+ if ((b8 ^ a8) & (a8 ^ a32) & 0x80) F |= VF;
+ T90.af.b.h = a32;
+ Cyc();
+ break;
+
+ case LDAR:
+ T90.hl.w.l = T90.pc.w.l + /*2 +*/ Read2_16();
+ Cyc();
+ break;
+
+ case RCF:
+ F &= SF | ZF | IF | VF;
+ Cyc();
+ break;
+ case SCF:
+ F = (F & (SF | ZF | IF | VF)) | XCF | CF;
+ Cyc();
+ break;
+ case CCF:
+ F = (F & (SF | ZF | IF | VF)) | ((F & CF)?HF:(XCF | CF));
+ Cyc();
+ break;
+
+// case TSET:
+// Cyc();
+// break;
+ case BIT:
+ F = (F & (IF | CF)) | HF | SZ_BIT[ Read2_8() & (1 << Read1_8()) ];
+ Cyc();
+ break;
+ case SET:
+ Write2_8( Read2_8() | (1 << Read1_8()) );
+ Cyc();
+ break;
+ case RES:
+ Write2_8( Read2_8() & (~(1 << Read1_8())) );
+ Cyc();
+ break;
+
+ case INC:
+ a8 = Read1_8() + 1;
+ Write1_8( a8 );
+ F = (F & (IF | CF)) | SZHV_inc[a8];
+ if (a8 == 0) F |= XCF;
+ Cyc();
+ break;
+ case INCX:
+ if ( F & XCF )
+ {
+ a8 = Read1_8() + 1;
+ Write1_8( a8 );
+ F = (F & (IF | CF)) | SZHV_inc[a8];
+ if (a8 == 0) F |= XCF;
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+ case INC | OP_16:
+ a16 = Read1_16() + 1;
+ Write1_16( a16 );
+ if (a16 == 0) F |= XCF;
+ else F &= ~XCF;
+ Cyc();
+ break;
+ case INCW:
+ a16 = Read1_16();
+ a32 = a16 + 1;
+ Write1_16( a32 );
+ F &= IF | CF;
+ if ((UINT16)a32 == 0) F |= ZF | XCF;
+ if (a32 & 0x8000) F |= SF;
+ if ((a16 ^ 0x8000) & a32 & 0x8000) F |= VF;
+ if ((a16 ^ a32 ^ 1) & 0x1000) F |= HF; //??
+ Cyc();
+ break;
+
+
+ case DEC:
+ a8 = Read1_8() - 1;
+ Write1_8( a8 );
+ F = (F & (IF | CF)) | SZHV_dec[a8];
+ if (a8 == 0) F |= XCF;
+ Cyc();
+ break;
+ case DECX:
+ if ( F & XCF )
+ {
+ a8 = Read1_8() - 1;
+ Write1_8( a8 );
+ F = (F & (IF | CF)) | SZHV_dec[a8];
+ if (a8 == 0) F |= XCF;
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+ case DEC | OP_16:
+ a16 = Read1_16() - 1;
+ Write1_16( a16 );
+ if (a16 == 0) F |= XCF;
+ else F &= ~XCF;
+ Cyc();
+ break;
+ case DECW:
+ a16 = Read1_16();
+ a32 = a16 - 1;
+ Write1_16( a32 );
+ F = (F & (IF | CF)) | NF;
+ if ((UINT16)a32 == 0) F |= ZF | XCF;
+ if (a32 & 0x8000) F |= SF;
+ if (a16 == 0x8000) F |= VF;
+ if ((a16 ^ a32 ^ 1) & 0x1000) F |= HF; //??
+ Cyc();
+ break;
+
+ case ADD:
+ case ADC:
+ a8 = Read1_8();
+ b8 = Read2_8();
+ a32 = a8 + b8;
+ if ( (op == ADC) && (F & CF) ) a32 += 1;
+ Write1_8( a32 );
+ F = (F & IF) | SZ[(UINT8)a32];
+ if (a32 & 0x100) F |= CF | XCF; //X?
+ if ((a8 ^ a32 ^ b8) & 0x10) F |= HF;
+ if ((b8 ^ a8 ^ 0x80) & (b8 ^ a32) & 0x80) F |= VF;
+ Cyc();
+ break;
+ case ADD | OP_16:
+ case ADC | OP_16:
+ a16 = Read1_16();
+ b16 = Read2_16();
+ a32 = a16 + b16;
+ if ( (op == (ADC | OP_16)) && (F & CF) ) a32 += 1;
+ Write1_16( a32 );
+ if ( (op == (ADD | OP_16)) && mode2 == MODE_R16 )
+ {
+ F &= SF | ZF | IF | VF;
+ }
+ else
+ {
+ F &= IF;
+ if ((UINT16)a32 == 0) F |= ZF;
+ if (a32 & 0x8000) F |= SF;
+ if ((b16 ^ a16 ^ 0x8000) & (b16 ^ a32) & 0x8000) F |= VF;
+ }
+ if (a32 & 0x10000) F |= CF | XCF; //X?
+ if ((a16 ^ a32 ^ b16) & 0x1000) F |= HF; //??
+ Cyc();
+ break;
+
+ case CP:
+ case SUB:
+ case SBC:
+ a8 = Read1_8();
+ b8 = Read2_8();
+ a32 = a8 - b8;
+ if ( (op == SBC) && (F & CF) ) a32 -= 1;
+ F = (F & IF) | SZ[(UINT8)a32] | NF;
+ if (a32 & 0x100) F |= CF | XCF; //X?
+ if ((a8 ^ a32 ^ b8) & 0x10) F |= HF;
+ if ((b8 ^ a8) & (a8 ^ a32) & 0x80) F |= VF;
+ if (op != CP)
+ Write1_8( a32 );
+ Cyc();
+ break;
+ case CP | OP_16:
+ case SUB | OP_16:
+ case SBC | OP_16:
+ a16 = Read1_16();
+ b16 = Read2_16();
+ a32 = a16 - b16;
+ if ( (op == (SBC | OP_16)) && (F & CF) ) a32 -= 1;
+ F = (F & IF) | NF;
+ if ((UINT16)a32 == 0) F |= ZF;
+ if (a32 & 0x8000) F |= SF;
+ if (a32 & 0x10000) F |= CF | XCF; //X?
+ if ((a16 ^ a32 ^ b16) & 0x1000) F |= HF; //??
+ if ((b16 ^ a16) & (a16 ^ a32) & 0x8000) F |= VF;
+ if (op != (CP | OP_16))
+ Write1_16( a32 );
+ Cyc();
+ break;
+
+ case AND:
+ a8 = Read1_8() & Read2_8();
+ Write1_8( a8 );
+ F = (F & IF) | SZP[a8] | HF;
+ Cyc();
+ break;
+ case AND | OP_16:
+ a16 = Read1_16() & Read2_16();
+ Write1_16( a16 );
+ F = (F & IF) | HF;
+ if (a16 == 0) F |= ZF;
+ if (a16 & 0x8000) F |= SF;
+ Cyc();
+ break;
+ case XOR:
+ a8 = Read1_8() ^ Read2_8();
+ Write1_8( a8 );
+ F = (F & IF) | SZP[a8];
+ Cyc();
+ break;
+ case XOR | OP_16:
+ a16 = Read1_16() ^ Read2_16();
+ Write1_16( a16 );
+ F &= IF;
+ if (a16 == 0) F |= ZF;
+ if (a16 & 0x8000) F |= SF;
+ Cyc();
+ break;
+ case OR:
+ a8 = Read1_8() | Read2_8();
+ Write1_8( a8 );
+ F = (F & IF) | SZP[a8];
+ Cyc();
+ break;
+ case OR | OP_16:
+ a16 = Read1_16() | Read2_16();
+ Write1_16( a16 );
+ F &= IF;
+ if (a16 == 0) F |= ZF;
+ if (a16 & 0x8000) F |= SF;
+ Cyc();
+ break;
+
+ case RLC:
+ a8 = Read1_8();
+ a8 = (a8 << 1) | (a8 >> 7);
+ Write1_8( a8 );
+ if ( mode1 == MODE_R8 && r1 == A ) F &= SF | ZF | IF | PF;
+ else F = (F & IF) | SZP[a8];
+ if (a8 & 0x01) F |= CF | XCF; // X?
+ Cyc();
+ break;
+ case RRC:
+ a8 = Read1_8();
+ a8 = (a8 >> 1) | (a8 << 7);
+ Write1_8( a8 );
+ if ( mode1 == MODE_R8 && r1 == A ) F &= SF | ZF | IF | PF;
+ else F = (F & IF) | SZP[a8];
+ if (a8 & 0x80) F |= CF | XCF; // X?
+ Cyc();
+ break;
+ case RL:
+ a8 = Read1_8();
+ b8 = a8 & 0x80;
+ a8 <<= 1;
+ if (F & CF) a8 |= 0x01;
+ Write1_8( a8 );
+ if ( mode1 == MODE_R8 && r1 == A ) F &= SF | ZF | IF | PF;
+ else F = (F & IF) | SZP[a8];
+ if (b8) F |= CF | XCF; // X?
+ Cyc();
+ break;
+ case RR:
+ a8 = Read1_8();
+ b8 = a8 & 0x01;
+ a8 >>= 1;
+ if (F & CF) a8 |= 0x80;
+ Write1_8( a8 );
+ if ( mode1 == MODE_R8 && r1 == A ) F &= SF | ZF | IF | PF;
+ else F = (F & IF) | SZP[a8];
+ if (b8) F |= CF | XCF; // X?
+ Cyc();
+ break;
+
+ case SLA:
+ case SLL:
+ a8 = Read1_8();
+ b8 = a8 & 0x80;
+ a8 <<= 1;
+ Write1_8( a8 );
+ if ( mode1 == MODE_R8 && r1 == A ) F &= SF | ZF | IF | PF;
+ else F = (F & IF) | SZP[a8];
+ if (b8) F |= CF | XCF; // X?
+ Cyc();
+ break;
+ case SRA:
+ a8 = Read1_8();
+ b8 = a8 & 0x01;
+ a8 = (a8 & 0x80) | (a8 >> 1);
+ Write1_8( a8 );
+ if ( mode1 == MODE_R8 && r1 == A ) F &= SF | ZF | IF | PF;
+ else F = (F & IF) | SZP[a8];
+ if (b8) F |= CF | XCF; // X?
+ Cyc();
+ break;
+ case SRL:
+ a8 = Read1_8();
+ b8 = a8 & 0x01;
+ a8 >>= 1;
+ Write1_8( a8 );
+ if ( mode1 == MODE_R8 && r1 == A ) F &= SF | ZF | IF | PF;
+ else F = (F & IF) | SZP[a8];
+ if (b8) F |= CF | XCF; // X?
+ Cyc();
+ break;
+ case RLD:
+ a8 = T90.af.b.h;
+ b8 = Read1_8();
+ Write1_8( (b8 << 4) | (a8 & 0x0f) );
+ a8 = (a8 & 0xf0) | (b8 >> 4);
+ F = (F & (IF | CF)) | SZP[a8];
+ T90.af.b.h = a8;
+ Cyc();
+ break;
+ case RRD:
+ a8 = T90.af.b.h;
+ b8 = Read1_8();
+ Write1_8( (b8 >> 4) | (a8 << 4) );
+ a8 = (a8 & 0xf0) | (b8 & 0x0f);
+ F = (F & (IF | CF)) | SZP[a8];
+ T90.af.b.h = a8;
+ Cyc();
+ break;
+
+ case DJNZ:
+ if ( --T90.bc.b.h )
+ {
+ T90.pc.w.l += /*2 +*/ (INT8)Read1_8();
+ change_pc( T90.pc.d );
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+ case DJNZ | OP_16:
+ if ( --T90.bc.w.l )
+ {
+ T90.pc.w.l += /*2 +*/ (INT8)Read2_8();
+ change_pc( T90.pc.d );
+ Cyc();
+ }
+ else Cyc_f();
+ break;
+
+ case MUL:
+ T90.hl.w.l = (UINT16)T90.hl.b.l * (UINT16)Read2_8();
+ Cyc();
+ break;
+ case DIV:
+ a16 = T90.hl.w.l;
+ b16 = (UINT16)Read2_8();
+ if (b16 == 0)
+ {
+ F |= VF;
+ T90.hl.w.l = (a16 << 8) | ((a16 >> 8) ^ 0xff);
+ }
+ else
+ {
+ T90.hl.b.h = a16 % b16;
+ a16 /= b16;
+ if (a16 > 0xff) F |= VF;
+ else F &= ~VF;
+ T90.hl.b.l = a16;
+ }
+ Cyc();
+ break;
+
+ default:
+ fatalerror("%04x: unimplemented opcode, op=%02x\n",activecpu_get_pc(),op);
+ }
+
+ if ( op != EI )
+ if (T90.after_EI)
+ {
+ F |= IF;
+ T90.after_EI = 0;
+ }
+
+ } while( t90_ICount > 0 );
+
+ t90_ICount -= T90.extra_cycles;
+ T90.extra_cycles = 0;
+
+ return cycles - t90_ICount;
+}
+
+static void t90_reset(void)
+{
+ T90.irq_state = 0;
+ T90.irq_mask = 0;
+ change_pc( T90.pc.d = 0x0000 );
+ F &= ~IF;
+/*
+ P0/D0-D7 P1/A0-A7 P2/A8-A15 P6 P7 = INPUT
+ P35/~RD P36/~WR CLK = 1 (ALWAYS OUTPUTS)
+ P4/A16-A19 P83 = 0
+ dedicated input ports and registers remain unchanged,
+ but PC IFF BX BY = 0, A undefined
+*/
+}
+
+static void t90_exit(void)
+{
+}
+
+static void t90_burn(int cycles)
+{
+ t90_ICount -= 4 * ((cycles + 3) / 4);
+}
+
+static void t90_get_context (void *dst)
+{
+ if( dst )
+ *(t90_Regs*)dst = T90;
+}
+
+static void t90_set_context (void *src)
+{
+ if( src )
+ T90 = *(t90_Regs*)src;
+ change_pc(T90.pc.d);
+}
+
+
+/*************************************************************************************************************
+
+
+----------------------------------------------------------------------------------------------------------------
+FFC0 P0 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-0 P07-P00 R W IN I/O Port 0
+
+----------------------------------------------------------------------------------------------------------------
+FFC1 P1 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-0 P17-P10 R W IN I/O Port 1
+
+----------------------------------------------------------------------------------------------------------------
+FFC2 P01CR/ R/W Reset Description * Prohibit Read-Modify-Write *
+ IRFL
+----------------------------------------------------------------------------------------------------------------
+ 7 - - 0 -
+ 6 IRF0 R 0 INT0 interrupt request (1 = asserted)
+ 5 IRFT0 R 0 INTT0 ""
+ 4 IRFT1 R 0 INTT1 ""
+ 3 - - 0 -
+ 2 EXT W 0 P1/P2 control: 0 = Port 1 = Address Bus
+ 1 P1CR W 0 P1 control: 0 = IN 1 = OUT |
+ 0 P0CR W 0 P0 control: 0 = IN 1 = OUT |
+ | |
+ Port 0 also functions as data bus (D0-D7),so P1: regardless of <P1CR>
+ P0CR is reset when external memory is accessed P2: only if P2CR is set to 1 (output)
+ TMP90C841A: always address bus
+
+----------------------------------------------------------------------------------------------------------------
+FFC3 IRFH R/W Reset Description * Prohibit Read-Modify-Write *
+----------------------------------------------------------------------------------------------------------------
+ 7 IRFT2 R W 0 INTT2 interrupt request (1 = asserted)
+ 6 IRFT3 R W 0 INTT3 ""
+ 5 IRFT4 R W 0 INTT4 ""
+ 4 IRF1 R W 0 INT1 ""
+ 3 IRFT5 R W 0 INTT5 ""
+ 2 IRF2 R W 0 INT2 ""
+ 1 IRFRX R W 0 INTRX ""
+ 0 IRFTX R W 0 INTTX ""
+ |__ Writing Vector/8 clears the request flip-flop for that interrupt
+
+----------------------------------------------------------------------------------------------------------------
+FFC4 P2 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-0 P27-P20 R W IN I/O Port 2
+
+----------------------------------------------------------------------------------------------------------------
+FFC5 P2CR R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-0 P27C- W 0 Port 2 control: 0 = IN 1 = OUT
+ P20C
+
+----------------------------------------------------------------------------------------------------------------
+FFC6 P3 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+ 7 P37 R IN P37 input
+ 6 P36 R W 1 ~WD
+ 5 P35 R W 1 ~RD
+ 4 P34 R IN P34 input
+ 3 P33 R W 1 TxD / P33 output
+ 2 P32 R W 1 TxD / P32 output
+ 1 P31 R IN RxD / P31 input
+ 0 P30 R IN RxD / P30 input
+
+----------------------------------------------------------------------------------------------------------------
+FFC7 P3CR R/W Reset Description * Prohibit Read-Modify-Write *
+----------------------------------------------------------------------------------------------------------------
+7-6 WAITC1-0R W 00 Wait control: 00 = 2state 01 = normal 10 = no wait 11 = reserved
+ 5 RDE R W 0 RD control: 0 = only external access 1 = always
+ 4 ODE R W 0 P33 control: 0 = CMOS 1 = Open Drain
+3-2 TXDC1-0 R W 00 P33-P32: 00 = OUT-OUT 01 = OUT-TxD 10 = TxD-OUT 11 = TxD-~RTS/SCLK
+1-0 RXDC1-0 R W 00 P31-P30: 00 = IN-IN 01 = IN-RxD 10 = RxD-IN 11 = not used
+
+----------------------------------------------------------------------------------------------------------------
+FFC8 P4 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-4 -
+3-0 P43-P40 R W 0 I/O Port 4 bits 3-0 or address bus A16-A19
+
+----------------------------------------------------------------------------------------------------------------
+FFC9 P4CR R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-4 -
+3-0 P43C- W 0 Port 4 control: 0 = OUT 1 = Address Output
+ P40C
+
+----------------------------------------------------------------------------------------------------------------
+FFCA P5 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7 - R 0 Test bit, must be set to 0
+6 - R 0
+5-0 P55-P50 R 0 I/O Port 5 bits 5-0 / AN5-AN0 analog inputs
+
+----------------------------------------------------------------------------------------------------------------
+FFCB SMMOD R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+ 7 - R W -
+ 6 SM7M0 R W 0 Motor Step: 0 = Full 1 = Half
+ 5 P70C1 R W 0 Port 7 control: 0 = IN-OUT 0 = IN-OUT,TO3 1 = IN / M1 1 = Timer 4
+ 4 P70C0 R W 0 0 1 0 Timer 2,3 1
+ 3 - R W -
+ 2 SM6M0 R W 0 Motor Step: 0 = Full 1 = Half
+ 1 P60C1 R W 0 Port 6 control: 0 = IN-OUT 0 = IN-OUT,TO1 1 = IN / M0
+ 0 P60C0 R W 0 0 1 X Timer 0,1
+
+----------------------------------------------------------------------------------------------------------------
+FFCC P6 R/W Reset Description * Read-Modify-Write not available in Stepping Motor control *
+----------------------------------------------------------------------------------------------------------------
+7-4 SA60-63 W Undef Stepping motor Port 0 (M0) Shifter alternate reg.
+3-0 P63-P60 R W IN Bits 3-0 of I/O Port 6 or Stepping motor Port 0 (M0)
+
+----------------------------------------------------------------------------------------------------------------
+FFCD P7 R/W Reset Description * Read-Modify-Write not available in Stepping Motor control *
+----------------------------------------------------------------------------------------------------------------
+7-4 SA70-73 W Undef Stepping motor Port 1 (M1) Shifter alternate reg.
+3-0 P73-P70 R W IN Bits 3-0 of I/O Port 7 or Stepping motor Port 1 (M1)
+
+----------------------------------------------------------------------------------------------------------------
+FFCE P67CR R/W Reset Description * Prohibit Read-Modify-Write *
+----------------------------------------------------------------------------------------------------------------
+7-4 P73-70C W 0 Port 7: 0 = IN 1 = OUT
+3-0 P63-60C W 0 Port 6: 0 = IN 1 = OUT
+
+----------------------------------------------------------------------------------------------------------------
+FFD0 P8 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-4 -
+ 3 P83 R W 0 P83 / TIO3 / TIO4 output
+ 2 P82 R IN P82 + INT2 input
+ 1 P81 R IN P81 + INT1 input
+ 0 P80 R IN P80 + INT0 input
+
+----------------------------------------------------------------------------------------------------------------
+FFD1 P8CR R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-4 -
+ 3 P83OC W 0 P83 out control: 0 = P83 1 = TO3 / TO4
+ 2 ZCE2 W 0 INT2/TI5 control: 0 = ZCD disable 1 = ZCD enable
+ 1 ZCE1 W 0 INT1/TI4 control: 0 = ZCD disable 1 = ZCD enable
+ 0 EDGE W 0 INT0 control: 0 = Level 1 = Rising edge
+
+----------------------------------------------------------------------------------------------------------------
+FFD2 WDMOD R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+ 7 WDTE R W 1 1 = WDT Enable
+ 6 WDTP1 R W 0 WDT detection time: 0 = 2^14/fc 0 = 2^16/fc 1 = 2^18/fc 1 = 2^20/fc
+ 5 WDTP0 R W 0 0 1 0 1
+ 4 WARM R W 0 Warming up time: 0 = 2^14/fc 1 = 2^16/fc
+ 3 HALTM1 R W 0 Standby mode: 0 = RUN 0 = STOP 1 = IDLE1 1 = IDLE2
+ 2 HALTM0 R W 0 0 1 0 1
+ 1 EXF R Undef Invert each time EXX instruction is executed
+ 0 DRIVE R W 0 1 to drive pins in stop mode
+
+----------------------------------------------------------------------------------------------------------------
+FFD4 TREG0 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-0 - W 0 Timer 0 match value
+
+----------------------------------------------------------------------------------------------------------------
+FFD5 TREG1 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-0 - W 0 Timer 0 match value
+
+----------------------------------------------------------------------------------------------------------------
+FFD6 TREG2 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-0 - W 0 Timer 0 match value
+
+----------------------------------------------------------------------------------------------------------------
+FFD7 TREG3 R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-0 - W 0 Timer 0 match value
+
+----------------------------------------------------------------------------------------------------------------
+FFD8 TCLK R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-6 T3CLK1-0R W 00 Timer 3 clock: 00 = Timer 2 01 = clock 10 = clock/16 11 = clock/256 <- Timer 2 overflow output in 16 bit mode
+5-4 T2CLK1-0R W 00 Timer 2 clock: 00 = - 01 = clock 10 = clock/16 11 = clock/256
+3-2 T1CLK1-0R W 00 Timer 1 clock: 00 = Timer 0 01 = clock 10 = clock/16 11 = clock/256 <- Timer 0 overflow output in 16 bit mode
+1-0 T0CLK1-0R W 00 Timer 0 clock: 00 = - 01 = clock 10 = clock/16 11 = clock/256
+
+----------------------------------------------------------------------------------------------------------------
+FFD9 TFFCR R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-6 TFF3C1-0 W - Timer 3 flip-flop: 00 = Clear 01 = Set 10 = Invert 11 = Don't care <- Always read as 11
+5 TFF3IE R W 0 Timer 3 Invert: 0 = Disable 1 = Enable
+4 TFF3IS R W 0 Timer 3 Invert: 0 = Timer 2 1 = Timer 3
+3-2 TFF1C1-0 W - Timer 1 Flip-Flop: 00 = Clear 01 = Set 10 = Invert 11 = Don't care <- Always read as 11
+1 TFF1IE R W 0 Timer 1 Invert: 0 = Disable 1 = Enable
+0 TFF1IS R W 0 Timer 1 Invert: 0 = Timer 0 1 = Timer 1
+
+----------------------------------------------------------------------------------------------------------------
+FFDA TMOD R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-6 T32M1-0 R W 00 Timers 2 & 3: 00 = 8b x 2 01 = 16b(T3+T2) 10 = 8b PPG(T3) 11 = 8b PWM (T3) + 8b (T2)
+5-4 PWM21-0 R W 00 Timer 3 PWM freq: 00 = - 01 = 63/fc 10 = 127/fc 11 = 255/fc
+3-2 T10M1-0 R W 00 Timers 1 & 0: 00 = 8b x 2 01 = 16b(T1+T0) 10 = 8b PPG(T1) 11 = 8b PWM (T1) + 8b (T0)
+1-0 PWM01-0 R W 00 Timer 1 PWM freq: 00 = - 01 = 63/fc 10 = 127/fc 11 = 255/fc
+
+----------------------------------------------------------------------------------------------------------------
+FFDB TRUN R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+7-6 BRATE1-0R W 00 Serial baud rate: 00 = 300/150 01 = 1200/600 10 = 4800/2400 11 = 19200/9600
+ 5 PRRUN R W 0 Prescaler control: 0 = Stop & Clear 1 = Run
+ 4 T4RUN R W 0 Timer 4 control: 0 = Stop & Clear 1 = Run
+3-0 T4RUN-0 R W 00 Timers 3-0 control: 0 = Stop & Clear 1 = Run
+
+----------------------------------------------------------------------------------------------------------------
+FFE6 INTEL R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+ 7 DET2 R W 0 INTT2/INTAD interrupt enable flag (1 = enable)
+ 6 DET3 R W 0 INTT3 ""
+ 5 DET4 R W 0 INTT4 ""
+ 4 DE1 R W 0 INT1 ""
+ 3 DET5 R W 0 INTT5 ""
+ 2 DE2 R W 0 INT2 ""
+ 1 DERX R W 0 INTRX ""
+ 0 DETX R W 0 INTTX ""
+
+----------------------------------------------------------------------------------------------------------------
+FFE7 INTEH R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+ 7 - R W 0 Write "0"
+ 6 DE0 R W 0 INT0 DMA enable flag (1 = enable)
+ 5 DET0 R W 0 INTT0 ""
+ 4 DET1 R W 0 INTT1 ""
+ 3 ADIS R W 0 INTT2/INTAD selection (1 = INTAD)
+ 2 IE0 R W 0 INT0 interrupt enable flag (1 = enable)
+ 1 IET0 R W 0 INTT0 ""
+ 0 IET1 R W 0 INTT1 ""
+
+----------------------------------------------------------------------------------------------------------------
+FFE8 DMAEH R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+ 7 DET2 R W 0 INTT2/INTAD DMA enable flag (1 = enable)
+ 6 DET3 R W 0 INTT3 ""
+ 5 DET4 R W 0 INTT4 ""
+ 4 DE1 R W 0 INT1 ""
+ 3 DET5 R W 0 INTT5 ""
+ 2 DE2 R W 0 INT2 ""
+ 1 DERX R W 0 INTRX ""
+ 0 DETX R W 0 INTTX ""
+
+----------------------------------------------------------------------------------------------------------------
+FFEC BX R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+ 7 - R 1
+ 6 - R 1
+ 5 - R 1
+ 4 - R 1
+ 3 BX3 R W 0 IX bank register bit 3
+ 2 BX2 R W 0 IX bank register bit 2
+ 1 BX1 R w 0 IX bank register bit 1
+ 0 BX0 R W 0 IX bank register bit 0
+
+----------------------------------------------------------------------------------------------------------------
+FFED BX R/W Reset Description
+----------------------------------------------------------------------------------------------------------------
+ 7 - R 1
+ 6 - R 1
+ 5 - R 1
+ 4 - R 1
+ 3 BY3 R W 0 IY bank register bit 3
+ 2 BY2 R W 0 IY bank register bit 2
+ 1 BY1 R w 0 IY bank register bit 1
+ 0 BY0 R W 0 IY bank register bit 0
+
+*************************************************************************************************************/
+
+static READ8_HANDLER( t90_internal_registers_r )
+{
+ #define RIO io_read_byte_8( T90_IOBASE+offset )
+
+ UINT8 data = T90.internal_registers[offset];
+ switch ( T90_IOBASE + offset )
+ {
+ case T90_P3: // 7,4,1,0
+ return (data & 0x6c) | (RIO & 0x93);
+
+// case T90_P4: // only output
+
+ case T90_P5:
+ return (RIO & 0x3f);
+
+ case T90_P6:
+ case T90_P7:
+ return (data & 0xf0) | (RIO & 0x0f);
+
+ case T90_P8: // 2,1,0
+ return (data & 0x08) | (RIO & 0x07);
+
+ case T90_BX:
+ case T90_BY:
+ return 0xf0 | data;
+ }
+ return data;
+}
+
+void t90_start_timer(int i)
+{
+ int prescaler;
+ attotime period;
+
+ T90.timer_value[i] = 0;
+
+ switch((T90.internal_registers[ T90_TMOD - T90_IOBASE ] >> (i * 2)) & 0x03)
+ {
+ case 0:
+ // 8-bit mode
+ break;
+ case 1:
+ // 16-bit mode
+ if (i & 1)
+ {
+ logerror("%04X: CPU Timer %d clocked by Timer %d overflow signal\n", activecpu_get_pc(), i,i-1);
+ return;
+ }
+ break;
+ case 2:
+ logerror("%04X: CPU Timer %d, unsupported PPG mode\n", activecpu_get_pc(), i);
+ return;
+ case 3:
+ logerror("%04X: CPU Timer %d, unsupported PWM mode\n", activecpu_get_pc(), i);
+ return;
+ }
+
+ switch((T90.internal_registers[ T90_TCLK - T90_IOBASE ] >> (i * 2)) & 0x03)
+ {
+ case 0: if (i & 1) logerror("%04X: CPU Timer %d clocked by Timer %d match signal\n", activecpu_get_pc(), i,i-1);
+ else logerror("%04X: CPU Timer %d, unsupported TCLK = 0\n", activecpu_get_pc(), i);
+ return;
+ case 2: prescaler = 16; break;
+ case 3: prescaler = 256; break;
+ default:
+ case 1: prescaler = 1; break;
+ }
+
+
+ period = attotime_mul(T90.timer_period, prescaler);
+
+ timer_adjust(T90.timer[i], period, i, period);
+
+ logerror("%04X: CPU Timer %d started at %lf Hz\n", activecpu_get_pc(), i, 1.0 / attotime_to_double(period));
+}
+
+void t90_start_timer4(void)
+{
+ int prescaler;
+ attotime period;
+
+ T90.timer4_value = 0;
+
+ switch(T90.internal_registers[ T90_T4MOD - T90_IOBASE ] & 0x03)
+ {
+ case 1: prescaler = 1; break;
+ case 2: prescaler = 16; break;
+ default: logerror("%04X: CPU Timer 4, unsupported T4MOD = %d\n", activecpu_get_pc(),T90.internal_registers[ T90_T4MOD - T90_IOBASE ] & 0x03);
+ return;
+ }
+
+ period = attotime_mul(T90.timer_period, prescaler);
+
+ timer_adjust(T90.timer[4], period, 4, period);
+
+ logerror("%04X: CPU Timer 4 started at %lf Hz\n", activecpu_get_pc(), 1.0 / attotime_to_double(period));
+}
+
+
+void t90_stop_timer(int i)
+{
+ timer_adjust(T90.timer[i], attotime_never, i, attotime_zero);
+ logerror("%04X: CPU Timer %d stopped\n", activecpu_get_pc(), i);
+}
+
+void t90_stop_timer4(void)
+{
+ t90_stop_timer(4);
+}
+
+static TIMER_CALLBACK( t90_timer_callback )
+{
+ int is16bit;
+ int i = param;
+
+ if ( (T90.internal_registers[ T90_TRUN - T90_IOBASE ] & (1 << i)) == 0 )
+ return;
+
+// logerror("CPU Timer %d fired! value = %d\n", i,(unsigned)T90.timer_value[i]);
+
+ T90.timer_value[i]++;
+
+ is16bit = ((T90.internal_registers[ T90_TMOD - T90_IOBASE ] >> (i/2 * 2 + 2)) & 0x03) == 1;
+
+ // Match
+
+ if ( T90.timer_value[i] == T90.internal_registers[ T90_TREG0+i - T90_IOBASE ] )
+ {
+// logerror("CPU Timer %d match\n", i);
+
+ if (is16bit)
+ {
+ if (i & 1)
+ {
+ if ( T90.timer_value[i-1] == T90.internal_registers[ T90_TREG0+i-1 - T90_IOBASE ] )
+ {
+ T90.timer_value[i] = 0;
+ T90.timer_value[i-1] = 0;
+
+ set_irq_line(INTT0 + i, 1);
+ }
+ }
+ else
+ set_irq_line(INTT0 + i, 1);
+ }
+ else
+ {
+ T90.timer_value[i] = 0;
+ set_irq_line(INTT0 + i, 1);
+ }
+
+ switch (i)
+ {
+ case 0:
+ case 2:
+ if ( !is16bit )
+ if ( (T90.internal_registers[ T90_TCLK - T90_IOBASE ] & (0x03 << (i * 2 + 2))) == 0 ) // T0/T1 match signal clocks T1/T3
+ t90_timer_callback(machine, i+1);
+ break;
+ }
+ }
+
+ // Overflow
+
+ if ( T90.timer_value[i] == 0 )
+ {
+// logerror("CPU Timer %d overflow\n", i);
+
+ switch (i)
+ {
+ case 0:
+ case 2:
+ if ( is16bit ) // T0/T1 overflow signal clocks T1/T3
+ t90_timer_callback(machine, i+1);
+ break;
+ }
+ }
+}
+
+static TIMER_CALLBACK( t90_timer4_callback )
+{
+// logerror("CPU Timer 4 fired! value = %d\n", (unsigned)T90.timer_value[4]);
+
+ T90.timer4_value++;
+
+ // Match
+
+ if ( T90.timer4_value == (T90.internal_registers[ T90_TREG4L - T90_IOBASE ] + (T90.internal_registers[ T90_TREG4H - T90_IOBASE ] << 8)) )
+ {
+// logerror("CPU Timer 4 matches TREG4\n");
+ set_irq_line(INTT4, 1);
+ }
+ if ( T90.timer4_value == (T90.internal_registers[ T90_TREG5L - T90_IOBASE ] + (T90.internal_registers[ T90_TREG5H - T90_IOBASE ] << 8)) )
+ {
+// logerror("CPU Timer 4 matches TREG5\n");
+ set_irq_line(INTT5, 1);
+ if (T90.internal_registers[ T90_T4MOD - T90_IOBASE ] & 0x04)
+ T90.timer4_value = 0;
+ }
+
+ // Overflow
+
+ if ( T90.timer_value == 0 )
+ {
+// logerror("CPU Timer 4 overflow\n");
+ }
+}
+
+static WRITE8_HANDLER( t90_internal_registers_w )
+{
+ #define WIO io_write_byte_8( T90_IOBASE+offset, data )
+
+ UINT8 out_mask;
+ UINT8 old = T90.internal_registers[offset];
+ switch ( T90_IOBASE + offset )
+ {
+ case T90_TRUN:
+ {
+ int i;
+ // Timers 0-3
+ for (i = 0; i < 4; i++)
+ {
+ if ( (old ^ data) & (0x20 | (1 << i)) ) // if timer bit or prescaler bit changed
+ {
+ if ( data == (0x20 | (1 << i)) ) t90_start_timer(i);
+ else t90_stop_timer(i);
+ }
+ }
+ // Timer 4
+ if ( (old ^ data) & (0x20 | 0x10) )
+ {
+ if ( data == (0x20 | 0x10) ) t90_start_timer4();
+ else t90_stop_timer4();
+ }
+ break;
+ }
+
+ case T90_INTEL:
+ T90.irq_mask &= ~( (1 << INTT2 ) |
+ (1 << INTT3 ) |
+ (1 << INTT4 ) |
+ (1 << INT1 ) |
+ (1 << INTT5 ) |
+ (1 << INT2 ) |
+ (1 << INTRX ) |
+ (1 << INTTX ) );
+
+ T90.irq_mask |= ((data & 0x80) ? (1 << INTT2 ) : 0) |
+ ((data & 0x40) ? (1 << INTT3 ) : 0) |
+ ((data & 0x20) ? (1 << INTT4 ) : 0) |
+ ((data & 0x10) ? (1 << INT1 ) : 0) |
+ ((data & 0x08) ? (1 << INTT5 ) : 0) |
+ ((data & 0x04) ? (1 << INT2 ) : 0) |
+ ((data & 0x02) ? (1 << INTRX ) : 0) |
+ ((data & 0x01) ? (1 << INTTX ) : 0) ;
+ break;
+
+ case T90_INTEH:
+ T90.irq_mask &= ~( (1 << INT0 ) |
+ (1 << INTT0) |
+ (1 << INTT1) );
+
+ T90.irq_mask |= ((data & 0x04) ? (1 << INT0 ) : 0) |
+ ((data & 0x02) ? (1 << INTT0) : 0) |
+ ((data & 0x01) ? (1 << INTT1) : 0) ;
+ break;
+
+ case T90_P3:
+ data &= 0x6c;
+ WIO;
+ break;
+
+ case T90_P4:
+ data &= 0x0f;
+ out_mask = (~T90.internal_registers[ T90_P4CR - T90_IOBASE ]) & 0x0f;
+ if (out_mask)
+ {
+ data &= out_mask;
+ WIO;
+ }
+ break;
+
+ case T90_P6:
+ out_mask = T90.internal_registers[ T90_P67CR - T90_IOBASE ] & 0x0f;
+ switch (T90.internal_registers[ T90_SMMOD - T90_IOBASE ] & 0x03)
+ {
+ case 1:
+ data &= ~0x01;
+ // add TO1 here
+ break;
+ case 2:
+ case 3:
+ data &= ~0x0f;
+ // add M0 here
+ break;
+ }
+
+ if (out_mask)
+ {
+ data &= out_mask;
+ WIO;
+ }
+ break;
+
+ case T90_P7:
+ out_mask = (T90.internal_registers[ T90_P67CR - T90_IOBASE ] & 0xf0) >> 4;
+ switch ((T90.internal_registers[ T90_SMMOD - T90_IOBASE ]>>4) & 0x03)
+ {
+ case 1:
+ data &= ~0x01;
+ // add TO3 here
+ break;
+ case 2:
+ case 3:
+ data &= ~0x0f;
+ // add M1 here
+ break;
+ }
+
+ if (out_mask)
+ {
+ data &= out_mask;
+ WIO;
+ }
+ break;
+
+ case T90_P8:
+ data &= 0x0f;
+ out_mask = (~T90.internal_registers[ T90_P8CR - T90_IOBASE ]) & 0x08;
+ if (out_mask)
+ {
+ data &= out_mask;
+ WIO;
+ }
+ break;
+
+ case T90_BX:
+ T90.ixbase = (data & 0xf) << 16;
+ break;
+ case T90_BY:
+ T90.iybase = (data & 0xf) << 16;
+ break;
+ }
+ T90.internal_registers[offset] = data;
+}
+
+static void t90_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int i, p;
+
+// state_save_register_item("z80", index, Z80.prvpc.w.l);
+
+ for (i = 0; i < 256; i++)
+ {
+ p = 0;
+ if( i&0x01 ) ++p;
+ if( i&0x02 ) ++p;
+ if( i&0x04 ) ++p;
+ if( i&0x08 ) ++p;
+ if( i&0x10 ) ++p;
+ if( i&0x20 ) ++p;
+ if( i&0x40 ) ++p;
+ if( i&0x80 ) ++p;
+ SZ[i] = i ? i & SF : ZF;
+// SZ[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */
+ SZ_BIT[i] = i ? i & SF : ZF | PF;
+// SZ_BIT[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */
+ SZP[i] = SZ[i] | ((p & 1) ? 0 : PF);
+ SZHV_inc[i] = SZ[i];
+ if( i == 0x80 ) SZHV_inc[i] |= VF;
+ if( (i & 0x0f) == 0x00 ) SZHV_inc[i] |= HF;
+ SZHV_dec[i] = SZ[i] | NF;
+ if( i == 0x7f ) SZHV_dec[i] |= VF;
+ if( (i & 0x0f) == 0x0f ) SZHV_dec[i] |= HF;
+ }
+
+ memset(&T90, 0, sizeof(T90));
+ T90.irq_callback = irqcallback;
+
+ T90.timer_period = attotime_mul(ATTOTIME_IN_HZ(cpunum_get_clock(cpu_getactivecpu())), 8);
+
+ // Reset registers to their initial values
+
+// IX = IY = 0xffff;
+// F = ZF;
+
+ // Timers
+
+ for (i = 0; i < 4; i++)
+ T90.timer[i] = timer_alloc(t90_timer_callback);
+
+ T90.timer[4] = timer_alloc(t90_timer4_callback);
+}
+
+static ADDRESS_MAP_START(tmp90840_mem, ADDRESS_SPACE_PROGRAM, 8)
+ AM_RANGE( 0x0000, 0x1fff ) AM_ROM // 8KB ROM (internal)
+ AM_RANGE( 0xfec0, 0xffc0 ) AM_RAM // 256b RAM (internal)
+ AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w )
+ADDRESS_MAP_END
+static ADDRESS_MAP_START(tmp90841_mem, ADDRESS_SPACE_PROGRAM, 8)
+// AM_RANGE( 0x0000, 0x1fff ) AM_ROM // rom-less
+ AM_RANGE( 0xfec0, 0xffc0 ) AM_RAM // 256b RAM (internal)
+ AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(tmp91640_mem, ADDRESS_SPACE_PROGRAM, 8)
+ AM_RANGE( 0x0000, 0x3fff ) AM_ROM // 16KB ROM (internal)
+ AM_RANGE( 0xfdc0, 0xffc0 ) AM_RAM // 512b RAM (internal)
+ AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w )
+ADDRESS_MAP_END
+static ADDRESS_MAP_START(tmp91641_mem, ADDRESS_SPACE_PROGRAM, 8)
+// AM_RANGE( 0x0000, 0x3fff ) AM_ROM // rom-less
+ AM_RANGE( 0xfdc0, 0xffc0 ) AM_RAM // 512b RAM (internal)
+ AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w )
+ADDRESS_MAP_END
+
+static void t90_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line( INTNMI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ0: set_irq_line( INT0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ1: set_irq_line( INT1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ2: set_irq_line( INT2, info->i); break;
+
+ case CPUINFO_INT_PC: change_pc( T90.pc.d = info->i ); break;
+ case CPUINFO_INT_REGISTER + T90_PC: T90.pc.w.l = info->i; break;
+ case CPUINFO_INT_SP: T90.sp.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_SP: T90.sp.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_A: T90.af.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_B: T90.bc.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_C: T90.bc.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_D: T90.de.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_E: T90.de.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_H: T90.hl.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_L: T90.hl.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_AF: T90.af.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_BC: T90.bc.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_DE: T90.de.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_HL: T90.hl.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_IX: T90.ix.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + T90_IY: T90.iy.w.l = info->i; break;
+ }
+}
+
+void tmp90840_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(T90); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 26; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 20; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = T90.irq_state & (1 << INTNMI); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ0: info->i = T90.irq_state & (1 << INT0); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ1: info->i = T90.irq_state & (1 << INT1); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ2: info->i = T90.irq_state & (1 << INT2); break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = T90.prvpc.w.l; break;
+ case CPUINFO_INT_PC: info->i = T90.pc.d; break;
+ case CPUINFO_INT_REGISTER + T90_PC: info->i = T90.pc.w.l; break;
+ case CPUINFO_INT_SP: info->i = T90.sp.d; break;
+ case CPUINFO_INT_REGISTER + T90_SP: info->i = T90.sp.w.l; break;
+ case CPUINFO_INT_REGISTER + T90_A: info->i = T90.af.b.h; break;
+ case CPUINFO_INT_REGISTER + T90_B: info->i = T90.bc.b.h; break;
+ case CPUINFO_INT_REGISTER + T90_C: info->i = T90.bc.b.l; break;
+ case CPUINFO_INT_REGISTER + T90_D: info->i = T90.de.b.h; break;
+ case CPUINFO_INT_REGISTER + T90_E: info->i = T90.de.b.l; break;
+ case CPUINFO_INT_REGISTER + T90_H: info->i = T90.hl.b.h; break;
+ case CPUINFO_INT_REGISTER + T90_L: info->i = T90.hl.b.l; break;
+ case CPUINFO_INT_REGISTER + T90_AF: info->i = T90.af.w.l; break;
+ case CPUINFO_INT_REGISTER + T90_BC: info->i = T90.bc.w.l; break;
+ case CPUINFO_INT_REGISTER + T90_DE: info->i = T90.de.w.l; break;
+ case CPUINFO_INT_REGISTER + T90_HL: info->i = T90.hl.w.l; break;
+ case CPUINFO_INT_REGISTER + T90_IX: info->i = T90.ix.w.l; break;
+ case CPUINFO_INT_REGISTER + T90_IY: info->i = T90.iy.w.l; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+
+ case CPUINFO_PTR_SET_INFO: info->setinfo = t90_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = t90_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = t90_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = t90_init; break;
+ case CPUINFO_PTR_RESET: info->reset = t90_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = t90_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = t90_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = t90_burn; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = t90_dasm; break;
+#endif
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &t90_ICount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_tmp90840_mem; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "TMP90840"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "Toshiba TLCS-90"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "Luca Elia"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s = cpuintrf_temp_str(), "%c%c%c%c%c%c%c%c",
+ F & 0x80 ? 'S':'.',
+ F & 0x40 ? 'Z':'.',
+ F & 0x20 ? 'I':'.',
+ F & 0x10 ? 'H':'.',
+ F & 0x08 ? 'X':'.',
+ F & 0x04 ? 'P':'.',
+ F & 0x02 ? 'N':'.',
+ F & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + T90_PC: sprintf(info->s = cpuintrf_temp_str(), "PC:%04X", T90.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + T90_SP: sprintf(info->s = cpuintrf_temp_str(), "SP:%04X", T90.sp.w.l); break;
+ case CPUINFO_STR_REGISTER + T90_A: sprintf(info->s = cpuintrf_temp_str(), "~A:%02X", T90.af.b.h); break;
+ case CPUINFO_STR_REGISTER + T90_B: sprintf(info->s = cpuintrf_temp_str(), "~B:%02X", T90.bc.b.h); break;
+ case CPUINFO_STR_REGISTER + T90_C: sprintf(info->s = cpuintrf_temp_str(), "~C:%02X", T90.bc.b.l); break;
+ case CPUINFO_STR_REGISTER + T90_D: sprintf(info->s = cpuintrf_temp_str(), "~D:%02X", T90.de.b.h); break;
+ case CPUINFO_STR_REGISTER + T90_E: sprintf(info->s = cpuintrf_temp_str(), "~E:%02X", T90.de.b.l); break;
+ case CPUINFO_STR_REGISTER + T90_H: sprintf(info->s = cpuintrf_temp_str(), "~H:%02X", T90.hl.b.h); break;
+ case CPUINFO_STR_REGISTER + T90_L: sprintf(info->s = cpuintrf_temp_str(), "~L:%02X", T90.hl.b.l); break;
+ case CPUINFO_STR_REGISTER + T90_AF: sprintf(info->s = cpuintrf_temp_str(), "AF:%04X", T90.af.w.l); break;
+ case CPUINFO_STR_REGISTER + T90_BC: sprintf(info->s = cpuintrf_temp_str(), "BC:%04X", T90.bc.w.l); break;
+ case CPUINFO_STR_REGISTER + T90_DE: sprintf(info->s = cpuintrf_temp_str(), "DE:%04X", T90.de.w.l); break;
+ case CPUINFO_STR_REGISTER + T90_HL: sprintf(info->s = cpuintrf_temp_str(), "HL:%04X", T90.hl.w.l); break;
+ case CPUINFO_STR_REGISTER + T90_IX: sprintf(info->s = cpuintrf_temp_str(), "IX:%04X", T90.ix.w.l); break;
+ case CPUINFO_STR_REGISTER + T90_IY: sprintf(info->s = cpuintrf_temp_str(), "IY:%04X", T90.iy.w.l); break;
+ }
+}
+
+void tmp90841_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_tmp90841_mem; return;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "TMP90841"); return;
+ }
+
+ tmp90840_get_info(state,info);
+}
+
+void tmp91640_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_tmp91640_mem; return;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "TMP91640"); return;
+ }
+
+ tmp90840_get_info(state,info);
+}
+
+void tmp91641_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_tmp91641_mem; return;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "TMP91641"); return;
+ }
+
+ tmp90840_get_info(state,info);
+}
diff --git a/src/emu/cpu/tlcs90/tlcs90.h b/src/emu/cpu/tlcs90/tlcs90.h
new file mode 100644
index 00000000000..fc750a00c1d
--- /dev/null
+++ b/src/emu/cpu/tlcs90/tlcs90.h
@@ -0,0 +1,26 @@
+#ifndef TLCS90_INCLUDE
+#define TLCS90_INCLUDE
+
+#include "cpuintrf.h"
+
+void tmp90840_get_info(UINT32, cpuinfo*);
+void tmp90841_get_info(UINT32, cpuinfo*);
+void tmp91640_get_info(UINT32, cpuinfo*);
+void tmp91641_get_info(UINT32, cpuinfo*);
+
+#ifdef MAME_DEBUG
+unsigned t90_dasm(char *buffer, UINT32 oldpc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#define T90_IOBASE 0xffc0
+
+typedef enum {
+ T90_P0=T90_IOBASE, T90_P1, T90_P01CR_IRFL, T90_IRFH, T90_P2, T90_P2CR, T90_P3, T90_P3CR,
+ T90_P4, T90_P4CR, T90_P5, T90_SMMOD, T90_P6, T90_P7, T90_P67CR, T90_SMCR,
+ T90_P8, T90_P8CR, T90_WDMOD, T90_WDCR, T90_TREG0, T90_TREG1, T90_TREG2, T90_TREG3,
+ T90_TCLK, T90_TFFCR, T90_TMOD, T90_TRUN, T90_CAP1L, T90_CAP1H, T90_CAP2L, T90_CAL2H,
+ T90_TREG4L, T90_TREG4H, T90_TREG5L, T90_TREG5H, T90_T4MOD, T90_T4FFCR, T90_INTEL, T90_INTEH,
+ T90_DMAEH, T90_SCMOD, T90_SCCR, T90_SCBUF, T90_BX, T90_BY, T90_ADREG, T90_ADMOD
+} e_ir;
+
+#endif
diff --git a/src/emu/cpu/tms32010/32010dsm.c b/src/emu/cpu/tms32010/32010dsm.c
new file mode 100644
index 00000000000..9c78d4deb68
--- /dev/null
+++ b/src/emu/cpu/tms32010/32010dsm.c
@@ -0,0 +1,349 @@
+ /**************************************************************************\
+ * Texas Instruments TMS32010 DSP Disassembler *
+ * *
+ * Copyright (C) 1999-2002+ Tony La Porta *
+ * To be used with TMS32010 DSP Emulator engine. *
+ * You are not allowed to distribute this software commercially. *
+ * Written for the MAME project. *
+ * *
+ * Many thanks to those involved in the i8039 Disassembler *
+ * as this was based on it. *
+ * *
+ * *
+ * *
+ * A Memory address *
+ * B Branch Address for Branch instructions (Requires next opcode read) *
+ * D Immediate byte load *
+ * K Immediate bit load *
+ * W Immediate word load (Actually 13 bit) *
+ * M AR[x] register modification type (for indirect addressing) *
+ * N ARP register to change ARP pointer to (for indirect addressing) *
+ * P I/O port address number *
+ * R AR[R] register to use *
+ * S Shift ALU left *
+ * *
+ \**************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef MAME_DEBUG /* Compile interface to MAME */
+#include "cpuintrf.h"
+#include "tms32010.h"
+#include "debugger.h"
+#else /* Compile interface for standalone */
+extern unsigned char *Buffer;
+#ifdef MSB_FIRST
+#define READOP16(A) ( ((Buffer[A+1]<<8) | Buffer[A]) )
+#define READARG16(A) ( ((Buffer[A+1]<<8) | Buffer[A]) )
+#else
+#define READOP16(A) ( ((Buffer[A]<<8) | Buffer[A+1]) )
+#define READARG16(A) ( ((Buffer[A]<<8) | Buffer[A+1]) )
+#endif
+#endif
+
+
+
+typedef unsigned char byte;
+typedef unsigned short int word;
+
+#define FMT(a,b) a, b
+#define PTRS_PER_FORMAT 2
+
+static const char *arith[4] = { "*" , "*-" , "*+" , "??" } ;
+static const char *nextar[4] = { ",AR0" , ",AR1" , "" , "" } ;
+
+
+static const char *TMS32010Formats[] = {
+ FMT("0000ssss0aaaaaaa", "add %A%S"),
+ FMT("0000ssss10mmn00n", "add %M%S%N"),
+ FMT("0001ssss0aaaaaaa", "sub %A%S"),
+ FMT("0001ssss10mmn00n", "sub %M%S%N"),
+ FMT("0010ssss0aaaaaaa", "lac %A%S"),
+ FMT("0010ssss10mmn00n", "lac %M%S%N"),
+ FMT("0011000r0aaaaaaa", "sar %R,%A"),
+ FMT("0011000r10mmn00n", "sar %R%M%N"),
+ FMT("0011100r0aaaaaaa", "lar %R,%A"),
+ FMT("0011100r10mmn00n", "lar %R%M%N"),
+ FMT("01000ppp0aaaaaaa", "in %A,%P"),
+ FMT("01000ppp10mmn00n", "in %M,%P%N"),
+ FMT("01001ppp0aaaaaaa", "out %A,%P"),
+ FMT("01001ppp10mmn00n", "out %M,%P%N"),
+ FMT("01010sss0aaaaaaa", "sacl %A"), /* This instruction has a shift but */
+ FMT("01010sss10mmn00n", "sacl %M%N"), /* is documented as not performed */
+ FMT("01011sss0aaaaaaa", "sach %A%S"),
+ FMT("01011sss10mmn00n", "sach %M%S%N"),
+ FMT("011000000aaaaaaa", "addh %A"),
+ FMT("0110000010mmn00n", "addh %M%N"),
+ FMT("011000010aaaaaaa", "adds %A"),
+ FMT("0110000110mmn00n", "adds %M%N"),
+ FMT("011000100aaaaaaa", "subh %A"),
+ FMT("0110001010mmn00n", "subh %M%N"),
+ FMT("011000110aaaaaaa", "subs %A"),
+ FMT("0110001110mmn00n", "subs %M%N"),
+ FMT("011001000aaaaaaa", "subc %A"),
+ FMT("0110010010mmn00n", "subc %M%N"),
+ FMT("011001010aaaaaaa", "zalh %A"),
+ FMT("0110010110mmn00n", "zalh %M%N"),
+ FMT("011001100aaaaaaa", "zals %A"),
+ FMT("0110011010mmn00n", "zals %M%N"),
+ FMT("011001110aaaaaaa", "tblr %A"),
+ FMT("0110011110mmn00n", "tblr %M%N"),
+ FMT("011010001000000k", "larp %K"),
+ FMT("011010000aaaaaaa", "mar %A"), /* Actually this is executed as a NOP */
+/* FMT("0110100010mmn00n", "mar %M%N"), */
+/* MAR indirect has been expanded out to all its variations because one of */
+/* its opcodes is the same as LARP (actually performs the same function) */
+
+ FMT("0110100010001000", "mar *"),
+ FMT("0110100010001001", "mar *"),
+ FMT("0110100010010000", "mar *-,AR0"),
+ FMT("0110100010010001", "mar *-,AR1"),
+ FMT("0110100010011000", "mar *-"),
+ FMT("0110100010011001", "mar *-"),
+ FMT("0110100010100000", "mar *+,AR0"),
+ FMT("0110100010100001", "mar *+,AR1"),
+ FMT("0110100010101000", "mar *+"),
+ FMT("0110100010101001", "mar *+"),
+ FMT("0110100010110000", "mar ??,AR0"),
+ FMT("0110100010110001", "mar ??,AR1"),
+ FMT("0110100010111000", "mar ??"),
+ FMT("0110100010111001", "mar ??"),
+
+ FMT("011010010aaaaaaa", "dmov %A"),
+ FMT("0110100110mmn00n", "dmov %M%N"),
+ FMT("011010100aaaaaaa", "lt %A"),
+ FMT("0110101010mmn00n", "lt %M%N"),
+ FMT("011010110aaaaaaa", "ltd %A"),
+ FMT("0110101110mmn00n", "ltd %M%N"),
+ FMT("011011000aaaaaaa", "lta %A"),
+ FMT("0110110010mmn00n", "lta %M%N"),
+ FMT("011011010aaaaaaa", "mpy %A"),
+ FMT("0110110110mmn00n", "mpy %M%N"),
+ FMT("011011100000000k", "ldpk %K"),
+ FMT("011011110aaaaaaa", "ldp %A"),
+ FMT("0110111110mmn00n", "ldp %M%N"),
+ FMT("0111000rdddddddd", "lark %R,%D"),
+ FMT("011110000aaaaaaa", "xor %A"),
+ FMT("0111100010mmn00n", "xor %M%N"),
+ FMT("011110010aaaaaaa", "and %A"),
+ FMT("0111100110mmn00n", "and %M%N"),
+ FMT("011110100aaaaaaa", "or %A"),
+ FMT("0111101010mmn00n", "or %M%N"),
+ FMT("011110110aaaaaaa", "lst %A"),
+ FMT("0111101110mmn00n", "lst %M%N"),
+ FMT("011111000aaaaaaa", "sst %A"),
+ FMT("0111110010mmn00n", "sst %M%N"),
+ FMT("011111010aaaaaaa", "tblw %A"),
+ FMT("0111110110mmn00n", "tblw %M%N"),
+ FMT("01111110dddddddd", "lack %D"),
+ FMT("0111111110000000", "nop"), /* 7F80 */
+ FMT("0111111110000001", "dint"),
+ FMT("0111111110000010", "eint"),
+ FMT("0111111110001000", "abs"), /* 7F88 */
+ FMT("0111111110001001", "zac"),
+ FMT("0111111110001010", "rovm"),
+ FMT("0111111110001011", "sovm"),
+ FMT("0111111110001100", "cala"),
+ FMT("0111111110001101", "ret"),
+ FMT("0111111110001110", "pac"),
+ FMT("0111111110001111", "apac"),
+ FMT("0111111110010000", "spac"),
+ FMT("0111111110011100", "push"),
+ FMT("0111111110011101", "pop"), /* 7F9D */
+ FMT("100wwwwwwwwwwwww", "mpyk %W"),
+ FMT("1111010000000000bbbbbbbbbbbbbbbb", "banz %B"),
+ FMT("1111010100000000bbbbbbbbbbbbbbbb", "bv %B"),
+ FMT("1111011000000000bbbbbbbbbbbbbbbb", "bioz %B"),
+ FMT("1111100000000000bbbbbbbbbbbbbbbb", "call %B"),
+ FMT("1111100100000000bbbbbbbbbbbbbbbb", "b %B"),
+ FMT("1111101000000000bbbbbbbbbbbbbbbb", "blz %B"),
+ FMT("1111101100000000bbbbbbbbbbbbbbbb", "blez %B"),
+ FMT("1111110000000000bbbbbbbbbbbbbbbb", "bgz %B"),
+ FMT("1111110100000000bbbbbbbbbbbbbbbb", "bgez %B"),
+ FMT("1111111000000000bbbbbbbbbbbbbbbb", "bnz %B"),
+ FMT("1111111100000000bbbbbbbbbbbbbbbb", "bz %B"),
+ NULL
+};
+
+#define MAX_OPS (((sizeof(TMS32010Formats) / sizeof(TMS32010Formats[0])) - 1) / PTRS_PER_FORMAT)
+
+typedef struct opcode {
+ word mask; /* instruction mask */
+ word bits; /* constant bits */
+ word extcode; /* value that gets extension code */
+ const char *parse; /* how to parse bits */
+ const char *fmt; /* instruction format */
+} TMS32010Opcode;
+
+static TMS32010Opcode Op[MAX_OPS+1];
+static int OpInizialized = 0;
+
+static void InitDasm32010(void)
+{
+ const char *p, **ops;
+ word mask, bits;
+ int bit;
+ int i;
+
+ ops = TMS32010Formats; i = 0;
+ while (*ops)
+ {
+ p = *ops;
+ mask = 0; bits = 0; bit = 15;
+ while (*p && bit >= 0)
+ {
+ switch (*p++)
+ {
+ case '1': mask |= 1<<bit; bits |= 1<<bit; bit--; break;
+ case '0': mask |= 1<<bit; bit--; break;
+ case ' ': break;
+ case 'a':
+ case 'b':
+ case 'd':
+ case 'k':
+ case 'm':
+ case 'n':
+ case 'p':
+ case 'r':
+ case 's':
+ case 'w':
+ bit --;
+ break;
+ default: fatalerror("Invalid instruction encoding '%s %s'",
+ ops[0],ops[1]);
+ }
+ }
+ if (bit != -1 )
+ {
+ fatalerror("not enough bits in encoding '%s %s' %d",
+ ops[0],ops[1],bit);
+ }
+ while (isspace(*p)) p++;
+ if (*p) Op[i].extcode = *p;
+ Op[i].bits = bits;
+ Op[i].mask = mask;
+ Op[i].fmt = ops[1];
+ Op[i].parse = ops[0];
+
+ ops += PTRS_PER_FORMAT;
+ i++;
+ }
+
+ OpInizialized = 1;
+}
+
+offs_t tms32010_dasm(char *str, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ int a, b, d, k, m, n, p, r, s, w; /* these can all be filled in by parsing an instruction */
+ int i;
+ int op;
+ int cnt = 1;
+ int code;
+ int bit;
+ char *strtmp;
+ const char *cp; /* character pointer in OpFormats */
+
+ if (!OpInizialized) InitDasm32010();
+
+ op = -1; /* no matching opcode */
+ code = (oprom[0] << 8) | oprom[1];
+ for ( i = 0; i < MAX_OPS; i++)
+ {
+ if ((code & Op[i].mask) == Op[i].bits)
+ {
+ if (op != -1)
+ {
+ mame_printf_debug("Error: opcode %04Xh matches %d (%s) and %d (%s)\n",
+ code,i,Op[i].fmt,op,Op[op].fmt);
+ }
+ op = i;
+ }
+ }
+ if (op == -1)
+ {
+ sprintf(str,"???? dw %04Xh",code);
+ return cnt | DASMFLAG_SUPPORTED;
+ }
+ strtmp = str;
+ if (Op[op].extcode)
+ {
+ bit = 31;
+ code <<= 16;
+ code |= (opram[2] << 8) | opram[3];
+ cnt++;
+ }
+ else
+ {
+ bit = 15;
+ }
+
+ /* shift out operands */
+ cp = Op[op].parse;
+ a = b = d = k = m = n = p = r = s = w = 0;
+
+ while (bit >= 0)
+ {
+ /* mame_printf_debug("{%c/%d}",*cp,bit); */
+ switch(*cp)
+ {
+ case 'a': a <<=1; a |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'b': b <<=1; b |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'd': d <<=1; d |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'k': k <<=1; k |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'm': m <<=1; m |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'n': n <<=1; n |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'p': p <<=1; p |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'r': r <<=1; r |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 's': s <<=1; s |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'w': w <<=1; w |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case ' ': break;
+ case '1': case '0': bit--; break;
+ case '\0': fatalerror("premature end of parse string, opcode %x, bit = %d",code,bit);
+ }
+ cp++;
+ }
+
+ /* now traverse format string */
+ cp = Op[op].fmt;
+
+ if (!strncmp(cp, "cal", 3))
+ flags = DASMFLAG_STEP_OVER;
+ else if (!strncmp(cp, "ret", 3))
+ flags = DASMFLAG_STEP_OUT;
+
+ while (*cp)
+ {
+ if (*cp == '%')
+ {
+ char num[20], *q;
+ cp++;
+ switch (*cp++)
+ {
+ case 'A': sprintf(num,"$%02X",a); break;
+ case 'B': sprintf(num,"$%04X",b); break;
+ case 'D': sprintf(num,"%02Xh",d); break;
+ case 'K': sprintf(num,"%d",k); break;
+ case 'N': sprintf(num,"%s",nextar[n]); break;
+ case 'M': sprintf(num,"%s",arith[m]); break;
+ case 'P': sprintf(num,"PA%d",p); break;
+ case 'R': sprintf(num,"AR%d",r); break;
+ case 'S': sprintf(num,",%d",s); break;
+ case 'W': sprintf(num,"%04Xh",w); break;
+ default:
+ fatalerror("illegal escape character in format '%s'",Op[op].fmt);
+ }
+ q = num; while (*q) *str++ = *q++;
+ *str = '\0';
+ }
+ else
+ {
+ *str++ = *cp++;
+ *str = '\0';
+ }
+ }
+ return cnt | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/tms32010/dis32010.c b/src/emu/cpu/tms32010/dis32010.c
new file mode 100644
index 00000000000..a3c8c0fd806
--- /dev/null
+++ b/src/emu/cpu/tms32010/dis32010.c
@@ -0,0 +1,136 @@
+ /**************************************************************************\
+ * Texas Instruments TMS32010 DSP Disassembler *
+ * *
+ * Copyright (C) 1999-2002+ Tony La Porta *
+ * You are not allowed to distribute this software commercially. *
+ * Written for the MAME project. *
+ * *
+ * Notes : Data is expected to be read from source file as MSB first. *
+ * This is a word based microcontroller, with addressing *
+ * architecture based on the Harvard addressing scheme. *
+ * *
+ \**************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "32010dsm.c"
+
+
+unsigned char *Buffer;
+
+
+int main(int argc,char *argv[])
+{
+ int length=0, length_to_dump=0, offset=0, disasm_words=0;
+ int filelength=0, bytes_read;
+ int Counter=0;
+
+ FILE *F;
+ char *String_Output;
+
+ if(argc<2)
+ {
+ printf("\n");
+ printf("TMS32010 Disassembler 1.1 by Tony La Porta (C)1999-2002+\n\n");
+ printf("Usage: dis32010 <input-file> [ <start-addr> [ <num-of-addr> ] ]\n");
+ printf(" <input-file> source file data must be MSB first\n");
+ printf(" <start-addr> starting address to disassemble from (decimal)\n");
+ printf(" <num-of-addr> number of addresses to disassemble (decimal)\n");
+ printf(" Preceed values with 0x if HEX values preffered\n");
+ exit(1);
+ }
+
+ if(!(F=fopen(argv[1],"rb")))
+ {
+ printf("\n%s: Can't open file %s\n",argv[0],argv[1]);
+ exit(2);
+ }
+ argv++; argc--;
+ if (argv[1])
+ {
+ offset = strtol(argv[1],NULL,0);
+ argv++; argc--;
+ }
+ if (argv[1])
+ {
+ length = strtol(argv[1],NULL,0);
+ argv++; argc--;
+ }
+
+ fseek(F,0, SEEK_END);
+ filelength = ftell(F);
+
+ length *= 2;
+
+ if ((length > (filelength - (offset*2))) || (length == 0)) length = filelength - (offset*2);
+ printf("Length=%04Xh(words) Offset=$%04Xh filelength=%04Xh(words) %04Xh(bytes)\n",length/2,offset,filelength/2,filelength);
+ length_to_dump = length;
+ printf("Starting from %d, dumping %d opcodes (word size)\n",offset,length/2);
+ Buffer = calloc((filelength+1),sizeof(char));
+ if (Buffer==NULL)
+ {
+ printf("Out of Memory !!!");
+ fclose(F);
+ exit(3);
+ }
+ String_Output = calloc(80,sizeof(char));
+ if (String_Output==NULL)
+ {
+ printf("Out of Memory !!!");
+ free(Buffer);
+ fclose(F);
+ exit(4);
+ }
+
+ if (fseek(F,0,SEEK_SET) != 0)
+ {
+ printf("Error seeking to beginning of file\n");
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ exit(5);
+ }
+
+ Counter = offset;
+ bytes_read = fread(Buffer,sizeof(char),filelength,F);
+ if (bytes_read >= length)
+ {
+ for (; length > 0; length -= (disasm_words*2))
+ {
+ int ii;
+ disasm_words = Dasm32010(String_Output,Counter);
+ printf("$%04lX: ",Counter);
+ for (ii = 0; ii < disasm_words; ii++)
+ {
+ if (((Counter*2) + ii) > filelength) /* Past end of length to dump ? */
+ {
+ sprintf(String_Output,"???? dw %02.2X%02.2Xh (Past end of disassembly !)",Buffer[((Counter-1)*2)],Buffer[((Counter-1)*2)+1]);
+ }
+ else
+ {
+ printf("%02.2x%02.2x ",Buffer[(Counter*2)],Buffer[(Counter*2) + 1]);
+ }
+ Counter++ ;
+ }
+ for (; ii < 4; ii++)
+ {
+ printf(" ");
+ }
+ printf("\t%s\n",String_Output);
+ }
+ }
+ else
+ {
+ printf("ERROR length to dump was %d ", length_to_dump/2);
+ printf(", but bytes read from file were %d\n", bytes_read/2);
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ exit(7);
+ }
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ return(0);
+}
diff --git a/src/emu/cpu/tms32010/tms32010.c b/src/emu/cpu/tms32010/tms32010.c
new file mode 100644
index 00000000000..c7c7105381b
--- /dev/null
+++ b/src/emu/cpu/tms32010/tms32010.c
@@ -0,0 +1,982 @@
+ /**************************************************************************\
+ * Texas Instruments TMS32010 DSP Emulator *
+ * *
+ * Copyright (C) 1999-2004+ Tony La Porta *
+ * You are not allowed to distribute this software commercially. *
+ * Written for the MAME project. *
+ * *
+ * *
+ * Notes : The term 'DMA' within this document, is in reference *
+ * to Direct Memory Addressing, and NOT the usual term *
+ * of Direct Memory Access. *
+ * This is a word based microcontroller, with addressing *
+ * architecture based on the Harvard addressing scheme. *
+ * *
+ * *
+ * *
+ * **** Change Log **** *
+ * *
+ * TLP (13-Jul-2002) *
+ * - Added Save-State support *
+ * - Converted the pending_irq flag to INTF (a real flag in this device) *
+ * - Fixed the ignore Interrupt Request for previous critical *
+ * instructions requiring an extra instruction to be processed. For *
+ * this reason, instant IRQ servicing cannot be supported here, so *
+ * INTF needs to be polled within the instruction execution loop *
+ * - Removed IRQ callback (IRQ ACK not supported on this device) *
+ * - A pending IRQ will remain pending until it's serviced. De-asserting *
+ * the IRQ Pin does not remove a pending IRQ state *
+ * - BIO is no longer treated as an IRQ line. It's polled when required. *
+ * This is the true behaviour of the device *
+ * - Removed the Clear OV flag from overflow instructions. Overflow *
+ * instructions can only set the flag. Flag test instructions clear it *
+ * - Fixed the ABST, SUBC and SUBH instructions *
+ * - Fixed the signedness in many equation based instructions *
+ * - Added the missing Previous PC to the get_register function *
+ * - Changed Cycle timings to include clock ticks *
+ * - Converted some registers from ints to pairs for much cleaner code *
+ * TLP (20-Jul-2002) Ver 1.10 *
+ * - Fixed the dissasembly from the debugger *
+ * - Changed all references from TMS320C10 to TMS32010 *
+ * ASG (24-Sep-2002) Ver 1.20 *
+ * - Fixed overflow handling *
+ * - Simplified logic in a few locations *
+ * TLP (22-Feb-2004) Ver 1.21 *
+ * - Overflow for ADDH only affects upper 16bits (was modifying 32 bits) *
+ * - Internal Data Memory map is assigned here now *
+ * - Cycle counts for invalid opcodes 7F1E and 7F1F are now 0 *
+ * RK (23-Nov-2006) Ver 1.22 *
+ * - Fixed state of the Overflow Flag on reset *
+ * - Fixed the SUBC instruction which was incorrectly zeroing the divisor *
+ * *
+ \**************************************************************************/
+
+
+
+#include "tms32010.h"
+#include "debugger.h"
+
+
+/* 1 cycle equals 4 clock ticks */
+#if 0
+#define CLK TMS32010_CLOCK_DIVIDER
+#else
+#define CLK 1 /* Moved the clock timing back into the driver */
+#endif
+
+
+#ifndef INLINE
+#define INLINE static inline
+#endif
+
+
+#define M_RDROM(A) TMS32010_ROM_RDMEM(A)
+#define M_WRTROM(A,V) TMS32010_ROM_WRMEM(A,V)
+#define M_RDRAM(A) TMS32010_RAM_RDMEM(A)
+#define M_WRTRAM(A,V) TMS32010_RAM_WRMEM(A,V)
+#define M_RDOP(A) TMS32010_RDOP(A)
+#define M_RDOP_ARG(A) TMS32010_RDOP_ARG(A)
+#define P_IN(A) TMS32010_In(A)
+#define P_OUT(A,V) TMS32010_Out(A,V)
+#define BIO_IN TMS32010_BIO_In
+
+
+
+typedef struct /* Page 3-6 shows all registers */
+{
+ /******************** CPU Internal Registers *******************/
+ UINT16 PC;
+ UINT16 PREVPC; /* previous program counter */
+ UINT16 STR;
+ PAIR ACC;
+ PAIR ALU;
+ PAIR Preg;
+ UINT16 Treg;
+ UINT16 AR[2];
+ UINT16 STACK[4];
+
+ /********************** Status data ****************************/
+ PAIR opcode;
+ int INTF; /* Pending Interrupt flag */
+} tms32010_Regs;
+
+static tms32010_Regs R;
+static PAIR oldacc;
+static UINT16 memaccess;
+static int tms32010_icount;
+static int addr_mask;
+typedef void (*opcode_fn) (void);
+
+
+/******** The following is the Status (Flag) register definition. *********/
+/* 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
+/* OV | OVM | INTM | 1 | 1 | 1 | 1 | ARP | 1 | 1 | 1 | 1 | 1 | 1 | 1 | DP */
+#define OV_FLAG 0x8000 /* OV (Overflow flag) 1 indicates an overflow */
+#define OVM_FLAG 0x4000 /* OVM (Overflow Mode bit) 1 forces ACC overflow to greatest positive or negative saturation value */
+#define INTM_FLAG 0x2000 /* INTM (Interrupt Mask flag) 0 enables maskable interrupts */
+#define ARP_REG 0x0100 /* ARP (Auxiliary Register Pointer) */
+#define DP_REG 0x0001 /* DP (Data memory Pointer (bank) bit) */
+
+#define OV ( R.STR & OV_FLAG) /* OV (Overflow flag) */
+#define OVM ( R.STR & OVM_FLAG) /* OVM (Overflow Mode bit) 1 indicates an overflow */
+#define INTM ( R.STR & INTM_FLAG) /* INTM (Interrupt enable flag) 0 enables maskable interrupts */
+#define ARP ((R.STR & ARP_REG) >> 8) /* ARP (Auxiliary Register Pointer) */
+#define DP ((R.STR & DP_REG) << 7) /* DP (Data memory Pointer bit) */
+
+#define DMA_DP (DP | (R.opcode.b.l & 0x7f)) /* address used in direct memory access operations */
+#define DMA_DP1 (0x80 | R.opcode.b.l) /* address used in direct memory access operations for sst instruction */
+#define IND (R.AR[ARP] & 0xff) /* address used in indirect memory access operations */
+
+
+
+
+/************************************************************************
+ * Shortcuts
+ ************************************************************************/
+
+INLINE void CLR(UINT16 flag) { R.STR &= ~flag; R.STR |= 0x1efe; }
+INLINE void SET(UINT16 flag) { R.STR |= flag; R.STR |= 0x1efe; }
+
+
+INLINE void CALCULATE_ADD_OVERFLOW(INT32 addval)
+{
+ if ((INT32)(~(oldacc.d ^ addval) & (oldacc.d ^ R.ACC.d)) < 0) {
+ SET(OV_FLAG);
+ if (OVM)
+ R.ACC.d = ((INT32)oldacc.d < 0) ? 0x80000000 : 0x7fffffff;
+ }
+}
+INLINE void CALCULATE_SUB_OVERFLOW(INT32 subval)
+{
+ if ((INT32)((oldacc.d ^ subval) & (oldacc.d ^ R.ACC.d)) < 0) {
+ SET(OV_FLAG);
+ if (OVM)
+ R.ACC.d = ((INT32)oldacc.d < 0) ? 0x80000000 : 0x7fffffff;
+ }
+}
+
+INLINE UINT16 POP_STACK(void)
+{
+ UINT16 data = R.STACK[3];
+ R.STACK[3] = R.STACK[2];
+ R.STACK[2] = R.STACK[1];
+ R.STACK[1] = R.STACK[0];
+ return (data & addr_mask);
+}
+INLINE void PUSH_STACK(UINT16 data)
+{
+ R.STACK[0] = R.STACK[1];
+ R.STACK[1] = R.STACK[2];
+ R.STACK[2] = R.STACK[3];
+ R.STACK[3] = (data & addr_mask);
+}
+
+INLINE void GET_MEM_ADDR(UINT16 DMA)
+{
+ if (R.opcode.b.l & 0x80)
+ memaccess = IND;
+ else
+ memaccess = DMA;
+}
+INLINE void UPDATE_AR(void)
+{
+ if (R.opcode.b.l & 0x30) {
+ UINT16 tmpAR = R.AR[ARP];
+ if (R.opcode.b.l & 0x20) tmpAR++ ;
+ if (R.opcode.b.l & 0x10) tmpAR-- ;
+ R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
+ }
+}
+INLINE void UPDATE_ARP(void)
+{
+ if (~R.opcode.b.l & 0x08) {
+ if (R.opcode.b.l & 0x01) SET(ARP_REG);
+ else CLR(ARP_REG);
+ }
+}
+
+
+INLINE void getdata(UINT8 shift,UINT8 signext)
+{
+ GET_MEM_ADDR(DMA_DP);
+ R.ALU.d = (UINT16)M_RDRAM(memaccess);
+ if (signext) R.ALU.d = (INT16)R.ALU.d;
+ R.ALU.d <<= shift;
+ if (R.opcode.b.l & 0x80) {
+ UPDATE_AR();
+ UPDATE_ARP();
+ }
+}
+
+INLINE void putdata(UINT16 data)
+{
+ GET_MEM_ADDR(DMA_DP);
+ if (R.opcode.b.l & 0x80) {
+ UPDATE_AR();
+ UPDATE_ARP();
+ }
+ M_WRTRAM(memaccess,data);
+}
+INLINE void putdata_sar(UINT8 data)
+{
+ GET_MEM_ADDR(DMA_DP);
+ if (R.opcode.b.l & 0x80) {
+ UPDATE_AR();
+ UPDATE_ARP();
+ }
+ M_WRTRAM(memaccess,R.AR[data]);
+}
+INLINE void putdata_sst(UINT16 data)
+{
+ GET_MEM_ADDR(DMA_DP1); /* Page 1 only */
+ if (R.opcode.b.l & 0x80) {
+ UPDATE_AR();
+ }
+ M_WRTRAM(memaccess,data);
+}
+
+
+
+/************************************************************************
+ * Emulate the Instructions
+ ************************************************************************/
+
+/* This following function is here to fill in the void for */
+/* the opcode call function. This function is never called. */
+
+static void other_7F_opcodes(void) { }
+
+
+static void illegal(void)
+{
+ logerror("TMS32010: PC=%04x, Illegal opcode = %04x\n", (R.PC-1), R.opcode.w.l);
+}
+
+static void abst(void)
+{
+ if ( (INT32)(R.ACC.d) < 0 ) {
+ R.ACC.d = -R.ACC.d;
+ if (OVM && (R.ACC.d == 0x80000000)) R.ACC.d-- ;
+ }
+}
+
+/*** The manual does not mention overflow with the ADD? instructions *****
+ *** however I implemented overflow, coz it doesnt make sense otherwise **
+ *** and newer generations of this type of chip supported it. I think ****
+ *** the manual is wrong (apart from other errors the manual has). *******
+
+static void add_sh(void) { getdata(R.opcode.b.h,1); R.ACC.d += R.ALU.d; }
+static void addh(void) { getdata(0,0); R.ACC.d += (R.ALU.d << 16); }
+ ***/
+
+static void add_sh(void)
+{
+ oldacc.d = R.ACC.d;
+ getdata((R.opcode.b.h & 0xf),1);
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+}
+static void addh(void)
+{
+ oldacc.d = R.ACC.d;
+ getdata(0,0);
+ R.ACC.w.h += R.ALU.w.l;
+ if ((INT16)(~(oldacc.w.h ^ R.ALU.w.h) & (oldacc.w.h ^ R.ACC.w.h)) < 0) {
+ SET(OV_FLAG);
+ if (OVM)
+ R.ACC.w.h = ((INT16)oldacc.w.h < 0) ? 0x8000 : 0x7fff;
+ }
+}
+static void adds(void)
+{
+ oldacc.d = R.ACC.d;
+ getdata(0,0);
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+}
+static void and(void)
+{
+ getdata(0,0);
+ R.ACC.d &= R.ALU.d;
+}
+static void apac(void)
+{
+ oldacc.d = R.ACC.d;
+ R.ACC.d += R.Preg.d;
+ CALCULATE_ADD_OVERFLOW(R.Preg.d);
+}
+static void br(void)
+{
+ R.PC = M_RDOP_ARG(R.PC);
+}
+static void banz(void)
+{
+ if (R.AR[ARP] & 0x01ff)
+ R.PC = M_RDOP_ARG(R.PC);
+ else
+ R.PC++ ;
+ R.ALU.w.l = R.AR[ARP];
+ R.ALU.w.l-- ;
+ R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (R.ALU.w.l & 0x01ff);
+}
+static void bgez(void)
+{
+ if ( (INT32)(R.ACC.d) >= 0 )
+ R.PC = M_RDOP_ARG(R.PC);
+ else
+ R.PC++ ;
+}
+static void bgz(void)
+{
+ if ( (INT32)(R.ACC.d) > 0 )
+ R.PC = M_RDOP_ARG(R.PC);
+ else
+ R.PC++ ;
+}
+static void bioz(void)
+{
+ if (BIO_IN != CLEAR_LINE)
+ R.PC = M_RDOP_ARG(R.PC);
+ else
+ R.PC++ ;
+}
+static void blez(void)
+{
+ if ( (INT32)(R.ACC.d) <= 0 )
+ R.PC = M_RDOP_ARG(R.PC);
+ else
+ R.PC++ ;
+}
+static void blz(void)
+{
+ if ( (INT32)(R.ACC.d) < 0 )
+ R.PC = M_RDOP_ARG(R.PC);
+ else
+ R.PC++ ;
+}
+static void bnz(void)
+{
+ if (R.ACC.d != 0)
+ R.PC = M_RDOP_ARG(R.PC);
+ else
+ R.PC++ ;
+}
+static void bv(void)
+{
+ if (OV) {
+ R.PC = M_RDOP_ARG(R.PC);
+ CLR(OV_FLAG);
+ }
+ else
+ R.PC++ ;
+}
+static void bz(void)
+{
+ if (R.ACC.d == 0)
+ R.PC = M_RDOP_ARG(R.PC);
+ else
+ R.PC++ ;
+}
+static void cala(void)
+{
+ PUSH_STACK(R.PC);
+ R.PC = R.ACC.w.l & addr_mask;
+}
+static void call(void)
+{
+ R.PC++ ;
+ PUSH_STACK(R.PC);
+ R.PC = M_RDOP_ARG((R.PC - 1)) & addr_mask;
+}
+static void dint(void)
+{
+ SET(INTM_FLAG);
+}
+static void dmov(void)
+{
+ getdata(0,0);
+ M_WRTRAM((memaccess + 1),R.ALU.w.l);
+}
+static void eint(void)
+{
+ CLR(INTM_FLAG);
+}
+static void in_p(void)
+{
+ R.ALU.w.l = P_IN( (R.opcode.b.h & 7) );
+ putdata(R.ALU.w.l);
+}
+static void lac_sh(void)
+{
+ getdata((R.opcode.b.h & 0x0f),1);
+ R.ACC.d = R.ALU.d;
+}
+static void lack(void)
+{
+ R.ACC.d = R.opcode.b.l;
+}
+static void lar_ar0(void)
+{
+ getdata(0,0);
+ R.AR[0] = R.ALU.w.l;
+}
+static void lar_ar1(void)
+{
+ getdata(0,0);
+ R.AR[1] = R.ALU.w.l;
+}
+static void lark_ar0(void)
+{
+ R.AR[0] = R.opcode.b.l;
+}
+static void lark_ar1(void)
+{
+ R.AR[1] = R.opcode.b.l;
+}
+static void larp_mar(void)
+{
+ if (R.opcode.b.l & 0x80) {
+ UPDATE_AR();
+ UPDATE_ARP();
+ }
+}
+static void ldp(void)
+{
+ getdata(0,0);
+ if (R.ALU.d & 1)
+ SET(DP_REG);
+ else
+ CLR(DP_REG);
+}
+static void ldpk(void)
+{
+ if (R.opcode.b.l & 1)
+ SET(DP_REG);
+ else
+ CLR(DP_REG);
+}
+static void lst(void)
+{
+ R.opcode.b.l |= 0x08; /* Next arp not supported here, so mask it */
+ getdata(0,0);
+ R.ALU.w.l &= (~INTM_FLAG); /* Must not affect INTM */
+ R.STR &= INTM_FLAG;
+ R.STR |= R.ALU.w.l;
+ R.STR |= 0x1efe;
+}
+static void lt(void)
+{
+ getdata(0,0);
+ R.Treg = R.ALU.w.l;
+}
+static void lta(void)
+{
+ oldacc.d = R.ACC.d;
+ getdata(0,0);
+ R.Treg = R.ALU.w.l;
+ R.ACC.d += R.Preg.d;
+ CALCULATE_ADD_OVERFLOW(R.Preg.d);
+}
+static void ltd(void)
+{
+ oldacc.d = R.ACC.d;
+ getdata(0,0);
+ R.Treg = R.ALU.w.l;
+ M_WRTRAM((memaccess + 1),R.ALU.w.l);
+ R.ACC.d += R.Preg.d;
+ CALCULATE_ADD_OVERFLOW(R.Preg.d);
+}
+static void mpy(void)
+{
+ getdata(0,0);
+ R.Preg.d = (INT16)R.ALU.w.l * (INT16)R.Treg;
+ if (R.Preg.d == 0x40000000) R.Preg.d = 0xc0000000;
+}
+static void mpyk(void)
+{
+ R.Preg.d = (INT16)R.Treg * ((INT16)(R.opcode.w.l << 3) >> 3);
+}
+static void nop(void)
+{
+ /* Nothing to do */
+}
+static void or(void)
+{
+ getdata(0,0);
+ R.ACC.w.l |= R.ALU.w.l;
+}
+static void out_p(void)
+{
+ getdata(0,0);
+ P_OUT( (R.opcode.b.h & 7), R.ALU.w.l );
+}
+static void pac(void)
+{
+ R.ACC.d = R.Preg.d;
+}
+static void pop(void)
+{
+ R.ACC.w.l = POP_STACK();
+ R.ACC.w.h = 0x0000;
+}
+static void push(void)
+{
+ PUSH_STACK(R.ACC.w.l);
+}
+static void ret(void)
+{
+ R.PC = POP_STACK();
+}
+static void rovm(void)
+{
+ CLR(OVM_FLAG);
+}
+static void sach_sh(void)
+{
+ R.ALU.d = (R.ACC.d << (R.opcode.b.h & 7));
+ putdata(R.ALU.w.h);
+}
+static void sacl(void)
+{
+ putdata(R.ACC.w.l);
+}
+static void sar_ar0(void)
+{
+ putdata_sar(0);
+}
+static void sar_ar1(void)
+{
+ putdata_sar(1);
+}
+static void sovm(void)
+{
+ SET(OVM_FLAG);
+}
+static void spac(void)
+{
+ oldacc.d = R.ACC.d;
+ R.ACC.d -= R.Preg.d;
+ CALCULATE_SUB_OVERFLOW(R.Preg.d);
+}
+static void sst(void)
+{
+ putdata_sst(R.STR);
+}
+static void sub_sh(void)
+{
+ oldacc.d = R.ACC.d;
+ getdata((R.opcode.b.h & 0x0f),1);
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+}
+static void subc(void)
+{
+ oldacc.d = R.ACC.d;
+ getdata(15,0);
+ R.ALU.d = (INT32) R.ACC.d - R.ALU.d;
+ if ((INT32)((oldacc.d ^ R.ALU.d) & (oldacc.d ^ R.ACC.d)) < 0)
+ SET(OV_FLAG);
+ if ( (INT32)(R.ALU.d) >= 0 )
+ R.ACC.d = ((R.ALU.d << 1) + 1);
+ else
+ R.ACC.d = (R.ACC.d << 1);
+}
+static void subh(void)
+{
+ oldacc.d = R.ACC.d;
+ getdata(16,0);
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+}
+static void subs(void)
+{
+ oldacc.d = R.ACC.d;
+ getdata(0,0);
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+}
+static void tblr(void)
+{
+ R.ALU.d = M_RDROM((R.ACC.w.l & addr_mask));
+ putdata(R.ALU.w.l);
+ R.STACK[0] = R.STACK[1];
+}
+static void tblw(void)
+{
+ getdata(0,0);
+ M_WRTROM(((R.ACC.w.l & addr_mask)),R.ALU.w.l);
+ R.STACK[0] = R.STACK[1];
+}
+static void xor(void)
+{
+ getdata(0,0);
+ R.ACC.w.l ^= R.ALU.w.l;
+}
+static void zac(void)
+{
+ R.ACC.d = 0;
+}
+static void zalh(void)
+{
+ getdata(0,0);
+ R.ACC.w.h = R.ALU.w.l;
+ R.ACC.w.l = 0x0000;
+}
+static void zals(void)
+{
+ getdata(0,0);
+ R.ACC.w.l = R.ALU.w.l;
+ R.ACC.w.h = 0x0000;
+}
+
+
+/***********************************************************************
+ * Cycle Timings
+ ***********************************************************************/
+
+static unsigned cycles_main[256]=
+{
+/*00*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*10*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*20*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*30*/ 1*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 1*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*40*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*50*/ 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*60*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 3*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*70*/ 1*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 3*CLK, 1*CLK, 0*CLK,
+/*80*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*90*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*A0*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*B0*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*C0*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*D0*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*E0*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*F0*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 2*CLK, 2*CLK, 2*CLK, 0*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK
+};
+
+static unsigned cycles_7F_other[32]=
+{
+/*80*/ 1*CLK, 1*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 2*CLK, 2*CLK, 1*CLK, 1*CLK,
+/*90*/ 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 2*CLK, 2*CLK, 0*CLK, 0*CLK
+};
+
+
+/***********************************************************************
+ * Opcode Table
+ ***********************************************************************/
+
+static opcode_fn opcode_main[256]=
+{
+/*00*/ add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh
+/*08*/ ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh
+/*10*/ ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh
+/*18*/ ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh
+/*20*/ ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh
+/*28*/ ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh
+/*30*/ ,sar_ar0 ,sar_ar1 ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*38*/ ,lar_ar0 ,lar_ar1 ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*40*/ ,in_p ,in_p ,in_p ,in_p ,in_p ,in_p ,in_p ,in_p
+/*48*/ ,out_p ,out_p ,out_p ,out_p ,out_p ,out_p ,out_p ,out_p
+/*50*/ ,sacl ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*58*/ ,sach_sh ,sach_sh ,sach_sh ,sach_sh ,sach_sh ,sach_sh ,sach_sh ,sach_sh
+/*60*/ ,addh ,adds ,subh ,subs ,subc ,zalh ,zals ,tblr
+/*68*/ ,larp_mar ,dmov ,lt ,ltd ,lta ,mpy ,ldpk ,ldp
+/*70*/ ,lark_ar0 ,lark_ar1 ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*78*/ ,xor ,and ,or ,lst ,sst ,tblw ,lack ,other_7F_opcodes
+/*80*/ ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk
+/*88*/ ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk
+/*90*/ ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk
+/*98*/ ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk
+/*A0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*A8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*B0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*B8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*C0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*C8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*D0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*D8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*E0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*E8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*F0*/ ,illegal ,illegal ,illegal ,illegal ,banz ,bv ,bioz ,illegal
+/*F8*/ ,call ,br ,blz ,blez ,bgz ,bgez ,bnz ,bz
+};
+
+static opcode_fn opcode_7F_other[32]=
+{
+/*80*/ nop ,dint ,eint ,illegal ,illegal ,illegal ,illegal ,illegal
+/*88*/ ,abst ,zac ,rovm ,sovm ,cala ,ret ,pac ,apac
+/*90*/ ,spac ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
+/*98*/ ,illegal ,illegal ,illegal ,illegal ,push ,pop ,illegal ,illegal
+};
+
+
+
+/****************************************************************************
+ * Inits CPU emulation
+ ****************************************************************************/
+static void tms32010_init (int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ state_save_register_item("tms32010", index, R.PC);
+ state_save_register_item("tms32010", index, R.PREVPC);
+ state_save_register_item("tms32010", index, R.STR);
+ state_save_register_item("tms32010", index, R.ACC.d);
+ state_save_register_item("tms32010", index, R.ALU.d);
+ state_save_register_item("tms32010", index, R.Preg.d);
+ state_save_register_item("tms32010", index, R.Treg);
+ state_save_register_item("tms32010", index, R.AR[0]);
+ state_save_register_item("tms32010", index, R.AR[1]);
+ state_save_register_item("tms32010", index, R.STACK[0]);
+ state_save_register_item("tms32010", index, R.STACK[1]);
+ state_save_register_item("tms32010", index, R.STACK[2]);
+ state_save_register_item("tms32010", index, R.STACK[3]);
+ state_save_register_item("tms32010", index, R.INTF);
+ state_save_register_item("tms32010", index, R.opcode.d);
+}
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+static void tms32010_reset (void)
+{
+ R.PC = 0;
+ R.STR = 0x7efe; // OV cleared
+ R.ACC.d = 0;
+ R.INTF = TMS32010_INT_NONE;
+ addr_mask = 0x0fff; /* TMS32010 can only address 0x0fff */
+ /* however other TMS3201x devices */
+ /* can address up to 0xffff (incase */
+ /* their support is ever added). */
+}
+
+
+/****************************************************************************
+ * Shut down CPU emulation
+ ****************************************************************************/
+static void tms32010_exit (void)
+{
+ /* nothing to do ? */
+}
+
+
+/****************************************************************************
+ * Issue an interrupt if necessary
+ ****************************************************************************/
+static int Ext_IRQ(void)
+{
+ if (INTM == 0)
+ {
+ logerror("TMS32010: EXT INTERRUPT\n");
+ R.INTF = TMS32010_INT_NONE;
+ SET(INTM_FLAG);
+ PUSH_STACK(R.PC);
+ R.PC = 0x0002;
+ return (3*CLK); /* 3 cycles used due to PUSH and DINT operation ? */
+ }
+ return (0*CLK);
+}
+
+
+
+/****************************************************************************
+ * Execute IPeriod. Return 0 if emulation should be stopped
+ ****************************************************************************/
+static int tms32010_execute(int cycles)
+{
+ tms32010_icount = cycles;
+
+ do
+ {
+ if (R.INTF) {
+ /* Dont service INT if prev instruction was MPY, MPYK or EINT */
+ if ((R.opcode.b.h != 0x6d) && ((R.opcode.b.h & 0xe0) != 0x80) && (R.opcode.w.l != 0x7f82))
+ tms32010_icount -= Ext_IRQ();
+ }
+
+ R.PREVPC = R.PC;
+
+ CALL_MAME_DEBUG;
+
+ R.opcode.d = M_RDOP(R.PC);
+ R.PC++;
+
+ if (R.opcode.b.h != 0x7f) { /* Do all opcodes except the 7Fxx ones */
+ tms32010_icount -= cycles_main[R.opcode.b.h];
+ (*(opcode_main[R.opcode.b.h]))();
+ }
+ else { /* Opcode major byte 7Fxx has many opcodes in its minor byte */
+ tms32010_icount -= cycles_7F_other[(R.opcode.b.l & 0x1f)];
+ (*(opcode_7F_other[(R.opcode.b.l & 0x1f)]))();
+ }
+ } while (tms32010_icount>0);
+
+ return cycles - tms32010_icount;
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void tms32010_get_context (void *dst)
+{
+ if( dst )
+ *(tms32010_Regs*)dst = R;
+}
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void tms32010_set_context (void *src)
+{
+ if (src)
+ R = *(tms32010_Regs*)src;
+}
+
+
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+static void set_irq_line(int irqline, int state)
+{
+ /* Pending Interrupts cannot be cleared! */
+ if (state == ASSERT_LINE) R.INTF |= TMS32010_INT_PENDING;
+}
+
+
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( tms32010_ram, ADDRESS_SPACE_DATA, 16 )
+ AM_RANGE(0x00, 0x7f) AM_RAM /* Page 0 */
+ AM_RANGE(0x80, 0x8f) AM_RAM /* Page 1 */
+ADDRESS_MAP_END
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void tms32010_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS32010_PC: R.PC = info->i; break;
+ /* This is actually not a stack pointer, but the stack contents */
+ /* Stack is a 4 level First In Last Out stack */
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS32010_STK3: R.STACK[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32010_STR: R.STR = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32010_ACC: R.ACC.d = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32010_PREG: R.Preg.d = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32010_TREG: R.Treg = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32010_AR0: R.AR[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32010_AR1: R.AR[1] = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void tms32010_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(R); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = TMS32010_CLOCK_DIVIDER; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1*CLK; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 3*CLK; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 12; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 5; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = -1; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = (R.INTF & TMS32010_INT_PENDING) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = R.PREVPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS32010_PC: info->i = R.PC; break;
+ /* This is actually not a stack pointer, but the stack contents */
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS32010_STK3: info->i = R.STACK[3]; break;
+ case CPUINFO_INT_REGISTER + TMS32010_ACC: info->i = R.ACC.d; break;
+ case CPUINFO_INT_REGISTER + TMS32010_STR: info->i = R.STR; break;
+ case CPUINFO_INT_REGISTER + TMS32010_PREG: info->i = R.Preg.d; break;
+ case CPUINFO_INT_REGISTER + TMS32010_TREG: info->i = R.Treg; break;
+ case CPUINFO_INT_REGISTER + TMS32010_AR0: info->i = R.AR[0]; break;
+ case CPUINFO_INT_REGISTER + TMS32010_AR1: info->i = R.AR[1]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = tms32010_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tms32010_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tms32010_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = tms32010_init; break;
+ case CPUINFO_PTR_RESET: info->reset = tms32010_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = tms32010_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = tms32010_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tms32010_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &tms32010_icount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = construct_map_tms32010_ram; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "TMS32010"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Texas Instruments TMS32010"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.22"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C)1999-2004+ by Tony La Porta"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ R.STR & 0x8000 ? 'O':'.',
+ R.STR & 0x4000 ? 'M':'.',
+ R.STR & 0x2000 ? 'I':'.',
+ R.STR & 0x1000 ? '.':'?',
+ R.STR & 0x0800 ? 'a':'?',
+ R.STR & 0x0400 ? 'r':'?',
+ R.STR & 0x0200 ? 'p':'?',
+ R.STR & 0x0100 ? '1':'0',
+ R.STR & 0x0080 ? '.':'?',
+ R.STR & 0x0040 ? '.':'?',
+ R.STR & 0x0020 ? '.':'?',
+ R.STR & 0x0010 ? '.':'?',
+ R.STR & 0x0008 ? '.':'?',
+ R.STR & 0x0004 ? 'd':'?',
+ R.STR & 0x0002 ? 'p':'?',
+ R.STR & 0x0001 ? '1':'0');
+ break;
+
+ case CPUINFO_STR_REGISTER + TMS32010_PC: sprintf(info->s, "PC:%04X", R.PC); break;
+ case CPUINFO_STR_REGISTER + TMS32010_SP: sprintf(info->s, "SP:%X", 0); /* fake stack pointer */ break;
+ case CPUINFO_STR_REGISTER + TMS32010_STR: sprintf(info->s, "STR:%04X", R.STR); break;
+ case CPUINFO_STR_REGISTER + TMS32010_ACC: sprintf(info->s, "ACC:%08X", R.ACC.d); break;
+ case CPUINFO_STR_REGISTER + TMS32010_PREG: sprintf(info->s, "P:%08X", R.Preg.d); break;
+ case CPUINFO_STR_REGISTER + TMS32010_TREG: sprintf(info->s, "T:%04X", R.Treg); break;
+ case CPUINFO_STR_REGISTER + TMS32010_AR0: sprintf(info->s, "AR0:%04X", R.AR[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32010_AR1: sprintf(info->s, "AR1:%04X", R.AR[1]); break;
+ case CPUINFO_STR_REGISTER + TMS32010_STK0: sprintf(info->s, "STK0:%04X", R.STACK[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32010_STK1: sprintf(info->s, "STK1:%04X", R.STACK[1]); break;
+ case CPUINFO_STR_REGISTER + TMS32010_STK2: sprintf(info->s, "STK2:%04X", R.STACK[2]); break;
+ case CPUINFO_STR_REGISTER + TMS32010_STK3: sprintf(info->s, "STK3:%04X", R.STACK[3]); break;
+ }
+}
diff --git a/src/emu/cpu/tms32010/tms32010.h b/src/emu/cpu/tms32010/tms32010.h
new file mode 100644
index 00000000000..181fb65a462
--- /dev/null
+++ b/src/emu/cpu/tms32010/tms32010.h
@@ -0,0 +1,140 @@
+ /**************************************************************************\
+ * Texas Instruments TMS32010 DSP Emulator *
+ * *
+ * Copyright (C) 1999-2002+ Tony La Porta *
+ * You are not allowed to distribute this software commercially. *
+ * Written for the MAME project. *
+ * *
+ * *
+ * Note : This is a word based microcontroller, with addressing *
+ * architecture based on the Harvard addressing scheme. *
+ * *
+ \**************************************************************************/
+
+#ifndef _TMS32010_H
+#define _TMS32010_H
+
+
+#include "cpuintrf.h"
+
+
+
+/**************************************************************************
+ * Internal Clock divisor
+ *
+ * External Clock is divided internally by 4, to produce the states
+ * used in carrying out an instruction (machine) cycle.
+ */
+
+#define TMS32010_CLOCK_DIVIDER 4
+
+
+/****************************************************************************
+ * Use this in the I/O port address fields of your driver for the BIO pin
+ * i.e,
+ * AM_RANGE(TMS32010_BIO, TMS32010_BIO) AM_READ(twincobr_bio_line_r)
+ */
+
+#define TMS32010_BIO 0x10 /* BIO input */
+
+
+#define TMS32010_INT_PENDING 0x80000000
+#define TMS32010_INT_NONE 0
+
+#define TMS32010_ADDR_MASK 0x0fff /* TMS32010 can only address 0x0fff */
+ /* however other TMS3201x devices */
+ /* can address up to 0xffff (incase */
+ /* their support is ever added). */
+
+
+enum {
+ TMS32010_PC=1, TMS32010_SP, TMS32010_STR, TMS32010_ACC,
+ TMS32010_PREG, TMS32010_TREG, TMS32010_AR0, TMS32010_AR1,
+ TMS32010_STK0, TMS32010_STK1, TMS32010_STK2, TMS32010_STK3
+};
+
+
+/****************************************************************************
+ * Public Functions
+ */
+
+void tms32010_get_info(UINT32 state, cpuinfo *info);
+
+
+
+/****************************************************************************
+ * Read the state of the BIO pin
+ */
+
+#define TMS32010_BIO_In (io_read_word_16be(TMS32010_BIO<<1))
+
+
+/****************************************************************************
+ * Input a word from given I/O port
+ */
+
+#define TMS32010_In(Port) (io_read_word_16be((Port)<<1))
+
+
+/****************************************************************************
+ * Output a word to given I/O port
+ */
+
+#define TMS32010_Out(Port,Value) (io_write_word_16be((Port)<<1,Value))
+
+
+
+/****************************************************************************
+ * Read a word from given ROM memory location
+ */
+
+#define TMS32010_ROM_RDMEM(A) (program_read_word_16be((A)<<1))
+
+
+/****************************************************************************
+ * Write a word to given ROM memory location
+ */
+
+#define TMS32010_ROM_WRMEM(A,V) (program_write_word_16be((A)<<1,V))
+
+
+
+/****************************************************************************
+ * Read a word from given RAM memory location
+ */
+
+#define TMS32010_RAM_RDMEM(A) (data_read_word_16be((A)<<1))
+
+
+/****************************************************************************
+ * Write a word to given RAM memory location
+ */
+
+#define TMS32010_RAM_WRMEM(A,V) (data_write_word_16be((A)<<1,V))
+
+
+
+/****************************************************************************
+ * TMS32010_RDOP() is identical to TMS32010_RDMEM() except it is used for reading
+ * opcodes. In case of system with memory mapped I/O, this function can be
+ * used to greatly speed up emulation
+ */
+
+#define TMS32010_RDOP(A) (cpu_readop16((A)<<1))
+
+
+/****************************************************************************
+ * TMS32010_RDOP_ARG() is identical to TMS32010_RDOP() except it is used
+ * for reading opcode arguments. This difference can be used to support systems
+ * that use different encoding mechanisms for opcodes and opcode arguments
+ */
+
+#define TMS32010_RDOP_ARG(A) (cpu_readop_arg16((A)<<1))
+
+
+
+#ifdef MAME_DEBUG
+offs_t tms32010_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _TMS32010_H */
diff --git a/src/emu/cpu/tms32025/32025dsm.c b/src/emu/cpu/tms32025/32025dsm.c
new file mode 100644
index 00000000000..ab6f524b42c
--- /dev/null
+++ b/src/emu/cpu/tms32025/32025dsm.c
@@ -0,0 +1,522 @@
+ /**************************************************************************\
+ * Texas Instruments TMS320x25 DSP Disassembler *
+ * *
+ * Copyright (C) 2001-2002+ Tony La Porta *
+ * To be used with TMS320x25 DSP Emulator engine. *
+ * Written for the MAME project. *
+ * *
+ * Many thanks to those involved in the i8039 Disassembler *
+ * as the structure here was borrowed from it. *
+ * *
+ * Note : This is a word based microcontroller, with addressing *
+ * architecture based on the Harvard addressing scheme. *
+ * *
+ * *
+ * A Memory Address *
+ * B Opcode Address Argument (Requires next opcode read) *
+ * C Compare mode *
+ * D Immediate byte load *
+ * K Immediate bit load *
+ * W Immediate word load *
+ * M AR[x] register modification type (for indirect addressing) *
+ * N ARP register to change ARP pointer to (for indirect addressing) *
+ * P I/O port address number *
+ * R AR[R] register to use *
+ * S Shift ALU left *
+ * T Shift ALU left (Hex) / Nibble data *
+ * X Don't care bit *
+ * *
+ \**************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef MAME_DEBUG /* Compile interface to MAME */
+#include "tms32025.h"
+#include "debugger.h"
+extern UINT16 *tms32025_pgmmap[0x200];
+//#define READOP16(A) (cpu_readop16((A) | (TMS32025_PGM_OFFSET << 1)))
+//#define READARG16(A) (cpu_readop_arg16((A) | (TMS32025_PGM_OFFSET << 1)))
+#define READOP16(A) ((tms32025_pgmmap[(A) >> 7]) ? (tms32025_pgmmap[(A) >> 7][(A) & 0x7f]) : cpu_readop16((A)<<1))
+#define READARG16(A) ((tms32025_pgmmap[(A) >> 7]) ? (tms32025_pgmmap[(A) >> 7][(A) & 0x7f]) : cpu_readop16((A)<<1))
+#else /* Compile interface for standalone */
+extern unsigned char *Buffer;
+#ifdef MSB_FIRST
+#define READOP16(A) ( ((Buffer[A+1]<<8) | Buffer[A]) )
+#define READARG16(A) ( ((Buffer[A+1]<<8) | Buffer[A]) )
+#else
+#define READOP16(A) ( ((Buffer[A]<<8) | Buffer[A+1]) )
+#define READARG16(A) ( ((Buffer[A]<<8) | Buffer[A+1]) )
+#endif
+#endif
+
+
+
+typedef unsigned char byte;
+typedef unsigned short int word;
+
+#define FMT(a,b) a, b
+#define PTRS_PER_FORMAT 2
+
+static const char *arith[8] = { "*", "*-", "*+", "??", "BR0-", "*0-", "*0+", "*BR0+" } ;
+static const char *nextar[16] = { "", "", "", "", "", "", "", "", ",AR0", ",AR1", ",AR2", ",AR3", ",AR4", ",AR5", ",AR6", ",AR7" } ;
+static const char *cmpmode[4] = { "0 (ARx = AR0)" , "1 (ARx < AR0)" , "2 (ARx > AR0)" , "3 (ARx <> AR0)" } ;
+
+
+static const char *TMS32025Formats[] = {
+ FMT("0000tttt0aaaaaaa", "add %A,%T"), /* 0xxx */
+ FMT("0000tttt1mmmnnnn", "add %M,%T%N"),
+ FMT("0001tttt0aaaaaaa", "sub %A,%T"), /* 1xxx */
+ FMT("0001tttt1mmmnnnn", "sub %M,%T%N"),
+ FMT("0010tttt0aaaaaaa", "lac %A,%T"), /* 2xxx */
+ FMT("0010tttt1mmmnnnn", "lac %M,%T%N"),
+ FMT("00110rrr0aaaaaaa", "lar %R,%A"), /* 3xxx */
+ FMT("00110rrr1mmmnnnn", "lar %R%M%N"),
+ FMT("001110000aaaaaaa", "mpy %A"), /* 38xx */
+ FMT("001110001mmmnnnn", "mpy %M%N"),
+ FMT("001110010aaaaaaa", "sqra %A"), /* 39xx */
+ FMT("001110011mmmnnnn", "sqra %M%N"),
+ FMT("001110100aaaaaaa", "mpya %A"), /* 3Axx */
+ FMT("001110101mmmnnnn", "mpya %M%N"),
+ FMT("001110110aaaaaaa", "mpys %A"), /* 3Bxx */
+ FMT("001110111mmmnnnn", "mpys %M%N"),
+ FMT("001111000aaaaaaa", "lt %A"), /* 3Cxx */
+ FMT("001111001mmmnnnn", "lt %M%N"),
+ FMT("001111010aaaaaaa", "lta %A"), /* 3Dxx */
+ FMT("001111011mmmnnnn", "lta %M%N"),
+ FMT("001111100aaaaaaa", "ltp %A"), /* 3Exx */
+ FMT("001111101mmmnnnn", "ltp %M%N"),
+ FMT("001111110aaaaaaa", "ltd %A"), /* 3Fxx */
+ FMT("001111111mmmnnnn", "ltd %M%N"),
+ FMT("010000000aaaaaaa", "zalh %A"), /* 40xx */
+ FMT("010000001mmmnnnn", "zalh %M%N"),
+ FMT("010000010aaaaaaa", "zals %A"), /* 41xx */
+ FMT("010000011mmmnnnn", "zals %M%N"),
+ FMT("010000100aaaaaaa", "lact %A"), /* 42xx */
+ FMT("010000101mmmnnnn", "lact %M%N"),
+ FMT("010000110aaaaaaa", "addc %A%S"), /* 43xx */
+ FMT("010000111mmmnnnn", "addc %M%S%N"),
+ FMT("010001000aaaaaaa", "subh %A"), /* 44xx */
+ FMT("010001001mmmnnnn", "subh %M%N"),
+ FMT("010001010aaaaaaa", "subs %A"), /* 45xx */
+ FMT("010001011mmmnnnn", "subs %M%N"),
+ FMT("010001100aaaaaaa", "subt %A"), /* 46xx */
+ FMT("010001101mmmnnnn", "subt %M%N"),
+ FMT("010001110aaaaaaa", "subc %A"), /* 47xx */
+ FMT("010001111mmmnnnn", "subc %M%N"),
+ FMT("010010000aaaaaaa", "addh %A"), /* 48xx */
+ FMT("010010001mmmnnnn", "addh %M%N"),
+ FMT("010010010aaaaaaa", "adds %A"), /* 49xx */
+ FMT("010010011mmmnnnn", "adds %M%N"),
+ FMT("010010100aaaaaaa", "addt %A"), /* 4Axx */
+ FMT("010010101mmmnnnn", "addt %M%N"),
+ FMT("010010110aaaaaaa", "rpt %A"), /* 4Bxx */
+ FMT("010010111mmmnnnn", "rpt %M%N"),
+ FMT("010011000aaaaaaa", "xor %A"), /* 4Cxx */
+ FMT("010011001mmmnnnn", "xor %M%N"),
+ FMT("010011010aaaaaaa", "or %A"), /* 4Dxx */
+ FMT("010011011mmmnnnn", "or %M%N"),
+ FMT("010011100aaaaaaa", "and %A"), /* 4Exx */
+ FMT("010011101mmmnnnn", "and %M%N"),
+ FMT("010011110aaaaaaa", "subb %A"), /* 4Fxx */
+ FMT("010011111mmmnnnn", "subb %M%N"),
+ FMT("010100000aaaaaaa", "lst %A"), /* 50xx */
+ FMT("010100001mmmnnnn", "lst %M%N"),
+ FMT("010100010aaaaaaa", "lst1 %A"), /* 51xx */
+ FMT("010100011mmmnnnn", "lst1 %M%N"),
+ FMT("010100100aaaaaaa", "ldp %A"), /* 52xx */
+ FMT("010100101mmmnnnn", "ldp %M%N"),
+ FMT("010100110aaaaaaa", "lph %A"), /* 53xx */
+ FMT("010100111mmmnnnn", "lph %M%N"),
+ FMT("010101000aaaaaaa", "pshd %A"), /* 54xx */
+ FMT("010101001mmmnnnn", "pshd %M%N"),
+
+/* FMT("010101010aaaaaaa", "mar %A"), 55xx */
+/* MAR direct has been expanded out to all its variations because one of its */
+/* its opcodes is the same as NOP. Actually MAR direct just performs a NOP */
+ FMT("0101010100000000", "nop"), /* 5500 */
+ FMT("0101010100000001", "mar $01"),
+ FMT("0101010100000010", "mar $02"),
+ FMT("0101010100000011", "mar $03"),
+ FMT("0101010100000100", "mar $04"),
+ FMT("0101010100000101", "mar $05"),
+ FMT("0101010100000110", "mar $06"),
+ FMT("0101010100000111", "mar $07"),
+ FMT("0101010100001000", "mar $08"),
+ FMT("0101010100001001", "mar $09"),
+ FMT("0101010100001010", "mar $0A"),
+ FMT("0101010100001011", "mar $0B"),
+ FMT("0101010100001100", "mar $0C"),
+ FMT("0101010100001101", "mar $0D"),
+ FMT("0101010100001110", "mar $0E"),
+ FMT("0101010100001111", "mar $0F"),
+ FMT("010101010001tttt", "mar $1%T"),
+ FMT("010101010010tttt", "mar $2%T"),
+ FMT("010101010011tttt", "mar $3%T"),
+ FMT("010101010100tttt", "mar $4%T"),
+ FMT("010101010101tttt", "mar $5%T"),
+ FMT("010101010110tttt", "mar $6%T"),
+ FMT("010101010111tttt", "mar $7%T"),
+
+/* FMT("010101011mmmnnnn", "mar %M%N"), 55xx */
+/* MAR indirect has been expanded out to all its variations because one of */
+/* its opcodes, is the same as LARP (actually performs the same function) */
+ FMT("0101010110000xxx", "mar *"), /* 558x */
+ FMT("0101010110001kkk", "larp %K"), /* 558x */
+ FMT("010101011001nnnn", "mar *-%N"), /* 558x */
+ FMT("010101011010nnnn", "mar *+%N"),
+ FMT("010101011011nnnn", "mar ??%N"),
+ FMT("010101011100nnnn", "mar *BR0-%N"),
+ FMT("010101011101nnnn", "mar *0-%N"),
+ FMT("010101011110nnnn", "mar *0+%N"),
+ FMT("010101011111nnnn", "mar *BR0+%N"),
+
+ FMT("010101100aaaaaaa", "dmov %A"), /* 56xx */
+ FMT("010101101mmmnnnn", "dmov %M%N"),
+ FMT("010101110aaaaaaa", "bitt %A"), /* 57xx */
+ FMT("010101111mmmnnnn", "bitt %M%N"),
+ FMT("010110000aaaaaaa", "tblr %A"), /* 58xx */
+ FMT("010110001mmmnnnn", "tblr %M%N"),
+ FMT("010110010aaaaaaa", "tblw %A"), /* 59xx */
+ FMT("010110011mmmnnnn", "tblw %M%N"),
+ FMT("010110100aaaaaaa", "sqrs %A"), /* 5Axx */
+ FMT("010110101mmmnnnn", "sqrs %M%N"),
+ FMT("010110110aaaaaaa", "lts %A"), /* 5Bxx */
+ FMT("010110111mmmnnnn", "lts %M%N"),
+ FMT("010111000aaaaaaabbbbbbbbbbbbbbbb", "macd %B,%A"), /* 5Cxx */
+ FMT("010111001mmmnnnnbbbbbbbbbbbbbbbb", "macd %B,%M%N"),
+ FMT("010111010aaaaaaabbbbbbbbbbbbbbbb", "mac %B,%A"), /* 5Dxx */
+ FMT("010111011mmmnnnnbbbbbbbbbbbbbbbb", "mac %B,%M%N"),
+ FMT("010111101mmmnnnnbbbbbbbbbbbbbbbb", "bc %B %M%N"), /* 5Exx */
+ FMT("010111111mmmnnnnbbbbbbbbbbbbbbbb", "bnc %B %M%N"), /* 5Fxx */
+ FMT("01100sss0aaaaaaa", "sacl %A%S"), /* 6xxx */
+ FMT("01100sss1mmmnnnn", "sacl %M%S%N"),
+ FMT("01101sss0aaaaaaa", "sach %A%S"), /* 6Xxx */
+ FMT("01101sss1mmmnnnn", "sach %M%S%N"),
+ FMT("01110rrr0aaaaaaa", "sar %R,%A"), /* 7xxx */
+ FMT("01110rrr1mmmnnnn", "sar %R%M%N"),
+ FMT("011110000aaaaaaa", "sst %A"), /* 78xx */
+ FMT("011110001mmmnnnn", "sst %M%N"),
+ FMT("011110010aaaaaaa", "sst1 %A"), /* 79xx */
+ FMT("011110011mmmnnnn", "sst1 %M%N"),
+ FMT("011110100aaaaaaa", "popd %A"), /* 7Axx */
+ FMT("011110101mmmnnnn", "popd %M%N"),
+ FMT("011110110aaaaaaa", "zalr %A"), /* 7Bxx */
+ FMT("011110111mmmnnnn", "zalr %M%N"),
+ FMT("011111000aaaaaaa", "spl %A"), /* 7Cxx */
+ FMT("011111001mmmnnnn", "spl %M%N"),
+ FMT("011111010aaaaaaa", "sph %A"), /* 7Dxx */
+ FMT("011111011mmmnnnn", "sph %M%N"),
+ FMT("011111100aaaaaaa", "adrk %A"), /* 7Exx */
+ FMT("011111101mmmnnnn", "adrk %M%N"),
+ FMT("011111110aaaaaaa", "sbrk %A"), /* 7Fxx */
+ FMT("011111111mmmnnnn", "sbrk %M%N"),
+ FMT("1000pppp0aaaaaaa", "in %A,%P"), /* 8xxx */
+ FMT("1000pppp1mmmnnnn", "in %M,%P%N"),
+ FMT("1001tttt0aaaaaaa", "bit %A,%T"), /* 9xxx */
+ FMT("1001tttt1mmmnnnn", "bit %M,%T%N"),
+ FMT("101wwwwwwwwwwwww", "mpyk %W"), /* Axxx-Bxxx */
+ FMT("11000rrrdddddddd", "lark %R,%D"), /* Cxxx */
+ FMT("1100100kdddddddd", "ldpk %K%D"), /* Cxxx */
+/* FMT("11001010dddddddd", "lack %D"), CAxx */
+/* LACK has been expanded out to all its variations because one of its */
+/* its opcodes is the same as ZAC. Actually, it performs the same function */
+ FMT("1100101000000000", "zac"), /* CA00 */
+ FMT("1100101000000001", "lack 01h"), /* CAxx */
+ FMT("1100101000000010", "lack 02h"),
+ FMT("1100101000000011", "lack 03h"),
+ FMT("1100101000000100", "lack 04h"),
+ FMT("1100101000000101", "lack 05h"),
+ FMT("1100101000000110", "lack 06h"),
+ FMT("1100101000000111", "lack 07h"),
+ FMT("1100101000001000", "lack 08h"),
+ FMT("1100101000001001", "lack 09h"),
+ FMT("1100101000001010", "lack 0Ah"),
+ FMT("1100101000001011", "lack 0Bh"),
+ FMT("1100101000001100", "lack 0Ch"),
+ FMT("1100101000001101", "lack 0Dh"),
+ FMT("1100101000001110", "lack 0Eh"),
+ FMT("1100101000001111", "lack 0Fh"),
+ FMT("110010100001tttt", "lack 1%T"),
+ FMT("110010100010tttt", "lack 2%T"),
+ FMT("110010100011tttt", "lack 3%T"),
+ FMT("110010100100tttt", "lack 4%T"),
+ FMT("110010100101tttt", "lack 5%T"),
+ FMT("110010100110tttt", "lack 6%T"),
+ FMT("110010100111tttt", "lack 7%T"),
+ FMT("110010101000tttt", "lack 8%T"),
+ FMT("110010101001tttt", "lack 9%T"),
+ FMT("110010101010tttt", "lack A%T"),
+ FMT("110010101011tttt", "lack B%T"),
+ FMT("110010101100tttt", "lack C%T"),
+ FMT("110010101101tttt", "lack D%T"),
+ FMT("110010101110tttt", "lack E%T"),
+ FMT("110010101111tttt", "lack F%T"),
+
+ FMT("11001011dddddddd", "rptk %D"), /* CBxx */
+ FMT("11001100dddddddd", "addk %D"), /* CCxx */
+ FMT("11001101dddddddd", "subk %D"), /* CDxx */
+ FMT("1100111000000000", "eint"), /* CE00 */
+ FMT("1100111000000001", "dint"), /* CE01 */
+ FMT("1100111000000010", "rovm"), /* CE02 */
+ FMT("1100111000000011", "sovm"), /* CE03 */
+ FMT("1100111000000100", "cnfd"), /* CE04 */
+ FMT("1100111000000101", "cnfp"), /* CE05 */
+ FMT("1100111000000110", "rsxm"), /* CE06 */
+ FMT("1100111000000111", "ssxm"), /* CE07 */
+ FMT("11001110000010kk", "spm %K"), /* CE0x */
+ FMT("1100111000001100", "rxf"), /* CE0C */
+ FMT("1100111000001101", "sxf"), /* CE0D */
+ FMT("110011100000111k", "fort %K"), /* CE0x */
+ FMT("1100111000010100", "pac"), /* CE14 */
+ FMT("1100111000010101", "apac"), /* CE15 */
+ FMT("1100111000010110", "spac"), /* CE16 */
+ FMT("1100111000011000", "sfl"), /* CE18 */
+ FMT("1100111000011001", "sfr"), /* CE19 */
+ FMT("1100111000011011", "abs"), /* CE1B */
+ FMT("1100111000011100", "push"), /* CE1C */
+ FMT("1100111000011101", "pop"), /* CE1D */
+ FMT("1100111000011110", "trap"), /* CE1E */
+ FMT("1100111000011111", "idle"), /* CE1F */
+ FMT("1100111000100000", "rtxm"), /* CE20 */
+ FMT("1100111000100001", "stxm"), /* CE21 */
+ FMT("1100111000100011", "neg"), /* CE23 */
+ FMT("1100111000100100", "cala"), /* CE24 */
+ FMT("1100111000100101", "bacc"), /* CE25 */
+ FMT("1100111000100110", "ret"), /* CE26 */
+ FMT("1100111000100111", "cmpl"), /* CE27 */
+ FMT("1100111000110000", "rc"), /* CE30 */
+ FMT("1100111000110001", "sc"), /* CE31 */
+ FMT("1100111000110010", "rtc"), /* CE32 */
+ FMT("1100111000110011", "stc"), /* CE33 */
+ FMT("1100111000110100", "rol"), /* CE34 */
+ FMT("1100111000110101", "ror"), /* CE35 */
+ FMT("1100111000110110", "rfsm"), /* CE36 */
+ FMT("1100111000110111", "sfsm"), /* CE37 */
+ FMT("1100111000111000", "rhm"), /* CE38 */
+ FMT("1100111000111001", "shm"), /* CE39 */
+ FMT("11001110001111kk", "conf %K"), /* CE3x */
+ FMT("11001110010100cc", "cmpr %C"), /* CE5x */
+ FMT("110011101mmm0010", "norm %M"), /* CEx2 */
+ FMT("110011110aaaaaaa", "mpys %A"), /* CFxx */
+ FMT("110011111mmmnnnn", "mpys %M%N"),
+ FMT("11010rrr00000000wwwwwwwwwwwwwwww", "lrlk %R,%W"), /* Dx00 */
+ FMT("1101tttt00000001wwwwwwwwwwwwwwww", "lalk %W,%T"), /* Dx01 */
+ FMT("1101tttt00000010wwwwwwwwwwwwwwww", "adlk %W,%T"), /* Dx02 */
+ FMT("1101tttt00000011wwwwwwwwwwwwwwww", "sblk %W,%T"), /* Dx03 */
+ FMT("1101tttt00000100wwwwwwwwwwwwwwww", "andk %W,%T"), /* Dx04 */
+ FMT("1101tttt00000101wwwwwwwwwwwwwwww", "ork %W,%T"), /* Dx05 */
+ FMT("1101tttt00000110wwwwwwwwwwwwwwww", "xork %W,%T"), /* Dx06 */
+ FMT("1110pppp0aaaaaaa", "out %A,%P"), /* Exxx */
+ FMT("1110pppp1mmmnnnn", "out %M,%P%N"),
+ FMT("111100001mmmnnnnbbbbbbbbbbbbbbbb", "bv %B %M%N"), /* F0xx */
+ FMT("111100011mmmnnnnbbbbbbbbbbbbbbbb", "bgz %B %M%N"), /* F1xx */
+ FMT("111100101mmmnnnnbbbbbbbbbbbbbbbb", "blez %B %M%N"), /* F2xx */
+ FMT("111100111mmmnnnnbbbbbbbbbbbbbbbb", "blz %B %M%N"), /* F3xx */
+ FMT("111101001mmmnnnnbbbbbbbbbbbbbbbb", "bgez %B %M%N"), /* F4xx */
+ FMT("111101011mmmnnnnbbbbbbbbbbbbbbbb", "bnz %B %M%N"), /* F5xx */
+ FMT("111101101mmmnnnnbbbbbbbbbbbbbbbb", "bz %B %M%N"), /* F6xx */
+ FMT("111101111mmmnnnnbbbbbbbbbbbbbbbb", "bnv %B %M%N"), /* F7xx */
+ FMT("111110001mmmnnnnbbbbbbbbbbbbbbbb", "bbz %B %M%N"), /* F8xx */
+ FMT("111110011mmmnnnnbbbbbbbbbbbbbbbb", "bbnz %B %M%N"), /* F9xx */
+ FMT("111110101mmmnnnnbbbbbbbbbbbbbbbb", "bioz %B %M%N"), /* FAxx */
+ FMT("111110111mmmnnnnbbbbbbbbbbbbbbbb", "banz %B %M%N"), /* FBxx */
+ FMT("111111000aaaaaaabbbbbbbbbbbbbbbb", "blkp %B,%A"), /* FCxx */
+ FMT("111111001mmmnnnnbbbbbbbbbbbbbbbb", "blkp %B,%M%N"),
+ FMT("111111010aaaaaaabbbbbbbbbbbbbbbb", "blkd %B,%A"), /* FDxx */
+ FMT("111111011mmmnnnnbbbbbbbbbbbbbbbb", "blkd %B,%M%N"),
+ FMT("111111101mmmnnnnbbbbbbbbbbbbbbbb", "call %B %M%N"), /* FExx */
+ FMT("111111111mmmnnnnbbbbbbbbbbbbbbbb", "b %B %M%N"), /* FFxx */
+ NULL
+};
+
+#define MAX_OPS (((sizeof(TMS32025Formats) / sizeof(TMS32025Formats[0])) - 1) / PTRS_PER_FORMAT)
+
+typedef struct opcode {
+ word mask; /* instruction mask */
+ word bits; /* constant bits */
+ word extcode; /* value that gets extension code */
+ const char *parse; /* how to parse bits */
+ const char *fmt; /* instruction format */
+} TMS32025Opcode;
+
+static TMS32025Opcode Op[MAX_OPS+1];
+static int OpInizialized = 0;
+
+static void InitDasm32025(void)
+{
+ const char *p, **ops;
+ word mask, bits;
+ int bit;
+ int i;
+
+ ops = TMS32025Formats; i = 0;
+ while (*ops)
+ {
+ p = *ops;
+ mask = 0; bits = 0; bit = 15;
+ while (*p && bit >= 0)
+ {
+ switch (*p++)
+ {
+ case '1': mask |= 1<<bit; bits |= 1<<bit; bit--; break;
+ case '0': mask |= 1<<bit; bit--; break;
+ case ' ': break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'k':
+ case 'm':
+ case 'n':
+ case 'p':
+ case 'r':
+ case 's':
+ case 't':
+ case 'w':
+ case 'x':
+ bit --;
+ break;
+ default: fatalerror("Invalid instruction encoding '%s %s'",
+ ops[0],ops[1]);
+ }
+ }
+ if (bit != -1 )
+ {
+ fatalerror("not enough bits in encoding '%s %s' %d",
+ ops[0],ops[1],bit);
+ }
+ while (isspace(*p)) p++;
+ if (*p) Op[i].extcode = *p;
+ Op[i].bits = bits;
+ Op[i].mask = mask;
+ Op[i].fmt = ops[1];
+ Op[i].parse = ops[0];
+
+ ops += PTRS_PER_FORMAT;
+ i++;
+ }
+
+ OpInizialized = 1;
+}
+
+offs_t tms32025_dasm(char *str, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ int a, b, c, d, k, m, n, p, r, s, t, w, x; /* these can all be filled in by parsing an instruction */
+ int i;
+ int op;
+ int cnt = 1;
+ int code;
+ int bit;
+ char *strtmp;
+ const char *cp; /* character pointer in OpFormats */
+
+ if (!OpInizialized) InitDasm32025();
+
+ op = -1; /* no matching opcode */
+ code = (oprom[0] << 8) | oprom[1];
+ for ( i = 0; i < MAX_OPS; i++)
+ {
+ if ((code & Op[i].mask) == Op[i].bits)
+ {
+ if (op != -1)
+ {
+ mame_printf_debug("Error: opcode %04Xh matches %d (%s) and %d (%s)\n",
+ code,i,Op[i].fmt,op,Op[op].fmt);
+ }
+ op = i;
+ }
+ }
+ if (op == -1)
+ {
+ sprintf(str,"???? dw %04Xh",code);
+ return cnt | DASMFLAG_SUPPORTED;
+ }
+ strtmp = str;
+ if (Op[op].extcode)
+ {
+ bit = 31;
+ code <<= 16;
+ code |= (opram[2] << 8) | opram[3];
+ cnt++;
+ }
+ else
+ {
+ bit = 15;
+ }
+
+ /* shift out operands */
+ cp = Op[op].parse;
+ a = b = c = d = k = m = n = p = r = s = t = w = x = 0;
+
+ while (bit >= 0)
+ {
+ /* mame_printf_debug("{%c/%d}",*cp,bit); */
+ switch(*cp)
+ {
+ case 'a': a <<=1; a |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'b': b <<=1; b |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'c': c <<=1; c |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'd': d <<=1; d |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'k': k <<=1; k |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'm': m <<=1; m |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'n': n <<=1; n |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'p': p <<=1; p |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'r': r <<=1; r |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 's': s <<=1; s |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 't': t <<=1; t |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'w': w <<=1; w |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'x': bit--; break;
+ case ' ': break;
+ case '1': case '0': bit--; break;
+ case '\0': fatalerror("premature end of parse string, opcode %x, bit = %d",code,bit);
+ }
+ cp++;
+ }
+
+ /* now traverse format string */
+ cp = Op[op].fmt;
+
+ if (!strncmp(cp, "cal", 3))
+ flags = DASMFLAG_STEP_OVER;
+ else if (!strncmp(cp, "ret", 3))
+ flags = DASMFLAG_STEP_OUT;
+
+ while (*cp)
+ {
+ if (*cp == '%')
+ {
+ char num[30], *q;
+ cp++;
+ switch (*cp++)
+ {
+ case 'A': sprintf(num,"$%02X",a); break;
+ case 'B': sprintf(num,"$%04X",b); break;
+ case 'C': sprintf(num,"%s",cmpmode[c]); break;
+ case 'D': sprintf(num,"%02Xh",d); break;
+ case 'K': sprintf(num,"%d",k); break;
+ case 'M': sprintf(num,"%s",arith[m]); break;
+ case 'N': sprintf(num,"%s",nextar[n]); break;
+ case 'P': sprintf(num,"PA$%01X",p); break;
+ case 'R': sprintf(num,"AR%d",r); break;
+ case 'S': sprintf(num,",%d",s); break;
+ case 'T': sprintf(num,"%01Xh",t); break;
+ case 'W': sprintf(num,"%04Xh",w); break;
+ case 'X': break;
+ default:
+ fatalerror("illegal escape character in format '%s'",Op[op].fmt);
+ }
+ q = num; while (*q) *str++ = *q++;
+ *str = '\0';
+ }
+ else
+ {
+ *str++ = *cp++;
+ *str = '\0';
+ }
+ }
+ return cnt | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/tms32025/dis32025.c b/src/emu/cpu/tms32025/dis32025.c
new file mode 100644
index 00000000000..62a7fd76ae8
--- /dev/null
+++ b/src/emu/cpu/tms32025/dis32025.c
@@ -0,0 +1,135 @@
+ /**************************************************************************\
+ * Texas Instruments TMS320x25 DSP Disassembler *
+ * *
+ * Copyright (C) 2001-2002+ Tony La Porta *
+ * Written for the MAME project. *
+ * *
+ * Notes : Data is expected to be read from source file as MSB first. *
+ * This is a word based microcontroller, with addressing *
+ * architecture based on the Harvard addressing scheme. *
+ * *
+ \**************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "32025dsm.c"
+
+
+unsigned char *Buffer;
+
+
+int main(int argc,char *argv[])
+{
+ int length=0, length_to_dump=0, offset=0, disasm_words=0;
+ int filelength=0, bytes_read;
+ int Counter=0;
+
+ FILE *F;
+ char *String_Output;
+
+ if(argc<2)
+ {
+ printf("\n");
+ printf("TMS32025 Disassembler 1.1 by Tony La Porta (C)2001-2002+\n\n");
+ printf("Usage: dis32025 <input-file> [ <start-addr> [ <num-of-addr> ] ]\n");
+ printf(" <input-file> source file data must be MSB first\n");
+ printf(" <start-addr> starting address to disassemble from (decimal)\n");
+ printf(" <num-of-addr> number of addresses to disassemble (decimal)\n");
+ printf(" Preceed values with 0x if HEX values preffered\n");
+ exit(1);
+ }
+
+ if(!(F=fopen(argv[1],"rb")))
+ {
+ printf("\n%s: Can't open file %s\n",argv[0],argv[1]);
+ exit(2);
+ }
+ argv++; argc--;
+ if (argv[1])
+ {
+ offset = strtol(argv[1],NULL,0);
+ argv++; argc--;
+ }
+ if (argv[1])
+ {
+ length = strtol(argv[1],NULL,0);
+ argv++; argc--;
+ }
+
+ fseek(F,0, SEEK_END);
+ filelength = ftell(F);
+
+ length *= 2;
+
+ if ((length > (filelength - (offset*2))) || (length == 0)) length = filelength - (offset*2);
+ printf("Length=%04Xh(words) Offset=$%04Xh filelength=%04Xh(words) %04Xh(bytes)\n",length/2,offset,filelength/2,filelength);
+ length_to_dump = length;
+ printf("Starting from %d, dumping %d opcodes (word size)\n",offset,length/2);
+ Buffer = calloc((filelength+1),sizeof(char));
+ if (Buffer==NULL)
+ {
+ printf("Out of Memory !!!");
+ fclose(F);
+ exit(3);
+ }
+ String_Output = calloc(80,sizeof(char));
+ if (String_Output==NULL)
+ {
+ printf("Out of Memory !!!");
+ free(Buffer);
+ fclose(F);
+ exit(4);
+ }
+
+ if (fseek(F,0,SEEK_SET) != 0)
+ {
+ printf("Error seeking to beginning of file\n");
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ exit(5);
+ }
+
+ Counter = offset;
+ bytes_read = fread(Buffer,sizeof(char),filelength,F);
+ if (bytes_read >= length)
+ {
+ for (; length > 0; length -= (disasm_words*2))
+ {
+ int ii;
+ disasm_words = Dasm32025(String_Output,Counter);
+ printf("$%04lX: ",Counter);
+ for (ii = 0; ii < disasm_words; ii++)
+ {
+ if (((Counter*2) + ii) > filelength) /* Past end of length to dump ? */
+ {
+ sprintf(String_Output,"???? dw %02.2X%02.2Xh (Past end of disassembly !)",Buffer[((Counter-1)*2)],Buffer[((Counter-1)*2)+1]);
+ }
+ else
+ {
+ printf("%02.2x%02.2x ",Buffer[(Counter*2)],Buffer[(Counter*2) + 1]);
+ }
+ Counter++ ;
+ }
+ for (; ii < 4; ii++)
+ {
+ printf(" ");
+ }
+ printf("\t%s\n",String_Output);
+ }
+ }
+ else
+ {
+ printf("ERROR length to dump was %d ", length_to_dump/2);
+ printf(", but bytes read from file were %d\n", bytes_read/2);
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ exit(7);
+ }
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ return(0);
+}
diff --git a/src/emu/cpu/tms32025/tms32025.c b/src/emu/cpu/tms32025/tms32025.c
new file mode 100644
index 00000000000..a4935a38c8d
--- /dev/null
+++ b/src/emu/cpu/tms32025/tms32025.c
@@ -0,0 +1,2477 @@
+ /**************************************************************************\
+ * Texas Instruments TMS320x25 DSP Emulator *
+ * *
+ * Copyright (C) 2001-2002+ Tony La Porta *
+ * Written for the MAME project. *
+ * *
+ * *
+ * Three versions of the chip are available, and they are: *
+ * TMS320C25 Internal ROM one time programmed at TI *
+ * TMS320E25 Internal ROM programmable as a normal EPROM *
+ * TMS320P25 Internal ROM programmable once as a normal EPROM only *
+ * These devices can also be used as a MicroController with external ROM *
+ * *
+ * *
+ * Notes : The term 'DMA' within this document, is in reference *
+ * to Direct Memory Addressing, and NOT the usual term *
+ * of Direct Memory Access. *
+ * This is a word based microcontroller, with addressing *
+ * architecture based on the Harvard addressing scheme. *
+ * *
+ * *
+ * *
+ * **** Change Log **** *
+ * *
+ * TLP (2x-May-2001) *
+ * - Work began on this emulator *
+ * TLP (12-Jul-2001) *
+ * - First private release *
+ * TLP (xx-Dec-2001) Ver 0.11 *
+ * - Various undocumented fixes *
+ * TLP (13-Jul-2002) Ver 0.12 *
+ * - Corrected IRQ2 vector pointer *
+ * - Fixed the signedness in many equation based instructions *
+ * - Adjusted the level sensing for the Signal inputs *
+ * - Added the ability to view the CPU in the debugger when it's halted *
+ * TLP (16-Nov-2002) *
+ * - First public release after nearly 1.5 years! *
+ * - Adjusted more signedness instructions (ADDH, SUBC, SUBH, etc) *
+ * TLP (21-Dec-2002) *
+ * - Added memory banking for the CNFD, CNFP and CONF instructions *
+ * - Corrected IRQ masking checks *
+ * TLP (25-Dec-2002) Ver 1.10 *
+ * - Added internal timer *
+ * *
+ \**************************************************************************/
+
+/*****************************************************************************
+ To fix, or currently lacking from this emulator are:
+
+ Fix the levels for S_IN and S_OUT - use assert/release line
+
+ # Support for the built in Timer/Counter Page 91
+ When idling, Counter must still be activly counting down. When counter
+ reaches 0 it should issue a TINT (if it's not masked), then come out of
+ IDLE mode.
+ If TINT is masked, the Timer still needs to count down.
+
+ # Support for the built in Serial Port
+ # Support for the Global memory register
+ # Support for the switch for RAM block 0 banking between RAM and ROM space
+ # Correct the mulit-cycle instruction cycle counts
+ # Add support to set ROM & RAM as Internal/External in order to correctly
+ compute cycle timings
+ # Possibly add internal memory into here (instead of having it in the driver)
+ # Check (read) Hold signal level during execution loop ?
+ # Fix bugs
+ # Fix more bugs :-)
+ # Add/fix other things I forgot
+*****************************************************************************/
+
+/*
+ TMS32025 CONF Mode Decoding Table
+|=======================================|
+| Status bit | Blocks |
+| CNF | B0 | B1 | B2 |
+|------------+---------+---------+------|
+| 0 0 | data | data | data |
+| 1 1 | program | data | data |
+|=======================================|
+
+
+ TMS32026 CONF Mode Decoding Table
+|==================================================|
+| Status bits | Blocks |
+| CNF1 | CNF0 | B0 | B1 | B2 | B3 |
+|------+------+---------+---------+------+---------|
+| 0 | 0 | data | data | data | data |
+| 0 | 1 | program | data | data | data |
+| 1 | 0 | program | program | data | data |
+| 1 | 1 | program | program | data | program |
+|==================================================|
+
+
+
+Table 3-2. TMS32025/26 Memory Blocks
+|=========================================================|
+| Configured As Data Memory |
+|-------+-------TMS320C25--------+-------TMS320C26--------|
+| | | Hexadecimal | | Hexadecimal |
+| Block | Pages | Address | Pages | Address |
+|-------+---------+--------------+---------+--------------|
+| B2 | 0 | 0060h-007Fh | 0 | 0060h-007Fh |
+| B0 | 4-5 | 0200h-02FFh | 4-7 | 0200h-03FFh |
+| B1 | 6-7 | 0300h-03FFh | 8-11 | 0400h-05FFh |
+| B3 | B3 does not exist | 12-15 | 0600h-07FFh |
+|=========================================================|
+| Configured As Program Memory |
+|-------+-------TMS320C25--------+-------TMS320C26--------|
+| | | Hexadecimal | | Hexadecimal |
+| Block | Pages | Address | Pages | Address |
+|-------+---------+--------------+---------+--------------|
+| B2 | B2 is not configurable | B2 is not configurable |
+| B0 | 510-511 | FF00h-FFFFh | 500-503 | FA00h-FBFFh |
+| B1 | B1 is not configurable | 504-507 | FC00h-FDFFh |
+| B3 | B3 does not exist | 508-511 | FE00h-FFFFh |
+|=========================================================|
+*/
+
+
+
+#include "tms32025.h"
+#include "debugger.h"
+
+
+#define CLK 4 /* 1 cycle equals 4 clock ticks */ /* PE/DI */
+
+
+#ifndef INLINE
+#define INLINE static inline
+#endif
+
+
+UINT16 *tms32025_pgmmap[0x200];
+UINT16 *tms32025_datamap[0x200];
+
+#define SET_PC(x) do { R.PC = (x); change_pc(R.PC<<1); } while (0)
+
+INLINE UINT16 M_RDROM(offs_t addr)
+{
+ UINT16 *ram;
+ addr &= 0xffff;
+ ram = tms32025_pgmmap[addr >> 7];
+ if (ram) return ram[addr & 0x7f];
+ return program_read_word_16be(addr << 1);
+}
+
+INLINE void M_WRTROM(offs_t addr, UINT16 data)
+{
+ UINT16 *ram;
+ addr &= 0xffff;
+ ram = tms32025_pgmmap[addr >> 7];
+ if (ram) { ram[addr & 0x7f] = data; }
+ else program_write_word_16be(addr << 1, data);
+}
+
+INLINE UINT16 M_RDRAM(offs_t addr)
+{
+ UINT16 *ram;
+ addr &= 0xffff;
+ ram = tms32025_datamap[addr >> 7];
+ if (ram) return ram[addr & 0x7f];
+ return data_read_word_16be(addr << 1);
+}
+
+INLINE void M_WRTRAM(offs_t addr, UINT16 data)
+{
+ UINT16 *ram;
+ addr &= 0xffff;
+ ram = tms32025_datamap[addr >> 7];
+ if (ram) { ram[addr & 0x7f] = data; }
+ else data_write_word_16be(addr << 1, data);
+}
+
+#define P_IN(A) (io_read_word_16be((A)<<1))
+#define P_OUT(A,V) (io_write_word_16be(((A)<<1),(V)))
+#define S_IN(A) (io_read_word_16be((A)<<1))
+#define S_OUT(A,V) (io_write_word_16be(((A)<<1),(V)))
+
+#define M_RDOP(A) ((tms32025_pgmmap[(A) >> 7]) ? (tms32025_pgmmap[(A) >> 7][(A) & 0x7f]) : cpu_readop16((A)<<1))
+#define M_RDOP_ARG(A) ((tms32025_pgmmap[(A) >> 7]) ? (tms32025_pgmmap[(A) >> 7][(A) & 0x7f]) : cpu_readop16((A)<<1))
+
+
+
+typedef struct /* Page 3-6 (45) shows all registers */
+{
+ /******************** CPU Internal Registers *******************/
+ UINT16 PREVPC; /* previous program counter */
+ UINT16 PC;
+ UINT16 PFC;
+ UINT16 STR0, STR1;
+ UINT8 IFR;
+ UINT8 RPTC;
+ PAIR ACC; /* PAIR defined in os/osd_cpu.h */
+ PAIR Preg;
+ UINT16 Treg;
+ UINT16 AR[8];
+ UINT16 STACK[8];
+ PAIR ALU;
+ UINT16 *intRAM;
+ UINT8 timerover;
+
+ /********************** Status data ****************************/
+ PAIR opcode;
+ int idle;
+ int hold;
+ int external_mem_access; /** required for hold mode. Implement it ! */
+ int init_load_addr; /* 0=No, 1=Yes, 2=Once for repeat mode */
+ int tms32025_irq_cycles;
+ int tms32025_dec_cycles;
+ int (*irq_callback)(int irqline);
+ UINT16 *datamap_save[16];
+ UINT16 *pgmmap_save[12];
+} tms32025_Regs;
+
+static tms32025_Regs R;
+static PAIR oldacc;
+static UINT32 memaccess;
+static int tms32025_icount;
+typedef void (*opcode_fn) (void);
+
+
+/************************** Memory mapped registers ****************/
+#define DRR R.intRAM[0]
+#define DXR R.intRAM[1]
+#define TIM R.intRAM[2]
+#define PRD R.intRAM[3]
+#define IMR R.intRAM[4]
+#define GREG R.intRAM[5]
+
+
+
+/****************************************************************************
+ ******* The following is the Status (Flag) register 0 definition. ********
+| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+| <----ARP---> | OV | OVM | 1 | INTM | <--------------DP---------------> | */
+
+#define ARP_REG 0xe000 /* ARP (Auxiliary Register Pointer) */
+#define OV_FLAG 0x1000 /* OV (Overflow flag) 1 indicates an overflow */
+#define OVM_FLAG 0x0800 /* OVM (Overflow Mode bit) 1 forces ACC overflow to greatest positive or negative saturation value */
+#define INTM_FLAG 0x0200 /* INTM (Interrupt Mask flag) 0 enables maskable interrupts */
+#define DP_REG 0x01ff /* DP (Data bank memory Pointer) */
+
+
+/***********************************************************************************
+ *** The following is the Status (Flag) register 1 definition for TMS32025. ********
+| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+| <----ARB---> | CNF0 | TC | SXM | C | 1 | 1 | HM | FSM | XF | FO | TXM | <-PM-> | */
+
+/*** The following is the Status (Flag) register 1 definition for TMS32026. ***********
+| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+| <----ARB---> | CNF0 | TC | SXM | C | 1 | CNF1 | HM | FSM | XF | FO | TXM | <-PM-> | */
+
+#define ARB_REG 0xe000 /* ARB (Auxiliary Register pointer Backup) */
+#define CNF0_REG 0x1000 /* CNF0 (Onchip RAM CoNFiguration) 0 means B0=data memory, 1means B0=program memory */
+#define CNF1_REG 0x0080 /* CNF1 (Onchip RAM CoNFiguration) 0 means B0=data memory, 1means B0=program memory */
+#define TC_FLAG 0x0800 /* TC (Test Control flag) */
+#define SXM_FLAG 0x0400 /* SXM (Sign eXtension Mode) */
+#define C_FLAG 0x0200 /* C (Carry flag) */
+#define HM_FLAG 0x0040 /* HM (Processor Hold Mode) */
+#define FSM_FLAG 0x0020 /* FSM (Frame Synchronization Mode - for serial port) */
+#define XF_FLAG 0x0010 /* XF (XF output pin status) */
+#define FO_FLAG 0x0008 /* FO (Serial port Format In/Out mode) */
+#define TXM_FLAG 0x0004 /* TXM (Transmit Mode - for serial port) */
+#define PM_REG 0x0003 /* PM (Product shift Mode) */
+
+
+#define OV ( R.STR0 & OV_FLAG) /* OV (Overflow flag) */
+#define OVM ( R.STR0 & OVM_FLAG) /* OVM (Overflow Mode bit) 1 indicates an overflow */
+#define INTM ( R.STR0 & INTM_FLAG) /* INTM (Interrupt enable flag) 0 enables maskable interrupts */
+#define ARP ((R.STR0 & ARP_REG) >> 13) /* ARP (Auxiliary Register Pointer) */
+#define DP ((R.STR0 & DP_REG) << 7) /* DP (Data memory Pointer bit) */
+#define ARB ( R.STR1 & ARB_REG) /* ARB (Backup Auxiliary Register pointer) */
+#define CNF0 ( R.STR1 & CNF0_REG) /* CNF0 (Onchip Ram Config register) */
+#define TC ( R.STR1 & TC_FLAG) /* TC (Test Control Flag) */
+#define SXM ( R.STR1 & SXM_FLAG) /* SXM (Sign Extension Mode) */
+#define CARRY ( R.STR1 & C_FLAG) /* C (Carry Flag for accumulator) */
+#define HM ( R.STR1 & HM_FLAG) /* HM (Processor Hold Mode) */
+#define FSM ( R.STR1 & FSM_FLAG) /* FSM (Frame Synchronization Mode - for serial port) */
+#define XF ( R.STR1 & FSM_FLAG) /* XF (XF output pin status) */
+#define FO ( R.STR1 & FO_FLAG) /* FO (Serial port Format In/Out mode) */
+#define TXM ( R.STR1 & TXM_FLAG) /* TXM (Transmit Mode - for serial port) */
+#define PM ( R.STR1 & PM_REG) /* PM (P register shift Mode. See SHIFT_Preg_TO_ALU below )*/
+
+#define DMA (DP | (R.opcode.b.l & 0x7f)) /* address used in direct memory access operations */
+#define DMApg0 (R.opcode.b.l & 0x7f) /* address used in direct memory access operations for sst instruction */
+#define IND R.AR[ARP] /* address used in indirect memory access operations */
+
+INLINE void CLR0(UINT16 flag) { R.STR0 &= ~flag; R.STR0 |= 0x0400; }
+INLINE void SET0(UINT16 flag) { R.STR0 |= flag; R.STR0 |= 0x0400; }
+INLINE void CLR1(UINT16 flag) { R.STR1 &= ~flag; R.STR1 |= 0x0180; }
+INLINE void SET1(UINT16 flag) { R.STR1 |= flag; R.STR1 |= 0x0180; }
+INLINE void MODIFY_DP (int data) { R.STR0 &= ~DP_REG; R.STR0 |= (data & DP_REG); R.STR0 |= 0x0400; }
+INLINE void MODIFY_PM (int data) { R.STR1 &= ~PM_REG; R.STR1 |= (data & PM_REG); R.STR1 |= 0x0180; }
+INLINE void MODIFY_ARP(int data) { R.STR1 &= ~ARB_REG; R.STR1 |= (R.STR0 & ARP_REG); R.STR1 |= 0x0180; \
+ R.STR0 &= ~ARP_REG; R.STR0 |= ((data << 13) & ARP_REG); R.STR0 |= 0x0400; }
+INLINE void MODIFY_ARB(int data) { R.STR1 &= ~ARB_REG; R.STR1 |= ((data << 13) & ARB_REG); R.STR1 |= 0x0180; }
+
+static int mHackIgnoreARP; /* special handling for lst, lst1 instructions */
+
+static UINT16 reverse_carry_add( UINT16 arg0, UINT16 arg1 )
+{
+ UINT16 result = 0;
+ int carry = 0;
+ int count;
+ for( count=0; count<16; count++ )
+ {
+ int sum = (arg0>>15)+(arg1>>15)+carry;
+ result = (result<<1)|(sum&1);
+ carry = sum>>1;
+ arg0<<=1;
+ arg1<<=1;
+ }
+ return result;
+}
+
+INLINE void MODIFY_AR_ARP(void)
+{ /* modify address register referenced by ARP */
+ switch (R.opcode.b.l & 0x70) /* Cases ordered by predicted useage */
+ {
+ case 0x00: /* 000 nop */
+ break;
+
+ case 0x10: /* 001 *- */
+ R.AR[ARP] -- ;
+ break;
+
+ case 0x20: /* 010 *+ */
+ R.AR[ARP] ++ ;
+ break;
+
+ case 0x30: /* 011 reserved */
+ break;
+
+ case 0x40: /* 100 *BR0- */
+ R.AR[ARP] = reverse_carry_add(R.AR[ARP],-R.AR[0]);
+ break;
+
+ case 0x50: /* 101 *0- */
+ R.AR[ARP] -= R.AR[0];
+ break;
+
+ case 0x60: /* 110 *0+ */
+ R.AR[ARP] += R.AR[0];
+ break;
+
+ case 0x70: /* 111 *BR0+ */
+ R.AR[ARP] += reverse_carry_add(R.AR[ARP],R.AR[0]);
+ break;
+
+ default:
+ break;
+ }
+
+ if( !mHackIgnoreARP )
+ {
+ if (R.opcode.b.l & 8)
+ { /* bit 3 determines if new value is loaded into ARP */
+ MODIFY_ARP(R.opcode.b.l & 7);
+ }
+ }
+}
+
+INLINE void CALCULATE_ADD_CARRY(void)
+{
+ if ( (UINT32)(oldacc.d) > (UINT32)(R.ACC.d) ) {
+ SET1(C_FLAG);
+ }
+ else {
+ CLR1(C_FLAG);
+ }
+}
+
+INLINE void CALCULATE_SUB_CARRY(void)
+{
+ if ( (UINT32)(oldacc.d) < (UINT32)(R.ACC.d) ) {
+ CLR1(C_FLAG);
+ }
+ else {
+ SET1(C_FLAG);
+ }
+}
+
+INLINE void CALCULATE_ADD_OVERFLOW(INT32 addval)
+{
+ if ((INT32)(~(oldacc.d ^ addval) & (oldacc.d ^ R.ACC.d)) < 0)
+ {
+ SET0(OV_FLAG);
+ if (OVM)
+ {
+ // Stroff:HACK! support for overflow capping as implemented results in bad DSP floating point math in many
+ // System22 games - for example, the score display in Prop Cycle.
+ // R.ACC.d = ((INT32)oldacc.d < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ }
+}
+INLINE void CALCULATE_SUB_OVERFLOW(INT32 subval)
+{
+ if ((INT32)((oldacc.d ^ subval) & (oldacc.d ^ R.ACC.d)) < 0)
+ {
+ SET0(OV_FLAG);
+ if (OVM)
+ {
+ R.ACC.d = ((INT32)oldacc.d < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ }
+}
+
+INLINE UINT16 POP_STACK(void)
+{
+ UINT16 data = R.STACK[7];
+ R.STACK[7] = R.STACK[6];
+ R.STACK[6] = R.STACK[5];
+ R.STACK[5] = R.STACK[4];
+ R.STACK[4] = R.STACK[3];
+ R.STACK[3] = R.STACK[2];
+ R.STACK[2] = R.STACK[1];
+ R.STACK[1] = R.STACK[0];
+ return data;
+}
+INLINE void PUSH_STACK(UINT16 data)
+{
+ R.STACK[0] = R.STACK[1];
+ R.STACK[1] = R.STACK[2];
+ R.STACK[2] = R.STACK[3];
+ R.STACK[3] = R.STACK[4];
+ R.STACK[4] = R.STACK[5];
+ R.STACK[5] = R.STACK[6];
+ R.STACK[6] = R.STACK[7];
+ R.STACK[7] = data;
+}
+
+INLINE void SHIFT_Preg_TO_ALU(void)
+{
+ switch(PM) /* PM (in STR1) is the shift mode for Preg */
+ {
+ case 0: R.ALU.d = R.Preg.d; break;
+ case 1: R.ALU.d = (R.Preg.d << 1); break;
+ case 2: R.ALU.d = (R.Preg.d << 4); break;
+ case 3: R.ALU.d = (R.Preg.d >> 6); if (R.Preg.d & 0x80000000) R.ALU.d |= 0xfc000000; break;
+ default: break;
+ }
+}
+
+INLINE void GETDATA(int shift,int signext)
+{
+ if (R.opcode.b.l & 0x80)
+ { /* indirect memory access */
+ memaccess = IND;
+ }
+ else
+ { /* direct memory address */
+ memaccess = DMA;
+ }
+
+ if (memaccess >= 0x800)
+ {
+ R.external_mem_access = 1; /* Pause if hold pin is active */
+ }
+ else
+ {
+ R.external_mem_access = 0;
+ }
+
+ R.ALU.d = (UINT16)M_RDRAM(memaccess);
+ if (signext) R.ALU.d = (INT16)R.ALU.d;
+ R.ALU.d <<= shift;
+
+ /* next ARP */
+ if (R.opcode.b.l & 0x80) MODIFY_AR_ARP();
+}
+
+INLINE void PUTDATA(UINT16 data)
+{
+ if (R.opcode.b.l & 0x80) {
+ if (memaccess >= 0x800) R.external_mem_access = 1; /* Pause if hold pin is active */
+ else R.external_mem_access = 0;
+
+ M_WRTRAM(IND,data);
+ MODIFY_AR_ARP();
+ }
+ else {
+ if (memaccess >= 0x800) R.external_mem_access = 1; /* Pause if hold pin is active */
+ else R.external_mem_access = 0;
+
+ M_WRTRAM(DMA,data);
+ }
+}
+INLINE void PUTDATA_SST(UINT16 data)
+{
+ if (R.opcode.b.l & 0x80) memaccess = IND;
+ else memaccess = DMApg0;
+
+ if (memaccess >= 0x800) R.external_mem_access = 1; /* Pause if hold pin is active */
+ else R.external_mem_access = 0;
+
+ if (R.opcode.b.l & 0x80) {
+ R.opcode.b.l &= 0xf7; /* Stop ARP changes */
+ MODIFY_AR_ARP();
+ }
+ M_WRTRAM(memaccess,data);
+}
+
+
+/* The following functions are here to fill the void for the */
+/* opcode call functions. These functions are never actually called. */
+static void opcodes_CE(void) { }
+static void opcodes_DX(void) { }
+
+static void illegal(void)
+{
+ logerror("TMS32025: PC = %04x, Illegal opcode = %04x\n", (R.PC-1), R.opcode.w.l);
+}
+
+static void abst(void)
+{
+ if ( (INT32)(R.ACC.d) < 0 ) {
+ R.ACC.d = -R.ACC.d;
+ if (R.ACC.d == 0x80000000)
+ {
+ SET0(OV_FLAG);
+ if (OVM) R.ACC.d-- ;
+ }
+ }
+ CLR1(C_FLAG);
+}
+static void add(void) /* #### add carry support - see page 3-31 (70) #### */
+{ /* page 10-13 (348) spru031d */
+ oldacc.d = R.ACC.d;
+ GETDATA((R.opcode.b.h & 0xf),SXM);
+ R.ACC.d += R.ALU.d;
+
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+}
+static void addc(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ if (CARRY) R.ALU.d++;
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+}
+static void addh(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ R.ACC.w.h += R.ALU.w.l;
+ if ((INT16)(~(oldacc.w.h ^ R.ALU.w.l) & (oldacc.w.h ^ R.ACC.w.h)) < 0) {
+ SET0(OV_FLAG);
+ if (OVM)
+ R.ACC.w.h = ((INT16)oldacc.w.h < 0) ? 0x8000 : 0x7fff;
+ }
+ if ( ((INT16)(oldacc.w.h) < 0) && ((INT16)(R.ACC.w.h) >= 0) ) {
+ SET1(C_FLAG);
+ }
+ /* Carry flag is not cleared, if no carry occured */
+}
+static void addk(void)
+{
+ oldacc.d = R.ACC.d;
+ R.ALU.d = (UINT8)R.opcode.b.l;
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+}
+static void adds(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+}
+static void addt(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA((R.Treg & 0xf),SXM);
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+}
+static void adlk(void)
+{
+ oldacc.d = R.ACC.d;
+ if (SXM) R.ALU.d = (INT16)M_RDOP_ARG(R.PC);
+ else R.ALU.d = (UINT16)M_RDOP_ARG(R.PC);
+ R.PC++;
+ R.ALU.d <<= (R.opcode.b.h & 0xf);
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+}
+static void adrk(void)
+{
+ R.AR[ARP] += R.opcode.b.l;
+}
+static void and(void)
+{
+ GETDATA(0,0);
+ R.ACC.d &= R.ALU.d;
+}
+static void andk(void)
+{
+ oldacc.d = R.ACC.d;
+ R.ALU.d = (UINT16)M_RDOP_ARG(R.PC);
+ R.PC++;
+ R.ALU.d <<= (R.opcode.b.h & 0xf);
+ R.ACC.d &= R.ALU.d;
+ R.ACC.d &= 0x7fffffff;
+}
+static void apac(void)
+{
+ oldacc.d = R.ACC.d;
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+}
+static void br(void)
+{
+ SET_PC(M_RDOP_ARG(R.PC));
+ MODIFY_AR_ARP();
+}
+static void bacc(void)
+{
+ SET_PC(R.ACC.w.l);
+}
+static void banz(void)
+{
+ if (R.AR[ARP]) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bbnz(void)
+{
+ if (TC) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bbz(void)
+{
+ if (TC == 0) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bc(void)
+{
+ if (CARRY) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bgez(void)
+{
+ if ( (INT32)(R.ACC.d) >= 0 ) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bgz(void)
+{
+ if ( (INT32)(R.ACC.d) > 0 ) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bioz(void)
+{
+ if (S_IN(TMS32025_BIO) != CLEAR_LINE) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bit(void)
+{
+ GETDATA(0,0);
+ if (R.ALU.d & (0x8000 >> (R.opcode.b.h & 0xf))) SET1(TC_FLAG);
+ else CLR1(TC_FLAG);
+}
+static void bitt(void)
+{
+ GETDATA(0,0);
+ if (R.ALU.d & (0x8000 >> (R.Treg & 0xf))) SET1(TC_FLAG);
+ else CLR1(TC_FLAG);
+}
+static void blez(void)
+{
+ if ( (INT32)(R.ACC.d) <= 0 ) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void blkd(void)
+{ /** Fix cycle timing **/
+ if (R.init_load_addr) {
+ R.PFC = M_RDOP_ARG(R.PC);
+ R.PC++;
+ }
+ R.ALU.d = M_RDRAM(R.PFC);
+ PUTDATA(R.ALU.d);
+ R.PFC++;
+ R.tms32025_dec_cycles += (1*CLK);
+}
+static void blkp(void)
+{ /** Fix cycle timing **/
+ if (R.init_load_addr) {
+ R.PFC = M_RDOP_ARG(R.PC);
+ R.PC++;
+ }
+ R.ALU.d = M_RDROM(R.PFC);
+ PUTDATA(R.ALU.d);
+ R.PFC++;
+ R.tms32025_dec_cycles += (2*CLK);
+}
+static void blz(void)
+{
+ if ( (INT32)(R.ACC.d) < 0 ) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bnc(void)
+{
+ if (CARRY == 0) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bnv(void)
+{
+ if (OV == 0) SET_PC(M_RDOP_ARG(R.PC));
+ else {
+ R.PC++ ;
+ CLR0(OV_FLAG);
+ }
+ MODIFY_AR_ARP();
+}
+static void bnz(void)
+{
+ if (R.ACC.d != 0) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bv(void)
+{
+ if (OV) {
+ SET_PC(M_RDOP_ARG(R.PC));
+ CLR0(OV_FLAG);
+ }
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void bz(void)
+{
+ if (R.ACC.d == 0) SET_PC(M_RDOP_ARG(R.PC));
+ else R.PC++ ;
+ MODIFY_AR_ARP();
+}
+static void cala(void)
+{
+ PUSH_STACK(R.PC);
+ SET_PC(R.ACC.w.l);
+}
+static void call(void)
+{
+ R.PC++ ;
+ PUSH_STACK(R.PC);
+ SET_PC(M_RDOP_ARG((R.PC - 1)));
+ MODIFY_AR_ARP();
+}
+static void cmpl(void)
+{
+ R.ACC.d = (~R.ACC.d);
+}
+static void cmpr(void)
+{
+ switch (R.opcode.b.l & 3)
+ {
+ case 00: if ( (UINT16)(R.AR[ARP]) == (UINT16)(R.AR[0]) ) SET1(TC_FLAG); else CLR1(TC_FLAG); break;
+ case 01: if ( (UINT16)(R.AR[ARP]) < (UINT16)(R.AR[0]) ) SET1(TC_FLAG); else CLR1(TC_FLAG); break;
+ case 02: if ( (UINT16)(R.AR[ARP]) > (UINT16)(R.AR[0]) ) SET1(TC_FLAG); else CLR1(TC_FLAG); break;
+ case 03: if ( (UINT16)(R.AR[ARP]) != (UINT16)(R.AR[0]) ) SET1(TC_FLAG); else CLR1(TC_FLAG); break;
+ default: break;
+ }
+}
+static void cnfd(void) /** next two fetches need to use previous CNF value ! **/
+{
+ CLR1(CNF0_REG);
+ tms32025_datamap[4] = &R.intRAM[0x200]; /* B0 */
+ tms32025_datamap[5] = &R.intRAM[0x280]; /* B0 */
+ tms32025_pgmmap[510] = NULL;
+ tms32025_pgmmap[511] = NULL;
+}
+static void cnfp(void) /** next two fetches need to use previous CNF value ! **/
+{
+ SET1(CNF0_REG);
+ tms32025_datamap[4] = NULL; /* B0 */
+ tms32025_datamap[5] = NULL; /* B0 */
+ tms32025_pgmmap[510] = &R.intRAM[0x200];
+ tms32025_pgmmap[511] = &R.intRAM[0x280];
+}
+static void conf(void) /** Need to reconfigure the memory blocks */
+{
+ switch (R.opcode.b.l & 3)
+ {
+ case 00: CLR1(CNF1_REG); CLR1(CNF0_REG);
+ tms32025_datamap[4] = &R.intRAM[0x200]; /* B0 */
+ tms32025_datamap[5] = &R.intRAM[0x280]; /* B0 */
+ tms32025_datamap[6] = &R.intRAM[0x300]; /* B0 */
+ tms32025_datamap[7] = &R.intRAM[0x380]; /* B0 */
+ tms32025_datamap[8] = &R.intRAM[0x400]; /* B1 */
+ tms32025_datamap[9] = &R.intRAM[0x480]; /* B1 */
+ tms32025_datamap[10] = &R.intRAM[0x500]; /* B1 */
+ tms32025_datamap[11] = &R.intRAM[0x580]; /* B1 */
+ tms32025_datamap[12] = &R.intRAM[0x600]; /* B3 */
+ tms32025_datamap[13] = &R.intRAM[0x680]; /* B3 */
+ tms32025_datamap[14] = &R.intRAM[0x700]; /* B3 */
+ tms32025_datamap[15] = &R.intRAM[0x780]; /* B3 */
+ tms32025_pgmmap[500] = NULL;
+ tms32025_pgmmap[501] = NULL;
+ tms32025_pgmmap[502] = NULL;
+ tms32025_pgmmap[503] = NULL;
+ tms32025_pgmmap[504] = NULL;
+ tms32025_pgmmap[505] = NULL;
+ tms32025_pgmmap[506] = NULL;
+ tms32025_pgmmap[507] = NULL;
+ tms32025_pgmmap[508] = NULL;
+ tms32025_pgmmap[509] = NULL;
+ tms32025_pgmmap[510] = NULL;
+ tms32025_pgmmap[511] = NULL;
+ break;
+ case 01: CLR1(CNF1_REG); SET1(CNF0_REG);
+ tms32025_datamap[4] = NULL;
+ tms32025_datamap[5] = NULL;
+ tms32025_datamap[6] = NULL;
+ tms32025_datamap[7] = NULL;
+ tms32025_datamap[8] = &R.intRAM[0x400]; /* B1 */
+ tms32025_datamap[9] = &R.intRAM[0x480]; /* B1 */
+ tms32025_datamap[10] = &R.intRAM[0x500]; /* B1 */
+ tms32025_datamap[11] = &R.intRAM[0x580]; /* B1 */
+ tms32025_datamap[12] = &R.intRAM[0x600]; /* B3 */
+ tms32025_datamap[13] = &R.intRAM[0x680]; /* B3 */
+ tms32025_datamap[14] = &R.intRAM[0x700]; /* B3 */
+ tms32025_datamap[15] = &R.intRAM[0x780]; /* B3 */
+ tms32025_pgmmap[500] = &R.intRAM[0x200]; /* B0 */
+ tms32025_pgmmap[501] = &R.intRAM[0x280]; /* B0 */
+ tms32025_pgmmap[502] = &R.intRAM[0x300]; /* B0 */
+ tms32025_pgmmap[503] = &R.intRAM[0x380]; /* B0 */
+ tms32025_pgmmap[504] = NULL;
+ tms32025_pgmmap[505] = NULL;
+ tms32025_pgmmap[506] = NULL;
+ tms32025_pgmmap[507] = NULL;
+ tms32025_pgmmap[508] = NULL;
+ tms32025_pgmmap[509] = NULL;
+ tms32025_pgmmap[510] = NULL;
+ tms32025_pgmmap[511] = NULL;
+ break;
+ case 02: SET1(CNF1_REG); CLR1(CNF0_REG);
+ tms32025_datamap[4] = NULL;
+ tms32025_datamap[5] = NULL;
+ tms32025_datamap[6] = NULL;
+ tms32025_datamap[7] = NULL;
+ tms32025_datamap[8] = NULL;
+ tms32025_datamap[9] = NULL;
+ tms32025_datamap[10] = NULL;
+ tms32025_datamap[11] = NULL;
+ tms32025_datamap[12] = &R.intRAM[0x600]; /* B3 */
+ tms32025_datamap[13] = &R.intRAM[0x680]; /* B3 */
+ tms32025_datamap[14] = &R.intRAM[0x700]; /* B3 */
+ tms32025_datamap[15] = &R.intRAM[0x780]; /* B3 */
+ tms32025_pgmmap[500] = &R.intRAM[0x200]; /* B0 */
+ tms32025_pgmmap[501] = &R.intRAM[0x280]; /* B0 */
+ tms32025_pgmmap[502] = &R.intRAM[0x300]; /* B0 */
+ tms32025_pgmmap[503] = &R.intRAM[0x380]; /* B0 */
+ tms32025_pgmmap[504] = &R.intRAM[0x400]; /* B1 */
+ tms32025_pgmmap[505] = &R.intRAM[0x480]; /* B1 */
+ tms32025_pgmmap[506] = &R.intRAM[0x500]; /* B1 */
+ tms32025_pgmmap[507] = &R.intRAM[0x580]; /* B1 */
+ tms32025_pgmmap[508] = NULL;
+ tms32025_pgmmap[509] = NULL;
+ tms32025_pgmmap[510] = NULL;
+ tms32025_pgmmap[511] = NULL;
+ break;
+ case 03: SET1(CNF1_REG); SET1(CNF0_REG);
+ tms32025_datamap[4] = NULL;
+ tms32025_datamap[5] = NULL;
+ tms32025_datamap[6] = NULL;
+ tms32025_datamap[7] = NULL;
+ tms32025_datamap[8] = NULL;
+ tms32025_datamap[9] = NULL;
+ tms32025_datamap[10] = NULL;
+ tms32025_datamap[11] = NULL;
+ tms32025_datamap[12] = NULL;
+ tms32025_datamap[13] = NULL;
+ tms32025_datamap[14] = NULL;
+ tms32025_datamap[15] = NULL;
+ tms32025_pgmmap[500] = &R.intRAM[0x200]; /* B0 */
+ tms32025_pgmmap[501] = &R.intRAM[0x280]; /* B0 */
+ tms32025_pgmmap[502] = &R.intRAM[0x300]; /* B0 */
+ tms32025_pgmmap[503] = &R.intRAM[0x380]; /* B0 */
+ tms32025_pgmmap[504] = &R.intRAM[0x400]; /* B1 */
+ tms32025_pgmmap[505] = &R.intRAM[0x480]; /* B1 */
+ tms32025_pgmmap[506] = &R.intRAM[0x500]; /* B1 */
+ tms32025_pgmmap[507] = &R.intRAM[0x580]; /* B1 */
+ tms32025_pgmmap[508] = &R.intRAM[0x600]; /* B3 */
+ tms32025_pgmmap[509] = &R.intRAM[0x680]; /* B3 */
+ tms32025_pgmmap[510] = &R.intRAM[0x700]; /* B3 */
+ tms32025_pgmmap[511] = &R.intRAM[0x780]; /* B3 */
+ break;
+ default: break;
+ }
+}
+static void dint(void)
+{
+ SET0(INTM_FLAG);
+}
+static void dmov(void) /** Careful with how memory is configured !! */
+{
+ GETDATA(0,0);
+ M_WRTRAM((memaccess + 1),R.ALU.w.l);
+}
+static void eint(void)
+{
+ CLR0(INTM_FLAG);
+}
+static void fort(void)
+{
+ if (R.opcode.b.l & 1) SET1(FO_FLAG);
+ else CLR1(FO_FLAG);
+}
+static void idle(void)
+{
+ CLR0(INTM_FLAG);
+ R.idle = 1;
+}
+static void in(void)
+{
+ R.ALU.w.l = P_IN( (R.opcode.b.h & 0xf) );
+ PUTDATA(R.ALU.w.l);
+}
+static void lac(void)
+{
+ GETDATA( (R.opcode.b.h & 0xf),SXM );
+ R.ACC.d = R.ALU.d;
+}
+static void lack(void) /* ZAC is a subset of this instruction */
+{
+ R.ACC.d = (UINT8)R.opcode.b.l;
+}
+static void lact(void)
+{
+ GETDATA( (R.Treg & 0xf),SXM );
+ R.ACC.d = R.ALU.d;
+}
+static void lalk(void)
+{
+ if (SXM) {
+ R.ALU.d = (INT16)M_RDOP_ARG(R.PC);
+ R.ACC.d = R.ALU.d << (R.opcode.b.h & 0xf);
+ }
+ else {
+ R.ALU.d = (UINT16)M_RDOP_ARG(R.PC);
+ R.ACC.d = R.ALU.d << (R.opcode.b.h & 0xf);
+ R.ACC.d &= 0x7fffffff;
+ }
+ R.PC++;
+}
+static void lar_ar0(void) { GETDATA(0,0); R.AR[0] = R.ALU.w.l; }
+static void lar_ar1(void) { GETDATA(0,0); R.AR[1] = R.ALU.w.l; }
+static void lar_ar2(void) { GETDATA(0,0); R.AR[2] = R.ALU.w.l; }
+static void lar_ar3(void) { GETDATA(0,0); R.AR[3] = R.ALU.w.l; }
+static void lar_ar4(void) { GETDATA(0,0); R.AR[4] = R.ALU.w.l; }
+static void lar_ar5(void) { GETDATA(0,0); R.AR[5] = R.ALU.w.l; }
+static void lar_ar6(void) { GETDATA(0,0); R.AR[6] = R.ALU.w.l; }
+static void lar_ar7(void) { GETDATA(0,0); R.AR[7] = R.ALU.w.l; }
+static void lark_ar0(void) { R.AR[0] = R.opcode.b.l; }
+static void lark_ar1(void) { R.AR[1] = R.opcode.b.l; }
+static void lark_ar2(void) { R.AR[2] = R.opcode.b.l; }
+static void lark_ar3(void) { R.AR[3] = R.opcode.b.l; }
+static void lark_ar4(void) { R.AR[4] = R.opcode.b.l; }
+static void lark_ar5(void) { R.AR[5] = R.opcode.b.l; }
+static void lark_ar6(void) { R.AR[6] = R.opcode.b.l; }
+static void lark_ar7(void) { R.AR[7] = R.opcode.b.l; }
+static void ldp(void)
+{
+ GETDATA(0,0);
+ MODIFY_DP(R.ALU.d & 0x1ff);
+}
+static void ldpk(void)
+{
+ MODIFY_DP(R.opcode.w.l & 0x1ff);
+}
+static void lph(void)
+{
+ GETDATA(0,0);
+ R.Preg.w.h = R.ALU.w.l;
+}
+static void lrlk(void)
+{
+ R.ALU.d = (UINT16)M_RDOP_ARG(R.PC);
+ R.PC++;
+ R.AR[R.opcode.b.h & 7] = R.ALU.w.l;
+}
+static void lst(void)
+{
+ mHackIgnoreARP = 1;
+ GETDATA(0,0);
+ mHackIgnoreARP = 0;
+
+ R.ALU.w.l &= (~INTM_FLAG);
+ R.STR0 &= INTM_FLAG;
+ R.STR0 |= R.ALU.w.l; /* Must not affect INTM */
+ R.STR0 |= 0x0400;
+}
+static void lst1(void)
+{
+ mHackIgnoreARP = 1;
+ GETDATA(0,0);
+ mHackIgnoreARP = 0;
+
+ R.STR1 = R.ALU.w.l;
+ R.STR1 |= 0x0180;
+ R.STR0 &= (~ARP_REG); /* ARB also gets copied to ARP */
+ R.STR0 |= (R.STR1 & ARB_REG);
+}
+static void lt(void)
+{
+ GETDATA(0,0);
+ R.Treg = R.ALU.w.l;
+}
+static void lta(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ R.Treg = R.ALU.w.l;
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+}
+static void ltd(void) /** Careful with how memory is configured !! */
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ R.Treg = R.ALU.w.l;
+ M_WRTRAM((memaccess+1),R.ALU.w.l);
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+}
+static void ltp(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ R.Treg = R.ALU.w.l;
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d = R.ALU.d;
+}
+static void lts(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ R.Treg = R.ALU.w.l;
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+}
+static void mac(void) /** RAM blocks B0,B1,B2 may be important ! */
+{ /** Fix cycle timing **/
+ oldacc.d = R.ACC.d;
+ if (R.init_load_addr) {
+ R.PFC = M_RDOP_ARG(R.PC);
+ R.PC++;
+ }
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+ GETDATA(0,0);
+ R.Treg = R.ALU.w.l;
+ R.Preg.d = ( (INT16)R.ALU.w.l * (INT16)M_RDROM(R.PFC) );
+ R.PFC++;
+ R.tms32025_dec_cycles += (2*CLK);
+}
+static void macd(void) /** RAM blocks B0,B1,B2 may be important ! */
+{ /** Fix cycle timing **/
+ oldacc.d = R.ACC.d;
+ if (R.init_load_addr) {
+ R.PFC = M_RDOP_ARG(R.PC);
+ R.PC++;
+ }
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+ GETDATA(0,0);
+ if ( (R.opcode.b.l & 0x80) || R.init_load_addr ) { /* No writing during repitition, or DMA mode */
+ M_WRTRAM((memaccess+1),R.ALU.w.l);
+ }
+ R.Treg = R.ALU.w.l;
+ R.Preg.d = ( (INT16)R.ALU.w.l * (INT16)M_RDROM(R.PFC) );
+ R.PFC++;
+ R.tms32025_dec_cycles += (2*CLK);
+}
+static void mar(void) /* LARP and NOP are a subset of this instruction */
+{
+ if (R.opcode.b.l & 0x80) MODIFY_AR_ARP();
+}
+static void mpy(void)
+{
+ GETDATA(0,0);
+ R.Preg.d = (INT16)(R.ALU.w.l) * (INT16)(R.Treg);
+}
+static void mpya(void)
+{
+ oldacc.d = R.ACC.d;
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+ GETDATA(0,0);
+ R.Preg.d = (INT16)(R.ALU.w.l) * (INT16)(R.Treg);
+}
+static void mpyk(void)
+{
+ R.Preg.d = (INT16)R.Treg * ((INT16)(R.opcode.w.l << 3) >> 3);
+
+}
+static void mpys(void)
+{
+ oldacc.d = R.ACC.d;
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+ GETDATA(0,0);
+ R.Preg.d = (INT16)(R.ALU.w.l) * (INT16)(R.Treg);
+}
+static void mpyu(void)
+{
+ GETDATA(0,0); R.Preg.d = (UINT16)(R.ALU.w.l) * (UINT16)(R.Treg);
+}
+static void neg(void)
+{
+ if (R.ACC.d == 0x80000000) {
+ SET0(OV_FLAG);
+ if (OVM) R.ACC.d = 0x7fffffff;
+ }
+ else R.ACC.d = -R.ACC.d;
+ if (R.ACC.d) CLR0(C_FLAG);
+ else SET0(C_FLAG);
+}
+/*
+static void nop(void) { } // NOP is a subset of the MAR instruction
+*/
+static void norm(void)
+{
+ UINT32 acc = R.ACC.d;
+
+ if( acc == 0 || ((acc^(acc<<1))&(1<<31))!=0 )
+ {
+ SET1(TC_FLAG); /* 1 -> TC */
+ }
+ else
+ {
+ CLR1(TC_FLAG); /* 0 -> TC */
+ R.ACC.d <<= 1; /* (ACC)*2 -> ACC */
+ MODIFY_AR_ARP();
+ }
+}
+static void or(void)
+{
+ GETDATA(0,0);
+ R.ACC.w.l |= R.ALU.w.l;
+}
+static void ork(void)
+{
+ R.ALU.d = (UINT16)M_RDOP_ARG(R.PC);
+ R.PC++;
+ R.ALU.d <<= (R.opcode.b.h & 0xf);
+ R.ACC.d |= (R.ALU.d & 0x7fffffff);
+}
+static void out(void)
+{
+ GETDATA(0,0);
+ P_OUT( (R.opcode.b.h & 0xf), R.ALU.w.l );
+}
+static void pac(void)
+{
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d = R.ALU.d;
+}
+static void pop(void)
+{
+ R.ACC.d = (UINT16)POP_STACK();
+}
+static void popd(void)
+{
+ R.ALU.d = (UINT16)POP_STACK();
+ PUTDATA(R.ALU.w.l);
+}
+static void pshd(void)
+{
+ GETDATA(0,0);
+ PUSH_STACK(R.ALU.w.l);
+}
+static void push(void)
+{
+ PUSH_STACK(R.ACC.w.l);
+}
+static void rc(void)
+{
+ CLR1(C_FLAG);
+}
+static void ret(void)
+{
+ SET_PC(POP_STACK());
+}
+static void rfsm(void) /** serial port mode */
+{
+ CLR1(FSM_FLAG);
+}
+static void rhm(void)
+{
+ CLR1(HM_FLAG);
+}
+static void rol(void)
+{
+ R.ALU.d = R.ACC.d;
+ R.ACC.d <<= 1;
+ if (CARRY) R.ACC.d |= 1;
+ if (R.ALU.d & 0x80000000) SET1(C_FLAG);
+ else CLR1(C_FLAG);
+}
+static void ror(void)
+{
+ R.ALU.d = R.ACC.d;
+ R.ACC.d >>= 1;
+ if (CARRY) R.ACC.d |= 0x80000000;
+ if (R.ALU.d & 1) SET1(C_FLAG);
+ else CLR1(C_FLAG);
+}
+static void rovm(void)
+{
+ CLR0(OVM_FLAG);
+}
+static void rpt(void)
+{
+ GETDATA(0,0);
+ R.RPTC = R.ALU.b.l;
+ R.init_load_addr = 2; /* Initiate repeat mode */
+}
+static void rptk(void)
+{
+ R.RPTC = R.opcode.b.l;
+ R.init_load_addr = 2; /* Initiate repeat mode */
+}
+static void rsxm(void)
+{
+ CLR1(SXM_FLAG);
+}
+static void rtc(void)
+{
+ CLR1(TC_FLAG);
+}
+static void rtxm(void) /** serial port stuff */
+{
+ CLR1(TXM_FLAG);
+}
+static void rxf(void)
+{
+ CLR1(XF_FLAG);
+ S_OUT(TMS32025_XF,CLEAR_LINE);
+}
+static void sach(void)
+{
+ R.ALU.d = (R.ACC.d << (R.opcode.b.h & 7));
+ PUTDATA(R.ALU.w.h);
+}
+static void sacl(void)
+{
+ R.ALU.d = (R.ACC.d << (R.opcode.b.h & 7));
+ PUTDATA(R.ALU.w.l);
+}
+static void sar_ar0(void) { PUTDATA(R.AR[0]); }
+static void sar_ar1(void) { PUTDATA(R.AR[1]); }
+static void sar_ar2(void) { PUTDATA(R.AR[2]); }
+static void sar_ar3(void) { PUTDATA(R.AR[3]); }
+static void sar_ar4(void) { PUTDATA(R.AR[4]); }
+static void sar_ar5(void) { PUTDATA(R.AR[5]); }
+static void sar_ar6(void) { PUTDATA(R.AR[6]); }
+static void sar_ar7(void) { PUTDATA(R.AR[7]); }
+
+static void sblk(void)
+{
+ oldacc.d = R.ACC.d;
+ if (SXM) R.ALU.d = (INT16)M_RDOP_ARG(R.PC);
+ else R.ALU.d = (UINT16)M_RDOP_ARG(R.PC);
+ R.PC++;
+ R.ALU.d <<= (R.opcode.b.h & 0xf);
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+}
+static void tms_sbrk(void)
+{
+ R.AR[ARP] -= R.opcode.b.l;
+}
+static void sc(void)
+{
+ SET1(C_FLAG);
+}
+static void sfl(void)
+{
+ R.ALU.d = R.ACC.d;
+ R.ACC.d <<= 1;
+ if (R.ALU.d & 0x80000000) SET1(C_FLAG);
+ else CLR1(C_FLAG);
+}
+static void sfr(void)
+{
+ R.ALU.d = R.ACC.d;
+ R.ACC.d >>= 1;
+ if (SXM) {
+ if (R.ALU.d & 0x80000000) R.ACC.d |= 0x80000000;
+ }
+ if (R.ALU.d & 1) SET1(C_FLAG);
+ else CLR1(C_FLAG);
+}
+static void sfsm(void) /** serial port mode */
+{
+ SET1(FSM_FLAG);
+}
+static void shm(void)
+{
+ SET1(HM_FLAG);
+}
+static void sovm(void)
+{
+ SET0(OVM_FLAG);
+}
+static void spac(void)
+{
+ oldacc.d = R.ACC.d;
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+}
+static void sph(void)
+{
+ SHIFT_Preg_TO_ALU();
+ PUTDATA(R.ALU.w.h);
+}
+static void spl(void)
+{
+ SHIFT_Preg_TO_ALU();
+ PUTDATA(R.ALU.w.l);
+}
+static void spm(void)
+{
+ MODIFY_PM( (R.opcode.b.l & 3) );
+}
+static void sqra(void)
+{
+ oldacc.d = R.ACC.d;
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d += R.ALU.d;
+ CALCULATE_ADD_OVERFLOW(R.ALU.d);
+ CALCULATE_ADD_CARRY();
+ GETDATA(0,0);
+ R.Treg = R.ALU.w.l;
+ R.Preg.d = ((INT16)R.ALU.w.l * (INT16)R.ALU.w.l);
+}
+static void sqrs(void)
+{
+ oldacc.d = R.ACC.d;
+ SHIFT_Preg_TO_ALU();
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+ GETDATA(0,0);
+ R.Treg = R.ALU.w.l;
+ R.Preg.d = ((INT16)R.ALU.w.l * (INT16)R.ALU.w.l);
+}
+static void sst(void)
+{
+ PUTDATA_SST(R.STR0);
+}
+static void sst1(void)
+{
+ PUTDATA_SST(R.STR1);
+}
+static void ssxm(void)
+{ /** Check instruction description, and make sure right instructions use SXM */
+ SET1(SXM_FLAG);
+}
+static void stc(void)
+{
+ SET1(TC_FLAG);
+}
+static void stxm(void) /** serial port stuff */
+{
+ SET1(TXM_FLAG);
+}
+static void sub(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA((R.opcode.b.h & 0xf),SXM);
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+}
+static void subb(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ if (CARRY == 0) R.ALU.d--;
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+}
+
+
+static void subc(void)
+{
+ /**
+ * conditional subtraction, which may be used for division
+ * execute 16 times for 16-bit division
+ *
+ * input: 32 bit numerator in accumulator
+ * 16 bit denominator in data memory
+ *
+ * output: remainder in upper 16 bits
+ * quotient in lower 16 bits
+ */
+ GETDATA(15,SXM);
+ if( R.ACC.d >= R.ALU.d )
+ {
+ R.ACC.d = (R.ACC.d - R.ALU.d)*2+1;
+ }
+ else
+ {
+ R.ACC.d = R.ACC.d*2;
+ }
+// Stroff: HACK! support for overflow capping as implemented results in bad DSP floating point math in many
+// System22 games - for example, the score display in Prop Cycle.
+// R.ACC.d = ((INT32)oldacc.d < 0) ? 0x80000000 : 0x7fffffff;
+
+// if ((INT32)((oldacc.d ^ subval ) & (oldacc.d ^ R.ALU.d)) < 0)
+// {
+// SET0(OV_FLAG);
+// }
+// CALCULATE_SUB_CARRY();
+}
+
+static void subh(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ R.ACC.w.h -= R.ALU.w.l;
+ if ((INT16)((oldacc.w.h ^ R.ALU.w.l) & (oldacc.w.h ^ R.ACC.w.h)) < 0) {
+ SET0(OV_FLAG);
+ if (OVM)
+ R.ACC.w.h = ((INT16)oldacc.w.h < 0) ? 0x8000 : 0x7fff;
+ }
+ if ( ((INT16)(oldacc.w.h) >= 0) && ((INT16)(R.ACC.w.h) < 0) ) {
+ CLR1(C_FLAG);
+ }
+ /* Carry flag is not affected, if no borrow occured */
+}
+static void subk(void)
+{
+ oldacc.d = R.ACC.d;
+ R.ALU.d = (UINT8)R.opcode.b.l;
+ R.ACC.d -= R.ALU.b.l;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+}
+static void subs(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA(0,0);
+ R.ACC.d -= R.ALU.w.l;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+}
+static void subt(void)
+{
+ oldacc.d = R.ACC.d;
+ GETDATA((R.Treg & 0xf),SXM);
+ R.ACC.d -= R.ALU.d;
+ CALCULATE_SUB_OVERFLOW(R.ALU.d);
+ CALCULATE_SUB_CARRY();
+}
+static void sxf(void)
+{
+ SET1(XF_FLAG);
+ S_OUT(TMS32025_XF,ASSERT_LINE);
+}
+static void tblr(void)
+{
+ if (R.init_load_addr)
+ {
+ R.PFC = R.ACC.w.l;
+ }
+ R.ALU.w.l = M_RDROM(R.PFC);
+ if ( (CNF0) && ( (UINT16)(R.PFC) >= 0xff00 ) ) {} /** TMS32025 only */
+ else R.tms32025_dec_cycles += (1*CLK);
+ PUTDATA(R.ALU.w.l);
+ R.PFC++;
+}
+static void tblw(void)
+{
+ if (R.init_load_addr)
+ {
+ R.PFC = R.ACC.w.l;
+ }
+ R.tms32025_dec_cycles += (1*CLK);
+ GETDATA(0,0);
+ if (R.external_mem_access) R.tms32025_dec_cycles += (1*CLK);
+ M_WRTROM(R.PFC, R.ALU.w.l);
+ R.PFC++;
+}
+static void trap(void)
+{
+ PUSH_STACK(R.PC);
+ SET_PC(0x001E); /* Trap vector */
+}
+static void xor(void)
+{
+ GETDATA(0,0);
+ R.ACC.w.l ^= R.ALU.w.l;
+}
+static void xork(void)
+{
+ oldacc.d = R.ACC.d;
+ R.ALU.d = M_RDOP_ARG(R.PC);
+ R.PC++;
+ R.ALU.d <<= (R.opcode.b.h & 0xf);
+ R.ACC.d ^= R.ALU.d;
+ R.ACC.d |= (oldacc.d & 0x80000000);
+}
+static void zalh(void)
+{
+ GETDATA(0,0);
+ R.ACC.w.h = R.ALU.w.l;
+ R.ACC.w.l = 0x0000;
+}
+static void zalr(void)
+{
+ GETDATA(0,0);
+ R.ACC.w.h = R.ALU.w.l;
+ R.ACC.w.l = 0x8000;
+}
+static void zals(void)
+{
+ GETDATA(0,0);
+ R.ACC.w.l = R.ALU.w.l;
+ R.ACC.w.h = 0x0000;
+}
+
+
+/***********************************************************************
+ * Cycle Timings
+ ***********************************************************************/
+
+static unsigned cycles_main[256]=
+{
+/*00*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*08*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*10*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*18*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*20*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*28*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*30*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*38*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*40*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*48*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*50*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*58*/ 3*CLK, 2*CLK, 1*CLK, 1*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*60*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*68*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*70*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*78*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*80*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*88*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*90*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*98*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*A0*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*A8*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*B0*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*B8*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*C0*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*C8*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*D0*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 0*CLK,
+/*D8*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*E0*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*E8*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*F0*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
+/*F8*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK
+};
+
+static unsigned cycles_DX_subset[8]=
+{
+/*00*/ 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 0
+};
+
+static unsigned cycles_CE_subset[256]=
+{
+/*00*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*08*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*10*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 0*CLK,
+/*18*/ 1*CLK, 1*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 2*CLK, 3*CLK,
+/*20*/ 1*CLK, 1*CLK, 0*CLK, 1*CLK, 2*CLK, 2*CLK, 2*CLK, 1*CLK,
+/*28*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*30*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*38*/ 1*CLK, 1*CLK, 0*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
+/*40*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*48*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*50*/ 1*CLK, 1*CLK, 1*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*58*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*60*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*68*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*70*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*78*/ 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*80*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*88*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*90*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*98*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*A0*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*A8*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*B0*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*B8*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*C0*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*C8*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*D0*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*D8*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*E0*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*E8*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*F0*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK,
+/*F8*/ 0*CLK, 0*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK
+};
+
+
+/***********************************************************************
+ * Opcode Table
+ ***********************************************************************/
+
+static opcode_fn opcode_main[256]=
+{
+/*00*/ add, add, add, add, add, add, add, add,
+/*08*/ add, add, add, add, add, add, add, add,
+/*10*/ sub, sub, sub, sub, sub, sub, sub, sub,
+/*18*/ sub, sub, sub, sub, sub, sub, sub, sub,
+/*20*/ lac, lac, lac, lac, lac, lac, lac, lac,
+/*28*/ lac, lac, lac, lac, lac, lac, lac, lac,
+/*30*/ lar_ar0, lar_ar1, lar_ar2, lar_ar3, lar_ar4, lar_ar5, lar_ar6, lar_ar7,
+/*38*/ mpy, sqra, mpya, mpys, lt, lta, ltp, ltd,
+/*40*/ zalh, zals, lact, addc, subh, subs, subt, subc,
+/*48*/ addh, adds, addt, rpt, xor, or, and, subb,
+/*50*/ lst, lst1, ldp, lph, pshd, mar, dmov, bitt,
+/*58*/ tblr, tblw, sqrs, lts, macd, mac, bc, bnc,
+/*60*/ sacl, sacl, sacl, sacl, sacl, sacl, sacl, sacl,
+/*68*/ sach, sach, sach, sach, sach, sach, sach, sach,
+/*70*/ sar_ar0, sar_ar1, sar_ar2, sar_ar3, sar_ar4, sar_ar5, sar_ar6, sar_ar7,
+/*78*/ sst, sst1, popd, zalr, spl, sph, adrk, tms_sbrk,
+/*80*/ in, in, in, in, in, in, in, in,
+/*88*/ in, in, in, in, in, in, in, in,
+/*90*/ bit, bit, bit, bit, bit, bit, bit, bit,
+/*98*/ bit, bit, bit, bit, bit, bit, bit, bit,
+/*A0*/ mpyk, mpyk, mpyk, mpyk, mpyk, mpyk, mpyk, mpyk,
+/*A8*/ mpyk, mpyk, mpyk, mpyk, mpyk, mpyk, mpyk, mpyk,
+/*B0*/ mpyk, mpyk, mpyk, mpyk, mpyk, mpyk, mpyk, mpyk,
+/*B8*/ mpyk, mpyk, mpyk, mpyk, mpyk, mpyk, mpyk, mpyk,
+/*C0*/ lark_ar0, lark_ar1, lark_ar2, lark_ar3, lark_ar4, lark_ar5, lark_ar6, lark_ar7,
+/*C8*/ ldpk, ldpk, lack, rptk, addk, subk, opcodes_CE, mpyu,
+/*D0*/ opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX,
+/*D8*/ opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX, opcodes_DX,
+/*E0*/ out, out, out, out, out, out, out, out,
+/*E8*/ out, out, out, out, out, out, out, out,
+/*F0*/ bv, bgz, blez, blz, bgez, bnz, bz, bnv,
+/*F8*/ bbz, bbnz, bioz, banz, blkp, blkd, call, br
+};
+
+static opcode_fn opcode_DX_subset[8]= /* Instructions living under the Dxxx opcode */
+{
+/*00*/ lrlk, lalk, adlk, sblk, andk, ork, xork, illegal
+};
+
+static opcode_fn opcode_CE_subset[256]=
+{
+/*00*/ eint, dint, rovm, sovm, cnfd, cnfp, rsxm, ssxm,
+/*08*/ spm, spm, spm, spm, rxf, sxf, fort, fort,
+/*10*/ illegal, illegal, illegal, illegal, pac, apac, spac, illegal,
+/*18*/ sfl, sfr, illegal, abst, push, pop, trap, idle,
+/*20*/ rtxm, stxm, illegal, neg, cala, bacc, ret, cmpl,
+/*28*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*30*/ rc, sc, rtc, stc, rol, ror, rfsm, sfsm,
+/*38*/ rhm, shm, illegal, illegal, conf, conf, conf, conf,
+/*40*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*48*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*50*/ cmpr, cmpr, cmpr, cmpr, illegal, illegal, illegal, illegal,
+/*58*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*60*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*68*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*70*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*78*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*80*/ illegal, illegal, norm, illegal, illegal, illegal, illegal, illegal,
+/*88*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*90*/ illegal, illegal, norm, illegal, illegal, illegal, illegal, illegal,
+/*98*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*A0*/ illegal, illegal, norm, illegal, illegal, illegal, illegal, illegal,
+/*A8*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*B0*/ illegal, illegal, norm, illegal, illegal, illegal, illegal, illegal,
+/*B8*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*C0*/ illegal, illegal, norm, illegal, illegal, illegal, illegal, illegal,
+/*C8*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*D0*/ illegal, illegal, norm, illegal, illegal, illegal, illegal, illegal,
+/*D8*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*E0*/ illegal, illegal, norm, illegal, illegal, illegal, illegal, illegal,
+/*E8*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+/*F0*/ illegal, illegal, norm, illegal, illegal, illegal, illegal, illegal,
+/*F8*/ illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal
+};
+
+
+
+/****************************************************************************
+ * Inits CPU emulation
+ ****************************************************************************/
+static void tms32025_init (int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ R.intRAM = auto_malloc(0x800*2);
+ R.irq_callback = irqcallback;
+
+ state_save_register_item("tms32025", index, R.PC);
+ state_save_register_item("tms32025", index, R.STR0);
+ state_save_register_item("tms32025", index, R.STR1);
+ state_save_register_item("tms32025", index, R.PFC);
+ state_save_register_item("tms32025", index, R.IFR);
+ state_save_register_item("tms32025", index, R.RPTC);
+ state_save_register_item("tms32025", index, R.ACC.d);
+ state_save_register_item("tms32025", index, R.ALU.d);
+ state_save_register_item("tms32025", index, R.Preg.d);
+ state_save_register_item("tms32025", index, R.Treg);
+ state_save_register_item("tms32025", index, R.AR[0]);
+ state_save_register_item("tms32025", index, R.AR[1]);
+ state_save_register_item("tms32025", index, R.AR[2]);
+ state_save_register_item("tms32025", index, R.AR[3]);
+ state_save_register_item("tms32025", index, R.AR[4]);
+ state_save_register_item("tms32025", index, R.AR[5]);
+ state_save_register_item("tms32025", index, R.AR[6]);
+ state_save_register_item("tms32025", index, R.AR[7]);
+ state_save_register_item("tms32025", index, R.STACK[0]);
+ state_save_register_item("tms32025", index, R.STACK[1]);
+ state_save_register_item("tms32025", index, R.STACK[2]);
+ state_save_register_item("tms32025", index, R.STACK[3]);
+ state_save_register_item("tms32025", index, R.STACK[4]);
+ state_save_register_item("tms32025", index, R.STACK[5]);
+ state_save_register_item("tms32025", index, R.STACK[6]);
+ state_save_register_item("tms32025", index, R.STACK[7]);
+
+ state_save_register_item("tms32025", index, R.idle);
+ state_save_register_item("tms32025", index, R.hold);
+ state_save_register_item("tms32025", index, R.external_mem_access);
+ state_save_register_item("tms32025", index, R.init_load_addr);
+ state_save_register_item("tms32025", index, R.PREVPC);
+}
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+static void tms32025_reset (void)
+{
+ SET_PC(0); /* Starting address on a reset */
+ R.STR0 |= 0x0600; /* INTM and unused bit set to 1 */
+ R.STR0 &= 0xefff; /* OV cleared to 0. Remaining bits undefined */
+ R.STR1 |= 0x07f0; /* SXM, C, HM, FSM, XF and unused bits set to 1 */
+ R.STR1 &= 0xeff0; /* CNF, FO, TXM, PM bits cleared to 0. Remaining bits undefined */
+ R.RPTC = 0; /* Reset repeat counter to 0 */
+ R.IFR = 0; /* IRQ pending flags */
+
+ S_OUT(TMS32025_XF,ASSERT_LINE); /* XF flag is high. Must set the pin */
+
+ /* Set the internal memory mapped registers */
+ GREG = 0;
+ TIM = 0xffff;
+ PRD = 0xffff;
+ IMR = 0xffc0;
+
+ R.idle = 0;
+ R.hold = 0;
+ R.init_load_addr = 1;
+
+ /* Reset the Data/Program address banks */
+ memset(tms32025_pgmmap, 0, sizeof(tms32025_pgmmap));
+ memset(tms32025_datamap, 0, sizeof(tms32025_datamap));
+
+ tms32025_datamap[0] = &R.intRAM[0x000]; /* B2 */
+ tms32025_datamap[4] = &R.intRAM[0x200]; /* B0 */
+ tms32025_datamap[5] = &R.intRAM[0x280]; /* B0 */
+ tms32025_datamap[6] = &R.intRAM[0x300]; /* B1 */
+ tms32025_datamap[7] = &R.intRAM[0x380]; /* B1 */
+}
+
+#if (HAS_TMS32026)
+static void tms32026_reset (void)
+{
+ tms32025_reset();
+
+ /* Reset the Data/Program address banks */
+ memset(tms32025_pgmmap, 0, sizeof(tms32025_pgmmap));
+ memset(tms32025_datamap, 0, sizeof(tms32025_datamap));
+
+ tms32025_datamap[0] = &R.intRAM[0x000]; /* B2 */
+ tms32025_datamap[4] = &R.intRAM[0x200]; /* B0 */
+ tms32025_datamap[5] = &R.intRAM[0x280]; /* B0 */
+ tms32025_datamap[6] = &R.intRAM[0x300]; /* B0 */
+ tms32025_datamap[7] = &R.intRAM[0x380]; /* B0 */
+ tms32025_datamap[8] = &R.intRAM[0x400]; /* B1 */
+ tms32025_datamap[9] = &R.intRAM[0x480]; /* B1 */
+ tms32025_datamap[10] = &R.intRAM[0x500]; /* B1 */
+ tms32025_datamap[11] = &R.intRAM[0x580]; /* B1 */
+ tms32025_datamap[12] = &R.intRAM[0x600]; /* B3 */
+ tms32025_datamap[13] = &R.intRAM[0x680]; /* B3 */
+ tms32025_datamap[14] = &R.intRAM[0x700]; /* B3 */
+ tms32025_datamap[15] = &R.intRAM[0x780]; /* B3 */
+}
+#endif
+
+
+/****************************************************************************
+ * Shut down CPU emulation
+ ****************************************************************************/
+static void tms32025_exit (void)
+{
+}
+
+
+/****************************************************************************
+ * Issue an interrupt if necessary
+ ****************************************************************************/
+static int process_IRQs(void)
+{
+ /********** Interrupt Flag Register (IFR) **********
+ | 5 | 4 | 3 | 2 | 1 | 0 |
+ | XINT| RINT| TINT| INT2| INT1| INT0|
+ */
+ R.tms32025_irq_cycles = 0;
+
+ /* Dont service Interrupts if masked, or prev instruction was EINT ! */
+
+ if ( (INTM == 0) && (R.opcode.w.l != 0xce00) && (R.IFR & IMR) )
+ {
+ R.tms32025_irq_cycles = (3*CLK); /* 3 clock cycles used due to PUSH and DINT operation ? */
+ PUSH_STACK(R.PC);
+
+ if ((R.IFR & 0x01) && (IMR & 0x01)) { /* IRQ line 0 */
+ //logerror("TMS32025: Active INT0\n");
+ SET_PC(0x0002);
+ (*R.irq_callback)(0);
+ R.idle = 0;
+ R.IFR &= (~0x01);
+ SET0(INTM_FLAG);
+ return R.tms32025_irq_cycles;
+ }
+ if ((R.IFR & 0x02) && (IMR & 0x02)) { /* IRQ line 1 */
+ //logerror("TMS32025: Active INT1\n");
+ SET_PC(0x0004);
+ (*R.irq_callback)(1);
+ R.idle = 0;
+ R.IFR &= (~0x02);
+ SET0(INTM_FLAG);
+ return R.tms32025_irq_cycles;
+ }
+ if ((R.IFR & 0x04) && (IMR & 0x04)) { /* IRQ line 2 */
+ //logerror("TMS32025: Active INT2\n");
+ SET_PC(0x0006);
+ (*R.irq_callback)(2);
+ R.idle = 0;
+ R.IFR &= (~0x04);
+ SET0(INTM_FLAG);
+ return R.tms32025_irq_cycles;
+ }
+ if ((R.IFR & 0x08) && (IMR & 0x08)) { /* Timer IRQ (internal) */
+// logerror("TMS32025: Active TINT (Timer)\n");
+ SET_PC(0x0018);
+ R.idle = 0;
+ R.IFR &= (~0x08);
+ SET0(INTM_FLAG);
+ return R.tms32025_irq_cycles;
+ }
+ if ((R.IFR & 0x10) && (IMR & 0x10)) { /* Serial port receive IRQ (internal) */
+// logerror("TMS32025: Active RINT (Serial recieve)\n");
+ DRR = S_IN(TMS32025_DR);
+ SET_PC(0x001A);
+ R.idle = 0;
+ R.IFR &= (~0x10);
+ SET0(INTM_FLAG);
+ return R.tms32025_irq_cycles;
+ }
+ if ((R.IFR & 0x20) && (IMR & 0x20)) { /* Serial port transmit IRQ (internal) */
+// logerror("TMS32025: Active XINT (Serial transmit)\n");
+ S_OUT(TMS32025_DX,DXR);
+ SET_PC(0x001C);
+ R.idle = 0;
+ R.IFR &= (~0x20);
+ SET0(INTM_FLAG);
+ return R.tms32025_irq_cycles;
+ }
+ }
+ return R.tms32025_irq_cycles;
+}
+
+INLINE void process_timer(int clocks)
+{
+ int preclocks, ticks;
+
+ /* easy case: no actual ticks */
+again:
+ preclocks = CLK - R.timerover;
+ if (clocks < preclocks)
+ {
+ R.timerover += clocks;
+ tms32025_icount -= clocks;
+ return;
+ }
+
+ /* if we're not going to overflow the timer, just count the clocks */
+ ticks = 1 + (clocks - preclocks) / CLK;
+ if (ticks <= TIM)
+ {
+ tms32025_icount -= clocks;
+ R.timerover = clocks - (ticks - 1) * CLK - preclocks;
+ TIM -= ticks;
+ }
+
+ /* otherwise, overflow the timer and signal an interrupt */
+ else
+ {
+ tms32025_icount -= preclocks + CLK * TIM;
+ R.timerover = 0;
+ TIM = PRD;
+
+ R.IFR |= 0x08;
+ clocks = process_IRQs(); /* Handle Timer IRQ */
+ goto again;
+ }
+}
+
+
+/****************************************************************************
+ * Execute ICount cycles. Exit when 0 or less
+ ****************************************************************************/
+static int tms32025_execute(int cycles)
+{
+ tms32025_icount = cycles;
+
+
+ /**** Respond to external hold signal */
+ if (S_IN(TMS32025_HOLD) == ASSERT_LINE) {
+ if (R.hold == 0) {
+ S_OUT(TMS32025_HOLDA,ASSERT_LINE); /* Hold-Ack (active low) */
+ }
+ R.hold = 1;
+ if (HM) {
+ tms32025_icount = 0; /* Exit */
+ }
+ else {
+ if (R.external_mem_access) {
+ tms32025_icount = 0; /* Exit */
+ }
+ }
+ }
+ else {
+ if (R.hold == 1) {
+ S_OUT(TMS32025_HOLDA,CLEAR_LINE); /* Hold-Ack (active low) */
+ process_timer(3);
+ }
+ R.hold = 0;
+ }
+
+ /**** If idling, update timer and/or exit execution */
+ while (R.idle && tms32025_icount > 0)
+ process_timer(tms32025_icount);
+
+ if (tms32025_icount <= 0) CALL_MAME_DEBUG;
+
+
+ while (tms32025_icount > 0)
+ {
+ R.tms32025_dec_cycles = (1*CLK);
+
+ if (R.IFR) { /* Check IRQ Flag Register for pending IRQs */
+ R.tms32025_dec_cycles += process_IRQs();
+ }
+
+ R.PREVPC = R.PC;
+
+ CALL_MAME_DEBUG;
+
+ R.opcode.d = M_RDOP(R.PC);
+ R.PC++;
+
+ if (R.opcode.b.h == 0xCE) /* Opcode 0xCExx has many opcodes in its minor byte */
+ {
+ R.tms32025_dec_cycles = cycles_CE_subset[R.opcode.b.l];
+ (*(opcode_CE_subset[R.opcode.b.l]))();
+ }
+ else if ((R.opcode.w.l & 0xf0f8) == 0xd000) /* Opcode 0xDxxx has many opcodes in its minor byte */
+ {
+ R.tms32025_dec_cycles = cycles_DX_subset[R.opcode.b.l];
+ (*(opcode_DX_subset[R.opcode.b.l]))();
+ }
+ else /* Do all opcodes except the CExx and Dxxx ones */
+ {
+ R.tms32025_dec_cycles = cycles_main[R.opcode.b.h];
+ (*(opcode_main[R.opcode.b.h]))();
+ }
+
+
+ if (R.init_load_addr == 2) { /* Repeat next instruction */
+ R.PREVPC = R.PC;
+
+ CALL_MAME_DEBUG;
+
+ R.opcode.d = M_RDOP(R.PC);
+ R.PC++;
+ R.tms32025_dec_cycles += (1*CLK);
+
+ do {
+ if (R.opcode.b.h == 0xCE)
+ { /* Do all 0xCExx Opcodes */
+ if (R.init_load_addr) {
+ R.tms32025_dec_cycles += (1*CLK);
+ }
+ else {
+ R.tms32025_dec_cycles += (1*CLK);
+ }
+ (*(opcode_CE_subset[R.opcode.b.l]))();
+ }
+ if ((R.opcode.w.l & 0xf0f8) == 0xd000)
+ { /* Do all valid 0xDxxx Opcodes */
+ if (R.init_load_addr) {
+ R.tms32025_dec_cycles += (1*CLK);
+ }
+ else {
+ R.tms32025_dec_cycles += (1*CLK);
+ }
+ (*(opcode_DX_subset[R.opcode.b.l]))();
+ }
+ else
+ { /* Do all other opcodes */
+ if (R.init_load_addr) {
+ R.tms32025_dec_cycles += (1*CLK);
+ }
+ else {
+ R.tms32025_dec_cycles += (1*CLK);
+ }
+ (*(opcode_main[R.opcode.b.h]))();
+ }
+ R.init_load_addr = 0;
+ R.RPTC-- ;
+ } while ((INT8)(R.RPTC) != -1);
+ R.RPTC = 0;
+ R.PFC = R.PC;
+ R.init_load_addr = 1;
+ }
+
+ process_timer(R.tms32025_dec_cycles);
+
+ /**** If device is put into idle mode, exit and wait for an interrupt */
+ while (R.idle && tms32025_icount > 0)
+ process_timer(tms32025_icount);
+
+
+ /**** If hold pin is active, exit if accessing external memory or if HM is set */
+ if (R.hold) {
+ if (R.external_mem_access || (HM)) {
+ if (tms32025_icount > 0) {
+ tms32025_icount = 0;
+ }
+ }
+ }
+ }
+
+ return (cycles - tms32025_icount);
+}
+
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void tms32025_get_context (void *dst)
+{
+ if (dst)
+ {
+ memcpy(&R.datamap_save, &tms32025_datamap[0], sizeof(R.datamap_save));
+ memcpy(&R.pgmmap_save, &tms32025_pgmmap[500], sizeof(R.pgmmap_save));
+ *(tms32025_Regs*)dst = R;
+ }
+}
+
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void tms32025_set_context (void *src)
+{
+ if (src)
+ {
+ R = *(tms32025_Regs*)src;
+ memcpy(&tms32025_datamap[0], &R.datamap_save, sizeof(R.datamap_save));
+ memcpy(&tms32025_pgmmap[500], &R.pgmmap_save, sizeof(R.pgmmap_save));
+ }
+}
+
+
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+static void set_irq_line(int irqline, int state)
+{
+ /* Pending IRQs cannot be cleared */
+
+ if (state != CLEAR_LINE)
+ {
+ R.IFR |= (1 << irqline);
+// R.IFR &= 0x07;
+ }
+}
+
+
+/****************************************************************************
+ * Opcode fetcher
+ ****************************************************************************/
+static int tms32025_readop(UINT32 offset, int size, UINT64 *value)
+{
+ void *ptr;
+
+ /* skip if not custom */
+ if (!tms32025_pgmmap[offset >> 8])
+ return 0;
+
+ ptr = &((UINT8 *)&tms32025_pgmmap[offset >> 8])[offset & 0xff];
+ switch (size)
+ {
+ case 1: *value = *((UINT8 *) ptr);
+ case 2: *value = *((UINT16 *) ptr);
+ case 4: *value = *((UINT32 *) ptr);
+ case 8: *value = *((UINT64 *) ptr);
+ }
+ return 1;
+}
+
+
+/****************************************************************************
+ * Memory reader
+ ****************************************************************************/
+static int tms32025_read(int space, UINT32 offset, int size, UINT64 *value)
+{
+ void *ptr = NULL;
+ UINT64 temp = 0;
+
+ switch (space)
+ {
+ case ADDRESS_SPACE_PROGRAM:
+ ptr = tms32025_pgmmap[offset >> 8];
+ if (!ptr)
+ return 0;
+ break;
+
+ case ADDRESS_SPACE_DATA:
+ ptr = tms32025_datamap[offset >> 8];
+ if (!ptr)
+ return 0;
+ break;
+
+ case ADDRESS_SPACE_IO:
+ return 0;
+ }
+
+ switch (size)
+ {
+ case 1:
+ *value = ((UINT8 *)ptr)[BYTE_XOR_BE(offset & 0xff)];
+ break;
+ case 2:
+ *value = ((UINT16 *)ptr)[(offset & 0xff) / 2];
+ break;
+ case 4:
+ tms32025_read(space, offset + 0, 2, &temp);
+ *value = temp << 16;
+ tms32025_read(space, offset + 2, 2, &temp);
+ *value |= temp & 0xffff;
+ break;
+ case 8:
+ tms32025_read(space, offset + 0, 4, &temp);
+ *value = temp << 32;
+ tms32025_read(space, offset + 4, 4, &temp);
+ *value |= temp & 0xffffffff;
+ break;
+ }
+ return 1;
+}
+
+
+/****************************************************************************
+ * Memory writer
+ ****************************************************************************/
+static int tms32025_write(int space, UINT32 offset, int size, UINT64 value)
+{
+ void *ptr = NULL;
+
+ switch (space)
+ {
+ case ADDRESS_SPACE_PROGRAM:
+ ptr = tms32025_pgmmap[offset >> 8];
+ if (!ptr)
+ return 0;
+ break;
+
+ case ADDRESS_SPACE_DATA:
+ ptr = tms32025_datamap[offset >> 8];
+ if (!ptr)
+ return 0;
+ break;
+
+ case ADDRESS_SPACE_IO:
+ return 0;
+ }
+
+ switch (size)
+ {
+ case 1:
+ ((UINT8 *)ptr)[BYTE_XOR_BE(offset & 0xff)] = value;
+ break;
+ case 2:
+ ((UINT16 *)ptr)[(offset & 0xff) / 2] = value;
+ break;
+ case 4:
+ tms32025_write(space, offset + 0, 2, value >> 16);
+ tms32025_write(space, offset + 2, 2, value);
+ break;
+ case 8:
+ tms32025_write(space, offset + 0, 4, value >> 32);
+ tms32025_write(space, offset + 4, 4, value);
+ break;
+ }
+ return 1;
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void tms32025_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + TMS32025_INT0: set_irq_line(TMS32025_INT0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_INT1: set_irq_line(TMS32025_INT1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_INT2: set_irq_line(TMS32025_INT2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_TINT: set_irq_line(TMS32025_TINT, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_RINT: set_irq_line(TMS32025_RINT, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_XINT: set_irq_line(TMS32025_XINT, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS32025_PC: R.PC = info->i; break;
+ /* This is actually not a stack pointer, but the stack contents */
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS32025_STK7: R.STACK[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK6: R.STACK[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK5: R.STACK[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK4: R.STACK[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK3: R.STACK[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK2: R.STACK[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK1: R.STACK[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK0: R.STACK[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STR0: R.STR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STR1: R.STR1 = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_IFR: R.IFR = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_RPTC: R.RPTC = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_ACC: R.ACC.d = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_PREG: R.Preg.d = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_TREG: R.Treg = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR0: R.AR[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR1: R.AR[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR2: R.AR[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR3: R.AR[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR4: R.AR[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR5: R.AR[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR6: R.AR[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR7: R.AR[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32025_DRR: M_WRTRAM(0,info->i); break;
+ case CPUINFO_INT_REGISTER + TMS32025_DXR: M_WRTRAM(1,info->i); break;
+ case CPUINFO_INT_REGISTER + TMS32025_TIM: M_WRTRAM(2,info->i); break;
+ case CPUINFO_INT_REGISTER + TMS32025_PRD: M_WRTRAM(3,info->i); break;
+ case CPUINFO_INT_REGISTER + TMS32025_IMR: M_WRTRAM(4,info->i); break;
+ case CPUINFO_INT_REGISTER + TMS32025_GREG: M_WRTRAM(5,info->i); break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void tms32025_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(R); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 6; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1*CLK; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 5*CLK; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 17; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = -1; break;
+
+ case CPUINFO_INT_INPUT_STATE + TMS32025_INT0: info->i = (R.IFR & 0x01) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_INT1: info->i = (R.IFR & 0x02) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_INT2: info->i = (R.IFR & 0x04) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_TINT: info->i = (R.IFR & 0x08) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_RINT: info->i = (R.IFR & 0x10) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32025_XINT: info->i = (R.IFR & 0x20) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = R.PREVPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS32025_PC: info->i = R.PC; break;
+ /* This is actually not a stack pointer, but the stack contents */
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS32025_STK7: info->i = R.STACK[7]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK6: info->i = R.STACK[6]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK5: info->i = R.STACK[5]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK4: info->i = R.STACK[4]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK3: info->i = R.STACK[3]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK2: info->i = R.STACK[2]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK1: info->i = R.STACK[1]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STK0: info->i = R.STACK[0]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STR0: info->i = R.STR0; break;
+ case CPUINFO_INT_REGISTER + TMS32025_STR1: info->i = R.STR1; break;
+ case CPUINFO_INT_REGISTER + TMS32025_IFR: info->i = R.IFR; break;
+ case CPUINFO_INT_REGISTER + TMS32025_RPTC: info->i = R.RPTC; break;
+ case CPUINFO_INT_REGISTER + TMS32025_ACC: info->i = R.ACC.d; break;
+ case CPUINFO_INT_REGISTER + TMS32025_PREG: info->i = R.Preg.d; break;
+ case CPUINFO_INT_REGISTER + TMS32025_TREG: info->i = R.Treg; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR0: info->i = R.AR[0]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR1: info->i = R.AR[1]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR2: info->i = R.AR[2]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR3: info->i = R.AR[3]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR4: info->i = R.AR[4]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR5: info->i = R.AR[5]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR6: info->i = R.AR[6]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_AR7: info->i = R.AR[7]; break;
+ case CPUINFO_INT_REGISTER + TMS32025_DRR: info->i = M_RDRAM(0); break;
+ case CPUINFO_INT_REGISTER + TMS32025_DXR: info->i = M_RDRAM(1); break;
+ case CPUINFO_INT_REGISTER + TMS32025_TIM: info->i = M_RDRAM(2); break;
+ case CPUINFO_INT_REGISTER + TMS32025_PRD: info->i = M_RDRAM(3); break;
+ case CPUINFO_INT_REGISTER + TMS32025_IMR: info->i = M_RDRAM(4); break;
+ case CPUINFO_INT_REGISTER + TMS32025_GREG: info->i = M_RDRAM(5); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = tms32025_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tms32025_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tms32025_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = tms32025_init; break;
+ case CPUINFO_PTR_RESET: info->reset = tms32025_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = tms32025_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = tms32025_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tms32025_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_READ: info->read = tms32025_read; break;
+ case CPUINFO_PTR_WRITE: info->write = tms32025_write; break;
+ case CPUINFO_PTR_READOP: info->readop = tms32025_readop; break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &tms32025_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "TMS32025"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Texas Instruments TMS320x25"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.10"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2001 by Tony La Porta"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "arp%d%c%c%c%cdp%03x arb%d%c%c%c%c%c%c%c%c%c%c%cpm%d",
+ (R.STR0 & 0xe000) >> 13,
+ R.STR0 & 0x1000 ? 'O':'.',
+ R.STR0 & 0x0800 ? 'M':'.',
+ R.STR0 & 0x0400 ? '.':'?',
+ R.STR0 & 0x0200 ? 'I':'.',
+ (R.STR0 & 0x01ff),
+
+ (R.STR1 & 0xe000) >> 13,
+ R.STR1 & 0x1000 ? 'P':'D',
+ R.STR1 & 0x0800 ? 'T':'.',
+ R.STR1 & 0x0400 ? 'S':'.',
+ R.STR1 & 0x0200 ? 'C':'?',
+ R.STR0 & 0x0100 ? '.':'?',
+ R.STR1 & 0x0080 ? '.':'?',
+ R.STR1 & 0x0040 ? 'H':'.',
+ R.STR1 & 0x0020 ? 'F':'.',
+ R.STR1 & 0x0010 ? 'X':'.',
+ R.STR1 & 0x0008 ? 'f':'.',
+ R.STR1 & 0x0004 ? 'o':'i',
+ (R.STR1 & 0x0003) );
+ break;
+
+ case CPUINFO_STR_REGISTER + TMS32025_PC: sprintf(info->s, "PC:%04X", R.PC); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STR0: sprintf(info->s, "STR0:%04X", R.STR0); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STR1: sprintf(info->s, "STR1:%04X", R.STR1); break;
+ case CPUINFO_STR_REGISTER + TMS32025_IFR: sprintf(info->s, "IFR:%04X", R.IFR); break;
+ case CPUINFO_STR_REGISTER + TMS32025_RPTC: sprintf(info->s, "RPTC:%02X", R.RPTC); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STK7: sprintf(info->s, "STK7:%04X", R.STACK[7]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STK6: sprintf(info->s, "STK6:%04X", R.STACK[6]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STK5: sprintf(info->s, "STK5:%04X", R.STACK[5]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STK4: sprintf(info->s, "STK4:%04X", R.STACK[4]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STK3: sprintf(info->s, "STK3:%04X", R.STACK[3]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STK2: sprintf(info->s, "STK2:%04X", R.STACK[2]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STK1: sprintf(info->s, "STK1:%04X", R.STACK[1]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_STK0: sprintf(info->s, "STK0:%04X", R.STACK[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_ACC: sprintf(info->s, "ACC:%08X", R.ACC.d); break;
+ case CPUINFO_STR_REGISTER + TMS32025_PREG: sprintf(info->s, "P:%08X", R.Preg.d); break;
+ case CPUINFO_STR_REGISTER + TMS32025_TREG: sprintf(info->s, "T:%04X", R.Treg); break;
+ case CPUINFO_STR_REGISTER + TMS32025_AR0: sprintf(info->s, "AR0:%04X", R.AR[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_AR1: sprintf(info->s, "AR1:%04X", R.AR[1]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_AR2: sprintf(info->s, "AR2:%04X", R.AR[2]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_AR3: sprintf(info->s, "AR3:%04X", R.AR[3]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_AR4: sprintf(info->s, "AR4:%04X", R.AR[4]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_AR5: sprintf(info->s, "AR5:%04X", R.AR[5]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_AR6: sprintf(info->s, "AR6:%04X", R.AR[6]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_AR7: sprintf(info->s, "AR7:%04X", R.AR[7]); break;
+ case CPUINFO_STR_REGISTER + TMS32025_DRR: sprintf(info->s, "DRR:%04X", M_RDRAM(0)); break;
+ case CPUINFO_STR_REGISTER + TMS32025_DXR: sprintf(info->s, "DXR:%04X", M_RDRAM(1)); break;
+ case CPUINFO_STR_REGISTER + TMS32025_TIM: sprintf(info->s, "TIM:%04X", M_RDRAM(2)); break;
+ case CPUINFO_STR_REGISTER + TMS32025_PRD: sprintf(info->s, "PRD:%04X", M_RDRAM(3)); break;
+ case CPUINFO_STR_REGISTER + TMS32025_IMR: sprintf(info->s, "IMR:%04X", M_RDRAM(4)); break;
+ case CPUINFO_STR_REGISTER + TMS32025_GREG: sprintf(info->s, "GREG:%04X", M_RDRAM(5)); break;
+ }
+}
+
+
+#if (HAS_TMS32026)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void tms32026_get_info(UINT32 _state, cpuinfo *info)
+{
+ switch (_state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_RESET: info->reset = tms32026_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "TMS32026"); break;
+
+ default: tms32025_get_info(_state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/tms32025/tms32025.h b/src/emu/cpu/tms32025/tms32025.h
new file mode 100644
index 00000000000..35b5a16b349
--- /dev/null
+++ b/src/emu/cpu/tms32025/tms32025.h
@@ -0,0 +1,78 @@
+ /**************************************************************************\
+ * Texas Instruments TMS320x25 DSP Emulator *
+ * *
+ * Copyright (C) 2001-2002+ Tony La Porta *
+ * Written for the MAME project. *
+ * *
+ * Note : This is a word based microcontroller, with addressing *
+ * architecture based on the Harvard addressing scheme. *
+ * *
+ * Three versions of the chip are available, and they are: *
+ * TMS320C25 Internal ROM one time programmed at TI *
+ * TMS320E25 Internal ROM programmable as a normal EPROM *
+ * TMS320P25 Internal ROM programmable once as a normal EPROM only *
+ * These devices can also be used as a MicroController with external ROM *
+ * *
+ \***************************************************************************/
+
+#ifndef _TMS32025_H
+#define _TMS32025_H
+
+
+#include "cpuintrf.h"
+
+
+
+#define TMS32025_BIO 0x10000 /* BIO input */
+#define TMS32025_HOLD 0x10001 /* HOLD input */
+#define TMS32025_HOLDA 0x10001 /* HOLD Acknowledge output */
+#define TMS32025_XF 0x10002 /* XF output */
+#define TMS32025_DR 0x10003 /* Serial Data Receive input */
+#define TMS32025_DX 0x10003 /* Serial Data Transmit output */
+#define TMS32025_CLKR 0x10004 /* Serial Clock Receive input */
+#define TMS32025_CLKX 0x10004 /* Serial Clock Transmit output */
+#define TMS32025_FSR 0x10005 /* Serial Frame Receive pulse input */
+#define TMS32025_FSX 0x10005 /* Serial Frame Transmit pulse output */
+
+
+
+/****************************************************************************
+ * Interrupt constants
+ */
+
+#define TMS32025_INT0 0 /* External INT0 */
+#define TMS32025_INT1 1 /* External INT1 */
+#define TMS32025_INT2 2 /* External INT2 */
+#define TMS32025_TINT 3 /* Internal Timer interrupt */
+#define TMS32025_RINT 4 /* Serial Port receive interrupt */
+#define TMS32025_XINT 5 /* Serial Port transmit interrupt */
+#define TMS32025_TRAP 6 /* Trap instruction */
+#define TMS32025_INT_NONE -1
+
+
+enum {
+ TMS32025_PC=1,
+ TMS32025_PFC, TMS32025_STR0, TMS32025_STR1, TMS32025_IFR,
+ TMS32025_RPTC, TMS32025_ACC, TMS32025_PREG, TMS32025_TREG,
+ TMS32025_AR0, TMS32025_AR1, TMS32025_AR2, TMS32025_AR3,
+ TMS32025_AR4, TMS32025_AR5, TMS32025_AR6, TMS32025_AR7,
+ TMS32025_STK0, TMS32025_STK1, TMS32025_STK2, TMS32025_STK3,
+ TMS32025_STK4, TMS32025_STK5, TMS32025_STK6, TMS32025_STK7,
+ TMS32025_DRR, TMS32025_DXR, TMS32025_TIM, TMS32025_PRD,
+ TMS32025_IMR, TMS32025_GREG
+};
+
+
+/****************************************************************************
+ * Public Functions
+ */
+
+extern void tms32025_get_info(UINT32 state, cpuinfo *info);
+extern void tms32026_get_info(UINT32 state, cpuinfo *info);
+
+
+#ifdef MAME_DEBUG
+offs_t tms32025_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _TMS32025_H */
diff --git a/src/emu/cpu/tms32031/32031ops.c b/src/emu/cpu/tms32031/32031ops.c
new file mode 100644
index 00000000000..94d2b608a75
--- /dev/null
+++ b/src/emu/cpu/tms32031/32031ops.c
@@ -0,0 +1,6627 @@
+/***************************************************************************
+
+ 32031ops.c
+ Core implementation for the portable TMS32C031 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+
+/***************************************************************************
+ COMPILE-TIME OPTIONS
+***************************************************************************/
+
+#define USE_FP 0
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define IREG(rnum) (tms32031.r[rnum].i32[0])
+#define FREGEXP(rnum) (EXPONENT(&tms32031.r[rnum]))
+#define FREGMAN(rnum) (MANTISSA(&tms32031.r[rnum]))
+
+#define FP2LONG(rnum) ((FREGEXP(rnum) << 24) | ((UINT32)FREGMAN(rnum) >> 8))
+#define LONG2FP(rnum,v) do { SET_MANTISSA(&tms32031.r[rnum], (v) << 8); SET_EXPONENT(&tms32031.r[rnum], (INT32)(v) >> 24); } while (0)
+#define SHORT2FP(rnum,v) do { \
+ if ((UINT16)(v) == 0x8000) { SET_MANTISSA(&tms32031.r[rnum], 0); SET_EXPONENT(&tms32031.r[rnum], -128); } \
+ else { SET_MANTISSA(&tms32031.r[rnum], (v) << 20); SET_EXPONENT(&tms32031.r[rnum], (INT16)(v) >> 12); } \
+ } while (0)
+
+#define DIRECT() (((IREG(TMR_DP) & 0xff) << 16) | ((UINT16)OP))
+#define INDIRECT_D(o) ((*indirect_d[((o) >> 3) & 31])(o))
+#define INDIRECT_1(o) ((*indirect_1[((o) >> 3) & 31])(o))
+#define INDIRECT_1_DEF(o) ((*indirect_1_def[((o) >> 3) & 31])(o))
+
+#define SIGN(val) ((val) & 0x80000000)
+
+#define OVERFLOW_SUB(a,b,r) ((INT32)(((a) ^ (b)) & ((a) ^ (r))) < 0)
+#define OVERFLOW_ADD(a,b,r) ((INT32)(~((a) ^ (b)) & ((a) ^ (r))) < 0)
+
+#define CLR_FLAGS(f) do { IREG(TMR_ST) &= ~(f); } while (0)
+#define CLR_NVUF() CLR_FLAGS(NFLAG | VFLAG | UFFLAG)
+#define CLR_NZVUF() CLR_FLAGS(NFLAG | ZFLAG | VFLAG | UFFLAG)
+#define CLR_NZCVUF() CLR_FLAGS(NFLAG | ZFLAG | VFLAG | CFLAG | UFFLAG)
+
+#define OR_C(flag) do { IREG(TMR_ST) |= flag & CFLAG; } while (0)
+#define OR_NZ(val) do { IREG(TMR_ST) |= (((val) >> 28) & NFLAG) | (((val) == 0) << 2); } while (0)
+#define OR_NZF(reg) do { IREG(TMR_ST) |= ((MANTISSA(reg) >> 28) & NFLAG) | ((EXPONENT(reg) == -128) << 2); } while (0)
+#define OR_NUF(reg) do { int temp = (EXPONENT(reg) == -128) << 4; IREG(TMR_ST) |= ((MANTISSA(reg) >> 28) & NFLAG) | (temp) | (temp << 2); } while (0)
+#define OR_V_SUB(a,b,r) do { UINT32 temp = ((((a) ^ (b)) & ((a) ^ (r))) >> 30) & VFLAG; IREG(TMR_ST) |= temp | (temp << 4); } while (0)
+#define OR_V_ADD(a,b,r) do { UINT32 temp = ((~((a) ^ (b)) & ((a) ^ (r))) >> 30) & VFLAG; IREG(TMR_ST) |= temp | (temp << 4); } while (0)
+#define OR_C_SUB(a,b,r) do { IREG(TMR_ST) |= ((UINT32)(b) > (UINT32)(a)); } while (0)
+#define OR_C_ADD(a,b,r) do { IREG(TMR_ST) |= ((UINT32)(~(a)) < (UINT32)(b)); } while (0)
+#define OR_NZCV_SUB(a,b,r) do { OR_V_SUB(a,b,r); OR_C_SUB(a,b,r); OR_NZ(r); } while (0)
+#define OR_NZCV_ADD(a,b,r) do { OR_V_ADD(a,b,r); OR_C_ADD(a,b,r); OR_NZ(r); } while (0)
+
+#define OVM (IREG(TMR_ST) & OVMFLAG)
+
+#define UPDATE_DEF() if (defptr) { *defptr = defval; defptr = NULL; }
+
+
+
+/***************************************************************************
+ FORWARD DECLARATIONS
+***************************************************************************/
+
+void (*tms32031ops[])(void);
+
+
+
+/***************************************************************************
+ LOCAL VARIABLES
+***************************************************************************/
+
+static UINT32 *defptr;
+static UINT32 defval;
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static void illegal(void)
+{
+#ifdef MAME_DEBUG
+ logerror("Illegal op @ %06X: %08X (tbl=%03X)\n", tms32031.pc - 1, OP, OP >> 21);
+ DEBUGGER_BREAK;
+#endif
+}
+
+
+static void unimplemented(void)
+{
+ fatalerror("Unimplemented op @ %06X: %08X (tbl=%03X)", tms32031.pc - 1, OP, OP >> 21);
+}
+
+
+INLINE void execute_one(void)
+{
+ CALL_MAME_DEBUG;
+ OP = ROPCODE(tms32031.pc);
+ tms32031_icount -= 2; /* 2 clocks per cycle */
+ tms32031.pc++;
+#if (LOG_OPCODE_USAGE)
+ hits[OP >> 21]++;
+#endif
+ (*tms32031ops[OP >> 21])();
+}
+
+
+static void update_special(int dreg)
+{
+ if (dreg == TMR_BK)
+ {
+ UINT32 temp = IREG(TMR_BK);
+ tms32031.bkmask = temp;
+ while (temp >>= 1)
+ tms32031.bkmask |= temp;
+ }
+ else if (dreg == TMR_IOF)
+ {
+ if (tms32031.xf0_w && IREG(TMR_IOF) & 0x002)
+ (*tms32031.xf0_w)((IREG(TMR_IOF) >> 2) & 1);
+ if (tms32031.xf1_w && IREG(TMR_IOF) & 0x020)
+ (*tms32031.xf1_w)((IREG(TMR_IOF) >> 6) & 1);
+ }
+ else if (dreg == TMR_ST || dreg == TMR_IF || dreg == TMR_IE)
+ check_irqs();
+}
+
+
+
+/***************************************************************************
+ CONDITION CODES
+***************************************************************************/
+
+#define CONDITION_LO (IREG(TMR_ST) & CFLAG)
+#define CONDITION_LS (IREG(TMR_ST) & (CFLAG | ZFLAG))
+#define CONDITION_HI (!(IREG(TMR_ST) & (CFLAG | ZFLAG)))
+#define CONDITION_HS (!(IREG(TMR_ST) & CFLAG))
+#define CONDITION_EQ (IREG(TMR_ST) & ZFLAG)
+#define CONDITION_NE (!(IREG(TMR_ST) & ZFLAG))
+#define CONDITION_LT (IREG(TMR_ST) & NFLAG)
+#define CONDITION_LE (IREG(TMR_ST) & (NFLAG | ZFLAG))
+#define CONDITION_GT (!(IREG(TMR_ST) & (NFLAG | ZFLAG)))
+#define CONDITION_GE (!(IREG(TMR_ST) & NFLAG))
+#define CONDITION_NV (!(IREG(TMR_ST) & VFLAG))
+#define CONDITION_V (IREG(TMR_ST) & VFLAG)
+#define CONDITION_NUF (!(IREG(TMR_ST) & UFFLAG))
+#define CONDITION_UF (IREG(TMR_ST) & UFFLAG)
+#define CONDITION_NLV (!(IREG(TMR_ST) & LVFLAG))
+#define CONDITION_LV (IREG(TMR_ST) & LVFLAG)
+#define CONDITION_NLUF (!(IREG(TMR_ST) & LUFFLAG))
+#define CONDITION_LUF (IREG(TMR_ST) & LUFFLAG)
+#define CONDITION_ZUF (IREG(TMR_ST) & (UFFLAG | ZFLAG))
+
+static int condition(int which)
+{
+ switch (which & 0x1f)
+ {
+ case 0: return 1;
+ case 1: return CONDITION_LO;
+ case 2: return CONDITION_LS;
+ case 3: return CONDITION_HI;
+ case 4: return CONDITION_HS;
+ case 5: return CONDITION_EQ;
+ case 6: return CONDITION_NE;
+ case 7: return CONDITION_LT;
+ case 8: return CONDITION_LE;
+ case 9: return CONDITION_GT;
+ case 10: return CONDITION_GE;
+ case 12: return CONDITION_NV;
+ case 13: return CONDITION_V;
+ case 14: return CONDITION_NUF;
+ case 15: return CONDITION_UF;
+ case 16: return CONDITION_NLV;
+ case 17: return CONDITION_LV;
+ case 18: return CONDITION_NLUF;
+ case 19: return CONDITION_LUF;
+ case 20: return CONDITION_ZUF;
+ default: illegal(); return 1;
+ }
+ return 0;
+}
+
+
+
+/***************************************************************************
+ FLOATING POINT HELPERS
+***************************************************************************/
+
+#if USE_FP
+void double_to_dsp_with_flags(double val, union genreg *result)
+{
+ int mantissa, exponent;
+ int_double id;
+ id.d = val;
+
+ CLR_NZVUF();
+
+ mantissa = ((id.i[BYTE_XOR_BE(0)] & 0x000fffff) << 11) | ((id.i[BYTE_XOR_BE(1)] & 0xffe00000) >> 21);
+ exponent = ((id.i[BYTE_XOR_BE(0)] & 0x7ff00000) >> 20) - 1023;
+ if (exponent <= -128)
+ {
+ SET_MANTISSA(result, 0);
+ SET_EXPONENT(result, -128);
+ IREG(TMR_ST) |= UFFLAG | LUFFLAG | ZFLAG;
+ }
+ else if (exponent > 127)
+ {
+ if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0)
+ SET_MANTISSA(result, 0x7fffffff);
+ else
+ {
+ SET_MANTISSA(result, 0x80000001);
+ IREG(TMR_ST) |= NFLAG;
+ }
+ SET_EXPONENT(result, 127);
+ IREG(TMR_ST) |= VFLAG | LVFLAG;
+ }
+ else if (val == 0)
+ {
+ SET_MANTISSA(result, 0);
+ SET_EXPONENT(result, -128);
+ IREG(TMR_ST) |= ZFLAG;
+ }
+ else if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0)
+ {
+ SET_MANTISSA(result, mantissa);
+ SET_EXPONENT(result, exponent);
+ }
+ else if (mantissa != 0)
+ {
+ SET_MANTISSA(result, 0x80000000 | -mantissa);
+ SET_EXPONENT(result, exponent);
+ IREG(TMR_ST) |= NFLAG;
+ }
+ else
+ {
+ SET_MANTISSA(result, 0x80000000);
+ SET_EXPONENT(result, exponent - 1);
+ IREG(TMR_ST) |= NFLAG;
+ }
+}
+#endif
+
+/* integer to floating point conversion */
+#if USE_FP
+static void int2float(union genreg *srcdst)
+{
+ double val = MANTISSA(srcdst);
+ double_to_dsp_with_flags(val, srcdst);
+}
+#else
+static void int2float(union genreg *srcdst)
+{
+ UINT32 man = MANTISSA(srcdst);
+ int exp, cnt;
+
+ /* never overflows or underflows */
+ CLR_NZVUF();
+
+ /* 0 always has exponent of -128 */
+ if (man == 0)
+ {
+ man = 0x80000000;
+ exp = -128;
+ }
+
+ /* check for -1 here because count_leading_ones will infinite loop */
+ else if (man == (UINT32)-1)
+ {
+ man = 0;
+ exp = -1;
+ }
+
+ /* positive values; count leading zeros and shift */
+ else if ((INT32)man > 0)
+ {
+ cnt = count_leading_zeros(man);
+ man <<= cnt;
+ exp = 31 - cnt;
+ }
+
+ /* negative values; count leading ones and shift */
+ else
+ {
+ cnt = count_leading_ones(man);
+ man <<= cnt;
+ exp = 31 - cnt;
+ }
+
+ /* set the final results and compute NZ */
+ SET_MANTISSA(srcdst, man ^ 0x80000000);
+ SET_EXPONENT(srcdst, exp);
+ OR_NZF(srcdst);
+}
+#endif
+
+
+/* floating point to integer conversion */
+#if USE_FP
+static void float2int(union genreg *srcdst, int setflags)
+{
+ INT32 val;
+
+ if (setflags) CLR_NZVUF();
+ if (EXPONENT(srcdst) > 30)
+ {
+ if ((INT32)MANTISSA(srcdst) >= 0)
+ val = 0x7fffffff;
+ else
+ val = 0x80000000;
+ if (setflags) IREG(TMR_ST) |= VFLAG | LVFLAG;
+ }
+ else
+ val = floor(dsp_to_double(srcdst));
+ SET_MANTISSA(srcdst, val);
+ if (setflags) OR_NZ(val);
+}
+#else
+static void float2int(union genreg *srcdst, int setflags)
+{
+ INT32 man = MANTISSA(srcdst);
+ int shift = 31 - EXPONENT(srcdst);
+
+ /* never underflows */
+ if (setflags) CLR_NZVUF();
+
+ /* if we've got too much to handle, overflow */
+ if (shift <= 0)
+ {
+ SET_MANTISSA(srcdst, (man >= 0) ? 0x7fffffff : 0x80000000);
+ if (setflags) IREG(TMR_ST) |= VFLAG | LVFLAG;
+ }
+
+ /* if we're too small, go to 0 or -1 */
+ else if (shift > 31)
+ SET_MANTISSA(srcdst, man >> 31);
+
+ /* we're in the middle; shift it */
+ else
+ SET_MANTISSA(srcdst, (man >> shift) ^ (1 << (31 - shift)));
+
+ /* set the NZ flags */
+ if (setflags) OR_NZ(MANTISSA(srcdst));
+}
+#endif
+
+
+/* compute the negative of a floating point value */
+#if USE_FP
+static void negf(union genreg *dst, union genreg *src)
+{
+ double val = -dsp_to_double(src);
+ double_to_dsp_with_flags(val, dst);
+}
+#else
+static void negf(union genreg *dst, union genreg *src)
+{
+ INT32 man = MANTISSA(src);
+
+ CLR_NZVUF();
+
+ if (EXPONENT(src) == -128)
+ {
+ SET_MANTISSA(dst, 0);
+ SET_EXPONENT(dst, -128);
+ }
+ else if ((man & 0x7fffffff) != 0)
+ {
+ SET_MANTISSA(dst, -man);
+ SET_EXPONENT(dst, EXPONENT(src));
+ }
+ else
+ {
+ SET_MANTISSA(dst, man ^ 0x80000000);
+ if (man == 0)
+ SET_EXPONENT(dst, EXPONENT(src) - 1);
+ else
+ SET_EXPONENT(dst, EXPONENT(src) + 1);
+ }
+ OR_NZF(dst);
+}
+#endif
+
+
+
+/* add two floating point values */
+#if USE_FP
+static void addf(union genreg *dst, union genreg *src1, union genreg *src2)
+{
+ double val = dsp_to_double(src1) + dsp_to_double(src2);
+ double_to_dsp_with_flags(val, dst);
+}
+#else
+static void addf(union genreg *dst, union genreg *src1, union genreg *src2)
+{
+ INT64 man;
+ INT64 m1, m2;
+ int exp, cnt;
+
+ /* reset over/underflow conditions */
+ CLR_NZVUF();
+
+ /* first check for 0 operands */
+ if (EXPONENT(src1) == -128)
+ {
+ *dst = *src2;
+ OR_NZF(dst);
+ return;
+ }
+ if (EXPONENT(src2) == -128)
+ {
+ *dst = *src1;
+ OR_NZF(dst);
+ return;
+ }
+
+ /* extract mantissas from 1.0.31 values to 1.1.31 values */
+ m1 = (INT64)MANTISSA(src1) ^ 0x80000000;
+ m2 = (INT64)MANTISSA(src2) ^ 0x80000000;
+
+ /* normalize based on the exponent */
+ if (EXPONENT(src1) > EXPONENT(src2))
+ {
+ exp = EXPONENT(src1);
+ cnt = exp - EXPONENT(src2);
+ if (cnt >= 32)
+ {
+ *dst = *src1;
+ OR_NZF(dst);
+ return;
+ }
+ m2 >>= cnt;
+ }
+ else
+ {
+ exp = EXPONENT(src2);
+ cnt = exp - EXPONENT(src1);
+ if (cnt >= 32)
+ {
+ *dst = *src2;
+ OR_NZF(dst);
+ return;
+ }
+ m1 >>= cnt;
+ }
+
+ /* add */
+ man = m1 + m2;
+
+ /* if the mantissa is zero, set the exponent appropriately */
+ if (man == 0 || exp == -128)
+ {
+ exp = -128;
+ man = 0x80000000;
+ }
+
+ /* if the mantissa is >= 2.0 or < -2.0, normalize */
+ else if (man >= ((INT64)2 << 31) || man < ((INT64)-2 << 31))
+ {
+ man >>= 1;
+ exp++;
+ }
+
+ /* if the mantissa is < 1.0 and > -1.0, normalize */
+ else if (man < ((INT64)1 << 31) && man >= ((INT64)-1 << 31))
+ {
+ if (man > 0)
+ {
+ cnt = count_leading_zeros((UINT32)man);
+ man <<= cnt;
+ exp -= cnt;
+ }
+ else
+ {
+ cnt = count_leading_ones((UINT32)man);
+ man <<= cnt;
+ exp -= cnt;
+ }
+ }
+
+ /* check for underflow */
+ if (exp <= -128)
+ {
+ man = 0x80000000;
+ exp = -128;
+ IREG(TMR_ST) |= UFFLAG | LUFFLAG;
+ }
+
+ /* check for overflow */
+ else if (exp > 127)
+ {
+ man = (man < 0) ? 0x00000000 : 0xffffffff;
+ exp = 127;
+ IREG(TMR_ST) |= VFLAG | LVFLAG;
+ }
+
+ /* store the result back, removing the implicit one and putting */
+ /* back the sign bit */
+ SET_MANTISSA(dst, (UINT32)man ^ 0x80000000);
+ SET_EXPONENT(dst, exp);
+ OR_NZF(dst);
+}
+#endif
+
+
+/* subtract two floating point values */
+#if USE_FP
+static void subf(union genreg *dst, union genreg *src1, union genreg *src2)
+{
+ double val = dsp_to_double(src1) - dsp_to_double(src2);
+ double_to_dsp_with_flags(val, dst);
+}
+#else
+static void subf(union genreg *dst, union genreg *src1, union genreg *src2)
+{
+ INT64 man;
+ INT64 m1, m2;
+ int exp, cnt;
+
+ /* reset over/underflow conditions */
+ CLR_NZVUF();
+
+ /* first check for 0 operands */
+ if (EXPONENT(src2) == -128)
+ {
+ *dst = *src1;
+ OR_NZF(dst);
+ return;
+ }
+
+ /* extract mantissas from 1.0.31 values to 1.1.31 values */
+ m1 = (INT64)MANTISSA(src1) ^ 0x80000000;
+ m2 = (INT64)MANTISSA(src2) ^ 0x80000000;
+
+ /* normalize based on the exponent */
+ if (EXPONENT(src1) > EXPONENT(src2))
+ {
+ exp = EXPONENT(src1);
+ cnt = exp - EXPONENT(src2);
+ if (cnt >= 32)
+ {
+ *dst = *src1;
+ OR_NZF(dst);
+ return;
+ }
+ m2 >>= cnt;
+ }
+ else
+ {
+ exp = EXPONENT(src2);
+ cnt = exp - EXPONENT(src1);
+ if (cnt >= 32)
+ {
+ negf(dst, src2);
+ return;
+ }
+ m1 >>= cnt;
+ }
+
+ /* subtract */
+ man = m1 - m2;
+
+ /* if the mantissa is zero, set the exponent appropriately */
+ if (man == 0 || exp == -128)
+ {
+ exp = -128;
+ man = 0x80000000;
+ }
+
+ /* if the mantissa is >= 2.0 or < -2.0, normalize */
+ else if (man >= ((INT64)2 << 31) || man < ((INT64)-2 << 31))
+ {
+ man >>= 1;
+ exp++;
+ }
+
+ /* if the mantissa is < 1.0 and > -1.0, normalize */
+ else if (man < ((INT64)1 << 31) && man >= ((INT64)-1 << 31))
+ {
+ if (man > 0)
+ {
+ cnt = count_leading_zeros((UINT32)man);
+ man <<= cnt;
+ exp -= cnt;
+ }
+ else
+ {
+ cnt = count_leading_ones((UINT32)man);
+ man <<= cnt;
+ exp -= cnt;
+ }
+ }
+
+ /* check for underflow */
+ if (exp <= -128)
+ {
+ man = 0x80000000;
+ exp = -128;
+ IREG(TMR_ST) |= UFFLAG | LUFFLAG;
+ }
+
+ /* check for overflow */
+ else if (exp > 127)
+ {
+ man = (man < 0) ? 0x00000000 : 0xffffffff;
+ exp = 127;
+ IREG(TMR_ST) |= VFLAG | LVFLAG;
+ }
+
+ /* store the result back, removing the implicit one and putting */
+ /* back the sign bit */
+ SET_MANTISSA(dst, (UINT32)man ^ 0x80000000);
+ SET_EXPONENT(dst, exp);
+ OR_NZF(dst);
+}
+#endif
+
+
+/* multiply two floating point values */
+#if USE_FP
+static void mpyf(union genreg *dst, union genreg *src1, union genreg *src2)
+{
+ double val = (double)dsp_to_float(src1) * (double)dsp_to_float(src2);
+ double_to_dsp_with_flags(val, dst);
+}
+#else
+static void mpyf(union genreg *dst, union genreg *src1, union genreg *src2)
+{
+ INT64 man;
+ INT32 m1, m2;
+ int exp;
+
+ /* reset over/underflow conditions */
+ CLR_NZVUF();
+
+ /* first check for 0 multipliers and return 0 in any case */
+ if (EXPONENT(src1) == -128 || EXPONENT(src2) == -128)
+ {
+ SET_MANTISSA(dst, 0);
+ SET_EXPONENT(dst, -128);
+ OR_NZF(dst);
+ return;
+ }
+
+ /* convert the mantissas from 1.0.31 numbers to 1.1.23 numbers */
+ m1 = (MANTISSA(src1) >> 8) ^ 0x800000;
+ m2 = (MANTISSA(src2) >> 8) ^ 0x800000;
+
+ /* multiply the mantissas and add the exponents */
+ man = (INT64)m1 * (INT64)m2;
+ exp = EXPONENT(src1) + EXPONENT(src2);
+
+ /* chop off the low bits, going from 1.2.46 down to 1.2.31 */
+ man >>= 46 - 31;
+
+ /* if the mantissa is zero, set the exponent appropriately */
+ if (man == 0)
+ {
+ exp = -128;
+ man = 0x80000000;
+ }
+
+ /* if the mantissa is >= 2.0 or <= -2.0, normalize */
+ else if (man >= ((INT64)2 << 31))
+ {
+ man >>= 1;
+ exp++;
+ if (man >= ((INT64)2 << 31))
+ {
+ man >>= 1;
+ exp++;
+ }
+ }
+
+ /* if the mantissa is >= 2.0 or <= -2.0, normalize */
+ else if (man < ((INT64)-2 << 31))
+ {
+ man >>= 1;
+ exp++;
+ }
+
+ /* check for underflow */
+ if (exp <= -128)
+ {
+ man = 0x80000000;
+ exp = -128;
+ IREG(TMR_ST) |= UFFLAG | LUFFLAG;
+ }
+
+ /* check for overflow */
+ else if (exp > 127)
+ {
+ man = (man < 0) ? 0x00000000 : 0xffffffff;
+ exp = 127;
+ IREG(TMR_ST) |= VFLAG | LVFLAG;
+ }
+
+ /* store the result back, removing the implicit one and putting */
+ /* back the sign bit */
+ SET_MANTISSA(dst, (UINT32)man ^ 0x80000000);
+ SET_EXPONENT(dst, exp);
+ OR_NZF(dst);
+}
+#endif
+
+
+/* normalize a floating point value */
+#if USE_FP
+static void norm(union genreg *dst, union genreg *src)
+{
+ fatalerror("norm not implemented");
+}
+#else
+static void norm(union genreg *dst, union genreg *src)
+{
+ INT32 man = MANTISSA(src);
+ int exp = EXPONENT(src);
+
+ CLR_NZVUF();
+
+ if (exp == -128 || man == 0)
+ {
+ SET_MANTISSA(dst, 0);
+ SET_EXPONENT(dst, -128);
+ if (man != 0)
+ IREG(TMR_ST) |= UFFLAG | LUFFLAG;
+ }
+ else
+ {
+ int cnt;
+ if (man > 0)
+ {
+ cnt = count_leading_zeros((UINT32)man);
+ man <<= cnt;
+ exp -= cnt;
+ }
+ else
+ {
+ cnt = count_leading_ones((UINT32)man);
+ man <<= cnt;
+ exp -= cnt;
+ }
+
+ /* check for underflow */
+ if (exp <= -128)
+ {
+ man = 0x00000000;
+ exp = -128;
+ IREG(TMR_ST) |= UFFLAG | LUFFLAG;
+ }
+ }
+
+ SET_MANTISSA(dst, man);
+ SET_EXPONENT(dst, exp);
+ OR_NZF(dst);
+}
+#endif
+
+
+
+
+/***************************************************************************
+ INDIRECT MEMORY REFS
+***************************************************************************/
+
+/* immediate displacement variants */
+
+static UINT32 mod00_d(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg) + (UINT8)OP;
+}
+
+static UINT32 mod01_d(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg) - (UINT8)OP;
+}
+
+static UINT32 mod02_d(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ IREG(reg) += (UINT8)OP;
+ return IREG(reg);
+}
+
+static UINT32 mod03_d(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ IREG(reg) -= (UINT8)OP;
+ return IREG(reg);
+}
+
+static UINT32 mod04_d(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ IREG(reg) += (UINT8)OP;
+ return result;
+}
+
+static UINT32 mod05_d(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ IREG(reg) -= (UINT8)OP;
+ return result;
+}
+
+static UINT32 mod06_d(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) + (UINT8)OP;
+ if (temp >= IREG(TMR_BK))
+ temp -= IREG(TMR_BK);
+ IREG(reg) = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+static UINT32 mod07_d(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) - (UINT8)OP;
+ if (temp < 0)
+ temp += IREG(TMR_BK);
+ IREG(reg) = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+
+/* immediate displacement variants (implied 1) */
+
+static UINT32 mod00_1(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg) + 1;
+}
+
+static UINT32 mod01_1(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg) - 1;
+}
+
+static UINT32 mod02_1(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return ++IREG(reg);
+}
+
+static UINT32 mod03_1(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return --IREG(reg);
+}
+
+static UINT32 mod04_1(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg)++;
+}
+
+static UINT32 mod05_1(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg)--;
+}
+
+static UINT32 mod06_1(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) + 1;
+ if (temp >= IREG(TMR_BK))
+ temp -= IREG(TMR_BK);
+ IREG(reg) = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+static UINT32 mod07_1(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) - 1;
+ if (temp < 0)
+ temp += IREG(TMR_BK);
+ IREG(reg) = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+
+/* IR0 displacement variants */
+
+static UINT32 mod08(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg) + IREG(TMR_IR0);
+}
+
+static UINT32 mod09(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg) - IREG(TMR_IR0);
+}
+
+static UINT32 mod0a(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ IREG(reg) += IREG(TMR_IR0);
+ return IREG(reg);
+}
+
+static UINT32 mod0b(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ IREG(reg) -= IREG(TMR_IR0);
+ return IREG(reg);
+}
+
+static UINT32 mod0c(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ IREG(reg) += IREG(TMR_IR0);
+ return result;
+}
+
+static UINT32 mod0d(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ IREG(reg) -= IREG(TMR_IR0);
+ return result;
+}
+
+static UINT32 mod0e(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) + IREG(TMR_IR0);
+ if (temp >= IREG(TMR_BK))
+ temp -= IREG(TMR_BK);
+ IREG(reg) = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+static UINT32 mod0f(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) - IREG(TMR_IR0);
+ if (temp < 0)
+ temp += IREG(TMR_BK);
+ IREG(reg) = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+
+/* IR1 displacement variants */
+
+static UINT32 mod10(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg) + IREG(TMR_IR1);
+}
+
+static UINT32 mod11(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg) - IREG(TMR_IR1);
+}
+
+static UINT32 mod12(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ IREG(reg) += IREG(TMR_IR1);
+ return IREG(reg);
+}
+
+static UINT32 mod13(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ IREG(reg) -= IREG(TMR_IR1);
+ return IREG(reg);
+}
+
+static UINT32 mod14(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ IREG(reg) += IREG(TMR_IR1);
+ return result;
+}
+
+static UINT32 mod15(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ IREG(reg) -= IREG(TMR_IR1);
+ return result;
+}
+
+static UINT32 mod16(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) + IREG(TMR_IR1);
+ if (temp >= IREG(TMR_BK))
+ temp -= IREG(TMR_BK);
+ IREG(reg) = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+static UINT32 mod17(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) - IREG(TMR_IR1);
+ if (temp < 0)
+ temp += IREG(TMR_BK);
+ IREG(reg) = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+
+/* special variants */
+
+static UINT32 mod18(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ return IREG(reg);
+}
+
+static UINT32 mod19(UINT8 ar)
+{
+ unimplemented();
+ return 0;
+}
+
+static UINT32 modillegal(UINT8 ar)
+{
+ illegal();
+ return 0;
+}
+
+
+/* immediate displacement variants (implied 1) */
+
+static UINT32 mod02_1_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) + 1;
+ return defval;
+}
+
+static UINT32 mod03_1_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) - 1;
+ return defval;
+}
+
+static UINT32 mod04_1_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) + 1;
+ return IREG(reg);
+}
+
+static UINT32 mod05_1_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) - 1;
+ return IREG(reg);
+}
+
+static UINT32 mod06_1_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) + 1;
+ if (temp >= IREG(TMR_BK))
+ temp -= IREG(TMR_BK);
+ defptr = &IREG(reg);
+ defval = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+static UINT32 mod07_1_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) - 1;
+ if (temp < 0)
+ temp += IREG(TMR_BK);
+ defptr = &IREG(reg);
+ defval = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+
+/* IR0 displacement variants */
+
+static UINT32 mod0a_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) + IREG(TMR_IR0);
+ return defval;
+}
+
+static UINT32 mod0b_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) - IREG(TMR_IR0);
+ return defval;
+}
+
+static UINT32 mod0c_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) + IREG(TMR_IR0);
+ return IREG(reg);
+}
+
+static UINT32 mod0d_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) - IREG(TMR_IR0);
+ return IREG(reg);
+}
+
+static UINT32 mod0e_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) + IREG(TMR_IR0);
+ if (temp >= IREG(TMR_BK))
+ temp -= IREG(TMR_BK);
+ defptr = &IREG(reg);
+ defval = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+static UINT32 mod0f_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) - IREG(TMR_IR0);
+ if (temp < 0)
+ temp += IREG(TMR_BK);
+ defptr = &IREG(reg);
+ defval = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+
+/* IR1 displacement variants */
+
+static UINT32 mod12_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) + IREG(TMR_IR1);
+ return defval;
+}
+
+static UINT32 mod13_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) - IREG(TMR_IR1);
+ return defval;
+}
+
+static UINT32 mod14_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) + IREG(TMR_IR1);
+ return IREG(reg);
+}
+
+static UINT32 mod15_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ defptr = &IREG(reg);
+ defval = IREG(reg) - IREG(TMR_IR1);
+ return IREG(reg);
+}
+
+static UINT32 mod16_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) + IREG(TMR_IR1);
+ if (temp >= IREG(TMR_BK))
+ temp -= IREG(TMR_BK);
+ defptr = &IREG(reg);
+ defval = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+static UINT32 mod17_def(UINT8 ar)
+{
+ int reg = TMR_AR0 + (ar & 7);
+ UINT32 result = IREG(reg);
+ INT32 temp = (result & tms32031.bkmask) - IREG(TMR_IR1);
+ if (temp < 0)
+ temp += IREG(TMR_BK);
+ defptr = &IREG(reg);
+ defval = (IREG(reg) & ~tms32031.bkmask) | (temp & tms32031.bkmask);
+ return result;
+}
+
+
+/* tables */
+
+static UINT32 (*indirect_d[0x20])(UINT8) =
+{
+ mod00_d, mod01_d, mod02_d, mod03_d, mod04_d, mod05_d, mod06_d, mod07_d,
+ mod08, mod09, mod0a, mod0b, mod0c, mod0d, mod0e, mod0f,
+ mod10, mod11, mod12, mod13, mod14, mod15, mod16, mod17,
+ mod18, mod19, modillegal, modillegal, modillegal, modillegal, modillegal, modillegal
+};
+
+
+static UINT32 (*indirect_1[0x20])(UINT8) =
+{
+ mod00_1, mod01_1, mod02_1, mod03_1, mod04_1, mod05_1, mod06_1, mod07_1,
+ mod08, mod09, mod0a, mod0b, mod0c, mod0d, mod0e, mod0f,
+ mod10, mod11, mod12, mod13, mod14, mod15, mod16, mod17,
+ mod18, mod19, modillegal, modillegal, modillegal, modillegal, modillegal, modillegal
+};
+
+
+static UINT32 (*indirect_1_def[0x20])(UINT8) =
+{
+ mod00_1, mod01_1, mod02_1_def,mod03_1_def,mod04_1_def,mod05_1_def,mod06_1_def,mod07_1_def,
+ mod08, mod09, mod0a_def, mod0b_def, mod0c_def, mod0d_def, mod0e_def, mod0f_def,
+ mod10, mod11, mod12_def, mod13_def, mod14_def, mod15_def, mod16_def, mod17_def,
+ mod18, mod19, modillegal, modillegal, modillegal, modillegal, modillegal, modillegal
+};
+
+
+
+/*-----------------------------------------------------*/
+
+#define ABSF(dreg, sreg) \
+{ \
+ INT32 man = FREGMAN(sreg); \
+ CLR_NZVUF(); \
+ tms32031.r[dreg] = tms32031.r[sreg]; \
+ if (man < 0) \
+ { \
+ SET_MANTISSA(&tms32031.r[dreg], ~man); \
+ if (man == (INT32)0x80000000 && FREGEXP(sreg) == 127) \
+ IREG(TMR_ST) |= VFLAG | LVFLAG; \
+ } \
+ OR_NZF(&tms32031.r[dreg]); \
+}
+
+static void absf_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ int sreg = OP & 7;
+ ABSF(dreg, sreg);
+}
+
+static void absf_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ ABSF(dreg, TMR_TEMP1);
+}
+
+static void absf_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ ABSF(dreg, TMR_TEMP1);
+}
+
+static void absf_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(TMR_TEMP1, OP);
+ ABSF(dreg, TMR_TEMP1);
+}
+
+/*-----------------------------------------------------*/
+
+#define ABSI(dreg, src) \
+{ \
+ UINT32 _res = ((INT32)src < 0) ? -src : src; \
+ if (!OVM || _res != 0x80000000) \
+ IREG(dreg) = _res; \
+ else \
+ IREG(dreg) = 0x7fffffff; \
+ if (dreg < 8) \
+ { \
+ CLR_NZVUF(); \
+ OR_NZ(_res); \
+ if (_res == 0x80000000) \
+ IREG(TMR_ST) |= VFLAG | LVFLAG; \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void absi_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ ABSI(dreg, src);
+}
+
+static void absi_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ ABSI(dreg, src);
+}
+
+static void absi_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ ABSI(dreg, src);
+}
+
+static void absi_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ ABSI(dreg, src);
+}
+
+/*-----------------------------------------------------*/
+
+#define ADDC(dreg, src1, src2) \
+{ \
+ UINT32 _res = src1 + src2 + (IREG(TMR_ST) & CFLAG); \
+ if (!OVM || !OVERFLOW_ADD(src1,src2,_res)) \
+ IREG(dreg) = _res; \
+ else \
+ IREG(dreg) = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; \
+ if (dreg < 8) \
+ { \
+ UINT32 tempc = src2 + (IREG(TMR_ST) & CFLAG); \
+ CLR_NZCVUF(); \
+ OR_NZCV_ADD(src1,tempc,_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void addc_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ADDC(dreg, dst, src);
+}
+
+static void addc_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ADDC(dreg, dst, src);
+}
+
+static void addc_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ADDC(dreg, dst, src);
+}
+
+static void addc_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ADDC(dreg, dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void addf_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ addf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[OP & 7]);
+}
+
+static void addf_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ addf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void addf_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ addf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void addf_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(TMR_TEMP1, OP);
+ addf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+/*-----------------------------------------------------*/
+
+#define ADDI(dreg, src1, src2) \
+{ \
+ UINT32 _res = src1 + src2; \
+ if (!OVM || !OVERFLOW_ADD(src1,src2,_res)) \
+ IREG(dreg) = _res; \
+ else \
+ IREG(dreg) = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; \
+ if (dreg < 8) \
+ { \
+ CLR_NZCVUF(); \
+ OR_NZCV_ADD(src1,src2,_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void addi_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ADDI(dreg, dst, src);
+}
+
+static void addi_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ADDI(dreg, dst, src);
+}
+
+static void addi_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ADDI(dreg, dst, src);
+}
+
+static void addi_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ADDI(dreg, dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+#define AND(dreg, src1, src2) \
+{ \
+ UINT32 _res = (src1) & (src2); \
+ IREG(dreg) = _res; \
+ if (dreg < 8) \
+ { \
+ CLR_NZVUF(); \
+ OR_NZ(_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void and_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ AND(dreg, dst, src);
+}
+
+static void and_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ AND(dreg, dst, src);
+}
+
+static void and_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ AND(dreg, dst, src);
+}
+
+static void and_imm(void)
+{
+ UINT32 src = (UINT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ AND(dreg, dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+#define ANDN(dreg, src1, src2) \
+{ \
+ UINT32 _res = (src1) & ~(src2); \
+ IREG(dreg) = _res; \
+ if (dreg < 8) \
+ { \
+ CLR_NZVUF(); \
+ OR_NZ(_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void andn_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ANDN(dreg, dst, src);
+}
+
+static void andn_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ANDN(dreg, dst, src);
+}
+
+static void andn_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ANDN(dreg, dst, src);
+}
+
+static void andn_imm(void)
+{
+ UINT32 src = (UINT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ ANDN(dreg, dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+#define ASH(dreg, src, count) \
+{ \
+ UINT32 _res; \
+ INT32 _count = (INT16)(count << 9) >> 9; /* 7 LSBs */ \
+ if (_count < 0) \
+ { \
+ if (_count >= -31) \
+ _res = (INT32)src >> -_count; \
+ else \
+ _res = (INT32)src >> 31; \
+ } \
+ else \
+ { \
+ if (_count <= 31) \
+ _res = (INT32)src << _count; \
+ else \
+ _res = 0; \
+ } \
+ IREG(dreg) = _res; \
+ if (dreg < 8) \
+ { \
+ CLR_NZCVUF(); \
+ OR_NZ(_res); \
+ if (_count < 0) \
+ { \
+ if (_count >= -32) \
+ OR_C(((INT32)src >> (-_count - 1)) & 1); \
+ else \
+ OR_C(((INT32)src >> 31) & 1); \
+ } \
+ else if (_count > 0) \
+ { \
+ if (_count <= 32) \
+ OR_C(((UINT32)src << (_count - 1)) >> 31); \
+ } \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void ash_reg(void)
+{
+ int dreg = (OP >> 16) & 31;
+ int count = IREG(OP & 31);
+ UINT32 src = IREG(dreg);
+ ASH(dreg, src, count);
+}
+
+static void ash_dir(void)
+{
+ int dreg = (OP >> 16) & 31;
+ int count = RMEM(DIRECT());
+ UINT32 src = IREG(dreg);
+ ASH(dreg, src, count);
+}
+
+static void ash_ind(void)
+{
+ int dreg = (OP >> 16) & 31;
+ int count = RMEM(INDIRECT_D(OP >> 8));
+ UINT32 src = IREG(dreg);
+ ASH(dreg, src, count);
+}
+
+static void ash_imm(void)
+{
+ int dreg = (OP >> 16) & 31;
+ int count = OP;
+ UINT32 src = IREG(dreg);
+ ASH(dreg, src, count);
+}
+
+/*-----------------------------------------------------*/
+
+static void cmpf_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ subf(&tms32031.r[TMR_TEMP2], &tms32031.r[dreg], &tms32031.r[OP & 7]);
+}
+
+static void cmpf_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ subf(&tms32031.r[TMR_TEMP2], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void cmpf_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ subf(&tms32031.r[TMR_TEMP2], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void cmpf_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(TMR_TEMP1, OP);
+ subf(&tms32031.r[TMR_TEMP2], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+/*-----------------------------------------------------*/
+
+#define CMPI(src1, src2) \
+{ \
+ UINT32 _res = src1 - src2; \
+ CLR_NZCVUF(); \
+ OR_NZCV_SUB(src1,src2,_res); \
+}
+
+static void cmpi_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ UINT32 dst = IREG((OP >> 16) & 31);
+ CMPI(dst, src);
+}
+
+static void cmpi_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ UINT32 dst = IREG((OP >> 16) & 31);
+ CMPI(dst, src);
+}
+
+static void cmpi_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ UINT32 dst = IREG((OP >> 16) & 31);
+ CMPI(dst, src);
+}
+
+static void cmpi_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ UINT32 dst = IREG((OP >> 16) & 31);
+ CMPI(dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void fix_reg(void)
+{
+ int dreg = (OP >> 16) & 31;
+ tms32031.r[dreg] = tms32031.r[OP & 7];
+ float2int(&tms32031.r[dreg], dreg < 8);
+}
+
+static void fix_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ LONG2FP(dreg, res);
+ float2int(&tms32031.r[dreg], dreg < 8);
+}
+
+static void fix_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ LONG2FP(dreg, res);
+ float2int(&tms32031.r[dreg], dreg < 8);
+}
+
+static void fix_imm(void)
+{
+ int dreg = (OP >> 16) & 31;
+ SHORT2FP(dreg, OP);
+ float2int(&tms32031.r[dreg], dreg < 8);
+}
+
+/*-----------------------------------------------------*/
+
+#define FLOAT(dreg, src) \
+{ \
+ IREG(dreg) = src; \
+ int2float(&tms32031.r[dreg]); \
+}
+
+static void float_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 7;
+ FLOAT(dreg, src);
+}
+
+static void float_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ FLOAT(dreg, src);
+}
+
+static void float_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ FLOAT(dreg, src);
+}
+
+static void float_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 7;
+ FLOAT(dreg, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void idle(void)
+{
+ tms32031.is_idling = 1;
+ IREG(TMR_ST) |= GIEFLAG;
+ check_irqs();
+ if (tms32031.is_idling)
+ tms32031_icount = 0;
+}
+
+/*-----------------------------------------------------*/
+
+static void lde_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SET_EXPONENT(&tms32031.r[dreg], EXPONENT(&tms32031.r[OP & 7]));
+ if (EXPONENT(&tms32031.r[dreg]) == -128)
+ SET_MANTISSA(&tms32031.r[dreg], 0);
+}
+
+static void lde_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ SET_EXPONENT(&tms32031.r[dreg], EXPONENT(&tms32031.r[TMR_TEMP1]));
+ if (EXPONENT(&tms32031.r[dreg]) == -128)
+ SET_MANTISSA(&tms32031.r[dreg], 0);
+}
+
+static void lde_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ SET_EXPONENT(&tms32031.r[dreg], EXPONENT(&tms32031.r[TMR_TEMP1]));
+ if (EXPONENT(&tms32031.r[dreg]) == -128)
+ SET_MANTISSA(&tms32031.r[dreg], 0);
+}
+
+static void lde_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(TMR_TEMP1, OP);
+ SET_EXPONENT(&tms32031.r[dreg], EXPONENT(&tms32031.r[TMR_TEMP1]));
+ if (EXPONENT(&tms32031.r[dreg]) == -128)
+ SET_MANTISSA(&tms32031.r[dreg], 0);
+}
+
+/*-----------------------------------------------------*/
+
+static void ldf_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ tms32031.r[dreg] = tms32031.r[OP & 7];
+ CLR_NZVUF();
+ OR_NZF(&tms32031.r[dreg]);
+}
+
+static void ldf_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ CLR_NZVUF();
+ OR_NZF(&tms32031.r[dreg]);
+}
+
+static void ldf_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ CLR_NZVUF();
+ OR_NZF(&tms32031.r[dreg]);
+}
+
+static void ldf_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ CLR_NZVUF();
+ OR_NZF(&tms32031.r[dreg]);
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfi_dir(void) { unimplemented(); }
+static void ldfi_ind(void) { unimplemented(); }
+
+/*-----------------------------------------------------*/
+
+#define LDI(dreg, src) \
+{ \
+ IREG(dreg) = src; \
+ if (dreg < 8) \
+ { \
+ CLR_NZVUF(); \
+ OR_NZ(src); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void ldi_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ LDI(dreg, src);
+}
+
+static void ldi_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ LDI(dreg, src);
+}
+
+static void ldi_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ LDI(dreg, src);
+}
+
+static void ldi_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ LDI(dreg, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void ldii_dir(void) { unimplemented(); }
+static void ldii_ind(void) { unimplemented(); }
+
+/*-----------------------------------------------------*/
+
+static void ldm_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SET_MANTISSA(&tms32031.r[dreg], MANTISSA(&tms32031.r[OP & 7]));
+}
+
+static void ldm_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ SET_MANTISSA(&tms32031.r[dreg], res);
+}
+
+static void ldm_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ SET_MANTISSA(&tms32031.r[dreg], res);
+}
+
+static void ldm_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(TMR_TEMP1, OP);
+ SET_MANTISSA(&tms32031.r[dreg], MANTISSA(&tms32031.r[TMR_TEMP1]));
+}
+
+/*-----------------------------------------------------*/
+
+#define LSH(dreg, src, count) \
+{ \
+ UINT32 _res; \
+ INT32 _count = (INT16)(count << 9) >> 9; /* 7 LSBs */ \
+ if (_count < 0) \
+ { \
+ if (_count >= -31) \
+ _res = (UINT32)src >> -_count; \
+ else \
+ _res = 0; \
+ } \
+ else \
+ { \
+ if (_count <= 31) \
+ _res = (UINT32)src << _count; \
+ else \
+ _res = 0; \
+ } \
+ IREG(dreg) = _res; \
+ if (dreg < 8) \
+ { \
+ CLR_NZCVUF(); \
+ OR_NZ(_res); \
+ if (_count < 0) \
+ { \
+ if (_count >= -32) \
+ OR_C(((UINT32)src >> (-_count - 1)) & 1); \
+ } \
+ else if (_count > 0) \
+ { \
+ if (_count <= 32) \
+ OR_C(((UINT32)src << (_count - 1)) >> 31); \
+ } \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void lsh_reg(void)
+{
+ int dreg = (OP >> 16) & 31;
+ int count = IREG(OP & 31);
+ UINT32 src = IREG(dreg);
+ LSH(dreg, src, count);
+}
+
+static void lsh_dir(void)
+{
+ int dreg = (OP >> 16) & 31;
+ int count = RMEM(DIRECT());
+ UINT32 src = IREG(dreg);
+ LSH(dreg, src, count);
+}
+
+static void lsh_ind(void)
+{
+ int dreg = (OP >> 16) & 31;
+ int count = RMEM(INDIRECT_D(OP >> 8));
+ UINT32 src = IREG(dreg);
+ LSH(dreg, src, count);
+}
+
+static void lsh_imm(void)
+{
+ int dreg = (OP >> 16) & 31;
+ int count = OP;
+ UINT32 src = IREG(dreg);
+ LSH(dreg, src, count);
+}
+
+/*-----------------------------------------------------*/
+
+static void mpyf_reg(void)
+{
+ int dreg = (OP >> 16) & 31;
+ mpyf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[OP & 31]);
+}
+
+static void mpyf_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ LONG2FP(TMR_TEMP1, res);
+ mpyf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void mpyf_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ LONG2FP(TMR_TEMP1, res);
+ mpyf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void mpyf_imm(void)
+{
+ int dreg = (OP >> 16) & 31;
+ SHORT2FP(TMR_TEMP1, OP);
+ mpyf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+/*-----------------------------------------------------*/
+
+#define MPYI(dreg, src1, src2) \
+{ \
+ INT64 _res = (INT64)((INT32)(src1 << 8) >> 8) * (INT64)((INT32)(src2 << 8) >> 8);\
+ if (!OVM || (_res >= -0x80000000 && _res <= 0x7fffffff)) \
+ IREG(dreg) = _res; \
+ else \
+ IREG(dreg) = (_res < 0) ? 0x80000000 : 0x7fffffff; \
+ if (dreg < 8) \
+ { \
+ CLR_NZVUF(); \
+ OR_NZ((UINT32)_res); \
+ if (_res < -(INT64)0x80000000 || _res > (INT64)0x7fffffff) \
+ IREG(TMR_ST) |= VFLAG | LVFLAG; \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void mpyi_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ MPYI(dreg, dst, src);
+}
+
+static void mpyi_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ MPYI(dreg, dst, src);
+}
+
+static void mpyi_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ MPYI(dreg, dst, src);
+}
+
+static void mpyi_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ MPYI(dreg, dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+#define NEGB(dreg, src) \
+{ \
+ UINT32 temps = 0 - (IREG(TMR_ST) & CFLAG); \
+ UINT32 _res = temps - src; \
+ if (!OVM || !OVERFLOW_SUB(temps,src,_res)) \
+ IREG(dreg) = _res; \
+ else \
+ IREG(dreg) = ((INT32)src < 0) ? 0x80000000 : 0x7fffffff; \
+ if (dreg < 8) \
+ { \
+ CLR_NZCVUF(); \
+ OR_NZCV_SUB(temps,src,_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void negb_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ NEGB(dreg, src);
+}
+
+static void negb_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ NEGB(dreg, src);
+}
+
+static void negb_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ NEGB(dreg, src);
+}
+
+static void negb_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ NEGB(dreg, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void negf_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ negf(&tms32031.r[dreg], &tms32031.r[OP & 7]);
+}
+
+static void negf_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ negf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void negf_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ negf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void negf_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(TMR_TEMP1, OP);
+ negf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+/*-----------------------------------------------------*/
+
+#define NEGI(dreg, src) \
+{ \
+ UINT32 _res = 0 - src; \
+ if (!OVM || !OVERFLOW_SUB(0,src,_res)) \
+ IREG(dreg) = _res; \
+ else \
+ IREG(dreg) = ((INT32)src < 0) ? 0x80000000 : 0x7fffffff; \
+ if (dreg < 8) \
+ { \
+ CLR_NZCVUF(); \
+ OR_NZCV_SUB(0,src,_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void negi_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ NEGI(dreg, src);
+}
+
+static void negi_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ NEGI(dreg, src);
+}
+
+static void negi_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ NEGI(dreg, src);
+}
+
+static void negi_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ NEGI(dreg, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void nop_reg(void)
+{
+}
+
+static void nop_ind(void)
+{
+ RMEM(INDIRECT_D(OP >> 8));
+}
+
+/*-----------------------------------------------------*/
+
+static void norm_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ norm(&tms32031.r[dreg], &tms32031.r[OP & 7]);
+}
+
+static void norm_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ norm(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void norm_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ norm(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void norm_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(TMR_TEMP1, OP);
+ norm(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+/*-----------------------------------------------------*/
+
+#define NOT(dreg, src) \
+{ \
+ UINT32 _res = ~(src); \
+ IREG(dreg) = _res; \
+ if (dreg < 8) \
+ { \
+ CLR_NZVUF(); \
+ OR_NZ(_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void not_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ NOT(dreg, src);
+}
+
+static void not_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ NOT(dreg, src);
+}
+
+static void not_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ NOT(dreg, src);
+}
+
+static void not_imm(void)
+{
+ UINT32 src = (UINT16)OP;
+ int dreg = (OP >> 16) & 31;
+ NOT(dreg, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void pop(void)
+{
+ int dreg = (OP >> 16) & 31;
+ UINT32 val = RMEM(IREG(TMR_SP)--);
+ IREG(dreg) = val;
+ if (dreg < 8)
+ {
+ CLR_NZVUF();
+ OR_NZ(val);
+ }
+ else if (dreg >= TMR_BK)
+ update_special(dreg);
+}
+
+static void popf(void)
+{
+ int dreg = (OP >> 16) & 7;
+ UINT32 val = RMEM(IREG(TMR_SP)--);
+ LONG2FP(dreg, val);
+ CLR_NZVUF();
+ OR_NZF(&tms32031.r[dreg]);
+}
+
+static void push(void)
+{
+ WMEM(++IREG(TMR_SP), IREG((OP >> 16) & 31));
+}
+
+static void pushf(void)
+{
+ int dreg = (OP >> 16) & 7;
+ WMEM(++IREG(TMR_SP), FP2LONG(dreg));
+}
+
+/*-----------------------------------------------------*/
+
+#define OR(dreg, src1, src2) \
+{ \
+ UINT32 _res = (src1) | (src2); \
+ IREG(dreg) = _res; \
+ if (dreg < 8) \
+ { \
+ CLR_NZVUF(); \
+ OR_NZ(_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void or_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ OR(dreg, dst, src);
+}
+
+static void or_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ OR(dreg, dst, src);
+}
+
+static void or_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ OR(dreg, dst, src);
+}
+
+static void or_imm(void)
+{
+ UINT32 src = (UINT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ OR(dreg, dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void maxspeed(void) { unimplemented(); }
+
+/*-----------------------------------------------------*/
+
+#define RND(dreg) \
+{ \
+ INT32 man = FREGMAN(dreg); \
+ CLR_NVUF(); \
+ if (man < 0x7fffff80) \
+ { \
+ SET_MANTISSA(&tms32031.r[dreg], ((UINT32)man + 0x80) & 0xffffff00); \
+ OR_NUF(&tms32031.r[dreg]); \
+ } \
+ else if (FREGEXP(dreg) < 127) \
+ { \
+ SET_MANTISSA(&tms32031.r[dreg], ((UINT32)man + 0x80) & 0x7fffff00); \
+ SET_EXPONENT(&tms32031.r[dreg], FREGEXP(dreg) + 1); \
+ OR_NUF(&tms32031.r[dreg]); \
+ } \
+ else \
+ { \
+ SET_MANTISSA(&tms32031.r[dreg], 0x7fffff00); \
+ IREG(TMR_ST) |= VFLAG | LVFLAG; \
+ } \
+}
+
+static void rnd_reg(void)
+{
+ int sreg = OP & 7;
+ int dreg = (OP >> 16) & 7;
+ tms32031.r[dreg] = tms32031.r[sreg];
+ RND(dreg);
+}
+
+static void rnd_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ RND(dreg);
+}
+
+static void rnd_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ RND(dreg);
+}
+
+static void rnd_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ RND(dreg);
+}
+
+/*-----------------------------------------------------*/
+
+static void rol(void)
+{
+ int dreg = (OP >> 16) & 31;
+ UINT32 res = IREG(dreg);
+ int newcflag = res >> 31;
+ res = (res << 1) | newcflag;
+ IREG(dreg) = res;
+ if (dreg < 8)
+ {
+ CLR_NZCVUF();
+ OR_NZ(res);
+ OR_C(newcflag);
+ }
+ else if (dreg >= TMR_BK)
+ update_special(dreg);
+}
+
+static void rolc(void)
+{
+ int dreg = (OP >> 16) & 31;
+ UINT32 res = IREG(dreg);
+ int newcflag = res >> 31;
+ res = (res << 1) | (IREG(TMR_ST) & CFLAG);
+ IREG(dreg) = res;
+ if (dreg < 8)
+ {
+ CLR_NZCVUF();
+ OR_NZ(res);
+ OR_C(newcflag);
+ }
+ else if (dreg >= TMR_BK)
+ update_special(dreg);
+}
+
+static void ror(void)
+{
+ int dreg = (OP >> 16) & 31;
+ UINT32 res = IREG(dreg);
+ int newcflag = res & 1;
+ res = (res >> 1) | (newcflag << 31);
+ IREG(dreg) = res;
+ if (dreg < 8)
+ {
+ CLR_NZCVUF();
+ OR_NZ(res);
+ OR_C(newcflag);
+ }
+ else if (dreg >= TMR_BK)
+ update_special(dreg);
+}
+
+static void rorc(void)
+{
+ int dreg = (OP >> 16) & 31;
+ UINT32 res = IREG(dreg);
+ int newcflag = res & 1;
+ res = (res >> 1) | ((IREG(TMR_ST) & CFLAG) << 31);
+ IREG(dreg) = res;
+ if (dreg < 8)
+ {
+ CLR_NZCVUF();
+ OR_NZ(res);
+ OR_C(newcflag);
+ }
+ else if (dreg >= TMR_BK)
+ update_special(dreg);
+}
+
+/*-----------------------------------------------------*/
+
+static void rtps_reg(void)
+{
+ IREG(TMR_RC) = IREG(OP & 31);
+ IREG(TMR_RS) = tms32031.pc;
+ IREG(TMR_RE) = tms32031.pc;
+ IREG(TMR_ST) |= RMFLAG;
+ tms32031_icount -= 3*2;
+ tms32031.delayed = 1;
+}
+
+static void rtps_dir(void)
+{
+ IREG(TMR_RC) = RMEM(DIRECT());
+ IREG(TMR_RS) = tms32031.pc;
+ IREG(TMR_RE) = tms32031.pc;
+ IREG(TMR_ST) |= RMFLAG;
+ tms32031_icount -= 3*2;
+ tms32031.delayed = 1;
+}
+
+static void rtps_ind(void)
+{
+ IREG(TMR_RC) = RMEM(INDIRECT_D(OP >> 8));
+ IREG(TMR_RS) = tms32031.pc;
+ IREG(TMR_RE) = tms32031.pc;
+ IREG(TMR_ST) |= RMFLAG;
+ tms32031_icount -= 3*2;
+ tms32031.delayed = 1;
+}
+
+static void rtps_imm(void)
+{
+ IREG(TMR_RC) = (UINT16)OP;
+ IREG(TMR_RS) = tms32031.pc;
+ IREG(TMR_RE) = tms32031.pc;
+ IREG(TMR_ST) |= RMFLAG;
+ tms32031_icount -= 3*2;
+ tms32031.delayed = 1;
+}
+
+/*-----------------------------------------------------*/
+
+static void stf_dir(void)
+{
+ WMEM(DIRECT(), FP2LONG((OP >> 16) & 7));
+}
+
+static void stf_ind(void)
+{
+ WMEM(INDIRECT_D(OP >> 8), FP2LONG((OP >> 16) & 7));
+}
+
+/*-----------------------------------------------------*/
+
+static void stfi_dir(void) { unimplemented(); }
+static void stfi_ind(void) { unimplemented(); }
+
+/*-----------------------------------------------------*/
+
+static void sti_dir(void)
+{
+ WMEM(DIRECT(), IREG((OP >> 16) & 31));
+}
+
+static void sti_ind(void)
+{
+ WMEM(INDIRECT_D(OP >> 8), IREG((OP >> 16) & 31));
+}
+
+/*-----------------------------------------------------*/
+
+static void stii_dir(void) { unimplemented(); }
+static void stii_ind(void) { unimplemented(); }
+
+/*-----------------------------------------------------*/
+
+static void sigi(void) { unimplemented(); }
+
+/*-----------------------------------------------------*/
+
+#define SUBB(dreg, src1, src2) \
+{ \
+ UINT32 temps = src1 - (IREG(TMR_ST) & CFLAG); \
+ UINT32 _res = temps - src2; \
+ if (!OVM || !OVERFLOW_SUB(temps,src2,_res)) \
+ IREG(dreg) = _res; \
+ else \
+ IREG(dreg) = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; \
+ if (dreg < 8) \
+ { \
+ CLR_NZCVUF(); \
+ OR_NZCV_SUB(temps,src2,_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void subb_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBB(dreg, dst, src);
+}
+
+static void subb_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBB(dreg, dst, src);
+}
+
+static void subb_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBB(dreg, dst, src);
+}
+
+static void subb_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBB(dreg, dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+#define SUBC(dreg, src) \
+{ \
+ UINT32 dst = IREG(dreg); \
+ if (dst >= src) \
+ IREG(dreg) = ((dst - src) << 1) | 1; \
+ else \
+ IREG(dreg) = dst << 1; \
+ if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void subc_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ SUBC(dreg, src);
+}
+
+static void subc_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ SUBC(dreg, src);
+}
+
+static void subc_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ SUBC(dreg, src);
+}
+
+static void subc_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ SUBC(dreg, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void subf_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ subf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[OP & 7]);
+}
+
+static void subf_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ subf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void subf_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ subf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+static void subf_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(TMR_TEMP1, OP);
+ subf(&tms32031.r[dreg], &tms32031.r[dreg], &tms32031.r[TMR_TEMP1]);
+}
+
+/*-----------------------------------------------------*/
+
+#define SUBI(dreg, src1, src2) \
+{ \
+ UINT32 _res = src1 - src2; \
+ if (!OVM || !OVERFLOW_SUB(src1,src2,_res)) \
+ IREG(dreg) = _res; \
+ else \
+ IREG(dreg) = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; \
+ if (dreg < 8) \
+ { \
+ CLR_NZCVUF(); \
+ OR_NZCV_SUB(src1,src2,_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void subi_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBI(dreg, dst, src);
+}
+
+static void subi_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBI(dreg, dst, src);
+}
+
+static void subi_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBI(dreg, dst, src);
+}
+
+static void subi_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBI(dreg, dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void subrb_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBB(dreg, src, dst);
+}
+
+static void subrb_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBB(dreg, src, dst);
+}
+
+static void subrb_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBB(dreg, src, dst);
+}
+
+static void subrb_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBB(dreg, src, dst);
+}
+
+/*-----------------------------------------------------*/
+
+static void subrf_reg(void)
+{
+ int dreg = (OP >> 16) & 7;
+ subf(&tms32031.r[dreg], &tms32031.r[OP & 7], &tms32031.r[dreg]);
+}
+
+static void subrf_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ subf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1], &tms32031.r[dreg]);
+}
+
+static void subrf_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, res);
+ subf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1], &tms32031.r[dreg]);
+}
+
+static void subrf_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(TMR_TEMP1, OP);
+ subf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1], &tms32031.r[dreg]);
+}
+
+/*-----------------------------------------------------*/
+
+static void subri_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBI(dreg, src, dst);
+}
+
+static void subri_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBI(dreg, src, dst);
+}
+
+static void subri_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBI(dreg, src, dst);
+}
+
+static void subri_imm(void)
+{
+ UINT32 src = (INT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ SUBI(dreg, src, dst);
+}
+
+/*-----------------------------------------------------*/
+
+#define TSTB(src1, src2) \
+{ \
+ UINT32 _res = (src1) & (src2); \
+ CLR_NZVUF(); \
+ OR_NZ(_res); \
+}
+
+static void tstb_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ UINT32 dst = IREG((OP >> 16) & 31);
+ TSTB(dst, src);
+}
+
+static void tstb_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ UINT32 dst = IREG((OP >> 16) & 31);
+ TSTB(dst, src);
+}
+
+static void tstb_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ UINT32 dst = IREG((OP >> 16) & 31);
+ TSTB(dst, src);
+}
+
+static void tstb_imm(void)
+{
+ UINT32 src = (UINT16)OP;
+ UINT32 dst = IREG((OP >> 16) & 31);
+ TSTB(dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+#define XOR(dreg, src1, src2) \
+{ \
+ UINT32 _res = (src1) ^ (src2); \
+ IREG(dreg) = _res; \
+ if (dreg < 8) \
+ { \
+ CLR_NZVUF(); \
+ OR_NZ(_res); \
+ } \
+ else if (dreg >= TMR_BK) \
+ update_special(dreg); \
+}
+
+static void xor_reg(void)
+{
+ UINT32 src = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ XOR(dreg, dst, src);
+}
+
+static void xor_dir(void)
+{
+ UINT32 src = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ XOR(dreg, dst, src);
+}
+
+static void xor_ind(void)
+{
+ UINT32 src = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ XOR(dreg, dst, src);
+}
+
+static void xor_imm(void)
+{
+ UINT32 src = (UINT16)OP;
+ int dreg = (OP >> 16) & 31;
+ UINT32 dst = IREG(dreg);
+ XOR(dreg, dst, src);
+}
+
+/*-----------------------------------------------------*/
+
+static void iack_dir(void)
+{
+ offs_t addr = DIRECT();
+ if (tms32031.iack_w)
+ (*tms32031.iack_w)(ASSERT_LINE, addr);
+ RMEM(addr);
+ if (tms32031.iack_w)
+ (*tms32031.iack_w)(CLEAR_LINE, addr);
+}
+
+static void iack_ind(void)
+{
+ offs_t addr = INDIRECT_D(OP >> 8);
+ if (tms32031.iack_w)
+ (*tms32031.iack_w)(ASSERT_LINE, addr);
+ RMEM(addr);
+ if (tms32031.iack_w)
+ (*tms32031.iack_w)(CLEAR_LINE, addr);
+}
+
+/*-----------------------------------------------------*/
+
+static void addc3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ ADDC(dreg, src1, src2);
+}
+
+static void addc3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ ADDC(dreg, src1, src2);
+}
+
+static void addc3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ ADDC(dreg, src1, src2);
+}
+
+static void addc3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ ADDC(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void addf3_regreg(void)
+{
+ int sreg1 = (OP >> 8) & 7;
+ int sreg2 = OP & 7;
+ int dreg = (OP >> 16) & 7;
+ addf(&tms32031.r[dreg], &tms32031.r[sreg1], &tms32031.r[sreg2]);
+}
+
+static void addf3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ int sreg2 = OP & 7;
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, src1);
+ addf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1], &tms32031.r[sreg2]);
+}
+
+static void addf3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int sreg1 = (OP >> 8) & 7;
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP2, src2);
+ addf(&tms32031.r[dreg], &tms32031.r[sreg1], &tms32031.r[TMR_TEMP2]);
+}
+
+static void addf3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 7;
+ UPDATE_DEF();
+ LONG2FP(TMR_TEMP1, src1);
+ LONG2FP(TMR_TEMP2, src2);
+ addf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP2]);
+}
+
+/*-----------------------------------------------------*/
+
+static void addi3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ ADDI(dreg, src1, src2);
+}
+
+static void addi3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ ADDI(dreg, src1, src2);
+}
+
+static void addi3_regind(void)
+{
+ /* Radikal Bikers confirms via ADDI3 AR3,*AR3++(1),R2 / SUB $0001,R2 sequence */
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ ADDI(dreg, src1, src2);
+}
+
+static void addi3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ ADDI(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void and3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ AND(dreg, src1, src2);
+}
+
+static void and3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ AND(dreg, src1, src2);
+}
+
+static void and3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ AND(dreg, src1, src2);
+}
+
+static void and3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ AND(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void andn3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ ANDN(dreg, src1, src2);
+}
+
+static void andn3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ ANDN(dreg, src1, src2);
+}
+
+static void andn3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ ANDN(dreg, src1, src2);
+}
+
+static void andn3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ ANDN(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void ash3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ ASH(dreg, src1, src2);
+}
+
+static void ash3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ ASH(dreg, src1, src2);
+}
+
+static void ash3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ ASH(dreg, src1, src2);
+}
+
+static void ash3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ ASH(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void cmpf3_regreg(void)
+{
+ int sreg1 = (OP >> 8) & 7;
+ int sreg2 = OP & 7;
+ subf(&tms32031.r[TMR_TEMP1], &tms32031.r[sreg1], &tms32031.r[sreg2]);
+}
+
+static void cmpf3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ int sreg2 = OP & 7;
+ LONG2FP(TMR_TEMP1, src1);
+ subf(&tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP1], &tms32031.r[sreg2]);
+}
+
+static void cmpf3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int sreg1 = (OP >> 8) & 7;
+ LONG2FP(TMR_TEMP2, src2);
+ subf(&tms32031.r[TMR_TEMP1], &tms32031.r[sreg1], &tms32031.r[TMR_TEMP2]);
+}
+
+static void cmpf3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UPDATE_DEF();
+ LONG2FP(TMR_TEMP1, src1);
+ LONG2FP(TMR_TEMP2, src2);
+ subf(&tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP2]);
+}
+
+/*-----------------------------------------------------*/
+
+static void cmpi3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ CMPI(src1, src2);
+}
+
+static void cmpi3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ CMPI(src1, src2);
+}
+
+static void cmpi3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ CMPI(src1, src2);
+}
+
+static void cmpi3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UPDATE_DEF();
+ CMPI(src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void lsh3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ LSH(dreg, src1, src2);
+}
+
+static void lsh3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ LSH(dreg, src1, src2);
+}
+
+static void lsh3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ LSH(dreg, src1, src2);
+}
+
+static void lsh3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ LSH(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void mpyf3_regreg(void)
+{
+ int sreg1 = (OP >> 8) & 7;
+ int sreg2 = OP & 7;
+ int dreg = (OP >> 16) & 7;
+ mpyf(&tms32031.r[dreg], &tms32031.r[sreg1], &tms32031.r[sreg2]);
+}
+
+static void mpyf3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ int sreg2 = OP & 7;
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, src1);
+ mpyf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1], &tms32031.r[sreg2]);
+}
+
+static void mpyf3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int sreg1 = (OP >> 8) & 7;
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP2, src2);
+ mpyf(&tms32031.r[dreg], &tms32031.r[sreg1], &tms32031.r[TMR_TEMP2]);
+}
+
+static void mpyf3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 7;
+ UPDATE_DEF();
+ LONG2FP(TMR_TEMP1, src1);
+ LONG2FP(TMR_TEMP2, src2);
+ mpyf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP2]);
+}
+
+/*-----------------------------------------------------*/
+
+static void mpyi3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ MPYI(dreg, src1, src2);
+}
+
+static void mpyi3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ MPYI(dreg, src1, src2);
+}
+
+static void mpyi3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ MPYI(dreg, src1, src2);
+}
+
+static void mpyi3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ MPYI(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void or3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ OR(dreg, src1, src2);
+}
+
+static void or3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ OR(dreg, src1, src2);
+}
+
+static void or3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ OR(dreg, src1, src2);
+}
+
+static void or3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ OR(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void subb3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ SUBB(dreg, src1, src2);
+}
+
+static void subb3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ SUBB(dreg, src1, src2);
+}
+
+static void subb3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ SUBB(dreg, src1, src2);
+}
+
+static void subb3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ SUBB(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void subf3_regreg(void)
+{
+ int sreg1 = (OP >> 8) & 7;
+ int sreg2 = OP & 7;
+ int dreg = (OP >> 16) & 7;
+ subf(&tms32031.r[dreg], &tms32031.r[sreg1], &tms32031.r[sreg2]);
+}
+
+static void subf3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ int sreg2 = OP & 7;
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP1, src1);
+ subf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1], &tms32031.r[sreg2]);
+}
+
+static void subf3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int sreg1 = (OP >> 8) & 7;
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(TMR_TEMP2, src2);
+ subf(&tms32031.r[dreg], &tms32031.r[sreg1], &tms32031.r[TMR_TEMP2]);
+}
+
+static void subf3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 7;
+ UPDATE_DEF();
+ LONG2FP(TMR_TEMP1, src1);
+ LONG2FP(TMR_TEMP2, src2);
+ subf(&tms32031.r[dreg], &tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP2]);
+}
+
+/*-----------------------------------------------------*/
+
+static void subi3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ SUBI(dreg, src1, src2);
+}
+
+static void subi3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ SUBI(dreg, src1, src2);
+}
+
+static void subi3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ SUBI(dreg, src1, src2);
+}
+
+static void subi3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ SUBI(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void tstb3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ TSTB(src1, src2);
+}
+
+static void tstb3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ TSTB(src1, src2);
+}
+
+static void tstb3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ TSTB(src1, src2);
+}
+
+static void tstb3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UPDATE_DEF();
+ TSTB(src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void xor3_regreg(void)
+{
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ XOR(dreg, src1, src2);
+}
+
+static void xor3_indreg(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1(OP >> 8));
+ UINT32 src2 = IREG(OP & 31);
+ int dreg = (OP >> 16) & 31;
+ XOR(dreg, src1, src2);
+}
+
+static void xor3_regind(void)
+{
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ UINT32 src1 = IREG((OP >> 8) & 31);
+ int dreg = (OP >> 16) & 31;
+ XOR(dreg, src1, src2);
+}
+
+static void xor3_indind(void)
+{
+ UINT32 src1 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src2 = RMEM(INDIRECT_1(OP));
+ int dreg = (OP >> 16) & 31;
+ UPDATE_DEF();
+ XOR(dreg, src1, src2);
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfu_reg(void)
+{
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfu_dir(void)
+{
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+}
+
+static void ldfu_ind(void)
+{
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+}
+
+static void ldfu_imm(void)
+{
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+}
+
+/*-----------------------------------------------------*/
+
+static void ldflo_reg(void)
+{
+ if (CONDITION_LO)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldflo_dir(void)
+{
+ if (CONDITION_LO)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldflo_ind(void)
+{
+ if (CONDITION_LO)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldflo_imm(void)
+{
+ if (CONDITION_LO)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfls_reg(void)
+{
+ if (CONDITION_LS)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfls_dir(void)
+{
+ if (CONDITION_LS)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfls_ind(void)
+{
+ if (CONDITION_LS)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfls_imm(void)
+{
+ if (CONDITION_LS)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfhi_reg(void)
+{
+ if (CONDITION_HI)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfhi_dir(void)
+{
+ if (CONDITION_HI)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfhi_ind(void)
+{
+ if (CONDITION_HI)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfhi_imm(void)
+{
+ if (CONDITION_HI)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfhs_reg(void)
+{
+ if (CONDITION_HS)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfhs_dir(void)
+{
+ if (CONDITION_HS)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfhs_ind(void)
+{
+ if (CONDITION_HS)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfhs_imm(void)
+{
+ if (CONDITION_HS)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfeq_reg(void)
+{
+ if (CONDITION_EQ)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfeq_dir(void)
+{
+ if (CONDITION_EQ)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfeq_ind(void)
+{
+ if (CONDITION_EQ)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfeq_imm(void)
+{
+ if (CONDITION_EQ)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfne_reg(void)
+{
+ if (CONDITION_NE)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfne_dir(void)
+{
+ if (CONDITION_NE)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfne_ind(void)
+{
+ if (CONDITION_NE)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfne_imm(void)
+{
+ if (CONDITION_NE)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldflt_reg(void)
+{
+ if (CONDITION_LT)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldflt_dir(void)
+{
+ if (CONDITION_LT)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldflt_ind(void)
+{
+ if (CONDITION_LT)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldflt_imm(void)
+{
+ if (CONDITION_LT)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfle_reg(void)
+{
+ if (CONDITION_LE)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfle_dir(void)
+{
+ if (CONDITION_LE)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfle_ind(void)
+{
+ if (CONDITION_LE)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfle_imm(void)
+{
+ if (CONDITION_LE)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfgt_reg(void)
+{
+ if (CONDITION_GT)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfgt_dir(void)
+{
+ if (CONDITION_GT)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfgt_ind(void)
+{
+ if (CONDITION_GT)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfgt_imm(void)
+{
+ if (CONDITION_GT)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfge_reg(void)
+{
+ if (CONDITION_GE)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfge_dir(void)
+{
+ if (CONDITION_GE)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfge_ind(void)
+{
+ if (CONDITION_GE)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfge_imm(void)
+{
+ if (CONDITION_GE)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfnv_reg(void)
+{
+ if (CONDITION_NV)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfnv_dir(void)
+{
+ if (CONDITION_NV)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfnv_ind(void)
+{
+ if (CONDITION_NV)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfnv_imm(void)
+{
+ if (CONDITION_NV)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfv_reg(void)
+{
+ if (CONDITION_V)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfv_dir(void)
+{
+ if (CONDITION_V)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfv_ind(void)
+{
+ if (CONDITION_V)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfv_imm(void)
+{
+ if (CONDITION_V)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfnuf_reg(void)
+{
+ if (CONDITION_NUF)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfnuf_dir(void)
+{
+ if (CONDITION_NUF)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfnuf_ind(void)
+{
+ if (CONDITION_NUF)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfnuf_imm(void)
+{
+ if (CONDITION_NUF)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfuf_reg(void)
+{
+ if (CONDITION_UF)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfuf_dir(void)
+{
+ if (CONDITION_UF)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfuf_ind(void)
+{
+ if (CONDITION_UF)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfuf_imm(void)
+{
+ if (CONDITION_UF)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfnlv_reg(void)
+{
+ if (CONDITION_NLV)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfnlv_dir(void)
+{
+ if (CONDITION_NLV)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfnlv_ind(void)
+{
+ if (CONDITION_NLV)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfnlv_imm(void)
+{
+ if (CONDITION_NLV)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldflv_reg(void)
+{
+ if (CONDITION_LV)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldflv_dir(void)
+{
+ if (CONDITION_LV)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldflv_ind(void)
+{
+ if (CONDITION_LV)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldflv_imm(void)
+{
+ if (CONDITION_LV)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfnluf_reg(void)
+{
+ if (CONDITION_NLUF)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfnluf_dir(void)
+{
+ if (CONDITION_NLUF)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfnluf_ind(void)
+{
+ if (CONDITION_NLUF)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfnluf_imm(void)
+{
+ if (CONDITION_NLUF)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfluf_reg(void)
+{
+ if (CONDITION_LUF)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfluf_dir(void)
+{
+ if (CONDITION_LUF)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfluf_ind(void)
+{
+ if (CONDITION_LUF)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfluf_imm(void)
+{
+ if (CONDITION_LUF)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfzuf_reg(void)
+{
+ if (CONDITION_ZUF)
+ tms32031.r[(OP >> 16) & 7] = tms32031.r[OP & 7];
+}
+
+static void ldfzuf_dir(void)
+{
+ if (CONDITION_ZUF)
+ {
+ UINT32 res = RMEM(DIRECT());
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+}
+
+static void ldfzuf_ind(void)
+{
+ if (CONDITION_ZUF)
+ {
+ UINT32 res = RMEM(INDIRECT_D(OP >> 8));
+ int dreg = (OP >> 16) & 7;
+ LONG2FP(dreg, res);
+ }
+ else
+ INDIRECT_D(OP >> 8);
+}
+
+static void ldfzuf_imm(void)
+{
+ if (CONDITION_ZUF)
+ {
+ int dreg = (OP >> 16) & 7;
+ SHORT2FP(dreg, OP);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldiu_reg(void)
+{
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+}
+
+static void ldiu_dir(void)
+{
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = RMEM(DIRECT());
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+}
+
+static void ldiu_ind(void)
+{
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = RMEM(INDIRECT_D(OP >> 8));
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+}
+
+static void ldiu_imm(void)
+{
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+}
+
+/*-----------------------------------------------------*/
+
+static void ldilo_reg(void)
+{
+ if (CONDITION_LO)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldilo_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_LO)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldilo_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_LO)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldilo_imm(void)
+{
+ if (CONDITION_LO)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldils_reg(void)
+{
+ if (CONDITION_LS)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldils_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_LS)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldils_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_LS)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldils_imm(void)
+{
+ if (CONDITION_LS)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldihi_reg(void)
+{
+ if (CONDITION_HI)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldihi_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_HI)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldihi_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_HI)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldihi_imm(void)
+{
+ if (CONDITION_HI)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldihs_reg(void)
+{
+ if (CONDITION_HS)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldihs_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_HS)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldihs_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_HS)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldihs_imm(void)
+{
+ if (CONDITION_HS)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldieq_reg(void)
+{
+ if (CONDITION_EQ)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldieq_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_EQ)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldieq_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_EQ)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldieq_imm(void)
+{
+ if (CONDITION_EQ)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldine_reg(void)
+{
+ if (CONDITION_NE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldine_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_NE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldine_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_NE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldine_imm(void)
+{
+ if (CONDITION_NE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldilt_reg(void)
+{
+ if (CONDITION_LT)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldilt_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_LT)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldilt_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_LT)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldilt_imm(void)
+{
+ if (CONDITION_LT)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldile_reg(void)
+{
+ if (CONDITION_LE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldile_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_LE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldile_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_LE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldile_imm(void)
+{
+ if (CONDITION_LE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldigt_reg(void)
+{
+ if (CONDITION_GT)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldigt_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_GT)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldigt_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_GT)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldigt_imm(void)
+{
+ if (CONDITION_GT)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldige_reg(void)
+{
+ if (CONDITION_GE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldige_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_GE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldige_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_GE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldige_imm(void)
+{
+ if (CONDITION_GE)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldinv_reg(void)
+{
+ if (CONDITION_NV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinv_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_NV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinv_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_NV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinv_imm(void)
+{
+ if (CONDITION_NV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldiuf_reg(void)
+{
+ if (CONDITION_UF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldiuf_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_UF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldiuf_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_UF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldiuf_imm(void)
+{
+ if (CONDITION_UF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldinuf_reg(void)
+{
+ if (CONDITION_NUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinuf_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_NUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinuf_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_NUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinuf_imm(void)
+{
+ if (CONDITION_NUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldiv_reg(void)
+{
+ if (CONDITION_V)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldiv_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_V)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldiv_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_V)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldiv_imm(void)
+{
+ if (CONDITION_V)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldinlv_reg(void)
+{
+ if (CONDITION_NLV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinlv_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_NLV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinlv_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_NLV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinlv_imm(void)
+{
+ if (CONDITION_NLV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldilv_reg(void)
+{
+ if (CONDITION_LV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldilv_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_LV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldilv_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_LV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldilv_imm(void)
+{
+ if (CONDITION_LV)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldinluf_reg(void)
+{
+ if (CONDITION_NLUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinluf_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_NLUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinluf_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_NLUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldinluf_imm(void)
+{
+ if (CONDITION_NLUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldiluf_reg(void)
+{
+ if (CONDITION_LUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldiluf_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_LUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldiluf_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_LUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldiluf_imm(void)
+{
+ if (CONDITION_LUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void ldizuf_reg(void)
+{
+ if (CONDITION_ZUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = IREG(OP & 31);
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldizuf_dir(void)
+{
+ UINT32 val = RMEM(DIRECT());
+ if (CONDITION_ZUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldizuf_ind(void)
+{
+ UINT32 val = RMEM(INDIRECT_D(OP >> 8));
+ if (CONDITION_ZUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = val;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+static void ldizuf_imm(void)
+{
+ if (CONDITION_ZUF)
+ {
+ int dreg = (OP >> 16) & 31;
+ IREG(dreg) = (INT16)OP;
+ if (dreg >= TMR_BK)
+ update_special(dreg);
+ }
+}
+
+/*-----------------------------------------------------*/
+
+INLINE void execute_delayed(UINT32 newpc)
+{
+ tms32031.delayed = 1;
+
+ execute_one();
+ execute_one();
+ execute_one();
+
+ tms32031.pc = newpc;
+ UPDATEPC(tms32031.pc);
+
+ tms32031.delayed = 0;
+ if (tms32031.irq_pending)
+ {
+ tms32031.irq_pending = 0;
+ check_irqs();
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void br_imm(void)
+{
+ tms32031.pc = OP & 0xffffff;
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 3*2;
+}
+
+static void brd_imm(void)
+{
+ execute_delayed(OP & 0xffffff);
+}
+
+/*-----------------------------------------------------*/
+
+static void call_imm(void)
+{
+ WMEM(++IREG(TMR_SP), tms32031.pc);
+ tms32031.pc = OP & 0xffffff;
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 3*2;
+}
+
+/*-----------------------------------------------------*/
+
+static void rptb_imm(void)
+{
+ IREG(TMR_RS) = tms32031.pc;
+ IREG(TMR_RE) = OP & 0xffffff;
+ IREG(TMR_ST) |= RMFLAG;
+ tms32031_icount -= 3*2;
+}
+
+/*-----------------------------------------------------*/
+
+static void swi(void) { unimplemented(); }
+
+/*-----------------------------------------------------*/
+
+static void brc_reg(void)
+{
+ if (condition(OP >> 16))
+ {
+ tms32031.pc = IREG(OP & 31);
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 3*2;
+ }
+}
+
+static void brcd_reg(void)
+{
+ if (condition(OP >> 16))
+ execute_delayed(IREG(OP & 31));
+}
+
+static void brc_imm(void)
+{
+ if (condition(OP >> 16))
+ {
+ tms32031.pc += (INT16)OP;
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 3*2;
+ }
+}
+
+static void brcd_imm(void)
+{
+ if (condition(OP >> 16))
+ execute_delayed(tms32031.pc + 2 + (INT16)OP);
+}
+
+/*-----------------------------------------------------*/
+
+static void dbc_reg(void)
+{
+ int reg = TMR_AR0 + ((OP >> 22) & 7);
+ int res = (IREG(reg) - 1) & 0xffffff;
+ IREG(reg) = res | (IREG(reg) & 0xff000000);
+ if (condition(OP >> 16) && !(res & 0x800000))
+ {
+ tms32031.pc = IREG(OP & 31);
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 3*2;
+ }
+}
+
+static void dbcd_reg(void)
+{
+ int reg = TMR_AR0 + ((OP >> 22) & 7);
+ int res = (IREG(reg) - 1) & 0xffffff;
+ IREG(reg) = res | (IREG(reg) & 0xff000000);
+ if (condition(OP >> 16) && !(res & 0x800000))
+ execute_delayed(IREG(OP & 31));
+}
+
+static void dbc_imm(void)
+{
+ int reg = TMR_AR0 + ((OP >> 22) & 7);
+ int res = (IREG(reg) - 1) & 0xffffff;
+ IREG(reg) = res | (IREG(reg) & 0xff000000);
+ if (condition(OP >> 16) && !(res & 0x800000))
+ {
+ tms32031.pc += (INT16)OP;
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 3*2;
+ }
+}
+
+static void dbcd_imm(void)
+{
+ int reg = TMR_AR0 + ((OP >> 22) & 7);
+ int res = (IREG(reg) - 1) & 0xffffff;
+ IREG(reg) = res | (IREG(reg) & 0xff000000);
+ if (condition(OP >> 16) && !(res & 0x800000))
+ execute_delayed(tms32031.pc + 2 + (INT16)OP);
+}
+
+/*-----------------------------------------------------*/
+
+static void callc_reg(void)
+{
+ if (condition(OP >> 16))
+ {
+ WMEM(++IREG(TMR_SP), tms32031.pc);
+ tms32031.pc = IREG(OP & 31);
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 3*2;
+ }
+}
+
+static void callc_imm(void)
+{
+ if (condition(OP >> 16))
+ {
+ WMEM(++IREG(TMR_SP), tms32031.pc);
+ tms32031.pc += (INT16)OP;
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 3*2;
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void trap(int trapnum)
+{
+ WMEM(++IREG(TMR_SP), tms32031.pc);
+ IREG(TMR_ST) &= ~GIEFLAG;
+ tms32031.pc = tms32031.mcu_mode ? (0x809fc0 + trapnum) : RMEM(trapnum);
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 4*2;
+}
+
+static void trapc(void)
+{
+ if (condition(OP >> 16))
+ trap(OP & 0x3f);
+}
+
+/*-----------------------------------------------------*/
+
+static void retic_reg(void)
+{
+ if (condition(OP >> 16))
+ {
+ tms32031.pc = RMEM(IREG(TMR_SP)--);
+ UPDATEPC(tms32031.pc);
+ IREG(TMR_ST) |= GIEFLAG;
+ tms32031_icount -= 3*2;
+ }
+}
+
+static void retsc_reg(void)
+{
+ if (condition(OP >> 16))
+ {
+ tms32031.pc = RMEM(IREG(TMR_SP)--);
+ UPDATEPC(tms32031.pc);
+ tms32031_icount -= 3*2;
+ }
+}
+
+/*-----------------------------------------------------*/
+
+static void mpyaddf_0(void)
+{
+ /* src3 * src4, src1 + src2 */
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ LONG2FP(TMR_TEMP1, src3);
+ LONG2FP(TMR_TEMP2, src4);
+ mpyf(&tms32031.r[TMR_TEMP3], &tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP2]);
+ addf(&tms32031.r[((OP >> 22) & 1) | 2], &tms32031.r[(OP >> 19) & 7], &tms32031.r[(OP >> 16) & 7]);
+ tms32031.r[(OP >> 23) & 1] = tms32031.r[TMR_TEMP3];
+ UPDATE_DEF();
+}
+
+static void mpyaddf_1(void)
+{
+ /* src3 * src1, src4 + src2 */
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ LONG2FP(TMR_TEMP1, src3);
+ LONG2FP(TMR_TEMP2, src4);
+ mpyf(&tms32031.r[TMR_TEMP3], &tms32031.r[TMR_TEMP1], &tms32031.r[(OP >> 19) & 7]);
+ addf(&tms32031.r[((OP >> 22) & 1) | 2], &tms32031.r[TMR_TEMP2], &tms32031.r[(OP >> 16) & 7]);
+ tms32031.r[(OP >> 23) & 1] = tms32031.r[TMR_TEMP3];
+ UPDATE_DEF();
+}
+
+static void mpyaddf_2(void)
+{
+ /* src1 * src2, src3 + src4 */
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ LONG2FP(TMR_TEMP1, src3);
+ LONG2FP(TMR_TEMP2, src4);
+ mpyf(&tms32031.r[TMR_TEMP3], &tms32031.r[(OP >> 19) & 7], &tms32031.r[(OP >> 16) & 7]);
+ addf(&tms32031.r[((OP >> 22) & 1) | 2], &tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP2]);
+ tms32031.r[(OP >> 23) & 1] = tms32031.r[TMR_TEMP3];
+ UPDATE_DEF();
+}
+
+static void mpyaddf_3(void)
+{
+ /* src3 * src1, src2 + src4 */
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ LONG2FP(TMR_TEMP1, src3);
+ LONG2FP(TMR_TEMP2, src4);
+ mpyf(&tms32031.r[TMR_TEMP3], &tms32031.r[TMR_TEMP1], &tms32031.r[(OP >> 19) & 7]);
+ addf(&tms32031.r[((OP >> 22) & 1) | 2], &tms32031.r[(OP >> 16) & 7], &tms32031.r[TMR_TEMP2]);
+ tms32031.r[(OP >> 23) & 1] = tms32031.r[TMR_TEMP3];
+ UPDATE_DEF();
+}
+
+/*-----------------------------------------------------*/
+
+static void mpysubf_0(void)
+{
+ /* src3 * src4, src1 - src2 */
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ LONG2FP(TMR_TEMP1, src3);
+ LONG2FP(TMR_TEMP2, src4);
+ mpyf(&tms32031.r[TMR_TEMP3], &tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP2]);
+ subf(&tms32031.r[((OP >> 22) & 1) | 2], &tms32031.r[(OP >> 19) & 7], &tms32031.r[(OP >> 16) & 7]);
+ tms32031.r[(OP >> 23) & 1] = tms32031.r[TMR_TEMP3];
+ UPDATE_DEF();
+}
+
+static void mpysubf_1(void)
+{
+ /* src3 * src1, src4 - src2 */
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ LONG2FP(TMR_TEMP1, src3);
+ LONG2FP(TMR_TEMP2, src4);
+ mpyf(&tms32031.r[TMR_TEMP3], &tms32031.r[TMR_TEMP1], &tms32031.r[(OP >> 19) & 7]);
+ subf(&tms32031.r[((OP >> 22) & 1) | 2], &tms32031.r[TMR_TEMP2], &tms32031.r[(OP >> 16) & 7]);
+ tms32031.r[(OP >> 23) & 1] = tms32031.r[TMR_TEMP3];
+ UPDATE_DEF();
+}
+
+static void mpysubf_2(void)
+{
+ /* src1 * src2, src3 - src4 */
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ LONG2FP(TMR_TEMP1, src3);
+ LONG2FP(TMR_TEMP2, src4);
+ mpyf(&tms32031.r[TMR_TEMP3], &tms32031.r[(OP >> 19) & 7], &tms32031.r[(OP >> 16) & 7]);
+ subf(&tms32031.r[((OP >> 22) & 1) | 2], &tms32031.r[TMR_TEMP1], &tms32031.r[TMR_TEMP2]);
+ tms32031.r[(OP >> 23) & 1] = tms32031.r[TMR_TEMP3];
+ UPDATE_DEF();
+}
+
+static void mpysubf_3(void)
+{
+ /* src3 * src1, src2 - src4 */
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ LONG2FP(TMR_TEMP1, src3);
+ LONG2FP(TMR_TEMP2, src4);
+ mpyf(&tms32031.r[TMR_TEMP3], &tms32031.r[TMR_TEMP1], &tms32031.r[(OP >> 19) & 7]);
+ subf(&tms32031.r[((OP >> 22) & 1) | 2], &tms32031.r[(OP >> 16) & 7], &tms32031.r[TMR_TEMP2]);
+ tms32031.r[(OP >> 23) & 1] = tms32031.r[TMR_TEMP3];
+ UPDATE_DEF();
+}
+
+/*-----------------------------------------------------*/
+
+static void mpyaddi_0(void)
+{
+ /* src3 * src4, src1 + src2 */
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ UINT32 src2 = IREG((OP >> 16) & 7);
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src4 << 8) >> 8);
+ UINT32 ares = src1 + src2;
+
+ CLR_NZVUF();
+ if (OVM)
+ {
+ if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff)
+ mres = (mres < 0) ? 0x80000000 : 0x7fffffff;
+ if (OVERFLOW_ADD(src1,src2,ares))
+ ares = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ IREG((OP >> 23) & 1) = mres;
+ IREG(((OP >> 22) & 1) | 2) = ares;
+ UPDATE_DEF();
+}
+
+static void mpyaddi_1(void)
+{
+ /* src3 * src1, src4 + src2 */
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ UINT32 src2 = IREG((OP >> 16) & 7);
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src1 << 8) >> 8);
+ UINT32 ares = src4 + src2;
+
+ CLR_NZVUF();
+ if (OVM)
+ {
+ if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff)
+ mres = (mres < 0) ? 0x80000000 : 0x7fffffff;
+ if (OVERFLOW_ADD(src4,src2,ares))
+ ares = ((INT32)src4 < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ IREG((OP >> 23) & 1) = mres;
+ IREG(((OP >> 22) & 1) | 2) = ares;
+ UPDATE_DEF();
+}
+
+static void mpyaddi_2(void)
+{
+ /* src1 * src2, src3 + src4 */
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ UINT32 src2 = IREG((OP >> 16) & 7);
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ INT64 mres = (INT64)((INT32)(src1 << 8) >> 8) * (INT64)((INT32)(src2 << 8) >> 8);
+ UINT32 ares = src3 + src4;
+
+ CLR_NZVUF();
+ if (OVM)
+ {
+ if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff)
+ mres = (mres < 0) ? 0x80000000 : 0x7fffffff;
+ if (OVERFLOW_ADD(src3,src4,ares))
+ ares = ((INT32)src3 < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ IREG((OP >> 23) & 1) = mres;
+ IREG(((OP >> 22) & 1) | 2) = ares;
+ UPDATE_DEF();
+}
+
+static void mpyaddi_3(void)
+{
+ /* src3 * src1, src2 + src4 */
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ UINT32 src2 = IREG((OP >> 16) & 7);
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src1 << 8) >> 8);
+ UINT32 ares = src2 + src4;
+
+ CLR_NZVUF();
+ if (OVM)
+ {
+ if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff)
+ mres = (mres < 0) ? 0x80000000 : 0x7fffffff;
+ if (OVERFLOW_ADD(src2,src4,ares))
+ ares = ((INT32)src2 < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ IREG((OP >> 23) & 1) = mres;
+ IREG(((OP >> 22) & 1) | 2) = ares;
+ UPDATE_DEF();
+}
+
+/*-----------------------------------------------------*/
+
+static void mpysubi_0(void)
+{
+ /* src3 * src4, src1 - src2 */
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ UINT32 src2 = IREG((OP >> 16) & 7);
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src4 << 8) >> 8);
+ UINT32 ares = src1 - src2;
+
+ CLR_NZVUF();
+ if (OVM)
+ {
+ if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff)
+ mres = (mres < 0) ? 0x80000000 : 0x7fffffff;
+ if (OVERFLOW_SUB(src1,src2,ares))
+ ares = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ IREG((OP >> 23) & 1) = mres;
+ IREG(((OP >> 22) & 1) | 2) = ares;
+ UPDATE_DEF();
+}
+
+static void mpysubi_1(void)
+{
+ /* src3 * src1, src4 - src2 */
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ UINT32 src2 = IREG((OP >> 16) & 7);
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src1 << 8) >> 8);
+ UINT32 ares = src4 - src2;
+
+ CLR_NZVUF();
+ if (OVM)
+ {
+ if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff)
+ mres = (mres < 0) ? 0x80000000 : 0x7fffffff;
+ if (OVERFLOW_SUB(src4,src2,ares))
+ ares = ((INT32)src4 < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ IREG((OP >> 23) & 1) = mres;
+ IREG(((OP >> 22) & 1) | 2) = ares;
+ UPDATE_DEF();
+}
+
+static void mpysubi_2(void)
+{
+ /* src1 * src2, src3 - src4 */
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ UINT32 src2 = IREG((OP >> 16) & 7);
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ INT64 mres = (INT64)((INT32)(src1 << 8) >> 8) * (INT64)((INT32)(src2 << 8) >> 8);
+ UINT32 ares = src3 - src4;
+
+ CLR_NZVUF();
+ if (OVM)
+ {
+ if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff)
+ mres = (mres < 0) ? 0x80000000 : 0x7fffffff;
+ if (OVERFLOW_SUB(src3,src4,ares))
+ ares = ((INT32)src3 < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ IREG((OP >> 23) & 1) = mres;
+ IREG(((OP >> 22) & 1) | 2) = ares;
+ UPDATE_DEF();
+}
+
+static void mpysubi_3(void)
+{
+ /* src3 * src1, src2 - src4 */
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ UINT32 src2 = IREG((OP >> 16) & 7);
+ UINT32 src3 = RMEM(INDIRECT_1_DEF(OP >> 8));
+ UINT32 src4 = RMEM(INDIRECT_1(OP));
+ INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src1 << 8) >> 8);
+ UINT32 ares = src2 - src4;
+
+ CLR_NZVUF();
+ if (OVM)
+ {
+ if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff)
+ mres = (mres < 0) ? 0x80000000 : 0x7fffffff;
+ if (OVERFLOW_SUB(src2,src4,ares))
+ ares = ((INT32)src2 < 0) ? 0x80000000 : 0x7fffffff;
+ }
+ IREG((OP >> 23) & 1) = mres;
+ IREG(((OP >> 22) & 1) | 2) = ares;
+ UPDATE_DEF();
+}
+
+/*-----------------------------------------------------*/
+
+static void stfstf(void)
+{
+ WMEM(INDIRECT_1_DEF(OP >> 8), FP2LONG((OP >> 16) & 7));
+ WMEM(INDIRECT_1(OP), FP2LONG((OP >> 22) & 7));
+ UPDATE_DEF();
+}
+
+static void stisti(void)
+{
+ WMEM(INDIRECT_1_DEF(OP >> 8), IREG((OP >> 16) & 7));
+ WMEM(INDIRECT_1(OP), IREG((OP >> 22) & 7));
+ UPDATE_DEF();
+}
+
+/*-----------------------------------------------------*/
+
+static void ldfldf(void)
+{
+ UINT32 res;
+ int dreg;
+
+ res = RMEM(INDIRECT_1_DEF(OP >> 8));
+ dreg = (OP >> 19) & 7;
+ LONG2FP(dreg, res);
+ res = RMEM(INDIRECT_1(OP));
+ dreg = (OP >> 22) & 7;
+ LONG2FP(dreg, res);
+ UPDATE_DEF();
+}
+
+static void ldildi(void)
+{
+ IREG((OP >> 19) & 7) = RMEM(INDIRECT_1_DEF(OP >> 8));
+ IREG((OP >> 22) & 7) = RMEM(INDIRECT_1(OP));
+ UPDATE_DEF();
+}
+
+/*-----------------------------------------------------*/
+
+// src2 = ind(OP)
+// dst2 = ind(OP >> 8)
+// sreg3 = ((OP >> 16) & 7)
+// sreg1 = ((OP >> 19) & 7)
+// dreg1 = ((OP >> 22) & 7)
+
+static void absfstf(void)
+{
+ UINT32 src3 = FP2LONG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ LONG2FP(TMR_TEMP1, src2);
+ ABSF(dreg, TMR_TEMP1);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void absisti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ ABSI(dreg, src2);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void addf3stf(void)
+{
+ UINT32 src3 = FP2LONG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ LONG2FP(TMR_TEMP1, src2);
+ addf(&tms32031.r[(OP >> 22) & 7], &tms32031.r[(OP >> 19) & 7], &tms32031.r[TMR_TEMP1]);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void addi3sti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ ADDI(dreg, src1, src2);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void and3sti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ AND(dreg, src1, src2);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void ash3sti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ UINT32 count = IREG((OP >> 19) & 7);
+ ASH(dreg, src2, count);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void fixsti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ LONG2FP(dreg, src2);
+ float2int(&tms32031.r[dreg], 1);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void floatstf(void)
+{
+ UINT32 src3 = FP2LONG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ IREG(dreg) = src2;
+ int2float(&tms32031.r[dreg]);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void ldfstf(void)
+{
+ UINT32 src3 = FP2LONG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ LONG2FP(dreg, src2);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void ldisti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ IREG((OP >> 22) & 7) = src2;
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void lsh3sti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ UINT32 count = IREG((OP >> 19) & 7);
+ LSH(dreg, src2, count);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void mpyf3stf(void)
+{
+ UINT32 src3 = FP2LONG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ LONG2FP(TMR_TEMP1, src2);
+ mpyf(&tms32031.r[(OP >> 22) & 7], &tms32031.r[(OP >> 19) & 7], &tms32031.r[TMR_TEMP1]);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void mpyi3sti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ MPYI(dreg, src1, src2);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void negfstf(void)
+{
+ UINT32 src3 = FP2LONG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ LONG2FP(TMR_TEMP1, src2);
+ negf(&tms32031.r[(OP >> 22) & 7], &tms32031.r[TMR_TEMP1]);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void negisti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ NEGI(dreg, src2);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void notsti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ NOT(dreg, src2);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void or3sti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ OR(dreg, src1, src2);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void subf3stf(void)
+{
+ UINT32 src3 = FP2LONG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ LONG2FP(TMR_TEMP1, src2);
+ subf(&tms32031.r[(OP >> 22) & 7], &tms32031.r[TMR_TEMP1], &tms32031.r[(OP >> 19) & 7]);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void subi3sti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ SUBI(dreg, src2, src1);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+static void xor3sti(void)
+{
+ UINT32 src3 = IREG((OP >> 16) & 7);
+ UINT32 src2 = RMEM(INDIRECT_1_DEF(OP));
+ {
+ int dreg = (OP >> 22) & 7;
+ UINT32 src1 = IREG((OP >> 19) & 7);
+ XOR(dreg, src1, src2);
+ }
+ WMEM(INDIRECT_1(OP >> 8), src3);
+ UPDATE_DEF();
+}
+
+
+/***************************************************************************
+ FUNCTION TABLE
+***************************************************************************/
+
+void (*tms32031ops[])(void) =
+{
+ absf_reg, absf_dir, absf_ind, absf_imm, /* 0x00 */
+ absi_reg, absi_dir, absi_ind, absi_imm,
+ addc_reg, addc_dir, addc_ind, addc_imm,
+ addf_reg, addf_dir, addf_ind, addf_imm,
+ addi_reg, addi_dir, addi_ind, addi_imm,
+ and_reg, and_dir, and_ind, and_imm,
+ andn_reg, andn_dir, andn_ind, andn_imm,
+ ash_reg, ash_dir, ash_ind, ash_imm,
+ cmpf_reg, cmpf_dir, cmpf_ind, cmpf_imm, /* 0x08 */
+ cmpi_reg, cmpi_dir, cmpi_ind, cmpi_imm,
+ fix_reg, fix_dir, fix_ind, fix_imm,
+ float_reg, float_dir, float_ind, float_imm,
+ idle, idle, idle, idle,
+ lde_reg, lde_dir, lde_ind, lde_imm,
+ ldf_reg, ldf_dir, ldf_ind, ldf_imm,
+ illegal, ldfi_dir, ldfi_ind, illegal,
+ ldi_reg, ldi_dir, ldi_ind, ldi_imm, /* 0x10 */
+ illegal, ldii_dir, ldii_ind, illegal,
+ ldm_reg, ldm_dir, ldm_ind, ldm_imm,
+ lsh_reg, lsh_dir, lsh_ind, lsh_imm,
+ mpyf_reg, mpyf_dir, mpyf_ind, mpyf_imm,
+ mpyi_reg, mpyi_dir, mpyi_ind, mpyi_imm,
+ negb_reg, negb_dir, negb_ind, negb_imm,
+ negf_reg, negf_dir, negf_ind, negf_imm,
+ negi_reg, negi_dir, negi_ind, negi_imm, /* 0x18 */
+ nop_reg, illegal, nop_ind, illegal,
+ norm_reg, norm_dir, norm_ind, norm_imm,
+ not_reg, not_dir, not_ind, not_imm,
+ illegal, pop, illegal, illegal,
+ illegal, popf, illegal, illegal,
+ illegal, push, illegal, illegal,
+ illegal, pushf, illegal, illegal,
+ or_reg, or_dir, or_ind, or_imm, /* 0x20 */
+ maxspeed, maxspeed, maxspeed, maxspeed,
+ rnd_reg, rnd_dir, rnd_ind, rnd_imm,
+ illegal, illegal, illegal, rol,
+ illegal, illegal, illegal, rolc,
+ illegal, illegal, illegal, ror,
+ illegal, illegal, illegal, rorc,
+ rtps_reg, rtps_dir, rtps_ind, rtps_imm,
+ illegal, stf_dir, stf_ind, illegal, /* 0x28 */
+ illegal, stfi_dir, stfi_ind, illegal,
+ illegal, sti_dir, sti_ind, illegal,
+ illegal, stii_dir, stii_ind, illegal,
+ sigi, illegal, illegal, illegal,
+ subb_reg, subb_dir, subb_ind, subb_imm,
+ subc_reg, subc_dir, subc_ind, subc_imm,
+ subf_reg, subf_dir, subf_ind, subf_imm,
+ subi_reg, subi_dir, subi_ind, subi_imm, /* 0x30 */
+ subrb_reg, subrb_dir, subrb_ind, subrb_imm,
+ subrf_reg, subrf_dir, subrf_ind, subrf_imm,
+ subri_reg, subri_dir, subri_ind, subri_imm,
+ tstb_reg, tstb_dir, tstb_ind, tstb_imm,
+ xor_reg, xor_dir, xor_ind, xor_imm,
+ illegal, iack_dir, iack_ind, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x38 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+
+ addc3_regreg, addc3_indreg, addc3_regind, addc3_indind, /* 0x40 */
+ addf3_regreg, addf3_indreg, addf3_regind, addf3_indind,
+ addi3_regreg, addi3_indreg, addi3_regind, addi3_indind,
+ and3_regreg, and3_indreg, and3_regind, and3_indind,
+ andn3_regreg, andn3_indreg, andn3_regind, andn3_indind,
+ ash3_regreg, ash3_indreg, ash3_regind, ash3_indind,
+ cmpf3_regreg, cmpf3_indreg, cmpf3_regind, cmpf3_indind,
+ cmpi3_regreg, cmpi3_indreg, cmpi3_regind, cmpi3_indind,
+ lsh3_regreg, lsh3_indreg, lsh3_regind, lsh3_indind, /* 0x48 */
+ mpyf3_regreg, mpyf3_indreg, mpyf3_regind, mpyf3_indind,
+ mpyi3_regreg, mpyi3_indreg, mpyi3_regind, mpyi3_indind,
+ or3_regreg, or3_indreg, or3_regind, or3_indind,
+ subb3_regreg, subb3_indreg, subb3_regind, subb3_indind,
+ subf3_regreg, subf3_indreg, subf3_regind, subf3_indind,
+ subi3_regreg, subi3_indreg, subi3_regind, subi3_indind,
+ tstb3_regreg, tstb3_indreg, tstb3_regind, tstb3_indind,
+ xor3_regreg, xor3_indreg, xor3_regind, xor3_indind, /* 0x50 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x58 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x60 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x68 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x70 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x78 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+
+ ldfu_reg, ldfu_dir, ldfu_ind, ldfu_imm, /* 0x80 */
+ ldflo_reg, ldflo_dir, ldflo_ind, ldflo_imm,
+ ldfls_reg, ldfls_dir, ldfls_ind, ldfls_imm,
+ ldfhi_reg, ldfhi_dir, ldfhi_ind, ldfhi_imm,
+ ldfhs_reg, ldfhs_dir, ldfhs_ind, ldfhs_imm,
+ ldfeq_reg, ldfeq_dir, ldfeq_ind, ldfeq_imm,
+ ldfne_reg, ldfne_dir, ldfne_ind, ldfne_imm,
+ ldflt_reg, ldflt_dir, ldflt_ind, ldflt_imm,
+ ldfle_reg, ldfle_dir, ldfle_ind, ldfle_imm, /* 0x88 */
+ ldfgt_reg, ldfgt_dir, ldfgt_ind, ldfgt_imm,
+ ldfge_reg, ldfge_dir, ldfge_ind, ldfge_imm,
+ illegal, illegal, illegal, illegal,
+ ldfnv_reg, ldfnv_dir, ldfnv_ind, ldfnv_imm,
+ ldfv_reg, ldfv_dir, ldfv_ind, ldfv_imm,
+ ldfnuf_reg, ldfnuf_dir, ldfnuf_ind, ldfnuf_imm,
+ ldfuf_reg, ldfuf_dir, ldfuf_ind, ldfuf_imm,
+ ldfnlv_reg, ldfnlv_dir, ldfnlv_ind, ldfnlv_imm, /* 0x90 */
+ ldflv_reg, ldflv_dir, ldflv_ind, ldflv_imm,
+ ldfnluf_reg, ldfnluf_dir, ldfnluf_ind, ldfnluf_imm,
+ ldfluf_reg, ldfluf_dir, ldfluf_ind, ldfluf_imm,
+ ldfzuf_reg, ldfzuf_dir, ldfzuf_ind, ldfzuf_imm,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x98 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ ldiu_reg, ldiu_dir, ldiu_ind, ldiu_imm, /* 0xa0 */
+ ldilo_reg, ldilo_dir, ldilo_ind, ldilo_imm,
+ ldils_reg, ldils_dir, ldils_ind, ldils_imm,
+ ldihi_reg, ldihi_dir, ldihi_ind, ldihi_imm,
+ ldihs_reg, ldihs_dir, ldihs_ind, ldihs_imm,
+ ldieq_reg, ldieq_dir, ldieq_ind, ldieq_imm,
+ ldine_reg, ldine_dir, ldine_ind, ldine_imm,
+ ldilt_reg, ldilt_dir, ldilt_ind, ldilt_imm,
+ ldile_reg, ldile_dir, ldile_ind, ldile_imm, /* 0xa8 */
+ ldigt_reg, ldigt_dir, ldigt_ind, ldigt_imm,
+ ldige_reg, ldige_dir, ldige_ind, ldige_imm,
+ illegal, illegal, illegal, illegal,
+ ldinv_reg, ldinv_dir, ldinv_ind, ldinv_imm,
+ ldiv_reg, ldiv_dir, ldiv_ind, ldiv_imm,
+ ldinuf_reg, ldinuf_dir, ldinuf_ind, ldinuf_imm,
+ ldiuf_reg, ldiuf_dir, ldiuf_ind, ldiuf_imm,
+ ldinlv_reg, ldinlv_dir, ldinlv_ind, ldinlv_imm, /* 0xb0 */
+ ldilv_reg, ldilv_dir, ldilv_ind, ldilv_imm,
+ ldinluf_reg, ldinluf_dir, ldinluf_ind, ldinluf_imm,
+ ldiluf_reg, ldiluf_dir, ldiluf_ind, ldiluf_imm,
+ ldizuf_reg, ldizuf_dir, ldizuf_ind, ldizuf_imm,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0xb8 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+
+ br_imm, br_imm, br_imm, br_imm, /* 0xc0 */
+ br_imm, br_imm, br_imm, br_imm,
+ brd_imm, brd_imm, brd_imm, brd_imm,
+ brd_imm, brd_imm, brd_imm, brd_imm,
+ call_imm, call_imm, call_imm, call_imm,
+ call_imm, call_imm, call_imm, call_imm,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ rptb_imm, rptb_imm, rptb_imm, rptb_imm, /* 0xc8 */
+ rptb_imm, rptb_imm, rptb_imm, rptb_imm,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ swi, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ brc_reg, brcd_reg, illegal, illegal, /* 0xd0 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ brc_imm, brcd_imm, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ dbc_reg, dbcd_reg, dbc_reg, dbcd_reg, /* 0xd8 */
+ dbc_reg, dbcd_reg, dbc_reg, dbcd_reg,
+ dbc_reg, dbcd_reg, dbc_reg, dbcd_reg,
+ dbc_reg, dbcd_reg, dbc_reg, dbcd_reg,
+ dbc_imm, dbcd_imm, dbc_imm, dbcd_imm,
+ dbc_imm, dbcd_imm, dbc_imm, dbcd_imm,
+ dbc_imm, dbcd_imm, dbc_imm, dbcd_imm,
+ dbc_imm, dbcd_imm, dbc_imm, dbcd_imm,
+ callc_reg, illegal, illegal, illegal, /* 0xe0 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ callc_imm, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ trapc, illegal, illegal, illegal, /* 0xe8 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ retic_reg, illegal, illegal, illegal, /* 0xf0 */
+ retsc_reg, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0xf8 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+
+ mpyaddf_0, mpyaddf_0, mpyaddf_0, mpyaddf_0, /* 0x100 */
+ mpyaddf_0, mpyaddf_0, mpyaddf_0, mpyaddf_0,
+ mpyaddf_1, mpyaddf_1, mpyaddf_1, mpyaddf_1,
+ mpyaddf_1, mpyaddf_1, mpyaddf_1, mpyaddf_1,
+ mpyaddf_2, mpyaddf_2, mpyaddf_2, mpyaddf_2,
+ mpyaddf_2, mpyaddf_2, mpyaddf_2, mpyaddf_2,
+ mpyaddf_3, mpyaddf_3, mpyaddf_3, mpyaddf_3,
+ mpyaddf_3, mpyaddf_3, mpyaddf_3, mpyaddf_3,
+ mpysubf_0, mpysubf_0, mpysubf_0, mpysubf_0, /* 0x108 */
+ mpysubf_0, mpysubf_0, mpysubf_0, mpysubf_0,
+ mpysubf_1, mpysubf_1, mpysubf_1, mpysubf_1,
+ mpysubf_1, mpysubf_1, mpysubf_1, mpysubf_1,
+ mpysubf_2, mpysubf_2, mpysubf_2, mpysubf_2,
+ mpysubf_2, mpysubf_2, mpysubf_2, mpysubf_2,
+ mpysubf_3, mpysubf_3, mpysubf_3, mpysubf_3,
+ mpysubf_3, mpysubf_3, mpysubf_3, mpysubf_3,
+ mpyaddi_0, mpyaddi_0, mpyaddi_0, mpyaddi_0, /* 0x110 */
+ mpyaddi_0, mpyaddi_0, mpyaddi_0, mpyaddi_0,
+ mpyaddi_1, mpyaddi_1, mpyaddi_1, mpyaddi_1,
+ mpyaddi_1, mpyaddi_1, mpyaddi_1, mpyaddi_1,
+ mpyaddi_2, mpyaddi_2, mpyaddi_2, mpyaddi_2,
+ mpyaddi_2, mpyaddi_2, mpyaddi_2, mpyaddi_2,
+ mpyaddi_3, mpyaddi_3, mpyaddi_3, mpyaddi_3,
+ mpyaddi_3, mpyaddi_3, mpyaddi_3, mpyaddi_3,
+ mpysubi_0, mpysubi_0, mpysubi_0, mpysubi_0, /* 0x118 */
+ mpysubi_0, mpysubi_0, mpysubi_0, mpysubi_0,
+ mpysubi_1, mpysubi_1, mpysubi_1, mpysubi_1,
+ mpysubi_1, mpysubi_1, mpysubi_1, mpysubi_1,
+ mpysubi_2, mpysubi_2, mpysubi_2, mpysubi_2,
+ mpysubi_2, mpysubi_2, mpysubi_2, mpysubi_2,
+ mpysubi_3, mpysubi_3, mpysubi_3, mpysubi_3,
+ mpysubi_3, mpysubi_3, mpysubi_3, mpysubi_3,
+ illegal, illegal, illegal, illegal, /* 0x120 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x128 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x130 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x138 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+
+ illegal, illegal, illegal, illegal, /* 0x140 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x148 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x150 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x158 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x160 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x168 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x170 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x178 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+
+ stfstf, stfstf, stfstf, stfstf, /* 0x180 */
+ stfstf, stfstf, stfstf, stfstf,
+ stfstf, stfstf, stfstf, stfstf,
+ stfstf, stfstf, stfstf, stfstf,
+ stisti, stisti, stisti, stisti,
+ stisti, stisti, stisti, stisti,
+ stisti, stisti, stisti, stisti,
+ stisti, stisti, stisti, stisti,
+ ldfldf, ldfldf, ldfldf, ldfldf, /* 0x188 */
+ ldfldf, ldfldf, ldfldf, ldfldf,
+ ldfldf, ldfldf, ldfldf, ldfldf,
+ ldfldf, ldfldf, ldfldf, ldfldf,
+ ldildi, ldildi, ldildi, ldildi,
+ ldildi, ldildi, ldildi, ldildi,
+ ldildi, ldildi, ldildi, ldildi,
+ ldildi, ldildi, ldildi, ldildi,
+ absfstf, absfstf, absfstf, absfstf, /* 0x190 */
+ absfstf, absfstf, absfstf, absfstf,
+ absfstf, absfstf, absfstf, absfstf,
+ absfstf, absfstf, absfstf, absfstf,
+ absisti, absisti, absisti, absisti,
+ absisti, absisti, absisti, absisti,
+ absisti, absisti, absisti, absisti,
+ absisti, absisti, absisti, absisti,
+ addf3stf, addf3stf, addf3stf, addf3stf, /* 0x198 */
+ addf3stf, addf3stf, addf3stf, addf3stf,
+ addf3stf, addf3stf, addf3stf, addf3stf,
+ addf3stf, addf3stf, addf3stf, addf3stf,
+ addi3sti, addi3sti, addi3sti, addi3sti,
+ addi3sti, addi3sti, addi3sti, addi3sti,
+ addi3sti, addi3sti, addi3sti, addi3sti,
+ addi3sti, addi3sti, addi3sti, addi3sti,
+ and3sti, and3sti, and3sti, and3sti, /* 0x1a0 */
+ and3sti, and3sti, and3sti, and3sti,
+ and3sti, and3sti, and3sti, and3sti,
+ and3sti, and3sti, and3sti, and3sti,
+ ash3sti, ash3sti, ash3sti, ash3sti,
+ ash3sti, ash3sti, ash3sti, ash3sti,
+ ash3sti, ash3sti, ash3sti, ash3sti,
+ ash3sti, ash3sti, ash3sti, ash3sti,
+ fixsti, fixsti, fixsti, fixsti, /* 0x1a8 */
+ fixsti, fixsti, fixsti, fixsti,
+ fixsti, fixsti, fixsti, fixsti,
+ fixsti, fixsti, fixsti, fixsti,
+ floatstf, floatstf, floatstf, floatstf,
+ floatstf, floatstf, floatstf, floatstf,
+ floatstf, floatstf, floatstf, floatstf,
+ floatstf, floatstf, floatstf, floatstf,
+ ldfstf, ldfstf, ldfstf, ldfstf, /* 0x1b0 */
+ ldfstf, ldfstf, ldfstf, ldfstf,
+ ldfstf, ldfstf, ldfstf, ldfstf,
+ ldfstf, ldfstf, ldfstf, ldfstf,
+ ldisti, ldisti, ldisti, ldisti,
+ ldisti, ldisti, ldisti, ldisti,
+ ldisti, ldisti, ldisti, ldisti,
+ ldisti, ldisti, ldisti, ldisti,
+ lsh3sti, lsh3sti, lsh3sti, lsh3sti, /* 0x1b8 */
+ lsh3sti, lsh3sti, lsh3sti, lsh3sti,
+ lsh3sti, lsh3sti, lsh3sti, lsh3sti,
+ lsh3sti, lsh3sti, lsh3sti, lsh3sti,
+ mpyf3stf, mpyf3stf, mpyf3stf, mpyf3stf,
+ mpyf3stf, mpyf3stf, mpyf3stf, mpyf3stf,
+ mpyf3stf, mpyf3stf, mpyf3stf, mpyf3stf,
+ mpyf3stf, mpyf3stf, mpyf3stf, mpyf3stf,
+
+ mpyi3sti, mpyi3sti, mpyi3sti, mpyi3sti, /* 0x1c0 */
+ mpyi3sti, mpyi3sti, mpyi3sti, mpyi3sti,
+ mpyi3sti, mpyi3sti, mpyi3sti, mpyi3sti,
+ mpyi3sti, mpyi3sti, mpyi3sti, mpyi3sti,
+ negfstf, negfstf, negfstf, negfstf,
+ negfstf, negfstf, negfstf, negfstf,
+ negfstf, negfstf, negfstf, negfstf,
+ negfstf, negfstf, negfstf, negfstf,
+ negisti, negisti, negisti, negisti, /* 0x1c8 */
+ negisti, negisti, negisti, negisti,
+ negisti, negisti, negisti, negisti,
+ negisti, negisti, negisti, negisti,
+ notsti, notsti, notsti, notsti,
+ notsti, notsti, notsti, notsti,
+ notsti, notsti, notsti, notsti,
+ notsti, notsti, notsti, notsti,
+ or3sti, or3sti, or3sti, or3sti, /* 0x1d0 */
+ or3sti, or3sti, or3sti, or3sti,
+ or3sti, or3sti, or3sti, or3sti,
+ or3sti, or3sti, or3sti, or3sti,
+ subf3stf, subf3stf, subf3stf, subf3stf,
+ subf3stf, subf3stf, subf3stf, subf3stf,
+ subf3stf, subf3stf, subf3stf, subf3stf,
+ subf3stf, subf3stf, subf3stf, subf3stf,
+ subi3sti, subi3sti, subi3sti, subi3sti, /* 0x1d8 */
+ subi3sti, subi3sti, subi3sti, subi3sti,
+ subi3sti, subi3sti, subi3sti, subi3sti,
+ subi3sti, subi3sti, subi3sti, subi3sti,
+ xor3sti, xor3sti, xor3sti, xor3sti,
+ xor3sti, xor3sti, xor3sti, xor3sti,
+ xor3sti, xor3sti, xor3sti, xor3sti,
+ xor3sti, xor3sti, xor3sti, xor3sti,
+ illegal, illegal, illegal, illegal, /* 0x1e0 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x1e8 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x1f0 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal, /* 0x1f8 */
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal,
+ illegal, illegal, illegal, illegal
+};
diff --git a/src/emu/cpu/tms32031/dis32031.c b/src/emu/cpu/tms32031/dis32031.c
new file mode 100644
index 00000000000..47735b19963
--- /dev/null
+++ b/src/emu/cpu/tms32031/dis32031.c
@@ -0,0 +1,733 @@
+/***************************************************************************
+
+ dis32031.c
+ Disassembler for the portable TMS32C031 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#include "tms32031.h"
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define INTEGER 0
+#define FLOAT 1
+#define NODEST 2
+#define NOSOURCE 4
+#define NOSOURCE1 NOSOURCE
+#define NOSOURCE2 8
+#define SWAPSRCDST 16
+#define UNSIGNED 32
+
+
+/***************************************************************************
+ CODE CODE
+***************************************************************************/
+
+INLINE char *signed_16bit(INT16 val)
+{
+ static char temp[10];
+ if (val < 0)
+ sprintf(temp, "-$%x", -val & 0xffff);
+ else
+ sprintf(temp, "$%x", val);
+ return temp;
+}
+
+static const char *regname[32] =
+{
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "AR0", "AR1", "AR2", "AR3", "AR4", "AR5", "AR6", "AR7",
+ "DP", "IR0", "IR1", "BK", "SP", "ST", "IE", "IF",
+ "IOF", "RS", "RE", "RC", "??", "??", "??", "??"
+};
+
+static const char *condition[32] =
+{
+ "U", "LO", "LS", "HI", "HS", "EQ", "NE", "LT",
+ "LE", "GT", "GE", "??", "NV", "V", "NUF", "UF",
+ "NLV", "LV", "NLUF", "LUF", "ZUF", "??", "??", "??",
+ "??", "??", "??", "??", "??", "??", "??", "??"
+};
+
+//
+// for instructions 0x000-0x3f
+// G = (op >> 21) & 3;
+// G == 0 -> register -> 000ooooo o00ddddd 00000000 000sssss
+// G == 1 -> direct -> 000ooooo o01ddddd DDDDDDDD DDDDDDDD
+// G == 2 -> indirect -> 000ooooo o10ddddd mmmmmaaa DDDDDDDD
+// G == 3 -> immediate -> 000ooooo o11ddddd iiiiiiii iiiiiiii
+//
+// for instructions 0x040-0x7f
+// T = (op >> 21) & 3; (src1) (src2)
+// T == 0 -> reg reg -> 001ooooo o00ddddd 000sssss 000SSSSS
+// T == 1 -> ind reg -> 001ooooo o01ddddd mmmmmaaa 000SSSSS
+// T == 2 -> reg ind -> 001ooooo o10ddddd 000sssss MMMMMAAA
+// T == 3 -> ind ind -> 001ooooo o11ddddd mmmmmaaa MMMMMAAA
+//
+// for instructions 0x100-0x1ff
+// 10ooooPP dDsssSSS mmmmmaaa MMMMMAAA
+// 10ooooPP dDsssSSS 111rrrrr 111RRRRR
+//
+// conditional branches
+// xxxxxxBa aaDccccc 00000000 000sssss
+// xxxxxxBa aaDccccc iiiiiiii iiiiiiii
+// D=0(standard) or 1(delayed)
+// B=0(register) or 1(immediate)
+//
+// status register
+// 31-14 = 0
+// 13 = GIE
+// 12 = CC
+// 11 = CE
+// 10 = CF
+// 9 = 0
+// 8 = RM
+// 7 = OVM
+// 6 = LUF (latched FP underflow)
+// 5 = LV (latched overflow)
+// 4 = UF (FP underflow)
+// 3 = N
+// 2 = Z
+// 1 = V
+// 0 = C
+//
+// conditions:
+// 0 = U (unconditional)
+// 1 = LO (C)
+// 2 = LS (C | Z)
+// 3 = HI (~C & ~Z)
+// 4 = HS (~C)
+// 5 = EQ (Z)
+// 6 = NE (~Z)
+// 7 = LT (N)
+// 8 = LE (N | Z)
+// 9 = GT (~N & ~Z)
+// 10 = GE (~N)
+// 12 = NV (~V)
+// 13 = V (V)
+// 14 = NUF (~UF)
+// 15 = UF (UF)
+// 16 = NLV (~LV)
+// 17 = LV (LV)
+// 18 = NLUF (~LUF)
+// 19 = LUF (LUF)
+// 20 = ZUF (Z | UF)
+
+static void append_indirect(UINT8 ma, INT8 disp, char *buffer)
+{
+ char *dst = &buffer[strlen(buffer)];
+ char dispstr[20];
+ int mode = (ma >> 3) & 0x1f;
+ int ar = ma & 7;
+
+ dispstr[0] = 0;
+ if (disp < 0)
+ sprintf(dispstr, "(-%X)", -disp & 0xffff);
+ else if (disp > 0)
+ sprintf(dispstr, "(%X)", disp);
+
+ switch (mode)
+ {
+ case 0: sprintf(dst, "*+AR%d%s", ar, dispstr); break;
+ case 1: sprintf(dst, "*-AR%d%s", ar, dispstr); break;
+ case 2: sprintf(dst, "*++AR%d%s", ar, dispstr); break;
+ case 3: sprintf(dst, "*--AR%d%s", ar, dispstr); break;
+ case 4: sprintf(dst, "*AR%d++%s", ar, dispstr); break;
+ case 5: sprintf(dst, "*AR%d--%s", ar, dispstr); break;
+ case 6: sprintf(dst, "*AR%d++%s%%", ar, dispstr); break;
+ case 7: sprintf(dst, "*AR%d--%s%%", ar, dispstr); break;
+
+ case 8: sprintf(dst, "*+AR%d(IR0)", ar); break;
+ case 9: sprintf(dst, "*-AR%d(IR0)", ar); break;
+ case 10: sprintf(dst, "*++AR%d(IR0)", ar); break;
+ case 11: sprintf(dst, "*--AR%d(IR0)", ar); break;
+ case 12: sprintf(dst, "*AR%d++(IR0)", ar); break;
+ case 13: sprintf(dst, "*AR%d--(IR0)", ar); break;
+ case 14: sprintf(dst, "*AR%d++(IR0)%%", ar); break;
+ case 15: sprintf(dst, "*AR%d--(IR0)%%", ar); break;
+
+ case 16: sprintf(dst, "*+AR%d(IR1)", ar); break;
+ case 17: sprintf(dst, "*-AR%d(IR1)", ar); break;
+ case 18: sprintf(dst, "*++AR%d(IR1)", ar); break;
+ case 19: sprintf(dst, "*--AR%d(IR1)", ar); break;
+ case 20: sprintf(dst, "*AR%d++(IR1)", ar); break;
+ case 21: sprintf(dst, "*AR%d--(IR1)", ar); break;
+ case 22: sprintf(dst, "*AR%d++(IR1)%%", ar); break;
+ case 23: sprintf(dst, "*AR%d--(IR1)%%", ar); break;
+
+ case 24: sprintf(dst, "*AR%d", ar); break;
+ case 25: sprintf(dst, "*AR%d++(IR0)B", ar); break;
+ case 28:
+ case 29:
+ case 30:
+ case 31: strcpy(dst, regname[ma & 31]); break;
+ default: sprintf(dst, "(unknown mode)"); break;
+ }
+}
+
+static void append_immediate(UINT16 data, int is_float, int is_unsigned, char *buffer)
+{
+ char *dst = &buffer[strlen(buffer)];
+
+ if (is_float)
+ {
+ int exp = ((INT16)data >> 12) + 127;
+ UINT32 expanded_data;
+ float float_val;
+
+ expanded_data = ((data & 0x0800) << 20) + ((exp << 23) & 0x7f800000);
+ if (data == 0x8000)
+ *(float *)&expanded_data = 0;
+ else if (!(data & 0x0800))
+ expanded_data += ((data & 0x0fff) << 12);
+ else
+ expanded_data += ((-data & 0x0fff) << 12);
+ float_val = *(float *)&expanded_data;
+ sprintf(dst, "%8f", float_val);
+ }
+ else if (!is_unsigned && (INT16)data < 0)
+ sprintf(dst, "-$%04X", -data & 0xffff);
+ else
+ sprintf(dst, "$%04X", data);
+}
+
+static void disasm_general(const char *opstring, UINT32 op, int flags, char *buffer)
+{
+ sprintf(buffer, "%-6s", opstring);
+
+ if (flags & SWAPSRCDST)
+ {
+ strcat(buffer, regname[(op >> 16) & 31]);
+ strcat(buffer, ",");
+ }
+
+ /* switch off of G */
+ if (!(flags & NOSOURCE))
+ {
+ switch ((op >> 21) & 3)
+ {
+ case 0:
+ strcat(buffer, regname[op & 31]);
+ break;
+
+ case 1:
+ sprintf(&buffer[strlen(buffer)], "($%04X)", op & 0xffff);
+ break;
+
+ case 2:
+ append_indirect((op >> 8) & 0xff, op, buffer);
+ break;
+
+ case 3:
+ append_immediate(op & 0xffff, (flags & FLOAT), (flags & UNSIGNED), buffer);
+ break;
+ }
+ }
+
+ /* add destination op */
+ if (!(flags & NODEST) && !(flags & SWAPSRCDST))
+ {
+ if (!(flags & NOSOURCE))
+ strcat(buffer, ",");
+ strcat(buffer, regname[(op >> 16) & 31]);
+ }
+}
+
+static void disasm_3op(const char *opstring, UINT32 op, int flags, char *buffer)
+{
+ sprintf(buffer, "%-6s", opstring);
+
+ /* switch off of T */
+ if (!(flags & NOSOURCE1))
+ {
+ switch ((op >> 21) & 1)
+ {
+ case 0:
+ strcat(buffer, regname[(op >> 8) & 31]);
+ break;
+
+ case 1:
+ append_indirect(op >> 8, 1, buffer);
+ break;
+ }
+ }
+
+ /* switch off of T */
+ if (!(flags & NOSOURCE2))
+ {
+ if (!(flags & NOSOURCE1))
+ strcat(buffer, ",");
+ switch ((op >> 22) & 1)
+ {
+ case 0:
+ strcat(buffer, regname[op & 31]);
+ break;
+
+ case 1:
+ append_indirect(op, 1, buffer);
+ break;
+ }
+ }
+
+ /* add destination op */
+ if (!(flags & NODEST))
+ {
+ if (!(flags & (NOSOURCE1 | NOSOURCE2)))
+ strcat(buffer, ",");
+ strcat(buffer, regname[(op >> 16) & 31]);
+ }
+}
+
+static void disasm_conditional(const char *opstring, UINT32 op, int flags, char *buffer)
+{
+ char temp[10];
+ sprintf(temp, "%s%s", opstring, condition[(op >> 23) & 31]);
+ disasm_general(temp, op, flags, buffer);
+}
+
+
+static void disasm_parallel_3op3op(const char *opstring1, const char *opstring2, UINT32 op, int flags, const UINT8 *srctable, char *buffer)
+{
+ const UINT8 *s = &srctable[((op >> 24) & 3) * 4];
+ int d1 = (op >> 23) & 1;
+ int d2 = 2 + ((op >> 22) & 1);
+ char src[5][20];
+
+ strcpy(src[1], regname[(op >> 19) & 7]);
+ strcpy(src[2], regname[(op >> 16) & 7]);
+
+ src[3][0] = 0;
+ append_indirect(op >> 8, 1, src[3]);
+
+ src[4][0] = 0;
+ append_indirect(op, 1, src[4]);
+
+ sprintf(buffer, "%s %s,%s,R%d || %s %s,%s,R%d",
+ opstring1, src[s[0]], src[s[1]], d1,
+ opstring2, src[s[2]], src[s[3]], d2);
+}
+
+
+static void disasm_parallel_3opstore(const char *opstring1, const char *opstring2, UINT32 op, int flags, char *buffer)
+{
+ int d1 = (op >> 22) & 7;
+ int s1 = (op >> 19) & 7;
+ int s3 = (op >> 16) & 7;
+ char dst2[20], src2[20];
+
+ dst2[0] = 0;
+ append_indirect(op >> 8, 1, dst2);
+
+ src2[0] = 0;
+ append_indirect(op, 1, src2);
+
+ if (!(flags & NOSOURCE1))
+ sprintf(buffer, "%s R%d,%s,R%d || %s R%d,%s",
+ opstring1, s1, src2, d1,
+ opstring2, s3, dst2);
+ else
+ sprintf(buffer, "%s %s,R%d || %s R%d,%s",
+ opstring1, src2, d1,
+ opstring2, s3, dst2);
+}
+
+
+static void disasm_parallel_loadload(const char *opstring1, const char *opstring2, UINT32 op, int flags, char *buffer)
+{
+ int d2 = (op >> 22) & 7;
+ int d1 = (op >> 19) & 7;
+ char src1[20], src2[20];
+
+ src1[0] = 0;
+ append_indirect(op >> 8, 1, src1);
+
+ src2[0] = 0;
+ append_indirect(op, 1, src2);
+
+ sprintf(buffer, "%s %s,R%d || %s %s,R%d",
+ opstring1, src2, d2,
+ opstring2, src1, d1);
+}
+
+
+static void disasm_parallel_storestore(const char *opstring1, const char *opstring2, UINT32 op, int flags, char *buffer)
+{
+ int s2 = (op >> 22) & 7;
+ int s1 = (op >> 16) & 7;
+ char dst1[20], dst2[20];
+
+ dst1[0] = 0;
+ append_indirect(op >> 8, 1, dst1);
+
+ dst2[0] = 0;
+ append_indirect(op, 1, dst2);
+
+ sprintf(buffer, "%s R%d,%s || %s R%d,%s",
+ opstring1, s2, dst2,
+ opstring2, s1, dst1);
+}
+
+
+
+unsigned dasm_tms32031(char *buffer, unsigned pc, UINT32 op)
+{
+ UINT32 flags = 0;
+
+ switch (op >> 23)
+ {
+ case 0x000: disasm_general("ABSF", op, FLOAT, buffer); break;
+ case 0x001: disasm_general("ABSI", op, INTEGER, buffer); break;
+ case 0x002: disasm_general("ADDC", op, INTEGER, buffer); break;
+ case 0x003: disasm_general("ADDF", op, FLOAT, buffer); break;
+ case 0x004: disasm_general("ADDI", op, INTEGER, buffer); break;
+ case 0x005: disasm_general("AND", op, INTEGER | UNSIGNED, buffer); break;
+ case 0x006: disasm_general("ANDN", op, INTEGER | UNSIGNED, buffer); break;
+ case 0x007: disasm_general("ASH", op, INTEGER, buffer); break;
+
+ case 0x008: disasm_general("CMPF", op, FLOAT, buffer); break;
+ case 0x009: disasm_general("CMPI", op, INTEGER, buffer); break;
+ case 0x00a: disasm_general("FIX", op, FLOAT, buffer); break;
+ case 0x00b: disasm_general("FLOAT", op, INTEGER, buffer); break;
+ case 0x00c: disasm_general((op & 1) ? "IDLE2" : "IDLE", op, NOSOURCE | NODEST, buffer); break;
+ case 0x00d: disasm_general("LDE", op, FLOAT, buffer); break;
+ case 0x00e: disasm_general("LDF", op, FLOAT, buffer); break;
+ case 0x00f: disasm_general("LDFI", op, FLOAT, buffer); break;
+
+ case 0x010: disasm_general("LDI", op, INTEGER, buffer); break;
+ case 0x011: disasm_general("LDII", op, INTEGER, buffer); break;
+ case 0x012: disasm_general("LDM", op, FLOAT, buffer); break;
+ case 0x013: disasm_general("LSH", op, INTEGER, buffer); break;
+ case 0x014: disasm_general("MPYF", op, FLOAT, buffer); break;
+ case 0x015: disasm_general("MPYI", op, INTEGER, buffer); break;
+ case 0x016: disasm_general("NEGB", op, INTEGER, buffer); break;
+ case 0x017: disasm_general("NEGF", op, FLOAT, buffer); break;
+
+ case 0x018: disasm_general("NEGI", op, INTEGER, buffer); break;
+ case 0x019: disasm_general("NOP", op, NODEST, buffer); break;
+ case 0x01a: disasm_general("NORM", op, FLOAT, buffer); break;
+ case 0x01b: disasm_general("NOT", op, INTEGER, buffer); break;
+ case 0x01c: disasm_general("POP", op, NOSOURCE, buffer); break;
+ case 0x01d: disasm_general("POPF", op, NOSOURCE, buffer); break;
+ case 0x01e: disasm_general("PUSH", op, NOSOURCE, buffer); break;
+ case 0x01f: disasm_general("PUSHF", op, NOSOURCE, buffer); break;
+
+ case 0x020: disasm_general("OR", op, INTEGER | UNSIGNED, buffer); break;
+ case 0x021: disasm_general((op & 1) ? "LOPOWER" : "MAXSPEED", op, NOSOURCE | NODEST, buffer); break;
+ case 0x022: disasm_general("RND", op, FLOAT, buffer); break;
+ case 0x023: disasm_general("ROL", op, INTEGER, buffer); break;
+ case 0x024: disasm_general("ROLC", op, INTEGER, buffer); break;
+ case 0x025: disasm_general("ROR", op, INTEGER, buffer); break;
+ case 0x026: disasm_general("RORC", op, INTEGER, buffer); break;
+ case 0x027: disasm_general("RTPS", op, INTEGER | NODEST, buffer); break;
+
+ case 0x028: disasm_general("STF", op, FLOAT | SWAPSRCDST, buffer); break;
+ case 0x029: disasm_general("STFI", op, FLOAT | SWAPSRCDST, buffer); break;
+ case 0x02a: disasm_general("STI", op, INTEGER | SWAPSRCDST, buffer); break;
+ case 0x02b: disasm_general("STII", op, INTEGER | SWAPSRCDST, buffer); break;
+ case 0x02c: disasm_general("SIGI", op, NOSOURCE | NODEST, buffer); break;
+ case 0x02d: disasm_general("SUBB", op, INTEGER, buffer); break;
+ case 0x02e: disasm_general("SUBC", op, INTEGER, buffer); break;
+ case 0x02f: disasm_general("SUBF", op, FLOAT, buffer); break;
+
+ case 0x030: disasm_general("SUBI", op, INTEGER, buffer); break;
+ case 0x031: disasm_general("SUBRB", op, INTEGER, buffer); break;
+ case 0x032: disasm_general("SUBRF", op, FLOAT, buffer); break;
+ case 0x033: disasm_general("SUBRI", op, INTEGER, buffer); break;
+ case 0x034: disasm_general("TSTB", op, INTEGER, buffer); break;
+ case 0x035: disasm_general("XOR", op, INTEGER | UNSIGNED, buffer); break;
+ case 0x036: disasm_general("IACK", op, INTEGER | NODEST, buffer); break;
+
+ case 0x040: disasm_3op("ADDC3", op, INTEGER, buffer); break;
+ case 0x041: disasm_3op("ADDF3", op, FLOAT, buffer); break;
+ case 0x042: disasm_3op("ADDI3", op, INTEGER, buffer); break;
+ case 0x043: disasm_3op("AND3", op, INTEGER, buffer); break;
+ case 0x044: disasm_3op("ANDN3", op, INTEGER, buffer); break;
+ case 0x045: disasm_3op("ASH3", op, INTEGER, buffer); break;
+ case 0x046: disasm_3op("CMPF3", op, FLOAT | NODEST, buffer); break;
+ case 0x047: disasm_3op("CMPI3", op, INTEGER | NODEST, buffer); break;
+
+ case 0x048: disasm_3op("LSH3", op, INTEGER, buffer); break;
+ case 0x049: disasm_3op("MPYF3", op, FLOAT, buffer); break;
+ case 0x04a: disasm_3op("MPYI3", op, INTEGER, buffer); break;
+ case 0x04b: disasm_3op("OR3", op, INTEGER, buffer); break;
+ case 0x04c: disasm_3op("SUBB3", op, INTEGER, buffer); break;
+ case 0x04d: disasm_3op("SUBF3", op, FLOAT, buffer); break;
+ case 0x04e: disasm_3op("SUBI3", op, INTEGER, buffer); break;
+ case 0x04f: disasm_3op("TSTB3", op, INTEGER, buffer); break;
+
+ case 0x050: disasm_3op("XOR3", op, INTEGER, buffer); break;
+
+ case 0x080: case 0x081: case 0x082: case 0x083:
+ case 0x084: case 0x085: case 0x086: case 0x087:
+ case 0x088: case 0x089: case 0x08a: case 0x08b:
+ case 0x08c: case 0x08d: case 0x08e: case 0x08f:
+ case 0x090: case 0x091: case 0x092: case 0x093:
+ case 0x094: case 0x095: case 0x096: case 0x097:
+ case 0x098: case 0x099: case 0x09a: case 0x09b:
+ case 0x09c: case 0x09d: case 0x09e: case 0x09f:
+ disasm_conditional("LDF", op, FLOAT, buffer);
+ break;
+
+ case 0x0a0: case 0x0a1: case 0x0a2: case 0x0a3:
+ case 0x0a4: case 0x0a5: case 0x0a6: case 0x0a7:
+ case 0x0a8: case 0x0a9: case 0x0aa: case 0x0ab:
+ case 0x0ac: case 0x0ad: case 0x0ae: case 0x0af:
+ case 0x0b0: case 0x0b1: case 0x0b2: case 0x0b3:
+ case 0x0b4: case 0x0b5: case 0x0b6: case 0x0b7:
+ case 0x0b8: case 0x0b9: case 0x0ba: case 0x0bb:
+ case 0x0bc: case 0x0bd: case 0x0be: case 0x0bf:
+ disasm_conditional("LDI", op, INTEGER, buffer);
+ break;
+
+
+ case 0x0c0: case 0x0c1:
+ sprintf(buffer, "BR $%06X", op & 0xffffff);
+ break;
+
+ case 0x0c2: case 0x0c3:
+ sprintf(buffer, "BRD $%06X", op & 0xffffff);
+ break;
+
+ case 0x0c4: case 0x0c5:
+ sprintf(buffer, "CALL $%06X", op & 0xffffff);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+
+ case 0x0c8: case 0x0c9:
+ sprintf(buffer, "RPTB $%06X", op & 0xffffff);
+ break;
+
+ case 0x0cc: case 0x0cd: case 0x0ce: case 0x0cf:
+ sprintf(buffer, "SWI");
+ break;
+
+
+ case 0x0d0:
+ {
+ char temp[10];
+ sprintf(temp, "B%s%s", condition[(op >> 16) & 31], ((op >> 21) & 1) ? "D" : "");
+ sprintf(buffer, "%-6s%s", temp, regname[op & 31]);
+ break;
+ }
+
+ case 0x0d4:
+ {
+ char temp[10];
+ sprintf(temp, "B%s%s", condition[(op >> 16) & 31], ((op >> 21) & 1) ? "D" : "");
+ sprintf(buffer, "%-6s$%06X", temp, (pc + (((op >> 21) & 1) ? 3 : 1) + (INT16)op) & 0xffffff);
+ break;
+ }
+
+
+ case 0x0d8: case 0x0d9: case 0x0da: case 0x0db:
+ {
+ char temp[10];
+ sprintf(temp, "DB%s%s", condition[(op >> 16) & 31], ((op >> 21) & 1) ? "D" : "");
+ sprintf(buffer, "%-6sAR%d,%s", temp, (op >> 22) & 7, regname[op & 31]);
+ break;
+ }
+
+ case 0x0dc: case 0x0dd: case 0x0de: case 0x0df:
+ {
+ char temp[10];
+ sprintf(temp, "DB%s%s", condition[(op >> 16) & 31], ((op >> 21) & 1) ? "D" : "");
+ sprintf(buffer, "%-6sAR%d,$%06X", temp, (op >> 22) & 7, (pc + (((op >> 21) & 1) ? 3 : 1) + (INT16)op) & 0xffffff);
+ break;
+ }
+
+
+ case 0x0e0:
+ {
+ char temp[10];
+ sprintf(temp, "CALL%s", condition[(op >> 16) & 31]);
+ sprintf(buffer, "%-6s%s", temp, regname[op & 31]);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ }
+
+ case 0x0e4:
+ {
+ char temp[10];
+ sprintf(temp, "CALL%s", condition[(op >> 16) & 31]);
+ sprintf(buffer, "%-6s$%06X", temp, (pc + 1 + (INT16)op) & 0xffffff);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ }
+
+
+ case 0x0e8: case 0x0e9: case 0x0ea: case 0x0eb:
+ {
+ char temp[10];
+ sprintf(temp, "TRAP%s", condition[(op >> 16) & 31]);
+ sprintf(buffer, "%-6s$%02X", temp, op & 31);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ }
+
+
+ case 0x0f0:
+ sprintf(buffer, "RETI%s", condition[(op >> 16) & 31]);
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ case 0x0f1:
+ sprintf(buffer, "RETS%s", condition[(op >> 16) & 31]);
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+
+ case 0x100: case 0x101: case 0x102: case 0x103:
+ case 0x104: case 0x105: case 0x106: case 0x107: // MPYF3||ADDF3
+ {
+ static const UINT8 srctable[] = { 3,4,1,2, 3,1,4,2, 1,2,3,4, 3,1,2,4 };
+ disasm_parallel_3op3op("MPYF3", "ADDF3", op, FLOAT, srctable, buffer);
+ break;
+ }
+
+
+ case 0x108: case 0x109: case 0x10a: case 0x10b:
+ case 0x10c: case 0x10d: case 0x10e: case 0x10f: // MPYF3||SUBF3
+ {
+ static const UINT8 srctable[] = { 3,4,1,2, 3,1,4,2, 1,2,3,4, 3,1,2,4 };
+ disasm_parallel_3op3op("MPYF3", "SUBF3", op, FLOAT, srctable, buffer);
+ break;
+ }
+
+
+ case 0x110: case 0x111: case 0x112: case 0x113:
+ case 0x114: case 0x115: case 0x116: case 0x117: // MPYI3||ADDI3
+ {
+ static const UINT8 srctable[] = { 3,4,1,2, 3,1,4,2, 1,2,3,4, 3,1,2,4 };
+ disasm_parallel_3op3op("MPYI3", "ADDI3", op, INTEGER, srctable, buffer);
+ break;
+ }
+
+
+ case 0x118: case 0x119: case 0x11a: case 0x11b:
+ case 0x11c: case 0x11d: case 0x11e: case 0x11f: // MPYI3||SUBI3
+ {
+ static const UINT8 srctable[] = { 3,4,1,2, 3,1,4,2, 1,2,3,4, 3,1,2,4 };
+ disasm_parallel_3op3op("MPYI3", "SUBI3", op, INTEGER, srctable, buffer);
+ break;
+ }
+
+
+ case 0x180: case 0x181: case 0x182: case 0x183: // STF||STF
+ disasm_parallel_storestore("STF", "STF", op, FLOAT, buffer);
+ break;
+
+ case 0x184: case 0x185: case 0x186: case 0x187: // STI||STI
+ disasm_parallel_storestore("STI", "STI", op, INTEGER, buffer);
+ break;
+
+
+ case 0x188: case 0x189: case 0x18a: case 0x18b: // LDF||LDF
+ disasm_parallel_loadload("LDF", "LDF", op, FLOAT, buffer);
+ break;
+
+ case 0x18c: case 0x18d: case 0x18e: case 0x18f: // LDI||LDI
+ disasm_parallel_loadload("LDI", "LDI", op, INTEGER, buffer);
+ break;
+
+
+ case 0x190: case 0x191: case 0x192: case 0x193: // ABSF||STF
+ disasm_parallel_3opstore("ABSF", "STF", op, FLOAT | NOSOURCE1, buffer);
+ break;
+
+ case 0x194: case 0x195: case 0x196: case 0x197: // ABSI||STI
+ disasm_parallel_3opstore("ABSI", "STI", op, INTEGER | NOSOURCE1, buffer);
+ break;
+
+
+ case 0x198: case 0x199: case 0x19a: case 0x19b: // ADDF3||STF
+ disasm_parallel_3opstore("ADDF3", "STF", op, FLOAT, buffer);
+ break;
+
+ case 0x19c: case 0x19d: case 0x19e: case 0x19f: // ADDI3||STI
+ disasm_parallel_3opstore("ADDI3", "STI", op, INTEGER, buffer);
+ break;
+
+
+ case 0x1a0: case 0x1a1: case 0x1a2: case 0x1a3: // AND3||STI
+ disasm_parallel_3opstore("AND3", "STI", op, INTEGER, buffer);
+ break;
+
+ case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: // ASH3||STI
+ disasm_parallel_3opstore("ASH3", "STI", op, INTEGER, buffer);
+ break;
+
+
+ case 0x1a8: case 0x1a9: case 0x1aa: case 0x1ab: // FIX||STI
+ disasm_parallel_3opstore("FIX", "STF", op, FLOAT | NOSOURCE1, buffer);
+ break;
+
+ case 0x1ac: case 0x1ad: case 0x1ae: case 0x1af: // FLOAT||STF
+ disasm_parallel_3opstore("FLOAT", "STF", op, FLOAT | NOSOURCE1, buffer);
+ break;
+
+
+ case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: // LDF||STF
+ disasm_parallel_3opstore("LDF", "STF", op, FLOAT | NOSOURCE1, buffer);
+ break;
+
+ case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: // LDI||STI
+ disasm_parallel_3opstore("LDI", "STI", op, INTEGER | NOSOURCE1, buffer);
+ break;
+
+
+ case 0x1b8: case 0x1b9: case 0x1ba: case 0x1bb: // LSH3||STI
+ disasm_parallel_3opstore("LSH3", "STI", op, INTEGER, buffer);
+ break;
+
+ case 0x1bc: case 0x1bd: case 0x1be: case 0x1bf: // MPYF3||STF
+ disasm_parallel_3opstore("MPYF3", "STF", op, FLOAT, buffer);
+ break;
+
+
+ case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3: // MPYI3||STI
+ disasm_parallel_3opstore("MPYI3", "STI", op, INTEGER, buffer);
+ break;
+
+ case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7: // NEGF||STF
+ disasm_parallel_3opstore("NEGF", "STF", op, FLOAT | NOSOURCE1, buffer);
+ break;
+
+
+ case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb: // NEGI||STI
+ disasm_parallel_3opstore("NEGI", "STI", op, INTEGER | NOSOURCE1, buffer);
+ break;
+
+ case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf: // NOT||STI
+ disasm_parallel_3opstore("NOT", "STI", op, INTEGER | NOSOURCE1, buffer);
+ break;
+
+
+ case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3: // OR3||STI
+ disasm_parallel_3opstore("OR3", "STI", op, INTEGER, buffer);
+ break;
+
+ case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: // SUBF3||STF
+ disasm_parallel_3opstore("SUBF3", "STF", op, FLOAT, buffer);
+ break;
+
+
+ case 0x1d8: case 0x1d9: case 0x1da: case 0x1db: // SUBI3||STI
+ disasm_parallel_3opstore("SUBI3", "STI", op, INTEGER, buffer);
+ break;
+
+ case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: // XOR3||STI
+ disasm_parallel_3opstore("XOR3", "STI", op, INTEGER, buffer);
+ break;
+
+
+ default:
+ break;
+ }
+
+ return 1 | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/tms32031/tms32031.c b/src/emu/cpu/tms32031/tms32031.c
new file mode 100644
index 00000000000..3545bc9e7fb
--- /dev/null
+++ b/src/emu/cpu/tms32031/tms32031.c
@@ -0,0 +1,829 @@
+/***************************************************************************
+
+ tms32031.c
+ Core implementation for the portable TMS32C031 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#include "debugger.h"
+#include "tms32031.h"
+#include "eminline.h"
+
+
+#define LOG_OPCODE_USAGE (0)
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+enum
+{
+ TMR_R0 = 0,
+ TMR_R1,
+ TMR_R2,
+ TMR_R3,
+ TMR_R4,
+ TMR_R5,
+ TMR_R6,
+ TMR_R7,
+ TMR_AR0,
+ TMR_AR1,
+ TMR_AR2,
+ TMR_AR3,
+ TMR_AR4,
+ TMR_AR5,
+ TMR_AR6,
+ TMR_AR7,
+ TMR_DP,
+ TMR_IR0,
+ TMR_IR1,
+ TMR_BK,
+ TMR_SP,
+ TMR_ST,
+ TMR_IE,
+ TMR_IF,
+ TMR_IOF,
+ TMR_RS,
+ TMR_RE,
+ TMR_RC,
+ TMR_R8, /* 3204x only */
+ TMR_R9, /* 3204x only */
+ TMR_R10, /* 3204x only */
+ TMR_R11, /* 3204x only */
+ TMR_TEMP1, /* used by the interpreter */
+ TMR_TEMP2, /* used by the interpreter */
+ TMR_TEMP3 /* used by the interpreter */
+};
+
+#define CFLAG 0x0001
+#define VFLAG 0x0002
+#define ZFLAG 0x0004
+#define NFLAG 0x0008
+#define UFFLAG 0x0010
+#define LVFLAG 0x0020
+#define LUFFLAG 0x0040
+#define OVMFLAG 0x0080
+#define RMFLAG 0x0100
+#define CFFLAG 0x0400
+#define CEFLAG 0x0800
+#define CCFLAG 0x1000
+#define GIEFLAG 0x2000
+
+#define IREG(rnum) (tms32031.r[rnum].i32[0])
+
+
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+union genreg
+{
+ UINT32 i32[2];
+ UINT16 i16[4];
+ UINT8 i8[8];
+};
+
+/* TMS34031 Registers */
+typedef struct
+{
+ /* core registers */
+ UINT32 pc;
+ union genreg r[36];
+ UINT32 bkmask;
+
+ /* internal stuff */
+ UINT32 ppc;
+ UINT32 op;
+ UINT8 delayed;
+ UINT8 irq_pending;
+ UINT8 mcu_mode;
+ UINT8 is_idling;
+ int interrupt_cycles;
+
+ UINT32 bootoffset;
+ void (*xf0_w)(UINT8 val);
+ void (*xf1_w)(UINT8 val);
+ void (*iack_w)(UINT8 val, offs_t addr);
+ int (*irq_callback)(int state);
+} tms32031_regs;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void trap(int trapnum);
+static UINT32 boot_loader(UINT32 boot_rom_addr);
+
+
+
+/***************************************************************************
+ PUBLIC GLOBAL VARIABLES
+***************************************************************************/
+
+static int tms32031_icount;
+
+
+
+/***************************************************************************
+ PRIVATE GLOBAL VARIABLES
+***************************************************************************/
+
+static tms32031_regs tms32031;
+
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+#define ROPCODE(pc) cpu_readop32((pc) << 2)
+#define OP tms32031.op
+
+#define RMEM(addr) program_read_dword_32le((addr) << 2)
+#define WMEM(addr,data) program_write_dword_32le((addr) << 2, data)
+#define UPDATEPC(addr) change_pc((addr) << 2)
+
+
+
+/***************************************************************************
+ HELPER MACROS
+***************************************************************************/
+
+#define MANTISSA(r) ((INT32)(r)->i32[0])
+#define EXPONENT(r) ((INT8)(r)->i32[1])
+#define SET_MANTISSA(r,v) ((r)->i32[0] = (v))
+#define SET_EXPONENT(r,v) ((r)->i32[1] = (v))
+
+typedef union int_double
+{
+ double d;
+ float f[2];
+ UINT32 i[2];
+} int_double;
+
+
+#if 0
+static float dsp_to_float(union genreg *fp)
+{
+ int_double id;
+
+ if (MANTISSA(fp) == 0 && EXPONENT(fp) == -128)
+ return 0;
+ else if (MANTISSA(fp) >= 0)
+ {
+ int exponent = (EXPONENT(fp) + 127) << 23;
+ id.i[0] = exponent + (MANTISSA(fp) >> 8);
+ }
+ else
+ {
+ int exponent = (EXPONENT(fp) + 127) << 23;
+ INT32 man = -MANTISSA(fp);
+ id.i[0] = 0x80000000 + exponent + ((man >> 8) & 0x00ffffff);
+ }
+ return id.f[0];
+}
+#endif
+
+
+static double dsp_to_double(union genreg *fp)
+{
+ int_double id;
+
+ if (MANTISSA(fp) == 0 && EXPONENT(fp) == -128)
+ return 0;
+ else if (MANTISSA(fp) >= 0)
+ {
+ int exponent = (EXPONENT(fp) + 1023) << 20;
+ id.i[BYTE_XOR_BE(0)] = exponent + (MANTISSA(fp) >> 11);
+ id.i[BYTE_XOR_BE(1)] = (MANTISSA(fp) << 21) & 0xffe00000;
+ }
+ else
+ {
+ int exponent = (EXPONENT(fp) + 1023) << 20;
+ INT32 man = -MANTISSA(fp);
+ id.i[BYTE_XOR_BE(0)] = 0x80000000 + exponent + ((man >> 11) & 0x001fffff);
+ id.i[BYTE_XOR_BE(1)] = (man << 21) & 0xffe00000;
+ }
+ return id.d;
+}
+
+
+static void double_to_dsp(double val, union genreg *result)
+{
+ int mantissa, exponent;
+ int_double id;
+ id.d = val;
+
+ mantissa = ((id.i[BYTE_XOR_BE(0)] & 0x000fffff) << 11) | ((id.i[BYTE_XOR_BE(1)] & 0xffe00000) >> 21);
+ exponent = ((id.i[BYTE_XOR_BE(0)] & 0x7ff00000) >> 20) - 1023;
+ if (exponent < -128)
+ {
+ SET_MANTISSA(result, 0);
+ SET_EXPONENT(result, -128);
+ }
+ else if (exponent > 127)
+ {
+ if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0)
+ SET_MANTISSA(result, 0x7fffffff);
+ else
+ SET_MANTISSA(result, 0x80000001);
+ SET_EXPONENT(result, 127);
+ }
+ else if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0)
+ {
+ SET_MANTISSA(result, mantissa);
+ SET_EXPONENT(result, exponent);
+ }
+ else if (mantissa != 0)
+ {
+ SET_MANTISSA(result, 0x80000000 | -mantissa);
+ SET_EXPONENT(result, exponent);
+ }
+ else
+ {
+ SET_MANTISSA(result, 0x80000000);
+ SET_EXPONENT(result, exponent - 1);
+ }
+}
+
+
+
+/***************************************************************************
+ EXECEPTION HANDLING
+***************************************************************************/
+
+INLINE void generate_exception(int exception)
+{
+}
+
+
+INLINE void invalid_instruction(UINT32 op)
+{
+}
+
+
+
+/***************************************************************************
+ IRQ HANDLING
+***************************************************************************/
+
+static void check_irqs(void)
+{
+ int validints = IREG(TMR_IF) & IREG(TMR_IE) & 0x07ff;
+ if (validints && (IREG(TMR_ST) & GIEFLAG))
+ {
+ int whichtrap = 0;
+ int i;
+
+ for (i = 0; i < 11; i++)
+ if (validints & (1 << i))
+ {
+ whichtrap = i + 1;
+ break;
+ }
+
+ if (whichtrap)
+ {
+ tms32031.is_idling = 0;
+ if (!tms32031.delayed)
+ {
+ trap(whichtrap);
+
+ /* for internal sources, clear the interrupt when taken */
+ if (whichtrap > 4)
+ IREG(TMR_IF) &= ~(1 << (whichtrap - 1));
+ }
+ else
+ tms32031.irq_pending = 1;
+ }
+ }
+}
+
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline < 11)
+ {
+ /* update the state */
+ if (state == ASSERT_LINE)
+ IREG(TMR_IF) |= 1 << irqline;
+ else
+ IREG(TMR_IF) &= ~(1 << irqline);
+
+ /* check for IRQs */
+ if (state != CLEAR_LINE)
+ check_irqs();
+ }
+}
+
+
+
+/***************************************************************************
+ CONTEXT SWITCHING
+***************************************************************************/
+
+static void tms32031_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(tms32031_regs *)dst = tms32031;
+}
+
+
+static void tms32031_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ tms32031 = *(tms32031_regs *)src;
+ UPDATEPC(tms32031.pc);
+
+ /* check for IRQs */
+ check_irqs();
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION AND SHUTDOWN
+***************************************************************************/
+
+static void tms32031_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const struct tms32031_config *config = _config;
+ int i;
+ char namebuf[30];
+
+ tms32031.irq_callback = irqcallback;
+
+ /* copy in the xf write routines */
+ tms32031.bootoffset = config ? config->bootoffset : 0;
+ if (config)
+ {
+ tms32031.xf0_w = config->xf0_w;
+ tms32031.xf1_w = config->xf1_w;
+ tms32031.iack_w = config->iack_w;
+ }
+
+ state_save_register_item("tms32031", index, tms32031.pc);
+ for (i=0;i<36;i++)
+ {
+ sprintf(namebuf,"tms32031.r[%d]",i);
+ state_save_register_generic("tms32031", index, namebuf, tms32031.r[i].i8, UINT8, 8);
+ }
+ state_save_register_item("tms32031", index, tms32031.bkmask);
+ state_save_register_item("tms32031", index, tms32031.ppc);
+ state_save_register_item("tms32031", index, tms32031.op);
+ state_save_register_item("tms32031", index, tms32031.delayed);
+ state_save_register_item("tms32031", index, tms32031.irq_pending);
+ state_save_register_item("tms32031", index, tms32031.mcu_mode);
+ state_save_register_item("tms32031", index, tms32031.is_idling);
+ state_save_register_item("tms32031", index, tms32031.interrupt_cycles);
+
+}
+
+static void tms32031_reset(void)
+{
+ /* if we have a config struct, get the boot ROM address */
+ if (tms32031.bootoffset)
+ {
+ tms32031.mcu_mode = 1;
+ tms32031.pc = boot_loader(tms32031.bootoffset);
+ }
+ else
+ {
+ tms32031.mcu_mode = 0;
+ tms32031.pc = RMEM(0);
+ }
+
+ /* reset some registers */
+ IREG(TMR_IE) = 0;
+ IREG(TMR_IF) = 0;
+ IREG(TMR_ST) = 0;
+ IREG(TMR_IOF) = 0;
+
+ /* reset internal stuff */
+ tms32031.delayed = tms32031.irq_pending = 0;
+ tms32031.is_idling = 0;
+}
+
+
+#if (LOG_OPCODE_USAGE)
+static UINT32 hits[0x200*4];
+#endif
+
+void tms32031_exit(void)
+{
+#if (LOG_OPCODE_USAGE)
+ int i;
+ for (i = 0; i < 0x200*4; i++)
+ if (hits[i])
+ mame_printf_debug("%10d - %03X.%X\n", hits[i], i / 4, i % 4);
+#endif
+}
+
+
+
+/***************************************************************************
+ CORE OPCODES
+***************************************************************************/
+
+#include "32031ops.c"
+
+
+
+/***************************************************************************
+ CORE EXECUTION LOOP
+***************************************************************************/
+
+static int tms32031_execute(int cycles)
+{
+ /* count cycles and interrupt cycles */
+ tms32031_icount = cycles;
+ tms32031_icount -= tms32031.interrupt_cycles;
+ tms32031.interrupt_cycles = 0;
+
+ /* check IRQs up front */
+ check_irqs();
+
+ /* if we're idling, just eat the cycles */
+ if (tms32031.is_idling)
+ return tms32031_icount;
+
+ while (tms32031_icount > 0)
+ {
+ if ((IREG(TMR_ST) & RMFLAG) && tms32031.pc == IREG(TMR_RE) + 1)
+ {
+ if ((INT32)--IREG(TMR_RC) >= 0)
+ tms32031.pc = IREG(TMR_RS);
+ else
+ {
+ IREG(TMR_ST) &= ~RMFLAG;
+ if (tms32031.delayed)
+ {
+ tms32031.delayed = 0;
+ if (tms32031.irq_pending)
+ {
+ tms32031.irq_pending = 0;
+ check_irqs();
+ }
+ }
+ }
+ continue;
+ }
+
+ execute_one();
+ }
+
+ tms32031_icount -= tms32031.interrupt_cycles;
+ tms32031.interrupt_cycles = 0;
+
+ return cycles - tms32031_icount;
+}
+
+
+
+/***************************************************************************
+ DISASSEMBLY HOOK
+***************************************************************************/
+
+#ifdef MAME_DEBUG
+static offs_t tms32031_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24);
+ extern unsigned dasm_tms32031(char *, unsigned, UINT32);
+ return dasm_tms32031(buffer, pc, op);
+}
+#endif /* MAME_DEBUG */
+
+
+
+/***************************************************************************
+ BOOT LOADER
+***************************************************************************/
+
+static UINT32 boot_loader(UINT32 boot_rom_addr)
+{
+ UINT32 bits, control, advance;
+ UINT32 start_offset = 0;
+ UINT32 datamask;
+ int first = 1, i;
+
+ /* read the size of the data */
+ bits = RMEM(boot_rom_addr);
+ if (bits != 8 && bits != 16 && bits != 32)
+ return 0;
+ datamask = 0xffffffffUL >> (32 - bits);
+ advance = 32 / bits;
+ boot_rom_addr += advance;
+
+ /* read the control register */
+ control = RMEM(boot_rom_addr++) & datamask;
+ for (i = 1; i < advance; i++)
+ control |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);
+
+ /* now parse the data */
+ while (1)
+ {
+ UINT32 offs, len;
+
+ /* read the length of this section */
+ len = RMEM(boot_rom_addr++) & datamask;
+ for (i = 1; i < advance; i++)
+ len |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);
+
+ /* stop at 0 */
+ if (len == 0)
+ return start_offset;
+
+ /* read the destination offset of this section */
+ offs = RMEM(boot_rom_addr++) & datamask;
+ for (i = 1; i < advance; i++)
+ offs |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);
+
+ /* if this is the first block, that's where we boot to */
+ if (first)
+ {
+ start_offset = offs;
+ first = 0;
+ }
+
+ /* now copy the data */
+ while (len--)
+ {
+ UINT32 data;
+
+ /* extract the 32-bit word */
+ data = RMEM(boot_rom_addr++) & datamask;
+ for (i = 1; i < advance; i++)
+ data |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);
+
+ /* write it out */
+ WMEM(offs++, data);
+ }
+ }
+
+ /* keep the compiler happy */
+ return 0;
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void tms32031_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ0: set_irq_line(TMS32031_IRQ0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ1: set_irq_line(TMS32031_IRQ1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ2: set_irq_line(TMS32031_IRQ2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ3: set_irq_line(TMS32031_IRQ3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_XINT0: set_irq_line(TMS32031_XINT0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_RINT0: set_irq_line(TMS32031_RINT0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_XINT1: set_irq_line(TMS32031_XINT1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_RINT1: set_irq_line(TMS32031_RINT1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_TINT0: set_irq_line(TMS32031_TINT0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_TINT1: set_irq_line(TMS32031_TINT1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_DINT: set_irq_line(TMS32031_DINT, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS32031_PC: tms32031.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_R0: IREG(TMR_R0) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_R1: IREG(TMR_R1) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_R2: IREG(TMR_R2) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_R3: IREG(TMR_R3) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_R4: IREG(TMR_R4) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_R5: IREG(TMR_R5) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_R6: IREG(TMR_R6) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_R7: IREG(TMR_R7) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_R0F: double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R0]); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R1F: double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R1]); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R2F: double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R2]); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R3F: double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R3]); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R4F: double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R4]); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R5F: double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R5]); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R6F: double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R6]); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R7F: double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R7]); break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR0: IREG(TMR_AR0) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR1: IREG(TMR_AR1) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR2: IREG(TMR_AR2) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR3: IREG(TMR_AR3) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR4: IREG(TMR_AR4) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR5: IREG(TMR_AR5) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR6: IREG(TMR_AR6) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR7: IREG(TMR_AR7) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_DP: IREG(TMR_DP) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_IR0: IREG(TMR_IR0) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_IR1: IREG(TMR_IR1) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_BK: IREG(TMR_BK) = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS32031_SP: IREG(TMR_SP) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_ST: IREG(TMR_ST) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_IE: IREG(TMR_IE) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_IF: IREG(TMR_IF) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_IOF: IREG(TMR_IOF) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_RS: IREG(TMR_RS) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_RE: IREG(TMR_RE) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32031_RC: IREG(TMR_RC) = info->i; break;
+ }
+}
+
+
+/**************************************************************************
+ * Internal memory map
+ **************************************************************************/
+
+static ADDRESS_MAP_START( internal_32031, ADDRESS_SPACE_PROGRAM, 32 )
+ AM_RANGE(0x809800, 0x809fff) AM_RAM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( internal_32032, ADDRESS_SPACE_PROGRAM, 32 )
+ AM_RANGE(0x87fe00, 0x87ffff) AM_RAM
+ADDRESS_MAP_END
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void tms32031_get_info(UINT32 state, cpuinfo *info)
+{
+ float ftemp;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(tms32031); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 11; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 4; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -2; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ0: info->i = (IREG(TMR_IF) & (1 << TMS32031_IRQ0)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ1: info->i = (IREG(TMR_IF) & (1 << TMS32031_IRQ1)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ2: info->i = (IREG(TMR_IF) & (1 << TMS32031_IRQ2)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ3: info->i = (IREG(TMR_IF) & (1 << TMS32031_IRQ3)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_XINT0: info->i = (IREG(TMR_IF) & (1 << TMS32031_XINT0)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_RINT0: info->i = (IREG(TMR_IF) & (1 << TMS32031_RINT0)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_XINT1: info->i = (IREG(TMR_IF) & (1 << TMS32031_XINT1)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_RINT1: info->i = (IREG(TMR_IF) & (1 << TMS32031_RINT1)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_TINT0: info->i = (IREG(TMR_IF) & (1 << TMS32031_TINT0)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_TINT1: info->i = (IREG(TMR_IF) & (1 << TMS32031_TINT1)) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + TMS32031_DINT: info->i = (IREG(TMR_IF) & (1 << TMS32031_DINT)) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = tms32031.ppc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS32031_PC: info->i = tms32031.pc; break;
+
+ case CPUINFO_INT_REGISTER + TMS32031_R0: info->i = IREG(TMR_R0); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R1: info->i = IREG(TMR_R1); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R2: info->i = IREG(TMR_R2); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R3: info->i = IREG(TMR_R3); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R4: info->i = IREG(TMR_R4); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R5: info->i = IREG(TMR_R5); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R6: info->i = IREG(TMR_R6); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R7: info->i = IREG(TMR_R7); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R0F: ftemp = dsp_to_double(&tms32031.r[TMR_R0]); info->i = f2u(ftemp); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R1F: ftemp = dsp_to_double(&tms32031.r[TMR_R1]); info->i = f2u(ftemp); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R2F: ftemp = dsp_to_double(&tms32031.r[TMR_R2]); info->i = f2u(ftemp); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R3F: ftemp = dsp_to_double(&tms32031.r[TMR_R3]); info->i = f2u(ftemp); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R4F: ftemp = dsp_to_double(&tms32031.r[TMR_R4]); info->i = f2u(ftemp); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R5F: ftemp = dsp_to_double(&tms32031.r[TMR_R5]); info->i = f2u(ftemp); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R6F: ftemp = dsp_to_double(&tms32031.r[TMR_R6]); info->i = f2u(ftemp); break;
+ case CPUINFO_INT_REGISTER + TMS32031_R7F: ftemp = dsp_to_double(&tms32031.r[TMR_R7]); info->i = f2u(ftemp); break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR0: info->i = IREG(TMR_AR0); break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR1: info->i = IREG(TMR_AR1); break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR2: info->i = IREG(TMR_AR2); break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR3: info->i = IREG(TMR_AR3); break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR4: info->i = IREG(TMR_AR4); break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR5: info->i = IREG(TMR_AR5); break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR6: info->i = IREG(TMR_AR6); break;
+ case CPUINFO_INT_REGISTER + TMS32031_AR7: info->i = IREG(TMR_AR7); break;
+ case CPUINFO_INT_REGISTER + TMS32031_DP: info->i = IREG(TMR_DP); break;
+ case CPUINFO_INT_REGISTER + TMS32031_IR0: info->i = IREG(TMR_IR0); break;
+ case CPUINFO_INT_REGISTER + TMS32031_IR1: info->i = IREG(TMR_IR1); break;
+ case CPUINFO_INT_REGISTER + TMS32031_BK: info->i = IREG(TMR_BK); break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS32031_SP: info->i = IREG(TMR_SP); break;
+ case CPUINFO_INT_REGISTER + TMS32031_ST: info->i = IREG(TMR_ST); break;
+ case CPUINFO_INT_REGISTER + TMS32031_IE: info->i = IREG(TMR_IE); break;
+ case CPUINFO_INT_REGISTER + TMS32031_IF: info->i = IREG(TMR_IF); break;
+ case CPUINFO_INT_REGISTER + TMS32031_IOF: info->i = IREG(TMR_IOF); break;
+ case CPUINFO_INT_REGISTER + TMS32031_RS: info->i = IREG(TMR_RS); break;
+ case CPUINFO_INT_REGISTER + TMS32031_RE: info->i = IREG(TMR_RE); break;
+ case CPUINFO_INT_REGISTER + TMS32031_RC: info->i = IREG(TMR_RC); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = tms32031_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tms32031_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tms32031_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = tms32031_init; break;
+ case CPUINFO_PTR_RESET: info->reset = tms32031_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = tms32031_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = tms32031_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tms32031_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &tms32031_icount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_internal_32031; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "TMS32031"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Texas Instruments TMS32031"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) Aaron Giles 2002"); break;
+
+ case CPUINFO_STR_FLAGS:
+ {
+ UINT32 temp = tms32031.r[TMR_ST].i32[0];
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ (temp & 0x80) ? 'O':'.',
+ (temp & 0x40) ? 'U':'.',
+ (temp & 0x20) ? 'V':'.',
+ (temp & 0x10) ? 'u':'.',
+ (temp & 0x08) ? 'n':'.',
+ (temp & 0x04) ? 'z':'.',
+ (temp & 0x02) ? 'v':'.',
+ (temp & 0x01) ? 'c':'.');
+ break;
+ }
+
+ case CPUINFO_STR_REGISTER + TMS32031_PC: sprintf(info->s, "PC: %08X", tms32031.pc); break;
+
+ case CPUINFO_STR_REGISTER + TMS32031_R0: sprintf(info->s, " R0:%08X", tms32031.r[TMR_R0].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R1: sprintf(info->s, " R1:%08X", tms32031.r[TMR_R1].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R2: sprintf(info->s, " R2:%08X", tms32031.r[TMR_R2].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R3: sprintf(info->s, " R3:%08X", tms32031.r[TMR_R3].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R4: sprintf(info->s, " R4:%08X", tms32031.r[TMR_R4].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R5: sprintf(info->s, " R5:%08X", tms32031.r[TMR_R5].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R6: sprintf(info->s, " R6:%08X", tms32031.r[TMR_R6].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R7: sprintf(info->s, " R7:%08X", tms32031.r[TMR_R7].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R0F: sprintf(info->s, "R0F:!%12g", dsp_to_double(&tms32031.r[TMR_R0])); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R1F: sprintf(info->s, "R1F:!%12g", dsp_to_double(&tms32031.r[TMR_R1])); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R2F: sprintf(info->s, "R2F:!%12g", dsp_to_double(&tms32031.r[TMR_R2])); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R3F: sprintf(info->s, "R3F:!%12g", dsp_to_double(&tms32031.r[TMR_R3])); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R4F: sprintf(info->s, "R4F:!%12g", dsp_to_double(&tms32031.r[TMR_R4])); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R5F: sprintf(info->s, "R5F:!%12g", dsp_to_double(&tms32031.r[TMR_R5])); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R6F: sprintf(info->s, "R6F:!%12g", dsp_to_double(&tms32031.r[TMR_R6])); break;
+ case CPUINFO_STR_REGISTER + TMS32031_R7F: sprintf(info->s, "R7F:!%12g", dsp_to_double(&tms32031.r[TMR_R7])); break;
+ case CPUINFO_STR_REGISTER + TMS32031_AR0: sprintf(info->s, "AR0:%08X", tms32031.r[TMR_AR0].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_AR1: sprintf(info->s, "AR1:%08X", tms32031.r[TMR_AR1].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_AR2: sprintf(info->s, "AR2:%08X", tms32031.r[TMR_AR2].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_AR3: sprintf(info->s, "AR3:%08X", tms32031.r[TMR_AR3].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_AR4: sprintf(info->s, "AR4:%08X", tms32031.r[TMR_AR4].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_AR5: sprintf(info->s, "AR5:%08X", tms32031.r[TMR_AR5].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_AR6: sprintf(info->s, "AR6:%08X", tms32031.r[TMR_AR6].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_AR7: sprintf(info->s, "AR7:%08X", tms32031.r[TMR_AR7].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_DP: sprintf(info->s, " DP:%02X", tms32031.r[TMR_DP].i8[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_IR0: sprintf(info->s, "IR0:%08X", tms32031.r[TMR_IR0].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_IR1: sprintf(info->s, "IR1:%08X", tms32031.r[TMR_IR1].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_BK: sprintf(info->s, " BK:%08X", tms32031.r[TMR_BK].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_SP: sprintf(info->s, " SP:%08X", tms32031.r[TMR_SP].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_ST: sprintf(info->s, " ST:%08X", tms32031.r[TMR_ST].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_IE: sprintf(info->s, " IE:%08X", tms32031.r[TMR_IE].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_IF: sprintf(info->s, " IF:%08X", tms32031.r[TMR_IF].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_IOF: sprintf(info->s, "IOF:%08X", tms32031.r[TMR_IOF].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_RS: sprintf(info->s, " RS:%08X", tms32031.r[TMR_RS].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_RE: sprintf(info->s, " RE:%08X", tms32031.r[TMR_RE].i32[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32031_RC: sprintf(info->s, " RC:%08X", tms32031.r[TMR_RC].i32[0]); break;
+ }
+}
+
+void tms32032_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_internal_32032; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "TMS32032"); break;
+
+ default: tms32031_get_info(state, info); break;
+ }
+}
diff --git a/src/emu/cpu/tms32031/tms32031.h b/src/emu/cpu/tms32031/tms32031.h
new file mode 100644
index 00000000000..3a19a6e93a7
--- /dev/null
+++ b/src/emu/cpu/tms32031/tms32031.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+
+ tms32031.h
+ Interface file for the portable TMS32C031 emulator.
+ Written by Aaron Giles
+
+***************************************************************************/
+
+#ifndef _TMS32031_H
+#define _TMS32031_H
+
+#include "cpuintrf.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct tms32031_config
+{
+ UINT32 bootoffset;
+ void (*xf0_w)(UINT8 val);
+ void (*xf1_w)(UINT8 val);
+ void (*iack_w)(UINT8 val, offs_t addr);
+};
+
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ TMS32031_PC=1,
+ TMS32031_R0,TMS32031_R1,TMS32031_R2,TMS32031_R3,
+ TMS32031_R4,TMS32031_R5,TMS32031_R6,TMS32031_R7,
+ TMS32031_R0F,TMS32031_R1F,TMS32031_R2F,TMS32031_R3F,
+ TMS32031_R4F,TMS32031_R5F,TMS32031_R6F,TMS32031_R7F,
+ TMS32031_AR0,TMS32031_AR1,TMS32031_AR2,TMS32031_AR3,
+ TMS32031_AR4,TMS32031_AR5,TMS32031_AR6,TMS32031_AR7,
+ TMS32031_DP,TMS32031_IR0,TMS32031_IR1,TMS32031_BK,
+ TMS32031_SP,TMS32031_ST,TMS32031_IE,TMS32031_IF,
+ TMS32031_IOF,TMS32031_RS,TMS32031_RE,TMS32031_RC
+};
+
+
+/***************************************************************************
+ INTERRUPT CONSTANTS
+***************************************************************************/
+
+#define TMS32031_IRQ0 0 /* IRQ0 */
+#define TMS32031_IRQ1 1 /* IRQ1 */
+#define TMS32031_IRQ2 2 /* IRQ2 */
+#define TMS32031_IRQ3 3 /* IRQ3 */
+#define TMS32031_XINT0 4 /* serial 0 transmit interrupt */
+#define TMS32031_RINT0 5 /* serial 0 receive interrupt */
+#define TMS32031_XINT1 6 /* serial 1 transmit interrupt */
+#define TMS32031_RINT1 7 /* serial 1 receive interrupt */
+#define TMS32031_TINT0 8 /* timer 0 interrupt */
+#define TMS32031_TINT1 9 /* timer 1 interrupt */
+#define TMS32031_DINT 10 /* DMA interrupt */
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+extern void tms32031_get_info(UINT32 state, cpuinfo *info);
+extern void tms32032_get_info(UINT32 state, cpuinfo *info);
+
+#endif /* _TMS32031_H */
diff --git a/src/emu/cpu/tms32051/32051ops.c b/src/emu/cpu/tms32051/32051ops.c
new file mode 100644
index 00000000000..d81ad4f995d
--- /dev/null
+++ b/src/emu/cpu/tms32051/32051ops.c
@@ -0,0 +1,1961 @@
+INLINE void PUSH_STACK(UINT16 pc)
+{
+ if (tms.pcstack_ptr >= 8)
+ {
+ fatalerror("32051: stack overflow at %04X!\n", tms.pc);
+ }
+
+ tms.pcstack[tms.pcstack_ptr] = pc;
+ tms.pcstack_ptr++;
+}
+
+INLINE UINT16 POP_STACK(void)
+{
+ UINT16 pc;
+ tms.pcstack_ptr--;
+ if (tms.pcstack_ptr < 0)
+ {
+ fatalerror("32051: stack underflow at %04X!\n", tms.pc);
+ }
+
+ pc = tms.pcstack[tms.pcstack_ptr];
+ return pc;
+}
+
+INLINE INT32 SUB(INT32 a, INT32 b, int shift16)
+{
+ INT64 res = a - b;
+ if (tms.st0.ovm) // overflow saturation mode
+ {
+ if ((res & 0x80000000) && ((UINT32)(res >> 32) & 0xffffffff) != 0xffffffff)
+ {
+ res = 0x80000000;
+ }
+ else if (((res & 0x80000000) == 0) && ((UINT32)(res >> 32) & 0xffffffff) != 0)
+ {
+ res = 0x7fffffff;
+ }
+ }
+ else // normal mode, result is not modified
+ {
+ // set OV flag if overflow occured, this is a sticky flag
+ if (((a) ^ (b)) & ((a) ^ ((INT32)res)) & 0x80000000)
+ {
+ tms.st0.ov = 1;
+ }
+ }
+
+ // set carry
+ if (!shift16)
+ {
+ // C is cleared if borrow was generated
+ if (((UINT64)(a) + (UINT64)(~b)) & U64(0x100000000))
+ {
+ tms.st1.c = 0;
+ }
+ else
+ {
+ tms.st1.c = 1;
+ }
+ }
+ else
+ {
+ // if 16-bit shift, C is cleared if borrow was generated, otherwise C is unaffected
+ if (((UINT64)(a) + (UINT64)(~b)) & U64(0x100000000))
+ {
+ tms.st1.c = 0;
+ }
+ }
+
+ return (INT32)(res);
+}
+
+INLINE INT32 ADD(INT32 a, INT32 b, int shift16)
+{
+ INT64 res = a + b;
+ if (tms.st0.ovm) // overflow saturation mode
+ {
+ if ((res & 0x80000000) && ((UINT32)(res >> 32) & 0xffffffff) != 0xffffffff)
+ {
+ res = 0x80000000;
+ }
+ else if (((res & 0x80000000) == 0) && ((UINT32)(res >> 32) & 0xffffffff) != 0)
+ {
+ res = 0x7fffffff;
+ }
+ }
+ else // normal mode, result is not modified
+ {
+ // set OV flag if overflow occured, this is a sticky flag
+ if (((res) ^ (b)) & ((res) ^ (a)) & 0x80000000)
+ {
+ tms.st0.ov = 1;
+ }
+ }
+
+ // set carry
+ if (!shift16)
+ {
+ // C is set if carry was generated
+ if (res & U64(0x100000000))
+ {
+ tms.st1.c = 1;
+ }
+ else
+ {
+ tms.st1.c = 0;
+ }
+ }
+ else
+ {
+ // if 16-bit shift, C is set carry was generated, otherwise C is unaffected
+ if (res & U64(0x100000000))
+ {
+ tms.st1.c = 1;
+ }
+ }
+
+ return (INT32)(res);
+}
+
+
+INLINE void UPDATE_AR(int ar, int step)
+{
+ int cenb1 = (tms.cbcr >> 3) & 0x1;
+ int car1 = tms.cbcr & 0x7;
+ int cenb2 = (tms.cbcr >> 7) & 0x1;
+ int car2 = (tms.cbcr >> 4) & 0x7;
+
+ if (cenb1 && ar == car1)
+ {
+ // update circular buffer 1
+ if (tms.ar[ar] == tms.cber1)
+ {
+ tms.ar[ar] = tms.cbsr1;
+ }
+ else
+ {
+ tms.ar[ar] += step;
+ }
+ }
+ else if (cenb2 && ar == car2)
+ {
+ // update circular buffer 2
+ if (tms.ar[ar] == tms.cber2)
+ {
+ tms.ar[ar] = tms.cbsr2;
+ }
+ else
+ {
+ tms.ar[ar] += step;
+ }
+ }
+ else
+ {
+ tms.ar[ar] += step;
+ }
+}
+
+INLINE void UPDATE_ARP(int nar)
+{
+ tms.st1.arb = tms.st0.arp;
+ tms.st0.arp = nar;
+}
+
+static UINT16 GET_ADDRESS(void)
+{
+ if (tms.op & 0x80) // Indirect Addressing
+ {
+ UINT16 ea;
+ int arp = tms.st0.arp;
+ int nar = tms.op & 0x7;
+
+ ea = tms.ar[arp];
+
+ switch ((tms.op >> 3) & 0xf)
+ {
+ case 0x0: // * (no operation)
+ {
+ break;
+ }
+ case 0x1: // *, ARn (NAR -> ARP)
+ {
+ UPDATE_ARP(nar);
+ break;
+ }
+ case 0x2: // *- ((CurrentAR)-1 -> CurrentAR)
+ {
+ UPDATE_AR(arp, -1);
+ break;
+ }
+ case 0x3: // *-, ARn ((CurrentAR)-1 -> CurrentAR, NAR -> ARP)
+ {
+ UPDATE_AR(arp, -1);
+ UPDATE_ARP(nar);
+ break;
+ }
+ case 0x4: // *+ ((CurrentAR)+1 -> CurrentAR)
+ {
+ UPDATE_AR(arp, 1);
+ break;
+ }
+ case 0x5: // *+, ARn ((CurrentAR)+1 -> CurrentAR, NAR -> ARP)
+ {
+ UPDATE_AR(arp, 1);
+ UPDATE_ARP(nar);
+ break;
+ }
+ case 0xa: // *0- ((CurrentAR) - INDX)
+ {
+ UPDATE_AR(arp, -tms.indx);
+ break;
+ }
+ case 0xb: // *0-, ARn ((CurrentAR) - INDX -> CurrentAR, NAR -> ARP)
+ {
+ UPDATE_AR(arp, -tms.indx);
+ UPDATE_ARP(nar);
+ break;
+ }
+ case 0xc: // *0+ ((CurrentAR) + INDX -> CurrentAR)
+ {
+ UPDATE_AR(arp, tms.indx);
+ break;
+ }
+ case 0xd: // *0+, ARn ((CurrentAR) + INDX -> CurrentAR, NAR -> ARP)
+ {
+ UPDATE_AR(arp, tms.indx);
+ UPDATE_ARP(nar);
+ break;
+ }
+
+ default: fatalerror("32051: GET_ADDRESS: unimplemented indirect addressing mode %d at %04X (%04X)\n", (tms.op >> 3) & 0xf, tms.pc, tms.op);
+ }
+
+ return ea;
+ }
+ else // Direct Addressing
+ {
+ return tms.st0.dp | (tms.op & 0x7f);
+ }
+}
+
+static int GET_ZLVC_CONDITION(int zlvc, int zlvc_mask)
+{
+ int condition = 0;
+
+ if (zlvc_mask & 0x8) // Z-bit
+ {
+ if ((zlvc & 0x8) && (INT32)(tms.acc) == 0) // EQ
+ {
+ condition = 1;
+ }
+ else if ((zlvc & 0x8) == 0 && (INT32)(tms.acc) != 0) // NEQ
+ {
+ condition = 1;
+ }
+ }
+ if (zlvc_mask & 0x4) // L-bit
+ {
+ if ((zlvc & 0x4) && (INT32)(tms.acc) < 0) // LT
+ {
+ condition = 1;
+ }
+ else if ((zlvc & 0x4) == 0 && (INT32)(tms.acc) > 0) // GT
+ {
+ condition = 1;
+ }
+ }
+ if (zlvc_mask & 0x2) // OV-bit
+ {
+ if ((zlvc & 0x2) && tms.st0.ov) // OV
+ {
+ condition = 1;
+ }
+ else if ((zlvc & 0x2) == 0 && tms.st0.ov == 0) // NOV
+ {
+ condition = 1;
+ }
+ }
+ if (zlvc_mask & 0x1) // C-bit
+ {
+ if ((zlvc & 0x1) && tms.st1.c) // C
+ {
+ condition = 1;
+ }
+ else if ((zlvc & 0x1) == 0 && tms.st1.c == 0) // NC
+ {
+ condition = 1;
+ }
+ }
+
+ return condition;
+}
+
+static int GET_TP_CONDITION(int tp)
+{
+ switch (tp)
+ {
+ case 0: // BIO pin low
+ {
+ // TODO
+ return 0;
+ }
+ case 1: // TC = 1
+ {
+ return (tms.st1.tc == 1) ? 1 : 0;
+ }
+ case 2: // TC = 0
+ {
+ return (tms.st1.tc == 0) ? 1 : 0;
+ }
+ case 3: // always false
+ {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+INLINE INT32 PREG_PSCALER(INT32 preg)
+{
+ switch (tms.st1.pm & 3)
+ {
+ case 0: // No shift
+ {
+ return preg;
+ }
+ case 1: // Left-shifted 1 bit, LSB zero-filled
+ {
+ return preg << 1;
+ }
+ case 2: // Left-shifted 4 bits, 4 LSBs zero-filled
+ {
+ return preg << 4;
+ }
+ case 3: // Right-shifted 6 bits, sign-extended, 6 LSBs lost
+ {
+ return (INT32)(preg >> 6);
+ }
+ }
+ return 0;
+}
+
+
+
+static void op_invalid(void)
+{
+ fatalerror("32051: invalid op at %08X", tms.pc-1);
+}
+
+static void op_group_be(void);
+static void op_group_bf(void);
+
+/*****************************************************************************/
+
+static void op_abs(void)
+{
+ fatalerror("32051: unimplemented op abs at %08X", tms.pc-1);
+}
+
+static void op_adcb(void)
+{
+ fatalerror("32051: unimplemented op adcb at %08X", tms.pc-1);
+}
+
+static void op_add_mem(void)
+{
+ INT32 d;
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ int shift = (tms.op >> 8) & 0xf;
+
+ if (tms.st1.sxm)
+ {
+ d = (INT32)(INT16)(data) << shift;
+ }
+ else
+ {
+ d = (UINT32)(UINT16)(data) << shift;
+ }
+
+ tms.acc = ADD(tms.acc, d, 0);
+
+ CYCLES(1);
+}
+
+static void op_add_simm(void)
+{
+ UINT16 imm = tms.op & 0xff;
+
+ tms.acc = ADD(tms.acc, imm, 0);
+
+ CYCLES(1);
+}
+
+static void op_add_limm(void)
+{
+ INT32 d;
+ UINT16 imm = ROPCODE();
+ int shift = tms.op & 0xf;
+
+ if (tms.st1.sxm)
+ {
+ d = (INT32)(INT16)(imm) << shift;
+ }
+ else
+ {
+ d = (UINT32)(UINT16)(imm) << shift;
+ }
+
+ tms.acc = ADD(tms.acc, d, 0);
+
+ CYCLES(2);
+}
+
+static void op_add_s16_mem(void)
+{
+ fatalerror("32051: unimplemented op add s16 mem at %08X", tms.pc-1);
+}
+
+static void op_addb(void)
+{
+ tms.acc = ADD(tms.acc, tms.accb, 0);
+
+ CYCLES(1);
+}
+
+static void op_addc(void)
+{
+ fatalerror("32051: unimplemented op addc at %08X", tms.pc-1);
+}
+
+static void op_adds(void)
+{
+ fatalerror("32051: unimplemented op adds at %08X", tms.pc-1);
+}
+
+static void op_addt(void)
+{
+ fatalerror("32051: unimplemented op addt at %08X", tms.pc-1);
+}
+
+static void op_and_mem(void)
+{
+ fatalerror("32051: unimplemented op and mem at %08X", tms.pc-1);
+}
+
+static void op_and_limm(void)
+{
+ UINT32 imm = ROPCODE();
+ int shift = tms.op & 0xf;
+
+ tms.acc &= imm << shift;
+
+ CYCLES(2);
+}
+
+static void op_and_s16_limm(void)
+{
+ fatalerror("32051: unimplemented op and s16 limm at %08X", tms.pc-1);
+}
+
+static void op_andb(void)
+{
+ fatalerror("32051: unimplemented op andb at %08X", tms.pc-1);
+}
+
+static void op_bsar(void)
+{
+ int shift = (tms.op & 0xf) + 1;
+
+ if (tms.st1.sxm)
+ {
+ tms.acc = (INT32)(tms.acc) >> shift;
+ }
+ else
+ {
+ tms.acc = (UINT32)(tms.acc) >> shift;
+ }
+
+ CYCLES(1);
+}
+
+static void op_cmpl(void)
+{
+ tms.acc = ~tms.acc;
+
+ CYCLES(1);
+}
+
+static void op_crgt(void)
+{
+ if (tms.acc > tms.accb)
+ {
+ tms.accb = tms.acc;
+ tms.st1.c = 1;
+ }
+ else if (tms.acc < tms.accb)
+ {
+ tms.acc = tms.accb;
+ tms.st1.c = 0;
+ }
+ else
+ {
+ tms.st1.c = 1;
+ }
+
+ CYCLES(1);
+}
+
+static void op_crlt(void)
+{
+ if (tms.acc < tms.accb)
+ {
+ tms.accb = tms.acc;
+ tms.st1.c = 1;
+ }
+ else if (tms.acc > tms.accb)
+ {
+ tms.acc = tms.accb;
+ tms.st1.c = 0;
+ }
+ else
+ {
+ tms.st1.c = 0;
+ }
+
+ CYCLES(1);
+}
+
+static void op_exar(void)
+{
+ INT32 tmp = tms.acc;
+ tms.acc = tms.accb;
+ tms.accb = tmp;
+
+ CYCLES(1);
+}
+
+static void op_lacb(void)
+{
+ tms.acc = tms.accb;
+
+ CYCLES(1);
+}
+
+static void op_lacc_mem(void)
+{
+ int shift = (tms.op >> 8) & 0xf;
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+
+ if (tms.st1.sxm)
+ {
+ tms.acc = (INT32)(INT16)(data) << shift;
+ }
+ else
+ {
+ tms.acc = (UINT32)(UINT16)(data) << shift;
+ }
+
+ CYCLES(1);
+}
+
+static void op_lacc_limm(void)
+{
+ UINT16 imm = ROPCODE();
+ int shift = tms.op & 0xf;
+
+ if (tms.st1.sxm)
+ {
+ tms.acc = (INT32)(INT16)(imm) << shift;
+ }
+ else
+ {
+ tms.acc = (UINT32)(UINT16)(imm) << shift;
+ }
+
+ CYCLES(1);
+}
+
+static void op_lacc_s16_mem(void)
+{
+ UINT16 ea = GET_ADDRESS();
+
+ if (tms.st1.sxm)
+ {
+ tms.acc = (INT32)(INT16)(DM_READ16(ea)) << 16;
+ }
+ else
+ {
+ tms.acc = (UINT32)(DM_READ16(ea)) << 16;
+ }
+
+ CYCLES(1);
+}
+
+static void op_lacl_simm(void)
+{
+ tms.acc = tms.op & 0xff;
+
+ CYCLES(1);
+}
+
+static void op_lacl_mem(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ tms.acc = DM_READ16(ea) & 0xffff;
+
+ CYCLES(1);
+}
+
+static void op_lact(void)
+{
+ fatalerror("32051: unimplemented op lact at %08X", tms.pc-1);
+}
+
+static void op_lamm(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ ea &= 0x7f;
+
+ tms.acc = DM_READ16(ea) & 0xffff;
+ CYCLES(1);
+}
+
+static void op_neg(void)
+{
+ if ((UINT32)(tms.acc) == 0x80000000)
+ {
+ tms.st0.ov = 1;
+ if (tms.st0.ovm)
+ {
+ tms.acc = 0x7fffffff;
+ }
+ else
+ {
+ tms.acc = 0x80000000;
+ }
+ }
+ else
+ {
+ tms.acc = 0 - (UINT32)(tms.acc);
+
+ if (tms.acc == 0)
+ {
+ tms.st1.c = 1;
+ }
+ else
+ {
+ tms.st1.c = 0;
+ }
+ }
+
+ CYCLES(1);
+}
+
+static void op_norm(void)
+{
+ fatalerror("32051: unimplemented op norm at %08X", tms.pc-1);
+}
+
+static void op_or_mem(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+
+ tms.acc |= (UINT32)(data);
+
+ CYCLES(1);
+}
+
+static void op_or_limm(void)
+{
+ UINT32 imm = ROPCODE();
+ int shift = tms.op & 0xf;
+
+ tms.acc |= imm << shift;
+
+ CYCLES(1);
+}
+
+static void op_or_s16_limm(void)
+{
+ fatalerror("32051: unimplemented op or s16 limm at %08X", tms.pc-1);
+}
+
+static void op_orb(void)
+{
+ tms.acc |= tms.accb;
+
+ CYCLES(1);
+}
+
+static void op_rol(void)
+{
+ fatalerror("32051: unimplemented op rol at %08X", tms.pc-1);
+}
+
+static void op_rolb(void)
+{
+ UINT32 acc = tms.acc;
+ UINT32 accb = tms.accb;
+ UINT32 c = tms.st1.c & 1;
+
+ tms.acc = (acc << 1) | ((accb >> 31) & 1);
+ tms.accb = (accb << 1) | c;
+ tms.st1.c = (acc >> 31) & 1;
+
+ CYCLES(1);
+}
+
+static void op_ror(void)
+{
+ fatalerror("32051: unimplemented op ror at %08X", tms.pc-1);
+}
+
+static void op_rorb(void)
+{
+ fatalerror("32051: unimplemented op rorb at %08X", tms.pc-1);
+}
+
+static void op_sacb(void)
+{
+ tms.accb = tms.acc;
+
+ CYCLES(1);
+}
+
+static void op_sach(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ int shift = (tms.op >> 8) & 0x7;
+
+ DM_WRITE16(ea, (UINT16)((tms.acc << shift) >> 16));
+ CYCLES(1);
+}
+
+static void op_sacl(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ int shift = (tms.op >> 8) & 0x7;
+
+ DM_WRITE16(ea, (UINT16)(tms.acc << shift));
+ CYCLES(1);
+}
+
+static void op_samm(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ ea &= 0x7f;
+
+ DM_WRITE16(ea, (UINT16)(tms.acc));
+ CYCLES(1);
+}
+
+static void op_sath(void)
+{
+ fatalerror("32051: unimplemented op sath at %08X", tms.pc-1);
+}
+
+static void op_satl(void)
+{
+ fatalerror("32051: unimplemented op satl at %08X", tms.pc-1);
+}
+
+static void op_sbb(void)
+{
+ tms.acc = SUB(tms.acc, tms.accb, 0);
+
+ CYCLES(1);
+}
+
+static void op_sbbb(void)
+{
+ fatalerror("32051: unimplemented op sbbb at %08X", tms.pc-1);
+}
+
+static void op_sfl(void)
+{
+ tms.st1.c = (tms.acc >> 31) & 1;
+ tms.acc = tms.acc << 1;
+
+ CYCLES(1);
+}
+
+static void op_sflb(void)
+{
+ UINT32 acc = tms.acc;
+ UINT32 accb = tms.accb;
+
+ tms.acc = (acc << 1) | ((accb >> 31) & 1);
+ tms.accb = (accb << 1);
+ tms.st1.c = (acc >> 31) & 1;
+
+ CYCLES(1);
+}
+
+static void op_sfr(void)
+{
+ tms.st1.c = tms.acc & 1;
+
+ if (tms.st1.sxm)
+ {
+ tms.acc = (INT32)(tms.acc) >> 1;
+ }
+ else
+ {
+ tms.acc = (UINT32)(tms.acc) >> 1;
+ }
+
+ CYCLES(1);
+}
+
+static void op_sfrb(void)
+{
+ fatalerror("32051: unimplemented op sfrb at %08X", tms.pc-1);
+}
+
+static void op_sub_mem(void)
+{
+ INT32 d;
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ int shift = (tms.op >> 8) & 0xf;
+
+ if (tms.st1.sxm)
+ {
+ d = (INT32)(INT16)(data) << shift;
+ }
+ else
+ {
+ d = (UINT32)(UINT16)(data) << shift;
+ }
+
+ tms.acc = SUB(tms.acc, d, 0);
+
+ CYCLES(1);
+}
+
+static void op_sub_s16_mem(void)
+{
+ fatalerror("32051: unimplemented op sub s16 mem at %08X", tms.pc-1);
+}
+
+static void op_sub_simm(void)
+{
+ UINT16 imm = tms.op & 0xff;
+
+ tms.acc = SUB(tms.acc, imm, 0);
+
+ CYCLES(1);
+}
+
+static void op_sub_limm(void)
+{
+ INT32 d;
+ UINT16 imm = ROPCODE();
+ int shift = tms.op & 0xf;
+
+ if (tms.st1.sxm)
+ {
+ d = (INT32)(INT16)(imm) << shift;
+ }
+ else
+ {
+ d = (UINT32)(UINT16)(imm) << shift;
+ }
+
+ tms.acc = SUB(tms.acc, d, 0);
+
+ CYCLES(2);
+}
+
+static void op_subb(void)
+{
+ fatalerror("32051: unimplemented op subb at %08X", tms.pc-1);
+}
+
+static void op_subc(void)
+{
+ fatalerror("32051: unimplemented op subc at %08X", tms.pc-1);
+}
+
+static void op_subs(void)
+{
+ fatalerror("32051: unimplemented op subs at %08X", tms.pc-1);
+}
+
+static void op_subt(void)
+{
+ fatalerror("32051: unimplemented op subt at %08X", tms.pc-1);
+}
+
+static void op_xor_mem(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+
+ tms.acc ^= (UINT32)(data);
+
+ CYCLES(1);
+}
+
+static void op_xor_limm(void)
+{
+ UINT32 imm = ROPCODE();
+ int shift = tms.op & 0xf;
+
+ tms.acc ^= imm << shift;
+
+ CYCLES(1);
+}
+
+static void op_xor_s16_limm(void)
+{
+ fatalerror("32051: unimplemented op xor s16 limm at %08X", tms.pc-1);
+}
+
+static void op_xorb(void)
+{
+ fatalerror("32051: unimplemented op xorb at %08X", tms.pc-1);
+}
+
+static void op_zalr(void)
+{
+ fatalerror("32051: unimplemented op zalr at %08X", tms.pc-1);
+}
+
+static void op_zap(void)
+{
+ tms.acc = 0;
+ tms.preg = 0;
+
+ CYCLES(1);
+}
+
+/*****************************************************************************/
+
+static void op_adrk(void)
+{
+ UINT16 imm = tms.op & 0xff;
+ UPDATE_AR(tms.st0.arp, imm);
+
+ CYCLES(1);
+}
+
+static void op_cmpr(void)
+{
+ tms.st1.tc = 0;
+
+ switch (tms.op & 0x3)
+ {
+ case 0: // (CurrentAR) == ARCR
+ {
+ if (tms.ar[tms.st0.arp] == tms.arcr)
+ {
+ tms.st1.tc = 1;
+ }
+ break;
+ }
+ case 1: // (CurrentAR) < ARCR
+ {
+ if (tms.ar[tms.st0.arp] < tms.arcr)
+ {
+ tms.st1.tc = 1;
+ }
+ break;
+ }
+ case 2: // (CurrentAR) > ARCR
+ {
+ if (tms.ar[tms.st0.arp] > tms.arcr)
+ {
+ tms.st1.tc = 1;
+ }
+ break;
+ }
+ case 3: // (CurrentAR) != ARCR
+ {
+ if (tms.ar[tms.st0.arp] != tms.arcr)
+ {
+ tms.st1.tc = 1;
+ }
+ break;
+ }
+ }
+
+ CYCLES(1);
+}
+
+static void op_lar_mem(void)
+{
+ int arx = (tms.op >> 8) & 0x7;
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+
+ tms.ar[arx] = data;
+
+ CYCLES(2);
+}
+
+static void op_lar_simm(void)
+{
+ int arx = (tms.op >> 8) & 0x7;
+ tms.ar[arx] = tms.op & 0xff;
+
+ CYCLES(2);
+}
+
+static void op_lar_limm(void)
+{
+ int arx = tms.op & 0x7;
+ UINT16 imm = ROPCODE();
+ tms.ar[arx] = imm;
+
+ CYCLES(2);
+}
+
+static void op_ldp_mem(void)
+{
+ fatalerror("32051: unimplemented op ldp mem at %08X", tms.pc-1);
+}
+
+static void op_ldp_imm(void)
+{
+ tms.st0.dp = (tms.op & 0x1ff) << 7;
+ CYCLES(2);
+}
+
+static void op_mar(void)
+{
+ // direct addressing is NOP
+ if (tms.op & 0x80)
+ {
+ GET_ADDRESS();
+ }
+ CYCLES(1);
+}
+
+static void op_sar(void)
+{
+ int arx = (tms.op >> 8) & 0x7;
+ UINT16 ar = tms.ar[arx];
+ UINT16 ea = GET_ADDRESS();
+ DM_WRITE16(ea, ar);
+
+ CYCLES(1);
+}
+
+static void op_sbrk(void)
+{
+ UINT16 imm = tms.op & 0xff;
+ UPDATE_AR(tms.st0.arp, -imm);
+
+ CYCLES(1);
+}
+
+/*****************************************************************************/
+
+static void op_b(void)
+{
+ UINT16 pma = ROPCODE();
+ GET_ADDRESS(); // update AR/ARP
+
+ CHANGE_PC(pma);
+ CYCLES(4);
+}
+
+static void op_bacc(void)
+{
+ CHANGE_PC((UINT16)(tms.acc));
+
+ CYCLES(4);
+}
+
+static void op_baccd(void)
+{
+ UINT16 pc = (UINT16)(tms.acc);
+
+ delay_slot(tms.pc);
+ CHANGE_PC(pc);
+
+ CYCLES(2);
+}
+
+static void op_banz(void)
+{
+ UINT16 pma = ROPCODE();
+
+ if (tms.ar[tms.st0.arp] != 0)
+ {
+ CHANGE_PC(pma);
+ CYCLES(4);
+ }
+ else
+ {
+ CYCLES(2);
+ }
+
+ GET_ADDRESS(); // modify AR/ARP
+}
+
+static void op_banzd(void)
+{
+ fatalerror("32051: unimplemented op banzd at %08X", tms.pc-1);
+}
+
+static void op_bcnd(void)
+{
+ UINT16 pma = ROPCODE();
+
+ int zlvc_condition = GET_ZLVC_CONDITION((tms.op >> 4) & 0xf, tms.op & 0xf);
+ int tp_condition = GET_TP_CONDITION((tms.op >> 8) & 0x3);
+
+ if (zlvc_condition || tp_condition)
+ {
+ CHANGE_PC(pma);
+ CYCLES(4);
+ }
+ else
+ {
+ CYCLES(2);
+ }
+}
+
+static void op_bcndd(void)
+{
+ UINT16 pma = ROPCODE();
+
+ int zlvc_condition = GET_ZLVC_CONDITION((tms.op >> 4) & 0xf, tms.op & 0xf);
+ int tp_condition = GET_TP_CONDITION((tms.op >> 8) & 0x3);
+
+ if (zlvc_condition || tp_condition)
+ {
+ delay_slot(tms.pc);
+ CHANGE_PC(pma);
+ CYCLES(4);
+ }
+ else
+ {
+ CYCLES(2);
+ }
+}
+
+static void op_bd(void)
+{
+ UINT16 pma = ROPCODE();
+ GET_ADDRESS(); // update AR/ARP
+
+ delay_slot(tms.pc);
+ CHANGE_PC(pma);
+ CYCLES(2);
+}
+
+static void op_cala(void)
+{
+ PUSH_STACK(tms.pc);
+
+ CHANGE_PC(tms.acc);
+
+ CYCLES(4);
+}
+
+static void op_calad(void)
+{
+ UINT16 pma = tms.acc;
+ PUSH_STACK(tms.pc+2);
+
+ delay_slot(tms.pc);
+ CHANGE_PC(pma);
+
+ CYCLES(4);
+}
+
+static void op_call(void)
+{
+ UINT16 pma = ROPCODE();
+ GET_ADDRESS(); // update AR/ARP
+ PUSH_STACK(tms.pc);
+
+ CHANGE_PC(pma);
+
+ CYCLES(4);
+}
+
+static void op_calld(void)
+{
+ UINT16 pma = ROPCODE();
+ GET_ADDRESS(); // update AR/ARP
+ PUSH_STACK(tms.pc+2);
+
+ delay_slot(tms.pc);
+ CHANGE_PC(pma);
+
+ CYCLES(4);
+}
+
+static void op_cc(void)
+{
+ fatalerror("32051: unimplemented op cc at %08X", tms.pc-1);
+}
+
+static void op_ccd(void)
+{
+ UINT16 pma = ROPCODE();
+ int zlvc_condition = GET_ZLVC_CONDITION((tms.op >> 4) & 0xf, tms.op & 0xf);
+ int tp_condition = GET_TP_CONDITION((tms.op >> 8) & 0x3);
+
+ if (zlvc_condition || tp_condition)
+ {
+ PUSH_STACK(tms.pc+2);
+
+ delay_slot(tms.pc);
+ CHANGE_PC(pma);
+ }
+
+ CYCLES(2);
+}
+
+static void op_intr(void)
+{
+ fatalerror("32051: unimplemented op intr at %08X", tms.pc-1);
+}
+
+static void op_nmi(void)
+{
+ fatalerror("32051: unimplemented op nmi at %08X", tms.pc-1);
+}
+
+static void op_retc(void)
+{
+ int condition = 0;
+
+ if ((tms.op & 0x3ff) == 0x300) // RET
+ {
+ condition = 1;
+ }
+ else
+ {
+ int zlvc_condition = GET_ZLVC_CONDITION((tms.op >> 4) & 0xf, tms.op & 0xf);
+ int tp_condition = GET_TP_CONDITION((tms.op >> 8) & 0x3);
+ condition = zlvc_condition || tp_condition;
+ }
+
+ if (condition)
+ {
+ UINT16 pc = POP_STACK();
+ CHANGE_PC(pc);
+ CYCLES(4);
+ }
+ else
+ {
+ CYCLES(2);
+ }
+}
+
+static void op_retcd(void)
+{
+ int condition = 0;
+
+ if ((tms.op & 0x3ff) == 0x300) // RETD
+ {
+ condition = 1;
+ }
+ else
+ {
+ int zlvc_condition = GET_ZLVC_CONDITION((tms.op >> 4) & 0xf, tms.op & 0xf);
+ int tp_condition = GET_TP_CONDITION((tms.op >> 8) & 0x3);
+ condition = zlvc_condition || tp_condition;
+ }
+
+ if (condition)
+ {
+ UINT16 pc = POP_STACK();
+ delay_slot(tms.pc);
+ CHANGE_PC(pc);
+ CYCLES(4);
+ }
+ else
+ {
+ CYCLES(2);
+ }
+}
+
+static void op_rete(void)
+{
+ UINT16 pc = POP_STACK();
+ CHANGE_PC(pc);
+
+ tms.st0.intm = 0;
+
+ restore_interrupt_context();
+
+ CYCLES(4);
+}
+
+static void op_reti(void)
+{
+ fatalerror("32051: unimplemented op reti at %08X", tms.pc-1);
+}
+
+static void op_trap(void)
+{
+ fatalerror("32051: unimplemented op trap at %08X", tms.pc-1);
+}
+
+static void op_xc(void)
+{
+ int n = ((tms.op >> 12) & 0x1) + 1;
+ int zlvc_condition = GET_ZLVC_CONDITION((tms.op >> 4) & 0xf, tms.op & 0xf);
+ int tp_condition = GET_TP_CONDITION((tms.op >> 8) & 0x3);
+
+ if (zlvc_condition || tp_condition)
+ {
+ CYCLES(1);
+ }
+ else
+ {
+ CHANGE_PC(tms.pc + n);
+ CYCLES(1 + n);
+ }
+}
+
+/*****************************************************************************/
+
+static void op_bldd_slimm(void)
+{
+ UINT16 pfc = ROPCODE();
+
+ while (tms.rptc > -1)
+ {
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(pfc);
+ DM_WRITE16(ea, data);
+ pfc++;
+ CYCLES(2);
+
+ tms.rptc--;
+ };
+}
+
+static void op_bldd_dlimm(void)
+{
+ UINT16 pfc = ROPCODE();
+
+ while (tms.rptc > -1)
+ {
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ DM_WRITE16(pfc, data);
+ pfc++;
+ CYCLES(2);
+
+ tms.rptc--;
+ };
+}
+
+static void op_bldd_sbmar(void)
+{
+ fatalerror("32051: unimplemented op bldd sbmar at %08X", tms.pc-1);
+}
+
+static void op_bldd_dbmar(void)
+{
+ UINT16 pfc = tms.bmar;
+
+ while (tms.rptc > -1)
+ {
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ DM_WRITE16(pfc, data);
+ pfc++;
+ CYCLES(2);
+
+ tms.rptc--;
+ };
+}
+
+static void op_bldp(void)
+{
+ UINT16 pfc = tms.bmar;
+
+ while (tms.rptc > -1)
+ {
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ PM_WRITE16(pfc, data);
+ pfc++;
+ CYCLES(1);
+
+ tms.rptc--;
+ };
+}
+
+static void op_blpd_bmar(void)
+{
+ fatalerror("32051: unimplemented op bpld bmar at %08X", tms.pc-1);
+}
+
+static void op_blpd_imm(void)
+{
+ UINT16 pfc = ROPCODE();
+
+ while (tms.rptc > -1)
+ {
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = PM_READ16(pfc);
+ DM_WRITE16(ea, data);
+ pfc++;
+ CYCLES(2);
+
+ tms.rptc--;
+ };
+}
+
+/*****************************************************************************/
+
+static void op_dmov(void)
+{
+ fatalerror("32051: unimplemented op dmov at %08X", tms.pc-1);
+}
+
+static void op_in(void)
+{
+ fatalerror("32051: unimplemented op in at %08X", tms.pc-1);
+}
+
+static void op_lmmr(void)
+{
+ UINT16 pfc = ROPCODE();
+
+ while (tms.rptc > -1)
+ {
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(pfc);
+ DM_WRITE16(ea & 0x7f, data);
+ pfc++;
+ CYCLES(2);
+
+ tms.rptc--;
+ };
+}
+
+static void op_out(void)
+{
+ fatalerror("32051: unimplemented op out at %08X", tms.pc-1);
+}
+
+static void op_smmr(void)
+{
+ UINT16 pfc = ROPCODE();
+
+ while (tms.rptc > -1)
+ {
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea & 0x7f);
+ DM_WRITE16(pfc, data);
+ pfc++;
+ CYCLES(2);
+
+ tms.rptc--;
+ };
+}
+
+static void op_tblr(void)
+{
+ UINT16 pfc = (UINT16)(tms.acc);
+
+ while (tms.rptc > -1)
+ {
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = PM_READ16(pfc);
+ DM_WRITE16(ea, data);
+ pfc++;
+ CYCLES(2);
+
+ tms.rptc--;
+ };
+}
+
+static void op_tblw(void)
+{
+ UINT16 pfc = (UINT16)(tms.acc);
+
+ while (tms.rptc > -1)
+ {
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ PM_WRITE16(pfc, data);
+ pfc++;
+ CYCLES(2);
+
+ tms.rptc--;
+ };
+}
+
+/*****************************************************************************/
+
+static void op_apl_dbmr(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ data &= tms.dbmr;
+ DM_WRITE16(ea, data);
+ CYCLES(1);
+}
+
+static void op_apl_imm(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 imm = ROPCODE();
+ UINT16 data = DM_READ16(ea);
+ data &= imm;
+ DM_WRITE16(ea, data);
+ CYCLES(1);
+}
+
+static void op_cpl_dbmr(void)
+{
+ fatalerror("32051: unimplemented op cpl dbmr at %08X", tms.pc-1);
+}
+
+static void op_cpl_imm(void)
+{
+ UINT16 imm = ROPCODE();
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+
+ if (data == imm)
+ {
+ tms.st1.tc = 1;
+ }
+ else
+ {
+ tms.st1.tc = 0;
+ }
+
+ CYCLES(1);
+}
+
+static void op_opl_dbmr(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ data |= tms.dbmr;
+ DM_WRITE16(ea, data);
+ CYCLES(1);
+}
+
+static void op_opl_imm(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 imm = ROPCODE();
+ UINT16 data = DM_READ16(ea);
+ data |= imm;
+ DM_WRITE16(ea, data);
+ CYCLES(1);
+}
+
+static void op_splk(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 imm = ROPCODE();
+
+ DM_WRITE16(ea, imm);
+
+ CYCLES(2);
+}
+
+static void op_xpl_dbmr(void)
+{
+ fatalerror("32051: unimplemented op xpl dbmr at %08X", tms.pc-1);
+}
+
+static void op_xpl_imm(void)
+{
+ fatalerror("32051: unimplemented op xpl imm at %08X", tms.pc-1);
+}
+
+static void op_apac(void)
+{
+ INT32 spreg = PREG_PSCALER(tms.preg);
+ tms.acc = ADD(tms.acc, spreg, 0);
+
+ CYCLES(1);
+}
+
+static void op_lph(void)
+{
+ fatalerror("32051: unimplemented op lph at %08X", tms.pc-1);
+}
+
+static void op_lt(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+
+ tms.treg0 = data;
+
+ CYCLES(1);
+}
+
+static void op_lta(void)
+{
+ INT32 spreg;
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+
+ tms.treg0 = data;
+ spreg = PREG_PSCALER(tms.preg);
+ tms.acc = ADD(tms.acc, spreg, 0);
+
+ CYCLES(1);
+}
+
+static void op_ltd(void)
+{
+ fatalerror("32051: unimplemented op ltd at %08X", tms.pc-1);
+}
+
+static void op_ltp(void)
+{
+ fatalerror("32051: unimplemented op ltp at %08X", tms.pc-1);
+}
+
+static void op_lts(void)
+{
+ fatalerror("32051: unimplemented op lts at %08X", tms.pc-1);
+}
+
+static void op_mac(void)
+{
+ fatalerror("32051: unimplemented op mac at %08X", tms.pc-1);
+}
+
+static void op_macd(void)
+{
+ fatalerror("32051: unimplemented op macd at %08X", tms.pc-1);
+}
+
+static void op_madd(void)
+{
+ fatalerror("32051: unimplemented op madd at %08X", tms.pc-1);
+}
+
+static void op_mads(void)
+{
+ fatalerror("32051: unimplemented op mads at %08X", tms.pc-1);
+}
+
+static void op_mpy_mem(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ INT16 data = DM_READ16(ea);
+
+ tms.preg = (INT32)(data) * (INT32)(INT16)(tms.treg0);
+
+ CYCLES(1);
+}
+
+static void op_mpy_simm(void)
+{
+ fatalerror("32051: unimplemented op mpy simm at %08X", tms.pc-1);
+}
+
+static void op_mpy_limm(void)
+{
+ fatalerror("32051: unimplemented op mpy limm at %08X", tms.pc-1);
+}
+
+static void op_mpya(void)
+{
+ fatalerror("32051: unimplemented op mpya at %08X", tms.pc-1);
+}
+
+static void op_mpys(void)
+{
+ fatalerror("32051: unimplemented op mpys at %08X", tms.pc-1);
+}
+
+static void op_mpyu(void)
+{
+ fatalerror("32051: unimplemented op mpyu at %08X", tms.pc-1);
+}
+
+static void op_pac(void)
+{
+ fatalerror("32051: unimplemented op pac at %08X", tms.pc-1);
+}
+
+static void op_spac(void)
+{
+ fatalerror("32051: unimplemented op spac at %08X", tms.pc-1);
+}
+
+static void op_sph(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 spreg = (UINT16)(PREG_PSCALER(tms.preg) >> 16);
+ DM_WRITE16(ea, spreg);
+
+ CYCLES(1);
+}
+
+static void op_spl(void)
+{
+ fatalerror("32051: unimplemented op spl at %08X", tms.pc-1);
+}
+
+static void op_spm(void)
+{
+ tms.st1.pm = tms.op & 0x3;
+
+ CYCLES(1);
+}
+
+static void op_sqra(void)
+{
+ fatalerror("32051: unimplemented op sqra at %08X", tms.pc-1);
+}
+
+static void op_sqrs(void)
+{
+ fatalerror("32051: unimplemented op sqrs at %08X", tms.pc-1);
+}
+
+static void op_zpr(void)
+{
+ fatalerror("32051: unimplemented op zpr at %08X", tms.pc-1);
+}
+
+static void op_bit(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ int bit = 15 - ((tms.op >> 8) & 0xf);
+
+ if (data & (1 << bit))
+ {
+ tms.st1.tc = 1;
+ }
+ else
+ {
+ tms.st1.tc = 0;
+ }
+
+ CYCLES(1);
+}
+
+static void op_bitt(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ int bit = 15 - (tms.treg2 & 0xf);
+
+ if (data & (1 << bit))
+ {
+ tms.st1.tc = 1;
+ }
+ else
+ {
+ tms.st1.tc = 0;
+ }
+
+ CYCLES(1);
+}
+
+static void op_clrc_ov(void)
+{
+ tms.st0.ovm = 0;
+
+ CYCLES(1);
+}
+
+static void op_clrc_ext(void)
+{
+ tms.st1.sxm = 0;
+
+ CYCLES(1);
+}
+
+static void op_clrc_hold(void)
+{
+ fatalerror("32051: unimplemented op clrc hold at %08X", tms.pc-1);
+}
+
+static void op_clrc_tc(void)
+{
+ fatalerror("32051: unimplemented op clrc tc at %08X", tms.pc-1);
+}
+
+static void op_clrc_carry(void)
+{
+ fatalerror("32051: unimplemented op clrc carry at %08X", tms.pc-1);
+}
+
+static void op_clrc_cnf(void)
+{
+ tms.st1.cnf = 0;
+
+ CYCLES(1);
+}
+
+static void op_clrc_intm(void)
+{
+ tms.st0.intm = 0;
+
+ check_interrupts();
+
+ CYCLES(1);
+}
+
+static void op_clrc_xf(void)
+{
+ fatalerror("32051: unimplemented op clrc xf at %08X", tms.pc-1);
+}
+
+static void op_idle(void)
+{
+ fatalerror("32051: unimplemented op idle at %08X", tms.pc-1);
+}
+
+static void op_idle2(void)
+{
+ fatalerror("32051: unimplemented op idle2 at %08X", tms.pc-1);
+}
+
+static void op_lst_st0(void)
+{
+ fatalerror("32051: unimplemented op lst st0 at %08X", tms.pc-1);
+}
+
+static void op_lst_st1(void)
+{
+ fatalerror("32051: unimplemented op lst st1 at %08X", tms.pc-1);
+}
+
+static void op_pop(void)
+{
+ tms.acc = POP_STACK();
+
+ CYCLES(1);
+}
+
+static void op_popd(void)
+{
+ fatalerror("32051: unimplemented op popd at %08X", tms.pc-1);
+}
+
+static void op_pshd(void)
+{
+ fatalerror("32051: unimplemented op pshd at %08X", tms.pc-1);
+}
+
+static void op_push(void)
+{
+ fatalerror("32051: unimplemented op push at %08X", tms.pc-1);
+}
+
+static void op_rpt_mem(void)
+{
+ UINT16 ea = GET_ADDRESS();
+ UINT16 data = DM_READ16(ea);
+ tms.rptc = data;
+ tms.rpt_start = tms.pc;
+ tms.rpt_end = tms.pc;
+
+ CYCLES(1);
+}
+
+static void op_rpt_limm(void)
+{
+ tms.rptc = (UINT16)ROPCODE();
+ tms.rpt_start = tms.pc;
+ tms.rpt_end = tms.pc;
+
+ CYCLES(2);
+}
+
+static void op_rpt_simm(void)
+{
+ tms.rptc = (tms.op & 0xff);
+ tms.rpt_start = tms.pc;
+ tms.rpt_end = tms.pc;
+
+ CYCLES(1);
+}
+
+static void op_rptb(void)
+{
+ UINT16 pma = ROPCODE();
+ tms.pmst.braf = 1;
+ tms.pasr = tms.pc;
+ tms.paer = pma + 1;
+
+ CYCLES(2);
+}
+
+static void op_rptz(void)
+{
+ fatalerror("32051: unimplemented op rptz at %08X", tms.pc-1);
+}
+
+static void op_setc_ov(void)
+{
+ tms.st0.ovm = 1;
+
+ CYCLES(1);
+}
+
+static void op_setc_ext(void)
+{
+ tms.st1.sxm = 1;
+
+ CYCLES(1);
+}
+
+static void op_setc_hold(void)
+{
+ fatalerror("32051: unimplemented op setc hold at %08X", tms.pc-1);
+}
+
+static void op_setc_tc(void)
+{
+ fatalerror("32051: unimplemented op setc tc at %08X", tms.pc-1);
+}
+
+static void op_setc_carry(void)
+{
+ fatalerror("32051: unimplemented op setc carry at %08X", tms.pc-1);
+}
+
+static void op_setc_xf(void)
+{
+ fatalerror("32051: unimplemented op setc xf at %08X", tms.pc-1);
+}
+
+static void op_setc_cnf(void)
+{
+ tms.st1.cnf = 1;
+
+ CYCLES(1);
+}
+
+static void op_setc_intm(void)
+{
+ tms.st0.intm = 1;
+
+ check_interrupts();
+
+ CYCLES(1);
+}
+
+static void op_sst_st0(void)
+{
+ fatalerror("32051: unimplemented op sst st0 at %08X", tms.pc-1);
+}
+
+static void op_sst_st1(void)
+{
+ fatalerror("32051: unimplemented op sst st1 at %08X", tms.pc-1);
+}
diff --git a/src/emu/cpu/tms32051/32051ops.h b/src/emu/cpu/tms32051/32051ops.h
new file mode 100644
index 00000000000..a2f2c222f3b
--- /dev/null
+++ b/src/emu/cpu/tms32051/32051ops.h
@@ -0,0 +1,251 @@
+static void (* tms32051_opcode_table[256])(void) =
+{
+ /* 0x00 - 0x0f */
+ op_lar_mem, op_lar_mem, op_lar_mem, op_lar_mem,
+ op_lar_mem, op_lar_mem, op_lar_mem, op_lar_mem,
+ op_lamm, op_smmr, op_subc, op_rpt_mem,
+ op_out, op_ldp_mem, op_lst_st0, op_lst_st1,
+ /* 0x10 - 0x1f */
+ op_lacc_mem, op_lacc_mem, op_lacc_mem, op_lacc_mem,
+ op_lacc_mem, op_lacc_mem, op_lacc_mem, op_lacc_mem,
+ op_lacc_mem, op_lacc_mem, op_lacc_mem, op_lacc_mem,
+ op_lacc_mem, op_lacc_mem, op_lacc_mem, op_lacc_mem,
+ /* 0x20 - 0x2f */
+ op_add_mem, op_add_mem, op_add_mem, op_add_mem,
+ op_add_mem, op_add_mem, op_add_mem, op_add_mem,
+ op_add_mem, op_add_mem, op_add_mem, op_add_mem,
+ op_add_mem, op_add_mem, op_add_mem, op_add_mem,
+ /* 0x30 - 0x3f */
+ op_sub_mem, op_sub_mem, op_sub_mem, op_sub_mem,
+ op_sub_mem, op_sub_mem, op_sub_mem, op_sub_mem,
+ op_sub_mem, op_sub_mem, op_sub_mem, op_sub_mem,
+ op_sub_mem, op_sub_mem, op_sub_mem, op_sub_mem,
+ /* 0x40 - 0x4f */
+ op_bit, op_bit, op_bit, op_bit,
+ op_bit, op_bit, op_bit, op_bit,
+ op_bit, op_bit, op_bit, op_bit,
+ op_bit, op_bit, op_bit, op_bit,
+ /* 0x50 - 0x5f */
+ op_mpya, op_mpys, op_sqra, op_sqrs,
+ op_mpy_mem, op_mpyu, op_invalid, op_bldp,
+ op_xpl_dbmr, op_opl_dbmr, op_apl_dbmr, op_cpl_dbmr,
+ op_xpl_imm, op_opl_imm, op_apl_imm, op_cpl_imm,
+ /* 0x60 - 0x6f */
+ op_addc, op_add_s16_mem, op_adds, op_addt,
+ op_subb, op_sub_s16_mem, op_subs, op_subt,
+ op_zalr, op_lacl_mem, op_lacc_s16_mem,op_lact,
+ op_xor_mem, op_or_mem, op_and_mem, op_bitt,
+ /* 0x70 - 0x7f */
+ op_lta, op_ltp, op_ltd, op_lt,
+ op_lts, op_lph, op_pshd, op_dmov,
+ op_adrk, op_b, op_call, op_banz,
+ op_sbrk, op_bd, op_calld, op_banzd,
+ /* 0x80 - 0x8f */
+ op_sar, op_sar, op_sar, op_sar,
+ op_sar, op_sar, op_sar, op_sar,
+ op_samm, op_lmmr, op_popd, op_mar,
+ op_spl, op_sph, op_sst_st0, op_sst_st1,
+ /* 0x90 - 0x9f */
+ op_sacl, op_sacl, op_sacl, op_sacl,
+ op_sacl, op_sacl, op_sacl, op_sacl,
+ op_sach, op_sach, op_sach, op_sach,
+ op_sach, op_sach, op_sach, op_sach,
+ /* 0xa0 - 0xaf */
+ op_norm, op_invalid, op_mac, op_macd,
+ op_blpd_bmar, op_blpd_imm, op_tblr, op_tblw,
+ op_bldd_slimm, op_bldd_dlimm, op_mads, op_madd,
+ op_bldd_sbmar, op_bldd_dbmar, op_splk, op_in,
+ /* 0xb0 - 0xbf */
+ op_lar_simm, op_lar_simm, op_lar_simm, op_lar_simm,
+ op_lar_simm, op_lar_simm, op_lar_simm, op_lar_simm,
+ op_add_simm, op_lacl_simm, op_sub_simm, op_rpt_simm,
+ op_ldp_imm, op_ldp_imm, op_group_be, op_group_bf,
+ /* 0xc0 - 0xcf */
+ op_mpy_simm, op_mpy_simm, op_mpy_simm, op_mpy_simm,
+ op_mpy_simm, op_mpy_simm, op_mpy_simm, op_mpy_simm,
+ op_mpy_simm, op_mpy_simm, op_mpy_simm, op_mpy_simm,
+ op_mpy_simm, op_mpy_simm, op_mpy_simm, op_mpy_simm,
+ /* 0xd0 - 0xdf */
+ op_mpy_simm, op_mpy_simm, op_mpy_simm, op_mpy_simm,
+ op_mpy_simm, op_mpy_simm, op_mpy_simm, op_mpy_simm,
+ op_mpy_simm, op_mpy_simm, op_mpy_simm, op_mpy_simm,
+ op_mpy_simm, op_mpy_simm, op_mpy_simm, op_mpy_simm,
+ /* 0xe0 - 0xef */
+ op_bcnd, op_bcnd, op_bcnd, op_bcnd,
+ op_xc, op_xc, op_xc, op_xc,
+ op_cc, op_cc, op_cc, op_cc,
+ op_retc, op_retc, op_retc, op_retc,
+ /* 0xf0 - 0xff */
+ op_bcndd, op_bcndd, op_bcndd, op_bcndd,
+ op_xc, op_xc, op_xc, op_xc,
+ op_ccd, op_ccd, op_ccd, op_ccd,
+ op_retcd, op_retcd, op_retcd, op_retcd
+};
+
+static void (* tms32051_opcode_table_be[256])(void) =
+{
+ /* 0x00 - 0x0f */
+ op_abs, op_cmpl, op_neg, op_pac,
+ op_apac, op_spac, op_invalid, op_invalid,
+ op_invalid, op_sfl, op_sfr, op_invalid,
+ op_rol, op_ror, op_invalid, op_invalid,
+ /* 0x10 - 0x1f */
+ op_addb, op_adcb, op_andb, op_orb,
+ op_rolb, op_rorb, op_sflb, op_sfrb,
+ op_sbb, op_sbbb, op_xorb, op_crgt,
+ op_crlt, op_exar, op_sacb, op_lacb,
+ /* 0x20 - 0x2f */
+ op_bacc, op_baccd, op_idle, op_idle2,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x30 - 0x3f */
+ op_cala, op_invalid, op_pop, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_reti, op_invalid, op_rete, op_invalid,
+ op_push, op_calad, op_invalid, op_invalid,
+ /* 0x40 - 0x4f */
+ op_clrc_intm, op_setc_intm, op_clrc_ov, op_setc_ov,
+ op_clrc_cnf, op_setc_cnf, op_clrc_ext, op_setc_ext,
+ op_clrc_hold, op_setc_hold, op_clrc_tc, op_setc_tc,
+ op_clrc_xf, op_setc_xf, op_clrc_carry, op_setc_carry,
+ /* 0x50 - 0x5f */
+ op_invalid, op_trap, op_nmi, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_zpr, op_zap, op_sath, op_satl,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x60 - 0x6f */
+ op_intr, op_intr, op_intr, op_intr,
+ op_intr, op_intr, op_intr, op_intr,
+ op_intr, op_intr, op_intr, op_intr,
+ op_intr, op_intr, op_intr, op_intr,
+ /* 0x70 - 0x7f */
+ op_intr, op_intr, op_intr, op_intr,
+ op_intr, op_intr, op_intr, op_intr,
+ op_intr, op_intr, op_intr, op_intr,
+ op_intr, op_intr, op_intr, op_intr,
+ /* 0x80 - 0x8f */
+ op_mpy_limm, op_and_s16_limm,op_or_s16_limm, op_xor_s16_limm,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x90 - 0x9f */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0xa0 - 0xaf */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0xb0 - 0xbf */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0xc0 - 0xcf */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_rpt_limm, op_rptz, op_rptb, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0xd0 - 0xdf */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0xe0 - 0xef */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0xf0 - 0xff */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+};
+
+static void (* tms32051_opcode_table_bf[256])(void) =
+{
+ /* 0x00 - 0x0f */
+ op_spm, op_spm, op_spm, op_spm,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_lar_limm, op_lar_limm, op_lar_limm, op_lar_limm,
+ op_lar_limm, op_lar_limm, op_lar_limm, op_lar_limm,
+ /* 0x10 - 0x1f */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x20 - 0x2f */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x30 - 0x3f */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x40 - 0x4f */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_cmpr, op_cmpr, op_cmpr, op_cmpr,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x50 - 0x5f */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x60 - 0x6f */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x70 - 0x7f */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ /* 0x80 - 0x8f */
+ op_lacc_limm, op_lacc_limm, op_lacc_limm, op_lacc_limm,
+ op_lacc_limm, op_lacc_limm, op_lacc_limm, op_lacc_limm,
+ op_lacc_limm, op_lacc_limm, op_lacc_limm, op_lacc_limm,
+ op_lacc_limm, op_lacc_limm, op_lacc_limm, op_lacc_limm,
+ /* 0x90 - 0x9f */
+ op_add_limm, op_add_limm, op_add_limm, op_add_limm,
+ op_add_limm, op_add_limm, op_add_limm, op_add_limm,
+ op_add_limm, op_add_limm, op_add_limm, op_add_limm,
+ op_add_limm, op_add_limm, op_add_limm, op_add_limm,
+ /* 0xa0 - 0xaf */
+ op_sub_limm, op_sub_limm, op_sub_limm, op_sub_limm,
+ op_sub_limm, op_sub_limm, op_sub_limm, op_sub_limm,
+ op_sub_limm, op_sub_limm, op_sub_limm, op_sub_limm,
+ op_sub_limm, op_sub_limm, op_sub_limm, op_sub_limm,
+ /* 0xb0 - 0xbf */
+ op_and_limm, op_and_limm, op_and_limm, op_and_limm,
+ op_and_limm, op_and_limm, op_and_limm, op_and_limm,
+ op_and_limm, op_and_limm, op_and_limm, op_and_limm,
+ op_and_limm, op_and_limm, op_and_limm, op_and_limm,
+ /* 0xc0 - 0xcf */
+ op_or_limm, op_or_limm, op_or_limm, op_or_limm,
+ op_or_limm, op_or_limm, op_or_limm, op_or_limm,
+ op_or_limm, op_or_limm, op_or_limm, op_or_limm,
+ op_or_limm, op_or_limm, op_or_limm, op_or_limm,
+ /* 0xd0 - 0xdf */
+ op_xor_limm, op_xor_limm, op_xor_limm, op_xor_limm,
+ op_xor_limm, op_xor_limm, op_xor_limm, op_xor_limm,
+ op_xor_limm, op_xor_limm, op_xor_limm, op_xor_limm,
+ op_xor_limm, op_xor_limm, op_xor_limm, op_xor_limm,
+ /* 0xe0 - 0xef */
+ op_bsar, op_bsar, op_bsar, op_bsar,
+ op_bsar, op_bsar, op_bsar, op_bsar,
+ op_bsar, op_bsar, op_bsar, op_bsar,
+ op_bsar, op_bsar, op_bsar, op_bsar,
+ /* 0xf0 - 0xff */
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+ op_invalid, op_invalid, op_invalid, op_invalid,
+};
diff --git a/src/emu/cpu/tms32051/dis32051.c b/src/emu/cpu/tms32051/dis32051.c
new file mode 100644
index 00000000000..f78862048f6
--- /dev/null
+++ b/src/emu/cpu/tms32051/dis32051.c
@@ -0,0 +1,643 @@
+#include "cpuintrf.h"
+#include <stdarg.h>
+
+
+
+static const char *zl_condition_codes[] =
+{
+ // bit 3, 2 (ZL), bit 1, 0 (MASK)
+ "", // Z=0, L=0, ZM=0, ZL=0
+ "gt", // Z=0, L=0, ZM=0, ZL=1
+ "neq", // Z=0, L=0, ZM=1, ZL=0
+ "gt", // Z=0, L=0, ZM=1, ZL=1
+ "", // Z=0, L=1, ZM=0, ZL=0
+ "lt", // Z=0, L=1, ZM=0, ZL=1
+ "neq", // Z=0, L=1, ZM=1, ZL=0
+ "lt", // Z=0, L=1, ZM=1, ZL=1
+ "", // Z=1, L=0, ZM=0, ZL=0
+ "gt", // Z=1, L=0, ZM=0, ZL=1
+ "eq", // Z=1, L=0, ZM=1, ZL=0
+ "geq", // Z=1, L=0, ZM=1, ZL=1
+ "", // Z=1, L=1, ZM=0, ZL=0
+ "lt", // Z=1, L=1, ZM=0, ZL=1
+ "eq", // Z=1, L=1, ZM=1, ZL=0
+ "leq", // Z=1, L=1, ZM=1, ZL=1
+};
+
+static const char *cv_condition_codes[16] =
+{
+ "", // C=0, V=0, CM=0, VM=0
+ "nov", // C=0, V=0, CM=0, VM=1
+ "nc", // C=0, V=0, CM=1, VM=0
+ "nc nov", // C=0, V=0, CM=1, VM=1
+ "", // C=0, V=1, CM=0, VM=0
+ "ov", // C=0, V=1, CM=0, VM=1
+ "nc", // C=0, V=1, CM=1, VM=0
+ "nc ov", // C=0, V=1, CM=1, VM=1
+ "", // C=1, V=0, CM=0, VM=0
+ "nov", // C=1, V=0, CM=0, VM=1
+ "c", // C=1, V=0, CM=1, VM=0
+ "c nov", // C=1, V=0, CM=1, VM=1
+ "", // C=1, V=1, CM=0, VM=0
+ "ov", // C=1, V=1, CM=0, VM=1
+ "c", // C=1, V=1, CM=1, VM=0
+ "c ov", // C=1, V=1, CM=1, VM=1
+};
+
+static const char *tp_condition_codes[4] =
+{
+ "bio",
+ "tc",
+ "ntc",
+ ""
+};
+
+
+static offs_t npc;
+static const UINT8 *rombase;
+static offs_t pcbase;
+
+static char *output;
+
+static void print(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ output += vsprintf(output, fmt, vl);
+ va_end(vl);
+}
+
+static UINT16 FETCH(void)
+{
+ UINT16 result = rombase[(npc - pcbase) * 2 + 0] | (rombase[(npc - pcbase) * 2 + 1] << 8);
+ npc++;
+ return result;
+}
+
+static char *GET_ADDRESS(int addr_mode, int address)
+{
+ static char buffer[100];
+
+ if (addr_mode) // Indirect addressing
+ {
+ int nar = address & 0x7;
+
+
+ switch ((address >> 3) & 0xf)
+ {
+ case 0x0: sprintf(buffer, "*"); break;
+ case 0x1: sprintf(buffer, "*, ar%d", nar); break;
+ case 0x2: sprintf(buffer, "*-"); break;
+ case 0x3: sprintf(buffer, "*-, ar%d", nar); break;
+ case 0x4: sprintf(buffer, "*+"); break;
+ case 0x5: sprintf(buffer, "*+, ar%d", nar); break;
+ case 0x8: sprintf(buffer, "*br0-"); break;
+ case 0x9: sprintf(buffer, "*br0-, ar%d", nar); break;
+ case 0xa: sprintf(buffer, "*0-"); break;
+ case 0xb: sprintf(buffer, "*0-, ar%d", nar); break;
+ case 0xc: sprintf(buffer, "*0+"); break;
+ case 0xd: sprintf(buffer, "*0+, ar%d", nar); break;
+ case 0xe: sprintf(buffer, "*br0+"); break;
+ case 0xf: sprintf(buffer, "*br0+, ar%d", nar); break;
+
+ default: sprintf(buffer, "??? (indirect)"); break;
+ }
+ }
+ else // Direct addressing
+ {
+ sprintf(buffer, "#%02X", address);
+ }
+ return buffer;
+}
+
+static char *GET_SHIFT(int shift)
+{
+ static char buffer[100];
+
+ if (shift > 0)
+ {
+ sprintf(buffer, ", %d", shift);
+ }
+ else
+ {
+ memset(buffer, 0, sizeof(buffer));
+ }
+
+ return buffer;
+}
+
+void dasm_group_be(UINT16 opcode)
+{
+ int subop = opcode & 0xff;
+
+ switch (subop)
+ {
+ case 0x00: print("abs"); break;
+ case 0x01: print("cmpl"); break;
+ case 0x02: print("neg"); break;
+ case 0x03: print("pac"); break;
+ case 0x04: print("apac"); break;
+ case 0x05: print("spac"); break;
+ case 0x09: print("sfl"); break;
+ case 0x0a: print("sfr"); break;
+ case 0x0c: print("rol"); break;
+ case 0x0d: print("ror"); break;
+ case 0x10: print("addb"); break;
+ case 0x11: print("adcb"); break;
+ case 0x12: print("andb"); break;
+ case 0x13: print("orb"); break;
+ case 0x14: print("rolb"); break;
+ case 0x15: print("rorb"); break;
+ case 0x16: print("sflb"); break;
+ case 0x17: print("sfrb"); break;
+ case 0x18: print("sbb"); break;
+ case 0x19: print("sbbb"); break;
+ case 0x1a: print("xorb"); break;
+ case 0x1b: print("crgt"); break;
+ case 0x1c: print("crlt"); break;
+ case 0x1d: print("exar"); break;
+ case 0x1e: print("sacb"); break;
+ case 0x1f: print("lacb"); break;
+ case 0x20: print("bacc"); break;
+ case 0x21: print("baccd"); break;
+ case 0x22: print("idle"); break;
+ case 0x23: print("idle2"); break;
+ case 0x30: print("cala"); break;
+ case 0x32: print("pop"); break;
+ case 0x38: print("reti"); break;
+ case 0x3a: print("rete"); break;
+ case 0x3c: print("push"); break;
+ case 0x3d: print("calad"); break;
+ case 0x40: print("clrc intm"); break;
+ case 0x41: print("setc intm"); break;
+ case 0x42: print("clrc ovm"); break;
+ case 0x43: print("setc ovm"); break;
+ case 0x44: print("clrc cnf"); break;
+ case 0x45: print("setc cnf"); break;
+ case 0x46: print("clrc sxm"); break;
+ case 0x47: print("setc sxm"); break;
+ case 0x48: print("clrc hold"); break;
+ case 0x49: print("setc hold"); break;
+ case 0x4a: print("clrc tc"); break;
+ case 0x4b: print("setc tc"); break;
+ case 0x4c: print("clrc xf"); break;
+ case 0x4d: print("setc xf"); break;
+ case 0x4e: print("clrc carry"); break;
+ case 0x4f: print("setc carry"); break;
+ case 0x51: print("trap"); break;
+ case 0x52: print("nmi"); break;
+ case 0x58: print("zpr"); break;
+ case 0x59: print("zap"); break;
+ case 0x5a: print("sath"); break;
+ case 0x5b: print("satl"); break;
+ case 0x60: case 0x61: case 0x62: case 0x63:
+ case 0x64: case 0x65: case 0x66: case 0x67:
+ case 0x68: case 0x69: case 0x6a: case 0x6b:
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b:
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+ print("intr %d", opcode & 0x1f); break;
+
+ case 0x80: print("mpy #%04X", FETCH()); break;
+ case 0x81: print("and #%04X", FETCH() << 16); break;
+ case 0x82: print("or #%04X", FETCH() << 16); break;
+ case 0x83: print("xor #%04X", FETCH() << 16); break;
+ case 0xc4: print("rpt #%04X", FETCH()); break;
+ case 0xc5: print("rpt #%04X", FETCH()); break;
+ case 0xc6: print("rpt #%04X", FETCH()); break;
+
+ default: print("??? (group be)"); break;
+ }
+}
+
+static void dasm_group_bf(UINT16 opcode)
+{
+ int subop = (opcode >> 4) & 0xf;
+ int shift = opcode & 0xf;
+
+ switch (subop)
+ {
+ case 0x0:
+ {
+ if (opcode & 0x8)
+ {
+ print("lar ar%d, #%04X", opcode & 0x7, FETCH());
+ }
+ else
+ {
+ print("spm #%02X", opcode & 0x3);
+ }
+ break;
+ }
+
+ case 0x4:
+ {
+ switch (opcode & 0x3)
+ {
+ case 0: print("cmpr ar = arcr"); break;
+ case 1: print("cmpr ar < arcr"); break;
+ case 2: print("cmpr ar > arcr"); break;
+ case 3: print("cmpr ar != arcr"); break;
+ }
+ break;
+ }
+
+ case 0x8: print("lacc #%04X", FETCH() << shift); break;
+ case 0x9: print("add #%04X", FETCH() << shift); break;
+ case 0xa: print("sub #%04X", FETCH() << shift); break;
+ case 0xb: print("and #%04X", FETCH() << shift); break;
+ case 0xc: print("or #%04X", FETCH() << shift); break;
+ case 0xd: print("xor #%04X", FETCH() << shift); break;
+ case 0xe: print("bsar %d", shift+1); break;
+
+ default: print("??? (group bf)"); break;
+ }
+}
+
+offs_t tms32051_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ UINT16 opcode;
+ int baseop;
+ int address, addr_mode;
+
+ pcbase = pc;
+ rombase = oprom;
+ npc = pc;
+ output = buffer;
+
+ opcode = FETCH();
+ baseop = (opcode >> 8) & 0xff;
+
+ addr_mode = (opcode >> 7) & 0x1;
+ address = opcode & 0x7f;
+
+ switch (baseop)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ {
+ print("lar ar%d, %s", (opcode >> 8) & 0x7, GET_ADDRESS(addr_mode, address));
+ break;
+ }
+ case 0x08: print("lamm %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x09: print("smmr %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x0a: print("subc %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x0b: print("rpt %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x0c: print("out %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0x0d: print("ldp %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x0e: print("lst 0, %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x0f: print("lst 1, %s", GET_ADDRESS(addr_mode, address)); break;
+
+ 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:
+ {
+ print("lacc %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0xf));
+ break;
+ }
+
+ case 0x20: case 0x21: case 0x22: case 0x23:
+ case 0x24: case 0x25: case 0x26: case 0x27:
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ {
+ print("add %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0xf));
+ break;
+ }
+
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b:
+ case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ {
+ print("sub %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0xf));
+ break;
+ }
+
+ case 0x40: case 0x41: case 0x42: case 0x43:
+ case 0x44: case 0x45: case 0x46: case 0x47:
+ case 0x48: case 0x49: case 0x4a: case 0x4b:
+ case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+ {
+ print("bit %d, %s", (opcode >> 8) & 0xf, GET_ADDRESS(addr_mode, address));
+ break;
+ }
+
+ case 0x50: print("mpya %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x51: print("mpys %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x52: print("sqra %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x53: print("sqrs %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x54: print("mpy %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x55: print("mpyu %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x57: print("bldp %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x58: print("xpl %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x59: print("opl %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x5a: print("apl %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x5b: print("cpl %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x5c: print("xpl %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0x5d: print("opl %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0x5e: print("apl %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0x5f: print("cpl %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+
+ case 0x60: print("addc %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x61: print("add %s << 16", GET_ADDRESS(addr_mode, address)); break;
+ case 0x62: print("adds %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x63: print("addt %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x64: print("subb %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x65: print("sub %s << 16", GET_ADDRESS(addr_mode, address)); break;
+ case 0x66: print("subs %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x67: print("subt %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x68: print("zalr %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x69: print("lacl %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x6a: print("lacc %s << 16", GET_ADDRESS(addr_mode, address)); break;
+ case 0x6b: print("lact %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x6c: print("xor %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x6d: print("or %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x6e: print("and %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x6f: print("bitt %s", GET_ADDRESS(addr_mode, address)); break;
+
+ case 0x70: print("lta %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x71: print("ltp %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x72: print("ltd %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x73: print("lt %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x74: print("lts %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x75: print("lph %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x76: print("pshd %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x77: print("dmov %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x78: print("adrk #%02X", opcode & 0xff); break;
+ case 0x79: print("b %04X, %s", FETCH(), GET_ADDRESS(1, address)); break;
+ case 0x7a: print("call %04X, %s", FETCH(), GET_ADDRESS(1, address)); flags = DASMFLAG_STEP_OVER; break;
+ case 0x7b: print("banz %04X, %s", FETCH(), GET_ADDRESS(1, address)); break;
+ case 0x7c: print("sbrk #%02X", opcode & 0xff); break;
+ case 0x7d: print("bd %04X, %s", FETCH(), GET_ADDRESS(1, address)); break;
+ case 0x7e: print("calld %04X, %s", FETCH(), GET_ADDRESS(1, address)); flags = DASMFLAG_STEP_OVER; break;
+ case 0x7f: print("banzd %04X, %s", FETCH(), GET_ADDRESS(1, address)); break;
+
+ case 0x80: case 0x81: case 0x82: case 0x83:
+ case 0x84: case 0x85: case 0x86: case 0x87:
+ {
+ print("sar ar%d, %s", (opcode >> 8) & 0x7, GET_ADDRESS(addr_mode, address));
+ break;
+ }
+ case 0x88: print("samm %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x89: print("lmmr %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0x8a: print("popd %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x8b:
+ {
+ if ((opcode & 0xff) == 0)
+ {
+ print("nop");
+ }
+ else
+ {
+ print("mar %s", GET_ADDRESS(addr_mode, address));
+ }
+ break;
+ }
+ case 0x8c: print("spl %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x8d: print("sph %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x8e: print("sst 0, %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0x8f: print("sst 1, %s", GET_ADDRESS(addr_mode, address)); break;
+
+ case 0x90: case 0x91: case 0x92: case 0x93:
+ case 0x94: case 0x95: case 0x96: case 0x97:
+ {
+ print("sacl %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0x7));
+ break;
+ }
+ case 0x98: case 0x99: case 0x9a: case 0x9b:
+ case 0x9c: case 0x9d: case 0x9e: case 0x9f:
+ {
+ print("sach %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0x7));
+ break;
+ }
+
+ case 0xa0: print("norm %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0xa2: print("mac %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0xa3: print("macd %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0xa4: print("blpd %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0xa5: print("blpd %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0xa6: print("tblr %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0xa7: print("tblw %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0xa8: print("bldd %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0xa9: print("bldd %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0xaa: print("mads %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0xab: print("madd %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0xac: print("bldd %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0xad: print("bldd %s", GET_ADDRESS(addr_mode, address)); break;
+ case 0xae: print("splk %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+ case 0xaf: print("in %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break;
+
+ case 0xb0: case 0xb1: case 0xb2: case 0xb3:
+ case 0xb4: case 0xb5: case 0xb6: case 0xb7:
+ {
+ print("lar ar%d, #%02X", (opcode >> 8) & 0x7, opcode & 0xff);
+ break;
+ }
+ case 0xb8: print("add #%02X", opcode & 0xff); break;
+ case 0xb9: print("lacl #%02X", opcode & 0xff); break;
+ case 0xba: print("sub #%02X", opcode & 0xff); break;
+ case 0xbb: print("rpt #%02X", opcode & 0xff); break;
+
+ case 0xbc:
+ case 0xbd:
+ {
+ print("ldp #%03X", opcode & 0x1ff);
+ break;
+ }
+ case 0xbe: dasm_group_be(opcode); break;
+ case 0xbf: dasm_group_bf(opcode); break;
+
+ case 0xe0: case 0xe1: case 0xe2: case 0xe3:
+ {
+ int zlcvmask = opcode & 0xf;
+ int zlcv = (opcode >> 4) & 0xf;
+ int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3);
+ int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3);
+ int tp = (opcode >> 8) & 0x3;
+
+ print("bcnd %04X", FETCH());
+
+ if (strlen(zl_condition_codes[zl]) > 0)
+ {
+ print(", %s", zl_condition_codes[zl]);
+ }
+ if (strlen(cv_condition_codes[cv]) > 0)
+ {
+ print(", %s", cv_condition_codes[cv]);
+ }
+ if (strlen(tp_condition_codes[tp]) > 0)
+ {
+ print(", %s", tp_condition_codes[tp]);
+ }
+ break;
+ }
+
+ case 0xe4: case 0xe5: case 0xe6: case 0xe7:
+ case 0xf4: case 0xf5: case 0xf6: case 0xf7:
+ {
+ int zlcvmask = opcode & 0xf;
+ int zlcv = (opcode >> 4) & 0xf;
+ int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3);
+ int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3);
+ int tp = (opcode >> 8) & 0x3;
+ int n = ((opcode >> 12) & 0x1) + 1;
+
+ print("xc %d", n);
+
+ if (strlen(zl_condition_codes[zl]) > 0)
+ {
+ print(", %s", zl_condition_codes[zl]);
+ }
+ if (strlen(cv_condition_codes[cv]) > 0)
+ {
+ print(", %s", cv_condition_codes[cv]);
+ }
+ if (strlen(tp_condition_codes[tp]) > 0)
+ {
+ print(", %s", tp_condition_codes[tp]);
+ }
+ break;
+ }
+
+ case 0xe8: case 0xe9: case 0xea: case 0xeb:
+ {
+ int zlcvmask = opcode & 0xf;
+ int zlcv = (opcode >> 4) & 0xf;
+ int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3);
+ int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3);
+ int tp = (opcode >> 8) & 0x3;
+
+ print("cc %04X", FETCH());
+
+ if (strlen(zl_condition_codes[zl]) > 0)
+ {
+ print(", %s", zl_condition_codes[zl]);
+ }
+ if (strlen(cv_condition_codes[cv]) > 0)
+ {
+ print(", %s", cv_condition_codes[cv]);
+ }
+ if (strlen(tp_condition_codes[tp]) > 0)
+ {
+ print(", %s", tp_condition_codes[tp]);
+ }
+ break;
+ }
+
+ case 0xec: case 0xed: case 0xee:
+ {
+ int zlcvmask = opcode & 0xf;
+ int zlcv = (opcode >> 4) & 0xf;
+ int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3);
+ int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3);
+ int tp = (opcode >> 8) & 0x3;
+
+ print("retc ");
+
+ if (strlen(zl_condition_codes[zl]) > 0)
+ {
+ print(", %s", zl_condition_codes[zl]);
+ }
+ if (strlen(cv_condition_codes[cv]) > 0)
+ {
+ print(", %s", cv_condition_codes[cv]);
+ }
+ if (strlen(tp_condition_codes[tp]) > 0)
+ {
+ print(", %s", tp_condition_codes[tp]);
+ }
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ }
+
+ case 0xef: print("ret"); flags = DASMFLAG_STEP_OUT; break;
+
+ case 0xf0: case 0xf1: case 0xf2: case 0xf3:
+ {
+ int zlcvmask = opcode & 0xf;
+ int zlcv = (opcode >> 4) & 0xf;
+ int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3);
+ int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3);
+ int tp = (opcode >> 8) & 0x3;
+
+ print("bcndd %04X", FETCH());
+
+ if (strlen(zl_condition_codes[zl]) > 0)
+ {
+ print(", %s", zl_condition_codes[zl]);
+ }
+ if (strlen(cv_condition_codes[cv]) > 0)
+ {
+ print(", %s", cv_condition_codes[cv]);
+ }
+ if (strlen(tp_condition_codes[tp]) > 0)
+ {
+ print(", %s", tp_condition_codes[tp]);
+ }
+ break;
+ }
+
+ case 0xf8: case 0xf9: case 0xfa: case 0xfb:
+ {
+ int zlcvmask = opcode & 0xf;
+ int zlcv = (opcode >> 4) & 0xf;
+ int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3);
+ int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3);
+ int tp = (opcode >> 8) & 0x3;
+
+ print("ccd %04X", FETCH());
+
+ if (strlen(zl_condition_codes[zl]) > 0)
+ {
+ print(", %s", zl_condition_codes[zl]);
+ }
+ if (strlen(cv_condition_codes[cv]) > 0)
+ {
+ print(", %s", cv_condition_codes[cv]);
+ }
+ if (strlen(tp_condition_codes[tp]) > 0)
+ {
+ print(", %s", tp_condition_codes[tp]);
+ }
+ break;
+ }
+
+ case 0xfc: case 0xfd: case 0xfe:
+ {
+ int zlcvmask = opcode & 0xf;
+ int zlcv = (opcode >> 4) & 0xf;
+ int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3);
+ int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3);
+ int tp = (opcode >> 8) & 0x3;
+
+ print("retcd ");
+
+ if (strlen(zl_condition_codes[zl]) > 0)
+ {
+ print(", %s", zl_condition_codes[zl]);
+ }
+ if (strlen(cv_condition_codes[cv]) > 0)
+ {
+ print(", %s", cv_condition_codes[cv]);
+ }
+ if (strlen(tp_condition_codes[tp]) > 0)
+ {
+ print(", %s", tp_condition_codes[tp]);
+ }
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ }
+
+ case 0xff: print("retd"); flags = DASMFLAG_STEP_OUT; break;
+
+ default: print("??? ($%04X)", opcode); break;
+ }
+
+ return (npc-pc) | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/tms32051/tms32051.c b/src/emu/cpu/tms32051/tms32051.c
new file mode 100644
index 00000000000..f1dbd246530
--- /dev/null
+++ b/src/emu/cpu/tms32051/tms32051.c
@@ -0,0 +1,723 @@
+/*
+ Texas Instruments TMS320C51 DSP Emulator
+
+ Written by Ville Linde
+*/
+
+#include "cpuintrf.h"
+#include "tms32051.h"
+#include "debugger.h"
+
+static void delay_slot(UINT16 startpc);
+static void save_interrupt_context(void);
+static void restore_interrupt_context(void);
+static void check_interrupts(void);
+
+#define INTERRUPT_INT1 0
+#define INTERRUPT_INT2 1
+#define INTERRUPT_INT3 2
+#define INTERRUPT_TINT 3
+#define INTERRUPT_RINT 4
+#define INTERRUPT_XINT 5
+#define INTERRUPT_TRNT 6
+#define INTERRUPT_TXNT 7
+#define INTERRUPT_INT4 8
+
+enum {
+ TMS32051_PC = 1,
+ TMS32051_ACC,
+ TMS32051_ACCB,
+ TMS32051_PREG,
+ TMS32051_TREG0,
+ TMS32051_TREG1,
+ TMS32051_TREG2,
+ TMS32051_BMAR,
+ TMS32051_RPTC,
+ TMS32051_BRCR,
+ TMS32051_INDX,
+ TMS32051_DBMR,
+ TMS32051_ARCR,
+ TMS32051_DP,
+ TMS32051_ARP,
+ TMS32051_ARB,
+ TMS32051_AR0,
+ TMS32051_AR1,
+ TMS32051_AR2,
+ TMS32051_AR3,
+ TMS32051_AR4,
+ TMS32051_AR5,
+ TMS32051_AR6,
+ TMS32051_AR7,
+};
+
+typedef struct
+{
+ UINT16 iptr;
+ UINT16 avis;
+ UINT16 ovly;
+ UINT16 ram;
+ UINT16 mpmc;
+ UINT16 ndx;
+ UINT16 trm;
+ UINT16 braf;
+} PMST;
+
+typedef struct
+{
+ UINT16 dp;
+ UINT16 intm;
+ UINT16 ovm;
+ UINT16 ov;
+ UINT16 arp;
+} ST0;
+
+typedef struct
+{
+ UINT16 arb;
+ UINT16 cnf;
+ UINT16 tc;
+ UINT16 sxm;
+ UINT16 c;
+ UINT16 hm;
+ UINT16 xf;
+ UINT16 pm;
+} ST1;
+
+typedef struct {
+ UINT16 pc;
+ UINT16 op;
+ INT32 acc;
+ INT32 accb;
+ INT32 preg;
+ UINT16 treg0;
+ UINT16 treg1;
+ UINT16 treg2;
+ UINT16 ar[8];
+ INT32 rptc;
+
+ UINT16 bmar;
+ INT32 brcr;
+ UINT16 paer;
+ UINT16 pasr;
+ UINT16 indx;
+ UINT16 dbmr;
+ UINT16 arcr;
+
+ ST0 st0;
+ ST1 st1;
+ PMST pmst;
+
+ UINT16 ifr;
+ UINT16 imr;
+
+ UINT16 pcstack[8];
+ int pcstack_ptr;
+
+ UINT16 rpt_start, rpt_end;
+
+ UINT16 cbcr;
+ UINT16 cbsr1;
+ UINT16 cber1;
+ UINT16 cbsr2;
+ UINT16 cber2;
+
+ struct
+ {
+ int tddr;
+ int psc;
+ UINT16 tim;
+ UINT16 prd;
+ } timer;
+
+ struct
+ {
+ INT32 acc;
+ INT32 accb;
+ UINT16 arcr;
+ UINT16 indx;
+ PMST pmst;
+ INT32 preg;
+ ST0 st0;
+ ST1 st1;
+ INT32 treg0;
+ INT32 treg1;
+ INT32 treg2;
+ } shadow;
+
+ int (*irq_callback)(int irqline);
+} TMS_REGS;
+
+static TMS_REGS tms;
+static int tms_icount;
+
+#define CYCLES(x) (tms_icount -= x)
+
+#define ROPCODE() cpu_readop16((tms.pc++) << 1)
+
+INLINE void CHANGE_PC(UINT16 new_pc)
+{
+ tms.pc = new_pc;
+ change_pc(tms.pc << 1);
+}
+
+INLINE UINT16 PM_READ16(UINT16 address)
+{
+ return program_read_word_16le(address << 1);
+}
+
+INLINE void PM_WRITE16(UINT16 address, UINT16 data)
+{
+ program_write_word_16le(address << 1, data);
+}
+
+INLINE UINT16 DM_READ16(UINT16 address)
+{
+ return data_read_word_16le(address << 1);
+}
+
+INLINE void DM_WRITE16(UINT16 address, UINT16 data)
+{
+ data_write_word_16le(address << 1, data);
+}
+
+#include "32051ops.c"
+#include "32051ops.h"
+
+static void op_group_be(void)
+{
+ tms32051_opcode_table_be[tms.op & 0xff]();
+}
+
+static void op_group_bf(void)
+{
+ tms32051_opcode_table_bf[tms.op & 0xff]();
+}
+
+static void delay_slot(UINT16 startpc)
+{
+ tms.op = ROPCODE();
+ tms32051_opcode_table[tms.op >> 8]();
+
+ while (tms.pc - startpc < 2)
+ {
+ tms.op = ROPCODE();
+ tms32051_opcode_table[tms.op >> 8]();
+ }
+}
+
+/*****************************************************************************/
+
+static void tms_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+
+}
+
+static void tms_reset(void)
+{
+ int i;
+ UINT16 src, dst, length;
+
+ src = 0x7800;
+ dst = DM_READ16(src++);
+ length = DM_READ16(src++);
+
+ CHANGE_PC(dst);
+
+ for (i=0; i < length; i++)
+ {
+ UINT16 data = DM_READ16(src++);
+ PM_WRITE16(dst++, data);
+ }
+
+ tms.st0.intm = 1;
+ tms.st0.ov = 0;
+ tms.st1.c = 1;
+ tms.st1.cnf = 0;
+ tms.st1.hm = 1;
+ tms.st1.pm = 0;
+ tms.st1.sxm = 1;
+ tms.st1.xf = 1;
+ tms.pmst.avis = 0;
+ tms.pmst.braf = 0;
+ tms.pmst.iptr = 0;
+ tms.pmst.ndx = 0;
+ tms.pmst.ovly = 0;
+ tms.pmst.ram = 0;
+ tms.pmst.trm = 0;
+ tms.ifr = 0;
+ tms.cbcr = 0;
+ tms.rptc = -1;
+}
+
+static void check_interrupts(void)
+{
+ int i;
+
+ if (tms.st0.intm == 0 && tms.ifr != 0)
+ {
+ for (i=0; i < 16; i++)
+ {
+ if (tms.ifr & (1 << i))
+ {
+ tms.st0.intm = 1;
+ PUSH_STACK(tms.pc);
+
+ tms.pc = (tms.pmst.iptr << 11) | ((i+1) << 1);
+ tms.ifr &= ~(1 << i);
+
+ save_interrupt_context();
+ break;
+ }
+ }
+ }
+}
+
+static void save_interrupt_context(void)
+{
+ tms.shadow.acc = tms.acc;
+ tms.shadow.accb = tms.accb;
+ tms.shadow.arcr = tms.arcr;
+ tms.shadow.indx = tms.indx;
+ tms.shadow.preg = tms.preg;
+ tms.shadow.treg0 = tms.treg0;
+ tms.shadow.treg1 = tms.treg1;
+ tms.shadow.treg2 = tms.treg2;
+ memcpy(&tms.shadow.pmst, &tms.pmst, sizeof(PMST));
+ memcpy(&tms.shadow.st0, &tms.st0, sizeof(ST0));
+ memcpy(&tms.shadow.st1, &tms.st1, sizeof(ST1));
+}
+
+static void restore_interrupt_context(void)
+{
+ tms.acc = tms.shadow.acc;
+ tms.accb = tms.shadow.accb;
+ tms.arcr = tms.shadow.arcr;
+ tms.indx = tms.shadow.indx;
+ tms.preg = tms.shadow.preg;
+ tms.treg0 = tms.shadow.treg0;
+ tms.treg1 = tms.shadow.treg1;
+ tms.treg2 = tms.shadow.treg2;
+ memcpy(&tms.pmst, &tms.shadow.pmst, sizeof(PMST));
+ memcpy(&tms.st0, &tms.shadow.st0, sizeof(ST0));
+ memcpy(&tms.st1, &tms.shadow.st1, sizeof(ST1));
+}
+
+static void tms_interrupt(int irq)
+{
+ if ((tms.imr & (1 << irq)) != 0)
+ {
+ tms.ifr |= 1 << irq;
+ }
+
+ check_interrupts();
+}
+
+static void tms_exit(void)
+{
+ /* TODO */
+}
+
+static void tms_get_context(void *dst)
+{
+ /* copy the context */
+ if (dst)
+ *(TMS_REGS *)dst = tms;
+}
+
+static void tms_set_context(void *src)
+{
+ /* copy the context */
+ if (src)
+ tms = *(TMS_REGS *)src;
+
+ CHANGE_PC(tms.pc);
+}
+
+static int tms_execute(int num_cycles)
+{
+ tms_icount = num_cycles;
+
+ while(tms_icount > 0)
+ {
+ UINT16 ppc;
+
+ // handle block repeat
+ if (tms.pmst.braf)
+ {
+ if (tms.pc == tms.paer)
+ {
+ if (tms.brcr > 0)
+ {
+ CHANGE_PC(tms.pasr);
+ }
+
+ tms.brcr--;
+ if (tms.brcr <= 0)
+ {
+ tms.pmst.braf = 0;
+ }
+ }
+ }
+
+ ppc = tms.pc;
+ CALL_MAME_DEBUG;
+
+ tms.op = ROPCODE();
+ tms32051_opcode_table[tms.op >> 8]();
+
+ // handle single repeat
+ if (tms.rptc > 0)
+ {
+ if (ppc == tms.rpt_end)
+ {
+ CHANGE_PC(tms.rpt_start);
+ tms.rptc--;
+ }
+ }
+ else
+ {
+ tms.rptc = 0;
+ }
+
+ tms.timer.psc--;
+ if (tms.timer.psc <= 0)
+ {
+ tms.timer.psc = tms.timer.tddr;
+ tms.timer.tim--;
+ if (tms.timer.tim <= 0)
+ {
+ // reset timer
+ tms.timer.tim = tms.timer.prd;
+
+ tms_interrupt(INTERRUPT_TINT);
+ }
+ }
+ }
+ return num_cycles - tms_icount;
+}
+
+
+/*****************************************************************************/
+
+static READ16_HANDLER( cpuregs_r )
+{
+ switch (offset)
+ {
+ case 0x04: return tms.imr;
+ case 0x06: return tms.ifr;
+
+ case 0x07: // PMST
+ {
+ UINT16 r = 0;
+ r |= tms.pmst.iptr << 11;
+ r |= tms.pmst.avis << 7;
+ r |= tms.pmst.ovly << 5;
+ r |= tms.pmst.ram << 4;
+ r |= tms.pmst.mpmc << 3;
+ r |= tms.pmst.ndx << 2;
+ r |= tms.pmst.trm << 1;
+ r |= tms.pmst.braf << 0;
+ return r;
+ }
+
+ case 0x09: return tms.brcr;
+ case 0x10: return tms.ar[0];
+ case 0x11: return tms.ar[1];
+ case 0x12: return tms.ar[2];
+ case 0x13: return tms.ar[3];
+ case 0x14: return tms.ar[4];
+ case 0x15: return tms.ar[5];
+ case 0x16: return tms.ar[6];
+ case 0x17: return tms.ar[7];
+ case 0x1e: return tms.cbcr;
+ case 0x1f: return tms.bmar;
+ case 0x24: return tms.timer.tim;
+ case 0x25: return tms.timer.prd;
+
+ case 0x26: // TCR
+ {
+ UINT16 r = 0;
+ r |= (tms.timer.psc & 0xf) << 6;
+ r |= (tms.timer.tddr & 0xf);
+ return r;
+ }
+
+ case 0x28: return 0; // PDWSR
+ default: fatalerror("32051: cpuregs_r: unimplemented memory-mapped register %02X at %04X\n", offset, tms.pc-1);
+ }
+
+ return 0;
+}
+
+static WRITE16_HANDLER( cpuregs_w )
+{
+ switch (offset)
+ {
+ case 0x00: break;
+ case 0x04: tms.imr = data; break;
+ case 0x06: // IFR
+ {
+ int i;
+ for (i=0; i < 16; i++)
+ {
+ if (data & (1 << i))
+ {
+ tms.ifr &= ~(1 << i);
+ }
+ }
+ break;
+ }
+
+ case 0x07: // PMST
+ {
+ tms.pmst.iptr = (data >> 11) & 0x1f;
+ tms.pmst.avis = (data & 0x80) ? 1 : 0;
+ tms.pmst.ovly = (data & 0x20) ? 1 : 0;
+ tms.pmst.ram = (data & 0x10) ? 1 : 0;
+ tms.pmst.mpmc = (data & 0x08) ? 1 : 0;
+ tms.pmst.ndx = (data & 0x04) ? 1 : 0;
+ tms.pmst.trm = (data & 0x02) ? 1 : 0;
+ tms.pmst.braf = (data & 0x01) ? 1 : 0;
+ break;
+ }
+
+ case 0x09: tms.brcr = data; break;
+ case 0x0e: tms.treg2 = data; break;
+ case 0x0f: tms.dbmr = data; break;
+ case 0x10: tms.ar[0] = data; break;
+ case 0x11: tms.ar[1] = data; break;
+ case 0x12: tms.ar[2] = data; break;
+ case 0x13: tms.ar[3] = data; break;
+ case 0x14: tms.ar[4] = data; break;
+ case 0x15: tms.ar[5] = data; break;
+ case 0x16: tms.ar[6] = data; break;
+ case 0x17: tms.ar[7] = data; break;
+ case 0x18: tms.indx = data; break;
+ case 0x19: tms.arcr = data; break;
+ case 0x1a: tms.cbsr1 = data; break;
+ case 0x1b: tms.cber1 = data; break;
+ case 0x1c: tms.cbsr2 = data; break;
+ case 0x1d: tms.cber2 = data; break;
+ case 0x1e: tms.cbcr = data; break;
+ case 0x1f: tms.bmar = data; break;
+ case 0x24: tms.timer.tim = data; break;
+ case 0x25: tms.timer.prd = data; break;
+
+ case 0x26: // TCR
+ {
+ tms.timer.tddr = data & 0xf;
+ tms.timer.psc = (data >> 6) & 0xf;
+
+ if (data & 0x20)
+ {
+ tms.timer.tim = tms.timer.prd;
+ tms.timer.psc = tms.timer.tddr;
+ }
+ break;
+ }
+
+ case 0x28: break; // PDWSR
+ default: fatalerror("32051: cpuregs_w: unimplemented memory-mapped register %02X, data %04X at %04X\n", offset, data, tms.pc-1);
+ }
+}
+
+/**************************************************************************
+ * Internal memory map
+ **************************************************************************/
+
+static ADDRESS_MAP_START( internal_pgm, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x2000, 0x23ff) AM_RAM // SARAM
+ AM_RANGE(0xfe00, 0xffff) AM_RAM AM_SHARE(11) // DARAM B0
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( internal_data, ADDRESS_SPACE_DATA, 16 )
+ AM_RANGE(0x0000, 0x005f) AM_READWRITE(cpuregs_r, cpuregs_w)
+ AM_RANGE(0x0060, 0x007f) AM_RAM // DARAM B2
+ AM_RANGE(0x0100, 0x02ff) AM_RAM AM_SHARE(11) // DARAM B0
+ AM_RANGE(0x0300, 0x04ff) AM_RAM // DARAM B1
+ADDRESS_MAP_END
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void tms_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS32051_PC: tms.pc = info->i; break;
+ }
+}
+
+static int tms_debug_read(int space, UINT32 offset, int size, UINT64 *value)
+{
+ if (space == ADDRESS_SPACE_PROGRAM)
+ {
+ *value = (PM_READ16(offset>>1) >> ((offset & 1) ? 0 : 8)) & 0xff;
+ }
+ else if (space == ADDRESS_SPACE_DATA)
+ {
+ *value = (DM_READ16(offset>>1) >> ((offset & 1) ? 0 : 8)) & 0xff;
+ }
+ return 1;
+}
+
+static void tms_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(tms); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 6; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 5; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS32051_PC: info->i = tms.pc; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ACC: info->i = tms.acc; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ACCB: info->i = tms.accb; break;
+ case CPUINFO_INT_REGISTER + TMS32051_PREG: info->i = tms.preg; break;
+ case CPUINFO_INT_REGISTER + TMS32051_TREG0: info->i = tms.treg0; break;
+ case CPUINFO_INT_REGISTER + TMS32051_TREG1: info->i = tms.treg1; break;
+ case CPUINFO_INT_REGISTER + TMS32051_TREG2: info->i = tms.treg2; break;
+ case CPUINFO_INT_REGISTER + TMS32051_BMAR: info->i = tms.bmar; break;
+ case CPUINFO_INT_REGISTER + TMS32051_RPTC: info->i = tms.rptc; break;
+ case CPUINFO_INT_REGISTER + TMS32051_BRCR: info->i = tms.brcr; break;
+ case CPUINFO_INT_REGISTER + TMS32051_INDX: info->i = tms.indx; break;
+ case CPUINFO_INT_REGISTER + TMS32051_DBMR: info->i = tms.dbmr; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ARCR: info->i = tms.arcr; break;
+ case CPUINFO_INT_REGISTER + TMS32051_DP: info->i = tms.st0.dp; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ARP: info->i = tms.st0.arp; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ARB: info->i = tms.st1.arb; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR0: info->i = tms.ar[0]; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR1: info->i = tms.ar[1]; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR2: info->i = tms.ar[2]; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR3: info->i = tms.ar[3]; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR4: info->i = tms.ar[4]; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR5: info->i = tms.ar[5]; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR6: info->i = tms.ar[6]; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR7: info->i = tms.ar[7]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tms_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tms_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = tms_init; break;
+ case CPUINFO_PTR_RESET: info->reset = tms_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = tms_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = tms_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tms32051_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_READ: info->read = tms_debug_read; break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &tms_icount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_internal_pgm; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map = construct_map_internal_data; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "TMS3205x"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2005-2006 Ville Linde"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + TMS32051_PC: sprintf(info->s, "PC: %04X", tms.pc); break;
+ case CPUINFO_STR_REGISTER + TMS32051_ACC: sprintf(info->s, "ACC: %08X", tms.acc); break;
+ case CPUINFO_STR_REGISTER + TMS32051_ACCB: sprintf(info->s, "ACCB: %08X", tms.accb); break;
+ case CPUINFO_STR_REGISTER + TMS32051_PREG: sprintf(info->s, "PREG: %08X", tms.preg); break;
+ case CPUINFO_STR_REGISTER + TMS32051_TREG0: sprintf(info->s, "TREG0: %04X", tms.treg0); break;
+ case CPUINFO_STR_REGISTER + TMS32051_TREG1: sprintf(info->s, "TREG1: %04X", tms.treg1); break;
+ case CPUINFO_STR_REGISTER + TMS32051_TREG2: sprintf(info->s, "TREG2: %04X", tms.treg2); break;
+ case CPUINFO_STR_REGISTER + TMS32051_BMAR: sprintf(info->s, "BMAR: %08X", tms.bmar); break;
+ case CPUINFO_STR_REGISTER + TMS32051_RPTC: sprintf(info->s, "RPTC: %08X", tms.rptc); break;
+ case CPUINFO_STR_REGISTER + TMS32051_BRCR: sprintf(info->s, "BRCR: %08X", tms.brcr); break;
+ case CPUINFO_STR_REGISTER + TMS32051_INDX: sprintf(info->s, "INDX: %04X", tms.indx); break;
+ case CPUINFO_STR_REGISTER + TMS32051_DBMR: sprintf(info->s, "DBMR: %04X", tms.dbmr); break;
+ case CPUINFO_STR_REGISTER + TMS32051_ARCR: sprintf(info->s, "ARCR: %04X", tms.arcr); break;
+ case CPUINFO_STR_REGISTER + TMS32051_DP: sprintf(info->s, "DP: %04X", tms.st0.dp); break;
+ case CPUINFO_STR_REGISTER + TMS32051_ARP: sprintf(info->s, "ARP: %04X", tms.st0.arp); break;
+ case CPUINFO_STR_REGISTER + TMS32051_ARB: sprintf(info->s, "ARB: %04X", tms.st1.arb); break;
+ case CPUINFO_STR_REGISTER + TMS32051_AR0: sprintf(info->s, "AR0: %04X", tms.ar[0]); break;
+ case CPUINFO_STR_REGISTER + TMS32051_AR1: sprintf(info->s, "AR1: %04X", tms.ar[1]); break;
+ case CPUINFO_STR_REGISTER + TMS32051_AR2: sprintf(info->s, "AR2: %04X", tms.ar[2]); break;
+ case CPUINFO_STR_REGISTER + TMS32051_AR3: sprintf(info->s, "AR3: %04X", tms.ar[3]); break;
+ case CPUINFO_STR_REGISTER + TMS32051_AR4: sprintf(info->s, "AR4: %04X", tms.ar[4]); break;
+ case CPUINFO_STR_REGISTER + TMS32051_AR5: sprintf(info->s, "AR5: %04X", tms.ar[5]); break;
+ case CPUINFO_STR_REGISTER + TMS32051_AR6: sprintf(info->s, "AR6: %04X", tms.ar[6]); break;
+ case CPUINFO_STR_REGISTER + TMS32051_AR7: sprintf(info->s, "AR7: %04X", tms.ar[7]); break;
+ }
+}
+
+#if (HAS_TMS32051)
+void tms32051_set_info(UINT32 state, cpuinfo *info)
+{
+ if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5)
+ {
+ return;
+ }
+ switch(state)
+ {
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS32051_PC: tms.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ACC: tms.acc = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ACCB: tms.accb = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_PREG: tms.preg = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_TREG0: tms.treg0 = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_TREG1: tms.treg1 = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_TREG2: tms.treg2 = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_BMAR: tms.bmar = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_BRCR: tms.brcr = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_INDX: tms.indx = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_DBMR: tms.dbmr = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ARCR: tms.arcr = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_DP: tms.st0.dp = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ARP: tms.st0.arp = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_ARB: tms.st1.arb = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR0: tms.ar[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR1: tms.ar[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR2: tms.ar[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR3: tms.ar[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR4: tms.ar[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR5: tms.ar[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR6: tms.ar[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS32051_AR7: tms.ar[7] = info->i; break;
+
+ default: tms_set_info(state, info); break;
+ }
+}
+
+void tms32051_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = tms32051_set_info; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "TMS32051"); break;
+
+ default: tms_get_info(state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/tms32051/tms32051.h b/src/emu/cpu/tms32051/tms32051.h
new file mode 100644
index 00000000000..86576b524e9
--- /dev/null
+++ b/src/emu/cpu/tms32051/tms32051.h
@@ -0,0 +1,12 @@
+#ifndef _TMS32051_H
+#define _TMS32051_H
+
+#if (HAS_TMS32051)
+void tms32051_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#ifdef MAME_DEBUG
+offs_t tms32051_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _TMS32051_H */
diff --git a/src/emu/cpu/tms34010/34010dsm.c b/src/emu/cpu/tms34010/34010dsm.c
new file mode 100644
index 00000000000..129ae27517e
--- /dev/null
+++ b/src/emu/cpu/tms34010/34010dsm.c
@@ -0,0 +1,1760 @@
+/*
+ * A TMS34010 disassembler
+ *
+ * This code written by Zsolt Vasvari for the MAME project
+ *
+ */
+
+#include "cpuintrf.h"
+
+#ifdef STANDALONE
+#define PC __pc + (offset << 3)
+#define OP_WORD(v) { v = filebuf[_pc>>3]; _pc += 8; v = v | (filebuf[_pc>>3] << 8); _pc += 8;}
+#define PARAM_WORD(v) { v = filebuf[_pc>>3]; _pc += 8; v = v | (filebuf[_pc>>3] << 8); _pc += 8;}
+#define PARAM_LONG(v) { int v1, v2; PARAM_WORD(v1); PARAM_WORD(v2); v = v1 | (v2 << 16); }
+#else
+#define PC __pc
+#define OP_WORD(v) { v = rombase[(__pc - pcbase) >> 3] | (rombase[(__pc + 8 - pcbase) >> 3] << 8); _pc += 16; }
+#define PARAM_WORD(v) { v = rambase[(__pc + 16 - pcbase) >> 3] | (rambase[(__pc + 24 - pcbase) >> 3] << 8); _pc += 16; }
+#define PARAM_LONG(v) { v = rambase[(__pc + 16 - pcbase) >> 3] | (rambase[(__pc + 24 - pcbase) >> 3] << 8) | (rambase[(__pc + 32 - pcbase) >> 3] << 16) | (rambase[(__pc + 40 - pcbase) >> 3] << 24); _pc += 32; }
+#endif
+
+static UINT8 rf;
+static UINT32 __pc, _pc;
+static UINT16 op,rs,rd;
+
+static char *buffer;
+static char temp[20];
+
+static const UINT8 *rombase;
+static const UINT8 *rambase;
+static offs_t pcbase;
+
+
+static void print_reg(UINT8 reg)
+{
+ if (reg != 0x0f)
+ {
+ sprintf(temp, "%c%d", rf, reg);
+ strcat(buffer, temp);
+ }
+ else
+ {
+ strcat(buffer, "SP");
+ }
+}
+
+static void print_src_reg(void)
+{
+ print_reg(rs);
+}
+
+static void print_des_reg(void)
+{
+ print_reg(rd);
+}
+
+static void print_src_des_reg(void)
+{
+ print_src_reg();
+ strcat(buffer, ",");
+ print_des_reg();
+}
+
+static void print_word_parm(void)
+{
+ UINT16 w;
+
+ PARAM_WORD(w);
+
+ sprintf(temp, "%Xh", w);
+ strcat(buffer, temp);
+}
+
+static void print_word_parm_1s_comp(void)
+{
+ UINT16 w;
+
+ PARAM_WORD(w);
+ w = ~w;
+ sprintf(temp, "%Xh", w);
+ strcat(buffer, temp);
+}
+
+static void print_long_parm(void)
+{
+ UINT32 l;
+
+ PARAM_LONG(l);
+ sprintf(temp, "%Xh", l);
+ strcat(buffer, temp);
+}
+
+static void print_long_parm_1s_comp(void)
+{
+ UINT32 l;
+
+ PARAM_LONG(l);
+ sprintf(temp, "%Xh", ~l);
+ strcat(buffer, temp);
+}
+
+static void print_constant(void)
+{
+ UINT8 constant = (op >> 5) & 0x1f;
+
+ sprintf(temp, "%Xh", constant);
+ strcat(buffer, temp);
+}
+
+static void print_constant_1_32(void)
+{
+ UINT8 constant = (op >> 5) & 0x1f;
+ if (!constant) constant = 0x20;
+
+ sprintf(temp, "%Xh", constant);
+ strcat(buffer, temp);
+}
+
+static void print_constant_1s_comp(void)
+{
+ UINT8 constant = (~op >> 5) & 0x1f;
+
+ sprintf(temp, "%Xh", constant);
+ strcat(buffer, temp);
+}
+
+static void print_constant_2s_comp(void)
+{
+ UINT8 constant = 32 - ((op >> 5) & 0x1f);
+
+ sprintf(temp, "%Xh", constant);
+ strcat(buffer, temp);
+}
+
+static void print_relative(void)
+{
+ UINT16 l;
+ INT16 ls;
+
+ PARAM_WORD(l);
+ ls = (INT16)l;
+
+ sprintf(temp, "%Xh", PC + 32 + (ls << 4));
+ strcat(buffer, temp);
+}
+
+static void print_relative_8bit(void)
+{
+ INT8 ls = (INT8)op;
+
+ sprintf(temp, "%Xh", PC + 16 + (ls << 4));
+ strcat(buffer, temp);
+}
+
+static void print_relative_5bit(void)
+{
+ INT8 ls = (INT8)((op >> 5) & 0x1f);
+ if (op & 0x0400) ls = -ls;
+
+ sprintf(temp, "%Xh", PC + 16 + (ls << 4));
+ strcat(buffer, temp);
+}
+
+static void print_field(void)
+{
+ sprintf(temp, "%c", (op & 0x200) ? '1' : '0');
+ strcat(buffer, temp);
+}
+
+static void print_condition_code(void)
+{
+ switch (op & 0x0f00)
+ {
+ case 0x0000: strcat(buffer, " "); break; /* This is really UC (Unconditional) */
+ case 0x0100: strcat(buffer, "P "); break;
+ case 0x0200: strcat(buffer, "LS"); break;
+ case 0x0300: strcat(buffer, "HI"); break;
+ case 0x0400: strcat(buffer, "LT"); break;
+ case 0x0500: strcat(buffer, "GE"); break;
+ case 0x0600: strcat(buffer, "LE"); break;
+ case 0x0700: strcat(buffer, "GT"); break;
+ case 0x0800: strcat(buffer, "C "); break;
+ case 0x0900: strcat(buffer, "NC"); break;
+ case 0x0a00: strcat(buffer, "EQ"); break;
+ case 0x0b00: strcat(buffer, "NE"); break;
+ case 0x0c00: strcat(buffer, "V "); break;
+ case 0x0d00: strcat(buffer, "NV"); break;
+ case 0x0e00: strcat(buffer, "N "); break;
+ case 0x0f00: strcat(buffer, "NN"); break;
+ }
+}
+
+static void print_reg_list_range(INT8 first, INT8 last)
+{
+ if ((first != -1 ) && (first != last))
+ {
+ if ((last - first) == 1)
+ strcat(buffer, ",");
+ else
+ strcat(buffer, "-");
+ print_reg(last);
+ }
+}
+
+static void print_reg_list(UINT16 rev)
+{
+ UINT16 l;
+ UINT8 i;
+ INT8 first = -1, last = 0;
+
+ PARAM_WORD(l);
+
+ for (i = 0; i < 16; i++)
+ {
+ int moved;
+
+ if (rev)
+ {
+ moved = l & 0x8000;
+ l <<= 1;
+ }
+ else
+ {
+ moved = l & 0x01;
+ l >>= 1;
+ }
+
+ if (moved)
+ {
+ if (first == -1)
+ {
+ strcat(buffer, ",");
+ print_reg(i);
+ first = i;
+ }
+ last = i;
+ }
+ else
+ {
+ print_reg_list_range(first, last);
+ first = -1;
+ }
+ }
+
+ print_reg_list_range(first, last);
+}
+
+
+unsigned Dasm340x0(char *buff, UINT32 pc, int is_34020)
+{
+ int flags = 0;
+ UINT8 bad = 0;
+ UINT16 subop;
+
+ __pc = _pc = pc;
+ buffer = buff;
+
+ OP_WORD(op);
+
+ subop = (op & 0x01e0);
+ rs = (op >> 5) & 0x0f; /* Source register */
+ rd = op & 0x0f; /* Destination register */
+ rf = ((op & 0x10) ? 'B' : 'A'); /* Register file */
+
+ switch (op & 0xfe00)
+ {
+ case 0x0000:
+ switch (subop)
+ {
+ case 0x0020:
+ sprintf (buffer, "REV ");
+ print_des_reg();
+ break;
+
+ case 0x0040:
+ if (is_34020)
+ sprintf (buffer, "IDLE ");
+ else
+ bad = 1;
+ break;
+
+ case 0x0080:
+ if (is_34020)
+ sprintf (buffer, "MWAIT ");
+ else
+ bad = 1;
+ break;
+
+ case 0x00e0:
+ if (is_34020)
+ sprintf (buffer, "BLMOVE %d,%d", (op >> 1) & 1, op & 1);
+ else
+ bad = 1;
+ break;
+
+ case 0x0100:
+ sprintf (buffer, "EMU ");
+ break;
+
+ case 0x0120:
+ sprintf (buffer, "EXGPC ");
+ print_des_reg();
+ break;
+
+ case 0x0140:
+ sprintf (buffer, "GETPC ");
+ print_des_reg();
+ break;
+
+ case 0x0160:
+ sprintf (buffer, "JUMP ");
+ print_des_reg();
+ break;
+
+ case 0x0180:
+ sprintf (buffer, "GETST ");
+ print_des_reg();
+ break;
+
+ case 0x01a0:
+ sprintf (buffer, "PUTST ");
+ print_des_reg();
+ break;
+
+ case 0x01c0:
+ sprintf (buffer, "POPST ");
+ break;
+
+ case 0x01e0:
+ sprintf (buffer, "PUSHST ");
+ break;
+
+ default:
+ bad = 1;
+ }
+ break;
+
+
+ case 0x0200:
+ switch (subop)
+ {
+ case 0x0040:
+ if (is_34020)
+ sprintf (buffer, "SETCSP ");
+ else
+ bad = 1;
+ break;
+
+ case 0x0060:
+ if (is_34020)
+ sprintf (buffer, "SETCDP ");
+ else
+ bad = 1;
+ break;
+
+ case 0x0080:
+ if (is_34020)
+ {
+ sprintf (buffer, "RPIX ");
+ print_des_reg();
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x00a0:
+ if (is_34020)
+ {
+ sprintf (buffer, "EXGPS ");
+ print_des_reg();
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x00c0:
+ if (is_34020)
+ {
+ sprintf (buffer, "GETPS ");
+ print_des_reg();
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x00e0:
+ if (is_34020)
+ sprintf (buffer, "SETCMP ");
+ else
+ bad = 1;
+ break;
+
+ case 0x0100:
+ sprintf (buffer, "NOP ");
+ break;
+
+ case 0x0120:
+ sprintf (buffer, "CLRC ");
+ break;
+
+ case 0x0140:
+ sprintf (buffer, "MOVB @");
+ print_long_parm();
+ strcat(buffer, ",@");
+ print_long_parm();
+ break;
+
+ case 0x0160:
+ sprintf (buffer, "DINT ");
+ break;
+
+ case 0x0180:
+ sprintf (buffer, "ABS ");
+ print_des_reg();
+ break;
+
+ case 0x01a0:
+ sprintf (buffer, "NEG ");
+ print_des_reg();
+ break;
+
+ case 0x01c0:
+ sprintf (buffer, "NEGB ");
+ print_des_reg();
+ break;
+
+ case 0x01e0:
+ sprintf (buffer, "NOT ");
+ print_des_reg();
+ break;
+
+ default:
+ bad = 1;
+ }
+ break;
+
+
+ case 0x0400:
+ case 0x0600:
+ switch (subop)
+ {
+ case 0x0000:
+ if (is_34020 && (op & 0xfe00) == 0x0600)
+ {
+ UINT32 x;
+ PARAM_LONG(x);
+ sprintf(buffer, "CEXEC %d,%06X,%d", (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x0020:
+ if (is_34020 && (op & 0xfe00) == 0x0600)
+ {
+ UINT32 x;
+ PARAM_LONG(x);
+ sprintf(buffer, "CMOVGC ");
+ print_des_reg();
+ sprintf(temp, ",%06X,%d", (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ strcat(buffer, temp);
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x0040:
+ if (is_34020 && (op & 0xfe00) == 0x0600)
+ {
+ UINT32 x;
+ PARAM_LONG(x);
+ sprintf(buffer, "CMOVGC ");
+ print_des_reg();
+ strcat(buffer, ",");
+ rf = (x & 0x10) ? 'B' : 'A';
+ print_reg(x & 0x0f);
+ sprintf(temp, ",%d,%06X,%d", (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ strcat(buffer, temp);
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x0060:
+ if (is_34020 && (op & 0xfe00) == 0x0600)
+ {
+ UINT32 x;
+ PARAM_LONG(x);
+
+ if (op == 0x0660 && (x & 0xff) == 0x01)
+ {
+ sprintf(buffer, "CMOVCS ");
+ sprintf(temp, ",%06X,%d", (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ strcat(buffer, temp);
+ }
+ else
+ {
+ sprintf(buffer, "CMOVCG ");
+ print_des_reg();
+ strcat(buffer, ",");
+ rf = (x & 0x10) ? 'B' : 'A';
+ print_reg(x & 0x0f);
+ sprintf(temp, ",%d,%06X,%d", (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ strcat(buffer, temp);
+ }
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x0080:
+ if (is_34020 && (op & 0xfe00) == 0x0600)
+ {
+ UINT32 x;
+ PARAM_LONG(x);
+ sprintf(buffer, "CMOVMC *");
+ rf = (x & 0x10) ? 'B' : 'A';
+ print_reg(x & 0x0f);
+ sprintf(temp, "+,%d,%d,%06X,%d", op & 0x1f, (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ strcat(buffer, temp);
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x00a0:
+ if (is_34020 && (op & 0xfe00) == 0x0600)
+ {
+ UINT32 x;
+ PARAM_LONG(x);
+ sprintf(buffer, "CMOVCM *");
+ print_des_reg();
+ sprintf(temp, "+,%d,%d,%06X,%d", x & 0x1f, (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ strcat(buffer, temp);
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x00c0:
+ if (is_34020 && (op & 0xfe00) == 0x0600)
+ {
+ UINT32 x;
+ PARAM_LONG(x);
+ sprintf(buffer, "CMOVCM *-");
+ print_des_reg();
+ sprintf(temp, ",%d,%d,%06X,%d", x & 0x1f, (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ strcat(buffer, temp);
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x00e0:
+ if (is_34020 && (op & 0xfe00) == 0x0600)
+ {
+ UINT32 x;
+ PARAM_LONG(x);
+ sprintf(buffer, "CMOVMC *");
+ rf = (x & 0x10) ? 'B' : 'A';
+ print_reg(x & 0x0f);
+ strcat(buffer, "+,");
+ rf = (op & 0x10) ? 'B' : 'A';
+ print_reg(op & 0x0f);
+ sprintf(temp, ",%d,%06X,%d", (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ strcat(buffer, temp);
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x0100:
+ sprintf (buffer, "SEXT ");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+ case 0x0120:
+ sprintf (buffer, "ZEXT ");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+ case 0x0140:
+ case 0x0160:
+ sprintf (buffer, "SETF %Xh,%X,",
+ (op & 0x1f) ? op & 0x1f : 0x20,
+ (op >> 5) & 1);
+ print_field();
+ break;
+
+ case 0x0180:
+ sprintf (buffer, "MOVE ");
+ print_des_reg();
+ strcat(buffer, ",@");
+ print_long_parm();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+ case 0x01a0:
+ sprintf (buffer, "MOVE @");
+ print_long_parm();
+ strcat(buffer, ",");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+ case 0x01c0:
+ sprintf (buffer, "MOVE @");
+ print_long_parm();
+ strcat(buffer, ",@");
+ print_long_parm();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+ case 0x01e0:
+ if (op & 0x200)
+ {
+ sprintf (buffer, "MOVE @");
+ print_long_parm();
+ strcat(buffer, ",");
+ print_des_reg();
+ }
+ else
+ {
+ sprintf (buffer, "MOVB ");
+ print_des_reg();
+ strcat(buffer, ",@");
+ print_long_parm();
+ }
+ break;
+
+ default:
+ bad = 1;
+ }
+ break;
+
+
+ case 0x0800:
+ switch (subop)
+ {
+ case 0x0000:
+ if (is_34020)
+ {
+ sprintf (buffer, "TRAPL ");
+ flags = DASMFLAG_STEP_OVER;
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x0020:
+ if (is_34020)
+ {
+ UINT32 x;
+ PARAM_LONG(x);
+ sprintf(buffer, "CMOVMC *-");
+ rf = (x & 0x10) ? 'B' : 'A';
+ print_reg(x & 0x0f);
+ sprintf(temp, ",%d,%d,%06X,%d", op & 0x1f, (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7);
+ strcat(buffer, temp);
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x0040:
+ if (is_34020)
+ sprintf (buffer, "VBLT B,L");
+ else
+ bad = 1;
+ break;
+
+ case 0x0060:
+ if (is_34020)
+ {
+ sprintf(buffer, "RETM ");
+ flags = DASMFLAG_STEP_OUT;
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x00e0:
+ if (is_34020)
+ sprintf (buffer, "CLIP ");
+ else
+ bad = 1;
+ break;
+
+ case 0x0100:
+ sprintf (buffer, "TRAP %Xh", op & 0x1f);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ case 0x0120:
+ sprintf (buffer, "CALL ");
+ print_des_reg();
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ case 0x0140:
+ sprintf (buffer, "RETI ");
+ flags = DASMFLAG_STEP_OUT;
+ break;
+
+ case 0x0160:
+ sprintf (buffer, "RETS ");
+ flags = DASMFLAG_STEP_OUT;
+ if (op & 0x1f)
+ {
+ sprintf(temp, "%Xh", op & 0x1f);
+ strcat(buffer, temp);
+ }
+ break;
+
+ case 0x0180:
+ sprintf (buffer, "MMTM ");
+ print_des_reg();
+ print_reg_list(1);
+ break;
+
+ case 0x01a0:
+ sprintf (buffer, "MMFM ");
+ print_des_reg();
+ print_reg_list(0);
+ break;
+
+ case 0x01c0:
+ sprintf (buffer, "MOVI ");
+ print_word_parm();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x01e0:
+ sprintf (buffer, "MOVI ");
+ print_long_parm();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ default:
+ bad = 1;
+ }
+ break;
+
+
+ case 0x0a00:
+ switch (subop)
+ {
+ case 0x0000:
+ if (is_34020)
+ sprintf (buffer, "VLCOL ");
+ else
+ bad = 1;
+ break;
+
+ case 0x0020:
+ if (is_34020)
+ sprintf (buffer, "PFILL XY");
+ else
+ bad = 1;
+ break;
+
+ case 0x0040:
+ if (is_34020)
+ sprintf (buffer, "VFILL L");
+ else
+ bad = 1;
+ break;
+
+ case 0x0060:
+ if (is_34020)
+ {
+ sprintf (buffer, "CVMXYL ");
+ print_des_reg();
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x0080:
+ if (is_34020)
+ {
+ sprintf (buffer, "CVDXYL ");
+ print_des_reg();
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x00a0:
+ if (is_34020)
+ sprintf (buffer, "FPIXEQ ");
+ else
+ bad = 1;
+ break;
+
+ case 0x00c0:
+ if (is_34020)
+ sprintf (buffer, "FPIXNE ");
+ else
+ bad = 1;
+ break;
+
+ case 0x0100:
+ sprintf (buffer, "ADDI ");
+ print_word_parm();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x0120:
+ sprintf (buffer, "ADDI ");
+ print_long_parm();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x0140:
+ sprintf (buffer, "CMPI ");
+ print_word_parm_1s_comp();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x0160:
+ sprintf (buffer, "CMPI ");
+ print_long_parm_1s_comp();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x0180:
+ sprintf (buffer, "ANDI ");
+ print_long_parm_1s_comp();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x01a0:
+ sprintf (buffer, "ORI ");
+ print_long_parm();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x01c0:
+ sprintf (buffer, "XORI ");
+ print_long_parm();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x01e0:
+ sprintf (buffer, "SUBI ");
+ print_word_parm_1s_comp();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ default:
+ bad = 1;
+ }
+ break;
+
+
+ case 0x0c00:
+ switch (subop)
+ {
+ case 0x0000:
+ if (is_34020)
+ {
+ sprintf (buffer, "ADDXYI ");
+ print_long_parm();
+ strcat(buffer, ",");
+ print_des_reg();
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x0040:
+ if (is_34020)
+ sprintf (buffer, "LINIT ");
+ else
+ bad = 1;
+ break;
+
+ case 0x0100:
+ sprintf (buffer, "SUBI ");
+ print_long_parm_1s_comp();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x0120:
+ sprintf (buffer, "CALLR ");
+ print_relative();
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ case 0x0140:
+ sprintf (buffer, "CALLA ");
+ print_long_parm();
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ case 0x0160:
+ sprintf (buffer, "EINT ");
+ break;
+
+ case 0x0180:
+ sprintf (buffer, "DSJ ");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_relative();
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ case 0x01a0:
+ sprintf (buffer, "DSJEQ ");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_relative();
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ case 0x01c0:
+ sprintf (buffer, "DSJNE ");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_relative();
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+ case 0x01e0:
+ sprintf (buffer, "SETC ");
+ break;
+
+ default:
+ bad = 1;
+ }
+ break;
+
+
+ case 0x0e00:
+ flags = DASMFLAG_STEP_OVER;
+ switch (subop)
+ {
+ case 0x0000:
+ if (is_34020)
+ sprintf (buffer, "PIXBLT L,M,L");
+ else
+ bad = 1;
+ break;
+
+ case 0x00e0:
+ if (is_34020)
+ sprintf (buffer, "TFILL XY");
+ else
+ bad = 1;
+ break;
+
+ case 0x0100:
+ sprintf (buffer, "PIXBLT L,L");
+ break;
+
+ case 0x0120:
+ sprintf (buffer, "PIXBLT L,XY");
+ break;
+
+ case 0x0140:
+ sprintf (buffer, "PIXBLT XY,L");
+ break;
+
+ case 0x0160:
+ sprintf (buffer, "PIXBLT XY,XY");
+ break;
+
+ case 0x0180:
+ sprintf (buffer, "PIXBLT B,L");
+ break;
+
+ case 0x01a0:
+ sprintf (buffer, "PIXBLT B,XY");
+ break;
+
+ case 0x01c0:
+ sprintf (buffer, "FILL L");
+ break;
+
+ case 0x01e0:
+ sprintf (buffer, "FILL XY");
+ break;
+
+ default:
+ bad = 1;
+ }
+ break;
+
+
+ case 0x1000:
+ case 0x1200:
+ if ((op & 0x03e0) != 0x0020)
+ {
+ sprintf (buffer, "ADDK ");
+ print_constant_1_32();
+ strcat(buffer, ",");
+ }
+ else
+ {
+ sprintf (buffer, "INC ");
+ }
+ print_des_reg();
+
+ break;
+
+
+ case 0x1400:
+ case 0x1600:
+ if ((op & 0x03e0) != 0x0020)
+ {
+ sprintf (buffer, "SUBK ");
+ print_constant_1_32();
+ strcat(buffer, ",");
+ }
+ else
+ {
+ sprintf (buffer, "DEC ");
+ }
+ print_des_reg();
+
+ break;
+
+
+ case 0x1800:
+ case 0x1a00:
+ sprintf (buffer, "MOVK ");
+ print_constant_1_32();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+
+ case 0x1c00:
+ case 0x1e00:
+ sprintf (buffer, "BTST ");
+ print_constant_1s_comp();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+
+ case 0x2000:
+ case 0x2200:
+ sprintf (buffer, "SLA ");
+ print_constant();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+
+ case 0x2400:
+ case 0x2600:
+ sprintf (buffer, "SLL ");
+ print_constant();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+
+ case 0x2800:
+ case 0x2a00:
+ sprintf (buffer, "SRA ");
+ print_constant_2s_comp();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+
+ case 0x2c00:
+ case 0x2e00:
+ sprintf (buffer, "SRL ");
+ print_constant_2s_comp();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+
+ case 0x3000:
+ case 0x3200:
+ sprintf (buffer, "RL ");
+ print_constant();
+ strcat(buffer, ",");
+ print_des_reg();
+ break;
+
+ case 0x3400:
+ case 0x3600:
+ if (is_34020)
+ {
+ sprintf (buffer, "CMPK ");
+ print_constant_1_32();
+ strcat(buffer, ",");
+ print_des_reg();
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x3800:
+ case 0x3a00:
+ case 0x3c00:
+ case 0x3e00:
+ sprintf (buffer, "DSJS ");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_relative_5bit();
+ flags = DASMFLAG_STEP_OVER;
+ break;
+
+
+ case 0x4000:
+ sprintf (buffer, "ADD ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x4200:
+ sprintf (buffer, "ADDC ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x4400:
+ sprintf (buffer, "SUB ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x4600:
+ sprintf (buffer, "SUBB ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x4800:
+ sprintf (buffer, "CMP ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x4a00:
+ sprintf (buffer, "BTST ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x4c00:
+ case 0x4e00:
+ sprintf (buffer, "MOVE ");
+
+ if (!(op & 0x0200))
+ {
+ print_src_des_reg();
+ }
+ else
+ {
+ print_src_reg();
+ strcat(buffer, ",");
+
+ if (rf == 'A')
+ {
+ rf = 'B';
+ }
+ else
+ {
+ rf = 'A';
+ }
+
+ print_des_reg();
+ }
+ break;
+
+
+ case 0x5000:
+ sprintf (buffer, "AND ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x5200:
+ sprintf (buffer, "ANDN ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x5400:
+ sprintf (buffer, "OR ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x5600:
+ if (rs != rd)
+ {
+ sprintf (buffer, "XOR ");
+ print_src_des_reg();
+ }
+ else
+ {
+ sprintf (buffer, "CLR ");
+ print_des_reg();
+ }
+ break;
+
+
+ case 0x5800:
+ sprintf (buffer, "DIVS ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x5a00:
+ sprintf (buffer, "DIVU ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x5c00:
+ sprintf (buffer, "MPYS ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x5e00:
+ sprintf (buffer, "MPYU ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x6000:
+ sprintf (buffer, "SLA ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x6200:
+ sprintf (buffer, "SLL ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x6400:
+ sprintf (buffer, "SRA ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x6600:
+ sprintf (buffer, "SRL ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x6800:
+ sprintf (buffer, "RL ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x6a00:
+ sprintf (buffer, "LMO ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x6c00:
+ sprintf (buffer, "MODS ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x6e00:
+ sprintf (buffer, "MODU ");
+ print_src_des_reg();
+ break;
+
+
+ case 0x7a00:
+ if (is_34020)
+ {
+ sprintf (buffer, "RMO ");
+ print_src_des_reg();
+ }
+ else
+ bad = 1;
+ break;
+
+ case 0x7e00:
+ if (is_34020)
+ {
+ sprintf (buffer, "SWAPF *");
+ print_src_des_reg();
+ strcat(buffer, ",0");
+ }
+ else
+ bad = 1;
+ break;
+
+
+ case 0x8000:
+ case 0x8200:
+ sprintf (buffer, "MOVE ");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+
+ case 0x8400:
+ case 0x8600:
+ sprintf (buffer, "MOVE *");
+ print_src_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+
+ case 0x8800:
+ case 0x8a00:
+ sprintf (buffer, "MOVE *");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+
+ case 0x8c00:
+ sprintf (buffer, "MOVB ");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ break;
+
+
+ case 0x8e00:
+ sprintf (buffer, "MOVB *");
+ print_src_des_reg();
+ break;
+
+
+ case 0x9000:
+ case 0x9200:
+ sprintf (buffer, "MOVE ");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ strcat(buffer, "+,");
+ print_field();
+ break;
+
+
+ case 0x9400:
+ case 0x9600:
+ sprintf (buffer, "MOVE *");
+ print_src_reg();
+ strcat(buffer, "+,");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+
+ case 0x9800:
+ case 0x9a00:
+ sprintf (buffer, "MOVE *");
+ print_src_reg();
+ strcat(buffer, "+,*");
+ print_des_reg();
+ strcat(buffer, "+,");
+ print_field();
+ break;
+
+
+ case 0x9c00:
+ sprintf (buffer, "MOVB *");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ break;
+
+
+ case 0xa000:
+ case 0xa200:
+ sprintf (buffer, "MOVE ");
+ print_src_reg();
+ strcat(buffer, ",-*");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+
+ case 0xa400:
+ case 0xa600:
+ sprintf (buffer, "MOVE -*");
+ print_src_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+
+ case 0xa800:
+ case 0xaa00:
+ sprintf (buffer, "MOVE -*");
+ print_src_reg();
+ strcat(buffer, ",-*");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+
+ case 0xac00:
+ sprintf (buffer, "MOVB ");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ strcat(buffer, "(");
+ print_word_parm();
+ strcat(buffer, ")");
+ break;
+
+
+ case 0xae00:
+ sprintf (buffer, "MOVB *");
+ print_src_reg();
+ strcat(buffer, "(");
+ print_word_parm();
+ strcat(buffer, "),");
+ print_des_reg();
+ break;
+
+
+ case 0xb000:
+ case 0xb200:
+ sprintf (buffer, "MOVE ");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ strcat(buffer, "(");
+ print_word_parm();
+ strcat(buffer, "),");
+ print_field();
+ break;
+
+
+ case 0xb400:
+ case 0xb600:
+ sprintf (buffer, "MOVE *");
+ print_src_reg();
+ strcat(buffer, "(");
+ print_word_parm();
+ strcat(buffer, "),");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+
+ case 0xb800:
+ case 0xba00:
+ sprintf (buffer, "MOVE *");
+ print_src_reg();
+ strcat(buffer, "(");
+ print_word_parm();
+ strcat(buffer, "),*");
+ print_des_reg();
+ strcat(buffer, "(");
+ print_word_parm();
+ strcat(buffer, "),");
+ print_field();
+ break;
+
+
+ case 0xbc00:
+ sprintf (buffer, "MOVB *");
+ print_src_reg();
+ strcat(buffer, "(");
+ print_word_parm();
+ strcat(buffer, "),*");
+ print_des_reg();
+ strcat(buffer, "(");
+ print_word_parm();
+ strcat(buffer, ")");
+ break;
+
+
+ case 0xc000:
+ case 0xc200:
+ case 0xc400:
+ case 0xc600:
+ case 0xc800:
+ case 0xca00:
+ case 0xcc00:
+ case 0xce00:
+ if ((op & 0x00ff) == 0x80)
+ {
+ sprintf (buffer, "JA");
+ }
+ else
+ {
+ sprintf (buffer, "JR");
+ }
+
+ print_condition_code();
+ strcat (buffer, " ");
+
+ switch (op & 0x00ff)
+ {
+ case 0x00:
+ print_relative();
+ break;
+
+ case 0x80:
+ print_long_parm();
+ break;
+
+ default:
+ print_relative_8bit();
+ }
+ break;
+
+
+ case 0xd000:
+ case 0xd200:
+ sprintf (buffer, "MOVE *");
+ print_src_reg();
+ strcat(buffer, "(");
+ print_word_parm();
+ strcat(buffer, "),*");
+ print_des_reg();
+ strcat(buffer, "+,");
+ print_field();
+ break;
+
+
+ case 0xd400:
+ case 0xd600:
+ switch (subop)
+ {
+ case 0x0000:
+ sprintf (buffer, "MOVE @");
+ print_long_parm();
+ strcat(buffer, ",*");
+ print_des_reg();
+ strcat(buffer, "+,");
+ print_field();
+ break;
+
+ case 0x0100:
+ sprintf (buffer, "EXGF ");
+ print_des_reg();
+ strcat(buffer, ",");
+ print_field();
+ break;
+
+ default:
+ bad = 1;
+ }
+ break;
+
+ case 0xd800:
+ if (is_34020)
+ {
+ UINT32 x;
+ PARAM_WORD(x);
+ sprintf(buffer, "CEXEC %d,%06X,%d", op & 1, ((x << 5) & 0x1fffe0) | ((op >> 1) & 0x1f), (x >> 13) & 7);
+ }
+ else
+ bad = 1;
+ break;
+
+
+ case 0xde00:
+ switch (subop)
+ {
+ case 0x0000:
+ if (is_34020)
+ sprintf (buffer, "FLINE 0");
+ else
+ bad = 1;
+ break;
+
+ case 0x0080:
+ if (is_34020)
+ sprintf (buffer, "FLINE 1");
+ else
+ bad = 1;
+ break;
+
+ case 0x0100:
+ sprintf (buffer, "LINE 0");
+ break;
+
+ case 0x0180:
+ sprintf (buffer, "LINE 1");
+ break;
+
+ default:
+ bad = 1;
+ }
+ break;
+
+ case 0xe000:
+ sprintf (buffer, "ADDXY ");
+ print_src_des_reg();
+ break;
+
+
+ case 0xe200:
+ sprintf (buffer, "SUBXY ");
+ print_src_des_reg();
+ break;
+
+
+ case 0xe400:
+ sprintf (buffer, "CMPXY ");
+ print_src_des_reg();
+ break;
+
+
+ case 0xe600:
+ sprintf (buffer, "CPW ");
+ print_src_des_reg();
+ break;
+
+
+ case 0xe800:
+ sprintf (buffer, "CVXYL ");
+ print_src_des_reg();
+ break;
+
+
+ case 0xea00:
+ if (is_34020)
+ {
+ sprintf (buffer, "CVSXYL ");
+ print_src_des_reg();
+ }
+ else
+ bad = 1;
+ break;
+
+
+ case 0xec00:
+ sprintf (buffer, "MOVX ");
+ print_src_des_reg();
+ break;
+
+
+ case 0xee00:
+ sprintf (buffer, "MOVY ");
+ print_src_des_reg();
+ break;
+
+
+ case 0xf000:
+ sprintf (buffer, "PIXT ");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ strcat(buffer, ",XY");
+ break;
+
+
+ case 0xf200:
+ sprintf (buffer, "PIXT *");
+ print_src_reg();
+ strcat(buffer, ",XY,");
+ print_des_reg();
+ break;
+
+
+ case 0xf400:
+ sprintf (buffer, "PIXT *");
+ print_src_reg();
+ strcat(buffer, ",XY,*");
+ print_des_reg();
+ strcat(buffer, ",XY");
+ break;
+
+
+ case 0xf600:
+ sprintf (buffer, "DRAV ");
+ print_src_des_reg();
+ break;
+
+
+ case 0xf800:
+ sprintf (buffer, "PIXT ");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ break;
+
+
+ case 0xfa00:
+ sprintf (buffer, "PIXT *");
+ print_src_des_reg();
+ break;
+
+
+ case 0xfc00:
+ sprintf (buffer, "PIXT *");
+ print_src_reg();
+ strcat(buffer, ",*");
+ print_des_reg();
+ break;
+
+ default:
+ bad = 1;
+ }
+
+ if (bad)
+ {
+ sprintf (buffer, "DW %04Xh", op & 0xffff);
+ }
+
+ return (_pc - __pc) | flags | DASMFLAG_SUPPORTED;
+}
+
+offs_t tms34010_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ rombase = oprom;
+ rambase = opram;
+ pcbase = pc;
+ return Dasm340x0(buffer, pc, 0);
+}
+
+offs_t tms34020_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ rombase = oprom;
+ rambase = opram;
+ pcbase = pc;
+ return Dasm340x0(buffer, pc, 1);
+}
+
diff --git a/src/emu/cpu/tms34010/34010fld.c b/src/emu/cpu/tms34010/34010fld.c
new file mode 100644
index 00000000000..dc3e4896da9
--- /dev/null
+++ b/src/emu/cpu/tms34010/34010fld.c
@@ -0,0 +1,683 @@
+/***************************************************************************
+
+ TMS34010: Portable Texas Instruments TMS34010 emulator
+
+ Copyright (C) Alex Pasadyn/Zsolt Vasvari 1998
+ Parts based on code by Aaron Giles
+
+***************************************************************************/
+
+#include "debugger.h"
+#include "tms34010.h"
+#include "34010ops.h"
+
+
+/***************************************************************************
+ FIELD WRITE FUNCTIONS
+***************************************************************************/
+
+static void wfield_01(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x01,16);
+}
+
+static void wfield_02(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x03,15);
+}
+
+static void wfield_03(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x07,14);
+}
+
+static void wfield_04(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x0f,13);
+}
+
+static void wfield_05(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x1f,12);
+}
+
+static void wfield_06(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x3f,11);
+}
+
+static void wfield_07(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x7f,10);
+}
+
+static void wfield_08(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_8;
+}
+
+static void wfield_09(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x1ff,8);
+}
+
+static void wfield_10(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x3ff,7);
+}
+
+static void wfield_11(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x7ff,6);
+}
+
+static void wfield_12(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0xfff,5);
+}
+
+static void wfield_13(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x1fff,4);
+}
+
+static void wfield_14(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x3fff,3);
+}
+
+static void wfield_15(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x7fff,2);
+}
+
+static void wfield_16(offs_t offset,UINT32 data)
+{
+ if (offset & 0x0f)
+ {
+ WFIELDMAC(0xffff,1);
+ }
+ else
+ {
+ TMS34010_WRMEM_WORD(TOBYTE(offset),data);
+ }
+}
+
+static void wfield_17(offs_t offset,UINT32 data)
+{
+ WFIELDMAC(0x1ffff,0);
+}
+
+static void wfield_18(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x3ffff,15);
+}
+
+static void wfield_19(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x7ffff,14);
+}
+
+static void wfield_20(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0xfffff,13);
+}
+
+static void wfield_21(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x1fffff,12);
+}
+
+static void wfield_22(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x3fffff,11);
+}
+
+static void wfield_23(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x7fffff,10);
+}
+
+static void wfield_24(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0xffffff,9);
+}
+
+static void wfield_25(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x1ffffff,8);
+}
+
+static void wfield_26(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x3ffffff,7);
+}
+
+static void wfield_27(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x7ffffff,6);
+}
+
+static void wfield_28(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0xfffffff,5);
+}
+
+static void wfield_29(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x1fffffff,4);
+}
+
+static void wfield_30(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x3fffffff,3);
+}
+
+static void wfield_31(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_BIG(0x7fffffff,2);
+}
+
+static void wfield_32(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_32;
+}
+
+
+void (*tms34010_wfield_functions[32])(offs_t offset,UINT32 data) =
+{
+ wfield_32, wfield_01, wfield_02, wfield_03, wfield_04, wfield_05,
+ wfield_06, wfield_07, wfield_08, wfield_09, wfield_10, wfield_11,
+ wfield_12, wfield_13, wfield_14, wfield_15, wfield_16, wfield_17,
+ wfield_18, wfield_19, wfield_20, wfield_21, wfield_22, wfield_23,
+ wfield_24, wfield_25, wfield_26, wfield_27, wfield_28, wfield_29,
+ wfield_30, wfield_31
+};
+
+
+
+/***************************************************************************
+ FIELD READ FUNCTIONS (ZERO-EXTEND)
+***************************************************************************/
+
+static UINT32 rfield_z_01(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x01,16);
+ return ret;
+}
+
+static UINT32 rfield_z_02(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x03,15);
+ return ret;
+}
+
+static UINT32 rfield_z_03(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x07,14);
+ return ret;
+}
+
+static UINT32 rfield_z_04(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x0f,13);
+ return ret;
+}
+
+static UINT32 rfield_z_05(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x1f,12);
+ return ret;
+}
+
+static UINT32 rfield_z_06(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x3f,11);
+ return ret;
+}
+
+static UINT32 rfield_z_07(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x7f,10);
+ return ret;
+}
+
+static UINT32 rfield_z_08(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_8;
+ return ret;
+}
+
+static UINT32 rfield_z_09(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x1ff,8);
+ return ret;
+}
+
+static UINT32 rfield_z_10(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x3ff,7);
+ return ret;
+}
+
+static UINT32 rfield_z_11(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x7ff,6);
+ return ret;
+}
+
+static UINT32 rfield_z_12(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0xfff,5);
+ return ret;
+}
+
+static UINT32 rfield_z_13(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x1fff,4);
+ return ret;
+}
+
+static UINT32 rfield_z_14(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x3fff,3);
+ return ret;
+}
+
+static UINT32 rfield_z_15(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x7fff,2);
+ return ret;
+}
+
+static UINT32 rfield_z_16(offs_t offset)
+{
+ UINT32 ret;
+ if (offset & 0x0f)
+ {
+ RFIELDMAC(0xffff,1);
+ }
+
+ else
+ ret = TMS34010_RDMEM_WORD(TOBYTE(offset));
+ return ret;
+}
+
+static UINT32 rfield_z_17(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x1ffff,0);
+ return ret;
+}
+
+static UINT32 rfield_z_18(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x3ffff,15);
+ return ret;
+}
+
+static UINT32 rfield_z_19(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x7ffff,14);
+ return ret;
+}
+
+static UINT32 rfield_z_20(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0xfffff,13);
+ return ret;
+}
+
+static UINT32 rfield_z_21(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x1fffff,12);
+ return ret;
+}
+
+static UINT32 rfield_z_22(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x3fffff,11);
+ return ret;
+}
+
+static UINT32 rfield_z_23(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x7fffff,10);
+ return ret;
+}
+
+static UINT32 rfield_z_24(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0xffffff,9);
+ return ret;
+}
+
+static UINT32 rfield_z_25(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x1ffffff,8);
+ return ret;
+}
+
+static UINT32 rfield_z_26(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x3ffffff,7);
+ return ret;
+}
+
+static UINT32 rfield_z_27(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x7ffffff,6);
+ return ret;
+}
+
+static UINT32 rfield_z_28(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0xfffffff,5);
+ return ret;
+}
+
+static UINT32 rfield_z_29(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x1fffffff,4);
+ return ret;
+}
+
+static UINT32 rfield_z_30(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x3fffffff,3);
+ return ret;
+}
+
+static UINT32 rfield_z_31(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x7fffffff,2);
+ return ret;
+}
+
+static UINT32 rfield_32(offs_t offset)
+{
+ RFIELDMAC_32;
+}
+
+
+/***************************************************************************
+ FIELD READ FUNCTIONS (SIGN-EXTEND)
+***************************************************************************/
+
+static UINT32 rfield_s_01(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x01,16);
+ return ((INT32)(ret << 31)) >> 31;
+}
+
+static UINT32 rfield_s_02(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x03,15);
+ return ((INT32)(ret << 30)) >> 30;
+}
+
+static UINT32 rfield_s_03(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x07,14);
+ return ((INT32)(ret << 29)) >> 29;
+}
+
+static UINT32 rfield_s_04(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x0f,13);
+ return ((INT32)(ret << 28)) >> 28;
+}
+
+static UINT32 rfield_s_05(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x1f,12);
+ return ((INT32)(ret << 27)) >> 27;
+}
+
+static UINT32 rfield_s_06(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x3f,11);
+ return ((INT32)(ret << 26)) >> 26;
+}
+
+static UINT32 rfield_s_07(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x7f,10);
+ return ((INT32)(ret << 25)) >> 25;
+}
+
+static UINT32 rfield_s_08(offs_t offset)
+{
+ UINT32 ret;
+ if (offset & 0x07)
+ {
+ RFIELDMAC(0xff,9);
+ }
+
+ else
+ ret = TMS34010_RDMEM(TOBYTE(offset));
+ return (INT32)(INT8)ret;
+}
+
+static UINT32 rfield_s_09(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x1ff,8);
+ return ((INT32)(ret << 23)) >> 23;
+}
+
+static UINT32 rfield_s_10(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x3ff,7);
+ return ((INT32)(ret << 22)) >> 22;
+}
+
+static UINT32 rfield_s_11(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x7ff,6);
+ return ((INT32)(ret << 21)) >> 21;
+}
+
+static UINT32 rfield_s_12(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0xfff,5);
+ return ((INT32)(ret << 20)) >> 20;
+}
+
+static UINT32 rfield_s_13(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x1fff,4);
+ return ((INT32)(ret << 19)) >> 19;
+}
+
+static UINT32 rfield_s_14(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x3fff,3);
+ return ((INT32)(ret << 18)) >> 18;
+}
+
+static UINT32 rfield_s_15(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x7fff,2);
+ return ((INT32)(ret << 17)) >> 17;
+}
+
+static UINT32 rfield_s_16(offs_t offset)
+{
+ UINT32 ret;
+ if (offset & 0x0f)
+ {
+ RFIELDMAC(0xffff,1);
+ }
+
+ else
+ {
+ ret = TMS34010_RDMEM_WORD(TOBYTE(offset));
+ }
+
+ return (INT32)(INT16)ret;
+}
+
+static UINT32 rfield_s_17(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC(0x1ffff,0);
+ return ((INT32)(ret << 15)) >> 15;
+}
+
+static UINT32 rfield_s_18(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x3ffff,15);
+ return ((INT32)(ret << 14)) >> 14;
+}
+
+static UINT32 rfield_s_19(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x7ffff,14);
+ return ((INT32)(ret << 13)) >> 13;
+}
+
+static UINT32 rfield_s_20(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0xfffff,13);
+ return ((INT32)(ret << 12)) >> 12;
+}
+
+static UINT32 rfield_s_21(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x1fffff,12);
+ return ((INT32)(ret << 11)) >> 11;
+}
+
+static UINT32 rfield_s_22(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x3fffff,11);
+ return ((INT32)(ret << 10)) >> 10;
+}
+
+static UINT32 rfield_s_23(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x7fffff,10);
+ return ((INT32)(ret << 9)) >> 9;
+}
+
+static UINT32 rfield_s_24(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0xffffff,9);
+ return ((INT32)(ret << 8)) >> 8;
+}
+
+static UINT32 rfield_s_25(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x1ffffff,8);
+ return ((INT32)(ret << 7)) >> 7;
+}
+
+static UINT32 rfield_s_26(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x3ffffff,7);
+ return ((INT32)(ret << 6)) >> 6;
+}
+
+static UINT32 rfield_s_27(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x7ffffff,6);
+ return ((INT32)(ret << 5)) >> 5;
+}
+
+static UINT32 rfield_s_28(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0xfffffff,5);
+ return ((INT32)(ret << 4)) >> 4;
+}
+
+static UINT32 rfield_s_29(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x1fffffff,4);
+ return ((INT32)(ret << 3)) >> 3;
+}
+
+static UINT32 rfield_s_30(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x3fffffff,3);
+ return ((INT32)(ret << 2)) >> 2;
+}
+
+static UINT32 rfield_s_31(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_BIG(0x7fffffff,2);
+ return ((INT32)(ret << 1)) >> 1;
+}
+
+UINT32 (*tms34010_rfield_functions[64])(offs_t offset) =
+{
+ rfield_32 , rfield_z_01, rfield_z_02, rfield_z_03, rfield_z_04, rfield_z_05,
+ rfield_z_06, rfield_z_07, rfield_z_08, rfield_z_09, rfield_z_10, rfield_z_11,
+ rfield_z_12, rfield_z_13, rfield_z_14, rfield_z_15, rfield_z_16, rfield_z_17,
+ rfield_z_18, rfield_z_19, rfield_z_20, rfield_z_21, rfield_z_22, rfield_z_23,
+ rfield_z_24, rfield_z_25, rfield_z_26, rfield_z_27, rfield_z_28, rfield_z_29,
+ rfield_z_30, rfield_z_31,
+ rfield_32 , rfield_s_01, rfield_s_02, rfield_s_03, rfield_s_04, rfield_s_05,
+ rfield_s_06, rfield_s_07, rfield_s_08, rfield_s_09, rfield_s_10, rfield_s_11,
+ rfield_s_12, rfield_s_13, rfield_s_14, rfield_s_15, rfield_s_16, rfield_s_17,
+ rfield_s_18, rfield_s_19, rfield_s_20, rfield_s_21, rfield_s_22, rfield_s_23,
+ rfield_s_24, rfield_s_25, rfield_s_26, rfield_s_27, rfield_s_28, rfield_s_29,
+ rfield_s_30, rfield_s_31
+};
+
diff --git a/src/emu/cpu/tms34010/34010gfx.c b/src/emu/cpu/tms34010/34010gfx.c
new file mode 100644
index 00000000000..f0f2cdd3ecb
--- /dev/null
+++ b/src/emu/cpu/tms34010/34010gfx.c
@@ -0,0 +1,2032 @@
+/***************************************************************************
+
+ TMS34010: Portable Texas Instruments TMS34010 emulator
+
+ Copyright (C) Alex Pasadyn/Zsolt Vasvari 1998
+ Parts based on code by Aaron Giles
+
+***************************************************************************/
+
+#ifndef RECURSIVE_INCLUDE
+
+#if LOG_GRAPHICS_OPS
+#define LOGGFX(x) do { if (input_code_pressed(KEYCODE_L)) logerror x ; } while (0)
+#else
+#define LOGGFX(x)
+#endif
+
+
+/* Graphics Instructions */
+
+static void line(void)
+{
+ if (!P_FLAG)
+ {
+ if (WINDOW_CHECKING != 0 && WINDOW_CHECKING != 3)
+ logerror("LINE XY %08X - Window Checking Mode %d not supported\n", PC, WINDOW_CHECKING);
+
+ state.st |= STBIT_P;
+ TEMP = (state.op & 0x80) ? 1 : 0; /* boundary value depends on the algorithm */
+ LOGGFX(("%08X(%3d):LINE (%d,%d)-(%d,%d)\n", PC, video_screen_get_vpos(state.config->scrnum), DADDR_X, DADDR_Y, DADDR_X + DYDX_X, DADDR_Y + DYDX_Y));
+ }
+
+ if (COUNT > 0)
+ {
+ INT16 x1,y1;
+
+ COUNT--;
+ if (WINDOW_CHECKING != 3 ||
+ (DADDR_X >= WSTART_X && DADDR_X <= WEND_X &&
+ DADDR_Y >= WSTART_Y && DADDR_Y <= WEND_Y))
+ WPIXEL(DXYTOL(DADDR_XY),COLOR1);
+
+ if (SADDR >= TEMP)
+ {
+ SADDR += DYDX_Y*2 - DYDX_X*2;
+ x1 = INC1_X;
+ y1 = INC1_Y;
+ }
+ else
+ {
+ SADDR += DYDX_Y*2;
+ x1 = INC2_X;
+ y1 = INC2_Y;
+ }
+ DADDR_X += x1;
+ DADDR_Y += y1;
+
+ COUNT_UNKNOWN_CYCLES(2);
+ PC -= 0x10; /* not done yet, check for interrupts and restart instruction */
+ return;
+ }
+ state.st &= ~STBIT_P;
+}
+
+
+/*
+cases:
+* window modes (0,1,2,3)
+* boolean/arithmetic ops (16+6)
+* transparency (on/off)
+* plane masking
+* directions (left->right/right->left, top->bottom/bottom->top)
+*/
+
+static int apply_window(const char *inst_name,int srcbpp, UINT32 *srcaddr, XY *dst, int *dx, int *dy)
+{
+ /* apply the window */
+ if (WINDOW_CHECKING == 0)
+ return 0;
+ else
+ {
+ int sx = dst->x;
+ int sy = dst->y;
+ int ex = sx + *dx - 1;
+ int ey = sy + *dy - 1;
+ int diff, cycles = 3;
+
+ if (WINDOW_CHECKING == 2)
+ logerror("%08x: %s apply_window window mode %d not supported!\n", activecpu_get_pc(), inst_name, WINDOW_CHECKING);
+
+ CLR_V;
+ if (WINDOW_CHECKING == 1)
+ SET_V_LOG(1);
+
+ /* clip X */
+ diff = WSTART_X - sx;
+ if (diff > 0)
+ {
+ if (srcaddr)
+ *srcaddr += diff * srcbpp;
+ sx += diff;
+ SET_V_LOG(1);
+ }
+ diff = ex - WEND_X;
+ if (diff > 0)
+ {
+ ex -= diff;
+ SET_V_LOG(1);
+ }
+
+ /* clip Y */
+ diff = WSTART_Y - sy;
+ if (diff > 0)
+ {
+ if (srcaddr)
+ *srcaddr += diff * SPTCH;
+ sy += diff;
+ SET_V_LOG(1);
+ }
+ diff = ey - WEND_Y;
+ if (diff > 0)
+ {
+ ey -= diff;
+ SET_V_LOG(1);
+ }
+
+ /* compute cycles */
+ if (*dx != ex - sx + 1 || *dy != ey - sy + 1)
+ {
+ if (dst->x != sx || dst->y != sy)
+ cycles += 11;
+ else
+ cycles += 3;
+ }
+ else if (dst->x != sx || dst->y != sy)
+ cycles += 7;
+
+ /* update the values */
+ dst->x = sx;
+ dst->y = sy;
+ *dx = ex - sx + 1;
+ *dy = ey - sy + 1;
+ return cycles;
+ }
+}
+
+
+/*******************************************************************
+
+ About the timing of gfx operations:
+
+ The 34010 manual lists a fairly intricate and accurate way of
+ computing cycle timings for graphics ops. However, there are
+ enough typos and misleading statements to make the reliability
+ of the timing info questionable.
+
+ So, to address this, here is a simplified approximate version
+ of the timing.
+
+ timing = setup + (srcwords * 2 + dstwords * gfxop) * rows
+
+ Each read access takes 2 cycles. Each gfx operation has
+ its own timing as specified in the 34010 manual. So, it's 2
+ cycles per read plus gfxop cycles per operation. Pretty
+ simple, no?
+
+*******************************************************************/
+
+static int compute_fill_cycles(int left_partials, int right_partials, int full_words, int op_timing)
+{
+ int dstwords;
+
+ if (left_partials) full_words += 1;
+ if (right_partials) full_words += 1;
+ dstwords = full_words;
+
+ return (dstwords * op_timing);
+}
+
+static int compute_pixblt_cycles(int left_partials, int right_partials, int full_words, int op_timing)
+{
+ int srcwords, dstwords;
+
+ if (left_partials) full_words += 1;
+ if (right_partials) full_words += 1;
+ srcwords = full_words;
+ dstwords = full_words;
+
+ return (dstwords * op_timing + srcwords * 2) + 2;
+}
+
+static int compute_pixblt_b_cycles(int left_partials, int right_partials, int full_words, int rows, int op_timing, int bpp)
+{
+ int srcwords, dstwords;
+
+ if (left_partials) full_words += 1;
+ if (right_partials) full_words += 1;
+ srcwords = full_words * bpp / 16;
+ dstwords = full_words;
+
+ return (dstwords * op_timing + srcwords * 2) * rows + 2;
+}
+
+
+/* Shift register handling */
+static void shiftreg_w(offs_t offset,UINT16 data)
+{
+ if (state.config->from_shiftreg)
+ (*state.config->from_shiftreg)((UINT32)(offset << 3) & ~15, &state.shiftreg[0]);
+ else
+ logerror("From ShiftReg function not set. PC = %08X\n", PC);
+}
+
+static UINT16 shiftreg_r(offs_t offset)
+{
+ if (state.config->to_shiftreg)
+ (*state.config->to_shiftreg)((UINT32)(offset << 3) & ~15, &state.shiftreg[0]);
+ else
+ logerror("To ShiftReg function not set. PC = %08X\n", PC);
+ return state.shiftreg[0];
+}
+
+static UINT16 dummy_shiftreg_r(offs_t offset)
+{
+ return state.shiftreg[0];
+}
+
+
+
+/* Pixel operations */
+static UINT32 pixel_op00(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return srcpix; }
+static UINT32 pixel_op01(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return srcpix & dstpix; }
+static UINT32 pixel_op02(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return srcpix & ~dstpix; }
+static UINT32 pixel_op03(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return 0; }
+static UINT32 pixel_op04(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (srcpix | ~dstpix) & mask; }
+static UINT32 pixel_op05(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return ~(srcpix ^ dstpix) & mask; }
+static UINT32 pixel_op06(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return ~dstpix & mask; }
+static UINT32 pixel_op07(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return ~(srcpix | dstpix) & mask; }
+static UINT32 pixel_op08(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (srcpix | dstpix) & mask; }
+static UINT32 pixel_op09(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return dstpix & mask; }
+static UINT32 pixel_op10(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (srcpix ^ dstpix) & mask; }
+static UINT32 pixel_op11(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (~srcpix & dstpix) & mask; }
+static UINT32 pixel_op12(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return mask; }
+static UINT32 pixel_op13(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (~srcpix & dstpix) & mask; }
+static UINT32 pixel_op14(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return ~(srcpix & dstpix) & mask; }
+static UINT32 pixel_op15(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return srcpix ^ mask; }
+static UINT32 pixel_op16(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (srcpix + dstpix) & mask; }
+static UINT32 pixel_op17(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { INT32 tmp = srcpix + (dstpix & mask); return (tmp > mask) ? mask : tmp; }
+static UINT32 pixel_op18(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (dstpix - srcpix) & mask; }
+static UINT32 pixel_op19(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { INT32 tmp = srcpix - (dstpix & mask); return (tmp < 0) ? 0 : tmp; }
+static UINT32 pixel_op20(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { dstpix &= mask; return (srcpix > dstpix) ? srcpix : dstpix; }
+static UINT32 pixel_op21(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { dstpix &= mask; return (srcpix < dstpix) ? srcpix : dstpix; }
+
+static UINT32 (*pixel_op_table[])(UINT32, UINT32, UINT32) =
+{
+ pixel_op00, pixel_op01, pixel_op02, pixel_op03, pixel_op04, pixel_op05, pixel_op06, pixel_op07,
+ pixel_op08, pixel_op09, pixel_op10, pixel_op11, pixel_op12, pixel_op13, pixel_op14, pixel_op15,
+ pixel_op16, pixel_op17, pixel_op18, pixel_op19, pixel_op20, pixel_op21, pixel_op00, pixel_op00,
+ pixel_op00, pixel_op00, pixel_op00, pixel_op00, pixel_op00, pixel_op00, pixel_op00, pixel_op00
+};
+static UINT8 pixel_op_timing_table[] =
+{
+ 2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,6,5,5,2,2,2,2,2,2,2,2,2,2,2
+};
+static UINT32 (*pixel_op)(UINT32, UINT32, UINT32);
+static UINT32 pixel_op_timing;
+
+
+/* Blitters/fillers */
+static void pixblt_1_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_2_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_4_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_8_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_16_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_r_1_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_r_2_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_r_4_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_r_8_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_r_16_op0(int src_is_linear, int dst_is_linear);
+static void pixblt_b_1_op0(int dst_is_linear);
+static void pixblt_b_2_op0(int dst_is_linear);
+static void pixblt_b_4_op0(int dst_is_linear);
+static void pixblt_b_8_op0(int dst_is_linear);
+static void pixblt_b_16_op0(int dst_is_linear);
+static void fill_1_op0(int dst_is_linear);
+static void fill_2_op0(int dst_is_linear);
+static void fill_4_op0(int dst_is_linear);
+static void fill_8_op0(int dst_is_linear);
+static void fill_16_op0(int dst_is_linear);
+
+static void pixblt_1_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_2_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_4_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_8_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_16_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_1_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_2_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_4_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_8_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_16_op0_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_b_1_op0_trans(int dst_is_linear);
+static void pixblt_b_2_op0_trans(int dst_is_linear);
+static void pixblt_b_4_op0_trans(int dst_is_linear);
+static void pixblt_b_8_op0_trans(int dst_is_linear);
+static void pixblt_b_16_op0_trans(int dst_is_linear);
+static void fill_1_op0_trans(int dst_is_linear);
+static void fill_2_op0_trans(int dst_is_linear);
+static void fill_4_op0_trans(int dst_is_linear);
+static void fill_8_op0_trans(int dst_is_linear);
+static void fill_16_op0_trans(int dst_is_linear);
+
+static void pixblt_1_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_2_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_4_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_8_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_16_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_r_1_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_r_2_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_r_4_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_r_8_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_r_16_opx(int src_is_linear, int dst_is_linear);
+static void pixblt_b_1_opx(int dst_is_linear);
+static void pixblt_b_2_opx(int dst_is_linear);
+static void pixblt_b_4_opx(int dst_is_linear);
+static void pixblt_b_8_opx(int dst_is_linear);
+static void pixblt_b_16_opx(int dst_is_linear);
+static void fill_1_opx(int dst_is_linear);
+static void fill_2_opx(int dst_is_linear);
+static void fill_4_opx(int dst_is_linear);
+static void fill_8_opx(int dst_is_linear);
+static void fill_16_opx(int dst_is_linear);
+
+static void pixblt_1_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_2_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_4_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_8_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_16_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_1_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_2_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_4_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_8_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_r_16_opx_trans(int src_is_linear, int dst_is_linear);
+static void pixblt_b_1_opx_trans(int dst_is_linear);
+static void pixblt_b_2_opx_trans(int dst_is_linear);
+static void pixblt_b_4_opx_trans(int dst_is_linear);
+static void pixblt_b_8_opx_trans(int dst_is_linear);
+static void pixblt_b_16_opx_trans(int dst_is_linear);
+static void fill_1_opx_trans(int dst_is_linear);
+static void fill_2_opx_trans(int dst_is_linear);
+static void fill_4_opx_trans(int dst_is_linear);
+static void fill_8_opx_trans(int dst_is_linear);
+static void fill_16_opx_trans(int dst_is_linear);
+
+
+/* tables */
+static void (*pixblt_op_table[])(int, int) =
+{
+ pixblt_1_op0, pixblt_1_op0_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+ pixblt_1_opx, pixblt_1_opx_trans, pixblt_1_opx, pixblt_1_opx_trans,
+
+ pixblt_2_op0, pixblt_2_op0_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+ pixblt_2_opx, pixblt_2_opx_trans, pixblt_2_opx, pixblt_2_opx_trans,
+
+ pixblt_4_op0, pixblt_4_op0_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+ pixblt_4_opx, pixblt_4_opx_trans, pixblt_4_opx, pixblt_4_opx_trans,
+
+ pixblt_8_op0, pixblt_8_op0_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+ pixblt_8_opx, pixblt_8_opx_trans, pixblt_8_opx, pixblt_8_opx_trans,
+
+ pixblt_16_op0, pixblt_16_op0_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans,
+ pixblt_16_opx, pixblt_16_opx_trans, pixblt_16_opx, pixblt_16_opx_trans
+};
+
+static void (*pixblt_r_op_table[])(int, int) =
+{
+ pixblt_r_1_op0, pixblt_r_1_op0_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+ pixblt_r_1_opx, pixblt_r_1_opx_trans, pixblt_r_1_opx, pixblt_r_1_opx_trans,
+
+ pixblt_r_2_op0, pixblt_r_2_op0_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+ pixblt_r_2_opx, pixblt_r_2_opx_trans, pixblt_r_2_opx, pixblt_r_2_opx_trans,
+
+ pixblt_r_4_op0, pixblt_r_4_op0_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+ pixblt_r_4_opx, pixblt_r_4_opx_trans, pixblt_r_4_opx, pixblt_r_4_opx_trans,
+
+ pixblt_r_8_op0, pixblt_r_8_op0_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+ pixblt_r_8_opx, pixblt_r_8_opx_trans, pixblt_r_8_opx, pixblt_r_8_opx_trans,
+
+ pixblt_r_16_op0,pixblt_r_16_op0_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans,
+ pixblt_r_16_opx,pixblt_r_16_opx_trans, pixblt_r_16_opx,pixblt_r_16_opx_trans
+};
+
+static void (*pixblt_b_op_table[])(int) =
+{
+ pixblt_b_1_op0, pixblt_b_1_op0_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+ pixblt_b_1_opx, pixblt_b_1_opx_trans, pixblt_b_1_opx, pixblt_b_1_opx_trans,
+
+ pixblt_b_2_op0, pixblt_b_2_op0_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+ pixblt_b_2_opx, pixblt_b_2_opx_trans, pixblt_b_2_opx, pixblt_b_2_opx_trans,
+
+ pixblt_b_4_op0, pixblt_b_4_op0_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+ pixblt_b_4_opx, pixblt_b_4_opx_trans, pixblt_b_4_opx, pixblt_b_4_opx_trans,
+
+ pixblt_b_8_op0, pixblt_b_8_op0_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+ pixblt_b_8_opx, pixblt_b_8_opx_trans, pixblt_b_8_opx, pixblt_b_8_opx_trans,
+
+ pixblt_b_16_op0,pixblt_b_16_op0_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans,
+ pixblt_b_16_opx,pixblt_b_16_opx_trans, pixblt_b_16_opx,pixblt_b_16_opx_trans
+};
+
+static void (*fill_op_table[])(int) =
+{
+ fill_1_op0, fill_1_op0_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+ fill_1_opx, fill_1_opx_trans, fill_1_opx, fill_1_opx_trans,
+
+ fill_2_op0, fill_2_op0_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+ fill_2_opx, fill_2_opx_trans, fill_2_opx, fill_2_opx_trans,
+
+ fill_4_op0, fill_4_op0_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+ fill_4_opx, fill_4_opx_trans, fill_4_opx, fill_4_opx_trans,
+
+ fill_8_op0, fill_8_op0_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+ fill_8_opx, fill_8_opx_trans, fill_8_opx, fill_8_opx_trans,
+
+ fill_16_op0, fill_16_op0_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans,
+ fill_16_opx, fill_16_opx_trans, fill_16_opx, fill_16_opx_trans
+};
+
+
+#define RECURSIVE_INCLUDE
+
+/* non-transparent replace ops */
+#define PIXEL_OP(src, mask, pixel) pixel = pixel
+#define PIXEL_OP_TIMING 2
+#define PIXEL_OP_REQUIRES_SOURCE 0
+#define TRANSPARENCY 0
+
+ /* 1bpp cases */
+ #define BITS_PER_PIXEL 1
+ #define FUNCTION_NAME(base) base##_1_op0
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 2bpp cases */
+ #define BITS_PER_PIXEL 2
+ #define FUNCTION_NAME(base) base##_2_op0
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 4bpp cases */
+ #define BITS_PER_PIXEL 4
+ #define FUNCTION_NAME(base) base##_4_op0
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 8bpp cases */
+ #define BITS_PER_PIXEL 8
+ #define FUNCTION_NAME(base) base##_8_op0
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 16bpp cases */
+ #define BITS_PER_PIXEL 16
+ #define FUNCTION_NAME(base) base##_16_op0
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+#undef TRANSPARENCY
+#undef PIXEL_OP_REQUIRES_SOURCE
+#undef PIXEL_OP_TIMING
+#undef PIXEL_OP
+
+
+#define PIXEL_OP(src, mask, pixel) pixel = (*pixel_op)(src, mask, pixel)
+#define PIXEL_OP_TIMING pixel_op_timing
+#define PIXEL_OP_REQUIRES_SOURCE 1
+#define TRANSPARENCY 0
+
+ /* 1bpp cases */
+ #define BITS_PER_PIXEL 1
+ #define FUNCTION_NAME(base) base##_1_opx
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 2bpp cases */
+ #define BITS_PER_PIXEL 2
+ #define FUNCTION_NAME(base) base##_2_opx
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 4bpp cases */
+ #define BITS_PER_PIXEL 4
+ #define FUNCTION_NAME(base) base##_4_opx
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 8bpp cases */
+ #define BITS_PER_PIXEL 8
+ #define FUNCTION_NAME(base) base##_8_opx
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 16bpp cases */
+ #define BITS_PER_PIXEL 16
+ #define FUNCTION_NAME(base) base##_16_opx
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+#undef TRANSPARENCY
+#undef PIXEL_OP_REQUIRES_SOURCE
+#undef PIXEL_OP_TIMING
+#undef PIXEL_OP
+
+
+/* transparent replace ops */
+#define PIXEL_OP(src, mask, pixel) pixel = pixel
+#define PIXEL_OP_REQUIRES_SOURCE 0
+#define PIXEL_OP_TIMING 4
+#define TRANSPARENCY 1
+
+ /* 1bpp cases */
+ #define BITS_PER_PIXEL 1
+ #define FUNCTION_NAME(base) base##_1_op0_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 2bpp cases */
+ #define BITS_PER_PIXEL 2
+ #define FUNCTION_NAME(base) base##_2_op0_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 4bpp cases */
+ #define BITS_PER_PIXEL 4
+ #define FUNCTION_NAME(base) base##_4_op0_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 8bpp cases */
+ #define BITS_PER_PIXEL 8
+ #define FUNCTION_NAME(base) base##_8_op0_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 16bpp cases */
+ #define BITS_PER_PIXEL 16
+ #define FUNCTION_NAME(base) base##_16_op0_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+#undef TRANSPARENCY
+#undef PIXEL_OP_REQUIRES_SOURCE
+#undef PIXEL_OP_TIMING
+#undef PIXEL_OP
+
+
+#define PIXEL_OP(src, mask, pixel) pixel = (*pixel_op)(src, mask, pixel)
+#define PIXEL_OP_REQUIRES_SOURCE 1
+#define PIXEL_OP_TIMING (2+pixel_op_timing)
+#define TRANSPARENCY 1
+
+ /* 1bpp cases */
+ #define BITS_PER_PIXEL 1
+ #define FUNCTION_NAME(base) base##_1_opx_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 2bpp cases */
+ #define BITS_PER_PIXEL 2
+ #define FUNCTION_NAME(base) base##_2_opx_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 4bpp cases */
+ #define BITS_PER_PIXEL 4
+ #define FUNCTION_NAME(base) base##_4_opx_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 8bpp cases */
+ #define BITS_PER_PIXEL 8
+ #define FUNCTION_NAME(base) base##_8_opx_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+ /* 16bpp cases */
+ #define BITS_PER_PIXEL 16
+ #define FUNCTION_NAME(base) base##_16_opx_trans
+ #include "34010gfx.c"
+ #undef FUNCTION_NAME
+ #undef BITS_PER_PIXEL
+
+#undef TRANSPARENCY
+#undef PIXEL_OP_REQUIRES_SOURCE
+#undef PIXEL_OP_TIMING
+#undef PIXEL_OP
+
+static UINT8 pixelsize_lookup[32] =
+{
+ 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
+};
+
+
+static void pixblt_b_l(void)
+{
+ int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f];
+ int trans = (IOREG(REG_CONTROL) & 0x20) >> 5;
+ int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f;
+ int ix = trans | (rop << 1) | (psize << 6);
+ if (!P_FLAG) LOGGFX(("%08X(%3d):PIXBLT B,L (%dx%d) depth=%d\n", PC, video_screen_get_vpos(state.config->scrnum), DYDX_X, DYDX_Y, IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32));
+ pixel_op = pixel_op_table[rop];
+ pixel_op_timing = pixel_op_timing_table[rop];
+ (*pixblt_b_op_table[ix])(1);
+}
+
+static void pixblt_b_xy(void)
+{
+ int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f];
+ int trans = (IOREG(REG_CONTROL) & 0x20) >> 5;
+ int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f;
+ int ix = trans | (rop << 1) | (psize << 6);
+ if (!P_FLAG) LOGGFX(("%08X(%3d):PIXBLT B,XY (%d,%d) (%dx%d) depth=%d\n", PC, video_screen_get_vpos(state.config->scrnum), DADDR_X, DADDR_Y, DYDX_X, DYDX_Y, IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32));
+ pixel_op = pixel_op_table[rop];
+ pixel_op_timing = pixel_op_timing_table[rop];
+ (*pixblt_b_op_table[ix])(0);
+}
+
+static void pixblt_l_l(void)
+{
+ int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f];
+ int trans = (IOREG(REG_CONTROL) & 0x20) >> 5;
+ int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f;
+ int pbh = (IOREG(REG_CONTROL) >> 8) & 1;
+ int ix = trans | (rop << 1) | (psize << 6);
+ if (!P_FLAG) LOGGFX(("%08X(%3d):PIXBLT L,L (%dx%d) depth=%d\n", PC, video_screen_get_vpos(state.config->scrnum), DYDX_X, DYDX_Y, IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32));
+ pixel_op = pixel_op_table[rop];
+ pixel_op_timing = pixel_op_timing_table[rop];
+ if (!pbh)
+ (*pixblt_op_table[ix])(1, 1);
+ else
+ (*pixblt_r_op_table[ix])(1, 1);
+}
+
+static void pixblt_l_xy(void)
+{
+ int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f];
+ int trans = (IOREG(REG_CONTROL) & 0x20) >> 5;
+ int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f;
+ int pbh = (IOREG(REG_CONTROL) >> 8) & 1;
+ int ix = trans | (rop << 1) | (psize << 6);
+ if (!P_FLAG) LOGGFX(("%08X(%3d):PIXBLT L,XY (%d,%d) (%dx%d) depth=%d\n", PC, video_screen_get_vpos(state.config->scrnum), DADDR_X, DADDR_Y, DYDX_X, DYDX_Y, IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32));
+ pixel_op = pixel_op_table[rop];
+ pixel_op_timing = pixel_op_timing_table[rop];
+ if (!pbh)
+ (*pixblt_op_table[ix])(1, 0);
+ else
+ (*pixblt_r_op_table[ix])(1, 0);
+}
+
+static void pixblt_xy_l(void)
+{
+ int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f];
+ int trans = (IOREG(REG_CONTROL) & 0x20) >> 5;
+ int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f;
+ int pbh = (IOREG(REG_CONTROL) >> 8) & 1;
+ int ix = trans | (rop << 1) | (psize << 6);
+ if (!P_FLAG) LOGGFX(("%08X(%3d):PIXBLT XY,L (%dx%d) depth=%d\n", PC, video_screen_get_vpos(state.config->scrnum), DYDX_X, DYDX_Y, IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32));
+ pixel_op = pixel_op_table[rop];
+ pixel_op_timing = pixel_op_timing_table[rop];
+ if (!pbh)
+ (*pixblt_op_table[ix])(0, 1);
+ else
+ (*pixblt_r_op_table[ix])(0, 1);
+}
+
+static void pixblt_xy_xy(void)
+{
+ int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f];
+ int trans = (IOREG(REG_CONTROL) & 0x20) >> 5;
+ int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f;
+ int pbh = (IOREG(REG_CONTROL) >> 8) & 1;
+ int ix = trans | (rop << 1) | (psize << 6);
+ if (!P_FLAG) LOGGFX(("%08X(%3d):PIXBLT XY,XY (%dx%d) depth=%d\n", PC, video_screen_get_vpos(state.config->scrnum), DYDX_X, DYDX_Y, IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32));
+ pixel_op = pixel_op_table[rop];
+ pixel_op_timing = pixel_op_timing_table[rop];
+ if (!pbh)
+ (*pixblt_op_table[ix])(0, 0);
+ else
+ (*pixblt_r_op_table[ix])(0, 0);
+}
+
+static void fill_l(void)
+{
+ int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f];
+ int trans = (IOREG(REG_CONTROL) & 0x20) >> 5;
+ int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f;
+ int ix = trans | (rop << 1) | (psize << 6);
+ if (!P_FLAG) LOGGFX(("%08X(%3d):FILL L (%dx%d) depth=%d\n", PC, video_screen_get_vpos(state.config->scrnum), DYDX_X, DYDX_Y, IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32));
+ pixel_op = pixel_op_table[rop];
+ pixel_op_timing = pixel_op_timing_table[rop];
+ (*fill_op_table[ix])(1);
+}
+
+static void fill_xy(void)
+{
+ int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f];
+ int trans = (IOREG(REG_CONTROL) & 0x20) >> 5;
+ int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f;
+ int ix = trans | (rop << 1) | (psize << 6);
+ if (!P_FLAG) LOGGFX(("%08X(%3d):FILL XY (%d,%d) (%dx%d) depth=%d\n", PC, video_screen_get_vpos(state.config->scrnum), DADDR_X, DADDR_Y, DYDX_X, DYDX_Y, IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32));
+ pixel_op = pixel_op_table[rop];
+ pixel_op_timing = pixel_op_timing_table[rop];
+ (*fill_op_table[ix])(0);
+}
+
+
+#else
+
+
+#undef PIXELS_PER_WORD
+#undef PIXEL_MASK
+
+#define PIXELS_PER_WORD (16 / BITS_PER_PIXEL)
+#define PIXEL_MASK ((1 << BITS_PER_PIXEL) - 1)
+
+static void FUNCTION_NAME(pixblt)(int src_is_linear, int dst_is_linear)
+{
+ /* if this is the first time through, perform the operation */
+ if (!P_FLAG)
+ {
+ int dx, dy, x, y, /*words,*/ yreverse;
+ void (*word_write)(offs_t address,UINT16 data);
+ UINT16 (*word_read)(offs_t address);
+ UINT32 readwrites = 0;
+ UINT32 saddr, daddr;
+ XY dstxy = { 0 };
+
+ /* determine read/write functions */
+ if (IOREG(REG_DPYCTL) & 0x0800)
+ {
+ word_write = shiftreg_w;
+ word_read = shiftreg_r;
+ }
+ else
+ {
+ word_write = program_write_word_16le;
+ word_read = program_read_word_16le;
+ }
+
+ /* compute the starting addresses */
+ saddr = src_is_linear ? SADDR : SXYTOL(SADDR_XY);
+
+ /* compute the bounds of the operation */
+ dx = (INT16)DYDX_X;
+ dy = (INT16)DYDX_Y;
+
+ /* apply the window for non-linear destinations */
+ state.gfxcycles = 7 + (src_is_linear ? 0 : 2);
+ if (!dst_is_linear)
+ {
+ dstxy = DADDR_XY;
+ state.gfxcycles += 2 + (!src_is_linear) + apply_window("PIXBLT", BITS_PER_PIXEL, &saddr, &dstxy, &dx, &dy);
+ daddr = DXYTOL(dstxy);
+ }
+ else
+ daddr = DADDR;
+ daddr &= ~(BITS_PER_PIXEL - 1);
+ LOGGFX((" saddr=%08X daddr=%08X sptch=%08X dptch=%08X\n", saddr, daddr, SPTCH, DPTCH));
+
+ /* bail if we're clipped */
+ if (dx <= 0 || dy <= 0)
+ return;
+
+ /* window mode 1: just return and interrupt if we are within the window */
+ if (WINDOW_CHECKING == 1 && !dst_is_linear)
+ {
+ CLR_V;
+ DADDR_XY = dstxy;
+ DYDX_X = dx;
+ DYDX_Y = dy;
+ IOREG(REG_INTPEND) |= TMS34010_WV;
+ check_interrupt();
+ return;
+ }
+
+ /* handle flipping the addresses */
+ yreverse = (IOREG(REG_CONTROL) >> 9) & 1;
+ if (!src_is_linear || !dst_is_linear)
+ if (yreverse)
+ {
+ saddr += (dy - 1) * SPTCH;
+ daddr += (dy - 1) * DPTCH;
+ }
+
+ state.st |= STBIT_P;
+
+ /* loop over rows */
+ for (y = 0; y < dy; y++)
+ {
+ UINT32 srcwordaddr = saddr >> 4;
+ UINT32 dstwordaddr = daddr >> 4;
+ UINT8 srcbit = saddr & 15;
+ UINT8 dstbit = daddr & 15;
+ UINT32 srcword, dstword = 0;
+
+ /* fetch the initial source word */
+ srcword = (*word_read)(srcwordaddr++ << 1);
+ readwrites++;
+
+ /* fetch the initial dest word */
+ if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY || (daddr & 0x0f) != 0)
+ {
+ dstword = (*word_read)(dstwordaddr << 1);
+ readwrites++;
+ }
+
+ /* loop over pixels */
+ for (x = 0; x < dx; x++)
+ {
+ UINT32 dstmask;
+ UINT32 pixel;
+
+ /* fetch more words if necessary */
+ if (srcbit + BITS_PER_PIXEL > 16)
+ {
+ srcword |= (*word_read)(srcwordaddr++ << 1) << 16;
+ readwrites++;
+ }
+
+ /* extract pixel from source */
+ pixel = (srcword >> srcbit) & PIXEL_MASK;
+ srcbit += BITS_PER_PIXEL;
+ if (srcbit > 16)
+ {
+ srcbit -= 16;
+ srcword >>= 16;
+ }
+
+ /* fetch additional destination word if necessary */
+ if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY)
+ if (dstbit + BITS_PER_PIXEL > 16)
+ {
+ dstword |= (*word_read)((dstwordaddr + 1) << 1) << 16;
+ readwrites++;
+ }
+
+ /* apply pixel operations */
+ pixel <<= dstbit;
+ dstmask = PIXEL_MASK << dstbit;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* flush destination words */
+ dstbit += BITS_PER_PIXEL;
+ if (dstbit > 16)
+ {
+ (*word_write)(dstwordaddr++ << 1, dstword);
+ readwrites++;
+ dstbit -= 16;
+ dstword >>= 16;
+ }
+ }
+
+ /* flush any remaining words */
+ if (dstbit > 0)
+ {
+ /* if we're right-partial, read and mask the remaining bits */
+ if (dstbit != 16)
+ {
+ UINT16 origdst = (*word_read)(dstwordaddr << 1);
+ UINT16 mask = 0xffff << dstbit;
+ dstword = (dstword & ~mask) | (origdst & mask);
+ readwrites++;
+ }
+
+ (*word_write)(dstwordaddr++ << 1, dstword);
+ readwrites++;
+ }
+
+
+
+#if 0
+ int left_partials, right_partials, full_words, bitshift, bitshift_alt;
+ UINT16 srcword, srcmask, dstword, dstmask, pixel;
+ UINT32 swordaddr, dwordaddr;
+
+ /* determine the bit shift to get from source to dest */
+ bitshift = ((daddr & 15) - (saddr & 15)) & 15;
+ bitshift_alt = (16 - bitshift) & 15;
+
+ /* how many left and right partial pixels do we have? */
+ left_partials = (PIXELS_PER_WORD - ((daddr & 15) / BITS_PER_PIXEL)) & (PIXELS_PER_WORD - 1);
+ right_partials = ((daddr + dx * BITS_PER_PIXEL) & 15) / BITS_PER_PIXEL;
+ full_words = dx - left_partials - right_partials;
+ if (full_words < 0)
+ left_partials = dx, right_partials = full_words = 0;
+ else
+ full_words /= PIXELS_PER_WORD;
+
+ /* compute cycles */
+ state.gfxcycles += compute_pixblt_cycles(left_partials, right_partials, full_words, PIXEL_OP_TIMING);
+
+ /* use word addresses each row */
+ swordaddr = saddr >> 4;
+ dwordaddr = daddr >> 4;
+
+ /* fetch the initial source word */
+ srcword = (*word_read)(swordaddr++ << 1);
+ srcmask = PIXEL_MASK << (saddr & 15);
+
+ /* handle the left partial word */
+ if (left_partials != 0)
+ {
+ /* fetch the destination word */
+ dstword = (*word_read)(dwordaddr << 1);
+ dstmask = PIXEL_MASK << (daddr & 15);
+
+ /* loop over partials */
+ for (x = 0; x < left_partials; x++)
+ {
+ /* fetch another word if necessary */
+ if (srcmask == 0)
+ {
+ srcword = (*word_read)(swordaddr++ << 1);
+ srcmask = PIXEL_MASK;
+ }
+
+ /* process the pixel */
+ pixel = srcword & srcmask;
+ if (dstmask > srcmask)
+ pixel <<= bitshift;
+ else
+ pixel >>= bitshift_alt;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the source */
+ srcmask <<= BITS_PER_PIXEL;
+
+ /* update the destination */
+ dstmask <<= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr++ << 1, dstword);
+ }
+
+ /* loop over full words */
+ for (words = 0; words < full_words; words++)
+ {
+ /* fetch the destination word (if necessary) */
+ if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY)
+ dstword = (*word_read)(dwordaddr << 1);
+ else
+ dstword = 0;
+ dstmask = PIXEL_MASK;
+
+ /* loop over partials */
+ for (x = 0; x < PIXELS_PER_WORD; x++)
+ {
+ /* fetch another word if necessary */
+ if (srcmask == 0)
+ {
+ srcword = (*word_read)(swordaddr++ << 1);
+ srcmask = PIXEL_MASK;
+ }
+
+ /* process the pixel */
+ pixel = srcword & srcmask;
+ if (dstmask > srcmask)
+ pixel <<= bitshift;
+ else
+ pixel >>= bitshift_alt;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the source */
+ srcmask <<= BITS_PER_PIXEL;
+
+ /* update the destination */
+ dstmask <<= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr++ << 1, dstword);
+ }
+
+ /* handle the right partial word */
+ if (right_partials != 0)
+ {
+ /* fetch the destination word */
+ dstword = (*word_read)(dwordaddr << 1);
+ dstmask = PIXEL_MASK;
+
+ /* loop over partials */
+ for (x = 0; x < right_partials; x++)
+ {
+ /* fetch another word if necessary */
+ if (srcmask == 0)
+ {
+ LOGGFX((" right fetch @ %08x\n", swordaddr));
+ srcword = (*word_read)(swordaddr++ << 1);
+ srcmask = PIXEL_MASK;
+ }
+
+ /* process the pixel */
+ pixel = srcword & srcmask;
+ if (dstmask > srcmask)
+ pixel <<= bitshift;
+ else
+ pixel >>= bitshift_alt;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the source */
+ srcmask <<= BITS_PER_PIXEL;
+
+ /* update the destination */
+ dstmask <<= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr++ << 1, dstword);
+ }
+#endif
+
+ /* update for next row */
+ if (!yreverse)
+ {
+ saddr += SPTCH;
+ daddr += DPTCH;
+ }
+ else
+ {
+ saddr -= SPTCH;
+ daddr -= DPTCH;
+ }
+ }
+
+ state.gfxcycles += readwrites * 2 + dx * dy * (PIXEL_OP_TIMING - 2);
+
+ LOGGFX((" (%d cycles)\n", state.gfxcycles));
+ }
+
+ /* eat cycles */
+ if (state.gfxcycles > tms34010_ICount)
+ {
+ state.gfxcycles -= tms34010_ICount;
+ tms34010_ICount = 0;
+ PC -= 0x10;
+ }
+ else
+ {
+ tms34010_ICount -= state.gfxcycles;
+ state.st &= ~STBIT_P;
+ if (src_is_linear && dst_is_linear)
+ SADDR += DYDX_Y * SPTCH;
+ else if (src_is_linear)
+ SADDR += DYDX_Y * SPTCH;
+ else
+ SADDR_Y += DYDX_Y;
+ if (dst_is_linear)
+ DADDR += DYDX_Y * DPTCH;
+ else
+ DADDR_Y += DYDX_Y;
+ }
+}
+
+static void FUNCTION_NAME(pixblt_r)(int src_is_linear, int dst_is_linear)
+{
+ /* if this is the first time through, perform the operation */
+ if (!P_FLAG)
+ {
+ int dx, dy, x, y, words, yreverse;
+ void (*word_write)(offs_t address,UINT16 data);
+ UINT16 (*word_read)(offs_t address);
+ UINT32 saddr, daddr;
+ XY dstxy = { 0 };
+
+ /* determine read/write functions */
+ if (IOREG(REG_DPYCTL) & 0x0800)
+ {
+ word_write = shiftreg_w;
+ word_read = shiftreg_r;
+ }
+ else
+ {
+ word_write = program_write_word_16le;
+ word_read = program_read_word_16le;
+ }
+
+ /* compute the starting addresses */
+ saddr = src_is_linear ? SADDR : SXYTOL(SADDR_XY);
+if ((saddr & (BITS_PER_PIXEL - 1)) != 0) mame_printf_debug("PIXBLT_R%d with odd saddr\n", BITS_PER_PIXEL);
+ saddr &= ~(BITS_PER_PIXEL - 1);
+
+ /* compute the bounds of the operation */
+ dx = (INT16)DYDX_X;
+ dy = (INT16)DYDX_Y;
+
+ /* apply the window for non-linear destinations */
+ state.gfxcycles = 7 + (src_is_linear ? 0 : 2);
+ if (!dst_is_linear)
+ {
+ dstxy = DADDR_XY;
+ state.gfxcycles += 2 + (!src_is_linear) + apply_window("PIXBLT R", BITS_PER_PIXEL, &saddr, &dstxy, &dx, &dy);
+ daddr = DXYTOL(dstxy);
+ }
+ else
+ daddr = DADDR;
+if ((daddr & (BITS_PER_PIXEL - 1)) != 0) mame_printf_debug("PIXBLT_R%d with odd daddr\n", BITS_PER_PIXEL);
+ daddr &= ~(BITS_PER_PIXEL - 1);
+ LOGGFX((" saddr=%08X daddr=%08X sptch=%08X dptch=%08X\n", saddr, daddr, SPTCH, DPTCH));
+
+ /* bail if we're clipped */
+ if (dx <= 0 || dy <= 0)
+ return;
+
+ /* window mode 1: just return and interrupt if we are within the window */
+ if (WINDOW_CHECKING == 1 && !dst_is_linear)
+ {
+ CLR_V;
+ DADDR_XY = dstxy;
+ DYDX_X = dx;
+ DYDX_Y = dy;
+ IOREG(REG_INTPEND) |= TMS34010_WV;
+ check_interrupt();
+ return;
+ }
+
+ /* handle flipping the addresses */
+ yreverse = (IOREG(REG_CONTROL) >> 9) & 1;
+ if (!src_is_linear || !dst_is_linear)
+ {
+ saddr += dx * BITS_PER_PIXEL;
+ daddr += dx * BITS_PER_PIXEL;
+ if (yreverse)
+ {
+ saddr += (dy - 1) * SPTCH;
+ daddr += (dy - 1) * DPTCH;
+ }
+ }
+
+ state.st |= STBIT_P;
+
+ /* loop over rows */
+ for (y = 0; y < dy; y++)
+ {
+ int left_partials, right_partials, full_words, bitshift, bitshift_alt;
+ UINT16 srcword, srcmask, dstword, dstmask, pixel;
+ UINT32 swordaddr, dwordaddr;
+
+ /* determine the bit shift to get from source to dest */
+ bitshift = ((daddr & 15) - (saddr & 15)) & 15;
+ bitshift_alt = (16 - bitshift) & 15;
+
+ /* how many left and right partial pixels do we have? */
+ left_partials = (PIXELS_PER_WORD - (((daddr - dx * BITS_PER_PIXEL) & 15) / BITS_PER_PIXEL)) & (PIXELS_PER_WORD - 1);
+ right_partials = (daddr & 15) / BITS_PER_PIXEL;
+ full_words = dx - left_partials - right_partials;
+ if (full_words < 0)
+ right_partials = dx, left_partials = full_words = 0;
+ else
+ full_words /= PIXELS_PER_WORD;
+
+ /* compute cycles */
+ state.gfxcycles += compute_pixblt_cycles(left_partials, right_partials, full_words, PIXEL_OP_TIMING);
+
+ /* use word addresses each row */
+ swordaddr = (saddr + 15) >> 4;
+ dwordaddr = (daddr + 15) >> 4;
+
+ /* fetch the initial source word */
+ srcword = (*word_read)(--swordaddr << 1);
+ srcmask = PIXEL_MASK << ((saddr - BITS_PER_PIXEL) & 15);
+
+ /* handle the right partial word */
+ if (right_partials != 0)
+ {
+ /* fetch the destination word */
+ dstword = (*word_read)(--dwordaddr << 1);
+ dstmask = PIXEL_MASK << ((daddr - BITS_PER_PIXEL) & 15);
+
+ /* loop over partials */
+ for (x = 0; x < right_partials; x++)
+ {
+ /* fetch source pixel if necessary */
+ if (srcmask == 0)
+ {
+ srcword = (*word_read)(--swordaddr << 1);
+ srcmask = PIXEL_MASK << (16 - BITS_PER_PIXEL);
+ }
+
+ /* process the pixel */
+ pixel = srcword & srcmask;
+ if (dstmask > srcmask)
+ pixel <<= bitshift;
+ else
+ pixel >>= bitshift_alt;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the source */
+ srcmask >>= BITS_PER_PIXEL;
+
+ /* update the destination */
+ dstmask >>= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr << 1, dstword);
+ }
+
+ /* loop over full words */
+ for (words = 0; words < full_words; words++)
+ {
+ /* fetch the destination word (if necessary) */
+ dwordaddr--;
+ if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY)
+ dstword = (*word_read)(dwordaddr << 1);
+ else
+ dstword = 0;
+ dstmask = PIXEL_MASK << (16 - BITS_PER_PIXEL);
+
+ /* loop over partials */
+ for (x = 0; x < PIXELS_PER_WORD; x++)
+ {
+ /* fetch source pixel if necessary */
+ if (srcmask == 0)
+ {
+ srcword = (*word_read)(--swordaddr << 1);
+ srcmask = PIXEL_MASK << (16 - BITS_PER_PIXEL);
+ }
+
+ /* process the pixel */
+ pixel = srcword & srcmask;
+ if (dstmask > srcmask)
+ pixel <<= bitshift;
+ else
+ pixel >>= bitshift_alt;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the source */
+ srcmask >>= BITS_PER_PIXEL;
+
+ /* update the destination */
+ dstmask >>= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr << 1, dstword);
+ }
+
+ /* handle the left partial word */
+ if (left_partials != 0)
+ {
+ /* fetch the destination word */
+ dstword = (*word_read)(--dwordaddr << 1);
+ dstmask = PIXEL_MASK << (16 - BITS_PER_PIXEL);
+
+ /* loop over partials */
+ for (x = 0; x < left_partials; x++)
+ {
+ /* fetch the source pixel if necessary */
+ if (srcmask == 0)
+ {
+ srcword = (*word_read)(--swordaddr << 1);
+ srcmask = PIXEL_MASK << (16 - BITS_PER_PIXEL);
+ }
+
+ /* process the pixel */
+ pixel = srcword & srcmask;
+ if (dstmask > srcmask)
+ pixel <<= bitshift;
+ else
+ pixel >>= bitshift_alt;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the source */
+ srcmask >>= BITS_PER_PIXEL;
+
+ /* update the destination */
+ dstmask >>= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr << 1, dstword);
+ }
+
+ /* update for next row */
+ if (!yreverse)
+ {
+ saddr += SPTCH;
+ daddr += DPTCH;
+ }
+ else
+ {
+ saddr -= SPTCH;
+ daddr -= DPTCH;
+ }
+ }
+ LOGGFX((" (%d cycles)\n", state.gfxcycles));
+ }
+
+ /* eat cycles */
+ if (state.gfxcycles > tms34010_ICount)
+ {
+ state.gfxcycles -= tms34010_ICount;
+ tms34010_ICount = 0;
+ PC -= 0x10;
+ }
+ else
+ {
+ tms34010_ICount -= state.gfxcycles;
+ state.st &= ~STBIT_P;
+ if (src_is_linear && dst_is_linear)
+ SADDR += DYDX_Y * SPTCH;
+ else if (src_is_linear)
+ SADDR += DYDX_Y * SPTCH;
+ else
+ SADDR_Y += DYDX_Y;
+ if (dst_is_linear)
+ DADDR += DYDX_Y * DPTCH;
+ else
+ DADDR_Y += DYDX_Y;
+ }
+}
+
+static void FUNCTION_NAME(pixblt_b)(int dst_is_linear)
+{
+ /* if this is the first time through, perform the operation */
+ if (!P_FLAG)
+ {
+ int dx, dy, x, y, words, left_partials, right_partials, full_words;
+ void (*word_write)(offs_t address,UINT16 data);
+ UINT16 (*word_read)(offs_t address);
+ UINT32 saddr, daddr;
+ XY dstxy = { 0 };
+
+ /* determine read/write functions */
+ if (IOREG(REG_DPYCTL) & 0x0800)
+ {
+ word_write = shiftreg_w;
+ word_read = shiftreg_r;
+ }
+ else
+ {
+ word_write = program_write_word_16le;
+ word_read = program_read_word_16le;
+ }
+
+ /* compute the starting addresses */
+ saddr = SADDR;
+
+ /* compute the bounds of the operation */
+ dx = (INT16)DYDX_X;
+ dy = (INT16)DYDX_Y;
+
+ /* apply the window for non-linear destinations */
+ state.gfxcycles = 4;
+ if (!dst_is_linear)
+ {
+ dstxy = DADDR_XY;
+ state.gfxcycles += 2 + apply_window("PIXBLT B", 1, &saddr, &dstxy, &dx, &dy);
+ daddr = DXYTOL(dstxy);
+ }
+ else
+ daddr = DADDR;
+ daddr &= ~(BITS_PER_PIXEL - 1);
+ LOGGFX((" saddr=%08X daddr=%08X sptch=%08X dptch=%08X\n", saddr, daddr, SPTCH, DPTCH));
+
+ /* bail if we're clipped */
+ if (dx <= 0 || dy <= 0)
+ return;
+
+ /* window mode 1: just return and interrupt if we are within the window */
+ if (WINDOW_CHECKING == 1 && !dst_is_linear)
+ {
+ CLR_V;
+ DADDR_XY = dstxy;
+ DYDX_X = dx;
+ DYDX_Y = dy;
+ IOREG(REG_INTPEND) |= TMS34010_WV;
+ check_interrupt();
+ return;
+ }
+
+ /* how many left and right partial pixels do we have? */
+ left_partials = (PIXELS_PER_WORD - ((daddr & 15) / BITS_PER_PIXEL)) & (PIXELS_PER_WORD - 1);
+ right_partials = ((daddr + dx * BITS_PER_PIXEL) & 15) / BITS_PER_PIXEL;
+ full_words = dx - left_partials - right_partials;
+ if (full_words < 0)
+ left_partials = dx, right_partials = full_words = 0;
+ else
+ full_words /= PIXELS_PER_WORD;
+
+ /* compute cycles */
+ state.gfxcycles += compute_pixblt_b_cycles(left_partials, right_partials, full_words, dy, PIXEL_OP_TIMING, BITS_PER_PIXEL);
+ state.st |= STBIT_P;
+
+ /* loop over rows */
+ for (y = 0; y < dy; y++)
+ {
+ UINT16 srcword, srcmask, dstword, dstmask, pixel;
+ UINT32 swordaddr, dwordaddr;
+
+ /* use byte addresses each row */
+ swordaddr = saddr >> 4;
+ dwordaddr = daddr >> 4;
+
+ /* fetch the initial source word */
+ srcword = (*word_read)(swordaddr++ << 1);
+ srcmask = 1 << (saddr & 15);
+
+ /* handle the left partial word */
+ if (left_partials != 0)
+ {
+ /* fetch the destination word */
+ dstword = (*word_read)(dwordaddr << 1);
+ dstmask = PIXEL_MASK << (daddr & 15);
+
+ /* loop over partials */
+ for (x = 0; x < left_partials; x++)
+ {
+ /* process the pixel */
+ pixel = (srcword & srcmask) ? COLOR1 : COLOR0;
+ pixel &= dstmask;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the source */
+ srcmask <<= 1;
+ if (srcmask == 0)
+ {
+ srcword = (*word_read)(swordaddr++ << 1);
+ srcmask = 0x0001;
+ }
+
+ /* update the destination */
+ dstmask <<= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr++ << 1, dstword);
+ }
+
+ /* loop over full words */
+ for (words = 0; words < full_words; words++)
+ {
+ /* fetch the destination word (if necessary) */
+ if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY)
+ dstword = (*word_read)(dwordaddr << 1);
+ else
+ dstword = 0;
+ dstmask = PIXEL_MASK;
+
+ /* loop over partials */
+ for (x = 0; x < PIXELS_PER_WORD; x++)
+ {
+ /* process the pixel */
+ pixel = (srcword & srcmask) ? COLOR1 : COLOR0;
+ pixel &= dstmask;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the source */
+ srcmask <<= 1;
+ if (srcmask == 0)
+ {
+ srcword = (*word_read)(swordaddr++ << 1);
+ srcmask = 0x0001;
+ }
+
+ /* update the destination */
+ dstmask <<= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr++ << 1, dstword);
+ }
+
+ /* handle the right partial word */
+ if (right_partials != 0)
+ {
+ /* fetch the destination word */
+ dstword = (*word_read)(dwordaddr << 1);
+ dstmask = PIXEL_MASK;
+
+ /* loop over partials */
+ for (x = 0; x < right_partials; x++)
+ {
+ /* process the pixel */
+ pixel = (srcword & srcmask) ? COLOR1 : COLOR0;
+ pixel &= dstmask;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the source */
+ srcmask <<= 1;
+ if (srcmask == 0)
+ {
+ srcword = (*word_read)(swordaddr++ << 1);
+ srcmask = 0x0001;
+ }
+
+ /* update the destination */
+ dstmask <<= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr++ << 1, dstword);
+ }
+
+ /* update for next row */
+ saddr += SPTCH;
+ daddr += DPTCH;
+ }
+ LOGGFX((" (%d cycles)\n", state.gfxcycles));
+ }
+
+ /* eat cycles */
+ if (state.gfxcycles > tms34010_ICount)
+ {
+ state.gfxcycles -= tms34010_ICount;
+ tms34010_ICount = 0;
+ PC -= 0x10;
+ }
+ else
+ {
+ tms34010_ICount -= state.gfxcycles;
+ state.st &= ~STBIT_P;
+ SADDR += DYDX_Y * SPTCH;
+ if (dst_is_linear)
+ DADDR += DYDX_Y * DPTCH;
+ else
+ DADDR_Y += DYDX_Y;
+ }
+}
+
+static void FUNCTION_NAME(fill)(int dst_is_linear)
+{
+ /* if this is the first time through, perform the operation */
+ if (!P_FLAG)
+ {
+ int dx, dy, x, y, words, left_partials, right_partials, full_words;
+ void (*word_write)(offs_t address,UINT16 data);
+ UINT16 (*word_read)(offs_t address);
+ UINT32 daddr;
+ XY dstxy = { 0 };
+
+ /* determine read/write functions */
+ if (IOREG(REG_DPYCTL) & 0x0800)
+ {
+ word_write = shiftreg_w;
+ word_read = dummy_shiftreg_r;
+ }
+ else
+ {
+ word_write = program_write_word_16le;
+ word_read = program_read_word_16le;
+ }
+
+ /* compute the bounds of the operation */
+ dx = (INT16)DYDX_X;
+ dy = (INT16)DYDX_Y;
+
+ /* apply the window for non-linear destinations */
+ state.gfxcycles = 4;
+ if (!dst_is_linear)
+ {
+ dstxy = DADDR_XY;
+ state.gfxcycles += 2 + apply_window("FILL", 0, NULL, &dstxy, &dx, &dy);
+ daddr = DXYTOL(dstxy);
+ }
+ else
+ daddr = DADDR;
+ daddr &= ~(BITS_PER_PIXEL - 1);
+ LOGGFX((" daddr=%08X\n", daddr));
+
+ /* bail if we're clipped */
+ if (dx <= 0 || dy <= 0)
+ return;
+
+ /* window mode 1: just return and interrupt if we are within the window */
+ if (WINDOW_CHECKING == 1 && !dst_is_linear)
+ {
+ CLR_V;
+ DADDR_XY = dstxy;
+ DYDX_X = dx;
+ DYDX_Y = dy;
+ IOREG(REG_INTPEND) |= TMS34010_WV;
+ check_interrupt();
+ return;
+ }
+
+ /* how many left and right partial pixels do we have? */
+ left_partials = (PIXELS_PER_WORD - ((daddr & 15) / BITS_PER_PIXEL)) & (PIXELS_PER_WORD - 1);
+ right_partials = ((daddr + dx * BITS_PER_PIXEL) & 15) / BITS_PER_PIXEL;
+ full_words = dx - left_partials - right_partials;
+ if (full_words < 0)
+ left_partials = dx, right_partials = full_words = 0;
+ else
+ full_words /= PIXELS_PER_WORD;
+
+ /* compute cycles */
+ state.gfxcycles += 2;
+ state.st |= STBIT_P;
+
+ /* loop over rows */
+ for (y = 0; y < dy; y++)
+ {
+ UINT16 dstword, dstmask, pixel;
+ UINT32 dwordaddr;
+
+ /* use byte addresses each row */
+ dwordaddr = daddr >> 4;
+
+ /* compute cycles */
+ state.gfxcycles += compute_fill_cycles(left_partials, right_partials, full_words, PIXEL_OP_TIMING);
+
+ /* handle the left partial word */
+ if (left_partials != 0)
+ {
+ /* fetch the destination word */
+ dstword = (*word_read)(dwordaddr << 1);
+ dstmask = PIXEL_MASK << (daddr & 15);
+
+ /* loop over partials */
+ for (x = 0; x < left_partials; x++)
+ {
+ /* process the pixel */
+ pixel = COLOR1 & dstmask;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the destination */
+ dstmask <<= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr++ << 1, dstword);
+ }
+
+ /* loop over full words */
+ for (words = 0; words < full_words; words++)
+ {
+ /* fetch the destination word (if necessary) */
+ if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY)
+ dstword = (*word_read)(dwordaddr << 1);
+ else
+ dstword = 0;
+ dstmask = PIXEL_MASK;
+
+ /* loop over partials */
+ for (x = 0; x < PIXELS_PER_WORD; x++)
+ {
+ /* process the pixel */
+ pixel = COLOR1 & dstmask;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the destination */
+ dstmask <<= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr++ << 1, dstword);
+ }
+
+ /* handle the right partial word */
+ if (right_partials != 0)
+ {
+ /* fetch the destination word */
+ dstword = (*word_read)(dwordaddr << 1);
+ dstmask = PIXEL_MASK;
+
+ /* loop over partials */
+ for (x = 0; x < right_partials; x++)
+ {
+ /* process the pixel */
+ pixel = COLOR1 & dstmask;
+ PIXEL_OP(dstword, dstmask, pixel);
+ if (!TRANSPARENCY || pixel != 0)
+ dstword = (dstword & ~dstmask) | pixel;
+
+ /* update the destination */
+ dstmask <<= BITS_PER_PIXEL;
+ }
+
+ /* write the result */
+ (*word_write)(dwordaddr++ << 1, dstword);
+ }
+
+ /* update for next row */
+ daddr += DPTCH;
+ }
+
+ LOGGFX((" (%d cycles)\n", state.gfxcycles));
+ }
+
+ /* eat cycles */
+ if (state.gfxcycles > tms34010_ICount)
+ {
+ state.gfxcycles -= tms34010_ICount;
+ tms34010_ICount = 0;
+ PC -= 0x10;
+ }
+ else
+ {
+ tms34010_ICount -= state.gfxcycles;
+ state.st &= ~STBIT_P;
+ if (dst_is_linear)
+ DADDR += DYDX_Y * DPTCH;
+ else
+ DADDR_Y += DYDX_Y;
+ }
+}
+
+#endif
+
diff --git a/src/emu/cpu/tms34010/34010ops.c b/src/emu/cpu/tms34010/34010ops.c
new file mode 100644
index 00000000000..d4de9f387dd
--- /dev/null
+++ b/src/emu/cpu/tms34010/34010ops.c
@@ -0,0 +1,2467 @@
+/***************************************************************************
+
+ TMS34010: Portable Texas Instruments TMS34010 emulator
+
+ Copyright (C) Alex Pasadyn/Zsolt Vasvari 1998
+ Parts based on code by Aaron Giles
+
+***************************************************************************/
+
+
+
+/***************************************************************************
+ MISC MACROS
+***************************************************************************/
+
+#define ZEXTEND(val,width) if (width) (val) &= ((UINT32)0xffffffff >> (32 - (width)))
+#define SEXTEND(val,width) if (width) (val) = (INT32)((val) << (32 - (width))) >> (32 - (width))
+
+#define SXYTOL(val) ((((INT16)(val).y * state.convsp) + ((INT16)(val).x << state.pixelshift)) + OFFSET)
+#define DXYTOL(val) ((((INT16)(val).y * state.convdp) + ((INT16)(val).x << state.pixelshift)) + OFFSET)
+#define MXYTOL(val) ((((INT16)(val).y * state.convmp) + ((INT16)(val).x << state.pixelshift)) + OFFSET)
+
+#define COUNT_CYCLES(x) tms34010_ICount -= x
+#define COUNT_UNKNOWN_CYCLES(x) COUNT_CYCLES(x)
+
+#define CORRECT_ODD_PC(x) do { if (PC & 0x0f) logerror("%s to PC=%08X\n", x, PC); PC &= ~0x0f; } while (0)
+
+
+
+/***************************************************************************
+ FLAG HANDLING MACROS
+***************************************************************************/
+
+#define SIGN(val) ((val) & 0x80000000)
+
+#define CLR_Z state.st &= ~STBIT_Z
+#define CLR_V state.st &= ~STBIT_V
+#define CLR_C state.st &= ~STBIT_C
+#define CLR_N state.st &= ~STBIT_N
+#define CLR_NZ state.st &= ~(STBIT_N | STBIT_Z)
+#define CLR_CZ state.st &= ~(STBIT_C | STBIT_Z)
+#define CLR_ZV state.st &= ~(STBIT_Z | STBIT_V)
+#define CLR_NZV state.st &= ~(STBIT_N | STBIT_Z | STBIT_V)
+#define CLR_NCZ state.st &= ~(STBIT_N | STBIT_C | STBIT_Z)
+#define CLR_NCZV state.st &= ~(STBIT_N | STBIT_C | STBIT_Z | STBIT_V)
+
+#define SET_V_BIT_LO(val,bit) state.st |= ((val) << (28 - (bit))) & STBIT_V
+#define SET_V_BIT_HI(val,bit) state.st |= ((val) >> ((bit) - 28)) & STBIT_V
+#define SET_V_LOG(val) state.st |= (val) << 28
+#define SET_Z_BIT_LO(val,bit) state.st |= ((val) << (29 - (bit))) & STBIT_Z
+#define SET_Z_BIT_HI(val,bit) state.st |= ((val) >> ((bit) - 29)) & STBIT_Z
+#define SET_Z_LOG(val) state.st |= (val) << 29
+#define SET_C_BIT_LO(val,bit) state.st |= ((val) << (30 - (bit))) & STBIT_C
+#define SET_C_BIT_HI(val,bit) state.st |= ((val) >> ((bit) - 30)) & STBIT_C
+#define SET_C_LOG(val) state.st |= (val) << 30
+#define SET_N_BIT(val,bit) state.st |= ((val) << (31 - (bit))) & STBIT_N
+#define SET_N_LOG(val) state.st |= (val) << 31
+
+#define SET_Z_VAL(val) SET_Z_LOG((val) == 0)
+#define SET_N_VAL(val) SET_N_BIT(val, 31)
+#define SET_NZ_VAL(val) SET_Z_VAL(val); SET_N_VAL(val)
+#define SET_V_SUB(a,b,r) SET_V_BIT_HI(((a) ^ (b)) & ((a) ^ (r)), 31)
+#define SET_V_ADD(a,b,r) SET_V_BIT_HI(~((a) ^ (b)) & ((a) ^ (r)), 31)
+#define SET_C_SUB(a,b) SET_C_LOG((UINT32)(b) > (UINT32)(a))
+#define SET_C_ADD(a,b) SET_C_LOG((UINT32)~(a) < (UINT32)(b))
+#define SET_NZV_SUB(a,b,r) SET_NZ_VAL(r); SET_V_SUB(a,b,r)
+#define SET_NZCV_SUB(a,b,r) SET_NZV_SUB(a,b,r); SET_C_SUB(a,b)
+#define SET_NZCV_ADD(a,b,r) SET_NZ_VAL(r); SET_V_ADD(a,b,r); SET_C_ADD(a,b)
+
+static const UINT8 fw_inc[32] = { 32,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 };
+
+
+/***************************************************************************
+ UNIMPLEMENTED INSTRUCTION
+***************************************************************************/
+
+static void unimpl(void)
+{
+ /* kludge for Super High Impact -- this doesn't seem to cause */
+ /* an illegal opcode exception */
+ if (cpu_readop16(TOBYTE(PC - 0x10)) == 0x0007)
+ return;
+
+ /* 9 Ball Shootout calls to FFDF7468, expecting it */
+ /* to execute the next instruction from FFDF7470 */
+ /* but the instruction at FFDF7460 is an 0x0001 */
+ if (cpu_readop16(TOBYTE(PC - 0x10)) == 0x0001)
+ return;
+
+ PUSH(PC);
+ PUSH(GET_ST());
+ RESET_ST();
+ PC = RLONG(0xfffffc20);
+ change_pc(TOBYTE(PC));
+ COUNT_UNKNOWN_CYCLES(16);
+
+ /* extra check to prevent bad things */
+ if (PC == 0 || opcode_table[cpu_readop16(TOBYTE(PC)) >> 4] == unimpl)
+ {
+ cpunum_set_input_line(cpu_getactivecpu(), INPUT_LINE_HALT, ASSERT_LINE);
+ DEBUGGER_BREAK;
+ }
+}
+
+
+
+/***************************************************************************
+ X/Y OPERATIONS
+***************************************************************************/
+
+#define ADD_XY(R) \
+{ \
+ XY a = R##REG_XY(SRCREG); \
+ XY *b = &R##REG_XY(DSTREG); \
+ CLR_NCZV; \
+ b->x += a.x; \
+ b->y += a.y; \
+ SET_N_LOG(b->x == 0); \
+ SET_C_BIT_LO(b->y, 15); \
+ SET_Z_LOG(b->y == 0); \
+ SET_V_BIT_LO(b->x, 15); \
+ COUNT_CYCLES(1); \
+}
+static void add_xy_a(void) { ADD_XY(A); }
+static void add_xy_b(void) { ADD_XY(B); }
+
+#define SUB_XY(R) \
+{ \
+ XY a = R##REG_XY(SRCREG); \
+ XY *b = &R##REG_XY(DSTREG); \
+ CLR_NCZV; \
+ SET_N_LOG(a.x == b->x); \
+ SET_C_LOG(a.y > b->y); \
+ SET_Z_LOG(a.y == b->y); \
+ SET_V_LOG(a.x > b->x); \
+ b->x -= a.x; \
+ b->y -= a.y; \
+ COUNT_CYCLES(1); \
+}
+static void sub_xy_a(void) { SUB_XY(A); }
+static void sub_xy_b(void) { SUB_XY(B); }
+
+#define CMP_XY(R) \
+{ \
+ INT16 res; \
+ XY a = R##REG_XY(DSTREG); \
+ XY b = R##REG_XY(SRCREG); \
+ CLR_NCZV; \
+ res = a.x-b.x; \
+ SET_N_LOG(res == 0); \
+ SET_V_BIT_LO(res, 15); \
+ res = a.y-b.y; \
+ SET_Z_LOG(res == 0); \
+ SET_C_BIT_LO(res, 15); \
+ COUNT_CYCLES(1); \
+}
+static void cmp_xy_a(void) { CMP_XY(A); }
+static void cmp_xy_b(void) { CMP_XY(B); }
+
+#define CPW(R) \
+{ \
+ INT32 res = 0; \
+ INT16 x = R##REG_X(SRCREG); \
+ INT16 y = R##REG_Y(SRCREG); \
+ \
+ CLR_V; \
+ res |= ((WSTART_X > x) ? 0x20 : 0); \
+ res |= ((x > WEND_X) ? 0x40 : 0); \
+ res |= ((WSTART_Y > y) ? 0x80 : 0); \
+ res |= ((y > WEND_Y) ? 0x100 : 0); \
+ R##REG(DSTREG) = res; \
+ SET_V_LOG(res != 0); \
+ COUNT_CYCLES(1); \
+}
+static void cpw_a(void) { CPW(A); }
+static void cpw_b(void) { CPW(B); }
+
+#define CVXYL(R) \
+{ \
+ R##REG(DSTREG) = DXYTOL(R##REG_XY(SRCREG)); \
+ COUNT_CYCLES(3); \
+}
+static void cvxyl_a(void) { CVXYL(A); }
+static void cvxyl_b(void) { CVXYL(B); }
+
+#define MOVX(R) \
+{ \
+ R##REG(DSTREG) = (R##REG(DSTREG) & 0xffff0000) | (UINT16)R##REG(SRCREG); \
+ COUNT_CYCLES(1); \
+}
+static void movx_a(void) { MOVX(A); }
+static void movx_b(void) { MOVX(B); }
+
+#define MOVY(R) \
+{ \
+ R##REG(DSTREG) = (R##REG(SRCREG) & 0xffff0000) | (UINT16)R##REG(DSTREG); \
+ COUNT_CYCLES(1); \
+}
+static void movy_a(void) { MOVY(A); }
+static void movy_b(void) { MOVY(B); }
+
+
+
+/***************************************************************************
+ PIXEL TRANSFER OPERATIONS
+***************************************************************************/
+
+#define PIXT_RI(R) \
+{ \
+ WPIXEL(R##REG(DSTREG),R##REG(SRCREG)); \
+ COUNT_UNKNOWN_CYCLES(2); \
+}
+static void pixt_ri_a(void) { PIXT_RI(A); }
+static void pixt_ri_b(void) { PIXT_RI(B); }
+
+#define PIXT_RIXY(R) \
+{ \
+ if (WINDOW_CHECKING != 0) \
+ { \
+ CLR_V; \
+ if (R##REG_X(DSTREG) < WSTART_X || R##REG_X(DSTREG) > WEND_X || \
+ R##REG_Y(DSTREG) < WSTART_Y || R##REG_Y(DSTREG) > WEND_Y) \
+ { \
+ SET_V_LOG(1); \
+ goto skip; \
+ } \
+ if (WINDOW_CHECKING == 1) goto skip; \
+ } \
+ WPIXEL(DXYTOL(R##REG_XY(DSTREG)),R##REG(SRCREG)); \
+skip: \
+ COUNT_UNKNOWN_CYCLES(4); \
+}
+static void pixt_rixy_a(void) { PIXT_RIXY(A); }
+static void pixt_rixy_b(void) { PIXT_RIXY(B); }
+
+#define PIXT_IR(R) \
+{ \
+ INT32 temp = RPIXEL(R##REG(SRCREG)); \
+ CLR_V; \
+ R##REG(DSTREG) = temp; \
+ SET_V_LOG(temp != 0); \
+ COUNT_CYCLES(4); \
+}
+static void pixt_ir_a(void) { PIXT_IR(A); }
+static void pixt_ir_b(void) { PIXT_IR(B); }
+
+#define PIXT_II(R) \
+{ \
+ WPIXEL(R##REG(DSTREG),RPIXEL(R##REG(SRCREG))); \
+ COUNT_UNKNOWN_CYCLES(4); \
+}
+static void pixt_ii_a(void) { PIXT_II(A); }
+static void pixt_ii_b(void) { PIXT_II(B); }
+
+#define PIXT_IXYR(R) \
+{ \
+ INT32 temp = RPIXEL(SXYTOL(R##REG_XY(SRCREG))); \
+ CLR_V; \
+ R##REG(DSTREG) = temp; \
+ SET_V_LOG(temp != 0); \
+ COUNT_CYCLES(6); \
+}
+static void pixt_ixyr_a(void) { PIXT_IXYR(A); }
+static void pixt_ixyr_b(void) { PIXT_IXYR(B); }
+
+#define PIXT_IXYIXY(R) \
+{ \
+ if (WINDOW_CHECKING != 0) \
+ { \
+ CLR_V; \
+ if (R##REG_X(DSTREG) < WSTART_X || R##REG_X(DSTREG) > WEND_X || \
+ R##REG_Y(DSTREG) < WSTART_Y || R##REG_Y(DSTREG) > WEND_Y) \
+ { \
+ SET_V_LOG(1); \
+ goto skip; \
+ } \
+ if (WINDOW_CHECKING == 1) goto skip; \
+ } \
+ WPIXEL(DXYTOL(R##REG_XY(DSTREG)),RPIXEL(SXYTOL(R##REG_XY(SRCREG)))); \
+skip: \
+ COUNT_UNKNOWN_CYCLES(7); \
+}
+static void pixt_ixyixy_a(void) { PIXT_IXYIXY(A); }
+static void pixt_ixyixy_b(void) { PIXT_IXYIXY(B); }
+
+#define DRAV(R) \
+{ \
+ if (WINDOW_CHECKING != 0) \
+ { \
+ CLR_V; \
+ if (R##REG_X(DSTREG) < WSTART_X || R##REG_X(DSTREG) > WEND_X || \
+ R##REG_Y(DSTREG) < WSTART_Y || R##REG_Y(DSTREG) > WEND_Y) \
+ { \
+ SET_V_LOG(1); \
+ goto skip; \
+ } \
+ if (WINDOW_CHECKING == 1) goto skip; \
+ } \
+ WPIXEL(DXYTOL(R##REG_XY(DSTREG)),COLOR1); \
+skip: \
+ R##REG_X(DSTREG) += R##REG_X(SRCREG); \
+ R##REG_Y(DSTREG) += R##REG_Y(SRCREG); \
+ COUNT_UNKNOWN_CYCLES(4); \
+}
+static void drav_a(void) { DRAV(A); }
+static void drav_b(void) { DRAV(B); }
+
+
+
+/***************************************************************************
+ ARITHMETIC OPERATIONS
+***************************************************************************/
+
+#define ABS(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 r = 0 - *rd; \
+ CLR_NZV; \
+ if (r > 0) *rd = r; \
+ SET_NZ_VAL(r); \
+ SET_V_LOG(r == (INT32)0x80000000); \
+ COUNT_CYCLES(1); \
+}
+static void abs_a(void) { ABS(A); }
+static void abs_b(void) { ABS(B); }
+
+#define ADD(R) \
+{ \
+ INT32 a = R##REG(SRCREG); \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 b = *rd; \
+ INT32 r = a + b; \
+ CLR_NCZV; \
+ *rd = r; \
+ SET_NZCV_ADD(a,b,r); \
+ COUNT_CYCLES(1); \
+}
+static void add_a(void) { ADD(A); }
+static void add_b(void) { ADD(B); }
+
+#define ADDC(R) \
+{ \
+ /* I'm not sure to which side the carry is added to, should */ \
+ /* verify it against the examples */ \
+ INT32 a = R##REG(SRCREG); \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 b = *rd; \
+ INT32 r = a + b + (C_FLAG ? 1 : 0); \
+ CLR_NCZV; \
+ *rd = r; \
+ SET_NZCV_ADD(a,b,r); \
+ COUNT_CYCLES(1); \
+}
+static void addc_a(void) { ADDC(A); }
+static void addc_b(void) { ADDC(B); }
+
+#define ADDI_W(R) \
+{ \
+ INT32 a = PARAM_WORD(); \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 b = *rd; \
+ INT32 r = a + b; \
+ CLR_NCZV; \
+ *rd = r; \
+ SET_NZCV_ADD(a,b,r); \
+ COUNT_CYCLES(2); \
+}
+static void addi_w_a(void) { ADDI_W(A); }
+static void addi_w_b(void) { ADDI_W(B); }
+
+#define ADDI_L(R) \
+{ \
+ INT32 a = PARAM_LONG(); \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 b = *rd; \
+ INT32 r = a + b; \
+ CLR_NCZV; \
+ *rd = r; \
+ SET_NZCV_ADD(a,b,r); \
+ COUNT_CYCLES(3); \
+}
+static void addi_l_a(void) { ADDI_L(A); }
+static void addi_l_b(void) { ADDI_L(B); }
+
+#define ADDK(R) \
+{ \
+ INT32 a = fw_inc[PARAM_K]; \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 b = *rd; \
+ INT32 r = a + b; \
+ CLR_NCZV; \
+ *rd = r; \
+ SET_NZCV_ADD(a,b,r); \
+ COUNT_CYCLES(1); \
+}
+static void addk_a(void) { ADDK(A); }
+static void addk_b(void) { ADDK(B); }
+
+#define AND(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ *rd &= R##REG(SRCREG); \
+ SET_Z_VAL(*rd); \
+ COUNT_CYCLES(1); \
+}
+static void and_a(void) { AND(A); }
+static void and_b(void) { AND(B); }
+
+#define ANDI(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ *rd &= ~PARAM_LONG(); \
+ SET_Z_VAL(*rd); \
+ COUNT_CYCLES(3); \
+}
+static void andi_a(void) { ANDI(A); }
+static void andi_b(void) { ANDI(B); }
+
+#define ANDN(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ *rd &= ~R##REG(SRCREG); \
+ SET_Z_VAL(*rd); \
+ COUNT_CYCLES(1); \
+}
+static void andn_a(void) { ANDN(A); }
+static void andn_b(void) { ANDN(B); }
+
+#define BTST_K(R) \
+{ \
+ int bit = 31 - PARAM_K; \
+ CLR_Z; \
+ if (bit <= 29) \
+ SET_Z_BIT_LO(~R##REG(DSTREG), bit); \
+ else \
+ SET_Z_BIT_HI(~R##REG(DSTREG), bit); \
+ COUNT_CYCLES(1); \
+}
+static void btst_k_a(void) { BTST_K(A); }
+static void btst_k_b(void) { BTST_K(B); }
+
+#define BTST_R(R) \
+{ \
+ int bit = R##REG(SRCREG) & 0x1f; \
+ CLR_Z; \
+ if (bit <= 29) \
+ SET_Z_BIT_LO(~R##REG(DSTREG), bit); \
+ else \
+ SET_Z_BIT_HI(~R##REG(DSTREG), bit); \
+ COUNT_CYCLES(2); \
+}
+static void btst_r_a(void) { BTST_R(A); }
+static void btst_r_b(void) { BTST_R(B); }
+
+static void clrc(void)
+{
+ CLR_C;
+ COUNT_CYCLES(1);
+}
+
+#define CMP(R) \
+{ \
+ INT32 *rs = &R##REG(SRCREG); \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 r = *rd - *rs; \
+ CLR_NCZV; \
+ SET_NZCV_SUB(*rd,*rs,r); \
+ COUNT_CYCLES(1); \
+}
+static void cmp_a(void) { CMP(A); }
+static void cmp_b(void) { CMP(B); }
+
+#define CMPI_W(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 t = (INT16)~PARAM_WORD(); \
+ INT32 r = *rd - t; \
+ CLR_NCZV; \
+ SET_NZCV_SUB(*rd,t,r); \
+ COUNT_CYCLES(2); \
+}
+static void cmpi_w_a(void) { CMPI_W(A); }
+static void cmpi_w_b(void) { CMPI_W(B); }
+
+#define CMPI_L(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 t = ~PARAM_LONG(); \
+ INT32 r = *rd - t; \
+ CLR_NCZV; \
+ SET_NZCV_SUB(*rd,t,r); \
+ COUNT_CYCLES(3); \
+}
+static void cmpi_l_a(void) { CMPI_L(A); }
+static void cmpi_l_b(void) { CMPI_L(B); }
+
+static void dint(void)
+{
+ state.st &= ~STBIT_IE;
+ COUNT_CYCLES(3);
+}
+
+#define DIVS(R) \
+{ \
+ INT32 *rs = &R##REG(SRCREG); \
+ INT32 *rd1 = &R##REG(DSTREG); \
+ CLR_NZV; \
+ if (!(DSTREG & 1)) \
+ { \
+ if (!*rs) \
+ { \
+ SET_V_LOG(1); \
+ } \
+ else \
+ { \
+ INT32 *rd2 = &R##REG(DSTREG+1); \
+ INT64 dividend = COMBINE_64_32_32(*rd1, *rd2); \
+ INT64 quotient = DIV_64_64_32(dividend, *rs); \
+ INT32 remainder = MOD_32_64_32(dividend, *rs); \
+ UINT32 signbits = (INT32)quotient >> 31; \
+ if (HI32_32_64(quotient) != signbits) \
+ { \
+ SET_V_LOG(1); \
+ } \
+ else \
+ { \
+ *rd1 = quotient; \
+ *rd2 = remainder; \
+ SET_NZ_VAL(*rd1); \
+ } \
+ } \
+ COUNT_CYCLES(40); \
+ } \
+ else \
+ { \
+ if (!*rs) \
+ { \
+ SET_V_LOG(1); \
+ } \
+ else \
+ { \
+ *rd1 /= *rs; \
+ SET_NZ_VAL(*rd1); \
+ } \
+ COUNT_CYCLES(39); \
+ } \
+}
+static void divs_a(void) { DIVS(A); }
+static void divs_b(void) { DIVS(B); }
+
+#define DIVU(R) \
+{ \
+ INT32 *rs = &R##REG(SRCREG); \
+ INT32 *rd1 = &R##REG(DSTREG); \
+ CLR_ZV; \
+ if (!(DSTREG & 1)) \
+ { \
+ if (!*rs) \
+ { \
+ SET_V_LOG(1); \
+ } \
+ else \
+ { \
+ INT32 *rd2 = &R##REG(DSTREG+1); \
+ UINT64 dividend = COMBINE_U64_U32_U32(*rd1, *rd2); \
+ UINT64 quotient = DIV_U64_U64_U32(dividend, *rs); \
+ UINT32 remainder = MOD_U32_U64_U32(dividend, *rs); \
+ if (HI32_U32_U64(quotient) != 0) \
+ { \
+ SET_V_LOG(1); \
+ } \
+ else \
+ { \
+ *rd1 = quotient; \
+ *rd2 = remainder; \
+ SET_Z_VAL(*rd1); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ if (!*rs) \
+ { \
+ SET_V_LOG(1); \
+ } \
+ else \
+ { \
+ *rd1 = (UINT32)*rd1 / (UINT32)*rs; \
+ SET_Z_VAL(*rd1); \
+ } \
+ } \
+ COUNT_CYCLES(37); \
+}
+static void divu_a(void) { DIVU(A); }
+static void divu_b(void) { DIVU(B); }
+
+static void eint(void)
+{
+ state.st |= STBIT_IE;
+ check_interrupt();
+ COUNT_CYCLES(3);
+}
+
+#define EXGF(F,R) \
+{ \
+ UINT8 shift = F ? 6 : 0; \
+ INT32 *rd = &R##REG(DSTREG); \
+ UINT32 temp = (state.st >> shift) & 0x3f; \
+ state.st &= ~(0x3f << shift); \
+ state.st |= (*rd & 0x3f) << shift; \
+ *rd = temp; \
+ COUNT_CYCLES(1); \
+}
+static void exgf0_a(void) { EXGF(0,A); }
+static void exgf0_b(void) { EXGF(0,B); }
+static void exgf1_a(void) { EXGF(1,A); }
+static void exgf1_b(void) { EXGF(1,B); }
+
+#define LMO(R) \
+{ \
+ UINT32 res = 0; \
+ UINT32 rs = R##REG(SRCREG); \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ SET_Z_VAL(rs); \
+ if (rs) \
+ { \
+ while (!(rs & 0x80000000)) \
+ { \
+ res++; \
+ rs <<= 1; \
+ } \
+ } \
+ *rd = res; \
+ COUNT_CYCLES(1); \
+}
+static void lmo_a(void) { LMO(A); }
+static void lmo_b(void) { LMO(B); }
+
+#define MMFM(R) \
+{ \
+ INT32 i; \
+ UINT16 l = (UINT16) PARAM_WORD(); \
+ COUNT_CYCLES(3); \
+ { \
+ INT32 rd = DSTREG; \
+ for (i = 15; i >= 0 ; i--) \
+ { \
+ if (l & 0x8000) \
+ { \
+ R##REG(i) = RLONG(R##REG(rd)); \
+ R##REG(rd) += 0x20; \
+ COUNT_CYCLES(4); \
+ } \
+ l <<= 1; \
+ } \
+ } \
+}
+static void mmfm_a(void) { MMFM(A); }
+static void mmfm_b(void) { MMFM(B); }
+
+#define MMTM(R) \
+{ \
+ UINT32 i; \
+ UINT16 l = (UINT16) PARAM_WORD(); \
+ COUNT_CYCLES(2); \
+ { \
+ INT32 rd = DSTREG; \
+ if (state.is_34020) \
+ { \
+ CLR_N; \
+ SET_N_VAL(R##REG(rd) ^ 0x80000000); \
+ } \
+ for (i = 0; i < 16; i++) \
+ { \
+ if (l & 0x8000) \
+ { \
+ R##REG(rd) -= 0x20; \
+ WLONG(R##REG(rd),R##REG(i)); \
+ COUNT_CYCLES(4); \
+ } \
+ l <<= 1; \
+ } \
+ } \
+}
+static void mmtm_a(void) { MMTM(A); }
+static void mmtm_b(void) { MMTM(B); }
+
+#define MODS(R) \
+{ \
+ INT32 *rs = &R##REG(SRCREG); \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_NZV; \
+ if (*rs != 0) \
+ { \
+ *rd %= *rs; \
+ SET_NZ_VAL(*rd); \
+ } \
+ else \
+ SET_V_LOG(1); \
+ COUNT_CYCLES(40); \
+}
+static void mods_a(void) { MODS(A); }
+static void mods_b(void) { MODS(B); }
+
+#define MODU(R) \
+{ \
+ INT32 *rs = &R##REG(SRCREG); \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_ZV; \
+ if (*rs != 0) \
+ { \
+ *rd = (UINT32)*rd % (UINT32)*rs; \
+ SET_Z_VAL(*rd); \
+ } \
+ else \
+ SET_V_LOG(1); \
+ COUNT_CYCLES(35); \
+}
+static void modu_a(void) { MODU(A); }
+static void modu_b(void) { MODU(B); }
+
+#define MPYS(R) \
+{ \
+ INT32 *rd1 = &R##REG(DSTREG); \
+ INT32 m1 = R##REG(SRCREG); \
+ INT64 product; \
+ \
+ SEXTEND(m1, FW(1)); \
+ CLR_NZ; \
+ product = MUL_64_32_32(m1, *rd1); \
+ SET_Z_LOG(product == 0); \
+ SET_N_BIT(product >> 32, 31); \
+ \
+ *rd1 = HI32_32_64(product); \
+ R##REG(DSTREG|1) = LO32_32_64(product); \
+ \
+ COUNT_CYCLES(20); \
+}
+static void mpys_a(void) { MPYS(A); }
+static void mpys_b(void) { MPYS(B); }
+
+#define MPYU(R) \
+{ \
+ INT32 *rd1 = &R##REG(DSTREG); \
+ UINT32 m1 = R##REG(SRCREG); \
+ UINT64 product; \
+ \
+ ZEXTEND(m1, FW(1)); \
+ CLR_Z; \
+ product = MUL_U64_U32_U32(m1, *rd1); \
+ SET_Z_LOG(product == 0); \
+ \
+ *rd1 = HI32_32_64(product); \
+ R##REG(DSTREG|1) = LO32_32_64(product); \
+ \
+ COUNT_CYCLES(21); \
+}
+static void mpyu_a(void) { MPYU(A); }
+static void mpyu_b(void) { MPYU(B); }
+
+#define NEG(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 r = 0 - *rd; \
+ CLR_NCZV; \
+ SET_NZCV_SUB(0,*rd,r); \
+ *rd = r; \
+ COUNT_CYCLES(1); \
+}
+static void neg_a(void) { NEG(A); }
+static void neg_b(void) { NEG(B); }
+
+#define NEGB(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 t = *rd + (C_FLAG ? 1 : 0); \
+ INT32 r = 0 - t; \
+ CLR_NCZV; \
+ SET_NZCV_SUB(0,t,r); \
+ *rd = r; \
+ COUNT_CYCLES(1); \
+}
+static void negb_a(void) { NEGB(A); }
+static void negb_b(void) { NEGB(B); }
+
+static void nop(void)
+{
+ COUNT_CYCLES(1);
+}
+
+#define NOT(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ *rd = ~(*rd); \
+ SET_Z_VAL(*rd); \
+ COUNT_CYCLES(1); \
+}
+static void not_a(void) { NOT(A); }
+static void not_b(void) { NOT(B); }
+
+#define OR(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ *rd |= R##REG(SRCREG); \
+ SET_Z_VAL(*rd); \
+ COUNT_CYCLES(1); \
+}
+static void or_a(void) { OR(A); }
+static void or_b(void) { OR(B); }
+
+#define ORI(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ *rd |= PARAM_LONG(); \
+ SET_Z_VAL(*rd); \
+ COUNT_CYCLES(3); \
+}
+static void ori_a(void) { ORI(A); }
+static void ori_b(void) { ORI(B); }
+
+static void setc(void)
+{
+ SET_C_LOG(1);
+ COUNT_CYCLES(1);
+}
+
+#define SETF(F) \
+{ \
+ UINT8 shift = F ? 6 : 0; \
+ state.st &= ~(0x3f << shift); \
+ state.st |= (state.op & 0x3f) << shift; \
+ COUNT_CYCLES(1+F); \
+}
+static void setf0(void) { SETF(0); }
+static void setf1(void) { SETF(1); }
+
+#define SEXT(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_NZ; \
+ SEXTEND(*rd,FW(F)); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(3); \
+}
+static void sext0_a(void) { SEXT(0,A); }
+static void sext0_b(void) { SEXT(0,B); }
+static void sext1_a(void) { SEXT(1,A); }
+static void sext1_b(void) { SEXT(1,B); }
+
+#define RL(R,K) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 res = *rd; \
+ INT32 k = (K); \
+ CLR_CZ; \
+ if (k) \
+ { \
+ res<<=(k-1); \
+ SET_C_BIT_HI(res, 31); \
+ res<<=1; \
+ res |= (((UINT32)*rd)>>((-k)&0x1f)); \
+ *rd = res; \
+ } \
+ SET_Z_VAL(res); \
+ COUNT_CYCLES(1); \
+}
+static void rl_k_a(void) { RL(A,PARAM_K); }
+static void rl_k_b(void) { RL(B,PARAM_K); }
+static void rl_r_a(void) { RL(A,AREG(SRCREG)&0x1f); }
+static void rl_r_b(void) { RL(B,BREG(SRCREG)&0x1f); }
+
+#define SLA(R,K) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ UINT32 res = *rd; \
+ INT32 k = K; \
+ CLR_NCZV; \
+ if (k) \
+ { \
+ UINT32 mask = (0xffffffff<<(31-k))&0x7fffffff; \
+ UINT32 res2 = SIGN(res) ? res^mask : res; \
+ SET_V_LOG((res2 & mask) != 0); \
+ \
+ res<<=(k-1); \
+ SET_C_BIT_HI(res, 31); \
+ res<<=1; \
+ *rd = res; \
+ } \
+ SET_NZ_VAL(res); \
+ COUNT_CYCLES(3); \
+}
+static void sla_k_a(void) { SLA(A,PARAM_K); }
+static void sla_k_b(void) { SLA(B,PARAM_K); }
+static void sla_r_a(void) { SLA(A,AREG(SRCREG)&0x1f); }
+static void sla_r_b(void) { SLA(B,BREG(SRCREG)&0x1f); }
+
+#define SLL(R,K) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ UINT32 res = *rd; \
+ INT32 k = K; \
+ CLR_CZ; \
+ if (k) \
+ { \
+ res<<=(k-1); \
+ SET_C_BIT_HI(res, 31); \
+ res<<=1; \
+ *rd = res; \
+ } \
+ SET_Z_VAL(res); \
+ COUNT_CYCLES(1); \
+}
+static void sll_k_a(void) { SLL(A,PARAM_K); }
+static void sll_k_b(void) { SLL(B,PARAM_K); }
+static void sll_r_a(void) { SLL(A,AREG(SRCREG)&0x1f); }
+static void sll_r_b(void) { SLL(B,BREG(SRCREG)&0x1f); }
+
+#define SRA(R,K) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 res = *rd; \
+ INT32 k = (-(K)) & 0x1f; \
+ CLR_NCZ; \
+ if (k) \
+ { \
+ res>>=(k-1); \
+ SET_C_BIT_LO(res, 0); \
+ res>>=1; \
+ *rd = res; \
+ } \
+ SET_NZ_VAL(res); \
+ COUNT_CYCLES(1); \
+}
+static void sra_k_a(void) { SRA(A,PARAM_K); }
+static void sra_k_b(void) { SRA(B,PARAM_K); }
+static void sra_r_a(void) { SRA(A,AREG(SRCREG)); }
+static void sra_r_b(void) { SRA(B,BREG(SRCREG)); }
+
+#define SRL(R,K) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ UINT32 res = *rd; \
+ INT32 k = (-(K)) & 0x1f; \
+ CLR_CZ; \
+ if (k) \
+ { \
+ res>>=(k-1); \
+ SET_C_BIT_LO(res, 0); \
+ res>>=1; \
+ *rd = res; \
+ } \
+ SET_Z_VAL(res); \
+ COUNT_CYCLES(1); \
+}
+static void srl_k_a(void) { SRL(A,PARAM_K); }
+static void srl_k_b(void) { SRL(B,PARAM_K); }
+static void srl_r_a(void) { SRL(A,AREG(SRCREG)); }
+static void srl_r_b(void) { SRL(B,BREG(SRCREG)); }
+
+#define SUB(R) \
+{ \
+ INT32 *rs = &R##REG(SRCREG); \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 r = *rd - *rs; \
+ CLR_NCZV; \
+ SET_NZCV_SUB(*rd,*rs,r); \
+ *rd = r; \
+ COUNT_CYCLES(1); \
+}
+static void sub_a(void) { SUB(A); }
+static void sub_b(void) { SUB(B); }
+
+#define SUBB(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 t = R##REG(SRCREG); \
+ INT32 r = *rd - t - (C_FLAG ? 1 : 0); \
+ CLR_NCZV; \
+ SET_NZCV_SUB(*rd,t,r); \
+ *rd = r; \
+ COUNT_CYCLES(1); \
+}
+static void subb_a(void) { SUBB(A); }
+static void subb_b(void) { SUBB(B); }
+
+#define SUBI_W(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 r; \
+ INT32 t = ~PARAM_WORD(); \
+ CLR_NCZV; \
+ r = *rd - t; \
+ SET_NZCV_SUB(*rd,t,r); \
+ *rd = r; \
+ COUNT_CYCLES(2); \
+}
+static void subi_w_a(void) { SUBI_W(A); }
+static void subi_w_b(void) { SUBI_W(B); }
+
+#define SUBI_L(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 t = ~PARAM_LONG(); \
+ INT32 r = *rd - t; \
+ CLR_NCZV; \
+ SET_NZCV_SUB(*rd,t,r); \
+ *rd = r; \
+ COUNT_CYCLES(3); \
+}
+static void subi_l_a(void) { SUBI_L(A); }
+static void subi_l_b(void) { SUBI_L(B); }
+
+#define SUBK(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 t = fw_inc[PARAM_K]; \
+ INT32 r = *rd - t; \
+ CLR_NCZV; \
+ SET_NZCV_SUB(*rd,t,r); \
+ *rd = r; \
+ COUNT_CYCLES(1); \
+}
+static void subk_a(void) { SUBK(A); }
+static void subk_b(void) { SUBK(B); }
+
+#define XOR(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ *rd ^= R##REG(SRCREG); \
+ SET_Z_VAL(*rd); \
+ COUNT_CYCLES(1); \
+}
+static void xor_a(void) { XOR(A); }
+static void xor_b(void) { XOR(B); }
+
+#define XORI(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ *rd ^= PARAM_LONG(); \
+ SET_Z_VAL(*rd); \
+ COUNT_CYCLES(3); \
+}
+static void xori_a(void) { XORI(A); }
+static void xori_b(void) { XORI(B); }
+
+#define ZEXT(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ ZEXTEND(*rd,FW(F)); \
+ SET_Z_VAL(*rd); \
+ COUNT_CYCLES(1); \
+}
+static void zext0_a(void) { ZEXT(0,A); }
+static void zext0_b(void) { ZEXT(0,B); }
+static void zext1_a(void) { ZEXT(1,A); }
+static void zext1_b(void) { ZEXT(1,B); }
+
+
+
+/***************************************************************************
+ MOVE INSTRUCTIONS
+***************************************************************************/
+
+#define MOVI_W(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_NZV; \
+ *rd=PARAM_WORD(); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(2); \
+}
+static void movi_w_a(void) { MOVI_W(A); }
+static void movi_w_b(void) { MOVI_W(B); }
+
+#define MOVI_L(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_NZV; \
+ *rd=PARAM_LONG(); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(3); \
+}
+static void movi_l_a(void) { MOVI_L(A); }
+static void movi_l_b(void) { MOVI_L(B); }
+
+#define MOVK(R) \
+{ \
+ INT32 k = PARAM_K; if (!k) k = 32; \
+ R##REG(DSTREG) = k; \
+ COUNT_CYCLES(1); \
+}
+static void movk_a(void) { MOVK(A); }
+static void movk_b(void) { MOVK(B); }
+
+#define MOVB_RN(R) \
+{ \
+ WBYTE(R##REG(DSTREG),R##REG(SRCREG)); \
+ COUNT_CYCLES(1); \
+}
+static void movb_rn_a(void) { MOVB_RN(A); }
+static void movb_rn_b(void) { MOVB_RN(B); }
+
+#define MOVB_NR(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_NZV; \
+ *rd = (INT8)RBYTE(R##REG(SRCREG)); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(3); \
+}
+static void movb_nr_a(void) { MOVB_NR(A); }
+static void movb_nr_b(void) { MOVB_NR(B); }
+
+#define MOVB_NN(R) \
+{ \
+ WBYTE(R##REG(DSTREG),(UINT32)(UINT8)RBYTE(R##REG(SRCREG))); \
+ COUNT_CYCLES(3); \
+}
+static void movb_nn_a(void) { MOVB_NN(A); }
+static void movb_nn_b(void) { MOVB_NN(B); }
+
+#define MOVB_R_NO(R) \
+{ \
+ INT32 o = PARAM_WORD(); \
+ WBYTE(R##REG(DSTREG)+o,R##REG(SRCREG)); \
+ COUNT_CYCLES(3); \
+}
+static void movb_r_no_a(void) { MOVB_R_NO(A); }
+static void movb_r_no_b(void) { MOVB_R_NO(B); }
+
+#define MOVB_NO_R(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 o = PARAM_WORD(); \
+ CLR_NZV; \
+ *rd = (INT8)RBYTE(R##REG(SRCREG)+o); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(5); \
+}
+static void movb_no_r_a(void) { MOVB_NO_R(A); }
+static void movb_no_r_b(void) { MOVB_NO_R(B); }
+
+#define MOVB_NO_NO(R) \
+{ \
+ INT32 o1 = PARAM_WORD(); \
+ INT32 o2 = PARAM_WORD(); \
+ WBYTE(R##REG(DSTREG)+o2,(UINT32)(UINT8)RBYTE(R##REG(SRCREG)+o1)); \
+ COUNT_CYCLES(5); \
+}
+static void movb_no_no_a(void) { MOVB_NO_NO(A); }
+static void movb_no_no_b(void) { MOVB_NO_NO(B); }
+
+#define MOVB_RA(R) \
+{ \
+ WBYTE(PARAM_LONG(),R##REG(DSTREG)); \
+ COUNT_CYCLES(1); \
+}
+static void movb_ra_a(void) { MOVB_RA(A); }
+static void movb_ra_b(void) { MOVB_RA(B); }
+
+#define MOVB_AR(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_NZV; \
+ *rd = (INT8)RBYTE(PARAM_LONG()); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(5); \
+}
+static void movb_ar_a(void) { MOVB_AR(A); }
+static void movb_ar_b(void) { MOVB_AR(B); }
+
+static void movb_aa(void)
+{
+ UINT32 bitaddrs=PARAM_LONG();
+ WBYTE(PARAM_LONG(),(UINT32)(UINT8)RBYTE(bitaddrs));
+ COUNT_CYCLES(6);
+}
+
+#define MOVE_RR(RS,RD) \
+{ \
+ INT32 *rd = &RD##REG(DSTREG); \
+ CLR_NZV; \
+ *rd = RS##REG(SRCREG); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(1); \
+}
+static void move_rr_a (void) { MOVE_RR(A,A); }
+static void move_rr_b (void) { MOVE_RR(B,B); }
+static void move_rr_ax(void) { MOVE_RR(A,B); }
+static void move_rr_bx(void) { MOVE_RR(B,A); }
+
+#define MOVE_RN(F,R) \
+{ \
+ WFIELD##F(R##REG(DSTREG),R##REG(SRCREG)); \
+ COUNT_CYCLES(1); \
+}
+static void move0_rn_a (void) { MOVE_RN(0,A); }
+static void move0_rn_b (void) { MOVE_RN(0,B); }
+static void move1_rn_a (void) { MOVE_RN(1,A); }
+static void move1_rn_b (void) { MOVE_RN(1,B); }
+
+#define MOVE_R_DN(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ *rd-=fw_inc[FW(F)]; \
+ WFIELD##F(*rd,R##REG(SRCREG)); \
+ COUNT_CYCLES(2); \
+}
+static void move0_r_dn_a (void) { MOVE_R_DN(0,A); }
+static void move0_r_dn_b (void) { MOVE_R_DN(0,B); }
+static void move1_r_dn_a (void) { MOVE_R_DN(1,A); }
+static void move1_r_dn_b (void) { MOVE_R_DN(1,B); }
+
+#define MOVE_R_NI(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ WFIELD##F(*rd,R##REG(SRCREG)); \
+ *rd+=fw_inc[FW(F)]; \
+ COUNT_CYCLES(1); \
+}
+static void move0_r_ni_a (void) { MOVE_R_NI(0,A); }
+static void move0_r_ni_b (void) { MOVE_R_NI(0,B); }
+static void move1_r_ni_a (void) { MOVE_R_NI(1,A); }
+static void move1_r_ni_b (void) { MOVE_R_NI(1,B); }
+
+#define MOVE_NR(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_NZV; \
+ *rd = RFIELD##F(R##REG(SRCREG)); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(3); \
+}
+static void move0_nr_a (void) { MOVE_NR(0,A); }
+static void move0_nr_b (void) { MOVE_NR(0,B); }
+static void move1_nr_a (void) { MOVE_NR(1,A); }
+static void move1_nr_b (void) { MOVE_NR(1,B); }
+
+#define MOVE_DN_R(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 *rs = &R##REG(SRCREG); \
+ CLR_NZV; \
+ *rs-=fw_inc[FW(F)]; \
+ *rd = RFIELD##F(*rs); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(4); \
+}
+static void move0_dn_r_a (void) { MOVE_DN_R(0,A); }
+static void move0_dn_r_b (void) { MOVE_DN_R(0,B); }
+static void move1_dn_r_a (void) { MOVE_DN_R(1,A); }
+static void move1_dn_r_b (void) { MOVE_DN_R(1,B); }
+
+#define MOVE_NI_R(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 *rs = &R##REG(SRCREG); \
+ INT32 data = RFIELD##F(*rs); \
+ CLR_NZV; \
+ *rs+=fw_inc[FW(F)]; \
+ *rd = data; \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(3); \
+}
+static void move0_ni_r_a (void) { MOVE_NI_R(0,A); }
+static void move0_ni_r_b (void) { MOVE_NI_R(0,B); }
+static void move1_ni_r_a (void) { MOVE_NI_R(1,A); }
+static void move1_ni_r_b (void) { MOVE_NI_R(1,B); }
+
+#define MOVE_NN(F,R) \
+{ \
+ WFIELD##F(R##REG(DSTREG),RFIELD##F(R##REG(SRCREG))); \
+ COUNT_CYCLES(3); \
+}
+static void move0_nn_a (void) { MOVE_NN(0,A); }
+static void move0_nn_b (void) { MOVE_NN(0,B); }
+static void move1_nn_a (void) { MOVE_NN(1,A); }
+static void move1_nn_b (void) { MOVE_NN(1,B); }
+
+#define MOVE_DN_DN(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 *rs = &R##REG(SRCREG); \
+ INT32 data; \
+ *rs-=fw_inc[FW(F)]; \
+ data = RFIELD##F(*rs); \
+ *rd-=fw_inc[FW(F)]; \
+ WFIELD##F(*rd,data); \
+ COUNT_CYCLES(4); \
+}
+static void move0_dn_dn_a (void) { MOVE_DN_DN(0,A); }
+static void move0_dn_dn_b (void) { MOVE_DN_DN(0,B); }
+static void move1_dn_dn_a (void) { MOVE_DN_DN(1,A); }
+static void move1_dn_dn_b (void) { MOVE_DN_DN(1,B); }
+
+#define MOVE_NI_NI(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 *rs = &R##REG(SRCREG); \
+ INT32 data = RFIELD##F(*rs); \
+ *rs+=fw_inc[FW(F)]; \
+ WFIELD##F(*rd,data); \
+ *rd+=fw_inc[FW(F)]; \
+ COUNT_CYCLES(4); \
+}
+static void move0_ni_ni_a (void) { MOVE_NI_NI(0,A); }
+static void move0_ni_ni_b (void) { MOVE_NI_NI(0,B); }
+static void move1_ni_ni_a (void) { MOVE_NI_NI(1,A); }
+static void move1_ni_ni_b (void) { MOVE_NI_NI(1,B); }
+
+#define MOVE_R_NO(F,R) \
+{ \
+ INT32 o = PARAM_WORD(); \
+ WFIELD##F(R##REG(DSTREG)+o,R##REG(SRCREG)); \
+ COUNT_CYCLES(3); \
+}
+static void move0_r_no_a (void) { MOVE_R_NO(0,A); }
+static void move0_r_no_b (void) { MOVE_R_NO(0,B); }
+static void move1_r_no_a (void) { MOVE_R_NO(1,A); }
+static void move1_r_no_b (void) { MOVE_R_NO(1,B); }
+
+#define MOVE_NO_R(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 o = PARAM_WORD(); \
+ CLR_NZV; \
+ *rd = RFIELD##F(R##REG(SRCREG)+o); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(5); \
+}
+static void move0_no_r_a (void) { MOVE_NO_R(0,A); }
+static void move0_no_r_b (void) { MOVE_NO_R(0,B); }
+static void move1_no_r_a (void) { MOVE_NO_R(1,A); }
+static void move1_no_r_b (void) { MOVE_NO_R(1,B); }
+
+#define MOVE_NO_NI(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 o = PARAM_WORD(); \
+ INT32 data = RFIELD##F(R##REG(SRCREG)+o); \
+ WFIELD##F(*rd,data); \
+ *rd+=fw_inc[FW(F)]; \
+ COUNT_CYCLES(5); \
+}
+static void move0_no_ni_a (void) { MOVE_NO_NI(0,A); }
+static void move0_no_ni_b (void) { MOVE_NO_NI(0,B); }
+static void move1_no_ni_a (void) { MOVE_NO_NI(1,A); }
+static void move1_no_ni_b (void) { MOVE_NO_NI(1,B); }
+
+#define MOVE_NO_NO(F,R) \
+{ \
+ INT32 o1 = PARAM_WORD(); \
+ INT32 o2 = PARAM_WORD(); \
+ INT32 data = RFIELD##F(R##REG(SRCREG)+o1); \
+ WFIELD##F(R##REG(DSTREG)+o2,data); \
+ COUNT_CYCLES(5); \
+}
+static void move0_no_no_a (void) { MOVE_NO_NO(0,A); }
+static void move0_no_no_b (void) { MOVE_NO_NO(0,B); }
+static void move1_no_no_a (void) { MOVE_NO_NO(1,A); }
+static void move1_no_no_b (void) { MOVE_NO_NO(1,B); }
+
+#define MOVE_RA(F,R) \
+{ \
+ WFIELD##F(PARAM_LONG(),R##REG(DSTREG)); \
+ COUNT_CYCLES(3); \
+}
+static void move0_ra_a (void) { MOVE_RA(0,A); }
+static void move0_ra_b (void) { MOVE_RA(0,B); }
+static void move1_ra_a (void) { MOVE_RA(1,A); }
+static void move1_ra_b (void) { MOVE_RA(1,B); }
+
+#define MOVE_AR(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_NZV; \
+ *rd = RFIELD##F(PARAM_LONG()); \
+ SET_NZ_VAL(*rd); \
+ COUNT_CYCLES(5); \
+}
+static void move0_ar_a (void) { MOVE_AR(0,A); }
+static void move0_ar_b (void) { MOVE_AR(0,B); }
+static void move1_ar_a (void) { MOVE_AR(1,A); }
+static void move1_ar_b (void) { MOVE_AR(1,B); }
+
+#define MOVE_A_NI(F,R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ WFIELD##F(*rd,RFIELD##F(PARAM_LONG())); \
+ *rd+=fw_inc[FW(F)]; \
+ COUNT_CYCLES(5); \
+}
+static void move0_a_ni_a (void) { MOVE_A_NI(0,A); }
+static void move0_a_ni_b (void) { MOVE_A_NI(0,B); }
+static void move1_a_ni_a (void) { MOVE_A_NI(1,A); }
+static void move1_a_ni_b (void) { MOVE_A_NI(1,B); }
+
+#define MOVE_AA(F) \
+{ \
+ UINT32 bitaddrs=PARAM_LONG(); \
+ WFIELD##F(PARAM_LONG(),RFIELD##F(bitaddrs)); \
+ COUNT_CYCLES(7); \
+}
+static void move0_aa (void) { MOVE_AA(0); }
+static void move1_aa (void) { MOVE_AA(1); }
+
+
+
+/***************************************************************************
+ PROGRAM CONTROL INSTRUCTIONS
+***************************************************************************/
+
+#define CALL(R) \
+{ \
+ PUSH(PC); \
+ PC = R##REG(DSTREG); \
+ CORRECT_ODD_PC("CALL"); \
+ change_pc(TOBYTE(PC)); \
+ COUNT_CYCLES(3); \
+}
+static void call_a (void) { CALL(A); }
+static void call_b (void) { CALL(B); }
+
+static void callr(void)
+{
+ PUSH(PC+0x10);
+ PC += (PARAM_WORD_NO_INC()<<4)+0x10;
+ COUNT_CYCLES(3);
+}
+
+static void calla(void)
+{
+ PUSH(PC+0x20);
+ PC = PARAM_LONG_NO_INC();
+ CORRECT_ODD_PC("CALLA");
+ change_pc(TOBYTE(PC));
+ COUNT_CYCLES(4);
+}
+
+#define DSJ(R) \
+{ \
+ if (--R##REG(DSTREG)) \
+ { \
+ PC += (PARAM_WORD_NO_INC()<<4)+0x10; \
+ COUNT_CYCLES(3); \
+ } \
+ else \
+ { \
+ SKIP_WORD; \
+ COUNT_CYCLES(2); \
+ } \
+}
+static void dsj_a (void) { DSJ(A); }
+static void dsj_b (void) { DSJ(B); }
+
+#define DSJEQ(R) \
+{ \
+ if (Z_FLAG) \
+ { \
+ if (--R##REG(DSTREG)) \
+ { \
+ PC += (PARAM_WORD_NO_INC()<<4)+0x10; \
+ COUNT_CYCLES(3); \
+ } \
+ else \
+ { \
+ SKIP_WORD; \
+ COUNT_CYCLES(2); \
+ } \
+ } \
+ else \
+ { \
+ SKIP_WORD; \
+ COUNT_CYCLES(2); \
+ } \
+}
+static void dsjeq_a (void) { DSJEQ(A); }
+static void dsjeq_b (void) { DSJEQ(B); }
+
+#define DSJNE(R) \
+{ \
+ if (!Z_FLAG) \
+ { \
+ if (--R##REG(DSTREG)) \
+ { \
+ PC += (PARAM_WORD_NO_INC()<<4)+0x10; \
+ COUNT_CYCLES(3); \
+ } \
+ else \
+ { \
+ SKIP_WORD; \
+ COUNT_CYCLES(2); \
+ } \
+ } \
+ else \
+ { \
+ SKIP_WORD; \
+ COUNT_CYCLES(2); \
+ } \
+}
+static void dsjne_a (void) { DSJNE(A); }
+static void dsjne_b (void) { DSJNE(B); }
+
+#define DSJS(R) \
+{ \
+ if (state.op & 0x0400) \
+ { \
+ if (--R##REG(DSTREG)) \
+ { \
+ PC -= ((PARAM_K)<<4); \
+ COUNT_CYCLES(2); \
+ } \
+ else \
+ COUNT_CYCLES(3); \
+ } \
+ else \
+ { \
+ if (--R##REG(DSTREG)) \
+ { \
+ PC += ((PARAM_K)<<4); \
+ COUNT_CYCLES(2); \
+ } \
+ else \
+ COUNT_CYCLES(3); \
+ } \
+}
+static void dsjs_a (void) { DSJS(A); }
+static void dsjs_b (void) { DSJS(B); }
+
+static void emu(void)
+{
+ /* in RUN state, this instruction is a NOP */
+ COUNT_CYCLES(6);
+}
+
+#define EXGPC(R) \
+{ \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 temppc = *rd; \
+ *rd = PC; \
+ PC = temppc; \
+ CORRECT_ODD_PC("EXGPC"); \
+ change_pc(TOBYTE(PC)); \
+ COUNT_CYCLES(2); \
+}
+static void exgpc_a (void) { EXGPC(A); }
+static void exgpc_b (void) { EXGPC(B); }
+
+#define GETPC(R) \
+{ \
+ R##REG(DSTREG) = PC; \
+ COUNT_CYCLES(1); \
+}
+static void getpc_a (void) { GETPC(A); }
+static void getpc_b (void) { GETPC(B); }
+
+#define GETST(R) \
+{ \
+ R##REG(DSTREG) = GET_ST(); \
+ COUNT_CYCLES(1); \
+}
+static void getst_a (void) { GETST(A); }
+static void getst_b (void) { GETST(B); }
+
+#define j_xx_8(TAKE) \
+{ \
+ if (DSTREG) \
+ { \
+ if (TAKE) \
+ { \
+ PC += (PARAM_REL8 << 4); \
+ COUNT_CYCLES(2); \
+ } \
+ else \
+ COUNT_CYCLES(1); \
+ } \
+ else \
+ { \
+ if (TAKE) \
+ { \
+ PC = PARAM_LONG_NO_INC(); \
+ CORRECT_ODD_PC("J_XX_8"); \
+ change_pc(TOBYTE(PC)); \
+ COUNT_CYCLES(3); \
+ } \
+ else \
+ { \
+ SKIP_LONG; \
+ COUNT_CYCLES(4); \
+ } \
+ } \
+}
+
+#define j_xx_0(TAKE) \
+{ \
+ if (DSTREG) \
+ { \
+ if (TAKE) \
+ { \
+ PC += (PARAM_REL8 << 4); \
+ COUNT_CYCLES(2); \
+ } \
+ else \
+ COUNT_CYCLES(1); \
+ } \
+ else \
+ { \
+ if (TAKE) \
+ { \
+ PC += (PARAM_WORD_NO_INC()<<4)+0x10; \
+ COUNT_CYCLES(3); \
+ } \
+ else \
+ { \
+ SKIP_WORD; \
+ COUNT_CYCLES(2); \
+ } \
+ } \
+}
+
+#define j_xx_x(TAKE) \
+{ \
+ if (TAKE) \
+ { \
+ PC += (PARAM_REL8 << 4); \
+ COUNT_CYCLES(2); \
+ } \
+ else \
+ COUNT_CYCLES(1); \
+}
+
+static void j_UC_0(void)
+{
+ j_xx_0(1);
+}
+static void j_UC_8(void)
+{
+ j_xx_8(1);
+}
+static void j_UC_x(void)
+{
+ j_xx_x(1);
+}
+static void j_P_0(void)
+{
+ j_xx_0(!N_FLAG && !Z_FLAG);
+}
+static void j_P_8(void)
+{
+ j_xx_8(!N_FLAG && !Z_FLAG);
+}
+static void j_P_x(void)
+{
+ j_xx_x(!N_FLAG && !Z_FLAG);
+}
+static void j_LS_0(void)
+{
+ j_xx_0(C_FLAG || Z_FLAG);
+}
+static void j_LS_8(void)
+{
+ j_xx_8(C_FLAG || Z_FLAG);
+}
+static void j_LS_x(void)
+{
+ j_xx_x(C_FLAG || Z_FLAG);
+}
+static void j_HI_0(void)
+{
+ j_xx_0(!C_FLAG && !Z_FLAG);
+}
+static void j_HI_8(void)
+{
+ j_xx_8(!C_FLAG && !Z_FLAG);
+}
+static void j_HI_x(void)
+{
+ j_xx_x(!C_FLAG && !Z_FLAG);
+}
+static void j_LT_0(void)
+{
+ j_xx_0((N_FLAG && !V_FLAG) || (!N_FLAG && V_FLAG));
+}
+static void j_LT_8(void)
+{
+ j_xx_8((N_FLAG && !V_FLAG) || (!N_FLAG && V_FLAG));
+}
+static void j_LT_x(void)
+{
+ j_xx_x((N_FLAG && !V_FLAG) || (!N_FLAG && V_FLAG));
+}
+static void j_GE_0(void)
+{
+ j_xx_0((N_FLAG && V_FLAG) || (!N_FLAG && !V_FLAG));
+}
+static void j_GE_8(void)
+{
+ j_xx_8((N_FLAG && V_FLAG) || (!N_FLAG && !V_FLAG));
+}
+static void j_GE_x(void)
+{
+ j_xx_x((N_FLAG && V_FLAG) || (!N_FLAG && !V_FLAG));
+}
+static void j_LE_0(void)
+{
+ j_xx_0((N_FLAG && !V_FLAG) || (!N_FLAG && V_FLAG) || Z_FLAG);
+}
+static void j_LE_8(void)
+{
+ j_xx_8((N_FLAG && !V_FLAG) || (!N_FLAG && V_FLAG) || Z_FLAG);
+}
+static void j_LE_x(void)
+{
+ j_xx_x((N_FLAG && !V_FLAG) || (!N_FLAG && V_FLAG) || Z_FLAG);
+}
+static void j_GT_0(void)
+{
+ j_xx_0((N_FLAG && V_FLAG && !Z_FLAG) || (!N_FLAG && !V_FLAG && !Z_FLAG));
+}
+static void j_GT_8(void)
+{
+ j_xx_8((N_FLAG && V_FLAG && !Z_FLAG) || (!N_FLAG && !V_FLAG && !Z_FLAG));
+}
+static void j_GT_x(void)
+{
+ j_xx_x((N_FLAG && V_FLAG && !Z_FLAG) || (!N_FLAG && !V_FLAG && !Z_FLAG));
+}
+static void j_C_0(void)
+{
+ j_xx_0(C_FLAG);
+}
+static void j_C_8(void)
+{
+ j_xx_8(C_FLAG);
+}
+static void j_C_x(void)
+{
+ j_xx_x(C_FLAG);
+}
+static void j_NC_0(void)
+{
+ j_xx_0(!C_FLAG);
+}
+static void j_NC_8(void)
+{
+ j_xx_8(!C_FLAG);
+}
+static void j_NC_x(void)
+{
+ j_xx_x(!C_FLAG);
+}
+static void j_EQ_0(void)
+{
+ j_xx_0(Z_FLAG);
+}
+static void j_EQ_8(void)
+{
+ j_xx_8(Z_FLAG);
+}
+static void j_EQ_x(void)
+{
+ j_xx_x(Z_FLAG);
+}
+static void j_NE_0(void)
+{
+ j_xx_0(!Z_FLAG);
+}
+static void j_NE_8(void)
+{
+ j_xx_8(!Z_FLAG);
+}
+static void j_NE_x(void)
+{
+ j_xx_x(!Z_FLAG);
+}
+static void j_V_0(void)
+{
+ j_xx_0(V_FLAG);
+}
+static void j_V_8(void)
+{
+ j_xx_8(V_FLAG);
+}
+static void j_V_x(void)
+{
+ j_xx_x(V_FLAG);
+}
+static void j_NV_0(void)
+{
+ j_xx_0(!V_FLAG);
+}
+static void j_NV_8(void)
+{
+ j_xx_8(!V_FLAG);
+}
+static void j_NV_x(void)
+{
+ j_xx_x(!V_FLAG);
+}
+static void j_N_0(void)
+{
+ j_xx_0(N_FLAG);
+}
+static void j_N_8(void)
+{
+ j_xx_8(N_FLAG);
+}
+static void j_N_x(void)
+{
+ j_xx_x(N_FLAG);
+}
+static void j_NN_0(void)
+{
+ j_xx_0(!N_FLAG);
+}
+static void j_NN_8(void)
+{
+ j_xx_8(!N_FLAG);
+}
+static void j_NN_x(void)
+{
+ j_xx_x(!N_FLAG);
+}
+
+#define JUMP(R) \
+{ \
+ PC = R##REG(DSTREG); \
+ CORRECT_ODD_PC("JUMP"); \
+ change_pc(TOBYTE(PC)); \
+ COUNT_CYCLES(2); \
+}
+static void jump_a (void) { JUMP(A); }
+static void jump_b (void) { JUMP(B); }
+
+static void popst(void)
+{
+ SET_ST(POP());
+ COUNT_CYCLES(8);
+}
+
+static void pushst(void)
+{
+ PUSH(GET_ST());
+ COUNT_CYCLES(2);
+}
+
+#define PUTST(R) \
+{ \
+ SET_ST(R##REG(DSTREG)); \
+ COUNT_CYCLES(3); \
+}
+static void putst_a (void) { PUTST(A); }
+static void putst_b (void) { PUTST(B); }
+
+static void reti(void)
+{
+ INT32 st = POP();
+ PC = POP();
+ CORRECT_ODD_PC("RETI");
+ change_pc(TOBYTE(PC));
+ SET_ST(st);
+ COUNT_CYCLES(11);
+}
+
+static void rets(void)
+{
+ UINT32 offs;
+ PC = POP();
+ CORRECT_ODD_PC("RETS");
+ change_pc(TOBYTE(PC));
+ offs = PARAM_N;
+ if (offs)
+ {
+ SP+=(offs<<4);
+ }
+ COUNT_CYCLES(7);
+}
+
+#define REV(R) \
+{ \
+ R##REG(DSTREG) = 0x0008; \
+ COUNT_CYCLES(1); \
+}
+static void rev_a (void) { REV(A); }
+static void rev_b (void) { REV(B); }
+
+static void trap(void)
+{
+ UINT32 t = PARAM_N;
+ if (t)
+ {
+ PUSH(PC);
+ PUSH(GET_ST());
+ }
+ RESET_ST();
+ PC = RLONG(0xffffffe0-(t<<5));
+ CORRECT_ODD_PC("TRAP");
+ change_pc(TOBYTE(PC));
+ COUNT_CYCLES(16);
+}
+
+
+
+/***************************************************************************
+ 34020 INSTRUCTIONS
+***************************************************************************/
+
+/************************************
+
+New 34020 ops:
+
+ 0000 1100 000R dddd = ADDXYI IL,Rd
+ iiii iiii iiii iiii
+ iiii iiii iiii iiii
+
+ 0000 0000 1111 00SD = BLMOVE S,D
+
+ 0000 0110 0000 0000 = CEXEC S,c,ID,L
+ cccc cccc S000 0000
+ iiic cccc cccc cccc
+
+ 1101 1000 0ccc cccS = CEXEC S,c,ID
+ iiic cccc cccc cccc
+
+ 0000 1000 1111 0010 = CLIP
+
+ 0000 0110 011R dddd = CMOVCG Rd1,Rd2,S,c,ID
+ cccc cccc S00R dddd
+ iiic cccc cccc cccc
+
+ 0000 0110 101R dddd = CMOVCM *Rd+,n,S,c,ID
+ cccc cccc S00n nnnn
+ iiic cccc cccc cccc
+
+ 0000 0110 110R dddd = CMOVCM -*Rd,n,S,c,ID
+ cccc cccc S00n nnnn
+ iiic cccc cccc cccc
+
+ 0000 0110 0110 0000 = CMOVCS c,ID
+ cccc cccc 0000 0001
+ iiic cccc cccc cccc
+
+ 0000 0110 001R ssss = CMOVGC Rs,c,ID
+ cccc cccc 0000 0000
+ iiic cccc cccc cccc
+
+ 0000 0110 010R ssss = CMOVGC Rs1,Rs2,S,c,ID
+ cccc cccc S00R ssss
+ iiic cccc cccc cccc
+
+ 0000 0110 100n nnnn = CMOVMC *Rs+,n,S,c,ID
+ cccc cccc S00R ssss
+ iiic cccc cccc cccc
+
+ 0000 1000 001n nnnn = CMOVMC -*Rs,n,S,c,ID
+ cccc cccc S00R ssss
+ iiic cccc cccc cccc
+
+ 0000 0110 111R dddd = CMOVMC *Rs+,Rd,S,c,ID
+ cccc cccc S00R ssss
+ iiic cccc cccc cccc
+
+ 0011 01kk kkkR dddd = CMPK k,Rd
+
+ 0000 1010 100R dddd = CVDXYL Rd
+
+ 0000 1010 011R dddd = CVMXYL Rd
+
+ 1110 101s sssR dddd = CVSXYL Rs,Rd
+
+ 0000 0010 101R dddd = EXGPS Rd
+
+ 1101 1110 Z001 1010 = FLINE Z
+
+ 0000 1010 1011 1011 = FPIXEQ
+
+ 0000 1010 1101 1011 = FPIXNE
+
+ 0000 0010 110R dddd = GETPS Rd
+
+ 0000 0000 0100 0000 = IDLE
+
+ 0000 1100 0101 0111 = LINIT
+
+ 0000 0000 1000 0000 = MWAIT
+
+ 0000 1010 0011 0111 = PFILL XY
+
+ 0000 1110 0001 0111 = PIXBLT L,M,L
+
+ 0000 1000 0110 0000 = RETM
+
+ 0111 101s sssR dddd = RMO Rs,Rd
+
+ 0000 0010 100R dddd = RPIX Rd
+
+ 0000 0010 0111 0011 = SETCDP
+
+ 0000 0010 1111 1011 = SETCMP
+
+ 0000 0010 0101 0001 = SETCSP
+
+ 0111 111s sssR dddd = SWAPF *Rs,Rd,0
+
+ 0000 1110 1111 1010 = TFILL XY
+
+ 0000 1000 0000 1111 = TRAPL
+
+ 0000 1000 0101 0111 = VBLT B,L
+
+ 0000 1010 0101 0111 = VFILL L
+
+ 0000 1010 0000 0000 = VLCOL
+
+************************************/
+
+
+#define ADD_XYI(R) \
+{ \
+ UINT32 a = PARAM_LONG(); \
+ XY *b = &R##REG_XY(DSTREG); \
+ CLR_NCZV; \
+ b->x += (INT16)(a & 0xffff); \
+ b->y += ((INT32)a >> 16); \
+ SET_N_LOG(b->x == 0); \
+ SET_C_BIT_LO(b->y, 15); \
+ SET_Z_LOG(b->y == 0); \
+ SET_V_BIT_LO(b->x, 15); \
+ COUNT_CYCLES(1); \
+}
+static void addxyi_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ ADD_XYI(A);
+}
+static void addxyi_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ ADD_XYI(B);
+}
+
+static void blmove(void)
+{
+ offs_t src = BREG(0);
+ offs_t dst = BREG(2);
+ offs_t bits = BREG(7);
+
+ if (!state.is_34020) { unimpl(); return; }
+
+ /* src and dst are aligned */
+ if (!(src & 0x0f) && !(dst & 0x0f))
+ {
+ while (bits >= 16 && tms34010_ICount > 0)
+ {
+ TMS34010_WRMEM_WORD(TOBYTE(dst), TMS34010_RDMEM_WORD(TOBYTE(src)));
+ src += 0x10;
+ dst += 0x10;
+ bits -= 0x10;
+ tms34010_ICount -= 2;
+ }
+ if (bits != 0 && tms34010_ICount > 0)
+ {
+ (*tms34010_wfield_functions[bits])(dst, (*tms34010_rfield_functions[bits])(src));
+ dst += bits;
+ src += bits;
+ bits = 0;
+ tms34010_ICount -= 2;
+ }
+ }
+
+ /* src is aligned, dst is not */
+ else if (!(src & 0x0f))
+ {
+ logerror("020:BLMOVE with aligned src and unaligned dst\n");
+ }
+
+ /* dst is aligned, src is not */
+ else if (!(dst & 0x0f))
+ {
+ logerror("020:BLMOVE with unaligned src and aligned dst\n");
+ }
+
+ /* neither are aligned */
+ else
+ {
+ logerror("020:BLMOVE with completely unaligned src and dst\n");
+ }
+
+ /* update the final results */
+ BREG(0) = src;
+ BREG(2) = dst;
+ BREG(7) = bits;
+
+ /* if we're not done yet, back up the PC */
+ if (bits != 0)
+ PC -= 0x10;
+}
+
+static void cexec_l(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cexec_l\n");
+}
+
+static void cexec_s(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cexec_s\n");
+}
+
+static void clip(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:clip\n");
+}
+
+static void cmovcg_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovcg_a\n");
+}
+
+static void cmovcg_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovcg_b\n");
+}
+
+static void cmovcm_f(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovcm_f\n");
+}
+
+static void cmovcm_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovcm_b\n");
+}
+
+static void cmovgc_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovgc_a\n");
+}
+
+static void cmovgc_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovgc_b\n");
+}
+
+static void cmovgc_a_s(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovgc_a_s\n");
+}
+
+static void cmovgc_b_s(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovgc_b_s\n");
+}
+
+static void cmovmc_f(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovmc_f\n");
+}
+
+static void cmovmc_f_va(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovmc_f_va\n");
+}
+
+static void cmovmc_f_vb(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovmc_f_vb\n");
+}
+
+static void cmovmc_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cmovmc_b\n");
+}
+
+#define CMPK(R) \
+{ \
+ INT32 r; \
+ INT32 *rd = &R##REG(DSTREG); \
+ INT32 t = PARAM_K; if (!t) t = 32; \
+ CLR_NCZV; \
+ r = *rd - t; \
+ SET_NZCV_SUB(*rd,t,r); \
+ COUNT_CYCLES(1); \
+}
+static void cmp_k_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ CMPK(A);
+}
+static void cmp_k_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ CMPK(B);
+}
+
+static void cvdxyl_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cvdxyl_a\n");
+}
+
+static void cvdxyl_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cvdxyl_b\n");
+}
+
+static void cvmxyl_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cvmxyl_a\n");
+}
+
+static void cvmxyl_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cvmxyl_b\n");
+}
+
+static void cvsxyl_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cvsxyl_a\n");
+}
+
+static void cvsxyl_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:cvsxyl_b\n");
+}
+
+static void exgps_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:exgps_a\n");
+}
+
+static void exgps_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:exgps_b\n");
+}
+
+static void fline(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:fline\n");
+}
+
+static void fpixeq(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:fpixeq\n");
+}
+
+static void fpixne(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:fpixne\n");
+}
+
+static void getps_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:getps_a\n");
+}
+
+static void getps_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:getps_b\n");
+}
+
+static void idle(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:idle\n");
+}
+
+static void linit(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:linit\n");
+}
+
+static void mwait(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+}
+
+static void pfill_xy(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:pfill_xy\n");
+}
+
+static void pixblt_l_m_l(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:pixblt_l_m_l\n");
+}
+
+static void retm(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:retm\n");
+}
+
+#define RMO(R) \
+{ \
+ UINT32 res = 0; \
+ UINT32 rs = R##REG(SRCREG); \
+ INT32 *rd = &R##REG(DSTREG); \
+ CLR_Z; \
+ SET_Z_VAL(rs); \
+ if (rs) \
+ { \
+ while (!(rs & 0x00000001)) \
+ { \
+ res++; \
+ rs >>= 1; \
+ } \
+ } \
+ *rd = res; \
+ COUNT_CYCLES(1); \
+}
+
+static void rmo_a(void) { RMO(A); }
+static void rmo_b(void) { RMO(B); }
+
+#define RPIX(R) \
+{ \
+ UINT32 v = R##REG(DSTREG); \
+ switch (state.pixelshift) \
+ { \
+ case 1: \
+ v = (v & 1) ? 0xffffffff : 0x00000000;\
+ COUNT_CYCLES(8); \
+ break; \
+ case 2: \
+ v &= 3; \
+ v |= v << 2; \
+ v |= v << 4; \
+ v |= v << 8; \
+ v |= v << 16; \
+ COUNT_CYCLES(7); \
+ break; \
+ case 4: \
+ v &= 0x0f; \
+ v |= v << 4; \
+ v |= v << 8; \
+ v |= v << 16; \
+ COUNT_CYCLES(6); \
+ break; \
+ case 8: \
+ v &= 0xff; \
+ v |= v << 8; \
+ v |= v << 16; \
+ COUNT_CYCLES(5); \
+ break; \
+ case 16: \
+ v &= 0xffff; \
+ v |= v << 16; \
+ COUNT_CYCLES(4); \
+ break; \
+ case 32: \
+ COUNT_CYCLES(2); \
+ break; \
+ } \
+ R##REG(DSTREG) = v; \
+}
+
+static void rpix_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ RPIX(A);
+}
+
+static void rpix_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ RPIX(B);
+}
+
+static void setcdp(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:setcdp\n");
+}
+
+static void setcmp(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:setcmp\n");
+}
+
+static void setcsp(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:setcsp\n");
+}
+
+static void swapf_a(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:swapf_a\n");
+}
+
+static void swapf_b(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:swapf_b\n");
+}
+
+static void tfill_xy(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:tfill_xy\n");
+}
+
+static void trapl(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:trapl\n");
+}
+
+static void vblt_b_l(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:vblt_b_l\n");
+}
+
+static void vfill_l(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:vfill_l\n");
+}
+
+static void vlcol(void)
+{
+ if (!state.is_34020) { unimpl(); return; }
+ logerror("020:vlcol\n");
+}
diff --git a/src/emu/cpu/tms34010/34010ops.h b/src/emu/cpu/tms34010/34010ops.h
new file mode 100644
index 00000000000..2d8c3e13eb0
--- /dev/null
+++ b/src/emu/cpu/tms34010/34010ops.h
@@ -0,0 +1,279 @@
+/***************************************************************************
+
+ TMS34010: Portable Texas Instruments TMS34010 emulator
+
+ Copyright (C) Alex Pasadyn/Zsolt Vasvari 1998
+ Parts based on code by Aaron Giles
+
+***************************************************************************/
+
+#ifndef _34010OPS_H
+#define _34010OPS_H
+
+#include "cpuintrf.h"
+
+#ifndef INLINE
+#define INLINE static inline
+#endif
+
+/* Size of the memory buffer allocated for the shiftr register */
+#define SHIFTREG_SIZE (8 * 512 * sizeof(UINT16))
+
+
+
+/***************************************************************************
+ MEMORY I/O MACROS
+***************************************************************************/
+
+#define TMS34010_RDMEM(A) ((unsigned)program_read_byte_16le (A))
+#define TMS34010_RDMEM_WORD(A) ((unsigned)program_read_word_16le (A))
+INLINE UINT32 TMS34010_RDMEM_DWORD(offs_t A)
+{
+ UINT32 result = program_read_word_16le(A);
+ return result | (program_read_word_16le(A+2)<<16);
+}
+
+#define TMS34010_WRMEM(A,V) (program_write_byte_16le(A,V))
+#define TMS34010_WRMEM_WORD(A,V) (program_write_word_16le(A,V))
+INLINE void TMS34010_WRMEM_DWORD(offs_t A,UINT32 V)
+{
+ program_write_word_16le(A,V);
+ program_write_word_16le(A+2,V>>16);
+}
+
+
+
+/***************************************************************************
+ INTERNAL I/O CONSTANTS
+***************************************************************************/
+
+enum
+{
+ REG_HESYNC = 0,
+ REG_HEBLNK,
+ REG_HSBLNK,
+ REG_HTOTAL,
+ REG_VESYNC,
+ REG_VEBLNK,
+ REG_VSBLNK,
+ REG_VTOTAL,
+ REG_DPYCTL,
+ REG_DPYSTRT,
+ REG_DPYINT,
+ REG_CONTROL,
+ REG_HSTDATA,
+ REG_HSTADRL,
+ REG_HSTADRH,
+ REG_HSTCTLL,
+
+ REG_HSTCTLH,
+ REG_INTENB,
+ REG_INTPEND,
+ REG_CONVSP,
+ REG_CONVDP,
+ REG_PSIZE,
+ REG_PMASK,
+ REG_UNK23,
+ REG_UNK24,
+ REG_UNK25,
+ REG_UNK26,
+ REG_DPYTAP,
+ REG_HCOUNT,
+ REG_VCOUNT,
+ REG_DPYADR,
+ REG_REFCNT
+};
+
+enum
+{
+ REG020_VESYNC,
+ REG020_HESYNC,
+ REG020_VEBLNK,
+ REG020_HEBLNK,
+ REG020_VSBLNK,
+ REG020_HSBLNK,
+ REG020_VTOTAL,
+ REG020_HTOTAL,
+ REG020_DPYCTL, /* matches 010 */
+ REG020_DPYSTRT, /* matches 010 */
+ REG020_DPYINT, /* matches 010 */
+ REG020_CONTROL, /* matches 010 */
+ REG020_HSTDATA, /* matches 010 */
+ REG020_HSTADRL, /* matches 010 */
+ REG020_HSTADRH, /* matches 010 */
+ REG020_HSTCTLL, /* matches 010 */
+
+ REG020_HSTCTLH, /* matches 010 */
+ REG020_INTENB, /* matches 010 */
+ REG020_INTPEND, /* matches 010 */
+ REG020_CONVSP, /* matches 010 */
+ REG020_CONVDP, /* matches 010 */
+ REG020_PSIZE, /* matches 010 */
+ REG020_PMASKL,
+ REG020_PMASKH,
+ REG020_CONVMP,
+ REG020_CONTROL2,
+ REG020_CONFIG,
+ REG020_DPYTAP, /* matches 010 */
+ REG020_VCOUNT,
+ REG020_HCOUNT,
+ REG020_DPYADR, /* matches 010 */
+ REG020_REFADR,
+
+ REG020_DPYSTL,
+ REG020_DPYSTH,
+ REG020_DPYNXL,
+ REG020_DPYNXH,
+ REG020_DINCL,
+ REG020_DINCH,
+ REG020_RES0,
+ REG020_HESERR,
+ REG020_RES1,
+ REG020_RES2,
+ REG020_RES3,
+ REG020_RES4,
+ REG020_SCOUNT,
+ REG020_BSFLTST,
+ REG020_DPYMSK,
+ REG020_RES5,
+
+ REG020_SETVCNT,
+ REG020_SETHCNT,
+ REG020_BSFLTDL,
+ REG020_BSFLTDH,
+ REG020_RES6,
+ REG020_RES7,
+ REG020_RES8,
+ REG020_RES9,
+ REG020_IHOST1L,
+ REG020_IHOST1H,
+ REG020_IHOST2L,
+ REG020_IHOST2H,
+ REG020_IHOST3L,
+ REG020_IHOST3H,
+ REG020_IHOST4L,
+ REG020_IHOST4H
+};
+
+/* Interrupts that are generated by the processor internally */
+#define TMS34010_INT1 0x0002 /* External Interrupt 1 */
+#define TMS34010_INT2 0x0004 /* External Interrupt 2 */
+#define TMS34010_HI 0x0200 /* Host Interrupt */
+#define TMS34010_DI 0x0400 /* Display Interrupt */
+#define TMS34010_WV 0x0800 /* Window Violation Interrupt */
+
+/* IO registers accessor */
+#define IOREG(reg) (state.IOregs[reg])
+#define SMART_IOREG(reg) (state.IOregs[state.is_34020 ? REG020_##reg : REG_##reg])
+#define PBH (IOREG(REG_CONTROL) & 0x0100)
+#define PBV (IOREG(REG_CONTROL) & 0x0200)
+
+
+
+/***************************************************************************
+ FIELD WRITE MACROS
+***************************************************************************/
+
+#define WFIELDMAC(MASK,MAX) \
+ UINT32 shift = offset & 0x0f; \
+ UINT32 masked_data = data & (MASK); \
+ UINT32 old; \
+ \
+ offset = TOBYTE(offset & 0xfffffff0); \
+ \
+ if (shift >= MAX) \
+ { \
+ old = (UINT32)TMS34010_RDMEM_DWORD(offset) & ~((MASK) << shift); \
+ TMS34010_WRMEM_DWORD(offset, (masked_data << shift) | old); \
+ } \
+ else \
+ { \
+ old = (UINT32)TMS34010_RDMEM_WORD(offset) & ~((MASK) << shift); \
+ TMS34010_WRMEM_WORD(offset, ((masked_data & (MASK)) << shift) | old); \
+ } \
+
+#define WFIELDMAC_BIG(MASK,MAX) \
+ UINT32 shift = offset & 0x0f; \
+ UINT32 masked_data = data & (MASK); \
+ UINT32 old; \
+ \
+ offset = TOBYTE(offset & 0xfffffff0); \
+ \
+ old = (UINT32)TMS34010_RDMEM_DWORD(offset) & ~(UINT32)((MASK) << shift); \
+ TMS34010_WRMEM_DWORD(offset, (UINT32)(masked_data << shift) | old); \
+ if (shift >= MAX) \
+ { \
+ shift = 32 - shift; \
+ old = (UINT32)TMS34010_RDMEM_WORD(offset + 4) & ~((MASK) >> shift); \
+ TMS34010_WRMEM_WORD(offset, (masked_data >> shift) | old); \
+ } \
+
+#define WFIELDMAC_8 \
+ if (offset & 0x07) \
+ { \
+ WFIELDMAC(0xff,9); \
+ } \
+ else \
+ TMS34010_WRMEM(TOBYTE(offset), data); \
+
+#define RFIELDMAC_8 \
+ if (offset & 0x07) \
+ { \
+ RFIELDMAC(0xff,9); \
+ } \
+ else \
+ return TMS34010_RDMEM(TOBYTE(offset)); \
+
+#define WFIELDMAC_32 \
+ if (offset & 0x0f) \
+ { \
+ UINT32 shift = offset&0x0f; \
+ UINT32 old; \
+ UINT32 hiword; \
+ offset &= 0xfffffff0; \
+ old = ((UINT32) TMS34010_RDMEM_DWORD (TOBYTE(offset ))&(0xffffffff>>(0x20-shift))); \
+ hiword = ((UINT32) TMS34010_RDMEM_DWORD (TOBYTE(offset+0x20))&(0xffffffff<<shift)); \
+ TMS34010_WRMEM_DWORD(TOBYTE(offset ),(data<< shift) |old); \
+ TMS34010_WRMEM_DWORD(TOBYTE(offset+0x20),(data>>(0x20-shift))|hiword); \
+ } \
+ else \
+ TMS34010_WRMEM_DWORD(TOBYTE(offset),data); \
+
+
+
+/***************************************************************************
+ FIELD READ MACROS
+***************************************************************************/
+
+#define RFIELDMAC(MASK,MAX) \
+ UINT32 shift = offset & 0x0f; \
+ offset = TOBYTE(offset & 0xfffffff0); \
+ \
+ if (shift >= MAX) \
+ ret = (TMS34010_RDMEM_DWORD(offset) >> shift) & (MASK); \
+ else \
+ ret = (TMS34010_RDMEM_WORD(offset) >> shift) & (MASK); \
+
+#define RFIELDMAC_BIG(MASK,MAX) \
+ UINT32 shift = offset & 0x0f; \
+ offset = TOBYTE(offset & 0xfffffff0); \
+ \
+ ret = (UINT32)TMS34010_RDMEM_DWORD(offset) >> shift; \
+ if (shift >= MAX) \
+ ret |= (TMS34010_RDMEM_WORD(offset + 4) << (32 - shift)); \
+ ret &= MASK; \
+
+#define RFIELDMAC_32 \
+ if (offset&0x0f) \
+ { \
+ UINT32 shift = offset&0x0f; \
+ offset &= 0xfffffff0; \
+ return (((UINT32)TMS34010_RDMEM_DWORD (TOBYTE(offset ))>> shift) | \
+ (TMS34010_RDMEM_DWORD (TOBYTE(offset+0x20))<<(0x20-shift)));\
+ } \
+ else \
+ return TMS34010_RDMEM_DWORD(TOBYTE(offset)); \
+
+
+
+#endif /* _34010OPS_H */
diff --git a/src/emu/cpu/tms34010/34010tbl.c b/src/emu/cpu/tms34010/34010tbl.c
new file mode 100644
index 00000000000..2e08b9ca29c
--- /dev/null
+++ b/src/emu/cpu/tms34010/34010tbl.c
@@ -0,0 +1,1167 @@
+/*** TMS34010: Portable TMS34010 emulator ***********************************
+
+ Copyright (C) Alex Pasadyn/Zsolt Vasvari 1998
+
+ Opcode Table
+
+*****************************************************************************/
+
+static void unimpl(void);
+
+/* Graphics Instructions */
+
+static void pixblt_l_l(void); /* 0f00 */
+static void pixblt_l_xy(void); /* 0f20 */
+static void pixblt_xy_l(void); /* 0f40 */
+static void pixblt_xy_xy(void); /* 0f60 */
+static void pixblt_b_l(void); /* 0f80 */
+static void pixblt_b_xy(void); /* 0fa0 */
+static void fill_l(void); /* 0fc0 */
+static void fill_xy(void); /* 0fe0 */
+static void line(void); /* df10/df90 */
+static void add_xy_a(void); /* e000/e100 */
+static void add_xy_b(void); /* e000/e100 */
+static void sub_xy_a(void); /* e200/e300 */
+static void sub_xy_b(void); /* e200/e300 */
+static void cmp_xy_a(void); /* e400/e500 */
+static void cmp_xy_b(void); /* e400/e500 */
+static void cpw_a(void); /* e600/e700 */
+static void cpw_b(void); /* e600/e700 */
+static void cvxyl_a(void); /* e800/e900 */
+static void cvxyl_b(void); /* e800/e900 */
+static void movx_a(void); /* ec00/ed00 */
+static void movx_b(void); /* ec00/ed00 */
+static void movy_a(void); /* ee00/ef00 */
+static void movy_b(void); /* ee00/ef00 */
+static void pixt_ri_a(void); /* f800/f900 */
+static void pixt_ri_b(void); /* f800/f900 */
+static void pixt_rixy_a(void); /* f000/f100 */
+static void pixt_rixy_b(void); /* f000/f100 */
+static void pixt_ir_a(void); /* fa00/fb00 */
+static void pixt_ir_b(void); /* fa00/fb00 */
+static void pixt_ii_a(void); /* fc00/fd00 */
+static void pixt_ii_b(void); /* fc00/fd00 */
+static void pixt_ixyr_a(void); /* f200/f300 */
+static void pixt_ixyr_b(void); /* f200/f300 */
+static void pixt_ixyixy_a(void); /* f400/f500 */
+static void pixt_ixyixy_b(void); /* f400/f500 */
+static void drav_a(void); /* f600/f700 */
+static void drav_b(void); /* f600/f700 */
+
+/* General Instructions */
+static void abs_a(void); /* 0380 */
+static void abs_b(void); /* 0390 */
+static void add_a(void); /* 4000/4100 */
+static void add_b(void); /* 4000/4100 */
+static void addc_a(void); /* 4200/4200 */
+static void addc_b(void); /* 4200/4200 */
+static void addi_w_a(void); /* 0b00 */
+static void addi_w_b(void); /* 0b10 */
+static void addi_l_a(void); /* 0b20 */
+static void addi_l_b(void); /* 0b30 */
+static void addk_a(void); /* 1000-1300 */
+static void addk_b(void); /* 1000-1300 */
+static void and_a(void); /* 5000/5100 */
+static void and_b(void); /* 5000/5100 */
+static void andi_a(void); /* 0b80 */
+static void andi_b(void); /* 0b90 */
+static void andn_a(void); /* 5200-5300 */
+static void andn_b(void); /* 5200-5300 */
+static void btst_k_a(void); /* 1c00-1f00 */
+static void btst_k_b(void); /* 1c00-1f00 */
+static void btst_r_a(void); /* 4a00-4b00 */
+static void btst_r_b(void); /* 4a00-4b00 */
+static void clrc(void); /* 0320 */
+static void cmp_a(void); /* 4800/4900 */
+static void cmp_b(void); /* 4800/4900 */
+static void cmpi_w_a(void); /* 0b40 */
+static void cmpi_w_b(void); /* 0b50 */
+static void cmpi_l_a(void); /* 0b60 */
+static void cmpi_l_b(void); /* 0b70 */
+static void dint(void);
+static void divs_a(void); /* 5800/5900 */
+static void divs_b(void); /* 5800/5900 */
+static void divu_a(void); /* 5a00/5b00 */
+static void divu_b(void); /* 5a00/5b00 */
+static void eint(void);
+static void exgf0_a(void); /* d500 */
+static void exgf0_b(void); /* d510 */
+static void exgf1_a(void); /* d700 */
+static void exgf1_b(void); /* d710 */
+static void lmo_a(void); /* 6a00/6b00 */
+static void lmo_b(void); /* 6a00/6b00 */
+static void mmfm_a(void); /* 09a0 */
+static void mmfm_b(void); /* 09b0 */
+static void mmtm_a(void); /* 0980 */
+static void mmtm_b(void); /* 0990 */
+static void mods_a(void); /* 6c00/6d00 */
+static void mods_b(void); /* 6c00/6d00 */
+static void modu_a(void); /* 6e00/6f00 */
+static void modu_b(void); /* 6e00/6f00 */
+static void mpys_a(void); /* 5c00/5d00 */
+static void mpys_b(void); /* 5c00/5d00 */
+static void mpyu_a(void); /* 5e00/5e00 */
+static void mpyu_b(void); /* 5e00/5f00 */
+static void neg_a(void); /* 03a0 */
+static void neg_b(void); /* 03b0 */
+static void negb_a(void); /* 03c0 */
+static void negb_b(void); /* 03d0 */
+static void nop(void); /* 0300 */
+static void not_a(void); /* 03e0 */
+static void not_b(void); /* 03f0 */
+static void or_a(void); /* 5400-5500 */
+static void or_b(void); /* 5400-5500 */
+static void ori_a(void); /* 0ba0 */
+static void ori_b(void); /* 0bb0 */
+static void rl_k_a(void); /* 3000-3300 */
+static void rl_k_b(void); /* 3000-3300 */
+static void rl_r_a(void); /* 6800/6900 */
+static void rl_r_b(void); /* 6800/6900 */
+static void setc(void); /* 0de0 */
+static void setf0(void);
+static void setf1(void);
+static void sext0_a(void); /* 0500 */
+static void sext0_b(void); /* 0510 */
+static void sext1_a(void); /* 0700 */
+static void sext1_b(void); /* 0710 */
+static void sla_k_a(void); /* 2000-2300 */
+static void sla_k_b(void); /* 2000-2300 */
+static void sla_r_a(void); /* 6000/6100 */
+static void sla_r_b(void); /* 6000/6100 */
+static void sll_k_a(void); /* 2400-2700 */
+static void sll_k_b(void); /* 2400-2700 */
+static void sll_r_a(void); /* 6200/6300 */
+static void sll_r_b(void); /* 6200/6300 */
+static void sra_k_a(void); /* 2800-2b00 */
+static void sra_k_b(void); /* 2800-2b00 */
+static void sra_r_a(void); /* 6400/6500 */
+static void sra_r_b(void); /* 6400/6500 */
+static void srl_k_a(void); /* 2c00-2f00 */
+static void srl_k_b(void); /* 2c00-2f00 */
+static void srl_r_a(void); /* 6600/6700 */
+static void srl_r_b(void); /* 6600/6700 */
+static void sub_a(void); /* 4400/4500 */
+static void sub_b(void); /* 4400/4500 */
+static void subb_a(void); /* 4600/4700 */
+static void subb_b(void); /* 4600/4700 */
+static void subi_w_a(void); /* 0be0 */
+static void subi_w_b(void); /* 0bf0 */
+static void subi_l_a(void); /* 0d00 */
+static void subi_l_b(void); /* 0d10 */
+static void subk_a(void); /* 1400-1700 */
+static void subk_b(void); /* 1400-1700 */
+static void xor_a(void); /* 5600-5700 */
+static void xor_b(void); /* 5600-5700 */
+static void xori_a(void); /* 0bc0 */
+static void xori_b(void); /* 0bd0 */
+static void zext0_a(void); /* 0520 */
+static void zext0_b(void); /* 0530 */
+static void zext1_a(void); /* 0720 */
+static void zext1_b(void); /* 0720 */
+
+
+/* Move Instructions */
+static void movi_w_a(void);
+static void movi_w_b(void);
+static void movi_l_a(void);
+static void movi_l_b(void);
+static void movk_a(void);
+static void movk_b(void);
+static void movb_rn_a(void); /* 8c00-8d00 */
+static void movb_rn_b(void); /* 8c00-8d00 */
+static void movb_nr_a(void); /* 8e00-8f00 */
+static void movb_nr_b(void); /* 8e00-8f00 */
+static void movb_nn_a(void); /* 9c00-9d00 */
+static void movb_nn_b(void); /* 9c00-9d00 */
+static void movb_r_no_a(void); /* ac00-ad00 */
+static void movb_r_no_b(void); /* ac00-ad00 */
+static void movb_no_r_a(void); /* ae00-af00 */
+static void movb_no_r_b(void); /* ae00-af00 */
+static void movb_no_no_a(void); /* bc00-bd00 */
+static void movb_no_no_b(void); /* bc00-bd00 */
+static void movb_ra_a(void);
+static void movb_ra_b(void);
+static void movb_ar_a(void);
+static void movb_ar_b(void);
+static void movb_aa(void);
+static void move_rr_a(void); /* 4c00/d00 */
+static void move_rr_b(void); /* 4c00/d00 */
+static void move_rr_ax(void); /* 4e00/f00 */
+static void move_rr_bx(void); /* 4e00/f00 */
+static void move0_rn_a(void); /* 8000 */
+static void move0_rn_b(void);
+static void move1_rn_a(void);
+static void move1_rn_b(void);
+static void move0_r_dn_a(void); /* a000 */
+static void move0_r_dn_b(void);
+static void move1_r_dn_a(void);
+static void move1_r_dn_b(void);
+static void move0_r_ni_a(void); /* 9000 */
+static void move0_r_ni_b(void);
+static void move1_r_ni_a(void);
+static void move1_r_ni_b(void);
+static void move0_nr_a(void); /* 8400-500 */
+static void move0_nr_b(void); /* 8400-500 */
+static void move1_nr_a(void); /* 8600-700 */
+static void move1_nr_b(void); /* 8600-700 */
+static void move0_dn_r_a(void); /* A400-500 */
+static void move0_dn_r_b(void); /* A400-500 */
+static void move1_dn_r_a(void); /* A600-700 */
+static void move1_dn_r_b(void); /* A600-700 */
+static void move0_ni_r_a(void); /* 9400-500 */
+static void move0_ni_r_b(void); /* 9400-500 */
+static void move1_ni_r_a(void); /* 9600-700 */
+static void move1_ni_r_b(void); /* 9600-700 */
+static void move0_nn_a(void); /* 8800 */
+static void move0_nn_b(void);
+static void move1_nn_a(void);
+static void move1_nn_b(void);
+static void move0_dn_dn_a(void); /* a800 */
+static void move0_dn_dn_b(void);
+static void move1_dn_dn_a(void);
+static void move1_dn_dn_b(void);
+static void move0_ni_ni_a(void); /* 9800 */
+static void move0_ni_ni_b(void);
+static void move1_ni_ni_a(void);
+static void move1_ni_ni_b(void);
+static void move0_r_no_a(void); /* b000 */
+static void move0_r_no_b(void);
+static void move1_r_no_a(void);
+static void move1_r_no_b(void);
+static void move0_no_r_a(void); /* b400 */
+static void move0_no_r_b(void);
+static void move1_no_r_a(void);
+static void move1_no_r_b(void);
+static void move0_no_ni_a(void); /* d000 */
+static void move0_no_ni_b(void);
+static void move1_no_ni_a(void);
+static void move1_no_ni_b(void);
+static void move0_no_no_a(void); /* b800 */
+static void move0_no_no_b(void);
+static void move1_no_no_a(void);
+static void move1_no_no_b(void);
+static void move0_ra_a(void);
+static void move0_ra_b(void);
+static void move1_ra_a(void);
+static void move1_ra_b(void);
+static void move0_ar_a(void);
+static void move0_ar_b(void);
+static void move1_ar_a(void);
+static void move1_ar_b(void);
+static void move0_a_ni_a(void); /* d400 */
+static void move0_a_ni_b(void); /* d410 */
+static void move1_a_ni_a(void); /* d600 */
+static void move1_a_ni_b(void); /* d610 */
+static void move0_aa(void); /* 05c0 */
+static void move1_aa(void); /* 07c0 */
+
+
+/* Program Control and Context Switching */
+static void call_a(void); /* 0920 */
+static void call_b(void); /* 0930 */
+static void callr(void); /* 0d3f */
+static void calla(void); /* 0d5f */
+static void dsj_a(void); /* 0d80 */
+static void dsj_b(void); /* 0d90 */
+static void dsjeq_a(void); /* 0da0 */
+static void dsjeq_b(void); /* 0db0 */
+static void dsjne_a(void); /* 0dc0 */
+static void dsjne_b(void); /* 0dd0 */
+static void dsjs_a(void);
+static void dsjs_b(void);
+static void emu(void); /* 0100 */
+static void exgpc_a(void); /* 0120 */
+static void exgpc_b(void); /* 0130 */
+static void getpc_a(void); /* 0140 */
+static void getpc_b(void); /* 0150 */
+static void getst_a(void); /* 0180 */
+static void getst_b(void); /* 0190 */
+static void j_UC_0(void);
+static void j_UC_8(void);
+static void j_UC_x(void);
+static void j_P_0(void);
+static void j_P_8(void);
+static void j_P_x(void);
+static void j_LS_0(void);
+static void j_LS_8(void);
+static void j_LS_x(void);
+static void j_HI_0(void);
+static void j_HI_8(void);
+static void j_HI_x(void);
+static void j_LT_0(void);
+static void j_LT_8(void);
+static void j_LT_x(void);
+static void j_GE_0(void);
+static void j_GE_8(void);
+static void j_GE_x(void);
+static void j_LE_0(void);
+static void j_LE_8(void);
+static void j_LE_x(void);
+static void j_GT_0(void);
+static void j_GT_8(void);
+static void j_GT_x(void);
+static void j_C_0(void);
+static void j_C_8(void);
+static void j_C_x(void);
+static void j_NC_0(void);
+static void j_NC_8(void);
+static void j_NC_x(void);
+static void j_EQ_0(void);
+static void j_EQ_8(void);
+static void j_EQ_x(void);
+static void j_NE_0(void);
+static void j_NE_8(void);
+static void j_NE_x(void);
+static void j_V_0(void);
+static void j_V_8(void);
+static void j_V_x(void);
+static void j_NV_0(void);
+static void j_NV_8(void);
+static void j_NV_x(void);
+static void j_N_0(void);
+static void j_N_8(void);
+static void j_N_x(void);
+static void j_NN_0(void);
+static void j_NN_8(void);
+static void j_NN_x(void);
+static void jump_a(void); /* 0160 */
+static void jump_b(void); /* 0170 */
+static void popst(void); /* 01c0 */
+static void pushst(void); /* 01e0 */
+static void putst_a(void); /* 01a0 */
+static void putst_b(void); /* 01b0 */
+static void reti(void); /* 0940 */
+static void rets(void); /* 0960/70 */
+static void rev_a(void); /* 0020 */
+static void rev_b(void); /* 0030 */
+static void trap(void); /* 0900/10 */
+
+
+/* 34020 instructions */
+static void addxyi_a(void);
+static void addxyi_b(void);
+static void blmove(void);
+static void cexec_l(void);
+static void cexec_s(void);
+static void clip(void);
+static void cmovcg_a(void);
+static void cmovcg_b(void);
+static void cmovcm_f(void);
+static void cmovcm_b(void);
+static void cmovgc_a(void);
+static void cmovgc_b(void);
+static void cmovgc_a_s(void);
+static void cmovgc_b_s(void);
+static void cmovmc_f(void);
+static void cmovmc_f_va(void);
+static void cmovmc_f_vb(void);
+static void cmovmc_b(void);
+static void cmp_k_a(void);
+static void cmp_k_b(void);
+static void cvdxyl_a(void);
+static void cvdxyl_b(void);
+static void cvmxyl_a(void);
+static void cvmxyl_b(void);
+static void cvsxyl_a(void);
+static void cvsxyl_b(void);
+static void exgps_a(void);
+static void exgps_b(void);
+static void fline(void);
+static void fpixeq(void);
+static void fpixne(void);
+static void getps_a(void);
+static void getps_b(void);
+static void idle(void);
+static void linit(void);
+static void mwait(void);
+static void pfill_xy(void);
+static void pixblt_l_m_l(void);
+static void retm(void);
+static void rmo_a(void);
+static void rmo_b(void);
+static void rpix_a(void);
+static void rpix_b(void);
+static void setcdp(void);
+static void setcmp(void);
+static void setcsp(void);
+static void swapf_a(void);
+static void swapf_b(void);
+static void tfill_xy(void);
+static void trapl(void);
+static void vblt_b_l(void);
+static void vfill_l(void);
+static void vlcol(void);
+
+
+/* Opcode Table */
+static void (*opcode_table[65536 >> 4])(void) =
+{
+ /* 0x0000 0x0010 0x0020 0x0030 ... 0x00f0 */
+ unimpl, unimpl, rev_a, rev_b, idle, unimpl, unimpl, unimpl,
+ mwait, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, blmove,
+ /* 0x0100 */
+ emu, unimpl, exgpc_a, exgpc_b, getpc_a, getpc_b, jump_a, jump_b,
+ getst_a, getst_b, putst_a, putst_b, popst, unimpl, pushst, unimpl,
+ /* 0x0200 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, setcsp, unimpl, setcdp,
+ rpix_a, rpix_b, exgps_a, exgps_b, getps_a, getps_b, unimpl, setcmp,
+ /* 0x0300 */
+ nop, unimpl, clrc, unimpl, movb_aa, unimpl, dint, unimpl,
+ abs_a, abs_b, neg_a, neg_b, negb_a, negb_b, not_a, not_b,
+ /* 0x0400 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x0500 */
+ sext0_a, sext0_b, zext0_a, zext0_b, setf0, setf0, setf0, setf0,
+ move0_ra_a, move0_ra_b, move0_ar_a, move0_ar_b, move0_aa, unimpl, movb_ra_a, movb_ra_b,
+ /* 0x0600 */
+ cexec_l, unimpl, cmovgc_a, cmovgc_b, cmovgc_a_s, cmovgc_b_s, cmovcg_a, cmovcg_b,
+ cmovmc_f, cmovmc_f, cmovcm_f, cmovcm_f, cmovcm_b, cmovcm_b, cmovmc_f_va,cmovmc_f_vb,
+ /* 0x0700 */
+ sext1_a, sext1_b, zext1_a, zext1_b, setf1, setf1, setf1, setf1,
+ move1_ra_a, move1_ra_b, move1_ar_a, move1_ar_b, move1_aa, unimpl, movb_ar_a, movb_ar_b,
+ /* 0x0800 */
+ trapl, unimpl, cmovmc_b, cmovmc_b, unimpl, vblt_b_l, retm, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, clip,
+ /* 0x0900 */
+ trap, trap, call_a, call_b, reti, unimpl, rets, rets,
+ mmtm_a, mmtm_b, mmfm_a, mmfm_b, movi_w_a, movi_w_b, movi_l_a, movi_l_b,
+ /* 0x0a00 */
+ vlcol, unimpl, unimpl, pfill_xy, unimpl, vfill_l, cvmxyl_a, cvmxyl_b,
+ cvdxyl_a, cvdxyl_b, unimpl, fpixeq, unimpl, fpixne, unimpl, unimpl,
+ /* 0x0b00 */
+ addi_w_a, addi_w_b, addi_l_a, addi_l_b, cmpi_w_a, cmpi_w_b, cmpi_l_a, cmpi_l_b,
+ andi_a, andi_b, ori_a, ori_b, xori_a, xori_b, subi_w_a, subi_w_b,
+ /* 0x0c00 */
+ addxyi_a, addxyi_b, unimpl, unimpl, unimpl, linit, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x0d00 */
+ subi_l_a, subi_l_b, unimpl, callr, unimpl, calla, eint, unimpl,
+ dsj_a, dsj_b, dsjeq_a, dsjeq_b, dsjne_a, dsjne_b, setc, unimpl,
+ /* 0x0e00 */
+ unimpl, pixblt_l_m_l,unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, tfill_xy,
+ /* 0x0f00 */
+ pixblt_l_l, unimpl, pixblt_l_xy,unimpl, pixblt_xy_l,unimpl, pixblt_xy_xy,unimpl,
+ pixblt_b_l, unimpl, pixblt_b_xy,unimpl, fill_l, unimpl, fill_xy, unimpl,
+ /* 0x1000 */
+ addk_a, addk_b, addk_a, addk_b, addk_a, addk_b, addk_a, addk_b,
+ addk_a, addk_b, addk_a, addk_b, addk_a, addk_b, addk_a, addk_b,
+ /* 0x1100 */
+ addk_a, addk_b, addk_a, addk_b, addk_a, addk_b, addk_a, addk_b,
+ addk_a, addk_b, addk_a, addk_b, addk_a, addk_b, addk_a, addk_b,
+ /* 0x1200 */
+ addk_a, addk_b, addk_a, addk_b, addk_a, addk_b, addk_a, addk_b,
+ addk_a, addk_b, addk_a, addk_b, addk_a, addk_b, addk_a, addk_b,
+ /* 0x1300 */
+ addk_a, addk_b, addk_a, addk_b, addk_a, addk_b, addk_a, addk_b,
+ addk_a, addk_b, addk_a, addk_b, addk_a, addk_b, addk_a, addk_b,
+ /* 0x1400 */
+ subk_a, subk_b, subk_a, subk_b, subk_a, subk_b, subk_a, subk_b,
+ subk_a, subk_b, subk_a, subk_b, subk_a, subk_b, subk_a, subk_b,
+ /* 0x1500 */
+ subk_a, subk_b, subk_a, subk_b, subk_a, subk_b, subk_a, subk_b,
+ subk_a, subk_b, subk_a, subk_b, subk_a, subk_b, subk_a, subk_b,
+ /* 0x1600 */
+ subk_a, subk_b, subk_a, subk_b, subk_a, subk_b, subk_a, subk_b,
+ subk_a, subk_b, subk_a, subk_b, subk_a, subk_b, subk_a, subk_b,
+ /* 0x1700 */
+ subk_a, subk_b, subk_a, subk_b, subk_a, subk_b, subk_a, subk_b,
+ subk_a, subk_b, subk_a, subk_b, subk_a, subk_b, subk_a, subk_b,
+ /* 0x1800 */
+ movk_a, movk_b, movk_a, movk_b, movk_a, movk_b, movk_a, movk_b,
+ movk_a, movk_b, movk_a, movk_b, movk_a, movk_b, movk_a, movk_b,
+ /* 0x1900 */
+ movk_a, movk_b, movk_a, movk_b, movk_a, movk_b, movk_a, movk_b,
+ movk_a, movk_b, movk_a, movk_b, movk_a, movk_b, movk_a, movk_b,
+ /* 0x1a00 */
+ movk_a, movk_b, movk_a, movk_b, movk_a, movk_b, movk_a, movk_b,
+ movk_a, movk_b, movk_a, movk_b, movk_a, movk_b, movk_a, movk_b,
+ /* 0x1b00 */
+ movk_a, movk_b, movk_a, movk_b, movk_a, movk_b, movk_a, movk_b,
+ movk_a, movk_b, movk_a, movk_b, movk_a, movk_b, movk_a, movk_b,
+ /* 0x1c00 */
+ btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b,
+ btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b,
+ /* 0x1d00 */
+ btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b,
+ btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b,
+ /* 0x1e00 */
+ btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b,
+ btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b,
+ /* 0x1f00 */
+ btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b,
+ btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b, btst_k_a, btst_k_b,
+ /* 0x2000 */
+ sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b,
+ sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b,
+ /* 0x2100 */
+ sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b,
+ sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b,
+ /* 0x2200 */
+ sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b,
+ sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b,
+ /* 0x2300 */
+ sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b,
+ sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b, sla_k_a, sla_k_b,
+ /* 0x2400 */
+ sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b,
+ sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b,
+ /* 0x2500 */
+ sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b,
+ sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b,
+ /* 0x2600 */
+ sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b,
+ sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b,
+ /* 0x2700 */
+ sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b,
+ sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b, sll_k_a, sll_k_b,
+ /* 0x2800 */
+ sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b,
+ sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b,
+ /* 0x2900 */
+ sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b,
+ sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b,
+ /* 0x2a00 */
+ sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b,
+ sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b,
+ /* 0x2b00 */
+ sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b,
+ sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b, sra_k_a, sra_k_b,
+ /* 0x2c00 */
+ srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b,
+ srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b,
+ /* 0x2d00 */
+ srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b,
+ srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b,
+ /* 0x2e00 */
+ srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b,
+ srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b,
+ /* 0x2f00 */
+ srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b,
+ srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b, srl_k_a, srl_k_b,
+ /* 0x3000 */
+ rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b,
+ rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b,
+ /* 0x3100 */
+ rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b,
+ rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b,
+ /* 0x3200 */
+ rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b,
+ rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b,
+ /* 0x3300 */
+ rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b,
+ rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b, rl_k_a, rl_k_b,
+ /* 0x3400 */
+ cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b,
+ cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b,
+ /* 0x3500 */
+ cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b,
+ cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b,
+ /* 0x3600 */
+ cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b,
+ cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b,
+ /* 0x3700 */
+ cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b,
+ cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b, cmp_k_a, cmp_k_b,
+ /* 0x3800 */
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ /* 0x3900 */
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ /* 0x3a00 */
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ /* 0x3b00 */
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ /* 0x3c00 */
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ /* 0x3d00 */
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ /* 0x3e00 */
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ /* 0x3f00 */
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b, dsjs_a, dsjs_b,
+ /* 0x4000 */
+ add_a, add_b, add_a, add_b, add_a, add_b, add_a, add_b,
+ add_a, add_b, add_a, add_b, add_a, add_b, add_a, add_b,
+ /* 0x4100 */
+ add_a, add_b, add_a, add_b, add_a, add_b, add_a, add_b,
+ add_a, add_b, add_a, add_b, add_a, add_b, add_a, add_b,
+ /* 0x4200 */
+ addc_a, addc_b, addc_a, addc_b, addc_a, addc_b, addc_a, addc_b,
+ addc_a, addc_b, addc_a, addc_b, addc_a, addc_b, addc_a, addc_b,
+ /* 0x4300 */
+ addc_a, addc_b, addc_a, addc_b, addc_a, addc_b, addc_a, addc_b,
+ addc_a, addc_b, addc_a, addc_b, addc_a, addc_b, addc_a, addc_b,
+ /* 0x4400 */
+ sub_a, sub_b, sub_a, sub_b, sub_a, sub_b, sub_a, sub_b,
+ sub_a, sub_b, sub_a, sub_b, sub_a, sub_b, sub_a, sub_b,
+ /* 0x4500 */
+ sub_a, sub_b, sub_a, sub_b, sub_a, sub_b, sub_a, sub_b,
+ sub_a, sub_b, sub_a, sub_b, sub_a, sub_b, sub_a, sub_b,
+ /* 0x4600 */
+ subb_a, subb_b, subb_a, subb_b, subb_a, subb_b, subb_a, subb_b,
+ subb_a, subb_b, subb_a, subb_b, subb_a, subb_b, subb_a, subb_b,
+ /* 0x4700 */
+ subb_a, subb_b, subb_a, subb_b, subb_a, subb_b, subb_a, subb_b,
+ subb_a, subb_b, subb_a, subb_b, subb_a, subb_b, subb_a, subb_b,
+ /* 0x4800 */
+ cmp_a, cmp_b, cmp_a, cmp_b, cmp_a, cmp_b, cmp_a, cmp_b,
+ cmp_a, cmp_b, cmp_a, cmp_b, cmp_a, cmp_b, cmp_a, cmp_b,
+ /* 0x4900 */
+ cmp_a, cmp_b, cmp_a, cmp_b, cmp_a, cmp_b, cmp_a, cmp_b,
+ cmp_a, cmp_b, cmp_a, cmp_b, cmp_a, cmp_b, cmp_a, cmp_b,
+ /* 0x4a00 */
+ btst_r_a, btst_r_b, btst_r_a, btst_r_b, btst_r_a, btst_r_b, btst_r_a, btst_r_b,
+ btst_r_a, btst_r_b, btst_r_a, btst_r_b, btst_r_a, btst_r_b, btst_r_a, btst_r_b,
+ /* 0x4b00 */
+ btst_r_a, btst_r_b, btst_r_a, btst_r_b, btst_r_a, btst_r_b, btst_r_a, btst_r_b,
+ btst_r_a, btst_r_b, btst_r_a, btst_r_b, btst_r_a, btst_r_b, btst_r_a, btst_r_b,
+ /* 0x4c00 */
+ move_rr_a, move_rr_b, move_rr_a, move_rr_b, move_rr_a, move_rr_b, move_rr_a, move_rr_b,
+ move_rr_a, move_rr_b, move_rr_a, move_rr_b, move_rr_a, move_rr_b, move_rr_a, move_rr_b,
+ /* 0x4d00 */
+ move_rr_a, move_rr_b, move_rr_a, move_rr_b, move_rr_a, move_rr_b, move_rr_a, move_rr_b,
+ move_rr_a, move_rr_b, move_rr_a, move_rr_b, move_rr_a, move_rr_b, move_rr_a, move_rr_b,
+ /* 0x4e00 */
+ move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx,
+ move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx,
+ /* 0x4f00 */
+ move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx,
+ move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx, move_rr_ax, move_rr_bx,
+ /* 0x5000 */
+ and_a, and_b, and_a, and_b, and_a, and_b, and_a, and_b,
+ and_a, and_b, and_a, and_b, and_a, and_b, and_a, and_b,
+ /* 0x5100 */
+ and_a, and_b, and_a, and_b, and_a, and_b, and_a, and_b,
+ and_a, and_b, and_a, and_b, and_a, and_b, and_a, and_b,
+ /* 0x5200 */
+ andn_a, andn_b, andn_a, andn_b, andn_a, andn_b, andn_a, andn_b,
+ andn_a, andn_b, andn_a, andn_b, andn_a, andn_b, andn_a, andn_b,
+ /* 0x5300 */
+ andn_a, andn_b, andn_a, andn_b, andn_a, andn_b, andn_a, andn_b,
+ andn_a, andn_b, andn_a, andn_b, andn_a, andn_b, andn_a, andn_b,
+ /* 0x5400 */
+ or_a, or_b, or_a, or_b, or_a, or_b, or_a, or_b,
+ or_a, or_b, or_a, or_b, or_a, or_b, or_a, or_b,
+ /* 0x5500 */
+ or_a, or_b, or_a, or_b, or_a, or_b, or_a, or_b,
+ or_a, or_b, or_a, or_b, or_a, or_b, or_a, or_b,
+ /* 0x5600 */
+ xor_a, xor_b, xor_a, xor_b, xor_a, xor_b, xor_a, xor_b,
+ xor_a, xor_b, xor_a, xor_b, xor_a, xor_b, xor_a, xor_b,
+ /* 0x5700 */
+ xor_a, xor_b, xor_a, xor_b, xor_a, xor_b, xor_a, xor_b,
+ xor_a, xor_b, xor_a, xor_b, xor_a, xor_b, xor_a, xor_b,
+ /* 0x5800 */
+ divs_a, divs_b, divs_a, divs_b, divs_a, divs_b, divs_a, divs_b,
+ divs_a, divs_b, divs_a, divs_b, divs_a, divs_b, divs_a, divs_b,
+ /* 0x5900 */
+ divs_a, divs_b, divs_a, divs_b, divs_a, divs_b, divs_a, divs_b,
+ divs_a, divs_b, divs_a, divs_b, divs_a, divs_b, divs_a, divs_b,
+ /* 0x5a00 */
+ divu_a, divu_b, divu_a, divu_b, divu_a, divu_b, divu_a, divu_b,
+ divu_a, divu_b, divu_a, divu_b, divu_a, divu_b, divu_a, divu_b,
+ /* 0x5b00 */
+ divu_a, divu_b, divu_a, divu_b, divu_a, divu_b, divu_a, divu_b,
+ divu_a, divu_b, divu_a, divu_b, divu_a, divu_b, divu_a, divu_b,
+ /* 0x5c00 */
+ mpys_a, mpys_b, mpys_a, mpys_b, mpys_a, mpys_b, mpys_a, mpys_b,
+ mpys_a, mpys_b, mpys_a, mpys_b, mpys_a, mpys_b, mpys_a, mpys_b,
+ /* 0x5d00 */
+ mpys_a, mpys_b, mpys_a, mpys_b, mpys_a, mpys_b, mpys_a, mpys_b,
+ mpys_a, mpys_b, mpys_a, mpys_b, mpys_a, mpys_b, mpys_a, mpys_b,
+ /* 0x5e00 */
+ mpyu_a, mpyu_b, mpyu_a, mpyu_b, mpyu_a, mpyu_b, mpyu_a, mpyu_b,
+ mpyu_a, mpyu_b, mpyu_a, mpyu_b, mpyu_a, mpyu_b, mpyu_a, mpyu_b,
+ /* 0x5f00 */
+ mpyu_a, mpyu_b, mpyu_a, mpyu_b, mpyu_a, mpyu_b, mpyu_a, mpyu_b,
+ mpyu_a, mpyu_b, mpyu_a, mpyu_b, mpyu_a, mpyu_b, mpyu_a, mpyu_b,
+ /* 0x6000 */
+ sla_r_a, sla_r_b, sla_r_a, sla_r_b, sla_r_a, sla_r_b, sla_r_a, sla_r_b,
+ sla_r_a, sla_r_b, sla_r_a, sla_r_b, sla_r_a, sla_r_b, sla_r_a, sla_r_b,
+ /* 0x6100 */
+ sla_r_a, sla_r_b, sla_r_a, sla_r_b, sla_r_a, sla_r_b, sla_r_a, sla_r_b,
+ sla_r_a, sla_r_b, sla_r_a, sla_r_b, sla_r_a, sla_r_b, sla_r_a, sla_r_b,
+ /* 0x6200 */
+ sll_r_a, sll_r_b, sll_r_a, sll_r_b, sll_r_a, sll_r_b, sll_r_a, sll_r_b,
+ sll_r_a, sll_r_b, sll_r_a, sll_r_b, sll_r_a, sll_r_b, sll_r_a, sll_r_b,
+ /* 0x6300 */
+ sll_r_a, sll_r_b, sll_r_a, sll_r_b, sll_r_a, sll_r_b, sll_r_a, sll_r_b,
+ sll_r_a, sll_r_b, sll_r_a, sll_r_b, sll_r_a, sll_r_b, sll_r_a, sll_r_b,
+ /* 0x6400 */
+ sra_r_a, sra_r_b, sra_r_a, sra_r_b, sra_r_a, sra_r_b, sra_r_a, sra_r_b,
+ sra_r_a, sra_r_b, sra_r_a, sra_r_b, sra_r_a, sra_r_b, sra_r_a, sra_r_b,
+ /* 0x6500 */
+ sra_r_a, sra_r_b, sra_r_a, sra_r_b, sra_r_a, sra_r_b, sra_r_a, sra_r_b,
+ sra_r_a, sra_r_b, sra_r_a, sra_r_b, sra_r_a, sra_r_b, sra_r_a, sra_r_b,
+ /* 0x6600 */
+ srl_r_a, srl_r_b, srl_r_a, srl_r_b, srl_r_a, srl_r_b, srl_r_a, srl_r_b,
+ srl_r_a, srl_r_b, srl_r_a, srl_r_b, srl_r_a, srl_r_b, srl_r_a, srl_r_b,
+ /* 0x6700 */
+ srl_r_a, srl_r_b, srl_r_a, srl_r_b, srl_r_a, srl_r_b, srl_r_a, srl_r_b,
+ srl_r_a, srl_r_b, srl_r_a, srl_r_b, srl_r_a, srl_r_b, srl_r_a, srl_r_b,
+ /* 0x6800 */
+ rl_r_a, rl_r_b, rl_r_a, rl_r_b, rl_r_a, rl_r_b, rl_r_a, rl_r_b,
+ rl_r_a, rl_r_b, rl_r_a, rl_r_b, rl_r_a, rl_r_b, rl_r_a, rl_r_b,
+ /* 0x6900 */
+ rl_r_a, rl_r_b, rl_r_a, rl_r_b, rl_r_a, rl_r_b, rl_r_a, rl_r_b,
+ rl_r_a, rl_r_b, rl_r_a, rl_r_b, rl_r_a, rl_r_b, rl_r_a, rl_r_b,
+ /* 0x6a00 */
+ lmo_a, lmo_b, lmo_a, lmo_b, lmo_a, lmo_b, lmo_a, lmo_b,
+ lmo_a, lmo_b, lmo_a, lmo_b, lmo_a, lmo_b, lmo_a, lmo_b,
+ /* 0x6b00 */
+ lmo_a, lmo_b, lmo_a, lmo_b, lmo_a, lmo_b, lmo_a, lmo_b,
+ lmo_a, lmo_b, lmo_a, lmo_b, lmo_a, lmo_b, lmo_a, lmo_b,
+ /* 0x6c00 */
+ mods_a, mods_b, mods_a, mods_b, mods_a, mods_b, mods_a, mods_b,
+ mods_a, mods_b, mods_a, mods_b, mods_a, mods_b, mods_a, mods_b,
+ /* 0x6d00 */
+ mods_a, mods_b, mods_a, mods_b, mods_a, mods_b, mods_a, mods_b,
+ mods_a, mods_b, mods_a, mods_b, mods_a, mods_b, mods_a, mods_b,
+ /* 0x6e00 */
+ modu_a, modu_b, modu_a, modu_b, modu_a, modu_b, modu_a, modu_b,
+ modu_a, modu_b, modu_a, modu_b, modu_a, modu_b, modu_a, modu_b,
+ /* 0x6f00 */
+ modu_a, modu_b, modu_a, modu_b, modu_a, modu_b, modu_a, modu_b,
+ modu_a, modu_b, modu_a, modu_b, modu_a, modu_b, modu_a, modu_b,
+ /* 0x7000 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7100 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7200 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7300 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7400 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7500 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7600 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7700 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7800 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7900 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7a00 */
+ rmo_a, rmo_b, rmo_a, rmo_b, rmo_a, rmo_b, rmo_a, rmo_b,
+ rmo_a, rmo_b, rmo_a, rmo_b, rmo_a, rmo_b, rmo_a, rmo_b,
+ /* 0x7b00 */
+ rmo_a, rmo_b, rmo_a, rmo_b, rmo_a, rmo_b, rmo_a, rmo_b,
+ rmo_a, rmo_b, rmo_a, rmo_b, rmo_a, rmo_b, rmo_a, rmo_b,
+ /* 0x7c00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7d00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x7e00 */
+ swapf_a, swapf_b, swapf_a, swapf_b, swapf_a, swapf_b, swapf_a, swapf_b,
+ swapf_a, swapf_b, swapf_a, swapf_b, swapf_a, swapf_b, swapf_a, swapf_b,
+ /* 0x7f00 */
+ swapf_a, swapf_b, swapf_a, swapf_b, swapf_a, swapf_b, swapf_a, swapf_b,
+ swapf_a, swapf_b, swapf_a, swapf_b, swapf_a, swapf_b, swapf_a, swapf_b,
+ /* 0x8000 */
+ move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b,
+ move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b,
+ /* 0x8100 */
+ move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b,
+ move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b, move0_rn_a, move0_rn_b,
+ /* 0x8200 */
+ move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b,
+ move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b,
+ /* 0x8300 */
+ move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b,
+ move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b, move1_rn_a, move1_rn_b,
+ /* 0x8400 */
+ move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b,
+ move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b,
+ /* 0x8500 */
+ move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b,
+ move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b, move0_nr_a, move0_nr_b,
+ /* 0x8600 */
+ move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b,
+ move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b,
+ /* 0x8700 */
+ move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b,
+ move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b, move1_nr_a, move1_nr_b,
+ /* 0x8800 */
+ move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b,
+ move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b,
+ /* 0x8900 */
+ move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b,
+ move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b, move0_nn_a, move0_nn_b,
+ /* 0x8a00 */
+ move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b,
+ move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b,
+ /* 0x8b00 */
+ move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b,
+ move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b, move1_nn_a, move1_nn_b,
+ /* 0x8c00 */
+ movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b,
+ movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b,
+ /* 0x8d00 */
+ movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b,
+ movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b, movb_rn_a, movb_rn_b,
+ /* 0x8e00 */
+ movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b,
+ movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b,
+ /* 0x8f00 */
+ movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b,
+ movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b, movb_nr_a, movb_nr_b,
+ /* 0x9000 */
+ move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b,
+ move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b,
+ /* 0x9100 */
+ move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b,
+ move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b, move0_r_ni_a, move0_r_ni_b,
+ /* 0x9200 */
+ move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b,
+ move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b,
+ /* 0x9300 */
+ move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b,
+ move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b, move1_r_ni_a, move1_r_ni_b,
+ /* 0x9400 */
+ move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b,
+ move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b,
+ /* 0x9500 */
+ move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b,
+ move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b, move0_ni_r_a, move0_ni_r_b,
+ /* 0x9600 */
+ move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b,
+ move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b,
+ /* 0x9700 */
+ move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b,
+ move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b, move1_ni_r_a, move1_ni_r_b,
+ /* 0x9800 */
+ move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b,
+ move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b,
+ /* 0x9900 */
+ move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b,
+ move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b, move0_ni_ni_a, move0_ni_ni_b,
+ /* 0x9a00 */
+ move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b,
+ move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b,
+ /* 0x9b00 */
+ move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b,
+ move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b, move1_ni_ni_a, move1_ni_ni_b,
+ /* 0x9c00 */
+ movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b,
+ movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b,
+ /* 0x9d00 */
+ movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b,
+ movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b, movb_nn_a, movb_nn_b,
+ /* 0x9e00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0x9f00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xa000 */
+ move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b,
+ move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b,
+ /* 0xa100 */
+ move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b,
+ move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b, move0_r_dn_a, move0_r_dn_b,
+ /* 0xa200 */
+ move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b,
+ move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b,
+ /* 0xa300 */
+ move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b,
+ move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b, move1_r_dn_a, move1_r_dn_b,
+ /* 0xa400 */
+ move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b,
+ move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b,
+ /* 0xa500 */
+ move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b,
+ move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b, move0_dn_r_a, move0_dn_r_b,
+ /* 0xa600 */
+ move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b,
+ move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b,
+ /* 0xa700 */
+ move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b,
+ move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b, move1_dn_r_a, move1_dn_r_b,
+ /* 0xa800 */
+ move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b,
+ move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b,
+ /* 0xa900 */
+ move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b,
+ move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b, move0_dn_dn_a, move0_dn_dn_b,
+ /* 0xaa00 */
+ move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b,
+ move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b,
+ /* 0xab00 */
+ move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b,
+ move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b, move1_dn_dn_a, move1_dn_dn_b,
+ /* 0xac00 */
+ movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b,
+ movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b,
+ /* 0xad00 */
+ movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b,
+ movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b, movb_r_no_a, movb_r_no_b,
+ /* 0xae00 */
+ movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b,
+ movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b,
+ /* 0xaf00 */
+ movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b,
+ movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b, movb_no_r_a, movb_no_r_b,
+ /* 0xb000 */
+ move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b,
+ move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b,
+ /* 0xb100 */
+ move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b,
+ move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b, move0_r_no_a, move0_r_no_b,
+ /* 0xb200 */
+ move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b,
+ move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b,
+ /* 0xb300 */
+ move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b,
+ move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b, move1_r_no_a, move1_r_no_b,
+ /* 0xb400 */
+ move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b,
+ move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b,
+ /* 0xb500 */
+ move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b,
+ move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b, move0_no_r_a, move0_no_r_b,
+ /* 0xb600 */
+ move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b,
+ move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b,
+ /* 0xb700 */
+ move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b,
+ move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b, move1_no_r_a, move1_no_r_b,
+ /* 0xb800 */
+ move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b,
+ move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b,
+ /* 0xb900 */
+ move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b,
+ move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b, move0_no_no_a, move0_no_no_b,
+ /* 0xba00 */
+ move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b,
+ move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b,
+ /* 0xbb00 */
+ move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b,
+ move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b, move1_no_no_a, move1_no_no_b,
+ /* 0xbc00 */
+ movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b,
+ movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b,
+ /* 0xbd00 */
+ movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b,
+ movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b, movb_no_no_a, movb_no_no_b,
+ /* 0xbe00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xbf00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xc000 */
+ j_UC_0, j_UC_x, j_UC_x, j_UC_x, j_UC_x, j_UC_x, j_UC_x, j_UC_x,
+ j_UC_8, j_UC_x, j_UC_x, j_UC_x, j_UC_x, j_UC_x, j_UC_x, j_UC_x,
+ /* 0xc100 */
+ j_P_0, j_P_x, j_P_x, j_P_x, j_P_x, j_P_x, j_P_x, j_P_x,
+ j_P_8, j_P_x, j_P_x, j_P_x, j_P_x, j_P_x, j_P_x, j_P_x,
+ /* 0xc200 */
+ j_LS_0, j_LS_x, j_LS_x, j_LS_x, j_LS_x, j_LS_x, j_LS_x, j_LS_x,
+ j_LS_8, j_LS_x, j_LS_x, j_LS_x, j_LS_x, j_LS_x, j_LS_x, j_LS_x,
+ /* 0xc300 */
+ j_HI_0, j_HI_x, j_HI_x, j_HI_x, j_HI_x, j_HI_x, j_HI_x, j_HI_x,
+ j_HI_8, j_HI_x, j_HI_x, j_HI_x, j_HI_x, j_HI_x, j_HI_x, j_HI_x,
+ /* 0xc400 */
+ j_LT_0, j_LT_x, j_LT_x, j_LT_x, j_LT_x, j_LT_x, j_LT_x, j_LT_x,
+ j_LT_8, j_LT_x, j_LT_x, j_LT_x, j_LT_x, j_LT_x, j_LT_x, j_LT_x,
+ /* 0xc500 */
+ j_GE_0, j_GE_x, j_GE_x, j_GE_x, j_GE_x, j_GE_x, j_GE_x, j_GE_x,
+ j_GE_8, j_GE_x, j_GE_x, j_GE_x, j_GE_x, j_GE_x, j_GE_x, j_GE_x,
+ /* 0xc600 */
+ j_LE_0, j_LE_x, j_LE_x, j_LE_x, j_LE_x, j_LE_x, j_LE_x, j_LE_x,
+ j_LE_8, j_LE_x, j_LE_x, j_LE_x, j_LE_x, j_LE_x, j_LE_x, j_LE_x,
+ /* 0xc700 */
+ j_GT_0, j_GT_x, j_GT_x, j_GT_x, j_GT_x, j_GT_x, j_GT_x, j_GT_x,
+ j_GT_8, j_GT_x, j_GT_x, j_GT_x, j_GT_x, j_GT_x, j_GT_x, j_GT_x,
+ /* 0xc800 */
+ j_C_0, j_C_x, j_C_x, j_C_x, j_C_x, j_C_x, j_C_x, j_C_x,
+ j_C_8, j_C_x, j_C_x, j_C_x, j_C_x, j_C_x, j_C_x, j_C_x,
+ /* 0xc900 */
+ j_NC_0, j_NC_x, j_NC_x, j_NC_x, j_NC_x, j_NC_x, j_NC_x, j_NC_x,
+ j_NC_8, j_NC_x, j_NC_x, j_NC_x, j_NC_x, j_NC_x, j_NC_x, j_NC_x,
+ /* 0xca00 */
+ j_EQ_0, j_EQ_x, j_EQ_x, j_EQ_x, j_EQ_x, j_EQ_x, j_EQ_x, j_EQ_x,
+ j_EQ_8, j_EQ_x, j_EQ_x, j_EQ_x, j_EQ_x, j_EQ_x, j_EQ_x, j_EQ_x,
+ /* 0xcb00 */
+ j_NE_0, j_NE_x, j_NE_x, j_NE_x, j_NE_x, j_NE_x, j_NE_x, j_NE_x,
+ j_NE_8, j_NE_x, j_NE_x, j_NE_x, j_NE_x, j_NE_x, j_NE_x, j_NE_x,
+ /* 0xcc00 */
+ j_V_0, j_V_x, j_V_x, j_V_x, j_V_x, j_V_x, j_V_x, j_V_x,
+ j_V_8, j_V_x, j_V_x, j_V_x, j_V_x, j_V_x, j_V_x, j_V_x,
+ /* 0xcd00 */
+ j_NV_0, j_NV_x, j_NV_x, j_NV_x, j_NV_x, j_NV_x, j_NV_x, j_NV_x,
+ j_NV_8, j_NV_x, j_NV_x, j_NV_x, j_NV_x, j_NV_x, j_NV_x, j_NV_x,
+ /* 0xce00 */
+ j_N_0, j_N_x, j_N_x, j_N_x, j_N_x, j_N_x, j_N_x, j_N_x,
+ j_N_8, j_N_x, j_N_x, j_N_x, j_N_x, j_N_x, j_N_x, j_N_x,
+ /* 0xcf00 */
+ j_NN_0, j_NN_x, j_NN_x, j_NN_x, j_NN_x, j_NN_x, j_NN_x, j_NN_x,
+ j_NN_8, j_NN_x, j_NN_x, j_NN_x, j_NN_x, j_NN_x, j_NN_x, j_NN_x,
+ /* 0xd000 */
+ move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b,
+ move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b,
+ /* 0xd100 */
+ move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b,
+ move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b, move0_no_ni_a, move0_no_ni_b,
+ /* 0xd200 */
+ move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b,
+ move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b,
+ /* 0xd300 */
+ move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b,
+ move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b, move1_no_ni_a, move1_no_ni_b,
+ /* 0xd400 */
+ move0_a_ni_a,move0_a_ni_b,unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xd500 */
+ exgf0_a, exgf0_b, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xd600 */
+ move1_a_ni_a,move1_a_ni_b,unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xd700 */
+ exgf1_a, exgf1_b, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xd800 */
+ cexec_s, cexec_s, cexec_s, cexec_s, cexec_s, cexec_s, cexec_s, cexec_s,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xd900 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xda00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xdb00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xdc00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xdd00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xde00 */
+ unimpl, fline, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, fline, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xdf00 */
+ unimpl, line, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, line, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xe000 */
+ add_xy_a, add_xy_b, add_xy_a, add_xy_b, add_xy_a, add_xy_b, add_xy_a, add_xy_b,
+ add_xy_a, add_xy_b, add_xy_a, add_xy_b, add_xy_a, add_xy_b, add_xy_a, add_xy_b,
+ /* 0xe100 */
+ add_xy_a, add_xy_b, add_xy_a, add_xy_b, add_xy_a, add_xy_b, add_xy_a, add_xy_b,
+ add_xy_a, add_xy_b, add_xy_a, add_xy_b, add_xy_a, add_xy_b, add_xy_a, add_xy_b,
+ /* 0xe200 */
+ sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b,
+ sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b,
+ /* 0xe300 */
+ sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b,
+ sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b, sub_xy_a, sub_xy_b,
+ /* 0xe400 */
+ cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b,
+ cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b,
+ /* 0xe500 */
+ cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b,
+ cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b, cmp_xy_a, cmp_xy_b,
+ /* 0xe600 */
+ cpw_a, cpw_b, cpw_a, cpw_b, cpw_a, cpw_b, cpw_a, cpw_b,
+ cpw_a, cpw_b, cpw_a, cpw_b, cpw_a, cpw_b, cpw_a, cpw_b,
+ /* 0xe700 */
+ cpw_a, cpw_b, cpw_a, cpw_b, cpw_a, cpw_b, cpw_a, cpw_b,
+ cpw_a, cpw_b, cpw_a, cpw_b, cpw_a, cpw_b, cpw_a, cpw_b,
+ /* 0xe800 */
+ cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b,
+ cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b,
+ /* 0xe900 */
+ cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b,
+ cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b, cvxyl_a, cvxyl_b,
+ /* 0xea00 */
+ cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b,
+ cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b,
+ /* 0xeb00 */
+ cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b,
+ cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b, cvsxyl_a, cvsxyl_b,
+ /* 0xec00 */
+ movx_a, movx_b, movx_a, movx_b, movx_a, movx_b, movx_a, movx_b,
+ movx_a, movx_b, movx_a, movx_b, movx_a, movx_b, movx_a, movx_b,
+ /* 0xed00 */
+ movx_a, movx_b, movx_a, movx_b, movx_a, movx_b, movx_a, movx_b,
+ movx_a, movx_b, movx_a, movx_b, movx_a, movx_b, movx_a, movx_b,
+ /* 0xee00 */
+ movy_a, movy_b, movy_a, movy_b, movy_a, movy_b, movy_a, movy_b,
+ movy_a, movy_b, movy_a, movy_b, movy_a, movy_b, movy_a, movy_b,
+ /* 0xef00 */
+ movy_a, movy_b, movy_a, movy_b, movy_a, movy_b, movy_a, movy_b,
+ movy_a, movy_b, movy_a, movy_b, movy_a, movy_b, movy_a, movy_b,
+ /* 0xf000 */
+ pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b,
+ pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b,
+ /* 0xf100 */
+ pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b,
+ pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b, pixt_rixy_a, pixt_rixy_b,
+ /* 0xf200 */
+ pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b,
+ pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b,
+ /* 0xf300 */
+ pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b,
+ pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b, pixt_ixyr_a, pixt_ixyr_b,
+ /* 0xf400 */
+ pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b,
+ pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b,
+ /* 0xf500 */
+ pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b,
+ pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b, pixt_ixyixy_a, pixt_ixyixy_b,
+ /* 0xf600 */
+ drav_a, drav_b, drav_a, drav_b, drav_a, drav_b, drav_a, drav_b,
+ drav_a, drav_b, drav_a, drav_b, drav_a, drav_b, drav_a, drav_b,
+ /* 0xf700 */
+ drav_a, drav_b, drav_a, drav_b, drav_a, drav_b, drav_a, drav_b,
+ drav_a, drav_b, drav_a, drav_b, drav_a, drav_b, drav_a, drav_b,
+ /* 0xf800 */
+ pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b,
+ pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b,
+ /* 0xf900 */
+ pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b,
+ pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b, pixt_ri_a, pixt_ri_b,
+ /* 0xfa00 */
+ pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b,
+ pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b,
+ /* 0xfb00 */
+ pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b,
+ pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b, pixt_ir_a, pixt_ir_b,
+ /* 0xfc00 */
+ pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b,
+ pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b,
+ /* 0xfd00 */
+ pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b,
+ pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b, pixt_ii_a, pixt_ii_b,
+ /* 0xfe00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ /* 0xff00 */
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl,
+ unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl, unimpl
+};
diff --git a/src/emu/cpu/tms34010/dis34010.c b/src/emu/cpu/tms34010/dis34010.c
new file mode 100644
index 00000000000..7b1addb953f
--- /dev/null
+++ b/src/emu/cpu/tms34010/dis34010.c
@@ -0,0 +1,113 @@
+/* This program is based on DIS68k by Aaron Giles */
+
+#include "cpuintrf.h"
+
+static UINT8 *filebuf;
+static UINT32 offset;
+
+#define STANDALONE
+#include "34010dsm.c"
+
+
+static char *Options[]=
+{
+ "begin","end","offset",0
+};
+
+static void usage (void)
+{
+ printf ("Usage: DIS34010 [options] <filename>\n"
+ "Available options are:\n"
+ " -begin - Specify begin offset in file to disassemble in bits [0]\n"
+ " -end - Specify end offset in file to disassemble in bits [none]\n"
+ " -offset - Specify address to load program in bits [0]\n"
+ "All values should be entered in hexadecimal\n");
+ exit (1);
+}
+
+int main (int argc,char *argv[])
+{
+ UINT8 i,j,n;
+ char *filename=0,buf[80];
+ FILE *f;
+ UINT32 begin=0,end=(UINT32)-1,filelen,len,pc;
+ printf ("DIS34010\n"
+ "Copyright (C) Zsolt Vasvari/Aaron Giles 1998-1999\n");
+
+ for (i=1,n=0;i<argc;++i)
+ {
+ if (argv[i][0]!='-')
+ {
+ switch (++n)
+ {
+ case 1: filename=argv[i]; break;
+ default: usage();
+ }
+ }
+ else
+ {
+ for (j=0;Options[j];++j)
+ if (!strcmp(argv[i]+1,Options[j])) break;
+
+ switch (j)
+ {
+ case 0: ++i; if (i>argc) usage();
+ begin=strtoul(argv[i],0,16) >> 3;
+ break;
+ case 1: ++i; if (i>argc) usage();
+ end=strtoul(argv[i],0,16) >> 3;
+ break;
+ case 2: ++i; if (i>argc) usage();
+ offset=strtoul(argv[i],0,16) >> 3;
+ break;
+ default: usage();
+ }
+ }
+ }
+
+ if (!filename)
+ {
+ usage();
+ return 1;
+ }
+ f=fopen (filename,"rb");
+ if (!f)
+ {
+ printf ("Unable to open %s\n",filename);
+ return 2;
+ }
+ fseek (f,0,SEEK_END);
+ filelen=ftell (f);
+ fseek (f,begin,SEEK_SET);
+ len=(filelen>end)? (end-begin+1):(filelen-begin);
+ filebuf=malloc(len+16);
+ if (!filebuf)
+ {
+ printf ("Memory allocation error\n");
+ fclose (f);
+ return 3;
+ }
+ memset (filebuf,0,len+16);
+ if (fread(filebuf,1,len,f)!=len)
+ {
+ printf ("Read error\n");
+ fclose (f);
+ free (filebuf);
+ return 4;
+ }
+ fclose (f);
+ pc=0;
+ while (pc<len-1)
+ {
+ i=(Dasm34010 (buf,pc<<3))>>3;
+
+ printf ("%08X: ",(pc+offset) << 3);
+ for (j=0;j<i ;++j) printf("%02X ",filebuf[pc+j]);
+ for ( ;j<10;++j) printf(" ");
+ printf(buf);
+ printf ("\n");
+ pc+=i;
+ }
+ free (filebuf);
+ return 0;
+}
diff --git a/src/emu/cpu/tms34010/makefile b/src/emu/cpu/tms34010/makefile
new file mode 100644
index 00000000000..9d2d0cedba9
--- /dev/null
+++ b/src/emu/cpu/tms34010/makefile
@@ -0,0 +1,6 @@
+dis34010.exe : dis34010.o -lalleg
+ gcc -m486 -O3 -ffast-math -fomit-frame-pointer -finline-functions dis34010.o -lalleg -o dis34010.exe
+
+dis34010.o : dis34010.c 34010dsm.c
+ gcc -c -m486 -O3 -ffast-math -fomit-frame-pointer -finline-functions -I/mame/src -I/mame/src/msdos dis34010.c
+
diff --git a/src/emu/cpu/tms34010/tms34010.c b/src/emu/cpu/tms34010/tms34010.c
new file mode 100644
index 00000000000..b2375f4d0b5
--- /dev/null
+++ b/src/emu/cpu/tms34010/tms34010.c
@@ -0,0 +1,1917 @@
+/***************************************************************************
+
+ TMS34010: Portable Texas Instruments TMS34010 emulator
+
+ Copyright (C) Alex Pasadyn/Zsolt Vasvari 1998
+ Parts based on code by Aaron Giles
+
+***************************************************************************/
+
+#include <stddef.h>
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "tms34010.h"
+#include "34010ops.h"
+#include "osd_cpu.h"
+#include "driver.h"
+
+
+/***************************************************************************
+ DEBUG STATE & STRUCTURES
+***************************************************************************/
+
+#define VERBOSE 0
+#define LOG_CONTROL_REGS 0
+#define LOG_GRAPHICS_OPS 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+/***************************************************************************
+ CORE STATE
+***************************************************************************/
+
+/* TMS34010 State */
+typedef struct
+{
+#ifdef LSB_FIRST
+ INT16 x;
+ INT16 y;
+#else
+ INT16 y;
+ INT16 x;
+#endif
+} XY;
+
+typedef struct tms34010_regs
+{
+ UINT16 op;
+ UINT32 pc;
+ UINT32 st;
+ void (*pixel_write)(offs_t offset,UINT32 data);
+ UINT32 (*pixel_read)(offs_t offset);
+ INT32 (*raster_op)(INT32 newpix, INT32 oldpix);
+ UINT32 convsp;
+ UINT32 convdp;
+ UINT32 convmp;
+ UINT16 *shiftreg;
+ INT32 gfxcycles;
+ UINT8 pixelshift;
+ UINT8 is_34020;
+ UINT8 reset_deferred;
+ int (*irq_callback)(int irqline);
+ const tms34010_config *config;
+ emu_timer *scantimer;
+
+ /* A registers 0-15 map to regs[0]-regs[15] */
+ /* B registers 0-15 map to regs[30]-regs[15] */
+ union
+ {
+ INT32 reg;
+ XY xy;
+ } regs[31];
+
+ /* for the 34010, we only copy 32 of these into the new state */
+ UINT16 IOregs[64];
+} tms34010_regs;
+
+#define TMS34010_STATE_SIZE (offsetof(tms34010_regs, IOregs) + 32 * sizeof(UINT16))
+#define TMS34020_STATE_SIZE (offsetof(tms34010_regs, IOregs) + 64 * sizeof(UINT16))
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* public globals */
+static int tms34010_ICount;
+
+/* internal state */
+static tms34010_regs state;
+static UINT8 external_host_access;
+static UINT8 screen_to_cpu[MAX_SCREENS];
+static UINT8 executing_cpu = 0xff;
+
+/* default configuration */
+static tms34010_config default_config =
+{
+ 0
+};
+
+static void check_interrupt(void);
+static TIMER_CALLBACK( scanline_callback );
+static void tms34010_state_postload(void);
+
+
+/***************************************************************************
+ FUNCTION TABLES
+***************************************************************************/
+
+extern void (*tms34010_wfield_functions[32])(offs_t offset,UINT32 data);
+extern UINT32 (*tms34010_rfield_functions[64])(offs_t offset);
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* status register definitions */
+#define STBIT_N (1 << 31)
+#define STBIT_C (1 << 30)
+#define STBIT_Z (1 << 29)
+#define STBIT_V (1 << 28)
+#define STBIT_P (1 << 25)
+#define STBIT_IE (1 << 21)
+#define STBIT_FE1 (1 << 11)
+#define STBITS_F1 (0x1f << 6)
+#define STBIT_FE0 (1 << 5)
+#define STBITS_F0 (0x1f << 0)
+
+/* register definitions and shortcuts */
+#define PC (state.pc)
+#define ST (state.st)
+#define N_FLAG (state.st & STBIT_N)
+#define Z_FLAG (state.st & STBIT_Z)
+#define C_FLAG (state.st & STBIT_C)
+#define V_FLAG (state.st & STBIT_V)
+#define P_FLAG (state.st & STBIT_P)
+#define IE_FLAG (state.st & STBIT_IE)
+#define FE0_FLAG (state.st & STBIT_FE0)
+#define FE1_FLAG (state.st & STBIT_FE1)
+
+/* register file access */
+#define AREG(i) (state.regs[i].reg)
+#define AREG_XY(i) (state.regs[i].xy)
+#define AREG_X(i) (state.regs[i].xy.x)
+#define AREG_Y(i) (state.regs[i].xy.y)
+#define BREG(i) (state.regs[30 - (i)].reg)
+#define BREG_XY(i) (state.regs[30 - (i)].xy)
+#define BREG_X(i) (state.regs[30 - (i)].xy.x)
+#define BREG_Y(i) (state.regs[30 - (i)].xy.y)
+#define SP AREG(15)
+#define FW(i) ((state.st >> (i ? 6 : 0)) & 0x1f)
+#define FWEX(i) ((state.st >> (i ? 6 : 0)) & 0x3f)
+
+/* opcode decode helpers */
+#define SRCREG ((state.op >> 5) & 0x0f)
+#define DSTREG (state.op & 0x0f)
+#define SKIP_WORD (PC += (2 << 3))
+#define SKIP_LONG (PC += (4 << 3))
+#define PARAM_K ((state.op >> 5) & 0x1f)
+#define PARAM_N (state.op & 0x1f)
+#define PARAM_REL8 ((INT8)state.op)
+
+/* memory I/O */
+#define WFIELD0(a,b) (*tms34010_wfield_functions[FW(0)])(a,b)
+#define WFIELD1(a,b) (*tms34010_wfield_functions[FW(1)])(a,b)
+#define RFIELD0(a) (*tms34010_rfield_functions[FWEX(0)])(a)
+#define RFIELD1(a) (*tms34010_rfield_functions[FWEX(1)])(a)
+#define WPIXEL(a,b) state.pixel_write(a,b)
+#define RPIXEL(a) state.pixel_read(a)
+
+/* Implied Operands */
+#define SADDR BREG(0)
+#define SADDR_X BREG_X(0)
+#define SADDR_Y BREG_Y(0)
+#define SADDR_XY BREG_XY(0)
+#define SPTCH BREG(1)
+#define DADDR BREG(2)
+#define DADDR_X BREG_X(2)
+#define DADDR_Y BREG_Y(2)
+#define DADDR_XY BREG_XY(2)
+#define DPTCH BREG(3)
+#define OFFSET BREG(4)
+#define WSTART_X BREG_X(5)
+#define WSTART_Y BREG_Y(5)
+#define WEND_X BREG_X(6)
+#define WEND_Y BREG_Y(6)
+#define DYDX_X BREG_X(7)
+#define DYDX_Y BREG_Y(7)
+#define COLOR0 BREG(8)
+#define COLOR1 BREG(9)
+#define COUNT BREG(10)
+#define INC1_X BREG_X(11)
+#define INC1_Y BREG_Y(11)
+#define INC2_X BREG_X(12)
+#define INC2_Y BREG_Y(12)
+#define PATTRN BREG(13)
+#define TEMP BREG(14)
+
+/* I/O registers */
+#define WINDOW_CHECKING ((IOREG(REG_CONTROL) >> 6) & 0x03)
+
+
+
+/***************************************************************************
+ INLINE SHORTCUTS
+***************************************************************************/
+
+/* Combine indiviual flags into the Status Register */
+INLINE UINT32 GET_ST(void)
+{
+ return state.st;
+}
+
+/* Break up Status Register into indiviual flags */
+INLINE void SET_ST(UINT32 st)
+{
+ state.st = st;
+ /* interrupts might have been enabled, check it */
+ check_interrupt();
+}
+
+/* Intialize Status to 0x0010 */
+INLINE void RESET_ST(void)
+{
+ SET_ST(0x00000010);
+}
+
+/* shortcuts for reading opcodes */
+INLINE UINT32 ROPCODE(void)
+{
+ UINT32 pc = TOBYTE(PC);
+ PC += 2 << 3;
+ return cpu_readop16(pc);
+}
+
+INLINE INT16 PARAM_WORD(void)
+{
+ UINT32 pc = TOBYTE(PC);
+ PC += 2 << 3;
+ return cpu_readop_arg16(pc);
+}
+
+INLINE INT32 PARAM_LONG(void)
+{
+ UINT32 pc = TOBYTE(PC);
+ PC += 4 << 3;
+ return (UINT16)cpu_readop_arg16(pc) | (cpu_readop_arg16(pc + 2) << 16);
+}
+
+INLINE INT16 PARAM_WORD_NO_INC(void)
+{
+ return cpu_readop_arg16(TOBYTE(PC));
+}
+
+INLINE INT32 PARAM_LONG_NO_INC(void)
+{
+ UINT32 pc = TOBYTE(PC);
+ return (UINT16)cpu_readop_arg16(pc) | (cpu_readop_arg16(pc + 2) << 16);
+}
+
+/* read memory byte */
+INLINE UINT32 RBYTE(offs_t offset)
+{
+ UINT32 ret;
+ RFIELDMAC_8;
+ return ret;
+}
+
+/* write memory byte */
+INLINE void WBYTE(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_8;
+}
+
+/* read memory long */
+INLINE UINT32 RLONG(offs_t offset)
+{
+ RFIELDMAC_32;
+}
+
+/* write memory long */
+INLINE void WLONG(offs_t offset,UINT32 data)
+{
+ WFIELDMAC_32;
+}
+
+/* pushes/pops a value from the stack */
+INLINE void PUSH(UINT32 data)
+{
+ SP -= 0x20;
+ WLONG(SP, data);
+}
+
+INLINE INT32 POP(void)
+{
+ INT32 ret = RLONG(SP);
+ SP += 0x20;
+ return ret;
+}
+
+
+
+/***************************************************************************
+ PIXEL READS
+***************************************************************************/
+
+#define RP(m1,m2) \
+ /* TODO: Plane masking */ \
+ return (TMS34010_RDMEM_WORD(TOBYTE(offset & 0xfffffff0)) >> (offset & m1)) & m2;
+
+static UINT32 read_pixel_1(offs_t offset) { RP(0x0f,0x01) }
+static UINT32 read_pixel_2(offs_t offset) { RP(0x0e,0x03) }
+static UINT32 read_pixel_4(offs_t offset) { RP(0x0c,0x0f) }
+static UINT32 read_pixel_8(offs_t offset) { RP(0x08,0xff) }
+static UINT32 read_pixel_16(offs_t offset)
+{
+ /* TODO: Plane masking */
+ return TMS34010_RDMEM_WORD(TOBYTE(offset & 0xfffffff0));
+}
+
+/* Shift register read */
+static UINT32 read_pixel_shiftreg(offs_t offset)
+{
+ if (state.config->to_shiftreg)
+ state.config->to_shiftreg(offset, &state.shiftreg[0]);
+ else
+ fatalerror("To ShiftReg function not set. PC = %08X\n", PC);
+ return state.shiftreg[0];
+}
+
+
+
+/***************************************************************************
+ PIXEL WRITES
+***************************************************************************/
+
+/* No Raster Op + No Transparency */
+#define WP(m1,m2) \
+ UINT32 a = TOBYTE(offset & 0xfffffff0); \
+ UINT32 pix = TMS34010_RDMEM_WORD(a); \
+ UINT32 shiftcount = offset & m1; \
+ \
+ /* TODO: plane masking */ \
+ data &= m2; \
+ pix = (pix & ~(m2 << shiftcount)) | (data << shiftcount); \
+ TMS34010_WRMEM_WORD(a, pix); \
+
+/* No Raster Op + Transparency */
+#define WP_T(m1,m2) \
+ /* TODO: plane masking */ \
+ data &= m2; \
+ if (data) \
+ { \
+ UINT32 a = TOBYTE(offset & 0xfffffff0); \
+ UINT32 pix = TMS34010_RDMEM_WORD(a); \
+ UINT32 shiftcount = offset & m1; \
+ \
+ /* TODO: plane masking */ \
+ pix = (pix & ~(m2 << shiftcount)) | (data << shiftcount); \
+ TMS34010_WRMEM_WORD(a, pix); \
+ } \
+
+/* Raster Op + No Transparency */
+#define WP_R(m1,m2) \
+ UINT32 a = TOBYTE(offset & 0xfffffff0); \
+ UINT32 pix = TMS34010_RDMEM_WORD(a); \
+ UINT32 shiftcount = offset & m1; \
+ \
+ /* TODO: plane masking */ \
+ data = state.raster_op(data & m2, (pix >> shiftcount) & m2) & m2; \
+ pix = (pix & ~(m2 << shiftcount)) | (data << shiftcount); \
+ TMS34010_WRMEM_WORD(a, pix); \
+
+/* Raster Op + Transparency */
+#define WP_R_T(m1,m2) \
+ UINT32 a = TOBYTE(offset & 0xfffffff0); \
+ UINT32 pix = TMS34010_RDMEM_WORD(a); \
+ UINT32 shiftcount = offset & m1; \
+ \
+ /* TODO: plane masking */ \
+ data = state.raster_op(data & m2, (pix >> shiftcount) & m2) & m2; \
+ if (data) \
+ { \
+ pix = (pix & ~(m2 << shiftcount)) | (data << shiftcount); \
+ TMS34010_WRMEM_WORD(a, pix); \
+ } \
+
+
+/* No Raster Op + No Transparency */
+static void write_pixel_1(offs_t offset,UINT32 data) { WP(0x0f, 0x01); }
+static void write_pixel_2(offs_t offset,UINT32 data) { WP(0x0e, 0x03); }
+static void write_pixel_4(offs_t offset,UINT32 data) { WP(0x0c, 0x0f); }
+static void write_pixel_8(offs_t offset,UINT32 data) { WP(0x08, 0xff); }
+static void write_pixel_16(offs_t offset,UINT32 data)
+{
+ /* TODO: plane masking */
+ TMS34010_WRMEM_WORD(TOBYTE(offset & 0xfffffff0), data);
+}
+
+/* No Raster Op + Transparency */
+static void write_pixel_t_1(offs_t offset,UINT32 data) { WP_T(0x0f, 0x01); }
+static void write_pixel_t_2(offs_t offset,UINT32 data) { WP_T(0x0e, 0x03); }
+static void write_pixel_t_4(offs_t offset,UINT32 data) { WP_T(0x0c, 0x0f); }
+static void write_pixel_t_8(offs_t offset,UINT32 data) { WP_T(0x08, 0xff); }
+static void write_pixel_t_16(offs_t offset,UINT32 data)
+{
+ /* TODO: plane masking */
+ if (data)
+ TMS34010_WRMEM_WORD(TOBYTE(offset & 0xfffffff0), data);
+}
+
+/* Raster Op + No Transparency */
+static void write_pixel_r_1(offs_t offset,UINT32 data) { WP_R(0x0f, 0x01); }
+static void write_pixel_r_2(offs_t offset,UINT32 data) { WP_R(0x0e, 0x03); }
+static void write_pixel_r_4(offs_t offset,UINT32 data) { WP_R(0x0c, 0x0f); }
+static void write_pixel_r_8(offs_t offset,UINT32 data) { WP_R(0x08, 0xff); }
+static void write_pixel_r_16(offs_t offset,UINT32 data)
+{
+ /* TODO: plane masking */
+ UINT32 a = TOBYTE(offset & 0xfffffff0);
+ TMS34010_WRMEM_WORD(a, state.raster_op(data, TMS34010_RDMEM_WORD(a)));
+}
+
+/* Raster Op + Transparency */
+static void write_pixel_r_t_1(offs_t offset,UINT32 data) { WP_R_T(0x0f,0x01); }
+static void write_pixel_r_t_2(offs_t offset,UINT32 data) { WP_R_T(0x0e,0x03); }
+static void write_pixel_r_t_4(offs_t offset,UINT32 data) { WP_R_T(0x0c,0x0f); }
+static void write_pixel_r_t_8(offs_t offset,UINT32 data) { WP_R_T(0x08,0xff); }
+static void write_pixel_r_t_16(offs_t offset,UINT32 data)
+{
+ /* TODO: plane masking */
+ UINT32 a = TOBYTE(offset & 0xfffffff0);
+ data = state.raster_op(data, TMS34010_RDMEM_WORD(a));
+
+ if (data)
+ TMS34010_WRMEM_WORD(a, data);
+}
+
+/* Shift register write */
+static void write_pixel_shiftreg(offs_t offset,UINT32 data)
+{
+ if (state.config->from_shiftreg)
+ state.config->from_shiftreg(offset, &state.shiftreg[0]);
+ else
+ fatalerror("From ShiftReg function not set. PC = %08X\n", PC);
+}
+
+
+
+/***************************************************************************
+ RASTER OPS
+***************************************************************************/
+
+/* Raster operations */
+static INT32 raster_op_1(INT32 newpix, INT32 oldpix) { return newpix & oldpix; }
+static INT32 raster_op_2(INT32 newpix, INT32 oldpix) { return newpix & ~oldpix; }
+static INT32 raster_op_3(INT32 newpix, INT32 oldpix) { return 0; }
+static INT32 raster_op_4(INT32 newpix, INT32 oldpix) { return newpix | ~oldpix; }
+static INT32 raster_op_5(INT32 newpix, INT32 oldpix) { return ~(newpix ^ oldpix); }
+static INT32 raster_op_6(INT32 newpix, INT32 oldpix) { return ~oldpix; }
+static INT32 raster_op_7(INT32 newpix, INT32 oldpix) { return ~(newpix | oldpix); }
+static INT32 raster_op_8(INT32 newpix, INT32 oldpix) { return newpix | oldpix; }
+static INT32 raster_op_9(INT32 newpix, INT32 oldpix) { return oldpix; }
+static INT32 raster_op_10(INT32 newpix, INT32 oldpix) { return newpix ^ oldpix; }
+static INT32 raster_op_11(INT32 newpix, INT32 oldpix) { return ~newpix & oldpix; }
+static INT32 raster_op_12(INT32 newpix, INT32 oldpix) { return 0xffff; }
+static INT32 raster_op_13(INT32 newpix, INT32 oldpix) { return ~newpix | oldpix; }
+static INT32 raster_op_14(INT32 newpix, INT32 oldpix) { return ~(newpix & oldpix); }
+static INT32 raster_op_15(INT32 newpix, INT32 oldpix) { return ~newpix; }
+static INT32 raster_op_16(INT32 newpix, INT32 oldpix) { return newpix + oldpix; }
+static INT32 raster_op_17(INT32 newpix, INT32 oldpix)
+{
+ INT32 max = (UINT32)0xffffffff >> (32 - IOREG(REG_PSIZE));
+ INT32 res = newpix + oldpix;
+ return (res > max) ? max : res;
+}
+static INT32 raster_op_18(INT32 newpix, INT32 oldpix) { return oldpix - newpix; }
+static INT32 raster_op_19(INT32 newpix, INT32 oldpix) { return (oldpix > newpix) ? oldpix - newpix : 0; }
+static INT32 raster_op_20(INT32 newpix, INT32 oldpix) { return (oldpix > newpix) ? oldpix : newpix; }
+static INT32 raster_op_21(INT32 newpix, INT32 oldpix) { return (oldpix > newpix) ? newpix : oldpix; }
+
+
+
+/***************************************************************************
+ OPCODE TABLE & IMPLEMENTATIONS
+***************************************************************************/
+
+/* includes the static function prototypes and the master opcode table */
+#include "34010tbl.c"
+
+/* includes the actual opcode implementations */
+#include "34010ops.c"
+#include "34010gfx.c"
+
+
+
+/***************************************************************************
+ Internal interrupt check
+****************************************************************************/
+
+/* Generate pending interrupts. */
+static void check_interrupt(void)
+{
+ int vector = 0;
+ int irqline = -1;
+ int irq;
+
+ /* if we're not actively executing, skip it */
+ if (executing_cpu != 0xff && executing_cpu != cpu_getactivecpu())
+ return;
+
+ /* check for NMI first */
+ if (IOREG(REG_HSTCTLH) & 0x0100)
+ {
+ LOG(("TMS34010#%d takes NMI\n", cpu_getactivecpu()));
+
+ /* ack the NMI */
+ IOREG(REG_HSTCTLH) &= ~0x0100;
+
+ /* handle NMI mode bit */
+ if (!(IOREG(REG_HSTCTLH) & 0x0200))
+ {
+ PUSH(PC);
+ PUSH(GET_ST());
+ }
+
+ /* leap to the vector */
+ RESET_ST();
+ PC = RLONG(0xfffffee0);
+ change_pc(TOBYTE(PC));
+ COUNT_CYCLES(16);
+ return;
+ }
+
+ /* early out if everything else is disabled */
+ irq = IOREG(REG_INTPEND) & IOREG(REG_INTENB);
+ if (!IE_FLAG || !irq)
+ return;
+
+ /* host interrupt */
+ if (irq & TMS34010_HI)
+ {
+ LOG(("TMS34010#%d takes HI\n", cpu_getactivecpu()));
+ vector = 0xfffffec0;
+ }
+
+ /* display interrupt */
+ else if (irq & TMS34010_DI)
+ {
+ LOG(("TMS34010#%d takes DI\n", cpu_getactivecpu()));
+ vector = 0xfffffea0;
+ }
+
+ /* window violation interrupt */
+ else if (irq & TMS34010_WV)
+ {
+ LOG(("TMS34010#%d takes WV\n", cpu_getactivecpu()));
+ vector = 0xfffffe80;
+ }
+
+ /* external 1 interrupt */
+ else if (irq & TMS34010_INT1)
+ {
+ LOG(("TMS34010#%d takes INT1\n", cpu_getactivecpu()));
+ vector = 0xffffffc0;
+ irqline = 0;
+ }
+
+ /* external 2 interrupt */
+ else if (irq & TMS34010_INT2)
+ {
+ LOG(("TMS34010#%d takes INT2\n", cpu_getactivecpu()));
+ vector = 0xffffffa0;
+ irqline = 1;
+ }
+
+ /* if we took something, generate it */
+ if (vector)
+ {
+ PUSH(PC);
+ PUSH(GET_ST());
+ RESET_ST();
+ PC = RLONG(vector);
+ change_pc(TOBYTE(PC));
+ COUNT_CYCLES(16);
+
+ /* call the callback for externals */
+ if (irqline >= 0)
+ (void)(*state.irq_callback)(irqline);
+ }
+}
+
+
+
+/***************************************************************************
+ Reset the CPU emulation
+***************************************************************************/
+
+static void tms34010_init(int index, int clock, const void *_config, int (*irqcallback)(int))
+{
+ const tms34010_config *config = _config ? _config : &default_config;
+
+ external_host_access = FALSE;
+
+ state.config = config;
+ state.irq_callback = irqcallback;
+
+ /* if we have a scanline callback, make us the owner of this screen */
+ if (config->scanline_callback != NULL)
+ screen_to_cpu[config->scrnum] = index;
+
+ /* allocate a scanline timer and set it to go off at the start */
+ state.scantimer = timer_alloc(scanline_callback);
+ timer_adjust(state.scantimer, attotime_zero, index, attotime_zero);
+
+ /* allocate the shiftreg */
+ state.shiftreg = auto_malloc(SHIFTREG_SIZE);
+
+ state_save_register_item("tms34010", index, state.op);
+ state_save_register_item("tms34010", index, state.pc);
+ state_save_register_item("tms34010", index, state.st);
+ state_save_register_item("tms34010", index, state.reset_deferred);
+ state_save_register_item_pointer("tms34010", index, state.shiftreg, SHIFTREG_SIZE / 2);
+ state_save_register_item_array("tms34010", index, state.IOregs);
+ state_save_register_item("tms34010", index, state.convsp);
+ state_save_register_item("tms34010", index, state.convdp);
+ state_save_register_item("tms34010", index, state.convmp);
+ state_save_register_item("tms34010", index, state.pixelshift);
+ state_save_register_item("tms34010", index, state.gfxcycles);
+ state_save_register_item_pointer("tms34010", index, (&state.regs[0].reg), ARRAY_LENGTH(state.regs));
+ state_save_register_func_postload(tms34010_state_postload);
+}
+
+static void tms34010_reset(void)
+{
+ const tms34010_config *config;
+ emu_timer *save_scantimer;
+ int (*save_irqcallback)(int);
+ UINT16 *shiftreg;
+
+ /* zap the state and copy in the config pointer */
+ config = state.config;
+ shiftreg = state.shiftreg;
+ save_irqcallback = state.irq_callback;
+ save_scantimer = state.scantimer;
+ memset(&state, 0, sizeof(state));
+ state.shiftreg = shiftreg;
+ state.config = config;
+ state.irq_callback = save_irqcallback;
+ state.scantimer = save_scantimer;
+
+ /* fetch the initial PC and reset the state */
+ PC = RLONG(0xffffffe0) & 0xfffffff0;
+ change_pc(TOBYTE(PC));
+ RESET_ST();
+
+ /* HALT the CPU if requested, and remember to re-read the starting PC */
+ /* the first time we are run */
+ state.reset_deferred = state.config->halt_on_reset;
+ if (state.config->halt_on_reset)
+ tms34010_io_register_w(REG_HSTCTLH, 0x8000, 0);
+}
+
+#if (HAS_TMS34020)
+static void tms34020_reset(void)
+{
+ tms34010_reset();
+ state.is_34020 = 1;
+}
+#endif
+
+
+
+/***************************************************************************
+ Shut down the CPU emulation
+***************************************************************************/
+
+static void tms34010_exit(void)
+{
+ state.shiftreg = NULL;
+}
+
+
+
+/***************************************************************************
+ Get all registers in given buffer
+***************************************************************************/
+
+static void tms34010_get_context(void *dst)
+{
+ if (dst)
+ memcpy(dst, &state, TMS34010_STATE_SIZE);
+}
+
+#if (HAS_TMS34020)
+static void tms34020_get_context(void *dst)
+{
+ if (dst)
+ memcpy(dst, &state, TMS34020_STATE_SIZE);
+}
+#endif
+
+
+
+/***************************************************************************
+ Set all registers to given values
+***************************************************************************/
+
+static void tms34010_set_context(void *src)
+{
+ if (src)
+ memcpy(&state, src, TMS34010_STATE_SIZE);
+ change_pc(TOBYTE(PC));
+}
+
+#if (HAS_TMS34020)
+static void tms34020_set_context(void *src)
+{
+ if (src)
+ memcpy(&state, src, TMS34020_STATE_SIZE);
+ change_pc(TOBYTE(PC));
+}
+#endif
+
+
+
+/***************************************************************************
+ Set IRQ line state
+***************************************************************************/
+
+static void set_irq_line(int irqline, int linestate)
+{
+ LOG(("TMS34010#%d set irq line %d state %d\n", cpu_getactivecpu(), irqline, linestate));
+
+ /* set the pending interrupt */
+ switch (irqline)
+ {
+ case 0:
+ if (linestate != CLEAR_LINE)
+ IOREG(REG_INTPEND) |= TMS34010_INT1;
+ else
+ IOREG(REG_INTPEND) &= ~TMS34010_INT1;
+ break;
+
+ case 1:
+ if (linestate != CLEAR_LINE)
+ IOREG(REG_INTPEND) |= TMS34010_INT2;
+ else
+ IOREG(REG_INTPEND) &= ~TMS34010_INT2;
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ Generate internal interrupt
+***************************************************************************/
+
+static TIMER_CALLBACK( internal_interrupt_callback )
+{
+ int cpunum = param & 0xff;
+ int type = param >> 8;
+
+ /* call through to the CPU to generate the int */
+ cpuintrf_push_context(cpunum);
+ IOREG(REG_INTPEND) |= type;
+ LOG(("TMS34010#%d set internal interrupt $%04x\n", cpu_getactivecpu(), type));
+ cpuintrf_pop_context();
+
+ /* generate triggers so that spin loops can key off them */
+ cpu_triggerint(cpunum);
+}
+
+
+
+/***************************************************************************
+ Execute
+***************************************************************************/
+
+static int tms34010_execute(int cycles)
+{
+ /* Get out if CPU is halted. Absolutely no interrupts must be taken!!! */
+ if (IOREG(REG_HSTCTLH) & 0x8000)
+ return cycles;
+
+ /* if the CPU's reset was deferred, do it now */
+ if (state.reset_deferred)
+ {
+ state.reset_deferred = 0;
+ PC = RLONG(0xffffffe0);
+ }
+
+ /* execute starting now */
+ tms34010_ICount = cycles;
+ change_pc(TOBYTE(PC));
+
+ /* check interrupts first */
+ executing_cpu = cpu_getactivecpu();
+ check_interrupt();
+ do
+ {
+
+ #ifdef MAME_DEBUG
+ if (Machine->debug_mode) { state.st = GET_ST(); mame_debug_hook(); }
+ #endif
+ state.op = ROPCODE();
+ (*opcode_table[state.op >> 4])();
+
+ } while (tms34010_ICount > 0);
+ executing_cpu = 0xff;
+
+ return cycles - tms34010_ICount;
+}
+
+
+
+/***************************************************************************
+ PIXEL OPS
+***************************************************************************/
+
+static void (*pixel_write_ops[4][5])(offs_t offset,UINT32 data) =
+{
+ { write_pixel_1, write_pixel_2, write_pixel_4, write_pixel_8, write_pixel_16 },
+ { write_pixel_r_1, write_pixel_r_2, write_pixel_r_4, write_pixel_r_8, write_pixel_r_16 },
+ { write_pixel_t_1, write_pixel_t_2, write_pixel_t_4, write_pixel_t_8, write_pixel_t_16 },
+ { write_pixel_r_t_1, write_pixel_r_t_2, write_pixel_r_t_4, write_pixel_r_t_8, write_pixel_r_t_16 }
+};
+
+static UINT32 (*pixel_read_ops[5])(offs_t offset) =
+{
+ read_pixel_1, read_pixel_2, read_pixel_4, read_pixel_8, read_pixel_16
+};
+
+
+static void set_pixel_function(void)
+{
+ UINT32 i1,i2;
+
+ if (IOREG(REG_DPYCTL) & 0x0800)
+ {
+ /* Shift Register Transfer */
+ state.pixel_write = write_pixel_shiftreg;
+ state.pixel_read = read_pixel_shiftreg;
+ return;
+ }
+
+ switch (IOREG(REG_PSIZE))
+ {
+ default:
+ case 0x01: i2 = 0; break;
+ case 0x02: i2 = 1; break;
+ case 0x04: i2 = 2; break;
+ case 0x08: i2 = 3; break;
+ case 0x10: i2 = 4; break;
+ }
+
+ if (IOREG(REG_CONTROL) & 0x20)
+ i1 = state.raster_op ? 3 : 2;
+ else
+ i1 = state.raster_op ? 1 : 0;
+
+ state.pixel_write = pixel_write_ops[i1][i2];
+ state.pixel_read = pixel_read_ops [i2];
+}
+
+
+
+/***************************************************************************
+ RASTER OPS
+***************************************************************************/
+
+static INT32 (*raster_ops[32]) (INT32 newpix, INT32 oldpix) =
+{
+ 0, raster_op_1 , raster_op_2 , raster_op_3,
+ raster_op_4 , raster_op_5 , raster_op_6 , raster_op_7,
+ raster_op_8 , raster_op_9 , raster_op_10, raster_op_11,
+ raster_op_12, raster_op_13, raster_op_14, raster_op_15,
+ raster_op_16, raster_op_17, raster_op_18, raster_op_19,
+ raster_op_20, raster_op_21, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+
+
+static void set_raster_op(void)
+{
+ state.raster_op = raster_ops[(IOREG(REG_CONTROL) >> 10) & 0x1f];
+}
+
+
+
+/***************************************************************************
+ VIDEO TIMING HELPERS
+***************************************************************************/
+
+static TIMER_CALLBACK( scanline_callback )
+{
+ const screen_state *screen;
+ int vsblnk, veblnk, vtotal;
+ int vcount = param >> 8;
+ int cpunum = param & 0xff;
+ int enabled;
+ int master;
+
+ /* set the CPU context */
+ cpuintrf_push_context(cpunum);
+ screen = &machine->screen[state.config->scrnum];
+
+ /* fetch the core timing parameters */
+ enabled = SMART_IOREG(DPYCTL) & 0x8000;
+ master = (state.is_34020 || (SMART_IOREG(DPYCTL) & 0x2000));
+ vsblnk = SMART_IOREG(VSBLNK);
+ veblnk = SMART_IOREG(VEBLNK);
+ vtotal = SMART_IOREG(VTOTAL);
+ if (!master)
+ {
+ vtotal = MIN(screen->height - 1, vtotal);
+ vcount = video_screen_get_vpos(state.config->scrnum);
+ }
+
+ /* update the VCOUNT */
+ SMART_IOREG(VCOUNT) = vcount;
+
+ /* if we match the display interrupt scanline, signal an interrupt */
+ if (enabled && vcount == SMART_IOREG(DPYINT))
+ {
+ /* generate the display interrupt signal */
+ internal_interrupt_callback(machine, cpunum | (TMS34010_DI << 8));
+ }
+
+ /* at the start of VBLANK, load the starting display address */
+ if (vcount == vsblnk)
+ {
+ /* 34010 loads DPYADR with DPYSTRT, and inverts if the origin is 0 */
+ if (!state.is_34020)
+ {
+ IOREG(REG_DPYADR) = IOREG(REG_DPYSTRT);
+ LOG(("Start of VBLANK, DPYADR = %04X\n", IOREG(REG_DPYADR)));
+ }
+
+ /* 34020 loads DPYNXx with DPYSTx */
+ else
+ {
+ IOREG(REG020_DPYNXL) = IOREG(REG020_DPYSTL) & 0xffe0;
+ IOREG(REG020_DPYNXH) = IOREG(REG020_DPYSTH);
+ }
+ }
+
+ /* at the end of the screen, update the display parameters */
+ if (vcount == vtotal)
+ {
+ /* only do this if we have an incoming pixel clock */
+ /* also, only do it if the HEBLNK/HSBLNK values are stable */
+ if (master && state.config->scanline_callback != NULL)
+ {
+ int htotal = SMART_IOREG(HTOTAL);
+ if (htotal > 0 && vtotal > 0)
+ {
+ attoseconds_t refresh = HZ_TO_ATTOSECONDS(state.config->pixclock) * (htotal + 1) * (vtotal + 1);
+ int width = (htotal + 1) * state.config->pixperclock;
+ int height = vtotal + 1;
+ rectangle visarea;
+
+ /* extract the visible area */
+ visarea.min_x = SMART_IOREG(HEBLNK) * state.config->pixperclock;
+ visarea.max_x = SMART_IOREG(HSBLNK) * state.config->pixperclock - 1;
+ visarea.min_y = veblnk;
+ visarea.max_y = vsblnk - 1;
+
+ /* if everything looks good, set the info */
+ if (visarea.min_x < visarea.max_x && visarea.max_x <= width && visarea.min_y < visarea.max_y && visarea.max_y <= height)
+ {
+ /* because many games play with the HEBLNK/HSBLNK for effects, we don't change
+ if they are the only thing that has changed */
+ if (width != screen->width || height != screen->height || visarea.min_y != screen->visarea.min_y || visarea.max_y != screen->visarea.max_y)
+ video_screen_configure(state.config->scrnum, width, height, &visarea, refresh);
+ }
+
+ LOG(("Configuring screen: HTOTAL=%3d BLANK=%3d-%3d VTOTAL=%3d BLANK=%3d-%3d refresh=%f\n",
+ htotal, SMART_IOREG(HEBLNK), SMART_IOREG(HSBLNK), vtotal, veblnk, vsblnk, ATTOSECONDS_TO_HZ(refresh)));
+
+ /* interlaced timing not supported */
+ if ((SMART_IOREG(DPYCTL) & 0x4000) == 0)
+ fatalerror("Interlaced video configured on the TMS34010 (unsupported)");
+ }
+ }
+ }
+
+ /* force a partial update within the visible area */
+ if (vcount >= screen->visarea.min_y && vcount <= screen->visarea.max_y && state.config->scanline_callback != NULL)
+ video_screen_update_partial(state.config->scrnum, vcount);
+
+ /* if we are in the visible area, increment DPYADR by DUDATE */
+ if (vcount >= veblnk && vcount < vsblnk)
+ {
+ /* 34010 increments by the DUDATE field in DPYCTL */
+ if (!state.is_34020)
+ {
+ UINT16 dpyadr = IOREG(REG_DPYADR);
+ if ((dpyadr & 3) == 0)
+ dpyadr = ((dpyadr & 0xfffc) - (IOREG(REG_DPYCTL) & 0x03fc)) | (IOREG(REG_DPYSTRT) & 0x0003);
+ else
+ dpyadr = (dpyadr & 0xfffc) | ((dpyadr - 1) & 3);
+ IOREG(REG_DPYADR) = dpyadr;
+ }
+
+ /* 34020 updates based on the DINC register, including zoom */
+ else
+ {
+ UINT32 dpynx = IOREG(REG020_DPYNXL) | (IOREG(REG020_DPYNXH) << 16);
+ UINT32 dinc = IOREG(REG020_DINCL) | (IOREG(REG020_DINCH) << 16);
+ dpynx = (dpynx & 0xffffffe0) | ((dpynx + dinc) & 0x1f);
+ if ((dpynx & 0x1f) == 0)
+ dpynx += dinc & 0xffffffe0;
+ IOREG(REG020_DPYNXL) = dpynx;
+ IOREG(REG020_DPYNXH) = dpynx >> 16;
+ }
+ }
+
+ /* adjust for the next callback */
+ vcount++;
+ if (vcount > vtotal)
+ vcount = 0;
+
+ /* note that we add !master (0 or 1) as a attoseconds value; this makes no practical difference */
+ /* but helps ensure that masters are updated first before slaves */
+ timer_adjust(state.scantimer, attotime_add_attoseconds(video_screen_get_time_until_pos(state.config->scrnum, vcount, 0), !master), cpunum | (vcount << 8), attotime_zero);
+
+ /* restore the context */
+ cpuintrf_pop_context();
+}
+
+
+void tms34010_get_display_params(int cpunum, tms34010_display_params *params)
+{
+ cpuintrf_push_context(cpunum);
+
+ params->enabled = ((SMART_IOREG(DPYCTL) & 0x8000) != 0);
+ params->vcount = SMART_IOREG(VCOUNT);
+ params->veblnk = SMART_IOREG(VEBLNK);
+ params->vsblnk = SMART_IOREG(VSBLNK);
+ params->heblnk = SMART_IOREG(HEBLNK) * state.config->pixperclock;
+ params->hsblnk = SMART_IOREG(HSBLNK) * state.config->pixperclock;
+
+ /* 34010 gets its address from DPYADR and DPYTAP */
+ if (!state.is_34020)
+ {
+ UINT16 dpyadr = IOREG(REG_DPYADR);
+ if (!(IOREG(REG_DPYCTL) & 0x0400))
+ dpyadr ^= 0xfffc;
+ params->rowaddr = dpyadr >> 4;
+ params->coladdr = ((dpyadr & 0x007c) << 4) | (IOREG(REG_DPYTAP) & 0x3fff);
+ params->yoffset = (IOREG(REG_DPYSTRT) - IOREG(REG_DPYADR)) & 3;
+ }
+
+ /* 34020 gets its address from DPYNX */
+ else
+ {
+ params->rowaddr = IOREG(REG020_DPYNXH);
+ params->coladdr = IOREG(REG020_DPYNXL) & 0xffe0;
+ params->yoffset = 0;
+ if ((IOREG(REG020_DINCL) & 0x1f) != 0)
+ params->yoffset = (IOREG(REG020_DPYNXL) & 0x1f) / (IOREG(REG020_DINCL) & 0x1f);
+ }
+
+ cpuintrf_pop_context();
+}
+
+
+VIDEO_UPDATE( tms340x0 )
+{
+ pen_t blackpen = get_black_pen(machine);
+ tms34010_display_params params;
+ int x;
+
+ /* get the display parameters for the screen */
+ tms34010_get_display_params(screen_to_cpu[screen], &params);
+
+ /* if the display is enabled, call the scanline callback */
+ if (params.enabled)
+ {
+ /* call through to the callback */
+ LOG((" Update: scan=%3d ROW=%04X COL=%04X\n", cliprect->min_y, params.rowaddr, params.coladdr));
+ (*state.config->scanline_callback)(machine, screen, bitmap, cliprect->min_y, &params);
+ }
+
+ /* otherwise, just blank the current scanline */
+ else
+ params.heblnk = params.hsblnk = cliprect->max_x + 1;
+
+ /* blank out the blank regions */
+ if (bitmap->bpp == 16)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, cliprect->min_y, 0);
+ for (x = cliprect->min_x; x < params.heblnk; x++)
+ dest[x] = blackpen;
+ for (x = params.hsblnk; x <= cliprect->max_y; x++)
+ dest[x] = blackpen;
+ }
+ else if (bitmap->bpp == 32)
+ {
+ UINT32 *dest = BITMAP_ADDR32(bitmap, cliprect->min_y, 0);
+ for (x = cliprect->min_x; x < params.heblnk; x++)
+ dest[x] = blackpen;
+ for (x = params.hsblnk; x <= cliprect->max_y; x++)
+ dest[x] = blackpen;
+ }
+ return 0;
+}
+
+
+/***************************************************************************
+ I/O REGISTER WRITES
+***************************************************************************/
+
+static const char *ioreg_name[] =
+{
+ "HESYNC", "HEBLNK", "HSBLNK", "HTOTAL",
+ "VESYNC", "VEBLNK", "VSBLNK", "VTOTAL",
+ "DPYCTL", "DPYSTART", "DPYINT", "CONTROL",
+ "HSTDATA", "HSTADRL", "HSTADRH", "HSTCTLL",
+
+ "HSTCTLH", "INTENB", "INTPEND", "CONVSP",
+ "CONVDP", "PSIZE", "PMASK", "RESERVED",
+ "RESERVED", "RESERVED", "RESERVED", "DPYTAP",
+ "HCOUNT", "VCOUNT", "DPYADR", "REFCNT"
+};
+
+WRITE16_HANDLER( tms34010_io_register_w )
+{
+ int cpunum = cpu_getactivecpu();
+ int oldreg, newreg;
+
+ /* Set register */
+ oldreg = IOREG(offset);
+ IOREG(offset) = data;
+
+ switch (offset)
+ {
+ case REG_CONTROL:
+ set_raster_op();
+ set_pixel_function();
+ break;
+
+ case REG_PSIZE:
+ set_pixel_function();
+
+ switch (data)
+ {
+ default:
+ case 0x01: state.pixelshift = 0; break;
+ case 0x02: state.pixelshift = 1; break;
+ case 0x04: state.pixelshift = 2; break;
+ case 0x08: state.pixelshift = 3; break;
+ case 0x10: state.pixelshift = 4; break;
+ }
+ break;
+
+ case REG_PMASK:
+ if (data) logerror("Plane masking not supported. PC=%08X\n", activecpu_get_pc());
+ break;
+
+ case REG_DPYCTL:
+ set_pixel_function();
+ break;
+
+ case REG_HSTCTLH:
+ /* if the CPU is halting itself, stop execution right away */
+ if ((data & 0x8000) && !external_host_access)
+ tms34010_ICount = 0;
+ cpunum_set_input_line(cpunum, INPUT_LINE_HALT, (data & 0x8000) ? ASSERT_LINE : CLEAR_LINE);
+
+ /* NMI issued? */
+ if (data & 0x0100)
+ timer_call_after_resynch(cpunum, internal_interrupt_callback);
+ break;
+
+ case REG_HSTCTLL:
+ /* the TMS34010 can change MSGOUT, can set INTOUT, and can clear INTIN */
+ if (!external_host_access)
+ {
+ newreg = (oldreg & 0xff8f) | (data & 0x0070);
+ newreg |= data & 0x0080;
+ newreg &= data | ~0x0008;
+ }
+
+ /* the host can change MSGIN, can set INTIN, and can clear INTOUT */
+ else
+ {
+ newreg = (oldreg & 0xfff8) | (data & 0x0007);
+ newreg &= data | ~0x0080;
+ newreg |= data & 0x0008;
+ }
+ IOREG(offset) = newreg;
+
+ /* the TMS34010 can set output interrupt? */
+ if (!(oldreg & 0x0080) && (newreg & 0x0080))
+ {
+ if (state.config->output_int)
+ (*state.config->output_int)(1);
+ }
+ else if ((oldreg & 0x0080) && !(newreg & 0x0080))
+ {
+ if (state.config->output_int)
+ (*state.config->output_int)(0);
+ }
+
+ /* input interrupt? (should really be state-based, but the functions don't exist!) */
+ if (!(oldreg & 0x0008) && (newreg & 0x0008))
+ timer_call_after_resynch(cpunum | (TMS34010_HI << 8), internal_interrupt_callback);
+ else if ((oldreg & 0x0008) && !(newreg & 0x0008))
+ IOREG(REG_INTPEND) &= ~TMS34010_HI;
+ break;
+
+ case REG_CONVSP:
+ state.convsp = 1 << (~data & 0x1f);
+ break;
+
+ case REG_CONVDP:
+ state.convdp = 1 << (~data & 0x1f);
+ break;
+
+ case REG_INTENB:
+ check_interrupt();
+ break;
+
+ case REG_INTPEND:
+ /* X1P, X2P and HIP are read-only */
+ /* WVP and DIP can only have 0's written to them */
+ IOREG(REG_INTPEND) = oldreg;
+ if (!(data & TMS34010_WV))
+ IOREG(REG_INTPEND) &= ~TMS34010_WV;
+ if (!(data & TMS34010_DI))
+ IOREG(REG_INTPEND) &= ~TMS34010_DI;
+ break;
+ }
+
+ if (LOG_CONTROL_REGS)
+ logerror("CPU#%d@%08X: %s = %04X (%d)\n", cpunum, activecpu_get_pc(), ioreg_name[offset], IOREG(offset), video_screen_get_vpos(state.config->scrnum));
+}
+
+
+static const char *ioreg020_name[] =
+{
+ "VESYNC", "HESYNC", "VEBLNK", "HEBLNK",
+ "VSBLNK", "HSBLNK", "VTOTAL", "HTOTAL",
+ "DPYCTL", "DPYSTRT", "DPYINT", "CONTROL",
+ "HSTDATA", "HSTADRL", "HSTADRH", "HSTCTLL",
+
+ "HSTCTLH", "INTENB", "INTPEND", "CONVSP",
+ "CONVDP", "PSIZE", "PMASKL", "PMASKH",
+ "CONVMP", "CONTROL2", "CONFIG", "DPYTAP",
+ "VCOUNT", "HCOUNT", "DPYADR", "REFADR",
+
+ "DPYSTL", "DPYSTH", "DPYNXL", "DPYNXH",
+ "DINCL", "DINCH", "RES0", "HESERR",
+ "RES1", "RES2", "RES3", "RES4",
+ "SCOUNT", "BSFLTST", "DPYMSK", "RES5",
+
+ "SETVCNT", "SETHCNT", "BSFLTDL", "BSFLTDH",
+ "RES6", "RES7", "RES8", "RES9",
+ "IHOST1L", "IHOST1H", "IHOST2L", "IHOST2H",
+ "IHOST3L", "IHOST3H", "IHOST4L", "IHOST4H"
+};
+
+WRITE16_HANDLER( tms34020_io_register_w )
+{
+ int cpunum = cpu_getactivecpu();
+ int oldreg, newreg;
+
+ /* Set register */
+ oldreg = IOREG(offset);
+ IOREG(offset) = data;
+
+ if (LOG_CONTROL_REGS)
+ logerror("CPU#%d@%08X: %s = %04X (%d)\n", cpunum, activecpu_get_pc(), ioreg020_name[offset], IOREG(offset), video_screen_get_vpos(state.config->scrnum));
+
+ switch (offset)
+ {
+ case REG020_CONTROL:
+ case REG020_CONTROL2:
+ IOREG(REG020_CONTROL) = data;
+ IOREG(REG020_CONTROL2) = data;
+ set_raster_op();
+ set_pixel_function();
+ break;
+
+ case REG020_PSIZE:
+ set_pixel_function();
+
+ switch (data)
+ {
+ default:
+ case 0x01: state.pixelshift = 0; break;
+ case 0x02: state.pixelshift = 1; break;
+ case 0x04: state.pixelshift = 2; break;
+ case 0x08: state.pixelshift = 3; break;
+ case 0x10: state.pixelshift = 4; break;
+ }
+ break;
+
+ case REG020_PMASKL:
+ case REG020_PMASKH:
+ if (data) logerror("Plane masking not supported. PC=%08X\n", activecpu_get_pc());
+ break;
+
+ case REG020_DPYCTL:
+ set_pixel_function();
+ break;
+
+ case REG020_HSTCTLH:
+ /* if the CPU is halting itself, stop execution right away */
+ if ((data & 0x8000) && !external_host_access)
+ tms34010_ICount = 0;
+ cpunum_set_input_line(cpunum, INPUT_LINE_HALT, (data & 0x8000) ? ASSERT_LINE : CLEAR_LINE);
+
+ /* NMI issued? */
+ if (data & 0x0100)
+ timer_call_after_resynch(cpunum, internal_interrupt_callback);
+ break;
+
+ case REG020_HSTCTLL:
+ /* the TMS34010 can change MSGOUT, can set INTOUT, and can clear INTIN */
+ if (!external_host_access)
+ {
+ newreg = (oldreg & 0xff8f) | (data & 0x0070);
+ newreg |= data & 0x0080;
+ newreg &= data | ~0x0008;
+ }
+
+ /* the host can change MSGIN, can set INTIN, and can clear INTOUT */
+ else
+ {
+ newreg = (oldreg & 0xfff8) | (data & 0x0007);
+ newreg &= data | ~0x0080;
+ newreg |= data & 0x0008;
+ }
+ IOREG(offset) = newreg;
+
+ /* the TMS34010 can set output interrupt? */
+ if (!(oldreg & 0x0080) && (newreg & 0x0080))
+ {
+ if (state.config->output_int)
+ (*state.config->output_int)(1);
+ }
+ else if ((oldreg & 0x0080) && !(newreg & 0x0080))
+ {
+ if (state.config->output_int)
+ (*state.config->output_int)(0);
+ }
+
+ /* input interrupt? (should really be state-based, but the functions don't exist!) */
+ if (!(oldreg & 0x0008) && (newreg & 0x0008))
+ timer_call_after_resynch(cpunum | (TMS34010_HI << 8), internal_interrupt_callback);
+ else if ((oldreg & 0x0008) && !(newreg & 0x0008))
+ IOREG(REG020_INTPEND) &= ~TMS34010_HI;
+ break;
+
+ case REG020_INTENB:
+ check_interrupt();
+ break;
+
+ case REG020_INTPEND:
+ /* X1P, X2P and HIP are read-only */
+ /* WVP and DIP can only have 0's written to them */
+ IOREG(REG020_INTPEND) = oldreg;
+ if (!(data & TMS34010_WV))
+ IOREG(REG020_INTPEND) &= ~TMS34010_WV;
+ if (!(data & TMS34010_DI))
+ IOREG(REG020_INTPEND) &= ~TMS34010_DI;
+ break;
+
+ case REG020_CONVSP:
+ if (data & 0x001f)
+ {
+ if (data & 0x1f00)
+ state.convsp = (1 << (~data & 0x1f)) + (1 << (~(data >> 8) & 0x1f));
+ else
+ state.convsp = 1 << (~data & 0x1f);
+ }
+ else
+ state.convsp = data;
+ break;
+
+ case REG020_CONVDP:
+ if (data & 0x001f)
+ {
+ if (data & 0x1f00)
+ state.convdp = (1 << (~data & 0x1f)) + (1 << (~(data >> 8) & 0x1f));
+ else
+ state.convdp = 1 << (~data & 0x1f);
+ }
+ else
+ state.convdp = data;
+ break;
+
+ case REG020_CONVMP:
+ if (data & 0x001f)
+ {
+ if (data & 0x1f00)
+ state.convmp = (1 << (~data & 0x1f)) + (1 << (~(data >> 8) & 0x1f));
+ else
+ state.convmp = 1 << (~data & 0x1f);
+ }
+ else
+ state.convmp = data;
+ break;
+
+ case REG020_DPYSTRT:
+ case REG020_DPYADR:
+ case REG020_DPYTAP:
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ I/O REGISTER READS
+***************************************************************************/
+
+READ16_HANDLER( tms34010_io_register_r )
+{
+ int cpunum = cpu_getactivecpu();
+ int result, total;
+
+ if (LOG_CONTROL_REGS)
+ logerror("CPU#%d@%08X: read %s\n", cpunum, activecpu_get_pc(), ioreg_name[offset]);
+
+ switch (offset)
+ {
+ case REG_HCOUNT:
+ /* scale the horizontal position from screen width to HTOTAL */
+ result = video_screen_get_hpos(state.config->scrnum);
+ total = IOREG(REG_HTOTAL) + 1;
+ result = result * total / Machine->screen[state.config->scrnum].width;
+
+ /* offset by the HBLANK end */
+ result += IOREG(REG_HEBLNK);
+
+ /* wrap around */
+ if (result > total)
+ result -= total;
+ return result;
+
+ case REG_REFCNT:
+ return (activecpu_gettotalcycles() / 16) & 0xfffc;
+
+ case REG_INTPEND:
+ result = IOREG(offset);
+
+ /* Cool Pool loops in mainline code on the appearance of the DI, even though they */
+ /* have an IRQ handler. For this reason, we return it signalled a bit early in order */
+ /* to make it past these loops. */
+ if (SMART_IOREG(VCOUNT) + 1 == SMART_IOREG(DPYINT) &&
+ attotime_compare(timer_timeleft(state.scantimer), ATTOTIME_IN_HZ(40000000/TMS34010_CLOCK_DIVIDER/3)) < 0)
+ result |= TMS34010_DI;
+ return result;
+ }
+
+ return IOREG(offset);
+}
+
+
+READ16_HANDLER( tms34020_io_register_r )
+{
+ int cpunum = cpu_getactivecpu();
+ int result, total;
+
+ if (LOG_CONTROL_REGS)
+ logerror("CPU#%d@%08X: read %s\n", cpunum, activecpu_get_pc(), ioreg_name[offset]);
+
+ switch (offset)
+ {
+ case REG020_HCOUNT:
+ /* scale the horizontal position from screen width to HTOTAL */
+ result = video_screen_get_hpos(state.config->scrnum);
+ total = IOREG(REG020_HTOTAL) + 1;
+ result = result * total / Machine->screen[state.config->scrnum].width;
+
+ /* offset by the HBLANK end */
+ result += IOREG(REG020_HEBLNK);
+
+ /* wrap around */
+ if (result > total)
+ result -= total;
+ return result;
+
+ case REG020_REFADR:
+ {
+ int refreshrate = (IOREG(REG020_CONFIG) >> 8) & 7;
+ if (refreshrate < 6)
+ return (activecpu_gettotalcycles() / refreshrate) & 0xffff;
+ break;
+ }
+ }
+
+ return IOREG(offset);
+}
+
+
+
+/***************************************************************************
+ UTILITY FUNCTIONS
+***************************************************************************/
+
+int tms34010_io_display_blanked(int cpu)
+{
+ int result;
+ cpuintrf_push_context(cpu);
+ result = !(IOREG(REG_DPYCTL) & 0x8000);
+ cpuintrf_pop_context();
+ return result;
+}
+
+
+int tms34020_io_display_blanked(int cpu)
+{
+ int result;
+ cpuintrf_push_context(cpu);
+ result = !(IOREG(REG020_DPYCTL) & 0x8000);
+ cpuintrf_pop_context();
+ return result;
+}
+
+
+int tms34010_get_DPYSTRT(int cpu)
+{
+ int result;
+ cpuintrf_push_context(cpu);
+ result = IOREG(REG_DPYSTRT);
+ cpuintrf_pop_context();
+ return result;
+}
+
+
+int tms34020_get_DPYSTRT(int cpu)
+{
+ int result;
+ cpuintrf_push_context(cpu);
+ result = (IOREG(REG020_DPYSTH) << 16) | (IOREG(REG020_DPYSTL) & ~0x1f);
+ cpuintrf_pop_context();
+ return result;
+}
+
+
+
+/***************************************************************************
+ SAVE STATE
+***************************************************************************/
+
+static void tms34010_state_postload(void)
+{
+ change_pc(TOBYTE(PC));
+ set_raster_op();
+ set_pixel_function();
+}
+
+
+/***************************************************************************
+ HOST INTERFACE WRITES
+***************************************************************************/
+
+void tms34010_host_w(int cpunum, int reg, int data)
+{
+ unsigned int addr;
+
+ /* swap to the target cpu */
+ cpuintrf_push_context(cpunum);
+
+ switch (reg)
+ {
+ /* upper 16 bits of the address */
+ case TMS34010_HOST_ADDRESS_H:
+ IOREG(REG_HSTADRH) = data;
+ break;
+
+ /* lower 16 bits of the address */
+ case TMS34010_HOST_ADDRESS_L:
+ IOREG(REG_HSTADRL) = data;
+ break;
+
+ /* actual data */
+ case TMS34010_HOST_DATA:
+
+ /* write to the address */
+ addr = (IOREG(REG_HSTADRH) << 16) | IOREG(REG_HSTADRL);
+ TMS34010_WRMEM_WORD(TOBYTE(addr & 0xfffffff0), data);
+
+ /* optional postincrement */
+ if (IOREG(REG_HSTCTLH) & 0x0800)
+ {
+ addr += 0x10;
+ IOREG(REG_HSTADRH) = addr >> 16;
+ IOREG(REG_HSTADRL) = (UINT16)addr;
+ }
+ break;
+
+ /* control register */
+ case TMS34010_HOST_CONTROL:
+ external_host_access = TRUE;
+ tms34010_io_register_w(REG_HSTCTLH, data & 0xff00, 0);
+ tms34010_io_register_w(REG_HSTCTLL, data & 0x00ff, 0);
+ external_host_access = FALSE;
+ break;
+
+ /* error case */
+ default:
+ logerror("tms34010_host_control_w called on invalid register %d\n", reg);
+ break;
+ }
+
+ /* swap back */
+ cpuintrf_pop_context();
+ activecpu_reset_banking();
+}
+
+
+
+/***************************************************************************
+ HOST INTERFACE READS
+***************************************************************************/
+
+int tms34010_host_r(int cpunum, int reg)
+{
+ unsigned int addr;
+ int result = 0;
+
+ /* swap to the target cpu */
+ cpuintrf_push_context(cpunum);
+
+ switch (reg)
+ {
+ /* upper 16 bits of the address */
+ case TMS34010_HOST_ADDRESS_H:
+ result = IOREG(REG_HSTADRH);
+ break;
+
+ /* lower 16 bits of the address */
+ case TMS34010_HOST_ADDRESS_L:
+ result = IOREG(REG_HSTADRL);
+ break;
+
+ /* actual data */
+ case TMS34010_HOST_DATA:
+
+ /* read from the address */
+ addr = (IOREG(REG_HSTADRH) << 16) | IOREG(REG_HSTADRL);
+ result = TMS34010_RDMEM_WORD(TOBYTE(addr & 0xfffffff0));
+
+ /* optional postincrement (it says preincrement, but data is preloaded, so it
+ is effectively a postincrement */
+ if (IOREG(REG_HSTCTLH) & 0x1000)
+ {
+ addr += 0x10;
+ IOREG(REG_HSTADRH) = addr >> 16;
+ IOREG(REG_HSTADRL) = (UINT16)addr;
+ }
+ break;
+
+ /* control register */
+ case TMS34010_HOST_CONTROL:
+ result = (IOREG(REG_HSTCTLH) & 0xff00) | (IOREG(REG_HSTCTLL) & 0x00ff);
+ break;
+
+ /* error case */
+ default:
+ logerror("tms34010_host_control_r called on invalid register %d\n", reg);
+ break;
+ }
+
+ /* swap back */
+ cpuintrf_pop_context();
+ activecpu_reset_banking();
+
+ return result;
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void tms34010_set_info(UINT32 _state, cpuinfo *info)
+{
+ switch (_state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+
+ case CPUINFO_INT_PC: PC = info->i; change_pc(TOBYTE(PC)); break;
+ case CPUINFO_INT_REGISTER + TMS34010_PC: PC = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS34010_SP: SP = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_ST: ST = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A0: AREG(0) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A1: AREG(1) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A2: AREG(2) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A3: AREG(3) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A4: AREG(4) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A5: AREG(5) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A6: AREG(6) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A7: AREG(7) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A8: AREG(8) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A9: AREG(9) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A10: AREG(10) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A11: AREG(11) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A12: AREG(12) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A13: AREG(13) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A14: AREG(14) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B0: BREG(0) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B1: BREG(1) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B2: BREG(2) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B3: BREG(3) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B4: BREG(4) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B5: BREG(5) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B6: BREG(6) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B7: BREG(7) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B8: BREG(8) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B9: BREG(9) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B10: BREG(10) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B11: BREG(11) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B12: BREG(12) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B13: BREG(13) = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS34010_B14: BREG(14) = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void tms34010_get_info(UINT32 _state, cpuinfo *info)
+{
+ switch (_state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = TMS34010_STATE_SIZE; break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = TMS34010_CLOCK_DIVIDER; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 10; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 10000; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 3; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = (IOREG(REG_INTPEND) & TMS34010_INT1) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + 1: info->i = (IOREG(REG_INTPEND) & TMS34010_INT2) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS34010_PC: info->i = PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS34010_SP: info->i = SP; break;
+ case CPUINFO_INT_REGISTER + TMS34010_ST: info->i = ST; break;
+ case CPUINFO_INT_REGISTER + TMS34010_A0: info->i = AREG(0); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A1: info->i = AREG(1); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A2: info->i = AREG(2); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A3: info->i = AREG(3); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A4: info->i = AREG(4); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A5: info->i = AREG(5); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A6: info->i = AREG(6); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A7: info->i = AREG(7); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A8: info->i = AREG(8); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A9: info->i = AREG(9); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A10: info->i = AREG(10); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A11: info->i = AREG(11); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A12: info->i = AREG(12); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A13: info->i = AREG(13); break;
+ case CPUINFO_INT_REGISTER + TMS34010_A14: info->i = AREG(14); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B0: info->i = BREG(0); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B1: info->i = BREG(1); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B2: info->i = BREG(2); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B3: info->i = BREG(3); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B4: info->i = BREG(4); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B5: info->i = BREG(5); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B6: info->i = BREG(6); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B7: info->i = BREG(7); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B8: info->i = BREG(8); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B9: info->i = BREG(9); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B10: info->i = BREG(10); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B11: info->i = BREG(11); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B12: info->i = BREG(12); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B13: info->i = BREG(13); break;
+ case CPUINFO_INT_REGISTER + TMS34010_B14: info->i = BREG(14); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = tms34010_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tms34010_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tms34010_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = tms34010_init; break;
+ case CPUINFO_PTR_RESET: info->reset = tms34010_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = tms34010_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = tms34010_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tms34010_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &tms34010_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "TMS34010"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Texas Instruments 340x0"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) Alex Pasadyn/Zsolt Vasvari 1998\nParts based on code by Aaron Giles"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ state.st & 0x80000000 ? 'N':'.',
+ state.st & 0x40000000 ? 'C':'.',
+ state.st & 0x20000000 ? 'Z':'.',
+ state.st & 0x10000000 ? 'V':'.',
+ state.st & 0x02000000 ? 'P':'.',
+ state.st & 0x00200000 ? 'I':'.',
+ state.st & 0x00000800 ? 'E':'.',
+ state.st & 0x00000400 ? 'F':'.',
+ state.st & 0x00000200 ? 'F':'.',
+ state.st & 0x00000100 ? 'F':'.',
+ state.st & 0x00000080 ? 'F':'.',
+ state.st & 0x00000040 ? 'F':'.',
+ state.st & 0x00000020 ? 'E':'.',
+ state.st & 0x00000010 ? 'F':'.',
+ state.st & 0x00000008 ? 'F':'.',
+ state.st & 0x00000004 ? 'F':'.',
+ state.st & 0x00000002 ? 'F':'.',
+ state.st & 0x00000001 ? 'F':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + TMS34010_PC: sprintf(info->s, "PC :%08X", state.pc); break;
+ case CPUINFO_STR_REGISTER + TMS34010_SP: sprintf(info->s, "SP :%08X", AREG(15)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_ST: sprintf(info->s, "ST :%08X", state.st); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A0: sprintf(info->s, "A0 :%08X", AREG( 0)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A1: sprintf(info->s, "A1 :%08X", AREG( 1)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A2: sprintf(info->s, "A2 :%08X", AREG( 2)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A3: sprintf(info->s, "A3 :%08X", AREG( 3)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A4: sprintf(info->s, "A4 :%08X", AREG( 4)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A5: sprintf(info->s, "A5 :%08X", AREG( 5)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A6: sprintf(info->s, "A6 :%08X", AREG( 6)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A7: sprintf(info->s, "A7 :%08X", AREG( 7)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A8: sprintf(info->s, "A8 :%08X", AREG( 8)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A9: sprintf(info->s, "A9 :%08X", AREG( 9)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A10: sprintf(info->s,"A10:%08X", AREG(10)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A11: sprintf(info->s,"A11:%08X", AREG(11)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A12: sprintf(info->s,"A12:%08X", AREG(12)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A13: sprintf(info->s,"A13:%08X", AREG(13)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_A14: sprintf(info->s,"A14:%08X", AREG(14)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B0: sprintf(info->s, "B0 :%08X", BREG( 0)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B1: sprintf(info->s, "B1 :%08X", BREG( 1)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B2: sprintf(info->s, "B2 :%08X", BREG( 2)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B3: sprintf(info->s, "B3 :%08X", BREG( 3)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B4: sprintf(info->s, "B4 :%08X", BREG( 4)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B5: sprintf(info->s, "B5 :%08X", BREG( 5)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B6: sprintf(info->s, "B6 :%08X", BREG( 6)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B7: sprintf(info->s, "B7 :%08X", BREG( 7)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B8: sprintf(info->s, "B8 :%08X", BREG( 8)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B9: sprintf(info->s, "B9 :%08X", BREG( 9)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B10: sprintf(info->s,"B10:%08X", BREG(10)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B11: sprintf(info->s,"B11:%08X", BREG(11)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B12: sprintf(info->s,"B12:%08X", BREG(12)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B13: sprintf(info->s,"B13:%08X", BREG(13)); break;
+ case CPUINFO_STR_REGISTER + TMS34010_B14: sprintf(info->s,"B14:%08X", BREG(14)); break;
+ }
+}
+
+
+#if (HAS_TMS34020)
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void tms34020_get_info(UINT32 _state, cpuinfo *info)
+{
+ switch (_state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = TMS34020_STATE_SIZE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = TMS34020_CLOCK_DIVIDER; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tms34020_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tms34020_set_context; break;
+ case CPUINFO_PTR_RESET: info->reset = tms34020_reset; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tms34020_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "TMS34020"); break;
+
+ default: tms34010_get_info(_state, info); break;
+ }
+}
+#endif
diff --git a/src/emu/cpu/tms34010/tms34010.h b/src/emu/cpu/tms34010/tms34010.h
new file mode 100644
index 00000000000..b1cc4f01128
--- /dev/null
+++ b/src/emu/cpu/tms34010/tms34010.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+
+ TMS34010: Portable Texas Instruments TMS34010 emulator
+
+ Copyright (C) Alex Pasadyn/Zsolt Vasvari 1998
+ Parts based on code by Aaron Giles
+
+***************************************************************************/
+
+#ifndef _TMS34010_H
+#define _TMS34010_H
+
+#include "cpuintrf.h"
+#include "driver.h"
+
+
+/* the TMS34010 input clock is divided by 8; the 34020 by 4 */
+#define TMS34010_CLOCK_DIVIDER 8
+#define TMS34020_CLOCK_DIVIDER 4
+
+
+/* register indexes for get_reg and set_reg */
+enum
+{
+ TMS34010_PC = 1,
+ TMS34010_SP,
+ TMS34010_ST,
+ TMS34010_A0,
+ TMS34010_A1,
+ TMS34010_A2,
+ TMS34010_A3,
+ TMS34010_A4,
+ TMS34010_A5,
+ TMS34010_A6,
+ TMS34010_A7,
+ TMS34010_A8,
+ TMS34010_A9,
+ TMS34010_A10,
+ TMS34010_A11,
+ TMS34010_A12,
+ TMS34010_A13,
+ TMS34010_A14,
+ TMS34010_B0,
+ TMS34010_B1,
+ TMS34010_B2,
+ TMS34010_B3,
+ TMS34010_B4,
+ TMS34010_B5,
+ TMS34010_B6,
+ TMS34010_B7,
+ TMS34010_B8,
+ TMS34010_B9,
+ TMS34010_B10,
+ TMS34010_B11,
+ TMS34010_B12,
+ TMS34010_B13,
+ TMS34010_B14
+};
+
+
+/* Configuration structure */
+typedef struct _tms34010_display_params tms34010_display_params;
+struct _tms34010_display_params
+{
+ UINT16 vcount; /* most recent VCOUNT */
+ UINT16 veblnk, vsblnk; /* start/end of VBLANK */
+ UINT16 heblnk, hsblnk; /* start/end of HBLANK */
+ UINT16 rowaddr, coladdr; /* row/column addresses */
+ UINT8 yoffset; /* y offset from addresses */
+ UINT8 enabled; /* video enabled */
+};
+
+
+typedef struct _tms34010_config tms34010_config;
+struct _tms34010_config
+{
+ UINT8 halt_on_reset; /* /HCS pin, which determines HALT state after reset */
+ UINT8 scrnum; /* the screen operated on */
+ UINT32 pixclock; /* the pixel clock (0 means don't adjust screen size) */
+ int pixperclock; /* pixels per clock */
+ void (*scanline_callback)(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params);
+ void (*output_int)(int state); /* output interrupt callback */
+ void (*to_shiftreg)(offs_t, UINT16 *); /* shift register write */
+ void (*from_shiftreg)(offs_t, UINT16 *); /* shift register read */
+};
+
+
+/* PUBLIC FUNCTIONS - 34010 */
+VIDEO_UPDATE( tms340x0 );
+void tms34010_get_display_params(int cpunum, tms34010_display_params *params);
+
+void tms34010_get_info(UINT32 state, cpuinfo *info);
+
+int tms34010_io_display_blanked(int cpu);
+int tms34010_get_DPYSTRT(int cpu);
+
+
+/* PUBLIC FUNCTIONS - 34020 */
+void tms34020_get_info(UINT32 state, cpuinfo *info);
+
+int tms34020_io_display_blanked(int cpu);
+int tms34020_get_DPYSTRT(int cpu);
+
+
+
+/* Host control interface */
+#define TMS34010_HOST_ADDRESS_L 0
+#define TMS34010_HOST_ADDRESS_H 1
+#define TMS34010_HOST_DATA 2
+#define TMS34010_HOST_CONTROL 3
+
+void tms34010_host_w(int cpunum, int reg, int data);
+int tms34010_host_r(int cpunum, int reg);
+
+
+/* Reads & writes to the 34010 I/O registers; place at 0xc0000000 */
+WRITE16_HANDLER( tms34010_io_register_w );
+READ16_HANDLER( tms34010_io_register_r );
+
+/* Reads & writes to the 34020 I/O registers; place at 0xc0000000 */
+WRITE16_HANDLER( tms34020_io_register_w );
+READ16_HANDLER( tms34020_io_register_r );
+
+
+/* Use this macro in the memory definitions to specify bit-based addresses */
+#define TOBYTE(bitaddr) ((offs_t)(bitaddr) >> 3)
+#define TOWORD(bitaddr) ((offs_t)(bitaddr) >> 4)
+
+
+#ifdef MAME_DEBUG
+offs_t tms34010_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t tms34020_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* _TMS34010_H */
diff --git a/src/emu/cpu/tms7000/7000dasm.c b/src/emu/cpu/tms7000/7000dasm.c
new file mode 100644
index 00000000000..3048c0f1689
--- /dev/null
+++ b/src/emu/cpu/tms7000/7000dasm.c
@@ -0,0 +1,445 @@
+#include "debugger.h"
+#include "tms7000.h"
+
+typedef enum { DONE, NONE, UI8, I8, UI16, I16, PCREL, PCABS, TRAP } operandtype;
+
+typedef struct {
+ char opstr[4][12];
+ operandtype decode[4];
+} oprandinfo;
+
+typedef struct {
+ int opcode;
+ char name[7];
+ int operand;
+ UINT32 s_flag;
+} opcodeinfo;
+
+static oprandinfo of[] = {
+/* 00 */ { {" B,A", "", "", ""}, {NONE, DONE, DONE, DONE} },
+/* 01 */ { {" R%u", ",A", "", ""}, {UI8, NONE, DONE, DONE} },
+/* 02 */ { {" R%u", ",B", "", ""}, {UI8, NONE, DONE, DONE} },
+/* 03 */ { {" R%u", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} },
+/* 04 */ { {" %%>%X", ",A", "", ""}, {UI8, NONE, DONE, DONE} },
+/* 05 */ { {" %%>%X", ",B", "", ""}, {UI8, NONE, DONE, DONE} },
+/* 06 */ { {" %%>%X", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} },
+
+/* 07 */ { {" A", ",P%u", "", ""}, {NONE,UI8,DONE,DONE} },
+/* 08 */ { {" B", ",P%u", "", ""}, {NONE,UI8,DONE,DONE} },
+/* 09 */ { {" %%>%02X", ",P%u", "", ""}, {UI8,UI8,DONE,DONE} },
+
+/* 10 */ { {" @>%04X", "", "", ""}, {UI16,DONE,DONE,DONE} },
+/* 11 */ { {" R%u", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 12 */ { {" @>%04X(B)","", "", ""}, {UI16, DONE, DONE, DONE} },
+
+/* 13 */ { {" B,A", ",%s", "", ""}, {NONE, PCREL, DONE, DONE} },
+/* 14 */ { {" R%u,A", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 15 */ { {" R%u,B", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 16 */ { {" R%u", ",R%u", ",%s", ""}, {UI8, UI8, PCREL, DONE} },
+/* 17 */ { {" %%>%X", ",A,%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 18 */ { {" %%>%X", ",B,%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 19 */ { {" %%>%X", ",R%u", ",%s", ""}, {UI8, UI8, PCREL, DONE} },
+
+/* 20 */ { {" A,P%u", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 21 */ { {" B,P%u", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 22 */ { {" %%>%02X", ",P%u", ",%s" ""}, {UI8, UI8, PCREL, DONE} },
+
+/* 23 */ { {"", "", "", ""}, {DONE, DONE, DONE, DONE} },
+/* 24 */ { {" R%u", "", "", ""}, {UI8, DONE, DONE, DONE} },
+
+/* 25 */ { {" A,%s", "", "", ""}, {PCREL, DONE, DONE, DONE} },
+/* 26 */ { {" B,%s", "", "", ""}, {PCREL, DONE, DONE, DONE} },
+/* 27 */ { {" R%u", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+
+/* 28 */ { {" %s", "", "", ""}, {PCREL, DONE, DONE, DONE} },
+
+/* 29 */ { {" A,B", "", "", ""}, {NONE, DONE, DONE, DONE} },
+/* 30 */ { {" B,A", "", "", ""}, {NONE, DONE, DONE, DONE} },
+/* 31 */ { {" A,R%u", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 32 */ { {" B,R%u", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 33 */ { {" R%u,A", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 34 */ { {" R%u,B", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 35 */ { {" R%u", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} },
+/* 36 */ { {" %%>%X,A", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 37 */ { {" %%>%X,B", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 38 */ { {" %%>%X", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} },
+
+/* 39 */ { {" %%>%04X",",R%u", "", ""}, {UI16, UI8, DONE, DONE} },
+/* 40 */ { {" %%>%04X(B)",",R%u", "", ""}, {UI16, UI8, DONE, DONE} },
+
+/* 41 */ { {" P%u,A", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 42 */ { {" P%u,B", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 43 */ { {" %s", "", "", ""}, {PCABS, DONE, DONE, DONE} },
+/* 44 */ { {"", "", "", ""}, {TRAP, DONE, DONE, DONE} }, /* Only For TRAP */
+
+/* 45 */ { {" *R%u", "", "", ""}, {UI8, DONE, DONE, DONE} }
+};
+
+static opcodeinfo opcodes[] = {
+ {0x69, "ADC", 0, 0 },
+ {0x19, "ADC", 1, 0 },
+ {0x39, "ADC", 2, 0 },
+ {0x49, "ADC", 3, 0 },
+ {0x29, "ADC", 4, 0 },
+ {0x59, "ADC", 5, 0 },
+ {0x79, "ADC", 6, 0 },
+
+ {0x68, "ADD", 0, 0 },
+ {0x18, "ADD", 1, 0 },
+ {0x38, "ADD", 2, 0 },
+ {0x48, "ADD", 3, 0 },
+ {0x28, "ADD", 4, 0 },
+ {0x58, "ADD", 5, 0 },
+ {0x78, "ADD", 6, 0 },
+
+ {0x63, "AND", 0, 0 },
+ {0x13, "AND", 1, 0 },
+ {0x33, "AND", 2, 0 },
+ {0x43, "AND", 3, 0 },
+ {0x23, "AND", 4, 0 },
+ {0x53, "AND", 5, 0 },
+ {0x73, "AND", 6, 0 },
+
+ {0x83, "ANDP", 7, 0 },
+ {0x93, "ANDP", 8, 0 },
+ {0xA3, "ANDP", 9, 0 },
+
+ {0x8C, "BR", 43, 0 },
+ {0x9C, "BR", 45, 0 },
+ {0xAC, "BR", 12, 0 },
+
+ {0x66, "BTJO", 13, 0 },
+ {0x16, "BTJO", 14, 0 },
+ {0x36, "BTJO", 15, 0 },
+ {0x46, "BTJO", 16, 0 },
+ {0x26, "BTJO", 17, 0 },
+ {0x56, "BTJO", 18, 0 },
+ {0x76, "BTJO", 19, 0 },
+
+ {0x86, "BTJOP", 20, 0 },
+ {0x96, "BTJOP", 21, 0 },
+ {0xA6, "BTJOP", 22, 0 },
+
+ {0x67, "BTJZ", 13, 0 },
+ {0x17, "BTJZ", 14, 0 },
+ {0x37, "BTJZ", 15, 0 },
+ {0x47, "BTJZ", 16, 0 },
+ {0x27, "BTJZ", 17, 0 },
+ {0x57, "BTJZ", 18, 0 },
+ {0x77, "BTJZ", 19, 0 },
+
+ {0x87, "BTJZP", 20, 0 },
+ {0x97, "BTJZP", 21, 0 },
+ {0xA7, "BTJZP", 22, 0 },
+
+ {0x8E, "CALL", 43, DASMFLAG_STEP_OVER },
+ {0x9E, "CALL", 45, DASMFLAG_STEP_OVER },
+ {0xAE, "CALL", 12, DASMFLAG_STEP_OVER },
+
+ {0xB5, "CLR A", 23, 0 },
+ {0xC5, "CLR B", 23, 0 },
+ {0xD5, "CLR", 24, 0 },
+
+ {0xB0, "CLRC", 23, 0 },
+
+ {0x6D, "CMP", 0, 0 },
+ {0x1D, "CMP", 1, 0 },
+ {0x3D, "CMP", 2, 0 },
+ {0x4D, "CMP", 3, 0 },
+ {0x2D, "CMP", 4, 0 },
+ {0x5D, "CMP", 5, 0 },
+ {0x7D, "CMP", 6, 0 },
+
+ {0x8D, "CMPA", 10, 0 },
+ {0x9D, "CMPA", 45, 0 },
+ {0xAD, "CMPA", 12, 0 },
+
+ {0x6E, "DAC", 0, 0 },
+ {0x1E, "DAC", 1, 0 },
+ {0x3E, "DAC", 2, 0 },
+ {0x4E, "DAC", 3, 0 },
+ {0x2E, "DAC", 4, 0 },
+ {0x5E, "DAC", 5, 0 },
+ {0x7E, "DAC", 6, 0 },
+
+ {0xB2, "DEC A", 23, 0 },
+ {0xC2, "DEC B", 23, 0 },
+ {0xD2, "DEC", 24, 0 },
+
+ {0xBB, "DECD A", 23, 0 },
+ {0xCB, "DECD B", 23, 0 },
+ {0xDB, "DECD", 24, 0 },
+
+ {0x06, "DINT", 23, 0 },
+
+ {0xBA, "DJNZ", 25, 0 },
+ {0xCA, "DJNZ", 26, 0 },
+ {0xDA, "DJNZ", 27, 0 },
+
+ {0x6F, "DSB", 0, 0 },
+ {0x1F, "DSB", 1, 0 },
+ {0x3F, "DSB", 2, 0 },
+ {0x4F, "DSB", 3, 0 },
+ {0x2F, "DSB", 4, 0 },
+ {0x5F, "DSB", 5, 0 },
+ {0x7F, "DSB", 6, 0 },
+
+ {0x05, "EINT", 23, 0 },
+
+ {0x01, "IDLE", 23, 0 },
+
+ {0xB3, "INC A", 23, 0 },
+ {0xC3, "INC B", 23, 0 },
+ {0xD3, "INC", 24, 0 },
+
+ {0xB4, "INV A", 23, 0 },
+ {0xC4, "INV B", 23, 0 },
+ {0xD4, "INV", 24, 0 },
+
+ {0xE2, "JEQ", 28, 0 },
+ {0xE3, "JHS", 28, 0 },
+ {0xE7, "JL", 28, 0 },
+ {0xE0, "JMP", 28, 0 },
+ {0xE1, "JN", 28, 0 },
+ {0xE6, "JNZ", 28, 0 },
+ {0xE4, "JP", 28, 0 },
+ {0xE5, "JPI", 28, 0 },
+
+ {0x8A, "LDA", 10, 0 },
+ {0x9A, "LDA", 45, 0 },
+ {0xAA, "LDA", 12, 0 },
+
+ {0x0D, "LDSP", 23, 0 },
+
+ {0xC0, "MOV", 29, 0 },
+ {0x62, "MOV", 30, 0 },
+ {0xD0, "MOV", 31, 0 },
+ {0xD1, "MOV", 32, 0 },
+ {0x12, "MOV", 33, 0 },
+ {0x32, "MOV", 34, 0 },
+ {0x42, "MOV", 35, 0 },
+ {0x22, "MOV", 36, 0 },
+ {0x52, "MOV", 37, 0 },
+ {0x72, "MOV", 38, 0 },
+
+ {0x88, "MOVD", 39, 0 },
+ {0x98, "MOVD", 35, 0 },
+ {0xA8, "MOVD", 40, 0 },
+
+ {0x82, "MOVP", 7, 0 },
+ {0x92, "MOVP", 8, 0 },
+ {0xA2, "MOVP", 9, 0 },
+ {0x80, "MOVP", 41, 0 },
+ {0x91, "MOVP", 42, 0 },
+
+ {0x6C, "MPY", 00, 0 },
+ {0x1C, "MPY", 01, 0 },
+ {0x3C, "MPY", 02, 0 },
+ {0x4C, "MPY", 03, 0 },
+ {0x2C, "MPY", 04, 0 },
+ {0x5C, "MPY", 05, 0 },
+ {0x7C, "MPY", 06, 0 },
+
+ {0x00, "NOP", 23, 0 },
+
+ {0x64, "OR", 00, 0 },
+ {0x14, "OR", 01, 0 },
+ {0x34, "OR", 02, 0 },
+ {0x44, "OR", 03, 0 },
+ {0x24, "OR", 04, 0 },
+ {0x54, "OR", 05, 0 },
+ {0x74, "OR", 06, 0 },
+
+ {0x84, "ORP", 7, 0 },
+ {0x94, "ORP", 8, 0 },
+ {0xA4, "ORP", 9, 0 },
+
+ {0xB9, "POP A", 23, 0 },
+ {0xC9, "POP B", 23, 0 },
+ {0xD9, "POP", 24, 0 },
+ {0x08, "POP ST", 23, 0 },
+
+ {0xB8, "PUSH A", 23, 0 },
+ {0xC8, "PUSH B", 23, 0 },
+ {0xD8, "PUSH", 24, 0 },
+ {0x0E, "PUSH ST", 23, 0 },
+
+ {0x0B, "RETI", 23, DASMFLAG_STEP_OUT },
+ {0x0A, "RETS", 23, DASMFLAG_STEP_OUT },
+
+ {0xBE, "RL A", 23, 0 },
+ {0xCE, "RL B", 23, 0 },
+ {0xDE, "RL", 11, 0 },
+
+ {0xBF, "RLC A", 23, 0 },
+ {0xCF, "RLC B", 23, 0 },
+ {0xDF, "RLC", 11, 0 },
+
+ {0xBC, "RR A", 23, 0 },
+ {0xCC, "RR B", 23, 0 },
+ {0xDC, "RR", 11, 0 },
+
+ {0xBD, "RRC A", 23, 0 },
+ {0xCD, "RRC B", 23, 0 },
+ {0xDD, "RRC", 11, 0 },
+
+ {0x6B, "SBB", 0, 0 },
+ {0x1B, "SBB", 1, 0 },
+ {0x3B, "SBB", 2, 0 },
+ {0x4B, "SBB", 3, 0 },
+ {0x2B, "SBB", 4, 0 },
+ {0x5B, "SBB", 5, 0 },
+ {0x7B, "SBB", 6, 0 },
+
+ {0x07, "SETC", 23, 0 },
+
+ {0x8B, "STA", 10, 0 },
+ {0x9B, "STA", 45, 0 },
+ {0xAB, "STA", 12, 0 },
+
+ {0x09, "STSP", 23, 0 },
+
+ {0x6A, "SUB", 0, 0 },
+ {0x1A, "SUB", 1, 0 },
+ {0x3A, "SUB", 2, 0 },
+ {0x4A, "SUB", 3, 0 },
+ {0x2A, "SUB", 4, 0 },
+ {0x5A, "SUB", 5, 0 },
+ {0x7A, "SUB", 6, 0 },
+
+ {0xFF, "TRAP 0", 44, DASMFLAG_STEP_OVER },
+ {0xFE, "TRAP 1", 44, DASMFLAG_STEP_OVER },
+ {0xFD, "TRAP 2", 44, DASMFLAG_STEP_OVER },
+ {0xFC, "TRAP 3", 44, DASMFLAG_STEP_OVER },
+ {0xFB, "TRAP 4", 44, DASMFLAG_STEP_OVER },
+ {0xFA, "TRAP 5", 44, DASMFLAG_STEP_OVER },
+ {0xF9, "TRAP 6", 44, DASMFLAG_STEP_OVER },
+ {0xF8, "TRAP 7", 44, DASMFLAG_STEP_OVER },
+ {0xF7, "TRAP 8", 44, DASMFLAG_STEP_OVER },
+ {0xF6, "TRAP 9", 44, DASMFLAG_STEP_OVER },
+ {0xF5, "TRAP 10", 44, DASMFLAG_STEP_OVER },
+ {0xF4, "TRAP 11", 44, DASMFLAG_STEP_OVER },
+ {0xF3, "TRAP 12", 44, DASMFLAG_STEP_OVER },
+ {0xF2, "TRAP 13", 44, DASMFLAG_STEP_OVER },
+ {0xF1, "TRAP 14", 44, DASMFLAG_STEP_OVER },
+ {0xF0, "TRAP 15", 44, DASMFLAG_STEP_OVER },
+ {0xEF, "TRAP 16", 44, DASMFLAG_STEP_OVER },
+ {0xEE, "TRAP 17", 44, DASMFLAG_STEP_OVER },
+ {0xED, "TRAP 18", 44, DASMFLAG_STEP_OVER },
+ {0xEC, "TRAP 19", 44, DASMFLAG_STEP_OVER },
+ {0xEB, "TRAP 20", 44, DASMFLAG_STEP_OVER },
+ {0xEA, "TRAP 21", 44, DASMFLAG_STEP_OVER },
+ {0xE9, "TRAP 22", 44, DASMFLAG_STEP_OVER },
+ {0xE8, "TRAP 23", 44, DASMFLAG_STEP_OVER },
+
+ {0xB7, "SWAP A", 23, 0 },
+ {0xC7, "SWAP B", 23, 0 },
+ {0xD7, "SWAP", 11, 0 },
+
+ {0xB0, "TSTA", 23, 0 },
+ {0xC1, "TSTB", 23, 0 },
+
+ {0xB6, "XCHB A", 23, 0 },
+ {0xC6, "XCHB B", 23, 0 },
+ {0xD6, "XCHB", 11, 0 },
+
+ {0x65, "XOR", 0, 0 },
+ {0x15, "XOR", 1, 0 },
+ {0x35, "XOR", 2, 0 },
+ {0x45, "XOR", 3, 0 },
+ {0x25, "XOR", 4, 0 },
+ {0x55, "XOR", 5, 0 },
+ {0x75, "XOR", 6, 0 },
+
+ {0x85, "XORP", 7, 0 },
+ {0x95, "XORP", 8, 0 },
+ {0xA5, "XORP", 9, 0 },
+
+ {0x00, "NOP", 23, 0 }
+};
+
+unsigned tms7000_dasm( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram )
+{
+ int opcode, i, size = 1;
+ int pos = 0;
+ char tmpbuf[32];
+
+ opcode = oprom[pos++];
+
+ for( i=0; i<sizeof(opcodes) / sizeof(opcodeinfo); i++ )
+ {
+ if( opcode == opcodes[i].opcode )
+ {
+ /* We found a match */
+
+ int j,k,vector;
+ UINT8 a;
+ INT8 b;
+ UINT16 c;
+ INT16 d;
+
+ buffer += sprintf (buffer, "%s", opcodes[i].name);
+
+ j=opcodes[i].operand;
+
+ for( k=0; k<4; k++ )
+ {
+ switch( of[j].decode[k] )
+ {
+ case DONE:
+ break;
+ case NONE:
+ buffer += sprintf (buffer, "%s", of[j].opstr[k]);
+ break;
+ case UI8:
+ a = (UINT8)opram[pos++];
+ buffer += sprintf(buffer, of[j].opstr[k], (unsigned int)a);
+ size += 1;
+ break;
+ case I8:
+ b = (INT8)opram[pos++];
+ buffer += sprintf (buffer, of[j].opstr[k], (INT8)b);
+ size += 1;
+ break;
+ case UI16:
+ c = (UINT16)opram[pos++];
+ c <<= 8;
+ c += opram[pos++];
+ buffer += sprintf (buffer, of[j].opstr[k], (unsigned int)c);
+ size += 2;
+ break;
+ case I16:
+ d = (INT16)opram[pos++];
+ d <<= 8;
+ d += opram[pos++];
+ buffer += sprintf (buffer, of[j].opstr[k], (signed int)d);
+ size += 2;
+ break;
+ case PCREL:
+ b = (INT8)opram[pos++];
+ sprintf(tmpbuf, "$%04X", pc+2+k);
+ buffer += sprintf (buffer, of[j].opstr[k], tmpbuf);
+ size += 1;
+ break;
+ case PCABS:
+ c = (UINT16)opram[pos++];
+ c <<= 8;
+ c += opram[pos++];
+ sprintf(tmpbuf, "$%04X", c);
+ buffer += sprintf (buffer, of[j].opstr[k], tmpbuf);
+ size += 2;
+ break;
+ case TRAP:
+ vector = 0xffff - ((0xff - opcode) * 2);
+ c = (UINT16)((cpu_readop( vector-1 ) << 8) + cpu_readop( vector ));
+ break;
+ }
+ }
+ return pos | opcodes[i].s_flag | DASMFLAG_SUPPORTED;
+ }
+ }
+
+ /* No Match */
+ strcpy (buffer, "Illegal Opcode");
+ return pos | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/tms7000/tms7000.c b/src/emu/cpu/tms7000/tms7000.c
new file mode 100644
index 00000000000..ad099dae1eb
--- /dev/null
+++ b/src/emu/cpu/tms7000/tms7000.c
@@ -0,0 +1,744 @@
+/*****************************************************************************
+ *
+ * tms7000.c
+ * Portable TMS7000 emulator (Texas Instruments 7000)
+ *
+ * Copyright (c) 2001 tim lindner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * tlindner@macmess.org
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************
+ * Currently this source emulates a TMS70x0, not any of the other variants
+ * Unimplemented is the MC pin which (in conjunection with IOCNT0 bits 7 and 6
+ * control the memory mapping.
+ *
+ * This source implements the MC pin at Vss and mode bits in single chip mode.
+ *****************************************************************************/
+
+// SJE: Changed all references to ICount to icount (to match MAME requirements)
+// SJE: Changed RM/WM macros to reference newly created tms7000 read/write handlers & removed unused SRM() macro
+// SJE: Fixed a mistake in tms70x0_pf_w where the wrong register was referenced
+// SJE: Implemented internal register file
+
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "tms7000.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+/* Private prototypes */
+
+static void tms7000_set_irq_line(int irqline, int state);
+static void tms7000_get_context(void *dst);
+static void tms7000_set_context(void *src);
+static void tms7000_check_IRQ_lines( void );
+static void tms7000_do_interrupt( UINT16 address, UINT8 line );
+static int tms7000_execute(int cycles);
+static int tms7000_exl_execute(int cycles);
+static void tms7000_service_timer1( void );
+static UINT16 bcd_add( UINT16 a, UINT16 b );
+static UINT16 bcd_tencomp( UINT16 a );
+static UINT16 bcd_sub( UINT16 a, UINT16 b);
+
+/* Static variables */
+
+static int tms7000_icount;
+static int tms7000_div_by_16_trigger;
+static int tms7000_cycles_per_INT2;
+
+#define RM(Addr) ((unsigned)program_read_byte_8(Addr))
+#define WM(Addr,Value) (program_write_byte_8(Addr,Value))
+
+INLINE UINT16 RM16( UINT32 mAddr ) /* Read memory (16-bit) */
+{
+ UINT32 result = RM(mAddr) << 8;
+ return result | RM((mAddr+1)&0xffff);
+}
+
+INLINE void WM16( UINT32 mAddr, PAIR p ) /*Write memory file (16 bit) */
+{
+ WM( mAddr, p.b.h );
+ WM( (mAddr+1)&0xffff, p.b.l );
+}
+
+INLINE UINT16 RRF16( UINT32 mAddr ) /*Read register file (16 bit) */
+{
+ PAIR result;
+ result.b.h = RM((mAddr-1)&0xffff);
+ result.b.l = RM(mAddr);
+ return result.w.l;
+}
+
+INLINE void WRF16( UINT32 mAddr, PAIR p ) /*Write register file (16 bit) */
+{
+ WM( (mAddr-1)&0xffff, p.b.h );
+ WM( mAddr, p.b.l );
+}
+
+#define IMMBYTE(b) b = ((unsigned)cpu_readop_arg(pPC)); pPC++
+#define SIMMBYTE(b) b = ((signed)cpu_readop_arg(pPC)); pPC++
+#define IMMWORD(w) w.b.h = (unsigned)cpu_readop_arg(pPC++); w.b.l = (unsigned)cpu_readop_arg(pPC++)
+
+#define PUSHBYTE(b) pSP++; WM(pSP,b)
+#define PUSHWORD(w) pSP++; WM(pSP,w.b.h); pSP++; WM(pSP,w.b.l)
+#define PULLBYTE(b) b = RM(pSP); pSP--
+#define PULLWORD(w) w.b.l = RM(pSP); pSP--; w.b.h = RM(pSP); pSP--
+
+typedef struct
+{
+ PAIR pc; /* Program counter */
+ UINT8 sp; /* Stack Pointer */
+ UINT8 sr; /* Status Register */
+ UINT8 irq_state[3]; /* State of the three IRQs */
+ UINT8 rf[0x80]; /* Register file (SJE) */
+ UINT8 pf[0x100]; /* Perpherial file */
+ int (*irq_callback)(int irqline);
+ UINT8 t1_capture_latch; /* Timer 1 capture latch */
+ INT8 t1_prescaler; /* Timer 1 prescaler (5 bits) */
+ INT16 t1_decrementer; /* Timer 1 decrementer (8 bits) */
+ UINT8 idle_state; /* Set after the execution of an idle instruction */
+} tms7000_Regs;
+
+static tms7000_Regs tms7000;
+
+#define pPC tms7000.pc.w.l
+#define PC tms7000.pc
+#define pSP tms7000.sp
+#define pSR tms7000.sr
+
+#define RDA RM(0x0000)
+#define RDB RM(0x0001)
+
+#define WRA(Value) (WM(0x0000,Value))
+#define WRB(Value) (WM(0x0001,Value))
+
+#define SR_C 0x80 /* Carry */
+#define SR_N 0x40 /* Negative */
+#define SR_Z 0x20 /* Zero */
+#define SR_I 0x10 /* Interrupt */
+
+#define CLR_NZC pSR&=~(SR_N|SR_Z|SR_C)
+#define CLR_NZCI pSR&=~(SR_N|SR_Z|SR_C|SR_I)
+#define SET_C8(a) pSR|=((a&0x0100)>>1)
+#define SET_N8(a) pSR|=((a&0x0080)>>1)
+#define SET_Z(a) if(!a)pSR|=SR_Z
+#define SET_Z8(a) SET_Z((UINT8)a)
+#define SET_Z16(a) SET_Z((UINT8)a>>8)
+#define GET_C (pSR >> 7)
+
+/* Not working */
+#define SET_C16(a) pSR|=((a&0x010000)>>9)
+
+#define SETC pSR |= SR_C
+#define SETZ pSR |= SR_Z
+#define SETN pSR |= SR_N
+
+#define CHANGE_PC change_pc(pPC)
+
+
+static READ8_HANDLER( tms7000_internal_r );
+static WRITE8_HANDLER( tms7000_internal_w );
+static READ8_HANDLER( tms70x0_pf_r );
+static WRITE8_HANDLER( tms70x0_pf_w );
+
+static ADDRESS_MAP_START(tms7000_mem, ADDRESS_SPACE_PROGRAM, 8)
+ AM_RANGE(0x0000, 0x007f) AM_READWRITE(tms7000_internal_r, tms7000_internal_w) /* tms7000 internal RAM */
+ AM_RANGE(0x0080, 0x00ff) AM_READWRITE(MRA8_NOP, MWA8_NOP) /* reserved */
+ AM_RANGE(0x0100, 0x01ff) AM_READWRITE(tms70x0_pf_r, tms70x0_pf_w) /* tms7000 internal I/O ports */
+ADDRESS_MAP_END
+
+
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+
+static void tms7000_get_context(void *dst)
+{
+ if( dst )
+ *(tms7000_Regs*)dst = tms7000;
+}
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void tms7000_set_context(void *src)
+{
+ if( src )
+ tms7000 = *(tms7000_Regs*)src;
+
+ tms7000_check_IRQ_lines();
+}
+
+static void tms7000_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int cpu = cpu_getactivecpu();
+
+ tms7000.irq_callback = irqcallback;
+
+ memset(tms7000.pf, 0, 0x100);
+ memset(tms7000.rf, 0, 0x80);
+
+ /* Save register state */
+ state_save_register_item("tms7000", cpu, pPC);
+ state_save_register_item("tms7000", cpu, pSP);
+ state_save_register_item("tms7000", cpu, pSR);
+
+ /* Save Interrupt state */
+ state_save_register_item_array("tms7000", cpu, tms7000.irq_state);
+
+ /* Save register and perpherial file state */
+ state_save_register_item_array("tms7000", cpu, tms7000.rf);
+ state_save_register_item_array("tms7000", cpu, tms7000.pf);
+
+ /* Save timer state */
+ state_save_register_item("tms7000", cpu, tms7000.t1_prescaler);
+ state_save_register_item("tms7000", cpu, tms7000.t1_capture_latch);
+ state_save_register_item("tms7000", cpu, tms7000.t1_decrementer);
+
+ state_save_register_item("tms7000", cpu, tms7000.idle_state);
+
+ tms7000.irq_callback = irqcallback;
+}
+
+static void tms7000_reset(void)
+{
+// tms7000.architecture = (int)param;
+
+ tms7000.idle_state = 0;
+ tms7000.irq_state[ TMS7000_IRQ1_LINE ] = CLEAR_LINE;
+ tms7000.irq_state[ TMS7000_IRQ2_LINE ] = CLEAR_LINE;
+ tms7000.irq_state[ TMS7000_IRQ3_LINE ] = CLEAR_LINE;
+
+ WM( 0x100 + 9, 0 ); /* Data direction regs are cleared */
+ WM( 0x100 + 11, 0 );
+
+// if( tms7000.architecture == TMS7000_NMOS )
+// {
+ WM( 0x100 + 4, 0xff ); /* Output 0xff on port A */
+ WM( 0x100 + 8, 0xff ); /* Output 0xff on port C */
+ WM( 0x100 + 10, 0xff ); /* Output 0xff on port D */
+// }
+// else
+// {
+// WM( 0x100 + 4, 0xff ); /* Output 0xff on port A */
+// }
+
+ pSP = 0x01; /* Set stack pointer to r1 */
+ pSR = 0x00; /* Clear status register (disabling interrupts */
+ WM( 0x100 + 0, 0 ); /* Write a zero to IOCNT0 */
+
+ /* On TMS70x2 and TMS70Cx2 IOCNT1 is zero */
+
+ WRA( tms7000.pc.b.h ); /* Write previous PC to A:B */
+ WRB( tms7000.pc.b.l );
+ pPC = RM16(0xfffe); /* Load reset vector */
+ CHANGE_PC;
+
+ tms7000_div_by_16_trigger = -16;
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void tms7000_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + TMS7000_IRQ1_LINE: tms7000_set_irq_line(TMS7000_IRQ1_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS7000_IRQ2_LINE: tms7000_set_irq_line(TMS7000_IRQ2_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + TMS7000_IRQ3_LINE: tms7000_set_irq_line(TMS7000_IRQ3_LINE, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS7000_PC: pPC = info->i; CHANGE_PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS7000_SP: pSP = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS7000_ST: pSR = info->i; tms7000_check_IRQ_lines(); break;
+ case CPUINFO_INT_REGISTER + TMS7000_IDLE: tms7000.idle_state = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS7000_T1_CL: tms7000.t1_capture_latch = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS7000_T1_PS: tms7000.t1_prescaler = info->i; break;
+ case CPUINFO_INT_REGISTER + TMS7000_T1_DEC: tms7000.t1_decrementer = info->i; break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void tms7000_get_info(UINT32 state, cpuinfo *info)
+{
+
+ switch( state )
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(tms7000); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 48; break; /* 48 represents the multiply instruction, the next highest is 17 */
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + TMS7000_IRQ1_LINE: info->i = tms7000.irq_state[TMS7000_IRQ1_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + TMS7000_IRQ2_LINE: info->i = tms7000.irq_state[TMS7000_IRQ2_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + TMS7000_IRQ3_LINE: info->i = tms7000.irq_state[TMS7000_IRQ3_LINE]; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* Not supported */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + TMS7000_PC: info->i = pPC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS7000_SP: info->i = pSP; break;
+ case CPUINFO_INT_REGISTER + TMS7000_ST: info->i = pSR; break;
+ case CPUINFO_INT_REGISTER + TMS7000_IDLE: info->i = tms7000.idle_state; break;
+ case CPUINFO_INT_REGISTER + TMS7000_T1_CL: info->i = tms7000.t1_capture_latch; break;
+ case CPUINFO_INT_REGISTER + TMS7000_T1_PS: info->i = tms7000.t1_prescaler; break;
+ case CPUINFO_INT_REGISTER + TMS7000_T1_DEC: info->i = tms7000.t1_decrementer; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = tms7000_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tms7000_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tms7000_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = tms7000_init; break;
+ case CPUINFO_PTR_RESET: info->reset = tms7000_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = tms7000_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; /* Not supported */break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tms7000_dasm; break;
+#endif
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &tms7000_icount; break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP: info->internal_map = construct_map_tms7000_mem; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "TMS7000"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "Texas Instriuments TMS7000"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "Copyright (C) tim lindner 2003"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s = cpuintrf_temp_str(), "%c%c%c%c%c%c%c%c",
+ tms7000.sr & 0x80 ? 'C':'c',
+ tms7000.sr & 0x40 ? 'N':'n',
+ tms7000.sr & 0x20 ? 'Z':'z',
+ tms7000.sr & 0x10 ? 'I':'i',
+ tms7000.sr & 0x08 ? '?':'.',
+ tms7000.sr & 0x04 ? '?':'.',
+ tms7000.sr & 0x02 ? '?':'.',
+ tms7000.sr & 0x01 ? '?':'.' );
+ break;
+
+ case CPUINFO_STR_REGISTER + TMS7000_PC: sprintf(info->s = cpuintrf_temp_str(), "PC:%04X", tms7000.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + TMS7000_SP: sprintf(info->s = cpuintrf_temp_str(), "S:%02X", tms7000.sp); break;
+ case CPUINFO_STR_REGISTER + TMS7000_ST: sprintf(info->s = cpuintrf_temp_str(), "ST:%02X", tms7000.sr); break;
+ case CPUINFO_STR_REGISTER + TMS7000_IDLE: sprintf(info->s = cpuintrf_temp_str(), "Idle:%02X", tms7000.idle_state); break;
+ case CPUINFO_STR_REGISTER + TMS7000_T1_CL: sprintf(info->s = cpuintrf_temp_str(), "T1CL:%02X", tms7000.t1_capture_latch); break;
+ case CPUINFO_STR_REGISTER + TMS7000_T1_PS: sprintf(info->s = cpuintrf_temp_str(), "T1PS:%02X", tms7000.t1_prescaler & 0x1f); break;
+ case CPUINFO_STR_REGISTER + TMS7000_T1_DEC: sprintf(info->s = cpuintrf_temp_str(), "T1DEC:%02X", tms7000.t1_decrementer & 0xff); break;
+
+ }
+}
+
+void tms7000_exl_get_info(UINT32 state, cpuinfo *info)
+{
+ switch( state )
+ {
+ case CPUINFO_PTR_EXECUTE:
+ info->execute = tms7000_exl_execute;
+ break;
+ default:
+ tms7000_get_info(state, info);
+ break;
+ }
+}
+
+void tms7000_set_irq_line(int irqline, int state)
+{
+ if (tms7000.irq_state[irqline] != state)
+ { /* check for transition */
+ tms7000.irq_state[irqline] = state;
+
+ LOG(("tms7000: (cpu #%d) set_irq_line (INT%d, state %d)\n", cpu_getactivecpu(), irqline+1, state));
+
+ if (state == CLEAR_LINE)
+ {
+ return;
+ }
+
+ tms7000.pf[0] |= (0x02 << (irqline * 2)); /* Set INTx iocntl0 flag */
+
+ if( irqline == TMS7000_IRQ3_LINE )
+ {
+ /* Latch the value in perpherial file register 3 */
+ tms7000.t1_capture_latch = tms7000.t1_decrementer & 0x00ff;
+ }
+
+ tms7000_check_IRQ_lines();
+ }
+}
+
+static void tms7000_check_IRQ_lines( void )
+{
+ if( pSR & SR_I ) /* Check Global Interrupt bit: Status register, bit 4 */
+ {
+ if ((tms7000.irq_state[TMS7000_IRQ1_LINE] == ASSERT_LINE) || (tms7000.pf[0] & 0x02))
+ {
+ if( tms7000.pf[0] & 0x01 ) /* INT1 Enable bit */
+ {
+ tms7000_do_interrupt( 0xfffc, TMS7000_IRQ1_LINE );
+ tms7000.pf[0] &= ~0x02; /* Data Manual, page: 9-41 */
+ return;
+ }
+ }
+
+ if( tms7000.irq_state[ TMS7000_IRQ2_LINE ] == ASSERT_LINE )
+ {
+ if( tms7000.pf[0] & 0x04 ) /* INT2 Enable bit */
+ {
+ tms7000_do_interrupt( 0xfffa, TMS7000_IRQ2_LINE );
+ return;
+ }
+ }
+
+ if ((tms7000.irq_state[TMS7000_IRQ3_LINE] == ASSERT_LINE) || (tms7000.pf[0] & 0x20))
+ {
+ if( tms7000.pf[0] & 0x10 ) /* INT3 Enable bit */
+ {
+ tms7000_do_interrupt( 0xfff8, TMS7000_IRQ3_LINE );
+ tms7000.pf[0] &= ~0x20; /* Data Manual, page: 9-41 */
+ return;
+ }
+ }
+ }
+}
+
+static void tms7000_do_interrupt( UINT16 address, UINT8 line )
+{
+ PUSHBYTE( pSR ); /* Push Status register */
+ PUSHWORD( PC ); /* Push Program Counter */
+ pSR = 0; /* Clear Status register */
+ pPC = RM16(address); /* Load PC with interrupt vector */
+ CHANGE_PC;
+
+ if( tms7000.idle_state == 0 )
+ tms7000_icount -= 19; /* 19 cycles used */
+ else
+ {
+ tms7000_icount -= 17; /* 17 if idled */
+ tms7000.idle_state = 0;
+ }
+
+ (void)(*tms7000.irq_callback)(line);
+}
+
+#include "tms70op.c"
+#include "tms70tb.c"
+
+static int tms7000_execute(int cycles)
+{
+ int op;
+
+ tms7000_icount = cycles;
+ tms7000_div_by_16_trigger += cycles;
+
+ do
+ {
+ CALL_MAME_DEBUG;
+
+ if( tms7000.idle_state == 0 )
+ {
+ op = cpu_readop(pPC++);
+
+ opfn[op]();
+ }
+ else
+ tms7000_icount -= 16;
+
+ /* Internal timer system */
+
+ while( tms7000_icount < tms7000_div_by_16_trigger )
+ {
+ tms7000_div_by_16_trigger -= 16;
+
+ if( (tms7000.pf[0x03] & 0x80) == 0x80 ) /* Is timer system active? */
+ {
+ if( (tms7000.pf[0x03] & 0x40) != 0x40) /* Is system clock (divided by 16) the timer source? */
+ tms7000_service_timer1();
+ }
+ }
+
+ } while( tms7000_icount > 0 );
+
+ tms7000_div_by_16_trigger -= tms7000_icount;
+ return cycles - tms7000_icount;
+}
+
+static int tms7000_exl_execute(int cycles)
+{
+ int op;
+
+ tms7000_icount = cycles;
+ tms7000_div_by_16_trigger += cycles;
+
+ do
+ {
+ CALL_MAME_DEBUG;
+
+ if( tms7000.idle_state == 0 )
+ {
+
+ op = cpu_readop(pPC++);
+
+ opfn_exl[op]();
+ }
+ else
+ tms7000_icount -= 16;
+
+ /* Internal timer system */
+
+ while( tms7000_icount < tms7000_div_by_16_trigger )
+ {
+ tms7000_div_by_16_trigger -= 16;
+
+ if( (tms7000.pf[0x03] & 0x80) == 0x80 ) /* Is timer system active? */
+ {
+ if( (tms7000.pf[0x03] & 0x40) != 0x40) /* Is system clock (divided by 16) the timer source? */
+ tms7000_service_timer1();
+ }
+ }
+
+ } while( tms7000_icount > 0 );
+
+ tms7000_div_by_16_trigger -= tms7000_icount;
+ return cycles - tms7000_icount;
+}
+
+/****************************************************************************
+ * Trigger the event counter
+ ****************************************************************************/
+void tms7000_A6EC1( void )
+{
+ if( (tms7000.pf[0x03] & 0x80) == 0x80 ) /* Is timer system active? */
+ {
+ if( (tms7000.pf[0x03] & 0x40) == 0x40) /* Is event counter the timer source? */
+ tms7000_service_timer1();
+ }
+}
+
+static void tms7000_service_timer1( void )
+{
+ if( --tms7000.t1_prescaler < 0 ) /* Decrement prescaler and check for underflow */
+ {
+ tms7000.t1_prescaler = tms7000.pf[3] & 0x1f; /* Reload prescaler (5 bit) */
+
+ if( --tms7000.t1_decrementer < 0 ) /* Decrement timer1 register and check for underflow */
+ {
+ tms7000.t1_decrementer = tms7000.pf[2]; /* Reload decrementer (8 bit) */
+ cpunum_set_input_line( cpu_getactivecpu(), TMS7000_IRQ2_LINE, HOLD_LINE);
+ LOG( ("tms7000: trigger int2 (cycles: %d)\t%d\tdelta %d\n", activecpu_gettotalcycles(), activecpu_gettotalcycles() - tick, tms7000_cycles_per_INT2-(activecpu_gettotalcycles() - tick) );
+ tick = activecpu_gettotalcycles() );
+ /* Also, cascade out to timer 2 - timer 2 unimplemented */
+ }
+ }
+// LOG( ( "tms7000: service timer1. 0x%2.2x 0x%2.2x (cycles %d)\t%d\t\n", tms7000.t1_prescaler, tms7000.t1_decrementer, activecpu_gettotalcycles(), activecpu_gettotalcycles() - tick2 ) );
+// tick2 = activecpu_gettotalcycles();
+}
+
+static WRITE8_HANDLER( tms70x0_pf_w ) /* Perpherial file write */
+{
+ UINT8 temp1, temp2, temp3;
+
+ switch( offset )
+ {
+ case 0x00: /* IOCNT0, Input/Ouput control */
+ temp1 = data & 0x2a; /* Record which bits to clear */
+ temp2 = tms7000.pf[0x00] & 0x2a; /* Get copy of current bits */
+ temp3 = (~temp1) & temp2; /* Clear the requested bits */
+ tms7000.pf[0x00] = temp3 | (data & (~0x2a) ); /* OR in the remaining data */
+ break;
+ case 0x02:
+ tms7000.t1_decrementer = tms7000.pf[0x02] = data;
+ tms7000_cycles_per_INT2 = 0x10*((tms7000.pf[3] & 0x1f)+1)*(tms7000.pf[0x02]+1);
+ LOG( ( "tms7000: Timer adjusted. Decrementer: 0x%2.2x (Cycles per interrupt: %d)\n", tms7000.t1_decrementer, tms7000_cycles_per_INT2 ) );
+ break;
+ case 0x03: /* T1CTL, timer 1 control */
+ if( ((tms7000.pf[0x03] & 0x80) == 0) && ((data & 0x80) == 0x80 ) ) /* Start timer? */
+ {
+ tms7000.pf[0x03] = data;
+ tms7000.t1_prescaler = tms7000.pf[3] & 0x1f; /* Reload prescaler (5 bit) */
+ tms7000_cycles_per_INT2 = 0x10*((tms7000.pf[3] & 0x1f)+1)*(tms7000.pf[0x02]+1);
+ LOG( ( "tms7000: Timer started. Prescaler: 0x%2.2x (Cycles per interrupt: %d)\n", tms7000.pf[3] & 0x1f, tms7000_cycles_per_INT2 ) );
+ }
+ else if( ((data & 0x80) == 0x80 ) && ((tms7000.pf[0x03] & 0x80) == 0) ) /* Timer Stopped? */
+ {
+ tms7000.pf[0x03] = data;
+ tms7000.t1_prescaler = tms7000.pf[3] & 0x1f; /* Reload prescaler (5 bit) */
+ tms7000_cycles_per_INT2 = 0x10*((tms7000.pf[3] & 0x1f)+1)*(tms7000.pf[0x02]+1);
+ LOG( ( "tms7000: Timer stopped. Prescaler: 0x%2.2x (Cycles per interrupt: %d)\n", tms7000.pf[3] & 0x1f, tms7000_cycles_per_INT2 ) );
+ }
+ else /* Don't modify timer state, but still store data */
+ {
+ tms7000.pf[0x03] = data;
+ tms7000_cycles_per_INT2 = 0x10*((tms7000.pf[3] & 0x1f)+1)*(tms7000.pf[0x02]+1);
+ LOG( ( "tms7000: Timer adjusted. Prescaler: 0x%2.2x (Cycles per interrupt: %d)\n", tms7000.pf[3] & 0x1f, tms7000_cycles_per_INT2 ) );
+ }
+ break;
+
+ case 0x04: /* Port A write */
+ /* Port A is read only so this is a NOP */
+ break;
+
+ case 0x06: /* Port B write */
+ io_write_byte_8( TMS7000_PORTB, data );
+ tms7000.pf[ 0x06 ] = data;
+ break;
+
+ case 0x08: /* Port C write */
+ temp1 = data & tms7000.pf[ 0x09 ]; /* Mask off input bits */
+ io_write_byte_8( TMS7000_PORTC, temp1 );
+ tms7000.pf[ 0x08 ] = temp1;
+ break;
+
+ case 0x0a: /* Port D write */
+ temp1 = data & tms7000.pf[ 0x0b ]; /* Mask off input bits */
+ io_write_byte_8( TMS7000_PORTD, temp1 );
+ tms7000.pf[ 0x0a ] = temp1;
+ break;
+
+ default:
+ /* Just stuff the other registers */
+ tms7000.pf[ offset ] = data;
+ break;
+ }
+}
+
+static READ8_HANDLER( tms70x0_pf_r ) /* Perpherial file read */
+{
+ UINT8 result;
+ UINT8 temp1, temp2, temp3;
+
+ switch( offset )
+ {
+ case 0x00: /* IOCNT0, Input/Ouput control */
+ result = tms7000.pf[0x00];
+ if (tms7000.irq_state[TMS7000_IRQ1_LINE] == ASSERT_LINE)
+ result |= 0x02;
+ if (tms7000.irq_state[TMS7000_IRQ3_LINE] == ASSERT_LINE)
+ result |= 0x20;
+ break;
+
+ case 0x02: /* T1DATA, timer 1 8-bit decrementer */
+ result = (tms7000.t1_decrementer & 0x00ff);
+ break;
+
+ case 0x03: /* T1CTL, timer 1 capture (latched by INT3) */
+ result = tms7000.t1_capture_latch;
+ break;
+
+ case 0x04: /* Port A read */
+ result = io_read_byte_8( TMS7000_PORTA );
+ break;
+
+
+ case 0x06: /* Port B read */
+ /* Port B is write only, return a previous written value */
+ result = tms7000.pf[ 0x06 ];
+ break;
+
+ case 0x08: /* Port C read */
+ temp1 = tms7000.pf[ 0x08 ] & tms7000.pf[ 0x09 ]; /* Get previous output bits */
+ temp2 = io_read_byte_8( TMS7000_PORTC ); /* Read port */
+ temp3 = temp2 & (~tms7000.pf[ 0x09 ]); /* Mask off output bits */
+ result = temp1 | temp3; /* OR together */
+ break;
+
+ case 0x0a: /* Port D read */
+ temp1 = tms7000.pf[ 0x0a ] & tms7000.pf[ 0x0b ]; /* Get previous output bits */
+ temp2 = io_read_byte_8( TMS7000_PORTD ); /* Read port */
+ temp3 = temp2 & (~tms7000.pf[ 0x0b ]); /* Mask off output bits */
+ result = temp1 | temp3; /* OR together */
+ break;
+
+ default:
+ /* Just unstuff the other registers */
+ result = tms7000.pf[ offset ];
+ break;
+ }
+
+ return result;
+}
+
+// BCD arthrimetic handling
+static UINT16 bcd_add( UINT16 a, UINT16 b )
+{
+ UINT16 t1,t2,t3,t4,t5,t6;
+
+ /* Sure it is a lot of code, but it works! */
+ t1 = a + 0x0666;
+ t2 = t1 + b;
+ t3 = t1 ^ b;
+ t4 = t2 ^ t3;
+ t5 = ~t4 & 0x1110;
+ t6 = (t5 >> 2) | (t5 >> 3);
+ return t2-t6;
+}
+
+static UINT16 bcd_tencomp( UINT16 a )
+{
+ UINT16 t1,t2,t3,t4,t5,t6;
+
+ t1 = 0xffff - a;
+ t2 = -a;
+ t3 = t1 ^ 0x0001;
+ t4 = t2 ^ t3;
+ t5 = ~t4 & 0x1110;
+ t6 = (t5 >> 2)|(t5>>3);
+ return t2-t6;
+}
+
+/*
+ Compute difference a-b???
+*/
+static UINT16 bcd_sub( UINT16 a, UINT16 b)
+{
+ //return bcd_tencomp(b) - bcd_tencomp(a);
+ return bcd_add(a, bcd_tencomp(b) & 0xff);
+}
+
+static WRITE8_HANDLER( tms7000_internal_w ) {
+ tms7000.rf[ offset ] = data;
+}
+
+static READ8_HANDLER( tms7000_internal_r ) {
+ return tms7000.rf[ offset ];
+}
diff --git a/src/emu/cpu/tms7000/tms7000.h b/src/emu/cpu/tms7000/tms7000.h
new file mode 100644
index 00000000000..95b2b16c246
--- /dev/null
+++ b/src/emu/cpu/tms7000/tms7000.h
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ *
+ * tms7000.h (c header file)
+ * Portable TMS7000 emulator (Texas Instruments 7000)
+ *
+ * Copyright (c) 2001 tim lindner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * tlindner@macmess.org
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#ifndef _TMS7000_H
+#define _TMS7000_H
+
+#include "cpuintrf.h"
+
+enum { TMS7000_PC=1, TMS7000_SP, TMS7000_ST, TMS7000_IDLE, TMS7000_T1_CL, TMS7000_T1_PS, TMS7000_T1_DEC };
+
+enum { TMS7000_VCC, TMS7000_VSS };
+
+enum { TMS7000_NMOS, TMS7000_CMOS };
+
+enum {
+ TMS7000_IRQ1_LINE = 0, /* INT1 */
+ TMS7000_IRQ2_LINE, /* INT2 */
+ TMS7000_IRQ3_LINE, /* INT3 */
+ TMS7000_IRQNONE = 255
+};
+
+enum {
+ TMS7000_PORTA = 0,
+ TMS7000_PORTB,
+ TMS7000_PORTC,
+ TMS7000_PORTD
+};
+
+/* PUBLIC FUNCTIONS */
+extern void tms7000_A6EC1( void ); /* External event counter */
+extern void tms7000_get_info(UINT32 state, cpuinfo *info);
+extern void tms7000_exl_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern unsigned tms7000_dasm( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram );
+#endif /* MAME_DEBUG */
+
+#endif /* _TMS7000_H */
+
diff --git a/src/emu/cpu/tms7000/tms70op.c b/src/emu/cpu/tms7000/tms70op.c
new file mode 100644
index 00000000000..15ff2c58968
--- /dev/null
+++ b/src/emu/cpu/tms7000/tms70op.c
@@ -0,0 +1,3958 @@
+/*****************************************************************************
+ *
+ * tms70op.c (Op code functions)
+ * Portable TMS7000 emulator (Texas Instruments 7000)
+ *
+ * Copyright (c) 2001 tim lindner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * tlindner@macmess.org
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+//SJE: Changed all references to ICount to icount (to match MAME requirements)
+
+#include "cpuintrf.h"
+
+static void illegal( void )
+{
+ /* This is a guess */
+ tms7000_icount -= 4;
+}
+
+static void adc_b2a( void )
+{
+ UINT16 t;
+
+ t = RDA + RDB + GET_C;
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void adc_r2a( void )
+{
+ UINT16 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) + RDA + GET_C;
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void adc_r2b( void )
+{
+ UINT16 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) + RDB + GET_C;
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void adc_r2r( void )
+{
+ UINT16 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = RM(i)+RM(j) + GET_C;
+ WM(j,t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void adc_i2a( void )
+{
+ UINT16 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v + RDA + GET_C;
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void adc_i2b( void )
+{
+ UINT16 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v + RDB + GET_C;
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void adc_i2r( void )
+{
+ UINT16 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = i+RM(j) + GET_C;
+ WM(j,t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void add_b2a( void )
+{
+ UINT16 t;
+
+ t = RDA + RDB;
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void add_r2a( void )
+{
+ UINT16 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) + RDA;
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void add_r2b( void )
+{
+ UINT16 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) + RDB;
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void add_r2r( void )
+{
+ UINT16 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = RM(i)+RM(j);
+ WM(j,t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void add_i2a( void )
+{
+ UINT16 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v + RDA;
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void add_i2b( void )
+{
+ UINT16 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v + RDB;
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void add_i2r( void )
+{
+ UINT16 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = i+RM(j);
+ WM(j,t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void and_b2a( void )
+{
+ UINT8 t;
+
+ t = RDA & RDB;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void and_r2a( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) & RDA;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void and_r2b( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) & RDB;
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void and_r2r( void )
+{
+ UINT8 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = RM(i) & RM(j);
+ WM(j,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void and_i2a( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v & RDA;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void and_i2b( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v & RDB;
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void and_i2r( void )
+{
+ UINT8 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = i & RM(j);
+ WM(j,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void andp_a2p( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+ t = RDA & RM( 0x0100 + v);
+ WM( 0x0100+v, t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void andp_b2p( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+ t = RDB & RM( 0x0100 + v);
+ WM( 0x0100+v, t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+
+static void movp_i2p( void )
+{
+ UINT8 i,v;
+
+ IMMBYTE(i);
+ IMMBYTE(v);
+ WM( 0x0100+v, i);
+
+ CLR_NZC;
+ SET_N8(i);
+ SET_Z8(i);
+
+ tms7000_icount -= 11;
+}
+
+static void andp_i2p( void )
+{
+ UINT8 t;
+ UINT8 i,v;
+
+ IMMBYTE(i);
+ IMMBYTE(v);
+ t = i & RM( 0x0100 + v);
+ WM( 0x0100+v, t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 11;
+}
+
+static void br_dir( void )
+{
+ PAIR p;
+
+ IMMWORD( p );
+ pPC = p.d;
+ CHANGE_PC;
+ tms7000_icount -= 10;
+}
+
+static void br_ind( void )
+{
+ UINT8 v;
+
+ IMMBYTE( v );
+ PC.w.l = RRF16(v);
+
+ tms7000_icount -= 9;
+}
+
+static void br_inx( void )
+{
+ PAIR p;
+
+ IMMWORD( p );
+ pPC = p.w.l + RDB;
+ CHANGE_PC;
+ tms7000_icount -= 12;
+}
+
+static void btjo_b2a( void )
+{
+ UINT8 t;
+
+ t = RDB & RDA;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE( j );
+ pPC += j;
+ tms7000_icount -= 9;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 7;
+ }
+ CHANGE_PC;
+}
+
+static void btjo_r2a( void )
+{
+ UINT8 t,r;
+
+ IMMBYTE( r );
+ t = RM( r ) & RDA;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE( j );
+ pPC += j;
+ tms7000_icount -= 9;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 7;
+ }
+ CHANGE_PC;
+}
+
+static void btjo_r2b( void )
+{
+ UINT8 t,r;
+
+ IMMBYTE(r);
+ t = RM(r) & RDB;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 12;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 10;
+ }
+ CHANGE_PC;
+}
+
+static void btjo_r2r( void )
+{
+ UINT8 t,r,s;
+
+ IMMBYTE(r);
+ IMMBYTE(s);
+ t = RM(r) & RM(s);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 14;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 12;
+ }
+ CHANGE_PC;
+}
+
+static void btjo_i2a( void )
+{
+ UINT8 t,r;
+
+ IMMBYTE(r);
+ t = r & RDA;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 11;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 9;
+ }
+ CHANGE_PC;
+}
+
+static void btjo_i2b( void )
+{
+ UINT8 t,i;
+
+ IMMBYTE(i);
+ t = i & RDB;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 11;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 9;
+ }
+ CHANGE_PC;
+}
+
+static void btjo_i2r( void )
+{
+ UINT8 t,i,r;
+
+ IMMBYTE(i);
+ IMMBYTE(r);
+ t = i & RM(r);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 13;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 11;
+ }
+ CHANGE_PC;
+}
+
+static void btjop_ap( void )
+{
+ UINT8 t,p;
+
+ IMMBYTE(p);
+
+ t = RM(0x100+p) & RDA;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 13;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 11;
+ }
+ CHANGE_PC;
+}
+
+static void btjop_bp( void )
+{
+ UINT8 t,p;
+
+ IMMBYTE(p);
+
+ t = RM(0x100+p) & RDB;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 12;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 10;
+ }
+ CHANGE_PC;
+}
+
+static void btjop_ip( void )
+{
+ UINT8 t,p,i;
+
+ IMMBYTE(i);
+ IMMBYTE(p);
+
+ t = RM(0x100+p) & i;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 14;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 12;
+ }
+ CHANGE_PC;
+}
+
+static void btjz_b2a( void )
+{
+ UINT8 t;
+
+ t = RDB & ~RDA;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE( j );
+ pPC += j;
+ tms7000_icount -= 9;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 7;
+ }
+ CHANGE_PC;
+}
+
+static void btjz_r2a( void )
+{
+ UINT8 t,r;
+
+ IMMBYTE( r );
+ t = RM( r ) & ~RDA;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE( j );
+ pPC += j;
+ tms7000_icount -= 9;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 7;
+ }
+ CHANGE_PC;
+}
+
+static void btjz_r2b( void )
+{
+ UINT8 t,r;
+
+ IMMBYTE(r);
+ t = RM(r) & ~RDB;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 12;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 10;
+ }
+ CHANGE_PC;
+}
+
+static void btjz_r2r( void )
+{
+ UINT8 t,r,s;
+
+ IMMBYTE(r);
+ IMMBYTE(s);
+ t = RM(r) & ~RM(s);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 14;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 12;
+ }
+ CHANGE_PC;
+}
+
+static void btjz_i2a( void )
+{
+ UINT8 t,r;
+
+ IMMBYTE(r);
+ t = r & ~RDA;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 11;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 9;
+ }
+ CHANGE_PC;
+}
+
+static void btjz_i2b( void )
+{
+ UINT8 t,i;
+
+ IMMBYTE(i);
+ t = i & ~RDB;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 11;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 9;
+ }
+ CHANGE_PC;
+}
+
+static void btjz_i2r( void )
+{
+ UINT8 t,i,r;
+
+ IMMBYTE(i);
+ IMMBYTE(r);
+ t = i & ~RM(r);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 13;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 11;
+ }
+ CHANGE_PC;
+}
+
+static void btjzp_ap( void )
+{
+ UINT8 t,p;
+
+ IMMBYTE(p);
+
+ t = RDA & ~RM(0x100+p);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 13;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 11;
+ }
+ CHANGE_PC;
+}
+
+static void btjzp_bp( void )
+{
+ UINT8 t,p;
+
+ IMMBYTE(p);
+
+ t = RDB & ~RM(0x100+p);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 12;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 10;
+ }
+ CHANGE_PC;
+}
+
+static void btjzp_ip( void )
+{
+ UINT8 t,p,i;
+
+ IMMBYTE(i);
+ IMMBYTE(p);
+
+ t = i & ~RM(0x100+p);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if(t != 0)
+ {
+ INT8 j;
+
+ SIMMBYTE(j);
+ pPC += j;
+ tms7000_icount -= 14;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 12;
+ }
+ CHANGE_PC;
+}
+
+static void call_dir( void )
+{
+ PAIR tPC;
+
+ IMMWORD( tPC );
+ PUSHWORD( PC );
+ pPC = tPC.d;
+ CHANGE_PC;
+
+ tms7000_icount -= 14;
+}
+
+static void call_ind( void )
+{
+ UINT8 v;
+
+ IMMBYTE( v );
+ PUSHWORD( PC );
+ PC.w.l = RRF16(v);
+
+ tms7000_icount -= 13;
+}
+
+static void call_inx( void )
+{
+ PAIR tPC;
+
+ IMMWORD( tPC );
+ PUSHWORD( PC );
+ pPC = tPC.w.l + RDB;
+ CHANGE_PC;
+ tms7000_icount -= 16;
+}
+
+static void clr_a( void )
+{
+ WRA(0);
+ tms7000_icount -= 5;
+}
+
+static void clr_b( void )
+{
+ WRB(0);
+ tms7000_icount -= 5;
+}
+
+static void clr_r( void )
+{
+ UINT8 r;
+
+ IMMBYTE(r);
+ WM(r,0);
+ tms7000_icount -= 7;
+}
+
+static void clrc( void )
+{
+ UINT8 a;
+
+ a = RDA;
+
+ CLR_NZC;
+ SET_N8(a);
+ SET_Z8(a);
+
+ tms7000_icount -= 6;
+}
+
+static void cmp_ba( void )
+{
+ UINT16 t;
+
+ t = RDA - RDB;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 5;
+}
+
+static void cmp_ra( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+ t = RDA - RM(r);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 8;
+}
+
+static void cmp_rb( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+ t = RDB - RM(r);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 8;
+}
+
+static void cmp_rr( void )
+{
+ UINT16 t;
+ UINT8 r,s;
+
+ IMMBYTE(r);
+ IMMBYTE(s);
+ t = RM(s) - RM(r);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 10;
+}
+
+static void cmp_ia( void )
+{
+ UINT16 t;
+ UINT8 i;
+
+ IMMBYTE(i);
+ t = RDA - i;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 7;
+}
+
+static void cmp_ib( void )
+{
+ UINT16 t;
+ UINT8 i;
+
+ IMMBYTE(i);
+ t = RDB - i;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 7;
+}
+
+static void cmp_ir( void )
+{
+ UINT16 t;
+ UINT8 i,r;
+
+ IMMBYTE(i);
+ IMMBYTE(r);
+ t = RM(r) - i;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 9;
+}
+
+static void cmpa_dir( void )
+{
+ UINT16 t;
+ PAIR i;
+
+ IMMWORD( i );
+ t = RDA - RM(i.w.l);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 12;
+}
+
+static void cmpa_ind( void )
+{
+ UINT16 t;
+ PAIR p;
+ INT8 i;
+
+ IMMBYTE(i);
+ p.w.l = RRF16(i);
+ t = RDA - RM(p.w.l);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 11;
+}
+
+static void cmpa_inx( void )
+{
+ UINT16 t;
+ PAIR i;
+
+ IMMWORD( i );
+ t = RDA - RM(i.w.l + RDB);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t==0 )
+ SETC;
+ else
+ SET_C8( ~t );
+
+ tms7000_icount -= 14;
+}
+
+static void dac_b2a( void )
+{
+ UINT16 t;
+
+ t = bcd_add( RDA, RDB );
+
+ if (pSR & SR_C)
+ t = bcd_add( t, 1 );
+
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void dac_r2a( void )
+{
+ UINT8 r;
+ UINT16 t;
+
+ IMMBYTE(r);
+
+ t = bcd_add( RDA, RM(r) );
+
+ if (pSR & SR_C)
+ t = bcd_add( t, 1 );
+
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void dac_r2b( void )
+{
+ UINT8 r;
+ UINT16 t;
+
+ IMMBYTE(r);
+
+ t = bcd_add( RDB, RM(r) );
+
+ if (pSR & SR_C)
+ t = bcd_add( t, 1 );
+
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void dac_r2r( void )
+{
+ UINT8 r,s;
+ UINT16 t;
+
+ IMMBYTE(s);
+ IMMBYTE(r);
+
+ t = bcd_add( RM(s), RM(r) );
+
+ if (pSR & SR_C)
+ t = bcd_add( t, 1 );
+
+ WM(r,t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 12;
+}
+
+static void dac_i2a( void )
+{
+ UINT8 i;
+ UINT16 t;
+
+ IMMBYTE(i);
+
+ t = bcd_add( i, RDA );
+
+ if (pSR & SR_C)
+ t = bcd_add( t, 1 );
+
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void dac_i2b( void )
+{
+ UINT8 i;
+ UINT16 t;
+
+ IMMBYTE(i);
+
+ t = bcd_add( i, RDB );
+
+ if (pSR & SR_C)
+ t = bcd_add( t, 1 );
+
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void dac_i2r( void )
+{
+ UINT8 i,r;
+ UINT16 t;
+
+ IMMBYTE(i);
+ IMMBYTE(r);
+
+ t = bcd_add( i, RM(r) );
+
+ if (pSR & SR_C)
+ t = bcd_add( t, 1 );
+
+ WM(r,t);
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 11;
+}
+
+static void dec_a( void )
+{
+ UINT16 t;
+
+ t = RDA - 1;
+
+ WRA( t );
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+ SET_C8(~t);
+
+ tms7000_icount -= 5;
+}
+
+static void dec_b( void )
+{
+ UINT16 t;
+
+ t = RDB - 1;
+
+ WRB( t );
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+ SET_C8(~t);
+
+ tms7000_icount -= 5;
+}
+
+static void dec_r( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+
+ t = RM(r) - 1;
+
+ WM( r, t );
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+ SET_C8(~t);
+
+ tms7000_icount -= 7;
+}
+
+static void decd_a( void )
+{
+ PAIR t;
+
+ t.w.h = 0;
+ t.w.l = RRF16(0);
+ t.d -= 1;
+ WRF16(0,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ SET_C16(~(t.d));
+
+ tms7000_icount -= 9;
+}
+
+static void decd_b( void )
+{
+ PAIR t;
+
+ t.w.h = 0;
+ t.w.l = RRF16(1);
+ t.d -= 1;
+ WRF16(1,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ SET_C16(~(t.d));
+
+ tms7000_icount -= 9;
+}
+
+static void decd_r( void )
+{
+ UINT8 r;
+ PAIR t;
+
+ IMMBYTE(r);
+ t.w.h = 0;
+ t.w.l = RRF16(r);
+ t.d -= 1;
+ WRF16(r,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ SET_C16(~(t.d));
+
+ tms7000_icount -= 11;
+}
+
+static void dint( void )
+{
+ CLR_NZCI;
+ tms7000_icount -= 5;
+}
+
+static void djnz_a( void )
+{
+ UINT16 t;
+
+ t = RDA - 1;
+
+ WRA( t );
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t != 0 )
+ {
+ INT8 s;
+
+ SIMMBYTE(s);
+ pPC += s;
+ tms7000_icount -= 7;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 2;
+ }
+ CHANGE_PC;
+}
+
+static void djnz_b( void )
+{
+ UINT16 t;
+
+ t = RDB - 1;
+
+ WRB( t );
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t != 0 )
+ {
+ INT8 s;
+
+ SIMMBYTE(s);
+ pPC += s;
+ tms7000_icount -= 7;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 2;
+ }
+ CHANGE_PC;
+}
+
+static void djnz_r( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+
+ t = RM(r) - 1;
+
+ WM(r,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ if( t != 0 )
+ {
+ INT8 s;
+
+ SIMMBYTE(s);
+ pPC += s;
+ tms7000_icount -= 9;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 3;
+ }
+ CHANGE_PC;
+}
+
+static void dsb_b2a( void )
+{
+ UINT16 t;
+
+ t = bcd_sub( RDA, RDB );
+
+ if( !(pSR & SR_C) )
+ t = bcd_sub( t, 1 );
+
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void dsb_r2a( void )
+{
+ UINT8 r;
+ UINT16 t;
+
+ IMMBYTE(r);
+
+ t = bcd_sub( RDA, RM(r) );
+
+ if( !(pSR & SR_C) )
+ t = bcd_sub( t, 1 );
+
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void dsb_r2b( void )
+{
+ UINT8 r;
+ UINT16 t;
+
+ IMMBYTE(r);
+
+ t = bcd_sub( RDB, RM(r) );
+
+ if( !(pSR & SR_C) )
+ t = bcd_sub( t, 1 );
+
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void dsb_r2r( void )
+{
+ UINT8 r,s;
+ UINT16 t;
+
+ IMMBYTE(s);
+ IMMBYTE(r);
+
+ t = bcd_sub( RM(s), RM(r) );
+
+ if( !(pSR & SR_C) )
+ t = bcd_sub( t, 1 );
+
+ WM(r,t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 12;
+}
+
+static void dsb_i2a( void )
+{
+ UINT8 i;
+ UINT16 t;
+
+ IMMBYTE(i);
+
+ t = bcd_sub( RDA, i );
+
+ if( !(pSR & SR_C) )
+ t = bcd_sub( t, 1 );
+
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void dsb_i2b( void )
+{
+ UINT8 i;
+ UINT16 t;
+
+ IMMBYTE(i);
+
+ t = bcd_sub( RDB, i );
+
+ if( !(pSR & SR_C) )
+ t = bcd_sub( t, 1 );
+
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void dsb_i2r( void )
+{
+ UINT8 r,i;
+ UINT16 t;
+
+ IMMBYTE(i);
+ IMMBYTE(r);
+
+ t = bcd_sub( RM(r), i );
+
+ if( !(pSR & SR_C) )
+ t = bcd_sub( t, 1 );
+
+ WM(r,t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 11;
+}
+
+static void eint( void )
+{
+ pSR |= (SR_N|SR_Z|SR_C|SR_I);
+ tms7000_icount -= 5;
+ tms7000_check_IRQ_lines();
+}
+
+static void idle( void )
+{
+ tms7000.idle_state = 1;
+ tms7000_icount -= 6;
+}
+
+static void inc_a( void )
+{
+ UINT16 t;
+
+ t = RDA + 1;
+
+ WRA( t );
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void inc_b( void )
+{
+ UINT16 t;
+
+ t = RDB + 1;
+
+ WRB( t );
+
+ CLR_NZC;
+ SET_C8(t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void inc_r( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+
+ t = RM(r) + 1;
+
+ WM( r, t );
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+ SET_C8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void inv_a( void )
+{
+ UINT16 t;
+
+ t = ~(RDA);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void inv_b( void )
+{
+ UINT16 t;
+
+ t = ~(RDA);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void inv_r( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+
+ t = ~(RM(r));
+
+ WM( r, t );
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void jc( void )
+{
+ if( pSR & SR_C )
+ {
+ INT8 s;
+
+ SIMMBYTE( s );
+ pPC += s;
+ CHANGE_PC;
+ tms7000_icount -= 7;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 5;
+ }
+}
+
+static void jeq( void )
+{
+ if( pSR & SR_Z )
+ {
+ INT8 s;
+
+ SIMMBYTE( s );
+ pPC += s;
+ CHANGE_PC;
+ tms7000_icount -= 7;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 5;
+ }
+}
+
+static void jl( void )
+{
+ if( pSR & SR_C )
+ {
+ pPC++;
+ tms7000_icount -= 5;
+ }
+ else
+ {
+ INT8 s;
+
+ SIMMBYTE( s );
+ pPC += s;
+ CHANGE_PC;
+ tms7000_icount -= 7;
+ }
+}
+
+static void jmp( void )
+{
+ INT8 s;
+
+ SIMMBYTE( s );
+ pPC += s;
+ CHANGE_PC;
+ tms7000_icount -= 7;
+}
+
+static void j_jn( void )
+{
+ if( pSR & SR_N )
+ {
+ INT8 s;
+
+ SIMMBYTE( s );
+ pPC += s;
+ CHANGE_PC;
+ tms7000_icount -= 7;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 5;
+ }
+
+}
+
+static void jne( void )
+{
+ if( pSR & SR_Z )
+ {
+ pPC++;
+ tms7000_icount -= 5;
+ }
+ else
+ {
+ INT8 s;
+
+ SIMMBYTE( s );
+ pPC += s;
+ CHANGE_PC;
+ tms7000_icount -= 7;
+ }
+}
+
+static void jp( void )
+{
+ if( pSR & (SR_Z|SR_N) )
+ {
+ pPC++;
+ tms7000_icount -= 5;
+ }
+ else
+ {
+ INT8 s;
+
+ SIMMBYTE( s );
+ pPC += s;
+ CHANGE_PC;
+ tms7000_icount -= 7;
+ }
+}
+
+static void jpz( void )
+{
+ if ((pSR & SR_N) == 0 && (pSR & SR_Z) != 0)
+ {
+ INT8 s;
+
+ SIMMBYTE( s );
+ pPC += s;
+ CHANGE_PC;
+ tms7000_icount -= 7;
+ }
+ else
+ {
+ pPC++;
+ tms7000_icount -= 5;
+ }
+}
+
+static void lda_dir( void )
+{
+ UINT16 t;
+ PAIR i;
+
+ IMMWORD( i );
+ t = RM(i.w.l);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 11;
+}
+
+static void lda_ind( void )
+{
+ UINT16 t;
+ PAIR p;
+ INT8 i;
+
+ IMMBYTE(i);
+ p.w.l=RRF16(i);
+ t = RM(p.w.l);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void lda_inx( void )
+{
+ UINT16 t;
+ PAIR i;
+
+ IMMWORD( i );
+ t = RM(i.w.l + RDB);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 13;
+}
+
+static void ldsp( void )
+{
+ pSP = RDB;
+ tms7000_icount -= 5;
+}
+
+static void mov_a2b( void )
+{
+ UINT16 t;
+
+ t = RDA;
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 6;
+}
+
+static void mov_b2a( void )
+{
+ UINT16 t;
+
+ t = RDB;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+
+static void mov_a2r( void )
+{
+ UINT8 r;
+ UINT16 t;
+
+ IMMBYTE(r);
+
+ t = RDA;
+ WM(r,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void mov_b2r( void )
+{
+ UINT8 r;
+ UINT16 t;
+
+ IMMBYTE(r);
+
+ t = RDB;
+ WM(r,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void mov_r2a( void )
+{
+ UINT8 r;
+ UINT16 t;
+
+ IMMBYTE(r);
+ t = RM(r);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void mov_r2b( void )
+{
+ UINT8 r;
+ UINT16 t;
+
+ IMMBYTE(r);
+ t = RM(r);
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void mov_r2r( void )
+{
+ UINT8 r,s;
+ UINT16 t;
+
+ IMMBYTE(r);
+ IMMBYTE(s);
+ t = RM(r);
+ WM(s,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void mov_i2a( void )
+{
+ UINT16 t;
+
+ IMMBYTE(t);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void mov_i2b( void )
+{
+ UINT16 t;
+
+ IMMBYTE(t);
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void mov_i2r( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(t);
+ IMMBYTE(r);
+ WM(r,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void movd_imm( void )
+{
+ PAIR t;
+ UINT8 r;
+
+ IMMWORD(t);
+ IMMBYTE(r);
+ WRF16(r,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 15;
+
+}
+
+static void movd_r( void )
+{
+ PAIR t;
+ UINT8 r,s;
+
+ IMMBYTE(r);
+ IMMBYTE(s);
+ t.w.l = RRF16(r);
+ WRF16(s,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 14;
+
+}
+
+static void movd_inx( void )
+{
+ PAIR t;
+ UINT8 r;
+
+ IMMWORD(t);
+ t.w.l += RDB;
+ IMMBYTE(r);
+ WRF16(r,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 17;
+}
+
+static void movp_a2p( void )
+{
+ UINT8 p;
+ UINT16 t;
+
+ IMMBYTE(p);
+ t=RDA;
+ WM( 0x0100+p,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void movp_b2p( void )
+{
+ UINT8 p;
+ UINT16 t;
+
+ IMMBYTE(p);
+ t=RDB;
+ WM( 0x0100+p,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+#if 0
+/* this appears to be unused */
+static void movp_r2p( void )
+{
+ UINT8 p,r;
+ UINT16 t;
+
+ IMMBYTE(r);
+ IMMBYTE(p);
+ t=RM(r);
+ WM( 0x0100+p,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 11;
+}
+#endif
+
+static void movp_p2a( void )
+{
+ UINT8 p;
+ UINT16 t;
+
+ IMMBYTE(p);
+ t=RM(0x0100+p);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void movp_p2b( void )
+{
+ UINT8 p;
+ UINT16 t;
+
+ IMMBYTE(p);
+ t=RM(0x0100+p);
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void mpy_ba( void )
+{
+ PAIR t;
+
+ t.w.l = RDA * RDB;
+
+ WRF16(0x01,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 43;
+
+}
+
+static void mpy_ra( void )
+{
+ PAIR t;
+ UINT8 r;
+
+ IMMBYTE(r);
+
+ t.w.l = RDA * RM(r);
+
+ WRF16(0x01,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 46;
+
+}
+
+static void mpy_rb( void )
+{
+ PAIR t;
+ UINT8 r;
+
+ IMMBYTE(r);
+
+ t.w.l = RDB * RM(r);
+
+ WRF16(0x01,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 46;
+
+}
+
+static void mpy_rr( void )
+{
+ PAIR t;
+ UINT8 r,s;
+
+ IMMBYTE(r);
+ IMMBYTE(s);
+
+ t.w.l = RM(s) * RM(r);
+
+ WRF16(0x01,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 48;
+
+}
+
+static void mpy_ia( void )
+{
+ PAIR t;
+ UINT8 i;
+
+ IMMBYTE(i);
+
+ t.w.l = RDA * i;
+
+ WRF16(0x01,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 45;
+
+}
+
+static void mpy_ib( void )
+{
+ PAIR t;
+ UINT8 i;
+
+ IMMBYTE(i);
+
+ t.w.l = RDB * i;
+
+ WRF16(0x01,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 45;
+
+}
+
+static void mpy_ir( void )
+{
+ PAIR t;
+ UINT8 i,r;
+
+ IMMBYTE(i);
+ IMMBYTE(r);
+
+ t.w.l = RM(r) * i;
+
+ WRF16(0x01,t);
+
+ CLR_NZC;
+ SET_N8(t.b.h);
+ SET_Z8(t.b.h);
+
+ tms7000_icount -= 47;
+
+}
+
+static void nop( void )
+{
+ tms7000_icount -= 4;
+}
+
+static void or_b2a( void )
+{
+ UINT8 t;
+
+ t = RDA | RDB;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void or_r2a( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) | RDA;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void or_r2b( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) | RDB;
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void or_r2r( void )
+{
+ UINT8 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = RM(i) | RM(j);
+ WM(j,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void or_i2a( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v | RDA;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void or_i2b( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v | RDB;
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void or_i2r( void )
+{
+ UINT8 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = i | RM(j);
+ WM(j,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void orp_a2p( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+ t = RDA | RM( 0x0100 + v);
+ WM( 0x0100+v, t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void orp_b2p( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+ t = RDB | RM( 0x0100 + v);
+ WM( 0x0100+v, t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void orp_i2p( void )
+{
+ UINT8 t;
+ UINT8 i,v;
+
+ IMMBYTE(i);
+ IMMBYTE(v);
+ t = i | RM( 0x0100 + v);
+ WM( 0x0100+v, t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 11;
+}
+
+static void pop_a( void )
+{
+ UINT16 t;
+
+ PULLBYTE(t);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 6;
+}
+
+static void pop_b( void )
+{
+ UINT16 t;
+
+ PULLBYTE(t);
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 6;
+}
+
+static void pop_r( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+ PULLBYTE(t);
+ WM(r,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void pop_st( void )
+{
+ UINT16 t;
+
+ PULLBYTE(t);
+ pSR = t;
+
+ tms7000_icount -= 6;
+}
+
+static void push_a( void )
+{
+ UINT16 t;
+
+ t = RDA;
+ PUSHBYTE(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 6;
+}
+
+static void push_b( void )
+{
+ UINT16 t;
+
+ t = RDB;
+ PUSHBYTE(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 6;
+}
+
+static void push_r( void )
+{
+ UINT16 t;
+ INT8 r;
+
+ IMMBYTE(r);
+ t = RM(r);
+ PUSHBYTE(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void push_st( void )
+{
+ UINT16 t;
+ t = pSR;
+ PUSHBYTE(t);
+
+ tms7000_icount -= 6;
+}
+
+static void reti( void )
+{
+ PULLWORD( PC );
+ PULLBYTE( pSR );
+
+ tms7000_icount -= 9;
+ tms7000_check_IRQ_lines();
+}
+
+static void rets( void )
+{
+ PULLWORD( PC );
+ tms7000_icount -= 7;
+}
+
+static void rl_a( void )
+{
+ UINT16 t;
+
+ t = RDA << 1;
+
+ CLR_NZC;
+ SET_C8(t);
+
+ if( pSR & SR_C )
+ t |= 0x01;
+
+ SET_N8(t);
+ SET_Z8(t);
+ WRA(t);
+
+ tms7000_icount -= 5;
+}
+
+static void rl_b( void )
+{
+ UINT16 t;
+
+ t = RDB << 1;
+
+ CLR_NZC;
+ SET_C8(t);
+
+ if( pSR & SR_C )
+ t |= 0x01;
+
+ SET_N8(t);
+ SET_Z8(t);
+ WRB(t);
+
+ tms7000_icount -= 5;
+}
+
+static void rl_r( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+ t = RM(r) << 1;
+
+ CLR_NZC;
+ SET_C8(t);
+
+ if( pSR & SR_C )
+ t |= 0x01;
+
+ SET_N8(t);
+ SET_Z8(t);
+ WM(r,t);
+
+ tms7000_icount -= 7;
+}
+
+static void rlc_a( void )
+{
+ UINT16 t;
+ int old_carry;
+
+ old_carry = (pSR & SR_C);
+
+ t = RDA << 1;
+
+ CLR_NZC;
+ SET_C8(t);
+
+ if( old_carry )
+ t |= 0x01;
+
+ SET_N8(t);
+ SET_Z8(t);
+ WRA(t);
+
+ tms7000_icount -= 5;
+}
+
+static void rlc_b( void )
+{
+ UINT16 t;
+ int old_carry;
+
+ old_carry = (pSR & SR_C);
+
+ t = RDB << 1;
+
+ CLR_NZC;
+ SET_C8(t);
+
+ if( old_carry )
+ t |= 0x01;
+
+ SET_N8(t);
+ SET_Z8(t);
+ WRB(t);
+
+ tms7000_icount -= 5;
+}
+
+static void rlc_r( void )
+{
+ UINT16 t;
+ UINT8 r;
+ int old_carry;
+
+ old_carry = (pSR & SR_C);
+
+ IMMBYTE(r);
+ t = RM(r) << 1;
+
+ CLR_NZC;
+ SET_C8(t);
+
+ if( old_carry )
+ t |= 0x01;
+
+ SET_N8(t);
+ SET_Z8(t);
+ WM(r,t);
+
+ tms7000_icount -= 7;
+}
+
+static void rr_a( void )
+{
+ UINT16 t;
+ int old_bit0;
+
+ t = RDA;
+
+ old_bit0 = t & 0x0001;
+ t = t >> 1;
+
+ CLR_NZC;
+
+ if( old_bit0 )
+ {
+ SETC;
+ t |= 0x80;
+ }
+
+ SET_N8(t);
+ SET_Z8(t);
+
+ WRA(t);
+
+ tms7000_icount -= 5;
+}
+
+static void rr_b( void )
+{
+ UINT16 t;
+ int old_bit0;
+
+ t = RDB;
+
+ old_bit0 = t & 0x0001;
+ t = t >> 1;
+
+ CLR_NZC;
+
+ if( old_bit0 )
+ {
+ SETC;
+ t |= 0x80;
+ }
+
+ SET_N8(t);
+ SET_Z8(t);
+
+ WRB(t);
+
+ tms7000_icount -= 5;
+}
+
+static void rr_r( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ int old_bit0;
+
+ IMMBYTE(r);
+ t = RM(r);
+
+ old_bit0 = t & 0x0001;
+ t = t >> 1;
+
+ CLR_NZC;
+
+ if( old_bit0 )
+ {
+ SETC;
+ t |= 0x80;
+ }
+
+ SET_N8(t);
+ SET_Z8(t);
+
+ WM(r,t);
+
+ tms7000_icount -= 7;
+}
+
+static void rrc_a( void )
+{
+ UINT16 t;
+ int old_bit0;
+
+ t = RDA;
+
+ old_bit0 = t & 0x0001;
+ /* Place carry bit in 9th position */
+ t |= ((pSR & SR_C) << 1);
+ t = t >> 1;
+
+ CLR_NZC;
+
+ if( old_bit0 )
+ SETC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ WRA(t);
+
+ tms7000_icount -= 5;
+}
+
+static void rrc_b( void )
+{
+ UINT16 t;
+ int old_bit0;
+
+ t = RDB;
+
+ old_bit0 = t & 0x0001;
+ /* Place carry bit in 9th position */
+ t |= ((pSR & SR_C) << 1);
+ t = t >> 1;
+
+ CLR_NZC;
+
+ if( old_bit0 )
+ SETC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ WRB(t);
+
+ tms7000_icount -= 5;
+}
+
+static void rrc_r( void )
+{
+ UINT16 t;
+ UINT8 r;
+ int old_bit0;
+
+ IMMBYTE(r);
+ t = RM(r);
+
+ old_bit0 = t & 0x0001;
+ /* Place carry bit in 9th position */
+ t |= ((pSR & SR_C) << 1);
+ t = t >> 1;
+
+ CLR_NZC;
+
+ if( old_bit0 )
+ SETC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ WM(r,t);
+
+ tms7000_icount -= 7;
+}
+
+static void sbb_ba( void )
+{
+ UINT16 t;
+
+ t = RDA - RDB - ((pSR & SR_C) ? 0 : 1);
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void sbb_ra( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+ t = RDA - RM(r) - ((pSR & SR_C) ? 0 : 1);
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void sbb_rb( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+ t = RDB - RM(r) - ((pSR & SR_C) ? 0 : 1);
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void sbb_rr( void )
+{
+ UINT16 t;
+ UINT8 r,s;
+
+ IMMBYTE(s);
+ IMMBYTE(r);
+ t = RM(r) - RM(s) - ((pSR & SR_C) ? 0 : 1);
+ WM(r,t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void sbb_ia( void )
+{
+ UINT16 t;
+ UINT8 i;
+
+ IMMBYTE(i);
+ t = RDA - i - ((pSR & SR_C) ? 0 : 1);
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void sbb_ib( void )
+{
+ UINT16 t;
+ UINT8 i;
+
+ IMMBYTE(i);
+ t = RDB - i - ((pSR & SR_C) ? 0 : 1);
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void sbb_ir( void )
+{
+ UINT16 t;
+ UINT8 r,i;
+
+ IMMBYTE(i);
+ IMMBYTE(r);
+ t = RM(r) - i - ((pSR & SR_C) ? 0 : 1);
+ WM(r,t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void setc( void )
+{
+ CLR_NZC;
+ pSR |= (SR_C|SR_Z);
+
+ tms7000_icount -= 5;
+}
+
+static void sta_dir( void )
+{
+ UINT16 t;
+ PAIR i;
+
+ t = RDA;
+ IMMWORD( i );
+
+ WM(i.w.l,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 11;
+}
+
+static void sta_ind( void )
+{
+ UINT16 t;
+ PAIR p;
+ INT8 r;
+
+ IMMBYTE(r);
+ p.w.l = RRF16(r);
+ t = RDA;
+ WM(p.w.l,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void sta_inx( void )
+{
+ UINT16 t;
+ PAIR i;
+
+ IMMWORD( i );
+ t = RDA;
+ WM(i.w.l+RDB,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 13;
+}
+
+static void stsp( void )
+{
+ WRB(pSP);
+
+ tms7000_icount -= 6;
+}
+
+static void sub_ba( void )
+{
+ UINT16 t;
+
+ t = RDA - RDB;
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void sub_ra( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+ t = RDA - RM(r);
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void sub_rb( void )
+{
+ UINT16 t;
+ UINT8 r;
+
+ IMMBYTE(r);
+ t = RDB - RM(r);
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void sub_rr( void )
+{
+ UINT16 t;
+ UINT8 r,s;
+
+ IMMBYTE(s);
+ IMMBYTE(r);
+ t = RM(r) - RM(s);
+ WM(r,t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void sub_ia( void )
+{
+ UINT16 t;
+ UINT8 i;
+
+ IMMBYTE(i);
+ t = RDA - i;
+ WRA(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void sub_ib( void )
+{
+ UINT16 t;
+ UINT8 i;
+
+ IMMBYTE(i);
+ t = RDB - i;
+ WRB(t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void sub_ir( void )
+{
+ UINT16 t;
+ UINT8 r,i;
+
+ IMMBYTE(i);
+ IMMBYTE(r);
+ t = RM(r) - i;
+ WM(r,t);
+
+ CLR_NZC;
+ SET_C8(~t);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void trap_0( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xfffe);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_1( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xfffc);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_2( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xfffa);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_3( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xfff8);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_4( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xfff6);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_5( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xfff4);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_6( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xfff2);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_7( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xfff0);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_8( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffee);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_9( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffec);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_10( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffea);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_11( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffe8);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_12( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffe6);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_13( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffe4);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_14( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffe2);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_15( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffe0);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_16( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffde);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_17( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffdc);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_18( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffda);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_19( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffd8);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_20( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffd6);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_21( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffd4);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_22( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffd2);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void trap_23( void )
+{
+ PUSHWORD( PC );
+ pPC = RM16(0xffd0);
+ CHANGE_PC;
+ tms7000_icount -= 14;
+}
+
+static void swap_a( void )
+{
+ UINT8 a,b;
+ UINT16 t;
+
+ a = b = RDA;
+
+ a <<= 4;
+ b >>= 4;
+ t = a+b;
+
+ WRA(t);
+
+ CLR_NZC;
+
+ pSR|=((t&0x0001)<<7);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -=8;
+}
+
+static void swap_b( void )
+{
+ UINT8 a,b;
+ UINT16 t;
+
+ a = b = RDB;
+
+ a <<= 4;
+ b >>= 4;
+ t = a+b;
+
+ WRB(t);
+
+ CLR_NZC;
+
+ pSR|=((t&0x0001)<<7);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -=8;
+}
+
+static void swap_r( void )
+{
+ UINT8 a,b,r;
+ UINT16 t;
+
+ IMMBYTE(r);
+ a = b = RM(r);
+
+ a <<= 4;
+ b >>= 4;
+ t = a+b;
+
+ WM(r,t);
+
+ CLR_NZC;
+
+ pSR|=((t&0x0001)<<7);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -=8;
+}
+
+static void swap_r_exl( void )
+{
+ UINT8 a,b,r;
+ UINT16 t;
+
+ IMMBYTE(r);
+
+ if (r == 0)
+ { /* opcode D7 00 (LVDP) mostly equivalent to MOVP P46,A??? (timings must
+ be different, possibly the microcode polls the state of the VDP RDY
+ line prior to doing the transfer) */
+ t=RM(0x012e);
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9; /* ?????? */
+ }
+ else
+ { /* stright swap Rn instruction */
+ a = b = RM(r);
+
+ a <<= 4;
+ b >>= 4;
+ t = a+b;
+
+ WM(r,t);
+
+ CLR_NZC;
+
+ pSR|=((t&0x0001)<<7);
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -=8;
+ }
+}
+
+static void tstb( void )
+{
+ UINT16 t;
+
+ t=RDB;
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 6;
+}
+
+static void xchb_a( void )
+{
+ UINT16 t,u;
+
+ t = RDB;
+ u = RDA;
+
+ WRA(t);
+ WRB(u);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 6;
+}
+
+static void xchb_b( void )
+{
+ UINT16 t;
+/* UINT16 u; */
+
+ t = RDB;
+/* u = RDB; */
+
+/* WRB(t); */
+/* WRB(u); */
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 6;
+}
+
+static void xchb_r( void )
+{
+ UINT16 t,u;
+ UINT8 r;
+
+ IMMBYTE(r);
+
+ t = RDB;
+ u = RM(r);
+
+ WRA(t);
+ WRB(u);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void xor_b2a( void )
+{
+ UINT8 t;
+
+ t = RDA ^ RDB;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 5;
+}
+
+static void xor_r2a( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) ^ RDA;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void xor_r2b( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = RM(v) ^ RDB;
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 8;
+}
+
+static void xor_r2r( void )
+{
+ UINT8 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = RM(i) ^ RM(j);
+ WM(j,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void xor_i2a( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v ^ RDA;
+ WRA(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void xor_i2b( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+
+ t = v ^ RDB;
+ WRB(t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 7;
+}
+
+static void xor_i2r( void )
+{
+ UINT8 t;
+ UINT8 i,j;
+
+ IMMBYTE(i);
+ IMMBYTE(j);
+
+ t = i ^ RM(j);
+ WM(j,t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void xorp_a2p( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+ t = RDA ^ RM( 0x0100 + v);
+ WM( 0x0100+v, t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 10;
+}
+
+static void xorp_b2p( void )
+{
+ UINT8 t;
+ UINT8 v;
+
+ IMMBYTE(v);
+ t = RDB ^ RM( 0x0100 + v);
+ WM( 0x0100+v, t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 9;
+}
+
+static void xorp_i2p( void )
+{
+ UINT8 t;
+ UINT8 i,v;
+
+ IMMBYTE(i);
+ IMMBYTE(v);
+ t = i ^ RM( 0x0100 + v);
+ WM( 0x0100+v, t);
+
+ CLR_NZC;
+ SET_N8(t);
+ SET_Z8(t);
+
+ tms7000_icount -= 11;
+}
diff --git a/src/emu/cpu/tms7000/tms70tb.c b/src/emu/cpu/tms7000/tms70tb.c
new file mode 100644
index 00000000000..c9b6587e234
--- /dev/null
+++ b/src/emu/cpu/tms7000/tms70tb.c
@@ -0,0 +1,124 @@
+/*****************************************************************************
+ *
+ * tms70tb.c (function table)
+ * Portable TMS7000 emulator (Texas Instruments 7000)
+ *
+ * Copyright (c) 2001 tim lindner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * tlindner@macmess.org
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+static void (*opfn[0x100])(void) = {
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7,
+ 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+
+/* 0x0X */ nop, idle, illegal, illegal, illegal, eint, dint, setc,
+ pop_st, stsp, rets, reti, illegal, ldsp, push_st, illegal,
+
+/* 0x1X */ illegal, illegal, mov_r2a, and_r2a, or_r2a, xor_r2a, btjo_r2a,btjz_r2a,
+ add_r2a, adc_r2a, sub_ra, sbb_ra, mpy_ra, cmp_ra, dac_r2a, dsb_r2a,
+
+/* 0x2X */ illegal, illegal, mov_i2a, and_i2a, or_i2a, xor_i2a, btjo_i2a,btjz_i2a,
+ add_i2a, adc_i2a, sub_ia, sbb_ia, mpy_ia, cmp_ia, dac_i2a, dsb_i2a,
+
+/* 0x3X */ illegal, illegal, mov_r2b, and_r2b, or_r2b, xor_r2b, btjo_r2b,btjz_r2b,
+ add_r2b, adc_r2b, sub_rb, sbb_rb, mpy_rb, cmp_rb, dac_r2b, dsb_r2b,
+
+/* 0x4X */ illegal, illegal, mov_r2r, and_r2r, or_r2r, xor_r2r, btjo_r2r,btjz_r2r,
+ add_r2r, adc_r2r, sub_rr, sbb_rr, mpy_rr, cmp_rr, dac_r2r, dsb_r2r,
+
+/* 0x5X */ illegal, illegal, mov_i2b, and_i2b, or_i2b, xor_i2b, btjo_i2b,btjz_i2b,
+ add_i2b, adc_i2b, sub_ib, sbb_ib, mpy_ib, cmp_ib, dac_i2b, dsb_i2b,
+
+/* 0x6X */ illegal, illegal, mov_b2a, and_b2a, or_b2a, xor_b2a, btjo_b2a,btjz_b2a,
+ add_b2a, adc_b2a, sub_ba, sbb_ba, mpy_ba, cmp_ba, dac_b2a, dsb_b2a,
+
+/* 0x7X */ illegal, illegal, mov_i2r, and_i2r, or_i2r, xor_i2r, btjo_i2r,btjz_i2r,
+ add_i2r, adc_i2r, sub_ir, sbb_ir, mpy_ir, cmp_ir, dac_i2r, dsb_i2r,
+
+/* 0x8X */ movp_p2a,illegal, movp_a2p,andp_a2p,orp_a2p, xorp_a2p,btjop_ap,btjzp_ap,
+ movd_imm,illegal, lda_dir, sta_dir, br_dir, cmpa_dir,call_dir,illegal,
+
+/* 0x9X */ illegal, movp_p2b,movp_b2p,andp_b2p,orp_b2p, xorp_b2p,btjop_bp,btjzp_bp,
+ movd_r, illegal, lda_ind, sta_ind, br_ind, cmpa_ind,call_ind,illegal,
+
+/* 0xAX */ illegal, illegal, movp_i2p,andp_i2p,orp_i2p, xorp_i2p,btjop_ip,btjzp_ip,
+ movd_inx,illegal, lda_inx, sta_inx, br_inx, cmpa_inx,call_inx,illegal,
+
+/* 0xBX */ clrc, illegal, dec_a, inc_a, inv_a, clr_a, xchb_a, swap_a,
+ push_a, pop_a, djnz_a, decd_a, rr_a, rrc_a, rl_a, rlc_a,
+
+/* 0xCX */ mov_a2b, tstb, dec_b, inc_b, inv_b, clr_b, xchb_b, swap_b,
+ push_b, pop_b, djnz_b, decd_b, rr_b, rrc_b, rl_b, rlc_b,
+
+/* 0xDX */ mov_a2r, mov_b2r, dec_r, inc_r, inv_r, clr_r, xchb_r, swap_r,
+ push_r, pop_r, djnz_r, decd_r, rr_r, rrc_r, rl_r, rlc_r,
+
+/* 0xEX */ jmp, j_jn, jeq, jc, jp, jpz, jne, jl,
+ trap_23, trap_22, trap_21, trap_20, trap_19, trap_18, trap_17, trap_16,
+
+/* 0xFX */ trap_15, trap_14, trap_13, trap_12, trap_11, trap_10, trap_9, trap_8,
+ trap_7, trap_6, trap_5, trap_4, trap_3, trap_2, trap_1, trap_0
+};
+
+static void (*opfn_exl[0x100])(void) = {
+/* 0xX0, 0xX1, 0xX2, 0xX3, 0xX4, 0xX5, 0xX6, 0xX7,
+ 0xX8, 0xX9, 0xXA, 0xXB, 0xXC, 0xXD, 0xXE, 0xXF */
+
+/* 0x0X */ nop, idle, illegal, illegal, illegal, eint, dint, setc,
+ pop_st, stsp, rets, reti, illegal, ldsp, push_st, illegal,
+
+/* 0x1X */ illegal, illegal, mov_r2a, and_r2a, or_r2a, xor_r2a, btjo_r2a,btjz_r2a,
+ add_r2a, adc_r2a, sub_ra, sbb_ra, mpy_ra, cmp_ra, dac_r2a, dsb_r2a,
+
+/* 0x2X */ illegal, illegal, mov_i2a, and_i2a, or_i2a, xor_i2a, btjo_i2a,btjz_i2a,
+ add_i2a, adc_i2a, sub_ia, sbb_ia, mpy_ia, cmp_ia, dac_i2a, dsb_i2a,
+
+/* 0x3X */ illegal, illegal, mov_r2b, and_r2b, or_r2b, xor_r2b, btjo_r2b,btjz_r2b,
+ add_r2b, adc_r2b, sub_rb, sbb_rb, mpy_rb, cmp_rb, dac_r2b, dsb_r2b,
+
+/* 0x4X */ illegal, illegal, mov_r2r, and_r2r, or_r2r, xor_r2r, btjo_r2r,btjz_r2r,
+ add_r2r, adc_r2r, sub_rr, sbb_rr, mpy_rr, cmp_rr, dac_r2r, dsb_r2r,
+
+/* 0x5X */ illegal, illegal, mov_i2b, and_i2b, or_i2b, xor_i2b, btjo_i2b,btjz_i2b,
+ add_i2b, adc_i2b, sub_ib, sbb_ib, mpy_ib, cmp_ib, dac_i2b, dsb_i2b,
+
+/* 0x6X */ illegal, illegal, mov_b2a, and_b2a, or_b2a, xor_b2a, btjo_b2a,btjz_b2a,
+ add_b2a, adc_b2a, sub_ba, sbb_ba, mpy_ba, cmp_ba, dac_b2a, dsb_b2a,
+
+/* 0x7X */ illegal, illegal, mov_i2r, and_i2r, or_i2r, xor_i2r, btjo_i2r,btjz_i2r,
+ add_i2r, adc_i2r, sub_ir, sbb_ir, mpy_ir, cmp_ir, dac_i2r, dsb_i2r,
+
+/* 0x8X */ movp_p2a,illegal, movp_a2p,andp_a2p,orp_a2p, xorp_a2p,btjop_ap,btjzp_ap,
+ movd_imm,illegal, lda_dir, sta_dir, br_dir, cmpa_dir,call_dir,illegal,
+
+/* 0x9X */ illegal, movp_p2b,movp_b2p,andp_b2p,orp_b2p, xorp_b2p,btjop_bp,btjzp_bp,
+ movd_r, illegal, lda_ind, sta_ind, br_ind, cmpa_ind,call_ind,illegal,
+
+/* 0xAX */ illegal, illegal, movp_i2p,andp_i2p,orp_i2p, xorp_i2p,btjop_ip,btjzp_ip,
+ movd_inx,illegal, lda_inx, sta_inx, br_inx, cmpa_inx,call_inx,illegal,
+
+/* 0xBX */ clrc, illegal, dec_a, inc_a, inv_a, clr_a, xchb_a, swap_a,
+ push_a, pop_a, djnz_a, decd_a, rr_a, rrc_a, rl_a, rlc_a,
+
+/* 0xCX */ mov_a2b, tstb, dec_b, inc_b, inv_b, clr_b, xchb_b, swap_b,
+ push_b, pop_b, djnz_b, decd_b, rr_b, rrc_b, rl_b, rlc_b,
+
+/* 0xDX */ mov_a2r, mov_b2r, dec_r, inc_r, inv_r, clr_r, xchb_r, swap_r_exl,
+ push_r, pop_r, djnz_r, decd_r, rr_r, rrc_r, rl_r, rlc_r,
+
+/* 0xEX */ jmp, j_jn, jeq, jc, jp, jpz, jne, jl,
+ trap_23, trap_22, trap_21, trap_20, trap_19, trap_18, trap_17, trap_16,
+
+/* 0xFX */ trap_15, trap_14, trap_13, trap_12, trap_11, trap_10, trap_9, trap_8,
+ trap_7, trap_6, trap_5, trap_4, trap_3, trap_2, trap_1, trap_0
+};
diff --git a/src/emu/cpu/tms9900/9900dasm.c b/src/emu/cpu/tms9900/9900dasm.c
new file mode 100644
index 00000000000..af5a6d035b5
--- /dev/null
+++ b/src/emu/cpu/tms9900/9900dasm.c
@@ -0,0 +1,801 @@
+/*****************************************************************************
+ *
+ * 9900dasm.c
+ * TMS 9900 family disassembler
+ *
+ * Raphael Nabet 2003
+ * Based on previous work Copyright (c) 1998 John Butler.
+ * Based on 6502dasm.c 6502/65c02/6510 disassembler by Juergen Buchmueller
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+
+#include "debugger.h"
+#include "tms9900.h"
+
+#define MASK 0x0000ffff
+#define BITS(val,n1,n2) ((val>>(15-(n2))) & (MASK>>(15-((n2)-(n1)))))
+
+typedef enum
+{
+ format_1, /* 2 address instructions */
+ format_2a, /* jump instructions */
+ format_2b, /* bit I/O instructions */
+ format_3_9, /* logical, multiply, and divide instructions */
+ format_4, /* CRU instructions */
+ format_5, /* register shift instructions */
+ format_6, /* single address instructions */
+ format_7, /* instructions without operands */
+ format_8a, /* immediate instructions (destination register) */
+ format_8b, /* immediate instructions (no destination register) */
+ format_9, /* extended operation instruction */
+ format_10, /* memory map file instruction */
+ format_11, /* multiple precision instructions */
+ format_12, /* string instructions */
+ format_13, /* multiple precision shift instructions */
+ format_14, /* bit testing instructions */
+ format_15, /* invert order of field instruction */
+ format_16, /* field instructions */
+ format_17, /* alter register and jump instructions */
+ format_18, /* single register operand instructions */
+ format_liim,/* format for liim (looks like format 18) */
+ format_19, /* move address instruction */
+ format_20, /* list search instructions */
+ format_21, /* extend precision instruction */
+
+ illegal
+} format_t;
+
+/* definitions for flags */
+enum
+{
+ /* processor set on which opcodes are available */
+ ps_any = 0x01, /* every processor in the tms9900/ti990 family */
+ ps_mapper = 0x02, /* processors with memory mapper (ti990/10, ti990/12,
+ and tms99000 with mapper coprocessor) */
+ ps_tms9995 = 0x04, /* ti990/12, tms9995, and later */
+ ps_tms99000 = 0x08, /* ti990/12, tms99000, and later */
+ ps_ti990_12 = 0x10, /* ti990/12 only */
+
+ /* additional flags for special decoding */
+ sd_11 = 0x100, /* bit 11 should be cleared in li, ai, andi, ori, ci, stwp, stst */
+ sd_11_15 = 0x200 /* bits 11-15 should be cleared in lwpi, limi, idle, rset, rtwp, ckon, ckof, lrex */
+};
+
+typedef struct description_t
+{
+ const char *mnemonic;
+ format_t format;
+ int flags;
+} description_t;
+
+
+enum opcodes {
+ /* basic instruction set */
+ _a=0, _ab, _c, _cb, _s, _sb, _soc, _socb, _szc, _szcb,
+ _mov, _movb, _coc, _czc, _xor, _mpy, _div, _xop, _b, _bl,
+ _blwp, _clr, _seto, _inv, _neg, _abs, _swpb, _inc, _inct, _dec,
+ _dect, _x, _ldcr, _stcr, _sbo, _sbz, _tb, _jeq, _jgt, _jh,
+ _jhe, _jl, _jle, _jlt, _jmp, _jnc, _jne, _jno, _joc, _jop,
+ _sla, _sra, _src, _srl, _ai, _andi, _ci, _li, _ori, _lwpi,
+ _limi, _stst, _stwp, _rtwp, _idle, _rset, _ckof, _ckon, _lrex,
+
+ /* mapper instruction set */
+ _lds, _ldd, _lmf,
+
+ /* tms9995 instruction set */
+ _divs, _mpys, _lst, _lwp,
+
+ /* tms99000 instruction set */
+ _bind,
+
+ /* ti990/12 instruction set */
+ _sram, _slam, _rto, _lto, _cnto, _slsl, _slsp, _bdc, _dbc, _swpm,
+ _xorm, _orm, _andm, _sm, _am, _mova, _emd, _eint, _dint, _stpc,
+ _cs, _seqb, _movs, _lim, _lcs, _blsk, _mvsr, _mvsk, _pops, _pshs,
+
+ _cri, _cdi, _negr, _negd, _cre, _cde, _cer, _ced, _nrm, _tmb,
+ _tcmb, _tsmb, _srj, _arj, _xit, _insf, _xv, _xf, _ar, _cir,
+ _sr, _mr, _dr, _lr, _str, _iof, _sneb, _crc, _ts, _ad,
+ _cid, _sd, _md, _dd, _ld, _std, _ep,
+
+ /* tms9940-only instruction set */
+ _liim, _dca, _dcs,
+
+ _ill
+};
+
+
+static const description_t descriptions[144+3+1] =
+{
+ /* basic instruction set */
+ { "a", format_1, ps_any }, { "ab", format_1, ps_any },
+ { "c", format_1, ps_any }, { "cb", format_1, ps_any },
+ { "s", format_1, ps_any }, { "sb", format_1, ps_any },
+ { "soc", format_1, ps_any }, { "socb", format_1, ps_any },
+ { "szc", format_1, ps_any }, { "szcb", format_1, ps_any },
+ { "mov", format_1, ps_any }, { "movb", format_1, ps_any },
+ { "coc", format_3_9, ps_any }, { "czc", format_3_9, ps_any },
+ { "xor", format_3_9, ps_any }, { "mpy", format_3_9, ps_any },
+ { "div", format_3_9, ps_any }, { "xop", format_9, ps_any },
+ { "b", format_6, ps_any }, { "bl", format_6, ps_any },
+ { "blwp", format_6, ps_any }, { "clr", format_6, ps_any },
+ { "seto", format_6, ps_any }, { "inv", format_6, ps_any },
+ { "neg", format_6, ps_any }, { "abs", format_6, ps_any },
+ { "swpb", format_6, ps_any }, { "inc", format_6, ps_any },
+ { "inct", format_6, ps_any }, { "dec", format_6, ps_any },
+ { "dect", format_6, ps_any }, { "x", format_6, ps_any },
+ { "ldcr", format_4, ps_any }, { "stcr", format_4, ps_any },
+ { "sbo", format_2b, ps_any }, { "sbz", format_2b, ps_any },
+ { "tb", format_2b, ps_any }, { "jeq", format_2a, ps_any },
+ { "jgt", format_2a, ps_any }, { "jh", format_2a, ps_any },
+ { "jhe", format_2a, ps_any }, { "jl", format_2a, ps_any },
+ { "jle", format_2a, ps_any }, { "jlt", format_2a, ps_any },
+ { "jmp", format_2a, ps_any }, { "jnc", format_2a, ps_any },
+ { "jne", format_2a, ps_any }, { "jno", format_2a, ps_any },
+ { "joc", format_2a, ps_any }, { "jop", format_2a, ps_any },
+ { "sla", format_5, ps_any }, { "sra", format_5, ps_any },
+ { "src", format_5, ps_any }, { "srl", format_5, ps_any },
+ { "ai", format_8a, ps_any|sd_11 }, { "andi", format_8a, ps_any|sd_11 },
+ { "ci", format_8a, ps_any|sd_11 }, { "li", format_8a, ps_any|sd_11 },
+ { "ori", format_8a, ps_any|sd_11 }, { "lwpi", format_8b, ps_any|sd_11|sd_11_15 },
+ { "limi", format_8b, ps_any|sd_11|sd_11_15 }, { "stst", format_18, ps_any|sd_11 },
+ { "stwp", format_18, ps_any|sd_11 }, { "rtwp", format_7, ps_any|sd_11|sd_11_15 },
+ { "idle", format_7, ps_any|sd_11|sd_11_15 }, { "rset", format_7, ps_any|sd_11|sd_11_15 },
+ { "ckof", format_7, ps_any|sd_11|sd_11_15 }, { "ckon", format_7, ps_any|sd_11|sd_11_15 },
+ { "lrex", format_7, ps_any|sd_11|sd_11_15 },
+
+ /* mapper instruction set */
+ { "lds", format_6, ps_mapper }, { "ldd", format_6, ps_mapper },
+ { "lmf", format_10, ps_mapper },
+
+ /* tms9995 instruction set */
+ { "divs", format_6, ps_tms9995 }, { "mpys", format_6, ps_tms9995 },
+ { "lst", format_18, ps_tms9995 }, { "lwp", format_18, ps_tms9995 },
+
+ /* tms99000 instruction set */
+ { "bind", format_6, ps_tms99000 },
+
+ /* ti990/12 instruction set */
+ { "sram", format_13, ps_ti990_12 }, { "slam", format_13, ps_ti990_12 },
+ { "rto", format_11, ps_ti990_12 }, { "lto", format_11, ps_ti990_12 },
+ { "cnto", format_11, ps_ti990_12 }, { "slsl", format_20, ps_ti990_12 },
+ { "slsp", format_20, ps_ti990_12 }, { "bdc", format_11, ps_ti990_12 },
+ { "dbc", format_11, ps_ti990_12 }, { "swpm", format_11, ps_ti990_12 },
+ { "xorm", format_11, ps_ti990_12 }, { "orm", format_11, ps_ti990_12 },
+ { "andm", format_11, ps_ti990_12 }, { "sm", format_11, ps_ti990_12 },
+ { "am", format_11, ps_ti990_12 }, { "mova", format_19, ps_ti990_12 },
+ { "emd", format_7, ps_ti990_12 }, { "eint", format_7, ps_ti990_12 },
+ { "dint", format_7, ps_ti990_12 }, { "stpc", format_18, ps_ti990_12 },
+ { "cs", format_12, ps_ti990_12 }, { "seqb", format_12, ps_ti990_12 },
+ { "movs", format_12, ps_ti990_12 }, { "lim", format_18, ps_ti990_12 },
+ { "lcs", format_18, ps_ti990_12 }, { "blsk", format_8a, ps_ti990_12 },
+ { "mvsr", format_12, ps_ti990_12 }, { "mvsk", format_12, ps_ti990_12 },
+ { "pops", format_12, ps_ti990_12 }, { "pshs", format_12, ps_ti990_12 },
+ { "cri", format_7, ps_ti990_12 }, { "cdi", format_7, ps_ti990_12 },
+ { "negr", format_7, ps_ti990_12 }, { "negd", format_7, ps_ti990_12 },
+ { "cre", format_7, ps_ti990_12 }, { "cde", format_7, ps_ti990_12 },
+ { "cer", format_7, ps_ti990_12 }, { "ced", format_7, ps_ti990_12 },
+ { "nrm", format_11, ps_ti990_12 }, { "tmb", format_14, ps_ti990_12 },
+ { "tcmb", format_14, ps_ti990_12 }, { "tsmb", format_14, ps_ti990_12 },
+ { "srj", format_17, ps_ti990_12 }, { "arj", format_17, ps_ti990_12 },
+ { "xit", format_7, ps_ti990_12 }, { "insf", format_16, ps_ti990_12 },
+ { "xv", format_16, ps_ti990_12 }, { "xf", format_16, ps_ti990_12 },
+ { "ar", format_6, ps_ti990_12 }, { "cir", format_6, ps_ti990_12 },
+ { "sr", format_6, ps_ti990_12 }, { "mr", format_6, ps_ti990_12 },
+ { "dr", format_6, ps_ti990_12 }, { "lr", format_6, ps_ti990_12 },
+ { "str", format_6, ps_ti990_12 }, { "iof", format_15, ps_ti990_12 },
+ { "sneb", format_12, ps_ti990_12 }, { "crc", format_12, ps_ti990_12 },
+ { "ts", format_12, ps_ti990_12 }, { "ad", format_6, ps_ti990_12 },
+ { "cid", format_6, ps_ti990_12 }, { "sd", format_6, ps_ti990_12 },
+ { "md", format_6, ps_ti990_12 }, { "dd", format_6, ps_ti990_12 },
+ { "ld", format_6, ps_ti990_12 }, { "std", format_6, ps_ti990_12 },
+ { "ep", format_21, ps_ti990_12 },
+
+ /* tms9940-only instruction set */
+ /* these instructions are said to be format 9 (xop), but since the xop
+ level is interpreted as part of the opcode, dca and dcs should be handled
+ like format 6. liim looks like format 18, but slightly different,
+ therefore it is handled like a special format. */
+ { "liim", format_liim,/*ps_tms9940*/0 }, { "dca", format_6, /*ps_tms9940*/0 },
+ { "dcs", format_6, /*ps_tms9940*/0 },
+
+ { NULL, illegal, ps_any }
+};
+
+
+static const enum opcodes ops_4000_ffff_s12[12]=
+{
+ _szc, _szcb, _s, _sb, /*4000-7000*/
+ _c, _cb, _a, _ab, _mov, _movb, _soc, _socb /*8000-f000*/
+};
+
+
+static const enum opcodes ops_2000_3fff_s10[8]=
+{
+ _coc, _czc, _xor, _xop, _ldcr, _stcr, _mpy, _div /*2000-3800*/
+};
+
+
+static const enum opcodes ops_1000_1fff_s8[16]=
+{
+ _jmp, _jlt, _jle, _jeq, _jhe, _jgt, _jne, _jnc, /*1000-1700*/
+ _joc, _jno, _jl, _jh, _jop, _sbo, _sbz, _tb /*1800-1f00*/
+};
+
+
+static const enum opcodes ops_0e40_0fff_s6[7]=
+{
+ _ad, _cid, _sd, _md, _dd, _ld, _std /*0e40-0fc0*/
+};
+
+
+static const enum opcodes ops_0e00_0e3f_s4[4]=
+{
+ _iof, _sneb, _crc, _ts /*0e00-0e30*/
+};
+
+
+static const enum opcodes ops_0c40_0dff_s6[7]=
+{
+ _ar, _cir, _sr, _mr, _dr, _lr, _str /*0c40-0dc0*/
+};
+
+
+static const enum opcodes ops_0c10_0c3f_s4[3]=
+{
+ _insf, _xv, _xf /*0c10-0c30*/
+};
+
+
+static const enum opcodes ops_0c00_0c0f_s0[16]=
+{
+ _cri, _cdi, _negr, _negd, _cre, _cde, _cer, _ced, /*0c00-0c07*/
+ _nrm, _tmb, _tcmb, _tsmb, _srj, _arj, _xit, _xit /*0c08-0c0f*/
+};
+
+
+
+static const enum opcodes ops_0800_0bff_s8[4]=
+{
+ _sra, _srl, _sla, _src /*0800-0b00*/
+};
+
+
+static const enum opcodes ops_0400_07ff_s6[16]=
+{
+ _blwp, _b, _x, _clr, _neg, _inv, _inc, _inct, /*0400-05c0*/
+ _dec, _dect, _bl, _swpb, _seto, _abs, _lds, _ldd /*0600-07c0*/
+};
+
+
+static const enum opcodes ops_0200_03ff_s5[16]=
+{
+ _li, _ai, _andi, _ori, _ci, _stwp, _stst, _lwpi, /*0200-02e0*/
+ _limi, _lmf, _idle, _rset, _rtwp, _ckon, _ckof, _lrex /*0300-03e0*/
+};
+
+
+static const enum opcodes ops_0100_01ff_s6[4]=
+{
+ _ill, _bind, _divs, _mpys /*0100-01c0*/
+};
+
+
+static const enum opcodes ops_0030_00ff_s4[13]=
+{
+ _stpc, _cs, _seqb, _movs, _lim, /*0030-0070*/
+ _lst, _lwp, _lcs, _blsk, _mvsr, _mvsk, _pops, _pshs /*0080-00f0*/
+};
+
+
+static const enum opcodes ops_001c_002f_s0[20]=
+{
+ _sram, _slam, _rto, _lto, /*001c-001f*/
+ _cnto, _slsl, _slsp, _bdc, _dbc, _swpm, _xorm, _orm, /*0020-0027*/
+ _andm, _sm, _am, _mova, _ill, _emd, _eint, _dint /*0028-002f*/
+};
+
+
+
+static int PC;
+
+
+INLINE UINT16 readop_arg(const UINT8 *opram, unsigned pc)
+{
+ UINT16 result = opram[PC++ - pc] << 8;
+ return result | opram[PC++ - pc];
+}
+
+static int print_arg (char *dest, int mode, int arg, const UINT8 *opram, unsigned pc)
+{
+ int base;
+
+ switch (mode)
+ {
+ case 0x0: /* workspace register */
+ return sprintf (dest, "R%d", arg);
+ break;
+ case 0x1: /* workspace register indirect */
+ return sprintf (dest, "*R%d", arg);
+ break;
+ case 0x2: /* symbolic|indexed */
+ base = readop_arg(opram, pc);
+ if (arg) /* indexed */
+ return sprintf (dest, "@>%04x(R%d)", base, arg);
+ else /* symbolic (direct) */
+ return sprintf (dest, "@>%04x", base);
+ break;
+ case 0x3: /* workspace register indirect auto increment */
+ return sprintf (dest, "*R%d+", arg);
+ break;
+ }
+
+ return 0;
+}
+
+
+/*****************************************************************************
+ * Disassemble a single command and return the number of bytes it uses.
+ *****************************************************************************/
+unsigned Dasm9900 (char *buffer, unsigned pc, int model_id, const UINT8 *oprom, const UINT8 *opram)
+{
+ int OP, OP2, opc;
+ int sarg, darg, smode, dmode;
+ signed char displacement;
+ int byte_count, checkpoint;
+ int bit_position, bit_width;
+ unsigned dasmflags = 0;
+
+ const char *mnemonic;
+ format_t format;
+ int flags;
+
+ /*
+ Under tms9900, opcodes >0400->07FF are incompletely decoded: bits 11 is ignored, and so are
+ bits 12-15 for instructions which do not require a register. On the other hand, ti990/10
+ generates an illegal instruction error when bit 11 is set, but still ignores bits 12-15.
+ Additionally, ti990/12 and tms9995 will generate an illegal error when bits 12-15 are
+ non-zero.
+ */
+ #define BETTER_0200_DECODING (model_id == TI990_10_ID)
+ #define COMPLETE_0200_DECODING (/*(model_id == TI990_12_ID) ||*/ (model_id >= TMS9995_ID))
+
+ int processor_mask = ps_any;
+
+ if ((model_id == TI990_10_ID) /*|| (model_id == TI990_12_ID)*/ || (model_id >= TMS99000_ID))
+ processor_mask |= ps_mapper; /* processors with memory mapper (ti990/10, ti990/12,
+ and tms99000 with mapper coprocessor) */
+ if (/*(model_id == TI990_12_ID) ||*/ (model_id >= TMS9995_ID))
+ processor_mask |= ps_tms9995; /* ti990/12, tms9995, and later */
+
+ if (/*(model_id == TI990_12_ID) ||*/ (model_id >= TMS99000_ID))
+ processor_mask |= ps_tms99000; /* ti990/12, tms99000, and later */
+
+ /*if ((model_id == TI990_12_ID))
+ processor_mask |= ps_ti990_12;*/ /* ti990/12, tms99000, and later */
+
+ PC = pc;
+ OP = oprom[PC++ - pc] << 8;
+ OP |= oprom[PC++ - pc];
+
+ /* let's identify the opcode */
+ if (OP >= 0x4000)
+ opc = ops_4000_ffff_s12[(OP - 0x4000) >> 12];
+ else if (OP >= 0x2000)
+ opc = ops_2000_3fff_s10[(OP - 0x2000) >> 10];
+ else if (OP >= 0x1000)
+ opc = ops_1000_1fff_s8[(OP - 0x1000) >> 8];
+ else if (OP >= 0x0C00)
+ {
+ if (OP >= 0x0E40)
+ opc = ops_0e40_0fff_s6[(OP - 0x0E40) >> 6];
+ else if (OP >= 0x0E00)
+ opc = ops_0e00_0e3f_s4[(OP - 0x0E00) >> 4];
+ else if (OP >= 0x0C40)
+ opc = ops_0c40_0dff_s6[(OP - 0x0C40) >> 6];
+ else if (OP >= 0x0C10)
+ opc = ops_0c10_0c3f_s4[(OP - 0x0C10) >> 4];
+ else
+ opc = ops_0c00_0c0f_s0[OP - 0x0C00];
+ }
+ else if (OP >= 0x0800)
+ opc = ops_0800_0bff_s8[(OP - 0x0800) >> 8];
+ else if (OP >= 0x0400)
+ opc = ops_0400_07ff_s6[(OP - 0x0400) >> 6];
+ else if (OP >= 0x0200)
+ {
+ opc = ops_0200_03ff_s5[(OP - 0x0200) >> 5];
+ if (BETTER_0200_DECODING || COMPLETE_0200_DECODING)
+ {
+ flags = descriptions[opc].flags;
+ if ( (COMPLETE_0200_DECODING && (flags & sd_11_15) && (OP & 0x001f))
+ || ((flags & sd_11) && (OP & 0x0010)) )
+ {
+ opc = _ill;
+ if (OP >= 0x03f0)
+ opc = _ep; /* the ep opcode is located in a "hole" */
+ }
+ }
+ }
+ else if (OP >= 0x0100)
+ opc = ops_0100_01ff_s6[(OP - 0x0100) >> 6];
+ else if (OP >= 0x0030)
+ opc = ops_0030_00ff_s4[(OP - 0x0030) >> 4];
+ else if (OP >= 0x001C)
+ opc = ops_001c_002f_s0[OP - 0x001C];
+ else
+ opc = _ill;
+
+ /* read flags */
+ flags = descriptions[opc].flags;
+ /* set as illegal if the processor does not implement this instruction */
+ if (! (flags & processor_mask))
+ {
+ opc = _ill;
+ flags = descriptions[opc].flags; /* read new flags */
+ }
+
+ /* tms9940 replace a few xops with custom instructions */
+ if ((opc == _xop) && ((model_id == TMS9940_ID) || (model_id == TMS9985_ID)))
+ {
+ switch (BITS(OP,6,9))
+ {
+ case 0:
+ /* opcode is dca */
+ opc = _dca;
+ break;
+
+ case 1:
+ /* opcode is dcs */
+ opc = _dcs;
+ break;
+
+ case 2:
+ case 3: /* should be 2, but instruction decoding is incomplete */
+ /* opcode is liim */
+ if (BITS(OP,12,15) == 0)
+ /* ts must be == 0 */
+ opc = _liim;
+ else
+ /* I don't know what happens when ts != 0. Maybe the CPU does
+ the complete address decoding, and liim gets a bogus value
+ instead of the immediate. Since I do not know, I handle this
+ as an illegal instruction. */
+ opc = _ill;
+ break;
+
+ default:
+ /* this is still a software xop */
+ break;
+ }
+ }
+
+ mnemonic = descriptions[opc].mnemonic;
+ format = descriptions[opc].format;
+
+ /* bl and blwp instructions are subroutines */
+ if (mnemonic != NULL && mnemonic[0] == 'b' && mnemonic[1] == 'l')
+ dasmflags = DASMFLAG_STEP_OVER;
+
+ /* b *r11 and rtwp are returns */
+ else if (opc == 0x045b || (mnemonic != NULL && strcmp(mnemonic, "rtwp") == 0))
+ dasmflags = DASMFLAG_STEP_OUT;
+
+ switch (format)
+ {
+ case format_1: /* 2 address instructions */
+ smode = BITS(OP,10,11);
+ sarg = BITS(OP,12,15);
+ dmode = BITS(OP,4,5);
+ darg = BITS(OP,6,9);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, ",");
+ buffer += print_arg (buffer, dmode, darg, opram, pc);
+ break;
+
+ case format_2a: /* jump instructions */
+ displacement = (signed char)BITS(OP,8,15);
+ sprintf (buffer, "%-4s >%04x", mnemonic, 0xffff & (PC + displacement * 2));
+ break;
+
+ case format_2b: /* bit I/O instructions */
+ displacement = (signed char)BITS(OP,8,15);
+ sprintf (buffer, "%-4s >%04x", mnemonic, 0xffff & displacement);
+ break;
+
+ case format_3_9: /* logical, multiply, and divide instructions */
+ case format_4: /* CRU instructions */
+ case format_9: /* extended operation instruction */
+ smode = BITS(OP,10,11);
+ sarg = BITS(OP,12,15);
+ darg = BITS(OP,6,9);
+
+ if ((darg == 0) && (format == format_4))
+ darg = 16;
+
+ if (format == format_3_9)
+ {
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, ",R%d", darg);
+ }
+ else
+ {
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, ",%d", darg);
+ }
+ break;
+
+ case format_5: /* register shift instructions */
+ sarg = BITS(OP,12,15);
+ darg = BITS(OP,8,11);
+
+ sprintf (buffer, darg ? "%-4s R%d,%d" : "%-4s R%d,R%d", mnemonic, sarg, darg);
+ break;
+
+ case format_6: /* single address instructions */
+ smode = BITS(OP,10,11);
+ sarg = BITS(OP,12,15);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ break;
+
+ case format_7: /* instructions without operands */
+ sprintf (buffer, "%s", mnemonic);
+ break;
+
+ case format_8a: /* immediate instructions (destination register) */
+ darg = BITS(OP,12,15);
+ sarg = readop_arg(opram, pc);
+
+ sprintf (buffer, "%-4s R%d,>%04x", mnemonic, darg, sarg);
+ break;
+
+ case format_8b: /* immediate instructions (no destination register) */
+ sarg = readop_arg(opram, pc);
+
+ sprintf (buffer, "%-4s >%04x", mnemonic, sarg);
+ break;
+
+ case format_10: /* memory map file instruction */
+ sarg = BITS(OP,12,15);
+ darg = BITS(OP,11,11);
+
+ sprintf (buffer, "%-4s R%d,%d", mnemonic, sarg, darg);
+ break;
+
+ case format_11: /* multiple precision instructions */
+ OP2 = readop_arg(opram, pc);
+
+ smode = BITS(OP2,10,11);
+ sarg = BITS(OP2,12,15);
+ dmode = BITS(OP2,4,5);
+ darg = BITS(OP2,6,9);
+ byte_count = BITS(OP2,0,3);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, ",");
+ buffer += print_arg (buffer, dmode, darg, opram, pc);
+ buffer += sprintf (buffer, byte_count ? ",%d" : ",R%d", byte_count);
+ break;
+
+ case format_12: /* string instructions */
+ OP2 = readop_arg(opram, pc);
+
+ smode = BITS(OP2,10,11);
+ sarg = BITS(OP2,12,15);
+ dmode = BITS(OP2,4,5);
+ darg = BITS(OP2,6,9);
+ byte_count = BITS(OP2,0,3);
+ checkpoint = BITS(OP,12,15);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, ",");
+ buffer += print_arg (buffer, dmode, darg, opram, pc);
+ buffer += sprintf (buffer, byte_count ? ",%d,R%d" : ",R%d,R%d", byte_count, checkpoint);
+ break;
+
+ case format_13: /* multiple precision shift instructions */
+ OP2 = readop_arg(opram, pc);
+
+ smode = BITS(OP2,10,11);
+ sarg = BITS(OP2,12,15);
+ darg = BITS(OP2,6,9);
+ byte_count = BITS(OP2,0,3);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, byte_count ? ",%d" : ",R%d", byte_count);
+ buffer += sprintf (buffer, darg ? ",%d" : ",R%d", darg);
+ break;
+
+ case format_14: /* bit testing instructions */
+ OP2 = readop_arg(opram, pc);
+
+ smode = BITS(OP2,10,11);
+ sarg = BITS(OP2,12,15);
+ darg = BITS(OP2,0,9);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ if (darg == 0x3ff)
+ buffer += sprintf (buffer, ",R0");
+ else
+ buffer += sprintf (buffer, ",%d", darg);
+ break;
+
+ case format_15: /* invert order of field instruction */
+ OP2 = readop_arg(opram, pc);
+
+ smode = BITS(OP2,10,11);
+ sarg = BITS(OP2,12,15);
+ bit_position = BITS(OP2,0,3);
+ bit_width = BITS(OP,12,15);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, bit_position ? ",(%d," : ",(R%d,", bit_position);
+ buffer += sprintf (buffer, bit_width ? "%d)" : "R%d)", bit_width);
+ break;
+
+ case format_16: /* field instructions */
+ OP2 = readop_arg(opram, pc);
+
+ smode = BITS(OP2,10,11);
+ sarg = BITS(OP2,12,15);
+ dmode = BITS(OP2,4,5);
+ darg = BITS(OP2,6,9);
+ bit_position = BITS(OP2,0,3);
+ bit_width = BITS(OP,12,15);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, ",");
+ buffer += print_arg (buffer, dmode, darg, opram, pc);
+ buffer += sprintf (buffer, bit_position ? ",(%d," : ",(%d,", bit_position);
+ buffer += sprintf (buffer, bit_width ? "%d)" : "R%d)", bit_width);
+ break;
+
+ case format_17: /* alter register and jump instructions */
+ OP2 = readop_arg(opram, pc);
+
+ displacement = (signed char)BITS(OP2,8,15);
+ sarg = BITS(OP2,4,7);
+ darg = BITS(OP2,0,3);
+ if (darg)
+ sprintf (buffer, darg ? "%-4s >%04x,%d,R%d" : "%-4s >%04x,R%d,R%d",
+ mnemonic, 0xffff & (PC + displacement * 2), sarg, darg);
+ break;
+
+ case format_18: /* single register operand instructions */
+ sarg = BITS(OP,12,15);
+
+ sprintf (buffer, "%-4s R%d", mnemonic, sarg);
+ break;
+
+ case format_liim: /* liim instruction */
+ sarg = BITS(OP,14,15);
+
+ sprintf (buffer, "%-4s %d", mnemonic, sarg);
+ break;
+
+ case format_19: /* move address instruction */
+ OP2 = readop_arg(opram, pc);
+
+ smode = BITS(OP2,10,11);
+ sarg = BITS(OP2,12,15);
+ dmode = BITS(OP2,4,5);
+ darg = BITS(OP2,6,9);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, ",");
+ buffer += print_arg (buffer, dmode, darg, opram, pc);
+ break;
+
+ case format_20: /* list search instructions */
+ {
+ const char *condition_code;
+
+ OP2 = readop_arg(opram, pc);
+
+ smode = BITS(OP2,10,11);
+ sarg = BITS(OP2,12,15);
+ dmode = BITS(OP2,4,5);
+ darg = BITS(OP2,6,9);
+
+ switch (BITS(OP2,0,3))
+ {
+ case 0:
+ condition_code = "eq";
+ break;
+ case 1:
+ condition_code = "ne";
+ break;
+ case 2:
+ condition_code = "he";
+ break;
+ case 3:
+ condition_code = "l";
+ break;
+ case 4:
+ condition_code = "ge";
+ break;
+ case 5:
+ condition_code = "lt";
+ break;
+ case 6:
+ condition_code = "le";
+ break;
+ case 7:
+ condition_code = "h";
+ break;
+ case 8:
+ condition_code = "lte";
+ break;
+ case 9:
+ condition_code = "gt";
+ break;
+ default:
+ condition_code = "??";
+ break;
+ }
+
+ buffer += sprintf (buffer, "%-4s %s,", mnemonic, condition_code);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, ",");
+ buffer += print_arg (buffer, dmode, darg, opram, pc);
+ break;
+ }
+
+ case format_21: /* extend precision instruction */
+ {
+ int dest_byte_count;
+
+ OP2 = readop_arg(opram, pc);
+
+ smode = BITS(OP2,10,11);
+ sarg = BITS(OP2,12,15);
+ dmode = BITS(OP2,4,5);
+ darg = BITS(OP2,6,9);
+ byte_count = BITS(OP2,0,3);
+ dest_byte_count = BITS(OP,12,15);
+
+ buffer += sprintf (buffer, "%-4s ", mnemonic);
+ buffer += print_arg (buffer, smode, sarg, opram, pc);
+ buffer += sprintf (buffer, ",");
+ buffer += print_arg (buffer, dmode, darg, opram, pc);
+ buffer += sprintf (buffer, byte_count ? ",%d" : ",R%d", byte_count);
+ buffer += sprintf (buffer, dest_byte_count ? ",%d" : ",R%d", dest_byte_count);
+ break;
+ }
+
+ default:
+ logerror("debbugger internal error, file %s, line %d\n", __FILE__, __LINE__);
+ case illegal:
+ sprintf (buffer, "data >%04x", OP);
+ break;
+ }
+
+ return (PC - pc) | DASMFLAG_SUPPORTED | dasmflags;
+}
+
+
+
diff --git a/src/emu/cpu/tms9900/99xxcore.h b/src/emu/cpu/tms9900/99xxcore.h
new file mode 100644
index 00000000000..49c80d734b4
--- /dev/null
+++ b/src/emu/cpu/tms9900/99xxcore.h
@@ -0,0 +1,4868 @@
+/*
+ 99xxcore.h : generic tms99xx emulation
+
+ The TMS99XX_MODEL switch tells which emulator we want to build. Set the
+ switch, then include 99xxcore.h, and you will have an emulator for this
+ processor.
+
+ Only ti990/10, tms9900, tms9980a/9981, and tms9995 work OK for now. Note
+ that tms9995 has not been tested extensively.
+
+ tms9940 is WIP: it is probably still buggy (particularily the BCD support),
+ as it has not been tested. tms9985 has been implemented as a 9940 with
+ a data bus, which should be mostly correct.
+
+ I think all software aspects of tms9985 and tms9989 are implemented.
+ You just need to implement bus interfaces, provided you know them.
+ (I don't...)
+
+ tms99000 cannot be implemented fully yet, due to lack of documentation.
+
+ ti990/12 is not supported at all, and it should probably be implemented as
+ a separate processor core, anyway.
+
+ Original tms9900 emulator by Edward Swartz
+ Smoothed out by Raphael Nabet
+ Originally converted for Mame by M.Coates
+ Processor timing, support for tms9980 and tms9995, and many bug fixes by R Nabet
+*/
+
+/*
+ The first member of the family was actually the ti990/10 minicomputer,
+ released in 1975. tms9900 was released in 1976, and has the same
+ instruction set as ti990/10: however, tms9900 is slower, it does not
+ support privileges and memory mapping, and illegal instructions do not
+ cause an error interrupt.
+
+ The ti990 family later evoluted into the huge ti990/12 system, with support
+ for 144 different instructions, and microcode programming in case some user
+ found it was not enough. ti990/10 was eventually replaced by a cheaper
+ ti990/10a board, built around a tms99000 microprocessor.
+
+ The tms9980 processor is merely a tms9900 with a 8-bit data bus (instead of
+ 16-bit on tms9900).
+
+ tms9940 is a microcontroller, and is mostly similar to 9900/9980. The
+ variant I know has 2kb of ROM, 128 bytes of RAM, a timer, 32 I/O line, some
+ of which can be reconfigured as a CRU bus, but no external memory bus. It
+ includes three additional opcodes, which are not supported by any other
+ member of the family (with the probable exception of TMS9985).
+
+ tms9985 is similar to tms9940, but it supports an external 8-bit-wide
+ memory bus. At least one variant included 8kb of ROM, 256 bytes of RAM.
+ It was ill-fated, as it was never released due to technical problems.
+
+ tms9989 is mostly alien to me. I guess it is a close relative of tms9995,
+ although I am not sure. I have read that the SBP68689 supports tms9995
+ opcodes, but that tms9989 does not.
+
+ tms9995 belongs to another generation. It is quite faster than tms9900,
+ and supports 4 extra opcodes. Its external bus is 8-bit-wide, and it has
+ 256 bytes of internal 16-bit RAM.
+
+ tms99000 is the successor to both ti9900 and ti990/10. It supports
+ privileges, and has a coprocessor interface which enables the use of an
+ external memory mapper. Additionnally, it can use a Macrostore ROM to
+ emulate additional instructions.
+
+ This feature allowed TI to expand the 99000 family with the tms99105 (which
+ was said to support 84 instructions types), the tms99110 (which supported
+ floating point instructions), and possibly another chip (tms99220???) which
+ included parts of the UCSD P-system in Macrostore.
+
+References :
+* 9900 family systems design, chapter 6, 7, 8
+* TMS 9980A/ TMS 9981 Product Data Book
+* TMS 9995 16-Bit Microcomputer Data Manual
+* Model 990/10A computer general description, section 4 (p/n 2302633-9701 A)
+* 990/99000 assembly language reference manual (p/n 2270509-9701 A)
+* Chapter 18 of unidentified book is the only reference on tms9940 I have found so far (Paperport format)
+ <ftp://ftp.whtech.com//datasheets/Hardware manuals/tms9900 9901 9904 9940 9980 (by a osborne).max>
+
+Other references can be found on spies.com:
+<http://www.spies.com/arcade/simulation/processors/index.html>
+<http://www.spies.com/~aek/pdf/ti/>
+
+*/
+
+
+#include "cpuintrf.h"
+#include "debugger.h"
+#include "tms9900.h"
+#include <math.h>
+
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+
+ #define TMS99XX_PREFIX ti990_10
+ #define TMS99XX_CPU_NAME "TI990/10"
+
+#elif (TMS99XX_MODEL == TMS9900_ID)
+
+ #define TMS99XX_PREFIX tms9900
+ #define TMS99XX_CPU_NAME "TMS9900"
+
+#elif (TMS99XX_MODEL == TMS9940_ID)
+
+ #define TMS99XX_PREFIX tms9940
+ #define TMS99XX_CPU_NAME "TMS9940"
+
+ #error "tms9940 is not yet supported"
+
+#elif (TMS99XX_MODEL == TMS9980_ID)
+
+ #define TMS99XX_PREFIX tms9980a
+ #define TMS99XX_CPU_NAME "TMS9980A/TMS9981"
+
+#elif (TMS99XX_MODEL == TMS9985_ID)
+
+ #define TMS99XX_PREFIX tms9985
+ #define TMS99XX_CPU_NAME "TMS9985"
+
+ #error "tms9985 is not yet supported"
+
+#elif (TMS99XX_MODEL == TMS9989_ID)
+
+ #define TMS99XX_PREFIX tms9989
+ #define TMS99XX_CPU_NAME "TMS9989"
+
+ #error "tms9989 is not yet supported"
+
+#elif (TMS99XX_MODEL == TMS9995_ID)
+
+ #define TMS99XX_PREFIX tms9995
+ #define TMS99XX_CPU_NAME "TMS9995"
+
+#elif (TMS99XX_MODEL == TMS99000_ID)
+
+ #define TMS99XX_PREFIX tms99000
+ #define TMS99XX_CPU_NAME "TMS99000"
+
+ #error "tms99000 is not yet supported"
+
+#elif (TMS99XX_MODEL == TMS99105A_ID)
+
+ #define TMS99XX_PREFIX tms99105a
+ #define TMS99XX_CPU_NAME "TMS99105A"
+
+ #error "tms99105a is not yet supported"
+
+#elif (TMS99XX_MODEL == TMS99110A_ID)
+
+ #define TMS99XX_PREFIX tms99110a
+ #define TMS99XX_CPU_NAME "TMS99110A"
+
+ #error "tms99110a is not yet supported"
+
+#endif
+
+/*
+ Now for some preprocessor wizardry.
+*/
+#define concat2(a,b) a##b
+
+#define ICOUNT(prefix) concat2(prefix,_ICount)
+#define GET_INFO(prefix) concat2(prefix,_get_info)
+#define RESET_PARAM(prefix) concat2(prefix,reset_param)
+
+#define TMS99XX_ICOUNT ICOUNT(TMS99XX_PREFIX)
+#define TMS99XX_GET_INFO GET_INFO(TMS99XX_PREFIX)
+#define TMS99XX_RESET_PARAM RESET_PARAM(TMS99XX_PREFIX)
+
+
+
+/*
+ I include this macro because we may eventually support other 99000 variants such as tms99110,
+ and this macro will remain true for every 99000 family member, even when we have
+ (TMS99XX_MODEL != TMS99000_ID).
+*/
+#define IS_99000 (TMS99XX_MODEL == TMS99000_ID)
+
+/*
+ On microprocessor implementations (other than TMS9940 and, probably, TMS9985), the CKOF, CKON,
+ IDLE, LREX and RSET cause an external CRU write. CKOF, CKON and LREX do nothing apart of this,
+ therefore they must be implemented with external hardware (CKON and CKOF are supposed to
+ enable/disable a line clock interrupt, and LREX to trigger a LOAD interrupt). IDLE and RSET
+ are functional, but, on the one hand, the design allowed to light a diagnostic LED when
+ the processor is in IDLE state, and, on the other hand, the RSET instruction is supposed
+ to reset external devices as well.
+
+ On the TI990/10 and TI990/12 minicomputers, there is no such CRU write. The line clock
+ interrupt latch is part of the CPU board, LREX is fully functional, the IDLE led is connected
+ to the board, and the RSET line is part of the TILINE bus connector.
+
+ On the TMS9940, CKOF, CKON, LREX and RSET are not supported. IDLE, on the other hand, is
+ supported, and the CPU can be configured to output its IDLE state on the P16 I/O pin.
+*/
+#define EXTERNAL_INSTRUCTION_DECODING (TMS99XX_MODEL != TI990_10_ID) && (TMS99XX_MODEL != TI9940_ID) && (TMS99XX_MODEL != TI9985_ID)
+#define EXTERNAL_INSTRUCTION_CALLBACK (TMS99XX_MODEL == TI990_10_ID)
+
+/*
+ ti990/10, ti990/12 and tms99000 support privileges
+
+ privileged instructions:
+ CKOF, CKON, IDLE, LIMI, LREX, RSET,
+ LDD, LDS, LMF, (memory mapping instructions)
+ DINT, EINT, EMD , LCS, LIM, SLSP. (990/12 instructions)
+
+ instructions which are privileged when the effective CRU address is higher than 0xE00:
+ LDCR, SBO, SBZ, STCR, TB.
+
+ instructions whose behaviour is modified in user mode (only user flags in ST are affected):
+ RTWP,
+ LST. (ti990/12 and tms99000 instruction)
+*/
+#define HAS_PRIVILEGE ((TMS99XX_MODEL == TI990_10_ID) || IS_99000)
+
+/*
+ opcode groups
+
+ * 69 basic opcodes implemented on all family members
+ * 3 memory mapping opcodes implemented on ti990/10 with mapping option, ti990/12, and
+ the tim99610 mapper in conjunction with any tms99000 family member: LMF, LDS, LDD
+ * 3 opcodes implemented on tms9940 (and probably tms9985) only: DCA, DCS, LIIM
+ * 4 opcodes implemented on ti990/12, tms9989 and above: MPYS, DIVS, LST, LWP
+ * 1 opcode implemented on ti990/12, and tms99000: BIND
+ * 72 opcodes implemented on ti990/12 only (some of which are emulated by tms99105 & tms99110)
+*/
+
+#define HAS_MAPPING ((TMS99XX_MODEL == TI990_10_ID) /*|| IS_99000*/)
+#define HAS_9995_OPCODES ((TMS99XX_MODEL == TMS9989_ID) || (TMS99XX_MODEL == TMS9995_ID) || IS_99000)
+#define HAS_BIND_OPCODE IS_99000
+
+#define HAS_OVERFLOW_INTERRUPT ((TMS99XX_MODEL == TMS9995_ID) || IS_99000)
+
+/*
+ Under tms9900, opcodes >0200->03FF are incompletely decoded: bits 11 is ignored, and so are
+ bits 12-15 for instructions which do not require a register. On the other hand, ti990/10
+ generates an illegal instruction error when bit 11 is set, but still ignores bits 12-15.
+ Additionally, ti990/12 and tms9995 will generate an illegal error when bits 12-15 are
+ non-zero.
+*/
+#define BETTER_0200_DECODING (TMS99XX_MODEL == TI990_10_ID)
+#define COMPLETE_0200_DECODING (TMS99XX_MODEL >= TMS9995_ID)
+
+/*
+ TI990/10 and tms9900 force unused bits in the ST register to 0.
+ TMS9995 does not.
+*/
+#define USE_ST_MASK (TMS99XX_MODEL <= TMS9985_ID)
+
+/*
+ TI990/10, TMS9900 and TMS99000 have a 16-bit-wide memory bus, and use 16-bus accessors.
+ TMS9940 use 16-bit accessors, too, as it has an internal 16-bit bus, and no external bus.
+*/
+#define USE_16_BIT_ACCESSORS ((TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) || (IS_99000))
+
+
+INLINE void execute(UINT16 opcode);
+
+#if EXTERNAL_INSTRUCTION_DECODING
+static void external_instruction_notify(int ext_op_ID);
+#endif
+static UINT16 decipheraddr(UINT16 opcode);
+static UINT16 decipheraddrbyte(UINT16 opcode);
+static void contextswitch(UINT16 addr);
+#if HAS_MAPPING || HAS_PRIVILEGE
+static void contextswitchX(UINT16 addr);
+#else
+#define contextswitchX(addr) contextswitch(addr)
+#endif
+static void field_interrupt(void);
+
+/***************************/
+/* Mame Interface Routines */
+/***************************/
+
+
+static int TMS99XX_ICOUNT = 0;
+
+
+/* tms9900 ST register bits. */
+
+/* These bits are set by every compare, move and arithmetic or logical operation : */
+/* (Well, COC, CZC and TB only set the E bit, but these are kind of exceptions.) */
+#define ST_LGT 0x8000 /* Logical Greater Than (strictly) */
+#define ST_AGT 0x4000 /* Arithmetical Greater Than (strictly) */
+#define ST_EQ 0x2000 /* Equal */
+
+/* These bits are set by arithmetic operations, when it makes sense to update them. */
+#define ST_C 0x1000 /* Carry */
+#define ST_OV 0x0800 /* OVerflow (overflow with operations on signed integers, */
+ /* and when the result of a 32bits:16bits division cannot fit in a 16-bit word.) */
+
+/* This bit is set by move and arithmetic operations WHEN THEY USE BYTE OPERANDS. */
+#define ST_OP 0x0400 /* Odd Parity */
+
+#if (TMS99XX_MODEL != TMS9940_ID)
+
+/* This bit is set by the XOP instruction. */
+#define ST_X 0x0200 /* Xop */
+
+#endif
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+
+/* This bit is set by arithmetic operations to support BCD */
+#define ST_DC 0x0100 /* Digit Carry */
+
+#endif
+
+#if HAS_PRIVILEGE
+
+/* This bit is set in user (i.e. non-supervisor) mode */
+#define ST_PR 0x0100 /* PRivilege */
+
+#endif
+
+#if HAS_MAPPING
+
+/* This tells which map is currently in use */
+#define ST_MF 0x0080 /* Map File */
+
+#endif
+
+#if (HAS_OVERFLOW_INTERRUPT)
+
+/* This bit is set in ti990/12, TMS9995 and later chips to generate a level-2 interrupt when
+the Overflow status bit is set */
+#define ST_OVIE 0x0020 /* OVerflow Interrupt Enable */
+
+#endif
+
+#if (IS_99000)
+
+/* This bit enables the macrostore feature on tms99000 */
+/* (It is used on ti990/12 with a different meaning.) */
+#define ST_EMR 0x0010 /* Enable Macrostore Rom */
+
+#endif
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+
+#define ST_IM 0x0003 /* Interrupt Mask */
+
+#else
+
+#define ST_IM 0x000F /* Interrupt Mask */
+
+#endif
+
+/* On models before TMS9995 (TMS9989 ?), unused ST bits are always forced to 0, so we define
+a ST_MASK */
+#if (USE_ST_MASK)
+ #if (TMS99XX_MODEL == TI990_10_ID)
+ #define ST_MASK 0xFF8F
+ #elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+#define ST_MASK 0xFD03
+ #else
+ #define ST_MASK 0xFE0F
+ #endif
+#endif
+
+
+/* error interrupt register bits */
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+
+/* This bit is set in user (i.e. non-supervisor) mode */
+#define EIR_MAPERR 0x0800 /* memory MAPping ERRor */
+#define EIR_MER 0x1000 /* Memory parity ERRor */
+#define EIR_ILLOP 0x2000 /* ILLegal OPcode */
+#define EIR_PRIVOP 0x4000 /* PRiviledged OPeration */
+#define EIR_TIMEOUT 0x8000 /* TILINE TIMEOUT */
+
+#endif
+
+
+/* Offsets for registers. */
+#define R0 0
+#define R1 2
+#define R2 4
+#define R3 6
+#define R4 8
+#define R5 10
+#define R6 12
+#define R7 14
+#define R8 16
+#define R9 18
+#define R10 20
+#define R11 22
+#define R12 24
+#define R13 26
+#define R14 28
+#define R15 30
+
+typedef struct map_file_t
+{
+ UINT16 L[3], B[3]; /* actual registers */
+ UINT32 limit[3], bias[3]; /* equivalent in a more convenient form */
+} map_file_t;
+
+typedef struct
+{
+/* "actual" tms9900 registers : */
+ UINT16 WP; /* Workspace pointer */
+ UINT16 PC; /* Program counter */
+ UINT16 STATUS; /* STatus register */
+
+/* Now, data used for emulation */
+ UINT16 IR; /* Instruction register, with the currently parsed opcode */
+
+ UINT8 interrupt_pending; /* true if an interrupt must be honored... */
+
+#if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID))
+ UINT8 load_state; /* nonzero if the LOAD* line is active (low) */
+#endif
+
+#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)
+ /* On tms9900, we cache the state of INTREQ* and IC0-IC3 here */
+ /* On tms9980/9981, we translate the state of IC0-IC2 to the equivalent state for a tms9900,
+ and store the result here */
+ UINT8 irq_level; /* when INTREQ* is active, interrupt level on IC0-IC3 ; else always 16 */
+ UINT8 irq_state; /* nonzero if the INTREQ* line is active (low) */
+ /* with TMS9940, bit 0 means INT1, bit 1 decrementer, bit 2 INT2 */
+#elif (TMS99XX_MODEL == TMS9995_ID)
+ /* tms9995 is quite different : it latches the interrupt inputs */
+ UINT8 irq_level; /* We store the level of the request with the highest level here */
+ UINT8 int_state; /* interrupt lines state */
+ UINT8 int_latch; /* interrupt latches state */
+#endif
+
+ /* interrupt callback */
+ /* note that this callback is used by tms9900_set_irq_line() and tms9980a_set_irq_line() to
+ retreive the value on IC0-IC3 (non-standard behaviour) */
+ int (*irq_callback)(int irq_line);
+
+ UINT8 IDLE; /* nonzero if processor is IDLE - i.e waiting for interrupt while writing
+ special data on CRU bus */
+
+#if HAS_MAPPING
+ UINT8 mapping_on; /* set by a CRU write */
+ map_file_t map_files[3]; /* internal mapper registers */
+ UINT8 cur_map; /* equivalent to ST_MF status bit */
+ UINT8 cur_src_map; /* set to 2 by LDS */
+ UINT8 cur_dst_map; /* set to 2 by LDD */
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+ UINT8 reset_maperr; /* reset mapper error flag line (reset flags in 945417-9701 p. 3-90) */
+
+ UINT32 mapper_address_latch; /* used to load the map file and for diagnostic purpose */
+ UINT16 mapper_cru_read_register; /* read register select code for mapper cru interface */
+ UINT8 diaglat; /* set when diagnostic address latch is done */
+ UINT8 latch_control[3]; /* latch control */
+
+#endif
+#endif
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+ UINT16 error_interrupt_register; /* one flag for each interrupt condition */
+ void (*error_interrupt_callback)(int state);
+#endif
+
+#if (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
+ UINT8 RAM[256]; /* on-chip RAM (I know this is weird, but the internal bus is 16-bit-wide, whereas the external bus is 8-bit-wide) */
+#endif
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
+ /* on-chip event counter/timer*/
+ UINT8 decrementer_enabled;
+ UINT16 decrementer_interval;
+ UINT16 decrementer_count; /* used in event counter mode*/
+ emu_timer *timer; /* used in timer mode */
+#endif
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+ /* additionnal registers */
+ UINT16 flag; /* flag register */
+ UINT8 MID_flag; /* MID flag register */
+
+ /* chip config, which can be set on reset */
+ UINT8 memory_wait_states_byte;
+ UINT8 memory_wait_states_word;
+
+ /* mask option (off on normal tms9995) */
+ UINT8 is_mp9537;
+#endif
+
+ /* Some instructions (i.e. XOP, BLWP, and MID) disable interrupt recognition until another
+ instruction is executed : so they set this flag */
+ UINT8 disable_interrupt_recognition;
+
+ /* notify the driver of changes in IDLE state */
+ void (*idle_callback)(int state);
+
+#if EXTERNAL_INSTRUCTION_CALLBACK
+ void (*rset_callback)(void);
+ void (*lrex_callback)(void);
+ void (*ckon_ckof_callback)(int state);
+#endif
+
+} tms99xx_Regs;
+
+static tms99xx_Regs I =
+{
+ 0,0,0,0, /* don't care */
+ 0, /* no pending interrupt */
+ 0, /* LOAD* inactive */
+ 16, 0, /* INTREQ* inactive */
+};
+static UINT8 lastparity; /* rather than handling ST_OP directly, we copy the last value which
+ would set it here */
+
+static char lds_flag, ldd_flag;
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+static void reset_decrementer(void);
+#endif
+
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+
+/*
+ accessor for the internal ROM
+*/
+READ16_HANDLER(ti990_10_internal_r)
+{
+ //return I.ROM[offset];
+ return program_read_word_16be(0x1ffc00+offset);
+}
+
+#endif
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+
+/*
+ accessor for the first 252 bytes of internal RAM
+*/
+READ8_HANDLER(tms9995_internal1_r)
+{
+ return I.RAM[offset];
+}
+
+WRITE8_HANDLER(tms9995_internal1_w)
+{
+ I.RAM[offset]=data;
+}
+
+/*
+ accessor for the last 4 bytes of internal RAM
+*/
+READ8_HANDLER(tms9995_internal2_r)
+{
+ return I.RAM[offset+0xfc];
+}
+
+WRITE8_HANDLER(tms9995_internal2_w)
+{
+ I.RAM[offset+0xfc]=data;
+}
+
+#endif
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+
+ /* on-board ROMs are not emulated (we use a hack) */
+
+ static int write_inhibit;
+
+ #define readword(addr) readwordX((addr), I.cur_map)
+ static int readwordX(int addr, int map_file)
+ {
+ if ((map_file == 0) && (addr >= 0xf800))
+ { /* intercept TPCS and CPU ROM */
+ if (addr < 0xfc00)
+ /* TPCS */
+ return program_read_word_16be(0x1f0000+addr);
+ else
+ /* CPU ROM */
+ return program_read_word_16be(0x1f0000+addr); /* hack... */
+ }
+ else if (! I.mapping_on)
+ {
+ return program_read_word_16be(addr);
+ }
+ else
+ {
+ int map_index;
+
+ if (addr <= I.map_files[map_file].limit[0])
+ map_index = 0;
+ else if (addr <= I.map_files[map_file].limit[1])
+ map_index = 1;
+ else if (addr <= I.map_files[map_file].limit[2])
+ map_index = 2;
+ else
+ { /* mapping error */
+ if ((! (I.error_interrupt_register & EIR_MAPERR)) && ! (I.diaglat))
+ I.mapper_address_latch = addr;
+ if ((! I.reset_maperr) && ! (I.error_interrupt_register & EIR_MAPERR))
+ {
+ I.error_interrupt_register |= EIR_MAPERR;
+ write_inhibit = 1;
+ }
+ return program_read_word_16be(addr);
+ }
+ if ((! (I.error_interrupt_register & EIR_MAPERR)) && ! (I.diaglat))
+ I.mapper_address_latch = I.map_files[map_file].bias[map_index]+addr;
+ if ((I.latch_control[map_index]) && (! I.reset_maperr))
+ I.diaglat = 1;
+ return program_read_word_16be(I.map_files[map_file].bias[map_index]+addr);
+ }
+ }
+
+ #define writeword(addr, data) writewordX((addr), (data), I.cur_map)
+ static void writewordX(int addr, int data, int map_file)
+ {
+ if ((map_file == 0) && (addr >= 0xf800))
+ { /* intercept TPCS and CPU ROM */
+ if (addr < 0xfc00)
+ /* TPCS */
+ program_write_word_16be(0x1f0000+addr, data);
+ else
+ /* CPU ROM */
+ program_write_word_16be(0x1f0000+addr, data); /* hack... */
+ }
+ else if (! I.mapping_on)
+ {
+ program_write_word_16be(addr, data);
+ }
+ else
+ {
+ int map_index;
+
+ if (addr <= I.map_files[map_file].limit[0])
+ map_index = 0;
+ else if (addr <= I.map_files[map_file].limit[1])
+ map_index = 1;
+ else if (addr <= I.map_files[map_file].limit[2])
+ map_index = 2;
+ else
+ { /* mapping error */
+ if ((! (I.error_interrupt_register & EIR_MAPERR)) && ! (I.diaglat))
+ I.mapper_address_latch = addr;
+ if ((! I.reset_maperr) && ! (I.error_interrupt_register & EIR_MAPERR))
+ {
+ I.error_interrupt_register |= EIR_MAPERR;
+ write_inhibit = 1;
+ }
+ if (write_inhibit)
+ (void)program_read_word_16be(addr);
+ else
+ program_write_word_16be(addr, data);
+ return;
+ }
+ if ((! (I.error_interrupt_register & EIR_MAPERR)) && ! (I.diaglat))
+ I.mapper_address_latch = I.map_files[map_file].bias[map_index]+addr;
+ if ((I.latch_control[map_index]) && (! I.reset_maperr))
+ I.diaglat = 1;
+ program_write_word_16be(I.map_files[map_file].bias[map_index]+addr, data);
+ }
+ }
+
+ #define readbyte(addr) readbyteX((addr), I.cur_map)
+ static int readbyteX(int addr, int map_file)
+ {
+ if ((map_file == 0) && (addr >= 0xf800))
+ { /* intercept TPCS and CPU ROM */
+ if (addr < 0xfc00)
+ /* TPCS */
+ return program_read_byte_16be(0x1f0000+addr);
+ else
+ /* CPU ROM */
+ return program_read_byte_16be(0x1f0000+addr); /* hack... */
+ }
+ else if (! I.mapping_on)
+ {
+ return program_read_byte_16be(addr);
+ }
+ else
+ {
+ int map_index;
+
+ if (addr <= I.map_files[map_file].limit[0])
+ map_index = 0;
+ else if (addr <= I.map_files[map_file].limit[1])
+ map_index = 1;
+ else if (addr <= I.map_files[map_file].limit[2])
+ map_index = 2;
+ else
+ { /* mapping error */
+ if ((! (I.error_interrupt_register & EIR_MAPERR)) && ! (I.diaglat))
+ I.mapper_address_latch = addr;
+ if ((! I.reset_maperr) && ! (I.error_interrupt_register & EIR_MAPERR))
+ {
+ I.error_interrupt_register |= EIR_MAPERR;
+ write_inhibit = 1;
+ }
+ return program_read_byte_16be(addr);
+ }
+ if ((! (I.error_interrupt_register & EIR_MAPERR)) && ! (I.diaglat))
+ I.mapper_address_latch = I.map_files[map_file].bias[map_index]+addr;
+ if ((I.latch_control[map_index]) && (! I.reset_maperr))
+ I.diaglat = 1;
+ return program_read_byte_16be(I.map_files[map_file].bias[map_index]+addr);
+ }
+ }
+
+ #define writebyte(addr, data) writebyteX((addr), (data), I.cur_map)
+ static void writebyteX(int addr, int data, int map_file)
+ {
+ if ((map_file == 0) && (addr >= 0xf800))
+ { /* intercept TPCS and CPU ROM */
+ if (addr < 0xfc00)
+ /* TPCS */
+ program_write_byte_16be(0x1f0000+addr, data);
+ else
+ /* CPU ROM */
+ program_write_byte_16be(0x1f0000+addr, data); /* hack... */
+ }
+ else if (! I.mapping_on)
+ {
+ program_write_byte_16be(addr, data);
+ }
+ else
+ {
+ int map_index;
+
+ if (addr <= I.map_files[map_file].limit[0])
+ map_index = 0;
+ else if (addr <= I.map_files[map_file].limit[1])
+ map_index = 1;
+ else if (addr <= I.map_files[map_file].limit[2])
+ map_index = 2;
+ else
+ { /* mapping error */
+ if ((! (I.error_interrupt_register & EIR_MAPERR)) && ! (I.diaglat))
+ I.mapper_address_latch = addr;
+ if ((! I.reset_maperr) && ! (I.error_interrupt_register & EIR_MAPERR))
+ {
+ I.error_interrupt_register |= EIR_MAPERR;
+ write_inhibit = 1;
+ }
+ if (write_inhibit)
+ (void)program_read_byte_16be(addr);
+ else
+ program_write_byte_16be(addr, data);
+ return;
+ }
+ if ((! (I.error_interrupt_register & EIR_MAPERR)) && ! (I.diaglat))
+ I.mapper_address_latch = I.map_files[map_file].bias[map_index]+addr;
+ if ((I.latch_control[map_index]) && (! I.reset_maperr))
+ I.diaglat = 1;
+ program_write_byte_16be(I.map_files[map_file].bias[map_index]+addr, data);
+ }
+ }
+
+#elif (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID)
+ /*16-bit data bus, 16-bit address bus (internal bus in the case of TMS9940)*/
+ /*Note that tms9900 actually never accesses a single byte : when performing byte operations,
+ it reads a 16-bit word, changes the revelant byte, then write a complete word. You should
+ remember this when writing memory handlers.*/
+ /*This does not apply to tms9995 and tms99xxx, but does apply to tms9980 (see below).*/
+
+ #define readword(addr) program_read_word_16be(addr)
+ #define writeword(addr,data) program_write_word_16be((addr), (data))
+
+ #define readbyte(addr) program_read_byte_16be(addr)
+ #define writebyte(addr,data) program_write_byte_16be((addr),(data))
+
+#elif (TMS99XX_MODEL == TMS9980_ID)
+ /*8-bit data bus, 14-bit address*/
+ /*Note that tms9980 never accesses a single byte (however crazy it may seem). Although this
+ makes memory access slower, I have emulated this feature, because if I did otherwise,
+ there would be some implementation problems in some driver sooner or later.*/
+
+ INLINE int readword(int addr)
+ {
+ int val;
+
+ TMS99XX_ICOUNT -= 2;
+ val = program_read_byte_8(addr);
+ return (val << 8) | program_read_byte_8(addr+1);
+ }
+ #define writeword(addr,data) { TMS99XX_ICOUNT -= 2; program_write_byte_8((addr), (data) >> 8); program_write_byte_8((addr) + 1, (data) & 0xff); }
+
+#if 0
+ #define readbyte(addr) (TMS99XX_ICOUNT -= 2, program_read_byte_8(addr))
+ #define writebyte(addr,data) { TMS99XX_ICOUNT -= 2; program_write_byte_8((addr),(data)); }
+#else
+ /*This is how it really works*/
+ /*Note that every writebyte must match a readbyte (which is indeed the case)*/
+ static int extra_byte; /* buffer holding the unused byte in a word read */
+
+ static int readbyte(int addr)
+ {
+ TMS99XX_ICOUNT -= 2;
+ if (addr & 1)
+ {
+ extra_byte = program_read_byte_8(addr-1);
+ return program_read_byte_8(addr);
+ }
+ else
+ {
+ int val = program_read_byte_8(addr);
+ extra_byte = program_read_byte_8(addr+1);
+ return val;
+ }
+ }
+ static void writebyte (int addr, int data)
+ {
+ TMS99XX_ICOUNT -= 2;
+ if (addr & 1)
+ {
+ program_write_byte_8(addr-1, extra_byte);
+ program_write_byte_8(addr, data);
+ }
+ else
+ {
+ program_write_byte_8(addr, data);
+ program_write_byte_8(addr+1, extra_byte);
+ }
+ }
+#endif
+
+#elif (TMS99XX_MODEL == TMS9985_ID)
+ /*Note that every writebyte must match a readbyte (which is indeed the case)*/
+ static int extra_byte; /* buffer holding the unused byte in a word read */
+
+ static int readword(int addr)
+ {
+ if (addr < 0x2000)
+ {
+ }
+ else if ((addr >= 0x8300) && (addr < 0x8400))
+ {
+ }
+ else
+ {
+ TMS99XX_ICOUNT -= 2;
+ return (program_read_byte_8(addr) << 8) + program_read_byte_8(addr + 1);
+ }
+ }
+ static void writeword(int addr, int data)
+ {
+ if ((addr >= 0x8300) && (addr < 0x8400))
+ {
+ }
+ else if (!(addr < 0x2000))
+ {
+ TMS99XX_ICOUNT -= 2;
+ program_write_byte_8(addr, data >> 8);
+ program_write_byte_8(addr + 1, data & 0xff);
+ }
+ }
+
+ static int readbyte(int addr)
+ {
+ if (addr < 0x2000)
+ {
+ }
+ else if ((addr >= 0x8300) && (addr < 0x8400))
+ {
+ }
+ else
+ {
+ TMS99XX_ICOUNT -= 2;
+ if (addr & 1)
+ {
+ extra_byte = program_read_byte_8(addr-1);
+ return program_read_byte_8(addr);
+ }
+ else
+ {
+ int val = program_read_byte_8(addr);
+ extra_byte = program_read_byte_8(addr+1);
+ return val;
+ }
+ }
+ }
+ static void writebyte(int addr, int data)
+ {
+ if ((addr >= 0x8300) && (addr < 0x8400))
+ {
+ }
+ else if (!(addr < 0x2000))
+ {
+ TMS99XX_ICOUNT -= 2;
+ if (addr & 1)
+ {
+ program_write_byte_8(addr-1, extra_byte);
+ program_write_byte_8(addr, data);
+ }
+ else
+ {
+ program_write_byte_8(addr, data);
+ program_write_byte_8(addr+1, extra_byte);
+ }
+ }
+ }
+
+#elif (TMS99XX_MODEL == TMS9995_ID)
+ /*8-bit external data bus, with on-chip 16-bit RAM, and 16-bit address bus*/
+ /*The code is complex, so we use functions rather than macros*/
+
+ static TIMER_CALLBACK( decrementer_callback );
+
+ static int readword(int addr)
+ {
+ if ((addr < 0xf000) || (I.is_mp9537))
+ {
+ int reply;
+ TMS99XX_ICOUNT -= I.memory_wait_states_word;
+ reply = program_read_byte_8(addr);
+ return (reply << 8) | program_read_byte_8(addr + 1);
+ }
+ else if (addr < 0xf0fc)
+ {
+ return *(UINT16 *)(& I.RAM[addr - 0xf000]);
+ }
+ else if (addr < 0xfffa)
+ {
+ int reply;
+ TMS99XX_ICOUNT -= I.memory_wait_states_word;
+ reply = program_read_byte_8(addr);
+ return (reply << 8) | program_read_byte_8(addr + 1);
+ }
+ else if (addr < 0xfffc)
+ {
+ /* read decrementer */
+ if (I.decrementer_enabled && !(I.flag & 1))
+ /* timer mode, timer enabled */
+ return ceil(ATTOTIME_TO_CYCLES(cpu_getactivecpu(), attotime_div(timer_timeleft(I.timer), 16)));
+ else
+ /* event counter mode or timer mode, timer disabled */
+ return I.decrementer_count;
+ }
+ else
+ {
+ return *(UINT16 *)(& I.RAM[addr - 0xff00]);
+ }
+ }
+
+ static void writeword (int addr, int data)
+ {
+ if ((addr < 0xf000) || (I.is_mp9537))
+ {
+ TMS99XX_ICOUNT -= I.memory_wait_states_word;
+ program_write_byte_8(addr, data >> 8);
+ program_write_byte_8(addr + 1, data & 0xff);
+ }
+ else if (addr < 0xf0fc)
+ {
+ *(UINT16 *)(& I.RAM[addr - 0xf000]) = data;
+ }
+ else if (addr < 0xfffa)
+ {
+ TMS99XX_ICOUNT -= I.memory_wait_states_word;
+ program_write_byte_8(addr, data >> 8);
+ program_write_byte_8(addr + 1, data & 0xff);
+ }
+ else if (addr < 0xfffc)
+ {
+ /* write decrementer */
+ I.decrementer_interval = data;
+ reset_decrementer();
+ }
+ else
+ {
+ *(UINT16 *)(& I.RAM[addr - 0xff00]) = data;
+ }
+ }
+
+ static int readbyte(int addr)
+ {
+ if ((addr < 0xf000) || (I.is_mp9537))
+ {
+ TMS99XX_ICOUNT -= I.memory_wait_states_byte;
+ return program_read_byte_8(addr);
+ }
+ else if (addr < 0xf0fc)
+ {
+ return I.RAM[BYTE_XOR_BE(addr - 0xf000)];
+ }
+ else if (addr < 0xfffa)
+ {
+ TMS99XX_ICOUNT -= I.memory_wait_states_byte;
+ return program_read_byte_8(addr);
+ }
+ else if (addr < 0xfffc)
+ {
+ /* read decrementer */
+ int value;
+
+ if (I.decrementer_enabled && !(I.flag & 1))
+ /* timer mode, timer enabled */
+ value = ceil(ATTOTIME_TO_CYCLES(cpu_getactivecpu(), attotime_div(timer_timeleft(I.timer), 16)));
+ else
+ /* event counter mode or timer mode, timer disabled */
+ value = I.decrementer_count;
+
+ if (addr & 1)
+ return (value & 0xFF);
+ else
+ return (value >> 8);
+ }
+ else
+ {
+ return I.RAM[BYTE_XOR_BE(addr - 0xff00)];
+ }
+ }
+
+ static void writebyte (int addr, int data)
+ {
+ if ((addr < 0xf000) || (I.is_mp9537))
+ {
+ TMS99XX_ICOUNT -= I.memory_wait_states_byte;
+ program_write_byte_8(addr, data);
+ }
+ else if (addr < 0xf0fc)
+ {
+ I.RAM[BYTE_XOR_BE(addr - 0xf000)] = data;
+ }
+ else if (addr < 0xfffa)
+ {
+ TMS99XX_ICOUNT -= I.memory_wait_states_byte;
+ program_write_byte_8(addr, data);
+ }
+ else if (addr < 0xfffc)
+ {
+ /* write decrementer */
+ /* Note that a byte write to tms9995 timer messes everything up. */
+ I.decrementer_interval = (data << 8) | data;
+ reset_decrementer();
+ }
+ else
+ {
+ I.RAM[BYTE_XOR_BE(addr - 0xff00)] = data;
+ }
+ }
+
+#else
+
+ #error "memory access not implemented"
+
+#endif
+
+#if !HAS_MAPPING
+ #define readwordX(addr, map_file) readword(addr)
+ #define writewordX(addr, data, map_file) writeword((addr), (data))
+ #define readbyteX(addr, map_file) readbyte(addr)
+ #define writebyteX(addr, data, map_file) writebyte((addr), (data))
+#endif
+
+#define READREG(reg) readword((I.WP+(reg)) & 0xffff)
+#define WRITEREG(reg, data) writeword((I.WP+(reg)) & 0xffff, (data))
+
+INLINE UINT16 READREG_DEBUG(int reg)
+{
+ int temp = TMS99XX_ICOUNT;
+ UINT16 result = READREG(reg);
+ TMS99XX_ICOUNT = temp;
+ return result;
+}
+
+INLINE void WRITEREG_DEBUG(int reg, UINT16 data)
+{
+ int temp = TMS99XX_ICOUNT;
+ WRITEREG(reg, data);
+ TMS99XX_ICOUNT = temp;
+}
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+ READ8_HANDLER(ti990_10_mapper_cru_r)
+ {
+ int reply = 0;
+
+ switch(I.mapper_cru_read_register)
+ {
+ case 0xb000:
+ reply = I.map_files[I.cur_map].B[0];
+ break;
+ case 0xb001:
+ reply = I.map_files[I.cur_map].B[1];
+ break;
+ case 0xb010:
+ reply = I.map_files[I.cur_map].B[2];
+ break;
+ case 0xb011:
+ reply = I.map_files[I.cur_map].L[0];
+ break;
+ case 0xb100:
+ reply = I.map_files[I.cur_map].L[1];
+ break;
+ case 0xb101:
+ reply = I.map_files[I.cur_map].L[2];
+ break;
+ case 0xb110:
+ reply = I.mapper_address_latch;
+ break;
+ case 0xb111:
+ reply = I.mapper_address_latch >> 16;
+ break;
+ }
+
+ if (offset)
+ return (reply >> 8) & 0xff;
+ else
+ return reply & 0xff;
+ }
+
+ WRITE8_HANDLER(ti990_10_mapper_cru_w)
+ {
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ /* read register select */
+ if (data)
+ I.mapper_cru_read_register |= (1 << offset);
+ else
+ I.mapper_cru_read_register &= ~ (1 << offset);
+ break;
+ case 3:
+ /* enable mapping */
+ I.mapping_on = data;
+ break;
+ case 4:
+ /* reset flags */
+ I.reset_maperr = data;
+ if (data)
+ {
+ I.error_interrupt_register &= ~ EIR_MAPERR;
+ I.diaglat = 0;
+ }
+ break;
+ case 5:
+ case 6:
+ case 7:
+ /* latch control */
+ I.latch_control[7-offset] = data;
+ break;
+ }
+ }
+
+ INLINE void handle_error_interrupt(void)
+ {
+ if (I.error_interrupt_callback)
+ (*I.error_interrupt_callback)(I.error_interrupt_register ? 1 : 0);
+ }
+
+ READ8_HANDLER(ti990_10_eir_cru_r)
+ {
+ return (offset == 1) ? (I.error_interrupt_register & 0xff) : 0;
+ }
+
+ WRITE8_HANDLER(ti990_10_eir_cru_w)
+ {
+ if (offset < 4) /* does not work for EIR_MAPERR */
+ {
+ I.error_interrupt_register &= ~ (1 << offset);
+
+ handle_error_interrupt();
+ }
+ }
+
+
+#endif
+
+/* Interrupt mask */
+#define IMASK (I.STATUS & ST_IM)
+
+/*
+ CYCLES macro : you provide timings for tms9900 and tms9995, and the macro chooses for you.
+
+ BTW, I have no idea what the timings are for tms9989 and tms99xxx...
+*/
+#if TMS99XX_MODEL == TI990_10_ID
+ /* Use TI990/10 timings*/
+ #define CYCLES(a,b,c) TMS99XX_ICOUNT -= a
+#elif TMS99XX_MODEL <= TMS9985_ID
+ /* Use TMS9900/TMS9980 timings*/
+ #define CYCLES(a,b,c) TMS99XX_ICOUNT -= b
+#else
+ /* Use TMS9995 timings*/
+ #define CYCLES(a,b,c) TMS99XX_ICOUNT -= c*4
+#endif
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+
+static void set_flag0(int val);
+static void set_flag1(int val);
+
+#endif
+
+/************************************************************************
+ * Status register functions
+ ************************************************************************/
+#include "99xxstat.h"
+
+/**************************************************************************/
+
+static void register_for_save_state(int index)
+{
+ state_save_register_item("tms99xx", index, I.WP);
+ state_save_register_item("tms99xx", index, I.PC);
+ state_save_register_item("tms99xx", index, I.STATUS);
+ state_save_register_item("tms99xx", index, I.interrupt_pending);
+
+#if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID))
+ state_save_register_item("tms99xx", index, I.load_state);
+#endif
+
+#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)
+ state_save_register_item("tms99xx", index, I.irq_level);
+ state_save_register_item("tms99xx", index, I.irq_state);
+#elif (TMS99XX_MODEL == TMS9995_ID)
+ state_save_register_item("tms99xx", index, I.irq_level);
+ state_save_register_item("tms99xx", index, I.int_state);
+ state_save_register_item("tms99xx", index, I.int_latch);
+#endif
+
+ state_save_register_item("tms99xx", index, I.IDLE);
+
+#if HAS_MAPPING
+ state_save_register_item("tms99xx", index, I.mapping_on);
+ state_save_register_item_array("tms99xx", index, I.map_files[0].L);
+ state_save_register_item_array("tms99xx", index, I.map_files[0].B);
+ state_save_register_item_array("tms99xx", index, I.map_files[0].limit);
+ state_save_register_item_array("tms99xx", index, I.map_files[0].bias);
+ state_save_register_item_array("tms99xx", index, I.map_files[1].L);
+ state_save_register_item_array("tms99xx", index, I.map_files[1].B);
+ state_save_register_item_array("tms99xx", index, I.map_files[1].limit);
+ state_save_register_item_array("tms99xx", index, I.map_files[1].bias);
+ state_save_register_item_array("tms99xx", index, I.map_files[2].L);
+ state_save_register_item_array("tms99xx", index, I.map_files[2].B);
+ state_save_register_item_array("tms99xx", index, I.map_files[2].limit);
+ state_save_register_item_array("tms99xx", index, I.map_files[2].bias);
+ state_save_register_item("tms99xx", index, I.cur_map);
+ state_save_register_item("tms99xx", index, I.cur_src_map);
+ state_save_register_item("tms99xx", index, I.cur_dst_map);
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+ state_save_register_item("tms99xx", index, I.reset_maperr);
+ state_save_register_item("tms99xx", index, I.mapper_address_latch);
+ state_save_register_item("tms99xx", index, I.mapper_cru_read_register);
+ state_save_register_item("tms99xx", index, I.diaglat);
+ state_save_register_item_array("tms99xx", index, I.latch_control);
+#endif
+#endif
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+ state_save_register_item("tms99xx", index, I.error_interrupt_register);
+#endif
+
+#if (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
+ state_save_register_item_array("tms99xx", index, I.RAM);
+#endif
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
+ state_save_register_item("tms99xx", index, I.decrementer_enabled);
+ state_save_register_item("tms99xx", index, I.decrementer_interval);
+ state_save_register_item("tms99xx", index, I.decrementer_count);
+#endif
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+ state_save_register_item("tms99xx", index, I.flag);
+ state_save_register_item("tms99xx", index, I.MID_flag);
+ state_save_register_item("tms99xx", index, I.memory_wait_states_byte);
+ state_save_register_item("tms99xx", index, I.memory_wait_states_word);
+ state_save_register_item("tms99xx", index, I.is_mp9537);
+#endif
+
+ state_save_register_item("tms99xx", index, I.disable_interrupt_recognition);
+}
+
+
+static void tms99xx_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ const TMS99XX_RESET_PARAM *param = (const TMS99XX_RESET_PARAM *) config;
+
+ register_for_save_state(index);
+
+ I.irq_callback = irqcallback;
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+ I.timer = timer_alloc(decrementer_callback);
+#endif
+
+ I.idle_callback = param ? param->idle_callback : NULL;
+ #if (TMS99XX_MODEL == TI990_10_ID)
+ I.rset_callback = param ? param->rset_callback : NULL;
+ I.lrex_callback = param ? param->lrex_callback : NULL;
+ I.ckon_ckof_callback = param ? param->ckon_ckof_callback : NULL;
+
+ I.error_interrupt_callback = param ? param->error_interrupt_callback : NULL;
+ #endif
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+ /* we can ask at reset time that the CPU always generates one wait state automatically */
+ if (param == NULL)
+ { /* if no param, the default is currently "wait state added" */
+ I.memory_wait_states_byte = 4;
+ I.memory_wait_states_word = 12;
+ I.is_mp9537 = 0;
+ }
+ else
+ {
+ I.memory_wait_states_byte = (param->auto_wait_state) ? 4 : 0;
+ I.memory_wait_states_word = (param->auto_wait_state) ? 12 : 4;
+ I.is_mp9537 = param->is_mp9537;
+ }
+#endif
+
+}
+
+/*
+ TMS9900 hard reset
+*/
+static void tms99xx_reset(void)
+{
+ I.STATUS = 0; /* TMS9980 and TMS9995 Data Books say so */
+ getstat();
+
+ #if HAS_MAPPING
+ I.mapping_on = 0;
+{
+ int i,j;
+
+ for (i=0; i<3; i++)
+ for (j=0; j<3; j++)
+ {
+ I.map_files[i].L[j] = 0;
+ I.map_files[i].limit[j] = 0xffff;
+ I.map_files[i].B[j] = 0;
+ I.map_files[i].bias[j] = 0;
+ }
+ }
+ I.cur_map = 0; /* equivalent to ST_MF status bit */
+ I.cur_src_map = 0; /* set to 2 by LDS */
+ I.cur_dst_map = 0; /* set to 2 by LDD */
+
+ I.reset_maperr = 0;
+ #endif
+
+ if (I.IDLE)
+ {
+ I.IDLE = 0; /* clear IDLE condition */
+ if (I.idle_callback)
+ (*I.idle_callback)(0);
+ }
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+ I.MID_flag = 0;
+
+ /* Clear flag bits 0 & 1 */
+ set_flag0(0);
+ set_flag1(0);
+
+ /* Clear internal interrupt latches */
+ I.int_latch = 0;
+ I.flag &= 0xFFE3;
+#endif
+
+ /* The ST register and interrupt latches changed, didn't they ? */
+ field_interrupt();
+
+ contextswitchX(0x0000);
+
+ CYCLES(6, 26, 14);
+}
+
+static void tms99xx_exit(void)
+{
+ /* nothing to do ? */
+}
+
+/* fetch : read one word at * PC, and increment PC. */
+INLINE UINT16 fetch(void)
+{
+ UINT16 value = readword(I.PC);
+ I.PC += 2;
+ return value;
+}
+
+
+static int tms99xx_execute(int cycles)
+ {
+ TMS99XX_ICOUNT = cycles;
+
+ lds_flag = 0;
+ ldd_flag = 0;
+
+ do
+ {
+ /* all TMS9900 chips I know do not honor interrupts after XOP, BLWP or MID (after any
+ interrupt-like instruction, actually), and they do not either after LDS and LDD
+ (There are good reasons for this). */
+ if ((I.interrupt_pending) && (! I.disable_interrupt_recognition))
+ {
+ int level;
+
+ level = I.irq_level;
+
+
+ if (I.load_state)
+ { /* LOAD has the highest priority */
+
+ contextswitchX(0xFFFC); /* load vector, save PC, WP and ST */
+
+ I.STATUS &= ~ST_IM; /* clear interrupt mask */
+
+ /* clear IDLE status if necessary */
+ if (I.IDLE)
+ {
+ I.IDLE = 0; /* clear IDLE condition */
+ if (I.idle_callback)
+ (*I.idle_callback)(0);
+ }
+
+ CYCLES(6/*to be confirmed*/, 22, 14);
+ }
+ else if (level <= IMASK)
+ { /* a maskable interrupt is honored only if its level isn't greater than IMASK */
+
+ contextswitchX(level*4); /* load vector, save PC, WP and ST */
+
+ /* change interrupt mask */
+ if (level)
+ {
+ I.STATUS = (I.STATUS & ~ST_IM) | (level -1); /* decrement mask */
+ I.interrupt_pending = 0; /* as a consequence, the interrupt request will be subsequently ignored */
+ }
+ else
+ I.STATUS &= ~ST_IM; /* clear mask (is this correct???) */
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+ I.STATUS &= 0xFE00;
+#endif
+
+ /* clear IDLE status if necessary */
+ if (I.IDLE)
+ {
+ I.IDLE = 0; /* clear IDLE condition */
+ if (I.idle_callback)
+ (*I.idle_callback)(0);
+ }
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+ /* Clear bit in latch */
+ /* I think tms9989 does this, too */
+ if (level != 2)
+ { /* Only do this on level 1, 3, 4 interrupts */
+ int mask = 1 << level;
+ int flag_mask = (level == 1) ? 4 : mask;
+
+ I.int_latch &= ~ mask;
+ I.flag &= ~ flag_mask;
+
+ /* unlike tms9900, we can call the callback */
+ if (level == 1)
+ (* I.irq_callback)(0);
+ else if (level == 4)
+ (* I.irq_callback)(1);
+ }
+#endif
+
+ CYCLES(6, 22, 14);
+ }
+ else
+ {
+ logerror("tms9900.c : the interrupt_pending flag was set incorrectly\n");
+ I.interrupt_pending = 0;
+ }
+ }
+
+ #ifdef MAME_DEBUG
+ {
+ if (Machine->debug_mode)
+ {
+ #if 0 /* Trace */
+ logerror("> PC %4.4x :%4.4x %4.4x : R=%4.4x %4.4x %4.4x %4.4x %4.4x %4.4x %4.4x %4.4x %4.4x %4.4x%4.4x %4.4x %4.4x %4.4x %4.4x %4.4x :T=%d\n",I.PC,I.STATUS,I.WP,I.FR[0],I.FR[1],I.FR[2],I.FR[3],I.FR[4],I.FR[5],I.FR[6],I.FR[7],I.FR[8],I.FR[9],I.FR[10],I.FR[11],I.FR[12],I.FR[13],I.FR[14],I.FR[15],TMS99XX_ICOUNT);
+ #if 0 /* useful with TI99/4a driver */
+ #ifdef MESS
+ if (I.PC == 0x0078)
+ {
+ extern struct
+ {
+ /* pointer to GROM data */
+ UINT8 *data_ptr;
+ /* current address pointer for the active GROM in port (16 bits) */
+ unsigned int addr;
+ /* GROM data buffer */
+ UINT8 buf;
+ /* internal flip-flops that are set after the first access to the GROM
+ address so that next access is mapped to the LSB, and cleared after each
+ data access */
+ char raddr_LSB, waddr_LSB;
+ } console_GROMs;
+ logerror("> GPL pointer %4.4X\n", console_GROMs.addr);
+ }
+ #endif
+ #endif
+ #endif
+
+ mame_debug_hook();
+ }
+ }
+ #endif
+
+ if (I.IDLE)
+ { /* IDLE instruction has halted execution */
+ #if EXTERNAL_INSTRUCTION_DECODING
+ external_instruction_notify(2);
+ CYCLES(Moof!, 2, 2); /* 2 cycles per CRU write */
+ #else
+ TMS99XX_ICOUNT = 0; /* much simpler... */
+ #endif
+ }
+ else
+ { /* we execute an instruction */
+ I.disable_interrupt_recognition = 0; /* default value */
+ I.IR = fetch();
+ execute(I.IR);
+ #if HAS_MAPPING
+ if (lds_flag)
+ {
+ lds_flag = 0;
+ I.cur_src_map = 2 /*(I.cur_src_map != 2) ? 2 : I.cur_map*/;
+ }
+ else
+ I.cur_src_map = I.cur_map;
+ if (ldd_flag)
+ {
+ ldd_flag = 0;
+ I.cur_dst_map = 2 /*(I.cur_src_map != 2) ? 2 : I.cur_map*/;
+ }
+ else
+ I.cur_dst_map = I.cur_map;
+ #if (TMS99XX_MODEL == TI990_10_ID)
+ write_inhibit = 0;
+ #endif
+ #endif
+
+ #if (HAS_OVERFLOW_INTERRUPT)
+ #if (TMS99XX_MODEL == TMS9995_ID)
+ /* Note that TI had some problem implementing this... I don't know if this feature works on
+ a real-world TMS9995. */
+ if ((I.STATUS & ST_OVIE) && (I.STATUS & ST_OV) && (I.irq_level > 2))
+ I.irq_level = 2; /* interrupt request */
+ #else
+ #warning "todo..."
+ #endif
+ #endif
+ }
+
+ } while (TMS99XX_ICOUNT > 0);
+
+ return cycles - TMS99XX_ICOUNT;
+}
+
+static void tms99xx_get_context(void *dst)
+{
+ setstat();
+
+ if( dst )
+ *(tms99xx_Regs*)dst = I;
+}
+
+static void tms99xx_set_context(void *src)
+{
+ if( src )
+ {
+ I = *(tms99xx_Regs*)src;
+ /* We have to make additionnal checks, because Mame debugger can foolishly initialize
+ the context to all 0s */
+ #if (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TI990_10_ID)
+ if (! I.irq_state)
+ I.irq_level = 16;
+#elif ((TMS99XX_MODEL == TMS9980_ID) || (TMS99XX_MODEL == TMS9995_ID))
+ /* Our job is simpler, since there is no level-0 request... */
+ if (! I.irq_level)
+ I.irq_level = 16;
+ #elif ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID))
+ if (! I.irq_level)
+ I.irq_level = 4;
+#else
+ #warning "You may want to have a look at this problem"
+#endif
+
+ getstat(); /* set last_parity */
+ }
+}
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+
+static void tms99xx_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ I.load_state = state; /* save new state */
+
+ field_interrupt(); /* interrupt status changed */
+ }
+ else
+ {
+ /*if (I.irq_state == state)
+ return;*/
+
+ I.irq_state = state;
+
+ if (state == CLEAR_LINE)
+ I.irq_level = 16;
+ /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */
+ else
+ I.irq_level = (* I.irq_callback)(0);
+
+ field_interrupt(); /* interrupt state is likely to have changed */
+ }
+}
+
+#elif (TMS99XX_MODEL == TMS9900_ID)
+
+/*
+void tms99xx_set_irq_line(INPUT_LINE_NMI, int state) : change the state of the LOAD* line
+
+ state == 0 -> LOAD* goes high (inactive)
+ state != 0 -> LOAD* goes low (active)
+
+ While LOAD* is low, we keep triggering LOAD interrupts...
+
+ A problem : some peripherals lower the LOAD* line for a fixed time interval (causing the 1st
+ instruction of the LOAD interrupt routine to be repeated while the line is low), and will be
+ perfectly happy with the current scheme, but others might be more clever and wait for the IAQ
+ (Instruction acquisition) line to go high, and this needs a callback function to emulate.
+*/
+
+/*
+void tms99xx_set_irq_line(int irqline, int state) : sets the state of the interrupt line.
+
+ irqline is ignored, and should always be 0.
+
+ state == 0 -> INTREQ* goes high (inactive)
+ state != 0 -> INTREQ* goes low (active)
+*/
+/*
+ R Nabet 991020, revised 991218 :
+ In short : interrupt code should call "cpu_set_irq_line(0, 0, ASSERT_LINE);" to set an
+ interrupt request (level-triggered interrupts). Also, there MUST be a call to
+ "cpu_set_irq_line(0, 0, CLEAR_LINE);" in the machine code, when the interrupt line is released by
+ the hardware (generally in response to an action performed by the interrupt routines).
+ On tms9995 (9989 ?), you can use PULSE_LINE, too, since the processor latches the line...
+
+ **Note** : HOLD_LINE *NEVER* makes sense on the TMS9900 (or 9980, 9995...). The reason is the
+ TMS9900 does NOT tell the world it acknoledges an interrupt, so no matter how much hardware you
+ use, you cannot know when the CPU takes the interrupt, hence you cannot release the line when
+ the CPU takes the interrupt. Generally, the interrupt condition is cleared by the interrupt
+ routine (with some CRU or memory access).
+
+ Note that cpu_generate_interrupt uses HOLD_LINE, so your driver interrupt code
+ should always use the new style, i.e. return "ignore_interrupt()" and call
+ "cpu_set_irq_line(0, 0, ASSERT_LINE);" explicitely.
+
+ Last, many TMS9900-based hardware use a TMS9901 interrupt-handling chip. If anybody wants
+ to emulate some hardware which uses it, note that I am writing some emulation in the TI99/4(A)
+ driver in MESS, so you should ask me.
+*/
+/*
+ * HJB 990430: changed to use irq_callback() to retrieve the vector
+ * instead of using 16 irqlines.
+ *
+ * R Nabet 990830 : My mistake, I rewrote all these once again ; I think it is now correct.
+ * A driver using the TMS9900 should do :
+ * cpu_0_irq_line_vector_w(0, level);
+ * cpu_set_irq_line(0,0,ASSERT_LINE);
+ *
+ * R Nabet 991108 : revised once again, with advice from Juergen Buchmueller, after a discussion
+ * with Nicola...
+ * We use the callback to retreive the interrupt level as soon as INTREQ* is asserted.
+ * As a consequence, I do not support HOLD_LINE normally... However, we do not really have to
+ * support HOLD_LINE, since no real world TMS9900-based system can support this.
+ * FYI, there are two alternatives to retreiving the interrupt level with the callback :
+ * a) using 16 pseudo-IRQ lines. Mostly OK, though it would require a few core changes.
+ * However, this could cause some problems if someone tried to set two lines simulteanously...
+ * And TMS9900 did NOT have 16 lines ! This is why Juergen and I did not retain this solution.
+ * b) modifying the interrupt system in order to provide an extra int to every xxx_set_irq_line
+ * function. I think this solution would be fine, but it would require quite a number of
+ * changes in the MAME core. (And I did not feel the courage to check out 4000 drivers and 25
+ * cpu cores ;-) .)
+ *
+ * Note that this does not apply to tms9995.
+*/
+static void tms99xx_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ I.load_state = state; /* save new state */
+
+ field_interrupt(); /* interrupt status changed */
+ }
+ else
+ {
+ /*if (I.irq_state == state)
+ return;*/
+
+ I.irq_state = state;
+
+ if (state == CLEAR_LINE)
+ I.irq_level = 16;
+ /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */
+ else
+ I.irq_level = (* I.irq_callback)(0);
+
+ field_interrupt(); /* interrupt state is likely to have changed */
+ }
+}
+
+#elif (TMS99XX_MODEL == TMS9980_ID)
+/*
+ interrupt system similar to tms9900, but only 3 interrupt pins (IC0-IC2)
+*/
+
+static void tms99xx_set_irq_line(int irqline, int state)
+{
+ if (state == CLEAR_LINE)
+ {
+ I.load_state = 0;
+ I.irq_state = 0;
+ I.irq_level = 16;
+ /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */
+ }
+ else
+ {
+ int level;
+
+ if (irqline == INPUT_LINE_NMI)
+ level = 2; /* translate MAME's convention to CPU's representation */
+ else
+ level = (* I.irq_callback)(0);
+
+ switch (level)
+ {
+ case 0:
+ case 1:
+ I.load_state = 0;
+ I.irq_state = 0;
+ I.irq_level = 16;
+ tms99xx_reset();
+ break;
+ case 2:
+ I.load_state = 1;
+ I.irq_state = 0;
+ I.irq_level = 16;
+ break;
+ case 7:
+ I.load_state = 0;
+ I.irq_state = 0;
+ I.irq_level = 16;
+ break;
+ default: /* external levels 1, 2, 3, 4 */
+ I.load_state = 0;
+ I.irq_state = 1;
+ I.irq_level = level - 2;
+ break;
+ }
+ }
+
+ field_interrupt(); /* interrupt state is likely to have changed */
+}
+
+#elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+/*
+ 2 interrupt pins (int1 and int2)
+*/
+
+static void tms99xx_set_irq_line(int irqline, int state)
+ {
+ int mask;
+
+ if (irqline == 0)
+ /* INT1 */
+ mask = 1;
+ else if (irqline == 1)
+ /* INT2 */
+ mask = 4;
+ else
+ /* What on earth??? */
+ return;
+
+ if (state)
+ I.irq_state |= mask;
+ else
+ I.irq_state &= ~mask;
+
+ field_interrupt(); /* interrupt state is likely to have changed */
+}
+
+#elif (TMS99XX_MODEL == TMS9995_ID)
+/*
+ this call-back is called by MESS timer system when the timer reaches 0.
+*/
+static TIMER_CALLBACK( decrementer_callback )
+{
+ /* request decrementer interrupt */
+ I.int_latch |= 0x8;
+ I.flag |= 0x8;
+
+ field_interrupt();
+}
+
+
+/*
+ reset and load the timer/decrementer
+
+ Note that I don't know whether toggling flag0/flag1 causes the decrementer to be reloaded or not
+*/
+static void reset_decrementer(void)
+{
+ timer_adjust(I.timer, attotime_never, 0, attotime_zero);
+
+ /* reload count */
+ I.decrementer_count = I.decrementer_interval;
+
+ /* decrementer / timer enabled ? */
+ I.decrementer_enabled = ((I.flag & 2) && (I.decrementer_interval));
+
+ if (I.decrementer_enabled && ! (I.flag & 1))
+ { /* timer */
+ attotime period = ATTOTIME_IN_CYCLES(I.decrementer_interval * 16L, cpu_getactivecpu());
+ timer_adjust(I.timer, period, 0, period);
+ }
+}
+
+/*
+ You have two interrupt line : one triggers level-1 interrupts, the other triggers level-4
+ interrupts (or decrements the decrementer register).
+
+ According to the hardware, you may use PULSE_LINE (edge-triggered interrupts), or ASSERT_LINE
+ (level-triggered interrupts). Edge-triggered interrupts are way simpler, but if multiple devices
+ share the same line, they must use level-triggered interrupts.
+*/
+static void tms99xx_set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ I.load_state = state; /* save new state */
+
+ field_interrupt(); /* interrupt status changed */
+ }
+ else
+ {
+ int mask = (irqline == 0) ? 0x2 : 0x10;
+ int flag_mask = (irqline == 0) ? 0x4 : 0x10;
+
+ if (((I.int_state & mask) != 0) ^ (state != 0))
+ { /* only if state changes */
+ if (state)
+ {
+ I.int_state |= mask;
+
+ if ((irqline == 1) && (I.flag & 1))
+ { /* event counter mode : INT4* triggers no interrupt... */
+ if (I.decrementer_enabled)
+ { /* decrement, then interrupt if reach 0 */
+ if ((-- I.decrementer_count) == 0)
+ {
+ decrementer_callback(Machine, 0);
+ I.decrementer_count = I.decrementer_interval; /* reload */
+ }
+ }
+ }
+ else
+ { /* plain interrupt mode */
+ I.int_latch |= mask;
+ I.flag |= flag_mask;
+ }
+ }
+ else
+ {
+ I.int_state &= ~ mask;
+ }
+
+ field_interrupt(); /* interrupt status changed */
+ }
+ }
+}
+
+#else
+
+#error "interrupt system not implemented"
+
+#endif
+
+/*
+ * field_interrupt
+ *
+ * Determines whether if an interrupt is pending, and sets the revelant flag.
+ *
+ * Called when an interrupt pin (LOAD*, INTREQ*, IC0-IC3) is changed, and when the interrupt mask
+ * is modified.
+ *
+ * By using this flag, we save some compares in the execution loop. Subtle, isn't it ;-) ?
+ *
+ * R Nabet.
+ */
+#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)
+
+static void field_interrupt(void)
+{
+ I.interrupt_pending = ((I.irq_level <= IMASK) || (I.load_state));
+}
+
+#elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+
+static void field_interrupt(void)
+{
+ if (I.irq_state & 1)
+ I.irq_level = 1;
+ else if (I.irq_state & 2)
+ I.irq_level = 2;
+ else if (I.irq_state & 4)
+ I.irq_level = 3;
+ else
+ I.irq_level = 4;
+ /* trick : 4 will always be bigger than the IM (0-3), so there will never be interrupts */
+
+ I.interrupt_pending = ((I.irq_level <= IMASK) || (I.load_state));
+}
+
+#elif (TMS99XX_MODEL == TMS9995_ID)
+
+static void field_interrupt(void)
+{
+ if (I.load_state)
+ {
+ I.interrupt_pending = 1;
+ }
+ else
+ {
+ int current_int;
+ int level;
+
+ if (I.flag & 1)
+ /* event counter mode : ignore int4* line... */
+ current_int = (I.int_state & ~0x10) | I.int_latch;
+ else
+ /* normal behavior */
+ current_int = I.int_state | I.int_latch;
+
+ if (current_int)
+ /* find first bit to 1 */
+ /* possible values : 1, 3, 4 */
+ for (level=0; ! (current_int & 1); current_int >>= 1, level++)
+ ;
+ else
+ level=16;
+
+ I.irq_level = level;
+
+ I.interrupt_pending = (level <= IMASK);
+ }
+}
+
+#else
+
+#error "field_interrupt() not written"
+
+#endif
+
+#ifdef MAME_DEBUG
+static unsigned tms99xx_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return Dasm9900(buffer, pc, TMS99XX_MODEL, oprom, opram);
+}
+#endif /* MAME_DEBUG */
+
+
+/*****************************************************************************/
+/*
+ CRU support code
+
+ The CRU bus is a 1-bit-wide I/O bus. The CPU can read or write bits at random address.
+ Special instructions are dedicated to reading and writing one or several consecutive bits.
+
+
+
+ Note that TMS99000 additionally supports parallel CRU operations, although I don't know how
+ this feature is implemented.
+*/
+
+enum
+{
+#if (TMS99XX_MODEL == TI990_10_ID)
+ /* 3 MSBs do exist, although they are not connected (don't ask...) */
+ CRUAddrBit = 15
+#elif (TMS99XX_MODEL == TMS9900_ID)
+ /* 3 MSBs are always 0 to support external instructions */
+ CRUAddrBit = 12
+#elif (TMS99XX_MODEL == TMS9980_ID)
+ /* 2 bits unused, and 2 MSBs are always 0 to support external instructions */
+ CRUAddrBit = 11
+#elif (TMS99XX_MODEL == TMS9940_ID)
+ /* 9 internal address lines (8 external) */
+ CRUAddrBit = 9
+#elif (TMS99XX_MODEL == TMS9995_ID)
+ /* no such problem here : data bus lines D0-D2 provide the external instruction code */
+ CRUAddrBit = 15
+#else
+ #warning "I don't know how your processor handles CRU."
+ CRUAddrBit = 15
+#endif
+};
+
+enum
+{
+ rCRUAddrMask = (1 << (CRUAddrBit - 3)) - 1,
+ wCRUAddrMask = (1 << CRUAddrBit) - 1
+};
+
+
+#if (TMS99XX_MODEL == TMS9995_ID)
+
+/* set decrementer mode flag */
+static void set_flag0(int val)
+{
+ if (val)
+ I.flag |= 1;
+ else
+ I.flag &= ~ 1;
+
+ reset_decrementer();
+}
+
+/* set decrementer enable flag */
+static void set_flag1(int val)
+{
+ if (val)
+ I.flag |= 2;
+ else
+ I.flag &= ~ 2;
+
+ reset_decrementer();
+}
+
+#endif
+
+typedef enum
+{
+ CRU_OK = 0,
+ CRU_PRIVILEGE_VIOLATION = -1
+} cru_error_code;
+
+#define WRITEPORT(port, data) io_write_byte_8(port, data)
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+/* on tms9940, we have to handle internal CRU ports */
+static void write_single_CRU(int port, int data)
+{
+ int mask;
+
+ if (! (port & 0x100))
+ {
+ /*if (I.config & CB0)*/
+ /* External CRU */
+ WRITEPORT(port, (data & 0x01));
+ }
+ else
+ {
+ /* internal CRU */
+ switch ((port >> 4) & 0xf)
+ {
+ case 0x8:
+ if (port == 0x181)
+ {
+ /* clear decrementer interrupt */
+ I.irq_state &= ~2;
+ }
+ if (port >= 0x183) && (port <= 0x186)
+ {
+ /* write configuration register */
+ mask = 1 << (port - 0x183);
+ /* ... */
+ }
+ break;
+
+ case 0x9:
+ if (port <= 0x19D)
+ {
+ /* write decrementer latch */
+ mask = 1 << (port - 0x190);
+ /* ... */
+ }
+ else if (port == 0x19E)
+ {
+ /* set decrementer as timer (1) or event counter (0) */
+ /* ... */
+ }
+ break;
+
+ case 0xA:
+ /* multiprocessor system interface */
+ mask = 1 << (port - 0x1A0);
+ /* ... */
+ break;
+
+ case 0xB:
+ /* flags */
+ mask = 1 << (port - 0x1B0);
+ /* ... */
+ break;
+
+ case 0xC:
+ case 0xD:
+ /* direction for P0-P31 */
+ mask = 1 << (port - 0x1C0);
+ /* ... */
+ break;
+
+ case 0xE:
+ case 0xF:
+ /* data for P0-P31 */
+ mask = 1 << (port - 0x1E0);
+ /* ... */
+ break;
+ }
+ }
+}
+#elif (TMS99XX_MODEL == TMS9995_ID)
+/* on tms9995, we have to handle internal CRU ports */
+static void write_single_CRU(int port, int data)
+ {
+ /* Internal CRU */
+ switch (port)
+ {
+ case 0xF70:
+ set_flag0(data & 0x01);
+ break;
+ case 0xF71:
+ set_flag1(data & 0x01);
+ break;
+ case 0xF72:
+ case 0xF73:
+ case 0xF74:
+ break; /* ignored */
+ case 0xF75:
+ case 0xF76:
+ case 0xF77:
+ case 0xF78:
+ case 0xF79:
+ case 0xF7A:
+ case 0xF7B:
+ case 0xF7C:
+ case 0xF7D:
+ case 0xF7E:
+ case 0xF7F:
+ { /* user defined flags */
+ int mask = 1 << (port - 0xF70);
+ if (data & 0x01)
+ I.flag |= mask;
+ else
+ I.flag &= ~ mask;
+ }
+ break;
+
+ case 0x0FED:
+ /* MID flag */
+ I.MID_flag = data & 0x01;
+ break;
+ }
+ /* External CRU */
+ /* Even though all the registers above are implemented internally, accesses
+ are passed to the external bus, too, and an external device might respond
+ to a write to these CRU address as well (particularly a write to the user
+ flag registers). */
+ WRITEPORT(port, (data & 0x01));
+}
+#else
+#define write_single_CRU(port, data) WRITEPORT(port, data)
+#endif
+
+/*
+ performs a normal write to CRU bus (used by SBZ, SBO, LDCR : address range 0 -> 0xFFF)
+*/
+static cru_error_code writeCRU(int CRUAddr, int Number, UINT16 Value)
+{
+ int count;
+
+ /*logerror("PC %4.4x Write CRU %x for %x =%x\n",I.PC,CRUAddr,Number,Value);*/
+
+ CRUAddr &= wCRUAddrMask;
+
+ /* Write Number bits from CRUAddr */
+
+ for(count=0; count<Number; count++)
+ {
+ #if HAS_PRIVILEGE
+ if ((I.STATUS & ST_PR) && (CRUAddr >= 0xE00))
+ return CRU_PRIVILEGE_VIOLATION;
+#endif
+
+ write_single_CRU(CRUAddr, (Value & 0x01));
+ Value >>= 1;
+ CRUAddr = (CRUAddr + 1) & wCRUAddrMask;
+ }
+
+ return CRU_OK;
+}
+
+#if EXTERNAL_INSTRUCTION_DECODING
+/*
+ Some opcodes perform a dummy write to a special CRU address, so that an external function may be
+ triggered.
+
+ Only the first 3 MSBs of the address matter : other address bits and the written value itself
+ are undefined.
+
+ How should we support this ? With callback functions ? Actually, as long as we do not support
+ hardware which makes use of this feature, it does not really matter :-) .
+*/
+static void external_instruction_notify(int ext_op_ID)
+{
+#if 1
+ /* I guess we can support this like normal CRU operations */
+#if (TMS99XX_MODEL == TMS9900_ID)
+ WRITEPORT(ext_op_ID << 12, 0); /* or is it 1 ??? */
+#elif (TMS99XX_MODEL == TMS9980_ID)
+ WRITEPORT((ext_op_ID & 3) << 11, (ext_op_ID & 4) ? 1 : 0);
+#elif (TMS99XX_MODEL == TMS9995_ID)
+ WRITEPORT(ext_op_ID << 15, 0); /* or is it 1 ??? */
+#else
+ #warning "I don't know how your processor handles external opcodes (maybe you don't need them, though)."
+#endif
+
+#else
+ switch (ext_op_ID)
+ {
+ case 2: /* IDLE */
+
+ break;
+ case 3: /* RSET */
+
+ break;
+ case 5: /* CKON */
+
+ break;
+ case 6: /* CKOF */
+
+ break;
+ case 7: /* LREX */
+
+ break;
+ case 0:
+ /* normal CRU write !!! */
+ logerror("PC %4.4x : external_instruction_notify : wrong ext_op_ID",I.PC);
+ break;
+ default:
+ /* unknown address */
+ logerror("PC %4.4x : external_instruction_notify : unknown ext_op_ID",I.PC);
+ break;
+ }
+#endif
+}
+#endif
+
+/*
+ performs a normal read to CRU bus (used by TB, STCR : address range 0->0xFFF)
+
+ Note that on some hardware, e.g. TI99/4(a), all normal memory operations cause unwanted CRU
+ read at the same address. This seems to be impossible to emulate efficiently, so, if you need
+ to emulate this, you're in trouble.
+*/
+#define READPORT(port) io_read_byte_8(port)
+
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+/* on tms9940, we have to handle internal CRU ports */
+static int read_single_CRU(int port)
+{
+ int reply;
+ int shift;
+
+ if (! (port & 0x20))
+ {
+ /*if (I.config & CB0)*/
+ /* External CRU */
+ reply = READPORT(port, (data & 0x01));
+ }
+ else
+ {
+ /* internal CRU */
+ switch (port)
+ {
+ case 0x10:
+ /* read interrupt state */
+ reply = I.irq_state;
+ break;
+
+ case 0x12:
+ /* read decrementer LSB */
+ /* ... */
+ break;
+ case 0x13:
+ /* read decrementer MSB */
+ /* ... */
+ break;
+
+ case 0x14:
+ /* read multiprocessor system interface LSB */
+ /* ... */
+ break;
+ case 0x15:
+ /* read multiprocessor system interface MSB */
+ /* ... */
+ break;
+
+ case 0x16:
+ /* read flags LSB */
+ /* ... */
+ break;
+ case 0x17:
+ /* read flags MSB */
+ /* ... */
+ break;
+
+ case 0x18:
+ case 0x19:
+ case 0x1A:
+ case 0x1B:
+ /* direction for P0-P31 */
+ shift = (port - 0x18) << 3;
+ /* ... */
+ break;
+
+ case 0x1C:
+ case 0x1D:
+ case 0x1E:
+ case 0x1F:
+ /* data for P0-P31 */
+ shift = (port - 0x1C) << 3;
+ /* ... */
+ break;
+
+ default:
+ reply = 0;
+ break;
+ }
+ }
+
+ return reply;
+}
+#elif (TMS99XX_MODEL == TMS9995_ID)
+/* on tms9995, we have to handle internal CRU ports */
+static int read_single_CRU(int port)
+{
+ switch (port)
+{
+ case 0x1EE:
+ /* flag, bits 0-7 */
+ return I.flag & 0xFF;
+ case 0x1EF:
+ /* flag, bits 8-15 */
+ return (I.flag >> 8) & 0xFF;
+ case 0x1FD:
+ /* MID flag, and external devices */
+ if (I.MID_flag)
+ return READPORT(port) | 0x10;
+ else
+ return READPORT(port) & ~ 0x10;
+ default:
+ /* external devices */
+ return READPORT(port);
+ }
+}
+#else
+#define read_single_CRU(port) READPORT(port)
+#endif
+
+static int readCRU(int CRUAddr, int Number)
+{
+ static int BitMask[] =
+ {
+ 0, /* filler - saves a subtract to find mask */
+ 0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,0x00FF,
+ 0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF
+ };
+
+ int Offset,Location,Value;
+
+ /*logerror("Read CRU %x for %x\n",CRUAddr,Number);*/
+
+ Location = (CRUAddr >> 3) & rCRUAddrMask;
+ Offset = CRUAddr & 07;
+
+ /* Read 8 bits */
+ #if HAS_PRIVILEGE
+ if ((I.STATUS & ST_PR) && (Location >= (0xE00 >> 3)))
+ return CRU_PRIVILEGE_VIOLATION;
+ #endif
+ Value = read_single_CRU(Location);
+
+ if ((Offset+Number) > 8)
+ {
+ /* Read next 8 bits */
+ Location = (Location + 1) & rCRUAddrMask;
+ #if HAS_PRIVILEGE
+ if ((I.STATUS & ST_PR) && (Location >= (0xE00 >> 3)))
+ return CRU_PRIVILEGE_VIOLATION;
+ #endif
+ Value |= read_single_CRU(Location) << 8;
+
+ if ((Offset+Number) > 16)
+ {
+ /* Read next 8 bits */
+ Location = (Location + 1) & rCRUAddrMask;
+ #if HAS_PRIVILEGE
+ if ((I.STATUS & ST_PR) && (Location >= (0xE00 >> 3)))
+ return CRU_PRIVILEGE_VIOLATION;
+ #endif
+ Value |= read_single_CRU(Location) << 16;
+ }
+ }
+
+ /* Allow for Offset */
+ Value >>= Offset;
+
+ /* Mask out what we want */
+ Value &= BitMask[Number];
+
+ /* And update */
+ return Value;
+ }
+
+/*****************************************************************************/
+
+#if HAS_MAPPING
+/* load a map file from memory */
+static void load_map_file(UINT16 src_addr, int src_map_file, int dst_file)
+{
+ int i;
+
+
+ /* load mapped address into the memory address register */
+ if ((src_map_file == 0) && (src_addr >= 0xf800))
+ { /* intercept TPCS and CPU ROM */
+ if (src_addr < 0xfc00)
+ /* TPCS */
+ I.mapper_address_latch = 0x1f0000+src_addr;
+ else
+ /* CPU ROM */
+ I.mapper_address_latch = 0x1f0000+src_addr; /* hack... */
+ }
+ else if (! I.mapping_on)
+ {
+ I.mapper_address_latch = src_addr;
+}
+ else
+ {
+ int map_index;
+
+ if (src_addr <= I.map_files[src_map_file].limit[0])
+ map_index = 0;
+ else if (src_addr <= I.map_files[src_map_file].limit[1])
+ map_index = 1;
+ else if (src_addr <= I.map_files[src_map_file].limit[2])
+ map_index = 2;
+ else
+ {
+ if ((! I.reset_maperr) && ! (I.error_interrupt_register & EIR_MAPERR))
+ {
+ I.error_interrupt_register |= EIR_MAPERR;
+ write_inhibit = 1;
+ }
+ I.mapper_address_latch = src_addr;
+ map_index = -1;
+ }
+ if (map_index != -1)
+ I.mapper_address_latch = I.map_files[src_map_file].bias[map_index]+src_addr;
+ }
+
+
+ for (i=0; i<3; i++)
+{
+ I.map_files[dst_file].L[i] = program_read_word_16be(I.mapper_address_latch) & 0xffe0;
+ I.map_files[dst_file].limit[i] = (I.map_files[dst_file].L[i] ^ 0xffe0) | 0x001f;
+ I.mapper_address_latch = (I.mapper_address_latch+2) & 0x1fffff;
+ I.map_files[dst_file].B[i] = program_read_word_16be(I.mapper_address_latch);
+ I.map_files[dst_file].bias[i] = ((unsigned int) I.map_files[dst_file].B[i]) << 5;
+ I.mapper_address_latch = (I.mapper_address_latch+2) & 0x1fffff;
+ }
+}
+#endif
+
+/* contextswitch : performs a BLWP, i.e. load PC, WP, and save old PC, old WP and ST... */
+static void contextswitch(UINT16 addr)
+{
+ UINT16 oldWP, oldpc;
+
+ /* save old state */
+ oldWP = I.WP;
+ oldpc = I.PC;
+
+ /* load vector */
+ I.WP = readword(addr) & ~1;
+ I.PC = readword(addr+2) & ~1;
+
+ /* write old state to regs */
+ WRITEREG(R13, oldWP);
+ WRITEREG(R14, oldpc);
+ setstat();
+ WRITEREG(R15, I.STATUS);
+}
+
+#if HAS_MAPPING || HAS_PRIVILEGE
+
+/* priviledged context switch, that occurs after a reset, interrupt or XOP:
+we enter priviledged mode and select map file 0 before doing the context switch */
+/* For CPU that have no priviledge support, contextswitchX would behave
+identically to contextswitch, so we can call contextswitch in all cases. */
+static void contextswitchX(UINT16 addr)
+{
+ UINT16 oldWP, oldpc, oldST;
+
+ /* save old state */
+ oldWP = I.WP;
+ oldpc = I.PC;
+ setstat();
+ oldST = I.STATUS;
+
+ /* enter priviledged mode and select map file 0 */
+ #if HAS_PRIVILEGE
+ I.STATUS &= ~ ST_PR;
+ #endif
+ #if HAS_MAPPING
+ I.STATUS &= ~ ST_MF;
+ #endif
+ getstat();
+
+ /* load vector */
+ I.WP = readword(addr) & ~1;
+ I.PC = readword(addr+2) & ~1;
+
+ /* write old state to regs */
+ WRITEREG(R13, oldWP);
+ WRITEREG(R14, oldpc);
+ WRITEREG(R15, oldST);
+}
+
+#endif
+
+/*
+ * decipheraddr : compute and return the effective adress in word instructions.
+ *
+ * NOTA : the LSBit is always ignored in word adresses,
+ * but we do not set it to 0 because of XOP...
+ */
+static UINT16 decipheraddr(UINT16 opcode)
+{
+ register UINT16 ts = opcode & 0x30;
+ register UINT16 reg = opcode & 0xF;
+
+ reg += reg;
+
+ if (ts == 0)
+ /* Rx */
+ return(reg + I.WP);
+ else if (ts == 0x10)
+ { /* *Rx */
+ CYCLES(0, 4, 1);
+ return(readword(reg + I.WP));
+ }
+ else if (ts == 0x20)
+ {
+ register UINT16 imm;
+
+ imm = fetch();
+
+ if (reg)
+ { /* @>xxxx(Rx) */
+ CYCLES(1, 8, 3);
+ return(readword(reg + I.WP) + imm);
+ }
+ else
+ { /* @>xxxx */
+ CYCLES(3, 8, 1);
+ return(imm);
+ }
+ }
+ else /*if (ts == 0x30)*/
+ { /* *Rx+ */
+ register UINT16 response;
+
+ reg += I.WP; /* reg now contains effective address */
+
+ CYCLES(1, 8, 3);
+
+ response = readword(reg);
+ writeword(reg, response+2); /* we increment register content */
+ return(response);
+ }
+}
+
+/* decipheraddrbyte : compute and return the effective adress in byte instructions. */
+static UINT16 decipheraddrbyte(UINT16 opcode)
+{
+ register UINT16 ts = opcode & 0x30;
+ register UINT16 reg = opcode & 0xF;
+
+ reg += reg;
+
+ if (ts == 0)
+ /* Rx */
+ return(reg + I.WP);
+ else if (ts == 0x10)
+ { /* *Rx */
+ CYCLES(0, 4, 1);
+ return(readword(reg + I.WP));
+ }
+ else if (ts == 0x20)
+ {
+ register UINT16 imm;
+
+ imm = fetch();
+
+ if (reg)
+ { /* @>xxxx(Rx) */
+ CYCLES(1, 8, 3);
+ return(readword(reg + I.WP) + imm);
+ }
+ else
+ { /* @>xxxx */
+ CYCLES(3, 8, 1);
+ return(imm);
+ }
+ }
+ else /*if (ts == 0x30)*/
+ { /* *Rx+ */
+ register UINT16 response;
+
+ reg += I.WP; /* reg now contains effective address */
+
+ CYCLES(1, 6, 3);
+
+ response = readword(reg);
+ writeword(reg, response+1); /* we increment register content */
+ return(response);
+ }
+}
+
+
+/*************************************************************************/
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+ /* TI990/10 generates an error interrupt */
+ /* timings are unknown */
+ #define HANDLE_ILLEGAL \
+ { \
+ I.error_interrupt_register |= EIR_ILLOP; \
+ if (I.error_interrupt_callback) \
+ (*I.error_interrupt_callback)(1); \
+ }
+#elif TMS99XX_MODEL <= TMS9989_ID
+ /* TMS9900/TMS9980 merely ignore the instruction */
+ #define HANDLE_ILLEGAL TMS99XX_ICOUNT -= 6
+#elif TMS99XX_MODEL == TMS9995_ID
+ /* TMS9995 generates a MID interrupt */
+ #define HANDLE_ILLEGAL \
+ { \
+ I.MID_flag = 1; \
+ contextswitchX(0x0008); \
+ I.STATUS = (I.STATUS & 0xFE00) | 0x1; \
+ I.disable_interrupt_recognition = 1; \
+ }
+#else
+#define HANDLE_ILLEGAL
+#warning "don't know"
+#endif
+
+#if HAS_PRIVILEGE
+ #if (TMS99XX_MODEL == TI990_10_ID)
+ /* TI990/10 generates an error interrupt */
+ /* timings are unknown */
+ #define HANDLE_PRIVILEGE_VIOLATION \
+ { \
+ I.error_interrupt_register |= EIR_PRIVOP; \
+ if (I.error_interrupt_callback) \
+ (*I.error_interrupt_callback)(1); \
+ }
+ #else
+ #define HANDLE_PRIVILEGE_VIOLATION
+ #warning "don't know"
+ #endif
+#endif
+
+/*==========================================================================
+ Illegal instructions >0000->01FF (not for 9989 and later)
+ >0C00->0FFF (not for 990/12 and 99110)
+============================================================================*/
+
+static void illegal(UINT16 opcode)
+{
+ HANDLE_ILLEGAL;
+}
+
+
+#if 0 /* ti990/12 only */
+/*==========================================================================
+ Additionnal instructions, >0000->002F
+ Additionnal single-register instruction, >0030->003F
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e |
+ | o p c o d e | reg # |
+ ---------------------------------
+
+============================================================================*/
+static void h0000(UINT16 opcode)
+{
+ if (opcode >= 0x30)
+ { /* STPC STore Program Counter */
+
+ }
+ else
+ {
+ switch (opcode /*& 0x3F*/)
+ {
+ case 0x1C: /* SRAM */
+ /* SRAM -- Shift Right Arithmetic Multiple precision */
+ case 0x1D: /* SLAM */
+ /* SLAM -- Shift Left Arithmetic Multiple precision */
+ case 0x1E:
+ /* RTO --- Right Test for Ones */
+ case 0x1F:
+ /* LTO --- Left Test for Ones */
+ case 0x20:
+ /* CNTO -- CouNT Ones */
+ case 0x21:
+ /* SLSL -- Search LiSt Logical address */
+ case 0x22:
+ /* SLSP -- Search LiSt Physical address */
+ case 0x23:
+ /* BDC --- Binary to Decimal ascii Conversion */
+ case 0x24:
+ /* DBC --- Decimal to Binary ascii Conversion */
+ case 0x25:
+ /* SWPM -- SWaP Multiple precision */
+ case 0x26:
+ /* XORM -- eXclusive OR Multiple precision */
+ case 0x27:
+ /* ORM --- OR Multiple precision */
+ case 0x28:
+ /* ANDM -- AND Multiple precision */
+ case 0x29: /* SM */
+ /* SM ---- Subtract Multiple precision integer */
+ case 0x2A: /* AM */
+ /* AM ---- Add Multiple precision integer */
+ case 0x2B:
+ /* MOVA -- MOVe Address */
+ case 0x2D:
+ /* EMD --- Execute Micro-Diagnostics */
+ case 0x2E:
+ /* EINT -- Enable INTerrupts */
+ case 0x2F:
+ /* DINT -- Disable INTerrupts */
+
+ break;
+
+ default:
+ HANDLE_ILLEGAL;
+ break;
+ }
+}
+}
+#endif
+
+
+#if HAS_9995_OPCODES
+/*==========================================================================
+ Additionnal single-register instructions, >0040->00FF
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e | reg # |
+ ---------------------------------
+
+tms9989 and later : LST, LWP
+============================================================================*/
+static void h0040(UINT16 opcode)
+{
+ register UINT16 addr;
+
+ addr = opcode & 0xF;
+ addr = ((addr + addr) + I.WP) & ~1;
+
+ switch ((opcode & 0xF0) >> 4)
+ {
+ case 8: /* LST */
+ /* LST --- Load STatus register */
+ /* ST = *Reg */
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ I.STATUS = (I.STATUS & 0x01DF) | (readword(addr) & 0xFE20);
+ else
+ I.STATUS = readword(addr);
+ #else
+ I.STATUS = readword(addr);
+ #endif
+ getstat(); /* set last_parity */
+ break;
+
+ case 9: /* LWP */
+ /* LWP --- Load Workspace Pointer */
+ /* WP = *Reg */
+ I.WP = readword(addr) & ~1;
+ break;
+
+#if 0 /* 990/12 opcodes */
+ case 4:
+ /* CS ---- Compare Strings */
+ case 5:
+ /* SEQB -- Search string for EQual Byte */
+ case 6:
+ /* MOVS -- MOVe String */
+ case 7:
+ /* LIM --- Load Interrupt Mask */
+
+ case 10:
+ /* LCS --- Load writable Control Store */
+
+ case 11: /* BLSK */
+ /* BLSK -- Branch immediate and push Link to StacK */
+
+ case 12:
+ /* MVSR -- MoVe String Reverse */
+ case 13:
+ /* MVSK -- MoVe string from StacK */
+ case 14:
+ /* POPS -- POP String from stack */
+ case 15:
+ /* PSHS -- PuSH String to stack */
+
+ break;
+#endif
+
+ default:
+ HANDLE_ILLEGAL;
+ break;
+ }
+}
+
+
+/*==========================================================================
+ Additionnal single-operand instructions, >0100->01FF
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e |TS | S |
+ ---------------------------------
+
+tms9989 and later : DIVS, MPYS
+tms99xxx : BIND
+============================================================================*/
+static void h0100(UINT16 opcode)
+{
+ register UINT16 src;
+#if HAS_MAPPING
+ int src_map = (opcode & 0x0030) ? I.cur_src_map : I.cur_map;
+#endif
+
+ src = decipheraddr(opcode) & ~1;
+
+ switch ((opcode & 0xC0) >> 6)
+ {
+#if HAS_BIND_OPCODE
+ case 1: /* BIND */
+ /* BIND -- Branch INDirect */
+ I.PC = readwordX(src, src_map) & ~1;
+ CYCLES(Mooof!, Mooof!, 4 /*don't know*/);
+ break;
+#endif
+
+ case 2: /* DIVS */
+ /* DIVS -- DIVide Signed */
+ /* R0 = (R0:R1)/S R1 = (R0:R1)%S */
+ {
+ INT16 d = readwordX(src, src_map);
+ INT32 divq = (READREG(R0) << 16) | READREG(R1);
+ INT32 q = divq/d;
+
+ if ((q < -32768L) || (q > 32767L))
+ {
+ I.STATUS |= ST_OV;
+ CYCLES(Mooof!, Mooof!, 10);
+ }
+ else
+ {
+ I.STATUS &= ~ST_OV;
+ setst_lae(q);
+ WRITEREG(R0, q);
+ WRITEREG(R1, divq%d);
+ /* tms9995 : 33 is the worst case */
+ CYCLES(Mooof!, Mooof!, 33);
+ }
+ }
+ break;
+
+ case 3: /* MPYS */
+ /* MPYS -- MultiPlY Signed */
+ /* Results: R0:R1 = R0*S */
+ {
+ INT32 prod = ((INT32) (INT16) readwordX(src, src_map));
+ prod = prod*((INT32) (INT16) READREG(R0));
+
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
+ if (prod > 0)
+ I.STATUS |= (ST_LGT | ST_AGT);
+ else if (prod < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ WRITEREG(R0, prod >> 16);
+ WRITEREG(R1, prod);
+ }
+ CYCLES(Mooof!, Mooof!, 25);
+ break;
+
+#if 0 /* Origin unknown */
+ case 0: /* EVAD */
+ /* EVAD -- EValuate ADdress instruction */
+
+ break;
+#endif
+
+ default:
+ HANDLE_ILLEGAL;
+ break;
+ }
+}
+#endif
+
+
+/*==========================================================================
+ Immediate, Control instructions, >0200->03FF
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e |0| reg # |
+ ---------------------------------
+
+ LI, AI, ANDI, ORI, CI, STWP, STST, LIMI, LWPI, IDLE, RSET, RTWP, CKON, CKOF, LREX
+systems with memory mapper: LMF
+============================================================================*/
+static void h0200(UINT16 opcode)
+{
+ register UINT16 addr;
+ register UINT16 value; /* used for anything */
+
+ addr = opcode & 0xF;
+ addr = ((addr + addr) + I.WP) & ~1;
+
+ #if HAS_MAPPING
+ if ((opcode >= 0x0320) && (opcode < 0x0340))
+ { /* LMF */
+ /* LMF --- Load memory Map File */
+ /* Used by the memory mapper on ti990/10 with mapping option, ti990/12, and the TIM99610
+ mapper chip to be associated with tms99000.
+ Syntax: "LMF Rn,m" loads map file m (0 or 1) with six words of memory, starting at address
+ specified in workspace register Rn (0 thru 15). */
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ {
+ HANDLE_PRIVILEGE_VIOLATION
+ return;
+ }
+ #endif
+
+ /* read address pointer */
+ addr = readword(addr);
+
+ load_map_file(addr, I.cur_map, (opcode & 0x10) ? 1 : 0);
+
+ CYCLES(3, Mooof!, Mooof!);
+ return;
+ }
+#endif
+
+ #if BETTER_0200_DECODING
+ /* better instruction decoding on ti990/10 */
+ if (opcode & 0x10)
+ {
+ HANDLE_ILLEGAL;
+ return;
+ }
+ #elif COMPLETE_0200_DECODING
+ /* full instruction decoding on tms9995 */
+ if (((opcode < 0x2E0) && (opcode & 0x10)) || ((opcode >= 0x2E0) && (opcode & 0x1F)))
+ {
+#if 0
+ /* tms99110 opcode (not supported by 990/12) */
+ if (opcode == 0x0301)
+ { /* CR ---- Compare Reals */
+ }
+ else
+ /* tms99105+tms99110 opcode (not supported by 990/12) */
+ if (opcode == 0x0302)
+ { /* MM ---- Multiply Multiple */
+ }
+ else
+ #endif
+ #if 0 /* ti990/12 only */
+ if (opcode >= 0x03F0)
+ { /* EP ---- Extended Precision */
+ }
+ else
+#endif
+ HANDLE_ILLEGAL;
+ return;
+ }
+#endif
+
+ switch ((opcode & 0x1e0) >> 5)
+ {
+ case 0: /* LI */
+ /* LI ---- Load Immediate */
+ /* *Reg = *PC+ */
+ value = fetch();
+ writeword(addr, value);
+ setst_lae(value);
+ CYCLES(3, 12, 3);
+ break;
+
+ case 1: /* AI */
+ /* AI ---- Add Immediate */
+ /* *Reg += *PC+ */
+ value = fetch();
+ value = setst_add_laeco(readword(addr), value);
+ writeword(addr, value);
+ CYCLES(4, 14, 4);
+ break;
+
+ case 2: /* ANDI */
+ /* ANDI -- AND Immediate */
+ /* *Reg &= *PC+ */
+ value = fetch();
+ value = readword(addr) & value;
+ writeword(addr, value);
+ setst_lae(value);
+ CYCLES(4, 14, 4);
+ break;
+
+ case 3: /* ORI */
+ /* ORI --- OR Immediate */
+ /* *Reg |= *PC+ */
+ value = fetch();
+ value = readword(addr) | value;
+ writeword(addr, value);
+ setst_lae(value);
+ CYCLES(4, 14, 4);
+ break;
+
+ case 4: /* CI */
+ /* CI ---- Compare Immediate */
+ /* status = (*Reg-*PC+) */
+ value = fetch();
+ setst_c_lae(value, readword(addr));
+ CYCLES(6, 14, 4);
+ break;
+
+ case 5: /* STWP */
+ /* STWP -- STore Workspace Pointer */
+ /* *Reg = WP */
+ writeword(addr, I.WP);
+ CYCLES(2, 8, 3);
+ break;
+
+ case 6: /* STST */
+ /* STST -- STore STatus register */
+ /* *Reg = ST */
+ setstat();
+ writeword(addr, I.STATUS);
+ CYCLES(2, 8, 3);
+ break;
+
+ case 7: /* LWPI */
+ /* LWPI -- Load Workspace Pointer Immediate */
+ /* WP = *PC+ */
+ I.WP = fetch() & ~1;
+ CYCLES(3, 10, 4);
+ break;
+
+ case 8: /* LIMI */
+ /* LIMI -- Load Interrupt Mask Immediate */
+ /* ST&15 |= (*PC+)&15 */
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ {
+ HANDLE_PRIVILEGE_VIOLATION
+ break;
+ }
+#endif
+
+ value = fetch();
+ I.STATUS = (I.STATUS & ~ST_IM) | (value & ST_IM);
+ field_interrupt(); /*IM has been modified.*/
+ CYCLES(3, 16, 5);
+ break;
+
+ case 9: /* LMF is implemented elsewhere - when it is implemented */
+ HANDLE_ILLEGAL;
+ break;
+
+ case 10: /* IDLE */
+ /* IDLE -- IDLE until a reset, interrupt, load */
+ /* The TMS99000 locks until an interrupt happen (like with 68k STOP instruction),
+ and continuously performs a special CRU write (code 2). */
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ {
+ HANDLE_PRIVILEGE_VIOLATION
+ break;
+ }
+ #endif
+ I.IDLE = 1;
+ #if EXTERNAL_INSTRUCTION_DECODING
+ external_instruction_notify(2);
+ #endif
+ if (I.idle_callback)
+ (*I.idle_callback)(1);
+ CYCLES(4, 12, 7);
+ /* we take care of further external_instruction_notify(2); in execute() */
+ break;
+
+ case 12: /* RTWP */
+ /* RTWP -- Return with Workspace Pointer */
+ /* WP = R13, PC = R14, ST = R15 */
+ addr = (I.WP + R13) & ~1;
+ I.WP = readword(addr) & ~1;
+ addr += 2;
+ I.PC = readword(addr) & ~1;
+ addr += 2;
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ I.STATUS = (I.STATUS & 0x01DF) | (readword(addr) & 0xFE20);
+ else
+ I.STATUS = readword(addr);
+ #else
+ I.STATUS = readword(addr);
+ #endif
+ getstat(); /* set last_parity */
+
+ field_interrupt(); /*IM has been modified.*/
+ CYCLES(3, 14, 6);
+ break;
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+
+ case 11: /* RSET */
+ case 13: /* CKON */
+ case 14: /* CKOF */
+ case 15: /* LREX */
+ HANDLE_ILLEGAL; /* These instruction "have been deleted" on the TMS9940 */
+ break;
+
+#else
+
+ case 11: /* RSET */
+ /* RSET -- ReSET */
+ /* Reset the Interrupt Mask, and perform a special CRU write (code 3). */
+ /* The CRU write is supposed to reset external devices. */
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ {
+ HANDLE_PRIVILEGE_VIOLATION
+ break;
+ }
+ #endif
+
+ I.STATUS &= 0xFFF0; /*clear IM.*/
+ field_interrupt(); /*IM has been modified.*/
+
+ #if (TMS99XX_MODEL == TMS9995_ID)
+ /*I.MID_flag = 0;*/ /* not sure about this */
+ #endif
+ #if (TMS99XX_MODEL == TI990_10_ID)
+ I.error_interrupt_register = 0;
+ I.mapping_on = 0;
+
+ I.reset_maperr = 0;
+ I.mapper_cru_read_register = 0;
+ I.latch_control[0] = I.latch_control[1] = I.latch_control[2] = 0;
+
+ I.diaglat = 0;
+ #endif
+
+ #if EXTERNAL_INSTRUCTION_DECODING
+ external_instruction_notify(3);
+ #endif
+
+ #if EXTERNAL_INSTRUCTION_CALLBACK
+ if (I.rset_callback)
+ (*I.rset_callback)();
+ #endif
+
+ CYCLES(5, 12, 7);
+ break;
+
+#if EXTERNAL_INSTRUCTION_DECODING
+
+ case 13: /* CKON */
+ case 14: /* CKOF */
+ case 15: /* LREX */
+ /* CKON -- ClocK ON */
+ /* Perform a special CRU write (code 5). */
+ /* An external circuitery could, for instance, enable the line clock interrupt (100Hz or 120Hz, depending on the electrical alimentation frequency). */
+ /* CKOF -- ClocK OFf */
+ /* Perform a special CRU write (code 6). */
+ /* An external circuitery could, for instance, disable the line clock interrupt. */
+ /* LREX -- Load or REstart eXecution */
+ /* Perform a special CRU write (code 7). */
+ /* An external circuitery could, for instance, activate the LOAD* line,
+ causing a non-maskable LOAD interrupt (vector -1). */
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ {
+ HANDLE_PRIVILEGE_VIOLATION
+ break;
+ }
+ #endif
+
+ external_instruction_notify((opcode & 0x00e0) >> 5);
+
+ #if EXTERNAL_INSTRUCTION_CALLBACK
+ #warning "todo..."
+ #endif
+
+ CYCLES(Mooof!, 12, 7);
+ break;
+
+#elif EXTERNAL_INSTRUCTION_CALLBACK
+
+ case 13: /* CKON */
+ case 14: /* CKOF */
+ /* CKON -- ClocK ON */
+ /* Enable the line clock interrupt (100Hz or 120Hz, depending on the electrical alimentation frequency). */
+ /* CKOF -- ClocK OFf */
+ /* Disable the line clock interrupt. */
+ /* We use a callback because the line clock is implemented in machine
+ code, not in the CPU core. */
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ {
+ HANDLE_PRIVILEGE_VIOLATION
+ break;
+ }
+ #endif
+
+ if (I.ckon_ckof_callback)
+ (*I.ckon_ckof_callback)((opcode & 0x0020) ? 1 : 0);
+
+
+ CYCLES(5, Mooof!, Mooof!);
+ break;
+
+ case 15: /* LREX */
+ /* LREX -- Load or REstart eXecution */
+ /* Trigger a LOAD interrupt (vector -1). (We use a callback, and I
+ have forgotten the reason why.) */
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ {
+ HANDLE_PRIVILEGE_VIOLATION
+ break;
+ }
+ #endif
+
+ if (I.lrex_callback)
+ (*I.lrex_callback)();
+
+ CYCLES(6, Mooof!, Mooof!);
+ break;
+
+#else
+
+ #warning "Should not happen..."
+
+#endif
+
+#endif
+ }
+}
+
+
+/*==========================================================================
+ Single-operand instructions, >0400->07FF
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e |TS | S |
+ ---------------------------------
+
+ BLWP, B, X, CLR, NEG, INV, INC, INCT, DEC, DECT, BL, SWPB, SETO, ABS
+systems with memory mapper: LDD, LDS
+============================================================================*/
+static void h0400(UINT16 opcode)
+{
+ register UINT16 addr = decipheraddr(opcode) & ~1;
+ register UINT16 value; /* used for anything */
+#if HAS_MAPPING
+ int src_map = (opcode & 0x0030) ? I.cur_src_map : I.cur_map;
+#endif
+
+ switch ((opcode & 0x3C0) >> 6)
+ {
+ case 0: /* BLWP */
+ /* BLWP -- Branch and Link with Workspace Pointer */
+ /* Result: WP = *S+, PC = *S */
+ /* New R13=old WP, New R14=Old PC, New R15=Old ST */
+ contextswitch(addr);
+ CYCLES(3, 26, 11);
+ I.disable_interrupt_recognition = 1;
+ break;
+ case 1: /* B */
+ /* B ----- Branch */
+ /* PC = S */
+#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID))
+ (void) readwordX(addr, src_map);
+#endif
+ I.PC = addr;
+ CYCLES(2, 8, 3);
+ break;
+ case 2: /* X */
+ /* X ----- eXecute */
+ /* Executes instruction *S */
+ execute(readwordX(addr, src_map));
+ /* On tms9900, the X instruction actually takes 8 cycles, but we gain 2 cycles on the next
+ instruction, as we don't need to fetch it. */
+ CYCLES(1, 6, 2);
+ break;
+ case 3: /* CLR */
+ /* CLR --- CLeaR */
+ /* *S = 0 */
+#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID))
+ (void) readwordX(addr, src_map);
+#endif
+ writewordX(addr, 0, src_map);
+ CYCLES(2, 10, 3);
+ break;
+ case 4: /* NEG */
+ /* NEG --- NEGate */
+ /* *S = -*S */
+ value = - (INT16) readwordX(addr, src_map);
+ if (value)
+ I.STATUS &= ~ ST_C;
+ else
+ I.STATUS |= ST_C;
+
+ #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+ if (value & 0x0FFF)
+ I.STATUS &= ~ ST_DC;
+ else
+ I.STATUS |= ST_DC;
+#endif
+
+ setst_laeo(value);
+ writewordX(addr, value, src_map);
+ CYCLES(3, 12, 3);
+ break;
+ case 5: /* INV */
+ /* INV --- INVert */
+ /* *S = ~*S */
+ value = ~ readwordX(addr, src_map);
+ writewordX(addr, value, src_map);
+ setst_lae(value);
+ CYCLES(2, 10, 3);
+ break;
+ case 6: /* INC */
+ /* INC --- INCrement */
+ /* (*S)++ */
+ value = setst_add_laeco(readwordX(addr, src_map), 1);
+ writewordX(addr, value, src_map);
+ CYCLES(2, 10, 3);
+ break;
+ case 7: /* INCT */
+ /* INCT -- INCrement by Two */
+ /* (*S) +=2 */
+ value = setst_add_laeco(readwordX(addr, src_map), 2);
+ writewordX(addr, value, src_map);
+ CYCLES(2, 10, 3);
+ break;
+ case 8: /* DEC */
+ /* DEC --- DECrement */
+ /* (*S)-- */
+ value = setst_sub_laeco(readwordX(addr, src_map), 1);
+ writewordX(addr, value, src_map);
+ CYCLES(2, 10, 3);
+ break;
+ case 9: /* DECT */
+ /* DECT -- DECrement by Two */
+ /* (*S) -= 2 */
+ value = setst_sub_laeco(readwordX(addr, src_map), 2);
+ writewordX(addr, value, src_map);
+ CYCLES(2, 10, 3);
+ break;
+ case 10: /* BL */
+ /* BL ---- Branch and Link */
+ /* IP=S, R11=old IP */
+#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID))
+ (void) readwordX(addr, src_map);
+#endif
+ WRITEREG(R11, I.PC);
+ I.PC = addr;
+ CYCLES(3, 12, 5);
+ break;
+ case 11: /* SWPB */
+ /* SWPB -- SWaP Bytes */
+ /* *S = swab(*S) */
+ value = readwordX(addr, src_map);
+ value = logical_right_shift(value, 8) | (value << 8);
+ writewordX(addr, value, src_map);
+ CYCLES(2, 10, 13);
+ break;
+ case 12: /* SETO */
+ /* SETO -- SET to Ones */
+ /* *S = #$FFFF */
+#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID))
+ (void) readwordX(addr, src_map);
+#endif
+ writewordX(addr, 0xFFFF, src_map);
+ CYCLES(2, 10, 3);
+ break;
+ case 13: /* ABS */
+ /* ABS --- ABSolute value */
+ /* *S = |*S| */
+ /* clearing ST_C seems to be necessary, although ABS will never set it. */
+#if (TMS99XX_MODEL <= TMS9985_ID)
+
+ /* ti990/10 and tms9900/tms9980 only write the result if it has changed */
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
+
+ #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+ /* I guess ST_DC is cleared here, too*/
+ I.STATUS &= ~ ST_DC;
+#endif
+
+ value = readwordX(addr, src_map);
+
+ CYCLES(5, 12, Mooof!);
+
+ if (((INT16) value) > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (((INT16) value) < 0)
+ {
+ I.STATUS |= ST_LGT;
+ if (value == 0x8000)
+ I.STATUS |= ST_OV;
+
+ #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+ if (! (value & 0x0FFF))
+ I.STATUS |= ST_DC;
+#endif
+
+ writewordX(addr, - ((INT16) value), src_map);
+ CYCLES(0, 2, Mooof!);
+ }
+ else
+ I.STATUS |= ST_EQ;
+
+ break;
+
+#else
+
+ /* tms9995 always write the result */
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
+ value = readwordX(addr, src_map);
+
+ CYCLES(Mooof!, Mooof!, 3);
+ if (((INT16) value) > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (((INT16) value) < 0)
+ {
+ I.STATUS |= ST_LGT;
+ if (value == 0x8000)
+ I.STATUS |= ST_OV;
+ value = - ((INT16) value);
+ }
+ else
+ I.STATUS |= ST_EQ;
+
+ writewordX(addr, value, src_map);
+
+ break;
+
+#endif
+
+
+#if HAS_MAPPING
+ /* Used by the memory mapper on ti990/10 with mapping option, ti990/12, and the TIM99610
+ mapper chip to be associated with tms99000. */
+ /* These opcode allow access to another page without the need of switching a page someplace. */
+ /* Note that, if I read the 990/10 schematics correctly, two consecutive LDS or LDD would
+ cause some trouble. */
+ case 14: /* LDS */
+ /* LDS --- Long Distance Source */
+
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ {
+ HANDLE_PRIVILEGE_VIOLATION
+ break;
+ }
+ #endif
+
+ load_map_file(addr, src_map, 2);
+ lds_flag = 1;
+ I.disable_interrupt_recognition = 1;
+ break;
+ case 15: /* LDD */
+ /* LDD --- Long Distance Destination */
+ #if HAS_PRIVILEGE
+ if (I.STATUS & ST_PR)
+ {
+ HANDLE_PRIVILEGE_VIOLATION
+ break;
+ }
+ #endif
+
+ load_map_file(addr, src_map, 2);
+ ldd_flag = 1;
+ I.disable_interrupt_recognition = 1;
+ break;
+
+#else
+
+ default:
+ /* illegal instructions */
+ HANDLE_ILLEGAL;
+ break;
+
+#endif
+ }
+}
+
+
+/*==========================================================================
+ Shift instructions, >0800->0BFF
+ --------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e | C | W |
+ ---------------------------------
+
+ SRA, SRL, SLA, SRC
+============================================================================*/
+static void h0800(UINT16 opcode)
+{
+ register UINT16 addr;
+ register UINT16 cnt = (opcode & 0xF0) >> 4;
+ register UINT16 value;
+
+ addr = (opcode & 0xF);
+ addr = ((addr+addr) + I.WP) & ~1;
+
+ CYCLES(3, 12, 5);
+
+ if (cnt == 0)
+ {
+ CYCLES(2, 8, 2);
+
+ cnt = READREG(R0) & 0xF;
+
+ if (cnt == 0)
+ cnt = 16;
+ }
+
+ CYCLES(cnt, cnt+cnt, cnt);
+
+ switch ((opcode & 0x300) >> 8)
+ {
+ case 0: /* SRA */
+ /* SRA --- Shift Right Arithmetic */
+ /* *W >>= C (*W is filled on the left with a copy of the sign bit) */
+ value = setst_sra_laec(readword(addr), cnt);
+ writeword(addr, value);
+ break;
+ case 1: /* SRL */
+ /* SRL --- Shift Right Logical */
+ /* *W >>= C (*W is filled on the left with 0) */
+ value = setst_srl_laec(readword(addr), cnt);
+ writeword(addr, value);
+ break;
+ case 2: /* SLA */
+ /* SLA --- Shift Left Arithmetic */
+ /* *W <<= C */
+ value = setst_sla_laeco(readword(addr), cnt);
+ writeword(addr, value);
+ break;
+ case 3: /* SRC */
+ /* SRC --- Shift Right Circular */
+ /* *W = rightcircularshift(*W, C) */
+ value = setst_src_laec(readword(addr), cnt);
+ writeword(addr, value);
+ break;
+ }
+}
+
+
+#if 0 /* 990/12 opcodes */
+/*==========================================================================
+ Additionnal instructions, >0C00->0C0F
+ Additionnal single-register instructions, >0C10->0C3F
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e |
+ | o p c o d e | reg # |
+ ---------------------------------
+
+============================================================================*/
+static void h0c00(UINT16 opcode)
+{
+ if (opcode & 0x30)
+ {
+ switch ((opcode & 0x30) >> 4)
+ {
+ case 1:
+ /* INSF -- INSert Field */
+ break;
+ case 2:
+ /* XV ---- eXtract Value */
+ break;
+ case 3:
+ /* XF ---- eXtract Field */
+ break;
+ }
+ }
+ else
+ {
+ switch (opcode & 0x0F)
+ {
+ /* floating point instructions */
+ case 0:
+ /* CRI --- Convert Real to Integer */
+ break;
+ case 2:
+ /* NEGR -- NEGate Real */
+ break;
+ case 4:
+ /* CRE --- Convert Real to Extended integer */
+ break;
+ case 6:
+ /* CER --- Convert Extended integer to Real */
+ break;
+
+ case 1:
+ /* CDI --- Convert Double precision real to Integer */
+ break;
+ case 3:
+ /* NEGD -- NEGate Double precision real */
+ break;
+ case 5:
+ /* CDE --- Convert Double precision real to Extended integer */
+ break;
+ case 7:
+ /* CED --- Convert Extended integer to Double precision real */
+ break;
+
+ case 8:
+ /* NRM --- NoRMalize */
+ break;
+
+ case 9:
+ /* TMB --- Test Memory Bit */
+ break;
+ case 10:
+ /* TCMB -- Test and Clear Memory Bit */
+ break;
+ case 11:
+ /* TSMB -- Test and Set Memory Bit */
+ break;
+
+ case 12:
+ /* SRJ --- Subtract from Register and Jump */
+ case 13:
+ /* ARJ --- Add to Register and Jump */
+
+ case 14:
+ case 15:
+ /* XIT --- eXIT from floating point interpreter */
+ /* Generated by some compilers, but equivalent to NOP on TI990/12. May have been used
+ by some software floating-point emulators. */
+ break;
+
+ default:
+ HANDLE_ILLEGAL;
+ break;
+ }
+ }
+}
+
+
+/*==========================================================================
+ Additionnal single-operand instructions, >0C40->0DFF
+ >0E40->0FFF
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e |TS | S |
+ ---------------------------------
+
+============================================================================*/
+static void h0c40(UINT16 opcode)
+{
+ register UINT16 src;
+
+#if HAS_MAPPING
+ int src_map = (opcode & 0x0030) ? I.cur_src_map : I.cur_map;
+#endif
+
+ src = decipheraddr(opcode) & ~1;
+
+ switch ((opcode & 0x03C0) >> 6)
+ {
+ case 1:
+ /* AR ---- Add Real */
+ break;
+ case 2:
+ /* CIR --- Convert Integer to Real */
+ break;
+ case 3:
+ /* SR ---- Subtract Real */
+ break;
+ case 4:
+ /* MR ---- Multiply Real */
+ break;
+ case 5:
+ /* DR ---- Divide Real */
+ break;
+ case 6:
+ /* LR ---- Load Real */
+ break;
+ case 7:
+ /* STR --- STore Real */
+ break;
+ case 9:
+ /* AD ---- Add Double */
+ break;
+ case 10:
+ /* CID --- Convert Integer to Double */
+ break;
+ case 11:
+ /* SD ---- Subtract Double */
+ break;
+ case 12:
+ /* MD ---- Multiply Double */
+ break;
+ case 13:
+ /* DD ---- Divide Double */
+ break;
+ case 14:
+ /* LD ---- Load Double */
+ break;
+ case 15:
+ /* SD ---- Store Double */
+ break;
+ default:
+ HANDLE_ILLEGAL;
+ break;
+ }
+}
+
+/*==========================================================================
+ Additionnal single-register instructions, >0E00->0E3F
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e | reg # |
+ ---------------------------------
+
+============================================================================*/
+static void h0e00(UINT16 opcode)
+{
+ switch ((opcode & 0x30) >> 4)
+ {
+ case 1:
+ /* IOF --- Invert Order of Field */
+ break;
+ case 1:
+ /* SNEB -- Search string for Not Equal Byte */
+ break;
+ case 2:
+ /* CRC --- Cyclic Redundancy Code calculation */
+ break;
+ case 3:
+ /* TS ---- Translate String */
+ break;
+ }
+}
+#endif
+
+
+/*==========================================================================
+ Jump, CRU bit instructions, >1000->1FFF
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | o p c o d e | signed offset |
+ ---------------------------------
+
+ JMP, JLT, JLE, JEQ, JHE, JGT, JNE, JNC, JOC, JNO, JL, JH, JOP
+ SBO, SBZ, TB
+============================================================================*/
+static void h1000(UINT16 opcode)
+{
+ /* we convert 8 bit signed word offset to a 16 bit effective word offset. */
+ register INT16 offset = ((INT8) opcode);
+
+
+ switch ((opcode & 0xF00) >> 8)
+ {
+ case 0: /* JMP */
+ /* JMP --- unconditional JuMP */
+ /* PC += offset */
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ break;
+ case 1: /* JLT */
+ /* JLT --- Jump if Less Than (arithmetic) */
+ /* if (A==0 && EQ==0), PC += offset */
+ if (! (I.STATUS & (ST_AGT | ST_EQ)))
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 2: /* JLE */
+ /* JLE --- Jump if Lower or Equal (logical) */
+ /* if (L==0 || EQ==1), PC += offset */
+ if ((! (I.STATUS & ST_LGT)) || (I.STATUS & ST_EQ))
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 3: /* JEQ */
+ /* JEQ --- Jump if EQual */
+ /* if (EQ==1), PC += offset */
+ if (I.STATUS & ST_EQ)
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 4: /* JHE */
+ /* JHE --- Jump if Higher or Equal (logical) */
+ /* if (L==1 || EQ==1), PC += offset */
+ if (I.STATUS & (ST_LGT | ST_EQ))
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 5: /* JGT */
+ /* JGT --- Jump if Greater Than (arithmetic) */
+ /* if (A==1), PC += offset */
+ if (I.STATUS & ST_AGT)
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 6: /* JNE */
+ /* JNE --- Jump if Not Equal */
+ /* if (EQ==0), PC += offset */
+ if (! (I.STATUS & ST_EQ))
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 7: /* JNC */
+ /* JNC --- Jump if No Carry */
+ /* if (C==0), PC += offset */
+ if (! (I.STATUS & ST_C))
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 8: /* JOC */
+ /* JOC --- Jump On Carry */
+ /* if (C==1), PC += offset */
+ if (I.STATUS & ST_C)
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 9: /* JNO */
+ /* JNO --- Jump if No Overflow */
+ /* if (OV==0), PC += offset */
+ if (! (I.STATUS & ST_OV))
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 10: /* JL */
+ /* JL ---- Jump if Lower (logical) */
+ /* if (L==0 && EQ==0), PC += offset */
+ if (! (I.STATUS & (ST_LGT | ST_EQ)))
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 11: /* JH */
+ /* JH ---- Jump if Higher (logical) */
+ /* if (L==1 && EQ==0), PC += offset */
+ if ((I.STATUS & ST_LGT) && ! (I.STATUS & ST_EQ))
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ break;
+ case 12: /* JOP */
+ /* JOP --- Jump On (odd) Parity */
+ /* if (P==1), PC += offset */
+ {
+ /* Let's set ST_OP. */
+ int i;
+ UINT8 a;
+ a = lastparity;
+ i = 0;
+
+ while (a != 0)
+ {
+ if (a & 1) /* If current bit is set, */
+ i++; /* increment bit count. */
+ a >>= 1U; /* Next bit. */
+ }
+
+ /* Set ST_OP bit. */
+ /*if (i & 1)
+ I.STATUS |= ST_OP;
+ else
+ I.STATUS &= ~ ST_OP;*/
+
+ /* Jump accordingly. */
+ if (i & 1) /*(I.STATUS & ST_OP)*/
+ {
+ I.PC += (offset + offset);
+ CYCLES(3, 10, 3);
+ }
+ else
+ CYCLES(2, 8, 3);
+ }
+
+ break;
+ case 13: /* SBO */
+ /* SBO --- Set Bit to One */
+ /* CRU Bit = 1 */
+ #if HAS_PRIVILEGE
+ if (writeCRU((READREG(R12) >> 1) + offset, 1, 1) == CRU_PRIVILEGE_VIOLATION)
+ HANDLE_PRIVILEGE_VIOLATION
+ #else
+ writeCRU((READREG(R12) >> 1) + offset, 1, 1);
+ #endif
+
+ CYCLES(4, 12, 8);
+ break;
+
+ case 14: /* SBZ */
+ /* SBZ --- Set Bit to Zero */
+ /* CRU Bit = 0 */
+ #if HAS_PRIVILEGE
+ if (writeCRU((READREG(R12) >> 1) + offset, 1, 0) == CRU_PRIVILEGE_VIOLATION)
+ HANDLE_PRIVILEGE_VIOLATION
+ #else
+ writeCRU((READREG(R12) >> 1) + offset, 1, 0);
+ #endif
+
+ CYCLES(4, 12, 8);
+ break;
+
+ case 15: /* TB */
+ /* TB ---- Test Bit */
+ /* EQ = (CRU Bit == 1) */
+ #if HAS_PRIVILEGE
+ {
+ int value;
+
+ value = readCRU((READREG(R12)>> 1) + offset, 1);
+ if (value == CRU_PRIVILEGE_VIOLATION)
+ HANDLE_PRIVILEGE_VIOLATION
+ else
+ setst_e(value & 1, 1);
+ }
+ #else
+ setst_e(readCRU((READREG(R12)>> 1) + offset, 1) & 1, 1);
+ #endif
+ CYCLES(5, 12, 8);
+ break;
+ }
+}
+
+
+/*==========================================================================
+ General and One-Register instructions >2000->3FFF
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ---------------------------------
+ | opcode | D |TS | S |
+ ---------------------------------
+
+ COC, CZC, XOR, LDCR, STCR, XOP, MPY, DIV
+tms9940 : DCA, DCS, LIIM
+==========================================================================*/
+
+/* xop, ldcr and stcr are handled elsewhere */
+static void h2000(UINT16 opcode)
+{
+ register UINT16 dest = (opcode & 0x3C0) >> 6;
+ register UINT16 src;
+ register UINT16 value;
+
+#if HAS_MAPPING
+ int src_map = (opcode & 0x0030) ? I.cur_src_map : I.cur_map;
+#endif
+
+ src = decipheraddr(opcode) & ~1;
+ dest = ((dest+dest) + I.WP) & ~1;
+
+ switch ((opcode & 0x1C00) >> 10)
+ {
+ case 0: /* COC */
+ /* COC --- Compare Ones Corresponding */
+ /* status E bit = (S&D == S) */
+ value = readwordX(src, src_map);
+ setst_e(value & readword(dest), value);
+ CYCLES(5, 14, 4);
+ break;
+ case 1: /* CZC */
+ /* CZC --- Compare Zeroes Corresponding */
+ /* status E bit = (S&~D == S) */
+ value = readwordX(src, src_map);
+ setst_e(value & (~ readword(dest)), value);
+ CYCLES(5, 14, 4);
+ break;
+ case 2: /* XOR */
+ /* XOR --- eXclusive OR */
+ /* D ^= S */
+ value = readwordX(src, src_map);
+ value ^= readword(dest);
+ setst_lae(value);
+ writeword(dest,value);
+ CYCLES(3, 14, 4);
+ break;
+ /*case 3:*/ /* XOP is implemented elsewhere */
+ /*case 4:*/ /* LDCR is implemented elsewhere */
+ /*case 5:*/ /* STCR is implemented elsewhere */
+ case 6: /* MPY */
+ /* MPY --- MultiPlY (unsigned) */
+ /* Results: D:D+1 = D*S */
+ /* Note that early TMS9995 reportedly performs an extra dummy read in PC space */
+ {
+ unsigned long prod = ((unsigned long) readwordX(src, src_map));
+ prod = prod * ((unsigned long) readword(dest));
+ writeword(dest, prod >> 16);
+ writeword((dest+2)&0xffff, prod);
+ }
+ /* ti990/10 : from 19 to 35, possibly 19 + (number of bits to 1 in one operand) */
+ CYCLES(35, 52, 23);
+ break;
+ case 7: /* DIV */
+ /* DIV --- DIVide (unsigned) */
+ /* D = D/S D+1 = D%S */
+ {
+ UINT16 d = readwordX(src, src_map);
+ UINT16 hi = readword(dest);
+ unsigned long divq = (((unsigned long) hi) << 16) | readword((dest+2)&0xffff);
+
+ if (d <= hi)
+ {
+ I.STATUS |= ST_OV;
+ CYCLES(4, 16, 6);
+ }
+ else
+ {
+ I.STATUS &= ~ST_OV;
+ writeword(dest, divq/d);
+ writeword((dest+2)&0xffff, divq%d);
+ /* tms9900 : from 92 to 124, possibly 92 + 2*(number of bits to 1 (or 0?) in quotient) */
+ /* tms9995 : 28 is the worst case */
+ /* ti990/10 : from 41 to 58, possibly 41 + (number of bits to 1 (or 0?) in quotient) */
+ CYCLES(41, 92, 28);
+ }
+ }
+ break;
+ }
+}
+
+static void xop(UINT16 opcode)
+{ /* XOP */
+ /* XOP --- eXtended OPeration */
+ /* WP = *(40h+D), PC = *(42h+D) */
+ /* New R13=old WP, New R14=Old IP, New R15=Old ST */
+ /* New R11=S */
+ /* Xop bit set */
+
+ register UINT16 immediate = (opcode & 0x3C0) >> 6;
+ register UINT16 operand;
+
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+ switch (immediate)
+ {
+ case 0: /* DCA */
+ /* DCA --- Decimal Correct Addition */
+ operand = decipheraddrbyte(opcode);
+ {
+ int value = readbyte(operand);
+ int X = (value >> 4) & 0xf;
+ int Y = value & 0xf;
+
+ if (Y >= 10)
+ {
+ Y -= 10;
+ I.STATUS |= ST_DC;
+ X++;
+ }
+ else if (I.STATUS & ST_DC)
+ {
+ Y += 6;
+ }
+
+ if (X >= 10)
+ {
+ X -= 10;
+ I.STATUS |= ST_C;
+ }
+ else if (I.STATUS & ST_C)
+ {
+ X += 6;
+ }
+
+ writebyte(operand, (X << 4) | Y);
+ }
+ break;
+ case 1: /* DCS */
+ /* DCS --- Decimal Correct Substraction */
+ operand = decipheraddrbyte(opcode);
+ {
+ int value = readbyte(operand);
+
+ if (! (I.STATUS & ST_DC))
+ {
+ value += 10;
+ }
+
+ if (! (I.STATUS & ST_C))
+ {
+ value += 10 << 4;
+ }
+
+ I.STATUS ^= ST_DC;
+
+ writebyte(operand, value);
+ }
+ break;
+ case 2: /* LIIM */
+ case 3: /* LIIM */
+ /* LIIM - Load Immediate Interrupt Mask */
+ /* Does the same job as LIMI, with a different opcode format. */
+ /* Note that, unlike TMS9900, the interrupt mask is only 2-bit long. */
+ (void)decipheraddr(opcode); /* dummy decode (personnal guess) */
+
+ I.STATUS = (I.STATUS & ~ST_IM) | (opcode & ST_IM);
+ break;
+ default: /* normal XOP */
+#endif
+
+ /* TODO : emulate 990/10 hardware XOP */
+ operand = decipheraddr(opcode);
+
+ #if ((TMS99XX_MODEL <= TMS9989_ID) && (TMS99XX_MODEL != TI990_10_ID))
+ (void)readword(operand & ~1); /*dummy read (personnal guess)*/
+#endif
+
+ contextswitchX(0x40 + (immediate << 2));
+
+ #if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID))
+ /* The bit is not set on tms9940 */
+ I.STATUS |= ST_X;
+#endif
+
+ WRITEREG(R11, operand);
+ CYCLES(7, 36, 15);
+ I.disable_interrupt_recognition = 1;
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+ break;
+ }
+#endif
+}
+
+/* LDCR and STCR */
+static void ldcr_stcr(UINT16 opcode)
+{
+ register UINT16 cnt = (opcode & 0x3C0) >> 6;
+ register UINT16 addr;
+ int value;
+
+#if HAS_MAPPING
+ int src_map = (opcode & 0x0030) ? I.cur_src_map : I.cur_map;
+#endif
+
+ if (cnt == 0)
+ cnt = 16;
+
+ if (cnt <= 8)
+ addr = decipheraddrbyte(opcode);
+ else
+ addr = decipheraddr(opcode) & ~1;
+
+ if (opcode < 0x3400)
+ { /* LDCR */
+ /* LDCR -- LoaD into CRu */
+ /* CRU R12--CRU R12+D-1 set to S */
+ if (cnt <= 8)
+ {
+#if (TMS99XX_MODEL != TMS9995_ID)
+ value = readbyteX(addr, src_map);
+#else
+ /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */
+ /* this must be because instruction decoding is too complex */
+ value = readwordX(addr & ~1, src_map);
+ if (addr & 1)
+ value &= 0xFF;
+ else
+ value = (value >> 8) & 0xFF;
+#endif
+
+ (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/
+
+ setst_byte_laep(value);
+ }
+ else
+ {
+ value = readwordX(addr, src_map);
+
+ (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/
+
+ setst_lae(value);
+ }
+
+ #if HAS_PRIVILEGE
+ if (writeCRU((READREG(R12) >> 1), cnt, value) == CRU_PRIVILEGE_VIOLATION)
+ HANDLE_PRIVILEGE_VIOLATION
+ #else
+ writeCRU((READREG(R12) >> 1), cnt, value);
+ #endif
+
+ CYCLES(4+cnt, 20 + cnt+cnt, 9 + cnt+cnt);
+ }
+ else
+ { /* STCR */
+ /* STCR -- STore from CRu */
+ /* S = CRU R12--CRU R12+D-1 */
+ if (cnt <= 8)
+ {
+#if (TMS99XX_MODEL != TMS9995_ID)
+ (void)readbyteX(addr, src_map); /*dummy read*/
+
+ (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/
+
+ #if HAS_PRIVILEGE
+ value = readCRU((READREG(R12) >> 1), cnt);
+ if (value == CRU_PRIVILEGE_VIOLATION)
+ HANDLE_PRIVILEGE_VIOLATION
+ else
+ {
+ setst_byte_laep(value);
+ writebyteX(addr, value, src_map);
+ }
+ #else
+ value = readCRU((READREG(R12) >> 1), cnt);
+ setst_byte_laep(value);
+ writebyteX(addr, value, src_map);
+ #endif
+ CYCLES(18+cnt, (cnt != 8) ? 42 : 44, 19 + cnt);
+#else
+ /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */
+ /* this must be because instruction decoding is too complex */
+ int value2 = readwordX(addr & ~1, src_map);
+
+ (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/
+
+ value = readCRU((READREG(R12) >> 1), cnt);
+ setst_byte_laep(value);
+
+ if (addr & 1)
+ writewordX(addr & ~1, (value & 0x00FF) | (value2 & 0xFF00), src_map);
+ else
+ writewordX(addr & ~1, (value2 & 0x00FF) | ((value << 8) & 0xFF00), src_map);
+
+ CYCLES(Mooof!, Mooof!, 19 + cnt);
+#endif
+ }
+ else
+ {
+ (void)readwordX(addr, src_map); /*dummy read*/
+
+ (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/
+
+ #if HAS_PRIVILEGE
+ value = readCRU((READREG(R12) >> 1), cnt);
+ if (value == CRU_PRIVILEGE_VIOLATION)
+ HANDLE_PRIVILEGE_VIOLATION
+ else
+ {
+ setst_lae(value);
+ writewordX(addr, value, src_map);
+ }
+ #else
+ value = readCRU((READREG(R12) >> 1), cnt);
+ setst_lae(value);
+ writewordX(addr, value, src_map);
+ #endif
+ CYCLES(24+cnt, (cnt != 16) ? 58 : 60, 27 + cnt);
+ }
+ }
+}
+
+
+/*==========================================================================
+ Two-Operand instructions >4000->FFFF
+ ---------------------------------------------------------------------------
+
+ 0 1 2 3-4 5 6 7+8 9 A B-C D E F
+ ----------------------------------
+ |opcode|B|TD | D |TS | S |
+ ----------------------------------
+
+ SZC, SZCB, S, SB, C, CB, A, AB, MOV, MOVB, SOC, SOCB
+============================================================================*/
+
+/* word instructions */
+static void h4000w(UINT16 opcode)
+{
+ register UINT16 src;
+ register UINT16 dest;
+ register UINT16 value;
+
+#if HAS_MAPPING
+ int src_map = (opcode & 0x0030) ? I.cur_src_map : I.cur_map;
+ int dst_map = (opcode & 0x0c00) ? I.cur_dst_map : I.cur_map;
+#endif
+
+ src = decipheraddr(opcode) & ~1;
+ dest = decipheraddr(opcode >> 6) & ~1;
+
+ value = readwordX(src, src_map);
+
+ switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */
+ {
+ case 2: /* SZC */
+ /* SZC --- Set Zeros Corresponding */
+ /* D &= ~S */
+ value = readwordX(dest, dst_map) & (~ value);
+ setst_lae(value);
+ writewordX(dest, value, dst_map);
+ CYCLES(2, 14, 4);
+ break;
+ case 3: /* S */
+ /* S ----- Subtract */
+ /* D -= S */
+ value = setst_sub_laeco(readwordX(dest, dst_map), value);
+ writewordX(dest, value, dst_map);
+ CYCLES(2, 14, 4);
+ break;
+ case 4: /* C */
+ /* C ----- Compare */
+ /* ST = (D - S) */
+ setst_c_lae(readwordX(dest, dst_map), value);
+ CYCLES(5, 14, 4);
+ break;
+ case 5: /* A */
+ /* A ----- Add */
+ /* D += S */
+ value = setst_add_laeco(readwordX(dest, dst_map), value);
+ writewordX(dest, value, dst_map);
+ CYCLES(2, 14, 4);
+ break;
+ case 6: /* MOV */
+ /* MOV --- MOVe */
+ /* D = S */
+ setst_lae(value);
+ #if ((TMS99XX_MODEL >= TMS9900_ID) && (TMS99XX_MODEL <= TMS9985_ID))
+ /* MOV performs a dummy read with tms9900/9980 (but neither ti990/10 nor tms9995) */
+ (void)readwordX(dest, dst_map);
+#endif
+ writewordX(dest, value, dst_map);
+ CYCLES(1, 14, 3);
+ break;
+ case 7: /* SOC */
+ /* SOC --- Set Ones Corresponding */
+ /* D |= S */
+ value = value | readwordX(dest, dst_map);
+ setst_lae(value);
+ writewordX(dest, value, dst_map);
+ CYCLES(2, 14, 4);
+ break;
+ }
+}
+
+/* byte instruction */
+static void h4000b(UINT16 opcode)
+{
+ register UINT16 src;
+ register UINT16 dest;
+ register UINT16 value;
+
+#if HAS_MAPPING
+ int src_map = (opcode & 0x0030) ? I.cur_src_map : I.cur_map;
+ int dst_map = (opcode & 0x0c00) ? I.cur_dst_map : I.cur_map;
+#endif
+
+ src = decipheraddrbyte(opcode);
+ dest = decipheraddrbyte(opcode >> 6);
+
+ value = readbyteX(src, src_map);
+
+ switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */
+ {
+ case 2: /* SZCB */
+ /* SZCB -- Set Zeros Corresponding, Byte */
+ /* D &= ~S */
+ value = readbyteX(dest, dst_map) & (~ value);
+ setst_byte_laep(value);
+ writebyteX(dest, value, dst_map);
+ CYCLES(3, 14, 4);
+ break;
+ case 3: /* SB */
+ /* SB ---- Subtract, Byte */
+ /* D -= S */
+ value = setst_subbyte_laecop(readbyteX(dest, dst_map), value);
+ writebyteX(dest, value, dst_map);
+ CYCLES(3, 14, 4);
+ break;
+ case 4: /* CB */
+ /* CB ---- Compare Bytes */
+ /* ST = (D - S) */
+ setst_c_lae(readbyteX(dest, dst_map)<<8, value<<8);
+ lastparity = value;
+ CYCLES(5, 14, 4);
+ break;
+ case 5: /* AB */
+ /* AB ---- Add, Byte */
+ /* D += S */
+ value = setst_addbyte_laecop(readbyteX(dest, dst_map), value);
+ writebyteX(dest, value, dst_map);
+ CYCLES(3, 14, 4);
+ break;
+ case 6: /* MOVB */
+ /* MOVB -- MOVe Bytes */
+ /* D = S */
+ setst_byte_laep(value);
+ #if (TMS99XX_MODEL <= TMS9985_ID)
+ /* On ti990/10 and tms9900, MOVB needs to read destination, because it cannot actually
+ read one single byte. It reads a word, replaces the revelant byte, then write
+ the result. A tms9980 should not need to do so, but still does, because it is just
+ a tms9900 with a 16 to 8 bit multiplexer (instead of a new chip design, like tms9995). */
+ (void)readbyteX(dest, dst_map);
+#endif
+ writebyteX(dest, value, dst_map);
+ CYCLES(3, 14, 3);
+ break;
+ case 7: /* SOCB */
+ /* SOCB -- Set Ones Corresponding, Byte */
+ /* D |= S */
+ value = value | readbyteX(dest, dst_map);
+ setst_byte_laep(value);
+ writebyteX(dest, value, dst_map);
+ CYCLES(3, 14, 4);
+ break;
+ }
+}
+
+
+INLINE void execute(UINT16 opcode)
+{
+#if (! HAS_9995_OPCODES)
+
+ /* tms9900-like instruction set*/
+
+ static void (* jumptable[128])(UINT16) =
+ {
+ &illegal,&h0200,&h0400,&h0400,&h0800,&h0800,&illegal,&illegal,
+ &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
+ &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&xop,&xop,
+ &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&h2000,&h2000,&h2000,&h2000,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b
+ };
+
+ (* jumptable[opcode >> 9])(opcode);
+
+#else
+
+ /* tms9989 and tms9995 include 4 extra instructions, and one additionnal instruction type */
+ /* tms99000 includes yet another additional instruction */
+
+ static void (* jumptable[256])(UINT16) =
+ {
+ &h0040,&h0100,&h0200,&h0200,&h0400,&h0400,&h0400,&h0400,
+ &h0800,&h0800,&h0800,&h0800,&illegal,&illegal,&illegal,&illegal,
+ &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
+ &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
+ &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
+ &h2000,&h2000,&h2000,&h2000,&xop,&xop,&xop,&xop,
+ &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,
+ &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
+ &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b
+ };
+
+ (* jumptable[opcode >> 8])(opcode);
+
+#endif
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void tms99xx_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: tms99xx_set_irq_line(INPUT_LINE_NMI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 0: tms99xx_set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: tms99xx_set_irq_line(1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 2: tms99xx_set_irq_line(2, info->i); break;
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+ case CPUINFO_INT_PC:
+ {
+ const unsigned top = (I.cur_map == 0) ? 0xf800 : 0x10000;
+
+ if ((I.cur_map == 0) && (info->i >= 0x1ff800))
+ /* intercept TPCS and CPU ROM */
+ I.PC = info->i - 0x1f0000;
+ else if (! I.mapping_on)
+ I.PC = (info->i < top) ? info->i : 0;
+ else
+ {
+ if ((info->i >= I.map_files[I.cur_map].bias[0])
+ && (info->i <= (I.map_files[I.cur_map].bias[0]+I.map_files[I.cur_map].limit[0])))
+ I.PC = info->i - I.map_files[I.cur_map].bias[0];
+ else if ((info->i > (I.map_files[I.cur_map].bias[1]+I.map_files[I.cur_map].limit[0]))
+ && (info->i <= (I.map_files[I.cur_map].bias[1]+I.map_files[I.cur_map].limit[1])))
+ I.PC = info->i - I.map_files[I.cur_map].bias[1];
+ else if ((info->i > (I.map_files[I.cur_map].bias[2]+I.map_files[I.cur_map].limit[0]))
+ && (info->i > (I.map_files[I.cur_map].bias[2]+I.map_files[I.cur_map].limit[1]))
+ && (info->i <= (I.map_files[I.cur_map].bias[2]+I.map_files[I.cur_map].limit[2])))
+ I.PC = info->i - I.map_files[I.cur_map].bias[2];
+ else
+ {
+ /*if ((info->i < top)
+ && (info->i > I.map_files[I.cur_map].limit[0])
+ && (info->i > I.map_files[I.cur_map].limit[1])
+ && (info->i > I.map_files[I.cur_map].limit[2]))
+ I.PC = info->i;
+ else*/
+ I.PC = 0;
+ }
+ /*if (info->i >= top)
+ I.PC = 0;*/
+ }
+ I.PC &= 0xfffe;
+ }
+ break;
+#else
+ case CPUINFO_INT_PC:
+#endif
+ case CPUINFO_INT_REGISTER + TMS9900_PC: I.PC = info->i & 0xfffe; break;
+ case CPUINFO_INT_REGISTER + TMS9900_IR: I.IR = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS9900_WP: I.WP = info->i & 0xfffe; break;
+ case CPUINFO_INT_REGISTER + TMS9900_STATUS: I.STATUS = info->i; getstat(); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R0: WRITEREG_DEBUG(R0, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R1: WRITEREG_DEBUG(R1, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R2: WRITEREG_DEBUG(R2, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R3: WRITEREG_DEBUG(R3, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R4: WRITEREG_DEBUG(R4, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R5: WRITEREG_DEBUG(R5, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R6: WRITEREG_DEBUG(R6, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R7: WRITEREG_DEBUG(R7, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R8: WRITEREG_DEBUG(R8, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R9: WRITEREG_DEBUG(R9, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R10: WRITEREG_DEBUG(R10, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R11: WRITEREG_DEBUG(R11, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R12: WRITEREG_DEBUG(R12, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R13: WRITEREG_DEBUG(R13, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R14: WRITEREG_DEBUG(R14, info->i); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R15: WRITEREG_DEBUG(R15, info->i); break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void TMS99XX_GET_INFO(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(I); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6;/*8 with 990/12, 99105, 99110*/break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 10;/*TODO: compute this value*/break;
+
+#if (USE_16_BIT_ACCESSORS)
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+#else
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+#endif
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM:
+#if (TMS99XX_MODEL == TI990_10_ID)
+ /* this CPU has a mapper to expand the address space */
+ info->i = 21;
+#elif (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
+ /* basic 16-bit address bus */
+ info->i = 16;
+#elif (TMS99XX_MODEL == TMS9980_ID)
+ /* 2 address MSBits are unconnected */
+ info->i = 14;
+#else
+ #warning "Please check how many address bits your CPU has."
+ info->i = 16;
+#endif
+ break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO:
+#if (TMS99XX_MODEL == TI990_10_ID)
+ /* 3 MSBs do exist, although they are not connected (don't ask...) */
+ info->i = 15;
+#elif (TMS99XX_MODEL == TMS9900_ID)
+ /* 3 MSBs are external instruction code */
+ info->i = 12;
+#elif (TMS99XX_MODEL == TMS9980_ID)
+ /* 2 bits unused, and 2 MSBs are external instruction code */
+ info->i = 13;
+#elif (TMS99XX_MODEL == TMS9940_ID)
+ /* 9 internal address lines (8 external) */
+ info->i = 9;
+#elif (TMS99XX_MODEL == TMS9995_ID)
+ /* 15-bit address and data bus lines D0-D2 provide the external instruction code */
+ info->i = 15+3;
+#else
+ #warning "I don't know how your processor handles CRU."
+ info->i = 15;
+#endif
+ break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+/* not implemented */
+/* case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = get_irq_line(INPUT_LINE_NMI); break;
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = get_irq_line(0); break;
+ case CPUINFO_INT_INPUT_STATE + 1: info->i = get_irq_line(1); break;
+ case CPUINFO_INT_INPUT_STATE + 2: info->i = get_irq_line(2); break;*/
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+#if (TMS99XX_MODEL == TI990_10_ID)
+ case CPUINFO_INT_PC:
+ if ((I.cur_map == 0) && (I.PC >= 0xf800))
+ /* intercept TPCS and CPU ROM */
+ info->i = 0x1f0000+I.PC;
+ else if (! I.mapping_on)
+ info->i = I.PC;
+ else
+ {
+ int map_index;
+
+ if (I.PC <= I.map_files[I.cur_map].limit[0])
+ map_index = 0;
+ else if (I.PC <= I.map_files[I.cur_map].limit[1])
+ map_index = 1;
+ else if (I.PC <= I.map_files[I.cur_map].limit[2])
+ map_index = 2;
+ else
+ {
+ info->i = I.PC;
+ break;
+ }
+
+ info->i = I.map_files[I.cur_map].bias[map_index]+I.PC;
+ }
+ break;
+#else
+ case CPUINFO_INT_PC:
+#endif
+ case CPUINFO_INT_REGISTER + TMS9900_PC: info->i = I.PC; break;
+ case CPUINFO_INT_REGISTER + TMS9900_IR: info->i = I.IR; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + TMS9900_WP: info->i = I.WP; break;
+ case CPUINFO_INT_REGISTER + TMS9900_STATUS: setstat(); info->i = I.STATUS; break;
+ case CPUINFO_INT_REGISTER + TMS9900_R0: info->i = READREG_DEBUG(R0); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R1: info->i = READREG_DEBUG(R1); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R2: info->i = READREG_DEBUG(R2); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R3: info->i = READREG_DEBUG(R3); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R4: info->i = READREG_DEBUG(R4); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R5: info->i = READREG_DEBUG(R5); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R6: info->i = READREG_DEBUG(R6); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R7: info->i = READREG_DEBUG(R7); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R8: info->i = READREG_DEBUG(R8); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R9: info->i = READREG_DEBUG(R9); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R10: info->i = READREG_DEBUG(R10); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R11: info->i = READREG_DEBUG(R11); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R12: info->i = READREG_DEBUG(R12); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R13: info->i = READREG_DEBUG(R13); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R14: info->i = READREG_DEBUG(R14); break;
+ case CPUINFO_INT_REGISTER + TMS9900_R15: info->i = READREG_DEBUG(R15); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = tms99xx_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = tms99xx_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = tms99xx_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = tms99xx_init; break;
+ case CPUINFO_PTR_RESET: info->reset = tms99xx_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = tms99xx_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = tms99xx_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = tms99xx_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &TMS99XX_ICOUNT; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, TMS99XX_CPU_NAME); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Texas Instruments 9900"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "2.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "C TMS9900 emulator by Edward Swartz, initially converted for Mame by M.Coates, updated by R. Nabet"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ I.WP & 0x8000 ? 'L':'.',
+ I.WP & 0x4000 ? 'A':'.',
+ I.WP & 0x2000 ? 'E':'.',
+ I.WP & 0x1000 ? 'C':'.',
+ I.WP & 0x0800 ? 'V':'.',
+ I.WP & 0x0400 ? 'P':'.',
+ I.WP & 0x0200 ? 'X':'.',
+ I.WP & 0x0100 ? '?':'.',
+ I.WP & 0x0080 ? '?':'.',
+ I.WP & 0x0040 ? '?':'.',
+ I.WP & 0x0020 ? '?':'.',
+ I.WP & 0x0010 ? '?':'.',
+ I.WP & 0x0008 ? 'I':'.',
+ I.WP & 0x0004 ? 'I':'.',
+ I.WP & 0x0002 ? 'I':'.',
+ I.WP & 0x0001 ? 'I':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + TMS9900_PC: sprintf(info->s, "PC :%04X", I.PC); break;
+ case CPUINFO_STR_REGISTER + TMS9900_IR: sprintf(info->s, "IR :%04X", I.IR); break;
+ case CPUINFO_STR_REGISTER + TMS9900_WP: sprintf(info->s, "WP :%04X", I.WP); break;
+ case CPUINFO_STR_REGISTER + TMS9900_STATUS: sprintf(info->s, "ST :%04X", I.STATUS); break;
+
+ case CPUINFO_STR_REGISTER + TMS9900_R0: sprintf(info->s, "R0 :%04X", READREG_DEBUG(R0)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R1: sprintf(info->s, "R1 :%04X", READREG_DEBUG(R1)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R2: sprintf(info->s, "R2 :%04X", READREG_DEBUG(R2)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R3: sprintf(info->s, "R3 :%04X", READREG_DEBUG(R3)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R4: sprintf(info->s, "R4 :%04X", READREG_DEBUG(R4)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R5: sprintf(info->s, "R5 :%04X", READREG_DEBUG(R5)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R6: sprintf(info->s, "R6 :%04X", READREG_DEBUG(R6)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R7: sprintf(info->s, "R7 :%04X", READREG_DEBUG(R7)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R8: sprintf(info->s, "R8 :%04X", READREG_DEBUG(R8)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R9: sprintf(info->s, "R9 :%04X", READREG_DEBUG(R9)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R10: sprintf(info->s, "R10:%04X", READREG_DEBUG(R10)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R11: sprintf(info->s, "R11:%04X", READREG_DEBUG(R11)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R12: sprintf(info->s, "R12:%04X", READREG_DEBUG(R12)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R13: sprintf(info->s, "R13:%04X", READREG_DEBUG(R13)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R14: sprintf(info->s, "R14:%04X", READREG_DEBUG(R14)); break;
+ case CPUINFO_STR_REGISTER + TMS9900_R15: sprintf(info->s, "R15:%04X", READREG_DEBUG(R15)); break;
+ }
+}
diff --git a/src/emu/cpu/tms9900/99xxstat.h b/src/emu/cpu/tms9900/99xxstat.h
new file mode 100644
index 00000000000..dc0877a80cf
--- /dev/null
+++ b/src/emu/cpu/tms9900/99xxstat.h
@@ -0,0 +1,483 @@
+/************************************************************************
+
+ ST register functions
+
+************************************************************************/
+
+/*
+ remember that the OP ST bit is maintained in lastparity
+*/
+
+/*
+ setstat sets the ST_OP bit according to lastparity
+
+ It must be called before reading the ST register.
+*/
+
+static void setstat(void)
+{
+ int i;
+ UINT8 a;
+
+ I.STATUS &= ~ ST_OP;
+
+ /* We set the parity bit. */
+ a = lastparity;
+
+ for (i=0; i<8; i++) /* 8 bits to test */
+ {
+ if (a & 1) /* If current bit is set */
+ I.STATUS ^= ST_OP; /* we toggle the ST_OP bit */
+
+ a >>= 1; /* Next bit. */
+ }
+}
+
+/*
+ getstat sets emulator's lastparity variable according to 9900's STATUS bits.
+ It must be called on interrupt return, or when, for some reason,
+ the emulated program sets the STATUS register directly.
+*/
+static void getstat(void)
+{
+#if (USE_ST_MASK)
+ I.STATUS &= ST_MASK; /* unused bits are forced to 0 */
+#endif
+
+ if (I.STATUS & ST_OP)
+ lastparity = 1;
+ else
+ lastparity = 0;
+
+#if HAS_MAPPING
+ I.cur_map = (I.STATUS & ST_MF) ? 1 : 0;
+#endif
+}
+
+/*
+ A few words about the following functions.
+
+ A big portability issue is the behavior of the ">>" instruction with the sign bit, which has
+ not been normalised. Every compiler does whatever it thinks smartest.
+ My code assumed that when shifting right signed numbers, the operand is left-filled with a
+ copy of sign bit, and that when shifting unsigned variables, it is left-filled with 0s.
+ This is probably the most logical behaviour, and it is the behavior of CW PRO3 - most time
+ (the exception is that ">>=" instructions always copy the sign bit (!)). But some compilers
+ are bound to disagree.
+
+ So, I had to create special functions with predefined tables included, so that this code work
+ on every compiler. BUT this is a real slow-down.
+ So, you might have to include a few lines in assembly to make this work better.
+ Sorry about this, this problem is really unpleasant and absurd, but it is not my fault.
+*/
+
+
+static const UINT16 right_shift_mask_table[17] =
+{
+ 0xFFFF,
+ 0x7FFF,
+ 0x3FFF,
+ 0x1FFF,
+ 0x0FFF,
+ 0x07FF,
+ 0x03FF,
+ 0x01FF,
+ 0x00FF,
+ 0x007F,
+ 0x003F,
+ 0x001F,
+ 0x000F,
+ 0x0007,
+ 0x0003,
+ 0x0001,
+ 0x0000
+};
+
+static const UINT16 inverted_right_shift_mask_table[17] =
+{
+ 0x0000,
+ 0x8000,
+ 0xC000,
+ 0xE000,
+ 0xF000,
+ 0xF800,
+ 0xFC00,
+ 0xFE00,
+ 0xFF00,
+ 0xFF80,
+ 0xFFC0,
+ 0xFFE0,
+ 0xFFF0,
+ 0xFFF8,
+ 0xFFFC,
+ 0xFFFE,
+ 0xFFFF
+};
+
+INLINE UINT16 logical_right_shift(UINT16 val, int c)
+{
+ return((val>>c) & right_shift_mask_table[c]);
+}
+
+INLINE INT16 arithmetic_right_shift(INT16 val, int c)
+{
+ if (val < 0)
+ return((val>>c) | inverted_right_shift_mask_table[c]);
+ else
+ return((val>>c) & right_shift_mask_table[c]);
+}
+
+
+
+
+
+/*
+ Set lae
+*/
+INLINE void setst_lae(INT16 val)
+{
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
+
+ if (val > 0)
+ I.STATUS |= (ST_LGT | ST_AGT);
+ else if (val < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+}
+
+
+/*
+ Set laep (BYTE)
+*/
+INLINE void setst_byte_laep(INT8 val)
+{
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
+
+ if (val > 0)
+ I.STATUS |= (ST_LGT | ST_AGT);
+ else if (val < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ lastparity = val;
+}
+
+/*
+ For COC, CZC, and TB
+*/
+INLINE void setst_e(UINT16 val, UINT16 to)
+{
+ if (val == to)
+ I.STATUS |= ST_EQ;
+ else
+ I.STATUS &= ~ ST_EQ;
+}
+
+/*
+ For CI, C, CB
+*/
+INLINE void setst_c_lae(UINT16 to, UINT16 val)
+{
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
+
+ if (val == to)
+ I.STATUS |= ST_EQ;
+ else
+ {
+ if ( ((INT16) val) > ((INT16) to) )
+ I.STATUS |= ST_AGT;
+ if ( ((UINT16) val) > ((UINT16) to) )
+ I.STATUS |= ST_LGT;
+ }
+}
+
+/*
+ Set laeco for add
+*/
+INLINE INT16 setst_add_laeco(int a, int b)
+{
+ UINT32 res;
+ INT16 res2;
+
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
+
+ res = (a & 0xffff) + (b & 0xffff);
+
+ if (res & 0x10000)
+ I.STATUS |= ST_C;
+
+ if ((res ^ b) & (res ^ a) & 0x8000)
+ I.STATUS |= ST_OV;
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+ if (((a & b) | ((a | b) & ~ res)) & 0x0800)
+ I.STATUS |= ST_DC;
+#endif
+
+ res2 = (INT16) res;
+
+ if (res2 > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (res2 < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ return res2;
+}
+
+
+/*
+ Set laeco for subtract
+*/
+INLINE INT16 setst_sub_laeco(int a, int b)
+{
+ UINT32 res;
+ INT16 res2;
+
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
+
+ res = (a & 0xffff) - (b & 0xffff);
+
+ if (! (res & 0x10000))
+ I.STATUS |= ST_C;
+
+ if ((a ^ b) & (a ^ res) & 0x8000)
+ I.STATUS |= ST_OV;
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+ if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x0800)
+ I.STATUS |= ST_DC;
+#endif
+
+ res2 = (INT16) res;
+
+ if (res2 > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (res2 < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ return res2;
+}
+
+
+/*
+ Set laecop for add (BYTE)
+*/
+INLINE INT8 setst_addbyte_laecop(int a, int b)
+{
+ unsigned int res;
+ INT8 res2;
+
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP);
+
+ res = (a & 0xff) + (b & 0xff);
+
+ if (res & 0x100)
+ I.STATUS |= ST_C;
+
+ if ((res ^ b) & (res ^ a) & 0x80)
+ I.STATUS |= ST_OV;
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+ if (((a & b) | ((a | b) & ~ res)) & 0x08)
+ I.STATUS |= ST_DC;
+#endif
+
+ res2 = (INT8) res;
+
+ if (res2 > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (res2 < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ lastparity = res2;
+
+ return res2;
+}
+
+
+/*
+ Set laecop for subtract (BYTE)
+*/
+INLINE INT8 setst_subbyte_laecop(int a, int b)
+{
+ unsigned int res;
+ INT8 res2;
+
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP);
+
+ res = (a & 0xff) - (b & 0xff);
+
+ if (! (res & 0x100))
+ I.STATUS |= ST_C;
+
+ if ((a ^ b) & (a ^ res) & 0x80)
+ I.STATUS |= ST_OV;
+
+#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
+ if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x08)
+ I.STATUS |= ST_DC;
+#endif
+
+ res2 = (INT8) res;
+
+ if (res2 > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (res2 < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ lastparity = res2;
+
+ return res2;
+}
+
+
+
+/*
+ For NEG
+*/
+INLINE void setst_laeo(INT16 val)
+{
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_OV);
+
+ if (val > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (val < 0)
+ {
+ I.STATUS |= ST_LGT;
+ if (((UINT16) val) == 0x8000)
+ I.STATUS |= ST_OV;
+ }
+ else
+ I.STATUS |= ST_EQ;
+}
+
+
+
+/*
+ Meat of SRA
+*/
+INLINE UINT16 setst_sra_laec(INT16 a, UINT16 c)
+{
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C);
+
+ if (c != 0)
+ {
+ a = arithmetic_right_shift(a, c-1);
+ if (a & 1) // The carry bit equals the last bit that is shifted out
+ I.STATUS |= ST_C;
+ a = arithmetic_right_shift(a, 1);
+ }
+
+ if (a > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (a < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ return a;
+}
+
+
+/*
+ Meat of SRL. Same algorithm as SRA, except that we fills in with 0s.
+*/
+INLINE UINT16 setst_srl_laec(UINT16 a,UINT16 c)
+{
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C);
+
+ if (c != 0)
+ {
+ a = logical_right_shift(a, c-1);
+ if (a & 1)
+ I.STATUS |= ST_C;
+ a = logical_right_shift(a, 1);
+ }
+
+ if (((INT16) a) > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (((INT16) a) < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ return a;
+}
+
+
+//
+// Meat of SRC
+//
+INLINE UINT16 setst_src_laec(UINT16 a,UINT16 c)
+{
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C);
+
+ if (c != 0)
+ {
+ a = logical_right_shift(a, c) | (a << (16-c));
+ if (a & 0x8000) // The carry bit equals the last bit that is shifted out
+ I.STATUS |= ST_C;
+ }
+
+ if (((INT16) a) > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (((INT16) a) < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ return a;
+}
+
+
+//
+// Meat of SLA
+//
+INLINE UINT16 setst_sla_laeco(UINT16 a, UINT16 c)
+{
+ I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
+
+ if (c != 0)
+ {
+ {
+ register UINT16 mask;
+ register UINT16 ousted_bits;
+
+ mask = 0xFFFF << (16-c-1);
+ ousted_bits = a & mask;
+
+ if (ousted_bits) // If ousted_bits is neither all 0s
+ if (ousted_bits ^ mask) // nor all 1s,
+ I.STATUS |= ST_OV; // we set overflow
+ }
+
+ a <<= c-1;
+ if (a & 0x8000) // The carry bit equals the last bit that is shifted out
+ I.STATUS |= ST_C;
+
+ a <<= 1;
+ }
+
+ if (((INT16) a) > 0)
+ I.STATUS |= ST_LGT | ST_AGT;
+ else if (((INT16) a) < 0)
+ I.STATUS |= ST_LGT;
+ else
+ I.STATUS |= ST_EQ;
+
+ return a;
+}
+
+
+/***********************************************************************/
+
diff --git a/src/emu/cpu/tms9900/ti990_10.c b/src/emu/cpu/tms9900/ti990_10.c
new file mode 100644
index 00000000000..1382503e6c9
--- /dev/null
+++ b/src/emu/cpu/tms9900/ti990_10.c
@@ -0,0 +1,9 @@
+/*
+ Generate the tms9900 emulator
+*/
+
+#include "tms9900.h"
+
+#define TMS99XX_MODEL TI990_10_ID
+
+#include "99xxcore.h"
diff --git a/src/emu/cpu/tms9900/tms9900.c b/src/emu/cpu/tms9900/tms9900.c
new file mode 100644
index 00000000000..7850e477b48
--- /dev/null
+++ b/src/emu/cpu/tms9900/tms9900.c
@@ -0,0 +1,9 @@
+/*
+ Generate the tms9900 emulator
+*/
+
+#include "tms9900.h"
+
+#define TMS99XX_MODEL TMS9900_ID
+
+#include "99xxcore.h"
diff --git a/src/emu/cpu/tms9900/tms9900.h b/src/emu/cpu/tms9900/tms9900.h
new file mode 100644
index 00000000000..8b248ed6b52
--- /dev/null
+++ b/src/emu/cpu/tms9900/tms9900.h
@@ -0,0 +1,223 @@
+/*
+ tms9900.h
+
+ C Header file for TMS9900 core
+*/
+
+#ifndef TMS9900_H
+#define TMS9900_H
+
+#include "cpuintrf.h"
+
+/*#define TI990_9_ID 0*//* early implementation, used in a few real-world applications, 1974 */
+ /* very similar to mapper-less 990/10 and tms9900, but the Load process */
+ /* is different */
+ /* ("ti990/9" is likely to be a nickname) */
+#define TI990_10_ID 1 /* original multi-chip implementation for minicomputer systems, 1975 */
+/*#define TI990_12_ID 2*//* multi-chip implementation, faster than 990/10. huge instruction set */
+ /* (144 instructions, with up to 16 additional custom instructions simulteanously) */
+ /* 1979 (or before) */
+#define TMS9900_ID 3 /* mono-chip implementation, 1976 */
+#define TMS9940_ID 4 /* microcontroller with 2kb ROM, 128b RAM, decrementer, CRU bus, 1979 */
+#define TMS9980_ID 5 /* 8-bit variant of tms9900. Two distinct chips actually : tms9980a, */
+ /* and tms9981 with an extra clock and simplified power supply */
+#define TMS9985_ID 6 /* 9940 with 8kb ROM, 256b RAM, and a 8-bit external bus, c. 1978 (never released) */
+#define TMS9989_ID 7 /* improved 9980, used in bombs, missiles, and other *nice* hardware */
+/*#define SBP68689_ID 8*//* improved 9989, built as an ASIC as 9989 was running scarce */
+#define TMS9995_ID 9 /* tms9985-like, with many improvements (but no ROM) */
+#define TMS99000_ID 10/* improved mono-chip implementation, meant to replace 990/10, 1981 */
+ /* This chip is available in several variants (tms99105, tms99110...), */
+ /* which are similar but emulate additional instructions thanks */
+ /* to the so-called macrostore feature. */
+
+/* NPW 25-May-2002 - Added these to get it to compile under windows */
+#define TI9940_ID TMS9940_ID
+#define TI9985_ID TMS9985_ID
+
+
+enum {
+ TMS9900_PC=1, TMS9900_WP, TMS9900_STATUS, TMS9900_IR,
+ TMS9900_R0, TMS9900_R1, TMS9900_R2, TMS9900_R3,
+ TMS9900_R4, TMS9900_R5, TMS9900_R6, TMS9900_R7,
+ TMS9900_R8, TMS9900_R9, TMS9900_R10, TMS9900_R11,
+ TMS9900_R12, TMS9900_R13, TMS9900_R14, TMS9900_R15
+};
+
+#if (HAS_TI990_10)
+
+extern void ti990_10_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with the parameters ti990_10_reset wants.
+*/
+typedef struct ti990_10reset_param
+{
+ void (*idle_callback)(int state);
+ void (*rset_callback)(void);
+ void (*lrex_callback)(void);
+ void (*ckon_ckof_callback)(int state);
+
+ void (*error_interrupt_callback)(int state);
+} ti990_10reset_param;
+
+/* accessor for the internal ROM */
+extern READ16_HANDLER(ti990_10_internal_r);
+
+/* CRU accessor for the mapper registers (R12 base 0x1fa0) */
+extern READ8_HANDLER(ti990_10_mapper_cru_r);
+extern WRITE8_HANDLER(ti990_10_mapper_cru_w);
+/* CRU accessor for the error interrupt register (R12 base 0x1fc0) */
+extern READ8_HANDLER(ti990_10_eir_cru_r);
+extern WRITE8_HANDLER(ti990_10_eir_cru_w);
+
+#endif
+
+#if (HAS_TMS9900)
+
+extern void tms9900_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with optional parameters for tms9900_reset.
+*/
+typedef struct tms9900reset_param
+{
+ void (*idle_callback)(int state);
+} tms9900reset_param;
+
+#endif
+
+#if (HAS_TMS9940)
+
+extern void tms9940_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with optional parameters for tms9940_reset.
+*/
+typedef struct tms9940reset_param
+{
+ void (*idle_callback)(int state);
+} tms9940reset_param;
+
+#endif
+
+#if (HAS_TMS9980)
+
+extern void tms9980a_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with optional parameters for tms9980a_reset.
+*/
+typedef struct tms9980areset_param
+{
+ void (*idle_callback)(int state);
+} tms9980areset_param;
+
+#endif
+
+#if (HAS_TMS9985)
+
+extern void tms9985_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with optional parameters for tms9985_reset.
+*/
+typedef struct tms9985reset_param
+{
+ void (*idle_callback)(int state);
+} tms9985reset_param;
+
+#endif
+
+#if (HAS_TMS9989)
+
+extern void tms9989_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with optional parameters for tms9989_reset.
+*/
+typedef struct tms9989reset_param
+{
+ void (*idle_callback)(int state);
+} tms9989reset_param;
+
+#endif
+
+#if (HAS_TMS9995)
+
+extern void tms9995_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with the parameters tms9995_reset wants.
+*/
+typedef struct tms9995reset_param
+{
+ /* auto_wait_state : a non-zero value makes tms9995 generate a wait state automatically on each
+ memory access */
+ int auto_wait_state;
+
+ void (*idle_callback)(int state);
+
+ /* on the tms9995-mp9537, internal RAM and decrementer register are
+ disabled. This chip is used by the ti99/8 so that internal RAM does
+ not prevent the mapper from working correctly. */
+ int is_mp9537;
+} tms9995reset_param;
+
+/* accessor for the first 252 bytes of internal RAM */
+extern READ8_HANDLER(tms9995_internal1_r);
+extern WRITE8_HANDLER(tms9995_internal1_w);
+/* accessors for the last 4 bytes of internal RAM */
+extern READ8_HANDLER(tms9995_internal2_r);
+extern WRITE8_HANDLER(tms9995_internal2_w);
+
+#endif
+
+#if (HAS_TMS99000)
+
+extern void tms99000_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with optional parameters for tms99000_reset.
+*/
+typedef struct tms99000reset_param
+{
+ void (*idle_callback)(int state);
+} tms99000reset_param;
+
+#endif
+
+#if (HAS_TMS99105A)
+
+extern void tms99105a_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with optional parameters for tms99105a_reset.
+*/
+typedef struct tms99105areset_param
+{
+ void (*idle_callback)(int state);
+} tms99105areset_param;
+
+#endif
+
+#if (HAS_TMS99110A)
+
+extern void tms99110a_get_info(UINT32 state, cpuinfo *info);
+
+/*
+ structure with optional parameters for tms99110a_reset.
+*/
+typedef struct tms99110areset_param
+{
+ void (*idle_callback)(int state);
+} tms99110areset_param;
+
+#endif
+
+#ifdef MAME_DEBUG
+unsigned Dasm9900 (char *buffer, unsigned pc, int model_id, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif
+
+
diff --git a/src/emu/cpu/tms9900/tms9980a.c b/src/emu/cpu/tms9900/tms9980a.c
new file mode 100644
index 00000000000..0a3ef483ac4
--- /dev/null
+++ b/src/emu/cpu/tms9900/tms9980a.c
@@ -0,0 +1,9 @@
+/*
+ generate the tms9980a/tms9981 emulator
+*/
+
+#include "tms9900.h"
+
+#define TMS99XX_MODEL TMS9980_ID
+
+#include "99xxcore.h"
diff --git a/src/emu/cpu/tms9900/tms9995.c b/src/emu/cpu/tms9900/tms9995.c
new file mode 100644
index 00000000000..e81a47e80da
--- /dev/null
+++ b/src/emu/cpu/tms9900/tms9995.c
@@ -0,0 +1,9 @@
+/*
+ generate the tms9995 emulator
+*/
+
+#include "tms9900.h"
+
+#define TMS99XX_MODEL TMS9995_ID
+
+#include "99xxcore.h"
diff --git a/src/emu/cpu/upd7810/7810dasm.c b/src/emu/cpu/upd7810/7810dasm.c
new file mode 100644
index 00000000000..0024992a555
--- /dev/null
+++ b/src/emu/cpu/upd7810/7810dasm.c
@@ -0,0 +1,4059 @@
+/*****************************************************************************
+ *
+ * Portable uPD7810/11, 7810H/11H, 78C10/C11/C14 disassembler
+ * Copyright (c) 2001 Juergen Buchmueller, all rights reserved.
+ *
+ * NS20030112: added 7807.
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "upd7810.h"
+
+struct dasm_s {
+ UINT8 token;
+ const void *args;
+ UINT8 oplen;
+ UINT8 cycles;
+};
+
+enum
+{
+ illegal=1,
+ ACI,
+ ADC,
+ ADCW,
+ ADCX,
+ ADD,
+ ADDNC,
+ ADDNCW,
+ ADDNCX,
+ ADDW,
+ ADDX,
+ ADI,
+ ADINC,
+ ANA,
+ ANAW,
+ ANAX,
+ AND,
+ ANI,
+ ANIW,
+ BIT,
+ BLOCK,
+ CALB,
+ CALF,
+ CALL,
+ CALT,
+ CLC,
+ CLR, /* 7807 */
+ CMC, /* 7807 */
+ DAA,
+ DADC,
+ DADD,
+ DADDNC,
+ DAN,
+ DCR,
+ DCRW,
+ DCX,
+ DEQ,
+ DGT,
+ DI,
+ DIV,
+ DLT,
+ DMOV,
+ DNE,
+ DOFF,
+ DON,
+ DOR,
+ DRLL,
+ DRLR,
+ DSBB,
+ DSLL,
+ DSLR,
+ DSUB,
+ DSUBNB,
+ DXR,
+ EADD,
+ EI,
+ EQA,
+ EQAW,
+ EQAX,
+ EQI,
+ EQIW,
+ ESUB,
+ EXA,
+ EXH,
+ EXX,
+ EXR, /* 7807 */
+ GTA,
+ GTAW,
+ GTAX,
+ GTI,
+ GTIW,
+ HALT,
+ INR,
+ INRW,
+ INX,
+ JB,
+ JEA,
+ JMP,
+ JR,
+ JRE,
+ LBCD,
+ LDAW,
+ LDAX,
+ LDEAX,
+ LDED,
+ LHLD,
+ LSPD,
+ LTA,
+ LTAW,
+ LTAX,
+ LTI,
+ LTIW,
+ LXI,
+ MOV,
+ MUL,
+ MVI,
+ MVIW,
+ MVIX,
+ NEA,
+ NEAW,
+ NEAX,
+ NEGA,
+ NEI,
+ NEIW,
+ NOP,
+ NOT, /* 7807 */
+ OFFA,
+ OFFAW,
+ OFFAX,
+ OFFI,
+ OFFIW,
+ ONA,
+ ONAW,
+ ONAX,
+ ONI,
+ ONIW,
+ OR, /* 7807 */
+ ORA,
+ ORAW,
+ ORAX,
+ ORI,
+ ORIW,
+ POP,
+ PUSH,
+ RET,
+ RETI,
+ RETS,
+ RLD,
+ RLL,
+ RLR,
+ RRD,
+ SBB,
+ SBBW,
+ SBBX,
+ SBCD,
+ SBI,
+ SDED,
+ SETB, /* 7807 */
+ SHLD,
+ SK,
+ SKIT,
+ SKN,
+ SKNIT,
+ SLL,
+ SLLC,
+ SLR,
+ SLRC,
+ SOFTI,
+ SSPD,
+ STAW,
+ STAX,
+ STC,
+ STEAX,
+ STOP,
+ SUB,
+ SUBNB,
+ SUBNBW,
+ SUBNBX,
+ SUBW,
+ SUBX,
+ SUI,
+ SUINB,
+ TABLE,
+ XOR, /* 7807 */
+ XRA,
+ XRAW,
+ XRAX,
+ XRI
+};
+
+static const char* token[] =
+{
+ "",
+ "illegal",
+ "ACI",
+ "ADC",
+ "ADCW",
+ "ADCX",
+ "ADD",
+ "ADDNC",
+ "ADDNCW",
+ "ADDNCX",
+ "ADDW",
+ "ADDX",
+ "ADI",
+ "ADINC",
+ "ANA",
+ "ANAW",
+ "ANAX",
+ "AND",
+ "ANI",
+ "ANIW",
+ "BIT",
+ "BLOCK",
+ "CALB",
+ "CALF",
+ "CALL",
+ "CALT",
+ "CLC",
+ "CLR", /* 7807 */
+ "CMC", /* 7807 */
+ "DAA",
+ "DADC",
+ "DADD",
+ "DADDNC",
+ "DAN",
+ "DCR",
+ "DCRW",
+ "DCX",
+ "DEQ",
+ "DGT",
+ "DI",
+ "DIV",
+ "DLT",
+ "DMOV",
+ "DNE",
+ "DOFF",
+ "DON",
+ "DOR",
+ "DRLL",
+ "DRLR",
+ "DSBB",
+ "DSLL",
+ "DSLR",
+ "DSUB",
+ "DSUBNB",
+ "DXR",
+ "EADD",
+ "EI",
+ "EQA",
+ "EQAW",
+ "EQAX",
+ "EQI",
+ "EQIW",
+ "ESUB",
+ "EXA",
+ "EXH",
+ "EXX",
+ "EXR", /* 7807 */
+ "GTA",
+ "GTAW",
+ "GTAX",
+ "GTI",
+ "GTIW",
+ "HALT",
+ "INR",
+ "INRW",
+ "INX",
+ "JB",
+ "JEA",
+ "JMP",
+ "JR",
+ "JRE",
+ "LBCD",
+ "LDAW",
+ "LDAX",
+ "LDEAX",
+ "LDED",
+ "LHLD",
+ "LSPD",
+ "LTA",
+ "LTAW",
+ "LTAX",
+ "LTI",
+ "LTIW",
+ "LXI",
+ "MOV",
+ "MUL",
+ "MVI",
+ "MVIW",
+ "MVIX",
+ "NEA",
+ "NEAW",
+ "NEAX",
+ "NEGA",
+ "NEI",
+ "NEIW",
+ "NOP",
+ "NOT", /* 7807 */
+ "OFFA",
+ "OFFAW",
+ "OFFAX",
+ "OFFI",
+ "OFFIW",
+ "ONA",
+ "ONAW",
+ "ONAX",
+ "ONI",
+ "ONIW",
+ "OR", /* 7807 */
+ "ORA",
+ "ORAW",
+ "ORAX",
+ "ORI",
+ "ORIW",
+ "POP",
+ "PUSH",
+ "RET",
+ "RETI",
+ "RETS",
+ "RLD",
+ "RLL",
+ "RLR",
+ "RRD",
+ "SBB",
+ "SBBW",
+ "SBBX",
+ "SBCD",
+ "SBI",
+ "SDED",
+ "SETB", /* 7807 */
+ "SHLD",
+ "SK",
+ "SKIT",
+ "SKN",
+ "SKNIT",
+ "SLL",
+ "SLLC",
+ "SLR",
+ "SLRC",
+ "SOFTI",
+ "SSPD",
+ "STAW",
+ "STAX",
+ "STC",
+ "STEAX",
+ "STOP",
+ "SUB",
+ "SUBNB",
+ "SUBNBW",
+ "SUBNBX",
+ "SUBW",
+ "SUBX",
+ "SUI",
+ "SUINB",
+ "TABLE",
+ "XOR", /* 7807 */
+ "XRA",
+ "XRAW",
+ "XRAX",
+ "XRI"
+};
+
+
+/* prefix 48 */
+static struct dasm_s dasm48_7810[256] =
+{
+ {illegal,0, 2, 8}, /* 00: 0100 1000 0000 0000 */
+ {SLRC,"A", 2, 8}, /* 01: 0100 1000 0000 0001 */
+ {SLRC,"B", 2, 8}, /* 02: 0100 1000 0000 0010 */
+ {SLRC,"C", 2, 8}, /* 03: 0100 1000 0000 0011 */
+ {illegal,0, 2, 8}, /* 04: 0100 1000 0000 0100 */
+ {SLLC,"A", 2, 8}, /* 05: 0100 1000 0000 0101 */
+ {SLLC,"B", 2, 8}, /* 06: 0100 1000 0000 0110 */
+ {SLLC,"C", 2, 8}, /* 07: 0100 1000 0000 0111 */
+ {SK,"NV", 2, 8}, /* 08: 0100 1000 0000 1000 */
+ {illegal,0, 2, 8}, /* 09: 0100 1000 0000 1001 */
+ {SK,"CY", 2, 8}, /* 0a: 0100 1000 0000 1010 */
+ {SK,"HC", 2, 8}, /* 0b: 0100 1000 0000 1011 */
+ {SK,"Z", 2, 8}, /* 0c: 0100 1000 0000 1100 */
+ {illegal,0, 2, 8}, /* 0d: 0100 1000 0000 1101 */
+ {illegal,0, 2, 8}, /* 0e: 0100 1000 0000 1110 */
+ {illegal,0, 2, 8}, /* 0f: 0100 1000 0000 1111 */
+
+ {illegal,0, 2, 8}, /* 10: 0100 1000 0001 0000 */
+ {illegal,0, 2, 8}, /* 11: 0100 1000 0001 0001 */
+ {illegal,0, 2, 8}, /* 12: 0100 1000 0001 0010 */
+ {illegal,0, 2, 8}, /* 13: 0100 1000 0001 0011 */
+ {illegal,0, 2, 8}, /* 14: 0100 1000 0001 0100 */
+ {illegal,0, 2, 8}, /* 15: 0100 1000 0001 0101 */
+ {illegal,0, 2, 8}, /* 16: 0100 1000 0001 0110 */
+ {illegal,0, 2, 8}, /* 17: 0100 1000 0001 0111 */
+ {SKN,"NV", 2, 8}, /* 18: 0100 1000 0001 1000 */
+ {illegal,0, 2, 8}, /* 19: 0100 1000 0001 1001 */
+ {SKN,"CY", 2, 8}, /* 1a: 0100 1000 0001 1010 */
+ {SKN,"HC", 2, 8}, /* 1b: 0100 1000 0001 1011 */
+ {SKN,"Z", 2, 8}, /* 1c: 0100 1000 0001 1100 */
+ {illegal,0, 2, 8}, /* 1d: 0100 1000 0001 1101 */
+ {illegal,0, 2, 8}, /* 1e: 0100 1000 0001 1110 */
+ {illegal,0, 2, 8}, /* 1f: 0100 1000 0001 1111 */
+
+ {illegal,0, 2, 8}, /* 20: 0100 1000 0010 0000 */
+ {SLR,"A", 2, 8}, /* 21: 0100 1000 0010 0001 */
+ {SLR,"B", 2, 8}, /* 22: 0100 1000 0010 0010 */
+ {SLR,"C", 2, 8}, /* 23: 0100 1000 0010 0011 */
+ {illegal,0, 2, 8}, /* 24: 0100 1000 0010 0100 */
+ {SLL,"A", 2, 8}, /* 25: 0100 1000 0010 0101 */
+ {SLL,"B", 2, 8}, /* 26: 0100 1000 0010 0110 */
+ {SLL,"C", 2, 8}, /* 27: 0100 1000 0010 0111 */
+ {JEA,0, 2, 8}, /* 28: 0100 1000 0010 1000 */
+ {CALB,0, 2,17}, /* 29: 0100 1000 0010 1001 */
+ {CLC,0, 2, 8}, /* 2a: 0100 1000 0010 1010 */
+ {STC,0, 2, 8}, /* 2b: 0100 1000 0010 1011 */
+ {illegal,0, 2,32}, /* 2c: 0100 1000 0010 1100 */
+ {MUL,"A", 2,32}, /* 2d: 0100 1000 0010 1101 */
+ {MUL,"B", 2,32}, /* 2e: 0100 1000 0010 1110 */
+ {MUL,"C", 2,32}, /* 2f: 0100 1000 0010 1111 */
+
+ {illegal,0, 2, 8}, /* 30: 0100 1000 0011 0000 */
+ {RLR,"A", 2, 8}, /* 31: 0100 1000 0011 0001 */
+ {RLR,"B", 2, 8}, /* 32: 0100 1000 0011 0010 */
+ {RLR,"C", 2, 8}, /* 33: 0100 1000 0011 0011 */
+ {illegal,0, 2, 8}, /* 34: 0100 1000 0011 0100 */
+ {RLL,"A", 2, 8}, /* 35: 0100 1000 0011 0101 */
+ {RLL,"B", 2, 8}, /* 36: 0100 1000 0011 0110 */
+ {RLL,"C", 2, 8}, /* 37: 0100 1000 0011 0111 */
+ {RLD,0, 2,17}, /* 38: 0100 1000 0011 1000 */
+ {RRD,0, 2,17}, /* 39: 0100 1000 0011 1001 */
+ {NEGA,0, 2, 8}, /* 3a: 0100 1000 0011 1010 */
+ {HALT,0, 2,12}, /* 3b: 0100 1000 0011 1011 */
+ {illegal,0, 2,59}, /* 3c: 0100 1000 0011 1100 */
+ {DIV,"A", 2,59}, /* 3d: 0100 1000 0011 1101 */
+ {DIV,"B", 2,59}, /* 3e: 0100 1000 0011 1110 */
+ {DIV,"C", 2,59}, /* 3f: 0100 1000 0011 1111 */
+
+ {SKIT,"NMI", 2, 8}, /* 40: 0100 1000 0100 0000 */
+ {SKIT,"FT0", 2, 8}, /* 41: 0100 1000 0100 0001 */
+ {SKIT,"FT1", 2, 8}, /* 42: 0100 1000 0100 0010 */
+ {SKIT,"F1", 2, 8}, /* 43: 0100 1000 0100 0011 */
+ {SKIT,"F2", 2, 8}, /* 44: 0100 1000 0100 0100 */
+ {SKIT,"FE0", 2, 8}, /* 45: 0100 1000 0100 0101 */
+ {SKIT,"FE1", 2, 8}, /* 46: 0100 1000 0100 0110 */
+ {SKIT,"FEIN", 2, 8}, /* 47: 0100 1000 0100 0111 */
+ {SKIT,"FAD", 2, 8}, /* 48: 0100 1000 0100 1000 */
+ {SKIT,"FSR", 2, 8}, /* 49: 0100 1000 0100 1001 */
+ {SKIT,"FST", 2, 8}, /* 4a: 0100 1000 0100 1010 */
+ {SKIT,"ER", 2, 8}, /* 4b: 0100 1000 0100 1011 */
+ {SKIT,"OV", 2, 8}, /* 4c: 0100 1000 0100 1100 */
+ {illegal,0, 2, 8}, /* 4d: 0100 1000 0100 1101 */
+ {illegal,0, 2, 8}, /* 4e: 0100 1000 0100 1110 */
+ {illegal,0, 2, 8}, /* 4f: 0100 1000 0100 1111 */
+
+ {SKIT,"AN4", 2, 8}, /* 50: 0100 1000 0101 0000 */
+ {SKIT,"AN5", 2, 8}, /* 51: 0100 1000 0101 0001 */
+ {SKIT,"AN6", 2, 8}, /* 52: 0100 1000 0101 0010 */
+ {SKIT,"AN7", 2, 8}, /* 53: 0100 1000 0101 0011 */
+ {SKIT,"SB", 2, 8}, /* 54: 0100 1000 0101 0100 */
+ {illegal,0, 2, 8}, /* 55: 0100 1000 0101 0101 */
+ {illegal,0, 2, 8}, /* 56: 0100 1000 0101 0110 */
+ {illegal,0, 2, 8}, /* 57: 0100 1000 0101 0111 */
+ {illegal,0, 2, 8}, /* 58: 0100 1000 0101 1000 */
+ {illegal,0, 2, 8}, /* 59: 0100 1000 0101 1001 */
+ {illegal,0, 2, 8}, /* 5a: 0100 1000 0101 1010 */
+ {illegal,0, 2, 8}, /* 5b: 0100 1000 0101 1011 */
+ {illegal,0, 2, 8}, /* 5c: 0100 1000 0101 1100 */
+ {illegal,0, 2, 8}, /* 5d: 0100 1000 0101 1101 */
+ {illegal,0, 2, 8}, /* 5e: 0100 1000 0101 1110 */
+ {illegal,0, 2, 8}, /* 5f: 0100 1000 0101 1111 */
+
+ {SKNIT,"NMI", 2, 8}, /* 60: 0100 1000 0110 0000 */
+ {SKNIT,"FT0", 2, 8}, /* 61: 0100 1000 0110 0001 */
+ {SKNIT,"FT1", 2, 8}, /* 62: 0100 1000 0110 0010 */
+ {SKNIT,"F1", 2, 8}, /* 63: 0100 1000 0110 0011 */
+ {SKNIT,"F2", 2, 8}, /* 64: 0100 1000 0110 0100 */
+ {SKNIT,"FE0", 2, 8}, /* 65: 0100 1000 0110 0101 */
+ {SKNIT,"FE1", 2, 8}, /* 66: 0100 1000 0110 0110 */
+ {SKNIT,"FEIN", 2, 8}, /* 67: 0100 1000 0110 0111 */
+ {SKNIT,"FAD", 2, 8}, /* 68: 0100 1000 0110 1000 */
+ {SKNIT,"FSR", 2, 8}, /* 69: 0100 1000 0110 1001 */
+ {SKNIT,"FST", 2, 8}, /* 6a: 0100 1000 0110 1010 */
+ {SKNIT,"ER", 2, 8}, /* 6b: 0100 1000 0110 1011 */
+ {SKNIT,"OV", 2, 8}, /* 6c: 0100 1000 0110 1100 */
+ {illegal,0, 2, 8}, /* 6d: 0100 1000 0110 1101 */
+ {illegal,0, 2, 8}, /* 6e: 0100 1000 0110 1110 */
+ {illegal,0, 2, 8}, /* 6f: 0100 1000 0110 1111 */
+
+ {SKNIT,"AN4", 2, 8}, /* 70: 0100 1000 0111 0000 */
+ {SKNIT,"AN5", 2, 8}, /* 71: 0100 1000 0111 0001 */
+ {SKNIT,"AN6", 2, 8}, /* 72: 0100 1000 0111 0010 */
+ {SKNIT,"AN7", 2, 8}, /* 73: 0100 1000 0111 0011 */
+ {SKNIT,"SB", 2, 8}, /* 74: 0100 1000 0111 0100 */
+ {illegal,0, 2, 8}, /* 75: 0100 1000 0111 0101 */
+ {illegal,0, 2, 8}, /* 76: 0100 1000 0111 0110 */
+ {illegal,0, 2, 8}, /* 77: 0100 1000 0111 0111 */
+ {illegal,0, 2, 8}, /* 78: 0100 1000 0111 1000 */
+ {illegal,0, 2, 8}, /* 79: 0100 1000 0111 1001 */
+ {illegal,0, 2, 8}, /* 7a: 0100 1000 0111 1010 */
+ {illegal,0, 2, 8}, /* 7b: 0100 1000 0111 1011 */
+ {illegal,0, 2, 8}, /* 7c: 0100 1000 0111 1100 */
+ {illegal,0, 2, 8}, /* 7d: 0100 1000 0111 1101 */
+ {illegal,0, 2, 8}, /* 7e: 0100 1000 0111 1110 */
+ {illegal,0, 2, 8}, /* 7f: 0100 1000 0111 1111 */
+
+ {illegal,0, 2, 8}, /* 80: 0100 1000 1000 0000 */
+ {illegal,0, 2, 8}, /* 81: 0100 1000 1000 0001 */
+ {LDEAX,"(DE)", 2,14}, /* 82: 0100 1000 1000 0010 */
+ {LDEAX,"(HL)", 2,14}, /* 83: 0100 1000 1000 0011 */
+ {LDEAX,"(DE++)", 2,14}, /* 84: 0100 1000 1000 0100 */
+ {LDEAX,"(HL++)", 2,14}, /* 85: 0100 1000 1000 0101 */
+ {illegal,0, 2, 8}, /* 86: 0100 1000 1000 0110 */
+ {illegal,0, 2, 8}, /* 87: 0100 1000 1000 0111 */
+ {illegal,0, 2, 8}, /* 88: 0100 1000 1000 1000 */
+ {illegal,0, 2, 8}, /* 89: 0100 1000 1000 1001 */
+ {illegal,0, 2, 8}, /* 8a: 0100 1000 1000 1010 */
+ {LDEAX,"(DE+%b)",3,20}, /* 8b: 0100 1000 1000 1011 xxxx xxxx */
+ {LDEAX,"(HL+A)", 2,20}, /* 8c: 0100 1000 1000 1100 */
+ {LDEAX,"(HL+B)", 2,20}, /* 8d: 0100 1000 1000 1101 */
+ {LDEAX,"(HL+EA)",2,20}, /* 8e: 0100 1000 1000 1110 */
+ {LDEAX,"(HL+%b)",3,20}, /* 8f: 0100 1000 1000 1111 xxxx xxxx */
+
+ {illegal,0, 2, 8}, /* 90: 0100 1000 1000 0000 */
+ {illegal,0, 2, 8}, /* 91: 0100 1000 1000 0001 */
+ {STEAX,"(DE)", 2,14}, /* 92: 0100 1000 1000 0010 */
+ {STEAX,"(HL)", 2,14}, /* 93: 0100 1000 1000 0011 */
+ {STEAX,"(DE++)", 2,14}, /* 94: 0100 1000 1000 0100 */
+ {STEAX,"(HL++)", 2,14}, /* 95: 0100 1000 1000 0101 */
+ {illegal,0, 2, 8}, /* 96: 0100 1000 1000 0110 */
+ {illegal,0, 2, 8}, /* 97: 0100 1000 1000 0111 */
+ {illegal,0, 2, 8}, /* 98: 0100 1000 1000 1000 */
+ {illegal,0, 2, 8}, /* 99: 0100 1000 1000 1001 */
+ {illegal,0, 2, 8}, /* 9a: 0100 1000 1000 1010 */
+ {STEAX,"(DE+%b)",3,20}, /* 9b: 0100 1000 1000 1011 xxxx xxxx */
+ {STEAX,"(HL+A)", 2,20}, /* 9c: 0100 1000 1000 1100 */
+ {STEAX,"(HL+B)", 2,20}, /* 9d: 0100 1000 1000 1101 */
+ {STEAX,"(HL+EA)",2,20}, /* 9e: 0100 1000 1000 1110 */
+ {STEAX,"(HL+%b)",3,20}, /* 9f: 0100 1000 1000 1111 xxxx xxxx */
+
+ {DSLR,"EA", 2, 8}, /* a0: 0100 1000 1010 0000 */
+ {illegal,0, 2, 8}, /* a1: 0100 1000 1010 0001 */
+ {illegal,0, 2, 8}, /* a2: 0100 1000 1010 0010 */
+ {illegal,0, 2, 8}, /* a3: 0100 1000 1010 0011 */
+ {DSLL,"EA", 2, 8}, /* a4: 0100 1000 1010 0100 */
+ {illegal,0, 2, 8}, /* a5: 0100 1000 1010 0101 */
+ {illegal,0, 2, 8}, /* a6: 0100 1000 1010 0110 */
+ {illegal,0, 2, 8}, /* a7: 0100 1000 1010 0111 */
+ {TABLE,0, 2,17}, /* a8: 0100 1000 1010 1000 */
+ {illegal,0, 2, 8}, /* a9: 0100 1000 1010 1001 */
+ {illegal,0, 2, 8}, /* aa: 0100 1000 1010 1010 */
+ {illegal,0, 2, 8}, /* ab: 0100 1000 1010 1011 */
+ {illegal,0, 2, 8}, /* ac: 0100 1000 1010 1100 */
+ {illegal,0, 2, 8}, /* ad: 0100 1000 1010 1101 */
+ {illegal,0, 2, 8}, /* ae: 0100 1000 1010 1110 */
+ {illegal,0, 2, 8}, /* af: 0100 1000 1010 1111 */
+
+ {DRLR,"EA", 2, 8}, /* b0: 0100 1000 1011 0000 */
+ {illegal,0, 2, 8}, /* b1: 0100 1000 1011 0001 */
+ {illegal,0, 2, 8}, /* b2: 0100 1000 1011 0010 */
+ {illegal,0, 2, 8}, /* b3: 0100 1000 1011 0011 */
+ {DRLL,"EA", 2, 8}, /* b4: 0100 1000 1011 0100 */
+ {illegal,0, 2, 8}, /* b5: 0100 1000 1011 0101 */
+ {illegal,0, 2, 8}, /* b6: 0100 1000 1011 0110 */
+ {illegal,0, 2, 8}, /* b7: 0100 1000 1011 0111 */
+ {illegal,0, 2, 8}, /* b8: 0100 1000 1011 1000 */
+ {illegal,0, 2, 8}, /* b9: 0100 1000 1011 1001 */
+ {illegal,0, 2, 8}, /* ba: 0100 1000 1011 1010 */
+ {STOP,0, 2,12}, /* bb: 0100 1000 1011 1011 */ /* 7810 */
+ {illegal,0, 2, 8}, /* bc: 0100 1000 1011 1100 */
+ {illegal,0, 2, 8}, /* bd: 0100 1000 1011 1101 */
+ {illegal,0, 2, 8}, /* be: 0100 1000 1011 1110 */
+ {illegal,0, 2, 8}, /* bf: 0100 1000 1011 1111 */
+
+ {DMOV,"EA,ECNT", 2,14}, /* c0: 0100 1000 1100 0000 */
+ {DMOV,"EA,ECPT", 2,14}, /* c1: 0100 1000 1100 0001 */ /* 7810 */
+ {illegal,0, 2, 8}, /* c2: 0100 1000 1100 0010 */
+ {illegal,0, 2, 8}, /* c3: 0100 1000 1100 0011 */
+ {illegal,0, 2, 8}, /* c4: 0100 1000 1100 0100 */
+ {illegal,0, 2, 8}, /* c5: 0100 1000 1100 0101 */
+ {illegal,0, 2, 8}, /* c6: 0100 1000 1100 0110 */
+ {illegal,0, 2, 8}, /* c7: 0100 1000 1100 0111 */
+ {illegal,0, 2, 8}, /* c8: 0100 1000 1100 1000 */
+ {illegal,0, 2, 8}, /* c9: 0100 1000 1100 1001 */
+ {illegal,0, 2, 8}, /* ca: 0100 1000 1100 1010 */
+ {illegal,0, 2, 8}, /* cb: 0100 1000 1100 1011 */
+ {illegal,0, 2, 8}, /* cc: 0100 1000 1100 1100 */
+ {illegal,0, 2, 8}, /* cd: 0100 1000 1100 1101 */
+ {illegal,0, 2, 8}, /* ce: 0100 1000 1100 1110 */
+ {illegal,0, 2, 8}, /* cf: 0100 1000 1100 1111 */
+
+ {illegal,0, 2, 8}, /* d0: 0100 1000 1101 0000 */
+ {illegal,0, 2, 8}, /* d1: 0100 1000 1101 0001 */
+ {DMOV,"ETM0,EA", 2,14}, /* d2: 0100 1000 1101 0010 */
+ {DMOV,"ETM1,EA", 2,14}, /* d3: 0100 1000 1101 0011 */
+ {illegal,0, 2, 8}, /* d4: 0100 1000 1101 0100 */
+ {illegal,0, 2, 8}, /* d5: 0100 1000 1101 0101 */
+ {illegal,0, 2, 8}, /* d6: 0100 1000 1101 0110 */
+ {illegal,0, 2, 8}, /* d7: 0100 1000 1101 0111 */
+ {illegal,0, 2, 8}, /* d8: 0100 1000 1101 1000 */
+ {illegal,0, 2, 8}, /* d9: 0100 1000 1101 1001 */
+ {illegal,0, 2, 8}, /* da: 0100 1000 1101 1010 */
+ {illegal,0, 2, 8}, /* db: 0100 1000 1101 1011 */
+ {illegal,0, 2, 8}, /* dc: 0100 1000 1101 1100 */
+ {illegal,0, 2, 8}, /* dd: 0100 1000 1101 1101 */
+ {illegal,0, 2, 8}, /* de: 0100 1000 1101 1110 */
+ {illegal,0, 2, 8}, /* df: 0100 1000 1101 1111 */
+
+ {illegal,0, 2, 8}, /* e0: 0100 1000 1110 0000 */
+ {illegal,0, 2, 8}, /* e1: 0100 1000 1110 0001 */
+ {illegal,0, 2, 8}, /* e2: 0100 1000 1110 0010 */
+ {illegal,0, 2, 8}, /* e3: 0100 1000 1110 0011 */
+ {illegal,0, 2, 8}, /* e4: 0100 1000 1110 0100 */
+ {illegal,0, 2, 8}, /* e5: 0100 1000 1110 0101 */
+ {illegal,0, 2, 8}, /* e6: 0100 1000 1110 0110 */
+ {illegal,0, 2, 8}, /* e7: 0100 1000 1110 0111 */
+ {illegal,0, 2, 8}, /* e8: 0100 1000 1110 1000 */
+ {illegal,0, 2, 8}, /* e9: 0100 1000 1110 1001 */
+ {illegal,0, 2, 8}, /* ea: 0100 1000 1110 1010 */
+ {illegal,0, 2, 8}, /* eb: 0100 1000 1110 1011 */
+ {illegal,0, 2, 8}, /* ec: 0100 1000 1110 1100 */
+ {illegal,0, 2, 8}, /* ed: 0100 1000 1110 1101 */
+ {illegal,0, 2, 8}, /* ee: 0100 1000 1110 1110 */
+ {illegal,0, 2, 8}, /* ef: 0100 1000 1110 1111 */
+
+ {illegal,0, 2, 8}, /* f0: 0100 1000 1111 0000 */
+ {illegal,0, 2, 8}, /* f1: 0100 1000 1111 0001 */
+ {illegal,0, 2, 8}, /* f2: 0100 1000 1111 0010 */
+ {illegal,0, 2, 8}, /* f3: 0100 1000 1111 0011 */
+ {illegal,0, 2, 8}, /* f4: 0100 1000 1111 0100 */
+ {illegal,0, 2, 8}, /* f5: 0100 1000 1111 0101 */
+ {illegal,0, 2, 8}, /* f6: 0100 1000 1111 0110 */
+ {illegal,0, 2, 8}, /* f7: 0100 1000 1111 0111 */
+ {illegal,0, 2, 8}, /* f8: 0100 1000 1111 1000 */
+ {illegal,0, 2, 8}, /* f9: 0100 1000 1111 1001 */
+ {illegal,0, 2, 8}, /* fa: 0100 1000 1111 1010 */
+ {illegal,0, 2, 8}, /* fb: 0100 1000 1111 1011 */
+ {illegal,0, 2, 8}, /* fc: 0100 1000 1111 1100 */
+ {illegal,0, 2, 8}, /* fd: 0100 1000 1111 1101 */
+ {illegal,0, 2, 8}, /* fe: 0100 1000 1111 1110 */
+ {illegal,0, 2, 8} /* ff: 0100 1000 1111 1111 */
+};
+
+static struct dasm_s dasm48_7807[256] =
+{
+ {illegal,0, 2, 8}, /* 00: 0100 1000 0000 0000 */
+ {SLRC,"A", 2, 8}, /* 01: 0100 1000 0000 0001 */
+ {SLRC,"B", 2, 8}, /* 02: 0100 1000 0000 0010 */
+ {SLRC,"C", 2, 8}, /* 03: 0100 1000 0000 0011 */
+ {illegal,0, 2, 8}, /* 04: 0100 1000 0000 0100 */
+ {SLLC,"A", 2, 8}, /* 05: 0100 1000 0000 0101 */
+ {SLLC,"B", 2, 8}, /* 06: 0100 1000 0000 0110 */
+ {SLLC,"C", 2, 8}, /* 07: 0100 1000 0000 0111 */
+ {SK,"NV", 2, 8}, /* 08: 0100 1000 0000 1000 */
+ {illegal,0, 2, 8}, /* 09: 0100 1000 0000 1001 */
+ {SK,"CY", 2, 8}, /* 0a: 0100 1000 0000 1010 */
+ {SK,"HC", 2, 8}, /* 0b: 0100 1000 0000 1011 */
+ {SK,"Z", 2, 8}, /* 0c: 0100 1000 0000 1100 */
+ {illegal,0, 2, 8}, /* 0d: 0100 1000 0000 1101 */
+ {illegal,0, 2, 8}, /* 0e: 0100 1000 0000 1110 */
+ {illegal,0, 2, 8}, /* 0f: 0100 1000 0000 1111 */
+
+ {illegal,0, 2, 8}, /* 10: 0100 1000 0001 0000 */
+ {illegal,0, 2, 8}, /* 11: 0100 1000 0001 0001 */
+ {illegal,0, 2, 8}, /* 12: 0100 1000 0001 0010 */
+ {illegal,0, 2, 8}, /* 13: 0100 1000 0001 0011 */
+ {illegal,0, 2, 8}, /* 14: 0100 1000 0001 0100 */
+ {illegal,0, 2, 8}, /* 15: 0100 1000 0001 0101 */
+ {illegal,0, 2, 8}, /* 16: 0100 1000 0001 0110 */
+ {illegal,0, 2, 8}, /* 17: 0100 1000 0001 0111 */
+ {SKN,"NV", 2, 8}, /* 18: 0100 1000 0001 1000 */
+ {illegal,0, 2, 8}, /* 19: 0100 1000 0001 1001 */
+ {SKN,"CY", 2, 8}, /* 1a: 0100 1000 0001 1010 */
+ {SKN,"HC", 2, 8}, /* 1b: 0100 1000 0001 1011 */
+ {SKN,"Z", 2, 8}, /* 1c: 0100 1000 0001 1100 */
+ {illegal,0, 2, 8}, /* 1d: 0100 1000 0001 1101 */
+ {illegal,0, 2, 8}, /* 1e: 0100 1000 0001 1110 */
+ {illegal,0, 2, 8}, /* 1f: 0100 1000 0001 1111 */
+
+ {illegal,0, 2, 8}, /* 20: 0100 1000 0010 0000 */
+ {SLR,"A", 2, 8}, /* 21: 0100 1000 0010 0001 */
+ {SLR,"B", 2, 8}, /* 22: 0100 1000 0010 0010 */
+ {SLR,"C", 2, 8}, /* 23: 0100 1000 0010 0011 */
+ {illegal,0, 2, 8}, /* 24: 0100 1000 0010 0100 */
+ {SLL,"A", 2, 8}, /* 25: 0100 1000 0010 0101 */
+ {SLL,"B", 2, 8}, /* 26: 0100 1000 0010 0110 */
+ {SLL,"C", 2, 8}, /* 27: 0100 1000 0010 0111 */
+ {JEA,0, 2, 8}, /* 28: 0100 1000 0010 1000 */
+ {CALB,0, 2,17}, /* 29: 0100 1000 0010 1001 */
+ {CLC,0, 2, 8}, /* 2a: 0100 1000 0010 1010 */
+ {STC,0, 2, 8}, /* 2b: 0100 1000 0010 1011 */
+ {illegal,0, 2,32}, /* 2c: 0100 1000 0010 1100 */
+ {MUL,"A", 2,32}, /* 2d: 0100 1000 0010 1101 */
+ {MUL,"B", 2,32}, /* 2e: 0100 1000 0010 1110 */
+ {MUL,"C", 2,32}, /* 2f: 0100 1000 0010 1111 */
+
+ {illegal,0, 2, 8}, /* 30: 0100 1000 0011 0000 */
+ {RLR,"A", 2, 8}, /* 31: 0100 1000 0011 0001 */
+ {RLR,"B", 2, 8}, /* 32: 0100 1000 0011 0010 */
+ {RLR,"C", 2, 8}, /* 33: 0100 1000 0011 0011 */
+ {illegal,0, 2, 8}, /* 34: 0100 1000 0011 0100 */
+ {RLL,"A", 2, 8}, /* 35: 0100 1000 0011 0101 */
+ {RLL,"B", 2, 8}, /* 36: 0100 1000 0011 0110 */
+ {RLL,"C", 2, 8}, /* 37: 0100 1000 0011 0111 */
+ {RLD,0, 2,17}, /* 38: 0100 1000 0011 1000 */
+ {RRD,0, 2,17}, /* 39: 0100 1000 0011 1001 */
+ {NEGA,0, 2, 8}, /* 3a: 0100 1000 0011 1010 */
+ {HALT,0, 2,12}, /* 3b: 0100 1000 0011 1011 */
+ {illegal,0, 2,59}, /* 3c: 0100 1000 0011 1100 */
+ {DIV,"A", 2,59}, /* 3d: 0100 1000 0011 1101 */
+ {DIV,"B", 2,59}, /* 3e: 0100 1000 0011 1110 */
+ {DIV,"C", 2,59}, /* 3f: 0100 1000 0011 1111 */
+
+ {SKIT,"NMI", 2, 8}, /* 40: 0100 1000 0100 0000 */
+ {SKIT,"FT0", 2, 8}, /* 41: 0100 1000 0100 0001 */
+ {SKIT,"FT1", 2, 8}, /* 42: 0100 1000 0100 0010 */
+ {SKIT,"F1", 2, 8}, /* 43: 0100 1000 0100 0011 */
+ {SKIT,"F2", 2, 8}, /* 44: 0100 1000 0100 0100 */
+ {SKIT,"FE0", 2, 8}, /* 45: 0100 1000 0100 0101 */
+ {SKIT,"FE1", 2, 8}, /* 46: 0100 1000 0100 0110 */
+ {SKIT,"FEIN", 2, 8}, /* 47: 0100 1000 0100 0111 */
+ {SKIT,"FAD", 2, 8}, /* 48: 0100 1000 0100 1000 */
+ {SKIT,"FSR", 2, 8}, /* 49: 0100 1000 0100 1001 */
+ {SKIT,"FST", 2, 8}, /* 4a: 0100 1000 0100 1010 */
+ {SKIT,"ER", 2, 8}, /* 4b: 0100 1000 0100 1011 */
+ {SKIT,"OV", 2, 8}, /* 4c: 0100 1000 0100 1100 */
+ {illegal,0, 2, 8}, /* 4d: 0100 1000 0100 1101 */
+ {illegal,0, 2, 8}, /* 4e: 0100 1000 0100 1110 */
+ {illegal,0, 2, 8}, /* 4f: 0100 1000 0100 1111 */
+
+ {SKIT,"AN4", 2, 8}, /* 50: 0100 1000 0101 0000 */
+ {SKIT,"AN5", 2, 8}, /* 51: 0100 1000 0101 0001 */
+ {SKIT,"AN6", 2, 8}, /* 52: 0100 1000 0101 0010 */
+ {SKIT,"AN7", 2, 8}, /* 53: 0100 1000 0101 0011 */
+ {SKIT,"SB", 2, 8}, /* 54: 0100 1000 0101 0100 */
+ {illegal,0, 2, 8}, /* 55: 0100 1000 0101 0101 */
+ {illegal,0, 2, 8}, /* 56: 0100 1000 0101 0110 */
+ {illegal,0, 2, 8}, /* 57: 0100 1000 0101 0111 */
+ {illegal,0, 2, 8}, /* 58: 0100 1000 0101 1000 */
+ {illegal,0, 2, 8}, /* 59: 0100 1000 0101 1001 */
+ {illegal,0, 2, 8}, /* 5a: 0100 1000 0101 1010 */
+ {illegal,0, 2, 8}, /* 5b: 0100 1000 0101 1011 */
+ {illegal,0, 2, 8}, /* 5c: 0100 1000 0101 1100 */
+ {illegal,0, 2, 8}, /* 5d: 0100 1000 0101 1101 */
+ {illegal,0, 2, 8}, /* 5e: 0100 1000 0101 1110 */
+ {illegal,0, 2, 8}, /* 5f: 0100 1000 0101 1111 */
+
+ {SKNIT,"NMI", 2, 8}, /* 60: 0100 1000 0110 0000 */
+ {SKNIT,"FT0", 2, 8}, /* 61: 0100 1000 0110 0001 */
+ {SKNIT,"FT1", 2, 8}, /* 62: 0100 1000 0110 0010 */
+ {SKNIT,"F1", 2, 8}, /* 63: 0100 1000 0110 0011 */
+ {SKNIT,"F2", 2, 8}, /* 64: 0100 1000 0110 0100 */
+ {SKNIT,"FE0", 2, 8}, /* 65: 0100 1000 0110 0101 */
+ {SKNIT,"FE1", 2, 8}, /* 66: 0100 1000 0110 0110 */
+ {SKNIT,"FEIN", 2, 8}, /* 67: 0100 1000 0110 0111 */
+ {SKNIT,"FAD", 2, 8}, /* 68: 0100 1000 0110 1000 */
+ {SKNIT,"FSR", 2, 8}, /* 69: 0100 1000 0110 1001 */
+ {SKNIT,"FST", 2, 8}, /* 6a: 0100 1000 0110 1010 */
+ {SKNIT,"ER", 2, 8}, /* 6b: 0100 1000 0110 1011 */
+ {SKNIT,"OV", 2, 8}, /* 6c: 0100 1000 0110 1100 */
+ {illegal,0, 2, 8}, /* 6d: 0100 1000 0110 1101 */
+ {illegal,0, 2, 8}, /* 6e: 0100 1000 0110 1110 */
+ {illegal,0, 2, 8}, /* 6f: 0100 1000 0110 1111 */
+
+ {SKNIT,"AN4", 2, 8}, /* 70: 0100 1000 0111 0000 */
+ {SKNIT,"AN5", 2, 8}, /* 71: 0100 1000 0111 0001 */
+ {SKNIT,"AN6", 2, 8}, /* 72: 0100 1000 0111 0010 */
+ {SKNIT,"AN7", 2, 8}, /* 73: 0100 1000 0111 0011 */
+ {SKNIT,"SB", 2, 8}, /* 74: 0100 1000 0111 0100 */
+ {illegal,0, 2, 8}, /* 75: 0100 1000 0111 0101 */
+ {illegal,0, 2, 8}, /* 76: 0100 1000 0111 0110 */
+ {illegal,0, 2, 8}, /* 77: 0100 1000 0111 0111 */
+ {illegal,0, 2, 8}, /* 78: 0100 1000 0111 1000 */
+ {illegal,0, 2, 8}, /* 79: 0100 1000 0111 1001 */
+ {illegal,0, 2, 8}, /* 7a: 0100 1000 0111 1010 */
+ {illegal,0, 2, 8}, /* 7b: 0100 1000 0111 1011 */
+ {illegal,0, 2, 8}, /* 7c: 0100 1000 0111 1100 */
+ {illegal,0, 2, 8}, /* 7d: 0100 1000 0111 1101 */
+ {illegal,0, 2, 8}, /* 7e: 0100 1000 0111 1110 */
+ {illegal,0, 2, 8}, /* 7f: 0100 1000 0111 1111 */
+
+ {illegal,0, 2, 8}, /* 80: 0100 1000 1000 0000 */
+ {illegal,0, 2, 8}, /* 81: 0100 1000 1000 0001 */
+ {LDEAX,"(DE)", 2,14}, /* 82: 0100 1000 1000 0010 */
+ {LDEAX,"(HL)", 2,14}, /* 83: 0100 1000 1000 0011 */
+ {LDEAX,"(DE++)", 2,14}, /* 84: 0100 1000 1000 0100 */
+ {LDEAX,"(HL++)", 2,14}, /* 85: 0100 1000 1000 0101 */
+ {illegal,0, 2, 8}, /* 86: 0100 1000 1000 0110 */
+ {illegal,0, 2, 8}, /* 87: 0100 1000 1000 0111 */
+ {illegal,0, 2, 8}, /* 88: 0100 1000 1000 1000 */
+ {illegal,0, 2, 8}, /* 89: 0100 1000 1000 1001 */
+ {illegal,0, 2, 8}, /* 8a: 0100 1000 1000 1010 */
+ {LDEAX,"(DE+%b)",3,20}, /* 8b: 0100 1000 1000 1011 xxxx xxxx */
+ {LDEAX,"(HL+A)", 2,20}, /* 8c: 0100 1000 1000 1100 */
+ {LDEAX,"(HL+B)", 2,20}, /* 8d: 0100 1000 1000 1101 */
+ {LDEAX,"(HL+EA)",2,20}, /* 8e: 0100 1000 1000 1110 */
+ {LDEAX,"(HL+%b)",3,20}, /* 8f: 0100 1000 1000 1111 xxxx xxxx */
+
+ {illegal,0, 2, 8}, /* 90: 0100 1000 1000 0000 */
+ {illegal,0, 2, 8}, /* 91: 0100 1000 1000 0001 */
+ {STEAX,"(DE)", 2,14}, /* 92: 0100 1000 1000 0010 */
+ {STEAX,"(HL)", 2,14}, /* 93: 0100 1000 1000 0011 */
+ {STEAX,"(DE++)", 2,14}, /* 94: 0100 1000 1000 0100 */
+ {STEAX,"(HL++)", 2,14}, /* 95: 0100 1000 1000 0101 */
+ {illegal,0, 2, 8}, /* 96: 0100 1000 1000 0110 */
+ {illegal,0, 2, 8}, /* 97: 0100 1000 1000 0111 */
+ {illegal,0, 2, 8}, /* 98: 0100 1000 1000 1000 */
+ {illegal,0, 2, 8}, /* 99: 0100 1000 1000 1001 */
+ {illegal,0, 2, 8}, /* 9a: 0100 1000 1000 1010 */
+ {STEAX,"(DE+%b)",3,20}, /* 9b: 0100 1000 1000 1011 xxxx xxxx */
+ {STEAX,"(HL+A)", 2,20}, /* 9c: 0100 1000 1000 1100 */
+ {STEAX,"(HL+B)", 2,20}, /* 9d: 0100 1000 1000 1101 */
+ {STEAX,"(HL+EA)",2,20}, /* 9e: 0100 1000 1000 1110 */
+ {STEAX,"(HL+%b)",3,20}, /* 9f: 0100 1000 1000 1111 xxxx xxxx */
+
+ {DSLR,"EA", 2, 8}, /* a0: 0100 1000 1010 0000 */
+ {illegal,0, 2, 8}, /* a1: 0100 1000 1010 0001 */
+ {illegal,0, 2, 8}, /* a2: 0100 1000 1010 0010 */
+ {illegal,0, 2, 8}, /* a3: 0100 1000 1010 0011 */
+ {DSLL,"EA", 2, 8}, /* a4: 0100 1000 1010 0100 */
+ {illegal,0, 2, 8}, /* a5: 0100 1000 1010 0101 */
+ {illegal,0, 2, 8}, /* a6: 0100 1000 1010 0110 */
+ {illegal,0, 2, 8}, /* a7: 0100 1000 1010 0111 */
+ {TABLE,0, 2,17}, /* a8: 0100 1000 1010 1000 */
+ {illegal,0, 2, 8}, /* a9: 0100 1000 1010 1001 */
+ {CMC,0, 2, 8}, /* aa: 0100 1000 1010 1010 */ /* 7807 */
+ {illegal,0, 2, 8}, /* ab: 0100 1000 1010 1011 */
+ {EXA,0, 2, 8}, /* ac: 0100 1000 1010 1100 */ /* 7807 */
+ {EXR,0, 2, 8}, /* ad: 0100 1000 1010 1101 */ /* 7807 */
+ {EXH,0, 2, 8}, /* ae: 0100 1000 1010 1110 */ /* 7807 */
+ {EXX,0, 2, 8}, /* af: 0100 1000 1010 1111 */ /* 7807 */
+
+ {DRLR,"EA", 2, 8}, /* b0: 0100 1000 1011 0000 */
+ {illegal,0, 2, 8}, /* b1: 0100 1000 1011 0001 */
+ {illegal,0, 2, 8}, /* b2: 0100 1000 1011 0010 */
+ {illegal,0, 2, 8}, /* b3: 0100 1000 1011 0011 */
+ {DRLL,"EA", 2, 8}, /* b4: 0100 1000 1011 0100 */
+ {illegal,0, 2, 8}, /* b5: 0100 1000 1011 0101 */
+ {illegal,0, 2, 8}, /* b6: 0100 1000 1011 0110 */
+ {illegal,0, 2, 8}, /* b7: 0100 1000 1011 0111 */
+ {illegal,0, 2, 8}, /* b8: 0100 1000 1011 1000 */
+ {illegal,0, 2, 8}, /* b9: 0100 1000 1011 1001 */
+ {illegal,0, 2, 8}, /* ba: 0100 1000 1011 1010 */
+ {illegal,0, 2, 8}, /* bb: 0100 1000 1011 1011 */
+ {illegal,0, 2, 8}, /* bc: 0100 1000 1011 1100 */
+ {illegal,0, 2, 8}, /* bd: 0100 1000 1011 1101 */
+ {illegal,0, 2, 8}, /* be: 0100 1000 1011 1110 */
+ {illegal,0, 2, 8}, /* bf: 0100 1000 1011 1111 */
+
+ {DMOV,"EA,ECNT", 2,14}, /* c0: 0100 1000 1100 0000 */
+ {DMOV,"EA,ECPT0",2,14}, /* c1: 0100 1000 1100 0001 */ /* 7807 */
+ {DMOV,"EA,ECPT1",2,14}, /* c2: 0100 1000 1100 0010 */ /* 7807 */
+ {illegal,0, 2, 8}, /* c3: 0100 1000 1100 0011 */
+ {illegal,0, 2, 8}, /* c4: 0100 1000 1100 0100 */
+ {illegal,0, 2, 8}, /* c5: 0100 1000 1100 0101 */
+ {illegal,0, 2, 8}, /* c6: 0100 1000 1100 0110 */
+ {illegal,0, 2, 8}, /* c7: 0100 1000 1100 0111 */
+ {illegal,0, 2, 8}, /* c8: 0100 1000 1100 1000 */
+ {illegal,0, 2, 8}, /* c9: 0100 1000 1100 1001 */
+ {illegal,0, 2, 8}, /* ca: 0100 1000 1100 1010 */
+ {illegal,0, 2, 8}, /* cb: 0100 1000 1100 1011 */
+ {illegal,0, 2, 8}, /* cc: 0100 1000 1100 1100 */
+ {illegal,0, 2, 8}, /* cd: 0100 1000 1100 1101 */
+ {illegal,0, 2, 8}, /* ce: 0100 1000 1100 1110 */
+ {illegal,0, 2, 8}, /* cf: 0100 1000 1100 1111 */
+
+ {illegal,0, 2, 8}, /* d0: 0100 1000 1101 0000 */
+ {illegal,0, 2, 8}, /* d1: 0100 1000 1101 0001 */
+ {DMOV,"ETM0,EA", 2,14}, /* d2: 0100 1000 1101 0010 */
+ {DMOV,"ETM1,EA", 2,14}, /* d3: 0100 1000 1101 0011 */
+ {illegal,0, 2, 8}, /* d4: 0100 1000 1101 0100 */
+ {illegal,0, 2, 8}, /* d5: 0100 1000 1101 0101 */
+ {illegal,0, 2, 8}, /* d6: 0100 1000 1101 0110 */
+ {illegal,0, 2, 8}, /* d7: 0100 1000 1101 0111 */
+ {illegal,0, 2, 8}, /* d8: 0100 1000 1101 1000 */
+ {illegal,0, 2, 8}, /* d9: 0100 1000 1101 1001 */
+ {illegal,0, 2, 8}, /* da: 0100 1000 1101 1010 */
+ {illegal,0, 2, 8}, /* db: 0100 1000 1101 1011 */
+ {illegal,0, 2, 8}, /* dc: 0100 1000 1101 1100 */
+ {illegal,0, 2, 8}, /* dd: 0100 1000 1101 1101 */
+ {illegal,0, 2, 8}, /* de: 0100 1000 1101 1110 */
+ {illegal,0, 2, 8}, /* df: 0100 1000 1101 1111 */
+
+ {illegal,0, 2, 8}, /* e0: 0100 1000 1110 0000 */
+ {illegal,0, 2, 8}, /* e1: 0100 1000 1110 0001 */
+ {illegal,0, 2, 8}, /* e2: 0100 1000 1110 0010 */
+ {illegal,0, 2, 8}, /* e3: 0100 1000 1110 0011 */
+ {illegal,0, 2, 8}, /* e4: 0100 1000 1110 0100 */
+ {illegal,0, 2, 8}, /* e5: 0100 1000 1110 0101 */
+ {illegal,0, 2, 8}, /* e6: 0100 1000 1110 0110 */
+ {illegal,0, 2, 8}, /* e7: 0100 1000 1110 0111 */
+ {illegal,0, 2, 8}, /* e8: 0100 1000 1110 1000 */
+ {illegal,0, 2, 8}, /* e9: 0100 1000 1110 1001 */
+ {illegal,0, 2, 8}, /* ea: 0100 1000 1110 1010 */
+ {illegal,0, 2, 8}, /* eb: 0100 1000 1110 1011 */
+ {illegal,0, 2, 8}, /* ec: 0100 1000 1110 1100 */
+ {illegal,0, 2, 8}, /* ed: 0100 1000 1110 1101 */
+ {illegal,0, 2, 8}, /* ee: 0100 1000 1110 1110 */
+ {illegal,0, 2, 8}, /* ef: 0100 1000 1110 1111 */
+
+ {illegal,0, 2, 8}, /* f0: 0100 1000 1111 0000 */
+ {illegal,0, 2, 8}, /* f1: 0100 1000 1111 0001 */
+ {illegal,0, 2, 8}, /* f2: 0100 1000 1111 0010 */
+ {illegal,0, 2, 8}, /* f3: 0100 1000 1111 0011 */
+ {illegal,0, 2, 8}, /* f4: 0100 1000 1111 0100 */
+ {illegal,0, 2, 8}, /* f5: 0100 1000 1111 0101 */
+ {illegal,0, 2, 8}, /* f6: 0100 1000 1111 0110 */
+ {illegal,0, 2, 8}, /* f7: 0100 1000 1111 0111 */
+ {illegal,0, 2, 8}, /* f8: 0100 1000 1111 1000 */
+ {illegal,0, 2, 8}, /* f9: 0100 1000 1111 1001 */
+ {illegal,0, 2, 8}, /* fa: 0100 1000 1111 1010 */
+ {illegal,0, 2, 8}, /* fb: 0100 1000 1111 1011 */
+ {illegal,0, 2, 8}, /* fc: 0100 1000 1111 1100 */
+ {illegal,0, 2, 8}, /* fd: 0100 1000 1111 1101 */
+ {illegal,0, 2, 8}, /* fe: 0100 1000 1111 1110 */
+ {illegal,0, 2, 8} /* ff: 0100 1000 1111 1111 */
+};
+
+/* prefix 4C */
+static struct dasm_s dasm4C_7810[256] =
+{
+ {illegal,0, 2, 8}, /* 00: 0100 1100 0000 0000 */
+ {illegal,0, 2, 8}, /* 01: 0100 1100 0000 0001 */
+ {illegal,0, 2, 8}, /* 02: 0100 1100 0000 0010 */
+ {illegal,0, 2, 8}, /* 03: 0100 1100 0000 0011 */
+ {illegal,0, 2, 8}, /* 04: 0100 1100 0000 0100 */
+ {illegal,0, 2, 8}, /* 05: 0100 1100 0000 0101 */
+ {illegal,0, 2, 8}, /* 06: 0100 1100 0000 0110 */
+ {illegal,0, 2, 8}, /* 07: 0100 1100 0000 0111 */
+ {illegal,0, 2, 8}, /* 08: 0100 1100 0000 1000 */
+ {illegal,0, 2, 8}, /* 09: 0100 1100 0000 1001 */
+ {illegal,0, 2, 8}, /* 0a: 0100 1100 0000 1010 */
+ {illegal,0, 2, 8}, /* 0b: 0100 1100 0000 1011 */
+ {illegal,0, 2, 8}, /* 0c: 0100 1100 0000 1100 */
+ {illegal,0, 2, 8}, /* 0d: 0100 1100 0000 1101 */
+ {illegal,0, 2, 8}, /* 0e: 0100 1100 0000 1110 */
+ {illegal,0, 2, 8}, /* 0f: 0100 1100 0000 1111 */
+
+ {illegal,0, 2, 8}, /* 10: 0100 1100 0001 0000 */
+ {illegal,0, 2, 8}, /* 11: 0100 1100 0001 0001 */
+ {illegal,0, 2, 8}, /* 12: 0100 1100 0001 0010 */
+ {illegal,0, 2, 8}, /* 13: 0100 1100 0001 0011 */
+ {illegal,0, 2, 8}, /* 14: 0100 1100 0001 0100 */
+ {illegal,0, 2, 8}, /* 15: 0100 1100 0001 0101 */
+ {illegal,0, 2, 8}, /* 16: 0100 1100 0001 0110 */
+ {illegal,0, 2, 8}, /* 17: 0100 1100 0001 0111 */
+ {illegal,0, 2, 8}, /* 18: 0100 1100 0001 1000 */
+ {illegal,0, 2, 8}, /* 19: 0100 1100 0001 1001 */
+ {illegal,0, 2, 8}, /* 1a: 0100 1100 0001 1010 */
+ {illegal,0, 2, 8}, /* 1b: 0100 1100 0001 1011 */
+ {illegal,0, 2, 8}, /* 1c: 0100 1100 0001 1100 */
+ {illegal,0, 2, 8}, /* 1d: 0100 1100 0001 1101 */
+ {illegal,0, 2, 8}, /* 1e: 0100 1100 0001 1110 */
+ {illegal,0, 2, 8}, /* 1f: 0100 1100 0001 1111 */
+
+ {illegal,0, 2, 8}, /* 20: 0100 1100 0010 0000 */
+ {illegal,0, 2, 8}, /* 21: 0100 1100 0010 0001 */
+ {illegal,0, 2, 8}, /* 22: 0100 1100 0010 0010 */
+ {illegal,0, 2, 8}, /* 23: 0100 1100 0010 0011 */
+ {illegal,0, 2, 8}, /* 24: 0100 1100 0010 0100 */
+ {illegal,0, 2, 8}, /* 25: 0100 1100 0010 0101 */
+ {illegal,0, 2, 8}, /* 26: 0100 1100 0010 0110 */
+ {illegal,0, 2, 8}, /* 27: 0100 1100 0010 0111 */
+ {illegal,0, 2, 8}, /* 28: 0100 1100 0010 1000 */
+ {illegal,0, 2, 8}, /* 29: 0100 1100 0010 1001 */
+ {illegal,0, 2, 8}, /* 2a: 0100 1100 0010 1010 */
+ {illegal,0, 2, 8}, /* 2b: 0100 1100 0010 1011 */
+ {illegal,0, 2, 8}, /* 2c: 0100 1100 0010 1100 */
+ {illegal,0, 2, 8}, /* 2d: 0100 1100 0010 1101 */
+ {illegal,0, 2, 8}, /* 2e: 0100 1100 0010 1110 */
+ {illegal,0, 2, 8}, /* 2f: 0100 1100 0010 1111 */
+
+ {illegal,0, 2, 8}, /* 30: 0100 1100 0011 0000 */
+ {illegal,0, 2, 8}, /* 31: 0100 1100 0011 0001 */
+ {illegal,0, 2, 8}, /* 32: 0100 1100 0011 0010 */
+ {illegal,0, 2, 8}, /* 33: 0100 1100 0011 0011 */
+ {illegal,0, 2, 8}, /* 34: 0100 1100 0011 0100 */
+ {illegal,0, 2, 8}, /* 35: 0100 1100 0011 0101 */
+ {illegal,0, 2, 8}, /* 36: 0100 1100 0011 0110 */
+ {illegal,0, 2, 8}, /* 37: 0100 1100 0011 0111 */
+ {illegal,0, 2, 8}, /* 38: 0100 1100 0011 1000 */
+ {illegal,0, 2, 8}, /* 39: 0100 1100 0011 1001 */
+ {illegal,0, 2, 8}, /* 3a: 0100 1100 0011 1010 */
+ {illegal,0, 2, 8}, /* 3b: 0100 1100 0011 1011 */
+ {illegal,0, 2, 8}, /* 3c: 0100 1100 0011 1100 */
+ {illegal,0, 2, 8}, /* 3d: 0100 1100 0011 1101 */
+ {illegal,0, 2, 8}, /* 3e: 0100 1100 0011 1110 */
+ {illegal,0, 2, 8}, /* 3f: 0100 1100 0011 1111 */
+
+ {illegal,0, 2, 8}, /* 40: 0100 1100 0100 0000 */
+ {illegal,0, 2, 8}, /* 41: 0100 1100 0100 0001 */
+ {illegal,0, 2, 8}, /* 42: 0100 1100 0100 0010 */
+ {illegal,0, 2, 8}, /* 43: 0100 1100 0100 0011 */
+ {illegal,0, 2, 8}, /* 44: 0100 1100 0100 0100 */
+ {illegal,0, 2, 8}, /* 45: 0100 1100 0100 0101 */
+ {illegal,0, 2, 8}, /* 46: 0100 1100 0100 0110 */
+ {illegal,0, 2, 8}, /* 47: 0100 1100 0100 0111 */
+ {illegal,0, 2, 8}, /* 48: 0100 1100 0100 1000 */
+ {illegal,0, 2, 8}, /* 49: 0100 1100 0100 1001 */
+ {illegal,0, 2, 8}, /* 4a: 0100 1100 0100 1010 */
+ {illegal,0, 2, 8}, /* 4b: 0100 1100 0100 1011 */
+ {illegal,0, 2, 8}, /* 4c: 0100 1100 0100 1100 */
+ {illegal,0, 2, 8}, /* 4d: 0100 1100 0100 1101 */
+ {illegal,0, 2, 8}, /* 4e: 0100 1100 0100 1110 */
+ {illegal,0, 2, 8}, /* 4f: 0100 1100 0100 1111 */
+
+ {illegal,0, 2, 8}, /* 50: 0100 1100 0101 0000 */
+ {illegal,0, 2, 8}, /* 51: 0100 1100 0101 0001 */
+ {illegal,0, 2, 8}, /* 52: 0100 1100 0101 0010 */
+ {illegal,0, 2, 8}, /* 53: 0100 1100 0101 0011 */
+ {illegal,0, 2, 8}, /* 54: 0100 1100 0101 0100 */
+ {illegal,0, 2, 8}, /* 55: 0100 1100 0101 0101 */
+ {illegal,0, 2, 8}, /* 56: 0100 1100 0101 0110 */
+ {illegal,0, 2, 8}, /* 57: 0100 1100 0101 0111 */
+ {illegal,0, 2, 8}, /* 58: 0100 1100 0101 1000 */
+ {illegal,0, 2, 8}, /* 59: 0100 1100 0101 1001 */
+ {illegal,0, 2, 8}, /* 5a: 0100 1100 0101 1010 */
+ {illegal,0, 2, 8}, /* 5b: 0100 1100 0101 1011 */
+ {illegal,0, 2, 8}, /* 5c: 0100 1100 0101 1100 */
+ {illegal,0, 2, 8}, /* 5d: 0100 1100 0101 1101 */
+ {illegal,0, 2, 8}, /* 5e: 0100 1100 0101 1110 */
+ {illegal,0, 2, 8}, /* 5f: 0100 1100 0101 1111 */
+
+ {illegal,0, 2, 8}, /* 60: 0100 1100 0110 0000 */
+ {illegal,0, 2, 8}, /* 61: 0100 1100 0110 0001 */
+ {illegal,0, 2, 8}, /* 62: 0100 1100 0110 0010 */
+ {illegal,0, 2, 8}, /* 63: 0100 1100 0110 0011 */
+ {illegal,0, 2, 8}, /* 64: 0100 1100 0110 0100 */
+ {illegal,0, 2, 8}, /* 65: 0100 1100 0110 0101 */
+ {illegal,0, 2, 8}, /* 66: 0100 1100 0110 0110 */
+ {illegal,0, 2, 8}, /* 67: 0100 1100 0110 0111 */
+ {illegal,0, 2, 8}, /* 68: 0100 1100 0110 1000 */
+ {illegal,0, 2, 8}, /* 69: 0100 1100 0110 1001 */
+ {illegal,0, 2, 8}, /* 6a: 0100 1100 0110 1010 */
+ {illegal,0, 2, 8}, /* 6b: 0100 1100 0110 1011 */
+ {illegal,0, 2, 8}, /* 6c: 0100 1100 0110 1100 */
+ {illegal,0, 2, 8}, /* 6d: 0100 1100 0110 1101 */
+ {illegal,0, 2, 8}, /* 6e: 0100 1100 0110 1110 */
+ {illegal,0, 2, 8}, /* 6f: 0100 1100 0110 1111 */
+
+ {illegal,0, 2, 8}, /* 70: 0100 1100 0111 0000 */
+ {illegal,0, 2, 8}, /* 71: 0100 1100 0111 0001 */
+ {illegal,0, 2, 8}, /* 72: 0100 1100 0111 0010 */
+ {illegal,0, 2, 8}, /* 73: 0100 1100 0111 0011 */
+ {illegal,0, 2, 8}, /* 74: 0100 1100 0111 0100 */
+ {illegal,0, 2, 8}, /* 75: 0100 1100 0111 0101 */
+ {illegal,0, 2, 8}, /* 76: 0100 1100 0111 0110 */
+ {illegal,0, 2, 8}, /* 77: 0100 1100 0111 0111 */
+ {illegal,0, 2, 8}, /* 78: 0100 1100 0111 1000 */
+ {illegal,0, 2, 8}, /* 79: 0100 1100 0111 1001 */
+ {illegal,0, 2, 8}, /* 7a: 0100 1100 0111 1010 */
+ {illegal,0, 2, 8}, /* 7b: 0100 1100 0111 1011 */
+ {illegal,0, 2, 8}, /* 7c: 0100 1100 0111 1100 */
+ {illegal,0, 2, 8}, /* 7d: 0100 1100 0111 1101 */
+ {illegal,0, 2, 8}, /* 7e: 0100 1100 0111 1110 */
+ {illegal,0, 2, 8}, /* 7f: 0100 1100 0111 1111 */
+
+ {illegal,0, 2, 8}, /* 80: 0100 1100 1000 0000 */
+ {illegal,0, 2, 8}, /* 81: 0100 1100 1000 0001 */
+ {illegal,0, 2, 8}, /* 82: 0100 1100 1000 0010 */
+ {illegal,0, 2, 8}, /* 83: 0100 1100 1000 0011 */
+ {illegal,0, 2, 8}, /* 84: 0100 1100 1000 0100 */
+ {illegal,0, 2, 8}, /* 85: 0100 1100 1000 0101 */
+ {illegal,0, 2, 8}, /* 86: 0100 1100 1000 0110 */
+ {illegal,0, 2, 8}, /* 87: 0100 1100 1000 0111 */
+ {illegal,0, 2, 8}, /* 88: 0100 1100 1000 1000 */
+ {illegal,0, 2, 8}, /* 89: 0100 1100 1000 1001 */
+ {illegal,0, 2, 8}, /* 8a: 0100 1100 1000 1010 */
+ {illegal,0, 2, 8}, /* 8b: 0100 1100 1000 1011 */
+ {illegal,0, 2, 8}, /* 8c: 0100 1100 1000 1100 */
+ {illegal,0, 2, 8}, /* 8d: 0100 1100 1000 1101 */
+ {illegal,0, 2, 8}, /* 8e: 0100 1100 1000 1110 */
+ {illegal,0, 2, 8}, /* 8f: 0100 1100 1000 1111 */
+
+ {illegal,0, 2, 8}, /* 90: 0100 1100 1001 0000 */
+ {illegal,0, 2, 8}, /* 91: 0100 1100 1001 0001 */
+ {illegal,0, 2, 8}, /* 92: 0100 1100 1001 0010 */
+ {illegal,0, 2, 8}, /* 93: 0100 1100 1001 0011 */
+ {illegal,0, 2, 8}, /* 94: 0100 1100 1001 0100 */
+ {illegal,0, 2, 8}, /* 95: 0100 1100 1001 0101 */
+ {illegal,0, 2, 8}, /* 96: 0100 1100 1001 0110 */
+ {illegal,0, 2, 8}, /* 97: 0100 1100 1001 0111 */
+ {illegal,0, 2, 8}, /* 98: 0100 1100 1001 1000 */
+ {illegal,0, 2, 8}, /* 99: 0100 1100 1001 1001 */
+ {illegal,0, 2, 8}, /* 9a: 0100 1100 1001 1010 */
+ {illegal,0, 2, 8}, /* 9b: 0100 1100 1001 1011 */
+ {illegal,0, 2, 8}, /* 9c: 0100 1100 1001 1100 */
+ {illegal,0, 2, 8}, /* 9d: 0100 1100 1001 1101 */
+ {illegal,0, 2, 8}, /* 9e: 0100 1100 1001 1110 */
+ {illegal,0, 2, 8}, /* 9f: 0100 1100 1001 1111 */
+
+ {illegal,0, 2, 8}, /* a0: 0100 1100 1010 0000 */
+ {illegal,0, 2, 8}, /* a1: 0100 1100 1010 0001 */
+ {illegal,0, 2, 8}, /* a2: 0100 1100 1010 0010 */
+ {illegal,0, 2, 8}, /* a3: 0100 1100 1010 0011 */
+ {illegal,0, 2, 8}, /* a4: 0100 1100 1010 0100 */
+ {illegal,0, 2, 8}, /* a5: 0100 1100 1010 0101 */
+ {illegal,0, 2, 8}, /* a6: 0100 1100 1010 0110 */
+ {illegal,0, 2, 8}, /* a7: 0100 1100 1010 0111 */
+ {illegal,0, 2, 8}, /* a8: 0100 1100 1010 1000 */
+ {illegal,0, 2, 8}, /* a9: 0100 1100 1010 1001 */
+ {illegal,0, 2, 8}, /* aa: 0100 1100 1010 1010 */
+ {illegal,0, 2, 8}, /* ab: 0100 1100 1010 1011 */
+ {illegal,0, 2, 8}, /* ac: 0100 1100 1010 1100 */
+ {illegal,0, 2, 8}, /* ad: 0100 1100 1010 1101 */
+ {illegal,0, 2, 8}, /* ae: 0100 1100 1010 1110 */
+ {illegal,0, 2, 8}, /* af: 0100 1100 1010 1111 */
+
+ {illegal,0, 2, 8}, /* b0: 0100 1100 1011 0000 */
+ {illegal,0, 2, 8}, /* b1: 0100 1100 1011 0001 */
+ {illegal,0, 2, 8}, /* b2: 0100 1100 1011 0010 */
+ {illegal,0, 2, 8}, /* b3: 0100 1100 1011 0011 */
+ {illegal,0, 2, 8}, /* b4: 0100 1100 1011 0100 */
+ {illegal,0, 2, 8}, /* b5: 0100 1100 1011 0101 */
+ {illegal,0, 2, 8}, /* b6: 0100 1100 1011 0110 */
+ {illegal,0, 2, 8}, /* b7: 0100 1100 1011 0111 */
+ {illegal,0, 2, 8}, /* b8: 0100 1100 1011 1000 */
+ {illegal,0, 2, 8}, /* b9: 0100 1100 1011 1001 */
+ {illegal,0, 2, 8}, /* ba: 0100 1100 1011 1010 */
+ {illegal,0, 2, 8}, /* bb: 0100 1100 1011 1011 */
+ {illegal,0, 2, 8}, /* bc: 0100 1100 1011 1100 */
+ {illegal,0, 2, 8}, /* bd: 0100 1100 1011 1101 */
+ {illegal,0, 2, 8}, /* be: 0100 1100 1011 1110 */
+ {illegal,0, 2, 8}, /* bf: 0100 1100 1011 1111 */
+
+ {MOV,"A,PA", 2,10}, /* c0: 0100 1100 1100 0000 */
+ {MOV,"A,PB", 2,10}, /* c1: 0100 1100 1100 0001 */
+ {MOV,"A,PC", 2,10}, /* c2: 0100 1100 1100 0010 */
+ {MOV,"A,PD", 2,10}, /* c3: 0100 1100 1100 0011 */
+ {illegal,0, 2,10}, /* c4: 0100 1100 1100 0100 */
+ {MOV,"A,PF", 2,10}, /* c5: 0100 1100 1100 0101 */
+ {MOV,"A,MKH", 2,10}, /* c6: 0100 1100 1100 0110 */
+ {MOV,"A,MKL", 2,10}, /* c7: 0100 1100 1100 0111 */
+ {MOV,"A,ANM", 2,10}, /* c8: 0100 1100 1100 1000 */ /* 7810 */
+ {MOV,"A,SMH", 2,10}, /* c9: 0100 1100 1100 1001 */
+ {illegal,0, 2,10}, /* ca: 0100 1100 1100 1010 */
+ {MOV,"A,EOM", 2,10}, /* cb: 0100 1100 1100 1011 */
+ {illegal,0, 2,10}, /* cc: 0100 1100 1100 1100 */
+ {MOV,"A,TMM", 2,10}, /* cd: 0100 1100 1100 1101 */
+ {illegal,0, 2,10}, /* ce: 0100 1100 1100 1110 */
+ {illegal,0, 2,10}, /* cf: 0100 1100 1100 1111 */
+
+ {illegal,0, 2,10}, /* d0: 0100 1100 1101 0000 */
+ {illegal,0, 2,10}, /* d1: 0100 1100 1101 0001 */
+ {illegal,0, 2,10}, /* d2: 0100 1100 1101 0010 */
+ {illegal,0, 2,10}, /* d3: 0100 1100 1101 0011 */
+ {illegal,0, 2,10}, /* d4: 0100 1100 1101 0100 */
+ {illegal,0, 2,10}, /* d5: 0100 1100 1101 0101 */
+ {illegal,0, 2,10}, /* d6: 0100 1100 1101 0110 */
+ {illegal,0, 2,10}, /* d7: 0100 1100 1101 0111 */
+ {illegal,0, 2,10}, /* d8: 0100 1100 1101 1000 */
+ {MOV,"A,RXB", 2,10}, /* d9: 0100 1100 1101 1001 */
+ {illegal,0, 2,10}, /* da: 0100 1100 1101 1010 */
+ {illegal,0, 2,10}, /* db: 0100 1100 1101 1011 */
+ {illegal,0, 2,10}, /* dc: 0100 1100 1101 1100 */
+ {illegal,0, 2,10}, /* dd: 0100 1100 1101 1101 */
+ {illegal,0, 2,10}, /* de: 0100 1100 1101 1110 */
+ {illegal,0, 2,10}, /* df: 0100 1100 1101 1111 */
+
+ {MOV,"A,CR0", 2,10}, /* e0: 0100 1100 1110 0000 */ /* 7810 */
+ {MOV,"A,CR1", 2,10}, /* e1: 0100 1100 1110 0001 */ /* 7810 */
+ {MOV,"A,CR2", 2,10}, /* e2: 0100 1100 1110 0010 */ /* 7810 */
+ {MOV,"A,CR3", 2,10}, /* e3: 0100 1100 1110 0011 */ /* 7810 */
+ {illegal,0, 2,10}, /* e4: 0100 1100 1110 0100 */
+ {illegal,0, 2,10}, /* e5: 0100 1100 1110 0101 */
+ {illegal,0, 2,10}, /* e6: 0100 1100 1110 0110 */
+ {illegal,0, 2,10}, /* e7: 0100 1100 1110 0111 */
+ {illegal,0, 2,10}, /* e8: 0100 1100 1110 1000 */
+ {illegal,0, 2,10}, /* e9: 0100 1100 1110 1001 */
+ {illegal,0, 2,10}, /* ea: 0100 1100 1110 1010 */
+ {illegal,0, 2,10}, /* eb: 0100 1100 1110 1011 */
+ {illegal,0, 2,10}, /* ec: 0100 1100 1110 1100 */
+ {illegal,0, 2,10}, /* ed: 0100 1100 1110 1101 */
+ {illegal,0, 2,10}, /* ee: 0100 1100 1110 1110 */
+ {illegal,0, 2,10}, /* ef: 0100 1100 1110 1111 */
+
+ {illegal,0, 2,10}, /* f0: 0100 1100 1111 0000 */
+ {illegal,0, 2,10}, /* f1: 0100 1100 1111 0001 */
+ {illegal,0, 2,10}, /* f2: 0100 1100 1111 0010 */
+ {illegal,0, 2,10}, /* f3: 0100 1100 1111 0011 */
+ {illegal,0, 2,10}, /* f4: 0100 1100 1111 0100 */
+ {illegal,0, 2,10}, /* f5: 0100 1100 1111 0101 */
+ {illegal,0, 2,10}, /* f6: 0100 1100 1111 0110 */
+ {illegal,0, 2,10}, /* f7: 0100 1100 1111 0111 */
+ {illegal,0, 2,10}, /* f8: 0100 1100 1111 1000 */
+ {illegal,0, 2,10}, /* f9: 0100 1100 1111 1001 */
+ {illegal,0, 2,10}, /* fa: 0100 1100 1111 1010 */
+ {illegal,0, 2,10}, /* fb: 0100 1100 1111 1011 */
+ {illegal,0, 2,10}, /* fc: 0100 1100 1111 1100 */
+ {illegal,0, 2,10}, /* fd: 0100 1100 1111 1101 */
+ {illegal,0, 2,10}, /* fe: 0100 1100 1111 1110 */
+ {illegal,0, 2,10} /* ff: 0100 1100 1111 1111 */
+};
+
+static struct dasm_s dasm4C_7807[256] =
+{
+ {illegal,0, 2, 8}, /* 00: 0100 1100 0000 0000 */
+ {illegal,0, 2, 8}, /* 01: 0100 1100 0000 0001 */
+ {illegal,0, 2, 8}, /* 02: 0100 1100 0000 0010 */
+ {illegal,0, 2, 8}, /* 03: 0100 1100 0000 0011 */
+ {illegal,0, 2, 8}, /* 04: 0100 1100 0000 0100 */
+ {illegal,0, 2, 8}, /* 05: 0100 1100 0000 0101 */
+ {illegal,0, 2, 8}, /* 06: 0100 1100 0000 0110 */
+ {illegal,0, 2, 8}, /* 07: 0100 1100 0000 0111 */
+ {illegal,0, 2, 8}, /* 08: 0100 1100 0000 1000 */
+ {illegal,0, 2, 8}, /* 09: 0100 1100 0000 1001 */
+ {illegal,0, 2, 8}, /* 0a: 0100 1100 0000 1010 */
+ {illegal,0, 2, 8}, /* 0b: 0100 1100 0000 1011 */
+ {illegal,0, 2, 8}, /* 0c: 0100 1100 0000 1100 */
+ {illegal,0, 2, 8}, /* 0d: 0100 1100 0000 1101 */
+ {illegal,0, 2, 8}, /* 0e: 0100 1100 0000 1110 */
+ {illegal,0, 2, 8}, /* 0f: 0100 1100 0000 1111 */
+
+ {illegal,0, 2, 8}, /* 10: 0100 1100 0001 0000 */
+ {illegal,0, 2, 8}, /* 11: 0100 1100 0001 0001 */
+ {illegal,0, 2, 8}, /* 12: 0100 1100 0001 0010 */
+ {illegal,0, 2, 8}, /* 13: 0100 1100 0001 0011 */
+ {illegal,0, 2, 8}, /* 14: 0100 1100 0001 0100 */
+ {illegal,0, 2, 8}, /* 15: 0100 1100 0001 0101 */
+ {illegal,0, 2, 8}, /* 16: 0100 1100 0001 0110 */
+ {illegal,0, 2, 8}, /* 17: 0100 1100 0001 0111 */
+ {illegal,0, 2, 8}, /* 18: 0100 1100 0001 1000 */
+ {illegal,0, 2, 8}, /* 19: 0100 1100 0001 1001 */
+ {illegal,0, 2, 8}, /* 1a: 0100 1100 0001 1010 */
+ {illegal,0, 2, 8}, /* 1b: 0100 1100 0001 1011 */
+ {illegal,0, 2, 8}, /* 1c: 0100 1100 0001 1100 */
+ {illegal,0, 2, 8}, /* 1d: 0100 1100 0001 1101 */
+ {illegal,0, 2, 8}, /* 1e: 0100 1100 0001 1110 */
+ {illegal,0, 2, 8}, /* 1f: 0100 1100 0001 1111 */
+
+ {illegal,0, 2, 8}, /* 20: 0100 1100 0010 0000 */
+ {illegal,0, 2, 8}, /* 21: 0100 1100 0010 0001 */
+ {illegal,0, 2, 8}, /* 22: 0100 1100 0010 0010 */
+ {illegal,0, 2, 8}, /* 23: 0100 1100 0010 0011 */
+ {illegal,0, 2, 8}, /* 24: 0100 1100 0010 0100 */
+ {illegal,0, 2, 8}, /* 25: 0100 1100 0010 0101 */
+ {illegal,0, 2, 8}, /* 26: 0100 1100 0010 0110 */
+ {illegal,0, 2, 8}, /* 27: 0100 1100 0010 0111 */
+ {illegal,0, 2, 8}, /* 28: 0100 1100 0010 1000 */
+ {illegal,0, 2, 8}, /* 29: 0100 1100 0010 1001 */
+ {illegal,0, 2, 8}, /* 2a: 0100 1100 0010 1010 */
+ {illegal,0, 2, 8}, /* 2b: 0100 1100 0010 1011 */
+ {illegal,0, 2, 8}, /* 2c: 0100 1100 0010 1100 */
+ {illegal,0, 2, 8}, /* 2d: 0100 1100 0010 1101 */
+ {illegal,0, 2, 8}, /* 2e: 0100 1100 0010 1110 */
+ {illegal,0, 2, 8}, /* 2f: 0100 1100 0010 1111 */
+
+ {illegal,0, 2, 8}, /* 30: 0100 1100 0011 0000 */
+ {illegal,0, 2, 8}, /* 31: 0100 1100 0011 0001 */
+ {illegal,0, 2, 8}, /* 32: 0100 1100 0011 0010 */
+ {illegal,0, 2, 8}, /* 33: 0100 1100 0011 0011 */
+ {illegal,0, 2, 8}, /* 34: 0100 1100 0011 0100 */
+ {illegal,0, 2, 8}, /* 35: 0100 1100 0011 0101 */
+ {illegal,0, 2, 8}, /* 36: 0100 1100 0011 0110 */
+ {illegal,0, 2, 8}, /* 37: 0100 1100 0011 0111 */
+ {illegal,0, 2, 8}, /* 38: 0100 1100 0011 1000 */
+ {illegal,0, 2, 8}, /* 39: 0100 1100 0011 1001 */
+ {illegal,0, 2, 8}, /* 3a: 0100 1100 0011 1010 */
+ {illegal,0, 2, 8}, /* 3b: 0100 1100 0011 1011 */
+ {illegal,0, 2, 8}, /* 3c: 0100 1100 0011 1100 */
+ {illegal,0, 2, 8}, /* 3d: 0100 1100 0011 1101 */
+ {illegal,0, 2, 8}, /* 3e: 0100 1100 0011 1110 */
+ {illegal,0, 2, 8}, /* 3f: 0100 1100 0011 1111 */
+
+ {illegal,0, 2, 8}, /* 40: 0100 1100 0100 0000 */
+ {illegal,0, 2, 8}, /* 41: 0100 1100 0100 0001 */
+ {illegal,0, 2, 8}, /* 42: 0100 1100 0100 0010 */
+ {illegal,0, 2, 8}, /* 43: 0100 1100 0100 0011 */
+ {illegal,0, 2, 8}, /* 44: 0100 1100 0100 0100 */
+ {illegal,0, 2, 8}, /* 45: 0100 1100 0100 0101 */
+ {illegal,0, 2, 8}, /* 46: 0100 1100 0100 0110 */
+ {illegal,0, 2, 8}, /* 47: 0100 1100 0100 0111 */
+ {illegal,0, 2, 8}, /* 48: 0100 1100 0100 1000 */
+ {illegal,0, 2, 8}, /* 49: 0100 1100 0100 1001 */
+ {illegal,0, 2, 8}, /* 4a: 0100 1100 0100 1010 */
+ {illegal,0, 2, 8}, /* 4b: 0100 1100 0100 1011 */
+ {illegal,0, 2, 8}, /* 4c: 0100 1100 0100 1100 */
+ {illegal,0, 2, 8}, /* 4d: 0100 1100 0100 1101 */
+ {illegal,0, 2, 8}, /* 4e: 0100 1100 0100 1110 */
+ {illegal,0, 2, 8}, /* 4f: 0100 1100 0100 1111 */
+
+ {illegal,0, 2, 8}, /* 50: 0100 1100 0101 0000 */
+ {illegal,0, 2, 8}, /* 51: 0100 1100 0101 0001 */
+ {illegal,0, 2, 8}, /* 52: 0100 1100 0101 0010 */
+ {illegal,0, 2, 8}, /* 53: 0100 1100 0101 0011 */
+ {illegal,0, 2, 8}, /* 54: 0100 1100 0101 0100 */
+ {illegal,0, 2, 8}, /* 55: 0100 1100 0101 0101 */
+ {illegal,0, 2, 8}, /* 56: 0100 1100 0101 0110 */
+ {illegal,0, 2, 8}, /* 57: 0100 1100 0101 0111 */
+ {illegal,0, 2, 8}, /* 58: 0100 1100 0101 1000 */
+ {illegal,0, 2, 8}, /* 59: 0100 1100 0101 1001 */
+ {illegal,0, 2, 8}, /* 5a: 0100 1100 0101 1010 */
+ {illegal,0, 2, 8}, /* 5b: 0100 1100 0101 1011 */
+ {illegal,0, 2, 8}, /* 5c: 0100 1100 0101 1100 */
+ {illegal,0, 2, 8}, /* 5d: 0100 1100 0101 1101 */
+ {illegal,0, 2, 8}, /* 5e: 0100 1100 0101 1110 */
+ {illegal,0, 2, 8}, /* 5f: 0100 1100 0101 1111 */
+
+ {illegal,0, 2, 8}, /* 60: 0100 1100 0110 0000 */
+ {illegal,0, 2, 8}, /* 61: 0100 1100 0110 0001 */
+ {illegal,0, 2, 8}, /* 62: 0100 1100 0110 0010 */
+ {illegal,0, 2, 8}, /* 63: 0100 1100 0110 0011 */
+ {illegal,0, 2, 8}, /* 64: 0100 1100 0110 0100 */
+ {illegal,0, 2, 8}, /* 65: 0100 1100 0110 0101 */
+ {illegal,0, 2, 8}, /* 66: 0100 1100 0110 0110 */
+ {illegal,0, 2, 8}, /* 67: 0100 1100 0110 0111 */
+ {illegal,0, 2, 8}, /* 68: 0100 1100 0110 1000 */
+ {illegal,0, 2, 8}, /* 69: 0100 1100 0110 1001 */
+ {illegal,0, 2, 8}, /* 6a: 0100 1100 0110 1010 */
+ {illegal,0, 2, 8}, /* 6b: 0100 1100 0110 1011 */
+ {illegal,0, 2, 8}, /* 6c: 0100 1100 0110 1100 */
+ {illegal,0, 2, 8}, /* 6d: 0100 1100 0110 1101 */
+ {illegal,0, 2, 8}, /* 6e: 0100 1100 0110 1110 */
+ {illegal,0, 2, 8}, /* 6f: 0100 1100 0110 1111 */
+
+ {illegal,0, 2, 8}, /* 70: 0100 1100 0111 0000 */
+ {illegal,0, 2, 8}, /* 71: 0100 1100 0111 0001 */
+ {illegal,0, 2, 8}, /* 72: 0100 1100 0111 0010 */
+ {illegal,0, 2, 8}, /* 73: 0100 1100 0111 0011 */
+ {illegal,0, 2, 8}, /* 74: 0100 1100 0111 0100 */
+ {illegal,0, 2, 8}, /* 75: 0100 1100 0111 0101 */
+ {illegal,0, 2, 8}, /* 76: 0100 1100 0111 0110 */
+ {illegal,0, 2, 8}, /* 77: 0100 1100 0111 0111 */
+ {illegal,0, 2, 8}, /* 78: 0100 1100 0111 1000 */
+ {illegal,0, 2, 8}, /* 79: 0100 1100 0111 1001 */
+ {illegal,0, 2, 8}, /* 7a: 0100 1100 0111 1010 */
+ {illegal,0, 2, 8}, /* 7b: 0100 1100 0111 1011 */
+ {illegal,0, 2, 8}, /* 7c: 0100 1100 0111 1100 */
+ {illegal,0, 2, 8}, /* 7d: 0100 1100 0111 1101 */
+ {illegal,0, 2, 8}, /* 7e: 0100 1100 0111 1110 */
+ {illegal,0, 2, 8}, /* 7f: 0100 1100 0111 1111 */
+
+ {illegal,0, 2, 8}, /* 80: 0100 1100 1000 0000 */
+ {illegal,0, 2, 8}, /* 81: 0100 1100 1000 0001 */
+ {illegal,0, 2, 8}, /* 82: 0100 1100 1000 0010 */
+ {illegal,0, 2, 8}, /* 83: 0100 1100 1000 0011 */
+ {illegal,0, 2, 8}, /* 84: 0100 1100 1000 0100 */
+ {illegal,0, 2, 8}, /* 85: 0100 1100 1000 0101 */
+ {illegal,0, 2, 8}, /* 86: 0100 1100 1000 0110 */
+ {illegal,0, 2, 8}, /* 87: 0100 1100 1000 0111 */
+ {illegal,0, 2, 8}, /* 88: 0100 1100 1000 1000 */
+ {illegal,0, 2, 8}, /* 89: 0100 1100 1000 1001 */
+ {illegal,0, 2, 8}, /* 8a: 0100 1100 1000 1010 */
+ {illegal,0, 2, 8}, /* 8b: 0100 1100 1000 1011 */
+ {illegal,0, 2, 8}, /* 8c: 0100 1100 1000 1100 */
+ {illegal,0, 2, 8}, /* 8d: 0100 1100 1000 1101 */
+ {illegal,0, 2, 8}, /* 8e: 0100 1100 1000 1110 */
+ {illegal,0, 2, 8}, /* 8f: 0100 1100 1000 1111 */
+
+ {illegal,0, 2, 8}, /* 90: 0100 1100 1001 0000 */
+ {illegal,0, 2, 8}, /* 91: 0100 1100 1001 0001 */
+ {illegal,0, 2, 8}, /* 92: 0100 1100 1001 0010 */
+ {illegal,0, 2, 8}, /* 93: 0100 1100 1001 0011 */
+ {illegal,0, 2, 8}, /* 94: 0100 1100 1001 0100 */
+ {illegal,0, 2, 8}, /* 95: 0100 1100 1001 0101 */
+ {illegal,0, 2, 8}, /* 96: 0100 1100 1001 0110 */
+ {illegal,0, 2, 8}, /* 97: 0100 1100 1001 0111 */
+ {illegal,0, 2, 8}, /* 98: 0100 1100 1001 1000 */
+ {illegal,0, 2, 8}, /* 99: 0100 1100 1001 1001 */
+ {illegal,0, 2, 8}, /* 9a: 0100 1100 1001 1010 */
+ {illegal,0, 2, 8}, /* 9b: 0100 1100 1001 1011 */
+ {illegal,0, 2, 8}, /* 9c: 0100 1100 1001 1100 */
+ {illegal,0, 2, 8}, /* 9d: 0100 1100 1001 1101 */
+ {illegal,0, 2, 8}, /* 9e: 0100 1100 1001 1110 */
+ {illegal,0, 2, 8}, /* 9f: 0100 1100 1001 1111 */
+
+ {illegal,0, 2, 8}, /* a0: 0100 1100 1010 0000 */
+ {illegal,0, 2, 8}, /* a1: 0100 1100 1010 0001 */
+ {illegal,0, 2, 8}, /* a2: 0100 1100 1010 0010 */
+ {illegal,0, 2, 8}, /* a3: 0100 1100 1010 0011 */
+ {illegal,0, 2, 8}, /* a4: 0100 1100 1010 0100 */
+ {illegal,0, 2, 8}, /* a5: 0100 1100 1010 0101 */
+ {illegal,0, 2, 8}, /* a6: 0100 1100 1010 0110 */
+ {illegal,0, 2, 8}, /* a7: 0100 1100 1010 0111 */
+ {illegal,0, 2, 8}, /* a8: 0100 1100 1010 1000 */
+ {illegal,0, 2, 8}, /* a9: 0100 1100 1010 1001 */
+ {illegal,0, 2, 8}, /* aa: 0100 1100 1010 1010 */
+ {illegal,0, 2, 8}, /* ab: 0100 1100 1010 1011 */
+ {illegal,0, 2, 8}, /* ac: 0100 1100 1010 1100 */
+ {illegal,0, 2, 8}, /* ad: 0100 1100 1010 1101 */
+ {illegal,0, 2, 8}, /* ae: 0100 1100 1010 1110 */
+ {illegal,0, 2, 8}, /* af: 0100 1100 1010 1111 */
+
+ {illegal,0, 2, 8}, /* b0: 0100 1100 1011 0000 */
+ {illegal,0, 2, 8}, /* b1: 0100 1100 1011 0001 */
+ {illegal,0, 2, 8}, /* b2: 0100 1100 1011 0010 */
+ {illegal,0, 2, 8}, /* b3: 0100 1100 1011 0011 */
+ {illegal,0, 2, 8}, /* b4: 0100 1100 1011 0100 */
+ {illegal,0, 2, 8}, /* b5: 0100 1100 1011 0101 */
+ {illegal,0, 2, 8}, /* b6: 0100 1100 1011 0110 */
+ {illegal,0, 2, 8}, /* b7: 0100 1100 1011 0111 */
+ {illegal,0, 2, 8}, /* b8: 0100 1100 1011 1000 */
+ {illegal,0, 2, 8}, /* b9: 0100 1100 1011 1001 */
+ {illegal,0, 2, 8}, /* ba: 0100 1100 1011 1010 */
+ {illegal,0, 2, 8}, /* bb: 0100 1100 1011 1011 */
+ {illegal,0, 2, 8}, /* bc: 0100 1100 1011 1100 */
+ {illegal,0, 2, 8}, /* bd: 0100 1100 1011 1101 */
+ {illegal,0, 2, 8}, /* be: 0100 1100 1011 1110 */
+ {illegal,0, 2, 8}, /* bf: 0100 1100 1011 1111 */
+
+ {MOV,"A,PA", 2,10}, /* c0: 0100 1100 1100 0000 */
+ {MOV,"A,PB", 2,10}, /* c1: 0100 1100 1100 0001 */
+ {MOV,"A,PC", 2,10}, /* c2: 0100 1100 1100 0010 */
+ {MOV,"A,PD", 2,10}, /* c3: 0100 1100 1100 0011 */
+ {illegal,0, 2,10}, /* c4: 0100 1100 1100 0100 */
+ {MOV,"A,PF", 2,10}, /* c5: 0100 1100 1100 0101 */
+ {MOV,"A,MKH", 2,10}, /* c6: 0100 1100 1100 0110 */
+ {MOV,"A,MKL", 2,10}, /* c7: 0100 1100 1100 0111 */
+ {illegal,0, 2,10}, /* c8: 0100 1100 1100 1000 */
+ {MOV,"A,SMH", 2,10}, /* c9: 0100 1100 1100 1001 */
+ {illegal,0, 2,10}, /* ca: 0100 1100 1100 1010 */
+ {MOV,"A,EOM", 2,10}, /* cb: 0100 1100 1100 1011 */
+ {illegal,0, 2,10}, /* cc: 0100 1100 1100 1100 */
+ {MOV,"A,TMM", 2,10}, /* cd: 0100 1100 1100 1101 */
+ {MOV,"A,PT", 2,10}, /* ce: 0100 1100 1100 1110 */ /* 7807 */
+ {illegal,0, 2,10}, /* cf: 0100 1100 1100 1111 */
+
+ {illegal,0, 2,10}, /* d0: 0100 1100 1101 0000 */
+ {illegal,0, 2,10}, /* d1: 0100 1100 1101 0001 */
+ {illegal,0, 2,10}, /* d2: 0100 1100 1101 0010 */
+ {illegal,0, 2,10}, /* d3: 0100 1100 1101 0011 */
+ {illegal,0, 2,10}, /* d4: 0100 1100 1101 0100 */
+ {illegal,0, 2,10}, /* d5: 0100 1100 1101 0101 */
+ {illegal,0, 2,10}, /* d6: 0100 1100 1101 0110 */
+ {illegal,0, 2,10}, /* d7: 0100 1100 1101 0111 */
+ {illegal,0, 2,10}, /* d8: 0100 1100 1101 1000 */
+ {MOV,"A,RXB", 2,10}, /* d9: 0100 1100 1101 1001 */
+ {illegal,0, 2,10}, /* da: 0100 1100 1101 1010 */
+ {illegal,0, 2,10}, /* db: 0100 1100 1101 1011 */
+ {illegal,0, 2,10}, /* dc: 0100 1100 1101 1100 */
+ {illegal,0, 2,10}, /* dd: 0100 1100 1101 1101 */
+ {illegal,0, 2,10}, /* de: 0100 1100 1101 1110 */
+ {illegal,0, 2,10}, /* df: 0100 1100 1101 1111 */
+
+ {illegal,0, 2,10}, /* e0: 0100 1100 1110 0000 */
+ {illegal,0, 2,10}, /* e1: 0100 1100 1110 0001 */
+ {illegal,0, 2,10}, /* e2: 0100 1100 1110 0010 */
+ {illegal,0, 2,10}, /* e3: 0100 1100 1110 0011 */
+ {illegal,0, 2,10}, /* e4: 0100 1100 1110 0100 */
+ {illegal,0, 2,10}, /* e5: 0100 1100 1110 0101 */
+ {illegal,0, 2,10}, /* e6: 0100 1100 1110 0110 */
+ {illegal,0, 2,10}, /* e7: 0100 1100 1110 0111 */
+ {illegal,0, 2,10}, /* e8: 0100 1100 1110 1000 */
+ {illegal,0, 2,10}, /* e9: 0100 1100 1110 1001 */
+ {illegal,0, 2,10}, /* ea: 0100 1100 1110 1010 */
+ {illegal,0, 2,10}, /* eb: 0100 1100 1110 1011 */
+ {illegal,0, 2,10}, /* ec: 0100 1100 1110 1100 */
+ {illegal,0, 2,10}, /* ed: 0100 1100 1110 1101 */
+ {illegal,0, 2,10}, /* ee: 0100 1100 1110 1110 */
+ {illegal,0, 2,10}, /* ef: 0100 1100 1110 1111 */
+
+ {illegal,0, 2,10}, /* f0: 0100 1100 1111 0000 */
+ {illegal,0, 2,10}, /* f1: 0100 1100 1111 0001 */
+ {illegal,0, 2,10}, /* f2: 0100 1100 1111 0010 */
+ {illegal,0, 2,10}, /* f3: 0100 1100 1111 0011 */
+ {illegal,0, 2,10}, /* f4: 0100 1100 1111 0100 */
+ {illegal,0, 2,10}, /* f5: 0100 1100 1111 0101 */
+ {illegal,0, 2,10}, /* f6: 0100 1100 1111 0110 */
+ {illegal,0, 2,10}, /* f7: 0100 1100 1111 0111 */
+ {illegal,0, 2,10}, /* f8: 0100 1100 1111 1000 */
+ {illegal,0, 2,10}, /* f9: 0100 1100 1111 1001 */
+ {illegal,0, 2,10}, /* fa: 0100 1100 1111 1010 */
+ {illegal,0, 2,10}, /* fb: 0100 1100 1111 1011 */
+ {illegal,0, 2,10}, /* fc: 0100 1100 1111 1100 */
+ {illegal,0, 2,10}, /* fd: 0100 1100 1111 1101 */
+ {illegal,0, 2,10}, /* fe: 0100 1100 1111 1110 */
+ {illegal,0, 2,10} /* ff: 0100 1100 1111 1111 */
+};
+
+/* prefix 4D */
+static struct dasm_s dasm4D_7810[256] =
+{
+ {illegal,0, 2, 8}, /* 00: 0100 1101 0000 0000 */
+ {illegal,0, 2, 8}, /* 01: 0100 1101 0000 0001 */
+ {illegal,0, 2, 8}, /* 02: 0100 1101 0000 0010 */
+ {illegal,0, 2, 8}, /* 03: 0100 1101 0000 0011 */
+ {illegal,0, 2, 8}, /* 04: 0100 1101 0000 0100 */
+ {illegal,0, 2, 8}, /* 05: 0100 1101 0000 0101 */
+ {illegal,0, 2, 8}, /* 06: 0100 1101 0000 0110 */
+ {illegal,0, 2, 8}, /* 07: 0100 1101 0000 0111 */
+ {illegal,0, 2, 8}, /* 08: 0100 1101 0000 1000 */
+ {illegal,0, 2, 8}, /* 09: 0100 1101 0000 1001 */
+ {illegal,0, 2, 8}, /* 0a: 0100 1101 0000 1010 */
+ {illegal,0, 2, 8}, /* 0b: 0100 1101 0000 1011 */
+ {illegal,0, 2, 8}, /* 0c: 0100 1101 0000 1100 */
+ {illegal,0, 2, 8}, /* 0d: 0100 1101 0000 1101 */
+ {illegal,0, 2, 8}, /* 0e: 0100 1101 0000 1110 */
+ {illegal,0, 2, 8}, /* 0f: 0100 1101 0000 1111 */
+
+ {illegal,0, 2, 8}, /* 10: 0100 1101 0001 0000 */
+ {illegal,0, 2, 8}, /* 11: 0100 1101 0001 0001 */
+ {illegal,0, 2, 8}, /* 12: 0100 1101 0001 0010 */
+ {illegal,0, 2, 8}, /* 13: 0100 1101 0001 0011 */
+ {illegal,0, 2, 8}, /* 14: 0100 1101 0001 0100 */
+ {illegal,0, 2, 8}, /* 15: 0100 1101 0001 0101 */
+ {illegal,0, 2, 8}, /* 16: 0100 1101 0001 0110 */
+ {illegal,0, 2, 8}, /* 17: 0100 1101 0001 0111 */
+ {illegal,0, 2, 8}, /* 18: 0100 1101 0001 1000 */
+ {illegal,0, 2, 8}, /* 19: 0100 1101 0001 1001 */
+ {illegal,0, 2, 8}, /* 1a: 0100 1101 0001 1010 */
+ {illegal,0, 2, 8}, /* 1b: 0100 1101 0001 1011 */
+ {illegal,0, 2, 8}, /* 1c: 0100 1101 0001 1100 */
+ {illegal,0, 2, 8}, /* 1d: 0100 1101 0001 1101 */
+ {illegal,0, 2, 8}, /* 1e: 0100 1101 0001 1110 */
+ {illegal,0, 2, 8}, /* 1f: 0100 1101 0001 1111 */
+
+ {illegal,0, 2, 8}, /* 20: 0100 1101 0010 0000 */
+ {illegal,0, 2, 8}, /* 21: 0100 1101 0010 0001 */
+ {illegal,0, 2, 8}, /* 22: 0100 1101 0010 0010 */
+ {illegal,0, 2, 8}, /* 23: 0100 1101 0010 0011 */
+ {illegal,0, 2, 8}, /* 24: 0100 1101 0010 0100 */
+ {illegal,0, 2, 8}, /* 25: 0100 1101 0010 0101 */
+ {illegal,0, 2, 8}, /* 26: 0100 1101 0010 0110 */
+ {illegal,0, 2, 8}, /* 27: 0100 1101 0010 0111 */
+ {illegal,0, 2, 8}, /* 28: 0100 1101 0010 1000 */
+ {illegal,0, 2, 8}, /* 29: 0100 1101 0010 1001 */
+ {illegal,0, 2, 8}, /* 2a: 0100 1101 0010 1010 */
+ {illegal,0, 2, 8}, /* 2b: 0100 1101 0010 1011 */
+ {illegal,0, 2, 8}, /* 2c: 0100 1101 0010 1100 */
+ {illegal,0, 2, 8}, /* 2d: 0100 1101 0010 1101 */
+ {illegal,0, 2, 8}, /* 2e: 0100 1101 0010 1110 */
+ {illegal,0, 2, 8}, /* 2f: 0100 1101 0010 1111 */
+
+ {illegal,0, 2, 8}, /* 30: 0100 1101 0011 0000 */
+ {illegal,0, 2, 8}, /* 31: 0100 1101 0011 0001 */
+ {illegal,0, 2, 8}, /* 32: 0100 1101 0011 0010 */
+ {illegal,0, 2, 8}, /* 33: 0100 1101 0011 0011 */
+ {illegal,0, 2, 8}, /* 34: 0100 1101 0011 0100 */
+ {illegal,0, 2, 8}, /* 35: 0100 1101 0011 0101 */
+ {illegal,0, 2, 8}, /* 36: 0100 1101 0011 0110 */
+ {illegal,0, 2, 8}, /* 37: 0100 1101 0011 0111 */
+ {illegal,0, 2, 8}, /* 38: 0100 1101 0011 1000 */
+ {illegal,0, 2, 8}, /* 39: 0100 1101 0011 1001 */
+ {illegal,0, 2, 8}, /* 3a: 0100 1101 0011 1010 */
+ {illegal,0, 2, 8}, /* 3b: 0100 1101 0011 1011 */
+ {illegal,0, 2, 8}, /* 3c: 0100 1101 0011 1100 */
+ {illegal,0, 2, 8}, /* 3d: 0100 1101 0011 1101 */
+ {illegal,0, 2, 8}, /* 3e: 0100 1101 0011 1110 */
+ {illegal,0, 2, 8}, /* 3f: 0100 1101 0011 1111 */
+
+ {illegal,0, 2, 8}, /* 40: 0100 1101 0100 0000 */
+ {illegal,0, 2, 8}, /* 41: 0100 1101 0100 0001 */
+ {illegal,0, 2, 8}, /* 42: 0100 1101 0100 0010 */
+ {illegal,0, 2, 8}, /* 43: 0100 1101 0100 0011 */
+ {illegal,0, 2, 8}, /* 44: 0100 1101 0100 0100 */
+ {illegal,0, 2, 8}, /* 45: 0100 1101 0100 0101 */
+ {illegal,0, 2, 8}, /* 46: 0100 1101 0100 0110 */
+ {illegal,0, 2, 8}, /* 47: 0100 1101 0100 0111 */
+ {illegal,0, 2, 8}, /* 48: 0100 1101 0100 1000 */
+ {illegal,0, 2, 8}, /* 49: 0100 1101 0100 1001 */
+ {illegal,0, 2, 8}, /* 4a: 0100 1101 0100 1010 */
+ {illegal,0, 2, 8}, /* 4b: 0100 1101 0100 1011 */
+ {illegal,0, 2, 8}, /* 4c: 0100 1101 0100 1100 */
+ {illegal,0, 2, 8}, /* 4d: 0100 1101 0100 1101 */
+ {illegal,0, 2, 8}, /* 4e: 0100 1101 0100 1110 */
+ {illegal,0, 2, 8}, /* 4f: 0100 1101 0100 1111 */
+
+ {illegal,0, 2, 8}, /* 50: 0100 1101 0101 0000 */
+ {illegal,0, 2, 8}, /* 51: 0100 1101 0101 0001 */
+ {illegal,0, 2, 8}, /* 52: 0100 1101 0101 0010 */
+ {illegal,0, 2, 8}, /* 53: 0100 1101 0101 0011 */
+ {illegal,0, 2, 8}, /* 54: 0100 1101 0101 0100 */
+ {illegal,0, 2, 8}, /* 55: 0100 1101 0101 0101 */
+ {illegal,0, 2, 8}, /* 56: 0100 1101 0101 0110 */
+ {illegal,0, 2, 8}, /* 57: 0100 1101 0101 0111 */
+ {illegal,0, 2, 8}, /* 58: 0100 1101 0101 1000 */
+ {illegal,0, 2, 8}, /* 59: 0100 1101 0101 1001 */
+ {illegal,0, 2, 8}, /* 5a: 0100 1101 0101 1010 */
+ {illegal,0, 2, 8}, /* 5b: 0100 1101 0101 1011 */
+ {illegal,0, 2, 8}, /* 5c: 0100 1101 0101 1100 */
+ {illegal,0, 2, 8}, /* 5d: 0100 1101 0101 1101 */
+ {illegal,0, 2, 8}, /* 5e: 0100 1101 0101 1110 */
+ {illegal,0, 2, 8}, /* 5f: 0100 1101 0101 1111 */
+
+ {illegal,0, 2, 8}, /* 60: 0100 1101 0110 0000 */
+ {illegal,0, 2, 8}, /* 61: 0100 1101 0110 0001 */
+ {illegal,0, 2, 8}, /* 62: 0100 1101 0110 0010 */
+ {illegal,0, 2, 8}, /* 63: 0100 1101 0110 0011 */
+ {illegal,0, 2, 8}, /* 64: 0100 1101 0110 0100 */
+ {illegal,0, 2, 8}, /* 65: 0100 1101 0110 0101 */
+ {illegal,0, 2, 8}, /* 66: 0100 1101 0110 0110 */
+ {illegal,0, 2, 8}, /* 67: 0100 1101 0110 0111 */
+ {illegal,0, 2, 8}, /* 68: 0100 1101 0110 1000 */
+ {illegal,0, 2, 8}, /* 69: 0100 1101 0110 1001 */
+ {illegal,0, 2, 8}, /* 6a: 0100 1101 0110 1010 */
+ {illegal,0, 2, 8}, /* 6b: 0100 1101 0110 1011 */
+ {illegal,0, 2, 8}, /* 6c: 0100 1101 0110 1100 */
+ {illegal,0, 2, 8}, /* 6d: 0100 1101 0110 1101 */
+ {illegal,0, 2, 8}, /* 6e: 0100 1101 0110 1110 */
+ {illegal,0, 2, 8}, /* 6f: 0100 1101 0110 1111 */
+
+ {illegal,0, 2, 8}, /* 70: 0100 1101 0111 0000 */
+ {illegal,0, 2, 8}, /* 71: 0100 1101 0111 0001 */
+ {illegal,0, 2, 8}, /* 72: 0100 1101 0111 0010 */
+ {illegal,0, 2, 8}, /* 73: 0100 1101 0111 0011 */
+ {illegal,0, 2, 8}, /* 74: 0100 1101 0111 0100 */
+ {illegal,0, 2, 8}, /* 75: 0100 1101 0111 0101 */
+ {illegal,0, 2, 8}, /* 76: 0100 1101 0111 0110 */
+ {illegal,0, 2, 8}, /* 77: 0100 1101 0111 0111 */
+ {illegal,0, 2, 8}, /* 78: 0100 1101 0111 1000 */
+ {illegal,0, 2, 8}, /* 79: 0100 1101 0111 1001 */
+ {illegal,0, 2, 8}, /* 7a: 0100 1101 0111 1010 */
+ {illegal,0, 2, 8}, /* 7b: 0100 1101 0111 1011 */
+ {illegal,0, 2, 8}, /* 7c: 0100 1101 0111 1100 */
+ {illegal,0, 2, 8}, /* 7d: 0100 1101 0111 1101 */
+ {illegal,0, 2, 8}, /* 7e: 0100 1101 0111 1110 */
+ {illegal,0, 2, 8}, /* 7f: 0100 1101 0111 1111 */
+
+ {illegal,0, 2, 8}, /* 80: 0100 1101 1000 0000 */
+ {illegal,0, 2, 8}, /* 81: 0100 1101 1000 0001 */
+ {illegal,0, 2, 8}, /* 82: 0100 1101 1000 0010 */
+ {illegal,0, 2, 8}, /* 83: 0100 1101 1000 0011 */
+ {illegal,0, 2, 8}, /* 84: 0100 1101 1000 0100 */
+ {illegal,0, 2, 8}, /* 85: 0100 1101 1000 0101 */
+ {illegal,0, 2, 8}, /* 86: 0100 1101 1000 0110 */
+ {illegal,0, 2, 8}, /* 87: 0100 1101 1000 0111 */
+ {illegal,0, 2, 8}, /* 88: 0100 1101 1000 1000 */
+ {illegal,0, 2, 8}, /* 89: 0100 1101 1000 1001 */
+ {illegal,0, 2, 8}, /* 8a: 0100 1101 1000 1010 */
+ {illegal,0, 2, 8}, /* 8b: 0100 1101 1000 1011 */
+ {illegal,0, 2, 8}, /* 8c: 0100 1101 1000 1100 */
+ {illegal,0, 2, 8}, /* 8d: 0100 1101 1000 1101 */
+ {illegal,0, 2, 8}, /* 8e: 0100 1101 1000 1110 */
+ {illegal,0, 2, 8}, /* 8f: 0100 1101 1000 1111 */
+
+ {illegal,0, 2, 8}, /* 90: 0100 1101 1001 0000 */
+ {illegal,0, 2, 8}, /* 91: 0100 1101 1001 0001 */
+ {illegal,0, 2, 8}, /* 92: 0100 1101 1001 0010 */
+ {illegal,0, 2, 8}, /* 93: 0100 1101 1001 0011 */
+ {illegal,0, 2, 8}, /* 94: 0100 1101 1001 0100 */
+ {illegal,0, 2, 8}, /* 95: 0100 1101 1001 0101 */
+ {illegal,0, 2, 8}, /* 96: 0100 1101 1001 0110 */
+ {illegal,0, 2, 8}, /* 97: 0100 1101 1001 0111 */
+ {illegal,0, 2, 8}, /* 98: 0100 1101 1001 1000 */
+ {illegal,0, 2, 8}, /* 99: 0100 1101 1001 1001 */
+ {illegal,0, 2, 8}, /* 9a: 0100 1101 1001 1010 */
+ {illegal,0, 2, 8}, /* 9b: 0100 1101 1001 1011 */
+ {illegal,0, 2, 8}, /* 9c: 0100 1101 1001 1100 */
+ {illegal,0, 2, 8}, /* 9d: 0100 1101 1001 1101 */
+ {illegal,0, 2, 8}, /* 9e: 0100 1101 1001 1110 */
+ {illegal,0, 2, 8}, /* 9f: 0100 1101 1001 1111 */
+
+ {illegal,0, 2, 8}, /* a0: 0100 1101 1010 0000 */
+ {illegal,0, 2, 8}, /* a1: 0100 1101 1010 0001 */
+ {illegal,0, 2, 8}, /* a2: 0100 1101 1010 0010 */
+ {illegal,0, 2, 8}, /* a3: 0100 1101 1010 0011 */
+ {illegal,0, 2, 8}, /* a4: 0100 1101 1010 0100 */
+ {illegal,0, 2, 8}, /* a5: 0100 1101 1010 0101 */
+ {illegal,0, 2, 8}, /* a6: 0100 1101 1010 0110 */
+ {illegal,0, 2, 8}, /* a7: 0100 1101 1010 0111 */
+ {illegal,0, 2, 8}, /* a8: 0100 1101 1010 1000 */
+ {illegal,0, 2, 8}, /* a9: 0100 1101 1010 1001 */
+ {illegal,0, 2, 8}, /* aa: 0100 1101 1010 1010 */
+ {illegal,0, 2, 8}, /* ab: 0100 1101 1010 1011 */
+ {illegal,0, 2, 8}, /* ac: 0100 1101 1010 1100 */
+ {illegal,0, 2, 8}, /* ad: 0100 1101 1010 1101 */
+ {illegal,0, 2, 8}, /* ae: 0100 1101 1010 1110 */
+ {illegal,0, 2, 8}, /* af: 0100 1101 1010 1111 */
+
+ {illegal,0, 2, 8}, /* b0: 0100 1101 1011 0000 */
+ {illegal,0, 2, 8}, /* b1: 0100 1101 1011 0001 */
+ {illegal,0, 2, 8}, /* b2: 0100 1101 1011 0010 */
+ {illegal,0, 2, 8}, /* b3: 0100 1101 1011 0011 */
+ {illegal,0, 2, 8}, /* b4: 0100 1101 1011 0100 */
+ {illegal,0, 2, 8}, /* b5: 0100 1101 1011 0101 */
+ {illegal,0, 2, 8}, /* b6: 0100 1101 1011 0110 */
+ {illegal,0, 2, 8}, /* b7: 0100 1101 1011 0111 */
+ {illegal,0, 2, 8}, /* b8: 0100 1101 1011 1000 */
+ {illegal,0, 2, 8}, /* b9: 0100 1101 1011 1001 */
+ {illegal,0, 2, 8}, /* ba: 0100 1101 1011 1010 */
+ {illegal,0, 2, 8}, /* bb: 0100 1101 1011 1011 */
+ {illegal,0, 2, 8}, /* bc: 0100 1101 1011 1100 */
+ {illegal,0, 2, 8}, /* bd: 0100 1101 1011 1101 */
+ {illegal,0, 2, 8}, /* be: 0100 1101 1011 1110 */
+ {illegal,0, 2, 8}, /* bf: 0100 1101 1011 1111 */
+
+ {MOV,"PA,A", 2,10}, /* c0: 0100 1101 1100 0000 */
+ {MOV,"PB,A", 2,10}, /* c1: 0100 1101 1100 0001 */
+ {MOV,"PC,A", 2,10}, /* c2: 0100 1101 1100 0010 */
+ {MOV,"PD,A", 2,10}, /* c3: 0100 1101 1100 0011 */
+ {illegal,0, 2,10}, /* c4: 0100 1101 1100 0100 */
+ {MOV,"PF,A", 2,10}, /* c5: 0100 1101 1100 0101 */
+ {MOV,"MKH,A", 2,10}, /* c6: 0100 1101 1100 0110 */
+ {MOV,"MKL,A", 2,10}, /* c7: 0100 1101 1100 0111 */
+ {MOV,"ANM,A", 2,10}, /* c8: 0100 1101 1100 1000 */ /* 7810 */
+ {MOV,"SMH,A", 2,10}, /* c9: 0100 1101 1100 1001 */
+ {MOV,"SML,A", 2,10}, /* ca: 0100 1101 1100 1010 */
+ {MOV,"EOM,A", 2,10}, /* cb: 0100 1101 1100 1011 */
+ {MOV,"ETMM,A", 2,10}, /* cc: 0100 1101 1100 1100 */
+ {MOV,"TMM,A", 2,10}, /* cd: 0100 1101 1100 1101 */
+ {illegal,0, 2,10}, /* ce: 0100 1101 1100 1110 */
+ {illegal,0, 2,10}, /* cf: 0100 1101 1100 1111 */
+
+ {MOV,"MM,A", 2,10}, /* d0: 0100 1101 1101 0000 */
+ {MOV,"MCC,A", 2,10}, /* d1: 0100 1101 1101 0001 */
+ {MOV,"MA,A", 2,10}, /* d2: 0100 1101 1101 0010 */
+ {MOV,"MB,A", 2,10}, /* d3: 0100 1101 1101 0011 */
+ {MOV,"MC,A", 2,10}, /* d4: 0100 1101 1101 0100 */
+ {illegal,0, 2,10}, /* d5: 0100 1101 1101 0101 */
+ {illegal,0, 2,10}, /* d6: 0100 1101 1101 0110 */
+ {MOV,"MF,A", 2,10}, /* d7: 0100 1101 1101 0111 */
+ {MOV,"TXB,A", 2,10}, /* d8: 0100 1101 1101 1000 */
+ {illegal,0, 2,10}, /* d9: 0100 1101 1101 1001 */
+ {MOV,"TM0,A", 2,10}, /* da: 0100 1101 1101 1010 */
+ {MOV,"TM1,A", 2,10}, /* db: 0100 1101 1101 1011 */
+ {illegal,0, 2,10}, /* dc: 0100 1101 1101 1100 */
+ {illegal,0, 2,10}, /* dd: 0100 1101 1101 1101 */
+ {illegal,0, 2,10}, /* de: 0100 1101 1101 1110 */
+ {illegal,0, 2,10}, /* df: 0100 1101 1101 1111 */
+
+ {illegal,0, 2,10}, /* e0: 0100 1101 1110 0000 */
+ {illegal,0, 2,10}, /* e1: 0100 1101 1110 0001 */
+ {illegal,0, 2,10}, /* e2: 0100 1101 1110 0010 */
+ {illegal,0, 2,10}, /* e3: 0100 1101 1110 0011 */
+ {illegal,0, 2,10}, /* e4: 0100 1101 1110 0100 */
+ {illegal,0, 2,10}, /* e5: 0100 1101 1110 0101 */
+ {illegal,0, 2,10}, /* e6: 0100 1101 1110 0110 */
+ {illegal,0, 2,10}, /* e7: 0100 1101 1110 0111 */
+ {MOV,"ZCM,A", 2,10}, /* e8: 0100 1101 1110 1000 */ /* 7810 */
+ {illegal,0, 2,10}, /* e9: 0100 1101 1110 1001 */
+ {illegal,0, 2,10}, /* ea: 0100 1101 1110 1010 */
+ {illegal,0, 2,10}, /* eb: 0100 1101 1110 1011 */
+ {illegal,0, 2,10}, /* ec: 0100 1101 1110 1100 */
+ {illegal,0, 2,10}, /* ed: 0100 1101 1110 1101 */
+ {illegal,0, 2,10}, /* ee: 0100 1101 1110 1110 */
+ {illegal,0, 2,10}, /* ef: 0100 1101 1110 1111 */
+
+ {illegal,0, 2,10}, /* f0: 0100 1101 1111 0000 */
+ {illegal,0, 2,10}, /* f1: 0100 1101 1111 0001 */
+ {illegal,0, 2,10}, /* f2: 0100 1101 1111 0010 */
+ {illegal,0, 2,10}, /* f3: 0100 1101 1111 0011 */
+ {illegal,0, 2,10}, /* f4: 0100 1101 1111 0100 */
+ {illegal,0, 2,10}, /* f5: 0100 1101 1111 0101 */
+ {illegal,0, 2,10}, /* f6: 0100 1101 1111 0110 */
+ {illegal,0, 2,10}, /* f7: 0100 1101 1111 0111 */
+ {illegal,0, 2,10}, /* f8: 0100 1101 1111 1000 */
+ {illegal,0, 2,10}, /* f9: 0100 1101 1111 1001 */
+ {illegal,0, 2,10}, /* fa: 0100 1101 1111 1010 */
+ {illegal,0, 2,10}, /* fb: 0100 1101 1111 1011 */
+ {illegal,0, 2,10}, /* fc: 0100 1101 1111 1100 */
+ {illegal,0, 2,10}, /* fd: 0100 1101 1111 1101 */
+ {illegal,0, 2,10}, /* fe: 0100 1101 1111 1110 */
+ {illegal,0, 2,10} /* ff: 0100 1101 1111 1111 */
+};
+
+static struct dasm_s dasm4D_7807[256] =
+{
+ {illegal,0, 2, 8}, /* 00: 0100 1101 0000 0000 */
+ {illegal,0, 2, 8}, /* 01: 0100 1101 0000 0001 */
+ {illegal,0, 2, 8}, /* 02: 0100 1101 0000 0010 */
+ {illegal,0, 2, 8}, /* 03: 0100 1101 0000 0011 */
+ {illegal,0, 2, 8}, /* 04: 0100 1101 0000 0100 */
+ {illegal,0, 2, 8}, /* 05: 0100 1101 0000 0101 */
+ {illegal,0, 2, 8}, /* 06: 0100 1101 0000 0110 */
+ {illegal,0, 2, 8}, /* 07: 0100 1101 0000 0111 */
+ {illegal,0, 2, 8}, /* 08: 0100 1101 0000 1000 */
+ {illegal,0, 2, 8}, /* 09: 0100 1101 0000 1001 */
+ {illegal,0, 2, 8}, /* 0a: 0100 1101 0000 1010 */
+ {illegal,0, 2, 8}, /* 0b: 0100 1101 0000 1011 */
+ {illegal,0, 2, 8}, /* 0c: 0100 1101 0000 1100 */
+ {illegal,0, 2, 8}, /* 0d: 0100 1101 0000 1101 */
+ {illegal,0, 2, 8}, /* 0e: 0100 1101 0000 1110 */
+ {illegal,0, 2, 8}, /* 0f: 0100 1101 0000 1111 */
+
+ {illegal,0, 2, 8}, /* 10: 0100 1101 0001 0000 */
+ {illegal,0, 2, 8}, /* 11: 0100 1101 0001 0001 */
+ {illegal,0, 2, 8}, /* 12: 0100 1101 0001 0010 */
+ {illegal,0, 2, 8}, /* 13: 0100 1101 0001 0011 */
+ {illegal,0, 2, 8}, /* 14: 0100 1101 0001 0100 */
+ {illegal,0, 2, 8}, /* 15: 0100 1101 0001 0101 */
+ {illegal,0, 2, 8}, /* 16: 0100 1101 0001 0110 */
+ {illegal,0, 2, 8}, /* 17: 0100 1101 0001 0111 */
+ {illegal,0, 2, 8}, /* 18: 0100 1101 0001 1000 */
+ {illegal,0, 2, 8}, /* 19: 0100 1101 0001 1001 */
+ {illegal,0, 2, 8}, /* 1a: 0100 1101 0001 1010 */
+ {illegal,0, 2, 8}, /* 1b: 0100 1101 0001 1011 */
+ {illegal,0, 2, 8}, /* 1c: 0100 1101 0001 1100 */
+ {illegal,0, 2, 8}, /* 1d: 0100 1101 0001 1101 */
+ {illegal,0, 2, 8}, /* 1e: 0100 1101 0001 1110 */
+ {illegal,0, 2, 8}, /* 1f: 0100 1101 0001 1111 */
+
+ {illegal,0, 2, 8}, /* 20: 0100 1101 0010 0000 */
+ {illegal,0, 2, 8}, /* 21: 0100 1101 0010 0001 */
+ {illegal,0, 2, 8}, /* 22: 0100 1101 0010 0010 */
+ {illegal,0, 2, 8}, /* 23: 0100 1101 0010 0011 */
+ {illegal,0, 2, 8}, /* 24: 0100 1101 0010 0100 */
+ {illegal,0, 2, 8}, /* 25: 0100 1101 0010 0101 */
+ {illegal,0, 2, 8}, /* 26: 0100 1101 0010 0110 */
+ {illegal,0, 2, 8}, /* 27: 0100 1101 0010 0111 */
+ {illegal,0, 2, 8}, /* 28: 0100 1101 0010 1000 */
+ {illegal,0, 2, 8}, /* 29: 0100 1101 0010 1001 */
+ {illegal,0, 2, 8}, /* 2a: 0100 1101 0010 1010 */
+ {illegal,0, 2, 8}, /* 2b: 0100 1101 0010 1011 */
+ {illegal,0, 2, 8}, /* 2c: 0100 1101 0010 1100 */
+ {illegal,0, 2, 8}, /* 2d: 0100 1101 0010 1101 */
+ {illegal,0, 2, 8}, /* 2e: 0100 1101 0010 1110 */
+ {illegal,0, 2, 8}, /* 2f: 0100 1101 0010 1111 */
+
+ {illegal,0, 2, 8}, /* 30: 0100 1101 0011 0000 */
+ {illegal,0, 2, 8}, /* 31: 0100 1101 0011 0001 */
+ {illegal,0, 2, 8}, /* 32: 0100 1101 0011 0010 */
+ {illegal,0, 2, 8}, /* 33: 0100 1101 0011 0011 */
+ {illegal,0, 2, 8}, /* 34: 0100 1101 0011 0100 */
+ {illegal,0, 2, 8}, /* 35: 0100 1101 0011 0101 */
+ {illegal,0, 2, 8}, /* 36: 0100 1101 0011 0110 */
+ {illegal,0, 2, 8}, /* 37: 0100 1101 0011 0111 */
+ {illegal,0, 2, 8}, /* 38: 0100 1101 0011 1000 */
+ {illegal,0, 2, 8}, /* 39: 0100 1101 0011 1001 */
+ {illegal,0, 2, 8}, /* 3a: 0100 1101 0011 1010 */
+ {illegal,0, 2, 8}, /* 3b: 0100 1101 0011 1011 */
+ {illegal,0, 2, 8}, /* 3c: 0100 1101 0011 1100 */
+ {illegal,0, 2, 8}, /* 3d: 0100 1101 0011 1101 */
+ {illegal,0, 2, 8}, /* 3e: 0100 1101 0011 1110 */
+ {illegal,0, 2, 8}, /* 3f: 0100 1101 0011 1111 */
+
+ {illegal,0, 2, 8}, /* 40: 0100 1101 0100 0000 */
+ {illegal,0, 2, 8}, /* 41: 0100 1101 0100 0001 */
+ {illegal,0, 2, 8}, /* 42: 0100 1101 0100 0010 */
+ {illegal,0, 2, 8}, /* 43: 0100 1101 0100 0011 */
+ {illegal,0, 2, 8}, /* 44: 0100 1101 0100 0100 */
+ {illegal,0, 2, 8}, /* 45: 0100 1101 0100 0101 */
+ {illegal,0, 2, 8}, /* 46: 0100 1101 0100 0110 */
+ {illegal,0, 2, 8}, /* 47: 0100 1101 0100 0111 */
+ {illegal,0, 2, 8}, /* 48: 0100 1101 0100 1000 */
+ {illegal,0, 2, 8}, /* 49: 0100 1101 0100 1001 */
+ {illegal,0, 2, 8}, /* 4a: 0100 1101 0100 1010 */
+ {illegal,0, 2, 8}, /* 4b: 0100 1101 0100 1011 */
+ {illegal,0, 2, 8}, /* 4c: 0100 1101 0100 1100 */
+ {illegal,0, 2, 8}, /* 4d: 0100 1101 0100 1101 */
+ {illegal,0, 2, 8}, /* 4e: 0100 1101 0100 1110 */
+ {illegal,0, 2, 8}, /* 4f: 0100 1101 0100 1111 */
+
+ {illegal,0, 2, 8}, /* 50: 0100 1101 0101 0000 */
+ {illegal,0, 2, 8}, /* 51: 0100 1101 0101 0001 */
+ {illegal,0, 2, 8}, /* 52: 0100 1101 0101 0010 */
+ {illegal,0, 2, 8}, /* 53: 0100 1101 0101 0011 */
+ {illegal,0, 2, 8}, /* 54: 0100 1101 0101 0100 */
+ {illegal,0, 2, 8}, /* 55: 0100 1101 0101 0101 */
+ {illegal,0, 2, 8}, /* 56: 0100 1101 0101 0110 */
+ {illegal,0, 2, 8}, /* 57: 0100 1101 0101 0111 */
+ {illegal,0, 2, 8}, /* 58: 0100 1101 0101 1000 */
+ {illegal,0, 2, 8}, /* 59: 0100 1101 0101 1001 */
+ {illegal,0, 2, 8}, /* 5a: 0100 1101 0101 1010 */
+ {illegal,0, 2, 8}, /* 5b: 0100 1101 0101 1011 */
+ {illegal,0, 2, 8}, /* 5c: 0100 1101 0101 1100 */
+ {illegal,0, 2, 8}, /* 5d: 0100 1101 0101 1101 */
+ {illegal,0, 2, 8}, /* 5e: 0100 1101 0101 1110 */
+ {illegal,0, 2, 8}, /* 5f: 0100 1101 0101 1111 */
+
+ {illegal,0, 2, 8}, /* 60: 0100 1101 0110 0000 */
+ {illegal,0, 2, 8}, /* 61: 0100 1101 0110 0001 */
+ {illegal,0, 2, 8}, /* 62: 0100 1101 0110 0010 */
+ {illegal,0, 2, 8}, /* 63: 0100 1101 0110 0011 */
+ {illegal,0, 2, 8}, /* 64: 0100 1101 0110 0100 */
+ {illegal,0, 2, 8}, /* 65: 0100 1101 0110 0101 */
+ {illegal,0, 2, 8}, /* 66: 0100 1101 0110 0110 */
+ {illegal,0, 2, 8}, /* 67: 0100 1101 0110 0111 */
+ {illegal,0, 2, 8}, /* 68: 0100 1101 0110 1000 */
+ {illegal,0, 2, 8}, /* 69: 0100 1101 0110 1001 */
+ {illegal,0, 2, 8}, /* 6a: 0100 1101 0110 1010 */
+ {illegal,0, 2, 8}, /* 6b: 0100 1101 0110 1011 */
+ {illegal,0, 2, 8}, /* 6c: 0100 1101 0110 1100 */
+ {illegal,0, 2, 8}, /* 6d: 0100 1101 0110 1101 */
+ {illegal,0, 2, 8}, /* 6e: 0100 1101 0110 1110 */
+ {illegal,0, 2, 8}, /* 6f: 0100 1101 0110 1111 */
+
+ {illegal,0, 2, 8}, /* 70: 0100 1101 0111 0000 */
+ {illegal,0, 2, 8}, /* 71: 0100 1101 0111 0001 */
+ {illegal,0, 2, 8}, /* 72: 0100 1101 0111 0010 */
+ {illegal,0, 2, 8}, /* 73: 0100 1101 0111 0011 */
+ {illegal,0, 2, 8}, /* 74: 0100 1101 0111 0100 */
+ {illegal,0, 2, 8}, /* 75: 0100 1101 0111 0101 */
+ {illegal,0, 2, 8}, /* 76: 0100 1101 0111 0110 */
+ {illegal,0, 2, 8}, /* 77: 0100 1101 0111 0111 */
+ {illegal,0, 2, 8}, /* 78: 0100 1101 0111 1000 */
+ {illegal,0, 2, 8}, /* 79: 0100 1101 0111 1001 */
+ {illegal,0, 2, 8}, /* 7a: 0100 1101 0111 1010 */
+ {illegal,0, 2, 8}, /* 7b: 0100 1101 0111 1011 */
+ {illegal,0, 2, 8}, /* 7c: 0100 1101 0111 1100 */
+ {illegal,0, 2, 8}, /* 7d: 0100 1101 0111 1101 */
+ {illegal,0, 2, 8}, /* 7e: 0100 1101 0111 1110 */
+ {illegal,0, 2, 8}, /* 7f: 0100 1101 0111 1111 */
+
+ {illegal,0, 2, 8}, /* 80: 0100 1101 1000 0000 */
+ {illegal,0, 2, 8}, /* 81: 0100 1101 1000 0001 */
+ {illegal,0, 2, 8}, /* 82: 0100 1101 1000 0010 */
+ {illegal,0, 2, 8}, /* 83: 0100 1101 1000 0011 */
+ {illegal,0, 2, 8}, /* 84: 0100 1101 1000 0100 */
+ {illegal,0, 2, 8}, /* 85: 0100 1101 1000 0101 */
+ {illegal,0, 2, 8}, /* 86: 0100 1101 1000 0110 */
+ {illegal,0, 2, 8}, /* 87: 0100 1101 1000 0111 */
+ {illegal,0, 2, 8}, /* 88: 0100 1101 1000 1000 */
+ {illegal,0, 2, 8}, /* 89: 0100 1101 1000 1001 */
+ {illegal,0, 2, 8}, /* 8a: 0100 1101 1000 1010 */
+ {illegal,0, 2, 8}, /* 8b: 0100 1101 1000 1011 */
+ {illegal,0, 2, 8}, /* 8c: 0100 1101 1000 1100 */
+ {illegal,0, 2, 8}, /* 8d: 0100 1101 1000 1101 */
+ {illegal,0, 2, 8}, /* 8e: 0100 1101 1000 1110 */
+ {illegal,0, 2, 8}, /* 8f: 0100 1101 1000 1111 */
+
+ {illegal,0, 2, 8}, /* 90: 0100 1101 1001 0000 */
+ {illegal,0, 2, 8}, /* 91: 0100 1101 1001 0001 */
+ {illegal,0, 2, 8}, /* 92: 0100 1101 1001 0010 */
+ {illegal,0, 2, 8}, /* 93: 0100 1101 1001 0011 */
+ {illegal,0, 2, 8}, /* 94: 0100 1101 1001 0100 */
+ {illegal,0, 2, 8}, /* 95: 0100 1101 1001 0101 */
+ {illegal,0, 2, 8}, /* 96: 0100 1101 1001 0110 */
+ {illegal,0, 2, 8}, /* 97: 0100 1101 1001 0111 */
+ {illegal,0, 2, 8}, /* 98: 0100 1101 1001 1000 */
+ {illegal,0, 2, 8}, /* 99: 0100 1101 1001 1001 */
+ {illegal,0, 2, 8}, /* 9a: 0100 1101 1001 1010 */
+ {illegal,0, 2, 8}, /* 9b: 0100 1101 1001 1011 */
+ {illegal,0, 2, 8}, /* 9c: 0100 1101 1001 1100 */
+ {illegal,0, 2, 8}, /* 9d: 0100 1101 1001 1101 */
+ {illegal,0, 2, 8}, /* 9e: 0100 1101 1001 1110 */
+ {illegal,0, 2, 8}, /* 9f: 0100 1101 1001 1111 */
+
+ {illegal,0, 2, 8}, /* a0: 0100 1101 1010 0000 */
+ {illegal,0, 2, 8}, /* a1: 0100 1101 1010 0001 */
+ {illegal,0, 2, 8}, /* a2: 0100 1101 1010 0010 */
+ {illegal,0, 2, 8}, /* a3: 0100 1101 1010 0011 */
+ {illegal,0, 2, 8}, /* a4: 0100 1101 1010 0100 */
+ {illegal,0, 2, 8}, /* a5: 0100 1101 1010 0101 */
+ {illegal,0, 2, 8}, /* a6: 0100 1101 1010 0110 */
+ {illegal,0, 2, 8}, /* a7: 0100 1101 1010 0111 */
+ {illegal,0, 2, 8}, /* a8: 0100 1101 1010 1000 */
+ {illegal,0, 2, 8}, /* a9: 0100 1101 1010 1001 */
+ {illegal,0, 2, 8}, /* aa: 0100 1101 1010 1010 */
+ {illegal,0, 2, 8}, /* ab: 0100 1101 1010 1011 */
+ {illegal,0, 2, 8}, /* ac: 0100 1101 1010 1100 */
+ {illegal,0, 2, 8}, /* ad: 0100 1101 1010 1101 */
+ {illegal,0, 2, 8}, /* ae: 0100 1101 1010 1110 */
+ {illegal,0, 2, 8}, /* af: 0100 1101 1010 1111 */
+
+ {illegal,0, 2, 8}, /* b0: 0100 1101 1011 0000 */
+ {illegal,0, 2, 8}, /* b1: 0100 1101 1011 0001 */
+ {illegal,0, 2, 8}, /* b2: 0100 1101 1011 0010 */
+ {illegal,0, 2, 8}, /* b3: 0100 1101 1011 0011 */
+ {illegal,0, 2, 8}, /* b4: 0100 1101 1011 0100 */
+ {illegal,0, 2, 8}, /* b5: 0100 1101 1011 0101 */
+ {illegal,0, 2, 8}, /* b6: 0100 1101 1011 0110 */
+ {illegal,0, 2, 8}, /* b7: 0100 1101 1011 0111 */
+ {illegal,0, 2, 8}, /* b8: 0100 1101 1011 1000 */
+ {illegal,0, 2, 8}, /* b9: 0100 1101 1011 1001 */
+ {illegal,0, 2, 8}, /* ba: 0100 1101 1011 1010 */
+ {illegal,0, 2, 8}, /* bb: 0100 1101 1011 1011 */
+ {illegal,0, 2, 8}, /* bc: 0100 1101 1011 1100 */
+ {illegal,0, 2, 8}, /* bd: 0100 1101 1011 1101 */
+ {illegal,0, 2, 8}, /* be: 0100 1101 1011 1110 */
+ {illegal,0, 2, 8}, /* bf: 0100 1101 1011 1111 */
+
+ {MOV,"PA,A", 2,10}, /* c0: 0100 1101 1100 0000 */
+ {MOV,"PB,A", 2,10}, /* c1: 0100 1101 1100 0001 */
+ {MOV,"PC,A", 2,10}, /* c2: 0100 1101 1100 0010 */
+ {MOV,"PD,A", 2,10}, /* c3: 0100 1101 1100 0011 */
+ {illegal,0, 2,10}, /* c4: 0100 1101 1100 0100 */
+ {MOV,"PF,A", 2,10}, /* c5: 0100 1101 1100 0101 */
+ {MOV,"MKH,A", 2,10}, /* c6: 0100 1101 1100 0110 */
+ {MOV,"MKL,A", 2,10}, /* c7: 0100 1101 1100 0111 */
+ {illegal,0, 2,10}, /* c8: 0100 1101 1100 1000 */
+ {MOV,"SMH,A", 2,10}, /* c9: 0100 1101 1100 1001 */
+ {MOV,"SML,A", 2,10}, /* ca: 0100 1101 1100 1010 */
+ {MOV,"EOM,A", 2,10}, /* cb: 0100 1101 1100 1011 */
+ {MOV,"ETMM,A", 2,10}, /* cc: 0100 1101 1100 1100 */
+ {MOV,"TMM,A", 2,10}, /* cd: 0100 1101 1100 1101 */
+ {illegal,0, 2,10}, /* ce: 0100 1101 1100 1110 */
+ {illegal,0, 2,10}, /* cf: 0100 1101 1100 1111 */
+
+ {MOV,"MM,A", 2,10}, /* d0: 0100 1101 1101 0000 */
+ {MOV,"MCC,A", 2,10}, /* d1: 0100 1101 1101 0001 */
+ {MOV,"MA,A", 2,10}, /* d2: 0100 1101 1101 0010 */
+ {MOV,"MB,A", 2,10}, /* d3: 0100 1101 1101 0011 */
+ {MOV,"MC,A", 2,10}, /* d4: 0100 1101 1101 0100 */
+ {illegal,0, 2,10}, /* d5: 0100 1101 1101 0101 */
+ {illegal,0, 2,10}, /* d6: 0100 1101 1101 0110 */
+ {MOV,"MF,A", 2,10}, /* d7: 0100 1101 1101 0111 */
+ {MOV,"TXB,A", 2,10}, /* d8: 0100 1101 1101 1000 */
+ {illegal,0, 2,10}, /* d9: 0100 1101 1101 1001 */
+ {MOV,"TM0,A", 2,10}, /* da: 0100 1101 1101 1010 */
+ {MOV,"TM1,A", 2,10}, /* db: 0100 1101 1101 1011 */
+ {illegal,0, 2,10}, /* dc: 0100 1101 1101 1100 */
+ {illegal,0, 2,10}, /* dd: 0100 1101 1101 1101 */
+ {illegal,0, 2,10}, /* de: 0100 1101 1101 1110 */
+ {illegal,0, 2,10}, /* df: 0100 1101 1101 1111 */
+
+ {illegal,0, 2,10}, /* e0: 0100 1101 1110 0000 */
+ {illegal,0, 2,10}, /* e1: 0100 1101 1110 0001 */
+ {illegal,0, 2,10}, /* e2: 0100 1101 1110 0010 */
+ {illegal,0, 2,10}, /* e3: 0100 1101 1110 0011 */
+ {illegal,0, 2,10}, /* e4: 0100 1101 1110 0100 */
+ {MOV,"MT,A", 2,10}, /* e5: 0100 1101 1110 0101 */ /* 7807 */
+ {illegal,0, 2,10}, /* e6: 0100 1101 1110 0110 */
+ {illegal,0, 2,10}, /* e7: 0100 1101 1110 0111 */
+ {illegal,0, 2,10}, /* e8: 0100 1101 1110 1000 */
+ {illegal,0, 2,10}, /* e9: 0100 1101 1110 1001 */
+ {illegal,0, 2,10}, /* ea: 0100 1101 1110 1010 */
+ {illegal,0, 2,10}, /* eb: 0100 1101 1110 1011 */
+ {illegal,0, 2,10}, /* ec: 0100 1101 1110 1100 */
+ {illegal,0, 2,10}, /* ed: 0100 1101 1110 1101 */
+ {illegal,0, 2,10}, /* ee: 0100 1101 1110 1110 */
+ {illegal,0, 2,10}, /* ef: 0100 1101 1110 1111 */
+
+ {illegal,0, 2,10}, /* f0: 0100 1101 1111 0000 */
+ {illegal,0, 2,10}, /* f1: 0100 1101 1111 0001 */
+ {illegal,0, 2,10}, /* f2: 0100 1101 1111 0010 */
+ {illegal,0, 2,10}, /* f3: 0100 1101 1111 0011 */
+ {illegal,0, 2,10}, /* f4: 0100 1101 1111 0100 */
+ {illegal,0, 2,10}, /* f5: 0100 1101 1111 0101 */
+ {illegal,0, 2,10}, /* f6: 0100 1101 1111 0110 */
+ {illegal,0, 2,10}, /* f7: 0100 1101 1111 0111 */
+ {illegal,0, 2,10}, /* f8: 0100 1101 1111 1000 */
+ {illegal,0, 2,10}, /* f9: 0100 1101 1111 1001 */
+ {illegal,0, 2,10}, /* fa: 0100 1101 1111 1010 */
+ {illegal,0, 2,10}, /* fb: 0100 1101 1111 1011 */
+ {illegal,0, 2,10}, /* fc: 0100 1101 1111 1100 */
+ {illegal,0, 2,10}, /* fd: 0100 1101 1111 1101 */
+ {illegal,0, 2,10}, /* fe: 0100 1101 1111 1110 */
+ {illegal,0, 2,10} /* ff: 0100 1101 1111 1111 */
+};
+
+/* prefix 60 */
+static struct dasm_s dasm60[256] =
+{
+ {illegal,0, 2, 8}, /* 00: 0110 0000 0000 0000 */
+ {illegal,0, 2, 8}, /* 01: 0110 0000 0000 0001 */
+ {illegal,0, 2, 8}, /* 02: 0110 0000 0000 0010 */
+ {illegal,0, 2, 8}, /* 03: 0110 0000 0000 0011 */
+ {illegal,0, 2, 8}, /* 04: 0110 0000 0000 0100 */
+ {illegal,0, 2, 8}, /* 05: 0110 0000 0000 0101 */
+ {illegal,0, 2, 8}, /* 06: 0110 0000 0000 0110 */
+ {illegal,0, 2, 8}, /* 07: 0110 0000 0000 0111 */
+ {ANA,"V,A", 2, 8}, /* 08: 0110 0000 0000 1000 */
+ {ANA,"A,A", 2, 8}, /* 09: 0110 0000 0000 1001 */
+ {ANA,"B,A", 2, 8}, /* 0a: 0110 0000 0000 1010 */
+ {ANA,"C,A", 2, 8}, /* 0b: 0110 0000 0000 1011 */
+ {ANA,"D,A", 2, 8}, /* 0c: 0110 0000 0000 1100 */
+ {ANA,"E,A", 2, 8}, /* 0d: 0110 0000 0000 1101 */
+ {ANA,"H,A", 2, 8}, /* 0e: 0110 0000 0000 1110 */
+ {ANA,"L,A", 2, 8}, /* 0f: 0110 0000 0000 1111 */
+
+ {XRA,"V,A", 2, 8}, /* 10: 0110 0000 0001 0000 */
+ {XRA,"A,A", 2, 8}, /* 11: 0110 0000 0001 0001 */
+ {XRA,"B,A", 2, 8}, /* 12: 0110 0000 0001 0010 */
+ {XRA,"C,A", 2, 8}, /* 13: 0110 0000 0001 0011 */
+ {XRA,"D,A", 2, 8}, /* 14: 0110 0000 0001 0100 */
+ {XRA,"E,A", 2, 8}, /* 15: 0110 0000 0001 0101 */
+ {XRA,"H,A", 2, 8}, /* 16: 0110 0000 0001 0110 */
+ {XRA,"L,A", 2, 8}, /* 17: 0110 0000 0001 0111 */
+ {ORA,"V,A", 2, 8}, /* 18: 0110 0000 0001 1000 */
+ {ORA,"A,A", 2, 8}, /* 19: 0110 0000 0001 1001 */
+ {ORA,"B,A", 2, 8}, /* 1a: 0110 0000 0001 1010 */
+ {ORA,"C,A", 2, 8}, /* 1b: 0110 0000 0001 1011 */
+ {ORA,"D,A", 2, 8}, /* 1c: 0110 0000 0001 1100 */
+ {ORA,"E,A", 2, 8}, /* 1d: 0110 0000 0001 1101 */
+ {ORA,"H,A", 2, 8}, /* 1e: 0110 0000 0001 1110 */
+ {ORA,"L,A", 2, 8}, /* 1f: 0110 0000 0001 1111 */
+
+ {ADDNC,"V,A", 2, 8}, /* 20: 0110 0000 0010 0000 */
+ {ADDNC,"A,A", 2, 8}, /* 21: 0110 0000 0010 0001 */
+ {ADDNC,"B,A", 2, 8}, /* 22: 0110 0000 0010 0010 */
+ {ADDNC,"C,A", 2, 8}, /* 23: 0110 0000 0010 0011 */
+ {ADDNC,"D,A", 2, 8}, /* 24: 0110 0000 0010 0100 */
+ {ADDNC,"E,A", 2, 8}, /* 25: 0110 0000 0010 0101 */
+ {ADDNC,"H,A", 2, 8}, /* 26: 0110 0000 0010 0110 */
+ {ADDNC,"L,A", 2, 8}, /* 27: 0110 0000 0010 0111 */
+ {GTA,"V,A", 2, 8}, /* 28: 0110 0000 0010 1000 */
+ {GTA,"A,A", 2, 8}, /* 29: 0110 0000 0010 1001 */
+ {GTA,"B,A", 2, 8}, /* 2a: 0110 0000 0010 1010 */
+ {GTA,"C,A", 2, 8}, /* 2b: 0110 0000 0010 1011 */
+ {GTA,"D,A", 2, 8}, /* 2c: 0110 0000 0010 1100 */
+ {GTA,"E,A", 2, 8}, /* 2d: 0110 0000 0010 1101 */
+ {GTA,"H,A", 2, 8}, /* 2e: 0110 0000 0010 1110 */
+ {GTA,"L,A", 2, 8}, /* 2f: 0110 0000 0010 1111 */
+
+ {SUBNB,"V,A", 2, 8}, /* 30: 0110 0000 0011 0000 */
+ {SUBNB,"A,A", 2, 8}, /* 31: 0110 0000 0011 0001 */
+ {SUBNB,"B,A", 2, 8}, /* 32: 0110 0000 0011 0010 */
+ {SUBNB,"C,A", 2, 8}, /* 33: 0110 0000 0011 0011 */
+ {SUBNB,"D,A", 2, 8}, /* 34: 0110 0000 0011 0100 */
+ {SUBNB,"E,A", 2, 8}, /* 35: 0110 0000 0011 0101 */
+ {SUBNB,"H,A", 2, 8}, /* 36: 0110 0000 0011 0110 */
+ {SUBNB,"L,A", 2, 8}, /* 37: 0110 0000 0011 0111 */
+ {LTA,"V,A", 2, 8}, /* 38: 0110 0000 0011 1000 */
+ {LTA,"A,A", 2, 8}, /* 39: 0110 0000 0011 1001 */
+ {LTA,"B,A", 2, 8}, /* 3a: 0110 0000 0011 1010 */
+ {LTA,"C,A", 2, 8}, /* 3b: 0110 0000 0011 1011 */
+ {LTA,"D,A", 2, 8}, /* 3c: 0110 0000 0011 1100 */
+ {LTA,"E,A", 2, 8}, /* 3d: 0110 0000 0011 1101 */
+ {LTA,"H,A", 2, 8}, /* 3e: 0110 0000 0011 1110 */
+ {LTA,"L,A", 2, 8}, /* 3f: 0110 0000 0011 1111 */
+
+ {ADD,"V,A", 2, 8}, /* 40: 0110 0000 0100 0000 */
+ {ADD,"A,A", 2, 8}, /* 41: 0110 0000 0100 0001 */
+ {ADD,"B,A", 2, 8}, /* 42: 0110 0000 0100 0010 */
+ {ADD,"C,A", 2, 8}, /* 43: 0110 0000 0100 0011 */
+ {ADD,"D,A", 2, 8}, /* 44: 0110 0000 0100 0100 */
+ {ADD,"E,A", 2, 8}, /* 45: 0110 0000 0100 0101 */
+ {ADD,"H,A", 2, 8}, /* 46: 0110 0000 0100 0110 */
+ {ADD,"L,A", 2, 8}, /* 47: 0110 0000 0100 0111 */
+ {illegal,0, 2, 8}, /* 48: 0110 0000 0100 1000 */
+ {illegal,0, 2, 8}, /* 49: 0110 0000 0100 1001 */
+ {illegal,0, 2, 8}, /* 4a: 0110 0000 0100 1010 */
+ {illegal,0, 2, 8}, /* 4b: 0110 0000 0100 1011 */
+ {illegal,0, 2, 8}, /* 4c: 0110 0000 0100 1100 */
+ {illegal,0, 2, 8}, /* 4d: 0110 0000 0100 1101 */
+ {illegal,0, 2, 8}, /* 4e: 0110 0000 0100 1110 */
+ {illegal,0, 2, 8}, /* 4f: 0110 0000 0100 1111 */
+
+ {ADC,"V,A", 2, 8}, /* 50: 0110 0000 0101 0000 */
+ {ADC,"A,A", 2, 8}, /* 51: 0110 0000 0101 0001 */
+ {ADC,"B,A", 2, 8}, /* 52: 0110 0000 0101 0010 */
+ {ADC,"C,A", 2, 8}, /* 53: 0110 0000 0101 0011 */
+ {ADC,"D,A", 2, 8}, /* 54: 0110 0000 0101 0100 */
+ {ADC,"E,A", 2, 8}, /* 55: 0110 0000 0101 0101 */
+ {ADC,"H,A", 2, 8}, /* 56: 0110 0000 0101 0110 */
+ {ADC,"L,A", 2, 8}, /* 57: 0110 0000 0101 0111 */
+ {illegal,0, 2, 8}, /* 58: 0110 0000 0101 1000 */
+ {illegal,0, 2, 8}, /* 59: 0110 0000 0101 1001 */
+ {illegal,0, 2, 8}, /* 5a: 0110 0000 0101 1010 */
+ {illegal,0, 2, 8}, /* 5b: 0110 0000 0101 1011 */
+ {illegal,0, 2, 8}, /* 5c: 0110 0000 0101 1100 */
+ {illegal,0, 2, 8}, /* 5d: 0110 0000 0101 1101 */
+ {illegal,0, 2, 8}, /* 5e: 0110 0000 0101 1110 */
+ {illegal,0, 2, 8}, /* 5f: 0110 0000 0101 1111 */
+
+ {SUB,"V,A", 2, 8}, /* 60: 0110 0000 0110 0000 */
+ {SUB,"A,A", 2, 8}, /* 61: 0110 0000 0110 0001 */
+ {SUB,"B,A", 2, 8}, /* 62: 0110 0000 0110 0010 */
+ {SUB,"C,A", 2, 8}, /* 63: 0110 0000 0110 0011 */
+ {SUB,"D,A", 2, 8}, /* 64: 0110 0000 0110 0100 */
+ {SUB,"E,A", 2, 8}, /* 65: 0110 0000 0110 0101 */
+ {SUB,"H,A", 2, 8}, /* 66: 0110 0000 0110 0110 */
+ {SUB,"L,A", 2, 8}, /* 67: 0110 0000 0110 0111 */
+ {NEA,"V,A", 2, 8}, /* 68: 0110 0000 0110 1000 */
+ {NEA,"A,A", 2, 8}, /* 69: 0110 0000 0110 1001 */
+ {NEA,"B,A", 2, 8}, /* 6a: 0110 0000 0110 1010 */
+ {NEA,"C,A", 2, 8}, /* 6b: 0110 0000 0110 1011 */
+ {NEA,"D,A", 2, 8}, /* 6c: 0110 0000 0110 1100 */
+ {NEA,"E,A", 2, 8}, /* 6d: 0110 0000 0110 1101 */
+ {NEA,"H,A", 2, 8}, /* 6e: 0110 0000 0110 1110 */
+ {NEA,"L,A", 2, 8}, /* 6f: 0110 0000 0110 1111 */
+
+ {SBB,"V,A", 2, 8}, /* 70: 0110 0000 0111 0000 */
+ {SBB,"A,A", 2, 8}, /* 71: 0110 0000 0111 0001 */
+ {SBB,"B,A", 2, 8}, /* 72: 0110 0000 0111 0010 */
+ {SBB,"C,A", 2, 8}, /* 73: 0110 0000 0111 0011 */
+ {SBB,"D,A", 2, 8}, /* 74: 0110 0000 0111 0100 */
+ {SBB,"E,A", 2, 8}, /* 75: 0110 0000 0111 0101 */
+ {SBB,"H,A", 2, 8}, /* 76: 0110 0000 0111 0110 */
+ {SBB,"L,A", 2, 8}, /* 77: 0110 0000 0111 0111 */
+ {EQA,"V,A", 2, 8}, /* 78: 0110 0000 0111 1000 */
+ {EQA,"A,A", 2, 8}, /* 79: 0110 0000 0111 1001 */
+ {EQA,"B,A", 2, 8}, /* 7a: 0110 0000 0111 1010 */
+ {EQA,"C,A", 2, 8}, /* 7b: 0110 0000 0111 1011 */
+ {EQA,"D,A", 2, 8}, /* 7c: 0110 0000 0111 1100 */
+ {EQA,"E,A", 2, 8}, /* 7d: 0110 0000 0111 1101 */
+ {EQA,"H,A", 2, 8}, /* 7e: 0110 0000 0111 1110 */
+ {EQA,"L,A", 2, 8}, /* 7f: 0110 0000 0111 1111 */
+
+ {illegal,0, 2, 8}, /* 80: 0110 0000 1000 0000 */
+ {illegal,0, 2, 8}, /* 81: 0110 0000 1000 0001 */
+ {illegal,0, 2, 8}, /* 82: 0110 0000 1000 0010 */
+ {illegal,0, 2, 8}, /* 83: 0110 0000 1000 0011 */
+ {illegal,0, 2, 8}, /* 84: 0110 0000 1000 0100 */
+ {illegal,0, 2, 8}, /* 85: 0110 0000 1000 0101 */
+ {illegal,0, 2, 8}, /* 86: 0110 0000 1000 0110 */
+ {illegal,0, 2, 8}, /* 87: 0110 0000 1000 0111 */
+ {ANA,"A,V", 2, 8}, /* 88: 0110 0000 1000 1000 */
+ {ANA,"A,A", 2, 8}, /* 89: 0110 0000 1000 1001 */
+ {ANA,"A,B", 2, 8}, /* 8a: 0110 0000 1000 1010 */
+ {ANA,"A,C", 2, 8}, /* 8b: 0110 0000 1000 1011 */
+ {ANA,"A,D", 2, 8}, /* 8c: 0110 0000 1000 1100 */
+ {ANA,"A,E", 2, 8}, /* 8d: 0110 0000 1000 1101 */
+ {ANA,"A,H", 2, 8}, /* 8e: 0110 0000 1000 1110 */
+ {ANA,"A,L", 2, 8}, /* 8f: 0110 0000 1000 1111 */
+
+ {XRA,"A,V", 2, 8}, /* 90: 0110 0000 1001 0000 */
+ {XRA,"A,A", 2, 8}, /* 91: 0110 0000 1001 0001 */
+ {XRA,"A,B", 2, 8}, /* 92: 0110 0000 1001 0010 */
+ {XRA,"A,C", 2, 8}, /* 93: 0110 0000 1001 0011 */
+ {XRA,"A,D", 2, 8}, /* 94: 0110 0000 1001 0100 */
+ {XRA,"A,E", 2, 8}, /* 95: 0110 0000 1001 0101 */
+ {XRA,"A,H", 2, 8}, /* 96: 0110 0000 1001 0110 */
+ {XRA,"A,L", 2, 8}, /* 97: 0110 0000 1001 0111 */
+ {ORA,"A,V", 2, 8}, /* 98: 0110 0000 1001 1000 */
+ {ORA,"A,A", 2, 8}, /* 99: 0110 0000 1001 1001 */
+ {ORA,"A,B", 2, 8}, /* 9a: 0110 0000 1001 1010 */
+ {ORA,"A,C", 2, 8}, /* 9b: 0110 0000 1001 1011 */
+ {ORA,"A,D", 2, 8}, /* 9c: 0110 0000 1001 1100 */
+ {ORA,"A,E", 2, 8}, /* 9d: 0110 0000 1001 1101 */
+ {ORA,"A,H", 2, 8}, /* 9e: 0110 0000 1001 1110 */
+ {ORA,"A,L", 2, 8}, /* 9f: 0110 0000 1001 1111 */
+
+ {ADDNC,"A,V", 2, 8}, /* a0: 0110 0000 1010 0000 */
+ {ADDNC,"A,A", 2, 8}, /* a1: 0110 0000 1010 0001 */
+ {ADDNC,"A,B", 2, 8}, /* a2: 0110 0000 1010 0010 */
+ {ADDNC,"A,C", 2, 8}, /* a3: 0110 0000 1010 0011 */
+ {ADDNC,"A,D", 2, 8}, /* a4: 0110 0000 1010 0100 */
+ {ADDNC,"A,E", 2, 8}, /* a5: 0110 0000 1010 0101 */
+ {ADDNC,"A,H", 2, 8}, /* a6: 0110 0000 1010 0110 */
+ {ADDNC,"A,L", 2, 8}, /* a7: 0110 0000 1010 0111 */
+ {GTA,"A,V", 2, 8}, /* a8: 0110 0000 1010 1000 */
+ {GTA,"A,A", 2, 8}, /* a9: 0110 0000 1010 1001 */
+ {GTA,"A,B", 2, 8}, /* aa: 0110 0000 1010 1010 */
+ {GTA,"A,C", 2, 8}, /* ab: 0110 0000 1010 1011 */
+ {GTA,"A,D", 2, 8}, /* ac: 0110 0000 1010 1100 */
+ {GTA,"A,E", 2, 8}, /* ad: 0110 0000 1010 1101 */
+ {GTA,"A,H", 2, 8}, /* ae: 0110 0000 1010 1110 */
+ {GTA,"A,L", 2, 8}, /* af: 0110 0000 1010 1111 */
+
+ {SUBNB,"A,V", 2, 8}, /* b0: 0110 0000 1011 0000 */
+ {SUBNB,"A,A", 2, 8}, /* b1: 0110 0000 1011 0001 */
+ {SUBNB,"A,B", 2, 8}, /* b2: 0110 0000 1011 0010 */
+ {SUBNB,"A,C", 2, 8}, /* b3: 0110 0000 1011 0011 */
+ {SUBNB,"A,D", 2, 8}, /* b4: 0110 0000 1011 0100 */
+ {SUBNB,"A,E", 2, 8}, /* b5: 0110 0000 1011 0101 */
+ {SUBNB,"A,H", 2, 8}, /* b6: 0110 0000 1011 0110 */
+ {SUBNB,"A,L", 2, 8}, /* b7: 0110 0000 1011 0111 */
+ {LTA,"A,V", 2, 8}, /* b8: 0110 0000 1011 1000 */
+ {LTA,"A,A", 2, 8}, /* b9: 0110 0000 1011 1001 */
+ {LTA,"A,B", 2, 8}, /* ba: 0110 0000 1011 1010 */
+ {LTA,"A,C", 2, 8}, /* bb: 0110 0000 1011 1011 */
+ {LTA,"A,D", 2, 8}, /* bc: 0110 0000 1011 1100 */
+ {LTA,"A,E", 2, 8}, /* bd: 0110 0000 1011 1101 */
+ {LTA,"A,H", 2, 8}, /* be: 0110 0000 1011 1110 */
+ {LTA,"A,L", 2, 8}, /* bf: 0110 0000 1011 1111 */
+
+ {ADD,"A,V", 2, 8}, /* c0: 0110 0000 1100 0000 */
+ {ADD,"A,A", 2, 8}, /* c1: 0110 0000 1100 0001 */
+ {ADD,"A,B", 2, 8}, /* c2: 0110 0000 1100 0010 */
+ {ADD,"A,C", 2, 8}, /* c3: 0110 0000 1100 0011 */
+ {ADD,"A,D", 2, 8}, /* c4: 0110 0000 1100 0100 */
+ {ADD,"A,E", 2, 8}, /* c5: 0110 0000 1100 0101 */
+ {ADD,"A,H", 2, 8}, /* c6: 0110 0000 1100 0110 */
+ {ADD,"A,L", 2, 8}, /* c7: 0110 0000 1100 0111 */
+ {ONA,"A,V", 2, 8}, /* c8: 0110 0000 1100 1000 */
+ {ONA,"A,A", 2, 8}, /* c9: 0110 0000 1100 1001 */
+ {ONA,"A,B", 2, 8}, /* ca: 0110 0000 1100 1010 */
+ {ONA,"A,C", 2, 8}, /* cb: 0110 0000 1100 1011 */
+ {ONA,"A,D", 2, 8}, /* cc: 0110 0000 1100 1100 */
+ {ONA,"A,E", 2, 8}, /* cd: 0110 0000 1100 1101 */
+ {ONA,"A,H", 2, 8}, /* ce: 0110 0000 1100 1110 */
+ {ONA,"A,L", 2, 8}, /* cf: 0110 0000 1100 1111 */
+
+ {ADC,"A,V", 2, 8}, /* d0: 0110 0000 1101 0000 */
+ {ADC,"A,A", 2, 8}, /* d1: 0110 0000 1101 0001 */
+ {ADC,"A,B", 2, 8}, /* d2: 0110 0000 1101 0010 */
+ {ADC,"A,C", 2, 8}, /* d3: 0110 0000 1101 0011 */
+ {ADC,"A,D", 2, 8}, /* d4: 0110 0000 1101 0100 */
+ {ADC,"A,E", 2, 8}, /* d5: 0110 0000 1101 0101 */
+ {ADC,"A,H", 2, 8}, /* d6: 0110 0000 1101 0110 */
+ {ADC,"A,L", 2, 8}, /* d7: 0110 0000 1101 0111 */
+ {OFFA,"A,V", 2, 8}, /* d8: 0110 0000 1101 1000 */
+ {OFFA,"A,A", 2, 8}, /* d9: 0110 0000 1101 1001 */
+ {OFFA,"A,B", 2, 8}, /* da: 0110 0000 1101 1010 */
+ {OFFA,"A,C", 2, 8}, /* db: 0110 0000 1101 1011 */
+ {OFFA,"A,D", 2, 8}, /* dc: 0110 0000 1101 1100 */
+ {OFFA,"A,E", 2, 8}, /* dd: 0110 0000 1101 1101 */
+ {OFFA,"A,H", 2, 8}, /* de: 0110 0000 1101 1110 */
+ {OFFA,"A,L", 2, 8}, /* df: 0110 0000 1101 1111 */
+
+ {SUB,"A,V", 2, 8}, /* e0: 0110 0000 1110 0000 */
+ {SUB,"A,A", 2, 8}, /* e1: 0110 0000 1110 0001 */
+ {SUB,"A,B", 2, 8}, /* e2: 0110 0000 1110 0010 */
+ {SUB,"A,C", 2, 8}, /* e3: 0110 0000 1110 0011 */
+ {SUB,"A,D", 2, 8}, /* e4: 0110 0000 1110 0100 */
+ {SUB,"A,E", 2, 8}, /* e5: 0110 0000 1110 0101 */
+ {SUB,"A,H", 2, 8}, /* e6: 0110 0000 1110 0110 */
+ {SUB,"A,L", 2, 8}, /* e7: 0110 0000 1110 0111 */
+ {NEA,"A,V", 2, 8}, /* e8: 0110 0000 1110 1000 */
+ {NEA,"A,A", 2, 8}, /* e9: 0110 0000 1110 1001 */
+ {NEA,"A,B", 2, 8}, /* ea: 0110 0000 1110 1010 */
+ {NEA,"A,C", 2, 8}, /* eb: 0110 0000 1110 1011 */
+ {NEA,"A,D", 2, 8}, /* ec: 0110 0000 1110 1100 */
+ {NEA,"A,E", 2, 8}, /* ed: 0110 0000 1110 1101 */
+ {NEA,"A,H", 2, 8}, /* ee: 0110 0000 1110 1110 */
+ {NEA,"A,L", 2, 8}, /* ef: 0110 0000 1110 1111 */
+
+ {SBB,"A,V", 2, 8}, /* f0: 0110 0000 1111 0000 */
+ {SBB,"A,A", 2, 8}, /* f1: 0110 0000 1111 0001 */
+ {SBB,"A,B", 2, 8}, /* f2: 0110 0000 1111 0010 */
+ {SBB,"A,C", 2, 8}, /* f3: 0110 0000 1111 0011 */
+ {SBB,"A,D", 2, 8}, /* f4: 0110 0000 1111 0100 */
+ {SBB,"A,E", 2, 8}, /* f5: 0110 0000 1111 0101 */
+ {SBB,"A,H", 2, 8}, /* f6: 0110 0000 1111 0110 */
+ {SBB,"A,L", 2, 8}, /* f7: 0110 0000 1111 0111 */
+ {EQA,"A,V", 2, 8}, /* f8: 0110 0000 1111 1000 */
+ {EQA,"A,A", 2, 8}, /* f9: 0110 0000 1111 1001 */
+ {EQA,"A,B", 2, 8}, /* fa: 0110 0000 1111 1010 */
+ {EQA,"A,C", 2, 8}, /* fb: 0110 0000 1111 1011 */
+ {EQA,"A,D", 2, 8}, /* fc: 0110 0000 1111 1100 */
+ {EQA,"A,E", 2, 8}, /* fd: 0110 0000 1111 1101 */
+ {EQA,"A,H", 2, 8}, /* fe: 0110 0000 1111 1110 */
+ {EQA,"A,L", 2, 8} /* ff: 0110 0000 1111 1111 */
+};
+
+/* prefix 64 */
+static struct dasm_s dasm64_7810[256] =
+{
+ {MVI,"PA,%b", 3,14}, /* 00: 0110 0100 0000 0000 xxxx xxxx */
+ {MVI,"PB,%b", 3,14}, /* 01: 0110 0100 0000 0001 xxxx xxxx */
+ {MVI,"PC,%b", 3,14}, /* 02: 0110 0100 0000 0010 xxxx xxxx */
+ {MVI,"PD,%b", 3,14}, /* 03: 0110 0100 0000 0011 xxxx xxxx */
+ {illegal,0, 3,14}, /* 04: 0110 0100 0000 0100 xxxx xxxx */
+ {MVI,"PF,%b", 3,14}, /* 05: 0110 0100 0000 0101 xxxx xxxx */
+ {MVI,"MKH,%b", 3,14}, /* 06: 0110 0100 0000 0110 xxxx xxxx */
+ {MVI,"MKL,%b", 3,14}, /* 07: 0110 0100 0000 0111 xxxx xxxx */
+ {ANI,"PA,%b", 3,20}, /* 08: 0110 0100 0000 1000 xxxx xxxx */
+ {ANI,"PB,%b", 3,20}, /* 09: 0110 0100 0000 1001 xxxx xxxx */
+ {ANI,"PC,%b", 3,20}, /* 0a: 0110 0100 0000 1010 xxxx xxxx */
+ {ANI,"PD,%b", 3,20}, /* 0b: 0110 0100 0000 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 0c: 0110 0100 0000 1100 xxxx xxxx */
+ {ANI,"PF,%b", 3,20}, /* 0d: 0110 0100 0000 1101 xxxx xxxx */
+ {ANI,"MKH,%b", 3,20}, /* 0e: 0110 0100 0000 1110 xxxx xxxx */
+ {ANI,"MKL,%b", 3,20}, /* 0f: 0110 0100 0000 1111 xxxx xxxx */
+
+ {XRI,"PA,%b", 3,20}, /* 10: 0110 0100 0001 0000 xxxx xxxx */
+ {XRI,"PB,%b", 3,20}, /* 11: 0110 0100 0001 0001 xxxx xxxx */
+ {XRI,"PC,%b", 3,20}, /* 12: 0110 0100 0001 0010 xxxx xxxx */
+ {XRI,"PD,%b", 3,20}, /* 13: 0110 0100 0001 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 14: 0110 0100 0001 0100 xxxx xxxx */
+ {XRI,"PF,%b", 3,20}, /* 15: 0110 0100 0001 0101 xxxx xxxx */
+ {XRI,"MKH,%b", 3,20}, /* 16: 0110 0100 0001 0110 xxxx xxxx */
+ {XRI,"MKL,%b", 3,20}, /* 17: 0110 0100 0001 0111 xxxx xxxx */
+ {ORI,"PA,%b", 3,20}, /* 18: 0110 0100 0001 1000 xxxx xxxx */
+ {ORI,"PB,%b", 3,20}, /* 19: 0110 0100 0001 1001 xxxx xxxx */
+ {ORI,"PC,%b", 3,20}, /* 1a: 0110 0100 0001 1010 xxxx xxxx */
+ {ORI,"PD,%b", 3,20}, /* 1b: 0110 0100 0001 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 1c: 0110 0100 0001 1100 xxxx xxxx */
+ {ORI,"PF,%b", 3,20}, /* 1d: 0110 0100 0001 1101 xxxx xxxx */
+ {ORI,"MKH,%b", 3,20}, /* 1e: 0110 0100 0001 1110 xxxx xxxx */
+ {ORI,"MKL,%b", 3,20}, /* 1f: 0110 0100 0001 1111 xxxx xxxx */
+
+ {ADINC,"PA,%b", 3,20}, /* 20: 0110 0100 0010 0000 xxxx xxxx */
+ {ADINC,"PB,%b", 3,20}, /* 21: 0110 0100 0010 0001 xxxx xxxx */
+ {ADINC,"PC,%b", 3,20}, /* 22: 0110 0100 0010 0010 xxxx xxxx */
+ {ADINC,"PD,%b", 3,20}, /* 23: 0110 0100 0010 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 24: 0110 0100 0010 0100 xxxx xxxx */
+ {ADINC,"PF,%b", 3,20}, /* 25: 0110 0100 0010 0101 xxxx xxxx */
+ {ADINC,"MKH,%b", 3,20}, /* 26: 0110 0100 0010 0110 xxxx xxxx */
+ {ADINC,"MKL,%b", 3,20}, /* 27: 0110 0100 0010 0111 xxxx xxxx */
+ {GTI,"PA,%b", 3,20}, /* 28: 0110 0100 0010 1000 xxxx xxxx */
+ {GTI,"PB,%b", 3,20}, /* 29: 0110 0100 0010 1001 xxxx xxxx */
+ {GTI,"PC,%b", 3,20}, /* 2a: 0110 0100 0010 1010 xxxx xxxx */
+ {GTI,"PD,%b", 3,20}, /* 2b: 0110 0100 0010 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 2c: 0110 0100 0010 1100 xxxx xxxx */
+ {GTI,"PF,%b", 3,20}, /* 2d: 0110 0100 0010 1101 xxxx xxxx */
+ {GTI,"MKH,%b", 3,20}, /* 2e: 0110 0100 0010 1110 xxxx xxxx */
+ {GTI,"MKL,%b", 3,20}, /* 2f: 0110 0100 0010 1111 xxxx xxxx */
+
+ {SUINB,"PA,%b", 3,20}, /* 30: 0110 0100 0011 0000 xxxx xxxx */
+ {SUINB,"PB,%b", 3,20}, /* 31: 0110 0100 0011 0001 xxxx xxxx */
+ {SUINB,"PC,%b", 3,20}, /* 32: 0110 0100 0011 0010 xxxx xxxx */
+ {SUINB,"PD,%b", 3,20}, /* 33: 0110 0100 0011 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 34: 0110 0100 0011 0100 xxxx xxxx */
+ {SUINB,"PF,%b", 3,20}, /* 35: 0110 0100 0011 0101 xxxx xxxx */
+ {SUINB,"MKH,%b", 3,20}, /* 36: 0110 0100 0011 0110 xxxx xxxx */
+ {SUINB,"MKL,%b", 3,20}, /* 37: 0110 0100 0011 0111 xxxx xxxx */
+ {LTI,"PA,%b", 3,20}, /* 38: 0110 0100 0011 1000 xxxx xxxx */
+ {LTI,"PB,%b", 3,20}, /* 39: 0110 0100 0011 1001 xxxx xxxx */
+ {LTI,"PC,%b", 3,20}, /* 3a: 0110 0100 0011 1010 xxxx xxxx */
+ {LTI,"PD,%b", 3,20}, /* 3b: 0110 0100 0011 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 3c: 0110 0100 0011 1100 xxxx xxxx */
+ {LTI,"PF,%b", 3,20}, /* 3d: 0110 0100 0011 1101 xxxx xxxx */
+ {LTI,"MKH,%b", 3,20}, /* 3e: 0110 0100 0011 1110 xxxx xxxx */
+ {LTI,"MKL,%b", 3,20}, /* 3f: 0110 0100 0011 1111 xxxx xxxx */
+
+ {ADI,"PA,%b", 3,20}, /* 40: 0110 0100 0100 0000 xxxx xxxx */
+ {ADI,"PB,%b", 3,20}, /* 41: 0110 0100 0100 0001 xxxx xxxx */
+ {ADI,"PC,%b", 3,20}, /* 42: 0110 0100 0100 0010 xxxx xxxx */
+ {ADI,"PD,%b", 3,20}, /* 43: 0110 0100 0100 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 44: 0110 0100 0100 0100 xxxx xxxx */
+ {ADI,"PF,%b", 3,20}, /* 45: 0110 0100 0100 0101 xxxx xxxx */
+ {ADI,"MKH,%b", 3,20}, /* 46: 0110 0100 0100 0110 xxxx xxxx */
+ {ADI,"MKL,%b", 3,20}, /* 47: 0110 0100 0100 0111 xxxx xxxx */
+ {ONI,"PA,%b", 3,20}, /* 48: 0110 0100 0100 1000 xxxx xxxx */
+ {ONI,"PB,%b", 3,20}, /* 49: 0110 0100 0100 1001 xxxx xxxx */
+ {ONI,"PC,%b", 3,20}, /* 4a: 0110 0100 0100 1010 xxxx xxxx */
+ {ONI,"PD,%b", 3,20}, /* 4b: 0110 0100 0100 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 4c: 0110 0100 0100 1100 xxxx xxxx */
+ {ONI,"PF,%b", 3,20}, /* 4d: 0110 0100 0100 1101 xxxx xxxx */
+ {ONI,"MKH,%b", 3,20}, /* 4e: 0110 0100 0100 1110 xxxx xxxx */
+ {ONI,"MKL,%b", 3,20}, /* 4f: 0110 0100 0100 1111 xxxx xxxx */
+
+ {ACI,"PA,%b", 3,20}, /* 50: 0110 0100 0101 0000 xxxx xxxx */
+ {ACI,"PB,%b", 3,20}, /* 51: 0110 0100 0101 0001 xxxx xxxx */
+ {ACI,"PC,%b", 3,20}, /* 52: 0110 0100 0101 0010 xxxx xxxx */
+ {ACI,"PD,%b", 3,20}, /* 53: 0110 0100 0101 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 54: 0110 0100 0101 0100 xxxx xxxx */
+ {ACI,"PF,%b", 3,20}, /* 55: 0110 0100 0101 0101 xxxx xxxx */
+ {ACI,"MKH,%b", 3,20}, /* 56: 0110 0100 0101 0110 xxxx xxxx */
+ {ACI,"MKL,%b", 3,20}, /* 57: 0110 0100 0101 0111 xxxx xxxx */
+ {OFFI,"PA,%b", 3,20}, /* 58: 0110 0100 0101 1000 xxxx xxxx */
+ {OFFI,"PB,%b", 3,20}, /* 59: 0110 0100 0101 1001 xxxx xxxx */
+ {OFFI,"PC,%b", 3,20}, /* 5a: 0110 0100 0101 1010 xxxx xxxx */
+ {OFFI,"PD,%b", 3,20}, /* 5b: 0110 0100 0101 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 5c: 0110 0100 0101 1100 xxxx xxxx */
+ {OFFI,"PF,%b", 3,20}, /* 5d: 0110 0100 0101 1101 xxxx xxxx */
+ {OFFI,"MKH,%b", 3,20}, /* 5e: 0110 0100 0101 1110 xxxx xxxx */
+ {OFFI,"MKL,%b", 3,20}, /* 5f: 0110 0100 0101 1111 xxxx xxxx */
+
+ {SUI,"PA,%b", 3,20}, /* 60: 0110 0100 0110 0000 xxxx xxxx */
+ {SUI,"PB,%b", 3,20}, /* 61: 0110 0100 0110 0001 xxxx xxxx */
+ {SUI,"PC,%b", 3,20}, /* 62: 0110 0100 0110 0010 xxxx xxxx */
+ {SUI,"PD,%b", 3,20}, /* 63: 0110 0100 0110 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 64: 0110 0100 0110 0100 xxxx xxxx */
+ {SUI,"PF,%b", 3,20}, /* 65: 0110 0100 0110 0101 xxxx xxxx */
+ {SUI,"MKH,%b", 3,20}, /* 66: 0110 0100 0110 0110 xxxx xxxx */
+ {SUI,"MKL,%b", 3,20}, /* 67: 0110 0100 0110 0111 xxxx xxxx */
+ {NEI,"PA,%b", 3,20}, /* 68: 0110 0100 0110 1000 xxxx xxxx */
+ {NEI,"PB,%b", 3,20}, /* 69: 0110 0100 0110 1001 xxxx xxxx */
+ {NEI,"PC,%b", 3,20}, /* 6a: 0110 0100 0110 1010 xxxx xxxx */
+ {NEI,"PD,%b", 3,20}, /* 6b: 0110 0100 0110 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 6c: 0110 0100 0110 1100 xxxx xxxx */
+ {NEI,"PF,%b", 3,20}, /* 6d: 0110 0100 0110 1101 xxxx xxxx */
+ {NEI,"MKH,%b", 3,20}, /* 6e: 0110 0100 0110 1110 xxxx xxxx */
+ {NEI,"MKL,%b", 3,20}, /* 6f: 0110 0100 0110 1111 xxxx xxxx */
+
+ {SBI,"PA,%b", 3,20}, /* 70: 0110 0100 0111 0000 xxxx xxxx */
+ {SBI,"PB,%b", 3,20}, /* 71: 0110 0100 0111 0001 xxxx xxxx */
+ {SBI,"PC,%b", 3,20}, /* 72: 0110 0100 0111 0010 xxxx xxxx */
+ {SBI,"PD,%b", 3,20}, /* 73: 0110 0100 0111 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 74: 0110 0100 0111 0100 xxxx xxxx */
+ {SBI,"PF,%b", 3,20}, /* 75: 0110 0100 0111 0101 xxxx xxxx */
+ {SBI,"MKH,%b", 3,20}, /* 76: 0110 0100 0111 0110 xxxx xxxx */
+ {SBI,"MKL,%b", 3,20}, /* 77: 0110 0100 0111 0111 xxxx xxxx */
+ {EQI,"PA,%b", 3,20}, /* 78: 0110 0100 0111 1000 xxxx xxxx */
+ {EQI,"PB,%b", 3,20}, /* 79: 0110 0100 0111 1001 xxxx xxxx */
+ {EQI,"PC,%b", 3,20}, /* 7a: 0110 0100 0111 1010 xxxx xxxx */
+ {EQI,"PD,%b", 3,20}, /* 7b: 0110 0100 0111 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 7c: 0110 0100 0111 1100 xxxx xxxx */
+ {EQI,"PF,%b", 3,20}, /* 7d: 0110 0100 0111 1101 xxxx xxxx */
+ {EQI,"MKH,%b", 3,20}, /* 7e: 0110 0100 0111 1110 xxxx xxxx */
+ {EQI,"MKL,%b", 3,20}, /* 7f: 0110 0100 0111 1111 xxxx xxxx */
+
+ {MVI,"ANM,%b", 3,14}, /* 80: 0110 0100 1000 0000 xxxx xxxx */ /* 7810 */
+ {MVI,"SMH,%b", 3,14}, /* 81: 0110 0100 1000 0001 xxxx xxxx */
+ {illegal,0, 3,14}, /* 82: 0110 0100 1000 0010 xxxx xxxx */
+ {MVI,"EOM,%b", 3,14}, /* 83: 0110 0100 1000 0011 xxxx xxxx */
+ {illegal,0, 3,14}, /* 84: 0110 0100 1000 0100 xxxx xxxx */
+ {MVI,"TMM,%b", 3,14}, /* 85: 0110 0100 1000 0101 xxxx xxxx */
+ {illegal,0, 3,14}, /* 86: 0110 0100 1000 0110 xxxx xxxx */
+ {illegal,0, 3,14}, /* 87: 0110 0100 1000 0111 xxxx xxxx */
+ {ANI,"ANM,%b", 3,20}, /* 88: 0110 0100 1000 1000 xxxx xxxx */ /* 7810 */
+ {ANI,"SMH,%b", 3,20}, /* 89: 0110 0100 1000 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* 8a: 0110 0100 1000 1010 xxxx xxxx */
+ {ANI,"EOM,%b", 3,20}, /* 8b: 0110 0100 1000 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 8c: 0110 0100 1000 1100 xxxx xxxx */
+ {ANI,"TMM,%b", 3,20}, /* 8d: 0110 0100 1000 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* 8e: 0110 0100 1000 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* 8f: 0110 0100 1000 1111 xxxx xxxx */
+
+ {XRI,"ANM,%b", 3,20}, /* 90: 0110 0100 1001 0000 xxxx xxxx */ /* 7810 */
+ {XRI,"SMH,%b", 3,20}, /* 91: 0110 0100 1001 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* 92: 0110 0100 1001 0010 xxxx xxxx */
+ {XRI,"EOM,%b", 3,20}, /* 93: 0110 0100 1001 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 94: 0110 0100 1001 0100 xxxx xxxx */
+ {XRI,"TMM,%b", 3,20}, /* 95: 0110 0100 1001 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* 96: 0110 0100 1001 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* 97: 0110 0100 1001 0111 xxxx xxxx */
+ {ORI,"ANM,%b", 3,20}, /* 98: 0110 0100 1001 1000 xxxx xxxx */ /* 7810 */
+ {ORI,"SMH,%b", 3,20}, /* 99: 0110 0100 1001 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* 9a: 0110 0100 1001 1010 xxxx xxxx */
+ {ORI,"EOM,%b", 3,20}, /* 9b: 0110 0100 1001 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 9c: 0110 0100 1001 1100 xxxx xxxx */
+ {ORI,"TMM,%b", 3,20}, /* 9d: 0110 0100 1001 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* 9e: 0110 0100 1001 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* 9f: 0110 0100 1001 1111 xxxx xxxx */
+
+ {ADINC,"ANM,%b", 3,20}, /* a0: 0110 0100 1010 0000 xxxx xxxx */ /* 7810 */
+ {ADINC,"SMH,%b", 3,20}, /* a1: 0110 0100 1010 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* a2: 0110 0100 1010 0010 xxxx xxxx */
+ {ADINC,"EOM,%b", 3,20}, /* a3: 0110 0100 1010 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* a4: 0110 0100 1010 0100 xxxx xxxx */
+ {ADINC,"TMM,%b", 3,20}, /* a5: 0110 0100 1010 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* a6: 0110 0100 1010 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* a7: 0110 0100 1010 0111 xxxx xxxx */
+ {GTI,"ANM,%b", 3,20}, /* a8: 0110 0100 1010 1000 xxxx xxxx */ /* 7810 */
+ {GTI,"SMH,%b", 3,20}, /* a9: 0110 0100 1010 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* aa: 0110 0100 1010 1010 xxxx xxxx */
+ {GTI,"EOM,%b", 3,20}, /* ab: 0110 0100 1010 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* ac: 0110 0100 1010 1100 xxxx xxxx */
+ {GTI,"TMM,%b", 3,20}, /* ad: 0110 0100 1010 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* ae: 0110 0100 1010 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* af: 0110 0100 1010 1111 xxxx xxxx */
+
+ {SUINB,"ANM,%b", 3,20}, /* b0: 0110 0100 1011 0000 xxxx xxxx */ /* 7810 */
+ {SUINB,"SMH,%b", 3,20}, /* b1: 0110 0100 1011 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* b2: 0110 0100 1011 0010 xxxx xxxx */
+ {SUINB,"EOM,%b", 3,20}, /* b3: 0110 0100 1011 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* b4: 0110 0100 1011 0100 xxxx xxxx */
+ {SUINB,"TMM,%b", 3,20}, /* b5: 0110 0100 1011 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* b6: 0110 0100 1011 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* b7: 0110 0100 1011 0111 xxxx xxxx */
+ {LTI,"ANM,%b", 3,20}, /* b8: 0110 0100 1011 1000 xxxx xxxx */ /* 7810 */
+ {LTI,"SMH,%b", 3,20}, /* b9: 0110 0100 1011 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* ba: 0110 0100 1011 1010 xxxx xxxx */
+ {LTI,"EOM,%b", 3,20}, /* bb: 0110 0100 1011 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* bc: 0110 0100 1011 1100 xxxx xxxx */
+ {LTI,"TMM,%b", 3,20}, /* bd: 0110 0100 1011 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* be: 0110 0100 1011 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* bf: 0110 0100 1011 1111 xxxx xxxx */
+
+ {ADI,"ANM,%b", 3,20}, /* c0: 0110 0100 1100 0000 xxxx xxxx */ /* 7810 */
+ {ADI,"SMH,%b", 3,20}, /* c1: 0110 0100 1100 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* c2: 0110 0100 1100 0010 xxxx xxxx */
+ {ADI,"EOM,%b", 3,20}, /* c3: 0110 0100 1100 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* c4: 0110 0100 1100 0100 xxxx xxxx */
+ {ADI,"TMM,%b", 3,20}, /* c5: 0110 0100 1100 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* c6: 0110 0100 1100 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* c7: 0110 0100 1100 0111 xxxx xxxx */
+ {ONI,"ANM,%b", 3,20}, /* c8: 0110 0100 1100 1000 xxxx xxxx */ /* 7810 */
+ {ONI,"SMH,%b", 3,20}, /* c9: 0110 0100 1100 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* ca: 0110 0100 1100 1010 xxxx xxxx */
+ {ONI,"EOM,%b", 3,20}, /* cb: 0110 0100 1100 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* cc: 0110 0100 1100 1100 xxxx xxxx */
+ {ONI,"TMM,%b", 3,20}, /* cd: 0110 0100 1100 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* ce: 0110 0100 1100 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* cf: 0110 0100 1100 1111 xxxx xxxx */
+
+ {ACI,"ANM,%b", 3,20}, /* d0: 0110 0100 1101 0000 xxxx xxxx */ /* 7810 */
+ {ACI,"SMH,%b", 3,20}, /* d1: 0110 0100 1101 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* d2: 0110 0100 1101 0010 xxxx xxxx */
+ {ACI,"EOM,%b", 3,20}, /* d3: 0110 0100 1101 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* d4: 0110 0100 1101 0100 xxxx xxxx */
+ {ACI,"TMM,%b", 3,20}, /* d5: 0110 0100 1101 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* d6: 0110 0100 1101 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* d7: 0110 0100 1101 0111 xxxx xxxx */
+ {OFFI,"ANM,%b", 3,20}, /* d8: 0110 0100 1101 1000 xxxx xxxx */ /* 7810 */
+ {OFFI,"SMH,%b", 3,20}, /* d9: 0110 0100 1101 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* da: 0110 0100 1101 1010 xxxx xxxx */
+ {OFFI,"EOM,%b", 3,20}, /* db: 0110 0100 1101 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* dc: 0110 0100 1101 1100 xxxx xxxx */
+ {OFFI,"TMM,%b", 3,20}, /* dd: 0110 0100 1101 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* de: 0110 0100 1101 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* df: 0110 0100 1101 1111 xxxx xxxx */
+
+ {SUI,"ANM,%b", 3,20}, /* e0: 0110 0100 1110 0000 xxxx xxxx */ /* 7810 */
+ {SUI,"SMH,%b", 3,20}, /* e1: 0110 0100 1110 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* e2: 0110 0100 1110 0010 xxxx xxxx */
+ {SUI,"EOM,%b", 3,20}, /* e3: 0110 0100 1110 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* e4: 0110 0100 1110 0100 xxxx xxxx */
+ {SUI,"TMM,%b", 3,20}, /* e5: 0110 0100 1110 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* e6: 0110 0100 1110 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* e7: 0110 0100 1110 0111 xxxx xxxx */
+ {NEI,"ANM,%b", 3,20}, /* e8: 0110 0100 1110 1000 xxxx xxxx */ /* 7810 */
+ {NEI,"SMH,%b", 3,20}, /* e9: 0110 0100 1110 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* ea: 0110 0100 1110 1010 xxxx xxxx */
+ {NEI,"EOM,%b", 3,20}, /* eb: 0110 0100 1110 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* ec: 0110 0100 1110 1100 xxxx xxxx */
+ {NEI,"TMM,%b", 3,20}, /* ed: 0110 0100 1110 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* ee: 0110 0100 1110 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* ef: 0110 0100 1110 1111 xxxx xxxx */
+
+ {SBI,"ANM,%b", 3,20}, /* f0: 0110 0100 1111 0000 xxxx xxxx */ /* 7810 */
+ {SBI,"SMH,%b", 3,20}, /* f1: 0110 0100 1111 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* f2: 0110 0100 1111 0010 xxxx xxxx */
+ {SBI,"EOM,%b", 3,20}, /* f3: 0110 0100 1111 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* f4: 0110 0100 1111 0100 xxxx xxxx */
+ {SBI,"TMM,%b", 3,20}, /* f5: 0110 0100 1111 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* f6: 0110 0100 1111 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* f7: 0110 0100 1111 0111 xxxx xxxx */
+ {EQI,"ANM,%b", 3,20}, /* f8: 0110 0100 1111 1000 xxxx xxxx */ /* 7810 */
+ {EQI,"SMH,%b", 3,20}, /* f9: 0110 0100 1111 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* fa: 0110 0100 1111 1010 xxxx xxxx */
+ {EQI,"EOM,%b", 3,20}, /* fb: 0110 0100 1111 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* fc: 0110 0100 1111 1100 xxxx xxxx */
+ {EQI,"TMM,%b", 3,20}, /* fd: 0110 0100 1111 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* fe: 0110 0100 1111 1110 xxxx xxxx */
+ {illegal,0, 3,20} /* ff: 0110 0100 1111 1111 xxxx xxxx */
+};
+
+static struct dasm_s dasm64_7807[256] =
+{
+ {MVI,"PA,%b", 3,14}, /* 00: 0110 0100 0000 0000 xxxx xxxx */
+ {MVI,"PB,%b", 3,14}, /* 01: 0110 0100 0000 0001 xxxx xxxx */
+ {MVI,"PC,%b", 3,14}, /* 02: 0110 0100 0000 0010 xxxx xxxx */
+ {MVI,"PD,%b", 3,14}, /* 03: 0110 0100 0000 0011 xxxx xxxx */
+ {illegal,0, 3,14}, /* 04: 0110 0100 0000 0100 xxxx xxxx */
+ {MVI,"PF,%b", 3,14}, /* 05: 0110 0100 0000 0101 xxxx xxxx */
+ {MVI,"MKH,%b", 3,14}, /* 06: 0110 0100 0000 0110 xxxx xxxx */
+ {MVI,"MKL,%b", 3,14}, /* 07: 0110 0100 0000 0111 xxxx xxxx */
+ {ANI,"PA,%b", 3,20}, /* 08: 0110 0100 0000 1000 xxxx xxxx */
+ {ANI,"PB,%b", 3,20}, /* 09: 0110 0100 0000 1001 xxxx xxxx */
+ {ANI,"PC,%b", 3,20}, /* 0a: 0110 0100 0000 1010 xxxx xxxx */
+ {ANI,"PD,%b", 3,20}, /* 0b: 0110 0100 0000 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 0c: 0110 0100 0000 1100 xxxx xxxx */
+ {ANI,"PF,%b", 3,20}, /* 0d: 0110 0100 0000 1101 xxxx xxxx */
+ {ANI,"MKH,%b", 3,20}, /* 0e: 0110 0100 0000 1110 xxxx xxxx */
+ {ANI,"MKL,%b", 3,20}, /* 0f: 0110 0100 0000 1111 xxxx xxxx */
+
+ {XRI,"PA,%b", 3,20}, /* 10: 0110 0100 0001 0000 xxxx xxxx */
+ {XRI,"PB,%b", 3,20}, /* 11: 0110 0100 0001 0001 xxxx xxxx */
+ {XRI,"PC,%b", 3,20}, /* 12: 0110 0100 0001 0010 xxxx xxxx */
+ {XRI,"PD,%b", 3,20}, /* 13: 0110 0100 0001 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 14: 0110 0100 0001 0100 xxxx xxxx */
+ {XRI,"PF,%b", 3,20}, /* 15: 0110 0100 0001 0101 xxxx xxxx */
+ {XRI,"MKH,%b", 3,20}, /* 16: 0110 0100 0001 0110 xxxx xxxx */
+ {XRI,"MKL,%b", 3,20}, /* 17: 0110 0100 0001 0111 xxxx xxxx */
+ {ORI,"PA,%b", 3,20}, /* 18: 0110 0100 0001 1000 xxxx xxxx */
+ {ORI,"PB,%b", 3,20}, /* 19: 0110 0100 0001 1001 xxxx xxxx */
+ {ORI,"PC,%b", 3,20}, /* 1a: 0110 0100 0001 1010 xxxx xxxx */
+ {ORI,"PD,%b", 3,20}, /* 1b: 0110 0100 0001 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 1c: 0110 0100 0001 1100 xxxx xxxx */
+ {ORI,"PF,%b", 3,20}, /* 1d: 0110 0100 0001 1101 xxxx xxxx */
+ {ORI,"MKH,%b", 3,20}, /* 1e: 0110 0100 0001 1110 xxxx xxxx */
+ {ORI,"MKL,%b", 3,20}, /* 1f: 0110 0100 0001 1111 xxxx xxxx */
+
+ {ADINC,"PA,%b", 3,20}, /* 20: 0110 0100 0010 0000 xxxx xxxx */
+ {ADINC,"PB,%b", 3,20}, /* 21: 0110 0100 0010 0001 xxxx xxxx */
+ {ADINC,"PC,%b", 3,20}, /* 22: 0110 0100 0010 0010 xxxx xxxx */
+ {ADINC,"PD,%b", 3,20}, /* 23: 0110 0100 0010 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 24: 0110 0100 0010 0100 xxxx xxxx */
+ {ADINC,"PF,%b", 3,20}, /* 25: 0110 0100 0010 0101 xxxx xxxx */
+ {ADINC,"MKH,%b", 3,20}, /* 26: 0110 0100 0010 0110 xxxx xxxx */
+ {ADINC,"MKL,%b", 3,20}, /* 27: 0110 0100 0010 0111 xxxx xxxx */
+ {GTI,"PA,%b", 3,20}, /* 28: 0110 0100 0010 1000 xxxx xxxx */
+ {GTI,"PB,%b", 3,20}, /* 29: 0110 0100 0010 1001 xxxx xxxx */
+ {GTI,"PC,%b", 3,20}, /* 2a: 0110 0100 0010 1010 xxxx xxxx */
+ {GTI,"PD,%b", 3,20}, /* 2b: 0110 0100 0010 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 2c: 0110 0100 0010 1100 xxxx xxxx */
+ {GTI,"PF,%b", 3,20}, /* 2d: 0110 0100 0010 1101 xxxx xxxx */
+ {GTI,"MKH,%b", 3,20}, /* 2e: 0110 0100 0010 1110 xxxx xxxx */
+ {GTI,"MKL,%b", 3,20}, /* 2f: 0110 0100 0010 1111 xxxx xxxx */
+
+ {SUINB,"PA,%b", 3,20}, /* 30: 0110 0100 0011 0000 xxxx xxxx */
+ {SUINB,"PB,%b", 3,20}, /* 31: 0110 0100 0011 0001 xxxx xxxx */
+ {SUINB,"PC,%b", 3,20}, /* 32: 0110 0100 0011 0010 xxxx xxxx */
+ {SUINB,"PD,%b", 3,20}, /* 33: 0110 0100 0011 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 34: 0110 0100 0011 0100 xxxx xxxx */
+ {SUINB,"PF,%b", 3,20}, /* 35: 0110 0100 0011 0101 xxxx xxxx */
+ {SUINB,"MKH,%b", 3,20}, /* 36: 0110 0100 0011 0110 xxxx xxxx */
+ {SUINB,"MKL,%b", 3,20}, /* 37: 0110 0100 0011 0111 xxxx xxxx */
+ {LTI,"PA,%b", 3,20}, /* 38: 0110 0100 0011 1000 xxxx xxxx */
+ {LTI,"PB,%b", 3,20}, /* 39: 0110 0100 0011 1001 xxxx xxxx */
+ {LTI,"PC,%b", 3,20}, /* 3a: 0110 0100 0011 1010 xxxx xxxx */
+ {LTI,"PD,%b", 3,20}, /* 3b: 0110 0100 0011 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 3c: 0110 0100 0011 1100 xxxx xxxx */
+ {LTI,"PF,%b", 3,20}, /* 3d: 0110 0100 0011 1101 xxxx xxxx */
+ {LTI,"MKH,%b", 3,20}, /* 3e: 0110 0100 0011 1110 xxxx xxxx */
+ {LTI,"MKL,%b", 3,20}, /* 3f: 0110 0100 0011 1111 xxxx xxxx */
+
+ {ADI,"PA,%b", 3,20}, /* 40: 0110 0100 0100 0000 xxxx xxxx */
+ {ADI,"PB,%b", 3,20}, /* 41: 0110 0100 0100 0001 xxxx xxxx */
+ {ADI,"PC,%b", 3,20}, /* 42: 0110 0100 0100 0010 xxxx xxxx */
+ {ADI,"PD,%b", 3,20}, /* 43: 0110 0100 0100 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 44: 0110 0100 0100 0100 xxxx xxxx */
+ {ADI,"PF,%b", 3,20}, /* 45: 0110 0100 0100 0101 xxxx xxxx */
+ {ADI,"MKH,%b", 3,20}, /* 46: 0110 0100 0100 0110 xxxx xxxx */
+ {ADI,"MKL,%b", 3,20}, /* 47: 0110 0100 0100 0111 xxxx xxxx */
+ {ONI,"PA,%b", 3,20}, /* 48: 0110 0100 0100 1000 xxxx xxxx */
+ {ONI,"PB,%b", 3,20}, /* 49: 0110 0100 0100 1001 xxxx xxxx */
+ {ONI,"PC,%b", 3,20}, /* 4a: 0110 0100 0100 1010 xxxx xxxx */
+ {ONI,"PD,%b", 3,20}, /* 4b: 0110 0100 0100 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 4c: 0110 0100 0100 1100 xxxx xxxx */
+ {ONI,"PF,%b", 3,20}, /* 4d: 0110 0100 0100 1101 xxxx xxxx */
+ {ONI,"MKH,%b", 3,20}, /* 4e: 0110 0100 0100 1110 xxxx xxxx */
+ {ONI,"MKL,%b", 3,20}, /* 4f: 0110 0100 0100 1111 xxxx xxxx */
+
+ {ACI,"PA,%b", 3,20}, /* 50: 0110 0100 0101 0000 xxxx xxxx */
+ {ACI,"PB,%b", 3,20}, /* 51: 0110 0100 0101 0001 xxxx xxxx */
+ {ACI,"PC,%b", 3,20}, /* 52: 0110 0100 0101 0010 xxxx xxxx */
+ {ACI,"PD,%b", 3,20}, /* 53: 0110 0100 0101 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 54: 0110 0100 0101 0100 xxxx xxxx */
+ {ACI,"PF,%b", 3,20}, /* 55: 0110 0100 0101 0101 xxxx xxxx */
+ {ACI,"MKH,%b", 3,20}, /* 56: 0110 0100 0101 0110 xxxx xxxx */
+ {ACI,"MKL,%b", 3,20}, /* 57: 0110 0100 0101 0111 xxxx xxxx */
+ {OFFI,"PA,%b", 3,20}, /* 58: 0110 0100 0101 1000 xxxx xxxx */
+ {OFFI,"PB,%b", 3,20}, /* 59: 0110 0100 0101 1001 xxxx xxxx */
+ {OFFI,"PC,%b", 3,20}, /* 5a: 0110 0100 0101 1010 xxxx xxxx */
+ {OFFI,"PD,%b", 3,20}, /* 5b: 0110 0100 0101 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 5c: 0110 0100 0101 1100 xxxx xxxx */
+ {OFFI,"PF,%b", 3,20}, /* 5d: 0110 0100 0101 1101 xxxx xxxx */
+ {OFFI,"MKH,%b", 3,20}, /* 5e: 0110 0100 0101 1110 xxxx xxxx */
+ {OFFI,"MKL,%b", 3,20}, /* 5f: 0110 0100 0101 1111 xxxx xxxx */
+
+ {SUI,"PA,%b", 3,20}, /* 60: 0110 0100 0110 0000 xxxx xxxx */
+ {SUI,"PB,%b", 3,20}, /* 61: 0110 0100 0110 0001 xxxx xxxx */
+ {SUI,"PC,%b", 3,20}, /* 62: 0110 0100 0110 0010 xxxx xxxx */
+ {SUI,"PD,%b", 3,20}, /* 63: 0110 0100 0110 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 64: 0110 0100 0110 0100 xxxx xxxx */
+ {SUI,"PF,%b", 3,20}, /* 65: 0110 0100 0110 0101 xxxx xxxx */
+ {SUI,"MKH,%b", 3,20}, /* 66: 0110 0100 0110 0110 xxxx xxxx */
+ {SUI,"MKL,%b", 3,20}, /* 67: 0110 0100 0110 0111 xxxx xxxx */
+ {NEI,"PA,%b", 3,20}, /* 68: 0110 0100 0110 1000 xxxx xxxx */
+ {NEI,"PB,%b", 3,20}, /* 69: 0110 0100 0110 1001 xxxx xxxx */
+ {NEI,"PC,%b", 3,20}, /* 6a: 0110 0100 0110 1010 xxxx xxxx */
+ {NEI,"PD,%b", 3,20}, /* 6b: 0110 0100 0110 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 6c: 0110 0100 0110 1100 xxxx xxxx */
+ {NEI,"PF,%b", 3,20}, /* 6d: 0110 0100 0110 1101 xxxx xxxx */
+ {NEI,"MKH,%b", 3,20}, /* 6e: 0110 0100 0110 1110 xxxx xxxx */
+ {NEI,"MKL,%b", 3,20}, /* 6f: 0110 0100 0110 1111 xxxx xxxx */
+
+ {SBI,"PA,%b", 3,20}, /* 70: 0110 0100 0111 0000 xxxx xxxx */
+ {SBI,"PB,%b", 3,20}, /* 71: 0110 0100 0111 0001 xxxx xxxx */
+ {SBI,"PC,%b", 3,20}, /* 72: 0110 0100 0111 0010 xxxx xxxx */
+ {SBI,"PD,%b", 3,20}, /* 73: 0110 0100 0111 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 74: 0110 0100 0111 0100 xxxx xxxx */
+ {SBI,"PF,%b", 3,20}, /* 75: 0110 0100 0111 0101 xxxx xxxx */
+ {SBI,"MKH,%b", 3,20}, /* 76: 0110 0100 0111 0110 xxxx xxxx */
+ {SBI,"MKL,%b", 3,20}, /* 77: 0110 0100 0111 0111 xxxx xxxx */
+ {EQI,"PA,%b", 3,20}, /* 78: 0110 0100 0111 1000 xxxx xxxx */
+ {EQI,"PB,%b", 3,20}, /* 79: 0110 0100 0111 1001 xxxx xxxx */
+ {EQI,"PC,%b", 3,20}, /* 7a: 0110 0100 0111 1010 xxxx xxxx */
+ {EQI,"PD,%b", 3,20}, /* 7b: 0110 0100 0111 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 7c: 0110 0100 0111 1100 xxxx xxxx */
+ {EQI,"PF,%b", 3,20}, /* 7d: 0110 0100 0111 1101 xxxx xxxx */
+ {EQI,"MKH,%b", 3,20}, /* 7e: 0110 0100 0111 1110 xxxx xxxx */
+ {EQI,"MKL,%b", 3,20}, /* 7f: 0110 0100 0111 1111 xxxx xxxx */
+
+ {illegal,0, 3,20}, /* 80: 0110 0100 1000 0000 xxxx xxxx */
+ {MVI,"SMH,%b", 3,14}, /* 81: 0110 0100 1000 0001 xxxx xxxx */
+ {illegal,0, 3,14}, /* 82: 0110 0100 1000 0010 xxxx xxxx */
+ {MVI,"EOM,%b", 3,14}, /* 83: 0110 0100 1000 0011 xxxx xxxx */
+ {illegal,0, 3,14}, /* 84: 0110 0100 1000 0100 xxxx xxxx */
+ {MVI,"TMM,%b", 3,14}, /* 85: 0110 0100 1000 0101 xxxx xxxx */
+ {illegal,0, 3,14}, /* 86: 0110 0100 1000 0110 xxxx xxxx */
+ {illegal,0, 3,14}, /* 87: 0110 0100 1000 0111 xxxx xxxx */
+ {illegal,0, 3,20}, /* 88: 0110 0100 1000 1000 xxxx xxxx */
+ {ANI,"SMH,%b", 3,20}, /* 89: 0110 0100 1000 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* 8a: 0110 0100 1000 1010 xxxx xxxx */
+ {ANI,"EOM,%b", 3,20}, /* 8b: 0110 0100 1000 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 8c: 0110 0100 1000 1100 xxxx xxxx */
+ {ANI,"TMM,%b", 3,20}, /* 8d: 0110 0100 1000 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* 8e: 0110 0100 1000 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* 8f: 0110 0100 1000 1111 xxxx xxxx */
+
+ {illegal,0, 3,20}, /* 90: 0110 0100 1001 0000 xxxx xxxx */
+ {XRI,"SMH,%b", 3,20}, /* 91: 0110 0100 1001 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* 92: 0110 0100 1001 0010 xxxx xxxx */
+ {XRI,"EOM,%b", 3,20}, /* 93: 0110 0100 1001 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 94: 0110 0100 1001 0100 xxxx xxxx */
+ {XRI,"TMM,%b", 3,20}, /* 95: 0110 0100 1001 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* 96: 0110 0100 1001 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* 97: 0110 0100 1001 0111 xxxx xxxx */
+ {illegal,0, 3,20}, /* 98: 0110 0100 1001 1000 xxxx xxxx */
+ {ORI,"SMH,%b", 3,20}, /* 99: 0110 0100 1001 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* 9a: 0110 0100 1001 1010 xxxx xxxx */
+ {ORI,"EOM,%b", 3,20}, /* 9b: 0110 0100 1001 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* 9c: 0110 0100 1001 1100 xxxx xxxx */
+ {ORI,"TMM,%b", 3,20}, /* 9d: 0110 0100 1001 1101 xxxx xxxx */
+ {illegal,0, 3,20}, /* 9e: 0110 0100 1001 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* 9f: 0110 0100 1001 1111 xxxx xxxx */
+
+ {illegal,0, 3,20}, /* a0: 0110 0100 1010 0000 xxxx xxxx */
+ {ADINC,"SMH,%b", 3,20}, /* a1: 0110 0100 1010 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* a2: 0110 0100 1010 0010 xxxx xxxx */
+ {ADINC,"EOM,%b", 3,20}, /* a3: 0110 0100 1010 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* a4: 0110 0100 1010 0100 xxxx xxxx */
+ {ADINC,"TMM,%b", 3,20}, /* a5: 0110 0100 1010 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* a6: 0110 0100 1010 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* a7: 0110 0100 1010 0111 xxxx xxxx */
+ {illegal,0, 3,20}, /* a8: 0110 0100 1010 1000 xxxx xxxx */
+ {GTI,"SMH,%b", 3,20}, /* a9: 0110 0100 1010 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* aa: 0110 0100 1010 1010 xxxx xxxx */
+ {GTI,"EOM,%b", 3,20}, /* ab: 0110 0100 1010 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* ac: 0110 0100 1010 1100 xxxx xxxx */
+ {GTI,"TMM,%b", 3,20}, /* ad: 0110 0100 1010 1101 xxxx xxxx */
+ {GTI,"PT,%b", 3,20}, /* ae: 0110 0100 1010 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* af: 0110 0100 1010 1111 xxxx xxxx */
+
+ {illegal,0, 3,20}, /* b0: 0110 0100 1011 0000 xxxx xxxx */
+ {SUINB,"SMH,%b", 3,20}, /* b1: 0110 0100 1011 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* b2: 0110 0100 1011 0010 xxxx xxxx */
+ {SUINB,"EOM,%b", 3,20}, /* b3: 0110 0100 1011 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* b4: 0110 0100 1011 0100 xxxx xxxx */
+ {SUINB,"TMM,%b", 3,20}, /* b5: 0110 0100 1011 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* b6: 0110 0100 1011 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* b7: 0110 0100 1011 0111 xxxx xxxx */
+ {illegal,0, 3,20}, /* b8: 0110 0100 1011 1000 xxxx xxxx */
+ {LTI,"SMH,%b", 3,20}, /* b9: 0110 0100 1011 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* ba: 0110 0100 1011 1010 xxxx xxxx */
+ {LTI,"EOM,%b", 3,20}, /* bb: 0110 0100 1011 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* bc: 0110 0100 1011 1100 xxxx xxxx */
+ {LTI,"TMM,%b", 3,20}, /* bd: 0110 0100 1011 1101 xxxx xxxx */
+ {LTI,"PT,%b", 3,20}, /* be: 0110 0100 1011 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* bf: 0110 0100 1011 1111 xxxx xxxx */
+
+ {illegal,0, 3,20}, /* c0: 0110 0100 1100 0000 xxxx xxxx */
+ {ADI,"SMH,%b", 3,20}, /* c1: 0110 0100 1100 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* c2: 0110 0100 1100 0010 xxxx xxxx */
+ {ADI,"EOM,%b", 3,20}, /* c3: 0110 0100 1100 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* c4: 0110 0100 1100 0100 xxxx xxxx */
+ {ADI,"TMM,%b", 3,20}, /* c5: 0110 0100 1100 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* c6: 0110 0100 1100 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* c7: 0110 0100 1100 0111 xxxx xxxx */
+ {illegal,0, 3,20}, /* c8: 0110 0100 1100 1000 xxxx xxxx */
+ {ONI,"SMH,%b", 3,20}, /* c9: 0110 0100 1100 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* ca: 0110 0100 1100 1010 xxxx xxxx */
+ {ONI,"EOM,%b", 3,20}, /* cb: 0110 0100 1100 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* cc: 0110 0100 1100 1100 xxxx xxxx */
+ {ONI,"TMM,%b", 3,20}, /* cd: 0110 0100 1100 1101 xxxx xxxx */
+ {ONI,"PT,%b", 3,20}, /* ce: 0110 0100 1100 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* cf: 0110 0100 1100 1111 xxxx xxxx */
+
+ {illegal,0, 3,20}, /* d0: 0110 0100 1101 0000 xxxx xxxx */
+ {ACI,"SMH,%b", 3,20}, /* d1: 0110 0100 1101 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* d2: 0110 0100 1101 0010 xxxx xxxx */
+ {ACI,"EOM,%b", 3,20}, /* d3: 0110 0100 1101 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* d4: 0110 0100 1101 0100 xxxx xxxx */
+ {ACI,"TMM,%b", 3,20}, /* d5: 0110 0100 1101 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* d6: 0110 0100 1101 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* d7: 0110 0100 1101 0111 xxxx xxxx */
+ {illegal,0, 3,20}, /* d8: 0110 0100 1101 1000 xxxx xxxx */
+ {OFFI,"SMH,%b", 3,20}, /* d9: 0110 0100 1101 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* da: 0110 0100 1101 1010 xxxx xxxx */
+ {OFFI,"EOM,%b", 3,20}, /* db: 0110 0100 1101 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* dc: 0110 0100 1101 1100 xxxx xxxx */
+ {OFFI,"TMM,%b", 3,20}, /* dd: 0110 0100 1101 1101 xxxx xxxx */
+ {OFFI,"PT,%b", 3,20}, /* de: 0110 0100 1101 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* df: 0110 0100 1101 1111 xxxx xxxx */
+
+ {illegal,0, 3,20}, /* e0: 0110 0100 1110 0000 xxxx xxxx */
+ {SUI,"SMH,%b", 3,20}, /* e1: 0110 0100 1110 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* e2: 0110 0100 1110 0010 xxxx xxxx */
+ {SUI,"EOM,%b", 3,20}, /* e3: 0110 0100 1110 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* e4: 0110 0100 1110 0100 xxxx xxxx */
+ {SUI,"TMM,%b", 3,20}, /* e5: 0110 0100 1110 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* e6: 0110 0100 1110 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* e7: 0110 0100 1110 0111 xxxx xxxx */
+ {illegal,0, 3,20}, /* e8: 0110 0100 1110 1000 xxxx xxxx */
+ {NEI,"SMH,%b", 3,20}, /* e9: 0110 0100 1110 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* ea: 0110 0100 1110 1010 xxxx xxxx */
+ {NEI,"EOM,%b", 3,20}, /* eb: 0110 0100 1110 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* ec: 0110 0100 1110 1100 xxxx xxxx */
+ {NEI,"TMM,%b", 3,20}, /* ed: 0110 0100 1110 1101 xxxx xxxx */
+ {NEI,"PT,%b", 3,20}, /* ee: 0110 0100 1110 1110 xxxx xxxx */
+ {illegal,0, 3,20}, /* ef: 0110 0100 1110 1111 xxxx xxxx */
+
+ {illegal,0, 3,20}, /* f0: 0110 0100 1111 0000 xxxx xxxx */
+ {SBI,"SMH,%b", 3,20}, /* f1: 0110 0100 1111 0001 xxxx xxxx */
+ {illegal,0, 3,20}, /* f2: 0110 0100 1111 0010 xxxx xxxx */
+ {SBI,"EOM,%b", 3,20}, /* f3: 0110 0100 1111 0011 xxxx xxxx */
+ {illegal,0, 3,20}, /* f4: 0110 0100 1111 0100 xxxx xxxx */
+ {SBI,"TMM,%b", 3,20}, /* f5: 0110 0100 1111 0101 xxxx xxxx */
+ {illegal,0, 3,20}, /* f6: 0110 0100 1111 0110 xxxx xxxx */
+ {illegal,0, 3,20}, /* f7: 0110 0100 1111 0111 xxxx xxxx */
+ {illegal,0, 3,20}, /* f8: 0110 0100 1111 1000 xxxx xxxx */
+ {EQI,"SMH,%b", 3,20}, /* f9: 0110 0100 1111 1001 xxxx xxxx */
+ {illegal,0, 3,20}, /* fa: 0110 0100 1111 1010 xxxx xxxx */
+ {EQI,"EOM,%b", 3,20}, /* fb: 0110 0100 1111 1011 xxxx xxxx */
+ {illegal,0, 3,20}, /* fc: 0110 0100 1111 1100 xxxx xxxx */
+ {EQI,"TMM,%b", 3,20}, /* fd: 0110 0100 1111 1101 xxxx xxxx */
+ {EQI,"PT,%b", 3,20}, /* fe: 0110 0100 1111 1110 xxxx xxxx */
+ {illegal,0, 3,20} /* ff: 0110 0100 1111 1111 xxxx xxxx */
+};
+
+/* prefix 70 */
+static struct dasm_s dasm70[256] =
+{
+ {illegal,0, 2, 8}, /* 00: 0111 0000 0000 0000 */
+ {illegal,0, 2, 8}, /* 01: 0111 0000 0000 0001 */
+ {illegal,0, 2, 8}, /* 02: 0111 0000 0000 0010 */
+ {illegal,0, 2, 8}, /* 03: 0111 0000 0000 0011 */
+ {illegal,0, 2, 8}, /* 04: 0111 0000 0000 0100 */
+ {illegal,0, 2, 8}, /* 05: 0111 0000 0000 0101 */
+ {illegal,0, 2, 8}, /* 06: 0111 0000 0000 0110 */
+ {illegal,0, 2, 8}, /* 07: 0111 0000 0000 0111 */
+ {illegal,0, 2, 8}, /* 08: 0111 0000 0000 1000 */
+ {illegal,0, 2, 8}, /* 09: 0111 0000 0000 1001 */
+ {illegal,0, 2, 8}, /* 0a: 0111 0000 0000 1010 */
+ {illegal,0, 2, 8}, /* 0b: 0111 0000 0000 1011 */
+ {illegal,0, 2, 8}, /* 0c: 0111 0000 0000 1100 */
+ {illegal,0, 2, 8}, /* 0d: 0111 0000 0000 1101 */
+ {SSPD,"%w", 4,20}, /* 0e: 0111 0000 0000 1110 llll llll hhhh hhhh */
+ {LSPD,"%w", 4,20}, /* 0f: 0111 0000 0000 1111 llll llll hhhh hhhh */
+
+ {illegal,0, 2, 8}, /* 10: 0111 0000 0001 0000 */
+ {illegal,0, 2, 8}, /* 11: 0111 0000 0001 0001 */
+ {illegal,0, 2, 8}, /* 12: 0111 0000 0001 0010 */
+ {illegal,0, 2, 8}, /* 13: 0111 0000 0001 0011 */
+ {illegal,0, 2, 8}, /* 14: 0111 0000 0001 0100 */
+ {illegal,0, 2, 8}, /* 15: 0111 0000 0001 0101 */
+ {illegal,0, 2, 8}, /* 16: 0111 0000 0001 0110 */
+ {illegal,0, 2, 8}, /* 17: 0111 0000 0001 0111 */
+ {illegal,0, 2, 8}, /* 18: 0111 0000 0001 1000 */
+ {illegal,0, 2, 8}, /* 19: 0111 0000 0001 1001 */
+ {illegal,0, 2, 8}, /* 1a: 0111 0000 0001 1010 */
+ {illegal,0, 2, 8}, /* 1b: 0111 0000 0001 1011 */
+ {illegal,0, 2, 8}, /* 1c: 0111 0000 0001 1100 */
+ {illegal,0, 2, 8}, /* 1d: 0111 0000 0001 1101 */
+ {SBCD,"%w", 4,20}, /* 1e: 0111 0000 0001 1110 llll llll hhhh hhhh */
+ {LBCD,"%w", 4,20}, /* 1f: 0111 0000 0001 1111 llll llll hhhh hhhh */
+
+ {illegal,0, 2, 8}, /* 20: 0111 0000 0010 0000 */
+ {illegal,0, 2, 8}, /* 21: 0111 0000 0010 0001 */
+ {illegal,0, 2, 8}, /* 22: 0111 0000 0010 0010 */
+ {illegal,0, 2, 8}, /* 23: 0111 0000 0010 0011 */
+ {illegal,0, 2, 8}, /* 24: 0111 0000 0010 0100 */
+ {illegal,0, 2, 8}, /* 25: 0111 0000 0010 0101 */
+ {illegal,0, 2, 8}, /* 26: 0111 0000 0010 0110 */
+ {illegal,0, 2, 8}, /* 27: 0111 0000 0010 0111 */
+ {illegal,0, 2, 8}, /* 28: 0111 0000 0010 1000 */
+ {illegal,0, 2, 8}, /* 29: 0111 0000 0010 1001 */
+ {illegal,0, 2, 8}, /* 2a: 0111 0000 0010 1010 */
+ {illegal,0, 2, 8}, /* 2b: 0111 0000 0010 1011 */
+ {illegal,0, 2, 8}, /* 2c: 0111 0000 0010 1100 */
+ {illegal,0, 2, 8}, /* 2d: 0111 0000 0010 1101 */
+ {SDED,"%w", 4,20}, /* 2e: 0111 0000 0010 1110 llll llll hhhh hhhh */
+ {LDED,"%w", 4,20}, /* 2f: 0111 0000 0010 1111 llll llll hhhh hhhh */
+
+ {illegal,0, 2, 8}, /* 30: 0111 0000 0011 0000 */
+ {illegal,0, 2, 8}, /* 31: 0111 0000 0011 0001 */
+ {illegal,0, 2, 8}, /* 32: 0111 0000 0011 0010 */
+ {illegal,0, 2, 8}, /* 33: 0111 0000 0011 0011 */
+ {illegal,0, 2, 8}, /* 34: 0111 0000 0011 0100 */
+ {illegal,0, 2, 8}, /* 35: 0111 0000 0011 0101 */
+ {illegal,0, 2, 8}, /* 36: 0111 0000 0011 0110 */
+ {illegal,0, 2, 8}, /* 37: 0111 0000 0011 0111 */
+ {illegal,0, 2, 8}, /* 38: 0111 0000 0011 1000 */
+ {illegal,0, 2, 8}, /* 39: 0111 0000 0011 1001 */
+ {illegal,0, 2, 8}, /* 3a: 0111 0000 0011 1010 */
+ {illegal,0, 2, 8}, /* 3b: 0111 0000 0011 1011 */
+ {illegal,0, 2, 8}, /* 3c: 0111 0000 0011 1100 */
+ {illegal,0, 2, 8}, /* 3d: 0111 0000 0011 1101 */
+ {SHLD,"%w", 4,20}, /* 3e: 0111 0000 0011 1110 llll llll hhhh hhhh */
+ {LHLD,"%w", 4,20}, /* 3f: 0111 0000 0011 1111 llll llll hhhh hhhh */
+
+ {EADD,"EA,V", 2,11}, /* 40: 0111 0000 0100 0000 */
+ {EADD,"EA,A", 2,11}, /* 41: 0111 0000 0100 0001 */
+ {EADD,"EA,B", 2,11}, /* 42: 0111 0000 0100 0010 */
+ {EADD,"EA,C", 2,11}, /* 43: 0111 0000 0100 0011 */
+ {illegal,0, 2, 8}, /* 44: 0111 0000 0100 0100 */
+ {illegal,0, 2, 8}, /* 45: 0111 0000 0100 0101 */
+ {illegal,0, 2, 8}, /* 46: 0111 0000 0100 0110 */
+ {illegal,0, 2, 8}, /* 47: 0111 0000 0100 0111 */
+ {illegal,0, 2, 8}, /* 48: 0111 0000 0100 1000 */
+ {illegal,0, 2, 8}, /* 49: 0111 0000 0100 1001 */
+ {illegal,0, 2, 8}, /* 4a: 0111 0000 0100 1010 */
+ {illegal,0, 2, 8}, /* 4b: 0111 0000 0100 1011 */
+ {illegal,0, 2, 8}, /* 4c: 0111 0000 0100 1100 */
+ {illegal,0, 2, 8}, /* 4d: 0111 0000 0100 1101 */
+ {illegal,0, 2, 8}, /* 4e: 0111 0000 0100 1110 */
+ {illegal,0, 2, 8}, /* 4f: 0111 0000 0100 1111 */
+
+ {illegal,0, 2, 8}, /* 50: 0111 0000 0101 0000 */
+ {illegal,0, 2, 8}, /* 51: 0111 0000 0101 0001 */
+ {illegal,0, 2, 8}, /* 52: 0111 0000 0101 0010 */
+ {illegal,0, 2, 8}, /* 53: 0111 0000 0101 0011 */
+ {illegal,0, 2, 8}, /* 54: 0111 0000 0101 0100 */
+ {illegal,0, 2, 8}, /* 55: 0111 0000 0101 0101 */
+ {illegal,0, 2, 8}, /* 56: 0111 0000 0101 0110 */
+ {illegal,0, 2, 8}, /* 57: 0111 0000 0101 0111 */
+ {illegal,0, 2, 8}, /* 58: 0111 0000 0101 1000 */
+ {illegal,0, 2, 8}, /* 59: 0111 0000 0101 1001 */
+ {illegal,0, 2, 8}, /* 5a: 0111 0000 0101 1010 */
+ {illegal,0, 2, 8}, /* 5b: 0111 0000 0101 1011 */
+ {illegal,0, 2, 8}, /* 5c: 0111 0000 0101 1100 */
+ {illegal,0, 2, 8}, /* 5d: 0111 0000 0101 1101 */
+ {illegal,0, 2, 8}, /* 5e: 0111 0000 0101 1110 */
+ {illegal,0, 2, 8}, /* 5f: 0111 0000 0101 1111 */
+
+ {ESUB,"EA,V", 2,11}, /* 60: 0111 0000 0110 0000 */
+ {ESUB,"EA,A", 2,11}, /* 61: 0111 0000 0110 0001 */
+ {ESUB,"EA,B", 2,11}, /* 62: 0111 0000 0110 0010 */
+ {ESUB,"EA,C", 2,11}, /* 63: 0111 0000 0110 0011 */
+ {illegal,0, 2, 8}, /* 64: 0111 0000 0110 0100 */
+ {illegal,0, 2, 8}, /* 65: 0111 0000 0110 0101 */
+ {illegal,0, 2, 8}, /* 66: 0111 0000 0110 0110 */
+ {illegal,0, 2, 8}, /* 67: 0111 0000 0110 0111 */
+ {MOV,"V,(%w)", 4,17}, /* 68: 0111 0000 0110 1000 llll llll hhhh hhhh */
+ {MOV,"A,(%w)", 4,17}, /* 69: 0111 0000 0110 1001 llll llll hhhh hhhh */
+ {MOV,"B,(%w)", 4,17}, /* 6a: 0111 0000 0110 1010 llll llll hhhh hhhh */
+ {MOV,"C,(%w)", 4,17}, /* 6b: 0111 0000 0110 1011 llll llll hhhh hhhh */
+ {MOV,"D,(%w)", 4,17}, /* 6c: 0111 0000 0110 1100 llll llll hhhh hhhh */
+ {MOV,"E,(%w)", 4,17}, /* 6d: 0111 0000 0110 1101 llll llll hhhh hhhh */
+ {MOV,"H,(%w)", 4,17}, /* 6e: 0111 0000 0110 1110 llll llll hhhh hhhh */
+ {MOV,"L,(%w)", 4,17}, /* 6f: 0111 0000 0110 1111 llll llll hhhh hhhh */
+
+ {illegal,0, 2, 8}, /* 70: 0111 0000 0111 0000 */
+ {illegal,0, 2, 8}, /* 71: 0111 0000 0111 0001 */
+ {illegal,0, 2, 8}, /* 72: 0111 0000 0111 0010 */
+ {illegal,0, 2, 8}, /* 73: 0111 0000 0111 0011 */
+ {illegal,0, 2, 8}, /* 74: 0111 0000 0111 0100 */
+ {illegal,0, 2, 8}, /* 75: 0111 0000 0111 0101 */
+ {illegal,0, 2, 8}, /* 76: 0111 0000 0111 0110 */
+ {illegal,0, 2, 8}, /* 77: 0111 0000 0111 0111 */
+ {MOV,"(%w),V", 4,17}, /* 78: 0111 0000 0111 1000 llll llll hhhh hhhh */
+ {MOV,"(%w),A", 4,17}, /* 79: 0111 0000 0111 1001 llll llll hhhh hhhh */
+ {MOV,"(%w),B", 4,17}, /* 7a: 0111 0000 0111 1010 llll llll hhhh hhhh */
+ {MOV,"(%w),C", 4,17}, /* 7b: 0111 0000 0111 1011 llll llll hhhh hhhh */
+ {MOV,"(%w),D", 4,17}, /* 7c: 0111 0000 0111 1100 llll llll hhhh hhhh */
+ {MOV,"(%w),E", 4,17}, /* 7d: 0111 0000 0111 1101 llll llll hhhh hhhh */
+ {MOV,"(%w),H", 4,17}, /* 7e: 0111 0000 0111 1110 llll llll hhhh hhhh */
+ {MOV,"(%w),L", 4,17}, /* 7f: 0111 0000 0111 1111 llll llll hhhh hhhh */
+
+ {illegal,0, 2, 8}, /* 80: 0111 0000 1000 0000 */
+ {illegal,0, 2, 8}, /* 81: 0111 0000 1000 0001 */
+ {illegal,0, 2, 8}, /* 82: 0111 0000 1000 0010 */
+ {illegal,0, 2, 8}, /* 83: 0111 0000 1000 0011 */
+ {illegal,0, 2, 8}, /* 84: 0111 0000 1000 0100 */
+ {illegal,0, 2, 8}, /* 85: 0111 0000 1000 0101 */
+ {illegal,0, 2, 8}, /* 86: 0111 0000 1000 0110 */
+ {illegal,0, 2, 8}, /* 87: 0111 0000 1000 0111 */
+ {illegal,0, 2,11}, /* 88: 0111 0000 1000 1000 */
+ {ANAX,"(BC)", 2,11}, /* 89: 0111 0000 1000 1001 */
+ {ANAX,"(DE)", 2,11}, /* 8a: 0111 0000 1000 1010 */
+ {ANAX,"(HL)", 2,11}, /* 8b: 0111 0000 1000 1011 */
+ {ANAX,"(DE+)", 2,11}, /* 8c: 0111 0000 1000 1100 */
+ {ANAX,"(HL+)", 2,11}, /* 8d: 0111 0000 1000 1101 */
+ {ANAX,"(DE-)", 2,11}, /* 8e: 0111 0000 1000 1110 */
+ {ANAX,"(HL-)", 2,11}, /* 8f: 0111 0000 1000 1111 */
+
+ {illegal,0, 2,11}, /* 90: 0111 0000 1001 0000 */
+ {XRAX,"(BC)", 2,11}, /* 91: 0111 0000 1001 0001 */
+ {XRAX,"(DE)", 2,11}, /* 92: 0111 0000 1001 0010 */
+ {XRAX,"(HL)", 2,11}, /* 93: 0111 0000 1001 0011 */
+ {XRAX,"(DE+)", 2,11}, /* 94: 0111 0000 1001 0100 */
+ {XRAX,"(HL+)", 2,11}, /* 95: 0111 0000 1001 0101 */
+ {XRAX,"(DE-)", 2,11}, /* 96: 0111 0000 1001 0110 */
+ {XRAX,"(HL-)", 2,11}, /* 97: 0111 0000 1001 0111 */
+ {illegal,0, 2, 8}, /* 98: 0111 0000 1001 1000 */
+ {ORAX,"(BC)", 2, 8}, /* 99: 0111 0000 1001 1001 */
+ {ORAX,"(DE)", 2, 8}, /* 9a: 0111 0000 1001 1010 */
+ {ORAX,"(HL)", 2, 8}, /* 9b: 0111 0000 1001 1011 */
+ {ORAX,"(DE+)", 2, 8}, /* 9c: 0111 0000 1001 1100 */
+ {ORAX,"(HL+)", 2, 8}, /* 9d: 0111 0000 1001 1101 */
+ {ORAX,"(DE-)", 2, 8}, /* 9e: 0111 0000 1001 1110 */
+ {ORAX,"(HL-)", 2, 8}, /* 9f: 0111 0000 1001 1111 */
+
+ {illegal,0, 2,11}, /* a0: 0111 0000 1010 0000 */
+ {ADDNCX,"(BC)", 2,11}, /* a1: 0111 0000 1010 0001 */
+ {ADDNCX,"(DE)", 2,11}, /* a2: 0111 0000 1010 0010 */
+ {ADDNCX,"(HL)", 2,11}, /* a3: 0111 0000 1010 0011 */
+ {ADDNCX,"(DE+)", 2,11}, /* a4: 0111 0000 1010 0100 */
+ {ADDNCX,"(HL+)", 2,11}, /* a5: 0111 0000 1010 0101 */
+ {ADDNCX,"(DE-)", 2,11}, /* a6: 0111 0000 1010 0110 */
+ {ADDNCX,"(HL-)", 2,11}, /* a7: 0111 0000 1010 0111 */
+ {illegal,0, 2,11}, /* a8: 0111 0000 1010 1000 */
+ {GTAX,"(BC)", 2,11}, /* a9: 0111 0000 1010 1001 */
+ {GTAX,"(DE)", 2,11}, /* aa: 0111 0000 1010 1010 */
+ {GTAX,"(HL)", 2,11}, /* ab: 0111 0000 1010 1011 */
+ {GTAX,"(DE+)", 2,11}, /* ac: 0111 0000 1010 1100 */
+ {GTAX,"(HL+)", 2,11}, /* ad: 0111 0000 1010 1101 */
+ {GTAX,"(DE-)", 2,11}, /* ae: 0111 0000 1010 1110 */
+ {GTAX,"(HL-)", 2,11}, /* af: 0111 0000 1010 1111 */
+
+ {illegal,0, 2,11}, /* b0: 0111 0000 1011 0000 */
+ {SUBNBX,"(BC)", 2,11}, /* b1: 0111 0000 1011 0001 */
+ {SUBNBX,"(DE)", 2,11}, /* b2: 0111 0000 1011 0010 */
+ {SUBNBX,"(HL)", 2,11}, /* b3: 0111 0000 1011 0011 */
+ {SUBNBX,"(DE+)", 2,11}, /* b4: 0111 0000 1011 0100 */
+ {SUBNBX,"(HL+)", 2,11}, /* b5: 0111 0000 1011 0101 */
+ {SUBNBX,"(DE-)", 2,11}, /* b6: 0111 0000 1011 0110 */
+ {SUBNBX,"(HL-)", 2,11}, /* b7: 0111 0000 1011 0111 */
+ {illegal,0, 2,11}, /* b8: 0111 0000 1011 1000 */
+ {LTAX,"(BC)", 2,11}, /* b9: 0111 0000 1011 1001 */
+ {LTAX,"(DE)", 2,11}, /* ba: 0111 0000 1011 1010 */
+ {LTAX,"(HL)", 2,11}, /* bb: 0111 0000 1011 1011 */
+ {LTAX,"(DE+)", 2,11}, /* bc: 0111 0000 1011 1100 */
+ {LTAX,"(HL+)", 2,11}, /* bd: 0111 0000 1011 1101 */
+ {LTAX,"(DE-)", 2,11}, /* be: 0111 0000 1011 1110 */
+ {LTAX,"(HL-)", 2,11}, /* bf: 0111 0000 1011 1111 */
+
+ {illegal,0, 2,11}, /* c0: 0111 0000 1100 0000 */
+ {ADDX,"(BC)", 2,11}, /* c1: 0111 0000 1100 0001 */
+ {ADDX,"(DE)", 2,11}, /* c2: 0111 0000 1100 0010 */
+ {ADDX,"(HL)", 2,11}, /* c3: 0111 0000 1100 0011 */
+ {ADDX,"(DE+)", 2,11}, /* c4: 0111 0000 1100 0100 */
+ {ADDX,"(HL+)", 2,11}, /* c5: 0111 0000 1100 0101 */
+ {ADDX,"(DE-)", 2,11}, /* c6: 0111 0000 1100 0110 */
+ {ADDX,"(HL-)", 2,11}, /* c7: 0111 0000 1100 0111 */
+ {illegal,0, 2,11}, /* c8: 0111 0000 1100 1000 */
+ {ONAX,"(BC)", 2,11}, /* c9: 0111 0000 1100 1001 */
+ {ONAX,"(DE)", 2,11}, /* ca: 0111 0000 1100 1010 */
+ {ONAX,"(HL)", 2,11}, /* cb: 0111 0000 1100 1011 */
+ {ONAX,"(DE+)", 2,11}, /* cc: 0111 0000 1100 1100 */
+ {ONAX,"(HL+)", 2,11}, /* cd: 0111 0000 1100 1101 */
+ {ONAX,"(DE-)", 2,11}, /* ce: 0111 0000 1100 1110 */
+ {ONAX,"(HL-)", 2,11}, /* cf: 0111 0000 1100 1111 */
+
+ {illegal,0, 2,11}, /* d0: 0111 0000 1101 0000 */
+ {ADCX,"(BC)", 2,11}, /* d1: 0111 0000 1101 0001 */
+ {ADCX,"(DE)", 2,11}, /* d2: 0111 0000 1101 0010 */
+ {ADCX,"(HL)", 2,11}, /* d3: 0111 0000 1101 0011 */
+ {ADCX,"(DE+)", 2,11}, /* d4: 0111 0000 1101 0100 */
+ {ADCX,"(HL+)", 2,11}, /* d5: 0111 0000 1101 0101 */
+ {ADCX,"(DE-)", 2,11}, /* d6: 0111 0000 1101 0110 */
+ {ADCX,"(HL-)", 2,11}, /* d7: 0111 0000 1101 0111 */
+ {illegal,0, 2,11}, /* d8: 0111 0000 1101 1000 */
+ {OFFAX,"(BC)", 2,11}, /* d9: 0111 0000 1101 1001 */
+ {OFFAX,"(DE)", 2,11}, /* da: 0111 0000 1101 1010 */
+ {OFFAX,"(HL)", 2,11}, /* db: 0111 0000 1101 1011 */
+ {OFFAX,"(DE+)", 2,11}, /* dc: 0111 0000 1101 1100 */
+ {OFFAX,"(HL+)", 2,11}, /* dd: 0111 0000 1101 1101 */
+ {OFFAX,"(DE-)", 2,11}, /* de: 0111 0000 1101 1110 */
+ {OFFAX,"(HL-)", 2,11}, /* df: 0111 0000 1101 1111 */
+
+ {illegal,0, 2,11}, /* e0: 0111 0000 1110 0000 */
+ {SUBX,"(BC)", 2,11}, /* e1: 0111 0000 1110 0001 */
+ {SUBX,"(DE)", 2,11}, /* e2: 0111 0000 1110 0010 */
+ {SUBX,"(HL)", 2,11}, /* e3: 0111 0000 1110 0011 */
+ {SUBX,"(DE+)", 2,11}, /* e4: 0111 0000 1110 0100 */
+ {SUBX,"(HL+)", 2,11}, /* e5: 0111 0000 1110 0101 */
+ {SUBX,"(DE-)", 2,11}, /* e6: 0111 0000 1110 0110 */
+ {SUBX,"(HL-)", 2,11}, /* e7: 0111 0000 1110 0111 */
+ {illegal,0, 2,11}, /* e8: 0111 0000 1110 1000 */
+ {NEAX,"(BC)", 2,11}, /* e9: 0111 0000 1110 1001 */
+ {NEAX,"(DE)", 2,11}, /* ea: 0111 0000 1110 1010 */
+ {NEAX,"(HL)", 2,11}, /* eb: 0111 0000 1110 1011 */
+ {NEAX,"(DE+)", 2,11}, /* ec: 0111 0000 1110 1100 */
+ {NEAX,"(HL+)", 2,11}, /* ed: 0111 0000 1110 1101 */
+ {NEAX,"(DE-)", 2,11}, /* ee: 0111 0000 1110 1110 */
+ {NEAX,"(HL-)", 2,11}, /* ef: 0111 0000 1110 1111 */
+
+ {illegal,0, 2,11}, /* f0: 0111 0000 1111 0000 */
+ {SBBX,"(BC)", 2,11}, /* f1: 0111 0000 1111 0001 */
+ {SBBX,"(DE)", 2,11}, /* f2: 0111 0000 1111 0010 */
+ {SBBX,"(HL)", 2,11}, /* f3: 0111 0000 1111 0011 */
+ {SBBX,"(DE+)", 2,11}, /* f4: 0111 0000 1111 0100 */
+ {SBBX,"(HL+)", 2,11}, /* f5: 0111 0000 1111 0101 */
+ {SBBX,"(DE-)", 2,11}, /* f6: 0111 0000 1111 0110 */
+ {SBBX,"(HL-)", 2,11}, /* f7: 0111 0000 1111 0111 */
+ {illegal,0, 2,11}, /* f8: 0111 0000 1111 1000 */
+ {EQAX,"(BC)", 2,11}, /* f9: 0111 0000 1111 1001 */
+ {EQAX,"(DE)", 2,11}, /* fa: 0111 0000 1111 1010 */
+ {EQAX,"(HL)", 2,11}, /* fb: 0111 0000 1111 1011 */
+ {EQAX,"(DE+)", 2,11}, /* fc: 0111 0000 1111 1100 */
+ {EQAX,"(HL+)", 2,11}, /* fd: 0111 0000 1111 1101 */
+ {EQAX,"(DE-)", 2,11}, /* fe: 0111 0000 1111 1110 */
+ {EQAX,"(HL-)", 2,11} /* ff: 0111 0000 1111 1111 */
+};
+
+/* prefix 74 */
+static struct dasm_s dasm74[256] =
+{
+ {illegal,0, 2, 8}, /* 00: 0111 0100 0000 0000 */
+ {illegal,0, 2, 8}, /* 01: 0111 0100 0000 0001 */
+ {illegal,0, 2, 8}, /* 02: 0111 0100 0000 0010 */
+ {illegal,0, 2, 8}, /* 03: 0111 0100 0000 0011 */
+ {illegal,0, 2, 8}, /* 04: 0111 0100 0000 0100 */
+ {illegal,0, 2, 8}, /* 05: 0111 0100 0000 0101 */
+ {illegal,0, 2, 8}, /* 06: 0111 0100 0000 0110 */
+ {illegal,0, 2, 8}, /* 07: 0111 0100 0000 0111 */
+ {ANI,"V,%b", 3,11}, /* 08: 0111 0100 0000 1000 xxxx xxxx */
+ {ANI,"A,%b", 3,11}, /* 09: 0111 0100 0000 1001 xxxx xxxx */
+ {ANI,"B,%b", 3,11}, /* 0a: 0111 0100 0000 1010 xxxx xxxx */
+ {ANI,"C,%b", 3,11}, /* 0b: 0111 0100 0000 1011 xxxx xxxx */
+ {ANI,"D,%b", 3,11}, /* 0c: 0111 0100 0000 1100 xxxx xxxx */
+ {ANI,"E,%b", 3,11}, /* 0d: 0111 0100 0000 1101 xxxx xxxx */
+ {ANI,"H,%b", 3,11}, /* 0e: 0111 0100 0000 1110 xxxx xxxx */
+ {ANI,"L,%b", 3,11}, /* 0f: 0111 0100 0000 1111 xxxx xxxx */
+
+ {XRI,"V,%b", 3,11}, /* 10: 0111 0100 0001 0000 xxxx xxxx */
+ {XRI,"A,%b", 3,11}, /* 11: 0111 0100 0001 0001 xxxx xxxx */
+ {XRI,"B,%b", 3,11}, /* 12: 0111 0100 0001 0010 xxxx xxxx */
+ {XRI,"C,%b", 3,11}, /* 13: 0111 0100 0001 0011 xxxx xxxx */
+ {XRI,"D,%b", 3,11}, /* 14: 0111 0100 0001 0100 xxxx xxxx */
+ {XRI,"E,%b", 3,11}, /* 15: 0111 0100 0001 0101 xxxx xxxx */
+ {XRI,"H,%b", 3,11}, /* 16: 0111 0100 0001 0110 xxxx xxxx */
+ {XRI,"L,%b", 3,11}, /* 17: 0111 0100 0001 0111 xxxx xxxx */
+ {ORI,"V,%b", 3,11}, /* 18: 0111 0100 0001 1000 xxxx xxxx */
+ {ORI,"A,%b", 3,11}, /* 19: 0111 0100 0001 1001 xxxx xxxx */
+ {ORI,"B,%b", 3,11}, /* 1a: 0111 0100 0001 1010 xxxx xxxx */
+ {ORI,"C,%b", 3,11}, /* 1b: 0111 0100 0001 1011 xxxx xxxx */
+ {ORI,"D,%b", 3,11}, /* 1c: 0111 0100 0001 1100 xxxx xxxx */
+ {ORI,"E,%b", 3,11}, /* 1d: 0111 0100 0001 1101 xxxx xxxx */
+ {ORI,"H,%b", 3,11}, /* 1e: 0111 0100 0001 1110 xxxx xxxx */
+ {ORI,"L,%b", 3,11}, /* 1f: 0111 0100 0001 1111 xxxx xxxx */
+
+ {ADINC,"V,%b", 3,11}, /* 20: 0111 0100 0010 0000 xxxx xxxx */
+ {ADINC,"A,%b", 3,11}, /* 21: 0111 0100 0010 0001 xxxx xxxx */
+ {ADINC,"B,%b", 3,11}, /* 22: 0111 0100 0010 0010 xxxx xxxx */
+ {ADINC,"C,%b", 3,11}, /* 23: 0111 0100 0010 0011 xxxx xxxx */
+ {ADINC,"D,%b", 3,11}, /* 24: 0111 0100 0010 0100 xxxx xxxx */
+ {ADINC,"E,%b", 3,11}, /* 25: 0111 0100 0010 0101 xxxx xxxx */
+ {ADINC,"H,%b", 3,11}, /* 26: 0111 0100 0010 0110 xxxx xxxx */
+ {ADINC,"L,%b", 3,11}, /* 27: 0111 0100 0010 0111 xxxx xxxx */
+ {GTI,"V,%b", 3,11}, /* 28: 0111 0100 0010 1000 xxxx xxxx */
+ {GTI,"A,%b", 3,11}, /* 29: 0111 0100 0010 1001 xxxx xxxx */
+ {GTI,"B,%b", 3,11}, /* 2a: 0111 0100 0010 1010 xxxx xxxx */
+ {GTI,"C,%b", 3,11}, /* 2b: 0111 0100 0010 1011 xxxx xxxx */
+ {GTI,"D,%b", 3,11}, /* 2c: 0111 0100 0010 1100 xxxx xxxx */
+ {GTI,"E,%b", 3,11}, /* 2d: 0111 0100 0010 1101 xxxx xxxx */
+ {GTI,"H,%b", 3,11}, /* 2e: 0111 0100 0010 1110 xxxx xxxx */
+ {GTI,"L,%b", 3,11}, /* 2f: 0111 0100 0010 1111 xxxx xxxx */
+
+ {SUINB,"V,%b", 3,11}, /* 30: 0111 0100 0011 0000 xxxx xxxx */
+ {SUINB,"A,%b", 3,11}, /* 31: 0111 0100 0011 0001 xxxx xxxx */
+ {SUINB,"B,%b", 3,11}, /* 32: 0111 0100 0011 0010 xxxx xxxx */
+ {SUINB,"C,%b", 3,11}, /* 33: 0111 0100 0011 0011 xxxx xxxx */
+ {SUINB,"D,%b", 3,11}, /* 34: 0111 0100 0011 0100 xxxx xxxx */
+ {SUINB,"E,%b", 3,11}, /* 35: 0111 0100 0011 0101 xxxx xxxx */
+ {SUINB,"H,%b", 3,11}, /* 36: 0111 0100 0011 0110 xxxx xxxx */
+ {SUINB,"L,%b", 3,11}, /* 37: 0111 0100 0011 0111 xxxx xxxx */
+ {LTI,"V,%b", 3,11}, /* 38: 0111 0100 0011 1000 xxxx xxxx */
+ {LTI,"A,%b", 3,11}, /* 39: 0111 0100 0011 1001 xxxx xxxx */
+ {LTI,"B,%b", 3,11}, /* 3a: 0111 0100 0011 1010 xxxx xxxx */
+ {LTI,"C,%b", 3,11}, /* 3b: 0111 0100 0011 1011 xxxx xxxx */
+ {LTI,"D,%b", 3,11}, /* 3c: 0111 0100 0011 1100 xxxx xxxx */
+ {LTI,"E,%b", 3,11}, /* 3d: 0111 0100 0011 1101 xxxx xxxx */
+ {LTI,"H,%b", 3,11}, /* 3e: 0111 0100 0011 1110 xxxx xxxx */
+ {LTI,"L,%b", 3,11}, /* 3f: 0111 0100 0011 1111 xxxx xxxx */
+
+ {ADI,"V,%b", 3,11}, /* 40: 0111 0100 0100 0000 xxxx xxxx */
+ {ADI,"A,%b", 3,11}, /* 41: 0111 0100 0100 0001 xxxx xxxx */
+ {ADI,"B,%b", 3,11}, /* 42: 0111 0100 0100 0010 xxxx xxxx */
+ {ADI,"C,%b", 3,11}, /* 43: 0111 0100 0100 0011 xxxx xxxx */
+ {ADI,"D,%b", 3,11}, /* 44: 0111 0100 0100 0100 xxxx xxxx */
+ {ADI,"E,%b", 3,11}, /* 45: 0111 0100 0100 0101 xxxx xxxx */
+ {ADI,"H,%b", 3,11}, /* 46: 0111 0100 0100 0110 xxxx xxxx */
+ {ADI,"L,%b", 3,11}, /* 47: 0111 0100 0100 0111 xxxx xxxx */
+ {ONI,"V,%b", 3,11}, /* 48: 0111 0100 0100 1000 xxxx xxxx */
+ {ONI,"A,%b", 3,11}, /* 49: 0111 0100 0100 1001 xxxx xxxx */
+ {ONI,"B,%b", 3,11}, /* 4a: 0111 0100 0100 1010 xxxx xxxx */
+ {ONI,"C,%b", 3,11}, /* 4b: 0111 0100 0100 1011 xxxx xxxx */
+ {ONI,"D,%b", 3,11}, /* 4c: 0111 0100 0100 1100 xxxx xxxx */
+ {ONI,"E,%b", 3,11}, /* 4d: 0111 0100 0100 1101 xxxx xxxx */
+ {ONI,"H,%b", 3,11}, /* 4e: 0111 0100 0100 1110 xxxx xxxx */
+ {ONI,"L,%b", 3,11}, /* 4f: 0111 0100 0100 1111 xxxx xxxx */
+
+ {ACI,"V,%b", 3,11}, /* 50: 0111 0100 0101 0000 xxxx xxxx */
+ {ACI,"A,%b", 3,11}, /* 51: 0111 0100 0101 0001 xxxx xxxx */
+ {ACI,"B,%b", 3,11}, /* 52: 0111 0100 0101 0010 xxxx xxxx */
+ {ACI,"C,%b", 3,11}, /* 53: 0111 0100 0101 0011 xxxx xxxx */
+ {ACI,"D,%b", 3,11}, /* 54: 0111 0100 0101 0100 xxxx xxxx */
+ {ACI,"E,%b", 3,11}, /* 55: 0111 0100 0101 0101 xxxx xxxx */
+ {ACI,"H,%b", 3,11}, /* 56: 0111 0100 0101 0110 xxxx xxxx */
+ {ACI,"L,%b", 3,11}, /* 57: 0111 0100 0101 0111 xxxx xxxx */
+ {OFFI,"V,%b", 3,11}, /* 58: 0111 0100 0101 1000 xxxx xxxx */
+ {OFFI,"A,%b", 3,11}, /* 59: 0111 0100 0101 1001 xxxx xxxx */
+ {OFFI,"B,%b", 3,11}, /* 5a: 0111 0100 0101 1010 xxxx xxxx */
+ {OFFI,"C,%b", 3,11}, /* 5b: 0111 0100 0101 1011 xxxx xxxx */
+ {OFFI,"D,%b", 3,11}, /* 5c: 0111 0100 0101 1100 xxxx xxxx */
+ {OFFI,"E,%b", 3,11}, /* 5d: 0111 0100 0101 1101 xxxx xxxx */
+ {OFFI,"H,%b", 3,11}, /* 5e: 0111 0100 0101 1110 xxxx xxxx */
+ {OFFI,"L,%b", 3,11}, /* 5f: 0111 0100 0101 1111 xxxx xxxx */
+
+ {SUI,"V,%b", 3,11}, /* 60: 0111 0100 0110 0000 xxxx xxxx */
+ {SUI,"A,%b", 3,11}, /* 61: 0111 0100 0110 0001 xxxx xxxx */
+ {SUI,"B,%b", 3,11}, /* 62: 0111 0100 0110 0010 xxxx xxxx */
+ {SUI,"C,%b", 3,11}, /* 63: 0111 0100 0110 0011 xxxx xxxx */
+ {SUI,"D,%b", 3,11}, /* 64: 0111 0100 0110 0100 xxxx xxxx */
+ {SUI,"E,%b", 3,11}, /* 65: 0111 0100 0110 0101 xxxx xxxx */
+ {SUI,"H,%b", 3,11}, /* 66: 0111 0100 0110 0110 xxxx xxxx */
+ {SUI,"L,%b", 3,11}, /* 67: 0111 0100 0110 0111 xxxx xxxx */
+ {NEI,"V,%b", 3,11}, /* 68: 0111 0100 0110 1000 xxxx xxxx */
+ {NEI,"A,%b", 3,11}, /* 69: 0111 0100 0110 1001 xxxx xxxx */
+ {NEI,"B,%b", 3,11}, /* 6a: 0111 0100 0110 1010 xxxx xxxx */
+ {NEI,"C,%b", 3,11}, /* 6b: 0111 0100 0110 1011 xxxx xxxx */
+ {NEI,"D,%b", 3,11}, /* 6c: 0111 0100 0110 1100 xxxx xxxx */
+ {NEI,"E,%b", 3,11}, /* 6d: 0111 0100 0110 1101 xxxx xxxx */
+ {NEI,"H,%b", 3,11}, /* 6e: 0111 0100 0110 1110 xxxx xxxx */
+ {NEI,"L,%b", 3,11}, /* 6f: 0111 0100 0110 1111 xxxx xxxx */
+
+ {SBI,"V,%b", 3,11}, /* 70: 0111 0100 0111 0000 xxxx xxxx */
+ {SBI,"A,%b", 3,11}, /* 71: 0111 0100 0111 0001 xxxx xxxx */
+ {SBI,"B,%b", 3,11}, /* 72: 0111 0100 0111 0010 xxxx xxxx */
+ {SBI,"C,%b", 3,11}, /* 73: 0111 0100 0111 0011 xxxx xxxx */
+ {SBI,"D,%b", 3,11}, /* 74: 0111 0100 0111 0100 xxxx xxxx */
+ {SBI,"E,%b", 3,11}, /* 75: 0111 0100 0111 0101 xxxx xxxx */
+ {SBI,"H,%b", 3,11}, /* 76: 0111 0100 0111 0110 xxxx xxxx */
+ {SBI,"L,%b", 3,11}, /* 77: 0111 0100 0111 0111 xxxx xxxx */
+ {EQI,"V,%b", 3,11}, /* 78: 0111 0100 0111 1000 xxxx xxxx */
+ {EQI,"A,%b", 3,11}, /* 79: 0111 0100 0111 1001 xxxx xxxx */
+ {EQI,"B,%b", 3,11}, /* 7a: 0111 0100 0111 1010 xxxx xxxx */
+ {EQI,"C,%b", 3,11}, /* 7b: 0111 0100 0111 1011 xxxx xxxx */
+ {EQI,"D,%b", 3,11}, /* 7c: 0111 0100 0111 1100 xxxx xxxx */
+ {EQI,"E,%b", 3,11}, /* 7d: 0111 0100 0111 1101 xxxx xxxx */
+ {EQI,"H,%b", 3,11}, /* 7e: 0111 0100 0111 1110 xxxx xxxx */
+ {EQI,"L,%b", 3,11}, /* 7f: 0111 0100 0111 1111 xxxx xxxx */
+
+ {illegal,0, 2, 8}, /* 80: 0111 0100 1000 0000 */
+ {illegal,0, 2, 8}, /* 81: 0111 0100 1000 0001 */
+ {illegal,0, 2, 8}, /* 82: 0111 0100 1000 0010 */
+ {illegal,0, 2, 8}, /* 83: 0111 0100 1000 0011 */
+ {illegal,0, 2, 8}, /* 84: 0111 0100 1000 0100 */
+ {illegal,0, 2, 8}, /* 85: 0111 0100 1000 0101 */
+ {illegal,0, 2, 8}, /* 86: 0111 0100 1000 0110 */
+ {illegal,0, 2, 8}, /* 87: 0111 0100 1000 0111 */
+ {ANAW,"%a", 3,14}, /* 88: 0111 0100 1000 1000 oooo oooo */
+ {illegal,0, 2, 8}, /* 89: 0111 0100 1000 1001 */
+ {illegal,0, 2, 8}, /* 8a: 0111 0100 1000 1010 */
+ {illegal,0, 2, 8}, /* 8b: 0111 0100 1000 1011 */
+ {illegal,0, 2, 8}, /* 8c: 0111 0100 1000 1100 */
+ {DAN,"EA,BC", 2,11}, /* 8d: 0111 0100 1000 1101 */
+ {DAN,"EA,DE", 2,11}, /* 8e: 0111 0100 1000 1110 */
+ {DAN,"EA,HL", 2,11}, /* 8f: 0111 0100 1000 1111 */
+
+ {XRAW,"%a", 3,14}, /* 90: 0111 0100 1001 0000 oooo oooo */
+ {illegal,0, 2, 8}, /* 91: 0111 0100 1001 0001 */
+ {illegal,0, 2, 8}, /* 92: 0111 0100 1001 0010 */
+ {illegal,0, 2, 8}, /* 93: 0111 0100 1001 0011 */
+ {illegal,0, 2, 8}, /* 94: 0111 0100 1001 0100 */
+ {DXR,"EA,BC", 2,11}, /* 95: 0111 0100 1001 0101 */
+ {DXR,"EA,DE", 2,11}, /* 96: 0111 0100 1001 0110 */
+ {DXR,"EA,HL", 2,11}, /* 97: 0111 0100 1001 0111 */
+ {ORAW,"%a", 3,14}, /* 98: 0111 0100 1001 1000 oooo oooo */
+ {illegal,0, 2, 8}, /* 99: 0111 0100 1001 1001 */
+ {illegal,0, 2, 8}, /* 9a: 0111 0100 1001 1010 */
+ {illegal,0, 2, 8}, /* 9b: 0111 0100 1001 1011 */
+ {illegal,0, 2, 8}, /* 9c: 0111 0100 1001 1100 */
+ {DOR,"EA,BC", 2,11}, /* 9d: 0111 0100 1001 1101 */
+ {DOR,"EA,DE", 2,11}, /* 9e: 0111 0100 1001 1110 */
+ {DOR,"EA,HL", 2,11}, /* 9f: 0111 0100 1001 1111 */
+
+ {ADDNCW,"%a", 3,14}, /* a0: 0111 0100 1010 0000 oooo oooo */
+ {illegal,0, 2, 8}, /* a1: 0111 0100 1010 0001 */
+ {illegal,0, 2, 8}, /* a2: 0111 0100 1010 0010 */
+ {illegal,0, 2, 8}, /* a3: 0111 0100 1010 0011 */
+ {illegal,0, 2, 8}, /* a4: 0111 0100 1010 0100 */
+ {DADDNC,"EA,BC", 2,11}, /* a5: 0111 0100 1010 0101 */
+ {DADDNC,"EA,DE", 2,11}, /* a6: 0111 0100 1010 0110 */
+ {DADDNC,"EA,HL", 2,11}, /* a7: 0111 0100 1010 0111 */
+ {GTAW,"%a", 3,14}, /* a8: 0111 0100 1010 1000 oooo oooo */
+ {illegal,0, 2, 8}, /* a9: 0111 0100 1010 1001 */
+ {illegal,0, 2, 8}, /* aa: 0111 0100 1010 1010 */
+ {illegal,0, 2, 8}, /* ab: 0111 0100 1010 1011 */
+ {illegal,0, 2, 8}, /* ac: 0111 0100 1010 1100 */
+ {DGT,"EA,BC", 2,11}, /* ad: 0111 0100 1010 1101 */
+ {DGT,"EA,DE", 2,11}, /* ae: 0111 0100 1010 1110 */
+ {DGT,"EA,HL", 2,11}, /* af: 0111 0100 1010 1111 */
+
+ {SUBNBW,"%a", 3,14}, /* b0: 0111 0100 1011 0000 oooo oooo */
+ {illegal,0, 2, 8}, /* b1: 0111 0100 1011 0001 */
+ {illegal,0, 2, 8}, /* b2: 0111 0100 1011 0010 */
+ {illegal,0, 2, 8}, /* b3: 0111 0100 1011 0011 */
+ {illegal,0, 2, 8}, /* b4: 0111 0100 1011 0100 */
+ {DSUBNB,"EA,BC", 2,11}, /* b5: 0111 0100 1011 0101 */
+ {DSUBNB,"EA,DE", 2,11}, /* b6: 0111 0100 1011 0110 */
+ {DSUBNB,"EA,HL", 2,11}, /* b7: 0111 0100 1011 0111 */
+ {LTAW,"%a", 3,14}, /* b8: 0111 0100 1011 1000 oooo oooo */
+ {illegal,0, 2, 8}, /* b9: 0111 0100 1011 1001 */
+ {illegal,0, 2, 8}, /* ba: 0111 0100 1011 1010 */
+ {illegal,0, 2, 8}, /* bb: 0111 0100 1011 1011 */
+ {illegal,0, 2, 8}, /* bc: 0111 0100 1011 1100 */
+ {DLT,"EA,BC", 2,11}, /* bd: 0111 0100 1011 1101 */
+ {DLT,"EA,DE", 2,11}, /* be: 0111 0100 1011 1110 */
+ {DLT,"EA,HL", 2,11}, /* bf: 0111 0100 1011 1111 */
+
+ {ADDW,"%a", 3,14}, /* c0: 0111 0100 1100 0000 oooo oooo */
+ {illegal,0, 2, 8}, /* c1: 0111 0100 1100 0001 */
+ {illegal,0, 2, 8}, /* c2: 0111 0100 1100 0010 */
+ {illegal,0, 2, 8}, /* c3: 0111 0100 1100 0011 */
+ {illegal,0, 2, 8}, /* c4: 0111 0100 1100 0100 */
+ {DADD,"EA,BC", 2,11}, /* c5: 0111 0100 1100 0101 */
+ {DADD,"EA,DE", 2,11}, /* c6: 0111 0100 1100 0110 */
+ {DADD,"EA,HL", 2,11}, /* c7: 0111 0100 1100 0111 */
+ {ONAW,"%a", 3,14}, /* c8: 0111 0100 1100 1000 oooo oooo */
+ {illegal,0, 2, 8}, /* c9: 0111 0100 1100 1001 */
+ {illegal,0, 2, 8}, /* ca: 0111 0100 1100 1010 */
+ {illegal,0, 2, 8}, /* cb: 0111 0100 1100 1011 */
+ {illegal,0, 2, 8}, /* cc: 0111 0100 1100 1100 */
+ {DON,"EA,BC", 2,11}, /* cd: 0111 0100 1100 1101 */
+ {DON,"EA,DE", 2,11}, /* ce: 0111 0100 1100 1110 */
+ {DON,"EA,HL", 2,11}, /* cf: 0111 0100 1100 1111 */
+
+ {ADCW,"%a", 3,14}, /* d0: 0111 0100 1101 0000 oooo oooo */
+ {illegal,0, 2, 8}, /* d1: 0111 0100 1101 0001 */
+ {illegal,0, 2, 8}, /* d2: 0111 0100 1101 0010 */
+ {illegal,0, 2, 8}, /* d3: 0111 0100 1101 0011 */
+ {illegal,0, 2, 8}, /* d4: 0111 0100 1101 0100 */
+ {DADC,"EA,BC", 2,11}, /* d5: 0111 0100 1101 0101 */
+ {DADC,"EA,DE", 2,11}, /* d6: 0111 0100 1101 0110 */
+ {DADC,"EA,HL", 2,11}, /* d7: 0111 0100 1101 0111 */
+ {OFFAW,"%a", 3,14}, /* d8: 0111 0100 1101 1000 oooo oooo */
+ {illegal,0, 2, 8}, /* d9: 0111 0100 1101 1001 */
+ {illegal,0, 2, 8}, /* da: 0111 0100 1101 1010 */
+ {illegal,0, 2, 8}, /* db: 0111 0100 1101 1011 */
+ {illegal,0, 2, 8}, /* dc: 0111 0100 1101 1100 */
+ {DOFF,"EA,BC", 2,11}, /* dd: 0111 0100 1101 1101 */
+ {DOFF,"EA,DE", 2,11}, /* de: 0111 0100 1101 1110 */
+ {DOFF,"EA,HL", 2,11}, /* df: 0111 0100 1101 1111 */
+
+ {SUBW,"%a", 3,14}, /* e0: 0111 0100 1110 0000 oooo oooo */
+ {illegal,0, 2, 8}, /* e1: 0111 0100 1110 0001 */
+ {illegal,0, 2, 8}, /* e2: 0111 0100 1110 0010 */
+ {illegal,0, 2, 8}, /* e3: 0111 0100 1110 0011 */
+ {illegal,0, 2, 8}, /* e4: 0111 0100 1110 0100 */
+ {DSUB,"EA,BC", 2,11}, /* e5: 0111 0100 1110 0101 */
+ {DSUB,"EA,DE", 2,11}, /* e6: 0111 0100 1110 0110 */
+ {DSUB,"EA,HL", 2,11}, /* e7: 0111 0100 1110 0111 */
+ {NEAW,"%a", 3,14}, /* e8: 0111 0100 1110 1000 oooo oooo */
+ {illegal,0, 2, 8}, /* e9: 0111 0100 1110 1001 */
+ {illegal,0, 2, 8}, /* ea: 0111 0100 1110 1010 */
+ {illegal,0, 2, 8}, /* eb: 0111 0100 1110 1011 */
+ {illegal,0, 2, 8}, /* ec: 0111 0100 1110 1100 */
+ {DNE,"EA,BC", 2,11}, /* ed: 0111 0100 1110 1101 */
+ {DNE,"EA,DE", 2,11}, /* ee: 0111 0100 1110 1110 */
+ {DNE,"EA,HL", 2,11}, /* ef: 0111 0100 1110 1111 */
+
+ {SBBW,"%a", 3,14}, /* f0: 0111 0100 1111 0000 oooo oooo */
+ {illegal,0, 2, 8}, /* f1: 0111 0100 1111 0001 */
+ {illegal,0, 2, 8}, /* f2: 0111 0100 1111 0010 */
+ {illegal,0, 2, 8}, /* f3: 0111 0100 1111 0011 */
+ {illegal,0, 2, 8}, /* f4: 0111 0100 1111 0100 */
+ {DSBB,"EA,BC", 2,11}, /* f5: 0111 0100 1111 0101 */
+ {DSBB,"EA,DE", 2,11}, /* f6: 0111 0100 1111 0110 */
+ {DSBB,"EA,HL", 2,11}, /* f7: 0111 0100 1111 0111 */
+ {EQAW,"%a", 3,14}, /* f8: 0111 0100 1111 1000 oooo oooo */
+ {illegal,0, 2, 8}, /* f9: 0111 0100 1111 1001 */
+ {illegal,0, 2, 8}, /* fa: 0111 0100 1111 1010 */
+ {illegal,0, 2, 8}, /* fb: 0111 0100 1111 1011 */
+ {illegal,0, 2, 8}, /* fc: 0111 0100 1111 1100 */
+ {DEQ,"EA,BC", 2,11}, /* fd: 0111 0100 1111 1101 */
+ {DEQ,"EA,DE", 2,11}, /* fe: 0111 0100 1111 1110 */
+ {DEQ,"EA,HL", 2,11} /* ff: 0111 0100 1111 1111 */
+};
+
+/* main opcodes */
+static struct dasm_s dasmXX_7810[256] =
+{
+ {NOP,0, 1, 4}, /* 00: 0000 0000 */
+ {LDAW,"%a", 2,10}, /* 01: 0000 0001 oooo oooo */
+ {INX,"SP", 1, 7}, /* 02: 0000 0010 */
+ {DCX,"SP", 1, 7}, /* 03: 0000 0011 */
+ {LXI,"SP,%w", 3,10}, /* 04: 0000 0100 llll llll hhhh hhhh */
+ {ANIW,"%a,%b", 3,19}, /* 05: 0000 0101 oooo oooo xxxx xxxx */
+ {illegal,0, 1, 4}, /* 06: */
+ {ANI,"A,%b", 2, 7}, /* 07: 0000 0111 xxxx xxxx */
+ {MOV,"A,EAH", 1, 4}, /* 08: 0000 1000 */
+ {MOV,"A,EAL", 1, 4}, /* 09: 0000 1001 */
+ {MOV,"A,B", 1, 4}, /* 0a: 0000 1010 */
+ {MOV,"A,C", 1, 4}, /* 0b: 0000 1011 */
+ {MOV,"A,D", 1, 4}, /* 0c: 0000 1100 */
+ {MOV,"A,E", 1, 4}, /* 0d: 0000 1101 */
+ {MOV,"A,H", 1, 4}, /* 0e: 0000 1110 */
+ {MOV,"A,L", 1, 4}, /* 0f: 0000 1111 */
+
+ {EXA,0, 1, 4}, /* 10: 0001 0000 */ /* 7810 */
+ {EXX,0, 1, 4}, /* 11: 0001 0001 */ /* 7810 */
+ {INX,"BC", 1, 7}, /* 12: 0001 0010 */
+ {DCX,"BC", 1, 7}, /* 13: 0001 0011 */
+ {LXI,"BC,%w", 3,10}, /* 14: 0001 0100 llll llll hhhh hhhh */
+ {ORIW,"%a,%b", 3,19}, /* 15: 0001 0101 oooo oooo xxxx xxxx */
+ {XRI,"A,%b", 2, 7}, /* 16: 0001 0110 xxxx xxxx */
+ {ORI,"A,%b", 2, 7}, /* 17: 0001 0111 xxxx xxxx */
+ {MOV,"EAH,A", 1, 4}, /* 18: 0001 1000 */
+ {MOV,"EAL,A", 1, 4}, /* 19: 0001 1001 */
+ {MOV,"B,A", 1, 4}, /* 1a: 0001 1010 */
+ {MOV,"C,A", 1, 4}, /* 1b: 0001 1011 */
+ {MOV,"D,A", 1, 4}, /* 1c: 0001 1100 */
+ {MOV,"E,A", 1, 4}, /* 1d: 0001 1101 */
+ {MOV,"H,A", 1, 4}, /* 1e: 0001 1110 */
+ {MOV,"L,A", 1, 4}, /* 1f: 0001 1111 */
+
+ {INRW,"%a", 2,16}, /* 20: 0010 0000 oooo oooo */
+ {JB,0, 1, 4}, /* 21: 0010 0001 */
+ {INX,"DE", 1, 7}, /* 22: 0010 0010 */
+ {DCX,"DE", 1, 7}, /* 23: 0010 0011 */
+ {LXI,"DE,%w", 3,10}, /* 24: 0010 0100 llll llll hhhh hhhh */
+ {GTIW,"%a,%b", 3,19}, /* 25: 0010 0101 oooo oooo xxxx xxxx */
+ {ADINC,"A,%b", 2, 7}, /* 26: 0010 0110 xxxx xxxx */
+ {GTI,"A,%b", 2, 7}, /* 27: 0010 0111 xxxx xxxx */
+ {illegal,0, 1, 4}, /* 28: 0010 1000 */
+ {LDAX,"(BC)", 1, 7}, /* 29: 0010 1001 */
+ {LDAX,"(DE)", 1, 7}, /* 2a: 0010 1010 */
+ {LDAX,"(HL)", 1, 7}, /* 2b: 0010 1011 */
+ {LDAX,"(DE+)", 1, 7}, /* 2c: 0010 1100 */
+ {LDAX,"(HL+)", 1, 7}, /* 2d: 0010 1101 */
+ {LDAX,"(DE-)", 1, 7}, /* 2e: 0010 1110 */
+ {LDAX,"(HL-)", 1, 7}, /* 2f: 0010 1111 */
+
+ {DCRW,"%a", 2,16}, /* 30: 0011 0000 oooo oooo */
+ {BLOCK,0, 1,13}, /* 31: 0011 0001 */ /* 7810 */
+ {INX,"HL", 1, 7}, /* 32: 0011 0010 */
+ {DCX,"HL", 1, 7}, /* 33: 0011 0011 */
+ {LXI,"HL,%w", 3,10}, /* 34: 0011 0100 llll llll hhhh hhhh */
+ {LTIW,"%a,%b", 3,19}, /* 35: 0011 0101 oooo oooo xxxx xxxx */
+ {SUINB,"A,%b", 2, 7}, /* 36: 0011 0110 xxxx xxxx */
+ {LTI,"A,%b", 2, 7}, /* 37: 0011 0111 xxxx xxxx */
+ {illegal,0, 1, 4}, /* 38: */
+ {STAX,"(BC)", 1, 7}, /* 39: 0011 1001 */
+ {STAX,"(DE)", 1, 7}, /* 3a: 0011 1010 */
+ {STAX,"(HL)", 1, 7}, /* 3b: 0011 1011 */
+ {STAX,"(DE+)", 1, 7}, /* 3c: 0011 1100 */
+ {STAX,"(HL+)", 1, 7}, /* 3d: 0011 1101 */
+ {STAX,"(DE-)", 1, 7}, /* 3e: 0011 1110 */
+ {STAX,"(HL-)", 1, 7}, /* 3f: 0011 1111 */
+
+ {CALL,"%w", 3,16}, /* 40: 0100 0000 llll llll hhhh hhhh */
+ {INR,"A", 1, 4}, /* 41: 0100 0001 */
+ {INR,"B", 1, 4}, /* 42: 0100 0010 */
+ {INR,"C", 1, 4}, /* 43: 0100 0011 */
+ {LXI,"EA,%w", 3,10}, /* 44: 0100 0100 llll llll hhhh hhhh */
+ {ONIW,"%a,%b", 3,19}, /* 45: 0100 0101 oooo oooo xxxx xxxx */
+ {ADI,"A,%b", 2, 7}, /* 46: 0100 0110 xxxx xxxx */
+ {ONI,"A,%b", 2, 7}, /* 47: 0100 0111 xxxx xxxx */
+ {0,dasm48_7810, 0, 0}, /* 48: prefix */
+ {MVIX,"BC,%b", 2,10}, /* 49: 0100 1001 xxxx xxxx */
+ {MVIX,"DE,%b", 2,10}, /* 4a: 0100 1010 xxxx xxxx */
+ {MVIX,"HL,%b", 2,10}, /* 4b: 0100 1011 xxxx xxxx */
+ {0,dasm4C_7810, 0, 0}, /* 4c: prefix */
+ {0,dasm4D_7810, 0, 0}, /* 4d: prefix */
+ {JRE,"%d", 2,10}, /* 4e: 0100 111d dddd dddd */
+ {JRE,"%d", 2,10}, /* 4f: 0100 111d dddd dddd */
+
+ {EXH,0, 1, 4}, /* 50: 0101 0000 */ /* 7810 */
+ {DCR,"A", 1, 4}, /* 51: 0101 0001 */
+ {DCR,"B", 1, 4}, /* 52: 0101 0010 */
+ {DCR,"C", 1, 4}, /* 53: 0101 0011 */
+ {JMP,"%w", 3,10}, /* 54: 0101 0100 llll llll hhhh hhhh */
+ {OFFIW,"%a,%b", 3,19}, /* 55: 0101 0101 oooo oooo xxxx xxxx */
+ {ACI,"A,%b", 2, 7}, /* 56: 0101 0110 xxxx xxxx */
+ {OFFI,"A,%b", 2, 7}, /* 57: 0101 0111 xxxx xxxx */
+ {BIT,"0,%a", 2,10}, /* 58: 0101 1000 oooo oooo */ /* 7810 */
+ {BIT,"1,%a", 2,10}, /* 59: 0101 1001 oooo oooo */ /* 7810 */
+ {BIT,"2,%a", 2,10}, /* 5a: 0101 1010 oooo oooo */ /* 7810 */
+ {BIT,"3,%a", 2,10}, /* 5b: 0101 1011 oooo oooo */ /* 7810 */
+ {BIT,"4,%a", 2,10}, /* 5c: 0101 1100 oooo oooo */ /* 7810 */
+ {BIT,"5,%a", 2,10}, /* 5d: 0101 1101 oooo oooo */ /* 7810 */
+ {BIT,"6,%a", 2,10}, /* 5e: 0101 1110 oooo oooo */ /* 7810 */
+ {BIT,"7,%a", 2,10}, /* 5f: 0101 1111 oooo oooo */ /* 7810 */
+
+ {0,dasm60, 0, 0}, /* 60: prefix */
+ {DAA,0, 1, 4}, /* 61: 0110 0001 */
+ {RETI,0, 1,13}, /* 62: 0110 0010 */
+ {STAW,"%a", 2,10}, /* 63: 0110 0011 oooo oooo */
+ {0,dasm64_7810, 0, 0}, /* 64: prefix */
+ {NEIW,"%a,%b", 3,19}, /* 65: 0110 0101 oooo oooo xxxx xxxx */
+ {SUI,"A,%b", 2, 7}, /* 66: 0110 0110 xxxx xxxx */
+ {NEI,"A,%b", 2, 7}, /* 67: 0110 0111 xxxx xxxx */
+ {MVI,"V,%b", 2, 7}, /* 68: 0110 1000 xxxx xxxx */
+ {MVI,"A,%b", 2, 7}, /* 69: 0110 1001 xxxx xxxx */
+ {MVI,"B,%b", 2, 7}, /* 6a: 0110 1010 xxxx xxxx */
+ {MVI,"C,%b", 2, 7}, /* 6b: 0110 1011 xxxx xxxx */
+ {MVI,"D,%b", 2, 7}, /* 6c: 0110 1100 xxxx xxxx */
+ {MVI,"E,%b", 2, 7}, /* 6d: 0110 1101 xxxx xxxx */
+ {MVI,"H,%b", 2, 7}, /* 6e: 0110 1110 xxxx xxxx */
+ {MVI,"L,%b", 2, 7}, /* 6f: 0110 1111 xxxx xxxx */
+
+ {0,dasm70, 0, 0}, /* 70: prefix */
+ {MVIW,"%a,%b", 3,13}, /* 71: 0111 0001 oooo oooo xxxx xxxx */
+ {SOFTI,0, 1,16}, /* 72: 0111 0010 */
+ {illegal,0, 1, 0}, /* 73: */
+ {0,dasm74, 0, 0}, /* 74: prefix */
+ {EQIW,"%a,%b", 3,19}, /* 75: 0111 0101 oooo oooo xxxx xxxx */
+ {SBI,"A,%b", 2, 7}, /* 76: 0111 0110 xxxx xxxx */
+ {EQI,"A,%b", 2, 7}, /* 77: 0111 0111 xxxx xxxx */
+ {CALF,"%f", 2,13}, /* 78: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 79: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7a: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7b: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7c: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7d: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7e: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7f: 0111 1ddd dddd dddd */
+
+ {CALT,"%t", 1,16}, /* 80: 100t tttt */
+ {CALT,"%t", 1,16}, /* 81: 100t tttt */
+ {CALT,"%t", 1,16}, /* 82: 100t tttt */
+ {CALT,"%t", 1,16}, /* 83: 100t tttt */
+ {CALT,"%t", 1,16}, /* 84: 100t tttt */
+ {CALT,"%t", 1,16}, /* 85: 100t tttt */
+ {CALT,"%t", 1,16}, /* 86: 100t tttt */
+ {CALT,"%t", 1,16}, /* 87: 100t tttt */
+ {CALT,"%t", 1,16}, /* 88: 100t tttt */
+ {CALT,"%t", 1,16}, /* 89: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8a: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8b: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8c: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8d: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8e: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8f: 100t tttt */
+
+ {CALT,"%t", 1,16}, /* 90: 100t tttt */
+ {CALT,"%t", 1,16}, /* 91: 100t tttt */
+ {CALT,"%t", 1,16}, /* 92: 100t tttt */
+ {CALT,"%t", 1,16}, /* 93: 100t tttt */
+ {CALT,"%t", 1,16}, /* 94: 100t tttt */
+ {CALT,"%t", 1,16}, /* 95: 100t tttt */
+ {CALT,"%t", 1,16}, /* 96: 100t tttt */
+ {CALT,"%t", 1,16}, /* 97: 100t tttt */
+ {CALT,"%t", 1,16}, /* 98: 100t tttt */
+ {CALT,"%t", 1,16}, /* 99: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9a: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9b: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9c: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9d: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9e: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9f: 100t tttt */
+
+ {POP,"VA", 1,10}, /* a0: 1010 0000 */
+ {POP,"BC", 1,10}, /* a1: 1010 0001 */
+ {POP,"DE", 1,10}, /* a2: 1010 0010 */
+ {POP,"HL", 1,10}, /* a3: 1010 0011 */
+ {POP,"EA", 1,10}, /* a4: 1010 0100 */
+ {DMOV,"EA,BC", 1, 4}, /* a5: 1010 0101 */
+ {DMOV,"EA,DE", 1, 4}, /* a6: 1010 0110 */
+ {DMOV,"EA,HL", 1, 4}, /* a7: 1010 0111 */
+ {INX,"EA", 1, 7}, /* a8: 1010 1000 */
+ {DCX,"EA", 1, 7}, /* a9: 1010 1001 */
+ {EI,0, 1, 4}, /* aa: 1010 1010 */
+ {LDAX,"(DE+%b)", 2,13}, /* ab: 1010 1011 dddd dddd */
+ {LDAX,"(HL+A)", 1,13}, /* ac: 1010 1100 */
+ {LDAX,"(HL+B)", 1,13}, /* ad: 1010 1101 */
+ {LDAX,"(HL+EA)", 1,13}, /* ae: 1010 1110 */
+ {LDAX,"(HL+%b)", 2,13}, /* af: 1010 1111 dddd dddd */
+
+ {PUSH,"VA", 1,13}, /* b0: 1011 0000 */
+ {PUSH,"BC", 1,13}, /* b1: 1011 0001 */
+ {PUSH,"DE", 1,13}, /* b2: 1011 0010 */
+ {PUSH,"HL", 1,13}, /* b3: 1011 0011 */
+ {PUSH,"EA", 1,13}, /* b4: 1011 0100 */
+ {DMOV,"BC,EA", 1, 4}, /* b5: 1011 0101 */
+ {DMOV,"DE,EA", 1, 4}, /* b6: 1011 0110 */
+ {DMOV,"HL,EA", 1, 4}, /* b7: 1011 0111 */
+ {RET,0, 1,10}, /* b8: 1011 1000 */
+ {RETS,0, 1,10}, /* b9: 1011 1001 */
+ {DI,0, 1, 4}, /* ba: 1011 1010 */
+ {STAX,"(DE+%b)", 2,13}, /* bb: 1011 1011 dddd dddd */
+ {STAX,"(HL+A)", 1,13}, /* bc: 1011 1100 */
+ {STAX,"(HL+B)", 1,13}, /* bd: 1011 1101 */
+ {STAX,"(HL+EA)", 1,13}, /* be: 1011 1110 */
+ {STAX,"(HL+%b)", 2,13}, /* bf: 1011 1111 dddd dddd */
+
+ {JR,"%o", 1,10}, /* c0: 11oo oooo */
+ {JR,"%o", 1,10}, /* c1: 11oo oooo */
+ {JR,"%o", 1,10}, /* c2: 11oo oooo */
+ {JR,"%o", 1,10}, /* c3: 11oo oooo */
+ {JR,"%o", 1,10}, /* c4: 11oo oooo */
+ {JR,"%o", 1,10}, /* c5: 11oo oooo */
+ {JR,"%o", 1,10}, /* c6: 11oo oooo */
+ {JR,"%o", 1,10}, /* c7: 11oo oooo */
+ {JR,"%o", 1,10}, /* c8: 11oo oooo */
+ {JR,"%o", 1,10}, /* c9: 11oo oooo */
+ {JR,"%o", 1,10}, /* ca: 11oo oooo */
+ {JR,"%o", 1,10}, /* cb: 11oo oooo */
+ {JR,"%o", 1,10}, /* cc: 11oo oooo */
+ {JR,"%o", 1,10}, /* cd: 11oo oooo */
+ {JR,"%o", 1,10}, /* ce: 11oo oooo */
+ {JR,"%o", 1,10}, /* cf: 11oo oooo */
+
+ {JR,"%o", 1,10}, /* d0: 11oo oooo */
+ {JR,"%o", 1,10}, /* d1: 11oo oooo */
+ {JR,"%o", 1,10}, /* d2: 11oo oooo */
+ {JR,"%o", 1,10}, /* d3: 11oo oooo */
+ {JR,"%o", 1,10}, /* d4: 11oo oooo */
+ {JR,"%o", 1,10}, /* d5: 11oo oooo */
+ {JR,"%o", 1,10}, /* d6: 11oo oooo */
+ {JR,"%o", 1,10}, /* d7: 11oo oooo */
+ {JR,"%o", 1,10}, /* d8: 11oo oooo */
+ {JR,"%o", 1,10}, /* d9: 11oo oooo */
+ {JR,"%o", 1,10}, /* da: 11oo oooo */
+ {JR,"%o", 1,10}, /* db: 11oo oooo */
+ {JR,"%o", 1,10}, /* dc: 11oo oooo */
+ {JR,"%o", 1,10}, /* dd: 11oo oooo */
+ {JR,"%o", 1,10}, /* de: 11oo oooo */
+ {JR,"%o", 1,10}, /* df: 11oo oooo */
+
+ {JR,"%o", 1,10}, /* e0: 11oo oooo */
+ {JR,"%o", 1,10}, /* e1: 11oo oooo */
+ {JR,"%o", 1,10}, /* e2: 11oo oooo */
+ {JR,"%o", 1,10}, /* e3: 11oo oooo */
+ {JR,"%o", 1,10}, /* e4: 11oo oooo */
+ {JR,"%o", 1,10}, /* e5: 11oo oooo */
+ {JR,"%o", 1,10}, /* e6: 11oo oooo */
+ {JR,"%o", 1,10}, /* e7: 11oo oooo */
+ {JR,"%o", 1,10}, /* e8: 11oo oooo */
+ {JR,"%o", 1,10}, /* e9: 11oo oooo */
+ {JR,"%o", 1,10}, /* ea: 11oo oooo */
+ {JR,"%o", 1,10}, /* eb: 11oo oooo */
+ {JR,"%o", 1,10}, /* ec: 11oo oooo */
+ {JR,"%o", 1,10}, /* ed: 11oo oooo */
+ {JR,"%o", 1,10}, /* ee: 11oo oooo */
+ {JR,"%o", 1,10}, /* ef: 11oo oooo */
+
+ {JR,"%o", 1,10}, /* f0: 11oo oooo */
+ {JR,"%o", 1,10}, /* f1: 11oo oooo */
+ {JR,"%o", 1,10}, /* f2: 11oo oooo */
+ {JR,"%o", 1,10}, /* f3: 11oo oooo */
+ {JR,"%o", 1,10}, /* f4: 11oo oooo */
+ {JR,"%o", 1,10}, /* f5: 11oo oooo */
+ {JR,"%o", 1,10}, /* f6: 11oo oooo */
+ {JR,"%o", 1,10}, /* f7: 11oo oooo */
+ {JR,"%o", 1,10}, /* f8: 11oo oooo */
+ {JR,"%o", 1,10}, /* f9: 11oo oooo */
+ {JR,"%o", 1,10}, /* fa: 11oo oooo */
+ {JR,"%o", 1,10}, /* fb: 11oo oooo */
+ {JR,"%o", 1,10}, /* fc: 11oo oooo */
+ {JR,"%o", 1,10}, /* fd: 11oo oooo */
+ {JR,"%o", 1,10}, /* fe: 11oo oooo */
+ {JR,"%o", 1,10} /* ff: 11oo oooo */
+};
+
+static struct dasm_s dasmXX_7807[256] =
+{
+ {NOP,0, 1, 4}, /* 00: 0000 0000 */
+ {LDAW,"%a", 2,10}, /* 01: 0000 0001 oooo oooo */
+ {INX,"SP", 1, 7}, /* 02: 0000 0010 */
+ {DCX,"SP", 1, 7}, /* 03: 0000 0011 */
+ {LXI,"SP,%w", 3,10}, /* 04: 0000 0100 llll llll hhhh hhhh */
+ {ANIW,"%a,%b", 3,19}, /* 05: 0000 0101 oooo oooo xxxx xxxx */
+ {illegal,0, 1, 4}, /* 06: */
+ {ANI,"A,%b", 2, 7}, /* 07: 0000 0111 xxxx xxxx */
+ {MOV,"A,EAH", 1, 4}, /* 08: 0000 1000 */
+ {MOV,"A,EAL", 1, 4}, /* 09: 0000 1001 */
+ {MOV,"A,B", 1, 4}, /* 0a: 0000 1010 */
+ {MOV,"A,C", 1, 4}, /* 0b: 0000 1011 */
+ {MOV,"A,D", 1, 4}, /* 0c: 0000 1100 */
+ {MOV,"A,E", 1, 4}, /* 0d: 0000 1101 */
+ {MOV,"A,H", 1, 4}, /* 0e: 0000 1110 */
+ {MOV,"A,L", 1, 4}, /* 0f: 0000 1111 */
+
+ {BLOCK,"D+", 1,13}, /* 10: 0001 0000 */ /* 7807 */
+ {BLOCK,"D-", 1,13}, /* 11: 0001 0001 */ /* 7807 */
+ {INX,"BC", 1, 7}, /* 12: 0001 0010 */
+ {DCX,"BC", 1, 7}, /* 13: 0001 0011 */
+ {LXI,"BC,%w", 3,10}, /* 14: 0001 0100 llll llll hhhh hhhh */
+ {ORIW,"%a,%b", 3,19}, /* 15: 0001 0101 oooo oooo xxxx xxxx */
+ {XRI,"A,%b", 2, 7}, /* 16: 0001 0110 xxxx xxxx */
+ {ORI,"A,%b", 2, 7}, /* 17: 0001 0111 xxxx xxxx */
+ {MOV,"EAH,A", 1, 4}, /* 18: 0001 1000 */
+ {MOV,"EAL,A", 1, 4}, /* 19: 0001 1001 */
+ {MOV,"B,A", 1, 4}, /* 1a: 0001 1010 */
+ {MOV,"C,A", 1, 4}, /* 1b: 0001 1011 */
+ {MOV,"D,A", 1, 4}, /* 1c: 0001 1100 */
+ {MOV,"E,A", 1, 4}, /* 1d: 0001 1101 */
+ {MOV,"H,A", 1, 4}, /* 1e: 0001 1110 */
+ {MOV,"L,A", 1, 4}, /* 1f: 0001 1111 */
+
+ {INRW,"%a", 2,16}, /* 20: 0010 0000 oooo oooo */
+ {JB,0, 1, 4}, /* 21: 0010 0001 */
+ {INX,"DE", 1, 7}, /* 22: 0010 0010 */
+ {DCX,"DE", 1, 7}, /* 23: 0010 0011 */
+ {LXI,"DE,%w", 3,10}, /* 24: 0010 0100 llll llll hhhh hhhh */
+ {GTIW,"%a,%b", 3,19}, /* 25: 0010 0101 oooo oooo xxxx xxxx */
+ {ADINC,"A,%b", 2, 7}, /* 26: 0010 0110 xxxx xxxx */
+ {GTI,"A,%b", 2, 7}, /* 27: 0010 0111 xxxx xxxx */
+ {illegal,0, 1, 4}, /* 28: 0010 1000 */
+ {LDAX,"(BC)", 1, 7}, /* 29: 0010 1001 */
+ {LDAX,"(DE)", 1, 7}, /* 2a: 0010 1010 */
+ {LDAX,"(HL)", 1, 7}, /* 2b: 0010 1011 */
+ {LDAX,"(DE+)", 1, 7}, /* 2c: 0010 1100 */
+ {LDAX,"(HL+)", 1, 7}, /* 2d: 0010 1101 */
+ {LDAX,"(DE-)", 1, 7}, /* 2e: 0010 1110 */
+ {LDAX,"(HL-)", 1, 7}, /* 2f: 0010 1111 */
+
+ {DCRW,"%a", 2,16}, /* 30: 0011 0000 oooo oooo */
+ {AND,"CY,%i", 2,10}, /* 31: 0011 0001 bbbb bbbb */ /* 7807 */
+ {INX,"HL", 1, 7}, /* 32: 0011 0010 */
+ {DCX,"HL", 1, 7}, /* 33: 0011 0011 */
+ {LXI,"HL,%w", 3,10}, /* 34: 0011 0100 llll llll hhhh hhhh */
+ {LTIW,"%a,%b", 3,19}, /* 35: 0011 0101 oooo oooo xxxx xxxx */
+ {SUINB,"A,%b", 2, 7}, /* 36: 0011 0110 xxxx xxxx */
+ {LTI,"A,%b", 2, 7}, /* 37: 0011 0111 xxxx xxxx */
+ {illegal,0, 1, 4}, /* 38: */
+ {STAX,"(BC)", 1, 7}, /* 39: 0011 1001 */
+ {STAX,"(DE)", 1, 7}, /* 3a: 0011 1010 */
+ {STAX,"(HL)", 1, 7}, /* 3b: 0011 1011 */
+ {STAX,"(DE+)", 1, 7}, /* 3c: 0011 1100 */
+ {STAX,"(HL+)", 1, 7}, /* 3d: 0011 1101 */
+ {STAX,"(DE-)", 1, 7}, /* 3e: 0011 1110 */
+ {STAX,"(HL-)", 1, 7}, /* 3f: 0011 1111 */
+
+ {CALL,"%w", 3,16}, /* 40: 0100 0000 llll llll hhhh hhhh */
+ {INR,"A", 1, 4}, /* 41: 0100 0001 */
+ {INR,"B", 1, 4}, /* 42: 0100 0010 */
+ {INR,"C", 1, 4}, /* 43: 0100 0011 */
+ {LXI,"EA,%w", 3,10}, /* 44: 0100 0100 llll llll hhhh hhhh */
+ {ONIW,"%a,%b", 3,19}, /* 45: 0100 0101 oooo oooo xxxx xxxx */
+ {ADI,"A,%b", 2, 7}, /* 46: 0100 0110 xxxx xxxx */
+ {ONI,"A,%b", 2, 7}, /* 47: 0100 0111 xxxx xxxx */
+ {0,dasm48_7807, 0, 0}, /* 48: prefix */
+ {MVIX,"BC,%b", 2,10}, /* 49: 0100 1001 xxxx xxxx */
+ {MVIX,"DE,%b", 2,10}, /* 4a: 0100 1010 xxxx xxxx */
+ {MVIX,"HL,%b", 2,10}, /* 4b: 0100 1011 xxxx xxxx */
+ {0,dasm4C_7807, 0, 0}, /* 4c: prefix */
+ {0,dasm4D_7807, 0, 0}, /* 4d: prefix */
+ {JRE,"%d", 2,10}, /* 4e: 0100 111d dddd dddd */
+ {JRE,"%d", 2,10}, /* 4f: 0100 111d dddd dddd */
+ {SKN,"%i", 2,10}, /* 50: 0101 0000 bbbb bbbb */ /* 7807 */
+ {DCR,"A", 1, 4}, /* 51: 0101 0001 */
+ {DCR,"B", 1, 4}, /* 52: 0101 0010 */
+ {DCR,"C", 1, 4}, /* 53: 0101 0011 */
+ {JMP,"%w", 3,10}, /* 54: 0101 0100 llll llll hhhh hhhh */
+ {OFFIW,"%a,%b", 3,19}, /* 55: 0101 0101 oooo oooo xxxx xxxx */
+ {ACI,"A,%b", 2, 7}, /* 56: 0101 0110 xxxx xxxx */
+ {OFFI,"A,%b", 2, 7}, /* 57: 0101 0111 xxxx xxxx */
+ {SETB,"%i", 2,13}, /* 58: 0101 1000 bbbb bbbb */ /* 7807 */
+ {NOT,"%i", 2,13}, /* 59: 0101 1001 bbbb bbbb */ /* 7807 */
+ {MOV,"%i,CY", 2,13}, /* 5a: 0101 1010 bbbb bbbb */ /* 7807 */
+ {CLR,"%i", 2,13}, /* 5b: 0101 1011 bbbb bbbb */ /* 7807 */
+ {OR,"CY,%i", 2,10}, /* 5c: 0101 1100 bbbb bbbb */ /* 7807 */
+ {SK,"%i", 2,10}, /* 5d: 0101 1101 bbbb bbbb */ /* 7807 */
+ {XOR,"CY,%i", 2,10}, /* 5e: 0101 1110 bbbb bbbb */ /* 7807 */
+ {MOV,"CY,%i", 2,10}, /* 5f: 0101 1111 bbbb bbbb */ /* 7807 */
+
+ {0,dasm60, 0, 0}, /* 60: prefix */
+ {DAA,0, 1, 4}, /* 61: 0110 0001 */
+ {RETI,0, 1,13}, /* 62: 0110 0010 */
+ {STAW,"%a", 2,10}, /* 63: 0110 0011 oooo oooo */
+ {0,dasm64_7807, 0, 0}, /* 64: prefix */
+ {NEIW,"%a,%b", 3,19}, /* 65: 0110 0101 oooo oooo xxxx xxxx */
+ {SUI,"A,%b", 2, 7}, /* 66: 0110 0110 xxxx xxxx */
+ {NEI,"A,%b", 2, 7}, /* 67: 0110 0111 xxxx xxxx */
+ {MVI,"V,%b", 2, 7}, /* 68: 0110 1000 xxxx xxxx */
+ {MVI,"A,%b", 2, 7}, /* 69: 0110 1001 xxxx xxxx */
+ {MVI,"B,%b", 2, 7}, /* 6a: 0110 1010 xxxx xxxx */
+ {MVI,"C,%b", 2, 7}, /* 6b: 0110 1011 xxxx xxxx */
+ {MVI,"D,%b", 2, 7}, /* 6c: 0110 1100 xxxx xxxx */
+ {MVI,"E,%b", 2, 7}, /* 6d: 0110 1101 xxxx xxxx */
+ {MVI,"H,%b", 2, 7}, /* 6e: 0110 1110 xxxx xxxx */
+ {MVI,"L,%b", 2, 7}, /* 6f: 0110 1111 xxxx xxxx */
+
+ {0,dasm70, 0, 0}, /* 70: prefix */
+ {MVIW,"%a,%b", 3,13}, /* 71: 0111 0001 oooo oooo xxxx xxxx */
+ {SOFTI,0, 1,16}, /* 72: 0111 0010 */
+ {illegal,0, 1, 0}, /* 73: */
+ {0,dasm74, 0, 0}, /* 74: prefix */
+ {EQIW,"%a,%b", 3,19}, /* 75: 0111 0101 oooo oooo xxxx xxxx */
+ {SBI,"A,%b", 2, 7}, /* 76: 0111 0110 xxxx xxxx */
+ {EQI,"A,%b", 2, 7}, /* 77: 0111 0111 xxxx xxxx */
+ {CALF,"%f", 2,13}, /* 78: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 79: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7a: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7b: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7c: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7d: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7e: 0111 1ddd dddd dddd */
+ {CALF,"%f", 2,13}, /* 7f: 0111 1ddd dddd dddd */
+
+ {CALT,"%t", 1,16}, /* 80: 100t tttt */
+ {CALT,"%t", 1,16}, /* 81: 100t tttt */
+ {CALT,"%t", 1,16}, /* 82: 100t tttt */
+ {CALT,"%t", 1,16}, /* 83: 100t tttt */
+ {CALT,"%t", 1,16}, /* 84: 100t tttt */
+ {CALT,"%t", 1,16}, /* 85: 100t tttt */
+ {CALT,"%t", 1,16}, /* 86: 100t tttt */
+ {CALT,"%t", 1,16}, /* 87: 100t tttt */
+ {CALT,"%t", 1,16}, /* 88: 100t tttt */
+ {CALT,"%t", 1,16}, /* 89: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8a: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8b: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8c: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8d: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8e: 100t tttt */
+ {CALT,"%t", 1,16}, /* 8f: 100t tttt */
+
+ {CALT,"%t", 1,16}, /* 90: 100t tttt */
+ {CALT,"%t", 1,16}, /* 91: 100t tttt */
+ {CALT,"%t", 1,16}, /* 92: 100t tttt */
+ {CALT,"%t", 1,16}, /* 93: 100t tttt */
+ {CALT,"%t", 1,16}, /* 94: 100t tttt */
+ {CALT,"%t", 1,16}, /* 95: 100t tttt */
+ {CALT,"%t", 1,16}, /* 96: 100t tttt */
+ {CALT,"%t", 1,16}, /* 97: 100t tttt */
+ {CALT,"%t", 1,16}, /* 98: 100t tttt */
+ {CALT,"%t", 1,16}, /* 99: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9a: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9b: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9c: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9d: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9e: 100t tttt */
+ {CALT,"%t", 1,16}, /* 9f: 100t tttt */
+
+ {POP,"VA", 1,10}, /* a0: 1010 0000 */
+ {POP,"BC", 1,10}, /* a1: 1010 0001 */
+ {POP,"DE", 1,10}, /* a2: 1010 0010 */
+ {POP,"HL", 1,10}, /* a3: 1010 0011 */
+ {POP,"EA", 1,10}, /* a4: 1010 0100 */
+ {DMOV,"EA,BC", 1, 4}, /* a5: 1010 0101 */
+ {DMOV,"EA,DE", 1, 4}, /* a6: 1010 0110 */
+ {DMOV,"EA,HL", 1, 4}, /* a7: 1010 0111 */
+ {INX,"EA", 1, 7}, /* a8: 1010 1000 */
+ {DCX,"EA", 1, 7}, /* a9: 1010 1001 */
+ {EI,0, 1, 4}, /* aa: 1010 1010 */
+ {LDAX,"(DE+%b)", 2,13}, /* ab: 1010 1011 dddd dddd */
+ {LDAX,"(HL+A)", 1,13}, /* ac: 1010 1100 */
+ {LDAX,"(HL+B)", 1,13}, /* ad: 1010 1101 */
+ {LDAX,"(HL+EA)", 1,13}, /* ae: 1010 1110 */
+ {LDAX,"(HL+%b)", 2,13}, /* af: 1010 1111 dddd dddd */
+
+ {PUSH,"VA", 1,13}, /* b0: 1011 0000 */
+ {PUSH,"BC", 1,13}, /* b1: 1011 0001 */
+ {PUSH,"DE", 1,13}, /* b2: 1011 0010 */
+ {PUSH,"HL", 1,13}, /* b3: 1011 0011 */
+ {PUSH,"EA", 1,13}, /* b4: 1011 0100 */
+ {DMOV,"BC,EA", 1, 4}, /* b5: 1011 0101 */
+ {DMOV,"DE,EA", 1, 4}, /* b6: 1011 0110 */
+ {DMOV,"HL,EA", 1, 4}, /* b7: 1011 0111 */
+ {RET,0, 1,10}, /* b8: 1011 1000 */
+ {RETS,0, 1,10}, /* b9: 1011 1001 */
+ {DI,0, 1, 4}, /* ba: 1011 1010 */
+ {STAX,"(DE+%b)", 2,13}, /* bb: 1011 1011 dddd dddd */
+ {STAX,"(HL+A)", 1,13}, /* bc: 1011 1100 */
+ {STAX,"(HL+B)", 1,13}, /* bd: 1011 1101 */
+ {STAX,"(HL+EA)", 1,13}, /* be: 1011 1110 */
+ {STAX,"(HL+%b)", 2,13}, /* bf: 1011 1111 dddd dddd */
+
+ {JR,"%o", 1,10}, /* c0: 11oo oooo */
+ {JR,"%o", 1,10}, /* c1: 11oo oooo */
+ {JR,"%o", 1,10}, /* c2: 11oo oooo */
+ {JR,"%o", 1,10}, /* c3: 11oo oooo */
+ {JR,"%o", 1,10}, /* c4: 11oo oooo */
+ {JR,"%o", 1,10}, /* c5: 11oo oooo */
+ {JR,"%o", 1,10}, /* c6: 11oo oooo */
+ {JR,"%o", 1,10}, /* c7: 11oo oooo */
+ {JR,"%o", 1,10}, /* c8: 11oo oooo */
+ {JR,"%o", 1,10}, /* c9: 11oo oooo */
+ {JR,"%o", 1,10}, /* ca: 11oo oooo */
+ {JR,"%o", 1,10}, /* cb: 11oo oooo */
+ {JR,"%o", 1,10}, /* cc: 11oo oooo */
+ {JR,"%o", 1,10}, /* cd: 11oo oooo */
+ {JR,"%o", 1,10}, /* ce: 11oo oooo */
+ {JR,"%o", 1,10}, /* cf: 11oo oooo */
+
+ {JR,"%o", 1,10}, /* d0: 11oo oooo */
+ {JR,"%o", 1,10}, /* d1: 11oo oooo */
+ {JR,"%o", 1,10}, /* d2: 11oo oooo */
+ {JR,"%o", 1,10}, /* d3: 11oo oooo */
+ {JR,"%o", 1,10}, /* d4: 11oo oooo */
+ {JR,"%o", 1,10}, /* d5: 11oo oooo */
+ {JR,"%o", 1,10}, /* d6: 11oo oooo */
+ {JR,"%o", 1,10}, /* d7: 11oo oooo */
+ {JR,"%o", 1,10}, /* d8: 11oo oooo */
+ {JR,"%o", 1,10}, /* d9: 11oo oooo */
+ {JR,"%o", 1,10}, /* da: 11oo oooo */
+ {JR,"%o", 1,10}, /* db: 11oo oooo */
+ {JR,"%o", 1,10}, /* dc: 11oo oooo */
+ {JR,"%o", 1,10}, /* dd: 11oo oooo */
+ {JR,"%o", 1,10}, /* de: 11oo oooo */
+ {JR,"%o", 1,10}, /* df: 11oo oooo */
+
+ {JR,"%o", 1,10}, /* e0: 11oo oooo */
+ {JR,"%o", 1,10}, /* e1: 11oo oooo */
+ {JR,"%o", 1,10}, /* e2: 11oo oooo */
+ {JR,"%o", 1,10}, /* e3: 11oo oooo */
+ {JR,"%o", 1,10}, /* e4: 11oo oooo */
+ {JR,"%o", 1,10}, /* e5: 11oo oooo */
+ {JR,"%o", 1,10}, /* e6: 11oo oooo */
+ {JR,"%o", 1,10}, /* e7: 11oo oooo */
+ {JR,"%o", 1,10}, /* e8: 11oo oooo */
+ {JR,"%o", 1,10}, /* e9: 11oo oooo */
+ {JR,"%o", 1,10}, /* ea: 11oo oooo */
+ {JR,"%o", 1,10}, /* eb: 11oo oooo */
+ {JR,"%o", 1,10}, /* ec: 11oo oooo */
+ {JR,"%o", 1,10}, /* ed: 11oo oooo */
+ {JR,"%o", 1,10}, /* ee: 11oo oooo */
+ {JR,"%o", 1,10}, /* ef: 11oo oooo */
+
+ {JR,"%o", 1,10}, /* f0: 11oo oooo */
+ {JR,"%o", 1,10}, /* f1: 11oo oooo */
+ {JR,"%o", 1,10}, /* f2: 11oo oooo */
+ {JR,"%o", 1,10}, /* f3: 11oo oooo */
+ {JR,"%o", 1,10}, /* f4: 11oo oooo */
+ {JR,"%o", 1,10}, /* f5: 11oo oooo */
+ {JR,"%o", 1,10}, /* f6: 11oo oooo */
+ {JR,"%o", 1,10}, /* f7: 11oo oooo */
+ {JR,"%o", 1,10}, /* f8: 11oo oooo */
+ {JR,"%o", 1,10}, /* f9: 11oo oooo */
+ {JR,"%o", 1,10}, /* fa: 11oo oooo */
+ {JR,"%o", 1,10}, /* fb: 11oo oooo */
+ {JR,"%o", 1,10}, /* fc: 11oo oooo */
+ {JR,"%o", 1,10}, /* fd: 11oo oooo */
+ {JR,"%o", 1,10}, /* fe: 11oo oooo */
+ {JR,"%o", 1,10} /* ff: 11oo oooo */
+};
+
+
+/* register names for bit manipulation instructions */
+static const char *regname[32] =
+{
+ "illegal", "illegal", "illegal", "illegal",
+ "illegal", "illegal", "illegal", "illegal",
+ "illegal", "illegal", "illegal", "illegal",
+ "illegal", "illegal", "illegal", "illegal",
+ "PA", "PB", "PC", "PD",
+ "illegal", "PF", "MKH", "MKL",
+ "illegal", "SMH", "illegal", "EOM",
+ "illegal", "TMM", "PT", "illegal"
+};
+
+static unsigned upd7810_get_reg(int reg) { cpuinfo info; upd7810_get_info(CPUINFO_INT_REGISTER + (reg), &info); return info.i; }
+
+static unsigned Dasm( char *buffer, unsigned pc, struct dasm_s *dasmXX, const UINT8 *oprom, const UINT8 *opram )
+{
+ unsigned opc = pc;
+ UINT8 op = oprom[pc++ - opc], op2, t, l;
+ int offset;
+ UINT16 ea;
+ const char *a;
+ UINT32 flags = 0;
+
+ t = dasmXX[op].token;
+ a = dasmXX[op].args;
+ l = dasmXX[op].oplen;
+
+ /* 0 token means prefix opcode (use table from args) */
+ if (0 == t)
+ {
+ struct dasm_s *p_dasm = (struct dasm_s *)a;
+
+ op2 = oprom[pc++ - opc];
+ t = p_dasm[op2].token;
+ a = p_dasm[op2].args;
+ l = p_dasm[op2].oplen;
+ }
+
+ buffer += sprintf(buffer, "%-8.8s", token[t]);
+
+ if (t == CALB || t == CALF || t == CALL || t == CALT)
+ flags = DASMFLAG_STEP_OVER;
+ else if (t == RET || t == RETI)
+ flags = DASMFLAG_STEP_OUT;
+
+ while (a && *a)
+ {
+ if ('%' == *a)
+ {
+ a++;
+ switch (*a)
+ {
+ case 'a': /* address V * 256 + offset */
+ op2 = opram[pc++ - opc];
+ ea = upd7810_get_reg(UPD7810_V) * 256 + op2;
+ buffer += sprintf(buffer, "$%04X", ea);
+ break;
+ case 'b': /* immediate byte */
+ buffer += sprintf(buffer, "$%02X", opram[pc++ - opc]);
+ break;
+ case 'w': /* immediate word */
+ ea = opram[pc++ - opc];
+ ea += opram[pc++ - opc] << 8;
+ buffer += sprintf(buffer, "$%04X", ea);
+ break;
+ case 'd': /* JRE address */
+ op2 = oprom[pc++ - opc];
+ offset = (op & 1) ? -(256 - op2): + op2;
+ buffer += sprintf(buffer, "$%04X", pc + offset);
+ break;
+ case 't': /* CALT address */
+ ea = 0x80 + 2 * (op & 0x1f);
+ buffer += sprintf(buffer, "($%04X)", ea);
+ break;
+ case 'f': /* CALF address */
+ op2 = oprom[pc++ - opc];
+ ea = 0x800 + 0x100 * (op & 0x07) + op2;
+ buffer += sprintf(buffer, "$%04X", ea);
+ break;
+ case 'o': /* JR offset */
+ op2 = oprom[pc++ - opc];
+ offset = (INT8)(op << 2) >> 2;
+ buffer += sprintf(buffer, "$%04X", pc + offset - 1);
+ break;
+ case 'i': /* bit manipulation */
+ op2 = oprom[pc++ - opc];
+ buffer += sprintf(buffer, "%s,%d", regname[op2 & 0x1f], op2 >> 5);
+ break;
+ default:
+ *buffer++ = *a;
+ }
+ }
+ else
+ *buffer++ = *a;
+ a++;
+ }
+ *buffer = '\0';
+
+ return l | flags | DASMFLAG_SUPPORTED;
+}
+
+unsigned upd7810_dasm( char *buffer, unsigned pc, const UINT8 *oprom, const UINT8 *opram )
+{
+ return Dasm( buffer, pc, dasmXX_7810, oprom, opram );
+}
+
+unsigned upd7807_dasm( char *buffer, unsigned pc, const UINT8 *oprom, const UINT8 *opram )
+{
+ return Dasm( buffer, pc, dasmXX_7807, oprom, opram );
+}
diff --git a/src/emu/cpu/upd7810/7810ops.c b/src/emu/cpu/upd7810/7810ops.c
new file mode 100644
index 00000000000..c243cd612b1
--- /dev/null
+++ b/src/emu/cpu/upd7810/7810ops.c
@@ -0,0 +1,9341 @@
+/*****************************************************************************
+ *
+ * Portable uPD7810/11, 7810H/11H, 78C10/C11/C14 emulator V0.2
+ * Copyright (c) 2001 Juergen Buchmueller, all rights reserved.
+ *
+ * 7810ops.c - opcode functions
+ *
+ *****************************************************************************/
+
+static void illegal(void)
+{
+ logerror("uPD7810 #%d: illegal opcode %02x at PC:%04x\n", cpu_getactivecpu(), OP, PC);
+}
+
+static void illegal2(void)
+{
+ logerror("uPD7810 #%d: illegal opcode %02x %02x at PC:%04x\n", cpu_getactivecpu(), OP, OP2, PC);
+}
+
+/* prefix 48 */
+
+/* 48 01: 0100 1000 0000 0001 */
+static void SLRC_A(void)
+{
+ PSW = (PSW & ~CY) | (A & CY);
+ A >>= 1;
+ SKIP_CY;
+}
+
+/* 48 02: 0100 1000 0000 0010 */
+static void SLRC_B(void)
+{
+ PSW = (PSW & ~CY) | (B & CY);
+ B >>= 1;
+ SKIP_CY;
+}
+
+/* 48 03: 0100 1000 0000 0011 */
+static void SLRC_C(void)
+{
+ PSW = (PSW & ~CY) | (C & CY);
+ C >>= 1;
+ SKIP_CY;
+}
+
+
+/* 48 05: 0100 1000 0000 0101 */
+static void SLLC_A(void)
+{
+ PSW = (PSW & ~CY) | ((A >> 7) & CY);
+ A <<= 1;
+ SKIP_CY;
+}
+
+/* 48 06: 0100 1000 0000 0110 */
+static void SLLC_B(void)
+{
+ PSW = (PSW & ~CY) | ((B >> 7) & CY);
+ B <<= 1;
+ SKIP_CY;
+}
+
+/* 48 07: 0100 1000 0000 0111 */
+static void SLLC_C(void)
+{
+ PSW = (PSW & ~CY) | ((C >> 7) & CY);
+ C <<= 1;
+ SKIP_CY;
+}
+
+/* 48 08: 0100 1000 0000 1000 */
+static void SK_NV(void)
+{
+ /* 48 skip never */
+}
+
+/* 48 0a: 0100 1000 0000 1010 */
+static void SK_CY(void)
+{
+ if (CY == (PSW & CY))
+ PSW |= SK;
+}
+
+/* 48 0b: 0100 1000 0000 1011 */
+static void SK_HC(void)
+{
+ if (HC == (PSW & HC))
+ PSW |= SK;
+}
+
+/* 48 0c: 0100 1000 0000 1100 */
+static void SK_Z(void)
+{
+ if (Z == (PSW & Z))
+ PSW |= SK;
+}
+
+/* 48 18: 0100 1000 0001 1000 */
+static void SKN_NV(void)
+{
+ /* skip not never -> skip always ;-) */
+ PSW |= SK;
+}
+
+/* 48 1a: 0100 1000 0001 1010 */
+static void SKN_CY(void)
+{
+ if (0 == (PSW & CY))
+ PSW |= SK;
+}
+
+/* 48 1b: 0100 1000 0001 1011 */
+static void SKN_HC(void)
+{
+ if (0 == (PSW & HC))
+ PSW |= SK;
+}
+
+/* 48 1c: 0100 1000 0001 1100 */
+static void SKN_Z(void)
+{
+ if (0 == (PSW & Z))
+ PSW |= SK;
+}
+
+/* 48 21: 0100 1000 0010 0001 */
+static void SLR_A(void)
+{
+ PSW = (PSW & ~CY) | (A & CY);
+ A >>= 1;
+}
+
+/* 48 22: 0100 1000 0010 0010 */
+static void SLR_B(void)
+{
+ PSW = (PSW & ~CY) | (B & CY);
+ B >>= 1;
+}
+
+/* 48 23: 0100 1000 0010 0011 */
+static void SLR_C(void)
+{
+ PSW = (PSW & ~CY) | (C & CY);
+ C >>= 1;
+}
+
+/* 48 25: 0100 1000 0010 0101 */
+static void SLL_A(void)
+{
+ PSW = (PSW & ~CY) | ((A >> 7) & CY);
+ A <<= 1;
+}
+
+/* 48 26: 0100 1000 0010 0110 */
+static void SLL_B(void)
+{
+ PSW = (PSW & ~CY) | ((B >> 7) & CY);
+ B <<= 1;
+}
+
+/* 48 27: 0100 1000 0010 0111 */
+static void SLL_C(void)
+{
+ PSW = (PSW & ~CY) | ((C >> 7) & CY);
+ C <<= 1;
+}
+
+/* 48 28: 0100 1000 0010 1000 */
+static void JEA(void)
+{
+ PC = EA;
+ change_pc( PCD );
+}
+
+/* 48 29: 0100 1000 0010 1001 */
+static void CALB(void)
+{
+ SP--;
+ WM( SPD, PCH );
+ SP--;
+ WM( SPD, PCL );
+
+ PC = BC;
+ change_pc( PCD );
+}
+
+/* 48 2a: 0100 1000 0010 1010 */
+static void CLC(void)
+{
+ PSW &= ~CY;
+}
+
+/* 48 2b: 0100 1000 0010 1011 */
+static void STC(void)
+{
+ PSW |= CY;
+}
+
+/* 48 2d: 0100 1000 0010 1101 */
+static void MUL_A(void)
+{
+ EA = A * A;
+}
+
+/* 48 2e: 0100 1000 0010 1110 */
+static void MUL_B(void)
+{
+ EA = A * B;
+}
+
+/* 48 2f: 0100 1000 0010 1111 */
+static void MUL_C(void)
+{
+ EA = A * C;
+}
+
+/* 48 31: 0100 1000 0011 0001 */
+static void RLR_A(void)
+{
+ UINT8 carry=(PSW&CY)<<7;
+ PSW = (PSW & ~CY) | (A & CY);
+ A = (A >> 1) | carry;
+}
+
+/* 48 32: 0100 1000 0011 0010 */
+static void RLR_B(void)
+{
+ UINT8 carry=(PSW&CY)<<7;
+ PSW = (PSW & ~CY) | (B & CY);
+ B = (B >> 1) | carry;
+}
+
+/* 48 33: 0100 1000 0011 0011 */
+static void RLR_C(void)
+{
+ UINT8 carry=(PSW&CY)<<7;
+ PSW = (PSW & ~CY) | (C & CY);
+ C = (C >> 1) | carry;
+}
+
+/* 48 35: 0100 1000 0011 0101 */
+static void RLL_A(void)
+{
+ UINT8 carry=PSW&CY;
+ PSW = (PSW & ~CY) | ((A >> 7) & CY);
+ A = (A << 1) | carry;
+}
+
+/* 48 36: 0100 1000 0011 0110 */
+static void RLL_B(void)
+{
+ UINT8 carry=PSW&CY;
+ PSW = (PSW & ~CY) | ((B >> 7) & CY);
+ B = (B << 1) | carry;
+}
+
+/* 48 37: 0100 1000 0011 0111 */
+static void RLL_C(void)
+{
+ UINT8 carry=PSW&CY;
+ PSW = (PSW & ~CY) | ((C >> 7) & CY);
+ C = (C << 1) | carry;
+}
+
+/* 48 38: 0100 1000 0011 1000 */
+static void RLD(void)
+{
+ UINT8 m = RM( HL ), tmp;
+ tmp = (m << 4) | (A & 0x0f);
+ A = (A & 0xf0) | (m >> 4);
+ WM( HL, tmp );
+}
+
+/* 48 39: 0100 1000 0011 1001 */
+static void RRD(void)
+{
+ UINT8 m = RM( HL ), tmp;
+ tmp = (A << 4) | (m >> 4);
+ A = (A & 0xf0) | (m & 0x0f);
+ WM( HL, tmp );
+}
+
+/* 48 3a: 0100 1000 0011 1010 */
+static void NEGA(void)
+{
+ A = ~A + 1;
+}
+
+/* 48 3b: 0100 1000 0011 1011 */
+static void HALT(void)
+{
+ int cycles = (upd7810_icount / 4) * 4;
+ upd7810_icount -= cycles;
+ upd7810_timers(cycles);
+ PC -= 1; /* continue executing HALT */
+}
+
+/* 48 3d: 0100 1000 0011 1101 */
+static void DIV_A(void)
+{
+ if (A)
+ {
+ UINT8 remainder;
+ remainder = EA % A;
+ EA /= A;
+ A = remainder;
+ }
+ else
+ EA = 0xffff; /* guess */
+}
+
+/* 48 3e: 0100 1000 0011 1110 */
+static void DIV_B(void)
+{
+ if (B)
+ {
+ UINT8 remainder;
+ remainder = EA % B;
+ EA /= B;
+ B = remainder;
+ }
+ else
+ EA = 0xffff; /* guess */
+}
+
+/* 48 3f: 0100 1000 0011 1111 */
+static void DIV_C(void)
+{
+ if (C)
+ {
+ UINT8 remainder;
+ remainder = EA % C;
+ EA /= C;
+ C = remainder;
+ }
+ else
+ EA = 0xffff; /* guess */
+}
+
+/* 48 40: 0100 1000 0100 0000 */
+static void SKIT_NMI(void)
+{
+ if (IRR & INTNMI)
+ PSW |= SK;
+ IRR &= ~INTNMI;
+}
+
+/* 48 41: 0100 1000 0100 0001 */
+static void SKIT_FT0(void)
+{
+ if (IRR & INTFT0)
+ PSW |= SK;
+ IRR &= ~INTFT0;
+}
+
+/* 48 42: 0100 1000 0100 0010 */
+static void SKIT_FT1(void)
+{
+ if (IRR & INTFT1)
+ PSW |= SK;
+ IRR &= ~INTFT1;
+}
+
+/* 48 43: 0100 1000 0100 0011 */
+static void SKIT_F1(void)
+{
+ if (IRR & INTF1)
+ PSW |= SK;
+ IRR &= ~INTF1;
+}
+
+/* 48 44: 0100 1000 0100 0100 */
+static void SKIT_F2(void)
+{
+ if (IRR & INTF2)
+ PSW |= SK;
+ IRR &= ~INTF2;
+}
+
+/* 48 45: 0100 1000 0100 0101 */
+static void SKIT_FE0(void)
+{
+ if (IRR & INTFE0)
+ PSW |= SK;
+ IRR &= ~INTFE0;
+}
+
+/* 48 46: 0100 1000 0100 0110 */
+static void SKIT_FE1(void)
+{
+ if (IRR & INTFE1)
+ PSW |= SK;
+ IRR &= ~INTFE1;
+}
+
+/* 48 47: 0100 1000 0100 0111 */
+static void SKIT_FEIN(void)
+{
+ if (IRR & INTFEIN)
+ PSW |= SK;
+ IRR &= ~INTFEIN;
+}
+
+/* 48 48: 0100 1000 0100 1000 */
+static void SKIT_FAD(void)
+{
+ if (IRR & INTFAD)
+ PSW |= SK;
+ IRR &= ~INTFAD;
+}
+
+/* 48 49: 0100 1000 0100 1001 */
+static void SKIT_FSR(void)
+{
+ if (IRR & INTFSR)
+ PSW |= SK;
+ IRR &= ~INTFSR;
+}
+
+/* 48 4a: 0100 1000 0100 1010 */
+static void SKIT_FST(void)
+{
+ if (IRR & INTFST)
+ PSW |= SK;
+ IRR &= ~INTFST;
+}
+
+/* 48 4b: 0100 1000 0100 1011 */
+static void SKIT_ER(void)
+{
+ if (IRR & INTER)
+ PSW |= SK;
+ IRR &= ~INTER;
+}
+
+/* 48 4c: 0100 1000 0100 1100 */
+static void SKIT_OV(void)
+{
+ if (IRR & INTOV)
+ PSW |= SK;
+ IRR &= ~INTOV;
+}
+
+/* 48 50: 0100 1000 0101 0000 */
+static void SKIT_AN4(void)
+{
+ if (ITF & INTAN4)
+ PSW |= SK;
+ ITF &= ~INTAN4;
+}
+
+/* 48 51: 0100 1000 0101 0001 */
+static void SKIT_AN5(void)
+{
+ if (ITF & INTAN5)
+ PSW |= SK;
+ ITF &= ~INTAN5;
+}
+
+/* 48 52: 0100 1000 0101 0010 */
+static void SKIT_AN6(void)
+{
+ if (ITF & INTAN6)
+ PSW |= SK;
+ ITF &= ~INTAN6;
+}
+
+/* 48 53: 0100 1000 0101 0011 */
+static void SKIT_AN7(void)
+{
+ if (ITF & INTAN7)
+ PSW |= SK;
+ ITF &= ~INTAN7;
+}
+
+/* 48 54: 0100 1000 0101 0100 */
+static void SKIT_SB(void)
+{
+ if (ITF & INTSB)
+ PSW |= SK;
+ ITF &= ~INTSB;
+}
+
+/* 48 60: 0100 1000 0110 0000 */
+static void SKNIT_NMI(void)
+{
+ if (0 == (IRR & INTNMI))
+ PSW |= SK;
+ IRR &= ~INTNMI;
+}
+
+/* 48 61: 0100 1000 0110 0001 */
+static void SKNIT_FT0(void)
+{
+ if (0 == (IRR & INTFT0))
+ PSW |= SK;
+ IRR &= ~INTFT0;
+}
+
+/* 48 62: 0100 1000 0110 0010 */
+static void SKNIT_FT1(void)
+{
+ if (0 == (IRR & INTFT1))
+ PSW |= SK;
+ IRR &= ~INTFT1;
+}
+
+/* 48 63: 0100 1000 0110 0011 */
+static void SKNIT_F1(void)
+{
+ if (0 == (IRR & INTF1))
+ PSW |= SK;
+ IRR &= ~INTF1;
+}
+
+/* 48 64: 0100 1000 0110 0100 */
+static void SKNIT_F2(void)
+{
+ if (0 == (IRR & INTF2))
+ PSW |= SK;
+ IRR &= ~INTF2;
+}
+
+/* 48 65: 0100 1000 0110 0101 */
+static void SKNIT_FE0(void)
+{
+ if (0 == (IRR & INTFE0))
+ PSW |= SK;
+ IRR &= ~INTFE0;
+}
+
+/* 48 66: 0100 1000 0110 0110 */
+static void SKNIT_FE1(void)
+{
+ if (0 == (IRR & INTFE1))
+ PSW |= SK;
+ IRR &= ~INTFE1;
+}
+
+/* 48 67: 0100 1000 0110 0111 */
+static void SKNIT_FEIN(void)
+{
+ if (0 == (IRR & INTFEIN))
+ PSW |= SK;
+ IRR &= ~INTFEIN;
+}
+
+/* 48 68: 0100 1000 0110 1000 */
+static void SKNIT_FAD(void)
+{
+ if (0 == (IRR & INTFAD))
+ PSW |= SK;
+ IRR &= ~INTFAD;
+}
+
+/* 48 69: 0100 1000 0110 1001 */
+static void SKNIT_FSR(void)
+{
+ if (0 == (IRR & INTFSR))
+ PSW |= SK;
+ IRR &= ~INTFSR;
+}
+
+/* 48 6a: 0100 1000 0110 1010 */
+static void SKNIT_FST(void)
+{
+ if (0 == (IRR & INTFST))
+ PSW |= SK;
+ IRR &= ~INTFST;
+}
+
+/* 48 6b: 0100 1000 0110 1011 */
+static void SKNIT_ER(void)
+{
+ if (0 == (IRR & INTER))
+ PSW |= SK;
+ IRR &= ~INTER;
+}
+
+/* 48 6c: 0100 1000 0110 1100 */
+static void SKNIT_OV(void)
+{
+ if (0 == (IRR & INTOV))
+ PSW |= SK;
+ IRR &= ~INTOV;
+}
+
+/* 48 70: 0100 1000 0111 0000 */
+static void SKNIT_AN4(void)
+{
+ if (0 == (ITF & INTAN4))
+ PSW |= SK;
+ ITF &= ~INTAN4;
+}
+
+/* 48 71: 0100 1000 0111 0001 */
+static void SKNIT_AN5(void)
+{
+ if (0 == (ITF & INTAN5))
+ PSW |= SK;
+ ITF &= ~INTAN5;
+}
+
+/* 48 72: 0100 1000 0111 0010 */
+static void SKNIT_AN6(void)
+{
+ if (0 == (ITF & INTAN6))
+ PSW |= SK;
+ ITF &= ~INTAN6;
+}
+
+/* 48 73: 0100 1000 0111 0011 */
+static void SKNIT_AN7(void)
+{
+ if (0 == (ITF & INTAN7))
+ PSW |= SK;
+ ITF &= ~INTAN7;
+}
+
+/* 48 74: 0100 1000 0111 0100 */
+static void SKNIT_SB(void)
+{
+ if (0 == (ITF & INTSB))
+ PSW |= SK;
+ ITF &= ~INTSB;
+}
+
+/* 48 82: 0100 1000 1000 0010 */
+static void LDEAX_D(void)
+{
+ EAL = RM( DE );
+ EAH = RM( DE + 1 );
+}
+
+/* 48 83: 0100 1000 1000 0011 */
+static void LDEAX_H(void)
+{
+ EAL = RM( HL );
+ EAH = RM( HL + 1 );
+}
+
+/* 48 84: 0100 1000 1000 0100 */
+static void LDEAX_Dp(void)
+{
+ EAL = RM( DE );
+ EAH = RM( DE + 1 );
+ DE += 2;
+}
+
+/* 48 85: 0100 1000 1000 0101 */
+static void LDEAX_Hp(void)
+{
+ EAL = RM( HL );
+ EAH = RM( HL + 1 );
+ HL += 2;
+}
+
+/* 48 8b: 0100 1000 1000 1011 xxxx xxxx */
+static void LDEAX_D_xx(void)
+{
+ UINT16 ea;
+ RDOPARG( ea );
+ ea += DE;
+ EAL = RM( ea );
+ EAH = RM( ea + 1 );
+}
+
+/* 48 8c: 0100 1000 1000 1100 */
+static void LDEAX_H_A(void)
+{
+ UINT16 ea = HL + A;
+ EAL = RM( ea );
+ EAH = RM( ea + 1 );
+}
+
+/* 48 8d: 0100 1000 1000 1101 */
+static void LDEAX_H_B(void)
+{
+ UINT16 ea = HL + B;
+ EAL = RM( ea );
+ EAH = RM( ea + 1 );
+}
+
+/* 48 8e: 0100 1000 1000 1110 */
+static void LDEAX_H_EA(void)
+{
+ UINT16 ea = HL + EA;
+ EAL = RM( ea );
+ EAH = RM( ea + 1 );
+}
+
+/* 48 8f: 0100 1000 1000 1111 xxxx xxxx */
+static void LDEAX_H_xx(void)
+{
+ UINT16 ea;
+ RDOPARG( ea );
+ ea += HL;
+ EAL = RM( ea );
+ EAH = RM( ea + 1 );
+}
+
+/* 48 92: 0100 1000 1000 0010 */
+static void STEAX_D(void)
+{
+ WM( DE, EAL );
+ WM( DE + 1, EAH );
+}
+
+/* 48 93: 0100 1000 1000 0011 */
+static void STEAX_H(void)
+{
+ WM( HL, EAL );
+ WM( HL + 1, EAH );
+}
+
+/* 48 94: 0100 1000 1000 0100 */
+static void STEAX_Dp(void)
+{
+ WM( DE, EAL );
+ WM( DE + 1, EAH );
+ DE += 2;
+}
+
+/* 48 95: 0100 1000 1000 0101 */
+static void STEAX_Hp(void)
+{
+ WM( HL, EAL );
+ WM( HL + 1, EAH );
+ HL += 2;
+}
+
+/* 48 9b: 0100 1000 1000 1011 xxxx xxxx */
+static void STEAX_D_xx(void)
+{
+ UINT16 ea;
+ RDOPARG( ea );
+ ea += DE;
+ WM( ea, EAL );
+ WM( ea + 1, EAH );
+}
+
+/* 48 9c: 0100 1000 1000 1100 */
+static void STEAX_H_A(void)
+{
+ UINT16 ea = HL + A;
+ WM( ea, EAL );
+ WM( ea + 1, EAH );
+}
+
+/* 48 9d: 0100 1000 1000 1101 */
+static void STEAX_H_B(void)
+{
+ UINT16 ea = HL + B;
+ WM( ea, EAL );
+ WM( ea + 1, EAH );
+}
+
+/* 48 9e: 0100 1000 1000 1110 */
+static void STEAX_H_EA(void)
+{
+ UINT16 ea = HL + EA;
+ WM( ea, EAL );
+ WM( ea + 1, EAH );
+}
+
+/* 48 9f: 0100 1000 1000 1111 xxxx xxxx */
+static void STEAX_H_xx(void)
+{
+ UINT16 ea;
+ RDOPARG( ea );
+ ea += HL;
+ WM( ea, EAL );
+ WM( ea + 1, EAH );
+}
+
+/* 48 a0: 0100 1000 1010 0000 */
+static void DSLR_EA(void)
+{
+ PSW = (PSW & ~CY) | (EA & CY);
+ EA >>= 1;
+}
+
+/* 48 a4: 0100 1000 1010 0100 */
+static void DSLL_EA(void)
+{
+ PSW = (PSW & ~CY) | ((EA >> 15) & CY);
+ EA <<= 1;
+}
+
+/* 48 a8: 0100 1000 1010 1000 */
+static void TABLE(void)
+{
+ UINT16 ea = PC + A + 1;
+ C = RM( ea );
+ B = RM( ea + 1 );
+}
+
+/* 48 b0: 0100 1000 1011 0000 */
+static void DRLR_EA(void)
+{
+ UINT8 carry=PSW&CY;
+ PSW = (PSW & ~CY) | (EA & CY);
+ EA = (EA >> 1) | (carry << 15);
+}
+
+/* 48 b4: 0100 1000 1011 0100 */
+static void DRLL_EA(void)
+{
+ UINT8 carry=PSW&CY;
+ PSW = (PSW & ~CY) | ((EA >> 15) & CY);
+ EA = (EA << 1) | carry;
+}
+
+/* 48 bb: 0100 1000 1011 1011 */
+static void STOP(void)
+{
+ int cycles = (upd7810_icount / 4) * 4;
+ upd7810_icount -= cycles;
+ upd7810_timers(cycles);
+ PC -= 1;
+}
+
+/* 48 c0: 0100 1000 1100 0000 */
+static void DMOV_EA_ECNT(void)
+{
+ EA = ECNT;
+}
+
+/* 48 c1: 0100 1000 1100 0001 */
+static void DMOV_EA_ECPT(void)
+{
+ EA = ECPT;
+}
+
+/* 48 d2: 0100 1000 1101 0010 */
+static void DMOV_ETM0_EA(void)
+{
+ ETM0 = EA;
+}
+
+/* 48 d3: 0100 1000 1101 0011 */
+static void DMOV_ETM1_EA(void)
+{
+ ETM1 = EA;
+}
+
+/* prefix 4C */
+/* 4c c0: 0100 1100 1100 0000 */
+static void MOV_A_PA(void)
+{
+ A = RP( UPD7810_PORTA );
+}
+
+/* 4c c1: 0100 1100 1100 0001 */
+static void MOV_A_PB(void)
+{
+ A = RP( UPD7810_PORTB );
+}
+
+/* 4c c2: 0100 1100 1100 0010 */
+static void MOV_A_PC(void)
+{
+ A = RP( UPD7810_PORTC );
+}
+
+/* 4c c3: 0100 1100 1100 0011 */
+static void MOV_A_PD(void)
+{
+ A = RP( UPD7810_PORTD );
+}
+
+/* 4c c5: 0100 1100 1100 0101 */
+static void MOV_A_PF(void)
+{
+ A = RP( UPD7810_PORTF );
+}
+
+/* 4c c6: 0100 1100 1100 0110 */
+static void MOV_A_MKH(void)
+{
+ A = MKH;
+}
+
+/* 4c c7: 0100 1100 1100 0111 */
+static void MOV_A_MKL(void)
+{
+ A = MKL;
+}
+
+/* 4c c8: 0100 1100 1100 1000 */
+static void MOV_A_ANM(void)
+{
+ A = ANM;
+}
+
+/* 4c c9: 0100 1100 1100 1001 */
+static void MOV_A_SMH(void)
+{
+ A = SMH;
+}
+
+/* 4c cb: 0100 1100 1100 1011 */
+static void MOV_A_EOM(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ A = eom;
+}
+
+/* 4c cd: 0100 1100 1100 1101 */
+static void MOV_A_TMM(void)
+{
+ A = TMM;
+}
+
+/* 4c ce: 0100 1100 1110 0000 (7807 only) */
+static void MOV_A_PT(void)
+{
+ A = RP( UPD7807_PORTT );
+}
+
+/* 4c d9: 0100 1100 1101 1001 */
+static void MOV_A_RXB(void)
+{
+ A = RXB;
+}
+
+/* 4c e0: 0100 1100 1110 0000 */
+static void MOV_A_CR0(void)
+{
+ A = CR0;
+}
+
+/* 4c e1: 0100 1100 1110 0001 */
+static void MOV_A_CR1(void)
+{
+ A = CR1;
+}
+
+/* 4c e2: 0100 1100 1110 0010 */
+static void MOV_A_CR2(void)
+{
+ A = CR2;
+}
+
+/* 4c e3: 0100 1100 1110 0011 */
+static void MOV_A_CR3(void)
+{
+ A = CR3;
+}
+
+/* prefix 4D */
+/* 4d c0: 0100 1101 1100 0000 */
+static void MOV_PA_A(void)
+{
+ WP( UPD7810_PORTA, A );
+}
+
+/* 4d c1: 0100 1101 1100 0001 */
+static void MOV_PB_A(void)
+{
+ WP( UPD7810_PORTB, A );
+}
+
+/* 4d c2: 0100 1101 1100 0010 */
+static void MOV_PC_A(void)
+{
+ WP( UPD7810_PORTC, A );
+}
+
+/* 4d c3: 0100 1101 1100 0011 */
+static void MOV_PD_A(void)
+{
+ WP( UPD7810_PORTD, A );
+}
+
+/* 4d c5: 0100 1101 1100 0101 */
+static void MOV_PF_A(void)
+{
+ WP( UPD7810_PORTF, A );
+}
+
+/* 4d c6: 0100 1101 1100 0110 */
+static void MOV_MKH_A(void)
+{
+ MKH = A;
+}
+
+/* 4d c7: 0100 1101 1100 0111 */
+static void MOV_MKL_A(void)
+{
+ MKL = A;
+}
+
+/* 4d c8: 0100 1101 1100 1000 */
+static void MOV_ANM_A(void)
+{
+ ANM = A;
+}
+
+/* 4d c9: 0100 1101 1100 1001 */
+static void MOV_SMH_A(void)
+{
+ SMH = A;
+}
+
+/* 4d ca: 0100 1101 1100 1010 */
+static void MOV_SML_A(void)
+{
+ SML = A;
+}
+
+/* 4d cb: 0100 1101 1100 1011 */
+static void MOV_EOM_A(void)
+{
+ EOM = A;
+ upd7810_write_EOM();
+}
+
+/* 4d cc: 0100 1101 1100 1100 */
+static void MOV_ETMM_A(void)
+{
+ ETMM = A;
+}
+
+/* 4d cd: 0100 1101 1100 1101 */
+static void MOV_TMM_A(void)
+{
+ TMM = A;
+}
+
+/* 4d d0: 0100 1101 1101 0000 */
+static void MOV_MM_A(void)
+{
+ MM = A;
+}
+
+/* 4d d1: 0100 1101 1101 0001 */
+static void MOV_MCC_A(void)
+{
+ MCC = A;
+}
+
+/* 4d d2: 0100 1101 1101 0010 */
+static void MOV_MA_A(void)
+{
+ MA = A;
+}
+
+/* 4d d3: 0100 1101 1101 0011 */
+static void MOV_MB_A(void)
+{
+ MB = A;
+}
+
+/* 4d d4: 0100 1101 1101 0100 */
+static void MOV_MC_A(void)
+{
+ MC = A;
+}
+
+/* 4d d7: 0100 1101 1101 0111 */
+static void MOV_MF_A(void)
+{
+ MF = A;
+}
+
+/* 4d d8: 0100 1101 1101 1000 */
+static void MOV_TXB_A(void)
+{
+ TXB = A;
+ upd7810_write_TXB();
+}
+
+/* 4d da: 0100 1101 1101 1010 */
+static void MOV_TM0_A(void)
+{
+ TM0 = A;
+}
+
+/* 4d db: 0100 1101 1101 1011 */
+static void MOV_TM1_A(void)
+{
+ TM1 = A;
+}
+
+/* 4d e8: 0100 1101 1110 1000 */
+static void MOV_ZCM_A(void)
+{
+ ZCM = A;
+}
+
+/* prefix 60 */
+/* 60 08: 0110 0000 0000 1000 */
+static void ANA_V_A(void)
+{
+ V &= A;
+ SET_Z(V);
+}
+
+/* 60 09: 0110 0000 0000 1001 */
+static void ANA_A_A(void)
+{
+ A &= A;
+ SET_Z(A);
+}
+
+/* 60 0a: 0110 0000 0000 1010 */
+static void ANA_B_A(void)
+{
+ B &= A;
+ SET_Z(B);
+}
+
+/* 60 0b: 0110 0000 0000 1011 */
+static void ANA_C_A(void)
+{
+ C &= A;
+ SET_Z(C);
+}
+
+/* 60 0c: 0110 0000 0000 1100 */
+static void ANA_D_A(void)
+{
+ D &= A;
+ SET_Z(D);
+}
+
+/* 60 0d: 0110 0000 0000 1101 */
+static void ANA_E_A(void)
+{
+ E &= A;
+ SET_Z(E);
+}
+
+/* 60 0e: 0110 0000 0000 1110 */
+static void ANA_H_A(void)
+{
+ H &= A;
+ SET_Z(H);
+}
+
+/* 60 0f: 0110 0000 0000 1111 */
+static void ANA_L_A(void)
+{
+ L &= A;
+ SET_Z(L);
+}
+
+/* 60 10: 0110 0000 0001 0000 */
+static void XRA_V_A(void)
+{
+ V ^= A;
+ SET_Z(V);
+}
+
+/* 60 11: 0110 0000 0001 0001 */
+static void XRA_A_A(void)
+{
+ A ^= A;
+ SET_Z(A);
+}
+
+/* 60 12: 0110 0000 0001 0010 */
+static void XRA_B_A(void)
+{
+ B ^= A;
+ SET_Z(B);
+}
+
+/* 60 13: 0110 0000 0001 0011 */
+static void XRA_C_A(void)
+{
+ C ^= A;
+ SET_Z(C);
+}
+
+/* 60 14: 0110 0000 0001 0100 */
+static void XRA_D_A(void)
+{
+ D ^= A;
+ SET_Z(D);
+}
+
+/* 60 15: 0110 0000 0001 0101 */
+static void XRA_E_A(void)
+{
+ E ^= A;
+ SET_Z(E);
+}
+
+/* 60 16: 0110 0000 0001 0110 */
+static void XRA_H_A(void)
+{
+ H ^= A;
+ SET_Z(H);
+}
+
+/* 60 17: 0110 0000 0001 0111 */
+static void XRA_L_A(void)
+{
+ L ^= A;
+ SET_Z(L);
+}
+
+/* 60 18: 0110 0000 0001 1000 */
+static void ORA_V_A(void)
+{
+ V |= A;
+ SET_Z(V);
+}
+
+/* 60 19: 0110 0000 0001 1001 */
+static void ORA_A_A(void)
+{
+ A |= A;
+ SET_Z(A);
+}
+
+/* 60 1a: 0110 0000 0001 1010 */
+static void ORA_B_A(void)
+{
+ B |= A;
+ SET_Z(B);
+}
+
+/* 60 1b: 0110 0000 0001 1011 */
+static void ORA_C_A(void)
+{
+ C |= A;
+ SET_Z(C);
+}
+
+/* 60 1c: 0110 0000 0001 1100 */
+static void ORA_D_A(void)
+{
+ D |= A;
+ SET_Z(D);
+}
+
+/* 60 1d: 0110 0000 0001 1101 */
+static void ORA_E_A(void)
+{
+ E |= A;
+ SET_Z(E);
+}
+
+/* 60 1e: 0110 0000 0001 1110 */
+static void ORA_H_A(void)
+{
+ H |= A;
+ SET_Z(H);
+}
+
+/* 60 1f: 0110 0000 0001 1111 */
+static void ORA_L_A(void)
+{
+ L |= A;
+ SET_Z(L);
+}
+
+/* 60 20: 0110 0000 0010 0000 */
+static void ADDNC_V_A(void)
+{
+ UINT8 tmp = V + A;
+ ZHC_ADD( tmp, V, 0 );
+ V = tmp;
+ SKIP_NC;
+}
+
+/* 60 21: 0110 0000 0010 0001 */
+static void ADDNC_A_A(void)
+{
+ UINT8 tmp = A + A;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 22: 0110 0000 0010 0010 */
+static void ADDNC_B_A(void)
+{
+ UINT8 tmp = B + A;
+ ZHC_ADD( tmp, B, 0 );
+ B = tmp;
+ SKIP_NC;
+}
+
+/* 60 23: 0110 0000 0010 0011 */
+static void ADDNC_C_A(void)
+{
+ UINT8 tmp = C + A;
+ ZHC_ADD( tmp, C, 0 );
+ C = tmp;
+ SKIP_NC;
+}
+
+/* 60 24: 0110 0000 0010 0100 */
+static void ADDNC_D_A(void)
+{
+ UINT8 tmp = D + A;
+ ZHC_ADD( tmp, D, 0 );
+ D = tmp;
+ SKIP_NC;
+}
+
+/* 60 25: 0110 0000 0010 0101 */
+static void ADDNC_E_A(void)
+{
+ UINT8 tmp = E + A;
+ ZHC_ADD( tmp, E, 0 );
+ E = tmp;
+ SKIP_NC;
+}
+
+/* 60 26: 0110 0000 0010 0110 */
+static void ADDNC_H_A(void)
+{
+ UINT8 tmp = H + A;
+ ZHC_ADD( tmp, H, 0 );
+ H = tmp;
+ SKIP_NC;
+}
+
+/* 60 27: 0110 0000 0010 0111 */
+static void ADDNC_L_A(void)
+{
+ UINT8 tmp = L + A;
+ ZHC_ADD( tmp, L, 0 );
+ L = tmp;
+ SKIP_NC;
+}
+
+/* 60 28: 0110 0000 0010 1000 */
+static void GTA_V_A(void)
+{
+ UINT16 tmp = V - A - 1;
+ ZHC_SUB( tmp, V, 0 );
+ SKIP_NC;
+}
+
+/* 60 29: 0110 0000 0010 1001 */
+static void GTA_A_A(void)
+{
+ UINT16 tmp = A - A - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 60 2a: 0110 0000 0010 1010 */
+static void GTA_B_A(void)
+{
+ UINT16 tmp = B - A - 1;
+ ZHC_SUB( tmp, B, 0 );
+ SKIP_NC;
+}
+
+/* 60 2b: 0110 0000 0010 1011 */
+static void GTA_C_A(void)
+{
+ UINT16 tmp = C - A - 1;
+ ZHC_SUB( tmp, C, 0 );
+ SKIP_NC;
+}
+
+/* 60 2c: 0110 0000 0010 1100 */
+static void GTA_D_A(void)
+{
+ UINT16 tmp = D - A - 1;
+ ZHC_SUB( tmp, D, 0 );
+ SKIP_NC;
+}
+
+/* 60 2d: 0110 0000 0010 1101 */
+static void GTA_E_A(void)
+{
+ UINT16 tmp = E - A - 1;
+ ZHC_SUB( tmp, E, 0 );
+ SKIP_NC;
+}
+
+/* 60 2e: 0110 0000 0010 1110 */
+static void GTA_H_A(void)
+{
+ UINT16 tmp = H - A - 1;
+ ZHC_SUB( tmp, H, 0 );
+ SKIP_NC;
+}
+
+/* 60 2f: 0110 0000 0010 1111 */
+static void GTA_L_A(void)
+{
+ UINT16 tmp = L - A - 1;
+ ZHC_SUB( tmp, L, 0 );
+ SKIP_NC;
+}
+
+/* 60 30: 0110 0000 0011 0000 */
+static void SUBNB_V_A(void)
+{
+ UINT8 tmp = V - A;
+ ZHC_SUB( tmp, V, 0 );
+ V = tmp;
+ SKIP_NC;
+}
+
+/* 60 31: 0110 0000 0011 0001 */
+static void SUBNB_A_A(void)
+{
+ UINT8 tmp = A - A;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 32: 0110 0000 0011 0010 */
+static void SUBNB_B_A(void)
+{
+ UINT8 tmp = B - A;
+ ZHC_SUB( tmp, B, 0 );
+ B = tmp;
+ SKIP_NC;
+}
+
+/* 60 33: 0110 0000 0011 0011 */
+static void SUBNB_C_A(void)
+{
+ UINT8 tmp = C - A;
+ ZHC_SUB( tmp, C, 0 );
+ C = tmp;
+ SKIP_NC;
+}
+
+/* 60 34: 0110 0000 0011 0100 */
+static void SUBNB_D_A(void)
+{
+ UINT8 tmp = D - A;
+ ZHC_SUB( tmp, D, 0 );
+ D = tmp;
+ SKIP_NC;
+}
+
+/* 60 35: 0110 0000 0011 0101 */
+static void SUBNB_E_A(void)
+{
+ UINT8 tmp = E - A;
+ ZHC_SUB( tmp, E, 0 );
+ E = tmp;
+ SKIP_NC;
+}
+
+/* 60 36: 0110 0000 0011 0110 */
+static void SUBNB_H_A(void)
+{
+ UINT8 tmp = H - A;
+ ZHC_SUB( tmp, H, 0 );
+ H = tmp;
+ SKIP_NC;
+}
+
+/* 60 37: 0110 0000 0011 0111 */
+static void SUBNB_L_A(void)
+{
+ UINT8 tmp = L - A;
+ ZHC_SUB( tmp, L, 0 );
+ L = tmp;
+ SKIP_NC;
+}
+
+/* 60 38: 0110 0000 0011 1000 */
+static void LTA_V_A(void)
+{
+ UINT8 tmp = V - A;
+ ZHC_SUB( tmp, V, 0 );
+ SKIP_CY;
+}
+
+/* 60 39: 0110 0000 0011 1001 */
+static void LTA_A_A(void)
+{
+ UINT8 tmp = A - A;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 60 3a: 0110 0000 0011 1010 */
+static void LTA_B_A(void)
+{
+ UINT8 tmp = B - A;
+ ZHC_SUB( tmp, B, 0 );
+ SKIP_CY;
+}
+
+/* 60 3b: 0110 0000 0011 1011 */
+static void LTA_C_A(void)
+{
+ UINT8 tmp = C - A;
+ ZHC_SUB( tmp, C, 0 );
+ SKIP_CY;
+}
+
+/* 60 3c: 0110 0000 0011 1100 */
+static void LTA_D_A(void)
+{
+ UINT8 tmp = D - A;
+ ZHC_SUB( tmp, D, 0 );
+ SKIP_CY;
+}
+
+/* 60 3d: 0110 0000 0011 1101 */
+static void LTA_E_A(void)
+{
+ UINT8 tmp = E - A;
+ ZHC_SUB( tmp, E, 0 );
+ SKIP_CY;
+}
+
+/* 60 3e: 0110 0000 0011 1110 */
+static void LTA_H_A(void)
+{
+ UINT8 tmp = H - A;
+ ZHC_SUB( tmp, H, 0 );
+ SKIP_CY;
+}
+
+/* 60 3f: 0110 0000 0011 1111 */
+static void LTA_L_A(void)
+{
+ UINT8 tmp = L - A;
+ ZHC_SUB( tmp, L, 0 );
+ SKIP_CY;
+}
+
+/* 60 40: 0110 0000 0100 0000 */
+static void ADD_V_A(void)
+{
+ UINT8 tmp = V + A;
+ ZHC_ADD( tmp, V, 0 );
+ V = tmp;
+}
+
+/* 60 41: 0110 0000 0100 0001 */
+static void ADD_A_A(void)
+{
+ UINT8 tmp = A + A;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 42: 0110 0000 0100 0010 */
+static void ADD_B_A(void)
+{
+ UINT8 tmp = B + A;
+ ZHC_ADD( tmp, B, 0 );
+ B = tmp;
+}
+
+/* 60 43: 0110 0000 0100 0011 */
+static void ADD_C_A(void)
+{
+ UINT8 tmp = C + A;
+ ZHC_ADD( tmp, C, 0 );
+ C = tmp;
+}
+
+/* 60 44: 0110 0000 0100 0100 */
+static void ADD_D_A(void)
+{
+ UINT8 tmp = D + A;
+ ZHC_ADD( tmp, D, 0 );
+ D = tmp;
+}
+
+/* 60 45: 0110 0000 0100 0101 */
+static void ADD_E_A(void)
+{
+ UINT8 tmp = E + A;
+ ZHC_ADD( tmp, E, 0 );
+ E = tmp;
+}
+
+/* 60 46: 0110 0000 0100 0110 */
+static void ADD_H_A(void)
+{
+ UINT8 tmp = H + A;
+ ZHC_ADD( tmp, H, 0 );
+ H = tmp;
+}
+
+/* 60 47: 0110 0000 0100 0111 */
+static void ADD_L_A(void)
+{
+ UINT8 tmp = L + A;
+ ZHC_ADD( tmp, L, 0 );
+ L = tmp;
+}
+
+/* 60 50: 0110 0000 0101 0000 */
+static void ADC_V_A(void)
+{
+ UINT8 tmp = V + A + (PSW & CY);
+ ZHC_ADD( tmp, V, (PSW & CY) );
+ V = tmp;
+}
+
+/* 60 51: 0110 0000 0101 0001 */
+static void ADC_A_A(void)
+{
+ UINT8 tmp = A + A + (PSW & CY);
+ ZHC_ADD( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 52: 0110 0000 0101 0010 */
+static void ADC_B_A(void)
+{
+ UINT8 tmp = B + A + (PSW & CY);
+ ZHC_ADD( tmp, B, (PSW & CY) );
+ B = tmp;
+}
+
+/* 60 53: 0110 0000 0101 0011 */
+static void ADC_C_A(void)
+{
+ UINT8 tmp = C + A + (PSW & CY);
+ ZHC_ADD( tmp, C, (PSW & CY) );
+ C = tmp;
+}
+
+/* 60 54: 0110 0000 0101 0100 */
+static void ADC_D_A(void)
+{
+ UINT8 tmp = D + A + (PSW & CY);
+ ZHC_ADD( tmp, D, (PSW & CY) );
+ D = tmp;
+}
+
+/* 60 55: 0110 0000 0101 0101 */
+static void ADC_E_A(void)
+{
+ UINT8 tmp = E + A + (PSW & CY);
+ ZHC_ADD( tmp, E, (PSW & CY) );
+ E = tmp;
+}
+
+/* 60 56: 0110 0000 0101 0110 */
+static void ADC_H_A(void)
+{
+ UINT8 tmp = H + A + (PSW & CY);
+ ZHC_ADD( tmp, H, (PSW & CY) );
+ H = tmp;
+}
+
+/* 60 57: 0110 0000 0101 0111 */
+static void ADC_L_A(void)
+{
+ UINT8 tmp = L + A + (PSW & CY);
+ ZHC_ADD( tmp, L, (PSW & CY) );
+ L = tmp;
+}
+
+/* 60 60: 0110 0000 0110 0000 */
+static void SUB_V_A(void)
+{
+ UINT8 tmp = V - A;
+ ZHC_SUB( tmp, V, 0 );
+ V = tmp;
+}
+
+/* 60 61: 0110 0000 0110 0001 */
+static void SUB_A_A(void)
+{
+ UINT8 tmp = A - A;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 62: 0110 0000 0110 0010 */
+static void SUB_B_A(void)
+{
+ UINT8 tmp = B - A;
+ ZHC_SUB( tmp, B, 0 );
+ B = tmp;
+}
+
+/* 60 63: 0110 0000 0110 0011 */
+static void SUB_C_A(void)
+{
+ UINT8 tmp = C - A;
+ ZHC_SUB( tmp, C, 0 );
+ C = tmp;
+}
+
+/* 60 64: 0110 0000 0110 0100 */
+static void SUB_D_A(void)
+{
+ UINT8 tmp = D - A;
+ ZHC_SUB( tmp, D, 0 );
+ D = tmp;
+}
+
+/* 60 65: 0110 0000 0110 0101 */
+static void SUB_E_A(void)
+{
+ UINT8 tmp = E - A;
+ ZHC_SUB( tmp, E, 0 );
+ E = tmp;
+}
+
+/* 60 66: 0110 0000 0110 0110 */
+static void SUB_H_A(void)
+{
+ UINT8 tmp = H - A;
+ ZHC_SUB( tmp, H, 0 );
+ H = tmp;
+}
+
+/* 60 67: 0110 0000 0110 0111 */
+static void SUB_L_A(void)
+{
+ UINT8 tmp = L - A;
+ ZHC_SUB( tmp, L, 0 );
+ L = tmp;
+}
+
+/* 60 68: 0110 0000 0110 1000 */
+static void NEA_V_A(void)
+{
+ UINT8 tmp = V - A;
+ ZHC_SUB( tmp, V, 0 );
+ SKIP_NZ;
+}
+
+/* 60 69: 0110 0000 0110 1001 */
+static void NEA_A_A(void)
+{
+ UINT8 tmp = A - A;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 60 6a: 0110 0000 0110 1010 */
+static void NEA_B_A(void)
+{
+ UINT8 tmp = B - A;
+ ZHC_SUB( tmp, B, 0 );
+ SKIP_NZ;
+}
+
+/* 60 6b: 0110 0000 0110 1011 */
+static void NEA_C_A(void)
+{
+ UINT8 tmp = C - A;
+ ZHC_SUB( tmp, C, 0 );
+ SKIP_NZ;
+}
+
+/* 60 6c: 0110 0000 0110 1100 */
+static void NEA_D_A(void)
+{
+ UINT8 tmp = D - A;
+ ZHC_SUB( tmp, D, 0 );
+ SKIP_NZ;
+}
+
+/* 60 6d: 0110 0000 0110 1101 */
+static void NEA_E_A(void)
+{
+ UINT8 tmp = E - A;
+ ZHC_SUB( tmp, E, 0 );
+ SKIP_NZ;
+}
+
+/* 60 6e: 0110 0000 0110 1110 */
+static void NEA_H_A(void)
+{
+ UINT8 tmp = H - A;
+ ZHC_SUB( tmp, H, 0 );
+ SKIP_NZ;
+}
+
+/* 60 6f: 0110 0000 0110 1111 */
+static void NEA_L_A(void)
+{
+ UINT8 tmp = L - A;
+ ZHC_SUB( tmp, L, 0 );
+ SKIP_NZ;
+}
+
+/* 60 70: 0110 0000 0111 0000 */
+static void SBB_V_A(void)
+{
+ UINT8 tmp = V - A - (PSW & CY);
+ ZHC_SUB( tmp, V, (PSW & CY) );
+ V = tmp;
+}
+
+/* 60 71: 0110 0000 0111 0001 */
+static void SBB_A_A(void)
+{
+ UINT8 tmp = A - A - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 72: 0110 0000 0111 0010 */
+static void SBB_B_A(void)
+{
+ UINT8 tmp = B - A - (PSW & CY);
+ ZHC_SUB( tmp, B, (PSW & CY) );
+ B = tmp;
+}
+
+/* 60 73: 0110 0000 0111 0011 */
+static void SBB_C_A(void)
+{
+ UINT8 tmp = C - A - (PSW & CY);
+ ZHC_SUB( tmp, C, (PSW & CY) );
+ C = tmp;
+}
+
+/* 60 74: 0110 0000 0111 0100 */
+static void SBB_D_A(void)
+{
+ UINT8 tmp = D - A - (PSW & CY);
+ ZHC_SUB( tmp, D, (PSW & CY) );
+ D = tmp;
+}
+
+/* 60 75: 0110 0000 0111 0101 */
+static void SBB_E_A(void)
+{
+ UINT8 tmp = E - A - (PSW & CY);
+ ZHC_SUB( tmp, E, (PSW & CY) );
+ E = tmp;
+}
+
+/* 60 76: 0110 0000 0111 0110 */
+static void SBB_H_A(void)
+{
+ UINT8 tmp = H - A - (PSW & CY);
+ ZHC_SUB( tmp, H, (PSW & CY) );
+ H = tmp;
+}
+
+/* 60 77: 0110 0000 0111 0111 */
+static void SBB_L_A(void)
+{
+ UINT8 tmp = L - A - (PSW & CY);
+ ZHC_SUB( tmp, L, (PSW & CY) );
+ L = tmp;
+}
+
+/* 60 78: 0110 0000 0111 1000 */
+static void EQA_V_A(void)
+{
+ UINT8 tmp = V - A;
+ ZHC_SUB( tmp, V, 0 );
+ SKIP_Z;
+}
+
+/* 60 79: 0110 0000 0111 1001 */
+static void EQA_A_A(void)
+{
+ UINT8 tmp = A - A;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 60 7a: 0110 0000 0111 1010 */
+static void EQA_B_A(void)
+{
+ UINT8 tmp = B - A;
+ ZHC_SUB( tmp, B, 0 );
+ SKIP_Z;
+}
+
+/* 60 7b: 0110 0000 0111 1011 */
+static void EQA_C_A(void)
+{
+ UINT8 tmp = C - A;
+ ZHC_SUB( tmp, C, 0 );
+ SKIP_Z;
+}
+
+/* 60 7c: 0110 0000 0111 1100 */
+static void EQA_D_A(void)
+{
+ UINT8 tmp = D - A;
+ ZHC_SUB( tmp, D, 0 );
+ SKIP_Z;
+}
+
+/* 60 7d: 0110 0000 0111 1101 */
+static void EQA_E_A(void)
+{
+ UINT8 tmp = E - A;
+ ZHC_SUB( tmp, E, 0 );
+ SKIP_Z;
+}
+
+/* 60 7e: 0110 0000 0111 1110 */
+static void EQA_H_A(void)
+{
+ UINT8 tmp = H - A;
+ ZHC_SUB( tmp, H, 0 );
+ SKIP_Z;
+}
+
+/* 60 7f: 0110 0000 0111 1111 */
+static void EQA_L_A(void)
+{
+ UINT8 tmp = L - A;
+ ZHC_SUB( tmp, L, 0 );
+ SKIP_Z;
+}
+
+/* 60 88: 0110 0000 1000 1000 */
+static void ANA_A_V(void)
+{
+ A &= V;
+ SET_Z(A);
+}
+
+/* 60 89: 0110 0000 1000 1001 */
+/* ANA_A_A already defined */
+
+/* 60 8a: 0110 0000 1000 1010 */
+static void ANA_A_B(void)
+{
+ A &= B;
+ SET_Z(A);
+}
+
+/* 60 8b: 0110 0000 1000 1011 */
+static void ANA_A_C(void)
+{
+ A &= C;
+ SET_Z(A);
+}
+
+/* 60 8c: 0110 0000 1000 1100 */
+static void ANA_A_D(void)
+{
+ A &= D;
+ SET_Z(A);
+}
+
+/* 60 8d: 0110 0000 1000 1101 */
+static void ANA_A_E(void)
+{
+ A &= E;
+ SET_Z(A);
+}
+
+/* 60 8e: 0110 0000 1000 1110 */
+static void ANA_A_H(void)
+{
+ A &= H;
+ SET_Z(A);
+}
+
+/* 60 8f: 0110 0000 1000 1111 */
+static void ANA_A_L(void)
+{
+ A &= L;
+ SET_Z(A);
+}
+
+/* 60 90: 0110 0000 1001 0000 */
+static void XRA_A_V(void)
+{
+ A ^= V;
+ SET_Z(A);
+}
+
+/* 60 91: 0110 0000 1001 0001 */
+/* XRA_A_A already defined */
+
+/* 60 92: 0110 0000 1001 0010 */
+static void XRA_A_B(void)
+{
+ A ^= B;
+ SET_Z(A);
+}
+
+/* 60 93: 0110 0000 1001 0011 */
+static void XRA_A_C(void)
+{
+ A ^= C;
+ SET_Z(A);
+}
+
+/* 60 94: 0110 0000 1001 0100 */
+static void XRA_A_D(void)
+{
+ A ^= D;
+ SET_Z(A);
+}
+
+/* 60 95: 0110 0000 1001 0101 */
+static void XRA_A_E(void)
+{
+ A ^= E;
+ SET_Z(A);
+}
+
+/* 60 96: 0110 0000 1001 0110 */
+static void XRA_A_H(void)
+{
+ A ^= H;
+ SET_Z(A);
+}
+
+/* 60 97: 0110 0000 1001 0111 */
+static void XRA_A_L(void)
+{
+ A ^= L;
+ SET_Z(A);
+}
+
+/* 60 98: 0110 0000 1001 1000 */
+static void ORA_A_V(void)
+{
+ A |= V;
+ SET_Z(A);
+}
+
+/* 60 99: 0110 0000 1001 1001 */
+/* ORA_A_A already defined */
+
+/* 60 9a: 0110 0000 1001 1010 */
+static void ORA_A_B(void)
+{
+ A |= B;
+ SET_Z(A);
+}
+
+/* 60 9b: 0110 0000 1001 1011 */
+static void ORA_A_C(void)
+{
+ A |= C;
+ SET_Z(A);
+}
+
+/* 60 9c: 0110 0000 1001 1100 */
+static void ORA_A_D(void)
+{
+ A |= D;
+ SET_Z(A);
+}
+
+/* 60 9d: 0110 0000 1001 1101 */
+static void ORA_A_E(void)
+{
+ A |= E;
+ SET_Z(A);
+}
+
+/* 60 9e: 0110 0000 1001 1110 */
+static void ORA_A_H(void)
+{
+ A |= H;
+ SET_Z(A);
+}
+
+/* 60 9f: 0110 0000 1001 1111 */
+static void ORA_A_L(void)
+{
+ A |= L;
+ SET_Z(A);
+}
+
+/* 60 a0: 0110 0000 1010 0000 */
+static void ADDNC_A_V(void)
+{
+ UINT8 tmp = A + V;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 a1: 0110 0000 1010 0001 */
+/* ADDNC_A_A already defined */
+
+/* 60 a2: 0110 0000 1010 0010 */
+static void ADDNC_A_B(void)
+{
+ UINT8 tmp = A + B;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 a3: 0110 0000 1010 0011 */
+static void ADDNC_A_C(void)
+{
+ UINT8 tmp = A + C;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 a4: 0110 0000 1010 0100 */
+static void ADDNC_A_D(void)
+{
+ UINT8 tmp = A + D;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 a5: 0110 0000 1010 0101 */
+static void ADDNC_A_E(void)
+{
+ UINT8 tmp = A + E;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 a6: 0110 0000 1010 0110 */
+static void ADDNC_A_H(void)
+{
+ UINT8 tmp = A + H;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 a7: 0110 0000 1010 0111 */
+static void ADDNC_A_L(void)
+{
+ UINT8 tmp = A + L;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 a8: 0110 0000 1010 1000 */
+static void GTA_A_V(void)
+{
+ UINT16 tmp = A - V - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 60 a9: 0110 0000 1010 1001 */
+/* GTA_A_A already defined */
+
+/* 60 aa: 0110 0000 1010 1010 */
+static void GTA_A_B(void)
+{
+ UINT16 tmp = A - B - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 60 ab: 0110 0000 1010 1011 */
+static void GTA_A_C(void)
+{
+ UINT16 tmp = A - C - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 60 ac: 0110 0000 1010 1100 */
+static void GTA_A_D(void)
+{
+ UINT16 tmp = A - D - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 60 ad: 0110 0000 1010 1101 */
+static void GTA_A_E(void)
+{
+ UINT16 tmp = A - E - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 60 ae: 0110 0000 1010 1110 */
+static void GTA_A_H(void)
+{
+ UINT16 tmp = A - H - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 60 af: 0110 0000 1010 1111 */
+static void GTA_A_L(void)
+{
+ UINT16 tmp = A - L - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 60 b0: 0110 0000 1011 0000 */
+static void SUBNB_A_V(void)
+{
+ UINT8 tmp = A - V;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 b1: 0110 0000 1011 0001 */
+/* SUBNB_A_A already defined */
+
+/* 60 b2: 0110 0000 1011 0010 */
+static void SUBNB_A_B(void)
+{
+ UINT8 tmp = A - B;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 b3: 0110 0000 1011 0011 */
+static void SUBNB_A_C(void)
+{
+ UINT8 tmp = A - C;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 b4: 0110 0000 1011 0100 */
+static void SUBNB_A_D(void)
+{
+ UINT8 tmp = A - D;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 b5: 0110 0000 1011 0101 */
+static void SUBNB_A_E(void)
+{
+ UINT8 tmp = A - E;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 b6: 0110 0000 1011 0110 */
+static void SUBNB_A_H(void)
+{
+ UINT8 tmp = A - H;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 b7: 0110 0000 1011 0111 */
+static void SUBNB_A_L(void)
+{
+ UINT8 tmp = A - L;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 60 b8: 0110 0000 1011 1000 */
+static void LTA_A_V(void)
+{
+ UINT8 tmp = A - V;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 60 b9: 0110 0000 1011 1001 */
+/* LTA_A_A already defined */
+
+/* 60 ba: 0110 0000 1011 1010 */
+static void LTA_A_B(void)
+{
+ UINT8 tmp = A - B;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 60 bb: 0110 0000 1011 1011 */
+static void LTA_A_C(void)
+{
+ UINT8 tmp = A - C;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 60 bc: 0110 0000 1011 1100 */
+static void LTA_A_D(void)
+{
+ UINT8 tmp = A - D;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 60 bd: 0110 0000 1011 1101 */
+static void LTA_A_E(void)
+{
+ UINT8 tmp = A - E;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 60 be: 0110 0000 1011 1110 */
+static void LTA_A_H(void)
+{
+ UINT8 tmp = A - H;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 60 bf: 0110 0000 1011 1111 */
+static void LTA_A_L(void)
+{
+ UINT8 tmp = A - L;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 60 c0: 0110 0000 1100 0000 */
+static void ADD_A_V(void)
+{
+ UINT8 tmp = A + V;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 c1: 0110 0000 1100 0001 */
+/* ADD_A_A already defined */
+
+/* 60 c2: 0110 0000 1100 0010 */
+static void ADD_A_B(void)
+{
+ UINT8 tmp = A + B;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 c3: 0110 0000 1100 0011 */
+static void ADD_A_C(void)
+{
+ UINT8 tmp = A + C;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 c4: 0110 0000 1100 0100 */
+static void ADD_A_D(void)
+{
+ UINT8 tmp = A + D;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 c5: 0110 0000 1100 0101 */
+static void ADD_A_E(void)
+{
+ UINT8 tmp = A + E;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 c6: 0110 0000 1100 0110 */
+static void ADD_A_H(void)
+{
+ UINT8 tmp = A + H;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 c7: 0110 0000 1100 0111 */
+static void ADD_A_L(void)
+{
+ UINT8 tmp = A + L;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 c8: 0110 0000 1100 1000 */
+static void ONA_A_V(void)
+{
+ if (A & V)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 60 c9: 0110 0000 1100 1001 */
+static void ONA_A_A(void)
+{
+ if (A & A)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 60 ca: 0110 0000 1100 1010 */
+static void ONA_A_B(void)
+{
+ if (A & B)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 60 cb: 0110 0000 1100 1011 */
+static void ONA_A_C(void)
+{
+ if (A & C)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 60 cc: 0110 0000 1100 1100 */
+static void ONA_A_D(void)
+{
+ if (A & D)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 60 cd: 0110 0000 1100 1101 */
+static void ONA_A_E(void)
+{
+ if (A & E)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 60 ce: 0110 0000 1100 1110 */
+static void ONA_A_H(void)
+{
+ if (A & H)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 60 cf: 0110 0000 1100 1111 */
+static void ONA_A_L(void)
+{
+ if (A & L)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 60 d0: 0110 0000 1101 0000 */
+static void ADC_A_V(void)
+{
+ UINT8 tmp = A + V + (PSW & CY);
+ ZHC_ADD( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 d1: 0110 0000 1101 0001 */
+/* ADC_A_A already defined */
+
+/* 60 d2: 0110 0000 1101 0010 */
+static void ADC_A_B(void)
+{
+ UINT8 tmp = A + B + (PSW & CY);
+ ZHC_ADD( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 d3: 0110 0000 1101 0011 */
+static void ADC_A_C(void)
+{
+ UINT8 tmp = A + C + (PSW & CY);
+ ZHC_ADD( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 d4: 0110 0000 1101 0100 */
+static void ADC_A_D(void)
+{
+ UINT8 tmp = A + D + (PSW & CY);
+ ZHC_ADD( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 d5: 0110 0000 1101 0101 */
+static void ADC_A_E(void)
+{
+ UINT8 tmp = A + E + (PSW & CY);
+ ZHC_ADD( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 d6: 0110 0000 1101 0110 */
+static void ADC_A_H(void)
+{
+ UINT8 tmp = A + H + (PSW & CY);
+ ZHC_ADD( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 d7: 0110 0000 1101 0111 */
+static void ADC_A_L(void)
+{
+ UINT8 tmp = A + L + (PSW & CY);
+ ZHC_ADD( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 d8: 0110 0000 1101 1000 */
+static void OFFA_A_V(void)
+{
+ if ( A & V )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 60 d9: 0110 0000 1101 1001 */
+static void OFFA_A_A(void)
+{
+ if ( A & A )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 60 da: 0110 0000 1101 1010 */
+static void OFFA_A_B(void)
+{
+ if ( A & B )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 60 db: 0110 0000 1101 1011 */
+static void OFFA_A_C(void)
+{
+ if ( A & C )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 60 dc: 0110 0000 1101 1100 */
+static void OFFA_A_D(void)
+{
+ if ( A & D )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 60 dd: 0110 0000 1101 1101 */
+static void OFFA_A_E(void)
+{
+ if ( A & E )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 60 de: 0110 0000 1101 1110 */
+static void OFFA_A_H(void)
+{
+ if ( A & H )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 60 df: 0110 0000 1101 1111 */
+static void OFFA_A_L(void)
+{
+ if ( A & L )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 60 e0: 0110 0000 1110 0000 */
+static void SUB_A_V(void)
+{
+ UINT8 tmp = A - V;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 e1: 0110 0000 1110 0001 */
+/* SUB_A_A already defined */
+
+/* 60 e2: 0110 0000 1110 0010 */
+static void SUB_A_B(void)
+{
+ UINT8 tmp = A - B;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 e3: 0110 0000 1110 0011 */
+static void SUB_A_C(void)
+{
+ UINT8 tmp = A - C;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 e4: 0110 0000 1110 0100 */
+static void SUB_A_D(void)
+{
+ UINT8 tmp = A - D;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 e5: 0110 0000 1110 0101 */
+static void SUB_A_E(void)
+{
+ UINT8 tmp = A - E;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 e6: 0110 0000 1110 0110 */
+static void SUB_A_H(void)
+{
+ UINT8 tmp = A - H;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 e7: 0110 0000 1110 0111 */
+static void SUB_A_L(void)
+{
+ UINT8 tmp = A - L;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 60 e8: 0110 0000 1110 1000 */
+static void NEA_A_V(void)
+{
+ UINT8 tmp = A - V;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 60 e9: 0110 0000 1110 1001 */
+/* NEA_A_A already defined */
+
+/* 60 ea: 0110 0000 1110 1010 */
+static void NEA_A_B(void)
+{
+ UINT8 tmp = A - B;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 60 eb: 0110 0000 1110 1011 */
+static void NEA_A_C(void)
+{
+ UINT8 tmp = A - C;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 60 ec: 0110 0000 1110 1100 */
+static void NEA_A_D(void)
+{
+ UINT8 tmp = A - D;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 60 ed: 0110 0000 1110 1101 */
+static void NEA_A_E(void)
+{
+ UINT8 tmp = A - E;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 60 ee: 0110 0000 1110 1110 */
+static void NEA_A_H(void)
+{
+ UINT8 tmp = A - H;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 60 ef: 0110 0000 1110 1111 */
+static void NEA_A_L(void)
+{
+ UINT8 tmp = A - L;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 60 f0: 0110 0000 1111 0000 */
+static void SBB_A_V(void)
+{
+ UINT8 tmp = A - V - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 f1: 0110 0000 1111 0001 */
+/* SBB_A_A already defined */
+
+/* 60 f2: 0110 0000 1111 0010 */
+static void SBB_A_B(void)
+{
+ UINT8 tmp = A - B - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 f3: 0110 0000 1111 0011 */
+static void SBB_A_C(void)
+{
+ UINT8 tmp = A - C - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 f4: 0110 0000 1111 0100 */
+static void SBB_A_D(void)
+{
+ UINT8 tmp = A - D - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 f5: 0110 0000 1111 0101 */
+static void SBB_A_E(void)
+{
+ UINT8 tmp = A - E - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 f6: 0110 0000 1111 0110 */
+static void SBB_A_H(void)
+{
+ UINT8 tmp = A - H - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 f7: 0110 0000 1111 0111 */
+static void SBB_A_L(void)
+{
+ UINT8 tmp = A - L - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 60 f8: 0110 0000 1111 1000 */
+static void EQA_A_V(void)
+{
+ UINT8 tmp = A - V;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 60 f9: 0110 0000 1111 1001 */
+/* EQA_A_A already defined */
+
+/* 60 fa: 0110 0000 1111 1010 */
+static void EQA_A_B(void)
+{
+ UINT8 tmp = A - B;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 60 fb: 0110 0000 1111 1011 */
+static void EQA_A_C(void)
+{
+ UINT8 tmp = A - C;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 60 fc: 0110 0000 1111 1100 */
+static void EQA_A_D(void)
+{
+ UINT8 tmp = A - D;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 60 fd: 0110 0000 1111 1101 */
+static void EQA_A_E(void)
+{
+ UINT8 tmp = A - E;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 60 fe: 0110 0000 1111 1110 */
+static void EQA_A_H(void)
+{
+ UINT8 tmp = A - H;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 60 ff: 0110 0000 1111 1111 */
+static void EQA_A_L(void)
+{
+ UINT8 tmp = A - L;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* prefix 64 */
+/* 64 00: 0110 0100 0000 0000 xxxx xxxx */
+static void MVI_PA_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ WP( UPD7810_PORTA, imm );
+}
+
+/* 64 01: 0110 0100 0000 0001 xxxx xxxx */
+static void MVI_PB_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ WP( UPD7810_PORTB, imm );
+}
+
+/* 64 02: 0110 0100 0000 0010 xxxx xxxx */
+static void MVI_PC_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ WP( UPD7810_PORTC, imm );
+}
+
+/* 64 03: 0110 0100 0000 0011 xxxx xxxx */
+static void MVI_PD_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ WP( UPD7810_PORTD, imm );
+}
+
+/* 64 05: 0110 0100 0000 0101 xxxx xxxx */
+static void MVI_PF_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ WP( UPD7810_PORTF, imm );
+}
+
+/* 64 06: 0110 0100 0000 0110 xxxx xxxx */
+static void MVI_MKH_xx(void)
+{
+ RDOPARG( MKH );
+}
+
+/* 64 07: 0110 0100 0000 0111 xxxx xxxx */
+static void MVI_MKL_xx(void)
+{
+ RDOPARG( MKL );
+}
+
+/* 64 08: 0110 0100 0000 1000 xxxx xxxx */
+static void ANI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA), imm;
+ RDOPARG( imm );
+ pa &= imm;
+ WP( UPD7810_PORTA, pa );
+ SET_Z(pa);
+}
+
+/* 64 09: 0110 0100 0000 1001 xxxx xxxx */
+static void ANI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB), imm;
+ RDOPARG( imm );
+ pb &= imm;
+ WP( UPD7810_PORTB, pb );
+ SET_Z(pb);
+}
+
+/* 64 0a: 0110 0100 0000 1010 xxxx xxxx */
+static void ANI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC), imm;
+ RDOPARG( imm );
+ pc &= imm;
+ WP( UPD7810_PORTC, pc );
+ SET_Z(pc);
+}
+
+/* 64 0b: 0110 0100 0000 1011 xxxx xxxx */
+static void ANI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), imm;
+ RDOPARG( imm );
+ pd &= imm;
+ WP( UPD7810_PORTD, pd );
+ SET_Z(pd);
+}
+
+/* 64 0d: 0110 0100 0000 1101 xxxx xxxx */
+static void ANI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), imm;
+ RDOPARG( imm );
+ pf &= imm;
+ WP( UPD7810_PORTF, pf );
+ SET_Z(pf);
+}
+
+/* 64 0e: 0110 0100 0000 1110 xxxx xxxx */
+static void ANI_MKH_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ MKH &= imm;
+ SET_Z(MKH);
+}
+
+/* 64 0f: 0110 0100 0000 1111 xxxx xxxx */
+static void ANI_MKL_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ MKL &= imm;
+ SET_Z(MKL);
+}
+
+/* 64 10: 0110 0100 0001 0000 xxxx xxxx */
+static void XRI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), imm;
+ RDOPARG( imm );
+ pa ^= imm;
+ WP( UPD7810_PORTA, pa );
+ SET_Z(pa);
+}
+
+/* 64 11: 0110 0100 0001 0001 xxxx xxxx */
+static void XRI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), imm;
+ RDOPARG( imm );
+ pb ^= imm;
+ WP( UPD7810_PORTB, pb );
+ SET_Z(pb);
+}
+
+/* 64 12: 0110 0100 0001 0010 xxxx xxxx */
+static void XRI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), imm;
+ RDOPARG( imm );
+ pc ^= imm;
+ WP( UPD7810_PORTC, pc );
+ SET_Z(pc);
+}
+
+/* 64 13: 0110 0100 0001 0011 xxxx xxxx */
+static void XRI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), imm;
+ RDOPARG( imm );
+ pd ^= imm;
+ WP( UPD7810_PORTD, pd );
+ SET_Z(pd);
+}
+
+/* 64 15: 0110 0100 0001 0101 xxxx xxxx */
+static void XRI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), imm;
+ RDOPARG( imm );
+ pf ^= imm;
+ WP( UPD7810_PORTF, pf );
+ SET_Z(pf);
+}
+
+/* 64 16: 0110 0100 0001 0110 xxxx xxxx */
+static void XRI_MKH_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ MKH ^= imm;
+ SET_Z(MKH);
+}
+
+/* 64 17: 0110 0100 0001 0111 xxxx xxxx */
+static void XRI_MKL_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ MKL ^= imm;
+ SET_Z(MKL);
+}
+
+/* 64 18: 0110 0100 0001 1000 xxxx xxxx */
+static void ORI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), imm;
+ RDOPARG( imm );
+ pa |= imm;
+ WP( UPD7810_PORTA, pa );
+ SET_Z(pa);
+}
+
+/* 64 19: 0110 0100 0001 1001 xxxx xxxx */
+static void ORI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), imm;
+ RDOPARG( imm );
+ pb |= imm;
+ WP( UPD7810_PORTB, pb );
+ SET_Z(pb);
+}
+
+/* 64 1a: 0110 0100 0001 1010 xxxx xxxx */
+static void ORI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), imm;
+ RDOPARG( imm );
+ pc |= imm;
+ WP( UPD7810_PORTC, pc );
+ SET_Z(pc);
+}
+
+/* 64 1b: 0110 0100 0001 1011 xxxx xxxx */
+static void ORI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), imm;
+ RDOPARG( imm );
+ pd |= imm;
+ WP( UPD7810_PORTD, pd );
+ SET_Z(pd);
+}
+
+/* 64 1d: 0110 0100 0001 1101 xxxx xxxx */
+static void ORI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), imm;
+ RDOPARG( imm );
+ pf |= imm;
+ WP( UPD7810_PORTF, pf );
+ SET_Z(pf);
+}
+
+/* 64 1e: 0110 0100 0001 1110 xxxx xxxx */
+static void ORI_MKH_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ MKH |= imm;
+ SET_Z(MKH);
+}
+
+/* 64 1f: 0110 0100 0001 1111 xxxx xxxx */
+static void ORI_MKL_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ MKL |= imm;
+ SET_Z(MKL);
+}
+
+/* 64 20: 0110 0100 0010 0000 xxxx xxxx */
+static void ADINC_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA );
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pa + imm;
+
+ ZHC_ADD( tmp, pa, 0 );
+ WP( UPD7810_PORTA , tmp );
+ SKIP_NC;
+}
+
+/* 64 21: 0110 0100 0010 0001 xxxx xxxx */
+static void ADINC_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB );
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pb + imm;
+
+ ZHC_ADD( tmp, pb, 0 );
+ WP( UPD7810_PORTB, tmp );
+ SKIP_NC;
+}
+
+/* 64 22: 0110 0100 0010 0010 xxxx xxxx */
+static void ADINC_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC );
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pc + imm;
+
+ ZHC_ADD( tmp, pc, 0 );
+ WP( UPD7810_PORTC, tmp );
+ SKIP_NC;
+}
+
+/* 64 23: 0110 0100 0010 0011 xxxx xxxx */
+static void ADINC_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD );
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pd + imm;
+
+ ZHC_ADD( tmp, pd, 0 );
+ WP( UPD7810_PORTD, tmp );
+ SKIP_NC;
+}
+
+/* 64 25: 0110 0100 0010 0101 xxxx xxxx */
+static void ADINC_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF );
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pf + imm;
+
+ ZHC_ADD( tmp, pf, 0 );
+ WP( UPD7810_PORTF, tmp );
+ SKIP_NC;
+}
+
+/* 64 26: 0110 0100 0010 0110 xxxx xxxx */
+static void ADINC_MKH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKH + imm;
+
+ ZHC_ADD( tmp, MKH, 0 );
+ MKH = tmp;
+ SKIP_NC;
+}
+
+/* 64 27: 0110 0100 0010 0111 xxxx xxxx */
+static void ADINC_MKL_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKL + imm;
+
+ ZHC_ADD( tmp, MKL, 0 );
+ MKL = tmp;
+ SKIP_NC;
+}
+
+/* 64 28: 0110 0100 0010 1000 xxxx xxxx */
+static void GTI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = pa - imm - 1;
+ ZHC_SUB( tmp, pa, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 29: 0110 0100 0010 1001 xxxx xxxx */
+static void GTI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = pb - imm - 1;
+ ZHC_SUB( tmp, pb, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 2a: 0110 0100 0010 1010 xxxx xxxx */
+static void GTI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = pc - imm - 1;
+ ZHC_SUB( tmp, pc, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 2b: 0110 0100 0010 1011 xxxx xxxx */
+static void GTI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = pd - imm - 1;
+ ZHC_SUB( tmp, pd, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 2d: 0110 0100 0010 1101 xxxx xxxx */
+static void GTI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = pf - imm - 1;
+ ZHC_SUB( tmp, pf, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 2e: 0110 0100 0010 1110 xxxx xxxx */
+static void GTI_MKH_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = MKH - imm - 1;
+ ZHC_SUB( tmp, MKH, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 2f: 0110 0100 0010 1111 xxxx xxxx */
+static void GTI_MKL_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = MKL - imm - 1;
+ ZHC_SUB( tmp, MKL, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 30: 0110 0100 0011 0000 xxxx xxxx */
+static void SUINB_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pa - imm;
+ ZHC_SUB( tmp, pa, 0 );
+ pa = tmp;
+ WP( UPD7810_PORTA, pa );
+ SKIP_NC;
+}
+
+/* 64 31: 0110 0100 0011 0001 xxxx xxxx */
+static void SUINB_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pb - imm;
+ ZHC_SUB( tmp, pb, 0 );
+ pb = tmp;
+ WP( UPD7810_PORTB, pb );
+ SKIP_NC;
+}
+
+/* 64 32: 0110 0100 0011 0010 xxxx xxxx */
+static void SUINB_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pc - imm;
+ ZHC_SUB( tmp, pc, 0 );
+ pc = tmp;
+ WP( UPD7810_PORTC, pc );
+ SKIP_NC;
+}
+
+/* 64 33: 0110 0100 0011 0011 xxxx xxxx */
+static void SUINB_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pd - imm;
+ ZHC_SUB( tmp, pd, 0 );
+ pd = tmp;
+ WP( UPD7810_PORTD, pd );
+ SKIP_NC;
+}
+
+/* 64 35: 0110 0100 0011 0101 xxxx xxxx */
+static void SUINB_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pf - imm;
+ ZHC_SUB( tmp, pf, 0 );
+ pf = tmp;
+ WP( UPD7810_PORTF, pf );
+ SKIP_NC;
+}
+
+/* 64 36: 0110 0100 0011 0110 xxxx xxxx */
+static void SUINB_MKH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKH - imm;
+ ZHC_SUB( tmp, MKH, 0 );
+ MKH = tmp;
+ SKIP_NC;
+}
+
+/* 64 37: 0110 0100 0011 0111 xxxx xxxx */
+static void SUINB_MKL_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKL - imm;
+ ZHC_SUB( tmp, MKL, 0 );
+ MKL = tmp;
+ SKIP_NC;
+}
+
+/* 64 38: 0110 0100 0011 1000 xxxx xxxx */
+static void LTI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), tmp, imm;
+ RDOPARG( imm );
+ tmp = pa - imm;
+ ZHC_SUB( tmp, pa, 0 );
+ SKIP_CY;
+}
+
+/* 64 39: 0110 0100 0011 1001 xxxx xxxx */
+static void LTI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), tmp, imm;
+ RDOPARG( imm );
+ tmp = pb - imm;
+ ZHC_SUB( tmp, pb, 0 );
+ SKIP_CY;
+}
+
+/* 64 3a: 0110 0100 0011 1010 xxxx xxxx */
+static void LTI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), tmp, imm;
+ RDOPARG( imm );
+ tmp = pc - imm;
+ ZHC_SUB( tmp, pc, 0 );
+ SKIP_CY;
+}
+
+/* 64 3b: 0110 0100 0011 1011 xxxx xxxx */
+static void LTI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), tmp, imm;
+ RDOPARG( imm );
+ tmp = pd - imm;
+ ZHC_SUB( tmp, pd, 0 );
+ SKIP_CY;
+}
+
+/* 64 3d: 0110 0100 0011 1101 xxxx xxxx */
+static void LTI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), tmp, imm;
+ RDOPARG( imm );
+ tmp = pf - imm;
+ ZHC_SUB( tmp, pf, 0 );
+ SKIP_CY;
+}
+
+/* 64 3e: 0110 0100 0011 1110 xxxx xxxx */
+static void LTI_MKH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKH - imm;
+ ZHC_SUB( tmp, MKH, 0 );
+ SKIP_CY;
+}
+
+/* 64 3f: 0110 0100 0011 1111 xxxx xxxx */
+static void LTI_MKL_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKL - imm;
+ ZHC_SUB( tmp, MKL, 0 );
+ SKIP_CY;
+}
+
+/* 64 40: 0110 0100 0100 0000 xxxx xxxx */
+static void ADI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pa + imm;
+ ZHC_ADD( tmp, pa, 0 );
+ pa = tmp;
+ WP( UPD7810_PORTA, pa );
+}
+
+/* 64 41: 0110 0100 0100 0001 xxxx xxxx */
+static void ADI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pb + imm;
+ ZHC_ADD( tmp, pb, 0 );
+ pb = tmp;
+ WP( UPD7810_PORTB, pb );
+}
+
+/* 64 42: 0110 0100 0100 0010 xxxx xxxx */
+static void ADI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pc + imm;
+ ZHC_ADD( tmp, pc, 0 );
+ pc = tmp;
+ WP( UPD7810_PORTC, pc );
+}
+
+/* 64 43: 0110 0100 0100 0011 xxxx xxxx */
+static void ADI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pd + imm;
+ ZHC_ADD( tmp, pd, 0 );
+ pd = tmp;
+ WP( UPD7810_PORTD, pd );
+}
+
+/* 64 45: 0110 0100 0100 0101 xxxx xxxx */
+static void ADI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pf + imm;
+ ZHC_ADD( tmp, pf, 0 );
+ pf = tmp;
+ WP( UPD7810_PORTF, pf );
+}
+
+/* 64 46: 0110 0100 0100 0110 xxxx xxxx */
+static void ADI_MKH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKH + imm;
+ ZHC_ADD( tmp, MKH, 0 );
+ MKH = tmp;
+}
+
+/* 64 47: 0110 0100 0100 0111 xxxx xxxx */
+static void ADI_MKL_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKL + imm;
+ ZHC_ADD( tmp, MKL, 0 );
+ MKL = tmp;
+}
+
+/* 64 48: 0110 0100 0100 1000 xxxx xxxx */
+static void ONI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), imm;
+
+ RDOPARG( imm );
+ if (pa & imm)
+ PSW |= SK;
+}
+
+/* 64 49: 0110 0100 0100 1001 xxxx xxxx */
+static void ONI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), imm;
+
+ RDOPARG( imm );
+ if (pb & imm)
+ PSW |= SK;
+}
+
+/* 64 4a: 0110 0100 0100 1010 xxxx xxxx */
+static void ONI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), imm;
+
+ RDOPARG( imm );
+ if (pc & imm)
+ PSW |= SK;
+}
+
+/* 64 4b: 0110 0100 0100 1011 xxxx xxxx */
+static void ONI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), imm;
+
+ RDOPARG( imm );
+ if (pd & imm)
+ PSW |= SK;
+}
+
+/* 64 4d: 0110 0100 0100 1101 xxxx xxxx */
+static void ONI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), imm;
+
+ RDOPARG( imm );
+ if (pf & imm)
+ PSW |= SK;
+}
+
+/* 64 4e: 0110 0100 0100 1110 xxxx xxxx */
+static void ONI_MKH_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (MKH & imm)
+ PSW |= SK;
+}
+
+/* 64 4f: 0110 0100 0100 1111 xxxx xxxx */
+static void ONI_MKL_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (MKL & imm)
+ PSW |= SK;
+}
+
+/* 64 50: 0110 0100 0101 0000 xxxx xxxx */
+static void ACI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pa + imm + (PSW & CY);
+ ZHC_ADD( tmp, pa, (PSW & CY) );
+ pa = tmp;
+ WP( UPD7810_PORTA, pa );
+}
+
+/* 64 51: 0110 0100 0101 0001 xxxx xxxx */
+static void ACI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pb + imm + (PSW & CY);
+ ZHC_ADD( tmp, pb, (PSW & CY) );
+ pb = tmp;
+ WP( UPD7810_PORTB, pb );
+}
+
+/* 64 52: 0110 0100 0101 0010 xxxx xxxx */
+static void ACI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pc + imm + (PSW & CY);
+ ZHC_ADD( tmp, pc, (PSW & CY) );
+ pc = tmp;
+ WP( UPD7810_PORTC, pc );
+}
+
+/* 64 53: 0110 0100 0101 0011 xxxx xxxx */
+static void ACI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pd + imm + (PSW & CY);
+ ZHC_ADD( tmp, pd, (PSW & CY) );
+ pd = tmp;
+ WP( UPD7810_PORTD, pd );
+}
+
+/* 64 55: 0110 0100 0101 0101 xxxx xxxx */
+static void ACI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pf + imm + (PSW & CY);
+ ZHC_ADD( tmp, pf, (PSW & CY) );
+ pf = tmp;
+ WP( UPD7810_PORTF, pf );
+}
+
+/* 64 56: 0110 0100 0101 0110 xxxx xxxx */
+static void ACI_MKH_xx(void)
+{
+ UINT8 imm, tmp;
+
+ RDOPARG( imm );
+ tmp = MKH + imm + (PSW & CY);
+ ZHC_ADD( tmp, MKH, (PSW & CY) );
+ MKH = tmp;
+}
+
+/* 64 57: 0110 0100 0101 0111 xxxx xxxx */
+static void ACI_MKL_xx(void)
+{
+ UINT8 imm, tmp;
+
+ RDOPARG( imm );
+ tmp = MKL + imm + (PSW & CY);
+ ZHC_ADD( tmp, MKL, (PSW & CY) );
+ MKL = tmp;
+}
+
+/* 64 58: 0110 0100 0101 1000 xxxx xxxx */
+static void OFFI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), imm;
+
+ RDOPARG( imm );
+ if (0 == (pa & imm))
+ PSW |= SK;
+}
+
+/* 64 59: 0110 0100 0101 1001 xxxx xxxx */
+static void OFFI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), imm;
+
+ RDOPARG( imm );
+ if (0 == (pb & imm))
+ PSW |= SK;
+}
+
+/* 64 5a: 0110 0100 0101 1010 xxxx xxxx */
+static void OFFI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), imm;
+
+ RDOPARG( imm );
+ if (0 == (pc & imm))
+ PSW |= SK;
+}
+
+/* 64 5b: 0110 0100 0101 1011 xxxx xxxx */
+static void OFFI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), imm;
+
+ RDOPARG( imm );
+ if (0 == (pd & imm))
+ PSW |= SK;
+}
+
+/* 64 5d: 0110 0100 0101 1101 xxxx xxxx */
+static void OFFI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), imm;
+
+ RDOPARG( imm );
+ if (0 == (pf & imm))
+ PSW |= SK;
+}
+
+/* 64 5e: 0110 0100 0101 1110 xxxx xxxx */
+static void OFFI_MKH_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (MKH & imm))
+ PSW |= SK;
+}
+
+/* 64 5f: 0110 0100 0101 1111 xxxx xxxx */
+static void OFFI_MKL_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (MKL & imm))
+ PSW |= SK;
+}
+
+/* 64 60: 0110 0100 0110 0000 xxxx xxxx */
+static void SUI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pa - imm;
+ ZHC_SUB( tmp, pa, 0 );
+ pa = tmp;
+ WP( UPD7810_PORTA, pa );
+}
+
+/* 64 61: 0110 0100 0110 0001 xxxx xxxx */
+static void SUI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pb - imm;
+ ZHC_SUB( tmp, pb, 0 );
+ pb = tmp;
+ WP( UPD7810_PORTB, pb );
+}
+
+/* 64 62: 0110 0100 0110 0010 xxxx xxxx */
+static void SUI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pc - imm;
+ ZHC_SUB( tmp, pc, 0 );
+ pc = tmp;
+ WP( UPD7810_PORTC, pc );
+}
+
+/* 64 63: 0110 0100 0110 0011 xxxx xxxx */
+static void SUI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pd - imm;
+ ZHC_SUB( tmp, pd, 0 );
+ pd = tmp;
+ WP( UPD7810_PORTD, pd );
+}
+
+/* 64 65: 0110 0100 0110 0101 xxxx xxxx */
+static void SUI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pf - imm;
+ ZHC_SUB( tmp, pf, 0 );
+ pf = tmp;
+ WP( UPD7810_PORTF, pf );
+}
+
+/* 64 66: 0110 0100 0110 0110 xxxx xxxx */
+static void SUI_MKH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKH - imm;
+ ZHC_SUB( tmp, MKH, 0 );
+ MKH = tmp;
+}
+
+/* 64 67: 0110 0100 0110 0111 xxxx xxxx */
+static void SUI_MKL_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKL - imm;
+ ZHC_SUB( tmp, MKL, 0 );
+ MKL = tmp;
+}
+
+/* 64 68: 0110 0100 0110 1000 xxxx xxxx */
+static void NEI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pa - imm;
+ ZHC_SUB( tmp, pa, 0 );
+ SKIP_NZ;
+}
+
+/* 64 69: 0110 0100 0110 1001 xxxx xxxx */
+static void NEI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pb - imm;
+ ZHC_SUB( tmp, pb, 0 );
+ SKIP_NZ;
+}
+
+/* 64 6a: 0110 0100 0110 1010 xxxx xxxx */
+static void NEI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pc - imm;
+ ZHC_SUB( tmp, pc, 0 );
+ SKIP_NZ;
+}
+
+/* 64 6b: 0110 0100 0110 1011 xxxx xxxx */
+static void NEI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pd - imm;
+ ZHC_SUB( tmp, pd, 0 );
+ SKIP_NZ;
+}
+
+/* 64 6d: 0110 0100 0110 1101 xxxx xxxx */
+static void NEI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pf - imm;
+ ZHC_SUB( tmp, pf, 0 );
+ SKIP_NZ;
+}
+
+/* 64 6e: 0110 0100 0110 1110 xxxx xxxx */
+static void NEI_MKH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKH - imm;
+ ZHC_SUB( tmp, MKH, 0 );
+ SKIP_NZ;
+}
+
+/* 64 6f: 0110 0100 0110 1111 xxxx xxxx */
+static void NEI_MKL_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKL - imm;
+ ZHC_SUB( tmp, MKL, 0 );
+ SKIP_NZ;
+}
+
+/* 64 70: 0110 0100 0111 0000 xxxx xxxx */
+static void SBI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pa - imm - (PSW & CY);
+ ZHC_SUB( tmp, pa, (PSW & CY) );
+ pa = tmp;
+ WP( UPD7810_PORTA, pa );
+}
+
+/* 64 71: 0110 0100 0111 0001 xxxx xxxx */
+static void SBI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pb - imm - (PSW & CY);
+ ZHC_SUB( tmp, pb, (PSW & CY) );
+ pb = tmp;
+ WP( UPD7810_PORTB, pb );
+}
+
+/* 64 72: 0110 0100 0111 0010 xxxx xxxx */
+static void SBI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pc - imm - (PSW & CY);
+ ZHC_SUB( tmp, pc, (PSW & CY) );
+ pc = tmp;
+ WP( UPD7810_PORTC, pc );
+}
+
+/* 64 73: 0110 0100 0111 0011 xxxx xxxx */
+static void SBI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pd - imm - (PSW & CY);
+ ZHC_SUB( tmp, pd, (PSW & CY) );
+ pd = tmp;
+ WP( UPD7810_PORTD, pd );
+}
+
+/* 64 75: 0110 0100 0111 0101 xxxx xxxx */
+static void SBI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pf - imm - (PSW & CY);
+ ZHC_SUB( tmp, pf, (PSW & CY) );
+ pf = tmp;
+ WP( UPD7810_PORTF, pf );
+}
+
+/* 64 76: 0110 0100 0111 0110 xxxx xxxx */
+static void SBI_MKH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKH - imm - (PSW & CY);
+ ZHC_SUB( tmp, MKH, (PSW & CY) );
+ MKH = tmp;
+}
+
+/* 64 77: 0110 0100 0111 0111 xxxx xxxx */
+static void SBI_MKL_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKL - imm - (PSW & CY);
+ ZHC_SUB( tmp, MKL, (PSW & CY) );
+ MKL = tmp;
+}
+
+/* 64 78: 0110 0100 0111 1000 xxxx xxxx */
+static void EQI_PA_xx(void)
+{
+ UINT8 pa = RP( UPD7810_PORTA ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pa - imm;
+ ZHC_SUB( tmp, pa, 0 );
+ SKIP_Z;
+}
+
+/* 64 79: 0110 0100 0111 1001 xxxx xxxx */
+static void EQI_PB_xx(void)
+{
+ UINT8 pb = RP( UPD7810_PORTB ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pb - imm;
+ ZHC_SUB( tmp, pb, 0 );
+ SKIP_Z;
+}
+
+/* 64 7a: 0110 0100 0111 1010 xxxx xxxx */
+static void EQI_PC_xx(void)
+{
+ UINT8 pc = RP( UPD7810_PORTC ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pc - imm;
+ ZHC_SUB( tmp, pc, 0 );
+ SKIP_Z;
+}
+
+/* 64 7b: 0110 0100 0111 1011 xxxx xxxx */
+static void EQI_PD_xx(void)
+{
+ UINT8 pd = RP( UPD7810_PORTD ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pd - imm;
+ ZHC_SUB( tmp, pd, 0 );
+ SKIP_Z;
+}
+
+/* 64 7d: 0110 0100 0111 1101 xxxx xxxx */
+static void EQI_PF_xx(void)
+{
+ UINT8 pf = RP( UPD7810_PORTF ), tmp, imm;
+
+ RDOPARG( imm );
+ tmp = pf - imm;
+ ZHC_SUB( tmp, pf, 0 );
+ SKIP_Z;
+}
+
+/* 64 7e: 0110 0100 0111 1110 xxxx xxxx */
+static void EQI_MKH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKH - imm;
+ ZHC_SUB( tmp, MKH, 0 );
+ SKIP_Z;
+}
+
+/* 64 7f: 0110 0100 0111 1111 xxxx xxxx */
+static void EQI_MKL_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = MKL - imm;
+ ZHC_SUB( tmp, MKL, 0 );
+ SKIP_Z;
+}
+
+/* 64 80: 0110 0100 1000 0000 xxxx xxxx */
+static void MVI_ANM_xx(void)
+{
+ RDOPARG( ANM );
+}
+
+/* 64 81: 0110 0100 1000 0001 xxxx xxxx */
+static void MVI_SMH_xx(void)
+{
+ RDOPARG( SMH );
+}
+
+/* 64 83: 0110 0100 1000 0011 xxxx xxxx */
+static void MVI_EOM_xx(void)
+{
+ RDOPARG( EOM );
+ upd7810_write_EOM();
+}
+
+/* 64 85: 0110 0100 1000 0101 xxxx xxxx */
+static void MVI_TMM_xx(void)
+{
+ RDOPARG( TMM );
+}
+
+/* 64 88: 0110 0100 1000 1000 xxxx xxxx */
+static void ANI_ANM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ ANM &= imm;
+ SET_Z(ANM);
+}
+
+/* 64 89: 0110 0100 1000 1001 xxxx xxxx */
+static void ANI_SMH_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ SMH &= imm;
+ SET_Z(SMH);
+}
+
+/* 64 8b: 0110 0100 1000 1011 xxxx xxxx */
+static void ANI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 imm;
+
+ RDOPARG( imm );
+ /* only bits #1 and #5 can be read */
+ EOM = eom & imm;
+ SET_Z(EOM);
+ upd7810_write_EOM();
+}
+
+/* 64 8d: 0110 0100 1000 1101 xxxx xxxx */
+static void ANI_TMM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ TMM &= imm;
+ SET_Z(TMM);
+}
+
+/* 64 90: 0110 0100 1001 0000 xxxx xxxx */
+static void XRI_ANM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ ANM ^= imm;
+ SET_Z(ANM);
+}
+
+/* 64 91: 0110 0100 1001 0001 xxxx xxxx */
+static void XRI_SMH_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ SMH ^= imm;
+ SET_Z(SMH);
+}
+
+/* 64 93: 0110 0100 1001 0011 xxxx xxxx */
+static void XRI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 imm;
+
+ RDOPARG( imm );
+ /* only bits #1 and #5 can be read */
+ EOM = eom ^ imm;
+ SET_Z(EOM);
+ upd7810_write_EOM();
+}
+
+/* 64 95: 0110 0100 1001 0101 xxxx xxxx */
+static void XRI_TMM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ TMM ^= imm;
+ SET_Z(TMM);
+}
+
+/* 64 98: 0110 0100 1001 1000 xxxx xxxx */
+static void ORI_ANM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ ANM |= imm;
+ SET_Z(ANM);
+}
+
+/* 64 99: 0110 0100 1001 1001 xxxx xxxx */
+static void ORI_SMH_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ SMH |= imm;
+ SET_Z(SMH);
+}
+
+/* 64 9b: 0110 0100 1001 1011 xxxx xxxx */
+static void ORI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 imm;
+
+ RDOPARG( imm );
+ /* only bits #1 and #5 can be read */
+ EOM = eom | imm;
+ SET_Z(EOM);
+ upd7810_write_EOM();
+}
+
+/* 64 9d: 0110 0100 1001 1101 xxxx xxxx */
+static void ORI_TMM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ TMM |= imm;
+ SET_Z(TMM);
+}
+
+/* 64 a0: 0110 0100 1010 0000 xxxx xxxx */
+static void ADINC_ANM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = ANM + imm;
+
+ ZHC_ADD( tmp, ANM, 0 );
+ ANM = tmp;
+ SKIP_NC;
+}
+
+/* 64 a1: 0110 0100 1010 0001 xxxx xxxx */
+static void ADINC_SMH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = SMH + imm;
+
+ ZHC_ADD( tmp, SMH, 0 );
+ SMH = tmp;
+ SKIP_NC;
+}
+
+/* 64 a3: 0110 0100 1010 0011 xxxx xxxx */
+static void ADINC_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ /* only bits #1 and #5 can be read */
+ tmp = eom + imm;
+
+ ZHC_ADD( tmp, eom, 0 );
+ EOM = tmp;
+ SKIP_NC;
+ upd7810_write_EOM();
+}
+
+/* 64 a5: 0110 0100 1010 0101 xxxx xxxx */
+static void ADINC_TMM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = TMM + imm;
+
+ ZHC_ADD( tmp, TMM, 0 );
+ TMM = tmp;
+ SKIP_NC;
+}
+
+/* 64 a8: 0110 0100 1010 1000 xxxx xxxx */
+static void GTI_ANM_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = ANM - imm - 1;
+ ZHC_SUB( tmp, ANM, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 a9: 0110 0100 1010 1001 xxxx xxxx */
+static void GTI_SMH_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = SMH - imm - 1;
+ ZHC_SUB( tmp, SMH, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 ab: 0110 0100 1010 1011 xxxx xxxx */
+static void GTI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = eom - imm - 1;
+ ZHC_SUB( tmp, eom, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 ad: 0110 0100 1010 1101 xxxx xxxx */
+static void GTI_TMM_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = TMM - imm - 1;
+ ZHC_SUB( tmp, TMM, 0 );
+
+ SKIP_NC;
+}
+
+/* 64 b0: 0110 0100 1011 0000 xxxx xxxx */
+static void SUINB_ANM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = ANM - imm;
+ ZHC_SUB( tmp, ANM, 0 );
+ ANM = tmp;
+ SKIP_NC;
+}
+
+/* 64 b1: 0110 0100 1011 0001 xxxx xxxx */
+static void SUINB_SMH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = SMH - imm;
+ ZHC_SUB( tmp, SMH, 0 );
+ SMH = tmp;
+ SKIP_NC;
+}
+
+/* 64 b3: 0110 0100 1011 0011 xxxx xxxx */
+static void SUINB_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = eom - imm;
+ ZHC_SUB( tmp, eom, 0 );
+ EOM = tmp;
+ SKIP_NC;
+ upd7810_write_EOM();
+}
+
+/* 64 b5: 0110 0100 1011 0101 xxxx xxxx */
+static void SUINB_TMM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = TMM - imm;
+ ZHC_SUB( tmp, TMM, 0 );
+ TMM = tmp;
+ SKIP_NC;
+}
+
+/* 64 b8: 0110 0100 1011 1000 xxxx xxxx */
+static void LTI_ANM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = ANM - imm;
+ ZHC_SUB( tmp, ANM, 0 );
+ SKIP_CY;
+}
+
+/* 64 b9: 0110 0100 1011 1001 xxxx xxxx */
+static void LTI_SMH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = SMH - imm;
+ ZHC_SUB( tmp, SMH, 0 );
+ SKIP_CY;
+}
+
+/* 64 bb: 0110 0100 1011 1011 xxxx xxxx */
+static void LTI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = eom - imm;
+ ZHC_SUB( tmp, eom, 0 );
+ SKIP_CY;
+}
+
+/* 64 bd: 0110 0100 1011 1101 xxxx xxxx */
+static void LTI_TMM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = TMM - imm;
+ ZHC_SUB( tmp, TMM, 0 );
+ SKIP_CY;
+}
+
+/* 64 c0: 0110 0100 1100 0000 xxxx xxxx */
+static void ADI_ANM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = ANM + imm;
+
+ ZHC_ADD( tmp, ANM, 0 );
+ ANM = tmp;
+}
+
+/* 64 c1: 0110 0100 1100 0001 xxxx xxxx */
+static void ADI_SMH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = SMH + imm;
+
+ ZHC_ADD( tmp, SMH, 0 );
+ SMH = tmp;
+}
+
+/* 64 c3: 0110 0100 1100 0011 xxxx xxxx */
+static void ADI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = eom + imm;
+
+ ZHC_ADD( tmp, eom, 0 );
+ EOM = tmp;
+ upd7810_write_EOM();
+}
+
+/* 64 c5: 0110 0100 1100 0101 xxxx xxxx */
+static void ADI_TMM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = TMM + imm;
+
+ ZHC_ADD( tmp, TMM, 0 );
+ TMM = tmp;
+}
+
+/* 64 c8: 0110 0100 1100 1000 xxxx xxxx */
+static void ONI_ANM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (ANM & imm)
+ PSW |= SK;
+}
+
+/* 64 c9: 0110 0100 1100 1001 xxxx xxxx */
+static void ONI_SMH_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (SMH & imm)
+ PSW |= SK;
+}
+
+/* 64 cb: 0110 0100 1100 1011 xxxx xxxx */
+static void ONI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (eom & imm)
+ PSW |= SK;
+}
+
+/* 64 cd: 0110 0100 1100 1101 xxxx xxxx */
+static void ONI_TMM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (TMM & imm)
+ PSW |= SK;
+}
+
+/* 64 d0: 0110 0100 1101 0000 xxxx xxxx */
+static void ACI_ANM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = ANM + imm + (PSW & CY);
+
+ ZHC_ADD( tmp, ANM, (PSW & CY) );
+ ANM = tmp;
+}
+
+/* 64 d1: 0110 0100 1101 0001 xxxx xxxx */
+static void ACI_SMH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = SMH + imm + (PSW & CY);
+
+ ZHC_ADD( tmp, SMH, (PSW & CY) );
+ SMH = tmp;
+}
+
+/* 64 d3: 0110 0100 1101 0011 xxxx xxxx */
+static void ACI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = eom + imm + (PSW & CY);
+
+ ZHC_ADD( tmp, eom, (PSW & CY) );
+ EOM = tmp;
+ upd7810_write_EOM();
+}
+
+/* 64 d5: 0110 0100 1101 0101 xxxx xxxx */
+static void ACI_TMM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = TMM + imm + (PSW & CY);
+
+ ZHC_ADD( tmp, TMM, (PSW & CY) );
+ TMM = tmp;
+}
+
+/* 64 d8: 0110 0100 1101 1000 xxxx xxxx */
+static void OFFI_ANM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (ANM & imm))
+ PSW |= SK;
+}
+
+/* 64 d9: 0110 0100 1101 1001 xxxx xxxx */
+static void OFFI_SMH_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (SMH & imm))
+ PSW |= SK;
+}
+
+/* 64 db: 0110 0100 1101 1011 xxxx xxxx */
+static void OFFI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (eom & imm))
+ PSW |= SK;
+}
+
+/* 64 dd: 0110 0100 1101 1101 xxxx xxxx */
+static void OFFI_TMM_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (TMM & imm))
+ PSW |= SK;
+}
+
+/* 64 e0: 0110 0100 1110 0000 xxxx xxxx */
+static void SUI_ANM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = ANM - imm;
+ ZHC_SUB( tmp, ANM, 0 );
+ ANM = tmp;
+}
+
+/* 64 e1: 0110 0100 1110 0001 xxxx xxxx */
+static void SUI_SMH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = SMH - imm;
+ ZHC_SUB( tmp, SMH, 0 );
+ SMH = tmp;
+}
+
+/* 64 e3: 0110 0100 1110 0011 xxxx xxxx */
+static void SUI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = eom - imm;
+ ZHC_SUB( tmp, eom, 0 );
+ EOM = tmp;
+ upd7810_write_EOM();
+}
+
+/* 64 e5: 0110 0100 1110 0101 xxxx xxxx */
+static void SUI_TMM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = TMM - imm;
+ ZHC_SUB( tmp, TMM, 0 );
+ TMM = tmp;
+}
+
+/* 64 e8: 0110 0100 1110 1000 xxxx xxxx */
+static void NEI_ANM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = ANM - imm;
+ ZHC_SUB( tmp, ANM, 0 );
+ SKIP_NZ;
+}
+
+/* 64 e9: 0110 0100 1110 1001 xxxx xxxx */
+static void NEI_SMH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = SMH - imm;
+ ZHC_SUB( tmp, SMH, 0 );
+ SKIP_NZ;
+}
+
+/* 64 eb: 0110 0100 1110 1011 xxxx xxxx */
+static void NEI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = eom - imm;
+ ZHC_SUB( tmp, eom, 0 );
+ SKIP_NZ;
+}
+
+/* 64 ed: 0110 0100 1110 1101 xxxx xxxx */
+static void NEI_TMM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = TMM - imm;
+ ZHC_SUB( tmp, TMM, 0 );
+ SKIP_NZ;
+}
+
+/* 64 f0: 0110 0100 1111 0000 xxxx xxxx */
+static void SBI_ANM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = ANM - imm - (PSW & CY);
+ ZHC_SUB( tmp, ANM, (PSW & CY) );
+ ANM = tmp;
+}
+
+/* 64 f1: 0110 0100 1111 0001 xxxx xxxx */
+static void SBI_SMH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = SMH - imm - (PSW & CY);
+ ZHC_SUB( tmp, SMH, (PSW & CY) );
+ SMH = tmp;
+}
+
+/* 64 f3: 0110 0100 1111 0011 xxxx xxxx */
+static void SBI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = eom - imm - (PSW & CY);
+ ZHC_SUB( tmp, eom, (PSW & CY) );
+ EOM = tmp;
+ upd7810_write_EOM();
+}
+
+/* 64 f5: 0110 0100 1111 0101 xxxx xxxx */
+static void SBI_TMM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = TMM - imm - (PSW & CY);
+ ZHC_SUB( tmp, TMM, (PSW & CY) );
+ TMM = tmp;
+}
+
+/* 64 f8: 0110 0100 1111 1000 xxxx xxxx */
+static void EQI_ANM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = ANM - imm;
+ ZHC_SUB( tmp, ANM, 0 );
+ SKIP_Z;
+}
+
+/* 64 f9: 0110 0100 1111 1001 xxxx xxxx */
+static void EQI_SMH_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = SMH - imm;
+ ZHC_SUB( tmp, SMH, 0 );
+ SKIP_Z;
+}
+
+/* 64 fb: 0110 0100 1111 1011 xxxx xxxx */
+static void EQI_EOM_xx(void)
+{
+ /* only bits #1 and #5 can be read */
+ UINT8 eom = EOM & 0x22;
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = eom - imm;
+ ZHC_SUB( tmp, eom, 0 );
+ SKIP_Z;
+}
+
+/* 64 fd: 0110 0100 1111 1101 xxxx xxxx */
+static void EQI_TMM_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = TMM - imm;
+ ZHC_SUB( tmp, TMM, 0 );
+ SKIP_Z;
+}
+
+/* prefix 70 */
+/* 70 0e: 0111 0000 0000 1110 llll llll hhhh hhhh */
+static void SSPD_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, SPL );
+ WM( ea.d + 1, SPH );
+}
+
+/* 70 0f: 0111 0000 0000 1111 llll llll hhhh hhhh */
+static void LSPD_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ SPL = RM( ea.d );
+ SPH = RM( ea.d + 1 );
+}
+
+/* 70 1e: 0111 0000 0001 1110 llll llll hhhh hhhh */
+static void SBCD_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, C );
+ WM( ea.d + 1, B );
+}
+
+/* 70 1f: 0111 0000 0001 1111 llll llll hhhh hhhh */
+static void LBCD_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ C = RM( ea.d );
+ B = RM( ea.d + 1 );
+}
+
+/* 70 2e: 0111 0000 0010 1110 llll llll hhhh hhhh */
+static void SDED_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, E );
+ WM( ea.d + 1, D );
+}
+
+/* 70 2f: 0111 0000 0010 1111 llll llll hhhh hhhh */
+static void LDED_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ E = RM( ea.d );
+ D = RM( ea.d + 1 );
+}
+
+/* 70 3e: 0111 0000 0011 1110 llll llll hhhh hhhh */
+static void SHLD_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, L );
+ WM( ea.d + 1, H );
+}
+
+/* 70 3f: 0111 0000 0011 1111 llll llll hhhh hhhh */
+static void LHLD_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ L = RM( ea.d );
+ H = RM( ea.d + 1 );
+}
+
+/* 70 41: 0111 0000 0100 0001 */
+static void EADD_EA_A(void)
+{
+ UINT16 tmp;
+ tmp = EA + A;
+ ZHC_ADD( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 70 42: 0111 0000 0100 0010 */
+static void EADD_EA_B(void)
+{
+ UINT16 tmp;
+ tmp = EA + B;
+ ZHC_ADD( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 70 43: 0111 0000 0100 0011 */
+static void EADD_EA_C(void)
+{
+ UINT16 tmp;
+ tmp = EA + C;
+ ZHC_ADD( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 70 61: 0111 0000 0110 0001 */
+static void ESUB_EA_A(void)
+{
+ UINT16 tmp;
+ tmp = EA - A;
+ ZHC_SUB( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 70 62: 0111 0000 0110 0010 */
+static void ESUB_EA_B(void)
+{
+ UINT16 tmp;
+ tmp = EA - B;
+ ZHC_SUB( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 70 63: 0111 0000 0110 0011 */
+static void ESUB_EA_C(void)
+{
+ UINT16 tmp;
+ tmp = EA - C;
+ ZHC_SUB( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 70 68: 0111 0000 0110 1000 llll llll hhhh hhhh */
+static void MOV_V_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ V = RM( ea.d );
+}
+
+/* 70 69: 0111 0000 0110 1001 llll llll hhhh hhhh */
+static void MOV_A_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ A = RM( ea.d );
+}
+
+/* 70 6a: 0111 0000 0110 1010 llll llll hhhh hhhh */
+static void MOV_B_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ B = RM( ea.d );
+}
+
+/* 70 6b: 0111 0000 0110 1011 llll llll hhhh hhhh */
+static void MOV_C_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ C = RM( ea.d );
+}
+
+/* 70 6c: 0111 0000 0110 1100 llll llll hhhh hhhh */
+static void MOV_D_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ D = RM( ea.d );
+}
+
+/* 70 6d: 0111 0000 0110 1101 llll llll hhhh hhhh */
+static void MOV_E_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ E = RM( ea.d );
+}
+
+/* 70 6e: 0111 0000 0110 1110 llll llll hhhh hhhh */
+static void MOV_H_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ H = RM( ea.d );
+}
+
+/* 70 6f: 0111 0000 0110 1111 llll llll hhhh hhhh */
+static void MOV_L_w(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ L = RM( ea.d );
+}
+
+/* 70 78: 0111 0000 0111 1000 llll llll hhhh hhhh */
+static void MOV_w_V(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, V );
+}
+
+/* 70 79: 0111 0000 0111 1001 llll llll hhhh hhhh */
+static void MOV_w_A(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, A );
+}
+
+/* 70 7a: 0111 0000 0111 1010 llll llll hhhh hhhh */
+static void MOV_w_B(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, B );
+}
+
+/* 70 7b: 0111 0000 0111 1011 llll llll hhhh hhhh */
+static void MOV_w_C(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, C );
+}
+
+/* 70 7c: 0111 0000 0111 1100 llll llll hhhh hhhh */
+static void MOV_w_D(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, D );
+}
+
+/* 70 7d: 0111 0000 0111 1101 llll llll hhhh hhhh */
+static void MOV_w_E(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, E );
+}
+
+/* 70 7e: 0111 0000 0111 1110 llll llll hhhh hhhh */
+static void MOV_w_H(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, H );
+}
+
+/* 70 7f: 0111 0000 0111 1111 llll llll hhhh hhhh */
+static void MOV_w_L(void)
+{
+ PAIR ea;
+ ea.d = 0;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( ea.b.h );
+ WM( ea.d, L );
+}
+
+/* 70 89: 0111 0000 1000 1001 */
+static void ANAX_B(void)
+{
+ A &= RM( BC );
+ SET_Z(A);
+}
+
+/* 70 8a: 0111 0000 1000 1010 */
+static void ANAX_D(void)
+{
+ A &= RM( DE );
+ SET_Z(A);
+}
+
+/* 70 8b: 0111 0000 1000 1011 */
+static void ANAX_H(void)
+{
+ A &= RM( HL );
+ SET_Z(A);
+}
+
+/* 70 8c: 0111 0000 1000 1100 */
+static void ANAX_Dp(void)
+{
+ A &= RM( DE );
+ DE++;
+ SET_Z(A);
+}
+
+/* 70 8d: 0111 0000 1000 1101 */
+static void ANAX_Hp(void)
+{
+ A &= RM( HL );
+ HL++;
+ SET_Z(A);
+}
+
+/* 70 8e: 0111 0000 1000 1110 */
+static void ANAX_Dm(void)
+{
+ A &= RM( DE );
+ DE--;
+ SET_Z(A);
+}
+
+/* 70 8f: 0111 0000 1000 1111 */
+static void ANAX_Hm(void)
+{
+ A &= RM( HL );
+ HL--;
+ SET_Z(A);
+}
+
+/* 70 91: 0111 0000 1001 0001 */
+static void XRAX_B(void)
+{
+ A ^= RM( BC );
+ SET_Z(A);
+}
+
+/* 70 92: 0111 0000 1001 0010 */
+static void XRAX_D(void)
+{
+ A ^= RM( DE );
+ SET_Z(A);
+}
+
+/* 70 93: 0111 0000 1001 0011 */
+static void XRAX_H(void)
+{
+ A ^= RM( HL );
+ SET_Z(A);
+}
+
+/* 70 94: 0111 0000 1001 0100 */
+static void XRAX_Dp(void)
+{
+ A ^= RM( DE );
+ DE++;
+ SET_Z(A);
+}
+
+/* 70 95: 0111 0000 1001 0101 */
+static void XRAX_Hp(void)
+{
+ A ^= RM( HL );
+ HL++;
+ SET_Z(A);
+}
+
+/* 70 96: 0111 0000 1001 0110 */
+static void XRAX_Dm(void)
+{
+ A ^= RM( DE );
+ DE--;
+ SET_Z(A);
+}
+
+/* 70 97: 0111 0000 1001 0111 */
+static void XRAX_Hm(void)
+{
+ A ^= RM( HL );
+ HL--;
+ SET_Z(A);
+}
+
+/* 70 99: 0111 0000 1001 1001 */
+static void ORAX_B(void)
+{
+ A |= RM( BC );
+ SET_Z(A);
+}
+
+/* 70 9a: 0111 0000 1001 1010 */
+static void ORAX_D(void)
+{
+ A |= RM( DE );
+ SET_Z(A);
+}
+
+/* 70 9b: 0111 0000 1001 1011 */
+static void ORAX_H(void)
+{
+ A |= RM( HL );
+ SET_Z(A);
+}
+
+/* 70 9c: 0111 0000 1001 0100 */
+static void ORAX_Dp(void)
+{
+ A |= RM( DE );
+ DE++;
+ SET_Z(A);
+}
+
+/* 70 9d: 0111 0000 1001 1101 */
+static void ORAX_Hp(void)
+{
+ A |= RM( HL );
+ HL++;
+ SET_Z(A);
+}
+
+/* 70 9e: 0111 0000 1001 1110 */
+static void ORAX_Dm(void)
+{
+ A |= RM( DE );
+ DE--;
+ SET_Z(A);
+}
+
+/* 70 9f: 0111 0000 1001 1111 */
+static void ORAX_Hm(void)
+{
+ A |= RM( HL );
+ HL--;
+ SET_Z(A);
+}
+
+/* 70 a1: 0111 0000 1010 0001 */
+static void ADDNCX_B(void)
+{
+ UINT8 tmp = A + RM( BC );
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 a2: 0111 0000 1010 0010 */
+static void ADDNCX_D(void)
+{
+ UINT8 tmp = A + RM( DE );
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 a3: 0111 0000 1010 0011 */
+static void ADDNCX_H(void)
+{
+ UINT8 tmp = A + RM( HL );
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 a4: 0111 0000 1010 0100 */
+static void ADDNCX_Dp(void)
+{
+ UINT8 tmp = A + RM( DE );
+ DE++;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 a5: 0111 0000 1010 0101 */
+static void ADDNCX_Hp(void)
+{
+ UINT8 tmp = A + RM( HL );
+ HL++;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 a6: 0111 0000 1010 0110 */
+static void ADDNCX_Dm(void)
+{
+ UINT8 tmp = A + RM( DE );
+ DE--;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 a7: 0111 0000 1010 0111 */
+static void ADDNCX_Hm(void)
+{
+ UINT8 tmp = A + RM( HL );
+ HL--;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 a9: 0111 0000 1010 1001 */
+static void GTAX_B(void)
+{
+ UINT16 tmp = A - RM( BC ) - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 70 aa: 0111 0000 1010 1010 */
+static void GTAX_D(void)
+{
+ UINT16 tmp = A - RM( DE ) - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 70 ab: 0111 0000 1010 1011 */
+static void GTAX_H(void)
+{
+ UINT16 tmp = A - RM( HL ) - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 70 ac: 0111 0000 1010 1100 */
+static void GTAX_Dp(void)
+{
+ UINT16 tmp = A - RM( DE ) - 1;
+ DE++;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 70 ad: 0111 0000 1010 1101 */
+static void GTAX_Hp(void)
+{
+ UINT16 tmp = A - RM( HL ) - 1;
+ HL++;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 70 ae: 0111 0000 1010 1110 */
+static void GTAX_Dm(void)
+{
+ UINT16 tmp = A - RM( DE ) - 1;
+ DE--;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 70 af: 0111 0000 1010 1111 */
+static void GTAX_Hm(void)
+{
+ UINT16 tmp = A - RM( HL ) - 1;
+ HL--;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 70 b1: 0111 0000 1011 0001 */
+static void SUBNBX_B(void)
+{
+ UINT8 tmp = A - RM( BC );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 b2: 0111 0000 1011 0010 */
+static void SUBNBX_D(void)
+{
+ UINT8 tmp = A - RM( DE );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 b3: 0111 0000 1011 0011 */
+static void SUBNBX_H(void)
+{
+ UINT8 tmp = A - RM( HL );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 b4: 0111 0000 1011 0100 */
+static void SUBNBX_Dp(void)
+{
+ UINT8 tmp = A - RM( DE );
+ DE++;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 b5: 0111 0000 1011 0101 */
+static void SUBNBX_Hp(void)
+{
+ UINT8 tmp = A - RM( HL );
+ HL++;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 b6: 0111 0000 1011 0110 */
+static void SUBNBX_Dm(void)
+{
+ UINT8 tmp = A - RM( DE );
+ DE--;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 b7: 0111 0000 1011 0111 */
+static void SUBNBX_Hm(void)
+{
+ UINT8 tmp = A - RM( HL );
+ HL--;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 70 b9: 0111 0000 1011 1001 */
+static void LTAX_B(void)
+{
+ UINT8 tmp = A - RM( BC );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 70 ba: 0111 0000 1011 1010 */
+static void LTAX_D(void)
+{
+ UINT8 tmp = A - RM( DE );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 70 bb: 0111 0000 1011 1011 */
+static void LTAX_H(void)
+{
+ UINT8 tmp = A - RM( HL );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 70 bc: 0111 0000 1011 1100 */
+static void LTAX_Dp(void)
+{
+ UINT8 tmp = A - RM( DE );
+ DE++;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 70 bd: 0111 0000 1011 1101 */
+static void LTAX_Hp(void)
+{
+ UINT8 tmp = A - RM( HL );
+ HL++;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 70 be: 0111 0000 1011 1110 */
+static void LTAX_Dm(void)
+{
+ UINT8 tmp = A - RM( DE );
+ DE--;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 70 bf: 0111 0000 1011 1111 */
+static void LTAX_Hm(void)
+{
+ UINT8 tmp = A - RM( HL );
+ HL--;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 70 c1: 0111 0000 1100 0001 */
+static void ADDX_B(void)
+{
+ UINT8 tmp = A + RM( BC );
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 c2: 0111 0000 1100 0010 */
+static void ADDX_D(void)
+{
+ UINT8 tmp = A + RM( DE );
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 c3: 0111 0000 1100 0011 */
+static void ADDX_H(void)
+{
+ UINT8 tmp = A + RM( HL );
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 c4: 0111 0000 1100 0100 */
+static void ADDX_Dp(void)
+{
+ UINT8 tmp = A + RM( DE );
+ DE++;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 c5: 0111 0000 1100 0101 */
+static void ADDX_Hp(void)
+{
+ UINT8 tmp = A + RM( HL );
+ HL++;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 c6: 0111 0000 1100 0110 */
+static void ADDX_Dm(void)
+{
+ UINT8 tmp = A + RM( DE );
+ DE--;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 c7: 0111 0000 1100 0111 */
+static void ADDX_Hm(void)
+{
+ UINT8 tmp = A + RM( HL );
+ HL--;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 c9: 0111 0000 1100 1001 */
+static void ONAX_B(void)
+{
+ if (A & RM( BC ))
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 70 ca: 0111 0000 1100 1010 */
+static void ONAX_D(void)
+{
+ if (A & RM( DE ))
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 70 cb: 0111 0000 1100 1011 */
+static void ONAX_H(void)
+{
+ if (A & RM( HL ))
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 70 cc: 0111 0000 1100 1100 */
+static void ONAX_Dp(void)
+{
+ if (A & RM( DE ))
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+ DE++;
+}
+
+/* 70 cd: 0111 0000 1100 1101 */
+static void ONAX_Hp(void)
+{
+ if (A & RM( HL ))
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+ HL++;
+}
+
+/* 70 ce: 0111 0000 1100 1110 */
+static void ONAX_Dm(void)
+{
+ if (A & RM( DE ))
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+ DE--;
+}
+
+/* 70 cf: 0111 0000 1100 1111 */
+static void ONAX_Hm(void)
+{
+ if (A & RM( HL ))
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+ HL--;
+}
+
+/* 70 d1: 0111 0000 1101 0001 */
+static void ADCX_B(void)
+{
+ UINT8 tmp = A + RM( BC ) + (PSW & CY);
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 d2: 0111 0000 1101 0010 */
+static void ADCX_D(void)
+{
+ UINT8 tmp = A + RM( DE ) + (PSW & CY);
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 d3: 0111 0000 1101 0011 */
+static void ADCX_H(void)
+{
+ UINT8 tmp = A + RM( HL ) + (PSW & CY);
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 d4: 0111 0000 1101 0100 */
+static void ADCX_Dp(void)
+{
+ UINT8 tmp = A + RM( DE ) + (PSW & CY);
+ DE++;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 d5: 0111 0000 1101 0101 */
+static void ADCX_Hp(void)
+{
+ UINT8 tmp = A + RM( HL ) + (PSW & CY);
+ HL++;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 d6: 0111 0000 1101 0110 */
+static void ADCX_Dm(void)
+{
+ UINT8 tmp = A + RM( DE ) + (PSW & CY);
+ DE--;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 d7: 0111 0000 1101 0111 */
+static void ADCX_Hm(void)
+{
+ UINT8 tmp = A + RM( HL ) + (PSW & CY);
+ HL--;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 d9: 0111 0000 1101 1001 */
+static void OFFAX_B(void)
+{
+ if ( A & RM( BC ) )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 70 da: 0111 0000 1101 1010 */
+static void OFFAX_D(void)
+{
+ if ( A & RM( DE ) )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 70 db: 0111 0000 1101 1011 */
+static void OFFAX_H(void)
+{
+ if ( A & RM( HL ) )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 70 dc: 0111 0000 1101 1100 */
+static void OFFAX_Dp(void)
+{
+ if ( A & RM( DE ) )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+ DE++;
+}
+
+/* 70 dd: 0111 0000 1101 1101 */
+static void OFFAX_Hp(void)
+{
+ if ( A & RM( HL ) )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+ HL++;
+}
+
+/* 70 de: 0111 0000 1101 1110 */
+static void OFFAX_Dm(void)
+{
+ if ( A & RM( DE ) )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+ DE--;
+}
+
+/* 70 df: 0111 0000 1101 1111 */
+static void OFFAX_Hm(void)
+{
+ if ( A & RM( HL ) )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+ HL--;
+}
+
+/* 70 e1: 0111 0000 1110 0001 */
+static void SUBX_B(void)
+{
+ UINT8 tmp = A - RM( BC );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 e2: 0111 0000 1110 0010 */
+static void SUBX_D(void)
+{
+ UINT8 tmp = A - RM( DE );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 e3: 0111 0000 1110 0011 */
+static void SUBX_H(void)
+{
+ UINT8 tmp = A - RM( HL );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 70 e4: 0111 0000 1110 0100 */
+static void SUBX_Dp(void)
+{
+ UINT8 tmp = A - RM( DE );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ DE++;
+}
+
+/* 70 e5: 0111 0000 1110 0101 */
+static void SUBX_Hp(void)
+{
+ UINT8 tmp = A - RM( HL );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ HL++;
+}
+
+/* 70 e6: 0111 0000 1110 0110 */
+static void SUBX_Dm(void)
+{
+ UINT8 tmp = A - RM( DE );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ DE--;
+}
+
+/* 70 e7: 0111 0000 1110 0111 */
+static void SUBX_Hm(void)
+{
+ UINT8 tmp = A - RM( HL );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ HL--;
+}
+
+/* 70 e9: 0111 0000 1110 1001 */
+static void NEAX_B(void)
+{
+ UINT8 tmp = A - RM( BC );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 70 ea: 0111 0000 1110 1010 */
+static void NEAX_D(void)
+{
+ UINT8 tmp = A - RM( DE );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 70 eb: 0111 0000 1110 1011 */
+static void NEAX_H(void)
+{
+ UINT8 tmp = A - RM( HL );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 70 ec: 0111 0000 1110 1100 */
+static void NEAX_Dp(void)
+{
+ UINT8 tmp = A - RM( DE );
+ DE++;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 70 ed: 0111 0000 1110 1101 */
+static void NEAX_Hp(void)
+{
+ UINT8 tmp = A - RM( HL );
+ HL++;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 70 ee: 0111 0000 1110 1110 */
+static void NEAX_Dm(void)
+{
+ UINT8 tmp = A - RM( DE );
+ DE--;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 70 ef: 0111 0000 1110 1111 */
+static void NEAX_Hm(void)
+{
+ UINT8 tmp = A - RM( HL );
+ HL--;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 70 f1: 0111 0000 1111 0001 */
+static void SBBX_B(void)
+{
+ UINT8 tmp = A - RM( BC ) - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 70 f2: 0111 0000 1111 0010 */
+static void SBBX_D(void)
+{
+ UINT8 tmp = A - RM( DE ) - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 70 f3: 0111 0000 1111 0011 */
+static void SBBX_H(void)
+{
+ UINT8 tmp = A - RM( HL ) - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 70 f4: 0111 0000 1111 0100 */
+static void SBBX_Dp(void)
+{
+ UINT8 tmp = A - RM( DE ) - (PSW & CY);
+ DE++;
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 70 f5: 0111 0000 1111 0101 */
+static void SBBX_Hp(void)
+{
+ UINT8 tmp = A - RM( HL ) - (PSW & CY);
+ HL++;
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 70 f6: 0111 0000 1111 0110 */
+static void SBBX_Dm(void)
+{
+ UINT8 tmp = A - RM( DE ) - (PSW & CY);
+ DE--;
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 70 f7: 0111 0000 1111 0111 */
+static void SBBX_Hm(void)
+{
+ UINT8 tmp = A - RM( HL ) - (PSW & CY);
+ HL--;
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 70 f9: 0111 0000 1111 1001 */
+static void EQAX_B(void)
+{
+ UINT8 tmp = A - RM( BC );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 70 fa: 0111 0000 1111 1010 */
+static void EQAX_D(void)
+{
+ UINT8 tmp = A - RM( DE );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 70 fb: 0111 0000 1111 1011 */
+static void EQAX_H(void)
+{
+ UINT8 tmp = A - RM( HL );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 70 fc: 0111 0000 1111 1100 */
+static void EQAX_Dp(void)
+{
+ UINT8 tmp = A - RM( DE );
+ DE++;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 70 fd: 0111 0000 1111 1101 */
+static void EQAX_Hp(void)
+{
+ UINT8 tmp = A - RM( HL );
+ HL++;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 70 fe: 0111 0000 1111 1110 */
+static void EQAX_Dm(void)
+{
+ UINT8 tmp = A - RM( DE );
+ DE--;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 70 ff: 0111 0000 1111 1111 */
+static void EQAX_Hm(void)
+{
+ UINT8 tmp = A - RM( HL );
+ HL--;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* prefix 74 */
+/* 74 08: 0111 0100 0000 1000 xxxx xxxx */
+static void ANI_V_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ V &= imm;
+ SET_Z(V);
+}
+
+/* 74 09: 0111 0100 0000 1001 xxxx xxxx */
+static void ANI_A_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ A &= imm;
+ SET_Z(A);
+}
+
+/* 74 0a: 0111 0100 0000 1010 xxxx xxxx */
+static void ANI_B_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ B &= imm;
+ SET_Z(B);
+}
+
+/* 74 0b: 0111 0100 0000 1011 xxxx xxxx */
+static void ANI_C_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ C &= imm;
+ SET_Z(C);
+}
+
+/* 74 0c: 0111 0100 0000 1100 xxxx xxxx */
+static void ANI_D_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ D &= imm;
+ SET_Z(D);
+}
+
+/* 74 0d: 0111 0100 0000 1101 xxxx xxxx */
+static void ANI_E_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ E &= imm;
+ SET_Z(E);
+}
+
+/* 74 0e: 0111 0100 0000 1110 xxxx xxxx */
+static void ANI_H_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ H &= imm;
+ SET_Z(H);
+}
+
+/* 74 0f: 0111 0100 0000 1111 xxxx xxxx */
+static void ANI_L_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ L &= imm;
+ SET_Z(L);
+}
+
+/* 74 10: 0111 0100 0001 0000 xxxx xxxx */
+static void XRI_V_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ V ^= imm;
+ SET_Z(V);
+}
+
+/* 74 11: 0111 0100 0001 0001 xxxx xxxx */
+static void XRI_A_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ A ^= imm;
+ SET_Z(A);
+}
+
+/* 74 12: 0111 0100 0001 0010 xxxx xxxx */
+static void XRI_B_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ B ^= imm;
+ SET_Z(B);
+}
+
+/* 74 13: 0111 0100 0001 0011 xxxx xxxx */
+static void XRI_C_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ C ^= imm;
+ SET_Z(C);
+}
+
+/* 74 14: 0111 0100 0001 0100 xxxx xxxx */
+static void XRI_D_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ D ^= imm;
+ SET_Z(D);
+}
+
+/* 74 15: 0111 0100 0001 0101 xxxx xxxx */
+static void XRI_E_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ E ^= imm;
+ SET_Z(E);
+}
+
+/* 74 16: 0111 0100 0001 0110 xxxx xxxx */
+static void XRI_H_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ H ^= imm;
+ SET_Z(H);
+}
+
+/* 74 17: 0111 0100 0001 0111 xxxx xxxx */
+static void XRI_L_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ L ^= imm;
+ SET_Z(L);
+}
+
+/* 74 18: 0111 0100 0001 1000 xxxx xxxx */
+static void ORI_V_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ V |= imm;
+ SET_Z(V);
+}
+
+/* 74 19: 0111 0100 0001 1001 xxxx xxxx */
+static void ORI_A_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ A |= imm;
+ SET_Z(A);
+}
+
+/* 74 1a: 0111 0100 0001 1010 xxxx xxxx */
+static void ORI_B_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ B |= imm;
+ SET_Z(B);
+}
+
+/* 74 1b: 0111 0100 0001 1011 xxxx xxxx */
+static void ORI_C_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ C |= imm;
+ SET_Z(C);
+}
+
+/* 74 1c: 0111 0100 0001 1100 xxxx xxxx */
+static void ORI_D_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ D |= imm;
+ SET_Z(D);
+}
+
+/* 74 1d: 0111 0100 0001 1101 xxxx xxxx */
+static void ORI_E_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ E |= imm;
+ SET_Z(E);
+}
+
+/* 74 1e: 0111 0100 0001 1110 xxxx xxxx */
+static void ORI_H_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ H |= imm;
+ SET_Z(H);
+}
+
+/* 74 1f: 0111 0100 0001 1111 xxxx xxxx */
+static void ORI_L_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ L |= imm;
+ SET_Z(L);
+}
+
+/* 74 20: 0111 0100 0010 0000 xxxx xxxx */
+static void ADINC_V_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = V + imm;
+
+ ZHC_ADD( tmp, V, 0 );
+ V = tmp;
+ SKIP_NC;
+}
+
+/* 74 21: 0111 0100 0010 0001 xxxx xxxx */
+static void ADINC_A_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = A + imm;
+
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 74 22: 0111 0100 0010 0010 xxxx xxxx */
+static void ADINC_B_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = B + imm;
+
+ ZHC_ADD( tmp, B, 0 );
+ B = tmp;
+ SKIP_NC;
+}
+
+/* 74 23: 0111 0100 0010 0011 xxxx xxxx */
+static void ADINC_C_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = C + imm;
+
+ ZHC_ADD( tmp, C, 0 );
+ C = tmp;
+ SKIP_NC;
+}
+
+/* 74 24: 0111 0100 0010 0100 xxxx xxxx */
+static void ADINC_D_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = D + imm;
+
+ ZHC_ADD( tmp, D, 0 );
+ D = tmp;
+ SKIP_NC;
+}
+
+/* 74 25: 0111 0100 0010 0101 xxxx xxxx */
+static void ADINC_E_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = E + imm;
+
+ ZHC_ADD( tmp, E, 0 );
+ E = tmp;
+ SKIP_NC;
+}
+
+/* 74 26: 0111 0100 0010 0110 xxxx xxxx */
+static void ADINC_H_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = H + imm;
+
+ ZHC_ADD( tmp, H, 0 );
+ H = tmp;
+ SKIP_NC;
+}
+
+/* 74 27: 0111 0100 0010 0111 xxxx xxxx */
+static void ADINC_L_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = L + imm;
+
+ ZHC_ADD( tmp, L, 0 );
+ L = tmp;
+ SKIP_NC;
+}
+
+/* 74 28: 0111 0100 0010 1000 xxxx xxxx */
+static void GTI_V_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = V - imm - 1;
+ ZHC_SUB( tmp, V, 0 );
+
+ SKIP_NC;
+}
+
+/* 74 29: 0111 0100 0010 1001 xxxx xxxx */
+static void GTI_A_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = A - imm - 1;
+ ZHC_SUB( tmp, A, 0 );
+
+ SKIP_NC;
+}
+
+/* 74 2a: 0111 0100 0010 1010 xxxx xxxx */
+static void GTI_B_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = B - imm - 1;
+ ZHC_SUB( tmp, B, 0 );
+
+ SKIP_NC;
+}
+
+/* 74 2b: 0111 0100 0010 1011 xxxx xxxx */
+static void GTI_C_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = C - imm - 1;
+ ZHC_SUB( tmp, C, 0 );
+
+ SKIP_NC;
+}
+
+/* 74 2c: 0111 0100 0010 1100 xxxx xxxx */
+static void GTI_D_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = D - imm - 1;
+ ZHC_SUB( tmp, D, 0 );
+
+ SKIP_NC;
+}
+
+/* 74 2d: 0111 0100 0010 1101 xxxx xxxx */
+static void GTI_E_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = E - imm - 1;
+ ZHC_SUB( tmp, E, 0 );
+
+ SKIP_NC;
+}
+
+/* 74 2e: 0111 0100 0010 1110 xxxx xxxx */
+static void GTI_H_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = H - imm - 1;
+ ZHC_SUB( tmp, H, 0 );
+
+ SKIP_NC;
+}
+
+/* 74 2f: 0111 0100 0010 1111 xxxx xxxx */
+static void GTI_L_xx(void)
+{
+ UINT8 imm;
+ UINT16 tmp;
+
+ RDOPARG( imm );
+ tmp = L - imm - 1;
+ ZHC_SUB( tmp, L, 0 );
+
+ SKIP_NC;
+}
+
+/* 74 30: 0111 0100 0011 0000 xxxx xxxx */
+static void SUINB_V_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = V - imm;
+ ZHC_SUB( tmp, V, 0 );
+ V = tmp;
+ SKIP_NC;
+}
+
+/* 74 31: 0111 0100 0011 0001 xxxx xxxx */
+static void SUINB_A_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = A - imm;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 74 32: 0111 0100 0011 0010 xxxx xxxx */
+static void SUINB_B_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = B - imm;
+ ZHC_SUB( tmp, B, 0 );
+ B = tmp;
+ SKIP_NC;
+}
+
+/* 74 33: 0111 0100 0011 0011 xxxx xxxx */
+static void SUINB_C_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = C - imm;
+ ZHC_SUB( tmp, C, 0 );
+ C = tmp;
+ SKIP_NC;
+}
+
+/* 74 34: 0111 0100 0011 0100 xxxx xxxx */
+static void SUINB_D_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = D - imm;
+ ZHC_SUB( tmp, D, 0 );
+ D = tmp;
+ SKIP_NC;
+}
+
+/* 74 35: 0111 0100 0011 0101 xxxx xxxx */
+static void SUINB_E_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = E - imm;
+ ZHC_SUB( tmp, E, 0 );
+ E = tmp;
+ SKIP_NC;
+}
+
+/* 74 36: 0111 0100 0011 0110 xxxx xxxx */
+static void SUINB_H_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = H - imm;
+ ZHC_SUB( tmp, H, 0 );
+ H = tmp;
+ SKIP_NC;
+}
+
+/* 74 37: 0111 0100 0011 0111 xxxx xxxx */
+static void SUINB_L_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = L - imm;
+ ZHC_SUB( tmp, L, 0 );
+ L = tmp;
+ SKIP_NC;
+}
+
+/* 74 38: 0111 0100 0011 1000 xxxx xxxx */
+static void LTI_V_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = V - imm;
+ ZHC_SUB( tmp, V, 0 );
+ SKIP_CY;
+}
+
+/* 74 39: 0111 0100 0011 1001 xxxx xxxx */
+static void LTI_A_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = A - imm;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 74 3a: 0111 0100 0011 1010 xxxx xxxx */
+static void LTI_B_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = B - imm;
+ ZHC_SUB( tmp, B, 0 );
+ SKIP_CY;
+}
+
+/* 74 3b: 0111 0100 0011 1011 xxxx xxxx */
+static void LTI_C_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = C - imm;
+ ZHC_SUB( tmp, C, 0 );
+ SKIP_CY;
+}
+
+/* 74 3c: 0111 0100 0011 1100 xxxx xxxx */
+static void LTI_D_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = D - imm;
+ ZHC_SUB( tmp, D, 0 );
+ SKIP_CY;
+}
+
+/* 74 3d: 0111 0100 0011 1101 xxxx xxxx */
+static void LTI_E_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = E - imm;
+ ZHC_SUB( tmp, E, 0 );
+ SKIP_CY;
+}
+
+/* 74 3e: 0111 0100 0011 1110 xxxx xxxx */
+static void LTI_H_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = H - imm;
+ ZHC_SUB( tmp, H, 0 );
+ SKIP_CY;
+}
+
+/* 74 3f: 0111 0100 0011 1111 xxxx xxxx */
+static void LTI_L_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = L - imm;
+ ZHC_SUB( tmp, L, 0 );
+ SKIP_CY;
+}
+
+/* 74 40: 0111 0100 0100 0000 xxxx xxxx */
+static void ADI_V_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = V + imm;
+
+ ZHC_ADD( tmp, V, 0 );
+ V = tmp;
+}
+
+/* 74 41: 0111 0100 0100 0001 xxxx xxxx */
+static void ADI_A_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = A + imm;
+
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 74 42: 0111 0100 0100 0010 xxxx xxxx */
+static void ADI_B_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = B + imm;
+
+ ZHC_ADD( tmp, B, 0 );
+ B = tmp;
+}
+
+/* 74 43: 0111 0100 0100 0011 xxxx xxxx */
+static void ADI_C_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = C + imm;
+
+ ZHC_ADD( tmp, C, 0 );
+ C = tmp;
+}
+
+/* 74 44: 0111 0100 0100 0100 xxxx xxxx */
+static void ADI_D_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = D + imm;
+
+ ZHC_ADD( tmp, D, 0 );
+ D = tmp;
+}
+
+/* 74 45: 0111 0100 0100 0101 xxxx xxxx */
+static void ADI_E_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = E + imm;
+
+ ZHC_ADD( tmp, E, 0 );
+ E = tmp;
+}
+
+/* 74 46: 0111 0100 0100 0110 xxxx xxxx */
+static void ADI_H_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = H + imm;
+
+ ZHC_ADD( tmp, H, 0 );
+ H = tmp;
+}
+
+/* 74 47: 0111 0100 0100 0111 xxxx xxxx */
+static void ADI_L_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = L + imm;
+
+ ZHC_ADD( tmp, L, 0 );
+ L = tmp;
+}
+
+/* 74 48: 0111 0100 0100 1000 xxxx xxxx */
+static void ONI_V_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (V & imm)
+ PSW |= SK;
+}
+
+/* 74 49: 0111 0100 0100 1001 xxxx xxxx */
+static void ONI_A_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (A & imm)
+ PSW |= SK;
+}
+
+/* 74 4a: 0111 0100 0100 1010 xxxx xxxx */
+static void ONI_B_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (B & imm)
+ PSW |= SK;
+}
+
+/* 74 4b: 0111 0100 0100 1011 xxxx xxxx */
+static void ONI_C_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (C & imm)
+ PSW |= SK;
+}
+
+/* 74 4c: 0111 0100 0100 1100 xxxx xxxx */
+static void ONI_D_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (D & imm)
+ PSW |= SK;
+}
+
+/* 74 4d: 0111 0100 0100 1101 xxxx xxxx */
+static void ONI_E_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (E & imm)
+ PSW |= SK;
+}
+
+/* 74 4e: 0111 0100 0100 1110 xxxx xxxx */
+static void ONI_H_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (H & imm)
+ PSW |= SK;
+}
+
+/* 74 4f: 0111 0100 0100 1111 xxxx xxxx */
+static void ONI_L_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (L & imm)
+ PSW |= SK;
+}
+
+/* 74 50: 0111 0100 0101 0000 xxxx xxxx */
+static void ACI_V_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = V + imm + (PSW & CY);
+ ZHC_SUB( tmp, V, (PSW & CY) );
+ V = tmp;
+}
+
+/* 74 51: 0111 0100 0101 0001 xxxx xxxx */
+static void ACI_A_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = A + imm + (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 74 52: 0111 0100 0101 0010 xxxx xxxx */
+static void ACI_B_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = B + imm + (PSW & CY);
+ ZHC_SUB( tmp, B, (PSW & CY) );
+ B = tmp;
+}
+
+/* 74 53: 0111 0100 0101 0011 xxxx xxxx */
+static void ACI_C_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = C + imm + (PSW & CY);
+ ZHC_SUB( tmp, C, (PSW & CY) );
+ C = tmp;
+}
+
+/* 74 54: 0111 0100 0101 0100 xxxx xxxx */
+static void ACI_D_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = D + imm + (PSW & CY);
+ ZHC_SUB( tmp, D, (PSW & CY) );
+ D = tmp;
+}
+
+/* 74 55: 0111 0100 0101 0101 xxxx xxxx */
+static void ACI_E_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = E + imm + (PSW & CY);
+ ZHC_SUB( tmp, E, (PSW & CY) );
+ E = tmp;
+}
+
+/* 74 56: 0111 0100 0101 0110 xxxx xxxx */
+static void ACI_H_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = H + imm + (PSW & CY);
+ ZHC_SUB( tmp, H, (PSW & CY) );
+ H = tmp;
+}
+
+/* 74 57: 0111 0100 0101 0111 xxxx xxxx */
+static void ACI_L_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = L + imm + (PSW & CY);
+ ZHC_SUB( tmp, L, (PSW & CY) );
+ L = tmp;
+}
+
+/* 74 58: 0111 0100 0101 1000 xxxx xxxx */
+static void OFFI_V_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (V & imm))
+ PSW |= SK;
+}
+
+/* 74 59: 0111 0100 0101 1001 xxxx xxxx */
+static void OFFI_A_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (A & imm))
+ PSW |= SK;
+}
+
+/* 74 5a: 0111 0100 0101 1010 xxxx xxxx */
+static void OFFI_B_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (B & imm))
+ PSW |= SK;
+}
+
+/* 74 5b: 0111 0100 0101 1011 xxxx xxxx */
+static void OFFI_C_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (C & imm))
+ PSW |= SK;
+}
+
+/* 74 5c: 0111 0100 0101 1100 xxxx xxxx */
+static void OFFI_D_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (D & imm))
+ PSW |= SK;
+}
+
+/* 74 5d: 0111 0100 0101 1101 xxxx xxxx */
+static void OFFI_E_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (E & imm))
+ PSW |= SK;
+}
+
+/* 74 5e: 0111 0100 0101 1110 xxxx xxxx */
+static void OFFI_H_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (H & imm))
+ PSW |= SK;
+}
+
+/* 74 5f: 0111 0100 0101 1111 xxxx xxxx */
+static void OFFI_L_xx(void)
+{
+ UINT8 imm;
+
+ RDOPARG( imm );
+ if (0 == (L & imm))
+ PSW |= SK;
+}
+
+/* 74 60: 0111 0100 0110 0000 xxxx xxxx */
+static void SUI_V_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = V - imm;
+ ZHC_SUB( tmp, V, 0 );
+ V = tmp;
+}
+
+/* 74 61: 0111 0100 0110 0001 xxxx xxxx */
+static void SUI_A_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = A - imm;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 74 62: 0111 0100 0110 0010 xxxx xxxx */
+static void SUI_B_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = B - imm;
+ ZHC_SUB( tmp, B, 0 );
+ B = tmp;
+}
+
+/* 74 63: 0111 0100 0110 0011 xxxx xxxx */
+static void SUI_C_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = C - imm;
+ ZHC_SUB( tmp, C, 0 );
+ C = tmp;
+}
+
+/* 74 64: 0111 0100 0110 0100 xxxx xxxx */
+static void SUI_D_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = D - imm;
+ ZHC_SUB( tmp, D, 0 );
+ D = tmp;
+}
+
+/* 74 65: 0111 0100 0110 0101 xxxx xxxx */
+static void SUI_E_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = E - imm;
+ ZHC_SUB( tmp, E, 0 );
+ E = tmp;
+}
+
+/* 74 66: 0111 0100 0110 0110 xxxx xxxx */
+static void SUI_H_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = H - imm;
+ ZHC_SUB( tmp, H, 0 );
+ H = tmp;
+}
+
+/* 74 67: 0111 0100 0110 0111 xxxx xxxx */
+static void SUI_L_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = L - imm;
+ ZHC_SUB( tmp, L, 0 );
+ L = tmp;
+}
+
+/* 74 68: 0111 0100 0110 1000 xxxx xxxx */
+static void NEI_V_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = V - imm;
+ ZHC_SUB( tmp, V, 0 );
+ SKIP_NZ;
+}
+
+/* 74 69: 0111 0100 0110 1001 xxxx xxxx */
+static void NEI_A_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = A - imm;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 74 6a: 0111 0100 0110 1010 xxxx xxxx */
+static void NEI_B_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = B - imm;
+ ZHC_SUB( tmp, B, 0 );
+ SKIP_NZ;
+}
+
+/* 74 6b: 0111 0100 0110 1011 xxxx xxxx */
+static void NEI_C_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = C - imm;
+ ZHC_SUB( tmp, C, 0 );
+ SKIP_NZ;
+}
+
+/* 74 6c: 0111 0100 0110 1100 xxxx xxxx */
+static void NEI_D_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = D - imm;
+ ZHC_SUB( tmp, D, 0 );
+ SKIP_NZ;
+}
+
+/* 74 6d: 0111 0100 0110 1101 xxxx xxxx */
+static void NEI_E_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = E - imm;
+ ZHC_SUB( tmp, E, 0 );
+ SKIP_NZ;
+}
+
+/* 74 6e: 0111 0100 0110 1110 xxxx xxxx */
+static void NEI_H_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = H - imm;
+ ZHC_SUB( tmp, H, 0 );
+ SKIP_NZ;
+}
+
+/* 74 6f: 0111 0100 0110 1111 xxxx xxxx */
+static void NEI_L_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = L - imm;
+ ZHC_SUB( tmp, L, 0 );
+ SKIP_NZ;
+}
+
+/* 74 70: 0111 0100 0111 0000 xxxx xxxx */
+static void SBI_V_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = V - imm - (PSW & CY);
+ ZHC_SUB( tmp, V, (PSW & CY) );
+ V = tmp;
+}
+
+/* 74 71: 0111 0100 0111 0001 xxxx xxxx */
+static void SBI_A_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = A - imm - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 74 72: 0111 0100 0111 0010 xxxx xxxx */
+static void SBI_B_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = B - imm - (PSW & CY);
+ ZHC_SUB( tmp, B, (PSW & CY) );
+ B = tmp;
+}
+
+/* 74 73: 0111 0100 0111 0011 xxxx xxxx */
+static void SBI_C_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = C - imm - (PSW & CY);
+ ZHC_SUB( tmp, C, (PSW & CY) );
+ C = tmp;
+}
+
+/* 74 74: 0111 0100 0111 0100 xxxx xxxx */
+static void SBI_D_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = D - imm - (PSW & CY);
+ ZHC_SUB( tmp, D, (PSW & CY) );
+ D = tmp;
+}
+
+/* 74 75: 0111 0100 0111 0101 xxxx xxxx */
+static void SBI_E_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = E - imm - (PSW & CY);
+ ZHC_SUB( tmp, E, (PSW & CY) );
+ E = tmp;
+}
+
+/* 74 76: 0111 0100 0111 0110 xxxx xxxx */
+static void SBI_H_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = H - imm - (PSW & CY);
+ ZHC_SUB( tmp, H, (PSW & CY) );
+ H = tmp;
+}
+
+/* 74 77: 0111 0100 0111 0111 xxxx xxxx */
+static void SBI_L_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = L - imm - (PSW & CY);
+ ZHC_SUB( tmp, L, (PSW & CY) );
+ L = tmp;
+}
+
+/* 74 78: 0111 0100 0111 1000 xxxx xxxx */
+static void EQI_V_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = V - imm;
+ ZHC_SUB( tmp, V, 0 );
+ SKIP_Z;
+}
+
+/* 74 79: 0111 0100 0111 1001 xxxx xxxx */
+static void EQI_A_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = A - imm;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 74 7a: 0111 0100 0111 1010 xxxx xxxx */
+static void EQI_B_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = B - imm;
+ ZHC_SUB( tmp, B, 0 );
+ SKIP_Z;
+}
+
+/* 74 7b: 0111 0100 0111 1011 xxxx xxxx */
+static void EQI_C_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = C - imm;
+ ZHC_SUB( tmp, C, 0 );
+ SKIP_Z;
+}
+
+/* 74 7c: 0111 0100 0111 1100 xxxx xxxx */
+static void EQI_D_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = D - imm;
+ ZHC_SUB( tmp, D, 0 );
+ SKIP_Z;
+}
+
+/* 74 7d: 0111 0100 0111 1101 xxxx xxxx */
+static void EQI_E_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = E - imm;
+ ZHC_SUB( tmp, E, 0 );
+ SKIP_Z;
+}
+
+/* 74 7e: 0111 0100 0111 1110 xxxx xxxx */
+static void EQI_H_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = H - imm;
+ ZHC_SUB( tmp, H, 0 );
+ SKIP_Z;
+}
+
+/* 74 7f: 0111 0100 0111 1111 xxxx xxxx */
+static void EQI_L_xx(void)
+{
+ UINT8 tmp, imm;
+
+ RDOPARG( imm );
+ tmp = L - imm;
+ ZHC_SUB( tmp, L, 0 );
+ SKIP_Z;
+}
+
+/* 74 88: 0111 0100 1000 1000 oooo oooo */
+static void ANAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ RDOPARG( ea.b.l );
+
+ A &= RM( ea.d );
+ SET_Z(A);
+}
+
+/* 74 8d: 0111 0100 1000 1101 */
+static void DAN_EA_BC(void)
+{
+ EA &= BC;
+ SET_Z(EA);
+}
+
+/* 74 8e: 0111 0100 1000 1110 */
+static void DAN_EA_DE(void)
+{
+ EA &= DE;
+ SET_Z(EA);
+}
+
+/* 74 8f: 0111 0100 1000 1111 */
+static void DAN_EA_HL(void)
+{
+ EA &= HL;
+ SET_Z(EA);
+}
+
+/* 74 90: 0111 0100 1001 0000 oooo oooo */
+static void XRAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ RDOPARG( ea.b.l );
+
+ A ^= RM( ea.d );
+ SET_Z(A);
+}
+
+/* 74 95: 0111 0100 1001 0101 */
+static void DXR_EA_BC(void)
+{
+ EA ^= BC;
+ SET_Z(EA);
+}
+
+/* 74 96: 0111 0100 1001 0110 */
+static void DXR_EA_DE(void)
+{
+ EA ^= DE;
+ SET_Z(EA);
+}
+
+/* 74 97: 0111 0100 1001 0111 */
+static void DXR_EA_HL(void)
+{
+ EA ^= HL;
+ SET_Z(EA);
+}
+
+/* 74 98: 0111 0100 1001 1000 oooo oooo */
+static void ORAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ RDOPARG( ea.b.l );
+
+ A |= RM( ea.d );
+ SET_Z(A);
+}
+
+/* 74 9d: 0111 0100 1001 1101 */
+static void DOR_EA_BC(void)
+{
+ EA |= BC;
+ SET_Z(EA);
+}
+
+/* 74 9e: 0111 0100 1001 1110 */
+static void DOR_EA_DE(void)
+{
+ EA |= DE;
+ SET_Z(EA);
+}
+
+/* 74 9f: 0111 0100 1001 1111 */
+static void DOR_EA_HL(void)
+{
+ EA |= HL;
+ SET_Z(EA);
+}
+
+/* 74 a0: 0111 0100 1010 0000 oooo oooo */
+static void ADDNCW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp;
+
+ RDOPARG( ea.b.l );
+
+ tmp = A + RM( ea.d );
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 74 a5: 0111 0100 1010 0101 */
+static void DADDNC_EA_BC(void)
+{
+ UINT16 tmp = EA + BC;
+
+ ZHC_ADD( tmp, EA, 0 );
+ EA = tmp;
+ SKIP_NC;
+}
+
+/* 74 a6: 0111 0100 1010 0110 */
+static void DADDNC_EA_DE(void)
+{
+ UINT16 tmp = EA + DE;
+
+ ZHC_ADD( tmp, EA, 0 );
+ EA = tmp;
+ SKIP_NC;
+}
+
+/* 74 a7: 0111 0100 1010 0111 */
+static void DADDNC_EA_HL(void)
+{
+ UINT16 tmp = EA + HL;
+
+ ZHC_ADD( tmp, EA, 0 );
+ EA = tmp;
+ SKIP_NC;
+}
+
+/* 74 a8: 0111 0100 1010 1000 oooo oooo */
+static void GTAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT16 tmp;
+
+ RDOPARG( ea.b.l );
+ tmp = A - RM( ea.d ) - 1;
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NC;
+}
+
+/* 74 ad: 0111 0100 1010 1101 */
+static void DGT_EA_BC(void)
+{
+ UINT32 tmp = EA - BC - 1;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_NC;
+}
+
+/* 74 ae: 0111 0100 1010 1110 */
+static void DGT_EA_DE(void)
+{
+ UINT32 tmp = EA - DE - 1;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_NC;
+}
+
+/* 74 af: 0111 0100 1010 1111 */
+static void DGT_EA_HL(void)
+{
+ UINT32 tmp = EA - HL - 1;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_NC;
+}
+
+/* 74 b0: 0111 0100 1011 0000 oooo oooo */
+static void SUBNBW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp;
+
+ RDOPARG( ea.b.l );
+ tmp = A - RM( ea.d );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_NC;
+}
+
+/* 74 b5: 0111 0100 1011 0101 */
+static void DSUBNB_EA_BC(void)
+{
+ UINT16 tmp = EA - BC;
+ ZHC_SUB( tmp, EA, 0 );
+ EA = tmp;
+ SKIP_NC;
+}
+
+/* 74 b6: 0111 0100 1011 0110 */
+static void DSUBNB_EA_DE(void)
+{
+ UINT16 tmp = EA - DE;
+ ZHC_SUB( tmp, EA, 0 );
+ EA = tmp;
+ SKIP_NC;
+}
+
+/* 74 b7: 0111 0100 1011 0111 */
+static void DSUBNB_EA_HL(void)
+{
+ UINT16 tmp;
+
+ tmp = EA - HL;
+ ZHC_SUB( tmp, EA, 0 );
+ EA = tmp;
+ SKIP_NC;
+}
+
+/* 74 b8: 0111 0100 1011 1000 oooo oooo */
+static void LTAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp;
+
+ RDOPARG( ea.b.l );
+ tmp = A - RM( ea.d );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_CY;
+}
+
+/* 74 bd: 0111 0100 1011 1101 */
+static void DLT_EA_BC(void)
+{
+ UINT16 tmp = EA - BC;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_CY;
+}
+
+/* 74 be: 0111 0100 1011 1110 */
+static void DLT_EA_DE(void)
+{
+ UINT16 tmp = EA - DE;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_CY;
+}
+
+/* 74 bf: 0111 0100 1011 1111 */
+static void DLT_EA_HL(void)
+{
+ UINT16 tmp = EA - HL;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_CY;
+}
+
+/* 74 c0: 0111 0100 1100 0000 oooo oooo */
+static void ADDW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp;
+ RDOPARG( ea.b.l );
+ tmp = A + RM( ea.d );
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 74 c5: 0111 0100 1100 0101 */
+static void DADD_EA_BC(void)
+{
+ UINT16 tmp = EA + BC;
+ ZHC_ADD( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 74 c6: 0111 0100 1100 0110 */
+static void DADD_EA_DE(void)
+{
+ UINT16 tmp = EA + DE;
+ ZHC_ADD( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 74 c7: 0111 0100 1100 0111 */
+static void DADD_EA_HL(void)
+{
+ UINT16 tmp = EA + HL;
+ ZHC_ADD( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 74 c8: 0111 0100 1100 1000 oooo oooo */
+static void ONAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ RDOPARG( ea.b.l );
+
+ if (A & RM( ea.d ))
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 74 cd: 0111 0100 1100 1101 */
+static void DON_EA_BC(void)
+{
+ if (EA & BC)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 74 ce: 0111 0100 1100 1110 */
+static void DON_EA_DE(void)
+{
+ if (EA & DE)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 74 cf: 0111 0100 1100 1111 */
+static void DON_EA_HL(void)
+{
+ if (EA & HL)
+ PSW = (PSW & ~Z) | SK;
+ else
+ PSW |= Z;
+}
+
+/* 74 d0: 0111 0100 1101 0000 oooo oooo */
+static void ADCW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp;
+
+ RDOPARG( ea.b.l );
+ tmp = A + RM( ea.d ) + (PSW & CY);
+ ZHC_ADD( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 74 d5: 0111 0100 1101 0101 */
+static void DADC_EA_BC(void)
+{
+ UINT16 tmp = EA + BC + (PSW & CY);
+ ZHC_ADD( tmp, EA, (PSW & CY) );
+ EA = tmp;
+}
+
+/* 74 d6: 0111 0100 1101 0110 */
+static void DADC_EA_DE(void)
+{
+ UINT16 tmp = EA + DE + (PSW & CY);
+ ZHC_ADD( tmp, EA, (PSW & CY) );
+ EA = tmp;
+}
+
+/* 74 d7: 0111 0100 1101 0111 */
+static void DADC_EA_HL(void)
+{
+ UINT16 tmp = EA + HL + (PSW & CY);
+ ZHC_ADD( tmp, EA, (PSW & CY) );
+ EA = tmp;
+}
+
+/* 74 d8: 0111 0100 1101 1000 oooo oooo */
+static void OFFAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ RDOPARG( ea.b.l );
+
+ if ( A & RM( ea.d ) )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 74 dd: 0111 0100 1101 1101 */
+static void DOFF_EA_BC(void)
+{
+ if ( EA & BC )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 74 de: 0111 0100 1101 1110 */
+static void DOFF_EA_DE(void)
+{
+ if ( EA & DE )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 74 df: 0111 0100 1101 1111 */
+static void DOFF_EA_HL(void)
+{
+ if ( EA & HL )
+ PSW &= ~Z;
+ else
+ PSW = PSW | Z | SK;
+}
+
+/* 74 e0: 0111 0100 1110 0000 oooo oooo */
+static void SUBW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp;
+
+ RDOPARG( ea.b.l );
+ tmp = A - RM( ea.d );
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+}
+
+/* 74 e5: 0111 0100 1110 0101 */
+static void DSUB_EA_BC(void)
+{
+ UINT16 tmp = EA - BC;
+ ZHC_SUB( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 74 e6: 0111 0100 1110 0110 */
+static void DSUB_EA_DE(void)
+{
+ UINT16 tmp = EA - DE;
+ ZHC_SUB( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 74 e7: 0111 0100 1110 0111 */
+static void DSUB_EA_HL(void)
+{
+ UINT16 tmp = EA - HL;
+ ZHC_SUB( tmp, EA, 0 );
+ EA = tmp;
+}
+
+/* 74 e8: 0111 0100 1110 1000 oooo oooo */
+static void NEAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp;
+
+ RDOPARG( ea.b.l );
+ tmp = A - RM( ea.d );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_NZ;
+}
+
+/* 74 ed: 0111 0100 1110 1101 */
+static void DNE_EA_BC(void)
+{
+ UINT16 tmp;
+
+ tmp = EA - BC;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_NZ;
+}
+
+/* 74 ee: 0111 0100 1110 1110 */
+static void DNE_EA_DE(void)
+{
+ UINT16 tmp;
+
+ tmp = EA - DE;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_NZ;
+}
+
+/* 74 ef: 0111 0100 1110 1111 */
+static void DNE_EA_HL(void)
+{
+ UINT16 tmp;
+
+ tmp = EA - HL;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_NZ;
+}
+
+/* 74 f0: 0111 0100 1111 0000 oooo oooo */
+static void SBBW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp;
+
+ RDOPARG( ea.b.l );
+ tmp = A - RM( ea.d ) - (PSW & CY);
+ ZHC_SUB( tmp, A, (PSW & CY) );
+ A = tmp;
+}
+
+/* 74 f5: 0111 0100 1111 0101 */
+static void DSBB_EA_BC(void)
+{
+ UINT16 tmp = EA - BC - (PSW & CY);
+ ZHC_SUB( tmp, EA, (PSW & CY) );
+ EA = tmp;
+}
+
+/* 74 f6: 0111 0100 1111 0110 */
+static void DSBB_EA_DE(void)
+{
+ UINT16 tmp = EA - DE - (PSW & CY);
+ ZHC_SUB( tmp, EA, (PSW & CY) );
+ EA = tmp;
+}
+
+/* 74 f7: 0111 0100 1111 0111 */
+static void DSBB_EA_HL(void)
+{
+ UINT16 tmp = EA - HL - (PSW & CY);
+ ZHC_SUB( tmp, EA, (PSW & CY) );
+ EA = tmp;
+}
+
+/* 74 f8: 0111 0100 1111 1000 oooo oooo */
+static void EQAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp;
+
+ RDOPARG( ea.b.l );
+ tmp = A - RM( ea.d );
+ ZHC_SUB( tmp, A, 0 );
+ SKIP_Z;
+}
+
+/* 74 fd: 0111 0100 1111 1101 */
+static void DEQ_EA_BC(void)
+{
+ UINT16 tmp;
+
+ tmp = EA - BC;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_Z;
+}
+
+/* 74 fe: 0111 0100 1111 1110 */
+static void DEQ_EA_DE(void)
+{
+ UINT16 tmp;
+
+ tmp = EA - DE;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_Z;
+}
+
+/* 74 ff: 0111 0100 1111 1111 */
+static void DEQ_EA_HL(void)
+{
+ UINT16 tmp;
+
+ tmp = EA - HL;
+ ZHC_SUB( tmp, EA, 0 );
+ SKIP_Z;
+}
+
+/************************************************
+ * main opcodes
+ ************************************************/
+
+/* 00: 0000 0000 */
+static void NOP(void)
+{
+}
+
+/* 01: 0000 0001 oooo oooo */
+static void LDAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ A = RM( ea.d );
+}
+
+/* 02: 0000 0010 */
+static void INX_SP(void)
+{
+ SP++;
+}
+
+/* 03: 0000 0011 */
+static void DCX_SP(void)
+{
+ SP--;
+}
+
+/* 04: 0000 0100 llll llll hhhh hhhh */
+static void LXI_S_w(void)
+{
+ RDOPARG( SPL );
+ RDOPARG( SPH );
+}
+
+/* 05: 0000 0101 oooo oooo xxxx xxxx */
+static void ANIW_wa_xx(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 m, imm;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( imm );
+ m = RM( ea.d );
+ m &= imm;
+ WM( ea.d, m );
+ SET_Z(m);
+}
+
+/* 07: 0000 0111 xxxx xxxx */
+/* ANI_A_xx already defined (long form) */
+
+/* 08: 0000 1000 */
+static void MOV_A_EAH(void)
+{
+ A = EAH;
+}
+
+/* 09: 0000 1001 */
+static void MOV_A_EAL(void)
+{
+ A = EAL;
+}
+
+/* 0a: 0000 1010 */
+static void MOV_A_B(void)
+{
+ A = B;
+}
+
+/* 0b: 0000 1011 */
+static void MOV_A_C(void)
+{
+ A = C;
+}
+
+/* 0c: 0000 1100 */
+static void MOV_A_D(void)
+{
+ A = D;
+}
+
+/* 0d: 0000 1101 */
+static void MOV_A_E(void)
+{
+ A = E;
+}
+
+/* 0e: 0000 1110 */
+static void MOV_A_H(void)
+{
+ A = H;
+}
+
+/* 0f: 0000 1111 */
+static void MOV_A_L(void)
+{
+ A = L;
+}
+
+/* 10: 0001 0000 */
+static void EXA(void)
+{
+ UINT16 tmp;
+ tmp = EA; EA = EA2; EA2 = tmp;
+ tmp = VA; VA = VA2; VA2 = tmp;
+}
+
+/* 11: 0001 0001 */
+static void EXX(void)
+{
+ UINT16 tmp;
+ tmp = BC; BC = BC2; BC2 = tmp;
+ tmp = DE; DE = DE2; DE2 = tmp;
+ tmp = HL; HL = HL2; HL2 = tmp;
+}
+
+/* 48 AD (7807 only) */
+static void EXR(void)
+{
+ UINT16 tmp;
+ tmp = BC; BC = BC2; BC2 = tmp;
+ tmp = DE; DE = DE2; DE2 = tmp;
+ tmp = HL; HL = HL2; HL2 = tmp;
+ tmp = EA; EA = EA2; EA2 = tmp;
+ tmp = VA; VA = VA2; VA2 = tmp;
+}
+
+/* 12: 0001 0010 */
+static void INX_BC(void)
+{
+ BC++;
+}
+
+/* 13: 0001 0011 */
+static void DCX_BC(void)
+{
+ BC--;
+}
+
+/* 14: 0001 0100 llll llll hhhh hhhh */
+static void LXI_B_w(void)
+{
+ RDOPARG( C );
+ RDOPARG( B );
+}
+
+/* 15: 0001 0101 oooo oooo xxxx xxxx */
+static void ORIW_wa_xx(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 m, imm;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( imm );
+ m = RM( ea.d );
+ m |= imm;
+ WM( ea.d, m );
+ SET_Z(m);
+}
+
+/* 16: 0001 0110 xxxx xxxx */
+/* XRI_A_xx already defined (long form) */
+
+/* 17: 0001 0111 xxxx xxxx */
+/* ORI_A_xx already defined (long form) */
+
+/* 18: 0001 1000 */
+static void MOV_EAH_A(void)
+{
+ EAH = A;
+}
+
+/* 19: 0001 1001 */
+static void MOV_EAL_A(void)
+{
+ EAL = A;
+}
+
+/* 1a: 0001 1010 */
+static void MOV_B_A(void)
+{
+ B = A;
+}
+
+/* 1b: 0001 1011 */
+static void MOV_C_A(void)
+{
+ C = A;
+}
+
+/* 1c: 0001 1100 */
+static void MOV_D_A(void)
+{
+ D = A;
+}
+
+/* 1d: 0001 1101 */
+static void MOV_E_A(void)
+{
+ E = A;
+}
+
+/* 1e: 0001 1110 */
+static void MOV_H_A(void)
+{
+ H = A;
+}
+
+/* 1f: 0001 1111 */
+static void MOV_L_A(void)
+{
+ L = A;
+}
+
+/* 20: 0010 0000 oooo oooo */
+static void INRW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp, m;
+
+ RDOPARG( ea.b.l );
+ m = RM( ea.d );
+ tmp = m + 1;
+ ZHC_ADD( tmp, m, 0 );
+ WM( ea.d, tmp );
+ SKIP_CY;
+}
+
+/* 21: 0010 0001 */
+static void JB(void)
+{
+ PC = BC;
+ change_pc( PCD );
+}
+
+/* 22: 0010 0010 */
+static void INX_DE(void)
+{
+ DE++;
+}
+
+/* 23: 0010 0011 */
+static void DCX_DE(void)
+{
+ DE--;
+}
+
+/* 24: 0010 0100 llll llll hhhh hhhh */
+static void LXI_D_w(void)
+{
+ RDOPARG( E );
+ RDOPARG( D );
+}
+
+/* 25: 0010 0101 oooo oooo xxxx xxxx */
+static void GTIW_wa_xx(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 m, imm;
+ UINT16 tmp;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( imm );
+ m = RM( ea.d );
+ tmp = m - imm - 1;
+ ZHC_SUB( tmp, m, 0 );
+ SKIP_NC;
+}
+
+/* 26: 0010 0110 xxxx xxxx */
+/* ADINC_A_xx already defined (long form) */
+
+/* 27: 0010 0111 xxxx xxxx */
+/* GTI_A_xx already defined (long form) */
+
+/* 29: 0010 1001 */
+static void LDAX_B(void)
+{
+ A = RM( BC );
+}
+
+/* 2a: 0010 1010 */
+static void LDAX_D(void)
+{
+ A = RM( DE );
+}
+
+/* 2b: 0010 1011 */
+static void LDAX_H(void)
+{
+ A = RM( HL );
+}
+
+/* 2c: 0010 1100 */
+static void LDAX_Dp(void)
+{
+ A = RM( DE );
+ DE++;
+}
+
+/* 2d: 0010 1101 dddd dddd */
+static void LDAX_Hp(void)
+{
+ A = RM( HL );
+ HL++;
+}
+
+/* 2e: 0010 1110 dddd dddd */
+static void LDAX_Dm(void)
+{
+ A = RM( DE );
+ DE--;
+}
+
+/* 2f: 0010 1111 dddd dddd */
+static void LDAX_Hm(void)
+{
+ A = RM( HL );
+ HL--;
+}
+
+/* 30: 0011 0000 oooo oooo */
+static void DCRW_wa(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp, m;
+
+ RDOPARG( ea.b.l );
+ m = RM( ea.d );
+ tmp = m - 1;
+ ZHC_SUB( tmp, m, 0 );
+ WM( ea.d, tmp );
+ SKIP_CY;
+}
+
+/* 31: 0011 0001 */
+static void BLOCK(void)
+{
+ WM( DE, RM( HL ) );
+ DE++;
+ HL++;
+ C--;
+ if (C == 0xff)
+ PSW |= CY;
+ else
+ {
+ PSW &= ~CY;
+ PC--;
+ }
+}
+
+/* 32: 0011 0010 */
+static void INX_HL(void)
+{
+ HL++;
+}
+
+/* 33: 0011 0011 */
+static void DCX_HL(void)
+{
+ HL--;
+}
+
+/* 34: 0011 0100 llll llll hhhh hhhh */
+static void LXI_H_w(void)
+{
+ if (PSW & L0) { /* overlay active? */
+ PC+=2;
+ return;
+ }
+ RDOPARG( L );
+ RDOPARG( H );
+ PSW |= L0;
+}
+
+/* 35: 0011 0101 oooo oooo xxxx xxxx */
+static void LTIW_wa_xx(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp, m, imm;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( imm );
+ m = RM( ea.d );
+ tmp = m - imm;
+ ZHC_SUB( tmp, m, 0 );
+ SKIP_CY;
+}
+
+/* 36: 0011 0110 xxxx xxxx */
+/* SUINB_A_xx already defined (long form) */
+
+/* 37: 0011 0111 xxxx xxxx */
+/* LTI_A_xx already defined (long form) */
+
+/* 39: 0011 1001 */
+static void STAX_B(void)
+{
+ WM( BC, A );
+}
+
+/* 3a: 0011 1010 */
+static void STAX_D(void)
+{
+ WM( DE, A );
+}
+
+/* 3b: 0011 1011 */
+static void STAX_H(void)
+{
+ WM( HL, A );
+}
+
+/* 3c: 0011 1100 */
+static void STAX_Dp(void)
+{
+ WM( DE, A );
+ DE++;
+}
+
+/* 3d: 0011 1101 */
+static void STAX_Hp(void)
+{
+ WM( HL, A );
+ HL++;
+}
+
+/* 3e: 0011 1110 */
+static void STAX_Dm(void)
+{
+ WM( DE, A );
+ DE--;
+}
+
+/* 3f: 0011 1111 */
+static void STAX_Hm(void)
+{
+ WM( HL, A );
+ HL--;
+}
+
+/* 40: 0100 0000 llll llll hhhh hhhh */
+static void CALL_w(void)
+{
+ PAIR w;
+ w.d = 0;
+
+ RDOPARG( w.b.l );
+ RDOPARG( w.b.h );
+
+ SP--;
+ WM( SPD, PCH );
+ SP--;
+ WM( SPD, PCL );
+
+ PC = w.w.l;
+ change_pc( PCD );
+}
+
+/* 41: 0100 0001 */
+static void INR_A(void)
+{
+ UINT8 tmp = A + 1;
+ ZHC_ADD( tmp, A, 0 );
+ A = tmp;
+ SKIP_CY;
+}
+
+/* 42: 0100 0010 */
+static void INR_B(void)
+{
+ UINT8 tmp = B + 1;
+ ZHC_ADD( tmp, B, 0 );
+ B = tmp;
+ SKIP_CY;
+}
+
+/* 43: 0100 0011 */
+static void INR_C(void)
+{
+ UINT8 tmp = C + 1;
+ ZHC_ADD( tmp, C, 0 );
+ C = tmp;
+ SKIP_CY;
+}
+
+/* 44: 0100 0100 llll llll hhhh hhhh */
+static void LXI_EA_s(void)
+{
+ RDOPARG( EAL );
+ RDOPARG( EAH );
+}
+
+/* 45: 0100 0101 oooo oooo xxxx xxxx */
+static void ONIW_wa_xx(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 imm;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( imm );
+
+ if (RM( ea.d ) & imm)
+ PSW |= SK;
+}
+
+/* 46: 0100 0110 xxxx xxxx */
+/* ADI_A_xx already defined (long form) */
+
+/* 47: 0100 0111 xxxx xxxx */
+/* ONI_A_xx already defined (long form) */
+
+/* 48: prefix */
+static void PRE_48(void)
+{
+ RDOP(OP2);
+ upd7810_icount -= op48[OP2].cycles;
+ upd7810_timers(op48[OP2].cycles);
+ (*op48[OP2].opfunc)();
+}
+
+/* 49: 0100 1001 xxxx xxxx */
+static void MVIX_BC_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ WM( BC, imm );
+}
+
+/* 4a: 0100 1010 xxxx xxxx */
+static void MVIX_DE_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ WM( DE, imm );
+}
+
+/* 4b: 0100 1011 xxxx xxxx */
+static void MVIX_HL_xx(void)
+{
+ UINT8 imm;
+ RDOPARG( imm );
+ WM( HL, imm );
+}
+
+/* 4c: prefix */
+static void PRE_4C(void)
+{
+ RDOP(OP2);
+ upd7810_icount -= op4C[OP2].cycles;
+ upd7810_timers(op4C[OP2].cycles);
+ (*op4C[OP2].opfunc)();
+}
+
+/* 4d: prefix */
+static void PRE_4D(void)
+{
+ RDOP(OP2);
+ upd7810_icount -= op4D[OP2].cycles;
+ upd7810_timers(op4D[OP2].cycles);
+ (*op4D[OP2].opfunc)();
+}
+
+/* 4e: 0100 111d dddd dddd */
+static void JRE(void)
+{
+ UINT8 offs;
+ RDOPARG( offs );
+ if (OP & 0x01)
+ PC -= 256 - offs;
+ else
+ PC += offs;
+ change_pc( PCD );
+}
+
+/* 50: 0101 0000 */
+static void EXH(void)
+{
+ UINT16 tmp;
+ tmp = HL; HL = HL2; HL2 = tmp;
+}
+
+/* 51: 0101 0001 */
+static void DCR_A(void)
+{
+ UINT8 tmp = A - 1;
+ ZHC_SUB( tmp, A, 0 );
+ A = tmp;
+ SKIP_CY;
+}
+
+/* 52: 0101 0010 */
+static void DCR_B(void)
+{
+ UINT8 tmp = B - 1;
+ ZHC_SUB( tmp, B, 0 );
+ B = tmp;
+ SKIP_CY;
+}
+
+/* 53: 0101 0011 */
+static void DCR_C(void)
+{
+ UINT8 tmp = C - 1;
+ ZHC_SUB( tmp, C, 0 );
+ C = tmp;
+ SKIP_CY;
+}
+
+/* 54: 0101 0100 llll llll hhhh hhhh */
+static void JMP_w(void)
+{
+ PAIR w;
+ w.d = 0;
+
+ RDOPARG( w.b.l );
+ RDOPARG( w.b.h );
+
+ PCD = w.d;
+ change_pc( PCD );
+}
+
+/* 55: 0101 0101 oooo oooo xxxx xxxx */
+static void OFFIW_wa_xx(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 imm;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( imm );
+
+ if (0 == (RM( ea.d ) & imm))
+ PSW |= SK;
+}
+
+/* 56: 0101 0110 xxxx xxxx */
+/* ACI_A_xx already defined (long form) */
+
+/* 57: 0101 0111 xxxx xxxx */
+/* OFFI_A_xx already defined (long form) */
+
+/* 58: 0101 1000 oooo oooo (7810 only) */
+static void BIT_0_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ if (RM( ea.d ) & 0x01)
+ PSW |= SK;
+}
+
+/* 59: 0101 1001 oooo oooo (7810 only) */
+static void BIT_1_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ if (RM( ea.d ) & 0x02)
+ PSW |= SK;
+}
+
+/* 5a: 0101 1010 oooo oooo (7810 only) */
+static void BIT_2_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ if (RM( ea.d ) & 0x04)
+ PSW |= SK;
+}
+
+/* 5b: 0101 1011 oooo oooo (7810 only) */
+static void BIT_3_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ if (RM( ea.d ) & 0x08)
+ PSW |= SK;
+}
+
+/* 5c: 0101 1100 oooo oooo (7810 only) */
+static void BIT_4_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ if (RM( ea.d ) & 0x10)
+ PSW |= SK;
+}
+
+/* 5d: 0101 1101 oooo oooo (7810 only) */
+static void BIT_5_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ if (RM( ea.d ) & 0x20)
+ PSW |= SK;
+}
+
+/* 5e: 0101 1110 oooo oooo (7810 only) */
+static void BIT_6_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ if (RM( ea.d ) & 0x40)
+ PSW |= SK;
+}
+
+/* 5f: 0101 1111 oooo oooo (7810 only) */
+static void BIT_7_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ if (RM( ea.d ) & 0x80)
+ PSW |= SK;
+}
+
+/* 5d: 0101 1111 bbbb bbbb (7807 only) */
+static void SKN_bit(void)
+{
+ UINT8 imm;
+ int val;
+
+ RDOPARG( imm );
+
+ switch( imm & 0x1f )
+ {
+ case 0x10: /* PA */
+ val = RP( UPD7810_PORTA );
+ break;
+ case 0x11: /* PB */
+ val = RP( UPD7810_PORTB );
+ break;
+ case 0x12: /* PC */
+ val = RP( UPD7810_PORTC );
+ break;
+ case 0x13: /* PD */
+ val = RP( UPD7810_PORTD );
+ break;
+ case 0x15: /* PF */
+ val = RP( UPD7810_PORTF );
+ break;
+ case 0x16: /* MKH */
+ val = MKH;
+ break;
+ case 0x17: /* MKL */
+ val = MKL;
+ break;
+ case 0x19: /* SMH */
+ val = SMH;
+ break;
+ case 0x1b: /* EOM */
+ val = EOM;
+ break;
+ case 0x1d: /* TMM */
+ val = TMM;
+ break;
+ case 0x1e: /* PT */
+ val = RP( UPD7807_PORTT );
+ break;
+ default:
+ logerror("uPD7810 #%d: illegal opcode %02x %02x at PC:%04x\n", cpu_getactivecpu(), OP, imm, PC);
+ val = 0;
+ break;
+ }
+
+ if (~val & (1 << (imm >> 5)))
+ PSW |= SK;
+}
+
+/* 58: 0101 1000 bbbb bbbb (7807 only) */
+static void SETB(void)
+{
+ UINT8 imm;
+ int bit;
+
+ RDOPARG( imm );
+ bit = imm >> 5;
+
+ switch( imm & 0x1f )
+ {
+ case 0x10: /* PA */
+ WP( UPD7810_PORTA, RP( UPD7810_PORTA ) | (1 << bit));
+ break;
+ case 0x11: /* PB */
+ WP( UPD7810_PORTB, RP( UPD7810_PORTB ) | (1 << bit));
+ break;
+ case 0x12: /* PC */
+ WP( UPD7810_PORTC, RP( UPD7810_PORTC ) | (1 << bit));
+ break;
+ case 0x13: /* PD */
+ WP( UPD7810_PORTD, RP( UPD7810_PORTD ) | (1 << bit));
+ break;
+ case 0x15: /* PF */
+ WP( UPD7810_PORTF, RP( UPD7810_PORTF ) | (1 << bit));
+ break;
+ case 0x16: /* MKH */
+ MKH |= (1 << bit);
+ break;
+ case 0x17: /* MKL */
+ MKL |= (1 << bit);
+ break;
+ case 0x19: /* SMH */
+ SMH |= (1 << bit);
+ break;
+ case 0x1b: /* EOM */
+ EOM |= (1 << bit);
+ break;
+ case 0x1d: /* TMM */
+ TMM |= (1 << bit);
+ break;
+// case 0x1e: /* PT */
+// PT is input only
+// break;
+ default:
+ logerror("uPD7810 #%d: illegal opcode %02x %02x at PC:%04x\n", cpu_getactivecpu(), OP, imm, PC);
+ break;
+ }
+}
+
+/* 5b: 0101 1011 bbbb bbbb (7807 only) */
+static void CLR(void)
+{
+ UINT8 imm;
+ int bit;
+
+ RDOPARG( imm );
+ bit = imm >> 5;
+
+ switch( imm & 0x1f )
+ {
+ case 0x10: /* PA */
+ WP( UPD7810_PORTA, RP( UPD7810_PORTA ) & ~(1 << bit));
+ break;
+ case 0x11: /* PB */
+ WP( UPD7810_PORTB, RP( UPD7810_PORTB ) & ~(1 << bit));
+ break;
+ case 0x12: /* PC */
+ WP( UPD7810_PORTC, RP( UPD7810_PORTC ) & ~(1 << bit));
+ break;
+ case 0x13: /* PD */
+ WP( UPD7810_PORTD, RP( UPD7810_PORTD ) & ~(1 << bit));
+ break;
+ case 0x15: /* PF */
+ WP( UPD7810_PORTF, RP( UPD7810_PORTF ) & ~(1 << bit));
+ break;
+ case 0x16: /* MKH */
+ MKH &= ~(1 << bit);
+ break;
+ case 0x17: /* MKL */
+ MKL &= ~(1 << bit);
+ break;
+ case 0x19: /* SMH */
+ SMH &= ~(1 << bit);
+ break;
+ case 0x1b: /* EOM */
+ EOM &= ~(1 << bit);
+ break;
+ case 0x1d: /* TMM */
+ TMM &= ~(1 << bit);
+ break;
+// case 0x1e: /* PT */
+// PT is input only
+// break;
+ default:
+ logerror("uPD7810 #%d: illegal opcode %02x %02x at PC:%04x\n", cpu_getactivecpu(), OP, imm, PC);
+ break;
+ }
+}
+
+/* 5d: 0101 1111 bbbb bbbb (7807 only) */
+static void SK_bit(void)
+{
+ UINT8 imm;
+ int val;
+
+ RDOPARG( imm );
+
+ switch( imm & 0x1f )
+ {
+ case 0x10: /* PA */
+ val = RP( UPD7810_PORTA );
+ break;
+ case 0x11: /* PB */
+ val = RP( UPD7810_PORTB );
+ break;
+ case 0x12: /* PC */
+ val = RP( UPD7810_PORTC );
+ break;
+ case 0x13: /* PD */
+ val = RP( UPD7810_PORTD );
+ break;
+ case 0x15: /* PF */
+ val = RP( UPD7810_PORTF );
+ break;
+ case 0x16: /* MKH */
+ val = MKH;
+ break;
+ case 0x17: /* MKL */
+ val = MKL;
+ break;
+ case 0x19: /* SMH */
+ val = SMH;
+ break;
+ case 0x1b: /* EOM */
+ val = EOM;
+ break;
+ case 0x1d: /* TMM */
+ val = TMM;
+ break;
+ case 0x1e: /* PT */
+ val = RP( UPD7807_PORTT );
+ break;
+ default:
+ logerror("uPD7810 #%d: illegal opcode %02x %02x at PC:%04x\n", cpu_getactivecpu(), OP, imm, PC);
+ val = 0;
+ break;
+ }
+
+ if (val & (1 << (imm >> 5)))
+ PSW |= SK;
+}
+
+/* 60:*/
+static void PRE_60(void)
+{
+ RDOP(OP2);
+ upd7810_icount -= op60[OP2].cycles;
+ upd7810_timers(op60[OP2].cycles);
+ (*op60[OP2].opfunc)();
+}
+
+/* 61: 0110 0001 */
+static void DAA(void)
+{
+ UINT8 l = A & 0x0f, h = A >> 4, tmp, adj = 0x00;
+ if (0 == (PSW & HC))
+ {
+ if (l < 10)
+ {
+ if (!(h < 10 && 0 == (PSW & CY)))
+ adj = 0x60;
+ }
+ else
+ {
+ if (h < 9 && 0 == (PSW & CY))
+ adj = 0x06;
+ else
+ adj = 0x66;
+ }
+ }
+ else
+ if (l < 3)
+ {
+ if (h < 10 && 0 == (PSW & CY))
+ adj = 0x06;
+ else
+ adj = 0x66;
+ }
+ tmp = A + adj;
+ ZHC_ADD( tmp, A, PSW & CY );
+ A = tmp;
+}
+
+/* 62: 0110 0010 */
+static void RETI(void)
+{
+ PCL = RM( SPD );
+ SP++;
+ PCH = RM( SPD );
+ SP++;
+ PSW = RM( SPD );
+ SP++;
+ change_pc( PCD );
+}
+
+/* 63: 0110 0011 oooo oooo */
+static void STAW_wa(void)
+{
+ PAIR ea = upd7810.va;
+
+ RDOPARG( ea.b.l );
+
+ WM( ea.d, A );
+}
+
+/* 64: prefix */
+static void PRE_64(void)
+{
+ RDOP(OP2);
+ upd7810_icount -= op64[OP2].cycles;
+ upd7810_timers(op64[OP2].cycles);
+ (*op64[OP2].opfunc)();
+}
+
+/* 65: 0110 0101 oooo oooo xxxx xxxx */
+static void NEIW_wa_xx(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp, m, imm;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( imm );
+ m = RM( ea.d );
+ tmp = m - imm;
+ ZHC_SUB( tmp, m, 0 );
+ SKIP_NZ;
+}
+
+/* 66: 0110 0110 xxxx xxxx */
+/* SUI_A_xx already defined (long form) */
+
+/* 67: 0110 0111 xxxx xxxx */
+/* NEI_A_xx already defined (long form) */
+
+/* 68: 0110 1000 xxxx xxxx */
+static void MVI_V_xx(void)
+{
+ RDOPARG( V );
+}
+
+/* 69: 0110 1001 xxxx xxxx */
+static void MVI_A_xx(void)
+{
+ if (PSW & L1) { /* overlay active? */
+ PC++;
+ return; /* NOP */
+ }
+ RDOPARG( A );
+ PSW |= L1;
+}
+
+/* 6a: 0110 1010 xxxx xxxx */
+static void MVI_B_xx(void)
+{
+ RDOPARG( B );
+}
+
+/* 6b: 0110 1011 xxxx xxxx */
+static void MVI_C_xx(void)
+{
+ RDOPARG( C );
+}
+
+/* 6c: 0110 1100 xxxx xxxx */
+static void MVI_D_xx(void)
+{
+ RDOPARG( D );
+}
+
+/* 6d: 0110 1101 xxxx xxxx */
+static void MVI_E_xx(void)
+{
+ RDOPARG( E );
+}
+
+/* 6e: 0110 1110 xxxx xxxx */
+static void MVI_H_xx(void)
+{
+ RDOPARG( H );
+}
+
+/* 6f: 0110 1111 xxxx xxxx */
+static void MVI_L_xx(void)
+{
+ if (PSW & L0) { /* overlay active? */
+ PC++;
+ return; /* NOP */
+ }
+ RDOPARG( L );
+ PSW |= L0;
+}
+
+/* 70: prefix */
+static void PRE_70(void)
+{
+ RDOP(OP2);
+ upd7810_icount -= op70[OP2].cycles;
+ upd7810_timers(op70[OP2].cycles);
+ (*op70[OP2].opfunc)();
+}
+
+/* 71: 0111 0001 oooo oooo xxxx xxxx */
+static void MVIW_wa_xx(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 imm;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( imm );
+
+ WM( ea.d, imm );
+}
+
+/* 72: 0111 0010 */
+static void SOFTI(void)
+{
+ SP--;
+ WM( SPD, PSW );
+ SP--;
+ WM( SPD, PCH );
+ SP--;
+ WM( SPD, PCL );
+
+ PC = 0x0060;
+ change_pc( PCD );
+}
+
+/* 74: prefix */
+static void PRE_74(void)
+{
+ RDOP(OP2);
+ upd7810_icount -= op74[OP2].cycles;
+ upd7810_timers(op74[OP2].cycles);
+ (*op74[OP2].opfunc)();
+}
+
+/* 75: 0111 0101 oooo oooo xxxx xxxx */
+static void EQIW_wa_xx(void)
+{
+ PAIR ea = upd7810.va;
+ UINT8 tmp, m, imm;
+
+ RDOPARG( ea.b.l );
+ RDOPARG( imm );
+ m = RM( ea.d );
+ tmp = m - imm;
+ ZHC_SUB( tmp, m, 0 );
+ SKIP_Z;
+}
+
+/* 76: 0111 0110 xxxx xxxx */
+/* SBI_A_xx already defined (long form) */
+
+/* 77: 0111 0111 xxxx xxxx */
+/* EQI_A_xx already defined (long form) */
+
+/* 78: 0111 1ddd dddd dddd */
+static void CALF(void)
+{
+ PAIR w;
+ w.d = 0;
+
+ RDOPARG( w.b.l );
+ w.b.h = 0x08 + (OP & 0x07);
+
+ SP--;
+ WM( SPD, PCH );
+ SP--;
+ WM( SPD, PCL );
+
+ PCD = w.d;
+ change_pc( PCD );
+}
+
+/* 80: 100t tttt */
+static void CALT(void)
+{
+ PAIR w;
+ w.d = 0;
+
+ switch (upd7810.config.type) {
+ case TYPE_7810_GAMEMASTER:
+ logerror ("!!!!!!!%.4x calt %.2x game master table position not known\n",PPC, OP);
+ break;
+ default:
+ w.w.l = 0x80 + 2 * (OP & 0x1f);
+ }
+
+ if (upd7810.config.type!=TYPE_7810_GAMEMASTER) {
+ SP--;
+ WM( SPD, PCH );
+ SP--;
+ WM( SPD, PCL );
+
+ PCL=RM(w.w.l);
+ PCH=RM(w.w.l+1);
+
+ change_pc( PCD );
+ logerror ("!!!!!!!%.4x calt %.2x %.4x; game master table position not known\n",PPC, OP, PCD);
+ }
+}
+
+/* a0: 1010 0000 */
+static void POP_VA(void)
+{
+ A = RM( SPD );
+ SP++;
+ V = RM( SPD );
+ SP++;
+}
+
+/* a1: 1010 0001 */
+static void POP_BC(void)
+{
+ C = RM( SPD );
+ SP++;
+ B = RM( SPD );
+ SP++;
+}
+
+/* a2: 1010 0010 */
+static void POP_DE(void)
+{
+ E = RM( SPD );
+ SP++;
+ D = RM( SPD );
+ SP++;
+}
+
+/* a3: 1010 0011 */
+static void POP_HL(void)
+{
+ L = RM( SPD );
+ SP++;
+ H = RM( SPD );
+ SP++;
+}
+
+/* a4: 1010 0100 */
+static void POP_EA(void)
+{
+ EAL = RM( SPD );
+ SP++;
+ EAH = RM( SPD );
+ SP++;
+}
+
+/* a5: 1010 0101 */
+static void DMOV_EA_BC(void)
+{
+ EA = BC;
+}
+
+/* a6: 1010 0110 */
+static void DMOV_EA_DE(void)
+{
+ EA = DE;
+}
+
+/* a7: 1010 0111 */
+static void DMOV_EA_HL(void)
+{
+ EA = HL;
+}
+
+/* a8: 1010 1000 */
+static void INX_EA(void)
+{
+ EA++;
+}
+
+/* a9: 1010 1001 */
+static void DCX_EA(void)
+{
+ EA--;
+}
+
+/* aa: 1010 1010 */
+static void EI(void)
+{
+ IFF = 1;
+}
+
+/* ab: 1010 1011 dddd dddd */
+static void LDAX_D_xx(void)
+{
+ UINT16 ea;
+ RDOPARG( ea );
+ ea += DE;
+ A = RM( ea );
+}
+
+/* ac: 1010 1100 */
+static void LDAX_H_A(void)
+{
+ UINT16 ea;
+ ea = HL + A;
+ A = RM( ea );
+}
+
+/* ad: 1010 1101 */
+static void LDAX_H_B(void)
+{
+ UINT16 ea;
+ ea = HL + B;
+ A = RM( ea );
+}
+
+/* ae: 1010 1110 */
+static void LDAX_H_EA(void)
+{
+ UINT16 ea;
+ ea = HL + EA;
+ A = RM( ea );
+}
+
+/* af: 1010 1111 dddd dddd */
+static void LDAX_H_xx(void)
+{
+ UINT16 ea;
+ RDOPARG( ea );
+ ea += HL;
+ A = RM( ea );
+}
+
+/* b0: 1011 0000 */
+static void PUSH_VA(void)
+{
+ SP--;
+ WM( SPD, V );
+ SP--;
+ WM( SPD, A );
+}
+
+/* b1: 1011 0001 */
+static void PUSH_BC(void)
+{
+ SP--;
+ WM( SPD, B );
+ SP--;
+ WM( SPD, C );
+}
+
+/* b2: 1011 0010 */
+static void PUSH_DE(void)
+{
+ SP--;
+ WM( SPD, D );
+ SP--;
+ WM( SPD, E );
+}
+
+/* b3: 1011 0011 */
+static void PUSH_HL(void)
+{
+ SP--;
+ WM( SPD, H );
+ SP--;
+ WM( SPD, L );
+}
+
+/* b4: 1011 0100 */
+static void PUSH_EA(void)
+{
+ SP--;
+ WM( SPD, EAH );
+ SP--;
+ WM( SPD, EAL );
+}
+
+/* b5: 1011 0101 */
+static void DMOV_BC_EA(void)
+{
+ BC = EA;
+}
+
+/* b6: 1011 0110 */
+static void DMOV_DE_EA(void)
+{
+ DE = EA;
+}
+
+/* b7: 1011 0111 */
+static void DMOV_HL_EA(void)
+{
+ HL = EA;
+}
+
+/* b8: 1011 1000 */
+static void RET(void)
+{
+ PCL = RM( SPD );
+ SP++;
+ PCH = RM( SPD );
+ SP++;
+ change_pc( PCD );
+}
+
+/* b9: 1011 1001 */
+static void RETS(void)
+{
+ PCL = RM( SPD );
+ SP++;
+ PCH = RM( SPD );
+ SP++;
+ PSW|=SK; /* skip one instruction */
+ change_pc( PCD );
+}
+
+/* ba: 1011 1010 */
+static void DI(void)
+{
+ IFF = 0;
+}
+
+/* bb: 1011 1011 dddd dddd */
+static void STAX_D_xx(void)
+{
+ UINT16 ea;
+ RDOPARG(ea);
+ ea += DE;
+ WM( ea, A );
+}
+
+/* bc: 1011 1100 */
+static void STAX_H_A(void)
+{
+ UINT16 ea = A;
+ ea += HL;
+ WM( ea, A );
+}
+
+/* bd: 1011 1101 */
+static void STAX_H_B(void)
+{
+ UINT16 ea = B;
+ ea += HL;
+ WM( ea, A );
+}
+
+/* be: 1011 1110 */
+static void STAX_H_EA(void)
+{
+ UINT16 ea = EA;
+ ea += HL;
+ WM( ea, A );
+}
+
+/* bf: 1011 1111 dddd dddd */
+static void STAX_H_xx(void)
+{
+ UINT16 ea;
+ RDOPARG( ea );
+ ea += HL;
+ WM( ea, A );
+}
+
+/* c0: 11dd dddd */
+static void JR(void)
+{
+ INT8 offs = (INT8)(OP << 2) >> 2;
+ PC += offs;
+ change_pc(PCD);
+}
+
diff --git a/src/emu/cpu/upd7810/7810tbl.c b/src/emu/cpu/upd7810/7810tbl.c
new file mode 100644
index 00000000000..d6032fc8aed
--- /dev/null
+++ b/src/emu/cpu/upd7810/7810tbl.c
@@ -0,0 +1,3513 @@
+/*****************************************************************************
+ *
+ * Portable uPD7810/11, 7810H/11H, 78C10/C11/C14 emulator V0.2
+ * Copyright (c) 2001 Juergen Buchmueller, all rights reserved.
+ *
+ * 7810tbl.c - function pointer tables
+ *
+ *****************************************************************************/
+
+static void illegal(void);
+static void illegal2(void);
+
+static void ACI_ANM_xx(void);
+static void ACI_A_xx(void);
+static void ACI_B_xx(void);
+static void ACI_C_xx(void);
+static void ACI_D_xx(void);
+static void ACI_EOM_xx(void);
+static void ACI_E_xx(void);
+static void ACI_H_xx(void);
+static void ACI_L_xx(void);
+static void ACI_MKH_xx(void);
+static void ACI_MKL_xx(void);
+static void ACI_PA_xx(void);
+static void ACI_PB_xx(void);
+static void ACI_PC_xx(void);
+static void ACI_PD_xx(void);
+static void ACI_PF_xx(void);
+static void ACI_SMH_xx(void);
+static void ACI_TMM_xx(void);
+static void ACI_V_xx(void);
+static void ADCW_wa(void);
+static void ADCX_B(void);
+static void ADCX_D(void);
+static void ADCX_Dm(void);
+static void ADCX_Dp(void);
+static void ADCX_H(void);
+static void ADCX_Hm(void);
+static void ADCX_Hp(void);
+static void ADC_A_A(void);
+static void ADC_A_A(void);
+static void ADC_A_B(void);
+static void ADC_A_C(void);
+static void ADC_A_D(void);
+static void ADC_A_E(void);
+static void ADC_A_H(void);
+static void ADC_A_L(void);
+static void ADC_A_V(void);
+static void ADC_B_A(void);
+static void ADC_C_A(void);
+static void ADC_D_A(void);
+static void ADC_E_A(void);
+static void ADC_H_A(void);
+static void ADC_L_A(void);
+static void ADC_V_A(void);
+static void ADDNCW_wa(void);
+static void ADDNCX_B(void);
+static void ADDNCX_D(void);
+static void ADDNCX_Dm(void);
+static void ADDNCX_Dp(void);
+static void ADDNCX_H(void);
+static void ADDNCX_Hm(void);
+static void ADDNCX_Hp(void);
+static void ADDNC_A_A(void);
+static void ADDNC_A_A(void);
+static void ADDNC_A_B(void);
+static void ADDNC_A_C(void);
+static void ADDNC_A_D(void);
+static void ADDNC_A_E(void);
+static void ADDNC_A_H(void);
+static void ADDNC_A_L(void);
+static void ADDNC_A_V(void);
+static void ADDNC_B_A(void);
+static void ADDNC_C_A(void);
+static void ADDNC_D_A(void);
+static void ADDNC_E_A(void);
+static void ADDNC_H_A(void);
+static void ADDNC_L_A(void);
+static void ADDNC_V_A(void);
+static void ADDW_wa(void);
+static void ADDX_B(void);
+static void ADDX_D(void);
+static void ADDX_Dm(void);
+static void ADDX_Dp(void);
+static void ADDX_H(void);
+static void ADDX_Hm(void);
+static void ADDX_Hp(void);
+static void ADD_A_A(void);
+static void ADD_A_A(void);
+static void ADD_A_B(void);
+static void ADD_A_C(void);
+static void ADD_A_D(void);
+static void ADD_A_E(void);
+static void ADD_A_H(void);
+static void ADD_A_L(void);
+static void ADD_A_V(void);
+static void ADD_B_A(void);
+static void ADD_C_A(void);
+static void ADD_D_A(void);
+static void ADD_E_A(void);
+static void ADD_H_A(void);
+static void ADD_L_A(void);
+static void ADD_V_A(void);
+static void ADINC_ANM_xx(void);
+static void ADINC_A_xx(void);
+static void ADINC_A_xx(void);
+static void ADINC_B_xx(void);
+static void ADINC_C_xx(void);
+static void ADINC_D_xx(void);
+static void ADINC_EOM_xx(void);
+static void ADINC_E_xx(void);
+static void ADINC_H_xx(void);
+static void ADINC_L_xx(void);
+static void ADINC_MKH_xx(void);
+static void ADINC_MKL_xx(void);
+static void ADINC_PA_xx(void);
+static void ADINC_PB_xx(void);
+static void ADINC_PC_xx(void);
+static void ADINC_PD_xx(void);
+static void ADINC_PF_xx(void);
+static void ADINC_SMH_xx(void);
+static void ADINC_TMM_xx(void);
+static void ADINC_V_xx(void);
+static void ADI_ANM_xx(void);
+static void ADI_A_xx(void);
+static void ADI_A_xx(void);
+static void ADI_B_xx(void);
+static void ADI_C_xx(void);
+static void ADI_D_xx(void);
+static void ADI_EOM_xx(void);
+static void ADI_E_xx(void);
+static void ADI_H_xx(void);
+static void ADI_L_xx(void);
+static void ADI_MKH_xx(void);
+static void ADI_MKL_xx(void);
+static void ADI_PA_xx(void);
+static void ADI_PB_xx(void);
+static void ADI_PC_xx(void);
+static void ADI_PD_xx(void);
+static void ADI_PF_xx(void);
+static void ADI_SMH_xx(void);
+static void ADI_TMM_xx(void);
+static void ADI_V_xx(void);
+static void ANAW_wa(void);
+static void ANAX_B(void);
+static void ANAX_D(void);
+static void ANAX_Dm(void);
+static void ANAX_Dp(void);
+static void ANAX_H(void);
+static void ANAX_Hm(void);
+static void ANAX_Hp(void);
+static void ANA_A_A(void);
+static void ANA_A_A(void);
+static void ANA_A_B(void);
+static void ANA_A_C(void);
+static void ANA_A_D(void);
+static void ANA_A_E(void);
+static void ANA_A_H(void);
+static void ANA_A_L(void);
+static void ANA_A_V(void);
+static void ANA_B_A(void);
+static void ANA_C_A(void);
+static void ANA_D_A(void);
+static void ANA_E_A(void);
+static void ANA_H_A(void);
+static void ANA_L_A(void);
+static void ANA_V_A(void);
+static void ANIW_wa_xx(void);
+static void ANI_ANM_xx(void);
+static void ANI_A_xx(void);
+static void ANI_A_xx(void);
+static void ANI_B_xx(void);
+static void ANI_C_xx(void);
+static void ANI_D_xx(void);
+static void ANI_EOM_xx(void);
+static void ANI_E_xx(void);
+static void ANI_H_xx(void);
+static void ANI_L_xx(void);
+static void ANI_MKH_xx(void);
+static void ANI_MKL_xx(void);
+static void ANI_PA_xx(void);
+static void ANI_PB_xx(void);
+static void ANI_PC_xx(void);
+static void ANI_PD_xx(void);
+static void ANI_PF_xx(void);
+static void ANI_SMH_xx(void);
+static void ANI_TMM_xx(void);
+static void ANI_V_xx(void);
+static void BIT_0_wa(void);
+static void BIT_1_wa(void);
+static void BIT_2_wa(void);
+static void BIT_3_wa(void);
+static void BIT_4_wa(void);
+static void BIT_5_wa(void);
+static void BIT_6_wa(void);
+static void BIT_7_wa(void);
+static void BLOCK(void);
+static void CALB(void);
+static void CALF(void);
+static void CALL_w(void);
+static void CALT(void);
+static void CLC(void);
+static void CLR(void);
+static void DAA(void);
+static void DADC_EA_BC(void);
+static void DADC_EA_DE(void);
+static void DADC_EA_HL(void);
+static void DADDNC_EA_BC(void);
+static void DADDNC_EA_DE(void);
+static void DADDNC_EA_HL(void);
+static void DADD_EA_BC(void);
+static void DADD_EA_DE(void);
+static void DADD_EA_HL(void);
+static void DAN_EA_BC(void);
+static void DAN_EA_DE(void);
+static void DAN_EA_HL(void);
+static void DCRW_wa(void);
+static void DCR_A(void);
+static void DCR_B(void);
+static void DCR_C(void);
+static void DCX_BC(void);
+static void DCX_DE(void);
+static void DCX_EA(void);
+static void DCX_HL(void);
+static void DCX_SP(void);
+static void DEQ_EA_BC(void);
+static void DEQ_EA_DE(void);
+static void DEQ_EA_HL(void);
+static void DGT_EA_BC(void);
+static void DGT_EA_DE(void);
+static void DGT_EA_HL(void);
+static void DI(void);
+static void DIV_A(void);
+static void DIV_B(void);
+static void DIV_C(void);
+static void DLT_EA_BC(void);
+static void DLT_EA_DE(void);
+static void DLT_EA_HL(void);
+static void DMOV_BC_EA(void);
+static void DMOV_DE_EA(void);
+static void DMOV_EA_BC(void);
+static void DMOV_EA_DE(void);
+static void DMOV_EA_ECNT(void);
+static void DMOV_EA_ECPT(void);
+static void DMOV_EA_HL(void);
+static void DMOV_ETM0_EA(void);
+static void DMOV_ETM1_EA(void);
+static void DMOV_HL_EA(void);
+static void DNE_EA_BC(void);
+static void DNE_EA_DE(void);
+static void DNE_EA_HL(void);
+static void DOFF_EA_BC(void);
+static void DOFF_EA_DE(void);
+static void DOFF_EA_HL(void);
+static void DON_EA_BC(void);
+static void DON_EA_DE(void);
+static void DON_EA_HL(void);
+static void DOR_EA_BC(void);
+static void DOR_EA_DE(void);
+static void DOR_EA_HL(void);
+static void DRLL_EA(void);
+static void DRLR_EA(void);
+static void DSBB_EA_BC(void);
+static void DSBB_EA_DE(void);
+static void DSBB_EA_HL(void);
+static void DSLL_EA(void);
+static void DSLR_EA(void);
+static void DSUBNB_EA_BC(void);
+static void DSUBNB_EA_DE(void);
+static void DSUBNB_EA_HL(void);
+static void DSUB_EA_BC(void);
+static void DSUB_EA_DE(void);
+static void DSUB_EA_HL(void);
+static void DXR_EA_BC(void);
+static void DXR_EA_DE(void);
+static void DXR_EA_HL(void);
+static void EADD_EA_A(void);
+static void EADD_EA_B(void);
+static void EADD_EA_C(void);
+static void EI(void);
+static void EQAW_wa(void);
+static void EQAX_B(void);
+static void EQAX_D(void);
+static void EQAX_Dm(void);
+static void EQAX_Dp(void);
+static void EQAX_H(void);
+static void EQAX_Hm(void);
+static void EQAX_Hp(void);
+static void EQA_A_A(void);
+static void EQA_A_A(void);
+static void EQA_A_B(void);
+static void EQA_A_C(void);
+static void EQA_A_D(void);
+static void EQA_A_E(void);
+static void EQA_A_H(void);
+static void EQA_A_L(void);
+static void EQA_A_V(void);
+static void EQA_B_A(void);
+static void EQA_C_A(void);
+static void EQA_D_A(void);
+static void EQA_E_A(void);
+static void EQA_H_A(void);
+static void EQA_L_A(void);
+static void EQA_V_A(void);
+static void EQIW_wa_xx(void);
+static void EQI_ANM_xx(void);
+static void EQI_A_xx(void);
+static void EQI_A_xx(void);
+static void EQI_B_xx(void);
+static void EQI_C_xx(void);
+static void EQI_D_xx(void);
+static void EQI_EOM_xx(void);
+static void EQI_E_xx(void);
+static void EQI_H_xx(void);
+static void EQI_L_xx(void);
+static void EQI_MKH_xx(void);
+static void EQI_MKL_xx(void);
+static void EQI_PA_xx(void);
+static void EQI_PB_xx(void);
+static void EQI_PC_xx(void);
+static void EQI_PD_xx(void);
+static void EQI_PF_xx(void);
+static void EQI_SMH_xx(void);
+static void EQI_TMM_xx(void);
+static void EQI_V_xx(void);
+static void ESUB_EA_A(void);
+static void ESUB_EA_B(void);
+static void ESUB_EA_C(void);
+static void EXA(void);
+static void EXH(void);
+static void EXX(void);
+static void EXR(void);
+static void GTAW_wa(void);
+static void GTAX_B(void);
+static void GTAX_D(void);
+static void GTAX_Dm(void);
+static void GTAX_Dp(void);
+static void GTAX_H(void);
+static void GTAX_Hm(void);
+static void GTAX_Hp(void);
+static void GTA_A_A(void);
+static void GTA_A_A(void);
+static void GTA_A_B(void);
+static void GTA_A_C(void);
+static void GTA_A_D(void);
+static void GTA_A_E(void);
+static void GTA_A_H(void);
+static void GTA_A_L(void);
+static void GTA_A_V(void);
+static void GTA_B_A(void);
+static void GTA_C_A(void);
+static void GTA_D_A(void);
+static void GTA_E_A(void);
+static void GTA_H_A(void);
+static void GTA_L_A(void);
+static void GTA_V_A(void);
+static void GTIW_wa_xx(void);
+static void GTI_ANM_xx(void);
+static void GTI_A_xx(void);
+static void GTI_A_xx(void);
+static void GTI_B_xx(void);
+static void GTI_C_xx(void);
+static void GTI_D_xx(void);
+static void GTI_EOM_xx(void);
+static void GTI_E_xx(void);
+static void GTI_H_xx(void);
+static void GTI_L_xx(void);
+static void GTI_MKH_xx(void);
+static void GTI_MKL_xx(void);
+static void GTI_PA_xx(void);
+static void GTI_PB_xx(void);
+static void GTI_PC_xx(void);
+static void GTI_PD_xx(void);
+static void GTI_PF_xx(void);
+static void GTI_SMH_xx(void);
+static void GTI_TMM_xx(void);
+static void GTI_V_xx(void);
+static void HALT(void);
+static void INRW_wa(void);
+static void INR_A(void);
+static void INR_B(void);
+static void INR_C(void);
+static void INX_BC(void);
+static void INX_DE(void);
+static void INX_EA(void);
+static void INX_HL(void);
+static void INX_SP(void);
+static void JB(void);
+static void JEA(void);
+static void JMP_w(void);
+static void JR(void);
+static void JRE(void);
+static void LBCD_w(void);
+static void LDAW_wa(void);
+static void LDAX_B(void);
+static void LDAX_D(void);
+static void LDAX_D_xx(void);
+static void LDAX_Dm(void);
+static void LDAX_Dp(void);
+static void LDAX_H(void);
+static void LDAX_H_A(void);
+static void LDAX_H_B(void);
+static void LDAX_H_EA(void);
+static void LDAX_H_xx(void);
+static void LDAX_Hm(void);
+static void LDAX_Hp(void);
+static void LDEAX_D(void);
+static void LDEAX_D_xx(void);
+static void LDEAX_Dp(void);
+static void LDEAX_H(void);
+static void LDEAX_H_A(void);
+static void LDEAX_H_B(void);
+static void LDEAX_H_EA(void);
+static void LDEAX_H_xx(void);
+static void LDEAX_Hp(void);
+static void LDED_w(void);
+static void LHLD_w(void);
+static void LSPD_w(void);
+static void LTAW_wa(void);
+static void LTAX_B(void);
+static void LTAX_D(void);
+static void LTAX_Dm(void);
+static void LTAX_Dp(void);
+static void LTAX_H(void);
+static void LTAX_Hm(void);
+static void LTAX_Hp(void);
+static void LTA_A_A(void);
+static void LTA_A_A(void);
+static void LTA_A_B(void);
+static void LTA_A_C(void);
+static void LTA_A_D(void);
+static void LTA_A_E(void);
+static void LTA_A_H(void);
+static void LTA_A_L(void);
+static void LTA_A_V(void);
+static void LTA_B_A(void);
+static void LTA_C_A(void);
+static void LTA_D_A(void);
+static void LTA_E_A(void);
+static void LTA_H_A(void);
+static void LTA_L_A(void);
+static void LTA_V_A(void);
+static void LTIW_wa_xx(void);
+static void LTI_ANM_xx(void);
+static void LTI_A_xx(void);
+static void LTI_A_xx(void);
+static void LTI_B_xx(void);
+static void LTI_C_xx(void);
+static void LTI_D_xx(void);
+static void LTI_EOM_xx(void);
+static void LTI_E_xx(void);
+static void LTI_H_xx(void);
+static void LTI_L_xx(void);
+static void LTI_MKH_xx(void);
+static void LTI_MKL_xx(void);
+static void LTI_PA_xx(void);
+static void LTI_PB_xx(void);
+static void LTI_PC_xx(void);
+static void LTI_PD_xx(void);
+static void LTI_PF_xx(void);
+static void LTI_SMH_xx(void);
+static void LTI_TMM_xx(void);
+static void LTI_V_xx(void);
+static void LXI_B_w(void);
+static void LXI_D_w(void);
+static void LXI_EA_s(void);
+static void LXI_H_w(void);
+static void LXI_S_w(void);
+static void MOV_ANM_A(void);
+static void MOV_A_ANM(void);
+static void MOV_A_B(void);
+static void MOV_A_C(void);
+static void MOV_A_CR0(void);
+static void MOV_A_CR1(void);
+static void MOV_A_CR2(void);
+static void MOV_A_CR3(void);
+static void MOV_A_D(void);
+static void MOV_A_E(void);
+static void MOV_A_EAH(void);
+static void MOV_A_EAL(void);
+static void MOV_A_EOM(void);
+static void MOV_A_H(void);
+static void MOV_A_L(void);
+static void MOV_A_MKH(void);
+static void MOV_A_MKL(void);
+static void MOV_A_PA(void);
+static void MOV_A_PB(void);
+static void MOV_A_PC(void);
+static void MOV_A_PD(void);
+static void MOV_A_PF(void);
+static void MOV_A_RXB(void);
+static void MOV_A_SMH(void);
+static void MOV_A_TMM(void);
+static void MOV_A_PT(void);
+static void MOV_A_w(void);
+static void MOV_B_A(void);
+static void MOV_B_w(void);
+static void MOV_C_A(void);
+static void MOV_C_w(void);
+static void MOV_D_A(void);
+static void MOV_D_w(void);
+static void MOV_EAH_A(void);
+static void MOV_EAL_A(void);
+static void MOV_EOM_A(void);
+static void MOV_ETMM_A(void);
+static void MOV_E_A(void);
+static void MOV_E_w(void);
+static void MOV_H_A(void);
+static void MOV_H_w(void);
+static void MOV_L_A(void);
+static void MOV_L_w(void);
+static void MOV_MA_A(void);
+static void MOV_MB_A(void);
+static void MOV_MCC_A(void);
+static void MOV_MC_A(void);
+static void MOV_MF_A(void);
+static void MOV_MKH_A(void);
+static void MOV_MKL_A(void);
+static void MOV_MM_A(void);
+static void MOV_PA_A(void);
+static void MOV_PB_A(void);
+static void MOV_PC_A(void);
+static void MOV_PD_A(void);
+static void MOV_PF_A(void);
+static void MOV_SMH_A(void);
+static void MOV_SML_A(void);
+static void MOV_TM0_A(void);
+static void MOV_TM1_A(void);
+static void MOV_TMM_A(void);
+static void MOV_TXB_A(void);
+static void MOV_V_w(void);
+static void MOV_ZCM_A(void);
+static void MOV_w_A(void);
+static void MOV_w_B(void);
+static void MOV_w_C(void);
+static void MOV_w_D(void);
+static void MOV_w_E(void);
+static void MOV_w_H(void);
+static void MOV_w_L(void);
+static void MOV_w_V(void);
+static void MUL_A(void);
+static void MUL_B(void);
+static void MUL_C(void);
+static void MVIW_wa_xx(void);
+static void MVIX_BC_xx(void);
+static void MVIX_DE_xx(void);
+static void MVIX_HL_xx(void);
+static void MVI_ANM_xx(void);
+static void MVI_A_xx(void);
+static void MVI_B_xx(void);
+static void MVI_C_xx(void);
+static void MVI_D_xx(void);
+static void MVI_EOM_xx(void);
+static void MVI_E_xx(void);
+static void MVI_H_xx(void);
+static void MVI_L_xx(void);
+static void MVI_MKH_xx(void);
+static void MVI_MKL_xx(void);
+static void MVI_PA_xx(void);
+static void MVI_PB_xx(void);
+static void MVI_PC_xx(void);
+static void MVI_PD_xx(void);
+static void MVI_PF_xx(void);
+static void MVI_SMH_xx(void);
+static void MVI_TMM_xx(void);
+static void MVI_V_xx(void);
+static void NEAW_wa(void);
+static void NEAX_B(void);
+static void NEAX_D(void);
+static void NEAX_Dm(void);
+static void NEAX_Dp(void);
+static void NEAX_H(void);
+static void NEAX_Hm(void);
+static void NEAX_Hp(void);
+static void NEA_A_A(void);
+static void NEA_A_A(void);
+static void NEA_A_B(void);
+static void NEA_A_C(void);
+static void NEA_A_D(void);
+static void NEA_A_E(void);
+static void NEA_A_H(void);
+static void NEA_A_L(void);
+static void NEA_A_V(void);
+static void NEA_B_A(void);
+static void NEA_C_A(void);
+static void NEA_D_A(void);
+static void NEA_E_A(void);
+static void NEA_H_A(void);
+static void NEA_L_A(void);
+static void NEA_V_A(void);
+static void NEGA(void);
+static void NEIW_wa_xx(void);
+static void NEI_ANM_xx(void);
+static void NEI_A_xx(void);
+static void NEI_A_xx(void);
+static void NEI_B_xx(void);
+static void NEI_C_xx(void);
+static void NEI_D_xx(void);
+static void NEI_EOM_xx(void);
+static void NEI_E_xx(void);
+static void NEI_H_xx(void);
+static void NEI_L_xx(void);
+static void NEI_MKH_xx(void);
+static void NEI_MKL_xx(void);
+static void NEI_PA_xx(void);
+static void NEI_PB_xx(void);
+static void NEI_PC_xx(void);
+static void NEI_PD_xx(void);
+static void NEI_PF_xx(void);
+static void NEI_SMH_xx(void);
+static void NEI_TMM_xx(void);
+static void NEI_V_xx(void);
+static void NOP(void);
+static void OFFAW_wa(void);
+static void OFFAX_B(void);
+static void OFFAX_D(void);
+static void OFFAX_Dm(void);
+static void OFFAX_Dp(void);
+static void OFFAX_H(void);
+static void OFFAX_Hm(void);
+static void OFFAX_Hp(void);
+static void OFFA_A_A(void);
+static void OFFA_A_B(void);
+static void OFFA_A_C(void);
+static void OFFA_A_D(void);
+static void OFFA_A_E(void);
+static void OFFA_A_H(void);
+static void OFFA_A_L(void);
+static void OFFA_A_V(void);
+static void OFFIW_wa_xx(void);
+static void OFFI_ANM_xx(void);
+static void OFFI_A_xx(void);
+static void OFFI_A_xx(void);
+static void OFFI_B_xx(void);
+static void OFFI_C_xx(void);
+static void OFFI_D_xx(void);
+static void OFFI_EOM_xx(void);
+static void OFFI_E_xx(void);
+static void OFFI_H_xx(void);
+static void OFFI_L_xx(void);
+static void OFFI_MKH_xx(void);
+static void OFFI_MKL_xx(void);
+static void OFFI_PA_xx(void);
+static void OFFI_PB_xx(void);
+static void OFFI_PC_xx(void);
+static void OFFI_PD_xx(void);
+static void OFFI_PF_xx(void);
+static void OFFI_SMH_xx(void);
+static void OFFI_TMM_xx(void);
+static void OFFI_V_xx(void);
+static void ONAW_wa(void);
+static void ONAX_B(void);
+static void ONAX_D(void);
+static void ONAX_Dm(void);
+static void ONAX_Dp(void);
+static void ONAX_H(void);
+static void ONAX_Hm(void);
+static void ONAX_Hp(void);
+static void ONA_A_A(void);
+static void ONA_A_B(void);
+static void ONA_A_C(void);
+static void ONA_A_D(void);
+static void ONA_A_E(void);
+static void ONA_A_H(void);
+static void ONA_A_L(void);
+static void ONA_A_V(void);
+static void ONIW_wa_xx(void);
+static void ONI_ANM_xx(void);
+static void ONI_A_xx(void);
+static void ONI_A_xx(void);
+static void ONI_B_xx(void);
+static void ONI_C_xx(void);
+static void ONI_D_xx(void);
+static void ONI_EOM_xx(void);
+static void ONI_E_xx(void);
+static void ONI_H_xx(void);
+static void ONI_L_xx(void);
+static void ONI_MKH_xx(void);
+static void ONI_MKL_xx(void);
+static void ONI_PA_xx(void);
+static void ONI_PB_xx(void);
+static void ONI_PC_xx(void);
+static void ONI_PD_xx(void);
+static void ONI_PF_xx(void);
+static void ONI_SMH_xx(void);
+static void ONI_TMM_xx(void);
+static void ONI_V_xx(void);
+static void ORAW_wa(void);
+static void ORAX_B(void);
+static void ORAX_D(void);
+static void ORAX_Dm(void);
+static void ORAX_Dp(void);
+static void ORAX_H(void);
+static void ORAX_Hm(void);
+static void ORAX_Hp(void);
+static void ORA_A_A(void);
+static void ORA_A_A(void);
+static void ORA_A_B(void);
+static void ORA_A_C(void);
+static void ORA_A_D(void);
+static void ORA_A_E(void);
+static void ORA_A_H(void);
+static void ORA_A_L(void);
+static void ORA_A_V(void);
+static void ORA_B_A(void);
+static void ORA_C_A(void);
+static void ORA_D_A(void);
+static void ORA_E_A(void);
+static void ORA_H_A(void);
+static void ORA_L_A(void);
+static void ORA_V_A(void);
+static void ORIW_wa_xx(void);
+static void ORI_ANM_xx(void);
+static void ORI_A_xx(void);
+static void ORI_A_xx(void);
+static void ORI_B_xx(void);
+static void ORI_C_xx(void);
+static void ORI_D_xx(void);
+static void ORI_EOM_xx(void);
+static void ORI_E_xx(void);
+static void ORI_H_xx(void);
+static void ORI_L_xx(void);
+static void ORI_MKH_xx(void);
+static void ORI_MKL_xx(void);
+static void ORI_PA_xx(void);
+static void ORI_PB_xx(void);
+static void ORI_PC_xx(void);
+static void ORI_PD_xx(void);
+static void ORI_PF_xx(void);
+static void ORI_SMH_xx(void);
+static void ORI_TMM_xx(void);
+static void ORI_V_xx(void);
+static void POP_BC(void);
+static void POP_DE(void);
+static void POP_EA(void);
+static void POP_HL(void);
+static void POP_VA(void);
+static void PRE_48(void);
+static void PRE_4C(void);
+static void PRE_4D(void);
+static void PRE_60(void);
+static void PRE_64(void);
+static void PRE_70(void);
+static void PRE_74(void);
+static void PUSH_BC(void);
+static void PUSH_DE(void);
+static void PUSH_EA(void);
+static void PUSH_HL(void);
+static void PUSH_VA(void);
+static void RET(void);
+static void RETI(void);
+static void RETS(void);
+static void RLD(void);
+static void RLL_A(void);
+static void RLL_B(void);
+static void RLL_C(void);
+static void RLR_A(void);
+static void RLR_B(void);
+static void RLR_C(void);
+static void RRD(void);
+static void SBBW_wa(void);
+static void SBBX_B(void);
+static void SBBX_D(void);
+static void SBBX_Dm(void);
+static void SBBX_Dp(void);
+static void SBBX_H(void);
+static void SBBX_Hm(void);
+static void SBBX_Hp(void);
+static void SBB_A_A(void);
+static void SBB_A_A(void);
+static void SBB_A_B(void);
+static void SBB_A_C(void);
+static void SBB_A_D(void);
+static void SBB_A_E(void);
+static void SBB_A_H(void);
+static void SBB_A_L(void);
+static void SBB_A_V(void);
+static void SBB_B_A(void);
+static void SBB_C_A(void);
+static void SBB_D_A(void);
+static void SBB_E_A(void);
+static void SBB_H_A(void);
+static void SBB_L_A(void);
+static void SBB_V_A(void);
+static void SBCD_w(void);
+static void SBI_ANM_xx(void);
+static void SBI_A_xx(void);
+static void SBI_A_xx(void);
+static void SBI_B_xx(void);
+static void SBI_C_xx(void);
+static void SBI_D_xx(void);
+static void SBI_EOM_xx(void);
+static void SBI_E_xx(void);
+static void SBI_H_xx(void);
+static void SBI_L_xx(void);
+static void SBI_MKH_xx(void);
+static void SBI_MKL_xx(void);
+static void SBI_PA_xx(void);
+static void SBI_PB_xx(void);
+static void SBI_PC_xx(void);
+static void SBI_PD_xx(void);
+static void SBI_PF_xx(void);
+static void SBI_SMH_xx(void);
+static void SBI_TMM_xx(void);
+static void SBI_V_xx(void);
+static void SDED_w(void);
+static void SETB(void);
+static void SHLD_w(void);
+static void SK_bit(void);
+static void SKN_bit(void);
+static void SKIT_AN4(void);
+static void SKIT_AN5(void);
+static void SKIT_AN6(void);
+static void SKIT_AN7(void);
+static void SKIT_ER(void);
+static void SKIT_F1(void);
+static void SKIT_F2(void);
+static void SKIT_FAD(void);
+static void SKIT_FE0(void);
+static void SKIT_FE1(void);
+static void SKIT_FEIN(void);
+static void SKIT_FSR(void);
+static void SKIT_FST(void);
+static void SKIT_FT0(void);
+static void SKIT_FT1(void);
+static void SKIT_NMI(void);
+static void SKIT_OV(void);
+static void SKIT_SB(void);
+static void SKNIT_AN4(void);
+static void SKNIT_AN5(void);
+static void SKNIT_AN6(void);
+static void SKNIT_AN7(void);
+static void SKNIT_ER(void);
+static void SKNIT_F1(void);
+static void SKNIT_F2(void);
+static void SKNIT_FAD(void);
+static void SKNIT_FE0(void);
+static void SKNIT_FE1(void);
+static void SKNIT_FEIN(void);
+static void SKNIT_FSR(void);
+static void SKNIT_FST(void);
+static void SKNIT_FT0(void);
+static void SKNIT_FT1(void);
+static void SKNIT_NMI(void);
+static void SKNIT_OV(void);
+static void SKNIT_SB(void);
+static void SKN_CY(void);
+static void SKN_HC(void);
+static void SKN_NV(void);
+static void SKN_Z(void);
+static void SK_CY(void);
+static void SK_HC(void);
+static void SK_NV(void);
+static void SK_Z(void);
+static void SLLC_A(void);
+static void SLLC_B(void);
+static void SLLC_C(void);
+static void SLL_A(void);
+static void SLL_B(void);
+static void SLL_C(void);
+static void SLRC_A(void);
+static void SLRC_B(void);
+static void SLRC_C(void);
+static void SLR_A(void);
+static void SLR_B(void);
+static void SLR_C(void);
+static void SOFTI(void);
+static void SSPD_w(void);
+static void STAW_wa(void);
+static void STAX_B(void);
+static void STAX_D(void);
+static void STAX_D_xx(void);
+static void STAX_Dm(void);
+static void STAX_Dp(void);
+static void STAX_H(void);
+static void STAX_H_A(void);
+static void STAX_H_B(void);
+static void STAX_H_EA(void);
+static void STAX_H_xx(void);
+static void STAX_Hm(void);
+static void STAX_Hp(void);
+static void STC(void);
+static void STEAX_D(void);
+static void STEAX_D_xx(void);
+static void STEAX_Dp(void);
+static void STEAX_H(void);
+static void STEAX_H_A(void);
+static void STEAX_H_B(void);
+static void STEAX_H_EA(void);
+static void STEAX_H_xx(void);
+static void STEAX_Hp(void);
+static void STOP(void);
+static void SUBNBW_wa(void);
+static void SUBNBX_B(void);
+static void SUBNBX_D(void);
+static void SUBNBX_Dm(void);
+static void SUBNBX_Dp(void);
+static void SUBNBX_H(void);
+static void SUBNBX_Hm(void);
+static void SUBNBX_Hp(void);
+static void SUBNB_A_A(void);
+static void SUBNB_A_A(void);
+static void SUBNB_A_B(void);
+static void SUBNB_A_C(void);
+static void SUBNB_A_D(void);
+static void SUBNB_A_E(void);
+static void SUBNB_A_H(void);
+static void SUBNB_A_L(void);
+static void SUBNB_A_V(void);
+static void SUBNB_B_A(void);
+static void SUBNB_C_A(void);
+static void SUBNB_D_A(void);
+static void SUBNB_E_A(void);
+static void SUBNB_H_A(void);
+static void SUBNB_L_A(void);
+static void SUBNB_V_A(void);
+static void SUBW_wa(void);
+static void SUBX_B(void);
+static void SUBX_D(void);
+static void SUBX_Dm(void);
+static void SUBX_Dp(void);
+static void SUBX_H(void);
+static void SUBX_Hm(void);
+static void SUBX_Hp(void);
+static void SUB_A_A(void);
+static void SUB_A_A(void);
+static void SUB_A_B(void);
+static void SUB_A_C(void);
+static void SUB_A_D(void);
+static void SUB_A_E(void);
+static void SUB_A_H(void);
+static void SUB_A_L(void);
+static void SUB_A_V(void);
+static void SUB_B_A(void);
+static void SUB_C_A(void);
+static void SUB_D_A(void);
+static void SUB_E_A(void);
+static void SUB_H_A(void);
+static void SUB_L_A(void);
+static void SUB_V_A(void);
+static void SUINB_ANM_xx(void);
+static void SUINB_A_xx(void);
+static void SUINB_A_xx(void);
+static void SUINB_B_xx(void);
+static void SUINB_C_xx(void);
+static void SUINB_D_xx(void);
+static void SUINB_EOM_xx(void);
+static void SUINB_E_xx(void);
+static void SUINB_H_xx(void);
+static void SUINB_L_xx(void);
+static void SUINB_MKH_xx(void);
+static void SUINB_MKL_xx(void);
+static void SUINB_PA_xx(void);
+static void SUINB_PB_xx(void);
+static void SUINB_PC_xx(void);
+static void SUINB_PD_xx(void);
+static void SUINB_PF_xx(void);
+static void SUINB_SMH_xx(void);
+static void SUINB_TMM_xx(void);
+static void SUINB_V_xx(void);
+static void SUI_ANM_xx(void);
+static void SUI_A_xx(void);
+static void SUI_A_xx(void);
+static void SUI_B_xx(void);
+static void SUI_C_xx(void);
+static void SUI_D_xx(void);
+static void SUI_EOM_xx(void);
+static void SUI_E_xx(void);
+static void SUI_H_xx(void);
+static void SUI_L_xx(void);
+static void SUI_MKH_xx(void);
+static void SUI_MKL_xx(void);
+static void SUI_PA_xx(void);
+static void SUI_PB_xx(void);
+static void SUI_PC_xx(void);
+static void SUI_PD_xx(void);
+static void SUI_PF_xx(void);
+static void SUI_SMH_xx(void);
+static void SUI_TMM_xx(void);
+static void SUI_V_xx(void);
+static void TABLE(void);
+static void XRAW_wa(void);
+static void XRAX_B(void);
+static void XRAX_D(void);
+static void XRAX_Dm(void);
+static void XRAX_Dp(void);
+static void XRAX_H(void);
+static void XRAX_Hm(void);
+static void XRAX_Hp(void);
+static void XRA_A_A(void);
+static void XRA_A_A(void);
+static void XRA_A_B(void);
+static void XRA_A_C(void);
+static void XRA_A_D(void);
+static void XRA_A_E(void);
+static void XRA_A_H(void);
+static void XRA_A_L(void);
+static void XRA_A_V(void);
+static void XRA_B_A(void);
+static void XRA_C_A(void);
+static void XRA_D_A(void);
+static void XRA_E_A(void);
+static void XRA_H_A(void);
+static void XRA_L_A(void);
+static void XRA_V_A(void);
+static void XRI_ANM_xx(void);
+static void XRI_A_xx(void);
+static void XRI_A_xx(void);
+static void XRI_B_xx(void);
+static void XRI_C_xx(void);
+static void XRI_D_xx(void);
+static void XRI_EOM_xx(void);
+static void XRI_E_xx(void);
+static void XRI_H_xx(void);
+static void XRI_L_xx(void);
+static void XRI_MKH_xx(void);
+static void XRI_MKL_xx(void);
+static void XRI_PA_xx(void);
+static void XRI_PB_xx(void);
+static void XRI_PC_xx(void);
+static void XRI_PD_xx(void);
+static void XRI_PF_xx(void);
+static void XRI_SMH_xx(void);
+static void XRI_TMM_xx(void);
+static void XRI_V_xx(void);
+
+static struct opcode_s op48[256] =
+{
+ {illegal, 2, 8, 8,L0|L1}, /* 00: 0100 1000 0000 0000 */
+ {SLRC_A, 2, 8, 8,L0|L1}, /* 01: 0100 1000 0000 0001 */
+ {SLRC_B, 2, 8, 8,L0|L1}, /* 02: 0100 1000 0000 0010 */
+ {SLRC_C, 2, 8, 8,L0|L1}, /* 03: 0100 1000 0000 0011 */
+ {illegal, 2, 8, 8,L0|L1}, /* 04: 0100 1000 0000 0100 */
+ {SLLC_A, 2, 8, 8,L0|L1}, /* 05: 0100 1000 0000 0101 */
+ {SLLC_B, 2, 8, 8,L0|L1}, /* 06: 0100 1000 0000 0110 */
+ {SLLC_C, 2, 8, 8,L0|L1}, /* 07: 0100 1000 0000 0111 */
+ {SK_NV, 2, 8, 8,L0|L1}, /* 08: 0100 1000 0000 1000 */
+ {illegal, 2, 8, 8,L0|L1}, /* 09: 0100 1000 0000 1001 */
+ {SK_CY, 2, 8, 8,L0|L1}, /* 0a: 0100 1000 0000 1010 */
+ {SK_HC, 2, 8, 8,L0|L1}, /* 0b: 0100 1000 0000 1011 */
+ {SK_Z, 2, 8, 8,L0|L1}, /* 0c: 0100 1000 0000 1100 */
+ {illegal, 2, 8, 8,L0|L1}, /* 0d: 0100 1000 0000 1101 */
+ {illegal, 2, 8, 8,L0|L1}, /* 0e: 0100 1000 0000 1110 */
+ {illegal, 2, 8, 8,L0|L1}, /* 0f: 0100 1000 0000 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 10: 0100 1000 0001 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 11: 0100 1000 0001 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 12: 0100 1000 0001 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 13: 0100 1000 0001 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 14: 0100 1000 0001 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 15: 0100 1000 0001 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 16: 0100 1000 0001 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 17: 0100 1000 0001 0111 */
+ {SKN_NV, 2, 8, 8,L0|L1}, /* 18: 0100 1000 0001 1000 */
+ {illegal, 2, 8, 8,L0|L1}, /* 19: 0100 1000 0001 1001 */
+ {SKN_CY, 2, 8, 8,L0|L1}, /* 1a: 0100 1000 0001 1010 */
+ {SKN_HC, 2, 8, 8,L0|L1}, /* 1b: 0100 1000 0001 1011 */
+ {SKN_Z, 2, 8, 8,L0|L1}, /* 1c: 0100 1000 0001 1100 */
+ {illegal, 2, 8, 8,L0|L1}, /* 1d: 0100 1000 0001 1101 */
+ {illegal, 2, 8, 8,L0|L1}, /* 1e: 0100 1000 0001 1110 */
+ {illegal, 2, 8, 8,L0|L1}, /* 1f: 0100 1000 0001 1111 */
+
+ {illegal, 2, 8, 8,L0|L1}, /* 20: 0100 1000 0010 0000 */
+ {SLR_A, 2, 8, 8,L0|L1}, /* 21: 0100 1000 0010 0001 */
+ {SLR_B, 2, 8, 8,L0|L1}, /* 22: 0100 1000 0010 0010 */
+ {SLR_C, 2, 8, 8,L0|L1}, /* 23: 0100 1000 0010 0011 */
+ {illegal, 2, 8, 8,L0|L1}, /* 24: 0100 1000 0010 0100 */
+ {SLL_A, 2, 8, 8,L0|L1}, /* 25: 0100 1000 0010 0101 */
+ {SLL_B, 2, 8, 8,L0|L1}, /* 26: 0100 1000 0010 0110 */
+ {SLL_C, 2, 8, 8,L0|L1}, /* 27: 0100 1000 0010 0111 */
+ {JEA, 2, 8, 8,L0|L1}, /* 28: 0100 1000 0010 1000 */
+ {CALB, 2,17,17,L0|L1}, /* 29: 0100 1000 0010 1001 */
+ {CLC, 2, 8, 8,L0|L1}, /* 2a: 0100 1000 0010 1010 */
+ {STC, 2, 8, 8,L0|L1}, /* 2b: 0100 1000 0010 1011 */
+ {illegal, 2,32,32,L0|L1}, /* 2c: 0100 1000 0010 1100 */
+ {MUL_A, 2,32,32,L0|L1}, /* 2d: 0100 1000 0010 1101 */
+ {MUL_B, 2,32,32,L0|L1}, /* 2e: 0100 1000 0010 1110 */
+ {MUL_C, 2,32,32,L0|L1}, /* 2f: 0100 1000 0010 1111 */
+
+ {illegal, 2, 8, 8,L0|L1}, /* 30: 0100 1000 0011 0000 */
+ {RLR_A, 2, 8, 8,L0|L1}, /* 31: 0100 1000 0011 0001 */
+ {RLR_B, 2, 8, 8,L0|L1}, /* 32: 0100 1000 0011 0010 */
+ {RLR_C, 2, 8, 8,L0|L1}, /* 33: 0100 1000 0011 0011 */
+ {illegal, 2, 8, 8,L0|L1}, /* 34: 0100 1000 0011 0100 */
+ {RLL_A, 2, 8, 8,L0|L1}, /* 35: 0100 1000 0011 0101 */
+ {RLL_B, 2, 8, 8,L0|L1}, /* 36: 0100 1000 0011 0110 */
+ {RLL_C, 2, 8, 8,L0|L1}, /* 37: 0100 1000 0011 0111 */
+ {RLD, 2,17,17,L0|L1}, /* 38: 0100 1000 0011 1000 */
+ {RRD, 2,17,17,L0|L1}, /* 39: 0100 1000 0011 1001 */
+ {NEGA, 2, 8, 8,L0|L1}, /* 3a: 0100 1000 0011 1010 */
+ {HALT, 2,12,12,L0|L1}, /* 3b: 0100 1000 0011 1011 */
+ {illegal, 2, 8, 8,L0|L1}, /* 3c: 0100 1000 0011 1100 */
+ {DIV_A, 2,59,59,L0|L1}, /* 3d: 0100 1000 0011 1101 */
+ {DIV_B, 2,59,59,L0|L1}, /* 3e: 0100 1000 0011 1110 */
+ {DIV_C, 2,59,59,L0|L1}, /* 3f: 0100 1000 0011 1111 */
+
+ {SKIT_NMI, 2, 8, 8,L0|L1}, /* 40: 0100 1000 0100 0000 */
+ {SKIT_FT0, 2, 8, 8,L0|L1}, /* 41: 0100 1000 0100 0001 */
+ {SKIT_FT1, 2, 8, 8,L0|L1}, /* 42: 0100 1000 0100 0010 */
+ {SKIT_F1, 2, 8, 8,L0|L1}, /* 43: 0100 1000 0100 0011 */
+ {SKIT_F2, 2, 8, 8,L0|L1}, /* 44: 0100 1000 0100 0100 */
+ {SKIT_FE0, 2, 8, 8,L0|L1}, /* 45: 0100 1000 0100 0101 */
+ {SKIT_FE1, 2, 8, 8,L0|L1}, /* 46: 0100 1000 0100 0110 */
+ {SKIT_FEIN, 2, 8, 8,L0|L1}, /* 47: 0100 1000 0100 0111 */
+ {SKIT_FAD, 2, 8, 8,L0|L1}, /* 48: 0100 1000 0100 1000 */
+ {SKIT_FSR, 2, 8, 8,L0|L1}, /* 49: 0100 1000 0100 1001 */
+ {SKIT_FST, 2, 8, 8,L0|L1}, /* 4a: 0100 1000 0100 1010 */
+ {SKIT_ER, 2, 8, 8,L0|L1}, /* 4b: 0100 1000 0100 1011 */
+ {SKIT_OV, 2, 8, 8,L0|L1}, /* 4c: 0100 1000 0100 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4d: 0100 1000 0100 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4e: 0100 1000 0100 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4f: 0100 1000 0100 1111 */
+
+ {SKIT_AN4, 2, 8, 8,L0|L1}, /* 50: 0100 1000 0101 0000 */
+ {SKIT_AN5, 2, 8, 8,L0|L1}, /* 51: 0100 1000 0101 0001 */
+ {SKIT_AN6, 2, 8, 8,L0|L1}, /* 52: 0100 1000 0101 0010 */
+ {SKIT_AN7, 2, 8, 8,L0|L1}, /* 53: 0100 1000 0101 0011 */
+ {SKIT_SB, 2, 8, 8,L0|L1}, /* 54: 0100 1000 0101 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 55: 0100 1000 0101 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 56: 0100 1000 0101 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 57: 0100 1000 0101 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 58: 0100 1000 0101 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 59: 0100 1000 0101 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5a: 0100 1000 0101 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5b: 0100 1000 0101 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5c: 0100 1000 0101 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5d: 0100 1000 0101 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5e: 0100 1000 0101 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5f: 0100 1000 0101 1111 */
+
+ {SKNIT_NMI, 2, 8, 8,L0|L1}, /* 60: 0100 1000 0110 0000 */
+ {SKNIT_FT0, 2, 8, 8,L0|L1}, /* 61: 0100 1000 0110 0001 */
+ {SKNIT_FT1, 2, 8, 8,L0|L1}, /* 62: 0100 1000 0110 0010 */
+ {SKNIT_F1, 2, 8, 8,L0|L1}, /* 63: 0100 1000 0110 0011 */
+ {SKNIT_F2, 2, 8, 8,L0|L1}, /* 64: 0100 1000 0110 0100 */
+ {SKNIT_FE0, 2, 8, 8,L0|L1}, /* 65: 0100 1000 0110 0101 */
+ {SKNIT_FE1, 2, 8, 8,L0|L1}, /* 66: 0100 1000 0110 0110 */
+ {SKNIT_FEIN, 2, 8, 8,L0|L1}, /* 67: 0100 1000 0110 0111 */
+ {SKNIT_FAD, 2, 8, 8,L0|L1}, /* 68: 0100 1000 0110 1000 */
+ {SKNIT_FSR, 2, 8, 8,L0|L1}, /* 69: 0100 1000 0110 1001 */
+ {SKNIT_FST, 2, 8, 8,L0|L1}, /* 6a: 0100 1000 0110 1010 */
+ {SKNIT_ER, 2, 8, 8,L0|L1}, /* 6b: 0100 1000 0110 1011 */
+ {SKNIT_OV, 2, 8, 8,L0|L1}, /* 6c: 0100 1000 0110 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6d: 0100 1000 0110 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6e: 0100 1000 0110 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6f: 0100 1000 0110 1111 */
+
+ {SKNIT_AN4, 2, 8, 8,L0|L1}, /* 70: 0100 1000 0111 0000 */
+ {SKNIT_AN5, 2, 8, 8,L0|L1}, /* 71: 0100 1000 0111 0001 */
+ {SKNIT_AN6, 2, 8, 8,L0|L1}, /* 72: 0100 1000 0111 0010 */
+ {SKNIT_AN7, 2, 8, 8,L0|L1}, /* 73: 0100 1000 0111 0011 */
+ {SKNIT_SB, 2, 8, 8,L0|L1}, /* 74: 0100 1000 0111 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 75: 0100 1000 0111 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 76: 0100 1000 0111 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 77: 0100 1000 0111 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 78: 0100 1000 0111 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 79: 0100 1000 0111 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7a: 0100 1000 0111 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7b: 0100 1000 0111 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7c: 0100 1000 0111 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7d: 0100 1000 0111 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7e: 0100 1000 0111 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7f: 0100 1000 0111 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 80: 0100 1000 1000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 81: 0100 1000 1000 0001 */
+ {LDEAX_D, 2,14,11,L0|L1}, /* 82: 0100 1000 1000 0010 */
+ {LDEAX_H, 2,14,11,L0|L1}, /* 83: 0100 1000 1000 0011 */
+ {LDEAX_Dp, 2,14,11,L0|L1}, /* 84: 0100 1000 1000 0100 */
+ {LDEAX_Hp, 2,14,11,L0|L1}, /* 85: 0100 1000 1000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 86: 0100 1000 1000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 87: 0100 1000 1000 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 88: 0100 1000 1000 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 89: 0100 1000 1000 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8a: 0100 1000 1000 1010 */
+ {LDEAX_D_xx, 3,20,20,L0|L1}, /* 8b: 0100 1000 1000 1011 xxxx xxxx */
+ {LDEAX_H_A, 2,20,20,L0|L1}, /* 8c: 0100 1000 1000 1100 */
+ {LDEAX_H_B, 2,20,20,L0|L1}, /* 8d: 0100 1000 1000 1101 */
+ {LDEAX_H_EA, 2,20,20,L0|L1}, /* 8e: 0100 1000 1000 1110 */
+ {LDEAX_H_xx, 3,20,20,L0|L1}, /* 8f: 0100 1000 1000 1111 xxxx xxxx */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 90: 0100 1000 1000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 91: 0100 1000 1000 0001 */
+ {STEAX_D, 2,14,11,L0|L1}, /* 92: 0100 1000 1000 0010 */
+ {STEAX_H, 2,14,11,L0|L1}, /* 93: 0100 1000 1000 0011 */
+ {STEAX_Dp, 2,14,11,L0|L1}, /* 94: 0100 1000 1000 0100 */
+ {STEAX_Hp, 2,14,11,L0|L1}, /* 95: 0100 1000 1000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 96: 0100 1000 1000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 97: 0100 1000 1000 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 98: 0100 1000 1000 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 99: 0100 1000 1000 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9a: 0100 1000 1000 1010 */
+ {STEAX_D_xx, 3,20,20,L0|L1}, /* 9b: 0100 1000 1000 1011 xxxx xxxx */
+ {STEAX_H_A, 2,20,20,L0|L1}, /* 9c: 0100 1000 1000 1100 */
+ {STEAX_H_B, 2,20,20,L0|L1}, /* 9d: 0100 1000 1000 1101 */
+ {STEAX_H_EA, 2,20,20,L0|L1}, /* 9e: 0100 1000 1000 1110 */
+ {STEAX_H_xx, 3,20,20,L0|L1}, /* 9f: 0100 1000 1000 1111 xxxx xxxx */
+
+ {DSLR_EA, 2, 8, 8,L0|L1}, /* a0: 0100 1000 1010 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a1: 0100 1000 1010 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a2: 0100 1000 1010 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a3: 0100 1000 1010 0011 */
+ {DSLL_EA, 2, 8, 8,L0|L1}, /* a4: 0100 1000 1010 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a5: 0100 1000 1010 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a6: 0100 1000 1010 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a7: 0100 1000 1010 0111 */
+ {TABLE, 2,17,17,L0|L1}, /* a8: 0100 1000 1010 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a9: 0100 1000 1010 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* aa: 0100 1000 1010 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ab: 0100 1000 1010 1011 */
+// {illegal2, 2, 8, 8,L0|L1}, /* ac: 0100 1000 1010 1100 */
+// {illegal2, 2, 8, 8,L0|L1}, /* ad: 0100 1000 1010 1101 */
+// {illegal2, 2, 8, 8,L0|L1}, /* ae: 0100 1000 1010 1110 */
+// {illegal2, 2, 8, 8,L0|L1}, /* af: 0100 1000 1010 1111 */
+ {EXA, 2, 8, 8,L0|L1}, /* ac: 0100 1000 1010 1100 */ /* 7807 */
+ {EXR, 2, 8, 8,L0|L1}, /* ad: 0100 1000 1010 1101 */ /* 7807 */
+ {EXH, 2, 8, 8,L0|L1}, /* ae: 0100 1000 1010 1110 */ /* 7807 */
+ {EXX, 2, 8, 8,L0|L1}, /* af: 0100 1000 1010 1111 */ /* 7807 */
+ {DRLR_EA, 2, 8, 8,L0|L1}, /* b0: 0100 1000 1011 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b1: 0100 1000 1011 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b2: 0100 1000 1011 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b3: 0100 1000 1011 0011 */
+ {DRLL_EA, 2, 8, 8,L0|L1}, /* b4: 0100 1000 1011 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b5: 0100 1000 1011 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b6: 0100 1000 1011 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b7: 0100 1000 1011 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b8: 0100 1000 1011 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b9: 0100 1000 1011 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ba: 0100 1000 1011 1010 */
+ {STOP, 2,12,12,L0|L1}, /* bb: 0100 1000 1011 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bc: 0100 1000 1011 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bd: 0100 1000 1011 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* be: 0100 1000 1011 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bf: 0100 1000 1011 1111 */
+
+ {DMOV_EA_ECNT, 2,14,11,L0|L1}, /* c0: 0100 1000 1100 0000 */
+ {DMOV_EA_ECPT, 2,14,11,L0|L1}, /* c1: 0100 1000 1100 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c2: 0100 1000 1100 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c3: 0100 1000 1100 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c4: 0100 1000 1100 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c5: 0100 1000 1100 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c6: 0100 1000 1100 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c7: 0100 1000 1100 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c8: 0100 1000 1100 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c9: 0100 1000 1100 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ca: 0100 1000 1100 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* cb: 0100 1000 1100 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* cc: 0100 1000 1100 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* cd: 0100 1000 1100 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ce: 0100 1000 1100 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* cf: 0100 1000 1100 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* d0: 0100 1000 1101 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d1: 0100 1000 1101 0001 */
+ {DMOV_ETM0_EA, 2,14,11,L0|L1}, /* d2: 0100 1000 1101 0010 */
+ {DMOV_ETM1_EA, 2,14,11,L0|L1}, /* d3: 0100 1000 1101 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d4: 0100 1000 1101 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d5: 0100 1000 1101 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d6: 0100 1000 1101 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d7: 0100 1000 1101 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d8: 0100 1000 1101 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d9: 0100 1000 1101 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* da: 0100 1000 1101 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* db: 0100 1000 1101 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* dc: 0100 1000 1101 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* dd: 0100 1000 1101 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* de: 0100 1000 1101 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* df: 0100 1000 1101 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* e0: 0100 1000 1110 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e1: 0100 1000 1110 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e2: 0100 1000 1110 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e3: 0100 1000 1110 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e4: 0100 1000 1110 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e5: 0100 1000 1110 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e6: 0100 1000 1110 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e7: 0100 1000 1110 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e8: 0100 1000 1110 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e9: 0100 1000 1110 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ea: 0100 1000 1110 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* eb: 0100 1000 1110 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ec: 0100 1000 1110 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ed: 0100 1000 1110 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ee: 0100 1000 1110 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ef: 0100 1000 1110 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* f0: 0100 1000 1111 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f1: 0100 1000 1111 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f2: 0100 1000 1111 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f3: 0100 1000 1111 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f4: 0100 1000 1111 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f5: 0100 1000 1111 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f6: 0100 1000 1111 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f7: 0100 1000 1111 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f8: 0100 1000 1111 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f9: 0100 1000 1111 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* fa: 0100 1000 1111 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* fb: 0100 1000 1111 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* fc: 0100 1000 1111 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* fd: 0100 1000 1111 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* fe: 0100 1000 1111 1110 */
+ {illegal2, 2, 8, 8,L0|L1} /* ff: 0100 1000 1111 1111 */
+};
+
+/* prefix 4C */
+static struct opcode_s op4C[256] =
+{
+ {illegal2, 2, 8, 8,L0|L1}, /* 00: 0100 1100 0000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 01: 0100 1100 0000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 02: 0100 1100 0000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 03: 0100 1100 0000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 04: 0100 1100 0000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 05: 0100 1100 0000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 06: 0100 1100 0000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 07: 0100 1100 0000 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 08: 0100 1100 0000 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 09: 0100 1100 0000 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0a: 0100 1100 0000 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0b: 0100 1100 0000 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0c: 0100 1100 0000 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0d: 0100 1100 0000 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0e: 0100 1100 0000 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0f: 0100 1100 0000 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 10: 0100 1100 0001 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 11: 0100 1100 0001 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 12: 0100 1100 0001 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 13: 0100 1100 0001 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 14: 0100 1100 0001 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 15: 0100 1100 0001 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 16: 0100 1100 0001 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 17: 0100 1100 0001 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 18: 0100 1100 0001 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 19: 0100 1100 0001 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1a: 0100 1100 0001 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1b: 0100 1100 0001 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1c: 0100 1100 0001 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1d: 0100 1100 0001 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1e: 0100 1100 0001 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1f: 0100 1100 0001 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 20: 0100 1100 0010 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 21: 0100 1100 0010 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 22: 0100 1100 0010 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 23: 0100 1100 0010 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 24: 0100 1100 0010 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 25: 0100 1100 0010 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 26: 0100 1100 0010 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 27: 0100 1100 0010 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 28: 0100 1100 0010 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 29: 0100 1100 0010 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2a: 0100 1100 0010 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2b: 0100 1100 0010 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2c: 0100 1100 0010 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2d: 0100 1100 0010 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2e: 0100 1100 0010 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2f: 0100 1100 0010 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 30: 0100 1100 0011 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 31: 0100 1100 0011 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 32: 0100 1100 0011 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 33: 0100 1100 0011 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 34: 0100 1100 0011 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 35: 0100 1100 0011 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 36: 0100 1100 0011 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 37: 0100 1100 0011 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 38: 0100 1100 0011 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 39: 0100 1100 0011 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3a: 0100 1100 0011 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3b: 0100 1100 0011 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3c: 0100 1100 0011 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3d: 0100 1100 0011 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3e: 0100 1100 0011 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3f: 0100 1100 0011 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 40: 0100 1100 0100 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 41: 0100 1100 0100 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 42: 0100 1100 0100 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 43: 0100 1100 0100 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 44: 0100 1100 0100 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 45: 0100 1100 0100 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 46: 0100 1100 0100 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 47: 0100 1100 0100 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 48: 0100 1100 0100 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 49: 0100 1100 0100 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4a: 0100 1100 0100 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4b: 0100 1100 0100 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4c: 0100 1100 0100 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4d: 0100 1100 0100 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4e: 0100 1100 0100 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4f: 0100 1100 0100 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 50: 0100 1100 0101 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 51: 0100 1100 0101 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 52: 0100 1100 0101 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 53: 0100 1100 0101 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 54: 0100 1100 0101 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 55: 0100 1100 0101 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 56: 0100 1100 0101 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 57: 0100 1100 0101 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 58: 0100 1100 0101 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 59: 0100 1100 0101 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5a: 0100 1100 0101 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5b: 0100 1100 0101 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5c: 0100 1100 0101 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5d: 0100 1100 0101 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5e: 0100 1100 0101 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5f: 0100 1100 0101 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 60: 0100 1100 0110 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 61: 0100 1100 0110 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 62: 0100 1100 0110 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 63: 0100 1100 0110 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 64: 0100 1100 0110 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 65: 0100 1100 0110 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 66: 0100 1100 0110 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 67: 0100 1100 0110 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 68: 0100 1100 0110 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 69: 0100 1100 0110 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6a: 0100 1100 0110 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6b: 0100 1100 0110 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6c: 0100 1100 0110 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6d: 0100 1100 0110 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6e: 0100 1100 0110 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6f: 0100 1100 0110 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 70: 0100 1100 0111 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 71: 0100 1100 0111 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 72: 0100 1100 0111 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 73: 0100 1100 0111 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 74: 0100 1100 0111 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 75: 0100 1100 0111 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 76: 0100 1100 0111 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 77: 0100 1100 0111 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 78: 0100 1100 0111 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 79: 0100 1100 0111 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7a: 0100 1100 0111 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7b: 0100 1100 0111 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7c: 0100 1100 0111 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7d: 0100 1100 0111 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7e: 0100 1100 0111 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7f: 0100 1100 0111 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 80: 0100 1100 1000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 81: 0100 1100 1000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 82: 0100 1100 1000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 83: 0100 1100 1000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 84: 0100 1100 1000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 85: 0100 1100 1000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 86: 0100 1100 1000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 87: 0100 1100 1000 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 88: 0100 1100 1000 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 89: 0100 1100 1000 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8a: 0100 1100 1000 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8b: 0100 1100 1000 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8c: 0100 1100 1000 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8d: 0100 1100 1000 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8e: 0100 1100 1000 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8f: 0100 1100 1000 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 90: 0100 1100 1001 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 91: 0100 1100 1001 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 92: 0100 1100 1001 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 93: 0100 1100 1001 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 94: 0100 1100 1001 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 95: 0100 1100 1001 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 96: 0100 1100 1001 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 97: 0100 1100 1001 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 98: 0100 1100 1001 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 99: 0100 1100 1001 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9a: 0100 1100 1001 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9b: 0100 1100 1001 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9c: 0100 1100 1001 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9d: 0100 1100 1001 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9e: 0100 1100 1001 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9f: 0100 1100 1001 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* a0: 0100 1100 1010 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a1: 0100 1100 1010 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a2: 0100 1100 1010 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a3: 0100 1100 1010 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a4: 0100 1100 1010 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a5: 0100 1100 1010 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a6: 0100 1100 1010 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a7: 0100 1100 1010 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a8: 0100 1100 1010 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a9: 0100 1100 1010 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* aa: 0100 1100 1010 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ab: 0100 1100 1010 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ac: 0100 1100 1010 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ad: 0100 1100 1010 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ae: 0100 1100 1010 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* af: 0100 1100 1010 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* b0: 0100 1100 1011 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b1: 0100 1100 1011 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b2: 0100 1100 1011 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b3: 0100 1100 1011 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b4: 0100 1100 1011 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b5: 0100 1100 1011 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b6: 0100 1100 1011 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b7: 0100 1100 1011 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b8: 0100 1100 1011 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b9: 0100 1100 1011 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ba: 0100 1100 1011 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bb: 0100 1100 1011 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bc: 0100 1100 1011 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bd: 0100 1100 1011 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* be: 0100 1100 1011 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bf: 0100 1100 1011 1111 */
+
+ {MOV_A_PA, 2,10,10,L0|L1}, /* c0: 0100 1100 1100 0000 */
+ {MOV_A_PB, 2,10,10,L0|L1}, /* c1: 0100 1100 1100 0001 */
+ {MOV_A_PC, 2,10,10,L0|L1}, /* c2: 0100 1100 1100 0010 */
+ {MOV_A_PD, 2,10,10,L0|L1}, /* c3: 0100 1100 1100 0011 */
+ {illegal2, 2,10,10,L0|L1}, /* c4: 0100 1100 1100 0100 */
+ {MOV_A_PF, 2,10,10,L0|L1}, /* c5: 0100 1100 1100 0101 */
+ {MOV_A_MKH, 2,10,10,L0|L1}, /* c6: 0100 1100 1100 0110 */
+ {MOV_A_MKL, 2,10,10,L0|L1}, /* c7: 0100 1100 1100 0111 */
+ {MOV_A_ANM, 2,10,10,L0|L1}, /* c8: 0100 1100 1100 1000 */
+ {MOV_A_SMH, 2,10,10,L0|L1}, /* c9: 0100 1100 1100 1001 */
+ {illegal2, 2,10,10,L0|L1}, /* ca: 0100 1100 1100 1010 */
+ {MOV_A_EOM, 2,10,10,L0|L1}, /* cb: 0100 1100 1100 1011 */
+ {illegal2, 2,10,10,L0|L1}, /* cc: 0100 1100 1100 1100 */
+ {MOV_A_TMM, 2,10,10,L0|L1}, /* cd: 0100 1100 1100 1101 */
+// {illegal2, 2,10,10,L0|L1}, /* ce: 0100 1100 1100 1110 */
+ {MOV_A_PT, 2,10,10,L0|L1}, /* ce: 0100 1100 1100 1110 */ /* 7807 */
+ {illegal2, 2,10,10,L0|L1}, /* cf: 0100 1100 1100 1111 */
+
+ {illegal2, 2,10,10,L0|L1}, /* d0: 0100 1100 1101 0000 */
+ {illegal2, 2,10,10,L0|L1}, /* d1: 0100 1100 1101 0001 */
+ {illegal2, 2,10,10,L0|L1}, /* d2: 0100 1100 1101 0010 */
+ {illegal2, 2,10,10,L0|L1}, /* d3: 0100 1100 1101 0011 */
+ {illegal2, 2,10,10,L0|L1}, /* d4: 0100 1100 1101 0100 */
+ {illegal2, 2,10,10,L0|L1}, /* d5: 0100 1100 1101 0101 */
+ {illegal2, 2,10,10,L0|L1}, /* d6: 0100 1100 1101 0110 */
+ {illegal2, 2,10,10,L0|L1}, /* d7: 0100 1100 1101 0111 */
+ {illegal2, 2,10,10,L0|L1}, /* d8: 0100 1100 1101 1000 */
+ {MOV_A_RXB, 2,10,10,L0|L1}, /* d9: 0100 1100 1101 1001 */
+ {illegal2, 2,10,10,L0|L1}, /* da: 0100 1100 1101 1010 */
+ {illegal2, 2,10,10,L0|L1}, /* db: 0100 1100 1101 1011 */
+ {illegal2, 2,10,10,L0|L1}, /* dc: 0100 1100 1101 1100 */
+ {illegal2, 2,10,10,L0|L1}, /* dd: 0100 1100 1101 1101 */
+ {illegal2, 2,10,10,L0|L1}, /* de: 0100 1100 1101 1110 */
+ {illegal2, 2,10,10,L0|L1}, /* df: 0100 1100 1101 1111 */
+
+ {MOV_A_CR0, 2,10,10,L0|L1}, /* e0: 0100 1100 1110 0000 */
+ {MOV_A_CR1, 2,10,10,L0|L1}, /* e1: 0100 1100 1110 0001 */
+ {MOV_A_CR2, 2,10,10,L0|L1}, /* e2: 0100 1100 1110 0010 */
+ {MOV_A_CR3, 2,10,10,L0|L1}, /* e3: 0100 1100 1110 0011 */
+ {illegal2, 2,10,10,L0|L1}, /* e4: 0100 1100 1110 0100 */
+ {illegal2, 2,10,10,L0|L1}, /* e5: 0100 1100 1110 0101 */
+ {illegal2, 2,10,10,L0|L1}, /* e6: 0100 1100 1110 0110 */
+ {illegal2, 2,10,10,L0|L1}, /* e7: 0100 1100 1110 0111 */
+ {illegal2, 2,10,10,L0|L1}, /* e8: 0100 1100 1110 1000 */
+ {illegal2, 2,10,10,L0|L1}, /* e9: 0100 1100 1110 1001 */
+ {illegal2, 2,10,10,L0|L1}, /* ea: 0100 1100 1110 1010 */
+ {illegal2, 2,10,10,L0|L1}, /* eb: 0100 1100 1110 1011 */
+ {illegal2, 2,10,10,L0|L1}, /* ec: 0100 1100 1110 1100 */
+ {illegal2, 2,10,10,L0|L1}, /* ed: 0100 1100 1110 1101 */
+ {illegal2, 2,10,10,L0|L1}, /* ee: 0100 1100 1110 1110 */
+ {illegal2, 2,10,10,L0|L1}, /* ef: 0100 1100 1110 1111 */
+
+ {illegal2, 2,10,10,L0|L1}, /* f0: 0100 1100 1111 0000 */
+ {illegal2, 2,10,10,L0|L1}, /* f1: 0100 1100 1111 0001 */
+ {illegal2, 2,10,10,L0|L1}, /* f2: 0100 1100 1111 0010 */
+ {illegal2, 2,10,10,L0|L1}, /* f3: 0100 1100 1111 0011 */
+ {illegal2, 2,10,10,L0|L1}, /* f4: 0100 1100 1111 0100 */
+ {illegal2, 2,10,10,L0|L1}, /* f5: 0100 1100 1111 0101 */
+ {illegal2, 2,10,10,L0|L1}, /* f6: 0100 1100 1111 0110 */
+ {illegal2, 2,10,10,L0|L1}, /* f7: 0100 1100 1111 0111 */
+ {illegal2, 2,10,10,L0|L1}, /* f8: 0100 1100 1111 1000 */
+ {illegal2, 2,10,10,L0|L1}, /* f9: 0100 1100 1111 1001 */
+ {illegal2, 2,10,10,L0|L1}, /* fa: 0100 1100 1111 1010 */
+ {illegal2, 2,10,10,L0|L1}, /* fb: 0100 1100 1111 1011 */
+ {illegal2, 2,10,10,L0|L1}, /* fc: 0100 1100 1111 1100 */
+ {illegal2, 2,10,10,L0|L1}, /* fd: 0100 1100 1111 1101 */
+ {illegal2, 2,10,10,L0|L1}, /* fe: 0100 1100 1111 1110 */
+ {illegal2, 2,10,10,L0|L1}, /* ff: 0100 1100 1111 1111 */
+};
+
+/* prefix 4D */
+static struct opcode_s op4D[256] =
+{
+ {illegal2, 2, 8, 8,L0|L1}, /* 00: 0100 1101 0000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 01: 0100 1101 0000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 02: 0100 1101 0000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 03: 0100 1101 0000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 04: 0100 1101 0000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 05: 0100 1101 0000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 06: 0100 1101 0000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 07: 0100 1101 0000 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 08: 0100 1101 0000 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 09: 0100 1101 0000 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0a: 0100 1101 0000 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0b: 0100 1101 0000 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0c: 0100 1101 0000 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0d: 0100 1101 0000 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0e: 0100 1101 0000 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0f: 0100 1101 0000 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 10: 0100 1101 0001 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 11: 0100 1101 0001 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 12: 0100 1101 0001 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 13: 0100 1101 0001 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 14: 0100 1101 0001 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 15: 0100 1101 0001 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 16: 0100 1101 0001 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 17: 0100 1101 0001 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 18: 0100 1101 0001 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 19: 0100 1101 0001 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1a: 0100 1101 0001 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1b: 0100 1101 0001 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1c: 0100 1101 0001 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1d: 0100 1101 0001 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1e: 0100 1101 0001 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1f: 0100 1101 0001 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 20: 0100 1101 0010 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 21: 0100 1101 0010 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 22: 0100 1101 0010 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 23: 0100 1101 0010 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 24: 0100 1101 0010 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 25: 0100 1101 0010 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 26: 0100 1101 0010 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 27: 0100 1101 0010 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 28: 0100 1101 0010 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 29: 0100 1101 0010 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2a: 0100 1101 0010 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2b: 0100 1101 0010 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2c: 0100 1101 0010 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2d: 0100 1101 0010 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2e: 0100 1101 0010 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2f: 0100 1101 0010 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 30: 0100 1101 0011 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 31: 0100 1101 0011 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 32: 0100 1101 0011 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 33: 0100 1101 0011 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 34: 0100 1101 0011 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 35: 0100 1101 0011 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 36: 0100 1101 0011 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 37: 0100 1101 0011 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 38: 0100 1101 0011 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 39: 0100 1101 0011 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3a: 0100 1101 0011 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3b: 0100 1101 0011 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3c: 0100 1101 0011 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3d: 0100 1101 0011 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3e: 0100 1101 0011 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3f: 0100 1101 0011 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 40: 0100 1101 0100 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 41: 0100 1101 0100 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 42: 0100 1101 0100 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 43: 0100 1101 0100 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 44: 0100 1101 0100 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 45: 0100 1101 0100 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 46: 0100 1101 0100 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 47: 0100 1101 0100 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 48: 0100 1101 0100 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 49: 0100 1101 0100 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4a: 0100 1101 0100 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4b: 0100 1101 0100 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4c: 0100 1101 0100 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4d: 0100 1101 0100 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4e: 0100 1101 0100 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4f: 0100 1101 0100 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 50: 0100 1101 0101 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 51: 0100 1101 0101 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 52: 0100 1101 0101 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 53: 0100 1101 0101 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 54: 0100 1101 0101 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 55: 0100 1101 0101 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 56: 0100 1101 0101 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 57: 0100 1101 0101 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 58: 0100 1101 0101 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 59: 0100 1101 0101 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5a: 0100 1101 0101 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5b: 0100 1101 0101 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5c: 0100 1101 0101 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5d: 0100 1101 0101 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5e: 0100 1101 0101 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5f: 0100 1101 0101 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 60: 0100 1101 0110 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 61: 0100 1101 0110 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 62: 0100 1101 0110 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 63: 0100 1101 0110 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 64: 0100 1101 0110 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 65: 0100 1101 0110 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 66: 0100 1101 0110 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 67: 0100 1101 0110 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 68: 0100 1101 0110 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 69: 0100 1101 0110 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6a: 0100 1101 0110 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6b: 0100 1101 0110 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6c: 0100 1101 0110 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6d: 0100 1101 0110 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6e: 0100 1101 0110 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 6f: 0100 1101 0110 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 70: 0100 1101 0111 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 71: 0100 1101 0111 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 72: 0100 1101 0111 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 73: 0100 1101 0111 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 74: 0100 1101 0111 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 75: 0100 1101 0111 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 76: 0100 1101 0111 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 77: 0100 1101 0111 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 78: 0100 1101 0111 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 79: 0100 1101 0111 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7a: 0100 1101 0111 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7b: 0100 1101 0111 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7c: 0100 1101 0111 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7d: 0100 1101 0111 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7e: 0100 1101 0111 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 7f: 0100 1101 0111 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 80: 0100 1101 1000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 81: 0100 1101 1000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 82: 0100 1101 1000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 83: 0100 1101 1000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 84: 0100 1101 1000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 85: 0100 1101 1000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 86: 0100 1101 1000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 87: 0100 1101 1000 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 88: 0100 1101 1000 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 89: 0100 1101 1000 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8a: 0100 1101 1000 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8b: 0100 1101 1000 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8c: 0100 1101 1000 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8d: 0100 1101 1000 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8e: 0100 1101 1000 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8f: 0100 1101 1000 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 90: 0100 1101 1001 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 91: 0100 1101 1001 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 92: 0100 1101 1001 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 93: 0100 1101 1001 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 94: 0100 1101 1001 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 95: 0100 1101 1001 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 96: 0100 1101 1001 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 97: 0100 1101 1001 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 98: 0100 1101 1001 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 99: 0100 1101 1001 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9a: 0100 1101 1001 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9b: 0100 1101 1001 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9c: 0100 1101 1001 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9d: 0100 1101 1001 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9e: 0100 1101 1001 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9f: 0100 1101 1001 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* a0: 0100 1101 1010 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a1: 0100 1101 1010 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a2: 0100 1101 1010 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a3: 0100 1101 1010 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a4: 0100 1101 1010 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a5: 0100 1101 1010 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a6: 0100 1101 1010 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a7: 0100 1101 1010 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a8: 0100 1101 1010 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a9: 0100 1101 1010 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* aa: 0100 1101 1010 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ab: 0100 1101 1010 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ac: 0100 1101 1010 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ad: 0100 1101 1010 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ae: 0100 1101 1010 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* af: 0100 1101 1010 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* b0: 0100 1101 1011 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b1: 0100 1101 1011 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b2: 0100 1101 1011 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b3: 0100 1101 1011 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b4: 0100 1101 1011 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b5: 0100 1101 1011 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b6: 0100 1101 1011 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b7: 0100 1101 1011 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b8: 0100 1101 1011 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b9: 0100 1101 1011 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ba: 0100 1101 1011 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bb: 0100 1101 1011 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bc: 0100 1101 1011 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bd: 0100 1101 1011 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* be: 0100 1101 1011 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bf: 0100 1101 1011 1111 */
+
+ {MOV_PA_A, 2,10,10,L0|L1}, /* c0: 0100 1101 1100 0000 */
+ {MOV_PB_A, 2,10,10,L0|L1}, /* c1: 0100 1101 1100 0001 */
+ {MOV_PC_A, 2,10,10,L0|L1}, /* c2: 0100 1101 1100 0010 */
+ {MOV_PD_A, 2,10,10,L0|L1}, /* c3: 0100 1101 1100 0011 */
+ {illegal2, 2,10,10,L0|L1}, /* c4: 0100 1101 1100 0100 */
+ {MOV_PF_A, 2,10,10,L0|L1}, /* c5: 0100 1101 1100 0101 */
+ {MOV_MKH_A, 2,10,10,L0|L1}, /* c6: 0100 1101 1100 0110 */
+ {MOV_MKL_A, 2,10,10,L0|L1}, /* c7: 0100 1101 1100 0111 */
+ {MOV_ANM_A, 2,10,10,L0|L1}, /* c8: 0100 1101 1100 1000 */
+ {MOV_SMH_A, 2,10,10,L0|L1}, /* c9: 0100 1101 1100 1001 */
+ {MOV_SML_A, 2,10,10,L0|L1}, /* ca: 0100 1101 1100 1010 */
+ {MOV_EOM_A, 2,10,10,L0|L1}, /* cb: 0100 1101 1100 1011 */
+ {MOV_ETMM_A, 2,10,10,L0|L1}, /* cc: 0100 1101 1100 1100 */
+ {MOV_TMM_A, 2,10,10,L0|L1}, /* cd: 0100 1101 1100 1101 */
+ {illegal2, 2,10,10,L0|L1}, /* ce: 0100 1101 1100 1110 */
+ {illegal2, 2,10,10,L0|L1}, /* cf: 0100 1101 1100 1111 */
+
+ {MOV_MM_A, 2,10,10,L0|L1}, /* d0: 0100 1101 1101 0000 */
+ {MOV_MCC_A, 2,10,10,L0|L1}, /* d1: 0100 1101 1101 0001 */
+ {MOV_MA_A, 2,10,10,L0|L1}, /* d2: 0100 1101 1101 0010 */
+ {MOV_MB_A, 2,10,10,L0|L1}, /* d3: 0100 1101 1101 0011 */
+ {MOV_MC_A, 2,10,10,L0|L1}, /* d4: 0100 1101 1101 0100 */
+ {illegal2, 2,10,10,L0|L1}, /* d5: 0100 1101 1101 0101 */
+ {illegal2, 2,10,10,L0|L1}, /* d6: 0100 1101 1101 0110 */
+ {MOV_MF_A, 2,10,10,L0|L1}, /* d7: 0100 1101 1101 0111 */
+ {MOV_TXB_A, 2,10,10,L0|L1}, /* d8: 0100 1101 1101 1000 */
+ {illegal2, 2,10,10,L0|L1}, /* d9: 0100 1101 1101 1001 */
+ {MOV_TM0_A, 2,10,10,L0|L1}, /* da: 0100 1101 1101 1010 */
+ {MOV_TM1_A, 2,10,10,L0|L1}, /* db: 0100 1101 1101 1011 */
+ {illegal2, 2,10,10,L0|L1}, /* dc: 0100 1101 1101 1100 */
+ {illegal2, 2,10,10,L0|L1}, /* dd: 0100 1101 1101 1101 */
+ {illegal2, 2,10,10,L0|L1}, /* de: 0100 1101 1101 1110 */
+ {illegal2, 2,10,10,L0|L1}, /* df: 0100 1101 1101 1111 */
+
+ {illegal2, 2,10,10,L0|L1}, /* e0: 0100 1101 1110 0000 */
+ {illegal2, 2,10,10,L0|L1}, /* e1: 0100 1101 1110 0001 */
+ {illegal2, 2,10,10,L0|L1}, /* e2: 0100 1101 1110 0010 */
+ {illegal2, 2,10,10,L0|L1}, /* e3: 0100 1101 1110 0011 */
+ {illegal2, 2,10,10,L0|L1}, /* e4: 0100 1101 1110 0100 */
+ {illegal2, 2,10,10,L0|L1}, /* e5: 0100 1101 1110 0101 */
+ {illegal2, 2,10,10,L0|L1}, /* e6: 0100 1101 1110 0110 */
+ {illegal2, 2,10,10,L0|L1}, /* e7: 0100 1101 1110 0111 */
+ {MOV_ZCM_A, 2,10,10,L0|L1}, /* e8: 0100 1101 1110 1000 */
+ {illegal2, 2,10,10,L0|L1}, /* e9: 0100 1101 1110 1001 */
+ {illegal2, 2,10,10,L0|L1}, /* ea: 0100 1101 1110 1010 */
+ {illegal2, 2,10,10,L0|L1}, /* eb: 0100 1101 1110 1011 */
+ {illegal2, 2,10,10,L0|L1}, /* ec: 0100 1101 1110 1100 */
+ {illegal2, 2,10,10,L0|L1}, /* ed: 0100 1101 1110 1101 */
+ {illegal2, 2,10,10,L0|L1}, /* ee: 0100 1101 1110 1110 */
+ {illegal2, 2,10,10,L0|L1}, /* ef: 0100 1101 1110 1111 */
+
+ {illegal2, 2,10,10,L0|L1}, /* f0: 0100 1101 1111 0000 */
+ {illegal2, 2,10,10,L0|L1}, /* f1: 0100 1101 1111 0001 */
+ {illegal2, 2,10,10,L0|L1}, /* f2: 0100 1101 1111 0010 */
+ {illegal2, 2,10,10,L0|L1}, /* f3: 0100 1101 1111 0011 */
+ {illegal2, 2,10,10,L0|L1}, /* f4: 0100 1101 1111 0100 */
+ {illegal2, 2,10,10,L0|L1}, /* f5: 0100 1101 1111 0101 */
+ {illegal2, 2,10,10,L0|L1}, /* f6: 0100 1101 1111 0110 */
+ {illegal2, 2,10,10,L0|L1}, /* f7: 0100 1101 1111 0111 */
+ {illegal2, 2,10,10,L0|L1}, /* f8: 0100 1101 1111 1000 */
+ {illegal2, 2,10,10,L0|L1}, /* f9: 0100 1101 1111 1001 */
+ {illegal2, 2,10,10,L0|L1}, /* fa: 0100 1101 1111 1010 */
+ {illegal2, 2,10,10,L0|L1}, /* fb: 0100 1101 1111 1011 */
+ {illegal2, 2,10,10,L0|L1}, /* fc: 0100 1101 1111 1100 */
+ {illegal2, 2,10,10,L0|L1}, /* fd: 0100 1101 1111 1101 */
+ {illegal2, 2,10,10,L0|L1}, /* fe: 0100 1101 1111 1110 */
+ {illegal2, 2,10,10,L0|L1} /* ff: 0100 1101 1111 1111 */
+};
+
+/* prefix 60 */
+static struct opcode_s op60[256] =
+{
+ {illegal2, 2, 8, 8,L0|L1}, /* 00: 0110 0000 0000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 01: 0110 0000 0000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 02: 0110 0000 0000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 03: 0110 0000 0000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 04: 0110 0000 0000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 05: 0110 0000 0000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 06: 0110 0000 0000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 07: 0110 0000 0000 0111 */
+ {ANA_V_A, 2, 8, 8,L0|L1}, /* 08: 0110 0000 0000 1000 */
+ {ANA_A_A, 2, 8, 8,L0|L1}, /* 09: 0110 0000 0000 1001 */
+ {ANA_B_A, 2, 8, 8,L0|L1}, /* 0a: 0110 0000 0000 1010 */
+ {ANA_C_A, 2, 8, 8,L0|L1}, /* 0b: 0110 0000 0000 1011 */
+ {ANA_D_A, 2, 8, 8,L0|L1}, /* 0c: 0110 0000 0000 1100 */
+ {ANA_E_A, 2, 8, 8,L0|L1}, /* 0d: 0110 0000 0000 1101 */
+ {ANA_H_A, 2, 8, 8,L0|L1}, /* 0e: 0110 0000 0000 1110 */
+ {ANA_L_A, 2, 8, 8,L0|L1}, /* 0f: 0110 0000 0000 1111 */
+
+ {XRA_V_A, 2, 8, 8,L0|L1}, /* 10: 0110 0000 0001 0000 */
+ {XRA_A_A, 2, 8, 8,L0|L1}, /* 11: 0110 0000 0001 0001 */
+ {XRA_B_A, 2, 8, 8,L0|L1}, /* 12: 0110 0000 0001 0010 */
+ {XRA_C_A, 2, 8, 8,L0|L1}, /* 13: 0110 0000 0001 0011 */
+ {XRA_D_A, 2, 8, 8,L0|L1}, /* 14: 0110 0000 0001 0100 */
+ {XRA_E_A, 2, 8, 8,L0|L1}, /* 15: 0110 0000 0001 0101 */
+ {XRA_H_A, 2, 8, 8,L0|L1}, /* 16: 0110 0000 0001 0110 */
+ {XRA_L_A, 2, 8, 8,L0|L1}, /* 17: 0110 0000 0001 0111 */
+ {ORA_V_A, 2, 8, 8,L0|L1}, /* 18: 0110 0000 0001 1000 */
+ {ORA_A_A, 2, 8, 8,L0|L1}, /* 19: 0110 0000 0001 1001 */
+ {ORA_B_A, 2, 8, 8,L0|L1}, /* 1a: 0110 0000 0001 1010 */
+ {ORA_C_A, 2, 8, 8,L0|L1}, /* 1b: 0110 0000 0001 1011 */
+ {ORA_D_A, 2, 8, 8,L0|L1}, /* 1c: 0110 0000 0001 1100 */
+ {ORA_E_A, 2, 8, 8,L0|L1}, /* 1d: 0110 0000 0001 1101 */
+ {ORA_H_A, 2, 8, 8,L0|L1}, /* 1e: 0110 0000 0001 1110 */
+ {ORA_L_A, 2, 8, 8,L0|L1}, /* 1f: 0110 0000 0001 1111 */
+
+ {ADDNC_V_A, 2, 8, 8,L0|L1}, /* 20: 0110 0000 0010 0000 */
+ {ADDNC_A_A, 2, 8, 8,L0|L1}, /* 21: 0110 0000 0010 0001 */
+ {ADDNC_B_A, 2, 8, 8,L0|L1}, /* 22: 0110 0000 0010 0010 */
+ {ADDNC_C_A, 2, 8, 8,L0|L1}, /* 23: 0110 0000 0010 0011 */
+ {ADDNC_D_A, 2, 8, 8,L0|L1}, /* 24: 0110 0000 0010 0100 */
+ {ADDNC_E_A, 2, 8, 8,L0|L1}, /* 25: 0110 0000 0010 0101 */
+ {ADDNC_H_A, 2, 8, 8,L0|L1}, /* 26: 0110 0000 0010 0110 */
+ {ADDNC_L_A, 2, 8, 8,L0|L1}, /* 27: 0110 0000 0010 0111 */
+ {GTA_V_A, 2, 8, 8,L0|L1}, /* 28: 0110 0000 0010 1000 */
+ {GTA_A_A, 2, 8, 8,L0|L1}, /* 29: 0110 0000 0010 1001 */
+ {GTA_B_A, 2, 8, 8,L0|L1}, /* 2a: 0110 0000 0010 1010 */
+ {GTA_C_A, 2, 8, 8,L0|L1}, /* 2b: 0110 0000 0010 1011 */
+ {GTA_D_A, 2, 8, 8,L0|L1}, /* 2c: 0110 0000 0010 1100 */
+ {GTA_E_A, 2, 8, 8,L0|L1}, /* 2d: 0110 0000 0010 1101 */
+ {GTA_H_A, 2, 8, 8,L0|L1}, /* 2e: 0110 0000 0010 1110 */
+ {GTA_L_A, 2, 8, 8,L0|L1}, /* 2f: 0110 0000 0010 1111 */
+
+ {SUBNB_V_A, 2, 8, 8,L0|L1}, /* 30: 0110 0000 0011 0000 */
+ {SUBNB_A_A, 2, 8, 8,L0|L1}, /* 31: 0110 0000 0011 0001 */
+ {SUBNB_B_A, 2, 8, 8,L0|L1}, /* 32: 0110 0000 0011 0010 */
+ {SUBNB_C_A, 2, 8, 8,L0|L1}, /* 33: 0110 0000 0011 0011 */
+ {SUBNB_D_A, 2, 8, 8,L0|L1}, /* 34: 0110 0000 0011 0100 */
+ {SUBNB_E_A, 2, 8, 8,L0|L1}, /* 35: 0110 0000 0011 0101 */
+ {SUBNB_H_A, 2, 8, 8,L0|L1}, /* 36: 0110 0000 0011 0110 */
+ {SUBNB_L_A, 2, 8, 8,L0|L1}, /* 37: 0110 0000 0011 0111 */
+ {LTA_V_A, 2, 8, 8,L0|L1}, /* 38: 0110 0000 0011 1000 */
+ {LTA_A_A, 2, 8, 8,L0|L1}, /* 39: 0110 0000 0011 1001 */
+ {LTA_B_A, 2, 8, 8,L0|L1}, /* 3a: 0110 0000 0011 1010 */
+ {LTA_C_A, 2, 8, 8,L0|L1}, /* 3b: 0110 0000 0011 1011 */
+ {LTA_D_A, 2, 8, 8,L0|L1}, /* 3c: 0110 0000 0011 1100 */
+ {LTA_E_A, 2, 8, 8,L0|L1}, /* 3d: 0110 0000 0011 1101 */
+ {LTA_H_A, 2, 8, 8,L0|L1}, /* 3e: 0110 0000 0011 1110 */
+ {LTA_L_A, 2, 8, 8,L0|L1}, /* 3f: 0110 0000 0011 1111 */
+
+ {ADD_V_A, 2, 8, 8,L0|L1}, /* 40: 0110 0000 0100 0000 */
+ {ADD_A_A, 2, 8, 8,L0|L1}, /* 41: 0110 0000 0100 0001 */
+ {ADD_B_A, 2, 8, 8,L0|L1}, /* 42: 0110 0000 0100 0010 */
+ {ADD_C_A, 2, 8, 8,L0|L1}, /* 43: 0110 0000 0100 0011 */
+ {ADD_D_A, 2, 8, 8,L0|L1}, /* 44: 0110 0000 0100 0100 */
+ {ADD_E_A, 2, 8, 8,L0|L1}, /* 45: 0110 0000 0100 0101 */
+ {ADD_H_A, 2, 8, 8,L0|L1}, /* 46: 0110 0000 0100 0110 */
+ {ADD_L_A, 2, 8, 8,L0|L1}, /* 47: 0110 0000 0100 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 48: 0110 0000 0100 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 49: 0110 0000 0100 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4a: 0110 0000 0100 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4b: 0110 0000 0100 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4c: 0110 0000 0100 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4d: 0110 0000 0100 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4e: 0110 0000 0100 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4f: 0110 0000 0100 1111 */
+
+ {ADC_V_A, 2, 8, 8,L0|L1}, /* 50: 0110 0000 0101 0000 */
+ {ADC_A_A, 2, 8, 8,L0|L1}, /* 51: 0110 0000 0101 0001 */
+ {ADC_B_A, 2, 8, 8,L0|L1}, /* 52: 0110 0000 0101 0010 */
+ {ADC_C_A, 2, 8, 8,L0|L1}, /* 53: 0110 0000 0101 0011 */
+ {ADC_D_A, 2, 8, 8,L0|L1}, /* 54: 0110 0000 0101 0100 */
+ {ADC_E_A, 2, 8, 8,L0|L1}, /* 55: 0110 0000 0101 0101 */
+ {ADC_H_A, 2, 8, 8,L0|L1}, /* 56: 0110 0000 0101 0110 */
+ {ADC_L_A, 2, 8, 8,L0|L1}, /* 57: 0110 0000 0101 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 58: 0110 0000 0101 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 59: 0110 0000 0101 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5a: 0110 0000 0101 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5b: 0110 0000 0101 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5c: 0110 0000 0101 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5d: 0110 0000 0101 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5e: 0110 0000 0101 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5f: 0110 0000 0101 1111 */
+
+ {SUB_V_A, 2, 8, 8,L0|L1}, /* 60: 0110 0000 0110 0000 */
+ {SUB_A_A, 2, 8, 8,L0|L1}, /* 61: 0110 0000 0110 0001 */
+ {SUB_B_A, 2, 8, 8,L0|L1}, /* 62: 0110 0000 0110 0010 */
+ {SUB_C_A, 2, 8, 8,L0|L1}, /* 63: 0110 0000 0110 0011 */
+ {SUB_D_A, 2, 8, 8,L0|L1}, /* 64: 0110 0000 0110 0100 */
+ {SUB_E_A, 2, 8, 8,L0|L1}, /* 65: 0110 0000 0110 0101 */
+ {SUB_H_A, 2, 8, 8,L0|L1}, /* 66: 0110 0000 0110 0110 */
+ {SUB_L_A, 2, 8, 8,L0|L1}, /* 67: 0110 0000 0110 0111 */
+ {NEA_V_A, 2, 8, 8,L0|L1}, /* 68: 0110 0000 0110 1000 */
+ {NEA_A_A, 2, 8, 8,L0|L1}, /* 69: 0110 0000 0110 1001 */
+ {NEA_B_A, 2, 8, 8,L0|L1}, /* 6a: 0110 0000 0110 1010 */
+ {NEA_C_A, 2, 8, 8,L0|L1}, /* 6b: 0110 0000 0110 1011 */
+ {NEA_D_A, 2, 8, 8,L0|L1}, /* 6c: 0110 0000 0110 1100 */
+ {NEA_E_A, 2, 8, 8,L0|L1}, /* 6d: 0110 0000 0110 1101 */
+ {NEA_H_A, 2, 8, 8,L0|L1}, /* 6e: 0110 0000 0110 1110 */
+ {NEA_L_A, 2, 8, 8,L0|L1}, /* 6f: 0110 0000 0110 1111 */
+
+ {SBB_V_A, 2, 8, 8,L0|L1}, /* 70: 0110 0000 0111 0000 */
+ {SBB_A_A, 2, 8, 8,L0|L1}, /* 71: 0110 0000 0111 0001 */
+ {SBB_B_A, 2, 8, 8,L0|L1}, /* 72: 0110 0000 0111 0010 */
+ {SBB_C_A, 2, 8, 8,L0|L1}, /* 73: 0110 0000 0111 0011 */
+ {SBB_D_A, 2, 8, 8,L0|L1}, /* 74: 0110 0000 0111 0100 */
+ {SBB_E_A, 2, 8, 8,L0|L1}, /* 75: 0110 0000 0111 0101 */
+ {SBB_H_A, 2, 8, 8,L0|L1}, /* 76: 0110 0000 0111 0110 */
+ {SBB_L_A, 2, 8, 8,L0|L1}, /* 77: 0110 0000 0111 0111 */
+ {EQA_V_A, 2, 8, 8,L0|L1}, /* 78: 0110 0000 0111 1000 */
+ {EQA_A_A, 2, 8, 8,L0|L1}, /* 79: 0110 0000 0111 1001 */
+ {EQA_B_A, 2, 8, 8,L0|L1}, /* 7a: 0110 0000 0111 1010 */
+ {EQA_C_A, 2, 8, 8,L0|L1}, /* 7b: 0110 0000 0111 1011 */
+ {EQA_D_A, 2, 8, 8,L0|L1}, /* 7c: 0110 0000 0111 1100 */
+ {EQA_E_A, 2, 8, 8,L0|L1}, /* 7d: 0110 0000 0111 1101 */
+ {EQA_H_A, 2, 8, 8,L0|L1}, /* 7e: 0110 0000 0111 1110 */
+ {EQA_L_A, 2, 8, 8,L0|L1}, /* 7f: 0110 0000 0111 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 80: 0110 0000 1000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 81: 0110 0000 1000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 82: 0110 0000 1000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 83: 0110 0000 1000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 84: 0110 0000 1000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 85: 0110 0000 1000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 86: 0110 0000 1000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 87: 0110 0000 1000 0111 */
+ {ANA_A_V, 2, 8, 8,L0|L1}, /* 88: 0110 0000 1000 1000 */
+ {ANA_A_A, 2, 8, 8,L0|L1}, /* 89: 0110 0000 1000 1001 */
+ {ANA_A_B, 2, 8, 8,L0|L1}, /* 8a: 0110 0000 1000 1010 */
+ {ANA_A_C, 2, 8, 8,L0|L1}, /* 8b: 0110 0000 1000 1011 */
+ {ANA_A_D, 2, 8, 8,L0|L1}, /* 8c: 0110 0000 1000 1100 */
+ {ANA_A_E, 2, 8, 8,L0|L1}, /* 8d: 0110 0000 1000 1101 */
+ {ANA_A_H, 2, 8, 8,L0|L1}, /* 8e: 0110 0000 1000 1110 */
+ {ANA_A_L, 2, 8, 8,L0|L1}, /* 8f: 0110 0000 1000 1111 */
+
+ {XRA_A_V, 2, 8, 8,L0|L1}, /* 90: 0110 0000 1001 0000 */
+ {XRA_A_A, 2, 8, 8,L0|L1}, /* 91: 0110 0000 1001 0001 */
+ {XRA_A_B, 2, 8, 8,L0|L1}, /* 92: 0110 0000 1001 0010 */
+ {XRA_A_C, 2, 8, 8,L0|L1}, /* 93: 0110 0000 1001 0011 */
+ {XRA_A_D, 2, 8, 8,L0|L1}, /* 94: 0110 0000 1001 0100 */
+ {XRA_A_E, 2, 8, 8,L0|L1}, /* 95: 0110 0000 1001 0101 */
+ {XRA_A_H, 2, 8, 8,L0|L1}, /* 96: 0110 0000 1001 0110 */
+ {XRA_A_L, 2, 8, 8,L0|L1}, /* 97: 0110 0000 1001 0111 */
+ {ORA_A_V, 2, 8, 8,L0|L1}, /* 98: 0110 0000 1001 1000 */
+ {ORA_A_A, 2, 8, 8,L0|L1}, /* 99: 0110 0000 1001 1001 */
+ {ORA_A_B, 2, 8, 8,L0|L1}, /* 9a: 0110 0000 1001 1010 */
+ {ORA_A_C, 2, 8, 8,L0|L1}, /* 9b: 0110 0000 1001 1011 */
+ {ORA_A_D, 2, 8, 8,L0|L1}, /* 9c: 0110 0000 1001 1100 */
+ {ORA_A_E, 2, 8, 8,L0|L1}, /* 9d: 0110 0000 1001 1101 */
+ {ORA_A_H, 2, 8, 8,L0|L1}, /* 9e: 0110 0000 1001 1110 */
+ {ORA_A_L, 2, 8, 8,L0|L1}, /* 9f: 0110 0000 1001 1111 */
+
+ {ADDNC_A_V, 2, 8, 8,L0|L1}, /* a0: 0110 0000 1010 0000 */
+ {ADDNC_A_A, 2, 8, 8,L0|L1}, /* a1: 0110 0000 1010 0001 */
+ {ADDNC_A_B, 2, 8, 8,L0|L1}, /* a2: 0110 0000 1010 0010 */
+ {ADDNC_A_C, 2, 8, 8,L0|L1}, /* a3: 0110 0000 1010 0011 */
+ {ADDNC_A_D, 2, 8, 8,L0|L1}, /* a4: 0110 0000 1010 0100 */
+ {ADDNC_A_E, 2, 8, 8,L0|L1}, /* a5: 0110 0000 1010 0101 */
+ {ADDNC_A_H, 2, 8, 8,L0|L1}, /* a6: 0110 0000 1010 0110 */
+ {ADDNC_A_L, 2, 8, 8,L0|L1}, /* a7: 0110 0000 1010 0111 */
+ {GTA_A_V, 2, 8, 8,L0|L1}, /* a8: 0110 0000 1010 1000 */
+ {GTA_A_A, 2, 8, 8,L0|L1}, /* a9: 0110 0000 1010 1001 */
+ {GTA_A_B, 2, 8, 8,L0|L1}, /* aa: 0110 0000 1010 1010 */
+ {GTA_A_C, 2, 8, 8,L0|L1}, /* ab: 0110 0000 1010 1011 */
+ {GTA_A_D, 2, 8, 8,L0|L1}, /* ac: 0110 0000 1010 1100 */
+ {GTA_A_E, 2, 8, 8,L0|L1}, /* ad: 0110 0000 1010 1101 */
+ {GTA_A_H, 2, 8, 8,L0|L1}, /* ae: 0110 0000 1010 1110 */
+ {GTA_A_L, 2, 8, 8,L0|L1}, /* af: 0110 0000 1010 1111 */
+
+ {SUBNB_A_V, 2, 8, 8,L0|L1}, /* b0: 0110 0000 1011 0000 */
+ {SUBNB_A_A, 2, 8, 8,L0|L1}, /* b1: 0110 0000 1011 0001 */
+ {SUBNB_A_B, 2, 8, 8,L0|L1}, /* b2: 0110 0000 1011 0010 */
+ {SUBNB_A_C, 2, 8, 8,L0|L1}, /* b3: 0110 0000 1011 0011 */
+ {SUBNB_A_D, 2, 8, 8,L0|L1}, /* b4: 0110 0000 1011 0100 */
+ {SUBNB_A_E, 2, 8, 8,L0|L1}, /* b5: 0110 0000 1011 0101 */
+ {SUBNB_A_H, 2, 8, 8,L0|L1}, /* b6: 0110 0000 1011 0110 */
+ {SUBNB_A_L, 2, 8, 8,L0|L1}, /* b7: 0110 0000 1011 0111 */
+ {LTA_A_V, 2, 8, 8,L0|L1}, /* b8: 0110 0000 1011 1000 */
+ {LTA_A_A, 2, 8, 8,L0|L1}, /* b9: 0110 0000 1011 1001 */
+ {LTA_A_B, 2, 8, 8,L0|L1}, /* ba: 0110 0000 1011 1010 */
+ {LTA_A_C, 2, 8, 8,L0|L1}, /* bb: 0110 0000 1011 1011 */
+ {LTA_A_D, 2, 8, 8,L0|L1}, /* bc: 0110 0000 1011 1100 */
+ {LTA_A_E, 2, 8, 8,L0|L1}, /* bd: 0110 0000 1011 1101 */
+ {LTA_A_H, 2, 8, 8,L0|L1}, /* be: 0110 0000 1011 1110 */
+ {LTA_A_L, 2, 8, 8,L0|L1}, /* bf: 0110 0000 1011 1111 */
+
+ {ADD_A_V, 2, 8, 8,L0|L1}, /* c0: 0110 0000 1100 0000 */
+ {ADD_A_A, 2, 8, 8,L0|L1}, /* c1: 0110 0000 1100 0001 */
+ {ADD_A_B, 2, 8, 8,L0|L1}, /* c2: 0110 0000 1100 0010 */
+ {ADD_A_C, 2, 8, 8,L0|L1}, /* c3: 0110 0000 1100 0011 */
+ {ADD_A_D, 2, 8, 8,L0|L1}, /* c4: 0110 0000 1100 0100 */
+ {ADD_A_E, 2, 8, 8,L0|L1}, /* c5: 0110 0000 1100 0101 */
+ {ADD_A_H, 2, 8, 8,L0|L1}, /* c6: 0110 0000 1100 0110 */
+ {ADD_A_L, 2, 8, 8,L0|L1}, /* c7: 0110 0000 1100 0111 */
+ {ONA_A_V, 2, 8, 8,L0|L1}, /* c8: 0110 0000 1100 1000 */
+ {ONA_A_A, 2, 8, 8,L0|L1}, /* c9: 0110 0000 1100 1001 */
+ {ONA_A_B, 2, 8, 8,L0|L1}, /* ca: 0110 0000 1100 1010 */
+ {ONA_A_C, 2, 8, 8,L0|L1}, /* cb: 0110 0000 1100 1011 */
+ {ONA_A_D, 2, 8, 8,L0|L1}, /* cc: 0110 0000 1100 1100 */
+ {ONA_A_E, 2, 8, 8,L0|L1}, /* cd: 0110 0000 1100 1101 */
+ {ONA_A_H, 2, 8, 8,L0|L1}, /* ce: 0110 0000 1100 1110 */
+ {ONA_A_L, 2, 8, 8,L0|L1}, /* cf: 0110 0000 1100 1111 */
+
+ {ADC_A_V, 2, 8, 8,L0|L1}, /* d0: 0110 0000 1101 0000 */
+ {ADC_A_A, 2, 8, 8,L0|L1}, /* d1: 0110 0000 1101 0001 */
+ {ADC_A_B, 2, 8, 8,L0|L1}, /* d2: 0110 0000 1101 0010 */
+ {ADC_A_C, 2, 8, 8,L0|L1}, /* d3: 0110 0000 1101 0011 */
+ {ADC_A_D, 2, 8, 8,L0|L1}, /* d4: 0110 0000 1101 0100 */
+ {ADC_A_E, 2, 8, 8,L0|L1}, /* d5: 0110 0000 1101 0101 */
+ {ADC_A_H, 2, 8, 8,L0|L1}, /* d6: 0110 0000 1101 0110 */
+ {ADC_A_L, 2, 8, 8,L0|L1}, /* d7: 0110 0000 1101 0111 */
+ {OFFA_A_V, 2, 8, 8,L0|L1}, /* d8: 0110 0000 1101 1000 */
+ {OFFA_A_A, 2, 8, 8,L0|L1}, /* d9: 0110 0000 1101 1001 */
+ {OFFA_A_B, 2, 8, 8,L0|L1}, /* da: 0110 0000 1101 1010 */
+ {OFFA_A_C, 2, 8, 8,L0|L1}, /* db: 0110 0000 1101 1011 */
+ {OFFA_A_D, 2, 8, 8,L0|L1}, /* dc: 0110 0000 1101 1100 */
+ {OFFA_A_E, 2, 8, 8,L0|L1}, /* dd: 0110 0000 1101 1101 */
+ {OFFA_A_H, 2, 8, 8,L0|L1}, /* de: 0110 0000 1101 1110 */
+ {OFFA_A_L, 2, 8, 8,L0|L1}, /* df: 0110 0000 1101 1111 */
+
+ {SUB_A_V, 2, 8, 8,L0|L1}, /* e0: 0110 0000 1110 0000 */
+ {SUB_A_A, 2, 8, 8,L0|L1}, /* e1: 0110 0000 1110 0001 */
+ {SUB_A_B, 2, 8, 8,L0|L1}, /* e2: 0110 0000 1110 0010 */
+ {SUB_A_C, 2, 8, 8,L0|L1}, /* e3: 0110 0000 1110 0011 */
+ {SUB_A_D, 2, 8, 8,L0|L1}, /* e4: 0110 0000 1110 0100 */
+ {SUB_A_E, 2, 8, 8,L0|L1}, /* e5: 0110 0000 1110 0101 */
+ {SUB_A_H, 2, 8, 8,L0|L1}, /* e6: 0110 0000 1110 0110 */
+ {SUB_A_L, 2, 8, 8,L0|L1}, /* e7: 0110 0000 1110 0111 */
+ {NEA_A_V, 2, 8, 8,L0|L1}, /* e8: 0110 0000 1110 1000 */
+ {NEA_A_A, 2, 8, 8,L0|L1}, /* e9: 0110 0000 1110 1001 */
+ {NEA_A_B, 2, 8, 8,L0|L1}, /* ea: 0110 0000 1110 1010 */
+ {NEA_A_C, 2, 8, 8,L0|L1}, /* eb: 0110 0000 1110 1011 */
+ {NEA_A_D, 2, 8, 8,L0|L1}, /* ec: 0110 0000 1110 1100 */
+ {NEA_A_E, 2, 8, 8,L0|L1}, /* ed: 0110 0000 1110 1101 */
+ {NEA_A_H, 2, 8, 8,L0|L1}, /* ee: 0110 0000 1110 1110 */
+ {NEA_A_L, 2, 8, 8,L0|L1}, /* ef: 0110 0000 1110 1111 */
+
+ {SBB_A_V, 2, 8, 8,L0|L1}, /* f0: 0110 0000 1111 0000 */
+ {SBB_A_A, 2, 8, 8,L0|L1}, /* f1: 0110 0000 1111 0001 */
+ {SBB_A_B, 2, 8, 8,L0|L1}, /* f2: 0110 0000 1111 0010 */
+ {SBB_A_C, 2, 8, 8,L0|L1}, /* f3: 0110 0000 1111 0011 */
+ {SBB_A_D, 2, 8, 8,L0|L1}, /* f4: 0110 0000 1111 0100 */
+ {SBB_A_E, 2, 8, 8,L0|L1}, /* f5: 0110 0000 1111 0101 */
+ {SBB_A_H, 2, 8, 8,L0|L1}, /* f6: 0110 0000 1111 0110 */
+ {SBB_A_L, 2, 8, 8,L0|L1}, /* f7: 0110 0000 1111 0111 */
+ {EQA_A_V, 2, 8, 8,L0|L1}, /* f8: 0110 0000 1111 1000 */
+ {EQA_A_A, 2, 8, 8,L0|L1}, /* f9: 0110 0000 1111 1001 */
+ {EQA_A_B, 2, 8, 8,L0|L1}, /* fa: 0110 0000 1111 1010 */
+ {EQA_A_C, 2, 8, 8,L0|L1}, /* fb: 0110 0000 1111 1011 */
+ {EQA_A_D, 2, 8, 8,L0|L1}, /* fc: 0110 0000 1111 1100 */
+ {EQA_A_E, 2, 8, 8,L0|L1}, /* fd: 0110 0000 1111 1101 */
+ {EQA_A_H, 2, 8, 8,L0|L1}, /* fe: 0110 0000 1111 1110 */
+ {EQA_A_L, 2, 8, 8,L0|L1} /* ff: 0110 0000 1111 1111 */
+};
+
+/* prefix 64 */
+static struct opcode_s op64[256] =
+{
+ {MVI_PA_xx, 3,14,11,L0|L1}, /* 00: 0110 0100 0000 0000 xxxx xxxx */
+ {MVI_PB_xx, 3,14,11,L0|L1}, /* 01: 0110 0100 0000 0001 xxxx xxxx */
+ {MVI_PC_xx, 3,14,11,L0|L1}, /* 02: 0110 0100 0000 0010 xxxx xxxx */
+ {MVI_PD_xx, 3,14,11,L0|L1}, /* 03: 0110 0100 0000 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 04: 0110 0100 0000 0100 xxxx xxxx */
+ {MVI_PF_xx, 3,14,11,L0|L1}, /* 05: 0110 0100 0000 0101 xxxx xxxx */
+ {MVI_MKH_xx, 3,14,11,L0|L1}, /* 06: 0110 0100 0000 0110 xxxx xxxx */
+ {MVI_MKL_xx, 3,14,11,L0|L1}, /* 07: 0110 0100 0000 0111 xxxx xxxx */
+ {ANI_PA_xx, 3,20,11,L0|L1}, /* 08: 0110 0100 0000 1000 xxxx xxxx */
+ {ANI_PB_xx, 3,20,11,L0|L1}, /* 09: 0110 0100 0000 1001 xxxx xxxx */
+ {ANI_PC_xx, 3,20,11,L0|L1}, /* 0a: 0110 0100 0000 1010 xxxx xxxx */
+ {ANI_PD_xx, 3,20,11,L0|L1}, /* 0b: 0110 0100 0000 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 0c: 0110 0100 0000 1100 xxxx xxxx */
+ {ANI_PF_xx, 3,20,11,L0|L1}, /* 0d: 0110 0100 0000 1101 xxxx xxxx */
+ {ANI_MKH_xx, 3,20,11,L0|L1}, /* 0e: 0110 0100 0000 1110 xxxx xxxx */
+ {ANI_MKL_xx, 3,20,11,L0|L1}, /* 0f: 0110 0100 0000 1111 xxxx xxxx */
+
+ {XRI_PA_xx, 3,20,11,L0|L1}, /* 10: 0110 0100 0001 0000 xxxx xxxx */
+ {XRI_PB_xx, 3,20,11,L0|L1}, /* 11: 0110 0100 0001 0001 xxxx xxxx */
+ {XRI_PC_xx, 3,20,11,L0|L1}, /* 12: 0110 0100 0001 0010 xxxx xxxx */
+ {XRI_PD_xx, 3,20,11,L0|L1}, /* 13: 0110 0100 0001 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 14: 0110 0100 0001 0100 xxxx xxxx */
+ {XRI_PF_xx, 3,20,11,L0|L1}, /* 15: 0110 0100 0001 0101 xxxx xxxx */
+ {XRI_MKH_xx, 3,20,11,L0|L1}, /* 16: 0110 0100 0001 0110 xxxx xxxx */
+ {XRI_MKL_xx, 3,20,11,L0|L1}, /* 17: 0110 0100 0001 0111 xxxx xxxx */
+ {ORI_PA_xx, 3,20,11,L0|L1}, /* 18: 0110 0100 0001 1000 xxxx xxxx */
+ {ORI_PB_xx, 3,20,11,L0|L1}, /* 19: 0110 0100 0001 1001 xxxx xxxx */
+ {ORI_PC_xx, 3,20,11,L0|L1}, /* 1a: 0110 0100 0001 1010 xxxx xxxx */
+ {ORI_PD_xx, 3,20,11,L0|L1}, /* 1b: 0110 0100 0001 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 1c: 0110 0100 0001 1100 xxxx xxxx */
+ {ORI_PF_xx, 3,20,11,L0|L1}, /* 1d: 0110 0100 0001 1101 xxxx xxxx */
+ {ORI_MKH_xx, 3,20,11,L0|L1}, /* 1e: 0110 0100 0001 1110 xxxx xxxx */
+ {ORI_MKL_xx, 3,20,11,L0|L1}, /* 1f: 0110 0100 0001 1111 xxxx xxxx */
+
+ {ADINC_PA_xx, 3,20,11,L0|L1}, /* 20: 0110 0100 0010 0000 xxxx xxxx */
+ {ADINC_PB_xx, 3,20,11,L0|L1}, /* 21: 0110 0100 0010 0001 xxxx xxxx */
+ {ADINC_PC_xx, 3,20,11,L0|L1}, /* 22: 0110 0100 0010 0010 xxxx xxxx */
+ {ADINC_PD_xx, 3,20,11,L0|L1}, /* 23: 0110 0100 0010 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 24: 0110 0100 0010 0100 xxxx xxxx */
+ {ADINC_PF_xx, 3,20,11,L0|L1}, /* 25: 0110 0100 0010 0101 xxxx xxxx */
+ {ADINC_MKH_xx, 3,20,11,L0|L1}, /* 26: 0110 0100 0010 0110 xxxx xxxx */
+ {ADINC_MKL_xx, 3,20,11,L0|L1}, /* 27: 0110 0100 0010 0111 xxxx xxxx */
+ {GTI_PA_xx, 3,20,11,L0|L1}, /* 28: 0110 0100 0010 1000 xxxx xxxx */
+ {GTI_PB_xx, 3,20,11,L0|L1}, /* 29: 0110 0100 0010 1001 xxxx xxxx */
+ {GTI_PC_xx, 3,20,11,L0|L1}, /* 2a: 0110 0100 0010 1010 xxxx xxxx */
+ {GTI_PD_xx, 3,20,11,L0|L1}, /* 2b: 0110 0100 0010 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 2c: 0110 0100 0010 1100 xxxx xxxx */
+ {GTI_PF_xx, 3,20,11,L0|L1}, /* 2d: 0110 0100 0010 1101 xxxx xxxx */
+ {GTI_MKH_xx, 3,20,11,L0|L1}, /* 2e: 0110 0100 0010 1110 xxxx xxxx */
+ {GTI_MKL_xx, 3,20,11,L0|L1}, /* 2f: 0110 0100 0010 1111 xxxx xxxx */
+
+ {SUINB_PA_xx, 3,20,11,L0|L1}, /* 30: 0110 0100 0011 0000 xxxx xxxx */
+ {SUINB_PB_xx, 3,20,11,L0|L1}, /* 31: 0110 0100 0011 0001 xxxx xxxx */
+ {SUINB_PC_xx, 3,20,11,L0|L1}, /* 32: 0110 0100 0011 0010 xxxx xxxx */
+ {SUINB_PD_xx, 3,20,11,L0|L1}, /* 33: 0110 0100 0011 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 34: 0110 0100 0011 0100 xxxx xxxx */
+ {SUINB_PF_xx, 3,20,11,L0|L1}, /* 35: 0110 0100 0011 0101 xxxx xxxx */
+ {SUINB_MKH_xx, 3,20,11,L0|L1}, /* 36: 0110 0100 0011 0110 xxxx xxxx */
+ {SUINB_MKL_xx, 3,20,11,L0|L1}, /* 37: 0110 0100 0011 0111 xxxx xxxx */
+ {LTI_PA_xx, 3,20,11,L0|L1}, /* 38: 0110 0100 0011 1000 xxxx xxxx */
+ {LTI_PB_xx, 3,20,11,L0|L1}, /* 39: 0110 0100 0011 1001 xxxx xxxx */
+ {LTI_PC_xx, 3,20,11,L0|L1}, /* 3a: 0110 0100 0011 1010 xxxx xxxx */
+ {LTI_PD_xx, 3,20,11,L0|L1}, /* 3b: 0110 0100 0011 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 3c: 0110 0100 0011 1100 xxxx xxxx */
+ {LTI_PF_xx, 3,20,11,L0|L1}, /* 3d: 0110 0100 0011 1101 xxxx xxxx */
+ {LTI_MKH_xx, 3,20,11,L0|L1}, /* 3e: 0110 0100 0011 1110 xxxx xxxx */
+ {LTI_MKL_xx, 3,20,11,L0|L1}, /* 3f: 0110 0100 0011 1111 xxxx xxxx */
+
+ {ADI_PA_xx, 3,20,11,L0|L1}, /* 40: 0110 0100 0100 0000 xxxx xxxx */
+ {ADI_PB_xx, 3,20,11,L0|L1}, /* 41: 0110 0100 0100 0001 xxxx xxxx */
+ {ADI_PC_xx, 3,20,11,L0|L1}, /* 42: 0110 0100 0100 0010 xxxx xxxx */
+ {ADI_PD_xx, 3,20,11,L0|L1}, /* 43: 0110 0100 0100 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 44: 0110 0100 0100 0100 xxxx xxxx */
+ {ADI_PF_xx, 3,20,11,L0|L1}, /* 45: 0110 0100 0100 0101 xxxx xxxx */
+ {ADI_MKH_xx, 3,20,11,L0|L1}, /* 46: 0110 0100 0100 0110 xxxx xxxx */
+ {ADI_MKL_xx, 3,20,11,L0|L1}, /* 47: 0110 0100 0100 0111 xxxx xxxx */
+ {ONI_PA_xx, 3,20,11,L0|L1}, /* 48: 0110 0100 0100 1000 xxxx xxxx */
+ {ONI_PB_xx, 3,20,11,L0|L1}, /* 49: 0110 0100 0100 1001 xxxx xxxx */
+ {ONI_PC_xx, 3,20,11,L0|L1}, /* 4a: 0110 0100 0100 1010 xxxx xxxx */
+ {ONI_PD_xx, 3,20,11,L0|L1}, /* 4b: 0110 0100 0100 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 4c: 0110 0100 0100 1100 xxxx xxxx */
+ {ONI_PF_xx, 3,20,11,L0|L1}, /* 4d: 0110 0100 0100 1101 xxxx xxxx */
+ {ONI_MKH_xx, 3,20,11,L0|L1}, /* 4e: 0110 0100 0100 1110 xxxx xxxx */
+ {ONI_MKL_xx, 3,20,11,L0|L1}, /* 4f: 0110 0100 0100 1111 xxxx xxxx */
+
+ {ACI_PA_xx, 3,20,11,L0|L1}, /* 50: 0110 0100 0101 0000 xxxx xxxx */
+ {ACI_PB_xx, 3,20,11,L0|L1}, /* 51: 0110 0100 0101 0001 xxxx xxxx */
+ {ACI_PC_xx, 3,20,11,L0|L1}, /* 52: 0110 0100 0101 0010 xxxx xxxx */
+ {ACI_PD_xx, 3,20,11,L0|L1}, /* 53: 0110 0100 0101 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 54: 0110 0100 0101 0100 xxxx xxxx */
+ {ACI_PF_xx, 3,20,11,L0|L1}, /* 55: 0110 0100 0101 0101 xxxx xxxx */
+ {ACI_MKH_xx, 3,20,11,L0|L1}, /* 56: 0110 0100 0101 0110 xxxx xxxx */
+ {ACI_MKL_xx, 3,20,11,L0|L1}, /* 57: 0110 0100 0101 0111 xxxx xxxx */
+ {OFFI_PA_xx, 3,20,11,L0|L1}, /* 58: 0110 0100 0101 1000 xxxx xxxx */
+ {OFFI_PB_xx, 3,20,11,L0|L1}, /* 59: 0110 0100 0101 1001 xxxx xxxx */
+ {OFFI_PC_xx, 3,20,11,L0|L1}, /* 5a: 0110 0100 0101 1010 xxxx xxxx */
+ {OFFI_PD_xx, 3,20,11,L0|L1}, /* 5b: 0110 0100 0101 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 5c: 0110 0100 0101 1100 xxxx xxxx */
+ {OFFI_PF_xx, 3,20,11,L0|L1}, /* 5d: 0110 0100 0101 1101 xxxx xxxx */
+ {OFFI_MKH_xx, 3,20,11,L0|L1}, /* 5e: 0110 0100 0101 1110 xxxx xxxx */
+ {OFFI_MKL_xx, 3,20,11,L0|L1}, /* 5f: 0110 0100 0101 1111 xxxx xxxx */
+
+ {SUI_PA_xx, 3,20,11,L0|L1}, /* 60: 0110 0100 0110 0000 xxxx xxxx */
+ {SUI_PB_xx, 3,20,11,L0|L1}, /* 61: 0110 0100 0110 0001 xxxx xxxx */
+ {SUI_PC_xx, 3,20,11,L0|L1}, /* 62: 0110 0100 0110 0010 xxxx xxxx */
+ {SUI_PD_xx, 3,20,11,L0|L1}, /* 63: 0110 0100 0110 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 64: 0110 0100 0110 0100 xxxx xxxx */
+ {SUI_PF_xx, 3,20,11,L0|L1}, /* 65: 0110 0100 0110 0101 xxxx xxxx */
+ {SUI_MKH_xx, 3,20,11,L0|L1}, /* 66: 0110 0100 0110 0110 xxxx xxxx */
+ {SUI_MKL_xx, 3,20,11,L0|L1}, /* 67: 0110 0100 0110 0111 xxxx xxxx */
+ {NEI_PA_xx, 3,20,11,L0|L1}, /* 68: 0110 0100 0110 1000 xxxx xxxx */
+ {NEI_PB_xx, 3,20,11,L0|L1}, /* 69: 0110 0100 0110 1001 xxxx xxxx */
+ {NEI_PC_xx, 3,20,11,L0|L1}, /* 6a: 0110 0100 0110 1010 xxxx xxxx */
+ {NEI_PD_xx, 3,20,11,L0|L1}, /* 6b: 0110 0100 0110 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 6c: 0110 0100 0110 1100 xxxx xxxx */
+ {NEI_PF_xx, 3,20,11,L0|L1}, /* 6d: 0110 0100 0110 1101 xxxx xxxx */
+ {NEI_MKH_xx, 3,20,11,L0|L1}, /* 6e: 0110 0100 0110 1110 xxxx xxxx */
+ {NEI_MKL_xx, 3,20,11,L0|L1}, /* 6f: 0110 0100 0110 1111 xxxx xxxx */
+
+ {SBI_PA_xx, 3,20,11,L0|L1}, /* 70: 0110 0100 0111 0000 xxxx xxxx */
+ {SBI_PB_xx, 3,20,11,L0|L1}, /* 71: 0110 0100 0111 0001 xxxx xxxx */
+ {SBI_PC_xx, 3,20,11,L0|L1}, /* 72: 0110 0100 0111 0010 xxxx xxxx */
+ {SBI_PD_xx, 3,20,11,L0|L1}, /* 73: 0110 0100 0111 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 74: 0110 0100 0111 0100 xxxx xxxx */
+ {SBI_PF_xx, 3,20,11,L0|L1}, /* 75: 0110 0100 0111 0101 xxxx xxxx */
+ {SBI_MKH_xx, 3,20,11,L0|L1}, /* 76: 0110 0100 0111 0110 xxxx xxxx */
+ {SBI_MKL_xx, 3,20,11,L0|L1}, /* 77: 0110 0100 0111 0111 xxxx xxxx */
+ {EQI_PA_xx, 3,20,11,L0|L1}, /* 78: 0110 0100 0111 1000 xxxx xxxx */
+ {EQI_PB_xx, 3,20,11,L0|L1}, /* 79: 0110 0100 0111 1001 xxxx xxxx */
+ {EQI_PC_xx, 3,20,11,L0|L1}, /* 7a: 0110 0100 0111 1010 xxxx xxxx */
+ {EQI_PD_xx, 3,20,11,L0|L1}, /* 7b: 0110 0100 0111 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 7c: 0110 0100 0111 1100 xxxx xxxx */
+ {EQI_PF_xx, 3,20,11,L0|L1}, /* 7d: 0110 0100 0111 1101 xxxx xxxx */
+ {EQI_MKH_xx, 3,20,11,L0|L1}, /* 7e: 0110 0100 0111 1110 xxxx xxxx */
+ {EQI_MKL_xx, 3,20,11,L0|L1}, /* 7f: 0110 0100 0111 1111 xxxx xxxx */
+
+ {MVI_ANM_xx, 3,14,11,L0|L1}, /* 80: 0110 0100 1000 0000 xxxx xxxx */
+ {MVI_SMH_xx, 3,14,11,L0|L1}, /* 81: 0110 0100 1000 0001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 82: 0110 0100 1000 0010 xxxx xxxx */
+ {MVI_EOM_xx, 3,14,11,L0|L1}, /* 83: 0110 0100 1000 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 84: 0110 0100 1000 0100 xxxx xxxx */
+ {MVI_TMM_xx, 3,14,11,L0|L1}, /* 85: 0110 0100 1000 0101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 86: 0110 0100 1000 0110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 87: 0110 0100 1000 0111 xxxx xxxx */
+ {ANI_ANM_xx, 3,20,11,L0|L1}, /* 88: 0110 0100 1000 1000 xxxx xxxx */
+ {ANI_SMH_xx, 3,20,11,L0|L1}, /* 89: 0110 0100 1000 1001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 8a: 0110 0100 1000 1010 xxxx xxxx */
+ {ANI_EOM_xx, 3,20,11,L0|L1}, /* 8b: 0110 0100 1000 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 8c: 0110 0100 1000 1100 xxxx xxxx */
+ {ANI_TMM_xx, 3,20,11,L0|L1}, /* 8d: 0110 0100 1000 1101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 8e: 0110 0100 1000 1110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 8f: 0110 0100 1000 1111 xxxx xxxx */
+
+ {XRI_ANM_xx, 3,20,11,L0|L1}, /* 90: 0110 0100 1001 0000 xxxx xxxx */
+ {XRI_SMH_xx, 3,20,11,L0|L1}, /* 91: 0110 0100 1001 0001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 92: 0110 0100 1001 0010 xxxx xxxx */
+ {XRI_EOM_xx, 3,20,11,L0|L1}, /* 93: 0110 0100 1001 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 94: 0110 0100 1001 0100 xxxx xxxx */
+ {XRI_TMM_xx, 3,20,11,L0|L1}, /* 95: 0110 0100 1001 0101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 96: 0110 0100 1001 0110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 97: 0110 0100 1001 0111 xxxx xxxx */
+ {ORI_ANM_xx, 3,20,11,L0|L1}, /* 98: 0110 0100 1001 1000 xxxx xxxx */
+ {ORI_SMH_xx, 3,20,11,L0|L1}, /* 99: 0110 0100 1001 1001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 9a: 0110 0100 1001 1010 xxxx xxxx */
+ {ORI_EOM_xx, 3,20,11,L0|L1}, /* 9b: 0110 0100 1001 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 9c: 0110 0100 1001 1100 xxxx xxxx */
+ {ORI_TMM_xx, 3,20,11,L0|L1}, /* 9d: 0110 0100 1001 1101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 9e: 0110 0100 1001 1110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* 9f: 0110 0100 1001 1111 xxxx xxxx */
+
+ {ADINC_ANM_xx, 3,20,11,L0|L1}, /* a0: 0110 0100 1010 0000 xxxx xxxx */
+ {ADINC_SMH_xx, 3,20,11,L0|L1}, /* a1: 0110 0100 1010 0001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* a2: 0110 0100 1010 0010 xxxx xxxx */
+ {ADINC_EOM_xx, 3,20,11,L0|L1}, /* a3: 0110 0100 1010 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* a4: 0110 0100 1010 0100 xxxx xxxx */
+ {ADINC_TMM_xx, 3,20,11,L0|L1}, /* a5: 0110 0100 1010 0101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* a6: 0110 0100 1010 0110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* a7: 0110 0100 1010 0111 xxxx xxxx */
+ {GTI_ANM_xx, 3,20,11,L0|L1}, /* a8: 0110 0100 1010 1000 xxxx xxxx */
+ {GTI_SMH_xx, 3,20,11,L0|L1}, /* a9: 0110 0100 1010 1001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* aa: 0110 0100 1010 1010 xxxx xxxx */
+ {GTI_EOM_xx, 3,20,11,L0|L1}, /* ab: 0110 0100 1010 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* ac: 0110 0100 1010 1100 xxxx xxxx */
+ {GTI_TMM_xx, 3,20,11,L0|L1}, /* ad: 0110 0100 1010 1101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* ae: 0110 0100 1010 1110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* af: 0110 0100 1010 1111 xxxx xxxx */
+
+ {SUINB_ANM_xx, 3,20,11,L0|L1}, /* b0: 0110 0100 1011 0000 xxxx xxxx */
+ {SUINB_SMH_xx, 3,20,11,L0|L1}, /* b1: 0110 0100 1011 0001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* b2: 0110 0100 1011 0010 xxxx xxxx */
+ {SUINB_EOM_xx, 3,20,11,L0|L1}, /* b3: 0110 0100 1011 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* b4: 0110 0100 1011 0100 xxxx xxxx */
+ {SUINB_TMM_xx, 3,20,11,L0|L1}, /* b5: 0110 0100 1011 0101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* b6: 0110 0100 1011 0110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* b7: 0110 0100 1011 0111 xxxx xxxx */
+ {LTI_ANM_xx, 3,20,11,L0|L1}, /* b8: 0110 0100 1011 1000 xxxx xxxx */
+ {LTI_SMH_xx, 3,20,11,L0|L1}, /* b9: 0110 0100 1011 1001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* ba: 0110 0100 1011 1010 xxxx xxxx */
+ {LTI_EOM_xx, 3,20,11,L0|L1}, /* bb: 0110 0100 1011 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* bc: 0110 0100 1011 1100 xxxx xxxx */
+ {LTI_TMM_xx, 3,20,11,L0|L1}, /* bd: 0110 0100 1011 1101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* be: 0110 0100 1011 1110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* bf: 0110 0100 1011 1111 xxxx xxxx */
+
+ {ADI_ANM_xx, 3,20,11,L0|L1}, /* c0: 0110 0100 1100 0000 xxxx xxxx */
+ {ADI_SMH_xx, 3,20,11,L0|L1}, /* c1: 0110 0100 1100 0001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* c2: 0110 0100 1100 0010 xxxx xxxx */
+ {ADI_EOM_xx, 3,20,11,L0|L1}, /* c3: 0110 0100 1100 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* c4: 0110 0100 1100 0100 xxxx xxxx */
+ {ADI_TMM_xx, 3,20,11,L0|L1}, /* c5: 0110 0100 1100 0101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* c6: 0110 0100 1100 0110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* c7: 0110 0100 1100 0111 xxxx xxxx */
+ {ONI_ANM_xx, 3,20,11,L0|L1}, /* c8: 0110 0100 1100 1000 xxxx xxxx */
+ {ONI_SMH_xx, 3,20,11,L0|L1}, /* c9: 0110 0100 1100 1001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* ca: 0110 0100 1100 1010 xxxx xxxx */
+ {ONI_EOM_xx, 3,20,11,L0|L1}, /* cb: 0110 0100 1100 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* cc: 0110 0100 1100 1100 xxxx xxxx */
+ {ONI_TMM_xx, 3,20,11,L0|L1}, /* cd: 0110 0100 1100 1101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* ce: 0110 0100 1100 1110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* cf: 0110 0100 1100 1111 xxxx xxxx */
+
+ {ACI_ANM_xx, 3,20,11,L0|L1}, /* d0: 0110 0100 1101 0000 xxxx xxxx */
+ {ACI_SMH_xx, 3,20,11,L0|L1}, /* d1: 0110 0100 1101 0001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* d2: 0110 0100 1101 0010 xxxx xxxx */
+ {ACI_EOM_xx, 3,20,11,L0|L1}, /* d3: 0110 0100 1101 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* d4: 0110 0100 1101 0100 xxxx xxxx */
+ {ACI_TMM_xx, 3,20,11,L0|L1}, /* d5: 0110 0100 1101 0101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* d6: 0110 0100 1101 0110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* d7: 0110 0100 1101 0111 xxxx xxxx */
+ {OFFI_ANM_xx, 3,20,11,L0|L1}, /* d8: 0110 0100 1101 1000 xxxx xxxx */
+ {OFFI_SMH_xx, 3,20,11,L0|L1}, /* d9: 0110 0100 1101 1001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* da: 0110 0100 1101 1010 xxxx xxxx */
+ {OFFI_EOM_xx, 3,20,11,L0|L1}, /* db: 0110 0100 1101 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* dc: 0110 0100 1101 1100 xxxx xxxx */
+ {OFFI_TMM_xx, 3,20,11,L0|L1}, /* dd: 0110 0100 1101 1101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* de: 0110 0100 1101 1110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* df: 0110 0100 1101 1111 xxxx xxxx */
+
+ {SUI_ANM_xx, 3,20,11,L0|L1}, /* e0: 0110 0100 1110 0000 xxxx xxxx */
+ {SUI_SMH_xx, 3,20,11,L0|L1}, /* e1: 0110 0100 1110 0001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* e2: 0110 0100 1110 0010 xxxx xxxx */
+ {SUI_EOM_xx, 3,20,11,L0|L1}, /* e3: 0110 0100 1110 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* e4: 0110 0100 1110 0100 xxxx xxxx */
+ {SUI_TMM_xx, 3,20,11,L0|L1}, /* e5: 0110 0100 1110 0101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* e6: 0110 0100 1110 0110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* e7: 0110 0100 1110 0111 xxxx xxxx */
+ {NEI_ANM_xx, 3,20,11,L0|L1}, /* e8: 0110 0100 1110 1000 xxxx xxxx */
+ {NEI_SMH_xx, 3,20,11,L0|L1}, /* e9: 0110 0100 1110 1001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* ea: 0110 0100 1110 1010 xxxx xxxx */
+ {NEI_EOM_xx, 3,20,11,L0|L1}, /* eb: 0110 0100 1110 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* ec: 0110 0100 1110 1100 xxxx xxxx */
+ {NEI_TMM_xx, 3,20,11,L0|L1}, /* ed: 0110 0100 1110 1101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* ee: 0110 0100 1110 1110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* ef: 0110 0100 1110 1111 xxxx xxxx */
+
+ {SBI_ANM_xx, 3,20,11,L0|L1}, /* f0: 0110 0100 1111 0000 xxxx xxxx */
+ {SBI_SMH_xx, 3,20,11,L0|L1}, /* f1: 0110 0100 1111 0001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* f2: 0110 0100 1111 0010 xxxx xxxx */
+ {SBI_EOM_xx, 3,20,11,L0|L1}, /* f3: 0110 0100 1111 0011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* f4: 0110 0100 1111 0100 xxxx xxxx */
+ {SBI_TMM_xx, 3,20,11,L0|L1}, /* f5: 0110 0100 1111 0101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* f6: 0110 0100 1111 0110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* f7: 0110 0100 1111 0111 xxxx xxxx */
+ {EQI_ANM_xx, 3,20,11,L0|L1}, /* f8: 0110 0100 1111 1000 xxxx xxxx */
+ {EQI_SMH_xx, 3,20,11,L0|L1}, /* f9: 0110 0100 1111 1001 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* fa: 0110 0100 1111 1010 xxxx xxxx */
+ {EQI_EOM_xx, 3,20,11,L0|L1}, /* fb: 0110 0100 1111 1011 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* fc: 0110 0100 1111 1100 xxxx xxxx */
+ {EQI_TMM_xx, 3,20,11,L0|L1}, /* fd: 0110 0100 1111 1101 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1}, /* fe: 0110 0100 1111 1110 xxxx xxxx */
+ {illegal2, 3,11,11,L0|L1} /* ff: 0110 0100 1111 1111 xxxx xxxx */
+};
+
+/* prefix 70 */
+static struct opcode_s op70[256] =
+{
+ {illegal2, 2, 8, 8,L0|L1}, /* 00: 0111 0000 0000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 01: 0111 0000 0000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 02: 0111 0000 0000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 03: 0111 0000 0000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 04: 0111 0000 0000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 05: 0111 0000 0000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 06: 0111 0000 0000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 07: 0111 0000 0000 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 08: 0111 0000 0000 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 09: 0111 0000 0000 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0a: 0111 0000 0000 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0b: 0111 0000 0000 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0c: 0111 0000 0000 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 0d: 0111 0000 0000 1101 */
+ {SSPD_w, 4,20,20,L0|L1}, /* 0e: 0111 0000 0000 1110 llll llll hhhh hhhh */
+ {LSPD_w, 4,20,20,L0|L1}, /* 0f: 0111 0000 0000 1111 llll llll hhhh hhhh */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 10: 0111 0000 0001 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 11: 0111 0000 0001 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 12: 0111 0000 0001 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 13: 0111 0000 0001 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 14: 0111 0000 0001 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 15: 0111 0000 0001 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 16: 0111 0000 0001 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 17: 0111 0000 0001 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 18: 0111 0000 0001 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 19: 0111 0000 0001 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1a: 0111 0000 0001 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1b: 0111 0000 0001 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1c: 0111 0000 0001 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 1d: 0111 0000 0001 1101 */
+ {SBCD_w, 4,20,20,L0|L1}, /* 1e: 0111 0000 0001 1110 llll llll hhhh hhhh */
+ {LBCD_w, 4,20,20,L0|L1}, /* 1f: 0111 0000 0001 1111 llll llll hhhh hhhh */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 20: 0111 0000 0010 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 21: 0111 0000 0010 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 22: 0111 0000 0010 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 23: 0111 0000 0010 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 24: 0111 0000 0010 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 25: 0111 0000 0010 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 26: 0111 0000 0010 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 27: 0111 0000 0010 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 28: 0111 0000 0010 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 29: 0111 0000 0010 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2a: 0111 0000 0010 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2b: 0111 0000 0010 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2c: 0111 0000 0010 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 2d: 0111 0000 0010 1101 */
+ {SDED_w, 4,20,20,L0|L1}, /* 2e: 0111 0000 0010 1110 llll llll hhhh hhhh */
+ {LDED_w, 4,20,20,L0|L1}, /* 2f: 0111 0000 0010 1111 llll llll hhhh hhhh */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 30: 0111 0000 0011 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 31: 0111 0000 0011 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 32: 0111 0000 0011 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 33: 0111 0000 0011 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 34: 0111 0000 0011 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 35: 0111 0000 0011 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 36: 0111 0000 0011 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 37: 0111 0000 0011 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 38: 0111 0000 0011 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 39: 0111 0000 0011 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3a: 0111 0000 0011 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3b: 0111 0000 0011 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3c: 0111 0000 0011 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 3d: 0111 0000 0011 1101 */
+ {SHLD_w, 4,20,20,L0|L1}, /* 3e: 0111 0000 0011 1110 llll llll hhhh hhhh */
+ {LHLD_w, 4,20,20,L0|L1}, /* 3f: 0111 0000 0011 1111 llll llll hhhh hhhh */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 40: 0111 0000 0100 0000 */
+ {EADD_EA_A, 2,11,11,L0|L1}, /* 41: 0111 0000 0100 0001 */
+ {EADD_EA_B, 2,11,11,L0|L1}, /* 42: 0111 0000 0100 0010 */
+ {EADD_EA_C, 2,11,11,L0|L1}, /* 43: 0111 0000 0100 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 44: 0111 0000 0100 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 45: 0111 0000 0100 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 46: 0111 0000 0100 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 47: 0111 0000 0100 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 48: 0111 0000 0100 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 49: 0111 0000 0100 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4a: 0111 0000 0100 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4b: 0111 0000 0100 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4c: 0111 0000 0100 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4d: 0111 0000 0100 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4e: 0111 0000 0100 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 4f: 0111 0000 0100 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 50: 0111 0000 0101 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 51: 0111 0000 0101 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 52: 0111 0000 0101 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 53: 0111 0000 0101 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 54: 0111 0000 0101 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 55: 0111 0000 0101 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 56: 0111 0000 0101 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 57: 0111 0000 0101 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 58: 0111 0000 0101 1000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 59: 0111 0000 0101 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5a: 0111 0000 0101 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5b: 0111 0000 0101 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5c: 0111 0000 0101 1100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5d: 0111 0000 0101 1101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5e: 0111 0000 0101 1110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 5f: 0111 0000 0101 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 60: 0111 0000 0110 0000 */
+ {ESUB_EA_A, 2,11,11,L0|L1}, /* 61: 0111 0000 0110 0001 */
+ {ESUB_EA_B, 2,11,11,L0|L1}, /* 62: 0111 0000 0110 0010 */
+ {ESUB_EA_C, 2,11,11,L0|L1}, /* 63: 0111 0000 0110 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 64: 0111 0000 0110 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 65: 0111 0000 0110 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 66: 0111 0000 0110 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 67: 0111 0000 0110 0111 */
+ {MOV_V_w, 4,17,17,L0|L1}, /* 68: 0111 0000 0110 1000 llll llll hhhh hhhh */
+ {MOV_A_w, 4,17,17,L0|L1}, /* 69: 0111 0000 0110 1001 llll llll hhhh hhhh */
+ {MOV_B_w, 4,17,17,L0|L1}, /* 6a: 0111 0000 0110 1010 llll llll hhhh hhhh */
+ {MOV_C_w, 4,17,17,L0|L1}, /* 6b: 0111 0000 0110 1011 llll llll hhhh hhhh */
+ {MOV_D_w, 4,17,17,L0|L1}, /* 6c: 0111 0000 0110 1100 llll llll hhhh hhhh */
+ {MOV_E_w, 4,17,17,L0|L1}, /* 6d: 0111 0000 0110 1101 llll llll hhhh hhhh */
+ {MOV_H_w, 4,17,17,L0|L1}, /* 6e: 0111 0000 0110 1110 llll llll hhhh hhhh */
+ {MOV_L_w, 4,17,17,L0|L1}, /* 6f: 0111 0000 0110 1111 llll llll hhhh hhhh */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 70: 0111 0000 0111 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 71: 0111 0000 0111 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 72: 0111 0000 0111 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 73: 0111 0000 0111 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 74: 0111 0000 0111 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 75: 0111 0000 0111 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 76: 0111 0000 0111 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 77: 0111 0000 0111 0111 */
+ {MOV_w_V, 4,17,17,L0|L1}, /* 78: 0111 0000 0111 1000 llll llll hhhh hhhh */
+ {MOV_w_A, 4,17,17,L0|L1}, /* 79: 0111 0000 0111 1001 llll llll hhhh hhhh */
+ {MOV_w_B, 4,17,17,L0|L1}, /* 7a: 0111 0000 0111 1010 llll llll hhhh hhhh */
+ {MOV_w_C, 4,17,17,L0|L1}, /* 7b: 0111 0000 0111 1011 llll llll hhhh hhhh */
+ {MOV_w_D, 4,17,17,L0|L1}, /* 7c: 0111 0000 0111 1100 llll llll hhhh hhhh */
+ {MOV_w_E, 4,17,17,L0|L1}, /* 7d: 0111 0000 0111 1101 llll llll hhhh hhhh */
+ {MOV_w_H, 4,17,17,L0|L1}, /* 7e: 0111 0000 0111 1110 llll llll hhhh hhhh */
+ {MOV_w_L, 4,17,17,L0|L1}, /* 7f: 0111 0000 0111 1111 llll llll hhhh hhhh */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 80: 0111 0000 1000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 81: 0111 0000 1000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 82: 0111 0000 1000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 83: 0111 0000 1000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 84: 0111 0000 1000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 85: 0111 0000 1000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 86: 0111 0000 1000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 87: 0111 0000 1000 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 88: 0111 0000 1000 1000 */
+ {ANAX_B, 2,11,11,L0|L1}, /* 89: 0111 0000 1000 1001 */
+ {ANAX_D, 2,11,11,L0|L1}, /* 8a: 0111 0000 1000 1010 */
+ {ANAX_H, 2,11,11,L0|L1}, /* 8b: 0111 0000 1000 1011 */
+ {ANAX_Dp, 2,11,11,L0|L1}, /* 8c: 0111 0000 1000 1100 */
+ {ANAX_Hp, 2,11,11,L0|L1}, /* 8d: 0111 0000 1000 1101 */
+ {ANAX_Dm, 2,11,11,L0|L1}, /* 8e: 0111 0000 1000 1110 */
+ {ANAX_Hm, 2,11,11,L0|L1}, /* 8f: 0111 0000 1000 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 90: 0111 0000 1001 0000 */
+ {XRAX_B, 2,11,11,L0|L1}, /* 91: 0111 0000 1001 0001 */
+ {XRAX_D, 2,11,11,L0|L1}, /* 92: 0111 0000 1001 0010 */
+ {XRAX_H, 2,11,11,L0|L1}, /* 93: 0111 0000 1001 0011 */
+ {XRAX_Dp, 2,11,11,L0|L1}, /* 94: 0111 0000 1001 0100 */
+ {XRAX_Hp, 2,11,11,L0|L1}, /* 95: 0111 0000 1001 0101 */
+ {XRAX_Dm, 2,11,11,L0|L1}, /* 96: 0111 0000 1001 0110 */
+ {XRAX_Hm, 2,11,11,L0|L1}, /* 97: 0111 0000 1001 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 98: 0111 0000 1001 1000 */
+// orax added, timings not verified
+ {ORAX_B, 2,11, 8,L0|L1}, /* 99: 0111 0000 1001 1001 */
+ {ORAX_D, 2,11, 8,L0|L1}, /* 9a: 0111 0000 1001 1010 */
+ {ORAX_H, 2,11, 8,L0|L1}, /* 9b: 0111 0000 1001 1011 */
+ {ORAX_Dp, 2,11, 8,L0|L1}, /* 9c: 0111 0000 1001 1100 */
+ {ORAX_Hp, 2,11, 8,L0|L1}, /* 9d: 0111 0000 1001 1101 */
+ {ORAX_Dm, 2,11, 8,L0|L1}, /* 9e: 0111 0000 1001 1110 */
+ {ORAX_Hm, 2,11, 8,L0|L1}, /* 9f: 0111 0000 1001 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* a0: 0111 0000 1010 0000 */
+ {ADDNCX_B, 2,11, 8,L0|L1}, /* a1: 0111 0000 1010 0001 */
+ {ADDNCX_D, 2,11, 8,L0|L1}, /* a2: 0111 0000 1010 0010 */
+ {ADDNCX_H, 2,11, 8,L0|L1}, /* a3: 0111 0000 1010 0011 */
+ {ADDNCX_Dp, 2,11, 8,L0|L1}, /* a4: 0111 0000 1010 0100 */
+ {ADDNCX_Hp, 2,11, 8,L0|L1}, /* a5: 0111 0000 1010 0101 */
+ {ADDNCX_Dm, 2,11, 8,L0|L1}, /* a6: 0111 0000 1010 0110 */
+ {ADDNCX_Hm, 2,11, 8,L0|L1}, /* a7: 0111 0000 1010 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a8: 0111 0000 1010 1000 */
+ {GTAX_B, 2,11,11,L0|L1}, /* a9: 0111 0000 1010 1001 */
+ {GTAX_D, 2,11,11,L0|L1}, /* aa: 0111 0000 1010 1010 */
+ {GTAX_H, 2,11,11,L0|L1}, /* ab: 0111 0000 1010 1011 */
+ {GTAX_Dp, 2,11,11,L0|L1}, /* ac: 0111 0000 1010 1100 */
+ {GTAX_Hp, 2,11,11,L0|L1}, /* ad: 0111 0000 1010 1101 */
+ {GTAX_Dm, 2,11,11,L0|L1}, /* ae: 0111 0000 1010 1110 */
+ {GTAX_Hm, 2,11,11,L0|L1}, /* af: 0111 0000 1010 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* b0: 0111 0000 1011 0000 */
+ {SUBNBX_B, 2,11,11,L0|L1}, /* b1: 0111 0000 1011 0001 */
+ {SUBNBX_D, 2,11,11,L0|L1}, /* b2: 0111 0000 1011 0010 */
+ {SUBNBX_H, 2,11,11,L0|L1}, /* b3: 0111 0000 1011 0011 */
+ {SUBNBX_Dp, 2,11,11,L0|L1}, /* b4: 0111 0000 1011 0100 */
+ {SUBNBX_Hp, 2,11,11,L0|L1}, /* b5: 0111 0000 1011 0101 */
+ {SUBNBX_Dm, 2,11,11,L0|L1}, /* b6: 0111 0000 1011 0110 */
+ {SUBNBX_Hm, 2,11,11,L0|L1}, /* b7: 0111 0000 1011 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b8: 0111 0000 1011 1000 */
+ {LTAX_B, 2,11,11,L0|L1}, /* b9: 0111 0000 1011 1001 */
+ {LTAX_D, 2,11,11,L0|L1}, /* ba: 0111 0000 1011 1010 */
+ {LTAX_H, 2,11,11,L0|L1}, /* bb: 0111 0000 1011 1011 */
+ {LTAX_Dp, 2,11,11,L0|L1}, /* bc: 0111 0000 1011 1100 */
+ {LTAX_Hp, 2,11,11,L0|L1}, /* bd: 0111 0000 1011 1101 */
+ {LTAX_Dm, 2,11,11,L0|L1}, /* be: 0111 0000 1011 1110 */
+ {LTAX_Hm, 2,11,11,L0|L1}, /* bf: 0111 0000 1011 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* c0: 0111 0000 1100 0000 */
+ {ADDX_B, 2,11, 8,L0|L1}, /* c1: 0111 0000 1100 0001 */
+ {ADDX_D, 2,11, 8,L0|L1}, /* c2: 0111 0000 1100 0010 */
+ {ADDX_H, 2,11, 8,L0|L1}, /* c3: 0111 0000 1100 0011 */
+ {ADDX_Dp, 2,11, 8,L0|L1}, /* c4: 0111 0000 1100 0100 */
+ {ADDX_Hp, 2,11, 8,L0|L1}, /* c5: 0111 0000 1100 0101 */
+ {ADDX_Dm, 2,11, 8,L0|L1}, /* c6: 0111 0000 1100 0110 */
+ {ADDX_Hm, 2,11, 8,L0|L1}, /* c7: 0111 0000 1100 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c8: 0111 0000 1100 1000 */
+ {ONAX_B, 2,11, 8,L0|L1}, /* c9: 0111 0000 1100 1001 */
+ {ONAX_D, 2,11, 8,L0|L1}, /* ca: 0111 0000 1100 1010 */
+ {ONAX_H, 2,11, 8,L0|L1}, /* cb: 0111 0000 1100 1011 */
+ {ONAX_Dp, 2,11, 8,L0|L1}, /* cc: 0111 0000 1100 1100 */
+ {ONAX_Hp, 2,11, 8,L0|L1}, /* cd: 0111 0000 1100 1101 */
+ {ONAX_Dm, 2,11, 8,L0|L1}, /* ce: 0111 0000 1100 1110 */
+ {ONAX_Hm, 2,11, 8,L0|L1}, /* cf: 0111 0000 1100 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* d0: 0111 0000 1101 0000 */
+ {ADCX_B, 2,11, 8,L0|L1}, /* d1: 0111 0000 1101 0001 */
+ {ADCX_D, 2,11, 8,L0|L1}, /* d2: 0111 0000 1101 0010 */
+ {ADCX_H, 2,11, 8,L0|L1}, /* d3: 0111 0000 1101 0011 */
+ {ADCX_Dp, 2,11, 8,L0|L1}, /* d4: 0111 0000 1101 0100 */
+ {ADCX_Hp, 2,11, 8,L0|L1}, /* d5: 0111 0000 1101 0101 */
+ {ADCX_Dm, 2,11, 8,L0|L1}, /* d6: 0111 0000 1101 0110 */
+ {ADCX_Hm, 2,11, 8,L0|L1}, /* d7: 0111 0000 1101 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d8: 0111 0000 1101 1000 */
+ {OFFAX_B, 2,11, 8,L0|L1}, /* d9: 0111 0000 1101 1001 */
+ {OFFAX_D, 2,11, 8,L0|L1}, /* da: 0111 0000 1101 1010 */
+ {OFFAX_H, 2,11, 8,L0|L1}, /* db: 0111 0000 1101 1011 */
+ {OFFAX_Dp, 2,11, 8,L0|L1}, /* dc: 0111 0000 1101 1100 */
+ {OFFAX_Hp, 2,11, 8,L0|L1}, /* dd: 0111 0000 1101 1101 */
+ {OFFAX_Dm, 2,11, 8,L0|L1}, /* de: 0111 0000 1101 1110 */
+ {OFFAX_Hm, 2,11, 8,L0|L1}, /* df: 0111 0000 1101 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* e0: 0111 0000 1110 0000 */
+ {SUBX_B, 2,11,11,L0|L1}, /* e1: 0111 0000 1110 0001 */
+ {SUBX_D, 2,11,11,L0|L1}, /* e2: 0111 0000 1110 0010 */
+ {SUBX_H, 2,11,11,L0|L1}, /* e3: 0111 0000 1110 0011 */
+ {SUBX_Dp, 2,11,11,L0|L1}, /* e4: 0111 0000 1110 0100 */
+ {SUBX_Hp, 2,11,11,L0|L1}, /* e5: 0111 0000 1110 0101 */
+ {SUBX_Dm, 2,11,11,L0|L1}, /* e6: 0111 0000 1110 0110 */
+ {SUBX_Hm, 2,11,11,L0|L1}, /* e7: 0111 0000 1110 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e8: 0111 0000 1110 1000 */
+ {NEAX_B, 2,11,11,L0|L1}, /* e9: 0111 0000 1110 1001 */
+ {NEAX_D, 2,11,11,L0|L1}, /* ea: 0111 0000 1110 1010 */
+ {NEAX_H, 2,11,11,L0|L1}, /* eb: 0111 0000 1110 1011 */
+ {NEAX_Dp, 2,11,11,L0|L1}, /* ec: 0111 0000 1110 1100 */
+ {NEAX_Hp, 2,11,11,L0|L1}, /* ed: 0111 0000 1110 1101 */
+ {NEAX_Dm, 2,11,11,L0|L1}, /* ee: 0111 0000 1110 1110 */
+ {NEAX_Hm, 2,11,11,L0|L1}, /* ef: 0111 0000 1110 1111 */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* f0: 0111 0000 1111 0000 */
+ {SBBX_B, 2,11,11,L0|L1}, /* f1: 0111 0000 1111 0001 */
+ {SBBX_D, 2,11,11,L0|L1}, /* f2: 0111 0000 1111 0010 */
+ {SBBX_H, 2,11,11,L0|L1}, /* f3: 0111 0000 1111 0011 */
+ {SBBX_Dp, 2,11,11,L0|L1}, /* f4: 0111 0000 1111 0100 */
+ {SBBX_Hp, 2,11,11,L0|L1}, /* f5: 0111 0000 1111 0101 */
+ {SBBX_Dm, 2,11,11,L0|L1}, /* f6: 0111 0000 1111 0110 */
+ {SBBX_Hm, 2,11,11,L0|L1}, /* f7: 0111 0000 1111 0111 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f8: 0111 0000 1111 1000 */
+ {EQAX_B, 2,11,11,L0|L1}, /* f9: 0111 0000 1111 1001 */
+ {EQAX_D, 2,11,11,L0|L1}, /* fa: 0111 0000 1111 1010 */
+ {EQAX_H, 2,11,11,L0|L1}, /* fb: 0111 0000 1111 1011 */
+ {EQAX_Dp, 2,11,11,L0|L1}, /* fc: 0111 0000 1111 1100 */
+ {EQAX_Hp, 2,11,11,L0|L1}, /* fd: 0111 0000 1111 1101 */
+ {EQAX_Dm, 2,11,11,L0|L1}, /* fe: 0111 0000 1111 1110 */
+ {EQAX_Hm, 2,11,11,L0|L1} /* ff: 0111 0000 1111 1111 */
+};
+
+/* prefix 74 */
+static struct opcode_s op74[256] =
+{
+ {illegal2, 2, 8, 8,L0|L1}, /* 00: 0111 0100 0000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 01: 0111 0100 0000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 02: 0111 0100 0000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 03: 0111 0100 0000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 04: 0111 0100 0000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 05: 0111 0100 0000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 06: 0111 0100 0000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 07: 0111 0100 0000 0111 */
+ {ANI_V_xx, 3,11,11,L0|L1}, /* 08: 0111 0100 0000 1000 xxxx xxxx */
+ {ANI_A_xx, 3,11,11,L0|L1}, /* 09: 0111 0100 0000 1001 xxxx xxxx */
+ {ANI_B_xx, 3,11,11,L0|L1}, /* 0a: 0111 0100 0000 1010 xxxx xxxx */
+ {ANI_C_xx, 3,11,11,L0|L1}, /* 0b: 0111 0100 0000 1011 xxxx xxxx */
+ {ANI_D_xx, 3,11,11,L0|L1}, /* 0c: 0111 0100 0000 1100 xxxx xxxx */
+ {ANI_E_xx, 3,11,11,L0|L1}, /* 0d: 0111 0100 0000 1101 xxxx xxxx */
+ {ANI_H_xx, 3,11,11,L0|L1}, /* 0e: 0111 0100 0000 1110 xxxx xxxx */
+ {ANI_L_xx, 3,11,11,L0|L1}, /* 0f: 0111 0100 0000 1111 xxxx xxxx */
+
+ {XRI_V_xx, 3,11,11,L0|L1}, /* 10: 0111 0100 0001 0000 xxxx xxxx */
+ {XRI_A_xx, 3,11,11,L0|L1}, /* 11: 0111 0100 0001 0001 xxxx xxxx */
+ {XRI_B_xx, 3,11,11,L0|L1}, /* 12: 0111 0100 0001 0010 xxxx xxxx */
+ {XRI_C_xx, 3,11,11,L0|L1}, /* 13: 0111 0100 0001 0011 xxxx xxxx */
+ {XRI_D_xx, 3,11,11,L0|L1}, /* 14: 0111 0100 0001 0100 xxxx xxxx */
+ {XRI_E_xx, 3,11,11,L0|L1}, /* 15: 0111 0100 0001 0101 xxxx xxxx */
+ {XRI_H_xx, 3,11,11,L0|L1}, /* 16: 0111 0100 0001 0110 xxxx xxxx */
+ {XRI_L_xx, 3,11,11,L0|L1}, /* 17: 0111 0100 0001 0111 xxxx xxxx */
+ {ORI_V_xx, 3,11,11,L0|L1}, /* 18: 0111 0100 0001 1000 xxxx xxxx */
+ {ORI_A_xx, 3,11,11,L0|L1}, /* 19: 0111 0100 0001 1001 xxxx xxxx */
+ {ORI_B_xx, 3,11,11,L0|L1}, /* 1a: 0111 0100 0001 1010 xxxx xxxx */
+ {ORI_C_xx, 3,11,11,L0|L1}, /* 1b: 0111 0100 0001 1011 xxxx xxxx */
+ {ORI_D_xx, 3,11,11,L0|L1}, /* 1c: 0111 0100 0001 1100 xxxx xxxx */
+ {ORI_E_xx, 3,11,11,L0|L1}, /* 1d: 0111 0100 0001 1101 xxxx xxxx */
+ {ORI_H_xx, 3,11,11,L0|L1}, /* 1e: 0111 0100 0001 1110 xxxx xxxx */
+ {ORI_L_xx, 3,11,11,L0|L1}, /* 1f: 0111 0100 0001 1111 xxxx xxxx */
+
+ {ADINC_V_xx, 3,11,11,L0|L1}, /* 20: 0111 0100 0010 0000 xxxx xxxx */
+ {ADINC_A_xx, 3,11,11,L0|L1}, /* 21: 0111 0100 0010 0001 xxxx xxxx */
+ {ADINC_B_xx, 3,11,11,L0|L1}, /* 22: 0111 0100 0010 0010 xxxx xxxx */
+ {ADINC_C_xx, 3,11,11,L0|L1}, /* 23: 0111 0100 0010 0011 xxxx xxxx */
+ {ADINC_D_xx, 3,11,11,L0|L1}, /* 24: 0111 0100 0010 0100 xxxx xxxx */
+ {ADINC_E_xx, 3,11,11,L0|L1}, /* 25: 0111 0100 0010 0101 xxxx xxxx */
+ {ADINC_H_xx, 3,11,11,L0|L1}, /* 26: 0111 0100 0010 0110 xxxx xxxx */
+ {ADINC_L_xx, 3,11,11,L0|L1}, /* 27: 0111 0100 0010 0111 xxxx xxxx */
+ {GTI_V_xx, 3,11,11,L0|L1}, /* 28: 0111 0100 0010 1000 xxxx xxxx */
+ {GTI_A_xx, 3,11,11,L0|L1}, /* 29: 0111 0100 0010 1001 xxxx xxxx */
+ {GTI_B_xx, 3,11,11,L0|L1}, /* 2a: 0111 0100 0010 1010 xxxx xxxx */
+ {GTI_C_xx, 3,11,11,L0|L1}, /* 2b: 0111 0100 0010 1011 xxxx xxxx */
+ {GTI_D_xx, 3,11,11,L0|L1}, /* 2c: 0111 0100 0010 1100 xxxx xxxx */
+ {GTI_E_xx, 3,11,11,L0|L1}, /* 2d: 0111 0100 0010 1101 xxxx xxxx */
+ {GTI_H_xx, 3,11,11,L0|L1}, /* 2e: 0111 0100 0010 1110 xxxx xxxx */
+ {GTI_L_xx, 3,11,11,L0|L1}, /* 2f: 0111 0100 0010 1111 xxxx xxxx */
+
+ {SUINB_V_xx, 3,11,11,L0|L1}, /* 30: 0111 0100 0011 0000 xxxx xxxx */
+ {SUINB_A_xx, 3,11,11,L0|L1}, /* 31: 0111 0100 0011 0001 xxxx xxxx */
+ {SUINB_B_xx, 3,11,11,L0|L1}, /* 32: 0111 0100 0011 0010 xxxx xxxx */
+ {SUINB_C_xx, 3,11,11,L0|L1}, /* 33: 0111 0100 0011 0011 xxxx xxxx */
+ {SUINB_D_xx, 3,11,11,L0|L1}, /* 34: 0111 0100 0011 0100 xxxx xxxx */
+ {SUINB_E_xx, 3,11,11,L0|L1}, /* 35: 0111 0100 0011 0101 xxxx xxxx */
+ {SUINB_H_xx, 3,11,11,L0|L1}, /* 36: 0111 0100 0011 0110 xxxx xxxx */
+ {SUINB_L_xx, 3,11,11,L0|L1}, /* 37: 0111 0100 0011 0111 xxxx xxxx */
+ {LTI_V_xx, 3,11,11,L0|L1}, /* 38: 0111 0100 0011 1000 xxxx xxxx */
+ {LTI_A_xx, 3,11,11,L0|L1}, /* 39: 0111 0100 0011 1001 xxxx xxxx */
+ {LTI_B_xx, 3,11,11,L0|L1}, /* 3a: 0111 0100 0011 1010 xxxx xxxx */
+ {LTI_C_xx, 3,11,11,L0|L1}, /* 3b: 0111 0100 0011 1011 xxxx xxxx */
+ {LTI_D_xx, 3,11,11,L0|L1}, /* 3c: 0111 0100 0011 1100 xxxx xxxx */
+ {LTI_E_xx, 3,11,11,L0|L1}, /* 3d: 0111 0100 0011 1101 xxxx xxxx */
+ {LTI_H_xx, 3,11,11,L0|L1}, /* 3e: 0111 0100 0011 1110 xxxx xxxx */
+ {LTI_L_xx, 3,11,11,L0|L1}, /* 3f: 0111 0100 0011 1111 xxxx xxxx */
+
+ {ADI_V_xx, 3,11,11,L0|L1}, /* 40: 0111 0100 0100 0000 xxxx xxxx */
+ {ADI_A_xx, 3,11,11,L0|L1}, /* 41: 0111 0100 0100 0001 xxxx xxxx */
+ {ADI_B_xx, 3,11,11,L0|L1}, /* 42: 0111 0100 0100 0010 xxxx xxxx */
+ {ADI_C_xx, 3,11,11,L0|L1}, /* 43: 0111 0100 0100 0011 xxxx xxxx */
+ {ADI_D_xx, 3,11,11,L0|L1}, /* 44: 0111 0100 0100 0100 xxxx xxxx */
+ {ADI_E_xx, 3,11,11,L0|L1}, /* 45: 0111 0100 0100 0101 xxxx xxxx */
+ {ADI_H_xx, 3,11,11,L0|L1}, /* 46: 0111 0100 0100 0110 xxxx xxxx */
+ {ADI_L_xx, 3,11,11,L0|L1}, /* 47: 0111 0100 0100 0111 xxxx xxxx */
+ {ONI_V_xx, 3,11,11,L0|L1}, /* 48: 0111 0100 0100 1000 xxxx xxxx */
+ {ONI_A_xx, 3,11,11,L0|L1}, /* 49: 0111 0100 0100 1001 xxxx xxxx */
+ {ONI_B_xx, 3,11,11,L0|L1}, /* 4a: 0111 0100 0100 1010 xxxx xxxx */
+ {ONI_C_xx, 3,11,11,L0|L1}, /* 4b: 0111 0100 0100 1011 xxxx xxxx */
+ {ONI_D_xx, 3,11,11,L0|L1}, /* 4c: 0111 0100 0100 1100 xxxx xxxx */
+ {ONI_E_xx, 3,11,11,L0|L1}, /* 4d: 0111 0100 0100 1101 xxxx xxxx */
+ {ONI_H_xx, 3,11,11,L0|L1}, /* 4e: 0111 0100 0100 1110 xxxx xxxx */
+ {ONI_L_xx, 3,11,11,L0|L1}, /* 4f: 0111 0100 0100 1111 xxxx xxxx */
+
+ {ACI_V_xx, 3,11,11,L0|L1}, /* 50: 0111 0100 0101 0000 xxxx xxxx */
+ {ACI_A_xx, 3,11,11,L0|L1}, /* 51: 0111 0100 0101 0001 xxxx xxxx */
+ {ACI_B_xx, 3,11,11,L0|L1}, /* 52: 0111 0100 0101 0010 xxxx xxxx */
+ {ACI_C_xx, 3,11,11,L0|L1}, /* 53: 0111 0100 0101 0011 xxxx xxxx */
+ {ACI_D_xx, 3,11,11,L0|L1}, /* 54: 0111 0100 0101 0100 xxxx xxxx */
+ {ACI_E_xx, 3,11,11,L0|L1}, /* 55: 0111 0100 0101 0101 xxxx xxxx */
+ {ACI_H_xx, 3,11,11,L0|L1}, /* 56: 0111 0100 0101 0110 xxxx xxxx */
+ {ACI_L_xx, 3,11,11,L0|L1}, /* 57: 0111 0100 0101 0111 xxxx xxxx */
+ {OFFI_V_xx, 3,11,11,L0|L1}, /* 58: 0111 0100 0101 1000 xxxx xxxx */
+ {OFFI_A_xx, 3,11,11,L0|L1}, /* 59: 0111 0100 0101 1001 xxxx xxxx */
+ {OFFI_B_xx, 3,11,11,L0|L1}, /* 5a: 0111 0100 0101 1010 xxxx xxxx */
+ {OFFI_C_xx, 3,11,11,L0|L1}, /* 5b: 0111 0100 0101 1011 xxxx xxxx */
+ {OFFI_D_xx, 3,11,11,L0|L1}, /* 5c: 0111 0100 0101 1100 xxxx xxxx */
+ {OFFI_E_xx, 3,11,11,L0|L1}, /* 5d: 0111 0100 0101 1101 xxxx xxxx */
+ {OFFI_H_xx, 3,11,11,L0|L1}, /* 5e: 0111 0100 0101 1110 xxxx xxxx */
+ {OFFI_L_xx, 3,11,11,L0|L1}, /* 5f: 0111 0100 0101 1111 xxxx xxxx */
+
+ {SUI_V_xx, 3,11,11,L0|L1}, /* 60: 0111 0100 0110 0000 xxxx xxxx */
+ {SUI_A_xx, 3,11,11,L0|L1}, /* 61: 0111 0100 0110 0001 xxxx xxxx */
+ {SUI_B_xx, 3,11,11,L0|L1}, /* 62: 0111 0100 0110 0010 xxxx xxxx */
+ {SUI_C_xx, 3,11,11,L0|L1}, /* 63: 0111 0100 0110 0011 xxxx xxxx */
+ {SUI_D_xx, 3,11,11,L0|L1}, /* 64: 0111 0100 0110 0100 xxxx xxxx */
+ {SUI_E_xx, 3,11,11,L0|L1}, /* 65: 0111 0100 0110 0101 xxxx xxxx */
+ {SUI_H_xx, 3,11,11,L0|L1}, /* 66: 0111 0100 0110 0110 xxxx xxxx */
+ {SUI_L_xx, 3,11,11,L0|L1}, /* 67: 0111 0100 0110 0111 xxxx xxxx */
+ {NEI_V_xx, 3,11,11,L0|L1}, /* 68: 0111 0100 0110 1000 xxxx xxxx */
+ {NEI_A_xx, 3,11,11,L0|L1}, /* 69: 0111 0100 0110 1001 xxxx xxxx */
+ {NEI_B_xx, 3,11,11,L0|L1}, /* 6a: 0111 0100 0110 1010 xxxx xxxx */
+ {NEI_C_xx, 3,11,11,L0|L1}, /* 6b: 0111 0100 0110 1011 xxxx xxxx */
+ {NEI_D_xx, 3,11,11,L0|L1}, /* 6c: 0111 0100 0110 1100 xxxx xxxx */
+ {NEI_E_xx, 3,11,11,L0|L1}, /* 6d: 0111 0100 0110 1101 xxxx xxxx */
+ {NEI_H_xx, 3,11,11,L0|L1}, /* 6e: 0111 0100 0110 1110 xxxx xxxx */
+ {NEI_L_xx, 3,11,11,L0|L1}, /* 6f: 0111 0100 0110 1111 xxxx xxxx */
+
+ {SBI_V_xx, 3,11,11,L0|L1}, /* 70: 0111 0100 0111 0000 xxxx xxxx */
+ {SBI_A_xx, 3,11,11,L0|L1}, /* 71: 0111 0100 0111 0001 xxxx xxxx */
+ {SBI_B_xx, 3,11,11,L0|L1}, /* 72: 0111 0100 0111 0010 xxxx xxxx */
+ {SBI_C_xx, 3,11,11,L0|L1}, /* 73: 0111 0100 0111 0011 xxxx xxxx */
+ {SBI_D_xx, 3,11,11,L0|L1}, /* 74: 0111 0100 0111 0100 xxxx xxxx */
+ {SBI_E_xx, 3,11,11,L0|L1}, /* 75: 0111 0100 0111 0101 xxxx xxxx */
+ {SBI_H_xx, 3,11,11,L0|L1}, /* 76: 0111 0100 0111 0110 xxxx xxxx */
+ {SBI_L_xx, 3,11,11,L0|L1}, /* 77: 0111 0100 0111 0111 xxxx xxxx */
+ {EQI_V_xx, 3,11,11,L0|L1}, /* 78: 0111 0100 0111 1000 xxxx xxxx */
+ {EQI_A_xx, 3,11,11,L0|L1}, /* 79: 0111 0100 0111 1001 xxxx xxxx */
+ {EQI_B_xx, 3,11,11,L0|L1}, /* 7a: 0111 0100 0111 1010 xxxx xxxx */
+ {EQI_C_xx, 3,11,11,L0|L1}, /* 7b: 0111 0100 0111 1011 xxxx xxxx */
+ {EQI_D_xx, 3,11,11,L0|L1}, /* 7c: 0111 0100 0111 1100 xxxx xxxx */
+ {EQI_E_xx, 3,11,11,L0|L1}, /* 7d: 0111 0100 0111 1101 xxxx xxxx */
+ {EQI_H_xx, 3,11,11,L0|L1}, /* 7e: 0111 0100 0111 1110 xxxx xxxx */
+ {EQI_L_xx, 3,11,11,L0|L1}, /* 7f: 0111 0100 0111 1111 xxxx xxxx */
+
+ {illegal2, 2, 8, 8,L0|L1}, /* 80: 0111 0100 1000 0000 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 81: 0111 0100 1000 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 82: 0111 0100 1000 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 83: 0111 0100 1000 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 84: 0111 0100 1000 0100 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 85: 0111 0100 1000 0101 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 86: 0111 0100 1000 0110 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 87: 0111 0100 1000 0111 */
+ {ANAW_wa, 3,14,11,L0|L1}, /* 88: 0111 0100 1000 1000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* 89: 0111 0100 1000 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8a: 0111 0100 1000 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8b: 0111 0100 1000 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 8c: 0111 0100 1000 1100 */
+ {DAN_EA_BC, 2,11,11,L0|L1}, /* 8d: 0111 0100 1000 1101 */
+ {DAN_EA_DE, 2,11,11,L0|L1}, /* 8e: 0111 0100 1000 1110 */
+ {DAN_EA_HL, 2,11,11,L0|L1}, /* 8f: 0111 0100 1000 1111 */
+
+ {XRAW_wa, 3,14,11,L0|L1}, /* 90: 0111 0100 1001 0000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* 91: 0111 0100 1001 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 92: 0111 0100 1001 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 93: 0111 0100 1001 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 94: 0111 0100 1001 0100 */
+ {DXR_EA_BC, 2,11,11,L0|L1}, /* 95: 0111 0100 1001 0101 */
+ {DXR_EA_DE, 2,11,11,L0|L1}, /* 96: 0111 0100 1001 0110 */
+ {DXR_EA_HL, 2,11,11,L0|L1}, /* 97: 0111 0100 1001 0111 */
+ {ORAW_wa, 3,14,11,L0|L1}, /* 98: 0111 0100 1001 1000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* 99: 0111 0100 1001 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9a: 0111 0100 1001 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9b: 0111 0100 1001 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* 9c: 0111 0100 1001 1100 */
+ {DOR_EA_BC, 2,11,11,L0|L1}, /* 9d: 0111 0100 1001 1101 */
+ {DOR_EA_DE, 2,11,11,L0|L1}, /* 9e: 0111 0100 1001 1110 */
+ {DOR_EA_HL, 2,11,11,L0|L1}, /* 9f: 0111 0100 1001 1111 */
+
+ {ADDNCW_wa, 3,14,11,L0|L1}, /* a0: 0111 0100 1010 0000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* a1: 0111 0100 1010 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a2: 0111 0100 1010 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a3: 0111 0100 1010 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* a4: 0111 0100 1010 0100 */
+ {DADDNC_EA_BC, 2,11,11,L0|L1}, /* a5: 0111 0100 1010 0101 */
+ {DADDNC_EA_DE, 2,11,11,L0|L1}, /* a6: 0111 0100 1010 0110 */
+ {DADDNC_EA_HL, 2,11,11,L0|L1}, /* a7: 0111 0100 1010 0111 */
+ {GTAW_wa, 3,14,11,L0|L1}, /* a8: 0111 0100 1010 1000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* a9: 0111 0100 1010 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* aa: 0111 0100 1010 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ab: 0111 0100 1010 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ac: 0111 0100 1010 1100 */
+ {DGT_EA_BC, 2,11,11,L0|L1}, /* ad: 0111 0100 1010 1101 */
+ {DGT_EA_DE, 2,11,11,L0|L1}, /* ae: 0111 0100 1010 1110 */
+ {DGT_EA_HL, 2,11,11,L0|L1}, /* af: 0111 0100 1010 1111 */
+
+ {SUBNBW_wa, 3,14,11,L0|L1}, /* b0: 0111 0100 1011 0000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* b1: 0111 0100 1011 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b2: 0111 0100 1011 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b3: 0111 0100 1011 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* b4: 0111 0100 1011 0100 */
+ {DSUBNB_EA_BC, 2,11,11,L0|L1}, /* b5: 0111 0100 1011 0101 */
+ {DSUBNB_EA_DE, 2,11,11,L0|L1}, /* b6: 0111 0100 1011 0110 */
+ {DSUBNB_EA_HL, 2,11,11,L0|L1}, /* b7: 0111 0100 1011 0111 */
+ {LTAW_wa, 3,14,11,L0|L1}, /* b8: 0111 0100 1011 1000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* b9: 0111 0100 1011 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ba: 0111 0100 1011 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bb: 0111 0100 1011 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* bc: 0111 0100 1011 1100 */
+ {DLT_EA_BC, 2,11,11,L0|L1}, /* bd: 0111 0100 1011 1101 */
+ {DLT_EA_DE, 2,11,11,L0|L1}, /* be: 0111 0100 1011 1110 */
+ {DLT_EA_HL, 2,11,11,L0|L1}, /* bf: 0111 0100 1011 1111 */
+
+ {ADDW_wa, 3,14,11,L0|L1}, /* c0: 0111 0100 1100 0000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* c1: 0111 0100 1100 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c2: 0111 0100 1100 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c3: 0111 0100 1100 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* c4: 0111 0100 1100 0100 */
+ {DADD_EA_BC, 2,11,11,L0|L1}, /* c5: 0111 0100 1100 0101 */
+ {DADD_EA_DE, 2,11,11,L0|L1}, /* c6: 0111 0100 1100 0110 */
+ {DADD_EA_HL, 2,11,11,L0|L1}, /* c7: 0111 0100 1100 0111 */
+ {ONAW_wa, 3,14,11,L0|L1}, /* c8: 0111 0100 1100 1000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* c9: 0111 0100 1100 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ca: 0111 0100 1100 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* cb: 0111 0100 1100 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* cc: 0111 0100 1100 1100 */
+ {DON_EA_BC, 2,11,11,L0|L1}, /* cd: 0111 0100 1100 1101 */
+ {DON_EA_DE, 2,11,11,L0|L1}, /* ce: 0111 0100 1100 1110 */
+ {DON_EA_HL, 2,11,11,L0|L1}, /* cf: 0111 0100 1100 1111 */
+
+ {ADCW_wa, 3,14,11,L0|L1}, /* d0: 0111 0100 1101 0000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* d1: 0111 0100 1101 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d2: 0111 0100 1101 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d3: 0111 0100 1101 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* d4: 0111 0100 1101 0100 */
+ {DADC_EA_BC, 2,11,11,L0|L1}, /* d5: 0111 0100 1101 0101 */
+ {DADC_EA_DE, 2,11,11,L0|L1}, /* d6: 0111 0100 1101 0110 */
+ {DADC_EA_HL, 2,11,11,L0|L1}, /* d7: 0111 0100 1101 0111 */
+ {OFFAW_wa, 3,14,11,L0|L1}, /* d8: 0111 0100 1101 1000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* d9: 0111 0100 1101 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* da: 0111 0100 1101 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* db: 0111 0100 1101 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* dc: 0111 0100 1101 1100 */
+ {DOFF_EA_BC, 2,11,11,L0|L1}, /* dd: 0111 0100 1101 1101 */
+ {DOFF_EA_DE, 2,11,11,L0|L1}, /* de: 0111 0100 1101 1110 */
+ {DOFF_EA_HL, 2,11,11,L0|L1}, /* df: 0111 0100 1101 1111 */
+
+ {SUBW_wa, 3,14,11,L0|L1}, /* e0: 0111 0100 1110 0000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* e1: 0111 0100 1110 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e2: 0111 0100 1110 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e3: 0111 0100 1110 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* e4: 0111 0100 1110 0100 */
+ {DSUB_EA_BC, 2,11,11,L0|L1}, /* e5: 0111 0100 1110 0101 */
+ {DSUB_EA_DE, 2,11,11,L0|L1}, /* e6: 0111 0100 1110 0110 */
+ {DSUB_EA_HL, 2,11,11,L0|L1}, /* e7: 0111 0100 1110 0111 */
+ {NEAW_wa, 3,14,11,L0|L1}, /* e8: 0111 0100 1110 1000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* e9: 0111 0100 1110 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ea: 0111 0100 1110 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* eb: 0111 0100 1110 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* ec: 0111 0100 1110 1100 */
+ {DNE_EA_BC, 2,11,11,L0|L1}, /* ed: 0111 0100 1110 1101 */
+ {DNE_EA_DE, 2,11,11,L0|L1}, /* ee: 0111 0100 1110 1110 */
+ {DNE_EA_HL, 2,11,11,L0|L1}, /* ef: 0111 0100 1110 1111 */
+
+ {SBBW_wa, 3,14,11,L0|L1}, /* f0: 0111 0100 1111 0000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* f1: 0111 0100 1111 0001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f2: 0111 0100 1111 0010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f3: 0111 0100 1111 0011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* f4: 0111 0100 1111 0100 */
+ {DSBB_EA_BC, 2,11,11,L0|L1}, /* f5: 0111 0100 1111 0101 */
+ {DSBB_EA_DE, 2,11,11,L0|L1}, /* f6: 0111 0100 1111 0110 */
+ {DSBB_EA_HL, 2,11,11,L0|L1}, /* f7: 0111 0100 1111 0111 */
+ {EQAW_wa, 3,14,11,L0|L1}, /* f8: 0111 0100 1111 1000 oooo oooo */
+ {illegal2, 2, 8, 8,L0|L1}, /* f9: 0111 0100 1111 1001 */
+ {illegal2, 2, 8, 8,L0|L1}, /* fa: 0111 0100 1111 1010 */
+ {illegal2, 2, 8, 8,L0|L1}, /* fb: 0111 0100 1111 1011 */
+ {illegal2, 2, 8, 8,L0|L1}, /* fc: 0111 0100 1111 1100 */
+ {DEQ_EA_BC, 2,11,11,L0|L1}, /* fd: 0111 0100 1111 1101 */
+ {DEQ_EA_DE, 2,11,11,L0|L1}, /* fe: 0111 0100 1111 1110 */
+ {DEQ_EA_HL, 2,11,11,L0|L1} /* ff: 0111 0100 1111 1111 */
+};
+
+/* main opcodes */
+static struct opcode_s opXX_7810[256] =
+{
+ {NOP, 1, 4, 4,L0|L1}, /* 00: 0000 0000 */
+ {LDAW_wa, 2,10,10,L0|L1}, /* 01: 0000 0001 oooo oooo */
+ {INX_SP, 1, 7, 7,L0|L1}, /* 02: 0000 0010 */
+ {DCX_SP, 1, 7, 7,L0|L1}, /* 03: 0000 0011 */
+ {LXI_S_w, 3,10,10,L0|L1}, /* 04: 0000 0100 llll llll hhhh hhhh */
+ {ANIW_wa_xx, 3,19,19,L0|L1}, /* 05: 0000 0101 oooo oooo xxxx xxxx */
+ {illegal, 1, 4, 4,L0|L1}, /* 06: */
+ {ANI_A_xx, 2, 7, 7,L0|L1}, /* 07: 0000 0111 xxxx xxxx */
+ {MOV_A_EAH, 1, 4, 4,L0|L1}, /* 08: 0000 1000 */
+ {MOV_A_EAL, 1, 4, 4,L0|L1}, /* 09: 0000 1001 */
+ {MOV_A_B, 1, 4, 4,L0|L1}, /* 0a: 0000 1010 */
+ {MOV_A_C, 1, 4, 4,L0|L1}, /* 0b: 0000 1011 */
+ {MOV_A_D, 1, 4, 4,L0|L1}, /* 0c: 0000 1100 */
+ {MOV_A_E, 1, 4, 4,L0|L1}, /* 0d: 0000 1101 */
+ {MOV_A_H, 1, 4, 4,L0|L1}, /* 0e: 0000 1110 */
+ {MOV_A_L, 1, 4, 4,L0|L1}, /* 0f: 0000 1111 */
+
+ {EXA, 1, 4, 4,L0|L1}, /* 10: 0001 0000 */
+ {EXX, 1, 4, 4,L0|L1}, /* 11: 0001 0001 */
+ {INX_BC, 1, 7, 7,L0|L1}, /* 12: 0001 0010 */
+ {DCX_BC, 1, 7, 7,L0|L1}, /* 13: 0001 0011 */
+ {LXI_B_w, 3,10,10,L0|L1}, /* 14: 0001 0100 llll llll hhhh hhhh */
+ {ORIW_wa_xx, 3,19,19,L0|L1}, /* 15: 0001 0101 oooo oooo xxxx xxxx */
+ {XRI_A_xx, 2, 7, 7,L0|L1}, /* 16: 0001 0110 xxxx xxxx */
+ {ORI_A_xx, 2, 7, 7,L0|L1}, /* 17: 0001 0111 xxxx xxxx */
+ {MOV_EAH_A, 1, 4, 4,L0|L1}, /* 18: 0001 1000 */
+ {MOV_EAL_A, 1, 4, 4,L0|L1}, /* 19: 0001 1001 */
+ {MOV_B_A, 1, 4, 4,L0|L1}, /* 1a: 0001 1010 */
+ {MOV_C_A, 1, 4, 4,L0|L1}, /* 1b: 0001 1011 */
+ {MOV_D_A, 1, 4, 4,L0|L1}, /* 1c: 0001 1100 */
+ {MOV_E_A, 1, 4, 4,L0|L1}, /* 1d: 0001 1101 */
+ {MOV_H_A, 1, 4, 4,L0|L1}, /* 1e: 0001 1110 */
+ {MOV_L_A, 1, 4, 4,L0|L1}, /* 1f: 0001 1111 */
+
+ {INRW_wa, 2,16,16,L0|L1}, /* 20: 0010 0000 oooo oooo */
+ {JB, 1, 4, 4,L0|L1}, /* 21: 0010 0001 */
+ {INX_DE, 1, 7, 7,L0|L1}, /* 22: 0010 0010 */
+ {DCX_DE, 1, 7, 7,L0|L1}, /* 23: 0010 0011 */
+ {LXI_D_w, 3,10,10,L0|L1}, /* 24: 0010 0100 llll llll hhhh hhhh */
+ {GTIW_wa_xx, 3,19,19,L0|L1}, /* 25: 0010 0101 oooo oooo xxxx xxxx */
+ {ADINC_A_xx, 2, 7, 7,L0|L1}, /* 26: 0010 0110 xxxx xxxx */
+ {GTI_A_xx, 2, 7, 7,L0|L1}, /* 27: 0010 0111 xxxx xxxx */
+ {illegal, 1, 4, 4,L0|L1}, /* 28: */
+ {LDAX_B, 2, 7, 7,L0|L1}, /* 29: 0010 1001 dddd dddd */
+ {LDAX_D, 2, 7, 7,L0|L1}, /* 2a: 0010 1010 dddd dddd */
+ {LDAX_H, 2, 7, 7,L0|L1}, /* 2b: 0010 1011 dddd dddd */
+ {LDAX_Dp, 2, 7, 7,L0|L1}, /* 2c: 0010 1100 dddd dddd */
+ {LDAX_Hp, 2, 7, 7,L0|L1}, /* 2d: 0010 1101 dddd dddd */
+ {LDAX_Dm, 2, 7, 7,L0|L1}, /* 2e: 0010 1110 dddd dddd */
+ {LDAX_Hm, 2, 7, 7,L0|L1}, /* 2f: 0010 1111 dddd dddd */
+
+ {DCRW_wa, 2,16,16,L0|L1}, /* 30: 0011 0000 oooo oooo */
+ {BLOCK, 1,13,13,L0|L1}, /* 31: 0011 0001 */ /* 7810 */
+ {INX_HL, 1, 7, 7,L0|L1}, /* 32: 0011 0010 */
+ {DCX_HL, 1, 7, 7,L0|L1}, /* 33: 0011 0011 */
+ {LXI_H_w, 3,10,10, L1}, /* 34: 0011 0100 llll llll hhhh hhhh */
+ {LTIW_wa_xx, 3,19,19,L0|L1}, /* 35: 0011 0101 oooo oooo xxxx xxxx */
+ {SUINB_A_xx, 2, 7, 7,L0|L1}, /* 36: 0011 0110 xxxx xxxx */
+ {LTI_A_xx, 2, 7, 7,L0|L1}, /* 37: 0011 0111 xxxx xxxx */
+ {illegal, 1, 4, 4,L0|L1}, /* 38: */
+ {STAX_B, 2, 7, 7,L0|L1}, /* 39: 0011 1001 dddd dddd */
+ {STAX_D, 2, 7, 7,L0|L1}, /* 3a: 0011 1010 dddd dddd */
+ {STAX_H, 2, 7, 7,L0|L1}, /* 3b: 0011 1011 dddd dddd */
+ {STAX_Dp, 2, 7, 7,L0|L1}, /* 3c: 0011 1100 dddd dddd */
+ {STAX_Hp, 2, 7, 7,L0|L1}, /* 3d: 0011 1101 dddd dddd */
+ {STAX_Dm, 2, 7, 7,L0|L1}, /* 3e: 0011 1110 dddd dddd */
+ {STAX_Hm, 2, 7, 7,L0|L1}, /* 3f: 0011 1111 dddd dddd */
+
+ {CALL_w, 3,16,16,L0|L1}, /* 40: 0100 0000 llll llll hhhh hhhh */
+ {INR_A, 1, 4, 4,L0|L1}, /* 41: 0100 0001 */
+ {INR_B, 1, 4, 4,L0|L1}, /* 42: 0100 0010 */
+ {INR_C, 1, 4, 4,L0|L1}, /* 43: 0100 0011 */
+ {LXI_EA_s, 3,10,10,L0|L1}, /* 44: 0100 0100 llll llll hhhh hhhh */
+ {ONIW_wa_xx, 3,19,19,L0|L1}, /* 45: 0100 0101 oooo oooo xxxx xxxx */
+ {ADI_A_xx, 2, 7, 7,L0|L1}, /* 46: 0100 0110 xxxx xxxx */
+ {ONI_A_xx, 2, 7, 7,L0|L1}, /* 47: 0100 0111 xxxx xxxx */
+ {PRE_48, 1, 0, 0,L0|L1}, /* 48: prefix */
+ {MVIX_BC_xx, 2,10,10,L0|L1}, /* 49: 0100 1001 xxxx xxxx */
+ {MVIX_DE_xx, 2,10,10,L0|L1}, /* 4a: 0100 1010 xxxx xxxx */
+ {MVIX_HL_xx, 2,10,10,L0|L1}, /* 4b: 0100 1011 xxxx xxxx */
+ {PRE_4C, 1, 0, 0,L0|L1}, /* 4c: prefix */
+ {PRE_4D, 1, 4, 4,L0|L1}, /* 4d: prefix */
+ {JRE, 2,10,10,L0|L1}, /* 4e: 0100 111d dddd dddd */
+ {JRE, 2,10,10,L0|L1}, /* 4f: 0100 111d dddd dddd */
+
+ {EXH, 1, 4, 4,L0|L1}, /* 50: 0101 0000 */ /* 7810 */
+ {DCR_A, 1, 4, 4,L0|L1}, /* 51: 0101 0001 */
+ {DCR_B, 1, 4, 4,L0|L1}, /* 52: 0101 0010 */
+ {DCR_C, 1, 4, 4,L0|L1}, /* 53: 0101 0011 */
+ {JMP_w, 3,10,10,L0|L1}, /* 54: 0101 0100 llll llll hhhh hhhh */
+ {OFFIW_wa_xx, 3,19,19,L0|L1}, /* 55: 0101 0101 oooo oooo xxxx xxxx */
+ {ACI_A_xx, 2, 7, 7,L0|L1}, /* 56: 0101 0110 xxxx xxxx */
+ {OFFI_A_xx, 2, 7, 7,L0|L1}, /* 57: 0101 0111 xxxx xxxx */
+ {BIT_0_wa, 2,10,10,L0|L1}, /* 58: 0101 1000 oooo oooo */ /* 7810 */
+ {BIT_1_wa, 2,10,10,L0|L1}, /* 59: 0101 1001 oooo oooo */ /* 7810 */
+ {BIT_2_wa, 2,10,10,L0|L1}, /* 5a: 0101 1010 oooo oooo */ /* 7810 */
+ {BIT_3_wa, 2,10,10,L0|L1}, /* 5b: 0101 1011 oooo oooo */ /* 7810 */
+ {BIT_4_wa, 2,10,10,L0|L1}, /* 5c: 0101 1100 oooo oooo */ /* 7810 */
+ {BIT_5_wa, 2,10,10,L0|L1}, /* 5d: 0101 1101 oooo oooo */ /* 7810 */
+ {BIT_6_wa, 2,10,10,L0|L1}, /* 5e: 0101 1110 oooo oooo */ /* 7810 */
+ {BIT_7_wa, 2,10,10,L0|L1}, /* 5f: 0101 1111 oooo oooo */ /* 7810 */
+
+ {PRE_60, 1, 0, 0,L0|L1}, /* 60: */
+ {DAA, 1, 4, 4,L0|L1}, /* 61: 0110 0001 */
+ {RETI, 1,13,13,L0|L1}, /* 62: 0110 0010 */
+ {STAW_wa, 2,10,10,L0|L1}, /* 63: 0110 0011 oooo oooo */
+ {PRE_64, 1, 0, 0,L0|L1}, /* 64: */
+ {NEIW_wa_xx, 3,19,19,L0|L1}, /* 65: 0110 0101 oooo oooo xxxx xxxx */
+ {SUI_A_xx, 2, 7, 7,L0|L1}, /* 66: 0110 0110 xxxx xxxx */
+ {NEI_A_xx, 2, 7, 7,L0|L1}, /* 67: 0110 0111 xxxx xxxx */
+ {MVI_V_xx, 2, 7, 7,L0|L1}, /* 68: 0110 1000 xxxx xxxx */
+ {MVI_A_xx, 2, 7, 7,L0 }, /* 69: 0110 1001 xxxx xxxx */
+ {MVI_B_xx, 2, 7, 7,L0|L1}, /* 6a: 0110 1010 xxxx xxxx */
+ {MVI_C_xx, 2, 7, 7,L0|L1}, /* 6b: 0110 1011 xxxx xxxx */
+ {MVI_D_xx, 2, 7, 7,L0|L1}, /* 6c: 0110 1100 xxxx xxxx */
+ {MVI_E_xx, 2, 7, 7,L0|L1}, /* 6d: 0110 1101 xxxx xxxx */
+ {MVI_H_xx, 2, 7, 7,L0|L1}, /* 6e: 0110 1110 xxxx xxxx */
+ {MVI_L_xx, 2, 7, 7, L1}, /* 6f: 0110 1111 xxxx xxxx */
+
+ {PRE_70, 1, 0, 0,L0|L1}, /* 70: */
+ {MVIW_wa_xx, 3,13,13,L0|L1}, /* 71: 0111 0001 oooo oooo xxxx xxxx */
+ {SOFTI, 1,16,16,L0|L1}, /* 72: 0111 0010 */
+ {illegal, 1, 0, 0,L0|L1}, /* 73: */
+ {PRE_74, 1, 0, 0,L0|L1}, /* 74: prefix */
+ {EQIW_wa_xx, 3,19,19,L0|L1}, /* 75: 0111 0101 oooo oooo xxxx xxxx */
+ {SBI_A_xx, 2, 7, 7,L0|L1}, /* 76: 0111 0110 xxxx xxxx */
+ {EQI_A_xx, 2, 7, 7,L0|L1}, /* 77: 0111 0111 xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 78: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 79: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7a: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7b: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7c: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7d: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7e: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7f: 0111 1xxx xxxx xxxx */
+
+ {CALT, 1,16,16,L0|L1}, /* 80: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 81: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 82: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 83: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 84: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 85: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 86: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 87: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 88: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 89: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8a: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8b: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8c: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8d: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8e: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8f: 100x xxxx */
+
+ {CALT, 1,16,16,L0|L1}, /* 90: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 91: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 92: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 93: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 94: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 95: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 96: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 97: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 98: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 99: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9a: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9b: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9c: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9d: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9e: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9f: 100x xxxx */
+
+ {POP_VA, 1,10,10,L0|L1}, /* a0: 1010 0000 */
+ {POP_BC, 1,10,10,L0|L1}, /* a1: 1010 0001 */
+ {POP_DE, 1,10,10,L0|L1}, /* a2: 1010 0010 */
+ {POP_HL, 1,10,10,L0|L1}, /* a3: 1010 0011 */
+ {POP_EA, 1,10,10,L0|L1}, /* a4: 1010 0100 */
+ {DMOV_EA_BC, 1, 4, 4,L0|L1}, /* a5: 1010 0101 */
+ {DMOV_EA_DE, 1, 4, 4,L0|L1}, /* a6: 1010 0110 */
+ {DMOV_EA_HL, 1, 4, 4,L0|L1}, /* a7: 1010 0111 */
+ {INX_EA, 1, 7, 7,L0|L1}, /* a8: 1010 1000 */
+ {DCX_EA, 1, 7, 7,L0|L1}, /* a9: 1010 1001 */
+ {EI, 1, 4, 4,L0|L1}, /* aa: 1010 1010 */
+ {LDAX_D_xx, 2, 7, 7,L0|L1}, /* ab: 1010 1011 dddd dddd */
+ {LDAX_H_A, 1, 7, 7,L0|L1}, /* ac: 1010 1100 */
+ {LDAX_H_B, 1, 7, 7,L0|L1}, /* ad: 1010 1101 */
+ {LDAX_H_EA, 1, 7, 7,L0|L1}, /* ae: 1010 1110 */
+ {LDAX_H_xx, 2, 7, 7,L0|L1}, /* af: 1010 1111 dddd dddd */
+
+ {PUSH_VA, 1,13,13,L0|L1}, /* b0: 1011 0000 */
+ {PUSH_BC, 1,13,13,L0|L1}, /* b1: 1011 0001 */
+ {PUSH_DE, 1,13,13,L0|L1}, /* b2: 1011 0010 */
+ {PUSH_HL, 1,13,13,L0|L1}, /* b3: 1011 0011 */
+ {PUSH_EA, 1,13,13,L0|L1}, /* b4: 1011 0100 */
+ {DMOV_BC_EA, 1, 4, 4,L0|L1}, /* b5: 1011 0101 */
+ {DMOV_DE_EA, 1, 4, 4,L0|L1}, /* b6: 1011 0110 */
+ {DMOV_HL_EA, 1, 4, 4,L0|L1}, /* b7: 1011 0111 */
+ {RET, 1,10,10,L0|L1}, /* b8: 1011 1000 */
+ {RETS, 1,10,10,L0|L1}, /* b9: 1011 1001 */
+ {DI, 1, 4, 4,L0|L1}, /* ba: 1011 1010 */
+ {STAX_D_xx, 2, 7, 7,L0|L1}, /* bb: 1011 1011 dddd dddd */
+ {STAX_H_A, 1, 7, 7,L0|L1}, /* bc: 1011 1100 */
+ {STAX_H_B, 1, 7, 7,L0|L1}, /* bd: 1011 1101 */
+ {STAX_H_EA, 1, 7, 7,L0|L1}, /* be: 1011 1110 */
+ {STAX_H_xx, 2, 7, 7,L0|L1}, /* bf: 1011 1111 dddd dddd */
+
+ {JR, 1,10,10,L0|L1}, /* c0: 1100 0000 */
+ {JR, 1,10,10,L0|L1}, /* c1: 1100 0001 */
+ {JR, 1,10,10,L0|L1}, /* c2: 1100 0010 */
+ {JR, 1,10,10,L0|L1}, /* c3: 1100 0011 */
+ {JR, 1,10,10,L0|L1}, /* c4: 1100 0100 */
+ {JR, 1,10,10,L0|L1}, /* c5: 1100 0101 */
+ {JR, 1,10,10,L0|L1}, /* c6: 1100 0110 */
+ {JR, 1,10,10,L0|L1}, /* c7: 1100 0111 */
+ {JR, 1,10,10,L0|L1}, /* c8: 1100 1000 */
+ {JR, 1,10,10,L0|L1}, /* c9: 1100 1001 */
+ {JR, 1,10,10,L0|L1}, /* ca: 1100 1010 */
+ {JR, 1,10,10,L0|L1}, /* cb: 1100 1011 */
+ {JR, 1,10,10,L0|L1}, /* cc: 1100 1100 */
+ {JR, 1,10,10,L0|L1}, /* cd: 1100 1101 */
+ {JR, 1,10,10,L0|L1}, /* ce: 1100 1110 */
+ {JR, 1,10,10,L0|L1}, /* cf: 1100 1111 */
+
+ {JR, 1,10,10,L0|L1}, /* d0: 1101 0000 */
+ {JR, 1,10,10,L0|L1}, /* d1: 1101 0001 */
+ {JR, 1,10,10,L0|L1}, /* d2: 1101 0010 */
+ {JR, 1,10,10,L0|L1}, /* d3: 1101 0011 */
+ {JR, 1,10,10,L0|L1}, /* d4: 1101 0100 */
+ {JR, 1,10,10,L0|L1}, /* d5: 1101 0101 */
+ {JR, 1,10,10,L0|L1}, /* d6: 1101 0110 */
+ {JR, 1,10,10,L0|L1}, /* d7: 1101 0111 */
+ {JR, 1,10,10,L0|L1}, /* d8: 1101 1000 */
+ {JR, 1,10,10,L0|L1}, /* d9: 1101 1001 */
+ {JR, 1,10,10,L0|L1}, /* da: 1101 1010 */
+ {JR, 1,10,10,L0|L1}, /* db: 1101 1011 */
+ {JR, 1,10,10,L0|L1}, /* dc: 1101 1100 */
+ {JR, 1,10,10,L0|L1}, /* dd: 1101 1101 */
+ {JR, 1,10,10,L0|L1}, /* de: 1101 1110 */
+ {JR, 1,10,10,L0|L1}, /* df: 1101 1111 */
+
+ {JR, 1,10,10,L0|L1}, /* e0: 1110 0000 */
+ {JR, 1,10,10,L0|L1}, /* e1: 1110 0001 */
+ {JR, 1,10,10,L0|L1}, /* e2: 1110 0010 */
+ {JR, 1,10,10,L0|L1}, /* e3: 1110 0011 */
+ {JR, 1,10,10,L0|L1}, /* e4: 1110 0100 */
+ {JR, 1,10,10,L0|L1}, /* e5: 1110 0101 */
+ {JR, 1,10,10,L0|L1}, /* e6: 1110 0110 */
+ {JR, 1,10,10,L0|L1}, /* e7: 1110 0111 */
+ {JR, 1,10,10,L0|L1}, /* e8: 1110 1000 */
+ {JR, 1,10,10,L0|L1}, /* e9: 1110 1001 */
+ {JR, 1,10,10,L0|L1}, /* ea: 1110 1010 */
+ {JR, 1,10,10,L0|L1}, /* eb: 1110 1011 */
+ {JR, 1,10,10,L0|L1}, /* ec: 1110 1100 */
+ {JR, 1,10,10,L0|L1}, /* ed: 1110 1101 */
+ {JR, 1,10,10,L0|L1}, /* ee: 1110 1110 */
+ {JR, 1,10,10,L0|L1}, /* ef: 1110 1111 */
+
+ {JR, 1,10,10,L0|L1}, /* f0: 1111 0000 */
+ {JR, 1,10,10,L0|L1}, /* f1: 1111 0001 */
+ {JR, 1,10,10,L0|L1}, /* f2: 1111 0010 */
+ {JR, 1,10,10,L0|L1}, /* f3: 1111 0011 */
+ {JR, 1,10,10,L0|L1}, /* f4: 1111 0100 */
+ {JR, 1,10,10,L0|L1}, /* f5: 1111 0101 */
+ {JR, 1,10,10,L0|L1}, /* f6: 1111 0110 */
+ {JR, 1,10,10,L0|L1}, /* f7: 1111 0111 */
+ {JR, 1,10,10,L0|L1}, /* f8: 1111 1000 */
+ {JR, 1,10,10,L0|L1}, /* f9: 1111 1001 */
+ {JR, 1,10,10,L0|L1}, /* fa: 1111 1010 */
+ {JR, 1,10,10,L0|L1}, /* fb: 1111 1011 */
+ {JR, 1,10,10,L0|L1}, /* fc: 1111 1100 */
+ {JR, 1,10,10,L0|L1}, /* fd: 1111 1101 */
+ {JR, 1,10,10,L0|L1}, /* fe: 1111 1110 */
+ {JR, 1,10,10,L0|L1} /* ff: 1111 1111 */
+};
+
+static struct opcode_s opXX_7807[256] =
+{
+ {NOP, 1, 4, 4,L0|L1}, /* 00: 0000 0000 */
+ {LDAW_wa, 2,10,10,L0|L1}, /* 01: 0000 0001 oooo oooo */
+ {INX_SP, 1, 7, 7,L0|L1}, /* 02: 0000 0010 */
+ {DCX_SP, 1, 7, 7,L0|L1}, /* 03: 0000 0011 */
+ {LXI_S_w, 3,10,10,L0|L1}, /* 04: 0000 0100 llll llll hhhh hhhh */
+ {ANIW_wa_xx, 3,19,19,L0|L1}, /* 05: 0000 0101 oooo oooo xxxx xxxx */
+ {illegal, 1, 4, 4,L0|L1}, /* 06: */
+ {ANI_A_xx, 2, 7, 7,L0|L1}, /* 07: 0000 0111 xxxx xxxx */
+ {MOV_A_EAH, 1, 4, 4,L0|L1}, /* 08: 0000 1000 */
+ {MOV_A_EAL, 1, 4, 4,L0|L1}, /* 09: 0000 1001 */
+ {MOV_A_B, 1, 4, 4,L0|L1}, /* 0a: 0000 1010 */
+ {MOV_A_C, 1, 4, 4,L0|L1}, /* 0b: 0000 1011 */
+ {MOV_A_D, 1, 4, 4,L0|L1}, /* 0c: 0000 1100 */
+ {MOV_A_E, 1, 4, 4,L0|L1}, /* 0d: 0000 1101 */
+ {MOV_A_H, 1, 4, 4,L0|L1}, /* 0e: 0000 1110 */
+ {MOV_A_L, 1, 4, 4,L0|L1}, /* 0f: 0000 1111 */
+
+ {illegal, 1,13, 4,L0|L1}, /* 10: 0001 0000 */ /* 7807 */
+ {illegal, 1,13, 4,L0|L1}, /* 11: 0001 0001 */ /* 7807 */
+ {INX_BC, 1, 7, 7,L0|L1}, /* 12: 0001 0010 */
+ {DCX_BC, 1, 7, 7,L0|L1}, /* 13: 0001 0011 */
+ {LXI_B_w, 3,10,10,L0|L1}, /* 14: 0001 0100 llll llll hhhh hhhh */
+ {ORIW_wa_xx, 3,19,19,L0|L1}, /* 15: 0001 0101 oooo oooo xxxx xxxx */
+ {XRI_A_xx, 2, 7, 7,L0|L1}, /* 16: 0001 0110 xxxx xxxx */
+ {ORI_A_xx, 2, 7, 7,L0|L1}, /* 17: 0001 0111 xxxx xxxx */
+ {MOV_EAH_A, 1, 4, 4,L0|L1}, /* 18: 0001 1000 */
+ {MOV_EAL_A, 1, 4, 4,L0|L1}, /* 19: 0001 1001 */
+ {MOV_B_A, 1, 4, 4,L0|L1}, /* 1a: 0001 1010 */
+ {MOV_C_A, 1, 4, 4,L0|L1}, /* 1b: 0001 1011 */
+ {MOV_D_A, 1, 4, 4,L0|L1}, /* 1c: 0001 1100 */
+ {MOV_E_A, 1, 4, 4,L0|L1}, /* 1d: 0001 1101 */
+ {MOV_H_A, 1, 4, 4,L0|L1}, /* 1e: 0001 1110 */
+ {MOV_L_A, 1, 4, 4,L0|L1}, /* 1f: 0001 1111 */
+
+ {INRW_wa, 2,16,16,L0|L1}, /* 20: 0010 0000 oooo oooo */
+ {JB, 1, 4, 4,L0|L1}, /* 21: 0010 0001 */
+ {INX_DE, 1, 7, 7,L0|L1}, /* 22: 0010 0010 */
+ {DCX_DE, 1, 7, 7,L0|L1}, /* 23: 0010 0011 */
+ {LXI_D_w, 3,10,10,L0|L1}, /* 24: 0010 0100 llll llll hhhh hhhh */
+ {GTIW_wa_xx, 3,19,19,L0|L1}, /* 25: 0010 0101 oooo oooo xxxx xxxx */
+ {ADINC_A_xx, 2, 7, 7,L0|L1}, /* 26: 0010 0110 xxxx xxxx */
+ {GTI_A_xx, 2, 7, 7,L0|L1}, /* 27: 0010 0111 xxxx xxxx */
+ {illegal, 1, 4, 4,L0|L1}, /* 28: */
+ {LDAX_B, 2, 7, 7,L0|L1}, /* 29: 0010 1001 dddd dddd */
+ {LDAX_D, 2, 7, 7,L0|L1}, /* 2a: 0010 1010 dddd dddd */
+ {LDAX_H, 2, 7, 7,L0|L1}, /* 2b: 0010 1011 dddd dddd */
+ {LDAX_Dp, 2, 7, 7,L0|L1}, /* 2c: 0010 1100 dddd dddd */
+ {LDAX_Hp, 2, 7, 7,L0|L1}, /* 2d: 0010 1101 dddd dddd */
+ {LDAX_Dm, 2, 7, 7,L0|L1}, /* 2e: 0010 1110 dddd dddd */
+ {LDAX_Hm, 2, 7, 7,L0|L1}, /* 2f: 0010 1111 dddd dddd */
+
+ {DCRW_wa, 2,16,16,L0|L1}, /* 30: 0011 0000 oooo oooo */
+ {illegal, 2, 8, 8,L0|L1}, /* 31: 0011 0001 bbbb bbbb */ /* 7807 */
+ {INX_HL, 1, 7, 7,L0|L1}, /* 32: 0011 0010 */
+ {DCX_HL, 1, 7, 7,L0|L1}, /* 33: 0011 0011 */
+ {LXI_H_w, 3,10,10, L1}, /* 34: 0011 0100 llll llll hhhh hhhh */
+ {LTIW_wa_xx, 3,19,19,L0|L1}, /* 35: 0011 0101 oooo oooo xxxx xxxx */
+ {SUINB_A_xx, 2, 7, 7,L0|L1}, /* 36: 0011 0110 xxxx xxxx */
+ {LTI_A_xx, 2, 7, 7,L0|L1}, /* 37: 0011 0111 xxxx xxxx */
+ {illegal, 1, 4, 4,L0|L1}, /* 38: */
+ {STAX_B, 2, 7, 7,L0|L1}, /* 39: 0011 1001 dddd dddd */
+ {STAX_D, 2, 7, 7,L0|L1}, /* 3a: 0011 1010 dddd dddd */
+ {STAX_H, 2, 7, 7,L0|L1}, /* 3b: 0011 1011 dddd dddd */
+ {STAX_Dp, 2, 7, 7,L0|L1}, /* 3c: 0011 1100 dddd dddd */
+ {STAX_Hp, 2, 7, 7,L0|L1}, /* 3d: 0011 1101 dddd dddd */
+ {STAX_Dm, 2, 7, 7,L0|L1}, /* 3e: 0011 1110 dddd dddd */
+ {STAX_Hm, 2, 7, 7,L0|L1}, /* 3f: 0011 1111 dddd dddd */
+
+ {CALL_w, 3,16,16,L0|L1}, /* 40: 0100 0000 llll llll hhhh hhhh */
+ {INR_A, 1, 4, 4,L0|L1}, /* 41: 0100 0001 */
+ {INR_B, 1, 4, 4,L0|L1}, /* 42: 0100 0010 */
+ {INR_C, 1, 4, 4,L0|L1}, /* 43: 0100 0011 */
+ {LXI_EA_s, 3,10,10,L0|L1}, /* 44: 0100 0100 llll llll hhhh hhhh */
+ {ONIW_wa_xx, 3,19,19,L0|L1}, /* 45: 0100 0101 oooo oooo xxxx xxxx */
+ {ADI_A_xx, 2, 7, 7,L0|L1}, /* 46: 0100 0110 xxxx xxxx */
+ {ONI_A_xx, 2, 7, 7,L0|L1}, /* 47: 0100 0111 xxxx xxxx */
+ {PRE_48, 1, 0, 0,L0|L1}, /* 48: prefix */
+ {MVIX_BC_xx, 2,10,10,L0|L1}, /* 49: 0100 1001 xxxx xxxx */
+ {MVIX_DE_xx, 2,10,10,L0|L1}, /* 4a: 0100 1010 xxxx xxxx */
+ {MVIX_HL_xx, 2,10,10,L0|L1}, /* 4b: 0100 1011 xxxx xxxx */
+ {PRE_4C, 1, 0, 0,L0|L1}, /* 4c: prefix */
+ {PRE_4D, 1, 4, 4,L0|L1}, /* 4d: prefix */
+ {JRE, 2,10,10,L0|L1}, /* 4e: 0100 111d dddd dddd */
+ {JRE, 2,10,10,L0|L1}, /* 4f: 0100 111d dddd dddd */
+
+ {SKN_bit, 2,13,13,L0|L1}, /* 50: 0101 0000 bbbb bbbb */ /* 7807 */
+ {DCR_A, 1, 4, 4,L0|L1}, /* 51: 0101 0001 */
+ {DCR_B, 1, 4, 4,L0|L1}, /* 52: 0101 0010 */
+ {DCR_C, 1, 4, 4,L0|L1}, /* 53: 0101 0011 */
+ {JMP_w, 3,10,10,L0|L1}, /* 54: 0101 0100 llll llll hhhh hhhh */
+ {OFFIW_wa_xx, 3,19,19,L0|L1}, /* 55: 0101 0101 oooo oooo xxxx xxxx */
+ {ACI_A_xx, 2, 7, 7,L0|L1}, /* 56: 0101 0110 xxxx xxxx */
+ {OFFI_A_xx, 2, 7, 7,L0|L1}, /* 57: 0101 0111 xxxx xxxx */
+ {SETB, 2,13,13,L0|L1}, /* 58: 0101 1000 bbbb bbbb */ /* 7807 */
+ {illegal, 2, 8, 8,L0|L1}, /* 59: 0101 1001 bbbb bbbb */ /* 7807 */
+ {illegal, 2, 8, 8,L0|L1}, /* 5a: 0101 1010 bbbb bbbb */ /* 7807 */
+ {CLR, 2,13,13,L0|L1}, /* 5b: 0101 1011 bbbb bbbb */ /* 7807 */
+ {illegal, 2, 8, 8,L0|L1}, /* 5c: 0101 1100 bbbb bbbb */ /* 7807 */
+ {SK_bit, 2,10,10,L0|L1}, /* 5d: 0101 1101 bbbb bbbb */ /* 7807 */
+ {illegal, 2, 8, 8,L0|L1}, /* 5e: 0101 1110 bbbb bbbb */ /* 7807 */
+ {illegal, 2, 8, 8,L0|L1}, /* 5f: 0101 1111 bbbb bbbb */ /* 7807 */
+
+ {PRE_60, 1, 0, 0,L0|L1}, /* 60: */
+ {DAA, 1, 4, 4,L0|L1}, /* 61: 0110 0001 */
+ {RETI, 1,13,13,L0|L1}, /* 62: 0110 0010 */
+ {STAW_wa, 2,10,10,L0|L1}, /* 63: 0110 0011 oooo oooo */
+ {PRE_64, 1, 0, 0,L0|L1}, /* 64: */
+ {NEIW_wa_xx, 3,19,19,L0|L1}, /* 65: 0110 0101 oooo oooo xxxx xxxx */
+ {SUI_A_xx, 2, 7, 7,L0|L1}, /* 66: 0110 0110 xxxx xxxx */
+ {NEI_A_xx, 2, 7, 7,L0|L1}, /* 67: 0110 0111 xxxx xxxx */
+ {MVI_V_xx, 2, 7, 7,L0|L1}, /* 68: 0110 1000 xxxx xxxx */
+ {MVI_A_xx, 2, 7, 7,L0 }, /* 69: 0110 1001 xxxx xxxx */
+ {MVI_B_xx, 2, 7, 7,L0|L1}, /* 6a: 0110 1010 xxxx xxxx */
+ {MVI_C_xx, 2, 7, 7,L0|L1}, /* 6b: 0110 1011 xxxx xxxx */
+ {MVI_D_xx, 2, 7, 7,L0|L1}, /* 6c: 0110 1100 xxxx xxxx */
+ {MVI_E_xx, 2, 7, 7,L0|L1}, /* 6d: 0110 1101 xxxx xxxx */
+ {MVI_H_xx, 2, 7, 7,L0|L1}, /* 6e: 0110 1110 xxxx xxxx */
+ {MVI_L_xx, 2, 7, 7, L1}, /* 6f: 0110 1111 xxxx xxxx */
+
+ {PRE_70, 1, 0, 0,L0|L1}, /* 70: */
+ {MVIW_wa_xx, 3,13,13,L0|L1}, /* 71: 0111 0001 oooo oooo xxxx xxxx */
+ {SOFTI, 1,16,16,L0|L1}, /* 72: 0111 0010 */
+ {illegal, 1, 0, 0,L0|L1}, /* 73: */
+ {PRE_74, 1, 0, 0,L0|L1}, /* 74: prefix */
+ {EQIW_wa_xx, 3,19,19,L0|L1}, /* 75: 0111 0101 oooo oooo xxxx xxxx */
+ {SBI_A_xx, 2, 7, 7,L0|L1}, /* 76: 0111 0110 xxxx xxxx */
+ {EQI_A_xx, 2, 7, 7,L0|L1}, /* 77: 0111 0111 xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 78: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 79: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7a: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7b: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7c: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7d: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7e: 0111 1xxx xxxx xxxx */
+ {CALF, 2,13,13,L0|L1}, /* 7f: 0111 1xxx xxxx xxxx */
+
+ {CALT, 1,16,16,L0|L1}, /* 80: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 81: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 82: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 83: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 84: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 85: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 86: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 87: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 88: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 89: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8a: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8b: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8c: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8d: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8e: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 8f: 100x xxxx */
+
+ {CALT, 1,16,16,L0|L1}, /* 90: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 91: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 92: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 93: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 94: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 95: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 96: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 97: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 98: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 99: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9a: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9b: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9c: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9d: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9e: 100x xxxx */
+ {CALT, 1,16,16,L0|L1}, /* 9f: 100x xxxx */
+
+ {POP_VA, 1,10,10,L0|L1}, /* a0: 1010 0000 */
+ {POP_BC, 1,10,10,L0|L1}, /* a1: 1010 0001 */
+ {POP_DE, 1,10,10,L0|L1}, /* a2: 1010 0010 */
+ {POP_HL, 1,10,10,L0|L1}, /* a3: 1010 0011 */
+ {POP_EA, 1,10,10,L0|L1}, /* a4: 1010 0100 */
+ {DMOV_EA_BC, 1, 4, 4,L0|L1}, /* a5: 1010 0101 */
+ {DMOV_EA_DE, 1, 4, 4,L0|L1}, /* a6: 1010 0110 */
+ {DMOV_EA_HL, 1, 4, 4,L0|L1}, /* a7: 1010 0111 */
+ {INX_EA, 1, 7, 7,L0|L1}, /* a8: 1010 1000 */
+ {DCX_EA, 1, 7, 7,L0|L1}, /* a9: 1010 1001 */
+ {EI, 1, 4, 4,L0|L1}, /* aa: 1010 1010 */
+ {LDAX_D_xx, 2, 7, 7,L0|L1}, /* ab: 1010 1011 dddd dddd */
+ {LDAX_H_A, 1, 7, 7,L0|L1}, /* ac: 1010 1100 */
+ {LDAX_H_B, 1, 7, 7,L0|L1}, /* ad: 1010 1101 */
+ {LDAX_H_EA, 1, 7, 7,L0|L1}, /* ae: 1010 1110 */
+ {LDAX_H_xx, 2, 7, 7,L0|L1}, /* af: 1010 1111 dddd dddd */
+
+ {PUSH_VA, 1,13,13,L0|L1}, /* b0: 1011 0000 */
+ {PUSH_BC, 1,13,13,L0|L1}, /* b1: 1011 0001 */
+ {PUSH_DE, 1,13,13,L0|L1}, /* b2: 1011 0010 */
+ {PUSH_HL, 1,13,13,L0|L1}, /* b3: 1011 0011 */
+ {PUSH_EA, 1,13,13,L0|L1}, /* b4: 1011 0100 */
+ {DMOV_BC_EA, 1, 4, 4,L0|L1}, /* b5: 1011 0101 */
+ {DMOV_DE_EA, 1, 4, 4,L0|L1}, /* b6: 1011 0110 */
+ {DMOV_HL_EA, 1, 4, 4,L0|L1}, /* b7: 1011 0111 */
+ {RET, 1,10,10,L0|L1}, /* b8: 1011 1000 */
+ {RETS, 1,10,10,L0|L1}, /* b9: 1011 1001 */
+ {DI, 1, 4, 4,L0|L1}, /* ba: 1011 1010 */
+ {STAX_D_xx, 2, 7, 7,L0|L1}, /* bb: 1011 1011 dddd dddd */
+ {STAX_H_A, 1, 7, 7,L0|L1}, /* bc: 1011 1100 */
+ {STAX_H_B, 1, 7, 7,L0|L1}, /* bd: 1011 1101 */
+ {STAX_H_EA, 1, 7, 7,L0|L1}, /* be: 1011 1110 */
+ {STAX_H_xx, 2, 7, 7,L0|L1}, /* bf: 1011 1111 dddd dddd */
+
+ {JR, 1,10,10,L0|L1}, /* c0: 1100 0000 */
+ {JR, 1,10,10,L0|L1}, /* c1: 1100 0001 */
+ {JR, 1,10,10,L0|L1}, /* c2: 1100 0010 */
+ {JR, 1,10,10,L0|L1}, /* c3: 1100 0011 */
+ {JR, 1,10,10,L0|L1}, /* c4: 1100 0100 */
+ {JR, 1,10,10,L0|L1}, /* c5: 1100 0101 */
+ {JR, 1,10,10,L0|L1}, /* c6: 1100 0110 */
+ {JR, 1,10,10,L0|L1}, /* c7: 1100 0111 */
+ {JR, 1,10,10,L0|L1}, /* c8: 1100 1000 */
+ {JR, 1,10,10,L0|L1}, /* c9: 1100 1001 */
+ {JR, 1,10,10,L0|L1}, /* ca: 1100 1010 */
+ {JR, 1,10,10,L0|L1}, /* cb: 1100 1011 */
+ {JR, 1,10,10,L0|L1}, /* cc: 1100 1100 */
+ {JR, 1,10,10,L0|L1}, /* cd: 1100 1101 */
+ {JR, 1,10,10,L0|L1}, /* ce: 1100 1110 */
+ {JR, 1,10,10,L0|L1}, /* cf: 1100 1111 */
+
+ {JR, 1,10,10,L0|L1}, /* d0: 1101 0000 */
+ {JR, 1,10,10,L0|L1}, /* d1: 1101 0001 */
+ {JR, 1,10,10,L0|L1}, /* d2: 1101 0010 */
+ {JR, 1,10,10,L0|L1}, /* d3: 1101 0011 */
+ {JR, 1,10,10,L0|L1}, /* d4: 1101 0100 */
+ {JR, 1,10,10,L0|L1}, /* d5: 1101 0101 */
+ {JR, 1,10,10,L0|L1}, /* d6: 1101 0110 */
+ {JR, 1,10,10,L0|L1}, /* d7: 1101 0111 */
+ {JR, 1,10,10,L0|L1}, /* d8: 1101 1000 */
+ {JR, 1,10,10,L0|L1}, /* d9: 1101 1001 */
+ {JR, 1,10,10,L0|L1}, /* da: 1101 1010 */
+ {JR, 1,10,10,L0|L1}, /* db: 1101 1011 */
+ {JR, 1,10,10,L0|L1}, /* dc: 1101 1100 */
+ {JR, 1,10,10,L0|L1}, /* dd: 1101 1101 */
+ {JR, 1,10,10,L0|L1}, /* de: 1101 1110 */
+ {JR, 1,10,10,L0|L1}, /* df: 1101 1111 */
+
+ {JR, 1,10,10,L0|L1}, /* e0: 1110 0000 */
+ {JR, 1,10,10,L0|L1}, /* e1: 1110 0001 */
+ {JR, 1,10,10,L0|L1}, /* e2: 1110 0010 */
+ {JR, 1,10,10,L0|L1}, /* e3: 1110 0011 */
+ {JR, 1,10,10,L0|L1}, /* e4: 1110 0100 */
+ {JR, 1,10,10,L0|L1}, /* e5: 1110 0101 */
+ {JR, 1,10,10,L0|L1}, /* e6: 1110 0110 */
+ {JR, 1,10,10,L0|L1}, /* e7: 1110 0111 */
+ {JR, 1,10,10,L0|L1}, /* e8: 1110 1000 */
+ {JR, 1,10,10,L0|L1}, /* e9: 1110 1001 */
+ {JR, 1,10,10,L0|L1}, /* ea: 1110 1010 */
+ {JR, 1,10,10,L0|L1}, /* eb: 1110 1011 */
+ {JR, 1,10,10,L0|L1}, /* ec: 1110 1100 */
+ {JR, 1,10,10,L0|L1}, /* ed: 1110 1101 */
+ {JR, 1,10,10,L0|L1}, /* ee: 1110 1110 */
+ {JR, 1,10,10,L0|L1}, /* ef: 1110 1111 */
+
+ {JR, 1,10,10,L0|L1}, /* f0: 1111 0000 */
+ {JR, 1,10,10,L0|L1}, /* f1: 1111 0001 */
+ {JR, 1,10,10,L0|L1}, /* f2: 1111 0010 */
+ {JR, 1,10,10,L0|L1}, /* f3: 1111 0011 */
+ {JR, 1,10,10,L0|L1}, /* f4: 1111 0100 */
+ {JR, 1,10,10,L0|L1}, /* f5: 1111 0101 */
+ {JR, 1,10,10,L0|L1}, /* f6: 1111 0110 */
+ {JR, 1,10,10,L0|L1}, /* f7: 1111 0111 */
+ {JR, 1,10,10,L0|L1}, /* f8: 1111 1000 */
+ {JR, 1,10,10,L0|L1}, /* f9: 1111 1001 */
+ {JR, 1,10,10,L0|L1}, /* fa: 1111 1010 */
+ {JR, 1,10,10,L0|L1}, /* fb: 1111 1011 */
+ {JR, 1,10,10,L0|L1}, /* fc: 1111 1100 */
+ {JR, 1,10,10,L0|L1}, /* fd: 1111 1101 */
+ {JR, 1,10,10,L0|L1}, /* fe: 1111 1110 */
+ {JR, 1,10,10,L0|L1} /* ff: 1111 1111 */
+};
+
diff --git a/src/emu/cpu/upd7810/upd7810.c b/src/emu/cpu/upd7810/upd7810.c
new file mode 100644
index 00000000000..c726934a4b1
--- /dev/null
+++ b/src/emu/cpu/upd7810/upd7810.c
@@ -0,0 +1,2019 @@
+/*****************************************************************************
+ *
+ * upd7810.c
+ * Portable uPD7810/11, 7810H/11H, 78C10/C11/C14 emulator V0.3
+ *
+ * Copyright (c) 2001 Juergen Buchmueller, all rights reserved.
+ *
+ * Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * You can contact me at juergen@mame.net or pullmoll@stop1984.com
+ *
+ * - This source code is released as freeware for non-commercial purposes
+ * as part of the M.A.M.E. (Multiple Arcade Machine Emulator) project.
+ * The licensing terms of MAME apply to this piece of code for the MAME
+ * project and derviative works, as defined by the MAME license. You
+ * may opt to make modifications, improvements or derivative works under
+ * that same conditions, and the MAME project may opt to keep
+ * modifications, improvements or derivatives under their terms exclusively.
+ *
+ * - Alternatively you can choose to apply the terms of the "GPL" (see
+ * below) to this - and only this - piece of code or your derivative works.
+ * Note that in no case your choice can have any impact on any other
+ * source code of the MAME project, or binary, or executable, be it closely
+ * or losely related to this piece of code.
+ *
+ * - At your choice you are also free to remove either licensing terms from
+ * this file and continue to use it under only one of the two licenses. Do this
+ * if you think that licenses are not compatible (enough) for you, or if you
+ * consider either license 'too restrictive' or 'too free'.
+ *
+ * - GPL (GNU General Public License)
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * This work is based on the
+ * "NEC Electronics User's Manual, April 1987"
+ *
+ * NS20030115:
+ * - fixed INRW_wa()
+ * - TODO: add 7807, differences are listed below.
+ * I only added support for these opcodes needed by homedata.c (yes, I am
+ * lazy):
+ * 4C CE (MOV A,PT)
+ * 48 AC (EXA)
+ * 48 AD (EXR)
+ * 48 AE (EXH)
+ * 48 AF (EXX)
+ * 50 xx (SKN bit)
+ * 58 xx (SETB)
+ * 5B xx (CLR)
+ * 5D xx (SK bit)
+ *
+ *****************************************************************************/
+/* Hau around 23 May 2004
+ gta, gti, dgt fixed
+ working reg opcodes fixed
+ sio input fixed
+--
+ PeT around 19 February 2002
+ type selection/gamemaster support added
+ gamemaster init hack? added
+ ORAX added
+ jre negativ fixed
+ prefixed opcodes skipping fixed
+ interrupts fixed and improved
+ sub(and related)/add/daa flags fixed
+ mvi ports,... fixed
+ rll, rlr, drll, drlr fixed
+ rets fixed
+ l0, l1 skipping fixed
+ calt fixed
+*/
+
+/*
+
+7807 DESCRIPTION
+
+
+
+ PA0 1 64 Vcc
+ PA1 2 63 Vdd
+ PA2 3 62 PD7/AD7
+ PA3 4 61 PD6/AD6
+ PA4 5 60 PD5/AD5
+ PA5 6 59 PD4/AD4
+ PA6 7 58 PD3/AD3
+ PA7 8 57 PD2/AD2
+ PB0 9 56 PD1/AD1
+ PB1 10 55 PD0/AD0
+ PB2 11 54 PF7/AB15
+ PB3 12 53 PF6/AB14
+ PB4 13 52 PF5/AB13
+ PB5 14 51 PF4/AB12
+ PB6 15 50 PF3/AB11
+ PB7 16 49 PF2/AB10
+ PC0 17 48 PF1/AB9
+ PC1 18 47 PF0/AB8
+ PC2 19 46 ALE
+ PC3 20 45 WR*
+ PC4 21 44 RD*
+ PC5 22 43 HLDA
+ PC6 23 42 HOLD
+ PC7 24 41 PT7
+ NMI* 25 40 PT6
+ INT1 26 39 PT5
+ MODE1 27 38 PT4
+RESET* 28 37 PT3
+ MODE0 29 36 PT2
+ X2 30 35 PT1
+ X1 31 34 PT0
+ Vss 32 33 Vth
+
+PA, PB, PC, PD, and PF is bidirectional I/O port
+and PT is comparator input port in uPD7808.
+uPD7807 uses PD port as data I/O and bottom address output,
+and uses PF port as top address output.
+
+NMI* is non maskable interrupt input signal (negative edge trigger).
+
+INT1 is interrupt input (positive edge trigger). It can be used as
+AC zero-cross input or trigger source of 16bit timer counter.
+
+MODE0 and MODE1 is input terminal which decides total amount of
+external memory of uPD7807 (4KByte, 16KBYte, and 64KByte).
+It also decides number of PF ports used as top address output.
+ 4KByte mode: PF0~PF3=address output, PF4~PF7=data I/O port
+16KByte mode: PF0~PF5=address output, PF6~PF7=data I/O port
+64KByte mode: PF0~PF7=address output
+
+RESET* is system rest terminal.
+
+X1 and X2 does clock signal generation (connect OSC and condenser).
+
+Vth is used to determine threshold voltage for PT port.
+PT0~PT7 is connected to + input of each comparator,
+and Vth deterimnes voltage connected to - input of PT0~PT7.
+But the voltage of Vth is not directly connected to comapators.
+It is connected via 16-level programmable voltage separate circuit.
+
+HOLD and HLDA is terminal for DMA. RD*, WR*, and ALE is bus
+interface signal (they are same type of Intel 8085).
+Unlike 8085, I/O address space is not available, so IO /M* signal
+does not exist. Read/write of external memory can be done
+by RD*, WR*, and ALE only.
+
+Vcc and Vss is main power source. Vdd is backup power source
+for internal RWM (32 Byte).
+
+
+PA and PB is I/O port. They have control register MA and MB.
+If control register is set to 1, the port is input.
+If control register is set to 0, the port is output.
+They are set to 1 by reset.
+
+PT is input-only port. It is consisted of input terminal PT0~PT7
+and Vth (set threshold voltage). Each PT input has analog comparator
+and latch, and + input of analog comparator is connected to
+PT terminal. Every - input of analog comparator is connected
+to devided voltage of Vth. Voltage dividing level can be set by
+bottom 4bits of MT (mode T) register. The range is 1/16~16/16 of Vth.
+
+Other internal I/Os are
+8bit timer (x2): Upcounter. If the counter matches to specified value,
+the timer is reset and counts again from 0.
+You can also set it to generate interrupt, or invert output flip-flop
+when the counter matches to specified value.
+Furthermore, you can output that flip-flop output to PC4/TO output,
+connect it to clock input of timer/event counter or watchdog timer.
+Or you can use it as bitrate clock of serial interface.
+Note: There is only 1 output flip-flop for 2 timers.
+If you use it for timer output of 1 timer, another timer cannot be used
+for other than interrupt generator.
+Clock input for timer can be switched between internal clock (2 type)
+or PC3/TI input. You can set 1 timer's match-output as another timer's
+clock input, so that you can use them as 1 16bit timer.
+
+16bit timer/event counter (x1): It can be used as
+- Interval timer
+- External event counter
+- Frequency measurement
+- Pulse width measurement
+- Programmable rectangle wave output
+- One pulse output
+Related terminals are PC5/CI input, PC6/CO0 output, and PC7/CO1.
+You can measure CI input's H duration, or you can output timing signal
+(with phase difference) to CO0 and CO1.
+
+serial I/F (x1): has 3 modes.
+- Asynchronous mode
+- Synchronous mode
+- I/O interface mode
+In all 3 modes, bitrate can be internal fixed clock, or timer output,
+or external clock.
+In asynchronous mode, you can
+- switch 7bit/8bit data
+- set parity ON/OFF and EVEN/ODD
+- set 1/2 stop bit
+
+
+
+
+DIFFERENCES BETWEEN 7810 and 7807
+
+--------------------------
+8bit transfer instructions
+--------------------------
+
+7810
+inst. 1st byte 2nd byte state action
+EXX 00001001 4 Swap BC DE HL
+EXA 00001000 4 Swap VA EA
+EXH 01010000 4 Swap HL
+BLOCK 00110001 13(C+1) (DE)+ <- (HL)+, C <- C - 1, until CY
+
+7807
+inst. 1st byte 2nd byte state action
+EXR 01001000 10101101 8 Swap VA BC DE HL EA
+EXX 01001000 10101111 8 Swap BC DE HL
+EXA 01001000 10101100 8 Swap VA EA
+EXH 01001000 10101110 8 Swap HL
+BLOCK D+ 00010000 13(C+1) (DE)+ <- (HL)+, C <- C - 1, until CY
+BLOCK D- 00010001 13(C+1) (DE)- <- (HL)-, C <- C - 1, until CY
+
+
+---------------------------
+16bit transfer instructions
+---------------------------
+All instructions are same except operand sr4 of DMOV instruction.
+7810
+V0-sr4 -function
+ 0-ECNT-timer/event counter upcounter
+ 1-ECPT-timer/event counter capture
+
+7807
+V1-V0- sr4 -function
+ 0- 0-ECNT -timer/event counter upcounter
+ 0- 1-ECPT0-timer/event counter capture 0
+ 1- 0-ECPT1-timer/event counter capture 1
+
+
+-----------------------------------------
+8bit operation instructions for registers
+-----------------------------------------
+All instructions are same.
+
+
+--------------------------------------
+8bit operation instructions for memory
+--------------------------------------
+All instructions are same.
+
+
+-----------------------------------------
+Operation instructions for immediate data
+-----------------------------------------
+uPD7807 has read-only PT port and special register group sr5 for it.
+ins. 1st byte 2nd byte 3rd 4th state func
+GTI sr5, byte 01100100 s0101sss dd 14 !CY sr5 - byte - 1
+LTI sr5, byte 01100100 s0111sss dd 14 CY sr5 - byte
+NEI sr5, byte 01100100 s1101sss dd 14 !Z sr5 - byte
+EQI sr5, byte 01100100 s1111sss dd 14 Z sr5 - byte
+ONI sr5, byte 01100100 s1001sss dd 14 !Z sr5 & byte
+OFFI sr5, byte 01100100 s1011sss dd 14 Z sr5 & byte
+
+S5-S4-S3-S2-S1-S0-sr -sr1-sr2-sr5-register function
+ 0 0 1 1 1 0 --- PT --- PT comparator input port T data
+ 1 0 0 1 0 0 WDM WDM --- --- watchdog timer mode register
+ 1 0 0 1 0 1 MT --- --- --- port T mode
+
+7807 doesn't have registers below
+ 0 0 1 0 0 0 ANM ANM ANM A/D channel mode
+ 1 0 0 0 0 0 --- CR0 --- A/D conversion result 0
+ 1 0 0 0 0 1 --- CR1 --- A/D conversion result 1
+ 1 0 0 0 1 0 --- CR2 --- A/D conversion result 2
+ 1 0 0 0 1 1 --- CR3 --- A/D conversion result 3
+ 1 0 1 0 0 0 ZCM --- --- zero cross mode
+
+Special register operand (includes registers for I/O ports) has
+6 groups - sr, sr1, sr2, sr3, sr4, and sr5. Among these groups,
+sr, sr1, sr2, and sr5 includes registers described in the table
+below, and expressed as bit pattern S5-S0.
+
+S5S4S3S2S1S0 sr sr1 sr2 sr5 register function
+0 0 0 0 0 0 PA PA PA PA port A
+0 0 0 0 0 1 PB PB PB PB port B
+0 0 0 0 1 0 PC PC PC PC port C
+0 0 0 0 1 1 PD PD PD PD port D
+0 0 0 1 0 1 PF PF PF PF port F
+0 0 0 1 1 0 MKH MKH MKH MKH mask high
+0 0 0 1 1 1 MKL MKL MKL MKL mask low
+0 0 1 0 0 1 SMH SMH SMH SMH serial mode high
+0 0 1 0 1 0 SML --- --- --- serial mode low
+0 0 1 0 1 1 EOM EOM EOM EOM timer/event counter output mode
+0 0 1 1 0 0 ETMM --- --- --- timer/event counter mode
+0 0 1 1 0 1 TMM TMM TMM TMM timer mode
+0 0 1 1 1 0 --- PT --- PT port T
+0 1 0 0 0 0 MM --- --- --- memory mapping
+0 1 0 0 0 1 MCC --- --- --- mode control C
+0 1 0 0 1 0 MA --- --- --- mode A
+0 1 0 0 1 1 MB --- --- --- mode B
+0 1 0 1 0 0 MC --- --- --- mode C
+0 1 0 1 1 1 MF --- --- --- mode F
+0 1 1 0 0 0 TXB --- --- --- Tx buffer
+0 1 1 0 0 1 --- RXB --- --- Rx buffer
+0 1 1 0 1 0 TM0 --- --- --- timer register 0
+0 1 1 0 1 1 TM1 --- --- --- timer register 1
+1 0 0 1 0 0 WDM WDM --- --- watchdog timer mode
+1 0 0 1 0 1 MT --- --- --- mode T
+
+For sr and sr1, all 6bits (S5, S4, S3, S2, S1, and S0) are used.
+For sr2 and sr5, only 4bits (S3, S2, S1, AND S0) are used.
+They are expressed as 'ssssss' and 's sss' in operation code.
+Note that 's sss' (of sr2 and sr5) is located separately.
+S0 is rightmost bit (LSB).
+
+
+--------------------------------------------
+Operation instructions for working registers
+--------------------------------------------
+All instructions are same.
+
+
+--------------------------------------------------------------------------
+16bit operation instructions and divider/multiplier operation instructions
+--------------------------------------------------------------------------
+All instructions are same.
+
+
+------------------------------------------
+Increment/decrement operation instructions
+------------------------------------------
+All instructions are same.
+
+
+----------------------------
+Other operation instructions
+----------------------------
+7807 has CMC instruction (inverts CY flag).
+ins. 1st byte 2nd byte 3rd 4th state func
+CMC 01001000 10101010 8 CY <- !CY
+
+
+---------------------------
+Rotation/shift instructions
+---------------------------
+All instructions are same.
+
+
+-----------------------------
+Jump/call/return instructions
+-----------------------------
+All instructions are same.
+
+
+-----------------
+Skip instructions
+-----------------
+7807 doesn't have this
+ins. 1st byte 2nd byte 3rd 4th state func
+BIT bit, wa 01011bbb wwwwwwww 10* bit skip if (V.wa).bit = 1
+
+Instead, 7807 has these bit manipulation instructions.
+ins. 1st byte 2nd byte 3rd 4th state func
+MOV CY, bit 01011111 bbbbbbbb 10* CY <- (bit)
+MOV bit, CY 01011010 bbbbbbbb 13* (bit) <- CY
+AND CY, bit 00110001 bbbbbbbb 10* CY <- CY & (bit)
+OR CY, bit 01011100 bbbbbbbb 10* CY <- CY | (bit)
+XOR CY, bit 01011110 bbbbbbbb 10* CY <- CY ^ (bit)
+SETB bit 01011000 bbbbbbbb 13* (bit) <- 1
+CLR bit 01011011 bbbbbbbb 13* (bit) <- 0
+NOT bit 01011001 bbbbbbbb 13* (bit) <- !(bit)
+SK bit 01011101 bbbbbbbb 10* (b) skip if (bit) = 1
+SKN bit 01010000 bbbbbbbb 10* !(b) skip if (bit) = 0
+
+
+------------------------
+CPU control instructions
+------------------------
+ins. 1st byte 2nd byte 3rd 4th state func
+HLT 01001000 00111011 11/12 halt
+11 state in uPD7807 and uPD7810, 12 state in uPD78C10.
+
+STOP 01001000 10111011 12 stop
+7807 doesn't have STOP instruction.
+
+*/
+
+
+#include "debugger.h"
+#include "upd7810.h"
+
+static UPD7810 upd7810;
+static int upd7810_icount;
+
+#define CY 0x01
+#define F1 0x02
+#define L0 0x04
+#define L1 0x08
+#define HC 0x10
+#define SK 0x20
+#define Z 0x40
+#define F7 0x80
+
+/* IRR flags */
+#define INTNMI 0x0001
+#define INTFT0 0x0002
+#define INTFT1 0x0004
+#define INTF1 0x0008
+#define INTF2 0x0010
+#define INTFE0 0x0020
+#define INTFE1 0x0040
+#define INTFEIN 0x0080
+#define INTFAD 0x0100
+#define INTFSR 0x0200
+#define INTFST 0x0400
+#define INTER 0x0800
+#define INTOV 0x1000
+
+/* ITF flags */
+#define INTAN4 0x0001
+#define INTAN5 0x0002
+#define INTAN6 0x0004
+#define INTAN7 0x0008
+#define INTSB 0x0010
+
+#define PPC upd7810.ppc.w.l
+#define PC upd7810.pc.w.l
+#define PCL upd7810.pc.b.l
+#define PCH upd7810.pc.b.h
+#define PCD upd7810.pc.d
+#define SP upd7810.sp.w.l
+#define SPL upd7810.sp.b.l
+#define SPH upd7810.sp.b.h
+#define SPD upd7810.sp.d
+#define PSW upd7810.psw
+#define OP upd7810.op
+#define OP2 upd7810.op2
+#define IFF upd7810.iff
+#define EA upd7810.ea.w.l
+#define EAL upd7810.ea.b.l
+#define EAH upd7810.ea.b.h
+#define VA upd7810.va.w.l
+#define V upd7810.va.b.h
+#define A upd7810.va.b.l
+#define VAD upd7810.va.d
+#define BC upd7810.bc.w.l
+#define B upd7810.bc.b.h
+#define C upd7810.bc.b.l
+#define DE upd7810.de.w.l
+#define D upd7810.de.b.h
+#define E upd7810.de.b.l
+#define HL upd7810.hl.w.l
+#define H upd7810.hl.b.h
+#define L upd7810.hl.b.l
+#define EA2 upd7810.ea2.w.l
+#define VA2 upd7810.va2.w.l
+#define BC2 upd7810.bc2.w.l
+#define DE2 upd7810.de2.w.l
+#define HL2 upd7810.hl2.w.l
+
+#define OVC0 upd7810.ovc0
+#define OVC1 upd7810.ovc1
+#define OVCE upd7810.ovce
+#define OVCF upd7810.ovcf
+#define OVCS upd7810.ovcs
+#define EDGES upd7810.edges
+
+#define CNT0 upd7810.cnt.b.l
+#define CNT1 upd7810.cnt.b.h
+#define TM0 upd7810.tm.b.l
+#define TM1 upd7810.tm.b.h
+#define ECNT upd7810.ecnt.w.l
+#define ECPT upd7810.ecnt.w.h
+#define ETM0 upd7810.etm.w.l
+#define ETM1 upd7810.etm.w.h
+
+#define MA upd7810.ma
+#define MB upd7810.mb
+#define MCC upd7810.mcc
+#define MC upd7810.mc
+#define MM upd7810.mm
+#define MF upd7810.mf
+#define TMM upd7810.tmm
+#define ETMM upd7810.etmm
+#define EOM upd7810.eom
+#define SML upd7810.sml
+#define SMH upd7810.smh
+#define ANM upd7810.anm
+#define MKL upd7810.mkl
+#define MKH upd7810.mkh
+#define ZCM upd7810.zcm
+
+#define CR0 upd7810.cr0
+#define CR1 upd7810.cr1
+#define CR2 upd7810.cr2
+#define CR3 upd7810.cr3
+#define RXB upd7810.rxb
+#define TXB upd7810.txb
+
+#define RXD upd7810.rxd
+#define TXD upd7810.txd
+#define SCK upd7810.sck
+#define TI upd7810.ti
+#define TO upd7810.to
+#define CI upd7810.ci
+#define CO0 upd7810.co0
+#define CO1 upd7810.co1
+
+#define IRR upd7810.irr
+#define ITF upd7810.itf
+
+struct opcode_s {
+ void (*opfunc)(void);
+ UINT8 oplen;
+ UINT8 cycles;
+ UINT8 cycles_skip;
+ UINT8 mask_l0_l1;
+};
+
+#define RDOP(O) O = cpu_readop(PCD); PC++
+#define RDOPARG(A) A = cpu_readop_arg(PCD); PC++
+#define RM(A) program_read_byte_8(A)
+#define WM(A,V) program_write_byte_8(A,V)
+
+#define ZHC_ADD(after,before,carry) \
+ if (after == 0) PSW |= Z; else PSW &= ~Z; \
+ if (after == before) \
+ PSW = (PSW&~CY) | (carry); \
+ else if (after < before) \
+ PSW |= CY; \
+ else \
+ PSW &= ~CY; \
+ if ((after & 15) < (before & 15)) \
+ PSW |= HC; \
+ else \
+ PSW &= ~HC; \
+
+#define ZHC_SUB(after,before,carry) \
+ if (after == 0) PSW |= Z; else PSW &= ~Z; \
+ if (before == after) \
+ PSW = (PSW & ~CY) | (carry); \
+ else if (after > before) \
+ PSW |= CY; \
+ else \
+ PSW &= ~CY; \
+ if ((after & 15) > (before & 15)) \
+ PSW |= HC; \
+ else \
+ PSW &= ~HC; \
+
+#define SKIP_CY if (CY == (PSW & CY)) PSW |= SK
+#define SKIP_NC if (0 == (PSW & CY)) PSW |= SK
+#define SKIP_Z if (Z == (PSW & Z)) PSW |= SK
+#define SKIP_NZ if (0 == (PSW & Z)) PSW |= SK
+#define SET_Z(n) if (n) PSW &= ~Z; else PSW |= Z
+
+static UINT8 RP(offs_t port)
+{
+ UINT8 data = 0xff;
+ switch (port)
+ {
+ case UPD7810_PORTA:
+ if (upd7810.ma) // NS20031301 no need to read if the port is set as output
+ upd7810.pa_in = io_read_byte_8(port);
+ data = (upd7810.pa_in & upd7810.ma) | (upd7810.pa_out & ~upd7810.ma);
+ break;
+ case UPD7810_PORTB:
+ if (upd7810.mb) // NS20031301 no need to read if the port is set as output
+ upd7810.pb_in = io_read_byte_8(port);
+ data = (upd7810.pb_in & upd7810.mb) | (upd7810.pb_out & ~upd7810.mb);
+ break;
+ case UPD7810_PORTC:
+ if (upd7810.mc) // NS20031301 no need to read if the port is set as output
+ upd7810.pc_in = io_read_byte_8(port);
+ data = (upd7810.pc_in & upd7810.mc) | (upd7810.pc_out & ~upd7810.mc);
+ if (upd7810.mcc & 0x01) /* PC0 = TxD output */
+ data = (data & ~0x01) | (upd7810.txd & 1 ? 0x01 : 0x00);
+ if (upd7810.mcc & 0x02) /* PC1 = RxD input */
+ data = (data & ~0x02) | (upd7810.rxd & 1 ? 0x02 : 0x00);
+ if (upd7810.mcc & 0x04) /* PC2 = SCK input/output */
+ data = (data & ~0x04) | (upd7810.sck & 1 ? 0x04 : 0x00);
+ if (upd7810.mcc & 0x08) /* PC3 = TI input */
+ data = (data & ~0x08) | (upd7810.ti & 1 ? 0x08 : 0x00);
+ if (upd7810.mcc & 0x10) /* PC4 = TO output */
+ data = (data & ~0x10) | (upd7810.to & 1 ? 0x10 : 0x00);
+ if (upd7810.mcc & 0x20) /* PC5 = CI input */
+ data = (data & ~0x20) | (upd7810.ci & 1 ? 0x20 : 0x00);
+ if (upd7810.mcc & 0x40) /* PC6 = CO0 output */
+ data = (data & ~0x40) | (upd7810.co0 & 1 ? 0x40 : 0x00);
+ if (upd7810.mcc & 0x80) /* PC7 = CO1 output */
+ data = (data & ~0x80) | (upd7810.co1 & 1 ? 0x80 : 0x00);
+ break;
+ case UPD7810_PORTD:
+ upd7810.pd_in = io_read_byte_8(port);
+ switch (upd7810.mm & 0x07)
+ {
+ case 0x00: /* PD input mode, PF port mode */
+ data = upd7810.pd_in;
+ break;
+ case 0x01: /* PD output mode, PF port mode */
+ data = upd7810.pd_out;
+ break;
+ default: /* PD extension mode, PF port/extension mode */
+ data = 0xff; /* what do we see on the port here? */
+ break;
+ }
+ break;
+ case UPD7810_PORTF:
+ upd7810.pf_in = io_read_byte_8(port);
+ switch (upd7810.mm & 0x06)
+ {
+ case 0x00: /* PD input/output mode, PF port mode */
+ data = (upd7810.pf_in & upd7810.mf) | (upd7810.pf_out & ~upd7810.mf);
+ break;
+ case 0x02: /* PD extension mode, PF0-3 extension mode, PF4-7 port mode */
+ data = (upd7810.pf_in & upd7810.mf) | (upd7810.pf_out & ~upd7810.mf);
+ data |= 0x0f; /* what would we see on the lower bits here? */
+ break;
+ case 0x04: /* PD extension mode, PF0-5 extension mode, PF6-7 port mode */
+ data = (upd7810.pf_in & upd7810.mf) | (upd7810.pf_out & ~upd7810.mf);
+ data |= 0x3f; /* what would we see on the lower bits here? */
+ break;
+ case 0x06:
+ data = 0xff; /* what would we see on the lower bits here? */
+ break;
+ }
+ break;
+ case UPD7807_PORTT: // NS20031301 partial implementation
+ data = io_read_byte_8(port);
+ break;
+ default:
+ logerror("uPD7810 internal error: RP() called with invalid port number\n");
+ }
+ return data;
+}
+
+static void WP(offs_t port, UINT8 data)
+{
+ switch (port)
+ {
+ case UPD7810_PORTA:
+ upd7810.pa_out = data;
+// data = (data & ~upd7810.ma) | (upd7810.pa_in & upd7810.ma);
+ data = (data & ~upd7810.ma) | (upd7810.ma); // NS20031401
+ io_write_byte_8(port, data);
+ break;
+ case UPD7810_PORTB:
+ upd7810.pb_out = data;
+// data = (data & ~upd7810.mb) | (upd7810.pb_in & upd7810.mb);
+ data = (data & ~upd7810.mb) | (upd7810.mb); // NS20031401
+ io_write_byte_8(port, data);
+ break;
+ case UPD7810_PORTC:
+ upd7810.pc_out = data;
+// data = (data & ~upd7810.mc) | (upd7810.pc_in & upd7810.mc);
+ data = (data & ~upd7810.mc) | (upd7810.mc); // NS20031401
+ if (upd7810.mcc & 0x01) /* PC0 = TxD output */
+ data = (data & ~0x01) | (upd7810.txd & 1 ? 0x01 : 0x00);
+ if (upd7810.mcc & 0x02) /* PC1 = RxD input */
+ data = (data & ~0x02) | (upd7810.rxd & 1 ? 0x02 : 0x00);
+ if (upd7810.mcc & 0x04) /* PC2 = SCK input/output */
+ data = (data & ~0x04) | (upd7810.sck & 1 ? 0x04 : 0x00);
+ if (upd7810.mcc & 0x08) /* PC3 = TI input */
+ data = (data & ~0x08) | (upd7810.ti & 1 ? 0x08 : 0x00);
+ if (upd7810.mcc & 0x10) /* PC4 = TO output */
+ data = (data & ~0x10) | (upd7810.to & 1 ? 0x10 : 0x00);
+ if (upd7810.mcc & 0x20) /* PC5 = CI input */
+ data = (data & ~0x20) | (upd7810.ci & 1 ? 0x20 : 0x00);
+ if (upd7810.mcc & 0x40) /* PC6 = CO0 output */
+ data = (data & ~0x40) | (upd7810.co0 & 1 ? 0x40 : 0x00);
+ if (upd7810.mcc & 0x80) /* PC7 = CO1 output */
+ data = (data & ~0x80) | (upd7810.co1 & 1 ? 0x80 : 0x00);
+ io_write_byte_8(port, data);
+ break;
+ case UPD7810_PORTD:
+ upd7810.pd_out = data;
+ switch (upd7810.mm & 0x07)
+ {
+ case 0x00: /* PD input mode, PF port mode */
+ data = upd7810.pd_in;
+ break;
+ case 0x01: /* PD output mode, PF port mode */
+ data = upd7810.pd_out;
+ break;
+ default: /* PD extension mode, PF port/extension mode */
+ return;
+ }
+ io_write_byte_8(port, data);
+ break;
+ case UPD7810_PORTF:
+ upd7810.pf_out = data;
+ data = (data & ~upd7810.mf) | (upd7810.pf_in & upd7810.mf);
+ switch (upd7810.mm & 0x06)
+ {
+ case 0x00: /* PD input/output mode, PF port mode */
+ break;
+ case 0x02: /* PD extension mode, PF0-3 extension mode, PF4-7 port mode */
+ data |= 0x0f; /* what would come out for the lower bits here? */
+ break;
+ case 0x04: /* PD extension mode, PF0-5 extension mode, PF6-7 port mode */
+ data |= 0x3f; /* what would come out for the lower bits here? */
+ break;
+ case 0x06:
+ data |= 0xff; /* what would come out for the lower bits here? */
+ break;
+ }
+ io_write_byte_8(port, data);
+ break;
+ default:
+ logerror("uPD7810 internal error: RP() called with invalid port number\n");
+ }
+}
+
+static void upd7810_take_irq(void)
+{
+ UINT16 vector = 0;
+ int irqline = 0;
+
+ /* global interrupt disable? */
+ if (0 == IFF)
+ return;
+
+ /* check the interrupts in priority sequence */
+ if ((IRR & INTFT0) && 0 == (MKL & 0x02))
+ {
+ switch (upd7810.config.type)
+ {
+ case TYPE_7810_GAMEMASTER:
+ vector = 0xff2a;
+ break;
+ default:
+ vector = 0x0008;
+ }
+ if (!((IRR & INTFT1) && 0 == (MKL & 0x04)))
+ IRR&=~INTFT0;
+ }
+ else
+ if ((IRR & INTFT1) && 0 == (MKL & 0x04))
+ {
+ switch (upd7810.config.type)
+ {
+ case TYPE_7810_GAMEMASTER:
+ vector = 0xff2a;
+ break;
+ default:
+ vector = 0x0008;
+ }
+ IRR&=~INTFT1;
+ }
+ else
+ if ((IRR & INTF1) && 0 == (MKL & 0x08))
+ {
+ irqline = UPD7810_INTF1;
+ vector = 0x0010;
+ if (!((IRR & INTF2) && 0 == (MKL & 0x10)))
+ IRR&=~INTF1;
+ }
+ else
+ if ((IRR & INTF2) && 0 == (MKL & 0x10))
+ {
+ irqline = UPD7810_INTF2;
+ vector = 0x0010;
+ IRR&=~INTF2;
+ }
+ else
+ if ((IRR & INTFE0) && 0 == (MKL & 0x20))
+ {
+ switch (upd7810.config.type)
+ {
+ case TYPE_7810_GAMEMASTER:
+ vector = 0xff2d;
+ break;
+ default:
+ vector = 0x0018;
+ }
+ if (!((IRR & INTFE1) && 0 == (MKL & 0x40)))
+ IRR&=~INTFE0;
+ }
+ else
+ if ((IRR & INTFE1) && 0 == (MKL & 0x40))
+ {
+ switch (upd7810.config.type)
+ {
+ case TYPE_7810_GAMEMASTER:
+ vector = 0xff2d;
+ break;
+ default:
+ vector = 0x0018;
+ }
+ IRR&=~INTFE1;
+ }
+ else
+ if ((IRR & INTFEIN) && 0 == (MKL & 0x80))
+ {
+ vector = 0x0020;
+ }
+ else
+ if ((IRR & INTFAD) && 0 == (MKH & 0x01))
+ {
+ vector = 0x0020;
+ }
+ else
+ if ((IRR & INTFSR) && 0 == (MKH & 0x02))
+ {
+ vector = 0x0028;
+ IRR&=~INTFSR;
+ }
+ else
+ if ((IRR & INTFST) && 0 == (MKH & 0x04))
+ {
+ vector = 0x0028;
+ IRR&=~INTFST;
+ }
+ if (vector)
+ {
+ /* acknowledge external IRQ */
+ if (irqline)
+ (*upd7810.irq_callback)(irqline);
+ SP--;
+ WM( SP, PSW );
+ SP--;
+ WM( SP, PCH );
+ SP--;
+ WM( SP, PCL );
+ IFF = 0;
+ PSW &= ~(SK|L0|L1);
+ PC = vector;
+ change_pc( PCD );
+ }
+}
+
+static void upd7810_write_EOM(void)
+{
+ if (EOM & 0x01) /* output LV0 content ? */
+ {
+ switch (EOM & 0x0e)
+ {
+ case 0x02: /* toggle CO0 */
+ CO0 = (CO0 >> 1) | ((CO0 ^ 2) & 2);
+ break;
+ case 0x04: /* reset CO0 */
+ CO0 = 0;
+ break;
+ case 0x08: /* set CO0 */
+ CO0 = 1;
+ break;
+ }
+ }
+ if (EOM & 0x10) /* output LV0 content ? */
+ {
+ switch (EOM & 0xe0)
+ {
+ case 0x20: /* toggle CO1 */
+ CO1 = (CO1 >> 1) | ((CO1 ^ 2) & 2);
+ break;
+ case 0x40: /* reset CO1 */
+ CO1 = 0;
+ break;
+ case 0x80: /* set CO1 */
+ CO1 = 1;
+ break;
+ }
+ }
+}
+
+static void upd7810_write_TXB(void)
+{
+ upd7810.txbuf = 1;
+}
+
+#define PAR7(n) ((((n)>>6)^((n)>>5)^((n)>>4)^((n)>>3)^((n)>>2)^((n)>>1)^((n)))&1)
+#define PAR8(n) ((((n)>>7)^((n)>>6)^((n)>>5)^((n)>>4)^((n)>>3)^((n)>>2)^((n)>>1)^((n)))&1)
+
+static void upd7810_sio_output(void)
+{
+ /* shift out more bits? */
+ if (upd7810.txcnt > 0)
+ {
+ TXD = upd7810.txs & 1;
+ if (upd7810.config.io_callback)
+ (*upd7810.config.io_callback)(UPD7810_TXD,TXD);
+ upd7810.txs >>= 1;
+ upd7810.txcnt--;
+ if (0 == upd7810.txcnt)
+ IRR |= INTFST; /* serial transfer completed */
+ }
+ else
+ if (SMH & 0x04) /* send enable ? */
+ {
+ /* nothing written into the transmitter buffer ? */
+ if (0 == upd7810.txbuf)
+ return;
+ upd7810.txbuf = 0;
+
+ if (SML & 0x03) /* asynchronous mode ? */
+ {
+ switch (SML & 0xfc)
+ {
+ case 0x48: /* 7bits, no parity, 1 stop bit */
+ case 0x68: /* 7bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ /* insert start bit in bit0, stop bit int bit8 */
+ upd7810.txs = (TXB << 1) | (1 << 8);
+ upd7810.txcnt = 9;
+ break;
+ case 0x4c: /* 8bits, no parity, 1 stop bit */
+ case 0x6c: /* 8bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ /* insert start bit in bit0, stop bit int bit9 */
+ upd7810.txs = (TXB << 1) | (1 << 9);
+ upd7810.txcnt = 10;
+ break;
+ case 0x58: /* 7bits, odd parity, 1 stop bit */
+ /* insert start bit in bit0, parity in bit 8, stop bit in bit9 */
+ upd7810.txs = (TXB << 1) | (PAR7(TXB) << 8) | (1 << 9);
+ upd7810.txcnt = 10;
+ break;
+ case 0x5c: /* 8bits, odd parity, 1 stop bit */
+ /* insert start bit in bit0, parity in bit 9, stop bit int bit10 */
+ upd7810.txs = (TXB << 1) | (PAR8(TXB) << 9) | (1 << 10);
+ upd7810.txcnt = 11;
+ break;
+ case 0x78: /* 7bits, even parity, 1 stop bit */
+ /* insert start bit in bit0, parity in bit 8, stop bit in bit9 */
+ upd7810.txs = (TXB << 1) | ((PAR7(TXB) ^ 1) << 8) | (1 << 9);
+ upd7810.txcnt = 10;
+ break;
+ case 0x7c: /* 8bits, even parity, 1 stop bit */
+ /* insert start bit in bit0, parity in bit 9, stop bit int bit10 */
+ upd7810.txs = (TXB << 1) | ((PAR8(TXB) ^ 1) << 9) | (1 << 10);
+ upd7810.txcnt = 11;
+ break;
+ case 0xc8: /* 7bits, no parity, 2 stop bits */
+ case 0xe8: /* 7bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ /* insert start bit in bit0, stop bits int bit8+9 */
+ upd7810.txs = (TXB << 1) | (3 << 8);
+ upd7810.txcnt = 10;
+ break;
+ case 0xcc: /* 8bits, no parity, 2 stop bits */
+ case 0xec: /* 8bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ /* insert start bit in bit0, stop bits in bits9+10 */
+ upd7810.txs = (TXB << 1) | (3 << 9);
+ upd7810.txcnt = 11;
+ break;
+ case 0xd8: /* 7bits, odd parity, 2 stop bits */
+ /* insert start bit in bit0, parity in bit 8, stop bits in bits9+10 */
+ upd7810.txs = (TXB << 1) | (PAR7(TXB) << 8) | (3 << 9);
+ upd7810.txcnt = 11;
+ break;
+ case 0xdc: /* 8bits, odd parity, 2 stop bits */
+ /* insert start bit in bit0, parity in bit 9, stop bits int bit10+11 */
+ upd7810.txs = (TXB << 1) | (PAR8(TXB) << 9) | (3 << 10);
+ upd7810.txcnt = 12;
+ break;
+ case 0xf8: /* 7bits, even parity, 2 stop bits */
+ /* insert start bit in bit0, parity in bit 8, stop bits in bit9+10 */
+ upd7810.txs = (TXB << 1) | ((PAR7(TXB) ^ 1) << 8) | (3 << 9);
+ upd7810.txcnt = 11;
+ break;
+ case 0xfc: /* 8bits, even parity, 2 stop bits */
+ /* insert start bit in bit0, parity in bit 9, stop bits int bits10+10 */
+ upd7810.txs = (TXB << 1) | ((PAR8(TXB) ^ 1) << 9) | (1 << 10);
+ upd7810.txcnt = 12;
+ break;
+ }
+ }
+ else
+ {
+ /* synchronous mode */
+ upd7810.txs = TXB;
+ upd7810.txcnt = 8;
+ }
+ }
+}
+
+static void upd7810_sio_input(void)
+{
+ /* sample next bit? */
+ if (upd7810.rxcnt > 0)
+ {
+ if (upd7810.config.io_callback)
+ RXD = (*upd7810.config.io_callback)(UPD7810_RXD,RXD);
+ upd7810.rxs = (upd7810.rxs >> 1) | ((UINT16)RXD << 15);
+ upd7810.rxcnt--;
+ if (0 == upd7810.rxcnt)
+ {
+ /* reset the TSK bit */
+ SMH &= ~0x40;
+ /* serial receive completed interrupt */
+ IRR |= INTFSR;
+ /* now extract the data from the shift register */
+ if (SML & 0x03) /* asynchronous mode ? */
+ {
+ switch (SML & 0xfc)
+ {
+ case 0x48: /* 7bits, no parity, 1 stop bit */
+ case 0x68: /* 7bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ upd7810.rxs >>= 16 - 9;
+ RXB = (upd7810.rxs >> 1) & 0x7f;
+ if ((1 << 8) != (upd7810.rxs & (1 | (1 << 8))))
+ IRR |= INTER; /* framing error */
+ break;
+ case 0x4c: /* 8bits, no parity, 1 stop bit */
+ case 0x6c: /* 8bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ upd7810.rxs >>= 16 - 10;
+ RXB = (upd7810.rxs >> 1) & 0xff;
+ if ((1 << 9) != (upd7810.rxs & (1 | (1 << 9))))
+ IRR |= INTER; /* framing error */
+ break;
+ case 0x58: /* 7bits, odd parity, 1 stop bit */
+ upd7810.rxs >>= 16 - 10;
+ RXB = (upd7810.rxs >> 1) & 0x7f;
+ if ((1 << 9) != (upd7810.rxs & (1 | (1 << 9))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((upd7810.rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0x5c: /* 8bits, odd parity, 1 stop bit */
+ upd7810.rxs >>= 16 - 11;
+ RXB = (upd7810.rxs >> 1) & 0xff;
+ if ((1 << 10) != (upd7810.rxs & (1 | (1 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((upd7810.rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0x78: /* 7bits, even parity, 1 stop bit */
+ upd7810.rxs >>= 16 - 10;
+ RXB = (upd7810.rxs >> 1) & 0x7f;
+ if ((1 << 9) != (upd7810.rxs & (1 | (1 << 9))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((upd7810.rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0x7c: /* 8bits, even parity, 1 stop bit */
+ upd7810.rxs >>= 16 - 11;
+ RXB = (upd7810.rxs >> 1) & 0xff;
+ if ((1 << 10) != (upd7810.rxs & (1 | (1 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((upd7810.rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xc8: /* 7bits, no parity, 2 stop bits */
+ case 0xe8: /* 7bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ upd7810.rxs >>= 16 - 10;
+ RXB = (upd7810.rxs >> 1) & 0x7f;
+ if ((3 << 9) != (upd7810.rxs & (1 | (3 << 9))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((upd7810.rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xcc: /* 8bits, no parity, 2 stop bits */
+ case 0xec: /* 8bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ upd7810.rxs >>= 16 - 11;
+ RXB = (upd7810.rxs >> 1) & 0xff;
+ if ((3 << 10) != (upd7810.rxs & (1 | (3 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((upd7810.rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xd8: /* 7bits, odd parity, 2 stop bits */
+ upd7810.rxs >>= 16 - 11;
+ RXB = (upd7810.rxs >> 1) & 0x7f;
+ if ((3 << 10) != (upd7810.rxs & (1 | (3 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((upd7810.rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xdc: /* 8bits, odd parity, 2 stop bits */
+ upd7810.rxs >>= 16 - 12;
+ RXB = (upd7810.rxs >> 1) & 0xff;
+ if ((3 << 11) != (upd7810.rxs & (1 | (3 << 11))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((upd7810.rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xf8: /* 7bits, even parity, 2 stop bits */
+ upd7810.rxs >>= 16 - 11;
+ RXB = (upd7810.rxs >> 1) & 0x7f;
+ if ((3 << 10) != (upd7810.rxs & (1 | (3 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((upd7810.rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xfc: /* 8bits, even parity, 2 stop bits */
+ upd7810.rxs >>= 16 - 12;
+ RXB = (upd7810.rxs >> 1) & 0xff;
+ if ((3 << 11) != (upd7810.rxs & (1 | (3 << 11))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((upd7810.rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ }
+ }
+ else
+ {
+ upd7810.rxs >>= 16 - 8;
+ RXB = upd7810.rxs;
+// upd7810.rxcnt = 8;
+ }
+ }
+ }
+ else
+ if (SMH & 0x08) /* receive enable ? */
+ {
+ if (SML & 0x03) /* asynchronous mode ? */
+ {
+ switch (SML & 0xfc)
+ {
+ case 0x48: /* 7bits, no parity, 1 stop bit */
+ case 0x68: /* 7bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ upd7810.rxcnt = 9;
+ break;
+ case 0x4c: /* 8bits, no parity, 1 stop bit */
+ case 0x6c: /* 8bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ upd7810.rxcnt = 10;
+ break;
+ case 0x58: /* 7bits, odd parity, 1 stop bit */
+ upd7810.rxcnt = 10;
+ break;
+ case 0x5c: /* 8bits, odd parity, 1 stop bit */
+ upd7810.rxcnt = 11;
+ break;
+ case 0x78: /* 7bits, even parity, 1 stop bit */
+ upd7810.rxcnt = 10;
+ break;
+ case 0x7c: /* 8bits, even parity, 1 stop bit */
+ upd7810.rxcnt = 11;
+ break;
+ case 0xc8: /* 7bits, no parity, 2 stop bits */
+ case 0xe8: /* 7bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ upd7810.rxcnt = 10;
+ break;
+ case 0xcc: /* 8bits, no parity, 2 stop bits */
+ case 0xec: /* 8bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ upd7810.rxcnt = 11;
+ break;
+ case 0xd8: /* 7bits, odd parity, 2 stop bits */
+ upd7810.rxcnt = 11;
+ break;
+ case 0xdc: /* 8bits, odd parity, 2 stop bits */
+ upd7810.rxcnt = 12;
+ break;
+ case 0xf8: /* 7bits, even parity, 2 stop bits */
+ upd7810.rxcnt = 11;
+ break;
+ case 0xfc: /* 8bits, even parity, 2 stop bits */
+ upd7810.rxcnt = 12;
+ break;
+ }
+ }
+ else
+ /* TSK bit set ? */
+ if (SMH & 0x40)
+ {
+ upd7810.rxcnt = 8;
+ }
+ }
+}
+
+static void upd7810_timers(int cycles)
+{
+ /**** TIMER 0 ****/
+ if (TMM & 0x10) /* timer 0 upcounter reset ? */
+ CNT0 = 0;
+ else
+ {
+ switch (TMM & 0x0c) /* timer 0 clock source */
+ {
+ case 0x00: /* clock divided by 12 */
+ OVC0 += cycles;
+ while (OVC0 >= 12)
+ {
+ OVC0 -= 12;
+ CNT0++;
+ if (CNT0 == TM0)
+ {
+ CNT0 = 0;
+ IRR |= INTFT0;
+ /* timer F/F source is timer 0 ? */
+ if (0x00 == (TMM & 0x03))
+ {
+ TO ^= 1;
+ if (upd7810.config.io_callback)
+ (*upd7810.config.io_callback)(UPD7810_TO,TO);
+ }
+ /* timer 1 chained with timer 0 ? */
+ if ((TMM & 0xe0) == 0x60)
+ {
+ CNT1++;
+ if (CNT1 == TM1)
+ {
+ IRR |= INTFT1;
+ CNT1 = 0;
+ /* timer F/F source is timer 1 ? */
+ if (0x01 == (TMM & 0x03))
+ {
+ TO ^= 1;
+ if (upd7810.config.io_callback)
+ (*upd7810.config.io_callback)(UPD7810_TO,TO);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 0x04: /* clock divided by 384 */
+ OVC0 += cycles;
+ while (OVC0 >= 384)
+ {
+ OVC0 -= 384;
+ CNT0++;
+ if (CNT0 == TM0)
+ {
+ CNT0 = 0;
+ IRR |= INTFT0;
+ /* timer F/F source is timer 0 ? */
+ if (0x00 == (TMM & 0x03))
+ {
+ TO ^= 1;
+ if (upd7810.config.io_callback)
+ (*upd7810.config.io_callback)(UPD7810_TO,TO);
+ }
+ /* timer 1 chained with timer 0 ? */
+ if ((TMM & 0xe0) == 0x60)
+ {
+ CNT1++;
+ if (CNT1 == TM1)
+ {
+ CNT1 = 0;
+ IRR |= INTFT1;
+ /* timer F/F source is timer 1 ? */
+ if (0x01 == (TMM & 0x03))
+ {
+ TO ^= 1;
+ if (upd7810.config.io_callback)
+ (*upd7810.config.io_callback)(UPD7810_TO,TO);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 0x08: /* external signal at TI */
+ break;
+ case 0x0c: /* disabled */
+ break;
+ }
+ }
+
+ /**** TIMER 1 ****/
+ if (TMM & 0x80) /* timer 1 upcounter reset ? */
+ CNT1 = 0;
+ else
+ {
+ switch (TMM & 0x60) /* timer 1 clock source */
+ {
+ case 0x00: /* clock divided by 12 */
+ OVC1 += cycles;
+ while (OVC1 >= 12)
+ {
+ OVC1 -= 12;
+ CNT1++;
+ if (CNT1 == TM1)
+ {
+ CNT1 = 0;
+ IRR |= INTFT1;
+ /* timer F/F source is timer 1 ? */
+ if (0x01 == (TMM & 0x03))
+ {
+ TO ^= 1;
+ if (upd7810.config.io_callback)
+ (*upd7810.config.io_callback)(UPD7810_TO,TO);
+ }
+ }
+ }
+ break;
+ case 0x20: /* clock divided by 384 */
+ OVC1 += cycles;
+ while (OVC1 >= 384)
+ {
+ OVC1 -= 384;
+ CNT1++;
+ if (CNT1 == TM1)
+ {
+ CNT1 = 0;
+ IRR |= INTFT1;
+ /* timer F/F source is timer 1 ? */
+ if (0x01 == (TMM & 0x03))
+ {
+ TO ^= 1;
+ if (upd7810.config.io_callback)
+ (*upd7810.config.io_callback)(UPD7810_TO,TO);
+ }
+ }
+ }
+ break;
+ case 0x40: /* external signal at TI */
+ break;
+ case 0x60: /* clocked with timer 0 */
+ break;
+ }
+ }
+
+ /**** TIMER F/F ****/
+ /* timer F/F source is clock divided by 3 ? */
+ if (0x02 == (TMM & 0x03))
+ {
+ OVCF += cycles;
+ while (OVCF >= 3)
+ {
+ TO ^= 1;
+ if (upd7810.config.io_callback)
+ (*upd7810.config.io_callback)(UPD7810_TO,TO);
+ OVCF -= 3;
+ }
+ }
+
+ /**** ETIMER ****/
+ /* ECNT clear */
+ if (0x00 == (ETMM & 0x0c))
+ ECNT = 0;
+ else
+ if (0x00 == (ETMM & 0x03) || (0x01 == (ETMM & 0x03) && CI))
+ {
+ OVCE += cycles;
+ /* clock divided by 12 */
+ while (OVCE >= 12)
+ {
+ OVCE -= 12;
+ ECNT++;
+ switch (ETMM & 0x0c)
+ {
+ case 0x00: /* clear ECNT */
+ break;
+ case 0x04: /* free running */
+ if (0 == ECNT)
+ ITF |= INTOV; /* set overflow flag if counter wrapped */
+ break;
+ case 0x08: /* reset at falling edge of CI or TO */
+ break;
+ case 0x0c: /* reset if ECNT == ETM1 */
+ if (ETM1 == ECNT)
+ ECNT = 0;
+ break;
+ }
+ switch (ETMM & 0x30)
+ {
+ case 0x00: /* set CO0 if ECNT == ETM0 */
+ if (ETM0 == ECNT)
+ {
+ switch (EOM & 0x0e)
+ {
+ case 0x02: /* toggle CO0 */
+ CO0 = (CO0 >> 1) | ((CO0 ^ 2) & 2);
+ break;
+ case 0x04: /* reset CO0 */
+ CO0 = 0;
+ break;
+ case 0x08: /* set CO0 */
+ CO0 = 1;
+ break;
+ }
+ }
+ break;
+ case 0x10: /* prohibited */
+ break;
+ case 0x20: /* set CO0 if ECNT == ETM0 or at falling CI input */
+ if (ETM0 == ECNT)
+ {
+ switch (EOM & 0x0e)
+ {
+ case 0x02: /* toggle CO0 */
+ CO0 = (CO0 >> 1) | ((CO0 ^ 2) & 2);
+ break;
+ case 0x04: /* reset CO0 */
+ CO0 = 0;
+ break;
+ case 0x08: /* set CO0 */
+ CO0 = 1;
+ break;
+ }
+ }
+ break;
+ case 0x30: /* latch CO0 if ECNT == ETM0 or ECNT == ETM1 */
+ if (ETM0 == ECNT || ETM1 == ECNT)
+ {
+ switch (EOM & 0x0e)
+ {
+ case 0x02: /* toggle CO0 */
+ CO0 = (CO0 >> 1) | ((CO0 ^ 2) & 2);
+ break;
+ case 0x04: /* reset CO0 */
+ CO0 = 0;
+ break;
+ case 0x08: /* set CO0 */
+ CO0 = 1;
+ break;
+ }
+ }
+ break;
+ }
+ switch (ETMM & 0xc0)
+ {
+ case 0x00: /* lacth CO1 if ECNT == ETM1 */
+ if (ETM1 == ECNT)
+ {
+ switch (EOM & 0xe0)
+ {
+ case 0x20: /* toggle CO1 */
+ CO1 = (CO1 >> 1) | ((CO1 ^ 2) & 2);
+ break;
+ case 0x40: /* reset CO1 */
+ CO1 = 0;
+ break;
+ case 0x80: /* set CO1 */
+ CO1 = 1;
+ break;
+ }
+ }
+ break;
+ case 0x40: /* prohibited */
+ break;
+ case 0x80: /* latch CO1 if ECNT == ETM1 or falling edge of CI input */
+ if (ETM1 == ECNT)
+ {
+ switch (EOM & 0xe0)
+ {
+ case 0x20: /* toggle CO1 */
+ CO1 = (CO1 >> 1) | ((CO1 ^ 2) & 2);
+ break;
+ case 0x40: /* reset CO1 */
+ CO1 = 0;
+ break;
+ case 0x80: /* set CO1 */
+ CO1 = 1;
+ break;
+ }
+ }
+ break;
+ case 0xc0: /* latch CO1 if ECNT == ETM0 or ECNT == ETM1 */
+ if (ETM0 == ECNT || ETM1 == ECNT)
+ {
+ switch (EOM & 0xe0)
+ {
+ case 0x20: /* toggle CO1 */
+ CO1 = (CO1 >> 1) | ((CO1 ^ 2) & 2);
+ break;
+ case 0x40: /* reset CO1 */
+ CO1 = 0;
+ break;
+ case 0x80: /* set CO1 */
+ CO1 = 1;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /**** SIO ****/
+ switch (SMH & 0x03)
+ {
+ case 0x00: /* interval timer F/F */
+ break;
+ case 0x01: /* internal clock divided by 384 */
+ OVCS += cycles;
+ while (OVCS >= 384)
+ {
+ OVCS -= 384;
+ if (0 == (EDGES ^= 1))
+ upd7810_sio_input();
+ else
+ upd7810_sio_output();
+ }
+ break;
+ case 0x02: /* internal clock divided by 24 */
+ OVCS += cycles;
+ while (OVCS >= 24)
+ {
+ OVCS -= 24;
+ if (0 == (EDGES ^= 1))
+ upd7810_sio_input();
+ else
+ upd7810_sio_output();
+ }
+ break;
+ }
+}
+
+void upd7810_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ upd7810.config = *(const UPD7810_CONFIG*) config;
+ upd7810.irq_callback = irqcallback;
+
+ state_save_register_item("upd7810", index, upd7810.ppc.w.l);
+ state_save_register_item("upd7810", index, upd7810.pc.w.l);
+ state_save_register_item("upd7810", index, upd7810.sp.w.l);
+ state_save_register_item("upd7810", index, upd7810.psw);
+ state_save_register_item("upd7810", index, upd7810.op);
+ state_save_register_item("upd7810", index, upd7810.op2);
+ state_save_register_item("upd7810", index, upd7810.iff);
+ state_save_register_item("upd7810", index, upd7810.ea.w.l);
+ state_save_register_item("upd7810", index, upd7810.va.w.l);
+ state_save_register_item("upd7810", index, upd7810.bc.w.l);
+ state_save_register_item("upd7810", index, upd7810.de.w.l);
+ state_save_register_item("upd7810", index, upd7810.hl.w.l);
+ state_save_register_item("upd7810", index, upd7810.ea2.w.l);
+ state_save_register_item("upd7810", index, upd7810.va2.w.l);
+ state_save_register_item("upd7810", index, upd7810.bc2.w.l);
+ state_save_register_item("upd7810", index, upd7810.de2.w.l);
+ state_save_register_item("upd7810", index, upd7810.hl2.w.l);
+ state_save_register_item("upd7810", index, upd7810.cnt.d);
+ state_save_register_item("upd7810", index, upd7810.tm.d);
+ state_save_register_item("upd7810", index, upd7810.ecnt.d);
+ state_save_register_item("upd7810", index, upd7810.etm.d);
+ state_save_register_item("upd7810", index, upd7810.ma);
+ state_save_register_item("upd7810", index, upd7810.mb);
+ state_save_register_item("upd7810", index, upd7810.mcc);
+ state_save_register_item("upd7810", index, upd7810.mc);
+ state_save_register_item("upd7810", index, upd7810.mm);
+ state_save_register_item("upd7810", index, upd7810.mf);
+ state_save_register_item("upd7810", index, upd7810.tmm);
+ state_save_register_item("upd7810", index, upd7810.etmm);
+ state_save_register_item("upd7810", index, upd7810.eom);
+ state_save_register_item("upd7810", index, upd7810.sml);
+ state_save_register_item("upd7810", index, upd7810.smh);
+ state_save_register_item("upd7810", index, upd7810.anm);
+ state_save_register_item("upd7810", index, upd7810.mkl);
+ state_save_register_item("upd7810", index, upd7810.mkh);
+ state_save_register_item("upd7810", index, upd7810.zcm);
+ state_save_register_item("upd7810", index, upd7810.pa_out);
+ state_save_register_item("upd7810", index, upd7810.pb_out);
+ state_save_register_item("upd7810", index, upd7810.pc_out);
+ state_save_register_item("upd7810", index, upd7810.pd_out);
+ state_save_register_item("upd7810", index, upd7810.pf_out);
+ state_save_register_item("upd7810", index, upd7810.cr0);
+ state_save_register_item("upd7810", index, upd7810.cr1);
+ state_save_register_item("upd7810", index, upd7810.cr2);
+ state_save_register_item("upd7810", index, upd7810.cr3);
+ state_save_register_item("upd7810", index, upd7810.txb);
+ state_save_register_item("upd7810", index, upd7810.rxb);
+ state_save_register_item("upd7810", index, upd7810.txd);
+ state_save_register_item("upd7810", index, upd7810.rxd);
+ state_save_register_item("upd7810", index, upd7810.sck);
+ state_save_register_item("upd7810", index, upd7810.ti);
+ state_save_register_item("upd7810", index, upd7810.to);
+ state_save_register_item("upd7810", index, upd7810.ci);
+ state_save_register_item("upd7810", index, upd7810.co0);
+ state_save_register_item("upd7810", index, upd7810.co1);
+ state_save_register_item("upd7810", index, upd7810.irr);
+ state_save_register_item("upd7810", index, upd7810.itf);
+ state_save_register_item("upd7810", index, upd7810.ovc0);
+ state_save_register_item("upd7810", index, upd7810.ovc1);
+ state_save_register_item("upd7810", index, upd7810.ovcf);
+ state_save_register_item("upd7810", index, upd7810.ovcs);
+ state_save_register_item("upd7810", index, upd7810.edges);
+}
+
+#include "7810tbl.c"
+#include "7810ops.c"
+
+static void upd7810_reset (void)
+{
+ UPD7810_CONFIG save_config;
+ int (*save_irqcallback)(int);
+
+ save_config = upd7810.config;
+ save_irqcallback = upd7810.irq_callback;
+ memset(&upd7810, 0, sizeof(upd7810));
+ upd7810.config = save_config;
+ upd7810.irq_callback = save_irqcallback;
+
+ upd7810.opXX = opXX_7810;
+ ETMM = 0xff;
+ TMM = 0xff;
+ MA = 0xff;
+ MB = 0xff;
+ switch (upd7810.config.type)
+ {
+ case TYPE_7810_GAMEMASTER:
+ // needed for lcd screen/ram selection; might be internal in cpu and therefor not needed; 0x10 written in some games
+ MC = 0xff&~0x7;
+ WP( UPD7810_PORTC, 1 ); //hyper space
+ PCD=0x8000;
+ break;
+ default:
+ MC = 0xff;
+ }
+ MF = 0xff;
+ // gamemaster falling block "and"s to enable interrupts
+ MKL = 0xff;
+ MKH = 0xff; //?
+}
+
+static void upd7807_reset (void)
+{
+ upd7810_reset();
+ upd7810.opXX = opXX_7807;
+}
+
+static void upd7810_exit (void)
+{
+}
+
+static int upd7810_execute (int cycles)
+{
+ const struct opcode_s *opXX = upd7810.opXX;
+
+ upd7810_icount = cycles;
+
+ do
+ {
+ int cc = 0;
+
+ CALL_MAME_DEBUG;
+
+ PPC = PC;
+ RDOP(OP);
+
+ /*
+ * clear L0 and/or L1 flags for all opcodes except
+ * L0 for "MVI L,xx" or "LXI H,xxxx"
+ * L1 for "MVI A,xx"
+ */
+ PSW &= ~opXX[OP].mask_l0_l1;
+
+ /* skip flag set and not SOFTI opcode? */
+ if ((PSW & SK) && (OP != 0x72))
+ {
+ if (opXX[OP].cycles)
+ {
+ cc = opXX[OP].cycles_skip;
+ PC += opXX[OP].oplen - 1;
+ }
+ else
+ {
+ RDOP(OP2);
+ switch (OP)
+ {
+ case 0x48:
+ cc = op48[OP2].cycles_skip;
+ PC += op48[OP2].oplen - 2;
+ break;
+ case 0x4c:
+ cc = op4C[OP2].cycles_skip;
+ PC += op4C[OP2].oplen - 2;
+ break;
+ case 0x4d:
+ cc = op4D[OP2].cycles_skip;
+ PC += op4D[OP2].oplen - 2;
+ break;
+ case 0x60:
+ cc = op60[OP2].cycles_skip;
+ PC += op60[OP2].oplen - 2;
+ break;
+ case 0x64:
+ cc = op64[OP2].cycles_skip;
+ PC += op64[OP2].oplen - 2;
+ break;
+ case 0x70:
+ cc = op70[OP2].cycles_skip;
+ PC += op70[OP2].oplen - 2;
+ break;
+ case 0x74:
+ cc = op74[OP2].cycles_skip;
+ PC += op74[OP2].oplen - 2;
+ break;
+ default:
+ fatalerror("uPD7810 internal error: check cycle counts for main");
+ }
+ }
+ PSW &= ~SK;
+ upd7810_timers( cc );
+ change_pc( PCD );
+ }
+ else
+ {
+ cc = opXX[OP].cycles;
+ upd7810_timers( cc );
+ (*opXX[OP].opfunc)();
+ }
+ upd7810_icount -= cc;
+ upd7810_take_irq();
+
+ } while (upd7810_icount > 0);
+
+ return cycles - upd7810_icount;
+}
+
+static void upd7810_get_context (void *dst)
+{
+ if (dst)
+ memcpy(dst, &upd7810, sizeof(upd7810));
+}
+
+static void upd7810_set_context (void *src)
+{
+ if (src)
+ memcpy(&upd7810, src, sizeof(upd7810));
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if (state != CLEAR_LINE)
+ {
+ if (irqline == INPUT_LINE_NMI)
+ {
+ /* no nested NMIs ? */
+// if (0 == (IRR & INTNMI))
+ {
+ IRR |= INTNMI;
+ SP--;
+ WM( SP, PSW );
+ SP--;
+ WM( SP, PCH );
+ SP--;
+ WM( SP, PCL );
+ IFF = 0;
+ PSW &= ~(SK|L0|L1);
+ PC = 0x0004;
+ change_pc( PCD );
+ }
+ }
+ else
+ if (irqline == UPD7810_INTF1)
+ IRR |= INTF1;
+ else
+ if (irqline == UPD7810_INTF2)
+ IRR |= INTF2;
+ // gamemaster hack
+ else
+ if (irqline == UPD7810_INTFE1)
+ IRR |= INTFE1;
+ else
+ logerror("upd7810_set_irq_line invalid irq line #%d\n", irqline);
+ }
+ /* resetting interrupt requests is done with the SKIT/SKNIT opcodes only! */
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void upd7810_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + UPD7810_INTF1: set_irq_line(UPD7810_INTF1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + UPD7810_INTF2: set_irq_line(UPD7810_INTF2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + UPD7810_INTFE1: set_irq_line(UPD7810_INTFE1, info->i); break;
+
+ case CPUINFO_INT_PC: PC = info->i; change_pc(PCD); break;
+ case CPUINFO_INT_REGISTER + UPD7810_PC: PC = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + UPD7810_SP: SP = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_PSW: PSW = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_A: A = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_V: V = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_EA: EA = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_VA: VA = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_BC: BC = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_DE: DE = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_HL: HL = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_EA2: EA2 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_VA2: VA2 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_BC2: BC2 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_DE2: DE2 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_HL2: HL2 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CNT0: CNT0 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CNT1: CNT1 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TM0: TM0 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TM1: TM1 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ECNT: ECNT = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ECPT: ECPT = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ETM0: ETM0 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ETM1: ETM1 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MA: MA = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MB: MB = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MCC: MCC = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MC: MC = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MM: MM = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MF: MF = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TMM: TMM = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ETMM: ETMM = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_EOM: EOM = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_SML: SML = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_SMH: SMH = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ANM: ANM = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MKL: MKL = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MKH: MKH = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ZCM: ZCM = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TXB: TXB = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_RXB: RXB = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CR0: CR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CR1: CR1 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CR2: CR2 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CR3: CR3 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TXD: TXD = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_RXD: RXD = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_SCK: SCK = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TI: TI = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TO: TO = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CI: CI = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CO0: CO0 = info->i; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CO1: CO1 = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void upd7810_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(upd7810); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = (IRR & INTNMI) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + UPD7810_INTF1: info->i = (IRR & INTF1) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + UPD7810_INTF2: info->i = (IRR & INTF2) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + UPD7810_INTFE1: info->i = (IRR & INTFE1) ? ASSERT_LINE : CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + UPD7810_PC: info->i = PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + UPD7810_SP: info->i = SP; break;
+ case CPUINFO_INT_REGISTER + UPD7810_PSW: info->i = PSW; break;
+ case CPUINFO_INT_REGISTER + UPD7810_EA: info->i = EA; break;
+ case CPUINFO_INT_REGISTER + UPD7810_VA: info->i = VA; break;
+ case CPUINFO_INT_REGISTER + UPD7810_BC: info->i = BC; break;
+ case CPUINFO_INT_REGISTER + UPD7810_DE: info->i = DE; break;
+ case CPUINFO_INT_REGISTER + UPD7810_HL: info->i = HL; break;
+ case CPUINFO_INT_REGISTER + UPD7810_EA2: info->i = EA2; break;
+ case CPUINFO_INT_REGISTER + UPD7810_VA2: info->i = VA2; break;
+ case CPUINFO_INT_REGISTER + UPD7810_BC2: info->i = BC2; break;
+ case CPUINFO_INT_REGISTER + UPD7810_DE2: info->i = DE2; break;
+ case CPUINFO_INT_REGISTER + UPD7810_HL2: info->i = HL2; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CNT0: info->i = CNT0; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CNT1: info->i = CNT1; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TM0: info->i = TM0; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TM1: info->i = TM1; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ECNT: info->i = ECNT; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ECPT: info->i = ECPT; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ETM0: info->i = ETM0; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ETM1: info->i = ETM1; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MA: info->i = MA; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MB: info->i = MB; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MCC: info->i = MCC; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MC: info->i = MC; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MM: info->i = MM; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MF: info->i = MF; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TMM: info->i = TMM; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ETMM: info->i = ETMM; break;
+ case CPUINFO_INT_REGISTER + UPD7810_EOM: info->i = EOM; break;
+ case CPUINFO_INT_REGISTER + UPD7810_SML: info->i = SML; break;
+ case CPUINFO_INT_REGISTER + UPD7810_SMH: info->i = SMH; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ANM: info->i = ANM; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MKL: info->i = MKL; break;
+ case CPUINFO_INT_REGISTER + UPD7810_MKH: info->i = MKH; break;
+ case CPUINFO_INT_REGISTER + UPD7810_ZCM: info->i = ZCM; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TXB: info->i = TXB; break;
+ case CPUINFO_INT_REGISTER + UPD7810_RXB: info->i = RXB; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CR0: info->i = CR0; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CR1: info->i = CR1; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CR2: info->i = CR2; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CR3: info->i = CR3; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TXD: info->i = TXD; break;
+ case CPUINFO_INT_REGISTER + UPD7810_RXD: info->i = RXD; break;
+ case CPUINFO_INT_REGISTER + UPD7810_SCK: info->i = SCK; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TI: info->i = TI; break;
+ case CPUINFO_INT_REGISTER + UPD7810_TO: info->i = TO; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CI: info->i = CI; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CO0: info->i = CO0; break;
+ case CPUINFO_INT_REGISTER + UPD7810_CO1: info->i = CO1; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = upd7810_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = upd7810_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = upd7810_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = upd7810_init; break;
+ case CPUINFO_PTR_RESET: info->reset = upd7810_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = upd7810_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = upd7810_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = upd7810_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &upd7810_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "uPD7810"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "NEC uPD7810"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.3"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2001 Juergen Buchmueller, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%s:%s:%s:%s:%s:%s",
+ upd7810.psw & 0x40 ? "ZF":"--",
+ upd7810.psw & 0x20 ? "SK":"--",
+ upd7810.psw & 0x10 ? "HC":"--",
+ upd7810.psw & 0x08 ? "L1":"--",
+ upd7810.psw & 0x04 ? "L0":"--",
+ upd7810.psw & 0x01 ? "CY":"--");
+ break;
+
+ case CPUINFO_STR_REGISTER + UPD7810_PC: sprintf(info->s, "PC :%04X", upd7810.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_SP: sprintf(info->s, "SP :%04X", upd7810.sp.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_PSW: sprintf(info->s, "PSW :%02X", upd7810.psw); break;
+ case CPUINFO_STR_REGISTER + UPD7810_A: sprintf(info->s, "A :%02X", upd7810.va.b.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_V: sprintf(info->s, "V :%02X", upd7810.va.b.h); break;
+ case CPUINFO_STR_REGISTER + UPD7810_EA: sprintf(info->s, "EA :%04X", upd7810.ea.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_BC: sprintf(info->s, "BC :%04X", upd7810.bc.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_DE: sprintf(info->s, "DE :%04X", upd7810.de.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_HL: sprintf(info->s, "HL :%04X", upd7810.hl.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_A2: sprintf(info->s, "A' :%02X", upd7810.va2.b.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_V2: sprintf(info->s, "V' :%02X", upd7810.va2.b.h); break;
+ case CPUINFO_STR_REGISTER + UPD7810_EA2: sprintf(info->s, "EA' :%04X", upd7810.ea2.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_BC2: sprintf(info->s, "BC' :%04X", upd7810.bc2.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_DE2: sprintf(info->s, "DE' :%04X", upd7810.de2.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_HL2: sprintf(info->s, "HL' :%04X", upd7810.hl2.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_CNT0: sprintf(info->s, "CNT0:%02X", upd7810.cnt.b.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_CNT1: sprintf(info->s, "CNT1:%02X", upd7810.cnt.b.h); break;
+ case CPUINFO_STR_REGISTER + UPD7810_TM0: sprintf(info->s, "TM0 :%02X", upd7810.tm.b.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_TM1: sprintf(info->s, "TM1 :%02X", upd7810.tm.b.h); break;
+ case CPUINFO_STR_REGISTER + UPD7810_ECNT: sprintf(info->s, "ECNT:%04X", upd7810.ecnt.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_ECPT: sprintf(info->s, "ECPT:%04X", upd7810.ecnt.w.h); break;
+ case CPUINFO_STR_REGISTER + UPD7810_ETM0: sprintf(info->s, "ETM0:%04X", upd7810.etm.w.l); break;
+ case CPUINFO_STR_REGISTER + UPD7810_ETM1: sprintf(info->s, "ETM1:%04X", upd7810.etm.w.h); break;
+ case CPUINFO_STR_REGISTER + UPD7810_MA: sprintf(info->s, "MA :%02X", upd7810.ma); break;
+ case CPUINFO_STR_REGISTER + UPD7810_MB: sprintf(info->s, "MB :%02X", upd7810.mb); break;
+ case CPUINFO_STR_REGISTER + UPD7810_MCC: sprintf(info->s, "MCC :%02X", upd7810.mcc); break;
+ case CPUINFO_STR_REGISTER + UPD7810_MC: sprintf(info->s, "MC :%02X", upd7810.mc); break;
+ case CPUINFO_STR_REGISTER + UPD7810_MM: sprintf(info->s, "MM :%02X", upd7810.mm); break;
+ case CPUINFO_STR_REGISTER + UPD7810_MF: sprintf(info->s, "MF :%02X", upd7810.mf); break;
+ case CPUINFO_STR_REGISTER + UPD7810_TMM: sprintf(info->s, "TMM :%02X", upd7810.tmm); break;
+ case CPUINFO_STR_REGISTER + UPD7810_ETMM: sprintf(info->s, "ETMM:%02X", upd7810.etmm); break;
+ case CPUINFO_STR_REGISTER + UPD7810_EOM: sprintf(info->s, "EOM :%02X", upd7810.eom); break;
+ case CPUINFO_STR_REGISTER + UPD7810_SML: sprintf(info->s, "SML :%02X", upd7810.sml); break;
+ case CPUINFO_STR_REGISTER + UPD7810_SMH: sprintf(info->s, "SMH :%02X", upd7810.smh); break;
+ case CPUINFO_STR_REGISTER + UPD7810_ANM: sprintf(info->s, "ANM :%02X", upd7810.anm); break;
+ case CPUINFO_STR_REGISTER + UPD7810_MKL: sprintf(info->s, "MKL :%02X", upd7810.mkl); break;
+ case CPUINFO_STR_REGISTER + UPD7810_MKH: sprintf(info->s, "MKH :%02X", upd7810.mkh); break;
+ case CPUINFO_STR_REGISTER + UPD7810_ZCM: sprintf(info->s, "ZCM :%02X", upd7810.zcm); break;
+ case CPUINFO_STR_REGISTER + UPD7810_CR0: sprintf(info->s, "CR0 :%02X", upd7810.cr0); break;
+ case CPUINFO_STR_REGISTER + UPD7810_CR1: sprintf(info->s, "CR1 :%02X", upd7810.cr1); break;
+ case CPUINFO_STR_REGISTER + UPD7810_CR2: sprintf(info->s, "CR2 :%02X", upd7810.cr2); break;
+ case CPUINFO_STR_REGISTER + UPD7810_CR3: sprintf(info->s, "CR3 :%02X", upd7810.cr3); break;
+ case CPUINFO_STR_REGISTER + UPD7810_RXB: sprintf(info->s, "RXB :%02X", upd7810.rxb); break;
+ case CPUINFO_STR_REGISTER + UPD7810_TXB: sprintf(info->s, "TXB :%02X", upd7810.txb); break;
+ case CPUINFO_STR_REGISTER + UPD7810_TXD: sprintf(info->s, "TXD :%d", upd7810.txd); break;
+ case CPUINFO_STR_REGISTER + UPD7810_RXD: sprintf(info->s, "RXD :%d", upd7810.rxd); break;
+ case CPUINFO_STR_REGISTER + UPD7810_SCK: sprintf(info->s, "SCK :%d", upd7810.sck); break;
+ case CPUINFO_STR_REGISTER + UPD7810_TI: sprintf(info->s, "TI :%d", upd7810.ti); break;
+ case CPUINFO_STR_REGISTER + UPD7810_TO: sprintf(info->s, "TO :%d", upd7810.to); break;
+ case CPUINFO_STR_REGISTER + UPD7810_CI: sprintf(info->s, "CI :%d", upd7810.ci); break;
+ case CPUINFO_STR_REGISTER + UPD7810_CO0: sprintf(info->s, "CO0 :%d", upd7810.co0 & 1); break;
+ case CPUINFO_STR_REGISTER + UPD7810_CO1: sprintf(info->s, "CO1 :%d", upd7810.co1 & 1); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void upd7807_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_RESET: info->reset = upd7807_reset; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = upd7807_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "uPD7807"); break;
+
+ default: upd7810_get_info(state, info); break;
+ }
+}
diff --git a/src/emu/cpu/upd7810/upd7810.h b/src/emu/cpu/upd7810/upd7810.h
new file mode 100644
index 00000000000..bd68a1499b2
--- /dev/null
+++ b/src/emu/cpu/upd7810/upd7810.h
@@ -0,0 +1,157 @@
+#ifndef _UPD7810_H_
+#define _UPD7810_H_
+
+#include "cpuintrf.h"
+
+/*
+ all types have internal ram at 0xff00-0xffff
+ 7810
+ 7811 (4kbyte),7812(8),7814(16) have internal rom at 0x0000
+*/
+
+// unfortunatly memory configuration differs with internal rom size
+typedef enum {
+ TYPE_7810,
+ TYPE_7810_GAMEMASTER, // a few modifications until internal rom dumped
+ TYPE_7807
+// TYPE_78C10, // stop instruction added
+// TYPE_78IV,
+// TYPE_78K0,
+// TYPE_78K0S
+// millions of subtypes
+} UPD7810_TYPE;
+
+/* Supply an instance of this function in your driver code:
+ * It will be called whenever an output signal changes or a new
+ * input line state is to be sampled.
+ */
+typedef int (*upd7810_io_callback)(int ioline, int state);
+
+// use it as reset parameter in the Machine struct
+typedef struct {
+ UPD7810_TYPE type;
+ upd7810_io_callback io_callback;
+} UPD7810_CONFIG;
+
+enum {
+ UPD7810_PC=1, UPD7810_SP, UPD7810_PSW,
+ UPD7810_EA, UPD7810_V, UPD7810_A, UPD7810_VA,
+ UPD7810_BC, UPD7810_B, UPD7810_C, UPD7810_DE, UPD7810_D, UPD7810_E, UPD7810_HL, UPD7810_H, UPD7810_L,
+ UPD7810_EA2, UPD7810_V2, UPD7810_A2, UPD7810_VA2,
+ UPD7810_BC2, UPD7810_B2, UPD7810_C2, UPD7810_DE2, UPD7810_D2, UPD7810_E2, UPD7810_HL2, UPD7810_H2, UPD7810_L2,
+ UPD7810_CNT0, UPD7810_CNT1, UPD7810_TM0, UPD7810_TM1, UPD7810_ECNT, UPD7810_ECPT, UPD7810_ETM0, UPD7810_ETM1,
+ UPD7810_MA, UPD7810_MB, UPD7810_MCC, UPD7810_MC, UPD7810_MM, UPD7810_MF,
+ UPD7810_TMM, UPD7810_ETMM, UPD7810_EOM, UPD7810_SML, UPD7810_SMH,
+ UPD7810_ANM, UPD7810_MKL, UPD7810_MKH, UPD7810_ZCM,
+ UPD7810_TXB, UPD7810_RXB, UPD7810_CR0, UPD7810_CR1, UPD7810_CR2, UPD7810_CR3,
+ UPD7810_TXD, UPD7810_RXD, UPD7810_SCK, UPD7810_TI, UPD7810_TO, UPD7810_CI, UPD7810_CO0, UPD7810_CO1
+};
+
+/* port numbers for PA,PB,PC,PD and PF */
+enum {
+ UPD7810_PORTA, UPD7810_PORTB, UPD7810_PORTC, UPD7810_PORTD, UPD7810_PORTF
+};
+
+enum {
+ UPD7807_PORTA, UPD7807_PORTB, UPD7807_PORTC, UPD7807_PORTD, UPD7807_PORTF,
+ UPD7807_PORTT
+};
+
+/* IRQ lines */
+#define UPD7810_INTF1 0
+#define UPD7810_INTF2 1
+#define UPD7810_INTFE1 4
+
+extern void upd7810_get_info(UINT32 state, cpuinfo *info);
+extern void upd7807_get_info(UINT32 state, cpuinfo *info);
+
+typedef struct {
+ PAIR ppc; /* previous program counter */
+ PAIR pc; /* program counter */
+ PAIR sp; /* stack pointer */
+ UINT8 op; /* opcode */
+ UINT8 op2; /* opcode part 2 */
+ UINT8 iff; /* interrupt enable flip flop */
+ UINT8 psw; /* processor status word */
+ PAIR ea; /* extended accumulator */
+ PAIR va; /* accumulator + vector register */
+ PAIR bc; /* 8bit B and C registers / 16bit BC register */
+ PAIR de; /* 8bit D and E registers / 16bit DE register */
+ PAIR hl; /* 8bit H and L registers / 16bit HL register */
+ PAIR ea2; /* alternate register set */
+ PAIR va2;
+ PAIR bc2;
+ PAIR de2;
+ PAIR hl2;
+ PAIR cnt; /* 8 bit timer counter */
+ PAIR tm; /* 8 bit timer 0/1 comparator inputs */
+ PAIR ecnt; /* timer counter register / capture register */
+ PAIR etm; /* timer 0/1 comparator inputs */
+ UINT8 ma; /* port A input or output mask */
+ UINT8 mb; /* port B input or output mask */
+ UINT8 mcc; /* port C control/port select */
+ UINT8 mc; /* port C input or output mask */
+ UINT8 mm; /* memory mapping */
+ UINT8 mf; /* port F input or output mask */
+ UINT8 tmm; /* timer 0 and timer 1 operating parameters */
+ UINT8 etmm; /* 16-bit multifunction timer/event counter */
+ UINT8 eom; /* 16-bit timer/event counter output control */
+ UINT8 sml; /* serial interface parameters low */
+ UINT8 smh; /* -"- high */
+ UINT8 anm; /* analog to digital converter operating parameters */
+ UINT8 mkl; /* interrupt mask low */
+ UINT8 mkh; /* -"- high */
+ UINT8 zcm; /* bias circuitry for ac zero-cross detection */
+ UINT8 pa_in; /* port A,B,C,D,F inputs */
+ UINT8 pb_in;
+ UINT8 pc_in;
+ UINT8 pd_in;
+ UINT8 pf_in;
+ UINT8 pa_out; /* port A,B,C,D,F outputs */
+ UINT8 pb_out;
+ UINT8 pc_out;
+ UINT8 pd_out;
+ UINT8 pf_out;
+ UINT8 cr0; /* analog digital conversion register 0 */
+ UINT8 cr1; /* analog digital conversion register 1 */
+ UINT8 cr2; /* analog digital conversion register 2 */
+ UINT8 cr3; /* analog digital conversion register 3 */
+ UINT8 txb; /* transmitter buffer */
+ UINT8 rxb; /* receiver buffer */
+ UINT8 txd; /* port C control line states */
+ UINT8 rxd;
+ UINT8 sck;
+ UINT8 ti;
+ UINT8 to;
+ UINT8 ci;
+ UINT8 co0;
+ UINT8 co1;
+ UINT16 irr; /* interrupt request register */
+ UINT16 itf; /* interrupt test flag register */
+
+/* internal helper variables */
+ UINT16 txs; /* transmitter shift register */
+ UINT16 rxs; /* receiver shift register */
+ UINT8 txcnt; /* transmitter shift register bit count */
+ UINT8 rxcnt; /* receiver shift register bit count */
+ UINT8 txbuf; /* transmitter buffer was written */
+ INT32 ovc0; /* overflow counter for timer 0 (for clock div 12/384) */
+ INT32 ovc1; /* overflow counter for timer 0 (for clock div 12/384) */
+ INT32 ovce; /* overflow counter for ecnt */
+ INT32 ovcf; /* overflow counter for fixed clock div 3 mode */
+ INT32 ovcs; /* overflow counter for serial I/O */
+ UINT8 edges; /* rising/falling edge flag for serial I/O */
+ const struct opcode_s *opXX; /* opcode table */
+ const struct opcode_s *op48;
+ const struct opcode_s *op4C;
+ UPD7810_CONFIG config;
+ int (*irq_callback)(int irqline);
+} UPD7810;
+
+#ifdef MAME_DEBUG
+offs_t upd7810_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t upd7807_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif
+
diff --git a/src/emu/cpu/v30mz/necea.h b/src/emu/cpu/v30mz/necea.h
new file mode 100644
index 00000000000..12fb93f3fee
--- /dev/null
+++ b/src/emu/cpu/v30mz/necea.h
@@ -0,0 +1,60 @@
+
+static UINT32 EA;
+static UINT16 EO;
+static UINT16 E16;
+
+static unsigned EA_000(void) { EO=I.regs.w[BW]+I.regs.w[IX]; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_001(void) { EO=I.regs.w[BW]+I.regs.w[IY]; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_002(void) { EO=I.regs.w[BP]+I.regs.w[IX]; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_003(void) { EO=I.regs.w[BP]+I.regs.w[IY]; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_004(void) { EO=I.regs.w[IX]; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_005(void) { EO=I.regs.w[IY]; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_006(void) { EO=FETCH; EO+=FETCH<<8; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_007(void) { EO=I.regs.w[BW]; EA=DefaultBase(DS)+EO; return EA; }
+
+static unsigned EA_100(void) { EO=(I.regs.w[BW]+I.regs.w[IX]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_101(void) { EO=(I.regs.w[BW]+I.regs.w[IY]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_102(void) { EO=(I.regs.w[BP]+I.regs.w[IX]+(INT8)FETCH); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_103(void) { EO=(I.regs.w[BP]+I.regs.w[IY]+(INT8)FETCH); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_104(void) { EO=(I.regs.w[IX]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_105(void) { EO=(I.regs.w[IY]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_106(void) { EO=(I.regs.w[BP]+(INT8)FETCH); EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_107(void) { EO=(I.regs.w[BW]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; }
+
+static unsigned EA_200(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+I.regs.w[IX]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_201(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+I.regs.w[IY]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_202(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+I.regs.w[IX]+(INT16)E16; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_203(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+I.regs.w[IY]+(INT16)E16; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_204(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[IX]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_205(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[IY]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; }
+static unsigned EA_206(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+(INT16)E16; EA=DefaultBase(SS)+EO; return EA; }
+static unsigned EA_207(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; }
+
+static unsigned (*GetEA[192])(void)={
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+ EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007,
+
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+ EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107,
+
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207,
+ EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207
+};
diff --git a/src/emu/cpu/v30mz/nechost.h b/src/emu/cpu/v30mz/nechost.h
new file mode 100644
index 00000000000..a2b5f44a03d
--- /dev/null
+++ b/src/emu/cpu/v30mz/nechost.h
@@ -0,0 +1,12 @@
+/*****************************************************************************/
+/* host dependent types */
+
+#define BIGCASE
+
+#include "mamecore.h"
+
+typedef char BOOLEAN;
+
+typedef UINT8 BYTE;
+typedef UINT16 WORD;
+typedef UINT32 DWORD;
diff --git a/src/emu/cpu/v30mz/necinstr.h b/src/emu/cpu/v30mz/necinstr.h
new file mode 100644
index 00000000000..f07fe442c0c
--- /dev/null
+++ b/src/emu/cpu/v30mz/necinstr.h
@@ -0,0 +1,507 @@
+static void i_add_br8(void);
+static void i_add_wr16(void);
+static void i_add_r8b(void);
+static void i_add_r16w(void);
+static void i_add_ald8(void);
+static void i_add_axd16(void);
+static void i_push_es(void);
+static void i_pop_es(void);
+static void i_or_br8(void);
+static void i_or_r8b(void);
+static void i_or_wr16(void);
+static void i_or_r16w(void);
+static void i_or_ald8(void);
+static void i_or_axd16(void);
+static void i_push_cs(void);
+static void i_pre_nec(void);
+static void i_adc_br8(void);
+static void i_adc_wr16(void);
+static void i_adc_r8b(void);
+static void i_adc_r16w(void);
+static void i_adc_ald8(void);
+static void i_adc_axd16(void);
+static void i_push_ss(void);
+static void i_pop_ss(void);
+static void i_sbb_br8(void);
+static void i_sbb_wr16(void);
+static void i_sbb_r8b(void);
+static void i_sbb_r16w(void);
+static void i_sbb_ald8(void);
+static void i_sbb_axd16(void);
+static void i_push_ds(void);
+static void i_pop_ds(void);
+static void i_and_br8(void);
+static void i_and_r8b(void);
+static void i_and_wr16(void);
+static void i_and_r16w(void);
+static void i_and_ald8(void);
+static void i_and_axd16(void);
+static void i_es(void);
+static void i_daa(void);
+static void i_sub_br8(void);
+static void i_sub_wr16(void);
+static void i_sub_r8b(void);
+static void i_sub_r16w(void);
+static void i_sub_ald8(void);
+static void i_sub_axd16(void);
+static void i_cs(void);
+static void i_das(void);
+static void i_xor_br8(void);
+static void i_xor_r8b(void);
+static void i_xor_wr16(void);
+static void i_xor_r16w(void);
+static void i_xor_ald8(void);
+static void i_xor_axd16(void);
+static void i_ss(void);
+static void i_aaa(void);
+static void i_cmp_br8(void);
+static void i_cmp_wr16(void);
+static void i_cmp_r8b(void);
+static void i_cmp_r16w(void);
+static void i_cmp_ald8(void);
+static void i_cmp_axd16(void);
+static void i_ds(void);
+static void i_aas(void);
+static void i_inc_ax(void);
+static void i_inc_cx(void);
+static void i_inc_dx(void);
+static void i_inc_bx(void);
+static void i_inc_sp(void);
+static void i_inc_bp(void);
+static void i_inc_si(void);
+static void i_inc_di(void);
+static void i_dec_ax(void);
+static void i_dec_cx(void);
+static void i_dec_dx(void);
+static void i_dec_bx(void);
+static void i_dec_sp(void);
+static void i_dec_bp(void);
+static void i_dec_si(void);
+static void i_dec_di(void);
+static void i_push_ax(void);
+static void i_push_cx(void);
+static void i_push_dx(void);
+static void i_push_bx(void);
+static void i_push_sp(void);
+static void i_push_bp(void);
+static void i_push_si(void);
+static void i_push_di(void);
+static void i_pop_ax(void);
+static void i_pop_cx(void);
+static void i_pop_dx(void);
+static void i_pop_bx(void);
+static void i_pop_sp(void);
+static void i_pop_bp(void);
+static void i_pop_si(void);
+static void i_pop_di(void);
+static void i_pusha(void);
+static void i_popa(void);
+static void i_chkind(void);
+static void i_repnc(void);
+static void i_repc(void);
+static void i_push_d16(void);
+static void i_imul_d16(void);
+static void i_push_d8(void);
+static void i_imul_d8(void);
+static void i_insb(void);
+static void i_insw(void);
+static void i_outsb(void);
+static void i_outsw(void);
+static void i_jo(void);
+static void i_jno(void);
+static void i_jc(void);
+static void i_jnc(void);
+static void i_jz(void);
+static void i_jnz(void);
+static void i_jce(void);
+static void i_jnce(void);
+static void i_js(void);
+static void i_jns(void);
+static void i_jp(void);
+static void i_jnp(void);
+static void i_jl(void);
+static void i_jnl(void);
+static void i_jle(void);
+static void i_jnle(void);
+static void i_80pre(void);
+static void i_82pre(void);
+static void i_81pre(void);
+static void i_83pre(void);
+static void i_test_br8(void);
+static void i_test_wr16(void);
+static void i_xchg_br8(void);
+static void i_xchg_wr16(void);
+static void i_mov_br8(void);
+static void i_mov_r8b(void);
+static void i_mov_wr16(void);
+static void i_mov_r16w(void);
+static void i_mov_wsreg(void);
+static void i_lea(void);
+static void i_mov_sregw(void);
+static void i_invalid(void);
+static void i_popw(void);
+static void i_nop(void);
+static void i_xchg_axcx(void);
+static void i_xchg_axdx(void);
+static void i_xchg_axbx(void);
+static void i_xchg_axsp(void);
+static void i_xchg_axbp(void);
+static void i_xchg_axsi(void);
+static void i_xchg_axdi(void);
+static void i_cbw(void);
+static void i_cwd(void);
+static void i_call_far(void);
+static void i_pushf(void);
+static void i_popf(void);
+static void i_sahf(void);
+static void i_lahf(void);
+static void i_mov_aldisp(void);
+static void i_mov_axdisp(void);
+static void i_mov_dispal(void);
+static void i_mov_dispax(void);
+static void i_movsb(void);
+static void i_movsw(void);
+static void i_cmpsb(void);
+static void i_cmpsw(void);
+static void i_test_ald8(void);
+static void i_test_axd16(void);
+static void i_stosb(void);
+static void i_stosw(void);
+static void i_lodsb(void);
+static void i_lodsw(void);
+static void i_scasb(void);
+static void i_scasw(void);
+static void i_mov_ald8(void);
+static void i_mov_cld8(void);
+static void i_mov_dld8(void);
+static void i_mov_bld8(void);
+static void i_mov_ahd8(void);
+static void i_mov_chd8(void);
+static void i_mov_dhd8(void);
+static void i_mov_bhd8(void);
+static void i_mov_axd16(void);
+static void i_mov_cxd16(void);
+static void i_mov_dxd16(void);
+static void i_mov_bxd16(void);
+static void i_mov_spd16(void);
+static void i_mov_bpd16(void);
+static void i_mov_sid16(void);
+static void i_mov_did16(void);
+static void i_rotshft_bd8(void);
+static void i_rotshft_wd8(void);
+static void i_ret_d16(void);
+static void i_ret(void);
+static void i_les_dw(void);
+static void i_lds_dw(void);
+static void i_mov_bd8(void);
+static void i_mov_wd16(void);
+static void i_enter(void);
+static void i_leave(void);
+static void i_retf_d16(void);
+static void i_retf(void);
+static void i_int3(void);
+static void i_int(void);
+static void i_into(void);
+static void i_iret(void);
+static void i_rotshft_b(void);
+static void i_rotshft_w(void);
+static void i_rotshft_bcl(void);
+static void i_rotshft_wcl(void);
+static void i_aam(void);
+static void i_aad(void);
+static void i_setalc(void);
+static void i_trans(void);
+static void i_fpo(void);
+static void i_loopne(void);
+static void i_loope(void);
+static void i_loop(void);
+static void i_jcxz(void);
+static void i_inal(void);
+static void i_inax(void);
+static void i_outal(void);
+static void i_outax(void);
+static void i_call_d16(void);
+static void i_jmp_d16(void);
+static void i_jmp_far(void);
+static void i_jmp_d8(void);
+static void i_inaldx(void);
+static void i_inaxdx(void);
+static void i_outdxal(void);
+static void i_outdxax(void);
+static void i_lock(void);
+static void i_repne(void);
+static void i_repe(void);
+static void i_hlt(void);
+static void i_cmc(void);
+static void i_f6pre(void);
+static void i_f7pre(void);
+static void i_clc(void);
+static void i_stc(void);
+static void i_di(void);
+static void i_ei(void);
+static void i_cld(void);
+static void i_std(void);
+static void i_fepre(void);
+static void i_ffpre(void);
+
+static void i_wait(void);
+
+static void (*nec_instruction[256])(void) =
+{
+ i_add_br8, /* 0x00 */
+ i_add_wr16, /* 0x01 */
+ i_add_r8b, /* 0x02 */
+ i_add_r16w, /* 0x03 */
+ i_add_ald8, /* 0x04 */
+ i_add_axd16, /* 0x05 */
+ i_push_es, /* 0x06 */
+ i_pop_es, /* 0x07 */
+ i_or_br8, /* 0x08 */
+ i_or_wr16, /* 0x09 */
+ i_or_r8b, /* 0x0a */
+ i_or_r16w, /* 0x0b */
+ i_or_ald8, /* 0x0c */
+ i_or_axd16, /* 0x0d */
+ i_push_cs, /* 0x0e */
+ i_pre_nec /* 0x0f */,
+ i_adc_br8, /* 0x10 */
+ i_adc_wr16, /* 0x11 */
+ i_adc_r8b, /* 0x12 */
+ i_adc_r16w, /* 0x13 */
+ i_adc_ald8, /* 0x14 */
+ i_adc_axd16, /* 0x15 */
+ i_push_ss, /* 0x16 */
+ i_pop_ss, /* 0x17 */
+ i_sbb_br8, /* 0x18 */
+ i_sbb_wr16, /* 0x19 */
+ i_sbb_r8b, /* 0x1a */
+ i_sbb_r16w, /* 0x1b */
+ i_sbb_ald8, /* 0x1c */
+ i_sbb_axd16, /* 0x1d */
+ i_push_ds, /* 0x1e */
+ i_pop_ds, /* 0x1f */
+ i_and_br8, /* 0x20 */
+ i_and_wr16, /* 0x21 */
+ i_and_r8b, /* 0x22 */
+ i_and_r16w, /* 0x23 */
+ i_and_ald8, /* 0x24 */
+ i_and_axd16, /* 0x25 */
+ i_es, /* 0x26 */
+ i_daa, /* 0x27 */
+ i_sub_br8, /* 0x28 */
+ i_sub_wr16, /* 0x29 */
+ i_sub_r8b, /* 0x2a */
+ i_sub_r16w, /* 0x2b */
+ i_sub_ald8, /* 0x2c */
+ i_sub_axd16, /* 0x2d */
+ i_cs, /* 0x2e */
+ i_das, /* 0x2f */
+ i_xor_br8, /* 0x30 */
+ i_xor_wr16, /* 0x31 */
+ i_xor_r8b, /* 0x32 */
+ i_xor_r16w, /* 0x33 */
+ i_xor_ald8, /* 0x34 */
+ i_xor_axd16, /* 0x35 */
+ i_ss, /* 0x36 */
+ i_aaa, /* 0x37 */
+ i_cmp_br8, /* 0x38 */
+ i_cmp_wr16, /* 0x39 */
+ i_cmp_r8b, /* 0x3a */
+ i_cmp_r16w, /* 0x3b */
+ i_cmp_ald8, /* 0x3c */
+ i_cmp_axd16, /* 0x3d */
+ i_ds, /* 0x3e */
+ i_aas, /* 0x3f */
+ i_inc_ax, /* 0x40 */
+ i_inc_cx, /* 0x41 */
+ i_inc_dx, /* 0x42 */
+ i_inc_bx, /* 0x43 */
+ i_inc_sp, /* 0x44 */
+ i_inc_bp, /* 0x45 */
+ i_inc_si, /* 0x46 */
+ i_inc_di, /* 0x47 */
+ i_dec_ax, /* 0x48 */
+ i_dec_cx, /* 0x49 */
+ i_dec_dx, /* 0x4a */
+ i_dec_bx, /* 0x4b */
+ i_dec_sp, /* 0x4c */
+ i_dec_bp, /* 0x4d */
+ i_dec_si, /* 0x4e */
+ i_dec_di, /* 0x4f */
+ i_push_ax, /* 0x50 */
+ i_push_cx, /* 0x51 */
+ i_push_dx, /* 0x52 */
+ i_push_bx, /* 0x53 */
+ i_push_sp, /* 0x54 */
+ i_push_bp, /* 0x55 */
+ i_push_si, /* 0x56 */
+ i_push_di, /* 0x57 */
+ i_pop_ax, /* 0x58 */
+ i_pop_cx, /* 0x59 */
+ i_pop_dx, /* 0x5a */
+ i_pop_bx, /* 0x5b */
+ i_pop_sp, /* 0x5c */
+ i_pop_bp, /* 0x5d */
+ i_pop_si, /* 0x5e */
+ i_pop_di, /* 0x5f */
+ i_pusha, /* 0x60 */
+ i_popa, /* 0x61 */
+ i_chkind, /* 0x62 */
+ i_invalid, /* 0x63 */
+ i_repnc, /* 0x64 */
+ i_repc, /* 0x65 */
+ i_invalid, /* 0x66 */
+ i_invalid, /* 0x67 */
+ i_push_d16, /* 0x68 */
+ i_imul_d16, /* 0x69 */
+ i_push_d8, /* 0x6a */
+ i_imul_d8, /* 0x6b */
+ i_insb, /* 0x6c */
+ i_insw, /* 0x6d */
+ i_outsb, /* 0x6e */
+ i_outsw, /* 0x6f */
+ i_jo, /* 0x70 */
+ i_jno, /* 0x71 */
+ i_jc, /* 0x72 */
+ i_jnc, /* 0x73 */
+ i_jz, /* 0x74 */
+ i_jnz, /* 0x75 */
+ i_jce, /* 0x76 */
+ i_jnce, /* 0x77 */
+ i_js, /* 0x78 */
+ i_jns, /* 0x79 */
+ i_jp, /* 0x7a */
+ i_jnp, /* 0x7b */
+ i_jl, /* 0x7c */
+ i_jnl, /* 0x7d */
+ i_jle, /* 0x7e */
+ i_jnle, /* 0x7f */
+ i_80pre, /* 0x80 */
+ i_81pre, /* 0x81 */
+ i_82pre, /* 0x82 */
+ i_83pre, /* 0x83 */
+ i_test_br8, /* 0x84 */
+ i_test_wr16, /* 0x85 */
+ i_xchg_br8, /* 0x86 */
+ i_xchg_wr16, /* 0x87 */
+ i_mov_br8, /* 0x88 */
+ i_mov_wr16, /* 0x89 */
+ i_mov_r8b, /* 0x8a */
+ i_mov_r16w, /* 0x8b */
+ i_mov_wsreg, /* 0x8c */
+ i_lea, /* 0x8d */
+ i_mov_sregw, /* 0x8e */
+ i_popw, /* 0x8f */
+ i_nop, /* 0x90 */
+ i_xchg_axcx, /* 0x91 */
+ i_xchg_axdx, /* 0x92 */
+ i_xchg_axbx, /* 0x93 */
+ i_xchg_axsp, /* 0x94 */
+ i_xchg_axbp, /* 0x95 */
+ i_xchg_axsi, /* 0x97 */
+ i_xchg_axdi, /* 0x97 */
+ i_cbw, /* 0x98 */
+ i_cwd, /* 0x99 */
+ i_call_far, /* 0x9a */
+ i_wait, /* 0x9b */
+ i_pushf, /* 0x9c */
+ i_popf, /* 0x9d */
+ i_sahf, /* 0x9e */
+ i_lahf, /* 0x9f */
+ i_mov_aldisp, /* 0xa0 */
+ i_mov_axdisp, /* 0xa1 */
+ i_mov_dispal, /* 0xa2 */
+ i_mov_dispax, /* 0xa3 */
+ i_movsb, /* 0xa4 */
+ i_movsw, /* 0xa5 */
+ i_cmpsb, /* 0xa6 */
+ i_cmpsw, /* 0xa7 */
+ i_test_ald8, /* 0xa8 */
+ i_test_axd16, /* 0xa9 */
+ i_stosb, /* 0xaa */
+ i_stosw, /* 0xab */
+ i_lodsb, /* 0xac */
+ i_lodsw, /* 0xad */
+ i_scasb, /* 0xae */
+ i_scasw, /* 0xaf */
+ i_mov_ald8, /* 0xb0 */
+ i_mov_cld8, /* 0xb1 */
+ i_mov_dld8, /* 0xb2 */
+ i_mov_bld8, /* 0xb3 */
+ i_mov_ahd8, /* 0xb4 */
+ i_mov_chd8, /* 0xb5 */
+ i_mov_dhd8, /* 0xb6 */
+ i_mov_bhd8, /* 0xb7 */
+ i_mov_axd16, /* 0xb8 */
+ i_mov_cxd16, /* 0xb9 */
+ i_mov_dxd16, /* 0xba */
+ i_mov_bxd16, /* 0xbb */
+ i_mov_spd16, /* 0xbc */
+ i_mov_bpd16, /* 0xbd */
+ i_mov_sid16, /* 0xbe */
+ i_mov_did16, /* 0xbf */
+ i_rotshft_bd8, /* 0xc0 */
+ i_rotshft_wd8, /* 0xc1 */
+ i_ret_d16, /* 0xc2 */
+ i_ret, /* 0xc3 */
+ i_les_dw, /* 0xc4 */
+ i_lds_dw, /* 0xc5 */
+ i_mov_bd8, /* 0xc6 */
+ i_mov_wd16, /* 0xc7 */
+ i_enter, /* 0xc8 */
+ i_leave, /* 0xc9 */
+ i_retf_d16, /* 0xca */
+ i_retf, /* 0xcb */
+ i_int3, /* 0xcc */
+ i_int, /* 0xcd */
+ i_into, /* 0xce */
+ i_iret, /* 0xcf */
+ i_rotshft_b, /* 0xd0 */
+ i_rotshft_w, /* 0xd1 */
+ i_rotshft_bcl, /* 0xd2 */
+ i_rotshft_wcl, /* 0xd3 */
+ i_aam, /* 0xd4 */
+ i_aad, /* 0xd5 */
+ i_setalc,
+ i_trans, /* 0xd7 */
+ i_fpo, /* 0xd8 */
+ i_fpo, /* 0xd9 */
+ i_fpo, /* 0xda */
+ i_fpo, /* 0xdb */
+ i_fpo, /* 0xdc */
+ i_fpo, /* 0xdd */
+ i_fpo, /* 0xde */
+ i_fpo, /* 0xdf */
+ i_loopne, /* 0xe0 */
+ i_loope, /* 0xe1 */
+ i_loop, /* 0xe2 */
+ i_jcxz, /* 0xe3 */
+ i_inal, /* 0xe4 */
+ i_inax, /* 0xe5 */
+ i_outal, /* 0xe6 */
+ i_outax, /* 0xe7 */
+ i_call_d16, /* 0xe8 */
+ i_jmp_d16, /* 0xe9 */
+ i_jmp_far, /* 0xea */
+ i_jmp_d8, /* 0xeb */
+ i_inaldx, /* 0xec */
+ i_inaxdx, /* 0xed */
+ i_outdxal, /* 0xee */
+ i_outdxax, /* 0xef */
+ i_lock, /* 0xf0 */
+ i_invalid, /* 0xf1 */
+ i_repne, /* 0xf2 */
+ i_repe, /* 0xf3 */
+ i_hlt, /* 0xf4 */
+ i_cmc, /* 0xf5 */
+ i_f6pre, /* 0xf6 */
+ i_f7pre, /* 0xf7 */
+ i_clc, /* 0xf8 */
+ i_stc, /* 0xf9 */
+ i_di, /* 0xfa */
+ i_ei, /* 0xfb */
+ i_cld, /* 0xfc */
+ i_std, /* 0xfd */
+ i_fepre, /* 0xfe */
+ i_ffpre /* 0xff */
+};
diff --git a/src/emu/cpu/v30mz/necintrf.h b/src/emu/cpu/v30mz/necintrf.h
new file mode 100644
index 00000000000..33650b9f716
--- /dev/null
+++ b/src/emu/cpu/v30mz/necintrf.h
@@ -0,0 +1,16 @@
+/* ASG 971222 -- rewrote this interface */
+#ifndef __NEC_H_
+#define __NEC_H_
+
+#include "cpuintrf.h"
+
+enum {
+ NEC_PC=0,
+ NEC_IP, NEC_AW, NEC_CW, NEC_DW, NEC_BW, NEC_SP, NEC_BP, NEC_IX, NEC_IY,
+ NEC_FLAGS, NEC_ES, NEC_CS, NEC_SS, NEC_DS,
+ NEC_VECTOR, NEC_PENDING };
+
+/* Public functions */
+extern void v30mz_get_info(UINT32 state, cpuinfo *info);
+
+#endif
diff --git a/src/emu/cpu/v30mz/necmodrm.h b/src/emu/cpu/v30mz/necmodrm.h
new file mode 100644
index 00000000000..9cfd59dc246
--- /dev/null
+++ b/src/emu/cpu/v30mz/necmodrm.h
@@ -0,0 +1,104 @@
+static struct {
+ struct {
+ WREGS w[256];
+ BREGS b[256];
+ } reg;
+ struct {
+ WREGS w[256];
+ BREGS b[256];
+ } RM;
+} Mod_RM;
+
+#define RegWord(ModRM) I.regs.w[Mod_RM.reg.w[ModRM]]
+#define RegByte(ModRM) I.regs.b[Mod_RM.reg.b[ModRM]]
+
+#define GetRMWord(ModRM) \
+ ((ModRM) >= 0xc0 ? I.regs.w[Mod_RM.RM.w[ModRM]] : ( (*GetEA[ModRM])(), ReadWord( EA ) ))
+
+#define PutbackRMWord(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) I.regs.w[Mod_RM.RM.w[ModRM]]=val; \
+ else WriteWord(EA,val); \
+}
+
+#define GetnextRMWord ReadWord((EA&0xf0000)|((EA+2)&0xffff))
+
+#define PutRMWord(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.w[Mod_RM.RM.w[ModRM]]=val; \
+ else { \
+ (*GetEA[ModRM])(); \
+ WriteWord( EA ,val); \
+ } \
+}
+
+#define PutImmRMWord(ModRM) \
+{ \
+ WORD val; \
+ if (ModRM >= 0xc0) \
+ FETCHWORD(I.regs.w[Mod_RM.RM.w[ModRM]]) \
+ else { \
+ (*GetEA[ModRM])(); \
+ FETCHWORD(val) \
+ WriteWord( EA , val); \
+ } \
+}
+
+#define GetRMByte(ModRM) \
+ ((ModRM) >= 0xc0 ? I.regs.b[Mod_RM.RM.b[ModRM]] : ReadByte( (*GetEA[ModRM])() ))
+
+#define PutRMByte(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.b[Mod_RM.RM.b[ModRM]]=val; \
+ else \
+ WriteByte( (*GetEA[ModRM])() ,val); \
+}
+
+#define PutImmRMByte(ModRM) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.b[Mod_RM.RM.b[ModRM]]=FETCH; \
+ else { \
+ (*GetEA[ModRM])(); \
+ WriteByte( EA , FETCH ); \
+ } \
+}
+
+#define PutbackRMByte(ModRM,val) \
+{ \
+ if (ModRM >= 0xc0) \
+ I.regs.b[Mod_RM.RM.b[ModRM]]=val; \
+ else \
+ WriteByte(EA,val); \
+}
+
+#define DEF_br8 \
+ UINT32 ModRM = FETCH,src,dst; \
+ src = RegByte(ModRM); \
+ dst = GetRMByte(ModRM)
+
+#define DEF_wr16 \
+ UINT32 ModRM = FETCH,src,dst; \
+ src = RegWord(ModRM); \
+ dst = GetRMWord(ModRM)
+
+#define DEF_r8b \
+ UINT32 ModRM = FETCH,src,dst; \
+ dst = RegByte(ModRM); \
+ src = GetRMByte(ModRM)
+
+#define DEF_r16w \
+ UINT32 ModRM = FETCH,src,dst; \
+ dst = RegWord(ModRM); \
+ src = GetRMWord(ModRM)
+
+#define DEF_ald8 \
+ UINT32 src = FETCH; \
+ UINT32 dst = I.regs.b[AL]
+
+#define DEF_axd16 \
+ UINT32 src = FETCH; \
+ UINT32 dst = I.regs.w[AW]; \
+ src += (FETCH << 8)
diff --git a/src/emu/cpu/v30mz/v30mz.c b/src/emu/cpu/v30mz/v30mz.c
new file mode 100644
index 00000000000..940e50d20b1
--- /dev/null
+++ b/src/emu/cpu/v30mz/v30mz.c
@@ -0,0 +1,1158 @@
+/****************************************************************************
+
+ NEC V20/V30/V33 emulator modified to a v30mz emulator
+
+ (Re)Written June-September 2000 by Bryan McPhail (mish@tendril.co.uk) based
+ on code by Oliver Bergmann (Raul_Bloodworth@hotmail.com) who based code
+ on the i286 emulator by Fabrice Frances which had initial work based on
+ David Hedley's pcemu(!).
+
+ This new core features 99% accurate cycle counts for each processor,
+ there are still some complex situations where cycle counts are wrong,
+ typically where a few instructions have differing counts for odd/even
+ source and odd/even destination memory operands.
+
+ Flag settings are also correct for the NEC processors rather than the
+ I86 versions.
+
+ Changelist:
+
+ 22/02/2003:
+ Removed cycle counts from memory accesses - they are certainly wrong,
+ and there is already a memory access cycle penalty in the opcodes
+ using them.
+
+ Fixed save states.
+
+ Fixed ADJBA/ADJBS/ADJ4A/ADJ4S flags/return values for all situations.
+ (Fixes bugs in Geostorm and Thunderblaster)
+
+ Fixed carry flag on NEG (I thought this had been fixed circa Mame 0.58,
+ but it seems I never actually submitted the fix).
+
+ Fixed many cycle counts in instructions and bug in cycle count
+ macros (odd word cases were testing for odd instruction word address
+ not data address).
+
+ Todo!
+ Double check cycle timing is 100%.
+ Fix memory interface (should be 16 bit).
+
+****************************************************************************/
+
+#include "debugger.h"
+
+typedef UINT8 BOOLEAN;
+typedef UINT8 BYTE;
+typedef UINT16 WORD;
+typedef UINT32 DWORD;
+
+#include "v30mz.h"
+#include "necintrf.h"
+
+extern int necv_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom);
+
+/* NEC registers */
+typedef union
+{ /* eight general registers */
+ UINT16 w[8]; /* viewed as 16 bits registers */
+ UINT8 b[16]; /* or as 8 bit registers */
+} necbasicregs;
+
+typedef struct
+{
+ necbasicregs regs;
+ UINT16 sregs[4];
+
+ UINT16 ip;
+
+ INT32 SignVal;
+ UINT32 AuxVal, OverVal, ZeroVal, CarryVal, ParityVal; /* 0 or non-0 valued flags */
+ UINT8 TF, IF, DF, MF; /* 0 or 1 valued flags */ /* OB[19.07.99] added Mode Flag V30 */
+ UINT32 int_vector;
+ UINT32 pending_irq;
+ UINT32 nmi_state;
+ UINT32 irq_state;
+ UINT8 no_interrupt;
+
+ int (*irq_callback)(int irqline);
+} nec_Regs;
+
+/***************************************************************************/
+/* cpu state */
+/***************************************************************************/
+
+static int nec_ICount;
+
+static nec_Regs I;
+
+static UINT32 chip_type;
+static UINT32 prefix_base; /* base address of the latest prefix segment */
+static char seg_prefix; /* prefix segment indicator */
+
+
+/* The interrupt number of a pending external interrupt pending NMI is 2. */
+/* For INTR interrupts, the level is caught on the bus during an INTA cycle */
+
+#define INT_IRQ 0x01
+#define NMI_IRQ 0x02
+
+#include "necinstr.h"
+#include "necea.h"
+#include "necmodrm.h"
+
+static UINT8 parity_table[256];
+
+/***************************************************************************/
+
+static void nec_reset (void)
+{
+ unsigned int i,j,c;
+ static const BREGS reg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH };
+ int (*save_irqcallback)(int);
+
+ save_irqcallback = I.irq_callback;
+ memset( &I, 0, sizeof(I) );
+ I.irq_callback = save_irqcallback;
+
+ I.sregs[CS] = 0xffff;
+
+ CHANGE_PC;
+
+ for (i = 0;i < 256; i++)
+ {
+ for (j = i, c = 0; j > 0; j >>= 1)
+ if (j & 1) c++;
+ parity_table[i] = !(c & 1);
+ }
+
+ I.ZeroVal = I.ParityVal = 1;
+ SetMD(1); /* set the mode-flag = native mode */
+
+ for (i = 0; i < 256; i++)
+ {
+ Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3];
+ Mod_RM.reg.w[i] = (WREGS) ( (i & 0x38) >> 3) ;
+ }
+
+ for (i = 0xc0; i < 0x100; i++)
+ {
+ Mod_RM.RM.w[i] = (WREGS)( i & 7 );
+ Mod_RM.RM.b[i] = (BREGS)reg_name[i & 7];
+ }
+}
+
+static void nec_exit (void)
+{
+
+}
+
+static void nec_interrupt(unsigned int_num,BOOLEAN md_flag)
+{
+ UINT32 dest_seg, dest_off;
+
+ i_pushf();
+ I.TF = I.IF = 0;
+ if (md_flag) SetMD(0); /* clear Mode-flag = start 8080 emulation mode */
+
+ if (int_num == -1)
+ {
+ int_num = (*I.irq_callback)(0);
+
+ I.irq_state = CLEAR_LINE;
+ I.pending_irq &= ~INT_IRQ;
+ }
+
+ dest_off = ReadWord(int_num*4);
+ dest_seg = ReadWord(int_num*4+2);
+
+ PUSH(I.sregs[CS]);
+ PUSH(I.ip);
+ I.ip = (WORD)dest_off;
+ I.sregs[CS] = (WORD)dest_seg;
+ CHANGE_PC;
+}
+
+static void nec_trap(void)
+{
+ nec_instruction[FETCHOP]();
+ nec_interrupt(1,0);
+}
+
+static void external_int(void)
+{
+ if( I.pending_irq & NMI_IRQ )
+ {
+ nec_interrupt(NEC_NMI_INT_VECTOR,0);
+ I.pending_irq &= ~NMI_IRQ;
+ }
+ else if( I.pending_irq )
+ {
+ /* the actual vector is retrieved after pushing flags */
+ /* and clearing the IF */
+ nec_interrupt(-1,0);
+ }
+}
+
+/****************************************************************************/
+/* OPCODES */
+/****************************************************************************/
+
+#define OP(num,func_name) static void func_name(void)
+
+OP( 0x00, i_add_br8 ) { DEF_br8; ADDB; PutbackRMByte(ModRM,dst); CLKM(1,3); }
+OP( 0x01, i_add_wr16 ) { DEF_wr16; ADDW; PutbackRMWord(ModRM,dst); CLKM(1,3);}
+OP( 0x02, i_add_r8b ) { DEF_r8b; ADDB; RegByte(ModRM)=dst; CLKM(1,2); }
+OP( 0x03, i_add_r16w ) { DEF_r16w; ADDW; RegWord(ModRM)=dst; CLKM(1,2); }
+OP( 0x04, i_add_ald8 ) { DEF_ald8; ADDB; I.regs.b[AL]=dst; CLK(1); }
+OP( 0x05, i_add_axd16) { DEF_axd16; ADDW; I.regs.w[AW]=dst; CLK(1); }
+OP( 0x06, i_push_es ) { PUSH(I.sregs[ES]); CLK(2); }
+OP( 0x07, i_pop_es ) { POP(I.sregs[ES]); CLK(3); }
+
+OP( 0x08, i_or_br8 ) { DEF_br8; ORB; PutbackRMByte(ModRM,dst); CLKM(1,3); }
+OP( 0x09, i_or_wr16 ) { DEF_wr16; ORW; PutbackRMWord(ModRM,dst); CLKM(1,3);}
+OP( 0x0a, i_or_r8b ) { DEF_r8b; ORB; RegByte(ModRM)=dst; CLKM(1,2); }
+OP( 0x0b, i_or_r16w ) { DEF_r16w; ORW; RegWord(ModRM)=dst; CLKM(1,2); }
+OP( 0x0c, i_or_ald8 ) { DEF_ald8; ORB; I.regs.b[AL]=dst; CLK(1); }
+OP( 0x0d, i_or_axd16 ) { DEF_axd16; ORW; I.regs.w[AW]=dst; CLK(1); }
+OP( 0x0e, i_push_cs ) { PUSH(I.sregs[CS]); CLK(2); }
+OP( 0x0f, i_pre_nec ) { UINT32 ModRM, tmp, tmp2;
+ switch (FETCH) {
+ case 0x10 : BITOP_BYTE; tmp2 = I.regs.b[CL] & 0x7; I.ZeroVal = (tmp & (1<<tmp2)) ? 1 : 0; I.CarryVal=I.OverVal=0; break; /* Test */
+ case 0x11 : BITOP_WORD; tmp2 = I.regs.b[CL] & 0xf; I.ZeroVal = (tmp & (1<<tmp2)) ? 1 : 0; I.CarryVal=I.OverVal=0; break; /* Test */
+ case 0x12 : BITOP_BYTE; tmp2 = I.regs.b[CL] & 0x7; tmp &= ~(1<<tmp2); PutbackRMByte(ModRM,tmp); break; /* Clr */
+ case 0x13 : BITOP_WORD; tmp2 = I.regs.b[CL] & 0xf; tmp &= ~(1<<tmp2); PutbackRMWord(ModRM,tmp); break; /* Clr */
+ case 0x14 : BITOP_BYTE; tmp2 = I.regs.b[CL] & 0x7; tmp |= (1<<tmp2); PutbackRMByte(ModRM,tmp); break; /* Set */
+ case 0x15 : BITOP_WORD; tmp2 = I.regs.b[CL] & 0xf; tmp |= (1<<tmp2); PutbackRMWord(ModRM,tmp); break; /* Set */
+ case 0x16 : BITOP_BYTE; tmp2 = I.regs.b[CL] & 0x7; BIT_NOT; PutbackRMByte(ModRM,tmp); break; /* Not */
+ case 0x17 : BITOP_WORD; tmp2 = I.regs.b[CL] & 0xf; BIT_NOT; PutbackRMWord(ModRM,tmp); break; /* Not */
+
+ case 0x18 : BITOP_BYTE; tmp2 = (FETCH) & 0x7; I.ZeroVal = (tmp & (1<<tmp2)) ? 1 : 0; I.CarryVal=I.OverVal=0; break; /* Test */
+ case 0x19 : BITOP_WORD; tmp2 = (FETCH) & 0xf; I.ZeroVal = (tmp & (1<<tmp2)) ? 1 : 0; I.CarryVal=I.OverVal=0; break; /* Test */
+ case 0x1a : BITOP_BYTE; tmp2 = (FETCH) & 0x7; tmp &= ~(1<<tmp2); PutbackRMByte(ModRM,tmp); break; /* Clr */
+ case 0x1b : BITOP_WORD; tmp2 = (FETCH) & 0xf; tmp &= ~(1<<tmp2); PutbackRMWord(ModRM,tmp); break; /* Clr */
+ case 0x1c : BITOP_BYTE; tmp2 = (FETCH) & 0x7; tmp |= (1<<tmp2); PutbackRMByte(ModRM,tmp); break; /* Set */
+ case 0x1d : BITOP_WORD; tmp2 = (FETCH) & 0xf; tmp |= (1<<tmp2); PutbackRMWord(ModRM,tmp); break; /* Set */
+ case 0x1e : BITOP_BYTE; tmp2 = (FETCH) & 0x7; BIT_NOT; PutbackRMByte(ModRM,tmp); break; /* Not */
+ case 0x1f : BITOP_WORD; tmp2 = (FETCH) & 0xf; BIT_NOT; PutbackRMWord(ModRM,tmp); break; /* Not */
+
+ case 0x20 : ADD4S; break;
+ case 0x22 : SUB4S; break;
+ case 0x26 : CMP4S; break;
+ case 0x28 : ModRM = FETCH; tmp = GetRMByte(ModRM); tmp <<= 4; tmp |= I.regs.b[AL] & 0xf; I.regs.b[AL] = (I.regs.b[AL] & 0xf0) | ((tmp>>8)&0xf); tmp &= 0xff; PutbackRMByte(ModRM,tmp); CLKM(9,15); break;
+ case 0x2a : ModRM = FETCH; tmp = GetRMByte(ModRM); tmp2 = (I.regs.b[AL] & 0xf)<<4; I.regs.b[AL] = (I.regs.b[AL] & 0xf0) | (tmp&0xf); tmp = tmp2 | (tmp>>4); PutbackRMByte(ModRM,tmp); CLKM(13,19); break;
+ case 0x31 : ModRM = FETCH; ModRM=0; logerror("%06x: Unimplemented bitfield INS\n",activecpu_get_pc()); break;
+ case 0x33 : ModRM = FETCH; ModRM=0; logerror("%06x: Unimplemented bitfield EXT\n",activecpu_get_pc()); break;
+ case 0x92 : CLK(2); break; /* V25/35 FINT */
+ case 0xe0 : ModRM = FETCH; ModRM=0; logerror("%06x: V33 unimplemented BRKXA (break to expansion address)\n",activecpu_get_pc()); break;
+ case 0xf0 : ModRM = FETCH; ModRM=0; logerror("%06x: V33 unimplemented RETXA (return from expansion address)\n",activecpu_get_pc()); break;
+ case 0xff : ModRM = FETCH; ModRM=0; logerror("%06x: unimplemented BRKEM (break to 8080 emulation mode)\n",activecpu_get_pc()); break;
+ default: logerror("%06x: Unknown V20 instruction\n",activecpu_get_pc()); break;
+ }
+}
+
+OP( 0x10, i_adc_br8 ) { DEF_br8; src+=CF; ADDB; PutbackRMByte(ModRM,dst); CLKM(1,3); }
+OP( 0x11, i_adc_wr16 ) { DEF_wr16; src+=CF; ADDW; PutbackRMWord(ModRM,dst); CLKM(1,3);}
+OP( 0x12, i_adc_r8b ) { DEF_r8b; src+=CF; ADDB; RegByte(ModRM)=dst; CLKM(1,2); }
+OP( 0x13, i_adc_r16w ) { DEF_r16w; src+=CF; ADDW; RegWord(ModRM)=dst; CLKM(1,2); }
+OP( 0x14, i_adc_ald8 ) { DEF_ald8; src+=CF; ADDB; I.regs.b[AL]=dst; CLK(1); }
+OP( 0x15, i_adc_axd16) { DEF_axd16; src+=CF; ADDW; I.regs.w[AW]=dst; CLK(1); }
+OP( 0x16, i_push_ss ) { PUSH(I.sregs[SS]); CLK(2); }
+OP( 0x17, i_pop_ss ) { POP(I.sregs[SS]); CLK(3); I.no_interrupt=1; }
+
+OP( 0x18, i_sbb_br8 ) { DEF_br8; src+=CF; SUBB; PutbackRMByte(ModRM,dst); CLKM(1,3); }
+OP( 0x19, i_sbb_wr16 ) { DEF_wr16; src+=CF; SUBW; PutbackRMWord(ModRM,dst); CLKM(1,3);}
+OP( 0x1a, i_sbb_r8b ) { DEF_r8b; src+=CF; SUBB; RegByte(ModRM)=dst; CLKM(1,2); }
+OP( 0x1b, i_sbb_r16w ) { DEF_r16w; src+=CF; SUBW; RegWord(ModRM)=dst; CLKM(1,2); }
+OP( 0x1c, i_sbb_ald8 ) { DEF_ald8; src+=CF; SUBB; I.regs.b[AL]=dst; CLK(1); }
+OP( 0x1d, i_sbb_axd16) { DEF_axd16; src+=CF; SUBW; I.regs.w[AW]=dst; CLK(1); }
+OP( 0x1e, i_push_ds ) { PUSH(I.sregs[DS]); CLK(2); }
+OP( 0x1f, i_pop_ds ) { POP(I.sregs[DS]); CLK(3); }
+
+OP( 0x20, i_and_br8 ) { DEF_br8; ANDB; PutbackRMByte(ModRM,dst); CLKM(1,3); }
+OP( 0x21, i_and_wr16 ) { DEF_wr16; ANDW; PutbackRMWord(ModRM,dst); CLKM(1,3);}
+OP( 0x22, i_and_r8b ) { DEF_r8b; ANDB; RegByte(ModRM)=dst; CLKM(1,2); }
+OP( 0x23, i_and_r16w ) { DEF_r16w; ANDW; RegWord(ModRM)=dst; CLKM(1,2); }
+OP( 0x24, i_and_ald8 ) { DEF_ald8; ANDB; I.regs.b[AL]=dst; CLK(1); }
+OP( 0x25, i_and_axd16) { DEF_axd16; ANDW; I.regs.w[AW]=dst; CLK(1); }
+OP( 0x26, i_es ) { seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; CLK(1); nec_instruction[FETCHOP](); seg_prefix=FALSE; }
+OP( 0x27, i_daa ) { ADJ4(6,0x60); CLK(10); }
+
+OP( 0x28, i_sub_br8 ) { DEF_br8; SUBB; PutbackRMByte(ModRM,dst); CLKM(1,3); }
+OP( 0x29, i_sub_wr16 ) { DEF_wr16; SUBW; PutbackRMWord(ModRM,dst); CLKM(1,3);}
+OP( 0x2a, i_sub_r8b ) { DEF_r8b; SUBB; RegByte(ModRM)=dst; CLKM(1,2); }
+OP( 0x2b, i_sub_r16w ) { DEF_r16w; SUBW; RegWord(ModRM)=dst; CLKM(1,2); }
+OP( 0x2c, i_sub_ald8 ) { DEF_ald8; SUBB; I.regs.b[AL]=dst; CLK(1); }
+OP( 0x2d, i_sub_axd16) { DEF_axd16; SUBW; I.regs.w[AW]=dst; CLK(1); }
+OP( 0x2e, i_cs ) { seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; CLK(1); nec_instruction[FETCHOP](); seg_prefix=FALSE; }
+OP( 0x2f, i_das ) { ADJ4(-6,-0x60); CLK(10); }
+
+OP( 0x30, i_xor_br8 ) { DEF_br8; XORB; PutbackRMByte(ModRM,dst); CLKM(1,3); }
+OP( 0x31, i_xor_wr16 ) { DEF_wr16; XORW; PutbackRMWord(ModRM,dst); CLKM(1,3);}
+OP( 0x32, i_xor_r8b ) { DEF_r8b; XORB; RegByte(ModRM)=dst; CLKM(1,2); }
+OP( 0x33, i_xor_r16w ) { DEF_r16w; XORW; RegWord(ModRM)=dst; CLKM(1,2); }
+OP( 0x34, i_xor_ald8 ) { DEF_ald8; XORB; I.regs.b[AL]=dst; CLK(1); }
+OP( 0x35, i_xor_axd16) { DEF_axd16; XORW; I.regs.w[AW]=dst; CLK(1); }
+OP( 0x36, i_ss ) { seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; CLK(1); nec_instruction[FETCHOP](); seg_prefix=FALSE; }
+OP( 0x37, i_aaa ) { ADJB(6, (I.regs.b[AL] > 0xf9) ? 2 : 1); CLK(9); }
+
+OP( 0x38, i_cmp_br8 ) { DEF_br8; SUBB; CLKM(1,2); }
+OP( 0x39, i_cmp_wr16 ) { DEF_wr16; SUBW; CLKM(1,2);}
+OP( 0x3a, i_cmp_r8b ) { DEF_r8b; SUBB; CLKM(1,2); }
+OP( 0x3b, i_cmp_r16w ) { DEF_r16w; SUBW; CLKM(1,2); }
+OP( 0x3c, i_cmp_ald8 ) { DEF_ald8; SUBB; CLK(1); }
+OP( 0x3d, i_cmp_axd16) { DEF_axd16; SUBW; CLK(1); }
+OP( 0x3e, i_ds ) { seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; CLK(1); nec_instruction[FETCHOP](); seg_prefix=FALSE; }
+OP( 0x3f, i_aas ) { ADJB(-6, (I.regs.b[AL] < 6) ? -2 : -1); CLK(9); }
+
+OP( 0x40, i_inc_ax ) { IncWordReg(AW); CLK(1); }
+OP( 0x41, i_inc_cx ) { IncWordReg(CW); CLK(1); }
+OP( 0x42, i_inc_dx ) { IncWordReg(DW); CLK(1); }
+OP( 0x43, i_inc_bx ) { IncWordReg(BW); CLK(1); }
+OP( 0x44, i_inc_sp ) { IncWordReg(SP); CLK(1); }
+OP( 0x45, i_inc_bp ) { IncWordReg(BP); CLK(1); }
+OP( 0x46, i_inc_si ) { IncWordReg(IX); CLK(1); }
+OP( 0x47, i_inc_di ) { IncWordReg(IY); CLK(1); }
+
+OP( 0x48, i_dec_ax ) { DecWordReg(AW); CLK(1); }
+OP( 0x49, i_dec_cx ) { DecWordReg(CW); CLK(1); }
+OP( 0x4a, i_dec_dx ) { DecWordReg(DW); CLK(1); }
+OP( 0x4b, i_dec_bx ) { DecWordReg(BW); CLK(1); }
+OP( 0x4c, i_dec_sp ) { DecWordReg(SP); CLK(1); }
+OP( 0x4d, i_dec_bp ) { DecWordReg(BP); CLK(1); }
+OP( 0x4e, i_dec_si ) { DecWordReg(IX); CLK(1); }
+OP( 0x4f, i_dec_di ) { DecWordReg(IY); CLK(1); }
+
+OP( 0x50, i_push_ax ) { PUSH(I.regs.w[AW]); CLK(1); }
+OP( 0x51, i_push_cx ) { PUSH(I.regs.w[CW]); CLK(1); }
+OP( 0x52, i_push_dx ) { PUSH(I.regs.w[DW]); CLK(1); }
+OP( 0x53, i_push_bx ) { PUSH(I.regs.w[BW]); CLK(1); }
+OP( 0x54, i_push_sp ) { PUSH(I.regs.w[SP]); CLK(1); }
+OP( 0x55, i_push_bp ) { PUSH(I.regs.w[BP]); CLK(1); }
+OP( 0x56, i_push_si ) { PUSH(I.regs.w[IX]); CLK(1); }
+OP( 0x57, i_push_di ) { PUSH(I.regs.w[IY]); CLK(1); }
+
+OP( 0x58, i_pop_ax ) { POP(I.regs.w[AW]); CLK(1); }
+OP( 0x59, i_pop_cx ) { POP(I.regs.w[CW]); CLK(1); }
+OP( 0x5a, i_pop_dx ) { POP(I.regs.w[DW]); CLK(1); }
+OP( 0x5b, i_pop_bx ) { POP(I.regs.w[BW]); CLK(1); }
+OP( 0x5c, i_pop_sp ) { POP(I.regs.w[SP]); CLK(1); }
+OP( 0x5d, i_pop_bp ) { POP(I.regs.w[BP]); CLK(1); }
+OP( 0x5e, i_pop_si ) { POP(I.regs.w[IX]); CLK(1); }
+OP( 0x5f, i_pop_di ) { POP(I.regs.w[IY]); CLK(1); }
+
+OP( 0x60, i_pusha ) {
+ unsigned tmp=I.regs.w[SP];
+ PUSH(I.regs.w[AW]);
+ PUSH(I.regs.w[CW]);
+ PUSH(I.regs.w[DW]);
+ PUSH(I.regs.w[BW]);
+ PUSH(tmp);
+ PUSH(I.regs.w[BP]);
+ PUSH(I.regs.w[IX]);
+ PUSH(I.regs.w[IY]);
+ CLK(9);
+}
+OP( 0x61, i_popa ) {
+ unsigned tmp;
+ POP(I.regs.w[IY]);
+ POP(I.regs.w[IX]);
+ POP(I.regs.w[BP]);
+ POP(tmp);
+ POP(I.regs.w[BW]);
+ POP(I.regs.w[DW]);
+ POP(I.regs.w[CW]);
+ POP(I.regs.w[AW]);
+ CLK(8);
+}
+OP( 0x62, i_chkind ) {
+ UINT32 low,high,tmp;
+ GetModRM;
+ low = GetRMWord(ModRM);
+ high= GetnextRMWord;
+ tmp= RegWord(ModRM);
+ if (tmp<low || tmp>high) {
+ nec_interrupt(5,0);
+ CLK(20);
+ } else {
+ CLK(13);
+ }
+ logerror("%06x: bound %04x high %04x low %04x tmp\n",activecpu_get_pc(),high,low,tmp);
+}
+OP( 0x64, i_repnc ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW];
+ switch(next) { /* Segments */
+ case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; next = FETCHOP; CLK(2); break;
+ case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; next = FETCHOP; CLK(2); break;
+ }
+
+ switch(next) {
+ case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break;
+ default: logerror("%06x: REPNC invalid\n",activecpu_get_pc()); nec_instruction[next]();
+ }
+ seg_prefix=FALSE;
+}
+
+OP( 0x65, i_repc ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW];
+ switch(next) { /* Segments */
+ case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; next = FETCHOP; CLK(2); break;
+ case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; next = FETCHOP; CLK(2); break;
+ }
+
+ switch(next) {
+ case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break;
+ default: logerror("%06x: REPC invalid\n",activecpu_get_pc()); nec_instruction[next]();
+ }
+ seg_prefix=FALSE;
+}
+
+OP( 0x68, i_push_d16 ) { UINT32 tmp; FETCHWORD(tmp); PUSH(tmp); CLK(1); }
+OP( 0x69, i_imul_d16 ) { UINT32 tmp; DEF_r16w; FETCHWORD(tmp); dst = (INT32)((INT16)src)*(INT32)((INT16)tmp); I.CarryVal = I.OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1); RegWord(ModRM)=(WORD)dst; if (ModRM >= 0xc0) CLK(3) else CLK(4) }
+OP( 0x6a, i_push_d8 ) { UINT32 tmp = (WORD)((INT16)((INT8)FETCH)); PUSH(tmp); CLK(1); }
+OP( 0x6b, i_imul_d8 ) { UINT32 src2; DEF_r16w; src2= (WORD)((INT16)((INT8)FETCH)); dst = (INT32)((INT16)src)*(INT32)((INT16)src2); I.CarryVal = I.OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1); RegWord(ModRM)=(WORD)dst; if (ModRM >= 0xc0) CLK(3) else CLK(4) }
+OP( 0x6c, i_insb ) { PutMemB(ES,I.regs.w[IY],read_port(I.regs.w[DW])); I.regs.w[IY]+= -2 * I.DF + 1; CLK(6); }
+OP( 0x6d, i_insw ) { PutMemB(ES,I.regs.w[IY],read_port(I.regs.w[DW])); PutMemB(ES,(I.regs.w[IY]+1)&0xffff,read_port((I.regs.w[DW]+1)&0xffff)); I.regs.w[IY]+= -4 * I.DF + 2; CLK(6); }
+OP( 0x6e, i_outsb ) { write_port(I.regs.w[DW],GetMemB(DS,I.regs.w[IX])); I.regs.w[IX]+= -2 * I.DF + 1; CLK(7); }
+OP( 0x6f, i_outsw ) { write_port(I.regs.w[DW],GetMemB(DS,I.regs.w[IX])); write_port((I.regs.w[DW]+1)&0xffff,GetMemB(DS,(I.regs.w[IX]+1)&0xffff)); I.regs.w[IX]+= -4 * I.DF + 2; CLK(7); }
+
+OP( 0x70, i_jo ) { JMP( OF); if ( OF) CLK(4) else CLK(1) }
+OP( 0x71, i_jno ) { JMP(!OF); if (!OF) CLK(4) else CLK(1) }
+OP( 0x72, i_jc ) { JMP( CF); if ( CF) CLK(4) else CLK(1) }
+OP( 0x73, i_jnc ) { JMP(!CF); if (!CF) CLK(4) else CLK(1) }
+OP( 0x74, i_jz ) { JMP( ZF); if ( ZF) CLK(4) else CLK(1) }
+OP( 0x75, i_jnz ) { JMP(!ZF); if (!ZF) CLK(4) else CLK(1) }
+OP( 0x76, i_jce ) { JMP(CF || ZF); if (CF || ZF) CLK(4) else CLK(1) }
+OP( 0x77, i_jnce ) { JMP(!(CF || ZF)); if (!(CF || ZF)) CLK(4) else CLK(1) }
+OP( 0x78, i_js ) { JMP( SF); if ( SF) CLK(4) else CLK(1) }
+OP( 0x79, i_jns ) { JMP(!SF); if (!SF) CLK(4) else CLK(1) }
+OP( 0x7a, i_jp ) { JMP( PF); if ( PF) CLK(4) else CLK(1) }
+OP( 0x7b, i_jnp ) { JMP(!PF); if (!PF) CLK(4) else CLK(1) }
+OP( 0x7c, i_jl ) { JMP((SF!=OF)&&(!ZF)); if ((SF!=OF)&&(!ZF)) CLK(4) else CLK(1) }
+OP( 0x7d, i_jnl ) { JMP((ZF)||(SF==OF)); if ((ZF)||(SF==OF)) CLK(4) else CLK(1) }
+OP( 0x7e, i_jle ) { JMP((ZF)||(SF!=OF)); if ((ZF)||(SF!=OF)) CLK(4) else CLK(1) }
+OP( 0x7f, i_jnle ) { JMP((SF==OF)&&(!ZF)); if ((SF==OF)&&(!ZF)) CLK(4) else CLK(1) }
+
+OP( 0x80, i_80pre ) { UINT32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = FETCH;
+ if (ModRM >=0xc0 ) CLK(1) else if ((ModRM & 0x38)==0x38) CLK(2) else CLK(3)
+ switch (ModRM & 0x38) {
+ case 0x00: ADDB; PutbackRMByte(ModRM,dst); break;
+ case 0x08: ORB; PutbackRMByte(ModRM,dst); break;
+ case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break;
+ case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break;
+ case 0x20: ANDB; PutbackRMByte(ModRM,dst); break;
+ case 0x28: SUBB; PutbackRMByte(ModRM,dst); break;
+ case 0x30: XORB; PutbackRMByte(ModRM,dst); break;
+ case 0x38: SUBB; break; /* CMP */
+ }
+}
+
+OP( 0x81, i_81pre ) { UINT32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = FETCH; src+= (FETCH << 8);
+ if (ModRM >=0xc0 ) CLK(1) else if ((ModRM & 0x38)==0x38) CLK(2) else CLK(3)
+ switch (ModRM & 0x38) {
+ case 0x00: ADDW; PutbackRMWord(ModRM,dst); break;
+ case 0x08: ORW; PutbackRMWord(ModRM,dst); break;
+ case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break;
+ case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break;
+ case 0x20: ANDW; PutbackRMWord(ModRM,dst); break;
+ case 0x28: SUBW; PutbackRMWord(ModRM,dst); break;
+ case 0x30: XORW; PutbackRMWord(ModRM,dst); break;
+ case 0x38: SUBW; break; /* CMP */
+ }
+}
+
+OP( 0x82, i_82pre ) { UINT32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = (BYTE)((INT8)FETCH);
+ if (ModRM >=0xc0 ) CLK(1) else if ((ModRM & 0x38)==0x38) CLK(2) else CLK(3)
+ switch (ModRM & 0x38) {
+ case 0x00: ADDB; PutbackRMByte(ModRM,dst); break;
+ case 0x08: ORB; PutbackRMByte(ModRM,dst); break;
+ case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break;
+ case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break;
+ case 0x20: ANDB; PutbackRMByte(ModRM,dst); break;
+ case 0x28: SUBB; PutbackRMByte(ModRM,dst); break;
+ case 0x30: XORB; PutbackRMByte(ModRM,dst); break;
+ case 0x38: SUBB; break; /* CMP */
+ }
+}
+
+OP( 0x83, i_83pre ) { UINT32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = (WORD)((INT16)((INT8)FETCH));
+ if (ModRM >=0xc0 ) CLK(1) else if ((ModRM & 0x38)==0x38) CLK(2) else CLK(3)
+ switch (ModRM & 0x38) {
+ case 0x00: ADDW; PutbackRMWord(ModRM,dst); break;
+ case 0x08: ORW; PutbackRMWord(ModRM,dst); break;
+ case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break;
+ case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break;
+ case 0x20: ANDW; PutbackRMWord(ModRM,dst); break;
+ case 0x28: SUBW; PutbackRMWord(ModRM,dst); break;
+ case 0x30: XORW; PutbackRMWord(ModRM,dst); break;
+ case 0x38: SUBW; break; /* CMP */
+ }
+}
+
+OP( 0x84, i_test_br8 ) { DEF_br8; ANDB; CLKM(1,2); }
+OP( 0x85, i_test_wr16 ) { DEF_wr16; ANDW; CLKM(1,2); }
+OP( 0x86, i_xchg_br8 ) { DEF_br8; RegByte(ModRM)=dst; PutbackRMByte(ModRM,src); CLKM(3,5); }
+OP( 0x87, i_xchg_wr16 ) { DEF_wr16; RegWord(ModRM)=dst; PutbackRMWord(ModRM,src); CLKM(3,5); }
+
+OP( 0x88, i_mov_br8 ) { UINT8 src; GetModRM; src = RegByte(ModRM); PutRMByte(ModRM,src); CLK(1); }
+OP( 0x89, i_mov_wr16 ) { UINT16 src; GetModRM; src = RegWord(ModRM); PutRMWord(ModRM,src); CLK(1); }
+OP( 0x8a, i_mov_r8b ) { UINT8 src; GetModRM; src = GetRMByte(ModRM); RegByte(ModRM)=src; CLK(1); }
+OP( 0x8b, i_mov_r16w ) { UINT16 src; GetModRM; src = GetRMWord(ModRM); RegWord(ModRM)=src; CLK(1); }
+OP( 0x8c, i_mov_wsreg ) { GetModRM; PutRMWord(ModRM,I.sregs[(ModRM & 0x38) >> 3]); CLKM(1,3); }
+OP( 0x8d, i_lea ) { UINT16 ModRM = FETCH; (void)(*GetEA[ModRM])(); RegWord(ModRM)=EO; CLK(1); }
+OP( 0x8e, i_mov_sregw ) { UINT16 src; GetModRM; src = GetRMWord(ModRM); CLKM(2,3);
+ switch (ModRM & 0x38) {
+ case 0x00: I.sregs[ES] = src; break; /* mov es,ew */
+ case 0x08: I.sregs[CS] = src; break; /* mov cs,ew */
+ case 0x10: I.sregs[SS] = src; break; /* mov ss,ew */
+ case 0x18: I.sregs[DS] = src; break; /* mov ds,ew */
+ default: logerror("%06x: Mov Sreg - Invalid register\n",activecpu_get_pc());
+ }
+ I.no_interrupt=1;
+}
+OP( 0x8f, i_popw ) { UINT16 tmp; GetModRM; POP(tmp); PutRMWord(ModRM,tmp); CLKM(1,3); }
+OP( 0x90, i_nop ) { CLK(1);
+ /* Cycle skip for idle loops (0: NOP 1: JMP 0) */
+ if (I.no_interrupt==0 && nec_ICount>0 && (I.pending_irq==0) && (PEEKOP((I.sregs[CS]<<4)+I.ip))==0xeb && (PEEK((I.sregs[CS]<<4)+I.ip+1))==0xfd)
+ nec_ICount%=15;
+}
+OP( 0x91, i_xchg_axcx ) { XchgAWReg(CW); CLK(3); }
+OP( 0x92, i_xchg_axdx ) { XchgAWReg(DW); CLK(3); }
+OP( 0x93, i_xchg_axbx ) { XchgAWReg(BW); CLK(3); }
+OP( 0x94, i_xchg_axsp ) { XchgAWReg(SP); CLK(3); }
+OP( 0x95, i_xchg_axbp ) { XchgAWReg(BP); CLK(3); }
+OP( 0x96, i_xchg_axsi ) { XchgAWReg(IX); CLK(3); }
+OP( 0x97, i_xchg_axdi ) { XchgAWReg(IY); CLK(3); }
+
+OP( 0x98, i_cbw ) { I.regs.b[AH] = (I.regs.b[AL] & 0x80) ? 0xff : 0; CLK(1); }
+OP( 0x99, i_cwd ) { I.regs.w[DW] = (I.regs.b[AH] & 0x80) ? 0xffff : 0; CLK(1); }
+OP( 0x9a, i_call_far ) { UINT32 tmp, tmp2; FETCHWORD(tmp); FETCHWORD(tmp2); PUSH(I.sregs[CS]); PUSH(I.ip); I.ip = (WORD)tmp; I.sregs[CS] = (WORD)tmp2; CHANGE_PC; CLK(10); }
+OP( 0x9b, i_wait ) { logerror("%06x: Hardware POLL\n",activecpu_get_pc()); }
+OP( 0x9c, i_pushf ) { PUSH( CompressFlags() ); CLK(2); }
+OP( 0x9d, i_popf ) { UINT32 tmp; POP(tmp); ExpandFlags(tmp); CLK(3); if (I.TF) nec_trap(); }
+OP( 0x9e, i_sahf ) { UINT32 tmp = (CompressFlags() & 0xff00) | (I.regs.b[AH] & 0xd5); ExpandFlags(tmp); CLK(4); }
+OP( 0x9f, i_lahf ) { I.regs.b[AH] = CompressFlags() & 0xff; CLK(2); }
+
+OP( 0xa0, i_mov_aldisp ) { UINT32 addr; FETCHWORD(addr); I.regs.b[AL] = GetMemB(DS, addr); CLK(1); }
+OP( 0xa1, i_mov_axdisp ) { UINT32 addr; FETCHWORD(addr); I.regs.b[AL] = GetMemB(DS, addr); I.regs.b[AH] = GetMemB(DS, (addr+1)&0xffff); CLK(1); }
+OP( 0xa2, i_mov_dispal ) { UINT32 addr; FETCHWORD(addr); PutMemB(DS, addr, I.regs.b[AL]); CLK(1); }
+OP( 0xa3, i_mov_dispax ) { UINT32 addr; FETCHWORD(addr); PutMemB(DS, addr, I.regs.b[AL]); PutMemB(DS, (addr+1)&0xffff, I.regs.b[AH]); CLK(1); }
+OP( 0xa4, i_movsb ) { UINT32 tmp = GetMemB(DS,I.regs.w[IX]); PutMemB(ES,I.regs.w[IY], tmp); I.regs.w[IY] += -2 * I.DF + 1; I.regs.w[IX] += -2 * I.DF + 1; CLK(5); }
+OP( 0xa5, i_movsw ) { UINT32 tmp = GetMemW(DS,I.regs.w[IX]); PutMemW(ES,I.regs.w[IY], tmp); I.regs.w[IY] += -4 * I.DF + 2; I.regs.w[IX] += -4 * I.DF + 2; CLK(5); }
+OP( 0xa6, i_cmpsb ) { UINT32 src = GetMemB(ES, I.regs.w[IY]); UINT32 dst = GetMemB(DS, I.regs.w[IX]); SUBB; I.regs.w[IY] += -2 * I.DF + 1; I.regs.w[IX] += -2 * I.DF + 1; CLK(6); }
+OP( 0xa7, i_cmpsw ) { UINT32 src = GetMemW(ES, I.regs.w[IY]); UINT32 dst = GetMemW(DS, I.regs.w[IX]); SUBW; I.regs.w[IY] += -4 * I.DF + 2; I.regs.w[IX] += -4 * I.DF + 2; CLK(6); }
+
+OP( 0xa8, i_test_ald8 ) { DEF_ald8; ANDB; CLK(1); }
+OP( 0xa9, i_test_axd16 ) { DEF_axd16; ANDW; CLK(1); }
+OP( 0xaa, i_stosb ) { PutMemB(ES,I.regs.w[IY],I.regs.b[AL]); I.regs.w[IY] += -2 * I.DF + 1; CLK(3); }
+OP( 0xab, i_stosw ) { PutMemW(ES,I.regs.w[IY],I.regs.w[AW]); I.regs.w[IY] += -4 * I.DF + 2; CLK(3); }
+OP( 0xac, i_lodsb ) { I.regs.b[AL] = GetMemB(DS,I.regs.w[IX]); I.regs.w[IX] += -2 * I.DF + 1; CLK(3); }
+OP( 0xad, i_lodsw ) { I.regs.w[AW] = GetMemW(DS,I.regs.w[IX]); I.regs.w[IX] += -4 * I.DF + 2; CLK(3); }
+OP( 0xae, i_scasb ) { UINT32 src = GetMemB(ES, I.regs.w[IY]); UINT32 dst = I.regs.b[AL]; SUBB; I.regs.w[IY] += -2 * I.DF + 1; CLK(4); }
+OP( 0xaf, i_scasw ) { UINT32 src = GetMemW(ES, I.regs.w[IY]); UINT32 dst = I.regs.w[AW]; SUBW; I.regs.w[IY] += -4 * I.DF + 2; CLK(4); }
+
+OP( 0xb0, i_mov_ald8 ) { I.regs.b[AL] = FETCH; CLK(1); }
+OP( 0xb1, i_mov_cld8 ) { I.regs.b[CL] = FETCH; CLK(1); }
+OP( 0xb2, i_mov_dld8 ) { I.regs.b[DL] = FETCH; CLK(1); }
+OP( 0xb3, i_mov_bld8 ) { I.regs.b[BL] = FETCH; CLK(1); }
+OP( 0xb4, i_mov_ahd8 ) { I.regs.b[AH] = FETCH; CLK(1); }
+OP( 0xb5, i_mov_chd8 ) { I.regs.b[CH] = FETCH; CLK(1); }
+OP( 0xb6, i_mov_dhd8 ) { I.regs.b[DH] = FETCH; CLK(1); }
+OP( 0xb7, i_mov_bhd8 ) { I.regs.b[BH] = FETCH; CLK(1); }
+
+OP( 0xb8, i_mov_axd16 ) { I.regs.b[AL] = FETCH; I.regs.b[AH] = FETCH; CLK(1); }
+OP( 0xb9, i_mov_cxd16 ) { I.regs.b[CL] = FETCH; I.regs.b[CH] = FETCH; CLK(1); }
+OP( 0xba, i_mov_dxd16 ) { I.regs.b[DL] = FETCH; I.regs.b[DH] = FETCH; CLK(1); }
+OP( 0xbb, i_mov_bxd16 ) { I.regs.b[BL] = FETCH; I.regs.b[BH] = FETCH; CLK(1); }
+OP( 0xbc, i_mov_spd16 ) { I.regs.b[SPL] = FETCH; I.regs.b[SPH] = FETCH; CLK(1); }
+OP( 0xbd, i_mov_bpd16 ) { I.regs.b[BPL] = FETCH; I.regs.b[BPH] = FETCH; CLK(1); }
+OP( 0xbe, i_mov_sid16 ) { I.regs.b[IXL] = FETCH; I.regs.b[IXH] = FETCH; CLK(1); }
+OP( 0xbf, i_mov_did16 ) { I.regs.b[IYL] = FETCH; I.regs.b[IYH] = FETCH; CLK(1); }
+
+OP( 0xc0, i_rotshft_bd8 ) {
+ UINT32 src, dst; UINT8 c;
+ GetModRM; src = (unsigned)GetRMByte(ModRM); dst=src;
+ c=FETCH;
+ CLKM(3,5);
+ if (c) switch (ModRM & 0x38) {
+ case 0x00: do { ROL_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x08: do { ROR_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x10: do { ROLC_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x18: do { RORC_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x20: SHL_BYTE(c); break;
+ case 0x28: SHR_BYTE(c); break;
+ case 0x30: logerror("%06x: Undefined opcode 0xc0 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_BYTE(c); break;
+ }
+}
+
+OP( 0xc1, i_rotshft_wd8 ) {
+ UINT32 src, dst; UINT8 c;
+ GetModRM; src = (unsigned)GetRMWord(ModRM); dst=src;
+ c=FETCH;
+ CLKM(3,5);
+ if (c) switch (ModRM & 0x38) {
+ case 0x00: do { ROL_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x08: do { ROR_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x10: do { ROLC_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x18: do { RORC_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x20: SHL_WORD(c); break;
+ case 0x28: SHR_WORD(c); break;
+ case 0x30: logerror("%06x: Undefined opcode 0xc1 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_WORD(c); break;
+ }
+}
+
+OP( 0xc2, i_ret_d16 ) { UINT32 count = FETCH; count += FETCH << 8; POP(I.ip); I.regs.w[SP]+=count; CHANGE_PC; CLK(6); }
+OP( 0xc3, i_ret ) { POP(I.ip); CHANGE_PC; CLK(6); }
+OP( 0xc4, i_les_dw ) { GetModRM; WORD tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; I.sregs[ES] = GetnextRMWord; CLK(6); }
+OP( 0xc5, i_lds_dw ) { GetModRM; WORD tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; I.sregs[DS] = GetnextRMWord; CLK(6); }
+OP( 0xc6, i_mov_bd8 ) { GetModRM; PutImmRMByte(ModRM); CLK(1); }
+OP( 0xc7, i_mov_wd16 ) { GetModRM; PutImmRMWord(ModRM); CLK(1); }
+
+OP( 0xc8, i_enter ) {
+ UINT32 nb = FETCH;
+ UINT32 i,level;
+
+ CLK(8);
+ nb += FETCH << 8;
+ level = FETCH;
+ PUSH(I.regs.w[BP]);
+ I.regs.w[BP]=I.regs.w[SP];
+ I.regs.w[SP] -= nb;
+ for (i=1;i<level;i++) {
+ PUSH(GetMemW(SS,I.regs.w[BP]-i*2));
+ CLK(4);
+ }
+ if (level) { PUSH(I.regs.w[BP]); if (level==1) CLK(2) else CLK(3) }
+}
+OP( 0xc9, i_leave ) {
+ I.regs.w[SP]=I.regs.w[BP];
+ POP(I.regs.w[BP]);
+ CLK(2);
+}
+OP( 0xca, i_retf_d16 ) { UINT32 count = FETCH; count += FETCH << 8; POP(I.ip); POP(I.sregs[CS]); I.regs.w[SP]+=count; CHANGE_PC; CLK(9); }
+OP( 0xcb, i_retf ) { POP(I.ip); POP(I.sregs[CS]); CHANGE_PC; CLK(8); }
+OP( 0xcc, i_int3 ) { nec_interrupt(3,0); CLK(9); }
+OP( 0xcd, i_int ) { nec_interrupt(FETCH,0); CLK(10); }
+OP( 0xce, i_into ) { if (OF) { nec_interrupt(4,0); CLK(13); } else CLK(6); }
+OP( 0xcf, i_iret ) { POP(I.ip); POP(I.sregs[CS]); i_popf(); CHANGE_PC; CLK(10); }
+
+OP( 0xd0, i_rotshft_b ) {
+ UINT32 src, dst; GetModRM; src = (UINT32)GetRMByte(ModRM); dst=src;
+ CLKM(1,3);
+ switch (ModRM & 0x38) {
+ case 0x00: ROL_BYTE; PutbackRMByte(ModRM,(BYTE)dst); I.OverVal = (src^dst)&0x80; break;
+ case 0x08: ROR_BYTE; PutbackRMByte(ModRM,(BYTE)dst); I.OverVal = (src^dst)&0x80; break;
+ case 0x10: ROLC_BYTE; PutbackRMByte(ModRM,(BYTE)dst); I.OverVal = (src^dst)&0x80; break;
+ case 0x18: RORC_BYTE; PutbackRMByte(ModRM,(BYTE)dst); I.OverVal = (src^dst)&0x80; break;
+ case 0x20: SHL_BYTE(1); I.OverVal = (src^dst)&0x80; break;
+ case 0x28: SHR_BYTE(1); I.OverVal = (src^dst)&0x80; break;
+ case 0x30: logerror("%06x: Undefined opcode 0xd0 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_BYTE(1); I.OverVal = 0; break;
+ }
+}
+
+OP( 0xd1, i_rotshft_w ) {
+ UINT32 src, dst; GetModRM; src = (UINT32)GetRMWord(ModRM); dst=src;
+ CLKM(1,3);
+ switch (ModRM & 0x38) {
+ case 0x00: ROL_WORD; PutbackRMWord(ModRM,(WORD)dst); I.OverVal = (src^dst)&0x8000; break;
+ case 0x08: ROR_WORD; PutbackRMWord(ModRM,(WORD)dst); I.OverVal = (src^dst)&0x8000; break;
+ case 0x10: ROLC_WORD; PutbackRMWord(ModRM,(WORD)dst); I.OverVal = (src^dst)&0x8000; break;
+ case 0x18: RORC_WORD; PutbackRMWord(ModRM,(WORD)dst); I.OverVal = (src^dst)&0x8000; break;
+ case 0x20: SHL_WORD(1); I.OverVal = (src^dst)&0x8000; break;
+ case 0x28: SHR_WORD(1); I.OverVal = (src^dst)&0x8000; break;
+ case 0x30: logerror("%06x: Undefined opcode 0xd1 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_WORD(1); I.OverVal = 0; break;
+ }
+}
+
+OP( 0xd2, i_rotshft_bcl ) {
+ UINT32 src, dst; UINT8 c; GetModRM; src = (UINT32)GetRMByte(ModRM); dst=src;
+ c=I.regs.b[CL];
+ CLKM(3,5);
+ if (c) switch (ModRM & 0x38) {
+ case 0x00: do { ROL_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x08: do { ROR_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x10: do { ROLC_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x18: do { RORC_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break;
+ case 0x20: SHL_BYTE(c); break;
+ case 0x28: SHR_BYTE(c); break;
+ case 0x30: logerror("%06x: Undefined opcode 0xd2 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_BYTE(c); break;
+ }
+}
+
+OP( 0xd3, i_rotshft_wcl ) {
+ UINT32 src, dst; UINT8 c; GetModRM; src = (UINT32)GetRMWord(ModRM); dst=src;
+ c=I.regs.b[CL];
+ CLKM(3,5);
+ if (c) switch (ModRM & 0x38) {
+ case 0x00: do { ROL_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x08: do { ROR_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x10: do { ROLC_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x18: do { RORC_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break;
+ case 0x20: SHL_WORD(c); break;
+ case 0x28: SHR_WORD(c); break;
+ case 0x30: logerror("%06x: Undefined opcode 0xd3 0x30 (SHLA)\n",activecpu_get_pc()); break;
+ case 0x38: SHRA_WORD(c); break;
+ }
+}
+
+OP( 0xd4, i_aam ) { UINT32 mult=FETCH; mult=0; I.regs.b[AH] = I.regs.b[AL] / 10; I.regs.b[AL] %= 10; SetSZPF_Word(I.regs.w[AW]); CLK(17); }
+OP( 0xd5, i_aad ) { UINT32 mult=FETCH; mult=0; I.regs.b[AL] = I.regs.b[AH] * 10 + I.regs.b[AL]; I.regs.b[AH] = 0; SetSZPF_Byte(I.regs.b[AL]); CLK(5); }
+OP( 0xd6, i_setalc ) { I.regs.b[AL] = (CF)?0xff:0x00; CLK(3); logerror("%06x: Undefined opcode (SETALC)\n",activecpu_get_pc()); }
+OP( 0xd7, i_trans ) { UINT32 dest = (I.regs.w[BW]+I.regs.b[AL])&0xffff; I.regs.b[AL] = GetMemB(DS, dest); CLK(5); }
+OP( 0xd8, i_fpo ) { GetModRM; CLK(1); logerror("%06x: Unimplemented floating point control %04x\n",activecpu_get_pc(),ModRM); }
+
+OP( 0xe0, i_loopne ) { INT8 disp = (INT8)FETCH; I.regs.w[CW]--; if (!ZF && I.regs.w[CW]) { I.ip = (WORD)(I.ip+disp); /*CHANGE_PC;*/ CLK(6); } else CLK(3); }
+OP( 0xe1, i_loope ) { INT8 disp = (INT8)FETCH; I.regs.w[CW]--; if ( ZF && I.regs.w[CW]) { I.ip = (WORD)(I.ip+disp); /*CHANGE_PC;*/ CLK(6); } else CLK(3); }
+OP( 0xe2, i_loop ) { INT8 disp = (INT8)FETCH; I.regs.w[CW]--; if (I.regs.w[CW]) { I.ip = (WORD)(I.ip+disp); /*CHANGE_PC;*/ CLK(5); } else CLK(2); }
+OP( 0xe3, i_jcxz ) { INT8 disp = (INT8)FETCH; if (I.regs.w[CW] == 0) { I.ip = (WORD)(I.ip+disp); /*CHANGE_PC;*/ CLK(4); } else CLK(1); }
+OP( 0xe4, i_inal ) { UINT8 port = FETCH; I.regs.b[AL] = read_port(port); CLK(6); }
+OP( 0xe5, i_inax ) { UINT8 port = FETCH; I.regs.b[AL] = read_port(port); I.regs.b[AH] = read_port(port+1); CLK(6); }
+OP( 0xe6, i_outal ) { UINT8 port = FETCH; write_port(port, I.regs.b[AL]); CLK(6); }
+OP( 0xe7, i_outax ) { UINT8 port = FETCH; write_port(port, I.regs.b[AL]); write_port(port+1, I.regs.b[AH]); CLK(6); }
+
+OP( 0xe8, i_call_d16 ) { UINT32 tmp; FETCHWORD(tmp); PUSH(I.ip); I.ip = (WORD)(I.ip+(INT16)tmp); CHANGE_PC; CLK(5); }
+OP( 0xe9, i_jmp_d16 ) { UINT32 tmp; FETCHWORD(tmp); I.ip = (WORD)(I.ip+(INT16)tmp); CHANGE_PC; CLK(4); }
+OP( 0xea, i_jmp_far ) { UINT32 tmp,tmp1; FETCHWORD(tmp); FETCHWORD(tmp1); I.sregs[CS] = (WORD)tmp1; I.ip = (WORD)tmp; CHANGE_PC; CLK(7); }
+OP( 0xeb, i_jmp_d8 ) { int tmp = (int)((INT8)FETCH); CLK(4);
+ if (tmp==-2 && I.no_interrupt==0 && (I.pending_irq==0) && nec_ICount>0) nec_ICount%=12; /* cycle skip */
+ I.ip = (WORD)(I.ip+tmp);
+}
+OP( 0xec, i_inaldx ) { I.regs.b[AL] = read_port(I.regs.w[DW]); CLK(6);}
+OP( 0xed, i_inaxdx ) { UINT32 port = I.regs.w[DW]; I.regs.b[AL] = read_port(port); I.regs.b[AH] = read_port(port+1); CLK(6); }
+OP( 0xee, i_outdxal ) { write_port(I.regs.w[DW], I.regs.b[AL]); CLK(6); }
+OP( 0xef, i_outdxax ) { UINT32 port = I.regs.w[DW]; write_port(port, I.regs.b[AL]); write_port(port+1, I.regs.b[AH]); CLK(6); }
+
+OP( 0xf0, i_lock ) { logerror("%06x: Warning - BUSLOCK\n",activecpu_get_pc()); I.no_interrupt=1; CLK(1); }
+OP( 0xf2, i_repne ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW];
+ switch(next) { /* Segments */
+ case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; next = FETCHOP; CLK(2); break;
+ case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; next = FETCHOP; CLK(2); break;
+ }
+
+ switch(next) {
+ case 0x6c: CLK(3); if (c) do { i_insb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6d: CLK(3); if (c) do { i_insw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6e: CLK(3); if (c) do { i_outsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6f: CLK(3); if (c) do { i_outsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa4: CLK(3); if (c) do { i_movsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa5: CLK(3); if (c) do { i_movsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa6: CLK(3); if (c) do { i_cmpsb(); c--; } while (c>0 && ZF==0); I.regs.w[CW]=c; break;
+ case 0xa7: CLK(3); if (c) do { i_cmpsw(); c--; } while (c>0 && ZF==0); I.regs.w[CW]=c; break;
+ case 0xaa: CLK(3); if (c) do { i_stosb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xab: CLK(3); if (c) do { i_stosw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xac: CLK(3); if (c) do { i_lodsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xad: CLK(3); if (c) do { i_lodsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xae: CLK(3); if (c) do { i_scasb(); c--; } while (c>0 && ZF==0); I.regs.w[CW]=c; break;
+ case 0xaf: CLK(3); if (c) do { i_scasw(); c--; } while (c>0 && ZF==0); I.regs.w[CW]=c; break;
+ default: logerror("%06x: REPNE invalid\n",activecpu_get_pc()); nec_instruction[next]();
+ }
+ seg_prefix=FALSE;
+}
+OP( 0xf3, i_repe ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW];
+ switch(next) { /* Segments */
+ case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; next = FETCHOP; CLK(2); break;
+ case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break;
+ case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; next = FETCHOP; CLK(2); break;
+ }
+
+ switch(next) {
+ case 0x6c: CLK(3); if (c) do { i_insb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6d: CLK(3); if (c) do { i_insw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6e: CLK(3); if (c) do { i_outsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0x6f: CLK(3); if (c) do { i_outsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa4: CLK(3); if (c) do { i_movsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa5: CLK(3); if (c) do { i_movsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xa6: CLK(3); if (c) do { i_cmpsb(); c--; } while (c>0 && ZF==1); I.regs.w[CW]=c; break;
+ case 0xa7: CLK(3); if (c) do { i_cmpsw(); c--; } while (c>0 && ZF==1); I.regs.w[CW]=c; break;
+ case 0xaa: CLK(3); if (c) do { i_stosb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xab: CLK(3); if (c) do { i_stosw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xac: CLK(3); if (c) do { i_lodsb(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xad: CLK(3); if (c) do { i_lodsw(); c--; } while (c>0); I.regs.w[CW]=c; break;
+ case 0xae: CLK(3); if (c) do { i_scasb(); c--; } while (c>0 && ZF==1); I.regs.w[CW]=c; break;
+ case 0xaf: CLK(3); if (c) do { i_scasw(); c--; } while (c>0 && ZF==1); I.regs.w[CW]=c; break;
+ default: logerror("%06x: REPE invalid\n",activecpu_get_pc()); nec_instruction[next]();
+ }
+ seg_prefix=FALSE;
+}
+OP( 0xf4, i_hlt ) { logerror("%06x: HALT\n",activecpu_get_pc()); nec_ICount=0; }
+OP( 0xf5, i_cmc ) { I.CarryVal = !CF; CLK(4); }
+OP( 0xf6, i_f6pre ) { UINT32 tmp; UINT32 uresult,uresult2; INT32 result,result2;
+ GetModRM; tmp = GetRMByte(ModRM);
+ switch (ModRM & 0x38) {
+ case 0x00: tmp &= FETCH; I.CarryVal = I.OverVal = 0; SetSZPF_Byte(tmp); CLKM(1,2); break; /* TEST */
+ case 0x08: logerror("%06x: Undefined opcode 0xf6 0x08\n",activecpu_get_pc()); break;
+ case 0x10: PutbackRMByte(ModRM,~tmp); CLKM(1,3); break; /* NOT */
+ case 0x18: I.CarryVal=(tmp!=0); tmp=(~tmp)+1; SetSZPF_Byte(tmp); PutbackRMByte(ModRM,tmp&0xff); CLKM(1,3); break; /* NEG */
+ case 0x20: uresult = I.regs.b[AL]*tmp; I.regs.w[AW]=(WORD)uresult; I.CarryVal=I.OverVal=(I.regs.b[AH]!=0); CLKM(3,4); break; /* MULU */
+ case 0x28: result = (INT16)((INT8)I.regs.b[AL])*(INT16)((INT8)tmp); I.regs.w[AW]=(WORD)result; I.CarryVal=I.OverVal=(I.regs.b[AH]!=0); CLKM(3,4); break; /* MUL */
+ case 0x30: if (tmp) { DIVUB; } else nec_interrupt(0,0); CLKM(15,16); break;
+ case 0x38: if (tmp) { DIVB; } else nec_interrupt(0,0); CLKM(17,18); break;
+ }
+}
+
+OP( 0xf7, i_f7pre ) { UINT32 tmp,tmp2; UINT32 uresult,uresult2; INT32 result,result2;
+ GetModRM; tmp = GetRMWord(ModRM);
+ switch (ModRM & 0x38) {
+ case 0x00: FETCHWORD(tmp2); tmp &= tmp2; I.CarryVal = I.OverVal = 0; SetSZPF_Word(tmp); CLKM(1,2); break; /* TEST */
+ case 0x08: logerror("%06x: Undefined opcode 0xf7 0x08\n",activecpu_get_pc()); break;
+ case 0x10: PutbackRMWord(ModRM,~tmp); CLKM(1,3); break; /* NOT */
+ case 0x18: I.CarryVal=(tmp!=0); tmp=(~tmp)+1; SetSZPF_Word(tmp); PutbackRMWord(ModRM,tmp&0xffff); CLKM(1,3); break; /* NEG */
+ case 0x20: uresult = I.regs.w[AW]*tmp; I.regs.w[AW]=uresult&0xffff; I.regs.w[DW]=((UINT32)uresult)>>16; I.CarryVal=I.OverVal=(I.regs.w[DW]!=0); CLKM(3,4); break; /* MULU */
+ case 0x28: result = (INT32)((INT16)I.regs.w[AW])*(INT32)((INT16)tmp); I.regs.w[AW]=result&0xffff; I.regs.w[DW]=result>>16; I.CarryVal=I.OverVal=(I.regs.w[DW]!=0); CLKM(3,4); break; /* MUL */
+ case 0x30: if (tmp) { DIVUW; } else nec_interrupt(0,0); CLKM(23,24); break;
+ case 0x38: if (tmp) { DIVW; } else nec_interrupt(0,0); CLKM(24,25); break;
+ }
+}
+
+OP( 0xf8, i_clc ) { I.CarryVal = 0; CLK(4); }
+OP( 0xf9, i_stc ) { I.CarryVal = 1; CLK(4); }
+OP( 0xfa, i_di ) { SetIF(0); CLK(4); }
+OP( 0xfb, i_ei ) { SetIF(1); CLK(4); }
+OP( 0xfc, i_cld ) { SetDF(0); CLK(4); }
+OP( 0xfd, i_std ) { SetDF(1); CLK(4); }
+OP( 0xfe, i_fepre ) { UINT32 tmp, tmp1; GetModRM; tmp=GetRMByte(ModRM);
+ switch(ModRM & 0x38) {
+ case 0x00: tmp1 = tmp+1; I.OverVal = (tmp==0x7f); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(BYTE)tmp1); CLKM(1,3); break; /* INC */
+ case 0x08: tmp1 = tmp-1; I.OverVal = (tmp==0x80); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(BYTE)tmp1); CLKM(1,3); break; /* DEC */
+ default: logerror("%06x: FE Pre with unimplemented mod\n",activecpu_get_pc());
+ }
+}
+OP( 0xff, i_ffpre ) { UINT32 tmp, tmp1; GetModRM; tmp=GetRMWord(ModRM);
+ switch(ModRM & 0x38) {
+ case 0x00: tmp1 = tmp+1; I.OverVal = (tmp==0x7fff); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(WORD)tmp1); CLKM(1,3); break; /* INC */
+ case 0x08: tmp1 = tmp-1; I.OverVal = (tmp==0x8000); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(WORD)tmp1); CLKM(1,3); break; /* DEC */
+ case 0x10: PUSH(I.ip); I.ip = (WORD)tmp; CHANGE_PC; CLKM(5,6); break; /* CALL */
+ case 0x18: tmp1 = I.sregs[CS]; I.sregs[CS] = GetnextRMWord; PUSH(tmp1); PUSH(I.ip); I.ip = tmp; CHANGE_PC; CLKM(5,12); break; /* CALL FAR */
+ case 0x20: I.ip = tmp; CHANGE_PC; CLKM(4,5); break; /* JMP */
+ case 0x28: I.ip = tmp; I.sregs[CS] = GetnextRMWord; CHANGE_PC; CLK(10); break; /* JMP FAR */
+ case 0x30: PUSH(tmp); CLK(1); break;
+ default: logerror("%06x: FF Pre with unimplemented mod\n",activecpu_get_pc());
+ }
+}
+
+static void i_invalid(void)
+{
+ nec_ICount-=10;
+ logerror("%06x: Invalid Opcode\n",activecpu_get_pc());
+}
+
+/*****************************************************************************/
+
+static void nec_get_context(void *dst)
+{
+ if( dst )
+ *(nec_Regs*)dst = I;
+}
+
+static void nec_set_context(void *src)
+{
+ if( src )
+ {
+ I = *(nec_Regs*)src;
+ CHANGE_PC;
+ }
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if( I.nmi_state == state ) return;
+ I.nmi_state = state;
+ if (state != CLEAR_LINE)
+ {
+ I.pending_irq |= NMI_IRQ;
+ }
+ }
+ else
+ {
+ I.irq_state = state;
+ if (state == CLEAR_LINE)
+ {
+ // if (!I.IF) NS010718 fix interrupt request loss
+ I.pending_irq &= ~INT_IRQ;
+ }
+ else
+ {
+ // if (I.IF) NS010718 fix interrupt request loss
+ I.pending_irq |= INT_IRQ;
+ }
+ }
+}
+
+#ifdef MAME_DEBUG
+static offs_t nec_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return necv_dasm_one(buffer, pc, oprom);
+}
+#endif /* MAME_DEBUG */
+
+static void nec_init(int index, int clock, const void *config, int (*irqcallback)(int), int type)
+{
+ static const char *names[]={"V20","V30","V33","V30MZ"};
+
+ state_save_register_item_array(names[type], index, I.regs.w);
+ state_save_register_item_array(names[type], index, I.sregs);
+
+ state_save_register_item(names[type], index, I.ip);
+ state_save_register_item(names[type], index, I.TF);
+ state_save_register_item(names[type], index, I.IF);
+ state_save_register_item(names[type], index, I.DF);
+ state_save_register_item(names[type], index, I.MF);
+ state_save_register_item(names[type], index, I.SignVal);
+ state_save_register_item(names[type], index, I.int_vector);
+ state_save_register_item(names[type], index, I.pending_irq);
+ state_save_register_item(names[type], index, I.nmi_state);
+ state_save_register_item(names[type], index, I.irq_state);
+ state_save_register_item(names[type], index, I.AuxVal);
+ state_save_register_item(names[type], index, I.OverVal);
+ state_save_register_item(names[type], index, I.ZeroVal);
+ state_save_register_item(names[type], index, I.CarryVal);
+ state_save_register_item(names[type], index, I.ParityVal);
+
+ I.irq_callback = irqcallback;
+}
+
+void v30mz_init(int index, int clock, const void *config, int (*irqcallback)(int)) { nec_init(index, clock, config, irqcallback, 3); }
+int v30mz_execute(int cycles)
+{
+ nec_ICount=cycles;
+ chip_type=V30MZ;
+
+ while(nec_ICount>0) {
+ /* Dispatch IRQ */
+ if (I.pending_irq && I.no_interrupt==0)
+ {
+ if (I.pending_irq & NMI_IRQ)
+ external_int();
+ else if (I.IF)
+ external_int();
+ }
+
+ /* No interrupt allowed between last instruction and this one */
+ if (I.no_interrupt)
+ I.no_interrupt--;
+
+ CALL_MAME_DEBUG;
+ nec_instruction[FETCHOP]();
+ }
+
+ return cycles - nec_ICount;
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void nec_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + NEC_PC:
+ if( info->i - (I.sregs[CS]<<4) < 0x10000 )
+ {
+ I.ip = info->i - (I.sregs[CS]<<4);
+ }
+ else
+ {
+ I.sregs[CS] = info->i >> 4;
+ I.ip = info->i & 0x0000f;
+ }
+ break;
+ case CPUINFO_INT_REGISTER + NEC_IP: I.ip = info->i; break;
+ case CPUINFO_INT_SP:
+ if( info->i - (I.sregs[SS]<<4) < 0x10000 )
+ {
+ I.regs.w[SP] = info->i - (I.sregs[SS]<<4);
+ }
+ else
+ {
+ I.sregs[SS] = info->i >> 4;
+ I.regs.w[SP] = info->i & 0x0000f;
+ }
+ break;
+ case CPUINFO_INT_REGISTER + NEC_SP: I.regs.w[SP] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_FLAGS: ExpandFlags(info->i); break;
+ case CPUINFO_INT_REGISTER + NEC_AW: I.regs.w[AW] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_CW: I.regs.w[CW] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_DW: I.regs.w[DW] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_BW: I.regs.w[BW] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_BP: I.regs.w[BP] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_IX: I.regs.w[IX] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_IY: I.regs.w[IY] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_ES: I.sregs[ES] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_CS: I.sregs[CS] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_SS: I.sregs[SS] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_DS: I.sregs[DS] = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_VECTOR: I.int_vector = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void v30mz_get_info(UINT32 state, cpuinfo *info)
+{
+ int flags;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(I); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 80; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 20; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = (I.pending_irq & INT_IRQ) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = I.nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not supported */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + NEC_PC: info->i = ((I.sregs[CS]<<4) + I.ip); break;
+ case CPUINFO_INT_REGISTER + NEC_IP: info->i = I.ip; break;
+ case CPUINFO_INT_SP: info->i = (I.sregs[SS]<<4) + I.regs.w[SP]; break;
+ case CPUINFO_INT_REGISTER + NEC_SP: info->i = I.regs.w[SP]; break;
+ case CPUINFO_INT_REGISTER + NEC_FLAGS: info->i = CompressFlags(); break;
+ case CPUINFO_INT_REGISTER + NEC_AW: info->i = I.regs.w[AW]; break;
+ case CPUINFO_INT_REGISTER + NEC_CW: info->i = I.regs.w[CW]; break;
+ case CPUINFO_INT_REGISTER + NEC_DW: info->i = I.regs.w[DW]; break;
+ case CPUINFO_INT_REGISTER + NEC_BW: info->i = I.regs.w[BW]; break;
+ case CPUINFO_INT_REGISTER + NEC_BP: info->i = I.regs.w[BP]; break;
+ case CPUINFO_INT_REGISTER + NEC_IX: info->i = I.regs.w[IX]; break;
+ case CPUINFO_INT_REGISTER + NEC_IY: info->i = I.regs.w[IY]; break;
+ case CPUINFO_INT_REGISTER + NEC_ES: info->i = I.sregs[ES]; break;
+ case CPUINFO_INT_REGISTER + NEC_CS: info->i = I.sregs[CS]; break;
+ case CPUINFO_INT_REGISTER + NEC_SS: info->i = I.sregs[SS]; break;
+ case CPUINFO_INT_REGISTER + NEC_DS: info->i = I.sregs[DS]; break;
+ case CPUINFO_INT_REGISTER + NEC_VECTOR: info->i = I.int_vector; break;
+ case CPUINFO_INT_REGISTER + NEC_PENDING: info->i = I.pending_irq; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = nec_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = nec_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = nec_set_context; break;
+ case CPUINFO_PTR_RESET: info->reset = nec_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = nec_exit; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = nec_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &nec_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s = cpuintrf_temp_str(), "NEC V-Series"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s = cpuintrf_temp_str(), "1.5"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s = cpuintrf_temp_str(), "NEC emulator v1.5 by Bryan McPhail"); break;
+
+ case CPUINFO_STR_FLAGS:
+ flags = CompressFlags();
+ sprintf(info->s = cpuintrf_temp_str(), "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ flags & 0x8000 ? 'M':'.',
+ flags & 0x4000 ? '?':'.',
+ flags & 0x2000 ? '?':'.',
+ flags & 0x1000 ? '?':'.',
+ flags & 0x0800 ? 'O':'.',
+ flags & 0x0400 ? 'D':'.',
+ flags & 0x0200 ? 'I':'.',
+ flags & 0x0100 ? 'T':'.',
+ flags & 0x0080 ? 'S':'.',
+ flags & 0x0040 ? 'Z':'.',
+ flags & 0x0020 ? '?':'.',
+ flags & 0x0010 ? 'A':'.',
+ flags & 0x0008 ? '?':'.',
+ flags & 0x0004 ? 'P':'.',
+ flags & 0x0002 ? 'N':'.',
+ flags & 0x0001 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + NEC_PC: sprintf(info->s = cpuintrf_temp_str(), "PC:%04X", (I.sregs[CS]<<4) + I.ip); break;
+ case CPUINFO_STR_REGISTER + NEC_IP: sprintf(info->s = cpuintrf_temp_str(), "IP:%04X", I.ip); break;
+ case CPUINFO_STR_REGISTER + NEC_SP: sprintf(info->s = cpuintrf_temp_str(), "SP:%04X", I.regs.w[SP]); break;
+ case CPUINFO_STR_REGISTER + NEC_FLAGS: sprintf(info->s = cpuintrf_temp_str(), "F:%04X", CompressFlags()); break;
+ case CPUINFO_STR_REGISTER + NEC_AW: sprintf(info->s = cpuintrf_temp_str(), "AW:%04X", I.regs.w[AW]); break;
+ case CPUINFO_STR_REGISTER + NEC_CW: sprintf(info->s = cpuintrf_temp_str(), "CW:%04X", I.regs.w[CW]); break;
+ case CPUINFO_STR_REGISTER + NEC_DW: sprintf(info->s = cpuintrf_temp_str(), "DW:%04X", I.regs.w[DW]); break;
+ case CPUINFO_STR_REGISTER + NEC_BW: sprintf(info->s = cpuintrf_temp_str(), "BW:%04X", I.regs.w[BW]); break;
+ case CPUINFO_STR_REGISTER + NEC_BP: sprintf(info->s = cpuintrf_temp_str(), "BP:%04X", I.regs.w[BP]); break;
+ case CPUINFO_STR_REGISTER + NEC_IX: sprintf(info->s = cpuintrf_temp_str(), "IX:%04X", I.regs.w[IX]); break;
+ case CPUINFO_STR_REGISTER + NEC_IY: sprintf(info->s = cpuintrf_temp_str(), "IY:%04X", I.regs.w[IY]); break;
+ case CPUINFO_STR_REGISTER + NEC_ES: sprintf(info->s = cpuintrf_temp_str(), "ES:%04X", I.sregs[ES]); break;
+ case CPUINFO_STR_REGISTER + NEC_CS: sprintf(info->s = cpuintrf_temp_str(), "CS:%04X", I.sregs[CS]); break;
+ case CPUINFO_STR_REGISTER + NEC_SS: sprintf(info->s = cpuintrf_temp_str(), "SS:%04X", I.sregs[SS]); break;
+ case CPUINFO_STR_REGISTER + NEC_DS: sprintf(info->s = cpuintrf_temp_str(), "DS:%04X", I.sregs[DS]); break;
+ case CPUINFO_STR_REGISTER + NEC_VECTOR: sprintf(info->s = cpuintrf_temp_str(), "V:%02X", I.int_vector); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = v30mz_init;
+ break;
+ case CPUINFO_PTR_EXECUTE: info->execute = v30mz_execute;
+ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s = cpuintrf_temp_str(), "V30MZ");
+ break;
+ }
+}
+
diff --git a/src/emu/cpu/v30mz/v30mz.h b/src/emu/cpu/v30mz/v30mz.h
new file mode 100644
index 00000000000..b73f420ff41
--- /dev/null
+++ b/src/emu/cpu/v30mz/v30mz.h
@@ -0,0 +1,359 @@
+typedef enum { ES, CS, SS, DS } SREGS;
+typedef enum { AW, CW, DW, BW, SP, BP, IX, IY } WREGS;
+
+#define NEC_NMI_INT_VECTOR 2
+
+/* Cpu types, steps of 8 to help the cycle count calculation */
+#define V30MZ 24
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+#ifdef LSB_FIRST
+typedef enum { AL,AH,CL,CH,DL,DH,BL,BH,SPL,SPH,BPL,BPH,IXL,IXH,IYL,IYH } BREGS;
+#else
+typedef enum { AH,AL,CH,CL,DH,DL,BH,BL,SPH,SPL,BPH,BPL,IXH,IXL,IYH,IYL } BREGS;
+#endif
+
+/* parameter x = result, y = source 1, z = source 2 */
+
+#define SetTF(x) (I.TF = (x))
+#define SetIF(x) (I.IF = (x))
+#define SetDF(x) (I.DF = (x))
+#define SetMD(x) (I.MF = (x)) /* OB [19.07.99] Mode Flag V30 */
+
+#define SetCFB(x) (I.CarryVal = (x) & 0x100)
+#define SetCFW(x) (I.CarryVal = (x) & 0x10000)
+#define SetAF(x,y,z) (I.AuxVal = ((x) ^ ((y) ^ (z))) & 0x10)
+#define SetSF(x) (I.SignVal = (x))
+#define SetZF(x) (I.ZeroVal = (x))
+#define SetPF(x) (I.ParityVal = (x))
+
+#define SetSZPF_Byte(x) (I.SignVal=I.ZeroVal=I.ParityVal=(INT8)(x))
+#define SetSZPF_Word(x) (I.SignVal=I.ZeroVal=I.ParityVal=(INT16)(x))
+
+#define SetOFW_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x8000)
+#define SetOFB_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x80)
+#define SetOFW_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x8000)
+#define SetOFB_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x80)
+
+#define ADDB { UINT32 res=dst+src; SetCFB(res); SetOFB_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; }
+#define ADDW { UINT32 res=dst+src; SetCFW(res); SetOFW_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; }
+
+#define SUBB { UINT32 res=dst-src; SetCFB(res); SetOFB_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; }
+#define SUBW { UINT32 res=dst-src; SetCFW(res); SetOFW_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; }
+
+#define ORB dst|=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst)
+#define ORW dst|=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst)
+
+#define ANDB dst&=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst)
+#define ANDW dst&=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst)
+
+#define XORB dst^=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst)
+#define XORW dst^=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst)
+
+#define CF (I.CarryVal!=0)
+#define SF (I.SignVal<0)
+#define ZF (I.ZeroVal==0)
+#define PF parity_table[(BYTE)I.ParityVal]
+#define AF (I.AuxVal!=0)
+#define OF (I.OverVal!=0)
+#define MD (I.MF!=0)
+
+/************************************************************************/
+
+#define CHANGE_PC change_pc((I.sregs[CS]<<4) + I.ip)
+
+#define SegBase(Seg) (I.sregs[Seg] << 4)
+
+#define DefaultBase(Seg) ((seg_prefix && (Seg==DS || Seg==SS)) ? prefix_base : I.sregs[Seg] << 4)
+
+#define GetMemB(Seg,Off) ((UINT8)program_read_byte_8((DefaultBase(Seg)+(Off))))
+#define GetMemW(Seg,Off) ((UINT16) program_read_byte_8((DefaultBase(Seg)+(Off))) + (program_read_byte_8((DefaultBase(Seg)+((Off)+1)))<<8) )
+
+#define PutMemB(Seg,Off,x) { program_write_byte_8((DefaultBase(Seg)+(Off)),(x)); }
+#define PutMemW(Seg,Off,x) { PutMemB(Seg,Off,(x)&0xff); PutMemB(Seg,(Off)+1,(BYTE)((x)>>8)); }
+
+/* Todo: Remove these later - plus readword could overflow */
+#define ReadByte(ea) ((BYTE)program_read_byte_8((ea)))
+#define ReadWord(ea) (program_read_byte_8((ea))+(program_read_byte_8(((ea)+1))<<8))
+#define WriteByte(ea,val) { program_write_byte_8((ea),val); }
+#define WriteWord(ea,val) { program_write_byte_8((ea),(BYTE)(val)); program_write_byte_8(((ea)+1),(val)>>8); }
+
+#define read_port(port) io_read_byte_8(port)
+#define write_port(port,val) io_write_byte_8(port,val)
+
+#define FETCH (cpu_readop_arg((I.sregs[CS]<<4)+I.ip++))
+#define FETCHOP (cpu_readop((I.sregs[CS]<<4)+I.ip++))
+#define FETCHWORD(var) { var=cpu_readop_arg((((I.sregs[CS]<<4)+I.ip)))+(cpu_readop_arg((((I.sregs[CS]<<4)+I.ip+1)))<<8); I.ip+=2; }
+#define PUSH(val) { I.regs.w[SP]-=2; WriteWord((((I.sregs[SS]<<4)+I.regs.w[SP])),val); }
+#define POP(var) { var = ReadWord((((I.sregs[SS]<<4)+I.regs.w[SP]))); I.regs.w[SP]+=2; }
+#define PEEK(addr) ((BYTE)cpu_readop_arg(addr))
+#define PEEKOP(addr) ((BYTE)cpu_readop(addr))
+
+#define GetModRM UINT32 ModRM=cpu_readop_arg((I.sregs[CS]<<4)+I.ip++)
+
+/* Cycle count macros:
+ CLK - cycle count is the same on all processors
+ CLKS - cycle count differs between processors, list all counts
+ CLKW - cycle count for word read/write differs for odd/even source/destination address
+ CLKM - cycle count for reg/mem instructions
+ CLKR - cycle count for reg/mem instructions with different counts for odd/even addresses
+
+
+ Prefetch & buswait time is not emulated.
+ Extra cycles for PUSH'ing or POP'ing registers to odd addresses is not emulated.
+*/
+
+#define CLK(v30mz) { nec_ICount-=v30mz; }
+#define CLKM(v30mz,v30mzm) { nec_ICount-=( ModRM >=0xc0 )?v30mz:v30mzm; }
+
+/************************************************************************/
+#define CompressFlags() (WORD)(CF | (PF << 2) | (AF << 4) | (ZF << 6) \
+ | (SF << 7) | (I.TF << 8) | (I.IF << 9) \
+ | (I.DF << 10) | (OF << 11)| (MD << 15))
+
+#define ExpandFlags(f) \
+{ \
+ I.CarryVal = (f) & 1; \
+ I.ParityVal = !((f) & 4); \
+ I.AuxVal = (f) & 16; \
+ I.ZeroVal = !((f) & 64); \
+ I.SignVal = (f) & 128 ? -1 : 0; \
+ I.TF = ((f) & 256) == 256; \
+ I.IF = ((f) & 512) == 512; \
+ I.DF = ((f) & 1024) == 1024; \
+ I.OverVal = (f) & 2048; \
+ I.MF = ((f) & 0x8000) == 0x8000; \
+}
+
+#define IncWordReg(Reg) \
+ unsigned tmp = (unsigned)I.regs.w[Reg]; \
+ unsigned tmp1 = tmp+1; \
+ I.OverVal = (tmp == 0x7fff); \
+ SetAF(tmp1,tmp,1); \
+ SetSZPF_Word(tmp1); \
+ I.regs.w[Reg]=tmp1
+
+#define DecWordReg(Reg) \
+ unsigned tmp = (unsigned)I.regs.w[Reg]; \
+ unsigned tmp1 = tmp-1; \
+ I.OverVal = (tmp == 0x8000); \
+ SetAF(tmp1,tmp,1); \
+ SetSZPF_Word(tmp1); \
+ I.regs.w[Reg]=tmp1
+
+#define JMP(flag) \
+ int tmp = (int)((INT8)FETCH); \
+ if (flag) \
+ { \
+ static const UINT8 table[3]={3,10,10}; \
+ I.ip = (WORD)(I.ip+tmp); \
+ nec_ICount-=table[chip_type/8]; \
+ CHANGE_PC; \
+ return; \
+ }
+
+#define ADJ4(param1,param2) \
+ if (AF || ((I.regs.b[AL] & 0xf) > 9)) \
+ { \
+ UINT16 tmp; \
+ tmp = I.regs.b[AL] + param1; \
+ I.regs.b[AL] = tmp; \
+ I.AuxVal = 1; \
+ I.CarryVal |= tmp & 0x100; \
+ } \
+ if (CF || (I.regs.b[AL]>0x9f)) \
+ { \
+ I.regs.b[AL] += param2; \
+ I.CarryVal = 1; \
+ } \
+ SetSZPF_Byte(I.regs.b[AL])
+
+#define ADJB(param1,param2) \
+ if (AF || ((I.regs.b[AL] & 0xf) > 9)) \
+ { \
+ I.regs.b[AL] += param1; \
+ I.regs.b[AH] += param2; \
+ I.AuxVal = 1; \
+ I.CarryVal = 1; \
+ } \
+ else \
+ { \
+ I.AuxVal = 0; \
+ I.CarryVal = 0; \
+ } \
+ I.regs.b[AL] &= 0x0F
+
+#define BITOP_BYTE \
+ ModRM = FETCH; \
+ if (ModRM >= 0xc0) { \
+ tmp=I.regs.b[Mod_RM.RM.b[ModRM]]; \
+ } \
+ else { \
+ (*GetEA[ModRM])(); \
+ tmp=ReadByte(EA); \
+ }
+
+#define BITOP_WORD \
+ ModRM = FETCH; \
+ if (ModRM >= 0xc0) { \
+ tmp=I.regs.w[Mod_RM.RM.w[ModRM]]; \
+ } \
+ else { \
+ (*GetEA[ModRM])(); \
+ tmp=ReadWord(EA); \
+ }
+
+#define BIT_NOT \
+ if (tmp & (1<<tmp2)) \
+ tmp &= ~(1<<tmp2); \
+ else \
+ tmp |= (1<<tmp2)
+
+#define XchgAWReg(Reg) \
+ WORD tmp; \
+ tmp = I.regs.w[Reg]; \
+ I.regs.w[Reg] = I.regs.w[AW]; \
+ I.regs.w[AW] = tmp
+
+#define ROL_BYTE I.CarryVal = dst & 0x80; dst = (dst << 1)+CF
+#define ROL_WORD I.CarryVal = dst & 0x8000; dst = (dst << 1)+CF
+#define ROR_BYTE I.CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<7)
+#define ROR_WORD I.CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<15)
+#define ROLC_BYTE dst = (dst << 1) + CF; SetCFB(dst)
+#define ROLC_WORD dst = (dst << 1) + CF; SetCFW(dst)
+#define RORC_BYTE dst = (CF<<8)+dst; I.CarryVal = dst & 0x01; dst >>= 1
+#define RORC_WORD dst = (CF<<16)+dst; I.CarryVal = dst & 0x01; dst >>= 1
+#define SHL_BYTE(c) nec_ICount-=c; dst <<= c; SetCFB(dst); SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst)
+#define SHL_WORD(c) nec_ICount-=c; dst <<= c; SetCFW(dst); SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst)
+#define SHR_BYTE(c) nec_ICount-=c; dst >>= c-1; I.CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst)
+#define SHR_WORD(c) nec_ICount-=c; dst >>= c-1; I.CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst)
+#define SHRA_BYTE(c) nec_ICount-=c; dst = ((INT8)dst) >> (c-1); I.CarryVal = dst & 0x1; dst = ((INT8)((BYTE)dst)) >> 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst)
+#define SHRA_WORD(c) nec_ICount-=c; dst = ((INT16)dst) >> (c-1); I.CarryVal = dst & 0x1; dst = ((INT16)((WORD)dst)) >> 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst)
+
+#define DIVUB \
+ uresult = I.regs.w[AW]; \
+ uresult2 = uresult % tmp; \
+ if ((uresult /= tmp) > 0xff) { \
+ nec_interrupt(0,0); break; \
+ } else { \
+ I.regs.b[AL] = uresult; \
+ I.regs.b[AH] = uresult2; \
+ }
+
+#define DIVB \
+ result = (INT16)I.regs.w[AW]; \
+ result2 = result % (INT16)((INT8)tmp); \
+ if ((result /= (INT16)((INT8)tmp)) > 0xff) { \
+ nec_interrupt(0,0); break; \
+ } else { \
+ I.regs.b[AL] = result; \
+ I.regs.b[AH] = result2; \
+ }
+
+#define DIVUW \
+ uresult = (((UINT32)I.regs.w[DW]) << 16) | I.regs.w[AW];\
+ uresult2 = uresult % tmp; \
+ if ((uresult /= tmp) > 0xffff) { \
+ nec_interrupt(0,0); break; \
+ } else { \
+ I.regs.w[AW]=uresult; \
+ I.regs.w[DW]=uresult2; \
+ }
+
+#define DIVW \
+ result = ((UINT32)I.regs.w[DW] << 16) + I.regs.w[AW]; \
+ result2 = result % (INT32)((INT16)tmp); \
+ if ((result /= (INT32)((INT16)tmp)) > 0xffff) { \
+ nec_interrupt(0,0); break; \
+ } else { \
+ I.regs.w[AW]=result; \
+ I.regs.w[DW]=result2; \
+ }
+
+#define ADD4S { \
+ int i,v1,v2,result; \
+ int count = (I.regs.b[CL]+1)/2; \
+ unsigned di = I.regs.w[IY]; \
+ unsigned si = I.regs.w[IX]; \
+ static const UINT8 table[3]={18,19,19}; \
+ if (seg_prefix) logerror("%06x: Warning: seg_prefix defined for add4s\n",activecpu_get_pc()); \
+ I.ZeroVal = I.CarryVal = 0; \
+ for (i=0;i<count;i++) { \
+ nec_ICount-=table[chip_type/8]; \
+ tmp = GetMemB(DS, si); \
+ tmp2 = GetMemB(ES, di); \
+ v1 = (tmp>>4)*10 + (tmp&0xf); \
+ v2 = (tmp2>>4)*10 + (tmp2&0xf); \
+ result = v1+v2+I.CarryVal; \
+ I.CarryVal = result > 99 ? 1 : 0; \
+ result = result % 100; \
+ v1 = ((result/10)<<4) | (result % 10); \
+ PutMemB(ES, di,v1); \
+ if (v1) I.ZeroVal = 1; \
+ si++; \
+ di++; \
+ } \
+}
+
+#define SUB4S { \
+ int count = (I.regs.b[CL]+1)/2; \
+ int i,v1,v2,result; \
+ unsigned di = I.regs.w[IY]; \
+ unsigned si = I.regs.w[IX]; \
+ static const UINT8 table[3]={18,19,19}; \
+ if (seg_prefix) logerror("%06x: Warning: seg_prefix defined for sub4s\n",activecpu_get_pc()); \
+ I.ZeroVal = I.CarryVal = 0; \
+ for (i=0;i<count;i++) { \
+ nec_ICount-=table[chip_type/8]; \
+ tmp = GetMemB(ES, di); \
+ tmp2 = GetMemB(DS, si); \
+ v1 = (tmp>>4)*10 + (tmp&0xf); \
+ v2 = (tmp2>>4)*10 + (tmp2&0xf); \
+ if (v1 < (v2+I.CarryVal)) { \
+ v1+=100; \
+ result = v1-(v2+I.CarryVal); \
+ I.CarryVal = 1; \
+ } else { \
+ result = v1-(v2+I.CarryVal); \
+ I.CarryVal = 0; \
+ } \
+ v1 = ((result/10)<<4) | (result % 10); \
+ PutMemB(ES, di,v1); \
+ if (v1) I.ZeroVal = 1; \
+ si++; \
+ di++; \
+ } \
+}
+
+#define CMP4S { \
+ int count = (I.regs.b[CL]+1)/2; \
+ int i,v1,v2,result; \
+ unsigned di = I.regs.w[IY]; \
+ unsigned si = I.regs.w[IX]; \
+ static const UINT8 table[3]={14,19,19}; \
+ if (seg_prefix) logerror("%06x: Warning: seg_prefix defined for cmp4s\n",activecpu_get_pc()); \
+ I.ZeroVal = I.CarryVal = 0; \
+ for (i=0;i<count;i++) { \
+ nec_ICount-=table[chip_type/8]; \
+ tmp = GetMemB(ES, di); \
+ tmp2 = GetMemB(DS, si); \
+ v1 = (tmp>>4)*10 + (tmp&0xf); \
+ v2 = (tmp2>>4)*10 + (tmp2&0xf); \
+ if (v1 < (v2+I.CarryVal)) { \
+ v1+=100; \
+ result = v1-(v2+I.CarryVal); \
+ I.CarryVal = 1; \
+ } else { \
+ result = v1-(v2+I.CarryVal); \
+ I.CarryVal = 0; \
+ } \
+ v1 = ((result/10)<<4) | (result % 10); \
+ if (v1) I.ZeroVal = 1; \
+ si++; \
+ di++; \
+ } \
+}
diff --git a/src/emu/cpu/v60/am.c b/src/emu/cpu/v60/am.c
new file mode 100644
index 00000000000..d386e25d8a3
--- /dev/null
+++ b/src/emu/cpu/v60/am.c
@@ -0,0 +1,102 @@
+
+// NOTE for bit string/field addressing
+// ************************************
+// modDim must be passed as 10 for bit string instructions,
+// and as 11 for bit field instructions
+
+
+
+// Output variables for ReadAMAddress()
+static UINT8 amFlag;
+static UINT32 amOut;
+static UINT32 bamOffset;
+
+// Appo temp var
+static UINT32 amLength1,amLength2;
+
+
+// Global vars used by AM functions
+static UINT32 modAdd;
+static UINT8 modM;
+static UINT8 modVal;
+static UINT8 modVal2;
+static UINT8 modWriteValB;
+static UINT16 modWriteValH;
+static UINT32 modWriteValW;
+static UINT8 modDim;
+
+// Addressing mode functions and tables
+#include "am1.c" // ReadAM
+#include "am2.c" // ReadAMAddress
+#include "am3.c" // WriteAM
+
+/*
+ Input:
+ modAdd
+ modDim
+
+ Output:
+ amOut
+ amLength
+*/
+
+static UINT32 ReadAM(void)
+{
+ modM=modM?1:0;
+ modVal=OpRead8(modAdd);
+ return AMTable1[modM][modVal>>5]();
+}
+
+static UINT32 BitReadAM(void)
+{
+ modM=modM?1:0;
+ modVal=OpRead8(modAdd);
+ return BAMTable1[modM][modVal>>5]();
+}
+
+
+
+/*
+ Input:
+ modAdd
+ modDim
+
+ Output:
+ amOut
+ amFlag
+ amLength
+*/
+
+static UINT32 ReadAMAddress(void)
+{
+ modM=modM?1:0;
+ modVal=OpRead8(modAdd);
+ return AMTable2[modM][modVal>>5]();
+}
+
+static UINT32 BitReadAMAddress(void)
+{
+ modM=modM?1:0;
+ modVal=OpRead8(modAdd);
+ return BAMTable2[modM][modVal>>5]();
+}
+
+/*
+ Input:
+ modAdd
+ modDim
+ modWriteValB/H/W
+
+ Output:
+ amOut
+ amLength
+*/
+
+static UINT32 WriteAM(void)
+{
+ modM=modM?1:0;
+ modVal=OpRead8(modAdd);
+ return AMTable3[modM][modVal>>5]();
+}
+
+
diff --git a/src/emu/cpu/v60/am1.c b/src/emu/cpu/v60/am1.c
new file mode 100644
index 00000000000..3377c604a64
--- /dev/null
+++ b/src/emu/cpu/v60/am1.c
@@ -0,0 +1,1391 @@
+
+// AM1 Functions (for ReadAM)
+// **************************
+
+static UINT32 am1Register(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=(UINT8)v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut=(UINT16)v60.reg[modVal&0x1F];
+ break;
+ case 2:
+ amOut=v60.reg[modVal&0x1F];
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 am1RegisterIndirect(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(v60.reg[modVal&0x1F]);
+ break;
+ case 2:
+ amOut=MemRead32(v60.reg[modVal&0x1F]);
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 bam1RegisterIndirect(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(v60.reg[modVal&0x1F]);
+ return 1;
+}
+
+static UINT32 am1RegisterIndirectIndexed(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(v60.reg[modVal2&0x1F]+v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(v60.reg[modVal2&0x1F]+v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(v60.reg[modVal2&0x1F]+v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 bam1RegisterIndirectIndexed(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(v60.reg[modVal2&0x1F]+bamOffset/8);
+ bamOffset&=7;
+ return 2;
+}
+
+static UINT32 am1Autoincrement(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(v60.reg[modVal&0x1F]);
+ v60.reg[modVal&0x1F]++;
+ break;
+ case 1:
+ amOut=MemRead16(v60.reg[modVal&0x1F]);
+ v60.reg[modVal&0x1F]+=2;
+ break;
+ case 2:
+ amOut=MemRead32(v60.reg[modVal&0x1F]);
+ v60.reg[modVal&0x1F]+=4;
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 bam1Autoincrement(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(v60.reg[modVal&0x1F]);
+ switch (modDim)
+ {
+ case 10:
+ v60.reg[modVal&0x1F]+=1;
+ break;
+ case 11:
+ v60.reg[modVal&0x1F]+=4;
+ break;
+ default:
+ fatalerror("CPU - BAM1 - 7");
+ break;
+ }
+ return 1;
+}
+
+static UINT32 am1Autodecrement(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ v60.reg[modVal&0x1F]--;
+ amOut=MemRead8(v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ v60.reg[modVal&0x1F]-=2;
+ amOut=MemRead16(v60.reg[modVal&0x1F]);
+ break;
+ case 2:
+ v60.reg[modVal&0x1F]-=4;
+ amOut=MemRead32(v60.reg[modVal&0x1F]);
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 bam1Autodecrement(void)
+{
+ bamOffset=0;
+ switch (modDim)
+ {
+ case 10:
+ v60.reg[modVal&0x1F]-=1;
+ break;
+ case 11:
+ v60.reg[modVal&0x1F]-=4;
+ break;
+ default:
+ fatalerror("CPU - BAM1 - 7");
+ break;
+ }
+ amOut=MemRead32(v60.reg[modVal&0x1F]);
+ return 1;
+}
+
+static UINT32 am1Displacement8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1));
+ break;
+ case 1:
+ amOut=MemRead16(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1));
+ break;
+ case 2:
+ amOut=MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1));
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 bam1Displacement8(void)
+{
+ bamOffset=MemRead8(modAdd+1);
+ amOut=MemRead32(v60.reg[modVal&0x1F]+bamOffset/8);
+ bamOffset&=7;
+ return 2;
+}
+
+
+static UINT32 am1Displacement16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1));
+ break;
+ case 1:
+ amOut=MemRead16(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1));
+ break;
+ case 2:
+ amOut=MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1));
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1Displacement16(void)
+{
+ bamOffset=OpRead16(modAdd+1);
+ amOut=MemRead32(v60.reg[modVal&0x1F]+bamOffset/8);
+ bamOffset&=7;
+ return 3;
+}
+
+static UINT32 am1Displacement32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(v60.reg[modVal&0x1F] + OpRead32(modAdd+1));
+ break;
+ case 1:
+ amOut=MemRead16(v60.reg[modVal&0x1F] + OpRead32(modAdd+1));
+ break;
+ case 2:
+ amOut=MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1));
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 bam1Displacement32(void)
+{
+ bamOffset=OpRead32(modAdd+1);
+ amOut=MemRead32(v60.reg[modVal&0x1F]+bamOffset/8);
+ bamOffset&=7;
+ return 5;
+}
+
+static UINT32 am1DisplacementIndexed8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1DisplacementIndexed8(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)+bamOffset/8);
+ bamOffset&=7;
+ return 3;
+}
+
+static UINT32 am1DisplacementIndexed16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 bam1DisplacementIndexed16(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)+bamOffset/8);
+ bamOffset&=7;
+ return 4;
+}
+
+static UINT32 am1DisplacementIndexed32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam1DisplacementIndexed32(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)+bamOffset/8);
+ bamOffset&=7;
+ return 6;
+}
+
+
+static UINT32 am1PCDisplacement8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(PC + (INT8)OpRead8(modAdd+1));
+ break;
+ case 1:
+ amOut=MemRead16(PC + (INT8)OpRead8(modAdd+1));
+ break;
+ case 2:
+ amOut=MemRead32(PC + (INT8)OpRead8(modAdd+1));
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 bam1PCDisplacement8(void)
+{
+ bamOffset=OpRead8(modAdd+1);
+ amOut=MemRead32(PC+bamOffset/8);
+ bamOffset&=7;
+ return 2;
+}
+
+static UINT32 am1PCDisplacement16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(PC + (INT16)OpRead16(modAdd+1));
+ break;
+ case 1:
+ amOut=MemRead16(PC + (INT16)OpRead16(modAdd+1));
+ break;
+ case 2:
+ amOut=MemRead32(PC + (INT16)OpRead16(modAdd+1));
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1PCDisplacement16(void)
+{
+ bamOffset=OpRead16(modAdd+1);
+ amOut=MemRead32(PC+bamOffset/8);
+ bamOffset&=7;
+ return 3;
+}
+
+static UINT32 am1PCDisplacement32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(PC + OpRead32(modAdd+1));
+ break;
+ case 1:
+ amOut=MemRead16(PC + OpRead32(modAdd+1));
+ break;
+ case 2:
+ amOut=MemRead32(PC + OpRead32(modAdd+1));
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 bam1PCDisplacement32(void)
+{
+ bamOffset=OpRead32(modAdd+1);
+ amOut=MemRead32(PC+bamOffset/8);
+ bamOffset&=7;
+ return 5;
+}
+
+static UINT32 am1PCDisplacementIndexed8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1PCDisplacementIndexed8(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(PC + (INT8)OpRead8(modAdd+2)+bamOffset/8);
+ bamOffset&=7;
+ return 3;
+}
+
+
+static UINT32 am1PCDisplacementIndexed16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 bam1PCDisplacementIndexed16(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(PC + (INT16)OpRead16(modAdd+2)+bamOffset/8);
+ bamOffset&=7;
+ return 4;
+}
+
+static UINT32 am1PCDisplacementIndexed32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam1PCDisplacementIndexed32(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(PC + OpRead32(modAdd+2)+bamOffset/8);
+ bamOffset&=7;
+ return 6;
+}
+
+static UINT32 am1DisplacementIndirect8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)));
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)));
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)));
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 bam1DisplacementIndirect8(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)));
+ return 2;
+}
+
+static UINT32 am1DisplacementIndirect16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)));
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)));
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)));
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1DisplacementIndirect16(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)));
+ return 3;
+}
+
+static UINT32 am1DisplacementIndirect32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)));
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)));
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)));
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 bam1DisplacementIndirect32(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)));
+ return 5;
+}
+
+static UINT32 am1DisplacementIndirectIndexed8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1DisplacementIndirectIndexed8(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2))+bamOffset/8);
+ bamOffset&=7;
+ return 3;
+}
+
+static UINT32 am1DisplacementIndirectIndexed16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 bam1DisplacementIndirectIndexed16(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2))+bamOffset/8);
+ bamOffset&=7;
+ return 4;
+}
+
+static UINT32 am1DisplacementIndirectIndexed32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam1DisplacementIndirectIndexed32(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2))+bamOffset/8);
+ bamOffset&=7;
+ return 6;
+}
+
+static UINT32 am1PCDisplacementIndirect8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(PC + (INT8)OpRead8(modAdd+1)));
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(PC + (INT8)OpRead8(modAdd+1)));
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(PC + (INT8)OpRead8(modAdd+1)));
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 bam1PCDisplacementIndirect8(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(MemRead32(PC + (INT8)OpRead8(modAdd+1)));
+ return 2;
+}
+
+static UINT32 am1PCDisplacementIndirect16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(PC + (INT16)OpRead16(modAdd+1)));
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(PC + (INT16)OpRead16(modAdd+1)));
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(PC + (INT16)OpRead16(modAdd+1)));
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1PCDisplacementIndirect16(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(MemRead32(PC + (INT16)OpRead16(modAdd+1)));
+ return 3;
+}
+
+static UINT32 am1PCDisplacementIndirect32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(PC + OpRead32(modAdd+1)));
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(PC + OpRead32(modAdd+1)));
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(PC + OpRead32(modAdd+1)));
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 bam1PCDisplacementIndirect32(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(MemRead32(PC + OpRead32(modAdd+1)));
+ return 5;
+}
+
+static UINT32 am1PCDisplacementIndirectIndexed8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1PCDisplacementIndirectIndexed8(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(MemRead32(PC + (INT8)OpRead8(modAdd+2))+bamOffset/8);
+ bamOffset&=7;
+ return 3;
+}
+
+static UINT32 am1PCDisplacementIndirectIndexed16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 bam1PCDisplacementIndirectIndexed16(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(MemRead32(PC + (INT16)OpRead16(modAdd+2))+bamOffset/8);
+ bamOffset&=7;
+ return 4;
+}
+
+static UINT32 am1PCDisplacementIndirectIndexed32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F]);
+ break;
+ case 1:
+ amOut=MemRead16(MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F]*2);
+ break;
+ case 2:
+ amOut=MemRead32(MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam1PCDisplacementIndirectIndexed32(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(MemRead32(PC + OpRead32(modAdd+2))+bamOffset/8);
+ bamOffset&=7;
+ return 6;
+}
+
+static UINT32 am1DoubleDisplacement8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2));
+ break;
+
+ case 1:
+ amOut=MemRead16(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2));
+ break;
+
+ case 2:
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2));
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1DoubleDisplacement8(void)
+{
+ bamOffset=OpRead8(modAdd+2);
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1))+bamOffset/8);
+ bamOffset&=7;
+ return 3;
+}
+
+static UINT32 am1DoubleDisplacement16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3));
+ break;
+
+ case 1:
+ amOut=MemRead16(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3));
+ break;
+
+ case 2:
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3));
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 bam1DoubleDisplacement16(void)
+{
+ bamOffset=OpRead16(modAdd+3);
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1))+bamOffset/8);
+ bamOffset&=7;
+ return 5;
+}
+
+static UINT32 am1DoubleDisplacement32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)) + OpRead32(modAdd+5));
+ break;
+
+ case 1:
+ amOut=MemRead16(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)) + OpRead32(modAdd+5));
+ break;
+
+ case 2:
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)) + OpRead32(modAdd+5));
+ break;
+ }
+
+ return 9;
+}
+
+static UINT32 bam1DoubleDisplacement32(void)
+{
+ bamOffset=OpRead32(modAdd+5);
+ amOut=MemRead32(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1))+bamOffset/8);
+ bamOffset&=7;
+ return 9;
+}
+
+static UINT32 am1PCDoubleDisplacement8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(PC + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2));
+ break;
+
+ case 1:
+ amOut=MemRead16(MemRead32(PC + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2));
+ break;
+
+ case 2:
+ amOut=MemRead32(MemRead32(PC + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2));
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam1PCDoubleDisplacement8(void)
+{
+ bamOffset=OpRead8(modAdd+2);
+ amOut=MemRead32(MemRead32(PC + (INT8)OpRead8(modAdd+1))+bamOffset/8);
+ bamOffset&=7;
+ return 3;
+}
+
+static UINT32 am1PCDoubleDisplacement16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(PC + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3));
+ break;
+
+ case 1:
+ amOut=MemRead16(MemRead32(PC + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3));
+ break;
+
+ case 2:
+ amOut=MemRead32(MemRead32(PC + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3));
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 bam1PCDoubleDisplacement16(void)
+{
+ bamOffset=OpRead16(modAdd+3);
+ amOut=MemRead32(MemRead32(PC + (INT16)OpRead16(modAdd+1))+bamOffset/8);
+ bamOffset&=7;
+ return 5;
+}
+
+
+static UINT32 am1PCDoubleDisplacement32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(PC + OpRead32(modAdd+1)) + OpRead32(modAdd+5));
+ break;
+
+ case 1:
+ amOut=MemRead16(MemRead32(PC + OpRead32(modAdd+1)) + OpRead32(modAdd+5));
+ break;
+
+ case 2:
+ amOut=MemRead32(MemRead32(PC + OpRead32(modAdd+1)) + OpRead32(modAdd+5));
+ break;
+ }
+
+ return 9;
+}
+
+static UINT32 bam1PCDoubleDisplacement32(void)
+{
+ bamOffset=OpRead32(modAdd+5);
+ amOut=MemRead32(MemRead32(PC + OpRead32(modAdd+1))+bamOffset/8);
+ bamOffset&=7;
+ return 9;
+}
+
+static UINT32 am1DirectAddress(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(OpRead32(modAdd+1));
+ break;
+
+ case 1:
+ amOut=MemRead16(OpRead32(modAdd+1));
+ break;
+
+ case 2:
+ amOut=MemRead32(OpRead32(modAdd+1));
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 bam1DirectAddress(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(OpRead32(modAdd+1));
+ return 5;
+}
+
+static UINT32 am1DirectAddressIndexed(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(OpRead32(modAdd+2) + v60.reg[modVal&0x1F]);
+ break;
+
+ case 1:
+ amOut=MemRead16(OpRead32(modAdd+2) + v60.reg[modVal&0x1F]*2);
+ break;
+
+ case 2:
+ amOut=MemRead32(OpRead32(modAdd+2) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam1DirectAddressIndexed(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(OpRead32(modAdd+2)+bamOffset/8);
+ bamOffset&=7;
+ return 6;
+}
+
+static UINT32 am1DirectAddressDeferred(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(OpRead32(modAdd+1)));
+ break;
+
+ case 1:
+ amOut=MemRead16(MemRead32(OpRead32(modAdd+1)));
+ break;
+
+ case 2:
+ amOut=MemRead32(MemRead32(OpRead32(modAdd+1)));
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 bam1DirectAddressDeferred(void)
+{
+ bamOffset=0;
+ amOut=MemRead32(MemRead32(OpRead32(modAdd+1)));
+ return 5;
+}
+
+static UINT32 am1DirectAddressDeferredIndexed(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=MemRead8(MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F]);
+ break;
+
+ case 1:
+ amOut=MemRead16(MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F]*2);
+ break;
+
+ case 2:
+ amOut=MemRead32(MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F]*4);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam1DirectAddressDeferredIndexed(void)
+{
+ bamOffset=v60.reg[modVal&0x1F];
+ amOut=MemRead32(MemRead32(OpRead32(modAdd+2))+bamOffset/8);
+ bamOffset&=7;
+ return 6;
+}
+
+static UINT32 am1Immediate(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ amOut=OpRead8(modAdd+1);
+ return 2;
+ break;
+
+ case 1:
+ amOut=OpRead16(modAdd+1);
+ return 3;
+ break;
+
+ case 2:
+ amOut=OpRead32(modAdd+1);
+ return 5;
+ break;
+ }
+
+ // It should not be here! Written to avoid warning
+ assert(0);
+ return 1;
+}
+
+static UINT32 am1ImmediateQuick(void)
+{
+ amOut=modVal&0xF;
+ return 1;
+}
+
+
+
+
+// AM1 Tables (for ReadAM)
+// ***********************
+
+static UINT32 am1Error1(void)
+{
+ fatalerror("CPU - AM1 - 1 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam1Error1(void)
+{
+ fatalerror("CPU - BAM1 - 1 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 am1Error2(void)
+{
+ fatalerror("CPU - AM1 - 2 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam1Error2(void)
+{
+ fatalerror("CPU - BAM1 - 2 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+#ifdef UNUSED_FUNCTION
+static UINT32 am1Error3(void)
+{
+ fatalerror("CPU - AM1 - 3 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam1Error3(void)
+{
+ fatalerror("CPU - BAM1 - 3 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+#endif
+
+static UINT32 am1Error4(void)
+{
+ fatalerror("CPU - AM1 - 4 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam1Error4(void)
+{
+ fatalerror("CPU - BAM1 - 4 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 am1Error5(void)
+{
+ fatalerror("CPU - AM1 - 5 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam1Error5(void)
+{
+ fatalerror("CPU - BAM1 - 5 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam1Error6(void)
+{
+ fatalerror("CPU - BAM1 - 6 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 (*const AMTable1_G7a[16])(void) =
+{
+ am1PCDisplacementIndexed8,
+ am1PCDisplacementIndexed16,
+ am1PCDisplacementIndexed32,
+ am1DirectAddressIndexed,
+ am1Error5,
+ am1Error5,
+ am1Error5,
+ am1Error5,
+ am1PCDisplacementIndirectIndexed8,
+ am1PCDisplacementIndirectIndexed16,
+ am1PCDisplacementIndirectIndexed32,
+ am1DirectAddressDeferredIndexed,
+ am1Error5,
+ am1Error5,
+ am1Error5,
+ am1Error5
+};
+
+static UINT32 (*const BAMTable1_G7a[16])(void) =
+{
+ bam1PCDisplacementIndexed8,
+ bam1PCDisplacementIndexed16,
+ bam1PCDisplacementIndexed32,
+ bam1DirectAddressIndexed,
+ bam1Error5,
+ bam1Error5,
+ bam1Error5,
+ bam1Error5,
+ bam1PCDisplacementIndirectIndexed8,
+ bam1PCDisplacementIndirectIndexed16,
+ bam1PCDisplacementIndirectIndexed32,
+ bam1DirectAddressDeferredIndexed,
+ bam1Error5,
+ bam1Error5,
+ bam1Error5,
+ bam1Error5
+};
+
+
+static UINT32 am1Group7a(void)
+{
+ if (!(modVal2&0x10))
+ return am1Error4();
+
+ return AMTable1_G7a[modVal2&0xF]();
+}
+
+static UINT32 bam1Group7a(void)
+{
+ if (!(modVal2&0x10))
+ return bam1Error4();
+
+ return BAMTable1_G7a[modVal2&0xF]();
+}
+
+static UINT32 (*const AMTable1_G7[32])(void) =
+{
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1ImmediateQuick,
+ am1PCDisplacement8,
+ am1PCDisplacement16,
+ am1PCDisplacement32,
+ am1DirectAddress,
+ am1Immediate,
+ am1Error2,
+ am1Error2,
+ am1Error2,
+ am1PCDisplacementIndirect8,
+ am1PCDisplacementIndirect16,
+ am1PCDisplacementIndirect32,
+ am1DirectAddressDeferred,
+ am1PCDoubleDisplacement8,
+ am1PCDoubleDisplacement16,
+ am1PCDoubleDisplacement32,
+ am1Error2
+};
+
+static UINT32 (*const BAMTable1_G7[32])(void) =
+{
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1Error6,
+ bam1PCDisplacement8,
+ bam1PCDisplacement16,
+ bam1PCDisplacement32,
+ bam1DirectAddress,
+ bam1Error6,
+ bam1Error2,
+ bam1Error2,
+ bam1Error2,
+ bam1PCDisplacementIndirect8,
+ bam1PCDisplacementIndirect16,
+ bam1PCDisplacementIndirect32,
+ bam1DirectAddressDeferred,
+ bam1PCDoubleDisplacement8,
+ bam1PCDoubleDisplacement16,
+ bam1PCDoubleDisplacement32,
+ bam1Error2
+};
+
+
+
+static UINT32 (*const AMTable1_G6[8])(void) =
+{
+ am1DisplacementIndexed8,
+ am1DisplacementIndexed16,
+ am1DisplacementIndexed32,
+ am1RegisterIndirectIndexed,
+ am1DisplacementIndirectIndexed8,
+ am1DisplacementIndirectIndexed16,
+ am1DisplacementIndirectIndexed32,
+ am1Group7a
+};
+
+static UINT32 (*const BAMTable1_G6[8])(void) =
+{
+ bam1DisplacementIndexed8,
+ bam1DisplacementIndexed16,
+ bam1DisplacementIndexed32,
+ bam1RegisterIndirectIndexed,
+ bam1DisplacementIndirectIndexed8,
+ bam1DisplacementIndirectIndexed16,
+ bam1DisplacementIndirectIndexed32,
+ bam1Group7a
+};
+
+
+static UINT32 am1Group6(void)
+{
+ modVal2=OpRead8(modAdd+1);
+ return AMTable1_G6[modVal2>>5]();
+}
+
+static UINT32 bam1Group6(void)
+{
+ modVal2=OpRead8(modAdd+1);
+ return BAMTable1_G6[modVal2>>5]();
+}
+
+
+static UINT32 am1Group7(void)
+{
+ return AMTable1_G7[modVal&0x1F]();
+}
+
+static UINT32 bam1Group7(void)
+{
+ return BAMTable1_G7[modVal&0x1F]();
+}
+
+static UINT32 (*const AMTable1[2][8])(void) =
+{
+ {
+ am1Displacement8,
+ am1Displacement16,
+ am1Displacement32,
+ am1RegisterIndirect,
+ am1DisplacementIndirect8,
+ am1DisplacementIndirect16,
+ am1DisplacementIndirect32,
+ am1Group7
+ },
+
+ {
+ am1DoubleDisplacement8,
+ am1DoubleDisplacement16,
+ am1DoubleDisplacement32,
+ am1Register,
+ am1Autoincrement,
+ am1Autodecrement,
+ am1Group6,
+ am1Error1
+ }
+};
+
+
+static UINT32 (*const BAMTable1[2][8])(void) =
+{
+ {
+ bam1Displacement8,
+ bam1Displacement16,
+ bam1Displacement32,
+ bam1RegisterIndirect,
+ bam1DisplacementIndirect8,
+ bam1DisplacementIndirect16,
+ bam1DisplacementIndirect32,
+ bam1Group7
+ },
+
+ {
+ bam1DoubleDisplacement8,
+ bam1DoubleDisplacement16,
+ bam1DoubleDisplacement32,
+ bam1Error6,
+ bam1Autoincrement,
+ bam1Autodecrement,
+ bam1Group6,
+ bam1Error1
+ }
+};
+
+
+
+
diff --git a/src/emu/cpu/v60/am2.c b/src/emu/cpu/v60/am2.c
new file mode 100644
index 00000000000..abbd2e5682c
--- /dev/null
+++ b/src/emu/cpu/v60/am2.c
@@ -0,0 +1,1256 @@
+
+// AM2 Functions (for ReadAMAddress)
+// *********************************
+
+static UINT32 am2Register(void)
+{
+ amFlag = 1;
+ amOut = modVal&0x1F;
+ return 1;
+}
+
+static UINT32 am2RegisterIndirect(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F];
+ return 1;
+}
+
+static UINT32 bam2RegisterIndirect(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F];
+ bamOffset = 0;
+ return 1;
+}
+
+static UINT32 am2RegisterIndirectIndexed(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = v60.reg[modVal2&0x1F] + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = v60.reg[modVal2&0x1F] + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = v60.reg[modVal2&0x1F] + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = v60.reg[modVal2&0x1F] + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 bam2RegisterIndirectIndexed(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal2&0x1F];
+ bamOffset = v60.reg[modVal&0x1F];
+ return 2;
+}
+
+static UINT32 am2Autoincrement(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F];
+
+ switch (modDim)
+ {
+ case 0:
+ v60.reg[modVal&0x1F] += 1;
+ break;
+ case 1:
+ v60.reg[modVal&0x1F] += 2;
+ break;
+ case 2:
+ v60.reg[modVal&0x1F] += 4;
+ break;
+ case 3:
+ v60.reg[modVal&0x1F] += 8;
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 bam2Autoincrement(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F];
+ bamOffset = 0;
+
+ switch (modDim)
+ {
+ case 10:
+ v60.reg[modVal&0x1F]+=1;
+ break;
+ case 11:
+ v60.reg[modVal&0x1F]+=4;
+ break;
+ default:
+ fatalerror("CPU - AM2 - 7 (t0 PC=%x)", PC);
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 am2Autodecrement(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ v60.reg[modVal&0x1F] -= 1;
+ break;
+ case 1:
+ v60.reg[modVal&0x1F] -= 2;
+ break;
+ case 2:
+ v60.reg[modVal&0x1F] -= 4;
+ break;
+ case 3:
+ v60.reg[modVal&0x1F] -= 8;
+ break;
+ }
+
+ amOut = v60.reg[modVal&0x1F];
+ return 1;
+}
+
+static UINT32 bam2Autodecrement(void)
+{
+ amFlag = 0;
+ bamOffset = 0;
+
+ switch (modDim)
+ {
+ case 10:
+ v60.reg[modVal&0x1F]-=1;
+ break;
+ case 11:
+ v60.reg[modVal&0x1F]-=4;
+ break;
+ default:
+ fatalerror("CPU - BAM2 - 7 (PC=%06x)", PC);
+ break;
+ }
+
+ amOut = v60.reg[modVal&0x1F];
+ return 1;
+}
+
+
+static UINT32 am2Displacement8(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1);
+
+ return 2;
+}
+
+static UINT32 bam2Displacement8(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F];
+ bamOffset = (INT8)OpRead8(modAdd+1);
+
+ return 2;
+}
+
+static UINT32 am2Displacement16(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1);
+
+ return 3;
+}
+
+static UINT32 bam2Displacement16(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F];
+ bamOffset = (INT16)OpRead16(modAdd+1);
+
+ return 3;
+}
+
+static UINT32 am2Displacement32(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F] + OpRead32(modAdd+1);
+
+ return 5;
+}
+
+static UINT32 bam2Displacement32(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal&0x1F];
+ bamOffset = OpRead32(modAdd+1);
+
+ return 5;
+}
+
+static UINT32 am2DisplacementIndexed8(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam2DisplacementIndexed8(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2);
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 3;
+}
+
+static UINT32 am2DisplacementIndexed16(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 bam2DisplacementIndexed16(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2);
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 4;
+}
+
+static UINT32 am2DisplacementIndexed32(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam2DisplacementIndexed32(void)
+{
+ amFlag = 0;
+ amOut = v60.reg[modVal2&0x1F] + OpRead32(modAdd+2);
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 6;
+}
+
+static UINT32 am2PCDisplacement8(void)
+{
+ amFlag = 0;
+ amOut = PC + (INT8)OpRead8(modAdd+1);
+
+ return 2;
+}
+
+static UINT32 bam2PCDisplacement8(void)
+{
+ amFlag = 0;
+ amOut = PC;
+ bamOffset = (INT8)OpRead8(modAdd+1);
+
+ return 2;
+}
+
+static UINT32 am2PCDisplacement16(void)
+{
+ amFlag = 0;
+ amOut = PC + (INT16)OpRead16(modAdd+1);
+
+ return 3;
+}
+
+static UINT32 bam2PCDisplacement16(void)
+{
+ amFlag = 0;
+ amOut = PC;
+ bamOffset = (INT16)OpRead16(modAdd+1);
+
+ return 3;
+}
+
+static UINT32 am2PCDisplacement32(void)
+{
+ amFlag = 0;
+ amOut = PC + OpRead32(modAdd+1);
+
+ return 5;
+}
+
+static UINT32 bam2PCDisplacement32(void)
+{
+ amFlag = 0;
+ amOut = PC;
+ bamOffset = OpRead32(modAdd+1);
+
+ return 5;
+}
+
+
+static UINT32 am2PCDisplacementIndexed8(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam2PCDisplacementIndexed8(void)
+{
+ amFlag = 0;
+ amOut = PC + (INT8)OpRead8(modAdd+2);
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 3;
+}
+
+static UINT32 am2PCDisplacementIndexed16(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 bam2PCDisplacementIndexed16(void)
+{
+ amFlag = 0;
+ amOut = PC + (INT16)OpRead16(modAdd+2);
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 4;
+}
+
+static UINT32 am2PCDisplacementIndexed32(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam2PCDisplacementIndexed32(void)
+{
+ amFlag = 0;
+ amOut = PC + OpRead32(modAdd+2);
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 6;
+}
+
+static UINT32 am2DisplacementIndirect8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1));
+
+ return 2;
+}
+
+static UINT32 bam2DisplacementIndirect8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1));
+ bamOffset = 0;
+ return 2;
+}
+
+static UINT32 am2DisplacementIndirect16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1));
+
+ return 3;
+}
+
+static UINT32 bam2DisplacementIndirect16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1));
+ bamOffset = 0;
+ return 3;
+}
+
+static UINT32 am2DisplacementIndirect32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1));
+
+ return 5;
+}
+
+static UINT32 bam2DisplacementIndirect32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1));
+ bamOffset = 0;
+
+ return 5;
+}
+
+static UINT32 am2DisplacementIndirectIndexed8(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam2DisplacementIndirectIndexed8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2));
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 3;
+}
+
+static UINT32 am2DisplacementIndirectIndexed16(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 bam2DisplacementIndirectIndexed16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2));
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 4;
+}
+
+static UINT32 am2DisplacementIndirectIndexed32(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam2DisplacementIndirectIndexed32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2));
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 6;
+}
+
+static UINT32 am2PCDisplacementIndirect8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT8)OpRead8(modAdd+1));
+
+ return 2;
+}
+
+static UINT32 bam2PCDisplacementIndirect8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT8)OpRead8(modAdd+1));
+ bamOffset = 0;
+
+ return 2;
+}
+
+static UINT32 am2PCDisplacementIndirect16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT16)OpRead16(modAdd+1));
+
+ return 3;
+}
+
+static UINT32 bam2PCDisplacementIndirect16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT16)OpRead16(modAdd+1));
+ bamOffset = 0;
+
+ return 3;
+}
+
+static UINT32 am2PCDisplacementIndirect32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + OpRead32(modAdd+1));
+
+ return 5;
+}
+
+static UINT32 bam2PCDisplacementIndirect32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + OpRead32(modAdd+1));
+ bamOffset = 0;
+
+ return 5;
+}
+
+static UINT32 am2PCDisplacementIndirectIndexed8(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 bam2PCDisplacementIndirectIndexed8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT8)OpRead8(modAdd+2));
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 3;
+}
+
+static UINT32 am2PCDisplacementIndirectIndexed16(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 4;
+}
+
+
+static UINT32 bam2PCDisplacementIndirectIndexed16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT16)OpRead16(modAdd+2));
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 4;
+}
+
+
+static UINT32 am2PCDisplacementIndirectIndexed32(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam2PCDisplacementIndirectIndexed32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + OpRead32(modAdd+2));
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 6;
+}
+
+static UINT32 am2DoubleDisplacement8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2);
+
+ return 3;
+}
+
+static UINT32 bam2DoubleDisplacement8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1));
+ bamOffset = (INT8)OpRead8(modAdd+2);
+
+ return 3;
+}
+
+static UINT32 am2DoubleDisplacement16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3);
+
+ return 5;
+}
+
+static UINT32 bam2DoubleDisplacement16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1));
+ bamOffset = (INT8)OpRead8(modAdd+3);
+
+ return 5;
+}
+
+static UINT32 am2DoubleDisplacement32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)) + OpRead32(modAdd+5);
+
+ return 9;
+}
+
+static UINT32 bam2DoubleDisplacement32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1));
+ bamOffset = OpRead32(modAdd+5);
+
+ return 9;
+}
+
+
+static UINT32 am2PCDoubleDisplacement8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2);
+
+ return 3;
+}
+
+static UINT32 bam2PCDoubleDisplacement8(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT8)OpRead8(modAdd+1));
+ bamOffset = (INT8)OpRead8(modAdd+2);
+
+ return 3;
+}
+
+static UINT32 am2PCDoubleDisplacement16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3);
+
+ return 5;
+}
+
+static UINT32 bam2PCDoubleDisplacement16(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + (INT16)OpRead16(modAdd+1));
+ bamOffset = (INT8)OpRead8(modAdd+3);
+
+ return 5;
+}
+
+static UINT32 am2PCDoubleDisplacement32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + OpRead32(modAdd+1)) + OpRead32(modAdd+5);
+
+ return 9;
+}
+
+static UINT32 bam2PCDoubleDisplacement32(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(PC + OpRead32(modAdd+1));
+ bamOffset = OpRead32(modAdd+5);
+
+ return 9;
+}
+
+static UINT32 am2DirectAddress(void)
+{
+ amFlag = 0;
+ amOut = OpRead32(modAdd+1);
+
+ return 5;
+}
+
+static UINT32 bam2DirectAddress(void)
+{
+ amFlag = 0;
+ amOut = OpRead32(modAdd+1);
+ bamOffset = 0;
+
+ return 5;
+}
+
+static UINT32 am2DirectAddressIndexed(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = OpRead32(modAdd+2) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam2DirectAddressIndexed(void)
+{
+ amFlag = 0;
+ amOut = OpRead32(modAdd+2);
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 6;
+}
+
+static UINT32 am2DirectAddressDeferred(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(OpRead32(modAdd+1));
+
+ return 5;
+}
+
+static UINT32 bam2DirectAddressDeferred(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(OpRead32(modAdd+1));
+ bamOffset = 0;
+
+ return 5;
+}
+
+static UINT32 am2DirectAddressDeferredIndexed(void)
+{
+ amFlag = 0;
+
+ switch (modDim)
+ {
+ case 0:
+ amOut = MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F];
+ break;
+ case 1:
+ amOut = MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 2;
+ break;
+ case 2:
+ amOut = MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 4;
+ break;
+ case 3:
+ amOut = MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 8;
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 bam2DirectAddressDeferredIndexed(void)
+{
+ amFlag = 0;
+ amOut = MemRead32(OpRead32(modAdd+2));
+ bamOffset = v60.reg[modVal&0x1F];
+
+ return 6;
+}
+
+static UINT32 am2Immediate(void)
+{
+ // Fuck off LDPR
+ return am1Immediate();
+}
+
+static UINT32 am2ImmediateQuick(void)
+{
+ // fuck off LDPR
+ return am1ImmediateQuick();
+}
+
+
+// AM2 Tables (for ReadAMAddress)
+// ******************************
+
+static UINT32 am2Error1(void)
+{
+ fatalerror("CPU - AM2 - 1 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 am2Error2(void)
+{
+ fatalerror("CPU - AM2 - 2 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+#ifdef UNUSED_FUNCTION
+static UINT32 am2Error3(void)
+{
+ fatalerror("CPU - AM2 - 3 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+#endif
+
+static UINT32 am2Error4(void)
+{
+ fatalerror("CPU - AM2 - 4 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 am2Error5(void)
+{
+ fatalerror("CPU - AM2 - 5 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam2Error1(void)
+{
+ fatalerror("CPU - BAM2 - 1 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam2Error2(void)
+{
+ fatalerror("CPU - BAM2 - 2 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+#ifdef UNUSED_FUNCTION
+static UINT32 bam2Error3(void)
+{
+ fatalerror("CPU - BAM2 - 3 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+#endif
+
+static UINT32 bam2Error4(void)
+{
+ fatalerror("CPU - BAM2 - 4 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam2Error5(void)
+{
+ fatalerror("CPU - BAM2 - 5 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 bam2Error6(void)
+{
+ fatalerror("CPU - BAM2 - 6 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+
+static UINT32 (*const AMTable2_G7a[16])(void) =
+{
+ am2PCDisplacementIndexed8,
+ am2PCDisplacementIndexed16,
+ am2PCDisplacementIndexed32,
+ am2DirectAddressIndexed,
+ am2Error5,
+ am2Error5,
+ am2Error5,
+ am2Error5,
+ am2PCDisplacementIndirectIndexed8,
+ am2PCDisplacementIndirectIndexed16,
+ am2PCDisplacementIndirectIndexed32,
+ am2DirectAddressDeferredIndexed,
+ am2Error5,
+ am2Error5,
+ am2Error5,
+ am2Error5
+};
+
+static UINT32 (*const BAMTable2_G7a[16])(void) =
+{
+ bam2PCDisplacementIndexed8,
+ bam2PCDisplacementIndexed16,
+ bam2PCDisplacementIndexed32,
+ bam2DirectAddressIndexed,
+ bam2Error5,
+ bam2Error5,
+ bam2Error5,
+ bam2Error5,
+ bam2PCDisplacementIndirectIndexed8,
+ bam2PCDisplacementIndirectIndexed16,
+ bam2PCDisplacementIndirectIndexed32,
+ bam2DirectAddressDeferredIndexed,
+ bam2Error5,
+ bam2Error5,
+ bam2Error5,
+ bam2Error5
+};
+
+static UINT32 am2Group7a(void)
+{
+ if (!(modVal2&0x10))
+ return am2Error4();
+
+ return AMTable2_G7a[modVal2&0xF]();
+}
+
+static UINT32 bam2Group7a(void)
+{
+ if (!(modVal2&0x10))
+ return bam2Error4();
+
+ return BAMTable2_G7a[modVal2&0xF]();
+}
+
+static UINT32 (*const AMTable2_G7[32])(void) =
+{
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2ImmediateQuick,
+ am2PCDisplacement8,
+ am2PCDisplacement16,
+ am2PCDisplacement32,
+ am2DirectAddress,
+ am2Immediate,
+ am2Error2,
+ am2Error2,
+ am2Error2,
+ am2PCDisplacementIndirect8,
+ am2PCDisplacementIndirect16,
+ am2PCDisplacementIndirect32,
+ am2DirectAddressDeferred,
+ am2PCDoubleDisplacement8,
+ am2PCDoubleDisplacement16,
+ am2PCDoubleDisplacement32,
+ am2Error2
+};
+
+static UINT32 (*const BAMTable2_G7[32])(void) =
+{
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2Error6,
+ bam2PCDisplacement8,
+ bam2PCDisplacement16,
+ bam2PCDisplacement32,
+ bam2DirectAddress,
+ bam2Error6,
+ bam2Error2,
+ bam2Error2,
+ bam2Error2,
+ bam2PCDisplacementIndirect8,
+ bam2PCDisplacementIndirect16,
+ bam2PCDisplacementIndirect32,
+ bam2DirectAddressDeferred,
+ bam2PCDoubleDisplacement8,
+ bam2PCDoubleDisplacement16,
+ bam2PCDoubleDisplacement32,
+ bam2Error2
+};
+
+static UINT32 (*const AMTable2_G6[8])(void) =
+{
+ am2DisplacementIndexed8,
+ am2DisplacementIndexed16,
+ am2DisplacementIndexed32,
+ am2RegisterIndirectIndexed,
+ am2DisplacementIndirectIndexed8,
+ am2DisplacementIndirectIndexed16,
+ am2DisplacementIndirectIndexed32,
+ am2Group7a
+};
+
+static UINT32 (*const BAMTable2_G6[8])(void) =
+{
+ bam2DisplacementIndexed8,
+ bam2DisplacementIndexed16,
+ bam2DisplacementIndexed32,
+ bam2RegisterIndirectIndexed,
+ bam2DisplacementIndirectIndexed8,
+ bam2DisplacementIndirectIndexed16,
+ bam2DisplacementIndirectIndexed32,
+ bam2Group7a
+};
+
+
+
+
+static UINT32 am2Group6(void)
+{
+ modVal2=OpRead8(modAdd+1);
+ return AMTable2_G6[modVal2>>5]();
+}
+static UINT32 bam2Group6(void)
+{
+ modVal2=OpRead8(modAdd+1);
+ return BAMTable2_G6[modVal2>>5]();
+}
+
+static UINT32 am2Group7(void)
+{
+ return AMTable2_G7[modVal&0x1F]();
+}
+static UINT32 bam2Group7(void)
+{
+ return BAMTable2_G7[modVal&0x1F]();
+}
+
+
+static UINT32 (*const AMTable2[2][8])(void) =
+{
+ {
+ am2Displacement8,
+ am2Displacement16,
+ am2Displacement32,
+ am2RegisterIndirect,
+ am2DisplacementIndirect8,
+ am2DisplacementIndirect16,
+ am2DisplacementIndirect32,
+ am2Group7
+ },
+
+ {
+ am2DoubleDisplacement8,
+ am2DoubleDisplacement16,
+ am2DoubleDisplacement32,
+ am2Register,
+ am2Autoincrement,
+ am2Autodecrement,
+ am2Group6,
+ am2Error1
+ }
+};
+
+static UINT32 (*const BAMTable2[2][8])(void) =
+{
+ {
+ bam2Displacement8,
+ bam2Displacement16,
+ bam2Displacement32,
+ bam2RegisterIndirect,
+ bam2DisplacementIndirect8,
+ bam2DisplacementIndirect16,
+ bam2DisplacementIndirect32,
+ bam2Group7
+ },
+
+ {
+ bam2DoubleDisplacement8,
+ bam2DoubleDisplacement16,
+ bam2DoubleDisplacement32,
+ bam2Error6,
+ bam2Autoincrement,
+ bam2Autodecrement,
+ bam2Group6,
+ bam2Error1
+ }
+};
+
+
+
+
diff --git a/src/emu/cpu/v60/am3.c b/src/emu/cpu/v60/am3.c
new file mode 100644
index 00000000000..8ddabbf6b60
--- /dev/null
+++ b/src/emu/cpu/v60/am3.c
@@ -0,0 +1,887 @@
+
+// AM3 Functions (for ReadAM)
+// **************************
+
+static UINT32 am3Register(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ SETREG8(v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ SETREG16(v60.reg[modVal&0x1F], modWriteValH);
+ break;
+ case 2:
+ v60.reg[modVal&0x1F] = modWriteValW;
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 am3RegisterIndirect(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(v60.reg[modVal&0x1F], modWriteValH);
+ break;
+ case 2:
+ MemWrite32(v60.reg[modVal&0x1F], modWriteValW);
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 am3RegisterIndirectIndexed(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(v60.reg[modVal2&0x1F] + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(v60.reg[modVal2&0x1F] + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(v60.reg[modVal2&0x1F] + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 am3Autoincrement(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(v60.reg[modVal&0x1F], modWriteValB);
+ v60.reg[modVal&0x1F] += 1;
+ break;
+ case 1:
+ MemWrite16(v60.reg[modVal&0x1F], modWriteValH);
+ v60.reg[modVal&0x1F] += 2;
+ break;
+ case 2:
+ MemWrite32(v60.reg[modVal&0x1F], modWriteValW);
+ v60.reg[modVal&0x1F] += 4;
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 am3Autodecrement(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ v60.reg[modVal&0x1F] -= 1;
+ MemWrite8(v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ v60.reg[modVal&0x1F] -= 2;
+ MemWrite16(v60.reg[modVal&0x1F], modWriteValH);
+ break;
+ case 2:
+ v60.reg[modVal&0x1F] -= 4;
+ MemWrite32(v60.reg[modVal&0x1F], modWriteValW);
+ break;
+ }
+
+ return 1;
+}
+
+static UINT32 am3Displacement8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1), modWriteValW);
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 am3Displacement16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1), modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3Displacement32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(v60.reg[modVal&0x1F] + OpRead32(modAdd+1), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(v60.reg[modVal&0x1F] + OpRead32(modAdd+1), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1), modWriteValW);
+ break;
+ }
+
+ return 5;
+}
+
+
+static UINT32 am3DisplacementIndexed8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3DisplacementIndexed16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 am3DisplacementIndexed32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 6;
+}
+
+
+static UINT32 am3PCDisplacement8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(PC + (INT8)OpRead8(modAdd+1), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(PC + (INT8)OpRead8(modAdd+1), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(PC + (INT8)OpRead8(modAdd+1), modWriteValW);
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 am3PCDisplacement16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(PC + (INT16)OpRead16(modAdd+1), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(PC + (INT16)OpRead16(modAdd+1), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(PC + (INT16)OpRead16(modAdd+1), modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3PCDisplacement32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(PC + OpRead32(modAdd+1), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(PC + OpRead32(modAdd+1), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(PC + OpRead32(modAdd+1), modWriteValW);
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 am3PCDisplacementIndexed8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(PC + (INT8)OpRead8(modAdd+2) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3PCDisplacementIndexed16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(PC + (INT16)OpRead16(modAdd+2) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 am3PCDisplacementIndexed32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(PC + OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 am3DisplacementIndirect8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)), modWriteValW);
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 am3DisplacementIndirect16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)), modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3DisplacementIndirect32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)), modWriteValW);
+ break;
+ }
+
+ return 5;
+}
+
+
+static UINT32 am3DisplacementIndirectIndexed8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(v60.reg[modVal2&0x1F] + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3DisplacementIndirectIndexed16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(v60.reg[modVal2&0x1F] + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 am3DisplacementIndirectIndexed32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(v60.reg[modVal2&0x1F] + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 am3PCDisplacementIndirect8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(PC + (INT8)OpRead8(modAdd+1)), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(PC + (INT8)OpRead8(modAdd+1)), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(PC + (INT8)OpRead8(modAdd+1)), modWriteValW);
+ break;
+ }
+
+ return 2;
+}
+
+static UINT32 am3PCDisplacementIndirect16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(PC + (INT16)OpRead16(modAdd+1)), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(PC + (INT16)OpRead16(modAdd+1)), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(PC + (INT16)OpRead16(modAdd+1)), modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3PCDisplacementIndirect32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(PC + OpRead32(modAdd+1)), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(PC + OpRead32(modAdd+1)), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(PC + OpRead32(modAdd+1)), modWriteValW);
+ break;
+ }
+
+ return 5;
+}
+
+
+static UINT32 am3PCDisplacementIndirectIndexed8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(PC + (INT8)OpRead8(modAdd+2)) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3PCDisplacementIndirectIndexed16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(PC + (INT16)OpRead16(modAdd+2)) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 4;
+}
+
+static UINT32 am3PCDisplacementIndirectIndexed32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(PC + OpRead32(modAdd+2)) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 6;
+}
+
+
+static UINT32 am3DoubleDisplacement8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(v60.reg[modVal&0x1F] + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2), modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3DoubleDisplacement16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(v60.reg[modVal&0x1F] + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3), modWriteValW);
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 am3DoubleDisplacement32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)) + OpRead32(modAdd+5), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)) + OpRead32(modAdd+5), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(v60.reg[modVal&0x1F] + OpRead32(modAdd+1)) + OpRead32(modAdd+5), modWriteValW);
+ break;
+ }
+
+ return 9;
+}
+
+
+static UINT32 am3PCDoubleDisplacement8(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(PC + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(PC + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(PC + (INT8)OpRead8(modAdd+1)) + (INT8)OpRead8(modAdd+2), modWriteValW);
+ break;
+ }
+
+ return 3;
+}
+
+static UINT32 am3PCDoubleDisplacement16(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(PC + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(PC + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(PC + (INT16)OpRead16(modAdd+1)) + (INT16)OpRead16(modAdd+3), modWriteValW);
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 am3PCDoubleDisplacement32(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(PC + OpRead32(modAdd+1)) + OpRead32(modAdd+5), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(PC + OpRead32(modAdd+1)) + OpRead32(modAdd+5), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(PC + OpRead32(modAdd+1)) + OpRead32(modAdd+5), modWriteValW);
+ break;
+ }
+
+ return 9;
+}
+
+static UINT32 am3DirectAddress(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(OpRead32(modAdd+1), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(OpRead32(modAdd+1), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(OpRead32(modAdd+1), modWriteValW);
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 am3DirectAddressIndexed(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(OpRead32(modAdd+2) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 2, modWriteValH);
+ break;
+ case 2:
+ MemWrite32(OpRead32(modAdd+2) + v60.reg[modVal&0x1F] * 4, modWriteValW);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 am3DirectAddressDeferred(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(OpRead32(modAdd+1)), modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(OpRead32(modAdd+1)), modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(OpRead32(modAdd+1)), modWriteValW);
+ break;
+ }
+
+ return 5;
+}
+
+static UINT32 am3DirectAddressDeferredIndexed(void)
+{
+ switch (modDim)
+ {
+ case 0:
+ MemWrite8(MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F], modWriteValB);
+ break;
+ case 1:
+ MemWrite16(MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F], modWriteValH);
+ break;
+ case 2:
+ MemWrite32(MemRead32(OpRead32(modAdd+2)) + v60.reg[modVal&0x1F], modWriteValW);
+ break;
+ }
+
+ return 6;
+}
+
+static UINT32 am3Immediate(void)
+{
+ fatalerror("CPU - AM3 - IMM (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 am3ImmediateQuick(void)
+{
+ fatalerror("CPU - AM3 - IMMQ (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+
+
+// AM3 Tables (for ReadAMAddress)
+// ******************************
+
+static UINT32 am3Error1(void)
+{
+ fatalerror("CPU - AM3 - 1 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 am3Error2(void)
+{
+ fatalerror("CPU - AM3 - 2 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+#ifdef UNUSED_FUNCTION
+static UINT32 am3Error3(void)
+{
+ fatalerror("CPU - AM3 - 3 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+#endif
+
+static UINT32 am3Error4(void)
+{
+ fatalerror("CPU - AM3 - 4 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 am3Error5(void)
+{
+ fatalerror("CPU - AM3 - 5 (PC=%06x)", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 (*const AMTable3_G7a[16])(void) =
+{
+ am3PCDisplacementIndexed8,
+ am3PCDisplacementIndexed16,
+ am3PCDisplacementIndexed32,
+ am3DirectAddressIndexed,
+ am3Error5,
+ am3Error5,
+ am3Error5,
+ am3Error5,
+ am3PCDisplacementIndirectIndexed8,
+ am3PCDisplacementIndirectIndexed16,
+ am3PCDisplacementIndirectIndexed32,
+ am3DirectAddressDeferredIndexed,
+ am3Error5,
+ am3Error5,
+ am3Error5,
+ am3Error5
+};
+
+static UINT32 am3Group7a(void)
+{
+ if (!(modVal2&0x10))
+ return am3Error4();
+
+ return AMTable3_G7a[modVal2&0xF]();
+}
+
+static UINT32 (*const AMTable3_G7[32])(void) =
+{
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3ImmediateQuick,
+ am3PCDisplacement8,
+ am3PCDisplacement16,
+ am3PCDisplacement32,
+ am3DirectAddress,
+ am3Immediate,
+ am3Error2,
+ am3Error2,
+ am3Error2,
+ am3PCDisplacementIndirect8,
+ am3PCDisplacementIndirect16,
+ am3PCDisplacementIndirect32,
+ am3DirectAddressDeferred,
+ am3PCDoubleDisplacement8,
+ am3PCDoubleDisplacement16,
+ am3PCDoubleDisplacement32,
+ am3Error2
+};
+
+static UINT32 (*const AMTable3_G6[8])(void) =
+{
+ am3DisplacementIndexed8,
+ am3DisplacementIndexed16,
+ am3DisplacementIndexed32,
+ am3RegisterIndirectIndexed,
+ am3DisplacementIndirectIndexed8,
+ am3DisplacementIndirectIndexed16,
+ am3DisplacementIndirectIndexed32,
+ am3Group7a
+};
+
+
+
+
+static UINT32 am3Group6(void)
+{
+ modVal2=OpRead8(modAdd+1);
+ return AMTable3_G6[modVal2>>5]();
+}
+
+
+static UINT32 am3Group7(void)
+{
+ return AMTable3_G7[modVal&0x1F]();
+}
+
+
+
+static UINT32 (*const AMTable3[2][8])(void) =
+{
+ {
+ am3Displacement8,
+ am3Displacement16,
+ am3Displacement32,
+ am3RegisterIndirect,
+ am3DisplacementIndirect8,
+ am3DisplacementIndirect16,
+ am3DisplacementIndirect32,
+ am3Group7
+ },
+
+ {
+ am3DoubleDisplacement8,
+ am3DoubleDisplacement16,
+ am3DoubleDisplacement32,
+ am3Register,
+ am3Autoincrement,
+ am3Autodecrement,
+ am3Group6,
+ am3Error1
+ }
+};
+
+
+
diff --git a/src/emu/cpu/v60/op12.c b/src/emu/cpu/v60/op12.c
new file mode 100644
index 00000000000..93359ef722b
--- /dev/null
+++ b/src/emu/cpu/v60/op12.c
@@ -0,0 +1,2399 @@
+/*
+ * MUL* and MULU* do not set OV correctly
+ * DIVX: the second operand should be treated as dword instead of word
+ * GETATE, GETPTE and GETRA should not be used
+ * UPDPSW: _CY and _OV must be cleared or unchanged? I suppose
+ * cleared, like TEST being done on the mask operand.
+ * MOVT: I cannot understand exactly what happens to the result
+ * when an overflow occurs
+ *
+ * Unimplemented opcodes:
+ * ROTC, UPDATE, UPDPTE
+ */
+
+static UINT32 f12Op1, f12Op2;
+static UINT8 f12Flag1, f12Flag2;
+
+
+/*
+ * Macro to access data in operands decoded with ReadAMAddress()
+ */
+
+#define F12LOADOPBYTE(num) \
+ if (f12Flag##num) \
+ appb = (UINT8)v60.reg[f12Op##num]; \
+ else \
+ appb = MemRead8(f12Op##num);
+
+#define F12LOADOPHALF(num) \
+ if (f12Flag##num) \
+ apph = (UINT16)v60.reg[f12Op##num]; \
+ else \
+ apph = MemRead16(f12Op##num);
+
+#define F12LOADOPWORD(num) \
+ if (f12Flag##num) \
+ appw = v60.reg[f12Op##num]; \
+ else \
+ appw = MemRead32(f12Op##num);
+
+#define F12STOREOPBYTE(num) \
+ if (f12Flag##num) \
+ SETREG8(v60.reg[f12Op##num], appb); \
+ else \
+ MemWrite8(f12Op##num,appb);
+
+#define F12STOREOPHALF(num) \
+ if (f12Flag##num) \
+ SETREG16(v60.reg[f12Op##num], apph); \
+ else \
+ MemWrite16(f12Op##num,apph);
+
+#define F12STOREOPWORD(num) \
+ if (f12Flag##num) \
+ v60.reg[f12Op##num] = appw; \
+ else \
+ MemWrite32(f12Op##num,appw);
+
+#define F12LOADOP1BYTE() F12LOADOPBYTE(1)
+#define F12LOADOP1HALF() F12LOADOPHALF(1)
+#define F12LOADOP1WORD() F12LOADOPWORD(1)
+
+#define F12LOADOP2BYTE() F12LOADOPBYTE(2)
+#define F12LOADOP2HALF() F12LOADOPHALF(2)
+#define F12LOADOP2WORD() F12LOADOPWORD(2)
+
+#define F12STOREOP1BYTE() F12STOREOPBYTE(1)
+#define F12STOREOP1HALF() F12STOREOPHALF(1)
+#define F12STOREOP1WORD() F12STOREOPWORD(1)
+
+#define F12STOREOP2BYTE() F12STOREOPBYTE(2)
+#define F12STOREOP2HALF() F12STOREOPHALF(2)
+#define F12STOREOP2WORD() F12STOREOPWORD(2)
+
+
+
+#define F12END() \
+ return amLength1 + amLength2 + 2;
+
+static UINT8 if12;
+
+// Decode the first operand of the instruction and prepare
+// writing to the second operand.
+static void F12DecodeFirstOperand(UINT32 (*DecodeOp1)(void), UINT8 dim1)
+{
+ if12 = OpRead8(PC + 1);
+
+ // Check if F1 or F2
+ if (if12 & 0x80)
+ {
+ modDim = dim1;
+ modM = if12 & 0x40;
+ modAdd = PC + 2;
+ amLength1 = DecodeOp1();
+ f12Op1 = amOut;
+ f12Flag1 = amFlag;
+ }
+ else
+ {
+ // Check D flag
+ if (if12 & 0x20)
+ {
+ modDim = dim1;
+ modM = if12 & 0x40;
+ modAdd = PC + 2;
+ amLength1 = DecodeOp1();
+ f12Op1 = amOut;
+ f12Flag1 = amFlag;
+ }
+ else
+ {
+ if (DecodeOp1==ReadAM)
+ {
+ switch (dim1)
+ {
+ case 0:
+ f12Op1 = (UINT8)v60.reg[if12 & 0x1F];
+ break;
+ case 1:
+ f12Op1 = (UINT16)v60.reg[if12 & 0x1F];
+ break;
+ case 2:
+ f12Op1 = v60.reg[if12 & 0x1F];
+ break;
+ }
+
+ f12Flag1 = 0;
+ }
+ else
+ {
+ f12Flag1 = 1;
+ f12Op1 = if12 & 0x1F;
+ }
+
+ amLength1 = 0;
+ }
+ }
+}
+
+static void F12WriteSecondOperand(UINT8 dim2)
+{
+ modDim = dim2;
+
+ // Check if F1 or F2
+ if (if12 & 0x80)
+ {
+ modM = if12 & 0x20;
+ modAdd = PC + 2 + amLength1;
+ modDim = dim2;
+ amLength2 = WriteAM();
+ }
+ else
+ {
+ // Check D flag
+ if (if12 & 0x20)
+ {
+ switch (dim2)
+ {
+ case 0:
+ SETREG8(v60.reg[if12 & 0x1F], modWriteValB);
+ break;
+ case 1:
+ SETREG16(v60.reg[if12 & 0x1F], modWriteValH);
+ break;
+ case 2:
+ v60.reg[if12 & 0x1F] = modWriteValW;
+ break;
+ }
+
+ amLength2 = 0;
+ }
+ else
+ {
+ modM = if12 & 0x40;
+ modAdd = PC + 2;
+ modDim = dim2;
+ amLength2 = WriteAM();
+ }
+ }
+}
+
+
+
+// Decode both format 1/2 operands
+static void F12DecodeOperands(UINT32 (*DecodeOp1)(void), UINT8 dim1, UINT32 (*DecodeOp2)(void), UINT8 dim2)
+{
+ UINT8 _if12 = OpRead8(PC + 1);
+
+ // Check if F1 or F2
+ if (_if12 & 0x80)
+ {
+ modDim = dim1;
+ modM = _if12 & 0x40;
+ modAdd = PC + 2;
+ amLength1 = DecodeOp1();
+ f12Op1 = amOut;
+ f12Flag1 = amFlag;
+
+ modDim = dim2;
+ modM = _if12 & 0x20;
+ modAdd = PC + 2 + amLength1;
+ amLength2 = DecodeOp2();
+ f12Op2 = amOut;
+ f12Flag2 = amFlag;
+ }
+ else
+ {
+ // Check D flag
+ if (_if12 & 0x20)
+ {
+ if (DecodeOp2==ReadAMAddress)
+ {
+ f12Op2 = _if12 & 0x1F;
+ f12Flag2 = 1;
+ }
+ else
+ {
+ switch (dim2)
+ {
+ case 0:
+ f12Op2 = (UINT8)v60.reg[_if12 & 0x1F];
+ break;
+ case 1:
+ f12Op2 = (UINT16)v60.reg[_if12 & 0x1F];
+ break;
+ case 2:
+ f12Op2 = v60.reg[_if12 & 0x1F];
+ break;
+ }
+ }
+
+ amLength2 = 0;
+
+ modDim = dim1;
+ modM = _if12 & 0x40;
+ modAdd = PC + 2;
+ amLength1 = DecodeOp1();
+ f12Op1 = amOut;
+ f12Flag1 = amFlag;
+ }
+ else
+ {
+ if (DecodeOp1==ReadAMAddress)
+ {
+ f12Op1 = _if12 & 0x1F;
+ f12Flag1 = 1;
+ }
+ else
+ {
+ switch (dim1)
+ {
+ case 0:
+ f12Op1 = (UINT8)v60.reg[_if12 & 0x1F];
+ break;
+ case 1:
+ f12Op1 = (UINT16)v60.reg[_if12 & 0x1F];
+ break;
+ case 2:
+ f12Op1 = v60.reg[_if12 & 0x1F];
+ break;
+ }
+ }
+ amLength1 = 0;
+
+ modDim = dim2;
+ modM = _if12 & 0x40;
+ modAdd = PC + 2 + amLength1;
+ amLength2 = DecodeOp2();
+ f12Op2 = amOut;
+ f12Flag2 = amFlag;
+ }
+ }
+}
+
+static UINT32 opADDB(void) /* TRUSTED (C too!)*/
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ ADDB(appb, (UINT8)f12Op1);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opADDH(void) /* TRUSTED (C too!)*/
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ ADDW(apph, (UINT16)f12Op1);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opADDW(void) /* TRUSTED (C too!) */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ ADDL(appw, (UINT32)f12Op1);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opADDCB(void)
+{
+ UINT8 appb, temp;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ temp = ((UINT8)f12Op1 + (_CY?1:0));
+ ADDB(appb, temp);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opADDCH(void)
+{
+ UINT16 apph, temp;
+
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ temp = ((UINT16)f12Op1 + (_CY?1:0));
+ ADDW(apph, temp);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opADDCW(void)
+{
+ UINT32 appw, temp;
+
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ temp = f12Op1 + (_CY?1:0);
+ ADDL(appw, temp);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opANDB(void) /* TRUSTED */
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ appb &= f12Op1;
+ _OV = 0;
+ _S = ((appb&0x80)!=0);
+ _Z = (appb==0);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opANDH(void) /* TRUSTED */
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ apph &= f12Op1;
+ _OV = 0;
+ _S = ((apph&0x8000)!=0);
+ _Z = (apph==0);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opANDW(void) /* TRUSTED */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ appw &= f12Op1;
+ _OV = 0;
+ _S = ((appw&0x80000000)!=0);
+ _Z = (appw==0);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opCALL(void) /* TRUSTED */
+{
+ F12DecodeOperands(ReadAMAddress,0,ReadAMAddress,2);
+
+ SP -= 4;
+ MemWrite32(SP, AP);
+ AP = f12Op2;
+
+ SP -= 4;
+ MemWrite32(SP, PC + amLength1 + amLength2 + 2);
+ PC = f12Op1;
+ ChangePC(PC);
+
+ return 0;
+}
+
+static UINT32 opCHKAR(void)
+{
+ F12DecodeOperands(ReadAM,0,ReadAM,0);
+
+ // No MMU and memory permissions yet @@@
+ _Z = 1;
+ _CY = 0;
+ _S = 0;
+
+ F12END();
+}
+
+static UINT32 opCHKAW(void)
+{
+ F12DecodeOperands(ReadAM,0,ReadAM,0);
+
+ // No MMU and memory permissions yet @@@
+ _Z = 1;
+ _CY = 0;
+ _S = 0;
+
+ F12END();
+}
+
+static UINT32 opCHKAE(void)
+{
+ F12DecodeOperands(ReadAM,0,ReadAM,0);
+
+ // No MMU and memory permissions yet @@@
+ _Z = 1;
+ _CY = 0;
+ _S = 0;
+
+ F12END();
+}
+
+static UINT32 opCHLVL(void)
+{
+ UINT32 oldPSW;
+
+ F12DecodeOperands(ReadAM,0,ReadAM,0);
+
+ if (f12Op1>3)
+ {
+ fatalerror("Illegal data field on opCHLVL, PC=%x", PC);
+ }
+
+ oldPSW = v60_update_psw_for_exception(0, f12Op1);
+
+ SP -= 4;
+ MemWrite32(SP,f12Op2);
+
+ SP -= 4;
+ MemWrite32(SP,EXCEPTION_CODE_AND_SIZE(0x1800 + f12Op1*0x100, 8));
+
+ SP -= 4;
+ MemWrite32(SP,oldPSW);
+
+ SP -= 4;
+ MemWrite32(SP,PC + amLength1 + amLength2 + 2);
+
+ PC = GETINTVECT(24+f12Op1);
+ ChangePC(PC);
+
+ return 0;
+}
+
+static UINT32 opCLR1(void) /* TRUSTED */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ _CY = ((appw & (1<<f12Op1))!=0);
+ _Z = !(_CY);
+
+ appw &= ~(1<<f12Op1);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opCMPB(void) /* TRUSTED (C too!) */
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAM,0);
+
+ appb = (UINT8)f12Op2;
+ SUBB(appb, (UINT8)f12Op1);
+
+ F12END();
+}
+
+static UINT32 opCMPH(void) /* TRUSTED (C too!) */
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAM,1);
+
+ apph = (UINT16)f12Op2;
+ SUBW(apph, (UINT16)f12Op1);
+
+ F12END();
+}
+
+
+static UINT32 opCMPW(void) /* TRUSTED (C too!)*/
+{
+ F12DecodeOperands(ReadAM,2,ReadAM,2);
+
+ SUBL(f12Op2, (UINT32)f12Op1);
+
+ F12END();
+}
+
+static UINT32 opDIVB(void) /* TRUSTED */
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ _OV = ((appb == 0x80) && (f12Op1==0xFF));
+ if (f12Op1 && !_OV)
+ appb= (INT8)appb / (INT8)f12Op1;
+ _Z = (appb == 0);
+ _S = ((appb & 0x80)!=0);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opDIVH(void) /* TRUSTED */
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ _OV = ((apph == 0x8000) && (f12Op1==0xFFFF));
+ if (f12Op1 && !_OV)
+ apph = (INT16)apph / (INT16)f12Op1;
+ _Z = (apph == 0);
+ _S = ((apph & 0x8000)!=0);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opDIVW(void) /* TRUSTED */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ _OV = ((appw == 0x80000000) && (f12Op1==0xFFFFFFFF));
+ if (f12Op1 && !_OV)
+ appw = (INT32)appw / (INT32)f12Op1;
+ _Z = (appw == 0);
+ _S = ((appw & 0x80000000)!=0);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opDIVX(void)
+{
+ UINT32 a,b;
+ INT64 dv;
+
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,3);
+
+ if (f12Flag2)
+ {
+ a=v60.reg[f12Op2&0x1F];
+ b=v60.reg[(f12Op2&0x1F)+1];
+ }
+ else
+ {
+ a=MemRead32(f12Op2);
+ b=MemRead32(f12Op2+4);
+ }
+
+ dv = ((UINT64)b<<32) | ((UINT64)a);
+
+ a = dv / (INT64)((INT32)f12Op1);
+ b = dv % (INT64)((INT32)f12Op1);
+
+ _S = ((a & 0x80000000)!=0);
+ _Z = (a == 0);
+
+ if (f12Flag2)
+ {
+ v60.reg[f12Op2&0x1F]=a;
+ v60.reg[(f12Op2&0x1F)+1]=b;
+ }
+ else
+ {
+ MemWrite32(f12Op2,a);
+ MemWrite32(f12Op2+4,b);
+ }
+
+ F12END();
+}
+
+static UINT32 opDIVUX(void)
+{
+ UINT32 a,b;
+ UINT64 dv;
+
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,3);
+
+ if (f12Flag2)
+ {
+ a=v60.reg[f12Op2&0x1F];
+ b=v60.reg[(f12Op2&0x1F)+1];
+ }
+ else
+ {
+ a=MemRead32(f12Op2);
+ b=MemRead32(f12Op2+4);
+ }
+
+ dv = (UINT64)(((UINT64)b<<32) | (UINT64)a);
+ a = (UINT32)(dv / (UINT64)f12Op1);
+ b = (UINT32)(dv % (UINT64)f12Op1);
+
+ _S = ((a & 0x80000000) != 0);
+ _Z = (a == 0);
+
+ if (f12Flag2)
+ {
+ v60.reg[f12Op2&0x1F]=a;
+ v60.reg[(f12Op2&0x1F)+1]=b;
+ }
+ else
+ {
+ MemWrite32(f12Op2,a);
+ MemWrite32(f12Op2+4,b);
+ }
+
+ F12END();
+}
+
+
+static UINT32 opDIVUB(void) /* TRUSTED */
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ _OV = 0;
+ if (f12Op1) appb /= (UINT8)f12Op1;
+ _Z = (appb == 0);
+ _S = ((appb & 0x80)!=0);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opDIVUH(void) /* TRUSTED */
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ _OV = 0;
+ if (f12Op1) apph /= (UINT16)f12Op1;
+ _Z = (apph == 0);
+ _S = ((apph & 0x8000)!=0);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opDIVUW(void) /* TRUSTED */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ _OV = 0;
+ if (f12Op1) appw /= f12Op1;
+ _Z = (appw == 0);
+ _S = ((appw & 0x80000000)!=0);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opINB(void)
+{
+ F12DecodeFirstOperand(ReadAMAddress,0);
+ modWriteValB=PortRead8(f12Op1);
+
+ if ( v60_stall_io )
+ {
+ v60_stall_io = 0;
+ return 0;
+ }
+
+ F12WriteSecondOperand(0);
+ F12END();
+}
+
+static UINT32 opINH(void)
+{
+ F12DecodeFirstOperand(ReadAMAddress,1);
+ modWriteValH=PortRead16(f12Op1);
+
+ if ( v60_stall_io )
+ {
+ v60_stall_io = 0;
+ return 0;
+ }
+
+ F12WriteSecondOperand(1);
+ F12END();
+}
+
+static UINT32 opINW(void)
+{
+ F12DecodeFirstOperand(ReadAMAddress,2);
+ modWriteValW=PortRead32(f12Op1);
+
+ if ( v60_stall_io )
+ {
+ v60_stall_io = 0;
+ return 0;
+ }
+
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opLDPR(void)
+{
+ F12DecodeOperands(ReadAMAddress,2,ReadAM,2);
+ if (f12Op2 >= 0 && f12Op2 <= 28)
+ {
+ if (f12Flag1 &&(!(OpRead8(PC + 1)&0x80 && OpRead8(PC + 2)==0xf4 ) ))
+ v60.reg[f12Op2 + 36] = v60.reg[f12Op1];
+ else
+ v60.reg[f12Op2 + 36] = f12Op1;
+ }
+ else
+ {
+ fatalerror("Invalid operand on LDPR PC=%x", PC);
+ }
+ F12END();
+}
+
+static UINT32 opLDTASK(void)
+{
+ int i;
+ F12DecodeOperands(ReadAMAddress,2,ReadAM,2);
+
+ v60WritePSW(v60ReadPSW() & 0xefffffff);
+
+ TR = f12Op2;
+
+ TKCW = MemRead32(f12Op2);
+ f12Op2 += 4;
+ if(SYCW & 0x100) {
+ L0SP = MemRead32(f12Op2);
+ f12Op2 += 4;
+ }
+ if(SYCW & 0x200) {
+ L1SP = MemRead32(f12Op2);
+ f12Op2 += 4;
+ }
+ if(SYCW & 0x400) {
+ L2SP = MemRead32(f12Op2);
+ f12Op2 += 4;
+ }
+ if(SYCW & 0x800) {
+ L3SP = MemRead32(f12Op2);
+ f12Op2 += 4;
+ }
+
+ v60ReloadStack();
+
+ // 31 registers supported, _not_ 32
+ for(i=0; i<31; i++)
+ if(f12Op1 & (1<<i)) {
+ v60.reg[i] = MemRead32(f12Op2);
+ f12Op2 += 4;
+ }
+
+ // #### Ignore the virtual addressing crap.
+
+ F12END();
+}
+
+static UINT32 opMOVD(void) /* TRUSTED */
+{
+ UINT32 a,b;
+
+ F12DecodeOperands(ReadAMAddress,3,ReadAMAddress,3);
+
+ if (f12Flag1)
+ {
+ a=v60.reg[f12Op1&0x1F];
+ b=v60.reg[(f12Op1&0x1F)+1];
+ }
+ else
+ {
+ a=MemRead32(f12Op1);
+ b=MemRead32(f12Op1+4);
+ }
+
+ if (f12Flag2)
+ {
+ v60.reg[f12Op2&0x1F]=a;
+ v60.reg[(f12Op2&0x1F)+1]=b;
+ }
+ else
+ {
+ MemWrite32(f12Op2,a);
+ MemWrite32(f12Op2+4,b);
+ }
+
+ F12END();
+}
+
+static UINT32 opMOVB(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,0);
+ modWriteValB = (UINT8)f12Op1;
+ F12WriteSecondOperand(0);
+ F12END();
+}
+
+static UINT32 opMOVH(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,1);
+ modWriteValH = (UINT16)f12Op1;
+ F12WriteSecondOperand(1);
+ F12END();
+}
+
+static UINT32 opMOVW(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,2);
+ modWriteValW = f12Op1;
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opMOVEAB(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAMAddress,0);
+ modWriteValW = f12Op1;
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opMOVEAH(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAMAddress,1);
+ modWriteValW = f12Op1;
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opMOVEAW(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAMAddress,2);
+ modWriteValW = f12Op1;
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opMOVSBH(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,0);
+ modWriteValH = (INT8)(f12Op1&0xFF);
+ F12WriteSecondOperand(1);
+ F12END();
+}
+
+static UINT32 opMOVSBW(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,0);
+ modWriteValW = (INT8)(f12Op1&0xFF);
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opMOVSHW(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,1);
+ modWriteValW = (INT16)(f12Op1&0xFFFF);
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opMOVTHB(void)
+{
+ F12DecodeFirstOperand(ReadAM,1);
+ modWriteValB = (UINT8)(f12Op1&0xFF);
+
+ // Check for overflow: the truncated bits must match the sign
+ // of the result, otherwise overflow
+ if (((modWriteValB&0x80)==0x80 && ((f12Op1&0xFF00)==0xFF00)) ||
+ ((modWriteValB&0x80)==0 && ((f12Op1&0xFF00)==0x0000)))
+ _OV = 0;
+ else
+ _OV = 1;
+
+ F12WriteSecondOperand(0);
+ F12END();
+}
+
+static UINT32 opMOVTWB(void)
+{
+ F12DecodeFirstOperand(ReadAM,2);
+ modWriteValB = (UINT8)(f12Op1&0xFF);
+
+ // Check for overflow: the truncated bits must match the sign
+ // of the result, otherwise overflow
+ if (((modWriteValB&0x80)==0x80 && ((f12Op1&0xFFFFFF00)==0xFFFFFF00)) ||
+ ((modWriteValB&0x80)==0 && ((f12Op1&0xFFFFFF00)==0x00000000)))
+ _OV = 0;
+ else
+ _OV = 1;
+
+ F12WriteSecondOperand(0);
+ F12END();
+}
+
+static UINT32 opMOVTWH(void)
+{
+ F12DecodeFirstOperand(ReadAM,2);
+ modWriteValH = (UINT16)(f12Op1&0xFFFF);
+
+ // Check for overflow: the truncated bits must match the sign
+ // of the result, otherwise overflow
+ if (((modWriteValH&0x8000)==0x8000 && ((f12Op1&0xFFFF0000)==0xFFFF0000)) ||
+ ((modWriteValH&0x8000)==0 && ((f12Op1&0xFFFF0000)==0x00000000)))
+ _OV = 0;
+ else
+ _OV = 1;
+
+ F12WriteSecondOperand(1);
+ F12END();
+}
+
+
+static UINT32 opMOVZBH(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,0);
+ modWriteValH = (UINT16)f12Op1;
+ F12WriteSecondOperand(1);
+ F12END();
+}
+
+static UINT32 opMOVZBW(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,0);
+ modWriteValW = f12Op1;
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opMOVZHW(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,1);
+ modWriteValW = f12Op1;
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opMULB(void)
+{
+ UINT8 appb;
+ UINT32 tmp;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ // @@@ OV not set!!
+ tmp=(INT8)appb * (INT32)(INT8)f12Op1;
+ appb = tmp;
+ _Z = (appb == 0);
+ _S = ((appb & 0x80)!=0);
+ _OV = ((tmp >> 8)!=0);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opMULH(void)
+{
+ UINT16 apph;
+ UINT32 tmp;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ // @@@ OV not set!!
+ tmp=(INT16)apph * (INT32)(INT16)f12Op1;
+ apph = tmp;
+ _Z = (apph == 0);
+ _S = ((apph & 0x8000)!=0);
+ _OV = ((tmp >> 16)!=0);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opMULW(void)
+{
+ UINT32 appw;
+ UINT64 tmp;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ // @@@ OV not set!!
+ tmp=(INT32)appw * (INT64)(INT32)f12Op1;
+ appw = tmp;
+ _Z = (appw == 0);
+ _S = ((appw & 0x80000000)!=0);
+ _OV = ((tmp >> 32) != 0);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opMULUB(void)
+{
+ UINT8 appb;
+ UINT32 tmp;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ // @@@ OV not set!!
+ tmp = appb * (UINT8)f12Op1;
+ appb = tmp;
+ _Z = (appb == 0);
+ _S = ((appb & 0x80)!=0);
+ _OV = ((tmp >> 8)!=0);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opMULUH(void)
+{
+ UINT16 apph;
+ UINT32 tmp;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ // @@@ OV not set!!
+ tmp=apph * (UINT16)f12Op1;
+ apph = tmp;
+ _Z = (apph == 0);
+ _S = ((apph & 0x8000)!=0);
+ _OV = ((tmp >> 16)!=0);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opMULUW(void)
+{
+ UINT32 appw;
+ UINT64 tmp;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ // @@@ OV not set!!
+ tmp=(UINT64)appw * (UINT64)f12Op1;
+ appw = tmp;
+ _Z = (appw == 0);
+ _S = ((appw & 0x80000000)!=0);
+ _OV = ((tmp >> 32)!=0);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opNEGB(void) /* TRUSTED (C too!)*/
+{
+ F12DecodeFirstOperand(ReadAM,0);
+
+ modWriteValB = 0;
+ SUBB(modWriteValB, (INT8)f12Op1);
+
+ F12WriteSecondOperand(0);
+ F12END();
+}
+
+static UINT32 opNEGH(void) /* TRUSTED (C too!)*/
+{
+ F12DecodeFirstOperand(ReadAM,1);
+
+ modWriteValH = 0;
+ SUBW(modWriteValH, (INT16)f12Op1);
+
+ F12WriteSecondOperand(1);
+ F12END();
+}
+
+static UINT32 opNEGW(void) /* TRUSTED (C too!)*/
+{
+ F12DecodeFirstOperand(ReadAM,2);
+
+ modWriteValW = 0;
+ SUBL(modWriteValW, (INT32)f12Op1);
+
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opNOTB(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,0);
+ modWriteValB=~f12Op1;
+
+ _OV=0;
+ _S=((modWriteValB&0x80)!=0);
+ _Z=(modWriteValB==0);
+
+ F12WriteSecondOperand(0);
+ F12END();
+}
+
+static UINT32 opNOTH(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,1);
+ modWriteValH=~f12Op1;
+
+ _OV=0;
+ _S=((modWriteValH&0x8000)!=0);
+ _Z=(modWriteValH==0);
+
+ F12WriteSecondOperand(1);
+ F12END();
+}
+
+static UINT32 opNOTW(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,2);
+ modWriteValW=~f12Op1;
+
+ _OV=0;
+ _S=((modWriteValW&0x80000000)!=0);
+ _Z=(modWriteValW==0);
+
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opNOT1(void) /* TRUSTED */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ _CY = ((appw & (1<<f12Op1))!=0);
+ _Z = !(_CY);
+
+ if (_CY)
+ appw &= ~(1<<f12Op1);
+ else
+ appw |= (1<<f12Op1);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opORB(void) /* TRUSTED (C too!)*/
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ ORB(appb, (UINT8)f12Op1);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opORH(void) /* TRUSTED (C too!)*/
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ ORW(apph, (UINT16)f12Op1);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opORW(void) /* TRUSTED (C too!) */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ ORL(appw, (UINT32)f12Op1);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opOUTB(void)
+{
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,2);
+ PortWrite8(f12Op2,(UINT8)f12Op1);
+ F12END();
+}
+
+static UINT32 opOUTH(void)
+{
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,2);
+ PortWrite16(f12Op2,(UINT16)f12Op1);
+ F12END();
+}
+
+static UINT32 opOUTW(void)
+{
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+ PortWrite32(f12Op2,f12Op1);
+ F12END();
+}
+
+static UINT32 opREMB(void)
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ _OV = 0;
+ if (f12Op1)
+ appb= (INT8)appb % (INT8)f12Op1;
+ _Z = (appb == 0);
+ _S = ((appb & 0x80)!=0);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opREMH(void)
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ _OV = 0;
+ if (f12Op1)
+ apph=(INT16)apph % (INT16)f12Op1;
+ _Z = (apph == 0);
+ _S = ((apph & 0x8000)!=0);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opREMW(void)
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ _OV = 0;
+ if (f12Op1)
+ appw=(INT32)appw % (INT32)f12Op1;
+ _Z = (appw == 0);
+ _S = ((appw & 0x80000000)!=0);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opREMUB(void)
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ _OV = 0;
+ if (f12Op1)
+ appb %= (UINT8)f12Op1;
+ _Z = (appb == 0);
+ _S = ((appb & 0x80)!=0);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opREMUH(void)
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ _OV = 0;
+ if (f12Op1)
+ apph %= (UINT16)f12Op1;
+ _Z = (apph == 0);
+ _S = ((apph & 0x8000)!=0);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opREMUW(void)
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ _OV = 0;
+ if (f12Op1)
+ appw %= f12Op1;
+ _Z = (appw == 0);
+ _S = ((appw & 0x80000000)!=0);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opROTB(void) /* TRUSTED */
+{
+ UINT8 appb;
+ INT8 i,count;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ count=(INT8)(f12Op1&0xFF);
+ if (count>0)
+ {
+ for (i=0;i<count;i++)
+ appb = (appb<<1) | ((appb&0x80) >> 7);
+
+ _CY=(appb&0x1)!=0;
+ }
+ else if (count<0)
+ {
+ count=-count;
+ for (i=0;i<count;i++)
+ appb = (appb>>1) | ((appb&0x1) << 7);
+
+ _CY=(appb&0x80)!=0;
+ }
+ else
+ _CY=0;
+
+ _OV=0;
+ _S=(appb&0x80)!=0;
+ _Z=(appb==0);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opROTH(void) /* TRUSTED */
+{
+ UINT16 apph;
+ INT8 i,count;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ count=(INT8)(f12Op1&0xFF);
+ if (count>0)
+ {
+ for (i=0;i<count;i++)
+ apph = (apph<<1) | ((apph&0x8000) >> 15);
+
+ _CY=(apph&0x1)!=0;
+ }
+ else if (count<0)
+ {
+ count=-count;
+ for (i=0;i<count;i++)
+ apph = (apph>>1) | ((apph&0x1) << 15);
+
+ _CY=(apph&0x8000)!=0;
+ }
+ else
+ _CY=0;
+
+ _OV=0;
+ _S=(apph&0x8000)!=0;
+ _Z=(apph==0);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opROTW(void) /* TRUSTED */
+{
+ UINT32 appw;
+ INT8 i,count;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ count=(INT8)(f12Op1&0xFF);
+ if (count>0)
+ {
+ for (i=0;i<count;i++)
+ appw = (appw<<1) | ((appw&0x80000000) >> 31);
+
+ _CY=(appw&0x1)!=0;
+ }
+ else if (count<0)
+ {
+ count=-count;
+ for (i=0;i<count;i++)
+ appw = (appw>>1) | ((appw&0x1) << 31);
+
+ _CY=(appw&0x80000000)!=0;
+ }
+ else
+ _CY=0;
+
+ _OV=0;
+ _S=(appw&0x80000000)!=0;
+ _Z=(appw==0);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opROTCB(void) /* TRUSTED */
+{
+ UINT8 appb;
+ INT8 i,cy,count;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+ NORMALIZEFLAGS();
+
+ count=(INT8)(f12Op1&0xFF);
+ if (count>0)
+ {
+ for (i=0;i<count;i++)
+ {
+ cy = _CY;
+ _CY = (UINT8)((appb & 0x80) >> 7);
+ appb = (appb<<1) | cy;
+ }
+ }
+ else if (count<0)
+ {
+ count=-count;
+ for (i=0;i<count;i++)
+ {
+ cy = _CY;
+ _CY = (appb & 1);
+ appb = (appb>>1) | (cy << 7);
+ }
+ }
+ else
+ _CY = 0;
+
+ _OV=0;
+ _S=(appb&0x80)!=0;
+ _Z=(appb==0);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opROTCH(void) /* TRUSTED */
+{
+ UINT16 apph;
+ INT8 i,cy,count;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+ NORMALIZEFLAGS();
+
+ count=(INT8)(f12Op1&0xFF);
+ if (count>0)
+ {
+ for (i=0;i<count;i++)
+ {
+ cy = _CY;
+ _CY = (UINT8)((apph & 0x8000) >> 15);
+ apph = (apph<<1) | cy;
+ }
+ }
+ else if (count<0)
+ {
+ count=-count;
+ for (i=0;i<count;i++)
+ {
+ cy = _CY;
+ _CY = (UINT8)(apph & 1);
+ apph = (apph>>1) | ((UINT16)cy << 15);
+ }
+ }
+ else
+ _CY = 0;
+
+ _OV=0;
+ _S=(apph&0x8000)!=0;
+ _Z=(apph==0);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opROTCW(void) /* TRUSTED */
+{
+ UINT32 appw;
+ INT8 i,cy,count;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+ NORMALIZEFLAGS();
+
+ count=(INT8)(f12Op1&0xFF);
+ if (count>0)
+ {
+ for (i=0;i<count;i++)
+ {
+ cy = _CY;
+ _CY = (UINT8)((appw & 0x80000000) >> 31);
+ appw = (appw<<1) | cy;
+ }
+ }
+ else if (count<0)
+ {
+ count=-count;
+ for (i=0;i<count;i++)
+ {
+ cy = _CY;
+ _CY = (UINT8)(appw & 1);
+ appw = (appw>>1) | ((UINT32)cy << 31);
+ }
+ }
+ else
+ _CY=0;
+
+ _OV=0;
+ _S=(appw&0x80000000)!=0;
+ _Z=(appw==0);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opRVBIT(void)
+{
+ F12DecodeFirstOperand(ReadAM,0);
+
+ modWriteValB =(UINT8)
+ (((f12Op1 & (1<<0)) << 7) |
+ ((f12Op1 & (1<<1)) << 5) |
+ ((f12Op1 & (1<<2)) << 3) |
+ ((f12Op1 & (1<<3)) << 1) |
+ ((f12Op1 & (1<<4)) >> 1) |
+ ((f12Op1 & (1<<5)) >> 3) |
+ ((f12Op1 & (1<<6)) >> 5) |
+ ((f12Op1 & (1<<7)) >> 7));
+
+ F12WriteSecondOperand(0);
+ F12END();
+}
+
+static UINT32 opRVBYT(void) /* TRUSTED */
+{
+ F12DecodeFirstOperand(ReadAM,2);
+
+ modWriteValW = ((f12Op1 & 0x000000FF) << 24) |
+ ((f12Op1 & 0x0000FF00) << 8) |
+ ((f12Op1 & 0x00FF0000) >> 8) |
+ ((f12Op1 & 0xFF000000) >> 24);
+
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+static UINT32 opSET1(void) /* TRUSTED */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ _CY = ((appw & (1<<f12Op1))!=0);
+ _Z = !(_CY);
+
+ appw |= (1<<f12Op1);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+
+static UINT32 opSETF(void)
+{
+ F12DecodeFirstOperand(ReadAM,0);
+
+ // Normalize the flags
+ NORMALIZEFLAGS();
+
+ switch (f12Op1 & 0xF)
+ {
+ case 0:
+ if (!_OV) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 1:
+ if (_OV) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 2:
+ if (!_CY) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 3:
+ if (_CY) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 4:
+ if (!_Z) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 5:
+ if (_Z) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 6:
+ if (!(_CY | _Z)) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 7:
+ if ((_CY | _Z)) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 8:
+ if (!_S) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 9:
+ if (_S) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 10:
+ modWriteValB=1;
+ break;
+ case 11:
+ modWriteValB=0;
+ break;
+ case 12:
+ if (!(_S^_OV)) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 13:
+ if ((_S^_OV)) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 14:
+ if (!((_S^_OV)|_Z)) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ case 15:
+ if (((_S^_OV)|_Z)) modWriteValB=0;
+ else modWriteValB=1;
+ break;
+ }
+
+ F12WriteSecondOperand(0);
+
+ F12END();
+}
+
+/*
+#define SHIFTLEFT_OY(val, count, bitsize) \
+{\
+ UINT32 tmp = ((val) >> (bitsize-1)) & 1; \
+ tmp <<= count; \
+ tmp -= 1; \
+ tmp <<= (bitsize - (count)); \
+ _OV = (((val) & tmp) != tmp); \
+ _CY = (((val) & (1 << (count-1))) != 0); \
+}
+*/
+
+// During the shift, the overflow is set if the sign bit changes at any point during the shift
+#define SHIFTLEFT_OV(val, count, bitsize) \
+{\
+ UINT32 tmp; \
+ if (count == 32) \
+ tmp = 0xFFFFFFFF; \
+ else \
+ tmp = ((1 << (count)) - 1); \
+ tmp <<= (bitsize - (count)); \
+ if (((val) >> (bitsize-1)) & 1) \
+ _OV = (((val) & tmp) != tmp); \
+ else \
+ _OV = (((val) & tmp) != 0); \
+}
+
+#define SHIFTLEFT_CY(val, count, bitsize) \
+ _CY = (UINT8)(((val) >> (bitsize - count)) & 1);
+
+
+
+#define SHIFTARITHMETICRIGHT_OV(val, count, bitsize) \
+ _OV = 0;
+
+#define SHIFTARITHMETICRIGHT_CY(val, count, bitsize) \
+ _CY = (UINT8)(((val) >> (count-1)) & 1);
+
+
+
+static UINT32 opSHAB(void)
+{
+ UINT8 appb;
+ INT8 count;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ count=(INT8)(f12Op1&0xFF);
+
+ // Special case: destination unchanged, flags set
+ if (count == 0)
+ {
+ _CY = _OV = 0;
+ SetSZPF_Byte(appb);
+ }
+ else if (count>0)
+ {
+ SHIFTLEFT_OV(appb, count, 8);
+
+ // @@@ Undefined what happens to CY when count >= bitsize
+ SHIFTLEFT_CY(appb, count, 8);
+
+ // do the actual shift...
+ if (count >= 8)
+ appb = 0;
+ else
+ appb <<= count;
+
+ // and set zero and sign
+ SetSZPF_Byte(appb);
+ }
+ else
+ {
+ count = -count;
+
+ SHIFTARITHMETICRIGHT_OV(appb, count, 8);
+ SHIFTARITHMETICRIGHT_CY(appb, count, 8);
+
+ if (count >= 8)
+ appb = (appb & 0x80) ? 0xFF : 0;
+ else
+ appb = ((INT8)appb) >> count;
+
+ SetSZPF_Byte(appb);
+ }
+
+// mame_printf_debug("SHAB: %x _CY: %d _Z: %d _OV: %d _S: %d\n", appb, _CY, _Z, _OV, _S);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opSHAH(void)
+{
+ UINT16 apph;
+ INT8 count;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ count=(INT8)(f12Op1&0xFF);
+
+ // Special case: destination unchanged, flags set
+ if (count == 0)
+ {
+ _CY = _OV = 0;
+ SetSZPF_Word(apph);
+ }
+ else if (count>0)
+ {
+ SHIFTLEFT_OV(apph, count, 16);
+
+ // @@@ Undefined what happens to CY when count >= bitsize
+ SHIFTLEFT_CY(apph, count, 16);
+
+ // do the actual shift...
+ if (count >= 16)
+ apph = 0;
+ else
+ apph <<= count;
+
+ // and set zero and sign
+ SetSZPF_Word(apph);
+ }
+ else
+ {
+ count = -count;
+
+ SHIFTARITHMETICRIGHT_OV(apph, count, 16);
+ SHIFTARITHMETICRIGHT_CY(apph, count, 16);
+
+ if (count >= 16)
+ apph = (apph & 0x8000) ? 0xFFFF : 0;
+ else
+ apph = ((INT16)apph) >> count;
+
+ SetSZPF_Word(apph);
+ }
+
+// mame_printf_debug("SHAH: %x >> %d = %x _CY: %d _Z: %d _OV: %d _S: %d\n", oldval, count, apph, _CY, _Z, _OV, _S);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opSHAW(void)
+{
+ UINT32 appw;
+ INT8 count;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ count=(INT8)(f12Op1&0xFF);
+
+ // Special case: destination unchanged, flags set
+ if (count == 0)
+ {
+ _CY = _OV = 0;
+ SetSZPF_Long(appw);
+ }
+ else if (count>0)
+ {
+ SHIFTLEFT_OV(appw, count, 32);
+
+ // @@@ Undefined what happens to CY when count >= bitsize
+ SHIFTLEFT_CY(appw, count, 32);
+
+ // do the actual shift...
+ if (count >= 32)
+ appw = 0;
+ else
+ appw <<= count;
+
+ // and set zero and sign
+ SetSZPF_Long(appw);
+ }
+ else
+ {
+ count = -count;
+
+ SHIFTARITHMETICRIGHT_OV(appw, count, 32);
+ SHIFTARITHMETICRIGHT_CY(appw, count, 32);
+
+ if (count >= 32)
+ appw = (appw & 0x80000000) ? 0xFFFFFFFF : 0;
+ else
+ appw = ((INT32)appw) >> count;
+
+ SetSZPF_Long(appw);
+ }
+
+// mame_printf_debug("SHAW: %x >> %d = %x _CY: %d _Z: %d _OV: %d _S: %d\n", oldval, count, appw, _CY, _Z, _OV, _S);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+
+static UINT32 opSHLB(void) /* TRUSTED */
+{
+ UINT8 appb;
+ INT8 count;
+ UINT32 tmp;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ count=(INT8)(f12Op1&0xFF);
+ if (count>0)
+ {
+ // left shift flags:
+ // carry gets the last bit shifted out,
+ // overflow is always CLEARed
+
+ _OV = 0; // default to no overflow
+
+ // now handle carry
+ tmp = appb & 0xff;
+ tmp <<= count;
+ SetCFB(tmp); // set carry properly
+
+ // do the actual shift...
+ appb <<= count;
+
+ // and set zero and sign
+ SetSZPF_Byte(appb);
+ }
+ else
+ {
+ if (count == 0)
+ {
+ // special case: clear carry and overflow, do nothing else
+ _CY = _OV = 0;
+ SetSZPF_Byte(appb); // doc. is unclear if this is true...
+ }
+ else
+ {
+ // right shift flags:
+ // carry = last bit shifted out
+ // overflow always cleared
+ tmp = appb & 0xff;
+ tmp >>= ((-count)-1);
+ _CY = (UINT8)(tmp & 0x1);
+ _OV = 0;
+
+ appb >>= -count;
+ SetSZPF_Byte(appb);
+ }
+ }
+
+// mame_printf_debug("SHLB: %x _CY: %d _Z: %d _OV: %d _S: %d\n", appb, _CY, _Z, _OV, _S);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opSHLH(void) /* TRUSTED */
+{
+ UINT16 apph;
+ INT8 count;
+ UINT32 tmp;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ count=(INT8)(f12Op1&0xFF);
+// mame_printf_debug("apph: %x count: %d ", apph, count);
+ if (count>0)
+ {
+ // left shift flags:
+ // carry gets the last bit shifted out,
+ // overflow is always CLEARed
+
+ _OV = 0;
+
+ // now handle carry
+ tmp = apph & 0xffff;
+ tmp <<= count;
+ SetCFW(tmp); // set carry properly
+
+ // do the actual shift...
+ apph <<= count;
+
+ // and set zero and sign
+ SetSZPF_Word(apph);
+ }
+ else
+ {
+ if (count == 0)
+ {
+ // special case: clear carry and overflow, do nothing else
+ _CY = _OV = 0;
+ SetSZPF_Word(apph); // doc. is unclear if this is true...
+ }
+ else
+ {
+ // right shift flags:
+ // carry = last bit shifted out
+ // overflow always cleared
+ tmp = apph & 0xffff;
+ tmp >>= ((-count)-1);
+ _CY = (UINT8)(tmp & 0x1);
+ _OV = 0;
+
+ apph >>= -count;
+ SetSZPF_Word(apph);
+ }
+ }
+
+// mame_printf_debug("SHLH: %x _CY: %d _Z: %d _OV: %d _S: %d\n", apph, _CY, _Z, _OV, _S);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opSHLW(void) /* TRUSTED */
+{
+ UINT32 appw;
+ INT8 count;
+ UINT64 tmp;
+
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ count=(INT8)(f12Op1&0xFF);
+ if (count>0)
+ {
+ // left shift flags:
+ // carry gets the last bit shifted out,
+ // overflow is always CLEARed
+
+ _OV = 0;
+
+ // now handle carry
+ tmp = appw & 0xffffffff;
+ tmp <<= count;
+ SetCFL(tmp); // set carry properly
+
+ // do the actual shift...
+ appw <<= count;
+
+ // and set zero and sign
+ SetSZPF_Long(appw);
+ }
+ else
+ {
+ if (count == 0)
+ {
+ // special case: clear carry and overflow, do nothing else
+ _CY = _OV = 0;
+ SetSZPF_Long(appw); // doc. is unclear if this is true...
+ }
+ else
+ {
+ // right shift flags:
+ // carry = last bit shifted out
+ // overflow always cleared
+ tmp = (UINT64)(appw & 0xffffffff);
+ tmp >>= ((-count)-1);
+ _CY = (UINT8)(tmp & 0x1);
+ _OV = 0;
+
+ appw >>= -count;
+ SetSZPF_Long(appw);
+ }
+ }
+
+// mame_printf_debug("SHLW: %x _CY: %d _Z: %d _OV: %d _S: %d\n", appw, _CY, _Z, _OV, _S);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opSTPR(void)
+{
+ F12DecodeFirstOperand(ReadAM,2);
+ if (f12Op1 >= 0 && f12Op1 <= 28)
+ modWriteValW = v60.reg[f12Op1 + 36];
+ else
+ {
+ fatalerror("Invalid operand on STPR PC=%x", PC);
+ }
+ F12WriteSecondOperand(2);
+ F12END();
+}
+
+
+static UINT32 opSUBB(void) /* TRUSTED (C too!) */
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ SUBB(appb, (UINT8)f12Op1);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opSUBH(void) /* TRUSTED (C too!) */
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ SUBW(apph, (UINT16)f12Op1);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opSUBW(void) /* TRUSTED (C too!) */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ SUBL(appw, (UINT32)f12Op1);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+
+static UINT32 opSUBCB(void)
+{
+ UINT8 appb;
+ UINT8 src;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ src = (UINT8)f12Op1 + (_CY?1:0);
+ SUBB(appb, src);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opSUBCH(void)
+{
+ UINT16 apph;
+ UINT16 src;
+
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ src = (UINT16)f12Op1 + (_CY?1:0);
+ SUBW(apph, src);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opSUBCW(void)
+{
+ UINT32 appw;
+ UINT32 src;
+
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ src = (UINT32)f12Op1 + (_CY?1:0);
+ SUBL(appw, src);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opTEST1(void)
+{
+ F12DecodeOperands(ReadAM,2,ReadAM,2);
+
+ _CY = ((f12Op2 & (1<<f12Op1))!=0);
+ _Z = !(_CY);
+
+ F12END();
+}
+
+static UINT32 opUPDPSWW(void)
+{
+ F12DecodeOperands(ReadAM,2,ReadAM,2);
+
+ /* can only modify condition code and control fields */
+ f12Op2 &= 0xFFFFFF;
+ f12Op1 &= 0xFFFFFF;
+ v60WritePSW((v60ReadPSW() & (~f12Op2)) | (f12Op1 & f12Op2));
+
+ F12END();
+}
+
+static UINT32 opUPDPSWH(void)
+{
+ F12DecodeOperands(ReadAM,2,ReadAM,2);
+
+ /* can only modify condition code fields */
+ f12Op2 &= 0xFFFF;
+ f12Op1 &= 0xFFFF;
+ v60WritePSW((v60ReadPSW() & (~f12Op2)) | (f12Op1 & f12Op2));
+
+ F12END();
+}
+
+static UINT32 opXCHB(void) /* TRUSTED */
+{
+ UINT8 appb, temp;
+
+ F12DecodeOperands(ReadAMAddress,0,ReadAMAddress,0);
+
+ F12LOADOP1BYTE();
+ temp=appb;
+ F12LOADOP2BYTE();
+ F12STOREOP1BYTE();
+ appb=temp;
+ F12STOREOP2BYTE();
+
+ F12END()
+}
+
+static UINT32 opXCHH(void) /* TRUSTED */
+{
+ UINT16 apph, temp;
+
+ F12DecodeOperands(ReadAMAddress,1,ReadAMAddress,1);
+
+ F12LOADOP1HALF();
+ temp=apph;
+ F12LOADOP2HALF();
+ F12STOREOP1HALF();
+ apph=temp;
+ F12STOREOP2HALF();
+
+ F12END()
+}
+
+static UINT32 opXCHW(void) /* TRUSTED */
+{
+ UINT32 appw, temp;
+
+ F12DecodeOperands(ReadAMAddress,2,ReadAMAddress,2);
+
+ F12LOADOP1WORD();
+ temp=appw;
+ F12LOADOP2WORD();
+ F12STOREOP1WORD();
+ appw=temp;
+ F12STOREOP2WORD();
+
+ F12END()
+}
+
+static UINT32 opXORB(void) /* TRUSTED (C too!) */
+{
+ UINT8 appb;
+ F12DecodeOperands(ReadAM,0,ReadAMAddress,0);
+
+ F12LOADOP2BYTE();
+
+ XORB(appb, (UINT8)f12Op1);
+
+ F12STOREOP2BYTE();
+ F12END();
+}
+
+static UINT32 opXORH(void) /* TRUSTED (C too!) */
+{
+ UINT16 apph;
+ F12DecodeOperands(ReadAM,1,ReadAMAddress,1);
+
+ F12LOADOP2HALF();
+
+ XORW(apph, (UINT16)f12Op1);
+
+ F12STOREOP2HALF();
+ F12END();
+}
+
+static UINT32 opXORW(void) /* TRUSTED (C too!) */
+{
+ UINT32 appw;
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,2);
+
+ F12LOADOP2WORD();
+
+ XORL(appw, (UINT32)f12Op1);
+
+ F12STOREOP2WORD();
+ F12END();
+}
+
+static UINT32 opMULX(void)
+{
+ INT32 a,b;
+ INT64 res;
+
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,3);
+
+ if (f12Flag2)
+ {
+ a=v60.reg[f12Op2&0x1F];
+ }
+ else
+ {
+ a=MemRead32(f12Op2);
+ }
+
+ res = (INT64)a * (INT64)(INT32)f12Op1;
+
+ b = (INT32)((res >> 32)&0xffffffff);
+ a = (INT32)(res&0xffffffff);
+
+ _S = ((b & 0x80000000) != 0);
+ _Z = (a == 0 && b == 0);
+
+ if (f12Flag2)
+ {
+ v60.reg[f12Op2&0x1F]=a;
+ v60.reg[(f12Op2&0x1F)+1]=b;
+ }
+ else
+ {
+ MemWrite32(f12Op2,a);
+ MemWrite32(f12Op2+4,b);
+ }
+
+ F12END();
+}
+
+static UINT32 opMULUX(void)
+{
+ INT32 a,b;
+ UINT64 res;
+
+ F12DecodeOperands(ReadAM,2,ReadAMAddress,3);
+
+ if (f12Flag2)
+ {
+ a=v60.reg[f12Op2&0x1F];
+ }
+ else
+ {
+ a=MemRead32(f12Op2);
+ }
+
+ res = (UINT64)a * (UINT64)f12Op1;
+ b = (INT32)((res >> 32)&0xffffffff);
+ a = (INT32)(res&0xffffffff);
+
+ _S = ((b & 0x80000000) != 0);
+ _Z = (a == 0 && b == 0);
+
+ if (f12Flag2)
+ {
+ v60.reg[f12Op2&0x1F]=a;
+ v60.reg[(f12Op2&0x1F)+1]=b;
+ }
+ else
+ {
+ MemWrite32(f12Op2,a);
+ MemWrite32(f12Op2+4,b);
+ }
+
+ F12END();
+}
diff --git a/src/emu/cpu/v60/op2.c b/src/emu/cpu/v60/op2.c
new file mode 100644
index 00000000000..d1a6bc6c3d7
--- /dev/null
+++ b/src/emu/cpu/v60/op2.c
@@ -0,0 +1,359 @@
+
+
+#define if2 if12
+#define f2Op1 f12Op1
+#define f2Op2 f12Op2
+#define f2Flag1 f12Flag1
+#define f2Flag2 f12Flag2
+
+#define F2END() \
+ return 2+amLength1+amLength2;
+
+#define F2LOADOPFLOAT(num) \
+ if (f2Flag##num) \
+ appf = u2f(v60.reg[f2Op##num]); \
+ else \
+ appf = u2f(MemRead32(f2Op##num));
+
+#define F2STOREOPFLOAT(num) \
+ if (f2Flag##num) \
+ v60.reg[f2Op##num] = f2u(appf); \
+ else \
+ MemWrite32(f2Op##num, f2u(appf));
+
+static void F2DecodeFirstOperand(UINT32 (*DecodeOp1)(void), UINT8 dim1)
+{
+ modDim = dim1;
+ modM = if2 & 0x40;
+ modAdd = PC + 2;
+ amLength1 = DecodeOp1();
+ f2Op1 = amOut;
+ f2Flag1 = amFlag;
+}
+
+static void F2DecodeSecondOperand(UINT32 (*DecodeOp2)(void), UINT8 dim2)
+{
+ modDim = dim2;
+ modM = if2 & 0x20;
+ modAdd = PC + 2 + amLength1;
+ amLength2 = DecodeOp2();
+ f2Op2 = amOut;
+ f2Flag2 = amFlag;
+}
+
+static void F2WriteSecondOperand(UINT8 dim2)
+{
+ modDim = dim2;
+ modM = if2 & 0x20;
+ modAdd = PC + 2 + amLength1;
+ amLength2 = WriteAM();
+}
+
+static UINT32 opCVTWS(void)
+{
+ float val;
+
+ F2DecodeFirstOperand(ReadAM,2);
+
+ // Convert to float
+ val = (float)(INT32)f2Op1;
+ modWriteValW = f2u(val);
+
+ _OV=0;
+ _CY=(val < 0.0f);
+ _S=((modWriteValW & 0x80000000)!=0);
+ _Z=(val == 0.0f);
+
+ F2WriteSecondOperand(2);
+ F2END();
+}
+
+static UINT32 opCVTSW(void)
+{
+ float val;
+
+ F2DecodeFirstOperand(ReadAM,2);
+
+ // Convert to UINT32
+ val = u2f(f2Op1);
+ modWriteValW = (UINT32)val;
+
+ _OV=0;
+ _CY=(val < 0.0f);
+ _S=((modWriteValW & 0x80000000)!=0);
+ _Z=(val == 0.0f);
+
+ F2WriteSecondOperand(2);
+ F2END();
+}
+
+static UINT32 opMOVFS(void)
+{
+ F2DecodeFirstOperand(ReadAM,2);
+ modWriteValW = f2Op1;
+ F2WriteSecondOperand(2);
+ F2END();
+}
+
+static UINT32 opNEGFS(void)
+{
+ float appf;
+
+ F2DecodeFirstOperand(ReadAM, 2);
+ F2DecodeSecondOperand(ReadAMAddress, 2);
+
+ appf = -u2f(f2Op1);
+
+ _OV=0;
+ _CY=(appf < 0.0f);
+ _S=((f2u(appf) & 0x80000000)!=0);
+ _Z=(appf == 0.0f);
+
+ F2STOREOPFLOAT(2);
+ F2END()
+}
+
+static UINT32 opABSFS(void)
+{
+ float appf;
+
+ F2DecodeFirstOperand(ReadAM, 2);
+ F2DecodeSecondOperand(ReadAMAddress, 2);
+
+ appf = u2f(f2Op1);
+
+ if(appf < 0)
+ appf = -appf;
+
+ _OV=0;
+ _CY=0;
+ _S=((f2u(appf) & 0x80000000)!=0);
+ _Z=(appf == 0.0f);
+
+ F2STOREOPFLOAT(2);
+ F2END()
+}
+
+static UINT32 opADDFS(void)
+{
+ UINT32 appw;
+ float appf;
+
+ F2DecodeFirstOperand(ReadAM, 2);
+ F2DecodeSecondOperand(ReadAMAddress, 2);
+
+ F2LOADOPFLOAT(2);
+
+ appf += u2f(f2Op1);
+
+ appw = f2u(appf);
+ _OV = _CY = 0;
+ _S = ((appw & 0x80000000)!=0);
+ _Z = (appw == 0);
+
+ F2STOREOPFLOAT(2);
+ F2END()
+}
+
+static UINT32 opSUBFS(void)
+{
+ UINT32 appw;
+ float appf;
+
+ F2DecodeFirstOperand(ReadAM, 2);
+ F2DecodeSecondOperand(ReadAMAddress, 2);
+
+ F2LOADOPFLOAT(2);
+
+ appf -= u2f(f2Op1);
+
+ appw = f2u(appf);
+ _OV = _CY = 0;
+ _S = ((appw & 0x80000000)!=0);
+ _Z = (appw == 0);
+
+ F2STOREOPFLOAT(2);
+ F2END()
+}
+
+static UINT32 opMULFS(void)
+{
+ UINT32 appw;
+ float appf;
+
+ F2DecodeFirstOperand(ReadAM, 2);
+ F2DecodeSecondOperand(ReadAMAddress, 2);
+
+ F2LOADOPFLOAT(2);
+
+ appf *= u2f(f2Op1);
+
+ appw = f2u(appf);
+ _OV = _CY = 0;
+ _S = ((appw & 0x80000000)!=0);
+ _Z = (appw == 0);
+
+ F2STOREOPFLOAT(2);
+ F2END()
+}
+
+static UINT32 opDIVFS(void)
+{
+ UINT32 appw;
+ float appf;
+
+ F2DecodeFirstOperand(ReadAM, 2);
+ F2DecodeSecondOperand(ReadAMAddress, 2);
+
+ F2LOADOPFLOAT(2);
+
+ appf /= u2f(f2Op1);
+
+ appw = f2u(appf);
+ _OV = _CY = 0;
+ _S = ((appw & 0x80000000)!=0);
+ _Z = (appw == 0);
+
+ F2STOREOPFLOAT(2);
+ F2END()
+}
+
+static UINT32 opSCLFS(void)
+{
+ UINT32 appw;
+ float appf;
+
+ F2DecodeFirstOperand(ReadAM, 1);
+ F2DecodeSecondOperand(ReadAMAddress, 2);
+
+ F2LOADOPFLOAT(2);
+
+ if ((INT16)f2Op1 < 0)
+ appf /= 1 << -(INT16)f2Op1;
+ else
+ appf *= 1 << f2Op1;
+
+ appw = f2u(appf);
+ _OV = _CY = 0;
+ _S = ((appw & 0x80000000)!=0);
+ _Z = (appw == 0);
+
+ F2STOREOPFLOAT(2);
+ F2END()
+}
+
+static UINT32 opCMPF(void)
+{
+ float appf;
+
+ F2DecodeFirstOperand(ReadAM, 2);
+ F2DecodeSecondOperand(ReadAM, 2);
+
+ appf = u2f(f2Op2) - u2f(f2Op1);
+
+ _Z = (appf == 0);
+ _S = (appf < 0);
+ _OV = 0;
+ _CY = 0;
+
+ F2END();
+}
+
+static UINT32 op5FUNHANDLED(void)
+{
+ fatalerror("Unhandled 5F opcode at %08x", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 op5CUNHANDLED(void)
+{
+ fatalerror("Unhandled 5C opcode at %08x", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 (*const Op5FTable[32])(void) =
+{
+ opCVTWS,
+ opCVTSW,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED,
+ op5FUNHANDLED
+};
+
+static UINT32 (*const Op5CTable[32])(void) =
+{
+ opCMPF,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ opMOVFS,
+ opNEGFS,
+ opABSFS,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+
+ opSCLFS,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ opADDFS,
+ opSUBFS,
+ opMULFS,
+ opDIVFS,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED,
+ op5CUNHANDLED
+};
+
+
+static UINT32 op5F(void)
+{
+ if2 = OpRead8(PC + 1);
+ return Op5FTable[if2&0x1F]();
+}
+
+
+static UINT32 op5C(void)
+{
+ if2 = OpRead8(PC + 1);
+ return Op5CTable[if2&0x1F]();
+}
diff --git a/src/emu/cpu/v60/op3.c b/src/emu/cpu/v60/op3.c
new file mode 100644
index 00000000000..79c12fa0dac
--- /dev/null
+++ b/src/emu/cpu/v60/op3.c
@@ -0,0 +1,645 @@
+static UINT32 opINCB(void) /* TRUSTED */
+{
+ UINT8 appb;
+ modAdd=PC+1;
+ modDim=0;
+
+ amLength1=ReadAMAddress();
+
+ if (amFlag)
+ appb=(UINT8)v60.reg[amOut];
+ else
+ appb=MemRead8(amOut);
+
+ ADDB(appb, 1);
+
+ if (amFlag)
+ SETREG8(v60.reg[amOut], appb);
+ else
+ MemWrite8(amOut, appb);
+
+ return amLength1+1;
+}
+
+static UINT32 opINCH(void) /* TRUSTED */
+{
+ UINT16 apph;
+ modAdd=PC+1;
+ modDim=1;
+
+ amLength1=ReadAMAddress();
+
+ if (amFlag)
+ apph=(UINT16)v60.reg[amOut];
+ else
+ apph=MemRead16(amOut);
+
+ ADDW(apph, 1);
+
+ if (amFlag)
+ SETREG16(v60.reg[amOut], apph);
+ else
+ MemWrite16(amOut, apph);
+
+ return amLength1+1;
+}
+
+static UINT32 opINCW(void) /* TRUSTED */
+{
+ UINT32 appw;
+ modAdd=PC+1;
+ modDim=2;
+
+ amLength1=ReadAMAddress();
+
+ if (amFlag)
+ appw=v60.reg[amOut];
+ else
+ appw=MemRead32(amOut);
+
+ ADDL(appw, 1);
+
+ if (amFlag)
+ v60.reg[amOut]=appw;
+ else
+ MemWrite32(amOut,appw);
+
+ return amLength1+1;
+}
+
+static UINT32 opDECB(void) /* TRUSTED */
+{
+ UINT8 appb;
+ modAdd=PC+1;
+ modDim=0;
+
+ amLength1=ReadAMAddress();
+
+ if (amFlag)
+ appb=(UINT8)v60.reg[amOut];
+ else
+ appb=MemRead8(amOut);
+
+ SUBB(appb, 1);
+
+ if (amFlag)
+ SETREG8(v60.reg[amOut], appb);
+ else
+ MemWrite8(amOut, appb);
+
+ return amLength1+1;
+}
+
+static UINT32 opDECH(void) /* TRUSTED */
+{
+ UINT16 apph;
+ modAdd=PC+1;
+ modDim=1;
+
+ amLength1=ReadAMAddress();
+
+ if (amFlag)
+ apph=(UINT16)v60.reg[amOut];
+ else
+ apph=MemRead16(amOut);
+
+ SUBW(apph, 1);
+
+ if (amFlag)
+ SETREG16(v60.reg[amOut], apph);
+ else
+ MemWrite16(amOut, apph);
+
+ return amLength1+1;
+}
+
+static UINT32 opDECW(void) /* TRUSTED */
+{
+ UINT32 appw;
+ modAdd=PC+1;
+ modDim=2;
+
+ amLength1=ReadAMAddress();
+
+ if (amFlag)
+ appw=v60.reg[amOut];
+ else
+ appw=MemRead32(amOut);
+
+ SUBL(appw, 1);
+
+ if (amFlag)
+ v60.reg[amOut]=appw;
+ else
+ MemWrite32(amOut,appw);
+
+ return amLength1+1;
+}
+
+static UINT32 opJMP(void) /* TRUSTED */
+{
+ modAdd=PC+1;
+ modDim=0;
+
+ // Read the address of the operand
+ ReadAMAddress();
+
+ // It cannot be a register!!
+ assert(amFlag==0);
+
+ // Jump there
+ PC=amOut;
+ ChangePC(PC);
+
+ return 0;
+}
+
+static UINT32 opJSR(void) /* TRUSTED */
+{
+ modAdd=PC + 1;
+ modDim=0;
+
+ // Read the address of the operand
+ amLength1=ReadAMAddress();
+
+ // It cannot be a register!!
+ assert(amFlag==0);
+
+ // Save NextPC into the stack
+ SP -= 4;
+ MemWrite32(SP, PC + amLength1 + 1);
+
+ // Jump there
+ PC=amOut;
+ ChangePC(PC);
+
+ return 0;
+}
+
+static UINT32 opPREPARE(void) /* somewhat TRUSTED */
+{
+ modAdd=PC+1;
+ modDim=2;
+
+ // Read the operand
+ amLength1=ReadAM();
+
+ // step 1: save frame pointer on the stack
+ SP -= 4;
+ MemWrite32(SP, FP);
+
+ // step 2: FP = new SP
+ FP = SP;
+
+ // step 3: SP -= operand
+ SP -= amOut;
+
+ return amLength1 + 1;
+}
+
+static UINT32 opRET(void) /* TRUSTED */
+{
+ modAdd=PC + 1;
+ modDim=2;
+
+ // Read the operand
+ ReadAM();
+
+ // Read return address from stack
+ PC=MemRead32(SP);
+ SP+=4;
+ ChangePC(PC);
+
+ // Restore AP from stack
+ AP=MemRead32(SP);
+ SP+=4;
+
+ // Skip stack frame
+ SP += amOut;
+
+ return 0;
+}
+
+static UINT32 opTRAP(void)
+{
+ UINT32 oldPSW;
+
+ modAdd=PC + 1;
+ modDim=0;
+
+ // Read the operand
+ amLength1=ReadAM();
+
+ // Normalize the flags
+ NORMALIZEFLAGS();
+
+ switch ((amOut >> 4) & 0xF)
+ {
+ case 0:
+ if (!_OV) return amLength1+1;
+ else break;
+ case 1:
+ if (_OV) return amLength1+1;
+ else break;
+ case 2:
+ if (!_CY) return amLength1+1;
+ else break;
+ case 3:
+ if (_CY) return amLength1+1;
+ else break;
+ case 4:
+ if (!_Z) return amLength1+1;
+ else break;
+ case 5:
+ if (_Z) return amLength1+1;
+ else break;
+ case 6:
+ if (!(_CY | _Z)) return amLength1+1;
+ else break;
+ case 7:
+ if ((_CY | _Z)) return amLength1+1;
+ else break;
+ case 8:
+ if (!_S) return amLength1+1;
+ else break;
+ case 9:
+ if (_S) return amLength1+1;
+ else break;
+ case 10:
+ break;
+ case 11:
+ return amLength1+1;
+ case 12:
+ if (!(_S^_OV)) return amLength1+1;
+ else break;
+ case 13:
+ if ((_S^_OV)) return amLength1+1;
+ else break;
+ case 14:
+ if (!((_S^_OV)|_Z)) return amLength1+1;
+ else break;
+ case 15:
+ if (((_S^_OV)|_Z)) return amLength1+1;
+ else break;
+ }
+
+ oldPSW = v60_update_psw_for_exception(0, 0);
+
+ // Issue the software trap with interrupts
+ SP -= 4;
+ MemWrite32(SP, EXCEPTION_CODE_AND_SIZE(0x3000 + 0x100 * (amOut&0xF), 4));
+
+ SP -= 4;
+ MemWrite32(SP, oldPSW);
+
+ SP -= 4;
+ MemWrite32(SP, PC + amLength1 + 1);
+
+ PC = GETINTVECT(48 + (amOut&0xF));
+ ChangePC(PC);
+
+ return 0;
+}
+
+static UINT32 opRETIU(void) /* TRUSTED */
+{
+ UINT32 newPSW;
+ modAdd=PC + 1;
+ modDim=1;
+
+ // Read the operand
+ ReadAM();
+
+ // Restore PC and PSW from stack
+ PC = MemRead32(SP);
+ SP += 4;
+ ChangePC(PC);
+
+ newPSW = MemRead32(SP);
+ SP += 4;
+
+ // Destroy stack frame
+ SP += amOut;
+
+ v60WritePSW(newPSW);
+
+ return 0;
+}
+
+static UINT32 opRETIS(void)
+{
+ UINT32 newPSW;
+
+ modAdd=PC + 1;
+ modDim=1;
+
+ // Read the operand
+ ReadAM();
+
+ // Restore PC and PSW from stack
+ PC = MemRead32(SP);
+ SP += 4;
+ ChangePC(PC);
+
+ newPSW = MemRead32(SP);
+ SP += 4;
+
+ // Destroy stack frame
+ SP += amOut;
+
+ v60WritePSW(newPSW);
+
+ return 0;
+}
+
+static UINT32 opSTTASK(void)
+{
+ int i;
+ UINT32 adr;
+
+ modAdd=PC + 1;
+ modDim=2;
+
+ amLength1 = ReadAM();
+
+ adr = TR;
+
+ v60WritePSW(v60ReadPSW() | 0x10000000);
+ v60SaveStack();
+
+ MemWrite32(adr, TKCW);
+ adr += 4;
+ if(SYCW & 0x100) {
+ MemWrite32(adr, L0SP);
+ adr += 4;
+ }
+ if(SYCW & 0x200) {
+ MemWrite32(adr, L1SP);
+ adr += 4;
+ }
+ if(SYCW & 0x400) {
+ MemWrite32(adr, L2SP);
+ adr += 4;
+ }
+ if(SYCW & 0x800) {
+ MemWrite32(adr, L3SP);
+ adr += 4;
+ }
+
+ // 31 registers supported, _not_ 32
+ for(i=0; i<31; i++)
+ if(amOut & (1<<i)) {
+ MemWrite32(adr, v60.reg[i]);
+ adr += 4;
+ }
+
+ // #### Ignore the virtual addressing crap.
+
+ return amLength1 + 1;
+}
+
+static UINT32 opGETPSW(void)
+{
+ modAdd=PC + 1;
+ modDim=2;
+ modWriteValW=v60ReadPSW();
+
+ // Write PSW to the operand
+ amLength1=WriteAM();
+
+ return amLength1 + 1;
+}
+
+static UINT32 opTASI(void)
+{
+ UINT8 appb;
+ modAdd=PC + 1;
+ modDim=0;
+
+ // Load the address of the operand
+ amLength1=ReadAMAddress();
+
+ // Load UINT8 from the address
+ if (amFlag)
+ appb=(UINT8)v60.reg[amOut&0x1F];
+ else
+ appb=MemRead8(amOut);
+
+ // Set the flags for SUB appb,FF
+ SUBB(appb, 0xff);
+
+ // Write FF in the operand
+ if (amFlag)
+ SETREG8(v60.reg[amOut&0x1F], 0xFF);
+ else
+ MemWrite8(amOut,0xFF);
+
+ return amLength1 + 1;
+}
+
+static UINT32 opCLRTLB(void)
+{
+ modAdd=PC+1;
+ modDim=2;
+
+ // Read the operand
+ amLength1=ReadAM();
+
+ // @@@ TLB not yet emulated
+
+ return amLength1 + 1;
+}
+
+static UINT32 opPOPM(void)
+{
+ int i;
+
+ modAdd=PC+1;
+ modDim=2;
+
+ // Read the bit register list
+ amLength1=ReadAM();
+
+ for (i=0;i<31;i++)
+ if (amOut & (1<<i))
+ {
+ v60.reg[i] = MemRead32(SP);
+ SP += 4;
+ }
+
+ if (amOut & (1<<31))
+ {
+ v60WritePSW((v60ReadPSW() & 0xffff0000) | MemRead16(SP));
+ SP += 4;
+ }
+
+ return amLength1 + 1;
+}
+
+static UINT32 opPUSHM(void)
+{
+ int i;
+
+ modAdd=PC+1;
+ modDim=2;
+
+ // Read the bit register list
+ amLength1=ReadAM();
+
+ if (amOut & (1<<31))
+ {
+ SP -= 4;
+ MemWrite32(SP,v60ReadPSW());
+ }
+
+ for (i=0;i<31;i++)
+ if (amOut & (1<<(30-i)))
+ {
+ SP -= 4;
+ MemWrite32(SP,v60.reg[(30-i)]);
+ }
+
+
+ return amLength1 + 1;
+}
+
+static UINT32 opTESTB(void) /* TRUSTED */
+{
+ modAdd=PC+1;
+ modDim=0;
+
+ // Read the operand
+ amLength1=ReadAM();
+
+ _Z = (amOut == 0);
+ _S = ((amOut & 0x80) != 0);
+ _CY = 0;
+ _OV = 0;
+
+ return amLength1 + 1;
+}
+
+static UINT32 opTESTH(void) /* TRUSTED */
+{
+ modAdd=PC+1;
+ modDim=1;
+
+ // Read the operand
+ amLength1=ReadAM();
+
+ _Z = (amOut == 0);
+ _S = ((amOut & 0x8000) != 0);
+ _CY = 0;
+ _OV = 0;
+
+ return amLength1 + 1;
+}
+
+static UINT32 opTESTW(void) /* TRUSTED */
+{
+ modAdd=PC+1;
+ modDim=2;
+
+ // Read the operand
+ amLength1=ReadAM();
+
+ _Z = (amOut == 0);
+ _S = ((amOut & 0x80000000) != 0);
+ _CY = 0;
+ _OV = 0;
+
+ return amLength1 + 1;
+}
+
+static UINT32 opPUSH(void)
+{
+ modAdd=PC+1;
+ modDim=2;
+
+ amLength1=ReadAM();
+
+ SP-=4;
+ MemWrite32(SP,amOut);
+
+ return amLength1 + 1;
+}
+
+static UINT32 opPOP(void)
+{
+ modAdd=PC+1;
+ modDim=2;
+ modWriteValW=MemRead32(SP);
+ SP+=4;
+ amLength1=WriteAM();
+
+ return amLength1 + 1;
+}
+
+
+static UINT32 opINCB_0(void) { modM=0; return opINCB(); }
+static UINT32 opINCB_1(void) { modM=1; return opINCB(); }
+static UINT32 opINCH_0(void) { modM=0; return opINCH(); }
+static UINT32 opINCH_1(void) { modM=1; return opINCH(); }
+static UINT32 opINCW_0(void) { modM=0; return opINCW(); }
+static UINT32 opINCW_1(void) { modM=1; return opINCW(); }
+
+static UINT32 opDECB_0(void) { modM=0; return opDECB(); }
+static UINT32 opDECB_1(void) { modM=1; return opDECB(); }
+static UINT32 opDECH_0(void) { modM=0; return opDECH(); }
+static UINT32 opDECH_1(void) { modM=1; return opDECH(); }
+static UINT32 opDECW_0(void) { modM=0; return opDECW(); }
+static UINT32 opDECW_1(void) { modM=1; return opDECW(); }
+
+static UINT32 opJMP_0(void) { modM=0; return opJMP(); }
+static UINT32 opJMP_1(void) { modM=1; return opJMP(); }
+
+static UINT32 opJSR_0(void) { modM=0; return opJSR(); }
+static UINT32 opJSR_1(void) { modM=1; return opJSR(); }
+
+static UINT32 opPREPARE_0(void) { modM=0; return opPREPARE(); }
+static UINT32 opPREPARE_1(void) { modM=1; return opPREPARE(); }
+
+static UINT32 opRET_0(void) { modM=0; return opRET(); }
+static UINT32 opRET_1(void) { modM=1; return opRET(); }
+
+static UINT32 opTRAP_0(void) { modM=0; return opTRAP(); }
+static UINT32 opTRAP_1(void) { modM=1; return opTRAP(); }
+
+static UINT32 opRETIU_0(void) { modM=0; return opRETIU(); }
+static UINT32 opRETIU_1(void) { modM=1; return opRETIU(); }
+
+static UINT32 opRETIS_0(void) { modM=0; return opRETIS(); }
+static UINT32 opRETIS_1(void) { modM=1; return opRETIS(); }
+
+static UINT32 opGETPSW_0(void) { modM=0; return opGETPSW(); }
+static UINT32 opGETPSW_1(void) { modM=1; return opGETPSW(); }
+
+static UINT32 opTASI_0(void) { modM=0; return opTASI(); }
+static UINT32 opTASI_1(void) { modM=1; return opTASI(); }
+
+static UINT32 opCLRTLB_0(void) { modM=0; return opCLRTLB(); }
+static UINT32 opCLRTLB_1(void) { modM=1; return opCLRTLB(); }
+
+static UINT32 opPOPM_0(void) { modM=0; return opPOPM(); }
+static UINT32 opPOPM_1(void) { modM=1; return opPOPM(); }
+
+static UINT32 opPUSHM_0(void) { modM=0; return opPUSHM(); }
+static UINT32 opPUSHM_1(void) { modM=1; return opPUSHM(); }
+
+static UINT32 opTESTB_0(void) { modM=0; return opTESTB(); }
+static UINT32 opTESTB_1(void) { modM=1; return opTESTB(); }
+
+static UINT32 opTESTH_0(void) { modM=0; return opTESTH(); }
+static UINT32 opTESTH_1(void) { modM=1; return opTESTH(); }
+
+static UINT32 opTESTW_0(void) { modM=0; return opTESTW(); }
+static UINT32 opTESTW_1(void) { modM=1; return opTESTW(); }
+
+static UINT32 opPUSH_0(void) { modM=0; return opPUSH(); }
+static UINT32 opPUSH_1(void) { modM=1; return opPUSH(); }
+
+static UINT32 opPOP_0(void) { modM=0; return opPOP(); }
+static UINT32 opPOP_1(void) { modM=1; return opPOP(); }
+
+static UINT32 opSTTASK_0(void) { modM=0; return opSTTASK(); }
+static UINT32 opSTTASK_1(void) { modM=1; return opSTTASK(); }
diff --git a/src/emu/cpu/v60/op4.c b/src/emu/cpu/v60/op4.c
new file mode 100644
index 00000000000..0d51493d015
--- /dev/null
+++ b/src/emu/cpu/v60/op4.c
@@ -0,0 +1,354 @@
+
+/*
+ FULLY TRUSTED
+*/
+
+static UINT32 opBGT8(void) /* TRUSTED */
+{
+ NORMALIZEFLAGS();
+
+ if (!((_S ^ _OV) | _Z))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBGT16(void) /* TRUSTED */
+{
+ NORMALIZEFLAGS();
+
+ if (!((_S ^ _OV) | _Z))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+
+static UINT32 opBGE8(void) /* TRUSTED */
+{
+ NORMALIZEFLAGS();
+
+ if (!(_S ^ _OV))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBGE16(void) /* TRUSTED */
+{
+ NORMALIZEFLAGS();
+
+ if (!(_S ^ _OV))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBLT8(void) /* TRUSTED */
+{
+ NORMALIZEFLAGS();
+
+ if ((_S ^ _OV))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBLT16(void) /* TRUSTED */
+{
+ NORMALIZEFLAGS();
+
+ if ((_S ^ _OV))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+
+static UINT32 opBLE8(void) /* TRUSTED */
+{
+ NORMALIZEFLAGS();
+
+ if (((_S ^ _OV) | _Z))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBLE16(void) /* TRUSTED */
+{
+ NORMALIZEFLAGS();
+
+ if (((_S ^ _OV) | _Z))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBH8(void) /* TRUSTED */
+{
+ if (!(_CY | _Z))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBH16(void) /* TRUSTED */
+{
+ if (!(_CY | _Z))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBNH8(void) /* TRUSTED */
+{
+ if ((_CY | _Z))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBNH16(void) /* TRUSTED */
+{
+ if ((_CY | _Z))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBNL8(void) /* TRUSTED */
+{
+ if (!(_CY))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBNL16(void) /* TRUSTED */
+{
+ if (!(_CY))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBL8(void) /* TRUSTED */
+{
+ if ((_CY))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBL16(void) /* TRUSTED */
+{
+ if ((_CY))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBNE8(void) /* TRUSTED */
+{
+ if (!(_Z))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBNE16(void) /* TRUSTED */
+{
+ if (!(_Z))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBE8(void) /* TRUSTED */
+{
+ if ((_Z))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBE16(void) /* TRUSTED */
+{
+ if ((_Z))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBNV8(void) /* TRUSTED */
+{
+ if (!(_OV))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBNV16(void) /* TRUSTED */
+{
+ if (!(_OV))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBV8(void) /* TRUSTED */
+{
+ if ((_OV))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBV16(void) /* TRUSTED */
+{
+ if ((_OV))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBP8(void) /* TRUSTED */
+{
+ if (!(_S))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBP16(void) /* TRUSTED */
+{
+ if (!(_S))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBN8(void) /* TRUSTED */
+{
+ if ((_S))
+ {
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+ }
+
+ return 2;
+}
+
+static UINT32 opBN16(void) /* TRUSTED */
+{
+ if ((_S))
+ {
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+ }
+
+ return 3;
+}
+
+static UINT32 opBR8(void) /* TRUSTED */
+{
+ PC += (INT8)OpRead8(PC + 1);
+ return 0;
+}
+
+static UINT32 opBR16(void) /* TRUSTED */
+{
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+}
+
+static UINT32 opBSR(void) /* TRUSTED */
+{
+ // Save Next PC onto the stack
+ SP -= 4;
+ MemWrite32(SP, PC+3);
+
+ // Jump to subroutine
+ PC += (INT16)OpRead16(PC + 1);
+ return 0;
+}
+
diff --git a/src/emu/cpu/v60/op5.c b/src/emu/cpu/v60/op5.c
new file mode 100644
index 00000000000..eacbf4783f5
--- /dev/null
+++ b/src/emu/cpu/v60/op5.c
@@ -0,0 +1,96 @@
+
+/*
+ * HALT: must add log
+ */
+
+static UINT32 opBRK(void)
+{
+/*
+ UINT32 oldPSW = v60_update_psw_for_exception(0, 0);
+
+ SP -=4;
+ MemWrite32(SP, EXCEPTION_CODE_AND_SIZE(0x0d00, 4));
+ SP -=4;
+ MemWrite32(SP, oldPSW);
+ SP -=4;
+ MemWrite32(SP, PC + 1);
+ PC = GETINTVECT(13);
+ ChangePC(PC);
+*/
+ logerror("Skipping BRK opcode! PC=%x", PC);
+
+ return 1;
+}
+
+static UINT32 opBRKV(void)
+{
+ UINT32 oldPSW = v60_update_psw_for_exception(0, 0);
+
+ SP -=4;
+ MemWrite32(SP, PC);
+ SP -=4;
+ MemWrite32(SP, EXCEPTION_CODE_AND_SIZE(0x1501, 4));
+ SP -=4;
+ MemWrite32(SP, oldPSW);
+ SP -=4;
+ MemWrite32(SP, PC + 1);
+ PC = GETINTVECT(21);
+ ChangePC(PC);
+
+ return 0;
+}
+
+static UINT32 opCLRTLBA(void)
+{
+ // @@@ TLB not yet supported
+ logerror("Skipping CLRTLBA opcode! PC=%x\n", PC);
+ return 1;
+}
+
+static UINT32 opDISPOSE(void)
+{
+ SP = FP;
+ FP = MemRead32(SP);
+ SP +=4;
+
+ return 1;
+}
+
+static UINT32 opHALT(void)
+{
+ // @@@ It should wait for an interrupt to occur
+ //logerror("HALT found: skipping");
+ return 1;
+}
+
+static UINT32 opNOP(void) /* TRUSTED */
+{
+ return 1;
+}
+
+static UINT32 opRSR(void)
+{
+ PC = MemRead32(SP);
+ SP +=4;
+ ChangePC(PC);
+
+ return 0;
+}
+
+static UINT32 opTRAPFL(void)
+{
+ if ((TKCW & 0x1F0) & ((v60ReadPSW() & 0x1F00) >> 4))
+ {
+ // @@@ FPU exception
+ fatalerror("Hit TRAPFL! PC=%x", PC);
+ }
+
+ return 1;
+}
+
+
+
+
+
+
+
diff --git a/src/emu/cpu/v60/op6.c b/src/emu/cpu/v60/op6.c
new file mode 100644
index 00000000000..0e39356d9b7
--- /dev/null
+++ b/src/emu/cpu/v60/op6.c
@@ -0,0 +1,254 @@
+
+/*
+ FULLY TRUSTED
+*/
+
+static UINT32 opTB(int reg) /* TRUSTED */
+{
+ if (v60.reg[reg] == 0)
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBGT(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ NORMALIZEFLAGS();
+ if ((v60.reg[reg] != 0) && !((_S ^ _OV) | _Z))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBLE(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ NORMALIZEFLAGS();
+ if ((v60.reg[reg] != 0) && ((_S ^ _OV) | _Z))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+
+static UINT32 opDBGE(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ NORMALIZEFLAGS();
+ if ((v60.reg[reg] != 0) && !(_S ^ _OV))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBLT(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ NORMALIZEFLAGS();
+ if ((v60.reg[reg] != 0) && (_S ^ _OV))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBH(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && !(_CY | _Z))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBNH(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && (_CY | _Z))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+
+static UINT32 opDBL(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && (_CY))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBNL(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && !(_CY))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBE(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && (_Z))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBNE(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && !(_Z))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBV(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && (_OV))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBNV(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && !(_OV))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBN(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && (_S))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBP(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if ((v60.reg[reg] != 0) && !(_S))
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 opDBR(int reg) /* TRUSTED */
+{
+ v60.reg[reg]--;
+
+ if (v60.reg[reg] != 0)
+ {
+ PC += (INT16)OpRead16(PC + 2);
+ return 0;
+ }
+
+ return 4;
+}
+
+static UINT32 (*const OpC6Table[8])(int reg) = /* TRUSTED */
+{
+ opDBV,
+ opDBL,
+ opDBE,
+ opDBNH,
+ opDBN,
+ opDBR,
+ opDBLT,
+ opDBLE
+};
+
+static UINT32 (*const OpC7Table[8])(int reg) = /* TRUSTED */
+{
+ opDBNV,
+ opDBNL,
+ opDBNE,
+ opDBH,
+ opDBP,
+ opTB,
+ opDBGE,
+ opDBGT
+};
+
+
+static UINT32 opC6(void) /* TRUSTED */
+{
+ UINT8 appb=OpRead8(PC + 1);
+ return OpC6Table[appb>>5](appb&0x1f);
+}
+
+static UINT32 opC7(void) /* TRUSTED */
+{
+ UINT8 appb=OpRead8(PC + 1);
+ return OpC7Table[appb>>5](appb&0x1f);
+}
+
diff --git a/src/emu/cpu/v60/op7a.c b/src/emu/cpu/v60/op7a.c
new file mode 100644
index 00000000000..db7a859b7ce
--- /dev/null
+++ b/src/emu/cpu/v60/op7a.c
@@ -0,0 +1,1230 @@
+
+/*
+ * CMPC: What happens to _S flag if the strings are identical?
+ * I suppose that it will be cleared. And is it set or cleared
+ * when the first one is a substring of the second? I suppose
+ * cleared (since _S should be (src > dst))
+ * MOVC: Why MOVCS does not exist in downward version?
+ * SHCHDB/SHCHDH: R27 is filled with the offset from the start or from the end?
+ *
+ * Strange stuff:
+ * SCHC opcodes does *not* modify _Z flag as stated in V60 manual:
+ * they do the opposite (set if not found, reset if found)
+ */
+
+static UINT32 f7aOp1, f7aOp2;
+static UINT8 f7aFlag1, f7aFlag2;
+static UINT32 f7aLenOp1, f7aLenOp2;
+static UINT8 subOp;
+
+static UINT32 f7bBamOffset1, f7bBamOffset2;
+
+#define f7bOp1 f7aOp1
+#define f7bFlag1 f7aFlag1
+#define f7bOp2 f7aOp2
+#define f7bFlag2 f7aFlag2
+#define f7bLen f7aLenOp1
+
+#define f7cOp1 f7aOp1
+#define f7cOp2 f7aOp2
+#define f7cLen f7aLenOp1
+#define f7cFlag1 f7aFlag1
+#define f7cFlag2 f7aFlag2
+
+#define F7AEND() \
+ return amLength1 + amLength2 + 4;
+
+#define F7BEND() \
+ return amLength1 + amLength2 + 3;
+
+#define F7CEND() \
+ return amLength1 + amLength2 + 3;
+
+#define F7BCREATEBITMASK(x) \
+ x=((1<<(x))-1)
+
+#define F7CCREATEBITMASK(x) \
+ x=((1<<(x))-1)
+
+static void F7aDecodeOperands(UINT32 (*DecodeOp1)(void), UINT8 dim1, UINT32 (*DecodeOp2)(void), UINT8 dim2)
+{
+ UINT8 appb;
+ // Decode first operand
+ modDim=dim1;
+ modM=subOp&0x40;
+ modAdd=PC+2;
+ amLength1=DecodeOp1();
+ f7aFlag1=amFlag;
+ f7aOp1=amOut;
+
+ // Decode length
+ appb=OpRead8(PC+2+amLength1);
+ if (appb&0x80)
+ f7aLenOp1=v60.reg[appb&0x1F];
+ else
+ f7aLenOp1=appb;
+
+ // Decode second operand
+ modDim=dim2;
+ modM=subOp&0x20;
+ modAdd=PC+3+amLength1;
+ amLength2=DecodeOp2();
+ f7aFlag2=amFlag;
+ f7aOp2=amOut;
+
+ // Decode length
+ appb=OpRead8(PC+3+amLength1+amLength2);
+ if (appb&0x80)
+ f7aLenOp2=v60.reg[appb&0x1F];
+ else
+ f7aLenOp2=appb;
+}
+
+static void F7bDecodeFirstOperand(UINT32 (*DecodeOp1)(void), UINT8 dim1)
+{
+ UINT8 appb;
+ // Decode first operand
+ modDim=dim1;
+ modM=subOp&0x40;
+ modAdd=PC+2;
+ amLength1=DecodeOp1();
+ f7bFlag1=amFlag;
+ f7bOp1=amOut;
+
+ // Decode ext
+ appb=OpRead8(PC+2+amLength1);
+ if (appb&0x80)
+ f7bLen=v60.reg[appb&0x1F];
+ else
+ f7bLen=appb;
+}
+
+
+static void F7bWriteSecondOperand(UINT8 dim2)
+{
+ modDim=dim2;
+ modM=subOp&0x20;
+ modAdd=PC+3+amLength1;
+ amLength2=WriteAM();
+}
+
+
+static void F7bDecodeOperands(UINT32 (*DecodeOp1)(void), UINT8 dim1, UINT32 (*DecodeOp2)(void), UINT8 dim2)
+{
+ // Decode first operand
+ F7bDecodeFirstOperand(DecodeOp1,dim1);
+ f7bBamOffset1 = bamOffset;
+
+ // Decode second operand
+ modDim=dim2;
+ modM=subOp&0x20;
+ modAdd=PC+3+amLength1;
+ amLength2=DecodeOp2();
+ f7bFlag2=amFlag;
+ f7bOp2=amOut;
+ f7bBamOffset2 = bamOffset;
+}
+
+static void F7cDecodeOperands(UINT32 (*DecodeOp1)(void), UINT8 dim1, UINT32 (*DecodeOp2)(void), UINT8 dim2)
+{
+ UINT8 appb;
+ // Decode first operand
+ modDim=dim1;
+ modM=subOp&0x40;
+ modAdd=PC+2;
+ amLength1=DecodeOp1();
+ f7cFlag1=amFlag;
+ f7cOp1=amOut;
+
+ // Decode second operand
+ modDim=dim2;
+ modM=subOp&0x20;
+ modAdd=PC+2+amLength1;
+ amLength2=DecodeOp2();
+ f7cFlag2=amFlag;
+ f7cOp2=amOut;
+
+ // Decode ext
+ appb=OpRead8(PC+2+amLength1+amLength2);
+ if (appb&0x80)
+ f7cLen=v60.reg[appb&0x1F];
+ else
+ f7cLen=appb;
+}
+
+#define F7CLOADOP1BYTE(appb) \
+ if (f7cFlag1) \
+ appb = (UINT8)(v60.reg[f7cOp1]&0xFF); \
+ else \
+ appb = MemRead8(f7cOp1);
+
+#define F7CLOADOP2BYTE(appb) \
+ if (f7cFlag2) \
+ appb = (UINT8)(v60.reg[f7cOp2]&0xFF); \
+ else \
+ appb = MemRead8(f7cOp2);
+
+
+#define F7CSTOREOP2BYTE() \
+ if (f7cFlag2) \
+ SETREG8(v60.reg[f7cOp2], appb); \
+ else \
+ MemWrite8(f7cOp2, appb);
+
+#define F7CSTOREOP2HALF() \
+ if (f7cFlag2) \
+ SETREG16(v60.reg[f7cOp2], apph); \
+ else \
+ MemWrite16(f7cOp2, apph);
+
+static UINT32 opCMPSTRB(UINT8 bFill, UINT8 bStop)
+{
+ UINT32 i,dest;
+ UINT8 c1,c2;
+
+ F7aDecodeOperands(ReadAMAddress,0,ReadAMAddress,0);
+
+ // Filling
+ if (bFill)
+ {
+ if (f7aLenOp1 < f7aLenOp2)
+ {
+ for (i=f7aLenOp1;i<f7aLenOp2;i++)
+ MemWrite8(f7aOp1+i,(UINT8)R26);
+ }
+ else if (f7aLenOp2 < f7aLenOp1)
+ {
+ for (i=f7aLenOp2;i<f7aLenOp1;i++)
+ MemWrite8(f7aOp2+i,(UINT8)R26);
+ }
+ }
+
+ dest=(f7aLenOp1 < f7aLenOp2 ? f7aLenOp1 : f7aLenOp2);
+
+ _Z = 0;
+ _S = 0;
+ if (bStop) _CY = 1;
+
+ for (i=0;i<dest;i++)
+ {
+ c1=MemRead8(f7aOp1+i);
+ c2=MemRead8(f7aOp2+i);
+
+ if (c1>c2)
+ {
+ _S=1; break;
+ }
+ else if (c2>c1)
+ {
+ _S=0; break;
+ }
+
+ if (bStop)
+ if (c1==(UINT8)R26 || c2==(UINT8)R26)
+ {
+ _CY=0;
+ break;
+ }
+ }
+
+ R28=f7aLenOp1+i;
+ R27=f7aLenOp2+i;
+
+ if (i==dest)
+ {
+ if (f7aLenOp1 > f7aLenOp2)
+ _S=1;
+ else if (f7aLenOp2 > f7aLenOp1)
+ _S=0;
+ else
+ _Z=1;
+ }
+
+ F7AEND();
+}
+
+static UINT32 opCMPSTRH(UINT8 bFill, UINT8 bStop)
+{
+ UINT32 i,dest;
+ UINT16 c1,c2;
+
+ F7aDecodeOperands(ReadAMAddress,0,ReadAMAddress,0);
+
+ // Filling
+ if (bFill)
+ {
+ if (f7aLenOp1 < f7aLenOp2)
+ {
+ for (i=f7aLenOp1;i<f7aLenOp2;i++)
+ MemWrite16(f7aOp1+i*2,(UINT16)R26);
+ }
+ else if (f7aLenOp2 < f7aLenOp1)
+ {
+ for (i=f7aLenOp2;i<f7aLenOp1;i++)
+ MemWrite16(f7aOp2+i*2,(UINT16)R26);
+ }
+ }
+
+ dest=(f7aLenOp1 < f7aLenOp2 ? f7aLenOp1 : f7aLenOp2);
+
+ _Z = 0;
+ _S = 0;
+ if (bStop) _CY = 1;
+
+ for (i=0;i<dest;i++)
+ {
+ c1=MemRead16(f7aOp1+i*2);
+ c2=MemRead16(f7aOp2+i*2);
+
+ if (c1>c2)
+ {
+ _S=1; break;
+ }
+ else if (c2>c1)
+ {
+ _S=0; break;
+ }
+
+ if (bStop)
+ if (c1==(UINT16)R26 || c2==(UINT16)R26)
+ {
+ _CY=0;
+ break;
+ }
+ }
+
+ R28=f7aLenOp1+i*2;
+ R27=f7aLenOp2+i*2;
+
+ if (i==dest)
+ {
+ if (f7aLenOp1 > f7aLenOp2)
+ _S=1;
+ else if (f7aLenOp2 > f7aLenOp1)
+ _S=0;
+ else
+ _Z=1;
+ }
+
+ F7AEND();
+}
+
+
+
+static UINT32 opMOVSTRUB(UINT8 bFill, UINT8 bStop) /* TRUSTED (0,0) (1,0) */
+{
+ UINT32 i,dest;
+ UINT8 c1;
+
+// if (bStop)
+// {
+// int a=1;
+// }
+
+ F7aDecodeOperands(ReadAMAddress,0,ReadAMAddress,0);
+
+ dest=(f7aLenOp1 < f7aLenOp2 ? f7aLenOp1 : f7aLenOp2);
+
+ for (i=0;i<dest;i++)
+ {
+ MemWrite8(f7aOp2+i,(c1=MemRead8(f7aOp1+i)));
+
+ if (bStop && c1==(UINT8)R26)
+ break;
+ }
+
+ R28=f7aOp1+i;
+ R27=f7aOp2+i;
+
+ if (bFill && f7aLenOp1 < f7aLenOp2)
+ {
+ for (;i<f7aLenOp2;i++)
+ MemWrite8(f7aOp2+i,(UINT8)R26);
+
+ R27=f7aOp2+i;
+ }
+
+
+ F7AEND();
+}
+
+static UINT32 opMOVSTRDB(UINT8 bFill, UINT8 bStop)
+{
+ UINT32 i,dest;
+ UINT8 c1;
+
+ F7aDecodeOperands(ReadAMAddress,0,ReadAMAddress,0);
+
+ dest=(f7aLenOp1 < f7aLenOp2 ? f7aLenOp1 : f7aLenOp2);
+
+ for (i=0;i<dest;i++)
+ {
+ MemWrite8(f7aOp2+(dest-i-1),(c1=MemRead8(f7aOp1+(dest-i-1))));
+
+ if (bStop && c1==(UINT8)R26)
+ break;
+ }
+
+ R28=f7aOp1+(f7aLenOp1-i-1);
+ R27=f7aOp2+(f7aLenOp2-i-1);
+
+ if (bFill && f7aLenOp1 < f7aLenOp2)
+ {
+ for (;i<f7aLenOp2;i++)
+ MemWrite8(f7aOp2+dest+(f7aLenOp2-i-1),(UINT8)R26);
+
+ R27=f7aOp2+(f7aLenOp2-i-1);
+ }
+
+
+ F7AEND();
+}
+
+
+static UINT32 opMOVSTRUH(UINT8 bFill, UINT8 bStop) /* TRUSTED (0,0) (1,0) */
+{
+ UINT32 i,dest;
+ UINT16 c1;
+
+// if (bStop)
+// { int a=1; }
+
+ F7aDecodeOperands(ReadAMAddress,1,ReadAMAddress,1);
+
+ dest=(f7aLenOp1 < f7aLenOp2 ? f7aLenOp1 : f7aLenOp2);
+
+ for (i=0;i<dest;i++)
+ {
+ MemWrite16(f7aOp2+i*2,(c1=MemRead16(f7aOp1+i*2)));
+
+ if (bStop && c1==(UINT16)R26)
+ break;
+ }
+
+ R28=f7aOp1+i*2;
+ R27=f7aOp2+i*2;
+
+ if (bFill && f7aLenOp1 < f7aLenOp2)
+ {
+ for (;i<f7aLenOp2;i++)
+ MemWrite16(f7aOp2+i*2,(UINT16)R26);
+
+ R27=f7aOp2+i*2;
+ }
+
+ F7AEND();
+}
+
+static UINT32 opMOVSTRDH(UINT8 bFill, UINT8 bStop)
+{
+ UINT32 i,dest;
+ UINT16 c1;
+
+// if (bFill | bStop)
+// { int a=1; }
+
+ F7aDecodeOperands(ReadAMAddress,1,ReadAMAddress,1);
+
+// if (f7aLenOp1 != f7aLenOp2)
+// { int a=1; }
+
+ dest=(f7aLenOp1 < f7aLenOp2 ? f7aLenOp1 : f7aLenOp2);
+
+ for (i=0;i<dest;i++)
+ {
+ MemWrite16(f7aOp2+(dest-i-1)*2,(c1=MemRead16(f7aOp1+(dest-i-1)*2)));
+
+ if (bStop && c1==(UINT16)R26)
+ break;
+ }
+
+ R28=f7aOp1+(f7aLenOp1-i-1)*2;
+ R27=f7aOp2+(f7aLenOp2-i-1)*2;
+
+ if (bFill && f7aLenOp1 < f7aLenOp2)
+ {
+ for (;i<f7aLenOp2;i++)
+ MemWrite16(f7aOp2+(f7aLenOp2-i-1)*2,(UINT16)R26);
+
+ R27=f7aOp2+(f7aLenOp2-i-1)*2;
+ }
+
+ F7AEND();
+}
+
+static UINT32 opSEARCHUB(UINT8 bSearch)
+{
+ UINT8 appb;
+ UINT32 i;
+
+ F7bDecodeOperands(ReadAMAddress,0,ReadAM,0);
+
+ for (i=0;i<f7bLen;i++)
+ {
+ appb = (MemRead8(f7bOp1+i)==(UINT8)f7bOp2);
+ if ((bSearch && appb) || (!bSearch && !appb))
+ break;
+ }
+
+ R28=f7bOp1+i;
+ R27=i;
+
+ // This is the opposite as stated in V60 manual...
+ if (i!=f7bLen)
+ _Z=0;
+ else
+ _Z=1;
+
+ F7BEND();
+}
+
+static UINT32 opSEARCHUH(UINT8 bSearch)
+{
+ UINT8 appb;
+ UINT32 i;
+
+ F7bDecodeOperands(ReadAMAddress,1,ReadAM,1);
+
+ for (i=0;i<f7bLen;i++)
+ {
+ appb = (MemRead16(f7bOp1+i*2)==(UINT16)f7bOp2);
+ if ((bSearch && appb) || (!bSearch && !appb))
+ break;
+ }
+
+ R28=f7bOp1+i*2;
+ R27=i;
+
+ if (i!=f7bLen)
+ _Z=0;
+ else
+ _Z=1;
+
+ F7BEND();
+}
+
+static UINT32 opSEARCHDB(UINT8 bSearch)
+{
+ UINT8 appb;
+ INT32 i;
+
+ F7bDecodeOperands(ReadAMAddress,0,ReadAM,0);
+
+ for (i=f7bLen;i>=0;i--)
+ {
+ appb = (MemRead8(f7bOp1+i)==(UINT8)f7bOp2);
+ if ((bSearch && appb) || (!bSearch && !appb))
+ break;
+ }
+
+ R28=f7bOp1+i;
+ R27=i;
+
+ // This is the opposite as stated in V60 manual...
+ if ((UINT32)i!=f7bLen)
+ _Z=0;
+ else
+ _Z=1;
+
+ F7BEND();
+}
+
+static UINT32 opSEARCHDH(UINT8 bSearch)
+{
+ UINT8 appb;
+ INT32 i;
+
+ F7bDecodeOperands(ReadAMAddress,1,ReadAM,1);
+
+ for (i=f7bLen-1;i>=0;i--)
+ {
+ appb = (MemRead16(f7bOp1+i*2)==(UINT16)f7bOp2);
+ if ((bSearch && appb) || (!bSearch && !appb))
+ break;
+ }
+
+ R28=f7bOp1+i*2;
+ R27=i;
+
+ if ((UINT32)i!=f7bLen)
+ _Z=0;
+ else
+ _Z=1;
+
+ F7BEND();
+}
+
+
+static UINT32 opSCHCUB(void) { return opSEARCHUB(1); }
+static UINT32 opSCHCUH(void) { return opSEARCHUH(1); }
+static UINT32 opSCHCDB(void) { return opSEARCHDB(1); }
+static UINT32 opSCHCDH(void) { return opSEARCHDH(1); }
+static UINT32 opSKPCUB(void) { return opSEARCHUB(0); }
+static UINT32 opSKPCUH(void) { return opSEARCHUH(0); }
+static UINT32 opSKPCDB(void) { return opSEARCHDB(0); }
+static UINT32 opSKPCDH(void) { return opSEARCHDH(0); }
+
+static UINT32 opCMPCB(void) { return opCMPSTRB(0,0); }
+static UINT32 opCMPCH(void) { return opCMPSTRH(0,0); }
+static UINT32 opCMPCFB(void) { return opCMPSTRB(1,0); }
+static UINT32 opCMPCFH(void) { return opCMPSTRH(1,0); }
+static UINT32 opCMPCSB(void) { return opCMPSTRB(0,1); }
+static UINT32 opCMPCSH(void) { return opCMPSTRH(0,1); }
+
+static UINT32 opMOVCUB(void) { return opMOVSTRUB(0,0); }
+static UINT32 opMOVCUH(void) { return opMOVSTRUH(0,0); }
+static UINT32 opMOVCFUB(void) { return opMOVSTRUB(1,0); }
+static UINT32 opMOVCFUH(void) { return opMOVSTRUH(1,0); }
+static UINT32 opMOVCSUB(void) { return opMOVSTRUB(0,1); }
+static UINT32 opMOVCSUH(void) { return opMOVSTRUH(0,1); }
+
+static UINT32 opMOVCDB(void) { return opMOVSTRDB(0,0); }
+static UINT32 opMOVCDH(void) { return opMOVSTRDH(0,0); }
+static UINT32 opMOVCFDB(void) { return opMOVSTRDB(1,0); }
+static UINT32 opMOVCFDH(void) { return opMOVSTRDH(1,0); }
+
+static UINT32 opEXTBFZ(void) /* TRUSTED */
+{
+ F7bDecodeFirstOperand(BitReadAM, 11);
+
+ F7BCREATEBITMASK(f7bLen);
+
+ modWriteValW=(f7bOp1 >> bamOffset) & f7bLen;
+
+ F7bWriteSecondOperand(2);
+
+ F7BEND();
+}
+
+static UINT32 opEXTBFS(void) /* TRUSTED */
+{
+ F7bDecodeFirstOperand(BitReadAM, 11);
+
+ F7BCREATEBITMASK(f7bLen);
+
+ modWriteValW=(f7bOp1 >> bamOffset) & f7bLen;
+ if (modWriteValW & ((f7bLen+1)>>1))
+ modWriteValW |= ~f7bLen;
+
+ F7bWriteSecondOperand(2);
+
+ F7BEND();
+}
+
+static UINT32 opEXTBFL(void)
+{
+ UINT32 appw;
+
+ F7bDecodeFirstOperand(BitReadAM, 11);
+
+ appw=f7bLen;
+ F7BCREATEBITMASK(f7bLen);
+
+ modWriteValW=(f7bOp1 >> bamOffset) & f7bLen;
+ modWriteValW<<=32-appw;
+
+ F7bWriteSecondOperand(2);
+
+ F7BEND();
+}
+
+static UINT32 opSCHBS(UINT32 bSearch1)
+{
+ UINT32 i,data;
+ UINT32 offset;
+
+ F7bDecodeFirstOperand(BitReadAMAddress,10);
+
+ // Read first UINT8
+ f7bOp1 += bamOffset/8;
+ data = MemRead8(f7bOp1);
+ offset = bamOffset&7;
+
+ // Scan bitstring
+ for (i=0;i<f7bLen;i++)
+ {
+ // Update the work register
+ R28 = f7bOp1;
+
+ // There is a 0/1 at current offset?
+ if ((bSearch1 && (data&(1<<offset))) ||
+ (!bSearch1 && !(data&(1<<offset))))
+ break;
+
+ // Next bit please
+ offset++;
+ if (offset==8)
+ {
+ // Next UINT8 please
+ offset=0;
+ f7bOp1++;
+ data = MemRead8(f7bOp1);
+ }
+ }
+
+ // Set zero if bit not found
+ _Z = (i == f7bLen);
+
+ // Write to destination the final offset
+ modWriteValW = i;
+ F7bWriteSecondOperand(2);
+
+ F7BEND();
+}
+
+static UINT32 opSCH0BSU(void) { return opSCHBS(0); }
+static UINT32 opSCH1BSU(void) { return opSCHBS(1); }
+
+static UINT32 opINSBFR(void)
+{
+ UINT32 appw;
+ F7cDecodeOperands(ReadAM,2,BitReadAMAddress,11);
+
+ F7CCREATEBITMASK(f7cLen);
+
+ f7cOp2 += bamOffset/8;
+ appw = MemRead32(f7cOp2);
+ bamOffset &= 7;
+
+ appw &= ~(f7cLen << bamOffset);
+ appw |= (f7cLen & f7cOp1) << bamOffset;
+
+ MemWrite32(f7cOp2, appw);
+
+ F7CEND();
+}
+
+static UINT32 opINSBFL(void)
+{
+ UINT32 appw;
+ F7cDecodeOperands(ReadAM,2,BitReadAMAddress,11);
+
+ f7cOp1 >>= (32-f7cLen);
+
+ F7CCREATEBITMASK(f7cLen);
+
+ f7cOp2 += bamOffset/8;
+ appw = MemRead32(f7cOp2);
+ bamOffset &= 7;
+
+ appw &= ~(f7cLen << bamOffset);
+ appw |= (f7cLen & f7cOp1) << bamOffset;
+
+ MemWrite32(f7cOp2, appw);
+
+ F7CEND();
+}
+
+static UINT32 opMOVBSD(void)
+{
+ UINT32 i;
+ UINT8 srcdata, dstdata;
+
+ F7bDecodeOperands(BitReadAMAddress,10,BitReadAMAddress,10);
+
+// if (f7bLen!=1)
+// { int a=1; }
+
+ f7bBamOffset1 += f7bLen-1;
+ f7bBamOffset2 += f7bLen-1;
+
+ f7bOp1 += f7bBamOffset1/8;
+ f7bOp2 += f7bBamOffset2/8;
+
+ f7bBamOffset1 &= 7;
+ f7bBamOffset2 &= 7;
+
+ srcdata = MemRead8(f7bOp1);
+ dstdata = MemRead8(f7bOp2);
+
+ for (i=0;i<f7bLen;i++)
+ {
+ // Update work registers
+ R28 = f7bOp1;
+ R27 = f7bOp2;
+
+ dstdata &= ~(1 << f7bBamOffset2);
+ dstdata |= ((srcdata >> f7bBamOffset1) & 1) << f7bBamOffset2;
+
+ if (f7bBamOffset1 == 0)
+ {
+ f7bBamOffset1 = 8;
+ f7bOp1--;
+ srcdata = MemRead8(f7bOp1);
+ }
+ if (f7bBamOffset2 == 0)
+ {
+ MemWrite8(f7bOp2, dstdata);
+ f7bBamOffset2 = 8;
+ f7bOp2--;
+ dstdata = MemRead8(f7bOp2);
+ }
+
+ f7bBamOffset1--;
+ f7bBamOffset2--;
+ }
+
+ // Flush of the final data
+ if (f7bBamOffset2 != 7)
+ MemWrite8(f7bOp2, dstdata);
+
+ F7BEND();
+}
+
+static UINT32 opMOVBSU(void)
+{
+ UINT32 i;
+ UINT8 srcdata, dstdata;
+
+ F7bDecodeOperands(BitReadAMAddress,10,BitReadAMAddress,10);
+
+ f7bOp1 += f7bBamOffset1/8;
+ f7bOp2 += f7bBamOffset2/8;
+
+ f7bBamOffset1 &= 7;
+ f7bBamOffset2 &= 7;
+
+ srcdata = MemRead8(f7bOp1);
+ dstdata = MemRead8(f7bOp2);
+
+ for (i=0;i<f7bLen;i++)
+ {
+ // Update work registers
+ R28 = f7bOp1;
+ R27 = f7bOp2;
+
+ dstdata &= ~(1 << f7bBamOffset2);
+ dstdata |= ((srcdata >> f7bBamOffset1) & 1) << f7bBamOffset2;
+
+ f7bBamOffset1++;
+ f7bBamOffset2++;
+ if (f7bBamOffset1 == 8)
+ {
+ f7bBamOffset1 = 0;
+ f7bOp1++;
+ srcdata = MemRead8(f7bOp1);
+ }
+ if (f7bBamOffset2 == 8)
+ {
+ MemWrite8(f7bOp2, dstdata);
+ f7bBamOffset2 = 0;
+ f7bOp2++;
+ dstdata = MemRead8(f7bOp2);
+ }
+ }
+
+ // Flush of the final data
+ if (f7bBamOffset2 != 0)
+ MemWrite8(f7bOp2, dstdata);
+
+ F7BEND();
+}
+
+// RADM 0x20f4b8 holds the time left
+
+static UINT32 opADDDC(void)
+{
+ UINT8 appb;
+ UINT8 src, dst;
+
+ F7cDecodeOperands(ReadAM, 0, ReadAMAddress, 0);
+
+ if (f7cLen != 0)
+ {
+ logerror("ADDDC %x (pat: %x)\n", f7cOp1, f7cLen);
+ }
+
+ F7CLOADOP2BYTE(appb);
+
+ src = (UINT8)(f7cOp1 >> 4) * 10 + (UINT8)(f7cOp1 & 0xF);
+ dst = (appb >> 4) * 10 + (appb & 0xF);
+
+ appb = src + dst + (_CY?1:0);
+
+ if (appb >= 100)
+ {
+ appb -= 100;
+ _CY = 1;
+ }
+ else
+ _CY = 0;
+
+ // compute z flag:
+ // cleared if result non-zero or carry generated
+ // unchanged otherwise
+ if (appb != 0 || _CY)
+ _Z = 0;
+
+ appb = ((appb/10)<<4) | (appb % 10);
+
+ F7CSTOREOP2BYTE();
+ F7CEND();
+}
+
+static UINT32 opSUBDC(void)
+{
+ INT8 appb;
+ UINT32 src, dst;
+
+ F7cDecodeOperands(ReadAM, 0, ReadAMAddress, 0);
+
+ if (f7cLen != 0)
+ {
+ logerror("SUBDC %x (pat: %x)\n", f7cOp1, f7cLen);
+ }
+
+ F7CLOADOP2BYTE(appb);
+
+ src = (UINT32)(f7cOp1 >> 4) * 10 + (UINT32)(f7cOp1 & 0xF);
+ dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF);
+
+ // Note that this APPB must be SIGNED!
+ appb = (INT32)dst - (INT32)src - (_CY?1:0);
+
+ if (appb < 0)
+ {
+ appb += 100;
+ _CY = 1;
+ }
+ else
+ _CY = 0;
+
+ // compute z flag:
+ // cleared if result non-zero or carry generated
+ // unchanged otherwise
+ if (appb != 0 || _CY)
+ _Z = 0;
+
+ appb = ((appb/10)<<4) | (appb % 10);
+
+ F7CSTOREOP2BYTE();
+ F7CEND();
+}
+
+static UINT32 opSUBRDC(void)
+{
+ INT8 appb;
+ UINT32 src, dst;
+
+ F7cDecodeOperands(ReadAM, 0, ReadAMAddress, 0);
+
+ if (f7cLen != 0)
+ {
+ logerror("SUBRDC %x (pat: %x)\n", f7cOp1, f7cLen);
+ }
+
+ F7CLOADOP2BYTE(appb);
+
+ src = (UINT32)(f7cOp1 >> 4) * 10 + (UINT32)(f7cOp1 & 0xF);
+ dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF);
+
+ // Note that this APPB must be SIGNED!
+ appb = (INT32)src - (INT32)dst - (_CY?1:0);
+
+ if (appb < 0)
+ {
+ appb += 100;
+ _CY = 1;
+ }
+ else
+ _CY = 0;
+
+ // compute z flag:
+ // cleared if result non-zero or carry generated
+ // unchanged otherwise
+ if (appb != 0 || _CY)
+ _Z = 0;
+
+ appb = ((appb/10)<<4) | (appb % 10);
+
+ F7CSTOREOP2BYTE();
+ F7CEND();
+}
+
+static UINT32 opCVTDPZ(void)
+{
+ UINT16 apph;
+
+ F7cDecodeOperands(ReadAM, 0, ReadAMAddress, 1);
+
+ apph = (UINT16)(((f7cOp1 >> 4) & 0xF) | ((f7cOp1 & 0xF) << 8));
+ apph |= (f7cLen);
+ apph |= (f7cLen<<8);
+
+ // Z flag is unchanged if src is zero, cleared otherwise
+ if (f7cOp1 != 0) _Z = 0;
+
+ F7CSTOREOP2HALF();
+ F7CEND();
+}
+
+static UINT32 opCVTDZP(void)
+{
+ UINT8 appb;
+ F7cDecodeOperands(ReadAM, 1, ReadAMAddress, 0);
+
+ if ((f7cOp1 & 0xF0) != (f7cLen & 0xF0) || ((f7cOp1 >> 8) & 0xF0) != (f7cLen & 0xF0))
+ {
+ // Decimal exception
+ logerror("CVTD.ZP Decimal exception #1!\n");
+ }
+
+ if ((f7cOp1 & 0xF) > 9 || ((f7cOp1 >> 8) & 0xF) > 9)
+ {
+ // Decimal exception
+ logerror("CVTD.ZP Decimal exception #2!\n");
+ }
+
+ appb = (UINT8)(((f7cOp1 >> 8) & 0xF) | ((f7cOp1 & 0xF) << 4));
+ if (appb != 0) _Z = 0;
+
+ F7CSTOREOP2BYTE();
+ F7CEND();
+}
+
+static UINT32 op58UNHANDLED(void)
+{
+ fatalerror("Unhandled 58 opcode at PC: /%06x", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 op5AUNHANDLED(void)
+{
+ fatalerror("Unhandled 5A opcode at PC: /%06x", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 op5BUNHANDLED(void)
+{
+ fatalerror("Unhandled 5B opcode at PC: /%06x", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 op5DUNHANDLED(void)
+{
+ fatalerror("Unhandled 5D opcode at PC: /%06x", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 op59UNHANDLED(void)
+{
+ fatalerror("Unhandled 59 opcode at PC: /%06x", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+static UINT32 (*const Op59Table[32])(void) =
+{
+ opADDDC,
+ opSUBDC,
+ opSUBRDC,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ opCVTDPZ,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ opCVTDZP,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED,
+ op59UNHANDLED
+};
+
+
+static UINT32 (*const Op5BTable[32])(void) =
+{
+ opSCH0BSU,
+ op5BUNHANDLED,
+ opSCH1BSU,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ opMOVBSU,
+ opMOVBSD,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED,
+ op5BUNHANDLED
+};
+
+
+static UINT32 (*const Op5DTable[32])(void) =
+{
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ opEXTBFS,
+ opEXTBFZ,
+ opEXTBFL,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ opINSBFR,
+ opINSBFL,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED,
+ op5DUNHANDLED
+};
+
+static UINT32 (*const Op58Table[32])(void) =
+{
+ opCMPCB,
+ opCMPCFB,
+ opCMPCSB,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ opMOVCUB,
+ opMOVCDB,
+ opMOVCFUB,
+ opMOVCFDB,
+ opMOVCSUB,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ opSCHCUB,
+ opSCHCDB,
+ opSKPCUB,
+ opSKPCDB,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED,
+ op58UNHANDLED
+};
+
+static UINT32 (*const Op5ATable[32])(void) =
+{
+ opCMPCH,
+ opCMPCFH,
+ opCMPCSH,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ opMOVCUH,
+ opMOVCDH,
+ opMOVCFUH,
+ opMOVCFDH,
+ opMOVCSUH,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ opSCHCUH,
+ opSCHCDH,
+ opSKPCUH,
+ opSKPCDH,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED,
+ op5AUNHANDLED
+};
+
+static UINT32 op58(void)
+{
+ subOp = OpRead8(PC + 1);
+
+ return Op58Table[subOp&0x1F]();
+}
+
+static UINT32 op5A(void)
+{
+ subOp = OpRead8(PC + 1);
+
+ return Op5ATable[subOp&0x1F]();
+}
+
+static UINT32 op5B(void)
+{
+ subOp = OpRead8(PC + 1);
+
+ return Op5BTable[subOp&0x1F]();
+}
+
+static UINT32 op5D(void)
+{
+ subOp = OpRead8(PC + 1);
+
+ return Op5DTable[subOp&0x1F]();
+}
+
+static UINT32 op59(void)
+{
+ subOp = OpRead8(PC + 1);
+
+ return Op59Table[subOp&0x1F]();
+}
diff --git a/src/emu/cpu/v60/optable.c b/src/emu/cpu/v60/optable.c
new file mode 100644
index 00000000000..96e9aed416e
--- /dev/null
+++ b/src/emu/cpu/v60/optable.c
@@ -0,0 +1,259 @@
+static UINT32 (*const OpCodeTable[256])(void) =
+{
+ /* 0x00 */ opHALT,
+ /* 0x01 */ opLDTASK,
+ /* 0x02 */ opSTPR,
+ /* 0x03 */ opUNHANDLED,
+ /* 0x04 */ opUNHANDLED,
+ /* 0x05 */ opUNHANDLED,
+ /* 0x06 */ opUNHANDLED,
+ /* 0x07 */ opUNHANDLED,
+ /* 0x08 */ opRVBIT,
+ /* 0x09 */ opMOVB,
+ /* 0x0a */ opMOVSBH,
+ /* 0x0b */ opMOVZBH,
+ /* 0x0c */ opMOVSBW,
+ /* 0x0d */ opMOVZBW,
+ /* 0x0e */ opUNHANDLED,
+ /* 0x0f */ opUNHANDLED,
+ /* 0x10 */ opCLRTLBA,
+ /* 0x11 */ opUNHANDLED,
+ /* 0x12 */ opLDPR,
+ /* 0x13 */ opUPDPSWW,
+ /* 0x14 */ opUNHANDLED,
+ /* 0x15 */ opUNHANDLED,
+ /* 0x16 */ opUNHANDLED,
+ /* 0x17 */ opUNHANDLED,
+ /* 0x18 */ opUNHANDLED,
+ /* 0x19 */ opMOVTHB,
+ /* 0x1a */ opUNHANDLED,
+ /* 0x1b */ opMOVH,
+ /* 0x1c */ opMOVSHW,
+ /* 0x1d */ opMOVZHW,
+ /* 0x1e */ opUNHANDLED,
+ /* 0x1f */ opUNHANDLED,
+ /* 0x20 */ opINB,
+ /* 0x21 */ opOUTB,
+ /* 0x22 */ opINH,
+ /* 0x23 */ opOUTH,
+ /* 0x24 */ opINW,
+ /* 0x25 */ opOUTW,
+ /* 0x26 */ opUNHANDLED,
+ /* 0x27 */ opUNHANDLED,
+ /* 0x28 */ opUNHANDLED,
+ /* 0x29 */ opMOVTWB,
+ /* 0x2a */ opUNHANDLED,
+ /* 0x2b */ opMOVTWH,
+ /* 0x2c */ opRVBYT,
+ /* 0x2d */ opMOVW,
+ /* 0x2e */ opUNHANDLED,
+ /* 0x2f */ opUNHANDLED,
+ /* 0x30 */ opUNHANDLED,
+ /* 0x31 */ opUNHANDLED,
+ /* 0x32 */ opUNHANDLED,
+ /* 0x33 */ opUNHANDLED,
+ /* 0x34 */ opUNHANDLED,
+ /* 0x35 */ opUNHANDLED,
+ /* 0x36 */ opUNHANDLED,
+ /* 0x37 */ opUNHANDLED,
+ /* 0x38 */ opNOTB,
+ /* 0x39 */ opNEGB,
+ /* 0x3a */ opNOTH,
+ /* 0x3b */ opNEGH,
+ /* 0x3c */ opNOTW,
+ /* 0x3d */ opNEGW,
+ /* 0x3e */ opUNHANDLED,
+ /* 0x3f */ opMOVD,
+ /* 0x40 */ opMOVEAB,
+ /* 0x41 */ opXCHB,
+ /* 0x42 */ opMOVEAH,
+ /* 0x43 */ opXCHH,
+ /* 0x44 */ opMOVEAW,
+ /* 0x45 */ opXCHW,
+ /* 0x46 */ opUNHANDLED,
+ /* 0x47 */ opSETF,
+ /* 0x48 */ opBSR,
+ /* 0x49 */ opCALL,
+ /* 0x4a */ opUPDPSWH,
+ /* 0x4b */ opCHLVL,
+ /* 0x4c */ opUNHANDLED,
+ /* 0x4d */ opCHKAR,
+ /* 0x4e */ opCHKAW,
+ /* 0x4f */ opCHKAE,
+ /* 0x50 */ opREMB,
+ /* 0x51 */ opREMUB,
+ /* 0x52 */ opREMH,
+ /* 0x53 */ opREMUH,
+ /* 0x54 */ opREMW,
+ /* 0x55 */ opREMUW,
+ /* 0x56 */ opUNHANDLED,
+ /* 0x57 */ opUNHANDLED,
+ /* 0x58 */ op58,
+ /* 0x59 */ op59,
+ /* 0x5a */ op5A,
+ /* 0x5b */ op5B,
+ /* 0x5c */ op5C,
+ /* 0x5d */ op5D,
+ /* 0x5e */ opUNHANDLED,
+ /* 0x5f */ op5F,
+ /* 0x60 */ opBV8,
+ /* 0x61 */ opBNV8,
+ /* 0x62 */ opBL8,
+ /* 0x63 */ opBNL8,
+ /* 0x64 */ opBE8,
+ /* 0x65 */ opBNE8,
+ /* 0x66 */ opBNH8,
+ /* 0x67 */ opBH8,
+ /* 0x68 */ opBN8,
+ /* 0x69 */ opBP8,
+ /* 0x6a */ opBR8,
+ /* 0x6b */ opUNHANDLED,
+ /* 0x6C */ opBLT8,
+ /* 0x6c */ opBGE8,
+ /* 0x6e */ opBLE8,
+ /* 0x6f */ opBGT8,
+ /* 0x70 */ opBV16,
+ /* 0x71 */ opBNV16,
+ /* 0x72 */ opBL16,
+ /* 0x73 */ opBNL16,
+ /* 0x74 */ opBE16,
+ /* 0x75 */ opBNE16,
+ /* 0x76 */ opBNH16,
+ /* 0x77 */ opBH16,
+ /* 0x78 */ opBN16,
+ /* 0x79 */ opBP16,
+ /* 0x7a */ opBR16,
+ /* 0x7b */ opUNHANDLED,
+ /* 0x7c */ opBLT16,
+ /* 0x7d */ opBGE16,
+ /* 0x7e */ opBLE16,
+ /* 0x7f */ opBGT16,
+ /* 0x80 */ opADDB,
+ /* 0x81 */ opMULB,
+ /* 0x82 */ opADDH,
+ /* 0x83 */ opMULH,
+ /* 0x84 */ opADDW,
+ /* 0x85 */ opMULW,
+ /* 0x86 */ opMULX,
+ /* 0x87 */ opTEST1,
+ /* 0x88 */ opORB,
+ /* 0x89 */ opROTB,
+ /* 0x8a */ opORH,
+ /* 0x8b */ opROTH,
+ /* 0x8c */ opORW,
+ /* 0x8d */ opROTW,
+ /* 0x8e */ opUNHANDLED,
+ /* 0x8f */ opUNHANDLED,
+ /* 0x90 */ opADDCB,
+ /* 0x91 */ opMULUB,
+ /* 0x92 */ opADDCH,
+ /* 0x93 */ opMULUH,
+ /* 0x94 */ opADDCW,
+ /* 0x95 */ opMULUW,
+ /* 0x96 */ opMULUX,
+ /* 0x97 */ opSET1,
+ /* 0x98 */ opSUBCB,
+ /* 0x99 */ opROTCB,
+ /* 0x9a */ opSUBCH,
+ /* 0x9b */ opROTCH,
+ /* 0x9c */ opSUBCW,
+ /* 0x9d */ opROTCW,
+ /* 0x9e */ opUNHANDLED,
+ /* 0x9f */ opUNHANDLED,
+ /* 0xa0 */ opANDB,
+ /* 0xa1 */ opDIVB,
+ /* 0xa2 */ opANDH,
+ /* 0xa3 */ opDIVH,
+ /* 0xa4 */ opANDW,
+ /* 0xa5 */ opDIVW,
+ /* 0xa6 */ opDIVX,
+ /* 0xa7 */ opCLR1,
+ /* 0xa8 */ opSUBB,
+ /* 0xa9 */ opSHLB,
+ /* 0xaa */ opSUBH,
+ /* 0xab */ opSHLH,
+ /* 0xac */ opSUBW,
+ /* 0xad */ opSHLW,
+ /* 0xae */ opUNHANDLED,
+ /* 0xaf */ opUNHANDLED,
+ /* 0xb0 */ opXORB,
+ /* 0xb1 */ opDIVUB,
+ /* 0xb2 */ opXORH,
+ /* 0xb3 */ opDIVUH,
+ /* 0xb4 */ opXORW,
+ /* 0xb5 */ opDIVUW,
+ /* 0xb6 */ opDIVUX,
+ /* 0xb7 */ opNOT1,
+ /* 0xb8 */ opCMPB,
+ /* 0xb9 */ opSHAB,
+ /* 0xba */ opCMPH,
+ /* 0xbb */ opSHAH,
+ /* 0xbc */ opCMPW,
+ /* 0xbd */ opSHAW,
+ /* 0xbe */ opUNHANDLED,
+ /* 0xbf */ opUNHANDLED,
+ /* 0xc0 */ opUNHANDLED,
+ /* 0xc1 */ opUNHANDLED,
+ /* 0xc2 */ opUNHANDLED,
+ /* 0xc3 */ opUNHANDLED,
+ /* 0xc4 */ opUNHANDLED,
+ /* 0xc5 */ opUNHANDLED,
+ /* 0xc6 */ opC6,
+ /* 0xc7 */ opC7,
+ /* 0xc8 */ opBRK,
+ /* 0xc9 */ opBRKV,
+ /* 0xca */ opRSR,
+ /* 0xcb */ opTRAPFL,
+ /* 0xcc */ opDISPOSE,
+ /* 0xcd */ opNOP,
+ /* 0xce */ opUNHANDLED,
+ /* 0xcf */ opUNHANDLED,
+ /* 0xd0 */ opDECB_0,
+ /* 0xd1 */ opDECB_1,
+ /* 0xd2 */ opDECH_0,
+ /* 0xd3 */ opDECH_1,
+ /* 0xd4 */ opDECW_0,
+ /* 0xd5 */ opDECW_1,
+ /* 0xd6 */ opJMP_0,
+ /* 0xd7 */ opJMP_1,
+ /* 0xd8 */ opINCB_0,
+ /* 0xd9 */ opINCB_1,
+ /* 0xda */ opINCH_0,
+ /* 0xdb */ opINCH_1,
+ /* 0xdc */ opINCW_0,
+ /* 0xdd */ opINCW_1,
+ /* 0xde */ opPREPARE_0,
+ /* 0xdf */ opPREPARE_1,
+ /* 0xe0 */ opTASI_0,
+ /* 0xe1 */ opTASI_1,
+ /* 0xe2 */ opRET_0,
+ /* 0xe3 */ opRET_1,
+ /* 0xe4 */ opPOPM_0,
+ /* 0xe5 */ opPOPM_1,
+ /* 0xe6 */ opPOP_0,
+ /* 0xe7 */ opPOP_1,
+ /* 0xe8 */ opJSR_0,
+ /* 0xe9 */ opJSR_1,
+ /* 0xea */ opRETIU_0,
+ /* 0xeb */ opRETIU_1,
+ /* 0xec */ opPUSHM_0,
+ /* 0xed */ opPUSHM_1,
+ /* 0xee */ opPUSH_0,
+ /* 0xef */ opPUSH_1,
+ /* 0xf0 */ opTESTB_0,
+ /* 0xf1 */ opTESTB_1,
+ /* 0xf2 */ opTESTH_0,
+ /* 0xf3 */ opTESTH_1,
+ /* 0xf4 */ opTESTW_0,
+ /* 0xf5 */ opTESTW_1,
+ /* 0xf6 */ opGETPSW_0,
+ /* 0xf7 */ opGETPSW_1,
+ /* 0xf8 */ opTRAP_0,
+ /* 0xf9 */ opTRAP_1,
+ /* 0xfa */ opRETIS_0,
+ /* 0xfb */ opRETIS_1,
+ /* 0xfc */ opSTTASK_0,
+ /* 0xfd */ opSTTASK_1,
+ /* 0xfe */ opCLRTLB_0,
+ /* 0xff */ opCLRTLB_1,
+};
diff --git a/src/emu/cpu/v60/v60.c b/src/emu/cpu/v60/v60.c
new file mode 100644
index 00000000000..c405054e287
--- /dev/null
+++ b/src/emu/cpu/v60/v60.c
@@ -0,0 +1,743 @@
+// V60.C
+// Undiscover the beast!
+// Main hacking and coding by Farfetch'd
+// Portability fixes by Richter Belmont
+
+#include "debugger.h"
+#include "v60.h"
+
+// memory accessors
+#include "v60mem.c"
+
+
+// macros stolen from MAME for flags calc
+// note that these types are in x86 naming:
+// byte = 8 bit, word = 16 bit, long = 32 bit
+
+// parameter x = result, y = source 1, z = source 2
+
+#define SetOFL_Add(x,y,z) (_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x80000000) ? 1: 0)
+#define SetOFW_Add(x,y,z) (_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x8000) ? 1 : 0)
+#define SetOFB_Add(x,y,z) (_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x80) ? 1 : 0)
+
+#define SetOFL_Sub(x,y,z) (_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x80000000) ? 1 : 0)
+#define SetOFW_Sub(x,y,z) (_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x8000) ? 1 : 0)
+#define SetOFB_Sub(x,y,z) (_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x80) ? 1 : 0)
+
+#define SetCFB(x) {_CY = ((x) & 0x100) ? 1 : 0; }
+#define SetCFW(x) {_CY = ((x) & 0x10000) ? 1 : 0; }
+#define SetCFL(x) {_CY = ((x) & (((UINT64)1) << 32)) ? 1 : 0; }
+
+#define SetSF(x) (_S = (x))
+#define SetZF(x) (_Z = (x))
+
+#define SetSZPF_Byte(x) {_Z = ((UINT8)(x)==0); _S = ((x)&0x80) ? 1 : 0; }
+#define SetSZPF_Word(x) {_Z = ((UINT16)(x)==0); _S = ((x)&0x8000) ? 1 : 0; }
+#define SetSZPF_Long(x) {_Z = ((UINT32)(x)==0); _S = ((x)&0x80000000) ? 1 : 0; }
+
+#define ORB(dst,src) { (dst) |= (src); _CY = _OV = 0; SetSZPF_Byte(dst); }
+#define ORW(dst,src) { (dst) |= (src); _CY = _OV = 0; SetSZPF_Word(dst); }
+#define ORL(dst,src) { (dst) |= (src); _CY = _OV = 0; SetSZPF_Long(dst); }
+
+#define ANDB(dst,src) { (dst) &= (src); _CY = _OV = 0; SetSZPF_Byte(dst); }
+#define ANDW(dst,src) { (dst) &= (src); _CY = _OV = 0; SetSZPF_Word(dst); }
+#define ANDL(dst,src) { (dst) &= (src); _CY = _OV = 0; SetSZPF_Long(dst); }
+
+#define XORB(dst,src) { (dst) ^= (src); _CY = _OV = 0; SetSZPF_Byte(dst); }
+#define XORW(dst,src) { (dst) ^= (src); _CY = _OV = 0; SetSZPF_Word(dst); }
+#define XORL(dst,src) { (dst) ^= (src); _CY = _OV = 0; SetSZPF_Long(dst); }
+
+#define SUBB(dst, src) { unsigned res=(dst)-(src); SetCFB(res); SetOFB_Sub(res,src,dst); SetSZPF_Byte(res); dst=(UINT8)res; }
+#define SUBW(dst, src) { unsigned res=(dst)-(src); SetCFW(res); SetOFW_Sub(res,src,dst); SetSZPF_Word(res); dst=(UINT16)res; }
+#define SUBL(dst, src) { UINT64 res=(UINT64)(dst)-(INT64)(src); SetCFL(res); SetOFL_Sub(res,src,dst); SetSZPF_Long(res); dst=(UINT32)res; }
+
+#define ADDB(dst, src) { unsigned res=(dst)+(src); SetCFB(res); SetOFB_Add(res,src,dst); SetSZPF_Byte(res); dst=(UINT8)res; }
+#define ADDW(dst, src) { unsigned res=(dst)+(src); SetCFW(res); SetOFW_Add(res,src,dst); SetSZPF_Word(res); dst=(UINT16)res; }
+#define ADDL(dst, src) { UINT64 res=(UINT64)(dst)+(UINT64)(src); SetCFL(res); SetOFL_Add(res,src,dst); SetSZPF_Long(res); dst=(UINT32)res; }
+
+#define SETREG8(a, b) (a) = ((a) & ~0xff) | ((b) & 0xff)
+#define SETREG16(a, b) (a) = ((a) & ~0xffff) | ((b) & 0xffff)
+
+typedef struct
+{
+ UINT8 CY;
+ UINT8 OV;
+ UINT8 S;
+ UINT8 Z;
+} Flags;
+
+// v60 Register Inside (Hm... It's not a pentium inside :-))) )
+static struct v60info {
+ struct cpu_info info;
+ UINT32 reg[68];
+ Flags flags;
+ UINT8 irq_line;
+ UINT8 nmi_line;
+ int (*irq_cb)(int irqline);
+ UINT32 PPC;
+} v60;
+
+static int v60_ICount;
+static int v60_stall_io;
+
+/*
+ * Prevent warnings on NetBSD. All identifiers beginning with an underscore
+ * followed by an uppercase letter are reserved by the C standard (ISO/IEC
+ * 9899:1999, 7.1.3) to be used by the implementation. It'd be best to rename
+ * all such instances, but this is less intrusive and error-prone.
+ */
+#undef _S
+
+#define _CY v60.flags.CY
+#define _OV v60.flags.OV
+#define _S v60.flags.S
+#define _Z v60.flags.Z
+
+
+// Defines of all v60 register...
+#define R0 v60.reg[0]
+#define R1 v60.reg[1]
+#define R2 v60.reg[2]
+#define R3 v60.reg[3]
+#define R4 v60.reg[4]
+#define R5 v60.reg[5]
+#define R6 v60.reg[6]
+#define R7 v60.reg[7]
+#define R8 v60.reg[8]
+#define R9 v60.reg[9]
+#define R10 v60.reg[10]
+#define R11 v60.reg[11]
+#define R12 v60.reg[12]
+#define R13 v60.reg[13]
+#define R14 v60.reg[14]
+#define R15 v60.reg[15]
+#define R16 v60.reg[16]
+#define R17 v60.reg[17]
+#define R18 v60.reg[18]
+#define R19 v60.reg[19]
+#define R20 v60.reg[20]
+#define R21 v60.reg[21]
+#define R22 v60.reg[22]
+#define R23 v60.reg[23]
+#define R24 v60.reg[24]
+#define R25 v60.reg[25]
+#define R26 v60.reg[26]
+#define R27 v60.reg[27]
+#define R28 v60.reg[28]
+#define AP v60.reg[29]
+#define FP v60.reg[30]
+#define SP v60.reg[31]
+
+#define PC v60.reg[32]
+#define PSW v60.reg[33]
+
+// Privileged registers
+#define ISP v60.reg[36]
+#define L0SP v60.reg[37]
+#define L1SP v60.reg[38]
+#define L2SP v60.reg[39]
+#define L3SP v60.reg[40]
+#define SBR v60.reg[41]
+#define TR v60.reg[42]
+#define SYCW v60.reg[43]
+#define TKCW v60.reg[44]
+#define PIR v60.reg[45]
+//10-14 reserved
+#define PSW2 v60.reg[51]
+#define ATBR0 v60.reg[52]
+#define ATLR0 v60.reg[53]
+#define ATBR1 v60.reg[54]
+#define ATLR1 v60.reg[55]
+#define ATBR2 v60.reg[56]
+#define ATLR2 v60.reg[57]
+#define ATBR3 v60.reg[58]
+#define ATLR3 v60.reg[59]
+#define TRMODE v60.reg[60]
+#define ADTR0 v60.reg[61]
+#define ADTR1 v60.reg[62]
+#define ADTMR0 v60.reg[63]
+#define ADTMR1 v60.reg[64]
+//29-31 reserved
+
+// Register names
+const char *v60_reg_names[69] = {
+ "R0", "R1", "R2", "R3",
+ "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10", "R11",
+ "R12", "R13", "R14", "R15",
+ "R16", "R17", "R18", "R19",
+ "R20", "R21", "R22", "R23",
+ "R24", "R25", "R26", "R27",
+ "R28", "AP", "FP", "SP",
+ "PC", "PSW","Unk","Unk",
+ "ISP", "L0SP", "L1SP", "L2SP",
+ "L3SP", "SBR","TR","SYCW",
+ "TKCW", "PIR", "Reserved","Reserved",
+ "Reserved","Reserved","Reserved","PSW2",
+ "ATBR0", "ATLR0", "ATBR1", "ATLR1",
+ "ATBR2", "ATLR2", "ATBR3", "ATLR3",
+ "TRMODE", "ADTR0", "ADTR1","ADTMR0",
+ "ADTMR1","Reserved","Reserved","Reserved"
+};
+
+// Defines...
+#define NORMALIZEFLAGS() \
+{ \
+ _S = _S ? 1 : 0; \
+ _OV = _OV ? 1 : 0; \
+ _Z = _Z ? 1 : 0; \
+ _CY = _CY ? 1 : 0; \
+}
+
+static void v60_try_irq(void);
+
+
+INLINE void v60SaveStack(void)
+{
+ if (PSW & 0x10000000)
+ ISP = SP;
+ else
+ v60.reg[37 + ((PSW >> 24) & 3)] = SP;
+}
+
+INLINE void v60ReloadStack(void)
+{
+ if (PSW & 0x10000000)
+ SP = ISP;
+ else
+ SP = v60.reg[37 + ((PSW >> 24) & 3)];
+}
+
+INLINE UINT32 v60ReadPSW(void)
+{
+ PSW &= 0xfffffff0;
+ PSW |= (_Z?1:0) | (_S?2:0) | (_OV?4:0) | (_CY?8:0);
+ return PSW;
+}
+
+INLINE void v60WritePSW(UINT32 newval)
+{
+ /* determine if we need to save/restore the stacks */
+ int updateStack = 0;
+
+ /* if the interrupt state is changing, we definitely need to update */
+ if ((newval ^ PSW) & 0x10000000)
+ updateStack = 1;
+
+ /* if we are not in interrupt mode and the level is changing, we also must update */
+ else if (!(PSW & 0x10000000) && ((newval ^ PSW) & 0x03000000))
+ updateStack = 1;
+
+ /* save the previous stack value */
+ if (updateStack)
+ v60SaveStack();
+
+ /* set the new value and update the flags */
+ PSW = newval;
+ _Z = (UINT8)(PSW & 1);
+ _S = (UINT8)(PSW & 2);
+ _OV = (UINT8)(PSW & 4);
+ _CY = (UINT8)(PSW & 8);
+
+ /* fetch the new stack value */
+ if (updateStack)
+ v60ReloadStack();
+}
+
+
+INLINE UINT32 v60_update_psw_for_exception(int is_interrupt, int target_level)
+{
+ UINT32 oldPSW = v60ReadPSW();
+ UINT32 newPSW = oldPSW;
+
+ // Change to interrupt context
+ newPSW &= ~(3 << 24); // PSW.EL = 0
+ newPSW |= target_level << 24; // set target level
+ newPSW &= ~(1 << 18); // PSW.IE = 0
+ newPSW &= ~(1 << 16); // PSW.TE = 0
+ newPSW &= ~(1 << 27); // PSW.TP = 0
+ newPSW &= ~(1 << 17); // PSW.AE = 0
+ newPSW &= ~(1 << 29); // PSW.EM = 0
+ if (is_interrupt)
+ newPSW |= (1 << 28);// PSW.IS = 1
+ newPSW |= (1 << 31); // PSW.ASA = 1
+ v60WritePSW(newPSW);
+
+ return oldPSW;
+}
+
+
+#define GETINTVECT(nint) MemRead32((SBR & ~0xfff) + (nint)*4)
+#define EXCEPTION_CODE_AND_SIZE(code, size) (((code) << 16) | (size))
+
+
+// Addressing mode decoding functions
+#include "am.c"
+
+// Opcode functions
+#include "op12.c"
+#include "op2.c"
+#include "op3.c"
+#include "op4.c"
+#include "op5.c"
+#include "op6.c"
+#include "op7a.c"
+
+static UINT32 opUNHANDLED(void)
+{
+ fatalerror("Unhandled OpCode found : %02x at %08x", OpRead16(PC), PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+// Opcode jump table
+#include "optable.c"
+
+#ifdef UNUSED_FUNCTION
+static int v60_default_irq_cb(int irqline)
+{
+ return 0;
+}
+#endif
+
+static void base_init(const char *type, int index, int (*irqcallback)(int))
+{
+ v60_stall_io = 0;
+ v60.irq_cb = irqcallback;
+ v60.irq_line = CLEAR_LINE;
+ v60.nmi_line = CLEAR_LINE;
+
+ state_save_register_item_array(type, index, v60.reg);
+ state_save_register_item(type, index, v60.irq_line);
+ state_save_register_item(type, index, v60.nmi_line);
+ state_save_register_item(type, index, v60.PPC);
+ state_save_register_item(type, index, _CY);
+ state_save_register_item(type, index, _OV);
+ state_save_register_item(type, index, _S);
+ state_save_register_item(type, index, _Z);
+}
+
+static void v60_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ base_init("v60", index, irqcallback);
+ // Set PIR (Processor ID) for NEC v60. LSB is reserved to NEC,
+ // so I don't know what it contains.
+ PIR = 0x00006000;
+ v60.info = v60_i;
+}
+
+static void v70_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ base_init("v70", index, irqcallback);
+ // Set PIR (Processor ID) for NEC v70. LSB is reserved to NEC,
+ // so I don't know what it contains.
+ PIR = 0x00007000;
+ v60.info = v70_i;
+}
+
+static void v60_reset(void)
+{
+ PSW = 0x10000000;
+ PC = v60.info.start_pc;
+ SBR = 0x00000000;
+ SYCW = 0x00000070;
+ TKCW = 0x0000e000;
+ PSW2 = 0x0000f002;
+ ChangePC(PC);
+
+ _CY = 0;
+ _OV = 0;
+ _S = 0;
+ _Z = 0;
+}
+
+static void v60_exit(void)
+{
+}
+
+void v60_stall(void)
+{
+ v60_stall_io = 1;
+}
+
+static void v60_do_irq(int vector)
+{
+ UINT32 oldPSW = v60_update_psw_for_exception(1, 0);
+
+ // Push PC and PSW onto the stack
+ SP-=4;
+ MemWrite32(SP, oldPSW);
+ SP-=4;
+ MemWrite32(SP, PC);
+
+ // Jump to vector for user interrupt
+ PC = GETINTVECT(vector);
+}
+
+static void v60_try_irq(void)
+{
+ if(v60.irq_line == CLEAR_LINE)
+ return;
+ if((PSW & (1<<18)) != 0) {
+ int vector;
+ if(v60.irq_line != ASSERT_LINE)
+ v60.irq_line = CLEAR_LINE;
+
+ vector = v60.irq_cb(0);
+
+ v60_do_irq(vector + 0x40);
+ } else if(v60.irq_line == PULSE_LINE)
+ v60.irq_line = CLEAR_LINE;
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if(irqline == INPUT_LINE_NMI) {
+ switch(state) {
+ case ASSERT_LINE:
+ if(v60.nmi_line == CLEAR_LINE) {
+ v60.nmi_line = ASSERT_LINE;
+ v60_do_irq(2);
+ }
+ break;
+ case CLEAR_LINE:
+ v60.nmi_line = CLEAR_LINE;
+ break;
+ case HOLD_LINE:
+ case PULSE_LINE:
+ v60.nmi_line = CLEAR_LINE;
+ v60_do_irq(2);
+ break;
+ }
+ } else {
+ v60.irq_line = state;
+ v60_try_irq();
+ }
+}
+
+// Actual cycles/instruction is unknown
+
+static int v60_execute(int cycles)
+{
+ UINT32 inc;
+
+ v60_ICount = cycles;
+ if(v60.irq_line != CLEAR_LINE)
+ v60_try_irq();
+ while(v60_ICount >= 0) {
+ v60.PPC = PC;
+ CALL_MAME_DEBUG;
+ v60_ICount -= 8; /* fix me -- this is just an average */
+ inc = OpCodeTable[OpRead8(PC)]();
+ PC += inc;
+ if(v60.irq_line != CLEAR_LINE)
+ v60_try_irq();
+ }
+
+ return cycles - v60_ICount;
+}
+
+static void v60_get_context(void *dst)
+{
+ if(dst)
+ *(struct v60info *)dst = v60;
+}
+
+static void v60_set_context(void *src)
+{
+ if(src)
+ {
+ v60 = *(struct v60info *)src;
+ ChangePC(PC);
+ }
+}
+
+
+#ifdef MAME_DEBUG
+offs_t v60_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+offs_t v70_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif /* MAME_DEBUG */
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void v60_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC: PC = info->i; ChangePC(PC); break;
+ case CPUINFO_INT_SP: SP = info->i; break;
+
+ case CPUINFO_INT_REGISTER + V60_R0: R0 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R1: R1 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R2: R2 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R3: R3 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R4: R4 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R5: R5 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R6: R6 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R7: R7 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R8: R8 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R9: R9 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R10: R10 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R11: R11 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R12: R12 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R13: R13 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R14: R14 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R15: R15 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R16: R16 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R17: R17 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R18: R18 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R19: R19 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R20: R20 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R21: R21 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R22: R22 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R23: R23 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R24: R24 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R25: R25 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R26: R26 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R27: R27 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_R28: R28 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_AP: AP = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_FP: FP = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_SP: SP = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_PC: PC = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_PSW: v60WritePSW(info->i); break;
+ case CPUINFO_INT_REGISTER + V60_ISP: ISP = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_L0SP: L0SP = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_L1SP: L1SP = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_L2SP: L2SP = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_L3SP: L3SP = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_SBR: SBR = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_TR: TR = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_SYCW: SYCW = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_TKCW: TKCW = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_PIR: PIR = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_PSW2: PSW2 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ATBR0: ATBR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ATLR0: ATLR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ATBR1: ATBR1 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ATLR1: ATLR1 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ATBR2: ATBR2 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ATLR2: ATLR2 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ATBR3: ATBR3 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ATLR3: ATLR3 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_TRMODE: TRMODE = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ADTR0: ADTR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ADTR1: ADTR1 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ADTMR0: ADTMR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + V60_ADTMR1: ADTMR1 = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void v60_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(v60); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 22; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 24; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = v60.irq_line; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = v60.nmi_line; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = v60.PPC; break;
+
+ case CPUINFO_INT_REGISTER + V60_R0: info->i = R0; break;
+ case CPUINFO_INT_REGISTER + V60_R1: info->i = R1; break;
+ case CPUINFO_INT_REGISTER + V60_R2: info->i = R2; break;
+ case CPUINFO_INT_REGISTER + V60_R3: info->i = R3; break;
+ case CPUINFO_INT_REGISTER + V60_R4: info->i = R4; break;
+ case CPUINFO_INT_REGISTER + V60_R5: info->i = R5; break;
+ case CPUINFO_INT_REGISTER + V60_R6: info->i = R6; break;
+ case CPUINFO_INT_REGISTER + V60_R7: info->i = R7; break;
+ case CPUINFO_INT_REGISTER + V60_R8: info->i = R8; break;
+ case CPUINFO_INT_REGISTER + V60_R9: info->i = R9; break;
+ case CPUINFO_INT_REGISTER + V60_R10: info->i = R10; break;
+ case CPUINFO_INT_REGISTER + V60_R11: info->i = R11; break;
+ case CPUINFO_INT_REGISTER + V60_R12: info->i = R12; break;
+ case CPUINFO_INT_REGISTER + V60_R13: info->i = R13; break;
+ case CPUINFO_INT_REGISTER + V60_R14: info->i = R14; break;
+ case CPUINFO_INT_REGISTER + V60_R15: info->i = R15; break;
+ case CPUINFO_INT_REGISTER + V60_R16: info->i = R16; break;
+ case CPUINFO_INT_REGISTER + V60_R17: info->i = R17; break;
+ case CPUINFO_INT_REGISTER + V60_R18: info->i = R18; break;
+ case CPUINFO_INT_REGISTER + V60_R19: info->i = R19; break;
+ case CPUINFO_INT_REGISTER + V60_R20: info->i = R20; break;
+ case CPUINFO_INT_REGISTER + V60_R21: info->i = R21; break;
+ case CPUINFO_INT_REGISTER + V60_R22: info->i = R22; break;
+ case CPUINFO_INT_REGISTER + V60_R23: info->i = R23; break;
+ case CPUINFO_INT_REGISTER + V60_R24: info->i = R24; break;
+ case CPUINFO_INT_REGISTER + V60_R25: info->i = R25; break;
+ case CPUINFO_INT_REGISTER + V60_R26: info->i = R26; break;
+ case CPUINFO_INT_REGISTER + V60_R27: info->i = R27; break;
+ case CPUINFO_INT_REGISTER + V60_R28: info->i = R28; break;
+ case CPUINFO_INT_REGISTER + V60_AP: info->i = AP; break;
+ case CPUINFO_INT_REGISTER + V60_FP: info->i = FP; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + V60_SP: info->i = SP; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + V60_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + V60_PSW: info->i = v60ReadPSW(); break;
+ case CPUINFO_INT_REGISTER + V60_ISP: info->i = ISP; break;
+ case CPUINFO_INT_REGISTER + V60_L0SP: info->i = L0SP; break;
+ case CPUINFO_INT_REGISTER + V60_L1SP: info->i = L1SP; break;
+ case CPUINFO_INT_REGISTER + V60_L2SP: info->i = L2SP; break;
+ case CPUINFO_INT_REGISTER + V60_L3SP: info->i = L3SP; break;
+ case CPUINFO_INT_REGISTER + V60_SBR: info->i = SBR; break;
+ case CPUINFO_INT_REGISTER + V60_TR: info->i = TR; break;
+ case CPUINFO_INT_REGISTER + V60_SYCW: info->i = SYCW; break;
+ case CPUINFO_INT_REGISTER + V60_TKCW: info->i = TKCW; break;
+ case CPUINFO_INT_REGISTER + V60_PIR: info->i = PIR; break;
+ case CPUINFO_INT_REGISTER + V60_PSW2: info->i = PSW2; break;
+ case CPUINFO_INT_REGISTER + V60_ATBR0: info->i = ATBR0; break;
+ case CPUINFO_INT_REGISTER + V60_ATLR0: info->i = ATLR0; break;
+ case CPUINFO_INT_REGISTER + V60_ATBR1: info->i = ATBR1; break;
+ case CPUINFO_INT_REGISTER + V60_ATLR1: info->i = ATLR1; break;
+ case CPUINFO_INT_REGISTER + V60_ATBR2: info->i = ATBR2; break;
+ case CPUINFO_INT_REGISTER + V60_ATLR2: info->i = ATLR2; break;
+ case CPUINFO_INT_REGISTER + V60_ATBR3: info->i = ATBR3; break;
+ case CPUINFO_INT_REGISTER + V60_ATLR3: info->i = ATLR3; break;
+ case CPUINFO_INT_REGISTER + V60_TRMODE: info->i = TRMODE; break;
+ case CPUINFO_INT_REGISTER + V60_ADTR0: info->i = ADTR0; break;
+ case CPUINFO_INT_REGISTER + V60_ADTR1: info->i = ADTR1; break;
+ case CPUINFO_INT_REGISTER + V60_ADTMR0: info->i = ADTMR0; break;
+ case CPUINFO_INT_REGISTER + V60_ADTMR1: info->i = ADTMR1; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = v60_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = v60_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = v60_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = v60_init; break;
+ case CPUINFO_PTR_RESET: info->reset = v60_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = v60_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = v60_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = v60_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &v60_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "V60"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "NEC V60"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Farfetch'd and R.Belmont"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
+
+ case CPUINFO_STR_REGISTER + V60_R0: sprintf(info->s, "R0:%08X", R0); break;
+ case CPUINFO_STR_REGISTER + V60_R1: sprintf(info->s, "R1:%08X", R1); break;
+ case CPUINFO_STR_REGISTER + V60_R2: sprintf(info->s, "R2:%08X", R2); break;
+ case CPUINFO_STR_REGISTER + V60_R3: sprintf(info->s, "R3:%08X", R3); break;
+ case CPUINFO_STR_REGISTER + V60_R4: sprintf(info->s, "R4:%08X", R4); break;
+ case CPUINFO_STR_REGISTER + V60_R5: sprintf(info->s, "R5:%08X", R5); break;
+ case CPUINFO_STR_REGISTER + V60_R6: sprintf(info->s, "R6:%08X", R6); break;
+ case CPUINFO_STR_REGISTER + V60_R7: sprintf(info->s, "R7:%08X", R7); break;
+ case CPUINFO_STR_REGISTER + V60_R8: sprintf(info->s, "R8:%08X", R8); break;
+ case CPUINFO_STR_REGISTER + V60_R9: sprintf(info->s, "R9:%08X", R9); break;
+ case CPUINFO_STR_REGISTER + V60_R10: sprintf(info->s, "R10:%08X", R10); break;
+ case CPUINFO_STR_REGISTER + V60_R11: sprintf(info->s, "R11:%08X", R11); break;
+ case CPUINFO_STR_REGISTER + V60_R12: sprintf(info->s, "R12:%08X", R12); break;
+ case CPUINFO_STR_REGISTER + V60_R13: sprintf(info->s, "R13:%08X", R13); break;
+ case CPUINFO_STR_REGISTER + V60_R14: sprintf(info->s, "R14:%08X", R14); break;
+ case CPUINFO_STR_REGISTER + V60_R15: sprintf(info->s, "R15:%08X", R15); break;
+ case CPUINFO_STR_REGISTER + V60_R16: sprintf(info->s, "R16:%08X", R16); break;
+ case CPUINFO_STR_REGISTER + V60_R17: sprintf(info->s, "R17:%08X", R17); break;
+ case CPUINFO_STR_REGISTER + V60_R18: sprintf(info->s, "R18:%08X", R18); break;
+ case CPUINFO_STR_REGISTER + V60_R19: sprintf(info->s, "R19:%08X", R19); break;
+ case CPUINFO_STR_REGISTER + V60_R20: sprintf(info->s, "R20:%08X", R20); break;
+ case CPUINFO_STR_REGISTER + V60_R21: sprintf(info->s, "R21:%08X", R21); break;
+ case CPUINFO_STR_REGISTER + V60_R22: sprintf(info->s, "R22:%08X", R22); break;
+ case CPUINFO_STR_REGISTER + V60_R23: sprintf(info->s, "R23:%08X", R23); break;
+ case CPUINFO_STR_REGISTER + V60_R24: sprintf(info->s, "R24:%08X", R24); break;
+ case CPUINFO_STR_REGISTER + V60_R25: sprintf(info->s, "R25:%08X", R25); break;
+ case CPUINFO_STR_REGISTER + V60_R26: sprintf(info->s, "R26:%08X", R26); break;
+ case CPUINFO_STR_REGISTER + V60_R27: sprintf(info->s, "R27:%08X", R27); break;
+ case CPUINFO_STR_REGISTER + V60_R28: sprintf(info->s, "R28:%08X", R28); break;
+ case CPUINFO_STR_REGISTER + V60_AP: sprintf(info->s, "AP:%08X", AP); break;
+ case CPUINFO_STR_REGISTER + V60_FP: sprintf(info->s, "FP:%08X", FP); break;
+ case CPUINFO_STR_REGISTER + V60_SP: sprintf(info->s, "SP:%08X", SP); break;
+ case CPUINFO_STR_REGISTER + V60_PC: sprintf(info->s, "PC:%08X", PC); break;
+ case CPUINFO_STR_REGISTER + V60_PSW: sprintf(info->s, "PSW:%08X", v60ReadPSW()); break;
+ case CPUINFO_STR_REGISTER + V60_ISP: sprintf(info->s, "ISP:%08X", ISP); break;
+ case CPUINFO_STR_REGISTER + V60_L0SP: sprintf(info->s, "L0SP:%08X", L0SP); break;
+ case CPUINFO_STR_REGISTER + V60_L1SP: sprintf(info->s, "L1SP:%08X", L1SP); break;
+ case CPUINFO_STR_REGISTER + V60_L2SP: sprintf(info->s, "L2SP:%08X", L2SP); break;
+ case CPUINFO_STR_REGISTER + V60_L3SP: sprintf(info->s, "L3SP:%08X", L3SP); break;
+ case CPUINFO_STR_REGISTER + V60_SBR: sprintf(info->s, "SBR:%08X", SBR); break;
+ case CPUINFO_STR_REGISTER + V60_TR: sprintf(info->s, "TR:%08X", TR); break;
+ case CPUINFO_STR_REGISTER + V60_SYCW: sprintf(info->s, "SYCW:%08X", SYCW); break;
+ case CPUINFO_STR_REGISTER + V60_TKCW: sprintf(info->s, "TKCW:%08X", TKCW); break;
+ case CPUINFO_STR_REGISTER + V60_PIR: sprintf(info->s, "PIR:%08X", PIR); break;
+ case CPUINFO_STR_REGISTER + V60_PSW2: sprintf(info->s, "PSW2:%08X", PSW2); break;
+ case CPUINFO_STR_REGISTER + V60_ATBR0: sprintf(info->s, "ATBR0:%08X", ATBR0); break;
+ case CPUINFO_STR_REGISTER + V60_ATLR0: sprintf(info->s, "ATLR0:%08X", ATLR0); break;
+ case CPUINFO_STR_REGISTER + V60_ATBR1: sprintf(info->s, "ATBR1:%08X", ATBR1); break;
+ case CPUINFO_STR_REGISTER + V60_ATLR1: sprintf(info->s, "ATLR1:%08X", ATLR1); break;
+ case CPUINFO_STR_REGISTER + V60_ATBR2: sprintf(info->s, "ATBR2:%08X", ATBR2); break;
+ case CPUINFO_STR_REGISTER + V60_ATLR2: sprintf(info->s, "ATLR2:%08X", ATLR2); break;
+ case CPUINFO_STR_REGISTER + V60_ATBR3: sprintf(info->s, "ATBR3:%08X", ATBR3); break;
+ case CPUINFO_STR_REGISTER + V60_ATLR3: sprintf(info->s, "ATLR3:%08X", ATLR3); break;
+ case CPUINFO_STR_REGISTER + V60_TRMODE: sprintf(info->s, "TRMODE:%08X", TRMODE); break;
+ case CPUINFO_STR_REGISTER + V60_ADTR0: sprintf(info->s, "ADTR0:%08X", ADTR0); break;
+ case CPUINFO_STR_REGISTER + V60_ADTR1: sprintf(info->s, "ADTR1:%08X", ADTR1); break;
+ case CPUINFO_STR_REGISTER + V60_ADTMR0: sprintf(info->s, "ADTMR0:%08X", ADTMR0); break;
+ case CPUINFO_STR_REGISTER + V60_ADTMR1: sprintf(info->s, "ADTMR1:%08X", ADTMR1); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+void v70_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_INIT: info->init = v70_init; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = v70_dasm; break;
+#endif /* MAME_DEBUG */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "V70"); break;
+
+ default: v60_get_info(state, info); break;
+ }
+}
diff --git a/src/emu/cpu/v60/v60.h b/src/emu/cpu/v60/v60.h
new file mode 100644
index 00000000000..d5dbb2ba9e7
--- /dev/null
+++ b/src/emu/cpu/v60/v60.h
@@ -0,0 +1,90 @@
+#ifndef __V60_H
+#define __V60_H
+
+#include "cpuintrf.h"
+
+enum {
+ V60_R0 = 1,
+ V60_R1,
+ V60_R2,
+ V60_R3,
+ V60_R4,
+ V60_R5,
+ V60_R6,
+ V60_R7,
+ V60_R8,
+ V60_R9,
+ V60_R10,
+ V60_R11,
+ V60_R12,
+ V60_R13,
+ V60_R14,
+ V60_R15,
+ V60_R16,
+ V60_R17,
+ V60_R18,
+ V60_R19,
+ V60_R20,
+ V60_R21,
+ V60_R22,
+ V60_R23,
+ V60_R24,
+ V60_R25,
+ V60_R26,
+ V60_R27,
+ V60_R28,
+ V60_AP,
+ V60_FP,
+ V60_SP,
+ V60_PC,
+ V60_PSW,
+ V60_U1,
+ V60_U2,
+ V60_ISP,
+ V60_L0SP,
+ V60_L1SP,
+ V60_L2SP,
+ V60_L3SP,
+ V60_SBR,
+ V60_TR,
+ V60_SYCW,
+ V60_TKCW,
+ V60_PIR,
+ V60_Res1,
+ V60_Res2,
+ V60_Res3,
+ V60_Res4,
+ V60_Res5,
+ V60_PSW2,
+ V60_ATBR0,
+ V60_ATLR0,
+ V60_ATBR1,
+ V60_ATLR1,
+ V60_ATBR2,
+ V60_ATLR2,
+ V60_ATBR3,
+ V60_ATLR3,
+ V60_TRMODE,
+ V60_ADTR0,
+ V60_ADTR1,
+ V60_ADTMR0,
+ V60_ADTMR1,
+ V60_Res6,
+ V60_Res7,
+ V60_Res8,
+ V60_REGMAX
+};
+
+extern const char *v60_reg_names[];
+void v60_stall(void);
+
+#if HAS_V60
+void v60_get_info(UINT32 state, cpuinfo *info);
+#endif
+
+#endif
+
+#if HAS_V70
+void v70_get_info(UINT32 state, cpuinfo *info);
+#endif
+
diff --git a/src/emu/cpu/v60/v60d.c b/src/emu/cpu/v60/v60d.c
new file mode 100644
index 00000000000..0723715986f
--- /dev/null
+++ b/src/emu/cpu/v60/v60d.c
@@ -0,0 +1,1477 @@
+
+#include "debugger.h"
+#include "v60.h"
+
+static const UINT8 *rombase;
+static offs_t pcbase;
+
+#define readop(a) rombase[(a) - pcbase]
+
+static signed char read8(unsigned pc)
+{
+ return readop(pc);
+}
+
+static signed short read16(unsigned pc)
+{
+ return readop(pc) | (readop(pc+1) << 8);
+}
+
+static signed int read32(unsigned pc)
+{
+ return readop(pc) | (readop(pc+1) << 8)| (readop(pc+2) << 16)| (readop(pc+3) << 24);
+}
+
+static void out_AM_Register(int reg, char *out)
+{
+ strcat(out, v60_reg_names[reg]);
+}
+
+static void out_AM_RegisterIndirect(int reg, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ *out++ = '@';
+ sprintf(out, "[%s]", v60_reg_names[reg]);
+}
+
+static void out_AM_RegisterIndirectIndexed(int rn, int rx, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ sprintf(out, "%s@[%s]", v60_reg_names[rx], v60_reg_names[rn]);
+ else
+ sprintf(out, "[%s](%s)", v60_reg_names[rn], v60_reg_names[rx]);
+
+}
+
+static void out_AM_Autoincrement(int reg, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ *out++ = '@';
+ sprintf(out, "[%s+]", v60_reg_names[reg]);
+}
+
+static void out_AM_Autodecrement(int reg, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ *out++ = '@';
+ sprintf(out, "[-%s]", v60_reg_names[reg]);
+}
+
+static void out_AM_Displacement(int reg, int disp, int opsize, char *out)
+{
+ sprintf(out, "%s%X%s[%s]",
+ disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,
+ opsize & 0x80 ? "@" : "",
+ v60_reg_names[reg]);
+}
+
+static void out_AM_DisplacementIndexed(int rn, int rx, int disp, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ sprintf(out, "%s@%s%X[%s]", v60_reg_names[rx], disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,v60_reg_names[rn]);
+ else
+ sprintf(out, "%s%X[%s](%s)", disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,v60_reg_names[rn], v60_reg_names[rx]);
+}
+
+static void out_AM_PCDisplacement(unsigned pc, int disp, int opsize, char *out)
+{
+ sprintf(out, "%X%s[PC]", pc+disp, opsize & 0x80 ? "@" : "");
+}
+
+static void out_AM_PCDisplacementIndexed(unsigned pc, int disp, int rx, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ sprintf(out, "%s@%X[PC]", v60_reg_names[rx], pc+disp);
+ else
+ sprintf(out, "%X[PC](%s)", pc+disp, v60_reg_names[rx]);
+}
+
+static void out_AM_DisplacementIndirect(int reg, int disp, int opsize, char *out)
+{
+ sprintf(out, "%s[%s%X[%s]]",
+ opsize & 0x80 ? "@" : "",
+ disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,
+ v60_reg_names[reg]);
+}
+
+static void out_AM_DisplacementIndirectIndexed(int rn, int rx, int disp, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ sprintf(out, "%s@[%s%X[%s]]", v60_reg_names[rx], disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,v60_reg_names[rn]);
+ else
+ sprintf(out, "[%s%X[%s]](%s)", disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,v60_reg_names[rn], v60_reg_names[rx]);
+}
+
+static void out_AM_PCDisplacementIndirect(unsigned pc, int disp, int opsize, char *out)
+{
+ sprintf(out, "%s[%X[PC]]", opsize & 0x80 ? "@" : "", pc+disp);
+}
+
+static void out_AM_PCDisplacementIndirectIndexed(unsigned pc, int disp, int rx, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ sprintf(out, "%s@[%X[PC]]", v60_reg_names[rx], pc+disp);
+ else
+ sprintf(out, "[%X[PC]](%s)", pc+disp, v60_reg_names[rx]);
+}
+
+static void out_AM_DoubleDisplacement(int reg, int disp2, int disp1, int opsize, char *out)
+{
+ sprintf(out, "%s%X%s[%s%X[%s]]",
+ disp1 >= 0 ? "" : "-", disp1 >= 0 ? disp1 : -disp1,
+ opsize & 0x80 ? "@" : "",
+ disp2 >= 0 ? "" : "-", disp2 >= 0 ? disp2 : -disp2,
+ v60_reg_names[reg]);
+}
+
+static void out_AM_PCDoubleDisplacement(unsigned pc, int disp2, int disp1, int opsize, char *out)
+{
+ sprintf(out, "%s%X%s[%X[PC]]",
+ disp1 >= 0 ? "" : "-", disp1 >= 0 ? disp1 : -disp1,
+ opsize & 0x80 ? "@" : "",
+ disp2 + pc);
+}
+
+static void out_AM_DirectAddress(unsigned addr, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ *out++ = '@';
+ sprintf(out, "%X", addr);
+}
+
+static void out_AM_DirectAddressIndexed(unsigned addr, int rx, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ sprintf(out, "%s@%X", v60_reg_names[rx], addr);
+ else
+ sprintf(out, "%X(%s)", addr, v60_reg_names[rx]);
+}
+
+static void out_AM_DirectAddressDeferred(unsigned addr, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ *out++ = '@';
+ sprintf(out, "[%X]", addr);
+}
+
+static void out_AM_DirectAddressDeferredIndexed(unsigned addr, int rx, int opsize, char *out)
+{
+ if(opsize & 0x80)
+ sprintf(out, "%s@[%X]", v60_reg_names[rx], addr);
+ else
+ sprintf(out, "[%X](%s)", addr, v60_reg_names[rx]);
+}
+
+static void out_AM_Immediate(unsigned value, int opsize, char *out)
+{
+ if(opsize == 0)
+ value &= 0xff;
+ else if(opsize == 1)
+ value &= 0xffff;
+
+ sprintf(out, "#%X", value);
+}
+
+static int decode_AM(unsigned ipc, unsigned pc, int m, int opsize, char *out)
+{
+ unsigned char mod = readop(pc);
+ if(m) {
+ switch(mod>>5) {
+ case 0: // Double displacement (8 bit)
+ out_AM_DoubleDisplacement(mod&0x1F, read8(pc+1), read8(pc+2), opsize, out);
+ return 3;
+
+ case 1: // Double displacement (16 bit)
+ out_AM_DoubleDisplacement(mod&0x1F, read16(pc+1), read16(pc+3), opsize, out);
+ return 5;
+
+ case 2: // Double displacement (32 bit)
+ out_AM_DoubleDisplacement(mod&0x1F, read32(pc+1), read32(pc+5), opsize, out);
+ return 9;
+
+ case 3: // Register
+ out_AM_Register(mod&0x1F, out);
+ return 1;
+
+ case 4: // Autoincrement
+ out_AM_Autoincrement(mod&0x1F, opsize, out);
+ return 1;
+
+ case 5: // Autodecrement
+ out_AM_Autodecrement(mod&0x1F, opsize, out);
+ return 1;
+
+ case 6:
+ switch (readop(pc+1)>>5)
+ {
+ case 0: // Displacement indexed (8 bit)
+ out_AM_DisplacementIndexed(readop(pc+1)&0x1F, mod&0x1F, read8(pc+2), opsize, out);
+ return 3;
+
+ case 1: // Displacement indexed (16 bit)
+ out_AM_DisplacementIndexed(readop(pc+1)&0x1F, mod&0x1F, read16(pc+2), opsize, out);
+ return 4;
+
+ case 2: // Displacement indexed (32 bit)
+ out_AM_DisplacementIndexed(readop(pc+1)&0x1F, mod&0x1F, read32(pc+2), opsize, out);
+ return 6;
+
+ case 3: // Register indirect indexed
+ out_AM_RegisterIndirectIndexed(readop(pc+1)&0x1F, mod&0x1F, opsize, out);
+ return 2;
+
+ case 4: // Displacement indirect indexed (8 bit)
+ out_AM_DisplacementIndirectIndexed(readop(pc+1)&0x1F, mod&0x1F, read8(pc+2), opsize, out);
+ return 3;
+
+ case 5: // Displacement indirect indexed (16 bit)
+ out_AM_DisplacementIndirectIndexed(readop(pc+1)&0x1F, mod&0x1F, read16(pc+2), opsize, out);
+ return 4;
+
+ case 6: // Displacement indirect indexed (32 bit)
+ out_AM_DisplacementIndirectIndexed(readop(pc+1)&0x1F, mod&0x1F, read32(pc+2), opsize, out);
+ return 6;
+
+ case 7:
+ switch (readop(pc+1)&0x1F)
+ {
+ case 16: // PC Displacement Indexed (8 bit)
+ out_AM_PCDisplacementIndexed(ipc, read8(pc+2), mod&0x1F, opsize, out);
+ return 3;
+
+ case 17: // PC Displacement Indexed (16 bit)
+ out_AM_PCDisplacementIndexed(ipc, read16(pc+2), mod&0x1F, opsize, out);
+ return 4;
+
+ case 18: // PC Displacement Indexed (32 bit)
+ out_AM_PCDisplacementIndexed(ipc, read32(pc+2), mod&0x1F, opsize, out);
+ return 6;
+
+ case 19: // Direct Address Indexed
+ out_AM_DirectAddressIndexed(read32(pc+2), mod&0x1F, opsize, out);
+ return 6;
+
+ case 24: // PC Displacement Indirect Indexed(8 bit)
+ out_AM_PCDisplacementIndirectIndexed(ipc, read8(pc+2), mod&0x1F, opsize, out);
+ return 3;
+
+ case 25: // PC Displacement Indirect Indexed (16 bit)
+ out_AM_PCDisplacementIndirectIndexed(ipc, read16(pc+2), mod&0x1F, opsize, out);
+ return 4;
+
+ case 26: // PC Displacement Indirect Indexed (32 bit)
+ out_AM_PCDisplacementIndirectIndexed(ipc, read32(pc+2), mod&0x1F, opsize, out);
+ return 6;
+
+ case 27: // Direct Address Deferred Indexed
+ out_AM_DirectAddressDeferredIndexed(read32(pc+2), mod&0x1F, opsize, out);
+ return 6;
+
+ default:
+ strcat(out, "!ERRAM3");
+ return 1;
+ }
+
+ default:
+ strcat(out, "!ERRAM2");
+ return 1;
+ }
+
+ default:
+ strcat(out, "!ERRAM1");
+ return 1;
+ }
+ } else {
+ switch(mod>>5) {
+ case 0: // Displacement (8 bit)
+ out_AM_Displacement(mod&0x1F, read8(pc+1), opsize, out);
+ return 2;
+
+ case 1: // Displacement (16 bit)
+ out_AM_Displacement(mod&0x1F, read16(pc+1), opsize, out);
+ return 3;
+
+ case 2: // Displacement (32 bit)
+ out_AM_Displacement(mod&0x1F, read32(pc+1), opsize, out);
+ return 5;
+
+ case 3: // Register indirect
+ out_AM_RegisterIndirect(mod&0x1F, opsize, out);
+ return 1;
+
+ case 4: // Displacement indirect (8 bit)
+ out_AM_DisplacementIndirect(mod&0x1F, read8(pc+1), opsize, out);
+ return 2;
+
+ case 5: // Displacement indirect (16 bit)
+ out_AM_DisplacementIndirect(mod&0x1F, read16(pc+1), opsize, out);
+ return 3;
+
+ case 6: // Displacement indirect (32 bit)
+ out_AM_DisplacementIndirect(mod&0x1F, read32(pc+1), opsize, out);
+ return 5;
+
+ case 7:
+ switch(mod&0x1F) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ out_AM_Immediate(mod&0x1F, opsize, out);
+ return 1;
+
+ case 16: // PC Displacement (8 bit)
+ out_AM_PCDisplacement(ipc, read8(pc+1), opsize, out);
+ return 2;
+
+ case 17: // PC Displacement (16 bit)
+ out_AM_PCDisplacement(ipc, read16(pc+1), opsize, out);
+ return 3;
+
+ case 18: // PC Displacement (32 bit)
+ out_AM_PCDisplacement(ipc, read32(pc+1), opsize, out);
+ return 5;
+
+ case 19: // Direct Address
+ out_AM_DirectAddress(read32(pc+1), opsize, out);
+ return 5;
+
+
+ case 20:
+ switch(opsize&0x7F) {
+ case 0: // Immediate (8 bit)
+ out_AM_Immediate(read8(pc+1), opsize, out);
+ return 2;
+
+ case 1: // Immediate (16 bit)
+ out_AM_Immediate(read16(pc+1), opsize, out);
+ return 3;
+
+ case 2: // Immediate (32 bit)
+ out_AM_Immediate(read32(pc+1), opsize, out);
+ return 5;
+
+ default:
+ strcat(out, "!ERRAM6");
+ return 1;
+ }
+
+ case 24: // PC Displacement Indirect (8 bit)
+ out_AM_PCDisplacementIndirect(ipc, read8(pc+1), opsize, out);
+ return 2;
+
+ case 25: // PC Displacement Indirect (16 bit)
+ out_AM_PCDisplacementIndirect(ipc, read16(pc+1), opsize, out);
+ return 3;
+
+ case 26: // PC Displacement Indirect (32 bit)
+ out_AM_PCDisplacementIndirect(ipc, read32(pc+1), opsize, out);
+ return 5;
+
+ case 27: // Direct Address Deferred
+ out_AM_DirectAddressDeferred(read32(pc+1), opsize, out);
+ return 5;
+
+ case 28: // PC Double Displacement (8 bit)
+ out_AM_PCDoubleDisplacement(ipc, read8(pc+1), read8(pc+2), opsize, out);
+ return 3;
+
+ case 29: // PC Double Displacement (16 bit)
+ out_AM_PCDoubleDisplacement(ipc, read16(pc+1), read16(pc+3), opsize, out);
+ return 5;
+
+ case 30: // PC Double Displacement (32 bit)
+ out_AM_PCDoubleDisplacement(ipc, read32(pc+1), read32(pc+5), opsize, out);
+ return 9;
+
+ default:
+ strcat(out, "!ERRAM5");
+ return 1;
+ }
+
+ default:
+ strcat(out, "!ERRAM4");
+ return 1;
+ }
+ }
+}
+
+
+static int decode_F1(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ unsigned char code = readop(pc);
+ sprintf(out, "%-8s", opnm);
+ if(code & 0x20) {
+ int ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out)) + 2;
+ strcat(out, ", ");
+ out_AM_Register(code & 0x1f, out + strlen(out));
+ return ret;
+ } else {
+ out_AM_Register(code & 0x1f, out + strlen(out));
+ strcat(out, ", ");
+ return decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out)) + 2;
+ }
+}
+
+static int decode_F2(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ int ret;
+ unsigned char code = readop(pc);
+ sprintf(out, "%-8s", opnm);
+ ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out));
+ strcat(out, ", ");
+ ret += decode_AM(ipc, pc+1+ret, code & 0x20, opsize2, out + strlen(out));
+ return ret+2;
+}
+
+static int decode_F1F2(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ if(readop(pc) & 0x80)
+ return decode_F2(opnm, opsize1, opsize2, ipc, pc, out);
+ else
+ return decode_F1(opnm, opsize1, opsize2, ipc, pc, out);
+}
+
+static int decode_F3(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "%-8s", opnm);
+ return decode_AM(ipc, pc, readop(pc-1) & 1, opsize1, out + strlen(out)) + 1;
+}
+
+static int decode_F4a(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "%-8s%X", opnm, ipc+read8(pc));
+ return 2;
+}
+
+static int decode_F4b(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "%-8s%X", opnm, ipc+read16(pc));
+ return 3;
+}
+
+static int decode_F5(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ strcpy(out, opnm);
+ return 1;
+}
+
+static int decode_F6(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "%-8s%s, %X[PC]", opnm, v60_reg_names[readop(pc) & 0x1f], ipc+read16(pc+1));
+ return 4;
+}
+
+static int decode_F7a(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ int ret;
+ unsigned char code = readop(pc);
+ unsigned char code2;
+
+ sprintf(out, "%-8s", opnm);
+ ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out));
+ strcat(out, ", ");
+
+ code2 = readop(pc+1+ret);
+ if(code2 & 0x80)
+ out_AM_Register(code2 & 0x1f, out + strlen(out));
+ else
+ out_AM_Immediate(code2, 1, out + strlen(out));
+ strcat(out, ", ");
+
+ ret += decode_AM(ipc, pc+2+ret, code & 0x20, opsize2, out + strlen(out));
+ strcat(out, ", ");
+
+ code2 = readop(pc+2+ret);
+ if(code2 & 0x80)
+ out_AM_Register(code2 & 0x1f, out + strlen(out));
+ else
+ out_AM_Immediate(code2, 1, out + strlen(out));
+
+ return ret+4;
+}
+
+static int decode_F7b(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ int ret;
+ unsigned char code = readop(pc);
+ unsigned char code2;
+
+ sprintf(out, "%-8s", opnm);
+ ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out));
+ strcat(out, ", ");
+
+ code2 = readop(pc+1+ret);
+ if(code2 & 0x80)
+ out_AM_Register(code2 & 0x1f, out + strlen(out));
+ else
+ out_AM_Immediate(code2, 1, out + strlen(out));
+ strcat(out, ", ");
+
+ ret += decode_AM(ipc, pc+2+ret, code & 0x20, opsize2, out + strlen(out));
+
+ return ret+3;
+}
+
+static int decode_F7c(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out)
+{
+ int ret;
+ unsigned char code = readop(pc);
+ unsigned char code2;
+
+ sprintf(out, "%-8s", opnm);
+ ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out));
+ strcat(out, ", ");
+
+ ret += decode_AM(ipc, pc+1+ret, code & 0x20, opsize2, out + strlen(out));
+ strcat(out, ", ");
+
+ code2 = readop(pc+1+ret);
+ if(code2 & 0x80)
+ out_AM_Register(code2 & 0x1f, out + strlen(out));
+ else
+ out_AM_Immediate(code2, 1, out + strlen(out));
+
+ return ret+3;
+}
+
+static int dopUNHANDLED(unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "$%02X", readop(pc));
+ return 1;
+}
+
+static int dop58UNHANDLED(unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "$58");
+ return 1;
+}
+
+static int dop59UNHANDLED(unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "$59");
+ return 1;
+}
+
+static int dop5AUNHANDLED(unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "$5A");
+ return 1;
+}
+
+static int dop5BUNHANDLED(unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "$5B");
+ return 1;
+}
+
+static int dop5CUNHANDLED(unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "$5C");
+ return 1;
+}
+
+static int dop5DUNHANDLED(unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "$5D");
+ return 1;
+}
+
+static int dop5EUNHANDLED(unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "$5E");
+ return 1;
+}
+
+static int dop5FUNHANDLED(unsigned ipc, unsigned pc, char *out)
+{
+ sprintf(out, "$5F");
+ return 1;
+}
+
+#define DEFINE_EASY_OPCODE(name, opnm, ftype, opsize1, opsize2) \
+ static int dop ## name(unsigned ipc, unsigned pc, char *out) \
+ { \
+ return decode_ ## ftype(opnm, opsize1, opsize2, ipc, pc, out); \
+ }
+
+#define DEFINE_EASY_OPCODE_EX(name, opnm, ftype, opsize1, opsize2, flags) \
+ static int dop ## name(unsigned ipc, unsigned pc, char *out) \
+ { \
+ return decode_ ## ftype(opnm, opsize1, opsize2, ipc, pc, out) | (flags); \
+ }
+
+#define DEFINE_TRIPLE_OPCODE(name, string, ftype) \
+ DEFINE_EASY_OPCODE(name##B,string ".b", ftype, 0, 0) \
+ DEFINE_EASY_OPCODE(name##H,string ".h", ftype, 1, 1) \
+ DEFINE_EASY_OPCODE(name##W,string ".w", ftype, 2, 2)
+
+#define DEFINE_DOUBLE_OPCODE(name, string, ftype) \
+ DEFINE_EASY_OPCODE(name##B,string ".b", ftype, 0, 0) \
+ DEFINE_EASY_OPCODE(name##H,string ".h", ftype, 1, 1)
+
+#define DEFINE_FPU_OPCODE(name,string,ftype) \
+ DEFINE_EASY_OPCODE(name##S,string ".s", ftype, 2, 2) \
+ DEFINE_EASY_OPCODE(name##L,string ".l", ftype, 2, 2)
+
+
+DEFINE_FPU_OPCODE(ABSF, "absf", F2)
+DEFINE_TRIPLE_OPCODE(ADD, "add", F1F2)
+DEFINE_TRIPLE_OPCODE(ADDC, "addc", F1F2)
+DEFINE_EASY_OPCODE(ADDDC, "adddc", F7c, 0, 0)
+DEFINE_FPU_OPCODE(ADDF, "addf", F2)
+DEFINE_TRIPLE_OPCODE(AND, "and", F1F2)
+DEFINE_EASY_OPCODE(ANDBSU, "andbsu", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(ANDBSD, "andbsd", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(ANDNBSU, "andnbsu", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(ANDNBSD, "andnbsd", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(BGT8, "bgt", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BGT16, "bgt", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BGE8, "bge", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BGE16, "bge", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BLT8, "blt", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BLT16, "blt", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BLE8, "ble", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BLE16, "ble", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BH8, "bh", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BH16, "bh", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BNL8, "bnl", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BNL16, "bnl", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BL8, "bl", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BL16, "bl", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BNH8, "bnh", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BNH16, "bnh", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BE8, "be", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BE16, "be", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BNE8, "bne", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BNE16, "bne", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BV8, "bv", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BV16, "bv", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BNV8, "bnv", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BNV16, "bnv", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BN8, "bn", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BN16, "bn", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BP8, "bp", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BP16, "bp", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BR8, "br", F4a, 0, 0)
+DEFINE_EASY_OPCODE(BR16, "br", F4b, 0, 0)
+DEFINE_EASY_OPCODE(BRK, "brk", F5, 0, 0)
+DEFINE_EASY_OPCODE(BRKV, "brkv", F5, 0, 0)
+DEFINE_EASY_OPCODE_EX(BSR, "bsr", F4b, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(CALL, "call", F1F2, 0, 2, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE(CAXI, "caxi", F1, 2, 2)
+DEFINE_EASY_OPCODE(CHKAR, "chkar", F1F2, 0, 0) // ?
+DEFINE_EASY_OPCODE(CHKAW, "chkaw", F1F2, 0, 0) // ?
+DEFINE_EASY_OPCODE(CHKAE, "chkae", F1F2, 0, 0)
+DEFINE_EASY_OPCODE(CHLVL, "chlvl", F1F2, 0, 0)
+DEFINE_EASY_OPCODE(CLR1, "clr1", F1F2, 2, 2)
+DEFINE_EASY_OPCODE(CLRTLB, "clrtlb", F3, 0, 0) // ?
+DEFINE_EASY_OPCODE(CLRTLBA, "clrtlba", F5, 0, 0)
+DEFINE_TRIPLE_OPCODE(CMP, "cmp", F1F2)
+DEFINE_EASY_OPCODE(CMPBFS, "cmpbfs", F7b, 0x82, 2)
+DEFINE_EASY_OPCODE(CMPBFZ, "cmpbfz", F7b, 0x82, 2)
+DEFINE_EASY_OPCODE(CMPBFL, "cmpbfl", F7b, 0x82, 2)
+DEFINE_DOUBLE_OPCODE(CMPC, "cmpc", F7a)
+DEFINE_DOUBLE_OPCODE(CMPCF, "cmpcf", F7a)
+DEFINE_DOUBLE_OPCODE(CMPCS, "cmpcs", F7a)
+DEFINE_FPU_OPCODE(CMPF, "cmpf", F2)
+DEFINE_EASY_OPCODE(CVTSL, "cvt.sl", F2, 0, 1)
+DEFINE_EASY_OPCODE(CVTLS, "cvt.ls", F2, 1, 0)
+DEFINE_EASY_OPCODE(CVTWS, "cvt.ws", F2, 2, 0)
+DEFINE_EASY_OPCODE(CVTWL, "cvt.wl", F2, 2, 1)
+DEFINE_EASY_OPCODE(CVTSW, "cvt.sw", F2, 0, 2)
+DEFINE_EASY_OPCODE(CVTLW, "cvt.lw", F2, 1, 2)
+DEFINE_EASY_OPCODE(CVTDPZ, "cvtd.pz", F7c, 0, 1)
+DEFINE_EASY_OPCODE(CVTDZP, "cvtd.zp", F7c, 1, 0)
+DEFINE_EASY_OPCODE_EX(DBGT, "dbgt", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBGE, "dbge", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBLT, "dbgt", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBLE, "dbge", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBH, "dbh", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBNL, "dbnl", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBL, "dbl", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBNH, "dbnh", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBE, "dbe", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBNE, "dbne", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBV, "dbe", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBNV, "dbne", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBN, "dbn", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBP, "dbp", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE_EX(DBR, "dbr", F6, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_TRIPLE_OPCODE(DEC, "dec", F3)
+DEFINE_EASY_OPCODE(DISPOSE, "dispose", F5, 0, 0)
+DEFINE_TRIPLE_OPCODE(DIV, "div", F1F2)
+DEFINE_FPU_OPCODE(DIVF, "divf", F2)
+DEFINE_TRIPLE_OPCODE(DIVU, "divu", F1F2)
+DEFINE_EASY_OPCODE(DIVX, "divx", F1F2, 2, 3)
+DEFINE_EASY_OPCODE(DIVUX, "divux", F1F2, 2, 3)
+DEFINE_EASY_OPCODE(EXTBFS, "extbfs", F7b, 0x82, 2)
+DEFINE_EASY_OPCODE(EXTBFZ, "extbfz", F7b, 0x82, 2)
+DEFINE_EASY_OPCODE(EXTBFL, "extbfl", F7b, 0x82, 2)
+DEFINE_EASY_OPCODE(GETATE, "getate", F1F2, 0, 3) // ?
+DEFINE_EASY_OPCODE(GETPSW, "getpsw", F3, 2, 0)
+DEFINE_EASY_OPCODE(GETPTE, "getpte", F1F2, 0, 2) // ?
+DEFINE_EASY_OPCODE(GETRA, "getra", F1F2, 0, 2) // ?
+DEFINE_EASY_OPCODE(HALT, "halt", F5, 0, 0)
+DEFINE_TRIPLE_OPCODE(IN, "in", F1F2)
+DEFINE_TRIPLE_OPCODE(INC, "inc", F3)
+DEFINE_EASY_OPCODE(INSBFL, "insbfl", F7c, 2, 0x82)
+DEFINE_EASY_OPCODE(INSBFR, "insbfr", F7c, 2, 0x82)
+DEFINE_EASY_OPCODE(JMP, "jmp", F3, 0, 0)
+DEFINE_EASY_OPCODE_EX(JSR, "jsr", F3, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE(LDPR, "ldpr", F1F2, 2, 2)
+DEFINE_EASY_OPCODE(LDTASK, "ldtask", F1F2, 2, 2)
+DEFINE_TRIPLE_OPCODE(MOV, "mov", F1F2)
+DEFINE_EASY_OPCODE(MOVBSU, "movbsu", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(MOVBSD, "movbsd", F7b, 0x80, 0x80)
+DEFINE_DOUBLE_OPCODE(MOVCU, "movcu", F7a)
+DEFINE_DOUBLE_OPCODE(MOVCD, "movcd", F7a)
+DEFINE_DOUBLE_OPCODE(MOVCFU, "movcfu", F7a)
+DEFINE_DOUBLE_OPCODE(MOVCFD, "movcfd", F7a)
+DEFINE_DOUBLE_OPCODE(MOVCS, "movcs", F7a)
+DEFINE_EASY_OPCODE(MOVD, "mov.d", F1F2, 3, 3)
+DEFINE_EASY_OPCODE(MOVEAB, "movea.b", F1F2, 0, 2)
+DEFINE_EASY_OPCODE(MOVEAH, "movea.h", F1F2, 1, 2)
+DEFINE_EASY_OPCODE(MOVEAW, "movea.w", F1F2, 2, 2)
+DEFINE_FPU_OPCODE(MOVF, "movf", F2)
+DEFINE_EASY_OPCODE(MOVSBH, "movs.bh", F1F2, 0, 1)
+DEFINE_EASY_OPCODE(MOVSBW, "movs.bw", F1F2, 0, 2)
+DEFINE_EASY_OPCODE(MOVSHW, "movs.hw", F1F2, 1, 2)
+DEFINE_EASY_OPCODE(MOVTHB, "movt.hb", F1F2, 1, 0)
+DEFINE_EASY_OPCODE(MOVTWB, "movt.wb", F1F2, 2, 0)
+DEFINE_EASY_OPCODE(MOVTWH, "movt.wh", F1F2, 2, 1)
+DEFINE_EASY_OPCODE(MOVZBH, "movz.bh", F1F2, 0, 1)
+DEFINE_EASY_OPCODE(MOVZBW, "movz.bw", F1F2, 0, 2)
+DEFINE_EASY_OPCODE(MOVZHW, "movz.hw", F1F2, 1, 2)
+DEFINE_TRIPLE_OPCODE(MUL, "mul", F1F2)
+DEFINE_FPU_OPCODE(MULF, "mulf", F2)
+DEFINE_TRIPLE_OPCODE(MULU, "mulu", F1F2)
+DEFINE_EASY_OPCODE(MULX, "mulx", F1F2, 2, 3)
+DEFINE_EASY_OPCODE(MULUX, "mulux", F1F2, 2, 3)
+DEFINE_TRIPLE_OPCODE(NEG, "neg", F1F2)
+DEFINE_FPU_OPCODE(NEGF, "negf", F2)
+DEFINE_EASY_OPCODE(NOP, "nop", F5, 0, 0)
+DEFINE_TRIPLE_OPCODE(NOT, "not", F1F2)
+DEFINE_EASY_OPCODE(NOT1, "not1", F1F2, 2, 2)
+DEFINE_EASY_OPCODE(NOTBSU, "notbsu", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(NOTBSD, "notbsd", F7b, 0x80, 0x80)
+DEFINE_TRIPLE_OPCODE(OR, "or", F1F2)
+DEFINE_EASY_OPCODE(ORBSU, "orbsu", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(ORBSD, "orbsd", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(ORNBSU, "ornbsu", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(ORNBSD, "ornbsd", F7b, 0x80, 0x80)
+DEFINE_TRIPLE_OPCODE(OUT, "out", F1F2)
+DEFINE_EASY_OPCODE(POP, "pop", F3, 2, 0)
+DEFINE_EASY_OPCODE(POPM, "popm", F3, 2, 0)
+DEFINE_EASY_OPCODE(PREPARE, "prepare", F3, 2, 0)
+DEFINE_EASY_OPCODE(PUSH, "push", F3, 2, 0)
+DEFINE_EASY_OPCODE(PUSHM, "pushm", F3, 2, 0)
+DEFINE_TRIPLE_OPCODE(REM, "rem", F1F2)
+DEFINE_TRIPLE_OPCODE(REMU, "remu", F1F2)
+DEFINE_EASY_OPCODE_EX(RET, "ret", F3, 2, 0, DASMFLAG_STEP_OUT)
+DEFINE_EASY_OPCODE_EX(RETIU, "retiu", F3, 1, 0, DASMFLAG_STEP_OUT)
+DEFINE_EASY_OPCODE_EX(RETIS, "retis", F3, 1, 0, DASMFLAG_STEP_OUT)
+DEFINE_EASY_OPCODE(ROTB, "rot.b", F1F2, 0, 0)
+DEFINE_EASY_OPCODE(ROTH, "rot.h", F1F2, 0, 1)
+DEFINE_EASY_OPCODE(ROTW, "rot.w", F1F2, 0, 2)
+DEFINE_EASY_OPCODE(ROTCB, "rotc.b", F1F2, 0, 0)
+DEFINE_EASY_OPCODE(ROTCH, "rotc.h", F1F2, 0, 1)
+DEFINE_EASY_OPCODE(ROTCW, "rotc.w", F1F2, 0, 2)
+DEFINE_EASY_OPCODE_EX(RSR, "rsr", F5, 0, 0, DASMFLAG_STEP_OUT)
+DEFINE_EASY_OPCODE(RVBIT, "rvbit", F1F2, 0, 0)
+DEFINE_EASY_OPCODE(RVBYT, "rvbyt", F1F2, 2, 2)
+DEFINE_EASY_OPCODE(SCH0BSU, "sch0bsu", F7b, 0x80, 2)
+DEFINE_EASY_OPCODE(SCH0BSD, "sch0bsd", F7b, 0x80, 2)
+DEFINE_EASY_OPCODE(SCH1BSU, "sch1bsu", F7b, 0x80, 2)
+DEFINE_EASY_OPCODE(SCH1BSD, "sch1bsd", F7b, 0x80, 2)
+DEFINE_EASY_OPCODE(SCHCUB, "schcu.b", F7b, 0, 0)
+DEFINE_EASY_OPCODE(SCHCDB, "schcd.b", F7b, 0, 0)
+DEFINE_EASY_OPCODE(SCHCUH, "schcu.h", F7b, 1, 1)
+DEFINE_EASY_OPCODE(SCHCDH, "schcd.h", F7b, 1, 1)
+DEFINE_EASY_OPCODE(SCLFS, "sclf.s", F2, 1, 2)
+DEFINE_EASY_OPCODE(SCLFL, "sclf.l", F2, 1, 2)
+DEFINE_EASY_OPCODE(SET1, "set1", F1F2, 2, 2)
+DEFINE_EASY_OPCODE(SETF, "setf", F1F2, 0, 0)
+DEFINE_EASY_OPCODE(SHAB, "sha.b", F1F2, 0, 0)
+DEFINE_EASY_OPCODE(SHAH, "sha.h", F1F2, 0, 1)
+DEFINE_EASY_OPCODE(SHAW, "sha.w", F1F2, 0, 2)
+DEFINE_EASY_OPCODE(SHLB, "shl.b", F1F2, 0, 0)
+DEFINE_EASY_OPCODE(SHLH, "shl.h", F1F2, 0, 1)
+DEFINE_EASY_OPCODE(SHLW, "shl.w", F1F2, 0, 2)
+DEFINE_EASY_OPCODE(SKPCUB, "skpcu.b", F7b, 0, 0)
+DEFINE_EASY_OPCODE(SKPCDB, "skpcd.b", F7b, 0, 0)
+DEFINE_EASY_OPCODE(SKPCUH, "skpcu.h", F7b, 1, 1)
+DEFINE_EASY_OPCODE(SKPCDH, "skpcd.h", F7b, 1, 1)
+DEFINE_EASY_OPCODE(STPR, "stpr", F1F2, 2, 2)
+DEFINE_EASY_OPCODE(STTASK, "sttask", F3, 2, 0)
+DEFINE_TRIPLE_OPCODE(SUB, "sub", F1F2)
+DEFINE_TRIPLE_OPCODE(SUBC, "subc", F1F2)
+DEFINE_EASY_OPCODE(SUBDC, "subdc", F7c, 0, 0)
+DEFINE_EASY_OPCODE(SUBRDC, "subrdc", F7c, 0, 0)
+DEFINE_FPU_OPCODE(SUBF, "subf", F2)
+DEFINE_EASY_OPCODE(TASI, "tasi", F3, 0, 0)
+DEFINE_EASY_OPCODE(TB, "tb", F6, 0, 0)
+DEFINE_TRIPLE_OPCODE(TEST, "test", F3)
+DEFINE_EASY_OPCODE(TEST1, "test1", F1F2, 2, 2)
+DEFINE_EASY_OPCODE_EX(TRAP, "trap", F3, 0, 0, DASMFLAG_STEP_OVER)
+DEFINE_EASY_OPCODE(TRAPFL, "trapfl", F5, 0, 0)
+DEFINE_EASY_OPCODE(UPDATE, "update", F1F2, 0, 3) // ?
+DEFINE_EASY_OPCODE(UPDPSWH, "updpsw.h", F1F2, 2, 2)
+DEFINE_EASY_OPCODE(UPDPSWW, "updpsw.w", F1F2, 2, 2)
+DEFINE_EASY_OPCODE(UPDPTE, "updpte", F1F2, 0, 2) // ?
+DEFINE_TRIPLE_OPCODE(XCH, "xch", F1)
+DEFINE_TRIPLE_OPCODE(XOR, "xor", F1F2)
+DEFINE_EASY_OPCODE(XORBSU, "xorbsu", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(XORBSD, "xorbsd", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(XORNBSU, "xornbsu", F7b, 0x80, 0x80)
+DEFINE_EASY_OPCODE(XORNBSD, "xornbsd", F7b, 0x80, 0x80)
+
+static int (*const dasm_optable_58[32])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x00 */ dopCMPCB,
+ /* 0x01 */ dopCMPCFB,
+ /* 0x02 */ dopCMPCSB,
+ /* 0x03 */ dop58UNHANDLED,
+ /* 0x04 */ dop58UNHANDLED,
+ /* 0x05 */ dop58UNHANDLED,
+ /* 0x06 */ dop58UNHANDLED,
+ /* 0x07 */ dop58UNHANDLED,
+ /* 0x08 */ dopMOVCUB,
+ /* 0x09 */ dopMOVCDB,
+ /* 0x0A */ dopMOVCFUB,
+ /* 0x0B */ dopMOVCFDB,
+ /* 0x0C */ dopMOVCSB,
+ /* 0x0D */ dop58UNHANDLED,
+ /* 0x0E */ dop58UNHANDLED,
+ /* 0x0F */ dop58UNHANDLED,
+ /* 0x10 */ dop58UNHANDLED,
+ /* 0x11 */ dop58UNHANDLED,
+ /* 0x12 */ dop58UNHANDLED,
+ /* 0x13 */ dop58UNHANDLED,
+ /* 0x14 */ dop58UNHANDLED,
+ /* 0x15 */ dop58UNHANDLED,
+ /* 0x16 */ dop58UNHANDLED,
+ /* 0x17 */ dop58UNHANDLED,
+ /* 0x18 */ dopSCHCUB,
+ /* 0x19 */ dopSCHCDB,
+ /* 0x1A */ dopSKPCUB,
+ /* 0x1B */ dopSKPCDB,
+ /* 0x1C */ dop58UNHANDLED,
+ /* 0x1D */ dop58UNHANDLED,
+ /* 0x1E */ dop58UNHANDLED,
+ /* 0x1F */ dop58UNHANDLED
+};
+
+static int (*const dasm_optable_59[32])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x00 */ dopADDDC,
+ /* 0x01 */ dopSUBDC,
+ /* 0x02 */ dopSUBRDC,
+ /* 0x03 */ dop59UNHANDLED,
+ /* 0x04 */ dop59UNHANDLED,
+ /* 0x05 */ dop59UNHANDLED,
+ /* 0x06 */ dop59UNHANDLED,
+ /* 0x07 */ dop59UNHANDLED,
+ /* 0x08 */ dop59UNHANDLED,
+ /* 0x09 */ dop59UNHANDLED,
+ /* 0x0A */ dop59UNHANDLED,
+ /* 0x0B */ dop59UNHANDLED,
+ /* 0x0C */ dop59UNHANDLED,
+ /* 0x0D */ dop59UNHANDLED,
+ /* 0x0E */ dop59UNHANDLED,
+ /* 0x0F */ dop59UNHANDLED,
+ /* 0x10 */ dopCVTDPZ,
+ /* 0x11 */ dop59UNHANDLED,
+ /* 0x12 */ dop59UNHANDLED,
+ /* 0x13 */ dop59UNHANDLED,
+ /* 0x14 */ dop59UNHANDLED,
+ /* 0x15 */ dop59UNHANDLED,
+ /* 0x16 */ dop59UNHANDLED,
+ /* 0x17 */ dop59UNHANDLED,
+ /* 0x18 */ dopCVTDZP,
+ /* 0x19 */ dop59UNHANDLED,
+ /* 0x1A */ dop59UNHANDLED,
+ /* 0x1B */ dop59UNHANDLED,
+ /* 0x1C */ dop59UNHANDLED,
+ /* 0x1D */ dop59UNHANDLED,
+ /* 0x1E */ dop59UNHANDLED,
+ /* 0x1F */ dop59UNHANDLED
+};
+
+static int (*const dasm_optable_5A[32])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x00 */ dopCMPCH,
+ /* 0x01 */ dopCMPCFH,
+ /* 0x02 */ dopCMPCSH,
+ /* 0x03 */ dop5AUNHANDLED,
+ /* 0x04 */ dop5AUNHANDLED,
+ /* 0x05 */ dop5AUNHANDLED,
+ /* 0x06 */ dop5AUNHANDLED,
+ /* 0x07 */ dop5AUNHANDLED,
+ /* 0x08 */ dopMOVCUH,
+ /* 0x09 */ dopMOVCDH,
+ /* 0x0A */ dopMOVCFUH,
+ /* 0x0B */ dopMOVCFDH,
+ /* 0x0C */ dopMOVCSH,
+ /* 0x0D */ dop5AUNHANDLED,
+ /* 0x0E */ dop5AUNHANDLED,
+ /* 0x0F */ dop5AUNHANDLED,
+ /* 0x10 */ dop5AUNHANDLED,
+ /* 0x11 */ dop5AUNHANDLED,
+ /* 0x12 */ dop5AUNHANDLED,
+ /* 0x13 */ dop5AUNHANDLED,
+ /* 0x14 */ dop5AUNHANDLED,
+ /* 0x15 */ dop5AUNHANDLED,
+ /* 0x16 */ dop5AUNHANDLED,
+ /* 0x17 */ dop5AUNHANDLED,
+ /* 0x18 */ dopSCHCUH,
+ /* 0x19 */ dopSCHCDH,
+ /* 0x1A */ dopSKPCUH,
+ /* 0x1B */ dopSKPCDH,
+ /* 0x1C */ dop5AUNHANDLED,
+ /* 0x1D */ dop5AUNHANDLED,
+ /* 0x1E */ dop5AUNHANDLED,
+ /* 0x1F */ dop5AUNHANDLED
+};
+
+static int (*const dasm_optable_5B[32])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x00 */ dopSCH0BSU,
+ /* 0x01 */ dopSCH0BSD,
+ /* 0x02 */ dopSCH1BSU,
+ /* 0x03 */ dopSCH1BSD,
+ /* 0x04 */ dop5BUNHANDLED,
+ /* 0x05 */ dop5BUNHANDLED,
+ /* 0x06 */ dop5BUNHANDLED,
+ /* 0x07 */ dop5BUNHANDLED,
+ /* 0x08 */ dopMOVBSU,
+ /* 0x09 */ dopMOVBSD,
+ /* 0x0A */ dopNOTBSU,
+ /* 0x0B */ dopNOTBSD,
+ /* 0x0C */ dop5BUNHANDLED,
+ /* 0x0D */ dop5BUNHANDLED,
+ /* 0x0E */ dop5BUNHANDLED,
+ /* 0x0F */ dop5BUNHANDLED,
+ /* 0x10 */ dopANDBSU,
+ /* 0x11 */ dopANDBSD,
+ /* 0x12 */ dopANDNBSU,
+ /* 0x13 */ dopANDNBSD,
+ /* 0x14 */ dopORBSU,
+ /* 0x15 */ dopORBSD,
+ /* 0x16 */ dopORNBSU,
+ /* 0x17 */ dopORNBSD,
+ /* 0x18 */ dopXORBSU,
+ /* 0x19 */ dopXORBSD,
+ /* 0x1A */ dopXORNBSU,
+ /* 0x1B */ dopXORNBSD,
+ /* 0x1C */ dop5BUNHANDLED,
+ /* 0x1D */ dop5BUNHANDLED,
+ /* 0x1E */ dop5BUNHANDLED,
+ /* 0x1F */ dop5BUNHANDLED
+};
+
+static int (*const dasm_optable_5C[32])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x00 */ dopCMPFS,
+ /* 0x01 */ dop5CUNHANDLED,
+ /* 0x02 */ dop5CUNHANDLED,
+ /* 0x03 */ dop5CUNHANDLED,
+ /* 0x04 */ dop5CUNHANDLED,
+ /* 0x05 */ dop5CUNHANDLED,
+ /* 0x06 */ dop5CUNHANDLED,
+ /* 0x07 */ dop5CUNHANDLED,
+ /* 0x08 */ dopMOVFS,
+ /* 0x09 */ dopNEGFS,
+ /* 0x0A */ dopABSFS,
+ /* 0x0B */ dop5CUNHANDLED,
+ /* 0x0C */ dop5CUNHANDLED,
+ /* 0x0D */ dop5CUNHANDLED,
+ /* 0x0E */ dop5CUNHANDLED,
+ /* 0x0F */ dop5CUNHANDLED,
+ /* 0x10 */ dopSCLFS,
+ /* 0x11 */ dop5CUNHANDLED,
+ /* 0x12 */ dop5CUNHANDLED,
+ /* 0x13 */ dop5CUNHANDLED,
+ /* 0x14 */ dop5CUNHANDLED,
+ /* 0x15 */ dop5CUNHANDLED,
+ /* 0x16 */ dop5CUNHANDLED,
+ /* 0x17 */ dop5CUNHANDLED,
+ /* 0x18 */ dopADDFS,
+ /* 0x19 */ dopSUBFS,
+ /* 0x1A */ dopMULFS,
+ /* 0x1B */ dopDIVFS,
+ /* 0x1C */ dop5CUNHANDLED,
+ /* 0x1D */ dop5CUNHANDLED,
+ /* 0x1E */ dop5CUNHANDLED,
+ /* 0x1F */ dop5CUNHANDLED
+};
+
+static int (*const dasm_optable_5D[32])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x00 */ dopCMPBFS,
+ /* 0x01 */ dopCMPBFZ,
+ /* 0x02 */ dopCMPBFL,
+ /* 0x03 */ dop5DUNHANDLED,
+ /* 0x04 */ dop5DUNHANDLED,
+ /* 0x05 */ dop5DUNHANDLED,
+ /* 0x06 */ dop5DUNHANDLED,
+ /* 0x07 */ dop5DUNHANDLED,
+ /* 0x08 */ dopEXTBFS,
+ /* 0x09 */ dopEXTBFZ,
+ /* 0x0A */ dopEXTBFL,
+ /* 0x0B */ dop5DUNHANDLED,
+ /* 0x0C */ dop5DUNHANDLED,
+ /* 0x0D */ dop5DUNHANDLED,
+ /* 0x0E */ dop5DUNHANDLED,
+ /* 0x0F */ dop5DUNHANDLED,
+ /* 0x10 */ dop5DUNHANDLED,
+ /* 0x11 */ dop5DUNHANDLED,
+ /* 0x12 */ dop5DUNHANDLED,
+ /* 0x13 */ dop5DUNHANDLED,
+ /* 0x14 */ dop5DUNHANDLED,
+ /* 0x15 */ dop5DUNHANDLED,
+ /* 0x16 */ dop5DUNHANDLED,
+ /* 0x17 */ dop5DUNHANDLED,
+ /* 0x18 */ dopINSBFR,
+ /* 0x19 */ dopINSBFL,
+ /* 0x1A */ dop5DUNHANDLED,
+ /* 0x1B */ dop5DUNHANDLED,
+ /* 0x1C */ dop5DUNHANDLED,
+ /* 0x1D */ dop5DUNHANDLED,
+ /* 0x1E */ dop5DUNHANDLED,
+ /* 0x1F */ dop5DUNHANDLED
+};
+
+static int (*const dasm_optable_5E[32])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x00 */ dopCMPFL,
+ /* 0x01 */ dop5EUNHANDLED,
+ /* 0x02 */ dop5EUNHANDLED,
+ /* 0x03 */ dop5EUNHANDLED,
+ /* 0x04 */ dop5EUNHANDLED,
+ /* 0x05 */ dop5EUNHANDLED,
+ /* 0x06 */ dop5EUNHANDLED,
+ /* 0x07 */ dop5EUNHANDLED,
+ /* 0x08 */ dopMOVFL,
+ /* 0x09 */ dopNEGFL,
+ /* 0x0A */ dopABSFL,
+ /* 0x0B */ dop5EUNHANDLED,
+ /* 0x0C */ dop5EUNHANDLED,
+ /* 0x0D */ dop5EUNHANDLED,
+ /* 0x0E */ dop5EUNHANDLED,
+ /* 0x0F */ dop5EUNHANDLED,
+ /* 0x10 */ dopSCLFL,
+ /* 0x11 */ dop5EUNHANDLED,
+ /* 0x12 */ dop5EUNHANDLED,
+ /* 0x13 */ dop5EUNHANDLED,
+ /* 0x14 */ dop5EUNHANDLED,
+ /* 0x15 */ dop5EUNHANDLED,
+ /* 0x16 */ dop5EUNHANDLED,
+ /* 0x17 */ dop5EUNHANDLED,
+ /* 0x18 */ dopADDFL,
+ /* 0x19 */ dopSUBFL,
+ /* 0x1A */ dopMULFL,
+ /* 0x1B */ dopDIVFL,
+ /* 0x1C */ dop5EUNHANDLED,
+ /* 0x1D */ dop5EUNHANDLED,
+ /* 0x1E */ dop5EUNHANDLED,
+ /* 0x1F */ dop5EUNHANDLED
+};
+
+static int (*const dasm_optable_5F[32])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x00 */ dopCVTWS,
+ /* 0x01 */ dopCVTSW,
+ /* 0x02 */ dop5FUNHANDLED,
+ /* 0x03 */ dop5FUNHANDLED,
+ /* 0x04 */ dop5FUNHANDLED,
+ /* 0x05 */ dop5FUNHANDLED,
+ /* 0x06 */ dop5FUNHANDLED,
+ /* 0x07 */ dop5FUNHANDLED,
+ /* 0x08 */ dopCVTLS,
+ /* 0x09 */ dopCVTLW,
+ /* 0x0A */ dop5FUNHANDLED,
+ /* 0x0B */ dop5FUNHANDLED,
+ /* 0x0C */ dop5FUNHANDLED,
+ /* 0x0D */ dop5FUNHANDLED,
+ /* 0x0E */ dop5FUNHANDLED,
+ /* 0x0F */ dop5FUNHANDLED,
+ /* 0x10 */ dopCVTSL,
+ /* 0x11 */ dopCVTWL,
+ /* 0x12 */ dop5FUNHANDLED,
+ /* 0x13 */ dop5FUNHANDLED,
+ /* 0x14 */ dop5FUNHANDLED,
+ /* 0x15 */ dop5FUNHANDLED,
+ /* 0x16 */ dop5FUNHANDLED,
+ /* 0x17 */ dop5FUNHANDLED,
+ /* 0x18 */ dop5FUNHANDLED,
+ /* 0x19 */ dop5FUNHANDLED,
+ /* 0x1A */ dop5FUNHANDLED,
+ /* 0x1B */ dop5FUNHANDLED,
+ /* 0x1C */ dop5FUNHANDLED,
+ /* 0x1D */ dop5FUNHANDLED,
+ /* 0x1E */ dop5FUNHANDLED,
+ /* 0x1F */ dop5FUNHANDLED
+};
+
+static int (*const dasm_optable_C6[8])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x0 */ dopDBV,
+ /* 0x1 */ dopDBL,
+ /* 0x2 */ dopDBE,
+ /* 0x3 */ dopDBNH,
+ /* 0x4 */ dopDBN,
+ /* 0x5 */ dopDBR,
+ /* 0x6 */ dopDBLT,
+ /* 0x7 */ dopDBLE
+};
+
+static int (*const dasm_optable_C7[8])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x0 */ dopDBNV,
+ /* 0x1 */ dopDBNL,
+ /* 0x2 */ dopDBNE,
+ /* 0x3 */ dopDBH,
+ /* 0x4 */ dopDBP,
+ /* 0x5 */ dopTB,
+ /* 0x6 */ dopDBGE,
+ /* 0x7 */ dopDBGT
+};
+
+static int dop58(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_58[readop(pc) & 0x1f](ipc, pc, out);
+}
+
+static int dop59(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_59[readop(pc) & 0x1f](ipc, pc, out);
+}
+
+static int dop5A(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_5A[readop(pc) & 0x1f](ipc, pc, out);
+}
+
+static int dop5B(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_5B[readop(pc) & 0x1f](ipc, pc, out);
+}
+
+static int dop5C(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_5C[readop(pc) & 0x1f](ipc, pc, out);
+}
+
+static int dop5D(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_5D[readop(pc) & 0x1f](ipc, pc, out);
+}
+
+static int dop5E(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_5E[readop(pc) & 0x1f](ipc, pc, out);
+}
+
+static int dop5F(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_5F[readop(pc) & 0x1f](ipc, pc, out);
+}
+
+static int dopC6(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_C6[readop(pc) >> 5](ipc, pc, out);
+}
+
+static int dopC7(unsigned ipc, unsigned pc, char *out)
+{
+ return dasm_optable_C7[readop(pc) >> 5](ipc, pc, out);
+}
+
+static int (*const dasm_optable[256])(unsigned ipc, unsigned pc, char *out) =
+{
+ /* 0x00 */ dopHALT,
+ /* 0x01 */ dopLDTASK,
+ /* 0x02 */ dopSTPR,
+ /* 0x03 */ dopGETRA,
+ /* 0x04 */ dopGETPTE,
+ /* 0x05 */ dopGETATE,
+ /* 0x06 */ dopUNHANDLED,
+ /* 0x07 */ dopUNHANDLED,
+ /* 0x08 */ dopRVBIT,
+ /* 0x09 */ dopMOVB,
+ /* 0x0A */ dopMOVSBH,
+ /* 0x0B */ dopMOVZBH,
+ /* 0x0C */ dopMOVSBW,
+ /* 0x0D */ dopMOVZBW,
+ /* 0x0E */ dopUNHANDLED,
+ /* 0x0F */ dopUNHANDLED,
+ /* 0x10 */ dopCLRTLBA,
+ /* 0x11 */ dopUNHANDLED,
+ /* 0x12 */ dopLDPR,
+ /* 0x13 */ dopUPDPSWW,
+ /* 0x14 */ dopUPDPTE,
+ /* 0x15 */ dopUPDATE,
+ /* 0x16 */ dopUNHANDLED,
+ /* 0x17 */ dopUNHANDLED,
+ /* 0x18 */ dopUNHANDLED,
+ /* 0x19 */ dopMOVTHB,
+ /* 0x1A */ dopUNHANDLED,
+ /* 0x1B */ dopMOVH,
+ /* 0x1C */ dopMOVSHW,
+ /* 0x1D */ dopMOVZHW,
+ /* 0x1E */ dopUNHANDLED,
+ /* 0x1F */ dopUNHANDLED,
+ /* 0x20 */ dopINB,
+ /* 0x21 */ dopOUTB,
+ /* 0x22 */ dopINH,
+ /* 0x23 */ dopOUTH,
+ /* 0x24 */ dopINW,
+ /* 0x25 */ dopOUTW,
+ /* 0x26 */ dopUNHANDLED,
+ /* 0x27 */ dopUNHANDLED,
+ /* 0x28 */ dopUNHANDLED,
+ /* 0x29 */ dopMOVTWB,
+ /* 0x2A */ dopUNHANDLED,
+ /* 0x2B */ dopMOVTWH,
+ /* 0x2C */ dopRVBYT,
+ /* 0x2D */ dopMOVW,
+ /* 0x2E */ dopUNHANDLED,
+ /* 0x2F */ dopUNHANDLED,
+ /* 0x30 */ dopUNHANDLED,
+ /* 0x31 */ dopUNHANDLED,
+ /* 0x32 */ dopUNHANDLED,
+ /* 0x33 */ dopUNHANDLED,
+ /* 0x34 */ dopUNHANDLED,
+ /* 0x35 */ dopUNHANDLED,
+ /* 0x36 */ dopUNHANDLED,
+ /* 0x37 */ dopUNHANDLED,
+ /* 0x38 */ dopNOTB,
+ /* 0x39 */ dopNEGB,
+ /* 0x3A */ dopNOTH,
+ /* 0x3B */ dopNEGH,
+ /* 0x3C */ dopNOTW,
+ /* 0x3D */ dopNEGW,
+ /* 0x3E */ dopUNHANDLED,
+ /* 0x3F */ dopMOVD,
+ /* 0x40 */ dopMOVEAB,
+ /* 0x41 */ dopXCHB,
+ /* 0x42 */ dopMOVEAH,
+ /* 0x43 */ dopXCHH,
+ /* 0x44 */ dopMOVEAW,
+ /* 0x45 */ dopXCHW,
+ /* 0x46 */ dopUNHANDLED,
+ /* 0x47 */ dopSETF,
+ /* 0x48 */ dopBSR,
+ /* 0x49 */ dopCALL,
+ /* 0x4A */ dopUPDPSWH,
+ /* 0x4B */ dopCHLVL,
+ /* 0x4C */ dopCAXI,
+ /* 0x4D */ dopCHKAR,
+ /* 0x4E */ dopCHKAW,
+ /* 0x4F */ dopCHKAE,
+ /* 0x50 */ dopREMB,
+ /* 0x51 */ dopREMUB,
+ /* 0x52 */ dopREMH,
+ /* 0x53 */ dopREMUH,
+ /* 0x54 */ dopREMW,
+ /* 0x55 */ dopREMUW,
+ /* 0x56 */ dopUNHANDLED,
+ /* 0x57 */ dopUNHANDLED,
+ /* 0x58 */ dop58,
+ /* 0x59 */ dop59,
+ /* 0x5A */ dop5A,
+ /* 0x5B */ dop5B,
+ /* 0x5C */ dop5C,
+ /* 0x5D */ dop5D,
+ /* 0x5E */ dop5E,
+ /* 0x5F */ dop5F,
+ /* 0x60 */ dopBV8,
+ /* 0x61 */ dopBNV8,
+ /* 0x62 */ dopBL8,
+ /* 0x63 */ dopBNL8,
+ /* 0x64 */ dopBE8,
+ /* 0x65 */ dopBNE8,
+ /* 0x66 */ dopBNH8,
+ /* 0x67 */ dopBH8,
+ /* 0x68 */ dopBN8,
+ /* 0x69 */ dopBP8,
+ /* 0x6A */ dopBR8,
+ /* 0x6B */ dopUNHANDLED,
+ /* 0x6C */ dopBLT8,
+ /* 0x6D */ dopBGE8,
+ /* 0x6E */ dopBLE8,
+ /* 0x6F */ dopBGT8,
+ /* 0x70 */ dopBV16,
+ /* 0x71 */ dopBNV16,
+ /* 0x72 */ dopBL16,
+ /* 0x73 */ dopBNL16,
+ /* 0x74 */ dopBE16,
+ /* 0x75 */ dopBNE16,
+ /* 0x76 */ dopBNH16,
+ /* 0x77 */ dopBH16,
+ /* 0x78 */ dopBN16,
+ /* 0x79 */ dopBP16,
+ /* 0x7A */ dopBR16,
+ /* 0x7B */ dopUNHANDLED,
+ /* 0x7C */ dopBLT16,
+ /* 0x7D */ dopBGE16,
+ /* 0x7E */ dopBLE16,
+ /* 0x7F */ dopBGT16,
+ /* 0x80 */ dopADDB,
+ /* 0x81 */ dopMULB,
+ /* 0x82 */ dopADDH,
+ /* 0x83 */ dopMULH,
+ /* 0x84 */ dopADDW,
+ /* 0x85 */ dopMULW,
+ /* 0x86 */ dopMULX,
+ /* 0x87 */ dopTEST1,
+ /* 0x88 */ dopORB,
+ /* 0x89 */ dopROTB,
+ /* 0x8A */ dopORH,
+ /* 0x8B */ dopROTH,
+ /* 0x8C */ dopORW,
+ /* 0x8D */ dopROTW,
+ /* 0x8E */ dopUNHANDLED,
+ /* 0x8F */ dopUNHANDLED,
+ /* 0x90 */ dopADDCB,
+ /* 0x91 */ dopMULUB,
+ /* 0x92 */ dopADDCH,
+ /* 0x93 */ dopMULUH,
+ /* 0x94 */ dopADDCW,
+ /* 0x95 */ dopMULUW,
+ /* 0x96 */ dopMULUX,
+ /* 0x97 */ dopSET1,
+ /* 0x98 */ dopSUBCB,
+ /* 0x99 */ dopROTCB,
+ /* 0x9A */ dopSUBCH,
+ /* 0x9B */ dopROTCH,
+ /* 0x9C */ dopSUBCW,
+ /* 0x9D */ dopROTCW,
+ /* 0x9E */ dopUNHANDLED,
+ /* 0x9F */ dopUNHANDLED,
+ /* 0xA0 */ dopANDB,
+ /* 0xA1 */ dopDIVB,
+ /* 0xA2 */ dopANDH,
+ /* 0xA3 */ dopDIVH,
+ /* 0xA4 */ dopANDW,
+ /* 0xA5 */ dopDIVW,
+ /* 0xA6 */ dopDIVX,
+ /* 0xA7 */ dopCLR1,
+ /* 0xA8 */ dopSUBB,
+ /* 0xA9 */ dopSHLB,
+ /* 0xAA */ dopSUBH,
+ /* 0xAB */ dopSHLH,
+ /* 0xAC */ dopSUBW,
+ /* 0xAD */ dopSHLW,
+ /* 0xAE */ dopUNHANDLED,
+ /* 0xAF */ dopUNHANDLED,
+ /* 0xB0 */ dopXORB,
+ /* 0xB1 */ dopDIVUB,
+ /* 0xB2 */ dopXORH,
+ /* 0xB3 */ dopDIVUH,
+ /* 0xB4 */ dopXORW,
+ /* 0xB5 */ dopDIVUW,
+ /* 0xB6 */ dopDIVUX,
+ /* 0xB7 */ dopNOT1,
+ /* 0xB8 */ dopCMPB,
+ /* 0xB9 */ dopSHAB,
+ /* 0xBA */ dopCMPH,
+ /* 0xBB */ dopSHAH,
+ /* 0xBC */ dopCMPW,
+ /* 0xBD */ dopSHAW,
+ /* 0xBE */ dopUNHANDLED,
+ /* 0xBF */ dopUNHANDLED,
+ /* 0xC0 */ dopUNHANDLED,
+ /* 0xC1 */ dopUNHANDLED,
+ /* 0xC2 */ dopUNHANDLED,
+ /* 0xC3 */ dopUNHANDLED,
+ /* 0xC4 */ dopUNHANDLED,
+ /* 0xC5 */ dopUNHANDLED,
+ /* 0xC6 */ dopC6,
+ /* 0xC7 */ dopC7,
+ /* 0xC8 */ dopBRK,
+ /* 0xC9 */ dopBRKV,
+ /* 0xCA */ dopRSR,
+ /* 0xCB */ dopTRAPFL,
+ /* 0xCC */ dopDISPOSE,
+ /* 0xCD */ dopNOP,
+ /* 0xCE */ dopUNHANDLED,
+ /* 0xCF */ dopUNHANDLED,
+ /* 0xD0 */ dopDECB,
+ /* 0xD1 */ dopDECB,
+ /* 0xD2 */ dopDECH,
+ /* 0xD3 */ dopDECH,
+ /* 0xD4 */ dopDECW,
+ /* 0xD5 */ dopDECW,
+ /* 0xD6 */ dopJMP,
+ /* 0xD7 */ dopJMP,
+ /* 0xD8 */ dopINCB,
+ /* 0xD9 */ dopINCB,
+ /* 0xDA */ dopINCH,
+ /* 0xDB */ dopINCH,
+ /* 0xDC */ dopINCW,
+ /* 0xDD */ dopINCW,
+ /* 0xDE */ dopPREPARE,
+ /* 0xDF */ dopPREPARE,
+ /* 0xE0 */ dopTASI,
+ /* 0xE1 */ dopTASI,
+ /* 0xE2 */ dopRET,
+ /* 0xE3 */ dopRET,
+ /* 0xE4 */ dopPOPM,
+ /* 0xE5 */ dopPOPM,
+ /* 0xE6 */ dopPOP,
+ /* 0xE7 */ dopPOP,
+ /* 0xE8 */ dopJSR,
+ /* 0xE9 */ dopJSR,
+ /* 0xEA */ dopRETIU,
+ /* 0xEB */ dopRETIU,
+ /* 0xEC */ dopPUSHM,
+ /* 0xED */ dopPUSHM,
+ /* 0xEE */ dopPUSH,
+ /* 0xEF */ dopPUSH,
+ /* 0xF0 */ dopTESTB,
+ /* 0xF1 */ dopTESTB,
+ /* 0xF2 */ dopTESTH,
+ /* 0xF3 */ dopTESTH,
+ /* 0xF4 */ dopTESTW,
+ /* 0xF5 */ dopTESTW,
+ /* 0xF6 */ dopGETPSW,
+ /* 0xF7 */ dopGETPSW,
+ /* 0xF8 */ dopTRAP,
+ /* 0xF9 */ dopTRAP,
+ /* 0xFA */ dopRETIS,
+ /* 0xFB */ dopRETIS,
+ /* 0xFC */ dopSTTASK,
+ /* 0xFD */ dopSTTASK,
+ /* 0xFE */ dopCLRTLB,
+ /* 0xFF */ dopCLRTLB
+};
+
+#ifdef MAME_DEBUG
+offs_t v60_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ rombase = oprom;
+ pcbase = pc;
+ return dasm_optable[oprom[0]](pc, pc+1, buffer) | DASMFLAG_SUPPORTED;
+}
+
+offs_t v70_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ rombase = oprom;
+ pcbase = pc;
+ return dasm_optable[oprom[0]](pc, pc+1, buffer) | DASMFLAG_SUPPORTED;
+}
+#endif
diff --git a/src/emu/cpu/v60/v60mem.c b/src/emu/cpu/v60/v60mem.c
new file mode 100644
index 00000000000..c29a1a81f33
--- /dev/null
+++ b/src/emu/cpu/v60/v60mem.c
@@ -0,0 +1,388 @@
+/****************************************************************/
+/* Structure defining all callbacks for different architectures */
+/****************************************************************/
+
+struct cpu_info {
+ UINT8 (*mr8) (offs_t address);
+ void (*mw8) (offs_t address, UINT8 data);
+ UINT16 (*mr16)(offs_t address);
+ void (*mw16)(offs_t address, UINT16 data);
+ UINT32 (*mr32)(offs_t address);
+ void (*mw32)(offs_t address, UINT32 data);
+ UINT8 (*pr8) (offs_t address);
+ void (*pw8) (offs_t address, UINT8 data);
+ UINT16 (*pr16)(offs_t address);
+ void (*pw16)(offs_t address, UINT16 data);
+ UINT32 (*pr32)(offs_t address);
+ void (*pw32)(offs_t address, UINT32 data);
+ UINT8 (*or8) (offs_t address);
+ UINT16 (*or16)(offs_t address);
+ UINT32 (*or32)(offs_t address);
+ void (*chpc)(offs_t newpc);
+ UINT32 start_pc;
+};
+
+
+
+/*****************************************************************/
+/* Memory accesses for 16-bit data bus, 24-bit address bus (V60) */
+/*****************************************************************/
+
+#define MemRead8_16 program_read_byte_16le
+#define MemWrite8_16 program_write_byte_16le
+
+static UINT16 MemRead16_16(offs_t address)
+{
+ if (!(address & 1))
+ return program_read_word_16le(address);
+ else
+ {
+ UINT16 result = program_read_byte_16le(address);
+ return result | program_read_byte_16le(address + 1) << 8;
+ }
+}
+
+static void MemWrite16_16(offs_t address, UINT16 data)
+{
+ if (!(address & 1))
+ program_write_word_16le(address, data);
+ else
+ {
+ program_write_byte_16le(address, data);
+ program_write_byte_16le(address + 1, data >> 8);
+ }
+}
+
+static UINT32 MemRead32_16(offs_t address)
+{
+ if (!(address & 1))
+ {
+ UINT32 result = program_read_word_16le(address);
+ return result | (program_read_word_16le(address + 2) << 16);
+ }
+ else
+ {
+ UINT32 result = program_read_byte_16le(address);
+ result |= program_read_word_16le(address + 1) << 8;
+ return result | program_read_byte_16le(address + 3) << 24;
+ }
+}
+
+static void MemWrite32_16(offs_t address, UINT32 data)
+{
+ if (!(address & 1))
+ {
+ program_write_word_16le(address, data);
+ program_write_word_16le(address + 2, data >> 16);
+ }
+ else
+ {
+ program_write_byte_16le(address, data);
+ program_write_word_16le(address + 1, data >> 8);
+ program_write_byte_16le(address + 3, data >> 24);
+ }
+}
+
+
+/***************************************************************/
+/* Port accesses for 16-bit data bus, 24-bit address bus (V60) */
+/***************************************************************/
+
+#define PortRead8_16 io_read_byte_16le
+#define PortWrite8_16 io_write_byte_16le
+
+static UINT16 PortRead16_16(offs_t address)
+{
+ if (!(address & 1))
+ return io_read_word_16le(address);
+ else
+ {
+ UINT16 result = io_read_byte_16le(address);
+ return result | io_read_byte_16le(address + 1) << 8;
+ }
+}
+
+static void PortWrite16_16(offs_t address, UINT16 data)
+{
+ if (!(address & 1))
+ io_write_word_16le(address, data);
+ else
+ {
+ io_write_byte_16le(address, data);
+ io_write_byte_16le(address + 1, data >> 8);
+ }
+}
+
+static UINT32 PortRead32_16(offs_t address)
+{
+ if (!(address & 1))
+ {
+ UINT32 result = io_read_word_16le(address);
+ return result | (io_read_word_16le(address + 2) << 16);
+ }
+ else
+ {
+ UINT32 result = io_read_byte_16le(address);
+ result |= io_read_word_16le(address + 1) << 8;
+ return result | io_read_byte_16le(address + 3) << 24;
+ }
+}
+
+static void PortWrite32_16(offs_t address, UINT32 data)
+{
+ if (!(address & 1))
+ {
+ io_write_word_16le(address, data);
+ io_write_word_16le(address + 2, data >> 16);
+ }
+ else
+ {
+ io_write_byte_16le(address, data);
+ io_write_word_16le(address + 1, data >> 8);
+ io_write_byte_16le(address + 3, data >> 24);
+ }
+}
+
+
+
+/*****************************************************************/
+/* Opcode accesses for 16-bit data bus, 24-bit address bus (V60) */
+/*****************************************************************/
+
+static UINT8 OpRead8_16(offs_t address)
+{
+ return cpu_readop(BYTE_XOR_LE(address));
+}
+
+static UINT16 OpRead16_16(offs_t address)
+{
+ return cpu_readop(BYTE_XOR_LE(address)) | (cpu_readop(BYTE_XOR_LE(address+1)) << 8);
+}
+
+static UINT32 OpRead32_16(offs_t address)
+{
+ return cpu_readop(BYTE_XOR_LE(address)) | (cpu_readop(BYTE_XOR_LE(address+1)) << 8) |
+ (cpu_readop(BYTE_XOR_LE(address+2)) << 16) | (cpu_readop(BYTE_XOR_LE(address+3)) << 24);
+}
+
+static void ChangePC_16(offs_t pc)
+{
+ change_pc(pc);
+}
+
+
+
+/*****************************************************************/
+/* Memory accesses for 32-bit data bus, 32-bit address bus (V70) */
+/*****************************************************************/
+
+#define MemRead8_32 program_read_byte_32le
+#define MemWrite8_32 program_write_byte_32le
+
+static UINT16 MemRead16_32(offs_t address)
+{
+ if (!(address & 1))
+ return program_read_word_32le(address);
+ else
+ {
+ UINT16 result = program_read_byte_32le(address);
+ return result | program_read_byte_32le(address + 1) << 8;
+ }
+}
+
+static void MemWrite16_32(offs_t address, UINT16 data)
+{
+ if (!(address & 1))
+ program_write_word_32le(address, data);
+ else
+ {
+ program_write_byte_32le(address, data);
+ program_write_byte_32le(address + 1, data >> 8);
+ }
+}
+
+static UINT32 MemRead32_32(offs_t address)
+{
+ if (!(address & 3))
+ return program_read_dword_32le(address);
+ else if (!(address & 1))
+ {
+ UINT32 result = program_read_word_32le(address);
+ return result | (program_read_word_32le(address + 2) << 16);
+ }
+ else
+ {
+ UINT32 result = program_read_byte_32le(address);
+ result |= program_read_word_32le(address + 1) << 8;
+ return result | program_read_byte_32le(address + 3) << 24;
+ }
+}
+
+static void MemWrite32_32(offs_t address, UINT32 data)
+{
+ if (!(address & 3))
+ program_write_dword_32le(address, data);
+ else if (!(address & 1))
+ {
+ program_write_word_32le(address, data);
+ program_write_word_32le(address + 2, data >> 16);
+ }
+ else
+ {
+ program_write_byte_32le(address, data);
+ program_write_word_32le(address + 1, data >> 8);
+ program_write_byte_32le(address + 3, data >> 24);
+ }
+}
+
+
+
+/***************************************************************/
+/* Port accesses for 32-bit data bus, 32-bit address bus (V70) */
+/***************************************************************/
+
+#define PortRead8_32 io_read_byte_32le
+#define PortWrite8_32 io_write_byte_32le
+
+static UINT16 PortRead16_32(offs_t address)
+{
+ if (!(address & 1))
+ {
+ return io_read_word_32le(address);
+ }
+ else
+ {
+ UINT16 result = io_read_byte_32le(address);
+ return result | io_read_byte_32le(address + 1) << 8;
+ }
+}
+
+static void PortWrite16_32(offs_t address, UINT16 data)
+{
+ if (!(address & 1))
+ {
+ io_write_word_32le(address, data);
+ }
+ else
+ {
+ io_write_byte_32le(address, data);
+ io_write_byte_32le(address + 1, data >> 8);
+ }
+}
+
+static UINT32 PortRead32_32(offs_t address)
+{
+ if (!(address & 3))
+ return io_read_dword_32le(address);
+ else if (!(address & 1))
+ {
+ UINT32 result = io_read_word_32le(address);
+ return result | (io_read_word_32le(address + 2) << 16);
+ }
+ else
+ {
+ UINT32 result = io_read_byte_32le(address);
+ result |= io_read_word_32le(address + 1) << 8;
+ return result | io_read_byte_32le(address + 3) << 24;
+ }
+}
+
+static void PortWrite32_32(offs_t address, UINT32 data)
+{
+ if (!(address & 3))
+ io_write_dword_32le(address, data);
+ else if (!(address & 1))
+ {
+ io_write_word_32le(address, data);
+ io_write_word_32le(address + 2, data >> 16);
+ }
+ else
+ {
+ io_write_byte_32le(address, data);
+ io_write_word_32le(address + 1, data >> 8);
+ io_write_byte_32le(address + 3, data >> 24);
+ }
+}
+
+
+
+/*****************************************************************/
+/* Opcode accesses for 32-bit data bus, 32-bit address bus (V60) */
+/*****************************************************************/
+
+static UINT8 OpRead8_32(offs_t address)
+{
+ return cpu_readop(BYTE4_XOR_LE(address));
+}
+
+static UINT16 OpRead16_32(offs_t address)
+{
+ return cpu_readop(BYTE4_XOR_LE(address)) | (cpu_readop(BYTE4_XOR_LE(address+1)) << 8);
+}
+
+static UINT32 OpRead32_32(offs_t address)
+{
+ return cpu_readop(BYTE4_XOR_LE(address)) | (cpu_readop(BYTE4_XOR_LE(address+1)) << 8) |
+ (cpu_readop(BYTE4_XOR_LE(address+2)) << 16) | (cpu_readop(BYTE4_XOR_LE(address+3)) << 24);
+}
+
+static void ChangePC_32(offs_t pc)
+{
+ change_pc(pc);
+}
+
+
+
+/************************************************/
+/* Structures pointing to various I/O functions */
+/************************************************/
+
+static struct cpu_info v60_i =
+{
+ MemRead8_16, MemWrite8_16, MemRead16_16, MemWrite16_16, MemRead32_16, MemWrite32_16,
+ PortRead8_16, PortWrite8_16, PortRead16_16, PortWrite16_16, PortRead32_16, PortWrite32_16,
+ OpRead8_16, OpRead16_16, OpRead32_16,
+ ChangePC_16,
+ 0xfffff0
+};
+
+static struct cpu_info v70_i =
+{
+ MemRead8_32, MemWrite8_32, MemRead16_32, MemWrite16_32, MemRead32_32, MemWrite32_32,
+ PortRead8_32, PortWrite8_32, PortRead16_32, PortWrite16_32, PortRead32_32, PortWrite32_32,
+ OpRead8_32, OpRead16_32, OpRead32_32,
+ ChangePC_32,
+ 0xfffffff0
+};
+
+
+
+/**************************************/
+/* Macro shorthands for I/O functions */
+/**************************************/
+
+#define MemRead8 v60.info.mr8
+#define MemWrite8 v60.info.mw8
+#define MemRead16 v60.info.mr16
+#define MemWrite16 v60.info.mw16
+#define MemRead32 v60.info.mr32
+#define MemWrite32 v60.info.mw32
+
+#define PortRead8 v60.info.pr8
+#define PortWrite8 v60.info.pw8
+#define PortRead16 v60.info.pr16
+#define PortWrite16 v60.info.pw16
+#define PortRead32 v60.info.pr32
+#define PortWrite32 v60.info.pw32
+
+#if defined(LSB_FIRST) && !defined(ALIGN_INTS)
+#define OpRead8(a) (cpu_readop(a))
+#define OpRead16(a) (cpu_readop16(a))
+#define OpRead32(a) (cpu_readop32(a))
+#else
+#define OpRead8 v60.info.mr8
+#define OpRead16 v60.info.mr16
+#define OpRead32 v60.info.mr32
+#endif
+
+#define ChangePC v60.info.chpc
diff --git a/src/emu/cpu/v810/v810.c b/src/emu/cpu/v810/v810.c
new file mode 100644
index 00000000000..277c8895536
--- /dev/null
+++ b/src/emu/cpu/v810/v810.c
@@ -0,0 +1,1240 @@
+/********************************************
+ NEC V810 (upd70732) core
+ Tomasz Slanina - analog[at]op.pl
+
+ Change Log
+ - 20/07/2004 - first public release
+
+
+ TODO:
+ - CY flag in few floating point opcodes
+ (all floating point opcodes are NOT tested!)
+ - traps/interrupts/exceptions
+ - bitstring opcodes
+ - timing
+ - missing opcodes : reti , trap
+
+********************************************/
+
+#include "debugger.h"
+#include "v810.h"
+
+#define clkIF 3
+#define clkMEM 3
+
+typedef struct
+{
+ UINT32 reg[65];
+ UINT8 irq_line;
+ UINT8 nmi_line;
+ int (*irq_cb)(int irqline);
+ UINT32 PPC;
+ UINT32 op;
+} v810info;
+
+static v810info v810;
+
+int v810_ICount;
+
+#define R0 v810.reg[0]
+#define R1 v810.reg[1]
+#define R2 v810.reg[2]
+#define SP v810.reg[3]
+#define R4 v810.reg[4]
+#define R5 v810.reg[5]
+#define R6 v810.reg[6]
+#define R7 v810.reg[7]
+#define R8 v810.reg[8]
+#define R9 v810.reg[9]
+#define R10 v810.reg[10]
+#define R11 v810.reg[11]
+#define R12 v810.reg[12]
+#define R13 v810.reg[13]
+#define R14 v810.reg[14]
+#define R15 v810.reg[15]
+#define R16 v810.reg[16]
+#define R17 v810.reg[17]
+#define R18 v810.reg[18]
+#define R19 v810.reg[19]
+#define R20 v810.reg[20]
+#define R21 v810.reg[21]
+#define R22 v810.reg[22]
+#define R23 v810.reg[23]
+#define R24 v810.reg[24]
+#define R25 v810.reg[25]
+#define R26 v810.reg[26]
+#define R27 v810.reg[27]
+#define R28 v810.reg[28]
+#define R29 v810.reg[29]
+#define R30 v810.reg[30]
+#define R31 v810.reg[31]
+
+#define EIPC v810.reg[32]
+#define EIPSW v810.reg[33]
+#define FEPC v810.reg[34]
+#define FEPSW v810.reg[35]
+#define ECR v810.reg[36]
+#define PSW v810.reg[37]
+#define PIR v810.reg[38]
+#define TKCW v810.reg[39]
+#define CHCW v810.reg[56]
+#define ADTRE v810.reg[57]
+
+#define OP v810.op
+#define PC v810.reg[64]
+
+/* Flags */
+#define GET_Z ( PSW & 0x00000001)
+#define GET_S ((PSW & 0x00000002)>>1)
+#define GET_OV ((PSW & 0x00000004)>>2)
+#define GET_CY ((PSW & 0x00000008)>>3)
+#define GET_ID ((PSW & 0x00008000)>>15)
+#define GET_EP ((PSW & 0x00010000)>>16)
+#define GET_NP ((PSW & 0x00020000)>>17)
+#define GET_AE ((PSW & 0x00040000)>>18)
+
+#define SET_Z(val) (PSW = (PSW & ~0x00000001) | (val))
+#define SET_S(val) (PSW = (PSW & ~0x00000002) | ((val) << 1))
+#define SET_OV(val) (PSW = (PSW & ~0x00000004) | ((val) << 2))
+#define SET_CY(val) (PSW = (PSW & ~0x00000008) | ((val) << 3))
+#define SET_ID(val) (PSW = (PSW & ~0x00008000) | ((val) << 15))
+#define SET_EP(val) (PSW = (PSW & ~0x00010000) | ((val) << 16))
+#define SET_NP(val) (PSW = (PSW & ~0x00020000) | ((val) << 17))
+#define SET_AE(val) (PSW = (PSW & ~0x00040000) | ((val) << 18))
+
+
+
+
+static void SETREG(UINT32 reg,UINT32 val)
+{
+ if(reg)
+ v810.reg[reg]=val;
+}
+
+static UINT32 GETREG(UINT32 reg)
+{
+ if(reg)
+ return v810.reg[reg];
+ else
+ return 0;
+}
+
+static UINT32 opUNDEF(void)
+{
+ logerror("V810: Unknown opcode %x @ %x",OP,PC-2);
+ return clkIF;
+}
+
+static UINT32 opMOVr(void) // mov reg1, reg2
+{
+ SETREG(GET2,GETREG(GET1));
+ return clkIF;
+}
+
+static UINT32 opMOVEA(void) // movea imm16, reg1, reg2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=R_OP(PC);
+ PC+=2;
+ op2=I16(op2);
+ SETREG(GET2,op1+op2);
+ return clkIF;
+}
+
+static UINT32 opMOVHI(void) // movhi imm16, reg1 ,reg2
+{
+ UINT32 op2=R_OP(PC);
+ PC+=2;
+ op2=UI16(op2);
+ op2<<=16;
+ SETREG(GET2,GETREG(GET1)+op2);
+ return clkIF;
+}
+
+static UINT32 opMOVi(void) // mov imm5,r2
+{
+ SETREG(GET2,I5(OP));
+ return clkIF;
+}
+
+static UINT32 opADDr(void) // add r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ UINT64 res=(UINT64)op2+(UINT64)op1;
+ CHECK_CY(res);
+ CHECK_OVADD(op1,op2,res);
+ CHECK_ZS(res);
+ SETREG(GET2,res);
+ return clkIF;
+}
+
+static UINT32 opADDi(void) // add imm5,r2
+{
+ UINT32 op1=I5(OP);
+ UINT32 op2=GETREG(GET2);
+ UINT64 res=(UINT64)op2+(UINT64)op1;
+ CHECK_CY(res);
+ CHECK_OVADD(op1,op2,res);
+ CHECK_ZS(res);
+ SETREG(GET2,res);
+ return clkIF;
+}
+
+
+static UINT32 opADDI(void) // addi imm16, reg1, reg2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=R_OP(PC);
+ UINT64 res;
+ PC+=2;
+ op2=I16(op2);
+ res=(UINT64)op2+(UINT64)op1;
+ CHECK_CY(res);
+ CHECK_OVADD(op1,op2,res);
+ CHECK_ZS(res);
+ SETREG(GET2,res);
+ return clkIF;
+}
+
+static UINT32 opSUBr(void) // sub r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ UINT64 res=(UINT64)op2-(UINT64)op1;
+ CHECK_CY(res);
+ CHECK_OVSUB(op1,op2,res);
+ CHECK_ZS(res);
+ SETREG(GET2,res);
+ return clkIF;
+}
+
+
+static UINT32 opCMPr(void) // cmp r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ UINT64 res=(UINT64)op2-(UINT64)op1;
+ CHECK_CY(res);
+ CHECK_OVSUB(op1,op2,res);
+ CHECK_ZS(res);
+ return clkIF;
+}
+
+static UINT32 opCMPi(void) // cmpi imm5,r2
+{
+ UINT32 op1=I5(OP);
+ UINT32 op2=GETREG(GET2);
+ UINT64 res=(UINT64)op2-(UINT64)op1;
+ CHECK_CY(res);
+ CHECK_OVSUB(op1,op2,res);
+ CHECK_ZS(res);
+ return clkIF;
+}
+
+static UINT32 opSETFi(void) // setf imm5,r2
+{
+ UINT32 op1=I5(OP);
+ UINT32 op2=PSW&0xf;
+ op1&=0xf;
+ SETREG(GET2,(op1==op2)?1:0);
+ return clkIF;
+}
+
+
+static UINT32 opANDr(void) // and r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ op2&=op1;
+ CHECK_ZS(op2);
+ SET_OV(0);
+ SETREG(GET2,op2);
+ return clkIF;
+}
+
+static UINT32 opANDI(void) // andi imm16,r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=R_OP(PC);
+ PC+=2;
+ op2=UI16(op2);
+ op2&=op1;
+ CHECK_ZS(op2);
+ SET_OV(0);
+ SET_S(0);
+ SETREG(GET2,op2);
+ return clkIF;
+}
+
+static UINT32 opORr(void) // or r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ op2|=op1;
+ CHECK_ZS(op2);
+ SET_OV(0);
+ SETREG(GET2,op2);
+ return clkIF;
+}
+
+static UINT32 opORI(void) // ori imm16,r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=R_OP(PC);
+ PC+=2;
+ op2=UI16(op2);
+ op2|=op1;
+ CHECK_ZS(op2);
+ SET_OV(0);
+ SET_S(0);
+ SETREG(GET2,op2);
+ return clkIF;
+}
+
+static UINT32 opXORr(void) // xor r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ op2^=op1;
+ CHECK_ZS(op2);
+ SET_OV(0);
+ SETREG(GET2,op2);
+ return clkIF;
+}
+
+
+static UINT32 opLDSR(void) // ldsr reg2,regID
+{
+ UINT32 op1=UI5(OP);
+ SETREG(32+op1,GETREG(GET2));
+ return clkIF;
+}
+
+static UINT32 opSTSR(void) // ldsr regID,reg2
+{
+ UINT32 op1=UI5(OP);
+ SETREG(GET2,GETREG(32+op1));
+ return clkIF;
+}
+
+
+static UINT32 opXORI(void) // xori imm16,r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=R_OP(PC);
+ PC+=2;
+ op2=UI16(op2);
+ op2^=op1;
+ CHECK_ZS(op2);
+ SET_OV(0);
+ SET_S(0);
+ SETREG(GET2,op2);
+ return clkIF;
+}
+
+static UINT32 opNOTr(void) // not r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=~op1;
+ CHECK_ZS(op2);
+ SET_OV(0);
+ SETREG(GET2,op2);
+ return clkIF;
+}
+
+static UINT32 opSHLr(void) // shl r1,r2
+{
+ UINT64 tmp;
+ UINT32 count=GETREG(GET1);
+ count&=0x1f;
+
+ SET_OV(0);
+ SET_CY(0);
+
+ if(count)
+ {
+ tmp=GETREG(GET2);
+ tmp<<=count;
+ CHECK_CY(tmp);
+ SETREG(GET2,tmp&0xffffffff);
+ CHECK_ZS(GETREG(GET2));
+ }
+ return clkIF;
+}
+
+static UINT32 opSHLi(void) // shl imm5,r2
+{
+ UINT64 tmp;
+ UINT32 count=UI5(OP);
+
+ SET_OV(0);
+ SET_CY(0);
+
+ if(count)
+ {
+ tmp=GETREG(GET2);
+ tmp<<=count;
+ CHECK_CY(tmp);
+ SETREG(GET2,tmp&0xffffffff);
+ }
+ CHECK_ZS(GETREG(GET2));
+ return clkIF;
+}
+
+static UINT32 opSHRr(void) // shr r1,r2
+{
+ UINT64 tmp;
+ UINT32 count=GETREG(GET1);
+ count&=0x1f;
+ SET_OV(0);
+ SET_CY(0);
+ if(count)
+ {
+ tmp=GETREG(GET2);
+ tmp>>=count-1;
+ SET_CY(tmp&1);
+ SETREG(GET2,(tmp>>1)&0xffffffff);
+ }
+ CHECK_ZS(GETREG(GET2));
+ return clkIF;
+}
+
+static UINT32 opSHRi(void) // shr imm5,r2
+{
+ UINT64 tmp;
+ UINT32 count=UI5(OP);
+ SET_OV(0);
+ SET_CY(0);
+ if(count)
+ {
+ tmp=GETREG(GET2);
+ tmp>>=count-1;
+ SET_CY(tmp&1);
+ tmp>>=1;
+ SETREG(GET2,tmp&0xffffffff);
+ }
+ CHECK_ZS(GETREG(GET2));
+ return clkIF;
+}
+
+static UINT32 opSARr(void) // sar r1,r2
+{
+ INT32 tmp;
+ UINT32 count=GETREG(GET1);
+ count&=0x1f;
+ SET_OV(0);
+ SET_CY(0);
+ if(count)
+ {
+ tmp=GETREG(GET2);
+ tmp>>=count-1;
+ SET_CY(tmp&1);
+ tmp>>=1;
+ SETREG(GET2,tmp);
+ }
+ CHECK_ZS(GETREG(GET2));
+ return clkIF;
+}
+
+static UINT32 opSARi(void) // sar imm5,r2
+{
+ INT32 tmp;
+ UINT32 count=UI5(OP);
+ SET_OV(0);
+ SET_CY(0);
+ if(count)
+ {
+ tmp=GETREG(GET2);
+ tmp>>=count-1;
+ SET_CY(tmp&1);
+ tmp>>=1;
+ SETREG(GET2,tmp);
+ }
+ CHECK_ZS(GETREG(GET2));
+ return clkIF;
+}
+
+static UINT32 opJMPr(void)
+{
+ PC=GETREG(GET1)&~1;
+ return clkIF+2;
+}
+
+
+static UINT32 opJR(void)
+{
+ UINT32 tmp=R_OP(PC);
+ PC=PC-2+(D26(OP,tmp)&~1);
+ return clkIF+2;
+}
+
+static UINT32 opJAL(void)
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ R31=PC;
+ PC+=D26(OP,tmp);
+ PC-=4;
+ PC&=~1;
+ return clkIF+2;
+}
+
+
+static UINT32 opEI(void)
+{
+ SET_ID(0);
+ return clkIF;
+}
+
+static UINT32 opDI(void)
+{
+ SET_ID(1);
+ return clkIF;
+}
+
+static UINT32 opHALT(void)
+{
+ logerror("V810: HALT @ %X",PC-2);
+ return clkIF;
+}
+
+static UINT32 opB(void)
+{
+ int doBranch=0;
+ switch((OP>>9)&0xf)
+ {
+ case 0: //bv
+ doBranch=GET_OV;
+ break;
+
+ case 1: //bl
+ doBranch=GET_CY;
+ break;
+
+ case 2: //be
+ doBranch=GET_Z;
+ break;
+
+ case 3: //bnh
+ doBranch=GET_Z||GET_CY;
+ break;
+
+ case 4: //bn
+ doBranch=GET_S;
+ break;
+
+ case 5: //br
+ doBranch=1;
+ break;
+
+ case 6: //blt
+ doBranch=GET_S^GET_OV;
+ break;
+
+ case 7: //ble
+ doBranch=GET_Z||(GET_S^GET_OV);
+ break;
+
+ case 8: //bnv
+ doBranch=!GET_OV;
+ break;
+
+ case 9: //bnl
+ doBranch=!GET_CY;
+ break;
+
+ case 10: //bne
+ doBranch=!GET_Z;
+ break;
+
+ case 11: //bh
+ doBranch=!(GET_Z||GET_CY);
+ break;
+
+ case 12: //bp
+ doBranch=!GET_S;
+ break;
+
+ case 13: //nop
+
+ break;
+
+ case 14: //bge
+ doBranch=!(GET_OV^GET_S);
+ break;
+
+ case 15: //bgt
+ doBranch=!(GET_Z||(GET_OV^GET_S));
+ break;
+ }
+ if(doBranch)
+ {
+ PC=PC-2+(D9(OP)&~1);
+ }
+ return clkIF;
+}
+
+static UINT32 opLDB(void) // ld.b disp16[reg1],reg2
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ tmp=R_B(tmp);
+ tmp|=(tmp&0x80)?0xffffff00:0;
+ SETREG(GET2,tmp);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opLDH(void) // ld.h disp16[reg1],reg2
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ tmp=R_H(tmp&~1);
+ tmp|=(tmp&0x8000)?0xffff0000:0;
+ SETREG(GET2,tmp);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opLDW(void) // ld.w disp16[reg1],reg2
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ tmp=R_W(tmp&~3);
+ SETREG(GET2,tmp);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opINB(void) // in.b disp16[reg1],reg2
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ tmp=RIO_B(tmp);
+ SETREG(GET2,tmp);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opCAXI(void) // caxi disp16[reg1],reg2
+{
+ PC+=2;
+ return clkIF;
+}
+
+static UINT32 opINH(void) // in.h disp16[reg1],reg2
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ tmp=RIO_H(tmp&~1);
+ SETREG(GET2,tmp);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opINW(void) // in.w disp16[reg1],reg2
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ tmp=RIO_W(tmp&~3);
+ SETREG(GET2,tmp);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opSTB(void) // st.b reg2, disp16[reg1]
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ W_B(tmp,GETREG(GET2)&0xff);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opSTH(void) // st.h reg2, disp16[reg1]
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ W_H(tmp&~1,GETREG(GET2)&0xffff);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opSTW(void) // st.w reg2, disp16[reg1]
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ W_W(tmp&~3,GETREG(GET2));
+ return clkIF+clkMEM;
+}
+
+static UINT32 opOUTB(void) // out.b reg2, disp16[reg1]
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ WIO_B(tmp,GETREG(GET2)&0xff);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opOUTH(void) // out.h reg2, disp16[reg1]
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ WIO_H(tmp&~1,GETREG(GET2)&0xffff);
+ return clkIF+clkMEM;
+}
+
+static UINT32 opOUTW(void) // out.w reg2, disp16[reg1]
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ tmp=D16(tmp);
+ tmp+=GETREG(GET1);
+ WIO_W(tmp&~3,GETREG(GET2));
+ return clkIF+clkMEM;
+}
+
+static UINT32 opMULr(void) // mul r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ UINT64 tmp;
+ tmp=(INT64)(INT32)op1*(INT64)(INT32)op2;
+ op2=tmp&0xffffffff;
+ tmp>>=32;
+ CHECK_ZS(tmp);//z = bad!
+ SET_Z( (tmp|op2)==0 );
+ SET_OV((tmp!=0));
+ SET_CY((tmp!=0));
+ SETREG(GET2,op2);
+ SETREG(30,tmp);
+ return clkIF;
+}
+
+static UINT32 opMULUr(void) // mulu r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ UINT64 tmp;
+ tmp=(UINT64)op1*(UINT64)op2;
+ op2=tmp&0xffffffff;
+ tmp>>=32;
+ CHECK_ZS(tmp);//z = bad!
+ SET_Z( (tmp|op2)==0 );
+ SET_OV((tmp!=0));
+ SET_CY((tmp!=0));
+ SETREG(GET2,op2);
+ SETREG(30,tmp);
+ return clkIF;
+}
+
+static UINT32 opDIVr(void) // div r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ if(op1)
+ {
+ SETREG(30,(INT32)((INT32)op2%(INT32)op1));
+ SETREG(GET2,(INT32)((INT32)op2/(INT32)op1));
+ SET_OV((op1^op2^GETREG(GET2)) == 0x80000000);
+ CHECK_ZS(GETREG(GET2));
+ }
+ return clkIF;
+}
+
+static UINT32 opDIVUr(void) // divu r1,r2
+{
+ UINT32 op1=GETREG(GET1);
+ UINT32 op2=GETREG(GET2);
+ if(op1)
+ {
+ SETREG(30,(INT32)(op2%op1));
+ SETREG(GET2,(INT32)(op2/op1));
+ SET_OV((op1^op2^GETREG(GET2)) == 0x80000000);
+ CHECK_ZS(GETREG(GET2));
+ }
+ return clkIF;
+}
+
+static void opADDF(void)
+{
+ //TODO: CY
+ float val1=u2f(GETREG(GET1));
+ float val2=u2f(GETREG(GET2));
+ SET_OV(0);
+ val2+=val1;
+ SET_Z((val2==0.0)?1:0);
+ SET_S((val2<0.0)?1:0);
+ SETREG(GET2,f2u(val2));
+}
+
+static void opSUBF(void)
+{
+ float val1=u2f(GETREG(GET1));
+ float val2=u2f(GETREG(GET2));
+ SET_OV(0);
+ SET_CY((val2<val1)?1:0);
+ val2-=val1;
+ SET_Z((val2==0.0)?1:0);
+ SET_S((val2<0.0)?1:0);
+ SETREG(GET2,f2u(val2));
+}
+
+static void opMULF(void)
+{
+ //TODO: CY
+ float val1=u2f(GETREG(GET1));
+ float val2=u2f(GETREG(GET2));
+ SET_OV(0);
+ val2*=val1;
+ SET_Z((val2==0.0)?1:0);
+ SET_S((val2<0.0)?1:0);
+ SETREG(GET2,f2u(val2));
+}
+
+static void opDIVF(void)
+{
+ //TODO: CY
+ float val1=u2f(GETREG(GET1));
+ float val2=u2f(GETREG(GET2));
+ SET_OV(0);
+ if(val1!=0)
+ val2/=val1;
+ SET_Z((val2==0.0)?1:0);
+ SET_S((val2<0.0)?1:0);
+ SETREG(GET2,f2u(val2));
+}
+
+static void opTRNC(void)
+{
+ float val1=u2f(GETREG(GET1));
+ SET_OV(0);
+ SET_Z((val1==0.0)?1:0);
+ SET_S((val1<0.0)?1:0);
+ SETREG(GET2,(INT32)val1);
+}
+
+static void opCMPF(void)
+{
+ float val1=u2f(GETREG(GET1));
+ float val2=u2f(GETREG(GET2));
+ SET_OV(0);
+ SET_CY((val2<val1)?1:0);
+ val2-=val1;
+ SET_Z((val2==0.0)?1:0);
+ SET_S((val2<0.0)?1:0);
+}
+
+static void opCVTS(void)
+{
+ float val1=u2f(GETREG(GET1));
+ SET_OV(0);
+ SET_Z((val1==0.0)?1:0);
+ SET_S((val1<0.0)?1:0);
+ SETREG(GET2,(INT32)val1);
+}
+
+static void opCVTW(void)
+{
+ //TODO: CY
+ float val1=GETREG(GET1);
+ SET_OV(0);
+ SET_Z((val1==0.0)?1:0);
+ SET_S((val1<0.0)?1:0);
+ SETREG(GET2,f2u(val1));
+}
+
+static UINT32 opFpoint(void)
+{
+ UINT32 tmp=R_OP(PC);
+ PC+=2;
+ switch((tmp&0xfc00)>>10)
+ {
+ case 0x0: opCMPF();break;
+ case 0x2: opCVTW();break;
+ case 0x3: opCVTS();break;
+ case 0x4: opADDF();break;
+ case 0x5: opSUBF();break;
+ case 0x6: opMULF();break;
+ case 0x7: opDIVF();break;
+ case 0xb: opTRNC();break;
+ }
+ return clkIF+1;
+}
+
+static UINT32 (*OpCodeTable[64])(void) =
+{
+ /* 0x00 */ opMOVr, // mov r1,r2 1
+ /* 0x01 */ opADDr, // add r1,r2 1
+ /* 0x02 */ opSUBr, // sub r1,r2 1
+ /* 0x03 */ opCMPr, // cmp2 r1,r2 1
+ /* 0x04 */ opSHLr, // shl r1,r2 1
+ /* 0x05 */ opSHRr, // shr r1,r2 1
+ /* 0x06 */ opJMPr, // jmp [r1] 1
+ /* 0x07 */ opSARr, // sar r1,r2 1
+ /* 0x08 */ opMULr, // mul r1,r2 1
+ /* 0x09 */ opDIVr, // div r1,r2 1
+ /* 0x0a */ opMULUr, // mulu r1,r2 1
+ /* 0x0b */ opDIVUr, // divu r1,r2 1
+ /* 0x0c */ opORr, // or r1,r2 1
+ /* 0x0d */ opANDr, // and r1,r2 1
+ /* 0x0e */ opXORr, // xor r1,r2 1
+ /* 0x0f */ opNOTr, // not r1,r2 1
+ /* 0x10 */ opMOVi, // mov imm5,r2 2
+ /* 0x11 */ opADDi, // add imm5,r2 2
+ /* 0x12 */ opSETFi, // setf imm5,r2 2
+ /* 0x13 */ opCMPi, // cmp imm5,r2 2
+ /* 0x14 */ opSHLi, // shl imm5,r2 2
+ /* 0x15 */ opSHRi, // shr imm5,r2 2
+ /* 0x16 */ opEI, // ei 2
+ /* 0x17 */ opSARi, // sar imm5,r2 2
+ /* 0x18 */ opUNDEF,
+ /* 0x19 */ opUNDEF,
+ /* 0x1a */ opHALT, // halt 2
+ /* 0x1b */ opUNDEF,
+ /* 0x1c */ opLDSR, // ldsr reg2,regID 2
+ /* 0x1d */ opSTSR, // stsr regID,reg2 2
+ /* 0x1e */ opDI, // DI 2
+ /* 0x1f */ opUNDEF,
+ /* 0x20 */ opB, // Branch (7 bit opcode)
+ /* 0x21 */ opB, // Branch (7 bit opcode)
+ /* 0x22 */ opB, // Branch (7 bit opcode)
+ /* 0x23 */ opB, // Branch (7 bit opcode)
+ /* 0x24 */ opB, // Branch (7 bit opcode)
+ /* 0x25 */ opB, // Branch (7 bit opcode)
+ /* 0x26 */ opB, // Branch (7 bit opcode)
+ /* 0x27 */ opB, // Branch (7 bit opcode)
+ /* 0x28 */ opMOVEA, // movea imm16, reg1, reg2 5
+ /* 0x29 */ opADDI, // addi imm16, reg1, reg2 5
+ /* 0x2a */ opJR, // jr disp26 4
+ /* 0x2b */ opJAL, // jal disp26 4
+ /* 0x2c */ opORI, // ori imm16, reg1, reg2 5
+ /* 0x2d */ opANDI, // andi imm16, reg1, reg2 5
+ /* 0x2e */ opXORI, // xori imm16, reg1, reg2 5
+ /* 0x2f */ opMOVHI, // movhi imm16, reg1 ,reg2 5
+ /* 0x30 */ opLDB, // ld.b disp16[reg1],reg2 6a
+ /* 0x31 */ opLDH, // ld.h disp16[reg1],reg2 6a
+ /* 0x32 */ opUNDEF,
+ /* 0x33 */ opLDW, // ld.w disp16[reg1],reg2 6a
+ /* 0x34 */ opSTB, // st.b reg2, disp16[reg1] 6b
+ /* 0x35 */ opSTH, // st.h reg2, disp16[reg1] 6b
+ /* 0x36 */ opUNDEF,
+ /* 0x37 */ opSTW, // st.w reg2, disp16[reg1] 6b
+ /* 0x38 */ opINB, // in.b disp16[reg1], reg2 6a
+ /* 0x39 */ opINH, // in.h disp16[reg1], reg2 6a
+ /* 0x3a */ opCAXI, // caxi disp16[reg1],reg2 6a
+ /* 0x3b */ opINW, // in.w disp16[reg1], reg2 6a
+ /* 0x3c */ opOUTB, // out.b reg2, disp16[reg1] 6b
+ /* 0x3d */ opOUTH, // out.h reg2, disp16[reg1] 6b
+ /* 0x3e */ opFpoint, //floating point opcodes
+ /* 0x3f */ opOUTW // out.w reg2, disp16[reg1] 6b
+};
+
+void v810_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ v810.irq_line = CLEAR_LINE;
+ v810.nmi_line = CLEAR_LINE;
+ v810.irq_cb = irqcallback;
+
+ state_save_register_item_array("v810", index, v810.reg);
+ state_save_register_item("v810", index, v810.irq_line);
+ state_save_register_item("v810", index, v810.nmi_line);
+ state_save_register_item("v810", index, v810.PPC);
+
+}
+
+void v810_reset(void)
+{
+ int i;
+ for(i=0;i<64;i++) v810.reg[i]=0;
+ PC = 0xfffffff0;
+ PSW = 0x8000;
+ ECR = 0x0000fff0;
+}
+
+int v810_execute(int cycles)
+{
+ v810_ICount = cycles;
+ while(v810_ICount>=0)
+ {
+ v810.PPC=PC;
+ CALL_MAME_DEBUG;
+ OP=R_OP(PC);
+ PC+=2;
+ v810_ICount-= OpCodeTable[OP>>10]();
+ }
+ return cycles-v810_ICount;
+}
+
+void v810_get_context(void *dst)
+{
+ if(dst)
+ *(v810info *)dst = v810;
+}
+
+void v810_set_context(void *src)
+{
+ if(src)
+ v810 = *(v810info *)src;
+}
+
+static void set_irq_line(int irqline, int state)
+{
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void v810_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 2: set_irq_line(2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 3: set_irq_line(3, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 4: set_irq_line(4, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 5: set_irq_line(5, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 6: set_irq_line(6, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 7: set_irq_line(7, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 8: set_irq_line(8, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 9: set_irq_line(9, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 10: set_irq_line(10, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 11: set_irq_line(11, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 12: set_irq_line(12, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 13: set_irq_line(13, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 14: set_irq_line(14, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 15: set_irq_line(15, info->i); break;
+
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PREVIOUSPC: v810.PPC = info->i; break;
+
+ case CPUINFO_INT_REGISTER + V810_PC:
+ case CPUINFO_INT_PC: PC = info->i; break;
+
+ case CPUINFO_INT_REGISTER + V810_R0: R0 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R1: R1 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R2: R2 = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + V810_SP: SP = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R4: R4 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R5: R5 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R6: R6 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R7: R7 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R8: R8 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R9: R9 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R10: R10 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R11: R11 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R12: R12 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R13: R13 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R14: R14 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R15: R15 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R16: R16 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R17: R17 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R18: R18 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R19: R19 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R20: R20 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R21: R21 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R22: R22 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R23: R23 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R24: R24 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R25: R25 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R26: R26 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R27: R27 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R28: R28 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R29: R29 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R30: R30 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_R31: R31 = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_PSW: PSW = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_EIPC: EIPC = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_EIPSW: EIPSW = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_FEPC: FEPC = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_FEPSW: FEPSW = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_ECR: ECR = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_PIR: PIR = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_TKCW: TKCW = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_CHCW: CHCW = info->i; break;
+ case CPUINFO_INT_REGISTER + V810_ADTRE: ADTRE = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void v810_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ GET_AE ? 'A':'.',
+ GET_NP ? 'N':'.',
+ GET_EP ? 'E':'.',
+ GET_ID ? 'I':'.',
+ GET_CY ? 'C':'.',
+ GET_OV ? 'V':'.',
+ GET_S ? 'S':'.',
+ GET_Z ? 'Z':'.');
+ break;
+
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(v810); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 9; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = v810.irq_line; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = v810.nmi_line; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = v810.PPC; break;
+
+ case CPUINFO_INT_REGISTER + V810_PC:
+ case CPUINFO_INT_PC: info->i = PC; break;
+
+ case CPUINFO_INT_REGISTER + V810_R0: info->i = R0; break;
+ case CPUINFO_INT_REGISTER + V810_R1: info->i = R1; break;
+ case CPUINFO_INT_REGISTER + V810_R2: info->i = R2; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + V810_SP: info->i = SP; break;
+ case CPUINFO_INT_REGISTER + V810_R4: info->i = R4; break;
+ case CPUINFO_INT_REGISTER + V810_R5: info->i = R5; break;
+ case CPUINFO_INT_REGISTER + V810_R6: info->i = R6; break;
+ case CPUINFO_INT_REGISTER + V810_R7: info->i = R7; break;
+ case CPUINFO_INT_REGISTER + V810_R8: info->i = R8; break;
+ case CPUINFO_INT_REGISTER + V810_R9: info->i = R9; break;
+ case CPUINFO_INT_REGISTER + V810_R10: info->i = R10; break;
+ case CPUINFO_INT_REGISTER + V810_R11: info->i = R11; break;
+ case CPUINFO_INT_REGISTER + V810_R12: info->i = R12; break;
+ case CPUINFO_INT_REGISTER + V810_R13: info->i = R13; break;
+ case CPUINFO_INT_REGISTER + V810_R14: info->i = R14; break;
+ case CPUINFO_INT_REGISTER + V810_R15: info->i = R15; break;
+ case CPUINFO_INT_REGISTER + V810_R16: info->i = R16; break;
+ case CPUINFO_INT_REGISTER + V810_R17: info->i = R17; break;
+ case CPUINFO_INT_REGISTER + V810_R18: info->i = R18; break;
+ case CPUINFO_INT_REGISTER + V810_R19: info->i = R19; break;
+ case CPUINFO_INT_REGISTER + V810_R20: info->i = R20; break;
+ case CPUINFO_INT_REGISTER + V810_R21: info->i = R21; break;
+ case CPUINFO_INT_REGISTER + V810_R22: info->i = R22; break;
+ case CPUINFO_INT_REGISTER + V810_R23: info->i = R23; break;
+ case CPUINFO_INT_REGISTER + V810_R24: info->i = R24; break;
+ case CPUINFO_INT_REGISTER + V810_R25: info->i = R25; break;
+ case CPUINFO_INT_REGISTER + V810_R26: info->i = R26; break;
+ case CPUINFO_INT_REGISTER + V810_R27: info->i = R27; break;
+ case CPUINFO_INT_REGISTER + V810_R28: info->i = R28; break;
+ case CPUINFO_INT_REGISTER + V810_R29: info->i = R29; break;
+ case CPUINFO_INT_REGISTER + V810_R30: info->i = R30; break;
+ case CPUINFO_INT_REGISTER + V810_R31: info->i = R31; break;
+ case CPUINFO_INT_REGISTER + V810_PSW: info->i = PSW; break;
+ case CPUINFO_INT_REGISTER + V810_EIPC: info->i = EIPC; break;
+ case CPUINFO_INT_REGISTER + V810_EIPSW: info->i = EIPSW; break;
+ case CPUINFO_INT_REGISTER + V810_FEPC: info->i = FEPC; break;
+ case CPUINFO_INT_REGISTER + V810_FEPSW: info->i = FEPSW; break;
+ case CPUINFO_INT_REGISTER + V810_ECR: info->i = ECR; break;
+ case CPUINFO_INT_REGISTER + V810_PIR: info->i = PIR; break;
+ case CPUINFO_INT_REGISTER + V810_TKCW: info->i = TKCW; break;
+ case CPUINFO_INT_REGISTER + V810_CHCW: info->i = CHCW; break;
+ case CPUINFO_INT_REGISTER + V810_ADTRE: info->i = ADTRE; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = v810_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = v810_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = v810_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = v810_init; break;
+ case CPUINFO_PTR_RESET: info->reset = v810_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = NULL; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = v810_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = v810_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &v810_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "V810"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "NEC V810"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Tomasz Slanina"); break;
+
+ case CPUINFO_STR_REGISTER + V810_PC: sprintf(info->s, "PC:%08X", PC); break;
+ case CPUINFO_STR_REGISTER + V810_R0: sprintf(info->s, "R0 :%08X", R0); break;
+ case CPUINFO_STR_REGISTER + V810_R1: sprintf(info->s, "R1 :%08X", R1); break;
+ case CPUINFO_STR_REGISTER + V810_R2: sprintf(info->s, "R2 :%08X", R2); break;
+ case CPUINFO_STR_REGISTER + V810_SP: sprintf(info->s, "SP :%08X", SP); break;
+ case CPUINFO_STR_REGISTER + V810_R4: sprintf(info->s, "R4 :%08X", R4); break;
+ case CPUINFO_STR_REGISTER + V810_R5: sprintf(info->s, "R5 :%08X", R5); break;
+ case CPUINFO_STR_REGISTER + V810_R6: sprintf(info->s, "R6 :%08X", R6); break;
+ case CPUINFO_STR_REGISTER + V810_R7: sprintf(info->s, "R7 :%08X", R7); break;
+ case CPUINFO_STR_REGISTER + V810_R8: sprintf(info->s, "R8 :%08X", R8); break;
+ case CPUINFO_STR_REGISTER + V810_R9: sprintf(info->s, "R9 :%08X", R9); break;
+ case CPUINFO_STR_REGISTER + V810_R10: sprintf(info->s, "R10:%08X", R10); break;
+ case CPUINFO_STR_REGISTER + V810_R11: sprintf(info->s, "R11:%08X", R11); break;
+ case CPUINFO_STR_REGISTER + V810_R12: sprintf(info->s, "R12:%08X", R12); break;
+ case CPUINFO_STR_REGISTER + V810_R13: sprintf(info->s, "R13:%08X", R13); break;
+ case CPUINFO_STR_REGISTER + V810_R14: sprintf(info->s, "R14:%08X", R14); break;
+ case CPUINFO_STR_REGISTER + V810_R15: sprintf(info->s, "R15:%08X", R15); break;
+ case CPUINFO_STR_REGISTER + V810_R16: sprintf(info->s, "R16:%08X", R16); break;
+ case CPUINFO_STR_REGISTER + V810_R17: sprintf(info->s, "R17:%08X", R17); break;
+ case CPUINFO_STR_REGISTER + V810_R18: sprintf(info->s, "R18:%08X", R18); break;
+ case CPUINFO_STR_REGISTER + V810_R19: sprintf(info->s, "R19:%08X", R19); break;
+ case CPUINFO_STR_REGISTER + V810_R20: sprintf(info->s, "R20:%08X", R20); break;
+ case CPUINFO_STR_REGISTER + V810_R21: sprintf(info->s, "R21:%08X", R21); break;
+ case CPUINFO_STR_REGISTER + V810_R22: sprintf(info->s, "R22:%08X", R22); break;
+ case CPUINFO_STR_REGISTER + V810_R23: sprintf(info->s, "R23:%08X", R23); break;
+ case CPUINFO_STR_REGISTER + V810_R24: sprintf(info->s, "R24:%08X", R24); break;
+ case CPUINFO_STR_REGISTER + V810_R25: sprintf(info->s, "R25:%08X", R25); break;
+ case CPUINFO_STR_REGISTER + V810_R26: sprintf(info->s, "R26:%08X", R26); break;
+ case CPUINFO_STR_REGISTER + V810_R27: sprintf(info->s, "R27:%08X", R27); break;
+ case CPUINFO_STR_REGISTER + V810_R28: sprintf(info->s, "R28:%08X", R28); break;
+ case CPUINFO_STR_REGISTER + V810_R29: sprintf(info->s, "R29:%08X", R29); break;
+ case CPUINFO_STR_REGISTER + V810_R30: sprintf(info->s, "R30:%08X", R30); break;
+ case CPUINFO_STR_REGISTER + V810_R31: sprintf(info->s, "R31:%08X", R31); break;
+ case CPUINFO_STR_REGISTER + V810_EIPC: sprintf(info->s, "EIPC :%08X", EIPC); break;
+ case CPUINFO_STR_REGISTER + V810_PSW: sprintf(info->s, "PSW :%08X", PSW); break;
+ case CPUINFO_STR_REGISTER + V810_EIPSW: sprintf(info->s, "EIPSW:%08X", EIPSW); break;
+ case CPUINFO_STR_REGISTER + V810_FEPC: sprintf(info->s, "FEPC :%08X", FEPC); break;
+ case CPUINFO_STR_REGISTER + V810_FEPSW: sprintf(info->s, "FEPSW:%08X", FEPSW); break;
+ case CPUINFO_STR_REGISTER + V810_ECR: sprintf(info->s, "ECR :%08X", ECR); break;
+ case CPUINFO_STR_REGISTER + V810_PIR: sprintf(info->s, "PIR :%08X", PIR); break;
+ case CPUINFO_STR_REGISTER + V810_TKCW: sprintf(info->s, "TKCW :%08X", TKCW); break;
+ case CPUINFO_STR_REGISTER + V810_CHCW: sprintf(info->s, "CHCW :%08X", CHCW); break;
+ case CPUINFO_STR_REGISTER + V810_ADTRE: sprintf(info->s, "ADTRE:%08X", ADTRE); break;
+ }
+}
diff --git a/src/emu/cpu/v810/v810.h b/src/emu/cpu/v810/v810.h
new file mode 100644
index 00000000000..2b522609f88
--- /dev/null
+++ b/src/emu/cpu/v810/v810.h
@@ -0,0 +1,128 @@
+#ifndef V810_H
+#define V810_H
+
+#include "cpuintrf.h"
+
+extern int v810_ICount;
+
+void v810_get_info(UINT32, cpuinfo*);
+
+#define R_B(addr) (program_read_byte_32le(addr))
+#define R_H(addr) (program_read_word_32le(addr))
+#define R_W(addr) (program_read_dword_32le(addr))
+
+
+#define W_B(addr, val) (program_write_byte_32le(addr,val))
+#define W_H(addr, val) (program_write_word_32le(addr,val))
+#define W_W(addr, val) (program_write_dword_32le(addr,val))
+
+
+#define RIO_B(addr) (io_read_byte_32le(addr))
+#define RIO_H(addr) (io_read_word_32le(addr))
+#define RIO_W(addr) (io_read_dword_32le(addr))
+
+
+#define WIO_B(addr, val) (io_write_byte_32le(addr,val))
+#define WIO_H(addr, val) (io_write_word_32le(addr,val))
+#define WIO_W(addr, val) (io_write_dword_32le(addr,val))
+
+#define R_OP(addr) (R_H(addr))
+
+#define GET1 (OP&0x1f)
+#define GET2 ((OP>>5)&0x1f)
+#define I5(x) (((x)&0x1f)|(((x)&0x10)?0xffffffe0:0))
+#define UI5(x) ((x)&0x1f)
+#define I16(x) (((x)&0xffff)|(((x)&0x8000)?0xffff0000:0))
+#define UI16(x) ((x)&0xffff)
+#define D16(x) (((x)&0xffff)|(((x)&0x8000)?0xffff0000:0))
+#define D26(x,y) ((y)|((x&0x3ff)<<16 )|((x&0x200)?0xfc000000:0))
+#define D9(x) ((x&0x1ff)|((x&0x100)?0xfffffe00:0))
+#define SO(opcode) ((opcode)&0xfc00)>>10)
+
+#define CHECK_CY(x) PSW=(PSW & ~8)|(((x) & (((UINT64)1) << 32)) ? 8 : 0)
+#define CHECK_OVADD(x,y,z) PSW=(PSW & ~0x00000004) |(( ((x) ^ (z)) & ((y) ^ (z)) & 0x80000000) ? 4: 0)
+#define CHECK_OVSUB(x,y,z) PSW=(PSW & ~0x00000004) |(( ((y) ^ (z)) & ((x) ^ (y)) & 0x80000000) ? 4: 0)
+#define CHECK_ZS(x) PSW=(PSW & ~3)|((UINT32)(x)==0)|(((x)&0x80000000) ? 2: 0)
+
+
+#define ADD(dst, src) { UINT64 res=(UINT64)(dst)+(UINT64)(src); SetCF(res); SetOF_Add(res,src,dst); SetSZPF(res); dst=(UINT32)res; }
+#define SUB(dst, src) { UINT64 res=(UINT64)(dst)-(INT64)(src); SetCF(res); SetOF_Sub(res,src,dst); SetSZPF(res); dst=(UINT32)res; }
+
+#ifdef MAME_DEBUG
+offs_t v810_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+enum
+{
+ V810_R0=1,
+ V810_R1,
+ V810_R2, /* R2 - handler stack pointer */
+ V810_SP, /* R3 - stack pointer */
+ V810_R4, /* R4 - global pointer */
+ V810_R5, /* R5 - text pointer */
+ V810_R6,
+ V810_R7,
+ V810_R8,
+ V810_R9,
+ V810_R10,
+ V810_R11,
+ V810_R12,
+ V810_R13,
+ V810_R14,
+ V810_R15,
+ V810_R16,
+ V810_R17,
+ V810_R18,
+ V810_R19,
+ V810_R20,
+ V810_R21,
+ V810_R22,
+ V810_R23,
+ V810_R24,
+ V810_R25,
+ V810_R26,
+ V810_R27,
+ V810_R28,
+ V810_R29,
+ V810_R30,
+ V810_R31, /* R31 - link pointer */
+
+ /* System Registers */
+ V810_EIPC, /* Exception/interrupt saving - PC */
+ V810_EIPSW,/* Exception/interrupt saving - PSW */
+ V810_FEPC, /* Duplexed exception/NMI saving - PC */
+ V810_FEPSW,/* Duplexed exception/NMI saving - PSW */
+ V810_ECR, /* Exception cause register */
+ V810_PSW, /* Program status word */
+ V810_PIR, /* Processor ID register */
+ V810_TKCW, /* Task control word */
+ V810_res08,
+ V810_res09,
+ V810_res10,
+ V810_res11,
+ V810_res12,
+ V810_res13,
+ V810_res14,
+ V810_res15,
+ V810_res16,
+ V810_res17,
+ V810_res18,
+ V810_res19,
+ V810_res20,
+ V810_res21,
+ V810_res22,
+ V810_res23,
+ V810_CHCW, /* Cache control word */
+ V810_ADTRE, /* Address trap register */
+ V810_res26,
+ V810_res27,
+ V810_res28,
+ V810_res29,
+ V810_res30,
+ V810_res31,
+
+ V810_PC
+};
+#endif
+
+
diff --git a/src/emu/cpu/v810/v810dasm.c b/src/emu/cpu/v810/v810dasm.c
new file mode 100644
index 00000000000..2cf52742d16
--- /dev/null
+++ b/src/emu/cpu/v810/v810dasm.c
@@ -0,0 +1,168 @@
+/********************************************
+ NEC V810 (upd70732) disassembler
+ Tomasz Slanina - analog[at]op.pl
+*******************************************/
+
+#include <math.h>
+#include "debugger.h"
+#include "v810.h"
+
+const static char *dRegs[]={
+"R0","R1","R2","SP","R4",
+"R5","R6","R7","R8","R9",
+"R10","R11","R12","R13",
+"R14","R15","R16","R17",
+"R18","R19","R20","R21",
+"R22","R23","R24","R25",
+"R26","R27","R28","R29",
+"R30","R31",
+"EIPC","EIPSW","FEPC","FEPSW","ECR",
+"PSW","PIR","TKCW","<Unk>","<Unk>",
+"<Unk>","<Unk>","<Unk>","<Unk>","<Unk>",
+"<Unk>","<Unk>","<Unk>","<Unk>","<Unk>",
+"<Unk>","<Unk>","<Unk>","<Unk>","CHCW","ADTRE",
+"<Unk>","<Unk>","<Unk>","<Unk>","<Unk>","<Unk>"
+};
+
+#define GET1s(opcode) dRegs[(opcode)&0x1f]
+#define GET2s(opcode) dRegs[((opcode)>>5)&0x1f]
+#define GETRs(opcode) dRegs[32+((opcode)&0x1f)]
+
+offs_t v810_dasm(char *buffer, offs_t oldpc, const UINT8 *oprom, const UINT8 *opram)
+{
+ UINT32 flags = 0;
+ UINT32 opc,opc2;
+ UINT32 pc=oldpc;
+ unsigned size;
+ opc = R_OP(pc);
+ opc2 = R_OP(pc+2);
+
+ switch(opc>>10)
+ {
+ case 0x00: sprintf(buffer,"MOV %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x01: sprintf(buffer,"ADD %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x02: sprintf(buffer,"SUB %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x03: sprintf(buffer,"CMP %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x04: sprintf(buffer,"SHL %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x05: sprintf(buffer,"SHR %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x06: sprintf(buffer,"JMP [%s]",GET1s(opc)); size=2; if ((opc&0x1f) == 31) flags = DASMFLAG_STEP_OUT; break;
+ case 0x07: sprintf(buffer,"SAR %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x08: sprintf(buffer,"MUL %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x09: sprintf(buffer,"DIV %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x0a: sprintf(buffer,"MULU %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x0b: sprintf(buffer,"DIVU %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x0c: sprintf(buffer,"OR %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x0d: sprintf(buffer,"AND %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x0e: sprintf(buffer,"XOR %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x0f: sprintf(buffer,"NOT %s,%s",GET1s(opc),GET2s(opc)); size=2; break;
+ case 0x10: sprintf(buffer,"MOV %X,%s",I5(opc),GET2s(opc)); size=2; break;
+ case 0x11: sprintf(buffer,"ADD %X,%s",I5(opc),GET2s(opc)); size=2; break;
+ case 0x12: sprintf(buffer,"SETF %X,%s",I5(opc),GET2s(opc)); size=2; break;
+ case 0x13: sprintf(buffer,"CMP %X,%s",I5(opc),GET2s(opc)); size=2; break;
+ case 0x14: sprintf(buffer,"SHL %X,%s",UI5(opc),GET2s(opc)); size=2; break;
+ case 0x15: sprintf(buffer,"SHR %X,%s",UI5(opc),GET2s(opc)); size=2; break;
+ case 0x16: sprintf(buffer,"EI"); size=2; break;
+ case 0x17: sprintf(buffer,"SAR %X,%s",UI5(opc),GET2s(opc)); size=2; break;
+ case 0x18: sprintf(buffer,"TRAP %X",I5(opc)); size=2; break;
+ case 0x19: sprintf(buffer,"RETI"); size=2; flags = DASMFLAG_STEP_OUT; break;
+ case 0x1a: sprintf(buffer,"HALT"); size=2; break;
+ case 0x1b: sprintf(buffer,"Unk 0x1B"); size=2; break;
+ case 0x1c: sprintf(buffer,"LDSR %s,%s",GET2s(opc),GETRs(opc));size=2; break;
+ case 0x1d: sprintf(buffer,"STSR %s,%s",GETRs(opc),GET2s(opc));size=2; break;
+ case 0x1e: sprintf(buffer,"DI"); size=2; break;
+ case 0x1f:
+ switch(opc&0x1f)
+ {
+ case 0x00: sprintf(buffer,"SCH0BSU"); break;
+ case 0x01: sprintf(buffer,"SCH0BSD"); break;
+ case 0x02: sprintf(buffer,"SCH1BSU"); break;
+ case 0x03: sprintf(buffer,"SCH1BSD"); break;
+ case 0x04: sprintf(buffer,"UnkS 4"); break;
+ case 0x05: sprintf(buffer,"UnkS 5"); break;
+ case 0x06: sprintf(buffer,"UnkS 6"); break;
+ case 0x08: sprintf(buffer,"ORBSU"); break;
+ case 0x09: sprintf(buffer,"ANDBSU"); break;
+ case 0x0a: sprintf(buffer,"XORBSU"); break;
+ case 0x0b: sprintf(buffer,"MOVBSU"); break;
+ case 0x0c: sprintf(buffer,"ORNBSU"); break;
+ case 0x0d: sprintf(buffer,"ANDNBSU"); break;
+ case 0x0e: sprintf(buffer,"XORNBSU"); break;
+ case 0x0f: sprintf(buffer,"NOTBSU"); break;
+ default: sprintf(buffer,"UnkBS 0x%X",opc&0x1f); break;
+ }
+ size=2;
+ break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27: switch( (opc>>9) &0xf)
+ {
+ case 0x0: sprintf(buffer,"BV %X",pc+D9(opc)); break;
+ case 0x1: sprintf(buffer,"BL %X",pc+D9(opc)); break;
+ case 0x2: sprintf(buffer,"BE %X",pc+D9(opc)); break;
+ case 0x3: sprintf(buffer,"BNH %X",pc+D9(opc)); break;
+ case 0x4: sprintf(buffer,"BN %X",pc+D9(opc)); break;
+ case 0x5: sprintf(buffer,"BR %X",pc+D9(opc)); break;
+ case 0x6: sprintf(buffer,"BLT %X",pc+D9(opc)); break;
+ case 0x7: sprintf(buffer,"BLE %X",pc+D9(opc)); break;
+ case 0x8: sprintf(buffer,"BNV %X",pc+D9(opc)); break;
+ case 0x9: sprintf(buffer,"BNL %X",pc+D9(opc)); break;
+ case 0xa: sprintf(buffer,"BNE %X",pc+D9(opc)); break;
+ case 0xb: sprintf(buffer,"BH %X",pc+D9(opc)); break;
+ case 0xc: sprintf(buffer,"BP %X",pc+D9(opc)); break;
+ case 0xd: sprintf(buffer,"NOP"); break;
+ case 0xe: sprintf(buffer,"BGE %X",pc+D9(opc)); break;
+ case 0xf: sprintf(buffer,"BGT %X",pc+D9(opc)); break;
+ }
+ size=2;
+ break;
+
+ case 0x28: sprintf(buffer,"MOVEA %X, %s, %s",I16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x29: sprintf(buffer,"ADDI %X, %s, %s",I16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x2a: sprintf(buffer,"JR %X",pc+D26(opc,opc2));size=4; break;
+ case 0x2b: sprintf(buffer,"JAL %X",pc+D26(opc,opc2));size=4; flags = DASMFLAG_STEP_OVER; break;
+ case 0x2c: sprintf(buffer,"ORI %X, %s, %s",UI16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x2d: sprintf(buffer,"ANDI %X, %s, %s",UI16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x2e: sprintf(buffer,"XORI %X, %s, %s",UI16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x2f: sprintf(buffer,"MOVHI %X, %s, %s",UI16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x30: sprintf(buffer,"LDB %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x31: sprintf(buffer,"LDH %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x32: sprintf(buffer,"Unk 0x32"); size=2; break;
+ case 0x33: sprintf(buffer,"LDW %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x34: sprintf(buffer,"STB %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break;
+ case 0x35: sprintf(buffer,"STH %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break;
+ case 0x36: sprintf(buffer,"Unk 0x36"); size=2; break;
+ case 0x37: sprintf(buffer,"STW %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break;
+ case 0x38: sprintf(buffer,"INB %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x39: sprintf(buffer,"INH %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x3a: sprintf(buffer,"CAXI %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+ case 0x3b: sprintf(buffer,"INW %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break;
+
+ case 0x3c: sprintf(buffer,"OUTB %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break;
+ case 0x3d: sprintf(buffer,"OUTH %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break;
+ case 0x3e:
+ switch((opc2&0xfc00)>>10)
+ {
+ case 0x0: sprintf(buffer,"CMPF.S %s, %s",GET1s(opc),GET2s(opc)); break;
+ case 0x2: sprintf(buffer,"CVT.WS %s, %s",GET1s(opc),GET2s(opc)); break;
+ case 0x3: sprintf(buffer,"CVT.SW %s, %s",GET1s(opc),GET2s(opc)); break;
+ case 0x4: sprintf(buffer,"ADDF.S %s, %s",GET1s(opc),GET2s(opc)); break;
+ case 0x5: sprintf(buffer,"SUBF.S %s, %s",GET1s(opc),GET2s(opc)); break;
+ case 0x6: sprintf(buffer,"MULF.S %s, %s",GET1s(opc),GET2s(opc)); break;
+ case 0x7: sprintf(buffer,"DIVF.S %s, %s",GET1s(opc),GET2s(opc)); break;
+ case 0xb: sprintf(buffer,"TRNC.SW %s, %s",GET1s(opc),GET2s(opc)); break;
+ default : sprintf(buffer,"Unkf 0x%X",(opc2&0xfc00)>>10); break;
+ }
+ size=4;
+ break;
+ case 0x3f: sprintf(buffer,"OUTW %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break;
+
+ default : size=2;
+ }
+ return size | flags | DASMFLAG_SUPPORTED;
+}
+
diff --git a/src/emu/cpu/x64drc.c b/src/emu/cpu/x64drc.c
new file mode 100644
index 00000000000..8c8218148b5
--- /dev/null
+++ b/src/emu/cpu/x64drc.c
@@ -0,0 +1,629 @@
+/***************************************************************************
+
+ x64drc.c
+
+ x64 Dynamic recompiler support routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Windows x64 conventions:
+
+ Register Status Use
+ -------- ------ ---
+ RAX Volatile Return value register
+ RCX Volatile First integer argument
+ RDX Volatile Second integer argument
+ R8 Volatile Third integer argument
+ R9 Volatile Fourth integer argument
+ R10:R11 Volatile Must be preserved as needed by caller; used in syscall/sysret instructions
+ R12:R15 Nonvolatile Must be preserved by callee
+ RDI Nonvolatile Must be preserved by callee
+ RSI Nonvolatile Must be preserved by callee
+ RBX Nonvolatile Must be preserved by callee
+ RBP Nonvolatile May be used as a frame pointer; must be preserved by callee
+ RSP Nonvolatile Stack pointer
+
+ XMM0 Volatile First FP argument
+ XMM1 Volatile Second FP argument
+ XMM2 Volatile Third FP argument
+ XMM3 Volatile Fourth FP argument
+ XMM4:XMM5 Volatile Must be preserved as needed by caller
+ XMM6:XMM15 Nonvolatile Must be preserved as needed by callee.
+
+
+ Linux/MacOS x64 conventions:
+
+ Register Status Use
+ -------- ------ ---
+ RAX Volatile Return value register
+ RDI Volatile First integer argument
+ RSI Volatile Second integer argument
+ RDX Volatile Third integer argument
+ RCX Volatile Fourth integer argument
+ R8 Volatile Fifth integer argument
+ R9 Volatile Sixth integer argument
+ R10:R11 Volatile Must be preserved as needed by caller
+ R12:R15 Nonvolatile Must be preserved by callee
+ RBX Nonvolatile Must be preserved by callee
+ RBP Nonvolatile Must be preserved by callee
+ RSP Nonvolatile Stack pointer
+
+ XMM0 Volatile First FP argument
+ XMM1 Volatile Second FP argument
+ XMM2 Volatile Third FP argument
+ XMM3 Volatile Fourth FP argument
+ XMM4 Volatile Fifth FP argument
+ XMM5 Volatile Sixth FP argument
+ XMM6:XMM15 Volatile Must be preserved as needed by caller.
+
+***************************************************************************/
+
+#include "cpuintrf.h"
+#include "x64drc.h"
+#include "debugger.h"
+
+#include <stddef.h>
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define MXCSR_VALUE(x) (0x1fc0 | ((x) << 14))
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void append_entry_point(drc_core *drc);
+static void append_exit_point(drc_core *drc);
+static void recompile_code(drc_core *drc);
+static void append_recompile(drc_core *drc);
+static void append_flush(drc_core *drc);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ allocate_l2_table - allocate an L2 table
+ if necessary
+-------------------------------------------------*/
+
+INLINE void allocate_l2_table(drc_core *drc, UINT32 l1index)
+{
+ if (drc->lookup_l1[l1index] == drc->lookup_l2_recompile)
+ {
+ /* create a new copy of the recompile table */
+ drc->lookup_l1[l1index] = drc_alloc(drc, sizeof(*drc->lookup_l2_recompile) << drc->l2bits);
+ memcpy(drc->lookup_l1[l1index], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) << drc->l2bits);
+ }
+}
+
+
+/***************************************************************************
+ EXTERNAL INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+ drc_init - initialize the DRC core
+-------------------------------------------------*/
+
+drc_core *drc_init(UINT8 cpunum, drc_config *config)
+{
+ int address_bits = config->address_bits;
+ int effective_address_bits = address_bits - config->lsbs_to_ignore;
+ drc_core *drc;
+ int i;
+
+ /* the drc structure lives at the start of the cache */
+ drc = (drc_core *)config->cache_base;
+ memset(drc, 0, sizeof(*drc));
+
+ /* copy in relevant data from the config */
+ drc->baseptr = config->baseptr;
+ drc->pcptr = config->pcptr;
+ drc->cb_reset = config->cb_reset;
+ drc->cb_recompile = config->cb_recompile;
+ drc->cb_entrygen = config->cb_entrygen;
+ drc->mxcsr_curr = MXCSR_VALUE(FPRND_NEAR);
+
+ /* configure cache */
+ drc->cache_base = (UINT8 *)config->cache_base + sizeof(*drc);
+ drc->cache_size = config->cache_size - sizeof(*drc);
+ drc->cache_end = drc->cache_base + drc->cache_size;
+ drc->cache_danger = drc->cache_end - 65536;
+
+ /* compute shifts and masks */
+ drc->l1bits = effective_address_bits / 2;
+ drc->l2bits = effective_address_bits - drc->l1bits;
+ drc->l1shift = config->lsbs_to_ignore + drc->l2bits;
+ drc->l2mask = ((1 << drc->l2bits) - 1) << config->lsbs_to_ignore;
+ drc->l2scale = sizeof(x86code *) >> config->lsbs_to_ignore;
+
+ /* configure the MXCSR states */
+ for (i = 0; i < 4; i++)
+ drc->mxcsr_values[i] = MXCSR_VALUE(i);
+
+ /* allocate lookup tables out of the cache */
+ drc->lookup_l1 = drc_alloc(drc, sizeof(*drc->lookup_l1) << drc->l1bits);
+ drc->lookup_l2_recompile = drc_alloc(drc, sizeof(*drc->lookup_l2_recompile) << drc->l2bits);
+ if (drc->lookup_l1 == NULL || drc->lookup_l2_recompile == NULL)
+ goto error;
+ memset(drc->lookup_l1, 0, sizeof(*drc->lookup_l1) << drc->l1bits);
+ memset(drc->lookup_l2_recompile, 0, sizeof(*drc->lookup_l2_recompile) << drc->l2bits);
+
+ /* allocate the sequence and tentative lists */
+ drc->sequence_count_max = config->max_instructions * 2;
+ drc->sequence_list = malloc(drc->sequence_count_max * sizeof(*drc->sequence_list));
+ if (drc->sequence_list == NULL)
+ goto error;
+
+ drc->tentative_count_max = config->max_instructions * 2;
+ drc->tentative_list = malloc(drc->tentative_count_max * sizeof(*drc->tentative_list));
+ if (drc->tentative_list == NULL)
+ goto error;
+
+ /* get pointers to external C functions */
+#ifdef MAME_DEBUG
+ drc->mame_debug_hook = (x86code *)mame_debug_hook;
+#endif
+ drc->recompile_code = (x86code *)recompile_code;
+ drc->drc_cache_reset = (x86code *)drc_cache_reset;
+ return drc;
+
+error:
+ if (drc != NULL)
+ drc_exit(drc);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ drc_alloc - allocate memory from the top of
+ the DRC cache
+-------------------------------------------------*/
+
+void *drc_alloc(drc_core *drc, size_t amount)
+{
+ /* if we don't have enough space, reset the cache */
+ if (drc->cache_top >= drc->cache_danger - amount)
+ drc_cache_reset(drc);
+
+ /* if we still don't have enough space, fail */
+ if (drc->cache_top >= drc->cache_danger - amount)
+ return NULL;
+
+ /* adjust the end and danger values downward */
+ drc->cache_end -= amount;
+ drc->cache_danger -= amount;
+ return drc->cache_end;
+}
+
+
+/*-------------------------------------------------
+ drc_cache_reset - reset the DRC cache
+-------------------------------------------------*/
+
+void drc_cache_reset(drc_core *drc)
+{
+ int i;
+
+ /* reset the cache and add the basics */
+ drc->cache_top = drc->cache_base;
+
+ /* append the core entry points to the fresh cache */
+ drc->entry_point = (void (*)(void *))(FPTR)drc->cache_top;
+ append_entry_point(drc);
+ drc->exit_point = drc->cache_top;
+ append_exit_point(drc);
+ drc->recompile = drc->cache_top;
+ append_recompile(drc);
+ drc->dispatch = drc->cache_top;
+ drc_append_dispatcher(drc);
+ drc->flush = drc->cache_top;
+ append_flush(drc);
+
+ /* populate the recompile table */
+ for (i = 0; i < (1 << drc->l2bits); i++)
+ drc->lookup_l2_recompile[i] = drc->recompile;
+
+ /* reset all the l1 tables */
+ for (i = 0; i < (1 << drc->l1bits); i++)
+ {
+ /* point NULL entries to the generic recompile table */
+ if (drc->lookup_l1[i] == NULL)
+ drc->lookup_l1[i] = drc->lookup_l2_recompile;
+
+ /* reset allocated tables to point all entries back to the recompiler */
+ else if (drc->lookup_l1[i] != drc->lookup_l2_recompile)
+ memcpy(drc->lookup_l1[i], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) << drc->l2bits);
+ }
+
+ /* call back to the host */
+ if (drc->cb_reset != NULL)
+ (*drc->cb_reset)(drc);
+}
+
+
+/*-------------------------------------------------
+ drc_execute - execute generated code
+-------------------------------------------------*/
+
+void drc_execute(drc_core *drc)
+{
+ (*drc->entry_point)(drc->baseptr);
+}
+
+
+/*-------------------------------------------------
+ drc_exit - release resources allocated by
+ the DRC core
+-------------------------------------------------*/
+
+void drc_exit(drc_core *drc)
+{
+ /* free the lists */
+ if (drc->sequence_list != NULL)
+ free(drc->sequence_list);
+ if (drc->tentative_list != NULL)
+ free(drc->tentative_list);
+}
+
+
+/*-------------------------------------------------
+ drc_begin_sequence - begin code generation
+ for a particular PC
+-------------------------------------------------*/
+
+void drc_begin_sequence(drc_core *drc, UINT32 pc)
+{
+ /* reset the sequence and tentative counts */
+ drc->sequence_count = 0;
+ drc->tentative_count = 0;
+}
+
+
+/*-------------------------------------------------
+ drc_add_entry_point - add a new external
+ entry point for a given PC
+-------------------------------------------------*/
+
+int drc_add_entry_point(drc_core *drc, UINT32 pc, int override)
+{
+ UINT32 l1index = pc >> drc->l1shift;
+ UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / sizeof(x86code *);
+ int was_occupied;
+
+ /* allocate memory if necessary */
+ allocate_l2_table(drc, l1index);
+
+ /* in case anybody was jumping directly to this code entry, replace
+ the code with a jmp to the new code */
+ was_occupied = (drc->lookup_l1[l1index][l2index] != drc->recompile);
+ if (was_occupied && override)
+ {
+ x86code *dest = drc->lookup_l1[l1index][l2index];
+ emit_jmp(&dest, drc->cache_top);
+ }
+
+ /* note the current location for this instruction */
+ if (!was_occupied || override)
+ drc->lookup_l1[l1index][l2index] = drc->cache_top;
+ return was_occupied;
+}
+
+
+/*------------------------------------------------------------------
+ drc_end_sequence
+------------------------------------------------------------------*/
+
+void drc_end_sequence(drc_core *drc)
+{
+ int i, j;
+
+ /* fix up any internal links */
+ for (i = 0; i < drc->tentative_count; i++)
+ {
+ for (j = 0; j < drc->sequence_count; j++)
+ if (drc->tentative_list[i].pc == drc->sequence_list[j].pc)
+ {
+ x86code *dest = drc->tentative_list[i].target;
+ emit_jmp(&dest, drc->sequence_list[j].target);
+ while (dest < drc->tentative_list[i].end)
+ emit_int_3(&dest);
+ break;
+ }
+ }
+}
+
+
+/*------------------------------------------------------------------
+ drc_register_code_at_cache_top
+------------------------------------------------------------------*/
+
+void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc)
+{
+ pc_ptr_pair *pair = &drc->sequence_list[drc->sequence_count++];
+ assert_always(drc->sequence_count <= drc->sequence_count_max, "drc_register_code_at_cache_top: too many instructions!");
+
+ pair->target = drc->cache_top;
+ pair->pc = pc;
+}
+
+
+/*------------------------------------------------------------------
+ drc_get_code_at_pc
+------------------------------------------------------------------*/
+
+x86code *drc_get_code_at_pc(drc_core *drc, UINT32 pc)
+{
+ UINT32 l1index = pc >> drc->l1shift;
+ UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / sizeof(x86code *);
+ x86code *codeptr = drc->lookup_l1[l1index][l2index];
+ return (codeptr != drc->recompile) ? codeptr : NULL;
+}
+
+
+/*------------------------------------------------------------------
+ drc_invalidate_code_range
+------------------------------------------------------------------*/
+
+void drc_invalidate_code_range(drc_core *drc, UINT32 startpc, UINT32 endpc)
+{
+ UINT32 startl1index = startpc >> drc->l1shift;
+ UINT32 startl2index = ((startpc & drc->l2mask) * drc->l2scale) / sizeof(x86code *);
+ UINT32 endl1index = endpc >> drc->l1shift;
+ UINT32 endl2index = ((endpc & drc->l2mask) * drc->l2scale) / sizeof(x86code *);
+ UINT32 curl1;
+
+ /* iterate over l1 bunches */
+ for (curl1 = startl1index; curl1 <= endl1index; curl1++)
+ {
+ x86code **l2table = drc->lookup_l1[curl1];
+ UINT32 l2start, l2end, curl2;
+
+ /* if this is already empty, skip it */
+ if (l2table == drc->lookup_l2_recompile)
+ continue;
+
+ /* determine start/stop for this range */
+ l2start = (curl1 == startl1index) ? startl2index : 0;
+ l2end = (curl1 == endl1index) ? endl2index : ((1 << drc->l2bits) - 1);
+
+ /* invalidate any code entries here */
+ for (curl2 = l2start; curl2 <= l2end; curl2++)
+ if (l2table[curl2] != drc->recompile)
+ {
+ /* overwrite code there with a jump to the recompiler in case we ever get there */
+ x86code *dest = l2table[curl2];
+// emit_int_3(&dest);
+ emit_jmp(&dest, drc->recompile);
+ l2table[curl2] = drc->recompile;
+ }
+ }
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_call_debugger
+------------------------------------------------------------------*/
+
+void drc_append_call_debugger(drc_core *drc)
+{
+#ifdef MAME_DEBUG
+ if (Machine->debug_mode)
+ emit_call_m64(DRCTOP, MDRC(&drc->mame_debug_hook)); // call mame_debug_hook
+#endif
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_dispatcher
+------------------------------------------------------------------*/
+
+void drc_append_dispatcher(drc_core *drc)
+{
+ /* target PC is in P1 on entry; we must keep P1 intact in case we jump to the recompile callback */
+ emit_mov_r32_r32(DRCTOP, REG_P2, REG_P1); // mov p2,p1
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_P1); // mov eax,p1
+ emit_shr_r32_imm(DRCTOP, REG_P2, drc->l1shift); // shr p2,l1shift
+ emit_mov_r64_m64(DRCTOP, REG_P2, MDRCISD(drc->lookup_l1, REG_P2, 8, 0)); // mov p2,[rbp+p2*8+l1lookup]
+ emit_and_r32_imm(DRCTOP, REG_EAX, drc->l2mask); // and eax,l2mask
+ emit_jmp_m64(DRCTOP, MBISD(REG_P2, REG_EAX, drc->l2scale, 0)); // jmp [p2 + eax*l2scale]
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_fixed_dispatcher
+------------------------------------------------------------------*/
+
+void drc_append_fixed_dispatcher(drc_core *drc, UINT32 pc, int loadpc)
+{
+ UINT32 l1index = pc >> drc->l1shift;
+ UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / sizeof(x86code *);
+
+ /* make sure we have an L2 table for this entry */
+ allocate_l2_table(drc, l1index);
+
+ /* emit a jump through the table entry */
+ if (loadpc)
+ emit_mov_r32_imm(DRCTOP, REG_P1, pc); // mov p1,pc
+ emit_jmp_m64(DRCTOP, MDRC(&drc->lookup_l1[l1index][l2index])); // jmp [lookup[l1index][l2index]]
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_tentative_fixed_dispatcher
+------------------------------------------------------------------*/
+
+void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc, int loadpc)
+{
+ pc_ptr_pair *pair = &drc->tentative_list[drc->tentative_count++];
+ assert_always(drc->tentative_count <= drc->tentative_count_max, "drc_append_tentative_fixed_dispatcher: too many tentative branches!");
+
+ pair->target = drc->cache_top;
+ pair->pc = newpc;
+ drc_append_fixed_dispatcher(drc, newpc, loadpc);
+ pair->end = drc->cache_top;
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_set_sse_rounding
+------------------------------------------------------------------*/
+
+void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex)
+{
+ emit_ldmxcsr_m32(DRCTOP, MDRCISD(&drc->mxcsr_values[0], regindex, 4, 0)); // ldmxcsr [mxcsr_values + reg*4]
+ emit_stmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_curr)); // stmxcsr [mxcsr_curr]
+}
+
+
+
+/*------------------------------------------------------------------
+ drc_append_set_temp_sse_rounding
+------------------------------------------------------------------*/
+
+void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding)
+{
+ emit_ldmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_values[rounding])); // ldmxcsr mxcsr_values[rounding]
+}
+
+
+
+/*------------------------------------------------------------------
+ drc_append_restore_sse_rounding
+------------------------------------------------------------------*/
+
+void drc_append_restore_sse_rounding(drc_core *drc)
+{
+ emit_ldmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr]
+}
+
+
+
+/***************************************************************************
+ INTERNAL CODEGEN
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ append_entry_point
+------------------------------------------------------------------*/
+
+static void append_entry_point(drc_core *drc)
+{
+ int pushbytes = 8 * (5 + (REG_NV5 != REG_NONE) + (REG_NV6 != REG_NONE));
+
+ /* save non-volatile registers */
+ emit_push_r64(DRCTOP, REG_NV0); // push nv0
+ emit_push_r64(DRCTOP, REG_NV1); // push nv1
+ emit_push_r64(DRCTOP, REG_NV2); // push nv2
+ emit_push_r64(DRCTOP, REG_NV3); // push nv3
+ emit_push_r64(DRCTOP, REG_NV4); // push nv4
+ if (REG_NV5 != REG_NONE) emit_push_r64(DRCTOP, REG_NV5); // push nv5
+ if (REG_NV6 != REG_NONE) emit_push_r64(DRCTOP, REG_NV6); // push nv6
+
+ /* stack frame:
+ 0x40/0x48 bytes of scratch space/alignment
+ 0x20 bytes for register parameter spilling in Windows ABI
+ */
+ emit_sub_r64_imm(DRCTOP, REG_RSP, 0x68 + (pushbytes % 16)); // sub rsp,0x68/0x70
+
+ /* parameter 1 is the baseptr; copy to RBP */
+ emit_mov_r64_r64(DRCTOP, REG_DRC, REG_P1); // mov rbp,p1
+
+ /* update the MXCSR register */
+ emit_stmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_save)); // stmxcsr [mxcsr_save]
+ emit_ldmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr]
+
+ /* continue performing entry generation duties */
+ if (drc->cb_entrygen != NULL)
+ (*drc->cb_entrygen)(drc); // additional entry point duties
+
+ /* reload the PC into P1 and dispatch */
+ emit_mov_r32_m32(DRCTOP, REG_P1, MDRC(drc->pcptr)); // mov p1,[pc]
+ drc_append_dispatcher(drc); // dispatch
+}
+
+
+/*------------------------------------------------------------------
+ append_exit_point
+------------------------------------------------------------------*/
+
+static void append_exit_point(drc_core *drc)
+{
+ int pushbytes = 8 * (5 + (REG_NV5 != REG_NONE) + (REG_NV6 != REG_NONE));
+
+ /* on exit, P1 must contain the final PC */
+ emit_mov_m32_r32(DRCTOP, MDRC(drc->pcptr), REG_P1); // mov [pc],p1
+
+ /* restore the MXCSR state */
+ emit_ldmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_save)); // ldmxcsr [mxcsr_save]
+
+ /* add 0x18 to RSP to get us back to the original stack pointer */
+ emit_add_r64_imm(DRCTOP, REG_RSP, 0x68 + (pushbytes % 16)); // add rsp,0x68/0x70
+
+ /* save non-volatile registers */
+ if (REG_NV6 != REG_NONE) emit_pop_r64(DRCTOP, REG_NV6); // pop nv6
+ if (REG_NV5 != REG_NONE) emit_pop_r64(DRCTOP, REG_NV5); // pop nv5
+ emit_pop_r64(DRCTOP, REG_NV4); // pop nv4
+ emit_pop_r64(DRCTOP, REG_NV3); // pop nv3
+ emit_pop_r64(DRCTOP, REG_NV2); // pop nv2
+ emit_pop_r64(DRCTOP, REG_NV1); // pop nv1
+ emit_pop_r64(DRCTOP, REG_NV0); // pop nv0
+ emit_ret(DRCTOP); // ret
+}
+
+
+/*------------------------------------------------------------------
+ recompile_code
+------------------------------------------------------------------*/
+
+static void recompile_code(drc_core *drc)
+{
+ /* if we're above the danger line, flush the cache before recompiling */
+ if (drc->cache_top >= drc->cache_danger)
+ drc_cache_reset(drc);
+
+ /* call the recompile callback */
+ (*drc->cb_recompile)(drc);
+}
+
+
+/*------------------------------------------------------------------
+ append_recompile
+------------------------------------------------------------------*/
+
+static void append_recompile(drc_core *drc)
+{
+ /* on entry, P1 must contain the PC that needs recompilation */
+ emit_mov_m32_r32(DRCTOP, MDRC(drc->pcptr), REG_P1); // mov [pc],p1
+ emit_lea_r64_m64(DRCTOP, REG_P1, MDRC(drc)); // lea p1,drc
+ emit_call_m64(DRCTOP, MDRC(&drc->recompile_code)); // call recompile_code
+ emit_mov_r32_m32(DRCTOP, REG_P1, MDRC(drc->pcptr)); // mov p1,[pc]
+ drc_append_dispatcher(drc); // dispatch
+}
+
+
+/*------------------------------------------------------------------
+ append_flush
+------------------------------------------------------------------*/
+
+static void append_flush(drc_core *drc)
+{
+ /* on entry, P1 must contain the PC that needs recompilation */
+ emit_mov_m32_r32(DRCTOP, MDRC(drc->pcptr), REG_P1); // mov [pc],p1
+ emit_lea_r64_m64(DRCTOP, REG_P1, MDRC(drc)); // lea p1,drc
+ emit_call_m64(DRCTOP, MDRC(&drc->drc_cache_reset)); // call drc_cache_reset
+ emit_mov_r32_m32(DRCTOP, REG_P1, MDRC(drc->pcptr)); // mov p1,[pc]
+ drc_append_dispatcher(drc); // dispatch
+}
diff --git a/src/emu/cpu/x64drc.h b/src/emu/cpu/x64drc.h
new file mode 100644
index 00000000000..7e61bccdc36
--- /dev/null
+++ b/src/emu/cpu/x64drc.h
@@ -0,0 +1,223 @@
+/***************************************************************************
+
+ x64drc.h
+
+ x64 Dynamic recompiler support routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __X64DRC_H__
+#define __X64DRC_H__
+
+#include "cpuintrf.h"
+#include "x86emit.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* ABI-specific configuration */
+#define REG_DRC REG_RBP /* pointer to DRC base */
+
+#ifdef X64_WINDOWS_ABI
+
+#define REG_P1 REG_RCX /* 1st function parameter */
+#define REG_P2 REG_RDX /* 2nd function parameter */
+#define REG_P3 REG_R8 /* 3rd function parameter */
+#define REG_P4 REG_R9 /* 4th function parameter */
+#define REG_V5 REG_R10 /* volatile register 5 */
+#define REG_V6 REG_R11 /* volatile register 6 */
+
+#define NUM_NVREG 7 /* number of non-volatile registers */
+#define REG_NV0 REG_RBX /* non-volatile reg 0 */
+#define REG_NV1 REG_RDI /* non-volatile reg 1 */
+#define REG_NV2 REG_RSI /* non-volatile reg 2 */
+#define REG_NV3 REG_R12 /* non-volatile reg 3 */
+#define REG_NV4 REG_R13 /* non-volatile reg 4 */
+#define REG_NV5 REG_R14 /* non-volatile reg 5 */
+#define REG_NV6 REG_R15 /* non-volatile reg 6 */
+
+#else
+
+#define REG_P1 REG_RDI /* 1st function parameter */
+#define REG_P2 REG_RSI /* 2nd function parameter */
+#define REG_P3 REG_RDX /* 3rd function parameter */
+#define REG_P4 REG_RCX /* 4th function parameter */
+#define REG_V5 REG_R10 /* volatile register 5 */
+#define REG_V6 REG_R11 /* volatile register 6 */
+
+#define NUM_NVREG 5 /* number of non-volatile registers */
+#define REG_NV0 REG_RBX /* non-volatile reg 0 */
+#define REG_NV1 REG_R12 /* non-volatile reg 1 */
+#define REG_NV2 REG_R13 /* non-volatile reg 2 */
+#define REG_NV3 REG_R14 /* non-volatile reg 3 */
+#define REG_NV4 REG_R15 /* non-volatile reg 4 */
+#define REG_NV5 REG_NONE /* non-volatile reg 5 */
+#define REG_NV6 REG_NONE /* non-volatile reg 6 */
+
+#endif
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* PC and pointer pair */
+typedef struct _pc_ptr_pair pc_ptr_pair;
+struct _pc_ptr_pair
+{
+ UINT32 pc;
+ x86code * target;
+ x86code * end;
+};
+
+
+/* core interface structure for the drc common code */
+typedef struct _drc_core drc_core;
+struct _drc_core
+{
+ /* cache parameters */
+ x86code * cache_base; /* base pointer to the compiler cache */
+ x86code * cache_top; /* current top of cache */
+ x86code * cache_danger; /* high water mark for the end */
+ x86code * cache_end; /* end of cache memory */
+ size_t cache_size; /* cache allocated size */
+
+ /* hash table lookups */
+ x86code *** lookup_l1; /* level 1 lookup */
+ x86code ** lookup_l2_recompile; /* level 2 lookup populated with recompile pointers */
+ UINT8 l1bits; /* number of bits in level 1 lookup */
+ UINT8 l2bits; /* number of bits in level 2 lookup */
+ UINT8 l1shift; /* shift to go from PC to level 1 lookup */
+ UINT32 l2mask; /* mask to go from PC to level 2 lookup */
+ UINT8 l2scale; /* scale to get from masked PC value to final level 2 lookup */
+
+ /* entry point for calling from C code */
+ void (*entry_point)(void *); /* pointer to asm entry point */
+
+ /* base pointer for memory accesses */
+ void * baseptr; /* pointer to base; all cache must be accessible from here */
+
+ /* internal subroutines generated in the cache */
+ x86code * exit_point; /* exit out of the DRC engine */
+ x86code * recompile; /* pointer to recompile jump point */
+ x86code * dispatch; /* pointer to dispatch jump point */
+ x86code * flush; /* pointer to flush jump point */
+
+ /* pointers to external C code */
+ x86code * mame_debug_hook; /* pointer to mame_debug_hook function */
+ x86code * recompile_code; /* pointer to recompile_code function */
+ x86code * drc_cache_reset; /* pointer to drc_cache_reset function */
+
+ /* pointers to the PC */
+ UINT32 * pcptr; /* pointer to where the PC is stored */
+
+ /* save areas for the MXCSR register */
+ UINT32 mxcsr_curr; /* current SSE control word */
+ UINT32 mxcsr_save; /* saved SSE control word */
+ UINT32 mxcsr_values[4]; /* array of values for different modes */
+
+ /* internal lists of sequences and tentative branches */
+ pc_ptr_pair * sequence_list; /* PC/pointer sets for the current instruction sequence */
+ UINT32 sequence_count; /* number of instructions in the current sequence */
+ UINT32 sequence_count_max; /* max number of instructions in the current sequence */
+ pc_ptr_pair * tentative_list; /* PC/pointer sets for tentative branches */
+ UINT32 tentative_count; /* number of tentative branches */
+ UINT32 tentative_count_max; /* max number of tentative branches */
+
+ /* CPU-specific callbacks */
+ void (*cb_reset)(struct _drc_core *drc); /* callback when the cache is reset */
+ void (*cb_recompile)(struct _drc_core *drc); /* callback when code needs to be recompiled */
+ void (*cb_entrygen)(struct _drc_core *drc); /* callback before generating the dispatcher on entry */
+};
+
+
+/* configuration structure for the drc common code */
+typedef struct _drc_config drc_config;
+struct _drc_config
+{
+ void * cache_base; /* base of cache */
+ UINT32 cache_size; /* size of cache */
+ UINT32 max_instructions; /* maximum instructions per sequence */
+ UINT8 address_bits; /* number of live address bits in the PC */
+ UINT8 lsbs_to_ignore; /* number of LSBs to ignore on the PC */
+
+ void * baseptr; /* pointer to base; all cache must be accessible from here */
+ UINT32 * pcptr; /* pointer to where the PC is stored */
+
+ void (*cb_reset)(drc_core *drc); /* callback when the cache is reset */
+ void (*cb_recompile)(drc_core *drc); /* callback when code needs to be recompiled */
+ void (*cb_entrygen)(drc_core *drc); /* callback before generating the dispatcher on entry */
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* use this macro in emit_* instructions to make them shorter */
+#define DRCTOP &drc->cache_top
+
+/* memory references to DRC-relative data */
+#define MDRC(x) MBD(REG_DRC, drcrel32(drc->baseptr, (x)))
+#define MDRCD(x, disp) MBD(REG_DRC, drcrel32(drc->baseptr, (x)) + (disp))
+#define MDRCISD(x, index, scale, disp) MBISD(REG_DRC, (index), (scale), drcrel32(drc->baseptr, (x)) + (disp))
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* init/shutdown */
+drc_core *drc_init(UINT8 cpunum, drc_config *config);
+void *drc_alloc(drc_core *drc, size_t amount);
+void drc_cache_reset(drc_core *drc);
+void drc_execute(drc_core *drc);
+void drc_exit(drc_core *drc);
+
+/* code management */
+void drc_begin_sequence(drc_core *drc, UINT32 pc);
+int drc_add_entry_point(drc_core *drc, UINT32 pc, int override);
+void drc_end_sequence(drc_core *drc);
+void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc);
+x86code *drc_get_code_at_pc(drc_core *drc, UINT32 pc);
+void drc_invalidate_code_range(drc_core *drc, UINT32 startpc, UINT32 endpc);
+
+/* standard appendages */
+void drc_append_dispatcher(drc_core *drc);
+void drc_append_fixed_dispatcher(drc_core *drc, UINT32 newpc, int loadpc);
+void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc, int loadpc);
+void drc_append_call_debugger(drc_core *drc);
+void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex);
+void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding);
+void drc_append_restore_sse_rounding(drc_core *drc);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE INT32 drcrel32(void *base, void *ptr)
+{
+ INT64 delta = (UINT8 *)ptr - (UINT8 *)base;
+ assert((INT32)delta == delta);
+ return (INT32)delta;
+}
+
+INLINE void *drcrelptr(drc_core *drc, INT32 offset)
+{
+ return (UINT8 *)drc + offset;
+}
+
+#endif /* __X64DRC_H__ */
diff --git a/src/emu/cpu/x86drc.c b/src/emu/cpu/x86drc.c
new file mode 100644
index 00000000000..5092ee70d5c
--- /dev/null
+++ b/src/emu/cpu/x86drc.c
@@ -0,0 +1,767 @@
+/***************************************************************************
+
+ x86drc.c
+
+ x86 Dynamic recompiler support routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "cpuintrf.h"
+#include "x86drc.h"
+#include "debugger.h"
+
+#define LOG_DISPATCHES 0
+#define BREAK_ON_MODIFIED_CODE 0
+
+
+
+
+static UINT16 fp_control[4] = { 0x023f, 0x063f, 0x0a3f, 0x0e3f };
+static UINT32 sse_control[4] = { 0x9fc0, 0xbfc0, 0xdfc0, 0xffc0 };
+
+
+static void append_entry_point(drc_core *drc);
+static void append_recompile(drc_core *drc);
+static void append_flush(drc_core *drc);
+static void append_out_of_cycles(drc_core *drc);
+
+#if LOG_DISPATCHES
+static void log_dispatch(drc_core *drc);
+#endif
+
+
+
+/***************************************************************************
+ EXTERNAL INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+ drc_init - initialize the DRC core
+-------------------------------------------------*/
+
+drc_core *drc_init(UINT8 cpunum, drc_config *config)
+{
+ int address_bits = config->address_bits;
+ int effective_address_bits = address_bits - config->lsbs_to_ignore;
+ UINT8 cache_allocated = FALSE;
+ drc_core *drc = NULL;
+
+ /* allocate memory */
+ if (config->cache_base == NULL)
+ {
+ config->cache_base = osd_alloc_executable(config->cache_size);
+ if (config->cache_base == NULL)
+ goto error;
+ cache_allocated = TRUE;
+ }
+
+ /* the drc structure lives at the start of the cache */
+ drc = (drc_core *)config->cache_base;
+ memset(drc, 0, sizeof(*drc));
+
+ /* copy in relevant data from the config */
+ drc->pcptr = config->pcptr;
+ drc->icountptr = config->icountptr;
+ drc->esiptr = config->esiptr;
+ drc->cb_reset = config->cb_reset;
+ drc->cb_recompile = config->cb_recompile;
+ drc->cb_entrygen = config->cb_entrygen;
+ drc->uses_fp = config->uses_fp;
+ drc->uses_sse = config->uses_sse;
+ drc->pc_in_memory = config->pc_in_memory;
+ drc->icount_in_memory = config->icount_in_memory;
+ drc->fpcw_curr = fp_control[0];
+ drc->mxcsr_curr = sse_control[0];
+
+ /* configure cache */
+ drc->cache_base = (UINT8 *)config->cache_base + sizeof(*drc);
+ drc->cache_size = config->cache_size - sizeof(*drc);
+ drc->cache_end = drc->cache_base + drc->cache_size;
+ drc->cache_danger = drc->cache_end - 65536;
+ drc->cache_allocated = cache_allocated;
+
+ /* compute shifts and masks */
+ drc->l1bits = effective_address_bits/2;
+ drc->l2bits = effective_address_bits - drc->l1bits;
+ drc->l1shift = config->lsbs_to_ignore + drc->l2bits;
+ drc->l2mask = ((1 << drc->l2bits) - 1) << config->lsbs_to_ignore;
+ drc->l2scale = 4 >> config->lsbs_to_ignore;
+
+ /* allocate lookup tables */
+ drc->lookup_l1 = malloc(sizeof(*drc->lookup_l1) * (1 << drc->l1bits));
+ drc->lookup_l2_recompile = malloc(sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits));
+ if (drc->lookup_l1 == NULL || drc->lookup_l2_recompile == NULL)
+ goto error;
+ memset(drc->lookup_l1, 0, sizeof(*drc->lookup_l1) * (1 << drc->l1bits));
+ memset(drc->lookup_l2_recompile, 0, sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits));
+
+ /* allocate the sequence and tentative lists */
+ drc->sequence_count_max = config->max_instructions;
+ drc->sequence_list = malloc(drc->sequence_count_max * sizeof(*drc->sequence_list));
+ if (drc->sequence_list == NULL)
+ goto error;
+
+ drc->tentative_count_max = config->max_instructions;
+ drc->tentative_list = malloc(drc->tentative_count_max * sizeof(*drc->tentative_list));
+ if (!drc->tentative_list)
+ return NULL;
+
+ return drc;
+
+error:
+ if (drc != NULL)
+ drc_exit(drc);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ drc_alloc - allocate memory from the top of
+ the DRC cache
+-------------------------------------------------*/
+
+void *drc_alloc(drc_core *drc, size_t amount)
+{
+ /* if we don't have enough space, reset the cache */
+ if (drc->cache_top >= drc->cache_danger - amount)
+ drc_cache_reset(drc);
+
+ /* if we still don't have enough space, fail */
+ if (drc->cache_top >= drc->cache_danger - amount)
+ return NULL;
+
+ /* adjust the end and danger values downward */
+ drc->cache_end -= amount;
+ drc->cache_danger -= amount;
+ return drc->cache_end;
+}
+
+
+/*-------------------------------------------------
+ drc_cache_reset - reset the DRC cache
+-------------------------------------------------*/
+
+void drc_cache_reset(drc_core *drc)
+{
+ int i;
+
+ /* reset the cache and add the basics */
+ drc->cache_top = drc->cache_base;
+
+ /* append the core entry points to the fresh cache */
+ drc->entry_point = (void (*)(void))(UINT32)drc->cache_top;
+ append_entry_point(drc);
+ drc->out_of_cycles = drc->cache_top;
+ append_out_of_cycles(drc);
+
+ /* append an INT 3 before the recompile so that BREAK_ON_MODIFIED_CODE works */
+ emit_int_3(DRCTOP);
+ drc->recompile = drc->cache_top;
+ append_recompile(drc);
+ drc->dispatch = drc->cache_top;
+ drc_append_dispatcher(drc);
+ drc->flush = drc->cache_top;
+ append_flush(drc);
+
+ /* populate the recompile table */
+ for (i = 0; i < (1 << drc->l2bits); i++)
+ drc->lookup_l2_recompile[i] = drc->recompile;
+
+ /* reset all the l1 tables */
+ for (i = 0; i < (1 << drc->l1bits); i++)
+ {
+ /* point NULL entries to the generic recompile table */
+ if (drc->lookup_l1[i] == NULL)
+ drc->lookup_l1[i] = drc->lookup_l2_recompile;
+
+ /* reset allocated tables to point all entries back to the recompiler */
+ else if (drc->lookup_l1[i] != drc->lookup_l2_recompile)
+ memcpy(drc->lookup_l1[i], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits));
+ }
+
+ /* call back to the host */
+ if (drc->cb_reset)
+ (*drc->cb_reset)(drc);
+}
+
+
+/*------------------------------------------------------------------
+ drc_execute
+------------------------------------------------------------------*/
+
+void drc_execute(drc_core *drc)
+{
+ (*drc->entry_point)();
+}
+
+
+/*------------------------------------------------------------------
+ drc_exit
+------------------------------------------------------------------*/
+
+void drc_exit(drc_core *drc)
+{
+ int i;
+
+ /* free all the l2 tables allocated */
+ for (i = 0; i < (1 << drc->l1bits); i++)
+ if (drc->lookup_l1[i] != drc->lookup_l2_recompile)
+ free(drc->lookup_l1[i]);
+
+ /* free the l1 table */
+ if (drc->lookup_l1)
+ free(drc->lookup_l1);
+
+ /* free the default l2 table */
+ if (drc->lookup_l2_recompile)
+ free(drc->lookup_l2_recompile);
+
+ /* free the lists */
+ if (drc->sequence_list)
+ free(drc->sequence_list);
+ if (drc->tentative_list)
+ free(drc->tentative_list);
+
+ /* and the drc itself */
+ if (drc->cache_allocated)
+ osd_free_executable(drc, drc->cache_size + sizeof(*drc));
+}
+
+
+/*------------------------------------------------------------------
+ drc_begin_sequence
+------------------------------------------------------------------*/
+
+void drc_begin_sequence(drc_core *drc, UINT32 pc)
+{
+ UINT32 l1index = pc >> drc->l1shift;
+ UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / 4;
+
+ /* reset the sequence and tentative counts */
+ drc->sequence_count = 0;
+ drc->tentative_count = 0;
+
+ /* allocate memory if necessary */
+ if (drc->lookup_l1[l1index] == drc->lookup_l2_recompile)
+ {
+ /* create a new copy of the recompile table */
+ drc->lookup_l1[l1index] = malloc_or_die(sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits));
+
+ memcpy(drc->lookup_l1[l1index], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits));
+ }
+
+ /* nuke any previous link to this instruction */
+ if (drc->lookup_l1[l1index][l2index] != drc->recompile)
+ {
+ UINT8 *cache_save = drc->cache_top;
+ drc->cache_top = drc->lookup_l1[l1index][l2index];
+ emit_jmp(DRCTOP, drc->dispatch);
+ drc->cache_top = cache_save;
+ }
+
+ /* note the current location for this instruction */
+ drc->lookup_l1[l1index][l2index] = drc->cache_top;
+}
+
+
+/*------------------------------------------------------------------
+ drc_end_sequence
+------------------------------------------------------------------*/
+
+void drc_end_sequence(drc_core *drc)
+{
+ int i, j;
+
+ /* fix up any internal links */
+ for (i = 0; i < drc->tentative_count; i++)
+ for (j = 0; j < drc->sequence_count; j++)
+ if (drc->tentative_list[i].pc == drc->sequence_list[j].pc)
+ {
+ UINT8 *cache_save = drc->cache_top;
+ drc->cache_top = drc->tentative_list[i].target;
+ emit_jmp(DRCTOP, drc->sequence_list[j].target);
+ drc->cache_top = cache_save;
+ break;
+ }
+}
+
+
+/*------------------------------------------------------------------
+ drc_register_code_at_cache_top
+------------------------------------------------------------------*/
+
+void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc)
+{
+ pc_ptr_pair *pair = &drc->sequence_list[drc->sequence_count++];
+ assert_always(drc->sequence_count <= drc->sequence_count_max, "drc_register_code_at_cache_top: too many instructions!");
+
+ pair->target = drc->cache_top;
+ pair->pc = pc;
+}
+
+
+/*------------------------------------------------------------------
+ drc_get_code_at_pc
+------------------------------------------------------------------*/
+
+void *drc_get_code_at_pc(drc_core *drc, UINT32 pc)
+{
+ UINT32 l1index = pc >> drc->l1shift;
+ UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / 4;
+ return (drc->lookup_l1[l1index][l2index] != drc->recompile) ? drc->lookup_l1[l1index][l2index] : NULL;
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_verify_code
+------------------------------------------------------------------*/
+
+void drc_append_verify_code(drc_core *drc, void *code, UINT8 length)
+{
+#if BREAK_ON_MODIFIED_CODE
+ x86code *recompile = drc->recompile - 1;
+#else
+ x86code *recompile = drc->recompile;
+#endif
+
+ if (length > 8)
+ {
+ UINT32 *codeptr = code, sum = 0;
+ void *target;
+ int i;
+
+ for (i = 0; i < length / 4; i++)
+ {
+ sum = (sum >> 1) | (sum << 31);
+ sum += *codeptr++;
+ }
+
+ emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
+ emit_mov_r32_imm(DRCTOP, REG_EBX, (FPTR)code); // mov ebx,code
+ emit_mov_r32_imm(DRCTOP, REG_ECX, length / 4); // mov ecx,length / 4
+ target = drc->cache_top; // target:
+ emit_ror_r32_imm(DRCTOP, REG_EAX, 1); // ror eax,1
+ emit_add_r32_m32(DRCTOP, REG_EAX, MBD(REG_EBX, 0)); // add eax,[ebx]
+ emit_sub_r32_imm(DRCTOP, REG_ECX, 1); // sub ecx,1
+ emit_lea_r32_m32(DRCTOP, REG_EBX, MBD(REG_EBX, 4)); // lea ebx,[ebx+4]
+ emit_jcc(DRCTOP, COND_NZ, target); // jnz target
+ emit_cmp_r32_imm(DRCTOP, REG_EAX, sum); // cmp eax,sum
+ emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile
+ }
+ else if (length >= 12)
+ {
+ emit_cmp_m32_imm(DRCTOP, MABS(code), *(UINT32 *)code); // cmp [pc],opcode
+ emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile
+ emit_cmp_m32_imm(DRCTOP, MABS((UINT8 *)code + 4), ((UINT32 *)code)[1]); // cmp [pc+4],opcode+4
+ emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile
+ emit_cmp_m32_imm(DRCTOP, MABS((UINT8 *)code + 8), ((UINT32 *)code)[2]); // cmp [pc+8],opcode+8
+ emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile
+ }
+ else if (length >= 8)
+ {
+ emit_cmp_m32_imm(DRCTOP, MABS(code), *(UINT32 *)code); // cmp [pc],opcode
+ emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile
+ emit_cmp_m32_imm(DRCTOP, MABS((UINT8 *)code + 4), ((UINT32 *)code)[1]); // cmp [pc+4],opcode+4
+ emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile
+ }
+ else if (length >= 4)
+ {
+ emit_cmp_m32_imm(DRCTOP, MABS(code), *(UINT32 *)code); // cmp [pc],opcode
+ emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile
+ }
+ else if (length >= 2)
+ {
+ emit_cmp_m16_imm(DRCTOP, MABS(code), *(UINT16 *)code); // cmp [pc],opcode
+ emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile
+ }
+ else
+ {
+ emit_cmp_m8_imm(DRCTOP, MABS(code), *(UINT8 *)code); // cmp [pc],opcode
+ emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile
+ }
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_call_debugger
+------------------------------------------------------------------*/
+
+void drc_append_call_debugger(drc_core *drc)
+{
+#ifdef MAME_DEBUG
+ if (Machine->debug_mode)
+ {
+ emit_link link;
+ emit_cmp_m32_imm(DRCTOP, MABS(&Machine->debug_mode), 0); // cmp [Machine->debug_mode],0
+ emit_jcc_short_link(DRCTOP, COND_E, &link); // je skip
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // align stack
+ drc_append_save_call_restore(drc, (x86code *)mame_debug_hook, 12); // save volatiles
+ resolve_link(DRCTOP, &link);
+ }
+#endif
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_save_volatiles
+------------------------------------------------------------------*/
+
+void drc_append_save_volatiles(drc_core *drc)
+{
+ if (drc->icountptr && !drc->icount_in_memory)
+ emit_mov_m32_r32(DRCTOP, MABS(drc->icountptr), REG_EBP);
+ if (drc->pcptr && !drc->pc_in_memory)
+ emit_mov_m32_r32(DRCTOP, MABS(drc->pcptr), REG_EDI);
+ if (drc->esiptr)
+ emit_mov_m32_r32(DRCTOP, MABS(drc->esiptr), REG_ESI);
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_restore_volatiles
+------------------------------------------------------------------*/
+
+void drc_append_restore_volatiles(drc_core *drc)
+{
+ if (drc->icountptr && !drc->icount_in_memory)
+ emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(drc->icountptr));
+ if (drc->pcptr && !drc->pc_in_memory)
+ emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(drc->pcptr));
+ if (drc->esiptr)
+ emit_mov_r32_m32(DRCTOP, REG_ESI, MABS(drc->esiptr));
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_save_call_restore
+------------------------------------------------------------------*/
+
+void drc_append_save_call_restore(drc_core *drc, x86code *target, UINT32 stackadj)
+{
+ drc_append_save_volatiles(drc); // save volatiles
+ emit_call(DRCTOP, target); // call target
+ drc_append_restore_volatiles(drc); // restore volatiles
+ if (stackadj)
+ emit_add_r32_imm(DRCTOP, REG_ESP, stackadj); // adjust stack
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_standard_epilogue
+------------------------------------------------------------------*/
+
+void drc_append_standard_epilogue(drc_core *drc, INT32 cycles, INT32 pcdelta, int allow_exit)
+{
+ if (pcdelta != 0 && drc->pc_in_memory)
+ emit_add_m32_imm(DRCTOP, MABS(drc->pcptr), pcdelta); // add [pc],pcdelta
+ if (cycles != 0)
+ {
+ if (drc->icount_in_memory)
+ emit_sub_m32_imm(DRCTOP, MABS(drc->icountptr), cycles); // sub [icount],cycles
+ else
+ emit_sub_r32_imm(DRCTOP, REG_EBP, cycles); // sub ebp,cycles
+ }
+ if (pcdelta != 0 && !drc->pc_in_memory)
+ emit_lea_r32_m32(DRCTOP, REG_EDI, MBD(REG_EDI, pcdelta)); // lea edi,[edi+pcdelta]
+ if (allow_exit && cycles != 0)
+ emit_jcc(DRCTOP, COND_S, drc->out_of_cycles); // js out_of_cycles
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_dispatcher
+------------------------------------------------------------------*/
+
+void drc_append_dispatcher(drc_core *drc)
+{
+#if LOG_DISPATCHES
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // align stack
+ emit_push_imm(DRCTOP, drc); // push drc
+ drc_append_save_call_restore(drc, (x86code *)log_dispatch, 12); // call log_dispatch
+#endif
+ if (drc->pc_in_memory)
+ emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(drc->pcptr)); // mov edi,[pc]
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi
+ emit_shr_r32_imm(DRCTOP, REG_EAX, drc->l1shift); // shr eax,l1shift
+ emit_mov_r32_r32(DRCTOP, REG_EDX, REG_EDI); // mov edx,edi
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MISD(REG_EAX, 4, (FPTR)drc->lookup_l1)); // mov eax,[eax*4 + l1lookup]
+ emit_and_r32_imm(DRCTOP, REG_EDX, drc->l2mask); // and edx,l2mask
+ emit_jmp_m32(DRCTOP, MBISD(REG_EAX, REG_EDX, drc->l2scale, 0)); // jmp [eax+edx*l2scale]
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_fixed_dispatcher
+------------------------------------------------------------------*/
+
+void drc_append_fixed_dispatcher(drc_core *drc, UINT32 newpc)
+{
+ x86code **base = drc->lookup_l1[newpc >> drc->l1shift];
+ if (base == drc->lookup_l2_recompile)
+ {
+ emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&drc->lookup_l1[newpc >> drc->l1shift]));
+ // mov eax,[(newpc >> l1shift)*4 + l1lookup]
+ emit_jmp_m32(DRCTOP, MBD(REG_EAX, (newpc & drc->l2mask) * drc->l2scale));
+ // jmp [eax+(newpc & l2mask)*l2scale]
+ }
+ else
+ emit_jmp_m32(DRCTOP, MABS((UINT8 *)base + (newpc & drc->l2mask) * drc->l2scale));
+ // jmp [eax+(newpc & l2mask)*l2scale]
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_tentative_fixed_dispatcher
+------------------------------------------------------------------*/
+
+void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc)
+{
+ pc_ptr_pair *pair = &drc->tentative_list[drc->tentative_count++];
+ assert_always(drc->tentative_count <= drc->tentative_count_max, "drc_append_tentative_fixed_dispatcher: too many tentative branches!");
+
+ pair->target = drc->cache_top;
+ pair->pc = newpc;
+ drc_append_fixed_dispatcher(drc, newpc);
+}
+
+
+/*------------------------------------------------------------------
+ drc_append_set_fp_rounding
+------------------------------------------------------------------*/
+
+void drc_append_set_fp_rounding(drc_core *drc, UINT8 regindex)
+{
+ emit_fldcw_m16(DRCTOP, MISD(regindex, 2, (INT32)&fp_control[0])); // fldcw [fp_control + reg*2]
+ emit_fstcw_m16(DRCTOP, MABS(&drc->fpcw_curr)); // fnstcw [fpcw_curr]
+}
+
+
+
+/*------------------------------------------------------------------
+ drc_append_set_temp_fp_rounding
+------------------------------------------------------------------*/
+
+void drc_append_set_temp_fp_rounding(drc_core *drc, UINT8 rounding)
+{
+ emit_fldcw_m16(DRCTOP, MABS(&fp_control[rounding])); // fldcw [fp_control]
+}
+
+
+
+/*------------------------------------------------------------------
+ drc_append_restore_fp_rounding
+------------------------------------------------------------------*/
+
+void drc_append_restore_fp_rounding(drc_core *drc)
+{
+ emit_fldcw_m16(DRCTOP, MABS(&drc->fpcw_curr)); // fldcw [fpcw_curr]
+}
+
+
+
+/*------------------------------------------------------------------
+ drc_append_set_sse_rounding
+------------------------------------------------------------------*/
+
+void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex)
+{
+ emit_ldmxcsr_m32(DRCTOP, MISD(regindex, 4, (INT32)&sse_control[0])); // ldmxcsr [sse_control + reg*2]
+ emit_stmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_curr)); // stmxcsr [mxcsr_curr]
+}
+
+
+
+/*------------------------------------------------------------------
+ drc_append_set_temp_sse_rounding
+------------------------------------------------------------------*/
+
+void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding)
+{
+ emit_ldmxcsr_m32(DRCTOP, MABS(&sse_control[rounding])); // ldmxcsr [sse_control]
+}
+
+
+
+/*------------------------------------------------------------------
+ drc_append_restore_sse_rounding
+------------------------------------------------------------------*/
+
+void drc_append_restore_sse_rounding(drc_core *drc)
+{
+ emit_ldmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr]
+}
+
+
+
+/*------------------------------------------------------------------
+ drc_dasm
+
+ An attempt to make a disassembler for DRC code; currently limited
+ by the functionality of DasmI386
+------------------------------------------------------------------*/
+
+void drc_dasm(FILE *f, const void *begin, const void *end)
+{
+ extern int i386_dasm_one(char *buffer, UINT32 eip, UINT8 *oprom, int mode);
+
+ char buffer[256];
+ const UINT8 *begin_ptr = (const UINT8 *) begin;
+ const UINT8 *end_ptr = (const UINT8 *) end;
+ UINT32 pc = (UINT32) begin;
+ int length;
+
+ while(begin_ptr < end_ptr)
+ {
+#if defined(MAME_DEBUG) && HAS_I386
+ length = i386_dasm_one(buffer, pc, (UINT8 *) begin_ptr, 32) & DASMFLAG_LENGTHMASK;
+#else
+ sprintf(buffer, "%02X", *begin_ptr);
+ length = 1;
+#endif
+
+ fprintf(f, "%08X:\t%s\n", (unsigned) pc, buffer);
+ begin_ptr += length;
+ pc += length;
+ }
+}
+
+
+
+
+/***************************************************************************
+ INTERNAL CODEGEN
+***************************************************************************/
+
+/*------------------------------------------------------------------
+ append_entry_point
+------------------------------------------------------------------*/
+
+static void append_entry_point(drc_core *drc)
+{
+ emit_pushad(DRCTOP); // pushad
+ if (drc->uses_fp)
+ {
+ emit_fstcw_m16(DRCTOP, MABS(&drc->fpcw_save)); // fstcw [fpcw_save]
+ emit_fldcw_m16(DRCTOP, MABS(&drc->fpcw_curr)); // fldcw [fpcw_curr]
+ }
+ if (drc->uses_sse)
+ {
+ emit_stmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_save)); // stmxcsr [mxcsr_save]
+ emit_ldmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr]
+ }
+ drc_append_restore_volatiles(drc); // load volatiles
+ if (drc->cb_entrygen)
+ (*drc->cb_entrygen)(drc); // additional entry point duties
+ drc_append_dispatcher(drc); // dispatch
+}
+
+
+/*------------------------------------------------------------------
+ recompile_code
+------------------------------------------------------------------*/
+
+static void recompile_code(drc_core *drc)
+{
+ if (drc->cache_top >= drc->cache_danger)
+ drc_cache_reset(drc);
+ (*drc->cb_recompile)(drc);
+}
+
+
+/*------------------------------------------------------------------
+ append_recompile
+------------------------------------------------------------------*/
+
+static void append_recompile(drc_core *drc)
+{
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // align stack
+ emit_push_imm(DRCTOP, (FPTR)drc); // push drc
+ drc_append_save_call_restore(drc, (x86code *)recompile_code, 12); // call recompile_code
+ drc_append_dispatcher(drc); // dispatch
+}
+
+
+/*------------------------------------------------------------------
+ append_flush
+------------------------------------------------------------------*/
+
+static void append_flush(drc_core *drc)
+{
+ emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // align stack
+ emit_push_imm(DRCTOP, (FPTR)drc); // push drc
+ drc_append_save_call_restore(drc, (x86code *)drc_cache_reset, 12); // call drc_cache_reset
+ drc_append_dispatcher(drc); // dispatch
+}
+
+
+/*------------------------------------------------------------------
+ append_out_of_cycles
+------------------------------------------------------------------*/
+
+static void append_out_of_cycles(drc_core *drc)
+{
+ drc_append_save_volatiles(drc); // save volatiles
+ if (drc->uses_fp)
+ {
+ emit_fclex(DRCTOP); // fnclex
+ emit_fldcw_m16(DRCTOP, MABS(&drc->fpcw_save)); // fldcw [fpcw_save]
+ }
+ if (drc->uses_sse)
+ emit_ldmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_save)); // ldmxcsr [mxcsr_save]
+ emit_popad(DRCTOP); // popad
+ emit_ret(DRCTOP); // ret
+}
+
+
+
+/*------------------------------------------------------------------
+ drc_x86_get_features()
+------------------------------------------------------------------*/
+UINT32 drc_x86_get_features(void)
+{
+ UINT32 features = 0;
+#ifdef _MSC_VER
+ __asm
+ {
+ mov eax, 1
+ xor ebx, ebx
+ xor ecx, ecx
+ xor edx, edx
+ __asm _emit 0Fh __asm _emit 0A2h // cpuid
+ mov features, edx
+ }
+#else /* !_MSC_VER */
+ __asm__
+ (
+ "pushl %%ebx ; "
+ "movl $1,%%eax ; "
+ "xorl %%ebx,%%ebx ; "
+ "xorl %%ecx,%%ecx ; "
+ "xorl %%edx,%%edx ; "
+ "cpuid ; "
+ "movl %%edx,%0 ; "
+ "popl %%ebx ; "
+ : "=&a" (features) /* result has to go in eax */
+ : /* no inputs */
+ : "%ecx", "%edx" /* clobbers ebx, ecx and edx */
+ );
+#endif /* MSC_VER */
+ return features;
+}
+
+
+
+/*------------------------------------------------------------------
+ log_dispatch
+------------------------------------------------------------------*/
+
+#if LOG_DISPATCHES
+static void log_dispatch(drc_core *drc)
+{
+ if (input_code_pressed(KEYCODE_D))
+ logerror("Disp:%08X\n", *drc->pcptr);
+}
+#endif
diff --git a/src/emu/cpu/x86drc.h b/src/emu/cpu/x86drc.h
new file mode 100644
index 00000000000..b3985b720d5
--- /dev/null
+++ b/src/emu/cpu/x86drc.h
@@ -0,0 +1,194 @@
+/***************************************************************************
+
+ x86drc.h
+
+ x86 Dynamic recompiler support routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __X86DRC_H__
+#define __X86DRC_H__
+
+#include "cpuintrf.h"
+#include "x86emit.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* PC and pointer pair */
+typedef struct _pc_ptr_pair pc_ptr_pair;
+struct _pc_ptr_pair
+{
+ UINT32 pc;
+ x86code * target;
+};
+
+
+/* core interface structure for the drc common code */
+typedef struct _drc_core drc_core;
+struct _drc_core
+{
+ UINT8 * cache_base; /* base pointer to the compiler cache */
+ UINT8 * cache_top; /* current top of cache */
+ UINT8 * cache_danger; /* high water mark for the end */
+ UINT8 * cache_end; /* end of cache memory */
+ size_t cache_size; /* cache allocated size */
+ UINT8 cache_allocated; /* did the DRC core allocate the cache? */
+
+ x86code *** lookup_l1; /* level 1 lookup */
+ x86code ** lookup_l2_recompile; /* level 2 lookup populated with recompile pointers */
+ UINT8 l1bits; /* number of bits in level 1 lookup */
+ UINT8 l2bits; /* number of bits in level 2 lookup */
+ UINT8 l1shift; /* shift to go from PC to level 1 lookup */
+ UINT32 l2mask; /* mask to go from PC to level 2 lookup */
+ UINT8 l2scale; /* scale to get from masked PC value to final level 2 lookup */
+
+ void (*entry_point)(void); /* pointer to asm entry point */
+ x86code * out_of_cycles; /* pointer to out of cycles jump point */
+ x86code * recompile; /* pointer to recompile jump point */
+ x86code * dispatch; /* pointer to dispatch jump point */
+ x86code * flush; /* pointer to flush jump point */
+
+ UINT32 * pcptr; /* pointer to where the PC is stored */
+ UINT32 * icountptr; /* pointer to where the icount is stored */
+ UINT32 * esiptr; /* pointer to where the volatile data in ESI is stored */
+ UINT8 pc_in_memory; /* true if the PC is stored in memory */
+ UINT8 icount_in_memory; /* true if the icount is stored in memory */
+
+ UINT8 uses_fp; /* true if we need the FP unit */
+ UINT8 uses_sse; /* true if we need the SSE unit */
+ UINT16 fpcw_curr; /* current FPU control word */
+ UINT32 mxcsr_curr; /* current SSE control word */
+ UINT16 fpcw_save; /* saved FPU control word */
+ UINT32 mxcsr_save; /* saved SSE control word */
+
+ pc_ptr_pair *sequence_list; /* PC/pointer sets for the current instruction sequence */
+ UINT32 sequence_count; /* number of instructions in the current sequence */
+ UINT32 sequence_count_max; /* max number of instructions in the current sequence */
+ pc_ptr_pair *tentative_list; /* PC/pointer sets for tentative branches */
+ UINT32 tentative_count; /* number of tentative branches */
+ UINT32 tentative_count_max; /* max number of tentative branches */
+
+ void (*cb_reset)(struct _drc_core *drc); /* callback when the cache is reset */
+ void (*cb_recompile)(struct _drc_core *drc); /* callback when code needs to be recompiled */
+ void (*cb_entrygen)(struct _drc_core *drc); /* callback before generating the dispatcher on entry */
+};
+
+
+/* configuration structure for the drc common code */
+typedef struct _drc_config drc_config;
+struct _drc_config
+{
+ UINT8 * cache_base; /* base pointer to the compiler cache */
+ UINT32 cache_size; /* size of cache to allocate */
+ UINT32 max_instructions; /* maximum instructions per sequence */
+ UINT8 address_bits; /* number of live address bits in the PC */
+ UINT8 lsbs_to_ignore; /* number of LSBs to ignore on the PC */
+ UINT8 uses_fp; /* true if we need the FP unit */
+ UINT8 uses_sse; /* true if we need the SSE unit */
+ UINT8 pc_in_memory; /* true if the PC is stored in memory */
+ UINT8 icount_in_memory; /* true if the icount is stored in memory */
+
+ UINT32 * pcptr; /* pointer to where the PC is stored */
+ UINT32 * icountptr; /* pointer to where the icount is stored */
+ UINT32 * esiptr; /* pointer to where the volatile data in ESI is stored */
+
+ void (*cb_reset)(drc_core *drc); /* callback when the cache is reset */
+ void (*cb_recompile)(drc_core *drc); /* callback when code needs to be recompiled */
+ void (*cb_entrygen)(drc_core *drc); /* callback before generating the dispatcher on entry */
+};
+
+
+/* structure to hold link data to be filled in later */
+typedef struct _link_info link_info;
+struct _link_info
+{
+ UINT8 size;
+ UINT8 * target;
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* use this macro in emit_* instructions to make them shorter */
+#define DRCTOP &drc->cache_top
+
+
+
+/***************************************************************************
+ HELPER MACROS
+***************************************************************************/
+
+/* useful macros for accessing hi/lo portions of 64-bit values */
+#define LO(x) (&(((UINT32 *)(UINT32)(x))[0]))
+#define HI(x) (&(((UINT32 *)(UINT32)(x))[1]))
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* features */
+#define CPUID_FEATURES_MMX (1 << 23)
+#define CPUID_FEATURES_SSE (1 << 26)
+#define CPUID_FEATURES_SSE2 (1 << 25)
+#define CPUID_FEATURES_CMOV (1 << 15)
+#define CPUID_FEATURES_TSC (1 << 4)
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* init/shutdown */
+drc_core *drc_init(UINT8 cpunum, drc_config *config);
+void *drc_alloc(drc_core *drc, size_t amount);
+void drc_cache_reset(drc_core *drc);
+void drc_execute(drc_core *drc);
+void drc_exit(drc_core *drc);
+
+/* code management */
+void drc_begin_sequence(drc_core *drc, UINT32 pc);
+void drc_end_sequence(drc_core *drc);
+void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc);
+void *drc_get_code_at_pc(drc_core *drc, UINT32 pc);
+
+/* standard appendages */
+void drc_append_dispatcher(drc_core *drc);
+void drc_append_fixed_dispatcher(drc_core *drc, UINT32 newpc);
+void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc);
+void drc_append_call_debugger(drc_core *drc);
+void drc_append_standard_epilogue(drc_core *drc, INT32 cycles, INT32 pcdelta, int allow_exit);
+void drc_append_save_volatiles(drc_core *drc);
+void drc_append_restore_volatiles(drc_core *drc);
+void drc_append_save_call_restore(drc_core *drc, x86code *target, UINT32 stackadj);
+void drc_append_verify_code(drc_core *drc, void *code, UINT8 length);
+
+void drc_append_set_fp_rounding(drc_core *drc, UINT8 regindex);
+void drc_append_set_temp_fp_rounding(drc_core *drc, UINT8 rounding);
+void drc_append_restore_fp_rounding(drc_core *drc);
+
+void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex);
+void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding);
+void drc_append_restore_sse_rounding(drc_core *drc);
+
+/* disassembling drc code */
+void drc_dasm(FILE *f, const void *begin, const void *end);
+
+/* x86 CPU features */
+UINT32 drc_x86_get_features(void);
+
+
+#endif /* __X86DRC_H__ */
diff --git a/src/emu/cpu/x86emit.h b/src/emu/cpu/x86emit.h
new file mode 100644
index 00000000000..1adda532d84
--- /dev/null
+++ b/src/emu/cpu/x86emit.h
@@ -0,0 +1,2888 @@
+/***************************************************************************
+
+ x86emit.h
+
+ Generic x86/x64 code emitters.
+
+ Copyright (c) 2007, Aaron Giles
+ Released for general use under the MAME license
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Important note:
+
+ It is assumed in 64-bit mode that all byte register accesses are
+ intended to be to the low 8 bits (SPL,BPL,SIL,DIL) and not to the
+ upper half (AH,CH,DH,BH).
+
+***************************************************************************/
+
+#ifndef __X86EMIT_H__
+#define __X86EMIT_H__
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* opcode size flag; low 4 bits must match REX low 4 bits, hence the odd numbers here */
+#define OP_16BIT 0x10
+#define OP_32BIT 0x00
+#define OP_64BIT 0x08
+
+/* 16 registers on x64, only 8 on x86 */
+#ifdef PTR64
+#define REG_MAX 16
+#else
+#define REG_MAX 8
+#endif
+
+/* invalid register index for "none" */
+#define REG_NONE REG_MAX
+
+/* 8-bit registers -- note that we assume a flat model for 64-bit */
+#define REG_AL 0
+#define REG_CL 1
+#define REG_DL 2
+#define REG_BL 3
+#ifndef PTR64
+#define REG_AH 4
+#define REG_CH 5
+#define REG_DH 6
+#define REG_BH 7
+#else
+#define REG_SPL 4
+#define REG_BPL 5
+#define REG_SIL 6
+#define REG_DIL 7
+#define REG_R8L 8
+#define REG_R9L 9
+#define REG_R10L 10
+#define REG_R11L 11
+#define REG_R12L 12
+#define REG_R13L 13
+#define REG_R14L 14
+#define REG_R15L 15
+#endif
+
+/* 16-bit registers */
+#define REG_AX 0
+#define REG_CX 1
+#define REG_DX 2
+#define REG_BX 3
+#define REG_SP 4
+#define REG_BP 5
+#define REG_SI 6
+#define REG_DI 7
+#ifdef PTR64
+#define REG_R8W 8
+#define REG_R9W 9
+#define REG_R10W 10
+#define REG_R11W 11
+#define REG_R12W 12
+#define REG_R13W 13
+#define REG_R14W 14
+#define REG_R15W 15
+#endif
+
+/* 32-bit registers */
+#define REG_EAX 0
+#define REG_ECX 1
+#define REG_EDX 2
+#define REG_EBX 3
+#define REG_ESP 4
+#define REG_EBP 5
+#define REG_ESI 6
+#define REG_EDI 7
+#ifdef PTR64
+#define REG_R8D 8
+#define REG_R9D 9
+#define REG_R10D 10
+#define REG_R11D 11
+#define REG_R12D 12
+#define REG_R13D 13
+#define REG_R14D 14
+#define REG_R15D 15
+#endif
+
+/* 64-bit registers */
+#ifdef PTR64
+#define REG_RAX 0
+#define REG_RCX 1
+#define REG_RDX 2
+#define REG_RBX 3
+#define REG_RSP 4
+#define REG_RBP 5
+#define REG_RSI 6
+#define REG_RDI 7
+#define REG_R8 8
+#define REG_R9 9
+#define REG_R10 10
+#define REG_R11 11
+#define REG_R12 12
+#define REG_R13 13
+#define REG_R14 14
+#define REG_R15 15
+#endif
+
+/* 64-bit MMX registers */
+#define REG_MM0 0
+#define REG_MM1 1
+#define REG_MM2 2
+#define REG_MM3 3
+#define REG_MM4 4
+#define REG_MM5 5
+#define REG_MM6 6
+#define REG_MM7 7
+#ifdef PTR64
+#define REG_MM8 8
+#define REG_MM9 9
+#define REG_MM10 10
+#define REG_MM11 11
+#define REG_MM12 12
+#define REG_MM13 13
+#define REG_MM14 14
+#define REG_MM15 15
+#endif
+
+/* 128-bit XMM registers */
+#define REG_XMM0 0
+#define REG_XMM1 1
+#define REG_XMM2 2
+#define REG_XMM3 3
+#define REG_XMM4 4
+#define REG_XMM5 5
+#define REG_XMM6 6
+#define REG_XMM7 7
+#ifdef PTR64
+#define REG_XMM8 8
+#define REG_XMM9 9
+#define REG_XMM10 10
+#define REG_XMM11 11
+#define REG_XMM12 12
+#define REG_XMM13 13
+#define REG_XMM14 14
+#define REG_XMM15 15
+#endif
+
+/* conditions */
+#define COND_A 7
+#define COND_AE 3
+#define COND_B 2
+#define COND_BE 6
+#define COND_C 2
+#define COND_E 4
+#define COND_Z 4
+#define COND_G 15
+#define COND_GE 13
+#define COND_L 12
+#define COND_LE 14
+#define COND_NA 6
+#define COND_NAE 2
+#define COND_NB 3
+#define COND_NBE 7
+#define COND_NC 3
+#define COND_NE 5
+#define COND_NG 14
+#define COND_NGE 12
+#define COND_NL 13
+#define COND_NLE 15
+#define COND_NO 1
+#define COND_NP 11
+#define COND_NS 9
+#define COND_NZ 5
+#define COND_O 0
+#define COND_P 10
+#define COND_PE 10
+#define COND_PO 11
+#define COND_S 8
+#define COND_Z 4
+
+/* floating point rounding modes */
+#define FPRND_NEAR 0
+#define FPRND_DOWN 1
+#define FPRND_UP 2
+#define FPRND_CHOP 3
+
+
+
+/***************************************************************************
+ OPCODE DEFINITIONS
+***************************************************************************/
+
+/* opcode flags (in upper 8 bits of opcode) */
+#define OPFLAG_8BITREG (1 << 24)
+#define OPFLAG_8BITRM (1 << 25)
+
+/* single byte opcodes */
+#define OP_ADD_Eb_Gb (0x00 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_ADD_Ev_Gv 0x01
+#define OP_ADD_Gb_Eb (0x02 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_ADD_Gv_Ev 0x03
+#define OP_ADD_AL_Ib 0x04
+#define OP_ADD_rAX_Iz 0x05
+#define OP_PUSH_ES 0x06
+#define OP_POP_ES 0x07
+#define OP_OR_Eb_Gb (0x08 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_OR_Ev_Gv 0x09
+#define OP_OR_Gb_Eb (0x0a | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_OR_Gv_Ev 0x0b
+#define OP_OR_AL_Ib 0x0c
+#define OP_OR_eAX_Iv 0x0d
+#define OP_PUSH_CS 0x0e
+#define OP_EXTENDED 0x0f
+
+#define OP_ADC_Eb_Gb (0x10 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_ADC_Ev_Gv 0x11
+#define OP_ADC_Gb_Eb (0x12 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_ADC_Gv_Ev 0x13
+#define OP_ADC_AL_Ib 0x14
+#define OP_ADC_rAX_Iz 0x15
+#define OP_PUSH_SS 0x16
+#define OP_POP_SS 0x17
+#define OP_SBB_Eb_Gb (0x18 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_SBB_Ev_Gv 0x19
+#define OP_SBB_Gb_Eb (0x1a | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_SBB_Gv_Ev 0x1b
+#define OP_SBB_AL_Ib 0x1c
+#define OP_SBB_eAX_Iv 0x1d
+#define OP_PUSH_DS 0x1e
+#define OP_POP_DS 0x1f
+
+#define OP_AND_Eb_Gb (0x20 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_AND_Ev_Gv 0x21
+#define OP_AND_Gb_Eb (0x22 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_AND_Gv_Ev 0x23
+#define OP_AND_AL_Ib 0x24
+#define OP_AND_rAX_Iz 0x25
+#define PREFIX_ES 0x26
+#define OP_DAA 0x27
+#define OP_SUB_Eb_Gb (0x28 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_SUB_Ev_Gv 0x29
+#define OP_SUB_Gb_Eb (0x2a | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_SUB_Gv_Ev 0x2b
+#define OP_SUB_AL_Ib 0x2c
+#define OP_SUB_eAX_Iv 0x2d
+#define PREFIX_CS 0x2e
+#define OP_DAS 0x2f
+
+#define OP_XOR_Eb_Gb (0x30 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_XOR_Ev_Gv 0x31
+#define OP_XOR_Gb_Eb (0x32 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_XOR_Gv_Ev 0x33
+#define OP_XOR_AL_Ib 0x34
+#define OP_XOR_rAX_Iz 0x35
+#define PREFIX_SS 0x36
+#define OP_AAA 0x37
+#define OP_CMP_Eb_Gb (0x38 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_CMP_Ev_Gv 0x39
+#define OP_CMP_Gb_Eb (0x3a | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_CMP_Gv_Ev 0x3b
+#define OP_CMP_AL_Ib 0x3c
+#define OP_CMP_eAX_Iv 0x3d
+#define PREFIX_DS 0x3e
+#define OP_AAS 0x3f
+
+#define OP_REX 0x40
+#define OP_REX_B 0x41
+#define OP_REX_X 0x42
+#define OP_REX_XB 0x43
+#define OP_REX_R 0x44
+#define OP_REX_RB 0x45
+#define OP_REX_RX 0x46
+#define OP_REX_RXB 0x47
+#define OP_REX_W 0x48
+#define OP_REX_WB 0x49
+#define OP_REX_WX 0x4a
+#define OP_REX_WXB 0x4b
+#define OP_REX_WR 0x4c
+#define OP_REX_WRB 0x4d
+#define OP_REX_WRX 0x4e
+#define OP_REX_WRXB 0x4f
+
+#define OP_PUSH_rAX 0x50
+#define OP_PUSH_rCX 0x51
+#define OP_PUSH_rDX 0x52
+#define OP_PUSH_rBX 0x53
+#define OP_PUSH_rSP 0x54
+#define OP_PUSH_rBP 0x55
+#define OP_PUSH_rSI 0x56
+#define OP_PUSH_rDI 0x57
+#define OP_POP_rAX 0x58
+#define OP_POP_rCX 0x59
+#define OP_POP_rDX 0x5a
+#define OP_POP_rBX 0x5b
+#define OP_POP_rSP 0x5c
+#define OP_POP_rBP 0x5d
+#define OP_POP_rSI 0x5e
+#define OP_POP_rDI 0x5f
+
+#define OP_PUSHA 0x60
+#define OP_POPA 0x61
+#define OP_BOUND_Gv_Ma 0x62
+#define OP_ARPL_Ew_Gw 0x63
+#define OP_MOVSXD_Gv_Ev 0x63
+#define PREFIX_FS 0x64
+#define PREFIX_GS 0x65
+#define PREFIX_OPSIZE 0x66
+#define PREFIX_ADSIZE 0x67
+#define OP_PUSH_Iz 0x68
+#define OP_IMUL_Gv_Ev_Iz 0x69
+#define OP_PUSH_Ib 0x6a
+#define OP_IMUL_Gv_Ev_Ib 0x6b
+#define OP_INS_Yb_DX 0x6c
+#define OP_INS_Yz_DX 0x6d
+#define OP_OUTS_DX_Xb 0x6e
+#define OP_OUTS_DX_Xz 0x6f
+
+#define OP_JCC_O_Jb 0x70
+#define OP_JCC_NO_Jb 0x71
+#define OP_JCC_B_Jb 0x72
+#define OP_JCC_C_Jb 0x72
+#define OP_JCC_NAE_Jb 0x72
+#define OP_JCC_AE_Jb 0x73
+#define OP_JCC_NB_Jb 0x73
+#define OP_JCC_NC_Jb 0x73
+#define OP_JCC_E_Jb 0x74
+#define OP_JCC_Z_Jb 0x74
+#define OP_JCC_NE_Jb 0x75
+#define OP_JCC_NZ_Jb 0x75
+#define OP_JCC_BE_Jb 0x76
+#define OP_JCC_NA_Jb 0x76
+#define OP_JCC_A_Jb 0x77
+#define OP_JCC_NBE_Jb 0x77
+#define OP_JCC_S_Jb 0x78
+#define OP_JCC_NS_Jb 0x79
+#define OP_JCC_P_Jb 0x7a
+#define OP_JCC_PE_Jb 0x7a
+#define OP_JCC_NP_Jb 0x7b
+#define OP_JCC_PO_Jb 0x7b
+#define OP_JCC_L_Jb 0x7c
+#define OP_JCC_NGE_Jb 0x7c
+#define OP_JCC_NL_Jb 0x7d
+#define OP_JCC_GE_Jb 0x7d
+#define OP_JCC_LE_Jb 0x7e
+#define OP_JCC_NG_Jb 0x7e
+#define OP_JCC_NLE_Jb 0x7f
+#define OP_JCC_G_Jb 0x7f
+
+#define OP_G1_Eb_Ib (0x80 | OPFLAG_8BITRM)
+#define OP_G1_Ev_Iz 0x81
+#define OP_G1_Eb_Ibx (0x82 | OPFLAG_8BITRM)
+#define OP_G1_Ev_Ib 0x83
+#define OP_TEST_Eb_Gb (0x84 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_TEST_Ev_Gv 0x85
+#define OP_XCHG_Eb_Gb (0x86 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_XCHG_Ev_Gv 0x87
+#define OP_MOV_Eb_Gb (0x88 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_MOV_Ev_Gv 0x89
+#define OP_MOV_Gb_Eb (0x8a | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_MOV_Gv_Ev 0x8b
+#define OP_MOV_Ev_Sw 0x8c
+#define OP_LEA_Gv_M 0x8d
+#define OP_MOV_Sw_Ew 0x8e
+#define OP_G1A_Ev 0x8f
+
+#define OP_NOP 0x90
+#define OP_PAUSE 0x90
+#define OP_XCHG_rCX 0x91
+#define OP_XCHG_rDX 0x92
+#define OP_XCHG_rBX 0x93
+#define OP_XCHG_rSP 0x94
+#define OP_XCHG_rBP 0x95
+#define OP_XCHG_rSI 0x96
+#define OP_XCHG_rDI 0x97
+#define OP_CBW 0x98
+#define OP_CWDE 0x98
+#define OP_CDQE 0x98
+#define OP_CWD 0x99
+#define OP_CDQ 0x99
+#define OP_CQO 0x99
+#define OP_CALLF_Ap 0x9a
+#define OP_FWAIT 0x9b
+#define OP_PUSHF_Fv 0x9c
+#define OP_POPF_Fv 0x9d
+#define OP_SAHF 0x9e
+#define OP_LAHF 0x9f
+
+#define OP_MOV_AL_Ob 0xa0
+#define OP_MOV_rAX_Ov 0xa1
+#define OP_MOV_Ob_AL 0xa2
+#define OP_MOV_Ov_rAX 0xa3
+#define OP_MOVS_Xb_Yb 0xa4
+#define OP_MOVS_Xv_Yv 0xa5
+#define OP_CMPS_Xb_Yb 0xa6
+#define OP_CMPS_Xv_Yv 0xa7
+#define OP_TEST_AL_Ib 0xa8
+#define OP_TEST_rAX_Iz 0xa9
+#define OP_STOS_Yb_AL 0xaa
+#define OP_STOS_Yv_rAX 0xab
+#define OP_LODS_AL_Xb 0xac
+#define OP_LODS_rAX_Xv 0xad
+#define OP_SCAS_AL_Yb 0xae
+#define OP_SCAC_rAX_Yv 0xaf
+
+#define OP_MOV_AL_Ib 0xb0
+#define OP_MOV_CL_Ib 0xb1
+#define OP_MOV_DL_Ib 0xb2
+#define OP_MOV_BL_Ib 0xb3
+#define OP_MOV_AH_Ib 0xb4
+#define OP_MOV_CH_Ib 0xb5
+#define OP_MOV_DH_Ib 0xb6
+#define OP_MOV_BH_Ib 0xb7
+#define OP_MOV_rAX_Iv 0xb8
+#define OP_MOV_rCX_Iv 0xb9
+#define OP_MOV_rDX_Iv 0xba
+#define OP_MOV_rBX_Iv 0xbb
+#define OP_MOV_rSP_Iv 0xbc
+#define OP_MOV_rBP_Iv 0xbd
+#define OP_MOV_rSI_Iv 0xbe
+#define OP_MOV_rDI_Iv 0xbf
+
+#define OP_G2_Eb_Ib (0xc0 | OPFLAG_8BITRM)
+#define OP_G2_Ev_Ib 0xc1
+#define OP_RETN_Iw 0xc2
+#define OP_RETN 0xc3
+#define OP_LES_Gz_Mp 0xc4
+#define OP_LDS_Gz_Mp 0xc5
+#define OP_G11_Eb_Ib (0xc6 | OPFLAG_8BITRM)
+#define OP_G11_Ev_Iz 0xc7
+#define OP_ENTER_Iw_Ib 0xc8
+#define OP_LEAVE 0xc9
+#define OP_RETF_Iw 0xca
+#define OP_RETF 0xcb
+#define OP_INT_3 0xcc
+#define OP_INT_Ib 0xcd
+#define OP_INTO 0xce
+#define OP_IRET 0xcf
+
+#define OP_G2_Eb_1 (0xd0 | OPFLAG_8BITRM)
+#define OP_G2_Ev_1 0xd1
+#define OP_G2_Eb_CL (0xd2 | OPFLAG_8BITRM)
+#define OP_G2_Ev_CL 0xd3
+#define OP_AAM 0xd4
+#define OP_AAD 0xd5
+#define OP_XLAT 0xd7
+#define OP_ESC_D8 0xd8
+#define OP_ESC_D9 0xd9
+#define OP_ESC_DA 0xda
+#define OP_ESC_DB 0xdb
+#define OP_ESC_DC 0xdc
+#define OP_ESC_DD 0xdd
+#define OP_ESC_DE 0xde
+#define OP_ESC_DF 0xdf
+
+#define OP_LOOPNE_Jb 0xe0
+#define OP_LOOPE_Jb 0xe1
+#define OP_LOOP_Jb 0xe2
+#define OP_JrCXZ_Jb 0xe3
+#define OP_IN_AL_Ib 0xe4
+#define OP_IN_eAX_Ib 0xe5
+#define OP_OUT_Ib_AL 0xe6
+#define OP_OUT_Ib_eAX 0xe7
+#define OP_CALL_Jz 0xe8
+#define OP_JMP_Jz 0xe9
+#define OP_JMPF_AP 0xea
+#define OP_JMP_Jb 0xeb
+#define OP_IN_AL_DX 0xec
+#define OP_IN_eAX_D 0xed
+#define OP_OUT_DX_AL 0xee
+#define OP_OUT_DX_eAX 0xef
+
+#define PREFIX_LOCK 0xf0
+#define PREFIX_REPNE 0xf2
+#define PREFIX_REPE 0xf3
+#define OP_HLT 0xf4
+#define OP_CMC 0xf5
+#define OP_G3_Eb (0xf6 | OPFLAG_8BITRM)
+#define OP_G3_Ev 0xf7
+#define OP_CLC 0xf8
+#define OP_STC 0xf9
+#define OP_CLI 0xfa
+#define OP_STI 0xfb
+#define OP_CLD 0xfc
+#define OP_STD 0xfd
+#define OP_G4 0xfe
+#define OP_G5 0xff
+
+
+/* double byte opcodes */
+#define OP_G6 0x0f00
+#define OP_G7 0x0f01
+#define OP_LAR_Gv_Ew 0x0f02
+#define OP_LSL_Gv_Ew 0x0f03
+#define OP_SYSCALL 0x0f05
+#define OP_CLTS 0x0f06
+#define OP_SYSRET 0x0f07
+#define OP_INVD 0x0f08
+#define OP_WBINVD 0x0f09
+#define OP_UD2 0x0f0b
+
+#define OP_MOVUPS_Vps_Wps 0x0f10
+#define OP_MOVSS_Vss_Wss 0xf30f10
+#define OP_MOVUPD_Vpd_Wpd 0x660f10
+#define OP_MOVSD_Vsd_Wsd 0xf20f10
+#define OP_MOVUPS_Wps_Vps 0x0f11
+#define OP_MOVSS_Wss_Vss 0xf30f11
+#define OP_MOVUPD_Wpd_Vpd 0x660f11
+#define OP_MOVSD_Wsd_Vsd 0xf20f11
+#define OP_MOVLPS_Vq_Mq 0x0f12
+#define OP_MOVLPD_Vq_Mq 0x660f12
+#define OP_MOVHLPS_Vq_Uq 0x0f12
+#define OP_MOVDDUP_Vq_Wq 0xf20f12
+#define OP_MOVSLDUP_Vq_Wq 0xf30f12
+#define OP_MOVLPS_Mq_Vq 0x0f13
+#define OP_MOVLPD_Mq_Vq 0x660f13
+#define OP_UNPCKLPS_Vps_Wq 0x0f14
+#define OP_UNPCKLPD_Vpd_Wq 0x660f14
+#define OP_UNPCKHPS_Vps_Wq 0x0f15
+#define OP_UNPCKHPD_Vpd_Wq 0x660f15
+#define OP_MOVHPS_Vq_Mq 0x0f16
+#define OP_MOVHPD_Vq_Mq 0x660f16
+#define OP_MOVLHPS_Vq_Uq 0x0f16
+#define OP_MOVSHDUP_Vq_Wq 0xf30f16
+#define OP_MOVHPS_Mq_Vq 0x0f17
+#define OP_MOVHPD_Mq_Vq 0x660f17
+#define OP_PREFETCH_G16 0x0f18
+
+#define OP_MOV_Rd_Cd 0x0f20
+#define OP_MOV_Rd_Dd 0x0f21
+#define OP_MOV_Cd_Rd 0x0f22
+#define OP_MOV_Dd_Rd 0x0f23
+#define OP_MOVAPS_Vps_Wps 0x0f28
+#define OP_MOVAPD_Vpd_Wpd 0x660f28
+#define OP_MOVAPS_Wps_Vps 0x0f29
+#define OP_MOVAPD_Wpd_Vpd 0x660f29
+#define OP_CVTPI2PS_Vps_Qq 0x0f2a
+#define OP_CVTSI2SS_Vss_Ed 0xf30f2a
+#define OP_CVTPI2PD_Vpd_Qq 0x660f2a
+#define OP_CVTSI2SD_Vsd_Ed 0xf20f2a
+#define OP_MOVNTPS_Mps_Vps 0x0f2b
+#define OP_MOVNTPD_Mpd_Vpd 0x660f2b
+#define OP_CVTTPS2PI_Pq_Wq 0x0f2c
+#define OP_CVTTSS2SI_Gd_Wss 0xf30f2c
+#define OP_CVTTPD2PI_Pq_Wpd 0x660f2c
+#define OP_CVTTSD2SI_Gd_Wsd 0xf20f2c
+#define OP_CVTPS2PI_Pq_Wq 0x0f2d
+#define OP_CVTSS2SI_Gd_Wss 0xf30f2d
+#define OP_CVTPD2PI_Pq_Wpd 0x660f2d
+#define OP_CVTSD2SI_Gd_Wsd 0xf20f2d
+#define OP_UCOMISS_Vss_Wss 0x0f2e
+#define OP_UCOMISD_Vsd_Wsd 0x660f2e
+#define OP_COMISS_Vss_Wss 0x0f2f
+#define OP_COMISD_Vsd_Wsd 0x660f2f
+
+#define OP_WRMSR 0x0f30
+#define OP_RDTSC 0x0f31
+#define OP_RDMSR 0x0f32
+#define OP_RDPMC 0x0f33
+#define OP_SYSENTER 0x0f34
+#define OP_SYSEXIT 0x0f35
+
+#define OP_CMOV_O_Gv_Ev 0x0f40
+#define OP_CMOV_NO_Gv_Ev 0x0f41
+#define OP_CMOV_B_Gv_Ev 0x0f42
+#define OP_CMOV_C_Gv_Ev 0x0f42
+#define OP_CMOV_AE_Gv_Ev 0x0f43
+#define OP_CMOV_NC_Gv_Ev 0x0f43
+#define OP_CMOV_E_Gv_Ev 0x0f44
+#define OP_CMOV_Z_Gv_Ev 0x0f44
+#define OP_CMOV_NE_Gv_Ev 0x0f45
+#define OP_CMOV_NZ_Gv_Ev 0x0f45
+#define OP_CMOV_BE_Gv_Ev 0x0f46
+#define OP_CMOV_A_Gv_Ev 0x0f47
+#define OP_CMOV_S_Gv_Ev 0x0f48
+#define OP_CMOV_NS_Gv_Ev 0x0f49
+#define OP_CMOV_P_Gv_Ev 0x0f4a
+#define OP_CMOV_PE_Gv_Ev 0x0f4a
+#define OP_CMOV_NP_Gv_Ev 0x0f4b
+#define OP_CMOV_PO_Gv_Ev 0x0f4b
+#define OP_CMOV_L_Gv_Ev 0x0f4c
+#define OP_CMOV_NGE_Gv_Ev 0x0f4c
+#define OP_CMOV_NL_Gv_Ev 0x0f4d
+#define OP_CMOV_GE_Gv_Ev 0x0f4d
+#define OP_CMOV_LE_Gv_Ev 0x0f4e
+#define OP_CMOV_NG_Gv_Ev 0x0f4e
+#define OP_CMOV_NLE_Gv_Ev 0x0f4f
+#define OP_CMOV_G_Gv_Ev 0x0f4f
+
+#define OP_MOVMSKPS_Gd_Ups 0x0f50
+#define OP_MOVMSKPD_Gd_Upd 0x660f50
+#define OP_SQRTPS_Vps_Wps 0x0f51
+#define OP_SQRTSS_Vss_Wss 0xf30f51
+#define OP_SQRTPD_Vpd_Wpd 0x660f51
+#define OP_SQRTSD_Vsd_Wsd 0xf20f51
+#define OP_RSQRTPS_Vps_Wps 0x0f52
+#define OP_RSQRTSS_Vss_Wss 0xf30f52
+#define OP_RCPPS_Vps_Wps 0x0f53
+#define OP_RCPSS_Vss_Wss 0xf30f53
+#define OP_ANDPS_Vps_Wps 0x0f54
+#define OP_ANDPD_Vpd_Wpd 0x660f54
+#define OP_ANDNPS_Vps_Wps 0x0f55
+#define OP_ANDNPD_Vpd_Wpd 0x660f55
+#define OP_ORPS_Vps_Wps 0x0f56
+#define OP_ORPD_Vpd_Wpd 0x660f56
+#define OP_XORPS_Vps_Wps 0x0f57
+#define OP_XORPD_Vpd_Wpd 0x660f57
+#define OP_ADDPS_Vps_Wps 0x0f58
+#define OP_ADDSS_Vss_Wss 0xf30f58
+#define OP_ADDPD_Vpd_Wpd 0x660f58
+#define OP_ADDSD_Vsd_Wsd 0xf20f58
+#define OP_MULPS_Vps_Wps 0x0f59
+#define OP_MULSS_Vss_Wss 0xf30f59
+#define OP_MULPD_Vpd_Wpd 0x660f59
+#define OP_MULSD_Vsd_Wsd 0xf20f59
+#define OP_CVTPS2PD_Vpd_Wq 0x0f5a
+#define OP_CVTSS2SD_Vsd_Wss 0xf30f5a
+#define OP_CVTPD2PS_Vps_Wpd 0x660f5a
+#define OP_CVTSD2SS_Vss_Wsd 0xf20f5a
+#define OP_CVTDQ2PS_Vps_Wdq 0x0f5b
+#define OP_CVTPS2DQ_Vdq_Wps 0x660f5b
+#define OP_CVTTPS2DQ_Vdq_Wps 0xf30f5b
+#define OP_SUBPS_Vps_Wps 0x0f5c
+#define OP_SUBSS_Vss_Wss 0xf30f5c
+#define OP_SUBPD_Vpd_Wpd 0x660f5c
+#define OP_SUBSD_Vsd_Wsd 0xf20f5c
+#define OP_MINPS_Vps_Wps 0x0f5d
+#define OP_MINSS_Vss_Wss 0xf30f5d
+#define OP_MINPD_Vpd_Wpd 0x660f5d
+#define OP_MINSD_Vsd_Wsd 0xf20f5d
+#define OP_DIVPS_Vps_Wps 0x0f5e
+#define OP_DIVSS_Vss_Wss 0xf30f5e
+#define OP_DIVPD_Vpd_Wpd 0x660f5e
+#define OP_DIVSD_Vsd_Wsd 0xf20f5e
+#define OP_MAXPS_Vps_Wps 0x0f5f
+#define OP_MAXSS_Vss_Wss 0xf30f5f
+#define OP_MAXPD_Vpd_Wpd 0x660f5f
+#define OP_MAXSD_Vsd_Wsd 0xf20f5f
+
+#define OP_PUNPCKLBW_Pq_Qd 0x0f60
+#define OP_PUNPCKLBW_Vdq_Wdq 0x660f60
+#define OP_PUNPCKLWD_Pq_Qd 0x0f61
+#define OP_PUNPCKLWD_Vdq_Wdq 0x660f61
+#define OP_PUNPCKLDQ_Pq_Qd 0x0f62
+#define OP_PUNPCKLDQ_Vdq_Wdq 0x660f62
+#define OP_PACKSSWB_Pq_Qq 0x0f63
+#define OP_PACKSSWB_Vdq_Wdq 0x660f63
+#define OP_PCMPGTB_Pq_Qq 0x0f64
+#define OP_PCMPGTB_Vdq_Wdq 0x660f64
+#define OP_PCMPGTW_Pq_Qq 0x0f65
+#define OP_PCMPGTW_Vdq_Wdq 0x660f65
+#define OP_PCMPGTD_Pq_Qq 0x0f66
+#define OP_PCMPGTD_Vdq_Wdq 0x660f66
+#define OP_PACKUSWB_Pq_Qq 0x0f67
+#define OP_PACKUSWB_Vdq_Wdq 0x660f67
+#define OP_PUNPCKHBW_Pq_Qq 0x0f68
+#define OP_PUNPCKHBW_Vdq_Qdq 0x660f68
+#define OP_PUNPCKHWD_Pq_Qq 0x0f69
+#define OP_PUNPCKHWD_Vdq_Qdq 0x660f69
+#define OP_PUNPCKHDQ_Pq_Qq 0x0f6a
+#define OP_PUNPCKHDQ_Vdq_Qdq 0x660f6a
+#define OP_PACKSSDW_Pq_Qq 0x0f6b
+#define OP_PACKSSDW_Vdq_Qdq 0x660f6b
+#define OP_PUNPCKLQDQ_Vdq_Wdq 0x660f6c
+#define OP_PUNPCKHQDQ_Vdq_Wdq 0x660f6d
+#define OP_MOVD_Pd_Ed 0x0f6e
+#define OP_MOVD_Vd_Ed 0x660f6e
+#define OP_MOVQ_Pq_Qq 0x0f6f
+#define OP_MOVDQA_Vdq_Wdq 0x660f6f
+#define OP_MOVDQU_Vdq_Wdq 0xf30f6f
+
+#define OP_PSHUFW_Pq_Qq_Ib 0x0f70
+#define OP_PSHUFD_Vdq_Wdq_Ib 0x660f70
+#define OP_PSHUFHW_Vdq_Wdq_Ib 0xf30f70
+#define OP_PSHUFLW_Vdq_Wdq_Ib 0xf20f70
+#define OP_G12 0x0f71
+#define OP_G13 0x0f72
+#define OP_G14 0x0f73
+#define OP_PCMPEQB_Pq_Qq 0x0f74
+#define OP_PCMPEQB_Vdq_Wdq 0x660f74
+#define OP_PCMPEQW_Pq_Qq 0x0f75
+#define OP_PCMPEQW_Vdq_Wdq 0x660f75
+#define OP_PCMPEQD_Pq_Qq 0x0f76
+#define OP_PCMPEQD_Vdq_Wdq 0x660f76
+#define OP_EMMS 0x0f77
+#define OP_HADDPD_Vpd_Wpd 0x660f7c
+#define OP_HADDPS_Vps_Wps 0xf20f7c
+#define OP_HSUBPD_Vpd_Wpd 0x660f7d
+#define OP_HSUBPS_Vps_Wps 0xf20f7d
+#define OP_MOVD_Ed_Pd 0x0f7e
+#define OP_MOVD_Ed_Vd 0x660f7e
+#define OP_MOVQ_Vq_Wq 0xf30f7e
+#define OP_MOVQ_Qq_Pq 0x0f7f
+#define OP_MOVDQA_Wdq_Vdq 0x660f7f
+#define OP_MOVDQU_Wdq_Vdq 0xf30f7f
+
+#define OP_JCC_O_Jv 0x0f80
+#define OP_JCC_NO_Jv 0x0f81
+#define OP_JCC_B_Jv 0x0f82
+#define OP_JCC_C_Jv 0x0f82
+#define OP_JCC_NAE_Jv 0x0f82
+#define OP_JCC_AE_Jv 0x0f83
+#define OP_JCC_NB_Jv 0x0f83
+#define OP_JCC_NC_Jv 0x0f83
+#define OP_JCC_E_Jv 0x0f84
+#define OP_JCC_Z_Jv 0x0f84
+#define OP_JCC_NE_Jv 0x0f85
+#define OP_JCC_NZ_Jv 0x0f85
+#define OP_JCC_BE_Jv 0x0f86
+#define OP_JCC_NA_Jv 0x0f86
+#define OP_JCC_A_Jv 0x0f87
+#define OP_JCC_NBE_Jv 0x0f87
+#define OP_JCC_S_Jv 0x0f88
+#define OP_JCC_NS_Jv 0x0f89
+#define OP_JCC_P_Jv 0x0f8a
+#define OP_JCC_PE_Jv 0x0f8a
+#define OP_JCC_NP_Jv 0x0f8b
+#define OP_JCC_PO_Jv 0x0f8b
+#define OP_JCC_L_Jv 0x0f8c
+#define OP_JCC_NGE_Jv 0x0f8c
+#define OP_JCC_NL_Jv 0x0f8d
+#define OP_JCC_GE_Jv 0x0f8d
+#define OP_JCC_LE_Jv 0x0f8e
+#define OP_JCC_NG_Jv 0x0f8e
+#define OP_JCC_NLE_Jv 0x0f8f
+#define OP_JCC_G_Jv 0x0f8f
+
+#define OP_SETCC_O_Eb (0x0f90 | OPFLAG_8BITRM)
+#define OP_SETCC_NO_Eb (0x0f91 | OPFLAG_8BITRM)
+#define OP_SETCC_B_Eb (0x0f92 | OPFLAG_8BITRM)
+#define OP_SETCC_C_Eb (0x0f92 | OPFLAG_8BITRM)
+#define OP_SETCC_NAE_Eb (0x0f92 | OPFLAG_8BITRM)
+#define OP_SETCC_AE_Eb (0x0f93 | OPFLAG_8BITRM)
+#define OP_SETCC_NB_Eb (0x0f93 | OPFLAG_8BITRM)
+#define OP_SETCC_NC_Eb (0x0f93 | OPFLAG_8BITRM)
+#define OP_SETCC_E_Eb (0x0f94 | OPFLAG_8BITRM)
+#define OP_SETCC_Z_Eb (0x0f94 | OPFLAG_8BITRM)
+#define OP_SETCC_NE_Eb (0x0f95 | OPFLAG_8BITRM)
+#define OP_SETCC_NZ_Eb (0x0f95 | OPFLAG_8BITRM)
+#define OP_SETCC_BE_Eb (0x0f96 | OPFLAG_8BITRM)
+#define OP_SETCC_NA_Eb (0x0f96 | OPFLAG_8BITRM)
+#define OP_SETCC_A_Eb (0x0f97 | OPFLAG_8BITRM)
+#define OP_SETCC_NBE_Eb (0x0f97 | OPFLAG_8BITRM)
+#define OP_SETCC_S_Eb (0x0f98 | OPFLAG_8BITRM)
+#define OP_SETCC_NS_Eb (0x0f99 | OPFLAG_8BITRM)
+#define OP_SETCC_P_Eb (0x0f9a | OPFLAG_8BITRM)
+#define OP_SETCC_PE_Eb (0x0f9a | OPFLAG_8BITRM)
+#define OP_SETCC_NP_Eb (0x0f9b | OPFLAG_8BITRM)
+#define OP_SETCC_PO_Eb (0x0f9b | OPFLAG_8BITRM)
+#define OP_SETCC_L_Eb (0x0f9c | OPFLAG_8BITRM)
+#define OP_SETCC_NGE_Eb (0x0f9c | OPFLAG_8BITRM)
+#define OP_SETCC_NL_Eb (0x0f9d | OPFLAG_8BITRM)
+#define OP_SETCC_GE_Eb (0x0f9d | OPFLAG_8BITRM)
+#define OP_SETCC_LE_Eb (0x0f9e | OPFLAG_8BITRM)
+#define OP_SETCC_NG_Eb (0x0f9e | OPFLAG_8BITRM)
+#define OP_SETCC_NLE_Eb (0x0f9f | OPFLAG_8BITRM)
+#define OP_SETCC_G_Eb (0x0f9f | OPFLAG_8BITRM)
+
+#define OP_PUSH_FS 0x0fa0
+#define OP_POP_FS 0x0fa1
+#define OP_CPUID 0x0fa2
+#define OP_BT_Ev_Gv 0x0fa3
+#define OP_SHLD_Ev_Gv_Ib 0x0fa4
+#define OP_SHLD_Ev_Gv_CL 0x0fa5
+#define OP_PUSH_GS 0x0fa8
+#define OP_POP_GS 0x0fa9
+#define OP_RSM 0x0faa
+#define OP_BTS_Ev_Gv 0x0fab
+#define OP_SHRD_Ev_Gv_Ib 0x0fac
+#define OP_SHRD_Ev_Gv_CL 0x0fad
+#define OP_G16 0x0fae
+#define OP_IMUL_Gv_Ev 0x0faf
+
+#define OP_CMPXCHG_Eb_Gb (0x0fb0 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_CMPXCHG_Ev_Gv 0x0fb1
+#define OP_LSS_Mp 0x0fb2
+#define OP_BTR_Ev_Gv 0x0fb3
+#define OP_LFS_Mp 0x0fb4
+#define OP_LGS_Mp 0x0fb5
+#define OP_MOVZX_Gv_Eb (0x0fb6 | OPFLAG_8BITRM)
+#define OP_MOVZX_Gv_Ew 0x0fb7
+#define OP_G10_INVALID 0x0fb9
+#define OP_G8_Ev_Ib 0x0fba
+#define OP_BTC_Ev_Gv 0x0fbb
+#define OP_BSF_Gv_Ev 0x0fbc
+#define OP_BSR_Gv_Ev 0x0fbd
+#define OP_MOVSX_Gv_Eb (0x0fbe | OPFLAG_8BITRM)
+#define OP_MOVSX_Gv_Ew 0x0fbf
+
+#define OP_XADD_Eb_Gb (0x0fc0 | OPFLAG_8BITRM | OPFLAG_8BITREG)
+#define OP_XADD_Ev_Gv 0x0fc1
+#define OP_CMPPS_Vps_Wps_Ib 0x0fc2
+#define OP_CMPSS_Vss_Wss_Ib 0xf30fc2
+#define OP_CMPPD_Vpd_Wpd_Ib 0x660fc2
+#define OP_CMPSD_Vsd_Wsd_Ib 0xf20fc2
+#define OP_MOVNTI_Md_Gd 0x0fc3
+#define OP_PINSRW_Pw_Ew_Ib 0x0fc4
+#define OP_PINSRW_Vw_Ew_Ib 0x660fc4
+#define OP_PEXTRW_Gw_Pw_Ib 0x0fc5
+#define OP_PEXTRW_Gw_Vw_Ib 0x660fc5
+#define OP_SHUFPS_Vps_Wps_Ib 0x0fc6
+#define OP_SHUFPD_Vpd_Wpd_Ib 0x660fc6
+#define OP_G9 0x0fc7
+#define OP_BSWAP_EAX 0x0fc8
+#define OP_BSWAP_ECX 0x0fc9
+#define OP_BSWAP_EDX 0x0fca
+#define OP_BSWAP_EBX 0x0fcb
+#define OP_BSWAP_ESP 0x0fcc
+#define OP_BSWAP_EBP 0x0fcd
+#define OP_BSWAP_ESI 0x0fce
+#define OP_BSWAP_EDI 0x0fcf
+
+#define OP_ADDSUBPD_Vpd_Wpd 0x0fd0
+#define OP_ADDSUBPS_Vps_Wps 0xf20fd0
+#define OP_PSRLW_Pq_Qq 0x0fd1
+#define OP_PSRLW_Vdq_Wdq 0x660fd1
+#define OP_PSRLD_Pq_Qq 0x0fd2
+#define OP_PSRLD_Vdq_Wdq 0x660fd2
+#define OP_PSRLQ_Pq_Qq 0x0fd3
+#define OP_PSRLQ_Vdq_Wdq 0x660fd3
+#define OP_PADDQ_Pq_Qq 0x0fd4
+#define OP_PADDQ_Vdq_Wdq 0x660fd4
+#define OP_PMULLW_Pq_Qq 0x0fd5
+#define OP_PMULLW_Vdq_Wdq 0x660fd5
+#define OP_MOVQ_Wq_Vq 0x0fd6
+#define OP_MOVQ2DQ_Vdq_Qq 0xf30fd6
+#define OP_MOVDQ2Q_Pq_Vq 0xf20fd6
+#define OP_PMOVMSKB_Gd_Pq 0x0fd7
+#define OP_PMOVMSKB_Gd_Vdq 0x660fd7
+#define OP_PSUBUSB_Pq_Qq 0x0fd8
+#define OP_PSUBUSB_Vdq_Wdq 0x660fd8
+#define OP_PSUBUSW_Pq_Qq 0x0fd9
+#define OP_PSUBUSW_Vdq_Wdq 0x660fd9
+#define OP_PMINUB_Pq_Qq 0x0fda
+#define OP_PMINUB_Vdq_Wdq 0x660fda
+#define OP_PAND_Pq_Qq 0x0fdb
+#define OP_PAND_Vdq_Wdq 0x660fdb
+#define OP_PADDUSB_Pq_Qq 0x0fdc
+#define OP_PADDUSB_Vdq_Wdq 0x660fdc
+#define OP_PADDUSW_Pq_Qq 0x0fdd
+#define OP_PADDUSW_Vdq_Wdq 0x660fdd
+#define OP_PMAXUB_Pq_Qq 0x0fde
+#define OP_PMAXUB_Vdq_Wdq 0x660fde
+#define OP_PANDN_Pq_Qq 0x0fdf
+#define OP_PANDN_Vdq_Wdq 0x660fdf
+
+#define OP_PAVGB_Pq_Qq 0x0fe0
+#define OP_PAVGB_Vdq_Wdq 0x660fe0
+#define OP_PSRAW_Pq_Qq 0x0fe1
+#define OP_PSRAW_Vdq_Wdq 0x660fe1
+#define OP_PSRAD_Pq_Qq 0x0fe2
+#define OP_PSRAD_Vdq_Wdq 0x660fe2
+#define OP_PAVGW_Pq_Qq 0x0fe3
+#define OP_PAVGW_Vdq_Wdq 0x660fe3
+#define OP_PMULHUW_Pq_Qq 0x0fe4
+#define OP_PMULHUW_Vdq_Wdq 0x660fe4
+#define OP_PMULHW_Pq_Qq 0x0fe5
+#define OP_PMULHW_Vdq_Wdq 0x660fe5
+#define OP_CVTPD2DQ_Vdq_Wpd 0xf20fe6
+#define OP_CVTTPD2DQ_Vdq_Wpd 0x660fe6
+#define OP_CVTDQ2PD_Vpd_Wq 0xf30fe6
+#define OP_MOVNTQ_Mq_Vq 0x0fe7
+#define OP_MOVNTDQ_Mdq_Vdq 0x660fe7
+#define OP_PSUBSB_Pq_Qq 0x0fe8
+#define OP_PSUBSB_Vdq_Wdq 0x660fe8
+#define OP_PSUBSW_Pq_Qq 0x0fe9
+#define OP_PSUBSW_Vdq_Wdq 0x660fe9
+#define OP_PMINSW_Pq_Qq 0x0fea
+#define OP_PMINSW_Vdq_Wdq 0x660fea
+#define OP_POR_Pq_Qq 0x0feb
+#define OP_POR_Vdq_Wdq 0x660feb
+#define OP_PADDSB_Pq_Qq 0x0fec
+#define OP_PADDSB_Vdq_Wdq 0x660fec
+#define OP_PADDSW_Pq_Qq 0x0fed
+#define OP_PADDSW_Vdq_Wdq 0x660fed
+#define OP_PMAXSW_Pq_Qq 0x0fee
+#define OP_PMAXSW_Vdq_Wdq 0x660fee
+#define OP_PXOR_Pq_Qq 0x0fef
+#define OP_PXOR_Vdq_Wdq 0x660fef
+
+#define OP_LDDQU_Vdq_Mdq 0xf20ff0
+#define OP_PSLLW_Pq_Qq 0x0ff1
+#define OP_PSLLW_Vdq_Wdq 0x660ff1
+#define OP_PSLLD_Pq_Qq 0x0ff2
+#define OP_PSLLD_Vdq_Wdq 0x660ff2
+#define OP_PSLLQ_Pq_Qq 0x0ff3
+#define OP_PSLLQ_Vdq_Wdq 0x660ff3
+#define OP_PMULUDQ_Pq_Qq 0x0ff4
+#define OP_PMULUDQ_Vdq_Wdq 0x660ff4
+#define OP_PMADDWD_Pq_Qq 0x0ff5
+#define OP_PMADDWD_Vdq_Wdq 0x660ff5
+#define OP_PSADBW_Pq_Qq 0x0ff6
+#define OP_PSADBW_Vdq_Wdq 0x660ff6
+#define OP_MASKMOVQ_Pq_Qq 0x0ff7
+#define OP_MASKMOVDQU_Vdq_Wdq 0x660ff7
+#define OP_PSUBB_Pq_Qq 0x0ff8
+#define OP_PSUBB_Vdq_Wdq 0x660ff8
+#define OP_PSUBW_Pq_Qq 0x0ff9
+#define OP_PSUBW_Vdq_Wdq 0x660ff9
+#define OP_PSUBD_Pq_Qq 0x0ffa
+#define OP_PSUBD_Vdq_Wdq 0x660ffa
+#define OP_PSUBQ_Pq_Qq 0x0ffb
+#define OP_PSUBQ_Vdq_Wdq 0x660ffb
+#define OP_PADDB_Pq_Qq 0x0ffc
+#define OP_PADDB_Vdq_Wdq 0x660ffc
+#define OP_PADDW_Pq_Qq 0x0ffd
+#define OP_PADDW_Vdq_Wdq 0x660ffd
+#define OP_PADDD_Pq_Qq 0x0ffe
+#define OP_PADDD_Vdq_Wdq 0x660ffe
+
+
+/* floating point opcodes */
+#define OP_FADD_ST0_STn 0xd8c0
+#define OP_FMUL_ST0_STn 0xd8c8
+#define OP_FCOM_ST0_STn 0xd8d0
+#define OP_FCOMP_ST0_STn 0xd8d8
+#define OP_FSUB_ST0_STn 0xd8e0
+#define OP_FSUBR_ST0_STn 0xd8e8
+#define OP_FDIV_ST0_STn 0xd8f0
+#define OP_FDIVR_ST0_STn 0xd8f8
+#define OP_FLD_ST0_STn 0xd9c0
+#define OP_FXCH_ST0_STn 0xd9c8
+#define OP_FNOP 0xd9d0
+#define OP_FCHS 0xd9e0
+#define OP_FABS 0xd9e1
+#define OP_FTST 0xd9e4
+#define OP_FXAM 0xd9e5
+#define OP_FLD1 0xd9e8
+#define OP_FLDL2T 0xd9e9
+#define OP_FLDL2E 0xd9ea
+#define OP_FLDPI 0xd9eb
+#define OP_FLDLG2 0xd9ec
+#define OP_FLDLN2 0xd9ed
+#define OP_FLDZ 0xd9ee
+#define OP_F2XM1 0xd9f0
+#define OP_FYL2X 0xd9f1
+#define OP_FPTAN 0xd9f2
+#define OP_FPATAN 0xd9f3
+#define OP_FXTRACT 0xd9f4
+#define OP_FPREM1 0xd9f5
+#define OP_FDECSTP 0xd9f6
+#define OP_FINCSTP 0xd9f7
+#define OP_FPREM 0xd9f8
+#define OP_FYL2XP1 0xd9f9
+#define OP_FSQRT 0xd9fa
+#define OP_FSINCOS 0xd9fb
+#define OP_FRNDINT 0xd9fc
+#define OP_FSCALE 0xd9fd
+#define OP_FSIN 0xd9fe
+#define OP_FCOS 0xd9ff
+#define OP_FCMOVB_ST0_STn 0xdac0
+#define OP_FCMOVE_ST0_STn 0xdac8
+#define OP_FCMOVBE_ST0_STn 0xdad0
+#define OP_FCMOVU_ST0_STn 0xdad8
+#define OP_FUCOMPP 0xdae9
+#define OP_FCMOVNB_ST0_STn 0xdbc0
+#define OP_FCMOVNE_ST0_STn 0xdbc8
+#define OP_FCMOVNBE_ST0_STn 0xdbd0
+#define OP_FCMOVNU_ST0_STn 0xdbd8
+#define OP_FCLEX 0xdbe2
+#define OP_FINIT 0xdbe3
+#define OP_FUCOMI_ST0_STn 0xdbe8
+#define OP_FCOMI_ST0_STn 0xdbf0
+#define OP_FADD_STn_ST0 0xdcc0
+#define OP_FMUL_STn_ST0 0xdcc8
+#define OP_FSUBR_STn_ST0 0xdce0
+#define OP_FSUB_STn_ST0 0xdce8
+#define OP_FDIVR_STn_ST0 0xdcf0
+#define OP_FDIV_STn_ST0 0xdcf8
+#define OP_FFREE_STn 0xddc0
+#define OP_FST_STn 0xddd0
+#define OP_FSTP_STn 0xddd8
+#define OP_FUCOM_STn_ST0 0xdde0
+#define OP_FUCOMP_STn 0xdde8
+#define OP_FADDP_STn_ST0 0xdec0
+#define OP_FMULP_STn_ST0 0xdec8
+#define OP_FCOMPP 0xded9
+#define OP_FSUBRP_STn_ST0 0xdee0
+#define OP_FSUBP_STn_ST0 0xdee8
+#define OP_FDIVRP_STn_ST0 0xdef0
+#define OP_FDIVP_STn_ST0 0xdef8
+#define OP_FSTSW_AX 0xdfe0
+#define OP_FCOMIP_ST0_STn 0xdff0
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* use x86code * to reference generated code */
+typedef UINT8 x86code;
+
+
+/* this structure tracks information about a link */
+typedef struct _emit_link emit_link;
+struct _emit_link
+{
+ x86code * target;
+ UINT8 size;
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define DECLARE_MEMPARAMS UINT8 base, UINT8 index, UINT8 scale, INT32 disp
+#define MEMPARAMS base, index, scale, disp
+
+#ifndef PTR64
+#define MBISD(base, index, scale, disp) (base), (index), (scale), (INT32)(disp)
+#define MABS(addr) MBISD(REG_NONE, REG_NONE, 1, (addr))
+#define MBD(base, disp) MBISD((base), REG_NONE, 1, (disp))
+#define MISD(index, scale, disp) MBISD(REG_NONE, (index), (scale), (disp))
+#else
+#define MBISD(base, index, scale, disp) (base), (index), (scale), (disp)
+#define MBD(base, disp) MBISD((base), REG_NONE, 1, (disp))
+#define MISD(index, scale, disp) MBISD(REG_NONE, (index), (scale), (disp))
+#endif
+
+
+
+/***************************************************************************
+ CORE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ make_modrm - assemble a modrm byte from the
+ three components
+-------------------------------------------------*/
+
+INLINE UINT8 make_modrm(UINT8 mode, UINT8 reg, UINT8 rm)
+{
+ assert(mode < 4);
+ assert(reg < REG_MAX);
+ assert(rm < REG_MAX);
+ return (mode << 6) | ((reg & 7) << 3) | (rm & 7);
+}
+
+
+/*-------------------------------------------------
+ make_sib - assemble an sib byte from the
+ three components
+-------------------------------------------------*/
+
+INLINE UINT8 make_sib(UINT8 scale, UINT8 index, UINT8 base)
+{
+ static const UINT8 scale_lookup[9] = { 0<<6, 0<<6, 1<<6, 0<<6, 2<<6, 0<<6, 0<<6, 0<<6, 3<<6 };
+ assert(scale == 1 || scale == 2 || scale == 4 || scale == 8);
+ assert(index < REG_MAX);
+ assert(base < REG_MAX);
+ return scale_lookup[scale] | ((index & 7) << 3) | (base & 7);
+}
+
+
+/*-------------------------------------------------
+ emit_byte - emit a byte
+-------------------------------------------------*/
+
+INLINE void emit_byte(x86code **emitptr, UINT8 byte)
+{
+ *((UINT8 *)*emitptr) = byte;
+ *emitptr += 1;
+}
+
+
+/*-------------------------------------------------
+ emit_word - emit a word
+-------------------------------------------------*/
+
+INLINE void emit_word(x86code **emitptr, UINT16 word)
+{
+ *((UINT16 *)*emitptr) = word;
+ *emitptr += 2;
+}
+
+
+/*-------------------------------------------------
+ emit_dword - emit a dword
+-------------------------------------------------*/
+
+INLINE void emit_dword(x86code **emitptr, UINT32 dword)
+{
+ *((UINT32 *)*emitptr) = dword;
+ *emitptr += 4;
+}
+
+
+/*-------------------------------------------------
+ emit_qword - emit a dword
+-------------------------------------------------*/
+
+INLINE void emit_qword(x86code **emitptr, UINT64 qword)
+{
+ *((UINT64 *)*emitptr) = qword;
+ *emitptr += 8;
+}
+
+
+
+/***************************************************************************
+ GENERIC OPCODE EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_op - emit a 1, 2, or 3-byte opcode,
+ along with any necessary REX prefixes for x64
+-------------------------------------------------*/
+
+INLINE void emit_op(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 sib, UINT8 rm)
+{
+ if (opsize == OP_16BIT)
+ emit_byte(emitptr, PREFIX_OPSIZE);
+
+#ifdef PTR64
+{
+ UINT8 rex;
+
+ assert(opsize == OP_16BIT || opsize == OP_32BIT || opsize == OP_64BIT);
+
+ rex = (opsize & 8) | ((reg & 8) >> 1) | ((sib & 8) >> 2) | ((rm & 8) >> 3);
+ if (rex != 0 || ((op & OPFLAG_8BITREG) && reg >= 4) || ((op & OPFLAG_8BITRM) && rm >= 4))
+ emit_byte(emitptr, OP_REX + rex);
+}
+#else
+ assert(opsize != OP_64BIT);
+#endif
+
+ if ((op & 0xff0000) != 0)
+ emit_byte(emitptr, op >> 16);
+ if ((op & 0xff00) != 0)
+ emit_byte(emitptr, op >> 8);
+ emit_byte(emitptr, op);
+}
+
+
+/*-------------------------------------------------
+ emit_op_simple - emit a simple opcode
+-------------------------------------------------*/
+
+INLINE void emit_op_simple(x86code **emitptr, UINT32 op, UINT8 opsize)
+{
+ emit_op(emitptr, op, opsize, 0, 0, 0);
+}
+
+
+/*-------------------------------------------------
+ emit_op_reg - emit a simple opcode that has
+ a register parameter
+-------------------------------------------------*/
+
+INLINE void emit_op_reg(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg)
+{
+ emit_op(emitptr, op, opsize, 0, 0, reg);
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_reg - emit an opcode with a
+ register modrm byte
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_reg(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 rm)
+{
+ assert(reg < REG_MAX);
+ assert(rm < REG_MAX);
+
+ emit_op(emitptr, op, opsize, reg, 0, rm);
+ emit_byte(emitptr, make_modrm(3, reg, rm));
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_mem - emit an opcode with a
+ memory modrm byte
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_mem(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg, DECLARE_MEMPARAMS)
+{
+ assert(reg < REG_MAX);
+ assert(base < REG_MAX || base == REG_NONE);
+ assert(index < REG_MAX || index == REG_NONE);
+
+ /* turn off the OPFLAG_8BITRM flag since it only applies to register operands */
+ op &= ~OPFLAG_8BITRM;
+
+ /* displacement only case */
+ if (base == REG_NONE && index == REG_NONE)
+ {
+#ifndef PTR64
+ emit_op(emitptr, op, opsize, reg, 0, 5);
+ emit_byte(emitptr, make_modrm(0, reg, 5));
+ emit_dword(emitptr, disp);
+#else
+ fatalerror("Invalid absolute mode in 64-bits!\n");
+#endif
+ }
+
+ /* base only case */
+ else if (index == REG_NONE && (base & 7) != REG_ESP)
+ {
+ emit_op(emitptr, op, opsize, reg, 0, base);
+
+ /* mode 0 for no offset */
+ if (disp == 0 && (base & 7) != REG_EBP)
+ emit_byte(emitptr, make_modrm(0, reg, base));
+
+ /* mode 1 for 1-byte offset */
+ else if ((INT8)disp == disp)
+ {
+ emit_byte(emitptr, make_modrm(1, reg, base));
+ emit_byte(emitptr, (INT8)disp);
+ }
+
+ /* mode 2 for 4-byte offset */
+ else
+ {
+ emit_byte(emitptr, make_modrm(2, reg, base));
+ emit_dword(emitptr, disp);
+ }
+ }
+
+ /* full BISD case */
+ else
+ {
+ assert(index != REG_ESP);
+ emit_op(emitptr, op, opsize, reg, index, base);
+
+ /* a "none" index == REG_ESP */
+ if (index == REG_NONE)
+ index = REG_ESP;
+
+ /* no base is a special case */
+ if (base == REG_NONE)
+ {
+ emit_byte(emitptr, make_modrm(0, reg, 4));
+ emit_byte(emitptr, make_sib(scale, index, REG_EBP));
+ emit_dword(emitptr, disp);
+ }
+
+ /* mode 0 for no offset */
+ else if (disp == 0 && (base & 7) != REG_EBP)
+ {
+ emit_byte(emitptr, make_modrm(0, reg, 4));
+ emit_byte(emitptr, make_sib(scale, index, base));
+ }
+
+ /* mode 1 for 1-byte offset */
+ else if ((INT8)disp == disp)
+ {
+ emit_byte(emitptr, make_modrm(1, reg, 4));
+ emit_byte(emitptr, make_sib(scale, index, base));
+ emit_byte(emitptr, (INT8)disp);
+ }
+
+ /* mode 2 for 4-byte offset */
+ else
+ {
+ emit_byte(emitptr, make_modrm(2, reg, 4));
+ emit_byte(emitptr, make_sib(scale, index, base));
+ emit_dword(emitptr, disp);
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ GENERIC OPCODE + IMMEDIATE EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_op_modrm_reg_imm8 - emit an opcode with a
+ register modrm byte and an 8-bit immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_reg_imm8(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 rm, UINT8 imm)
+{
+ emit_op_modrm_reg(emitptr, op, opsize, reg, rm);
+ emit_byte(emitptr, imm);
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_mem_imm8 - emit an opcode with a
+ memory modrm byte and an 8-bit immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_mem_imm8(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg, DECLARE_MEMPARAMS, UINT8 imm)
+{
+ emit_op_modrm_mem(emitptr, op, opsize, reg, MEMPARAMS);
+ emit_byte(emitptr, imm);
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_reg_imm16 - emit an opcode with a
+ register modrm byte and a 16-bit immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_reg_imm16(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 rm, UINT16 imm)
+{
+ emit_op_modrm_reg(emitptr, op, opsize, reg, rm);
+ emit_word(emitptr, imm);
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_mem_imm16 - emit an opcode with a
+ memory modrm byte and a 16-bit immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_mem_imm16(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg, DECLARE_MEMPARAMS, UINT16 imm)
+{
+ emit_op_modrm_mem(emitptr, op, opsize, reg, MEMPARAMS);
+ emit_word(emitptr, imm);
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_reg_imm816 - emit an opcode with
+ a register modrm byte and an 8-bit or 16-bit
+ immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_reg_imm816(x86code **emitptr, UINT32 op8, UINT32 op16, UINT8 opsize, UINT8 reg, UINT8 rm, UINT16 imm)
+{
+ if ((INT8)imm == (INT16)imm)
+ {
+ emit_op_modrm_reg(emitptr, op8, opsize, reg, rm);
+ emit_byte(emitptr, imm);
+ }
+ else
+ {
+ emit_op_modrm_reg(emitptr, op16, opsize, reg, rm);
+ emit_word(emitptr, imm);
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_mem_imm816 - emit an opcode with
+ a memory modrm byte and an 8-bit or 16-bit
+ immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_mem_imm816(x86code **emitptr, UINT32 op8, UINT32 op16, UINT8 opsize, UINT8 reg, DECLARE_MEMPARAMS, UINT16 imm)
+{
+ if ((INT8)imm == (INT16)imm)
+ {
+ emit_op_modrm_mem(emitptr, op8, opsize, reg, MEMPARAMS);
+ emit_byte(emitptr, imm);
+ }
+ else
+ {
+ emit_op_modrm_mem(emitptr, op16, opsize, reg, MEMPARAMS);
+ emit_word(emitptr, imm);
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_reg_imm32 - emit an opcode with a
+ register modrm byte and a 32-bit immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_reg_imm32(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 rm, UINT32 imm)
+{
+ emit_op_modrm_reg(emitptr, op, opsize, reg, rm);
+ emit_dword(emitptr, imm);
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_mem_imm32 - emit an opcode with a
+ memory modrm byte and a 32-bit immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_mem_imm32(x86code **emitptr, UINT32 op, UINT8 opsize, UINT8 reg, DECLARE_MEMPARAMS, UINT32 imm)
+{
+ emit_op_modrm_mem(emitptr, op, opsize, reg, MEMPARAMS);
+ emit_dword(emitptr, imm);
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_reg_imm832 - emit an opcode with
+ a register modrm byte and an 8-bit or 32-bit
+ immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_reg_imm832(x86code **emitptr, UINT32 op8, UINT32 op32, UINT8 opsize, UINT8 reg, UINT8 rm, UINT32 imm)
+{
+ if ((INT8)imm == (INT32)imm)
+ {
+ emit_op_modrm_reg(emitptr, op8, opsize, reg, rm);
+ emit_byte(emitptr, imm);
+ }
+ else
+ {
+ emit_op_modrm_reg(emitptr, op32, opsize, reg, rm);
+ emit_dword(emitptr, imm);
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_op_modrm_mem_imm832 - emit an opcode with
+ a memory modrm byte and an 8-bit or 32-bit
+ immediate
+-------------------------------------------------*/
+
+INLINE void emit_op_modrm_mem_imm832(x86code **emitptr, UINT32 op8, UINT32 op32, UINT8 opsize, UINT8 reg, DECLARE_MEMPARAMS, UINT32 imm)
+{
+ if ((INT8)imm == (INT32)imm)
+ {
+ emit_op_modrm_mem(emitptr, op8, opsize, reg, MEMPARAMS);
+ emit_byte(emitptr, imm);
+ }
+ else
+ {
+ emit_op_modrm_mem(emitptr, op32, opsize, reg, MEMPARAMS);
+ emit_dword(emitptr, imm);
+ }
+}
+
+
+
+/***************************************************************************
+ SIMPLE OPCODE EMITTERS
+***************************************************************************/
+
+INLINE void emit_nop(x86code **emitptr) { emit_op_simple(emitptr, OP_NOP, OP_32BIT); }
+INLINE void emit_int_3(x86code **emitptr) { emit_op_simple(emitptr, OP_INT_3, OP_32BIT); }
+INLINE void emit_ret(x86code **emitptr) { emit_op_simple(emitptr, OP_RETN, OP_32BIT); }
+INLINE void emit_cdq(x86code **emitptr) { emit_op_simple(emitptr, OP_CDQ, OP_32BIT); }
+INLINE void emit_cmc(x86code **emitptr) { emit_op_simple(emitptr, OP_CMC, OP_32BIT); }
+
+#ifndef PTR64
+INLINE void emit_pushad(x86code **emitptr) { emit_op_simple(emitptr, OP_PUSHA, OP_32BIT); }
+INLINE void emit_popad(x86code **emitptr) { emit_op_simple(emitptr, OP_POPA, OP_32BIT); }
+INLINE void emit_lahf(x86code **emitptr) { emit_op_simple(emitptr, OP_LAHF, OP_32BIT); }
+INLINE void emit_sahf(x86code **emitptr) { emit_op_simple(emitptr, OP_SAHF, OP_32BIT); }
+#endif
+
+#ifdef PTR64
+INLINE void emit_cqo(x86code **emitptr) { emit_op_simple(emitptr, OP_CQO, OP_64BIT); }
+#endif
+
+
+
+/***************************************************************************
+ CALL/JUMP EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ resolve_link - resolve a link in a jump
+ instruction
+-------------------------------------------------*/
+
+INLINE void resolve_link(x86code **destptr, const emit_link *linkinfo)
+{
+ INT64 delta = *destptr - linkinfo->target;
+ if (linkinfo->size == 1)
+ {
+ assert((INT8)delta == delta);
+ ((INT8 *)linkinfo->target)[-1] = (INT8)delta;
+ }
+ else if (linkinfo->size == 2)
+ {
+ assert((INT16)delta == delta);
+ ((INT16 *)linkinfo->target)[-1] = (INT16)delta;
+ }
+ else
+ {
+ assert((INT32)delta == delta);
+ ((INT32 *)linkinfo->target)[-1] = (INT32)delta;
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_call_*
+-------------------------------------------------*/
+
+INLINE void emit_call_link(x86code **emitptr, emit_link *linkinfo)
+{
+ emit_op_simple(emitptr, OP_CALL_Jz, OP_32BIT);
+ emit_dword(emitptr, 0);
+ linkinfo->target = *emitptr;
+ linkinfo->size = 4;
+}
+
+INLINE void emit_call(x86code **emitptr, x86code *target)
+{
+ emit_link link;
+ emit_call_link(emitptr, &link);
+ resolve_link(&target, &link);
+}
+
+
+/*-------------------------------------------------
+ emit_jmp_*
+-------------------------------------------------*/
+
+INLINE void emit_jmp_short_link(x86code **emitptr, emit_link *linkinfo)
+{
+ emit_op_simple(emitptr, OP_JMP_Jb, OP_32BIT);
+ emit_byte(emitptr, 0);
+ linkinfo->target = *emitptr;
+ linkinfo->size = 1;
+}
+
+INLINE void emit_jmp_near_link(x86code **emitptr, emit_link *linkinfo)
+{
+ emit_op_simple(emitptr, OP_JMP_Jz, OP_32BIT);
+ emit_dword(emitptr, 0);
+ linkinfo->target = *emitptr;
+ linkinfo->size = 4;
+}
+
+INLINE void emit_jmp(x86code **emitptr, x86code *target)
+{
+ INT32 delta = target - (*emitptr + 2);
+ emit_link link;
+
+ if ((INT8)delta == delta)
+ emit_jmp_short_link(emitptr, &link);
+ else
+ emit_jmp_near_link(emitptr, &link);
+ resolve_link(&target, &link);
+}
+
+
+/*-------------------------------------------------
+ emit_jcc_*
+-------------------------------------------------*/
+
+INLINE void emit_jcc_short_link(x86code **emitptr, UINT8 cond, emit_link *linkinfo)
+{
+ emit_op_simple(emitptr, OP_JCC_O_Jb + cond, OP_32BIT);
+ emit_byte(emitptr, 0);
+ linkinfo->target = *emitptr;
+ linkinfo->size = 1;
+}
+
+INLINE void emit_jcc_near_link(x86code **emitptr, UINT8 cond, emit_link *linkinfo)
+{
+ emit_op_simple(emitptr, OP_JCC_O_Jv + cond, OP_32BIT);
+ emit_dword(emitptr, 0);
+ linkinfo->target = *emitptr;
+ linkinfo->size = 4;
+}
+
+INLINE void emit_jcc(x86code **emitptr, UINT8 cond, x86code *target)
+{
+ INT32 delta = *emitptr + 2 - target;
+ emit_link link;
+
+ if ((INT8)delta == delta)
+ emit_jcc_short_link(emitptr, cond, &link);
+ else
+ emit_jcc_near_link(emitptr, cond, &link);
+ resolve_link(&target, &link);
+}
+
+
+/*-------------------------------------------------
+ emit_call/jmp_*
+-------------------------------------------------*/
+
+#ifndef PTR64
+INLINE void emit_call_r32(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G5, OP_32BIT, 2, dreg); }
+INLINE void emit_call_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_jmp_r32(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G5, OP_32BIT, 4, dreg); }
+INLINE void emit_jmp_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 4, MEMPARAMS); }
+#else
+INLINE void emit_call_r64(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G5, OP_32BIT, 2, dreg); }
+INLINE void emit_call_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_jmp_r64(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G5, OP_32BIT, 4, dreg); }
+INLINE void emit_jmp_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 4, MEMPARAMS); }
+#endif
+
+
+
+/***************************************************************************
+ PUSH/POP EMITTERS
+***************************************************************************/
+
+INLINE void emit_push_imm(x86code **emitptr, INT32 imm)
+{
+ if ((INT8)imm == imm)
+ {
+ emit_op_simple(emitptr, OP_PUSH_Ib, OP_32BIT);
+ emit_byte(emitptr, (INT8)imm);
+ }
+ else
+ {
+ emit_op_simple(emitptr, OP_PUSH_Iz, OP_32BIT);
+ emit_dword(emitptr, imm);
+ }
+}
+
+#ifndef PTR64
+
+INLINE void emit_push_r32(x86code **emitptr, UINT8 reg) { emit_op_reg(emitptr, OP_PUSH_rAX + (reg & 7), OP_32BIT, reg); }
+INLINE void emit_push_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 6, MEMPARAMS); }
+INLINE void emit_pop_r32(x86code **emitptr, UINT8 reg) { emit_op_reg(emitptr, OP_POP_rAX + (reg & 7), OP_32BIT, reg); }
+INLINE void emit_pop_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G1A_Ev, OP_32BIT, 0, MEMPARAMS); }
+
+#else
+
+INLINE void emit_push_r64(x86code **emitptr, UINT8 reg) { emit_op_reg(emitptr, OP_PUSH_rAX + (reg & 7), OP_32BIT, reg); }
+INLINE void emit_push_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 6, MEMPARAMS); }
+INLINE void emit_pop_r64(x86code **emitptr, UINT8 reg) { emit_op_reg(emitptr, OP_POP_rAX + (reg & 7), OP_32BIT, reg); }
+INLINE void emit_pop_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G1A_Ev, OP_32BIT, 0, MEMPARAMS); }
+
+#endif
+
+
+
+/***************************************************************************
+ MOVE EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_mov_r8_*
+-------------------------------------------------*/
+
+INLINE void emit_mov_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm)
+{
+ emit_op_reg(emitptr, OP_MOV_AL_Ib | (dreg & 7), OP_32BIT, dreg);
+ emit_byte(emitptr, imm);
+}
+
+INLINE void emit_mov_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOV_Gb_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_mov_r8_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOV_Gb_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_mov_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOV_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+INLINE void emit_mov_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G11_Eb_Ib, OP_32BIT, 0, MEMPARAMS, imm); }
+
+
+/*-------------------------------------------------
+ emit_mov_r16_*
+-------------------------------------------------*/
+
+INLINE void emit_mov_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm)
+{
+ emit_op_reg(emitptr, OP_MOV_rAX_Iv | (dreg & 7), OP_16BIT, dreg);
+ emit_word(emitptr, imm);
+}
+
+INLINE void emit_mov_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOV_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_mov_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOV_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_mov_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm16(emitptr, OP_G11_Ev_Iz, OP_16BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_mov_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOV_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+INLINE void emit_movsx_r16_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Eb, OP_16BIT, dreg, sreg); }
+INLINE void emit_movsx_r16_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Eb, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_movzx_r16_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Eb, OP_16BIT, dreg, sreg); }
+INLINE void emit_movzx_r16_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Eb, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_cmovcc_r16_r16(x86code **emitptr, UINT8 cond, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_16BIT, dreg, sreg); }
+INLINE void emit_cmovcc_r16_m16(x86code **emitptr, UINT8 cond, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_16BIT, dreg, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_mov_r32_*
+-------------------------------------------------*/
+
+INLINE void emit_mov_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm)
+{
+ emit_op_reg(emitptr, OP_MOV_rAX_Iv | (dreg & 7), OP_32BIT, dreg);
+ emit_dword(emitptr, imm);
+}
+
+INLINE void emit_mov_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOV_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_mov_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOV_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_mov_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm32(emitptr, OP_G11_Ev_Iz, OP_32BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_mov_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOV_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+INLINE void emit_movsx_r32_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_movsx_r32_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_movsx_r32_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Ew, OP_32BIT, dreg, sreg); }
+INLINE void emit_movsx_r32_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Ew, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_movzx_r32_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_movzx_r32_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_movzx_r32_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Ew, OP_32BIT, dreg, sreg); }
+INLINE void emit_movzx_r32_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Ew, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_cmovcc_r32_r32(x86code **emitptr, UINT8 cond, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_32BIT, dreg, sreg); }
+INLINE void emit_cmovcc_r32_m32(x86code **emitptr, UINT8 cond, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_32BIT, dreg, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_mov_r64_*
+-------------------------------------------------*/
+
+#ifdef PTR64
+
+INLINE void emit_mov_r64_imm(x86code **emitptr, UINT8 dreg, UINT64 imm)
+{
+ if ((UINT32)imm == imm)
+ {
+ emit_op_reg(emitptr, OP_MOV_rAX_Iv | (dreg & 7), OP_32BIT, dreg);
+ emit_dword(emitptr, imm);
+ }
+ else if ((INT32)imm == imm)
+ emit_op_modrm_reg_imm32(emitptr, OP_G11_Ev_Iz, OP_64BIT, 0, dreg, imm);
+ else
+ {
+ emit_op_reg(emitptr, OP_MOV_rAX_Iv | (dreg & 7), OP_64BIT, dreg);
+ emit_qword(emitptr, imm);
+ }
+}
+
+INLINE void emit_mov_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOV_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_mov_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOV_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_mov_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm32(emitptr, OP_G11_Ev_Iz, OP_64BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_mov_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOV_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+INLINE void emit_movsx_r64_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Eb, OP_64BIT, dreg, sreg); }
+INLINE void emit_movsx_r64_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Eb, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_movsx_r64_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Ew, OP_64BIT, dreg, sreg); }
+INLINE void emit_movsx_r64_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Ew, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_movsxd_r64_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSXD_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_movsxd_r64_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVSXD_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_movzx_r64_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Eb, OP_64BIT, dreg, sreg); }
+INLINE void emit_movzx_r64_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Eb, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_movzx_r64_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Ew, OP_64BIT, dreg, sreg); }
+INLINE void emit_movzx_r64_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Ew, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_cmovcc_r64_r64(x86code **emitptr, UINT8 cond, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_64BIT, dreg, sreg); }
+INLINE void emit_cmovcc_r64_m64(x86code **emitptr, UINT8 cond, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_64BIT, dreg, MEMPARAMS); }
+
+#endif
+
+
+
+/***************************************************************************
+ ARITHMETIC EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_arith_r8_*
+-------------------------------------------------*/
+
+INLINE void emit_add_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 0, dreg, imm); }
+INLINE void emit_add_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_add_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADD_Gb_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_add_r8_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADD_Gb_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_add_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADD_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_or_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 1, dreg, imm); }
+INLINE void emit_or_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 1, MEMPARAMS, imm); }
+INLINE void emit_or_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_OR_Gb_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_or_r8_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_OR_Gb_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_or_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_OR_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_adc_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 2, dreg, imm); }
+INLINE void emit_adc_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 2, MEMPARAMS, imm); }
+INLINE void emit_adc_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADC_Gb_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_adc_r8_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADC_Gb_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_adc_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADC_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_sbb_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 3, dreg, imm); }
+INLINE void emit_sbb_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 3, MEMPARAMS, imm); }
+INLINE void emit_sbb_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SBB_Gb_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_sbb_r8_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SBB_Gb_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_sbb_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SBB_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_and_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 4, dreg, imm); }
+INLINE void emit_and_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 4, MEMPARAMS, imm); }
+INLINE void emit_and_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_AND_Gb_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_and_r8_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_AND_Gb_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_and_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_AND_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_sub_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 5, dreg, imm); }
+INLINE void emit_sub_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 5, MEMPARAMS, imm); }
+INLINE void emit_sub_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUB_Gb_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_sub_r8_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SUB_Gb_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_sub_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SUB_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_xor_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 6, dreg, imm); }
+INLINE void emit_xor_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 6, MEMPARAMS, imm); }
+INLINE void emit_xor_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XOR_Gb_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_xor_r8_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_XOR_Gb_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_xor_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_XOR_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_cmp_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 7, dreg, imm); }
+INLINE void emit_cmp_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 7, MEMPARAMS, imm); }
+INLINE void emit_cmp_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMP_Gb_Eb, OP_32BIT, dreg, sreg); }
+INLINE void emit_cmp_r8_m8(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CMP_Gb_Eb, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_cmp_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_CMP_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_test_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G3_Eb, OP_32BIT, 0, dreg, imm); }
+INLINE void emit_test_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G3_Eb, OP_32BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_test_r8_r8(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_TEST_Eb_Gb, OP_32BIT, sreg, dreg); }
+INLINE void emit_test_m8_r8(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_TEST_Eb_Gb, OP_32BIT, sreg, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_arith_r16_*
+-------------------------------------------------*/
+
+INLINE void emit_add_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 0, dreg, imm); }
+INLINE void emit_add_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_add_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADD_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_add_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADD_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_add_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADD_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_or_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 1, dreg, imm); }
+INLINE void emit_or_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 1, MEMPARAMS, imm); }
+INLINE void emit_or_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_OR_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_or_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_OR_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_or_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_OR_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_adc_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 2, dreg, imm); }
+INLINE void emit_adc_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 2, MEMPARAMS, imm); }
+INLINE void emit_adc_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADC_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_adc_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADC_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_adc_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADC_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_sbb_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 3, dreg, imm); }
+INLINE void emit_sbb_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 3, MEMPARAMS, imm); }
+INLINE void emit_sbb_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SBB_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_sbb_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SBB_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_sbb_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SBB_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_and_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 4, dreg, imm); }
+INLINE void emit_and_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 4, MEMPARAMS, imm); }
+INLINE void emit_and_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_AND_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_and_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_AND_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_and_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_AND_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_sub_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 5, dreg, imm); }
+INLINE void emit_sub_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 5, MEMPARAMS, imm); }
+INLINE void emit_sub_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUB_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_sub_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SUB_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_sub_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SUB_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_xor_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 6, dreg, imm); }
+INLINE void emit_xor_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 6, MEMPARAMS, imm); }
+INLINE void emit_xor_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XOR_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_xor_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_XOR_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_xor_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_XOR_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_cmp_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 7, dreg, imm); }
+INLINE void emit_cmp_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 7, MEMPARAMS, imm); }
+INLINE void emit_cmp_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMP_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_cmp_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CMP_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_cmp_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_CMP_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_test_r16_imm(x86code **emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm16(emitptr, OP_G3_Ev, OP_16BIT, 0, dreg, imm); }
+INLINE void emit_test_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT16 imm) { emit_op_modrm_mem_imm16(emitptr, OP_G3_Ev, OP_16BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_test_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_TEST_Ev_Gv, OP_16BIT, sreg, dreg); }
+INLINE void emit_test_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_TEST_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_arith_r32_*
+-------------------------------------------------*/
+
+INLINE void emit_add_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 0, dreg, imm); }
+INLINE void emit_add_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_add_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADD_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_add_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADD_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_add_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADD_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_or_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 1, dreg, imm); }
+INLINE void emit_or_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 1, MEMPARAMS, imm); }
+INLINE void emit_or_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_OR_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_or_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_OR_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_or_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_OR_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_adc_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 2, dreg, imm); }
+INLINE void emit_adc_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 2, MEMPARAMS, imm); }
+INLINE void emit_adc_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADC_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_adc_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADC_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_adc_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADC_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_sbb_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 3, dreg, imm); }
+INLINE void emit_sbb_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 3, MEMPARAMS, imm); }
+INLINE void emit_sbb_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SBB_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_sbb_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SBB_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_sbb_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SBB_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_and_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 4, dreg, imm); }
+INLINE void emit_and_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 4, MEMPARAMS, imm); }
+INLINE void emit_and_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_AND_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_and_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_AND_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_and_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_AND_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_sub_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 5, dreg, imm); }
+INLINE void emit_sub_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 5, MEMPARAMS, imm); }
+INLINE void emit_sub_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUB_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_sub_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SUB_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_sub_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SUB_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_xor_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 6, dreg, imm); }
+INLINE void emit_xor_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 6, MEMPARAMS, imm); }
+INLINE void emit_xor_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XOR_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_xor_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_XOR_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_xor_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_XOR_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_cmp_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 7, dreg, imm); }
+INLINE void emit_cmp_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 7, MEMPARAMS, imm); }
+INLINE void emit_cmp_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMP_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_cmp_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CMP_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_cmp_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_CMP_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_test_r32_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm32(emitptr, OP_G3_Ev, OP_32BIT, 0, dreg, imm); }
+INLINE void emit_test_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm32(emitptr, OP_G3_Ev, OP_32BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_test_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_TEST_Ev_Gv, OP_32BIT, sreg, dreg); }
+INLINE void emit_test_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_TEST_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_arith_r64_*
+-------------------------------------------------*/
+
+#ifdef PTR64
+
+INLINE void emit_add_r64_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 0, dreg, imm); }
+INLINE void emit_add_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_add_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADD_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_add_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADD_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_add_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADD_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_or_r64_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 1, dreg, imm); }
+INLINE void emit_or_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 1, MEMPARAMS, imm); }
+INLINE void emit_or_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_OR_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_or_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_OR_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_or_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_OR_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_adc_r64_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 2, dreg, imm); }
+INLINE void emit_adc_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 2, MEMPARAMS, imm); }
+INLINE void emit_adc_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADC_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_adc_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADC_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_adc_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADC_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_sbb_r64_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 3, dreg, imm); }
+INLINE void emit_sbb_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 3, MEMPARAMS, imm); }
+INLINE void emit_sbb_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SBB_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_sbb_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SBB_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_sbb_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SBB_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_and_r64_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 4, dreg, imm); }
+INLINE void emit_and_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 4, MEMPARAMS, imm); }
+INLINE void emit_and_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_AND_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_and_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_AND_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_and_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_AND_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_sub_r64_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 5, dreg, imm); }
+INLINE void emit_sub_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 5, MEMPARAMS, imm); }
+INLINE void emit_sub_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUB_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_sub_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SUB_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_sub_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SUB_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_xor_r64_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 6, dreg, imm); }
+INLINE void emit_xor_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 6, MEMPARAMS, imm); }
+INLINE void emit_xor_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XOR_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_xor_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_XOR_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_xor_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_XOR_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_cmp_r64_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 7, dreg, imm); }
+INLINE void emit_cmp_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 7, MEMPARAMS, imm); }
+INLINE void emit_cmp_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMP_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_cmp_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CMP_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_cmp_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_CMP_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_test_r64_imm(x86code **emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm32(emitptr, OP_G3_Ev, OP_64BIT, 0, dreg, imm); }
+INLINE void emit_test_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT32 imm) { emit_op_modrm_mem_imm32(emitptr, OP_G3_Ev, OP_64BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_test_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_TEST_Ev_Gv, OP_64BIT, sreg, dreg); }
+INLINE void emit_test_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_TEST_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+
+#endif
+
+
+
+/***************************************************************************
+ SHIFT EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_shift_reg_imm
+-------------------------------------------------*/
+
+INLINE void emit_shift_reg_imm(x86code **emitptr, UINT32 op1, UINT32 opn, UINT8 opsize, UINT8 opindex, UINT8 dreg, UINT8 imm)
+{
+ if (imm == 1)
+ emit_op_modrm_reg(emitptr, op1, opsize, opindex, dreg);
+ else
+ emit_op_modrm_reg_imm8(emitptr, opn, opsize, opindex, dreg, imm);
+}
+
+INLINE void emit_shift_mem_imm(x86code **emitptr, UINT32 op1, UINT32 opn, UINT8 opsize, UINT8 opindex, DECLARE_MEMPARAMS, UINT8 imm)
+{
+ if (imm == 1)
+ emit_op_modrm_mem(emitptr, op1, opsize, opindex, MEMPARAMS);
+ else
+ emit_op_modrm_mem_imm8(emitptr, opn, opsize, opindex, MEMPARAMS, imm);
+}
+
+
+/*-------------------------------------------------
+ emit_shift_r8_*
+-------------------------------------------------*/
+
+INLINE void emit_rol_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 0, dreg, imm); }
+INLINE void emit_rol_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_rol_r8_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 0, dreg); }
+INLINE void emit_rol_m8_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 0, MEMPARAMS); }
+
+INLINE void emit_ror_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 1, dreg, imm); }
+INLINE void emit_ror_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 1, MEMPARAMS, imm); }
+INLINE void emit_ror_r8_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 1, dreg); }
+INLINE void emit_ror_m8_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 1, MEMPARAMS); }
+
+INLINE void emit_rcl_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 2, dreg, imm); }
+INLINE void emit_rcl_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 2, MEMPARAMS, imm); }
+INLINE void emit_rcl_r8_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 2, dreg); }
+INLINE void emit_rcl_m8_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 2, MEMPARAMS); }
+
+INLINE void emit_rcr_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 3, dreg, imm); }
+INLINE void emit_rcr_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 3, MEMPARAMS, imm); }
+INLINE void emit_rcr_r8_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 3, dreg); }
+INLINE void emit_rcr_m8_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 3, MEMPARAMS); }
+
+INLINE void emit_shl_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 4, dreg, imm); }
+INLINE void emit_shl_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 4, MEMPARAMS, imm); }
+INLINE void emit_shl_r8_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 4, dreg); }
+INLINE void emit_shl_m8_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 4, MEMPARAMS); }
+
+INLINE void emit_shr_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 5, dreg, imm); }
+INLINE void emit_shr_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 5, MEMPARAMS, imm); }
+INLINE void emit_shr_r8_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 5, dreg); }
+INLINE void emit_shr_m8_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 5, MEMPARAMS); }
+
+INLINE void emit_sar_r8_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 7, dreg, imm); }
+INLINE void emit_sar_m8_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 7, MEMPARAMS, imm); }
+INLINE void emit_sar_r8_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 7, dreg); }
+INLINE void emit_sar_m8_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 7, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_shift_r16_*
+-------------------------------------------------*/
+
+INLINE void emit_rol_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 0, dreg, imm); }
+INLINE void emit_rol_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_rol_r16_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 0, dreg); }
+INLINE void emit_rol_m16_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 0, MEMPARAMS); }
+
+INLINE void emit_ror_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 1, dreg, imm); }
+INLINE void emit_ror_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 1, MEMPARAMS, imm); }
+INLINE void emit_ror_r16_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 1, dreg); }
+INLINE void emit_ror_m16_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 1, MEMPARAMS); }
+
+INLINE void emit_rcl_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 2, dreg, imm); }
+INLINE void emit_rcl_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 2, MEMPARAMS, imm); }
+INLINE void emit_rcl_r16_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 2, dreg); }
+INLINE void emit_rcl_m16_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 2, MEMPARAMS); }
+
+INLINE void emit_rcr_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 3, dreg, imm); }
+INLINE void emit_rcr_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 3, MEMPARAMS, imm); }
+INLINE void emit_rcr_r16_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 3, dreg); }
+INLINE void emit_rcr_m16_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 3, MEMPARAMS); }
+
+INLINE void emit_shl_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 4, dreg, imm); }
+INLINE void emit_shl_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 4, MEMPARAMS, imm); }
+INLINE void emit_shl_r16_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 4, dreg); }
+INLINE void emit_shl_m16_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 4, MEMPARAMS); }
+
+INLINE void emit_shr_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 5, dreg, imm); }
+INLINE void emit_shr_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 5, MEMPARAMS, imm); }
+INLINE void emit_shr_r16_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 5, dreg); }
+INLINE void emit_shr_m16_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 5, MEMPARAMS); }
+
+INLINE void emit_sar_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 7, dreg, imm); }
+INLINE void emit_sar_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 7, MEMPARAMS, imm); }
+INLINE void emit_sar_r16_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 7, dreg); }
+INLINE void emit_sar_m16_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 7, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_shift_r32_*
+-------------------------------------------------*/
+
+INLINE void emit_rol_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 0, dreg, imm); }
+INLINE void emit_rol_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_rol_r32_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 0, dreg); }
+INLINE void emit_rol_m32_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 0, MEMPARAMS); }
+
+INLINE void emit_ror_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 1, dreg, imm); }
+INLINE void emit_ror_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 1, MEMPARAMS, imm); }
+INLINE void emit_ror_r32_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 1, dreg); }
+INLINE void emit_ror_m32_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 1, MEMPARAMS); }
+
+INLINE void emit_rcl_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 2, dreg, imm); }
+INLINE void emit_rcl_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 2, MEMPARAMS, imm); }
+INLINE void emit_rcl_r32_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 2, dreg); }
+INLINE void emit_rcl_m32_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 2, MEMPARAMS); }
+
+INLINE void emit_rcr_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 3, dreg, imm); }
+INLINE void emit_rcr_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 3, MEMPARAMS, imm); }
+INLINE void emit_rcr_r32_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 3, dreg); }
+INLINE void emit_rcr_m32_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 3, MEMPARAMS); }
+
+INLINE void emit_shl_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 4, dreg, imm); }
+INLINE void emit_shl_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 4, MEMPARAMS, imm); }
+INLINE void emit_shl_r32_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 4, dreg); }
+INLINE void emit_shl_m32_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 4, MEMPARAMS); }
+
+INLINE void emit_shr_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 5, dreg, imm); }
+INLINE void emit_shr_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 5, MEMPARAMS, imm); }
+INLINE void emit_shr_r32_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 5, dreg); }
+INLINE void emit_shr_m32_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 5, MEMPARAMS); }
+
+INLINE void emit_sar_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 7, dreg, imm); }
+INLINE void emit_sar_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 7, MEMPARAMS, imm); }
+INLINE void emit_sar_r32_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 7, dreg); }
+INLINE void emit_sar_m32_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 7, MEMPARAMS); }
+
+INLINE void emit_shld_r32_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_SHLD_Ev_Gv_Ib, OP_32BIT, sreg, dreg, imm); }
+INLINE void emit_shld_m32_r32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_SHLD_Ev_Gv_Ib, OP_32BIT, sreg, MEMPARAMS, imm); }
+INLINE void emit_shld_r32_r32_cl(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SHLD_Ev_Gv_CL, OP_32BIT, sreg, dreg); }
+INLINE void emit_shld_m32_r32_cl(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SHLD_Ev_Gv_CL, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_shrd_r32_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_SHRD_Ev_Gv_Ib, OP_32BIT, sreg, dreg, imm); }
+INLINE void emit_shrd_m32_r32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_SHRD_Ev_Gv_Ib, OP_32BIT, sreg, MEMPARAMS, imm); }
+INLINE void emit_shrd_r32_r32_cl(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SHRD_Ev_Gv_CL, OP_32BIT, sreg, dreg); }
+INLINE void emit_shrd_m32_r32_cl(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SHRD_Ev_Gv_CL, OP_32BIT, sreg, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_shift_r64_*
+-------------------------------------------------*/
+
+#ifdef PTR64
+
+INLINE void emit_rol_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 0, dreg, imm); }
+INLINE void emit_rol_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 0, MEMPARAMS, imm); }
+INLINE void emit_rol_r64_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 0, dreg); }
+INLINE void emit_rol_m64_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 0, MEMPARAMS); }
+
+INLINE void emit_ror_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 1, dreg, imm); }
+INLINE void emit_ror_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 1, MEMPARAMS, imm); }
+INLINE void emit_ror_r64_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 1, dreg); }
+INLINE void emit_ror_m64_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 1, MEMPARAMS); }
+
+INLINE void emit_rcl_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 2, dreg, imm); }
+INLINE void emit_rcl_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 2, MEMPARAMS, imm); }
+INLINE void emit_rcl_r64_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 2, dreg); }
+INLINE void emit_rcl_m64_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 2, MEMPARAMS); }
+
+INLINE void emit_rcr_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 3, dreg, imm); }
+INLINE void emit_rcr_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 3, MEMPARAMS, imm); }
+INLINE void emit_rcr_r64_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 3, dreg); }
+INLINE void emit_rcr_m64_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 3, MEMPARAMS); }
+
+INLINE void emit_shl_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 4, dreg, imm); }
+INLINE void emit_shl_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 4, MEMPARAMS, imm); }
+INLINE void emit_shl_r64_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 4, dreg); }
+INLINE void emit_shl_m64_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 4, MEMPARAMS); }
+
+INLINE void emit_shr_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 5, dreg, imm); }
+INLINE void emit_shr_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 5, MEMPARAMS, imm); }
+INLINE void emit_shr_r64_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 5, dreg); }
+INLINE void emit_shr_m64_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 5, MEMPARAMS); }
+
+INLINE void emit_sar_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 7, dreg, imm); }
+INLINE void emit_sar_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 7, MEMPARAMS, imm); }
+INLINE void emit_sar_r64_cl(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 7, dreg); }
+INLINE void emit_sar_m64_cl(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 7, MEMPARAMS); }
+
+INLINE void emit_shld_r64_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_SHLD_Ev_Gv_Ib, OP_64BIT, sreg, dreg, imm); }
+INLINE void emit_shld_m64_r64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_SHLD_Ev_Gv_Ib, OP_64BIT, sreg, MEMPARAMS, imm); }
+INLINE void emit_shld_r64_r64_cl(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SHLD_Ev_Gv_CL, OP_64BIT, sreg, dreg); }
+INLINE void emit_shld_m64_r64_cl(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SHLD_Ev_Gv_CL, OP_64BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_shrd_r64_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_SHRD_Ev_Gv_Ib, OP_64BIT, sreg, dreg, imm); }
+INLINE void emit_shrd_m64_r64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_SHRD_Ev_Gv_Ib, OP_64BIT, sreg, MEMPARAMS, imm); }
+INLINE void emit_shrd_r64_r64_cl(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SHRD_Ev_Gv_CL, OP_64BIT, sreg, dreg); }
+INLINE void emit_shrd_m64_r64_cl(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SHRD_Ev_Gv_CL, OP_64BIT, sreg, MEMPARAMS); }
+
+#endif
+
+
+
+/***************************************************************************
+ GROUP3 EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_group3_r8_*
+-------------------------------------------------*/
+
+INLINE void emit_not_r8(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 2, dreg); }
+INLINE void emit_not_m8(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 2, MEMPARAMS); }
+
+INLINE void emit_neg_r8(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 3, dreg); }
+INLINE void emit_neg_m8(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 3, MEMPARAMS); }
+
+INLINE void emit_mul_r8(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 4, dreg); }
+INLINE void emit_mul_m8(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 4, MEMPARAMS); }
+
+INLINE void emit_imul_r8(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 5, dreg); }
+INLINE void emit_imul_m8(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 5, MEMPARAMS); }
+
+INLINE void emit_div_r8(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 6, dreg); }
+INLINE void emit_div_m8(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 6, MEMPARAMS); }
+
+INLINE void emit_idiv_r8(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 7, dreg); }
+INLINE void emit_idiv_m8(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 7, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_group3_r16_*
+-------------------------------------------------*/
+
+INLINE void emit_not_r16(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 2, dreg); }
+INLINE void emit_not_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 2, MEMPARAMS); }
+
+INLINE void emit_neg_r16(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 3, dreg); }
+INLINE void emit_neg_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 3, MEMPARAMS); }
+
+INLINE void emit_mul_r16(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 4, dreg); }
+INLINE void emit_mul_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 4, MEMPARAMS); }
+
+INLINE void emit_imul_r16(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 5, dreg); }
+INLINE void emit_imul_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 5, MEMPARAMS); }
+
+INLINE void emit_div_r16(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 6, dreg); }
+INLINE void emit_div_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 6, MEMPARAMS); }
+
+INLINE void emit_idiv_r16(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 7, dreg); }
+INLINE void emit_idiv_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 7, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_group3_r32_*
+-------------------------------------------------*/
+
+INLINE void emit_not_r32(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 2, dreg); }
+INLINE void emit_not_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 2, MEMPARAMS); }
+
+INLINE void emit_neg_r32(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 3, dreg); }
+INLINE void emit_neg_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 3, MEMPARAMS); }
+
+INLINE void emit_mul_r32(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 4, dreg); }
+INLINE void emit_mul_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 4, MEMPARAMS); }
+
+INLINE void emit_imul_r32(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 5, dreg); }
+INLINE void emit_imul_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 5, MEMPARAMS); }
+
+INLINE void emit_div_r32(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 6, dreg); }
+INLINE void emit_div_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 6, MEMPARAMS); }
+
+INLINE void emit_idiv_r32(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 7, dreg); }
+INLINE void emit_idiv_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 7, MEMPARAMS); }
+
+
+/*-------------------------------------------------
+ emit_group3_r64_*
+-------------------------------------------------*/
+
+#ifdef PTR64
+
+INLINE void emit_not_r64(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 2, dreg); }
+INLINE void emit_not_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 2, MEMPARAMS); }
+
+INLINE void emit_neg_r64(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 3, dreg); }
+INLINE void emit_neg_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 3, MEMPARAMS); }
+
+INLINE void emit_mul_r64(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 4, dreg); }
+INLINE void emit_mul_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 4, MEMPARAMS); }
+
+INLINE void emit_imul_r64(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 5, dreg); }
+INLINE void emit_imul_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 5, MEMPARAMS); }
+
+INLINE void emit_div_r64(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 6, dreg); }
+INLINE void emit_div_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 6, MEMPARAMS); }
+
+INLINE void emit_idiv_r64(x86code **emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 7, dreg); }
+INLINE void emit_idiv_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 7, MEMPARAMS); }
+
+#endif
+
+
+
+/***************************************************************************
+ IMUL EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_imul_r16_*
+-------------------------------------------------*/
+
+INLINE void emit_imul_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_IMUL_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_imul_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_IMUL_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_imul_r16_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 sreg, INT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_16BIT, dreg, sreg, imm); }
+INLINE void emit_imul_r16_m16_imm(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS, INT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_16BIT, dreg, MEMPARAMS, imm); }
+
+INLINE void emit_imul_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_IMUL_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_imul_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_IMUL_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_imul_r32_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 sreg, INT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_32BIT, dreg, sreg, imm); }
+INLINE void emit_imul_r32_m32_imm(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS, INT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_32BIT, dreg, MEMPARAMS, imm); }
+
+#ifdef PTR64
+
+INLINE void emit_imul_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_IMUL_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_imul_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_IMUL_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_imul_r64_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 sreg, INT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_64BIT, dreg, sreg, imm); }
+INLINE void emit_imul_r64_m64_imm(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS, INT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_64BIT, dreg, MEMPARAMS, imm); }
+
+#endif
+
+
+
+/***************************************************************************
+ BIT OPERATION EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_bswap_*
+-------------------------------------------------*/
+
+INLINE void emit_bswap_r32(x86code **emitptr, UINT8 dreg) { emit_op_reg(emitptr, OP_BSWAP_EAX + (dreg & 7), OP_32BIT, dreg); }
+INLINE void emit_bswap_r64(x86code **emitptr, UINT8 dreg) { emit_op_reg(emitptr, OP_BSWAP_EAX + (dreg & 7), OP_64BIT, dreg); }
+
+
+/*-------------------------------------------------
+ emit_bsr/bsf_r16_*
+-------------------------------------------------*/
+
+INLINE void emit_bsf_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSF_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_bsf_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_BSF_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+INLINE void emit_bsr_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSR_Gv_Ev, OP_16BIT, dreg, sreg); }
+INLINE void emit_bsr_r16_m16(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_BSR_Gv_Ev, OP_16BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_bsf_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSF_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_bsf_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_BSF_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_bsr_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSR_Gv_Ev, OP_32BIT, dreg, sreg); }
+INLINE void emit_bsr_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_BSR_Gv_Ev, OP_32BIT, dreg, MEMPARAMS); }
+
+#ifdef PTR64
+INLINE void emit_bsf_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSF_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_bsf_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_BSF_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+INLINE void emit_bsr_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSR_Gv_Ev, OP_64BIT, dreg, sreg); }
+INLINE void emit_bsr_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_BSR_Gv_Ev, OP_64BIT, dreg, MEMPARAMS); }
+#endif
+
+
+/*-------------------------------------------------
+ emit_bit_r16_*
+-------------------------------------------------*/
+
+INLINE void emit_bt_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BT_Ev_Gv, OP_16BIT, sreg, dreg); }
+INLINE void emit_bt_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BT_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+INLINE void emit_bt_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 4, dreg, imm); }
+INLINE void emit_bt_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 4, MEMPARAMS, imm); }
+
+INLINE void emit_bts_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTS_Ev_Gv, OP_16BIT, sreg, dreg); }
+INLINE void emit_bts_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTS_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+INLINE void emit_bts_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 5, dreg, imm); }
+INLINE void emit_bts_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 5, MEMPARAMS, imm); }
+
+INLINE void emit_btr_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTR_Ev_Gv, OP_16BIT, sreg, dreg); }
+INLINE void emit_btr_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTR_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+INLINE void emit_btr_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 6, dreg, imm); }
+INLINE void emit_btr_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 6, MEMPARAMS, imm); }
+
+INLINE void emit_btc_r16_r16(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTC_Ev_Gv, OP_16BIT, sreg, dreg); }
+INLINE void emit_btc_m16_r16(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTC_Ev_Gv, OP_16BIT, sreg, MEMPARAMS); }
+INLINE void emit_btc_r16_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 7, dreg, imm); }
+INLINE void emit_btc_m16_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 7, MEMPARAMS, imm); }
+
+
+/*-------------------------------------------------
+ emit_bit_r32_*
+-------------------------------------------------*/
+
+INLINE void emit_bt_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BT_Ev_Gv, OP_32BIT, sreg, dreg); }
+INLINE void emit_bt_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BT_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+INLINE void emit_bt_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 4, dreg, imm); }
+INLINE void emit_bt_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 4, MEMPARAMS, imm); }
+
+INLINE void emit_bts_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTS_Ev_Gv, OP_32BIT, sreg, dreg); }
+INLINE void emit_bts_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTS_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+INLINE void emit_bts_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 5, dreg, imm); }
+INLINE void emit_bts_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 5, MEMPARAMS, imm); }
+
+INLINE void emit_btr_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTR_Ev_Gv, OP_32BIT, sreg, dreg); }
+INLINE void emit_btr_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTR_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+INLINE void emit_btr_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 6, dreg, imm); }
+INLINE void emit_btr_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 6, MEMPARAMS, imm); }
+
+INLINE void emit_btc_r32_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTC_Ev_Gv, OP_32BIT, sreg, dreg); }
+INLINE void emit_btc_m32_r32(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTC_Ev_Gv, OP_32BIT, sreg, MEMPARAMS); }
+INLINE void emit_btc_r32_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 7, dreg, imm); }
+INLINE void emit_btc_m32_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 7, MEMPARAMS, imm); }
+
+
+/*-------------------------------------------------
+ emit_bit_r64_*
+-------------------------------------------------*/
+
+#ifdef PTR64
+
+INLINE void emit_bt_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BT_Ev_Gv, OP_64BIT, sreg, dreg); }
+INLINE void emit_bt_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BT_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+INLINE void emit_bt_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 4, dreg, imm); }
+INLINE void emit_bt_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 4, MEMPARAMS, imm); }
+
+INLINE void emit_bts_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTS_Ev_Gv, OP_64BIT, sreg, dreg); }
+INLINE void emit_bts_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTS_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+INLINE void emit_bts_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 5, dreg, imm); }
+INLINE void emit_bts_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 5, MEMPARAMS, imm); }
+
+INLINE void emit_btr_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTR_Ev_Gv, OP_64BIT, sreg, dreg); }
+INLINE void emit_btr_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTR_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+INLINE void emit_btr_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 6, dreg, imm); }
+INLINE void emit_btr_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 6, MEMPARAMS, imm); }
+
+INLINE void emit_btc_r64_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTC_Ev_Gv, OP_64BIT, sreg, dreg); }
+INLINE void emit_btc_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTC_Ev_Gv, OP_64BIT, sreg, MEMPARAMS); }
+INLINE void emit_btc_r64_imm(x86code **emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 7, dreg, imm); }
+INLINE void emit_btc_m64_imm(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 7, MEMPARAMS, imm); }
+
+#endif
+
+
+
+/***************************************************************************
+ LEA EMITTERS
+***************************************************************************/
+
+INLINE void emit_lea_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_LEA_Gv_M, OP_32BIT, dreg, MEMPARAMS); }
+
+#ifdef PTR64
+INLINE void emit_lea_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_LEA_Gv_M, OP_64BIT, dreg, MEMPARAMS); }
+#endif
+
+
+
+/***************************************************************************
+ SET EMITTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_setcc_*
+-------------------------------------------------*/
+
+INLINE void emit_setcc_r8(x86code **emitptr, UINT8 cond, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_SETCC_O_Eb + cond, OP_32BIT, 0, dreg); }
+INLINE void emit_setcc_m8(x86code **emitptr, UINT8 cond, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SETCC_O_Eb + cond, OP_32BIT, 0, MEMPARAMS); }
+
+
+
+/***************************************************************************
+ SIMPLE FPU EMITTERS
+***************************************************************************/
+
+#ifndef PTR64
+
+INLINE void emit_fnop(x86code **emitptr) { emit_op_simple(emitptr, OP_FNOP, OP_32BIT); }
+INLINE void emit_fchs(x86code **emitptr) { emit_op_simple(emitptr, OP_FCHS, OP_32BIT); }
+INLINE void emit_fabs(x86code **emitptr) { emit_op_simple(emitptr, OP_FABS, OP_32BIT); }
+INLINE void emit_ftst(x86code **emitptr) { emit_op_simple(emitptr, OP_FTST, OP_32BIT); }
+INLINE void emit_fxam(x86code **emitptr) { emit_op_simple(emitptr, OP_FXAM, OP_32BIT); }
+INLINE void emit_fld1(x86code **emitptr) { emit_op_simple(emitptr, OP_FLD1, OP_32BIT); }
+INLINE void emit_fldl2t(x86code **emitptr) { emit_op_simple(emitptr, OP_FLDL2T, OP_32BIT); }
+INLINE void emit_fldl2e(x86code **emitptr) { emit_op_simple(emitptr, OP_FLDL2E, OP_32BIT); }
+INLINE void emit_fldpi(x86code **emitptr) { emit_op_simple(emitptr, OP_FLDPI, OP_32BIT); }
+INLINE void emit_fldlg2(x86code **emitptr) { emit_op_simple(emitptr, OP_FLDLG2, OP_32BIT); }
+INLINE void emit_fldln2(x86code **emitptr) { emit_op_simple(emitptr, OP_FLDLN2, OP_32BIT); }
+INLINE void emit_fldz(x86code **emitptr) { emit_op_simple(emitptr, OP_FLDZ, OP_32BIT); }
+INLINE void emit_f2xm1(x86code **emitptr) { emit_op_simple(emitptr, OP_F2XM1, OP_32BIT); }
+INLINE void emit_fyl2x(x86code **emitptr) { emit_op_simple(emitptr, OP_FYL2X, OP_32BIT); }
+INLINE void emit_fptan(x86code **emitptr) { emit_op_simple(emitptr, OP_FPTAN, OP_32BIT); }
+INLINE void emit_fpatan(x86code **emitptr) { emit_op_simple(emitptr, OP_FPATAN, OP_32BIT); }
+INLINE void emit_fxtract(x86code **emitptr) { emit_op_simple(emitptr, OP_FXTRACT, OP_32BIT); }
+INLINE void emit_fprem1(x86code **emitptr) { emit_op_simple(emitptr, OP_FPREM1, OP_32BIT); }
+INLINE void emit_fdecstp(x86code **emitptr) { emit_op_simple(emitptr, OP_FDECSTP, OP_32BIT); }
+INLINE void emit_fincstp(x86code **emitptr) { emit_op_simple(emitptr, OP_FINCSTP, OP_32BIT); }
+INLINE void emit_fprem(x86code **emitptr) { emit_op_simple(emitptr, OP_FPREM, OP_32BIT); }
+INLINE void emit_fyl2xp1(x86code **emitptr) { emit_op_simple(emitptr, OP_FYL2XP1, OP_32BIT); }
+INLINE void emit_fsqrt(x86code **emitptr) { emit_op_simple(emitptr, OP_FSQRT, OP_32BIT); }
+INLINE void emit_fsincos(x86code **emitptr) { emit_op_simple(emitptr, OP_FSINCOS, OP_32BIT); }
+INLINE void emit_frndint(x86code **emitptr) { emit_op_simple(emitptr, OP_FRNDINT, OP_32BIT); }
+INLINE void emit_fscale(x86code **emitptr) { emit_op_simple(emitptr, OP_FSCALE, OP_32BIT); }
+INLINE void emit_fsin(x86code **emitptr) { emit_op_simple(emitptr, OP_FSIN, OP_32BIT); }
+INLINE void emit_fcos(x86code **emitptr) { emit_op_simple(emitptr, OP_FCOS, OP_32BIT); }
+INLINE void emit_fucompp(x86code **emitptr) { emit_op_simple(emitptr, OP_FUCOMPP, OP_32BIT); }
+INLINE void emit_fclex(x86code **emitptr) { emit_op_simple(emitptr, OP_FCLEX, OP_32BIT); }
+INLINE void emit_finit(x86code **emitptr) { emit_op_simple(emitptr, OP_FINIT, OP_32BIT); }
+INLINE void emit_fcompp(x86code **emitptr) { emit_op_simple(emitptr, OP_FCOMPP, OP_32BIT); }
+INLINE void emit_fstsw_ax(x86code **emitptr) { emit_op_simple(emitptr, OP_FSTSW_AX, OP_32BIT); }
+
+#endif
+
+
+
+/***************************************************************************
+ REGISTER-BASED FPU EMITTERS
+***************************************************************************/
+
+#ifndef PTR64
+
+INLINE void emit_ffree_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FFREE_STn + reg, OP_32BIT); }
+INLINE void emit_fst_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FST_STn + reg, OP_32BIT); }
+INLINE void emit_fstp_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSTP_STn + reg, OP_32BIT); }
+INLINE void emit_fucomp_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FUCOMP_STn + reg, OP_32BIT); }
+
+INLINE void emit_fadd_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FADD_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fmul_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FMUL_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcom_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCOM_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcomp_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCOMP_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fsub_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUB_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fsubr_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUBR_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fdiv_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIV_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fdivr_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIVR_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fld_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FLD_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fxch_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FXCH_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcmovb_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVB_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcmove_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVE_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcmovbe_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVBE_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcmovu_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVU_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcmovnb_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVNB_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcmovne_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVNE_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcmovnbe_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVNBE_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcmovnu_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVNU_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fucomi_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FUCOMI_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcomi_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCOMI_ST0_STn + reg, OP_32BIT); }
+INLINE void emit_fcomip_st0_stn(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCOMIP_ST0_STn + reg, OP_32BIT); }
+
+INLINE void emit_fadd_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FADD_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fmul_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FMUL_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fsubr_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUBR_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fsub_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUB_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fdivr_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIVR_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fdiv_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIV_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fucom_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FUCOM_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_faddp_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FADDP_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fmulp_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FMULP_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fsubrp_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUBRP_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fsubp_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUBP_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fdivrp_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIVRP_STn_ST0 + reg, OP_32BIT); }
+INLINE void emit_fdivp_stn_st0(x86code **emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIVP_STn_ST0 + reg, OP_32BIT); }
+
+INLINE void emit_faddp(x86code **emitptr) { emit_faddp_stn_st0(emitptr, 1); }
+INLINE void emit_fmulp(x86code **emitptr) { emit_fmulp_stn_st0(emitptr, 1); }
+INLINE void emit_fsubrp(x86code **emitptr) { emit_fsubrp_stn_st0(emitptr, 1); }
+INLINE void emit_fsubp(x86code **emitptr) { emit_fsubp_stn_st0(emitptr, 1); }
+INLINE void emit_fdivrp(x86code **emitptr) { emit_fdivrp_stn_st0(emitptr, 1); }
+INLINE void emit_fdivp(x86code **emitptr) { emit_fdivp_stn_st0(emitptr, 1); }
+
+#endif
+
+
+
+/***************************************************************************
+ MEMORY FPU EMITTERS
+***************************************************************************/
+
+#ifndef PTR64
+
+INLINE void emit_fadd_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 0, MEMPARAMS); }
+INLINE void emit_fmul_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 1, MEMPARAMS); }
+INLINE void emit_fcom_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_fcomp_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 3, MEMPARAMS); }
+INLINE void emit_fsub_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 4, MEMPARAMS); }
+INLINE void emit_fsubr_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 5, MEMPARAMS); }
+INLINE void emit_fdiv_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 6, MEMPARAMS); }
+INLINE void emit_fdivr_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 7, MEMPARAMS); }
+
+INLINE void emit_fld_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 0, MEMPARAMS); }
+INLINE void emit_fst_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_fstp_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 3, MEMPARAMS); }
+INLINE void emit_fldenv_m(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 4, MEMPARAMS); }
+INLINE void emit_fldcw_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 5, MEMPARAMS); }
+INLINE void emit_fstenv_m(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 6, MEMPARAMS); }
+INLINE void emit_fstcw_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 7, MEMPARAMS); }
+
+INLINE void emit_fiadd_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 0, MEMPARAMS); }
+INLINE void emit_fimul_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 1, MEMPARAMS); }
+INLINE void emit_ficom_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_ficomp_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 3, MEMPARAMS); }
+INLINE void emit_fisub_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 4, MEMPARAMS); }
+INLINE void emit_fisubr_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 5, MEMPARAMS); }
+INLINE void emit_fidiv_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 6, MEMPARAMS); }
+INLINE void emit_fidivr_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 7, MEMPARAMS); }
+
+INLINE void emit_fild_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 0, MEMPARAMS); }
+INLINE void emit_fisttp_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 1, MEMPARAMS); }
+INLINE void emit_fist_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_fistp_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 3, MEMPARAMS); }
+INLINE void emit_fld_m80(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 5, MEMPARAMS); }
+INLINE void emit_fstp_m80(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 7, MEMPARAMS); }
+
+INLINE void emit_fadd_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 0, MEMPARAMS); }
+INLINE void emit_fmul_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 1, MEMPARAMS); }
+INLINE void emit_fcom_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_fcomp_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 3, MEMPARAMS); }
+INLINE void emit_fsub_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 4, MEMPARAMS); }
+INLINE void emit_fsubr_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 5, MEMPARAMS); }
+INLINE void emit_fdiv_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 6, MEMPARAMS); }
+INLINE void emit_fdivr_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 7, MEMPARAMS); }
+
+INLINE void emit_fld_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 0, MEMPARAMS); }
+INLINE void emit_fisttp_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 1, MEMPARAMS); }
+INLINE void emit_fst_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_fstp_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 3, MEMPARAMS); }
+INLINE void emit_frstor_m(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 4, MEMPARAMS); }
+INLINE void emit_fsave_m(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 6, MEMPARAMS); }
+INLINE void emit_fstsw_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 7, MEMPARAMS); }
+
+INLINE void emit_fiadd_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 0, MEMPARAMS); }
+INLINE void emit_fimul_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 1, MEMPARAMS); }
+INLINE void emit_ficom_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_ficomp_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 3, MEMPARAMS); }
+INLINE void emit_fisub_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 4, MEMPARAMS); }
+INLINE void emit_fisubr_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 5, MEMPARAMS); }
+INLINE void emit_fidiv_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 6, MEMPARAMS); }
+INLINE void emit_fidivr_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 7, MEMPARAMS); }
+
+INLINE void emit_fild_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 0, MEMPARAMS); }
+INLINE void emit_fisttp_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 1, MEMPARAMS); }
+INLINE void emit_fist_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_fistp_m16(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 3, MEMPARAMS); }
+INLINE void emit_fbld_m80(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 4, MEMPARAMS); }
+INLINE void emit_fild_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 5, MEMPARAMS); }
+INLINE void emit_fbstp_m80(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 6, MEMPARAMS); }
+INLINE void emit_fistp_m64(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 7, MEMPARAMS); }
+
+#endif
+
+
+
+/***************************************************************************
+ GROUP16 EMITTERS
+***************************************************************************/
+
+INLINE void emit_ldmxcsr_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G16, OP_32BIT, 2, MEMPARAMS); }
+INLINE void emit_stmxcsr_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_G16, OP_32BIT, 3, MEMPARAMS); }
+
+
+
+/***************************************************************************
+ SSE SCALAR SINGLE EMITTERS
+***************************************************************************/
+
+INLINE void emit_movss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_movss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVSS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_movss_m32_r128(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVSS_Wss_Vss, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_addss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADDSS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_addss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADDSS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_subss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUBSS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_subss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SUBSS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_mulss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MULSS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_mulss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MULSS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_divss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_DIVSS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_divss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_DIVSS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_rcpss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_RCPSS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_rcpss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_RCPSS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_sqrtss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SQRTSS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_sqrtss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SQRTSS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_rsqrtss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_RSQRTSS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_rsqrtss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_RSQRTSS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_comiss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_COMISS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_comiss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_COMISS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_ucomiss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_UCOMISS_Vss_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_ucomiss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_UCOMISS_Vss_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtsi2ss_r128_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSI2SS_Vss_Ed, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtsi2ss_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSI2SS_Vss_Ed, OP_32BIT, dreg, MEMPARAMS); }
+
+#ifdef PTR64
+INLINE void emit_cvtsi2ss_r128_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSI2SS_Vss_Ed, OP_64BIT, dreg, sreg); }
+INLINE void emit_cvtsi2ss_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSI2SS_Vss_Ed, OP_64BIT, dreg, MEMPARAMS); }
+#endif
+
+INLINE void emit_cvtsd2ss_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSD2SS_Vss_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtsd2ss_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSD2SS_Vss_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtss2si_r32_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSS2SI_Gd_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtss2si_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSS2SI_Gd_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+#ifdef PTR64
+INLINE void emit_cvtss2si_r64_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSS2SI_Gd_Wss, OP_64BIT, dreg, sreg); }
+INLINE void emit_cvtss2si_r64_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSS2SI_Gd_Wss, OP_64BIT, dreg, MEMPARAMS); }
+#endif
+
+INLINE void emit_cvttss2si_r32_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTSS2SI_Gd_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvttss2si_r32_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTTSS2SI_Gd_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+#ifdef PTR64
+INLINE void emit_cvttss2si_r64_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTSS2SI_Gd_Wss, OP_64BIT, dreg, sreg); }
+INLINE void emit_cvttss2si_r64_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTTSS2SI_Gd_Wss, OP_64BIT, dreg, MEMPARAMS); }
+#endif
+
+
+
+/***************************************************************************
+ SSE PACKED SINGLE EMITTERS
+***************************************************************************/
+
+INLINE void emit_movps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVAPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_movps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVAPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_movps_m128_r128(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVAPS_Wps_Vps, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_addps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADDPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_addps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADDPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_subps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUBPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_subps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SUBPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_mulps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MULPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_mulps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MULPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_divps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_DIVPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_divps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_DIVPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_rcpps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_RCPPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_rcpps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_RCPPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_sqrtps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SQRTPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_sqrtps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SQRTPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_rsqrtps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_RSQRTPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_rsqrtps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_RSQRTPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_andps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ANDPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_andps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ANDPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_andnps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ANDNPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_andnps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ANDNPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_orps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ORPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_orps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ORPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_xorps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XORPS_Vps_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_xorps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_XORPS_Vps_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtdq2ps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTDQ2PS_Vps_Wdq, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtdq2ps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTDQ2PS_Vps_Wdq, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtpd2ps_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTPD2PS_Vps_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtpd2ps_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTPD2PS_Vps_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtps2dq_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTPS2DQ_Vdq_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtps2dq_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTPS2DQ_Vdq_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvttps2dq_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTPS2DQ_Vdq_Wps, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvttps2dq_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTTPS2DQ_Vdq_Wps, OP_32BIT, dreg, MEMPARAMS); }
+
+
+
+/***************************************************************************
+ SSE SCALAR DOUBLE EMITTERS
+***************************************************************************/
+
+INLINE void emit_movsd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSD_Vsd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_movsd_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVSD_Vsd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_movsd_m64_r128(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVSD_Wsd_Vsd, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_addsd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADDSD_Vsd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_addsd_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADDSD_Vsd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_subsd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUBSD_Vsd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_subsd_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SUBSD_Vsd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_mulsd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MULSD_Vsd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_mulsd_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MULSD_Vsd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_divsd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_DIVSD_Vsd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_divsd_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_DIVSD_Vsd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_sqrtsd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SQRTSD_Vsd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_sqrtsd_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SQRTSD_Vsd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_comisd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_COMISD_Vsd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_comisd_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_COMISD_Vsd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_ucomisd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_UCOMISD_Vsd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_ucomisd_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_UCOMISD_Vsd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtsi2sd_r128_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSI2SD_Vsd_Ed, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtsi2sd_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSI2SD_Vsd_Ed, OP_32BIT, dreg, MEMPARAMS); }
+
+#ifdef PTR64
+INLINE void emit_cvtsi2sd_r128_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSI2SD_Vsd_Ed, OP_64BIT, dreg, sreg); }
+INLINE void emit_cvtsi2sd_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSI2SD_Vsd_Ed, OP_64BIT, dreg, MEMPARAMS); }
+#endif
+
+INLINE void emit_cvtss2sd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSS2SD_Vsd_Wss, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtss2sd_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSS2SD_Vsd_Wss, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtsd2si_r32_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSD2SI_Gd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtsd2si_r32_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSD2SI_Gd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+#ifdef PTR64
+INLINE void emit_cvtsd2si_r64_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSD2SI_Gd_Wsd, OP_64BIT, dreg, sreg); }
+INLINE void emit_cvtsd2si_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTSD2SI_Gd_Wsd, OP_64BIT, dreg, MEMPARAMS); }
+#endif
+
+INLINE void emit_cvttsd2si_r32_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTSD2SI_Gd_Wsd, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvttsd2si_r32_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTTSD2SI_Gd_Wsd, OP_32BIT, dreg, MEMPARAMS); }
+
+#ifdef PTR64
+INLINE void emit_cvttsd2si_r64_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTSD2SI_Gd_Wsd, OP_64BIT, dreg, sreg); }
+INLINE void emit_cvttsd2si_r64_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTTSD2SI_Gd_Wsd, OP_64BIT, dreg, MEMPARAMS); }
+#endif
+
+
+
+/***************************************************************************
+ SSE PACKED DOUBLE EMITTERS
+***************************************************************************/
+
+INLINE void emit_movpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVAPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_movpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVAPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+INLINE void emit_movpd_m128_r128(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVAPD_Wpd_Vpd, OP_32BIT, sreg, MEMPARAMS); }
+
+INLINE void emit_addpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADDPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_addpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ADDPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_subpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUBPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_subpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SUBPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_mulpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MULPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_mulpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MULPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_divpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_DIVPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_divpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_DIVPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_sqrtpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SQRTPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_sqrtpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_SQRTPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_andpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ANDPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_andpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ANDPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_andnpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ANDNPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_andnpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ANDNPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_orpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ORPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_orpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_ORPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_xorpd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XORPD_Vpd_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_xorpd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_XORPD_Vpd_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtdq2pd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTDQ2PD_Vpd_Wq, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtdq2pd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTDQ2PD_Vpd_Wq, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtps2pd_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTPS2PD_Vpd_Wq, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtps2pd_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTPS2PD_Vpd_Wq, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvtpd2dq_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTPD2DQ_Vdq_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvtpd2dq_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTPD2DQ_Vdq_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+INLINE void emit_cvttpd2dq_r128_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTPD2DQ_Vdq_Wpd, OP_32BIT, dreg, sreg); }
+INLINE void emit_cvttpd2dq_r128_m128(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_CVTTPD2DQ_Vdq_Wpd, OP_32BIT, dreg, MEMPARAMS); }
+
+#endif
diff --git a/src/emu/cpu/x86log.c b/src/emu/cpu/x86log.c
new file mode 100644
index 00000000000..a336817ca17
--- /dev/null
+++ b/src/emu/cpu/x86log.c
@@ -0,0 +1,316 @@
+/***************************************************************************
+
+ x86log.c
+
+ x86/x64 code logging helpers.
+
+ Copyright (c) 2007, Aaron Giles
+ Released for general use under the MAME license
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "x86log.h"
+
+#include <stddef.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* comment parameters */
+#define MAX_COMMENTS 1000
+#define MAX_DATA_RANGES 1000
+#define COMMENT_POOL_SIZE (MAX_COMMENTS * 40)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* code logging info */
+typedef struct _log_comment log_comment;
+struct _log_comment
+{
+ x86code * base;
+ const char * string;
+};
+
+
+/* data ranges */
+typedef struct _data_range data_range;
+struct _data_range
+{
+ x86code * base;
+ x86code * end;
+ int size;
+};
+
+
+/* the code logging context */
+struct _x86log_context
+{
+ astring * filename; /* name of the file */
+ FILE * file; /* file we are logging to */
+
+ data_range data_range[MAX_DATA_RANGES]; /* list of data ranges */
+ int data_range_count; /* number of data ranges */
+
+ log_comment comment_list[MAX_COMMENTS]; /* list of comments */
+ int comment_count; /* number of live comments */
+
+ char comment_pool[COMMENT_POOL_SIZE];/* string pool to hold comments */
+ char * comment_pool_next; /* pointer to next string pool location */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void reset_log(x86log_context *log);
+static int x86log_i386_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom, int mode);
+
+
+
+/***************************************************************************
+ EXTERNAL INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+ x86log_create_context - create a new context
+-------------------------------------------------*/
+
+x86log_context *x86log_create_context(const char *filename)
+{
+ x86log_context *log;
+
+ /* allocate the log */
+ log = malloc_or_die(sizeof(*log));
+ memset(log, 0, sizeof(*log));
+
+ /* allocate the filename */
+ log->filename = astring_dupc(filename);
+
+ /* reset things */
+ reset_log(log);
+ return log;
+}
+
+
+/*-------------------------------------------------
+ x86log_free_context - release a context
+-------------------------------------------------*/
+
+void x86log_free_context(x86log_context *log)
+{
+ /* close any open files */
+ if (log->file != NULL)
+ fclose(log->file);
+
+ /* free the structure */
+ astring_free(log->filename);
+ free(log);
+}
+
+
+/*-------------------------------------------------
+ x86log_add_comment - add a comment associated
+ with a given code pointer
+-------------------------------------------------*/
+
+void x86log_add_comment(x86log_context *log, x86code *base, const char *format, ...)
+{
+ char *string = log->comment_pool_next;
+ log_comment *comment;
+ va_list va;
+
+ assert(log->comment_count < MAX_COMMENTS);
+ assert(log->comment_pool_next + strlen(format) + 256 < log->comment_pool + COMMENT_POOL_SIZE);
+
+ /* we assume comments are registered in order; enforce this */
+ assert(log->comment_count == 0 || base >= log->comment_list[log->comment_count - 1].base);
+
+ /* if we exceed the maxima, skip it */
+ if (log->comment_count >= MAX_COMMENTS)
+ return;
+ if (log->comment_pool_next + strlen(format) + 256 >= log->comment_pool + COMMENT_POOL_SIZE)
+ return;
+
+ /* do the printf to the string pool */
+ va_start(va, format);
+ log->comment_pool_next += vsprintf(log->comment_pool_next, format, va) + 1;
+ va_end(va);
+
+ /* fill in the new comment */
+ comment = &log->comment_list[log->comment_count++];
+ comment->base = base;
+ comment->string = string;
+}
+
+
+/*-------------------------------------------------
+ x86log_mark_as_data - mark a given range as
+ data for logging purposes
+-------------------------------------------------*/
+
+void x86log_mark_as_data(x86log_context *log, x86code *base, x86code *end, int size)
+{
+ data_range *data;
+
+ assert(log->data_range_count < MAX_DATA_RANGES);
+ assert(end >= base);
+ assert(size == 1 || size == 2 || size == 4 || size == 8);
+
+ /* we assume data ranges are registered in order; enforce this */
+ assert(log->data_range_count == 0 || base > log->data_range[log->data_range_count - 1].end);
+
+ /* if we exceed the maxima, skip it */
+ if (log->data_range_count >= MAX_DATA_RANGES)
+ return;
+
+ /* fill in the new range */
+ data = &log->data_range[log->data_range_count++];
+ data->base = base;
+ data->end = end;
+ data->size = size;
+}
+
+
+/*-------------------------------------------------
+ x86log_disasm_code_range - disassemble a range
+ of code and reset accumulated information
+-------------------------------------------------*/
+
+void x86log_disasm_code_range(x86log_context *log, const char *label, x86code *start, x86code *stop)
+{
+ const log_comment *lastcomment = &log->comment_list[log->comment_count];
+ const log_comment *curcomment = &log->comment_list[0];
+ const data_range *lastdata = &log->data_range[log->data_range_count];
+ const data_range *curdata = &log->data_range[0];
+ x86code *cur = start;
+
+ /* print the optional label */
+ if (label != NULL)
+ x86log_printf(log, "\n%s\n", label);
+
+ /* loop from the start until the cache top */
+ while (cur < stop)
+ {
+ char buffer[100];
+ int bytes;
+
+ /* skip past any past data ranges */
+ while (curdata < lastdata && cur > curdata->end)
+ curdata++;
+
+ /* skip past any past comments */
+ while (curcomment < lastcomment && cur > curcomment->base)
+ curcomment++;
+
+ /* if we're in a data range, output the next chunk and continue */
+ if (cur >= curdata->base && cur <= curdata->end)
+ {
+ bytes = curdata->size;
+ switch (curdata->size)
+ {
+ default:
+ case 1: sprintf(buffer, "db %02X", *cur); break;
+ case 2: sprintf(buffer, "dw %04X", *(UINT16 *)cur); break;
+ case 4: sprintf(buffer, "dd %08X", *(UINT32 *)cur); break;
+ case 8: sprintf(buffer, "dq %08X%08X", ((UINT32 *)cur)[1], ((UINT32 *)cur)[0]); break;
+ }
+ }
+
+ /* if we're not in the data range, skip filler opcodes */
+ else if (*cur == 0xcc)
+ {
+ cur++;
+ continue;
+ }
+
+ /* otherwise, do a disassembly of the current instruction */
+ else
+ {
+#ifdef PTR64
+ bytes = x86log_i386_dasm_one(buffer, (UINT32)(FPTR)cur, cur, 64) & DASMFLAG_LENGTHMASK;
+#else
+ bytes = x86log_i386_dasm_one(buffer, (UINT32)(FPTR)cur, cur, 32) & DASMFLAG_LENGTHMASK;
+#endif
+ }
+
+ /* if we have a matching comment, output it */
+ if (curcomment < lastcomment && cur == curcomment->base)
+ {
+ /* if we have additional matching comments at the same address, output them first */
+ for ( ; curcomment + 1 < lastcomment && cur == curcomment[1].base; curcomment++)
+ x86log_printf(log, "%p: %-50s; %s\n", cur, "", curcomment->string);
+ x86log_printf(log, "%p: %-50s; %s\n", cur, buffer, curcomment->string);
+ }
+
+ /* if we don't, just print the disassembly and move on */
+ else
+ x86log_printf(log, "%p: %s\n", cur, buffer);
+
+ /* advance past this instruction */
+ cur += bytes;
+ }
+
+ /* reset our state */
+ reset_log(log);
+}
+
+
+/*-------------------------------------------------
+ x86log_printf - manually printf information to
+ the log file
+-------------------------------------------------*/
+
+void x86log_printf(x86log_context *log, const char *format, ...)
+{
+ va_list va;
+
+ /* open the file, creating it if necessary */
+ if (log->file == NULL)
+ log->file = fopen(astring_c(log->filename), "w");
+ if (log->file == NULL)
+ return;
+
+ /* do the printf */
+ va_start(va, format);
+ vfprintf(log->file, format, va);
+ va_end(va);
+
+ /* flush the file */
+ fflush(log->file);
+}
+
+
+
+/***************************************************************************
+ LOCAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ reset_log - reset the state of the log
+-------------------------------------------------*/
+
+static void reset_log(x86log_context *log)
+{
+ log->data_range_count = 0;
+ log->comment_count = 0;
+ log->comment_pool_next = log->comment_pool;
+}
+
+
+
+/***************************************************************************
+ DISASSEMBLERS
+***************************************************************************/
+
+#define i386_dasm_one x86log_i386_dasm_one
+#include "cpu/i386/i386dasm.c"
diff --git a/src/emu/cpu/x86log.h b/src/emu/cpu/x86log.h
new file mode 100644
index 00000000000..fe3e6490303
--- /dev/null
+++ b/src/emu/cpu/x86log.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+
+ x86log.h
+
+ x86/x64 code logging helpers.
+
+ Copyright (c) 2007, Aaron Giles
+ Released for general use under the MAME license
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __X86LOG_H__
+#define __X86LOG_H__
+
+#include "cpuintrf.h"
+#include "x86emit.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _x86log_context x86log_context;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* create a new context */
+x86log_context *x86log_create_context(const char *filename);
+
+/* release a context */
+void x86log_free_context(x86log_context *log);
+
+/* add a comment associated with a given code pointer */
+void x86log_add_comment(x86log_context *log, x86code *base, const char *format, ...);
+
+/* mark a given range as data for logging purposes */
+void x86log_mark_as_data(x86log_context *log, x86code *base, x86code *end, int size);
+
+/* disassemble a range of code and reset accumulated information */
+void x86log_disasm_code_range(x86log_context *log, const char *label, x86code *start, x86code *stop);
+
+/* manually printf information to the log file */
+void x86log_printf(x86log_context *log, const char *format, ...);
+
+
+#endif /* __X86LOG_H__ */
diff --git a/src/emu/cpu/z180/z180.c b/src/emu/cpu/z180/z180.c
new file mode 100644
index 00000000000..e0c4cfdc127
--- /dev/null
+++ b/src/emu/cpu/z180/z180.c
@@ -0,0 +1,2643 @@
+/*****************************************************************************
+ *
+ * z180.c
+ * Portable Z180 emulator V0.3
+ *
+ * Copyright (C) 2000 Juergen Buchmueller, all rights reserved.
+ *
+ * Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * You can contact me at juergen@mame.net or pullmoll@stop1984.com
+ *
+ * - This source code is released as freeware for non-commercial purposes
+ * as part of the M.A.M.E. (Multiple Arcade Machine Emulator) project.
+ * The licensing terms of MAME apply to this piece of code for the MAME
+ * project and derviative works, as defined by the MAME license. You
+ * may opt to make modifications, improvements or derivative works under
+ * that same conditions, and the MAME project may opt to keep
+ * modifications, improvements or derivatives under their terms exclusively.
+ *
+ * - Alternatively you can choose to apply the terms of the "GPL" (see
+ * below) to this - and only this - piece of code or your derivative works.
+ * Note that in no case your choice can have any impact on any other
+ * source code of the MAME project, or binary, or executable, be it closely
+ * or losely related to this piece of code.
+ *
+ * - At your choice you are also free to remove either licensing terms from
+ * this file and continue to use it under only one of the two licenses. Do this
+ * if you think that licenses are not compatible (enough) for you, or if you
+ * consider either license 'too restrictive' or 'too free'.
+ *
+ * - GPL (GNU General Public License)
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "z180.h"
+#include "cpu/z80/z80daisy.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+/* execute main opcodes inside a big switch statement */
+#ifndef BIG_SWITCH
+#define BIG_SWITCH 0
+#endif
+
+/* use big flag arrays (4*64K) for ADD/ADC/SUB/SBC/CP results */
+#define BIG_FLAGS_ARRAY 1
+
+/* Set to 1 for a more exact (but somewhat slower) Z180 emulation */
+#define Z180_EXACT 1
+
+/* on JP and JR opcodes check for tight loops */
+#define BUSY_LOOP_HACKS 0
+
+/* check for delay loops counting down BC */
+#define TIME_LOOP_HACKS 0
+
+static void set_irq_line(int irqline, int state);
+
+/****************************************************************************/
+/* The Z180 registers. HALT is set to 1 when the CPU is halted, the refresh */
+/* register is calculated as follows: refresh=(Regs.R&127)|(Regs.R2&128) */
+/****************************************************************************/
+typedef struct {
+ PAIR PREPC,PC,SP,AF,BC,DE,HL,IX,IY;
+ PAIR AF2,BC2,DE2,HL2;
+ UINT8 R,R2,IFF1,IFF2,HALT,IM,I;
+ UINT8 tmdr_latch; /* flag latched TMDR0H, TMDR1H values */
+ UINT8 read_tcr_tmdr[2]; /* flag to indicate that TCR or TMDR was read */
+ UINT32 iol; /* I/O line status bits */
+ UINT8 io[64]; /* 64 internal 8 bit registers */
+ offs_t mmu[16]; /* MMU address translation */
+ UINT8 tmdrh[2]; /* latched TMDR0H and TMDR1H values */
+ UINT16 tmdr_value[2]; /* TMDR values used byt PRT0 and PRT1 as down counter */
+ UINT8 tif[2]; /* TIF0 and TIF1 values */
+ UINT8 nmi_state; /* nmi line state */
+ UINT8 nmi_pending; /* nmi pending */
+ UINT8 irq_state[3]; /* irq line states (INT0,INT1,INT2) */
+ UINT8 after_EI; /* are we in the EI shadow? */
+ const struct z80_irq_daisy_chain *daisy;
+ int (*irq_callback)(int irqline);
+} Z180_Regs;
+
+#define CF 0x01
+#define NF 0x02
+#define PF 0x04
+#define VF PF
+#define XF 0x08
+#define HF 0x10
+#define YF 0x20
+#define ZF 0x40
+#define SF 0x80
+
+/* I/O line status flags */
+#define Z180_CKA0 0x00000001 /* I/O asynchronous clock 0 (active high) or DREQ0 (mux) */
+#define Z180_CKA1 0x00000002 /* I/O asynchronous clock 1 (active high) or TEND1 (mux) */
+#define Z180_CKS 0x00000004 /* I/O serial clock (active high) */
+#define Z180_CTS0 0x00000100 /* I clear to send 0 (active low) */
+#define Z180_CTS1 0x00000200 /* I clear to send 1 (active low) or RXS (mux) */
+#define Z180_DCD0 0x00000400 /* I data carrier detect (active low) */
+#define Z180_DREQ0 0x00000800 /* I data request DMA ch 0 (active low) or CKA0 (mux) */
+#define Z180_DREQ1 0x00001000 /* I data request DMA ch 1 (active low) */
+#define Z180_RXA0 0x00002000 /* I asynchronous receive data 0 (active high) */
+#define Z180_RXA1 0x00004000 /* I asynchronous receive data 1 (active high) */
+#define Z180_RXS 0x00008000 /* I clocked serial receive data (active high) or CTS1 (mux) */
+#define Z180_RTS0 0x00010000 /* O request to send (active low) */
+#define Z180_TEND0 0x00020000 /* O transfer end 0 (active low) or CKA1 (mux) */
+#define Z180_TEND1 0x00040000 /* O transfer end 1 (active low) */
+#define Z180_A18_TOUT 0x00080000 /* O transfer out (PRT channel, active low) or A18 (mux) */
+#define Z180_TXA0 0x00100000 /* O asynchronous transmit data 0 (active high) */
+#define Z180_TXA1 0x00200000 /* O asynchronous transmit data 1 (active high) */
+#define Z180_TXS 0x00400000 /* O clocked serial transmit data (active high) */
+
+/*
+ * Prevent warnings on NetBSD. All identifiers beginning with an underscore
+ * followed by an uppercase letter are reserved by the C standard (ISO/IEC
+ * 9899:1999, 7.1.3) to be used by the implementation. It'd be best to rename
+ * all such instances, but this is less intrusive and error-prone.
+ */
+#undef _B
+#undef _C
+#undef _L
+
+#define _PPC Z180.PREPC.d /* previous program counter */
+
+#define _PCD Z180.PC.d
+#define _PC Z180.PC.w.l
+
+#define _SPD Z180.SP.d
+#define _SP Z180.SP.w.l
+
+#define _AFD Z180.AF.d
+#define _AF Z180.AF.w.l
+#define _A Z180.AF.b.h
+#define _F Z180.AF.b.l
+
+#define _BCD Z180.BC.d
+#define _BC Z180.BC.w.l
+#define _B Z180.BC.b.h
+#define _C Z180.BC.b.l
+
+#define _DED Z180.DE.d
+#define _DE Z180.DE.w.l
+#define _D Z180.DE.b.h
+#define _E Z180.DE.b.l
+
+#define _HLD Z180.HL.d
+#define _HL Z180.HL.w.l
+#define _H Z180.HL.b.h
+#define _L Z180.HL.b.l
+
+#define _IXD Z180.IX.d
+#define _IX Z180.IX.w.l
+#define _HX Z180.IX.b.h
+#define _LX Z180.IX.b.l
+
+#define _IYD Z180.IY.d
+#define _IY Z180.IY.w.l
+#define _HY Z180.IY.b.h
+#define _LY Z180.IY.b.l
+
+#define _I Z180.I
+#define _R Z180.R
+#define _R2 Z180.R2
+#define _IM Z180.IM
+#define _IFF1 Z180.IFF1
+#define _IFF2 Z180.IFF2
+#define _HALT Z180.HALT
+
+#define IO(n) Z180.io[(n)-Z180_CNTLA0]
+#define IO_CNTLA0 IO(Z180_CNTLA0)
+#define IO_CNTLA1 IO(Z180_CNTLA1)
+#define IO_CNTLB0 IO(Z180_CNTLB0)
+#define IO_CNTLB1 IO(Z180_CNTLB1)
+#define IO_STAT0 IO(Z180_STAT0)
+#define IO_STAT1 IO(Z180_STAT1)
+#define IO_TDR0 IO(Z180_TDR0)
+#define IO_TDR1 IO(Z180_TDR1)
+#define IO_RDR0 IO(Z180_RDR0)
+#define IO_RDR1 IO(Z180_RDR1)
+#define IO_CNTR IO(Z180_CNTR)
+#define IO_TRDR IO(Z180_TRDR)
+#define IO_TMDR0L IO(Z180_TMDR0L)
+#define IO_TMDR0H IO(Z180_TMDR0H)
+#define IO_RLDR0L IO(Z180_RLDR0L)
+#define IO_RLDR0H IO(Z180_RLDR0H)
+#define IO_TCR IO(Z180_TCR)
+#define IO_IO11 IO(Z180_IO11)
+#define IO_ASEXT0 IO(Z180_ASEXT0)
+#define IO_ASEXT1 IO(Z180_ASEXT1)
+#define IO_TMDR1L IO(Z180_TMDR1L)
+#define IO_TMDR1H IO(Z180_TMDR1H)
+#define IO_RLDR1L IO(Z180_RLDR1L)
+#define IO_RLDR1H IO(Z180_RLDR1H)
+#define IO_FRC IO(Z180_FRC)
+#define IO_IO19 IO(Z180_IO19)
+#define IO_ASTC0L IO(Z180_ASTC0L)
+#define IO_ASTC0H IO(Z180_ASTC0H)
+#define IO_ASTC1L IO(Z180_ASTC1L)
+#define IO_ASTC1H IO(Z180_ASTC1H)
+#define IO_CMR IO(Z180_CMR)
+#define IO_CCR IO(Z180_CCR)
+#define IO_SAR0L IO(Z180_SAR0L)
+#define IO_SAR0H IO(Z180_SAR0H)
+#define IO_SAR0B IO(Z180_SAR0B)
+#define IO_DAR0L IO(Z180_DAR0L)
+#define IO_DAR0H IO(Z180_DAR0H)
+#define IO_DAR0B IO(Z180_DAR0B)
+#define IO_BCR0L IO(Z180_BCR0L)
+#define IO_BCR0H IO(Z180_BCR0H)
+#define IO_MAR1L IO(Z180_MAR1L)
+#define IO_MAR1H IO(Z180_MAR1H)
+#define IO_MAR1B IO(Z180_MAR1B)
+#define IO_IAR1L IO(Z180_IAR1L)
+#define IO_IAR1H IO(Z180_IAR1H)
+#define IO_IAR1B IO(Z180_IAR1B)
+#define IO_BCR1L IO(Z180_BCR1L)
+#define IO_BCR1H IO(Z180_BCR1H)
+#define IO_DSTAT IO(Z180_DSTAT)
+#define IO_DMODE IO(Z180_DMODE)
+#define IO_DCNTL IO(Z180_DCNTL)
+#define IO_IL IO(Z180_IL)
+#define IO_ITC IO(Z180_ITC)
+#define IO_IO35 IO(Z180_IO35)
+#define IO_RCR IO(Z180_RCR)
+#define IO_IO37 IO(Z180_IO37)
+#define IO_CBR IO(Z180_CBR)
+#define IO_BBR IO(Z180_BBR)
+#define IO_CBAR IO(Z180_CBAR)
+#define IO_IO3B IO(Z180_IO3B)
+#define IO_IO3C IO(Z180_IO3C)
+#define IO_IO3D IO(Z180_IO3D)
+#define IO_OMCR IO(Z180_OMCR)
+#define IO_IOCR IO(Z180_IOCR)
+
+/* 00 ASCI control register A ch 0 */
+#define Z180_CNTLA0_MPE 0x80
+#define Z180_CNTLA0_RE 0x40
+#define Z180_CNTLA0_TE 0x20
+#define Z180_CNTLA0_RTS0 0x10
+#define Z180_CNTLA0_MPBR_EFR 0x08
+#define Z180_CNTLA0_MODE_DATA 0x04
+#define Z180_CNTLA0_MODE_PARITY 0x02
+#define Z180_CNTLA0_MODE_STOPB 0x01
+
+#define Z180_CNTLA0_RESET 0x10
+#define Z180_CNTLA0_RMASK 0xff
+#define Z180_CNTLA0_WMASK 0xff
+
+/* 01 ASCI control register A ch 1 */
+#define Z180_CNTLA1_MPE 0x80
+#define Z180_CNTLA1_RE 0x40
+#define Z180_CNTLA1_TE 0x20
+#define Z180_CNTLA1_CKA1D 0x10
+#define Z180_CNTLA1_MPBR_EFR 0x08
+#define Z180_CNTLA1_MODE 0x07
+
+#define Z180_CNTLA1_RESET 0x10
+#define Z180_CNTLA1_RMASK 0xff
+#define Z180_CNTLA1_WMASK 0xff
+
+/* 02 ASCI control register B ch 0 */
+#define Z180_CNTLB0_MPBT 0x80
+#define Z180_CNTLB0_MP 0x40
+#define Z180_CNTLB0_CTS_PS 0x20
+#define Z180_CNTLB0_PEO 0x10
+#define Z180_CNTLB0_DR 0x08
+#define Z180_CNTLB0_SS 0x07
+
+#define Z180_CNTLB0_RESET 0x07
+#define Z180_CNTLB0_RMASK 0xff
+#define Z180_CNTLB0_WMASK 0xff
+
+/* 03 ASCI control register B ch 1 */
+#define Z180_CNTLB1_MPBT 0x80
+#define Z180_CNTLB1_MP 0x40
+#define Z180_CNTLB1_CTS_PS 0x20
+#define Z180_CNTLB1_PEO 0x10
+#define Z180_CNTLB1_DR 0x08
+#define Z180_CNTLB1_SS 0x07
+
+#define Z180_CNTLB1_RESET 0x07
+#define Z180_CNTLB1_RMASK 0xff
+#define Z180_CNTLB1_WMASK 0xff
+
+/* 04 ASCI status register 0 */
+#define Z180_STAT0_RDRF 0x80
+#define Z180_STAT0_OVRN 0x40
+#define Z180_STAT0_PE 0x20
+#define Z180_STAT0_FE 0x10
+#define Z180_STAT0_RIE 0x08
+#define Z180_STAT0_DCD0 0x04
+#define Z180_STAT0_TDRE 0x02
+#define Z180_STAT0_TIE 0x01
+
+#define Z180_STAT0_RESET 0x00
+#define Z180_STAT0_RMASK 0xff
+#define Z180_STAT0_WMASK 0x09
+
+/* 05 ASCI status register 1 */
+#define Z180_STAT1_RDRF 0x80
+#define Z180_STAT1_OVRN 0x40
+#define Z180_STAT1_PE 0x20
+#define Z180_STAT1_FE 0x10
+#define Z180_STAT1_RIE 0x08
+#define Z180_STAT1_CTS1E 0x04
+#define Z180_STAT1_TDRE 0x02
+#define Z180_STAT1_TIE 0x01
+
+#define Z180_STAT1_RESET 0x00
+#define Z180_STAT1_RMASK 0xff
+#define Z180_STAT1_WMASK 0x0d
+
+/* 06 ASCI transmit data register 0 */
+#define Z180_TDR0_TDR 0xff
+
+#define Z180_TDR0_RESET 0x00
+#define Z180_TDR0_RMASK 0xff
+#define Z180_TDR0_WMASK 0xff
+
+/* 07 ASCI transmit data register 1 */
+#define Z180_TDR1_TDR 0xff
+
+#define Z180_TDR1_RESET 0x00
+#define Z180_TDR1_RMASK 0xff
+#define Z180_TDR1_WMASK 0xff
+
+/* 08 ASCI receive register 0 */
+#define Z180_RDR0_RDR 0xff
+
+#define Z180_RDR0_RESET 0x00
+#define Z180_RDR0_RMASK 0xff
+#define Z180_RDR0_WMASK 0xff
+
+/* 09 ASCI receive register 1 */
+#define Z180_RDR1_RDR 0xff
+
+#define Z180_RDR1_RESET 0x00
+#define Z180_RDR1_RMASK 0xff
+#define Z180_RDR1_WMASK 0xff
+
+/* 0a CSI/O control/status register */
+#define Z180_CNTR_EF 0x80
+#define Z180_CNTR_EIE 0x40
+#define Z180_CNTR_RE 0x20
+#define Z180_CNTR_TE 0x10
+#define Z180_CNTR_SS 0x07
+
+#define Z180_CNTR_RESET 0x07
+#define Z180_CNTR_RMASK 0xff
+#define Z180_CNTR_WMASK 0x7f
+
+/* 0b CSI/O transmit/receive register */
+#define Z180_TRDR_RESET 0x00
+#define Z180_TRDR_RMASK 0xff
+#define Z180_TRDR_WMASK 0xff
+
+/* 0c TIMER data register ch 0 L */
+#define Z180_TMDR0L_RESET 0x00
+#define Z180_TMDR0L_RMASK 0xff
+#define Z180_TMDR0L_WMASK 0xff
+
+/* 0d TIMER data register ch 0 H */
+#define Z180_TMDR0H_RESET 0x00
+#define Z180_TMDR0H_RMASK 0xff
+#define Z180_TMDR0H_WMASK 0xff
+
+/* 0e TIMER reload register ch 0 L */
+#define Z180_RLDR0L_RESET 0xff
+#define Z180_RLDR0L_RMASK 0xff
+#define Z180_RLDR0L_WMASK 0xff
+
+/* 0f TIMER reload register ch 0 H */
+#define Z180_RLDR0H_RESET 0xff
+#define Z180_RLDR0H_RMASK 0xff
+#define Z180_RLDR0H_WMASK 0xff
+
+/* 10 TIMER control register */
+#define Z180_TCR_TIF1 0x80
+#define Z180_TCR_TIF0 0x40
+#define Z180_TCR_TIE1 0x20
+#define Z180_TCR_TIE0 0x10
+#define Z180_TCR_TOC1 0x08
+#define Z180_TCR_TOC0 0x04
+#define Z180_TCR_TDE1 0x02
+#define Z180_TCR_TDE0 0x01
+
+#define Z180_TCR_RESET 0x00
+#define Z180_TCR_RMASK 0xff
+#define Z180_TCR_WMASK 0x3f
+
+/* 11 reserved */
+#define Z180_IO11_RESET 0x00
+#define Z180_IO11_RMASK 0xff
+#define Z180_IO11_WMASK 0xff
+
+/* 12 (Z8S180/Z8L180) ASCI extension control register 0 */
+#define Z180_ASEXT0_RDRF 0x80
+#define Z180_ASEXT0_DCD0 0x40
+#define Z180_ASEXT0_CTS0 0x20
+#define Z180_ASEXT0_X1_BIT_CLK0 0x10
+#define Z180_ASEXT0_BRG0_MODE 0x08
+#define Z180_ASEXT0_BRK_EN 0x04
+#define Z180_ASEXT0_BRK_DET 0x02
+#define Z180_ASEXT0_BRK_SEND 0x01
+
+#define Z180_ASEXT0_RESET 0x00
+#define Z180_ASEXT0_RMASK 0xff
+#define Z180_ASEXT0_WMASK 0xfd
+
+/* 13 (Z8S180/Z8L180) ASCI extension control register 0 */
+#define Z180_ASEXT1_RDRF 0x80
+#define Z180_ASEXT1_X1_BIT_CLK1 0x10
+#define Z180_ASEXT1_BRG1_MODE 0x08
+#define Z180_ASEXT1_BRK_EN 0x04
+#define Z180_ASEXT1_BRK_DET 0x02
+#define Z180_ASEXT1_BRK_SEND 0x01
+
+#define Z180_ASEXT1_RESET 0x00
+#define Z180_ASEXT1_RMASK 0xff
+#define Z180_ASEXT1_WMASK 0xfd
+
+
+/* 14 TIMER data register ch 1 L */
+#define Z180_TMDR1L_RESET 0x00
+#define Z180_TMDR1L_RMASK 0xff
+#define Z180_TMDR1L_WMASK 0xff
+
+/* 15 TIMER data register ch 1 H */
+#define Z180_TMDR1H_RESET 0x00
+#define Z180_TMDR1H_RMASK 0xff
+#define Z180_TMDR1H_WMASK 0xff
+
+/* 16 TIMER reload register ch 1 L */
+#define Z180_RLDR1L_RESET 0x00
+#define Z180_RLDR1L_RMASK 0xff
+#define Z180_RLDR1L_WMASK 0xff
+
+/* 17 TIMER reload register ch 1 H */
+#define Z180_RLDR1H_RESET 0x00
+#define Z180_RLDR1H_RMASK 0xff
+#define Z180_RLDR1H_WMASK 0xff
+
+/* 18 free running counter */
+#define Z180_FRC_RESET 0x00
+#define Z180_FRC_RMASK 0xff
+#define Z180_FRC_WMASK 0xff
+
+/* 19 reserved */
+#define Z180_IO19_RESET 0x00
+#define Z180_IO19_RMASK 0xff
+#define Z180_IO19_WMASK 0xff
+
+/* 1a ASCI time constant ch 0 L */
+#define Z180_ASTC0L_RESET 0x00
+#define Z180_ASTC0L_RMASK 0xff
+#define Z180_ASTC0L_WMASK 0xff
+
+/* 1b ASCI time constant ch 0 H */
+#define Z180_ASTC0H_RESET 0x00
+#define Z180_ASTC0H_RMASK 0xff
+#define Z180_ASTC0H_WMASK 0xff
+
+/* 1c ASCI time constant ch 1 L */
+#define Z180_ASTC1L_RESET 0x00
+#define Z180_ASTC1L_RMASK 0xff
+#define Z180_ASTC1L_WMASK 0xff
+
+/* 1d ASCI time constant ch 1 H */
+#define Z180_ASTC1H_RESET 0x00
+#define Z180_ASTC1H_RMASK 0xff
+#define Z180_ASTC1H_WMASK 0xff
+
+/* 1e clock multiplier */
+#define Z180_CMR_X2 0x80
+
+#define Z180_CMR_RESET 0x7f
+#define Z180_CMR_RMASK 0x80
+#define Z180_CMR_WMASK 0x80
+
+/* 1f chip control register */
+#define Z180_CCR_CLOCK_DIVIDE 0x80
+#define Z180_CCR_STDBY_IDLE1 0x40
+#define Z180_CCR_BREXT 0x20
+#define Z180_CCR_LNPHI 0x10
+#define Z180_CCR_STDBY_IDLE0 0x08
+#define Z180_CCR_LNIO 0x04
+#define Z180_CCR_LNCPU_CTL 0x02
+#define Z180_CCR_LNAD_DATA 0x01
+
+#define Z180_CCR_RESET 0x00
+#define Z180_CCR_RMASK 0xff
+#define Z180_CCR_WMASK 0xff
+
+/* 20 DMA source address register ch 0 L */
+#define Z180_SAR0L_SAR 0xff
+
+#define Z180_SAR0L_RESET 0x00
+#define Z180_SAR0L_RMASK 0xff
+#define Z180_SAR0L_WMASK 0xff
+
+/* 21 DMA source address register ch 0 H */
+#define Z180_SAR0H_SAR 0xff
+
+#define Z180_SAR0H_RESET 0x00
+#define Z180_SAR0H_RMASK 0xff
+#define Z180_SAR0H_WMASK 0xff
+
+/* 22 DMA source address register ch 0 B */
+#define Z180_SAR0B_SAR 0x0f
+
+#define Z180_SAR0B_RESET 0x00
+#define Z180_SAR0B_RMASK 0x0f
+#define Z180_SAR0B_WMASK 0x0f
+
+/* 23 DMA destination address register ch 0 L */
+#define Z180_DAR0L_DAR 0xff
+
+#define Z180_DAR0L_RESET 0x00
+#define Z180_DAR0L_RMASK 0xff
+#define Z180_DAR0L_WMASK 0xff
+
+/* 24 DMA destination address register ch 0 H */
+#define Z180_DAR0H_DAR 0xff
+
+#define Z180_DAR0H_RESET 0x00
+#define Z180_DAR0H_RMASK 0xff
+#define Z180_DAR0H_WMASK 0xff
+
+/* 25 DMA destination address register ch 0 B */
+#define Z180_DAR0B_DAR 0x00
+
+#define Z180_DAR0B_RESET 0x00
+#define Z180_DAR0B_RMASK 0x0f
+#define Z180_DAR0B_WMASK 0x0f
+
+/* 26 DMA byte count register ch 0 L */
+#define Z180_BCR0L_BCR 0xff
+
+#define Z180_BCR0L_RESET 0x00
+#define Z180_BCR0L_RMASK 0xff
+#define Z180_BCR0L_WMASK 0xff
+
+/* 27 DMA byte count register ch 0 H */
+#define Z180_BCR0H_BCR 0xff
+
+#define Z180_BCR0H_RESET 0x00
+#define Z180_BCR0H_RMASK 0xff
+#define Z180_BCR0H_WMASK 0xff
+
+/* 28 DMA memory address register ch 1 L */
+#define Z180_MAR1L_MAR 0xff
+
+#define Z180_MAR1L_RESET 0x00
+#define Z180_MAR1L_RMASK 0xff
+#define Z180_MAR1L_WMASK 0xff
+
+/* 29 DMA memory address register ch 1 H */
+#define Z180_MAR1H_MAR 0xff
+
+#define Z180_MAR1H_RESET 0x00
+#define Z180_MAR1H_RMASK 0xff
+#define Z180_MAR1H_WMASK 0xff
+
+/* 2a DMA memory address register ch 1 B */
+#define Z180_MAR1B_MAR 0x0f
+
+#define Z180_MAR1B_RESET 0x00
+#define Z180_MAR1B_RMASK 0x0f
+#define Z180_MAR1B_WMASK 0x0f
+
+/* 2b DMA I/O address register ch 1 L */
+#define Z180_IAR1L_IAR 0xff
+
+#define Z180_IAR1L_RESET 0x00
+#define Z180_IAR1L_RMASK 0xff
+#define Z180_IAR1L_WMASK 0xff
+
+/* 2c DMA I/O address register ch 1 H */
+#define Z180_IAR1H_IAR 0xff
+
+#define Z180_IAR1H_RESET 0x00
+#define Z180_IAR1H_RMASK 0xff
+#define Z180_IAR1H_WMASK 0xff
+
+/* 2d (Z8S180/Z8L180) DMA I/O address register ch 1 B */
+#define Z180_IAR1B_IAR 0x0f
+
+#define Z180_IAR1B_RESET 0x00
+#define Z180_IAR1B_RMASK 0x0f
+#define Z180_IAR1B_WMASK 0x0f
+
+/* 2e DMA byte count register ch 1 L */
+#define Z180_BCR1L_BCR 0xff
+
+#define Z180_BCR1L_RESET 0x00
+#define Z180_BCR1L_RMASK 0xff
+#define Z180_BCR1L_WMASK 0xff
+
+/* 2f DMA byte count register ch 1 H */
+#define Z180_BCR1H_BCR 0xff
+
+#define Z180_BCR1H_RESET 0x00
+#define Z180_BCR1H_RMASK 0xff
+#define Z180_BCR1H_WMASK 0xff
+
+/* 30 DMA status register */
+#define Z180_DSTAT_DE1 0x80 /* DMA enable ch 1 */
+#define Z180_DSTAT_DE0 0x40 /* DMA enable ch 0 */
+#define Z180_DSTAT_DWE1 0x20 /* DMA write enable ch 0 (active low) */
+#define Z180_DSTAT_DWE0 0x10 /* DMA write enable ch 1 (active low) */
+#define Z180_DSTAT_DIE1 0x08 /* DMA IRQ enable ch 1 */
+#define Z180_DSTAT_DIE0 0x04 /* DMA IRQ enable ch 0 */
+#define Z180_DSTAT_DME 0x01 /* DMA enable (read only) */
+
+#define Z180_DSTAT_RESET 0x30
+#define Z180_DSTAT_RMASK 0xfd
+#define Z180_DSTAT_WMASK 0xcc
+
+/* 31 DMA mode register */
+#define Z180_DMODE_DM 0x30
+#define Z180_DMODE_SM 0x0c
+#define Z180_DMODE_MMOD 0x04
+
+#define Z180_DMODE_RESET 0x00
+#define Z180_DMODE_RMASK 0x3e
+#define Z180_DMODE_WMASK 0x3e
+
+/* 32 DMA/WAIT control register */
+#define Z180_DCNTL_MWI1 0x80
+#define Z180_DCNTL_MWI0 0x40
+#define Z180_DCNTL_IWI1 0x20
+#define Z180_DCNTL_IWI0 0x10
+#define Z180_DCNTL_DMS1 0x08
+#define Z180_DCNTL_DMS0 0x04
+#define Z180_DCNTL_DIM1 0x02
+#define Z180_DCNTL_DIM0 0x01
+
+#define Z180_DCNTL_RESET 0x00
+#define Z180_DCNTL_RMASK 0xff
+#define Z180_DCNTL_WMASK 0xff
+
+/* 33 INT vector low register */
+#define Z180_IL_IL 0xe0
+
+#define Z180_IL_RESET 0x00
+#define Z180_IL_RMASK 0xe0
+#define Z180_IL_WMASK 0xe0
+
+/* 34 INT/TRAP control register */
+#define Z180_ITC_TRAP 0x80
+#define Z180_ITC_UFO 0x40
+#define Z180_ITC_ITE2 0x04
+#define Z180_ITC_ITE1 0x02
+#define Z180_ITC_ITE0 0x01
+
+#define Z180_ITC_RESET 0x01
+#define Z180_ITC_RMASK 0xc7
+#define Z180_ITC_WMASK 0x87
+
+/* 35 reserved */
+#define Z180_IO35_RESET 0x00
+#define Z180_IO35_RMASK 0xff
+#define Z180_IO35_WMASK 0xff
+
+/* 36 refresh control register */
+#define Z180_RCR_REFE 0x80
+#define Z180_RCR_REFW 0x80
+#define Z180_RCR_CYC 0x03
+
+#define Z180_RCR_RESET 0xc0
+#define Z180_RCR_RMASK 0xc3
+#define Z180_RCR_WMASK 0xc3
+
+/* 37 reserved */
+#define Z180_IO37_RESET 0x00
+#define Z180_IO37_RMASK 0xff
+#define Z180_IO37_WMASK 0xff
+
+/* 38 MMU common base register */
+#define Z180_CBR_CB 0xff
+
+#define Z180_CBR_RESET 0x00
+#define Z180_CBR_RMASK 0xff
+#define Z180_CBR_WMASK 0xff
+
+/* 39 MMU bank base register */
+#define Z180_BBR_BB 0xff
+
+#define Z180_BBR_RESET 0x00
+#define Z180_BBR_RMASK 0xff
+#define Z180_BBR_WMASK 0xff
+
+/* 3a MMU common/bank area register */
+#define Z180_CBAR_CA 0xf0
+#define Z180_CBAR_BA 0x0f
+
+#define Z180_CBAR_RESET 0xf0
+#define Z180_CBAR_RMASK 0xff
+#define Z180_CBAR_WMASK 0xff
+
+/* 3b reserved */
+#define Z180_IO3B_RESET 0x00
+#define Z180_IO3B_RMASK 0xff
+#define Z180_IO3B_WMASK 0xff
+
+/* 3c reserved */
+#define Z180_IO3C_RESET 0x00
+#define Z180_IO3C_RMASK 0xff
+#define Z180_IO3C_WMASK 0xff
+
+/* 3d reserved */
+#define Z180_IO3D_RESET 0x00
+#define Z180_IO3D_RMASK 0xff
+#define Z180_IO3D_WMASK 0xff
+
+/* 3e operation mode control register */
+#define Z180_OMCR_RESET 0x00
+#define Z180_OMCR_RMASK 0xff
+#define Z180_OMCR_WMASK 0xff
+
+/* 3f I/O control register */
+#define Z180_IOCR_RESET 0x00
+#define Z180_IOCR_RMASK 0xff
+#define Z180_IOCR_WMASK 0xff
+
+int z180_icount;
+static Z180_Regs Z180;
+static UINT32 EA;
+
+static UINT8 SZ[256]; /* zero and sign flags */
+static UINT8 SZ_BIT[256]; /* zero, sign and parity/overflow (=zero) flags for BIT opcode */
+static UINT8 SZP[256]; /* zero, sign and parity flags */
+static UINT8 SZHV_inc[256]; /* zero, sign, half carry and overflow flags INC r8 */
+static UINT8 SZHV_dec[256]; /* zero, sign, half carry and overflow flags DEC r8 */
+
+#if BIG_FLAGS_ARRAY
+static UINT8 *SZHVC_add = 0;
+static UINT8 *SZHVC_sub = 0;
+#endif
+
+/****************************************************************************
+ * Burn an odd amount of cycles, that is instructions taking something
+ * different from 4 T-states per opcode (and R increment)
+ ****************************************************************************/
+INLINE void BURNODD(int cycles, int opcodes, int cyclesum)
+{
+ if( cycles > 0 )
+ {
+ _R += (cycles / cyclesum) * opcodes;
+ z180_icount -= (cycles / cyclesum) * cyclesum;
+ }
+}
+
+static UINT8 z180_readcontrol(offs_t port);
+static void z180_writecontrol(offs_t port, UINT8 data);
+static void z180_dma0(void);
+static void z180_dma1(void);
+static void z180_burn(int cycles);
+static void z180_set_info(UINT32 state, cpuinfo *info);
+
+#include "z180daa.h"
+#include "z180ops.h"
+#include "z180tbl.h"
+
+#include "z180cb.c"
+#include "z180xy.c"
+#include "z180dd.c"
+#include "z180fd.c"
+#include "z180ed.c"
+#include "z180op.c"
+
+static UINT8 z180_readcontrol(offs_t port)
+{
+ /* normal external readport */
+ UINT8 data = io_read_byte_8(port);
+
+ /* remap internal I/O registers */
+ if((port & (IO_IOCR & 0xc0)) == (IO_IOCR & 0xc0))
+ port = port - (IO_IOCR & 0xc0);
+
+ /* but ignore the data and read the internal register */
+ switch (port + Z180_CNTLA0)
+ {
+ case Z180_CNTLA0:
+ data = IO_CNTLA0 & Z180_CNTLA0_RMASK;
+ LOG(("Z180 #%d CNTLA0 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_CNTLA1:
+ data = IO_CNTLA1 & Z180_CNTLA1_RMASK;
+ LOG(("Z180 #%d CNTLA1 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_CNTLB0:
+ data = IO_CNTLB0 & Z180_CNTLB0_RMASK;
+ LOG(("Z180 #%d CNTLB0 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_CNTLB1:
+ data = IO_CNTLB1 & Z180_CNTLB1_RMASK;
+ LOG(("Z180 #%d CNTLB1 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_STAT0:
+ data = IO_STAT0 & Z180_STAT0_RMASK;
+data |= 0x02; // kludge for 20pacgal
+ LOG(("Z180 #%d STAT0 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_STAT1:
+ data = IO_STAT1 & Z180_STAT1_RMASK;
+ LOG(("Z180 #%d STAT1 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_TDR0:
+ data = IO_TDR0 & Z180_TDR0_RMASK;
+ LOG(("Z180 #%d TDR0 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_TDR1:
+ data = IO_TDR1 & Z180_TDR1_RMASK;
+ LOG(("Z180 #%d TDR1 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_RDR0:
+ data = IO_RDR0 & Z180_RDR0_RMASK;
+ LOG(("Z180 #%d RDR0 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_RDR1:
+ data = IO_RDR1 & Z180_RDR1_RMASK;
+ LOG(("Z180 #%d RDR1 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_CNTR:
+ data = IO_CNTR & Z180_CNTR_RMASK;
+ LOG(("Z180 #%d CNTR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_TRDR:
+ data = IO_TRDR & Z180_TRDR_RMASK;
+ LOG(("Z180 #%d TRDR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_TMDR0L:
+ data = Z180.tmdr_value[0] & Z180_TMDR0L_RMASK;
+ LOG(("Z180 #%d TMDR0L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ /* if timer is counting, latch the MSB and set the latch flag */
+ if ((IO_TCR & Z180_TCR_TDE0) == 0)
+ {
+ Z180.tmdr_latch |= 1;
+ Z180.tmdrh[0] = (Z180.tmdr_value[0] & 0xff00) >> 8;
+ }
+
+ if(Z180.read_tcr_tmdr[0])
+ {
+ Z180.tif[0] = 0; // reset TIF0
+ Z180.read_tcr_tmdr[0] = 0;
+ }
+ else
+ {
+ Z180.read_tcr_tmdr[0] = 1;
+ }
+ break;
+
+ case Z180_TMDR0H:
+ /* read latched value? */
+ if (Z180.tmdr_latch & 1)
+ {
+ Z180.tmdr_latch &= ~1;
+ data = Z180.tmdrh[0];
+ }
+ else
+ {
+ data = (Z180.tmdr_value[0] & 0xff00) >> 8;
+ }
+
+ if(Z180.read_tcr_tmdr[0])
+ {
+ Z180.tif[0] = 0; // reset TIF0
+ Z180.read_tcr_tmdr[0] = 0;
+ }
+ else
+ {
+ Z180.read_tcr_tmdr[0] = 1;
+ }
+ LOG(("Z180 #%d TMDR0H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_RLDR0L:
+ data = IO_RLDR0L & Z180_RLDR0L_RMASK;
+ LOG(("Z180 #%d RLDR0L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_RLDR0H:
+ data = IO_RLDR0H & Z180_RLDR0H_RMASK;
+ LOG(("Z180 #%d RLDR0H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_TCR:
+ data = (IO_TCR & Z180_TCR_RMASK) | (Z180.tif[0] << 6) | (Z180.tif[1] << 7);
+
+ if(Z180.read_tcr_tmdr[0])
+ {
+ Z180.tif[0] = 0; // reset TIF0
+ Z180.read_tcr_tmdr[0] = 0;
+ }
+ else
+ {
+ Z180.read_tcr_tmdr[0] = 1;
+ }
+
+ if(Z180.read_tcr_tmdr[1])
+ {
+ Z180.tif[1] = 0; // reset TIF1
+ Z180.read_tcr_tmdr[1] = 0;
+ }
+ else
+ {
+ Z180.read_tcr_tmdr[1] = 1;
+ }
+
+ LOG(("Z180 #%d TCR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IO11:
+ data = IO_IO11 & Z180_IO11_RMASK;
+ LOG(("Z180 #%d IO11 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_ASEXT0:
+ data = IO_ASEXT0 & Z180_ASEXT0_RMASK;
+ LOG(("Z180 #%d ASEXT0 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_ASEXT1:
+ data = IO_ASEXT1 & Z180_ASEXT1_RMASK;
+ LOG(("Z180 #%d ASEXT1 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_TMDR1L:
+ data = Z180.tmdr_value[1] & Z180_TMDR1L_RMASK;
+ LOG(("Z180 #%d TMDR1L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ /* if timer is counting, latch the MSB and set the latch flag */
+ if ((IO_TCR & Z180_TCR_TDE1) == 0)
+ {
+ Z180.tmdr_latch |= 2;
+ Z180.tmdrh[1] = (Z180.tmdr_value[1] & 0xff00) >> 8;
+ }
+
+ if(Z180.read_tcr_tmdr[1])
+ {
+ Z180.tif[1] = 0; // reset TIF1
+ Z180.read_tcr_tmdr[1] = 0;
+ }
+ else
+ {
+ Z180.read_tcr_tmdr[1] = 1;
+ }
+ break;
+
+ case Z180_TMDR1H:
+ /* read latched value? */
+ if (Z180.tmdr_latch & 2)
+ {
+ Z180.tmdr_latch &= ~2;
+ data = Z180.tmdrh[1];
+ }
+ else
+ {
+ data = (Z180.tmdr_value[1] & 0xff00) >> 8;
+ }
+
+ if(Z180.read_tcr_tmdr[1])
+ {
+ Z180.tif[1] = 0; // reset TIF1
+ Z180.read_tcr_tmdr[1] = 0;
+ }
+ else
+ {
+ Z180.read_tcr_tmdr[1] = 1;
+ }
+ LOG(("Z180 #%d TMDR1H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_RLDR1L:
+ data = IO_RLDR1L & Z180_RLDR1L_RMASK;
+ LOG(("Z180 #%d RLDR1L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_RLDR1H:
+ data = IO_RLDR1H & Z180_RLDR1H_RMASK;
+ LOG(("Z180 #%d RLDR1H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_FRC:
+ data = IO_FRC & Z180_FRC_RMASK;
+ LOG(("Z180 #%d FRC rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IO19:
+ data = IO_IO19 & Z180_IO19_RMASK;
+ LOG(("Z180 #%d IO19 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_ASTC0L:
+ data = IO_ASTC0L & Z180_ASTC0L_RMASK;
+ LOG(("Z180 #%d ASTC0L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_ASTC0H:
+ data = IO_ASTC0H & Z180_ASTC0H_RMASK;
+ LOG(("Z180 #%d ASTC0H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_ASTC1L:
+ data = IO_ASTC1L & Z180_ASTC1L_RMASK;
+ LOG(("Z180 #%d ASTC1L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_ASTC1H:
+ data = IO_ASTC1H & Z180_ASTC1H_RMASK;
+ LOG(("Z180 #%d ASTC1H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_CMR:
+ data = IO_CMR & Z180_CMR_RMASK;
+ LOG(("Z180 #%d CMR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_CCR:
+ data = IO_CCR & Z180_CCR_RMASK;
+ LOG(("Z180 #%d CCR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_SAR0L:
+ data = IO_SAR0L & Z180_SAR0L_RMASK;
+ LOG(("Z180 #%d SAR0L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_SAR0H:
+ data = IO_SAR0H & Z180_SAR0H_RMASK;
+ LOG(("Z180 #%d SAR0H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_SAR0B:
+ data = IO_SAR0B & Z180_SAR0B_RMASK;
+ LOG(("Z180 #%d SAR0B rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_DAR0L:
+ data = IO_DAR0L & Z180_DAR0L_RMASK;
+ LOG(("Z180 #%d DAR0L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_DAR0H:
+ data = IO_DAR0H & Z180_DAR0H_RMASK;
+ LOG(("Z180 #%d DAR0H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_DAR0B:
+ data = IO_DAR0B & Z180_DAR0B_RMASK;
+ LOG(("Z180 #%d DAR0B rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_BCR0L:
+ data = IO_BCR0L & Z180_BCR0L_RMASK;
+ LOG(("Z180 #%d BCR0L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_BCR0H:
+ data = IO_BCR0H & Z180_BCR0H_RMASK;
+ LOG(("Z180 #%d BCR0H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_MAR1L:
+ data = IO_MAR1L & Z180_MAR1L_RMASK;
+ LOG(("Z180 #%d MAR1L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_MAR1H:
+ data = IO_MAR1H & Z180_MAR1H_RMASK;
+ LOG(("Z180 #%d MAR1H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_MAR1B:
+ data = IO_MAR1B & Z180_MAR1B_RMASK;
+ LOG(("Z180 #%d MAR1B rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IAR1L:
+ data = IO_IAR1L & Z180_IAR1L_RMASK;
+ LOG(("Z180 #%d IAR1L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IAR1H:
+ data = IO_IAR1H & Z180_IAR1H_RMASK;
+ LOG(("Z180 #%d IAR1H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IAR1B:
+ data = IO_IAR1B & Z180_IAR1B_RMASK;
+ LOG(("Z180 #%d IAR1B rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_BCR1L:
+ data = IO_BCR1L & Z180_BCR1L_RMASK;
+ LOG(("Z180 #%d BCR1L rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_BCR1H:
+ data = IO_BCR1H & Z180_BCR1H_RMASK;
+ LOG(("Z180 #%d BCR1H rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_DSTAT:
+ data = IO_DSTAT & Z180_DSTAT_RMASK;
+ LOG(("Z180 #%d DSTAT rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_DMODE:
+ data = IO_DMODE & Z180_DMODE_RMASK;
+ LOG(("Z180 #%d DMODE rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_DCNTL:
+ data = IO_DCNTL & Z180_DCNTL_RMASK;
+ LOG(("Z180 #%d DCNTL rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IL:
+ data = IO_IL & Z180_IL_RMASK;
+ LOG(("Z180 #%d IL rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_ITC:
+ data = IO_ITC & Z180_ITC_RMASK;
+ LOG(("Z180 #%d ITC rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IO35:
+ data = IO_IO35 & Z180_IO35_RMASK;
+ LOG(("Z180 #%d IO35 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_RCR:
+ data = IO_RCR & Z180_RCR_RMASK;
+ LOG(("Z180 #%d RCR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IO37:
+ data = IO_IO37 & Z180_IO37_RMASK;
+ LOG(("Z180 #%d IO37 rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_CBR:
+ data = IO_CBR & Z180_CBR_RMASK;
+ LOG(("Z180 #%d CBR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_BBR:
+ data = IO_BBR & Z180_BBR_RMASK;
+ LOG(("Z180 #%d BBR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_CBAR:
+ data = IO_CBAR & Z180_CBAR_RMASK;
+ LOG(("Z180 #%d CBAR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IO3B:
+ data = IO_IO3B & Z180_IO3B_RMASK;
+ LOG(("Z180 #%d IO3B rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IO3C:
+ data = IO_IO3C & Z180_IO3C_RMASK;
+ LOG(("Z180 #%d IO3C rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IO3D:
+ data = IO_IO3D & Z180_IO3D_RMASK;
+ LOG(("Z180 #%d IO3D rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_OMCR:
+ data = IO_OMCR & Z180_OMCR_RMASK;
+ LOG(("Z180 #%d OMCR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+
+ case Z180_IOCR:
+ data = IO_IOCR & Z180_IOCR_RMASK;
+ LOG(("Z180 #%d IOCR rd $%02x ($%02x)\n", cpu_getactivecpu(), data, Z180.io[port & 0x3f]));
+ break;
+ }
+
+ return data;
+}
+
+static void z180_writecontrol(offs_t port, UINT8 data)
+{
+ /* normal external write port */
+ io_write_byte_8(port, data);
+
+ /* remap internal I/O registers */
+ if((port & (IO_IOCR & 0xc0)) == (IO_IOCR & 0xc0))
+ port = port - (IO_IOCR & 0xc0);
+
+ /* store the data in the internal register */
+ switch (port + Z180_CNTLA0)
+ {
+ case Z180_CNTLA0:
+ LOG(("Z180 #%d CNTLA0 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_CNTLA0_WMASK));
+ IO_CNTLA0 = (IO_CNTLA0 & ~Z180_CNTLA0_WMASK) | (data & Z180_CNTLA0_WMASK);
+ break;
+
+ case Z180_CNTLA1:
+ LOG(("Z180 #%d CNTLA1 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_CNTLA1_WMASK));
+ IO_CNTLA1 = (IO_CNTLA1 & ~Z180_CNTLA1_WMASK) | (data & Z180_CNTLA1_WMASK);
+ break;
+
+ case Z180_CNTLB0:
+ LOG(("Z180 #%d CNTLB0 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_CNTLB0_WMASK));
+ IO_CNTLB0 = (IO_CNTLB0 & ~Z180_CNTLB0_WMASK) | (data & Z180_CNTLB0_WMASK);
+ break;
+
+ case Z180_CNTLB1:
+ LOG(("Z180 #%d CNTLB1 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_CNTLB1_WMASK));
+ IO_CNTLB1 = (IO_CNTLB1 & ~Z180_CNTLB1_WMASK) | (data & Z180_CNTLB1_WMASK);
+ break;
+
+ case Z180_STAT0:
+ LOG(("Z180 #%d STAT0 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_STAT0_WMASK));
+ IO_STAT0 = (IO_STAT0 & ~Z180_STAT0_WMASK) | (data & Z180_STAT0_WMASK);
+ break;
+
+ case Z180_STAT1:
+ LOG(("Z180 #%d STAT1 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_STAT1_WMASK));
+ IO_STAT1 = (IO_STAT1 & ~Z180_STAT1_WMASK) | (data & Z180_STAT1_WMASK);
+ break;
+
+ case Z180_TDR0:
+ LOG(("Z180 #%d TDR0 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_TDR0_WMASK));
+ IO_TDR0 = (IO_TDR0 & ~Z180_TDR0_WMASK) | (data & Z180_TDR0_WMASK);
+ break;
+
+ case Z180_TDR1:
+ LOG(("Z180 #%d TDR1 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_TDR1_WMASK));
+ IO_TDR1 = (IO_TDR1 & ~Z180_TDR1_WMASK) | (data & Z180_TDR1_WMASK);
+ break;
+
+ case Z180_RDR0:
+ LOG(("Z180 #%d RDR0 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_RDR0_WMASK));
+ IO_RDR0 = (IO_RDR0 & ~Z180_RDR0_WMASK) | (data & Z180_RDR0_WMASK);
+ break;
+
+ case Z180_RDR1:
+ LOG(("Z180 #%d RDR1 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_RDR1_WMASK));
+ IO_RDR1 = (IO_RDR1 & ~Z180_RDR1_WMASK) | (data & Z180_RDR1_WMASK);
+ break;
+
+ case Z180_CNTR:
+ LOG(("Z180 #%d CNTR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_CNTR_WMASK));
+ IO_CNTR = (IO_CNTR & ~Z180_CNTR_WMASK) | (data & Z180_CNTR_WMASK);
+ break;
+
+ case Z180_TRDR:
+ LOG(("Z180 #%d TRDR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_TRDR_WMASK));
+ IO_TRDR = (IO_TRDR & ~Z180_TRDR_WMASK) | (data & Z180_TRDR_WMASK);
+ break;
+
+ case Z180_TMDR0L:
+ LOG(("Z180 #%d TMDR0L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_TMDR0L_WMASK));
+ IO_TMDR0L = data & Z180_TMDR0L_WMASK;
+ Z180.tmdr_value[0] = (Z180.tmdr_value[0] & 0xff00) | IO_TMDR0L;
+ break;
+
+ case Z180_TMDR0H:
+ LOG(("Z180 #%d TMDR0H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_TMDR0H_WMASK));
+ IO_TMDR0H = data & Z180_TMDR0H_WMASK;
+ Z180.tmdr_value[0] = (Z180.tmdr_value[0] & 0x00ff) | (IO_TMDR0H << 8);
+ break;
+
+ case Z180_RLDR0L:
+ LOG(("Z180 #%d RLDR0L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_RLDR0L_WMASK));
+ IO_RLDR0L = (IO_RLDR0L & ~Z180_RLDR0L_WMASK) | (data & Z180_RLDR0L_WMASK);
+ break;
+
+ case Z180_RLDR0H:
+ LOG(("Z180 #%d RLDR0H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_RLDR0H_WMASK));
+ IO_RLDR0H = (IO_RLDR0H & ~Z180_RLDR0H_WMASK) | (data & Z180_RLDR0H_WMASK);
+ break;
+
+ case Z180_TCR:
+ LOG(("Z180 #%d TCR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_TCR_WMASK));
+ IO_TCR = (IO_TCR & ~Z180_TCR_WMASK) | (data & Z180_TCR_WMASK);
+ break;
+
+ case Z180_IO11:
+ LOG(("Z180 #%d IO11 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IO11_WMASK));
+ IO_IO11 = (IO_IO11 & ~Z180_IO11_WMASK) | (data & Z180_IO11_WMASK);
+ break;
+
+ case Z180_ASEXT0:
+ LOG(("Z180 #%d ASEXT0 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_ASEXT0_WMASK));
+ IO_ASEXT0 = (IO_ASEXT0 & ~Z180_ASEXT0_WMASK) | (data & Z180_ASEXT0_WMASK);
+ break;
+
+ case Z180_ASEXT1:
+ LOG(("Z180 #%d ASEXT1 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_ASEXT1_WMASK));
+ IO_ASEXT1 = (IO_ASEXT1 & ~Z180_ASEXT1_WMASK) | (data & Z180_ASEXT1_WMASK);
+ break;
+
+ case Z180_TMDR1L:
+ LOG(("Z180 #%d TMDR1L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_TMDR1L_WMASK));
+ IO_TMDR1L = data & Z180_TMDR1L_WMASK;
+ Z180.tmdr_value[1] = (Z180.tmdr_value[1] & 0xff00) | IO_TMDR1L;
+ break;
+
+ case Z180_TMDR1H:
+ LOG(("Z180 #%d TMDR1H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_TMDR1H_WMASK));
+ IO_TMDR1H = data & Z180_TMDR1H_WMASK;
+ Z180.tmdr_value[1] = (Z180.tmdr_value[1] & 0x00ff) | IO_TMDR1H;
+ break;
+
+ case Z180_RLDR1L:
+ LOG(("Z180 #%d RLDR1L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_RLDR1L_WMASK));
+ IO_RLDR1L = (IO_RLDR1L & ~Z180_RLDR1L_WMASK) | (data & Z180_RLDR1L_WMASK);
+ break;
+
+ case Z180_RLDR1H:
+ LOG(("Z180 #%d RLDR1H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_RLDR1H_WMASK));
+ IO_RLDR1H = (IO_RLDR1H & ~Z180_RLDR1H_WMASK) | (data & Z180_RLDR1H_WMASK);
+ break;
+
+ case Z180_FRC:
+ LOG(("Z180 #%d FRC wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_FRC_WMASK));
+ IO_FRC = (IO_FRC & ~Z180_FRC_WMASK) | (data & Z180_FRC_WMASK);
+ break;
+
+ case Z180_IO19:
+ LOG(("Z180 #%d IO19 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IO19_WMASK));
+ IO_IO19 = (IO_IO19 & ~Z180_IO19_WMASK) | (data & Z180_IO19_WMASK);
+ break;
+
+ case Z180_ASTC0L:
+ LOG(("Z180 #%d ASTC0L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_ASTC0L_WMASK));
+ IO_ASTC0L = (IO_ASTC0L & ~Z180_ASTC0L_WMASK) | (data & Z180_ASTC0L_WMASK);
+ break;
+
+ case Z180_ASTC0H:
+ LOG(("Z180 #%d ASTC0H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_ASTC0H_WMASK));
+ IO_ASTC0H = (IO_ASTC0H & ~Z180_ASTC0H_WMASK) | (data & Z180_ASTC0H_WMASK);
+ break;
+
+ case Z180_ASTC1L:
+ LOG(("Z180 #%d ASTC1L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_ASTC1L_WMASK));
+ IO_ASTC1L = (IO_ASTC1L & ~Z180_ASTC1L_WMASK) | (data & Z180_ASTC1L_WMASK);
+ break;
+
+ case Z180_ASTC1H:
+ LOG(("Z180 #%d ASTC1H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_ASTC1H_WMASK));
+ IO_ASTC1H = (IO_ASTC1H & ~Z180_ASTC1H_WMASK) | (data & Z180_ASTC1H_WMASK);
+ break;
+
+ case Z180_CMR:
+ LOG(("Z180 #%d CMR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_CMR_WMASK));
+ IO_CMR = (IO_CMR & ~Z180_CMR_WMASK) | (data & Z180_CMR_WMASK);
+ break;
+
+ case Z180_CCR:
+ LOG(("Z180 #%d CCR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_CCR_WMASK));
+ IO_CCR = (IO_CCR & ~Z180_CCR_WMASK) | (data & Z180_CCR_WMASK);
+ break;
+
+ case Z180_SAR0L:
+ LOG(("Z180 #%d SAR0L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_SAR0L_WMASK));
+ IO_SAR0L = (IO_SAR0L & ~Z180_SAR0L_WMASK) | (data & Z180_SAR0L_WMASK);
+ break;
+
+ case Z180_SAR0H:
+ LOG(("Z180 #%d SAR0H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_SAR0H_WMASK));
+ IO_SAR0H = (IO_SAR0H & ~Z180_SAR0H_WMASK) | (data & Z180_SAR0H_WMASK);
+ break;
+
+ case Z180_SAR0B:
+ LOG(("Z180 #%d SAR0B wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_SAR0B_WMASK));
+ IO_SAR0B = (IO_SAR0B & ~Z180_SAR0B_WMASK) | (data & Z180_SAR0B_WMASK);
+ break;
+
+ case Z180_DAR0L:
+ LOG(("Z180 #%d DAR0L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_DAR0L_WMASK));
+ IO_DAR0L = (IO_DAR0L & ~Z180_DAR0L_WMASK) | (data & Z180_DAR0L_WMASK);
+ break;
+
+ case Z180_DAR0H:
+ LOG(("Z180 #%d DAR0H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_DAR0H_WMASK));
+ IO_DAR0H = (IO_DAR0H & ~Z180_DAR0H_WMASK) | (data & Z180_DAR0H_WMASK);
+ break;
+
+ case Z180_DAR0B:
+ LOG(("Z180 #%d DAR0B wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_DAR0B_WMASK));
+ IO_DAR0B = (IO_DAR0B & ~Z180_DAR0B_WMASK) | (data & Z180_DAR0B_WMASK);
+ break;
+
+ case Z180_BCR0L:
+ LOG(("Z180 #%d BCR0L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_BCR0L_WMASK));
+ IO_BCR0L = (IO_BCR0L & ~Z180_BCR0L_WMASK) | (data & Z180_BCR0L_WMASK);
+ break;
+
+ case Z180_BCR0H:
+ LOG(("Z180 #%d BCR0H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_BCR0H_WMASK));
+ IO_BCR0H = (IO_BCR0H & ~Z180_BCR0H_WMASK) | (data & Z180_BCR0H_WMASK);
+ break;
+
+ case Z180_MAR1L:
+ LOG(("Z180 #%d MAR1L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_MAR1L_WMASK));
+ IO_MAR1L = (IO_MAR1L & ~Z180_MAR1L_WMASK) | (data & Z180_MAR1L_WMASK);
+ break;
+
+ case Z180_MAR1H:
+ LOG(("Z180 #%d MAR1H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_MAR1H_WMASK));
+ IO_MAR1H = (IO_MAR1H & ~Z180_MAR1H_WMASK) | (data & Z180_MAR1H_WMASK);
+ break;
+
+ case Z180_MAR1B:
+ LOG(("Z180 #%d MAR1B wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_MAR1B_WMASK));
+ IO_MAR1B = (IO_MAR1B & ~Z180_MAR1B_WMASK) | (data & Z180_MAR1B_WMASK);
+ break;
+
+ case Z180_IAR1L:
+ LOG(("Z180 #%d IAR1L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IAR1L_WMASK));
+ IO_IAR1L = (IO_IAR1L & ~Z180_IAR1L_WMASK) | (data & Z180_IAR1L_WMASK);
+ break;
+
+ case Z180_IAR1H:
+ LOG(("Z180 #%d IAR1H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IAR1H_WMASK));
+ IO_IAR1H = (IO_IAR1H & ~Z180_IAR1H_WMASK) | (data & Z180_IAR1H_WMASK);
+ break;
+
+ case Z180_IAR1B:
+ LOG(("Z180 #%d IAR1B wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IAR1B_WMASK));
+ IO_IAR1B = (IO_IAR1B & ~Z180_IAR1B_WMASK) | (data & Z180_IAR1B_WMASK);
+ break;
+
+ case Z180_BCR1L:
+ LOG(("Z180 #%d BCR1L wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_BCR1L_WMASK));
+ IO_BCR1L = (IO_BCR1L & ~Z180_BCR1L_WMASK) | (data & Z180_BCR1L_WMASK);
+ break;
+
+ case Z180_BCR1H:
+ LOG(("Z180 #%d BCR1H wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_BCR1H_WMASK));
+ IO_BCR1H = (IO_BCR1H & ~Z180_BCR1H_WMASK) | (data & Z180_BCR1H_WMASK);
+ break;
+
+ case Z180_DSTAT:
+ LOG(("Z180 #%d DSTAT wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_DSTAT_WMASK));
+ IO_DSTAT = (IO_DSTAT & ~Z180_DSTAT_WMASK) | (data & Z180_DSTAT_WMASK);
+ if ((data & (Z180_DSTAT_DE1 | Z180_DSTAT_DWE1)) == Z180_DSTAT_DE1)
+ IO_DSTAT |= Z180_DSTAT_DME; /* DMA enable */
+ if ((data & (Z180_DSTAT_DE0 | Z180_DSTAT_DWE0)) == Z180_DSTAT_DE0)
+ IO_DSTAT |= Z180_DSTAT_DME; /* DMA enable */
+ break;
+
+ case Z180_DMODE:
+ LOG(("Z180 #%d DMODE wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_DMODE_WMASK));
+ IO_DMODE = (IO_DMODE & ~Z180_DMODE_WMASK) | (data & Z180_DMODE_WMASK);
+ break;
+
+ case Z180_DCNTL:
+ LOG(("Z180 #%d DCNTL wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_DCNTL_WMASK));
+ IO_DCNTL = (IO_DCNTL & ~Z180_DCNTL_WMASK) | (data & Z180_DCNTL_WMASK);
+ break;
+
+ case Z180_IL:
+ LOG(("Z180 #%d IL wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IL_WMASK));
+ IO_IL = (IO_IL & ~Z180_IL_WMASK) | (data & Z180_IL_WMASK);
+ break;
+
+ case Z180_ITC:
+ LOG(("Z180 #%d ITC wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_ITC_WMASK));
+ IO_ITC = (IO_ITC & ~Z180_ITC_WMASK) | (data & Z180_ITC_WMASK);
+ break;
+
+ case Z180_IO35:
+ LOG(("Z180 #%d IO35 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IO35_WMASK));
+ IO_IO35 = (IO_IO35 & ~Z180_IO35_WMASK) | (data & Z180_IO35_WMASK);
+ break;
+
+ case Z180_RCR:
+ LOG(("Z180 #%d RCR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_RCR_WMASK));
+ IO_RCR = (IO_RCR & ~Z180_RCR_WMASK) | (data & Z180_RCR_WMASK);
+ break;
+
+ case Z180_IO37:
+ LOG(("Z180 #%d IO37 wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IO37_WMASK));
+ IO_IO37 = (IO_IO37 & ~Z180_IO37_WMASK) | (data & Z180_IO37_WMASK);
+ break;
+
+ case Z180_CBR:
+ LOG(("Z180 #%d CBR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_CBR_WMASK));
+ IO_CBR = (IO_CBR & ~Z180_CBR_WMASK) | (data & Z180_CBR_WMASK);
+ z180_mmu();
+ break;
+
+ case Z180_BBR:
+ LOG(("Z180 #%d BBR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_BBR_WMASK));
+ IO_BBR = (IO_BBR & ~Z180_BBR_WMASK) | (data & Z180_BBR_WMASK);
+ z180_mmu();
+ break;
+
+ case Z180_CBAR:
+ LOG(("Z180 #%d CBAR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_CBAR_WMASK));
+ IO_CBAR = (IO_CBAR & ~Z180_CBAR_WMASK) | (data & Z180_CBAR_WMASK);
+ z180_mmu();
+ break;
+
+ case Z180_IO3B:
+ LOG(("Z180 #%d IO3B wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IO3B_WMASK));
+ IO_IO3B = (IO_IO3B & ~Z180_IO3B_WMASK) | (data & Z180_IO3B_WMASK);
+ break;
+
+ case Z180_IO3C:
+ LOG(("Z180 #%d IO3C wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IO3C_WMASK));
+ IO_IO3C = (IO_IO3C & ~Z180_IO3C_WMASK) | (data & Z180_IO3C_WMASK);
+ break;
+
+ case Z180_IO3D:
+ LOG(("Z180 #%d IO3D wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IO3D_WMASK));
+ IO_IO3D = (IO_IO3D & ~Z180_IO3D_WMASK) | (data & Z180_IO3D_WMASK);
+ break;
+
+ case Z180_OMCR:
+ LOG(("Z180 #%d OMCR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_OMCR_WMASK));
+ IO_OMCR = (IO_OMCR & ~Z180_OMCR_WMASK) | (data & Z180_OMCR_WMASK);
+ break;
+
+ case Z180_IOCR:
+ LOG(("Z180 #%d IOCR wr $%02x ($%02x)\n", cpu_getactivecpu(), data, data & Z180_IOCR_WMASK));
+ IO_IOCR = (IO_IOCR & ~Z180_IOCR_WMASK) | (data & Z180_IOCR_WMASK);
+ break;
+ }
+}
+
+static void z180_dma0(void)
+{
+ offs_t sar0 = 65536 * IO_SAR0B + 256 * IO_SAR0H + IO_SAR0L;
+ offs_t dar0 = 65536 * IO_DAR0B + 256 * IO_DAR0H + IO_DAR0L;
+ int bcr0 = 256 * IO_BCR0H + IO_BCR0L;
+ int count = (IO_DMODE & Z180_DMODE_MMOD) ? bcr0 : 1;
+
+ if (bcr0 == 0)
+ {
+ IO_DSTAT &= ~Z180_DSTAT_DE0;
+ return;
+ }
+
+ while (count-- > 0)
+ {
+ /* last transfer happening now? */
+ if (bcr0 == 1)
+ {
+ Z180.iol |= Z180_TEND0;
+ }
+ switch( IO_DMODE & (Z180_DMODE_SM | Z180_DMODE_DM) )
+ {
+ case 0x00: /* memory SAR0+1 to memory DAR0+1 */
+ program_write_byte_8(dar0++, program_read_byte_8(sar0++));
+ break;
+ case 0x04: /* memory SAR0-1 to memory DAR0+1 */
+ program_write_byte_8(dar0++, program_read_byte_8(sar0--));
+ break;
+ case 0x08: /* memory SAR0 fixed to memory DAR0+1 */
+ program_write_byte_8(dar0++, program_read_byte_8(sar0));
+ break;
+ case 0x0c: /* I/O SAR0 fixed to memory DAR0+1 */
+ if (Z180.iol & Z180_DREQ0)
+ {
+ program_write_byte_8(dar0++, IN(sar0));
+ /* edge sensitive DREQ0 ? */
+ if (IO_DCNTL & Z180_DCNTL_DIM0)
+ {
+ Z180.iol &= ~Z180_DREQ0;
+ count = 0;
+ }
+ }
+ break;
+ case 0x10: /* memory SAR0+1 to memory DAR0-1 */
+ program_write_byte_8(dar0--, program_read_byte_8(sar0++));
+ break;
+ case 0x14: /* memory SAR0-1 to memory DAR0-1 */
+ program_write_byte_8(dar0--, program_read_byte_8(sar0--));
+ break;
+ case 0x18: /* memory SAR0 fixed to memory DAR0-1 */
+ program_write_byte_8(dar0--, program_read_byte_8(sar0));
+ break;
+ case 0x1c: /* I/O SAR0 fixed to memory DAR0-1 */
+ if (Z180.iol & Z180_DREQ0)
+ {
+ program_write_byte_8(dar0--, IN(sar0));
+ /* edge sensitive DREQ0 ? */
+ if (IO_DCNTL & Z180_DCNTL_DIM0)
+ {
+ Z180.iol &= ~Z180_DREQ0;
+ count = 0;
+ }
+ }
+ break;
+ case 0x20: /* memory SAR0+1 to memory DAR0 fixed */
+ program_write_byte_8(dar0, program_read_byte_8(sar0++));
+ break;
+ case 0x24: /* memory SAR0-1 to memory DAR0 fixed */
+ program_write_byte_8(dar0, program_read_byte_8(sar0--));
+ break;
+ case 0x28: /* reserved */
+ break;
+ case 0x2c: /* reserved */
+ break;
+ case 0x30: /* memory SAR0+1 to I/O DAR0 fixed */
+ if (Z180.iol & Z180_DREQ0)
+ {
+ OUT(dar0, program_read_byte_8(sar0++));
+ /* edge sensitive DREQ0 ? */
+ if (IO_DCNTL & Z180_DCNTL_DIM0)
+ {
+ Z180.iol &= ~Z180_DREQ0;
+ count = 0;
+ }
+ }
+ break;
+ case 0x34: /* memory SAR0-1 to I/O DAR0 fixed */
+ if (Z180.iol & Z180_DREQ0)
+ {
+ OUT(dar0, program_read_byte_8(sar0--));
+ /* edge sensitive DREQ0 ? */
+ if (IO_DCNTL & Z180_DCNTL_DIM0)
+ {
+ Z180.iol &= ~Z180_DREQ0;
+ count = 0;
+ }
+ }
+ break;
+ case 0x38: /* reserved */
+ break;
+ case 0x3c: /* reserved */
+ break;
+ }
+ bcr0--;
+ count--;
+ if ((z180_icount -= 6) < 0)
+ break;
+ }
+
+ IO_SAR0L = sar0;
+ IO_SAR0H = sar0 >> 8;
+ IO_SAR0B = sar0 >> 16;
+ IO_DAR0L = dar0;
+ IO_DAR0H = dar0 >> 8;
+ IO_DAR0B = dar0 >> 16;
+ IO_BCR0L = bcr0;
+ IO_BCR0H = bcr0 >> 8;
+
+ /* DMA terminal count? */
+ if (bcr0 == 0)
+ {
+ Z180.iol &= ~Z180_TEND0;
+ IO_DSTAT &= ~Z180_DSTAT_DE0;
+ /* terminal count interrupt enabled? */
+ if (IO_DSTAT & Z180_DSTAT_DIE0 && _IFF1)
+ take_interrupt(Z180_INT_DMA0);
+ }
+}
+
+static void z180_dma1(void)
+{
+ offs_t mar1 = 65536 * IO_MAR1B + 256 * IO_MAR1H + IO_MAR1L;
+ offs_t iar1 = 256 * IO_IAR1H + IO_IAR1L;
+ int bcr1 = 256 * IO_BCR1H + IO_BCR1L;
+
+ if ((Z180.iol & Z180_DREQ1) == 0)
+ return;
+
+ /* counter is zero? */
+ if (bcr1 == 0)
+ {
+ IO_DSTAT &= ~Z180_DSTAT_DE1;
+ return;
+ }
+
+ /* last transfer happening now? */
+ if (bcr1 == 1)
+ {
+ Z180.iol |= Z180_TEND1;
+ }
+
+ switch (IO_DCNTL & (Z180_DCNTL_DIM1 | Z180_DCNTL_DIM0))
+ {
+ case 0x00: /* memory MAR1+1 to I/O IAR1 fixed */
+ io_write_byte_8(iar1, program_read_byte_8(mar1++));
+ break;
+ case 0x01: /* memory MAR1-1 to I/O IAR1 fixed */
+ io_write_byte_8(iar1, program_read_byte_8(mar1--));
+ break;
+ case 0x02: /* I/O IAR1 fixed to memory MAR1+1 */
+ program_write_byte_8(mar1++, io_read_byte_8(iar1));
+ break;
+ case 0x03: /* I/O IAR1 fixed to memory MAR1-1 */
+ program_write_byte_8(mar1--, io_read_byte_8(iar1));
+ break;
+ }
+
+ /* edge sensitive DREQ1 ? */
+ if (IO_DCNTL & Z180_DCNTL_DIM1)
+ Z180.iol &= ~Z180_DREQ1;
+
+ IO_MAR1L = mar1;
+ IO_MAR1H = mar1 >> 8;
+ IO_MAR1B = mar1 >> 16;
+ IO_BCR1L = bcr1;
+ IO_BCR1H = bcr1 >> 8;
+
+ /* DMA terminal count? */
+ if (bcr1 == 0)
+ {
+ Z180.iol &= ~Z180_TEND1;
+ IO_DSTAT &= ~Z180_DSTAT_DE1;
+ if (IO_DSTAT & Z180_DSTAT_DIE1 && _IFF1)
+ take_interrupt(Z180_INT_DMA1);
+ }
+
+ /* six cycles per transfer (minimum) */
+ z180_icount -= 6;
+}
+
+static void z180_write_iolines(UINT32 data)
+{
+ UINT32 changes = Z180.iol ^ data;
+
+ /* I/O asynchronous clock 0 (active high) or DREQ0 (mux) */
+ if (changes & Z180_CKA0)
+ {
+ LOG(("Z180 #%d CKA0 %d\n", cpu_getactivecpu(), data & Z180_CKA0 ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_CKA0) | (data & Z180_CKA0);
+ }
+
+ /* I/O asynchronous clock 1 (active high) or TEND1 (mux) */
+ if (changes & Z180_CKA1)
+ {
+ LOG(("Z180 #%d CKA1 %d\n", cpu_getactivecpu(), data & Z180_CKA1 ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_CKA1) | (data & Z180_CKA1);
+ }
+
+ /* I/O serial clock (active high) */
+ if (changes & Z180_CKS)
+ {
+ LOG(("Z180 #%d CKS %d\n", cpu_getactivecpu(), data & Z180_CKS ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_CKS) | (data & Z180_CKS);
+ }
+
+ /* I clear to send 0 (active low) */
+ if (changes & Z180_CTS0)
+ {
+ LOG(("Z180 #%d CTS0 %d\n", cpu_getactivecpu(), data & Z180_CTS0 ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_CTS0) | (data & Z180_CTS0);
+ }
+
+ /* I clear to send 1 (active low) or RXS (mux) */
+ if (changes & Z180_CTS1)
+ {
+ LOG(("Z180 #%d CTS1 %d\n", cpu_getactivecpu(), data & Z180_CTS1 ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_CTS1) | (data & Z180_CTS1);
+ }
+
+ /* I data carrier detect (active low) */
+ if (changes & Z180_DCD0)
+ {
+ LOG(("Z180 #%d DCD0 %d\n", cpu_getactivecpu(), data & Z180_DCD0 ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_DCD0) | (data & Z180_DCD0);
+ }
+
+ /* I data request DMA ch 0 (active low) or CKA0 (mux) */
+ if (changes & Z180_DREQ0)
+ {
+ LOG(("Z180 #%d DREQ0 %d\n", cpu_getactivecpu(), data & Z180_DREQ0 ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_DREQ0) | (data & Z180_DREQ0);
+ }
+
+ /* I data request DMA ch 1 (active low) */
+ if (changes & Z180_DREQ1)
+ {
+ LOG(("Z180 #%d DREQ1 %d\n", cpu_getactivecpu(), data & Z180_DREQ1 ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_DREQ1) | (data & Z180_DREQ1);
+ }
+
+ /* I asynchronous receive data 0 (active high) */
+ if (changes & Z180_RXA0)
+ {
+ LOG(("Z180 #%d RXA0 %d\n", cpu_getactivecpu(), data & Z180_RXA0 ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_RXA0) | (data & Z180_RXA0);
+ }
+
+ /* I asynchronous receive data 1 (active high) */
+ if (changes & Z180_RXA1)
+ {
+ LOG(("Z180 #%d RXA1 %d\n", cpu_getactivecpu(), data & Z180_RXA1 ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_RXA1) | (data & Z180_RXA1);
+ }
+
+ /* I clocked serial receive data (active high) or CTS1 (mux) */
+ if (changes & Z180_RXS)
+ {
+ LOG(("Z180 #%d RXS %d\n", cpu_getactivecpu(), data & Z180_RXS ? 1 : 0));
+ Z180.iol = (Z180.iol & ~Z180_RXS) | (data & Z180_RXS);
+ }
+
+ /* O request to send (active low) */
+ if (changes & Z180_RTS0)
+ {
+ LOG(("Z180 #%d RTS0 won't change output\n", cpu_getactivecpu()));
+ }
+
+ /* O transfer end 0 (active low) or CKA1 (mux) */
+ if (changes & Z180_TEND0)
+ {
+ LOG(("Z180 #%d TEND0 won't change output\n", cpu_getactivecpu()));
+ }
+
+ /* O transfer end 1 (active low) */
+ if (changes & Z180_TEND1)
+ {
+ LOG(("Z180 #%d TEND1 won't change output\n", cpu_getactivecpu()));
+ }
+
+ /* O transfer out (PRT channel, active low) or A18 (mux) */
+ if (changes & Z180_A18_TOUT)
+ {
+ LOG(("Z180 #%d TOUT won't change output\n", cpu_getactivecpu()));
+ }
+
+ /* O asynchronous transmit data 0 (active high) */
+ if (changes & Z180_TXA0)
+ {
+ LOG(("Z180 #%d TXA0 won't change output\n", cpu_getactivecpu()));
+ }
+
+ /* O asynchronous transmit data 1 (active high) */
+ if (changes & Z180_TXA1)
+ {
+ LOG(("Z180 #%d TXA1 won't change output\n", cpu_getactivecpu()));
+ }
+
+ /* O clocked serial transmit data (active high) */
+ if (changes & Z180_TXS)
+ {
+ LOG(("Z180 #%d TXS won't change output\n", cpu_getactivecpu()));
+ }
+}
+
+
+static void z180_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ Z180.daisy = config;
+ Z180.irq_callback = irqcallback;
+
+ state_save_register_item("z180", index, Z180.AF.w.l);
+ state_save_register_item("z180", index, Z180.BC.w.l);
+ state_save_register_item("z180", index, Z180.DE.w.l);
+ state_save_register_item("z180", index, Z180.HL.w.l);
+ state_save_register_item("z180", index, Z180.IX.w.l);
+ state_save_register_item("z180", index, Z180.IY.w.l);
+ state_save_register_item("z180", index, Z180.PC.w.l);
+ state_save_register_item("z180", index, Z180.SP.w.l);
+ state_save_register_item("z180", index, Z180.AF2.w.l);
+ state_save_register_item("z180", index, Z180.BC2.w.l);
+ state_save_register_item("z180", index, Z180.DE2.w.l);
+ state_save_register_item("z180", index, Z180.HL2.w.l);
+ state_save_register_item("z180", index, Z180.R);
+ state_save_register_item("z180", index, Z180.R2);
+ state_save_register_item("z180", index, Z180.IFF1);
+ state_save_register_item("z180", index, Z180.IFF2);
+ state_save_register_item("z180", index, Z180.HALT);
+ state_save_register_item("z180", index, Z180.IM);
+ state_save_register_item("z180", index, Z180.I);
+ state_save_register_item("z180", index, Z180.nmi_state);
+ state_save_register_item("z180", index, Z180.nmi_pending);
+ state_save_register_item("z180", index, Z180.irq_state[0]);
+ state_save_register_item("z180", index, Z180.irq_state[1]);
+ state_save_register_item("z180", index, Z180.irq_state[2]);
+ state_save_register_item("z180", index, Z180.after_EI);
+}
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+static void z180_reset(void)
+{
+ const struct z80_irq_daisy_chain *save_daisy;
+ int (*save_irqcallback)(int);
+ int i, p;
+#if BIG_FLAGS_ARRAY
+ if( !SZHVC_add || !SZHVC_sub )
+ {
+ int oldval, newval, val;
+ UINT8 *padd, *padc, *psub, *psbc;
+ /* allocate big flag arrays once */
+ SZHVC_add = (UINT8 *)auto_malloc(2*256*256);
+ SZHVC_sub = (UINT8 *)auto_malloc(2*256*256);
+ padd = &SZHVC_add[ 0*256];
+ padc = &SZHVC_add[256*256];
+ psub = &SZHVC_sub[ 0*256];
+ psbc = &SZHVC_sub[256*256];
+ for (oldval = 0; oldval < 256; oldval++)
+ {
+ for (newval = 0; newval < 256; newval++)
+ {
+ /* add or adc w/o carry set */
+ val = newval - oldval;
+ *padd = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
+#if Z180_EXACT
+ *padd |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
+#endif
+ if( (newval & 0x0f) < (oldval & 0x0f) ) *padd |= HF;
+ if( newval < oldval ) *padd |= CF;
+ if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padd |= VF;
+ padd++;
+
+ /* adc with carry set */
+ val = newval - oldval - 1;
+ *padc = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
+#if Z180_EXACT
+ *padc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
+#endif
+ if( (newval & 0x0f) <= (oldval & 0x0f) ) *padc |= HF;
+ if( newval <= oldval ) *padc |= CF;
+ if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padc |= VF;
+ padc++;
+
+ /* cp, sub or sbc w/o carry set */
+ val = oldval - newval;
+ *psub = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
+#if Z180_EXACT
+ *psub |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
+#endif
+ if( (newval & 0x0f) > (oldval & 0x0f) ) *psub |= HF;
+ if( newval > oldval ) *psub |= CF;
+ if( (val^oldval) & (oldval^newval) & 0x80 ) *psub |= VF;
+ psub++;
+
+ /* sbc with carry set */
+ val = oldval - newval - 1;
+ *psbc = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
+#if Z180_EXACT
+ *psbc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
+#endif
+ if( (newval & 0x0f) >= (oldval & 0x0f) ) *psbc |= HF;
+ if( newval >= oldval ) *psbc |= CF;
+ if( (val^oldval) & (oldval^newval) & 0x80 ) *psbc |= VF;
+ psbc++;
+ }
+ }
+ }
+#endif
+ for (i = 0; i < 256; i++)
+ {
+ p = 0;
+ if( i&0x01 ) ++p;
+ if( i&0x02 ) ++p;
+ if( i&0x04 ) ++p;
+ if( i&0x08 ) ++p;
+ if( i&0x10 ) ++p;
+ if( i&0x20 ) ++p;
+ if( i&0x40 ) ++p;
+ if( i&0x80 ) ++p;
+ SZ[i] = i ? i & SF : ZF;
+#if Z180_EXACT
+ SZ[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */
+#endif
+ SZ_BIT[i] = i ? i & SF : ZF | PF;
+#if Z180_EXACT
+ SZ_BIT[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */
+#endif
+ SZP[i] = SZ[i] | ((p & 1) ? 0 : PF);
+ SZHV_inc[i] = SZ[i];
+ if( i == 0x80 ) SZHV_inc[i] |= VF;
+ if( (i & 0x0f) == 0x00 ) SZHV_inc[i] |= HF;
+ SZHV_dec[i] = SZ[i] | NF;
+ if( i == 0x7f ) SZHV_dec[i] |= VF;
+ if( (i & 0x0f) == 0x0f ) SZHV_dec[i] |= HF;
+ }
+
+ save_daisy = Z180.daisy;
+ save_irqcallback = Z180.irq_callback;
+ memset(&Z180, 0, sizeof(Z180));
+ Z180.daisy = save_daisy;
+ Z180.irq_callback = save_irqcallback;
+ _IX = _IY = 0xffff; /* IX and IY are FFFF after a reset! */
+ _F = ZF; /* Zero flag is set */
+ Z180.nmi_state = CLEAR_LINE;
+ Z180.nmi_pending = 0;
+ Z180.irq_state[0] = CLEAR_LINE;
+ Z180.irq_state[1] = CLEAR_LINE;
+ Z180.irq_state[2] = CLEAR_LINE;
+ Z180.after_EI = 0;
+ Z180.tif[0] = 0;
+ Z180.tif[1] = 0;
+ Z180.read_tcr_tmdr[0] = 0;
+ Z180.read_tcr_tmdr[1] = 0;
+ Z180.tmdr_value[0] = 0xffff;
+ Z180.tmdr_value[1] = 0xffff;
+
+ /* reset io registers */
+ IO_CNTLA0 = Z180_CNTLA0_RESET;
+ IO_CNTLA1 = Z180_CNTLA1_RESET;
+ IO_CNTLB0 = Z180_CNTLB0_RESET;
+ IO_CNTLB1 = Z180_CNTLB1_RESET;
+ IO_STAT0 = Z180_STAT0_RESET;
+ IO_STAT1 = Z180_STAT1_RESET;
+ IO_TDR0 = Z180_TDR0_RESET;
+ IO_TDR1 = Z180_TDR1_RESET;
+ IO_RDR0 = Z180_RDR0_RESET;
+ IO_RDR1 = Z180_RDR1_RESET;
+ IO_CNTR = Z180_CNTR_RESET;
+ IO_TRDR = Z180_TRDR_RESET;
+ IO_TMDR0L = Z180_TMDR0L_RESET;
+ IO_TMDR0H = Z180_TMDR0H_RESET;
+ IO_RLDR0L = Z180_RLDR0L_RESET;
+ IO_RLDR0H = Z180_RLDR0H_RESET;
+ IO_TCR = Z180_TCR_RESET;
+ IO_IO11 = Z180_IO11_RESET;
+ IO_ASEXT0 = Z180_ASEXT0_RESET;
+ IO_ASEXT1 = Z180_ASEXT1_RESET;
+ IO_TMDR1L = Z180_TMDR1L_RESET;
+ IO_TMDR1H = Z180_TMDR1H_RESET;
+ IO_RLDR1L = Z180_RLDR1L_RESET;
+ IO_RLDR1H = Z180_RLDR1H_RESET;
+ IO_FRC = Z180_FRC_RESET;
+ IO_IO19 = Z180_IO19_RESET;
+ IO_ASTC0L = Z180_ASTC0L_RESET;
+ IO_ASTC0H = Z180_ASTC0H_RESET;
+ IO_ASTC1L = Z180_ASTC1L_RESET;
+ IO_ASTC1H = Z180_ASTC1H_RESET;
+ IO_CMR = Z180_CMR_RESET;
+ IO_CCR = Z180_CCR_RESET;
+ IO_SAR0L = Z180_SAR0L_RESET;
+ IO_SAR0H = Z180_SAR0H_RESET;
+ IO_SAR0B = Z180_SAR0B_RESET;
+ IO_DAR0L = Z180_DAR0L_RESET;
+ IO_DAR0H = Z180_DAR0H_RESET;
+ IO_DAR0B = Z180_DAR0B_RESET;
+ IO_BCR0L = Z180_BCR0L_RESET;
+ IO_BCR0H = Z180_BCR0H_RESET;
+ IO_MAR1L = Z180_MAR1L_RESET;
+ IO_MAR1H = Z180_MAR1H_RESET;
+ IO_MAR1B = Z180_MAR1B_RESET;
+ IO_IAR1L = Z180_IAR1L_RESET;
+ IO_IAR1H = Z180_IAR1H_RESET;
+ IO_IAR1B = Z180_IAR1B_RESET;
+ IO_BCR1L = Z180_BCR1L_RESET;
+ IO_BCR1H = Z180_BCR1H_RESET;
+ IO_DSTAT = Z180_DSTAT_RESET;
+ IO_DMODE = Z180_DMODE_RESET;
+ IO_DCNTL = Z180_DCNTL_RESET;
+ IO_IL = Z180_IL_RESET;
+ IO_ITC = Z180_ITC_RESET;
+ IO_IO35 = Z180_IO35_RESET;
+ IO_RCR = Z180_RCR_RESET;
+ IO_IO37 = Z180_IO37_RESET;
+ IO_CBR = Z180_CBR_RESET;
+ IO_BBR = Z180_BBR_RESET;
+ IO_CBAR = Z180_CBAR_RESET;
+ IO_IO3B = Z180_IO3B_RESET;
+ IO_IO3C = Z180_IO3C_RESET;
+ IO_IO3D = Z180_IO3D_RESET;
+ IO_OMCR = Z180_OMCR_RESET;
+ IO_IOCR = Z180_IOCR_RESET;
+
+ if (Z180.daisy)
+ z80daisy_reset(Z180.daisy);
+ z180_mmu();
+ z180_change_pc(_PCD);
+}
+
+/* Handle PRT timers, decreasing them after 20 clocks and returning the new icount base that needs to be used for the next check */
+static int handle_timers(int current_icount, int previous_icount)
+{
+ int diff = previous_icount - current_icount;
+ int new_icount_base;
+
+ if(diff >= 20)
+ {
+ /* Programmable Reload Timer 0 */
+ if(IO_TCR & Z180_TCR_TDE0)
+ {
+ Z180.tmdr_value[0]--;
+ if(Z180.tmdr_value[0] == 0)
+ {
+ Z180.tmdr_value[0] = IO_RLDR0L | (IO_RLDR0H << 8);
+ Z180.tif[0] = 1;
+ }
+ }
+
+ /* Programmable Reload Timer 1 */
+ if(IO_TCR & Z180_TCR_TDE1)
+ {
+ Z180.tmdr_value[1]--;
+ if(Z180.tmdr_value[1] == 0)
+ {
+ Z180.tmdr_value[1] = IO_RLDR1L | (IO_RLDR1H << 8);
+ Z180.tif[1] = 1;
+ }
+ }
+
+ if((IO_TCR & Z180_TCR_TIE0) && Z180.tif[0])
+ {
+ // check if we can take the interrupt
+ if(_IFF1 && !Z180.after_EI)
+ {
+ take_interrupt(Z180_INT_PRT0);
+ }
+ }
+
+ if((IO_TCR & Z180_TCR_TIE1) && Z180.tif[1])
+ {
+ // check if we can take the interrupt
+ if(_IFF1 && !Z180.after_EI)
+ {
+ take_interrupt(Z180_INT_PRT1);
+ }
+ }
+
+ new_icount_base = current_icount + (diff - 20);
+ }
+ else
+ {
+ new_icount_base = previous_icount;
+ }
+
+ return new_icount_base;
+}
+
+static void check_interrupts(void)
+{
+ int i;
+ for(i = 0; i <= 2; i++)
+ {
+ /* check for IRQs before each instruction */
+ if(Z180.irq_state[i] != CLEAR_LINE && _IFF1 && !Z180.after_EI)
+ {
+ take_interrupt(Z180_INT0 + i);
+ }
+ }
+}
+
+/****************************************************************************
+ * Execute 'cycles' T-states. Return number of T-states really executed
+ ****************************************************************************/
+static int z180_execute(int cycles)
+{
+ int old_icount = cycles;
+ z180_icount = cycles;
+
+ /* check for NMIs on the way in; they can only be set externally */
+ /* via timers, and can't be dynamically enabled, so it is safe */
+ /* to just check here */
+ if (Z180.nmi_pending)
+ {
+ LOG(("Z180 #%d take NMI\n", cpu_getactivecpu()));
+ _PPC = -1; /* there isn't a valid previous program counter */
+ LEAVE_HALT; /* Check if processor was halted */
+
+ /* disable DMA transfers!! */
+ IO_DSTAT &= ~Z180_DSTAT_DME;
+
+ _IFF2 = _IFF1;
+ _IFF1 = 0;
+ PUSH( PC );
+ _PCD = 0x0066;
+ z180_icount -= 11;
+ Z180.nmi_pending = 0;
+ }
+
+again:
+ /* check if any DMA transfer is running */
+ if ((IO_DSTAT & Z180_DSTAT_DME) == Z180_DSTAT_DME)
+ {
+ /* check if DMA channel 0 is running and also is in burst mode */
+ if ((IO_DSTAT & Z180_DSTAT_DE0) == Z180_DSTAT_DE0 &&
+ (IO_DMODE & Z180_DMODE_MMOD) == Z180_DMODE_MMOD)
+ {
+ CALL_MAME_DEBUG;
+
+ z180_dma0();
+ old_icount = handle_timers(z180_icount, old_icount);
+ }
+ else
+ {
+ do
+ {
+ check_interrupts();
+ Z180.after_EI = 0;
+
+ _PPC = _PCD;
+ CALL_MAME_DEBUG;
+ _R++;
+
+ EXEC_INLINE(op,ROP());
+ old_icount = handle_timers(z180_icount, old_icount);
+
+ z180_dma0();
+ old_icount = handle_timers(z180_icount, old_icount);
+
+ z180_dma1();
+ old_icount = handle_timers(z180_icount, old_icount);
+
+ /* If DMA is done break out to the faster loop */
+ if ((IO_DSTAT & Z180_DSTAT_DME) != Z180_DSTAT_DME)
+ break;
+ } while( z180_icount > 0 );
+ }
+ }
+
+ if (z180_icount > 0)
+ {
+ do
+ {
+ check_interrupts();
+ Z180.after_EI = 0;
+
+ _PPC = _PCD;
+ CALL_MAME_DEBUG;
+ _R++;
+ EXEC_INLINE(op,ROP());
+ old_icount = handle_timers(z180_icount, old_icount);
+
+ /* If DMA is started go to check the mode */
+ if ((IO_DSTAT & Z180_DSTAT_DME) == Z180_DSTAT_DME)
+ goto again;
+ } while( z180_icount > 0 );
+ }
+
+ return cycles - z180_icount;
+}
+
+/****************************************************************************
+ * Burn 'cycles' T-states. Adjust R register for the lost time
+ ****************************************************************************/
+static void z180_burn(int cycles)
+{
+ if( cycles > 0 )
+ {
+ /* NOP takes 3 cycles per instruction */
+ int n = (cycles + 2) / 3;
+ _R += n;
+ z180_icount -= 3 * n;
+ }
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void z180_get_context (void *dst)
+{
+ if( dst )
+ *(Z180_Regs*)dst = Z180;
+}
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void z180_set_context (void *src)
+{
+ if( src )
+ Z180 = *(Z180_Regs*)src;
+ z180_change_pc(_PCD);
+}
+
+READ8_HANDLER( z180_internal_r )
+{
+ return Z180.io[offset & 0x3f];
+}
+
+WRITE8_HANDLER( z180_internal_w )
+{
+ cpuinfo info;
+ info.i = data;
+ z180_set_info( CPUINFO_INT_REGISTER + Z180_CNTLA0 + (offset & 0x3f), &info );
+}
+
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ /* mark an NMI pending on the rising edge */
+ if (Z180.nmi_state == CLEAR_LINE && state != CLEAR_LINE)
+ Z180.nmi_pending = 1;
+ Z180.nmi_state = state;
+ }
+ else
+ {
+ LOG(("Z180 #%d set_irq_line %d = %d\n",cpu_getactivecpu() , irqline,state));
+
+ /* update the IRQ state */
+ Z180.irq_state[irqline] = state;
+ if (Z180.daisy)
+ Z180.irq_state[0] = z80daisy_update_irq_state(Z180.daisy);
+
+ /* the main execute loop will take the interrupt */
+ }
+}
+
+/* logical to physical address translation */
+static int z180_translate(int space, offs_t *addr)
+{
+ if (space == ADDRESS_SPACE_PROGRAM)
+ {
+ *addr = MMU_REMAP_ADDR(*addr);
+ }
+ return 1;
+}
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void z180_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + Z180_INT0: set_irq_line(Z180_INT0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + Z180_INT1: set_irq_line(Z180_INT1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + Z180_INT2: set_irq_line(Z180_INT2, info->i); break;
+
+ case CPUINFO_INT_PC: _PC = info->i; z180_change_pc(_PCD); break;
+ case CPUINFO_INT_REGISTER + Z180_PC: Z180.PC.w.l = info->i; break;
+ case CPUINFO_INT_SP: _SP = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_SP: Z180.SP.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_AF: Z180.AF.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_BC: Z180.BC.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_DE: Z180.DE.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_HL: Z180.HL.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IX: Z180.IX.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IY: Z180.IY.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_R: Z180.R = info->i; Z180.R2 = info->i & 0x80; break;
+ case CPUINFO_INT_REGISTER + Z180_I: Z180.I = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_AF2: Z180.AF2.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_BC2: Z180.BC2.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_DE2: Z180.DE2.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_HL2: Z180.HL2.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IM: Z180.IM = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IFF1: Z180.IFF1 = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IFF2: Z180.IFF2 = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_HALT: Z180.HALT = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTLA0: Z180.io[0x00] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTLA1: Z180.io[0x01] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTLB0: Z180.io[0x02] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTLB1: Z180.io[0x03] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_STAT0: Z180.io[0x04] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_STAT1: Z180.io[0x05] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_TDR0: Z180.io[0x06] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_TDR1: Z180.io[0x07] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_RDR0: Z180.io[0x08] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_RDR1: Z180.io[0x09] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTR: Z180.io[0x0a] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_TRDR: Z180.io[0x0b] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_TMDR0L: Z180.io[0x0c] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_TMDR0H: Z180.io[0x0d] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_RLDR0L: Z180.io[0x0e] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_RLDR0H: Z180.io[0x0f] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_TCR: Z180.io[0x10] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IO11: Z180.io[0x11] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_ASEXT0: Z180.io[0x12] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_ASEXT1: Z180.io[0x13] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_TMDR1L: Z180.io[0x14] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_TMDR1H: Z180.io[0x15] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_RLDR1L: Z180.io[0x16] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_RLDR1H: Z180.io[0x17] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_FRC: Z180.io[0x18] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IO19: Z180.io[0x19] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_ASTC0L: Z180.io[0x1a] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_ASTC0H: Z180.io[0x1b] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_ASTC1L: Z180.io[0x1c] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_ASTC1H: Z180.io[0x1d] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_CMR: Z180.io[0x1e] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_CCR: Z180.io[0x1f] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_SAR0L: Z180.io[0x20] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_SAR0H: Z180.io[0x21] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_SAR0B: Z180.io[0x22] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_DAR0L: Z180.io[0x23] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_DAR0H: Z180.io[0x24] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_DAR0B: Z180.io[0x25] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_BCR0L: Z180.io[0x26] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_BCR0H: Z180.io[0x27] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_MAR1L: Z180.io[0x28] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_MAR1H: Z180.io[0x29] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_MAR1B: Z180.io[0x2a] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IAR1L: Z180.io[0x2b] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IAR1H: Z180.io[0x2c] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IAR1B: Z180.io[0x2d] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_BCR1L: Z180.io[0x2e] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_BCR1H: Z180.io[0x2f] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_DSTAT: Z180.io[0x30] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_DMODE: Z180.io[0x31] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_DCNTL: Z180.io[0x32] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IL: Z180.io[0x33] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_ITC: Z180.io[0x34] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IO35: Z180.io[0x35] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_RCR: Z180.io[0x36] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IO37: Z180.io[0x37] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_CBR: Z180.io[0x38] = info->i; z180_mmu(); break;
+ case CPUINFO_INT_REGISTER + Z180_BBR: Z180.io[0x39] = info->i; z180_mmu(); break;
+ case CPUINFO_INT_REGISTER + Z180_CBAR: Z180.io[0x3a] = info->i; z180_mmu(); break;
+ case CPUINFO_INT_REGISTER + Z180_IO3B: Z180.io[0x3b] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IO3C: Z180.io[0x3c] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IO3D: Z180.io[0x3d] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_OMCR: Z180.io[0x3e] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IOCR: Z180.io[0x3f] = info->i; break;
+ case CPUINFO_INT_REGISTER + Z180_IOLINES: z180_write_iolines(info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_op: cc[Z180_TABLE_op] = info->p; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_cb: cc[Z180_TABLE_cb] = info->p; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_ed: cc[Z180_TABLE_ed] = info->p; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_xy: cc[Z180_TABLE_xy] = info->p; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_xycb: cc[Z180_TABLE_xycb] = info->p; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_ex: cc[Z180_TABLE_ex] = info->p; break;
+ }
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void z180_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(Z180); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 16; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 20; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = Z180.nmi_state; break;
+ case CPUINFO_INT_INPUT_STATE + Z180_INT0: info->i = Z180.irq_state[0]; break;
+ case CPUINFO_INT_INPUT_STATE + Z180_INT1: info->i = Z180.irq_state[1]; break;
+ case CPUINFO_INT_INPUT_STATE + Z180_INT2: info->i = Z180.irq_state[2]; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = Z180.PREPC.w.l; break;
+
+ case CPUINFO_INT_PC: info->i = _PCD; break;
+ case CPUINFO_INT_REGISTER + Z180_PC: info->i = Z180.PC.w.l; break;
+ case CPUINFO_INT_SP: info->i = _SPD; break;
+ case CPUINFO_INT_REGISTER + Z180_SP: info->i = Z180.SP.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_AF: info->i = Z180.AF.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_BC: info->i = Z180.BC.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_DE: info->i = Z180.DE.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_HL: info->i = Z180.HL.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_IX: info->i = Z180.IX.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_IY: info->i = Z180.IY.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_R: info->i = (Z180.R & 0x7f) | (Z180.R2 & 0x80); break;
+ case CPUINFO_INT_REGISTER + Z180_I: info->i = Z180.I; break;
+ case CPUINFO_INT_REGISTER + Z180_AF2: info->i = Z180.AF2.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_BC2: info->i = Z180.BC2.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_DE2: info->i = Z180.DE2.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_HL2: info->i = Z180.HL2.w.l; break;
+ case CPUINFO_INT_REGISTER + Z180_IM: info->i = Z180.IM; break;
+ case CPUINFO_INT_REGISTER + Z180_IFF1: info->i = Z180.IFF1; break;
+ case CPUINFO_INT_REGISTER + Z180_IFF2: info->i = Z180.IFF2; break;
+ case CPUINFO_INT_REGISTER + Z180_HALT: info->i = Z180.HALT; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTLA0: info->i = Z180.io[0x00]; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTLA1: info->i = Z180.io[0x01]; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTLB0: info->i = Z180.io[0x02]; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTLB1: info->i = Z180.io[0x03]; break;
+ case CPUINFO_INT_REGISTER + Z180_STAT0: info->i = Z180.io[0x04]; break;
+ case CPUINFO_INT_REGISTER + Z180_STAT1: info->i = Z180.io[0x05]; break;
+ case CPUINFO_INT_REGISTER + Z180_TDR0: info->i = Z180.io[0x06]; break;
+ case CPUINFO_INT_REGISTER + Z180_TDR1: info->i = Z180.io[0x07]; break;
+ case CPUINFO_INT_REGISTER + Z180_RDR0: info->i = Z180.io[0x08]; break;
+ case CPUINFO_INT_REGISTER + Z180_RDR1: info->i = Z180.io[0x09]; break;
+ case CPUINFO_INT_REGISTER + Z180_CNTR: info->i = Z180.io[0x0a]; break;
+ case CPUINFO_INT_REGISTER + Z180_TRDR: info->i = Z180.io[0x0b]; break;
+ case CPUINFO_INT_REGISTER + Z180_TMDR0L: info->i = Z180.io[0x0c]; break;
+ case CPUINFO_INT_REGISTER + Z180_TMDR0H: info->i = Z180.io[0x0d]; break;
+ case CPUINFO_INT_REGISTER + Z180_RLDR0L: info->i = Z180.io[0x0e]; break;
+ case CPUINFO_INT_REGISTER + Z180_RLDR0H: info->i = Z180.io[0x0f]; break;
+ case CPUINFO_INT_REGISTER + Z180_TCR: info->i = Z180.io[0x10]; break;
+ case CPUINFO_INT_REGISTER + Z180_IO11: info->i = Z180.io[0x11]; break;
+ case CPUINFO_INT_REGISTER + Z180_ASEXT0: info->i = Z180.io[0x12]; break;
+ case CPUINFO_INT_REGISTER + Z180_ASEXT1: info->i = Z180.io[0x13]; break;
+ case CPUINFO_INT_REGISTER + Z180_TMDR1L: info->i = Z180.io[0x14]; break;
+ case CPUINFO_INT_REGISTER + Z180_TMDR1H: info->i = Z180.io[0x15]; break;
+ case CPUINFO_INT_REGISTER + Z180_RLDR1L: info->i = Z180.io[0x16]; break;
+ case CPUINFO_INT_REGISTER + Z180_RLDR1H: info->i = Z180.io[0x17]; break;
+ case CPUINFO_INT_REGISTER + Z180_FRC: info->i = Z180.io[0x18]; break;
+ case CPUINFO_INT_REGISTER + Z180_IO19: info->i = Z180.io[0x19]; break;
+ case CPUINFO_INT_REGISTER + Z180_ASTC0L: info->i = Z180.io[0x1a]; break;
+ case CPUINFO_INT_REGISTER + Z180_ASTC0H: info->i = Z180.io[0x1b]; break;
+ case CPUINFO_INT_REGISTER + Z180_ASTC1L: info->i = Z180.io[0x1c]; break;
+ case CPUINFO_INT_REGISTER + Z180_ASTC1H: info->i = Z180.io[0x1d]; break;
+ case CPUINFO_INT_REGISTER + Z180_CMR: info->i = Z180.io[0x1e]; break;
+ case CPUINFO_INT_REGISTER + Z180_CCR: info->i = Z180.io[0x1f]; break;
+ case CPUINFO_INT_REGISTER + Z180_SAR0L: info->i = Z180.io[0x20]; break;
+ case CPUINFO_INT_REGISTER + Z180_SAR0H: info->i = Z180.io[0x21]; break;
+ case CPUINFO_INT_REGISTER + Z180_SAR0B: info->i = Z180.io[0x22]; break;
+ case CPUINFO_INT_REGISTER + Z180_DAR0L: info->i = Z180.io[0x23]; break;
+ case CPUINFO_INT_REGISTER + Z180_DAR0H: info->i = Z180.io[0x24]; break;
+ case CPUINFO_INT_REGISTER + Z180_DAR0B: info->i = Z180.io[0x25]; break;
+ case CPUINFO_INT_REGISTER + Z180_BCR0L: info->i = Z180.io[0x26]; break;
+ case CPUINFO_INT_REGISTER + Z180_BCR0H: info->i = Z180.io[0x27]; break;
+ case CPUINFO_INT_REGISTER + Z180_MAR1L: info->i = Z180.io[0x28]; break;
+ case CPUINFO_INT_REGISTER + Z180_MAR1H: info->i = Z180.io[0x29]; break;
+ case CPUINFO_INT_REGISTER + Z180_MAR1B: info->i = Z180.io[0x2a]; break;
+ case CPUINFO_INT_REGISTER + Z180_IAR1L: info->i = Z180.io[0x2b]; break;
+ case CPUINFO_INT_REGISTER + Z180_IAR1H: info->i = Z180.io[0x2c]; break;
+ case CPUINFO_INT_REGISTER + Z180_IAR1B: info->i = Z180.io[0x2d]; break;
+ case CPUINFO_INT_REGISTER + Z180_BCR1L: info->i = Z180.io[0x2e]; break;
+ case CPUINFO_INT_REGISTER + Z180_BCR1H: info->i = Z180.io[0x2f]; break;
+ case CPUINFO_INT_REGISTER + Z180_DSTAT: info->i = Z180.io[0x30]; break;
+ case CPUINFO_INT_REGISTER + Z180_DMODE: info->i = Z180.io[0x31]; break;
+ case CPUINFO_INT_REGISTER + Z180_DCNTL: info->i = Z180.io[0x32]; break;
+ case CPUINFO_INT_REGISTER + Z180_IL: info->i = Z180.io[0x33]; break;
+ case CPUINFO_INT_REGISTER + Z180_ITC: info->i = Z180.io[0x34]; break;
+ case CPUINFO_INT_REGISTER + Z180_IO35: info->i = Z180.io[0x35]; break;
+ case CPUINFO_INT_REGISTER + Z180_RCR: info->i = Z180.io[0x36]; break;
+ case CPUINFO_INT_REGISTER + Z180_IO37: info->i = Z180.io[0x37]; break;
+ case CPUINFO_INT_REGISTER + Z180_CBR: info->i = Z180.io[0x38]; break;
+ case CPUINFO_INT_REGISTER + Z180_BBR: info->i = Z180.io[0x39]; break;
+ case CPUINFO_INT_REGISTER + Z180_CBAR: info->i = Z180.io[0x3a]; break;
+ case CPUINFO_INT_REGISTER + Z180_IO3B: info->i = Z180.io[0x3b]; break;
+ case CPUINFO_INT_REGISTER + Z180_IO3C: info->i = Z180.io[0x3c]; break;
+ case CPUINFO_INT_REGISTER + Z180_IO3D: info->i = Z180.io[0x3d]; break;
+ case CPUINFO_INT_REGISTER + Z180_OMCR: info->i = Z180.io[0x3e]; break;
+ case CPUINFO_INT_REGISTER + Z180_IOCR: info->i = Z180.io[0x3f]; break;
+ case CPUINFO_INT_REGISTER + Z180_IOLINES: info->i = Z180.iol; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = z180_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = z180_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = z180_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = z180_init; break;
+ case CPUINFO_PTR_RESET: info->reset = z180_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = z180_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = z180_burn; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = z180_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &z180_icount; break;
+ case CPUINFO_PTR_TRANSLATE: info->translate = z180_translate; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_op: info->p = cc[Z180_TABLE_op]; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_cb: info->p = cc[Z180_TABLE_cb]; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_ed: info->p = cc[Z180_TABLE_ed]; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_xy: info->p = cc[Z180_TABLE_xy]; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_xycb: info->p = cc[Z180_TABLE_xycb]; break;
+ case CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_ex: info->p = cc[Z180_TABLE_ex]; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "Z180"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Zilog Z8x180"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.3"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2000 Juergen Buchmueller, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ Z180.AF.b.l & 0x80 ? 'S':'.',
+ Z180.AF.b.l & 0x40 ? 'Z':'.',
+ Z180.AF.b.l & 0x20 ? '5':'.',
+ Z180.AF.b.l & 0x10 ? 'H':'.',
+ Z180.AF.b.l & 0x08 ? '3':'.',
+ Z180.AF.b.l & 0x04 ? 'P':'.',
+ Z180.AF.b.l & 0x02 ? 'N':'.',
+ Z180.AF.b.l & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + Z180_PC: sprintf(info->s, "PC:%04X", Z180.PC.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_SP: sprintf(info->s, "SP:%04X", Z180.SP.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_AF: sprintf(info->s, "AF:%04X", Z180.AF.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_BC: sprintf(info->s, "BC:%04X", Z180.BC.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_DE: sprintf(info->s, "DE:%04X", Z180.DE.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_HL: sprintf(info->s, "HL:%04X", Z180.HL.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_IX: sprintf(info->s, "IX:%04X", Z180.IX.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_IY: sprintf(info->s, "IY:%04X", Z180.IY.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_R: sprintf(info->s, "R :%02X", (Z180.R & 0x7f) | (Z180.R2 & 0x80)); break;
+ case CPUINFO_STR_REGISTER + Z180_I: sprintf(info->s, "I :%02X", Z180.I); break;
+ case CPUINFO_STR_REGISTER + Z180_IL: sprintf(info->s, "IL :%02X", Z180.io[Z180_IL-Z180_CNTLA0]); break;
+ case CPUINFO_STR_REGISTER + Z180_AF2: sprintf(info->s, "AF2:%04X", Z180.AF2.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_BC2: sprintf(info->s, "BC2:%04X", Z180.BC2.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_DE2: sprintf(info->s, "DE2:%04X", Z180.DE2.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_HL2: sprintf(info->s, "HL2:%04X", Z180.HL2.w.l); break;
+ case CPUINFO_STR_REGISTER + Z180_IM: sprintf(info->s, "IM :%X", Z180.IM); break;
+ case CPUINFO_STR_REGISTER + Z180_IFF1: sprintf(info->s, "IFF1:%X", Z180.IFF1); break;
+ case CPUINFO_STR_REGISTER + Z180_IFF2: sprintf(info->s, "IFF2:%X", Z180.IFF2); break;
+ case CPUINFO_STR_REGISTER + Z180_HALT: sprintf(info->s, "HALT:%X", Z180.HALT); break;
+ case CPUINFO_STR_REGISTER + Z180_CCR: sprintf(info->s, "CCR :%02X", Z180.io[Z180_CCR-Z180_CNTLA0]); break;
+ case CPUINFO_STR_REGISTER + Z180_ITC: sprintf(info->s, "ITC :%02X", Z180.io[Z180_ITC-Z180_CNTLA0]); break;
+ case CPUINFO_STR_REGISTER + Z180_CBR: sprintf(info->s, "CBR :%02X", Z180.io[Z180_CBR-Z180_CNTLA0]); break;
+ case CPUINFO_STR_REGISTER + Z180_BBR: sprintf(info->s, "BBR :%02X", Z180.io[Z180_BBR-Z180_CNTLA0]); break;
+ case CPUINFO_STR_REGISTER + Z180_CBAR: sprintf(info->s, "CBAR:%02X", Z180.io[Z180_CBAR-Z180_CNTLA0]); break;
+ case CPUINFO_STR_REGISTER + Z180_OMCR: sprintf(info->s, "OMCR:%02X", Z180.io[Z180_OMCR-Z180_CNTLA0]); break;
+ case CPUINFO_STR_REGISTER + Z180_IOCR: sprintf(info->s, "IOCR:%02X", Z180.io[Z180_IOCR-Z180_CNTLA0]); break;
+ }
+}
diff --git a/src/emu/cpu/z180/z180.h b/src/emu/cpu/z180/z180.h
new file mode 100644
index 00000000000..825e08f3168
--- /dev/null
+++ b/src/emu/cpu/z180/z180.h
@@ -0,0 +1,135 @@
+#ifndef Z180_H
+#define Z180_H
+
+#include "cpuintrf.h"
+
+enum {
+ Z180_PC=1,
+ Z180_SP,
+ Z180_AF,
+ Z180_BC,
+ Z180_DE,
+ Z180_HL,
+ Z180_IX,
+ Z180_IY,
+ Z180_AF2,
+ Z180_BC2,
+ Z180_DE2,
+ Z180_HL2,
+ Z180_R,
+ Z180_I,
+ Z180_IM,
+ Z180_IFF1,
+ Z180_IFF2,
+ Z180_HALT,
+ Z180_DC0,
+ Z180_DC1,
+ Z180_DC2,
+ Z180_DC3,
+ Z180_CNTLA0, /* 00 ASCI control register A ch 0 */
+ Z180_CNTLA1, /* 01 ASCI control register A ch 1 */
+ Z180_CNTLB0, /* 02 ASCI control register B ch 0 */
+ Z180_CNTLB1, /* 03 ASCI control register B ch 1 */
+ Z180_STAT0, /* 04 ASCI status register 0 */
+ Z180_STAT1, /* 05 ASCI status register 1 */
+ Z180_TDR0, /* 06 ASCI transmit data register 0 */
+ Z180_TDR1, /* 07 ASCI transmit data register 1 */
+ Z180_RDR0, /* 08 ASCI receive data register 0 */
+ Z180_RDR1, /* 09 ASCI receive data register 1 */
+ Z180_CNTR, /* 0a CSI/O control/status register */
+ Z180_TRDR, /* 0b CSI/O transmit/receive register */
+ Z180_TMDR0L, /* 0c TIMER data register ch 0 L */
+ Z180_TMDR0H, /* 0d TIMER data register ch 0 H */
+ Z180_RLDR0L, /* 0e TIMER reload register ch 0 L */
+ Z180_RLDR0H, /* 0f TIMER reload register ch 0 H */
+ Z180_TCR, /* 10 TIMER control register */
+ Z180_IO11, /* 11 reserved */
+ Z180_ASEXT0, /* 12 (Z8S180/Z8L180) ASCI extension control register 0 */
+ Z180_ASEXT1, /* 13 (Z8S180/Z8L180) ASCI extension control register 0 */
+ Z180_TMDR1L, /* 14 TIMER data register ch 1 L */
+ Z180_TMDR1H, /* 15 TIMER data register ch 1 H */
+ Z180_RLDR1L, /* 16 TIMER reload register ch 1 L */
+ Z180_RLDR1H, /* 17 TIMER reload register ch 1 H */
+ Z180_FRC, /* 18 free running counter */
+ Z180_IO19, /* 19 reserved */
+ Z180_ASTC0L, /* 1a ASCI time constant ch 0 L */
+ Z180_ASTC0H, /* 1b ASCI time constant ch 0 H */
+ Z180_ASTC1L, /* 1c ASCI time constant ch 1 L */
+ Z180_ASTC1H, /* 1d ASCI time constant ch 1 H */
+ Z180_CMR, /* 1e clock multiplier */
+ Z180_CCR, /* 1f chip control register */
+ Z180_SAR0L, /* 20 DMA source address register ch 0 L */
+ Z180_SAR0H, /* 21 DMA source address register ch 0 H */
+ Z180_SAR0B, /* 22 DMA source address register ch 0 B */
+ Z180_DAR0L, /* 23 DMA destination address register ch 0 L */
+ Z180_DAR0H, /* 24 DMA destination address register ch 0 H */
+ Z180_DAR0B, /* 25 DMA destination address register ch 0 B */
+ Z180_BCR0L, /* 26 DMA byte count register ch 0 L */
+ Z180_BCR0H, /* 27 DMA byte count register ch 0 H */
+ Z180_MAR1L, /* 28 DMA memory address register ch 1 L */
+ Z180_MAR1H, /* 29 DMA memory address register ch 1 H */
+ Z180_MAR1B, /* 2a DMA memory address register ch 1 B */
+ Z180_IAR1L, /* 2b DMA I/O address register ch 1 L */
+ Z180_IAR1H, /* 2c DMA I/O address register ch 1 H */
+ Z180_IAR1B, /* 2d (Z8S180/Z8L180) DMA I/O address register ch 1 B */
+ Z180_BCR1L, /* 2e DMA byte count register ch 1 L */
+ Z180_BCR1H, /* 2f DMA byte count register ch 1 H */
+ Z180_DSTAT, /* 30 DMA status register */
+ Z180_DMODE, /* 31 DMA mode register */
+ Z180_DCNTL, /* 32 DMA/WAIT control register */
+ Z180_IL, /* 33 INT vector low register */
+ Z180_ITC, /* 34 INT/TRAP control register */
+ Z180_IO35, /* 35 reserved */
+ Z180_RCR, /* 36 refresh control register */
+ Z180_IO37, /* 37 reserved */
+ Z180_CBR, /* 38 MMU common base register */
+ Z180_BBR, /* 39 MMU bank base register */
+ Z180_CBAR, /* 3a MMU common/bank area register */
+ Z180_IO3B, /* 3b reserved */
+ Z180_IO3C, /* 3c reserved */
+ Z180_IO3D, /* 3d reserved */
+ Z180_OMCR, /* 3e operation mode control register */
+ Z180_IOCR, /* 3f I/O control register */
+ Z180_IOLINES /* read/write I/O lines */
+};
+
+enum {
+ Z180_TABLE_op,
+ Z180_TABLE_cb,
+ Z180_TABLE_ed,
+ Z180_TABLE_xy,
+ Z180_TABLE_xycb,
+ Z180_TABLE_ex /* cycles counts for taken jr/jp/call and interrupt latency (rst opcodes) */
+};
+
+enum
+{
+ CPUINFO_PTR_Z180_CYCLE_TABLE = CPUINFO_PTR_CPU_SPECIFIC,
+ CPUINFO_PTR_Z180_CYCLE_TABLE_LAST = CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_ex
+};
+
+
+#define Z180_INT0 0 /* Execute INT1 */
+#define Z180_INT1 1 /* Execute INT1 */
+#define Z180_INT2 2 /* Execute INT2 */
+#define Z180_INT_PRT0 3 /* Internal PRT channel 0 */
+#define Z180_INT_PRT1 4 /* Internal PRT channel 1 */
+#define Z180_INT_DMA0 5 /* Internal DMA channel 0 */
+#define Z180_INT_DMA1 6 /* Internal DMA channel 1 */
+#define Z180_INT_CSIO 7 /* Internal CSI/O */
+#define Z180_INT_ASCI0 8 /* Internal ASCI channel 0 */
+#define Z180_INT_ASCI1 9 /* Internal ASCI channel 1 */
+
+/* MMU mapped memory lookup */
+extern UINT8 z180_readmem(offs_t offset);
+extern void z180_writemem(offs_t offset, UINT8 data);
+extern void z180_setOPbase(int pc);
+
+extern void z180_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+offs_t z180_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif
+
diff --git a/src/emu/cpu/z180/z180cb.c b/src/emu/cpu/z180/z180cb.c
new file mode 100644
index 00000000000..07235cd51e2
--- /dev/null
+++ b/src/emu/cpu/z180/z180cb.c
@@ -0,0 +1,293 @@
+/**********************************************************
+ * opcodes with CB prefix
+ * rotate, shift and bit operations
+ **********************************************************/
+OP(cb,00) { _B = RLC(_B); } /* RLC B */
+OP(cb,01) { _C = RLC(_C); } /* RLC C */
+OP(cb,02) { _D = RLC(_D); } /* RLC D */
+OP(cb,03) { _E = RLC(_E); } /* RLC E */
+OP(cb,04) { _H = RLC(_H); } /* RLC H */
+OP(cb,05) { _L = RLC(_L); } /* RLC L */
+OP(cb,06) { WM( _HL, RLC(RM(_HL)) ); } /* RLC (HL) */
+OP(cb,07) { _A = RLC(_A); } /* RLC A */
+
+OP(cb,08) { _B = RRC(_B); } /* RRC B */
+OP(cb,09) { _C = RRC(_C); } /* RRC C */
+OP(cb,0a) { _D = RRC(_D); } /* RRC D */
+OP(cb,0b) { _E = RRC(_E); } /* RRC E */
+OP(cb,0c) { _H = RRC(_H); } /* RRC H */
+OP(cb,0d) { _L = RRC(_L); } /* RRC L */
+OP(cb,0e) { WM( _HL, RRC(RM(_HL)) ); } /* RRC (HL) */
+OP(cb,0f) { _A = RRC(_A); } /* RRC A */
+
+OP(cb,10) { _B = RL(_B); } /* RL B */
+OP(cb,11) { _C = RL(_C); } /* RL C */
+OP(cb,12) { _D = RL(_D); } /* RL D */
+OP(cb,13) { _E = RL(_E); } /* RL E */
+OP(cb,14) { _H = RL(_H); } /* RL H */
+OP(cb,15) { _L = RL(_L); } /* RL L */
+OP(cb,16) { WM( _HL, RL(RM(_HL)) ); } /* RL (HL) */
+OP(cb,17) { _A = RL(_A); } /* RL A */
+
+OP(cb,18) { _B = RR(_B); } /* RR B */
+OP(cb,19) { _C = RR(_C); } /* RR C */
+OP(cb,1a) { _D = RR(_D); } /* RR D */
+OP(cb,1b) { _E = RR(_E); } /* RR E */
+OP(cb,1c) { _H = RR(_H); } /* RR H */
+OP(cb,1d) { _L = RR(_L); } /* RR L */
+OP(cb,1e) { WM( _HL, RR(RM(_HL)) ); } /* RR (HL) */
+OP(cb,1f) { _A = RR(_A); } /* RR A */
+
+OP(cb,20) { _B = SLA(_B); } /* SLA B */
+OP(cb,21) { _C = SLA(_C); } /* SLA C */
+OP(cb,22) { _D = SLA(_D); } /* SLA D */
+OP(cb,23) { _E = SLA(_E); } /* SLA E */
+OP(cb,24) { _H = SLA(_H); } /* SLA H */
+OP(cb,25) { _L = SLA(_L); } /* SLA L */
+OP(cb,26) { WM( _HL, SLA(RM(_HL)) ); } /* SLA (HL) */
+OP(cb,27) { _A = SLA(_A); } /* SLA A */
+
+OP(cb,28) { _B = SRA(_B); } /* SRA B */
+OP(cb,29) { _C = SRA(_C); } /* SRA C */
+OP(cb,2a) { _D = SRA(_D); } /* SRA D */
+OP(cb,2b) { _E = SRA(_E); } /* SRA E */
+OP(cb,2c) { _H = SRA(_H); } /* SRA H */
+OP(cb,2d) { _L = SRA(_L); } /* SRA L */
+OP(cb,2e) { WM( _HL, SRA(RM(_HL)) ); } /* SRA (HL) */
+OP(cb,2f) { _A = SRA(_A); } /* SRA A */
+
+OP(cb,30) { _B = SLL(_B); } /* SLL B */
+OP(cb,31) { _C = SLL(_C); } /* SLL C */
+OP(cb,32) { _D = SLL(_D); } /* SLL D */
+OP(cb,33) { _E = SLL(_E); } /* SLL E */
+OP(cb,34) { _H = SLL(_H); } /* SLL H */
+OP(cb,35) { _L = SLL(_L); } /* SLL L */
+OP(cb,36) { WM( _HL, SLL(RM(_HL)) ); } /* SLL (HL) */
+OP(cb,37) { _A = SLL(_A); } /* SLL A */
+
+OP(cb,38) { _B = SRL(_B); } /* SRL B */
+OP(cb,39) { _C = SRL(_C); } /* SRL C */
+OP(cb,3a) { _D = SRL(_D); } /* SRL D */
+OP(cb,3b) { _E = SRL(_E); } /* SRL E */
+OP(cb,3c) { _H = SRL(_H); } /* SRL H */
+OP(cb,3d) { _L = SRL(_L); } /* SRL L */
+OP(cb,3e) { WM( _HL, SRL(RM(_HL)) ); } /* SRL (HL) */
+OP(cb,3f) { _A = SRL(_A); } /* SRL A */
+
+OP(cb,40) { BIT(0,_B); } /* BIT 0,B */
+OP(cb,41) { BIT(0,_C); } /* BIT 0,C */
+OP(cb,42) { BIT(0,_D); } /* BIT 0,D */
+OP(cb,43) { BIT(0,_E); } /* BIT 0,E */
+OP(cb,44) { BIT(0,_H); } /* BIT 0,H */
+OP(cb,45) { BIT(0,_L); } /* BIT 0,L */
+OP(cb,46) { BIT(0,RM(_HL)); } /* BIT 0,(HL) */
+OP(cb,47) { BIT(0,_A); } /* BIT 0,A */
+
+OP(cb,48) { BIT(1,_B); } /* BIT 1,B */
+OP(cb,49) { BIT(1,_C); } /* BIT 1,C */
+OP(cb,4a) { BIT(1,_D); } /* BIT 1,D */
+OP(cb,4b) { BIT(1,_E); } /* BIT 1,E */
+OP(cb,4c) { BIT(1,_H); } /* BIT 1,H */
+OP(cb,4d) { BIT(1,_L); } /* BIT 1,L */
+OP(cb,4e) { BIT(1,RM(_HL)); } /* BIT 1,(HL) */
+OP(cb,4f) { BIT(1,_A); } /* BIT 1,A */
+
+OP(cb,50) { BIT(2,_B); } /* BIT 2,B */
+OP(cb,51) { BIT(2,_C); } /* BIT 2,C */
+OP(cb,52) { BIT(2,_D); } /* BIT 2,D */
+OP(cb,53) { BIT(2,_E); } /* BIT 2,E */
+OP(cb,54) { BIT(2,_H); } /* BIT 2,H */
+OP(cb,55) { BIT(2,_L); } /* BIT 2,L */
+OP(cb,56) { BIT(2,RM(_HL)); } /* BIT 2,(HL) */
+OP(cb,57) { BIT(2,_A); } /* BIT 2,A */
+
+OP(cb,58) { BIT(3,_B); } /* BIT 3,B */
+OP(cb,59) { BIT(3,_C); } /* BIT 3,C */
+OP(cb,5a) { BIT(3,_D); } /* BIT 3,D */
+OP(cb,5b) { BIT(3,_E); } /* BIT 3,E */
+OP(cb,5c) { BIT(3,_H); } /* BIT 3,H */
+OP(cb,5d) { BIT(3,_L); } /* BIT 3,L */
+OP(cb,5e) { BIT(3,RM(_HL)); } /* BIT 3,(HL) */
+OP(cb,5f) { BIT(3,_A); } /* BIT 3,A */
+
+OP(cb,60) { BIT(4,_B); } /* BIT 4,B */
+OP(cb,61) { BIT(4,_C); } /* BIT 4,C */
+OP(cb,62) { BIT(4,_D); } /* BIT 4,D */
+OP(cb,63) { BIT(4,_E); } /* BIT 4,E */
+OP(cb,64) { BIT(4,_H); } /* BIT 4,H */
+OP(cb,65) { BIT(4,_L); } /* BIT 4,L */
+OP(cb,66) { BIT(4,RM(_HL)); } /* BIT 4,(HL) */
+OP(cb,67) { BIT(4,_A); } /* BIT 4,A */
+
+OP(cb,68) { BIT(5,_B); } /* BIT 5,B */
+OP(cb,69) { BIT(5,_C); } /* BIT 5,C */
+OP(cb,6a) { BIT(5,_D); } /* BIT 5,D */
+OP(cb,6b) { BIT(5,_E); } /* BIT 5,E */
+OP(cb,6c) { BIT(5,_H); } /* BIT 5,H */
+OP(cb,6d) { BIT(5,_L); } /* BIT 5,L */
+OP(cb,6e) { BIT(5,RM(_HL)); } /* BIT 5,(HL) */
+OP(cb,6f) { BIT(5,_A); } /* BIT 5,A */
+
+OP(cb,70) { BIT(6,_B); } /* BIT 6,B */
+OP(cb,71) { BIT(6,_C); } /* BIT 6,C */
+OP(cb,72) { BIT(6,_D); } /* BIT 6,D */
+OP(cb,73) { BIT(6,_E); } /* BIT 6,E */
+OP(cb,74) { BIT(6,_H); } /* BIT 6,H */
+OP(cb,75) { BIT(6,_L); } /* BIT 6,L */
+OP(cb,76) { BIT(6,RM(_HL)); } /* BIT 6,(HL) */
+OP(cb,77) { BIT(6,_A); } /* BIT 6,A */
+
+OP(cb,78) { BIT(7,_B); } /* BIT 7,B */
+OP(cb,79) { BIT(7,_C); } /* BIT 7,C */
+OP(cb,7a) { BIT(7,_D); } /* BIT 7,D */
+OP(cb,7b) { BIT(7,_E); } /* BIT 7,E */
+OP(cb,7c) { BIT(7,_H); } /* BIT 7,H */
+OP(cb,7d) { BIT(7,_L); } /* BIT 7,L */
+OP(cb,7e) { BIT(7,RM(_HL)); } /* BIT 7,(HL) */
+OP(cb,7f) { BIT(7,_A); } /* BIT 7,A */
+
+OP(cb,80) { _B = RES(0,_B); } /* RES 0,B */
+OP(cb,81) { _C = RES(0,_C); } /* RES 0,C */
+OP(cb,82) { _D = RES(0,_D); } /* RES 0,D */
+OP(cb,83) { _E = RES(0,_E); } /* RES 0,E */
+OP(cb,84) { _H = RES(0,_H); } /* RES 0,H */
+OP(cb,85) { _L = RES(0,_L); } /* RES 0,L */
+OP(cb,86) { WM( _HL, RES(0,RM(_HL)) ); } /* RES 0,(HL) */
+OP(cb,87) { _A = RES(0,_A); } /* RES 0,A */
+
+OP(cb,88) { _B = RES(1,_B); } /* RES 1,B */
+OP(cb,89) { _C = RES(1,_C); } /* RES 1,C */
+OP(cb,8a) { _D = RES(1,_D); } /* RES 1,D */
+OP(cb,8b) { _E = RES(1,_E); } /* RES 1,E */
+OP(cb,8c) { _H = RES(1,_H); } /* RES 1,H */
+OP(cb,8d) { _L = RES(1,_L); } /* RES 1,L */
+OP(cb,8e) { WM( _HL, RES(1,RM(_HL)) ); } /* RES 1,(HL) */
+OP(cb,8f) { _A = RES(1,_A); } /* RES 1,A */
+
+OP(cb,90) { _B = RES(2,_B); } /* RES 2,B */
+OP(cb,91) { _C = RES(2,_C); } /* RES 2,C */
+OP(cb,92) { _D = RES(2,_D); } /* RES 2,D */
+OP(cb,93) { _E = RES(2,_E); } /* RES 2,E */
+OP(cb,94) { _H = RES(2,_H); } /* RES 2,H */
+OP(cb,95) { _L = RES(2,_L); } /* RES 2,L */
+OP(cb,96) { WM( _HL, RES(2,RM(_HL)) ); } /* RES 2,(HL) */
+OP(cb,97) { _A = RES(2,_A); } /* RES 2,A */
+
+OP(cb,98) { _B = RES(3,_B); } /* RES 3,B */
+OP(cb,99) { _C = RES(3,_C); } /* RES 3,C */
+OP(cb,9a) { _D = RES(3,_D); } /* RES 3,D */
+OP(cb,9b) { _E = RES(3,_E); } /* RES 3,E */
+OP(cb,9c) { _H = RES(3,_H); } /* RES 3,H */
+OP(cb,9d) { _L = RES(3,_L); } /* RES 3,L */
+OP(cb,9e) { WM( _HL, RES(3,RM(_HL)) ); } /* RES 3,(HL) */
+OP(cb,9f) { _A = RES(3,_A); } /* RES 3,A */
+
+OP(cb,a0) { _B = RES(4,_B); } /* RES 4,B */
+OP(cb,a1) { _C = RES(4,_C); } /* RES 4,C */
+OP(cb,a2) { _D = RES(4,_D); } /* RES 4,D */
+OP(cb,a3) { _E = RES(4,_E); } /* RES 4,E */
+OP(cb,a4) { _H = RES(4,_H); } /* RES 4,H */
+OP(cb,a5) { _L = RES(4,_L); } /* RES 4,L */
+OP(cb,a6) { WM( _HL, RES(4,RM(_HL)) ); } /* RES 4,(HL) */
+OP(cb,a7) { _A = RES(4,_A); } /* RES 4,A */
+
+OP(cb,a8) { _B = RES(5,_B); } /* RES 5,B */
+OP(cb,a9) { _C = RES(5,_C); } /* RES 5,C */
+OP(cb,aa) { _D = RES(5,_D); } /* RES 5,D */
+OP(cb,ab) { _E = RES(5,_E); } /* RES 5,E */
+OP(cb,ac) { _H = RES(5,_H); } /* RES 5,H */
+OP(cb,ad) { _L = RES(5,_L); } /* RES 5,L */
+OP(cb,ae) { WM( _HL, RES(5,RM(_HL)) ); } /* RES 5,(HL) */
+OP(cb,af) { _A = RES(5,_A); } /* RES 5,A */
+
+OP(cb,b0) { _B = RES(6,_B); } /* RES 6,B */
+OP(cb,b1) { _C = RES(6,_C); } /* RES 6,C */
+OP(cb,b2) { _D = RES(6,_D); } /* RES 6,D */
+OP(cb,b3) { _E = RES(6,_E); } /* RES 6,E */
+OP(cb,b4) { _H = RES(6,_H); } /* RES 6,H */
+OP(cb,b5) { _L = RES(6,_L); } /* RES 6,L */
+OP(cb,b6) { WM( _HL, RES(6,RM(_HL)) ); } /* RES 6,(HL) */
+OP(cb,b7) { _A = RES(6,_A); } /* RES 6,A */
+
+OP(cb,b8) { _B = RES(7,_B); } /* RES 7,B */
+OP(cb,b9) { _C = RES(7,_C); } /* RES 7,C */
+OP(cb,ba) { _D = RES(7,_D); } /* RES 7,D */
+OP(cb,bb) { _E = RES(7,_E); } /* RES 7,E */
+OP(cb,bc) { _H = RES(7,_H); } /* RES 7,H */
+OP(cb,bd) { _L = RES(7,_L); } /* RES 7,L */
+OP(cb,be) { WM( _HL, RES(7,RM(_HL)) ); } /* RES 7,(HL) */
+OP(cb,bf) { _A = RES(7,_A); } /* RES 7,A */
+
+OP(cb,c0) { _B = SET(0,_B); } /* SET 0,B */
+OP(cb,c1) { _C = SET(0,_C); } /* SET 0,C */
+OP(cb,c2) { _D = SET(0,_D); } /* SET 0,D */
+OP(cb,c3) { _E = SET(0,_E); } /* SET 0,E */
+OP(cb,c4) { _H = SET(0,_H); } /* SET 0,H */
+OP(cb,c5) { _L = SET(0,_L); } /* SET 0,L */
+OP(cb,c6) { WM( _HL, SET(0,RM(_HL)) ); } /* SET 0,(HL) */
+OP(cb,c7) { _A = SET(0,_A); } /* SET 0,A */
+
+OP(cb,c8) { _B = SET(1,_B); } /* SET 1,B */
+OP(cb,c9) { _C = SET(1,_C); } /* SET 1,C */
+OP(cb,ca) { _D = SET(1,_D); } /* SET 1,D */
+OP(cb,cb) { _E = SET(1,_E); } /* SET 1,E */
+OP(cb,cc) { _H = SET(1,_H); } /* SET 1,H */
+OP(cb,cd) { _L = SET(1,_L); } /* SET 1,L */
+OP(cb,ce) { WM( _HL, SET(1,RM(_HL)) ); } /* SET 1,(HL) */
+OP(cb,cf) { _A = SET(1,_A); } /* SET 1,A */
+
+OP(cb,d0) { _B = SET(2,_B); } /* SET 2,B */
+OP(cb,d1) { _C = SET(2,_C); } /* SET 2,C */
+OP(cb,d2) { _D = SET(2,_D); } /* SET 2,D */
+OP(cb,d3) { _E = SET(2,_E); } /* SET 2,E */
+OP(cb,d4) { _H = SET(2,_H); } /* SET 2,H */
+OP(cb,d5) { _L = SET(2,_L); } /* SET 2,L */
+OP(cb,d6) { WM( _HL, SET(2,RM(_HL)) ); }/* SET 2,(HL) */
+OP(cb,d7) { _A = SET(2,_A); } /* SET 2,A */
+
+OP(cb,d8) { _B = SET(3,_B); } /* SET 3,B */
+OP(cb,d9) { _C = SET(3,_C); } /* SET 3,C */
+OP(cb,da) { _D = SET(3,_D); } /* SET 3,D */
+OP(cb,db) { _E = SET(3,_E); } /* SET 3,E */
+OP(cb,dc) { _H = SET(3,_H); } /* SET 3,H */
+OP(cb,dd) { _L = SET(3,_L); } /* SET 3,L */
+OP(cb,de) { WM( _HL, SET(3,RM(_HL)) ); } /* SET 3,(HL) */
+OP(cb,df) { _A = SET(3,_A); } /* SET 3,A */
+
+OP(cb,e0) { _B = SET(4,_B); } /* SET 4,B */
+OP(cb,e1) { _C = SET(4,_C); } /* SET 4,C */
+OP(cb,e2) { _D = SET(4,_D); } /* SET 4,D */
+OP(cb,e3) { _E = SET(4,_E); } /* SET 4,E */
+OP(cb,e4) { _H = SET(4,_H); } /* SET 4,H */
+OP(cb,e5) { _L = SET(4,_L); } /* SET 4,L */
+OP(cb,e6) { WM( _HL, SET(4,RM(_HL)) ); } /* SET 4,(HL) */
+OP(cb,e7) { _A = SET(4,_A); } /* SET 4,A */
+
+OP(cb,e8) { _B = SET(5,_B); } /* SET 5,B */
+OP(cb,e9) { _C = SET(5,_C); } /* SET 5,C */
+OP(cb,ea) { _D = SET(5,_D); } /* SET 5,D */
+OP(cb,eb) { _E = SET(5,_E); } /* SET 5,E */
+OP(cb,ec) { _H = SET(5,_H); } /* SET 5,H */
+OP(cb,ed) { _L = SET(5,_L); } /* SET 5,L */
+OP(cb,ee) { WM( _HL, SET(5,RM(_HL)) ); } /* SET 5,(HL) */
+OP(cb,ef) { _A = SET(5,_A); } /* SET 5,A */
+
+OP(cb,f0) { _B = SET(6,_B); } /* SET 6,B */
+OP(cb,f1) { _C = SET(6,_C); } /* SET 6,C */
+OP(cb,f2) { _D = SET(6,_D); } /* SET 6,D */
+OP(cb,f3) { _E = SET(6,_E); } /* SET 6,E */
+OP(cb,f4) { _H = SET(6,_H); } /* SET 6,H */
+OP(cb,f5) { _L = SET(6,_L); } /* SET 6,L */
+OP(cb,f6) { WM( _HL, SET(6,RM(_HL)) ); } /* SET 6,(HL) */
+OP(cb,f7) { _A = SET(6,_A); } /* SET 6,A */
+
+OP(cb,f8) { _B = SET(7,_B); } /* SET 7,B */
+OP(cb,f9) { _C = SET(7,_C); } /* SET 7,C */
+OP(cb,fa) { _D = SET(7,_D); } /* SET 7,D */
+OP(cb,fb) { _E = SET(7,_E); } /* SET 7,E */
+OP(cb,fc) { _H = SET(7,_H); } /* SET 7,H */
+OP(cb,fd) { _L = SET(7,_L); } /* SET 7,L */
+OP(cb,fe) { WM( _HL, SET(7,RM(_HL)) ); } /* SET 7,(HL) */
+OP(cb,ff) { _A = SET(7,_A); } /* SET 7,A */
+
+
diff --git a/src/emu/cpu/z180/z180daa.h b/src/emu/cpu/z180/z180daa.h
new file mode 100644
index 00000000000..44dbbd3bc0b
--- /dev/null
+++ b/src/emu/cpu/z180/z180daa.h
@@ -0,0 +1,2051 @@
+static UINT16 DAATable[0x800] = {
+ (0x00<<8) +ZF +VF ,
+ (0x01<<8) ,
+ (0x02<<8) ,
+ (0x03<<8) +VF ,
+ (0x04<<8) ,
+ (0x05<<8) +VF ,
+ (0x06<<8) +VF ,
+ (0x07<<8) ,
+ (0x08<<8) +XF ,
+ (0x09<<8) +XF+VF ,
+ (0x10<<8) +HF ,
+ (0x11<<8) +HF +VF ,
+ (0x12<<8) +HF +VF ,
+ (0x13<<8) +HF ,
+ (0x14<<8) +HF +VF ,
+ (0x15<<8) +HF ,
+ (0x10<<8) ,
+ (0x11<<8) +VF ,
+ (0x12<<8) +VF ,
+ (0x13<<8) ,
+ (0x14<<8) +VF ,
+ (0x15<<8) ,
+ (0x16<<8) ,
+ (0x17<<8) +VF ,
+ (0x18<<8) +XF+VF ,
+ (0x19<<8) +XF ,
+ (0x20<<8) +YF+HF ,
+ (0x21<<8) +YF+HF +VF ,
+ (0x22<<8) +YF+HF +VF ,
+ (0x23<<8) +YF+HF ,
+ (0x24<<8) +YF+HF +VF ,
+ (0x25<<8) +YF+HF ,
+ (0x20<<8) +YF ,
+ (0x21<<8) +YF +VF ,
+ (0x22<<8) +YF +VF ,
+ (0x23<<8) +YF ,
+ (0x24<<8) +YF +VF ,
+ (0x25<<8) +YF ,
+ (0x26<<8) +YF ,
+ (0x27<<8) +YF +VF ,
+ (0x28<<8) +YF +XF+VF ,
+ (0x29<<8) +YF +XF ,
+ (0x30<<8) +YF+HF +VF ,
+ (0x31<<8) +YF+HF ,
+ (0x32<<8) +YF+HF ,
+ (0x33<<8) +YF+HF +VF ,
+ (0x34<<8) +YF+HF ,
+ (0x35<<8) +YF+HF +VF ,
+ (0x30<<8) +YF +VF ,
+ (0x31<<8) +YF ,
+ (0x32<<8) +YF ,
+ (0x33<<8) +YF +VF ,
+ (0x34<<8) +YF ,
+ (0x35<<8) +YF +VF ,
+ (0x36<<8) +YF +VF ,
+ (0x37<<8) +YF ,
+ (0x38<<8) +YF +XF ,
+ (0x39<<8) +YF +XF+VF ,
+ (0x40<<8) +HF ,
+ (0x41<<8) +HF +VF ,
+ (0x42<<8) +HF +VF ,
+ (0x43<<8) +HF ,
+ (0x44<<8) +HF +VF ,
+ (0x45<<8) +HF ,
+ (0x40<<8) ,
+ (0x41<<8) +VF ,
+ (0x42<<8) +VF ,
+ (0x43<<8) ,
+ (0x44<<8) +VF ,
+ (0x45<<8) ,
+ (0x46<<8) ,
+ (0x47<<8) +VF ,
+ (0x48<<8) +XF+VF ,
+ (0x49<<8) +XF ,
+ (0x50<<8) +HF +VF ,
+ (0x51<<8) +HF ,
+ (0x52<<8) +HF ,
+ (0x53<<8) +HF +VF ,
+ (0x54<<8) +HF ,
+ (0x55<<8) +HF +VF ,
+ (0x50<<8) +VF ,
+ (0x51<<8) ,
+ (0x52<<8) ,
+ (0x53<<8) +VF ,
+ (0x54<<8) ,
+ (0x55<<8) +VF ,
+ (0x56<<8) +VF ,
+ (0x57<<8) ,
+ (0x58<<8) +XF ,
+ (0x59<<8) +XF+VF ,
+ (0x60<<8) +YF+HF +VF ,
+ (0x61<<8) +YF+HF ,
+ (0x62<<8) +YF+HF ,
+ (0x63<<8) +YF+HF +VF ,
+ (0x64<<8) +YF+HF ,
+ (0x65<<8) +YF+HF +VF ,
+ (0x60<<8) +YF +VF ,
+ (0x61<<8) +YF ,
+ (0x62<<8) +YF ,
+ (0x63<<8) +YF +VF ,
+ (0x64<<8) +YF ,
+ (0x65<<8) +YF +VF ,
+ (0x66<<8) +YF +VF ,
+ (0x67<<8) +YF ,
+ (0x68<<8) +YF +XF ,
+ (0x69<<8) +YF +XF+VF ,
+ (0x70<<8) +YF+HF ,
+ (0x71<<8) +YF+HF +VF ,
+ (0x72<<8) +YF+HF +VF ,
+ (0x73<<8) +YF+HF ,
+ (0x74<<8) +YF+HF +VF ,
+ (0x75<<8) +YF+HF ,
+ (0x70<<8) +YF ,
+ (0x71<<8) +YF +VF ,
+ (0x72<<8) +YF +VF ,
+ (0x73<<8) +YF ,
+ (0x74<<8) +YF +VF ,
+ (0x75<<8) +YF ,
+ (0x76<<8) +YF ,
+ (0x77<<8) +YF +VF ,
+ (0x78<<8) +YF +XF+VF ,
+ (0x79<<8) +YF +XF ,
+ (0x80<<8)+SF +HF ,
+ (0x81<<8)+SF +HF +VF ,
+ (0x82<<8)+SF +HF +VF ,
+ (0x83<<8)+SF +HF ,
+ (0x84<<8)+SF +HF +VF ,
+ (0x85<<8)+SF +HF ,
+ (0x80<<8)+SF ,
+ (0x81<<8)+SF +VF ,
+ (0x82<<8)+SF +VF ,
+ (0x83<<8)+SF ,
+ (0x84<<8)+SF +VF ,
+ (0x85<<8)+SF ,
+ (0x86<<8)+SF ,
+ (0x87<<8)+SF +VF ,
+ (0x88<<8)+SF +XF+VF ,
+ (0x89<<8)+SF +XF ,
+ (0x90<<8)+SF +HF +VF ,
+ (0x91<<8)+SF +HF ,
+ (0x92<<8)+SF +HF ,
+ (0x93<<8)+SF +HF +VF ,
+ (0x94<<8)+SF +HF ,
+ (0x95<<8)+SF +HF +VF ,
+ (0x90<<8)+SF +VF ,
+ (0x91<<8)+SF ,
+ (0x92<<8)+SF ,
+ (0x93<<8)+SF +VF ,
+ (0x94<<8)+SF ,
+ (0x95<<8)+SF +VF ,
+ (0x96<<8)+SF +VF ,
+ (0x97<<8)+SF ,
+ (0x98<<8)+SF +XF ,
+ (0x99<<8)+SF +XF+VF ,
+ (0x00<<8) +ZF +HF +VF +CF,
+ (0x01<<8) +HF +CF,
+ (0x02<<8) +HF +CF,
+ (0x03<<8) +HF +VF +CF,
+ (0x04<<8) +HF +CF,
+ (0x05<<8) +HF +VF +CF,
+ (0x00<<8) +ZF +VF +CF,
+ (0x01<<8) +CF,
+ (0x02<<8) +CF,
+ (0x03<<8) +VF +CF,
+ (0x04<<8) +CF,
+ (0x05<<8) +VF +CF,
+ (0x06<<8) +VF +CF,
+ (0x07<<8) +CF,
+ (0x08<<8) +XF +CF,
+ (0x09<<8) +XF+VF +CF,
+ (0x10<<8) +HF +CF,
+ (0x11<<8) +HF +VF +CF,
+ (0x12<<8) +HF +VF +CF,
+ (0x13<<8) +HF +CF,
+ (0x14<<8) +HF +VF +CF,
+ (0x15<<8) +HF +CF,
+ (0x10<<8) +CF,
+ (0x11<<8) +VF +CF,
+ (0x12<<8) +VF +CF,
+ (0x13<<8) +CF,
+ (0x14<<8) +VF +CF,
+ (0x15<<8) +CF,
+ (0x16<<8) +CF,
+ (0x17<<8) +VF +CF,
+ (0x18<<8) +XF+VF +CF,
+ (0x19<<8) +XF +CF,
+ (0x20<<8) +YF+HF +CF,
+ (0x21<<8) +YF+HF +VF +CF,
+ (0x22<<8) +YF+HF +VF +CF,
+ (0x23<<8) +YF+HF +CF,
+ (0x24<<8) +YF+HF +VF +CF,
+ (0x25<<8) +YF+HF +CF,
+ (0x20<<8) +YF +CF,
+ (0x21<<8) +YF +VF +CF,
+ (0x22<<8) +YF +VF +CF,
+ (0x23<<8) +YF +CF,
+ (0x24<<8) +YF +VF +CF,
+ (0x25<<8) +YF +CF,
+ (0x26<<8) +YF +CF,
+ (0x27<<8) +YF +VF +CF,
+ (0x28<<8) +YF +XF+VF +CF,
+ (0x29<<8) +YF +XF +CF,
+ (0x30<<8) +YF+HF +VF +CF,
+ (0x31<<8) +YF+HF +CF,
+ (0x32<<8) +YF+HF +CF,
+ (0x33<<8) +YF+HF +VF +CF,
+ (0x34<<8) +YF+HF +CF,
+ (0x35<<8) +YF+HF +VF +CF,
+ (0x30<<8) +YF +VF +CF,
+ (0x31<<8) +YF +CF,
+ (0x32<<8) +YF +CF,
+ (0x33<<8) +YF +VF +CF,
+ (0x34<<8) +YF +CF,
+ (0x35<<8) +YF +VF +CF,
+ (0x36<<8) +YF +VF +CF,
+ (0x37<<8) +YF +CF,
+ (0x38<<8) +YF +XF +CF,
+ (0x39<<8) +YF +XF+VF +CF,
+ (0x40<<8) +HF +CF,
+ (0x41<<8) +HF +VF +CF,
+ (0x42<<8) +HF +VF +CF,
+ (0x43<<8) +HF +CF,
+ (0x44<<8) +HF +VF +CF,
+ (0x45<<8) +HF +CF,
+ (0x40<<8) +CF,
+ (0x41<<8) +VF +CF,
+ (0x42<<8) +VF +CF,
+ (0x43<<8) +CF,
+ (0x44<<8) +VF +CF,
+ (0x45<<8) +CF,
+ (0x46<<8) +CF,
+ (0x47<<8) +VF +CF,
+ (0x48<<8) +XF+VF +CF,
+ (0x49<<8) +XF +CF,
+ (0x50<<8) +HF +VF +CF,
+ (0x51<<8) +HF +CF,
+ (0x52<<8) +HF +CF,
+ (0x53<<8) +HF +VF +CF,
+ (0x54<<8) +HF +CF,
+ (0x55<<8) +HF +VF +CF,
+ (0x50<<8) +VF +CF,
+ (0x51<<8) +CF,
+ (0x52<<8) +CF,
+ (0x53<<8) +VF +CF,
+ (0x54<<8) +CF,
+ (0x55<<8) +VF +CF,
+ (0x56<<8) +VF +CF,
+ (0x57<<8) +CF,
+ (0x58<<8) +XF +CF,
+ (0x59<<8) +XF+VF +CF,
+ (0x60<<8) +YF+HF +VF +CF,
+ (0x61<<8) +YF+HF +CF,
+ (0x62<<8) +YF+HF +CF,
+ (0x63<<8) +YF+HF +VF +CF,
+ (0x64<<8) +YF+HF +CF,
+ (0x65<<8) +YF+HF +VF +CF,
+ (0x60<<8) +YF +VF +CF,
+ (0x61<<8) +YF +CF,
+ (0x62<<8) +YF +CF,
+ (0x63<<8) +YF +VF +CF,
+ (0x64<<8) +YF +CF,
+ (0x65<<8) +YF +VF +CF,
+ (0x66<<8) +YF +VF +CF,
+ (0x67<<8) +YF +CF,
+ (0x68<<8) +YF +XF +CF,
+ (0x69<<8) +YF +XF+VF +CF,
+ (0x70<<8) +YF+HF +CF,
+ (0x71<<8) +YF+HF +VF +CF,
+ (0x72<<8) +YF+HF +VF +CF,
+ (0x73<<8) +YF+HF +CF,
+ (0x74<<8) +YF+HF +VF +CF,
+ (0x75<<8) +YF+HF +CF,
+ (0x70<<8) +YF +CF,
+ (0x71<<8) +YF +VF +CF,
+ (0x72<<8) +YF +VF +CF,
+ (0x73<<8) +YF +CF,
+ (0x74<<8) +YF +VF +CF,
+ (0x75<<8) +YF +CF,
+ (0x76<<8) +YF +CF,
+ (0x77<<8) +YF +VF +CF,
+ (0x78<<8) +YF +XF+VF +CF,
+ (0x79<<8) +YF +XF +CF,
+ (0x80<<8)+SF +HF +CF,
+ (0x81<<8)+SF +HF +VF +CF,
+ (0x82<<8)+SF +HF +VF +CF,
+ (0x83<<8)+SF +HF +CF,
+ (0x84<<8)+SF +HF +VF +CF,
+ (0x85<<8)+SF +HF +CF,
+ (0x80<<8)+SF +CF,
+ (0x81<<8)+SF +VF +CF,
+ (0x82<<8)+SF +VF +CF,
+ (0x83<<8)+SF +CF,
+ (0x84<<8)+SF +VF +CF,
+ (0x85<<8)+SF +CF,
+ (0x86<<8)+SF +CF,
+ (0x87<<8)+SF +VF +CF,
+ (0x88<<8)+SF +XF+VF +CF,
+ (0x89<<8)+SF +XF +CF,
+ (0x90<<8)+SF +HF +VF +CF,
+ (0x91<<8)+SF +HF +CF,
+ (0x92<<8)+SF +HF +CF,
+ (0x93<<8)+SF +HF +VF +CF,
+ (0x94<<8)+SF +HF +CF,
+ (0x95<<8)+SF +HF +VF +CF,
+ (0x90<<8)+SF +VF +CF,
+ (0x91<<8)+SF +CF,
+ (0x92<<8)+SF +CF,
+ (0x93<<8)+SF +VF +CF,
+ (0x94<<8)+SF +CF,
+ (0x95<<8)+SF +VF +CF,
+ (0x96<<8)+SF +VF +CF,
+ (0x97<<8)+SF +CF,
+ (0x98<<8)+SF +XF +CF,
+ (0x99<<8)+SF +XF+VF +CF,
+ (0xA0<<8)+SF +YF+HF +VF +CF,
+ (0xA1<<8)+SF +YF+HF +CF,
+ (0xA2<<8)+SF +YF+HF +CF,
+ (0xA3<<8)+SF +YF+HF +VF +CF,
+ (0xA4<<8)+SF +YF+HF +CF,
+ (0xA5<<8)+SF +YF+HF +VF +CF,
+ (0xA0<<8)+SF +YF +VF +CF,
+ (0xA1<<8)+SF +YF +CF,
+ (0xA2<<8)+SF +YF +CF,
+ (0xA3<<8)+SF +YF +VF +CF,
+ (0xA4<<8)+SF +YF +CF,
+ (0xA5<<8)+SF +YF +VF +CF,
+ (0xA6<<8)+SF +YF +VF +CF,
+ (0xA7<<8)+SF +YF +CF,
+ (0xA8<<8)+SF +YF +XF +CF,
+ (0xA9<<8)+SF +YF +XF+VF +CF,
+ (0xB0<<8)+SF +YF+HF +CF,
+ (0xB1<<8)+SF +YF+HF +VF +CF,
+ (0xB2<<8)+SF +YF+HF +VF +CF,
+ (0xB3<<8)+SF +YF+HF +CF,
+ (0xB4<<8)+SF +YF+HF +VF +CF,
+ (0xB5<<8)+SF +YF+HF +CF,
+ (0xB0<<8)+SF +YF +CF,
+ (0xB1<<8)+SF +YF +VF +CF,
+ (0xB2<<8)+SF +YF +VF +CF,
+ (0xB3<<8)+SF +YF +CF,
+ (0xB4<<8)+SF +YF +VF +CF,
+ (0xB5<<8)+SF +YF +CF,
+ (0xB6<<8)+SF +YF +CF,
+ (0xB7<<8)+SF +YF +VF +CF,
+ (0xB8<<8)+SF +YF +XF+VF +CF,
+ (0xB9<<8)+SF +YF +XF +CF,
+ (0xC0<<8)+SF +HF +VF +CF,
+ (0xC1<<8)+SF +HF +CF,
+ (0xC2<<8)+SF +HF +CF,
+ (0xC3<<8)+SF +HF +VF +CF,
+ (0xC4<<8)+SF +HF +CF,
+ (0xC5<<8)+SF +HF +VF +CF,
+ (0xC0<<8)+SF +VF +CF,
+ (0xC1<<8)+SF +CF,
+ (0xC2<<8)+SF +CF,
+ (0xC3<<8)+SF +VF +CF,
+ (0xC4<<8)+SF +CF,
+ (0xC5<<8)+SF +VF +CF,
+ (0xC6<<8)+SF +VF +CF,
+ (0xC7<<8)+SF +CF,
+ (0xC8<<8)+SF +XF +CF,
+ (0xC9<<8)+SF +XF+VF +CF,
+ (0xD0<<8)+SF +HF +CF,
+ (0xD1<<8)+SF +HF +VF +CF,
+ (0xD2<<8)+SF +HF +VF +CF,
+ (0xD3<<8)+SF +HF +CF,
+ (0xD4<<8)+SF +HF +VF +CF,
+ (0xD5<<8)+SF +HF +CF,
+ (0xD0<<8)+SF +CF,
+ (0xD1<<8)+SF +VF +CF,
+ (0xD2<<8)+SF +VF +CF,
+ (0xD3<<8)+SF +CF,
+ (0xD4<<8)+SF +VF +CF,
+ (0xD5<<8)+SF +CF,
+ (0xD6<<8)+SF +CF,
+ (0xD7<<8)+SF +VF +CF,
+ (0xD8<<8)+SF +XF+VF +CF,
+ (0xD9<<8)+SF +XF +CF,
+ (0xE0<<8)+SF +YF+HF +CF,
+ (0xE1<<8)+SF +YF+HF +VF +CF,
+ (0xE2<<8)+SF +YF+HF +VF +CF,
+ (0xE3<<8)+SF +YF+HF +CF,
+ (0xE4<<8)+SF +YF+HF +VF +CF,
+ (0xE5<<8)+SF +YF+HF +CF,
+ (0xE0<<8)+SF +YF +CF,
+ (0xE1<<8)+SF +YF +VF +CF,
+ (0xE2<<8)+SF +YF +VF +CF,
+ (0xE3<<8)+SF +YF +CF,
+ (0xE4<<8)+SF +YF +VF +CF,
+ (0xE5<<8)+SF +YF +CF,
+ (0xE6<<8)+SF +YF +CF,
+ (0xE7<<8)+SF +YF +VF +CF,
+ (0xE8<<8)+SF +YF +XF+VF +CF,
+ (0xE9<<8)+SF +YF +XF +CF,
+ (0xF0<<8)+SF +YF+HF +VF +CF,
+ (0xF1<<8)+SF +YF+HF +CF,
+ (0xF2<<8)+SF +YF+HF +CF,
+ (0xF3<<8)+SF +YF+HF +VF +CF,
+ (0xF4<<8)+SF +YF+HF +CF,
+ (0xF5<<8)+SF +YF+HF +VF +CF,
+ (0xF0<<8)+SF +YF +VF +CF,
+ (0xF1<<8)+SF +YF +CF,
+ (0xF2<<8)+SF +YF +CF,
+ (0xF3<<8)+SF +YF +VF +CF,
+ (0xF4<<8)+SF +YF +CF,
+ (0xF5<<8)+SF +YF +VF +CF,
+ (0xF6<<8)+SF +YF +VF +CF,
+ (0xF7<<8)+SF +YF +CF,
+ (0xF8<<8)+SF +YF +XF +CF,
+ (0xF9<<8)+SF +YF +XF+VF +CF,
+ (0x00<<8) +ZF +HF +VF +CF,
+ (0x01<<8) +HF +CF,
+ (0x02<<8) +HF +CF,
+ (0x03<<8) +HF +VF +CF,
+ (0x04<<8) +HF +CF,
+ (0x05<<8) +HF +VF +CF,
+ (0x00<<8) +ZF +VF +CF,
+ (0x01<<8) +CF,
+ (0x02<<8) +CF,
+ (0x03<<8) +VF +CF,
+ (0x04<<8) +CF,
+ (0x05<<8) +VF +CF,
+ (0x06<<8) +VF +CF,
+ (0x07<<8) +CF,
+ (0x08<<8) +XF +CF,
+ (0x09<<8) +XF+VF +CF,
+ (0x10<<8) +HF +CF,
+ (0x11<<8) +HF +VF +CF,
+ (0x12<<8) +HF +VF +CF,
+ (0x13<<8) +HF +CF,
+ (0x14<<8) +HF +VF +CF,
+ (0x15<<8) +HF +CF,
+ (0x10<<8) +CF,
+ (0x11<<8) +VF +CF,
+ (0x12<<8) +VF +CF,
+ (0x13<<8) +CF,
+ (0x14<<8) +VF +CF,
+ (0x15<<8) +CF,
+ (0x16<<8) +CF,
+ (0x17<<8) +VF +CF,
+ (0x18<<8) +XF+VF +CF,
+ (0x19<<8) +XF +CF,
+ (0x20<<8) +YF+HF +CF,
+ (0x21<<8) +YF+HF +VF +CF,
+ (0x22<<8) +YF+HF +VF +CF,
+ (0x23<<8) +YF+HF +CF,
+ (0x24<<8) +YF+HF +VF +CF,
+ (0x25<<8) +YF+HF +CF,
+ (0x20<<8) +YF +CF,
+ (0x21<<8) +YF +VF +CF,
+ (0x22<<8) +YF +VF +CF,
+ (0x23<<8) +YF +CF,
+ (0x24<<8) +YF +VF +CF,
+ (0x25<<8) +YF +CF,
+ (0x26<<8) +YF +CF,
+ (0x27<<8) +YF +VF +CF,
+ (0x28<<8) +YF +XF+VF +CF,
+ (0x29<<8) +YF +XF +CF,
+ (0x30<<8) +YF+HF +VF +CF,
+ (0x31<<8) +YF+HF +CF,
+ (0x32<<8) +YF+HF +CF,
+ (0x33<<8) +YF+HF +VF +CF,
+ (0x34<<8) +YF+HF +CF,
+ (0x35<<8) +YF+HF +VF +CF,
+ (0x30<<8) +YF +VF +CF,
+ (0x31<<8) +YF +CF,
+ (0x32<<8) +YF +CF,
+ (0x33<<8) +YF +VF +CF,
+ (0x34<<8) +YF +CF,
+ (0x35<<8) +YF +VF +CF,
+ (0x36<<8) +YF +VF +CF,
+ (0x37<<8) +YF +CF,
+ (0x38<<8) +YF +XF +CF,
+ (0x39<<8) +YF +XF+VF +CF,
+ (0x40<<8) +HF +CF,
+ (0x41<<8) +HF +VF +CF,
+ (0x42<<8) +HF +VF +CF,
+ (0x43<<8) +HF +CF,
+ (0x44<<8) +HF +VF +CF,
+ (0x45<<8) +HF +CF,
+ (0x40<<8) +CF,
+ (0x41<<8) +VF +CF,
+ (0x42<<8) +VF +CF,
+ (0x43<<8) +CF,
+ (0x44<<8) +VF +CF,
+ (0x45<<8) +CF,
+ (0x46<<8) +CF,
+ (0x47<<8) +VF +CF,
+ (0x48<<8) +XF+VF +CF,
+ (0x49<<8) +XF +CF,
+ (0x50<<8) +HF +VF +CF,
+ (0x51<<8) +HF +CF,
+ (0x52<<8) +HF +CF,
+ (0x53<<8) +HF +VF +CF,
+ (0x54<<8) +HF +CF,
+ (0x55<<8) +HF +VF +CF,
+ (0x50<<8) +VF +CF,
+ (0x51<<8) +CF,
+ (0x52<<8) +CF,
+ (0x53<<8) +VF +CF,
+ (0x54<<8) +CF,
+ (0x55<<8) +VF +CF,
+ (0x56<<8) +VF +CF,
+ (0x57<<8) +CF,
+ (0x58<<8) +XF +CF,
+ (0x59<<8) +XF+VF +CF,
+ (0x60<<8) +YF+HF +VF +CF,
+ (0x61<<8) +YF+HF +CF,
+ (0x62<<8) +YF+HF +CF,
+ (0x63<<8) +YF+HF +VF +CF,
+ (0x64<<8) +YF+HF +CF,
+ (0x65<<8) +YF+HF +VF +CF,
+ (0x06<<8) +VF ,
+ (0x07<<8) ,
+ (0x08<<8) +XF ,
+ (0x09<<8) +XF+VF ,
+ (0x0A<<8) +XF+VF ,
+ (0x0B<<8) +XF ,
+ (0x0C<<8) +XF+VF ,
+ (0x0D<<8) +XF ,
+ (0x0E<<8) +XF ,
+ (0x0F<<8) +XF+VF ,
+ (0x10<<8) +HF ,
+ (0x11<<8) +HF +VF ,
+ (0x12<<8) +HF +VF ,
+ (0x13<<8) +HF ,
+ (0x14<<8) +HF +VF ,
+ (0x15<<8) +HF ,
+ (0x16<<8) ,
+ (0x17<<8) +VF ,
+ (0x18<<8) +XF+VF ,
+ (0x19<<8) +XF ,
+ (0x1A<<8) +XF ,
+ (0x1B<<8) +XF+VF ,
+ (0x1C<<8) +XF ,
+ (0x1D<<8) +XF+VF ,
+ (0x1E<<8) +XF+VF ,
+ (0x1F<<8) +XF ,
+ (0x20<<8) +YF+HF ,
+ (0x21<<8) +YF+HF +VF ,
+ (0x22<<8) +YF+HF +VF ,
+ (0x23<<8) +YF+HF ,
+ (0x24<<8) +YF+HF +VF ,
+ (0x25<<8) +YF+HF ,
+ (0x26<<8) +YF ,
+ (0x27<<8) +YF +VF ,
+ (0x28<<8) +YF +XF+VF ,
+ (0x29<<8) +YF +XF ,
+ (0x2A<<8) +YF +XF ,
+ (0x2B<<8) +YF +XF+VF ,
+ (0x2C<<8) +YF +XF ,
+ (0x2D<<8) +YF +XF+VF ,
+ (0x2E<<8) +YF +XF+VF ,
+ (0x2F<<8) +YF +XF ,
+ (0x30<<8) +YF+HF +VF ,
+ (0x31<<8) +YF+HF ,
+ (0x32<<8) +YF+HF ,
+ (0x33<<8) +YF+HF +VF ,
+ (0x34<<8) +YF+HF ,
+ (0x35<<8) +YF+HF +VF ,
+ (0x36<<8) +YF +VF ,
+ (0x37<<8) +YF ,
+ (0x38<<8) +YF +XF ,
+ (0x39<<8) +YF +XF+VF ,
+ (0x3A<<8) +YF +XF+VF ,
+ (0x3B<<8) +YF +XF ,
+ (0x3C<<8) +YF +XF+VF ,
+ (0x3D<<8) +YF +XF ,
+ (0x3E<<8) +YF +XF ,
+ (0x3F<<8) +YF +XF+VF ,
+ (0x40<<8) +HF ,
+ (0x41<<8) +HF +VF ,
+ (0x42<<8) +HF +VF ,
+ (0x43<<8) +HF ,
+ (0x44<<8) +HF +VF ,
+ (0x45<<8) +HF ,
+ (0x46<<8) ,
+ (0x47<<8) +VF ,
+ (0x48<<8) +XF+VF ,
+ (0x49<<8) +XF ,
+ (0x4A<<8) +XF ,
+ (0x4B<<8) +XF+VF ,
+ (0x4C<<8) +XF ,
+ (0x4D<<8) +XF+VF ,
+ (0x4E<<8) +XF+VF ,
+ (0x4F<<8) +XF ,
+ (0x50<<8) +HF +VF ,
+ (0x51<<8) +HF ,
+ (0x52<<8) +HF ,
+ (0x53<<8) +HF +VF ,
+ (0x54<<8) +HF ,
+ (0x55<<8) +HF +VF ,
+ (0x56<<8) +VF ,
+ (0x57<<8) ,
+ (0x58<<8) +XF ,
+ (0x59<<8) +XF+VF ,
+ (0x5A<<8) +XF+VF ,
+ (0x5B<<8) +XF ,
+ (0x5C<<8) +XF+VF ,
+ (0x5D<<8) +XF ,
+ (0x5E<<8) +XF ,
+ (0x5F<<8) +XF+VF ,
+ (0x60<<8) +YF+HF +VF ,
+ (0x61<<8) +YF+HF ,
+ (0x62<<8) +YF+HF ,
+ (0x63<<8) +YF+HF +VF ,
+ (0x64<<8) +YF+HF ,
+ (0x65<<8) +YF+HF +VF ,
+ (0x66<<8) +YF +VF ,
+ (0x67<<8) +YF ,
+ (0x68<<8) +YF +XF ,
+ (0x69<<8) +YF +XF+VF ,
+ (0x6A<<8) +YF +XF+VF ,
+ (0x6B<<8) +YF +XF ,
+ (0x6C<<8) +YF +XF+VF ,
+ (0x6D<<8) +YF +XF ,
+ (0x6E<<8) +YF +XF ,
+ (0x6F<<8) +YF +XF+VF ,
+ (0x70<<8) +YF+HF ,
+ (0x71<<8) +YF+HF +VF ,
+ (0x72<<8) +YF+HF +VF ,
+ (0x73<<8) +YF+HF ,
+ (0x74<<8) +YF+HF +VF ,
+ (0x75<<8) +YF+HF ,
+ (0x76<<8) +YF ,
+ (0x77<<8) +YF +VF ,
+ (0x78<<8) +YF +XF+VF ,
+ (0x79<<8) +YF +XF ,
+ (0x7A<<8) +YF +XF ,
+ (0x7B<<8) +YF +XF+VF ,
+ (0x7C<<8) +YF +XF ,
+ (0x7D<<8) +YF +XF+VF ,
+ (0x7E<<8) +YF +XF+VF ,
+ (0x7F<<8) +YF +XF ,
+ (0x80<<8)+SF +HF ,
+ (0x81<<8)+SF +HF +VF ,
+ (0x82<<8)+SF +HF +VF ,
+ (0x83<<8)+SF +HF ,
+ (0x84<<8)+SF +HF +VF ,
+ (0x85<<8)+SF +HF ,
+ (0x86<<8)+SF ,
+ (0x87<<8)+SF +VF ,
+ (0x88<<8)+SF +XF+VF ,
+ (0x89<<8)+SF +XF ,
+ (0x8A<<8)+SF +XF ,
+ (0x8B<<8)+SF +XF+VF ,
+ (0x8C<<8)+SF +XF ,
+ (0x8D<<8)+SF +XF+VF ,
+ (0x8E<<8)+SF +XF+VF ,
+ (0x8F<<8)+SF +XF ,
+ (0x90<<8)+SF +HF +VF ,
+ (0x91<<8)+SF +HF ,
+ (0x92<<8)+SF +HF ,
+ (0x93<<8)+SF +HF +VF ,
+ (0x94<<8)+SF +HF ,
+ (0x95<<8)+SF +HF +VF ,
+ (0x96<<8)+SF +VF ,
+ (0x97<<8)+SF ,
+ (0x98<<8)+SF +XF ,
+ (0x99<<8)+SF +XF+VF ,
+ (0x9A<<8)+SF +XF+VF ,
+ (0x9B<<8)+SF +XF ,
+ (0x9C<<8)+SF +XF+VF ,
+ (0x9D<<8)+SF +XF ,
+ (0x9E<<8)+SF +XF ,
+ (0x9F<<8)+SF +XF+VF ,
+ (0x00<<8) +ZF +HF +VF +CF,
+ (0x01<<8) +HF +CF,
+ (0x02<<8) +HF +CF,
+ (0x03<<8) +HF +VF +CF,
+ (0x04<<8) +HF +CF,
+ (0x05<<8) +HF +VF +CF,
+ (0x06<<8) +VF +CF,
+ (0x07<<8) +CF,
+ (0x08<<8) +XF +CF,
+ (0x09<<8) +XF+VF +CF,
+ (0x0A<<8) +XF+VF +CF,
+ (0x0B<<8) +XF +CF,
+ (0x0C<<8) +XF+VF +CF,
+ (0x0D<<8) +XF +CF,
+ (0x0E<<8) +XF +CF,
+ (0x0F<<8) +XF+VF +CF,
+ (0x10<<8) +HF +CF,
+ (0x11<<8) +HF +VF +CF,
+ (0x12<<8) +HF +VF +CF,
+ (0x13<<8) +HF +CF,
+ (0x14<<8) +HF +VF +CF,
+ (0x15<<8) +HF +CF,
+ (0x16<<8) +CF,
+ (0x17<<8) +VF +CF,
+ (0x18<<8) +XF+VF +CF,
+ (0x19<<8) +XF +CF,
+ (0x1A<<8) +XF +CF,
+ (0x1B<<8) +XF+VF +CF,
+ (0x1C<<8) +XF +CF,
+ (0x1D<<8) +XF+VF +CF,
+ (0x1E<<8) +XF+VF +CF,
+ (0x1F<<8) +XF +CF,
+ (0x20<<8) +YF+HF +CF,
+ (0x21<<8) +YF+HF +VF +CF,
+ (0x22<<8) +YF+HF +VF +CF,
+ (0x23<<8) +YF+HF +CF,
+ (0x24<<8) +YF+HF +VF +CF,
+ (0x25<<8) +YF+HF +CF,
+ (0x26<<8) +YF +CF,
+ (0x27<<8) +YF +VF +CF,
+ (0x28<<8) +YF +XF+VF +CF,
+ (0x29<<8) +YF +XF +CF,
+ (0x2A<<8) +YF +XF +CF,
+ (0x2B<<8) +YF +XF+VF +CF,
+ (0x2C<<8) +YF +XF +CF,
+ (0x2D<<8) +YF +XF+VF +CF,
+ (0x2E<<8) +YF +XF+VF +CF,
+ (0x2F<<8) +YF +XF +CF,
+ (0x30<<8) +YF+HF +VF +CF,
+ (0x31<<8) +YF+HF +CF,
+ (0x32<<8) +YF+HF +CF,
+ (0x33<<8) +YF+HF +VF +CF,
+ (0x34<<8) +YF+HF +CF,
+ (0x35<<8) +YF+HF +VF +CF,
+ (0x36<<8) +YF +VF +CF,
+ (0x37<<8) +YF +CF,
+ (0x38<<8) +YF +XF +CF,
+ (0x39<<8) +YF +XF+VF +CF,
+ (0x3A<<8) +YF +XF+VF +CF,
+ (0x3B<<8) +YF +XF +CF,
+ (0x3C<<8) +YF +XF+VF +CF,
+ (0x3D<<8) +YF +XF +CF,
+ (0x3E<<8) +YF +XF +CF,
+ (0x3F<<8) +YF +XF+VF +CF,
+ (0x40<<8) +HF +CF,
+ (0x41<<8) +HF +VF +CF,
+ (0x42<<8) +HF +VF +CF,
+ (0x43<<8) +HF +CF,
+ (0x44<<8) +HF +VF +CF,
+ (0x45<<8) +HF +CF,
+ (0x46<<8) +CF,
+ (0x47<<8) +VF +CF,
+ (0x48<<8) +XF+VF +CF,
+ (0x49<<8) +XF +CF,
+ (0x4A<<8) +XF +CF,
+ (0x4B<<8) +XF+VF +CF,
+ (0x4C<<8) +XF +CF,
+ (0x4D<<8) +XF+VF +CF,
+ (0x4E<<8) +XF+VF +CF,
+ (0x4F<<8) +XF +CF,
+ (0x50<<8) +HF +VF +CF,
+ (0x51<<8) +HF +CF,
+ (0x52<<8) +HF +CF,
+ (0x53<<8) +HF +VF +CF,
+ (0x54<<8) +HF +CF,
+ (0x55<<8) +HF +VF +CF,
+ (0x56<<8) +VF +CF,
+ (0x57<<8) +CF,
+ (0x58<<8) +XF +CF,
+ (0x59<<8) +XF+VF +CF,
+ (0x5A<<8) +XF+VF +CF,
+ (0x5B<<8) +XF +CF,
+ (0x5C<<8) +XF+VF +CF,
+ (0x5D<<8) +XF +CF,
+ (0x5E<<8) +XF +CF,
+ (0x5F<<8) +XF+VF +CF,
+ (0x60<<8) +YF+HF +VF +CF,
+ (0x61<<8) +YF+HF +CF,
+ (0x62<<8) +YF+HF +CF,
+ (0x63<<8) +YF+HF +VF +CF,
+ (0x64<<8) +YF+HF +CF,
+ (0x65<<8) +YF+HF +VF +CF,
+ (0x66<<8) +YF +VF +CF,
+ (0x67<<8) +YF +CF,
+ (0x68<<8) +YF +XF +CF,
+ (0x69<<8) +YF +XF+VF +CF,
+ (0x6A<<8) +YF +XF+VF +CF,
+ (0x6B<<8) +YF +XF +CF,
+ (0x6C<<8) +YF +XF+VF +CF,
+ (0x6D<<8) +YF +XF +CF,
+ (0x6E<<8) +YF +XF +CF,
+ (0x6F<<8) +YF +XF+VF +CF,
+ (0x70<<8) +YF+HF +CF,
+ (0x71<<8) +YF+HF +VF +CF,
+ (0x72<<8) +YF+HF +VF +CF,
+ (0x73<<8) +YF+HF +CF,
+ (0x74<<8) +YF+HF +VF +CF,
+ (0x75<<8) +YF+HF +CF,
+ (0x76<<8) +YF +CF,
+ (0x77<<8) +YF +VF +CF,
+ (0x78<<8) +YF +XF+VF +CF,
+ (0x79<<8) +YF +XF +CF,
+ (0x7A<<8) +YF +XF +CF,
+ (0x7B<<8) +YF +XF+VF +CF,
+ (0x7C<<8) +YF +XF +CF,
+ (0x7D<<8) +YF +XF+VF +CF,
+ (0x7E<<8) +YF +XF+VF +CF,
+ (0x7F<<8) +YF +XF +CF,
+ (0x80<<8)+SF +HF +CF,
+ (0x81<<8)+SF +HF +VF +CF,
+ (0x82<<8)+SF +HF +VF +CF,
+ (0x83<<8)+SF +HF +CF,
+ (0x84<<8)+SF +HF +VF +CF,
+ (0x85<<8)+SF +HF +CF,
+ (0x86<<8)+SF +CF,
+ (0x87<<8)+SF +VF +CF,
+ (0x88<<8)+SF +XF+VF +CF,
+ (0x89<<8)+SF +XF +CF,
+ (0x8A<<8)+SF +XF +CF,
+ (0x8B<<8)+SF +XF+VF +CF,
+ (0x8C<<8)+SF +XF +CF,
+ (0x8D<<8)+SF +XF+VF +CF,
+ (0x8E<<8)+SF +XF+VF +CF,
+ (0x8F<<8)+SF +XF +CF,
+ (0x90<<8)+SF +HF +VF +CF,
+ (0x91<<8)+SF +HF +CF,
+ (0x92<<8)+SF +HF +CF,
+ (0x93<<8)+SF +HF +VF +CF,
+ (0x94<<8)+SF +HF +CF,
+ (0x95<<8)+SF +HF +VF +CF,
+ (0x96<<8)+SF +VF +CF,
+ (0x97<<8)+SF +CF,
+ (0x98<<8)+SF +XF +CF,
+ (0x99<<8)+SF +XF+VF +CF,
+ (0x9A<<8)+SF +XF+VF +CF,
+ (0x9B<<8)+SF +XF +CF,
+ (0x9C<<8)+SF +XF+VF +CF,
+ (0x9D<<8)+SF +XF +CF,
+ (0x9E<<8)+SF +XF +CF,
+ (0x9F<<8)+SF +XF+VF +CF,
+ (0xA0<<8)+SF +YF+HF +VF +CF,
+ (0xA1<<8)+SF +YF+HF +CF,
+ (0xA2<<8)+SF +YF+HF +CF,
+ (0xA3<<8)+SF +YF+HF +VF +CF,
+ (0xA4<<8)+SF +YF+HF +CF,
+ (0xA5<<8)+SF +YF+HF +VF +CF,
+ (0xA6<<8)+SF +YF +VF +CF,
+ (0xA7<<8)+SF +YF +CF,
+ (0xA8<<8)+SF +YF +XF +CF,
+ (0xA9<<8)+SF +YF +XF+VF +CF,
+ (0xAA<<8)+SF +YF +XF+VF +CF,
+ (0xAB<<8)+SF +YF +XF +CF,
+ (0xAC<<8)+SF +YF +XF+VF +CF,
+ (0xAD<<8)+SF +YF +XF +CF,
+ (0xAE<<8)+SF +YF +XF +CF,
+ (0xAF<<8)+SF +YF +XF+VF +CF,
+ (0xB0<<8)+SF +YF+HF +CF,
+ (0xB1<<8)+SF +YF+HF +VF +CF,
+ (0xB2<<8)+SF +YF+HF +VF +CF,
+ (0xB3<<8)+SF +YF+HF +CF,
+ (0xB4<<8)+SF +YF+HF +VF +CF,
+ (0xB5<<8)+SF +YF+HF +CF,
+ (0xB6<<8)+SF +YF +CF,
+ (0xB7<<8)+SF +YF +VF +CF,
+ (0xB8<<8)+SF +YF +XF+VF +CF,
+ (0xB9<<8)+SF +YF +XF +CF,
+ (0xBA<<8)+SF +YF +XF +CF,
+ (0xBB<<8)+SF +YF +XF+VF +CF,
+ (0xBC<<8)+SF +YF +XF +CF,
+ (0xBD<<8)+SF +YF +XF+VF +CF,
+ (0xBE<<8)+SF +YF +XF+VF +CF,
+ (0xBF<<8)+SF +YF +XF +CF,
+ (0xC0<<8)+SF +HF +VF +CF,
+ (0xC1<<8)+SF +HF +CF,
+ (0xC2<<8)+SF +HF +CF,
+ (0xC3<<8)+SF +HF +VF +CF,
+ (0xC4<<8)+SF +HF +CF,
+ (0xC5<<8)+SF +HF +VF +CF,
+ (0xC6<<8)+SF +VF +CF,
+ (0xC7<<8)+SF +CF,
+ (0xC8<<8)+SF +XF +CF,
+ (0xC9<<8)+SF +XF+VF +CF,
+ (0xCA<<8)+SF +XF+VF +CF,
+ (0xCB<<8)+SF +XF +CF,
+ (0xCC<<8)+SF +XF+VF +CF,
+ (0xCD<<8)+SF +XF +CF,
+ (0xCE<<8)+SF +XF +CF,
+ (0xCF<<8)+SF +XF+VF +CF,
+ (0xD0<<8)+SF +HF +CF,
+ (0xD1<<8)+SF +HF +VF +CF,
+ (0xD2<<8)+SF +HF +VF +CF,
+ (0xD3<<8)+SF +HF +CF,
+ (0xD4<<8)+SF +HF +VF +CF,
+ (0xD5<<8)+SF +HF +CF,
+ (0xD6<<8)+SF +CF,
+ (0xD7<<8)+SF +VF +CF,
+ (0xD8<<8)+SF +XF+VF +CF,
+ (0xD9<<8)+SF +XF +CF,
+ (0xDA<<8)+SF +XF +CF,
+ (0xDB<<8)+SF +XF+VF +CF,
+ (0xDC<<8)+SF +XF +CF,
+ (0xDD<<8)+SF +XF+VF +CF,
+ (0xDE<<8)+SF +XF+VF +CF,
+ (0xDF<<8)+SF +XF +CF,
+ (0xE0<<8)+SF +YF+HF +CF,
+ (0xE1<<8)+SF +YF+HF +VF +CF,
+ (0xE2<<8)+SF +YF+HF +VF +CF,
+ (0xE3<<8)+SF +YF+HF +CF,
+ (0xE4<<8)+SF +YF+HF +VF +CF,
+ (0xE5<<8)+SF +YF+HF +CF,
+ (0xE6<<8)+SF +YF +CF,
+ (0xE7<<8)+SF +YF +VF +CF,
+ (0xE8<<8)+SF +YF +XF+VF +CF,
+ (0xE9<<8)+SF +YF +XF +CF,
+ (0xEA<<8)+SF +YF +XF +CF,
+ (0xEB<<8)+SF +YF +XF+VF +CF,
+ (0xEC<<8)+SF +YF +XF +CF,
+ (0xED<<8)+SF +YF +XF+VF +CF,
+ (0xEE<<8)+SF +YF +XF+VF +CF,
+ (0xEF<<8)+SF +YF +XF +CF,
+ (0xF0<<8)+SF +YF+HF +VF +CF,
+ (0xF1<<8)+SF +YF+HF +CF,
+ (0xF2<<8)+SF +YF+HF +CF,
+ (0xF3<<8)+SF +YF+HF +VF +CF,
+ (0xF4<<8)+SF +YF+HF +CF,
+ (0xF5<<8)+SF +YF+HF +VF +CF,
+ (0xF6<<8)+SF +YF +VF +CF,
+ (0xF7<<8)+SF +YF +CF,
+ (0xF8<<8)+SF +YF +XF +CF,
+ (0xF9<<8)+SF +YF +XF+VF +CF,
+ (0xFA<<8)+SF +YF +XF+VF +CF,
+ (0xFB<<8)+SF +YF +XF +CF,
+ (0xFC<<8)+SF +YF +XF+VF +CF,
+ (0xFD<<8)+SF +YF +XF +CF,
+ (0xFE<<8)+SF +YF +XF +CF,
+ (0xFF<<8)+SF +YF +XF+VF +CF,
+ (0x00<<8) +ZF +HF +VF +CF,
+ (0x01<<8) +HF +CF,
+ (0x02<<8) +HF +CF,
+ (0x03<<8) +HF +VF +CF,
+ (0x04<<8) +HF +CF,
+ (0x05<<8) +HF +VF +CF,
+ (0x06<<8) +VF +CF,
+ (0x07<<8) +CF,
+ (0x08<<8) +XF +CF,
+ (0x09<<8) +XF+VF +CF,
+ (0x0A<<8) +XF+VF +CF,
+ (0x0B<<8) +XF +CF,
+ (0x0C<<8) +XF+VF +CF,
+ (0x0D<<8) +XF +CF,
+ (0x0E<<8) +XF +CF,
+ (0x0F<<8) +XF+VF +CF,
+ (0x10<<8) +HF +CF,
+ (0x11<<8) +HF +VF +CF,
+ (0x12<<8) +HF +VF +CF,
+ (0x13<<8) +HF +CF,
+ (0x14<<8) +HF +VF +CF,
+ (0x15<<8) +HF +CF,
+ (0x16<<8) +CF,
+ (0x17<<8) +VF +CF,
+ (0x18<<8) +XF+VF +CF,
+ (0x19<<8) +XF +CF,
+ (0x1A<<8) +XF +CF,
+ (0x1B<<8) +XF+VF +CF,
+ (0x1C<<8) +XF +CF,
+ (0x1D<<8) +XF+VF +CF,
+ (0x1E<<8) +XF+VF +CF,
+ (0x1F<<8) +XF +CF,
+ (0x20<<8) +YF+HF +CF,
+ (0x21<<8) +YF+HF +VF +CF,
+ (0x22<<8) +YF+HF +VF +CF,
+ (0x23<<8) +YF+HF +CF,
+ (0x24<<8) +YF+HF +VF +CF,
+ (0x25<<8) +YF+HF +CF,
+ (0x26<<8) +YF +CF,
+ (0x27<<8) +YF +VF +CF,
+ (0x28<<8) +YF +XF+VF +CF,
+ (0x29<<8) +YF +XF +CF,
+ (0x2A<<8) +YF +XF +CF,
+ (0x2B<<8) +YF +XF+VF +CF,
+ (0x2C<<8) +YF +XF +CF,
+ (0x2D<<8) +YF +XF+VF +CF,
+ (0x2E<<8) +YF +XF+VF +CF,
+ (0x2F<<8) +YF +XF +CF,
+ (0x30<<8) +YF+HF +VF +CF,
+ (0x31<<8) +YF+HF +CF,
+ (0x32<<8) +YF+HF +CF,
+ (0x33<<8) +YF+HF +VF +CF,
+ (0x34<<8) +YF+HF +CF,
+ (0x35<<8) +YF+HF +VF +CF,
+ (0x36<<8) +YF +VF +CF,
+ (0x37<<8) +YF +CF,
+ (0x38<<8) +YF +XF +CF,
+ (0x39<<8) +YF +XF+VF +CF,
+ (0x3A<<8) +YF +XF+VF +CF,
+ (0x3B<<8) +YF +XF +CF,
+ (0x3C<<8) +YF +XF+VF +CF,
+ (0x3D<<8) +YF +XF +CF,
+ (0x3E<<8) +YF +XF +CF,
+ (0x3F<<8) +YF +XF+VF +CF,
+ (0x40<<8) +HF +CF,
+ (0x41<<8) +HF +VF +CF,
+ (0x42<<8) +HF +VF +CF,
+ (0x43<<8) +HF +CF,
+ (0x44<<8) +HF +VF +CF,
+ (0x45<<8) +HF +CF,
+ (0x46<<8) +CF,
+ (0x47<<8) +VF +CF,
+ (0x48<<8) +XF+VF +CF,
+ (0x49<<8) +XF +CF,
+ (0x4A<<8) +XF +CF,
+ (0x4B<<8) +XF+VF +CF,
+ (0x4C<<8) +XF +CF,
+ (0x4D<<8) +XF+VF +CF,
+ (0x4E<<8) +XF+VF +CF,
+ (0x4F<<8) +XF +CF,
+ (0x50<<8) +HF +VF +CF,
+ (0x51<<8) +HF +CF,
+ (0x52<<8) +HF +CF,
+ (0x53<<8) +HF +VF +CF,
+ (0x54<<8) +HF +CF,
+ (0x55<<8) +HF +VF +CF,
+ (0x56<<8) +VF +CF,
+ (0x57<<8) +CF,
+ (0x58<<8) +XF +CF,
+ (0x59<<8) +XF+VF +CF,
+ (0x5A<<8) +XF+VF +CF,
+ (0x5B<<8) +XF +CF,
+ (0x5C<<8) +XF+VF +CF,
+ (0x5D<<8) +XF +CF,
+ (0x5E<<8) +XF +CF,
+ (0x5F<<8) +XF+VF +CF,
+ (0x60<<8) +YF+HF +VF +CF,
+ (0x61<<8) +YF+HF +CF,
+ (0x62<<8) +YF+HF +CF,
+ (0x63<<8) +YF+HF +VF +CF,
+ (0x64<<8) +YF+HF +CF,
+ (0x65<<8) +YF+HF +VF +CF,
+ (0x00<<8) +ZF +VF+NF ,
+ (0x01<<8) +NF ,
+ (0x02<<8) +NF ,
+ (0x03<<8) +VF+NF ,
+ (0x04<<8) +NF ,
+ (0x05<<8) +VF+NF ,
+ (0x06<<8) +VF+NF ,
+ (0x07<<8) +NF ,
+ (0x08<<8) +XF +NF ,
+ (0x09<<8) +XF+VF+NF ,
+ (0x04<<8) +NF ,
+ (0x05<<8) +VF+NF ,
+ (0x06<<8) +VF+NF ,
+ (0x07<<8) +NF ,
+ (0x08<<8) +XF +NF ,
+ (0x09<<8) +XF+VF+NF ,
+ (0x10<<8) +NF ,
+ (0x11<<8) +VF+NF ,
+ (0x12<<8) +VF+NF ,
+ (0x13<<8) +NF ,
+ (0x14<<8) +VF+NF ,
+ (0x15<<8) +NF ,
+ (0x16<<8) +NF ,
+ (0x17<<8) +VF+NF ,
+ (0x18<<8) +XF+VF+NF ,
+ (0x19<<8) +XF +NF ,
+ (0x14<<8) +VF+NF ,
+ (0x15<<8) +NF ,
+ (0x16<<8) +NF ,
+ (0x17<<8) +VF+NF ,
+ (0x18<<8) +XF+VF+NF ,
+ (0x19<<8) +XF +NF ,
+ (0x20<<8) +YF +NF ,
+ (0x21<<8) +YF +VF+NF ,
+ (0x22<<8) +YF +VF+NF ,
+ (0x23<<8) +YF +NF ,
+ (0x24<<8) +YF +VF+NF ,
+ (0x25<<8) +YF +NF ,
+ (0x26<<8) +YF +NF ,
+ (0x27<<8) +YF +VF+NF ,
+ (0x28<<8) +YF +XF+VF+NF ,
+ (0x29<<8) +YF +XF +NF ,
+ (0x24<<8) +YF +VF+NF ,
+ (0x25<<8) +YF +NF ,
+ (0x26<<8) +YF +NF ,
+ (0x27<<8) +YF +VF+NF ,
+ (0x28<<8) +YF +XF+VF+NF ,
+ (0x29<<8) +YF +XF +NF ,
+ (0x30<<8) +YF +VF+NF ,
+ (0x31<<8) +YF +NF ,
+ (0x32<<8) +YF +NF ,
+ (0x33<<8) +YF +VF+NF ,
+ (0x34<<8) +YF +NF ,
+ (0x35<<8) +YF +VF+NF ,
+ (0x36<<8) +YF +VF+NF ,
+ (0x37<<8) +YF +NF ,
+ (0x38<<8) +YF +XF +NF ,
+ (0x39<<8) +YF +XF+VF+NF ,
+ (0x34<<8) +YF +NF ,
+ (0x35<<8) +YF +VF+NF ,
+ (0x36<<8) +YF +VF+NF ,
+ (0x37<<8) +YF +NF ,
+ (0x38<<8) +YF +XF +NF ,
+ (0x39<<8) +YF +XF+VF+NF ,
+ (0x40<<8) +NF ,
+ (0x41<<8) +VF+NF ,
+ (0x42<<8) +VF+NF ,
+ (0x43<<8) +NF ,
+ (0x44<<8) +VF+NF ,
+ (0x45<<8) +NF ,
+ (0x46<<8) +NF ,
+ (0x47<<8) +VF+NF ,
+ (0x48<<8) +XF+VF+NF ,
+ (0x49<<8) +XF +NF ,
+ (0x44<<8) +VF+NF ,
+ (0x45<<8) +NF ,
+ (0x46<<8) +NF ,
+ (0x47<<8) +VF+NF ,
+ (0x48<<8) +XF+VF+NF ,
+ (0x49<<8) +XF +NF ,
+ (0x50<<8) +VF+NF ,
+ (0x51<<8) +NF ,
+ (0x52<<8) +NF ,
+ (0x53<<8) +VF+NF ,
+ (0x54<<8) +NF ,
+ (0x55<<8) +VF+NF ,
+ (0x56<<8) +VF+NF ,
+ (0x57<<8) +NF ,
+ (0x58<<8) +XF +NF ,
+ (0x59<<8) +XF+VF+NF ,
+ (0x54<<8) +NF ,
+ (0x55<<8) +VF+NF ,
+ (0x56<<8) +VF+NF ,
+ (0x57<<8) +NF ,
+ (0x58<<8) +XF +NF ,
+ (0x59<<8) +XF+VF+NF ,
+ (0x60<<8) +YF +VF+NF ,
+ (0x61<<8) +YF +NF ,
+ (0x62<<8) +YF +NF ,
+ (0x63<<8) +YF +VF+NF ,
+ (0x64<<8) +YF +NF ,
+ (0x65<<8) +YF +VF+NF ,
+ (0x66<<8) +YF +VF+NF ,
+ (0x67<<8) +YF +NF ,
+ (0x68<<8) +YF +XF +NF ,
+ (0x69<<8) +YF +XF+VF+NF ,
+ (0x64<<8) +YF +NF ,
+ (0x65<<8) +YF +VF+NF ,
+ (0x66<<8) +YF +VF+NF ,
+ (0x67<<8) +YF +NF ,
+ (0x68<<8) +YF +XF +NF ,
+ (0x69<<8) +YF +XF+VF+NF ,
+ (0x70<<8) +YF +NF ,
+ (0x71<<8) +YF +VF+NF ,
+ (0x72<<8) +YF +VF+NF ,
+ (0x73<<8) +YF +NF ,
+ (0x74<<8) +YF +VF+NF ,
+ (0x75<<8) +YF +NF ,
+ (0x76<<8) +YF +NF ,
+ (0x77<<8) +YF +VF+NF ,
+ (0x78<<8) +YF +XF+VF+NF ,
+ (0x79<<8) +YF +XF +NF ,
+ (0x74<<8) +YF +VF+NF ,
+ (0x75<<8) +YF +NF ,
+ (0x76<<8) +YF +NF ,
+ (0x77<<8) +YF +VF+NF ,
+ (0x78<<8) +YF +XF+VF+NF ,
+ (0x79<<8) +YF +XF +NF ,
+ (0x80<<8)+SF +NF ,
+ (0x81<<8)+SF +VF+NF ,
+ (0x82<<8)+SF +VF+NF ,
+ (0x83<<8)+SF +NF ,
+ (0x84<<8)+SF +VF+NF ,
+ (0x85<<8)+SF +NF ,
+ (0x86<<8)+SF +NF ,
+ (0x87<<8)+SF +VF+NF ,
+ (0x88<<8)+SF +XF+VF+NF ,
+ (0x89<<8)+SF +XF +NF ,
+ (0x84<<8)+SF +VF+NF ,
+ (0x85<<8)+SF +NF ,
+ (0x86<<8)+SF +NF ,
+ (0x87<<8)+SF +VF+NF ,
+ (0x88<<8)+SF +XF+VF+NF ,
+ (0x89<<8)+SF +XF +NF ,
+ (0x90<<8)+SF +VF+NF ,
+ (0x91<<8)+SF +NF ,
+ (0x92<<8)+SF +NF ,
+ (0x93<<8)+SF +VF+NF ,
+ (0x94<<8)+SF +NF ,
+ (0x95<<8)+SF +VF+NF ,
+ (0x96<<8)+SF +VF+NF ,
+ (0x97<<8)+SF +NF ,
+ (0x98<<8)+SF +XF +NF ,
+ (0x99<<8)+SF +XF+VF+NF ,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x40<<8) +NF+CF,
+ (0x41<<8) +VF+NF+CF,
+ (0x42<<8) +VF+NF+CF,
+ (0x43<<8) +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x50<<8) +VF+NF+CF,
+ (0x51<<8) +NF+CF,
+ (0x52<<8) +NF+CF,
+ (0x53<<8) +VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x60<<8) +YF +VF+NF+CF,
+ (0x61<<8) +YF +NF+CF,
+ (0x62<<8) +YF +NF+CF,
+ (0x63<<8) +YF +VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x70<<8) +YF +NF+CF,
+ (0x71<<8) +YF +VF+NF+CF,
+ (0x72<<8) +YF +VF+NF+CF,
+ (0x73<<8) +YF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x80<<8)+SF +NF+CF,
+ (0x81<<8)+SF +VF+NF+CF,
+ (0x82<<8)+SF +VF+NF+CF,
+ (0x83<<8)+SF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x90<<8)+SF +VF+NF+CF,
+ (0x91<<8)+SF +NF+CF,
+ (0x92<<8)+SF +NF+CF,
+ (0x93<<8)+SF +VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0xA0<<8)+SF +YF +VF+NF+CF,
+ (0xA1<<8)+SF +YF +NF+CF,
+ (0xA2<<8)+SF +YF +NF+CF,
+ (0xA3<<8)+SF +YF +VF+NF+CF,
+ (0xA4<<8)+SF +YF +NF+CF,
+ (0xA5<<8)+SF +YF +VF+NF+CF,
+ (0xA6<<8)+SF +YF +VF+NF+CF,
+ (0xA7<<8)+SF +YF +NF+CF,
+ (0xA8<<8)+SF +YF +XF +NF+CF,
+ (0xA9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xA4<<8)+SF +YF +NF+CF,
+ (0xA5<<8)+SF +YF +VF+NF+CF,
+ (0xA6<<8)+SF +YF +VF+NF+CF,
+ (0xA7<<8)+SF +YF +NF+CF,
+ (0xA8<<8)+SF +YF +XF +NF+CF,
+ (0xA9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xB0<<8)+SF +YF +NF+CF,
+ (0xB1<<8)+SF +YF +VF+NF+CF,
+ (0xB2<<8)+SF +YF +VF+NF+CF,
+ (0xB3<<8)+SF +YF +NF+CF,
+ (0xB4<<8)+SF +YF +VF+NF+CF,
+ (0xB5<<8)+SF +YF +NF+CF,
+ (0xB6<<8)+SF +YF +NF+CF,
+ (0xB7<<8)+SF +YF +VF+NF+CF,
+ (0xB8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xB9<<8)+SF +YF +XF +NF+CF,
+ (0xB4<<8)+SF +YF +VF+NF+CF,
+ (0xB5<<8)+SF +YF +NF+CF,
+ (0xB6<<8)+SF +YF +NF+CF,
+ (0xB7<<8)+SF +YF +VF+NF+CF,
+ (0xB8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xB9<<8)+SF +YF +XF +NF+CF,
+ (0xC0<<8)+SF +VF+NF+CF,
+ (0xC1<<8)+SF +NF+CF,
+ (0xC2<<8)+SF +NF+CF,
+ (0xC3<<8)+SF +VF+NF+CF,
+ (0xC4<<8)+SF +NF+CF,
+ (0xC5<<8)+SF +VF+NF+CF,
+ (0xC6<<8)+SF +VF+NF+CF,
+ (0xC7<<8)+SF +NF+CF,
+ (0xC8<<8)+SF +XF +NF+CF,
+ (0xC9<<8)+SF +XF+VF+NF+CF,
+ (0xC4<<8)+SF +NF+CF,
+ (0xC5<<8)+SF +VF+NF+CF,
+ (0xC6<<8)+SF +VF+NF+CF,
+ (0xC7<<8)+SF +NF+CF,
+ (0xC8<<8)+SF +XF +NF+CF,
+ (0xC9<<8)+SF +XF+VF+NF+CF,
+ (0xD0<<8)+SF +NF+CF,
+ (0xD1<<8)+SF +VF+NF+CF,
+ (0xD2<<8)+SF +VF+NF+CF,
+ (0xD3<<8)+SF +NF+CF,
+ (0xD4<<8)+SF +VF+NF+CF,
+ (0xD5<<8)+SF +NF+CF,
+ (0xD6<<8)+SF +NF+CF,
+ (0xD7<<8)+SF +VF+NF+CF,
+ (0xD8<<8)+SF +XF+VF+NF+CF,
+ (0xD9<<8)+SF +XF +NF+CF,
+ (0xD4<<8)+SF +VF+NF+CF,
+ (0xD5<<8)+SF +NF+CF,
+ (0xD6<<8)+SF +NF+CF,
+ (0xD7<<8)+SF +VF+NF+CF,
+ (0xD8<<8)+SF +XF+VF+NF+CF,
+ (0xD9<<8)+SF +XF +NF+CF,
+ (0xE0<<8)+SF +YF +NF+CF,
+ (0xE1<<8)+SF +YF +VF+NF+CF,
+ (0xE2<<8)+SF +YF +VF+NF+CF,
+ (0xE3<<8)+SF +YF +NF+CF,
+ (0xE4<<8)+SF +YF +VF+NF+CF,
+ (0xE5<<8)+SF +YF +NF+CF,
+ (0xE6<<8)+SF +YF +NF+CF,
+ (0xE7<<8)+SF +YF +VF+NF+CF,
+ (0xE8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xE9<<8)+SF +YF +XF +NF+CF,
+ (0xE4<<8)+SF +YF +VF+NF+CF,
+ (0xE5<<8)+SF +YF +NF+CF,
+ (0xE6<<8)+SF +YF +NF+CF,
+ (0xE7<<8)+SF +YF +VF+NF+CF,
+ (0xE8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xE9<<8)+SF +YF +XF +NF+CF,
+ (0xF0<<8)+SF +YF +VF+NF+CF,
+ (0xF1<<8)+SF +YF +NF+CF,
+ (0xF2<<8)+SF +YF +NF+CF,
+ (0xF3<<8)+SF +YF +VF+NF+CF,
+ (0xF4<<8)+SF +YF +NF+CF,
+ (0xF5<<8)+SF +YF +VF+NF+CF,
+ (0xF6<<8)+SF +YF +VF+NF+CF,
+ (0xF7<<8)+SF +YF +NF+CF,
+ (0xF8<<8)+SF +YF +XF +NF+CF,
+ (0xF9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xF4<<8)+SF +YF +NF+CF,
+ (0xF5<<8)+SF +YF +VF+NF+CF,
+ (0xF6<<8)+SF +YF +VF+NF+CF,
+ (0xF7<<8)+SF +YF +NF+CF,
+ (0xF8<<8)+SF +YF +XF +NF+CF,
+ (0xF9<<8)+SF +YF +XF+VF+NF+CF,
+ (0x00<<8) +ZF +VF+NF+CF,
+ (0x01<<8) +NF+CF,
+ (0x02<<8) +NF+CF,
+ (0x03<<8) +VF+NF+CF,
+ (0x04<<8) +NF+CF,
+ (0x05<<8) +VF+NF+CF,
+ (0x06<<8) +VF+NF+CF,
+ (0x07<<8) +NF+CF,
+ (0x08<<8) +XF +NF+CF,
+ (0x09<<8) +XF+VF+NF+CF,
+ (0x04<<8) +NF+CF,
+ (0x05<<8) +VF+NF+CF,
+ (0x06<<8) +VF+NF+CF,
+ (0x07<<8) +NF+CF,
+ (0x08<<8) +XF +NF+CF,
+ (0x09<<8) +XF+VF+NF+CF,
+ (0x10<<8) +NF+CF,
+ (0x11<<8) +VF+NF+CF,
+ (0x12<<8) +VF+NF+CF,
+ (0x13<<8) +NF+CF,
+ (0x14<<8) +VF+NF+CF,
+ (0x15<<8) +NF+CF,
+ (0x16<<8) +NF+CF,
+ (0x17<<8) +VF+NF+CF,
+ (0x18<<8) +XF+VF+NF+CF,
+ (0x19<<8) +XF +NF+CF,
+ (0x14<<8) +VF+NF+CF,
+ (0x15<<8) +NF+CF,
+ (0x16<<8) +NF+CF,
+ (0x17<<8) +VF+NF+CF,
+ (0x18<<8) +XF+VF+NF+CF,
+ (0x19<<8) +XF +NF+CF,
+ (0x20<<8) +YF +NF+CF,
+ (0x21<<8) +YF +VF+NF+CF,
+ (0x22<<8) +YF +VF+NF+CF,
+ (0x23<<8) +YF +NF+CF,
+ (0x24<<8) +YF +VF+NF+CF,
+ (0x25<<8) +YF +NF+CF,
+ (0x26<<8) +YF +NF+CF,
+ (0x27<<8) +YF +VF+NF+CF,
+ (0x28<<8) +YF +XF+VF+NF+CF,
+ (0x29<<8) +YF +XF +NF+CF,
+ (0x24<<8) +YF +VF+NF+CF,
+ (0x25<<8) +YF +NF+CF,
+ (0x26<<8) +YF +NF+CF,
+ (0x27<<8) +YF +VF+NF+CF,
+ (0x28<<8) +YF +XF+VF+NF+CF,
+ (0x29<<8) +YF +XF +NF+CF,
+ (0x30<<8) +YF +VF+NF+CF,
+ (0x31<<8) +YF +NF+CF,
+ (0x32<<8) +YF +NF+CF,
+ (0x33<<8) +YF +VF+NF+CF,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x40<<8) +NF+CF,
+ (0x41<<8) +VF+NF+CF,
+ (0x42<<8) +VF+NF+CF,
+ (0x43<<8) +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x50<<8) +VF+NF+CF,
+ (0x51<<8) +NF+CF,
+ (0x52<<8) +NF+CF,
+ (0x53<<8) +VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x60<<8) +YF +VF+NF+CF,
+ (0x61<<8) +YF +NF+CF,
+ (0x62<<8) +YF +NF+CF,
+ (0x63<<8) +YF +VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x70<<8) +YF +NF+CF,
+ (0x71<<8) +YF +VF+NF+CF,
+ (0x72<<8) +YF +VF+NF+CF,
+ (0x73<<8) +YF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x80<<8)+SF +NF+CF,
+ (0x81<<8)+SF +VF+NF+CF,
+ (0x82<<8)+SF +VF+NF+CF,
+ (0x83<<8)+SF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x90<<8)+SF +VF+NF+CF,
+ (0x91<<8)+SF +NF+CF,
+ (0x92<<8)+SF +NF+CF,
+ (0x93<<8)+SF +VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0xFA<<8)+SF +YF+HF+XF+VF+NF ,
+ (0xFB<<8)+SF +YF+HF+XF +NF ,
+ (0xFC<<8)+SF +YF+HF+XF+VF+NF ,
+ (0xFD<<8)+SF +YF+HF+XF +NF ,
+ (0xFE<<8)+SF +YF+HF+XF +NF ,
+ (0xFF<<8)+SF +YF+HF+XF+VF+NF ,
+ (0x00<<8) +ZF +VF+NF ,
+ (0x01<<8) +NF ,
+ (0x02<<8) +NF ,
+ (0x03<<8) +VF+NF ,
+ (0x04<<8) +NF ,
+ (0x05<<8) +VF+NF ,
+ (0x06<<8) +VF+NF ,
+ (0x07<<8) +NF ,
+ (0x08<<8) +XF +NF ,
+ (0x09<<8) +XF+VF+NF ,
+ (0x0A<<8) +HF+XF+VF+NF ,
+ (0x0B<<8) +HF+XF +NF ,
+ (0x0C<<8) +HF+XF+VF+NF ,
+ (0x0D<<8) +HF+XF +NF ,
+ (0x0E<<8) +HF+XF +NF ,
+ (0x0F<<8) +HF+XF+VF+NF ,
+ (0x10<<8) +NF ,
+ (0x11<<8) +VF+NF ,
+ (0x12<<8) +VF+NF ,
+ (0x13<<8) +NF ,
+ (0x14<<8) +VF+NF ,
+ (0x15<<8) +NF ,
+ (0x16<<8) +NF ,
+ (0x17<<8) +VF+NF ,
+ (0x18<<8) +XF+VF+NF ,
+ (0x19<<8) +XF +NF ,
+ (0x1A<<8) +HF+XF +NF ,
+ (0x1B<<8) +HF+XF+VF+NF ,
+ (0x1C<<8) +HF+XF +NF ,
+ (0x1D<<8) +HF+XF+VF+NF ,
+ (0x1E<<8) +HF+XF+VF+NF ,
+ (0x1F<<8) +HF+XF +NF ,
+ (0x20<<8) +YF +NF ,
+ (0x21<<8) +YF +VF+NF ,
+ (0x22<<8) +YF +VF+NF ,
+ (0x23<<8) +YF +NF ,
+ (0x24<<8) +YF +VF+NF ,
+ (0x25<<8) +YF +NF ,
+ (0x26<<8) +YF +NF ,
+ (0x27<<8) +YF +VF+NF ,
+ (0x28<<8) +YF +XF+VF+NF ,
+ (0x29<<8) +YF +XF +NF ,
+ (0x2A<<8) +YF+HF+XF +NF ,
+ (0x2B<<8) +YF+HF+XF+VF+NF ,
+ (0x2C<<8) +YF+HF+XF +NF ,
+ (0x2D<<8) +YF+HF+XF+VF+NF ,
+ (0x2E<<8) +YF+HF+XF+VF+NF ,
+ (0x2F<<8) +YF+HF+XF +NF ,
+ (0x30<<8) +YF +VF+NF ,
+ (0x31<<8) +YF +NF ,
+ (0x32<<8) +YF +NF ,
+ (0x33<<8) +YF +VF+NF ,
+ (0x34<<8) +YF +NF ,
+ (0x35<<8) +YF +VF+NF ,
+ (0x36<<8) +YF +VF+NF ,
+ (0x37<<8) +YF +NF ,
+ (0x38<<8) +YF +XF +NF ,
+ (0x39<<8) +YF +XF+VF+NF ,
+ (0x3A<<8) +YF+HF+XF+VF+NF ,
+ (0x3B<<8) +YF+HF+XF +NF ,
+ (0x3C<<8) +YF+HF+XF+VF+NF ,
+ (0x3D<<8) +YF+HF+XF +NF ,
+ (0x3E<<8) +YF+HF+XF +NF ,
+ (0x3F<<8) +YF+HF+XF+VF+NF ,
+ (0x40<<8) +NF ,
+ (0x41<<8) +VF+NF ,
+ (0x42<<8) +VF+NF ,
+ (0x43<<8) +NF ,
+ (0x44<<8) +VF+NF ,
+ (0x45<<8) +NF ,
+ (0x46<<8) +NF ,
+ (0x47<<8) +VF+NF ,
+ (0x48<<8) +XF+VF+NF ,
+ (0x49<<8) +XF +NF ,
+ (0x4A<<8) +HF+XF +NF ,
+ (0x4B<<8) +HF+XF+VF+NF ,
+ (0x4C<<8) +HF+XF +NF ,
+ (0x4D<<8) +HF+XF+VF+NF ,
+ (0x4E<<8) +HF+XF+VF+NF ,
+ (0x4F<<8) +HF+XF +NF ,
+ (0x50<<8) +VF+NF ,
+ (0x51<<8) +NF ,
+ (0x52<<8) +NF ,
+ (0x53<<8) +VF+NF ,
+ (0x54<<8) +NF ,
+ (0x55<<8) +VF+NF ,
+ (0x56<<8) +VF+NF ,
+ (0x57<<8) +NF ,
+ (0x58<<8) +XF +NF ,
+ (0x59<<8) +XF+VF+NF ,
+ (0x5A<<8) +HF+XF+VF+NF ,
+ (0x5B<<8) +HF+XF +NF ,
+ (0x5C<<8) +HF+XF+VF+NF ,
+ (0x5D<<8) +HF+XF +NF ,
+ (0x5E<<8) +HF+XF +NF ,
+ (0x5F<<8) +HF+XF+VF+NF ,
+ (0x60<<8) +YF +VF+NF ,
+ (0x61<<8) +YF +NF ,
+ (0x62<<8) +YF +NF ,
+ (0x63<<8) +YF +VF+NF ,
+ (0x64<<8) +YF +NF ,
+ (0x65<<8) +YF +VF+NF ,
+ (0x66<<8) +YF +VF+NF ,
+ (0x67<<8) +YF +NF ,
+ (0x68<<8) +YF +XF +NF ,
+ (0x69<<8) +YF +XF+VF+NF ,
+ (0x6A<<8) +YF+HF+XF+VF+NF ,
+ (0x6B<<8) +YF+HF+XF +NF ,
+ (0x6C<<8) +YF+HF+XF+VF+NF ,
+ (0x6D<<8) +YF+HF+XF +NF ,
+ (0x6E<<8) +YF+HF+XF +NF ,
+ (0x6F<<8) +YF+HF+XF+VF+NF ,
+ (0x70<<8) +YF +NF ,
+ (0x71<<8) +YF +VF+NF ,
+ (0x72<<8) +YF +VF+NF ,
+ (0x73<<8) +YF +NF ,
+ (0x74<<8) +YF +VF+NF ,
+ (0x75<<8) +YF +NF ,
+ (0x76<<8) +YF +NF ,
+ (0x77<<8) +YF +VF+NF ,
+ (0x78<<8) +YF +XF+VF+NF ,
+ (0x79<<8) +YF +XF +NF ,
+ (0x7A<<8) +YF+HF+XF +NF ,
+ (0x7B<<8) +YF+HF+XF+VF+NF ,
+ (0x7C<<8) +YF+HF+XF +NF ,
+ (0x7D<<8) +YF+HF+XF+VF+NF ,
+ (0x7E<<8) +YF+HF+XF+VF+NF ,
+ (0x7F<<8) +YF+HF+XF +NF ,
+ (0x80<<8)+SF +NF ,
+ (0x81<<8)+SF +VF+NF ,
+ (0x82<<8)+SF +VF+NF ,
+ (0x83<<8)+SF +NF ,
+ (0x84<<8)+SF +VF+NF ,
+ (0x85<<8)+SF +NF ,
+ (0x86<<8)+SF +NF ,
+ (0x87<<8)+SF +VF+NF ,
+ (0x88<<8)+SF +XF+VF+NF ,
+ (0x89<<8)+SF +XF +NF ,
+ (0x8A<<8)+SF +HF+XF +NF ,
+ (0x8B<<8)+SF +HF+XF+VF+NF ,
+ (0x8C<<8)+SF +HF+XF +NF ,
+ (0x8D<<8)+SF +HF+XF+VF+NF ,
+ (0x8E<<8)+SF +HF+XF+VF+NF ,
+ (0x8F<<8)+SF +HF+XF +NF ,
+ (0x90<<8)+SF +VF+NF ,
+ (0x91<<8)+SF +NF ,
+ (0x92<<8)+SF +NF ,
+ (0x93<<8)+SF +VF+NF ,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x3A<<8) +YF+HF+XF+VF+NF+CF,
+ (0x3B<<8) +YF+HF+XF +NF+CF,
+ (0x3C<<8) +YF+HF+XF+VF+NF+CF,
+ (0x3D<<8) +YF+HF+XF +NF+CF,
+ (0x3E<<8) +YF+HF+XF +NF+CF,
+ (0x3F<<8) +YF+HF+XF+VF+NF+CF,
+ (0x40<<8) +NF+CF,
+ (0x41<<8) +VF+NF+CF,
+ (0x42<<8) +VF+NF+CF,
+ (0x43<<8) +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x4A<<8) +HF+XF +NF+CF,
+ (0x4B<<8) +HF+XF+VF+NF+CF,
+ (0x4C<<8) +HF+XF +NF+CF,
+ (0x4D<<8) +HF+XF+VF+NF+CF,
+ (0x4E<<8) +HF+XF+VF+NF+CF,
+ (0x4F<<8) +HF+XF +NF+CF,
+ (0x50<<8) +VF+NF+CF,
+ (0x51<<8) +NF+CF,
+ (0x52<<8) +NF+CF,
+ (0x53<<8) +VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x5A<<8) +HF+XF+VF+NF+CF,
+ (0x5B<<8) +HF+XF +NF+CF,
+ (0x5C<<8) +HF+XF+VF+NF+CF,
+ (0x5D<<8) +HF+XF +NF+CF,
+ (0x5E<<8) +HF+XF +NF+CF,
+ (0x5F<<8) +HF+XF+VF+NF+CF,
+ (0x60<<8) +YF +VF+NF+CF,
+ (0x61<<8) +YF +NF+CF,
+ (0x62<<8) +YF +NF+CF,
+ (0x63<<8) +YF +VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x6A<<8) +YF+HF+XF+VF+NF+CF,
+ (0x6B<<8) +YF+HF+XF +NF+CF,
+ (0x6C<<8) +YF+HF+XF+VF+NF+CF,
+ (0x6D<<8) +YF+HF+XF +NF+CF,
+ (0x6E<<8) +YF+HF+XF +NF+CF,
+ (0x6F<<8) +YF+HF+XF+VF+NF+CF,
+ (0x70<<8) +YF +NF+CF,
+ (0x71<<8) +YF +VF+NF+CF,
+ (0x72<<8) +YF +VF+NF+CF,
+ (0x73<<8) +YF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x7A<<8) +YF+HF+XF +NF+CF,
+ (0x7B<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7C<<8) +YF+HF+XF +NF+CF,
+ (0x7D<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7E<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7F<<8) +YF+HF+XF +NF+CF,
+ (0x80<<8)+SF +NF+CF,
+ (0x81<<8)+SF +VF+NF+CF,
+ (0x82<<8)+SF +VF+NF+CF,
+ (0x83<<8)+SF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x8A<<8)+SF +HF+XF +NF+CF,
+ (0x8B<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8C<<8)+SF +HF+XF +NF+CF,
+ (0x8D<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8E<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8F<<8)+SF +HF+XF +NF+CF,
+ (0x90<<8)+SF +VF+NF+CF,
+ (0x91<<8)+SF +NF+CF,
+ (0x92<<8)+SF +NF+CF,
+ (0x93<<8)+SF +VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF,
+ (0x9A<<8)+SF +HF+XF+VF+NF+CF,
+ (0x9B<<8)+SF +HF+XF +NF+CF,
+ (0x9C<<8)+SF +HF+XF+VF+NF+CF,
+ (0x9D<<8)+SF +HF+XF +NF+CF,
+ (0x9E<<8)+SF +HF+XF +NF+CF,
+ (0x9F<<8)+SF +HF+XF+VF+NF+CF,
+ (0xA0<<8)+SF +YF +VF+NF+CF,
+ (0xA1<<8)+SF +YF +NF+CF,
+ (0xA2<<8)+SF +YF +NF+CF,
+ (0xA3<<8)+SF +YF +VF+NF+CF,
+ (0xA4<<8)+SF +YF +NF+CF,
+ (0xA5<<8)+SF +YF +VF+NF+CF,
+ (0xA6<<8)+SF +YF +VF+NF+CF,
+ (0xA7<<8)+SF +YF +NF+CF,
+ (0xA8<<8)+SF +YF +XF +NF+CF,
+ (0xA9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xAA<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xAB<<8)+SF +YF+HF+XF +NF+CF,
+ (0xAC<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xAD<<8)+SF +YF+HF+XF +NF+CF,
+ (0xAE<<8)+SF +YF+HF+XF +NF+CF,
+ (0xAF<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xB0<<8)+SF +YF +NF+CF,
+ (0xB1<<8)+SF +YF +VF+NF+CF,
+ (0xB2<<8)+SF +YF +VF+NF+CF,
+ (0xB3<<8)+SF +YF +NF+CF,
+ (0xB4<<8)+SF +YF +VF+NF+CF,
+ (0xB5<<8)+SF +YF +NF+CF,
+ (0xB6<<8)+SF +YF +NF+CF,
+ (0xB7<<8)+SF +YF +VF+NF+CF,
+ (0xB8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xB9<<8)+SF +YF +XF +NF+CF,
+ (0xBA<<8)+SF +YF+HF+XF +NF+CF,
+ (0xBB<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xBC<<8)+SF +YF+HF+XF +NF+CF,
+ (0xBD<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xBE<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xBF<<8)+SF +YF+HF+XF +NF+CF,
+ (0xC0<<8)+SF +VF+NF+CF,
+ (0xC1<<8)+SF +NF+CF,
+ (0xC2<<8)+SF +NF+CF,
+ (0xC3<<8)+SF +VF+NF+CF,
+ (0xC4<<8)+SF +NF+CF,
+ (0xC5<<8)+SF +VF+NF+CF,
+ (0xC6<<8)+SF +VF+NF+CF,
+ (0xC7<<8)+SF +NF+CF,
+ (0xC8<<8)+SF +XF +NF+CF,
+ (0xC9<<8)+SF +XF+VF+NF+CF,
+ (0xCA<<8)+SF +HF+XF+VF+NF+CF,
+ (0xCB<<8)+SF +HF+XF +NF+CF,
+ (0xCC<<8)+SF +HF+XF+VF+NF+CF,
+ (0xCD<<8)+SF +HF+XF +NF+CF,
+ (0xCE<<8)+SF +HF+XF +NF+CF,
+ (0xCF<<8)+SF +HF+XF+VF+NF+CF,
+ (0xD0<<8)+SF +NF+CF,
+ (0xD1<<8)+SF +VF+NF+CF,
+ (0xD2<<8)+SF +VF+NF+CF,
+ (0xD3<<8)+SF +NF+CF,
+ (0xD4<<8)+SF +VF+NF+CF,
+ (0xD5<<8)+SF +NF+CF,
+ (0xD6<<8)+SF +NF+CF,
+ (0xD7<<8)+SF +VF+NF+CF,
+ (0xD8<<8)+SF +XF+VF+NF+CF,
+ (0xD9<<8)+SF +XF +NF+CF,
+ (0xDA<<8)+SF +HF+XF +NF+CF,
+ (0xDB<<8)+SF +HF+XF+VF+NF+CF,
+ (0xDC<<8)+SF +HF+XF +NF+CF,
+ (0xDD<<8)+SF +HF+XF+VF+NF+CF,
+ (0xDE<<8)+SF +HF+XF+VF+NF+CF,
+ (0xDF<<8)+SF +HF+XF +NF+CF,
+ (0xE0<<8)+SF +YF +NF+CF,
+ (0xE1<<8)+SF +YF +VF+NF+CF,
+ (0xE2<<8)+SF +YF +VF+NF+CF,
+ (0xE3<<8)+SF +YF +NF+CF,
+ (0xE4<<8)+SF +YF +VF+NF+CF,
+ (0xE5<<8)+SF +YF +NF+CF,
+ (0xE6<<8)+SF +YF +NF+CF,
+ (0xE7<<8)+SF +YF +VF+NF+CF,
+ (0xE8<<8)+SF +YF +XF+VF+NF+CF,
+ (0xE9<<8)+SF +YF +XF +NF+CF,
+ (0xEA<<8)+SF +YF+HF+XF +NF+CF,
+ (0xEB<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xEC<<8)+SF +YF+HF+XF +NF+CF,
+ (0xED<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xEE<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xEF<<8)+SF +YF+HF+XF +NF+CF,
+ (0xF0<<8)+SF +YF +VF+NF+CF,
+ (0xF1<<8)+SF +YF +NF+CF,
+ (0xF2<<8)+SF +YF +NF+CF,
+ (0xF3<<8)+SF +YF +VF+NF+CF,
+ (0xF4<<8)+SF +YF +NF+CF,
+ (0xF5<<8)+SF +YF +VF+NF+CF,
+ (0xF6<<8)+SF +YF +VF+NF+CF,
+ (0xF7<<8)+SF +YF +NF+CF,
+ (0xF8<<8)+SF +YF +XF +NF+CF,
+ (0xF9<<8)+SF +YF +XF+VF+NF+CF,
+ (0xFA<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xFB<<8)+SF +YF+HF+XF +NF+CF,
+ (0xFC<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0xFD<<8)+SF +YF+HF+XF +NF+CF,
+ (0xFE<<8)+SF +YF+HF+XF +NF+CF,
+ (0xFF<<8)+SF +YF+HF+XF+VF+NF+CF,
+ (0x00<<8) +ZF +VF+NF+CF,
+ (0x01<<8) +NF+CF,
+ (0x02<<8) +NF+CF,
+ (0x03<<8) +VF+NF+CF,
+ (0x04<<8) +NF+CF,
+ (0x05<<8) +VF+NF+CF,
+ (0x06<<8) +VF+NF+CF,
+ (0x07<<8) +NF+CF,
+ (0x08<<8) +XF +NF+CF,
+ (0x09<<8) +XF+VF+NF+CF,
+ (0x0A<<8) +HF+XF+VF+NF+CF,
+ (0x0B<<8) +HF+XF +NF+CF,
+ (0x0C<<8) +HF+XF+VF+NF+CF,
+ (0x0D<<8) +HF+XF +NF+CF,
+ (0x0E<<8) +HF+XF +NF+CF,
+ (0x0F<<8) +HF+XF+VF+NF+CF,
+ (0x10<<8) +NF+CF,
+ (0x11<<8) +VF+NF+CF,
+ (0x12<<8) +VF+NF+CF,
+ (0x13<<8) +NF+CF,
+ (0x14<<8) +VF+NF+CF,
+ (0x15<<8) +NF+CF,
+ (0x16<<8) +NF+CF,
+ (0x17<<8) +VF+NF+CF,
+ (0x18<<8) +XF+VF+NF+CF,
+ (0x19<<8) +XF +NF+CF,
+ (0x1A<<8) +HF+XF +NF+CF,
+ (0x1B<<8) +HF+XF+VF+NF+CF,
+ (0x1C<<8) +HF+XF +NF+CF,
+ (0x1D<<8) +HF+XF+VF+NF+CF,
+ (0x1E<<8) +HF+XF+VF+NF+CF,
+ (0x1F<<8) +HF+XF +NF+CF,
+ (0x20<<8) +YF +NF+CF,
+ (0x21<<8) +YF +VF+NF+CF,
+ (0x22<<8) +YF +VF+NF+CF,
+ (0x23<<8) +YF +NF+CF,
+ (0x24<<8) +YF +VF+NF+CF,
+ (0x25<<8) +YF +NF+CF,
+ (0x26<<8) +YF +NF+CF,
+ (0x27<<8) +YF +VF+NF+CF,
+ (0x28<<8) +YF +XF+VF+NF+CF,
+ (0x29<<8) +YF +XF +NF+CF,
+ (0x2A<<8) +YF+HF+XF +NF+CF,
+ (0x2B<<8) +YF+HF+XF+VF+NF+CF,
+ (0x2C<<8) +YF+HF+XF +NF+CF,
+ (0x2D<<8) +YF+HF+XF+VF+NF+CF,
+ (0x2E<<8) +YF+HF+XF+VF+NF+CF,
+ (0x2F<<8) +YF+HF+XF +NF+CF,
+ (0x30<<8) +YF +VF+NF+CF,
+ (0x31<<8) +YF +NF+CF,
+ (0x32<<8) +YF +NF+CF,
+ (0x33<<8) +YF +VF+NF+CF,
+ (0x34<<8) +YF +NF+CF,
+ (0x35<<8) +YF +VF+NF+CF,
+ (0x36<<8) +YF +VF+NF+CF,
+ (0x37<<8) +YF +NF+CF,
+ (0x38<<8) +YF +XF +NF+CF,
+ (0x39<<8) +YF +XF+VF+NF+CF,
+ (0x3A<<8) +YF+HF+XF+VF+NF+CF,
+ (0x3B<<8) +YF+HF+XF +NF+CF,
+ (0x3C<<8) +YF+HF+XF+VF+NF+CF,
+ (0x3D<<8) +YF+HF+XF +NF+CF,
+ (0x3E<<8) +YF+HF+XF +NF+CF,
+ (0x3F<<8) +YF+HF+XF+VF+NF+CF,
+ (0x40<<8) +NF+CF,
+ (0x41<<8) +VF+NF+CF,
+ (0x42<<8) +VF+NF+CF,
+ (0x43<<8) +NF+CF,
+ (0x44<<8) +VF+NF+CF,
+ (0x45<<8) +NF+CF,
+ (0x46<<8) +NF+CF,
+ (0x47<<8) +VF+NF+CF,
+ (0x48<<8) +XF+VF+NF+CF,
+ (0x49<<8) +XF +NF+CF,
+ (0x4A<<8) +HF+XF +NF+CF,
+ (0x4B<<8) +HF+XF+VF+NF+CF,
+ (0x4C<<8) +HF+XF +NF+CF,
+ (0x4D<<8) +HF+XF+VF+NF+CF,
+ (0x4E<<8) +HF+XF+VF+NF+CF,
+ (0x4F<<8) +HF+XF +NF+CF,
+ (0x50<<8) +VF+NF+CF,
+ (0x51<<8) +NF+CF,
+ (0x52<<8) +NF+CF,
+ (0x53<<8) +VF+NF+CF,
+ (0x54<<8) +NF+CF,
+ (0x55<<8) +VF+NF+CF,
+ (0x56<<8) +VF+NF+CF,
+ (0x57<<8) +NF+CF,
+ (0x58<<8) +XF +NF+CF,
+ (0x59<<8) +XF+VF+NF+CF,
+ (0x5A<<8) +HF+XF+VF+NF+CF,
+ (0x5B<<8) +HF+XF +NF+CF,
+ (0x5C<<8) +HF+XF+VF+NF+CF,
+ (0x5D<<8) +HF+XF +NF+CF,
+ (0x5E<<8) +HF+XF +NF+CF,
+ (0x5F<<8) +HF+XF+VF+NF+CF,
+ (0x60<<8) +YF +VF+NF+CF,
+ (0x61<<8) +YF +NF+CF,
+ (0x62<<8) +YF +NF+CF,
+ (0x63<<8) +YF +VF+NF+CF,
+ (0x64<<8) +YF +NF+CF,
+ (0x65<<8) +YF +VF+NF+CF,
+ (0x66<<8) +YF +VF+NF+CF,
+ (0x67<<8) +YF +NF+CF,
+ (0x68<<8) +YF +XF +NF+CF,
+ (0x69<<8) +YF +XF+VF+NF+CF,
+ (0x6A<<8) +YF+HF+XF+VF+NF+CF,
+ (0x6B<<8) +YF+HF+XF +NF+CF,
+ (0x6C<<8) +YF+HF+XF+VF+NF+CF,
+ (0x6D<<8) +YF+HF+XF +NF+CF,
+ (0x6E<<8) +YF+HF+XF +NF+CF,
+ (0x6F<<8) +YF+HF+XF+VF+NF+CF,
+ (0x70<<8) +YF +NF+CF,
+ (0x71<<8) +YF +VF+NF+CF,
+ (0x72<<8) +YF +VF+NF+CF,
+ (0x73<<8) +YF +NF+CF,
+ (0x74<<8) +YF +VF+NF+CF,
+ (0x75<<8) +YF +NF+CF,
+ (0x76<<8) +YF +NF+CF,
+ (0x77<<8) +YF +VF+NF+CF,
+ (0x78<<8) +YF +XF+VF+NF+CF,
+ (0x79<<8) +YF +XF +NF+CF,
+ (0x7A<<8) +YF+HF+XF +NF+CF,
+ (0x7B<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7C<<8) +YF+HF+XF +NF+CF,
+ (0x7D<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7E<<8) +YF+HF+XF+VF+NF+CF,
+ (0x7F<<8) +YF+HF+XF +NF+CF,
+ (0x80<<8)+SF +NF+CF,
+ (0x81<<8)+SF +VF+NF+CF,
+ (0x82<<8)+SF +VF+NF+CF,
+ (0x83<<8)+SF +NF+CF,
+ (0x84<<8)+SF +VF+NF+CF,
+ (0x85<<8)+SF +NF+CF,
+ (0x86<<8)+SF +NF+CF,
+ (0x87<<8)+SF +VF+NF+CF,
+ (0x88<<8)+SF +XF+VF+NF+CF,
+ (0x89<<8)+SF +XF +NF+CF,
+ (0x8A<<8)+SF +HF+XF +NF+CF,
+ (0x8B<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8C<<8)+SF +HF+XF +NF+CF,
+ (0x8D<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8E<<8)+SF +HF+XF+VF+NF+CF,
+ (0x8F<<8)+SF +HF+XF +NF+CF,
+ (0x90<<8)+SF +VF+NF+CF,
+ (0x91<<8)+SF +NF+CF,
+ (0x92<<8)+SF +NF+CF,
+ (0x93<<8)+SF +VF+NF+CF,
+ (0x94<<8)+SF +NF+CF,
+ (0x95<<8)+SF +VF+NF+CF,
+ (0x96<<8)+SF +VF+NF+CF,
+ (0x97<<8)+SF +NF+CF,
+ (0x98<<8)+SF +XF +NF+CF,
+ (0x99<<8)+SF +XF+VF+NF+CF
+};
+
diff --git a/src/emu/cpu/z180/z180dasm.c b/src/emu/cpu/z180/z180dasm.c
new file mode 100644
index 00000000000..8f3dff1874c
--- /dev/null
+++ b/src/emu/cpu/z180/z180dasm.c
@@ -0,0 +1,555 @@
+/*****************************************************************************
+ *
+ * z180dasm.c
+ * Portable Z8x180 disassembler
+ *
+ * Copyright (C) 2000 Juergen Buchmueller, all rights reserved.
+ *
+ * Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * You can contact me at juergen@mame.net or pullmoll@stop1984.com
+ *
+ * - This source code is released as freeware for non-commercial purposes
+ * as part of the M.A.M.E. (Multiple Arcade Machine Emulator) project.
+ * The licensing terms of MAME apply to this piece of code for the MAME
+ * project and derviative works, as defined by the MAME license. You
+ * may opt to make modifications, improvements or derivative works under
+ * that same conditions, and the MAME project may opt to keep
+ * modifications, improvements or derivatives under their terms exclusively.
+ *
+ * - Alternatively you can choose to apply the terms of the "GPL" (see
+ * below) to this - and only this - piece of code or your derivative works.
+ * Note that in no case your choice can have any impact on any other
+ * source code of the MAME project, or binary, or executable, be it closely
+ * or losely related to this piece of code.
+ *
+ * - At your choice you are also free to remove either licensing terms from
+ * this file and continue to use it under only one of the two licenses. Do this
+ * if you think that licenses are not compatible (enough) for you, or if you
+ * consider either license 'too restrictive' or 'too free'.
+ *
+ * - GPL (GNU General Public License)
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "z180.h"
+
+enum e_mnemonics {
+ zADC ,zADD ,zAND ,zBIT ,zCALL ,zCCF ,zCP ,zCPD ,
+ zCPDR ,zCPI ,zCPIR ,zCPL ,zDAA ,zDB ,zDEC ,zDI ,
+ zDJNZ ,zEI ,zEX ,zEXX ,zHLT ,zIM ,zIN ,zIN0 ,
+ zINC ,zIND ,zINDR ,zINI ,zINIR ,zJP ,zJR ,zLD ,
+ zLDD ,zLDDR ,zLDI ,zLDIR ,zMLT ,zNEG ,zNOP ,zOR ,
+ zOTDM ,zOTDMR ,zOTDR ,zOTIM ,zOTIMR ,zOTIR ,zOUT ,zOUT0 ,
+ zOUTD ,zOUTI ,zPOP ,zPUSH ,zRES ,zRET ,zRETI ,zRETN ,
+ zRL ,zRLA ,zRLC ,zRLCA ,zRLD ,zRR ,zRRA ,zRRC ,
+ zRRCA ,zRRD ,zRST ,zSBC ,zSCF ,zSET ,zSLA ,zSLL ,
+ zSLP ,zSRA ,zSRL ,zSUB ,zTST ,zTSTIO ,zXOR
+};
+
+static const char *s_mnemonic[] = {
+ "adc" ,"add" ,"and" ,"bit" ,"call" ,"ccf" ,"cp" ,"cpd" ,
+ "cpdr" ,"cpi" ,"cpir" ,"cpl" ,"daa" ,"db" ,"dec" ,"di" ,
+ "djnz" ,"ei" ,"ex" ,"exx" ,"halt" ,"im" ,"in" ,"in0" ,
+ "inc" ,"ind" ,"indr" ,"ini" ,"inir" ,"jp" ,"jr" ,"ld" ,
+ "ldd" ,"lddr" ,"ldi" ,"ldir" ,"mlt" ,"neg" ,"nop" ,"or" ,
+ "otdm" ,"otdmr","otdr" ,"otim" ,"otimr","otir" ,"out" ,"out0" ,
+ "outd" ,"outi" ,"pop" ,"push" ,"res" ,"ret" ,"reti" ,"retn" ,
+ "rl" ,"rla" ,"rlc" ,"rlca" ,"rld" ,"rr" ,"rra" ,"rrc" ,
+ "rrca" ,"rrd" ,"rst" ,"sbc" ,"scf" ,"set" ,"sla" ,"sll" ,
+ "slp" ,"sra" ,"srl" ,"sub" ,"tst" ,"tstio","xor "
+};
+
+typedef struct {
+ UINT8 mnemonic;
+ const char *arguments;
+} z80dasm;
+
+static z80dasm mnemonic_xx_cb[256]= {
+ {zRLC,"b=Y"}, {zRLC,"c=Y"}, {zRLC,"d=Y"}, {zRLC,"e=Y"},
+ {zRLC,"h=Y"}, {zRLC,"l=Y"}, {zRLC,"Y"}, {zRLC,"a=Y"},
+ {zRRC,"b=Y"}, {zRRC,"c=Y"}, {zRRC,"d=Y"}, {zRRC,"e=Y"},
+ {zRRC,"h=Y"}, {zRRC,"l=Y"}, {zRRC,"Y"}, {zRRC,"a=Y"},
+ {zRL,"b=Y"}, {zRL,"c=Y"}, {zRL,"d=Y"}, {zRL,"e=Y"},
+ {zRL,"h=Y"}, {zRL,"l=Y"}, {zRL,"Y"}, {zRL,"a=Y"},
+ {zRR,"b=Y"}, {zRR,"c=Y"}, {zRR,"d=Y"}, {zRR,"e=Y"},
+ {zRR,"h=Y"}, {zRR,"l=Y"}, {zRR,"Y"}, {zRR,"a=Y"},
+ {zSLA,"b=Y"}, {zSLA,"c=Y"}, {zSLA,"d=Y"}, {zSLA,"e=Y"},
+ {zSLA,"h=Y"}, {zSLA,"l=Y"}, {zSLA,"Y"}, {zSLA,"a=Y"},
+ {zSRA,"b=Y"}, {zSRA,"c=Y"}, {zSRA,"d=Y"}, {zSRA,"e=Y"},
+ {zSRA,"h=Y"}, {zSRA,"l=Y"}, {zSRA,"Y"}, {zSRA,"a=Y"},
+ {zSLL,"b=Y"}, {zSLL,"c=Y"}, {zSLL,"d=Y"}, {zSLL,"e=Y"},
+ {zSLL,"h=Y"}, {zSLL,"l=Y"}, {zSLL,"Y"}, {zSLL,"a=Y"},
+ {zSRL,"b=Y"}, {zSRL,"c=Y"}, {zSRL,"d=Y"}, {zSRL,"e=Y"},
+ {zSRL,"h=Y"}, {zSRL,"l=Y"}, {zSRL,"Y"}, {zSRL,"a=Y"},
+ {zBIT,"b=0,Y"}, {zBIT,"c=0,Y"}, {zBIT,"d=0,Y"}, {zBIT,"e=0,Y"},
+ {zBIT,"h=0,Y"}, {zBIT,"l=0,Y"}, {zBIT,"0,Y"}, {zBIT,"a=0,Y"},
+ {zBIT,"b=1,Y"}, {zBIT,"c=1,Y"}, {zBIT,"d=1,Y"}, {zBIT,"e=1,Y"},
+ {zBIT,"h=1,Y"}, {zBIT,"l=1,Y"}, {zBIT,"1,Y"}, {zBIT,"a=1,Y"},
+ {zBIT,"b=2,Y"}, {zBIT,"c=2,Y"}, {zBIT,"d=2,Y"}, {zBIT,"e=2,Y"},
+ {zBIT,"h=2,Y"}, {zBIT,"l=2,Y"}, {zBIT,"2,Y"}, {zBIT,"a=2,Y"},
+ {zBIT,"b=3,Y"}, {zBIT,"c=3,Y"}, {zBIT,"d=3,Y"}, {zBIT,"e=3,Y"},
+ {zBIT,"h=3,Y"}, {zBIT,"l=3,Y"}, {zBIT,"3,Y"}, {zBIT,"a=3,Y"},
+ {zBIT,"b=4,Y"}, {zBIT,"c=4,Y"}, {zBIT,"d=4,Y"}, {zBIT,"e=4,Y"},
+ {zBIT,"h=4,Y"}, {zBIT,"l=4,Y"}, {zBIT,"4,Y"}, {zBIT,"a=4,Y"},
+ {zBIT,"b=5,Y"}, {zBIT,"c=5,Y"}, {zBIT,"d=5,Y"}, {zBIT,"e=5,Y"},
+ {zBIT,"h=5,Y"}, {zBIT,"l=5,Y"}, {zBIT,"5,Y"}, {zBIT,"a=5,Y"},
+ {zBIT,"b=6,Y"}, {zBIT,"c=6,Y"}, {zBIT,"d=6,Y"}, {zBIT,"e=6,Y"},
+ {zBIT,"h=6,Y"}, {zBIT,"l=6,Y"}, {zBIT,"6,Y"}, {zBIT,"a=6,Y"},
+ {zBIT,"b=7,Y"}, {zBIT,"c=7,Y"}, {zBIT,"d=7,Y"}, {zBIT,"e=7,Y"},
+ {zBIT,"h=7,Y"}, {zBIT,"l=7,Y"}, {zBIT,"7,Y"}, {zBIT,"a=7,Y"},
+ {zRES,"b=0,Y"}, {zRES,"c=0,Y"}, {zRES,"d=0,Y"}, {zRES,"e=0,Y"},
+ {zRES,"h=0,Y"}, {zRES,"l=0,Y"}, {zRES,"0,Y"}, {zRES,"a=0,Y"},
+ {zRES,"b=1,Y"}, {zRES,"c=1,Y"}, {zRES,"d=1,Y"}, {zRES,"e=1,Y"},
+ {zRES,"h=1,Y"}, {zRES,"l=1,Y"}, {zRES,"1,Y"}, {zRES,"a=1,Y"},
+ {zRES,"b=2,Y"}, {zRES,"c=2,Y"}, {zRES,"d=2,Y"}, {zRES,"e=2,Y"},
+ {zRES,"h=2,Y"}, {zRES,"l=2,Y"}, {zRES,"2,Y"}, {zRES,"a=2,Y"},
+ {zRES,"b=3,Y"}, {zRES,"c=3,Y"}, {zRES,"d=3,Y"}, {zRES,"e=3,Y"},
+ {zRES,"h=3,Y"}, {zRES,"l=3,Y"}, {zRES,"3,Y"}, {zRES,"a=3,Y"},
+ {zRES,"b=4,Y"}, {zRES,"c=4,Y"}, {zRES,"d=4,Y"}, {zRES,"e=4,Y"},
+ {zRES,"h=4,Y"}, {zRES,"l=4,Y"}, {zRES,"4,Y"}, {zRES,"a=4,Y"},
+ {zRES,"b=5,Y"}, {zRES,"c=5,Y"}, {zRES,"d=5,Y"}, {zRES,"e=5,Y"},
+ {zRES,"h=5,Y"}, {zRES,"l=5,Y"}, {zRES,"5,Y"}, {zRES,"a=5,Y"},
+ {zRES,"b=6,Y"}, {zRES,"c=6,Y"}, {zRES,"d=6,Y"}, {zRES,"e=6,Y"},
+ {zRES,"h=6,Y"}, {zRES,"l=6,Y"}, {zRES,"6,Y"}, {zRES,"a=6,Y"},
+ {zRES,"b=7,Y"}, {zRES,"c=7,Y"}, {zRES,"d=7,Y"}, {zRES,"e=7,Y"},
+ {zRES,"h=7,Y"}, {zRES,"l=7,Y"}, {zRES,"7,Y"}, {zRES,"a=7,Y"},
+ {zSET,"b=0,Y"}, {zSET,"c=0,Y"}, {zSET,"d=0,Y"}, {zSET,"e=0,Y"},
+ {zSET,"h=0,Y"}, {zSET,"l=0,Y"}, {zSET,"0,Y"}, {zSET,"a=0,Y"},
+ {zSET,"b=1,Y"}, {zSET,"c=1,Y"}, {zSET,"d=1,Y"}, {zSET,"e=1,Y"},
+ {zSET,"h=1,Y"}, {zSET,"l=1,Y"}, {zSET,"1,Y"}, {zSET,"a=1,Y"},
+ {zSET,"b=2,Y"}, {zSET,"c=2,Y"}, {zSET,"d=2,Y"}, {zSET,"e=2,Y"},
+ {zSET,"h=2,Y"}, {zSET,"l=2,Y"}, {zSET,"2,Y"}, {zSET,"a=2,Y"},
+ {zSET,"b=3,Y"}, {zSET,"c=3,Y"}, {zSET,"d=3,Y"}, {zSET,"e=3,Y"},
+ {zSET,"h=3,Y"}, {zSET,"l=3,Y"}, {zSET,"3,Y"}, {zSET,"a=3,Y"},
+ {zSET,"b=4,Y"}, {zSET,"c=4,Y"}, {zSET,"d=4,Y"}, {zSET,"e=4,Y"},
+ {zSET,"h=4,Y"}, {zSET,"l=4,Y"}, {zSET,"4,Y"}, {zSET,"a=4,Y"},
+ {zSET,"b=5,Y"}, {zSET,"c=5,Y"}, {zSET,"d=5,Y"}, {zSET,"e=5,Y"},
+ {zSET,"h=5,Y"}, {zSET,"l=5,Y"}, {zSET,"5,Y"}, {zSET,"a=5,Y"},
+ {zSET,"b=6,Y"}, {zSET,"c=6,Y"}, {zSET,"d=6,Y"}, {zSET,"e=6,Y"},
+ {zSET,"h=6,Y"}, {zSET,"l=6,Y"}, {zSET,"6,Y"}, {zSET,"a=6,Y"},
+ {zSET,"b=7,Y"}, {zSET,"c=7,Y"}, {zSET,"d=7,Y"}, {zSET,"e=7,Y"},
+ {zSET,"h=7,Y"}, {zSET,"l=7,Y"}, {zSET,"7,Y"}, {zSET,"a=7,Y"}
+};
+
+static z80dasm mnemonic_cb[256] = {
+ {zRLC,"b"}, {zRLC,"c"}, {zRLC,"d"}, {zRLC,"e"},
+ {zRLC,"h"}, {zRLC,"l"}, {zRLC,"(hl)"}, {zRLC,"a"},
+ {zRRC,"b"}, {zRRC,"c"}, {zRRC,"d"}, {zRRC,"e"},
+ {zRRC,"h"}, {zRRC,"l"}, {zRRC,"(hl)"}, {zRRC,"a"},
+ {zRL,"b"}, {zRL,"c"}, {zRL,"d"}, {zRL,"e"},
+ {zRL,"h"}, {zRL,"l"}, {zRL,"(hl)"}, {zRL,"a"},
+ {zRR,"b"}, {zRR,"c"}, {zRR,"d"}, {zRR,"e"},
+ {zRR,"h"}, {zRR,"l"}, {zRR,"(hl)"}, {zRR,"a"},
+ {zSLA,"b"}, {zSLA,"c"}, {zSLA,"d"}, {zSLA,"e"},
+ {zSLA,"h"}, {zSLA,"l"}, {zSLA,"(hl)"}, {zSLA,"a"},
+ {zSRA,"b"}, {zSRA,"c"}, {zSRA,"d"}, {zSRA,"e"},
+ {zSRA,"h"}, {zSRA,"l"}, {zSRA,"(hl)"}, {zSRA,"a"},
+ {zSLL,"b"}, {zSLL,"c"}, {zSLL,"d"}, {zSLL,"e"},
+ {zSLL,"h"}, {zSLL,"l"}, {zSLL,"(hl)"}, {zSLL,"a"},
+ {zSRL,"b"}, {zSRL,"c"}, {zSRL,"d"}, {zSRL,"e"},
+ {zSRL,"h"}, {zSRL,"l"}, {zSRL,"(hl)"}, {zSRL,"a"},
+ {zBIT,"0,b"}, {zBIT,"0,c"}, {zBIT,"0,d"}, {zBIT,"0,e"},
+ {zBIT,"0,h"}, {zBIT,"0,l"}, {zBIT,"0,(hl)"},{zBIT,"0,a"},
+ {zBIT,"1,b"}, {zBIT,"1,c"}, {zBIT,"1,d"}, {zBIT,"1,e"},
+ {zBIT,"1,h"}, {zBIT,"1,l"}, {zBIT,"1,(hl)"},{zBIT,"1,a"},
+ {zBIT,"2,b"}, {zBIT,"2,c"}, {zBIT,"2,d"}, {zBIT,"2,e"},
+ {zBIT,"2,h"}, {zBIT,"2,l"}, {zBIT,"2,(hl)"},{zBIT,"2,a"},
+ {zBIT,"3,b"}, {zBIT,"3,c"}, {zBIT,"3,d"}, {zBIT,"3,e"},
+ {zBIT,"3,h"}, {zBIT,"3,l"}, {zBIT,"3,(hl)"},{zBIT,"3,a"},
+ {zBIT,"4,b"}, {zBIT,"4,c"}, {zBIT,"4,d"}, {zBIT,"4,e"},
+ {zBIT,"4,h"}, {zBIT,"4,l"}, {zBIT,"4,(hl)"},{zBIT,"4,a"},
+ {zBIT,"5,b"}, {zBIT,"5,c"}, {zBIT,"5,d"}, {zBIT,"5,e"},
+ {zBIT,"5,h"}, {zBIT,"5,l"}, {zBIT,"5,(hl)"},{zBIT,"5,a"},
+ {zBIT,"6,b"}, {zBIT,"6,c"}, {zBIT,"6,d"}, {zBIT,"6,e"},
+ {zBIT,"6,h"}, {zBIT,"6,l"}, {zBIT,"6,(hl)"},{zBIT,"6,a"},
+ {zBIT,"7,b"}, {zBIT,"7,c"}, {zBIT,"7,d"}, {zBIT,"7,e"},
+ {zBIT,"7,h"}, {zBIT,"7,l"}, {zBIT,"7,(hl)"},{zBIT,"7,a"},
+ {zRES,"0,b"}, {zRES,"0,c"}, {zRES,"0,d"}, {zRES,"0,e"},
+ {zRES,"0,h"}, {zRES,"0,l"}, {zRES,"0,(hl)"},{zRES,"0,a"},
+ {zRES,"1,b"}, {zRES,"1,c"}, {zRES,"1,d"}, {zRES,"1,e"},
+ {zRES,"1,h"}, {zRES,"1,l"}, {zRES,"1,(hl)"},{zRES,"1,a"},
+ {zRES,"2,b"}, {zRES,"2,c"}, {zRES,"2,d"}, {zRES,"2,e"},
+ {zRES,"2,h"}, {zRES,"2,l"}, {zRES,"2,(hl)"},{zRES,"2,a"},
+ {zRES,"3,b"}, {zRES,"3,c"}, {zRES,"3,d"}, {zRES,"3,e"},
+ {zRES,"3,h"}, {zRES,"3,l"}, {zRES,"3,(hl)"},{zRES,"3,a"},
+ {zRES,"4,b"}, {zRES,"4,c"}, {zRES,"4,d"}, {zRES,"4,e"},
+ {zRES,"4,h"}, {zRES,"4,l"}, {zRES,"4,(hl)"},{zRES,"4,a"},
+ {zRES,"5,b"}, {zRES,"5,c"}, {zRES,"5,d"}, {zRES,"5,e"},
+ {zRES,"5,h"}, {zRES,"5,l"}, {zRES,"5,(hl)"},{zRES,"5,a"},
+ {zRES,"6,b"}, {zRES,"6,c"}, {zRES,"6,d"}, {zRES,"6,e"},
+ {zRES,"6,h"}, {zRES,"6,l"}, {zRES,"6,(hl)"},{zRES,"6,a"},
+ {zRES,"7,b"}, {zRES,"7,c"}, {zRES,"7,d"}, {zRES,"7,e"},
+ {zRES,"7,h"}, {zRES,"7,l"}, {zRES,"7,(hl)"},{zRES,"7,a"},
+ {zSET,"0,b"}, {zSET,"0,c"}, {zSET,"0,d"}, {zSET,"0,e"},
+ {zSET,"0,h"}, {zSET,"0,l"}, {zSET,"0,(hl)"},{zSET,"0,a"},
+ {zSET,"1,b"}, {zSET,"1,c"}, {zSET,"1,d"}, {zSET,"1,e"},
+ {zSET,"1,h"}, {zSET,"1,l"}, {zSET,"1,(hl)"},{zSET,"1,a"},
+ {zSET,"2,b"}, {zSET,"2,c"}, {zSET,"2,d"}, {zSET,"2,e"},
+ {zSET,"2,h"}, {zSET,"2,l"}, {zSET,"2,(hl)"},{zSET,"2,a"},
+ {zSET,"3,b"}, {zSET,"3,c"}, {zSET,"3,d"}, {zSET,"3,e"},
+ {zSET,"3,h"}, {zSET,"3,l"}, {zSET,"3,(hl)"},{zSET,"3,a"},
+ {zSET,"4,b"}, {zSET,"4,c"}, {zSET,"4,d"}, {zSET,"4,e"},
+ {zSET,"4,h"}, {zSET,"4,l"}, {zSET,"4,(hl)"},{zSET,"4,a"},
+ {zSET,"5,b"}, {zSET,"5,c"}, {zSET,"5,d"}, {zSET,"5,e"},
+ {zSET,"5,h"}, {zSET,"5,l"}, {zSET,"5,(hl)"},{zSET,"5,a"},
+ {zSET,"6,b"}, {zSET,"6,c"}, {zSET,"6,d"}, {zSET,"6,e"},
+ {zSET,"6,h"}, {zSET,"6,l"}, {zSET,"6,(hl)"},{zSET,"6,a"},
+ {zSET,"7,b"}, {zSET,"7,c"}, {zSET,"7,d"}, {zSET,"7,e"},
+ {zSET,"7,h"}, {zSET,"7,l"}, {zSET,"7,(hl)"},{zSET,"7,a"}
+};
+
+static z80dasm mnemonic_ed[256]= {
+ {zIN0,"b,(B)"}, {zOUT0,"(B),b"},{zDB,"?"}, {zDB,"?"},
+ {zTST,"b"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zIN0,"c,(B)"}, {zOUT0,"(B),c"},{zDB,"?"}, {zDB,"?"},
+ {zTST,"c"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zIN0,"d,(B)"}, {zOUT0,"(B),d"},{zDB,"?"}, {zDB,"?"},
+ {zTST,"d"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zIN0,"e,(B)"}, {zOUT0,"(B),e"},{zDB,"?"}, {zDB,"?"},
+ {zTST,"e"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zIN0,"h,(B)"}, {zOUT0,"(B),h"},{zDB,"?"}, {zDB,"?"},
+ {zTST,"h"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zIN0,"l,(B)"}, {zOUT0,"(B),l"},{zDB,"?"}, {zDB,"?"},
+ {zTST,"l"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zIN0,"f,(B)"}, {zOUT0,"(B),0"},{zDB,"?"}, {zDB,"?"},
+ {zTST,"(hl)"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zIN0,"a,(B)"}, {zOUT0,"(B),a"},{zDB,"?"}, {zDB,"?"},
+ {zTST,"a"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zIN,"b,(c)"}, {zOUT,"(c),b"}, {zSBC,"hl,bc"}, {zLD,"(W),bc"},
+ {zNEG,0}, {zRETN,0}, {zIM,"0"}, {zLD,"i,a"},
+ {zIN,"c,(c)"}, {zOUT,"(c),c"}, {zADC,"hl,bc"}, {zLD,"bc,(W)"},
+ {zMLT,"bc"}, {zRETI,0}, {zIM,"0"}, {zLD,"r,a"},
+ {zIN,"d,(c)"}, {zOUT,"(c),d"}, {zSBC,"hl,de"}, {zLD,"(W),de"},
+ {zNEG,"*"}, {zRETN,0}, {zIM,"1"}, {zLD,"a,i"},
+ {zIN,"e,(c)"}, {zOUT,"(c),e"}, {zADC,"hl,de"}, {zLD,"de,(W)"},
+ {zMLT,"de"}, {zRETI,0}, {zIM,"2"}, {zLD,"a,r"},
+ {zIN,"h,(c)"}, {zOUT,"(c),h"}, {zSBC,"hl,hl"}, {zLD,"(W),hl"},
+ {zTST,"B"}, {zRETN,0}, {zIM,"0"}, {zRRD,"(hl)"},
+ {zIN,"l,(c)"}, {zOUT,"(c),l"}, {zADC,"hl,hl"}, {zLD,"hl,(W)"},
+ {zMLT,"hl"}, {zRETI,0}, {zIM,"0"}, {zRLD,"(hl)"},
+ {zIN,"0,(c)"}, {zOUT,"(c),0"}, {zSBC,"hl,sp"}, {zLD,"(W),sp"},
+ {zTSTIO,"B"}, {zRETN,0}, {zSLP,0}, {zDB,"?"},
+ {zIN,"a,(c)"}, {zOUT,"(c),a"}, {zADC,"hl,sp"}, {zLD,"sp,(W)"},
+ {zMLT,"sp"}, {zRETI,0}, {zIM,"2"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zOTIM,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zOTDM,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zOTIMR,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zOTDMR,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLDI,0}, {zCPI,0}, {zINI,0}, {zOUTI,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLDD,0}, {zCPD,0}, {zIND,0}, {zOUTD,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLDIR,0}, {zCPIR,0}, {zINIR,0}, {zOTIR,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLDDR,0}, {zCPDR,0}, {zINDR,0}, {zOTDR,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}
+};
+
+static z80dasm mnemonic_xx[256]= {
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zADD,"I,bc"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zADD,"I,de"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zLD,"I,N"}, {zLD,"(W),I"}, {zINC,"I"},
+ {zINC,"Ih"}, {zDEC,"Ih"}, {zLD,"Ih,B"}, {zDB,"?"},
+ {zDB,"?"}, {zADD,"I,I"}, {zLD,"I,(W)"}, {zDEC,"I"},
+ {zINC,"Il"}, {zDEC,"Il"}, {zLD,"Il,B"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zINC,"X"}, {zDEC,"X"}, {zLD,"X,B"}, {zDB,"?"},
+ {zDB,"?"}, {zADD,"I,sp"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"b,Ih"}, {zLD,"b,Il"}, {zLD,"b,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"c,Ih"}, {zLD,"c,Il"}, {zLD,"c,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"d,Ih"}, {zLD,"d,Il"}, {zLD,"d,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"e,Ih"}, {zLD,"e,Il"}, {zLD,"e,X"}, {zDB,"?"},
+ {zLD,"Ih,b"}, {zLD,"Ih,c"}, {zLD,"Ih,d"}, {zLD,"Ih,e"},
+ {zLD,"Ih,Ih"}, {zLD,"Ih,Il"}, {zLD,"h,X"}, {zLD,"Ih,a"},
+ {zLD,"Il,b"}, {zLD,"Il,c"}, {zLD,"Il,d"}, {zLD,"Il,e"},
+ {zLD,"Il,Ih"}, {zLD,"Il,Il"}, {zLD,"l,X"}, {zLD,"Il,a"},
+ {zLD,"X,b"}, {zLD,"X,c"}, {zLD,"X,d"}, {zLD,"X,e"},
+ {zLD,"X,h"}, {zLD,"X,l"}, {zDB,"?"}, {zLD,"X,a"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"a,Ih"}, {zLD,"a,Il"}, {zLD,"a,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zADD,"a,Ih"}, {zADD,"a,Il"}, {zADD,"a,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zADC,"a,Ih"}, {zADC,"a,Il"}, {zADC,"a,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zSUB,"Ih"}, {zSUB,"Il"}, {zSUB,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zSBC,"a,Ih"}, {zSBC,"a,Il"}, {zSBC,"a,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zAND,"Ih"}, {zAND,"Il"}, {zAND,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zXOR,"Ih"}, {zXOR,"Il"}, {zXOR,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zOR,"Ih"}, {zOR,"Il"}, {zOR,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zCP,"Ih"}, {zCP,"Il"}, {zCP,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"cb"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zPOP,"I"}, {zDB,"?"}, {zEX,"(sp),I"},
+ {zDB,"?"}, {zPUSH,"I"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zJP,"(I)"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zLD,"sp,I"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}
+};
+
+static z80dasm mnemonic_main[256]= {
+ {zNOP,0}, {zLD,"bc,N"}, {zLD,"(bc),a"}, {zINC,"bc"},
+ {zINC,"b"}, {zDEC,"b"}, {zLD,"b,B"}, {zRLCA,0},
+ {zEX,"af,af'"}, {zADD,"hl,bc"}, {zLD,"a,(bc)"}, {zDEC,"bc"},
+ {zINC,"c"}, {zDEC,"c"}, {zLD,"c,B"}, {zRRCA,0},
+ {zDJNZ,"O"}, {zLD,"de,N"}, {zLD,"(de),a"}, {zINC,"de"},
+ {zINC,"d"}, {zDEC,"d"}, {zLD,"d,B"}, {zRLA,0},
+ {zJR,"O"}, {zADD,"hl,de"}, {zLD,"a,(de)"}, {zDEC,"de"},
+ {zINC,"e"}, {zDEC,"e"}, {zLD,"e,B"}, {zRRA,0},
+ {zJR,"nz,O"}, {zLD,"hl,N"}, {zLD,"(W),hl"}, {zINC,"hl"},
+ {zINC,"h"}, {zDEC,"h"}, {zLD,"h,B"}, {zDAA,0},
+ {zJR,"z,O"}, {zADD,"hl,hl"}, {zLD,"hl,(W)"}, {zDEC,"hl"},
+ {zINC,"l"}, {zDEC,"l"}, {zLD,"l,B"}, {zCPL,0},
+ {zJR,"nc,O"}, {zLD,"sp,N"}, {zLD,"(W),a"}, {zINC,"sp"},
+ {zINC,"(hl)"}, {zDEC,"(hl)"}, {zLD,"(hl),B"}, {zSCF,0},
+ {zJR,"c,O"}, {zADD,"hl,sp"}, {zLD,"a,(W)"}, {zDEC,"sp"},
+ {zINC,"a"}, {zDEC,"a"}, {zLD,"a,B"}, {zCCF,0},
+ {zLD,"b,b"}, {zLD,"b,c"}, {zLD,"b,d"}, {zLD,"b,e"},
+ {zLD,"b,h"}, {zLD,"b,l"}, {zLD,"b,(hl)"}, {zLD,"b,a"},
+ {zLD,"c,b"}, {zLD,"c,c"}, {zLD,"c,d"}, {zLD,"c,e"},
+ {zLD,"c,h"}, {zLD,"c,l"}, {zLD,"c,(hl)"}, {zLD,"c,a"},
+ {zLD,"d,b"}, {zLD,"d,c"}, {zLD,"d,d"}, {zLD,"d,e"},
+ {zLD,"d,h"}, {zLD,"d,l"}, {zLD,"d,(hl)"}, {zLD,"d,a"},
+ {zLD,"e,b"}, {zLD,"e,c"}, {zLD,"e,d"}, {zLD,"e,e"},
+ {zLD,"e,h"}, {zLD,"e,l"}, {zLD,"e,(hl)"}, {zLD,"e,a"},
+ {zLD,"h,b"}, {zLD,"h,c"}, {zLD,"h,d"}, {zLD,"h,e"},
+ {zLD,"h,h"}, {zLD,"h,l"}, {zLD,"h,(hl)"}, {zLD,"h,a"},
+ {zLD,"l,b"}, {zLD,"l,c"}, {zLD,"l,d"}, {zLD,"l,e"},
+ {zLD,"l,h"}, {zLD,"l,l"}, {zLD,"l,(hl)"}, {zLD,"l,a"},
+ {zLD,"(hl),b"}, {zLD,"(hl),c"}, {zLD,"(hl),d"}, {zLD,"(hl),e"},
+ {zLD,"(hl),h"}, {zLD,"(hl),l"}, {zHLT,0}, {zLD,"(hl),a"},
+ {zLD,"a,b"}, {zLD,"a,c"}, {zLD,"a,d"}, {zLD,"a,e"},
+ {zLD,"a,h"}, {zLD,"a,l"}, {zLD,"a,(hl)"}, {zLD,"a,a"},
+ {zADD,"a,b"}, {zADD,"a,c"}, {zADD,"a,d"}, {zADD,"a,e"},
+ {zADD,"a,h"}, {zADD,"a,l"}, {zADD,"a,(hl)"},{zADD,"a,a"},
+ {zADC,"a,b"}, {zADC,"a,c"}, {zADC,"a,d"}, {zADC,"a,e"},
+ {zADC,"a,h"}, {zADC,"a,l"}, {zADC,"a,(hl)"},{zADC,"a,a"},
+ {zSUB,"b"}, {zSUB,"c"}, {zSUB,"d"}, {zSUB,"e"},
+ {zSUB,"h"}, {zSUB,"l"}, {zSUB,"(hl)"}, {zSUB,"a"},
+ {zSBC,"a,b"}, {zSBC,"a,c"}, {zSBC,"a,d"}, {zSBC,"a,e"},
+ {zSBC,"a,h"}, {zSBC,"a,l"}, {zSBC,"a,(hl)"},{zSBC,"a,a"},
+ {zAND,"b"}, {zAND,"c"}, {zAND,"d"}, {zAND,"e"},
+ {zAND,"h"}, {zAND,"l"}, {zAND,"(hl)"}, {zAND,"a"},
+ {zXOR,"b"}, {zXOR,"c"}, {zXOR,"d"}, {zXOR,"e"},
+ {zXOR,"h"}, {zXOR,"l"}, {zXOR,"(hl)"}, {zXOR,"a"},
+ {zOR,"b"}, {zOR,"c"}, {zOR,"d"}, {zOR,"e"},
+ {zOR,"h"}, {zOR,"l"}, {zOR,"(hl)"}, {zOR,"a"},
+ {zCP,"b"}, {zCP,"c"}, {zCP,"d"}, {zCP,"e"},
+ {zCP,"h"}, {zCP,"l"}, {zCP,"(hl)"}, {zCP,"a"},
+ {zRET,"nz"}, {zPOP,"bc"}, {zJP,"nz,A"}, {zJP,"A"},
+ {zCALL,"nz,A"}, {zPUSH,"bc"}, {zADD,"a,B"}, {zRST,"V"},
+ {zRET,"z"}, {zRET,0}, {zJP,"z,A"}, {zDB,"cb"},
+ {zCALL,"z,A"}, {zCALL,"A"}, {zADC,"a,B"}, {zRST,"V"},
+ {zRET,"nc"}, {zPOP,"de"}, {zJP,"nc,A"}, {zOUT,"(P),a"},
+ {zCALL,"nc,A"}, {zPUSH,"de"}, {zSUB,"B"}, {zRST,"V"},
+ {zRET,"c"}, {zEXX,0}, {zJP,"c,A"}, {zIN,"a,(P)"},
+ {zCALL,"c,A"}, {zDB,"dd"}, {zSBC,"a,B"}, {zRST,"V"},
+ {zRET,"po"}, {zPOP,"hl"}, {zJP,"po,A"}, {zEX,"(sp),hl"},
+ {zCALL,"po,A"}, {zPUSH,"hl"}, {zAND,"B"}, {zRST,"V"},
+ {zRET,"pe"}, {zJP,"(hl)"}, {zJP,"pe,A"}, {zEX,"de,hl"},
+ {zCALL,"pe,A"}, {zDB,"ed"}, {zXOR,"B"}, {zRST,"V"},
+ {zRET,"p"}, {zPOP,"af"}, {zJP,"p,A"}, {zDI,0},
+ {zCALL,"p,A"}, {zPUSH,"af"}, {zOR,"B"}, {zRST,"V"},
+ {zRET,"m"}, {zLD,"sp,hl"}, {zJP,"m,A"}, {zEI,0},
+ {zCALL,"m,A"}, {zDB,"fd"}, {zCP,"B"}, {zRST,"V"}
+};
+
+static char sign(INT8 offset)
+{
+ return (offset < 0)? '-':'+';
+}
+
+static int offs(INT8 offset)
+{
+ if (offset < 0) return -offset;
+ return offset;
+}
+
+/****************************************************************************
+ * Disassemble opcode at PC and return number of bytes it takes
+ ****************************************************************************/
+offs_t z180_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ z80dasm *d;
+ const char *src, *ixy;
+ char *dst;
+ unsigned PC = pc;
+ INT8 offset = 0;
+ UINT8 op, op1 = 0;
+ UINT16 ea = 0;
+ int pos = 0;
+ UINT32 flags = 0;
+
+ ixy = "oops!!";
+ dst = buffer;
+
+ op = oprom[pos++];
+
+ switch (op)
+ {
+ case 0xcb:
+ op = oprom[pos++];
+ d = &mnemonic_cb[op];
+ break;
+ case 0xed:
+ op1 = oprom[pos++];
+ d = &mnemonic_ed[op1];
+ break;
+ case 0xdd:
+ ixy = "ix";
+ op1 = oprom[pos++];
+ if( op1 == 0xcb )
+ {
+ offset = (INT8) opram[pos++];
+ op1 = opram[pos++]; /* fourth byte from opcode_arg_base! */
+ d = &mnemonic_xx_cb[op1];
+ }
+ else d = &mnemonic_xx[op1];
+ break;
+ case 0xfd:
+ ixy = "iy";
+ op1 = oprom[pos++];
+ if( op1 == 0xcb )
+ {
+ offset = (INT8) opram[pos++];
+ op1 = opram[pos++]; /* fourth byte from opcode_arg_base! */
+ d = &mnemonic_xx_cb[op1];
+ }
+ else d = &mnemonic_xx[op1];
+ break;
+ default:
+ d = &mnemonic_main[op];
+ break;
+ }
+
+ if( d->arguments )
+ {
+ dst += sprintf(dst, "%-5s ", s_mnemonic[d->mnemonic]);
+ src = d->arguments;
+ while( *src )
+ {
+ switch( *src )
+ {
+ case '?': /* illegal opcode */
+ dst += sprintf( dst, "$%02x,$%02x", op, op1);
+ break;
+ case 'A':
+ ea = opram[pos] + ( opram[pos+1] << 8);
+ pos += 2;
+ dst += sprintf( dst, "$%04X", ea );
+ break;
+ case 'B': /* Byte op arg */
+ ea = opram[pos++];
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case 'N': /* Immediate 16 bit */
+ ea = opram[pos] + ( opram[pos+1] << 8 );
+ pos += 2;
+ dst += sprintf( dst, "$%04X", ea );
+ break;
+ case 'O': /* Offset relative to PC */
+ offset = (INT8) opram[pos++];
+ dst += sprintf( dst, "$%05X", PC + offset + 2 );
+ break;
+ case 'P': /* Port number */
+ ea = opram[pos++];
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case 'V': /* Restart vector */
+ ea = op & 0x38;
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case 'W': /* Memory address word */
+ ea = opram[pos] + ( opram[pos+1] << 8);
+ pos += 2;
+ dst += sprintf( dst, "$%05X", ea );
+ break;
+ case 'X':
+ offset = (INT8) opram[pos++];
+ case 'Y':
+ dst += sprintf( dst,"(%s%c$%02x)", ixy, sign(offset), offs(offset) );
+ break;
+ case 'I':
+ dst += sprintf( dst, "%s", ixy);
+ break;
+ default:
+ *dst++ = *src;
+ }
+ src++;
+ }
+ *dst = '\0';
+ }
+ else
+ {
+ dst += sprintf(dst, "%s", s_mnemonic[d->mnemonic]);
+ }
+
+ if (d->mnemonic == zCALL || d->mnemonic == zCPDR || d->mnemonic == zCPIR || d->mnemonic == zDJNZ ||
+ d->mnemonic == zHLT || d->mnemonic == zINDR || d->mnemonic == zINIR || d->mnemonic == zLDDR ||
+ d->mnemonic == zLDIR || d->mnemonic == zOTDR || d->mnemonic == zOTIR || d->mnemonic == zRST)
+ flags = DASMFLAG_STEP_OVER;
+ else if (d->mnemonic == zRETN || d->mnemonic == zRET || d->mnemonic == zRETI)
+ flags = DASMFLAG_STEP_OUT;
+
+ return pos | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/z180/z180dd.c b/src/emu/cpu/z180/z180dd.c
new file mode 100644
index 00000000000..92fba05943d
--- /dev/null
+++ b/src/emu/cpu/z180/z180dd.c
@@ -0,0 +1,296 @@
+OP(illegal,1) {
+ logerror("Z180 #%d ill. opcode $%02x $%02x\n",
+ cpu_getactivecpu(), cpu_readop((_PCD-1)&0xffff), cpu_readop(_PCD));
+}
+
+/**********************************************************
+ * IX register related opcodes (DD prefix)
+ **********************************************************/
+OP(dd,00) { illegal_1(); op_00(); } /* DB DD */
+OP(dd,01) { illegal_1(); op_01(); } /* DB DD */
+OP(dd,02) { illegal_1(); op_02(); } /* DB DD */
+OP(dd,03) { illegal_1(); op_03(); } /* DB DD */
+OP(dd,04) { illegal_1(); op_04(); } /* DB DD */
+OP(dd,05) { illegal_1(); op_05(); } /* DB DD */
+OP(dd,06) { illegal_1(); op_06(); } /* DB DD */
+OP(dd,07) { illegal_1(); op_07(); } /* DB DD */
+
+OP(dd,08) { illegal_1(); op_08(); } /* DB DD */
+OP(dd,09) { _R++; ADD16(IX,BC); } /* ADD IX,BC */
+OP(dd,0a) { illegal_1(); op_0a(); } /* DB DD */
+OP(dd,0b) { illegal_1(); op_0b(); } /* DB DD */
+OP(dd,0c) { illegal_1(); op_0c(); } /* DB DD */
+OP(dd,0d) { illegal_1(); op_0d(); } /* DB DD */
+OP(dd,0e) { illegal_1(); op_0e(); } /* DB DD */
+OP(dd,0f) { illegal_1(); op_0f(); } /* DB DD */
+
+OP(dd,10) { illegal_1(); op_10(); } /* DB DD */
+OP(dd,11) { illegal_1(); op_11(); } /* DB DD */
+OP(dd,12) { illegal_1(); op_12(); } /* DB DD */
+OP(dd,13) { illegal_1(); op_13(); } /* DB DD */
+OP(dd,14) { illegal_1(); op_14(); } /* DB DD */
+OP(dd,15) { illegal_1(); op_15(); } /* DB DD */
+OP(dd,16) { illegal_1(); op_16(); } /* DB DD */
+OP(dd,17) { illegal_1(); op_17(); } /* DB DD */
+
+OP(dd,18) { illegal_1(); op_18(); } /* DB DD */
+OP(dd,19) { _R++; ADD16(IX,DE); } /* ADD IX,DE */
+OP(dd,1a) { illegal_1(); op_1a(); } /* DB DD */
+OP(dd,1b) { illegal_1(); op_1b(); } /* DB DD */
+OP(dd,1c) { illegal_1(); op_1c(); } /* DB DD */
+OP(dd,1d) { illegal_1(); op_1d(); } /* DB DD */
+OP(dd,1e) { illegal_1(); op_1e(); } /* DB DD */
+OP(dd,1f) { illegal_1(); op_1f(); } /* DB DD */
+
+OP(dd,20) { illegal_1(); op_20(); } /* DB DD */
+OP(dd,21) { _R++; _IX = ARG16(); } /* LD IX,w */
+OP(dd,22) { _R++; EA = ARG16(); WM16( EA, &Z180.IX ); } /* LD (w),IX */
+OP(dd,23) { _R++; _IX++; } /* INC IX */
+OP(dd,24) { _R++; _HX = INC(_HX); } /* INC HX */
+OP(dd,25) { _R++; _HX = DEC(_HX); } /* DEC HX */
+OP(dd,26) { _R++; _HX = ARG(); } /* LD HX,n */
+OP(dd,27) { illegal_1(); op_27(); } /* DB DD */
+
+OP(dd,28) { illegal_1(); op_28(); } /* DB DD */
+OP(dd,29) { _R++; ADD16(IX,IX); } /* ADD IX,IX */
+OP(dd,2a) { _R++; EA = ARG16(); RM16( EA, &Z180.IX ); } /* LD IX,(w) */
+OP(dd,2b) { _R++; _IX--; } /* DEC IX */
+OP(dd,2c) { _R++; _LX = INC(_LX); } /* INC LX */
+OP(dd,2d) { _R++; _LX = DEC(_LX); } /* DEC LX */
+OP(dd,2e) { _R++; _LX = ARG(); } /* LD LX,n */
+OP(dd,2f) { illegal_1(); op_2f(); } /* DB DD */
+
+OP(dd,30) { illegal_1(); op_30(); } /* DB DD */
+OP(dd,31) { illegal_1(); op_31(); } /* DB DD */
+OP(dd,32) { illegal_1(); op_32(); } /* DB DD */
+OP(dd,33) { illegal_1(); op_33(); } /* DB DD */
+OP(dd,34) { _R++; EAX; WM( EA, INC(RM(EA)) ); } /* INC (IX+o) */
+OP(dd,35) { _R++; EAX; WM( EA, DEC(RM(EA)) ); } /* DEC (IX+o) */
+OP(dd,36) { _R++; EAX; WM( EA, ARG() ); } /* LD (IX+o),n */
+OP(dd,37) { illegal_1(); op_37(); } /* DB DD */
+
+OP(dd,38) { illegal_1(); op_38(); } /* DB DD */
+OP(dd,39) { _R++; ADD16(IX,SP); } /* ADD IX,SP */
+OP(dd,3a) { illegal_1(); op_3a(); } /* DB DD */
+OP(dd,3b) { illegal_1(); op_3b(); } /* DB DD */
+OP(dd,3c) { illegal_1(); op_3c(); } /* DB DD */
+OP(dd,3d) { illegal_1(); op_3d(); } /* DB DD */
+OP(dd,3e) { illegal_1(); op_3e(); } /* DB DD */
+OP(dd,3f) { illegal_1(); op_3f(); } /* DB DD */
+
+OP(dd,40) { illegal_1(); op_40(); } /* DB DD */
+OP(dd,41) { illegal_1(); op_41(); } /* DB DD */
+OP(dd,42) { illegal_1(); op_42(); } /* DB DD */
+OP(dd,43) { illegal_1(); op_43(); } /* DB DD */
+OP(dd,44) { _R++; _B = _HX; } /* LD B,HX */
+OP(dd,45) { _R++; _B = _LX; } /* LD B,LX */
+OP(dd,46) { _R++; EAX; _B = RM(EA); } /* LD B,(IX+o) */
+OP(dd,47) { illegal_1(); op_47(); } /* DB DD */
+
+OP(dd,48) { illegal_1(); op_48(); } /* DB DD */
+OP(dd,49) { illegal_1(); op_49(); } /* DB DD */
+OP(dd,4a) { illegal_1(); op_4a(); } /* DB DD */
+OP(dd,4b) { illegal_1(); op_4b(); } /* DB DD */
+OP(dd,4c) { _R++; _C = _HX; } /* LD C,HX */
+OP(dd,4d) { _R++; _C = _LX; } /* LD C,LX */
+OP(dd,4e) { _R++; EAX; _C = RM(EA); } /* LD C,(IX+o) */
+OP(dd,4f) { illegal_1(); op_4f(); } /* DB DD */
+
+OP(dd,50) { illegal_1(); op_50(); } /* DB DD */
+OP(dd,51) { illegal_1(); op_51(); } /* DB DD */
+OP(dd,52) { illegal_1(); op_52(); } /* DB DD */
+OP(dd,53) { illegal_1(); op_53(); } /* DB DD */
+OP(dd,54) { _R++; _D = _HX; } /* LD D,HX */
+OP(dd,55) { _R++; _D = _LX; } /* LD D,LX */
+OP(dd,56) { _R++; EAX; _D = RM(EA); } /* LD D,(IX+o) */
+OP(dd,57) { illegal_1(); op_57(); } /* DB DD */
+
+OP(dd,58) { illegal_1(); op_58(); } /* DB DD */
+OP(dd,59) { illegal_1(); op_59(); } /* DB DD */
+OP(dd,5a) { illegal_1(); op_5a(); } /* DB DD */
+OP(dd,5b) { illegal_1(); op_5b(); } /* DB DD */
+OP(dd,5c) { _R++; _E = _HX; } /* LD E,HX */
+OP(dd,5d) { _R++; _E = _LX; } /* LD E,LX */
+OP(dd,5e) { _R++; EAX; _E = RM(EA); } /* LD E,(IX+o) */
+OP(dd,5f) { illegal_1(); op_5f(); } /* DB DD */
+
+OP(dd,60) { _R++; _HX = _B; } /* LD HX,B */
+OP(dd,61) { _R++; _HX = _C; } /* LD HX,C */
+OP(dd,62) { _R++; _HX = _D; } /* LD HX,D */
+OP(dd,63) { _R++; _HX = _E; } /* LD HX,E */
+OP(dd,64) { } /* LD HX,HX */
+OP(dd,65) { _R++; _HX = _LX; } /* LD HX,LX */
+OP(dd,66) { _R++; EAX; _H = RM(EA); } /* LD H,(IX+o) */
+OP(dd,67) { _R++; _HX = _A; } /* LD HX,A */
+
+OP(dd,68) { _R++; _LX = _B; } /* LD LX,B */
+OP(dd,69) { _R++; _LX = _C; } /* LD LX,C */
+OP(dd,6a) { _R++; _LX = _D; } /* LD LX,D */
+OP(dd,6b) { _R++; _LX = _E; } /* LD LX,E */
+OP(dd,6c) { _R++; _LX = _HX; } /* LD LX,HX */
+OP(dd,6d) { } /* LD LX,LX */
+OP(dd,6e) { _R++; EAX; _L = RM(EA); } /* LD L,(IX+o) */
+OP(dd,6f) { _R++; _LX = _A; } /* LD LX,A */
+
+OP(dd,70) { _R++; EAX; WM( EA, _B ); } /* LD (IX+o),B */
+OP(dd,71) { _R++; EAX; WM( EA, _C ); } /* LD (IX+o),C */
+OP(dd,72) { _R++; EAX; WM( EA, _D ); } /* LD (IX+o),D */
+OP(dd,73) { _R++; EAX; WM( EA, _E ); } /* LD (IX+o),E */
+OP(dd,74) { _R++; EAX; WM( EA, _H ); } /* LD (IX+o),H */
+OP(dd,75) { _R++; EAX; WM( EA, _L ); } /* LD (IX+o),L */
+OP(dd,76) { illegal_1(); op_76(); } /* DB DD */
+OP(dd,77) { _R++; EAX; WM( EA, _A ); } /* LD (IX+o),A */
+
+OP(dd,78) { illegal_1(); op_78(); } /* DB DD */
+OP(dd,79) { illegal_1(); op_79(); } /* DB DD */
+OP(dd,7a) { illegal_1(); op_7a(); } /* DB DD */
+OP(dd,7b) { illegal_1(); op_7b(); } /* DB DD */
+OP(dd,7c) { _R++; _A = _HX; } /* LD A,HX */
+OP(dd,7d) { _R++; _A = _LX; } /* LD A,LX */
+OP(dd,7e) { _R++; EAX; _A = RM(EA); } /* LD A,(IX+o) */
+OP(dd,7f) { illegal_1(); op_7f(); } /* DB DD */
+
+OP(dd,80) { illegal_1(); op_80(); } /* DB DD */
+OP(dd,81) { illegal_1(); op_81(); } /* DB DD */
+OP(dd,82) { illegal_1(); op_82(); } /* DB DD */
+OP(dd,83) { illegal_1(); op_83(); } /* DB DD */
+OP(dd,84) { _R++; ADD(_HX); } /* ADD A,HX */
+OP(dd,85) { _R++; ADD(_LX); } /* ADD A,LX */
+OP(dd,86) { _R++; EAX; ADD(RM(EA)); } /* ADD A,(IX+o) */
+OP(dd,87) { illegal_1(); op_87(); } /* DB DD */
+
+OP(dd,88) { illegal_1(); op_88(); } /* DB DD */
+OP(dd,89) { illegal_1(); op_89(); } /* DB DD */
+OP(dd,8a) { illegal_1(); op_8a(); } /* DB DD */
+OP(dd,8b) { illegal_1(); op_8b(); } /* DB DD */
+OP(dd,8c) { _R++; ADC(_HX); } /* ADC A,HX */
+OP(dd,8d) { _R++; ADC(_LX); } /* ADC A,LX */
+OP(dd,8e) { _R++; EAX; ADC(RM(EA)); } /* ADC A,(IX+o) */
+OP(dd,8f) { illegal_1(); op_8f(); } /* DB DD */
+
+OP(dd,90) { illegal_1(); op_90(); } /* DB DD */
+OP(dd,91) { illegal_1(); op_91(); } /* DB DD */
+OP(dd,92) { illegal_1(); op_92(); } /* DB DD */
+OP(dd,93) { illegal_1(); op_93(); } /* DB DD */
+OP(dd,94) { _R++; SUB(_HX); } /* SUB HX */
+OP(dd,95) { _R++; SUB(_LX); } /* SUB LX */
+OP(dd,96) { _R++; EAX; SUB(RM(EA)); } /* SUB (IX+o) */
+OP(dd,97) { illegal_1(); op_97(); } /* DB DD */
+
+OP(dd,98) { illegal_1(); op_98(); } /* DB DD */
+OP(dd,99) { illegal_1(); op_99(); } /* DB DD */
+OP(dd,9a) { illegal_1(); op_9a(); } /* DB DD */
+OP(dd,9b) { illegal_1(); op_9b(); } /* DB DD */
+OP(dd,9c) { _R++; SBC(_HX); } /* SBC A,HX */
+OP(dd,9d) { _R++; SBC(_LX); } /* SBC A,LX */
+OP(dd,9e) { _R++; EAX; SBC(RM(EA)); } /* SBC A,(IX+o) */
+OP(dd,9f) { illegal_1(); op_9f(); } /* DB DD */
+
+OP(dd,a0) { illegal_1(); op_a0(); } /* DB DD */
+OP(dd,a1) { illegal_1(); op_a1(); } /* DB DD */
+OP(dd,a2) { illegal_1(); op_a2(); } /* DB DD */
+OP(dd,a3) { illegal_1(); op_a3(); } /* DB DD */
+OP(dd,a4) { _R++; AND(_HX); } /* AND HX */
+OP(dd,a5) { _R++; AND(_LX); } /* AND LX */
+OP(dd,a6) { _R++; EAX; AND(RM(EA)); } /* AND (IX+o) */
+OP(dd,a7) { illegal_1(); op_a7(); } /* DB DD */
+
+OP(dd,a8) { illegal_1(); op_a8(); } /* DB DD */
+OP(dd,a9) { illegal_1(); op_a9(); } /* DB DD */
+OP(dd,aa) { illegal_1(); op_aa(); } /* DB DD */
+OP(dd,ab) { illegal_1(); op_ab(); } /* DB DD */
+OP(dd,ac) { _R++; XOR(_HX); } /* XOR HX */
+OP(dd,ad) { _R++; XOR(_LX); } /* XOR LX */
+OP(dd,ae) { _R++; EAX; XOR(RM(EA)); } /* XOR (IX+o) */
+OP(dd,af) { illegal_1(); op_af(); } /* DB DD */
+
+OP(dd,b0) { illegal_1(); op_b0(); } /* DB DD */
+OP(dd,b1) { illegal_1(); op_b1(); } /* DB DD */
+OP(dd,b2) { illegal_1(); op_b2(); } /* DB DD */
+OP(dd,b3) { illegal_1(); op_b3(); } /* DB DD */
+OP(dd,b4) { _R++; OR(_HX); } /* OR HX */
+OP(dd,b5) { _R++; OR(_LX); } /* OR LX */
+OP(dd,b6) { _R++; EAX; OR(RM(EA)); } /* OR (IX+o) */
+OP(dd,b7) { illegal_1(); op_b7(); } /* DB DD */
+
+OP(dd,b8) { illegal_1(); op_b8(); } /* DB DD */
+OP(dd,b9) { illegal_1(); op_b9(); } /* DB DD */
+OP(dd,ba) { illegal_1(); op_ba(); } /* DB DD */
+OP(dd,bb) { illegal_1(); op_bb(); } /* DB DD */
+OP(dd,bc) { _R++; CP(_HX); } /* CP HX */
+OP(dd,bd) { _R++; CP(_LX); } /* CP LX */
+OP(dd,be) { _R++; EAX; CP(RM(EA)); } /* CP (IX+o) */
+OP(dd,bf) { illegal_1(); op_bf(); } /* DB DD */
+
+OP(dd,c0) { illegal_1(); op_c0(); } /* DB DD */
+OP(dd,c1) { illegal_1(); op_c1(); } /* DB DD */
+OP(dd,c2) { illegal_1(); op_c2(); } /* DB DD */
+OP(dd,c3) { illegal_1(); op_c3(); } /* DB DD */
+OP(dd,c4) { illegal_1(); op_c4(); } /* DB DD */
+OP(dd,c5) { illegal_1(); op_c5(); } /* DB DD */
+OP(dd,c6) { illegal_1(); op_c6(); } /* DB DD */
+OP(dd,c7) { illegal_1(); op_c7(); } /* DB DD */
+
+OP(dd,c8) { illegal_1(); op_c8(); } /* DB DD */
+OP(dd,c9) { illegal_1(); op_c9(); } /* DB DD */
+OP(dd,ca) { illegal_1(); op_ca(); } /* DB DD */
+OP(dd,cb) { _R++; EAX; EXEC(xycb,ARG()); } /* ** DD CB xx */
+OP(dd,cc) { illegal_1(); op_cc(); } /* DB DD */
+OP(dd,cd) { illegal_1(); op_cd(); } /* DB DD */
+OP(dd,ce) { illegal_1(); op_ce(); } /* DB DD */
+OP(dd,cf) { illegal_1(); op_cf(); } /* DB DD */
+
+OP(dd,d0) { illegal_1(); op_d0(); } /* DB DD */
+OP(dd,d1) { illegal_1(); op_d1(); } /* DB DD */
+OP(dd,d2) { illegal_1(); op_d2(); } /* DB DD */
+OP(dd,d3) { illegal_1(); op_d3(); } /* DB DD */
+OP(dd,d4) { illegal_1(); op_d4(); } /* DB DD */
+OP(dd,d5) { illegal_1(); op_d5(); } /* DB DD */
+OP(dd,d6) { illegal_1(); op_d6(); } /* DB DD */
+OP(dd,d7) { illegal_1(); op_d7(); } /* DB DD */
+
+OP(dd,d8) { illegal_1(); op_d8(); } /* DB DD */
+OP(dd,d9) { illegal_1(); op_d9(); } /* DB DD */
+OP(dd,da) { illegal_1(); op_da(); } /* DB DD */
+OP(dd,db) { illegal_1(); op_db(); } /* DB DD */
+OP(dd,dc) { illegal_1(); op_dc(); } /* DB DD */
+OP(dd,dd) { illegal_1(); op_dd(); } /* DB DD */
+OP(dd,de) { illegal_1(); op_de(); } /* DB DD */
+OP(dd,df) { illegal_1(); op_df(); } /* DB DD */
+
+OP(dd,e0) { illegal_1(); op_e0(); } /* DB DD */
+OP(dd,e1) { _R++; POP(IX); } /* POP IX */
+OP(dd,e2) { illegal_1(); op_e2(); } /* DB DD */
+OP(dd,e3) { _R++; EXSP(IX); } /* EX (SP),IX */
+OP(dd,e4) { illegal_1(); op_e4(); } /* DB DD */
+OP(dd,e5) { _R++; PUSH( IX ); } /* PUSH IX */
+OP(dd,e6) { illegal_1(); op_e6(); } /* DB DD */
+OP(dd,e7) { illegal_1(); op_e7(); } /* DB DD */
+
+OP(dd,e8) { illegal_1(); op_e8(); } /* DB DD */
+OP(dd,e9) { _R++; _PC = _IX; z180_change_pc(_PCD); } /* JP (IX) */
+OP(dd,ea) { illegal_1(); op_ea(); } /* DB DD */
+OP(dd,eb) { illegal_1(); op_eb(); } /* DB DD */
+OP(dd,ec) { illegal_1(); op_ec(); } /* DB DD */
+OP(dd,ed) { illegal_1(); op_ed(); } /* DB DD */
+OP(dd,ee) { illegal_1(); op_ee(); } /* DB DD */
+OP(dd,ef) { illegal_1(); op_ef(); } /* DB DD */
+
+OP(dd,f0) { illegal_1(); op_f0(); } /* DB DD */
+OP(dd,f1) { illegal_1(); op_f1(); } /* DB DD */
+OP(dd,f2) { illegal_1(); op_f2(); } /* DB DD */
+OP(dd,f3) { illegal_1(); op_f3(); } /* DB DD */
+OP(dd,f4) { illegal_1(); op_f4(); } /* DB DD */
+OP(dd,f5) { illegal_1(); op_f5(); } /* DB DD */
+OP(dd,f6) { illegal_1(); op_f6(); } /* DB DD */
+OP(dd,f7) { illegal_1(); op_f7(); } /* DB DD */
+
+OP(dd,f8) { illegal_1(); op_f8(); } /* DB DD */
+OP(dd,f9) { _R++; _SP = _IX; } /* LD SP,IX */
+OP(dd,fa) { illegal_1(); op_fa(); } /* DB DD */
+OP(dd,fb) { illegal_1(); op_fb(); } /* DB DD */
+OP(dd,fc) { illegal_1(); op_fc(); } /* DB DD */
+OP(dd,fd) { illegal_1(); op_fd(); } /* DB DD */
+OP(dd,fe) { illegal_1(); op_fe(); } /* DB DD */
+OP(dd,ff) { illegal_1(); op_ff(); } /* DB DD */
+
diff --git a/src/emu/cpu/z180/z180ed.c b/src/emu/cpu/z180/z180ed.c
new file mode 100644
index 00000000000..7bfd500c991
--- /dev/null
+++ b/src/emu/cpu/z180/z180ed.c
@@ -0,0 +1,297 @@
+OP(illegal,2)
+{
+ logerror("Z180 #%d ill. opcode $ed $%02x\n",
+ cpu_getactivecpu(), cpu_readop((_PCD-1)&0xffff));
+}
+
+/**********************************************************
+ * special opcodes (ED prefix)
+ **********************************************************/
+OP(ed,00) { unsigned n = ARG(); _B = IN( n ); } /* IN0 B,(n) */
+OP(ed,01) { unsigned n = ARG(); OUT( n, _B ); } /* OUT0 (n),B */
+OP(ed,02) { illegal_2(); } /* DB ED */
+OP(ed,03) { illegal_2(); } /* DB ED */
+OP(ed,04) { TST( _B ); } /* TST B */
+OP(ed,05) { illegal_2(); } /* DB ED */
+OP(ed,06) { illegal_2(); } /* DB ED */
+OP(ed,07) { illegal_2(); } /* DB ED */
+
+OP(ed,08) { unsigned n = ARG(); _C = IN( n ); } /* IN0 C,(n) */
+OP(ed,09) { unsigned n = ARG(); OUT( n, _C ); } /* OUT0 (n),C */
+OP(ed,0a) { illegal_2(); } /* DB ED */
+OP(ed,0b) { illegal_2(); } /* DB ED */
+OP(ed,0c) { TST( _C ); } /* TST C */
+OP(ed,0d) { illegal_2(); } /* DB ED */
+OP(ed,0e) { illegal_2(); } /* DB ED */
+OP(ed,0f) { illegal_2(); } /* DB ED */
+
+OP(ed,10) { unsigned n = ARG(); _D = IN( n ); } /* IN0 D,(n) */
+OP(ed,11) { unsigned n = ARG(); OUT( n, _D ); } /* OUT0 (n),D */
+OP(ed,12) { illegal_2(); } /* DB ED */
+OP(ed,13) { illegal_2(); } /* DB ED */
+OP(ed,14) { TST( _D ); } /* TST D */
+OP(ed,15) { illegal_2(); } /* DB ED */
+OP(ed,16) { illegal_2(); } /* DB ED */
+OP(ed,17) { illegal_2(); } /* DB ED */
+
+OP(ed,18) { unsigned n = ARG(); _E = IN( n ); } /* IN0 E,(n) */
+OP(ed,19) { unsigned n = ARG(); OUT( n, _E ); } /* OUT0 (n),E */
+OP(ed,1a) { illegal_2(); } /* DB ED */
+OP(ed,1b) { illegal_2(); } /* DB ED */
+OP(ed,1c) { TST( _E ); } /* TST E */
+OP(ed,1d) { illegal_2(); } /* DB ED */
+OP(ed,1e) { illegal_2(); } /* DB ED */
+OP(ed,1f) { illegal_2(); } /* DB ED */
+
+OP(ed,20) { unsigned n = ARG(); _H = IN( n ); } /* IN0 H,(n) */
+OP(ed,21) { unsigned n = ARG(); OUT( n, _H ); } /* OUT0 (n),H */
+OP(ed,22) { illegal_2(); } /* DB ED */
+OP(ed,23) { illegal_2(); } /* DB ED */
+OP(ed,24) { TST( _H ); } /* TST H */
+OP(ed,25) { illegal_2(); } /* DB ED */
+OP(ed,26) { illegal_2(); } /* DB ED */
+OP(ed,27) { illegal_2(); } /* DB ED */
+
+OP(ed,28) { unsigned n = ARG(); _L = IN( n ); } /* IN0 L,(n) */
+OP(ed,29) { unsigned n = ARG(); OUT( n, _L ); } /* OUT0 (n),L */
+OP(ed,2a) { illegal_2(); } /* DB ED */
+OP(ed,2b) { illegal_2(); } /* DB ED */
+OP(ed,2c) { TST( _L ); } /* TST L */
+OP(ed,2d) { illegal_2(); } /* DB ED */
+OP(ed,2e) { illegal_2(); } /* DB ED */
+OP(ed,2f) { illegal_2(); } /* DB ED */
+
+OP(ed,30) { unsigned n = ARG(); IN( n ); } /* IN0 (n) */
+OP(ed,31) { unsigned n = ARG(); OUT( n, 0 ); } /* OUT0 (n) */
+OP(ed,32) { illegal_2(); } /* DB ED */
+OP(ed,33) { illegal_2(); } /* DB ED */
+OP(ed,34) { TST( RM(_HL) ); } /* TST (HL) */
+OP(ed,35) { illegal_2(); } /* DB ED */
+OP(ed,36) { illegal_2(); } /* DB ED */
+OP(ed,37) { illegal_2(); } /* DB ED */
+
+OP(ed,38) { unsigned n = ARG(); _A = IN( n ); } /* IN0 A,(n) */
+OP(ed,39) { unsigned n = ARG(); OUT( n, _A ); } /* OUT0 (n),A */
+OP(ed,3a) { illegal_2(); } /* DB ED */
+OP(ed,3b) { illegal_2(); } /* DB ED */
+OP(ed,3c) { TST( _A ); } /* TST A */
+OP(ed,3d) { illegal_2(); } /* DB ED */
+OP(ed,3e) { illegal_2(); } /* DB ED */
+OP(ed,3f) { illegal_2(); } /* DB ED */
+
+OP(ed,40) { _B = IN(_BC); _F = (_F & CF) | SZP[_B]; } /* IN B,(C) */
+OP(ed,41) { OUT(_BC,_B); } /* OUT (C),B */
+OP(ed,42) { SBC16( BC ); } /* SBC HL,BC */
+OP(ed,43) { EA = ARG16(); WM16( EA, &Z180.BC ); } /* LD (w),BC */
+OP(ed,44) { NEG; } /* NEG */
+OP(ed,45) { RETN; } /* RETN; */
+OP(ed,46) { _IM = 0; } /* IM 0 */
+OP(ed,47) { LD_I_A; } /* LD I,A */
+
+OP(ed,48) { _C = IN(_BC); _F = (_F & CF) | SZP[_C]; } /* IN C,(C) */
+OP(ed,49) { OUT(_BC,_C); } /* OUT (C),C */
+OP(ed,4a) { ADC16( BC ); } /* ADC HL,BC */
+OP(ed,4b) { EA = ARG16(); RM16( EA, &Z180.BC ); } /* LD BC,(w) */
+OP(ed,4c) { MLT( BC ); } /* MLT BC */
+OP(ed,4d) { RETI; } /* RETI */
+OP(ed,4e) { _IM = 0; } /* IM 0 */
+OP(ed,4f) { LD_R_A; } /* LD R,A */
+
+OP(ed,50) { _D = IN(_BC); _F = (_F & CF) | SZP[_D]; } /* IN D,(C) */
+OP(ed,51) { OUT(_BC,_D); } /* OUT (C),D */
+OP(ed,52) { SBC16( DE ); } /* SBC HL,DE */
+OP(ed,53) { EA = ARG16(); WM16( EA, &Z180.DE ); } /* LD (w),DE */
+OP(ed,54) { NEG; } /* NEG */
+OP(ed,55) { RETN; } /* RETN; */
+OP(ed,56) { _IM = 1; } /* IM 1 */
+OP(ed,57) { LD_A_I; } /* LD A,I */
+
+OP(ed,58) { _E = IN(_BC); _F = (_F & CF) | SZP[_E]; } /* IN E,(C) */
+OP(ed,59) { OUT(_BC,_E); } /* OUT (C),E */
+OP(ed,5a) { ADC16( DE ); } /* ADC HL,DE */
+OP(ed,5b) { EA = ARG16(); RM16( EA, &Z180.DE ); } /* LD DE,(w) */
+OP(ed,5c) { MLT( DE ); } /* MLT DE */
+OP(ed,5d) { RETI; } /* RETI */
+OP(ed,5e) { _IM = 2; } /* IM 2 */
+OP(ed,5f) { LD_A_R; } /* LD A,R */
+
+OP(ed,60) { _H = IN(_BC); _F = (_F & CF) | SZP[_H]; } /* IN H,(C) */
+OP(ed,61) { OUT(_BC,_H); } /* OUT (C),H */
+OP(ed,62) { SBC16( HL ); } /* SBC HL,HL */
+OP(ed,63) { EA = ARG16(); WM16( EA, &Z180.HL ); } /* LD (w),HL */
+OP(ed,64) { unsigned m = ARG(); TST( m ); } /* TST m */
+OP(ed,65) { RETN; } /* RETN; */
+OP(ed,66) { _IM = 0; } /* IM 0 */
+OP(ed,67) { RRD; } /* RRD (HL) */
+
+OP(ed,68) { _L = IN(_BC); _F = (_F & CF) | SZP[_L]; } /* IN L,(C) */
+OP(ed,69) { OUT(_BC,_L); } /* OUT (C),L */
+OP(ed,6a) { ADC16( HL ); } /* ADC HL,HL */
+OP(ed,6b) { EA = ARG16(); RM16( EA, &Z180.HL ); } /* LD HL,(w) */
+OP(ed,6c) { MLT( HL ); } /* MLT HL */
+OP(ed,6d) { RETI; } /* RETI */
+OP(ed,6e) { _IM = 0; } /* IM 0 */
+OP(ed,6f) { RLD; } /* RLD (HL) */
+
+OP(ed,70) { UINT8 res = IN(_BC); _F = (_F & CF) | SZP[res]; } /* IN 0,(C) */
+OP(ed,71) { OUT(_BC,0); } /* OUT (C),0 */
+OP(ed,72) { SBC16( SP ); } /* SBC HL,SP */
+OP(ed,73) { EA = ARG16(); WM16( EA, &Z180.SP ); } /* LD (w),SP */
+OP(ed,74) { unsigned m = ARG(); _F = (_F & CF) | SZP[IN(_C) & m]; } /* TSTIO m */
+OP(ed,75) { RETN; } /* RETN; */
+OP(ed,76) { SLP; } /* SLP */
+OP(ed,77) { illegal_2(); } /* DB ED,77 */
+
+OP(ed,78) { _A = IN(_BC); _F = (_F & CF) | SZP[_A]; } /* IN E,(C) */
+OP(ed,79) { OUT(_BC,_A); } /* OUT (C),E */
+OP(ed,7a) { ADC16( SP ); } /* ADC HL,SP */
+OP(ed,7b) { EA = ARG16(); RM16( EA, &Z180.SP ); } /* LD SP,(w) */
+OP(ed,7c) { MLT( SP ); } /* MLT SP */
+OP(ed,7d) { RETI; } /* RETI */
+OP(ed,7e) { _IM = 2; } /* IM 2 */
+OP(ed,7f) { illegal_2(); } /* DB ED,7F */
+
+OP(ed,80) { illegal_2(); } /* DB ED */
+OP(ed,81) { illegal_2(); } /* DB ED */
+OP(ed,82) { illegal_2(); } /* DB ED */
+OP(ed,83) { OTIM; } /* OTIM */
+OP(ed,84) { illegal_2(); } /* DB ED */
+OP(ed,85) { illegal_2(); } /* DB ED */
+OP(ed,86) { illegal_2(); } /* DB ED */
+OP(ed,87) { illegal_2(); } /* DB ED */
+
+OP(ed,88) { illegal_2(); } /* DB ED */
+OP(ed,89) { illegal_2(); } /* DB ED */
+OP(ed,8a) { illegal_2(); } /* DB ED */
+OP(ed,8b) { OTDM; } /* OTDM */
+OP(ed,8c) { illegal_2(); } /* DB ED */
+OP(ed,8d) { illegal_2(); } /* DB ED */
+OP(ed,8e) { illegal_2(); } /* DB ED */
+OP(ed,8f) { illegal_2(); } /* DB ED */
+
+OP(ed,90) { illegal_2(); } /* DB ED */
+OP(ed,91) { illegal_2(); } /* DB ED */
+OP(ed,92) { illegal_2(); } /* DB ED */
+OP(ed,93) { OTIMR; } /* OTIMR */
+OP(ed,94) { illegal_2(); } /* DB ED */
+OP(ed,95) { illegal_2(); } /* DB ED */
+OP(ed,96) { illegal_2(); } /* DB ED */
+OP(ed,97) { illegal_2(); } /* DB ED */
+
+OP(ed,98) { illegal_2(); } /* DB ED */
+OP(ed,99) { illegal_2(); } /* DB ED */
+OP(ed,9a) { illegal_2(); } /* DB ED */
+OP(ed,9b) { OTDMR; } /* OTDMR */
+OP(ed,9c) { illegal_2(); } /* DB ED */
+OP(ed,9d) { illegal_2(); } /* DB ED */
+OP(ed,9e) { illegal_2(); } /* DB ED */
+OP(ed,9f) { illegal_2(); } /* DB ED */
+
+OP(ed,a0) { LDI; } /* LDI */
+OP(ed,a1) { CPI; } /* CPI */
+OP(ed,a2) { INI; } /* INI */
+OP(ed,a3) { OUTI; } /* OUTI */
+OP(ed,a4) { illegal_2(); } /* DB ED */
+OP(ed,a5) { illegal_2(); } /* DB ED */
+OP(ed,a6) { illegal_2(); } /* DB ED */
+OP(ed,a7) { illegal_2(); } /* DB ED */
+
+OP(ed,a8) { LDD; } /* LDD */
+OP(ed,a9) { CPD; } /* CPD */
+OP(ed,aa) { IND; } /* IND */
+OP(ed,ab) { OUTD; } /* OUTD */
+OP(ed,ac) { illegal_2(); } /* DB ED */
+OP(ed,ad) { illegal_2(); } /* DB ED */
+OP(ed,ae) { illegal_2(); } /* DB ED */
+OP(ed,af) { illegal_2(); } /* DB ED */
+
+OP(ed,b0) { LDIR; } /* LDIR */
+OP(ed,b1) { CPIR; } /* CPIR */
+OP(ed,b2) { INIR; } /* INIR */
+OP(ed,b3) { OTIR; } /* OTIR */
+OP(ed,b4) { illegal_2(); } /* DB ED */
+OP(ed,b5) { illegal_2(); } /* DB ED */
+OP(ed,b6) { illegal_2(); } /* DB ED */
+OP(ed,b7) { illegal_2(); } /* DB ED */
+
+OP(ed,b8) { LDDR; } /* LDDR */
+OP(ed,b9) { CPDR; } /* CPDR */
+OP(ed,ba) { INDR; } /* INDR */
+OP(ed,bb) { OTDR; } /* OTDR */
+OP(ed,bc) { illegal_2(); } /* DB ED */
+OP(ed,bd) { illegal_2(); } /* DB ED */
+OP(ed,be) { illegal_2(); } /* DB ED */
+OP(ed,bf) { illegal_2(); } /* DB ED */
+
+OP(ed,c0) { illegal_2(); } /* DB ED */
+OP(ed,c1) { illegal_2(); } /* DB ED */
+OP(ed,c2) { illegal_2(); } /* DB ED */
+OP(ed,c3) { illegal_2(); } /* DB ED */
+OP(ed,c4) { illegal_2(); } /* DB ED */
+OP(ed,c5) { illegal_2(); } /* DB ED */
+OP(ed,c6) { illegal_2(); } /* DB ED */
+OP(ed,c7) { illegal_2(); } /* DB ED */
+
+OP(ed,c8) { illegal_2(); } /* DB ED */
+OP(ed,c9) { illegal_2(); } /* DB ED */
+OP(ed,ca) { illegal_2(); } /* DB ED */
+OP(ed,cb) { illegal_2(); } /* DB ED */
+OP(ed,cc) { illegal_2(); } /* DB ED */
+OP(ed,cd) { illegal_2(); } /* DB ED */
+OP(ed,ce) { illegal_2(); } /* DB ED */
+OP(ed,cf) { illegal_2(); } /* DB ED */
+
+OP(ed,d0) { illegal_2(); } /* DB ED */
+OP(ed,d1) { illegal_2(); } /* DB ED */
+OP(ed,d2) { illegal_2(); } /* DB ED */
+OP(ed,d3) { illegal_2(); } /* DB ED */
+OP(ed,d4) { illegal_2(); } /* DB ED */
+OP(ed,d5) { illegal_2(); } /* DB ED */
+OP(ed,d6) { illegal_2(); } /* DB ED */
+OP(ed,d7) { illegal_2(); } /* DB ED */
+
+OP(ed,d8) { illegal_2(); } /* DB ED */
+OP(ed,d9) { illegal_2(); } /* DB ED */
+OP(ed,da) { illegal_2(); } /* DB ED */
+OP(ed,db) { illegal_2(); } /* DB ED */
+OP(ed,dc) { illegal_2(); } /* DB ED */
+OP(ed,dd) { illegal_2(); } /* DB ED */
+OP(ed,de) { illegal_2(); } /* DB ED */
+OP(ed,df) { illegal_2(); } /* DB ED */
+
+OP(ed,e0) { illegal_2(); } /* DB ED */
+OP(ed,e1) { illegal_2(); } /* DB ED */
+OP(ed,e2) { illegal_2(); } /* DB ED */
+OP(ed,e3) { illegal_2(); } /* DB ED */
+OP(ed,e4) { illegal_2(); } /* DB ED */
+OP(ed,e5) { illegal_2(); } /* DB ED */
+OP(ed,e6) { illegal_2(); } /* DB ED */
+OP(ed,e7) { illegal_2(); } /* DB ED */
+
+OP(ed,e8) { illegal_2(); } /* DB ED */
+OP(ed,e9) { illegal_2(); } /* DB ED */
+OP(ed,ea) { illegal_2(); } /* DB ED */
+OP(ed,eb) { illegal_2(); } /* DB ED */
+OP(ed,ec) { illegal_2(); } /* DB ED */
+OP(ed,ed) { illegal_2(); } /* DB ED */
+OP(ed,ee) { illegal_2(); } /* DB ED */
+OP(ed,ef) { illegal_2(); } /* DB ED */
+
+OP(ed,f0) { illegal_2(); } /* DB ED */
+OP(ed,f1) { illegal_2(); } /* DB ED */
+OP(ed,f2) { illegal_2(); } /* DB ED */
+OP(ed,f3) { illegal_2(); } /* DB ED */
+OP(ed,f4) { illegal_2(); } /* DB ED */
+OP(ed,f5) { illegal_2(); } /* DB ED */
+OP(ed,f6) { illegal_2(); } /* DB ED */
+OP(ed,f7) { illegal_2(); } /* DB ED */
+
+OP(ed,f8) { illegal_2(); } /* DB ED */
+OP(ed,f9) { illegal_2(); } /* DB ED */
+OP(ed,fa) { illegal_2(); } /* DB ED */
+OP(ed,fb) { illegal_2(); } /* DB ED */
+OP(ed,fc) { illegal_2(); } /* DB ED */
+OP(ed,fd) { illegal_2(); } /* DB ED */
+OP(ed,fe) { illegal_2(); } /* DB ED */
+OP(ed,ff) { illegal_2(); } /* DB ED */
+
diff --git a/src/emu/cpu/z180/z180fd.c b/src/emu/cpu/z180/z180fd.c
new file mode 100644
index 00000000000..44af305f42e
--- /dev/null
+++ b/src/emu/cpu/z180/z180fd.c
@@ -0,0 +1,291 @@
+/**********************************************************
+ * IY register related opcodes (FD prefix)
+ **********************************************************/
+OP(fd,00) { illegal_1(); op_00(); } /* DB FD */
+OP(fd,01) { illegal_1(); op_01(); } /* DB FD */
+OP(fd,02) { illegal_1(); op_02(); } /* DB FD */
+OP(fd,03) { illegal_1(); op_03(); } /* DB FD */
+OP(fd,04) { illegal_1(); op_04(); } /* DB FD */
+OP(fd,05) { illegal_1(); op_05(); } /* DB FD */
+OP(fd,06) { illegal_1(); op_06(); } /* DB FD */
+OP(fd,07) { illegal_1(); op_07(); } /* DB FD */
+
+OP(fd,08) { illegal_1(); op_08(); } /* DB FD */
+OP(fd,09) { _R++; ADD16(IY,BC); } /* ADD IY,BC */
+OP(fd,0a) { illegal_1(); op_0a(); } /* DB FD */
+OP(fd,0b) { illegal_1(); op_0b(); } /* DB FD */
+OP(fd,0c) { illegal_1(); op_0c(); } /* DB FD */
+OP(fd,0d) { illegal_1(); op_0d(); } /* DB FD */
+OP(fd,0e) { illegal_1(); op_0e(); } /* DB FD */
+OP(fd,0f) { illegal_1(); op_0f(); } /* DB FD */
+
+OP(fd,10) { illegal_1(); op_10(); } /* DB FD */
+OP(fd,11) { illegal_1(); op_11(); } /* DB FD */
+OP(fd,12) { illegal_1(); op_12(); } /* DB FD */
+OP(fd,13) { illegal_1(); op_13(); } /* DB FD */
+OP(fd,14) { illegal_1(); op_14(); } /* DB FD */
+OP(fd,15) { illegal_1(); op_15(); } /* DB FD */
+OP(fd,16) { illegal_1(); op_16(); } /* DB FD */
+OP(fd,17) { illegal_1(); op_17(); } /* DB FD */
+
+OP(fd,18) { illegal_1(); op_18(); } /* DB FD */
+OP(fd,19) { _R++; ADD16(IY,DE); } /* ADD IY,DE */
+OP(fd,1a) { illegal_1(); op_1a(); } /* DB FD */
+OP(fd,1b) { illegal_1(); op_1b(); } /* DB FD */
+OP(fd,1c) { illegal_1(); op_1c(); } /* DB FD */
+OP(fd,1d) { illegal_1(); op_1d(); } /* DB FD */
+OP(fd,1e) { illegal_1(); op_1e(); } /* DB FD */
+OP(fd,1f) { illegal_1(); op_1f(); } /* DB FD */
+
+OP(fd,20) { illegal_1(); op_20(); } /* DB FD */
+OP(fd,21) { _R++; _IY = ARG16(); } /* LD IY,w */
+OP(fd,22) { _R++; EA = ARG16(); WM16( EA, &Z180.IY ); } /* LD (w),IY */
+OP(fd,23) { _R++; _IY++; } /* INC IY */
+OP(fd,24) { _R++; _HY = INC(_HY); } /* INC HY */
+OP(fd,25) { _R++; _HY = DEC(_HY); } /* DEC HY */
+OP(fd,26) { _R++; _HY = ARG(); } /* LD HY,n */
+OP(fd,27) { illegal_1(); op_27(); } /* DB FD */
+
+OP(fd,28) { illegal_1(); op_28(); } /* DB FD */
+OP(fd,29) { _R++; ADD16(IY,IY); } /* ADD IY,IY */
+OP(fd,2a) { _R++; EA = ARG16(); RM16( EA, &Z180.IY ); } /* LD IY,(w) */
+OP(fd,2b) { _R++; _IY--; } /* DEC IY */
+OP(fd,2c) { _R++; _LY = INC(_LY); } /* INC LY */
+OP(fd,2d) { _R++; _LY = DEC(_LY); } /* DEC LY */
+OP(fd,2e) { _R++; _LY = ARG(); } /* LD LY,n */
+OP(fd,2f) { illegal_1(); op_2f(); } /* DB FD */
+
+OP(fd,30) { illegal_1(); op_30(); } /* DB FD */
+OP(fd,31) { illegal_1(); op_31(); } /* DB FD */
+OP(fd,32) { illegal_1(); op_32(); } /* DB FD */
+OP(fd,33) { illegal_1(); op_33(); } /* DB FD */
+OP(fd,34) { _R++; EAY; WM( EA, INC(RM(EA)) ); } /* INC (IY+o) */
+OP(fd,35) { _R++; EAY; WM( EA, DEC(RM(EA)) ); } /* DEC (IY+o) */
+OP(fd,36) { _R++; EAY; WM( EA, ARG() ); } /* LD (IY+o),n */
+OP(fd,37) { illegal_1(); op_37(); } /* DB FD */
+
+OP(fd,38) { illegal_1(); op_38(); } /* DB FD */
+OP(fd,39) { _R++; ADD16(IY,SP); } /* ADD IY,SP */
+OP(fd,3a) { illegal_1(); op_3a(); } /* DB FD */
+OP(fd,3b) { illegal_1(); op_3b(); } /* DB FD */
+OP(fd,3c) { illegal_1(); op_3c(); } /* DB FD */
+OP(fd,3d) { illegal_1(); op_3d(); } /* DB FD */
+OP(fd,3e) { illegal_1(); op_3e(); } /* DB FD */
+OP(fd,3f) { illegal_1(); op_3f(); } /* DB FD */
+
+OP(fd,40) { illegal_1(); op_40(); } /* DB FD */
+OP(fd,41) { illegal_1(); op_41(); } /* DB FD */
+OP(fd,42) { illegal_1(); op_42(); } /* DB FD */
+OP(fd,43) { illegal_1(); op_43(); } /* DB FD */
+OP(fd,44) { _R++; _B = _HY; } /* LD B,HY */
+OP(fd,45) { _R++; _B = _LY; } /* LD B,LY */
+OP(fd,46) { _R++; EAY; _B = RM(EA); } /* LD B,(IY+o) */
+OP(fd,47) { illegal_1(); op_47(); } /* DB FD */
+
+OP(fd,48) { illegal_1(); op_48(); } /* DB FD */
+OP(fd,49) { illegal_1(); op_49(); } /* DB FD */
+OP(fd,4a) { illegal_1(); op_4a(); } /* DB FD */
+OP(fd,4b) { illegal_1(); op_4b(); } /* DB FD */
+OP(fd,4c) { _R++; _C = _HY; } /* LD C,HY */
+OP(fd,4d) { _R++; _C = _LY; } /* LD C,LY */
+OP(fd,4e) { _R++; EAY; _C = RM(EA); } /* LD C,(IY+o) */
+OP(fd,4f) { illegal_1(); op_4f(); } /* DB FD */
+
+OP(fd,50) { illegal_1(); op_50(); } /* DB FD */
+OP(fd,51) { illegal_1(); op_51(); } /* DB FD */
+OP(fd,52) { illegal_1(); op_52(); } /* DB FD */
+OP(fd,53) { illegal_1(); op_53(); } /* DB FD */
+OP(fd,54) { _R++; _D = _HY; } /* LD D,HY */
+OP(fd,55) { _R++; _D = _LY; } /* LD D,LY */
+OP(fd,56) { _R++; EAY; _D = RM(EA); } /* LD D,(IY+o) */
+OP(fd,57) { illegal_1(); op_57(); } /* DB FD */
+
+OP(fd,58) { illegal_1(); op_58(); } /* DB FD */
+OP(fd,59) { illegal_1(); op_59(); } /* DB FD */
+OP(fd,5a) { illegal_1(); op_5a(); } /* DB FD */
+OP(fd,5b) { illegal_1(); op_5b(); } /* DB FD */
+OP(fd,5c) { _R++; _E = _HY; } /* LD E,HY */
+OP(fd,5d) { _R++; _E = _LY; } /* LD E,LY */
+OP(fd,5e) { _R++; EAY; _E = RM(EA); } /* LD E,(IY+o) */
+OP(fd,5f) { illegal_1(); op_5f(); } /* DB FD */
+
+OP(fd,60) { _R++; _HY = _B; } /* LD HY,B */
+OP(fd,61) { _R++; _HY = _C; } /* LD HY,C */
+OP(fd,62) { _R++; _HY = _D; } /* LD HY,D */
+OP(fd,63) { _R++; _HY = _E; } /* LD HY,E */
+OP(fd,64) { _R++; } /* LD HY,HY */
+OP(fd,65) { _R++; _HY = _LY; } /* LD HY,LY */
+OP(fd,66) { _R++; EAY; _H = RM(EA); } /* LD H,(IY+o) */
+OP(fd,67) { _R++; _HY = _A; } /* LD HY,A */
+
+OP(fd,68) { _R++; _LY = _B; } /* LD LY,B */
+OP(fd,69) { _R++; _LY = _C; } /* LD LY,C */
+OP(fd,6a) { _R++; _LY = _D; } /* LD LY,D */
+OP(fd,6b) { _R++; _LY = _E; } /* LD LY,E */
+OP(fd,6c) { _R++; _LY = _HY; } /* LD LY,HY */
+OP(fd,6d) { _R++; } /* LD LY,LY */
+OP(fd,6e) { _R++; EAY; _L = RM(EA); } /* LD L,(IY+o) */
+OP(fd,6f) { _R++; _LY = _A; } /* LD LY,A */
+
+OP(fd,70) { _R++; EAY; WM( EA, _B ); } /* LD (IY+o),B */
+OP(fd,71) { _R++; EAY; WM( EA, _C ); } /* LD (IY+o),C */
+OP(fd,72) { _R++; EAY; WM( EA, _D ); } /* LD (IY+o),D */
+OP(fd,73) { _R++; EAY; WM( EA, _E ); } /* LD (IY+o),E */
+OP(fd,74) { _R++; EAY; WM( EA, _H ); } /* LD (IY+o),H */
+OP(fd,75) { _R++; EAY; WM( EA, _L ); } /* LD (IY+o),L */
+OP(fd,76) { illegal_1(); op_76(); } /* DB FD */
+OP(fd,77) { _R++; EAY; WM( EA, _A ); } /* LD (IY+o),A */
+
+OP(fd,78) { illegal_1(); op_78(); } /* DB FD */
+OP(fd,79) { illegal_1(); op_79(); } /* DB FD */
+OP(fd,7a) { illegal_1(); op_7a(); } /* DB FD */
+OP(fd,7b) { illegal_1(); op_7b(); } /* DB FD */
+OP(fd,7c) { _R++; _A = _HY; } /* LD A,HY */
+OP(fd,7d) { _R++; _A = _LY; } /* LD A,LY */
+OP(fd,7e) { _R++; EAY; _A = RM(EA); } /* LD A,(IY+o) */
+OP(fd,7f) { illegal_1(); op_7f(); } /* DB FD */
+
+OP(fd,80) { illegal_1(); op_80(); } /* DB FD */
+OP(fd,81) { illegal_1(); op_81(); } /* DB FD */
+OP(fd,82) { illegal_1(); op_82(); } /* DB FD */
+OP(fd,83) { illegal_1(); op_83(); } /* DB FD */
+OP(fd,84) { _R++; ADD(_HY); } /* ADD A,HY */
+OP(fd,85) { _R++; ADD(_LY); } /* ADD A,LY */
+OP(fd,86) { _R++; EAY; ADD(RM(EA)); } /* ADD A,(IY+o) */
+OP(fd,87) { illegal_1(); op_87(); } /* DB FD */
+
+OP(fd,88) { illegal_1(); op_88(); } /* DB FD */
+OP(fd,89) { illegal_1(); op_89(); } /* DB FD */
+OP(fd,8a) { illegal_1(); op_8a(); } /* DB FD */
+OP(fd,8b) { illegal_1(); op_8b(); } /* DB FD */
+OP(fd,8c) { _R++; ADC(_HY); } /* ADC A,HY */
+OP(fd,8d) { _R++; ADC(_LY); } /* ADC A,LY */
+OP(fd,8e) { _R++; EAY; ADC(RM(EA)); } /* ADC A,(IY+o) */
+OP(fd,8f) { illegal_1(); op_8f(); } /* DB FD */
+
+OP(fd,90) { illegal_1(); op_90(); } /* DB FD */
+OP(fd,91) { illegal_1(); op_91(); } /* DB FD */
+OP(fd,92) { illegal_1(); op_92(); } /* DB FD */
+OP(fd,93) { illegal_1(); op_93(); } /* DB FD */
+OP(fd,94) { _R++; SUB(_HY); } /* SUB HY */
+OP(fd,95) { _R++; SUB(_LY); } /* SUB LY */
+OP(fd,96) { _R++; EAY; SUB(RM(EA)); } /* SUB (IY+o) */
+OP(fd,97) { illegal_1(); op_97(); } /* DB FD */
+
+OP(fd,98) { illegal_1(); op_98(); } /* DB FD */
+OP(fd,99) { illegal_1(); op_99(); } /* DB FD */
+OP(fd,9a) { illegal_1(); op_9a(); } /* DB FD */
+OP(fd,9b) { illegal_1(); op_9b(); } /* DB FD */
+OP(fd,9c) { _R++; SBC(_HY); } /* SBC A,HY */
+OP(fd,9d) { _R++; SBC(_LY); } /* SBC A,LY */
+OP(fd,9e) { _R++; EAY; SBC(RM(EA)); } /* SBC A,(IY+o) */
+OP(fd,9f) { illegal_1(); op_9f(); } /* DB FD */
+
+OP(fd,a0) { illegal_1(); op_a0(); } /* DB FD */
+OP(fd,a1) { illegal_1(); op_a1(); } /* DB FD */
+OP(fd,a2) { illegal_1(); op_a2(); } /* DB FD */
+OP(fd,a3) { illegal_1(); op_a3(); } /* DB FD */
+OP(fd,a4) { _R++; AND(_HY); } /* AND HY */
+OP(fd,a5) { _R++; AND(_LY); } /* AND LY */
+OP(fd,a6) { _R++; EAY; AND(RM(EA)); } /* AND (IY+o) */
+OP(fd,a7) { illegal_1(); op_a7(); } /* DB FD */
+
+OP(fd,a8) { illegal_1(); op_a8(); } /* DB FD */
+OP(fd,a9) { illegal_1(); op_a9(); } /* DB FD */
+OP(fd,aa) { illegal_1(); op_aa(); } /* DB FD */
+OP(fd,ab) { illegal_1(); op_ab(); } /* DB FD */
+OP(fd,ac) { _R++; XOR(_HY); } /* XOR HY */
+OP(fd,ad) { _R++; XOR(_LY); } /* XOR LY */
+OP(fd,ae) { _R++; EAY; XOR(RM(EA)); } /* XOR (IY+o) */
+OP(fd,af) { illegal_1(); op_af(); } /* DB FD */
+
+OP(fd,b0) { illegal_1(); op_b0(); } /* DB FD */
+OP(fd,b1) { illegal_1(); op_b1(); } /* DB FD */
+OP(fd,b2) { illegal_1(); op_b2(); } /* DB FD */
+OP(fd,b3) { illegal_1(); op_b3(); } /* DB FD */
+OP(fd,b4) { _R++; OR(_HY); } /* OR HY */
+OP(fd,b5) { _R++; OR(_LY); } /* OR LY */
+OP(fd,b6) { _R++; EAY; OR(RM(EA)); } /* OR (IY+o) */
+OP(fd,b7) { illegal_1(); op_b7(); } /* DB FD */
+
+OP(fd,b8) { illegal_1(); op_b8(); } /* DB FD */
+OP(fd,b9) { illegal_1(); op_b9(); } /* DB FD */
+OP(fd,ba) { illegal_1(); op_ba(); } /* DB FD */
+OP(fd,bb) { illegal_1(); op_bb(); } /* DB FD */
+OP(fd,bc) { _R++; CP(_HY); } /* CP HY */
+OP(fd,bd) { _R++; CP(_LY); } /* CP LY */
+OP(fd,be) { _R++; EAY; CP(RM(EA)); } /* CP (IY+o) */
+OP(fd,bf) { illegal_1(); op_bf(); } /* DB FD */
+
+OP(fd,c0) { illegal_1(); op_c0(); } /* DB FD */
+OP(fd,c1) { illegal_1(); op_c1(); } /* DB FD */
+OP(fd,c2) { illegal_1(); op_c2(); } /* DB FD */
+OP(fd,c3) { illegal_1(); op_c3(); } /* DB FD */
+OP(fd,c4) { illegal_1(); op_c4(); } /* DB FD */
+OP(fd,c5) { illegal_1(); op_c5(); } /* DB FD */
+OP(fd,c6) { illegal_1(); op_c6(); } /* DB FD */
+OP(fd,c7) { illegal_1(); op_c7(); } /* DB FD */
+
+OP(fd,c8) { illegal_1(); op_c8(); } /* DB FD */
+OP(fd,c9) { illegal_1(); op_c9(); } /* DB FD */
+OP(fd,ca) { illegal_1(); op_ca(); } /* DB FD */
+OP(fd,cb) { _R++; EAY; EXEC(xycb,ARG()); } /* ** FD CB xx */
+OP(fd,cc) { illegal_1(); op_cc(); } /* DB FD */
+OP(fd,cd) { illegal_1(); op_cd(); } /* DB FD */
+OP(fd,ce) { illegal_1(); op_ce(); } /* DB FD */
+OP(fd,cf) { illegal_1(); op_cf(); } /* DB FD */
+
+OP(fd,d0) { illegal_1(); op_d0(); } /* DB FD */
+OP(fd,d1) { illegal_1(); op_d1(); } /* DB FD */
+OP(fd,d2) { illegal_1(); op_d2(); } /* DB FD */
+OP(fd,d3) { illegal_1(); op_d3(); } /* DB FD */
+OP(fd,d4) { illegal_1(); op_d4(); } /* DB FD */
+OP(fd,d5) { illegal_1(); op_d5(); } /* DB FD */
+OP(fd,d6) { illegal_1(); op_d6(); } /* DB FD */
+OP(fd,d7) { illegal_1(); op_d7(); } /* DB FD */
+
+OP(fd,d8) { illegal_1(); op_d8(); } /* DB FD */
+OP(fd,d9) { illegal_1(); op_d9(); } /* DB FD */
+OP(fd,da) { illegal_1(); op_da(); } /* DB FD */
+OP(fd,db) { illegal_1(); op_db(); } /* DB FD */
+OP(fd,dc) { illegal_1(); op_dc(); } /* DB FD */
+OP(fd,dd) { illegal_1(); op_dd(); } /* DB FD */
+OP(fd,de) { illegal_1(); op_de(); } /* DB FD */
+OP(fd,df) { illegal_1(); op_df(); } /* DB FD */
+
+OP(fd,e0) { illegal_1(); op_e0(); } /* DB FD */
+OP(fd,e1) { _R++; POP(IY); } /* POP IY */
+OP(fd,e2) { illegal_1(); op_e2(); } /* DB FD */
+OP(fd,e3) { _R++; EXSP(IY); } /* EX (SP),IY */
+OP(fd,e4) { illegal_1(); op_e4(); } /* DB FD */
+OP(fd,e5) { _R++; PUSH( IY ); } /* PUSH IY */
+OP(fd,e6) { illegal_1(); op_e6(); } /* DB FD */
+OP(fd,e7) { illegal_1(); op_e7(); } /* DB FD */
+
+OP(fd,e8) { illegal_1(); op_e8(); } /* DB FD */
+OP(fd,e9) { _R++; _PC = _IY; z180_change_pc(_PCD); } /* JP (IY) */
+OP(fd,ea) { illegal_1(); op_ea(); } /* DB FD */
+OP(fd,eb) { illegal_1(); op_eb(); } /* DB FD */
+OP(fd,ec) { illegal_1(); op_ec(); } /* DB FD */
+OP(fd,ed) { illegal_1(); op_ed(); } /* DB FD */
+OP(fd,ee) { illegal_1(); op_ee(); } /* DB FD */
+OP(fd,ef) { illegal_1(); op_ef(); } /* DB FD */
+
+OP(fd,f0) { illegal_1(); op_f0(); } /* DB FD */
+OP(fd,f1) { illegal_1(); op_f1(); } /* DB FD */
+OP(fd,f2) { illegal_1(); op_f2(); } /* DB FD */
+OP(fd,f3) { illegal_1(); op_f3(); } /* DB FD */
+OP(fd,f4) { illegal_1(); op_f4(); } /* DB FD */
+OP(fd,f5) { illegal_1(); op_f5(); } /* DB FD */
+OP(fd,f6) { illegal_1(); op_f6(); } /* DB FD */
+OP(fd,f7) { illegal_1(); op_f7(); } /* DB FD */
+
+OP(fd,f8) { illegal_1(); op_f8(); } /* DB FD */
+OP(fd,f9) { _R++; _SP = _IY; } /* LD SP,IY */
+OP(fd,fa) { illegal_1(); op_fa(); } /* DB FD */
+OP(fd,fb) { illegal_1(); op_fb(); } /* DB FD */
+OP(fd,fc) { illegal_1(); op_fc(); } /* DB FD */
+OP(fd,fd) { illegal_1(); op_fd(); } /* DB FD */
+OP(fd,fe) { illegal_1(); op_fe(); } /* DB FD */
+OP(fd,ff) { illegal_1(); op_ff(); } /* DB FD */
+
diff --git a/src/emu/cpu/z180/z180op.c b/src/emu/cpu/z180/z180op.c
new file mode 100644
index 00000000000..2342ce06656
--- /dev/null
+++ b/src/emu/cpu/z180/z180op.c
@@ -0,0 +1,520 @@
+#if TIME_LOOP_HACKS
+
+#define CHECK_BC_LOOP \
+if( _BC > 1 && _PCD < 0xfffc ) { \
+ UINT8 op1 = cpu_readop(_PCD); \
+ UINT8 op2 = cpu_readop(_PCD+1); \
+ if( (op1==0x78 && op2==0xb1) || (op1==0x79 && op2==0xb0) ) \
+ { \
+ UINT8 op3 = cpu_readop(_PCD+2); \
+ UINT8 op4 = cpu_readop(_PCD+3); \
+ if( op3==0x20 && op4==0xfb ) \
+ { \
+ int cnt = \
+ cc[Z180_TABLE_op][0x78] + \
+ cc[Z180_TABLE_op][0xb1] + \
+ cc[Z180_TABLE_op][0x20] + \
+ cc[Z180_TABLE_ex][0x20]; \
+ while( _BC > 0 && z180_icount > cnt ) \
+ { \
+ BURNODD( cnt, 4, cnt ); \
+ _BC--; \
+ } \
+ } \
+ else \
+ if( op3 == 0xc2 ) \
+ { \
+ UINT8 ad1 = cpu_readop_arg(_PCD+3); \
+ UINT8 ad2 = cpu_readop_arg(_PCD+4); \
+ if( (ad1 + 256 * ad2) == (_PCD - 1) ) \
+ { \
+ int cnt = \
+ cc[Z180_TABLE_op][0x78] + \
+ cc[Z180_TABLE_op][0xb1] + \
+ cc[Z180_TABLE_op][0xc2] + \
+ cc[Z180_TABLE_ex][0xc2]; \
+ while( _BC > 0 && z180_icount > cnt ) \
+ { \
+ BURNODD( cnt, 4, cnt ); \
+ _BC--; \
+ } \
+ } \
+ } \
+ } \
+}
+
+#define CHECK_DE_LOOP \
+if( _DE > 1 && _PCD < 0xfffc ) { \
+ UINT8 op1 = cpu_readop(_PCD); \
+ UINT8 op2 = cpu_readop(_PCD+1); \
+ if( (op1==0x7a && op2==0xb3) || (op1==0x7b && op2==0xb2) ) \
+ { \
+ UINT8 op3 = cpu_readop(_PCD+2); \
+ UINT8 op4 = cpu_readop(_PCD+3); \
+ if( op3==0x20 && op4==0xfb ) \
+ { \
+ int cnt = \
+ cc[Z180_TABLE_op][0x7a] + \
+ cc[Z180_TABLE_op][0xb3] + \
+ cc[Z180_TABLE_op][0x20] + \
+ cc[Z180_TABLE_ex][0x20]; \
+ while( _DE > 0 && z180_icount > cnt ) \
+ { \
+ BURNODD( cnt, 4, cnt ); \
+ _DE--; \
+ } \
+ } \
+ else \
+ if( op3==0xc2 ) \
+ { \
+ UINT8 ad1 = cpu_readop_arg(_PCD+3); \
+ UINT8 ad2 = cpu_readop_arg(_PCD+4); \
+ if( (ad1 + 256 * ad2) == (_PCD - 1) ) \
+ { \
+ int cnt = \
+ cc[Z180_TABLE_op][0x7a] + \
+ cc[Z180_TABLE_op][0xb3] + \
+ cc[Z180_TABLE_op][0xc2] + \
+ cc[Z180_TABLE_ex][0xc2]; \
+ while( _DE > 0 && z180_icount > cnt ) \
+ { \
+ BURNODD( cnt, 4, cnt ); \
+ _DE--; \
+ } \
+ } \
+ } \
+ } \
+}
+
+#define CHECK_HL_LOOP \
+if( _HL > 1 && _PCD < 0xfffc ) { \
+ UINT8 op1 = cpu_readop(_PCD); \
+ UINT8 op2 = cpu_readop(_PCD+1); \
+ if( (op1==0x7c && op2==0xb5) || (op1==0x7d && op2==0xb4) ) \
+ { \
+ UINT8 op3 = cpu_readop(_PCD+2); \
+ UINT8 op4 = cpu_readop(_PCD+3); \
+ if( op3==0x20 && op4==0xfb ) \
+ { \
+ int cnt = \
+ cc[Z180_TABLE_op][0x7c] + \
+ cc[Z180_TABLE_op][0xb5] + \
+ cc[Z180_TABLE_op][0x20] + \
+ cc[Z180_TABLE_ex][0x20]; \
+ while( _HL > 0 && z180_icount > cnt ) \
+ { \
+ BURNODD( cnt, 4, cnt ); \
+ _HL--; \
+ } \
+ } \
+ else \
+ if( op3==0xc2 ) \
+ { \
+ UINT8 ad1 = cpu_readop_arg(_PCD+3); \
+ UINT8 ad2 = cpu_readop_arg(_PCD+4); \
+ if( (ad1 + 256 * ad2) == (_PCD - 1) ) \
+ { \
+ int cnt = \
+ cc[Z180_TABLE_op][0x7c] + \
+ cc[Z180_TABLE_op][0xb5] + \
+ cc[Z180_TABLE_op][0xc2] + \
+ cc[Z180_TABLE_ex][0xc2]; \
+ while( _HL > 0 && z180_icount > cnt ) \
+ { \
+ BURNODD( cnt, 4, cnt ); \
+ _HL--; \
+ } \
+ } \
+ } \
+ } \
+}
+
+#else
+
+#define CHECK_BC_LOOP
+#define CHECK_DE_LOOP
+#define CHECK_HL_LOOP
+
+#endif
+
+/**********************************************************
+ * main opcodes
+ **********************************************************/
+OP(op,00) { } /* NOP */
+OP(op,01) { _BC = ARG16(); } /* LD BC,w */
+OP(op,02) { WM( _BC, _A ); } /* LD (BC),A */
+OP(op,03) { _BC++; } /* INC BC */
+OP(op,04) { _B = INC(_B); } /* INC B */
+OP(op,05) { _B = DEC(_B); } /* DEC B */
+OP(op,06) { _B = ARG(); } /* LD B,n */
+OP(op,07) { RLCA; } /* RLCA */
+
+OP(op,08) { EX_AF; } /* EX AF,AF' */
+OP(op,09) { ADD16(HL,BC); } /* ADD HL,BC */
+OP(op,0a) { _A = RM(_BC); } /* LD A,(BC) */
+OP(op,0b) { _BC--; CHECK_BC_LOOP; } /* DEC BC */
+OP(op,0c) { _C = INC(_C); } /* INC C */
+OP(op,0d) { _C = DEC(_C); } /* DEC C */
+OP(op,0e) { _C = ARG(); } /* LD C,n */
+OP(op,0f) { RRCA; } /* RRCA */
+
+OP(op,10) { _B--; JR_COND( _B, 0x10 ); } /* DJNZ o */
+OP(op,11) { _DE = ARG16(); } /* LD DE,w */
+OP(op,12) { WM( _DE, _A ); } /* LD (DE),A */
+OP(op,13) { _DE++; } /* INC DE */
+OP(op,14) { _D = INC(_D); } /* INC D */
+OP(op,15) { _D = DEC(_D); } /* DEC D */
+OP(op,16) { _D = ARG(); } /* LD D,n */
+OP(op,17) { RLA; } /* RLA */
+
+OP(op,18) { JR(); } /* JR o */
+OP(op,19) { ADD16(HL,DE); } /* ADD HL,DE */
+OP(op,1a) { _A = RM(_DE); } /* LD A,(DE) */
+OP(op,1b) { _DE--; CHECK_DE_LOOP; } /* DEC DE */
+OP(op,1c) { _E = INC(_E); } /* INC E */
+OP(op,1d) { _E = DEC(_E); } /* DEC E */
+OP(op,1e) { _E = ARG(); } /* LD E,n */
+OP(op,1f) { RRA; } /* RRA */
+
+OP(op,20) { JR_COND( !(_F & ZF), 0x20 ); } /* JR NZ,o */
+OP(op,21) { _HL = ARG16(); } /* LD HL,w */
+OP(op,22) { EA = ARG16(); WM16( EA, &Z180.HL ); } /* LD (w),HL */
+OP(op,23) { _HL++; } /* INC HL */
+OP(op,24) { _H = INC(_H); } /* INC H */
+OP(op,25) { _H = DEC(_H); } /* DEC H */
+OP(op,26) { _H = ARG(); } /* LD H,n */
+OP(op,27) { DAA; } /* DAA */
+
+OP(op,28) { JR_COND( _F & ZF, 0x28 ); } /* JR Z,o */
+OP(op,29) { ADD16(HL,HL); } /* ADD HL,HL */
+OP(op,2a) { EA = ARG16(); RM16( EA, &Z180.HL ); } /* LD HL,(w) */
+OP(op,2b) { _HL--; CHECK_HL_LOOP; } /* DEC HL */
+OP(op,2c) { _L = INC(_L); } /* INC L */
+OP(op,2d) { _L = DEC(_L); } /* DEC L */
+OP(op,2e) { _L = ARG(); } /* LD L,n */
+OP(op,2f) { _A ^= 0xff; _F = (_F&(SF|ZF|PF|CF))|HF|NF|(_A&(YF|XF)); } /* CPL */
+
+OP(op,30) { JR_COND( !(_F & CF), 0x30 ); } /* JR NC,o */
+OP(op,31) { _SP = ARG16(); } /* LD SP,w */
+OP(op,32) { EA = ARG16(); WM( EA, _A ); } /* LD (w),A */
+OP(op,33) { _SP++; } /* INC SP */
+OP(op,34) { WM( _HL, INC(RM(_HL)) ); } /* INC (HL) */
+OP(op,35) { WM( _HL, DEC(RM(_HL)) ); } /* DEC (HL) */
+OP(op,36) { WM( _HL, ARG() ); } /* LD (HL),n */
+OP(op,37) { _F = (_F & (SF|ZF|PF)) | CF | (_A & (YF|XF)); } /* SCF */
+
+OP(op,38) { JR_COND( _F & CF, 0x38 ); } /* JR C,o */
+OP(op,39) { ADD16(HL,SP); } /* ADD HL,SP */
+OP(op,3a) { EA = ARG16(); _A = RM( EA ); } /* LD A,(w) */
+OP(op,3b) { _SP--; } /* DEC SP */
+OP(op,3c) { _A = INC(_A); } /* INC A */
+OP(op,3d) { _A = DEC(_A); } /* DEC A */
+OP(op,3e) { _A = ARG(); } /* LD A,n */
+OP(op,3f) { _F = ((_F&(SF|ZF|PF|CF))|((_F&CF)<<4)|(_A&(YF|XF)))^CF; } /* CCF */
+//OP(op,3f) { _F = ((_F & ~(HF|NF)) | ((_F & CF)<<4)) ^ CF; } /* CCF */
+
+OP(op,40) { } /* LD B,B */
+OP(op,41) { _B = _C; } /* LD B,C */
+OP(op,42) { _B = _D; } /* LD B,D */
+OP(op,43) { _B = _E; } /* LD B,E */
+OP(op,44) { _B = _H; } /* LD B,H */
+OP(op,45) { _B = _L; } /* LD B,L */
+OP(op,46) { _B = RM(_HL); } /* LD B,(HL) */
+OP(op,47) { _B = _A; } /* LD B,A */
+
+OP(op,48) { _C = _B; } /* LD C,B */
+OP(op,49) { } /* LD C,C */
+OP(op,4a) { _C = _D; } /* LD C,D */
+OP(op,4b) { _C = _E; } /* LD C,E */
+OP(op,4c) { _C = _H; } /* LD C,H */
+OP(op,4d) { _C = _L; } /* LD C,L */
+OP(op,4e) { _C = RM(_HL); } /* LD C,(HL) */
+OP(op,4f) { _C = _A; } /* LD C,A */
+
+OP(op,50) { _D = _B; } /* LD D,B */
+OP(op,51) { _D = _C; } /* LD D,C */
+OP(op,52) { } /* LD D,D */
+OP(op,53) { _D = _E; } /* LD D,E */
+OP(op,54) { _D = _H; } /* LD D,H */
+OP(op,55) { _D = _L; } /* LD D,L */
+OP(op,56) { _D = RM(_HL); } /* LD D,(HL) */
+OP(op,57) { _D = _A; } /* LD D,A */
+
+OP(op,58) { _E = _B; } /* LD E,B */
+OP(op,59) { _E = _C; } /* LD E,C */
+OP(op,5a) { _E = _D; } /* LD E,D */
+OP(op,5b) { } /* LD E,E */
+OP(op,5c) { _E = _H; } /* LD E,H */
+OP(op,5d) { _E = _L; } /* LD E,L */
+OP(op,5e) { _E = RM(_HL); } /* LD E,(HL) */
+OP(op,5f) { _E = _A; } /* LD E,A */
+
+OP(op,60) { _H = _B; } /* LD H,B */
+OP(op,61) { _H = _C; } /* LD H,C */
+OP(op,62) { _H = _D; } /* LD H,D */
+OP(op,63) { _H = _E; } /* LD H,E */
+OP(op,64) { } /* LD H,H */
+OP(op,65) { _H = _L; } /* LD H,L */
+OP(op,66) { _H = RM(_HL); } /* LD H,(HL) */
+OP(op,67) { _H = _A; } /* LD H,A */
+
+OP(op,68) { _L = _B; } /* LD L,B */
+OP(op,69) { _L = _C; } /* LD L,C */
+OP(op,6a) { _L = _D; } /* LD L,D */
+OP(op,6b) { _L = _E; } /* LD L,E */
+OP(op,6c) { _L = _H; } /* LD L,H */
+OP(op,6d) { } /* LD L,L */
+OP(op,6e) { _L = RM(_HL); } /* LD L,(HL) */
+OP(op,6f) { _L = _A; } /* LD L,A */
+
+OP(op,70) { WM( _HL, _B ); } /* LD (HL),B */
+OP(op,71) { WM( _HL, _C ); } /* LD (HL),C */
+OP(op,72) { WM( _HL, _D ); } /* LD (HL),D */
+OP(op,73) { WM( _HL, _E ); } /* LD (HL),E */
+OP(op,74) { WM( _HL, _H ); } /* LD (HL),H */
+OP(op,75) { WM( _HL, _L ); } /* LD (HL),L */
+OP(op,76) { ENTER_HALT; } /* HALT */
+OP(op,77) { WM( _HL, _A ); } /* LD (HL),A */
+
+OP(op,78) { _A = _B; } /* LD A,B */
+OP(op,79) { _A = _C; } /* LD A,C */
+OP(op,7a) { _A = _D; } /* LD A,D */
+OP(op,7b) { _A = _E; } /* LD A,E */
+OP(op,7c) { _A = _H; } /* LD A,H */
+OP(op,7d) { _A = _L; } /* LD A,L */
+OP(op,7e) { _A = RM(_HL); } /* LD A,(HL) */
+OP(op,7f) { } /* LD A,A */
+
+OP(op,80) { ADD(_B); } /* ADD A,B */
+OP(op,81) { ADD(_C); } /* ADD A,C */
+OP(op,82) { ADD(_D); } /* ADD A,D */
+OP(op,83) { ADD(_E); } /* ADD A,E */
+OP(op,84) { ADD(_H); } /* ADD A,H */
+OP(op,85) { ADD(_L); } /* ADD A,L */
+OP(op,86) { ADD(RM(_HL)); } /* ADD A,(HL) */
+OP(op,87) { ADD(_A); } /* ADD A,A */
+
+OP(op,88) { ADC(_B); } /* ADC A,B */
+OP(op,89) { ADC(_C); } /* ADC A,C */
+OP(op,8a) { ADC(_D); } /* ADC A,D */
+OP(op,8b) { ADC(_E); } /* ADC A,E */
+OP(op,8c) { ADC(_H); } /* ADC A,H */
+OP(op,8d) { ADC(_L); } /* ADC A,L */
+OP(op,8e) { ADC(RM(_HL)); } /* ADC A,(HL) */
+OP(op,8f) { ADC(_A); } /* ADC A,A */
+
+OP(op,90) { SUB(_B); } /* SUB B */
+OP(op,91) { SUB(_C); } /* SUB C */
+OP(op,92) { SUB(_D); } /* SUB D */
+OP(op,93) { SUB(_E); } /* SUB E */
+OP(op,94) { SUB(_H); } /* SUB H */
+OP(op,95) { SUB(_L); } /* SUB L */
+OP(op,96) { SUB(RM(_HL)); } /* SUB (HL) */
+OP(op,97) { SUB(_A); } /* SUB A */
+
+OP(op,98) { SBC(_B); } /* SBC A,B */
+OP(op,99) { SBC(_C); } /* SBC A,C */
+OP(op,9a) { SBC(_D); } /* SBC A,D */
+OP(op,9b) { SBC(_E); } /* SBC A,E */
+OP(op,9c) { SBC(_H); } /* SBC A,H */
+OP(op,9d) { SBC(_L); } /* SBC A,L */
+OP(op,9e) { SBC(RM(_HL)); } /* SBC A,(HL) */
+OP(op,9f) { SBC(_A); } /* SBC A,A */
+
+OP(op,a0) { AND(_B); } /* AND B */
+OP(op,a1) { AND(_C); } /* AND C */
+OP(op,a2) { AND(_D); } /* AND D */
+OP(op,a3) { AND(_E); } /* AND E */
+OP(op,a4) { AND(_H); } /* AND H */
+OP(op,a5) { AND(_L); } /* AND L */
+OP(op,a6) { AND(RM(_HL)); } /* AND (HL) */
+OP(op,a7) { AND(_A); } /* AND A */
+
+OP(op,a8) { XOR(_B); } /* XOR B */
+OP(op,a9) { XOR(_C); } /* XOR C */
+OP(op,aa) { XOR(_D); } /* XOR D */
+OP(op,ab) { XOR(_E); } /* XOR E */
+OP(op,ac) { XOR(_H); } /* XOR H */
+OP(op,ad) { XOR(_L); } /* XOR L */
+OP(op,ae) { XOR(RM(_HL)); } /* XOR (HL) */
+OP(op,af) { XOR(_A); } /* XOR A */
+
+OP(op,b0) { OR(_B); } /* OR B */
+OP(op,b1) { OR(_C); } /* OR C */
+OP(op,b2) { OR(_D); } /* OR D */
+OP(op,b3) { OR(_E); } /* OR E */
+OP(op,b4) { OR(_H); } /* OR H */
+OP(op,b5) { OR(_L); } /* OR L */
+OP(op,b6) { OR(RM(_HL)); } /* OR (HL) */
+OP(op,b7) { OR(_A); } /* OR A */
+
+OP(op,b8) { CP(_B); } /* CP B */
+OP(op,b9) { CP(_C); } /* CP C */
+OP(op,ba) { CP(_D); } /* CP D */
+OP(op,bb) { CP(_E); } /* CP E */
+OP(op,bc) { CP(_H); } /* CP H */
+OP(op,bd) { CP(_L); } /* CP L */
+OP(op,be) { CP(RM(_HL)); } /* CP (HL) */
+OP(op,bf) { CP(_A); } /* CP A */
+
+OP(op,c0) { RET_COND( !(_F & ZF), 0xc0 ); } /* RET NZ */
+OP(op,c1) { POP(BC); } /* POP BC */
+OP(op,c2) { JP_COND( !(_F & ZF) ); } /* JP NZ,a */
+OP(op,c3) { JP; } /* JP a */
+OP(op,c4) { CALL_COND( !(_F & ZF), 0xc4 ); } /* CALL NZ,a */
+OP(op,c5) { PUSH( BC ); } /* PUSH BC */
+OP(op,c6) { ADD(ARG()); } /* ADD A,n */
+OP(op,c7) { RST(0x00); } /* RST 0 */
+
+OP(op,c8) { RET_COND( _F & ZF, 0xc8 ); } /* RET Z */
+OP(op,c9) { POP(PC); z180_change_pc(_PCD); } /* RET */
+OP(op,ca) { JP_COND( _F & ZF ); } /* JP Z,a */
+OP(op,cb) { _R++; EXEC(cb,ROP()); } /* **** CB xx */
+OP(op,cc) { CALL_COND( _F & ZF, 0xcc ); } /* CALL Z,a */
+OP(op,cd) { CALL(); } /* CALL a */
+OP(op,ce) { ADC(ARG()); } /* ADC A,n */
+OP(op,cf) { RST(0x08); } /* RST 1 */
+
+OP(op,d0) { RET_COND( !(_F & CF), 0xd0 ); } /* RET NC */
+OP(op,d1) { POP(DE); } /* POP DE */
+OP(op,d2) { JP_COND( !(_F & CF) ); } /* JP NC,a */
+OP(op,d3) { unsigned n = ARG() | (_A << 8); OUT( n, _A ); } /* OUT (n),A */
+OP(op,d4) { CALL_COND( !(_F & CF), 0xd4 ); } /* CALL NC,a */
+OP(op,d5) { PUSH( DE ); } /* PUSH DE */
+OP(op,d6) { SUB(ARG()); } /* SUB n */
+OP(op,d7) { RST(0x10); } /* RST 2 */
+
+OP(op,d8) { RET_COND( _F & CF, 0xd8 ); } /* RET C */
+OP(op,d9) { EXX; } /* EXX */
+OP(op,da) { JP_COND( _F & CF ); } /* JP C,a */
+OP(op,db) { unsigned n = ARG() | (_A << 8); _A = IN( n ); } /* IN A,(n) */
+OP(op,dc) { CALL_COND( _F & CF, 0xdc ); } /* CALL C,a */
+OP(op,dd) { _R++; EXEC(dd,ROP()); } /* **** DD xx */
+OP(op,de) { SBC(ARG()); } /* SBC A,n */
+OP(op,df) { RST(0x18); } /* RST 3 */
+
+OP(op,e0) { RET_COND( !(_F & PF), 0xe0 ); } /* RET PO */
+OP(op,e1) { POP(HL); } /* POP HL */
+OP(op,e2) { JP_COND( !(_F & PF) ); } /* JP PO,a */
+OP(op,e3) { EXSP(HL); } /* EX HL,(SP) */
+OP(op,e4) { CALL_COND( !(_F & PF), 0xe4 ); } /* CALL PO,a */
+OP(op,e5) { PUSH( HL ); } /* PUSH HL */
+OP(op,e6) { AND(ARG()); } /* AND n */
+OP(op,e7) { RST(0x20); } /* RST 4 */
+
+OP(op,e8) { RET_COND( _F & PF, 0xe8 ); } /* RET PE */
+OP(op,e9) { _PC = _HL; z180_change_pc(_PCD); } /* JP (HL) */
+OP(op,ea) { JP_COND( _F & PF ); } /* JP PE,a */
+OP(op,eb) { EX_DE_HL; } /* EX DE,HL */
+OP(op,ec) { CALL_COND( _F & PF, 0xec ); } /* CALL PE,a */
+OP(op,ed) { _R++; EXEC(ed,ROP()); } /* **** ED xx */
+OP(op,ee) { XOR(ARG()); } /* XOR n */
+OP(op,ef) { RST(0x28); } /* RST 5 */
+
+OP(op,f0) { RET_COND( !(_F & SF), 0xf0 ); } /* RET P */
+OP(op,f1) { POP(AF); } /* POP AF */
+OP(op,f2) { JP_COND( !(_F & SF) ); } /* JP P,a */
+OP(op,f3) { _IFF1 = _IFF2 = 0; } /* DI */
+OP(op,f4) { CALL_COND( !(_F & SF), 0xf4 ); } /* CALL P,a */
+OP(op,f5) { PUSH( AF ); } /* PUSH AF */
+OP(op,f6) { OR(ARG()); } /* OR n */
+OP(op,f7) { RST(0x30); } /* RST 6 */
+
+OP(op,f8) { RET_COND( _F & SF, 0xf8 ); } /* RET M */
+OP(op,f9) { _SP = _HL; } /* LD SP,HL */
+OP(op,fa) { JP_COND(_F & SF); } /* JP M,a */
+OP(op,fb) { EI; } /* EI */
+OP(op,fc) { CALL_COND( _F & SF, 0xfc ); } /* CALL M,a */
+OP(op,fd) { _R++; EXEC(fd,ROP()); } /* **** FD xx */
+OP(op,fe) { CP(ARG()); } /* CP n */
+OP(op,ff) { RST(0x38); } /* RST 7 */
+
+
+static void take_interrupt(int irq)
+{
+ int irq_vector;
+
+ /* there isn't a valid previous program counter */
+ _PPC = -1;
+
+ /* Check if processor was halted */
+ LEAVE_HALT;
+
+ /* Clear both interrupt flip flops */
+ _IFF1 = _IFF2 = 0;
+
+ if( irq == Z180_INT0 )
+ {
+ /* Daisy chain mode? If so, call the requesting device */
+ if (Z180.daisy)
+ irq_vector = z80daisy_call_ack_device(Z180.daisy);
+
+ /* else call back the cpu interface to retrieve the vector */
+ else
+ irq_vector = (*Z180.irq_callback)(0);
+
+ LOG(("Z180 #%d single int. irq_vector $%02x\n", cpu_getactivecpu(), irq_vector));
+
+ /* Interrupt mode 2. Call [Z180.I:databyte] */
+ if( _IM == 2 )
+ {
+ irq_vector = (irq_vector & 0xff) + (_I << 8);
+ PUSH( PC );
+ RM16( irq_vector, &Z180.PC );
+ LOG(("Z180 #%d IM2 [$%04x] = $%04x\n",cpu_getactivecpu() , irq_vector, _PCD));
+ /* CALL opcode timing */
+ z180_icount -= cc[Z180_TABLE_op][0xcd];
+ }
+ else
+ /* Interrupt mode 1. RST 38h */
+ if( _IM == 1 )
+ {
+ LOG(("Z180 #%d IM1 $0038\n",cpu_getactivecpu() ));
+ PUSH( PC );
+ _PCD = 0x0038;
+ /* RST $38 + 'interrupt latency' cycles */
+ z180_icount -= cc[Z180_TABLE_op][0xff] - cc[Z180_TABLE_ex][0xff];
+ }
+ else
+ {
+ /* Interrupt mode 0. We check for CALL and JP instructions, */
+ /* if neither of these were found we assume a 1 byte opcode */
+ /* was placed on the databus */
+ LOG(("Z180 #%d IM0 $%04x\n",cpu_getactivecpu() , irq_vector));
+ switch (irq_vector & 0xff0000)
+ {
+ case 0xcd0000: /* call */
+ PUSH( PC );
+ _PCD = irq_vector & 0xffff;
+ /* CALL $xxxx + 'interrupt latency' cycles */
+ z180_icount -= cc[Z180_TABLE_op][0xcd] - cc[Z180_TABLE_ex][0xff];
+ break;
+ case 0xc30000: /* jump */
+ _PCD = irq_vector & 0xffff;
+ /* JP $xxxx + 2 cycles */
+ z180_icount -= cc[Z180_TABLE_op][0xc3] - cc[Z180_TABLE_ex][0xff];
+ break;
+ default: /* rst (or other opcodes?) */
+ PUSH( PC );
+ _PCD = irq_vector & 0x0038;
+ /* RST $xx + 2 cycles */
+ z180_icount -= cc[Z180_TABLE_op][_PCD] - cc[Z180_TABLE_ex][_PCD];
+ break;
+ }
+ }
+ }
+ else
+ {
+ irq_vector = (IO(Z180_IL) & Z180_IL_IL) + (irq - Z180_INT1) * 2;
+ irq_vector = (_I << 8) + (irq_vector & 0xff);
+ PUSH( PC );
+ RM16( irq_vector, &Z180.PC );
+ LOG(("Z180 #%d INT%d [$%04x] = $%04x\n", cpu_getactivecpu(), irq, irq_vector, _PCD));
+ /* CALL opcode timing */
+ z180_icount -= cc[Z180_TABLE_op][0xcd];
+ }
+ z180_change_pc(_PCD);
+
+
+}
+
diff --git a/src/emu/cpu/z180/z180ops.h b/src/emu/cpu/z180/z180ops.h
new file mode 100644
index 00000000000..8995a368391
--- /dev/null
+++ b/src/emu/cpu/z180/z180ops.h
@@ -0,0 +1,1197 @@
+/***************************************************************
+ * Enter HALT state; write 1 to fake port on first execution
+ ***************************************************************/
+#define ENTER_HALT { \
+ _PC--; \
+ _HALT = 1; \
+ if( !Z180.after_EI ) \
+ z180_burn( z180_icount ); \
+}
+
+/***************************************************************
+ * Leave HALT state; write 0 to fake port
+ ***************************************************************/
+#define LEAVE_HALT { \
+ if( _HALT ) \
+ { \
+ _HALT = 0; \
+ _PC++; \
+ } \
+}
+
+/***************************************************************
+ * Input a byte from given I/O port
+ ***************************************************************/
+#define IN(port) \
+ (((port ^ IO_IOCR) & 0xffc0) == 0) ? \
+ z180_readcontrol(port) : io_read_byte_8(port)
+
+/***************************************************************
+ * Output a byte to given I/O port
+ ***************************************************************/
+#define OUT(port,value) \
+ if (((port ^ IO_IOCR) & 0xffc0) == 0) \
+ z180_writecontrol(port,value); \
+ else io_write_byte_8(port,value)
+
+/***************************************************************
+ * MMU calculate the memory managemant lookup table
+ * bb and cb specify a 4K page
+ * If the 4 most significant bits of an 16 bit address are
+ * greater or equal to the bank base, the bank base register
+ * specifies the 4K offset into the 20 bit address space.
+ * If the 4 bits are also greater or equal to the common base,
+ * the common base register is used to specify the offset.
+ ***************************************************************/
+INLINE void z180_mmu( void )
+{
+ offs_t addr, page, bb, cb;
+ bb = IO_CBAR & 15;
+ cb = IO_CBAR >> 4;
+ for( page = 0; page < 16; page++ )
+ {
+ addr = page << 12;
+ if (page >= bb)
+ {
+ if (page >= cb)
+ addr += IO_CBR << 12;
+ else
+ addr += IO_BBR << 12;
+ }
+ Z180.mmu[page] = addr;
+ }
+}
+
+
+#define MMU_REMAP_ADDR(addr) (Z180.mmu[((addr)>>12)&15]|((addr)&4095))
+
+/***************************************************************
+ * Read a byte from given memory location
+ ***************************************************************/
+#define RM(addr) program_read_byte_8(MMU_REMAP_ADDR(addr))
+UINT8 z180_readmem(offs_t offset)
+{
+ return RM(offset);
+}
+
+/***************************************************************
+ * Write a byte to given memory location
+ ***************************************************************/
+#define WM(addr,value) program_write_byte_8(MMU_REMAP_ADDR(addr),value)
+void z180_writemem(offs_t offset, UINT8 data)
+{
+ WM(offset, data);
+}
+
+
+/***************************************************************
+ * Read a word from given memory location
+ ***************************************************************/
+INLINE void RM16( offs_t addr, PAIR *r )
+{
+ r->b.l = RM(addr);
+ r->b.h = RM(addr+1);
+}
+
+/***************************************************************
+ * Write a word to given memory location
+ ***************************************************************/
+INLINE void WM16( offs_t addr, PAIR *r )
+{
+ WM(addr,r->b.l);
+ WM(addr+1,r->b.h);
+}
+
+/***************************************************************
+ * ROP() is identical to RM() except it is used for
+ * reading opcodes. In case of system with memory mapped I/O,
+ * this function can be used to greatly speed up emulation
+ ***************************************************************/
+INLINE UINT8 ROP(void)
+{
+ offs_t addr = _PCD;
+ _PC++;
+ return cpu_readop(MMU_REMAP_ADDR(addr));
+}
+
+/****************************************************************
+ * ARG() is identical to ROP() except it is used
+ * for reading opcode arguments. This difference can be used to
+ * support systems that use different encoding mechanisms for
+ * opcodes and opcode arguments
+ ***************************************************************/
+INLINE UINT8 ARG(void)
+{
+ offs_t addr = _PCD;
+ _PC++;
+ return cpu_readop_arg(MMU_REMAP_ADDR(addr));
+}
+
+INLINE UINT32 ARG16(void)
+{
+ offs_t addr = _PCD;
+ _PC += 2;
+ return cpu_readop_arg(MMU_REMAP_ADDR(addr)) | (cpu_readop_arg(MMU_REMAP_ADDR(addr+1)) << 8);
+}
+
+/****************************************************************************
+ * Change program counter - MMU lookup
+ ****************************************************************************/
+#define z180_change_pc(addr) change_pc(MMU_REMAP_ADDR(addr))
+void z180_setOPbase(int pc)
+{
+ z180_change_pc(pc);
+}
+
+/***************************************************************
+ * Calculate the effective addess EA of an opcode using
+ * IX+offset resp. IY+offset addressing.
+ ***************************************************************/
+#define EAX EA = (UINT32)(UINT16)(_IX+(INT8)ARG())
+#define EAY EA = (UINT32)(UINT16)(_IY+(INT8)ARG())
+
+/***************************************************************
+ * POP
+ ***************************************************************/
+#define POP(DR) { RM16( _SPD, &Z180.DR ); _SP += 2; }
+
+/***************************************************************
+ * PUSH
+ ***************************************************************/
+#define PUSH(SR) { _SP -= 2; WM16( _SPD, &Z180.SR ); }
+
+/***************************************************************
+ * JP
+ ***************************************************************/
+#if BUSY_LOOP_HACKS
+#define JP { \
+ unsigned oldpc = _PCD-1; \
+ _PCD = ARG16(); \
+ z180_change_pc(_PCD); \
+ /* speed up busy loop */ \
+ if( _PCD == oldpc ) \
+ { \
+ if( !Z180.after_EI ) \
+ BURNODD( z180_icount, 1, cc[Z180_TABLE_op][0xc3] ); \
+ } \
+ else \
+ { \
+ UINT8 op = cpu_readop(_PCD); \
+ if( _PCD == oldpc-1 ) \
+ { \
+ /* NOP - JP $-1 or EI - JP $-1 */ \
+ if ( op == 0x00 || op == 0xfb ) \
+ { \
+ if( !Z180.after_EI ) \
+ BURNODD( z180_icount-cc[Z180_TABLE_op][0x00],\
+ 2, cc[Z180_TABLE_op][0x00]+cc[Z180_TABLE_op][0xc3]); \
+ } \
+ } \
+ else \
+ /* LD SP,#xxxx - JP $-3 (Galaga) */ \
+ if( _PCD == oldpc-3 && op == 0x31 ) \
+ { \
+ if( !Z180.after_EI ) \
+ BURNODD( z180_icount-cc[Z180_TABLE_op][0x31], \
+ 2, cc[Z180_TABLE_op][0x31]+cc[Z180_TABLE_op][0xc3]); \
+ } \
+ } \
+}
+#else
+#define JP { \
+ _PCD = ARG16(); \
+ z180_change_pc(_PCD); \
+}
+#endif
+
+/***************************************************************
+ * JP_COND
+ ***************************************************************/
+
+#define JP_COND(cond) \
+ if( cond ) \
+ { \
+ _PCD = ARG16(); \
+ z180_change_pc(_PCD); \
+ } \
+ else \
+ { \
+ _PC += 2; \
+ }
+
+/***************************************************************
+ * JR
+ ***************************************************************/
+#define JR() \
+{ \
+ unsigned oldpc = _PCD-1; \
+ INT8 arg = (INT8)ARG(); /* ARG() also increments _PC */ \
+ _PC += arg; /* so don't do _PC += ARG() */ \
+ z180_change_pc(_PCD); \
+ /* speed up busy loop */ \
+ if( _PCD == oldpc ) \
+ { \
+ if( !Z180.after_EI ) \
+ BURNODD( z180_icount, 1, cc[Z180_TABLE_op][0x18] ); \
+ } \
+ else \
+ { \
+ UINT8 op = cpu_readop(_PCD); \
+ if( _PCD == oldpc-1 ) \
+ { \
+ /* NOP - JR $-1 or EI - JR $-1 */ \
+ if ( op == 0x00 || op == 0xfb ) \
+ { \
+ if( !Z180.after_EI ) \
+ BURNODD( z180_icount-cc[Z180_TABLE_op][0x00],\
+ 2, cc[Z180_TABLE_op][0x00]+cc[Z180_TABLE_op][0x18]); \
+ } \
+ } \
+ else \
+ /* LD SP,#xxxx - JR $-3 */ \
+ if( _PCD == oldpc-3 && op == 0x31 ) \
+ { \
+ if( !Z180.after_EI ) \
+ BURNODD( z180_icount-cc[Z180_TABLE_op][0x31], \
+ 2, cc[Z180_TABLE_op][0x31]+cc[Z180_TABLE_op][0x18]); \
+ } \
+ } \
+}
+
+/***************************************************************
+ * JR_COND
+ ***************************************************************/
+#define JR_COND(cond,opcode) \
+ if( cond ) \
+ { \
+ INT8 arg = (INT8)ARG(); /* ARG() also increments _PC */ \
+ _PC += arg; /* so don't do _PC += ARG() */ \
+ CC(ex,opcode); \
+ z180_change_pc(_PCD); \
+ } \
+ else _PC++; \
+
+/***************************************************************
+ * CALL
+ ***************************************************************/
+#define CALL() \
+ EA = ARG16(); \
+ PUSH( PC ); \
+ _PCD = EA; \
+ z180_change_pc(_PCD)
+
+/***************************************************************
+ * CALL_COND
+ ***************************************************************/
+#define CALL_COND(cond,opcode) \
+ if( cond ) \
+ { \
+ EA = ARG16(); \
+ PUSH( PC ); \
+ _PCD = EA; \
+ CC(ex,opcode); \
+ z180_change_pc(_PCD); \
+ } \
+ else \
+ { \
+ _PC+=2; \
+ }
+
+/***************************************************************
+ * RET_COND
+ ***************************************************************/
+#define RET_COND(cond,opcode) \
+ if( cond ) \
+ { \
+ POP(PC); \
+ z180_change_pc(_PCD); \
+ CC(ex,opcode); \
+ }
+
+/***************************************************************
+ * RETN
+ ***************************************************************/
+#define RETN { \
+ LOG(("Z180 #%d RETN IFF1:%d IFF2:%d\n", cpu_getactivecpu(), _IFF1, _IFF2)); \
+ POP(PC); \
+ z180_change_pc(_PCD); \
+ _IFF1 = _IFF2; \
+}
+
+/***************************************************************
+ * RETI
+ ***************************************************************/
+#define RETI { \
+ POP(PC); \
+ z180_change_pc(_PCD); \
+/* according to http://www.msxnet.org/tech/Z80/z80undoc.txt */ \
+/* _IFF1 = _IFF2; */ \
+ if (Z180.daisy) \
+ z80daisy_call_reti_device(Z180.daisy); \
+}
+
+/***************************************************************
+ * LD R,A
+ ***************************************************************/
+#define LD_R_A { \
+ _R = _A; \
+ _R2 = _A & 0x80; /* keep bit 7 of R */ \
+}
+
+/***************************************************************
+ * LD A,R
+ ***************************************************************/
+#define LD_A_R { \
+ _A = (_R & 0x7f) | _R2; \
+ _F = (_F & CF) | SZ[_A] | ( _IFF2 << 2 ); \
+}
+
+/***************************************************************
+ * LD I,A
+ ***************************************************************/
+#define LD_I_A { \
+ _I = _A; \
+}
+
+/***************************************************************
+ * LD A,I
+ ***************************************************************/
+#define LD_A_I { \
+ _A = _I; \
+ _F = (_F & CF) | SZ[_A] | ( _IFF2 << 2 ); \
+}
+
+/***************************************************************
+ * RST
+ ***************************************************************/
+#define RST(addr) \
+ PUSH( PC ); \
+ _PCD = addr; \
+ z180_change_pc(_PCD)
+
+/***************************************************************
+ * INC r8
+ ***************************************************************/
+INLINE UINT8 INC(UINT8 value)
+{
+ UINT8 res = value + 1;
+ _F = (_F & CF) | SZHV_inc[res];
+ return (UINT8)res;
+}
+
+/***************************************************************
+ * DEC r8
+ ***************************************************************/
+INLINE UINT8 DEC(UINT8 value)
+{
+ UINT8 res = value - 1;
+ _F = (_F & CF) | SZHV_dec[res];
+ return res;
+}
+
+/***************************************************************
+ * RLCA
+ ***************************************************************/
+#if Z180_EXACT
+#define RLCA \
+ _A = (_A << 1) | (_A >> 7); \
+ _F = (_F & (SF | ZF | PF)) | (_A & (YF | XF | CF))
+#else
+#define RLCA \
+ _A = (_A << 1) | (_A >> 7); \
+ _F = (_F & (SF | ZF | YF | XF | PF)) | (_A & CF)
+#endif
+
+/***************************************************************
+ * RRCA
+ ***************************************************************/
+#if Z180_EXACT
+#define RRCA \
+ _F = (_F & (SF | ZF | PF)) | (_A & (YF | XF | CF)); \
+ _A = (_A >> 1) | (_A << 7)
+#else
+#define RRCA \
+ _F = (_F & (SF | ZF | YF | XF | PF)) | (_A & CF); \
+ _A = (_A >> 1) | (_A << 7)
+#endif
+
+/***************************************************************
+ * RLA
+ ***************************************************************/
+#if Z180_EXACT
+#define RLA { \
+ UINT8 res = (_A << 1) | (_F & CF); \
+ UINT8 c = (_A & 0x80) ? CF : 0; \
+ _F = (_F & (SF | ZF | PF)) | c | (res & (YF | XF)); \
+ _A = res; \
+}
+#else
+#define RLA { \
+ UINT8 res = (_A << 1) | (_F & CF); \
+ UINT8 c = (_A & 0x80) ? CF : 0; \
+ _F = (_F & (SF | ZF | YF | XF | PF)) | c; \
+ _A = res; \
+}
+#endif
+
+/***************************************************************
+ * RRA
+ ***************************************************************/
+#if Z180_EXACT
+#define RRA { \
+ UINT8 res = (_A >> 1) | (_F << 7); \
+ UINT8 c = (_A & 0x01) ? CF : 0; \
+ _F = (_F & (SF | ZF | PF)) | c | (res & (YF | XF)); \
+ _A = res; \
+}
+#else
+#define RRA { \
+ UINT8 res = (_A >> 1) | (_F << 7); \
+ UINT8 c = (_A & 0x01) ? CF : 0; \
+ _F = (_F & (SF | ZF | YF | XF | PF)) | c; \
+ _A = res; \
+}
+#endif
+
+/***************************************************************
+ * RRD
+ ***************************************************************/
+#define RRD { \
+ UINT8 n = RM(_HL); \
+ WM( _HL, (n >> 4) | (_A << 4) ); \
+ _A = (_A & 0xf0) | (n & 0x0f); \
+ _F = (_F & CF) | SZP[_A]; \
+}
+
+/***************************************************************
+ * RLD
+ ***************************************************************/
+#define RLD { \
+ UINT8 n = RM(_HL); \
+ WM( _HL, (n << 4) | (_A & 0x0f) ); \
+ _A = (_A & 0xf0) | (n >> 4); \
+ _F = (_F & CF) | SZP[_A]; \
+}
+
+/***************************************************************
+ * ADD A,n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define ADD(value) \
+{ \
+ UINT32 ah = _AFD & 0xff00; \
+ UINT32 res = (UINT8)((ah >> 8) + value); \
+ _F = SZHVC_add[ah | res]; \
+ _A = res; \
+}
+#else
+#define ADD(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = _A + val; \
+ _F = SZ[(UINT8)res] | ((res >> 8) & CF) | \
+ ((_A ^ res ^ val) & HF) | \
+ (((val ^ _A ^ 0x80) & (val ^ res) & 0x80) >> 5); \
+ _A = (UINT8)res; \
+}
+#endif
+
+/***************************************************************
+ * ADC A,n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define ADC(value) \
+{ \
+ UINT32 ah = _AFD & 0xff00, c = _AFD & 1; \
+ UINT32 res = (UINT8)((ah >> 8) + value + c); \
+ _F = SZHVC_add[(c << 16) | ah | res]; \
+ _A = res; \
+}
+#else
+#define ADC(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = _A + val + (_F & CF); \
+ _F = SZ[res & 0xff] | ((res >> 8) & CF) | \
+ ((_A ^ res ^ val) & HF) | \
+ (((val ^ _A ^ 0x80) & (val ^ res) & 0x80) >> 5); \
+ _A = res; \
+}
+#endif
+
+/***************************************************************
+ * SUB n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define SUB(value) \
+{ \
+ UINT32 ah = _AFD & 0xff00; \
+ UINT32 res = (UINT8)((ah >> 8) - value); \
+ _F = SZHVC_sub[ah | res]; \
+ _A = res; \
+}
+#else
+#define SUB(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = _A - val; \
+ _F = SZ[res & 0xff] | ((res >> 8) & CF) | NF | \
+ ((_A ^ res ^ val) & HF) | \
+ (((val ^ _A) & (_A ^ res) & 0x80) >> 5); \
+ _A = res; \
+}
+#endif
+
+/***************************************************************
+ * SBC A,n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define SBC(value) \
+{ \
+ UINT32 ah = _AFD & 0xff00, c = _AFD & 1; \
+ UINT32 res = (UINT8)((ah >> 8) - value - c); \
+ _F = SZHVC_sub[(c<<16) | ah | res]; \
+ _A = res; \
+}
+#else
+#define SBC(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = _A - val - (_F & CF); \
+ _F = SZ[res & 0xff] | ((res >> 8) & CF) | NF | \
+ ((_A ^ res ^ val) & HF) | \
+ (((val ^ _A) & (_A ^ res) & 0x80) >> 5); \
+ _A = res; \
+}
+#endif
+
+/***************************************************************
+ * NEG
+ ***************************************************************/
+#define NEG { \
+ UINT8 value = _A; \
+ _A = 0; \
+ SUB(value); \
+}
+
+/***************************************************************
+ * DAA
+ ***************************************************************/
+#define DAA { \
+ int idx = _A; \
+ if( _F & CF ) idx |= 0x100; \
+ if( _F & HF ) idx |= 0x200; \
+ if( _F & NF ) idx |= 0x400; \
+ _AF = DAATable[idx]; \
+}
+
+/***************************************************************
+ * AND n
+ ***************************************************************/
+#define AND(value) \
+ _A &= value; \
+ _F = SZP[_A] | HF
+
+/***************************************************************
+ * OR n
+ ***************************************************************/
+#define OR(value) \
+ _A |= value; \
+ _F = SZP[_A]
+
+/***************************************************************
+ * XOR n
+ ***************************************************************/
+#define XOR(value) \
+ _A ^= value; \
+ _F = SZP[_A]
+
+/***************************************************************
+ * CP n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define CP(value) \
+{ \
+ UINT32 ah = _AFD & 0xff00; \
+ UINT32 res = (UINT8)((ah >> 8) - value); \
+ _F = SZHVC_sub[ah | res]; \
+}
+#else
+#define CP(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = _A - val; \
+ _F = SZ[res & 0xff] | ((res >> 8) & CF) | NF | \
+ ((_A ^ res ^ val) & HF) | \
+ ((((val ^ _A) & (_A ^ res)) >> 5) & VF); \
+}
+#endif
+
+/***************************************************************
+ * EX AF,AF'
+ ***************************************************************/
+#define EX_AF { \
+ PAIR tmp; \
+ tmp = Z180.AF; Z180.AF = Z180.AF2; Z180.AF2 = tmp; \
+}
+
+/***************************************************************
+ * EX DE,HL
+ ***************************************************************/
+#define EX_DE_HL { \
+ PAIR tmp; \
+ tmp = Z180.DE; Z180.DE = Z180.HL; Z180.HL = tmp; \
+}
+
+/***************************************************************
+ * EXX
+ ***************************************************************/
+#define EXX { \
+ PAIR tmp; \
+ tmp = Z180.BC; Z180.BC = Z180.BC2; Z180.BC2 = tmp; \
+ tmp = Z180.DE; Z180.DE = Z180.DE2; Z180.DE2 = tmp; \
+ tmp = Z180.HL; Z180.HL = Z180.HL2; Z180.HL2 = tmp; \
+}
+
+/***************************************************************
+ * EX (SP),r16
+ ***************************************************************/
+#define EXSP(DR) \
+{ \
+ PAIR tmp = { { 0, 0, 0, 0 } }; \
+ RM16( _SPD, &tmp ); \
+ WM16( _SPD, &Z180.DR ); \
+ Z180.DR = tmp; \
+}
+
+
+/***************************************************************
+ * ADD16
+ ***************************************************************/
+#define ADD16(DR,SR) \
+{ \
+ UINT32 res = Z180.DR.d + Z180.SR.d; \
+ _F = (_F & (SF | ZF | VF)) | \
+ (((Z180.DR.d ^ res ^ Z180.SR.d) >> 8) & HF) | \
+ ((res >> 16) & CF); \
+ Z180.DR.w.l = (UINT16)res; \
+}
+
+/***************************************************************
+ * ADC r16,r16
+ ***************************************************************/
+#define ADC16(DR) \
+{ \
+ UINT32 res = _HLD + Z180.DR.d + (_F & CF); \
+ _F = (((_HLD ^ res ^ Z180.DR.d) >> 8) & HF) | \
+ ((res >> 16) & CF) | \
+ ((res >> 8) & SF) | \
+ ((res & 0xffff) ? 0 : ZF) | \
+ (((Z180.DR.d ^ _HLD ^ 0x8000) & (Z180.DR.d ^ res) & 0x8000) >> 13); \
+ _HL = (UINT16)res; \
+}
+
+/***************************************************************
+ * SBC r16,r16
+ ***************************************************************/
+#define SBC16(DR) \
+{ \
+ UINT32 res = _HLD - Z180.DR.d - (_F & CF); \
+ _F = (((_HLD ^ res ^ Z180.DR.d) >> 8) & HF) | NF | \
+ ((res >> 16) & CF) | \
+ ((res >> 8) & SF) | \
+ ((res & 0xffff) ? 0 : ZF) | \
+ (((Z180.DR.d ^ _HLD) & (_HLD ^ res) &0x8000) >> 13); \
+ _HL = (UINT16)res; \
+}
+
+/***************************************************************
+ * RLC r8
+ ***************************************************************/
+INLINE UINT8 RLC(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x80) ? CF : 0;
+ res = ((res << 1) | (res >> 7)) & 0xff;
+ _F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * RRC r8
+ ***************************************************************/
+INLINE UINT8 RRC(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x01) ? CF : 0;
+ res = ((res >> 1) | (res << 7)) & 0xff;
+ _F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * RL r8
+ ***************************************************************/
+INLINE UINT8 RL(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x80) ? CF : 0;
+ res = ((res << 1) | (_F & CF)) & 0xff;
+ _F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * RR r8
+ ***************************************************************/
+INLINE UINT8 RR(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x01) ? CF : 0;
+ res = ((res >> 1) | (_F << 7)) & 0xff;
+ _F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * SLA r8
+ ***************************************************************/
+INLINE UINT8 SLA(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x80) ? CF : 0;
+ res = (res << 1) & 0xff;
+ _F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * SRA r8
+ ***************************************************************/
+INLINE UINT8 SRA(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x01) ? CF : 0;
+ res = ((res >> 1) | (res & 0x80)) & 0xff;
+ _F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * SLL r8
+ ***************************************************************/
+INLINE UINT8 SLL(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x80) ? CF : 0;
+ res = ((res << 1) | 0x01) & 0xff;
+ _F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * SRL r8
+ ***************************************************************/
+INLINE UINT8 SRL(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x01) ? CF : 0;
+ res = (res >> 1) & 0xff;
+ _F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * BIT bit,r8
+ ***************************************************************/
+#undef BIT
+#define BIT(bit,reg) \
+ _F = (_F & CF) | HF | SZ_BIT[reg & (1<<bit)]
+
+/***************************************************************
+ * BIT bit,(IX/Y+o)
+ ***************************************************************/
+#if Z180_EXACT
+#define BIT_XY(bit,reg) \
+ _F = (_F & CF) | HF | (SZ_BIT[reg & (1<<bit)] & ~(YF|XF)) | ((EA>>8) & (YF|XF))
+#else
+#define BIT_XY BIT
+#endif
+
+/***************************************************************
+ * RES bit,r8
+ ***************************************************************/
+INLINE UINT8 RES(UINT8 bit, UINT8 value)
+{
+ return value & ~(1<<bit);
+}
+
+/***************************************************************
+ * SET bit,r8
+ ***************************************************************/
+INLINE UINT8 SET(UINT8 bit, UINT8 value)
+{
+ return value | (1<<bit);
+}
+
+/***************************************************************
+ * LDI
+ ***************************************************************/
+#if Z180_EXACT
+#define LDI { \
+ UINT8 io = RM(_HL); \
+ WM( _DE, io ); \
+ _F &= SF | ZF | CF; \
+ if( (_A + io) & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \
+ if( (_A + io) & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \
+ _HL++; _DE++; _BC--; \
+ if( _BC ) _F |= VF; \
+}
+#else
+#define LDI { \
+ WM( _DE, RM(_HL) ); \
+ _F &= SF | ZF | YF | XF | CF; \
+ _HL++; _DE++; _BC--; \
+ if( _BC ) _F |= VF; \
+}
+#endif
+
+/***************************************************************
+ * CPI
+ ***************************************************************/
+#if Z180_EXACT
+#define CPI { \
+ UINT8 val = RM(_HL); \
+ UINT8 res = _A - val; \
+ _HL++; _BC--; \
+ _F = (_F & CF) | (SZ[res] & ~(YF|XF)) | ((_A ^ val ^ res) & HF) | NF; \
+ if( _F & HF ) res -= 1; \
+ if( res & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \
+ if( res & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \
+ if( _BC ) _F |= VF; \
+}
+#else
+#define CPI { \
+ UINT8 val = RM(_HL); \
+ UINT8 res = _A - val; \
+ _HL++; _BC--; \
+ _F = (_F & CF) | SZ[res] | ((_A ^ val ^ res) & HF) | NF; \
+ if( _BC ) _F |= VF; \
+}
+#endif
+
+/***************************************************************
+ * INI
+ ***************************************************************/
+#if Z180_EXACT
+#define INI { \
+ UINT8 io = IN(_BC); \
+ _B--; \
+ WM( _HL, io ); \
+ _HL++; \
+ _F = SZ[_B]; \
+ if( io & SF ) _F |= NF; \
+ if( (_C + io + 1) & 0x100 ) _F |= HF | CF; \
+ if( (irep_tmp1[_C & 3][io & 3] ^ \
+ breg_tmp2[_B] ^ \
+ (_C >> 2) ^ \
+ (io >> 2)) & 1 ) \
+ _F |= PF; \
+}
+#else
+#define INI { \
+ _B--; \
+ WM( _HL, IN(_BC) ); \
+ _HL++; \
+ _F = (_B) ? NF : NF | ZF; \
+}
+#endif
+
+/***************************************************************
+ * OUTI
+ ***************************************************************/
+#if Z180_EXACT
+#define OUTI { \
+ UINT8 io = RM(_HL); \
+ _B--; \
+ OUT( _BC, io ); \
+ _HL++; \
+ _F = SZ[_B]; \
+ if( io & SF ) _F |= NF; \
+ if( (_C + io + 1) & 0x100 ) _F |= HF | CF; \
+ if( (irep_tmp1[_C & 3][io & 3] ^ \
+ breg_tmp2[_B] ^ \
+ (_C >> 2) ^ \
+ (io >> 2)) & 1 ) \
+ _F |= PF; \
+}
+#else
+#define OUTI { \
+ _B--; \
+ OUT( _BC, RM(_HL) ); \
+ _HL++; \
+ _F = (_B) ? NF : NF | ZF; \
+}
+#endif
+
+/***************************************************************
+ * LDD
+ ***************************************************************/
+#if Z180_EXACT
+#define LDD { \
+ UINT8 io = RM(_HL); \
+ WM( _DE, io ); \
+ _F &= SF | ZF | CF; \
+ if( (_A + io) & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \
+ if( (_A + io) & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \
+ _HL--; _DE--; _BC--; \
+ if( _BC ) _F |= VF; \
+}
+#else
+#define LDD { \
+ WM( _DE, RM(_HL) ); \
+ _F &= SF | ZF | YF | XF | CF; \
+ _HL--; _DE--; _BC--; \
+ if( _BC ) _F |= VF; \
+}
+#endif
+
+/***************************************************************
+ * CPD
+ ***************************************************************/
+#if Z180_EXACT
+#define CPD { \
+ UINT8 val = RM(_HL); \
+ UINT8 res = _A - val; \
+ _HL--; _BC--; \
+ _F = (_F & CF) | (SZ[res] & ~(YF|XF)) | ((_A ^ val ^ res) & HF) | NF; \
+ if( _F & HF ) res -= 1; \
+ if( res & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \
+ if( res & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \
+ if( _BC ) _F |= VF; \
+}
+#else
+#define CPD { \
+ UINT8 val = RM(_HL); \
+ UINT8 res = _A - val; \
+ _HL--; _BC--; \
+ _F = (_F & CF) | SZ[res] | ((_A ^ val ^ res) & HF) | NF; \
+ if( _BC ) _F |= VF; \
+}
+#endif
+
+/***************************************************************
+ * IND
+ ***************************************************************/
+#if Z180_EXACT
+#define IND { \
+ UINT8 io = IN(_BC); \
+ _B--; \
+ WM( _HL, io ); \
+ _HL--; \
+ _F = SZ[_B]; \
+ if( io & SF ) _F |= NF; \
+ if( (_C + io - 1) & 0x100 ) _F |= HF | CF; \
+ if( (drep_tmp1[_C & 3][io & 3] ^ \
+ breg_tmp2[_B] ^ \
+ (_C >> 2) ^ \
+ (io >> 2)) & 1 ) \
+ _F |= PF; \
+}
+#else
+#define IND { \
+ _B--; \
+ WM( _HL, IN(_BC) ); \
+ _HL--; \
+ _F = (_B) ? NF : NF | ZF; \
+}
+#endif
+
+/***************************************************************
+ * OUTD
+ ***************************************************************/
+#if Z180_EXACT
+#define OUTD { \
+ UINT8 io = RM(_HL); \
+ _B--; \
+ OUT( _BC, io ); \
+ _HL--; \
+ _F = SZ[_B]; \
+ if( io & SF ) _F |= NF; \
+ if( (_C + io - 1) & 0x100 ) _F |= HF | CF; \
+ if( (drep_tmp1[_C & 3][io & 3] ^ \
+ breg_tmp2[_B] ^ \
+ (_C >> 2) ^ \
+ (io >> 2)) & 1 ) \
+ _F |= PF; \
+}
+#else
+#define OUTD { \
+ _B--; \
+ OUT( _BC, RM(_HL) ); \
+ _HL--; \
+ _F = (_B) ? NF : NF | ZF; \
+}
+#endif
+
+/***************************************************************
+ * LDIR
+ ***************************************************************/
+#define LDIR \
+ LDI; \
+ if( _BC ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xb0); \
+ }
+
+/***************************************************************
+ * CPIR
+ ***************************************************************/
+#define CPIR \
+ CPI; \
+ if( _BC && !(_F & ZF) ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xb1); \
+ }
+
+/***************************************************************
+ * INIR
+ ***************************************************************/
+#define INIR \
+ INI; \
+ if( _B ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xb2); \
+ }
+
+/***************************************************************
+ * OTIR
+ ***************************************************************/
+#define OTIR \
+ OUTI; \
+ if( _B ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xb3); \
+ }
+
+/***************************************************************
+ * LDDR
+ ***************************************************************/
+#define LDDR \
+ LDD; \
+ if( _BC ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xb8); \
+ }
+
+/***************************************************************
+ * CPDR
+ ***************************************************************/
+#define CPDR \
+ CPD; \
+ if( _BC && !(_F & ZF) ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xb9); \
+ }
+
+/***************************************************************
+ * INDR
+ ***************************************************************/
+#define INDR \
+ IND; \
+ if( _B ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xba); \
+ }
+
+/***************************************************************
+ * OTDR
+ ***************************************************************/
+#define OTDR \
+ OUTD; \
+ if( _B ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xbb); \
+ }
+
+/***************************************************************
+ * EI
+ ***************************************************************/
+#define EI { \
+ _IFF1 = _IFF2 = 1; \
+ Z180.after_EI = 1; \
+}
+
+/***************************************************************
+ * TST n
+ ***************************************************************/
+#define TST(value) \
+ _F = SZP[_A & value] | HF
+
+/***************************************************************
+ * MLT rr
+ ***************************************************************/
+#define MLT(DR) { \
+ Z180.DR.w.l = Z180.DR.b.l * Z180.DR.b.h; \
+}
+
+/***************************************************************
+ * OTIM
+ ***************************************************************/
+#define OTIM { \
+ _B--; \
+ OUT( _C, RM(_HL) ); \
+ _HL++; \
+ _C++; \
+ _F = (_B) ? NF : NF | ZF; \
+}
+
+/***************************************************************
+ * OTDM
+ ***************************************************************/
+#define OTDM { \
+ _B--; \
+ OUT( _C, RM(_HL) ); \
+ _HL--; \
+ _C--; \
+ _F = (_B) ? NF : NF | ZF; \
+}
+
+/***************************************************************
+ * OTIMR
+ ***************************************************************/
+#define OTIMR \
+ OTIM; \
+ if( _B ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xb3); \
+ }
+
+/***************************************************************
+ * OTDMR
+ ***************************************************************/
+#define OTDMR \
+ OTDM; \
+ if( _B ) \
+ { \
+ _PC -= 2; \
+ CC(ex,0xb3); \
+ }
+
+/***************************************************************
+ * OTDMR
+ ***************************************************************/
+#define SLP { \
+ z180_icount = 0; \
+ _HALT = 2; \
+}
+
diff --git a/src/emu/cpu/z180/z180tbl.h b/src/emu/cpu/z180/z180tbl.h
new file mode 100644
index 00000000000..bfd2271aa5f
--- /dev/null
+++ b/src/emu/cpu/z180/z180tbl.h
@@ -0,0 +1,362 @@
+#if Z180_EXACT
+/* tmp1 value for ini/inir/outi/otir for [C.1-0][io.1-0] */
+static UINT8 irep_tmp1[4][4] = {
+ {0,0,1,0},{0,1,0,1},{1,0,1,1},{0,1,1,0}
+};
+
+/* tmp1 value for ind/indr/outd/otdr for [C.1-0][io.1-0] */
+static UINT8 drep_tmp1[4][4] = {
+ {0,1,0,0},{1,0,0,1},{0,0,1,0},{0,1,0,1}
+};
+
+/* tmp2 value for all in/out repeated opcodes for B.7-0 */
+static UINT8 breg_tmp2[256] = {
+ 0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
+ 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
+ 1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
+ 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
+ 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
+ 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
+ 0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
+ 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
+ 1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
+ 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
+ 0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
+ 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
+ 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
+ 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
+ 1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
+ 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1
+};
+#endif
+
+static UINT8 cc_op[0x100] = {
+/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */
+ 3, 9, 7, 4, 4, 4, 6, 3, 4, 7, 6, 4, 4, 4, 6, 3,
+ 7, 9, 7, 4, 4, 4, 6, 3, 8, 7, 6, 4, 4, 4, 6, 3,
+ 6, 9,16, 4, 4, 4, 6, 4, 6, 7,15, 4, 4, 4, 6, 3,
+ 6, 9,13, 4,10,10, 9, 3, 6, 7,12, 4, 4, 4, 6, 3,
+ 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4,
+ 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4,
+ 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4,
+ 7, 7, 7, 7, 7, 7, 3, 7, 4, 4, 4, 4, 4, 4, 6, 4,
+ 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4,
+ 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4,
+ 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4,
+ 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4,
+ 5, 9, 6, 9, 6,11, 6,11, 5, 9, 6, 0, 6,16, 6,11,
+ 5, 9, 6,10, 6,11, 6,11, 5, 3, 6, 9, 6, 0, 6,11,
+ 5, 9, 6,16, 6,11, 6,11, 5, 3, 6, 3, 6, 0, 6,11,
+ 5, 9, 6, 3, 6,11, 6,11, 5, 4, 6, 3, 6, 0, 6,11
+};
+
+static UINT8 cc_cb[0x100] = {
+/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 9, 6,
+ 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 9, 6,
+ 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 9, 6,
+ 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 9, 6,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7,
+ 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7
+};
+
+static UINT8 cc_ed[0x100] = {
+/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */
+ 12,13, 6, 6, 9, 6, 6, 6,12,13, 6, 6, 9, 6, 6, 6,
+ 12,13, 6, 6, 9, 6, 6, 6,12,13, 6, 6, 9, 6, 6, 6,
+ 12,13, 6, 6, 9, 6, 6, 6,12,13, 6, 6,10, 6, 6, 6,
+ 12,13, 6, 6, 9, 6, 6, 6,12,13, 6, 6, 9, 6, 6, 6,
+ 9,10,10,19, 6,12, 6, 6, 9,10,10,18,17,12, 6, 6,
+ 9,10,10,19, 6,12, 6, 6, 9,10,10,18,17,12, 6, 6,
+ 9,10,10,19, 6,12, 6,16, 9,10,10,18,17,12, 6,16,
+ 9,10,10,19,12,12, 8, 6, 9,10,10,18,17,12, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 12,12,12,12, 6, 6, 6, 6,12,12,12,12, 6, 6, 6, 6,
+ 12,12,12,12, 6, 6, 6, 6,12,12,12,12, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
+};
+
+static UINT8 cc_xy[0x100] = {
+/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */
+ 4, 4, 4, 4, 4, 4, 4, 4, 4,10, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4,10, 4, 4, 4, 4, 4, 4,
+ 4,12,19, 7, 9, 9,15, 4, 4,10,18, 7, 9, 9, 9, 4,
+ 4, 4, 4, 4,18,18,15, 4, 4,10, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4,
+ 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4,
+ 9, 9, 9, 9, 9, 9,14, 9, 9, 9, 9, 9, 9, 9,14, 9,
+ 15,15,15,15,15,15, 4,15, 4, 4, 4, 4, 9, 9,14, 4,
+ 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4,
+ 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4,
+ 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4,
+ 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4,12, 4,19, 4,14, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4
+};
+
+static UINT8 cc_xycb[0x100] = {
+/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+ 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19
+};
+
+/* extra cycles if jr/jp/call taken and 'interrupt latency' on rst 0-7 */
+static UINT8 cc_ex[0x100] = {
+/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DJNZ */
+ 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* JR NZ/JR Z */
+ 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* JR NC/JR C */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, 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,
+ 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, /* LDIR/CPIR/INIR/OTIR LDDR/CPDR/INDR/OTDR */
+ 5, 0, 3, 0,10, 0, 0, 2, 5, 0, 3, 0,10, 0, 0, 2,
+ 5, 0, 3, 0,10, 0, 0, 2, 5, 0, 3, 0,10, 0, 0, 2,
+ 5, 0, 3, 0,10, 0, 0, 2, 5, 0, 3, 0,10, 0, 0, 2,
+ 5, 0, 3, 0,10, 0, 0, 2, 5, 0, 3, 0,10, 0, 0, 2
+};
+
+static UINT8 *cc[6] = { cc_op, cc_cb, cc_ed, cc_xy, cc_xycb, cc_ex };
+#define Z180_TABLE_dd Z180_TABLE_xy
+#define Z180_TABLE_fd Z180_TABLE_xy
+
+static void take_interrupt(int irqline);
+
+#define PROTOTYPES(tablename,prefix) \
+ INLINE void prefix##_00(void); INLINE void prefix##_01(void); INLINE void prefix##_02(void); INLINE void prefix##_03(void); \
+ INLINE void prefix##_04(void); INLINE void prefix##_05(void); INLINE void prefix##_06(void); INLINE void prefix##_07(void); \
+ INLINE void prefix##_08(void); INLINE void prefix##_09(void); INLINE void prefix##_0a(void); INLINE void prefix##_0b(void); \
+ INLINE void prefix##_0c(void); INLINE void prefix##_0d(void); INLINE void prefix##_0e(void); INLINE void prefix##_0f(void); \
+ INLINE void prefix##_10(void); INLINE void prefix##_11(void); INLINE void prefix##_12(void); INLINE void prefix##_13(void); \
+ INLINE void prefix##_14(void); INLINE void prefix##_15(void); INLINE void prefix##_16(void); INLINE void prefix##_17(void); \
+ INLINE void prefix##_18(void); INLINE void prefix##_19(void); INLINE void prefix##_1a(void); INLINE void prefix##_1b(void); \
+ INLINE void prefix##_1c(void); INLINE void prefix##_1d(void); INLINE void prefix##_1e(void); INLINE void prefix##_1f(void); \
+ INLINE void prefix##_20(void); INLINE void prefix##_21(void); INLINE void prefix##_22(void); INLINE void prefix##_23(void); \
+ INLINE void prefix##_24(void); INLINE void prefix##_25(void); INLINE void prefix##_26(void); INLINE void prefix##_27(void); \
+ INLINE void prefix##_28(void); INLINE void prefix##_29(void); INLINE void prefix##_2a(void); INLINE void prefix##_2b(void); \
+ INLINE void prefix##_2c(void); INLINE void prefix##_2d(void); INLINE void prefix##_2e(void); INLINE void prefix##_2f(void); \
+ INLINE void prefix##_30(void); INLINE void prefix##_31(void); INLINE void prefix##_32(void); INLINE void prefix##_33(void); \
+ INLINE void prefix##_34(void); INLINE void prefix##_35(void); INLINE void prefix##_36(void); INLINE void prefix##_37(void); \
+ INLINE void prefix##_38(void); INLINE void prefix##_39(void); INLINE void prefix##_3a(void); INLINE void prefix##_3b(void); \
+ INLINE void prefix##_3c(void); INLINE void prefix##_3d(void); INLINE void prefix##_3e(void); INLINE void prefix##_3f(void); \
+ INLINE void prefix##_40(void); INLINE void prefix##_41(void); INLINE void prefix##_42(void); INLINE void prefix##_43(void); \
+ INLINE void prefix##_44(void); INLINE void prefix##_45(void); INLINE void prefix##_46(void); INLINE void prefix##_47(void); \
+ INLINE void prefix##_48(void); INLINE void prefix##_49(void); INLINE void prefix##_4a(void); INLINE void prefix##_4b(void); \
+ INLINE void prefix##_4c(void); INLINE void prefix##_4d(void); INLINE void prefix##_4e(void); INLINE void prefix##_4f(void); \
+ INLINE void prefix##_50(void); INLINE void prefix##_51(void); INLINE void prefix##_52(void); INLINE void prefix##_53(void); \
+ INLINE void prefix##_54(void); INLINE void prefix##_55(void); INLINE void prefix##_56(void); INLINE void prefix##_57(void); \
+ INLINE void prefix##_58(void); INLINE void prefix##_59(void); INLINE void prefix##_5a(void); INLINE void prefix##_5b(void); \
+ INLINE void prefix##_5c(void); INLINE void prefix##_5d(void); INLINE void prefix##_5e(void); INLINE void prefix##_5f(void); \
+ INLINE void prefix##_60(void); INLINE void prefix##_61(void); INLINE void prefix##_62(void); INLINE void prefix##_63(void); \
+ INLINE void prefix##_64(void); INLINE void prefix##_65(void); INLINE void prefix##_66(void); INLINE void prefix##_67(void); \
+ INLINE void prefix##_68(void); INLINE void prefix##_69(void); INLINE void prefix##_6a(void); INLINE void prefix##_6b(void); \
+ INLINE void prefix##_6c(void); INLINE void prefix##_6d(void); INLINE void prefix##_6e(void); INLINE void prefix##_6f(void); \
+ INLINE void prefix##_70(void); INLINE void prefix##_71(void); INLINE void prefix##_72(void); INLINE void prefix##_73(void); \
+ INLINE void prefix##_74(void); INLINE void prefix##_75(void); INLINE void prefix##_76(void); INLINE void prefix##_77(void); \
+ INLINE void prefix##_78(void); INLINE void prefix##_79(void); INLINE void prefix##_7a(void); INLINE void prefix##_7b(void); \
+ INLINE void prefix##_7c(void); INLINE void prefix##_7d(void); INLINE void prefix##_7e(void); INLINE void prefix##_7f(void); \
+ INLINE void prefix##_80(void); INLINE void prefix##_81(void); INLINE void prefix##_82(void); INLINE void prefix##_83(void); \
+ INLINE void prefix##_84(void); INLINE void prefix##_85(void); INLINE void prefix##_86(void); INLINE void prefix##_87(void); \
+ INLINE void prefix##_88(void); INLINE void prefix##_89(void); INLINE void prefix##_8a(void); INLINE void prefix##_8b(void); \
+ INLINE void prefix##_8c(void); INLINE void prefix##_8d(void); INLINE void prefix##_8e(void); INLINE void prefix##_8f(void); \
+ INLINE void prefix##_90(void); INLINE void prefix##_91(void); INLINE void prefix##_92(void); INLINE void prefix##_93(void); \
+ INLINE void prefix##_94(void); INLINE void prefix##_95(void); INLINE void prefix##_96(void); INLINE void prefix##_97(void); \
+ INLINE void prefix##_98(void); INLINE void prefix##_99(void); INLINE void prefix##_9a(void); INLINE void prefix##_9b(void); \
+ INLINE void prefix##_9c(void); INLINE void prefix##_9d(void); INLINE void prefix##_9e(void); INLINE void prefix##_9f(void); \
+ INLINE void prefix##_a0(void); INLINE void prefix##_a1(void); INLINE void prefix##_a2(void); INLINE void prefix##_a3(void); \
+ INLINE void prefix##_a4(void); INLINE void prefix##_a5(void); INLINE void prefix##_a6(void); INLINE void prefix##_a7(void); \
+ INLINE void prefix##_a8(void); INLINE void prefix##_a9(void); INLINE void prefix##_aa(void); INLINE void prefix##_ab(void); \
+ INLINE void prefix##_ac(void); INLINE void prefix##_ad(void); INLINE void prefix##_ae(void); INLINE void prefix##_af(void); \
+ INLINE void prefix##_b0(void); INLINE void prefix##_b1(void); INLINE void prefix##_b2(void); INLINE void prefix##_b3(void); \
+ INLINE void prefix##_b4(void); INLINE void prefix##_b5(void); INLINE void prefix##_b6(void); INLINE void prefix##_b7(void); \
+ INLINE void prefix##_b8(void); INLINE void prefix##_b9(void); INLINE void prefix##_ba(void); INLINE void prefix##_bb(void); \
+ INLINE void prefix##_bc(void); INLINE void prefix##_bd(void); INLINE void prefix##_be(void); INLINE void prefix##_bf(void); \
+ INLINE void prefix##_c0(void); INLINE void prefix##_c1(void); INLINE void prefix##_c2(void); INLINE void prefix##_c3(void); \
+ INLINE void prefix##_c4(void); INLINE void prefix##_c5(void); INLINE void prefix##_c6(void); INLINE void prefix##_c7(void); \
+ INLINE void prefix##_c8(void); INLINE void prefix##_c9(void); INLINE void prefix##_ca(void); INLINE void prefix##_cb(void); \
+ INLINE void prefix##_cc(void); INLINE void prefix##_cd(void); INLINE void prefix##_ce(void); INLINE void prefix##_cf(void); \
+ INLINE void prefix##_d0(void); INLINE void prefix##_d1(void); INLINE void prefix##_d2(void); INLINE void prefix##_d3(void); \
+ INLINE void prefix##_d4(void); INLINE void prefix##_d5(void); INLINE void prefix##_d6(void); INLINE void prefix##_d7(void); \
+ INLINE void prefix##_d8(void); INLINE void prefix##_d9(void); INLINE void prefix##_da(void); INLINE void prefix##_db(void); \
+ INLINE void prefix##_dc(void); INLINE void prefix##_dd(void); INLINE void prefix##_de(void); INLINE void prefix##_df(void); \
+ INLINE void prefix##_e0(void); INLINE void prefix##_e1(void); INLINE void prefix##_e2(void); INLINE void prefix##_e3(void); \
+ INLINE void prefix##_e4(void); INLINE void prefix##_e5(void); INLINE void prefix##_e6(void); INLINE void prefix##_e7(void); \
+ INLINE void prefix##_e8(void); INLINE void prefix##_e9(void); INLINE void prefix##_ea(void); INLINE void prefix##_eb(void); \
+ INLINE void prefix##_ec(void); INLINE void prefix##_ed(void); INLINE void prefix##_ee(void); INLINE void prefix##_ef(void); \
+ INLINE void prefix##_f0(void); INLINE void prefix##_f1(void); INLINE void prefix##_f2(void); INLINE void prefix##_f3(void); \
+ INLINE void prefix##_f4(void); INLINE void prefix##_f5(void); INLINE void prefix##_f6(void); INLINE void prefix##_f7(void); \
+ INLINE void prefix##_f8(void); INLINE void prefix##_f9(void); INLINE void prefix##_fa(void); INLINE void prefix##_fb(void); \
+ INLINE void prefix##_fc(void); INLINE void prefix##_fd(void); INLINE void prefix##_fe(void); INLINE void prefix##_ff(void); \
+static void (*tablename[0x100])(void) = { \
+ prefix##_00,prefix##_01,prefix##_02,prefix##_03,prefix##_04,prefix##_05,prefix##_06,prefix##_07, \
+ prefix##_08,prefix##_09,prefix##_0a,prefix##_0b,prefix##_0c,prefix##_0d,prefix##_0e,prefix##_0f, \
+ prefix##_10,prefix##_11,prefix##_12,prefix##_13,prefix##_14,prefix##_15,prefix##_16,prefix##_17, \
+ prefix##_18,prefix##_19,prefix##_1a,prefix##_1b,prefix##_1c,prefix##_1d,prefix##_1e,prefix##_1f, \
+ prefix##_20,prefix##_21,prefix##_22,prefix##_23,prefix##_24,prefix##_25,prefix##_26,prefix##_27, \
+ prefix##_28,prefix##_29,prefix##_2a,prefix##_2b,prefix##_2c,prefix##_2d,prefix##_2e,prefix##_2f, \
+ prefix##_30,prefix##_31,prefix##_32,prefix##_33,prefix##_34,prefix##_35,prefix##_36,prefix##_37, \
+ prefix##_38,prefix##_39,prefix##_3a,prefix##_3b,prefix##_3c,prefix##_3d,prefix##_3e,prefix##_3f, \
+ prefix##_40,prefix##_41,prefix##_42,prefix##_43,prefix##_44,prefix##_45,prefix##_46,prefix##_47, \
+ prefix##_48,prefix##_49,prefix##_4a,prefix##_4b,prefix##_4c,prefix##_4d,prefix##_4e,prefix##_4f, \
+ prefix##_50,prefix##_51,prefix##_52,prefix##_53,prefix##_54,prefix##_55,prefix##_56,prefix##_57, \
+ prefix##_58,prefix##_59,prefix##_5a,prefix##_5b,prefix##_5c,prefix##_5d,prefix##_5e,prefix##_5f, \
+ prefix##_60,prefix##_61,prefix##_62,prefix##_63,prefix##_64,prefix##_65,prefix##_66,prefix##_67, \
+ prefix##_68,prefix##_69,prefix##_6a,prefix##_6b,prefix##_6c,prefix##_6d,prefix##_6e,prefix##_6f, \
+ prefix##_70,prefix##_71,prefix##_72,prefix##_73,prefix##_74,prefix##_75,prefix##_76,prefix##_77, \
+ prefix##_78,prefix##_79,prefix##_7a,prefix##_7b,prefix##_7c,prefix##_7d,prefix##_7e,prefix##_7f, \
+ prefix##_80,prefix##_81,prefix##_82,prefix##_83,prefix##_84,prefix##_85,prefix##_86,prefix##_87, \
+ prefix##_88,prefix##_89,prefix##_8a,prefix##_8b,prefix##_8c,prefix##_8d,prefix##_8e,prefix##_8f, \
+ prefix##_90,prefix##_91,prefix##_92,prefix##_93,prefix##_94,prefix##_95,prefix##_96,prefix##_97, \
+ prefix##_98,prefix##_99,prefix##_9a,prefix##_9b,prefix##_9c,prefix##_9d,prefix##_9e,prefix##_9f, \
+ prefix##_a0,prefix##_a1,prefix##_a2,prefix##_a3,prefix##_a4,prefix##_a5,prefix##_a6,prefix##_a7, \
+ prefix##_a8,prefix##_a9,prefix##_aa,prefix##_ab,prefix##_ac,prefix##_ad,prefix##_ae,prefix##_af, \
+ prefix##_b0,prefix##_b1,prefix##_b2,prefix##_b3,prefix##_b4,prefix##_b5,prefix##_b6,prefix##_b7, \
+ prefix##_b8,prefix##_b9,prefix##_ba,prefix##_bb,prefix##_bc,prefix##_bd,prefix##_be,prefix##_bf, \
+ prefix##_c0,prefix##_c1,prefix##_c2,prefix##_c3,prefix##_c4,prefix##_c5,prefix##_c6,prefix##_c7, \
+ prefix##_c8,prefix##_c9,prefix##_ca,prefix##_cb,prefix##_cc,prefix##_cd,prefix##_ce,prefix##_cf, \
+ prefix##_d0,prefix##_d1,prefix##_d2,prefix##_d3,prefix##_d4,prefix##_d5,prefix##_d6,prefix##_d7, \
+ prefix##_d8,prefix##_d9,prefix##_da,prefix##_db,prefix##_dc,prefix##_dd,prefix##_de,prefix##_df, \
+ prefix##_e0,prefix##_e1,prefix##_e2,prefix##_e3,prefix##_e4,prefix##_e5,prefix##_e6,prefix##_e7, \
+ prefix##_e8,prefix##_e9,prefix##_ea,prefix##_eb,prefix##_ec,prefix##_ed,prefix##_ee,prefix##_ef, \
+ prefix##_f0,prefix##_f1,prefix##_f2,prefix##_f3,prefix##_f4,prefix##_f5,prefix##_f6,prefix##_f7, \
+ prefix##_f8,prefix##_f9,prefix##_fa,prefix##_fb,prefix##_fc,prefix##_fd,prefix##_fe,prefix##_ff \
+}
+
+PROTOTYPES(Z180op,op);
+PROTOTYPES(Z180cb,cb);
+PROTOTYPES(Z180dd,dd);
+PROTOTYPES(Z180ed,ed);
+PROTOTYPES(Z180fd,fd);
+PROTOTYPES(Z180xycb,xycb);
+
+/***************************************************************
+ * define an opcode function
+ ***************************************************************/
+#define OP(prefix,opcode) INLINE void prefix##_##opcode(void)
+
+/***************************************************************
+ * adjust cycle count by n T-states
+ ***************************************************************/
+#define CC(prefix,opcode) z180_icount -= cc[Z180_TABLE_##prefix][opcode]
+
+/***************************************************************
+ * execute an opcode
+ ***************************************************************/
+#define EXEC(prefix,opcode) \
+{ \
+ unsigned op = opcode; \
+ CC(prefix,op); \
+ (*Z180##prefix[op])(); \
+}
+
+#if BIG_SWITCH
+#define EXEC_INLINE(prefix,opcode) \
+{ \
+ unsigned op = opcode; \
+ CC(prefix,op); \
+ switch(op) \
+ { \
+ case 0x00:prefix##_##00();break; case 0x01:prefix##_##01();break; case 0x02:prefix##_##02();break; case 0x03:prefix##_##03();break; \
+ case 0x04:prefix##_##04();break; case 0x05:prefix##_##05();break; case 0x06:prefix##_##06();break; case 0x07:prefix##_##07();break; \
+ case 0x08:prefix##_##08();break; case 0x09:prefix##_##09();break; case 0x0a:prefix##_##0a();break; case 0x0b:prefix##_##0b();break; \
+ case 0x0c:prefix##_##0c();break; case 0x0d:prefix##_##0d();break; case 0x0e:prefix##_##0e();break; case 0x0f:prefix##_##0f();break; \
+ case 0x10:prefix##_##10();break; case 0x11:prefix##_##11();break; case 0x12:prefix##_##12();break; case 0x13:prefix##_##13();break; \
+ case 0x14:prefix##_##14();break; case 0x15:prefix##_##15();break; case 0x16:prefix##_##16();break; case 0x17:prefix##_##17();break; \
+ case 0x18:prefix##_##18();break; case 0x19:prefix##_##19();break; case 0x1a:prefix##_##1a();break; case 0x1b:prefix##_##1b();break; \
+ case 0x1c:prefix##_##1c();break; case 0x1d:prefix##_##1d();break; case 0x1e:prefix##_##1e();break; case 0x1f:prefix##_##1f();break; \
+ case 0x20:prefix##_##20();break; case 0x21:prefix##_##21();break; case 0x22:prefix##_##22();break; case 0x23:prefix##_##23();break; \
+ case 0x24:prefix##_##24();break; case 0x25:prefix##_##25();break; case 0x26:prefix##_##26();break; case 0x27:prefix##_##27();break; \
+ case 0x28:prefix##_##28();break; case 0x29:prefix##_##29();break; case 0x2a:prefix##_##2a();break; case 0x2b:prefix##_##2b();break; \
+ case 0x2c:prefix##_##2c();break; case 0x2d:prefix##_##2d();break; case 0x2e:prefix##_##2e();break; case 0x2f:prefix##_##2f();break; \
+ case 0x30:prefix##_##30();break; case 0x31:prefix##_##31();break; case 0x32:prefix##_##32();break; case 0x33:prefix##_##33();break; \
+ case 0x34:prefix##_##34();break; case 0x35:prefix##_##35();break; case 0x36:prefix##_##36();break; case 0x37:prefix##_##37();break; \
+ case 0x38:prefix##_##38();break; case 0x39:prefix##_##39();break; case 0x3a:prefix##_##3a();break; case 0x3b:prefix##_##3b();break; \
+ case 0x3c:prefix##_##3c();break; case 0x3d:prefix##_##3d();break; case 0x3e:prefix##_##3e();break; case 0x3f:prefix##_##3f();break; \
+ case 0x40:prefix##_##40();break; case 0x41:prefix##_##41();break; case 0x42:prefix##_##42();break; case 0x43:prefix##_##43();break; \
+ case 0x44:prefix##_##44();break; case 0x45:prefix##_##45();break; case 0x46:prefix##_##46();break; case 0x47:prefix##_##47();break; \
+ case 0x48:prefix##_##48();break; case 0x49:prefix##_##49();break; case 0x4a:prefix##_##4a();break; case 0x4b:prefix##_##4b();break; \
+ case 0x4c:prefix##_##4c();break; case 0x4d:prefix##_##4d();break; case 0x4e:prefix##_##4e();break; case 0x4f:prefix##_##4f();break; \
+ case 0x50:prefix##_##50();break; case 0x51:prefix##_##51();break; case 0x52:prefix##_##52();break; case 0x53:prefix##_##53();break; \
+ case 0x54:prefix##_##54();break; case 0x55:prefix##_##55();break; case 0x56:prefix##_##56();break; case 0x57:prefix##_##57();break; \
+ case 0x58:prefix##_##58();break; case 0x59:prefix##_##59();break; case 0x5a:prefix##_##5a();break; case 0x5b:prefix##_##5b();break; \
+ case 0x5c:prefix##_##5c();break; case 0x5d:prefix##_##5d();break; case 0x5e:prefix##_##5e();break; case 0x5f:prefix##_##5f();break; \
+ case 0x60:prefix##_##60();break; case 0x61:prefix##_##61();break; case 0x62:prefix##_##62();break; case 0x63:prefix##_##63();break; \
+ case 0x64:prefix##_##64();break; case 0x65:prefix##_##65();break; case 0x66:prefix##_##66();break; case 0x67:prefix##_##67();break; \
+ case 0x68:prefix##_##68();break; case 0x69:prefix##_##69();break; case 0x6a:prefix##_##6a();break; case 0x6b:prefix##_##6b();break; \
+ case 0x6c:prefix##_##6c();break; case 0x6d:prefix##_##6d();break; case 0x6e:prefix##_##6e();break; case 0x6f:prefix##_##6f();break; \
+ case 0x70:prefix##_##70();break; case 0x71:prefix##_##71();break; case 0x72:prefix##_##72();break; case 0x73:prefix##_##73();break; \
+ case 0x74:prefix##_##74();break; case 0x75:prefix##_##75();break; case 0x76:prefix##_##76();break; case 0x77:prefix##_##77();break; \
+ case 0x78:prefix##_##78();break; case 0x79:prefix##_##79();break; case 0x7a:prefix##_##7a();break; case 0x7b:prefix##_##7b();break; \
+ case 0x7c:prefix##_##7c();break; case 0x7d:prefix##_##7d();break; case 0x7e:prefix##_##7e();break; case 0x7f:prefix##_##7f();break; \
+ case 0x80:prefix##_##80();break; case 0x81:prefix##_##81();break; case 0x82:prefix##_##82();break; case 0x83:prefix##_##83();break; \
+ case 0x84:prefix##_##84();break; case 0x85:prefix##_##85();break; case 0x86:prefix##_##86();break; case 0x87:prefix##_##87();break; \
+ case 0x88:prefix##_##88();break; case 0x89:prefix##_##89();break; case 0x8a:prefix##_##8a();break; case 0x8b:prefix##_##8b();break; \
+ case 0x8c:prefix##_##8c();break; case 0x8d:prefix##_##8d();break; case 0x8e:prefix##_##8e();break; case 0x8f:prefix##_##8f();break; \
+ case 0x90:prefix##_##90();break; case 0x91:prefix##_##91();break; case 0x92:prefix##_##92();break; case 0x93:prefix##_##93();break; \
+ case 0x94:prefix##_##94();break; case 0x95:prefix##_##95();break; case 0x96:prefix##_##96();break; case 0x97:prefix##_##97();break; \
+ case 0x98:prefix##_##98();break; case 0x99:prefix##_##99();break; case 0x9a:prefix##_##9a();break; case 0x9b:prefix##_##9b();break; \
+ case 0x9c:prefix##_##9c();break; case 0x9d:prefix##_##9d();break; case 0x9e:prefix##_##9e();break; case 0x9f:prefix##_##9f();break; \
+ case 0xa0:prefix##_##a0();break; case 0xa1:prefix##_##a1();break; case 0xa2:prefix##_##a2();break; case 0xa3:prefix##_##a3();break; \
+ case 0xa4:prefix##_##a4();break; case 0xa5:prefix##_##a5();break; case 0xa6:prefix##_##a6();break; case 0xa7:prefix##_##a7();break; \
+ case 0xa8:prefix##_##a8();break; case 0xa9:prefix##_##a9();break; case 0xaa:prefix##_##aa();break; case 0xab:prefix##_##ab();break; \
+ case 0xac:prefix##_##ac();break; case 0xad:prefix##_##ad();break; case 0xae:prefix##_##ae();break; case 0xaf:prefix##_##af();break; \
+ case 0xb0:prefix##_##b0();break; case 0xb1:prefix##_##b1();break; case 0xb2:prefix##_##b2();break; case 0xb3:prefix##_##b3();break; \
+ case 0xb4:prefix##_##b4();break; case 0xb5:prefix##_##b5();break; case 0xb6:prefix##_##b6();break; case 0xb7:prefix##_##b7();break; \
+ case 0xb8:prefix##_##b8();break; case 0xb9:prefix##_##b9();break; case 0xba:prefix##_##ba();break; case 0xbb:prefix##_##bb();break; \
+ case 0xbc:prefix##_##bc();break; case 0xbd:prefix##_##bd();break; case 0xbe:prefix##_##be();break; case 0xbf:prefix##_##bf();break; \
+ case 0xc0:prefix##_##c0();break; case 0xc1:prefix##_##c1();break; case 0xc2:prefix##_##c2();break; case 0xc3:prefix##_##c3();break; \
+ case 0xc4:prefix##_##c4();break; case 0xc5:prefix##_##c5();break; case 0xc6:prefix##_##c6();break; case 0xc7:prefix##_##c7();break; \
+ case 0xc8:prefix##_##c8();break; case 0xc9:prefix##_##c9();break; case 0xca:prefix##_##ca();break; case 0xcb:prefix##_##cb();break; \
+ case 0xcc:prefix##_##cc();break; case 0xcd:prefix##_##cd();break; case 0xce:prefix##_##ce();break; case 0xcf:prefix##_##cf();break; \
+ case 0xd0:prefix##_##d0();break; case 0xd1:prefix##_##d1();break; case 0xd2:prefix##_##d2();break; case 0xd3:prefix##_##d3();break; \
+ case 0xd4:prefix##_##d4();break; case 0xd5:prefix##_##d5();break; case 0xd6:prefix##_##d6();break; case 0xd7:prefix##_##d7();break; \
+ case 0xd8:prefix##_##d8();break; case 0xd9:prefix##_##d9();break; case 0xda:prefix##_##da();break; case 0xdb:prefix##_##db();break; \
+ case 0xdc:prefix##_##dc();break; case 0xdd:prefix##_##dd();break; case 0xde:prefix##_##de();break; case 0xdf:prefix##_##df();break; \
+ case 0xe0:prefix##_##e0();break; case 0xe1:prefix##_##e1();break; case 0xe2:prefix##_##e2();break; case 0xe3:prefix##_##e3();break; \
+ case 0xe4:prefix##_##e4();break; case 0xe5:prefix##_##e5();break; case 0xe6:prefix##_##e6();break; case 0xe7:prefix##_##e7();break; \
+ case 0xe8:prefix##_##e8();break; case 0xe9:prefix##_##e9();break; case 0xea:prefix##_##ea();break; case 0xeb:prefix##_##eb();break; \
+ case 0xec:prefix##_##ec();break; case 0xed:prefix##_##ed();break; case 0xee:prefix##_##ee();break; case 0xef:prefix##_##ef();break; \
+ case 0xf0:prefix##_##f0();break; case 0xf1:prefix##_##f1();break; case 0xf2:prefix##_##f2();break; case 0xf3:prefix##_##f3();break; \
+ case 0xf4:prefix##_##f4();break; case 0xf5:prefix##_##f5();break; case 0xf6:prefix##_##f6();break; case 0xf7:prefix##_##f7();break; \
+ case 0xf8:prefix##_##f8();break; case 0xf9:prefix##_##f9();break; case 0xfa:prefix##_##fa();break; case 0xfb:prefix##_##fb();break; \
+ case 0xfc:prefix##_##fc();break; case 0xfd:prefix##_##fd();break; case 0xfe:prefix##_##fe();break; case 0xff:prefix##_##ff();break; \
+ } \
+}
+#else
+#define EXEC_INLINE EXEC
+#endif
diff --git a/src/emu/cpu/z180/z180xy.c b/src/emu/cpu/z180/z180xy.c
new file mode 100644
index 00000000000..6ac5fce496b
--- /dev/null
+++ b/src/emu/cpu/z180/z180xy.c
@@ -0,0 +1,292 @@
+/**********************************************************
+* opcodes with DD/FD CB prefix
+* rotate, shift and bit operations with (IX+o)
+**********************************************************/
+OP(xycb,00) { _B = RLC( RM(EA) ); WM( EA,_B ); } /* RLC B=(XY+o) */
+OP(xycb,01) { _C = RLC( RM(EA) ); WM( EA,_C ); } /* RLC C=(XY+o) */
+OP(xycb,02) { _D = RLC( RM(EA) ); WM( EA,_D ); } /* RLC D=(XY+o) */
+OP(xycb,03) { _E = RLC( RM(EA) ); WM( EA,_E ); } /* RLC E=(XY+o) */
+OP(xycb,04) { _H = RLC( RM(EA) ); WM( EA,_H ); } /* RLC H=(XY+o) */
+OP(xycb,05) { _L = RLC( RM(EA) ); WM( EA,_L ); } /* RLC L=(XY+o) */
+OP(xycb,06) { WM( EA, RLC( RM(EA) ) ); } /* RLC (XY+o) */
+OP(xycb,07) { _A = RLC( RM(EA) ); WM( EA,_A ); } /* RLC A=(XY+o) */
+
+OP(xycb,08) { _B = RRC( RM(EA) ); WM( EA,_B ); } /* RRC B=(XY+o) */
+OP(xycb,09) { _C = RRC( RM(EA) ); WM( EA,_C ); } /* RRC C=(XY+o) */
+OP(xycb,0a) { _D = RRC( RM(EA) ); WM( EA,_D ); } /* RRC D=(XY+o) */
+OP(xycb,0b) { _E = RRC( RM(EA) ); WM( EA,_E ); } /* RRC E=(XY+o) */
+OP(xycb,0c) { _H = RRC( RM(EA) ); WM( EA,_H ); } /* RRC H=(XY+o) */
+OP(xycb,0d) { _L = RRC( RM(EA) ); WM( EA,_L ); } /* RRC L=(XY+o) */
+OP(xycb,0e) { WM( EA,RRC( RM(EA) ) ); } /* RRC (XY+o) */
+OP(xycb,0f) { _A = RRC( RM(EA) ); WM( EA,_A ); } /* RRC A=(XY+o) */
+
+OP(xycb,10) { _B = RL( RM(EA) ); WM( EA,_B ); } /* RL B=(XY+o) */
+OP(xycb,11) { _C = RL( RM(EA) ); WM( EA,_C ); } /* RL C=(XY+o) */
+OP(xycb,12) { _D = RL( RM(EA) ); WM( EA,_D ); } /* RL D=(XY+o) */
+OP(xycb,13) { _E = RL( RM(EA) ); WM( EA,_E ); } /* RL E=(XY+o) */
+OP(xycb,14) { _H = RL( RM(EA) ); WM( EA,_H ); } /* RL H=(XY+o) */
+OP(xycb,15) { _L = RL( RM(EA) ); WM( EA,_L ); } /* RL L=(XY+o) */
+OP(xycb,16) { WM( EA,RL( RM(EA) ) ); } /* RL (XY+o) */
+OP(xycb,17) { _A = RL( RM(EA) ); WM( EA,_A ); } /* RL A=(XY+o) */
+
+OP(xycb,18) { _B = RR( RM(EA) ); WM( EA,_B ); } /* RR B=(XY+o) */
+OP(xycb,19) { _C = RR( RM(EA) ); WM( EA,_C ); } /* RR C=(XY+o) */
+OP(xycb,1a) { _D = RR( RM(EA) ); WM( EA,_D ); } /* RR D=(XY+o) */
+OP(xycb,1b) { _E = RR( RM(EA) ); WM( EA,_E ); } /* RR E=(XY+o) */
+OP(xycb,1c) { _H = RR( RM(EA) ); WM( EA,_H ); } /* RR H=(XY+o) */
+OP(xycb,1d) { _L = RR( RM(EA) ); WM( EA,_L ); } /* RR L=(XY+o) */
+OP(xycb,1e) { WM( EA,RR( RM(EA) ) ); } /* RR (XY+o) */
+OP(xycb,1f) { _A = RR( RM(EA) ); WM( EA,_A ); } /* RR A=(XY+o) */
+
+OP(xycb,20) { _B = SLA( RM(EA) ); WM( EA,_B ); } /* SLA B=(XY+o) */
+OP(xycb,21) { _C = SLA( RM(EA) ); WM( EA,_C ); } /* SLA C=(XY+o) */
+OP(xycb,22) { _D = SLA( RM(EA) ); WM( EA,_D ); } /* SLA D=(XY+o) */
+OP(xycb,23) { _E = SLA( RM(EA) ); WM( EA,_E ); } /* SLA E=(XY+o) */
+OP(xycb,24) { _H = SLA( RM(EA) ); WM( EA,_H ); } /* SLA H=(XY+o) */
+OP(xycb,25) { _L = SLA( RM(EA) ); WM( EA,_L ); } /* SLA L=(XY+o) */
+OP(xycb,26) { WM( EA,SLA( RM(EA) ) ); } /* SLA (XY+o) */
+OP(xycb,27) { _A = SLA( RM(EA) ); WM( EA,_A ); } /* SLA A=(XY+o) */
+
+OP(xycb,28) { _B = SRA( RM(EA) ); WM( EA,_B ); } /* SRA B=(XY+o) */
+OP(xycb,29) { _C = SRA( RM(EA) ); WM( EA,_C ); } /* SRA C=(XY+o) */
+OP(xycb,2a) { _D = SRA( RM(EA) ); WM( EA,_D ); } /* SRA D=(XY+o) */
+OP(xycb,2b) { _E = SRA( RM(EA) ); WM( EA,_E ); } /* SRA E=(XY+o) */
+OP(xycb,2c) { _H = SRA( RM(EA) ); WM( EA,_H ); } /* SRA H=(XY+o) */
+OP(xycb,2d) { _L = SRA( RM(EA) ); WM( EA,_L ); } /* SRA L=(XY+o) */
+OP(xycb,2e) { WM( EA,SRA( RM(EA) ) ); } /* SRA (XY+o) */
+OP(xycb,2f) { _A = SRA( RM(EA) ); WM( EA,_A ); } /* SRA A=(XY+o) */
+
+OP(xycb,30) { _B = SLL( RM(EA) ); WM( EA,_B ); } /* SLL B=(XY+o) */
+OP(xycb,31) { _C = SLL( RM(EA) ); WM( EA,_C ); } /* SLL C=(XY+o) */
+OP(xycb,32) { _D = SLL( RM(EA) ); WM( EA,_D ); } /* SLL D=(XY+o) */
+OP(xycb,33) { _E = SLL( RM(EA) ); WM( EA,_E ); } /* SLL E=(XY+o) */
+OP(xycb,34) { _H = SLL( RM(EA) ); WM( EA,_H ); } /* SLL H=(XY+o) */
+OP(xycb,35) { _L = SLL( RM(EA) ); WM( EA,_L ); } /* SLL L=(XY+o) */
+OP(xycb,36) { WM( EA,SLL( RM(EA) ) ); } /* SLL (XY+o) */
+OP(xycb,37) { _A = SLL( RM(EA) ); WM( EA,_A ); } /* SLL A=(XY+o) */
+
+OP(xycb,38) { _B = SRL( RM(EA) ); WM( EA,_B ); } /* SRL B=(XY+o) */
+OP(xycb,39) { _C = SRL( RM(EA) ); WM( EA,_C ); } /* SRL C=(XY+o) */
+OP(xycb,3a) { _D = SRL( RM(EA) ); WM( EA,_D ); } /* SRL D=(XY+o) */
+OP(xycb,3b) { _E = SRL( RM(EA) ); WM( EA,_E ); } /* SRL E=(XY+o) */
+OP(xycb,3c) { _H = SRL( RM(EA) ); WM( EA,_H ); } /* SRL H=(XY+o) */
+OP(xycb,3d) { _L = SRL( RM(EA) ); WM( EA,_L ); } /* SRL L=(XY+o) */
+OP(xycb,3e) { WM( EA,SRL( RM(EA) ) ); } /* SRL (XY+o) */
+OP(xycb,3f) { _A = SRL( RM(EA) ); WM( EA,_A ); } /* SRL A=(XY+o) */
+
+OP(xycb,40) { xycb_46(); } /* BIT 0,B=(XY+o) */
+OP(xycb,41) { xycb_46(); } /* BIT 0,C=(XY+o) */
+OP(xycb,42) { xycb_46(); } /* BIT 0,D=(XY+o) */
+OP(xycb,43) { xycb_46(); } /* BIT 0,E=(XY+o) */
+OP(xycb,44) { xycb_46(); } /* BIT 0,H=(XY+o) */
+OP(xycb,45) { xycb_46(); } /* BIT 0,L=(XY+o) */
+OP(xycb,46) { BIT_XY(0,RM(EA)); } /* BIT 0,(XY+o) */
+OP(xycb,47) { xycb_46(); } /* BIT 0,A=(XY+o) */
+
+OP(xycb,48) { xycb_4e(); } /* BIT 1,B=(XY+o) */
+OP(xycb,49) { xycb_4e(); } /* BIT 1,C=(XY+o) */
+OP(xycb,4a) { xycb_4e(); } /* BIT 1,D=(XY+o) */
+OP(xycb,4b) { xycb_4e(); } /* BIT 1,E=(XY+o) */
+OP(xycb,4c) { xycb_4e(); } /* BIT 1,H=(XY+o) */
+OP(xycb,4d) { xycb_4e(); } /* BIT 1,L=(XY+o) */
+OP(xycb,4e) { BIT_XY(1,RM(EA)); } /* BIT 1,(XY+o) */
+OP(xycb,4f) { xycb_4e(); } /* BIT 1,A=(XY+o) */
+
+OP(xycb,50) { xycb_56(); } /* BIT 2,B=(XY+o) */
+OP(xycb,51) { xycb_56(); } /* BIT 2,C=(XY+o) */
+OP(xycb,52) { xycb_56(); } /* BIT 2,D=(XY+o) */
+OP(xycb,53) { xycb_56(); } /* BIT 2,E=(XY+o) */
+OP(xycb,54) { xycb_56(); } /* BIT 2,H=(XY+o) */
+OP(xycb,55) { xycb_56(); } /* BIT 2,L=(XY+o) */
+OP(xycb,56) { BIT_XY(2,RM(EA)); } /* BIT 2,(XY+o) */
+OP(xycb,57) { xycb_56(); } /* BIT 2,A=(XY+o) */
+
+OP(xycb,58) { xycb_5e(); } /* BIT 3,B=(XY+o) */
+OP(xycb,59) { xycb_5e(); } /* BIT 3,C=(XY+o) */
+OP(xycb,5a) { xycb_5e(); } /* BIT 3,D=(XY+o) */
+OP(xycb,5b) { xycb_5e(); } /* BIT 3,E=(XY+o) */
+OP(xycb,5c) { xycb_5e(); } /* BIT 3,H=(XY+o) */
+OP(xycb,5d) { xycb_5e(); } /* BIT 3,L=(XY+o) */
+OP(xycb,5e) { BIT_XY(3,RM(EA)); } /* BIT 3,(XY+o) */
+OP(xycb,5f) { xycb_5e(); } /* BIT 3,A=(XY+o) */
+
+OP(xycb,60) { xycb_66(); } /* BIT 4,B=(XY+o) */
+OP(xycb,61) { xycb_66(); } /* BIT 4,C=(XY+o) */
+OP(xycb,62) { xycb_66(); } /* BIT 4,D=(XY+o) */
+OP(xycb,63) { xycb_66(); } /* BIT 4,E=(XY+o) */
+OP(xycb,64) { xycb_66(); } /* BIT 4,H=(XY+o) */
+OP(xycb,65) { xycb_66(); } /* BIT 4,L=(XY+o) */
+OP(xycb,66) { BIT_XY(4,RM(EA)); } /* BIT 4,(XY+o) */
+OP(xycb,67) { xycb_66(); } /* BIT 4,A=(XY+o) */
+
+OP(xycb,68) { xycb_6e(); } /* BIT 5,B=(XY+o) */
+OP(xycb,69) { xycb_6e(); } /* BIT 5,C=(XY+o) */
+OP(xycb,6a) { xycb_6e(); } /* BIT 5,D=(XY+o) */
+OP(xycb,6b) { xycb_6e(); } /* BIT 5,E=(XY+o) */
+OP(xycb,6c) { xycb_6e(); } /* BIT 5,H=(XY+o) */
+OP(xycb,6d) { xycb_6e(); } /* BIT 5,L=(XY+o) */
+OP(xycb,6e) { BIT_XY(5,RM(EA)); } /* BIT 5,(XY+o) */
+OP(xycb,6f) { xycb_6e(); } /* BIT 5,A=(XY+o) */
+
+OP(xycb,70) { xycb_76(); } /* BIT 6,B=(XY+o) */
+OP(xycb,71) { xycb_76(); } /* BIT 6,C=(XY+o) */
+OP(xycb,72) { xycb_76(); } /* BIT 6,D=(XY+o) */
+OP(xycb,73) { xycb_76(); } /* BIT 6,E=(XY+o) */
+OP(xycb,74) { xycb_76(); } /* BIT 6,H=(XY+o) */
+OP(xycb,75) { xycb_76(); } /* BIT 6,L=(XY+o) */
+OP(xycb,76) { BIT_XY(6,RM(EA)); } /* BIT 6,(XY+o) */
+OP(xycb,77) { xycb_76(); } /* BIT 6,A=(XY+o) */
+
+OP(xycb,78) { xycb_7e(); } /* BIT 7,B=(XY+o) */
+OP(xycb,79) { xycb_7e(); } /* BIT 7,C=(XY+o) */
+OP(xycb,7a) { xycb_7e(); } /* BIT 7,D=(XY+o) */
+OP(xycb,7b) { xycb_7e(); } /* BIT 7,E=(XY+o) */
+OP(xycb,7c) { xycb_7e(); } /* BIT 7,H=(XY+o) */
+OP(xycb,7d) { xycb_7e(); } /* BIT 7,L=(XY+o) */
+OP(xycb,7e) { BIT_XY(7,RM(EA)); } /* BIT 7,(XY+o) */
+OP(xycb,7f) { xycb_7e(); } /* BIT 7,A=(XY+o) */
+
+OP(xycb,80) { _B = RES(0, RM(EA) ); WM( EA,_B ); } /* RES 0,B=(XY+o) */
+OP(xycb,81) { _C = RES(0, RM(EA) ); WM( EA,_C ); } /* RES 0,C=(XY+o) */
+OP(xycb,82) { _D = RES(0, RM(EA) ); WM( EA,_D ); } /* RES 0,D=(XY+o) */
+OP(xycb,83) { _E = RES(0, RM(EA) ); WM( EA,_E ); } /* RES 0,E=(XY+o) */
+OP(xycb,84) { _H = RES(0, RM(EA) ); WM( EA,_H ); } /* RES 0,H=(XY+o) */
+OP(xycb,85) { _L = RES(0, RM(EA) ); WM( EA,_L ); } /* RES 0,L=(XY+o) */
+OP(xycb,86) { WM( EA, RES(0,RM(EA)) ); } /* RES 0,(XY+o) */
+OP(xycb,87) { _A = RES(0, RM(EA) ); WM( EA,_A ); } /* RES 0,A=(XY+o) */
+
+OP(xycb,88) { _B = RES(1, RM(EA) ); WM( EA,_B ); } /* RES 1,B=(XY+o) */
+OP(xycb,89) { _C = RES(1, RM(EA) ); WM( EA,_C ); } /* RES 1,C=(XY+o) */
+OP(xycb,8a) { _D = RES(1, RM(EA) ); WM( EA,_D ); } /* RES 1,D=(XY+o) */
+OP(xycb,8b) { _E = RES(1, RM(EA) ); WM( EA,_E ); } /* RES 1,E=(XY+o) */
+OP(xycb,8c) { _H = RES(1, RM(EA) ); WM( EA,_H ); } /* RES 1,H=(XY+o) */
+OP(xycb,8d) { _L = RES(1, RM(EA) ); WM( EA,_L ); } /* RES 1,L=(XY+o) */
+OP(xycb,8e) { WM( EA, RES(1,RM(EA)) ); } /* RES 1,(XY+o) */
+OP(xycb,8f) { _A = RES(1, RM(EA) ); WM( EA,_A ); } /* RES 1,A=(XY+o) */
+
+OP(xycb,90) { _B = RES(2, RM(EA) ); WM( EA,_B ); } /* RES 2,B=(XY+o) */
+OP(xycb,91) { _C = RES(2, RM(EA) ); WM( EA,_C ); } /* RES 2,C=(XY+o) */
+OP(xycb,92) { _D = RES(2, RM(EA) ); WM( EA,_D ); } /* RES 2,D=(XY+o) */
+OP(xycb,93) { _E = RES(2, RM(EA) ); WM( EA,_E ); } /* RES 2,E=(XY+o) */
+OP(xycb,94) { _H = RES(2, RM(EA) ); WM( EA,_H ); } /* RES 2,H=(XY+o) */
+OP(xycb,95) { _L = RES(2, RM(EA) ); WM( EA,_L ); } /* RES 2,L=(XY+o) */
+OP(xycb,96) { WM( EA, RES(2,RM(EA)) ); } /* RES 2,(XY+o) */
+OP(xycb,97) { _A = RES(2, RM(EA) ); WM( EA,_A ); } /* RES 2,A=(XY+o) */
+
+OP(xycb,98) { _B = RES(3, RM(EA) ); WM( EA,_B ); } /* RES 3,B=(XY+o) */
+OP(xycb,99) { _C = RES(3, RM(EA) ); WM( EA,_C ); } /* RES 3,C=(XY+o) */
+OP(xycb,9a) { _D = RES(3, RM(EA) ); WM( EA,_D ); } /* RES 3,D=(XY+o) */
+OP(xycb,9b) { _E = RES(3, RM(EA) ); WM( EA,_E ); } /* RES 3,E=(XY+o) */
+OP(xycb,9c) { _H = RES(3, RM(EA) ); WM( EA,_H ); } /* RES 3,H=(XY+o) */
+OP(xycb,9d) { _L = RES(3, RM(EA) ); WM( EA,_L ); } /* RES 3,L=(XY+o) */
+OP(xycb,9e) { WM( EA, RES(3,RM(EA)) ); } /* RES 3,(XY+o) */
+OP(xycb,9f) { _A = RES(3, RM(EA) ); WM( EA,_A ); } /* RES 3,A=(XY+o) */
+
+OP(xycb,a0) { _B = RES(4, RM(EA) ); WM( EA,_B ); } /* RES 4,B=(XY+o) */
+OP(xycb,a1) { _C = RES(4, RM(EA) ); WM( EA,_C ); } /* RES 4,C=(XY+o) */
+OP(xycb,a2) { _D = RES(4, RM(EA) ); WM( EA,_D ); } /* RES 4,D=(XY+o) */
+OP(xycb,a3) { _E = RES(4, RM(EA) ); WM( EA,_E ); } /* RES 4,E=(XY+o) */
+OP(xycb,a4) { _H = RES(4, RM(EA) ); WM( EA,_H ); } /* RES 4,H=(XY+o) */
+OP(xycb,a5) { _L = RES(4, RM(EA) ); WM( EA,_L ); } /* RES 4,L=(XY+o) */
+OP(xycb,a6) { WM( EA, RES(4,RM(EA)) ); } /* RES 4,(XY+o) */
+OP(xycb,a7) { _A = RES(4, RM(EA) ); WM( EA,_A ); } /* RES 4,A=(XY+o) */
+
+OP(xycb,a8) { _B = RES(5, RM(EA) ); WM( EA,_B ); } /* RES 5,B=(XY+o) */
+OP(xycb,a9) { _C = RES(5, RM(EA) ); WM( EA,_C ); } /* RES 5,C=(XY+o) */
+OP(xycb,aa) { _D = RES(5, RM(EA) ); WM( EA,_D ); } /* RES 5,D=(XY+o) */
+OP(xycb,ab) { _E = RES(5, RM(EA) ); WM( EA,_E ); } /* RES 5,E=(XY+o) */
+OP(xycb,ac) { _H = RES(5, RM(EA) ); WM( EA,_H ); } /* RES 5,H=(XY+o) */
+OP(xycb,ad) { _L = RES(5, RM(EA) ); WM( EA,_L ); } /* RES 5,L=(XY+o) */
+OP(xycb,ae) { WM( EA, RES(5,RM(EA)) ); } /* RES 5,(XY+o) */
+OP(xycb,af) { _A = RES(5, RM(EA) ); WM( EA,_A ); } /* RES 5,A=(XY+o) */
+
+OP(xycb,b0) { _B = RES(6, RM(EA) ); WM( EA,_B ); } /* RES 6,B=(XY+o) */
+OP(xycb,b1) { _C = RES(6, RM(EA) ); WM( EA,_C ); } /* RES 6,C=(XY+o) */
+OP(xycb,b2) { _D = RES(6, RM(EA) ); WM( EA,_D ); } /* RES 6,D=(XY+o) */
+OP(xycb,b3) { _E = RES(6, RM(EA) ); WM( EA,_E ); } /* RES 6,E=(XY+o) */
+OP(xycb,b4) { _H = RES(6, RM(EA) ); WM( EA,_H ); } /* RES 6,H=(XY+o) */
+OP(xycb,b5) { _L = RES(6, RM(EA) ); WM( EA,_L ); } /* RES 6,L=(XY+o) */
+OP(xycb,b6) { WM( EA, RES(6,RM(EA)) ); } /* RES 6,(XY+o) */
+OP(xycb,b7) { _A = RES(6, RM(EA) ); WM( EA,_A ); } /* RES 6,A=(XY+o) */
+
+OP(xycb,b8) { _B = RES(7, RM(EA) ); WM( EA,_B ); } /* RES 7,B=(XY+o) */
+OP(xycb,b9) { _C = RES(7, RM(EA) ); WM( EA,_C ); } /* RES 7,C=(XY+o) */
+OP(xycb,ba) { _D = RES(7, RM(EA) ); WM( EA,_D ); } /* RES 7,D=(XY+o) */
+OP(xycb,bb) { _E = RES(7, RM(EA) ); WM( EA,_E ); } /* RES 7,E=(XY+o) */
+OP(xycb,bc) { _H = RES(7, RM(EA) ); WM( EA,_H ); } /* RES 7,H=(XY+o) */
+OP(xycb,bd) { _L = RES(7, RM(EA) ); WM( EA,_L ); } /* RES 7,L=(XY+o) */
+OP(xycb,be) { WM( EA, RES(7,RM(EA)) ); } /* RES 7,(XY+o) */
+OP(xycb,bf) { _A = RES(7, RM(EA) ); WM( EA,_A ); } /* RES 7,A=(XY+o) */
+
+OP(xycb,c0) { _B = SET(0, RM(EA) ); WM( EA,_B ); } /* SET 0,B=(XY+o) */
+OP(xycb,c1) { _C = SET(0, RM(EA) ); WM( EA,_C ); } /* SET 0,C=(XY+o) */
+OP(xycb,c2) { _D = SET(0, RM(EA) ); WM( EA,_D ); } /* SET 0,D=(XY+o) */
+OP(xycb,c3) { _E = SET(0, RM(EA) ); WM( EA,_E ); } /* SET 0,E=(XY+o) */
+OP(xycb,c4) { _H = SET(0, RM(EA) ); WM( EA,_H ); } /* SET 0,H=(XY+o) */
+OP(xycb,c5) { _L = SET(0, RM(EA) ); WM( EA,_L ); } /* SET 0,L=(XY+o) */
+OP(xycb,c6) { WM( EA, SET(0,RM(EA)) ); } /* SET 0,(XY+o) */
+OP(xycb,c7) { _A = SET(0, RM(EA) ); WM( EA,_A ); } /* SET 0,A=(XY+o) */
+
+OP(xycb,c8) { _B = SET(1, RM(EA) ); WM( EA,_B ); } /* SET 1,B=(XY+o) */
+OP(xycb,c9) { _C = SET(1, RM(EA) ); WM( EA,_C ); } /* SET 1,C=(XY+o) */
+OP(xycb,ca) { _D = SET(1, RM(EA) ); WM( EA,_D ); } /* SET 1,D=(XY+o) */
+OP(xycb,cb) { _E = SET(1, RM(EA) ); WM( EA,_E ); } /* SET 1,E=(XY+o) */
+OP(xycb,cc) { _H = SET(1, RM(EA) ); WM( EA,_H ); } /* SET 1,H=(XY+o) */
+OP(xycb,cd) { _L = SET(1, RM(EA) ); WM( EA,_L ); } /* SET 1,L=(XY+o) */
+OP(xycb,ce) { WM( EA, SET(1,RM(EA)) ); } /* SET 1,(XY+o) */
+OP(xycb,cf) { _A = SET(1, RM(EA) ); WM( EA,_A ); } /* SET 1,A=(XY+o) */
+
+OP(xycb,d0) { _B = SET(2, RM(EA) ); WM( EA,_B ); } /* SET 2,B=(XY+o) */
+OP(xycb,d1) { _C = SET(2, RM(EA) ); WM( EA,_C ); } /* SET 2,C=(XY+o) */
+OP(xycb,d2) { _D = SET(2, RM(EA) ); WM( EA,_D ); } /* SET 2,D=(XY+o) */
+OP(xycb,d3) { _E = SET(2, RM(EA) ); WM( EA,_E ); } /* SET 2,E=(XY+o) */
+OP(xycb,d4) { _H = SET(2, RM(EA) ); WM( EA,_H ); } /* SET 2,H=(XY+o) */
+OP(xycb,d5) { _L = SET(2, RM(EA) ); WM( EA,_L ); } /* SET 2,L=(XY+o) */
+OP(xycb,d6) { WM( EA, SET(2,RM(EA)) ); } /* SET 2,(XY+o) */
+OP(xycb,d7) { _A = SET(2, RM(EA) ); WM( EA,_A ); } /* SET 2,A=(XY+o) */
+
+OP(xycb,d8) { _B = SET(3, RM(EA) ); WM( EA,_B ); } /* SET 3,B=(XY+o) */
+OP(xycb,d9) { _C = SET(3, RM(EA) ); WM( EA,_C ); } /* SET 3,C=(XY+o) */
+OP(xycb,da) { _D = SET(3, RM(EA) ); WM( EA,_D ); } /* SET 3,D=(XY+o) */
+OP(xycb,db) { _E = SET(3, RM(EA) ); WM( EA,_E ); } /* SET 3,E=(XY+o) */
+OP(xycb,dc) { _H = SET(3, RM(EA) ); WM( EA,_H ); } /* SET 3,H=(XY+o) */
+OP(xycb,dd) { _L = SET(3, RM(EA) ); WM( EA,_L ); } /* SET 3,L=(XY+o) */
+OP(xycb,de) { WM( EA, SET(3,RM(EA)) ); } /* SET 3,(XY+o) */
+OP(xycb,df) { _A = SET(3, RM(EA) ); WM( EA,_A ); } /* SET 3,A=(XY+o) */
+
+OP(xycb,e0) { _B = SET(4, RM(EA) ); WM( EA,_B ); } /* SET 4,B=(XY+o) */
+OP(xycb,e1) { _C = SET(4, RM(EA) ); WM( EA,_C ); } /* SET 4,C=(XY+o) */
+OP(xycb,e2) { _D = SET(4, RM(EA) ); WM( EA,_D ); } /* SET 4,D=(XY+o) */
+OP(xycb,e3) { _E = SET(4, RM(EA) ); WM( EA,_E ); } /* SET 4,E=(XY+o) */
+OP(xycb,e4) { _H = SET(4, RM(EA) ); WM( EA,_H ); } /* SET 4,H=(XY+o) */
+OP(xycb,e5) { _L = SET(4, RM(EA) ); WM( EA,_L ); } /* SET 4,L=(XY+o) */
+OP(xycb,e6) { WM( EA, SET(4,RM(EA)) ); } /* SET 4,(XY+o) */
+OP(xycb,e7) { _A = SET(4, RM(EA) ); WM( EA,_A ); } /* SET 4,A=(XY+o) */
+
+OP(xycb,e8) { _B = SET(5, RM(EA) ); WM( EA,_B ); } /* SET 5,B=(XY+o) */
+OP(xycb,e9) { _C = SET(5, RM(EA) ); WM( EA,_C ); } /* SET 5,C=(XY+o) */
+OP(xycb,ea) { _D = SET(5, RM(EA) ); WM( EA,_D ); } /* SET 5,D=(XY+o) */
+OP(xycb,eb) { _E = SET(5, RM(EA) ); WM( EA,_E ); } /* SET 5,E=(XY+o) */
+OP(xycb,ec) { _H = SET(5, RM(EA) ); WM( EA,_H ); } /* SET 5,H=(XY+o) */
+OP(xycb,ed) { _L = SET(5, RM(EA) ); WM( EA,_L ); } /* SET 5,L=(XY+o) */
+OP(xycb,ee) { WM( EA, SET(5,RM(EA)) ); } /* SET 5,(XY+o) */
+OP(xycb,ef) { _A = SET(5, RM(EA) ); WM( EA,_A ); } /* SET 5,A=(XY+o) */
+
+OP(xycb,f0) { _B = SET(6, RM(EA) ); WM( EA,_B ); } /* SET 6,B=(XY+o) */
+OP(xycb,f1) { _C = SET(6, RM(EA) ); WM( EA,_C ); } /* SET 6,C=(XY+o) */
+OP(xycb,f2) { _D = SET(6, RM(EA) ); WM( EA,_D ); } /* SET 6,D=(XY+o) */
+OP(xycb,f3) { _E = SET(6, RM(EA) ); WM( EA,_E ); } /* SET 6,E=(XY+o) */
+OP(xycb,f4) { _H = SET(6, RM(EA) ); WM( EA,_H ); } /* SET 6,H=(XY+o) */
+OP(xycb,f5) { _L = SET(6, RM(EA) ); WM( EA,_L ); } /* SET 6,L=(XY+o) */
+OP(xycb,f6) { WM( EA, SET(6,RM(EA)) ); } /* SET 6,(XY+o) */
+OP(xycb,f7) { _A = SET(6, RM(EA) ); WM( EA,_A ); } /* SET 6,A=(XY+o) */
+
+OP(xycb,f8) { _B = SET(7, RM(EA) ); WM( EA,_B ); } /* SET 7,B=(XY+o) */
+OP(xycb,f9) { _C = SET(7, RM(EA) ); WM( EA,_C ); } /* SET 7,C=(XY+o) */
+OP(xycb,fa) { _D = SET(7, RM(EA) ); WM( EA,_D ); } /* SET 7,D=(XY+o) */
+OP(xycb,fb) { _E = SET(7, RM(EA) ); WM( EA,_E ); } /* SET 7,E=(XY+o) */
+OP(xycb,fc) { _H = SET(7, RM(EA) ); WM( EA,_H ); } /* SET 7,H=(XY+o) */
+OP(xycb,fd) { _L = SET(7, RM(EA) ); WM( EA,_L ); } /* SET 7,L=(XY+o) */
+OP(xycb,fe) { WM( EA, SET(7,RM(EA)) ); } /* SET 7,(XY+o) */
+OP(xycb,ff) { _A = SET(7, RM(EA) ); WM( EA,_A ); } /* SET 7,A=(XY+o) */
+
diff --git a/src/emu/cpu/z80/z80.c b/src/emu/cpu/z80/z80.c
new file mode 100644
index 00000000000..b91d4869960
--- /dev/null
+++ b/src/emu/cpu/z80/z80.c
@@ -0,0 +1,3818 @@
+/*****************************************************************************
+ *
+ * z80.c
+ * Portable Z80 emulator V3.5
+ *
+ * Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * Changes in 3.7 [Aaron Giles]
+ * - Changed NMI handling. NMIs are now latched in set_irq_state
+ * but are not taken there. Instead they are taken at the start of the
+ * execute loop.
+ * - Changed IRQ handling. IRQ state is set in set_irq_state but not taken
+ * except during the inner execute loop.
+ * - Removed x86 assembly hacks and obsolete timing loop catchers.
+ * Changes in 3.6
+ * - Got rid of the code that would inexactly emulate a Z80, i.e. removed
+ * all the #if Z80_EXACT #else branches.
+ * - Removed leading underscores from local register name shortcuts as
+ * this violates the C99 standard.
+ * - Renamed the registers inside the Z80 context to lower case to avoid
+ * ambiguities (shortcuts would have had the same names as the fields
+ * of the structure).
+ * Changes in 3.5
+ * - Implemented OTIR, INIR, etc. without look-up table for PF flag.
+ * [Ramsoft, Sean Young]
+ * Changes in 3.4
+ * - Removed Z80-MSX specific code as it's not needed any more.
+ * - Implemented DAA without look-up table [Ramsoft, Sean Young]
+ * Changes in 3.3
+ * - Fixed undocumented flags XF & YF in the non-asm versions of CP,
+ * and all the 16 bit arithmetic instructions. [Sean Young]
+ * Changes in 3.2
+ * - Fixed undocumented flags XF & YF of RRCA, and CF and HF of
+ * INI/IND/OUTI/OUTD/INIR/INDR/OTIR/OTDR [Sean Young]
+ * Changes in 3.1
+ * - removed the REPEAT_AT_ONCE execution of LDIR/CPIR etc. opcodes
+ * for readabilities sake and because the implementation was buggy
+ * (and I was not able to find the difference)
+ * Changes in 3.0
+ * - 'finished' switch to dynamically overrideable cycle count tables
+ * Changes in 2.9:
+ * - added methods to access and override the cycle count tables
+ * - fixed handling and timing of multiple DD/FD prefixed opcodes
+ * Changes in 2.8:
+ * - OUTI/OUTD/OTIR/OTDR also pre-decrement the B register now.
+ * This was wrong because of a bug fix on the wrong side
+ * (astrocade sound driver).
+ * Changes in 2.7:
+ * - removed z80_vm specific code, it's not needed (and never was).
+ * Changes in 2.6:
+ * - BUSY_LOOP_HACKS needed to call change_pc() earlier, before
+ * checking the opcodes at the new address, because otherwise they
+ * might access the old (wrong or even NULL) banked memory region.
+ * Thanks to Sean Young for finding this nasty bug.
+ * Changes in 2.5:
+ * - Burning cycles always adjusts the ICount by a multiple of 4.
+ * - In REPEAT_AT_ONCE cases the R register wasn't incremented twice
+ * per repetition as it should have been. Those repeated opcodes
+ * could also underflow the ICount.
+ * - Simplified TIME_LOOP_HACKS for BC and added two more for DE + HL
+ * timing loops. I think those hacks weren't endian safe before too.
+ * Changes in 2.4:
+ * - z80_reset zaps the entire context, sets IX and IY to 0xffff(!) and
+ * sets the Z flag. With these changes the Tehkan World Cup driver
+ * _seems_ to work again.
+ * Changes in 2.3:
+ * - External termination of the execution loop calls z80_burn() and
+ * z80_vm_burn() to burn an amount of cycles (R adjustment)
+ * - Shortcuts which burn CPU cycles (BUSY_LOOP_HACKS and TIME_LOOP_HACKS)
+ * now also adjust the R register depending on the skipped opcodes.
+ * Changes in 2.2:
+ * - Fixed bugs in CPL, SCF and CCF instructions flag handling.
+ * - Changed variable EA and ARG16() function to UINT32; this
+ * produces slightly more efficient code.
+ * - The DD/FD XY CB opcodes where XY is 40-7F and Y is not 6/E
+ * are changed to calls to the X6/XE opcodes to reduce object size.
+ * They're hardly ever used so this should not yield a speed penalty.
+ * New in 2.0:
+ * - Optional more exact Z80 emulation (#define Z80_EXACT 1) according
+ * to a detailed description by Sean Young which can be found at:
+ * http://www.msxnet.org/tech/z80-documented.pdf
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "z80.h"
+#include "z80daisy.h"
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+/* execute main opcodes inside a big switch statement */
+#ifndef BIG_SWITCH
+#define BIG_SWITCH 1
+#endif
+
+/* big flags array for ADD/ADC/SUB/SBC/CP results */
+#define BIG_FLAGS_ARRAY 1
+
+/* on JP and JR opcodes check for tight loops */
+#define BUSY_LOOP_HACKS 1
+
+
+/****************************************************************************/
+/* The Z80 registers. HALT is set to 1 when the CPU is halted, the refresh */
+/* register is calculated as follows: refresh=(Z80.r&127)|(Z80.r2&128) */
+/****************************************************************************/
+typedef struct
+{
+ PAIR prvpc,pc,sp,af,bc,de,hl,ix,iy;
+ PAIR af2,bc2,de2,hl2;
+ UINT8 r,r2,iff1,iff2,halt,im,i;
+ UINT8 nmi_state; /* nmi line state */
+ UINT8 nmi_pending; /* nmi pending */
+ UINT8 irq_state; /* irq line state */
+ UINT8 after_ei; /* are we in the EI shadow? */
+ const struct z80_irq_daisy_chain *daisy;
+ int (*irq_callback)(int irqline);
+} Z80_Regs;
+
+#define CF 0x01
+#define NF 0x02
+#define PF 0x04
+#define VF PF
+#define XF 0x08
+#define HF 0x10
+#define YF 0x20
+#define ZF 0x40
+#define SF 0x80
+
+#define INT_IRQ 0x01
+#define NMI_IRQ 0x02
+
+#define PRVPC Z80.prvpc.d /* previous program counter */
+
+#define PCD Z80.pc.d
+#define PC Z80.pc.w.l
+
+#define SPD Z80.sp.d
+#define SP Z80.sp.w.l
+
+#define AFD Z80.af.d
+#define AF Z80.af.w.l
+#define A Z80.af.b.h
+#define F Z80.af.b.l
+
+#define BCD Z80.bc.d
+#define BC Z80.bc.w.l
+#define B Z80.bc.b.h
+#define C Z80.bc.b.l
+
+#define DED Z80.de.d
+#define DE Z80.de.w.l
+#define D Z80.de.b.h
+#define E Z80.de.b.l
+
+#define HLD Z80.hl.d
+#define HL Z80.hl.w.l
+#define H Z80.hl.b.h
+#define L Z80.hl.b.l
+
+#define IXD Z80.ix.d
+#define IX Z80.ix.w.l
+#define HX Z80.ix.b.h
+#define LX Z80.ix.b.l
+
+#define IYD Z80.iy.d
+#define IY Z80.iy.w.l
+#define HY Z80.iy.b.h
+#define LY Z80.iy.b.l
+
+#define I Z80.i
+#define R Z80.r
+#define R2 Z80.r2
+#define IM Z80.im
+#define IFF1 Z80.iff1
+#define IFF2 Z80.iff2
+#define HALT Z80.halt
+
+static int z80_ICount;
+static Z80_Regs Z80;
+static UINT32 EA;
+
+static UINT8 SZ[256]; /* zero and sign flags */
+static UINT8 SZ_BIT[256]; /* zero, sign and parity/overflow (=zero) flags for BIT opcode */
+static UINT8 SZP[256]; /* zero, sign and parity flags */
+static UINT8 SZHV_inc[256]; /* zero, sign, half carry and overflow flags INC r8 */
+static UINT8 SZHV_dec[256]; /* zero, sign, half carry and overflow flags DEC r8 */
+
+#if BIG_FLAGS_ARRAY
+static UINT8 *SZHVC_add = 0;
+static UINT8 *SZHVC_sub = 0;
+#endif
+
+static const UINT8 cc_op[0x100] = {
+ 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4,
+ 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4,
+ 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4,
+ 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4,
+ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
+ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
+ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
+ 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4,
+ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
+ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
+ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
+ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
+ 5,10,10,10,10,11, 7,11, 5,10,10, 0,10,17, 7,11,
+ 5,10,10,11,10,11, 7,11, 5, 4,10,11,10, 0, 7,11,
+ 5,10,10,19,10,11, 7,11, 5, 4,10, 4,10, 0, 7,11,
+ 5,10,10, 4,10,11, 7,11, 5, 6,10, 4,10, 0, 7,11};
+
+static const UINT8 cc_cb[0x100] = {
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
+ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
+ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
+ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
+ 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8};
+
+static const UINT8 cc_ed[0x100] = {
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+12,12,15,20, 8,14, 8, 9,12,12,15,20, 8,14, 8, 9,
+12,12,15,20, 8,14, 8, 9,12,12,15,20, 8,14, 8, 9,
+12,12,15,20, 8,14, 8,18,12,12,15,20, 8,14, 8,18,
+12,12,15,20, 8,14, 8, 8,12,12,15,20, 8,14, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+16,16,16,16, 8, 8, 8, 8,16,16,16,16, 8, 8, 8, 8,
+16,16,16,16, 8, 8, 8, 8,16,16,16,16, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
+
+static const UINT8 cc_xy[0x100] = {
+ 4, 4, 4, 4, 4, 4, 4, 4, 4,15, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4,15, 4, 4, 4, 4, 4, 4,
+ 4,14,20,10, 9, 9, 9, 4, 4,15,20,10, 9, 9, 9, 4,
+ 4, 4, 4, 4,23,23,19, 4, 4,15, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
+ 4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
+ 9, 9, 9, 9, 9, 9,19, 9, 9, 9, 9, 9, 9, 9,19, 9,
+19,19,19,19,19,19, 4,19, 4, 4, 4, 4, 9, 9,19, 4,
+ 4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
+ 4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
+ 4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
+ 4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4,14, 4,23, 4,15, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4,10, 4, 4, 4, 4, 4, 4};
+
+static const UINT8 cc_xycb[0x100] = {
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
+20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
+20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
+20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23};
+
+/* extra cycles if jr/jp/call taken and 'interrupt latency' on rst 0-7 */
+static const UINT8 cc_ex[0x100] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DJNZ */
+ 5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, /* JR NZ/JR Z */
+ 5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, /* JR NC/JR C */
+ 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, 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,
+ 5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, /* LDIR/CPIR/INIR/OTIR LDDR/CPDR/INDR/OTDR */
+ 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2,
+ 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2,
+ 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2,
+ 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2};
+
+static const UINT8 *cc[6];
+#define Z80_TABLE_dd Z80_TABLE_xy
+#define Z80_TABLE_fd Z80_TABLE_xy
+
+static void take_interrupt(void);
+static void z80_burn(int cycles);
+
+typedef void (*funcptr)(void);
+
+#define PROTOTYPES(tablename,prefix) \
+ INLINE void prefix##_00(void); INLINE void prefix##_01(void); INLINE void prefix##_02(void); INLINE void prefix##_03(void); \
+ INLINE void prefix##_04(void); INLINE void prefix##_05(void); INLINE void prefix##_06(void); INLINE void prefix##_07(void); \
+ INLINE void prefix##_08(void); INLINE void prefix##_09(void); INLINE void prefix##_0a(void); INLINE void prefix##_0b(void); \
+ INLINE void prefix##_0c(void); INLINE void prefix##_0d(void); INLINE void prefix##_0e(void); INLINE void prefix##_0f(void); \
+ INLINE void prefix##_10(void); INLINE void prefix##_11(void); INLINE void prefix##_12(void); INLINE void prefix##_13(void); \
+ INLINE void prefix##_14(void); INLINE void prefix##_15(void); INLINE void prefix##_16(void); INLINE void prefix##_17(void); \
+ INLINE void prefix##_18(void); INLINE void prefix##_19(void); INLINE void prefix##_1a(void); INLINE void prefix##_1b(void); \
+ INLINE void prefix##_1c(void); INLINE void prefix##_1d(void); INLINE void prefix##_1e(void); INLINE void prefix##_1f(void); \
+ INLINE void prefix##_20(void); INLINE void prefix##_21(void); INLINE void prefix##_22(void); INLINE void prefix##_23(void); \
+ INLINE void prefix##_24(void); INLINE void prefix##_25(void); INLINE void prefix##_26(void); INLINE void prefix##_27(void); \
+ INLINE void prefix##_28(void); INLINE void prefix##_29(void); INLINE void prefix##_2a(void); INLINE void prefix##_2b(void); \
+ INLINE void prefix##_2c(void); INLINE void prefix##_2d(void); INLINE void prefix##_2e(void); INLINE void prefix##_2f(void); \
+ INLINE void prefix##_30(void); INLINE void prefix##_31(void); INLINE void prefix##_32(void); INLINE void prefix##_33(void); \
+ INLINE void prefix##_34(void); INLINE void prefix##_35(void); INLINE void prefix##_36(void); INLINE void prefix##_37(void); \
+ INLINE void prefix##_38(void); INLINE void prefix##_39(void); INLINE void prefix##_3a(void); INLINE void prefix##_3b(void); \
+ INLINE void prefix##_3c(void); INLINE void prefix##_3d(void); INLINE void prefix##_3e(void); INLINE void prefix##_3f(void); \
+ INLINE void prefix##_40(void); INLINE void prefix##_41(void); INLINE void prefix##_42(void); INLINE void prefix##_43(void); \
+ INLINE void prefix##_44(void); INLINE void prefix##_45(void); INLINE void prefix##_46(void); INLINE void prefix##_47(void); \
+ INLINE void prefix##_48(void); INLINE void prefix##_49(void); INLINE void prefix##_4a(void); INLINE void prefix##_4b(void); \
+ INLINE void prefix##_4c(void); INLINE void prefix##_4d(void); INLINE void prefix##_4e(void); INLINE void prefix##_4f(void); \
+ INLINE void prefix##_50(void); INLINE void prefix##_51(void); INLINE void prefix##_52(void); INLINE void prefix##_53(void); \
+ INLINE void prefix##_54(void); INLINE void prefix##_55(void); INLINE void prefix##_56(void); INLINE void prefix##_57(void); \
+ INLINE void prefix##_58(void); INLINE void prefix##_59(void); INLINE void prefix##_5a(void); INLINE void prefix##_5b(void); \
+ INLINE void prefix##_5c(void); INLINE void prefix##_5d(void); INLINE void prefix##_5e(void); INLINE void prefix##_5f(void); \
+ INLINE void prefix##_60(void); INLINE void prefix##_61(void); INLINE void prefix##_62(void); INLINE void prefix##_63(void); \
+ INLINE void prefix##_64(void); INLINE void prefix##_65(void); INLINE void prefix##_66(void); INLINE void prefix##_67(void); \
+ INLINE void prefix##_68(void); INLINE void prefix##_69(void); INLINE void prefix##_6a(void); INLINE void prefix##_6b(void); \
+ INLINE void prefix##_6c(void); INLINE void prefix##_6d(void); INLINE void prefix##_6e(void); INLINE void prefix##_6f(void); \
+ INLINE void prefix##_70(void); INLINE void prefix##_71(void); INLINE void prefix##_72(void); INLINE void prefix##_73(void); \
+ INLINE void prefix##_74(void); INLINE void prefix##_75(void); INLINE void prefix##_76(void); INLINE void prefix##_77(void); \
+ INLINE void prefix##_78(void); INLINE void prefix##_79(void); INLINE void prefix##_7a(void); INLINE void prefix##_7b(void); \
+ INLINE void prefix##_7c(void); INLINE void prefix##_7d(void); INLINE void prefix##_7e(void); INLINE void prefix##_7f(void); \
+ INLINE void prefix##_80(void); INLINE void prefix##_81(void); INLINE void prefix##_82(void); INLINE void prefix##_83(void); \
+ INLINE void prefix##_84(void); INLINE void prefix##_85(void); INLINE void prefix##_86(void); INLINE void prefix##_87(void); \
+ INLINE void prefix##_88(void); INLINE void prefix##_89(void); INLINE void prefix##_8a(void); INLINE void prefix##_8b(void); \
+ INLINE void prefix##_8c(void); INLINE void prefix##_8d(void); INLINE void prefix##_8e(void); INLINE void prefix##_8f(void); \
+ INLINE void prefix##_90(void); INLINE void prefix##_91(void); INLINE void prefix##_92(void); INLINE void prefix##_93(void); \
+ INLINE void prefix##_94(void); INLINE void prefix##_95(void); INLINE void prefix##_96(void); INLINE void prefix##_97(void); \
+ INLINE void prefix##_98(void); INLINE void prefix##_99(void); INLINE void prefix##_9a(void); INLINE void prefix##_9b(void); \
+ INLINE void prefix##_9c(void); INLINE void prefix##_9d(void); INLINE void prefix##_9e(void); INLINE void prefix##_9f(void); \
+ INLINE void prefix##_a0(void); INLINE void prefix##_a1(void); INLINE void prefix##_a2(void); INLINE void prefix##_a3(void); \
+ INLINE void prefix##_a4(void); INLINE void prefix##_a5(void); INLINE void prefix##_a6(void); INLINE void prefix##_a7(void); \
+ INLINE void prefix##_a8(void); INLINE void prefix##_a9(void); INLINE void prefix##_aa(void); INLINE void prefix##_ab(void); \
+ INLINE void prefix##_ac(void); INLINE void prefix##_ad(void); INLINE void prefix##_ae(void); INLINE void prefix##_af(void); \
+ INLINE void prefix##_b0(void); INLINE void prefix##_b1(void); INLINE void prefix##_b2(void); INLINE void prefix##_b3(void); \
+ INLINE void prefix##_b4(void); INLINE void prefix##_b5(void); INLINE void prefix##_b6(void); INLINE void prefix##_b7(void); \
+ INLINE void prefix##_b8(void); INLINE void prefix##_b9(void); INLINE void prefix##_ba(void); INLINE void prefix##_bb(void); \
+ INLINE void prefix##_bc(void); INLINE void prefix##_bd(void); INLINE void prefix##_be(void); INLINE void prefix##_bf(void); \
+ INLINE void prefix##_c0(void); INLINE void prefix##_c1(void); INLINE void prefix##_c2(void); INLINE void prefix##_c3(void); \
+ INLINE void prefix##_c4(void); INLINE void prefix##_c5(void); INLINE void prefix##_c6(void); INLINE void prefix##_c7(void); \
+ INLINE void prefix##_c8(void); INLINE void prefix##_c9(void); INLINE void prefix##_ca(void); INLINE void prefix##_cb(void); \
+ INLINE void prefix##_cc(void); INLINE void prefix##_cd(void); INLINE void prefix##_ce(void); INLINE void prefix##_cf(void); \
+ INLINE void prefix##_d0(void); INLINE void prefix##_d1(void); INLINE void prefix##_d2(void); INLINE void prefix##_d3(void); \
+ INLINE void prefix##_d4(void); INLINE void prefix##_d5(void); INLINE void prefix##_d6(void); INLINE void prefix##_d7(void); \
+ INLINE void prefix##_d8(void); INLINE void prefix##_d9(void); INLINE void prefix##_da(void); INLINE void prefix##_db(void); \
+ INLINE void prefix##_dc(void); INLINE void prefix##_dd(void); INLINE void prefix##_de(void); INLINE void prefix##_df(void); \
+ INLINE void prefix##_e0(void); INLINE void prefix##_e1(void); INLINE void prefix##_e2(void); INLINE void prefix##_e3(void); \
+ INLINE void prefix##_e4(void); INLINE void prefix##_e5(void); INLINE void prefix##_e6(void); INLINE void prefix##_e7(void); \
+ INLINE void prefix##_e8(void); INLINE void prefix##_e9(void); INLINE void prefix##_ea(void); INLINE void prefix##_eb(void); \
+ INLINE void prefix##_ec(void); INLINE void prefix##_ed(void); INLINE void prefix##_ee(void); INLINE void prefix##_ef(void); \
+ INLINE void prefix##_f0(void); INLINE void prefix##_f1(void); INLINE void prefix##_f2(void); INLINE void prefix##_f3(void); \
+ INLINE void prefix##_f4(void); INLINE void prefix##_f5(void); INLINE void prefix##_f6(void); INLINE void prefix##_f7(void); \
+ INLINE void prefix##_f8(void); INLINE void prefix##_f9(void); INLINE void prefix##_fa(void); INLINE void prefix##_fb(void); \
+ INLINE void prefix##_fc(void); INLINE void prefix##_fd(void); INLINE void prefix##_fe(void); INLINE void prefix##_ff(void); \
+static const funcptr tablename[0x100] = { \
+ prefix##_00,prefix##_01,prefix##_02,prefix##_03,prefix##_04,prefix##_05,prefix##_06,prefix##_07, \
+ prefix##_08,prefix##_09,prefix##_0a,prefix##_0b,prefix##_0c,prefix##_0d,prefix##_0e,prefix##_0f, \
+ prefix##_10,prefix##_11,prefix##_12,prefix##_13,prefix##_14,prefix##_15,prefix##_16,prefix##_17, \
+ prefix##_18,prefix##_19,prefix##_1a,prefix##_1b,prefix##_1c,prefix##_1d,prefix##_1e,prefix##_1f, \
+ prefix##_20,prefix##_21,prefix##_22,prefix##_23,prefix##_24,prefix##_25,prefix##_26,prefix##_27, \
+ prefix##_28,prefix##_29,prefix##_2a,prefix##_2b,prefix##_2c,prefix##_2d,prefix##_2e,prefix##_2f, \
+ prefix##_30,prefix##_31,prefix##_32,prefix##_33,prefix##_34,prefix##_35,prefix##_36,prefix##_37, \
+ prefix##_38,prefix##_39,prefix##_3a,prefix##_3b,prefix##_3c,prefix##_3d,prefix##_3e,prefix##_3f, \
+ prefix##_40,prefix##_41,prefix##_42,prefix##_43,prefix##_44,prefix##_45,prefix##_46,prefix##_47, \
+ prefix##_48,prefix##_49,prefix##_4a,prefix##_4b,prefix##_4c,prefix##_4d,prefix##_4e,prefix##_4f, \
+ prefix##_50,prefix##_51,prefix##_52,prefix##_53,prefix##_54,prefix##_55,prefix##_56,prefix##_57, \
+ prefix##_58,prefix##_59,prefix##_5a,prefix##_5b,prefix##_5c,prefix##_5d,prefix##_5e,prefix##_5f, \
+ prefix##_60,prefix##_61,prefix##_62,prefix##_63,prefix##_64,prefix##_65,prefix##_66,prefix##_67, \
+ prefix##_68,prefix##_69,prefix##_6a,prefix##_6b,prefix##_6c,prefix##_6d,prefix##_6e,prefix##_6f, \
+ prefix##_70,prefix##_71,prefix##_72,prefix##_73,prefix##_74,prefix##_75,prefix##_76,prefix##_77, \
+ prefix##_78,prefix##_79,prefix##_7a,prefix##_7b,prefix##_7c,prefix##_7d,prefix##_7e,prefix##_7f, \
+ prefix##_80,prefix##_81,prefix##_82,prefix##_83,prefix##_84,prefix##_85,prefix##_86,prefix##_87, \
+ prefix##_88,prefix##_89,prefix##_8a,prefix##_8b,prefix##_8c,prefix##_8d,prefix##_8e,prefix##_8f, \
+ prefix##_90,prefix##_91,prefix##_92,prefix##_93,prefix##_94,prefix##_95,prefix##_96,prefix##_97, \
+ prefix##_98,prefix##_99,prefix##_9a,prefix##_9b,prefix##_9c,prefix##_9d,prefix##_9e,prefix##_9f, \
+ prefix##_a0,prefix##_a1,prefix##_a2,prefix##_a3,prefix##_a4,prefix##_a5,prefix##_a6,prefix##_a7, \
+ prefix##_a8,prefix##_a9,prefix##_aa,prefix##_ab,prefix##_ac,prefix##_ad,prefix##_ae,prefix##_af, \
+ prefix##_b0,prefix##_b1,prefix##_b2,prefix##_b3,prefix##_b4,prefix##_b5,prefix##_b6,prefix##_b7, \
+ prefix##_b8,prefix##_b9,prefix##_ba,prefix##_bb,prefix##_bc,prefix##_bd,prefix##_be,prefix##_bf, \
+ prefix##_c0,prefix##_c1,prefix##_c2,prefix##_c3,prefix##_c4,prefix##_c5,prefix##_c6,prefix##_c7, \
+ prefix##_c8,prefix##_c9,prefix##_ca,prefix##_cb,prefix##_cc,prefix##_cd,prefix##_ce,prefix##_cf, \
+ prefix##_d0,prefix##_d1,prefix##_d2,prefix##_d3,prefix##_d4,prefix##_d5,prefix##_d6,prefix##_d7, \
+ prefix##_d8,prefix##_d9,prefix##_da,prefix##_db,prefix##_dc,prefix##_dd,prefix##_de,prefix##_df, \
+ prefix##_e0,prefix##_e1,prefix##_e2,prefix##_e3,prefix##_e4,prefix##_e5,prefix##_e6,prefix##_e7, \
+ prefix##_e8,prefix##_e9,prefix##_ea,prefix##_eb,prefix##_ec,prefix##_ed,prefix##_ee,prefix##_ef, \
+ prefix##_f0,prefix##_f1,prefix##_f2,prefix##_f3,prefix##_f4,prefix##_f5,prefix##_f6,prefix##_f7, \
+ prefix##_f8,prefix##_f9,prefix##_fa,prefix##_fb,prefix##_fc,prefix##_fd,prefix##_fe,prefix##_ff \
+}
+
+PROTOTYPES(Z80op,op);
+PROTOTYPES(Z80cb,cb);
+PROTOTYPES(Z80dd,dd);
+PROTOTYPES(Z80ed,ed);
+PROTOTYPES(Z80fd,fd);
+PROTOTYPES(Z80xycb,xycb);
+
+/****************************************************************************/
+/* Burn an odd amount of cycles, that is instructions taking something */
+/* different from 4 T-states per opcode (and R increment) */
+/****************************************************************************/
+INLINE void BURNODD(int cycles, int opcodes, int cyclesum)
+{
+ if( cycles > 0 )
+ {
+ R += (cycles / cyclesum) * opcodes;
+ z80_ICount -= (cycles / cyclesum) * cyclesum;
+ }
+}
+
+/***************************************************************
+ * define an opcode function
+ ***************************************************************/
+#define OP(prefix,opcode) INLINE void prefix##_##opcode(void)
+
+/***************************************************************
+ * adjust cycle count by n T-states
+ ***************************************************************/
+#define CC(prefix,opcode) z80_ICount -= cc[Z80_TABLE_##prefix][opcode]
+
+/***************************************************************
+ * execute an opcode
+ ***************************************************************/
+#define EXEC(prefix,opcode) \
+{ \
+ unsigned op = opcode; \
+ CC(prefix,op); \
+ (*Z80##prefix[op])(); \
+}
+
+#if BIG_SWITCH
+#define EXEC_INLINE(prefix,opcode) \
+{ \
+ unsigned op = opcode; \
+ CC(prefix,op); \
+ switch(op) \
+ { \
+ case 0x00:prefix##_##00();break; case 0x01:prefix##_##01();break; case 0x02:prefix##_##02();break; case 0x03:prefix##_##03();break; \
+ case 0x04:prefix##_##04();break; case 0x05:prefix##_##05();break; case 0x06:prefix##_##06();break; case 0x07:prefix##_##07();break; \
+ case 0x08:prefix##_##08();break; case 0x09:prefix##_##09();break; case 0x0a:prefix##_##0a();break; case 0x0b:prefix##_##0b();break; \
+ case 0x0c:prefix##_##0c();break; case 0x0d:prefix##_##0d();break; case 0x0e:prefix##_##0e();break; case 0x0f:prefix##_##0f();break; \
+ case 0x10:prefix##_##10();break; case 0x11:prefix##_##11();break; case 0x12:prefix##_##12();break; case 0x13:prefix##_##13();break; \
+ case 0x14:prefix##_##14();break; case 0x15:prefix##_##15();break; case 0x16:prefix##_##16();break; case 0x17:prefix##_##17();break; \
+ case 0x18:prefix##_##18();break; case 0x19:prefix##_##19();break; case 0x1a:prefix##_##1a();break; case 0x1b:prefix##_##1b();break; \
+ case 0x1c:prefix##_##1c();break; case 0x1d:prefix##_##1d();break; case 0x1e:prefix##_##1e();break; case 0x1f:prefix##_##1f();break; \
+ case 0x20:prefix##_##20();break; case 0x21:prefix##_##21();break; case 0x22:prefix##_##22();break; case 0x23:prefix##_##23();break; \
+ case 0x24:prefix##_##24();break; case 0x25:prefix##_##25();break; case 0x26:prefix##_##26();break; case 0x27:prefix##_##27();break; \
+ case 0x28:prefix##_##28();break; case 0x29:prefix##_##29();break; case 0x2a:prefix##_##2a();break; case 0x2b:prefix##_##2b();break; \
+ case 0x2c:prefix##_##2c();break; case 0x2d:prefix##_##2d();break; case 0x2e:prefix##_##2e();break; case 0x2f:prefix##_##2f();break; \
+ case 0x30:prefix##_##30();break; case 0x31:prefix##_##31();break; case 0x32:prefix##_##32();break; case 0x33:prefix##_##33();break; \
+ case 0x34:prefix##_##34();break; case 0x35:prefix##_##35();break; case 0x36:prefix##_##36();break; case 0x37:prefix##_##37();break; \
+ case 0x38:prefix##_##38();break; case 0x39:prefix##_##39();break; case 0x3a:prefix##_##3a();break; case 0x3b:prefix##_##3b();break; \
+ case 0x3c:prefix##_##3c();break; case 0x3d:prefix##_##3d();break; case 0x3e:prefix##_##3e();break; case 0x3f:prefix##_##3f();break; \
+ case 0x40:prefix##_##40();break; case 0x41:prefix##_##41();break; case 0x42:prefix##_##42();break; case 0x43:prefix##_##43();break; \
+ case 0x44:prefix##_##44();break; case 0x45:prefix##_##45();break; case 0x46:prefix##_##46();break; case 0x47:prefix##_##47();break; \
+ case 0x48:prefix##_##48();break; case 0x49:prefix##_##49();break; case 0x4a:prefix##_##4a();break; case 0x4b:prefix##_##4b();break; \
+ case 0x4c:prefix##_##4c();break; case 0x4d:prefix##_##4d();break; case 0x4e:prefix##_##4e();break; case 0x4f:prefix##_##4f();break; \
+ case 0x50:prefix##_##50();break; case 0x51:prefix##_##51();break; case 0x52:prefix##_##52();break; case 0x53:prefix##_##53();break; \
+ case 0x54:prefix##_##54();break; case 0x55:prefix##_##55();break; case 0x56:prefix##_##56();break; case 0x57:prefix##_##57();break; \
+ case 0x58:prefix##_##58();break; case 0x59:prefix##_##59();break; case 0x5a:prefix##_##5a();break; case 0x5b:prefix##_##5b();break; \
+ case 0x5c:prefix##_##5c();break; case 0x5d:prefix##_##5d();break; case 0x5e:prefix##_##5e();break; case 0x5f:prefix##_##5f();break; \
+ case 0x60:prefix##_##60();break; case 0x61:prefix##_##61();break; case 0x62:prefix##_##62();break; case 0x63:prefix##_##63();break; \
+ case 0x64:prefix##_##64();break; case 0x65:prefix##_##65();break; case 0x66:prefix##_##66();break; case 0x67:prefix##_##67();break; \
+ case 0x68:prefix##_##68();break; case 0x69:prefix##_##69();break; case 0x6a:prefix##_##6a();break; case 0x6b:prefix##_##6b();break; \
+ case 0x6c:prefix##_##6c();break; case 0x6d:prefix##_##6d();break; case 0x6e:prefix##_##6e();break; case 0x6f:prefix##_##6f();break; \
+ case 0x70:prefix##_##70();break; case 0x71:prefix##_##71();break; case 0x72:prefix##_##72();break; case 0x73:prefix##_##73();break; \
+ case 0x74:prefix##_##74();break; case 0x75:prefix##_##75();break; case 0x76:prefix##_##76();break; case 0x77:prefix##_##77();break; \
+ case 0x78:prefix##_##78();break; case 0x79:prefix##_##79();break; case 0x7a:prefix##_##7a();break; case 0x7b:prefix##_##7b();break; \
+ case 0x7c:prefix##_##7c();break; case 0x7d:prefix##_##7d();break; case 0x7e:prefix##_##7e();break; case 0x7f:prefix##_##7f();break; \
+ case 0x80:prefix##_##80();break; case 0x81:prefix##_##81();break; case 0x82:prefix##_##82();break; case 0x83:prefix##_##83();break; \
+ case 0x84:prefix##_##84();break; case 0x85:prefix##_##85();break; case 0x86:prefix##_##86();break; case 0x87:prefix##_##87();break; \
+ case 0x88:prefix##_##88();break; case 0x89:prefix##_##89();break; case 0x8a:prefix##_##8a();break; case 0x8b:prefix##_##8b();break; \
+ case 0x8c:prefix##_##8c();break; case 0x8d:prefix##_##8d();break; case 0x8e:prefix##_##8e();break; case 0x8f:prefix##_##8f();break; \
+ case 0x90:prefix##_##90();break; case 0x91:prefix##_##91();break; case 0x92:prefix##_##92();break; case 0x93:prefix##_##93();break; \
+ case 0x94:prefix##_##94();break; case 0x95:prefix##_##95();break; case 0x96:prefix##_##96();break; case 0x97:prefix##_##97();break; \
+ case 0x98:prefix##_##98();break; case 0x99:prefix##_##99();break; case 0x9a:prefix##_##9a();break; case 0x9b:prefix##_##9b();break; \
+ case 0x9c:prefix##_##9c();break; case 0x9d:prefix##_##9d();break; case 0x9e:prefix##_##9e();break; case 0x9f:prefix##_##9f();break; \
+ case 0xa0:prefix##_##a0();break; case 0xa1:prefix##_##a1();break; case 0xa2:prefix##_##a2();break; case 0xa3:prefix##_##a3();break; \
+ case 0xa4:prefix##_##a4();break; case 0xa5:prefix##_##a5();break; case 0xa6:prefix##_##a6();break; case 0xa7:prefix##_##a7();break; \
+ case 0xa8:prefix##_##a8();break; case 0xa9:prefix##_##a9();break; case 0xaa:prefix##_##aa();break; case 0xab:prefix##_##ab();break; \
+ case 0xac:prefix##_##ac();break; case 0xad:prefix##_##ad();break; case 0xae:prefix##_##ae();break; case 0xaf:prefix##_##af();break; \
+ case 0xb0:prefix##_##b0();break; case 0xb1:prefix##_##b1();break; case 0xb2:prefix##_##b2();break; case 0xb3:prefix##_##b3();break; \
+ case 0xb4:prefix##_##b4();break; case 0xb5:prefix##_##b5();break; case 0xb6:prefix##_##b6();break; case 0xb7:prefix##_##b7();break; \
+ case 0xb8:prefix##_##b8();break; case 0xb9:prefix##_##b9();break; case 0xba:prefix##_##ba();break; case 0xbb:prefix##_##bb();break; \
+ case 0xbc:prefix##_##bc();break; case 0xbd:prefix##_##bd();break; case 0xbe:prefix##_##be();break; case 0xbf:prefix##_##bf();break; \
+ case 0xc0:prefix##_##c0();break; case 0xc1:prefix##_##c1();break; case 0xc2:prefix##_##c2();break; case 0xc3:prefix##_##c3();break; \
+ case 0xc4:prefix##_##c4();break; case 0xc5:prefix##_##c5();break; case 0xc6:prefix##_##c6();break; case 0xc7:prefix##_##c7();break; \
+ case 0xc8:prefix##_##c8();break; case 0xc9:prefix##_##c9();break; case 0xca:prefix##_##ca();break; case 0xcb:prefix##_##cb();break; \
+ case 0xcc:prefix##_##cc();break; case 0xcd:prefix##_##cd();break; case 0xce:prefix##_##ce();break; case 0xcf:prefix##_##cf();break; \
+ case 0xd0:prefix##_##d0();break; case 0xd1:prefix##_##d1();break; case 0xd2:prefix##_##d2();break; case 0xd3:prefix##_##d3();break; \
+ case 0xd4:prefix##_##d4();break; case 0xd5:prefix##_##d5();break; case 0xd6:prefix##_##d6();break; case 0xd7:prefix##_##d7();break; \
+ case 0xd8:prefix##_##d8();break; case 0xd9:prefix##_##d9();break; case 0xda:prefix##_##da();break; case 0xdb:prefix##_##db();break; \
+ case 0xdc:prefix##_##dc();break; case 0xdd:prefix##_##dd();break; case 0xde:prefix##_##de();break; case 0xdf:prefix##_##df();break; \
+ case 0xe0:prefix##_##e0();break; case 0xe1:prefix##_##e1();break; case 0xe2:prefix##_##e2();break; case 0xe3:prefix##_##e3();break; \
+ case 0xe4:prefix##_##e4();break; case 0xe5:prefix##_##e5();break; case 0xe6:prefix##_##e6();break; case 0xe7:prefix##_##e7();break; \
+ case 0xe8:prefix##_##e8();break; case 0xe9:prefix##_##e9();break; case 0xea:prefix##_##ea();break; case 0xeb:prefix##_##eb();break; \
+ case 0xec:prefix##_##ec();break; case 0xed:prefix##_##ed();break; case 0xee:prefix##_##ee();break; case 0xef:prefix##_##ef();break; \
+ case 0xf0:prefix##_##f0();break; case 0xf1:prefix##_##f1();break; case 0xf2:prefix##_##f2();break; case 0xf3:prefix##_##f3();break; \
+ case 0xf4:prefix##_##f4();break; case 0xf5:prefix##_##f5();break; case 0xf6:prefix##_##f6();break; case 0xf7:prefix##_##f7();break; \
+ case 0xf8:prefix##_##f8();break; case 0xf9:prefix##_##f9();break; case 0xfa:prefix##_##fa();break; case 0xfb:prefix##_##fb();break; \
+ case 0xfc:prefix##_##fc();break; case 0xfd:prefix##_##fd();break; case 0xfe:prefix##_##fe();break; case 0xff:prefix##_##ff();break; \
+ } \
+}
+#else
+#define EXEC_INLINE EXEC
+#endif
+
+
+/***************************************************************
+ * Enter HALT state; write 1 to fake port on first execution
+ ***************************************************************/
+#define ENTER_HALT { \
+ PC--; \
+ HALT = 1; \
+ if( Z80.irq_state == CLEAR_LINE ) \
+ z80_burn( z80_ICount ); \
+}
+
+/***************************************************************
+ * Leave HALT state; write 0 to fake port
+ ***************************************************************/
+#define LEAVE_HALT { \
+ if( HALT ) \
+ { \
+ HALT = 0; \
+ PC++; \
+ } \
+}
+
+/***************************************************************
+ * Input a byte from given I/O port
+ ***************************************************************/
+#define IN(port) ((UINT8)io_read_byte_8(port))
+
+/***************************************************************
+ * Output a byte to given I/O port
+ ***************************************************************/
+#define OUT(port,value) io_write_byte_8(port,value)
+
+/***************************************************************
+ * Read a byte from given memory location
+ ***************************************************************/
+#define RM(addr) (UINT8)program_read_byte_8(addr)
+
+/***************************************************************
+ * Read a word from given memory location
+ ***************************************************************/
+INLINE void RM16( UINT32 addr, PAIR *r )
+{
+ r->b.l = RM(addr);
+ r->b.h = RM((addr+1)&0xffff);
+}
+
+/***************************************************************
+ * Write a byte to given memory location
+ ***************************************************************/
+#define WM(addr,value) program_write_byte_8(addr,value)
+
+/***************************************************************
+ * Write a word to given memory location
+ ***************************************************************/
+INLINE void WM16( UINT32 addr, PAIR *r )
+{
+ WM(addr,r->b.l);
+ WM((addr+1)&0xffff,r->b.h);
+}
+
+/***************************************************************
+ * ROP() is identical to RM() except it is used for
+ * reading opcodes. In case of system with memory mapped I/O,
+ * this function can be used to greatly speed up emulation
+ ***************************************************************/
+INLINE UINT8 ROP(void)
+{
+ unsigned pc = PCD;
+ PC++;
+ return cpu_readop(pc);
+}
+
+/****************************************************************
+ * ARG() is identical to ROP() except it is used
+ * for reading opcode arguments. This difference can be used to
+ * support systems that use different encoding mechanisms for
+ * opcodes and opcode arguments
+ ***************************************************************/
+INLINE UINT8 ARG(void)
+{
+ unsigned pc = PCD;
+ PC++;
+ return cpu_readop_arg(pc);
+}
+
+INLINE UINT32 ARG16(void)
+{
+ unsigned pc = PCD;
+ PC += 2;
+ return cpu_readop_arg(pc) | (cpu_readop_arg((pc+1)&0xffff) << 8);
+}
+
+/***************************************************************
+ * Calculate the effective address EA of an opcode using
+ * IX+offset resp. IY+offset addressing.
+ ***************************************************************/
+#define EAX EA = (UINT32)(UINT16)(IX + (INT8)ARG())
+#define EAY EA = (UINT32)(UINT16)(IY + (INT8)ARG())
+
+/***************************************************************
+ * POP
+ ***************************************************************/
+#define POP(DR) do { RM16( SPD, &Z80.DR ); SP += 2; } while (0)
+
+/***************************************************************
+ * PUSH
+ ***************************************************************/
+#define PUSH(SR) do { SP -= 2; WM16( SPD, &Z80.SR ); } while (0)
+
+/***************************************************************
+ * JP
+ ***************************************************************/
+#if BUSY_LOOP_HACKS
+#define JP { \
+ unsigned oldpc = PCD-1; \
+ PCD = ARG16(); \
+ change_pc(PCD); \
+ /* speed up busy loop */ \
+ if( PCD == oldpc ) \
+ { \
+ if( Z80.irq_state == CLEAR_LINE ) \
+ BURNODD( z80_ICount, 1, cc[Z80_TABLE_op][0xc3] ); \
+ } \
+ else \
+ { \
+ UINT8 op = cpu_readop(PCD); \
+ if( PCD == oldpc-1 ) \
+ { \
+ /* NOP - JP $-1 or EI - JP $-1 */ \
+ if ( op == 0x00 || op == 0xfb ) \
+ { \
+ if( Z80.irq_state == CLEAR_LINE ) \
+ BURNODD( z80_ICount-cc[Z80_TABLE_op][0x00], \
+ 2, cc[Z80_TABLE_op][0x00]+cc[Z80_TABLE_op][0xc3]); \
+ } \
+ } \
+ else \
+ /* LD SP,#xxxx - JP $-3 (Galaga) */ \
+ if( PCD == oldpc-3 && op == 0x31 ) \
+ { \
+ if( Z80.irq_state == CLEAR_LINE ) \
+ BURNODD( z80_ICount-cc[Z80_TABLE_op][0x31], \
+ 2, cc[Z80_TABLE_op][0x31]+cc[Z80_TABLE_op][0xc3]); \
+ } \
+ } \
+}
+#else
+#define JP { \
+ PCD = ARG16(); \
+ change_pc(PCD); \
+}
+#endif
+
+/***************************************************************
+ * JP_COND
+ ***************************************************************/
+
+#define JP_COND(cond) \
+ if( cond ) \
+ { \
+ PCD = ARG16(); \
+ change_pc(PCD); \
+ } \
+ else \
+ { \
+ PC += 2; \
+ }
+
+/***************************************************************
+ * JR
+ ***************************************************************/
+#define JR() \
+{ \
+ unsigned oldpc = PCD-1; \
+ INT8 arg = (INT8)ARG(); /* ARG() also increments PC */ \
+ PC += arg; /* so don't do PC += ARG() */ \
+ change_pc(PCD); \
+ /* speed up busy loop */ \
+ if( PCD == oldpc ) \
+ { \
+ if( Z80.irq_state == CLEAR_LINE ) \
+ BURNODD( z80_ICount, 1, cc[Z80_TABLE_op][0x18] ); \
+ } \
+ else \
+ { \
+ UINT8 op = cpu_readop(PCD); \
+ if( PCD == oldpc-1 ) \
+ { \
+ /* NOP - JR $-1 or EI - JR $-1 */ \
+ if ( op == 0x00 || op == 0xfb ) \
+ { \
+ if( Z80.irq_state == CLEAR_LINE ) \
+ BURNODD( z80_ICount-cc[Z80_TABLE_op][0x00], \
+ 2, cc[Z80_TABLE_op][0x00]+cc[Z80_TABLE_op][0x18]); \
+ } \
+ } \
+ else \
+ /* LD SP,#xxxx - JR $-3 */ \
+ if( PCD == oldpc-3 && op == 0x31 ) \
+ { \
+ if( Z80.irq_state == CLEAR_LINE ) \
+ BURNODD( z80_ICount-cc[Z80_TABLE_op][0x31], \
+ 2, cc[Z80_TABLE_op][0x31]+cc[Z80_TABLE_op][0x18]); \
+ } \
+ } \
+}
+
+/***************************************************************
+ * JR_COND
+ ***************************************************************/
+#define JR_COND(cond,opcode) \
+ if( cond ) \
+ { \
+ INT8 arg = (INT8)ARG(); /* ARG() also increments PC */ \
+ PC += arg; /* so don't do PC += ARG() */ \
+ CC(ex,opcode); \
+ change_pc(PCD); \
+ } \
+ else PC++; \
+
+/***************************************************************
+ * CALL
+ ***************************************************************/
+#define CALL() \
+ EA = ARG16(); \
+ PUSH( pc ); \
+ PCD = EA; \
+ change_pc(PCD)
+
+/***************************************************************
+ * CALL_COND
+ ***************************************************************/
+#define CALL_COND(cond,opcode) \
+ if( cond ) \
+ { \
+ EA = ARG16(); \
+ PUSH( pc ); \
+ PCD = EA; \
+ CC(ex,opcode); \
+ change_pc(PCD); \
+ } \
+ else \
+ { \
+ PC+=2; \
+ }
+
+/***************************************************************
+ * RET_COND
+ ***************************************************************/
+#define RET_COND(cond,opcode) \
+ if( cond ) \
+ { \
+ POP( pc ); \
+ change_pc(PCD); \
+ CC(ex,opcode); \
+ }
+
+/***************************************************************
+ * RETN
+ ***************************************************************/
+#define RETN { \
+ LOG(("Z80 #%d RETN IFF1:%d IFF2:%d\n", cpu_getactivecpu(), IFF1, IFF2)); \
+ POP( pc ); \
+ change_pc(PCD); \
+ IFF1 = IFF2; \
+}
+
+/***************************************************************
+ * RETI
+ ***************************************************************/
+#define RETI { \
+ POP( pc ); \
+ change_pc(PCD); \
+/* according to http://www.msxnet.org/tech/z80-documented.pdf */\
+ IFF1 = IFF2; \
+ if (Z80.daisy) \
+ z80daisy_call_reti_device(Z80.daisy); \
+}
+
+/***************************************************************
+ * LD R,A
+ ***************************************************************/
+#define LD_R_A { \
+ R = A; \
+ R2 = A & 0x80; /* keep bit 7 of R */ \
+}
+
+/***************************************************************
+ * LD A,R
+ ***************************************************************/
+#define LD_A_R { \
+ A = (R & 0x7f) | R2; \
+ F = (F & CF) | SZ[A] | ( IFF2 << 2 ); \
+}
+
+/***************************************************************
+ * LD I,A
+ ***************************************************************/
+#define LD_I_A { \
+ I = A; \
+}
+
+/***************************************************************
+ * LD A,I
+ ***************************************************************/
+#define LD_A_I { \
+ A = I; \
+ F = (F & CF) | SZ[A] | ( IFF2 << 2 ); \
+}
+
+/***************************************************************
+ * RST
+ ***************************************************************/
+#define RST(addr) \
+ PUSH( pc ); \
+ PCD = addr; \
+ change_pc(PCD)
+
+/***************************************************************
+ * INC r8
+ ***************************************************************/
+INLINE UINT8 INC(UINT8 value)
+{
+ UINT8 res = value + 1;
+ F = (F & CF) | SZHV_inc[res];
+ return (UINT8)res;
+}
+
+/***************************************************************
+ * DEC r8
+ ***************************************************************/
+INLINE UINT8 DEC(UINT8 value)
+{
+ UINT8 res = value - 1;
+ F = (F & CF) | SZHV_dec[res];
+ return res;
+}
+
+/***************************************************************
+ * RLCA
+ ***************************************************************/
+#define RLCA \
+ A = (A << 1) | (A >> 7); \
+ F = (F & (SF | ZF | PF)) | (A & (YF | XF | CF))
+
+/***************************************************************
+ * RRCA
+ ***************************************************************/
+#define RRCA \
+ F = (F & (SF | ZF | PF)) | (A & CF); \
+ A = (A >> 1) | (A << 7); \
+ F |= (A & (YF | XF) )
+
+/***************************************************************
+ * RLA
+ ***************************************************************/
+#define RLA { \
+ UINT8 res = (A << 1) | (F & CF); \
+ UINT8 c = (A & 0x80) ? CF : 0; \
+ F = (F & (SF | ZF | PF)) | c | (res & (YF | XF)); \
+ A = res; \
+}
+
+/***************************************************************
+ * RRA
+ ***************************************************************/
+#define RRA { \
+ UINT8 res = (A >> 1) | (F << 7); \
+ UINT8 c = (A & 0x01) ? CF : 0; \
+ F = (F & (SF | ZF | PF)) | c | (res & (YF | XF)); \
+ A = res; \
+}
+
+/***************************************************************
+ * RRD
+ ***************************************************************/
+#define RRD { \
+ UINT8 n = RM(HL); \
+ WM( HL, (n >> 4) | (A << 4) ); \
+ A = (A & 0xf0) | (n & 0x0f); \
+ F = (F & CF) | SZP[A]; \
+}
+
+/***************************************************************
+ * RLD
+ ***************************************************************/
+#define RLD { \
+ UINT8 n = RM(HL); \
+ WM( HL, (n << 4) | (A & 0x0f) ); \
+ A = (A & 0xf0) | (n >> 4); \
+ F = (F & CF) | SZP[A]; \
+}
+
+/***************************************************************
+ * ADD A,n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define ADD(value) \
+{ \
+ UINT32 ah = AFD & 0xff00; \
+ UINT32 res = (UINT8)((ah >> 8) + value); \
+ F = SZHVC_add[ah | res]; \
+ A = res; \
+}
+#else
+#define ADD(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = A + val; \
+ F = SZ[(UINT8)res] | ((res >> 8) & CF) | \
+ ((A ^ res ^ val) & HF) | \
+ (((val ^ A ^ 0x80) & (val ^ res) & 0x80) >> 5); \
+ A = (UINT8)res; \
+}
+#endif
+
+/***************************************************************
+ * ADC A,n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define ADC(value) \
+{ \
+ UINT32 ah = AFD & 0xff00, c = AFD & 1; \
+ UINT32 res = (UINT8)((ah >> 8) + value + c); \
+ F = SZHVC_add[(c << 16) | ah | res]; \
+ A = res; \
+}
+#else
+#define ADC(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = A + val + (F & CF); \
+ F = SZ[res & 0xff] | ((res >> 8) & CF) | \
+ ((A ^ res ^ val) & HF) | \
+ (((val ^ A ^ 0x80) & (val ^ res) & 0x80) >> 5); \
+ A = res; \
+}
+#endif
+
+/***************************************************************
+ * SUB n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define SUB(value) \
+{ \
+ UINT32 ah = AFD & 0xff00; \
+ UINT32 res = (UINT8)((ah >> 8) - value); \
+ F = SZHVC_sub[ah | res]; \
+ A = res; \
+}
+#else
+#define SUB(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = A - val; \
+ F = SZ[res & 0xff] | ((res >> 8) & CF) | NF | \
+ ((A ^ res ^ val) & HF) | \
+ (((val ^ A) & (A ^ res) & 0x80) >> 5); \
+ A = res; \
+}
+#endif
+
+/***************************************************************
+ * SBC A,n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define SBC(value) \
+{ \
+ UINT32 ah = AFD & 0xff00, c = AFD & 1; \
+ UINT32 res = (UINT8)((ah >> 8) - value - c); \
+ F = SZHVC_sub[(c<<16) | ah | res]; \
+ A = res; \
+}
+#else
+#define SBC(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = A - val - (F & CF); \
+ F = SZ[res & 0xff] | ((res >> 8) & CF) | NF | \
+ ((A ^ res ^ val) & HF) | \
+ (((val ^ A) & (A ^ res) & 0x80) >> 5); \
+ A = res; \
+}
+#endif
+
+/***************************************************************
+ * NEG
+ ***************************************************************/
+#define NEG { \
+ UINT8 value = A; \
+ A = 0; \
+ SUB(value); \
+}
+
+/***************************************************************
+ * DAA
+ ***************************************************************/
+#define DAA { \
+ UINT8 cf, nf, hf, lo, hi, diff; \
+ cf = F & CF; \
+ nf = F & NF; \
+ hf = F & HF; \
+ lo = A & 15; \
+ hi = A / 16; \
+ \
+ if (cf) \
+ { \
+ diff = (lo <= 9 && !hf) ? 0x60 : 0x66; \
+ } \
+ else \
+ { \
+ if (lo >= 10) \
+ { \
+ diff = hi <= 8 ? 0x06 : 0x66; \
+ } \
+ else \
+ { \
+ if (hi >= 10) \
+ { \
+ diff = hf ? 0x66 : 0x60; \
+ } \
+ else \
+ { \
+ diff = hf ? 0x06 : 0x00; \
+ } \
+ } \
+ } \
+ if (nf) A -= diff; \
+ else A += diff; \
+ \
+ F = SZP[A] | (F & NF); \
+ if (cf || (lo <= 9 ? hi >= 10 : hi >= 9)) F |= CF; \
+ if (nf ? hf && lo <= 5 : lo >= 10) F |= HF; \
+}
+
+/***************************************************************
+ * AND n
+ ***************************************************************/
+#define AND(value) \
+ A &= value; \
+ F = SZP[A] | HF
+
+/***************************************************************
+ * OR n
+ ***************************************************************/
+#define OR(value) \
+ A |= value; \
+ F = SZP[A]
+
+/***************************************************************
+ * XOR n
+ ***************************************************************/
+#define XOR(value) \
+ A ^= value; \
+ F = SZP[A]
+
+/***************************************************************
+ * CP n
+ ***************************************************************/
+#if BIG_FLAGS_ARRAY
+#define CP(value) \
+{ \
+ unsigned val = value; \
+ UINT32 ah = AFD & 0xff00; \
+ UINT32 res = (UINT8)((ah >> 8) - val); \
+ F = (SZHVC_sub[ah | res] & ~(YF | XF)) | \
+ (val & (YF | XF)); \
+}
+#else
+#define CP(value) \
+{ \
+ unsigned val = value; \
+ unsigned res = A - val; \
+ F = (SZ[res & 0xff] & (SF | ZF)) | \
+ (val & (YF | XF)) | ((res >> 8) & CF) | NF | \
+ ((A ^ res ^ val) & HF) | \
+ ((((val ^ A) & (A ^ res)) >> 5) & VF); \
+}
+#endif
+
+/***************************************************************
+ * EX AF,AF'
+ ***************************************************************/
+#define EX_AF { \
+ PAIR tmp; \
+ tmp = Z80.af; Z80.af = Z80.af2; Z80.af2 = tmp; \
+}
+
+/***************************************************************
+ * EX DE,HL
+ ***************************************************************/
+#define EX_DE_HL { \
+ PAIR tmp; \
+ tmp = Z80.de; Z80.de = Z80.hl; Z80.hl = tmp; \
+}
+
+/***************************************************************
+ * EXX
+ ***************************************************************/
+#define EXX { \
+ PAIR tmp; \
+ tmp = Z80.bc; Z80.bc = Z80.bc2; Z80.bc2 = tmp; \
+ tmp = Z80.de; Z80.de = Z80.de2; Z80.de2 = tmp; \
+ tmp = Z80.hl; Z80.hl = Z80.hl2; Z80.hl2 = tmp; \
+}
+
+/***************************************************************
+ * EX (SP),r16
+ ***************************************************************/
+#define EXSP(DR) \
+{ \
+ PAIR tmp = { { 0, 0, 0, 0 } }; \
+ RM16( SPD, &tmp ); \
+ WM16( SPD, &Z80.DR ); \
+ Z80.DR = tmp; \
+}
+
+
+/***************************************************************
+ * ADD16
+ ***************************************************************/
+#define ADD16(DR,SR) \
+{ \
+ UINT32 res = Z80.DR.d + Z80.SR.d; \
+ F = (F & (SF | ZF | VF)) | \
+ (((Z80.DR.d ^ res ^ Z80.SR.d) >> 8) & HF) | \
+ ((res >> 16) & CF) | ((res >> 8) & (YF | XF)); \
+ Z80.DR.w.l = (UINT16)res; \
+}
+
+/***************************************************************
+ * ADC r16,r16
+ ***************************************************************/
+#define ADC16(Reg) \
+{ \
+ UINT32 res = HLD + Z80.Reg.d + (F & CF); \
+ F = (((HLD ^ res ^ Z80.Reg.d) >> 8) & HF) | \
+ ((res >> 16) & CF) | \
+ ((res >> 8) & (SF | YF | XF)) | \
+ ((res & 0xffff) ? 0 : ZF) | \
+ (((Z80.Reg.d ^ HLD ^ 0x8000) & (Z80.Reg.d ^ res) & 0x8000) >> 13); \
+ HL = (UINT16)res; \
+}
+
+/***************************************************************
+ * SBC r16,r16
+ ***************************************************************/
+#define SBC16(Reg) \
+{ \
+ UINT32 res = HLD - Z80.Reg.d - (F & CF); \
+ F = (((HLD ^ res ^ Z80.Reg.d) >> 8) & HF) | NF | \
+ ((res >> 16) & CF) | \
+ ((res >> 8) & (SF | YF | XF)) | \
+ ((res & 0xffff) ? 0 : ZF) | \
+ (((Z80.Reg.d ^ HLD) & (HLD ^ res) &0x8000) >> 13); \
+ HL = (UINT16)res; \
+}
+
+/***************************************************************
+ * RLC r8
+ ***************************************************************/
+INLINE UINT8 RLC(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x80) ? CF : 0;
+ res = ((res << 1) | (res >> 7)) & 0xff;
+ F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * RRC r8
+ ***************************************************************/
+INLINE UINT8 RRC(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x01) ? CF : 0;
+ res = ((res >> 1) | (res << 7)) & 0xff;
+ F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * RL r8
+ ***************************************************************/
+INLINE UINT8 RL(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x80) ? CF : 0;
+ res = ((res << 1) | (F & CF)) & 0xff;
+ F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * RR r8
+ ***************************************************************/
+INLINE UINT8 RR(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x01) ? CF : 0;
+ res = ((res >> 1) | (F << 7)) & 0xff;
+ F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * SLA r8
+ ***************************************************************/
+INLINE UINT8 SLA(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x80) ? CF : 0;
+ res = (res << 1) & 0xff;
+ F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * SRA r8
+ ***************************************************************/
+INLINE UINT8 SRA(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x01) ? CF : 0;
+ res = ((res >> 1) | (res & 0x80)) & 0xff;
+ F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * SLL r8
+ ***************************************************************/
+INLINE UINT8 SLL(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x80) ? CF : 0;
+ res = ((res << 1) | 0x01) & 0xff;
+ F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * SRL r8
+ ***************************************************************/
+INLINE UINT8 SRL(UINT8 value)
+{
+ unsigned res = value;
+ unsigned c = (res & 0x01) ? CF : 0;
+ res = (res >> 1) & 0xff;
+ F = SZP[res] | c;
+ return res;
+}
+
+/***************************************************************
+ * BIT bit,r8
+ ***************************************************************/
+#undef BIT
+#define BIT(bit,reg) \
+ F = (F & CF) | HF | SZ_BIT[reg & (1<<bit)]
+
+/***************************************************************
+ * BIT bit,(IX/Y+o)
+ ***************************************************************/
+
+#define BIT_XY(bit,reg) \
+ F = (F & CF) | HF | (SZ_BIT[reg & (1<<bit)] & ~(YF|XF)) | ((EA>>8) & (YF|XF))
+
+/***************************************************************
+ * RES bit,r8
+ ***************************************************************/
+INLINE UINT8 RES(UINT8 bit, UINT8 value)
+{
+ return value & ~(1<<bit);
+}
+
+/***************************************************************
+ * SET bit,r8
+ ***************************************************************/
+INLINE UINT8 SET(UINT8 bit, UINT8 value)
+{
+ return value | (1<<bit);
+}
+
+/***************************************************************
+ * LDI
+ ***************************************************************/
+#define LDI { \
+ UINT8 io = RM(HL); \
+ WM( DE, io ); \
+ F &= SF | ZF | CF; \
+ if( (A + io) & 0x02 ) F |= YF; /* bit 1 -> flag 5 */ \
+ if( (A + io) & 0x08 ) F |= XF; /* bit 3 -> flag 3 */ \
+ HL++; DE++; BC--; \
+ if( BC ) F |= VF; \
+}
+
+/***************************************************************
+ * CPI
+ ***************************************************************/
+#define CPI { \
+ UINT8 val = RM(HL); \
+ UINT8 res = A - val; \
+ HL++; BC--; \
+ F = (F & CF) | (SZ[res]&~(YF|XF)) | ((A^val^res)&HF) | NF; \
+ if( F & HF ) res -= 1; \
+ if( res & 0x02 ) F |= YF; /* bit 1 -> flag 5 */ \
+ if( res & 0x08 ) F |= XF; /* bit 3 -> flag 3 */ \
+ if( BC ) F |= VF; \
+}
+
+/***************************************************************
+ * INI
+ ***************************************************************/
+#define INI { \
+ unsigned t; \
+ UINT8 io = IN(BC); \
+ B--; \
+ WM( HL, io ); \
+ HL++; \
+ F = SZ[B]; \
+ t = (unsigned)((C + 1) & 0xff) + (unsigned)io; \
+ if( io & SF ) F |= NF; \
+ if( t & 0x100 ) F |= HF | CF; \
+ F |= SZP[(UINT8)(t & 0x07) ^ B] & PF; \
+}
+
+/***************************************************************
+ * OUTI
+ ***************************************************************/
+#define OUTI { \
+ unsigned t; \
+ UINT8 io = RM(HL); \
+ B--; \
+ OUT( BC, io ); \
+ HL++; \
+ F = SZ[B]; \
+ t = (unsigned)L + (unsigned)io; \
+ if( io & SF ) F |= NF; \
+ if( t & 0x100 ) F |= HF | CF; \
+ F |= SZP[(UINT8)(t & 0x07) ^ B] & PF; \
+}
+
+/***************************************************************
+ * LDD
+ ***************************************************************/
+#define LDD { \
+ UINT8 io = RM(HL); \
+ WM( DE, io ); \
+ F &= SF | ZF | CF; \
+ if( (A + io) & 0x02 ) F |= YF; /* bit 1 -> flag 5 */ \
+ if( (A + io) & 0x08 ) F |= XF; /* bit 3 -> flag 3 */ \
+ HL--; DE--; BC--; \
+ if( BC ) F |= VF; \
+}
+
+/***************************************************************
+ * CPD
+ ***************************************************************/
+#define CPD { \
+ UINT8 val = RM(HL); \
+ UINT8 res = A - val; \
+ HL--; BC--; \
+ F = (F & CF) | (SZ[res]&~(YF|XF)) | ((A^val^res)&HF) | NF; \
+ if( F & HF ) res -= 1; \
+ if( res & 0x02 ) F |= YF; /* bit 1 -> flag 5 */ \
+ if( res & 0x08 ) F |= XF; /* bit 3 -> flag 3 */ \
+ if( BC ) F |= VF; \
+}
+
+/***************************************************************
+ * IND
+ ***************************************************************/
+#define IND { \
+ unsigned t; \
+ UINT8 io = IN(BC); \
+ B--; \
+ WM( HL, io ); \
+ HL--; \
+ F = SZ[B]; \
+ t = ((unsigned)(C - 1) & 0xff) + (unsigned)io; \
+ if( io & SF ) F |= NF; \
+ if( t & 0x100 ) F |= HF | CF; \
+ F |= SZP[(UINT8)(t & 0x07) ^ B] & PF; \
+}
+
+/***************************************************************
+ * OUTD
+ ***************************************************************/
+#define OUTD { \
+ unsigned t; \
+ UINT8 io = RM(HL); \
+ B--; \
+ OUT( BC, io ); \
+ HL--; \
+ F = SZ[B]; \
+ t = (unsigned)L + (unsigned)io; \
+ if( io & SF ) F |= NF; \
+ if( t & 0x100 ) F |= HF | CF; \
+ F |= SZP[(UINT8)(t & 0x07) ^ B] & PF; \
+}
+
+/***************************************************************
+ * LDIR
+ ***************************************************************/
+#define LDIR \
+ LDI; \
+ if( BC ) \
+ { \
+ PC -= 2; \
+ CC(ex,0xb0); \
+ }
+
+/***************************************************************
+ * CPIR
+ ***************************************************************/
+#define CPIR \
+ CPI; \
+ if( BC && !(F & ZF) ) \
+ { \
+ PC -= 2; \
+ CC(ex,0xb1); \
+ }
+
+/***************************************************************
+ * INIR
+ ***************************************************************/
+#define INIR \
+ INI; \
+ if( B ) \
+ { \
+ PC -= 2; \
+ CC(ex,0xb2); \
+ }
+
+/***************************************************************
+ * OTIR
+ ***************************************************************/
+#define OTIR \
+ OUTI; \
+ if( B ) \
+ { \
+ PC -= 2; \
+ CC(ex,0xb3); \
+ }
+
+/***************************************************************
+ * LDDR
+ ***************************************************************/
+#define LDDR \
+ LDD; \
+ if( BC ) \
+ { \
+ PC -= 2; \
+ CC(ex,0xb8); \
+ }
+
+/***************************************************************
+ * CPDR
+ ***************************************************************/
+#define CPDR \
+ CPD; \
+ if( BC && !(F & ZF) ) \
+ { \
+ PC -= 2; \
+ CC(ex,0xb9); \
+ }
+
+/***************************************************************
+ * INDR
+ ***************************************************************/
+#define INDR \
+ IND; \
+ if( B ) \
+ { \
+ PC -= 2; \
+ CC(ex,0xba); \
+ }
+
+/***************************************************************
+ * OTDR
+ ***************************************************************/
+#define OTDR \
+ OUTD; \
+ if( B ) \
+ { \
+ PC -= 2; \
+ CC(ex,0xbb); \
+ }
+
+/***************************************************************
+ * EI
+ ***************************************************************/
+#define EI { \
+ IFF1 = IFF2 = 1; \
+ Z80.after_ei = TRUE; \
+}
+
+/**********************************************************
+ * opcodes with CB prefix
+ * rotate, shift and bit operations
+ **********************************************************/
+OP(cb,00) { B = RLC(B); } /* RLC B */
+OP(cb,01) { C = RLC(C); } /* RLC C */
+OP(cb,02) { D = RLC(D); } /* RLC D */
+OP(cb,03) { E = RLC(E); } /* RLC E */
+OP(cb,04) { H = RLC(H); } /* RLC H */
+OP(cb,05) { L = RLC(L); } /* RLC L */
+OP(cb,06) { WM( HL, RLC(RM(HL)) ); } /* RLC (HL) */
+OP(cb,07) { A = RLC(A); } /* RLC A */
+
+OP(cb,08) { B = RRC(B); } /* RRC B */
+OP(cb,09) { C = RRC(C); } /* RRC C */
+OP(cb,0a) { D = RRC(D); } /* RRC D */
+OP(cb,0b) { E = RRC(E); } /* RRC E */
+OP(cb,0c) { H = RRC(H); } /* RRC H */
+OP(cb,0d) { L = RRC(L); } /* RRC L */
+OP(cb,0e) { WM( HL, RRC(RM(HL)) ); } /* RRC (HL) */
+OP(cb,0f) { A = RRC(A); } /* RRC A */
+
+OP(cb,10) { B = RL(B); } /* RL B */
+OP(cb,11) { C = RL(C); } /* RL C */
+OP(cb,12) { D = RL(D); } /* RL D */
+OP(cb,13) { E = RL(E); } /* RL E */
+OP(cb,14) { H = RL(H); } /* RL H */
+OP(cb,15) { L = RL(L); } /* RL L */
+OP(cb,16) { WM( HL, RL(RM(HL)) ); } /* RL (HL) */
+OP(cb,17) { A = RL(A); } /* RL A */
+
+OP(cb,18) { B = RR(B); } /* RR B */
+OP(cb,19) { C = RR(C); } /* RR C */
+OP(cb,1a) { D = RR(D); } /* RR D */
+OP(cb,1b) { E = RR(E); } /* RR E */
+OP(cb,1c) { H = RR(H); } /* RR H */
+OP(cb,1d) { L = RR(L); } /* RR L */
+OP(cb,1e) { WM( HL, RR(RM(HL)) ); } /* RR (HL) */
+OP(cb,1f) { A = RR(A); } /* RR A */
+
+OP(cb,20) { B = SLA(B); } /* SLA B */
+OP(cb,21) { C = SLA(C); } /* SLA C */
+OP(cb,22) { D = SLA(D); } /* SLA D */
+OP(cb,23) { E = SLA(E); } /* SLA E */
+OP(cb,24) { H = SLA(H); } /* SLA H */
+OP(cb,25) { L = SLA(L); } /* SLA L */
+OP(cb,26) { WM( HL, SLA(RM(HL)) ); } /* SLA (HL) */
+OP(cb,27) { A = SLA(A); } /* SLA A */
+
+OP(cb,28) { B = SRA(B); } /* SRA B */
+OP(cb,29) { C = SRA(C); } /* SRA C */
+OP(cb,2a) { D = SRA(D); } /* SRA D */
+OP(cb,2b) { E = SRA(E); } /* SRA E */
+OP(cb,2c) { H = SRA(H); } /* SRA H */
+OP(cb,2d) { L = SRA(L); } /* SRA L */
+OP(cb,2e) { WM( HL, SRA(RM(HL)) ); } /* SRA (HL) */
+OP(cb,2f) { A = SRA(A); } /* SRA A */
+
+OP(cb,30) { B = SLL(B); } /* SLL B */
+OP(cb,31) { C = SLL(C); } /* SLL C */
+OP(cb,32) { D = SLL(D); } /* SLL D */
+OP(cb,33) { E = SLL(E); } /* SLL E */
+OP(cb,34) { H = SLL(H); } /* SLL H */
+OP(cb,35) { L = SLL(L); } /* SLL L */
+OP(cb,36) { WM( HL, SLL(RM(HL)) ); } /* SLL (HL) */
+OP(cb,37) { A = SLL(A); } /* SLL A */
+
+OP(cb,38) { B = SRL(B); } /* SRL B */
+OP(cb,39) { C = SRL(C); } /* SRL C */
+OP(cb,3a) { D = SRL(D); } /* SRL D */
+OP(cb,3b) { E = SRL(E); } /* SRL E */
+OP(cb,3c) { H = SRL(H); } /* SRL H */
+OP(cb,3d) { L = SRL(L); } /* SRL L */
+OP(cb,3e) { WM( HL, SRL(RM(HL)) ); } /* SRL (HL) */
+OP(cb,3f) { A = SRL(A); } /* SRL A */
+
+OP(cb,40) { BIT(0,B); } /* BIT 0,B */
+OP(cb,41) { BIT(0,C); } /* BIT 0,C */
+OP(cb,42) { BIT(0,D); } /* BIT 0,D */
+OP(cb,43) { BIT(0,E); } /* BIT 0,E */
+OP(cb,44) { BIT(0,H); } /* BIT 0,H */
+OP(cb,45) { BIT(0,L); } /* BIT 0,L */
+OP(cb,46) { BIT(0,RM(HL)); } /* BIT 0,(HL) */
+OP(cb,47) { BIT(0,A); } /* BIT 0,A */
+
+OP(cb,48) { BIT(1,B); } /* BIT 1,B */
+OP(cb,49) { BIT(1,C); } /* BIT 1,C */
+OP(cb,4a) { BIT(1,D); } /* BIT 1,D */
+OP(cb,4b) { BIT(1,E); } /* BIT 1,E */
+OP(cb,4c) { BIT(1,H); } /* BIT 1,H */
+OP(cb,4d) { BIT(1,L); } /* BIT 1,L */
+OP(cb,4e) { BIT(1,RM(HL)); } /* BIT 1,(HL) */
+OP(cb,4f) { BIT(1,A); } /* BIT 1,A */
+
+OP(cb,50) { BIT(2,B); } /* BIT 2,B */
+OP(cb,51) { BIT(2,C); } /* BIT 2,C */
+OP(cb,52) { BIT(2,D); } /* BIT 2,D */
+OP(cb,53) { BIT(2,E); } /* BIT 2,E */
+OP(cb,54) { BIT(2,H); } /* BIT 2,H */
+OP(cb,55) { BIT(2,L); } /* BIT 2,L */
+OP(cb,56) { BIT(2,RM(HL)); } /* BIT 2,(HL) */
+OP(cb,57) { BIT(2,A); } /* BIT 2,A */
+
+OP(cb,58) { BIT(3,B); } /* BIT 3,B */
+OP(cb,59) { BIT(3,C); } /* BIT 3,C */
+OP(cb,5a) { BIT(3,D); } /* BIT 3,D */
+OP(cb,5b) { BIT(3,E); } /* BIT 3,E */
+OP(cb,5c) { BIT(3,H); } /* BIT 3,H */
+OP(cb,5d) { BIT(3,L); } /* BIT 3,L */
+OP(cb,5e) { BIT(3,RM(HL)); } /* BIT 3,(HL) */
+OP(cb,5f) { BIT(3,A); } /* BIT 3,A */
+
+OP(cb,60) { BIT(4,B); } /* BIT 4,B */
+OP(cb,61) { BIT(4,C); } /* BIT 4,C */
+OP(cb,62) { BIT(4,D); } /* BIT 4,D */
+OP(cb,63) { BIT(4,E); } /* BIT 4,E */
+OP(cb,64) { BIT(4,H); } /* BIT 4,H */
+OP(cb,65) { BIT(4,L); } /* BIT 4,L */
+OP(cb,66) { BIT(4,RM(HL)); } /* BIT 4,(HL) */
+OP(cb,67) { BIT(4,A); } /* BIT 4,A */
+
+OP(cb,68) { BIT(5,B); } /* BIT 5,B */
+OP(cb,69) { BIT(5,C); } /* BIT 5,C */
+OP(cb,6a) { BIT(5,D); } /* BIT 5,D */
+OP(cb,6b) { BIT(5,E); } /* BIT 5,E */
+OP(cb,6c) { BIT(5,H); } /* BIT 5,H */
+OP(cb,6d) { BIT(5,L); } /* BIT 5,L */
+OP(cb,6e) { BIT(5,RM(HL)); } /* BIT 5,(HL) */
+OP(cb,6f) { BIT(5,A); } /* BIT 5,A */
+
+OP(cb,70) { BIT(6,B); } /* BIT 6,B */
+OP(cb,71) { BIT(6,C); } /* BIT 6,C */
+OP(cb,72) { BIT(6,D); } /* BIT 6,D */
+OP(cb,73) { BIT(6,E); } /* BIT 6,E */
+OP(cb,74) { BIT(6,H); } /* BIT 6,H */
+OP(cb,75) { BIT(6,L); } /* BIT 6,L */
+OP(cb,76) { BIT(6,RM(HL)); } /* BIT 6,(HL) */
+OP(cb,77) { BIT(6,A); } /* BIT 6,A */
+
+OP(cb,78) { BIT(7,B); } /* BIT 7,B */
+OP(cb,79) { BIT(7,C); } /* BIT 7,C */
+OP(cb,7a) { BIT(7,D); } /* BIT 7,D */
+OP(cb,7b) { BIT(7,E); } /* BIT 7,E */
+OP(cb,7c) { BIT(7,H); } /* BIT 7,H */
+OP(cb,7d) { BIT(7,L); } /* BIT 7,L */
+OP(cb,7e) { BIT(7,RM(HL)); } /* BIT 7,(HL) */
+OP(cb,7f) { BIT(7,A); } /* BIT 7,A */
+
+OP(cb,80) { B = RES(0,B); } /* RES 0,B */
+OP(cb,81) { C = RES(0,C); } /* RES 0,C */
+OP(cb,82) { D = RES(0,D); } /* RES 0,D */
+OP(cb,83) { E = RES(0,E); } /* RES 0,E */
+OP(cb,84) { H = RES(0,H); } /* RES 0,H */
+OP(cb,85) { L = RES(0,L); } /* RES 0,L */
+OP(cb,86) { WM( HL, RES(0,RM(HL)) ); } /* RES 0,(HL) */
+OP(cb,87) { A = RES(0,A); } /* RES 0,A */
+
+OP(cb,88) { B = RES(1,B); } /* RES 1,B */
+OP(cb,89) { C = RES(1,C); } /* RES 1,C */
+OP(cb,8a) { D = RES(1,D); } /* RES 1,D */
+OP(cb,8b) { E = RES(1,E); } /* RES 1,E */
+OP(cb,8c) { H = RES(1,H); } /* RES 1,H */
+OP(cb,8d) { L = RES(1,L); } /* RES 1,L */
+OP(cb,8e) { WM( HL, RES(1,RM(HL)) ); } /* RES 1,(HL) */
+OP(cb,8f) { A = RES(1,A); } /* RES 1,A */
+
+OP(cb,90) { B = RES(2,B); } /* RES 2,B */
+OP(cb,91) { C = RES(2,C); } /* RES 2,C */
+OP(cb,92) { D = RES(2,D); } /* RES 2,D */
+OP(cb,93) { E = RES(2,E); } /* RES 2,E */
+OP(cb,94) { H = RES(2,H); } /* RES 2,H */
+OP(cb,95) { L = RES(2,L); } /* RES 2,L */
+OP(cb,96) { WM( HL, RES(2,RM(HL)) ); } /* RES 2,(HL) */
+OP(cb,97) { A = RES(2,A); } /* RES 2,A */
+
+OP(cb,98) { B = RES(3,B); } /* RES 3,B */
+OP(cb,99) { C = RES(3,C); } /* RES 3,C */
+OP(cb,9a) { D = RES(3,D); } /* RES 3,D */
+OP(cb,9b) { E = RES(3,E); } /* RES 3,E */
+OP(cb,9c) { H = RES(3,H); } /* RES 3,H */
+OP(cb,9d) { L = RES(3,L); } /* RES 3,L */
+OP(cb,9e) { WM( HL, RES(3,RM(HL)) ); } /* RES 3,(HL) */
+OP(cb,9f) { A = RES(3,A); } /* RES 3,A */
+
+OP(cb,a0) { B = RES(4,B); } /* RES 4,B */
+OP(cb,a1) { C = RES(4,C); } /* RES 4,C */
+OP(cb,a2) { D = RES(4,D); } /* RES 4,D */
+OP(cb,a3) { E = RES(4,E); } /* RES 4,E */
+OP(cb,a4) { H = RES(4,H); } /* RES 4,H */
+OP(cb,a5) { L = RES(4,L); } /* RES 4,L */
+OP(cb,a6) { WM( HL, RES(4,RM(HL)) ); } /* RES 4,(HL) */
+OP(cb,a7) { A = RES(4,A); } /* RES 4,A */
+
+OP(cb,a8) { B = RES(5,B); } /* RES 5,B */
+OP(cb,a9) { C = RES(5,C); } /* RES 5,C */
+OP(cb,aa) { D = RES(5,D); } /* RES 5,D */
+OP(cb,ab) { E = RES(5,E); } /* RES 5,E */
+OP(cb,ac) { H = RES(5,H); } /* RES 5,H */
+OP(cb,ad) { L = RES(5,L); } /* RES 5,L */
+OP(cb,ae) { WM( HL, RES(5,RM(HL)) ); } /* RES 5,(HL) */
+OP(cb,af) { A = RES(5,A); } /* RES 5,A */
+
+OP(cb,b0) { B = RES(6,B); } /* RES 6,B */
+OP(cb,b1) { C = RES(6,C); } /* RES 6,C */
+OP(cb,b2) { D = RES(6,D); } /* RES 6,D */
+OP(cb,b3) { E = RES(6,E); } /* RES 6,E */
+OP(cb,b4) { H = RES(6,H); } /* RES 6,H */
+OP(cb,b5) { L = RES(6,L); } /* RES 6,L */
+OP(cb,b6) { WM( HL, RES(6,RM(HL)) ); } /* RES 6,(HL) */
+OP(cb,b7) { A = RES(6,A); } /* RES 6,A */
+
+OP(cb,b8) { B = RES(7,B); } /* RES 7,B */
+OP(cb,b9) { C = RES(7,C); } /* RES 7,C */
+OP(cb,ba) { D = RES(7,D); } /* RES 7,D */
+OP(cb,bb) { E = RES(7,E); } /* RES 7,E */
+OP(cb,bc) { H = RES(7,H); } /* RES 7,H */
+OP(cb,bd) { L = RES(7,L); } /* RES 7,L */
+OP(cb,be) { WM( HL, RES(7,RM(HL)) ); } /* RES 7,(HL) */
+OP(cb,bf) { A = RES(7,A); } /* RES 7,A */
+
+OP(cb,c0) { B = SET(0,B); } /* SET 0,B */
+OP(cb,c1) { C = SET(0,C); } /* SET 0,C */
+OP(cb,c2) { D = SET(0,D); } /* SET 0,D */
+OP(cb,c3) { E = SET(0,E); } /* SET 0,E */
+OP(cb,c4) { H = SET(0,H); } /* SET 0,H */
+OP(cb,c5) { L = SET(0,L); } /* SET 0,L */
+OP(cb,c6) { WM( HL, SET(0,RM(HL)) ); } /* SET 0,(HL) */
+OP(cb,c7) { A = SET(0,A); } /* SET 0,A */
+
+OP(cb,c8) { B = SET(1,B); } /* SET 1,B */
+OP(cb,c9) { C = SET(1,C); } /* SET 1,C */
+OP(cb,ca) { D = SET(1,D); } /* SET 1,D */
+OP(cb,cb) { E = SET(1,E); } /* SET 1,E */
+OP(cb,cc) { H = SET(1,H); } /* SET 1,H */
+OP(cb,cd) { L = SET(1,L); } /* SET 1,L */
+OP(cb,ce) { WM( HL, SET(1,RM(HL)) ); } /* SET 1,(HL) */
+OP(cb,cf) { A = SET(1,A); } /* SET 1,A */
+
+OP(cb,d0) { B = SET(2,B); } /* SET 2,B */
+OP(cb,d1) { C = SET(2,C); } /* SET 2,C */
+OP(cb,d2) { D = SET(2,D); } /* SET 2,D */
+OP(cb,d3) { E = SET(2,E); } /* SET 2,E */
+OP(cb,d4) { H = SET(2,H); } /* SET 2,H */
+OP(cb,d5) { L = SET(2,L); } /* SET 2,L */
+OP(cb,d6) { WM( HL, SET(2,RM(HL)) ); } /* SET 2,(HL) */
+OP(cb,d7) { A = SET(2,A); } /* SET 2,A */
+
+OP(cb,d8) { B = SET(3,B); } /* SET 3,B */
+OP(cb,d9) { C = SET(3,C); } /* SET 3,C */
+OP(cb,da) { D = SET(3,D); } /* SET 3,D */
+OP(cb,db) { E = SET(3,E); } /* SET 3,E */
+OP(cb,dc) { H = SET(3,H); } /* SET 3,H */
+OP(cb,dd) { L = SET(3,L); } /* SET 3,L */
+OP(cb,de) { WM( HL, SET(3,RM(HL)) ); } /* SET 3,(HL) */
+OP(cb,df) { A = SET(3,A); } /* SET 3,A */
+
+OP(cb,e0) { B = SET(4,B); } /* SET 4,B */
+OP(cb,e1) { C = SET(4,C); } /* SET 4,C */
+OP(cb,e2) { D = SET(4,D); } /* SET 4,D */
+OP(cb,e3) { E = SET(4,E); } /* SET 4,E */
+OP(cb,e4) { H = SET(4,H); } /* SET 4,H */
+OP(cb,e5) { L = SET(4,L); } /* SET 4,L */
+OP(cb,e6) { WM( HL, SET(4,RM(HL)) ); } /* SET 4,(HL) */
+OP(cb,e7) { A = SET(4,A); } /* SET 4,A */
+
+OP(cb,e8) { B = SET(5,B); } /* SET 5,B */
+OP(cb,e9) { C = SET(5,C); } /* SET 5,C */
+OP(cb,ea) { D = SET(5,D); } /* SET 5,D */
+OP(cb,eb) { E = SET(5,E); } /* SET 5,E */
+OP(cb,ec) { H = SET(5,H); } /* SET 5,H */
+OP(cb,ed) { L = SET(5,L); } /* SET 5,L */
+OP(cb,ee) { WM( HL, SET(5,RM(HL)) ); } /* SET 5,(HL) */
+OP(cb,ef) { A = SET(5,A); } /* SET 5,A */
+
+OP(cb,f0) { B = SET(6,B); } /* SET 6,B */
+OP(cb,f1) { C = SET(6,C); } /* SET 6,C */
+OP(cb,f2) { D = SET(6,D); } /* SET 6,D */
+OP(cb,f3) { E = SET(6,E); } /* SET 6,E */
+OP(cb,f4) { H = SET(6,H); } /* SET 6,H */
+OP(cb,f5) { L = SET(6,L); } /* SET 6,L */
+OP(cb,f6) { WM( HL, SET(6,RM(HL)) ); } /* SET 6,(HL) */
+OP(cb,f7) { A = SET(6,A); } /* SET 6,A */
+
+OP(cb,f8) { B = SET(7,B); } /* SET 7,B */
+OP(cb,f9) { C = SET(7,C); } /* SET 7,C */
+OP(cb,fa) { D = SET(7,D); } /* SET 7,D */
+OP(cb,fb) { E = SET(7,E); } /* SET 7,E */
+OP(cb,fc) { H = SET(7,H); } /* SET 7,H */
+OP(cb,fd) { L = SET(7,L); } /* SET 7,L */
+OP(cb,fe) { WM( HL, SET(7,RM(HL)) ); } /* SET 7,(HL) */
+OP(cb,ff) { A = SET(7,A); } /* SET 7,A */
+
+
+/**********************************************************
+* opcodes with DD/FD CB prefix
+* rotate, shift and bit operations with (IX+o)
+**********************************************************/
+OP(xycb,00) { B = RLC( RM(EA) ); WM( EA,B ); } /* RLC B=(XY+o) */
+OP(xycb,01) { C = RLC( RM(EA) ); WM( EA,C ); } /* RLC C=(XY+o) */
+OP(xycb,02) { D = RLC( RM(EA) ); WM( EA,D ); } /* RLC D=(XY+o) */
+OP(xycb,03) { E = RLC( RM(EA) ); WM( EA,E ); } /* RLC E=(XY+o) */
+OP(xycb,04) { H = RLC( RM(EA) ); WM( EA,H ); } /* RLC H=(XY+o) */
+OP(xycb,05) { L = RLC( RM(EA) ); WM( EA,L ); } /* RLC L=(XY+o) */
+OP(xycb,06) { WM( EA, RLC( RM(EA) ) ); } /* RLC (XY+o) */
+OP(xycb,07) { A = RLC( RM(EA) ); WM( EA,A ); } /* RLC A=(XY+o) */
+
+OP(xycb,08) { B = RRC( RM(EA) ); WM( EA,B ); } /* RRC B=(XY+o) */
+OP(xycb,09) { C = RRC( RM(EA) ); WM( EA,C ); } /* RRC C=(XY+o) */
+OP(xycb,0a) { D = RRC( RM(EA) ); WM( EA,D ); } /* RRC D=(XY+o) */
+OP(xycb,0b) { E = RRC( RM(EA) ); WM( EA,E ); } /* RRC E=(XY+o) */
+OP(xycb,0c) { H = RRC( RM(EA) ); WM( EA,H ); } /* RRC H=(XY+o) */
+OP(xycb,0d) { L = RRC( RM(EA) ); WM( EA,L ); } /* RRC L=(XY+o) */
+OP(xycb,0e) { WM( EA,RRC( RM(EA) ) ); } /* RRC (XY+o) */
+OP(xycb,0f) { A = RRC( RM(EA) ); WM( EA,A ); } /* RRC A=(XY+o) */
+
+OP(xycb,10) { B = RL( RM(EA) ); WM( EA,B ); } /* RL B=(XY+o) */
+OP(xycb,11) { C = RL( RM(EA) ); WM( EA,C ); } /* RL C=(XY+o) */
+OP(xycb,12) { D = RL( RM(EA) ); WM( EA,D ); } /* RL D=(XY+o) */
+OP(xycb,13) { E = RL( RM(EA) ); WM( EA,E ); } /* RL E=(XY+o) */
+OP(xycb,14) { H = RL( RM(EA) ); WM( EA,H ); } /* RL H=(XY+o) */
+OP(xycb,15) { L = RL( RM(EA) ); WM( EA,L ); } /* RL L=(XY+o) */
+OP(xycb,16) { WM( EA,RL( RM(EA) ) ); } /* RL (XY+o) */
+OP(xycb,17) { A = RL( RM(EA) ); WM( EA,A ); } /* RL A=(XY+o) */
+
+OP(xycb,18) { B = RR( RM(EA) ); WM( EA,B ); } /* RR B=(XY+o) */
+OP(xycb,19) { C = RR( RM(EA) ); WM( EA,C ); } /* RR C=(XY+o) */
+OP(xycb,1a) { D = RR( RM(EA) ); WM( EA,D ); } /* RR D=(XY+o) */
+OP(xycb,1b) { E = RR( RM(EA) ); WM( EA,E ); } /* RR E=(XY+o) */
+OP(xycb,1c) { H = RR( RM(EA) ); WM( EA,H ); } /* RR H=(XY+o) */
+OP(xycb,1d) { L = RR( RM(EA) ); WM( EA,L ); } /* RR L=(XY+o) */
+OP(xycb,1e) { WM( EA,RR( RM(EA) ) ); } /* RR (XY+o) */
+OP(xycb,1f) { A = RR( RM(EA) ); WM( EA,A ); } /* RR A=(XY+o) */
+
+OP(xycb,20) { B = SLA( RM(EA) ); WM( EA,B ); } /* SLA B=(XY+o) */
+OP(xycb,21) { C = SLA( RM(EA) ); WM( EA,C ); } /* SLA C=(XY+o) */
+OP(xycb,22) { D = SLA( RM(EA) ); WM( EA,D ); } /* SLA D=(XY+o) */
+OP(xycb,23) { E = SLA( RM(EA) ); WM( EA,E ); } /* SLA E=(XY+o) */
+OP(xycb,24) { H = SLA( RM(EA) ); WM( EA,H ); } /* SLA H=(XY+o) */
+OP(xycb,25) { L = SLA( RM(EA) ); WM( EA,L ); } /* SLA L=(XY+o) */
+OP(xycb,26) { WM( EA,SLA( RM(EA) ) ); } /* SLA (XY+o) */
+OP(xycb,27) { A = SLA( RM(EA) ); WM( EA,A ); } /* SLA A=(XY+o) */
+
+OP(xycb,28) { B = SRA( RM(EA) ); WM( EA,B ); } /* SRA B=(XY+o) */
+OP(xycb,29) { C = SRA( RM(EA) ); WM( EA,C ); } /* SRA C=(XY+o) */
+OP(xycb,2a) { D = SRA( RM(EA) ); WM( EA,D ); } /* SRA D=(XY+o) */
+OP(xycb,2b) { E = SRA( RM(EA) ); WM( EA,E ); } /* SRA E=(XY+o) */
+OP(xycb,2c) { H = SRA( RM(EA) ); WM( EA,H ); } /* SRA H=(XY+o) */
+OP(xycb,2d) { L = SRA( RM(EA) ); WM( EA,L ); } /* SRA L=(XY+o) */
+OP(xycb,2e) { WM( EA,SRA( RM(EA) ) ); } /* SRA (XY+o) */
+OP(xycb,2f) { A = SRA( RM(EA) ); WM( EA,A ); } /* SRA A=(XY+o) */
+
+OP(xycb,30) { B = SLL( RM(EA) ); WM( EA,B ); } /* SLL B=(XY+o) */
+OP(xycb,31) { C = SLL( RM(EA) ); WM( EA,C ); } /* SLL C=(XY+o) */
+OP(xycb,32) { D = SLL( RM(EA) ); WM( EA,D ); } /* SLL D=(XY+o) */
+OP(xycb,33) { E = SLL( RM(EA) ); WM( EA,E ); } /* SLL E=(XY+o) */
+OP(xycb,34) { H = SLL( RM(EA) ); WM( EA,H ); } /* SLL H=(XY+o) */
+OP(xycb,35) { L = SLL( RM(EA) ); WM( EA,L ); } /* SLL L=(XY+o) */
+OP(xycb,36) { WM( EA,SLL( RM(EA) ) ); } /* SLL (XY+o) */
+OP(xycb,37) { A = SLL( RM(EA) ); WM( EA,A ); } /* SLL A=(XY+o) */
+
+OP(xycb,38) { B = SRL( RM(EA) ); WM( EA,B ); } /* SRL B=(XY+o) */
+OP(xycb,39) { C = SRL( RM(EA) ); WM( EA,C ); } /* SRL C=(XY+o) */
+OP(xycb,3a) { D = SRL( RM(EA) ); WM( EA,D ); } /* SRL D=(XY+o) */
+OP(xycb,3b) { E = SRL( RM(EA) ); WM( EA,E ); } /* SRL E=(XY+o) */
+OP(xycb,3c) { H = SRL( RM(EA) ); WM( EA,H ); } /* SRL H=(XY+o) */
+OP(xycb,3d) { L = SRL( RM(EA) ); WM( EA,L ); } /* SRL L=(XY+o) */
+OP(xycb,3e) { WM( EA,SRL( RM(EA) ) ); } /* SRL (XY+o) */
+OP(xycb,3f) { A = SRL( RM(EA) ); WM( EA,A ); } /* SRL A=(XY+o) */
+
+OP(xycb,40) { xycb_46(); } /* BIT 0,(XY+o) */
+OP(xycb,41) { xycb_46(); } /* BIT 0,(XY+o) */
+OP(xycb,42) { xycb_46(); } /* BIT 0,(XY+o) */
+OP(xycb,43) { xycb_46(); } /* BIT 0,(XY+o) */
+OP(xycb,44) { xycb_46(); } /* BIT 0,(XY+o) */
+OP(xycb,45) { xycb_46(); } /* BIT 0,(XY+o) */
+OP(xycb,46) { BIT_XY(0,RM(EA)); } /* BIT 0,(XY+o) */
+OP(xycb,47) { xycb_46(); } /* BIT 0,(XY+o) */
+
+OP(xycb,48) { xycb_4e(); } /* BIT 1,(XY+o) */
+OP(xycb,49) { xycb_4e(); } /* BIT 1,(XY+o) */
+OP(xycb,4a) { xycb_4e(); } /* BIT 1,(XY+o) */
+OP(xycb,4b) { xycb_4e(); } /* BIT 1,(XY+o) */
+OP(xycb,4c) { xycb_4e(); } /* BIT 1,(XY+o) */
+OP(xycb,4d) { xycb_4e(); } /* BIT 1,(XY+o) */
+OP(xycb,4e) { BIT_XY(1,RM(EA)); } /* BIT 1,(XY+o) */
+OP(xycb,4f) { xycb_4e(); } /* BIT 1,(XY+o) */
+
+OP(xycb,50) { xycb_56(); } /* BIT 2,(XY+o) */
+OP(xycb,51) { xycb_56(); } /* BIT 2,(XY+o) */
+OP(xycb,52) { xycb_56(); } /* BIT 2,(XY+o) */
+OP(xycb,53) { xycb_56(); } /* BIT 2,(XY+o) */
+OP(xycb,54) { xycb_56(); } /* BIT 2,(XY+o) */
+OP(xycb,55) { xycb_56(); } /* BIT 2,(XY+o) */
+OP(xycb,56) { BIT_XY(2,RM(EA)); } /* BIT 2,(XY+o) */
+OP(xycb,57) { xycb_56(); } /* BIT 2,(XY+o) */
+
+OP(xycb,58) { xycb_5e(); } /* BIT 3,(XY+o) */
+OP(xycb,59) { xycb_5e(); } /* BIT 3,(XY+o) */
+OP(xycb,5a) { xycb_5e(); } /* BIT 3,(XY+o) */
+OP(xycb,5b) { xycb_5e(); } /* BIT 3,(XY+o) */
+OP(xycb,5c) { xycb_5e(); } /* BIT 3,(XY+o) */
+OP(xycb,5d) { xycb_5e(); } /* BIT 3,(XY+o) */
+OP(xycb,5e) { BIT_XY(3,RM(EA)); } /* BIT 3,(XY+o) */
+OP(xycb,5f) { xycb_5e(); } /* BIT 3,(XY+o) */
+
+OP(xycb,60) { xycb_66(); } /* BIT 4,(XY+o) */
+OP(xycb,61) { xycb_66(); } /* BIT 4,(XY+o) */
+OP(xycb,62) { xycb_66(); } /* BIT 4,(XY+o) */
+OP(xycb,63) { xycb_66(); } /* BIT 4,(XY+o) */
+OP(xycb,64) { xycb_66(); } /* BIT 4,(XY+o) */
+OP(xycb,65) { xycb_66(); } /* BIT 4,(XY+o) */
+OP(xycb,66) { BIT_XY(4,RM(EA)); } /* BIT 4,(XY+o) */
+OP(xycb,67) { xycb_66(); } /* BIT 4,(XY+o) */
+
+OP(xycb,68) { xycb_6e(); } /* BIT 5,(XY+o) */
+OP(xycb,69) { xycb_6e(); } /* BIT 5,(XY+o) */
+OP(xycb,6a) { xycb_6e(); } /* BIT 5,(XY+o) */
+OP(xycb,6b) { xycb_6e(); } /* BIT 5,(XY+o) */
+OP(xycb,6c) { xycb_6e(); } /* BIT 5,(XY+o) */
+OP(xycb,6d) { xycb_6e(); } /* BIT 5,(XY+o) */
+OP(xycb,6e) { BIT_XY(5,RM(EA)); } /* BIT 5,(XY+o) */
+OP(xycb,6f) { xycb_6e(); } /* BIT 5,(XY+o) */
+
+OP(xycb,70) { xycb_66(); } /* BIT 6,(XY+o) */
+OP(xycb,71) { xycb_66(); } /* BIT 6,(XY+o) */
+OP(xycb,72) { xycb_66(); } /* BIT 6,(XY+o) */
+OP(xycb,73) { xycb_66(); } /* BIT 6,(XY+o) */
+OP(xycb,74) { xycb_66(); } /* BIT 6,(XY+o) */
+OP(xycb,75) { xycb_66(); } /* BIT 6,(XY+o) */
+OP(xycb,76) { BIT_XY(6,RM(EA)); } /* BIT 6,(XY+o) */
+OP(xycb,77) { xycb_66(); } /* BIT 6,(XY+o) */
+
+OP(xycb,78) { xycb_7e(); } /* BIT 7,(XY+o) */
+OP(xycb,79) { xycb_7e(); } /* BIT 7,(XY+o) */
+OP(xycb,7a) { xycb_7e(); } /* BIT 7,(XY+o) */
+OP(xycb,7b) { xycb_7e(); } /* BIT 7,(XY+o) */
+OP(xycb,7c) { xycb_7e(); } /* BIT 7,(XY+o) */
+OP(xycb,7d) { xycb_7e(); } /* BIT 7,(XY+o) */
+OP(xycb,7e) { BIT_XY(7,RM(EA)); } /* BIT 7,(XY+o) */
+OP(xycb,7f) { xycb_7e(); } /* BIT 7,(XY+o) */
+
+OP(xycb,80) { B = RES(0, RM(EA) ); WM( EA,B ); } /* RES 0,B=(XY+o) */
+OP(xycb,81) { C = RES(0, RM(EA) ); WM( EA,C ); } /* RES 0,C=(XY+o) */
+OP(xycb,82) { D = RES(0, RM(EA) ); WM( EA,D ); } /* RES 0,D=(XY+o) */
+OP(xycb,83) { E = RES(0, RM(EA) ); WM( EA,E ); } /* RES 0,E=(XY+o) */
+OP(xycb,84) { H = RES(0, RM(EA) ); WM( EA,H ); } /* RES 0,H=(XY+o) */
+OP(xycb,85) { L = RES(0, RM(EA) ); WM( EA,L ); } /* RES 0,L=(XY+o) */
+OP(xycb,86) { WM( EA, RES(0,RM(EA)) ); } /* RES 0,(XY+o) */
+OP(xycb,87) { A = RES(0, RM(EA) ); WM( EA,A ); } /* RES 0,A=(XY+o) */
+
+OP(xycb,88) { B = RES(1, RM(EA) ); WM( EA,B ); } /* RES 1,B=(XY+o) */
+OP(xycb,89) { C = RES(1, RM(EA) ); WM( EA,C ); } /* RES 1,C=(XY+o) */
+OP(xycb,8a) { D = RES(1, RM(EA) ); WM( EA,D ); } /* RES 1,D=(XY+o) */
+OP(xycb,8b) { E = RES(1, RM(EA) ); WM( EA,E ); } /* RES 1,E=(XY+o) */
+OP(xycb,8c) { H = RES(1, RM(EA) ); WM( EA,H ); } /* RES 1,H=(XY+o) */
+OP(xycb,8d) { L = RES(1, RM(EA) ); WM( EA,L ); } /* RES 1,L=(XY+o) */
+OP(xycb,8e) { WM( EA, RES(1,RM(EA)) ); } /* RES 1,(XY+o) */
+OP(xycb,8f) { A = RES(1, RM(EA) ); WM( EA,A ); } /* RES 1,A=(XY+o) */
+
+OP(xycb,90) { B = RES(2, RM(EA) ); WM( EA,B ); } /* RES 2,B=(XY+o) */
+OP(xycb,91) { C = RES(2, RM(EA) ); WM( EA,C ); } /* RES 2,C=(XY+o) */
+OP(xycb,92) { D = RES(2, RM(EA) ); WM( EA,D ); } /* RES 2,D=(XY+o) */
+OP(xycb,93) { E = RES(2, RM(EA) ); WM( EA,E ); } /* RES 2,E=(XY+o) */
+OP(xycb,94) { H = RES(2, RM(EA) ); WM( EA,H ); } /* RES 2,H=(XY+o) */
+OP(xycb,95) { L = RES(2, RM(EA) ); WM( EA,L ); } /* RES 2,L=(XY+o) */
+OP(xycb,96) { WM( EA, RES(2,RM(EA)) ); } /* RES 2,(XY+o) */
+OP(xycb,97) { A = RES(2, RM(EA) ); WM( EA,A ); } /* RES 2,A=(XY+o) */
+
+OP(xycb,98) { B = RES(3, RM(EA) ); WM( EA,B ); } /* RES 3,B=(XY+o) */
+OP(xycb,99) { C = RES(3, RM(EA) ); WM( EA,C ); } /* RES 3,C=(XY+o) */
+OP(xycb,9a) { D = RES(3, RM(EA) ); WM( EA,D ); } /* RES 3,D=(XY+o) */
+OP(xycb,9b) { E = RES(3, RM(EA) ); WM( EA,E ); } /* RES 3,E=(XY+o) */
+OP(xycb,9c) { H = RES(3, RM(EA) ); WM( EA,H ); } /* RES 3,H=(XY+o) */
+OP(xycb,9d) { L = RES(3, RM(EA) ); WM( EA,L ); } /* RES 3,L=(XY+o) */
+OP(xycb,9e) { WM( EA, RES(3,RM(EA)) ); } /* RES 3,(XY+o) */
+OP(xycb,9f) { A = RES(3, RM(EA) ); WM( EA,A ); } /* RES 3,A=(XY+o) */
+
+OP(xycb,a0) { B = RES(4, RM(EA) ); WM( EA,B ); } /* RES 4,B=(XY+o) */
+OP(xycb,a1) { C = RES(4, RM(EA) ); WM( EA,C ); } /* RES 4,C=(XY+o) */
+OP(xycb,a2) { D = RES(4, RM(EA) ); WM( EA,D ); } /* RES 4,D=(XY+o) */
+OP(xycb,a3) { E = RES(4, RM(EA) ); WM( EA,E ); } /* RES 4,E=(XY+o) */
+OP(xycb,a4) { H = RES(4, RM(EA) ); WM( EA,H ); } /* RES 4,H=(XY+o) */
+OP(xycb,a5) { L = RES(4, RM(EA) ); WM( EA,L ); } /* RES 4,L=(XY+o) */
+OP(xycb,a6) { WM( EA, RES(4,RM(EA)) ); } /* RES 4,(XY+o) */
+OP(xycb,a7) { A = RES(4, RM(EA) ); WM( EA,A ); } /* RES 4,A=(XY+o) */
+
+OP(xycb,a8) { B = RES(5, RM(EA) ); WM( EA,B ); } /* RES 5,B=(XY+o) */
+OP(xycb,a9) { C = RES(5, RM(EA) ); WM( EA,C ); } /* RES 5,C=(XY+o) */
+OP(xycb,aa) { D = RES(5, RM(EA) ); WM( EA,D ); } /* RES 5,D=(XY+o) */
+OP(xycb,ab) { E = RES(5, RM(EA) ); WM( EA,E ); } /* RES 5,E=(XY+o) */
+OP(xycb,ac) { H = RES(5, RM(EA) ); WM( EA,H ); } /* RES 5,H=(XY+o) */
+OP(xycb,ad) { L = RES(5, RM(EA) ); WM( EA,L ); } /* RES 5,L=(XY+o) */
+OP(xycb,ae) { WM( EA, RES(5,RM(EA)) ); } /* RES 5,(XY+o) */
+OP(xycb,af) { A = RES(5, RM(EA) ); WM( EA,A ); } /* RES 5,A=(XY+o) */
+
+OP(xycb,b0) { B = RES(6, RM(EA) ); WM( EA,B ); } /* RES 6,B=(XY+o) */
+OP(xycb,b1) { C = RES(6, RM(EA) ); WM( EA,C ); } /* RES 6,C=(XY+o) */
+OP(xycb,b2) { D = RES(6, RM(EA) ); WM( EA,D ); } /* RES 6,D=(XY+o) */
+OP(xycb,b3) { E = RES(6, RM(EA) ); WM( EA,E ); } /* RES 6,E=(XY+o) */
+OP(xycb,b4) { H = RES(6, RM(EA) ); WM( EA,H ); } /* RES 6,H=(XY+o) */
+OP(xycb,b5) { L = RES(6, RM(EA) ); WM( EA,L ); } /* RES 6,L=(XY+o) */
+OP(xycb,b6) { WM( EA, RES(6,RM(EA)) ); } /* RES 6,(XY+o) */
+OP(xycb,b7) { A = RES(6, RM(EA) ); WM( EA,A ); } /* RES 6,A=(XY+o) */
+
+OP(xycb,b8) { B = RES(7, RM(EA) ); WM( EA,B ); } /* RES 7,B=(XY+o) */
+OP(xycb,b9) { C = RES(7, RM(EA) ); WM( EA,C ); } /* RES 7,C=(XY+o) */
+OP(xycb,ba) { D = RES(7, RM(EA) ); WM( EA,D ); } /* RES 7,D=(XY+o) */
+OP(xycb,bb) { E = RES(7, RM(EA) ); WM( EA,E ); } /* RES 7,E=(XY+o) */
+OP(xycb,bc) { H = RES(7, RM(EA) ); WM( EA,H ); } /* RES 7,H=(XY+o) */
+OP(xycb,bd) { L = RES(7, RM(EA) ); WM( EA,L ); } /* RES 7,L=(XY+o) */
+OP(xycb,be) { WM( EA, RES(7,RM(EA)) ); } /* RES 7,(XY+o) */
+OP(xycb,bf) { A = RES(7, RM(EA) ); WM( EA,A ); } /* RES 7,A=(XY+o) */
+
+OP(xycb,c0) { B = SET(0, RM(EA) ); WM( EA,B ); } /* SET 0,B=(XY+o) */
+OP(xycb,c1) { C = SET(0, RM(EA) ); WM( EA,C ); } /* SET 0,C=(XY+o) */
+OP(xycb,c2) { D = SET(0, RM(EA) ); WM( EA,D ); } /* SET 0,D=(XY+o) */
+OP(xycb,c3) { E = SET(0, RM(EA) ); WM( EA,E ); } /* SET 0,E=(XY+o) */
+OP(xycb,c4) { H = SET(0, RM(EA) ); WM( EA,H ); } /* SET 0,H=(XY+o) */
+OP(xycb,c5) { L = SET(0, RM(EA) ); WM( EA,L ); } /* SET 0,L=(XY+o) */
+OP(xycb,c6) { WM( EA, SET(0,RM(EA)) ); } /* SET 0,(XY+o) */
+OP(xycb,c7) { A = SET(0, RM(EA) ); WM( EA,A ); } /* SET 0,A=(XY+o) */
+
+OP(xycb,c8) { B = SET(1, RM(EA) ); WM( EA,B ); } /* SET 1,B=(XY+o) */
+OP(xycb,c9) { C = SET(1, RM(EA) ); WM( EA,C ); } /* SET 1,C=(XY+o) */
+OP(xycb,ca) { D = SET(1, RM(EA) ); WM( EA,D ); } /* SET 1,D=(XY+o) */
+OP(xycb,cb) { E = SET(1, RM(EA) ); WM( EA,E ); } /* SET 1,E=(XY+o) */
+OP(xycb,cc) { H = SET(1, RM(EA) ); WM( EA,H ); } /* SET 1,H=(XY+o) */
+OP(xycb,cd) { L = SET(1, RM(EA) ); WM( EA,L ); } /* SET 1,L=(XY+o) */
+OP(xycb,ce) { WM( EA, SET(1,RM(EA)) ); } /* SET 1,(XY+o) */
+OP(xycb,cf) { A = SET(1, RM(EA) ); WM( EA,A ); } /* SET 1,A=(XY+o) */
+
+OP(xycb,d0) { B = SET(2, RM(EA) ); WM( EA,B ); } /* SET 2,B=(XY+o) */
+OP(xycb,d1) { C = SET(2, RM(EA) ); WM( EA,C ); } /* SET 2,C=(XY+o) */
+OP(xycb,d2) { D = SET(2, RM(EA) ); WM( EA,D ); } /* SET 2,D=(XY+o) */
+OP(xycb,d3) { E = SET(2, RM(EA) ); WM( EA,E ); } /* SET 2,E=(XY+o) */
+OP(xycb,d4) { H = SET(2, RM(EA) ); WM( EA,H ); } /* SET 2,H=(XY+o) */
+OP(xycb,d5) { L = SET(2, RM(EA) ); WM( EA,L ); } /* SET 2,L=(XY+o) */
+OP(xycb,d6) { WM( EA, SET(2,RM(EA)) ); } /* SET 2,(XY+o) */
+OP(xycb,d7) { A = SET(2, RM(EA) ); WM( EA,A ); } /* SET 2,A=(XY+o) */
+
+OP(xycb,d8) { B = SET(3, RM(EA) ); WM( EA,B ); } /* SET 3,B=(XY+o) */
+OP(xycb,d9) { C = SET(3, RM(EA) ); WM( EA,C ); } /* SET 3,C=(XY+o) */
+OP(xycb,da) { D = SET(3, RM(EA) ); WM( EA,D ); } /* SET 3,D=(XY+o) */
+OP(xycb,db) { E = SET(3, RM(EA) ); WM( EA,E ); } /* SET 3,E=(XY+o) */
+OP(xycb,dc) { H = SET(3, RM(EA) ); WM( EA,H ); } /* SET 3,H=(XY+o) */
+OP(xycb,dd) { L = SET(3, RM(EA) ); WM( EA,L ); } /* SET 3,L=(XY+o) */
+OP(xycb,de) { WM( EA, SET(3,RM(EA)) ); } /* SET 3,(XY+o) */
+OP(xycb,df) { A = SET(3, RM(EA) ); WM( EA,A ); } /* SET 3,A=(XY+o) */
+
+OP(xycb,e0) { B = SET(4, RM(EA) ); WM( EA,B ); } /* SET 4,B=(XY+o) */
+OP(xycb,e1) { C = SET(4, RM(EA) ); WM( EA,C ); } /* SET 4,C=(XY+o) */
+OP(xycb,e2) { D = SET(4, RM(EA) ); WM( EA,D ); } /* SET 4,D=(XY+o) */
+OP(xycb,e3) { E = SET(4, RM(EA) ); WM( EA,E ); } /* SET 4,E=(XY+o) */
+OP(xycb,e4) { H = SET(4, RM(EA) ); WM( EA,H ); } /* SET 4,H=(XY+o) */
+OP(xycb,e5) { L = SET(4, RM(EA) ); WM( EA,L ); } /* SET 4,L=(XY+o) */
+OP(xycb,e6) { WM( EA, SET(4,RM(EA)) ); } /* SET 4,(XY+o) */
+OP(xycb,e7) { A = SET(4, RM(EA) ); WM( EA,A ); } /* SET 4,A=(XY+o) */
+
+OP(xycb,e8) { B = SET(5, RM(EA) ); WM( EA,B ); } /* SET 5,B=(XY+o) */
+OP(xycb,e9) { C = SET(5, RM(EA) ); WM( EA,C ); } /* SET 5,C=(XY+o) */
+OP(xycb,ea) { D = SET(5, RM(EA) ); WM( EA,D ); } /* SET 5,D=(XY+o) */
+OP(xycb,eb) { E = SET(5, RM(EA) ); WM( EA,E ); } /* SET 5,E=(XY+o) */
+OP(xycb,ec) { H = SET(5, RM(EA) ); WM( EA,H ); } /* SET 5,H=(XY+o) */
+OP(xycb,ed) { L = SET(5, RM(EA) ); WM( EA,L ); } /* SET 5,L=(XY+o) */
+OP(xycb,ee) { WM( EA, SET(5,RM(EA)) ); } /* SET 5,(XY+o) */
+OP(xycb,ef) { A = SET(5, RM(EA) ); WM( EA,A ); } /* SET 5,A=(XY+o) */
+
+OP(xycb,f0) { B = SET(6, RM(EA) ); WM( EA,B ); } /* SET 6,B=(XY+o) */
+OP(xycb,f1) { C = SET(6, RM(EA) ); WM( EA,C ); } /* SET 6,C=(XY+o) */
+OP(xycb,f2) { D = SET(6, RM(EA) ); WM( EA,D ); } /* SET 6,D=(XY+o) */
+OP(xycb,f3) { E = SET(6, RM(EA) ); WM( EA,E ); } /* SET 6,E=(XY+o) */
+OP(xycb,f4) { H = SET(6, RM(EA) ); WM( EA,H ); } /* SET 6,H=(XY+o) */
+OP(xycb,f5) { L = SET(6, RM(EA) ); WM( EA,L ); } /* SET 6,L=(XY+o) */
+OP(xycb,f6) { WM( EA, SET(6,RM(EA)) ); } /* SET 6,(XY+o) */
+OP(xycb,f7) { A = SET(6, RM(EA) ); WM( EA,A ); } /* SET 6,A=(XY+o) */
+
+OP(xycb,f8) { B = SET(7, RM(EA) ); WM( EA,B ); } /* SET 7,B=(XY+o) */
+OP(xycb,f9) { C = SET(7, RM(EA) ); WM( EA,C ); } /* SET 7,C=(XY+o) */
+OP(xycb,fa) { D = SET(7, RM(EA) ); WM( EA,D ); } /* SET 7,D=(XY+o) */
+OP(xycb,fb) { E = SET(7, RM(EA) ); WM( EA,E ); } /* SET 7,E=(XY+o) */
+OP(xycb,fc) { H = SET(7, RM(EA) ); WM( EA,H ); } /* SET 7,H=(XY+o) */
+OP(xycb,fd) { L = SET(7, RM(EA) ); WM( EA,L ); } /* SET 7,L=(XY+o) */
+OP(xycb,fe) { WM( EA, SET(7,RM(EA)) ); } /* SET 7,(XY+o) */
+OP(xycb,ff) { A = SET(7, RM(EA) ); WM( EA,A ); } /* SET 7,A=(XY+o) */
+
+OP(illegal,1) {
+ logerror("Z80 #%d ill. opcode $%02x $%02x\n",
+ cpu_getactivecpu(), cpu_readop((PCD-1)&0xffff), cpu_readop(PCD));
+}
+
+/**********************************************************
+ * IX register related opcodes (DD prefix)
+ **********************************************************/
+OP(dd,00) { illegal_1(); op_00(); } /* DB DD */
+OP(dd,01) { illegal_1(); op_01(); } /* DB DD */
+OP(dd,02) { illegal_1(); op_02(); } /* DB DD */
+OP(dd,03) { illegal_1(); op_03(); } /* DB DD */
+OP(dd,04) { illegal_1(); op_04(); } /* DB DD */
+OP(dd,05) { illegal_1(); op_05(); } /* DB DD */
+OP(dd,06) { illegal_1(); op_06(); } /* DB DD */
+OP(dd,07) { illegal_1(); op_07(); } /* DB DD */
+
+OP(dd,08) { illegal_1(); op_08(); } /* DB DD */
+OP(dd,09) { R++; ADD16(ix,bc); } /* ADD IX,BC */
+OP(dd,0a) { illegal_1(); op_0a(); } /* DB DD */
+OP(dd,0b) { illegal_1(); op_0b(); } /* DB DD */
+OP(dd,0c) { illegal_1(); op_0c(); } /* DB DD */
+OP(dd,0d) { illegal_1(); op_0d(); } /* DB DD */
+OP(dd,0e) { illegal_1(); op_0e(); } /* DB DD */
+OP(dd,0f) { illegal_1(); op_0f(); } /* DB DD */
+
+OP(dd,10) { illegal_1(); op_10(); } /* DB DD */
+OP(dd,11) { illegal_1(); op_11(); } /* DB DD */
+OP(dd,12) { illegal_1(); op_12(); } /* DB DD */
+OP(dd,13) { illegal_1(); op_13(); } /* DB DD */
+OP(dd,14) { illegal_1(); op_14(); } /* DB DD */
+OP(dd,15) { illegal_1(); op_15(); } /* DB DD */
+OP(dd,16) { illegal_1(); op_16(); } /* DB DD */
+OP(dd,17) { illegal_1(); op_17(); } /* DB DD */
+
+OP(dd,18) { illegal_1(); op_18(); } /* DB DD */
+OP(dd,19) { R++; ADD16(ix,de); } /* ADD IX,DE */
+OP(dd,1a) { illegal_1(); op_1a(); } /* DB DD */
+OP(dd,1b) { illegal_1(); op_1b(); } /* DB DD */
+OP(dd,1c) { illegal_1(); op_1c(); } /* DB DD */
+OP(dd,1d) { illegal_1(); op_1d(); } /* DB DD */
+OP(dd,1e) { illegal_1(); op_1e(); } /* DB DD */
+OP(dd,1f) { illegal_1(); op_1f(); } /* DB DD */
+
+OP(dd,20) { illegal_1(); op_20(); } /* DB DD */
+OP(dd,21) { R++; IX = ARG16(); } /* LD IX,w */
+OP(dd,22) { R++; EA = ARG16(); WM16( EA, &Z80.ix ); } /* LD (w),IX */
+OP(dd,23) { R++; IX++; } /* INC IX */
+OP(dd,24) { R++; HX = INC(HX); } /* INC HX */
+OP(dd,25) { R++; HX = DEC(HX); } /* DEC HX */
+OP(dd,26) { R++; HX = ARG(); } /* LD HX,n */
+OP(dd,27) { illegal_1(); op_27(); } /* DB DD */
+
+OP(dd,28) { illegal_1(); op_28(); } /* DB DD */
+OP(dd,29) { R++; ADD16(ix,ix); } /* ADD IX,IX */
+OP(dd,2a) { R++; EA = ARG16(); RM16( EA, &Z80.ix ); } /* LD IX,(w) */
+OP(dd,2b) { R++; IX--; } /* DEC IX */
+OP(dd,2c) { R++; LX = INC(LX); } /* INC LX */
+OP(dd,2d) { R++; LX = DEC(LX); } /* DEC LX */
+OP(dd,2e) { R++; LX = ARG(); } /* LD LX,n */
+OP(dd,2f) { illegal_1(); op_2f(); } /* DB DD */
+
+OP(dd,30) { illegal_1(); op_30(); } /* DB DD */
+OP(dd,31) { illegal_1(); op_31(); } /* DB DD */
+OP(dd,32) { illegal_1(); op_32(); } /* DB DD */
+OP(dd,33) { illegal_1(); op_33(); } /* DB DD */
+OP(dd,34) { R++; EAX; WM( EA, INC(RM(EA)) ); } /* INC (IX+o) */
+OP(dd,35) { R++; EAX; WM( EA, DEC(RM(EA)) ); } /* DEC (IX+o) */
+OP(dd,36) { R++; EAX; WM( EA, ARG() ); } /* LD (IX+o),n */
+OP(dd,37) { illegal_1(); op_37(); } /* DB DD */
+
+OP(dd,38) { illegal_1(); op_38(); } /* DB DD */
+OP(dd,39) { R++; ADD16(ix,sp); } /* ADD IX,SP */
+OP(dd,3a) { illegal_1(); op_3a(); } /* DB DD */
+OP(dd,3b) { illegal_1(); op_3b(); } /* DB DD */
+OP(dd,3c) { illegal_1(); op_3c(); } /* DB DD */
+OP(dd,3d) { illegal_1(); op_3d(); } /* DB DD */
+OP(dd,3e) { illegal_1(); op_3e(); } /* DB DD */
+OP(dd,3f) { illegal_1(); op_3f(); } /* DB DD */
+
+OP(dd,40) { illegal_1(); op_40(); } /* DB DD */
+OP(dd,41) { illegal_1(); op_41(); } /* DB DD */
+OP(dd,42) { illegal_1(); op_42(); } /* DB DD */
+OP(dd,43) { illegal_1(); op_43(); } /* DB DD */
+OP(dd,44) { R++; B = HX; } /* LD B,HX */
+OP(dd,45) { R++; B = LX; } /* LD B,LX */
+OP(dd,46) { R++; EAX; B = RM(EA); } /* LD B,(IX+o) */
+OP(dd,47) { illegal_1(); op_47(); } /* DB DD */
+
+OP(dd,48) { illegal_1(); op_48(); } /* DB DD */
+OP(dd,49) { illegal_1(); op_49(); } /* DB DD */
+OP(dd,4a) { illegal_1(); op_4a(); } /* DB DD */
+OP(dd,4b) { illegal_1(); op_4b(); } /* DB DD */
+OP(dd,4c) { R++; C = HX; } /* LD C,HX */
+OP(dd,4d) { R++; C = LX; } /* LD C,LX */
+OP(dd,4e) { R++; EAX; C = RM(EA); } /* LD C,(IX+o) */
+OP(dd,4f) { illegal_1(); op_4f(); } /* DB DD */
+
+OP(dd,50) { illegal_1(); op_50(); } /* DB DD */
+OP(dd,51) { illegal_1(); op_51(); } /* DB DD */
+OP(dd,52) { illegal_1(); op_52(); } /* DB DD */
+OP(dd,53) { illegal_1(); op_53(); } /* DB DD */
+OP(dd,54) { R++; D = HX; } /* LD D,HX */
+OP(dd,55) { R++; D = LX; } /* LD D,LX */
+OP(dd,56) { R++; EAX; D = RM(EA); } /* LD D,(IX+o) */
+OP(dd,57) { illegal_1(); op_57(); } /* DB DD */
+
+OP(dd,58) { illegal_1(); op_58(); } /* DB DD */
+OP(dd,59) { illegal_1(); op_59(); } /* DB DD */
+OP(dd,5a) { illegal_1(); op_5a(); } /* DB DD */
+OP(dd,5b) { illegal_1(); op_5b(); } /* DB DD */
+OP(dd,5c) { R++; E = HX; } /* LD E,HX */
+OP(dd,5d) { R++; E = LX; } /* LD E,LX */
+OP(dd,5e) { R++; EAX; E = RM(EA); } /* LD E,(IX+o) */
+OP(dd,5f) { illegal_1(); op_5f(); } /* DB DD */
+
+OP(dd,60) { R++; HX = B; } /* LD HX,B */
+OP(dd,61) { R++; HX = C; } /* LD HX,C */
+OP(dd,62) { R++; HX = D; } /* LD HX,D */
+OP(dd,63) { R++; HX = E; } /* LD HX,E */
+OP(dd,64) { } /* LD HX,HX */
+OP(dd,65) { R++; HX = LX; } /* LD HX,LX */
+OP(dd,66) { R++; EAX; H = RM(EA); } /* LD H,(IX+o) */
+OP(dd,67) { R++; HX = A; } /* LD HX,A */
+
+OP(dd,68) { R++; LX = B; } /* LD LX,B */
+OP(dd,69) { R++; LX = C; } /* LD LX,C */
+OP(dd,6a) { R++; LX = D; } /* LD LX,D */
+OP(dd,6b) { R++; LX = E; } /* LD LX,E */
+OP(dd,6c) { R++; LX = HX; } /* LD LX,HX */
+OP(dd,6d) { } /* LD LX,LX */
+OP(dd,6e) { R++; EAX; L = RM(EA); } /* LD L,(IX+o) */
+OP(dd,6f) { R++; LX = A; } /* LD LX,A */
+
+OP(dd,70) { R++; EAX; WM( EA, B ); } /* LD (IX+o),B */
+OP(dd,71) { R++; EAX; WM( EA, C ); } /* LD (IX+o),C */
+OP(dd,72) { R++; EAX; WM( EA, D ); } /* LD (IX+o),D */
+OP(dd,73) { R++; EAX; WM( EA, E ); } /* LD (IX+o),E */
+OP(dd,74) { R++; EAX; WM( EA, H ); } /* LD (IX+o),H */
+OP(dd,75) { R++; EAX; WM( EA, L ); } /* LD (IX+o),L */
+OP(dd,76) { illegal_1(); op_76(); } /* DB DD */
+OP(dd,77) { R++; EAX; WM( EA, A ); } /* LD (IX+o),A */
+
+OP(dd,78) { illegal_1(); op_78(); } /* DB DD */
+OP(dd,79) { illegal_1(); op_79(); } /* DB DD */
+OP(dd,7a) { illegal_1(); op_7a(); } /* DB DD */
+OP(dd,7b) { illegal_1(); op_7b(); } /* DB DD */
+OP(dd,7c) { R++; A = HX; } /* LD A,HX */
+OP(dd,7d) { R++; A = LX; } /* LD A,LX */
+OP(dd,7e) { R++; EAX; A = RM(EA); } /* LD A,(IX+o) */
+OP(dd,7f) { illegal_1(); op_7f(); } /* DB DD */
+
+OP(dd,80) { illegal_1(); op_80(); } /* DB DD */
+OP(dd,81) { illegal_1(); op_81(); } /* DB DD */
+OP(dd,82) { illegal_1(); op_82(); } /* DB DD */
+OP(dd,83) { illegal_1(); op_83(); } /* DB DD */
+OP(dd,84) { R++; ADD(HX); } /* ADD A,HX */
+OP(dd,85) { R++; ADD(LX); } /* ADD A,LX */
+OP(dd,86) { R++; EAX; ADD(RM(EA)); } /* ADD A,(IX+o) */
+OP(dd,87) { illegal_1(); op_87(); } /* DB DD */
+
+OP(dd,88) { illegal_1(); op_88(); } /* DB DD */
+OP(dd,89) { illegal_1(); op_89(); } /* DB DD */
+OP(dd,8a) { illegal_1(); op_8a(); } /* DB DD */
+OP(dd,8b) { illegal_1(); op_8b(); } /* DB DD */
+OP(dd,8c) { R++; ADC(HX); } /* ADC A,HX */
+OP(dd,8d) { R++; ADC(LX); } /* ADC A,LX */
+OP(dd,8e) { R++; EAX; ADC(RM(EA)); } /* ADC A,(IX+o) */
+OP(dd,8f) { illegal_1(); op_8f(); } /* DB DD */
+
+OP(dd,90) { illegal_1(); op_90(); } /* DB DD */
+OP(dd,91) { illegal_1(); op_91(); } /* DB DD */
+OP(dd,92) { illegal_1(); op_92(); } /* DB DD */
+OP(dd,93) { illegal_1(); op_93(); } /* DB DD */
+OP(dd,94) { R++; SUB(HX); } /* SUB HX */
+OP(dd,95) { R++; SUB(LX); } /* SUB LX */
+OP(dd,96) { R++; EAX; SUB(RM(EA)); } /* SUB (IX+o) */
+OP(dd,97) { illegal_1(); op_97(); } /* DB DD */
+
+OP(dd,98) { illegal_1(); op_98(); } /* DB DD */
+OP(dd,99) { illegal_1(); op_99(); } /* DB DD */
+OP(dd,9a) { illegal_1(); op_9a(); } /* DB DD */
+OP(dd,9b) { illegal_1(); op_9b(); } /* DB DD */
+OP(dd,9c) { R++; SBC(HX); } /* SBC A,HX */
+OP(dd,9d) { R++; SBC(LX); } /* SBC A,LX */
+OP(dd,9e) { R++; EAX; SBC(RM(EA)); } /* SBC A,(IX+o) */
+OP(dd,9f) { illegal_1(); op_9f(); } /* DB DD */
+
+OP(dd,a0) { illegal_1(); op_a0(); } /* DB DD */
+OP(dd,a1) { illegal_1(); op_a1(); } /* DB DD */
+OP(dd,a2) { illegal_1(); op_a2(); } /* DB DD */
+OP(dd,a3) { illegal_1(); op_a3(); } /* DB DD */
+OP(dd,a4) { R++; AND(HX); } /* AND HX */
+OP(dd,a5) { R++; AND(LX); } /* AND LX */
+OP(dd,a6) { R++; EAX; AND(RM(EA)); } /* AND (IX+o) */
+OP(dd,a7) { illegal_1(); op_a7(); } /* DB DD */
+
+OP(dd,a8) { illegal_1(); op_a8(); } /* DB DD */
+OP(dd,a9) { illegal_1(); op_a9(); } /* DB DD */
+OP(dd,aa) { illegal_1(); op_aa(); } /* DB DD */
+OP(dd,ab) { illegal_1(); op_ab(); } /* DB DD */
+OP(dd,ac) { R++; XOR(HX); } /* XOR HX */
+OP(dd,ad) { R++; XOR(LX); } /* XOR LX */
+OP(dd,ae) { R++; EAX; XOR(RM(EA)); } /* XOR (IX+o) */
+OP(dd,af) { illegal_1(); op_af(); } /* DB DD */
+
+OP(dd,b0) { illegal_1(); op_b0(); } /* DB DD */
+OP(dd,b1) { illegal_1(); op_b1(); } /* DB DD */
+OP(dd,b2) { illegal_1(); op_b2(); } /* DB DD */
+OP(dd,b3) { illegal_1(); op_b3(); } /* DB DD */
+OP(dd,b4) { R++; OR(HX); } /* OR HX */
+OP(dd,b5) { R++; OR(LX); } /* OR LX */
+OP(dd,b6) { R++; EAX; OR(RM(EA)); } /* OR (IX+o) */
+OP(dd,b7) { illegal_1(); op_b7(); } /* DB DD */
+
+OP(dd,b8) { illegal_1(); op_b8(); } /* DB DD */
+OP(dd,b9) { illegal_1(); op_b9(); } /* DB DD */
+OP(dd,ba) { illegal_1(); op_ba(); } /* DB DD */
+OP(dd,bb) { illegal_1(); op_bb(); } /* DB DD */
+OP(dd,bc) { R++; CP(HX); } /* CP HX */
+OP(dd,bd) { R++; CP(LX); } /* CP LX */
+OP(dd,be) { R++; EAX; CP(RM(EA)); } /* CP (IX+o) */
+OP(dd,bf) { illegal_1(); op_bf(); } /* DB DD */
+
+OP(dd,c0) { illegal_1(); op_c0(); } /* DB DD */
+OP(dd,c1) { illegal_1(); op_c1(); } /* DB DD */
+OP(dd,c2) { illegal_1(); op_c2(); } /* DB DD */
+OP(dd,c3) { illegal_1(); op_c3(); } /* DB DD */
+OP(dd,c4) { illegal_1(); op_c4(); } /* DB DD */
+OP(dd,c5) { illegal_1(); op_c5(); } /* DB DD */
+OP(dd,c6) { illegal_1(); op_c6(); } /* DB DD */
+OP(dd,c7) { illegal_1(); op_c7(); } /* DB DD */
+
+OP(dd,c8) { illegal_1(); op_c8(); } /* DB DD */
+OP(dd,c9) { illegal_1(); op_c9(); } /* DB DD */
+OP(dd,ca) { illegal_1(); op_ca(); } /* DB DD */
+OP(dd,cb) { R++; EAX; EXEC(xycb,ARG()); } /* ** DD CB xx */
+OP(dd,cc) { illegal_1(); op_cc(); } /* DB DD */
+OP(dd,cd) { illegal_1(); op_cd(); } /* DB DD */
+OP(dd,ce) { illegal_1(); op_ce(); } /* DB DD */
+OP(dd,cf) { illegal_1(); op_cf(); } /* DB DD */
+
+OP(dd,d0) { illegal_1(); op_d0(); } /* DB DD */
+OP(dd,d1) { illegal_1(); op_d1(); } /* DB DD */
+OP(dd,d2) { illegal_1(); op_d2(); } /* DB DD */
+OP(dd,d3) { illegal_1(); op_d3(); } /* DB DD */
+OP(dd,d4) { illegal_1(); op_d4(); } /* DB DD */
+OP(dd,d5) { illegal_1(); op_d5(); } /* DB DD */
+OP(dd,d6) { illegal_1(); op_d6(); } /* DB DD */
+OP(dd,d7) { illegal_1(); op_d7(); } /* DB DD */
+
+OP(dd,d8) { illegal_1(); op_d8(); } /* DB DD */
+OP(dd,d9) { illegal_1(); op_d9(); } /* DB DD */
+OP(dd,da) { illegal_1(); op_da(); } /* DB DD */
+OP(dd,db) { illegal_1(); op_db(); } /* DB DD */
+OP(dd,dc) { illegal_1(); op_dc(); } /* DB DD */
+OP(dd,dd) { illegal_1(); op_dd(); } /* DB DD */
+OP(dd,de) { illegal_1(); op_de(); } /* DB DD */
+OP(dd,df) { illegal_1(); op_df(); } /* DB DD */
+
+OP(dd,e0) { illegal_1(); op_e0(); } /* DB DD */
+OP(dd,e1) { R++; POP( ix ); } /* POP IX */
+OP(dd,e2) { illegal_1(); op_e2(); } /* DB DD */
+OP(dd,e3) { R++; EXSP( ix ); } /* EX (SP),IX */
+OP(dd,e4) { illegal_1(); op_e4(); } /* DB DD */
+OP(dd,e5) { R++; PUSH( ix ); } /* PUSH IX */
+OP(dd,e6) { illegal_1(); op_e6(); } /* DB DD */
+OP(dd,e7) { illegal_1(); op_e7(); } /* DB DD */
+
+OP(dd,e8) { illegal_1(); op_e8(); } /* DB DD */
+OP(dd,e9) { R++; PC = IX; change_pc(PCD); } /* JP (IX) */
+OP(dd,ea) { illegal_1(); op_ea(); } /* DB DD */
+OP(dd,eb) { illegal_1(); op_eb(); } /* DB DD */
+OP(dd,ec) { illegal_1(); op_ec(); } /* DB DD */
+OP(dd,ed) { illegal_1(); op_ed(); } /* DB DD */
+OP(dd,ee) { illegal_1(); op_ee(); } /* DB DD */
+OP(dd,ef) { illegal_1(); op_ef(); } /* DB DD */
+
+OP(dd,f0) { illegal_1(); op_f0(); } /* DB DD */
+OP(dd,f1) { illegal_1(); op_f1(); } /* DB DD */
+OP(dd,f2) { illegal_1(); op_f2(); } /* DB DD */
+OP(dd,f3) { illegal_1(); op_f3(); } /* DB DD */
+OP(dd,f4) { illegal_1(); op_f4(); } /* DB DD */
+OP(dd,f5) { illegal_1(); op_f5(); } /* DB DD */
+OP(dd,f6) { illegal_1(); op_f6(); } /* DB DD */
+OP(dd,f7) { illegal_1(); op_f7(); } /* DB DD */
+
+OP(dd,f8) { illegal_1(); op_f8(); } /* DB DD */
+OP(dd,f9) { R++; SP = IX; } /* LD SP,IX */
+OP(dd,fa) { illegal_1(); op_fa(); } /* DB DD */
+OP(dd,fb) { illegal_1(); op_fb(); } /* DB DD */
+OP(dd,fc) { illegal_1(); op_fc(); } /* DB DD */
+OP(dd,fd) { illegal_1(); op_fd(); } /* DB DD */
+OP(dd,fe) { illegal_1(); op_fe(); } /* DB DD */
+OP(dd,ff) { illegal_1(); op_ff(); } /* DB DD */
+
+/**********************************************************
+ * IY register related opcodes (FD prefix)
+ **********************************************************/
+OP(fd,00) { illegal_1(); op_00(); } /* DB FD */
+OP(fd,01) { illegal_1(); op_01(); } /* DB FD */
+OP(fd,02) { illegal_1(); op_02(); } /* DB FD */
+OP(fd,03) { illegal_1(); op_03(); } /* DB FD */
+OP(fd,04) { illegal_1(); op_04(); } /* DB FD */
+OP(fd,05) { illegal_1(); op_05(); } /* DB FD */
+OP(fd,06) { illegal_1(); op_06(); } /* DB FD */
+OP(fd,07) { illegal_1(); op_07(); } /* DB FD */
+
+OP(fd,08) { illegal_1(); op_08(); } /* DB FD */
+OP(fd,09) { R++; ADD16(iy,bc); } /* ADD IY,BC */
+OP(fd,0a) { illegal_1(); op_0a(); } /* DB FD */
+OP(fd,0b) { illegal_1(); op_0b(); } /* DB FD */
+OP(fd,0c) { illegal_1(); op_0c(); } /* DB FD */
+OP(fd,0d) { illegal_1(); op_0d(); } /* DB FD */
+OP(fd,0e) { illegal_1(); op_0e(); } /* DB FD */
+OP(fd,0f) { illegal_1(); op_0f(); } /* DB FD */
+
+OP(fd,10) { illegal_1(); op_10(); } /* DB FD */
+OP(fd,11) { illegal_1(); op_11(); } /* DB FD */
+OP(fd,12) { illegal_1(); op_12(); } /* DB FD */
+OP(fd,13) { illegal_1(); op_13(); } /* DB FD */
+OP(fd,14) { illegal_1(); op_14(); } /* DB FD */
+OP(fd,15) { illegal_1(); op_15(); } /* DB FD */
+OP(fd,16) { illegal_1(); op_16(); } /* DB FD */
+OP(fd,17) { illegal_1(); op_17(); } /* DB FD */
+
+OP(fd,18) { illegal_1(); op_18(); } /* DB FD */
+OP(fd,19) { R++; ADD16(iy,de); } /* ADD IY,DE */
+OP(fd,1a) { illegal_1(); op_1a(); } /* DB FD */
+OP(fd,1b) { illegal_1(); op_1b(); } /* DB FD */
+OP(fd,1c) { illegal_1(); op_1c(); } /* DB FD */
+OP(fd,1d) { illegal_1(); op_1d(); } /* DB FD */
+OP(fd,1e) { illegal_1(); op_1e(); } /* DB FD */
+OP(fd,1f) { illegal_1(); op_1f(); } /* DB FD */
+
+OP(fd,20) { illegal_1(); op_20(); } /* DB FD */
+OP(fd,21) { R++; IY = ARG16(); } /* LD IY,w */
+OP(fd,22) { R++; EA = ARG16(); WM16( EA, &Z80.iy ); } /* LD (w),IY */
+OP(fd,23) { R++; IY++; } /* INC IY */
+OP(fd,24) { R++; HY = INC(HY); } /* INC HY */
+OP(fd,25) { R++; HY = DEC(HY); } /* DEC HY */
+OP(fd,26) { R++; HY = ARG(); } /* LD HY,n */
+OP(fd,27) { illegal_1(); op_27(); } /* DB FD */
+
+OP(fd,28) { illegal_1(); op_28(); } /* DB FD */
+OP(fd,29) { R++; ADD16(iy,iy); } /* ADD IY,IY */
+OP(fd,2a) { R++; EA = ARG16(); RM16( EA, &Z80.iy ); } /* LD IY,(w) */
+OP(fd,2b) { R++; IY--; } /* DEC IY */
+OP(fd,2c) { R++; LY = INC(LY); } /* INC LY */
+OP(fd,2d) { R++; LY = DEC(LY); } /* DEC LY */
+OP(fd,2e) { R++; LY = ARG(); } /* LD LY,n */
+OP(fd,2f) { illegal_1(); op_2f(); } /* DB FD */
+
+OP(fd,30) { illegal_1(); op_30(); } /* DB FD */
+OP(fd,31) { illegal_1(); op_31(); } /* DB FD */
+OP(fd,32) { illegal_1(); op_32(); } /* DB FD */
+OP(fd,33) { illegal_1(); op_33(); } /* DB FD */
+OP(fd,34) { R++; EAY; WM( EA, INC(RM(EA)) ); } /* INC (IY+o) */
+OP(fd,35) { R++; EAY; WM( EA, DEC(RM(EA)) ); } /* DEC (IY+o) */
+OP(fd,36) { R++; EAY; WM( EA, ARG() ); } /* LD (IY+o),n */
+OP(fd,37) { illegal_1(); op_37(); } /* DB FD */
+
+OP(fd,38) { illegal_1(); op_38(); } /* DB FD */
+OP(fd,39) { R++; ADD16(iy,sp); } /* ADD IY,SP */
+OP(fd,3a) { illegal_1(); op_3a(); } /* DB FD */
+OP(fd,3b) { illegal_1(); op_3b(); } /* DB FD */
+OP(fd,3c) { illegal_1(); op_3c(); } /* DB FD */
+OP(fd,3d) { illegal_1(); op_3d(); } /* DB FD */
+OP(fd,3e) { illegal_1(); op_3e(); } /* DB FD */
+OP(fd,3f) { illegal_1(); op_3f(); } /* DB FD */
+
+OP(fd,40) { illegal_1(); op_40(); } /* DB FD */
+OP(fd,41) { illegal_1(); op_41(); } /* DB FD */
+OP(fd,42) { illegal_1(); op_42(); } /* DB FD */
+OP(fd,43) { illegal_1(); op_43(); } /* DB FD */
+OP(fd,44) { R++; B = HY; } /* LD B,HY */
+OP(fd,45) { R++; B = LY; } /* LD B,LY */
+OP(fd,46) { R++; EAY; B = RM(EA); } /* LD B,(IY+o) */
+OP(fd,47) { illegal_1(); op_47(); } /* DB FD */
+
+OP(fd,48) { illegal_1(); op_48(); } /* DB FD */
+OP(fd,49) { illegal_1(); op_49(); } /* DB FD */
+OP(fd,4a) { illegal_1(); op_4a(); } /* DB FD */
+OP(fd,4b) { illegal_1(); op_4b(); } /* DB FD */
+OP(fd,4c) { R++; C = HY; } /* LD C,HY */
+OP(fd,4d) { R++; C = LY; } /* LD C,LY */
+OP(fd,4e) { R++; EAY; C = RM(EA); } /* LD C,(IY+o) */
+OP(fd,4f) { illegal_1(); op_4f(); } /* DB FD */
+
+OP(fd,50) { illegal_1(); op_50(); } /* DB FD */
+OP(fd,51) { illegal_1(); op_51(); } /* DB FD */
+OP(fd,52) { illegal_1(); op_52(); } /* DB FD */
+OP(fd,53) { illegal_1(); op_53(); } /* DB FD */
+OP(fd,54) { R++; D = HY; } /* LD D,HY */
+OP(fd,55) { R++; D = LY; } /* LD D,LY */
+OP(fd,56) { R++; EAY; D = RM(EA); } /* LD D,(IY+o) */
+OP(fd,57) { illegal_1(); op_57(); } /* DB FD */
+
+OP(fd,58) { illegal_1(); op_58(); } /* DB FD */
+OP(fd,59) { illegal_1(); op_59(); } /* DB FD */
+OP(fd,5a) { illegal_1(); op_5a(); } /* DB FD */
+OP(fd,5b) { illegal_1(); op_5b(); } /* DB FD */
+OP(fd,5c) { R++; E = HY; } /* LD E,HY */
+OP(fd,5d) { R++; E = LY; } /* LD E,LY */
+OP(fd,5e) { R++; EAY; E = RM(EA); } /* LD E,(IY+o) */
+OP(fd,5f) { illegal_1(); op_5f(); } /* DB FD */
+
+OP(fd,60) { R++; HY = B; } /* LD HY,B */
+OP(fd,61) { R++; HY = C; } /* LD HY,C */
+OP(fd,62) { R++; HY = D; } /* LD HY,D */
+OP(fd,63) { R++; HY = E; } /* LD HY,E */
+OP(fd,64) { R++; } /* LD HY,HY */
+OP(fd,65) { R++; HY = LY; } /* LD HY,LY */
+OP(fd,66) { R++; EAY; H = RM(EA); } /* LD H,(IY+o) */
+OP(fd,67) { R++; HY = A; } /* LD HY,A */
+
+OP(fd,68) { R++; LY = B; } /* LD LY,B */
+OP(fd,69) { R++; LY = C; } /* LD LY,C */
+OP(fd,6a) { R++; LY = D; } /* LD LY,D */
+OP(fd,6b) { R++; LY = E; } /* LD LY,E */
+OP(fd,6c) { R++; LY = HY; } /* LD LY,HY */
+OP(fd,6d) { R++; } /* LD LY,LY */
+OP(fd,6e) { R++; EAY; L = RM(EA); } /* LD L,(IY+o) */
+OP(fd,6f) { R++; LY = A; } /* LD LY,A */
+
+OP(fd,70) { R++; EAY; WM( EA, B ); } /* LD (IY+o),B */
+OP(fd,71) { R++; EAY; WM( EA, C ); } /* LD (IY+o),C */
+OP(fd,72) { R++; EAY; WM( EA, D ); } /* LD (IY+o),D */
+OP(fd,73) { R++; EAY; WM( EA, E ); } /* LD (IY+o),E */
+OP(fd,74) { R++; EAY; WM( EA, H ); } /* LD (IY+o),H */
+OP(fd,75) { R++; EAY; WM( EA, L ); } /* LD (IY+o),L */
+OP(fd,76) { illegal_1(); op_76(); } /* DB FD */
+OP(fd,77) { R++; EAY; WM( EA, A ); } /* LD (IY+o),A */
+
+OP(fd,78) { illegal_1(); op_78(); } /* DB FD */
+OP(fd,79) { illegal_1(); op_79(); } /* DB FD */
+OP(fd,7a) { illegal_1(); op_7a(); } /* DB FD */
+OP(fd,7b) { illegal_1(); op_7b(); } /* DB FD */
+OP(fd,7c) { R++; A = HY; } /* LD A,HY */
+OP(fd,7d) { R++; A = LY; } /* LD A,LY */
+OP(fd,7e) { R++; EAY; A = RM(EA); } /* LD A,(IY+o) */
+OP(fd,7f) { illegal_1(); op_7f(); } /* DB FD */
+
+OP(fd,80) { illegal_1(); op_80(); } /* DB FD */
+OP(fd,81) { illegal_1(); op_81(); } /* DB FD */
+OP(fd,82) { illegal_1(); op_82(); } /* DB FD */
+OP(fd,83) { illegal_1(); op_83(); } /* DB FD */
+OP(fd,84) { R++; ADD(HY); } /* ADD A,HY */
+OP(fd,85) { R++; ADD(LY); } /* ADD A,LY */
+OP(fd,86) { R++; EAY; ADD(RM(EA)); } /* ADD A,(IY+o) */
+OP(fd,87) { illegal_1(); op_87(); } /* DB FD */
+
+OP(fd,88) { illegal_1(); op_88(); } /* DB FD */
+OP(fd,89) { illegal_1(); op_89(); } /* DB FD */
+OP(fd,8a) { illegal_1(); op_8a(); } /* DB FD */
+OP(fd,8b) { illegal_1(); op_8b(); } /* DB FD */
+OP(fd,8c) { R++; ADC(HY); } /* ADC A,HY */
+OP(fd,8d) { R++; ADC(LY); } /* ADC A,LY */
+OP(fd,8e) { R++; EAY; ADC(RM(EA)); } /* ADC A,(IY+o) */
+OP(fd,8f) { illegal_1(); op_8f(); } /* DB FD */
+
+OP(fd,90) { illegal_1(); op_90(); } /* DB FD */
+OP(fd,91) { illegal_1(); op_91(); } /* DB FD */
+OP(fd,92) { illegal_1(); op_92(); } /* DB FD */
+OP(fd,93) { illegal_1(); op_93(); } /* DB FD */
+OP(fd,94) { R++; SUB(HY); } /* SUB HY */
+OP(fd,95) { R++; SUB(LY); } /* SUB LY */
+OP(fd,96) { R++; EAY; SUB(RM(EA)); } /* SUB (IY+o) */
+OP(fd,97) { illegal_1(); op_97(); } /* DB FD */
+
+OP(fd,98) { illegal_1(); op_98(); } /* DB FD */
+OP(fd,99) { illegal_1(); op_99(); } /* DB FD */
+OP(fd,9a) { illegal_1(); op_9a(); } /* DB FD */
+OP(fd,9b) { illegal_1(); op_9b(); } /* DB FD */
+OP(fd,9c) { R++; SBC(HY); } /* SBC A,HY */
+OP(fd,9d) { R++; SBC(LY); } /* SBC A,LY */
+OP(fd,9e) { R++; EAY; SBC(RM(EA)); } /* SBC A,(IY+o) */
+OP(fd,9f) { illegal_1(); op_9f(); } /* DB FD */
+
+OP(fd,a0) { illegal_1(); op_a0(); } /* DB FD */
+OP(fd,a1) { illegal_1(); op_a1(); } /* DB FD */
+OP(fd,a2) { illegal_1(); op_a2(); } /* DB FD */
+OP(fd,a3) { illegal_1(); op_a3(); } /* DB FD */
+OP(fd,a4) { R++; AND(HY); } /* AND HY */
+OP(fd,a5) { R++; AND(LY); } /* AND LY */
+OP(fd,a6) { R++; EAY; AND(RM(EA)); } /* AND (IY+o) */
+OP(fd,a7) { illegal_1(); op_a7(); } /* DB FD */
+
+OP(fd,a8) { illegal_1(); op_a8(); } /* DB FD */
+OP(fd,a9) { illegal_1(); op_a9(); } /* DB FD */
+OP(fd,aa) { illegal_1(); op_aa(); } /* DB FD */
+OP(fd,ab) { illegal_1(); op_ab(); } /* DB FD */
+OP(fd,ac) { R++; XOR(HY); } /* XOR HY */
+OP(fd,ad) { R++; XOR(LY); } /* XOR LY */
+OP(fd,ae) { R++; EAY; XOR(RM(EA)); } /* XOR (IY+o) */
+OP(fd,af) { illegal_1(); op_af(); } /* DB FD */
+
+OP(fd,b0) { illegal_1(); op_b0(); } /* DB FD */
+OP(fd,b1) { illegal_1(); op_b1(); } /* DB FD */
+OP(fd,b2) { illegal_1(); op_b2(); } /* DB FD */
+OP(fd,b3) { illegal_1(); op_b3(); } /* DB FD */
+OP(fd,b4) { R++; OR(HY); } /* OR HY */
+OP(fd,b5) { R++; OR(LY); } /* OR LY */
+OP(fd,b6) { R++; EAY; OR(RM(EA)); } /* OR (IY+o) */
+OP(fd,b7) { illegal_1(); op_b7(); } /* DB FD */
+
+OP(fd,b8) { illegal_1(); op_b8(); } /* DB FD */
+OP(fd,b9) { illegal_1(); op_b9(); } /* DB FD */
+OP(fd,ba) { illegal_1(); op_ba(); } /* DB FD */
+OP(fd,bb) { illegal_1(); op_bb(); } /* DB FD */
+OP(fd,bc) { R++; CP(HY); } /* CP HY */
+OP(fd,bd) { R++; CP(LY); } /* CP LY */
+OP(fd,be) { R++; EAY; CP(RM(EA)); } /* CP (IY+o) */
+OP(fd,bf) { illegal_1(); op_bf(); } /* DB FD */
+
+OP(fd,c0) { illegal_1(); op_c0(); } /* DB FD */
+OP(fd,c1) { illegal_1(); op_c1(); } /* DB FD */
+OP(fd,c2) { illegal_1(); op_c2(); } /* DB FD */
+OP(fd,c3) { illegal_1(); op_c3(); } /* DB FD */
+OP(fd,c4) { illegal_1(); op_c4(); } /* DB FD */
+OP(fd,c5) { illegal_1(); op_c5(); } /* DB FD */
+OP(fd,c6) { illegal_1(); op_c6(); } /* DB FD */
+OP(fd,c7) { illegal_1(); op_c7(); } /* DB FD */
+
+OP(fd,c8) { illegal_1(); op_c8(); } /* DB FD */
+OP(fd,c9) { illegal_1(); op_c9(); } /* DB FD */
+OP(fd,ca) { illegal_1(); op_ca(); } /* DB FD */
+OP(fd,cb) { R++; EAY; EXEC(xycb,ARG()); } /* ** FD CB xx */
+OP(fd,cc) { illegal_1(); op_cc(); } /* DB FD */
+OP(fd,cd) { illegal_1(); op_cd(); } /* DB FD */
+OP(fd,ce) { illegal_1(); op_ce(); } /* DB FD */
+OP(fd,cf) { illegal_1(); op_cf(); } /* DB FD */
+
+OP(fd,d0) { illegal_1(); op_d0(); } /* DB FD */
+OP(fd,d1) { illegal_1(); op_d1(); } /* DB FD */
+OP(fd,d2) { illegal_1(); op_d2(); } /* DB FD */
+OP(fd,d3) { illegal_1(); op_d3(); } /* DB FD */
+OP(fd,d4) { illegal_1(); op_d4(); } /* DB FD */
+OP(fd,d5) { illegal_1(); op_d5(); } /* DB FD */
+OP(fd,d6) { illegal_1(); op_d6(); } /* DB FD */
+OP(fd,d7) { illegal_1(); op_d7(); } /* DB FD */
+
+OP(fd,d8) { illegal_1(); op_d8(); } /* DB FD */
+OP(fd,d9) { illegal_1(); op_d9(); } /* DB FD */
+OP(fd,da) { illegal_1(); op_da(); } /* DB FD */
+OP(fd,db) { illegal_1(); op_db(); } /* DB FD */
+OP(fd,dc) { illegal_1(); op_dc(); } /* DB FD */
+OP(fd,dd) { illegal_1(); op_dd(); } /* DB FD */
+OP(fd,de) { illegal_1(); op_de(); } /* DB FD */
+OP(fd,df) { illegal_1(); op_df(); } /* DB FD */
+
+OP(fd,e0) { illegal_1(); op_e0(); } /* DB FD */
+OP(fd,e1) { R++; POP( iy ); } /* POP IY */
+OP(fd,e2) { illegal_1(); op_e2(); } /* DB FD */
+OP(fd,e3) { R++; EXSP( iy ); } /* EX (SP),IY */
+OP(fd,e4) { illegal_1(); op_e4(); } /* DB FD */
+OP(fd,e5) { R++; PUSH( iy ); } /* PUSH IY */
+OP(fd,e6) { illegal_1(); op_e6(); } /* DB FD */
+OP(fd,e7) { illegal_1(); op_e7(); } /* DB FD */
+
+OP(fd,e8) { illegal_1(); op_e8(); } /* DB FD */
+OP(fd,e9) { R++; PC = IY; change_pc(PCD); } /* JP (IY) */
+OP(fd,ea) { illegal_1(); op_ea(); } /* DB FD */
+OP(fd,eb) { illegal_1(); op_eb(); } /* DB FD */
+OP(fd,ec) { illegal_1(); op_ec(); } /* DB FD */
+OP(fd,ed) { illegal_1(); op_ed(); } /* DB FD */
+OP(fd,ee) { illegal_1(); op_ee(); } /* DB FD */
+OP(fd,ef) { illegal_1(); op_ef(); } /* DB FD */
+
+OP(fd,f0) { illegal_1(); op_f0(); } /* DB FD */
+OP(fd,f1) { illegal_1(); op_f1(); } /* DB FD */
+OP(fd,f2) { illegal_1(); op_f2(); } /* DB FD */
+OP(fd,f3) { illegal_1(); op_f3(); } /* DB FD */
+OP(fd,f4) { illegal_1(); op_f4(); } /* DB FD */
+OP(fd,f5) { illegal_1(); op_f5(); } /* DB FD */
+OP(fd,f6) { illegal_1(); op_f6(); } /* DB FD */
+OP(fd,f7) { illegal_1(); op_f7(); } /* DB FD */
+
+OP(fd,f8) { illegal_1(); op_f8(); } /* DB FD */
+OP(fd,f9) { R++; SP = IY; } /* LD SP,IY */
+OP(fd,fa) { illegal_1(); op_fa(); } /* DB FD */
+OP(fd,fb) { illegal_1(); op_fb(); } /* DB FD */
+OP(fd,fc) { illegal_1(); op_fc(); } /* DB FD */
+OP(fd,fd) { illegal_1(); op_fd(); } /* DB FD */
+OP(fd,fe) { illegal_1(); op_fe(); } /* DB FD */
+OP(fd,ff) { illegal_1(); op_ff(); } /* DB FD */
+
+OP(illegal,2)
+{
+ logerror("Z80 #%d ill. opcode $ed $%02x\n",
+ cpu_getactivecpu(), cpu_readop((PCD-1)&0xffff));
+}
+
+/**********************************************************
+ * special opcodes (ED prefix)
+ **********************************************************/
+OP(ed,00) { illegal_2(); } /* DB ED */
+OP(ed,01) { illegal_2(); } /* DB ED */
+OP(ed,02) { illegal_2(); } /* DB ED */
+OP(ed,03) { illegal_2(); } /* DB ED */
+OP(ed,04) { illegal_2(); } /* DB ED */
+OP(ed,05) { illegal_2(); } /* DB ED */
+OP(ed,06) { illegal_2(); } /* DB ED */
+OP(ed,07) { illegal_2(); } /* DB ED */
+
+OP(ed,08) { illegal_2(); } /* DB ED */
+OP(ed,09) { illegal_2(); } /* DB ED */
+OP(ed,0a) { illegal_2(); } /* DB ED */
+OP(ed,0b) { illegal_2(); } /* DB ED */
+OP(ed,0c) { illegal_2(); } /* DB ED */
+OP(ed,0d) { illegal_2(); } /* DB ED */
+OP(ed,0e) { illegal_2(); } /* DB ED */
+OP(ed,0f) { illegal_2(); } /* DB ED */
+
+OP(ed,10) { illegal_2(); } /* DB ED */
+OP(ed,11) { illegal_2(); } /* DB ED */
+OP(ed,12) { illegal_2(); } /* DB ED */
+OP(ed,13) { illegal_2(); } /* DB ED */
+OP(ed,14) { illegal_2(); } /* DB ED */
+OP(ed,15) { illegal_2(); } /* DB ED */
+OP(ed,16) { illegal_2(); } /* DB ED */
+OP(ed,17) { illegal_2(); } /* DB ED */
+
+OP(ed,18) { illegal_2(); } /* DB ED */
+OP(ed,19) { illegal_2(); } /* DB ED */
+OP(ed,1a) { illegal_2(); } /* DB ED */
+OP(ed,1b) { illegal_2(); } /* DB ED */
+OP(ed,1c) { illegal_2(); } /* DB ED */
+OP(ed,1d) { illegal_2(); } /* DB ED */
+OP(ed,1e) { illegal_2(); } /* DB ED */
+OP(ed,1f) { illegal_2(); } /* DB ED */
+
+OP(ed,20) { illegal_2(); } /* DB ED */
+OP(ed,21) { illegal_2(); } /* DB ED */
+OP(ed,22) { illegal_2(); } /* DB ED */
+OP(ed,23) { illegal_2(); } /* DB ED */
+OP(ed,24) { illegal_2(); } /* DB ED */
+OP(ed,25) { illegal_2(); } /* DB ED */
+OP(ed,26) { illegal_2(); } /* DB ED */
+OP(ed,27) { illegal_2(); } /* DB ED */
+
+OP(ed,28) { illegal_2(); } /* DB ED */
+OP(ed,29) { illegal_2(); } /* DB ED */
+OP(ed,2a) { illegal_2(); } /* DB ED */
+OP(ed,2b) { illegal_2(); } /* DB ED */
+OP(ed,2c) { illegal_2(); } /* DB ED */
+OP(ed,2d) { illegal_2(); } /* DB ED */
+OP(ed,2e) { illegal_2(); } /* DB ED */
+OP(ed,2f) { illegal_2(); } /* DB ED */
+
+OP(ed,30) { illegal_2(); } /* DB ED */
+OP(ed,31) { illegal_2(); } /* DB ED */
+OP(ed,32) { illegal_2(); } /* DB ED */
+OP(ed,33) { illegal_2(); } /* DB ED */
+OP(ed,34) { illegal_2(); } /* DB ED */
+OP(ed,35) { illegal_2(); } /* DB ED */
+OP(ed,36) { illegal_2(); } /* DB ED */
+OP(ed,37) { illegal_2(); } /* DB ED */
+
+OP(ed,38) { illegal_2(); } /* DB ED */
+OP(ed,39) { illegal_2(); } /* DB ED */
+OP(ed,3a) { illegal_2(); } /* DB ED */
+OP(ed,3b) { illegal_2(); } /* DB ED */
+OP(ed,3c) { illegal_2(); } /* DB ED */
+OP(ed,3d) { illegal_2(); } /* DB ED */
+OP(ed,3e) { illegal_2(); } /* DB ED */
+OP(ed,3f) { illegal_2(); } /* DB ED */
+
+OP(ed,40) { B = IN(BC); F = (F & CF) | SZP[B]; } /* IN B,(C) */
+OP(ed,41) { OUT(BC, B); } /* OUT (C),B */
+OP(ed,42) { SBC16( bc ); } /* SBC HL,BC */
+OP(ed,43) { EA = ARG16(); WM16( EA, &Z80.bc ); } /* LD (w),BC */
+OP(ed,44) { NEG; } /* NEG */
+OP(ed,45) { RETN; } /* RETN; */
+OP(ed,46) { IM = 0; } /* IM 0 */
+OP(ed,47) { LD_I_A; } /* LD I,A */
+
+OP(ed,48) { C = IN(BC); F = (F & CF) | SZP[C]; } /* IN C,(C) */
+OP(ed,49) { OUT(BC, C); } /* OUT (C),C */
+OP(ed,4a) { ADC16( bc ); } /* ADC HL,BC */
+OP(ed,4b) { EA = ARG16(); RM16( EA, &Z80.bc ); } /* LD BC,(w) */
+OP(ed,4c) { NEG; } /* NEG */
+OP(ed,4d) { RETI; } /* RETI */
+OP(ed,4e) { IM = 0; } /* IM 0 */
+OP(ed,4f) { LD_R_A; } /* LD R,A */
+
+OP(ed,50) { D = IN(BC); F = (F & CF) | SZP[D]; } /* IN D,(C) */
+OP(ed,51) { OUT(BC, D); } /* OUT (C),D */
+OP(ed,52) { SBC16( de ); } /* SBC HL,DE */
+OP(ed,53) { EA = ARG16(); WM16( EA, &Z80.de ); } /* LD (w),DE */
+OP(ed,54) { NEG; } /* NEG */
+OP(ed,55) { RETN; } /* RETN; */
+OP(ed,56) { IM = 1; } /* IM 1 */
+OP(ed,57) { LD_A_I; } /* LD A,I */
+
+OP(ed,58) { E = IN(BC); F = (F & CF) | SZP[E]; } /* IN E,(C) */
+OP(ed,59) { OUT(BC, E); } /* OUT (C),E */
+OP(ed,5a) { ADC16( de ); } /* ADC HL,DE */
+OP(ed,5b) { EA = ARG16(); RM16( EA, &Z80.de ); } /* LD DE,(w) */
+OP(ed,5c) { NEG; } /* NEG */
+OP(ed,5d) { RETI; } /* RETI */
+OP(ed,5e) { IM = 2; } /* IM 2 */
+OP(ed,5f) { LD_A_R; } /* LD A,R */
+
+OP(ed,60) { H = IN(BC); F = (F & CF) | SZP[H]; } /* IN H,(C) */
+OP(ed,61) { OUT(BC, H); } /* OUT (C),H */
+OP(ed,62) { SBC16( hl ); } /* SBC HL,HL */
+OP(ed,63) { EA = ARG16(); WM16( EA, &Z80.hl ); } /* LD (w),HL */
+OP(ed,64) { NEG; } /* NEG */
+OP(ed,65) { RETN; } /* RETN; */
+OP(ed,66) { IM = 0; } /* IM 0 */
+OP(ed,67) { RRD; } /* RRD (HL) */
+
+OP(ed,68) { L = IN(BC); F = (F & CF) | SZP[L]; } /* IN L,(C) */
+OP(ed,69) { OUT(BC, L); } /* OUT (C),L */
+OP(ed,6a) { ADC16( hl ); } /* ADC HL,HL */
+OP(ed,6b) { EA = ARG16(); RM16( EA, &Z80.hl ); } /* LD HL,(w) */
+OP(ed,6c) { NEG; } /* NEG */
+OP(ed,6d) { RETI; } /* RETI */
+OP(ed,6e) { IM = 0; } /* IM 0 */
+OP(ed,6f) { RLD; } /* RLD (HL) */
+
+OP(ed,70) { UINT8 res = IN(BC); F = (F & CF) | SZP[res]; } /* IN 0,(C) */
+OP(ed,71) { OUT(BC, 0); } /* OUT (C),0 */
+OP(ed,72) { SBC16( sp ); } /* SBC HL,SP */
+OP(ed,73) { EA = ARG16(); WM16( EA, &Z80.sp ); } /* LD (w),SP */
+OP(ed,74) { NEG; } /* NEG */
+OP(ed,75) { RETN; } /* RETN; */
+OP(ed,76) { IM = 1; } /* IM 1 */
+OP(ed,77) { illegal_2(); } /* DB ED,77 */
+
+OP(ed,78) { A = IN(BC); F = (F & CF) | SZP[A]; } /* IN E,(C) */
+OP(ed,79) { OUT(BC, A); } /* OUT (C),A */
+OP(ed,7a) { ADC16( sp ); } /* ADC HL,SP */
+OP(ed,7b) { EA = ARG16(); RM16( EA, &Z80.sp ); } /* LD SP,(w) */
+OP(ed,7c) { NEG; } /* NEG */
+OP(ed,7d) { RETI; } /* RETI */
+OP(ed,7e) { IM = 2; } /* IM 2 */
+OP(ed,7f) { illegal_2(); } /* DB ED,7F */
+
+OP(ed,80) { illegal_2(); } /* DB ED */
+OP(ed,81) { illegal_2(); } /* DB ED */
+OP(ed,82) { illegal_2(); } /* DB ED */
+OP(ed,83) { illegal_2(); } /* DB ED */
+OP(ed,84) { illegal_2(); } /* DB ED */
+OP(ed,85) { illegal_2(); } /* DB ED */
+OP(ed,86) { illegal_2(); } /* DB ED */
+OP(ed,87) { illegal_2(); } /* DB ED */
+
+OP(ed,88) { illegal_2(); } /* DB ED */
+OP(ed,89) { illegal_2(); } /* DB ED */
+OP(ed,8a) { illegal_2(); } /* DB ED */
+OP(ed,8b) { illegal_2(); } /* DB ED */
+OP(ed,8c) { illegal_2(); } /* DB ED */
+OP(ed,8d) { illegal_2(); } /* DB ED */
+OP(ed,8e) { illegal_2(); } /* DB ED */
+OP(ed,8f) { illegal_2(); } /* DB ED */
+
+OP(ed,90) { illegal_2(); } /* DB ED */
+OP(ed,91) { illegal_2(); } /* DB ED */
+OP(ed,92) { illegal_2(); } /* DB ED */
+OP(ed,93) { illegal_2(); } /* DB ED */
+OP(ed,94) { illegal_2(); } /* DB ED */
+OP(ed,95) { illegal_2(); } /* DB ED */
+OP(ed,96) { illegal_2(); } /* DB ED */
+OP(ed,97) { illegal_2(); } /* DB ED */
+
+OP(ed,98) { illegal_2(); } /* DB ED */
+OP(ed,99) { illegal_2(); } /* DB ED */
+OP(ed,9a) { illegal_2(); } /* DB ED */
+OP(ed,9b) { illegal_2(); } /* DB ED */
+OP(ed,9c) { illegal_2(); } /* DB ED */
+OP(ed,9d) { illegal_2(); } /* DB ED */
+OP(ed,9e) { illegal_2(); } /* DB ED */
+OP(ed,9f) { illegal_2(); } /* DB ED */
+
+OP(ed,a0) { LDI; } /* LDI */
+OP(ed,a1) { CPI; } /* CPI */
+OP(ed,a2) { INI; } /* INI */
+OP(ed,a3) { OUTI; } /* OUTI */
+OP(ed,a4) { illegal_2(); } /* DB ED */
+OP(ed,a5) { illegal_2(); } /* DB ED */
+OP(ed,a6) { illegal_2(); } /* DB ED */
+OP(ed,a7) { illegal_2(); } /* DB ED */
+
+OP(ed,a8) { LDD; } /* LDD */
+OP(ed,a9) { CPD; } /* CPD */
+OP(ed,aa) { IND; } /* IND */
+OP(ed,ab) { OUTD; } /* OUTD */
+OP(ed,ac) { illegal_2(); } /* DB ED */
+OP(ed,ad) { illegal_2(); } /* DB ED */
+OP(ed,ae) { illegal_2(); } /* DB ED */
+OP(ed,af) { illegal_2(); } /* DB ED */
+
+OP(ed,b0) { LDIR; } /* LDIR */
+OP(ed,b1) { CPIR; } /* CPIR */
+OP(ed,b2) { INIR; } /* INIR */
+OP(ed,b3) { OTIR; } /* OTIR */
+OP(ed,b4) { illegal_2(); } /* DB ED */
+OP(ed,b5) { illegal_2(); } /* DB ED */
+OP(ed,b6) { illegal_2(); } /* DB ED */
+OP(ed,b7) { illegal_2(); } /* DB ED */
+
+OP(ed,b8) { LDDR; } /* LDDR */
+OP(ed,b9) { CPDR; } /* CPDR */
+OP(ed,ba) { INDR; } /* INDR */
+OP(ed,bb) { OTDR; } /* OTDR */
+OP(ed,bc) { illegal_2(); } /* DB ED */
+OP(ed,bd) { illegal_2(); } /* DB ED */
+OP(ed,be) { illegal_2(); } /* DB ED */
+OP(ed,bf) { illegal_2(); } /* DB ED */
+
+OP(ed,c0) { illegal_2(); } /* DB ED */
+OP(ed,c1) { illegal_2(); } /* DB ED */
+OP(ed,c2) { illegal_2(); } /* DB ED */
+OP(ed,c3) { illegal_2(); } /* DB ED */
+OP(ed,c4) { illegal_2(); } /* DB ED */
+OP(ed,c5) { illegal_2(); } /* DB ED */
+OP(ed,c6) { illegal_2(); } /* DB ED */
+OP(ed,c7) { illegal_2(); } /* DB ED */
+
+OP(ed,c8) { illegal_2(); } /* DB ED */
+OP(ed,c9) { illegal_2(); } /* DB ED */
+OP(ed,ca) { illegal_2(); } /* DB ED */
+OP(ed,cb) { illegal_2(); } /* DB ED */
+OP(ed,cc) { illegal_2(); } /* DB ED */
+OP(ed,cd) { illegal_2(); } /* DB ED */
+OP(ed,ce) { illegal_2(); } /* DB ED */
+OP(ed,cf) { illegal_2(); } /* DB ED */
+
+OP(ed,d0) { illegal_2(); } /* DB ED */
+OP(ed,d1) { illegal_2(); } /* DB ED */
+OP(ed,d2) { illegal_2(); } /* DB ED */
+OP(ed,d3) { illegal_2(); } /* DB ED */
+OP(ed,d4) { illegal_2(); } /* DB ED */
+OP(ed,d5) { illegal_2(); } /* DB ED */
+OP(ed,d6) { illegal_2(); } /* DB ED */
+OP(ed,d7) { illegal_2(); } /* DB ED */
+
+OP(ed,d8) { illegal_2(); } /* DB ED */
+OP(ed,d9) { illegal_2(); } /* DB ED */
+OP(ed,da) { illegal_2(); } /* DB ED */
+OP(ed,db) { illegal_2(); } /* DB ED */
+OP(ed,dc) { illegal_2(); } /* DB ED */
+OP(ed,dd) { illegal_2(); } /* DB ED */
+OP(ed,de) { illegal_2(); } /* DB ED */
+OP(ed,df) { illegal_2(); } /* DB ED */
+
+OP(ed,e0) { illegal_2(); } /* DB ED */
+OP(ed,e1) { illegal_2(); } /* DB ED */
+OP(ed,e2) { illegal_2(); } /* DB ED */
+OP(ed,e3) { illegal_2(); } /* DB ED */
+OP(ed,e4) { illegal_2(); } /* DB ED */
+OP(ed,e5) { illegal_2(); } /* DB ED */
+OP(ed,e6) { illegal_2(); } /* DB ED */
+OP(ed,e7) { illegal_2(); } /* DB ED */
+
+OP(ed,e8) { illegal_2(); } /* DB ED */
+OP(ed,e9) { illegal_2(); } /* DB ED */
+OP(ed,ea) { illegal_2(); } /* DB ED */
+OP(ed,eb) { illegal_2(); } /* DB ED */
+OP(ed,ec) { illegal_2(); } /* DB ED */
+OP(ed,ed) { illegal_2(); } /* DB ED */
+OP(ed,ee) { illegal_2(); } /* DB ED */
+OP(ed,ef) { illegal_2(); } /* DB ED */
+
+OP(ed,f0) { illegal_2(); } /* DB ED */
+OP(ed,f1) { illegal_2(); } /* DB ED */
+OP(ed,f2) { illegal_2(); } /* DB ED */
+OP(ed,f3) { illegal_2(); } /* DB ED */
+OP(ed,f4) { illegal_2(); } /* DB ED */
+OP(ed,f5) { illegal_2(); } /* DB ED */
+OP(ed,f6) { illegal_2(); } /* DB ED */
+OP(ed,f7) { illegal_2(); } /* DB ED */
+
+OP(ed,f8) { illegal_2(); } /* DB ED */
+OP(ed,f9) { illegal_2(); } /* DB ED */
+OP(ed,fa) { illegal_2(); } /* DB ED */
+OP(ed,fb) { illegal_2(); } /* DB ED */
+OP(ed,fc) { illegal_2(); } /* DB ED */
+OP(ed,fd) { illegal_2(); } /* DB ED */
+OP(ed,fe) { illegal_2(); } /* DB ED */
+OP(ed,ff) { illegal_2(); } /* DB ED */
+
+
+/**********************************************************
+ * main opcodes
+ **********************************************************/
+OP(op,00) { } /* NOP */
+OP(op,01) { BC = ARG16(); } /* LD BC,w */
+OP(op,02) { WM( BC, A ); } /* LD (BC),A */
+OP(op,03) { BC++; } /* INC BC */
+OP(op,04) { B = INC(B); } /* INC B */
+OP(op,05) { B = DEC(B); } /* DEC B */
+OP(op,06) { B = ARG(); } /* LD B,n */
+OP(op,07) { RLCA; } /* RLCA */
+
+OP(op,08) { EX_AF; } /* EX AF,AF' */
+OP(op,09) { ADD16(hl, bc); } /* ADD HL,BC */
+OP(op,0a) { A = RM( BC ); } /* LD A,(BC) */
+OP(op,0b) { BC--; } /* DEC BC */
+OP(op,0c) { C = INC(C); } /* INC C */
+OP(op,0d) { C = DEC(C); } /* DEC C */
+OP(op,0e) { C = ARG(); } /* LD C,n */
+OP(op,0f) { RRCA; } /* RRCA */
+
+OP(op,10) { B--; JR_COND( B, 0x10 ); } /* DJNZ o */
+OP(op,11) { DE = ARG16(); } /* LD DE,w */
+OP(op,12) { WM( DE, A ); } /* LD (DE),A */
+OP(op,13) { DE++; } /* INC DE */
+OP(op,14) { D = INC(D); } /* INC D */
+OP(op,15) { D = DEC(D); } /* DEC D */
+OP(op,16) { D = ARG(); } /* LD D,n */
+OP(op,17) { RLA; } /* RLA */
+
+OP(op,18) { JR(); } /* JR o */
+OP(op,19) { ADD16(hl, de); } /* ADD HL,DE */
+OP(op,1a) { A = RM( DE ); } /* LD A,(DE) */
+OP(op,1b) { DE--; } /* DEC DE */
+OP(op,1c) { E = INC(E); } /* INC E */
+OP(op,1d) { E = DEC(E); } /* DEC E */
+OP(op,1e) { E = ARG(); } /* LD E,n */
+OP(op,1f) { RRA; } /* RRA */
+
+OP(op,20) { JR_COND( !(F & ZF), 0x20 ); } /* JR NZ,o */
+OP(op,21) { HL = ARG16(); } /* LD HL,w */
+OP(op,22) { EA = ARG16(); WM16( EA, &Z80.hl ); } /* LD (w),HL */
+OP(op,23) { HL++; } /* INC HL */
+OP(op,24) { H = INC(H); } /* INC H */
+OP(op,25) { H = DEC(H); } /* DEC H */
+OP(op,26) { H = ARG(); } /* LD H,n */
+OP(op,27) { DAA; } /* DAA */
+
+OP(op,28) { JR_COND( F & ZF, 0x28 ); } /* JR Z,o */
+OP(op,29) { ADD16(hl, hl); } /* ADD HL,HL */
+OP(op,2a) { EA = ARG16(); RM16( EA, &Z80.hl ); } /* LD HL,(w) */
+OP(op,2b) { HL--; } /* DEC HL */
+OP(op,2c) { L = INC(L); } /* INC L */
+OP(op,2d) { L = DEC(L); } /* DEC L */
+OP(op,2e) { L = ARG(); } /* LD L,n */
+OP(op,2f) { A ^= 0xff; F = (F&(SF|ZF|PF|CF))|HF|NF|(A&(YF|XF)); } /* CPL */
+
+OP(op,30) { JR_COND( !(F & CF), 0x30 ); } /* JR NC,o */
+OP(op,31) { SP = ARG16(); } /* LD SP,w */
+OP(op,32) { EA = ARG16(); WM( EA, A ); } /* LD (w),A */
+OP(op,33) { SP++; } /* INC SP */
+OP(op,34) { WM( HL, INC(RM(HL)) ); } /* INC (HL) */
+OP(op,35) { WM( HL, DEC(RM(HL)) ); } /* DEC (HL) */
+OP(op,36) { WM( HL, ARG() ); } /* LD (HL),n */
+OP(op,37) { F = (F & (SF|ZF|PF)) | CF | (A & (YF|XF)); } /* SCF */
+
+OP(op,38) { JR_COND( F & CF, 0x38 ); } /* JR C,o */
+OP(op,39) { ADD16(hl, sp); } /* ADD HL,SP */
+OP(op,3a) { EA = ARG16(); A = RM( EA ); } /* LD A,(w) */
+OP(op,3b) { SP--; } /* DEC SP */
+OP(op,3c) { A = INC(A); } /* INC A */
+OP(op,3d) { A = DEC(A); } /* DEC A */
+OP(op,3e) { A = ARG(); } /* LD A,n */
+OP(op,3f) { F = ((F&(SF|ZF|PF|CF))|((F&CF)<<4)|(A&(YF|XF)))^CF; } /* CCF */
+
+OP(op,40) { } /* LD B,B */
+OP(op,41) { B = C; } /* LD B,C */
+OP(op,42) { B = D; } /* LD B,D */
+OP(op,43) { B = E; } /* LD B,E */
+OP(op,44) { B = H; } /* LD B,H */
+OP(op,45) { B = L; } /* LD B,L */
+OP(op,46) { B = RM(HL); } /* LD B,(HL) */
+OP(op,47) { B = A; } /* LD B,A */
+
+OP(op,48) { C = B; } /* LD C,B */
+OP(op,49) { } /* LD C,C */
+OP(op,4a) { C = D; } /* LD C,D */
+OP(op,4b) { C = E; } /* LD C,E */
+OP(op,4c) { C = H; } /* LD C,H */
+OP(op,4d) { C = L; } /* LD C,L */
+OP(op,4e) { C = RM(HL); } /* LD C,(HL) */
+OP(op,4f) { C = A; } /* LD C,A */
+
+OP(op,50) { D = B; } /* LD D,B */
+OP(op,51) { D = C; } /* LD D,C */
+OP(op,52) { } /* LD D,D */
+OP(op,53) { D = E; } /* LD D,E */
+OP(op,54) { D = H; } /* LD D,H */
+OP(op,55) { D = L; } /* LD D,L */
+OP(op,56) { D = RM(HL); } /* LD D,(HL) */
+OP(op,57) { D = A; } /* LD D,A */
+
+OP(op,58) { E = B; } /* LD E,B */
+OP(op,59) { E = C; } /* LD E,C */
+OP(op,5a) { E = D; } /* LD E,D */
+OP(op,5b) { } /* LD E,E */
+OP(op,5c) { E = H; } /* LD E,H */
+OP(op,5d) { E = L; } /* LD E,L */
+OP(op,5e) { E = RM(HL); } /* LD E,(HL) */
+OP(op,5f) { E = A; } /* LD E,A */
+
+OP(op,60) { H = B; } /* LD H,B */
+OP(op,61) { H = C; } /* LD H,C */
+OP(op,62) { H = D; } /* LD H,D */
+OP(op,63) { H = E; } /* LD H,E */
+OP(op,64) { } /* LD H,H */
+OP(op,65) { H = L; } /* LD H,L */
+OP(op,66) { H = RM(HL); } /* LD H,(HL) */
+OP(op,67) { H = A; } /* LD H,A */
+
+OP(op,68) { L = B; } /* LD L,B */
+OP(op,69) { L = C; } /* LD L,C */
+OP(op,6a) { L = D; } /* LD L,D */
+OP(op,6b) { L = E; } /* LD L,E */
+OP(op,6c) { L = H; } /* LD L,H */
+OP(op,6d) { } /* LD L,L */
+OP(op,6e) { L = RM(HL); } /* LD L,(HL) */
+OP(op,6f) { L = A; } /* LD L,A */
+
+OP(op,70) { WM( HL, B ); } /* LD (HL),B */
+OP(op,71) { WM( HL, C ); } /* LD (HL),C */
+OP(op,72) { WM( HL, D ); } /* LD (HL),D */
+OP(op,73) { WM( HL, E ); } /* LD (HL),E */
+OP(op,74) { WM( HL, H ); } /* LD (HL),H */
+OP(op,75) { WM( HL, L ); } /* LD (HL),L */
+OP(op,76) { ENTER_HALT; } /* HALT */
+OP(op,77) { WM( HL, A ); } /* LD (HL),A */
+
+OP(op,78) { A = B; } /* LD A,B */
+OP(op,79) { A = C; } /* LD A,C */
+OP(op,7a) { A = D; } /* LD A,D */
+OP(op,7b) { A = E; } /* LD A,E */
+OP(op,7c) { A = H; } /* LD A,H */
+OP(op,7d) { A = L; } /* LD A,L */
+OP(op,7e) { A = RM(HL); } /* LD A,(HL) */
+OP(op,7f) { } /* LD A,A */
+
+OP(op,80) { ADD(B); } /* ADD A,B */
+OP(op,81) { ADD(C); } /* ADD A,C */
+OP(op,82) { ADD(D); } /* ADD A,D */
+OP(op,83) { ADD(E); } /* ADD A,E */
+OP(op,84) { ADD(H); } /* ADD A,H */
+OP(op,85) { ADD(L); } /* ADD A,L */
+OP(op,86) { ADD(RM(HL)); } /* ADD A,(HL) */
+OP(op,87) { ADD(A); } /* ADD A,A */
+
+OP(op,88) { ADC(B); } /* ADC A,B */
+OP(op,89) { ADC(C); } /* ADC A,C */
+OP(op,8a) { ADC(D); } /* ADC A,D */
+OP(op,8b) { ADC(E); } /* ADC A,E */
+OP(op,8c) { ADC(H); } /* ADC A,H */
+OP(op,8d) { ADC(L); } /* ADC A,L */
+OP(op,8e) { ADC(RM(HL)); } /* ADC A,(HL) */
+OP(op,8f) { ADC(A); } /* ADC A,A */
+
+OP(op,90) { SUB(B); } /* SUB B */
+OP(op,91) { SUB(C); } /* SUB C */
+OP(op,92) { SUB(D); } /* SUB D */
+OP(op,93) { SUB(E); } /* SUB E */
+OP(op,94) { SUB(H); } /* SUB H */
+OP(op,95) { SUB(L); } /* SUB L */
+OP(op,96) { SUB(RM(HL)); } /* SUB (HL) */
+OP(op,97) { SUB(A); } /* SUB A */
+
+OP(op,98) { SBC(B); } /* SBC A,B */
+OP(op,99) { SBC(C); } /* SBC A,C */
+OP(op,9a) { SBC(D); } /* SBC A,D */
+OP(op,9b) { SBC(E); } /* SBC A,E */
+OP(op,9c) { SBC(H); } /* SBC A,H */
+OP(op,9d) { SBC(L); } /* SBC A,L */
+OP(op,9e) { SBC(RM(HL)); } /* SBC A,(HL) */
+OP(op,9f) { SBC(A); } /* SBC A,A */
+
+OP(op,a0) { AND(B); } /* AND B */
+OP(op,a1) { AND(C); } /* AND C */
+OP(op,a2) { AND(D); } /* AND D */
+OP(op,a3) { AND(E); } /* AND E */
+OP(op,a4) { AND(H); } /* AND H */
+OP(op,a5) { AND(L); } /* AND L */
+OP(op,a6) { AND(RM(HL)); } /* AND (HL) */
+OP(op,a7) { AND(A); } /* AND A */
+
+OP(op,a8) { XOR(B); } /* XOR B */
+OP(op,a9) { XOR(C); } /* XOR C */
+OP(op,aa) { XOR(D); } /* XOR D */
+OP(op,ab) { XOR(E); } /* XOR E */
+OP(op,ac) { XOR(H); } /* XOR H */
+OP(op,ad) { XOR(L); } /* XOR L */
+OP(op,ae) { XOR(RM(HL)); } /* XOR (HL) */
+OP(op,af) { XOR(A); } /* XOR A */
+
+OP(op,b0) { OR(B); } /* OR B */
+OP(op,b1) { OR(C); } /* OR C */
+OP(op,b2) { OR(D); } /* OR D */
+OP(op,b3) { OR(E); } /* OR E */
+OP(op,b4) { OR(H); } /* OR H */
+OP(op,b5) { OR(L); } /* OR L */
+OP(op,b6) { OR(RM(HL)); } /* OR (HL) */
+OP(op,b7) { OR(A); } /* OR A */
+
+OP(op,b8) { CP(B); } /* CP B */
+OP(op,b9) { CP(C); } /* CP C */
+OP(op,ba) { CP(D); } /* CP D */
+OP(op,bb) { CP(E); } /* CP E */
+OP(op,bc) { CP(H); } /* CP H */
+OP(op,bd) { CP(L); } /* CP L */
+OP(op,be) { CP(RM(HL)); } /* CP (HL) */
+OP(op,bf) { CP(A); } /* CP A */
+
+OP(op,c0) { RET_COND( !(F & ZF), 0xc0 ); } /* RET NZ */
+OP(op,c1) { POP( bc ); } /* POP BC */
+OP(op,c2) { JP_COND( !(F & ZF) ); } /* JP NZ,a */
+OP(op,c3) { JP; } /* JP a */
+OP(op,c4) { CALL_COND( !(F & ZF), 0xc4 ); } /* CALL NZ,a */
+OP(op,c5) { PUSH( bc ); } /* PUSH BC */
+OP(op,c6) { ADD(ARG()); } /* ADD A,n */
+OP(op,c7) { RST(0x00); } /* RST 0 */
+
+OP(op,c8) { RET_COND( F & ZF, 0xc8 ); } /* RET Z */
+OP(op,c9) { POP( pc ); change_pc(PCD); } /* RET */
+OP(op,ca) { JP_COND( F & ZF ); } /* JP Z,a */
+OP(op,cb) { R++; EXEC(cb,ROP()); } /* **** CB xx */
+OP(op,cc) { CALL_COND( F & ZF, 0xcc ); } /* CALL Z,a */
+OP(op,cd) { CALL(); } /* CALL a */
+OP(op,ce) { ADC(ARG()); } /* ADC A,n */
+OP(op,cf) { RST(0x08); } /* RST 1 */
+
+OP(op,d0) { RET_COND( !(F & CF), 0xd0 ); } /* RET NC */
+OP(op,d1) { POP( de ); } /* POP DE */
+OP(op,d2) { JP_COND( !(F & CF) ); } /* JP NC,a */
+OP(op,d3) { unsigned n = ARG() | (A << 8); OUT( n, A ); } /* OUT (n),A */
+OP(op,d4) { CALL_COND( !(F & CF), 0xd4 ); } /* CALL NC,a */
+OP(op,d5) { PUSH( de ); } /* PUSH DE */
+OP(op,d6) { SUB(ARG()); } /* SUB n */
+OP(op,d7) { RST(0x10); } /* RST 2 */
+
+OP(op,d8) { RET_COND( F & CF, 0xd8 ); } /* RET C */
+OP(op,d9) { EXX; } /* EXX */
+OP(op,da) { JP_COND( F & CF ); } /* JP C,a */
+OP(op,db) { unsigned n = ARG() | (A << 8); A = IN( n ); } /* IN A,(n) */
+OP(op,dc) { CALL_COND( F & CF, 0xdc ); } /* CALL C,a */
+OP(op,dd) { R++; EXEC(dd,ROP()); } /* **** DD xx */
+OP(op,de) { SBC(ARG()); } /* SBC A,n */
+OP(op,df) { RST(0x18); } /* RST 3 */
+
+OP(op,e0) { RET_COND( !(F & PF), 0xe0 ); } /* RET PO */
+OP(op,e1) { POP( hl ); } /* POP HL */
+OP(op,e2) { JP_COND( !(F & PF) ); } /* JP PO,a */
+OP(op,e3) { EXSP( hl ); } /* EX HL,(SP) */
+OP(op,e4) { CALL_COND( !(F & PF), 0xe4 ); } /* CALL PO,a */
+OP(op,e5) { PUSH( hl ); } /* PUSH HL */
+OP(op,e6) { AND(ARG()); } /* AND n */
+OP(op,e7) { RST(0x20); } /* RST 4 */
+
+OP(op,e8) { RET_COND( F & PF, 0xe8 ); } /* RET PE */
+OP(op,e9) { PC = HL; change_pc(PCD); } /* JP (HL) */
+OP(op,ea) { JP_COND( F & PF ); } /* JP PE,a */
+OP(op,eb) { EX_DE_HL; } /* EX DE,HL */
+OP(op,ec) { CALL_COND( F & PF, 0xec ); } /* CALL PE,a */
+OP(op,ed) { R++; EXEC(ed,ROP()); } /* **** ED xx */
+OP(op,ee) { XOR(ARG()); } /* XOR n */
+OP(op,ef) { RST(0x28); } /* RST 5 */
+
+OP(op,f0) { RET_COND( !(F & SF), 0xf0 ); } /* RET P */
+OP(op,f1) { POP( af ); } /* POP AF */
+OP(op,f2) { JP_COND( !(F & SF) ); } /* JP P,a */
+OP(op,f3) { IFF1 = IFF2 = 0; } /* DI */
+OP(op,f4) { CALL_COND( !(F & SF), 0xf4 ); } /* CALL P,a */
+OP(op,f5) { PUSH( af ); } /* PUSH AF */
+OP(op,f6) { OR(ARG()); } /* OR n */
+OP(op,f7) { RST(0x30); } /* RST 6 */
+
+OP(op,f8) { RET_COND( F & SF, 0xf8 ); } /* RET M */
+OP(op,f9) { SP = HL; } /* LD SP,HL */
+OP(op,fa) { JP_COND(F & SF); } /* JP M,a */
+OP(op,fb) { EI; } /* EI */
+OP(op,fc) { CALL_COND( F & SF, 0xfc ); } /* CALL M,a */
+OP(op,fd) { R++; EXEC(fd,ROP()); } /* **** FD xx */
+OP(op,fe) { CP(ARG()); } /* CP n */
+OP(op,ff) { RST(0x38); } /* RST 7 */
+
+
+static void take_interrupt(void)
+{
+ int irq_vector;
+
+ /* there isn't a valid previous program counter */
+ PRVPC = -1;
+
+ /* Check if processor was halted */
+ LEAVE_HALT;
+
+ /* Clear both interrupt flip flops */
+ IFF1 = IFF2 = 0;
+
+ /* Daisy chain mode? If so, call the requesting device */
+ if (Z80.daisy)
+ irq_vector = z80daisy_call_ack_device(Z80.daisy);
+
+ /* else call back the cpu interface to retrieve the vector */
+ else
+ irq_vector = (*Z80.irq_callback)(0);
+
+ LOG(("Z80 #%d single int. irq_vector $%02x\n", cpu_getactivecpu(), irq_vector));
+
+ /* Interrupt mode 2. Call [Z80.i:databyte] */
+ if( IM == 2 )
+ {
+ irq_vector = (irq_vector & 0xff) | (I << 8);
+ PUSH( pc );
+ RM16( irq_vector, &Z80.pc );
+ LOG(("Z80 #%d IM2 [$%04x] = $%04x\n",cpu_getactivecpu() , irq_vector, PCD));
+ /* CALL opcode timing */
+ z80_ICount -= cc[Z80_TABLE_op][0xcd];
+ }
+ else
+ /* Interrupt mode 1. RST 38h */
+ if( IM == 1 )
+ {
+ LOG(("Z80 #%d IM1 $0038\n",cpu_getactivecpu() ));
+ PUSH( pc );
+ PCD = 0x0038;
+ /* RST $38 + 'interrupt latency' cycles */
+ z80_ICount -= cc[Z80_TABLE_op][0xff] + cc[Z80_TABLE_ex][0xff];
+ }
+ else
+ {
+ /* Interrupt mode 0. We check for CALL and JP instructions, */
+ /* if neither of these were found we assume a 1 byte opcode */
+ /* was placed on the databus */
+ LOG(("Z80 #%d IM0 $%04x\n",cpu_getactivecpu() , irq_vector));
+ switch (irq_vector & 0xff0000)
+ {
+ case 0xcd0000: /* call */
+ PUSH( pc );
+ PCD = irq_vector & 0xffff;
+ /* CALL $xxxx + 'interrupt latency' cycles */
+ z80_ICount -= cc[Z80_TABLE_op][0xcd] + cc[Z80_TABLE_ex][0xff];
+ break;
+ case 0xc30000: /* jump */
+ PCD = irq_vector & 0xffff;
+ /* JP $xxxx + 2 cycles */
+ z80_ICount -= cc[Z80_TABLE_op][0xc3] + cc[Z80_TABLE_ex][0xff];
+ break;
+ default: /* rst (or other opcodes?) */
+ PUSH( pc );
+ PCD = irq_vector & 0x0038;
+ /* RST $xx + 2 cycles */
+ z80_ICount -= cc[Z80_TABLE_op][PCD] + cc[Z80_TABLE_ex][PCD];
+ break;
+ }
+ }
+ change_pc(PCD);
+}
+
+/****************************************************************************
+ * Processor initialization
+ ****************************************************************************/
+static void z80_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int i, p;
+
+ /* setup cycle tables */
+ cc[Z80_TABLE_op] = cc_op;
+ cc[Z80_TABLE_cb] = cc_cb;
+ cc[Z80_TABLE_ed] = cc_ed;
+ cc[Z80_TABLE_xy] = cc_xy;
+ cc[Z80_TABLE_xycb] = cc_xycb;
+ cc[Z80_TABLE_ex] = cc_ex;
+
+#if BIG_FLAGS_ARRAY
+ if( !SZHVC_add || !SZHVC_sub )
+ {
+ int oldval, newval, val;
+ UINT8 *padd, *padc, *psub, *psbc;
+ /* allocate big flag arrays once */
+ SZHVC_add = (UINT8 *)malloc(2*256*256);
+ SZHVC_sub = (UINT8 *)malloc(2*256*256);
+ if( !SZHVC_add || !SZHVC_sub )
+ {
+ fatalerror("Z80: failed to allocate 2 * 128K flags arrays!!!");
+ }
+ padd = &SZHVC_add[ 0*256];
+ padc = &SZHVC_add[256*256];
+ psub = &SZHVC_sub[ 0*256];
+ psbc = &SZHVC_sub[256*256];
+ for (oldval = 0; oldval < 256; oldval++)
+ {
+ for (newval = 0; newval < 256; newval++)
+ {
+ /* add or adc w/o carry set */
+ val = newval - oldval;
+ *padd = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
+ *padd |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
+ if( (newval & 0x0f) < (oldval & 0x0f) ) *padd |= HF;
+ if( newval < oldval ) *padd |= CF;
+ if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padd |= VF;
+ padd++;
+
+ /* adc with carry set */
+ val = newval - oldval - 1;
+ *padc = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
+ *padc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
+ if( (newval & 0x0f) <= (oldval & 0x0f) ) *padc |= HF;
+ if( newval <= oldval ) *padc |= CF;
+ if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padc |= VF;
+ padc++;
+
+ /* cp, sub or sbc w/o carry set */
+ val = oldval - newval;
+ *psub = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
+ *psub |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
+ if( (newval & 0x0f) > (oldval & 0x0f) ) *psub |= HF;
+ if( newval > oldval ) *psub |= CF;
+ if( (val^oldval) & (oldval^newval) & 0x80 ) *psub |= VF;
+ psub++;
+
+ /* sbc with carry set */
+ val = oldval - newval - 1;
+ *psbc = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
+ *psbc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
+ if( (newval & 0x0f) >= (oldval & 0x0f) ) *psbc |= HF;
+ if( newval >= oldval ) *psbc |= CF;
+ if( (val^oldval) & (oldval^newval) & 0x80 ) *psbc |= VF;
+ psbc++;
+ }
+ }
+ }
+#endif
+ for (i = 0; i < 256; i++)
+ {
+ p = 0;
+ if( i&0x01 ) ++p;
+ if( i&0x02 ) ++p;
+ if( i&0x04 ) ++p;
+ if( i&0x08 ) ++p;
+ if( i&0x10 ) ++p;
+ if( i&0x20 ) ++p;
+ if( i&0x40 ) ++p;
+ if( i&0x80 ) ++p;
+ SZ[i] = i ? i & SF : ZF;
+ SZ[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */
+ SZ_BIT[i] = i ? i & SF : ZF | PF;
+ SZ_BIT[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */
+ SZP[i] = SZ[i] | ((p & 1) ? 0 : PF);
+ SZHV_inc[i] = SZ[i];
+ if( i == 0x80 ) SZHV_inc[i] |= VF;
+ if( (i & 0x0f) == 0x00 ) SZHV_inc[i] |= HF;
+ SZHV_dec[i] = SZ[i] | NF;
+ if( i == 0x7f ) SZHV_dec[i] |= VF;
+ if( (i & 0x0f) == 0x0f ) SZHV_dec[i] |= HF;
+ }
+
+ state_save_register_item("z80", index, Z80.prvpc.w.l);
+ state_save_register_item("z80", index, Z80.pc.w.l);
+ state_save_register_item("z80", index, Z80.sp.w.l);
+ state_save_register_item("z80", index, Z80.af.w.l);
+ state_save_register_item("z80", index, Z80.bc.w.l);
+ state_save_register_item("z80", index, Z80.de.w.l);
+ state_save_register_item("z80", index, Z80.hl.w.l);
+ state_save_register_item("z80", index, Z80.ix.w.l);
+ state_save_register_item("z80", index, Z80.iy.w.l);
+ state_save_register_item("z80", index, Z80.af2.w.l);
+ state_save_register_item("z80", index, Z80.bc2.w.l);
+ state_save_register_item("z80", index, Z80.de2.w.l);
+ state_save_register_item("z80", index, Z80.hl2.w.l);
+ state_save_register_item("z80", index, Z80.r);
+ state_save_register_item("z80", index, Z80.r2);
+ state_save_register_item("z80", index, Z80.iff1);
+ state_save_register_item("z80", index, Z80.iff2);
+ state_save_register_item("z80", index, Z80.halt);
+ state_save_register_item("z80", index, Z80.im);
+ state_save_register_item("z80", index, Z80.i);
+ state_save_register_item("z80", index, Z80.nmi_state);
+ state_save_register_item("z80", index, Z80.nmi_pending);
+ state_save_register_item("z80", index, Z80.irq_state);
+ state_save_register_item("z80", index, Z80.after_ei);
+
+ /* Reset registers to their initial values */
+ memset(&Z80, 0, sizeof(Z80));
+ Z80.daisy = config;
+ Z80.irq_callback = irqcallback;
+ IX = IY = 0xffff; /* IX and IY are FFFF after a reset! */
+ F = ZF; /* Zero flag is set */
+}
+
+/****************************************************************************
+ * Do a reset
+ ****************************************************************************/
+static void z80_reset(void)
+{
+ PC = 0x0000;
+ I = 0;
+ R = 0;
+ R2 = 0;
+ Z80.nmi_state = CLEAR_LINE;
+ Z80.nmi_pending = FALSE;
+ Z80.irq_state = CLEAR_LINE;
+ Z80.after_ei = FALSE;
+
+ if (Z80.daisy)
+ z80daisy_reset(Z80.daisy);
+
+ change_pc(PCD);
+}
+
+static void z80_exit(void)
+{
+#if BIG_FLAGS_ARRAY
+ if (SZHVC_add) free(SZHVC_add);
+ SZHVC_add = NULL;
+ if (SZHVC_sub) free(SZHVC_sub);
+ SZHVC_sub = NULL;
+#endif
+}
+
+/****************************************************************************
+ * Execute 'cycles' T-states. Return number of T-states really executed
+ ****************************************************************************/
+static int z80_execute(int cycles)
+{
+ z80_ICount = cycles;
+
+ /* check for NMIs on the way in; they can only be set externally */
+ /* via timers, and can't be dynamically enabled, so it is safe */
+ /* to just check here */
+ if (Z80.nmi_pending)
+ {
+ LOG(("Z80 #%d take NMI\n", cpu_getactivecpu()));
+ PRVPC = -1; /* there isn't a valid previous program counter */
+ LEAVE_HALT; /* Check if processor was halted */
+
+ IFF1 = 0;
+ PUSH( pc );
+ PCD = 0x0066;
+ change_pc(PCD);
+ z80_ICount -= 11;
+ Z80.nmi_pending = FALSE;
+ }
+
+ do
+ {
+ /* check for IRQs before each instruction */
+ if (Z80.irq_state != CLEAR_LINE && IFF1 && !Z80.after_ei)
+ take_interrupt();
+ Z80.after_ei = FALSE;
+
+ PRVPC = PCD;
+ CALL_MAME_DEBUG;
+ R++;
+ EXEC_INLINE(op,ROP());
+ } while( z80_ICount > 0 );
+
+ return cycles - z80_ICount;
+}
+
+/****************************************************************************
+ * Burn 'cycles' T-states. Adjust R register for the lost time
+ ****************************************************************************/
+static void z80_burn(int cycles)
+{
+ if( cycles > 0 )
+ {
+ /* NOP takes 4 cycles per instruction */
+ int n = (cycles + 3) / 4;
+ R += n;
+ z80_ICount -= 4 * n;
+ }
+}
+
+/****************************************************************************
+ * Get all registers in given buffer
+ ****************************************************************************/
+static void z80_get_context (void *dst)
+{
+ if( dst )
+ *(Z80_Regs*)dst = Z80;
+}
+
+/****************************************************************************
+ * Set all registers to given values
+ ****************************************************************************/
+static void z80_set_context (void *src)
+{
+ if( src )
+ Z80 = *(Z80_Regs*)src;
+ change_pc(PCD);
+}
+
+/****************************************************************************
+ * Set IRQ line state
+ ****************************************************************************/
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ /* mark an NMI pending on the rising edge */
+ if (Z80.nmi_state == CLEAR_LINE && state != CLEAR_LINE)
+ Z80.nmi_pending = TRUE;
+ Z80.nmi_state = state;
+ }
+ else
+ {
+ /* update the IRQ state via the daisy chain */
+ Z80.irq_state = state;
+ if (Z80.daisy)
+ Z80.irq_state = z80daisy_update_irq_state(Z80.daisy);
+
+ /* the main execute loop will take the interrupt */
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void z80_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+
+ case CPUINFO_INT_PC: PC = info->i; change_pc(PCD); break;
+ case CPUINFO_INT_REGISTER + Z80_PC: Z80.pc.w.l = info->i; break;
+ case CPUINFO_INT_SP: SP = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_SP: Z80.sp.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_A: Z80.af.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_B: Z80.bc.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_C: Z80.bc.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_D: Z80.de.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_E: Z80.de.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_H: Z80.hl.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_L: Z80.hl.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_AF: Z80.af.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_BC: Z80.bc.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_DE: Z80.de.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_HL: Z80.hl.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_IX: Z80.ix.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_IY: Z80.iy.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_R: Z80.r = info->i; Z80.r2 = info->i & 0x80; break;
+ case CPUINFO_INT_REGISTER + Z80_I: Z80.i = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_AF2: Z80.af2.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_BC2: Z80.bc2.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_DE2: Z80.de2.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_HL2: Z80.hl2.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_IM: Z80.im = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_IFF1: Z80.iff1 = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_IFF2: Z80.iff2 = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80_HALT: Z80.halt = info->i; break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_op: cc[Z80_TABLE_op] = info->p; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_cb: cc[Z80_TABLE_cb] = info->p; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_ed: cc[Z80_TABLE_ed] = info->p; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_xy: cc[Z80_TABLE_xy] = info->p; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_xycb: cc[Z80_TABLE_xycb] = info->p; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_ex: cc[Z80_TABLE_ex] = info->p; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void z80_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(Z80); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 16; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = Z80.nmi_state; break;
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = Z80.irq_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = Z80.prvpc.w.l; break;
+
+ case CPUINFO_INT_PC: info->i = PCD; break;
+ case CPUINFO_INT_REGISTER + Z80_PC: info->i = Z80.pc.w.l; break;
+ case CPUINFO_INT_SP: info->i = SPD; break;
+ case CPUINFO_INT_REGISTER + Z80_SP: info->i = Z80.sp.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_A: info->i = Z80.af.b.h; break;
+ case CPUINFO_INT_REGISTER + Z80_B: info->i = Z80.bc.b.h; break;
+ case CPUINFO_INT_REGISTER + Z80_C: info->i = Z80.bc.b.l; break;
+ case CPUINFO_INT_REGISTER + Z80_D: info->i = Z80.de.b.h; break;
+ case CPUINFO_INT_REGISTER + Z80_E: info->i = Z80.de.b.l; break;
+ case CPUINFO_INT_REGISTER + Z80_H: info->i = Z80.hl.b.h; break;
+ case CPUINFO_INT_REGISTER + Z80_L: info->i = Z80.hl.b.l; break;
+ case CPUINFO_INT_REGISTER + Z80_AF: info->i = Z80.af.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_BC: info->i = Z80.bc.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_DE: info->i = Z80.de.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_HL: info->i = Z80.hl.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_IX: info->i = Z80.ix.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_IY: info->i = Z80.iy.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_R: info->i = (Z80.r & 0x7f) | (Z80.r2 & 0x80); break;
+ case CPUINFO_INT_REGISTER + Z80_I: info->i = Z80.i; break;
+ case CPUINFO_INT_REGISTER + Z80_AF2: info->i = Z80.af2.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_BC2: info->i = Z80.bc2.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_DE2: info->i = Z80.de2.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_HL2: info->i = Z80.hl2.w.l; break;
+ case CPUINFO_INT_REGISTER + Z80_IM: info->i = Z80.im; break;
+ case CPUINFO_INT_REGISTER + Z80_IFF1: info->i = Z80.iff1; break;
+ case CPUINFO_INT_REGISTER + Z80_IFF2: info->i = Z80.iff2; break;
+ case CPUINFO_INT_REGISTER + Z80_HALT: info->i = Z80.halt; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = z80_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = z80_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = z80_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = z80_init; break;
+ case CPUINFO_PTR_RESET: info->reset = z80_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = z80_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = z80_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = z80_dasm; break;
+#endif
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &z80_ICount; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_op: info->p = (void *)cc[Z80_TABLE_op]; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_cb: info->p = (void *)cc[Z80_TABLE_cb]; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_ed: info->p = (void *)cc[Z80_TABLE_ed]; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_xy: info->p = (void *)cc[Z80_TABLE_xy]; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_xycb: info->p = (void *)cc[Z80_TABLE_xycb]; break;
+ case CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_ex: info->p = (void *)cc[Z80_TABLE_ex]; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "Z80"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Zilog Z80"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "3.7"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ Z80.af.b.l & 0x80 ? 'S':'.',
+ Z80.af.b.l & 0x40 ? 'Z':'.',
+ Z80.af.b.l & 0x20 ? '5':'.',
+ Z80.af.b.l & 0x10 ? 'H':'.',
+ Z80.af.b.l & 0x08 ? '3':'.',
+ Z80.af.b.l & 0x04 ? 'P':'.',
+ Z80.af.b.l & 0x02 ? 'N':'.',
+ Z80.af.b.l & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + Z80_PC: sprintf(info->s, "PC:%04X", Z80.pc.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_SP: sprintf(info->s, "SP:%04X", Z80.sp.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_A: sprintf(info->s, "~A:%02X", Z80.af.b.h); break;
+ case CPUINFO_STR_REGISTER + Z80_B: sprintf(info->s, "~B:%02X", Z80.bc.b.h); break;
+ case CPUINFO_STR_REGISTER + Z80_C: sprintf(info->s, "~C:%02X", Z80.bc.b.l); break;
+ case CPUINFO_STR_REGISTER + Z80_D: sprintf(info->s, "~D:%02X", Z80.de.b.h); break;
+ case CPUINFO_STR_REGISTER + Z80_E: sprintf(info->s, "~E:%02X", Z80.de.b.l); break;
+ case CPUINFO_STR_REGISTER + Z80_H: sprintf(info->s, "~H:%02X", Z80.hl.b.h); break;
+ case CPUINFO_STR_REGISTER + Z80_L: sprintf(info->s, "~L:%02X", Z80.hl.b.l); break;
+ case CPUINFO_STR_REGISTER + Z80_AF: sprintf(info->s, "AF:%04X", Z80.af.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_BC: sprintf(info->s, "BC:%04X", Z80.bc.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_DE: sprintf(info->s, "DE:%04X", Z80.de.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_HL: sprintf(info->s, "HL:%04X", Z80.hl.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_IX: sprintf(info->s, "IX:%04X", Z80.ix.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_IY: sprintf(info->s, "IY:%04X", Z80.iy.w.l);
+ break;
+ case CPUINFO_STR_REGISTER + Z80_R: sprintf(info->s, "R:%02X", (Z80.r & 0x7f) | (Z80.r2 & 0x80)); break;
+ case CPUINFO_STR_REGISTER + Z80_I: sprintf(info->s, "I:%02X", Z80.i); break;
+ case CPUINFO_STR_REGISTER + Z80_AF2: sprintf(info->s, "AF2:%04X", Z80.af2.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_BC2: sprintf(info->s, "BC2:%04X", Z80.bc2.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_DE2: sprintf(info->s, "DE2:%04X", Z80.de2.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_HL2: sprintf(info->s, "HL2:%04X", Z80.hl2.w.l); break;
+ case CPUINFO_STR_REGISTER + Z80_IM: sprintf(info->s, "IM:%X", Z80.im); break;
+ case CPUINFO_STR_REGISTER + Z80_IFF1: sprintf(info->s, "IFF1:%X", Z80.iff1); break;
+ case CPUINFO_STR_REGISTER + Z80_IFF2: sprintf(info->s, "IFF2:%X", Z80.iff2); break;
+ case CPUINFO_STR_REGISTER + Z80_HALT: sprintf(info->s, "HALT:%X", Z80.halt); break;
+ }
+}
diff --git a/src/emu/cpu/z80/z80.h b/src/emu/cpu/z80/z80.h
new file mode 100644
index 00000000000..a2a080b78ad
--- /dev/null
+++ b/src/emu/cpu/z80/z80.h
@@ -0,0 +1,38 @@
+#ifndef _Z80_H_
+#define _Z80_H_
+
+#include "cpuintrf.h"
+
+enum {
+ Z80_PC=1, Z80_SP,
+ Z80_A, Z80_B, Z80_C, Z80_D, Z80_E, Z80_H, Z80_L,
+ Z80_AF, Z80_BC, Z80_DE, Z80_HL,
+ Z80_IX, Z80_IY, Z80_AF2, Z80_BC2, Z80_DE2, Z80_HL2,
+ Z80_R, Z80_I, Z80_IM, Z80_IFF1, Z80_IFF2, Z80_HALT,
+ Z80_DC0, Z80_DC1, Z80_DC2, Z80_DC3
+};
+
+enum {
+ Z80_TABLE_op,
+ Z80_TABLE_cb,
+ Z80_TABLE_ed,
+ Z80_TABLE_xy,
+ Z80_TABLE_xycb,
+ Z80_TABLE_ex /* cycles counts for taken jr/jp/call and interrupt latency (rst opcodes) */
+};
+
+enum
+{
+ CPUINFO_PTR_Z80_CYCLE_TABLE = CPUINFO_PTR_CPU_SPECIFIC,
+ CPUINFO_PTR_Z80_CYCLE_TABLE_LAST = CPUINFO_PTR_Z80_CYCLE_TABLE + Z80_TABLE_ex
+};
+
+extern void z80_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern unsigned z80_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+
+#endif
+
diff --git a/src/emu/cpu/z80/z80daisy.c b/src/emu/cpu/z80/z80daisy.c
new file mode 100644
index 00000000000..55d88ae0b58
--- /dev/null
+++ b/src/emu/cpu/z80/z80daisy.c
@@ -0,0 +1,75 @@
+/***************************************************************************
+
+ z80daisy.c
+
+ Z80/180 daisy chaining support functions.
+
+***************************************************************************/
+
+#include "cpuintrf.h"
+#include "z80daisy.h"
+
+
+void z80daisy_reset(const struct z80_irq_daisy_chain *daisy)
+{
+ /* loop over all devices and call their reset function */
+ for ( ; daisy->param != -1; daisy++)
+ if (daisy->reset)
+ (*daisy->reset)(daisy->param);
+}
+
+
+int z80daisy_update_irq_state(const struct z80_irq_daisy_chain *daisy)
+{
+ /* loop over all devices; dev[0] is highest priority */
+ for ( ; daisy->param != -1; daisy++)
+ {
+ int state = (*daisy->irq_state)(daisy->param);
+
+ /* if this device is asserting the INT line, that's the one we want */
+ if (state & Z80_DAISY_INT)
+ return ASSERT_LINE;
+
+ /* if this device is asserting the IEO line, it blocks everyone else */
+ if (state & Z80_DAISY_IEO)
+ return CLEAR_LINE;
+ }
+
+ return CLEAR_LINE;
+}
+
+
+int z80daisy_call_ack_device(const struct z80_irq_daisy_chain *daisy)
+{
+ /* loop over all devices; dev[0] is the highest priority */
+ for ( ; daisy->param != -1; daisy++)
+ {
+ int state = (*daisy->irq_state)(daisy->param);
+
+ /* if this device is asserting the INT line, that's the one we want */
+ if (state & Z80_DAISY_INT)
+ return (*daisy->irq_ack)(daisy->param);
+ }
+
+ logerror("z80daisy_call_ack_device: failed to find an device to ack!\n");
+ return 0;
+}
+
+
+void z80daisy_call_reti_device(const struct z80_irq_daisy_chain *daisy)
+{
+ /* loop over all devices; dev[0] is the highest priority */
+ for ( ; daisy->param != -1; daisy++)
+ {
+ int state = (*daisy->irq_state)(daisy->param);
+
+ /* if this device is asserting the IEO line, that's the one we want */
+ if (state & Z80_DAISY_IEO)
+ {
+ (*daisy->irq_reti)(daisy->param);
+ return;
+ }
+ }
+
+ logerror("z80daisy_call_reti_device: failed to find an device to reti!\n");
+}
diff --git a/src/emu/cpu/z80/z80daisy.h b/src/emu/cpu/z80/z80daisy.h
new file mode 100644
index 00000000000..b0e791e6ef1
--- /dev/null
+++ b/src/emu/cpu/z80/z80daisy.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+
+ z80daisy.h
+
+ Z80/180 daisy chaining support functions.
+
+***************************************************************************/
+
+
+#ifndef Z80DAISY_H
+#define Z80DAISY_H
+
+
+/* daisy-chain link */
+struct z80_irq_daisy_chain
+{
+ void (*reset)(int); /* reset callback */
+ int (*irq_state)(int); /* get interrupt state */
+ int (*irq_ack)(int); /* interrupt acknowledge callback */
+ void (*irq_reti)(int); /* reti callback */
+ int param; /* callback parameter (-1 ends list) */
+};
+
+
+/* these constants are returned from the irq_state function */
+#define Z80_DAISY_INT 0x01 /* interrupt request mask */
+#define Z80_DAISY_IEO 0x02 /* interrupt disable mask (IEO) */
+
+
+/* prototypes */
+void z80daisy_reset(const struct z80_irq_daisy_chain *daisy);
+int z80daisy_update_irq_state(const struct z80_irq_daisy_chain *chain);
+int z80daisy_call_ack_device(const struct z80_irq_daisy_chain *chain);
+void z80daisy_call_reti_device(const struct z80_irq_daisy_chain *chain);
+
+#endif
diff --git a/src/emu/cpu/z80/z80dasm.c b/src/emu/cpu/z80/z80dasm.c
new file mode 100644
index 00000000000..6070f8cce33
--- /dev/null
+++ b/src/emu/cpu/z80/z80dasm.c
@@ -0,0 +1,543 @@
+/*****************************************************************************
+ *
+ * z80dasm.c
+ * Portable Z80 disassembler
+ *
+ * Copyright (C) 1998 Juergen Buchmueller, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "z80.h"
+
+enum e_mnemonics
+{
+ zADC ,zADD ,zAND ,zBIT ,zCALL ,zCCF ,zCP ,zCPD ,
+ zCPDR ,zCPI ,zCPIR ,zCPL ,zDAA ,zDB ,zDEC ,zDI ,
+ zDJNZ ,zEI ,zEX ,zEXX ,zHLT ,zIM ,zIN ,zINC ,
+ zIND ,zINDR ,zINI ,zINIR ,zJP ,zJR ,zLD ,zLDD ,
+ zLDDR ,zLDI ,zLDIR ,zNEG ,zNOP ,zOR ,zOTDR ,zOTIR ,
+ zOUT ,zOUTD ,zOUTI ,zPOP ,zPUSH ,zRES ,zRET ,zRETI ,
+ zRETN ,zRL ,zRLA ,zRLC ,zRLCA ,zRLD ,zRR ,zRRA ,
+ zRRC ,zRRCA ,zRRD ,zRST ,zSBC ,zSCF ,zSET ,zSLA ,
+ zSLL ,zSRA ,zSRL ,zSUB ,zXOR
+};
+
+static const char *s_mnemonic[] =
+{
+ "adc" ,"add" ,"and" ,"bit" ,"call","ccf" ,"cp" ,"cpd" ,
+ "cpdr","cpi" ,"cpir","cpl" ,"daa" ,"db" ,"dec" ,"di" ,
+ "djnz","ei" ,"ex" ,"exx" ,"halt","im" ,"in" ,"inc" ,
+ "ind" ,"indr","ini" ,"inir","jp" ,"jr" ,"ld" ,"ldd" ,
+ "lddr","ldi" ,"ldir","neg" ,"nop" ,"or" ,"otdr","otir",
+ "out" ,"outd","outi","pop" ,"push","res" ,"ret" ,"reti",
+ "retn","rl" ,"rla" ,"rlc" ,"rlca","rld" ,"rr" ,"rra" ,
+ "rrc" ,"rrca","rrd" ,"rst" ,"sbc" ,"scf" ,"set" ,"sla" ,
+ "sll" ,"sra" ,"srl" ,"sub" ,"xor "
+};
+
+#define _OVER DASMFLAG_STEP_OVER
+#define _OUT DASMFLAG_STEP_OUT
+
+static const UINT32 s_flags[] =
+{
+ 0 ,0 ,0 ,0 ,_OVER,0 ,0 ,0 ,
+ _OVER,0 ,_OVER,0 ,0 ,0 ,0 ,0 ,
+ _OVER,0 ,0 ,0 ,_OVER,0 ,0 ,0 ,
+ 0 ,_OVER,0 ,_OVER,0 ,0 ,0 ,0 ,
+ _OVER,0 ,_OVER,0 ,0 ,0 ,_OVER,_OVER,
+ 0 ,0 ,0 ,0 ,0 ,0 ,_OUT ,_OUT ,
+ _OUT ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ 0 ,0 ,0 ,_OVER,0 ,0 ,0 ,0 ,
+ 0 ,0 ,0 ,0 ,0
+};
+
+typedef struct
+{
+ UINT8 mnemonic;
+ const char *arguments;
+} z80dasm;
+
+static const z80dasm mnemonic_xx_cb[256] =
+{
+ {zRLC,"b=Y"}, {zRLC,"c=Y"}, {zRLC,"d=Y"}, {zRLC,"e=Y"},
+ {zRLC,"h=Y"}, {zRLC,"l=Y"}, {zRLC,"Y"}, {zRLC,"a=Y"},
+ {zRRC,"b=Y"}, {zRRC,"c=Y"}, {zRRC,"d=Y"}, {zRRC,"e=Y"},
+ {zRRC,"h=Y"}, {zRRC,"l=Y"}, {zRRC,"Y"}, {zRRC,"a=Y"},
+ {zRL,"b=Y"}, {zRL,"c=Y"}, {zRL,"d=Y"}, {zRL,"e=Y"},
+ {zRL,"h=Y"}, {zRL,"l=Y"}, {zRL,"Y"}, {zRL,"a=Y"},
+ {zRR,"b=Y"}, {zRR,"c=Y"}, {zRR,"d=Y"}, {zRR,"e=Y"},
+ {zRR,"h=Y"}, {zRR,"l=Y"}, {zRR,"Y"}, {zRR,"a=Y"},
+ {zSLA,"b=Y"}, {zSLA,"c=Y"}, {zSLA,"d=Y"}, {zSLA,"e=Y"},
+ {zSLA,"h=Y"}, {zSLA,"l=Y"}, {zSLA,"Y"}, {zSLA,"a=Y"},
+ {zSRA,"b=Y"}, {zSRA,"c=Y"}, {zSRA,"d=Y"}, {zSRA,"e=Y"},
+ {zSRA,"h=Y"}, {zSRA,"l=Y"}, {zSRA,"Y"}, {zSRA,"a=Y"},
+ {zSLL,"b=Y"}, {zSLL,"c=Y"}, {zSLL,"d=Y"}, {zSLL,"e=Y"},
+ {zSLL,"h=Y"}, {zSLL,"l=Y"}, {zSLL,"Y"}, {zSLL,"a=Y"},
+ {zSRL,"b=Y"}, {zSRL,"c=Y"}, {zSRL,"d=Y"}, {zSRL,"e=Y"},
+ {zSRL,"h=Y"}, {zSRL,"l=Y"}, {zSRL,"Y"}, {zSRL,"a=Y"},
+ {zBIT,"b=0,Y"}, {zBIT,"c=0,Y"}, {zBIT,"d=0,Y"}, {zBIT,"e=0,Y"},
+ {zBIT,"h=0,Y"}, {zBIT,"l=0,Y"}, {zBIT,"0,Y"}, {zBIT,"a=0,Y"},
+ {zBIT,"b=1,Y"}, {zBIT,"c=1,Y"}, {zBIT,"d=1,Y"}, {zBIT,"e=1,Y"},
+ {zBIT,"h=1,Y"}, {zBIT,"l=1,Y"}, {zBIT,"1,Y"}, {zBIT,"a=1,Y"},
+ {zBIT,"b=2,Y"}, {zBIT,"c=2,Y"}, {zBIT,"d=2,Y"}, {zBIT,"e=2,Y"},
+ {zBIT,"h=2,Y"}, {zBIT,"l=2,Y"}, {zBIT,"2,Y"}, {zBIT,"a=2,Y"},
+ {zBIT,"b=3,Y"}, {zBIT,"c=3,Y"}, {zBIT,"d=3,Y"}, {zBIT,"e=3,Y"},
+ {zBIT,"h=3,Y"}, {zBIT,"l=3,Y"}, {zBIT,"3,Y"}, {zBIT,"a=3,Y"},
+ {zBIT,"b=4,Y"}, {zBIT,"c=4,Y"}, {zBIT,"d=4,Y"}, {zBIT,"e=4,Y"},
+ {zBIT,"h=4,Y"}, {zBIT,"l=4,Y"}, {zBIT,"4,Y"}, {zBIT,"a=4,Y"},
+ {zBIT,"b=5,Y"}, {zBIT,"c=5,Y"}, {zBIT,"d=5,Y"}, {zBIT,"e=5,Y"},
+ {zBIT,"h=5,Y"}, {zBIT,"l=5,Y"}, {zBIT,"5,Y"}, {zBIT,"a=5,Y"},
+ {zBIT,"b=6,Y"}, {zBIT,"c=6,Y"}, {zBIT,"d=6,Y"}, {zBIT,"e=6,Y"},
+ {zBIT,"h=6,Y"}, {zBIT,"l=6,Y"}, {zBIT,"6,Y"}, {zBIT,"a=6,Y"},
+ {zBIT,"b=7,Y"}, {zBIT,"c=7,Y"}, {zBIT,"d=7,Y"}, {zBIT,"e=7,Y"},
+ {zBIT,"h=7,Y"}, {zBIT,"l=7,Y"}, {zBIT,"7,Y"}, {zBIT,"a=7,Y"},
+ {zRES,"b=0,Y"}, {zRES,"c=0,Y"}, {zRES,"d=0,Y"}, {zRES,"e=0,Y"},
+ {zRES,"h=0,Y"}, {zRES,"l=0,Y"}, {zRES,"0,Y"}, {zRES,"a=0,Y"},
+ {zRES,"b=1,Y"}, {zRES,"c=1,Y"}, {zRES,"d=1,Y"}, {zRES,"e=1,Y"},
+ {zRES,"h=1,Y"}, {zRES,"l=1,Y"}, {zRES,"1,Y"}, {zRES,"a=1,Y"},
+ {zRES,"b=2,Y"}, {zRES,"c=2,Y"}, {zRES,"d=2,Y"}, {zRES,"e=2,Y"},
+ {zRES,"h=2,Y"}, {zRES,"l=2,Y"}, {zRES,"2,Y"}, {zRES,"a=2,Y"},
+ {zRES,"b=3,Y"}, {zRES,"c=3,Y"}, {zRES,"d=3,Y"}, {zRES,"e=3,Y"},
+ {zRES,"h=3,Y"}, {zRES,"l=3,Y"}, {zRES,"3,Y"}, {zRES,"a=3,Y"},
+ {zRES,"b=4,Y"}, {zRES,"c=4,Y"}, {zRES,"d=4,Y"}, {zRES,"e=4,Y"},
+ {zRES,"h=4,Y"}, {zRES,"l=4,Y"}, {zRES,"4,Y"}, {zRES,"a=4,Y"},
+ {zRES,"b=5,Y"}, {zRES,"c=5,Y"}, {zRES,"d=5,Y"}, {zRES,"e=5,Y"},
+ {zRES,"h=5,Y"}, {zRES,"l=5,Y"}, {zRES,"5,Y"}, {zRES,"a=5,Y"},
+ {zRES,"b=6,Y"}, {zRES,"c=6,Y"}, {zRES,"d=6,Y"}, {zRES,"e=6,Y"},
+ {zRES,"h=6,Y"}, {zRES,"l=6,Y"}, {zRES,"6,Y"}, {zRES,"a=6,Y"},
+ {zRES,"b=7,Y"}, {zRES,"c=7,Y"}, {zRES,"d=7,Y"}, {zRES,"e=7,Y"},
+ {zRES,"h=7,Y"}, {zRES,"l=7,Y"}, {zRES,"7,Y"}, {zRES,"a=7,Y"},
+ {zSET,"b=0,Y"}, {zSET,"c=0,Y"}, {zSET,"d=0,Y"}, {zSET,"e=0,Y"},
+ {zSET,"h=0,Y"}, {zSET,"l=0,Y"}, {zSET,"0,Y"}, {zSET,"a=0,Y"},
+ {zSET,"b=1,Y"}, {zSET,"c=1,Y"}, {zSET,"d=1,Y"}, {zSET,"e=1,Y"},
+ {zSET,"h=1,Y"}, {zSET,"l=1,Y"}, {zSET,"1,Y"}, {zSET,"a=1,Y"},
+ {zSET,"b=2,Y"}, {zSET,"c=2,Y"}, {zSET,"d=2,Y"}, {zSET,"e=2,Y"},
+ {zSET,"h=2,Y"}, {zSET,"l=2,Y"}, {zSET,"2,Y"}, {zSET,"a=2,Y"},
+ {zSET,"b=3,Y"}, {zSET,"c=3,Y"}, {zSET,"d=3,Y"}, {zSET,"e=3,Y"},
+ {zSET,"h=3,Y"}, {zSET,"l=3,Y"}, {zSET,"3,Y"}, {zSET,"a=3,Y"},
+ {zSET,"b=4,Y"}, {zSET,"c=4,Y"}, {zSET,"d=4,Y"}, {zSET,"e=4,Y"},
+ {zSET,"h=4,Y"}, {zSET,"l=4,Y"}, {zSET,"4,Y"}, {zSET,"a=4,Y"},
+ {zSET,"b=5,Y"}, {zSET,"c=5,Y"}, {zSET,"d=5,Y"}, {zSET,"e=5,Y"},
+ {zSET,"h=5,Y"}, {zSET,"l=5,Y"}, {zSET,"5,Y"}, {zSET,"a=5,Y"},
+ {zSET,"b=6,Y"}, {zSET,"c=6,Y"}, {zSET,"d=6,Y"}, {zSET,"e=6,Y"},
+ {zSET,"h=6,Y"}, {zSET,"l=6,Y"}, {zSET,"6,Y"}, {zSET,"a=6,Y"},
+ {zSET,"b=7,Y"}, {zSET,"c=7,Y"}, {zSET,"d=7,Y"}, {zSET,"e=7,Y"},
+ {zSET,"h=7,Y"}, {zSET,"l=7,Y"}, {zSET,"7,Y"}, {zSET,"a=7,Y"}
+};
+
+static const z80dasm mnemonic_cb[256] =
+{
+ {zRLC,"b"}, {zRLC,"c"}, {zRLC,"d"}, {zRLC,"e"},
+ {zRLC,"h"}, {zRLC,"l"}, {zRLC,"(hl)"}, {zRLC,"a"},
+ {zRRC,"b"}, {zRRC,"c"}, {zRRC,"d"}, {zRRC,"e"},
+ {zRRC,"h"}, {zRRC,"l"}, {zRRC,"(hl)"}, {zRRC,"a"},
+ {zRL,"b"}, {zRL,"c"}, {zRL,"d"}, {zRL,"e"},
+ {zRL,"h"}, {zRL,"l"}, {zRL,"(hl)"}, {zRL,"a"},
+ {zRR,"b"}, {zRR,"c"}, {zRR,"d"}, {zRR,"e"},
+ {zRR,"h"}, {zRR,"l"}, {zRR,"(hl)"}, {zRR,"a"},
+ {zSLA,"b"}, {zSLA,"c"}, {zSLA,"d"}, {zSLA,"e"},
+ {zSLA,"h"}, {zSLA,"l"}, {zSLA,"(hl)"}, {zSLA,"a"},
+ {zSRA,"b"}, {zSRA,"c"}, {zSRA,"d"}, {zSRA,"e"},
+ {zSRA,"h"}, {zSRA,"l"}, {zSRA,"(hl)"}, {zSRA,"a"},
+ {zSLL,"b"}, {zSLL,"c"}, {zSLL,"d"}, {zSLL,"e"},
+ {zSLL,"h"}, {zSLL,"l"}, {zSLL,"(hl)"}, {zSLL,"a"},
+ {zSRL,"b"}, {zSRL,"c"}, {zSRL,"d"}, {zSRL,"e"},
+ {zSRL,"h"}, {zSRL,"l"}, {zSRL,"(hl)"}, {zSRL,"a"},
+ {zBIT,"0,b"}, {zBIT,"0,c"}, {zBIT,"0,d"}, {zBIT,"0,e"},
+ {zBIT,"0,h"}, {zBIT,"0,l"}, {zBIT,"0,(hl)"},{zBIT,"0,a"},
+ {zBIT,"1,b"}, {zBIT,"1,c"}, {zBIT,"1,d"}, {zBIT,"1,e"},
+ {zBIT,"1,h"}, {zBIT,"1,l"}, {zBIT,"1,(hl)"},{zBIT,"1,a"},
+ {zBIT,"2,b"}, {zBIT,"2,c"}, {zBIT,"2,d"}, {zBIT,"2,e"},
+ {zBIT,"2,h"}, {zBIT,"2,l"}, {zBIT,"2,(hl)"},{zBIT,"2,a"},
+ {zBIT,"3,b"}, {zBIT,"3,c"}, {zBIT,"3,d"}, {zBIT,"3,e"},
+ {zBIT,"3,h"}, {zBIT,"3,l"}, {zBIT,"3,(hl)"},{zBIT,"3,a"},
+ {zBIT,"4,b"}, {zBIT,"4,c"}, {zBIT,"4,d"}, {zBIT,"4,e"},
+ {zBIT,"4,h"}, {zBIT,"4,l"}, {zBIT,"4,(hl)"},{zBIT,"4,a"},
+ {zBIT,"5,b"}, {zBIT,"5,c"}, {zBIT,"5,d"}, {zBIT,"5,e"},
+ {zBIT,"5,h"}, {zBIT,"5,l"}, {zBIT,"5,(hl)"},{zBIT,"5,a"},
+ {zBIT,"6,b"}, {zBIT,"6,c"}, {zBIT,"6,d"}, {zBIT,"6,e"},
+ {zBIT,"6,h"}, {zBIT,"6,l"}, {zBIT,"6,(hl)"},{zBIT,"6,a"},
+ {zBIT,"7,b"}, {zBIT,"7,c"}, {zBIT,"7,d"}, {zBIT,"7,e"},
+ {zBIT,"7,h"}, {zBIT,"7,l"}, {zBIT,"7,(hl)"},{zBIT,"7,a"},
+ {zRES,"0,b"}, {zRES,"0,c"}, {zRES,"0,d"}, {zRES,"0,e"},
+ {zRES,"0,h"}, {zRES,"0,l"}, {zRES,"0,(hl)"},{zRES,"0,a"},
+ {zRES,"1,b"}, {zRES,"1,c"}, {zRES,"1,d"}, {zRES,"1,e"},
+ {zRES,"1,h"}, {zRES,"1,l"}, {zRES,"1,(hl)"},{zRES,"1,a"},
+ {zRES,"2,b"}, {zRES,"2,c"}, {zRES,"2,d"}, {zRES,"2,e"},
+ {zRES,"2,h"}, {zRES,"2,l"}, {zRES,"2,(hl)"},{zRES,"2,a"},
+ {zRES,"3,b"}, {zRES,"3,c"}, {zRES,"3,d"}, {zRES,"3,e"},
+ {zRES,"3,h"}, {zRES,"3,l"}, {zRES,"3,(hl)"},{zRES,"3,a"},
+ {zRES,"4,b"}, {zRES,"4,c"}, {zRES,"4,d"}, {zRES,"4,e"},
+ {zRES,"4,h"}, {zRES,"4,l"}, {zRES,"4,(hl)"},{zRES,"4,a"},
+ {zRES,"5,b"}, {zRES,"5,c"}, {zRES,"5,d"}, {zRES,"5,e"},
+ {zRES,"5,h"}, {zRES,"5,l"}, {zRES,"5,(hl)"},{zRES,"5,a"},
+ {zRES,"6,b"}, {zRES,"6,c"}, {zRES,"6,d"}, {zRES,"6,e"},
+ {zRES,"6,h"}, {zRES,"6,l"}, {zRES,"6,(hl)"},{zRES,"6,a"},
+ {zRES,"7,b"}, {zRES,"7,c"}, {zRES,"7,d"}, {zRES,"7,e"},
+ {zRES,"7,h"}, {zRES,"7,l"}, {zRES,"7,(hl)"},{zRES,"7,a"},
+ {zSET,"0,b"}, {zSET,"0,c"}, {zSET,"0,d"}, {zSET,"0,e"},
+ {zSET,"0,h"}, {zSET,"0,l"}, {zSET,"0,(hl)"},{zSET,"0,a"},
+ {zSET,"1,b"}, {zSET,"1,c"}, {zSET,"1,d"}, {zSET,"1,e"},
+ {zSET,"1,h"}, {zSET,"1,l"}, {zSET,"1,(hl)"},{zSET,"1,a"},
+ {zSET,"2,b"}, {zSET,"2,c"}, {zSET,"2,d"}, {zSET,"2,e"},
+ {zSET,"2,h"}, {zSET,"2,l"}, {zSET,"2,(hl)"},{zSET,"2,a"},
+ {zSET,"3,b"}, {zSET,"3,c"}, {zSET,"3,d"}, {zSET,"3,e"},
+ {zSET,"3,h"}, {zSET,"3,l"}, {zSET,"3,(hl)"},{zSET,"3,a"},
+ {zSET,"4,b"}, {zSET,"4,c"}, {zSET,"4,d"}, {zSET,"4,e"},
+ {zSET,"4,h"}, {zSET,"4,l"}, {zSET,"4,(hl)"},{zSET,"4,a"},
+ {zSET,"5,b"}, {zSET,"5,c"}, {zSET,"5,d"}, {zSET,"5,e"},
+ {zSET,"5,h"}, {zSET,"5,l"}, {zSET,"5,(hl)"},{zSET,"5,a"},
+ {zSET,"6,b"}, {zSET,"6,c"}, {zSET,"6,d"}, {zSET,"6,e"},
+ {zSET,"6,h"}, {zSET,"6,l"}, {zSET,"6,(hl)"},{zSET,"6,a"},
+ {zSET,"7,b"}, {zSET,"7,c"}, {zSET,"7,d"}, {zSET,"7,e"},
+ {zSET,"7,h"}, {zSET,"7,l"}, {zSET,"7,(hl)"},{zSET,"7,a"}
+};
+
+static const z80dasm mnemonic_ed[256] =
+{
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zIN,"b,(c)"}, {zOUT,"(c),b"}, {zSBC,"hl,bc"}, {zLD,"(W),bc"},
+ {zNEG,0}, {zRETN,0}, {zIM,"0"}, {zLD,"i,a"},
+ {zIN,"c,(c)"}, {zOUT,"(c),c"}, {zADC,"hl,bc"}, {zLD,"bc,(W)"},
+ {zNEG,"*"}, {zRETI,0}, {zIM,"0"}, {zLD,"r,a"},
+ {zIN,"d,(c)"}, {zOUT,"(c),d"}, {zSBC,"hl,de"}, {zLD,"(W),de"},
+ {zNEG,"*"}, {zRETN,0}, {zIM,"1"}, {zLD,"a,i"},
+ {zIN,"e,(c)"}, {zOUT,"(c),e"}, {zADC,"hl,de"}, {zLD,"de,(W)"},
+ {zNEG,"*"}, {zRETI,0}, {zIM,"2"}, {zLD,"a,r"},
+ {zIN,"h,(c)"}, {zOUT,"(c),h"}, {zSBC,"hl,hl"}, {zLD,"(W),hl"},
+ {zNEG,"*"}, {zRETN,0}, {zIM,"0"}, {zRRD,"(hl)"},
+ {zIN,"l,(c)"}, {zOUT,"(c),l"}, {zADC,"hl,hl"}, {zLD,"hl,(W)"},
+ {zNEG,"*"}, {zRETI,0}, {zIM,"0"}, {zRLD,"(hl)"},
+ {zIN,"0,(c)"}, {zOUT,"(c),0"}, {zSBC,"hl,sp"}, {zLD,"(W),sp"},
+ {zNEG,"*"}, {zRETN,0}, {zIM,"1"}, {zDB,"?"},
+ {zIN,"a,(c)"}, {zOUT,"(c),a"}, {zADC,"hl,sp"}, {zLD,"sp,(W)"},
+ {zNEG,"*"}, {zRETI,0}, {zIM,"2"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLDI,0}, {zCPI,0}, {zINI,0}, {zOUTI,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLDD,0}, {zCPD,0}, {zIND,0}, {zOUTD,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLDIR,0}, {zCPIR,0}, {zINIR,0}, {zOTIR,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLDDR,0}, {zCPDR,0}, {zINDR,0}, {zOTDR,0},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}
+};
+
+static const z80dasm mnemonic_xx[256] =
+{
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zADD,"I,bc"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zADD,"I,de"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zLD,"I,N"}, {zLD,"(W),I"}, {zINC,"I"},
+ {zINC,"Ih"}, {zDEC,"Ih"}, {zLD,"Ih,B"}, {zDB,"?"},
+ {zDB,"?"}, {zADD,"I,I"}, {zLD,"I,(W)"}, {zDEC,"I"},
+ {zINC,"Il"}, {zDEC,"Il"}, {zLD,"Il,B"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zINC,"X"}, {zDEC,"X"}, {zLD,"X,B"}, {zDB,"?"},
+ {zDB,"?"}, {zADD,"I,sp"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"b,Ih"}, {zLD,"b,Il"}, {zLD,"b,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"c,Ih"}, {zLD,"c,Il"}, {zLD,"c,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"d,Ih"}, {zLD,"d,Il"}, {zLD,"d,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"e,Ih"}, {zLD,"e,Il"}, {zLD,"e,X"}, {zDB,"?"},
+ {zLD,"Ih,b"}, {zLD,"Ih,c"}, {zLD,"Ih,d"}, {zLD,"Ih,e"},
+ {zLD,"Ih,Ih"}, {zLD,"Ih,Il"}, {zLD,"h,X"}, {zLD,"Ih,a"},
+ {zLD,"Il,b"}, {zLD,"Il,c"}, {zLD,"Il,d"}, {zLD,"Il,e"},
+ {zLD,"Il,Ih"}, {zLD,"Il,Il"}, {zLD,"l,X"}, {zLD,"Il,a"},
+ {zLD,"X,b"}, {zLD,"X,c"}, {zLD,"X,d"}, {zLD,"X,e"},
+ {zLD,"X,h"}, {zLD,"X,l"}, {zDB,"?"}, {zLD,"X,a"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zLD,"a,Ih"}, {zLD,"a,Il"}, {zLD,"a,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zADD,"a,Ih"}, {zADD,"a,Il"}, {zADD,"a,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zADC,"a,Ih"}, {zADC,"a,Il"}, {zADC,"a,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zSUB,"Ih"}, {zSUB,"Il"}, {zSUB,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zSBC,"a,Ih"}, {zSBC,"a,Il"}, {zSBC,"a,X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zAND,"Ih"}, {zAND,"Il"}, {zAND,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zXOR,"Ih"}, {zXOR,"Il"}, {zXOR,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zOR,"Ih"}, {zOR,"Il"}, {zOR,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zCP,"Ih"}, {zCP,"Il"}, {zCP,"X"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"cb"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zPOP,"I"}, {zDB,"?"}, {zEX,"(sp),I"},
+ {zDB,"?"}, {zPUSH,"I"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zJP,"(I)"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zLD,"sp,I"}, {zDB,"?"}, {zDB,"?"},
+ {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}
+};
+
+static const z80dasm mnemonic_main[256] =
+{
+ {zNOP,0}, {zLD,"bc,N"}, {zLD,"(bc),a"}, {zINC,"bc"},
+ {zINC,"b"}, {zDEC,"b"}, {zLD,"b,B"}, {zRLCA,0},
+ {zEX,"af,af'"}, {zADD,"hl,bc"}, {zLD,"a,(bc)"}, {zDEC,"bc"},
+ {zINC,"c"}, {zDEC,"c"}, {zLD,"c,B"}, {zRRCA,0},
+ {zDJNZ,"O"}, {zLD,"de,N"}, {zLD,"(de),a"}, {zINC,"de"},
+ {zINC,"d"}, {zDEC,"d"}, {zLD,"d,B"}, {zRLA,0},
+ {zJR,"O"}, {zADD,"hl,de"}, {zLD,"a,(de)"}, {zDEC,"de"},
+ {zINC,"e"}, {zDEC,"e"}, {zLD,"e,B"}, {zRRA,0},
+ {zJR,"nz,O"}, {zLD,"hl,N"}, {zLD,"(W),hl"}, {zINC,"hl"},
+ {zINC,"h"}, {zDEC,"h"}, {zLD,"h,B"}, {zDAA,0},
+ {zJR,"z,O"}, {zADD,"hl,hl"}, {zLD,"hl,(W)"}, {zDEC,"hl"},
+ {zINC,"l"}, {zDEC,"l"}, {zLD,"l,B"}, {zCPL,0},
+ {zJR,"nc,O"}, {zLD,"sp,N"}, {zLD,"(W),a"}, {zINC,"sp"},
+ {zINC,"(hl)"}, {zDEC,"(hl)"}, {zLD,"(hl),B"}, {zSCF,0},
+ {zJR,"c,O"}, {zADD,"hl,sp"}, {zLD,"a,(W)"}, {zDEC,"sp"},
+ {zINC,"a"}, {zDEC,"a"}, {zLD,"a,B"}, {zCCF,0},
+ {zLD,"b,b"}, {zLD,"b,c"}, {zLD,"b,d"}, {zLD,"b,e"},
+ {zLD,"b,h"}, {zLD,"b,l"}, {zLD,"b,(hl)"}, {zLD,"b,a"},
+ {zLD,"c,b"}, {zLD,"c,c"}, {zLD,"c,d"}, {zLD,"c,e"},
+ {zLD,"c,h"}, {zLD,"c,l"}, {zLD,"c,(hl)"}, {zLD,"c,a"},
+ {zLD,"d,b"}, {zLD,"d,c"}, {zLD,"d,d"}, {zLD,"d,e"},
+ {zLD,"d,h"}, {zLD,"d,l"}, {zLD,"d,(hl)"}, {zLD,"d,a"},
+ {zLD,"e,b"}, {zLD,"e,c"}, {zLD,"e,d"}, {zLD,"e,e"},
+ {zLD,"e,h"}, {zLD,"e,l"}, {zLD,"e,(hl)"}, {zLD,"e,a"},
+ {zLD,"h,b"}, {zLD,"h,c"}, {zLD,"h,d"}, {zLD,"h,e"},
+ {zLD,"h,h"}, {zLD,"h,l"}, {zLD,"h,(hl)"}, {zLD,"h,a"},
+ {zLD,"l,b"}, {zLD,"l,c"}, {zLD,"l,d"}, {zLD,"l,e"},
+ {zLD,"l,h"}, {zLD,"l,l"}, {zLD,"l,(hl)"}, {zLD,"l,a"},
+ {zLD,"(hl),b"}, {zLD,"(hl),c"}, {zLD,"(hl),d"}, {zLD,"(hl),e"},
+ {zLD,"(hl),h"}, {zLD,"(hl),l"}, {zHLT,0}, {zLD,"(hl),a"},
+ {zLD,"a,b"}, {zLD,"a,c"}, {zLD,"a,d"}, {zLD,"a,e"},
+ {zLD,"a,h"}, {zLD,"a,l"}, {zLD,"a,(hl)"}, {zLD,"a,a"},
+ {zADD,"a,b"}, {zADD,"a,c"}, {zADD,"a,d"}, {zADD,"a,e"},
+ {zADD,"a,h"}, {zADD,"a,l"}, {zADD,"a,(hl)"},{zADD,"a,a"},
+ {zADC,"a,b"}, {zADC,"a,c"}, {zADC,"a,d"}, {zADC,"a,e"},
+ {zADC,"a,h"}, {zADC,"a,l"}, {zADC,"a,(hl)"},{zADC,"a,a"},
+ {zSUB,"b"}, {zSUB,"c"}, {zSUB,"d"}, {zSUB,"e"},
+ {zSUB,"h"}, {zSUB,"l"}, {zSUB,"(hl)"}, {zSUB,"a"},
+ {zSBC,"a,b"}, {zSBC,"a,c"}, {zSBC,"a,d"}, {zSBC,"a,e"},
+ {zSBC,"a,h"}, {zSBC,"a,l"}, {zSBC,"a,(hl)"},{zSBC,"a,a"},
+ {zAND,"b"}, {zAND,"c"}, {zAND,"d"}, {zAND,"e"},
+ {zAND,"h"}, {zAND,"l"}, {zAND,"(hl)"}, {zAND,"a"},
+ {zXOR,"b"}, {zXOR,"c"}, {zXOR,"d"}, {zXOR,"e"},
+ {zXOR,"h"}, {zXOR,"l"}, {zXOR,"(hl)"}, {zXOR,"a"},
+ {zOR,"b"}, {zOR,"c"}, {zOR,"d"}, {zOR,"e"},
+ {zOR,"h"}, {zOR,"l"}, {zOR,"(hl)"}, {zOR,"a"},
+ {zCP,"b"}, {zCP,"c"}, {zCP,"d"}, {zCP,"e"},
+ {zCP,"h"}, {zCP,"l"}, {zCP,"(hl)"}, {zCP,"a"},
+ {zRET,"nz"}, {zPOP,"bc"}, {zJP,"nz,A"}, {zJP,"A"},
+ {zCALL,"nz,A"}, {zPUSH,"bc"}, {zADD,"a,B"}, {zRST,"V"},
+ {zRET,"z"}, {zRET,0}, {zJP,"z,A"}, {zDB,"cb"},
+ {zCALL,"z,A"}, {zCALL,"A"}, {zADC,"a,B"}, {zRST,"V"},
+ {zRET,"nc"}, {zPOP,"de"}, {zJP,"nc,A"}, {zOUT,"(P),a"},
+ {zCALL,"nc,A"}, {zPUSH,"de"}, {zSUB,"B"}, {zRST,"V"},
+ {zRET,"c"}, {zEXX,0}, {zJP,"c,A"}, {zIN,"a,(P)"},
+ {zCALL,"c,A"}, {zDB,"dd"}, {zSBC,"a,B"}, {zRST,"V"},
+ {zRET,"po"}, {zPOP,"hl"}, {zJP,"po,A"}, {zEX,"(sp),hl"},
+ {zCALL,"po,A"}, {zPUSH,"hl"}, {zAND,"B"}, {zRST,"V"},
+ {zRET,"pe"}, {zJP,"(hl)"}, {zJP,"pe,A"}, {zEX,"de,hl"},
+ {zCALL,"pe,A"}, {zDB,"ed"}, {zXOR,"B"}, {zRST,"V"},
+ {zRET,"p"}, {zPOP,"af"}, {zJP,"p,A"}, {zDI,0},
+ {zCALL,"p,A"}, {zPUSH,"af"}, {zOR,"B"}, {zRST,"V"},
+ {zRET,"m"}, {zLD,"sp,hl"}, {zJP,"m,A"}, {zEI,0},
+ {zCALL,"m,A"}, {zDB,"fd"}, {zCP,"B"}, {zRST,"V"}
+};
+
+static char sign(INT8 offset)
+{
+ return (offset < 0)? '-':'+';
+}
+
+static int offs(INT8 offset)
+{
+ if (offset < 0) return -offset;
+ return offset;
+}
+
+/****************************************************************************
+ * Disassemble opcode at PC and return number of bytes it takes
+ ****************************************************************************/
+unsigned z80_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ const z80dasm *d;
+ const char *src, *ixy;
+ char *dst;
+ INT8 offset = 0;
+ UINT8 op, op1 = 0;
+ UINT16 ea = 0;
+ int pos = 0;
+
+ ixy = "oops!!";
+ dst = buffer;
+
+ op = oprom[pos++];
+
+ switch (op)
+ {
+ case 0xcb:
+ op = oprom[pos++];
+ d = &mnemonic_cb[op];
+ break;
+ case 0xed:
+ op1 = oprom[pos++];
+ d = &mnemonic_ed[op1];
+ break;
+ case 0xdd:
+ ixy = "ix";
+ op1 = oprom[pos++];
+ if( op1 == 0xcb )
+ {
+ offset = (INT8) opram[pos++];
+ op1 = opram[pos++]; /* fourth byte from opcode_arg_base! */
+ d = &mnemonic_xx_cb[op1];
+ }
+ else d = &mnemonic_xx[op1];
+ break;
+ case 0xfd:
+ ixy = "iy";
+ op1 = oprom[pos++];
+ if( op1 == 0xcb )
+ {
+ offset = (INT8) opram[pos++];
+ op1 = opram[pos++]; /* fourth byte from opcode_arg_base! */
+ d = &mnemonic_xx_cb[op1];
+ }
+ else d = &mnemonic_xx[op1];
+ break;
+ default:
+ d = &mnemonic_main[op];
+ break;
+ }
+
+ if( d->arguments )
+ {
+ dst += sprintf(dst, "%-4s ", s_mnemonic[d->mnemonic]);
+ src = d->arguments;
+ while( *src )
+ {
+ switch( *src )
+ {
+ case '?': /* illegal opcode */
+ dst += sprintf( dst, "$%02x,$%02x", op, op1 );
+ break;
+ case 'A':
+ ea = opram[pos+0] + ( opram[pos+1] << 8 );
+ pos += 2;
+ dst += sprintf( dst, "$%04X", ea );
+ break;
+ case 'B': /* Byte op arg */
+ ea = opram[pos++];
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case 'N': /* Immediate 16 bit */
+ ea = opram[pos+0] + ( opram[pos+1] << 8 );
+ pos += 2;
+ dst += sprintf( dst, "$%04X", ea );
+ break;
+ case 'O': /* Offset relative to PC */
+ offset = (INT8) opram[pos++];
+ dst += sprintf( dst, "$%04X", (pc + offset + 2) & 0xffff );
+ break;
+ case 'P': /* Port number */
+ ea = opram[pos++];
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case 'V': /* Restart vector */
+ ea = op & 0x38;
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case 'W': /* Memory address word */
+ ea = opram[pos+0] + ( opram[pos+1] << 8 );
+ pos += 2;
+ dst += sprintf( dst, "$%04X", ea );
+ break;
+ case 'X':
+ offset = (INT8) opram[pos++];
+ /* fall through */
+ case 'Y':
+ dst += sprintf( dst,"(%s%c$%02x)", ixy, sign(offset), offs(offset) );
+ break;
+ case 'I':
+ dst += sprintf( dst, "%s", ixy);
+ break;
+ default:
+ *dst++ = *src;
+ }
+ src++;
+ }
+ *dst = '\0';
+ }
+ else
+ {
+ dst += sprintf(dst, "%s", s_mnemonic[d->mnemonic]);
+ }
+
+ return pos | s_flags[d->mnemonic] | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/z8000/8000dasm.c b/src/emu/cpu/z8000/8000dasm.c
new file mode 100644
index 00000000000..ac380060ade
--- /dev/null
+++ b/src/emu/cpu/z8000/8000dasm.c
@@ -0,0 +1,318 @@
+/*****************************************************************************
+ *
+ * 8000dasm.c
+ * Portable Z8000(2) emulator
+ * Z8000 disassembler; requires the z8000_exec table to be initialized
+ *
+ * Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * You can contact me at juergen@mame.net or pullmoll@stop1984.com
+ *
+ * - This source code is released as freeware for non-commercial purposes
+ * as part of the M.A.M.E. (Multiple Arcade Machine Emulator) project.
+ * The licensing terms of MAME apply to this piece of code for the MAME
+ * project and derviative works, as defined by the MAME license. You
+ * may opt to make modifications, improvements or derivative works under
+ * that same conditions, and the MAME project may opt to keep
+ * modifications, improvements or derivatives under their terms exclusively.
+ *
+ * - Alternatively you can choose to apply the terms of the "GPL" (see
+ * below) to this - and only this - piece of code or your derivative works.
+ * Note that in no case your choice can have any impact on any other
+ * source code of the MAME project, or binary, or executable, be it closely
+ * or losely related to this piece of code.
+ *
+ * - At your choice you are also free to remove either licensing terms from
+ * this file and continue to use it under only one of the two licenses. Do this
+ * if you think that licenses are not compatible (enough) for you, or if you
+ * consider either license 'too restrictive' or 'too free'.
+ *
+ * - GPL (GNU General Public License)
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *****************************************************************************/
+
+#include "z8000.h"
+#include "z8000cpu.h"
+#include "cpuintrf.h"
+
+static int n[12]; /* opcode nibbles */
+static int b[6]; /* opcode bytes */
+static int w[3]; /* opcode words */
+
+static void GET_OP(const UINT8 *oprom, int i, unsigned offset)
+{
+ UINT16 opcode = (oprom[offset] << 8) | oprom[offset + 1];
+ w[i] = opcode;
+ b[i*2+0] = opcode >> 8;
+ b[i*2+1] = opcode & 0xff;
+ n[i*4+0] = (opcode >> 12) & 0x0f;
+ n[i*4+1] = (opcode >> 8) & 0x0f;
+ n[i*4+2] = (opcode >> 4) & 0x0f;
+ n[i*4+3] = opcode & 0x0f;
+}
+
+static const char *cc[16] = {
+ "n", "lt", "le", "ule", "pe/ov", "mi", "eq/z", "c/ult",
+ "a", "ge", "gt", "ugt", "po/nov", "pl", "ne/nz", "nc/uge"
+};
+
+static const char *flg[16] = {
+ "", "p/v", "s", "p/v,s", "z", "p/v,z", "s,z", "p/v,s,z",
+ "c", "p/v,c","s,c", "p/v,s,c", "z,c", "p/v,z,c","s,z,c","p/v,s,z,c"
+};
+
+static const char *ints[4] = {
+ "", "vi", "nvi", "vi,nvi"
+};
+
+offs_t z8000_dasm(char *buff, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ int new_pc = pc, i, tmp;
+ char *dst = buff;
+ const char *src;
+ Z8000_exec *o;
+ UINT32 flags = 0;
+
+ GET_OP(oprom, 0, new_pc - pc);
+ new_pc += 2;
+ switch (pc)
+ {
+ case 0x0000:
+ dst += sprintf(dst, ".word #$%04x ;RST", w[0]);
+ break;
+ case 0x0002:
+ dst += sprintf(dst, ".word #$%04x ;RST FCW", w[0]);
+ break;
+ case 0x0004:
+ dst += sprintf(dst, ".word #$%04x ;RST PC", w[0]);
+ break;
+ default:
+ o = &z8000_exec[w[0]];
+ if (o->size > 1) { GET_OP(oprom, 1, new_pc - pc); new_pc += 2; }
+ if (o->size > 2) { GET_OP(oprom, 2, new_pc - pc); new_pc += 2; }
+ src = o->dasm;
+ flags = o->dasmflags;
+
+ while (*src)
+ {
+ if (*src == '%')
+ {
+ src++;
+ switch (*src) {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ /* nibble number */
+ i = *src++ - '0';
+ dst += sprintf(dst, "%d", n[i]);
+ break;
+ case '#':
+ /* immediate */
+ src++;
+ switch (*src++) {
+ case 'b': /* imm8 (byte) */
+ i = *src++ - '0';
+ dst += sprintf(dst, "#$%02x", b[i]);
+ break;
+ case 'w': /* imm16 (word) */
+ i = *src++ - '0';
+ dst += sprintf(dst, "#$%04x", w[i]);
+ break;
+ case 'l': /* imm32 (long) */
+ i = *src++ - '0';
+ dst += sprintf(dst, "#$%04x%04x", w[i], w[i+1]);
+ break;
+ }
+ break;
+ case '$':
+ /* absolute immediate 8bit (rl/rr) */
+ src++;
+ i = *src++ - '0';
+ dst += sprintf(dst, "#%d", ((INT8)b[i]<0) ? -(INT8)b[i] : b[i]);
+ break;
+ case '+':
+ /* imm4m1 (inc/dec value) */
+ src++;
+ i = *src++ - '0';
+ dst += sprintf(dst, "%i", n[i] + 1);
+ break;
+ case '*':
+ /* left/right (rotate/shift) */
+ src++;
+ dst += sprintf(dst, "%c", b[2] ? 'r' : 'l');
+ break;
+ case '?':
+ /* imm1or2 (shift/rotate once or twice) */
+ src++;
+ i = *src++ - '0';
+ dst += sprintf(dst, "%c", (n[i] & 2) ? '2' : '1');
+ break;
+ case 'R':
+ src++;
+ tmp = ((n[1] & 0x01) << 16) + (n[3] << 8) + (n[7] & 0x08);
+ switch (tmp)
+ {
+ case 0x000: dst += sprintf(dst, "inirb "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x008: dst += sprintf(dst, "inib "); break;
+ case 0x010: dst += sprintf(dst, "sinirb"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x018: dst += sprintf(dst, "sinib "); break;
+ case 0x020: dst += sprintf(dst, "otirb "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x028: dst += sprintf(dst, "outib "); break;
+ case 0x030: dst += sprintf(dst, "soutib"); break;
+ case 0x038: dst += sprintf(dst, "sotirb"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x040: dst += sprintf(dst, "inb "); break;
+ case 0x048: dst += sprintf(dst, "inb "); break;
+ case 0x050: dst += sprintf(dst, "sinb "); break;
+ case 0x058: dst += sprintf(dst, "sinb "); break;
+ case 0x060: dst += sprintf(dst, "outb "); break;
+ case 0x068: dst += sprintf(dst, "outb "); break;
+ case 0x070: dst += sprintf(dst, "soutb "); break;
+ case 0x078: dst += sprintf(dst, "soutb "); break;
+ case 0x080: dst += sprintf(dst, "indrb "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x088: dst += sprintf(dst, "indb "); break;
+ case 0x090: dst += sprintf(dst, "sindrb"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x098: dst += sprintf(dst, "sindb "); break;
+ case 0x0a0: dst += sprintf(dst, "otdrb "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x0a8: dst += sprintf(dst, "outdb "); break;
+ case 0x0b0: dst += sprintf(dst, "soutdb"); break;
+ case 0x0b8: dst += sprintf(dst, "sotdrb"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x100: dst += sprintf(dst, "inir "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x108: dst += sprintf(dst, "ini "); break;
+ case 0x110: dst += sprintf(dst, "sinir "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x118: dst += sprintf(dst, "sini "); break;
+ case 0x120: dst += sprintf(dst, "otir "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x128: dst += sprintf(dst, "outi "); break;
+ case 0x130: dst += sprintf(dst, "souti "); break;
+ case 0x138: dst += sprintf(dst, "sotir "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x140: dst += sprintf(dst, "in "); break;
+ case 0x148: dst += sprintf(dst, "in "); break;
+ case 0x150: dst += sprintf(dst, "sin "); break;
+ case 0x158: dst += sprintf(dst, "sin "); break;
+ case 0x160: dst += sprintf(dst, "out "); break;
+ case 0x168: dst += sprintf(dst, "out "); break;
+ case 0x170: dst += sprintf(dst, "sout "); break;
+ case 0x178: dst += sprintf(dst, "sout "); break;
+ case 0x180: dst += sprintf(dst, "indr "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x188: dst += sprintf(dst, "ind "); break;
+ case 0x190: dst += sprintf(dst, "sindr "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x198: dst += sprintf(dst, "sind "); break;
+ case 0x1a0: dst += sprintf(dst, "otdr "); flags = DASMFLAG_STEP_OVER; break;
+ case 0x1a8: dst += sprintf(dst, "outd "); break;
+ case 0x1b0: dst += sprintf(dst, "soutd "); break;
+ case 0x1b8: dst += sprintf(dst, "sotdr "); flags = DASMFLAG_STEP_OVER; break;
+ default:
+ dst += sprintf(dst, "??????");
+ }
+ break;
+ case 'a':
+ /* address */
+ src++;
+ i = *src++ - '0';
+ dst += sprintf(dst, "$%04x", w[i]);
+ break;
+ case 'c':
+ /* condition code */
+ src++;
+ i = *src++ - '0';
+ if (n[i] == 8) { /* always? */
+ /* skip following comma */
+ if (*src == ',')
+ src++;
+ }
+ else dst += sprintf(dst, "%s", cc[n[i]]);
+ break;
+ case 'd':
+ /* displacement */
+ src++;
+ i = *src++ - '0';
+ switch (i) {
+ case 0: /* disp7 */
+ tmp = new_pc - 2 * (w[0] & 0x7f);
+ dst += sprintf(dst, "#$%04x", tmp);
+ break;
+ case 1: /* disp8 */
+ tmp = new_pc + 2 * (INT8)(w[0] & 0xff);
+ dst += sprintf(dst, "#$%04x", tmp);
+ break;
+ case 2: /* disp12 */
+ tmp = w[0] & 0x7ff;
+ if (w[0] & 0x800)
+ tmp = new_pc + 0x1000 -2 * tmp;
+ else
+ tmp = new_pc + -2 * tmp;
+ dst += sprintf(dst, "#$%04x", tmp);
+ break;
+ }
+ break;
+ case 'f':
+ /* flag (setflg/resflg/comflg) */
+ src++;
+ i = *src++ - '0';
+ dst += sprintf(dst, "%s", flg[n[i]]);
+ break;
+ case 'i':
+ /* interrupts */
+ src++;
+ i = *src++ - '0';
+ dst += sprintf(dst, "%s", ints[n[i] & 3]);
+ break;
+ case 'p':
+ /* disp16 (pc relative) */
+ src++;
+ i = *src++ - '0';
+ dst += sprintf(dst, "$%04x", new_pc + w[i]);
+ break;
+ case 'r':
+ /* register */
+ src++;
+ switch (*src++) {
+ case 'b':
+ /* byte */
+ i = *src++ - '0';
+ if (n[i] & 8)
+ dst += sprintf(dst, "rl%d", n[i] & 7);
+ else
+ dst += sprintf(dst, "rh%d", n[i]);
+ break;
+ case 'w':
+ /* word */
+ i = *src++ - '0';
+ dst += sprintf(dst, "r%d", n[i]);
+ break;
+ case 'l':
+ /* long */
+ i = *src++ - '0';
+ dst += sprintf(dst, "rr%d", n[i]);
+ break;
+ case 'q':
+ /* quad word (long long) */
+ i = *src++ - '0';
+ dst += sprintf(dst, "rq%d", n[i]);
+ break;
+ }
+ break;
+ default:
+ *dst++ = '%';
+ *dst++ = *src++;
+ break;
+ }
+ } else *dst++ = *src++;
+ }
+ *dst = '\0';
+ break;
+ }
+ return (new_pc - pc) | flags | DASMFLAG_SUPPORTED;
+}
+
diff --git a/src/emu/cpu/z8000/makedab.c b/src/emu/cpu/z8000/makedab.c
new file mode 100644
index 00000000000..58bf9c0a490
--- /dev/null
+++ b/src/emu/cpu/z8000/makedab.c
@@ -0,0 +1,87 @@
+#include <stdio.h>
+
+#define CF 0x100
+#define HF 0x200
+#define DF 0x400
+
+int dab[0x800];
+
+int main(int ac, char **av)
+{
+ int i, result;
+
+ for (i = 0; i < DF; i++) {
+ if (i & CF) {
+ if (i & 0x0f < 0x0a)
+ dab[i] = CF | ((i + 0x60) & 0xff);
+ else
+ dab[i] = CF | ((i + 0x66) & 0xff);
+ } else {
+ if (i & HF) {
+ if (i & 0xf0 < 0xa0)
+ dab[i] = ((i + 0x06) & 0xff);
+ else
+ dab[i] = CF | ((i + 0x66) & 0xff);
+ } else {
+ if ((i & 0xf0) < 0xa0 && (i & 0x0f) < 0x0a)
+ dab[i] = i & 0xff;
+ else if ((i & 0xf0) < 0x90 && (i & 0x0f) >= 0x0a)
+ dab[i] = ((i + 0x06) & 0xff);
+ else if ((i & 0xf0) >= 0xa0 && (i & 0x0f) < 0x0a)
+ dab[i] = CF | ((i + 0x60) & 0xff);
+ else if ((i & 0xf0) >= 0x90 && (i & 0x0f) >= 0x0a)
+ dab[i] = CF | ((i + 0x66) & 0xff);
+ else {
+ fprintf(stderr, "unhandled $%04x\n", i);
+ return 1;
+ }
+
+ }
+ }
+
+ if (i & CF) {
+ if (i & HF) {
+ dab[DF+i] = CF | ((i + 0x9a) & 0xff);
+ } else {
+ dab[DF+i] = CF | ((i + 0xa0) & 0xff);
+ }
+ } else {
+ if (i & HF) {
+ dab[DF+i] = CF | ((i + 0xfa) & 0xff);
+ } else {
+ dab[DF+i] = (i & 0xff);
+ }
+ }
+ }
+
+ printf("/************************************************ \n");
+ printf(" * Result table for Z8000 DAB instruction \n");
+ printf(" * \n");
+ printf(" * bits description \n");
+ printf(" * ---------------------------------------------- \n");
+ printf(" * 0..7 destination value \n");
+ printf(" * 8 carry flag before \n");
+ printf(" * 9 half carry flag before \n");
+ printf(" * 10 D flag (0 add/adc, 1 sub/sbc) \n");
+ printf(" * \n");
+ printf(" * result description \n");
+ printf(" * ---------------------------------------------- \n");
+ printf(" * 0..7 result value \n");
+ printf(" * 8 carry flag after \n");
+ printf(" ************************************************/\n");
+ printf("static UINT16 Z8000_dab[0x800] = {\n");
+ for (i = 0; i < 0x800; i++) {
+ if ((i & 0x3ff) == 0) {
+ if (i & 0x400)
+ printf("\t/* sub/sbc results */\n");
+ else
+ printf("\t/* add/adc results */\n");
+ }
+ if ((i & 7) == 0) printf("\t");
+ printf("0x%03x,",dab[i]);
+ if ((i & 7) == 7) printf("\n");
+ }
+ printf("};\n");
+
+ return 0;
+}
diff --git a/src/emu/cpu/z8000/z8000.c b/src/emu/cpu/z8000/z8000.c
new file mode 100644
index 00000000000..1e1cfd2ee7a
--- /dev/null
+++ b/src/emu/cpu/z8000/z8000.c
@@ -0,0 +1,756 @@
+/*****************************************************************************
+ *
+ * z8000.c
+ * Portable Z8000(2) emulator
+ * Z8000 MAME interface
+ *
+ * Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
+ * You can contact me at juergen@mame.net or pullmoll@stop1984.com
+ *
+ * - This source code is released as freeware for non-commercial purposes
+ * as part of the M.A.M.E. (Multiple Arcade Machine Emulator) project.
+ * The licensing terms of MAME apply to this piece of code for the MAME
+ * project and derviative works, as defined by the MAME license. You
+ * may opt to make modifications, improvements or derivative works under
+ * that same conditions, and the MAME project may opt to keep
+ * modifications, improvements or derivatives under their terms exclusively.
+ *
+ * - Alternatively you can choose to apply the terms of the "GPL" (see
+ * below) to this - and only this - piece of code or your derivative works.
+ * Note that in no case your choice can have any impact on any other
+ * source code of the MAME project, or binary, or executable, be it closely
+ * or losely related to this piece of code.
+ *
+ * - At your choice you are also free to remove either licensing terms from
+ * this file and continue to use it under only one of the two licenses. Do this
+ * if you think that licenses are not compatible (enough) for you, or if you
+ * consider either license 'too restrictive' or 'too free'.
+ *
+ * - GPL (GNU General Public License)
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "z8000.h"
+#include "z8000cpu.h"
+#include "osd_cpu.h"
+
+#define VERBOSE 0
+
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+/* opcode execution table */
+Z8000_exec *z8000_exec = NULL;
+
+typedef union {
+ UINT8 B[16]; /* RL0,RH0,RL1,RH1...RL7,RH7 */
+ UINT16 W[16]; /* R0,R1,R2...R15 */
+ UINT32 L[8]; /* RR0,RR2,RR4..RR14 */
+ UINT64 Q[4]; /* RQ0,RQ4,..RQ12 */
+} z8000_reg_file;
+
+typedef struct {
+ UINT16 op[4]; /* opcodes/data of current instruction */
+ UINT16 ppc; /* previous program counter */
+ UINT16 pc; /* program counter */
+ UINT16 psap; /* program status pointer */
+ UINT16 fcw; /* flags and control word */
+ UINT16 refresh; /* refresh timer/counter */
+ UINT16 nsp; /* system stack pointer */
+ UINT16 irq_req; /* CPU is halted, interrupt or trap request */
+ UINT16 irq_srv; /* serviced interrupt request */
+ UINT16 irq_vec; /* interrupt vector */
+ z8000_reg_file regs;/* registers */
+ int nmi_state; /* NMI line state */
+ int irq_state[2]; /* IRQ line states (NVI, VI) */
+ int (*irq_callback)(int irqline);
+} z8000_Regs;
+
+int z8000_ICount;
+
+/* current CPU context */
+static z8000_Regs Z;
+
+/* zero, sign and parity flags for logical byte operations */
+static UINT8 z8000_zsp[256];
+
+/* conversion table for Z8000 DAB opcode */
+#include "z8000dab.h"
+
+/**************************************************************************
+ * This is the register file layout:
+ *
+ * BYTE WORD LONG QUAD
+ * msb lsb bits bits bits
+ * RH0 - RL0 R 0 15- 0 RR 0 31-16 RQ 0 63-48
+ * RH1 - RL1 R 1 15- 0 15- 0 47-32
+ * RH2 - RL2 R 2 15- 0 RR 2 31-16 31-16
+ * RH3 - RL3 R 3 15- 0 15- 0 15- 0
+ * RH4 - RL4 R 4 15- 0 RR 4 31-16 RQ 4 63-48
+ * RH5 - RL5 R 5 15- 0 15- 0 47-32
+ * RH6 - RL6 R 6 15- 0 RR 6 31-16 31-16
+ * RH7 - RL7 R 7 15- 0 15- 0 15- 0
+ * R 8 15- 0 RR 8 31-16 RQ 8 63-48
+ * R 9 15- 0 15- 0 47-32
+ * R10 15- 0 RR10 31-16 31-16
+ * R11 15- 0 15- 0 15- 0
+ * R12 15- 0 RR12 31-16 RQ12 63-48
+ * R13 15- 0 15- 0 47-32
+ * R14 15- 0 RR14 31-16 31-16
+ * R15 15- 0 15- 0 15- 0
+ *
+ * Note that for LSB_FIRST machines we have the case that the RR registers
+ * use the lower numbered R registers in the higher bit positions.
+ * And also the RQ registers use the lower numbered RR registers in the
+ * higher bit positions.
+ * That's the reason for the ordering in the following pointer table.
+ **************************************************************************/
+#ifdef LSB_FIRST
+ /* pointers to byte (8bit) registers */
+ static UINT8 *pRB[16] =
+ {
+ &Z.regs.B[ 7],&Z.regs.B[ 5],&Z.regs.B[ 3],&Z.regs.B[ 1],
+ &Z.regs.B[15],&Z.regs.B[13],&Z.regs.B[11],&Z.regs.B[ 9],
+ &Z.regs.B[ 6],&Z.regs.B[ 4],&Z.regs.B[ 2],&Z.regs.B[ 0],
+ &Z.regs.B[14],&Z.regs.B[12],&Z.regs.B[10],&Z.regs.B[ 8]
+ };
+
+ static UINT16 *pRW[16] =
+ {
+ &Z.regs.W[ 3],&Z.regs.W[ 2],&Z.regs.W[ 1],&Z.regs.W[ 0],
+ &Z.regs.W[ 7],&Z.regs.W[ 6],&Z.regs.W[ 5],&Z.regs.W[ 4],
+ &Z.regs.W[11],&Z.regs.W[10],&Z.regs.W[ 9],&Z.regs.W[ 8],
+ &Z.regs.W[15],&Z.regs.W[14],&Z.regs.W[13],&Z.regs.W[12]
+ };
+
+ /* pointers to long (32bit) registers */
+ static UINT32 *pRL[16] =
+ {
+ &Z.regs.L[ 1],&Z.regs.L[ 1],&Z.regs.L[ 0],&Z.regs.L[ 0],
+ &Z.regs.L[ 3],&Z.regs.L[ 3],&Z.regs.L[ 2],&Z.regs.L[ 2],
+ &Z.regs.L[ 5],&Z.regs.L[ 5],&Z.regs.L[ 4],&Z.regs.L[ 4],
+ &Z.regs.L[ 7],&Z.regs.L[ 7],&Z.regs.L[ 6],&Z.regs.L[ 6]
+ };
+
+#else /* MSB_FIRST */
+
+ /* pointers to byte (8bit) registers */
+ static UINT8 *pRB[16] =
+ {
+ &Z.regs.B[ 0],&Z.regs.B[ 2],&Z.regs.B[ 4],&Z.regs.B[ 6],
+ &Z.regs.B[ 8],&Z.regs.B[10],&Z.regs.B[12],&Z.regs.B[14],
+ &Z.regs.B[ 1],&Z.regs.B[ 3],&Z.regs.B[ 5],&Z.regs.B[ 7],
+ &Z.regs.B[ 9],&Z.regs.B[11],&Z.regs.B[13],&Z.regs.B[15]
+ };
+
+ /* pointers to word (16bit) registers */
+ static UINT16 *pRW[16] =
+ {
+ &Z.regs.W[ 0],&Z.regs.W[ 1],&Z.regs.W[ 2],&Z.regs.W[ 3],
+ &Z.regs.W[ 4],&Z.regs.W[ 5],&Z.regs.W[ 6],&Z.regs.W[ 7],
+ &Z.regs.W[ 8],&Z.regs.W[ 9],&Z.regs.W[10],&Z.regs.W[11],
+ &Z.regs.W[12],&Z.regs.W[13],&Z.regs.W[14],&Z.regs.W[15]
+ };
+
+ /* pointers to long (32bit) registers */
+ static UINT32 *pRL[16] =
+ {
+ &Z.regs.L[ 0],&Z.regs.L[ 0],&Z.regs.L[ 1],&Z.regs.L[ 1],
+ &Z.regs.L[ 2],&Z.regs.L[ 2],&Z.regs.L[ 3],&Z.regs.L[ 3],
+ &Z.regs.L[ 4],&Z.regs.L[ 4],&Z.regs.L[ 5],&Z.regs.L[ 5],
+ &Z.regs.L[ 6],&Z.regs.L[ 6],&Z.regs.L[ 7],&Z.regs.L[ 7]
+ };
+
+#endif
+
+/* pointers to quad word (64bit) registers */
+static UINT64 *pRQ[16] = {
+ &Z.regs.Q[ 0],&Z.regs.Q[ 0],&Z.regs.Q[ 0],&Z.regs.Q[ 0],
+ &Z.regs.Q[ 1],&Z.regs.Q[ 1],&Z.regs.Q[ 1],&Z.regs.Q[ 1],
+ &Z.regs.Q[ 2],&Z.regs.Q[ 2],&Z.regs.Q[ 2],&Z.regs.Q[ 2],
+ &Z.regs.Q[ 3],&Z.regs.Q[ 3],&Z.regs.Q[ 3],&Z.regs.Q[ 3]};
+
+INLINE UINT16 RDOP(void)
+{
+ UINT16 res = cpu_readop16(PC);
+ PC += 2;
+ return res;
+}
+
+INLINE UINT8 RDMEM_B(UINT16 addr)
+{
+ return program_read_byte_16be(addr);
+}
+
+INLINE UINT16 RDMEM_W(UINT16 addr)
+{
+ addr &= ~1;
+ return program_read_word_16be(addr);
+}
+
+INLINE UINT32 RDMEM_L(UINT16 addr)
+{
+ UINT32 result;
+ addr &= ~1;
+ result = program_read_word_16be(addr) << 16;
+ return result + program_read_word_16be(addr + 2);
+}
+
+INLINE void WRMEM_B(UINT16 addr, UINT8 value)
+{
+ program_write_byte_16be(addr, value);
+}
+
+INLINE void WRMEM_W(UINT16 addr, UINT16 value)
+{
+ addr &= ~1;
+ program_write_word_16be(addr, value);
+}
+
+INLINE void WRMEM_L(UINT16 addr, UINT32 value)
+{
+ addr &= ~1;
+ program_write_word_16be(addr, value >> 16);
+ program_write_word_16be((UINT16)(addr + 2), value & 0xffff);
+}
+
+INLINE UINT8 RDPORT_B(int mode, UINT16 addr)
+{
+ if( mode == 0 )
+ {
+ return io_read_byte_8(addr);
+ }
+ else
+ {
+ /* how to handle MMU reads? */
+ return 0x00;
+ }
+}
+
+INLINE UINT16 RDPORT_W(int mode, UINT16 addr)
+{
+ if( mode == 0 )
+ {
+ return io_read_byte_8((UINT16)(addr)) +
+ (io_read_byte_8((UINT16)(addr+1)) << 8);
+ }
+ else
+ {
+ /* how to handle MMU reads? */
+ return 0x0000;
+ }
+}
+
+INLINE UINT32 RDPORT_L(int mode, UINT16 addr)
+{
+ if( mode == 0 )
+ {
+ return io_read_byte_8((UINT16)(addr)) +
+ (io_read_byte_8((UINT16)(addr+1)) << 8) +
+ (io_read_byte_8((UINT16)(addr+2)) << 16) +
+ (io_read_byte_8((UINT16)(addr+3)) << 24);
+ }
+ else
+ {
+ /* how to handle MMU reads? */
+ return 0x00000000;
+ }
+}
+
+INLINE void WRPORT_B(int mode, UINT16 addr, UINT8 value)
+{
+ if( mode == 0 )
+ {
+ io_write_byte_8(addr,value);
+ }
+ else
+ {
+ /* how to handle MMU writes? */
+ }
+}
+
+INLINE void WRPORT_W(int mode, UINT16 addr, UINT16 value)
+{
+ if( mode == 0 )
+ {
+ io_write_byte_8((UINT16)(addr),value & 0xff);
+ io_write_byte_8((UINT16)(addr+1),(value >> 8) & 0xff);
+ }
+ else
+ {
+ /* how to handle MMU writes? */
+ }
+}
+
+INLINE void WRPORT_L(int mode, UINT16 addr, UINT32 value)
+{
+ if( mode == 0 )
+ {
+ io_write_byte_8((UINT16)(addr),value & 0xff);
+ io_write_byte_8((UINT16)(addr+1),(value >> 8) & 0xff);
+ io_write_byte_8((UINT16)(addr+2),(value >> 16) & 0xff);
+ io_write_byte_8((UINT16)(addr+3),(value >> 24) & 0xff);
+ }
+ else
+ {
+ /* how to handle MMU writes? */
+ }
+}
+
+#include "z8000ops.c"
+#include "z8000tbl.c"
+
+INLINE void set_irq(int type)
+{
+ switch ((type >> 8) & 255)
+ {
+ case Z8000_TRAP >> 8:
+ if (IRQ_SRV >= Z8000_TRAP)
+ return; /* double TRAP.. very bad :( */
+ IRQ_REQ = type;
+ break;
+ case Z8000_NMI >> 8:
+ if (IRQ_SRV >= Z8000_NMI)
+ return; /* no NMIs inside trap */
+ IRQ_REQ = type;
+ break;
+ case Z8000_SEGTRAP >> 8:
+ if (IRQ_SRV >= Z8000_SEGTRAP)
+ return; /* no SEGTRAPs inside NMI/TRAP */
+ IRQ_REQ = type;
+ break;
+ case Z8000_NVI >> 8:
+ if (IRQ_SRV >= Z8000_NVI)
+ return; /* no NVIs inside SEGTRAP/NMI/TRAP */
+ IRQ_REQ = type;
+ break;
+ case Z8000_VI >> 8:
+ if (IRQ_SRV >= Z8000_VI)
+ return; /* no VIs inside NVI/SEGTRAP/NMI/TRAP */
+ IRQ_REQ = type;
+ break;
+ case Z8000_SYSCALL >> 8:
+ LOG(("Z8K#%d SYSCALL $%02x\n", cpu_getactivecpu(), type & 0xff));
+ IRQ_REQ = type;
+ break;
+ default:
+ logerror("Z8000 invalid Cause_Interrupt %04x\n", type);
+ return;
+ }
+ /* set interrupt request flag, reset HALT flag */
+ IRQ_REQ = type & ~Z8000_HALT;
+}
+
+
+INLINE void Interrupt(void)
+{
+ UINT16 fcw = FCW;
+
+ if (IRQ_REQ & Z8000_NVI)
+ {
+ int type = (*Z.irq_callback)(0);
+ set_irq(type);
+ }
+
+ if (IRQ_REQ & Z8000_VI)
+ {
+ int type = (*Z.irq_callback)(1);
+ set_irq(type);
+ }
+
+ /* trap ? */
+ if ( IRQ_REQ & Z8000_TRAP )
+ {
+ CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
+ PUSHW( SP, PC ); /* save current PC */
+ PUSHW( SP, fcw ); /* save current FCW */
+ PUSHW( SP, IRQ_REQ ); /* save interrupt/trap type tag */
+ IRQ_SRV = IRQ_REQ;
+ IRQ_REQ &= ~Z8000_TRAP;
+ PC = TRAP;
+ LOG(("Z8K#%d trap $%04x\n", cpu_getactivecpu(), PC ));
+ }
+ else
+ if ( IRQ_REQ & Z8000_SYSCALL )
+ {
+ CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
+ PUSHW( SP, PC ); /* save current PC */
+ PUSHW( SP, fcw ); /* save current FCW */
+ PUSHW( SP, IRQ_REQ ); /* save interrupt/trap type tag */
+ IRQ_SRV = IRQ_REQ;
+ IRQ_REQ &= ~Z8000_SYSCALL;
+ PC = SYSCALL;
+ LOG(("Z8K#%d syscall $%04x\n", cpu_getactivecpu(), PC ));
+ }
+ else
+ if ( IRQ_REQ & Z8000_SEGTRAP )
+ {
+ CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
+ PUSHW( SP, PC ); /* save current PC */
+ PUSHW( SP, fcw ); /* save current FCW */
+ PUSHW( SP, IRQ_REQ ); /* save interrupt/trap type tag */
+ IRQ_SRV = IRQ_REQ;
+ IRQ_REQ &= ~Z8000_SEGTRAP;
+ PC = SEGTRAP;
+ LOG(("Z8K#%d segtrap $%04x\n", cpu_getactivecpu(), PC ));
+ }
+ else
+ if ( IRQ_REQ & Z8000_NMI )
+ {
+ CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
+ PUSHW( SP, PC ); /* save current PC */
+ PUSHW( SP, fcw ); /* save current FCW */
+ PUSHW( SP, IRQ_REQ ); /* save interrupt/trap type tag */
+ IRQ_SRV = IRQ_REQ;
+ fcw = RDMEM_W( NMI );
+ PC = RDMEM_W( NMI + 2 );
+ IRQ_REQ &= ~Z8000_NMI;
+ CHANGE_FCW(fcw);
+ PC = NMI;
+ LOG(("Z8K#%d NMI $%04x\n", cpu_getactivecpu(), PC ));
+ }
+ else
+ if ( (IRQ_REQ & Z8000_NVI) && (FCW & F_NVIE) )
+ {
+ CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
+ PUSHW( SP, PC ); /* save current PC */
+ PUSHW( SP, fcw ); /* save current FCW */
+ PUSHW( SP, IRQ_REQ ); /* save interrupt/trap type tag */
+ IRQ_SRV = IRQ_REQ;
+ fcw = RDMEM_W( NVI );
+ PC = RDMEM_W( NVI + 2 );
+ IRQ_REQ &= ~Z8000_NVI;
+ CHANGE_FCW(fcw);
+ LOG(("Z8K#%d NVI $%04x\n", cpu_getactivecpu(), PC ));
+ }
+ else
+ if ( (IRQ_REQ & Z8000_VI) && (FCW & F_VIE) )
+ {
+ CHANGE_FCW(fcw | F_S_N);/* swap to system stack */
+ PUSHW( SP, PC ); /* save current PC */
+ PUSHW( SP, fcw ); /* save current FCW */
+ PUSHW( SP, IRQ_REQ ); /* save interrupt/trap type tag */
+ IRQ_SRV = IRQ_REQ;
+ fcw = RDMEM_W( IRQ_VEC );
+ PC = RDMEM_W( VEC00 + 2 * (IRQ_REQ & 0xff) );
+ IRQ_REQ &= ~Z8000_VI;
+ CHANGE_FCW(fcw);
+ LOG(("Z8K#%d VI [$%04x/$%04x] fcw $%04x, pc $%04x\n", cpu_getactivecpu(), IRQ_VEC, VEC00 + VEC00 + 2 * (IRQ_REQ & 0xff), FCW, PC ));
+ }
+}
+
+
+static void z8000_reset(void)
+{
+ int (*save_irqcallback)(int) = Z.irq_callback;
+ memset(&Z, 0, sizeof(z8000_Regs));
+ Z.irq_callback = save_irqcallback;
+ FCW = RDMEM_W( 2 ); /* get reset FCW */
+ PC = RDMEM_W( 4 ); /* get reset PC */
+ change_pc(PC);
+}
+
+static void z8000_exit(void)
+{
+ z8000_deinit();
+}
+
+static int z8000_execute(int cycles)
+{
+ z8000_ICount = cycles;
+
+ do
+ {
+ /* any interrupt request pending? */
+ if (IRQ_REQ)
+ Interrupt();
+
+ CALL_MAME_DEBUG;
+
+ if (IRQ_REQ & Z8000_HALT)
+ {
+ z8000_ICount = 0;
+ }
+ else
+ {
+ Z8000_exec *exec;
+ Z.op[0] = RDOP();
+ exec = &z8000_exec[Z.op[0]];
+
+ if (exec->size > 1)
+ Z.op[1] = RDOP();
+ if (exec->size > 2)
+ Z.op[2] = RDOP();
+
+ z8000_ICount -= exec->cycles;
+ (*exec->opcode)();
+
+ }
+ } while (z8000_ICount > 0);
+
+ return cycles - z8000_ICount;
+
+}
+
+static void z8000_get_context(void *dst)
+{
+ if( dst )
+ *(z8000_Regs*)dst = Z;
+}
+
+static void z8000_set_context(void *src)
+{
+ if( src )
+ {
+ Z = *(z8000_Regs*)src;
+ change_pc(PC);
+ }
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (Z.nmi_state == state)
+ return;
+
+ Z.nmi_state = state;
+
+ if (state != CLEAR_LINE)
+ {
+ if (IRQ_SRV >= Z8000_NMI) /* no NMIs inside trap */
+ return;
+ IRQ_REQ = Z8000_NMI;
+ IRQ_VEC = NMI;
+ }
+ }
+ else if (irqline < 2)
+ {
+ Z.irq_state[irqline] = state;
+ if (irqline == 0)
+ {
+ if (state == CLEAR_LINE)
+ {
+ if (!(FCW & F_NVIE))
+ IRQ_REQ &= ~Z8000_NVI;
+ }
+ else
+ {
+ if (FCW & F_NVIE)
+ IRQ_REQ |= Z8000_NVI;
+ }
+ }
+ else
+ {
+ if (state == CLEAR_LINE)
+ {
+ if (!(FCW & F_VIE))
+ IRQ_REQ &= ~Z8000_VI;
+ }
+ else
+ {
+ if (FCW & F_VIE)
+ IRQ_REQ |= Z8000_VI;
+ }
+ }
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void z8000_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+
+ case CPUINFO_INT_PC: PC = info->i; change_pc(PC); break;
+ case CPUINFO_INT_REGISTER + Z8000_PC: PC = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + Z8000_NSP: NSP = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_FCW: FCW = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_PSAP: PSAP = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_REFRESH: REFRESH = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_IRQ_REQ: IRQ_REQ = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_IRQ_SRV: IRQ_SRV = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_IRQ_VEC: IRQ_VEC = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R0: RW( 0) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R1: RW( 1) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R2: RW( 2) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R3: RW( 3) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R4: RW( 4) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R5: RW( 5) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R6: RW( 6) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R7: RW( 7) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R8: RW( 8) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R9: RW( 9) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R10: RW(10) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R11: RW(11) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R12: RW(12) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R13: RW(13) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R14: RW(14) = info->i; break;
+ case CPUINFO_INT_REGISTER + Z8000_R15: RW(15) = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void z8000_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(Z); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 16; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = Z.nmi_state; break;
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = Z.irq_state[0]; break;
+ case CPUINFO_INT_INPUT_STATE + 1: info->i = Z.irq_state[1]; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + Z8000_PC: info->i = PC; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + Z8000_NSP: info->i = NSP; break;
+ case CPUINFO_INT_REGISTER + Z8000_FCW: info->i = FCW; break;
+ case CPUINFO_INT_REGISTER + Z8000_PSAP: info->i = PSAP; break;
+ case CPUINFO_INT_REGISTER + Z8000_REFRESH: info->i = REFRESH; break;
+ case CPUINFO_INT_REGISTER + Z8000_IRQ_REQ: info->i = IRQ_REQ; break;
+ case CPUINFO_INT_REGISTER + Z8000_IRQ_SRV: info->i = IRQ_SRV; break;
+ case CPUINFO_INT_REGISTER + Z8000_IRQ_VEC: info->i = IRQ_VEC; break;
+ case CPUINFO_INT_REGISTER + Z8000_R0: info->i = RW( 0); break;
+ case CPUINFO_INT_REGISTER + Z8000_R1: info->i = RW( 1); break;
+ case CPUINFO_INT_REGISTER + Z8000_R2: info->i = RW( 2); break;
+ case CPUINFO_INT_REGISTER + Z8000_R3: info->i = RW( 3); break;
+ case CPUINFO_INT_REGISTER + Z8000_R4: info->i = RW( 4); break;
+ case CPUINFO_INT_REGISTER + Z8000_R5: info->i = RW( 5); break;
+ case CPUINFO_INT_REGISTER + Z8000_R6: info->i = RW( 6); break;
+ case CPUINFO_INT_REGISTER + Z8000_R7: info->i = RW( 7); break;
+ case CPUINFO_INT_REGISTER + Z8000_R8: info->i = RW( 8); break;
+ case CPUINFO_INT_REGISTER + Z8000_R9: info->i = RW( 9); break;
+ case CPUINFO_INT_REGISTER + Z8000_R10: info->i = RW(10); break;
+ case CPUINFO_INT_REGISTER + Z8000_R11: info->i = RW(11); break;
+ case CPUINFO_INT_REGISTER + Z8000_R12: info->i = RW(12); break;
+ case CPUINFO_INT_REGISTER + Z8000_R13: info->i = RW(13); break;
+ case CPUINFO_INT_REGISTER + Z8000_R14: info->i = RW(14); break;
+ case CPUINFO_INT_REGISTER + Z8000_R15: info->i = RW(15); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = z8000_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = z8000_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = z8000_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = z8000_init; break;
+ case CPUINFO_PTR_RESET: info->reset = z8000_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = z8000_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = z8000_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = z8000_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &z8000_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "Z8002"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Zilog Z8000"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.1"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 1998,1999 Juergen Buchmueller, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ Z.fcw & 0x8000 ? 's':'.',
+ Z.fcw & 0x4000 ? 'n':'.',
+ Z.fcw & 0x2000 ? 'e':'.',
+ Z.fcw & 0x1000 ? '2':'.',
+ Z.fcw & 0x0800 ? '1':'.',
+ Z.fcw & 0x0400 ? '?':'.',
+ Z.fcw & 0x0200 ? '?':'.',
+ Z.fcw & 0x0100 ? '?':'.',
+ Z.fcw & 0x0080 ? 'C':'.',
+ Z.fcw & 0x0040 ? 'Z':'.',
+ Z.fcw & 0x0020 ? 'S':'.',
+ Z.fcw & 0x0010 ? 'V':'.',
+ Z.fcw & 0x0008 ? 'D':'.',
+ Z.fcw & 0x0004 ? 'H':'.',
+ Z.fcw & 0x0002 ? '?':'.',
+ Z.fcw & 0x0001 ? '?':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + Z8000_PC: sprintf(info->s, "PC :%04X", Z.pc); break;
+ case CPUINFO_STR_REGISTER + Z8000_NSP: sprintf(info->s, "SP :%04X", Z.nsp); break;
+ case CPUINFO_STR_REGISTER + Z8000_FCW: sprintf(info->s, "FCW:%04X", Z.fcw); break;
+ case CPUINFO_STR_REGISTER + Z8000_PSAP: sprintf(info->s, "NSP:%04X", Z.psap); break;
+ case CPUINFO_STR_REGISTER + Z8000_REFRESH: sprintf(info->s, "REFR:%04X", Z.refresh); break;
+ case CPUINFO_STR_REGISTER + Z8000_IRQ_REQ: sprintf(info->s, "IRQR:%04X", Z.irq_req); break;
+ case CPUINFO_STR_REGISTER + Z8000_IRQ_SRV: sprintf(info->s, "IRQS:%04X", Z.irq_srv); break;
+ case CPUINFO_STR_REGISTER + Z8000_IRQ_VEC: sprintf(info->s, "IRQV:%04X", Z.irq_vec); break;
+#ifdef LSB_FIRST
+#define REG_XOR 3
+#else
+#define REG_XOR 0
+#endif
+ case CPUINFO_STR_REGISTER + Z8000_R0: sprintf(info->s, "R0 :%04X", Z.regs.W[ 0^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R1: sprintf(info->s, "R1 :%04X", Z.regs.W[ 1^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R2: sprintf(info->s, "R2 :%04X", Z.regs.W[ 2^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R3: sprintf(info->s, "R3 :%04X", Z.regs.W[ 3^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R4: sprintf(info->s, "R4 :%04X", Z.regs.W[ 4^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R5: sprintf(info->s, "R5 :%04X", Z.regs.W[ 5^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R6: sprintf(info->s, "R6 :%04X", Z.regs.W[ 6^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R7: sprintf(info->s, "R7 :%04X", Z.regs.W[ 7^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R8: sprintf(info->s, "R8 :%04X", Z.regs.W[ 8^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R9: sprintf(info->s, "R9 :%04X", Z.regs.W[ 9^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R10: sprintf(info->s, "R10:%04X", Z.regs.W[10^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R11: sprintf(info->s, "R11:%04X", Z.regs.W[11^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R12: sprintf(info->s, "R12:%04X", Z.regs.W[12^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R13: sprintf(info->s, "R13:%04X", Z.regs.W[13^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R14: sprintf(info->s, "R14:%04X", Z.regs.W[14^REG_XOR]); break;
+ case CPUINFO_STR_REGISTER + Z8000_R15: sprintf(info->s, "R15:%04X", Z.regs.W[15^REG_XOR]); break;
+ }
+}
diff --git a/src/emu/cpu/z8000/z8000.h b/src/emu/cpu/z8000/z8000.h
new file mode 100644
index 00000000000..92f07f30f71
--- /dev/null
+++ b/src/emu/cpu/z8000/z8000.h
@@ -0,0 +1,29 @@
+#ifndef Z8K_H
+
+#include "cpuintrf.h"
+
+enum {
+ Z8000_PC=1, Z8000_NSP, Z8000_FCW, Z8000_PSAP, Z8000_REFRESH,
+ Z8000_IRQ_REQ, Z8000_IRQ_SRV, Z8000_IRQ_VEC,
+ Z8000_R0, Z8000_R1, Z8000_R2, Z8000_R3,
+ Z8000_R4, Z8000_R5, Z8000_R6, Z8000_R7,
+ Z8000_R8, Z8000_R9, Z8000_R10, Z8000_R11,
+ Z8000_R12, Z8000_R13, Z8000_R14, Z8000_R15 };
+
+/* Interrupt Types that can be generated by outside sources */
+#define Z8000_TRAP 0x4000 /* internal trap */
+#define Z8000_NMI 0x2000 /* non maskable interrupt */
+#define Z8000_SEGTRAP 0x1000 /* segment trap (Z8001) */
+#define Z8000_NVI 0x0800 /* non vectored interrupt */
+#define Z8000_VI 0x0400 /* vectored interrupt (LSB is vector) */
+#define Z8000_SYSCALL 0x0200 /* system call (lsb is vector) */
+#define Z8000_HALT 0x0100 /* halted flag */
+
+/* PUBLIC FUNCTIONS */
+extern void z8000_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+offs_t z8000_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+#endif
+
+#endif /* Z8K_H */
diff --git a/src/emu/cpu/z8000/z8000cpu.h b/src/emu/cpu/z8000/z8000cpu.h
new file mode 100644
index 00000000000..c52a122fe07
--- /dev/null
+++ b/src/emu/cpu/z8000/z8000cpu.h
@@ -0,0 +1,196 @@
+/*****************************************************************************
+ *
+ * z8000cpu.h
+ * Portable Z8000(2) emulator
+ * Macros and types used in z8000.c / z8000ops.c / z8000tbl.c
+ *
+ * Copyright (c) 1998,1999 Juergen Buchmueller, all rights reserved.
+ * Bug fixes and MSB_FIRST compliance Ernesto Corvi.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+/* pointers to the registers inside the Z8000_Regs struct Z */
+#define RB(n) (*pRB[n])
+#define RW(n) (*pRW[n])
+#define RL(n) (*pRL[n])
+#define RQ(n) (*pRQ[n])
+
+/* the register used as stack pointer */
+#define SP 15
+
+/* programm status */
+#define PPC Z.ppc
+#define PC Z.pc
+#define PSAP Z.psap
+#define FCW Z.fcw
+#define REFRESH Z.refresh
+#define NSP Z.nsp
+#define IRQ_REQ Z.irq_req
+#define IRQ_SRV Z.irq_srv
+#define IRQ_VEC Z.irq_vec
+
+/* these vectors are based on PSAP */
+#define RST (Z.psap + 0x0000) /* start up FCW and PC */
+#define EPU (Z.psap + 0x0004) /* extension processor unit? trap */
+#define TRAP (Z.psap + 0x0008) /* privilege violation trap */
+#define SYSCALL (Z.psap + 0x000c) /* system call SC */
+#define SEGTRAP (Z.psap + 0x0010) /* segment trap */
+#define NMI (Z.psap + 0x0014) /* non maskable interrupt */
+#define NVI (Z.psap + 0x0018) /* non vectored interrupt */
+#define VI (Z.psap + 0x001c) /* vectored interrupt */
+#define VEC00 (Z.psap + 0x001e) /* vector n PC value */
+
+/* bits of the FCW */
+#define F_SEG 0x8000 /* segmented mode (Z8001 only) */
+#define F_S_N 0x4000 /* system / normal mode */
+#define F_EPU 0x2000 /* extension processor unit? */
+#define F_NVIE 0x1000 /* non vectored interrupt enable */
+#define F_VIE 0x0800 /* vectored interrupt enable */
+#define F_10 0x0400 /* unused */
+#define F_9 0x0200 /* unused */
+#define F_8 0x0100 /* unused */
+#define F_C 0x0080 /* carry flag */
+#define F_Z 0x0040 /* zero flag */
+#define F_S 0x0020 /* sign flag */
+#define F_PV 0x0010 /* parity/overflow flag */
+#define F_DA 0x0008 /* decimal adjust flag (0 add/adc, 1 sub/sbc) */
+#define F_H 0x0004 /* half carry flag (byte arithmetic only) */
+#define F_1 0x0002 /* unused */
+#define F_0 0x0001 /* unused */
+
+/* opcode word numbers in Z.op[] array */
+#define OP0 0
+#define OP1 1
+#define OP2 2
+
+/* nibble shift factors for an opcode word */
+/* left to right: 0x1340 -> NIB0=1, NIB1=3, NIB2=4, NIB3=0 */
+#define NIB0 12
+#define NIB1 8
+#define NIB2 4
+#define NIB3 0
+
+/* sign bit masks for byte, word and long */
+#define S08 0x80
+#define S16 0x8000
+#define S32 0x80000000
+
+/* get a single flag bit 0/1 */
+#define GET_C ((FCW >> 7) & 1)
+#define GET_Z ((FCW >> 6) & 1)
+#define GET_S ((FCW >> 5) & 1)
+#define GET_PV ((FCW >> 4) & 1)
+#define GET_DA ((FCW >> 3) & 1)
+#define GET_H ((FCW >> 2) & 1)
+
+/* clear a single flag bit */
+#define CLR_C FCW &= ~F_C
+#define CLR_Z FCW &= ~F_Z
+#define CLR_S FCW &= ~F_S
+#define CLR_P FCW &= ~F_PV
+#define CLR_V FCW &= ~F_PV
+#define CLR_DA FCW &= ~F_DA
+#define CLR_H FCW &= ~F_H
+
+/* clear a flag bit combination */
+#define CLR_CZS FCW &= ~(F_C|F_Z|F_S)
+#define CLR_CZSP FCW &= ~(F_C|F_Z|F_S|F_PV)
+#define CLR_CZSV FCW &= ~(F_C|F_Z|F_S|F_PV)
+#define CLR_CZSVH FCW &= ~(F_C|F_Z|F_S|F_PV|F_H)
+#define CLR_ZS FCW &= ~(F_Z|F_S)
+#define CLR_ZSV FCW &= ~(F_Z|F_S|F_PV)
+#define CLR_ZSP FCW &= ~(F_Z|F_S|F_PV)
+
+/* set a single flag bit */
+#define SET_C FCW |= F_C
+#define SET_Z FCW |= F_Z
+#define SET_S FCW |= F_S
+#define SET_P FCW |= F_PV
+#define SET_V FCW |= F_PV
+#define SET_DA FCW |= F_DA
+#define SET_H FCW |= F_H
+
+/* set a flag bit combination */
+#define SET_SC FCW |= F_C | F_S
+
+/* check condition codes */
+#define CC0 (0) /* always false */
+#define CC1 (GET_PV^GET_S) /* less than */
+#define CC2 (GET_Z|(GET_PV^GET_S)) /* less than or equal */
+#define CC3 (GET_Z|GET_C) /* unsigned less than or equal */
+#define CC4 GET_PV /* parity even / overflow */
+#define CC5 GET_S /* minus (signed) */
+#define CC6 GET_Z /* zero / equal */
+#define CC7 GET_C /* carry / unsigned less than */
+
+#define CC8 (1) /* always true */
+#define CC9 !(GET_PV^GET_S) /* greater than or equal */
+#define CCA !(GET_Z|(GET_PV^GET_S)) /* greater than */
+#define CCB !(GET_Z|GET_C) /* unsigned greater than */
+#define CCC !GET_PV /* parity odd / no overflow */
+#define CCD !GET_S /* plus (not signed) */
+#define CCE !GET_Z /* not zero / not equal */
+#define CCF !GET_C /* not carry / unsigned greater than */
+
+/* get data from the opcode words */
+/* o is the opcode word offset */
+/* s is a nibble shift factor */
+#define GET_BIT(o) UINT16 bit = 1 << (Z.op[o] & 15)
+#define GET_CCC(o,s) UINT8 cc = (Z.op[o] >> (s)) & 15
+
+#define GET_DST(o,s) UINT8 dst = (Z.op[o] >> (s)) & 15
+#define GET_SRC(o,s) UINT8 src = (Z.op[o] >> (s)) & 15
+#define GET_IDX(o,s) UINT8 idx = (Z.op[o] >> (s)) & 15
+#define GET_CNT(o,s) INT8 cnt = (Z.op[o] >> (s)) & 15
+#define GET_IMM4(o,s) UINT8 imm4 = (Z.op[o] >> (s)) & 15
+
+#define GET_I4M1(o,s) UINT8 i4p1 = ((Z.op[o] >> (s)) & 15) + 1
+#define GET_IMM1(o,s) UINT8 imm1 = (Z.op[o] >> (s)) & 2
+#define GET_IMM2(o,s) UINT8 imm2 = (Z.op[o] >> (s)) & 3
+#define GET_IMM3(o,s) UINT8 imm3 = (Z.op[o] >> (s)) & 7
+
+#define GET_IMM8(o) UINT8 imm8 = (UINT8)Z.op[o]
+
+#define GET_IMM16(o) UINT16 imm16 = Z.op[o]
+#define GET_IMM32 UINT32 imm32 = Z.op[2] + (Z.op[1] << 16)
+#define GET_DSP7 UINT8 dsp7 = Z.op[0] & 127
+#define GET_DSP8 INT8 dsp8 = (INT8)Z.op[0]
+#define GET_DSP16 UINT16 dsp16 = PC + (INT16)Z.op[1]
+#define GET_ADDR(o) UINT16 addr = (UINT16)Z.op[o]
+
+/* structure for the opcode definition table */
+typedef struct {
+ int beg, end, step;
+ int size, cycles;
+ void (*opcode)(void);
+ const char *dasm;
+ UINT32 dasmflags;
+} Z8000_init;
+
+/* structure for the opcode execution table / disassembler */
+typedef struct {
+ void (*opcode)(void);
+ int cycles;
+ int size;
+ const char *dasm;
+ UINT32 dasmflags;
+} Z8000_exec;
+
+/* opcode execution table */
+extern Z8000_exec *z8000_exec;
+
+extern void z8000_init(int index, int clock, const void *config, int (*irqcallback)(int));
+extern void z8000_deinit(void);
+
diff --git a/src/emu/cpu/z8000/z8000dab.h b/src/emu/cpu/z8000/z8000dab.h
new file mode 100644
index 00000000000..c68af257749
--- /dev/null
+++ b/src/emu/cpu/z8000/z8000dab.h
@@ -0,0 +1,275 @@
+/************************************************
+ * Result table for Z8000 DAB instruction
+ *
+ * bits description
+ * ----------------------------------------------
+ * 0..7 destination value
+ * 8 carry flag before
+ * 9 half carry flag before
+ * 10 D flag (0 add/adc, 1 sub/sbc)
+ *
+ * result description
+ * ----------------------------------------------
+ * 0..7 result value
+ * 8 carry flag after
+ ************************************************/
+static UINT16 Z8000_dab[0x800] = {
+ /* add/adc results */
+ 0x000,0x001,0x002,0x003,0x004,0x005,0x006,0x007,
+ 0x008,0x009,0x010,0x011,0x012,0x013,0x014,0x015,
+ 0x010,0x011,0x012,0x013,0x014,0x015,0x016,0x017,
+ 0x018,0x019,0x020,0x021,0x022,0x023,0x024,0x025,
+ 0x020,0x021,0x022,0x023,0x024,0x025,0x026,0x027,
+ 0x028,0x029,0x030,0x031,0x032,0x033,0x034,0x035,
+ 0x030,0x031,0x032,0x033,0x034,0x035,0x036,0x037,
+ 0x038,0x039,0x040,0x041,0x042,0x043,0x044,0x045,
+ 0x040,0x041,0x042,0x043,0x044,0x045,0x046,0x047,
+ 0x048,0x049,0x050,0x051,0x052,0x053,0x054,0x055,
+ 0x050,0x051,0x052,0x053,0x054,0x055,0x056,0x057,
+ 0x058,0x059,0x060,0x061,0x062,0x063,0x064,0x065,
+ 0x060,0x061,0x062,0x063,0x064,0x065,0x066,0x067,
+ 0x068,0x069,0x070,0x071,0x072,0x073,0x074,0x075,
+ 0x070,0x071,0x072,0x073,0x074,0x075,0x076,0x077,
+ 0x078,0x079,0x080,0x081,0x082,0x083,0x084,0x085,
+ 0x080,0x081,0x082,0x083,0x084,0x085,0x086,0x087,
+ 0x088,0x089,0x090,0x091,0x092,0x093,0x094,0x095,
+ 0x090,0x091,0x092,0x093,0x094,0x095,0x096,0x097,
+ 0x098,0x099,0x100,0x101,0x102,0x103,0x104,0x105,
+ 0x100,0x101,0x102,0x103,0x104,0x105,0x106,0x107,
+ 0x108,0x109,0x110,0x111,0x112,0x113,0x114,0x115,
+ 0x110,0x111,0x112,0x113,0x114,0x115,0x116,0x117,
+ 0x118,0x119,0x120,0x121,0x122,0x123,0x124,0x125,
+ 0x120,0x121,0x122,0x123,0x124,0x125,0x126,0x127,
+ 0x128,0x129,0x130,0x131,0x132,0x133,0x134,0x135,
+ 0x130,0x131,0x132,0x133,0x134,0x135,0x136,0x137,
+ 0x138,0x139,0x140,0x141,0x142,0x143,0x144,0x145,
+ 0x140,0x141,0x142,0x143,0x144,0x145,0x146,0x147,
+ 0x148,0x149,0x150,0x151,0x152,0x153,0x154,0x155,
+ 0x150,0x151,0x152,0x153,0x154,0x155,0x156,0x157,
+ 0x158,0x159,0x160,0x161,0x162,0x163,0x164,0x165,
+ 0x166,0x167,0x168,0x169,0x16a,0x16b,0x16c,0x16d,
+ 0x16e,0x16f,0x170,0x171,0x172,0x173,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,0x1c0,0x1c1,0x1c2,0x1c3,0x1c4,0x1c5,
+ 0x1c6,0x1c7,0x1c8,0x1c9,0x1ca,0x1cb,0x1cc,0x1cd,
+ 0x1ce,0x1cf,0x1d0,0x1d1,0x1d2,0x1d3,0x1d4,0x1d5,
+ 0x1d6,0x1d7,0x1d8,0x1d9,0x1da,0x1db,0x1dc,0x1dd,
+ 0x1de,0x1df,0x1e0,0x1e1,0x1e2,0x1e3,0x1e4,0x1e5,
+ 0x1e6,0x1e7,0x1e8,0x1e9,0x1ea,0x1eb,0x1ec,0x1ed,
+ 0x1ee,0x1ef,0x1f0,0x1f1,0x1f2,0x1f3,0x1f4,0x1f5,
+ 0x1f6,0x1f7,0x1f8,0x1f9,0x1fa,0x1fb,0x1fc,0x1fd,
+ 0x1fe,0x1ff,0x100,0x101,0x102,0x103,0x104,0x105,
+ 0x106,0x107,0x108,0x109,0x10a,0x10b,0x10c,0x10d,
+ 0x10e,0x10f,0x110,0x111,0x112,0x113,0x114,0x115,
+ 0x116,0x117,0x118,0x119,0x11a,0x11b,0x11c,0x11d,
+ 0x11e,0x11f,0x120,0x121,0x122,0x123,0x124,0x125,
+ 0x126,0x127,0x128,0x129,0x12a,0x12b,0x12c,0x12d,
+ 0x12e,0x12f,0x130,0x131,0x132,0x133,0x134,0x135,
+ 0x136,0x137,0x138,0x139,0x13a,0x13b,0x13c,0x13d,
+ 0x13e,0x13f,0x140,0x141,0x142,0x143,0x144,0x145,
+ 0x146,0x147,0x148,0x149,0x14a,0x14b,0x14c,0x14d,
+ 0x14e,0x14f,0x150,0x151,0x152,0x153,0x154,0x155,
+ 0x156,0x157,0x158,0x159,0x15a,0x15b,0x15c,0x15d,
+ 0x15e,0x15f,0x160,0x161,0x162,0x163,0x164,0x165,
+ 0x166,0x167,0x168,0x169,0x16a,0x16b,0x16c,0x16d,
+ 0x16e,0x16f,0x170,0x171,0x172,0x173,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,0x1c0,0x1c1,0x1c2,0x1c3,0x1c4,0x1c5,
+ 0x1c6,0x1c7,0x1c8,0x1c9,0x1ca,0x1cb,0x1cc,0x1cd,
+ 0x1ce,0x1cf,0x1d0,0x1d1,0x1d2,0x1d3,0x1d4,0x1d5,
+ 0x1d6,0x1d7,0x1d8,0x1d9,0x1da,0x1db,0x1dc,0x1dd,
+ 0x1de,0x1df,0x1e0,0x1e1,0x1e2,0x1e3,0x1e4,0x1e5,
+ 0x1e6,0x1e7,0x1e8,0x1e9,0x1ea,0x1eb,0x1ec,0x1ed,
+ 0x1ee,0x1ef,0x1f0,0x1f1,0x1f2,0x1f3,0x1f4,0x1f5,
+ 0x1f6,0x1f7,0x1f8,0x1f9,0x1fa,0x1fb,0x1fc,0x1fd,
+ 0x1fe,0x1ff,0x100,0x101,0x102,0x103,0x104,0x105,
+ 0x106,0x107,0x108,0x109,0x10a,0x10b,0x10c,0x10d,
+ 0x10e,0x10f,0x110,0x111,0x112,0x113,0x114,0x115,
+ 0x116,0x117,0x118,0x119,0x11a,0x11b,0x11c,0x11d,
+ 0x11e,0x11f,0x120,0x121,0x122,0x123,0x124,0x125,
+ 0x126,0x127,0x128,0x129,0x12a,0x12b,0x12c,0x12d,
+ 0x12e,0x12f,0x130,0x131,0x132,0x133,0x134,0x135,
+ 0x136,0x137,0x138,0x139,0x13a,0x13b,0x13c,0x13d,
+ 0x13e,0x13f,0x140,0x141,0x142,0x143,0x144,0x145,
+ 0x146,0x147,0x148,0x149,0x14a,0x14b,0x14c,0x14d,
+ 0x14e,0x14f,0x150,0x151,0x152,0x153,0x154,0x155,
+ 0x156,0x157,0x158,0x159,0x15a,0x15b,0x15c,0x15d,
+ 0x15e,0x15f,0x160,0x161,0x162,0x163,0x164,0x165,
+ 0x166,0x167,0x168,0x169,0x16a,0x16b,0x16c,0x16d,
+ 0x16e,0x16f,0x170,0x171,0x172,0x173,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,0x1c0,0x1c1,0x1c2,0x1c3,0x1c4,0x1c5,
+ 0x1c6,0x1c7,0x1c8,0x1c9,0x1ca,0x1cb,0x1cc,0x1cd,
+ 0x1ce,0x1cf,0x1d0,0x1d1,0x1d2,0x1d3,0x1d4,0x1d5,
+ 0x1d6,0x1d7,0x1d8,0x1d9,0x1da,0x1db,0x1dc,0x1dd,
+ 0x1de,0x1df,0x1e0,0x1e1,0x1e2,0x1e3,0x1e4,0x1e5,
+ 0x1e6,0x1e7,0x1e8,0x1e9,0x1ea,0x1eb,0x1ec,0x1ed,
+ 0x1ee,0x1ef,0x1f0,0x1f1,0x1f2,0x1f3,0x1f4,0x1f5,
+ 0x1f6,0x1f7,0x1f8,0x1f9,0x1fa,0x1fb,0x1fc,0x1fd,
+ 0x1fe,0x1ff,0x100,0x101,0x102,0x103,0x104,0x105,
+ 0x106,0x107,0x108,0x109,0x10a,0x10b,0x10c,0x10d,
+ 0x10e,0x10f,0x110,0x111,0x112,0x113,0x114,0x115,
+ 0x116,0x117,0x118,0x119,0x11a,0x11b,0x11c,0x11d,
+ 0x11e,0x11f,0x120,0x121,0x122,0x123,0x124,0x125,
+ 0x126,0x127,0x128,0x129,0x12a,0x12b,0x12c,0x12d,
+ 0x12e,0x12f,0x130,0x131,0x132,0x133,0x134,0x135,
+ 0x136,0x137,0x138,0x139,0x13a,0x13b,0x13c,0x13d,
+ 0x13e,0x13f,0x140,0x141,0x142,0x143,0x144,0x145,
+ 0x146,0x147,0x148,0x149,0x14a,0x14b,0x14c,0x14d,
+ 0x14e,0x14f,0x150,0x151,0x152,0x153,0x154,0x155,
+ 0x156,0x157,0x158,0x159,0x15a,0x15b,0x15c,0x15d,
+ 0x15e,0x15f,0x160,0x161,0x162,0x163,0x164,0x165,
+ /* sub/sbc results */
+ 0x000,0x001,0x002,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,0x042,0x043,0x044,0x045,0x046,0x047,
+ 0x048,0x049,0x04a,0x04b,0x04c,0x04d,0x04e,0x04f,
+ 0x050,0x051,0x052,0x053,0x054,0x055,0x056,0x057,
+ 0x058,0x059,0x05a,0x05b,0x05c,0x05d,0x05e,0x05f,
+ 0x060,0x061,0x062,0x063,0x064,0x065,0x066,0x067,
+ 0x068,0x069,0x06a,0x06b,0x06c,0x06d,0x06e,0x06f,
+ 0x070,0x071,0x072,0x073,0x074,0x075,0x076,0x077,
+ 0x078,0x079,0x07a,0x07b,0x07c,0x07d,0x07e,0x07f,
+ 0x080,0x081,0x082,0x083,0x084,0x085,0x086,0x087,
+ 0x088,0x089,0x08a,0x08b,0x08c,0x08d,0x08e,0x08f,
+ 0x090,0x091,0x092,0x093,0x094,0x095,0x096,0x097,
+ 0x098,0x099,0x09a,0x09b,0x09c,0x09d,0x09e,0x09f,
+ 0x0a0,0x0a1,0x0a2,0x0a3,0x0a4,0x0a5,0x0a6,0x0a7,
+ 0x0a8,0x0a9,0x0aa,0x0ab,0x0ac,0x0ad,0x0ae,0x0af,
+ 0x0b0,0x0b1,0x0b2,0x0b3,0x0b4,0x0b5,0x0b6,0x0b7,
+ 0x0b8,0x0b9,0x0ba,0x0bb,0x0bc,0x0bd,0x0be,0x0bf,
+ 0x0c0,0x0c1,0x0c2,0x0c3,0x0c4,0x0c5,0x0c6,0x0c7,
+ 0x0c8,0x0c9,0x0ca,0x0cb,0x0cc,0x0cd,0x0ce,0x0cf,
+ 0x0d0,0x0d1,0x0d2,0x0d3,0x0d4,0x0d5,0x0d6,0x0d7,
+ 0x0d8,0x0d9,0x0da,0x0db,0x0dc,0x0dd,0x0de,0x0df,
+ 0x0e0,0x0e1,0x0e2,0x0e3,0x0e4,0x0e5,0x0e6,0x0e7,
+ 0x0e8,0x0e9,0x0ea,0x0eb,0x0ec,0x0ed,0x0ee,0x0ef,
+ 0x0f0,0x0f1,0x0f2,0x0f3,0x0f4,0x0f5,0x0f6,0x0f7,
+ 0x0f8,0x0f9,0x0fa,0x0fb,0x0fc,0x0fd,0x0fe,0x0ff,
+ 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,
+ 0x1c0,0x1c1,0x1c2,0x1c3,0x1c4,0x1c5,0x1c6,0x1c7,
+ 0x1c8,0x1c9,0x1ca,0x1cb,0x1cc,0x1cd,0x1ce,0x1cf,
+ 0x1d0,0x1d1,0x1d2,0x1d3,0x1d4,0x1d5,0x1d6,0x1d7,
+ 0x1d8,0x1d9,0x1da,0x1db,0x1dc,0x1dd,0x1de,0x1df,
+ 0x1e0,0x1e1,0x1e2,0x1e3,0x1e4,0x1e5,0x1e6,0x1e7,
+ 0x1e8,0x1e9,0x1ea,0x1eb,0x1ec,0x1ed,0x1ee,0x1ef,
+ 0x1f0,0x1f1,0x1f2,0x1f3,0x1f4,0x1f5,0x1f6,0x1f7,
+ 0x1f8,0x1f9,0x1fa,0x1fb,0x1fc,0x1fd,0x1fe,0x1ff,
+ 0x100,0x101,0x102,0x103,0x104,0x105,0x106,0x107,
+ 0x108,0x109,0x10a,0x10b,0x10c,0x10d,0x10e,0x10f,
+ 0x110,0x111,0x112,0x113,0x114,0x115,0x116,0x117,
+ 0x118,0x119,0x11a,0x11b,0x11c,0x11d,0x11e,0x11f,
+ 0x120,0x121,0x122,0x123,0x124,0x125,0x126,0x127,
+ 0x128,0x129,0x12a,0x12b,0x12c,0x12d,0x12e,0x12f,
+ 0x130,0x131,0x132,0x133,0x134,0x135,0x136,0x137,
+ 0x138,0x139,0x13a,0x13b,0x13c,0x13d,0x13e,0x13f,
+ 0x140,0x141,0x142,0x143,0x144,0x145,0x146,0x147,
+ 0x148,0x149,0x14a,0x14b,0x14c,0x14d,0x14e,0x14f,
+ 0x150,0x151,0x152,0x153,0x154,0x155,0x156,0x157,
+ 0x158,0x159,0x15a,0x15b,0x15c,0x15d,0x15e,0x15f,
+ 0x160,0x161,0x162,0x163,0x164,0x165,0x166,0x167,
+ 0x168,0x169,0x16a,0x16b,0x16c,0x16d,0x16e,0x16f,
+ 0x170,0x171,0x172,0x173,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,
+ 0x1fa,0x1fb,0x1fc,0x1fd,0x1fe,0x1ff,0x100,0x101,
+ 0x102,0x103,0x104,0x105,0x106,0x107,0x108,0x109,
+ 0x10a,0x10b,0x10c,0x10d,0x10e,0x10f,0x110,0x111,
+ 0x112,0x113,0x114,0x115,0x116,0x117,0x118,0x119,
+ 0x11a,0x11b,0x11c,0x11d,0x11e,0x11f,0x120,0x121,
+ 0x122,0x123,0x124,0x125,0x126,0x127,0x128,0x129,
+ 0x12a,0x12b,0x12c,0x12d,0x12e,0x12f,0x130,0x131,
+ 0x132,0x133,0x134,0x135,0x136,0x137,0x138,0x139,
+ 0x13a,0x13b,0x13c,0x13d,0x13e,0x13f,0x140,0x141,
+ 0x142,0x143,0x144,0x145,0x146,0x147,0x148,0x149,
+ 0x14a,0x14b,0x14c,0x14d,0x14e,0x14f,0x150,0x151,
+ 0x152,0x153,0x154,0x155,0x156,0x157,0x158,0x159,
+ 0x15a,0x15b,0x15c,0x15d,0x15e,0x15f,0x160,0x161,
+ 0x162,0x163,0x164,0x165,0x166,0x167,0x168,0x169,
+ 0x16a,0x16b,0x16c,0x16d,0x16e,0x16f,0x170,0x171,
+ 0x172,0x173,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,0x1c0,0x1c1,
+ 0x1c2,0x1c3,0x1c4,0x1c5,0x1c6,0x1c7,0x1c8,0x1c9,
+ 0x1ca,0x1cb,0x1cc,0x1cd,0x1ce,0x1cf,0x1d0,0x1d1,
+ 0x1d2,0x1d3,0x1d4,0x1d5,0x1d6,0x1d7,0x1d8,0x1d9,
+ 0x1da,0x1db,0x1dc,0x1dd,0x1de,0x1df,0x1e0,0x1e1,
+ 0x1e2,0x1e3,0x1e4,0x1e5,0x1e6,0x1e7,0x1e8,0x1e9,
+ 0x1ea,0x1eb,0x1ec,0x1ed,0x1ee,0x1ef,0x1f0,0x1f1,
+ 0x1f2,0x1f3,0x1f4,0x1f5,0x1f6,0x1f7,0x1f8,0x1f9,
+ 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,0x1c0,0x1c1,
+ 0x1c2,0x1c3,0x1c4,0x1c5,0x1c6,0x1c7,0x1c8,0x1c9,
+ 0x1ca,0x1cb,0x1cc,0x1cd,0x1ce,0x1cf,0x1d0,0x1d1,
+ 0x1d2,0x1d3,0x1d4,0x1d5,0x1d6,0x1d7,0x1d8,0x1d9,
+ 0x1da,0x1db,0x1dc,0x1dd,0x1de,0x1df,0x1e0,0x1e1,
+ 0x1e2,0x1e3,0x1e4,0x1e5,0x1e6,0x1e7,0x1e8,0x1e9,
+ 0x1ea,0x1eb,0x1ec,0x1ed,0x1ee,0x1ef,0x1f0,0x1f1,
+ 0x1f2,0x1f3,0x1f4,0x1f5,0x1f6,0x1f7,0x1f8,0x1f9,
+ 0x1fa,0x1fb,0x1fc,0x1fd,0x1fe,0x1ff,0x100,0x101,
+ 0x102,0x103,0x104,0x105,0x106,0x107,0x108,0x109,
+ 0x10a,0x10b,0x10c,0x10d,0x10e,0x10f,0x110,0x111,
+ 0x112,0x113,0x114,0x115,0x116,0x117,0x118,0x119,
+ 0x11a,0x11b,0x11c,0x11d,0x11e,0x11f,0x120,0x121,
+ 0x122,0x123,0x124,0x125,0x126,0x127,0x128,0x129,
+ 0x12a,0x12b,0x12c,0x12d,0x12e,0x12f,0x130,0x131,
+ 0x132,0x133,0x134,0x135,0x136,0x137,0x138,0x139,
+ 0x13a,0x13b,0x13c,0x13d,0x13e,0x13f,0x140,0x141,
+ 0x142,0x143,0x144,0x145,0x146,0x147,0x148,0x149,
+ 0x14a,0x14b,0x14c,0x14d,0x14e,0x14f,0x150,0x151,
+ 0x152,0x153,0x154,0x155,0x156,0x157,0x158,0x159,
+ 0x15a,0x15b,0x15c,0x15d,0x15e,0x15f,0x160,0x161,
+ 0x162,0x163,0x164,0x165,0x166,0x167,0x168,0x169,
+ 0x16a,0x16b,0x16c,0x16d,0x16e,0x16f,0x170,0x171,
+ 0x172,0x173,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,
+};
diff --git a/src/emu/cpu/z8000/z8000ops.c b/src/emu/cpu/z8000/z8000ops.c
new file mode 100644
index 00000000000..d26e23fd3e3
--- /dev/null
+++ b/src/emu/cpu/z8000/z8000ops.c
@@ -0,0 +1,6503 @@
+/*****************************************************************************
+ *
+ * z8000ops.c
+ * Portable Z8000(2) emulator
+ * Opcode functions
+ *
+ * Copyright (c) 1998 Juergen Buchmueller, all rights reserved.
+ * Bug fixes and MSB_FIRST compliance Ernesto Corvi.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+/******************************************
+ helper functions
+ ******************************************/
+
+/******************************************
+ check new fcw for switch to system mode
+ and swap stack pointer if needed
+ ******************************************/
+INLINE void CHANGE_FCW(UINT16 fcw)
+{
+ if (fcw & F_S_N) { /* system mode now? */
+ if (!(FCW & F_S_N)) { /* and not before? */
+ UINT16 tmp = RW(SP);
+ RW(SP) = NSP;
+ NSP = tmp;
+ }
+ } else { /* user mode now */
+ if (FCW & F_S_N) { /* and not before? */
+ UINT16 tmp = RW(SP);
+ RW(SP) = NSP;
+ NSP = tmp;
+ }
+ }
+ if (!(FCW & F_NVIE) && (fcw & F_NVIE) && (Z.irq_state[0] != CLEAR_LINE))
+ IRQ_REQ |= Z8000_NVI;
+ if (!(FCW & F_VIE) && (fcw & F_VIE) && (Z.irq_state[1] != CLEAR_LINE))
+ IRQ_REQ |= Z8000_VI;
+ FCW = fcw; /* set new FCW */
+}
+
+INLINE void PUSHW(UINT8 dst, UINT16 value)
+{
+ RW(dst) -= 2;
+ WRMEM_W( RW(dst), value );
+}
+
+INLINE UINT16 POPW(UINT8 src)
+{
+ UINT16 result = RDMEM_W( RW(src) );
+ RW(src) += 2;
+ return result;
+}
+
+INLINE void PUSHL(UINT8 dst, UINT32 value)
+{
+ RW(dst) -= 4;
+ WRMEM_L( RW(dst), value );
+}
+
+INLINE UINT32 POPL(UINT8 src)
+{
+ UINT32 result = RDMEM_L( RW(src) );
+ RW(src) += 4;
+ return result;
+}
+
+/* check zero and sign flag for byte, word and long results */
+#define CHK_XXXB_ZS if (!result) SET_Z; else if ((INT8) result < 0) SET_S
+#define CHK_XXXW_ZS if (!result) SET_Z; else if ((INT16)result < 0) SET_S
+#define CHK_XXXL_ZS if (!result) SET_Z; else if ((INT32)result < 0) SET_S
+#define CHK_XXXQ_ZS if (!result) SET_Z; else if ((INT64)result < 0) SET_S
+
+#define CHK_XXXB_ZSP FCW |= z8000_zsp[result]
+
+/* check carry for addition and subtraction */
+#define CHK_ADDX_C if (result < dest) SET_C
+#define CHK_ADCX_C if (result < dest || (result == dest && value)) SET_C
+
+#define CHK_SUBX_C if (result > dest) SET_C
+#define CHK_SBCX_C if (result > dest || (result == dest && value)) SET_C
+
+/* check half carry for A addition and S subtraction */
+#define CHK_ADDB_H if ((result & 15) < (dest & 15)) SET_H
+#define CHK_ADCB_H if ((result & 15) < (dest & 15) || ((result & 15) == (dest & 15) && (value & 15))) SET_H
+
+#define CHK_SUBB_H if ((result & 15) > (dest & 15)) SET_H
+#define CHK_SBCB_H if ((result & 15) > (dest & 15) || ((result & 15) == (dest & 15) && (value & 15))) SET_H
+
+/* check overflow for addition for byte, word and long */
+#define CHK_ADDB_V if (((value & dest & ~result) | (~value & ~dest & result)) & S08) SET_V
+#define CHK_ADDW_V if (((value & dest & ~result) | (~value & ~dest & result)) & S16) SET_V
+#define CHK_ADDL_V if (((value & dest & ~result) | (~value & ~dest & result)) & S32) SET_V
+
+/* check overflow for subtraction for byte, word and long */
+#define CHK_SUBB_V if (((~value & dest & ~result) | (value & ~dest & result)) & S08) SET_V
+#define CHK_SUBW_V if (((~value & dest & ~result) | (value & ~dest & result)) & S16) SET_V
+#define CHK_SUBL_V if (((~value & dest & ~result) | (value & ~dest & result)) & S32) SET_V
+
+
+/******************************************
+ add byte
+ flags: CZSVDH
+ ******************************************/
+INLINE UINT8 ADDB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest + value;
+ CLR_CZSVH; /* first clear C, Z, S, P/V and H flags */
+ CLR_DA; /* clear DA (decimal adjust) flag for addb */
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ CHK_ADDX_C; /* set C if result overflowed */
+ CHK_ADDB_V; /* set V if result has incorrect sign */
+ CHK_ADDB_H; /* set H if lower nibble overflowed */
+ return result;
+}
+
+/******************************************
+ add word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 ADDW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest + value;
+ CLR_CZSV; /* first clear C, Z, S, P/V flags */
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ CHK_ADDX_C; /* set C if result overflowed */
+ CHK_ADDW_V; /* set V if result has incorrect sign */
+ return result;
+}
+
+/******************************************
+ add long
+ flags: CZSV--
+ ******************************************/
+INLINE UINT32 ADDL(UINT32 dest, UINT32 value)
+{
+ UINT32 result = dest + value;
+ CLR_CZSV; /* first clear C, Z, S, P/V flags */
+ CHK_XXXL_ZS; /* set Z and S flags for result long */
+ CHK_ADDX_C; /* set C if result overflowed */
+ CHK_ADDL_V; /* set V if result has incorrect sign */
+ return result;
+}
+
+/******************************************
+ add with carry byte
+ flags: CZSVDH
+ ******************************************/
+INLINE UINT8 ADCB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest + value + GET_C;
+ CLR_CZSVH; /* first clear C, Z, S, P/V and H flags */
+ CLR_DA; /* clear DA (decimal adjust) flag for adcb */
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ CHK_ADCX_C; /* set C if result overflowed */
+ CHK_ADDB_V; /* set V if result has incorrect sign */
+ CHK_ADCB_H; /* set H if lower nibble overflowed */
+ return result;
+}
+
+/******************************************
+ add with carry word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 ADCW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest + value + GET_C;
+ CLR_CZSV; /* first clear C, Z, S, P/V flags */
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ CHK_ADCX_C; /* set C if result overflowed */
+ CHK_ADDW_V; /* set V if result has incorrect sign */
+ return result;
+}
+
+/******************************************
+ subtract byte
+ flags: CZSVDH
+ ******************************************/
+INLINE UINT8 SUBB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest - value;
+ CLR_CZSVH; /* first clear C, Z, S, P/V and H flags */
+ SET_DA; /* set DA (decimal adjust) flag for subb */
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ CHK_SUBX_C; /* set C if result underflowed */
+ CHK_SUBB_V; /* set V if result has incorrect sign */
+ CHK_SUBB_H; /* set H if lower nibble underflowed */
+ return result;
+}
+
+/******************************************
+ subtract word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 SUBW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest - value;
+ CLR_CZSV; /* first clear C, Z, S, P/V flags */
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ CHK_SUBX_C; /* set C if result underflowed */
+ CHK_SUBW_V; /* set V if result has incorrect sign */
+ return result;
+}
+
+/******************************************
+ subtract long
+ flags: CZSV--
+ ******************************************/
+INLINE UINT32 SUBL(UINT32 dest, UINT32 value)
+{
+ UINT32 result = dest - value;
+ CLR_CZSV; /* first clear C, Z, S, P/V flags */
+ CHK_XXXL_ZS; /* set Z and S flags for result long */
+ CHK_SUBX_C; /* set C if result underflowed */
+ CHK_SUBL_V; /* set V if result has incorrect sign */
+ return result;
+}
+
+/******************************************
+ subtract with carry byte
+ flags: CZSVDH
+ ******************************************/
+INLINE UINT8 SBCB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest - value - GET_C;
+ CLR_CZSVH; /* first clear C, Z, S, P/V and H flags */
+ SET_DA; /* set DA (decimal adjust) flag for sbcb */
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ CHK_SBCX_C; /* set C if result underflowed */
+ CHK_SUBB_V; /* set V if result has incorrect sign */
+ CHK_SBCB_H; /* set H if lower nibble underflowed */
+ return result;
+}
+
+/******************************************
+ subtract with carry word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 SBCW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest - value - GET_C;
+ CLR_CZSV; /* first clear C, Z, S, P/V flags */
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ CHK_SBCX_C; /* set C if result underflowed */
+ CHK_SUBW_V; /* set V if result has incorrect sign */
+ return result;
+}
+
+/******************************************
+ logical or byte
+ flags: -ZSP--
+ ******************************************/
+INLINE UINT8 ORB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest | value;
+ CLR_ZSP; /* first clear Z, S, P/V flags */
+ CHK_XXXB_ZSP; /* set Z, S and P flags for result byte */
+ return result;
+}
+
+/******************************************
+ logical or word
+ flags: -ZS---
+ ******************************************/
+INLINE UINT16 ORW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest | value;
+ CLR_ZS; /* first clear Z, and S flags */
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ return result;
+}
+
+/******************************************
+ logical and byte
+ flags: -ZSP--
+ ******************************************/
+INLINE UINT8 ANDB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest & value;
+ CLR_ZSP; /* first clear Z,S and P/V flags */
+ CHK_XXXB_ZSP; /* set Z, S and P flags for result byte */
+ return result;
+}
+
+/******************************************
+ logical and word
+ flags: -ZS---
+ ******************************************/
+INLINE UINT16 ANDW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest & value;
+ CLR_ZS; /* first clear Z and S flags */
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ return result;
+}
+
+/******************************************
+ logical exclusive or byte
+ flags: -ZSP--
+ ******************************************/
+INLINE UINT8 XORB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest ^ value;
+ CLR_ZSP; /* first clear Z, S and P/V flags */
+ CHK_XXXB_ZSP; /* set Z, S and P flags for result byte */
+ return result;
+}
+
+/******************************************
+ logical exclusive or word
+ flags: -ZS---
+ ******************************************/
+INLINE UINT16 XORW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest ^ value;
+ CLR_ZS; /* first clear Z and S flags */
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ return result;
+}
+
+
+/******************************************
+ compare byte
+ flags: CZSV--
+ ******************************************/
+INLINE void CPB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest - value;
+ CLR_CZSV; /* first clear C, Z, S and P/V flags */
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ CHK_SUBX_C; /* set C if result underflowed */
+ CHK_SUBB_V;
+}
+
+/******************************************
+ compare word
+ flags: CZSV--
+ ******************************************/
+INLINE void CPW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest - value;
+ CLR_CZSV;
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ CHK_SUBX_C; /* set C if result underflowed */
+ CHK_SUBW_V;
+}
+
+/******************************************
+ compare long
+ flags: CZSV--
+ ******************************************/
+INLINE void CPL(UINT32 dest, UINT32 value)
+{
+ UINT32 result = dest - value;
+ CLR_CZSV;
+ CHK_XXXL_ZS; /* set Z and S flags for result long */
+ CHK_SUBX_C; /* set C if result underflowed */
+ CHK_SUBL_V;
+}
+
+/******************************************
+ complement byte
+ flags: -ZSP--
+ ******************************************/
+INLINE UINT8 COMB(UINT8 dest)
+{
+ UINT8 result = ~dest;
+ CLR_ZSP;
+ CHK_XXXB_ZSP; /* set Z, S and P flags for result byte */
+ return result;
+}
+
+/******************************************
+ complement word
+ flags: -ZS---
+ ******************************************/
+INLINE UINT16 COMW(UINT16 dest)
+{
+ UINT16 result = ~dest;
+ CLR_ZS;
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ return result;
+}
+
+/******************************************
+ negate byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 NEGB(UINT8 dest)
+{
+ UINT8 result = (UINT8) -dest;
+ CLR_CZSV;
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (result > 0) SET_C;
+ if (result == S08) SET_V;
+ return result;
+}
+
+/******************************************
+ negate word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 NEGW(UINT16 dest)
+{
+ UINT16 result = (UINT16) -dest;
+ CLR_CZSV;
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (result > 0) SET_C;
+ if (result == S16) SET_V;
+ return result;
+}
+
+/******************************************
+ test byte
+ flags: -ZSP--
+ ******************************************/
+INLINE void TESTB(UINT8 result)
+{
+ CLR_ZSP;
+ CHK_XXXB_ZSP; /* set Z and S flags for result byte */
+}
+
+/******************************************
+ test word
+ flags: -ZS---
+ ******************************************/
+INLINE void TESTW(UINT16 dest)
+{
+ CLR_ZS;
+ if (!dest) SET_Z; else if (dest & S16) SET_S;
+}
+
+/******************************************
+ test long
+ flags: -ZS---
+ ******************************************/
+INLINE void TESTL(UINT32 dest)
+{
+ CLR_ZS;
+ if (!dest) SET_Z; else if (dest & S32) SET_S;
+}
+
+/******************************************
+ increment byte
+ flags: -ZSV--
+ ******************************************/
+INLINE UINT8 INCB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest + value;
+ CLR_ZSV;
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ CHK_ADDB_V; /* set V if result overflowed */
+ return result;
+}
+
+/******************************************
+ increment word
+ flags: -ZSV--
+ ******************************************/
+INLINE UINT16 INCW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest + value;
+ CLR_ZSV;
+ CHK_XXXW_ZS; /* set Z and S flags for result byte */
+ CHK_ADDW_V; /* set V if result overflowed */
+ return result;
+}
+
+/******************************************
+ decrement byte
+ flags: -ZSV--
+ ******************************************/
+INLINE UINT8 DECB(UINT8 dest, UINT8 value)
+{
+ UINT8 result = dest - value;
+ CLR_ZSV;
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ CHK_SUBB_V; /* set V if result overflowed */
+ return result;
+}
+
+/******************************************
+ decrement word
+ flags: -ZSV--
+ ******************************************/
+INLINE UINT16 DECW(UINT16 dest, UINT16 value)
+{
+ UINT16 result = dest - value;
+ CLR_ZSV;
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ CHK_SUBW_V; /* set V if result overflowed */
+ return result;
+}
+
+/******************************************
+ multiply words
+ flags: CZSV--
+ ******************************************/
+INLINE UINT32 MULTW(UINT16 dest, UINT16 value)
+{
+ UINT32 result = (INT32)(INT16)dest * (INT16)value;
+ CLR_CZSV;
+ CHK_XXXL_ZS;
+ if( !value )
+ {
+ /* multiplication with zero is faster */
+ z8000_ICount += (70-18);
+ }
+ if( (INT32)result < -0x7fff || (INT32)result >= 0x7fff ) SET_C;
+ return result;
+}
+
+/******************************************
+ multiply longs
+ flags: CZSV--
+ ******************************************/
+INLINE UINT64 MULTL(UINT32 dest, UINT32 value)
+{
+ UINT64 result = (INT64)(INT32)dest * (INT32)value;
+ if( !value )
+ {
+ /* multiplication with zero is faster */
+ z8000_ICount += (282 - 30);
+ }
+ else
+ {
+ int n;
+ for( n = 0; n < 32; n++ )
+ if( dest & (1L << n) ) z8000_ICount -= 7;
+ }
+ CLR_CZSV;
+ CHK_XXXQ_ZS;
+ if( (INT64)result < -0x7fffffffL || (INT64)result >= 0x7fffffffL ) SET_C;
+ return result;
+}
+
+/******************************************
+ divide long by word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT32 DIVW(UINT32 dest, UINT16 value)
+{
+ UINT32 result = dest;
+ UINT16 remainder = 0;
+ CLR_CZSV;
+ if (value)
+ {
+ UINT16 qsign = ((dest >> 16) ^ value) & S16;
+ UINT16 rsign = (dest >> 16) & S16;
+ if ((INT32)dest < 0) dest = -dest;
+ if ((INT16)value < 0) value = -value;
+ result = dest / value;
+ remainder = dest % value;
+ if (qsign) result = -result;
+ if (rsign) remainder = -remainder;
+ if ((INT32)result < -0x8000 || (INT32)result > 0x7fff)
+ {
+ INT32 temp = (INT32)result >> 1;
+ SET_V;
+ if (temp >= -0x8000 && temp <= 0x7fff)
+ {
+ result = (temp < 0) ? -1 : 0;
+ CHK_XXXW_ZS;
+ SET_C;
+ }
+ }
+ else
+ {
+ CHK_XXXW_ZS;
+ }
+ result = ((UINT32)remainder << 16) | (result & 0xffff);
+ }
+ else
+ {
+ SET_Z;
+ SET_V;
+ }
+ return result;
+}
+
+/******************************************
+ divide quad word by long
+ flags: CZSV--
+ ******************************************/
+INLINE UINT64 DIVL(UINT64 dest, UINT32 value)
+{
+ UINT64 result = dest;
+ UINT32 remainder = 0;
+ CLR_CZSV;
+ if (value)
+ {
+ UINT32 qsign = ((dest >> 32) ^ value) & S32;
+ UINT32 rsign = (dest >> 32) & S32;
+ if ((INT64)dest < 0) dest = -dest;
+ if ((INT32)value < 0) value = -value;
+ result = dest / value;
+ remainder = dest % value;
+ if (qsign) result = -result;
+ if (rsign) remainder = -remainder;
+ if ((INT64)result < -0x80000000 || (INT64)result > 0x7fffffff)
+ {
+ INT64 temp = (INT64)result >> 1;
+ SET_V;
+ if (temp >= -0x80000000 && temp <= 0x7fffffff)
+ {
+ result = (temp < 0) ? -1 : 0;
+ CHK_XXXL_ZS;
+ SET_C;
+ }
+ }
+ else
+ {
+ CHK_XXXL_ZS;
+ }
+ result = ((UINT64)remainder << 32) | (result & 0xffffffff);
+ }
+ else
+ {
+ SET_Z;
+ SET_V;
+ }
+ return result;
+}
+
+/******************************************
+ rotate left byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 RLB(UINT8 dest, UINT8 twice)
+{
+ UINT8 result = (dest << 1) | (dest >> 7);
+ CLR_CZSV;
+ if (twice) result = (result << 1) | (result >> 7);
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (result & 0x01) SET_C;
+ if ((result ^ dest) & S08) SET_V;
+ return result;
+}
+
+/******************************************
+ rotate left word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 RLW(UINT16 dest, UINT8 twice)
+{
+ UINT16 result = (dest << 1) | (dest >> 15);
+ CLR_CZSV;
+ if (twice) result = (result << 1) | (result >> 15);
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (result & 0x0001) SET_C;
+ if ((result ^ dest) & S16) SET_V;
+ return result;
+}
+
+/******************************************
+ rotate left through carry byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 RLCB(UINT8 dest, UINT8 twice)
+{
+ UINT8 c = dest & S08;
+ UINT8 result = (dest << 1) | GET_C;
+ CLR_CZSV;
+ if (twice) {
+ UINT8 c1 = c >> 7;
+ c = result & S08;
+ result = (result << 1) | c1;
+ }
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (c) SET_C;
+ if ((result ^ dest) & S08) SET_V;
+ return result;
+}
+
+/******************************************
+ rotate left through carry word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 RLCW(UINT16 dest, UINT8 twice)
+{
+ UINT16 c = dest & S16;
+ UINT16 result = (dest << 1) | GET_C;
+ CLR_CZSV;
+ if (twice) {
+ UINT16 c1 = c >> 15;
+ c = result & S16;
+ result = (result << 1) | c1;
+ }
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (c) SET_C;
+ if ((result ^ dest) & S16) SET_V;
+ return result;
+}
+
+/******************************************
+ rotate right byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 RRB(UINT8 dest, UINT8 twice)
+{
+ UINT8 result = (dest >> 1) | (dest << 7);
+ CLR_CZSV;
+ if (twice) result = (result >> 1) | (result << 7);
+ if (!result) SET_Z; else if (result & S08) SET_SC;
+ if ((result ^ dest) & S08) SET_V;
+ return result;
+}
+
+/******************************************
+ rotate right word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 RRW(UINT16 dest, UINT8 twice)
+{
+ UINT16 result = (dest >> 1) | (dest << 15);
+ CLR_CZSV;
+ if (twice) result = (result >> 1) | (result << 15);
+ if (!result) SET_Z; else if (result & S16) SET_SC;
+ if ((result ^ dest) & S16) SET_V;
+ return result;
+}
+
+/******************************************
+ rotate right through carry byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 RRCB(UINT8 dest, UINT8 twice)
+{
+ UINT8 c = dest & 1;
+ UINT8 result = (dest >> 1) | (GET_C << 7);
+ CLR_CZSV;
+ if (twice) {
+ UINT8 c1 = c << 7;
+ c = result & 1;
+ result = (result >> 1) | c1;
+ }
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (c) SET_C;
+ if ((result ^ dest) & S08) SET_V;
+ return result;
+}
+
+/******************************************
+ rotate right through carry word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 RRCW(UINT16 dest, UINT8 twice)
+{
+ UINT16 c = dest & 1;
+ UINT16 result = (dest >> 1) | (GET_C << 15);
+ CLR_CZSV;
+ if (twice) {
+ UINT16 c1 = c << 15;
+ c = result & 1;
+ result = (result >> 1) | c1;
+ }
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (c) SET_C;
+ if ((result ^ dest) & S16) SET_V;
+ return result;
+}
+
+/******************************************
+ shift dynamic arithmetic byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 SDAB(UINT8 dest, INT8 count)
+{
+ INT8 result = (INT8) dest;
+ UINT8 c = 0;
+ CLR_CZSV;
+ while (count > 0) {
+ c = result & S08;
+ result <<= 1;
+ count--;
+ }
+ while (count < 0) {
+ c = result & 0x01;
+ result >>= 1;
+ count++;
+ }
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (c) SET_C;
+ if ((result ^ dest) & S08) SET_V;
+ return (UINT8)result;
+}
+
+/******************************************
+ shift dynamic arithmetic word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 SDAW(UINT16 dest, INT8 count)
+{
+ INT16 result = (INT16) dest;
+ UINT16 c = 0;
+ CLR_CZSV;
+ while (count > 0) {
+ c = result & S16;
+ result <<= 1;
+ count--;
+ }
+ while (count < 0) {
+ c = result & 0x0001;
+ result >>= 1;
+ count++;
+ }
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (c) SET_C;
+ if ((result ^ dest) & S16) SET_V;
+ return (UINT16)result;
+}
+
+/******************************************
+ shift dynamic arithmetic long
+ flags: CZSV--
+ ******************************************/
+INLINE UINT32 SDAL(UINT32 dest, INT8 count)
+{
+ INT32 result = (INT32) dest;
+ UINT32 c = 0;
+ CLR_CZSV;
+ while (count > 0) {
+ c = result & S32;
+ result <<= 1;
+ count--;
+ }
+ while (count < 0) {
+ c = result & 0x00000001;
+ result >>= 1;
+ count++;
+ }
+ CHK_XXXL_ZS; /* set Z and S flags for result long */
+ if (c) SET_C;
+ if ((result ^ dest) & S32) SET_V;
+ return (UINT32) result;
+}
+
+/******************************************
+ shift dynamic logic byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 SDLB(UINT8 dest, INT8 count)
+{
+ UINT8 result = dest;
+ UINT8 c = 0;
+ CLR_CZSV;
+ while (count > 0) {
+ c = result & S08;
+ result <<= 1;
+ count--;
+ }
+ while (count < 0) {
+ c = result & 0x01;
+ result >>= 1;
+ count++;
+ }
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (c) SET_C;
+ if ((result ^ dest) & S08) SET_V;
+ return result;
+}
+
+/******************************************
+ shift dynamic logic word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 SDLW(UINT16 dest, INT8 count)
+{
+ UINT16 result = dest;
+ UINT16 c = 0;
+ CLR_CZSV;
+ while (count > 0) {
+ c = result & S16;
+ result <<= 1;
+ count--;
+ }
+ while (count < 0) {
+ c = result & 0x0001;
+ result >>= 1;
+ count++;
+ }
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (c) SET_C;
+ if ((result ^ dest) & S16) SET_V;
+ return result;
+}
+
+/******************************************
+ shift dynamic logic long
+ flags: CZSV--
+ ******************************************/
+INLINE UINT32 SDLL(UINT32 dest, INT8 count)
+{
+ UINT32 result = dest;
+ UINT32 c = 0;
+ CLR_CZSV;
+ while (count > 0) {
+ c = result & S32;
+ result <<= 1;
+ count--;
+ }
+ while (count < 0) {
+ c = result & 0x00000001;
+ result >>= 1;
+ count++;
+ }
+ CHK_XXXL_ZS; /* set Z and S flags for result long */
+ if (c) SET_C;
+ if ((result ^ dest) & S32) SET_V;
+ return result;
+}
+
+/******************************************
+ shift left arithmetic byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 SLAB(UINT8 dest, UINT8 count)
+{
+ UINT8 c = (count) ? (dest << (count - 1)) & S08 : 0;
+ UINT8 result = (UINT8)((INT8)dest << count);
+ CLR_CZSV;
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (c) SET_C;
+ if ((result ^ dest) & S08) SET_V;
+ return result;
+}
+
+/******************************************
+ shift left arithmetic word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 SLAW(UINT16 dest, UINT8 count)
+{
+ UINT16 c = (count) ? (dest << (count - 1)) & S16 : 0;
+ UINT16 result = (UINT16)((INT16)dest << count);
+ CLR_CZSV;
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (c) SET_C;
+ if ((result ^ dest) & S16) SET_V;
+ return result;
+}
+
+/******************************************
+ shift left arithmetic long
+ flags: CZSV--
+ ******************************************/
+INLINE UINT32 SLAL(UINT32 dest, UINT8 count)
+{
+ UINT32 c = (count) ? (dest << (count - 1)) & S32 : 0;
+ UINT32 result = (UINT32)((INT32)dest << count);
+ CLR_CZSV;
+ CHK_XXXL_ZS; /* set Z and S flags for result long */
+ if (c) SET_C;
+ if ((result ^ dest) & S32) SET_V;
+ return result;
+}
+
+/******************************************
+ shift left logic byte
+ flags: CZS---
+ ******************************************/
+INLINE UINT8 SLLB(UINT8 dest, UINT8 count)
+{
+ UINT8 c = (count) ? (dest << (count - 1)) & S08 : 0;
+ UINT8 result = dest << count;
+ CLR_CZS;
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (c) SET_C;
+ return result;
+}
+
+/******************************************
+ shift left logic word
+ flags: CZS---
+ ******************************************/
+INLINE UINT16 SLLW(UINT16 dest, UINT8 count)
+{
+ UINT16 c = (count) ? (dest << (count - 1)) & S16 : 0;
+ UINT16 result = dest << count;
+ CLR_CZS;
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (c) SET_C;
+ return result;
+}
+
+/******************************************
+ shift left logic long
+ flags: CZS---
+ ******************************************/
+INLINE UINT32 SLLL(UINT32 dest, UINT8 count)
+{
+ UINT32 c = (count) ? (dest << (count - 1)) & S32 : 0;
+ UINT32 result = dest << count;
+ CLR_CZS;
+ CHK_XXXL_ZS; /* set Z and S flags for result long */
+ if (c) SET_C;
+ return result;
+}
+
+/******************************************
+ shift right arithmetic byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 SRAB(UINT8 dest, UINT8 count)
+{
+ UINT8 c = (count) ? ((INT8)dest >> (count - 1)) & 1 : 0;
+ UINT8 result = (UINT8)((INT8)dest >> count);
+ CLR_CZSV;
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (c) SET_C;
+ return result;
+}
+
+/******************************************
+ shift right arithmetic word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 SRAW(UINT16 dest, UINT8 count)
+{
+ UINT8 c = (count) ? ((INT16)dest >> (count - 1)) & 1 : 0;
+ UINT16 result = (UINT16)((INT16)dest >> count);
+ CLR_CZSV;
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (c) SET_C;
+ return result;
+}
+
+/******************************************
+ shift right arithmetic long
+ flags: CZSV--
+ ******************************************/
+INLINE UINT32 SRAL(UINT32 dest, UINT8 count)
+{
+ UINT8 c = (count) ? ((INT32)dest >> (count - 1)) & 1 : 0;
+ UINT32 result = (UINT32)((INT32)dest >> count);
+ CLR_CZSV;
+ CHK_XXXL_ZS; /* set Z and S flags for result long */
+ if (c) SET_C;
+ return result;
+}
+
+/******************************************
+ shift right logic byte
+ flags: CZSV--
+ ******************************************/
+INLINE UINT8 SRLB(UINT8 dest, UINT8 count)
+{
+ UINT8 c = (count) ? (dest >> (count - 1)) & 1 : 0;
+ UINT8 result = dest >> count;
+ CLR_CZS;
+ CHK_XXXB_ZS; /* set Z and S flags for result byte */
+ if (c) SET_C;
+ return result;
+}
+
+/******************************************
+ shift right logic word
+ flags: CZSV--
+ ******************************************/
+INLINE UINT16 SRLW(UINT16 dest, UINT8 count)
+{
+ UINT8 c = (count) ? (dest >> (count - 1)) & 1 : 0;
+ UINT16 result = dest >> count;
+ CLR_CZS;
+ CHK_XXXW_ZS; /* set Z and S flags for result word */
+ if (c) SET_C;
+ return result;
+}
+
+/******************************************
+ shift right logic long
+ flags: CZSV--
+ ******************************************/
+INLINE UINT32 SRLL(UINT32 dest, UINT8 count)
+{
+ UINT8 c = (count) ? (dest >> (count - 1)) & 1 : 0;
+ UINT32 result = dest >> count;
+ CLR_CZS;
+ CHK_XXXL_ZS; /* set Z and S flags for result long */
+ if (c) SET_C;
+ return result;
+}
+
+/******************************************
+ invalid
+ flags: ------
+ ******************************************/
+static void zinvalid(void)
+{
+ logerror("Z8000 invalid opcode %04x: %04x\n", PC, Z.op[0]);
+}
+
+/******************************************
+ addb rbd,imm8
+ flags: CZSVDH
+ ******************************************/
+static void Z00_0000_dddd_imm8(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM8(OP1);
+ RB(dst) = ADDB( RB(dst), imm8);
+}
+
+/******************************************
+ addb rbd,@rs
+ flags: CZSVDH
+ ******************************************/
+static void Z00_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = ADDB( RB(dst), RDMEM_B(RW(src)) );
+}
+
+/******************************************
+ add rd,imm16
+ flags: CZSV--
+ ******************************************/
+static void Z01_0000_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM16(OP1);
+ RW(dst) = ADDW( RW(dst), imm16 );
+}
+
+/******************************************
+ add rd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z01_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = ADDW( RW(dst), RDMEM_W(RW(src)) );
+}
+
+/******************************************
+ subb rbd,imm8
+ flags: CZSVDH
+ ******************************************/
+static void Z02_0000_dddd_imm8(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM8(OP1);
+ RB(dst) = SUBB( RB(dst), imm8 );
+}
+
+/******************************************
+ subb rbd,@rs
+ flags: CZSVDH
+ ******************************************/
+static void Z02_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = SUBB( RB(dst), RDMEM_B(RW(src)) ); /* EHC */
+}
+
+/******************************************
+ sub rd,imm16
+ flags: CZSV--
+ ******************************************/
+static void Z03_0000_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM16(OP1);
+ RW(dst) = SUBW( RW(dst), imm16 );
+}
+
+/******************************************
+ sub rd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z03_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = SUBW( RW(dst), RDMEM_W(RW(src)) );
+}
+
+/******************************************
+ orb rbd,imm8
+ flags: CZSP--
+ ******************************************/
+static void Z04_0000_dddd_imm8(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM8(OP1);
+ RB(dst) = ORB( RB(dst), imm8 );
+}
+
+/******************************************
+ orb rbd,@rs
+ flags: CZSP--
+ ******************************************/
+static void Z04_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = ORB( RB(dst), RDMEM_B(RW(src)) );
+}
+
+/******************************************
+ or rd,imm16
+ flags: CZS---
+ ******************************************/
+static void Z05_0000_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM16(OP1);
+ RW(dst) = ORW( RW(dst), imm16 );
+}
+
+/******************************************
+ or rd,@rs
+ flags: CZS---
+ ******************************************/
+static void Z05_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = ORW( RW(dst), RDMEM_W(RW(src)) );
+}
+
+/******************************************
+ andb rbd,imm8
+ flags: -ZSP--
+ ******************************************/
+static void Z06_0000_dddd_imm8(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM8(OP1);
+ RB(dst) = ANDB( RB(dst), imm8 );
+}
+
+/******************************************
+ andb rbd,@rs
+ flags: -ZSP--
+ ******************************************/
+static void Z06_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = ANDB( RB(dst), RDMEM_B(RW(src)) );
+}
+
+/******************************************
+ and rd,imm16
+ flags: -ZS---
+ ******************************************/
+static void Z07_0000_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM16(OP1);
+ RW(dst) = ANDW( RW(dst), imm16 );
+}
+
+/******************************************
+ and rd,@rs
+ flags: -ZS---
+ ******************************************/
+static void Z07_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = ANDW( RW(dst), RDMEM_W(RW(src)) );
+}
+
+/******************************************
+ xorb rbd,imm8
+ flags: -ZSP--
+ ******************************************/
+static void Z08_0000_dddd_imm8(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM8(OP1);
+ RB(dst) = XORB(RB(dst), imm8);
+}
+
+/******************************************
+ xorb rbd,@rs
+ flags: -ZSP--
+ ******************************************/
+static void Z08_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = XORB( RB(dst), RDMEM_B(RW(src)) );
+}
+
+/******************************************
+ xor rd,imm16
+ flags: -ZS---
+ ******************************************/
+static void Z09_0000_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM16(OP1);
+ RW(dst) = XORW( RW(dst), imm16 );
+}
+
+/******************************************
+ xor rd,@rs
+ flags: -ZS---
+ ******************************************/
+static void Z09_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = XORW( RW(dst), RDMEM_W(RW(src)) );
+}
+
+/******************************************
+ cpb rbd,imm8
+ flags: CZSV--
+ ******************************************/
+static void Z0A_0000_dddd_imm8(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM8(OP1);
+ CPB(RB(dst), imm8);
+}
+
+/******************************************
+ cpb rbd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z0A_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ CPB( RB(dst), RDMEM_B(RW(src)) );
+}
+
+/******************************************
+ cp rd,imm16
+ flags: CZSV--
+ ******************************************/
+static void Z0B_0000_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM16(OP1);
+ CPW( RW(dst), imm16 );
+}
+
+/******************************************
+ cp rd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z0B_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ CPW( RW(dst), RDMEM_W(RW(src)) );
+}
+
+/******************************************
+ comb @rd
+ flags: -ZSP--
+ ******************************************/
+static void Z0C_ddN0_0000(void)
+{
+ GET_DST(OP0,NIB3);
+ WRMEM_B( RW(dst), COMB(RDMEM_B(RW(dst))) );
+}
+
+/******************************************
+ cpb @rd,imm8
+ flags: CZSV--
+ ******************************************/
+static void Z0C_ddN0_0001_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM8(OP1);
+ CPB( RB(dst), imm8 );
+}
+
+/******************************************
+ negb @rd
+ flags: CZSV--
+ ******************************************/
+static void Z0C_ddN0_0010(void)
+{
+ GET_DST(OP0,NIB2);
+ WRMEM_B( RW(dst), NEGB(RDMEM_B(RW(dst))) );
+}
+
+/******************************************
+ testb @rd
+ flags: -ZSP--
+ ******************************************/
+static void Z0C_ddN0_0100(void)
+{
+ GET_DST(OP0,NIB2);
+ TESTB(RDMEM_B(RW(dst)));
+}
+
+/******************************************
+ ldb @rd,imm8
+ flags: ------
+ ******************************************/
+static void Z0C_ddN0_0101_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM8(OP1);
+ WRMEM_B( RW(dst), imm8 );
+}
+
+/******************************************
+ tsetb @rd
+ flags: --S---
+ ******************************************/
+static void Z0C_ddN0_0110(void)
+{
+ GET_DST(OP0,NIB2);
+ if (RDMEM_B(RW(dst)) & S08) SET_S; else CLR_S;
+ WRMEM_B(RW(dst), 0xff);
+}
+
+/******************************************
+ clrb @rd
+ flags: ------
+ ******************************************/
+static void Z0C_ddN0_1000(void)
+{
+ GET_DST(OP0,NIB2);
+ WRMEM_B( RW(dst), 0 );
+}
+
+/******************************************
+ com @rd
+ flags: -ZS---
+ ******************************************/
+static void Z0D_ddN0_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ WRMEM_W( RW(dst), COMW(RDMEM_W(RW(dst))) );
+}
+
+/******************************************
+ cp @rd,imm16
+ flags: CZSV--
+ ******************************************/
+static void Z0D_ddN0_0001_imm16(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ CPW( RDMEM_W(RW(dst)), imm16 );
+}
+
+/******************************************
+ neg @rd
+ flags: CZSV--
+ ******************************************/
+static void Z0D_ddN0_0010(void)
+{
+ GET_DST(OP0,NIB2);
+ WRMEM_W( RW(dst), NEGW(RDMEM_W(RW(dst))) );
+}
+
+/******************************************
+ test @rd
+ flags: -ZS---
+ ******************************************/
+static void Z0D_ddN0_0100(void)
+{
+ GET_DST(OP0,NIB2);
+ TESTW( RDMEM_W(RW(dst)) );
+}
+
+/******************************************
+ ld @rd,imm16
+ flags: ------
+ ******************************************/
+static void Z0D_ddN0_0101_imm16(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ WRMEM_W( RW(dst), imm16);
+}
+
+/******************************************
+ tset @rd
+ flags: --S---
+ ******************************************/
+static void Z0D_ddN0_0110(void)
+{
+ GET_DST(OP0,NIB2);
+ if (RDMEM_W(RW(dst)) & S16) SET_S; else CLR_S;
+ WRMEM_W(RW(dst), 0xffff);
+}
+
+/******************************************
+ clr @rd
+ flags: ------
+ ******************************************/
+static void Z0D_ddN0_1000(void)
+{
+ GET_DST(OP0,NIB2);
+ WRMEM_W( RDMEM_W(RW(dst)), 0 );
+}
+
+/******************************************
+ push @rd,imm16
+ flags: ------
+ ******************************************/
+static void Z0D_ddN0_1001_imm16(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ PUSHW( dst, imm16 );
+}
+
+/******************************************
+ ext0e imm8
+ flags: ------
+ ******************************************/
+static void Z0E_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: ext0e $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ ext0f imm8
+ flags: ------
+ ******************************************/
+static void Z0F_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: ext0f $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ cpl rrd,imm32
+ flags: CZSV--
+ ******************************************/
+static void Z10_0000_dddd_imm32(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM32;
+ CPL( RL(dst), imm32 );
+}
+
+/******************************************
+ cpl rrd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z10_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ CPL( RL(dst), RDMEM_L(RW(src)) );
+}
+
+/******************************************
+ pushl @rd,@rs
+ flags: ------
+ ******************************************/
+static void Z11_ddN0_ssN0(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ PUSHL( dst, RDMEM_L(RW(src)) );
+}
+
+/******************************************
+ subl rrd,imm32
+ flags: CZSV--
+ ******************************************/
+static void Z12_0000_dddd_imm32(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM32;
+ RL(dst) = SUBL( RL(dst), imm32 );
+}
+
+/******************************************
+ subl rrd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z12_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = SUBL( RL(dst), RDMEM_L(RW(src)) );
+}
+
+/******************************************
+ push @rd,@rs
+ flags: ------
+ ******************************************/
+static void Z13_ddN0_ssN0(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ PUSHW( dst, RDMEM_W(RW(src)) );
+}
+
+/******************************************
+ ldl rrd,imm32
+ flags: ------
+ ******************************************/
+static void Z14_0000_dddd_imm32(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM32;
+ RL(dst) = imm32;
+}
+
+/******************************************
+ ldl rrd,@rs
+ flags: ------
+ ******************************************/
+static void Z14_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = RDMEM_L( RW(src) );
+}
+
+/******************************************
+ popl @rd,@rs
+ flags: ------
+ ******************************************/
+static void Z15_ssN0_ddN0(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = POPL( src );
+}
+
+/******************************************
+ addl rrd,imm32
+ flags: CZSV--
+ ******************************************/
+static void Z16_0000_dddd_imm32(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM32;
+ RL(dst) = ADDL( RL(dst), imm32 );
+}
+
+/******************************************
+ addl rrd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z16_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = ADDL( RL(dst), RDMEM_L(RW(src)) );
+}
+
+/******************************************
+ pop @rd,@rs
+ flags: ------
+ ******************************************/
+static void Z17_ssN0_ddN0(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = POPW( src );
+}
+
+/******************************************
+ multl rqd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z18_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RQ(dst) = MULTL( RQ(dst), RL(src) );
+}
+
+/******************************************
+ mult rrd,imm16
+ flags: CZSV--
+ ******************************************/
+static void Z19_0000_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM16(OP1);
+ RL(dst) = MULTW( RL(dst), imm16 );
+}
+
+/******************************************
+ mult rrd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z19_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = MULTW( RL(dst), RDMEM_W(RW(src)) );
+}
+
+/******************************************
+ divl rqd,imm32
+ flags: CZSV--
+ ******************************************/
+static void Z1A_0000_dddd_imm32(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM32;
+ RQ(dst) = DIVL( RQ(dst), imm32 );
+}
+
+/******************************************
+ divl rqd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z1A_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RQ(dst) = DIVL( RQ(dst), RDMEM_L(RW(src)) );
+}
+
+/******************************************
+ div rrd,imm16
+ flags: CZSV--
+ ******************************************/
+static void Z1B_0000_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM16(OP1);
+ RL(dst) = DIVW( RL(dst), imm16 );
+}
+
+/******************************************
+ div rrd,@rs
+ flags: CZSV--
+ ******************************************/
+static void Z1B_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = DIVW( RL(dst), RDMEM_W(RW(src)) );
+}
+
+/******************************************
+ testl @rd
+ flags: -ZS---
+ ******************************************/
+static void Z1C_ddN0_1000(void)
+{
+ GET_DST(OP0,NIB2);
+ TESTL( RDMEM_L(RW(dst)) );
+}
+
+/******************************************
+ ldm @rd,rs,n
+ flags: ------
+ ******************************************/
+static void Z1C_ddN0_1001_0000_ssss_0000_nmin1(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_CNT(OP1,NIB3);
+ GET_SRC(OP1,NIB1);
+ UINT16 idx = RW(dst);
+ while (cnt-- >= 0) {
+ WRMEM_W( idx, RW(src) );
+ idx = (idx + 2) & 0xffff;
+ src = (src+1) & 15;
+ }
+}
+
+/******************************************
+ ldm rd,@rs,n
+ flags: ------
+ ******************************************/
+static void Z1C_ssN0_0001_0000_dddd_0000_nmin1(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB3);
+ GET_DST(OP1,NIB1);
+ UINT16 idx = RW(src);
+ while (cnt-- >= 0) {
+ RW(dst) = RDMEM_W( idx );
+ idx = (idx + 2) & 0xffff;
+ dst = (dst+1) & 15;
+ }
+}
+
+/******************************************
+ ldl @rd,rrs
+ flags: ------
+ ******************************************/
+static void Z1D_ddN0_ssss(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ WRMEM_L( RW(dst), RL(src) );
+}
+
+/******************************************
+ jp cc,rd
+ flags: ------
+ ******************************************/
+static void Z1E_ddN0_cccc(void)
+{
+ GET_CCC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ switch (cc) {
+ case 0: if (CC0) PC = RW(dst); break;
+ case 1: if (CC1) PC = RW(dst); break;
+ case 2: if (CC2) PC = RW(dst); break;
+ case 3: if (CC3) PC = RW(dst); break;
+ case 4: if (CC4) PC = RW(dst); break;
+ case 5: if (CC5) PC = RW(dst); break;
+ case 6: if (CC6) PC = RW(dst); break;
+ case 7: if (CC7) PC = RW(dst); break;
+ case 8: if (CC8) PC = RW(dst); break;
+ case 9: if (CC9) PC = RW(dst); break;
+ case 10: if (CCA) PC = RW(dst); break;
+ case 11: if (CCB) PC = RW(dst); break;
+ case 12: if (CCC) PC = RW(dst); break;
+ case 13: if (CCD) PC = RW(dst); break;
+ case 14: if (CCE) PC = RW(dst); break;
+ case 15: if (CCF) PC = RW(dst); break;
+ }
+ change_pc(PC);
+}
+
+/******************************************
+ call @rd
+ flags: ------
+ ******************************************/
+static void Z1F_ddN0_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ PUSHW( SP, PC );
+ PC = RW(dst);
+ change_pc(PC);
+}
+
+/******************************************
+ ldb rbd,@rs
+ flags: ------
+ ******************************************/
+static void Z20_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = RDMEM_B( RW(src) );
+}
+
+/******************************************
+ ld rd,imm16
+ flags: ------
+ ******************************************/
+static void Z21_0000_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_IMM16(OP1);
+ RW(dst) = imm16;
+}
+
+/******************************************
+ ld rd,@rs
+ flags: ------
+ ******************************************/
+static void Z21_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = RDMEM_W( RW(src) );
+}
+
+/******************************************
+ resb rbd,rs
+ flags: ------
+ ******************************************/
+static void Z22_0000_ssss_0000_dddd_0000_0000(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP1,NIB1);
+ RB(dst) = RB(dst) & ~(1 << (RW(src) & 7));
+}
+
+/******************************************
+ resb @rd,imm4
+ flags: ------
+ ******************************************/
+static void Z22_ddN0_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ WRMEM_B(RW(dst), RDMEM_B(RW(dst)) & ~bit);
+}
+
+/******************************************
+ result rd,rs
+ flags: ------
+ ******************************************/
+static void Z23_0000_ssss_0000_dddd_0000_0000(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP1,NIB1);
+ RW(dst) = RW(dst) & ~(1 << (RW(src) & 15));
+}
+
+/******************************************
+ res @rd,imm4
+ flags: ------
+ ******************************************/
+static void Z23_ddN0_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ WRMEM_W(RW(dst), RDMEM_W(RW(dst)) & ~bit);
+}
+
+/******************************************
+ setb rbd,rs
+ flags: ------
+ ******************************************/
+static void Z24_0000_ssss_0000_dddd_0000_0000(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP1,NIB1);
+ RB(dst) = RB(dst) | (1 << (RW(src) & 7));
+}
+
+/******************************************
+ setb @rd,imm4
+ flags: ------
+ ******************************************/
+static void Z24_ddN0_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ WRMEM_B(RW(dst), RDMEM_B(RW(dst)) | bit);
+}
+
+/******************************************
+ set rd,rs
+ flags: ------
+ ******************************************/
+static void Z25_0000_ssss_0000_dddd_0000_0000(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP1,NIB1);
+ RW(dst) = RW(dst) | (1 << (RW(src) & 15));
+}
+
+/******************************************
+ set @rd,imm4
+ flags: ------
+ ******************************************/
+static void Z25_ddN0_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ WRMEM_W(RW(dst), RDMEM_W(RW(dst)) | bit);
+}
+
+/******************************************
+ bitb rbd,rs
+ flags: -Z----
+ ******************************************/
+static void Z26_0000_ssss_0000_dddd_0000_0000(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP1,NIB1);
+ if (RB(dst) & (1 << (RW(src) & 7))) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ bitb @rd,imm4
+ flags: -Z----
+ ******************************************/
+static void Z26_ddN0_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ if (RDMEM_B(RW(dst)) & bit) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ bit rd,rs
+ flags: -Z----
+ ******************************************/
+static void Z27_0000_ssss_0000_dddd_0000_0000(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP1,NIB1);
+ if (RW(dst) & (1 << (RW(src) & 15))) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ bit @rd,imm4
+ flags: -Z----
+ ******************************************/
+static void Z27_ddN0_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ if (RDMEM_W(RW(dst)) & bit) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ incb @rd,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z28_ddN0_imm4m1(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ WRMEM_B( RW(dst), INCB( RDMEM_B(RW(dst)), i4p1) );
+}
+
+/******************************************
+ inc @rd,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z29_ddN0_imm4m1(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ WRMEM_W( RW(dst), INCW( RDMEM_W(RW(dst)), i4p1 ) );
+}
+
+/******************************************
+ decb @rd,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z2A_ddN0_imm4m1(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ WRMEM_B( RW(dst), DECB( RDMEM_B(RW(dst)), i4p1 ) );
+}
+
+/******************************************
+ dec @rd,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z2B_ddN0_imm4m1(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ WRMEM_W( RW(dst), DECW( RDMEM_W(RW(dst)), i4p1 ) );
+}
+
+/******************************************
+ exb rbd,@rs
+ flags: ------
+ ******************************************/
+static void Z2C_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ UINT8 tmp = RDMEM_B( RW(src) );
+ WRMEM_B( RW(src), RB(dst) );
+ RB(dst) = tmp;
+}
+
+/******************************************
+ ex rd,@rs
+ flags: ------
+ ******************************************/
+static void Z2D_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ UINT16 tmp = RDMEM_W( RW(src) );
+ WRMEM_W( RW(src), RW(dst) );
+ RW(dst) = tmp;
+}
+
+/******************************************
+ ldb @rd,rbs
+ flags: ------
+ ******************************************/
+static void Z2E_ddN0_ssss(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ WRMEM_B( RW(dst), RB(src) );
+}
+
+/******************************************
+ ld @rd,rs
+ flags: ------
+ ******************************************/
+static void Z2F_ddN0_ssss(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ WRMEM_W( RW(dst), RW(src) );
+}
+
+/******************************************
+ ldrb rbd,dsp16
+ flags: ------
+ ******************************************/
+static void Z30_0000_dddd_dsp16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_DSP16;
+ RB(dst) = RDMEM_B(dsp16);
+}
+
+/******************************************
+ ldb rbd,rs(imm16)
+ flags: ------
+ ******************************************/
+static void Z30_ssN0_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_IMM16(OP1);
+ imm16 += RW(src);
+ RB(dst) = RDMEM_B( imm16 );
+}
+
+/******************************************
+ ldr rd,dsp16
+ flags: ------
+ ******************************************/
+static void Z31_0000_dddd_dsp16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_DSP16;
+ RW(dst) = RDMEM_W(dsp16);
+}
+
+/******************************************
+ ld rd,rs(imm16)
+ flags: ------
+ ******************************************/
+static void Z31_ssN0_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_IMM16(OP1);
+ imm16 += RW(src);
+ RW(dst) = RDMEM_W( imm16 );
+}
+
+/******************************************
+ ldrb dsp16,rbs
+ flags: ------
+ ******************************************/
+static void Z32_0000_ssss_dsp16(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DSP16;
+ WRMEM_B( dsp16, RB(src) );
+}
+
+/******************************************
+ ldb rd(imm16),rbs
+ flags: ------
+ ******************************************/
+static void Z32_ddN0_ssss_imm16(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ imm16 += RW(dst);
+ WRMEM_B( imm16, RB(src) );
+}
+
+/******************************************
+ ldr dsp16,rs
+ flags: ------
+ ******************************************/
+static void Z33_0000_ssss_dsp16(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DSP16;
+ WRMEM_W( dsp16, RW(src) );
+}
+
+/******************************************
+ ld rd(imm16),rs
+ flags: ------
+ ******************************************/
+static void Z33_ddN0_ssss_imm16(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ imm16 += RW(dst);
+ WRMEM_W( imm16, RW(src) );
+}
+
+/******************************************
+ ldar prd,dsp16
+ flags: ------
+ ******************************************/
+static void Z34_0000_dddd_dsp16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_DSP16;
+ RW(dst) = dsp16;
+}
+
+/******************************************
+ lda prd,rs(imm16)
+ flags: ------
+ ******************************************/
+static void Z34_ssN0_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_IMM16(OP1);
+ imm16 += RW(src);
+ RW(dst) = imm16;
+}
+
+/******************************************
+ ldrl rrd,dsp16
+ flags: ------
+ ******************************************/
+static void Z35_0000_dddd_dsp16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_DSP16;
+ RL(dst) = RDMEM_L( dsp16 );
+}
+
+/******************************************
+ ldl rrd,rs(imm16)
+ flags: ------
+ ******************************************/
+static void Z35_ssN0_dddd_imm16(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_IMM16(OP1);
+ imm16 += RW(src);
+ RL(dst) = RDMEM_L( imm16 );
+}
+
+/******************************************
+ bpt
+ flags: ------
+ ******************************************/
+static void Z36_0000_0000(void)
+{
+ /* execute break point trap IRQ_REQ */
+ IRQ_REQ = Z8000_TRAP;
+}
+
+/******************************************
+ rsvd36
+ flags: ------
+ ******************************************/
+static void Z36_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: rsvd36 $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ ldrl dsp16,rrs
+ flags: ------
+ ******************************************/
+static void Z37_0000_ssss_dsp16(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DSP16;
+ WRMEM_L( dsp16, RL(src) );
+}
+
+/******************************************
+ ldl rd(imm16),rrs
+ flags: ------
+ ******************************************/
+static void Z37_ddN0_ssss_imm16(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ imm16 += RW(dst);
+ WRMEM_L( imm16, RL(src) );
+}
+
+/******************************************
+ rsvd38
+ flags: ------
+ ******************************************/
+static void Z38_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: rsvd38 $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ ldps @rs
+ flags: CZSVDH
+ ******************************************/
+static void Z39_ssN0_0000(void)
+{
+ GET_SRC(OP0,NIB2);
+ UINT16 fcw;
+ fcw = RDMEM_W( RW(src) );
+ PC = RDMEM_W( (UINT16)(RW(src) + 2) );
+ CHANGE_FCW(fcw); /* check for user/system mode change */
+ change_pc(PC);
+}
+
+/******************************************
+ inib(r) @rd,@rs,ra
+ flags: ---V--
+ ******************************************/
+static void Z3A_ssss_0000_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_B( RW(dst), RDPORT_B( 0, RW(src) ) );
+ RW(dst)++;
+ RW(src)++;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ sinib @rd,@rs,ra
+ sinibr @rd,@rs,ra
+ flags: ------
+ ******************************************/
+static void Z3A_ssss_0001_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_B( RW(dst), RDPORT_B( 1, RW(src) ) );
+ RW(dst)++;
+ RW(src)++;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ outib @rd,@rs,ra
+ outibr @rd,@rs,ra
+ flags: ---V--
+ ******************************************/
+static void Z3A_ssss_0010_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRPORT_B( 0, RW(dst), RDMEM_B( RW(src) ) );
+ RW(dst)++;
+ RW(src)++;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ soutib @rd,@rs,ra
+ soutibr @rd,@rs,ra
+ flags: ------
+ ******************************************/
+static void Z3A_ssss_0011_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRPORT_B( 1, RW(dst), RDMEM_B( RW(src) ) );
+ RW(dst)++;
+ RW(src)++;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ inb rbd,imm16
+ flags: ------
+ ******************************************/
+static void Z3A_dddd_0100_imm16(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ RB(dst) = RDPORT_B( 0, imm16 );
+}
+
+/******************************************
+ sinb rbd,imm16
+ flags: ------
+ ******************************************/
+static void Z3A_dddd_0101_imm16(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ RB(dst) = RDPORT_B( 1, imm16 );
+}
+
+/******************************************
+ outb imm16,rbs
+ flags: ---V--
+ ******************************************/
+static void Z3A_ssss_0110_imm16(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_IMM16(OP1);
+ WRPORT_B( 0, imm16, RB(src) );
+}
+
+/******************************************
+ soutb imm16,rbs
+ flags: ------
+ ******************************************/
+static void Z3A_ssss_0111_imm16(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_IMM16(OP1);
+ WRPORT_B( 1, imm16, RB(src) );
+}
+
+/******************************************
+ indb @rd,@rs,rba
+ indbr @rd,@rs,rba
+ flags: ---V--
+ ******************************************/
+static void Z3A_ssss_1000_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_B( RW(dst), RDPORT_B( 0, RW(src) ) );
+ RW(dst)--;
+ RW(src)--;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ sindb @rd,@rs,rba
+ sindbr @rd,@rs,rba
+ flags: ------
+ ******************************************/
+static void Z3A_ssss_1001_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_B( RW(dst), RDPORT_B( 1, RW(src) ) );
+ RW(dst)--;
+ RW(src)--;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ outdb @rd,@rs,rba
+ outdbr @rd,@rs,rba
+ flags: ---V--
+ ******************************************/
+static void Z3A_ssss_1010_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRPORT_B( 0, RW(dst), RDMEM_B( RW(src) ) );
+ RW(dst)--;
+ RW(src)--;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ soutdb @rd,@rs,rba
+ soutdbr @rd,@rs,rba
+ flags: ------
+ ******************************************/
+static void Z3A_ssss_1011_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRPORT_B( 1, RW(dst), RDMEM_B( RW(src) ) );
+ RW(dst)--;
+ RW(src)--;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ ini @rd,@rs,ra
+ inir @rd,@rs,ra
+ flags: ---V--
+ ******************************************/
+static void Z3B_ssss_0000_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_W( RW(dst), RDPORT_W( 0, RW(src) ) );
+ RW(dst) += 2;
+ RW(src) += 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ sini @rd,@rs,ra
+ sinir @rd,@rs,ra
+ flags: ------
+ ******************************************/
+static void Z3B_ssss_0001_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_W( RW(dst), RDPORT_W( 1, RW(src) ) );
+ RW(dst) += 2;
+ RW(src) += 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ outi @rd,@rs,ra
+ outir @rd,@rs,ra
+ flags: ---V--
+ ******************************************/
+static void Z3B_ssss_0010_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRPORT_W( 0, RW(dst), RDMEM_W( RW(src) ) );
+ RW(dst) += 2;
+ RW(src) += 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ souti @rd,@rs,ra
+ soutir @rd,@rs,ra
+ flags: ------
+ ******************************************/
+static void Z3B_ssss_0011_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRPORT_W( 1, RW(dst), RDMEM_W( RW(src) ) );
+ RW(dst) += 2;
+ RW(src) += 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ in rd,imm16
+ flags: ------
+ ******************************************/
+static void Z3B_dddd_0100_imm16(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ RW(dst) = RDPORT_W( 0, imm16 );
+}
+
+/******************************************
+ sin rd,imm16
+ flags: ------
+ ******************************************/
+static void Z3B_dddd_0101_imm16(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ RW(dst) = RDPORT_W( 1, imm16 );
+}
+
+/******************************************
+ out imm16,rs
+ flags: ---V--
+ ******************************************/
+static void Z3B_ssss_0110_imm16(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_IMM16(OP1);
+ WRPORT_W( 0, imm16, RW(src) );
+}
+
+/******************************************
+ sout imm16,rbs
+ flags: ------
+ ******************************************/
+static void Z3B_ssss_0111_imm16(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_IMM16(OP1);
+ WRPORT_W( 1, imm16, RW(src) );
+}
+
+/******************************************
+ ind @rd,@rs,ra
+ indr @rd,@rs,ra
+ flags: ---V--
+ ******************************************/
+static void Z3B_ssss_1000_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_W( RW(dst), RDPORT_W( 0, RW(src) ) );
+ RW(dst) -= 2;
+ RW(src) -= 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ sind @rd,@rs,ra
+ sindr @rd,@rs,ra
+ flags: ------
+ ******************************************/
+static void Z3B_ssss_1001_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_W( RW(dst), RDPORT_W( 1, RW(src) ) );
+ RW(dst) -= 2;
+ RW(src) -= 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ outd @rd,@rs,ra
+ outdr @rd,@rs,ra
+ flags: ---V--
+ ******************************************/
+static void Z3B_ssss_1010_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRPORT_W( 0, RW(dst), RDMEM_W( RW(src) ) );
+ RW(dst) -= 2;
+ RW(src) -= 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ soutd @rd,@rs,ra
+ soutdr @rd,@rs,ra
+ flags: ------
+ ******************************************/
+static void Z3B_ssss_1011_0000_aaaa_dddd_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRPORT_W( 1, RW(dst), RDMEM_W( RW(src) ) );
+ RW(dst) -= 2;
+ RW(src) -= 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ inb rbd,@rs
+ flags: ------
+ ******************************************/
+static void Z3C_ssss_dddd(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_DST(OP0,NIB3);
+ RB(dst) = RDPORT_B( 0, RDMEM_W( RW(src) ) );
+}
+
+/******************************************
+ in rd,@rs
+ flags: ------
+ ******************************************/
+static void Z3D_ssss_dddd(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_DST(OP0,NIB3);
+ RW(dst) = RDPORT_W( 0, RDMEM_W( RW(src) ) );
+}
+
+/******************************************
+ outb @rd,rbs
+ flags: ---V--
+ ******************************************/
+static void Z3E_dddd_ssss(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP0,NIB3);
+ WRPORT_B( 0, RDMEM_W( RW(dst) ), RB(src) );
+}
+
+/******************************************
+ out @rd,rs
+ flags: ---V--
+ ******************************************/
+static void Z3F_dddd_ssss(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP0,NIB3);
+ WRPORT_W( 0, RDMEM_W( RW(dst) ), RW(src) );
+}
+
+/******************************************
+ addb rbd,addr
+ flags: CZSVDH
+ ******************************************/
+static void Z40_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RB(dst) = ADDB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ addb rbd,addr(rs)
+ flags: CZSVDH
+ ******************************************/
+static void Z40_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RB(dst) = ADDB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ add rd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z41_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RW(dst) = ADDW( RW(dst), RDMEM_W(addr)); /* EHC */
+}
+
+/******************************************
+ add rd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z41_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RW(dst) = ADDW( RW(dst), RDMEM_W(addr) ); /* ASG */
+}
+
+/******************************************
+ subb rbd,addr
+ flags: CZSVDH
+ ******************************************/
+static void Z42_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RB(dst) = SUBB( RB(dst), RDMEM_B(addr)); /* EHC */
+}
+
+/******************************************
+ subb rbd,addr(rs)
+ flags: CZSVDH
+ ******************************************/
+static void Z42_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RB(dst) = SUBB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ sub rd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z43_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RW(dst) = SUBW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ sub rd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z43_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RW(dst) = SUBW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ orb rbd,addr
+ flags: CZSP--
+ ******************************************/
+static void Z44_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RB(dst) = ORB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ orb rbd,addr(rs)
+ flags: CZSP--
+ ******************************************/
+static void Z44_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RB(dst) = ORB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ or rd,addr
+ flags: CZS---
+ ******************************************/
+static void Z45_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RW(dst) = ORW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ or rd,addr(rs)
+ flags: CZS---
+ ******************************************/
+static void Z45_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RW(dst) = ORW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ andb rbd,addr
+ flags: -ZSP--
+ ******************************************/
+static void Z46_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RB(dst) = ANDB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ andb rbd,addr(rs)
+ flags: -ZSP--
+ ******************************************/
+static void Z46_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RB(dst) = ANDB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ and rd,addr
+ flags: -ZS---
+ ******************************************/
+static void Z47_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RW(dst) = ANDW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ and rd,addr(rs)
+ flags: -ZS---
+ ******************************************/
+static void Z47_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RW(dst) = ANDW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ xorb rbd,addr
+ flags: -ZSP--
+ ******************************************/
+static void Z48_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RB(dst) = XORB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ xorb rbd,addr(rs)
+ flags: -ZSP--
+ ******************************************/
+static void Z48_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RB(dst) = XORB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ xor rd,addr
+ flags: -ZS---
+ ******************************************/
+static void Z49_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RW(dst) = XORW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ xor rd,addr(rs)
+ flags: -ZS---
+ ******************************************/
+static void Z49_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RW(dst) = XORW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ cpb rbd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z4A_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ CPB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ cpb rbd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z4A_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ CPB( RB(dst), RDMEM_B(addr) );
+}
+
+/******************************************
+ cp rd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z4B_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ CPW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ cp rd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z4B_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ CPW( RW(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ comb addr
+ flags: -ZSP--
+ ******************************************/
+static void Z4C_0000_0000_addr(void)
+{
+ GET_ADDR(OP1);
+ WRMEM_B( addr, COMB(RDMEM_W(addr)) );
+}
+
+/******************************************
+ cpb addr,imm8
+ flags: CZSV--
+ ******************************************/
+static void Z4C_0000_0001_addr_imm8(void)
+{
+ GET_ADDR(OP1);
+ GET_IMM8(OP2);
+ CPB( RDMEM_B(addr), imm8 );
+}
+
+/******************************************
+ negb addr
+ flags: CZSV--
+ ******************************************/
+static void Z4C_0000_0010_addr(void)
+{
+ GET_ADDR(OP1);
+ WRMEM_B( addr, NEGB(RDMEM_B(addr)) );
+}
+
+/******************************************
+ testb addr
+ flags: -ZSP--
+ ******************************************/
+static void Z4C_0000_0100_addr(void)
+{
+ GET_ADDR(OP1);
+ TESTB(RDMEM_B(addr));
+}
+
+/******************************************
+ ldb addr,imm8
+ flags: ------
+ ******************************************/
+static void Z4C_0000_0101_addr_imm8(void)
+{
+ GET_ADDR(OP1);
+ GET_IMM8(OP2);
+ WRMEM_B( addr, imm8 );
+}
+
+/******************************************
+ tsetb addr
+ flags: --S---
+ ******************************************/
+static void Z4C_0000_0110_addr(void)
+{
+ GET_ADDR(OP1);
+ if (RDMEM_B(addr) & S08) SET_S; else CLR_S;
+ WRMEM_B(addr, 0xff);
+}
+
+/******************************************
+ clrb addr
+ flags: ------
+ ******************************************/
+static void Z4C_0000_1000_addr(void)
+{
+ GET_ADDR(OP1);
+ WRMEM_B( addr, 0 );
+}
+
+/******************************************
+ comb addr(rd)
+ flags: -ZSP--
+ ******************************************/
+static void Z4C_ddN0_0000_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_B( addr, COMB(RDMEM_B(addr)) );
+}
+
+/******************************************
+ cpb addr(rd),imm8
+ flags: CZSV--
+ ******************************************/
+static void Z4C_ddN0_0001_addr_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ GET_IMM8(OP2);
+ addr += RW(dst);
+ CPB( RDMEM_B(addr), imm8 );
+}
+
+/******************************************
+ negb addr(rd)
+ flags: CZSV--
+ ******************************************/
+static void Z4C_ddN0_0010_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_B( addr, NEGB(RDMEM_B(addr)) );
+}
+
+/******************************************
+ testb addr(rd)
+ flags: -ZSP--
+ ******************************************/
+static void Z4C_ddN0_0100_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ TESTB( RDMEM_B(addr) );
+}
+
+/******************************************
+ ldb addr(rd),imm8
+ flags: ------
+ ******************************************/
+static void Z4C_ddN0_0101_addr_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ GET_IMM8(OP2);
+ addr += RW(dst);
+ WRMEM_B( addr, imm8 );
+}
+
+/******************************************
+ tsetb addr(rd)
+ flags: --S---
+ ******************************************/
+static void Z4C_ddN0_0110_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ if (RDMEM_B(addr) & S08) SET_S; else CLR_S;
+ WRMEM_B(addr, 0xff);
+}
+
+/******************************************
+ clrb addr(rd)
+ flags: ------
+ ******************************************/
+static void Z4C_ddN0_1000_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_B( addr, 0 );
+}
+
+/******************************************
+ com addr
+ flags: -ZS---
+ ******************************************/
+static void Z4D_0000_0000_addr(void)
+{
+ GET_ADDR(OP1);
+ WRMEM_W( addr, COMW(RDMEM_W(addr)) );
+}
+
+/******************************************
+ cp addr,imm16
+ flags: CZSV--
+ ******************************************/
+static void Z4D_0000_0001_addr_imm16(void)
+{
+ GET_ADDR(OP1);
+ GET_IMM16(OP2);
+ CPW( RDMEM_W(addr), imm16 );
+}
+
+/******************************************
+ neg addr
+ flags: CZSV--
+ ******************************************/
+static void Z4D_0000_0010_addr(void)
+{
+ GET_ADDR(OP1);
+ WRMEM_W( addr, NEGW(RDMEM_W(addr)) );
+}
+
+/******************************************
+ test addr
+ flags: ------
+ ******************************************/
+static void Z4D_0000_0100_addr(void)
+{
+ GET_ADDR(OP1);
+ TESTW( RDMEM_W(addr) );
+}
+
+/******************************************
+ ld addr,imm16
+ flags: ------
+ ******************************************/
+static void Z4D_0000_0101_addr_imm16(void)
+{
+ GET_ADDR(OP1);
+ GET_IMM16(OP2);
+ WRMEM_W( addr, imm16 );
+}
+
+/******************************************
+ tset addr
+ flags: --S---
+ ******************************************/
+static void Z4D_0000_0110_addr(void)
+{
+ GET_ADDR(OP1);
+ if (RDMEM_W(addr) & S16) SET_S; else CLR_S;
+ WRMEM_W(addr, 0xffff);
+}
+
+/******************************************
+ clr addr
+ flags: ------
+ ******************************************/
+static void Z4D_0000_1000_addr(void)
+{
+ GET_ADDR(OP1);
+ WRMEM_W( addr, 0 );
+}
+
+/******************************************
+ com addr(rd)
+ flags: -ZS---
+ ******************************************/
+static void Z4D_ddN0_0000_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_W( addr, COMW(RDMEM_W(addr)) );
+}
+
+/******************************************
+ cp addr(rd),imm16
+ flags: CZSV--
+ ******************************************/
+static void Z4D_ddN0_0001_addr_imm16(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ GET_IMM16(OP2);
+ addr += RW(dst);
+ CPW( RDMEM_W(addr), imm16 );
+}
+
+/******************************************
+ neg addr(rd)
+ flags: CZSV--
+ ******************************************/
+static void Z4D_ddN0_0010_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_W( addr, NEGW(RDMEM_W(addr)) );
+}
+
+/******************************************
+ test addr(rd)
+ flags: ------
+ ******************************************/
+static void Z4D_ddN0_0100_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ TESTW( RDMEM_W(addr) );
+}
+
+/******************************************
+ ld addr(rd),imm16
+ flags: ------
+ ******************************************/
+static void Z4D_ddN0_0101_addr_imm16(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ GET_IMM16(OP2);
+ addr += RW(dst);
+ WRMEM_W( addr, imm16 );
+}
+
+/******************************************
+ tset addr(rd)
+ flags: --S---
+ ******************************************/
+static void Z4D_ddN0_0110_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ if (RDMEM_W(addr) & S16) SET_S; else CLR_S;
+ WRMEM_W(addr, 0xffff);
+}
+
+/******************************************
+ clr addr(rd)
+ flags: ------
+ ******************************************/
+static void Z4D_ddN0_1000_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_W( addr, 0 );
+}
+
+/******************************************
+ ldb addr(rd),rbs
+ flags: ------
+ ******************************************/
+static void Z4E_ddN0_ssN0_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP0,NIB3);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_B( addr, RB(src) );
+}
+
+/******************************************
+ cpl rrd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z50_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ CPL( RL(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ cpl rrd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z50_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ CPL( RL(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ pushl @rd,addr
+ flags: ------
+ ******************************************/
+static void Z51_ddN0_0000_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ PUSHL( dst, RDMEM_L(addr) );
+}
+
+/******************************************
+ pushl @rd,addr(rs)
+ flags: ------
+ ******************************************/
+static void Z51_ddN0_ssN0_addr(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ PUSHL( dst, RDMEM_L(addr) );
+}
+
+/******************************************
+ subl rrd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z52_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RL(dst) = SUBL( RL(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ subl rrd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z52_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RL(dst) = SUBL( RL(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ push @rd,addr
+ flags: ------
+ ******************************************/
+static void Z53_ddN0_0000_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ PUSHW( dst, RDMEM_W(addr) );
+}
+
+/******************************************
+ push @rd,addr(rs)
+ flags: ------
+ ******************************************/
+static void Z53_ddN0_ssN0_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP0,NIB3);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ PUSHW( dst, RDMEM_W(addr) );
+}
+
+/******************************************
+ ldl rrd,addr
+ flags: ------
+ ******************************************/
+static void Z54_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RL(dst) = RDMEM_L( addr );
+}
+
+/******************************************
+ ldl rrd,addr(rs)
+ flags: ------
+ ******************************************/
+static void Z54_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RL(dst) = RDMEM_L( addr );
+}
+
+/******************************************
+ popl addr,@rs
+ flags: ------
+ ******************************************/
+static void Z55_ssN0_0000_addr(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ WRMEM_L( addr, POPL(src) );
+}
+
+/******************************************
+ popl addr(rd),@rs
+ flags: ------
+ ******************************************/
+static void Z55_ssN0_ddN0_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_L( addr, POPL(src) );
+}
+
+/******************************************
+ addl rrd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z56_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RL(dst) = ADDL( RL(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ addl rrd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z56_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RL(dst) = ADDL( RL(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ pop addr,@rs
+ flags: ------
+ ******************************************/
+static void Z57_ssN0_0000_addr(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ WRMEM_W( addr, POPW(src) );
+}
+
+/******************************************
+ pop addr(rd),@rs
+ flags: ------
+ ******************************************/
+static void Z57_ssN0_ddN0_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_W( addr, POPW(src) );
+}
+
+/******************************************
+ multl rqd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z58_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RQ(dst) = MULTL( RQ(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ multl rqd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z58_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RQ(dst) = MULTL( RQ(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ mult rrd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z59_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RL(dst) = MULTW( RL(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ mult rrd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z59_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RL(dst) = MULTW( RL(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ divl rqd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z5A_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RQ(dst) = DIVL( RQ(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ divl rqd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z5A_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RQ(dst) = DIVL( RQ(dst), RDMEM_L(addr) );
+}
+
+/******************************************
+ div rrd,addr
+ flags: CZSV--
+ ******************************************/
+static void Z5B_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RL(dst) = DIVW( RL(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ div rrd,addr(rs)
+ flags: CZSV--
+ ******************************************/
+static void Z5B_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RL(dst) = DIVW( RL(dst), RDMEM_W(addr) );
+}
+
+/******************************************
+ ldm rd,addr,n
+ flags: ------
+ ******************************************/
+static void Z5C_0000_0001_0000_dddd_0000_nmin1_addr(void)
+{
+ GET_DST(OP1,NIB1);
+ GET_CNT(OP1,NIB3);
+ GET_ADDR(OP2);
+ while (cnt-- >= 0) {
+ RW(dst) = RDMEM_W(addr);
+ dst = (dst+1) & 15;
+ addr = (addr + 2) & 0xffff;
+ }
+}
+
+/******************************************
+ testl addr
+ flags: -ZS---
+ ******************************************/
+static void Z5C_0000_1000_addr(void)
+{
+ GET_ADDR(OP1);
+ TESTL( RDMEM_L(addr) );
+}
+
+/******************************************
+ ldm addr,rs,n
+ flags: ------
+ ******************************************/
+static void Z5C_0000_1001_0000_ssss_0000_nmin1_addr(void)
+{
+ GET_SRC(OP1,NIB1);
+ GET_CNT(OP1,NIB3);
+ GET_ADDR(OP2);
+ while (cnt-- >= 0) {
+ WRMEM_W( addr, RW(src) );
+ src = (src+1) & 15;
+ addr = (addr + 2) & 0xffff;
+ }
+}
+
+/******************************************
+ testl addr(rd)
+ flags: -ZS---
+ ******************************************/
+static void Z5C_ddN0_1000_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ TESTL( RDMEM_L(addr) );
+}
+
+/******************************************
+ ldm addr(rd),rs,n
+ flags: ------
+ ******************************************/
+static void Z5C_ddN0_1001_0000_ssN0_0000_nmin1_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB1);
+ GET_CNT(OP1,NIB3);
+ GET_ADDR(OP2);
+ addr += RW(dst);
+ while (cnt-- >= 0) {
+ WRMEM_W( addr, RW(src) );
+ src = (src+1) & 15;
+ addr = (addr + 2) & 0xffff;
+ }
+}
+
+/******************************************
+ ldm rd,addr(rs),n
+ flags: ------
+ ******************************************/
+static void Z5C_ssN0_0001_0000_dddd_0000_nmin1_addr(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_DST(OP1,NIB1);
+ GET_CNT(OP1,NIB3);
+ GET_ADDR(OP2);
+ addr += RW(src);
+ while (cnt-- >= 0) {
+ RW(dst) = RDMEM_W(addr);
+ dst = (dst+1) & 15;
+ addr = (addr + 2) & 0xffff;
+ }
+}
+
+/******************************************
+ ldl addr,rrs
+ flags: ------
+ ******************************************/
+static void Z5D_0000_ssss_addr(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_ADDR(OP1);
+ WRMEM_L( addr, RL(src) );
+}
+
+/******************************************
+ ldl addr(rd),rrs
+ flags: ------
+ ******************************************/
+static void Z5D_ddN0_ssss_addr(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_L( addr, RL(src) );
+}
+
+/******************************************
+ jp cc,addr
+ flags: ------
+ ******************************************/
+static void Z5E_0000_cccc_addr(void)
+{
+ GET_CCC(OP0,NIB3);
+ GET_ADDR(OP1);
+ switch (cc) {
+ case 0: if (CC0) PC = addr; break;
+ case 1: if (CC1) PC = addr; break;
+ case 2: if (CC2) PC = addr; break;
+ case 3: if (CC3) PC = addr; break;
+ case 4: if (CC4) PC = addr; break;
+ case 5: if (CC5) PC = addr; break;
+ case 6: if (CC6) PC = addr; break;
+ case 7: if (CC7) PC = addr; break;
+ case 8: if (CC8) PC = addr; break;
+ case 9: if (CC9) PC = addr; break;
+ case 10: if (CCA) PC = addr; break;
+ case 11: if (CCB) PC = addr; break;
+ case 12: if (CCC) PC = addr; break;
+ case 13: if (CCD) PC = addr; break;
+ case 14: if (CCE) PC = addr; break;
+ case 15: if (CCF) PC = addr; break;
+ }
+ change_pc(PC);
+}
+
+/******************************************
+ jp cc,addr(rd)
+ flags: ------
+ ******************************************/
+static void Z5E_ddN0_cccc_addr(void)
+{
+ GET_CCC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ switch (cc) {
+ case 0: if (CC0) PC = addr; break;
+ case 1: if (CC1) PC = addr; break;
+ case 2: if (CC2) PC = addr; break;
+ case 3: if (CC3) PC = addr; break;
+ case 4: if (CC4) PC = addr; break;
+ case 5: if (CC5) PC = addr; break;
+ case 6: if (CC6) PC = addr; break;
+ case 7: if (CC7) PC = addr; break;
+ case 8: if (CC8) PC = addr; break;
+ case 9: if (CC9) PC = addr; break;
+ case 10: if (CCA) PC = addr; break;
+ case 11: if (CCB) PC = addr; break;
+ case 12: if (CCC) PC = addr; break;
+ case 13: if (CCD) PC = addr; break;
+ case 14: if (CCE) PC = addr; break;
+ case 15: if (CCF) PC = addr; break;
+ }
+ change_pc(PC);
+}
+
+/******************************************
+ call addr
+ flags: ------
+ ******************************************/
+static void Z5F_0000_0000_addr(void)
+{
+ GET_ADDR(OP1);
+ PUSHW( SP, PC );
+ PC = addr;
+ change_pc(PC);
+}
+
+/******************************************
+ call addr(rd)
+ flags: ------
+ ******************************************/
+static void Z5F_ddN0_0000_addr(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ PUSHW( SP, PC );
+ addr += RW(dst);
+ PC = addr;
+ change_pc(PC);
+}
+
+/******************************************
+ ldb rbd,addr
+ flags: ------
+ ******************************************/
+static void Z60_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RB(dst) = RDMEM_B(addr);
+}
+
+/******************************************
+ ldb rbd,addr(rs)
+ flags: ------
+ ******************************************/
+static void Z60_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RB(dst) = RDMEM_B(addr);
+}
+
+/******************************************
+ ld rd,addr
+ flags: ------
+ ******************************************/
+static void Z61_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RW(dst) = RDMEM_W(addr);
+}
+
+/******************************************
+ ld rd,addr(rs)
+ flags: ------
+ ******************************************/
+static void Z61_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RW(dst) = RDMEM_W(addr);
+}
+
+/******************************************
+ resb addr,imm4
+ flags: ------
+ ******************************************/
+static void Z62_0000_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_ADDR(OP1);
+ WRMEM_B( addr, RDMEM_B(addr) & ~bit );
+}
+
+/******************************************
+ resb addr(rd),imm4
+ flags: ------
+ ******************************************/
+static void Z62_ddN0_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_B( addr, RDMEM_B(addr) & ~bit );
+}
+
+/******************************************
+ res addr,imm4
+ flags: ------
+ ******************************************/
+static void Z63_0000_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_ADDR(OP1);
+ WRMEM_W( addr, RDMEM_W(addr) & ~bit );
+}
+
+/******************************************
+ res addr(rd),imm4
+ flags: ------
+ ******************************************/
+static void Z63_ddN0_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_W( addr, RDMEM_W(addr) & ~bit );
+}
+
+/******************************************
+ setb addr,imm4
+ flags: ------
+ ******************************************/
+static void Z64_0000_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_ADDR(OP1);
+ WRMEM_B( addr, RDMEM_B(addr) | bit );
+}
+
+/******************************************
+ setb addr(rd),imm4
+ flags: ------
+ ******************************************/
+static void Z64_ddN0_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_B( addr, RDMEM_B(addr) | bit );
+}
+
+/******************************************
+ set addr,imm4
+ flags: ------
+ ******************************************/
+static void Z65_0000_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_ADDR(OP1);
+ WRMEM_W( addr, RDMEM_W(addr) | bit );
+}
+
+/******************************************
+ set addr(rd),imm4
+ flags: ------
+ ******************************************/
+static void Z65_ddN0_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_W( addr, RDMEM_W(addr) | bit );
+}
+
+/******************************************
+ bitb addr,imm4
+ flags: -Z----
+ ******************************************/
+static void Z66_0000_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_ADDR(OP1);
+ if ( RDMEM_B(addr) & bit) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ bitb addr(rd),imm4
+ flags: -Z----
+ ******************************************/
+static void Z66_ddN0_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ if ( RDMEM_B(addr) & bit) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ bit addr,imm4
+ flags: -Z----
+ ******************************************/
+static void Z67_0000_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_ADDR(OP1);
+ if ( RDMEM_W(addr) & bit) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ bit addr(rd),imm4
+ flags: -Z----
+ ******************************************/
+static void Z67_ddN0_imm4_addr(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ if ( RDMEM_W(addr) & bit) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ incb addr,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z68_0000_imm4m1_addr(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_ADDR(OP1);
+ WRMEM_B( addr, INCB(RDMEM_B(addr), i4p1) );
+}
+
+/******************************************
+ incb addr(rd),imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z68_ddN0_imm4m1_addr(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_B( addr, INCB(RDMEM_B(addr), i4p1) );
+}
+
+/******************************************
+ inc addr,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z69_0000_imm4m1_addr(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_ADDR(OP1);
+ WRMEM_W( addr, INCW(RDMEM_W(addr), i4p1) );
+}
+
+/******************************************
+ inc addr(rd),imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z69_ddN0_imm4m1_addr(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_W( addr, INCW(RDMEM_W(addr), i4p1) );
+}
+
+/******************************************
+ decb addr,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z6A_0000_imm4m1_addr(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_ADDR(OP1);
+ WRMEM_B( addr, DECB(RDMEM_B(addr), i4p1) );
+}
+
+/******************************************
+ decb addr(rd),imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z6A_ddN0_imm4m1_addr(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_B( addr, DECB(RDMEM_B(addr), i4p1) );
+}
+
+/******************************************
+ dec addr,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z6B_0000_imm4m1_addr(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_ADDR(OP1);
+ WRMEM_W( addr, DECW(RDMEM_W(addr), i4p1) );
+}
+
+/******************************************
+ dec addr(rd),imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void Z6B_ddN0_imm4m1_addr(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_W( addr, DECW(RDMEM_W(addr), i4p1) );
+}
+
+/******************************************
+ exb rbd,addr
+ flags: ------
+ ******************************************/
+static void Z6C_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ UINT8 tmp = RDMEM_B(addr);
+ WRMEM_B(addr, RB(dst));
+ RB(dst) = tmp;
+}
+
+/******************************************
+ exb rbd,addr(rs)
+ flags: ------
+ ******************************************/
+static void Z6C_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ UINT8 tmp;
+ addr += RW(src);
+ tmp = RDMEM_B(addr);
+ WRMEM_B(addr, RB(dst));
+ RB(dst) = tmp;
+}
+
+/******************************************
+ ex rd,addr
+ flags: ------
+ ******************************************/
+static void Z6D_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ UINT16 tmp = RDMEM_W(addr);
+ WRMEM_W( addr, RW(dst) );
+ RW(dst) = tmp;
+}
+
+/******************************************
+ ex rd,addr(rs)
+ flags: ------
+ ******************************************/
+static void Z6D_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ UINT16 tmp;
+ addr += RW(src);
+ tmp = RDMEM_W(addr);
+ WRMEM_W( addr, RW(dst) );
+ RW(dst) = tmp;
+}
+
+/******************************************
+ ldb addr,rbs
+ flags: ------
+ ******************************************/
+static void Z6E_0000_ssss_addr(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_ADDR(OP1);
+ WRMEM_B( addr, RB(src) );
+}
+
+/******************************************
+ ldb addr(rd),rbs
+ flags: ------
+ ******************************************/
+static void Z6E_ddN0_ssss_addr(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_B( addr, RB(src) );
+}
+
+/******************************************
+ ld addr,rs
+ flags: ------
+ ******************************************/
+static void Z6F_0000_ssss_addr(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_ADDR(OP1);
+ WRMEM_W( addr, RW(src) );
+}
+
+/******************************************
+ ld addr(rd),rs
+ flags: ------
+ ******************************************/
+static void Z6F_ddN0_ssss_addr(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(dst);
+ WRMEM_W( addr, RW(src) );
+}
+
+/******************************************
+ ldb rbd,rs(rx)
+ flags: ------
+ ******************************************/
+static void Z70_ssN0_dddd_0000_xxxx_0000_0000(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_IDX(OP1,NIB1);
+ RB(dst) = RDMEM_B( (UINT16)(RW(src) + RW(idx)) );
+}
+
+/******************************************
+ ld rd,rs(rx)
+ flags: ------
+ ******************************************/
+static void Z71_ssN0_dddd_0000_xxxx_0000_0000(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_IDX(OP1,NIB1);
+ RW(dst) = RDMEM_W( (UINT16)(RW(src) + RW(idx)) );
+}
+
+/******************************************
+ ldb rd(rx),rbs
+ flags: ------
+ ******************************************/
+static void Z72_ddN0_ssss_0000_xxxx_0000_0000(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_IDX(OP1,NIB1);
+ WRMEM_B( (UINT16)(RW(dst) + RW(idx)), RB(src) );
+}
+
+/******************************************
+ ld rd(rx),rs
+ flags: ------
+ ******************************************/
+static void Z73_ddN0_ssss_0000_xxxx_0000_0000(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_IDX(OP1,NIB1);
+ WRMEM_W( (UINT16)(RW(dst) + RW(idx)), RW(src) );
+}
+
+/******************************************
+ lda prd,rs(rx)
+ flags: ------
+ ******************************************/
+static void Z74_ssN0_dddd_0000_xxxx_0000_0000(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_IDX(OP1,NIB1);
+ RW(dst) = (UINT16)(RW(src) + RW(idx));
+}
+
+/******************************************
+ ldl rrd,rs(rx)
+ flags: ------
+ ******************************************/
+static void Z75_ssN0_dddd_0000_xxxx_0000_0000(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_IDX(OP1,NIB1);
+ RL(dst) = RDMEM_L( (UINT16)(RW(src) + RW(idx)) );
+}
+
+/******************************************
+ lda prd,addr
+ flags: ------
+ ******************************************/
+static void Z76_0000_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_ADDR(OP1);
+ RW(dst) = addr;
+}
+
+/******************************************
+ lda prd,addr(rs)
+ flags: ------
+ ******************************************/
+static void Z76_ssN0_dddd_addr(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ addr += RW(src);
+ RW(dst) = addr;
+}
+
+/******************************************
+ ldl rd(rx),rrs
+ flags: ------
+ ******************************************/
+static void Z77_ddN0_ssss_0000_xxxx_0000_0000(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ GET_IDX(OP1,NIB1);
+ WRMEM_L( (UINT16)(RW(dst) + RW(idx)), RL(src) );
+}
+
+/******************************************
+ rsvd78
+ flags: ------
+ ******************************************/
+static void Z78_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: rsvd78 $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ ldps addr
+ flags: CZSVDH
+ ******************************************/
+static void Z79_0000_0000_addr(void)
+{
+ GET_ADDR(OP1);
+ UINT16 fcw;
+ fcw = RDMEM_W(addr);
+ PC = RDMEM_W((UINT16)(addr + 2));
+ CHANGE_FCW(fcw); /* check for user/system mode change */
+ change_pc(PC);
+}
+
+/******************************************
+ ldps addr(rs)
+ flags: CZSVDH
+ ******************************************/
+static void Z79_ssN0_0000_addr(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_ADDR(OP1);
+ UINT16 fcw;
+ addr += RW(src);
+ fcw = RDMEM_W(addr);
+ PC = RDMEM_W((UINT16)(addr + 2));
+ CHANGE_FCW(fcw); /* check for user/system mode change */
+ change_pc(PC);
+}
+
+/******************************************
+ halt
+ flags: ------
+ ******************************************/
+static void Z7A_0000_0000(void)
+{
+ IRQ_REQ |= Z8000_HALT;
+ if (z8000_ICount > 0) z8000_ICount = 0;
+}
+
+/******************************************
+ iret
+ flags: CZSVDH
+ ******************************************/
+static void Z7B_0000_0000(void)
+{
+ UINT16 tag, fcw;
+ tag = POPW( SP ); /* get type tag */
+ fcw = POPW( SP ); /* get FCW */
+ PC = POPW( SP ); /* get PC */
+ IRQ_SRV &= ~tag; /* remove IRQ serviced flag */
+ CHANGE_FCW(fcw); /* check for user/system mode change */
+ change_pc(PC);
+ LOG(("Z8K#%d IRET tag $%04x, fcw $%04x, pc $%04x\n", cpu_getactivecpu(), tag, fcw, PC));
+}
+
+/******************************************
+ mset
+ flags: ------
+ ******************************************/
+static void Z7B_0000_1000(void)
+{
+ /* set mu-0 line */
+}
+
+/******************************************
+ mres
+ flags: ------
+ ******************************************/
+static void Z7B_0000_1001(void)
+{
+ /* reset mu-0 line */
+}
+
+/******************************************
+ mbit
+ flags: CZS---
+ ******************************************/
+static void Z7B_0000_1010(void)
+{
+ /* test mu-I line */
+}
+
+/******************************************
+ mreq rd
+ flags: -ZS---
+ ******************************************/
+static void Z7B_dddd_1101(void)
+{
+ /* test mu-I line, invert cascade to mu-0 */
+}
+
+/******************************************
+ di i2
+ flags: ------
+ ******************************************/
+static void Z7C_0000_00ii(void)
+{
+ GET_IMM2(OP0,NIB3);
+ UINT16 fcw = FCW;
+ fcw &= ~(imm2 << 11);
+ CHANGE_FCW(fcw);
+}
+
+/******************************************
+ ei i2
+ flags: ------
+ ******************************************/
+static void Z7C_0000_01ii(void)
+{
+ GET_IMM2(OP0,NIB3);
+ UINT16 fcw = FCW;
+ fcw |= imm2 << 11;
+ CHANGE_FCW(fcw);
+}
+
+/******************************************
+ ldctl rd,ctrl
+ flags: ------
+ ******************************************/
+static void Z7D_dddd_0ccc(void)
+{
+ GET_IMM3(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ switch (imm3) {
+ case 0:
+ RW(dst) = FCW;
+ break;
+ case 3:
+ RW(dst) = REFRESH;
+ break;
+ case 5:
+ RW(dst) = PSAP;
+ break;
+ case 7:
+ RW(dst) = NSP;
+ break;
+ default:
+ LOG(("Z8K#%d LDCTL R%d,%d\n", cpu_getactivecpu(), dst, imm3));
+ }
+}
+
+/******************************************
+ ldctl ctrl,rs
+ flags: ------
+ ******************************************/
+static void Z7D_ssss_1ccc(void)
+{
+ GET_IMM3(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ switch (imm3) {
+ case 0:
+ {
+ UINT16 fcw;
+ fcw = RW(src);
+ CHANGE_FCW(fcw); /* check for user/system mode change */
+ }
+ break;
+ case 3:
+ REFRESH = RW(src);
+ break;
+ case 5:
+ PSAP = RW(src);
+ break;
+ case 7:
+ NSP = RW(src);
+ break;
+ default:
+ LOG(("Z8K#%d LDCTL %d,R%d\n", cpu_getactivecpu(), imm3, src));
+ }
+}
+
+/******************************************
+ rsvd7e
+ flags: ------
+ ******************************************/
+static void Z7E_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: rsvd7e $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ sc imm8
+ flags: CZSVDH
+ ******************************************/
+static void Z7F_imm8(void)
+{
+ GET_IMM8(0);
+ /* execute system call via IRQ */
+ IRQ_REQ = Z8000_SYSCALL | imm8;
+
+}
+
+/******************************************
+ addb rbd,rbs
+ flags: CZSVDH
+ ******************************************/
+static void Z80_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = ADDB( RB(dst), RB(src) );
+}
+
+/******************************************
+ add rd,rs
+ flags: CZSV--
+ ******************************************/
+static void Z81_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = ADDW( RW(dst), RW(src) );
+}
+
+/******************************************
+ subb rbd,rbs
+ flags: CZSVDH
+ ******************************************/
+static void Z82_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = SUBB( RB(dst), RB(src) );
+}
+
+/******************************************
+ sub rd,rs
+ flags: CZSV--
+ ******************************************/
+static void Z83_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = SUBW( RW(dst), RW(src) );
+}
+
+/******************************************
+ orb rbd,rbs
+ flags: CZSP--
+ ******************************************/
+static void Z84_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = ORB( RB(dst), RB(src) );
+}
+
+/******************************************
+ or rd,rs
+ flags: CZS---
+ ******************************************/
+static void Z85_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = ORW( RW(dst), RW(src) );
+}
+
+/******************************************
+ andb rbd,rbs
+ flags: -ZSP--
+ ******************************************/
+static void Z86_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = ANDB( RB(dst), RB(src) );
+}
+
+/******************************************
+ and rd,rs
+ flags: -ZS---
+ ******************************************/
+static void Z87_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = ANDW( RW(dst), RW(src) );
+}
+
+/******************************************
+ xorb rbd,rbs
+ flags: -ZSP--
+ ******************************************/
+static void Z88_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = XORB( RB(dst), RB(src) );
+}
+
+/******************************************
+ xor rd,rs
+ flags: -ZS---
+ ******************************************/
+static void Z89_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = XORW( RW(dst), RW(src) );
+}
+
+/******************************************
+ cpb rbd,rbs
+ flags: CZSV--
+ ******************************************/
+static void Z8A_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ CPB( RB(dst), RB(src) );
+}
+
+/******************************************
+ cp rd,rs
+ flags: CZSV--
+ ******************************************/
+static void Z8B_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ CPW( RW(dst), RW(src) );
+}
+
+/******************************************
+ comb rbd
+ flags: -ZSP--
+ ******************************************/
+static void Z8C_dddd_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ RB(dst) = COMB( RB(dst) );
+}
+
+/******************************************
+ negb rbd
+ flags: CZSV--
+ ******************************************/
+static void Z8C_dddd_0010(void)
+{
+ GET_DST(OP0,NIB2);
+ RB(dst) = NEGB( RB(dst) );
+}
+
+/******************************************
+ testb rbd
+ flags: -ZSP--
+ ******************************************/
+static void Z8C_dddd_0100(void)
+{
+ GET_DST(OP0,NIB2);
+ TESTB( RB(dst) );
+}
+
+/******************************************
+ tsetb rbd
+ flags: --S---
+ ******************************************/
+static void Z8C_dddd_0110(void)
+{
+ GET_DST(OP0,NIB2);
+ if (RB(dst) & S08) SET_S; else CLR_S;
+ RB(dst) = 0xff;
+}
+
+/******************************************
+ clrb rbd
+ flags: ------
+ ******************************************/
+static void Z8C_dddd_1000(void)
+{
+ GET_DST(OP0,NIB2);
+ RB(dst) = 0;
+}
+
+/******************************************
+ nop
+ flags: ------
+ ******************************************/
+static void Z8D_0000_0111(void)
+{
+ /* nothing */
+}
+
+/******************************************
+ com rd
+ flags: -ZS---
+ ******************************************/
+static void Z8D_dddd_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ RW(dst) = COMW( RW(dst) );
+}
+
+/******************************************
+ neg rd
+ flags: CZSV--
+ ******************************************/
+static void Z8D_dddd_0010(void)
+{
+ GET_DST(OP0,NIB2);
+ RW(dst) = NEGW( RW(dst) );
+}
+
+/******************************************
+ test rd
+ flags: ------
+ ******************************************/
+static void Z8D_dddd_0100(void)
+{
+ GET_DST(OP0,NIB2);
+ TESTW( RW(dst) );
+}
+
+/******************************************
+ tset rd
+ flags: --S---
+ ******************************************/
+static void Z8D_dddd_0110(void)
+{
+ GET_DST(OP0,NIB2);
+ if (RW(dst) & S16) SET_S; else CLR_S;
+ RW(dst) = 0xffff;
+}
+
+/******************************************
+ clr rd
+ flags: ------
+ ******************************************/
+static void Z8D_dddd_1000(void)
+{
+ GET_DST(OP0,NIB2);
+ RW(dst) = 0;
+}
+
+/******************************************
+ setflg imm4
+ flags: CZSV--
+ ******************************************/
+static void Z8D_imm4_0001(void)
+{
+ FCW |= Z.op[0] & 0x00f0;
+}
+
+/******************************************
+ resflg imm4
+ flags: CZSV--
+ ******************************************/
+static void Z8D_imm4_0011(void)
+{
+ FCW &= ~(Z.op[0] & 0x00f0);
+}
+
+/******************************************
+ comflg flags
+ flags: CZSP--
+ ******************************************/
+static void Z8D_imm4_0101(void)
+{
+ FCW ^= (Z.op[0] & 0x00f0);
+}
+
+/******************************************
+ ext8e imm8
+ flags: ------
+ ******************************************/
+static void Z8E_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: ext8e $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ ext8f imm8
+ flags: ------
+ ******************************************/
+static void Z8F_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: ext8f $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ cpl rrd,rrs
+ flags: CZSV--
+ ******************************************/
+static void Z90_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ CPL( RL(dst), RL(src) );
+}
+
+/******************************************
+ pushl @rd,rrs
+ flags: ------
+ ******************************************/
+static void Z91_ddN0_ssss(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ PUSHL( dst, RL(src) );
+}
+
+/******************************************
+ subl rrd,rrs
+ flags: CZSV--
+ ******************************************/
+static void Z92_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = SUBL( RL(dst), RL(src) );
+}
+
+/******************************************
+ push @rd,rs
+ flags: ------
+ ******************************************/
+static void Z93_ddN0_ssss(void)
+{
+ GET_SRC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ PUSHW(dst, RW(src));
+}
+
+/******************************************
+ ldl rrd,rrs
+ flags: ------
+ ******************************************/
+static void Z94_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = RL(src);
+}
+
+/******************************************
+ popl rrd,@rs
+ flags: ------
+ ******************************************/
+static void Z95_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = POPL( src );
+}
+
+/******************************************
+ addl rrd,rrs
+ flags: CZSV--
+ ******************************************/
+static void Z96_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = ADDL( RL(dst), RL(src) );
+}
+
+/******************************************
+ pop rd,@rs
+ flags: ------
+ ******************************************/
+static void Z97_ssN0_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = POPW( src );
+}
+
+/******************************************
+ multl rqd,rrs
+ flags: CZSV--
+ ******************************************/
+static void Z98_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RQ(dst) = MULTL( RQ(dst), RL(src) );
+}
+
+/******************************************
+ mult rrd,rs
+ flags: CZSV--
+ ******************************************/
+static void Z99_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = MULTW( RL(dst), RW(src) );
+}
+
+/******************************************
+ divl rqd,rrs
+ flags: CZSV--
+ ******************************************/
+static void Z9A_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RQ(dst) = DIVL( RQ(dst), RL(src) );
+}
+
+/******************************************
+ div rrd,rs
+ flags: CZSV--
+ ******************************************/
+static void Z9B_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RL(dst) = DIVW( RL(dst), RW(src) );
+}
+
+/******************************************
+ testl rrd
+ flags: -ZS---
+ ******************************************/
+static void Z9C_dddd_1000(void)
+{
+ GET_DST(OP0,NIB2);
+ CLR_ZS;
+ if (!RL(dst)) SET_Z;
+ else if (RL(dst) & S32) SET_S;
+}
+
+/******************************************
+ rsvd9d
+ flags: ------
+ ******************************************/
+static void Z9D_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: rsvd9d $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ ret cc
+ flags: ------
+ ******************************************/
+static void Z9E_0000_cccc(void)
+{
+ GET_CCC(OP0,NIB3);
+ switch (cc) {
+ case 0: if (CC0) PC = POPW( SP ); break;
+ case 1: if (CC1) PC = POPW( SP ); break;
+ case 2: if (CC2) PC = POPW( SP ); break;
+ case 3: if (CC3) PC = POPW( SP ); break;
+ case 4: if (CC4) PC = POPW( SP ); break;
+ case 5: if (CC5) PC = POPW( SP ); break;
+ case 6: if (CC6) PC = POPW( SP ); break;
+ case 7: if (CC7) PC = POPW( SP ); break;
+ case 8: if (CC8) PC = POPW( SP ); break;
+ case 9: if (CC9) PC = POPW( SP ); break;
+ case 10: if (CCA) PC = POPW( SP ); break;
+ case 11: if (CCB) PC = POPW( SP ); break;
+ case 12: if (CCC) PC = POPW( SP ); break;
+ case 13: if (CCD) PC = POPW( SP ); break;
+ case 14: if (CCE) PC = POPW( SP ); break;
+ case 15: if (CCF) PC = POPW( SP ); break;
+ }
+ change_pc(PC);
+}
+
+/******************************************
+ rsvd9f
+ flags: ------
+ ******************************************/
+static void Z9F_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: rsvd9f $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+}
+
+/******************************************
+ ldb rbd,rbs
+ flags: ------
+ ******************************************/
+static void ZA0_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = RB(src);
+}
+
+/******************************************
+ ld rd,rs
+ flags: ------
+ ******************************************/
+static void ZA1_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = RW(src);
+}
+
+/******************************************
+ resb rbd,imm4
+ flags: ------
+ ******************************************/
+static void ZA2_dddd_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ RB(dst) &= ~bit;
+}
+
+/******************************************
+ res rd,imm4
+ flags: ------
+ ******************************************/
+static void ZA3_dddd_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ RW(dst) &= ~bit;
+}
+
+/******************************************
+ setb rbd,imm4
+ flags: ------
+ ******************************************/
+static void ZA4_dddd_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ RB(dst) |= bit;
+}
+
+/******************************************
+ set rd,imm4
+ flags: ------
+ ******************************************/
+static void ZA5_dddd_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ RW(dst) |= bit;
+}
+
+/******************************************
+ bitb rbd,imm4
+ flags: -Z----
+ ******************************************/
+static void ZA6_dddd_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ if (RB(dst) & bit) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ bit rd,imm4
+ flags: -Z----
+ ******************************************/
+static void ZA7_dddd_imm4(void)
+{
+ GET_BIT(OP0);
+ GET_DST(OP0,NIB2);
+ if (RW(dst) & bit) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ incb rbd,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void ZA8_dddd_imm4m1(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ RB(dst) = INCB( RB(dst), i4p1);
+}
+
+/******************************************
+ inc rd,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void ZA9_dddd_imm4m1(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ RW(dst) = INCW( RW(dst), i4p1 );
+}
+
+/******************************************
+ decb rbd,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void ZAA_dddd_imm4m1(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ RB(dst) = DECB( RB(dst), i4p1 );
+}
+
+/******************************************
+ dec rd,imm4m1
+ flags: -ZSV--
+ ******************************************/
+static void ZAB_dddd_imm4m1(void)
+{
+ GET_I4M1(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ RW(dst) = DECW( RW(dst), i4p1 );
+}
+
+/******************************************
+ exb rbd,rbs
+ flags: ------
+ ******************************************/
+static void ZAC_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ UINT8 tmp = RB(src);
+ RB(src) = RB(dst);
+ RB(dst) = tmp;
+}
+
+/******************************************
+ ex rd,rs
+ flags: ------
+ ******************************************/
+static void ZAD_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ UINT16 tmp = RW(src);
+ RW(src) = RW(dst);
+ RW(dst) = tmp;
+}
+
+/******************************************
+ tccb cc,rbd
+ flags: ------
+ ******************************************/
+static void ZAE_dddd_cccc(void)
+{
+ GET_CCC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ UINT8 tmp = RB(dst) & ~1;
+ switch (cc) {
+ case 0: if (CC0) tmp |= 1; break;
+ case 1: if (CC1) tmp |= 1; break;
+ case 2: if (CC2) tmp |= 1; break;
+ case 3: if (CC3) tmp |= 1; break;
+ case 4: if (CC4) tmp |= 1; break;
+ case 5: if (CC5) tmp |= 1; break;
+ case 6: if (CC6) tmp |= 1; break;
+ case 7: if (CC7) tmp |= 1; break;
+ case 8: if (CC8) tmp |= 1; break;
+ case 9: if (CC9) tmp |= 1; break;
+ case 10: if (CCA) tmp |= 1; break;
+ case 11: if (CCB) tmp |= 1; break;
+ case 12: if (CCC) tmp |= 1; break;
+ case 13: if (CCD) tmp |= 1; break;
+ case 14: if (CCE) tmp |= 1; break;
+ case 15: if (CCF) tmp |= 1; break;
+ }
+ RB(dst) = tmp;
+}
+
+/******************************************
+ tcc cc,rd
+ flags: ------
+ ******************************************/
+static void ZAF_dddd_cccc(void)
+{
+ GET_CCC(OP0,NIB3);
+ GET_DST(OP0,NIB2);
+ UINT16 tmp = RW(dst) & ~1;
+ switch (cc) {
+ case 0: if (CC0) tmp |= 1; break;
+ case 1: if (CC1) tmp |= 1; break;
+ case 2: if (CC2) tmp |= 1; break;
+ case 3: if (CC3) tmp |= 1; break;
+ case 4: if (CC4) tmp |= 1; break;
+ case 5: if (CC5) tmp |= 1; break;
+ case 6: if (CC6) tmp |= 1; break;
+ case 7: if (CC7) tmp |= 1; break;
+ case 8: if (CC8) tmp |= 1; break;
+ case 9: if (CC9) tmp |= 1; break;
+ case 10: if (CCA) tmp |= 1; break;
+ case 11: if (CCB) tmp |= 1; break;
+ case 12: if (CCC) tmp |= 1; break;
+ case 13: if (CCD) tmp |= 1; break;
+ case 14: if (CCE) tmp |= 1; break;
+ case 15: if (CCF) tmp |= 1; break;
+ }
+ RW(dst) = tmp;
+}
+
+/******************************************
+ dab rbd
+ flags: CZS---
+ ******************************************/
+static void ZB0_dddd_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ UINT8 result;
+ UINT16 idx = RB(dst);
+ if (FCW & F_C) idx |= 0x100;
+ if (FCW & F_H) idx |= 0x200;
+ if (FCW & F_DA) idx |= 0x400;
+ result = Z8000_dab[idx];
+ CLR_CZS;
+ CHK_XXXB_ZS;
+ if (Z8000_dab[idx] & 0x100) SET_C;
+ RB(dst) = result;
+}
+
+/******************************************
+ extsb rd
+ flags: ------
+ ******************************************/
+static void ZB1_dddd_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ RW(dst) = (RW(dst) & 0xff) | ((RW(dst) & S08) ? 0xff00 : 0x0000);
+}
+
+/******************************************
+ extsl rqd
+ flags: ------
+ ******************************************/
+static void ZB1_dddd_0111(void)
+{
+ GET_DST(OP0,NIB2);
+ RQ(dst) = COMBINE_U64_U32_U32( (RQ(dst) & S32) ?
+ 0xfffffffful : 0, LO32_U32_U64(RQ(dst)));
+}
+
+/******************************************
+ exts rrd
+ flags: ------
+ ******************************************/
+static void ZB1_dddd_1010(void)
+{
+ GET_DST(OP0,NIB2);
+ RL(dst) = (RL(dst) & 0xffff) | ((RL(dst) & S16) ?
+ 0xffff0000ul : 0x00000000ul);
+}
+
+/******************************************
+ sllb rbd,imm8
+ flags: CZS---
+ srlb rbd,imm8
+ flags: CZSV--
+ ******************************************/
+static void ZB2_dddd_0001_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ if (imm16 & S16)
+ RB(dst) = SRLB( RB(dst), -(INT16)imm16 );
+ else
+ RB(dst) = SLLB( RB(dst), imm16 );
+}
+
+/******************************************
+ sdlb rbd,rs
+ flags: CZS---
+ ******************************************/
+static void ZB2_dddd_0011_0000_ssss_0000_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB1);
+ RB(dst) = SRLB( RB(dst), (INT8)RW(src) );
+}
+
+/******************************************
+ rlb rbd,imm1or2
+ flags: CZSV--
+ ******************************************/
+static void ZB2_dddd_00I0(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM1(OP0,NIB3);
+ RB(dst) = RLB( RB(dst), imm1 );
+}
+
+/******************************************
+ rrb rbd,imm1or2
+ flags: CZSV--
+ ******************************************/
+static void ZB2_dddd_01I0(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM1(OP0,NIB3);
+ RB(dst) = RRB( RB(dst), imm1 );
+}
+
+/******************************************
+ slab rbd,imm8
+ flags: CZSV--
+ srab rbd,imm8
+ flags: CZSV--
+ ******************************************/
+static void ZB2_dddd_1001_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ if (imm16 & S16)
+ RB(dst) = SRAB( RB(dst), -(INT16)imm16 );
+ else
+ RB(dst) = SLAB( RB(dst), imm16 );
+}
+
+/******************************************
+ sdab rbd,rs
+ flags: CZSV--
+ ******************************************/
+static void ZB2_dddd_1011_0000_ssss_0000_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB1);
+ RB(dst) = SDAB( RB(dst), (INT8) RW(src) );
+}
+
+/******************************************
+ rlcb rbd,imm1or2
+ flags: -Z----
+ ******************************************/
+static void ZB2_dddd_10I0(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM1(OP0,NIB3);
+ RB(dst) = RLCB( RB(dst), imm1 );
+}
+
+/******************************************
+ rrcb rbd,imm1or2
+ flags: -Z----
+ ******************************************/
+static void ZB2_dddd_11I0(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM1(OP0,NIB3);
+ RB(dst) = RRCB( RB(dst), imm1 );
+}
+
+/******************************************
+ sll rd,imm8
+ flags: CZS---
+ srl rd,imm8
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_0001_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ if (imm16 & S16)
+ RW(dst) = SRLW( RW(dst), -(INT16)imm16 );
+ else
+ RW(dst) = SLLW( RW(dst), imm16 );
+}
+
+/******************************************
+ sdl rd,rs
+ flags: CZS---
+ ******************************************/
+static void ZB3_dddd_0011_0000_ssss_0000_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB1);
+ RW(dst) = SDLW( RW(dst), (INT8)RW(src) );
+}
+
+/******************************************
+ rl rd,imm1or2
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_00I0(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM1(OP0,NIB3);
+ RW(dst) = RLW( RW(dst), imm1 );
+}
+
+/******************************************
+ slll rrd,imm8
+ flags: CZS---
+ srll rrd,imm8
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_0101_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ if (imm16 & S16)
+ RL(dst) = SRLL( RL(dst), -(INT16)imm16 );
+ else
+ RL(dst) = SLLL( RL(dst), imm16 );
+}
+
+/******************************************
+ sdll rrd,rs
+ flags: CZS---
+ ******************************************/
+static void ZB3_dddd_0111_0000_ssss_0000_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB1);
+ RL(dst) = SDLL( RL(dst), RW(src) & 0xff );
+}
+
+/******************************************
+ rr rd,imm1or2
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_01I0(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM1(OP0,NIB3);
+ RW(dst) = RRW( RW(dst), imm1 );
+}
+
+/******************************************
+ sla rd,imm8
+ flags: CZSV--
+ sra rd,imm8
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_1001_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ if (imm16 & S16)
+ RW(dst) = SRAW( RW(dst), -(INT16)imm16 );
+ else
+ RW(dst) = SLAW( RW(dst), imm16 );
+}
+
+/******************************************
+ sda rd,rs
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_1011_0000_ssss_0000_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB1);
+ RW(dst) = SDAW( RW(dst), (INT8)RW(src) );
+}
+
+/******************************************
+ rlc rd,imm1or2
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_10I0(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM1(OP0,NIB3);
+ RW(dst) = RLCW( RW(dst), imm1 );
+}
+
+/******************************************
+ slal rrd,imm8
+ flags: CZSV--
+ sral rrd,imm8
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_1101_imm8(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM16(OP1);
+ if (imm16 & S16)
+ RL(dst) = SRAL( RL(dst), -(INT16)imm16 );
+ else
+ RL(dst) = SLAL( RL(dst), imm16 );
+}
+
+/******************************************
+ sdal rrd,rs
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_1111_0000_ssss_0000_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB1);
+ RL(dst) = SDAL( RL(dst), RW(src) & 0xff );
+}
+
+/******************************************
+ rrc rd,imm1or2
+ flags: CZSV--
+ ******************************************/
+static void ZB3_dddd_11I0(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM1(OP0,NIB3);
+ RW(dst) = RRCW( RW(dst), imm1 );
+}
+
+/******************************************
+ adcb rbd,rbs
+ flags: CZSVDH
+ ******************************************/
+static void ZB4_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = ADCB( RB(dst), RB(src) );
+}
+
+/******************************************
+ adc rd,rs
+ flags: CZSV--
+ ******************************************/
+static void ZB5_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = ADCW( RW(dst), RW(src) );
+}
+
+/******************************************
+ sbcb rbd,rbs
+ flags: CZSVDH
+ ******************************************/
+static void ZB6_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RB(dst) = SBCB( RB(dst), RB(src) );
+}
+
+/******************************************
+ sbc rd,rs
+ flags: CZSV--
+ ******************************************/
+static void ZB7_ssss_dddd(void)
+{
+ GET_DST(OP0,NIB3);
+ GET_SRC(OP0,NIB2);
+ RW(dst) = SBCW( RW(dst), RW(src) );
+}
+
+/******************************************
+ trtib @rd,@rs,rr
+ flags: -ZSV--
+ ******************************************/
+static void ZB8_ddN0_0010_0000_rrrr_ssN0_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ UINT8 xlt = RDMEM_B( (UINT16)(RW(src) + RDMEM_B(RW(dst))) );
+ RB(2) = xlt;
+ if (xlt) CLR_Z; else SET_Z;
+ RW(dst)++;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ trtirb @rd,@rs,rbr
+ flags: -ZSV--
+ ******************************************/
+static void ZB8_ddN0_0110_0000_rrrr_ssN0_1110(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ UINT8 xlt = RDMEM_B( (UINT16)(RW(src) + RDMEM_B(RW(dst))) );
+ RB(2) = xlt;
+ if (xlt) CLR_Z; else SET_Z;
+ RW(dst)++;
+ if (--RW(cnt)) { CLR_V; PC -= 4; } else SET_V;
+}
+
+/******************************************
+ trtdb @rd,@rs,rbr
+ flags: -ZSV--
+ ******************************************/
+static void ZB8_ddN0_1010_0000_rrrr_ssN0_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ UINT8 xlt = RDMEM_B( (UINT16)(RW(src) + RDMEM_B(RW(dst))) );
+ RB(2) = xlt;
+ if (xlt) CLR_Z; else SET_Z;
+ RW(dst)--;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ trtdrb @rd,@rs,rbr
+ flags: -ZSV--
+ ******************************************/
+static void ZB8_ddN0_1110_0000_rrrr_ssN0_1110(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ UINT8 xlt = RDMEM_B( (UINT16)(RW(src) + RDMEM_B(RW(dst))) );
+ RB(2) = xlt;
+ if (xlt) CLR_Z; else SET_Z;
+ RW(dst)--;
+ if (--RW(cnt)) { CLR_V; PC -= 4; } else SET_V;
+}
+
+/******************************************
+ trib @rd,@rs,rbr
+ flags: -ZSV--
+ ******************************************/
+static void ZB8_ddN0_0000_0000_rrrr_ssN0_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ UINT8 xlt = RDMEM_B( (UINT16)(RW(src) + RDMEM_B(RW(dst))) );
+ WRMEM_B( RW(dst), xlt );
+ RW(dst)++;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ trirb @rd,@rs,rbr
+ flags: -ZSV--
+ ******************************************/
+static void ZB8_ddN0_0100_0000_rrrr_ssN0_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ UINT8 xlt = RDMEM_B( (UINT16)(RW(src) + RDMEM_B(RW(dst))) );
+ WRMEM_B( RW(dst), xlt );
+ RW(dst)++;
+ if (--RW(cnt)) { CLR_V; PC -= 4; } else SET_V;
+}
+
+/******************************************
+ trdb @rd,@rs,rbr
+ flags: -ZSV--
+ ******************************************/
+static void ZB8_ddN0_1000_0000_rrrr_ssN0_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ UINT8 xlt = RDMEM_B( (UINT16)(RW(src) + RDMEM_B(RW(dst))) );
+ WRMEM_B( RW(dst), xlt );
+ RW(dst)--;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ trdrb @rd,@rs,rbr
+ flags: -ZSV--
+ ******************************************/
+static void ZB8_ddN0_1100_0000_rrrr_ssN0_0000(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_SRC(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ UINT8 xlt = RDMEM_B( (UINT16)(RW(src) + RDMEM_B(RW(dst))) );
+ WRMEM_B( RW(dst), xlt );
+ RW(dst)--;
+ if (--RW(cnt)) { CLR_V; PC -= 4; } else SET_V;
+}
+
+/******************************************
+ rsvdb9
+ flags: ------
+ ******************************************/
+static void ZB9_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: rsvdb9 $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+ (void)imm8;
+}
+
+/******************************************
+ cpib rbd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBA_ssN0_0000_0000_rrrr_dddd_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPB( RB(dst), RDMEM_B(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(src)++;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ ldib @rd,@rs,rr
+ ldibr @rd,@rs,rr
+ flags: ---V--
+ ******************************************/
+static void ZBA_ssN0_0001_0000_rrrr_ddN0_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3); /* repeat? */
+ WRMEM_B( RW(dst), RDMEM_B(RW(src)) );
+ RW(dst)++;
+ RW(src)++;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpsib @rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBA_ssN0_0010_0000_rrrr_ddN0_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPB( RDMEM_B(RW(dst)), RDMEM_B(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(dst)++;
+ RW(src)++;
+ if (--RW(cnt)) { CLR_V; if (!(FCW & F_Z)) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpirb rbd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBA_ssN0_0100_0000_rrrr_dddd_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPB( RB(dst), RDMEM_B(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(src)++;
+ if (--RW(cnt)) { CLR_V; if (!(FCW & F_Z)) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpsirb @rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBA_ssN0_0110_0000_rrrr_ddN0_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPB( RDMEM_B(RW(dst)), RDMEM_B(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(dst)++;
+ RW(src)++;
+ if (--RW(cnt)) { CLR_V; if (!(FCW & F_Z)) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpdb rbd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBA_ssN0_1000_0000_rrrr_dddd_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPB( RB(dst), RDMEM_B(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(src)--;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ lddb @rs,@rd,rr
+ lddbr @rs,@rd,rr
+ flags: ---V--
+ ******************************************/
+static void ZBA_ssN0_1001_0000_rrrr_ddN0_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_B( RW(dst), RDMEM_B(RW(src)) );
+ RW(dst)--;
+ RW(src)--;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpsdb @rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBA_ssN0_1010_0000_rrrr_ddN0_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPB( RDMEM_B(RW(dst)), RDMEM_B(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(dst)--;
+ RW(src)--;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ cpdrb rbd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBA_ssN0_1100_0000_rrrr_dddd_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPB( RB(dst), RDMEM_B(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(src)--;
+ if (--RW(cnt)) { CLR_V; if (!(FCW & F_Z)) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpsdrb @rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBA_ssN0_1110_0000_rrrr_ddN0_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPB( RDMEM_B(RW(dst)), RDMEM_B(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(dst)--;
+ RW(src)--;
+ if (--RW(cnt)) { CLR_V; if (!(FCW & F_Z)) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpi rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBB_ssN0_0000_0000_rrrr_dddd_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPW( RW(dst), RDMEM_W(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(src) += 2;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ ldi @rd,@rs,rr
+ ldir @rd,@rs,rr
+ flags: ---V--
+ ******************************************/
+static void ZBB_ssN0_0001_0000_rrrr_ddN0_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_W( RW(dst), RDMEM_W(RW(src)) );
+ RW(dst) += 2;
+ RW(src) += 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpsi @rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBB_ssN0_0010_0000_rrrr_ddN0_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPW( RDMEM_W(RW(dst)), RDMEM_W(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(dst) += 2;
+ RW(src) += 2;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ cpir rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBB_ssN0_0100_0000_rrrr_dddd_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPW( RW(dst), RDMEM_W(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(src) += 2;
+ if (--RW(cnt)) { CLR_V; if (!(FCW & F_Z)) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpsir @rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBB_ssN0_0110_0000_rrrr_ddN0_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPW( RDMEM_W(RW(dst)), RDMEM_W(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(dst) += 2;
+ RW(src) += 2;
+ if (--RW(cnt)) { CLR_V; if (!(FCW & F_Z)) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpd rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBB_ssN0_1000_0000_rrrr_dddd_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPW( RW(dst), RDMEM_W(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(src) -= 2;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ ldd @rs,@rd,rr
+ lddr @rs,@rd,rr
+ flags: ---V--
+ ******************************************/
+static void ZBB_ssN0_1001_0000_rrrr_ddN0_x000(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CNT(OP1,NIB1);
+ GET_DST(OP1,NIB2);
+ GET_CCC(OP1,NIB3);
+ WRMEM_W( RW(dst), RDMEM_W(RW(src)) );
+ RW(dst) -= 2;
+ RW(src) -= 2;
+ if (--RW(cnt)) { CLR_V; if (cc == 0) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpsd @rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBB_ssN0_1010_0000_rrrr_ddN0_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPW( RDMEM_W(RW(dst)), RDMEM_W(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(dst) -= 2;
+ RW(src) -= 2;
+ if (--RW(cnt)) CLR_V; else SET_V;
+}
+
+/******************************************
+ cpdr rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBB_ssN0_1100_0000_rrrr_dddd_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPW( RW(dst), RDMEM_W(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(src) -= 2;
+ if (--RW(cnt)) { CLR_V; if (!(FCW & F_Z)) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ cpsdr @rd,@rs,rr,cc
+ flags: CZSV--
+ ******************************************/
+static void ZBB_ssN0_1110_0000_rrrr_ddN0_cccc(void)
+{
+ GET_SRC(OP0,NIB2);
+ GET_CCC(OP1,NIB3);
+ GET_DST(OP1,NIB2);
+ GET_CNT(OP1,NIB1);
+ CPW( RDMEM_W(RW(dst)), RDMEM_W(RW(src)) );
+ switch (cc) {
+ case 0: if (CC0) SET_Z; else CLR_Z; break;
+ case 1: if (CC1) SET_Z; else CLR_Z; break;
+ case 2: if (CC2) SET_Z; else CLR_Z; break;
+ case 3: if (CC3) SET_Z; else CLR_Z; break;
+ case 4: if (CC4) SET_Z; else CLR_Z; break;
+ case 5: if (CC5) SET_Z; else CLR_Z; break;
+ case 6: if (CC6) SET_Z; else CLR_Z; break;
+ case 7: if (CC7) SET_Z; else CLR_Z; break;
+ case 8: if (CC8) SET_Z; else CLR_Z; break;
+ case 9: if (CC9) SET_Z; else CLR_Z; break;
+ case 10: if (CCA) SET_Z; else CLR_Z; break;
+ case 11: if (CCB) SET_Z; else CLR_Z; break;
+ case 12: if (CCC) SET_Z; else CLR_Z; break;
+ case 13: if (CCD) SET_Z; else CLR_Z; break;
+ case 14: if (CCE) SET_Z; else CLR_Z; break;
+ case 15: if (CCF) SET_Z; else CLR_Z; break;
+ }
+ RW(dst) -= 2;
+ RW(src) -= 2;
+ if (--RW(cnt)) { CLR_V; if (!(FCW & F_Z)) PC -= 4; } else SET_V;
+}
+
+/******************************************
+ rrdb rbb,rba
+ flags: -Z----
+ ******************************************/
+static void ZBC_aaaa_bbbb(void)
+{
+ UINT8 b = Z.op[0] & 15;
+ UINT8 a = (Z.op[0] >> 4) & 15;
+ UINT8 tmp = RB(b);
+ RB(a) = (RB(a) >> 4) | (RB(b) << 4);
+ RB(b) = (RB(b) & 0xf0) | (tmp & 0x0f);
+ if (RB(b)) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ ldk rd,imm4
+ flags: ------
+ ******************************************/
+static void ZBD_dddd_imm4(void)
+{
+ GET_DST(OP0,NIB2);
+ GET_IMM4(OP0,NIB3);
+ RW(dst) = imm4;
+}
+
+/******************************************
+ rldb rbb,rba
+ flags: -Z----
+ ******************************************/
+static void ZBE_aaaa_bbbb(void)
+{
+ UINT8 b = Z.op[0] & 15;
+ UINT8 a = (Z.op[0] >> 4) & 15;
+ UINT8 tmp = RB(a);
+ RB(a) = (RB(a) << 4) | (RB(b) & 0x0f);
+ RB(b) = (RB(b) & 0xf0) | (tmp >> 4);
+ if (RB(b)) CLR_Z; else SET_Z;
+}
+
+/******************************************
+ rsvdbf
+ flags: ------
+ ******************************************/
+static void ZBF_imm8(void)
+{
+ GET_IMM8(0);
+ LOG(("Z8K#%d %04x: rsvdbf $%02x\n", cpu_getactivecpu(), PC, imm8));
+ if (FCW & F_EPU) {
+ /* Z8001 EPU code goes here */
+ (void)imm8;
+ }
+ (void)imm8;
+}
+
+/******************************************
+ ldb rbd,imm8
+ flags: ------
+ ******************************************/
+static void ZC_dddd_imm8(void)
+{
+ GET_DST(OP0,NIB1);
+ GET_IMM8(0);
+ RB(dst) = imm8;
+}
+
+/******************************************
+ calr dsp12
+ flags: ------
+ ******************************************/
+static void ZD_dsp12(void)
+{
+ INT16 dsp12 = Z.op[0] & 0xfff;
+ PUSHW( SP, PC );
+ dsp12 = (dsp12 & 2048) ? 4096 -2 * (dsp12 & 2047) : -2 * (dsp12 & 2047);
+ PC += dsp12;
+ change_pc(PC);
+}
+
+/******************************************
+ jr cc,dsp8
+ flags: ------
+ ******************************************/
+static void ZE_cccc_dsp8(void)
+{
+ GET_DSP8;
+ GET_CCC(OP0,NIB1);
+ switch (cc) {
+ case 0: if (CC0) PC += dsp8 * 2; break;
+ case 1: if (CC1) PC += dsp8 * 2; break;
+ case 2: if (CC2) PC += dsp8 * 2; break;
+ case 3: if (CC3) PC += dsp8 * 2; break;
+ case 4: if (CC4) PC += dsp8 * 2; break;
+ case 5: if (CC5) PC += dsp8 * 2; break;
+ case 6: if (CC6) PC += dsp8 * 2; break;
+ case 7: if (CC7) PC += dsp8 * 2; break;
+ case 8: if (CC8) PC += dsp8 * 2; break;
+ case 9: if (CC9) PC += dsp8 * 2; break;
+ case 10: if (CCA) PC += dsp8 * 2; break;
+ case 11: if (CCB) PC += dsp8 * 2; break;
+ case 12: if (CCC) PC += dsp8 * 2; break;
+ case 13: if (CCD) PC += dsp8 * 2; break;
+ case 14: if (CCE) PC += dsp8 * 2; break;
+ case 15: if (CCF) PC += dsp8 * 2; break;
+ }
+ change_pc(PC);
+}
+
+/******************************************
+ dbjnz rbd,dsp7
+ flags: ------
+ ******************************************/
+static void ZF_dddd_0dsp7(void)
+{
+ GET_DST(OP0,NIB1);
+ GET_DSP7;
+ RB(dst) -= 1;
+ if (RB(dst)) {
+ PC = PC - 2 * dsp7;
+ change_pc(PC);
+ }
+}
+
+/******************************************
+ djnz rd,dsp7
+ flags: ------
+ ******************************************/
+static void ZF_dddd_1dsp7(void)
+{
+ GET_DST(OP0,NIB1);
+ GET_DSP7;
+ RW(dst) -= 1;
+ if (RW(dst)) {
+ PC = PC - 2 * dsp7;
+ change_pc(PC);
+ }
+}
+
+
diff --git a/src/emu/cpu/z8000/z8000tbl.c b/src/emu/cpu/z8000/z8000tbl.c
new file mode 100644
index 00000000000..c1a2f0ee3fa
--- /dev/null
+++ b/src/emu/cpu/z8000/z8000tbl.c
@@ -0,0 +1,596 @@
+/*****************************************************************************
+ *
+ * z8000tbl.c
+ * Portable Z8000(2) emulator
+ * Opcode table (including mnemonics) and initialization
+ *
+ * Copyright (c) 1998 Juergen Buchmueller, all rights reserved.
+ * Bug fixes and MSB_FIRST compliance Ernesto Corvi.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+static Z8000_init table[] = {
+{0x0000,0x000f, 1,2, 7,Z00_0000_dddd_imm8, "addb %rb3,%#b3"},
+{0x0010,0x00ff, 1,1, 7,Z00_ssN0_dddd, "addb %rb3,@%rw2"},
+{0x0100,0x010f, 1,2, 7,Z01_0000_dddd_imm16, "add %rw3,%#w1"},
+{0x0110,0x01ff, 1,1, 7,Z01_ssN0_dddd, "add %rw3,@%rw2"},
+{0x0200,0x020f, 1,2, 7,Z02_0000_dddd_imm8, "subb %rb3,%#b3"},
+{0x0210,0x02ff, 1,1, 7,Z02_ssN0_dddd, "subb %rb3,@%rw2"},
+{0x0300,0x030f, 1,2, 7,Z03_0000_dddd_imm16, "sub %rw3,%#w1"},
+{0x0310,0x03ff, 1,1, 7,Z03_ssN0_dddd, "sub %rw3,@%rw2"},
+{0x0400,0x040f, 1,2, 7,Z04_0000_dddd_imm8, "orb %rb3,%#b3"},
+{0x0410,0x04ff, 1,1, 7,Z04_ssN0_dddd, "orb %rb3,@%rw2"},
+{0x0500,0x050f, 1,2, 7,Z05_0000_dddd_imm16, "or %rw3,%#w1"},
+{0x0510,0x05ff, 1,1, 7,Z05_ssN0_dddd, "or %rw3,@%rw2"},
+{0x0600,0x060f, 1,2, 7,Z06_0000_dddd_imm8, "andb %rb3,%#b3"},
+{0x0610,0x06ff, 1,1, 7,Z06_ssN0_dddd, "andb %rb3,@%rw2"},
+{0x0700,0x070f, 1,2, 7,Z07_0000_dddd_imm16, "and %rw3,%#w1"},
+{0x0710,0x07ff, 1,1, 7,Z07_ssN0_dddd, "and %rw3,@%rw2"},
+{0x0800,0x080f, 1,2, 7,Z08_0000_dddd_imm8, "xorb %rb3,%#b3"},
+{0x0810,0x08ff, 1,1, 7,Z08_ssN0_dddd, "xorb %rb3,@%rw2"},
+{0x0900,0x090f, 1,2, 7,Z09_0000_dddd_imm16, "xor %rw3,%#w1"},
+{0x0910,0x09ff, 1,1, 7,Z09_ssN0_dddd, "xor %rw3,@%rw2"},
+{0x0a00,0x0a0f, 1,2, 7,Z0A_0000_dddd_imm8, "cpb %rb3,%#b3"},
+{0x0a10,0x0aff, 1,1, 7,Z0A_ssN0_dddd, "cpb %rb3,@%rw2"},
+{0x0b00,0x0b0f, 1,2, 7,Z0B_0000_dddd_imm16, "cp %rw3,%#w1"},
+{0x0b10,0x0bff, 1,1, 7,Z0B_ssN0_dddd, "cp %rw3,@%rw2"},
+{0x0c10,0x0cf0,16,1, 12,Z0C_ddN0_0000, "comb @%rw2"},
+{0x0c11,0x0cf1,16,2, 11,Z0C_ddN0_0001_imm8, "cpb @%rw2,%#b3"},
+{0x0c12,0x0cf2,16,1, 12,Z0C_ddN0_0010, "negb @%rw2"},
+{0x0c14,0x0cf4,16,1, 8,Z0C_ddN0_0100, "testb @%rw2"},
+{0x0c15,0x0cf5,16,2, 7,Z0C_ddN0_0101_imm8, "ldb @%rw2,%#b3"},
+{0x0c16,0x0cf6,16,1, 11,Z0C_ddN0_0110, "tsetb @%rw2"},
+{0x0c18,0x0cf8,16,1, 8,Z0C_ddN0_1000, "clrb @%rw2"},
+{0x0d10,0x0df0,16,1, 12,Z0D_ddN0_0000, "com @%rw2"},
+{0x0d11,0x0df1,16,2, 11,Z0D_ddN0_0001_imm16, "cp @%rw2,%#w1"},
+{0x0d12,0x0df2,16,1, 12,Z0D_ddN0_0010, "neg @%rw2"},
+{0x0d14,0x0df4,16,1, 8,Z0D_ddN0_0100, "test @%rw2"},
+{0x0d15,0x0df5,16,2, 11,Z0D_ddN0_0101_imm16, "ld @%rw2,%#w1"}, /* fix cycles ld IR,IM */
+{0x0d16,0x0df6,16,1, 11,Z0D_ddN0_0110, "tset @%rw2"},
+{0x0d18,0x0df8,16,1, 8,Z0D_ddN0_1000, "clr @%rw2"},
+{0x0d19,0x0df9,16,2, 12,Z0D_ddN0_1001_imm16, "push @%rw2,%#w1"},
+{0x0e00,0x0eff, 1,1, 10,Z0E_imm8, "ext0e %#b1"},
+{0x0f00,0x0fff, 1,1, 10,Z0F_imm8, "ext0f %#b1"},
+{0x1000,0x100f, 1,3, 14,Z10_0000_dddd_imm32, "cpl %rl3,%#l1"},
+{0x1010,0x10ff, 1,1, 14,Z10_ssN0_dddd, "cpl %rl3,@%rw2"},
+{0x1111,0x11ff, 1,1, 20,Z11_ddN0_ssN0, "pushl @%rw2,@%rw3"},
+{0x1200,0x120f, 1,3, 14,Z12_0000_dddd_imm32, "subl %rl3,%#l1"},
+{0x1210,0x12ff, 1,1, 14,Z12_ssN0_dddd, "subl %rl3,@%rw2"},
+{0x1311,0x13ff, 1,1, 13,Z13_ddN0_ssN0, "push @%rw2,@%rw3"},
+{0x1400,0x140f, 1,3, 11,Z14_0000_dddd_imm32, "ldl %rl3,%#l1"},
+{0x1410,0x14ff, 1,1, 11,Z14_ssN0_dddd, "ldl %rl3,@%rw2"},
+{0x1511,0x15ff, 1,1, 19,Z15_ssN0_ddN0, "popl @%rw3,@%rw2"},
+{0x1600,0x160f, 1,3, 14,Z16_0000_dddd_imm32, "addl %rl3,%#l1"},
+{0x1610,0x16ff, 1,1, 14,Z16_ssN0_dddd, "addl %rl3,@%rw2"},
+{0x1711,0x17ff, 1,1, 12,Z17_ssN0_ddN0, "pop @%rw3,@%rw2"},
+{0x1810,0x18ff, 1,1,282,Z18_ssN0_dddd, "multl %rq3,@%rw2"},
+{0x1900,0x190f, 1,2, 70,Z19_0000_dddd_imm16, "mult %rl3,%#w1"},
+{0x1910,0x19ff, 1,1, 70,Z19_ssN0_dddd, "mult %rl3,@%rw2"},
+{0x1a00,0x1a0f, 1,3,744,Z1A_0000_dddd_imm32, "divl %rq3,%#l1"},
+{0x1a10,0x1aff, 1,1,744,Z1A_ssN0_dddd, "divl %rq3,@%rw2"},
+{0x1b00,0x1b0f, 1,2,107,Z1B_0000_dddd_imm16, "div %rl3,%#w1"},
+{0x1b10,0x1bff, 1,1,107,Z1B_ssN0_dddd, "div %rl3,@%rw2"},
+{0x1c11,0x1cf1,16,2, 11,Z1C_ssN0_0001_0000_dddd_0000_nmin1, "ldm %rw5,@%rw2,n"},
+{0x1c18,0x1cf8,16,1, 13,Z1C_ddN0_1000, "testl @%rw2"},
+{0x1c19,0x1cf9,16,2, 11,Z1C_ddN0_1001_0000_ssss_0000_nmin1, "ldm @%rw2,%rw5,n"},
+{0x1d10,0x1dff, 1,1, 11,Z1D_ddN0_ssss, "ldl @%rw2,%rl3"},
+{0x1e10,0x1eff, 1,1, 10,Z1E_ddN0_cccc, "jp %c3,%rw2"},
+{0x1f10,0x1ff0,16,1, 10,Z1F_ddN0_0000, "call %rw2", DASMFLAG_STEP_OVER},
+{0x2010,0x20ff, 1,1, 7,Z20_ssN0_dddd, "ldb %rb3,@%rw2"},
+{0x2100,0x210f, 1,2, 7,Z21_0000_dddd_imm16, "ld %rw3,%#w1"},
+{0x2110,0x21ff, 1,1, 7,Z21_ssN0_dddd, "ld %rw3,@%rw2"},
+{0x2200,0x220f, 1,2, 10,Z22_0000_ssss_0000_dddd_0000_0000, "resb %rb5,%rw3"},
+{0x2210,0x22ff, 1,1, 11,Z22_ddN0_imm4, "resb @%rw3,%3"},
+{0x2300,0x230f, 1,2, 10,Z23_0000_ssss_0000_dddd_0000_0000, "res %rw5,%rw3"},
+{0x2310,0x23ff, 1,1, 11,Z23_ddN0_imm4, "res @%rw3,%3"},
+{0x2400,0x240f, 1,2, 10,Z24_0000_ssss_0000_dddd_0000_0000, "setb %rb5,%rw3"},
+{0x2410,0x24ff, 1,1, 11,Z24_ddN0_imm4, "setb @%rw3,%3"},
+{0x2500,0x250f, 1,2, 10,Z25_0000_ssss_0000_dddd_0000_0000, "set %rw5,%rw3"},
+{0x2510,0x25ff, 1,1, 11,Z25_ddN0_imm4, "set @%rw3,%3"},
+{0x2600,0x260f, 1,2, 10,Z26_0000_ssss_0000_dddd_0000_0000, "bitb %rb5,%rw3"},
+{0x2610,0x26ff, 1,1, 8,Z26_ddN0_imm4, "bitb @%rw3,%3"},
+{0x2700,0x270f, 1,2, 10,Z27_0000_ssss_0000_dddd_0000_0000, "bit %rw5,%rw3"},
+{0x2710,0x27ff, 1,1, 8,Z27_ddN0_imm4, "bit @%rw2,%3"},
+{0x2810,0x28ff, 1,1, 11,Z28_ddN0_imm4m1, "incb @%rw2,%+3"},
+{0x2910,0x29ff, 1,1, 11,Z29_ddN0_imm4m1, "inc @%rw2,%+3"},
+{0x2a10,0x2aff, 1,1, 11,Z2A_ddN0_imm4m1, "decb @%rw2,%+3"},
+{0x2b10,0x2bff, 1,1, 11,Z2B_ddN0_imm4m1, "dec @%rw2,%+3"},
+{0x2c10,0x2cff, 1,1, 12,Z2C_ssN0_dddd, "exb %rb3,@%rw2"},
+{0x2d10,0x2dff, 1,1, 12,Z2D_ssN0_dddd, "ex %rw3,@%rw2"},
+{0x2e10,0x2eff, 1,1, 8,Z2E_ddN0_ssss, "ldb @%rw2,%rb3"},
+{0x2f10,0x2fff, 1,1, 8,Z2F_ddN0_ssss, "ld @%rw2,%rw3"},
+{0x3000,0x300f, 1,2, 14,Z30_0000_dddd_dsp16, "ldrb %rb3,%p1"},
+{0x3010,0x30ff, 1,2, 14,Z30_ssN0_dddd_imm16, "ldb %rb3,%rw2(%#w1)"},
+{0x3100,0x310f, 1,2, 14,Z31_0000_dddd_dsp16, "ldr %rw3,%p1"},
+{0x3110,0x31ff, 1,2, 14,Z31_ssN0_dddd_imm16, "ld %rw3,%rw2(%#w1)"},
+{0x3200,0x320f, 1,2, 14,Z32_0000_ssss_dsp16, "ldrb %p1,%rb3"},
+{0x3210,0x32ff, 1,2, 14,Z32_ddN0_ssss_imm16, "ldb %rw2(%#w1),%rb3"},
+{0x3300,0x330f, 1,2, 14,Z33_0000_ssss_dsp16, "ldr %p1,%rw3"},
+{0x3310,0x33ff, 1,2, 14,Z33_ddN0_ssss_imm16, "ld %rw2(%#w1),%rw3"},
+{0x3400,0x340f, 1,2, 15,Z34_0000_dddd_dsp16, "ldar p%rw3,%p1"},
+{0x3410,0x34ff, 1,2, 15,Z34_ssN0_dddd_imm16, "lda p%rw3,%rw2(%#w1)"},
+{0x3500,0x350f, 1,2, 17,Z35_0000_dddd_dsp16, "ldrl %rl3,%p1"},
+{0x3510,0x35ff, 1,2, 17,Z35_ssN0_dddd_imm16, "ldl %rl3,%rw2(%#w1)"},
+{0x3600,0x3600, 1,1, 2,Z36_0000_0000, "bpt"},
+{0x3601,0x36ff, 1,1, 10,Z36_imm8, "rsvd36"},
+{0x3700,0x370f, 1,2, 17,Z37_0000_ssss_dsp16, "ldrl %p1,%rl3"},
+{0x3710,0x37ff, 1,2, 17,Z37_ddN0_ssss_imm16, "ldl %rw2(%#w1),%rl3"},
+{0x3800,0x38ff, 1,1, 10,Z38_imm8, "rsvd38"},
+{0x3910,0x39f0,16,1, 12,Z39_ssN0_0000, "ldps @%rw2"},
+{0x3a00,0x3af0,16,2, 21,Z3A_ssss_0000_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3a01,0x3af1,16,2, 21,Z3A_ssss_0001_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3a02,0x3af2,16,2, 21,Z3A_ssss_0010_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3a03,0x3af3,16,2, 21,Z3A_ssss_0011_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3a04,0x3af4,16,2, 10,Z3A_dddd_0100_imm16, "%R %rb2,%#w1"},
+{0x3a05,0x3af5,16,2, 10,Z3A_dddd_0101_imm16, "%R %rb2,%#w1"},
+{0x3a06,0x3af6,16,2, 12,Z3A_ssss_0110_imm16, "%R %#w1,%rb2"},
+{0x3a07,0x3af7,16,2, 12,Z3A_ssss_0111_imm16, "%R %#w1,%rb2"},
+{0x3a08,0x3af8,16,2, 21,Z3A_ssss_1000_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3a09,0x3af9,16,2, 21,Z3A_ssss_1001_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3a0a,0x3afa,16,2, 21,Z3A_ssss_1010_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3a0b,0x3afb,16,2, 21,Z3A_ssss_1011_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3b00,0x3bf0,16,2, 21,Z3B_ssss_0000_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3b01,0x3bf1,16,2, 21,Z3B_ssss_0001_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3b02,0x3bf2,16,2, 21,Z3B_ssss_0010_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3b03,0x3bf3,16,2, 21,Z3B_ssss_0011_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3b04,0x3bf4,16,2, 12,Z3B_dddd_0100_imm16, "%R %rw2,%#w1"},
+{0x3b05,0x3bf5,16,2, 12,Z3B_dddd_0101_imm16, "%R %rw2,%#w1"},
+{0x3b06,0x3bf6,16,2, 12,Z3B_ssss_0110_imm16, "%R %#w1,%rw2"},
+{0x3b07,0x3bf7,16,2, 12,Z3B_ssss_0111_imm16, "%R %#w1,%rw2"},
+{0x3b08,0x3bf8,16,2, 21,Z3B_ssss_1000_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3b09,0x3bf9,16,2, 21,Z3B_ssss_1001_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5"},
+{0x3b0a,0x3bfa,16,2, 21,Z3B_ssss_1010_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rb5"},
+{0x3b0b,0x3bfb,16,2, 21,Z3B_ssss_1011_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rb5"},
+{0x3c00,0x3cff, 1,1, 10,Z3C_ssss_dddd, "inb %rb3,@%rw2"},
+{0x3d00,0x3dff, 1,1, 10,Z3D_ssss_dddd, "in %rw3,@%rw2"},
+{0x3e00,0x3eff, 1,1, 12,Z3E_dddd_ssss, "outb @%rw2,%rb3"},
+{0x3f00,0x3fff, 1,1, 12,Z3F_dddd_ssss, "out @%rw2,%rw3"},
+{0x4000,0x400f, 1,2, 9,Z40_0000_dddd_addr, "addb %rb3,%a1"},
+{0x4010,0x40ff, 1,2, 10,Z40_ssN0_dddd_addr, "addb %rb3,%a1(%rw2)"},
+{0x4100,0x410f, 1,2, 9,Z41_0000_dddd_addr, "add %rw3,%a1"},
+{0x4110,0x41ff, 1,2, 10,Z41_ssN0_dddd_addr, "add %rw3,%a1(%rw2)"},
+{0x4200,0x420f, 1,2, 9,Z42_0000_dddd_addr, "subb %rb3,%a1"},
+{0x4210,0x42ff, 1,2, 10,Z42_ssN0_dddd_addr, "subb %rb3,%a1(%rw2)"},
+{0x4300,0x430f, 1,2, 9,Z43_0000_dddd_addr, "sub %rw3,%a1"},
+{0x4310,0x43ff, 1,2, 10,Z43_ssN0_dddd_addr, "sub %rw3,%a1(%rw2)"},
+{0x4400,0x440f, 1,2, 9,Z44_0000_dddd_addr, "orb %rb3,%a1"},
+{0x4410,0x44ff, 1,2, 10,Z44_ssN0_dddd_addr, "orb %rb3,%a1(%rw2)"},
+{0x4500,0x450f, 1,2, 9,Z45_0000_dddd_addr, "or %rw3,%a1"},
+{0x4510,0x45ff, 1,2, 10,Z45_ssN0_dddd_addr, "or %rw3,%a1(%rw2)"},
+{0x4600,0x460f, 1,2, 9,Z46_0000_dddd_addr, "andb %rb3,%a1"},
+{0x4610,0x46ff, 1,2, 10,Z46_ssN0_dddd_addr, "andb %rb3,%a1(%rw2)"},
+{0x4700,0x470f, 1,2, 9,Z47_0000_dddd_addr, "and %rw3,%a1"},
+{0x4710,0x47ff, 1,2, 10,Z47_ssN0_dddd_addr, "and %rw3,%a1(%rw2)"},
+{0x4800,0x480f, 1,2, 9,Z48_0000_dddd_addr, "xorb %rb3,%a1"},
+{0x4810,0x48ff, 1,2, 10,Z48_ssN0_dddd_addr, "xorb %rb3,%a1(%rw2)"},
+{0x4900,0x490f, 1,2, 9,Z49_0000_dddd_addr, "xor %rw3,%a1"},
+{0x4910,0x49ff, 1,2, 10,Z49_ssN0_dddd_addr, "xor %rw3,%a1(%rw2)"},
+{0x4a00,0x4a0f, 1,2, 9,Z4A_0000_dddd_addr, "cpb %rb3,%a1"},
+{0x4a10,0x4aff, 1,2, 10,Z4A_ssN0_dddd_addr, "cpb %rb3,%a1(%rw2)"},
+{0x4b00,0x4b0f, 1,2, 9,Z4B_0000_dddd_addr, "cp %rw3,%a1"},
+{0x4b10,0x4bff, 1,2, 10,Z4B_ssN0_dddd_addr, "cp %rw3,%a1(%rw2)"},
+{0x4c00,0x4c00, 1,2, 15,Z4C_0000_0000_addr, "comb %a1"},
+{0x4c01,0x4c01, 1,3, 14,Z4C_0000_0001_addr_imm8, "cpb %a1,%#b3"},
+{0x4c02,0x4c02, 1,2, 15,Z4C_0000_0010_addr, "negb %a1"},
+{0x4c04,0x4c04, 1,2, 11,Z4C_0000_0100_addr, "testb %a1"},
+{0x4c05,0x4c05, 1,3, 14,Z4C_0000_0101_addr_imm8, "ldb %a1,%#b3"},
+{0x4c06,0x4c06, 1,2, 14,Z4C_0000_0110_addr, "tsetb %a1"},
+{0x4c08,0x4c08, 1,2, 11,Z4C_0000_1000_addr, "clrb %a1"},
+{0x4c10,0x4cf0,16,2, 16,Z4C_ddN0_0000_addr, "comb %a1(%rw2)"},
+{0x4c11,0x4cf1,16,3, 15,Z4C_ddN0_0001_addr_imm8, "cpb %a1(%rw2),%#b3"},
+{0x4c12,0x4cf2,16,2, 16,Z4C_ddN0_0010_addr, "negb %a1(%rw2)"},
+{0x4c14,0x4cf4,16,2, 12,Z4C_ddN0_0100_addr, "testb %a1(%rw2)"},
+{0x4c15,0x4cf5,16,3, 15,Z4C_ddN0_0101_addr_imm8, "ldb %a1(%rw2),%#b3"},
+{0x4c16,0x4cf6,16,2, 15,Z4C_ddN0_0110_addr, "tsetb %a1(%rw2)"},
+{0x4c18,0x4cf8,16,2, 12,Z4C_ddN0_1000_addr, "clrb %a1(%rw2)"},
+{0x4d00,0x4d00, 1,2, 15,Z4D_0000_0000_addr, "com %a1"},
+{0x4d01,0x4d01, 1,3, 14,Z4D_0000_0001_addr_imm16, "cp %a1,%#w2"},
+{0x4d02,0x4d02, 1,2, 15,Z4D_0000_0010_addr, "neg %a1"},
+{0x4d04,0x4d04, 1,2, 11,Z4D_0000_0100_addr, "test %a1"},
+{0x4d05,0x4d05, 1,3, 14,Z4D_0000_0101_addr_imm16, "ld %a1,%#w2"},
+{0x4d06,0x4d06, 1,2, 14,Z4D_0000_0110_addr, "tset %a1"},
+{0x4d08,0x4d08, 1,2, 11,Z4D_0000_1000_addr, "clr %a1"},
+{0x4d10,0x4df0,16,2, 16,Z4D_ddN0_0000_addr, "com %a1(%rw2)"},
+{0x4d11,0x4df1,16,3, 15,Z4D_ddN0_0001_addr_imm16, "cp %a1(%rw2),%#w2"},
+{0x4d12,0x4df2,16,2, 16,Z4D_ddN0_0010_addr, "neg %a1(%rw2)"},
+{0x4d14,0x4df4,16,2, 12,Z4D_ddN0_0100_addr, "test %a1(%rw2)"},
+{0x4d15,0x4df5,16,3, 15,Z4D_ddN0_0101_addr_imm16, "ld %a1(%rw2),%#w2"},
+{0x4d16,0x4df6,16,2, 15,Z4D_ddN0_0110_addr, "tset %a1(%rw2)"},
+{0x4d18,0x4df8,16,2, 12,Z4D_ddN0_1000_addr, "clr %a1(%rw2)"},
+{0x4e11,0x4ef0,16,2, 12,Z4E_ddN0_ssN0_addr, "ldb %a1(%rw2),%rb3"},
+{0x5000,0x500f, 1,2, 15,Z50_0000_dddd_addr, "cpl %rl3,%a1"},
+{0x5010,0x50ff, 1,2, 16,Z50_ssN0_dddd_addr, "cpl %rl3,%a1(%rw2)"},
+{0x5110,0x51f0,16,2, 21,Z51_ddN0_0000_addr, "pushl @%rw2,%a1"},
+{0x5111,0x51f1,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x5112,0x51f2,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x5113,0x51f3,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x5114,0x51f4,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x5115,0x51f5,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x5116,0x51f6,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x5117,0x51f7,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x5118,0x51f8,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x5119,0x51f9,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x511a,0x51fa,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x511b,0x51fb,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x511c,0x51fc,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x511d,0x51fd,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x511e,0x51fe,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x511f,0x51ff,16,2, 21,Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)"},
+{0x5200,0x520f, 1,2, 15,Z52_0000_dddd_addr, "subl %rl3,%a1"},
+{0x5210,0x52ff, 1,2, 16,Z52_ssN0_dddd_addr, "subl %rl3,%a1(%rw2)"},
+{0x5310,0x53f0,16,2, 14,Z53_ddN0_0000_addr, "push @%rw2,%a1"},
+{0x5311,0x53f1,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x5312,0x53f2,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x5313,0x53f3,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x5314,0x53f4,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x5315,0x53f5,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x5316,0x53f6,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x5317,0x53f7,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x5318,0x53f8,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x5319,0x53f9,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x531a,0x53fa,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x531b,0x53fb,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x531c,0x53fc,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x531d,0x53fd,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x531e,0x53fe,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x531f,0x53ff,16,2, 14,Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)"},
+{0x5400,0x540f, 1,2, 12,Z54_0000_dddd_addr, "ldl %rl3,%a1"},
+{0x5410,0x54ff, 1,2, 13,Z54_ssN0_dddd_addr, "ldl %rl3,%a1(%rw2)"},
+{0x5510,0x55f0,16,2, 23,Z55_ssN0_0000_addr, "popl %a1,@%rw2"},
+{0x5511,0x55f1,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x5512,0x55f2,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x5513,0x55f3,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x5514,0x55f4,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x5515,0x55f5,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x5516,0x55f6,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x5517,0x55f7,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x5518,0x55f8,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x5519,0x55f9,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x551a,0x55fa,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x551b,0x55fb,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x551c,0x55fc,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x551d,0x55fd,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x551e,0x55fe,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x551f,0x55ff,16,2, 23,Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2"},
+{0x5600,0x560f, 1,2, 15,Z56_0000_dddd_addr, "addl %rl3,%a1"},
+{0x5610,0x56ff, 1,2, 16,Z56_ssN0_dddd_addr, "addl %rl3,%a1(%rw2)"},
+{0x5710,0x57f0,16,2, 16,Z57_ssN0_0000_addr, "pop %a1,@%rw2"},
+{0x5711,0x57f1,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x5712,0x57f2,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x5713,0x57f3,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x5714,0x57f4,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x5715,0x57f5,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x5716,0x57f6,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x5717,0x57f7,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x5718,0x57f8,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x5719,0x57f9,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x571a,0x57fa,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x571b,0x57fb,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x571c,0x57fc,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x571d,0x57fd,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x571e,0x57fe,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x571f,0x57ff,16,2, 16,Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2"},
+{0x5800,0x580f, 1,2,283,Z58_0000_dddd_addr, "multl %rq3,%a1"},
+{0x5810,0x58ff, 1,2,284,Z58_ssN0_dddd_addr, "multl %rq3,%a1(%rw2)"},
+{0x5900,0x590f, 1,2, 71,Z59_0000_dddd_addr, "mult %rl3,%a1"},
+{0x5910,0x59ff, 1,2, 72,Z59_ssN0_dddd_addr, "mult %rl3,%a1(%rw2)"},
+{0x5a00,0x5a0f, 1,2,745,Z5A_0000_dddd_addr, "divl %rq3,%a1"},
+{0x5a10,0x5aff, 1,2,746,Z5A_ssN0_dddd_addr, "divl %rq3,%a1(%rw2)"},
+{0x5b00,0x5b0f, 1,2,108,Z5B_0000_dddd_addr, "div %rl3,%a1"},
+{0x5b10,0x5bff, 1,2,109,Z5B_ssN0_dddd_addr, "div %rl3,%a1(%rw2)"},
+{0x5c01,0x5c01, 1,3, 14,Z5C_0000_0001_0000_dddd_0000_nmin1_addr, "ldm %rw5,%a2,n"},
+{0x5c08,0x5c08, 1,2, 16,Z5C_0000_1000_addr, "testl %a1"},
+{0x5c09,0x5c09, 1,3, 14,Z5C_0000_1001_0000_ssss_0000_nmin1_addr, "ldm %a2,%rw5,n"},
+{0x5c11,0x5cf1,16,3, 15,Z5C_ssN0_0001_0000_dddd_0000_nmin1_addr, "ldm %rw5,%a2(%rw2),n"},
+{0x5c18,0x5cf8,16,2, 17,Z5C_ddN0_1000_addr, "testl %a1(%rw2)"},
+{0x5c19,0x5cf9,16,3, 15,Z5C_ddN0_1001_0000_ssN0_0000_nmin1_addr, "ldm %a2(%rw2),%rw5,n"},
+{0x5d00,0x5d0f, 1,2, 15,Z5D_0000_ssss_addr, "ldl %a1,%rl3"},
+{0x5d10,0x5dff, 1,2, 14,Z5D_ddN0_ssss_addr, "ldl %a1(%rw2),%rl3"},
+{0x5e00,0x5e0f, 1,2, 7,Z5E_0000_cccc_addr, "jp %c3,%a1"},
+{0x5e10,0x5eff, 1,2, 8,Z5E_ddN0_cccc_addr, "jp %c3,%a1(%rw2)"},
+{0x5f00,0x5f00, 1,2, 12,Z5F_0000_0000_addr, "call %a1", DASMFLAG_STEP_OVER},
+{0x5f10,0x5ff0,16,2, 13,Z5F_ddN0_0000_addr, "call %a1(%rw2)", DASMFLAG_STEP_OVER},
+{0x6000,0x600f, 1,2, 9,Z60_0000_dddd_addr, "ldb %rb3,%a1"},
+{0x6010,0x60ff, 1,2, 10,Z60_ssN0_dddd_addr, "ldb %rb3,%a1(%rw2)"},
+{0x6100,0x610f, 1,2, 9,Z61_0000_dddd_addr, "ld %rw3,%a1"},
+{0x6110,0x61ff, 1,2, 10,Z61_ssN0_dddd_addr, "ld %rw3,%a1(%rw2)"},
+{0x6200,0x620f, 1,2, 13,Z62_0000_imm4_addr, "resb %a1,%3"},
+{0x6210,0x62ff, 1,2, 14,Z62_ddN0_imm4_addr, "resb %a1(%rw2),%3"},
+{0x6300,0x630f, 1,2, 13,Z63_0000_imm4_addr, "res %a1,%3"},
+{0x6310,0x63ff, 1,2, 14,Z63_ddN0_imm4_addr, "res %a1(%rw2),%3"},
+{0x6400,0x640f, 1,2, 13,Z64_0000_imm4_addr, "setb %a1,%3"},
+{0x6410,0x64ff, 1,2, 14,Z64_ddN0_imm4_addr, "setb %a1(%rw2),%3"},
+{0x6500,0x650f, 1,2, 13,Z65_0000_imm4_addr, "set %a1,%3"},
+{0x6510,0x65ff, 1,2, 14,Z65_ddN0_imm4_addr, "set %a1(%rw2),%3"},
+{0x6600,0x660f, 1,2, 10,Z66_0000_imm4_addr, "bitb %a1,%3"},
+{0x6610,0x66ff, 1,2, 11,Z66_ddN0_imm4_addr, "bitb %a1(%rw2),%3"},
+{0x6700,0x670f, 1,2, 10,Z67_0000_imm4_addr, "bit %a1,%3"},
+{0x6710,0x67ff, 1,2, 11,Z67_ddN0_imm4_addr, "bit %a1(%rw2),%3"},
+{0x6800,0x680f, 1,2, 13,Z68_0000_imm4m1_addr, "incb %a1,%+3"},
+{0x6810,0x68ff, 1,2, 14,Z68_ddN0_imm4m1_addr, "incb %a1(%rw2),%+3"},
+{0x6900,0x690f, 1,2, 13,Z69_0000_imm4m1_addr, "inc %a1,%+3"},
+{0x6910,0x69ff, 1,2, 14,Z69_ddN0_imm4m1_addr, "inc %a1(%rw2),%+3"},
+{0x6a00,0x6a0f, 1,2, 13,Z6A_0000_imm4m1_addr, "decb %a1,%+3"},
+{0x6a10,0x6aff, 1,2, 14,Z6A_ddN0_imm4m1_addr, "decb %a1(%rw2),%+3"},
+{0x6b00,0x6b0f, 1,2, 13,Z6B_0000_imm4m1_addr, "dec %a1,%+3"},
+{0x6b10,0x6bff, 1,2, 14,Z6B_ddN0_imm4m1_addr, "dec %a1(%rw2),%+3"},
+{0x6c00,0x6c0f, 1,2, 15,Z6C_0000_dddd_addr, "exb %rb3,%a1"},
+{0x6c10,0x6cff, 1,2, 16,Z6C_ssN0_dddd_addr, "exb %rb3,%a1(%rw2)"},
+{0x6d00,0x6d0f, 1,2, 15,Z6D_0000_dddd_addr, "ex %rw3,%a1"},
+{0x6d10,0x6dff, 1,2, 16,Z6D_ssN0_dddd_addr, "ex %rw3,%a1(%rw2)"},
+{0x6e00,0x6e0f, 1,2, 11,Z6E_0000_ssss_addr, "ldb %a1,%rb3"},
+{0x6e10,0x6eff, 1,2, 11,Z6E_ddN0_ssss_addr, "ldb %a1(%rw2),%rb3"},
+{0x6f00,0x6f0f, 1,2, 11,Z6F_0000_ssss_addr, "ld %a1,%rw3"},
+{0x6f10,0x6fff, 1,2, 12,Z6F_ddN0_ssss_addr, "ld %a1(%rw2),%rw3"},
+{0x7010,0x70ff, 1,2, 14,Z70_ssN0_dddd_0000_xxxx_0000_0000, "ldb %rb3,%rw2(%rw5)"},
+{0x7110,0x71ff, 1,2, 14,Z71_ssN0_dddd_0000_xxxx_0000_0000, "ld %rw3,%rw2(%rw5)"},
+{0x7210,0x72ff, 1,2, 14,Z72_ddN0_ssss_0000_xxxx_0000_0000, "ldb %rw2(%rw5),%rb3"},
+{0x7310,0x73ff, 1,2, 14,Z73_ddN0_ssss_0000_xxxx_0000_0000, "ld %rw2(%rw5),%rw3"},
+{0x7410,0x74ff, 1,2, 15,Z74_ssN0_dddd_0000_xxxx_0000_0000, "lda p%rw3,%rw2(%rw5)"},
+{0x7510,0x75ff, 1,2, 17,Z75_ssN0_dddd_0000_xxxx_0000_0000, "ldl %rl3,%rw2(%rw5)"},
+{0x7600,0x760f, 1,2, 12,Z76_0000_dddd_addr, "lda p%rw3,%a1"},
+{0x7610,0x76ff, 1,2, 13,Z76_ssN0_dddd_addr, "lda p%rw3,%a1(%rw2)"},
+{0x7710,0x77ff, 1,2, 17,Z77_ddN0_ssss_0000_xxxx_0000_0000, "ldl %rw2(%rw5),%rl3"},
+{0x7800,0x78ff, 1,1, 10,Z78_imm8, "rsvd78"},
+{0x7900,0x7900, 1,2, 16,Z79_0000_0000_addr, "ldps %a1"},
+{0x7910,0x79f0,16,2, 17,Z79_ssN0_0000_addr, "ldps %a1(%rw2)"},
+{0x7a00,0x7a00, 1,1, 8,Z7A_0000_0000, "halt", DASMFLAG_STEP_OVER},
+{0x7b00,0x7b00, 1,1, 13,Z7B_0000_0000, "iret", DASMFLAG_STEP_OUT},
+{0x7b08,0x7b08, 1,1, 5,Z7B_0000_1000, "mset"},
+{0x7b09,0x7b09, 1,1, 5,Z7B_0000_1001, "mres"},
+{0x7b0a,0x7b0a, 1,1, 7,Z7B_0000_1010, "mbit"},
+{0x7b0d,0x7bfd,16,1, 12,Z7B_dddd_1101, "mreq %rw2"},
+{0x7c00,0x7c03, 1,1, 7,Z7C_0000_00ii, "di %i3"},
+{0x7c04,0x7c07, 1,1, 7,Z7C_0000_01ii, "ei %i3"},
+{0x7d00,0x7df0,16,1, 7,Z7D_dddd_0ccc, "ldctl %rw2,ctrl0"},
+{0x7d01,0x7df1,16,1, 7,Z7D_dddd_0ccc, "ldctl %rw2,ctrl1"},
+{0x7d02,0x7df2,16,1, 7,Z7D_dddd_0ccc, "ldctl %rw2,fcw"},
+{0x7d03,0x7df3,16,1, 7,Z7D_dddd_0ccc, "ldctl %rw2,refresh"},
+{0x7d04,0x7df4,16,1, 7,Z7D_dddd_0ccc, "ldctl %rw2,ctrl4"},
+{0x7d05,0x7df5,16,1, 7,Z7D_dddd_0ccc, "ldctl %rw2,psap"},
+{0x7d06,0x7df6,16,1, 7,Z7D_dddd_0ccc, "ldctl %rw2,ctrl6"},
+{0x7d07,0x7df7,16,1, 7,Z7D_dddd_0ccc, "ldctl %rw2,nsp"},
+{0x7d08,0x7df8,16,1, 7,Z7D_ssss_1ccc, "ldctl ctrl0,%rw2"},
+{0x7d09,0x7df9,16,1, 7,Z7D_ssss_1ccc, "ldctl ctrl1,%rw2"},
+{0x7d0a,0x7dfa,16,1, 7,Z7D_ssss_1ccc, "ldctl fcw,%rw2"},
+{0x7d0b,0x7dfb,16,1, 7,Z7D_ssss_1ccc, "ldctl refresh,%rw2"},
+{0x7d0c,0x7dfc,16,1, 7,Z7D_ssss_1ccc, "ldctl ctrl4,%rw2"},
+{0x7d0d,0x7dfd,16,1, 7,Z7D_ssss_1ccc, "ldctl psap,%rw2"},
+{0x7d0e,0x7dfe,16,1, 7,Z7D_ssss_1ccc, "ldctl ctrl6,%rw2"},
+{0x7d0f,0x7dff,16,1, 7,Z7D_ssss_1ccc, "ldctl nsp,%rw2"},
+{0x7e00,0x7eff, 1,1, 10,Z7E_imm8, "rsvd7e %#b1"},
+{0x7f00,0x7fff, 1,1, 33,Z7F_imm8, "sc %#b1"},
+{0x8000,0x80ff, 1,1, 4,Z80_ssss_dddd, "addb %rb3,%rb2"},
+{0x8100,0x81ff, 1,1, 4,Z81_ssss_dddd, "add %rw3,%rw2"},
+{0x8200,0x82ff, 1,1, 4,Z82_ssss_dddd, "subb %rb3,%rb2"},
+{0x8300,0x83ff, 1,1, 4,Z83_ssss_dddd, "sub %rw3,%rw2"},
+{0x8400,0x84ff, 1,1, 4,Z84_ssss_dddd, "orb %rb3,%rb2"},
+{0x8500,0x85ff, 1,1, 4,Z85_ssss_dddd, "or %rw3,%rw2"},
+{0x8600,0x86ff, 1,1, 4,Z86_ssss_dddd, "andb %rb3,%rb2"},
+{0x8700,0x87ff, 1,1, 4,Z87_ssss_dddd, "and %rw3,%rw2"},
+{0x8800,0x88ff, 1,1, 4,Z88_ssss_dddd, "xorb %rb3,%rb2"},
+{0x8900,0x89ff, 1,1, 4,Z89_ssss_dddd, "xor %rw3,%rw2"},
+{0x8a00,0x8aff, 1,1, 4,Z8A_ssss_dddd, "cpb %rb3,%rb2"},
+{0x8b00,0x8bff, 1,1, 4,Z8B_ssss_dddd, "cp %rw3,%rw2"},
+{0x8c00,0x8cf0,16,1, 7,Z8C_dddd_0000, "comb %rb2"},
+{0x8c02,0x8cf2,16,1, 7,Z8C_dddd_0010, "negb %rb2"},
+{0x8c04,0x8cf4,16,1, 7,Z8C_dddd_0100, "testb %rb2"},
+{0x8c06,0x8cf6,16,1, 7,Z8C_dddd_0110, "tsetb %rb2"},
+{0x8c08,0x8cf8,16,1, 7,Z8C_dddd_1000, "clrb %rb2"},
+{0x8d00,0x8df0,16,1, 7,Z8D_dddd_0000, "com %rw2"},
+{0x8d01,0x8df1,16,1, 7,Z8D_imm4_0001, "setflg %f2"},
+{0x8d02,0x8df2,16,1, 7,Z8D_dddd_0010, "neg %rw2"},
+{0x8d03,0x8df3,16,1, 7,Z8D_imm4_0011, "resflg %f2"},
+{0x8d04,0x8df4,16,1, 7,Z8D_dddd_0100, "test %rw2"},
+{0x8d05,0x8df5,16,1, 7,Z8D_imm4_0101, "comflg %f2"},
+{0x8d06,0x8df6,16,1, 7,Z8D_dddd_0110, "tset %rw2"},
+{0x8d07,0x8d07, 1,1, 7,Z8D_0000_0111, "nop"},
+{0x8d08,0x8df8,16,1, 7,Z8D_dddd_1000, "clr %rw2"},
+{0x8e00,0x8eff, 1,1, 10,Z8E_imm8, "ext8e %#b1"},
+{0x8f00,0x8fff, 1,1, 10,Z8F_imm8, "ext8f %#b1"},
+{0x9000,0x90ff, 1,1, 8,Z90_ssss_dddd, "cpl %rl3,%rl2"},
+{0x9110,0x91ff, 1,1, 12,Z91_ddN0_ssss, "pushl @%rw2,%rl3"},
+{0x9200,0x92ff, 1,1, 8,Z92_ssss_dddd, "subl %rl3,%rl2"},
+{0x9310,0x93ff, 1,1, 9,Z93_ddN0_ssss, "push @%rw2,%rw3"},
+{0x9400,0x94ff, 1,1, 5,Z94_ssss_dddd, "ldl %rl3,%rl2"},
+{0x9510,0x95ff, 1,1, 12,Z95_ssN0_dddd, "popl %rl3,@%rw2"},
+{0x9600,0x96ff, 1,1, 8,Z96_ssss_dddd, "addl %rl3,%rl2"},
+{0x9710,0x97ff, 1,1, 8,Z97_ssN0_dddd, "pop %rw3,@%rw2"},
+{0x9800,0x98ff, 1,1,282,Z98_ssss_dddd, "multl %rq3,%rl2"},
+{0x9900,0x99ff, 1,1, 70,Z99_ssss_dddd, "mult %rl3,%rw2"},
+{0x9a00,0x9aff, 1,1,744,Z9A_ssss_dddd, "divl %rq3,%rl2"},
+{0x9b00,0x9bff, 1,1,107,Z9B_ssss_dddd, "div %rl3,%rw2"},
+{0x9c08,0x9cf8,16,1, 13,Z9C_dddd_1000, "testl %rl2"},
+{0x9d00,0x9dff, 1,1, 10,Z9D_imm8, "rsvd9d"},
+{0x9e00,0x9e0f, 1,1, 10,Z9E_0000_cccc, "ret %c3", DASMFLAG_STEP_OUT},
+{0x9f00,0x9fff, 1,1, 10,Z9F_imm8, "rsvd9f"},
+{0xa000,0xa0ff, 1,1, 3,ZA0_ssss_dddd, "ldb %rb3,%rb2"},
+{0xa100,0xa1ff, 1,1, 3,ZA1_ssss_dddd, "ld %rw3,%rw2"},
+{0xa200,0xa2ff, 1,1, 4,ZA2_dddd_imm4, "resb %rb2,%3"},
+{0xa300,0xa3ff, 1,1, 4,ZA3_dddd_imm4, "res %rw2,%3"},
+{0xa400,0xa4ff, 1,1, 4,ZA4_dddd_imm4, "setb %rb2,%3"},
+{0xa500,0xa5ff, 1,1, 4,ZA5_dddd_imm4, "set %rw2,%3"},
+{0xa600,0xa6ff, 1,1, 4,ZA6_dddd_imm4, "bitb %rb2,%3"},
+{0xa700,0xa7ff, 1,1, 4,ZA7_dddd_imm4, "bit %rw2,%3"},
+{0xa800,0xa8ff, 1,1, 4,ZA8_dddd_imm4m1, "incb %rb2,%+3"},
+{0xa900,0xa9ff, 1,1, 4,ZA9_dddd_imm4m1, "inc %rw2,%+3"},
+{0xaa00,0xaaff, 1,1, 4,ZAA_dddd_imm4m1, "decb %rb2,%+3"},
+{0xab00,0xabff, 1,1, 4,ZAB_dddd_imm4m1, "dec %rw2,%+3"},
+{0xac00,0xacff, 1,1, 6,ZAC_ssss_dddd, "exb %rb3,%rb2"},
+{0xad00,0xadff, 1,1, 6,ZAD_ssss_dddd, "ex %rw3,%rw2"},
+{0xae00,0xaeff, 1,1, 5,ZAE_dddd_cccc, "tccb %c3,%rb2"},
+{0xaf00,0xafff, 1,1, 5,ZAF_dddd_cccc, "tcc %c3,%rw2"},
+{0xb000,0xb0f0,16,1, 5,ZB0_dddd_0000, "dab %rb2"},
+{0xb100,0xb1f0,16,1, 11,ZB1_dddd_0000, "extsb %rw2"},
+{0xb107,0xb1f7,16,1, 11,ZB1_dddd_0111, "extsl %rq2"},
+{0xb10a,0xb1fa,16,1, 11,ZB1_dddd_1010, "exts %rl2"},
+{0xb200,0xb2f0,16,1, 6,ZB2_dddd_00I0, "rlb %rb2,%?3"},
+{0xb201,0xb2f1,16,2, 13,ZB2_dddd_0001_imm8, "s%*lb %rb2,%$3"},
+{0xb202,0xb2f2,16,1, 6,ZB2_dddd_00I0, "rlb %rb2,%?3"},
+{0xb203,0xb2f3,16,2, 15,ZB2_dddd_0011_0000_ssss_0000_0000, "sdlb %rb2,%rw5"},
+{0xb204,0xb2f4,16,1, 6,ZB2_dddd_01I0, "rrb %rb2,%?3"},
+{0xb206,0xb2f6,16,1, 6,ZB2_dddd_01I0, "rrb %rb2,%?3"},
+{0xb208,0xb2f8,16,1, 9,ZB2_dddd_10I0, "rlcb %rb2,%?3"},
+{0xb209,0xb2f9,16,2, 13,ZB2_dddd_1001_imm8, "s%*ab %rb2,%$3"},
+{0xb20a,0xb2fa,16,1, 9,ZB2_dddd_10I0, "rlcb %rb2,%?3"},
+{0xb20b,0xb2fb,16,2, 15,ZB2_dddd_1011_0000_ssss_0000_0000, "sdab %rb2,%rw5"},
+{0xb20c,0xb2fc,16,1, 9,ZB2_dddd_11I0, "rrcb %rb2,%?3"},
+{0xb20e,0xb2fe,16,1, 9,ZB2_dddd_11I0, "rrcb %rb2,%?3"},
+{0xb300,0xb3f0,16,1, 6,ZB3_dddd_00I0, "rl %rw2,%?3"},
+{0xb301,0xb3f1,16,2, 13,ZB3_dddd_0001_imm8, "s%*l %rw2,%$3"},
+{0xb303,0xb3f3,16,2, 15,ZB3_dddd_0011_0000_ssss_0000_0000, "sdl %rw2,%rw5"},
+{0xb304,0xb3f4,16,1, 6,ZB3_dddd_01I0, "rr %rw2,%?3"},
+{0xb305,0xb3f5,16,2, 13,ZB3_dddd_0101_imm8, "s%*ll %rl2,%$3"},
+{0xb307,0xb3f7,16,2, 15,ZB3_dddd_0111_0000_ssss_0000_0000, "sdll %rl2,%rw5"},
+{0xb308,0xb3f8,16,1, 6,ZB3_dddd_10I0, "rlc %rw2,%?3"},
+{0xb309,0xb3f9,16,2, 13,ZB3_dddd_1001_imm8, "s%*a %rw2,%$3"},
+{0xb30b,0xb3fb,16,2, 15,ZB3_dddd_1011_0000_ssss_0000_0000, "sda %rw2,%rw5"},
+{0xb30c,0xb3fc,16,1, 6,ZB3_dddd_11I0, "rrc %rw2,%?3"},
+{0xb30d,0xb3fd,16,2, 13,ZB3_dddd_1101_imm8, "s%*al %rl2,%$3"},
+{0xb30f,0xb3ff,16,2, 15,ZB3_dddd_1111_0000_ssss_0000_0000, "sdal %rl2,%rw5"},
+{0xb400,0xb4ff, 1,1, 5,ZB4_ssss_dddd, "adcb %rb3,%rb2"},
+{0xb500,0xb5ff, 1,1, 5,ZB5_ssss_dddd, "adc %rw3,%rw2"},
+{0xb600,0xb6ff, 1,1, 5,ZB6_ssss_dddd, "sbcb %rb3,%rb2"},
+{0xb700,0xb7ff, 1,1, 5,ZB7_ssss_dddd, "sbc %rw3,%rw2"},
+{0xb810,0xb8f0,16,2, 25,ZB8_ddN0_0000_0000_rrrr_ssN0_0000, "trib @%rw2,@%rw6,rbr"},
+{0xb812,0xb8f2,16,2, 25,ZB8_ddN0_0010_0000_rrrr_ssN0_0000, "trtib @%rw2,@%rw6,rbr"},
+{0xb814,0xb8f4,16,2, 25,ZB8_ddN0_0100_0000_rrrr_ssN0_0000, "trirb @%rw2,@%rw6,rbr"},
+{0xb816,0xb8f6,16,2, 25,ZB8_ddN0_0110_0000_rrrr_ssN0_1110, "trtirb @%rw2,@%rw6,rbr"},
+{0xb818,0xb8f8,16,2, 25,ZB8_ddN0_1000_0000_rrrr_ssN0_0000, "trdb @%rw2,@%rw6,rbr"},
+{0xb81a,0xb8fa,16,2, 25,ZB8_ddN0_1010_0000_rrrr_ssN0_0000, "trtrb @%rw2,@%rw6,rbr"},
+{0xb81c,0xb8fc,16,2, 25,ZB8_ddN0_1100_0000_rrrr_ssN0_0000, "trdrb @%rw2,@%rw6,rbr"},
+{0xb81e,0xb8fe,16,2, 25,ZB8_ddN0_1110_0000_rrrr_ssN0_1110, "trtdrb @%rw2,@%rw6,rbr"},
+{0xb900,0xb9ff,16,1, 10,ZB9_imm8, "rsvdb9"},
+{0xba10,0xbaf0,16,2, 11,ZBA_ssN0_0000_0000_rrrr_dddd_cccc, "cpib %rb6,@%rw2,rr,%c7"},
+{0xba11,0xbaf1,16,2, 11,ZBA_ssN0_0001_0000_rrrr_ddN0_x000, "ldirb @%rw6,@%rw2,rr", DASMFLAG_STEP_OVER},
+{0xba12,0xbaf2,16,2, 11,ZBA_ssN0_0010_0000_rrrr_ddN0_cccc, "cpsib @%rw6,@%rw2,rr,%c7"},
+{0xba14,0xbaf4,16,2, 11,ZBA_ssN0_0100_0000_rrrr_dddd_cccc, "cpirb %rb6,@%rw2,rr,%c7", DASMFLAG_STEP_OVER},
+{0xba16,0xbaf6,16,2, 11,ZBA_ssN0_0110_0000_rrrr_ddN0_cccc, "cpsirb @%rw6,@%rw2,rr,%c7", DASMFLAG_STEP_OVER},
+{0xba18,0xbaf8,16,2, 11,ZBA_ssN0_1000_0000_rrrr_dddd_cccc, "cpdb %rb6,@%rw2,rr,%c7"},
+{0xba19,0xbaf9,16,2, 11,ZBA_ssN0_1001_0000_rrrr_ddN0_x000, "lddrb @%rw2,@%rw6,rr", DASMFLAG_STEP_OVER},
+{0xba1a,0xbafa,16,2, 11,ZBA_ssN0_1010_0000_rrrr_ddN0_cccc, "cpsdb @%rw6,@%rw2,rr,%c7"},
+{0xba1c,0xbafc,16,2, 11,ZBA_ssN0_1100_0000_rrrr_dddd_cccc, "cpdrb %rb6,@%rw2,rr,%c7", DASMFLAG_STEP_OVER},
+{0xba1e,0xbafe,16,2, 11,ZBA_ssN0_1110_0000_rrrr_ddN0_cccc, "cpsdrb @%rw6,@%rw2,rr,%c7", DASMFLAG_STEP_OVER},
+{0xbb10,0xbbf0,16,2, 11,ZBB_ssN0_0000_0000_rrrr_dddd_cccc, "cpi %rw6,@%rw2,rr,%c7"},
+{0xbb11,0xbbf1,16,2, 11,ZBB_ssN0_0001_0000_rrrr_ddN0_x000, "ldir @%rw6,@%rw2,rr", DASMFLAG_STEP_OVER},
+{0xbb12,0xbbf2,16,2, 11,ZBB_ssN0_0010_0000_rrrr_ddN0_cccc, "cpsi @%rw6,@%rw2,rr,%c7"},
+{0xbb14,0xbbf4,16,2, 11,ZBB_ssN0_0100_0000_rrrr_dddd_cccc, "cpir %rw6,@%rw2,rr,%c7", DASMFLAG_STEP_OVER},
+{0xbb16,0xbbf6,16,2, 11,ZBB_ssN0_0110_0000_rrrr_ddN0_cccc, "cpsir @%rw6,@%rw2,rr,%c7", DASMFLAG_STEP_OVER},
+{0xbb18,0xbbf8,16,2, 11,ZBB_ssN0_1000_0000_rrrr_dddd_cccc, "cpd %rw6,@%rw2,rr,%c7"},
+{0xbb19,0xbbf9,16,2, 11,ZBB_ssN0_1001_0000_rrrr_ddN0_x000, "lddr @%rw2,@%rw6,rr", DASMFLAG_STEP_OVER},
+{0xbb1a,0xbbfa,16,2, 11,ZBB_ssN0_1010_0000_rrrr_ddN0_cccc, "cpsd @%rw6,@%rw2,rr,%c7"},
+{0xbb1c,0xbbfc,16,2, 11,ZBB_ssN0_1100_0000_rrrr_dddd_cccc, "cpdr %rw6,@%rw2,rr,%c7", DASMFLAG_STEP_OVER},
+{0xbb1e,0xbbfe,16,2, 11,ZBB_ssN0_1110_0000_rrrr_ddN0_cccc, "cpsdr @%rw6,@%rw2,rr,%c7", DASMFLAG_STEP_OVER},
+{0xbc00,0xbcff, 1,1, 9,ZBC_aaaa_bbbb, "rrdb %rb3,%rb2"},
+{0xbd00,0xbdff, 1,1, 5,ZBD_dddd_imm4, "ldk %rw2,%3"},
+{0xbe00,0xbeff, 1,1, 9,ZBE_aaaa_bbbb, "rldb %rb3,%rb2"},
+{0xbf00,0xbfff, 1,1, 10,ZBF_imm8, "rsvdbf"},
+{0xc000,0xcfff, 1,1, 5,ZC_dddd_imm8, "ldb %rb1,%#b1"},
+{0xd000,0xdfff, 1,1, 10,ZD_dsp12, "calr %d2", DASMFLAG_STEP_OVER},
+{0xe000,0xefff, 1,1, 6,ZE_cccc_dsp8, "jr %c1,%d1"},
+{0xf000,0xf07f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf100,0xf17f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf200,0xf27f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf300,0xf37f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf400,0xf47f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf500,0xf57f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf600,0xf67f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf700,0xf77f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf800,0xf87f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf900,0xf97f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xfa00,0xfa7f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xfb00,0xfb7f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xfc00,0xfc7f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xfd00,0xfd7f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xfe00,0xfe7f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xff00,0xff7f, 1,1, 11,ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER},
+{0xf080,0xf0ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xf180,0xf1ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xf280,0xf2ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xf380,0xf3ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xf480,0xf4ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xf580,0xf5ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xf680,0xf6ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xf780,0xf7ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xf880,0xf8ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xf980,0xf9ff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xfa80,0xfaff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xfb80,0xfbff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xfc80,0xfcff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xfd80,0xfdff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xfe80,0xfeff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0xff80,0xffff, 1,1, 11,ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER},
+{0, 0, 0, 0, 0,0, 0},
+};
+
+void z8000_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int i;
+ Z8000_init *init;
+
+ /* already initialized? */
+ if( z8000_exec )
+ return;
+
+ /* allocate the opcode execution and disassembler array */
+ z8000_exec = (Z8000_exec *)malloc(0x10000 * sizeof(Z8000_exec));
+ if( !z8000_exec )
+ {
+ fatalerror("cannot allocate Z8000 execution table\n");
+ }
+
+ /* set up the zero, sign, parity lookup table */
+ for (i = 0; i < 256; i++)
+ z8000_zsp[i] = ((i == 0) ? F_Z : 0) |
+ ((i & 128) ? F_S : 0) |
+ ((((i>>7)^(i>>6)^(i>>5)^(i>>4)^(i>>3)^(i>>2)^(i>>1)^i) & 1) ? F_PV : 0);
+
+ /* first set all 64K opcodes to invalid */
+ for (i = 0; i < 0x10000; i++)
+ {
+ z8000_exec[i].opcode = zinvalid;
+ z8000_exec[i].cycles = 4;
+ z8000_exec[i].size = 1;
+ z8000_exec[i].dasm = ".word %#w0";
+ z8000_exec[i].dasmflags = 0;
+ }
+
+ /* now decompose the initialization table */
+ for (init = table; init->size; init++)
+ {
+ for (i = init->beg; i <= init->end; i += init->step)
+ {
+ if (z8000_exec[i].opcode != zinvalid)
+ logerror("Z8000 opcode %04x clash '%s'\n", i, z8000_exec[i].dasm);
+
+ z8000_exec[i].opcode = init->opcode;
+ z8000_exec[i].cycles = init->cycles;
+ z8000_exec[i].size = init->size;
+ z8000_exec[i].dasm = init->dasm;
+ z8000_exec[i].dasmflags = init->dasmflags;
+ }
+ }
+
+ Z.irq_callback = irqcallback;
+}
+
+void z8000_deinit(void)
+{
+ if( !z8000_exec )
+ return;
+ free( z8000_exec );
+ z8000_exec = 0;
+}
+
diff --git a/src/emu/cpu/z80gb/opc_cb.h b/src/emu/cpu/z80gb/opc_cb.h
new file mode 100644
index 00000000000..4f85e6a8fb7
--- /dev/null
+++ b/src/emu/cpu/z80gb/opc_cb.h
@@ -0,0 +1,1440 @@
+#define RLC_8BIT(x) \
+{ \
+ register UINT8 f; \
+ (x)=(UINT8)(((x)<<1)|((x)>>7)); \
+ if( (x)&1 ) \
+ f=FLAG_C; \
+ else \
+ f=0; \
+ if( (x)==0 ) \
+ f|=FLAG_Z; \
+ Regs.b.F=f; \
+}
+
+#define RL_8BIT(x) \
+{ \
+ register UINT8 r; \
+ r=((x)&0x80)?FLAG_C:0; \
+ (x)=(UINT8)(((x)<<1)|((Regs.b.F&FLAG_C)?1:0)); \
+ if( (x)==0 ) \
+ r|=FLAG_Z; \
+ Regs.b.F=r; \
+}
+
+#define RRC_8BIT(x) \
+{ \
+ register UINT8 f; \
+ (x)=(UINT8)(((x)>>1)|((x)<<7)); \
+ if( (x)&0x80 ) \
+ f=FLAG_C; \
+ else \
+ f=0; \
+ if( (x)==0 ) \
+ f|=FLAG_Z; \
+ Regs.b.F=f; \
+}
+
+#define RR_8BIT(x) \
+{ \
+ register UINT8 r; \
+ r=((x)&1)?FLAG_C:0; \
+ (x)=(UINT8)(((x)>>1)|((Regs.b.F&FLAG_C)?0x80:0)); \
+ if( (x)==0 ) \
+ r|=FLAG_Z; \
+ Regs.b.F=r; \
+}
+
+#define SLA_8BIT(x) \
+{ \
+ register UINT8 f; \
+ if( (x)&0x80 ) \
+ f=FLAG_C; \
+ else \
+ f=0; \
+ (x)<<=1; \
+ if( (x)==0 ) \
+ f|=FLAG_Z; \
+ Regs.b.F=f; \
+}
+
+#define SRA_8BIT(x) \
+{ \
+ register UINT8 f; \
+ if( (x)&1 ) \
+ f=FLAG_C; \
+ else \
+ f=0; \
+ (x)=(UINT8)(((char)(x))>>1); \
+ if( (x)==0 ) \
+ f|=FLAG_Z; \
+ Regs.b.F=f; \
+}
+
+#define SWAP_8BIT(x) \
+ (x)=(UINT8)(((x)>>4)|((x)<<4)); \
+ if( (x)==0 ) \
+ Regs.b.F=FLAG_Z; \
+ else \
+ Regs.b.F=0;
+
+
+#define SRL_8BIT(x) \
+{ \
+ register UINT8 f; \
+ if( (x)&1 ) \
+ f=FLAG_C; \
+ else \
+ f=0; \
+ (x)>>=1; \
+ if( (x)==0 ) \
+ f|=FLAG_Z; \
+ Regs.b.F=f; \
+}
+
+#define BIT_8BIT(n,x) \
+ if( (x)&(1<<(n)) ) \
+ Regs.b.F=(UINT8)(FLAG_H|(Regs.b.F&FLAG_C)); \
+ else \
+ Regs.b.F=(UINT8)(FLAG_Z|FLAG_H|(Regs.b.F&FLAG_C));
+
+#define RES_8BIT(n,x) (x)&=~(1<<(n));
+
+#define SET_8BIT(n,x) (x)|=(1<<(n));
+
+
+case 0x00:
+ /* RLC B */
+
+ RLC_8BIT (Regs.b.B)
+ break;
+case 0x01:
+ /* RLC C */
+
+ RLC_8BIT (Regs.b.C)
+ break;
+case 0x02:
+ /* RLC D */
+
+ RLC_8BIT (Regs.b.D)
+ break;
+case 0x03:
+ /* RLC E */
+
+ RLC_8BIT (Regs.b.E)
+ break;
+case 0x04:
+ /* RLC H */
+
+ RLC_8BIT (Regs.b.H)
+ break;
+case 0x05:
+ /* RLC L */
+
+ RLC_8BIT (Regs.b.L)
+ break;
+case 0x06:
+ /* RLC (HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RLC_8BIT (x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x07:
+ /* RLC A */
+
+ RLC_8BIT (Regs.b.A)
+ break;
+case 0x08:
+ /* RRC B */
+
+ RRC_8BIT (Regs.b.B)
+ break;
+case 0x09:
+ /* RRC C */
+
+ RRC_8BIT (Regs.b.C)
+ break;
+case 0x0A:
+ /* RRC D */
+
+ RRC_8BIT (Regs.b.D)
+ break;
+case 0x0B:
+ /* RRC E */
+
+ RRC_8BIT (Regs.b.E)
+ break;
+case 0x0C:
+ /* RRC H */
+
+ RRC_8BIT (Regs.b.H)
+ break;
+case 0x0D:
+ /* RRC L */
+
+ RRC_8BIT (Regs.b.L)
+ break;
+case 0x0E:
+ /* RRC (HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RRC_8BIT (x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x0F:
+ /* RRC A */
+
+ RRC_8BIT (Regs.b.A)
+ break;
+case 0x10:
+ /* RL B */
+
+ RL_8BIT (Regs.b.B)
+ break;
+case 0x11:
+ /* RL C */
+
+ RL_8BIT (Regs.b.C)
+ break;
+case 0x12:
+ /* RL D */
+
+ RL_8BIT (Regs.b.D)
+ break;
+case 0x13:
+ /* RL E */
+
+ RL_8BIT (Regs.b.E)
+ break;
+case 0x14:
+ /* RL H */
+
+ RL_8BIT (Regs.b.H)
+ break;
+case 0x15:
+ /* RL L */
+
+ RL_8BIT (Regs.b.L)
+ break;
+case 0x16:
+ /* RL (HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RL_8BIT (x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x17:
+ /* RL A */
+
+ RL_8BIT (Regs.b.A)
+ break;
+case 0x18:
+ /* RR B */
+
+ RR_8BIT (Regs.b.B)
+ break;
+case 0x19:
+ /* RR C */
+
+ RR_8BIT (Regs.b.C)
+ break;
+case 0x1A:
+ /* RR D */
+
+ RR_8BIT (Regs.b.D)
+ break;
+case 0x1B:
+ /* RR E */
+
+ RR_8BIT (Regs.b.E)
+ break;
+case 0x1C:
+ /* RR H */
+
+ RR_8BIT (Regs.b.H)
+ break;
+case 0x1D:
+ /* RR L */
+
+ RR_8BIT (Regs.b.L)
+ break;
+case 0x1E:
+ /* RR (HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RR_8BIT (x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x1F:
+ /* RR A */
+
+ RR_8BIT (Regs.b.A)
+ break;
+case 0x20:
+ /* SLA B */
+
+ SLA_8BIT (Regs.b.B)
+ break;
+case 0x21:
+ /* SLA C */
+
+ SLA_8BIT (Regs.b.C)
+ break;
+case 0x22:
+ /* SLA D */
+
+ SLA_8BIT (Regs.b.D)
+ break;
+case 0x23:
+ /* SLA E */
+
+ SLA_8BIT (Regs.b.E)
+ break;
+case 0x24:
+ /* SLA H */
+
+ SLA_8BIT (Regs.b.H)
+ break;
+case 0x25:
+ /* SLA L */
+
+ SLA_8BIT (Regs.b.L)
+ break;
+case 0x26:
+ /* SLA (HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SLA_8BIT (x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x27:
+ /* SLA A */
+
+ SLA_8BIT (Regs.b.A)
+ break;
+case 0x28:
+ /* SRA B */
+
+ SRA_8BIT (Regs.b.B)
+ break;
+case 0x29:
+ /* SRA C */
+
+ SRA_8BIT (Regs.b.C)
+ break;
+case 0x2A:
+ /* SRA D */
+
+ SRA_8BIT (Regs.b.D)
+ break;
+case 0x2B:
+ /* SRA E */
+
+ SRA_8BIT (Regs.b.E)
+ break;
+case 0x2C:
+ /* SRA H */
+
+ SRA_8BIT (Regs.b.H)
+ break;
+case 0x2D:
+ /* SRA L */
+
+ SRA_8BIT (Regs.b.L)
+ break;
+case 0x2E:
+ /* SRA (HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SRA_8BIT (x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x2F:
+ /* SRA A */
+
+ SRA_8BIT (Regs.b.A)
+ break;
+case 0x30:
+ /* SWAP B */
+
+ SWAP_8BIT (Regs.b.B)
+ break;
+case 0x31:
+ /* SWAP C */
+
+ SWAP_8BIT (Regs.b.C)
+ break;
+case 0x32:
+ /* SWAP D */
+
+ SWAP_8BIT (Regs.b.D)
+ break;
+case 0x33:
+ /* SWAP E */
+
+ SWAP_8BIT (Regs.b.E)
+ break;
+case 0x34:
+ /* SWAP H */
+
+ SWAP_8BIT (Regs.b.H)
+ break;
+case 0x35:
+ /* SWAP L */
+
+ SWAP_8BIT (Regs.b.L)
+ break;
+case 0x36:
+ /* SWAP (HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SWAP_8BIT (x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x37:
+ /* SWAP A */
+
+ SWAP_8BIT (Regs.b.A)
+ break;
+case 0x38:
+ /* SRL B */
+
+ SRL_8BIT (Regs.b.B)
+ break;
+case 0x39:
+ /* SRL C */
+
+ SRL_8BIT (Regs.b.C)
+ break;
+case 0x3A:
+ /* SRL D */
+
+ SRL_8BIT (Regs.b.D)
+ break;
+case 0x3B:
+ /* SRL E */
+
+ SRL_8BIT (Regs.b.E)
+ break;
+case 0x3C:
+ /* SRL H */
+
+ SRL_8BIT (Regs.b.H)
+ break;
+case 0x3D:
+ /* SRL L */
+
+ SRL_8BIT (Regs.b.L)
+ break;
+case 0x3E:
+ /* SRL (HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SRL_8BIT (x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x3F:
+ /* SRL A */
+
+ SRL_8BIT (Regs.b.A)
+ break;
+case 0x40:
+ /* BIT 0,B */
+
+ BIT_8BIT (0, Regs.b.B)
+ break;
+case 0x41:
+ /* BIT 0,C */
+
+ BIT_8BIT (0, Regs.b.C)
+ break;
+case 0x42:
+ /* BIT 0,D */
+
+ BIT_8BIT (0, Regs.b.D)
+ break;
+case 0x43:
+ /* BIT 0,E */
+
+ BIT_8BIT (0, Regs.b.E)
+ break;
+case 0x44:
+ /* BIT 0,H */
+
+ BIT_8BIT (0, Regs.b.H)
+ break;
+case 0x45:
+ /* BIT 0,L */
+
+ BIT_8BIT (0, Regs.b.L)
+ break;
+case 0x46:
+ /* BIT 0,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ BIT_8BIT (0, x)
+ break;
+case 0x47:
+ /* BIT 0,A */
+
+ BIT_8BIT (0, Regs.b.A)
+ break;
+case 0x48:
+ /* BIT 1,B */
+
+ BIT_8BIT (1, Regs.b.B)
+ break;
+case 0x49:
+ /* BIT 1,C */
+
+ BIT_8BIT (1, Regs.b.C)
+ break;
+case 0x4A:
+ /* BIT 1,D */
+
+ BIT_8BIT (1, Regs.b.D)
+ break;
+case 0x4B:
+ /* BIT 1,E */
+
+ BIT_8BIT (1, Regs.b.E)
+ break;
+case 0x4C:
+ /* BIT 1,H */
+
+ BIT_8BIT (1, Regs.b.H)
+ break;
+case 0x4D:
+ /* BIT 1,L */
+
+ BIT_8BIT (1, Regs.b.L)
+ break;
+case 0x4E:
+ /* BIT 1,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ BIT_8BIT (1, x)
+ break;
+case 0x4F:
+ /* BIT 1,A */
+
+ BIT_8BIT (1, Regs.b.A)
+ break;
+case 0x50:
+ /* BIT 2,B */
+
+ BIT_8BIT (2, Regs.b.B)
+ break;
+case 0x51:
+ /* BIT 2,C */
+
+ BIT_8BIT (2, Regs.b.C)
+ break;
+case 0x52:
+ /* BIT 2,D */
+
+ BIT_8BIT (2, Regs.b.D)
+ break;
+case 0x53:
+ /* BIT 2,E */
+
+ BIT_8BIT (2, Regs.b.E)
+ break;
+case 0x54:
+ /* BIT 2,H */
+
+ BIT_8BIT (2, Regs.b.H)
+ break;
+case 0x55:
+ /* BIT 2,L */
+
+ BIT_8BIT (2, Regs.b.L)
+ break;
+case 0x56:
+ /* BIT 2,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ BIT_8BIT (2, x)
+ break;
+case 0x57:
+ /* BIT 2,A */
+
+ BIT_8BIT (2, Regs.b.A)
+ break;
+case 0x58:
+ /* BIT 3,B */
+
+ BIT_8BIT (3, Regs.b.B)
+ break;
+case 0x59:
+ /* BIT 3,C */
+
+ BIT_8BIT (3, Regs.b.C)
+ break;
+case 0x5A:
+ /* BIT 3,D */
+
+ BIT_8BIT (3, Regs.b.D)
+ break;
+case 0x5B:
+ /* BIT 3,E */
+
+ BIT_8BIT (3, Regs.b.E)
+ break;
+case 0x5C:
+ /* BIT 3,H */
+
+ BIT_8BIT (3, Regs.b.H)
+ break;
+case 0x5D:
+ /* BIT 3,L */
+
+ BIT_8BIT (3, Regs.b.L)
+ break;
+case 0x5E:
+ /* BIT 3,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ BIT_8BIT (3, x)
+ break;
+case 0x5F:
+ /* BIT 3,A */
+
+ BIT_8BIT (3, Regs.b.A)
+ break;
+case 0x60:
+ /* BIT 4,B */
+
+ BIT_8BIT (4, Regs.b.B)
+ break;
+case 0x61:
+ /* BIT 4,C */
+
+ BIT_8BIT (4, Regs.b.C)
+ break;
+case 0x62:
+ /* BIT 4,D */
+
+ BIT_8BIT (4, Regs.b.D)
+ break;
+case 0x63:
+ /* BIT 4,E */
+
+ BIT_8BIT (4, Regs.b.E)
+ break;
+case 0x64:
+ /* BIT 4,H */
+
+ BIT_8BIT (4, Regs.b.H)
+ break;
+case 0x65:
+ /* BIT 4,L */
+
+ BIT_8BIT (4, Regs.b.L)
+ break;
+case 0x66:
+ /* BIT 4,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ BIT_8BIT (4, x)
+ break;
+case 0x67:
+ /* BIT 4,A */
+
+ BIT_8BIT (4, Regs.b.A)
+ break;
+case 0x68:
+ /* BIT 5,B */
+
+ BIT_8BIT (5, Regs.b.B)
+ break;
+case 0x69:
+ /* BIT 5,C */
+
+ BIT_8BIT (5, Regs.b.C)
+ break;
+case 0x6A:
+ /* BIT 5,D */
+
+ BIT_8BIT (5, Regs.b.D)
+ break;
+case 0x6B:
+ /* BIT 5,E */
+
+ BIT_8BIT (5, Regs.b.E)
+ break;
+case 0x6C:
+ /* BIT 5,H */
+
+ BIT_8BIT (5, Regs.b.H)
+ break;
+case 0x6D:
+ /* BIT 5,L */
+
+ BIT_8BIT (5, Regs.b.L)
+ break;
+case 0x6E:
+ /* BIT 5,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ BIT_8BIT (5, x)
+ break;
+case 0x6F:
+ /* BIT 5,A */
+
+ BIT_8BIT (5, Regs.b.A)
+ break;
+case 0x70:
+ /* BIT 6,B */
+
+ BIT_8BIT (6, Regs.b.B)
+ break;
+case 0x71:
+ /* BIT 6,C */
+
+ BIT_8BIT (6, Regs.b.C)
+ break;
+case 0x72:
+ /* BIT 6,D */
+
+ BIT_8BIT (6, Regs.b.D)
+ break;
+case 0x73:
+ /* BIT 6,E */
+
+ BIT_8BIT (6, Regs.b.E)
+ break;
+case 0x74:
+ /* BIT 6,H */
+
+ BIT_8BIT (6, Regs.b.H)
+ break;
+case 0x75:
+ /* BIT 6,L */
+
+ BIT_8BIT (6, Regs.b.L)
+ break;
+case 0x76:
+ /* BIT 6,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ BIT_8BIT (6, x)
+ break;
+case 0x77:
+ /* BIT 6,A */
+
+ BIT_8BIT (6, Regs.b.A)
+ break;
+case 0x78:
+ /* BIT 7,B */
+
+ BIT_8BIT (7, Regs.b.B)
+ break;
+case 0x79:
+ /* BIT 7,C */
+
+ BIT_8BIT (7, Regs.b.C)
+ break;
+case 0x7A:
+ /* BIT 7,D */
+
+ BIT_8BIT (7, Regs.b.D)
+ break;
+case 0x7B:
+ /* BIT 7,E */
+
+ BIT_8BIT (7, Regs.b.E)
+ break;
+case 0x7C:
+ /* BIT 7,H */
+
+ BIT_8BIT (7, Regs.b.H)
+ break;
+case 0x7D:
+ /* BIT 7,L */
+
+ BIT_8BIT (7, Regs.b.L)
+ break;
+case 0x7E:
+ /* BIT 7,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ BIT_8BIT (7, x)
+ break;
+case 0x7F:
+ /* BIT 7,A */
+
+ BIT_8BIT (7, Regs.b.A)
+ break;
+case 0x80:
+ /* RES 0,B */
+
+ RES_8BIT (0, Regs.b.B)
+ break;
+case 0x81:
+ /* RES 0,C */
+
+ RES_8BIT (0, Regs.b.C)
+ break;
+case 0x82:
+ /* RES 0,D */
+
+ RES_8BIT (0, Regs.b.D)
+ break;
+case 0x83:
+ /* RES 0,E */
+
+ RES_8BIT (0, Regs.b.E)
+ break;
+case 0x84:
+ /* RES 0,H */
+
+ RES_8BIT (0, Regs.b.H)
+ break;
+case 0x85:
+ /* RES 0,L */
+
+ RES_8BIT (0, Regs.b.L)
+ break;
+case 0x86:
+ /* RES 0,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RES_8BIT (0, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x87:
+ /* RES 0,A */
+
+ RES_8BIT (0, Regs.b.A)
+ break;
+case 0x88:
+ /* RES 1,B */
+
+ RES_8BIT (1, Regs.b.B)
+ break;
+case 0x89:
+ /* RES 1,C */
+
+ RES_8BIT (1, Regs.b.C)
+ break;
+case 0x8A:
+ /* RES 1,D */
+
+ RES_8BIT (1, Regs.b.D)
+ break;
+case 0x8B:
+ /* RES 1,E */
+
+ RES_8BIT (1, Regs.b.E)
+ break;
+case 0x8C:
+ /* RES 1,H */
+
+ RES_8BIT (1, Regs.b.H)
+ break;
+case 0x8D:
+ /* RES 1,L */
+
+ RES_8BIT (1, Regs.b.L)
+ break;
+case 0x8E:
+ /* RES 1,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RES_8BIT (1, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x8F:
+ /* RES 1,A */
+
+ RES_8BIT (1, Regs.b.A)
+ break;
+case 0x90:
+ /* RES 2,B */
+
+ RES_8BIT (2, Regs.b.B)
+ break;
+case 0x91:
+ /* RES 2,C */
+
+ RES_8BIT (2, Regs.b.C)
+ break;
+case 0x92:
+ /* RES 2,D */
+
+ RES_8BIT (2, Regs.b.D)
+ break;
+case 0x93:
+ /* RES 2,E */
+
+ RES_8BIT (2, Regs.b.E)
+ break;
+case 0x94:
+ /* RES 2,H */
+
+ RES_8BIT (2, Regs.b.H)
+ break;
+case 0x95:
+ /* RES 2,L */
+
+ RES_8BIT (2, Regs.b.L)
+ break;
+case 0x96:
+ /* RES 2,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RES_8BIT (2, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x97:
+ /* RES 2,A */
+
+ RES_8BIT (2, Regs.b.A)
+ break;
+case 0x98:
+ /* RES 3,B */
+
+ RES_8BIT (3, Regs.b.B)
+ break;
+case 0x99:
+ /* RES 3,C */
+
+ RES_8BIT (3, Regs.b.C)
+ break;
+case 0x9A:
+ /* RES 3,D */
+
+ RES_8BIT (3, Regs.b.D)
+ break;
+case 0x9B:
+ /* RES 3,E */
+
+ RES_8BIT (3, Regs.b.E)
+ break;
+case 0x9C:
+ /* RES 3,H */
+
+ RES_8BIT (3, Regs.b.H)
+ break;
+case 0x9D:
+ /* RES 3,L */
+
+ RES_8BIT (3, Regs.b.L)
+ break;
+case 0x9E:
+ /* RES 3,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RES_8BIT (3, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0x9F:
+ /* RES 3,A */
+
+ RES_8BIT (3, Regs.b.A)
+ break;
+case 0xA0:
+ /* RES 4,B */
+
+ RES_8BIT (4, Regs.b.B)
+ break;
+case 0xA1:
+ /* RES 4,C */
+
+ RES_8BIT (4, Regs.b.C)
+ break;
+case 0xA2:
+ /* RES 4,D */
+
+ RES_8BIT (4, Regs.b.D)
+ break;
+case 0xA3:
+ /* RES 4,E */
+
+ RES_8BIT (4, Regs.b.E)
+ break;
+case 0xA4:
+ /* RES 4,H */
+
+ RES_8BIT (4, Regs.b.H)
+ break;
+case 0xA5:
+ /* RES 4,L */
+
+ RES_8BIT (4, Regs.b.L)
+ break;
+case 0xA6:
+ /* RES 4,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RES_8BIT (4, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xA7:
+ /* RES 4,A */
+
+ RES_8BIT (4, Regs.b.A)
+ break;
+case 0xA8:
+ /* RES 5,B */
+
+ RES_8BIT (5, Regs.b.B)
+ break;
+case 0xA9:
+ /* RES 5,C */
+
+ RES_8BIT (5, Regs.b.C)
+ break;
+case 0xAA:
+ /* RES 5,D */
+
+ RES_8BIT (5, Regs.b.D)
+ break;
+case 0xAB:
+ /* RES 5,E */
+
+ RES_8BIT (5, Regs.b.E)
+ break;
+case 0xAC:
+ /* RES 5,H */
+
+ RES_8BIT (5, Regs.b.H)
+ break;
+case 0xAD:
+ /* RES 5,L */
+
+ RES_8BIT (5, Regs.b.L)
+ break;
+case 0xAE:
+ /* RES 5,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RES_8BIT (5, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xAF:
+ /* RES 5,A */
+
+ RES_8BIT (5, Regs.b.A)
+ break;
+case 0xB0:
+ /* RES 6,B */
+
+ RES_8BIT (6, Regs.b.B)
+ break;
+case 0xB1:
+ /* RES 6,C */
+
+ RES_8BIT (6, Regs.b.C)
+ break;
+case 0xB2:
+ /* RES 6,D */
+
+ RES_8BIT (6, Regs.b.D)
+ break;
+case 0xB3:
+ /* RES 6,E */
+
+ RES_8BIT (6, Regs.b.E)
+ break;
+case 0xB4:
+ /* RES 6,H */
+
+ RES_8BIT (6, Regs.b.H)
+ break;
+case 0xB5:
+ /* RES 6,L */
+
+ RES_8BIT (6, Regs.b.L)
+ break;
+case 0xB6:
+ /* RES 6,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RES_8BIT (6, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xB7:
+ /* RES 6,A */
+
+ RES_8BIT (6, Regs.b.A)
+ break;
+case 0xB8:
+ /* RES 7,B */
+
+ RES_8BIT (7, Regs.b.B)
+ break;
+case 0xB9:
+ /* RES 7,C */
+
+ RES_8BIT (7, Regs.b.C)
+ break;
+case 0xBA:
+ /* RES 7,D */
+
+ RES_8BIT (7, Regs.b.D)
+ break;
+case 0xBB:
+ /* RES 7,E */
+
+ RES_8BIT (7, Regs.b.E)
+ break;
+case 0xBC:
+ /* RES 7,H */
+
+ RES_8BIT (7, Regs.b.H)
+ break;
+case 0xBD:
+ /* RES 7,L */
+
+ RES_8BIT (7, Regs.b.L)
+ break;
+case 0xBE:
+ /* RES 7,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ RES_8BIT (7, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xBF:
+ /* RES 7,A */
+
+ RES_8BIT (7, Regs.b.A)
+ break;
+case 0xC0:
+ /* SET 0,B */
+
+ SET_8BIT (0, Regs.b.B)
+ break;
+case 0xC1:
+ /* SET 0,C */
+
+ SET_8BIT (0, Regs.b.C)
+ break;
+case 0xC2:
+ /* SET 0,D */
+
+ SET_8BIT (0, Regs.b.D)
+ break;
+case 0xC3:
+ /* SET 0,E */
+
+ SET_8BIT (0, Regs.b.E)
+ break;
+case 0xC4:
+ /* SET 0,H */
+
+ SET_8BIT (0, Regs.b.H)
+ break;
+case 0xC5:
+ /* SET 0,L */
+
+ SET_8BIT (0, Regs.b.L)
+ break;
+case 0xC6:
+ /* SET 0,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SET_8BIT (0, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xC7:
+ /* SET 0,A */
+
+ SET_8BIT (0, Regs.b.A)
+ break;
+case 0xC8:
+ /* SET 1,B */
+
+ SET_8BIT (1, Regs.b.B)
+ break;
+case 0xC9:
+ /* SET 1,C */
+
+ SET_8BIT (1, Regs.b.C)
+ break;
+case 0xCA:
+ /* SET 1,D */
+
+ SET_8BIT (1, Regs.b.D)
+ break;
+case 0xCB:
+ /* SET 1,E */
+
+ SET_8BIT (1, Regs.b.E)
+ break;
+case 0xCC:
+ /* SET 1,H */
+
+ SET_8BIT (1, Regs.b.H)
+ break;
+case 0xCD:
+ /* SET 1,L */
+
+ SET_8BIT (1, Regs.b.L)
+ break;
+case 0xCE:
+ /* SET 1,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SET_8BIT (1, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xCF:
+ /* SET 1,A */
+
+ SET_8BIT (1, Regs.b.A)
+ break;
+case 0xD0:
+ /* SET 2,B */
+
+ SET_8BIT (2, Regs.b.B)
+ break;
+case 0xD1:
+ /* SET 2,C */
+
+ SET_8BIT (2, Regs.b.C)
+ break;
+case 0xD2:
+ /* SET 2,D */
+
+ SET_8BIT (2, Regs.b.D)
+ break;
+case 0xD3:
+ /* SET 2,E */
+
+ SET_8BIT (2, Regs.b.E)
+ break;
+case 0xD4:
+ /* SET 2,H */
+
+ SET_8BIT (2, Regs.b.H)
+ break;
+case 0xD5:
+ /* SET 2,L */
+
+ SET_8BIT (2, Regs.b.L)
+ break;
+case 0xD6:
+ /* SET 2,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SET_8BIT (2, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xD7:
+ /* SET 2,A */
+
+ SET_8BIT (2, Regs.b.A)
+ break;
+case 0xD8:
+ /* SET 3,B */
+
+ SET_8BIT (3, Regs.b.B)
+ break;
+case 0xD9:
+ /* SET 3,C */
+
+ SET_8BIT (3, Regs.b.C)
+ break;
+case 0xDA:
+ /* SET 3,D */
+
+ SET_8BIT (3, Regs.b.D)
+ break;
+case 0xDB:
+ /* SET 3,E */
+
+ SET_8BIT (3, Regs.b.E)
+ break;
+case 0xDC:
+ /* SET 3,H */
+
+ SET_8BIT (3, Regs.b.H)
+ break;
+case 0xDD:
+ /* SET 3,L */
+
+ SET_8BIT (3, Regs.b.L)
+ break;
+case 0xDE:
+ /* SET 3,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SET_8BIT (3, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xDF:
+ /* SET 3,A */
+
+ SET_8BIT (3, Regs.b.A)
+ break;
+case 0xE0:
+ /* SET 4,B */
+
+ SET_8BIT (4, Regs.b.B)
+ break;
+case 0xE1:
+ /* SET 4,C */
+
+ SET_8BIT (4, Regs.b.C)
+ break;
+case 0xE2:
+ /* SET 4,D */
+
+ SET_8BIT (4, Regs.b.D)
+ break;
+case 0xE3:
+ /* SET 4,E */
+
+ SET_8BIT (4, Regs.b.E)
+ break;
+case 0xE4:
+ /* SET 4,H */
+
+ SET_8BIT (4, Regs.b.H)
+ break;
+case 0xE5:
+ /* SET 4,L */
+
+ SET_8BIT (4, Regs.b.L)
+ break;
+case 0xE6:
+ /* SET 4,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SET_8BIT (4, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xE7:
+ /* SET 4,A */
+
+ SET_8BIT (4, Regs.b.A)
+ break;
+case 0xE8:
+ /* SET 5,B */
+
+ SET_8BIT (5, Regs.b.B)
+ break;
+case 0xE9:
+ /* SET 5,C */
+
+ SET_8BIT (5, Regs.b.C)
+ break;
+case 0xEA:
+ /* SET 5,D */
+
+ SET_8BIT (5, Regs.b.D)
+ break;
+case 0xEB:
+ /* SET 5,E */
+
+ SET_8BIT (5, Regs.b.E)
+ break;
+case 0xEC:
+ /* SET 5,H */
+
+ SET_8BIT (5, Regs.b.H)
+ break;
+case 0xED:
+ /* SET 5,L */
+
+ SET_8BIT (5, Regs.b.L)
+ break;
+case 0xEE:
+ /* SET 5,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SET_8BIT (5, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xEF:
+ /* SET 5,A */
+
+ SET_8BIT (5, Regs.b.A)
+ break;
+case 0xF0:
+ /* SET 6,B */
+
+ SET_8BIT (6, Regs.b.B)
+ break;
+case 0xF1:
+ /* SET 6,C */
+
+ SET_8BIT (6, Regs.b.C)
+ break;
+case 0xF2:
+ /* SET 6,D */
+
+ SET_8BIT (6, Regs.b.D)
+ break;
+case 0xF3:
+ /* SET 6,E */
+
+ SET_8BIT (6, Regs.b.E)
+ break;
+case 0xF4:
+ /* SET 6,H */
+
+ SET_8BIT (6, Regs.b.H)
+ break;
+case 0xF5:
+ /* SET 6,L */
+
+ SET_8BIT (6, Regs.b.L)
+ break;
+case 0xF6:
+ /* SET 6,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SET_8BIT (6, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xF7:
+ /* SET 6,A */
+
+ SET_8BIT (6, Regs.b.A)
+ break;
+case 0xF8:
+ /* SET 7,B */
+
+ SET_8BIT (7, Regs.b.B)
+ break;
+case 0xF9:
+ /* SET 7,C */
+
+ SET_8BIT (7, Regs.b.C)
+ break;
+case 0xFA:
+ /* SET 7,D */
+
+ SET_8BIT (7, Regs.b.D)
+ break;
+case 0xFB:
+ /* SET 7,E */
+
+ SET_8BIT (7, Regs.b.E)
+ break;
+case 0xFC:
+ /* SET 7,H */
+
+ SET_8BIT (7, Regs.b.H)
+ break;
+case 0xFD:
+ /* SET 7,L */
+
+ SET_8BIT (7, Regs.b.L)
+ break;
+case 0xFE:
+ /* SET 7,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+ SET_8BIT (7, x)
+ mem_WriteByte (Regs.w.HL, x);
+ break;
+case 0xFF:
+ /* SET 7,A */
+
+ SET_8BIT (7, Regs.b.A)
+ break;
diff --git a/src/emu/cpu/z80gb/opc_main.h b/src/emu/cpu/z80gb/opc_main.h
new file mode 100644
index 00000000000..5a00ca4ef8f
--- /dev/null
+++ b/src/emu/cpu/z80gb/opc_main.h
@@ -0,0 +1,1552 @@
+#define INC_8BIT(x) \
+{ \
+ register UINT8 r,f; \
+ x++; \
+ r=(x); \
+ f=(UINT8)(Regs.b.F&FLAG_C); \
+ if( r==0 ) f|=FLAG_Z; \
+ if( (r&0xF)==0 ) f|=FLAG_H; \
+ Regs.b.F=f; \
+}
+
+#define DEC_8BIT(x) \
+{ \
+ register UINT8 r,f; \
+ x--; \
+ r=(x); \
+ f=(UINT8)((Regs.b.F&FLAG_C)|FLAG_N); \
+ if( r==0 ) f|=FLAG_Z; \
+ if( (r&0xF)==0xF ) f|=FLAG_H; \
+ Regs.b.F=f; \
+}
+
+#define ADD_HL_RR(x) \
+{ \
+ register UINT32 r1,r2; \
+ register UINT8 f; \
+ r1=Regs.w.HL+(x); \
+ r2=(Regs.w.HL&0xFFF)+((x)&0xFFF); \
+ f=(UINT8)(Regs.b.F&FLAG_Z); \
+ if( r1>0xFFFF ) f|=FLAG_C; \
+ if( r2>0x0FFF ) f|=FLAG_H; \
+ Regs.w.HL=(UINT16)r1; \
+ Regs.b.F=f; \
+}
+
+#define ADD_A_X(x) \
+{ \
+ register UINT16 r1,r2; \
+ register UINT8 f; \
+ r1=(UINT16)((Regs.b.A&0xF)+((x)&0xF)); \
+ r2=(UINT16)(Regs.b.A+(x)); \
+ Regs.b.A=(UINT8)r2; \
+ if( ((UINT8)r2)==0 ) f=FLAG_Z; \
+ else f=0; \
+ if( r2>0xFF ) f|=FLAG_C; \
+ if( r1>0xF ) f|=FLAG_H; \
+ Regs.b.F=f; \
+}
+
+#define SUB_A_X(x) \
+{ \
+ register UINT16 r1,r2; \
+ register UINT8 f; \
+ r1=(UINT16)((Regs.b.A&0xF)-((x)&0xF)); \
+ r2=(UINT16)(Regs.b.A-(x)); \
+ Regs.b.A=(UINT8)r2; \
+ if( ((UINT8)r2)==0 ) f=FLAG_N|FLAG_Z; \
+ else f=FLAG_N; \
+ if( r2>0xFF ) f|=FLAG_C; \
+ if( r1>0xF ) f|=FLAG_H; \
+ Regs.b.F=f; \
+}
+
+/*
+ #define CP_A_X(x) \
+ { \
+ register UINT16 r; \
+ register UINT8 f; \
+ r=(UINT16)(Regs.b.A-(x)); \
+ if( ((UINT8)r)==0 ) \
+ f=FLAG_N|FLAG_Z; \
+ else \
+ f=FLAG_N; \
+ f|=(UINT8)((r>>8)&FLAG_C); \
+ if( (r^Regs.b.A^(x))&0x10 ) \
+ f|=FLAG_H; \
+ Regs.b.F=f; \
+ }
+ */
+
+#define CP_A_X(x) \
+{ \
+ register UINT16 r1,r2; \
+ register UINT8 f; \
+ r1=(UINT16)((Regs.b.A&0xF)-((x)&0xF)); \
+ r2=(UINT16)(Regs.b.A-(x)); \
+ if( ((UINT8)r2)==0 ) f=FLAG_N|FLAG_Z; \
+ else f=FLAG_N; \
+ if( r2>0xFF ) f|=FLAG_C; \
+ if( r1>0xF ) f|=FLAG_H; \
+ Regs.b.F=f; \
+}
+
+#define SBC_A_X(x) \
+{ \
+ register UINT16 r1,r2; \
+ register UINT8 f; \
+ r1=(UINT16)((Regs.b.A&0xF)-((x)&0xF)-((Regs.b.F&FLAG_C)?1:0)); \
+ r2=(UINT16)(Regs.b.A-(x)-((Regs.b.F&FLAG_C)?1:0)); \
+ Regs.b.A=(UINT8)r2; \
+ if( ((UINT8)r2)==0 ) f=FLAG_N|FLAG_Z; \
+ else f=FLAG_N; \
+ if( r2>0xFF ) f|=FLAG_C; \
+ if( r1>0xF ) f|=FLAG_H; \
+ Regs.b.F=f; \
+}
+
+#define ADC_A_X(x) \
+{ \
+ register UINT16 r1,r2; \
+ register UINT8 f; \
+ r1=(UINT16)((Regs.b.A&0xF)+((x)&0xF)+((Regs.b.F&FLAG_C)?1:0)); \
+ r2=(UINT16)(Regs.b.A+(x)+((Regs.b.F&FLAG_C)?1:0)); \
+ if( (Regs.b.A=(UINT8)r2)==0 ) f=FLAG_Z; \
+ else f=0; \
+ if( r2>0xFF ) f|=FLAG_C; \
+ if( r1>0xF ) f|=FLAG_H; \
+ Regs.b.F=f; \
+}
+
+#define AND_A_X(x) \
+ if( (Regs.b.A&=(x))==0 ) \
+ Regs.b.F=FLAG_H|FLAG_Z; \
+ else \
+ Regs.b.F=FLAG_H;
+
+#define XOR_A_X(x) \
+ if( (Regs.b.A^=(x))==0 ) \
+ Regs.b.F=FLAG_Z; \
+ else \
+ Regs.b.F=0;
+
+#define OR_A_X(x) \
+ if( (Regs.b.A|=(x))==0 ) \
+ Regs.b.F=FLAG_Z; \
+ else \
+ Regs.b.F=0;
+
+
+case 0x00: /* NOP */
+ break;
+case 0x01: /* LD BC,n16 */
+ Regs.w.BC = mem_ReadWord (Regs.w.PC);
+ Regs.w.PC += 2;
+ break;
+case 0x02: /* LD (BC),A */
+ mem_WriteByte (Regs.w.BC, Regs.b.A);
+ break;
+case 0x03: /* INC BC */
+
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.B == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+ Regs.w.BC += 1;
+ break;
+case 0x04: /* INC B */
+
+ INC_8BIT (Regs.b.B)
+ break;
+case 0x05: /* DEC B */
+
+ DEC_8BIT (Regs.b.B)
+ break;
+case 0x06: /* LD B,n8 */
+
+ Regs.b.B = mem_ReadByte (Regs.w.PC++);
+ break;
+case 0x07: /* RLCA */
+
+ Regs.b.A = (UINT8) ((Regs.b.A << 1) | (Regs.b.A >> 7));
+ if (Regs.b.A & 1)
+ {
+ Regs.b.F = FLAG_C;
+ }
+ else
+ {
+ Regs.b.F = 0;
+ }
+ break;
+case 0x08: /* LD (n16),SP */
+
+ mem_WriteWord (mem_ReadWord (Regs.w.PC), Regs.w.SP);
+ Regs.w.PC += 2;
+ break;
+case 0x09: /* ADD HL,BC */
+
+ ADD_HL_RR (Regs.w.BC)
+ break;
+case 0x0A: /* LD A,(BC) */
+
+ Regs.b.A = mem_ReadByte (Regs.w.BC);
+ break;
+case 0x0B: /* DEC BC */
+
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.B == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+
+ Regs.w.BC -= 1;
+ break;
+case 0x0C: /* INC C */
+
+ INC_8BIT (Regs.b.C)
+ break;
+case 0x0D: /* DEC C */
+
+ DEC_8BIT (Regs.b.C)
+ break;
+case 0x0E: /* LD C,n8 */
+
+ Regs.b.C = mem_ReadByte (Regs.w.PC++);
+ break;
+case 0x0F: /* RRCA */
+
+ Regs.b.A = (UINT8) ((Regs.b.A >> 1) | (Regs.b.A << 7));
+ Regs.b.F = 0;
+ if (Regs.b.A & 0x80)
+ {
+ Regs.b.F |= FLAG_C;
+ }
+ break;
+case 0x10: /* STOP */
+ if ( Regs.w.gb_speed_change_pending ) {
+ Regs.w.gb_speed = ( Regs.w.gb_speed == 1 ) ? 2 : 1;
+ }
+ Regs.w.gb_speed_change_pending = 0;
+ break;
+case 0x11: /* LD DE,n16 */
+
+ Regs.w.DE = mem_ReadWord (Regs.w.PC);
+ Regs.w.PC += 2;
+ break;
+case 0x12: /* LD (DE),A */
+ mem_WriteByte (Regs.w.DE, Regs.b.A);
+ break;
+case 0x13: /* INC DE */
+
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.D == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+
+ Regs.w.DE += 1;
+ break;
+case 0x14: /* INC D */
+
+ INC_8BIT (Regs.b.D)
+ break;
+case 0x15: /* DEC D */
+
+ DEC_8BIT (Regs.b.D)
+ break;
+case 0x16: /* LD D,n8 */
+
+ Regs.b.D = mem_ReadByte (Regs.w.PC++);
+ break;
+case 0x17: /* RLA */
+
+ x = (Regs.b.A & 0x80) ? FLAG_C : 0;
+
+ Regs.b.A = (UINT8) ((Regs.b.A << 1) | ((Regs.b.F & FLAG_C) ? 1 : 0));
+ Regs.b.F = x;
+ break;
+case 0x18: /* JR n8 */
+ {
+ INT8 offset;
+
+ offset = mem_ReadByte (Regs.w.PC++);
+ Regs.w.PC += offset;
+ }
+ break;
+case 0x19: /* ADD HL,DE */
+
+ ADD_HL_RR (Regs.w.DE)
+ break;
+case 0x1A: /* LD A,(DE) */
+
+ Regs.b.A = mem_ReadByte (Regs.w.DE);
+ break;
+case 0x1B: /* DEC DE */
+
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.D == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+
+ Regs.w.DE -= 1;
+ break;
+case 0x1C: /* INC E */
+
+ INC_8BIT (Regs.b.E)
+ break;
+case 0x1D: /* DEC E */
+
+ DEC_8BIT (Regs.b.E)
+ break;
+case 0x1E: /* LD E,n8 */
+
+ Regs.b.E = mem_ReadByte (Regs.w.PC++);
+ break;
+case 0x1F: /* RRA */
+
+ x = (Regs.b.A & 1) ? FLAG_C : 0;
+
+ Regs.b.A = (UINT8) ((Regs.b.A >> 1) | ((Regs.b.F & FLAG_C) ? 0x80 : 0));
+ Regs.b.F = x;
+ break;
+case 0x20: /* JR NZ,n8 */
+
+ if (Regs.b.F & FLAG_Z)
+ {
+ Regs.w.PC++;
+ }
+ else
+ {
+ INT8 offset;
+
+ offset = mem_ReadByte (Regs.w.PC++);
+ Regs.w.PC += offset;
+ CYCLES_PASSED( 4 );
+ }
+ break;
+case 0x21: /* LD HL,n16 */
+
+ Regs.w.HL = mem_ReadWord (Regs.w.PC);
+ Regs.w.PC += 2;
+ break;
+case 0x22: /* LD (HL+),A */
+
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.H == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+
+ mem_WriteByte (Regs.w.HL, Regs.b.A);
+ Regs.w.HL += 1;
+ break;
+case 0x23: /* INC HL */
+
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.H == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+
+ Regs.w.HL += 1;
+ break;
+case 0x24: /* INC H */
+
+ INC_8BIT (Regs.b.H);
+ break;
+case 0x25: /* DEC H */
+
+ DEC_8BIT (Regs.b.H);
+ break;
+case 0x26: /* LD H,n8 */
+
+ Regs.b.H = mem_ReadByte (Regs.w.PC++);
+ break;
+case 0x27: /* DAA */
+ {
+ int tmp = Regs.b.A;
+
+ if ( ! ( Regs.b.F & FLAG_N ) ) {
+ if ( ( Regs.b.F & FLAG_H ) || ( tmp & 0x0F ) > 9 )
+ tmp += 6;
+ if ( ( Regs.b.F & FLAG_C ) || tmp > 0x9F )
+ tmp += 0x60;
+ } else {
+ if ( Regs.b.F & FLAG_H ) {
+ tmp -= 6;
+ if ( ! ( Regs.b.F & FLAG_C ) )
+ tmp &= 0xFF;
+ }
+ if ( Regs.b.F & FLAG_C )
+ tmp -= 0x60;
+ }
+ Regs.b.F &= ~ ( FLAG_H | FLAG_Z );
+ if ( tmp & 0x100 )
+ Regs.b.F |= FLAG_C;
+ Regs.b.A = tmp & 0xFF;
+ if ( ! Regs.b.A )
+ Regs.b.F |= FLAG_Z;
+ }
+ break;
+case 0x28: /* JR Z,n8 */
+
+ if (Regs.b.F & FLAG_Z)
+ {
+ INT8 offset;
+
+ offset = mem_ReadByte (Regs.w.PC++);
+ Regs.w.PC += offset;
+
+ CYCLES_PASSED( 4 );
+ }
+ else
+ {
+ Regs.w.PC += 1;
+ }
+ break;
+case 0x29: /* ADD HL,HL */
+
+ ADD_HL_RR (Regs.w.HL)
+ break;
+case 0x2A: /* LD A,(HL+) */
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.H == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+
+ Regs.b.A = mem_ReadByte (Regs.w.HL);
+ Regs.w.HL += 1;
+ break;
+case 0x2B: /* DEC HL */
+
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.H == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+
+ Regs.w.HL -= 1;
+ break;
+case 0x2C: /* INC L */
+
+ INC_8BIT (Regs.b.L);
+ break;
+case 0x2D: /* DEC L */
+
+ DEC_8BIT (Regs.b.L);
+ break;
+case 0x2E: /* LD L,n8 */
+
+ Regs.b.L = mem_ReadByte (Regs.w.PC++);
+ break;
+case 0x2F: /* CPL */
+
+ Regs.b.A = ~Regs.b.A;
+ Regs.b.F |= FLAG_N | FLAG_H;
+ break;
+case 0x30: /* JR NC,n8 */
+
+ if (Regs.b.F & FLAG_C)
+ {
+ Regs.w.PC += 1;
+ }
+ else
+ {
+ INT8 offset;
+
+ offset = mem_ReadByte (Regs.w.PC++);
+ Regs.w.PC += offset;
+ CYCLES_PASSED( 4 );
+ }
+ break;
+case 0x31: /* LD SP,n16 */
+
+ Regs.w.SP = mem_ReadWord (Regs.w.PC);
+ Regs.w.PC += 2;
+ break;
+case 0x32: /* LD (HL-),A */
+
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.H == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+
+ mem_WriteByte (Regs.w.HL, Regs.b.A);
+ Regs.w.HL -= 1;
+ break;
+case 0x33: /* INC SP */
+
+ Regs.w.SP += 1;
+ break;
+case 0x34: /* INC (HL) */
+
+ {
+ register UINT8 r, f;
+
+ f = (UINT8) (Regs.b.F & FLAG_C);
+ r = (UINT8) (mem_ReadByte (Regs.w.HL) + 1);
+ mem_WriteByte (Regs.w.HL, r);
+
+ if (r == 0)
+ f |= FLAG_Z;
+
+ if ((r & 0xF) == 0)
+ f |= FLAG_H;
+
+ Regs.b.F = f;
+ }
+ break;
+case 0x35: /* DEC (HL) */
+
+ {
+ register UINT8 r, f;
+
+ f = (UINT8) ((Regs.b.F & FLAG_C) | FLAG_N);
+ r = (UINT8) (mem_ReadByte (Regs.w.HL) - 1);
+ mem_WriteByte (Regs.w.HL, r);
+
+ if (r == 0)
+ f |= FLAG_Z;
+
+ if ((r & 0xF) == 0xF)
+ f |= FLAG_H;
+
+ Regs.b.F = f;
+ }
+ break;
+case 0x36: /* LD (HL),n8 */
+ /* FIXED / broken ? */
+ mem_WriteByte (Regs.w.HL, mem_ReadByte (Regs.w.PC++));
+ break;
+case 0x37: /* SCF */
+
+ Regs.b.F = (UINT8) ((Regs.b.F & FLAG_Z) | FLAG_C);
+ break;
+case 0x38: /* JR C,n8 */
+
+ if (Regs.b.F & FLAG_C)
+ {
+ INT8 offset;
+
+ offset = mem_ReadByte (Regs.w.PC++);
+ Regs.w.PC += offset;
+
+ CYCLES_PASSED( 4 );
+ }
+ else
+ {
+ Regs.w.PC += 1;
+ }
+ break;
+case 0x39: /* ADD HL,SP */
+ ADD_HL_RR (Regs.w.SP)
+ break;
+case 0x3A: /* LD A,(HL-) */
+#if 0 /* FIXME ?? do we want to support this? (bug emulation) */
+ if (Regs.b.H == 0xFE)
+ {
+ trash_sprites (state);
+ }
+#endif
+
+ Regs.b.A = mem_ReadByte (Regs.w.HL);
+ Regs.w.HL -= 1;
+ break;
+case 0x3B: /* DEC SP */
+
+ Regs.w.SP -= 1;
+ break;
+case 0x3C: /* INC A */
+
+ INC_8BIT (Regs.b.A);
+ break;
+case 0x3D: /* DEC A */
+
+ DEC_8BIT (Regs.b.A);
+ break;
+case 0x3E: /* LD A,n8 */
+
+ Regs.b.A = mem_ReadByte (Regs.w.PC++);
+ break;
+case 0x3F: /* CCF */
+
+ Regs.b.F = (UINT8) ((Regs.b.F & FLAG_Z) | ((Regs.b.F & FLAG_C) ? 0 : FLAG_C));
+ break;
+case 0x40: /* LD B,B */
+ break;
+case 0x41: /* LD B,C */
+
+ Regs.b.B = Regs.b.C;
+ break;
+case 0x42: /* LD B,D */
+
+ Regs.b.B = Regs.b.D;
+ break;
+case 0x43: /* LD B,E */
+
+ Regs.b.B = Regs.b.E;
+ break;
+case 0x44: /* LD B,H */
+
+ Regs.b.B = Regs.b.H;
+ break;
+case 0x45: /* LD B,L */
+
+ Regs.b.B = Regs.b.L;
+ break;
+case 0x46: /* LD B,(HL) */
+
+ Regs.b.B = mem_ReadByte (Regs.w.HL);
+ break;
+case 0x47: /* LD B,A */
+
+ Regs.b.B = Regs.b.A;
+ break;
+case 0x48: /* LD C,B */
+
+ Regs.b.C = Regs.b.B;
+ break;
+case 0x49: /* LD C,C */
+ break;
+case 0x4A: /* LD C,D */
+
+ Regs.b.C = Regs.b.D;
+ break;
+case 0x4B: /* LD C,E */
+
+ Regs.b.C = Regs.b.E;
+ break;
+case 0x4C: /* LD C,H */
+
+ Regs.b.C = Regs.b.H;
+ break;
+case 0x4D: /* LD C,L */
+
+ Regs.b.C = Regs.b.L;
+ break;
+case 0x4E: /* LD C,(HL) */
+
+ Regs.b.C = mem_ReadByte (Regs.w.HL);
+ break;
+case 0x4F: /* LD C,A */
+
+ Regs.b.C = Regs.b.A;
+ break;
+case 0x50: /* LD D,B */
+
+ Regs.b.D = Regs.b.B;
+ break;
+case 0x51: /* LD D,C */
+
+ Regs.b.D = Regs.b.C;
+ break;
+case 0x52: /* LD D,D */
+ break;
+case 0x53: /* LD D,E */
+
+ Regs.b.D = Regs.b.E;
+ break;
+case 0x54: /* LD D,H */
+
+ Regs.b.D = Regs.b.H;
+ break;
+case 0x55: /* LD D,L */
+
+ Regs.b.D = Regs.b.L;
+ break;
+case 0x56: /* LD D,(HL) */
+
+ Regs.b.D = mem_ReadByte (Regs.w.HL);
+ break;
+case 0x57: /* LD D,A */
+
+ Regs.b.D = Regs.b.A;
+ break;
+case 0x58: /* LD E,B */
+
+ Regs.b.E = Regs.b.B;
+ break;
+case 0x59: /* LD E,C */
+
+ Regs.b.E = Regs.b.C;
+ break;
+case 0x5A: /* LD E,D */
+
+ Regs.b.E = Regs.b.D;
+ break;
+case 0x5B: /* LD E,E */
+ break;
+case 0x5C: /* LD E,H */
+
+ Regs.b.E = Regs.b.H;
+ break;
+case 0x5D: /* LD E,L */
+
+ Regs.b.E = Regs.b.L;
+ break;
+case 0x5E: /* LD E,(HL) */
+
+ Regs.b.E = mem_ReadByte (Regs.w.HL);
+ break;
+case 0x5F: /* LD E,A */
+
+ Regs.b.E = Regs.b.A;
+ break;
+case 0x60: /* LD H,B */
+
+ Regs.b.H = Regs.b.B;
+ break;
+case 0x61: /* LD H,C */
+
+ Regs.b.H = Regs.b.C;
+ break;
+case 0x62: /* LD H,D */
+
+ Regs.b.H = Regs.b.D;
+ break;
+case 0x63: /* LD H,E */
+
+ Regs.b.H = Regs.b.E;
+ break;
+case 0x64: /* LD H,H */
+ break;
+case 0x65: /* LD H,L */
+
+ Regs.b.H = Regs.b.L;
+ break;
+case 0x66: /* LD H,(HL) */
+
+ Regs.b.H = mem_ReadByte (Regs.w.HL);
+ break;
+case 0x67: /* LD H,A */
+
+ Regs.b.H = Regs.b.A;
+ break;
+case 0x68: /* LD L,B */
+
+ Regs.b.L = Regs.b.B;
+ break;
+case 0x69: /* LD L,C */
+
+ Regs.b.L = Regs.b.C;
+ break;
+case 0x6A: /* LD L,D */
+ Regs.b.L = Regs.b.D;
+ break;
+case 0x6B: /* LD L,E */
+
+ Regs.b.L = Regs.b.E;
+ break;
+case 0x6C: /* LD L,H */
+
+ Regs.b.L = Regs.b.H;
+ break;
+case 0x6D: /* LD L,L */
+ break;
+case 0x6E: /* LD L,(HL) */
+
+ Regs.b.L = mem_ReadByte (Regs.w.HL);
+ break;
+case 0x6F: /* LD L,A */
+
+ Regs.b.L = Regs.b.A;
+ break;
+case 0x70: /* LD (HL),B */
+
+ mem_WriteByte (Regs.w.HL, Regs.b.B);
+ break;
+case 0x71: /* LD (HL),C */
+
+ mem_WriteByte (Regs.w.HL, Regs.b.C);
+ break;
+case 0x72: /* LD (HL),D */
+
+ mem_WriteByte (Regs.w.HL, Regs.b.D);
+ break;
+case 0x73: /* LD (HL),E */
+
+ mem_WriteByte (Regs.w.HL, Regs.b.E);
+ break;
+case 0x74: /* LD (HL),H */
+
+ mem_WriteByte (Regs.w.HL, Regs.b.H);
+ break;
+case 0x75: /* LD (HL),L */
+
+ mem_WriteByte (Regs.w.HL, Regs.b.L);
+ break;
+case 0x76: /* HALT */
+ Regs.w.enable |= HALTED;
+ Regs.w.haltIFstatus = Regs.w.IF & Regs.w.IE;
+ Regs.w.PC--;
+ break;
+case 0x77: /* LD (HL),A */
+
+ mem_WriteByte (Regs.w.HL, Regs.b.A);
+ break;
+case 0x78: /* LD A,B */
+
+ Regs.b.A = Regs.b.B;
+ break;
+case 0x79: /* LD A,C */
+
+ Regs.b.A = Regs.b.C;
+ break;
+case 0x7A: /* LD A,D */
+
+ Regs.b.A = Regs.b.D;
+ break;
+case 0x7B: /* LD A,E */
+
+ Regs.b.A = Regs.b.E;
+ break;
+case 0x7C: /* LD A,H */
+
+ Regs.b.A = Regs.b.H;
+ break;
+case 0x7D: /* LD A,L */
+
+ Regs.b.A = Regs.b.L;
+ break;
+case 0x7E: /* LD A,(HL) */
+
+ Regs.b.A = mem_ReadByte (Regs.w.HL);
+ break;
+case 0x7F: /* LD A,A */
+ break;
+case 0x80: /* ADD A,B */
+
+ ADD_A_X (Regs.b.B)
+ break;
+case 0x81: /* ADD A,C */
+
+ ADD_A_X (Regs.b.C)
+ break;
+case 0x82: /* ADD A,D */
+
+ ADD_A_X (Regs.b.D)
+ break;
+case 0x83: /* ADD A,E */
+
+ ADD_A_X (Regs.b.E)
+ break;
+case 0x84: /* ADD A,H */
+
+ ADD_A_X (Regs.b.H)
+ break;
+case 0x85: /* ADD A,L */
+
+ ADD_A_X (Regs.b.L)
+ break;
+case 0x86: /* ADD A,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+
+ ADD_A_X (x)
+ break;
+case 0x87: /* ADD A,A */
+
+ ADD_A_X (Regs.b.A)
+ break;
+case 0x88: /* ADC A,B */
+
+ ADC_A_X (Regs.b.B)
+ break;
+case 0x89: /* ADC A,C */
+
+ ADC_A_X (Regs.b.C)
+ break;
+case 0x8A: /* ADC A,D */
+
+ ADC_A_X (Regs.b.D)
+ break;
+case 0x8B: /* ADC A,E */
+
+ ADC_A_X (Regs.b.E)
+ break;
+case 0x8C: /* ADC A,H */
+
+ ADC_A_X (Regs.b.H)
+ break;
+case 0x8D: /* ADC A,L */
+
+ ADC_A_X (Regs.b.L)
+ break;
+case 0x8E: /* ADC A,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+
+ ADC_A_X (x)
+ break;
+case 0x8F: /* ADC A,A */
+
+ ADC_A_X (Regs.b.A)
+ break;
+case 0x90: /* SUB A,B */
+
+ SUB_A_X (Regs.b.B)
+ break;
+case 0x91: /* SUB A,C */
+
+ SUB_A_X (Regs.b.C)
+ break;
+case 0x92: /* SUB A,D */
+
+ SUB_A_X (Regs.b.D)
+ break;
+case 0x93: /* SUB A,E */
+
+ SUB_A_X (Regs.b.E)
+ break;
+case 0x94: /* SUB A,H */
+
+ SUB_A_X (Regs.b.H)
+ break;
+case 0x95: /* SUB A,L */
+
+ SUB_A_X (Regs.b.L)
+ break;
+case 0x96: /* SUB A,(HL) */
+
+
+ x = mem_ReadByte (Regs.w.HL);
+
+ SUB_A_X (x)
+ break;
+case 0x97: /* SUB A,A */
+
+ SUB_A_X (Regs.b.A)
+ break;
+case 0x98: /* SBC A,B */
+
+ SBC_A_X (Regs.b.B)
+ break;
+case 0x99: /* SBC A,C */
+
+ SBC_A_X (Regs.b.C)
+ break;
+case 0x9A: /* SBC A,D */
+
+ SBC_A_X (Regs.b.D)
+ break;
+case 0x9B: /* SBC A,E */
+
+ SBC_A_X (Regs.b.E)
+ break;
+case 0x9C: /* SBC A,H */
+
+ SBC_A_X (Regs.b.H)
+ break;
+case 0x9D: /* SBC A,L */
+
+ SBC_A_X (Regs.b.L)
+ break;
+case 0x9E: /* SBC A,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+
+ SBC_A_X (x)
+ break;
+case 0x9F: /* SBC A,A */
+
+ SBC_A_X (Regs.b.A)
+ break;
+case 0xA0: /* AND A,B */
+
+ AND_A_X (Regs.b.B)
+ break;
+case 0xA1: /* AND A,C */
+
+ AND_A_X (Regs.b.C)
+ break;
+case 0xA2: /* AND A,D */
+
+ AND_A_X (Regs.b.D)
+ break;
+case 0xA3: /* AND A,E */
+
+ AND_A_X (Regs.b.E)
+ break;
+case 0xA4: /* AND A,H */
+
+ AND_A_X (Regs.b.H)
+ break;
+case 0xA5: /* AND A,L */
+
+ AND_A_X (Regs.b.L)
+ break;
+case 0xA6: /* AND A,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+
+ AND_A_X (x)
+ break;
+case 0xA7: /* AND A,A */
+
+ Regs.b.F = (Regs.b.A == 0) ? (FLAG_H | FLAG_Z) : FLAG_H;
+ break;
+case 0xA8: /* XOR A,B */
+
+ XOR_A_X (Regs.b.B)
+ break;
+case 0xA9: /* XOR A,C */
+
+ XOR_A_X (Regs.b.C)
+ break;
+case 0xAA: /* XOR A,D */
+
+ XOR_A_X (Regs.b.D)
+ break;
+case 0xAB: /* XOR A,E */
+
+ XOR_A_X (Regs.b.E)
+ break;
+case 0xAC: /* XOR A,H */
+
+ XOR_A_X (Regs.b.H)
+ break;
+case 0xAD: /* XOR A,L */
+
+ XOR_A_X (Regs.b.L)
+ break;
+case 0xAE: /* XOR A,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+
+ XOR_A_X (x)
+ break;
+case 0xAF: /* XOR A,A */
+
+ XOR_A_X (Regs.b.A)
+ break;
+case 0xB0: /* OR A,B */
+
+ OR_A_X (Regs.b.B)
+ break;
+case 0xB1: /* OR A,C */
+
+ OR_A_X (Regs.b.C)
+ break;
+case 0xB2: /* OR A,D */
+
+ OR_A_X (Regs.b.D)
+ break;
+case 0xB3: /* OR A,E */
+
+ OR_A_X (Regs.b.E)
+ break;
+case 0xB4: /* OR A,H */
+
+ OR_A_X (Regs.b.H)
+ break;
+case 0xB5: /* OR A,L */
+
+ OR_A_X (Regs.b.L)
+ break;
+case 0xB6: /* OR A,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+
+ OR_A_X (x)
+ break;
+case 0xB7: /* OR A,A */
+
+ OR_A_X (Regs.b.A)
+ break;
+case 0xB8: /* CP A,B */
+
+ CP_A_X (Regs.b.B)
+ break;
+case 0xB9: /* CP A,C */
+
+ CP_A_X (Regs.b.C)
+ break;
+case 0xBA: /* CP A,D */
+
+ CP_A_X (Regs.b.D)
+ break;
+case 0xBB: /* CP A,E */
+
+ CP_A_X (Regs.b.E)
+ break;
+case 0xBC: /* CP A,H */
+
+ CP_A_X (Regs.b.H)
+ break;
+case 0xBD: /* CP A,L */
+
+ CP_A_X (Regs.b.L)
+ break;
+case 0xBE: /* CP A,(HL) */
+
+ x = mem_ReadByte (Regs.w.HL);
+
+ CP_A_X (x)
+ break;
+case 0xBF: /* CP A,A */
+
+ CP_A_X (Regs.b.A)
+ break;
+case 0xC0: /* RET NZ */
+
+ if (!(Regs.b.F & FLAG_Z))
+ {
+ Regs.w.PC = mem_ReadWord (Regs.w.SP);
+ Regs.w.SP += 2;
+ CYCLES_PASSED( 12 );
+ }
+ break;
+case 0xC1: /* POP BC */
+
+ Regs.w.BC = mem_ReadWord (Regs.w.SP);
+ Regs.w.SP += 2;
+ break;
+case 0xC2: /* JP NZ,n16 */
+
+ if (Regs.b.F & FLAG_Z)
+ {
+ Regs.w.PC += 2;
+ }
+ else
+ {
+ Regs.w.PC = mem_ReadWord (Regs.w.PC);
+ CYCLES_PASSED( 4 );
+ }
+ break;
+case 0xC3: /* JP n16 */
+
+ Regs.w.PC = mem_ReadWord (Regs.w.PC);
+ break;
+case 0xC4: /* CALL NZ,n16 */
+
+ if (Regs.b.F & FLAG_Z)
+ {
+ Regs.w.PC += 2;
+ }
+ else
+ {
+ register UINT16 PC;
+ PC = mem_ReadWord (Regs.w.PC);
+ Regs.w.PC += 2;
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = PC;
+ CYCLES_PASSED( 12 );
+ }
+ break;
+case 0xC5: /* PUSH BC */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.BC);
+ break;
+case 0xC6: /* ADD A,n8 */
+
+ x = mem_ReadByte (Regs.w.PC++);
+ ADD_A_X (x)
+ break;
+case 0xC7: /* RST 0 */
+
+ {
+ register UINT16 PC;
+ PC = Regs.w.PC;
+ Regs.w.PC = 0;
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, PC);
+ }
+ break;
+case 0xC8: /* RET Z */
+
+ if (Regs.b.F & FLAG_Z)
+ {
+ Regs.w.PC = mem_ReadWord (Regs.w.SP);
+ Regs.w.SP += 2;
+ CYCLES_PASSED( 12 );
+ }
+ break;
+case 0xC9: /* RET */
+
+ Regs.w.PC = mem_ReadWord (Regs.w.SP);
+ Regs.w.SP += 2;
+ break;
+case 0xCA: /* JP Z,n16 */
+
+ if (Regs.b.F & FLAG_Z)
+ {
+ Regs.w.PC = mem_ReadWord (Regs.w.PC);
+ CYCLES_PASSED( 4 );
+ }
+ else
+ {
+ Regs.w.PC += 2;
+ }
+ break;
+case 0xCB: /* PREFIX! */
+ x = mem_ReadByte (Regs.w.PC++);
+ CYCLES_PASSED( CyclesCB[x] );
+ switch (x)
+ {
+ #include "opc_cb.h"
+ }
+ break;
+case 0xCC: /* CALL Z,n16 */
+
+ if (Regs.b.F & FLAG_Z)
+ {
+ register UINT16 PC;
+ PC = mem_ReadWord (Regs.w.PC);
+ Regs.w.PC += 2;
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = PC;
+ CYCLES_PASSED( 12 );
+ }
+ else
+ {
+ Regs.w.PC += 2;
+ }
+ break;
+case 0xCD: /* CALL n16 */
+ {
+ register UINT16 PC;
+ PC = mem_ReadWord (Regs.w.PC);
+ Regs.w.PC += 2;
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = PC;
+ }
+ break;
+case 0xCE: /* ADC A,n8 */
+
+ x = mem_ReadByte (Regs.w.PC++);
+ ADC_A_X (x)
+ break;
+case 0xCF: /* RST 8 */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = 8;
+ break;
+case 0xD0: /* RET NC */
+
+ if (!(Regs.b.F & FLAG_C))
+ {
+ Regs.w.PC = mem_ReadWord (Regs.w.SP);
+ Regs.w.SP += 2;
+ CYCLES_PASSED( 12 );
+ }
+ break;
+case 0xD1: /* POP DE */
+
+ Regs.w.DE = mem_ReadWord (Regs.w.SP);
+ Regs.w.SP += 2;
+ break;
+case 0xD2: /* JP NC,n16 */
+
+ if (Regs.b.F & FLAG_C)
+ {
+ Regs.w.PC += 2;
+ }
+ else
+ {
+ Regs.w.PC = mem_ReadWord (Regs.w.PC);
+ CYCLES_PASSED( 4 );
+ }
+ break;
+case 0xD3: /* EH? */
+ break;
+case 0xD4: /* CALL NC,n16 */
+
+ if (Regs.b.F & FLAG_C)
+ {
+ Regs.w.PC += 2;
+ }
+ else
+ {
+ register UINT16 PC;
+ PC = mem_ReadWord (Regs.w.PC);
+ Regs.w.PC += 2;
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = PC;
+ CYCLES_PASSED( 12 );
+ }
+ break;
+case 0xD5: /* PUSH DE */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.DE);
+ break;
+case 0xD6: /* SUB A,n8 */
+
+ x = mem_ReadByte (Regs.w.PC++);
+ SUB_A_X (x)
+ break;
+case 0xD7: /* RST $10 */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = 0x10;
+ break;
+case 0xD8: /* RET C */
+
+ if (Regs.b.F & FLAG_C)
+ {
+ Regs.w.PC = mem_ReadWord (Regs.w.SP);
+ Regs.w.SP += 2;
+ CYCLES_PASSED( 12 );
+ }
+ break;
+case 0xD9: /* RETI */
+
+ Regs.w.PC = mem_ReadWord (Regs.w.SP);
+ Regs.w.SP += 2;
+ Regs.w.enable |= IME;
+ break;
+case 0xDA: /* JP C,n16 */
+
+ if (Regs.b.F & FLAG_C)
+ {
+ Regs.w.PC = mem_ReadWord (Regs.w.PC);
+ CYCLES_PASSED( 4 );
+ }
+ else
+ {
+ Regs.w.PC += 2;
+ }
+ break;
+case 0xDB: /* EH? */
+ break;
+case 0xDC: /* CALL C,n16 */
+
+ if (Regs.b.F & FLAG_C)
+ {
+ register UINT16 PC;
+ PC = mem_ReadWord (Regs.w.PC);
+ Regs.w.PC += 2;
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = PC;
+ CYCLES_PASSED( 12 );
+ }
+ else
+ {
+ Regs.w.PC += 2;
+ }
+ break;
+case 0xDD: /* EH? */
+ break;
+case 0xDE: /* SBC A,n8 */
+
+ x = mem_ReadByte (Regs.w.PC++);
+ SBC_A_X (x)
+ break;
+case 0xDF: /* RST $18 */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = 0x18;
+ break;
+case 0xE0: /* LD ($FF00+n8),A */
+ mem_WriteByte (mem_ReadByte (Regs.w.PC++) + 0xFF00, Regs.b.A);
+ break;
+case 0xE1: /* POP HL */
+
+ Regs.w.HL = mem_ReadWord (Regs.w.SP);
+ Regs.w.SP += 2;
+ break;
+case 0xE2: /* LD ($FF00+C),A */
+
+ mem_WriteByte ((UINT16) (0xFF00 + Regs.b.C), Regs.b.A);
+ break;
+case 0xE3: /* EH? */
+ break;
+case 0xE4: /* EH? */
+ break;
+case 0xE5: /* PUSH HL */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.HL);
+ break;
+case 0xE6: /* AND A,n8 */
+
+ x = mem_ReadByte (Regs.w.PC++);
+ AND_A_X (x)
+ break;
+case 0xE7: /* RST $20 */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = 0x20;
+ break;
+case 0xE8: /* ADD SP,n8 */
+/*
+ * Z - Reset.
+ * N - Reset.
+ * H - Set or reset according to operation.
+ * C - Set or reset according to operation.
+ */
+
+ {
+ register INT32 n;
+
+ n = (INT32) ((INT8) mem_ReadByte (Regs.w.PC++));
+
+ if ( ( Regs.w.SP & 0xFF ) + (UINT8)(n & 0xFF) > 0xFF )
+ {
+ Regs.b.F = FLAG_C;
+ }
+ else
+ {
+ Regs.b.F = 0;
+ }
+
+ if ( ( Regs.w.SP & 0x0F ) + ( n & 0x0F ) > 0x0F )
+ {
+ Regs.b.F |= FLAG_H;
+ }
+
+ Regs.w.SP = (UINT16) ( Regs.w.SP + n );
+ }
+ break;
+case 0xE9: /* JP (HL) */
+
+ Regs.w.PC = Regs.w.HL;
+ break;
+case 0xEA: /* LD (n16),A */
+
+ mem_WriteByte (mem_ReadWord (Regs.w.PC), Regs.b.A);
+ Regs.w.PC += 2;
+ break;
+case 0xEB: /* EH? */
+ break;
+case 0xEC: /* EH? */
+ break;
+case 0xED: /* EH? */
+ break;
+case 0xEE: /* XOR A,n8 */
+
+ x = mem_ReadByte (Regs.w.PC++);
+ XOR_A_X (x)
+ break;
+case 0xEF: /* RST $28 */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = 0x28;
+ break;
+case 0xF0: /* LD A,($FF00+n8) */
+
+ Regs.b.A = mem_ReadByte (0xFF00 + mem_ReadByte (Regs.w.PC++));
+ break;
+case 0xF1: /* POP AF */
+
+ Regs.w.AF = (UINT16) (mem_ReadWord (Regs.w.SP) & 0xFFF0);
+ Regs.w.SP += 2;
+ break;
+case 0xF2: /* LD A,($FF00+C) */
+
+ Regs.b.A = mem_ReadByte ((UINT16) (0xFF00 + Regs.b.C));
+ break;
+case 0xF3: /* DI */
+ Regs.w.ei_delay = 0;
+ Regs.w.enable &= ~IME;
+ break;
+case 0xF4: /* EH? */
+ break;
+case 0xF5: /* PUSH AF */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, (UINT16) (Regs.w.AF & 0xFFF0));
+ break;
+case 0xF6: /* OR A,n8 */
+
+ x = mem_ReadByte (Regs.w.PC++);
+ OR_A_X (x)
+ break;
+case 0xF7: /* RST $30 */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = 0x30;
+ break;
+case 0xF8: /* LD HL,SP+n8 */
+/*
+ * n = one UINT8 signed immediate value.
+ * Flags affected:
+ * Z - Reset.
+ * N - Reset.
+ * H - Set or reset according to operation.
+ * C - Set or reset according to operation.
+ *
+ */
+
+ {
+ register INT32 n;
+
+ n = (INT32) ((INT8) mem_ReadByte (Regs.w.PC++));
+
+ if ( ( Regs.w.SP & 0xFF ) + (UINT8)(n & 0xFF) > 0xFF )
+ {
+ Regs.b.F = FLAG_C;
+ }
+ else
+ {
+ Regs.b.F = 0;
+ }
+
+ if ( ( Regs.w.SP & 0x0F ) + ( n & 0x0F ) > 0x0F )
+ {
+ Regs.b.F |= FLAG_H;
+ }
+
+ Regs.w.HL = (UINT16) ( Regs.w.SP + n );
+ }
+ break;
+case 0xF9: /* LD SP,HL */
+
+ Regs.w.SP = Regs.w.HL;
+ break;
+case 0xFA: /* LD A,(n16) */
+
+ Regs.b.A = mem_ReadByte (mem_ReadWord (Regs.w.PC));
+ Regs.w.PC += 2;
+ break;
+case 0xFB: /* EI */
+
+ Regs.w.enable |= IME;
+ Regs.w.ei_delay = 1;
+ break;
+case 0xFC: /* EH? */
+ break;
+case 0xFD: /* EH? */
+ break;
+case 0xFE: /* CP A,n8 */
+
+ x = mem_ReadByte (Regs.w.PC++);
+ CP_A_X (x)
+ break;
+case 0xFF: /* RST $38 */
+
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = 0x38;
+ break;
diff --git a/src/emu/cpu/z80gb/z80gb.c b/src/emu/cpu/z80gb/z80gb.c
new file mode 100644
index 00000000000..99ca7773bdd
--- /dev/null
+++ b/src/emu/cpu/z80gb/z80gb.c
@@ -0,0 +1,485 @@
+/*************************************************************/
+/** **/
+/** z80gb.c **/
+/** **/
+/** This file contains implementation for the GameBoy CPU. **/
+/** See z80gb.h for the relevant definitions. Please, note **/
+/** that this code can not be used to emulate a generic Z80 **/
+/** because the GameBoy version of it differs from Z80 in **/
+/** many ways. **/
+/** **/
+/** Orginal cpu code (PlayBoy) Carsten Sorensen 1998 **/
+/** MESS modifications Hans de Goede 1998 **/
+/** Adapted to new cpuintrf Juergen Buchmueller 2000 **/
+/** Adapted to new cpuintrf Anthony Kruize 2002 **/
+/** Changed reset function to **/
+/** reset all registers instead **/
+/** of just AF. Wilbert Pol 2004 **/
+/** **/
+/** 1.1: **/
+/** Removed dependency on the mess gameboy driver **/
+/** **/
+/** 1.2: **/
+/** Fixed cycle count for taking an interrupt **/
+/** Fixed cycle count for BIT X,(HL) instructions **/
+/** Fixed flags in RRCA instruction **/
+/** Fixed DAA instruction **/
+/** Fixed flags in ADD SP,n8 instruction **/
+/** Fixed flags in LD HL,SP+n8 instruction **/
+/** **/
+/** 1.3: **/
+/** Improved triggering of the HALT bug **/
+/** Added 4 cycle penalty when leaving HALT state for **/
+/** newer versions of the cpu core **/
+/** **/
+/*************************************************************/
+#include "z80gb.h"
+#include "debugger.h"
+
+#define FLAG_Z 0x80
+#define FLAG_N 0x40
+#define FLAG_H 0x20
+#define FLAG_C 0x10
+
+#define CYCLES_PASSED(X) z80gb_ICount -= ((X) / (Regs.w.gb_speed)); \
+ if ( Regs.w.timer_callback ) { \
+ Regs.w.timer_callback( X ); \
+ }
+
+typedef struct {
+ UINT16 AF;
+ UINT16 BC;
+ UINT16 DE;
+ UINT16 HL;
+
+ UINT16 SP;
+ UINT16 PC;
+ /* Interrupt related */
+ UINT8 IE;
+ UINT8 IF;
+ int irq_state;
+ int ei_delay;
+ int (*irq_callback)(int irqline);
+ /* Timer stuff */
+ void (*timer_callback)(int cycles);
+ /* Others */
+ int gb_speed;
+ int gb_speed_change_pending;
+ int enable;
+ int doHALTbug;
+ int haltIFstatus;
+ UINT8 features;
+ const Z80GB_CONFIG *config;
+} z80gb_16BitRegs;
+
+#ifdef LSB_FIRST
+typedef struct {
+ UINT8 F;
+ UINT8 A;
+ UINT8 C;
+ UINT8 B;
+ UINT8 E;
+ UINT8 D;
+ UINT8 L;
+ UINT8 H;
+} z80gb_8BitRegs;
+#else
+typedef struct {
+ UINT8 A;
+ UINT8 F;
+ UINT8 B;
+ UINT8 C;
+ UINT8 D;
+ UINT8 E;
+ UINT8 H;
+ UINT8 L;
+} z80gb_8BitRegs;
+#endif
+
+typedef union {
+ z80gb_16BitRegs w;
+ z80gb_8BitRegs b;
+} z80gb_regs;
+
+typedef int (*OpcodeEmulator) (void);
+
+static z80gb_regs Regs;
+
+#define IME 0x01
+#define HALTED 0x02
+
+/****************************************************************************/
+/* Memory functions */
+/****************************************************************************/
+
+#define mem_ReadByte(A) ((UINT8)program_read_byte_8(A))
+#define mem_WriteByte(A,V) (program_write_byte_8(A,V))
+
+INLINE UINT16 mem_ReadWord (UINT32 address)
+{
+ UINT16 value = (UINT16) mem_ReadByte ((address + 1) & 0xffff) << 8;
+ value |= mem_ReadByte (address);
+ return value;
+}
+
+INLINE void mem_WriteWord (UINT32 address, UINT16 value)
+{
+ mem_WriteByte (address, value & 0xFF);
+ mem_WriteByte ((address + 1) & 0xffff, value >> 8);
+}
+
+/* Nr of cycles to run */
+int z80gb_ICount;
+
+static int Cycles[256] =
+{
+ 4,12, 8, 8, 4, 4, 8, 4,20, 8, 8, 8, 4, 4, 8, 4,
+ 4,12, 8, 8, 4, 4, 8, 4,12, 8, 8, 8, 4, 4, 8, 4,
+ 8,12, 8, 8, 4, 4, 8, 4, 8, 8, 8, 8, 4, 4, 8, 4,
+ 8,12, 8, 8,12,12,12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 8, 8, 8, 8, 8, 8, 4, 8, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 8,12,12,16,12,16, 8,16, 8,16,12, 0,12,24, 8,16,
+ 8,12,12, 4,12,16, 8,16, 8,16,12, 4,12, 4, 8,16,
+ 12,12, 8, 4, 4,16, 8,16,16, 4,16, 4, 4, 4, 8,16,
+ 12,12, 8, 4, 4,16, 8,16,12, 8,16, 4, 4, 4, 8,16
+};
+
+static int CyclesCB[256] =
+{
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
+ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
+ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
+ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
+ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8
+};
+
+static void z80gb_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ Regs.w.config = (const Z80GB_CONFIG *) config;
+ Regs.w.irq_callback = irqcallback;
+}
+
+/*** Reset Z80 registers: *********************************/
+/*** This function can be used to reset the register ***/
+/*** file before starting execution with z80gb_execute()***/
+/*** It sets the registers to their initial values. ***/
+/**********************************************************/
+static void z80gb_reset(void)
+{
+ Regs.w.AF = 0x0000;
+ Regs.w.BC = 0x0000;
+ Regs.w.DE = 0x0000;
+ Regs.w.HL = 0x0000;
+ Regs.w.SP = 0x0000;
+ Regs.w.PC = 0x0000;
+ Regs.w.timer_callback = NULL;
+ Regs.w.features = Z80GB_FEATURE_HALT_BUG;
+ if (Regs.w.config)
+ {
+ if ( Regs.w.config->regs ) {
+ Regs.w.AF = Regs.w.config->regs[0];
+ Regs.w.BC = Regs.w.config->regs[1];
+ Regs.w.DE = Regs.w.config->regs[2];
+ Regs.w.HL = Regs.w.config->regs[3];
+ Regs.w.SP = Regs.w.config->regs[4];
+ Regs.w.PC = Regs.w.config->regs[5];
+ }
+ Regs.w.timer_callback = Regs.w.config->timer_callback;
+ Regs.w.features = Regs.w.config->features;
+ }
+ Regs.w.enable = 0;
+ Regs.w.IE = 0;
+ Regs.w.IF = 0;
+
+ Regs.w.doHALTbug = 0;
+ Regs.w.ei_delay = 0;
+ Regs.w.gb_speed_change_pending = 0;
+ Regs.w.gb_speed = 1;
+}
+
+INLINE void z80gb_ProcessInterrupts (void)
+{
+ UINT8 irq = Regs.w.IE & Regs.w.IF;
+
+ /* Interrupts should be taken after the first instruction after an EI instruction */
+ if (Regs.w.ei_delay) {
+ Regs.w.ei_delay = 0;
+ return;
+ }
+
+ /*
+ logerror("Attempting to process Z80GB Interrupt IRQ $%02X\n", irq);
+ logerror("Attempting to process Z80GB Interrupt IE $%02X\n", Regs.w.IE);
+ logerror("Attempting to process Z80GB Interrupt IF $%02X\n", Regs.w.IF);
+ */
+ if (irq)
+ {
+ int irqline = 0;
+ /*
+ logerror("Z80GB Interrupt IRQ $%02X\n", irq);
+ */
+
+ for( ; irqline < 5; irqline++ )
+ {
+ if( irq & (1<<irqline) )
+ {
+ if (Regs.w.enable & HALTED)
+ {
+ Regs.w.enable &= ~HALTED;
+ Regs.w.IF &= ~(1 << irqline);
+ Regs.w.PC++;
+ if ( ! Regs.w.enable & IME ) {
+ if ( Regs.w.features & Z80GB_FEATURE_HALT_BUG ) {
+ /* Old cpu core (dmg/mgb/sgb) */
+ /* check if the HALT bug should be performed */
+ if ( Regs.w.haltIFstatus ) {
+ Regs.w.doHALTbug = 1;
+ }
+ } else {
+ /* New cpu core (cgb/agb/ags) */
+ CYCLES_PASSED( 4 );
+ }
+ }
+ }
+ if ( Regs.w.enable & IME ) {
+ if ( Regs.w.irq_callback )
+ (*Regs.w.irq_callback)(irqline);
+ Regs.w.enable &= ~IME;
+ Regs.w.IF &= ~(1 << irqline);
+ CYCLES_PASSED( 20 );
+ Regs.w.SP -= 2;
+ mem_WriteWord (Regs.w.SP, Regs.w.PC);
+ Regs.w.PC = 0x40 + irqline * 8;
+ /*logerror("Z80GB Interrupt PC $%04X\n", Regs.w.PC );*/
+ return;
+ }
+ }
+ }
+ }
+}
+
+/**********************************************************/
+/*** Execute z80gb code for cycles cycles, return nr of ***/
+/*** cycles actually executed. ***/
+/**********************************************************/
+static int z80gb_execute (int cycles)
+{
+ UINT8 x;
+
+ z80gb_ICount = cycles;
+
+ do
+ {
+ z80gb_ProcessInterrupts ();
+ CALL_MAME_DEBUG;
+ if ( Regs.w.enable & HALTED ) {
+ CYCLES_PASSED( Cycles[0x76] );
+ } else {
+ x = mem_ReadByte (Regs.w.PC++);
+ if ( Regs.w.doHALTbug ) {
+ Regs.w.PC--;
+ Regs.w.doHALTbug = 0;
+ }
+ CYCLES_PASSED( Cycles[x] );
+ switch (x)
+ {
+#include "opc_main.h"
+ }
+ }
+ } while (z80gb_ICount > 0);
+
+ return cycles - z80gb_ICount;
+}
+
+static void z80gb_burn(int cycles)
+{
+ if( cycles > 0 )
+ {
+ /* NOP takes 4 cycles per instruction */
+ int n = (cycles + 3) / 4;
+ z80gb_ICount -= 4 * n;
+ }
+}
+
+/****************************************************************************/
+/* Set all registers to given values */
+/****************************************************************************/
+static void z80gb_set_context (void *src)
+{
+ if( src )
+ Regs = *(z80gb_regs *)src;
+ change_pc(Regs.w.PC);
+}
+
+/****************************************************************************/
+/* Get all registers in given buffer */
+/****************************************************************************/
+static void z80gb_get_context (void *dst)
+{
+ if( dst )
+ *(z80gb_regs *)dst = Regs;
+}
+
+
+
+static void z80gb_set_irq_line (int irqline, int state)
+{
+ /*logerror("setting irq line 0x%02x state 0x%08x\n", irqline, state);*/
+ //if( Regs.w.irq_state == state )
+ // return;
+
+ Regs.w.irq_state = state;
+ if( state == ASSERT_LINE )
+ {
+
+ Regs.w.IF |= (0x01 << irqline);
+ /*logerror("Z80GB assert irq line %d ($%02X)\n", irqline, Regs.w.IF);*/
+
+ }
+ else
+ {
+
+ Regs.w.IF &= ~(0x01 << irqline);
+ /*logerror("Z80GB clear irq line %d ($%02X)\n", irqline, Regs.w.IF);*/
+
+ }
+}
+
+/*static void z80gb_clear_pending_interrupts (void)
+{
+ Regs.w.IF = 0;
+}*/
+
+static void z80gb_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0:
+ case CPUINFO_INT_INPUT_STATE + 1:
+ case CPUINFO_INT_INPUT_STATE + 2:
+ case CPUINFO_INT_INPUT_STATE + 3:
+ case CPUINFO_INT_INPUT_STATE + 4: z80gb_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); break;
+
+ case CPUINFO_INT_SP: Regs.w.SP = info->i; break;
+ case CPUINFO_INT_PC: Regs.w.PC = info->i; change_pc(Regs.w.PC); break;
+
+ case CPUINFO_INT_REGISTER + Z80GB_PC: Regs.w.PC = info->i; change_pc(Regs.w.PC); break;
+ case CPUINFO_INT_REGISTER + Z80GB_SP: Regs.w.SP = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80GB_AF: Regs.w.AF = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80GB_BC: Regs.w.BC = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80GB_DE: Regs.w.DE = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80GB_HL: Regs.w.HL = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80GB_IE: Regs.w.IE = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80GB_IF: Regs.w.IF = info->i; break;
+ case CPUINFO_INT_REGISTER + Z80GB_SPEED: Regs.w.gb_speed_change_pending = info->i & 0x01; break;
+ }
+}
+
+void z80gb_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(Regs); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; /* right? */ break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 16; /* right? */ break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_SP: info->i = Regs.w.SP; break;
+ case CPUINFO_INT_PC: info->i = Regs.w.PC; break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* TODO??? */ break;
+
+ case CPUINFO_INT_INPUT_STATE + 0:
+ case CPUINFO_INT_INPUT_STATE + 1:
+ case CPUINFO_INT_INPUT_STATE + 2:
+ case CPUINFO_INT_INPUT_STATE + 3:
+ case CPUINFO_INT_INPUT_STATE + 4: info->i = Regs.w.IF & (1 << (state-CPUINFO_INT_INPUT_STATE)); break;
+
+ case CPUINFO_INT_REGISTER + Z80GB_PC: info->i = Regs.w.PC; break;
+ case CPUINFO_INT_REGISTER + Z80GB_SP: info->i = Regs.w.SP; break;
+ case CPUINFO_INT_REGISTER + Z80GB_AF: info->i = Regs.w.AF; break;
+ case CPUINFO_INT_REGISTER + Z80GB_BC: info->i = Regs.w.BC; break;
+ case CPUINFO_INT_REGISTER + Z80GB_DE: info->i = Regs.w.DE; break;
+ case CPUINFO_INT_REGISTER + Z80GB_HL: info->i = Regs.w.HL; break;
+ case CPUINFO_INT_REGISTER + Z80GB_IE: info->i = Regs.w.IE; break;
+ case CPUINFO_INT_REGISTER + Z80GB_IF: info->i = Regs.w.IF; break;
+ case CPUINFO_INT_REGISTER + Z80GB_SPEED: info->i = 0x7E | ( ( Regs.w.gb_speed - 1 ) << 7 ) | Regs.w.gb_speed_change_pending;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = z80gb_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = z80gb_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = z80gb_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = z80gb_init; break;
+ case CPUINFO_PTR_RESET: info->reset = z80gb_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = z80gb_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = z80gb_burn; break;
+
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = z80gb_dasm; break;
+#endif
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &z80gb_ICount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "Z80GB"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Nintendo Z80"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.3"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2000 by The MESS Team."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ Regs.b.F & 0x80 ? 'Z':'.',
+ Regs.b.F & 0x40 ? 'N':'.',
+ Regs.b.F & 0x20 ? 'H':'.',
+ Regs.b.F & 0x10 ? 'C':'.',
+ Regs.b.F & 0x08 ? '3':'.',
+ Regs.b.F & 0x04 ? '2':'.',
+ Regs.b.F & 0x02 ? '1':'.',
+ Regs.b.F & 0x01 ? '0':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + Z80GB_PC: sprintf(info->s, "PC:%04X", Regs.w.PC); break;
+ case CPUINFO_STR_REGISTER + Z80GB_SP: sprintf(info->s, "SP:%04X", Regs.w.SP); break;
+ case CPUINFO_STR_REGISTER + Z80GB_AF: sprintf(info->s, "AF:%04X", Regs.w.AF); break;
+ case CPUINFO_STR_REGISTER + Z80GB_BC: sprintf(info->s, "BC:%04X", Regs.w.BC); break;
+ case CPUINFO_STR_REGISTER + Z80GB_DE: sprintf(info->s, "DE:%04X", Regs.w.DE); break;
+ case CPUINFO_STR_REGISTER + Z80GB_HL: sprintf(info->s, "HL:%04X", Regs.w.HL); break;
+ case CPUINFO_STR_REGISTER + Z80GB_IRQ_STATE: sprintf(info->s, "IRQ:%X", Regs.w.enable & IME ); break;
+ case CPUINFO_STR_REGISTER + Z80GB_IE: sprintf(info->s, "IE:%02X", Regs.w.IE); break;
+ case CPUINFO_STR_REGISTER + Z80GB_IF: sprintf(info->s, "IF:%02X", Regs.w.IF); break;
+ }
+}
diff --git a/src/emu/cpu/z80gb/z80gb.h b/src/emu/cpu/z80gb/z80gb.h
new file mode 100644
index 00000000000..aca87845348
--- /dev/null
+++ b/src/emu/cpu/z80gb/z80gb.h
@@ -0,0 +1,34 @@
+#ifndef z80gb_H
+#define z80gb_H
+
+#include "cpuintrf.h"
+
+extern int z80gb_ICount;
+
+typedef struct {
+ UINT16 *regs;
+ UINT8 features;
+ void (*timer_callback)(int cycles);
+} Z80GB_CONFIG;
+
+enum {
+ Z80GB_PC=1, Z80GB_SP, Z80GB_AF, Z80GB_BC, Z80GB_DE, Z80GB_HL,
+ Z80GB_IRQ_STATE,
+ /* Pseudo registers to keep track of the interrupt statuses */
+ Z80GB_IE, Z80GB_IF,
+ /* Pseudo register to change and check the cpu operating speed */
+ Z80GB_SPEED,
+};
+
+#define Z80GB_FEATURE_HALT_BUG 0x01
+
+/****************************************************************************/
+/* Return register contents */
+/****************************************************************************/
+extern void z80gb_get_info(UINT32 state, cpuinfo *info);
+
+#ifdef MAME_DEBUG
+extern unsigned z80gb_dasm( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram );
+#endif /* MAME_DEBUG */
+
+#endif
diff --git a/src/emu/cpu/z80gb/z80gbd.c b/src/emu/cpu/z80gb/z80gbd.c
new file mode 100644
index 00000000000..0989ed1e171
--- /dev/null
+++ b/src/emu/cpu/z80gb/z80gbd.c
@@ -0,0 +1,288 @@
+/*****************************************************************************
+ *
+ * z80gbd.c
+ * Portable Z80 Gameboy disassembler
+ *
+ * Copyright (C) 2000 by The MESS Team.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "z80gb.h"
+
+enum e_mnemonics
+{
+ zADC, zADD, zAND, zBIT, zCALL, zCCF, zCP,
+ zCPL, zDAA, zDB, zDEC, zDI, zEI, zHLT,
+ zIN, zINC, zJP, zJR, zLD, zNOP, zOR,
+ zPOP, zPUSH, zRES, zRET, zRETI, zRL, zRLA,
+ zRLC, zRLCA, zRR, zRRA, zRRC, zRRCA, zRST,
+ zSBC, zSCF, zSET, zSLA, zSLL, zSRA, zSRL,
+ zSTOP, zSUB, zXOR, zSWAP
+};
+
+static const char *s_mnemonic[] =
+{
+ "adc", "add", "and", "bit", "call","ccf", "cp",
+ "cpl", "daa", "db", "dec", "di", "ei", "halt",
+ "in", "inc", "jp", "jr", "ld", "nop", "or",
+ "pop", "push","res", "ret", "reti","rl", "rla",
+ "rlc", "rlca","rr", "rra", "rrc", "rrca","rst",
+ "sbc", "scf", "set", "sla", "sll", "sra", "srl",
+ "stop","sub", "xor", "swap"
+};
+
+#define _OVER DASMFLAG_STEP_OVER
+#define _OUT DASMFLAG_STEP_OUT
+
+static const UINT32 s_flags[] = {
+ 0 ,0 ,0 ,0 ,_OVER,0 ,0 ,
+ 0 ,0 ,0 ,0 ,0 ,0 ,_OVER,
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ 0 ,0 ,0 ,_OUT ,_OUT ,0 ,0 ,
+ 0 ,0 ,0 ,0 ,0 ,0 ,_OVER,
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ _OVER,0 ,0 ,0
+};
+
+typedef struct
+{
+ UINT8 mnemonic;
+ const char *arguments;
+} z80gbdasm;
+
+static z80gbdasm mnemonic_cb[256] = {
+ {zRLC,"b"}, {zRLC,"c"}, {zRLC,"d"}, {zRLC,"e"},
+ {zRLC,"h"}, {zRLC,"l"}, {zRLC,"(hl)"}, {zRLC,"a"},
+ {zRRC,"b"}, {zRRC,"c"}, {zRRC,"d"}, {zRRC,"e"},
+ {zRRC,"h"}, {zRRC,"l"}, {zRRC,"(hl)"}, {zRRC,"a"},
+ {zRL,"b"}, {zRL,"c"}, {zRL,"d"}, {zRL,"e"},
+ {zRL,"h"}, {zRL,"l"}, {zRL,"(hl)"}, {zRL,"a"},
+ {zRR,"b"}, {zRR,"c"}, {zRR,"d"}, {zRR,"e"},
+ {zRR,"h"}, {zRR,"l"}, {zRR,"(hl)"}, {zRR,"a"},
+ {zSLA,"b"}, {zSLA,"c"}, {zSLA,"d"}, {zSLA,"e"},
+ {zSLA,"h"}, {zSLA,"l"}, {zSLA,"(hl)"}, {zSLA,"a"},
+ {zSRA,"b"}, {zSRA,"c"}, {zSRA,"d"}, {zSRA,"e"},
+ {zSRA,"h"}, {zSRA,"l"}, {zSRA,"(hl)"}, {zSRA,"a"},
+ {zSWAP,"b"}, {zSWAP,"c"}, {zSWAP,"d"}, {zSWAP,"e"},
+ {zSWAP,"h"}, {zSWAP,"l"}, {zSWAP,"(hl)"}, {zSWAP,"a"},
+ {zSRL,"b"}, {zSRL,"c"}, {zSRL,"d"}, {zSRL,"e"},
+ {zSRL,"h"}, {zSRL,"l"}, {zSRL,"(hl)"}, {zSRL,"a"},
+ {zBIT,"0,b"}, {zBIT,"0,c"}, {zBIT,"0,d"}, {zBIT,"0,e"},
+ {zBIT,"0,h"}, {zBIT,"0,l"}, {zBIT,"0,(hl)"},{zBIT,"0,a"},
+ {zBIT,"1,b"}, {zBIT,"1,c"}, {zBIT,"1,d"}, {zBIT,"1,e"},
+ {zBIT,"1,h"}, {zBIT,"1,l"}, {zBIT,"1,(hl)"},{zBIT,"1,a"},
+ {zBIT,"2,b"}, {zBIT,"2,c"}, {zBIT,"2,d"}, {zBIT,"2,e"},
+ {zBIT,"2,h"}, {zBIT,"2,l"}, {zBIT,"2,(hl)"},{zBIT,"2,a"},
+ {zBIT,"3,b"}, {zBIT,"3,c"}, {zBIT,"3,d"}, {zBIT,"3,e"},
+ {zBIT,"3,h"}, {zBIT,"3,l"}, {zBIT,"3,(hl)"},{zBIT,"3,a"},
+ {zBIT,"4,b"}, {zBIT,"4,c"}, {zBIT,"4,d"}, {zBIT,"4,e"},
+ {zBIT,"4,h"}, {zBIT,"4,l"}, {zBIT,"4,(hl)"},{zBIT,"4,a"},
+ {zBIT,"5,b"}, {zBIT,"5,c"}, {zBIT,"5,d"}, {zBIT,"5,e"},
+ {zBIT,"5,h"}, {zBIT,"5,l"}, {zBIT,"5,(hl)"},{zBIT,"5,a"},
+ {zBIT,"6,b"}, {zBIT,"6,c"}, {zBIT,"6,d"}, {zBIT,"6,e"},
+ {zBIT,"6,h"}, {zBIT,"6,l"}, {zBIT,"6,(hl)"},{zBIT,"6,a"},
+ {zBIT,"7,b"}, {zBIT,"7,c"}, {zBIT,"7,d"}, {zBIT,"7,e"},
+ {zBIT,"7,h"}, {zBIT,"7,l"}, {zBIT,"7,(hl)"},{zBIT,"7,a"},
+ {zRES,"0,b"}, {zRES,"0,c"}, {zRES,"0,d"}, {zRES,"0,e"},
+ {zRES,"0,h"}, {zRES,"0,l"}, {zRES,"0,(hl)"},{zRES,"0,a"},
+ {zRES,"1,b"}, {zRES,"1,c"}, {zRES,"1,d"}, {zRES,"1,e"},
+ {zRES,"1,h"}, {zRES,"1,l"}, {zRES,"1,(hl)"},{zRES,"1,a"},
+ {zRES,"2,b"}, {zRES,"2,c"}, {zRES,"2,d"}, {zRES,"2,e"},
+ {zRES,"2,h"}, {zRES,"2,l"}, {zRES,"2,(hl)"},{zRES,"2,a"},
+ {zRES,"3,b"}, {zRES,"3,c"}, {zRES,"3,d"}, {zRES,"3,e"},
+ {zRES,"3,h"}, {zRES,"3,l"}, {zRES,"3,(hl)"},{zRES,"3,a"},
+ {zRES,"4,b"}, {zRES,"4,c"}, {zRES,"4,d"}, {zRES,"4,e"},
+ {zRES,"4,h"}, {zRES,"4,l"}, {zRES,"4,(hl)"},{zRES,"4,a"},
+ {zRES,"5,b"}, {zRES,"5,c"}, {zRES,"5,d"}, {zRES,"5,e"},
+ {zRES,"5,h"}, {zRES,"5,l"}, {zRES,"5,(hl)"},{zRES,"5,a"},
+ {zRES,"6,b"}, {zRES,"6,c"}, {zRES,"6,d"}, {zRES,"6,e"},
+ {zRES,"6,h"}, {zRES,"6,l"}, {zRES,"6,(hl)"},{zRES,"6,a"},
+ {zRES,"7,b"}, {zRES,"7,c"}, {zRES,"7,d"}, {zRES,"7,e"},
+ {zRES,"7,h"}, {zRES,"7,l"}, {zRES,"7,(hl)"},{zRES,"7,a"},
+ {zSET,"0,b"}, {zSET,"0,c"}, {zSET,"0,d"}, {zSET,"0,e"},
+ {zSET,"0,h"}, {zSET,"0,l"}, {zSET,"0,(hl)"},{zSET,"0,a"},
+ {zSET,"1,b"}, {zSET,"1,c"}, {zSET,"1,d"}, {zSET,"1,e"},
+ {zSET,"1,h"}, {zSET,"1,l"}, {zSET,"1,(hl)"},{zSET,"1,a"},
+ {zSET,"2,b"}, {zSET,"2,c"}, {zSET,"2,d"}, {zSET,"2,e"},
+ {zSET,"2,h"}, {zSET,"2,l"}, {zSET,"2,(hl)"},{zSET,"2,a"},
+ {zSET,"3,b"}, {zSET,"3,c"}, {zSET,"3,d"}, {zSET,"3,e"},
+ {zSET,"3,h"}, {zSET,"3,l"}, {zSET,"3,(hl)"},{zSET,"3,a"},
+ {zSET,"4,b"}, {zSET,"4,c"}, {zSET,"4,d"}, {zSET,"4,e"},
+ {zSET,"4,h"}, {zSET,"4,l"}, {zSET,"4,(hl)"},{zSET,"4,a"},
+ {zSET,"5,b"}, {zSET,"5,c"}, {zSET,"5,d"}, {zSET,"5,e"},
+ {zSET,"5,h"}, {zSET,"5,l"}, {zSET,"5,(hl)"},{zSET,"5,a"},
+ {zSET,"6,b"}, {zSET,"6,c"}, {zSET,"6,d"}, {zSET,"6,e"},
+ {zSET,"6,h"}, {zSET,"6,l"}, {zSET,"6,(hl)"},{zSET,"6,a"},
+ {zSET,"7,b"}, {zSET,"7,c"}, {zSET,"7,d"}, {zSET,"7,e"},
+ {zSET,"7,h"}, {zSET,"7,l"}, {zSET,"7,(hl)"},{zSET,"7,a"}
+};
+
+static z80gbdasm mnemonic_main[256]= {
+ {zNOP,0}, {zLD,"bc,N"}, {zLD,"(bc),a"}, {zINC,"bc"},
+ {zINC,"b"}, {zDEC,"b"}, {zLD,"b,B"}, {zRLCA,0},
+ {zLD,"(W),sp"}, {zADD,"hl,bc"}, {zLD,"a,(bc)"}, {zDEC,"bc"},
+ {zINC,"c"}, {zDEC,"c"}, {zLD,"c,B"}, {zRRCA,0},
+ {zSTOP,0}, {zLD,"de,N"}, {zLD,"(de),a"}, {zINC,"de"},
+ {zINC,"d"}, {zDEC,"d"}, {zLD,"d,B"}, {zRLA,0},
+ {zJR,"O"}, {zADD,"hl,de"}, {zLD,"a,(de)"}, {zDEC,"de"},
+ {zINC,"e"}, {zDEC,"e"}, {zLD,"e,B"}, {zRRA,0},
+ {zJR,"nz,O"}, {zLD,"hl,N"}, {zLD,"(hl+),a"},{zINC,"hl"},
+ {zINC,"h"}, {zDEC,"h"}, {zLD,"h,B"}, {zDAA,0},
+ {zJR,"z,O"}, {zADD,"hl,hl"}, {zLD,"a,(hl+)"},{zDEC,"hl"},
+ {zINC,"l"}, {zDEC,"l"}, {zLD,"l,B"}, {zCPL,0},
+ {zJR,"nc,O"}, {zLD,"sp,N"}, {zLD,"(hl-),a"},{zINC,"sp"},
+ {zINC,"(hl)"}, {zDEC,"(hl)"}, {zLD,"(hl),B"}, {zSCF,0},
+ {zJR,"c,O"}, {zADD,"hl,sp"}, {zLD,"a,(hl-)"},{zDEC,"sp"},
+ {zINC,"a"}, {zDEC,"a"}, {zLD,"a,B"}, {zCCF,0},
+ {zLD,"b,b"}, {zLD,"b,c"}, {zLD,"b,d"}, {zLD,"b,e"},
+ {zLD,"b,h"}, {zLD,"b,l"}, {zLD,"b,(hl)"}, {zLD,"b,a"},
+ {zLD,"c,b"}, {zLD,"c,c"}, {zLD,"c,d"}, {zLD,"c,e"},
+ {zLD,"c,h"}, {zLD,"c,l"}, {zLD,"c,(hl)"}, {zLD,"c,a"},
+ {zLD,"d,b"}, {zLD,"d,c"}, {zLD,"d,d"}, {zLD,"d,e"},
+ {zLD,"d,h"}, {zLD,"d,l"}, {zLD,"d,(hl)"}, {zLD,"d,a"},
+ {zLD,"e,b"}, {zLD,"e,c"}, {zLD,"e,d"}, {zLD,"e,e"},
+ {zLD,"e,h"}, {zLD,"e,l"}, {zLD,"e,(hl)"}, {zLD,"e,a"},
+ {zLD,"h,b"}, {zLD,"h,c"}, {zLD,"h,d"}, {zLD,"h,e"},
+ {zLD,"h,h"}, {zLD,"h,l"}, {zLD,"h,(hl)"}, {zLD,"h,a"},
+ {zLD,"l,b"}, {zLD,"l,c"}, {zLD,"l,d"}, {zLD,"l,e"},
+ {zLD,"l,h"}, {zLD,"l,l"}, {zLD,"l,(hl)"}, {zLD,"l,a"},
+ {zLD,"(hl),b"}, {zLD,"(hl),c"}, {zLD,"(hl),d"}, {zLD,"(hl),e"},
+ {zLD,"(hl),h"}, {zLD,"(hl),l"}, {zHLT,0}, {zLD,"(hl),a"},
+ {zLD,"a,b"}, {zLD,"a,c"}, {zLD,"a,d"}, {zLD,"a,e"},
+ {zLD,"a,h"}, {zLD,"a,l"}, {zLD,"a,(hl)"}, {zLD,"a,a"},
+ {zADD,"a,b"}, {zADD,"a,c"}, {zADD,"a,d"}, {zADD,"a,e"},
+ {zADD,"a,h"}, {zADD,"a,l"}, {zADD,"a,(hl)"},{zADD,"a,a"},
+ {zADC,"a,b"}, {zADC,"a,c"}, {zADC,"a,d"}, {zADC,"a,e"},
+ {zADC,"a,h"}, {zADC,"a,l"}, {zADC,"a,(hl)"},{zADC,"a,a"},
+ {zSUB,"b"}, {zSUB,"c"}, {zSUB,"d"}, {zSUB,"e"},
+ {zSUB,"h"}, {zSUB,"l"}, {zSUB,"(hl)"}, {zSUB,"a"},
+ {zSBC,"a,b"}, {zSBC,"a,c"}, {zSBC,"a,d"}, {zSBC,"a,e"},
+ {zSBC,"a,h"}, {zSBC,"a,l"}, {zSBC,"a,(hl)"},{zSBC,"a,a"},
+ {zAND,"b"}, {zAND,"c"}, {zAND,"d"}, {zAND,"e"},
+ {zAND,"h"}, {zAND,"l"}, {zAND,"(hl)"}, {zAND,"a"},
+ {zXOR,"b"}, {zXOR,"c"}, {zXOR,"d"}, {zXOR,"e"},
+ {zXOR,"h"}, {zXOR,"l"}, {zXOR,"(hl)"}, {zXOR,"a"},
+ {zOR,"b"}, {zOR,"c"}, {zOR,"d"}, {zOR,"e"},
+ {zOR,"h"}, {zOR,"l"}, {zOR,"(hl)"}, {zOR,"a"},
+ {zCP,"b"}, {zCP,"c"}, {zCP,"d"}, {zCP,"e"},
+ {zCP,"h"}, {zCP,"l"}, {zCP,"(hl)"}, {zCP,"a"},
+ {zRET,"nz"}, {zPOP,"bc"}, {zJP,"nz,A"}, {zJP,"A"},
+ {zCALL,"nz,A"}, {zPUSH,"bc"}, {zADD,"a,B"}, {zRST,"V"},
+ {zRET,"z"}, {zRET,0}, {zJP,"z,A"}, {zDB,"cb"},
+ {zCALL,"z,A"}, {zCALL,"A"}, {zADC,"a,B"}, {zRST,"V"},
+ {zRET,"nc"}, {zPOP,"de"}, {zJP,"nc,A"}, {zDB,"d3"},
+ {zCALL,"nc,A"}, {zPUSH,"de"}, {zSUB,"B"}, {zRST,"V"},
+ {zRET,"c"}, {zRETI,0}, {zJP,"c,A"}, {zDB,"db"},
+ {zCALL,"c,A"}, {zDB,"dd"}, {zSBC,"a,B"}, {zRST,"V"},
+ {zLD,"(F),a"}, {zPOP,"hl"}, {zLD,"(C),a"}, {zDB,"e3"},
+ {zDB,"e4"}, {zPUSH,"hl"}, {zAND,"B"}, {zRST,"V"},
+ {zADD,"SP,B"}, {zJP,"(hl)"}, {zLD,"(W),a"}, {zDB,"eb"},
+ {zDB,"ec"}, {zDB,"ed"}, {zXOR,"B"}, {zRST,"V"},
+ {zLD,"a,(F)"}, {zPOP,"af"}, {zLD,"a,(C)"}, {zDI,0},
+ {zDB,"f4"}, {zPUSH,"af"}, {zOR,"B"}, {zRST,"V"},
+ {zLD,"hl,sp+B"},{zLD,"sp,hl"}, {zLD,"a,(W)"}, {zEI,0},
+ {zDB,"fc"}, {zDB,"fd"}, {zCP,"B"}, {zRST,"V"}
+};
+
+/****************************************************************************
+ * Disassemble opcode at PC and return number of bytes it takes
+ ****************************************************************************/
+
+unsigned z80gb_dasm( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram )
+{
+ z80gbdasm *d;
+ const char *symbol, *src;
+ char *dst;
+ INT8 offset = 0;
+ UINT8 op, op1;
+ UINT16 ea = 0;
+ int pos = 0;
+
+ dst = buffer;
+ symbol = NULL;
+
+ op = oprom[pos++];
+ op1 = 0; /* keep GCC happy */
+
+ if( op == 0xcb ) {
+ op = oprom[pos++];
+ d = &mnemonic_cb[op];
+ } else {
+ d = &mnemonic_main[op];
+ }
+
+ if( d->arguments ) {
+ dst += sprintf(dst, "%-4s ", s_mnemonic[d->mnemonic]);
+ src = d->arguments;
+ while( *src ) {
+ switch( *src ) {
+ case '?': /* illegal opcode */
+ dst += sprintf( dst, "$%02X,$%02X", op, op1);
+ break;
+ case 'A':
+ ea = opram[pos] + ( opram[pos+1] << 8);
+ pos += 2;
+ dst += sprintf( dst, "$%04X", ea );
+ break;
+ case 'B': /* Byte op arg */
+ ea = opram[pos++];
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case '(': /* Memory byte at (...) */
+ *dst++ = *src;
+ if( !strncmp( src, "(bc)", 4) ) {
+ } else if( !strncmp( src, "(de)", 4) ) {
+ } else if( !strncmp( src, "(hl)", 4) ) {
+ } else if( !strncmp( src, "(sp)", 4) ) {
+ } else if( !strncmp( src, "(F)", 3) ) {
+ ea = 0xFF00 + opram[pos++];
+ dst += sprintf( dst, "$%02X", ea );
+ src++;
+ } else if( !strncmp( src, "(C)", 3) ) {
+ dst += sprintf( dst, "$FF00+c" );
+ src++;
+ }
+ break;
+ case 'N': /* Immediate 16 bit */
+ ea = opram[pos] + ( opram[pos+1] << 8 );
+ pos += 2;
+ dst += sprintf( dst, "$%04X", ea );
+ break;
+ case 'O': /* Offset relative to PC */
+ offset = (INT8) opram[pos++];
+ dst += sprintf( dst, "$%04X", pc + offset + 2 );
+ break;
+ case 'V': /* Restart vector */
+ ea = op & 0x38;
+ dst += sprintf( dst, "$%02X", ea );
+ break;
+ case 'W': /* Memory address word */
+ ea = opram[pos] + ( opram[pos+1] << 8 );
+ pos += 2;
+ dst += sprintf( dst, "$%04X", ea );
+ break;
+ default:
+ *dst++ = *src;
+ }
+ src++;
+ }
+ *dst = '\0';
+ } else {
+ dst += sprintf(dst, "%s", s_mnemonic[d->mnemonic]);
+ }
+
+ return pos | s_flags[d->mnemonic] | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpuexec.c b/src/emu/cpuexec.c
new file mode 100644
index 00000000000..8c7556ef092
--- /dev/null
+++ b/src/emu/cpuexec.c
@@ -0,0 +1,1511 @@
+/***************************************************************************
+
+ cpuexec.c
+
+ Core multi-CPU execution engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include <math.h>
+#include "driver.h"
+#include "cheat.h"
+#include "profiler.h"
+#include "debugger.h"
+
+#ifdef MAME_DEBUG
+#include "debug/debugcpu.h"
+#endif
+
+
+
+/*************************************
+ *
+ * Debug logging
+ *
+ *************************************/
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+
+/*************************************
+ *
+ * Macros to help verify active CPU
+ *
+ *************************************/
+
+#define VERIFY_ACTIVECPU(name) \
+ int activecpu = cpu_getactivecpu(); \
+ assert_always(activecpu >= 0, #name "() called with no active cpu!")
+
+#define VERIFY_EXECUTINGCPU(name) \
+ int activecpu = cpu_getexecutingcpu(); \
+ assert_always(activecpu >= 0, #name "() called with no executing cpu!")
+
+#define VERIFY_CPUNUM(name) \
+ assert_always(cpunum >= 0 && cpunum < cpu_gettotalcpu(), #name "() called for invalid cpu num!")
+
+
+
+/*************************************
+ *
+ * Triggers for the timer system
+ *
+ *************************************/
+
+enum
+{
+ TRIGGER_TIMESLICE = -1000,
+ TRIGGER_INT = -2000,
+ TRIGGER_YIELDTIME = -3000,
+ TRIGGER_SUSPENDTIME = -4000
+};
+
+
+
+/*************************************
+ *
+ * Internal CPU info structure
+ *
+ *************************************/
+
+typedef struct _cpuexec_data cpuexec_data;
+struct _cpuexec_data
+{
+ UINT8 saveable; /* true if saveable */
+
+ UINT8 suspend; /* suspend reason mask (0 = not suspended) */
+ UINT8 nextsuspend; /* pending suspend reason mask */
+ UINT8 eatcycles; /* true if we eat cycles while suspended */
+ UINT8 nexteatcycles; /* pending value */
+ INT32 trigger; /* pending trigger to release a trigger suspension */
+
+ INT32 iloops; /* number of interrupts remaining this frame */
+
+ UINT64 totalcycles; /* total CPU cycles executed */
+ attotime localtime; /* local time, relative to the timer system's global time */
+ INT32 clock; /* current active clock */
+ double clockscale; /* current active clock scale factor */
+
+ INT32 vblankint_countdown; /* number of vblank callbacks left until we interrupt */
+ INT32 vblankint_multiplier; /* number of vblank callbacks per interrupt */
+ void * vblankint_timer; /* reference to elapsed time counter */
+
+ void * timedint_timer; /* reference to this CPU's timer */
+ attotime timedint_period; /* timing period of the timed interrupt */
+};
+
+
+
+/*************************************
+ *
+ * General CPU variables
+ *
+ *************************************/
+
+static cpuexec_data cpu[MAX_CPU];
+
+static UINT8 vblank;
+static UINT32 current_frame;
+static INT32 watchdog_counter;
+
+static int cycles_running;
+static int cycles_stolen;
+
+
+
+/*************************************
+ *
+ * Timer variables
+ *
+ *************************************/
+
+static emu_timer *vblank_timer;
+static INT32 vblank_countdown;
+static INT32 vblank_multiplier;
+static attotime vblank_period;
+
+static emu_timer *update_timer;
+
+emu_timer *refresh_timer; /* temporarily made non-static (for ccpu) */
+static attotime refresh_period;
+
+static emu_timer *timeslice_timer;
+static attotime timeslice_period;
+
+static emu_timer *interleave_boost_timer;
+static emu_timer *interleave_boost_timer_end;
+static attotime perfect_interleave;
+
+static emu_timer *watchdog_timer;
+
+
+
+/*************************************
+ *
+ * Static prototypes
+ *
+ *************************************/
+
+static void cpuexec_exit(running_machine *machine);
+static void cpuexec_reset(running_machine *machine);
+static void cpu_inittimers(running_machine *machine);
+static void cpu_vblankreset(void);
+static TIMER_CALLBACK( cpu_vblankcallback );
+static TIMER_CALLBACK( cpu_updatecallback );
+static TIMER_CALLBACK( end_interleave_boost );
+static void compute_perfect_interleave(void);
+static void watchdog_setup(int alloc_new);
+
+
+
+/*************************************
+ *
+ * Watchdog Flags
+ *
+ *************************************/
+
+#define WATCHDOG_IS_STARTED_DISABLED -1
+#define WATCHDOG_IS_DISABLED -2
+#define WATCHDOG_IS_TIMER_BASED -3
+#define WATCHDOG_IS_INVALID -4
+#define WATCHDOG_IS_BEING_STARTED -5
+
+
+
+#if 0
+#pragma mark CORE CPU
+#endif
+
+/*************************************
+ *
+ * Initialize all the CPUs
+ *
+ *************************************/
+
+void cpuexec_init(running_machine *machine)
+{
+ int cpunum;
+
+ /* if there has been no VBLANK time specified in the MACHINE_DRIVER, compute it now
+ from the visible area */
+ if (machine->screen[0].vblank == 0 && !machine->screen[0].oldstyle_vblank_supplied)
+ machine->screen[0].vblank = (machine->screen[0].refresh / machine->screen[0].height) * (machine->screen[0].height - (machine->screen[0].visarea.max_y + 1 - machine->screen[0].visarea.min_y));
+
+ /* allocate vblank and refresh timers, and compute the initial timing */
+ vblank_timer = timer_alloc(cpu_vblankcallback);
+ refresh_timer = timer_alloc(NULL);
+ cpu_compute_vblank_timing();
+
+ /* loop over all our CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ cpu_type cputype = machine->drv->cpu[cpunum].type;
+ int num_regs;
+
+ /* if this is a dummy, stop looking */
+ if (cputype == CPU_DUMMY)
+ break;
+
+ /* initialize the cpuinfo struct */
+ memset(&cpu[cpunum], 0, sizeof(cpu[cpunum]));
+ cpu[cpunum].suspend = SUSPEND_REASON_RESET;
+ cpu[cpunum].clock = machine->drv->cpu[cpunum].clock;
+ cpu[cpunum].clockscale = 1.0;
+ cpu[cpunum].localtime = attotime_zero;
+
+ /* compute the cycle times */
+ cycles_per_second[cpunum] = cpu[cpunum].clockscale * cpu[cpunum].clock;
+ attoseconds_per_cycle[cpunum] = ATTOSECONDS_PER_SECOND / (cpu[cpunum].clockscale * cpu[cpunum].clock);
+
+ /* register some of our variables for later */
+ state_save_register_item("cpu", cpunum, cpu[cpunum].suspend);
+ state_save_register_item("cpu", cpunum, cpu[cpunum].nextsuspend);
+ state_save_register_item("cpu", cpunum, cpu[cpunum].eatcycles);
+ state_save_register_item("cpu", cpunum, cpu[cpunum].nexteatcycles);
+ state_save_register_item("cpu", cpunum, cpu[cpunum].trigger);
+
+ state_save_register_item("cpu", cpunum, cpu[cpunum].iloops);
+
+ state_save_register_item("cpu", cpunum, cpu[cpunum].totalcycles);
+ state_save_register_item("cpu", cpunum, cpu[cpunum].localtime.seconds);
+ state_save_register_item("cpu", cpunum, cpu[cpunum].localtime.attoseconds);
+ state_save_register_item("cpu", cpunum, cpu[cpunum].clock);
+ state_save_register_item("cpu", cpunum, cpu[cpunum].clockscale);
+
+ state_save_register_item("cpu", cpunum, cpu[cpunum].vblankint_countdown);
+
+ /* initialize this CPU */
+ state_save_push_tag(cpunum + 1);
+ num_regs = state_save_get_reg_count();
+ if (cpuintrf_init_cpu(cpunum, cputype, cpu[cpunum].clock, machine->drv->cpu[cpunum].reset_param, cpu_irq_callbacks[cpunum]))
+ fatalerror("Unable to initialize CPU #%d (%s)", cpunum, cputype_name(cputype));
+ num_regs = state_save_get_reg_count() - num_regs;
+ state_save_pop_tag();
+
+ /* if no state registered for saving, we can't save */
+ if (num_regs == 0)
+ {
+ logerror("CPU #%d (%s) did not register any state to save!\n", cpunum, cputype_name(cputype));
+ if (machine->gamedrv->flags & GAME_SUPPORTS_SAVE)
+ fatalerror("CPU #%d (%s) did not register any state to save!", cpunum, cputype_name(cputype));
+ }
+ }
+ add_reset_callback(machine, cpuexec_reset);
+ add_exit_callback(machine, cpuexec_exit);
+
+ /* compute the perfect interleave factor */
+ compute_perfect_interleave();
+
+ /* save some stuff in the default tag */
+ state_save_push_tag(0);
+ state_save_register_item("cpu", 0, vblank);
+ state_save_register_item("cpu", 0, current_frame);
+ state_save_register_item("cpu", 0, watchdog_counter);
+ state_save_register_item("cpu", 0, vblank_countdown);
+ state_save_pop_tag();
+}
+
+
+
+/*************************************
+ *
+ * Prepare the system for execution
+ *
+ *************************************/
+
+static void cpuexec_reset(running_machine *machine)
+{
+ int cpunum;
+
+ /* initialize the various timers (suspends all CPUs at startup) */
+ cpu_inittimers(machine);
+ watchdog_counter = WATCHDOG_IS_INVALID;
+ watchdog_setup(TRUE);
+
+ /* first pass over CPUs */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ /* enable all CPUs (except for disabled CPUs) */
+ if (!(machine->drv->cpu[cpunum].flags & CPU_DISABLE))
+ cpunum_resume(cpunum, SUSPEND_ANY_REASON);
+ else
+ cpunum_suspend(cpunum, SUSPEND_REASON_DISABLE, 1);
+
+ /* reset the total number of cycles */
+ cpu[cpunum].totalcycles = 0;
+
+ /* then reset the CPU directly */
+ cpunum_reset(cpunum);
+ }
+
+ /* reset the globals */
+ cpu_vblankreset();
+ vblank = 0;
+ current_frame = 0;
+}
+
+
+
+/*************************************
+ *
+ * Deinitialize all the CPUs
+ *
+ *************************************/
+
+static void cpuexec_exit(running_machine *machine)
+{
+ int cpunum;
+
+ /* shut down the CPU cores */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ cpuintrf_exit_cpu(cpunum);
+}
+
+
+
+
+#if 0
+#pragma mark -
+#pragma mark WATCHDOG
+#endif
+
+/*************************************
+ *
+ * Watchdog timer callback
+ *
+ *************************************/
+
+static TIMER_CALLBACK( watchdog_callback )
+{
+ logerror("reset caused by the (time) watchdog\n");
+ mame_schedule_soft_reset(machine);
+}
+
+
+
+/*************************************
+ *
+ * Watchdog setup routine
+ *
+ *************************************/
+
+static void watchdog_setup(int alloc_new)
+{
+ if (watchdog_counter != WATCHDOG_IS_DISABLED)
+ {
+ if (Machine->drv->watchdog_vblank_count)
+ {
+ /* Start a vblank based watchdog. */
+ watchdog_counter = Machine->drv->watchdog_vblank_count;
+ }
+ else if (attotime_compare(Machine->drv->watchdog_time, attotime_zero) != 0)
+ {
+ /* Start a time based watchdog. */
+ if (alloc_new)
+ watchdog_timer = timer_alloc(watchdog_callback);
+ timer_adjust(watchdog_timer, Machine->drv->watchdog_time, 0, attotime_zero);
+ watchdog_counter = WATCHDOG_IS_TIMER_BASED;
+ }
+ else if (watchdog_counter == WATCHDOG_IS_INVALID)
+ {
+ /* The watchdog was not initialized in the MACHINE_DRIVER,
+ * so we will start with it disabled.
+ */
+ watchdog_counter = WATCHDOG_IS_STARTED_DISABLED;
+ }
+ else
+ {
+ /* The watchdog was not initialized in the MACHINE_DRIVER.
+ * But it has been manually started, so we will default to
+ * using a vblank watchdog. We will set up a default time
+ * of 3 times the refresh rate. Which is 3 seconds @ 60Hz
+ * refresh.
+
+ * The 3 seconds delay is targeted at qzshowby, which otherwise
+ * would reset at the start of a game.
+ */
+ watchdog_counter = 3 * ATTOSECONDS_TO_HZ(Machine->screen[0].refresh);
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Watchdog reset
+ *
+ *************************************/
+
+void watchdog_reset(void)
+{
+ if (watchdog_counter == WATCHDOG_IS_TIMER_BASED)
+ {
+ timer_reset(watchdog_timer, Machine->drv->watchdog_time);
+ }
+ else
+ {
+ if (watchdog_counter == WATCHDOG_IS_STARTED_DISABLED)
+ {
+ watchdog_counter = WATCHDOG_IS_BEING_STARTED;
+ logerror("(vblank) watchdog armed by reset\n");
+ }
+
+ watchdog_setup(FALSE);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Watchdog enable/disable
+ *
+ *************************************/
+
+void watchdog_enable(int enable)
+{
+ if (!enable)
+ {
+ // Disable all timers
+ watchdog_counter = WATCHDOG_IS_DISABLED;
+ }
+ else
+ // Setup only on change from disable to enable.
+ // Do not setup if watchdog is disabled from machine init.
+ if (watchdog_counter == WATCHDOG_IS_DISABLED)
+ {
+ watchdog_counter = WATCHDOG_IS_BEING_STARTED;
+ watchdog_setup(FALSE);
+ }
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark CPU SCHEDULING
+#endif
+
+/*************************************
+ *
+ * Execute all the CPUs for one
+ * timeslice
+ *
+ *************************************/
+
+void cpuexec_timeslice(void)
+{
+ attotime target = timer_next_fire_time();
+ attotime base = timer_get_time();
+ int cpunum, ran;
+
+ LOG(("------------------\n"));
+ LOG(("cpu_timeslice: target = %s\n", attotime_string(target, 9)));
+
+ /* process any pending suspends */
+ for (cpunum = 0; Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ {
+ if (cpu[cpunum].suspend != cpu[cpunum].nextsuspend)
+ LOG(("--> updated CPU%d suspend from %X to %X\n", cpunum, cpu[cpunum].suspend, cpu[cpunum].nextsuspend));
+ cpu[cpunum].suspend = cpu[cpunum].nextsuspend;
+ cpu[cpunum].eatcycles = cpu[cpunum].nexteatcycles;
+ }
+
+ /* loop over CPUs */
+ for (cpunum = 0; Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ {
+ /* only process if we're not suspended */
+ if (!cpu[cpunum].suspend)
+ {
+ /* compute how long to run */
+ cycles_running = ATTOTIME_TO_CYCLES(cpunum, attotime_sub(target, cpu[cpunum].localtime));
+ LOG((" cpu %d: %d cycles\n", cpunum, cycles_running));
+
+ /* run for the requested number of cycles */
+ if (cycles_running > 0)
+ {
+ profiler_mark(PROFILER_CPU1 + cpunum);
+
+ /* note that this global variable cycles_stolen can be modified */
+ /* via the call to the cpunum_execute */
+ cycles_stolen = 0;
+ ran = cpunum_execute(cpunum, cycles_running);
+
+#ifdef MAME_DEBUG
+ if (ran < cycles_stolen)
+ fatalerror("Negative CPU cycle count!");
+#endif /* MAME_DEBUG */
+
+ ran -= cycles_stolen;
+ profiler_mark(PROFILER_END);
+
+ /* account for these cycles */
+ cpu[cpunum].totalcycles += ran;
+ cpu[cpunum].localtime = attotime_add(cpu[cpunum].localtime, ATTOTIME_IN_CYCLES(ran, cpunum));
+ LOG((" %d ran, %d total, time = %s\n", ran, (INT32)cpu[cpunum].totalcycles, attotime_string(cpu[cpunum].localtime, 9)));
+
+ /* if the new local CPU time is less than our target, move the target up */
+ if (attotime_compare(cpu[cpunum].localtime, target) < 0)
+ {
+ if (attotime_compare(cpu[cpunum].localtime, base) > 0)
+ target = cpu[cpunum].localtime;
+ else
+ target = base;
+ LOG((" (new target)\n"));
+ }
+ }
+ }
+ }
+
+ /* update the local times of all CPUs */
+ for (cpunum = 0; Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ {
+ /* if we're suspended and counting, process */
+ if (cpu[cpunum].suspend && cpu[cpunum].eatcycles && attotime_compare(cpu[cpunum].localtime, target) < 0)
+ {
+ /* compute how long to run */
+ cycles_running = ATTOTIME_TO_CYCLES(cpunum, attotime_sub(target, cpu[cpunum].localtime));
+ LOG((" cpu %d: %d cycles (suspended)\n", cpunum, cycles_running));
+
+ cpu[cpunum].totalcycles += cycles_running;
+ cpu[cpunum].localtime = attotime_add(cpu[cpunum].localtime, ATTOTIME_IN_CYCLES(cycles_running, cpunum));
+ LOG((" %d skipped, %d total, time = %s\n", cycles_running, (INT32)cpu[cpunum].totalcycles, attotime_string(cpu[cpunum].localtime, 9)));
+ }
+
+ /* update the suspend state */
+ if (cpu[cpunum].suspend != cpu[cpunum].nextsuspend)
+ LOG(("--> updated CPU%d suspend from %X to %X\n", cpunum, cpu[cpunum].suspend, cpu[cpunum].nextsuspend));
+ cpu[cpunum].suspend = cpu[cpunum].nextsuspend;
+ cpu[cpunum].eatcycles = cpu[cpunum].nexteatcycles;
+ }
+
+ /* update the global time */
+ timer_set_global_time(target);
+}
+
+
+
+/*************************************
+ *
+ * Abort the timeslice for the
+ * active CPU
+ *
+ *************************************/
+
+void activecpu_abort_timeslice(void)
+{
+ int current_icount;
+
+ VERIFY_EXECUTINGCPU(activecpu_abort_timeslice);
+ LOG(("activecpu_abort_timeslice (CPU=%d, cycles_left=%d)\n", cpu_getexecutingcpu(), activecpu_get_icount() + 1));
+
+ /* swallow the remaining cycles */
+ current_icount = activecpu_get_icount() + 1;
+ cycles_stolen += current_icount;
+ cycles_running -= current_icount;
+ activecpu_adjust_icount(-current_icount);
+}
+
+
+
+/*************************************
+ *
+ * Return the current local time for
+ * a CPU, relative to the current
+ * timeslice
+ *
+ *************************************/
+
+attotime cpunum_get_localtime(int cpunum)
+{
+ attotime result;
+
+ VERIFY_CPUNUM(cpunum_get_localtime);
+
+ /* if we're active, add in the time from the current slice */
+ result = cpu[cpunum].localtime;
+ if (cpunum == cpu_getexecutingcpu())
+ {
+ int cycles = cycles_currently_ran();
+ result = attotime_add(result, ATTOTIME_IN_CYCLES(cycles, cpunum));
+ }
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Set a suspend reason for the
+ * given CPU
+ *
+ *************************************/
+
+void cpunum_suspend(int cpunum, int reason, int eatcycles)
+{
+ VERIFY_CPUNUM(cpunum_suspend);
+ LOG(("cpunum_suspend (CPU=%d, r=%X, eat=%d)\n", cpunum, reason, eatcycles));
+
+ /* set the pending suspend bits, and force a resync */
+ cpu[cpunum].nextsuspend |= reason;
+ cpu[cpunum].nexteatcycles = eatcycles;
+ if (cpu_getexecutingcpu() >= 0)
+ activecpu_abort_timeslice();
+}
+
+
+
+/*************************************
+ *
+ * Clear a suspend reason for a
+ * given CPU
+ *
+ *************************************/
+
+void cpunum_resume(int cpunum, int reason)
+{
+ VERIFY_CPUNUM(cpunum_resume);
+ LOG(("cpunum_resume (CPU=%d, r=%X)\n", cpunum, reason));
+
+ /* clear the pending suspend bits, and force a resync */
+ cpu[cpunum].nextsuspend &= ~reason;
+ if (cpu_getexecutingcpu() >= 0)
+ activecpu_abort_timeslice();
+}
+
+
+
+/*************************************
+ *
+ * Return true if a given CPU is
+ * suspended
+ *
+ *************************************/
+
+int cpunum_is_suspended(int cpunum, int reason)
+{
+ VERIFY_CPUNUM(cpunum_suspend);
+ return ((cpu[cpunum].nextsuspend & reason) != 0);
+}
+
+
+
+/*************************************
+ *
+ * Gets the current CPU's clock speed
+ *
+ *************************************/
+
+int cpunum_get_clock(int cpunum)
+{
+ VERIFY_CPUNUM(cpunum_get_clock);
+ return cpu[cpunum].clock;
+}
+
+
+
+/*************************************
+ *
+ * Sets the current CPU's clock speed
+ *
+ *************************************/
+
+void cpunum_set_clock(int cpunum, int clock)
+{
+ VERIFY_CPUNUM(cpunum_set_clock);
+
+ cpu[cpunum].clock = clock;
+ cycles_per_second[cpunum] = (double)clock * cpu[cpunum].clockscale;
+ attoseconds_per_cycle[cpunum] = ATTOSECONDS_PER_SECOND / ((double)clock * cpu[cpunum].clockscale);
+
+ /* re-compute the perfect interleave factor */
+ compute_perfect_interleave();
+}
+
+
+
+void cpunum_set_clock_period(int cpunum, attoseconds_t clock_period)
+{
+ VERIFY_CPUNUM(cpunum_set_clock);
+
+ cpu[cpunum].clock = ATTOSECONDS_PER_SECOND / clock_period;
+ cycles_per_second[cpunum] = (double) (ATTOSECONDS_PER_SECOND / clock_period) * cpu[cpunum].clockscale;
+ attoseconds_per_cycle[cpunum] = clock_period;
+
+ /* re-compute the perfect interleave factor */
+ compute_perfect_interleave();
+}
+
+
+
+/*************************************
+ *
+ * Returns the current scaling factor
+ * for a CPU's clock speed
+ *
+ *************************************/
+
+double cpunum_get_clockscale(int cpunum)
+{
+ VERIFY_CPUNUM(cpunum_get_clockscale);
+ return cpu[cpunum].clockscale;
+}
+
+
+
+/*************************************
+ *
+ * Sets the current scaling factor
+ * for a CPU's clock speed
+ *
+ *************************************/
+
+void cpunum_set_clockscale(int cpunum, double clockscale)
+{
+ VERIFY_CPUNUM(cpunum_set_clockscale);
+
+ cpu[cpunum].clockscale = clockscale;
+ cycles_per_second[cpunum] = (double)cpu[cpunum].clock * clockscale;
+ attoseconds_per_cycle[cpunum] = ATTOSECONDS_PER_SECOND / ((double)cpu[cpunum].clock * clockscale);
+
+ /* re-compute the perfect interleave factor */
+ compute_perfect_interleave();
+}
+
+
+
+/*************************************
+ *
+ * Temporarily boosts the interleave
+ * factor
+ *
+ *************************************/
+
+void cpu_boost_interleave(attotime timeslice_time, attotime boost_duration)
+{
+ /* if you pass 0 for the timeslice_time, it means pick something reasonable */
+ if (attotime_compare(timeslice_time, perfect_interleave) < 0)
+ timeslice_time = perfect_interleave;
+
+ LOG(("cpu_boost_interleave(%s, %s)\n", attotime_string(timeslice_time, 9), attotime_string(boost_duration, 9)));
+
+ /* adjust the interleave timer */
+ timer_adjust(interleave_boost_timer, timeslice_time, 0, timeslice_time);
+
+ /* adjust the end timer, but only if we are going to extend it */
+ if (!timer_enabled(interleave_boost_timer_end) || attotime_compare(timer_timeleft(interleave_boost_timer_end), boost_duration) < 0)
+ timer_adjust(interleave_boost_timer_end, boost_duration, 0, attotime_never);
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark TIMING HELPERS
+#endif
+
+/*************************************
+ *
+ * Return cycles ran this iteration
+ *
+ *************************************/
+
+int cycles_currently_ran(void)
+{
+ VERIFY_EXECUTINGCPU(cycles_currently_ran);
+ return cycles_running - activecpu_get_icount();
+}
+
+
+
+/*************************************
+ *
+ * Return total number of CPU cycles
+ * for the active CPU or for a given CPU.
+ *
+ *************************************/
+
+/*--------------------------------------------------------------
+
+ IMPORTANT: this value wraps around in a relatively short
+ time. For example, for a 6MHz CPU, it will wrap around in
+ 2^32/6000000 = 716 seconds = 12 minutes.
+
+ Make sure you don't do comparisons between values returned
+ by this function, but only use the difference (which will
+ be correct regardless of wraparound).
+
+ Alternatively, use the new 64-bit variants instead.
+
+--------------------------------------------------------------*/
+
+UINT32 activecpu_gettotalcycles(void)
+{
+ VERIFY_ACTIVECPU(activecpu_gettotalcycles);
+ if (activecpu == cpu_getexecutingcpu())
+ return cpu[activecpu].totalcycles + cycles_currently_ran();
+ else
+ return cpu[activecpu].totalcycles;
+}
+
+UINT32 cpunum_gettotalcycles(int cpunum)
+{
+ VERIFY_CPUNUM(cpunum_gettotalcycles);
+ if (cpunum == cpu_getexecutingcpu())
+ return cpu[cpunum].totalcycles + cycles_currently_ran();
+ else
+ return cpu[cpunum].totalcycles;
+}
+
+
+UINT64 activecpu_gettotalcycles64(void)
+{
+ VERIFY_ACTIVECPU(activecpu_gettotalcycles64);
+ if (activecpu == cpu_getexecutingcpu())
+ return cpu[activecpu].totalcycles + cycles_currently_ran();
+ else
+ return cpu[activecpu].totalcycles;
+}
+
+UINT64 cpunum_gettotalcycles64(int cpunum)
+{
+ VERIFY_CPUNUM(cpunum_gettotalcycles64);
+ if (cpunum == cpu_getexecutingcpu())
+ return cpu[cpunum].totalcycles + cycles_currently_ran();
+ else
+ return cpu[cpunum].totalcycles;
+}
+
+
+
+/*************************************
+ *
+ * Safely eats cycles so we don't
+ * cross a timeslice boundary
+ *
+ *************************************/
+
+void activecpu_eat_cycles(int cycles)
+{
+ int cyclesleft = activecpu_get_icount();
+ if (cycles > cyclesleft)
+ cycles = cyclesleft;
+ activecpu_adjust_icount(-cycles);
+}
+
+
+
+/*************************************
+ *
+ * Scales a given value by the fraction
+ * of time elapsed between refreshes
+ *
+ *************************************/
+
+int cpu_scalebyfcount(int value)
+{
+ attotime refresh_elapsed = timer_timeelapsed(refresh_timer);
+ int result;
+
+ /* shift off some bits to ensure no overflow */
+ if (value < 65536)
+ result = value * (refresh_elapsed.attoseconds >> 16) / (refresh_period.attoseconds >> 16);
+ else
+ result = value * (refresh_elapsed.attoseconds >> 32) / (refresh_period.attoseconds >> 32);
+ if (value >= 0)
+ return (result < value) ? result : value;
+ else
+ return (result > value) ? result : value;
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark VIDEO TIMING
+#endif
+
+/*************************************
+ *
+ * Computes the VBLANK timing
+ *
+ *************************************/
+
+void cpu_compute_vblank_timing(void)
+{
+ refresh_period = attotime_make(0, Machine->screen[0].refresh);
+
+ /* recompute the vblank period */
+ vblank_period = attotime_make(0, Machine->screen[0].refresh / (vblank_multiplier ? vblank_multiplier : 1));
+ if (vblank_timer != NULL && timer_enable(vblank_timer, FALSE))
+ {
+ attotime remaining = timer_timeleft(vblank_timer);
+ if (remaining.seconds == 0 && remaining.attoseconds == 0)
+ remaining = vblank_period;
+ timer_adjust(vblank_timer, remaining, 0, vblank_period);
+ }
+
+ LOG(("cpu_compute_vblank_timing: refresh=%s vblank=%s\n", attotime_string(refresh_period, 9), attotime_string(vblank_period, 9)));
+}
+
+
+
+/*************************************
+ *
+ * Returns the VBLANK state
+ *
+ *************************************/
+
+int cpu_getvblank(void)
+{
+ return vblank;
+}
+
+
+
+/*************************************
+ *
+ * Returns the current frame count
+ *
+ *************************************/
+
+int cpu_getcurrentframe(void)
+{
+ return current_frame;
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark SYNCHRONIZATION
+#endif
+
+/*************************************
+ *
+ * Generate a specific trigger
+ *
+ *************************************/
+
+void cpu_trigger(int trigger)
+{
+ int cpunum;
+
+ /* cause an immediate resynchronization */
+ if (cpu_getexecutingcpu() >= 0)
+ activecpu_abort_timeslice();
+
+ /* look for suspended CPUs waiting for this trigger and unsuspend them */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ /* if this is a dummy, stop looking */
+ if (Machine->drv->cpu[cpunum].type == CPU_DUMMY)
+ break;
+
+ /* see if this is a matching trigger */
+ if (cpu[cpunum].suspend && cpu[cpunum].trigger == trigger)
+ {
+ cpunum_resume(cpunum, SUSPEND_REASON_TRIGGER);
+ cpu[cpunum].trigger = 0;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Generate a trigger in the future
+ *
+ *************************************/
+
+static TIMER_CALLBACK( cpu_triggertime_callback )
+{
+ cpu_trigger(param);
+}
+
+
+void cpu_triggertime(attotime duration, int trigger)
+{
+ timer_set(duration, trigger, cpu_triggertime_callback);
+}
+
+
+
+/*************************************
+ *
+ * Generate a trigger for an int
+ *
+ *************************************/
+
+void cpu_triggerint(int cpunum)
+{
+ cpu_trigger(TRIGGER_INT + cpunum);
+}
+
+
+
+/*************************************
+ *
+ * Burn/yield CPU cycles until a trigger
+ *
+ *************************************/
+
+void cpu_spinuntil_trigger(int trigger)
+{
+ int cpunum = cpu_getexecutingcpu();
+
+ VERIFY_EXECUTINGCPU(cpu_spinuntil_trigger);
+
+ /* suspend the CPU immediately if it's not already */
+ cpunum_suspend(cpunum, SUSPEND_REASON_TRIGGER, 1);
+
+ /* set the trigger */
+ cpu[cpunum].trigger = trigger;
+}
+
+void cpunum_spinuntil_trigger( int cpunum, int trigger )
+{
+ VERIFY_CPUNUM(cpunum_spinuntil_trigger);
+
+ /* suspend the CPU immediately if it's not already */
+ cpunum_suspend(cpunum, SUSPEND_REASON_TRIGGER, 1);
+
+ /* set the trigger */
+ cpu[cpunum].trigger = trigger;
+}
+
+void cpu_yielduntil_trigger(int trigger)
+{
+ int cpunum = cpu_getexecutingcpu();
+
+ VERIFY_EXECUTINGCPU(cpu_yielduntil_trigger);
+
+ /* suspend the CPU immediately if it's not already */
+ cpunum_suspend(cpunum, SUSPEND_REASON_TRIGGER, 0);
+
+ /* set the trigger */
+ cpu[cpunum].trigger = trigger;
+}
+
+
+
+/*************************************
+ *
+ * Burn/yield CPU cycles until an
+ * interrupt
+ *
+ *************************************/
+
+void cpu_spinuntil_int(void)
+{
+ VERIFY_EXECUTINGCPU(cpu_spinuntil_int);
+ cpu_spinuntil_trigger(TRIGGER_INT + activecpu);
+}
+
+
+void cpu_yielduntil_int(void)
+{
+ VERIFY_EXECUTINGCPU(cpu_yielduntil_int);
+ cpu_yielduntil_trigger(TRIGGER_INT + activecpu);
+}
+
+
+
+/*************************************
+ *
+ * Burn/yield CPU cycles until the
+ * end of the current timeslice
+ *
+ *************************************/
+
+void cpu_spin(void)
+{
+ cpu_spinuntil_trigger(TRIGGER_TIMESLICE);
+}
+
+
+void cpu_yield(void)
+{
+ cpu_yielduntil_trigger(TRIGGER_TIMESLICE);
+}
+
+
+
+/*************************************
+ *
+ * Burn/yield CPU cycles for a
+ * specific period of time
+ *
+ *************************************/
+
+void cpu_spinuntil_time(attotime duration)
+{
+ static int timetrig = 0;
+
+ cpu_spinuntil_trigger(TRIGGER_SUSPENDTIME + timetrig);
+ cpu_triggertime(duration, TRIGGER_SUSPENDTIME + timetrig);
+ timetrig = (timetrig + 1) & 255;
+}
+
+
+void cpu_yielduntil_time(attotime duration)
+{
+ static int timetrig = 0;
+
+ cpu_yielduntil_trigger(TRIGGER_YIELDTIME + timetrig);
+ cpu_triggertime(duration, TRIGGER_YIELDTIME + timetrig);
+ timetrig = (timetrig + 1) & 255;
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark CORE TIMING
+#endif
+
+/*************************************
+ *
+ * Returns the number of times the
+ * interrupt handler will be called
+ * before the end of the current
+ * video frame.
+ *
+ *************************************/
+
+/*--------------------------------------------------------------
+
+ This can be useful to interrupt handlers to synchronize
+ their operation. If you call this from outside an interrupt
+ handler, add 1 to the result, i.e. if it returns 0, it means
+ that the interrupt handler will be called once.
+
+--------------------------------------------------------------*/
+
+int cpu_getiloops(void)
+{
+ VERIFY_ACTIVECPU(cpu_getiloops);
+ return cpu[activecpu].iloops;
+}
+
+
+
+/*************************************
+ *
+ * Hook for updating things on the
+ * real VBLANK (once per frame)
+ *
+ *************************************/
+
+static void cpu_vblankreset(void)
+{
+ int cpunum;
+
+ /* notify the video system of a VBLANK start */
+ video_vblank_start(Machine);
+
+ /* read keyboard & update the status of the input ports */
+ input_port_vblank_start();
+
+ /* check the watchdog */
+ if (watchdog_counter > 0)
+ {
+ if (--watchdog_counter == 0)
+ {
+ logerror("reset caused by the (vblank) watchdog\n");
+ mame_schedule_soft_reset(Machine);
+ }
+ }
+
+ /* reset the cycle counters */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ if (!(cpu[cpunum].suspend & SUSPEND_REASON_DISABLE))
+ cpu[cpunum].iloops = Machine->drv->cpu[cpunum].vblank_interrupts_per_frame - 1;
+ else
+ cpu[cpunum].iloops = -1;
+ }
+}
+
+
+
+/*************************************
+ *
+ * First-run callback for VBLANKs
+ *
+ *************************************/
+
+static TIMER_CALLBACK( cpu_firstvblankcallback )
+{
+ /* now that we're synced up, pulse from here on out */
+ timer_adjust(vblank_timer, vblank_period, param, vblank_period);
+
+ /* but we need to call the standard routine as well */
+ cpu_vblankcallback(machine, param);
+}
+
+
+
+/*************************************
+ *
+ * VBLANK core handler
+ *
+ *************************************/
+
+static TIMER_CALLBACK( cpu_vblankcallback )
+{
+ int cpunum;
+
+ if (vblank_countdown == 1)
+ vblank = 1;
+
+ /* loop over CPUs */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ /* if the interrupt multiplier is valid */
+ if (cpu[cpunum].vblankint_multiplier != -1)
+ {
+ /* decrement; if we hit zero, generate the interrupt and reset the countdown */
+ if (!--cpu[cpunum].vblankint_countdown)
+ {
+ /* a param of -1 means don't call any callbacks */
+ if (param != -1)
+ {
+ /* if the CPU has a VBLANK handler, call it */
+ if (machine->drv->cpu[cpunum].vblank_interrupt && !cpunum_is_suspended(cpunum, SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE))
+ {
+ cpuintrf_push_context(cpunum);
+ (*machine->drv->cpu[cpunum].vblank_interrupt)();
+ cpuintrf_pop_context();
+ }
+
+ /* update the counters */
+ cpu[cpunum].iloops--;
+ }
+
+ /* reset the countdown and timer */
+ cpu[cpunum].vblankint_countdown = cpu[cpunum].vblankint_multiplier;
+ timer_adjust(cpu[cpunum].vblankint_timer, attotime_never, 0, attotime_never);
+ }
+ }
+
+ /* else reset the VBLANK timer if this is going to be a real VBLANK */
+ else if (vblank_countdown == 1)
+ timer_adjust(cpu[cpunum].vblankint_timer, attotime_never, 0, attotime_never);
+ }
+
+ /* is it a real VBLANK? */
+ if (!--vblank_countdown)
+ {
+ /* do we update the screen now? */
+ if (!(machine->drv->video_attributes & VIDEO_UPDATE_AFTER_VBLANK))
+ video_frame_update();
+
+ /* Set the timer to update the screen */
+ timer_adjust(update_timer, attotime_make(0, machine->screen[0].vblank), 0, attotime_zero);
+
+ /* reset the globals */
+ cpu_vblankreset();
+
+ /* reset the counter */
+ vblank_countdown = vblank_multiplier;
+
+#ifdef MAME_DEBUG
+ /* notify the debugger */
+ debug_vblank_hook();
+#endif
+ }
+}
+
+
+
+/*************************************
+ *
+ * End-of-VBLANK callback
+ *
+ *************************************/
+
+static TIMER_CALLBACK( cpu_updatecallback )
+{
+ /* update the screen if we didn't before */
+ if (machine->drv->video_attributes & VIDEO_UPDATE_AFTER_VBLANK)
+ video_frame_update();
+ vblank = 0;
+
+ /* update IPT_VBLANK input ports */
+ input_port_vblank_end();
+
+ /* track total frames */
+ current_frame++;
+
+ /* reset the refresh timer */
+ timer_adjust(refresh_timer, attotime_never, 0, attotime_never);
+}
+
+
+
+/*************************************
+ *
+ * Callback for timed interrupts
+ * (not tied to a VBLANK)
+ *
+ *************************************/
+
+static TIMER_CALLBACK( cpu_timedintcallback )
+{
+ /* bail if there is no routine */
+ if (machine->drv->cpu[param].timed_interrupt && !cpunum_is_suspended(param, SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE))
+ {
+ cpuintrf_push_context(param);
+ (*machine->drv->cpu[param].timed_interrupt)();
+ cpuintrf_pop_context();
+ }
+}
+
+
+
+/*************************************
+ *
+ * Callback to force a timeslice
+ *
+ *************************************/
+
+static TIMER_CALLBACK( cpu_timeslicecallback )
+{
+ cpu_trigger(TRIGGER_TIMESLICE);
+}
+
+
+
+/*************************************
+ *
+ * Callback to end a temporary
+ * interleave boost
+ *
+ *************************************/
+
+static TIMER_CALLBACK( end_interleave_boost )
+{
+ timer_adjust(interleave_boost_timer, attotime_never, 0, attotime_never);
+ LOG(("end_interleave_boost\n"));
+}
+
+
+
+/*************************************
+ *
+ * Compute the "perfect" interleave
+ * interval
+ *
+ *************************************/
+
+static void compute_perfect_interleave(void)
+{
+ attoseconds_t smallest = attoseconds_per_cycle[0];
+ int cpunum;
+
+ /* start with a huge time factor and find the 2nd smallest cycle time */
+ perfect_interleave = attotime_zero;
+ perfect_interleave.attoseconds = ATTOSECONDS_PER_SECOND - 1;
+ for (cpunum = 1; Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ {
+ /* find the 2nd smallest cycle interval */
+ if (attoseconds_per_cycle[cpunum] < smallest)
+ {
+ perfect_interleave.attoseconds = smallest;
+ smallest = attoseconds_per_cycle[cpunum];
+ }
+ else if (attoseconds_per_cycle[cpunum] < perfect_interleave.attoseconds)
+ perfect_interleave.attoseconds = attoseconds_per_cycle[cpunum];
+ }
+
+ /* adjust the final value */
+ if (perfect_interleave.attoseconds == ATTOSECONDS_PER_SECOND - 1)
+ perfect_interleave.attoseconds = attoseconds_per_cycle[0];
+
+ LOG(("Perfect interleave = %s, smallest = %.9f\n", attotime_string(perfect_interleave), ATTOSECONDS_TO_DOUBLE(smallest)));
+}
+
+
+
+/*************************************
+ *
+ * Setup all the core timers
+ *
+ *************************************/
+
+static void cpu_inittimers(running_machine *machine)
+{
+ attotime first_time;
+ int cpunum, max, ipf;
+
+ /* allocate a dummy timer at the minimum frequency to break things up */
+ ipf = machine->drv->cpu_slices_per_frame;
+ if (ipf <= 0)
+ ipf = 1;
+ timeslice_period = attotime_make(0, machine->screen[0].refresh / ipf);
+ timeslice_timer = timer_alloc(cpu_timeslicecallback);
+ timer_adjust(timeslice_timer, timeslice_period, 0, timeslice_period);
+
+ /* allocate timers to handle interleave boosts */
+ interleave_boost_timer = timer_alloc(NULL);
+ interleave_boost_timer_end = timer_alloc(end_interleave_boost);
+
+ /*
+ * The following code finds all the CPUs that are interrupting in sync with the VBLANK
+ * and sets up the VBLANK timer to run at the minimum number of cycles per frame in
+ * order to service all the synced interrupts
+ */
+
+ /* find the CPU with the maximum interrupts per frame */
+ max = 1;
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ ipf = machine->drv->cpu[cpunum].vblank_interrupts_per_frame;
+ if (ipf > max)
+ max = ipf;
+ }
+
+ /* now find the LCD with the rest of the CPUs (brute force - these numbers aren't huge) */
+ vblank_multiplier = max;
+ while (1)
+ {
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ ipf = machine->drv->cpu[cpunum].vblank_interrupts_per_frame;
+ if (ipf > 0 && (vblank_multiplier % ipf) != 0)
+ break;
+ }
+ if (cpunum == cpu_gettotalcpu())
+ break;
+ vblank_multiplier += max;
+ }
+
+ /* initialize the countdown timers and intervals */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ ipf = machine->drv->cpu[cpunum].vblank_interrupts_per_frame;
+ if (ipf > 0)
+ cpu[cpunum].vblankint_countdown = cpu[cpunum].vblankint_multiplier = vblank_multiplier / ipf;
+ else
+ cpu[cpunum].vblankint_countdown = cpu[cpunum].vblankint_multiplier = -1;
+ }
+
+ /* allocate a vblank timer at the frame rate * the LCD number of interrupts per frame */
+ vblank_period = attotime_make(0, machine->screen[0].refresh / vblank_multiplier);
+ vblank_countdown = vblank_multiplier;
+
+ /* allocate an update timer that will be used to time the actual screen updates */
+ update_timer = timer_alloc(cpu_updatecallback);
+
+ /*
+ * The following code creates individual timers for each CPU whose interrupts are not
+ * synced to the VBLANK, and computes the typical number of cycles per interrupt
+ */
+
+ /* start the CPU interrupt timers */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ ipf = machine->drv->cpu[cpunum].vblank_interrupts_per_frame;
+
+ /* compute the average number of cycles per interrupt */
+ if (ipf <= 0)
+ ipf = 1;
+ cpu[cpunum].vblankint_timer = timer_alloc(NULL);
+
+ /* see if we need to allocate a CPU timer */
+ if (machine->drv->cpu[cpunum].timed_interrupt_period != 0)
+ {
+ cpu[cpunum].timedint_period = attotime_make(0, machine->drv->cpu[cpunum].timed_interrupt_period);
+ cpu[cpunum].timedint_timer = timer_alloc(cpu_timedintcallback);
+ timer_adjust(cpu[cpunum].timedint_timer, cpu[cpunum].timedint_period, cpunum, cpu[cpunum].timedint_period);
+ }
+ }
+
+ /* note that since we start the first frame on the refresh, we can't pulse starting
+ immediately; instead, we back up one VBLANK period, and inch forward until we hit
+ positive time. That time will be the time of the first VBLANK timer callback */
+ first_time = attotime_sub_attoseconds(vblank_period, machine->screen[0].vblank);
+ while (attotime_compare(first_time, attotime_zero) < 0)
+ {
+ cpu_vblankcallback(machine, -1);
+ first_time = attotime_add(first_time, vblank_period);
+ }
+ timer_set(first_time, 0, cpu_firstvblankcallback);
+
+ /* reset the refresh timer to get ourself back in sync */
+ timer_adjust(refresh_timer, attotime_never, 0, attotime_never);
+}
+
diff --git a/src/emu/cpuexec.h b/src/emu/cpuexec.h
new file mode 100644
index 00000000000..ba966ae6046
--- /dev/null
+++ b/src/emu/cpuexec.h
@@ -0,0 +1,434 @@
+/***************************************************************************
+
+ cpuexec.h
+
+ Core multi-CPU execution engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CPUEXEC_H__
+#define __CPUEXEC_H__
+
+#include "memory.h"
+#include "timer.h"
+
+
+/* Enum listing all the CPUs */
+typedef enum _cpu_type cpu_type;
+enum _cpu_type
+{
+ CPU_DUMMY,
+ CPU_Z80,
+ CPU_Z180,
+ CPU_8080,
+ CPU_8085A,
+ CPU_M6502,
+ CPU_M65C02,
+ CPU_M65SC02,
+ CPU_M65CE02,
+ CPU_M6509,
+ CPU_M6510,
+ CPU_M6510T,
+ CPU_M7501,
+ CPU_M8502,
+ CPU_N2A03,
+ CPU_DECO16,
+ CPU_M4510,
+ CPU_H6280,
+ CPU_I8086,
+ CPU_I8088,
+ CPU_I80186,
+ CPU_I80188,
+ CPU_I80286,
+ CPU_V20,
+ CPU_V25,
+ CPU_V30,
+ CPU_V33,
+ CPU_V35,
+ CPU_V60,
+ CPU_V70,
+ CPU_I8035,
+ CPU_I8039,
+ CPU_I8048,
+ CPU_N7751,
+ CPU_I8X41,
+ CPU_I8051,
+ CPU_I8052,
+ CPU_I8751,
+ CPU_I8752,
+ CPU_M6800,
+ CPU_M6801,
+ CPU_M6802,
+ CPU_M6803,
+ CPU_M6808,
+ CPU_HD63701,
+ CPU_NSC8105,
+ CPU_M6805,
+ CPU_M68705,
+ CPU_HD63705,
+ CPU_HD6309,
+ CPU_M6809,
+ CPU_M6809E,
+ CPU_KONAMI,
+ CPU_M68000,
+ CPU_M68008,
+ CPU_M68010,
+ CPU_M68EC020,
+ CPU_M68020,
+ CPU_M68040,
+ CPU_T11,
+ CPU_S2650,
+ CPU_TMS34010,
+ CPU_TMS34020,
+ CPU_TI990_10,
+ CPU_TMS9900,
+ CPU_TMS9940,
+ CPU_TMS9980,
+ CPU_TMS9985,
+ CPU_TMS9989,
+ CPU_TMS9995,
+ CPU_TMS99100,
+ CPU_TMS99105A,
+ CPU_TMS99110A,
+ CPU_Z8000,
+ CPU_TMS32010,
+ CPU_TMS32025,
+ CPU_TMS32026,
+ CPU_TMS32031,
+ CPU_TMS32032,
+ CPU_TMS32051,
+ CPU_CCPU,
+ CPU_ADSP2100,
+ CPU_ADSP2101,
+ CPU_ADSP2104,
+ CPU_ADSP2105,
+ CPU_ADSP2115,
+ CPU_ADSP2181,
+ CPU_PSXCPU,
+ CPU_ASAP,
+ CPU_UPD7810,
+ CPU_UPD7807,
+ CPU_JAGUARGPU,
+ CPU_JAGUARDSP,
+ CPU_R3000BE,
+ CPU_R3000LE,
+ CPU_R4600BE,
+ CPU_R4600LE,
+ CPU_R4650BE,
+ CPU_R4650LE,
+ CPU_R4700BE,
+ CPU_R4700LE,
+ CPU_R5000BE,
+ CPU_R5000LE,
+ CPU_QED5271BE,
+ CPU_QED5271LE,
+ CPU_RM7000BE,
+ CPU_RM7000LE,
+ CPU_ARM,
+ CPU_ARM7,
+ CPU_SH2,
+ CPU_SH4,
+ CPU_DSP32C,
+ CPU_PIC16C54,
+ CPU_PIC16C55,
+ CPU_PIC16C56,
+ CPU_PIC16C57,
+ CPU_PIC16C58,
+ CPU_G65816,
+ CPU_SPC700,
+ CPU_E116T,
+ CPU_E116XT,
+ CPU_E116XS,
+ CPU_E116XSR,
+ CPU_E132N,
+ CPU_E132T,
+ CPU_E132XN,
+ CPU_E132XT,
+ CPU_E132XS,
+ CPU_E132XSR,
+ CPU_GMS30C2116,
+ CPU_GMS30C2132,
+ CPU_GMS30C2216,
+ CPU_GMS30C2232,
+ CPU_I386,
+ CPU_I486,
+ CPU_PENTIUM,
+ CPU_MEDIAGX,
+ CPU_I960,
+ CPU_H83002,
+ CPU_V810,
+ CPU_M37702,
+ CPU_M37710,
+ CPU_PPC403,
+ CPU_PPC601,
+ CPU_PPC602,
+ CPU_PPC603,
+ CPU_MPC8240,
+ CPU_SE3208,
+ CPU_MC68HC11,
+ CPU_ADSP21062,
+ CPU_DSP56156,
+ CPU_RSP,
+ CPU_ALPHA8201,
+ CPU_ALPHA8301,
+ CPU_CDP1802,
+ CPU_COP420,
+ CPU_COP410,
+ CPU_COP411,
+ CPU_TMP90840,
+ CPU_TMP90841,
+ CPU_TMP91640,
+ CPU_TMP91641,
+ CPU_APEXC,
+ CPU_CP1610,
+ CPU_F8,
+ CPU_LH5801,
+ CPU_PDP1,
+ CPU_SATURN,
+ CPU_SC61860,
+ CPU_TX0_64KW,
+ CPU_TX0_8KW,
+ CPU_Z80GB,
+ CPU_TMS7000,
+ CPU_TMS7000_EXL,
+ CPU_SM8500,
+ CPU_V30MZ,
+ CPU_MB8841,
+ CPU_MB8842,
+ CPU_MB8843,
+ CPU_MB8844,
+ CPU_MB86233,
+ CPU_SSP1610,
+ CPU_MINX,
+ CPU_COUNT
+};
+
+
+/*************************************
+ *
+ * CPU description for drivers
+ *
+ *************************************/
+
+typedef struct _cpu_config cpu_config;
+struct _cpu_config
+{
+ cpu_type type; /* index for the CPU type */
+ int flags; /* flags; see #defines below */
+ int clock; /* in Hertz */
+ construct_map_t construct_map[ADDRESS_SPACES][2]; /* 2 memory maps per address space */
+ void (*vblank_interrupt)(void); /* for interrupts tied to VBLANK */
+ int vblank_interrupts_per_frame;/* usually 1 */
+ void (*timed_interrupt)(void); /* for interrupts not tied to VBLANK */
+ attoseconds_t timed_interrupt_period; /* period for periodic interrupts */
+ void * reset_param; /* parameter for cpu_reset */
+ const char *tag;
+};
+
+
+
+/*************************************
+ *
+ * CPU flag constants
+ *
+ *************************************/
+
+enum
+{
+ /* set this flag to disable execution of a CPU (if one is there for documentation */
+ /* purposes only, for example */
+ CPU_DISABLE = 0x0001
+};
+
+
+
+
+/*************************************
+ *
+ * Core CPU execution
+ *
+ *************************************/
+
+/* Prepare CPUs for execution */
+void cpuexec_init(running_machine *machine);
+
+/* Execute for a single timeslice */
+void cpuexec_timeslice(void);
+
+
+
+/*************************************
+ *
+ * Optional watchdog
+ *
+ *************************************/
+
+/* bang on the watchdog */
+void watchdog_reset(void);
+
+/* watchdog enabled when TRUE */
+/* timer is set to reset state when going from disable to enable */
+void watchdog_enable(int enable);
+
+
+
+/*************************************
+ *
+ * CPU scheduling
+ *
+ *************************************/
+
+/* Suspension reasons */
+enum
+{
+ SUSPEND_REASON_HALT = 0x0001,
+ SUSPEND_REASON_RESET = 0x0002,
+ SUSPEND_REASON_SPIN = 0x0004,
+ SUSPEND_REASON_TRIGGER = 0x0008,
+ SUSPEND_REASON_DISABLE = 0x0010,
+ SUSPEND_ANY_REASON = ~0
+};
+
+/* Suspend the given CPU for a specific reason */
+void cpunum_suspend(int cpunum, int reason, int eatcycles);
+
+/* Suspend the given CPU for a specific reason */
+void cpunum_resume(int cpunum, int reason);
+
+/* Returns true if the given CPU is suspended for any of the given reasons */
+int cpunum_is_suspended(int cpunum, int reason);
+
+/* Aborts the timeslice for the active CPU */
+void activecpu_abort_timeslice(void);
+
+/* Returns the current local time for a CPU */
+attotime cpunum_get_localtime(int cpunum);
+
+/* Returns the current CPU's unscaled running clock speed */
+/* If you want to know the current effective running clock
+ * after scaling it is just the double sec_to_cycles[cpunum] */
+int cpunum_get_clock(int cpunum);
+
+/* Sets the current CPU's clock speed and then adjusts for scaling */
+void cpunum_set_clock(int cpunum, int clock);
+void cpunum_set_clock_period(int cpunum, attoseconds_t clock_period);
+
+/* Returns the current scaling factor for a CPU's clock speed */
+double cpunum_get_clockscale(int cpunum);
+
+/* Sets the current scaling factor for a CPU's clock speed */
+void cpunum_set_clockscale(int cpunum, double clockscale);
+
+/* Temporarily boosts the interleave factor */
+void cpu_boost_interleave(attotime timeslice_time, attotime boost_duration);
+
+
+
+/*************************************
+ *
+ * Timing helpers
+ *
+ *************************************/
+
+/* Returns the number of cycles run so far this timeslice */
+int cycles_currently_ran(void);
+
+/* Returns the total number of CPU cycles */
+UINT32 activecpu_gettotalcycles(void);
+UINT64 activecpu_gettotalcycles64(void);
+
+/* Returns the total number of CPU cycles for a given CPU */
+UINT32 cpunum_gettotalcycles(int cpunum);
+UINT64 cpunum_gettotalcycles64(int cpunum);
+
+/* Safely eats cycles so we don't cross a timeslice boundary */
+void activecpu_eat_cycles(int cycles);
+
+/* Scales a given value by the ratio of fcount / fperiod */
+int cpu_scalebyfcount(int value);
+
+
+
+/*************************************
+ *
+ * Video timing
+ *
+ *************************************/
+
+/***** OBSOLETE NOTICE: these functions are no longer considered */
+/***** to be the authority on scanline timing. Please use the */
+/***** video_screen_* functions in video.c for newer drivers. */
+/***** These functions may eventually go away. */
+
+/* Recomputes the VBLANK timing after, e.g., a visible area change */
+void cpu_compute_vblank_timing(void);
+
+/* Returns the number of the video frame we are currently playing */
+int cpu_getcurrentframe(void);
+
+
+
+/*************************************
+ *
+ * Synchronization
+ *
+ *************************************/
+
+/* generate a trigger now */
+void cpu_trigger(int trigger);
+
+/* generate a trigger after a specific period of time */
+void cpu_triggertime(attotime duration, int trigger);
+
+/* generate a trigger corresponding to an interrupt on the given CPU */
+void cpu_triggerint(int cpunum);
+
+/* burn CPU cycles until a timer trigger */
+void cpu_spinuntil_trigger(int trigger);
+
+/* burn specified CPU cycles until a timer trigger */
+void cpunum_spinuntil_trigger(int cpunum, int trigger);
+
+/* yield our timeslice until a timer trigger */
+void cpu_yielduntil_trigger(int trigger);
+
+/* burn CPU cycles until the next interrupt */
+void cpu_spinuntil_int(void);
+
+/* yield our timeslice until the next interrupt */
+void cpu_yielduntil_int(void);
+
+/* burn CPU cycles until our timeslice is up */
+void cpu_spin(void);
+
+/* yield our current timeslice */
+void cpu_yield(void);
+
+/* burn CPU cycles for a specific period of time */
+void cpu_spinuntil_time(attotime duration);
+
+/* yield our timeslice for a specific period of time */
+void cpu_yielduntil_time(attotime duration);
+
+
+
+/*************************************
+ *
+ * Core timing
+ *
+ *************************************/
+
+/* Returns the number of times the interrupt handler will be called before
+ the end of the current video frame. This is can be useful to interrupt
+ handlers to synchronize their operation. If you call this from outside
+ an interrupt handler, add 1 to the result, i.e. if it returns 0, it means
+ that the interrupt handler will be called once. */
+int cpu_getiloops(void);
+
+
+#endif /* __CPUEXEC_H__ */
diff --git a/src/emu/cpuint.c b/src/emu/cpuint.c
new file mode 100644
index 00000000000..256801dafa0
--- /dev/null
+++ b/src/emu/cpuint.c
@@ -0,0 +1,390 @@
+/***************************************************************************
+
+ cpuint.c
+
+ Core multi-CPU interrupt engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+
+#ifdef MAME_DEBUG
+#include "debug/debugcpu.h"
+#endif
+
+
+/*************************************
+ *
+ * Debug logging
+ *
+ *************************************/
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+
+/*************************************
+ *
+ * Macros to help verify active CPU
+ *
+ *************************************/
+
+#define VERIFY_ACTIVECPU(retval, name) \
+ int activecpu = cpu_getactivecpu(); \
+ assert_always(activecpu >= 0, #name "() called with no active cpu!")
+
+#define VERIFY_ACTIVECPU_VOID(name) \
+ int activecpu = cpu_getactivecpu(); \
+ assert_always(activecpu >= 0, #name "() called with no active cpu!")
+
+
+
+/*************************************
+ *
+ * CPU interrupt variables
+ *
+ *************************************/
+
+/* current states for each CPU */
+static INT32 interrupt_vector[MAX_CPU][MAX_INPUT_LINES];
+
+/* deferred states written in callbacks */
+static UINT8 input_line_state[MAX_CPU][MAX_INPUT_LINES];
+static INT32 input_line_vector[MAX_CPU][MAX_INPUT_LINES];
+
+/* ick, interrupt event queues */
+#define MAX_INPUT_EVENTS 32
+static INT32 input_event_queue[MAX_CPU][MAX_INPUT_LINES][MAX_INPUT_EVENTS];
+static int input_event_index[MAX_CPU][MAX_INPUT_LINES];
+
+
+
+/*************************************
+ *
+ * IRQ acknowledge callbacks
+ *
+ *************************************/
+
+static int cpu_0_irq_callback(int line);
+static int cpu_1_irq_callback(int line);
+static int cpu_2_irq_callback(int line);
+static int cpu_3_irq_callback(int line);
+static int cpu_4_irq_callback(int line);
+static int cpu_5_irq_callback(int line);
+static int cpu_6_irq_callback(int line);
+static int cpu_7_irq_callback(int line);
+
+int (*cpu_irq_callbacks[MAX_CPU])(int) =
+{
+ cpu_0_irq_callback,
+ cpu_1_irq_callback,
+ cpu_2_irq_callback,
+ cpu_3_irq_callback,
+ cpu_4_irq_callback,
+ cpu_5_irq_callback,
+ cpu_6_irq_callback,
+ cpu_7_irq_callback
+};
+
+static int (*drv_irq_callbacks[MAX_CPU])(int);
+
+
+
+#if 0
+#pragma mark CORE CPU
+#endif
+
+/*************************************
+ *
+ * Initialize a CPU's interrupt states
+ *
+ *************************************/
+
+void cpuint_init(running_machine *machine)
+{
+ int cpunum;
+ int line;
+
+ /* loop over all CPUs and input lines */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ /* reset any driver hooks into the IRQ acknowledge callbacks */
+ drv_irq_callbacks[cpunum] = NULL;
+
+ /* clear out all the CPU states */
+ for (line = 0; line < MAX_INPUT_LINES; line++)
+ {
+ input_line_state[cpunum][line] = CLEAR_LINE;
+ interrupt_vector[cpunum][line] =
+ input_line_vector[cpunum][line] = cputype_default_irq_vector(Machine->drv->cpu[cpunum].type);
+ input_event_index[cpunum][line] = 0;
+ }
+ }
+
+ /* set up some stuff to save */
+ state_save_push_tag(0);
+ state_save_register_item_2d_array("cpu", 0, interrupt_vector);
+ state_save_register_item_2d_array("cpu", 0, input_line_state);
+ state_save_register_item_2d_array("cpu", 0, input_line_vector);
+ state_save_pop_tag();
+}
+
+
+
+/*************************************
+ *
+ * Reset a CPU's interrupt states
+ *
+ *************************************/
+
+void cpuint_reset(void)
+{
+ int cpunum, line;
+
+ /* loop over CPUs */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ for (line = 0; line < MAX_INPUT_LINES; line++)
+ {
+ interrupt_vector[cpunum][line] = cpunum_default_irq_vector(cpunum);
+ input_event_index[cpunum][line] = 0;
+ }
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark LINE STATES
+#endif
+
+
+/*************************************
+ *
+ * Empty a CPU's event queue for
+ * a specific input line
+ *
+ *************************************/
+
+static TIMER_CALLBACK( cpunum_empty_event_queue )
+{
+ int cpunum = param & 0xff;
+ int line = param >> 8;
+ int i;
+
+ /* swap to the CPU's context */
+ cpuintrf_push_context(cpunum);
+
+ /* loop over all events */
+ for (i = 0; i < input_event_index[cpunum][line]; i++)
+ {
+ INT32 input_event = input_event_queue[cpunum][line][i];
+ int state = input_event & 0xff;
+ int vector = input_event >> 8;
+
+ LOG(("cpunum_empty_event_queue %d,%d,%d\n",cpunum,line,state));
+
+ /* set the input line state and vector */
+ input_line_state[cpunum][line] = state;
+ input_line_vector[cpunum][line] = vector;
+
+ /* special case: RESET */
+ if (line == INPUT_LINE_RESET)
+ {
+ /* if we're asserting the line, just halt the CPU */
+ if (state == ASSERT_LINE)
+ cpunum_suspend(cpunum, SUSPEND_REASON_RESET, 1);
+ else
+ {
+ /* if we're clearing the line that was previously asserted, or if we're just */
+ /* pulsing the line, reset the CPU */
+ if ((state == CLEAR_LINE && cpunum_is_suspended(cpunum, SUSPEND_REASON_RESET)) || state == PULSE_LINE)
+ cpunum_reset(cpunum);
+
+ /* if we're clearing the line, make sure the CPU is not halted */
+ cpunum_resume(cpunum, SUSPEND_REASON_RESET);
+ }
+ }
+
+ /* special case: HALT */
+ else if (line == INPUT_LINE_HALT)
+ {
+ /* if asserting, halt the CPU */
+ if (state == ASSERT_LINE)
+ cpunum_suspend(cpunum, SUSPEND_REASON_HALT, 1);
+
+ /* if clearing, unhalt the CPU */
+ else if (state == CLEAR_LINE)
+ cpunum_resume(cpunum, SUSPEND_REASON_HALT);
+ }
+
+ /* all other cases */
+ else
+ {
+ /* switch off the requested state */
+ switch (state)
+ {
+ case PULSE_LINE:
+ /* temporary: PULSE_LINE only makes sense for NMI lines on Z80 */
+ assert(machine->drv->cpu[cpunum].type != CPU_Z80 || line == INPUT_LINE_NMI);
+ activecpu_set_input_line(line, INTERNAL_ASSERT_LINE);
+ activecpu_set_input_line(line, INTERNAL_CLEAR_LINE);
+ break;
+
+ case HOLD_LINE:
+ case ASSERT_LINE:
+ activecpu_set_input_line(line, INTERNAL_ASSERT_LINE);
+ break;
+
+ case CLEAR_LINE:
+ activecpu_set_input_line(line, INTERNAL_CLEAR_LINE);
+ break;
+
+ default:
+ logerror("cpunum_empty_event_queue cpu #%d, line %d, unknown state %d\n", cpunum, line, state);
+ }
+
+ /* generate a trigger to unsuspend any CPUs waiting on the interrupt */
+ if (state != CLEAR_LINE)
+ cpu_triggerint(cpunum);
+ }
+ }
+
+ /* swap back */
+ cpuintrf_pop_context();
+
+ /* reset counter */
+ input_event_index[cpunum][line] = 0;
+}
+
+
+
+/*************************************
+ *
+ * Set the state of a CPU's input
+ * line
+ *
+ *************************************/
+
+void cpunum_set_input_line(int cpunum, int line, int state)
+{
+ int vector = (line >= 0 && line < MAX_INPUT_LINES) ? interrupt_vector[cpunum][line] : 0xff;
+ cpunum_set_input_line_and_vector(cpunum, line, state, vector);
+}
+
+
+void cpunum_set_input_line_vector(int cpunum, int line, int vector)
+{
+ if (cpunum < cpu_gettotalcpu() && line >= 0 && line < MAX_INPUT_LINES)
+ {
+ LOG(("cpunum_set_input_line_vector(%d,%d,$%04x)\n",cpunum,line,vector));
+ interrupt_vector[cpunum][line] = vector;
+ return;
+ }
+ LOG(("cpunum_set_input_line_vector CPU#%d line %d > max input lines\n", cpunum, line));
+}
+
+
+void cpunum_set_input_line_and_vector(int cpunum, int line, int state, int vector)
+{
+ if (line >= 0 && line < MAX_INPUT_LINES)
+ {
+ INT32 input_event = (state & 0xff) | (vector << 8);
+ int event_index = input_event_index[cpunum][line]++;
+
+ LOG(("cpunum_set_input_line_and_vector(%d,%d,%d,%02x)\n", cpunum, line, state, vector));
+
+ /* if we're full of events, flush the queue and log a message */
+ if (event_index >= MAX_INPUT_EVENTS)
+ {
+ input_event_index[cpunum][line]--;
+ cpunum_empty_event_queue(Machine, cpunum | (line << 8));
+ event_index = input_event_index[cpunum][line]++;
+ logerror("Exceeded pending input line event queue on CPU %d!\n", cpunum);
+ }
+
+ /* enqueue the event */
+ if (event_index < MAX_INPUT_EVENTS)
+ {
+ input_event_queue[cpunum][line][event_index] = input_event;
+
+ /* if this is the first one, set the timer */
+ if (event_index == 0)
+ timer_call_after_resynch(cpunum | (line << 8), cpunum_empty_event_queue);
+ }
+ }
+}
+
+
+
+
+#if 0
+#pragma mark -
+#pragma mark INTERRUPT HANDLING
+#endif
+
+/*************************************
+ *
+ * Set IRQ callback for drivers
+ *
+ *************************************/
+
+void cpunum_set_irq_callback(int cpunum, int (*callback)(int))
+{
+ drv_irq_callbacks[cpunum] = callback;
+}
+
+
+
+/*************************************
+ *
+ * Internal IRQ callbacks
+ *
+ *************************************/
+
+INLINE int cpu_irq_callback(int cpunum, int line)
+{
+ int vector = input_line_vector[cpunum][line];
+
+ LOG(("cpu_%d_irq_callback(%d) $%04x\n", cpunum, line, vector));
+
+ /* if the IRQ state is HOLD_LINE, clear it */
+ if (input_line_state[cpunum][line] == HOLD_LINE)
+ {
+ LOG(("->set_irq_line(%d,%d,%d)\n", cpunum, line, CLEAR_LINE));
+ activecpu_set_input_line(line, INTERNAL_CLEAR_LINE);
+ input_line_state[cpunum][line] = CLEAR_LINE;
+ }
+
+ /* if there's a driver callback, run it */
+ if (drv_irq_callbacks[cpunum])
+ vector = (*drv_irq_callbacks[cpunum])(line);
+
+#ifdef MAME_DEBUG
+ /* notify the debugger */
+ debug_interrupt_hook(cpunum, line);
+#endif
+
+ /* otherwise, just return the current vector */
+ return vector;
+}
+
+static int cpu_0_irq_callback(int line) { return cpu_irq_callback(0, line); }
+static int cpu_1_irq_callback(int line) { return cpu_irq_callback(1, line); }
+static int cpu_2_irq_callback(int line) { return cpu_irq_callback(2, line); }
+static int cpu_3_irq_callback(int line) { return cpu_irq_callback(3, line); }
+static int cpu_4_irq_callback(int line) { return cpu_irq_callback(4, line); }
+static int cpu_5_irq_callback(int line) { return cpu_irq_callback(5, line); }
+static int cpu_6_irq_callback(int line) { return cpu_irq_callback(6, line); }
+static int cpu_7_irq_callback(int line) { return cpu_irq_callback(7, line); }
+
+
+
diff --git a/src/emu/cpuint.h b/src/emu/cpuint.h
new file mode 100644
index 00000000000..ca45d3006c4
--- /dev/null
+++ b/src/emu/cpuint.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+
+ cpuint.h
+
+ Core multi-CPU interrupt engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CPUINT_H__
+#define __CPUINT_H__
+
+#include "memory.h"
+
+#define INTERRUPT_GEN(func) void func(void)
+
+
+
+/*************************************
+ *
+ * Startup/shutdown
+ *
+ *************************************/
+
+void cpuint_init(running_machine *machine);
+
+void cpuint_reset(void);
+
+extern int (*cpu_irq_callbacks[])(int);
+
+
+
+/*************************************
+ *
+ * CPU lines
+ *
+ *************************************/
+
+/* Set the logical state (ASSERT_LINE/CLEAR_LINE) of the an input line on a CPU */
+void cpunum_set_input_line(int cpunum, int line, int state);
+
+/* Set the vector to be returned during a CPU's interrupt acknowledge cycle */
+void cpunum_set_input_line_vector(int cpunum, int irqline, int vector);
+
+/* Set the logical state (ASSERT_LINE/CLEAR_LINE) of the an input line on a CPU and its associated vector */
+void cpunum_set_input_line_and_vector(int cpunum, int line, int state, int vector);
+
+/* Install a driver callback for IRQ acknowledge */
+void cpunum_set_irq_callback(int cpunum, int (*callback)(int irqline));
+
+
+#endif /* __CPUINT_H__ */
diff --git a/src/emu/cpuintrf.c b/src/emu/cpuintrf.c
new file mode 100644
index 00000000000..7d5e433f42e
--- /dev/null
+++ b/src/emu/cpuintrf.c
@@ -0,0 +1,1653 @@
+/***************************************************************************
+
+ cpuintrf.c
+
+ Core CPU interface functions and definitions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+/*************************************
+ *
+ * Include headers from all CPUs
+ *
+ *************************************/
+
+void dummy_get_info(UINT32 state, cpuinfo *info);
+void z80_get_info(UINT32 state, cpuinfo *info);
+void z180_get_info(UINT32 state, cpuinfo *info);
+void i8080_get_info(UINT32 state, cpuinfo *info);
+void i8085_get_info(UINT32 state, cpuinfo *info);
+void m6502_get_info(UINT32 state, cpuinfo *info);
+void m65c02_get_info(UINT32 state, cpuinfo *info);
+void m65sc02_get_info(UINT32 state, cpuinfo *info);
+void m65ce02_get_info(UINT32 state, cpuinfo *info);
+void m6509_get_info(UINT32 state, cpuinfo *info);
+void m6510_get_info(UINT32 state, cpuinfo *info);
+void m6510t_get_info(UINT32 state, cpuinfo *info);
+void m7501_get_info(UINT32 state, cpuinfo *info);
+void m8502_get_info(UINT32 state, cpuinfo *info);
+void n2a03_get_info(UINT32 state, cpuinfo *info);
+void deco16_get_info(UINT32 state, cpuinfo *info);
+void m4510_get_info(UINT32 state, cpuinfo *info);
+void h6280_get_info(UINT32 state, cpuinfo *info);
+void i8086_get_info(UINT32 state, cpuinfo *info);
+void i8088_get_info(UINT32 state, cpuinfo *info);
+void i80186_get_info(UINT32 state, cpuinfo *info);
+void i80188_get_info(UINT32 state, cpuinfo *info);
+void i80286_get_info(UINT32 state, cpuinfo *info);
+void v20_get_info(UINT32 state, cpuinfo *info);
+void v25_get_info(UINT32 state, cpuinfo *info);
+void v30_get_info(UINT32 state, cpuinfo *info);
+void v33_get_info(UINT32 state, cpuinfo *info);
+void v35_get_info(UINT32 state, cpuinfo *info);
+void v60_get_info(UINT32 state, cpuinfo *info);
+void v70_get_info(UINT32 state, cpuinfo *info);
+void i8035_get_info(UINT32 state, cpuinfo *info);
+void i8039_get_info(UINT32 state, cpuinfo *info);
+void i8048_get_info(UINT32 state, cpuinfo *info);
+void n7751_get_info(UINT32 state, cpuinfo *info);
+void i8x41_get_info(UINT32 state, cpuinfo *info);
+void i8051_get_info(UINT32 state, cpuinfo *info);
+void i8052_get_info(UINT32 state, cpuinfo *info);
+void i8751_get_info(UINT32 state, cpuinfo *info);
+void i8752_get_info(UINT32 state, cpuinfo *info);
+void m6800_get_info(UINT32 state, cpuinfo *info);
+void m6801_get_info(UINT32 state, cpuinfo *info);
+void m6802_get_info(UINT32 state, cpuinfo *info);
+void m6803_get_info(UINT32 state, cpuinfo *info);
+void m6808_get_info(UINT32 state, cpuinfo *info);
+void hd63701_get_info(UINT32 state, cpuinfo *info);
+void nsc8105_get_info(UINT32 state, cpuinfo *info);
+void m6805_get_info(UINT32 state, cpuinfo *info);
+void m68705_get_info(UINT32 state, cpuinfo *info);
+void hd63705_get_info(UINT32 state, cpuinfo *info);
+void hd6309_get_info(UINT32 state, cpuinfo *info);
+void m6809_get_info(UINT32 state, cpuinfo *info);
+void m6809e_get_info(UINT32 state, cpuinfo *info);
+void konami_get_info(UINT32 state, cpuinfo *info);
+void m68000_get_info(UINT32 state, cpuinfo *info);
+void m68008_get_info(UINT32 state, cpuinfo *info);
+void m68010_get_info(UINT32 state, cpuinfo *info);
+void m68ec020_get_info(UINT32 state, cpuinfo *info);
+void m68020_get_info(UINT32 state, cpuinfo *info);
+void m68040_get_info(UINT32 state, cpuinfo *info);
+void t11_get_info(UINT32 state, cpuinfo *info);
+void s2650_get_info(UINT32 state, cpuinfo *info);
+void tms34010_get_info(UINT32 state, cpuinfo *info);
+void tms34020_get_info(UINT32 state, cpuinfo *info);
+void ti990_10_get_info(UINT32 state, cpuinfo *info);
+void tms9900_get_info(UINT32 state, cpuinfo *info);
+void tms9940_get_info(UINT32 state, cpuinfo *info);
+void tms9980a_get_info(UINT32 state, cpuinfo *info);
+void tms9985_get_info(UINT32 state, cpuinfo *info);
+void tms9989_get_info(UINT32 state, cpuinfo *info);
+void tms9995_get_info(UINT32 state, cpuinfo *info);
+void tms99105a_get_info(UINT32 state, cpuinfo *info);
+void tms99110a_get_info(UINT32 state, cpuinfo *info);
+void z8000_get_info(UINT32 state, cpuinfo *info);
+void tms32010_get_info(UINT32 state, cpuinfo *info);
+void tms32025_get_info(UINT32 state, cpuinfo *info);
+void tms32026_get_info(UINT32 state, cpuinfo *info);
+void tms32031_get_info(UINT32 state, cpuinfo *info);
+void tms32032_get_info(UINT32 state, cpuinfo *info);
+void tms32051_get_info(UINT32 state, cpuinfo *info);
+void ccpu_get_info(UINT32 state, cpuinfo *info);
+void adsp2100_get_info(UINT32 state, cpuinfo *info);
+void adsp2101_get_info(UINT32 state, cpuinfo *info);
+void adsp2104_get_info(UINT32 state, cpuinfo *info);
+void adsp2105_get_info(UINT32 state, cpuinfo *info);
+void adsp2115_get_info(UINT32 state, cpuinfo *info);
+void adsp2181_get_info(UINT32 state, cpuinfo *info);
+void psxcpu_get_info(UINT32 state, cpuinfo *info);
+void asap_get_info(UINT32 state, cpuinfo *info);
+void upd7810_get_info(UINT32 state, cpuinfo *info);
+void upd7807_get_info(UINT32 state, cpuinfo *info);
+void jaguargpu_get_info(UINT32 state, cpuinfo *info);
+void jaguardsp_get_info(UINT32 state, cpuinfo *info);
+void r3000be_get_info(UINT32 state, cpuinfo *info);
+void r3000le_get_info(UINT32 state, cpuinfo *info);
+void r4600be_get_info(UINT32 state, cpuinfo *info);
+void r4600le_get_info(UINT32 state, cpuinfo *info);
+void r4650be_get_info(UINT32 state, cpuinfo *info);
+void r4650le_get_info(UINT32 state, cpuinfo *info);
+void r4700be_get_info(UINT32 state, cpuinfo *info);
+void r4700le_get_info(UINT32 state, cpuinfo *info);
+void r5000be_get_info(UINT32 state, cpuinfo *info);
+void r5000le_get_info(UINT32 state, cpuinfo *info);
+void qed5271be_get_info(UINT32 state, cpuinfo *info);
+void qed5271le_get_info(UINT32 state, cpuinfo *info);
+void rm7000be_get_info(UINT32 state, cpuinfo *info);
+void rm7000le_get_info(UINT32 state, cpuinfo *info);
+void arm_get_info(UINT32 state, cpuinfo *info);
+void arm7_get_info(UINT32 state, cpuinfo *info);
+void sh2_get_info(UINT32 state, cpuinfo *info);
+void sh4_get_info(UINT32 state, cpuinfo *info);
+void dsp32c_get_info(UINT32 state, cpuinfo *info);
+void pic16C54_get_info(UINT32 state, cpuinfo *info);
+void pic16C55_get_info(UINT32 state, cpuinfo *info);
+void pic16C56_get_info(UINT32 state, cpuinfo *info);
+void pic16C57_get_info(UINT32 state, cpuinfo *info);
+void pic16C58_get_info(UINT32 state, cpuinfo *info);
+void g65816_get_info(UINT32 state, cpuinfo *info);
+void spc700_get_info(UINT32 state, cpuinfo *info);
+void e116t_get_info(UINT32 state, cpuinfo *info);
+void e116xt_get_info(UINT32 state, cpuinfo *info);
+void e116xs_get_info(UINT32 state, cpuinfo *info);
+void e116xsr_get_info(UINT32 state, cpuinfo *info);
+void e132n_get_info(UINT32 state, cpuinfo *info);
+void e132t_get_info(UINT32 state, cpuinfo *info);
+void e132xn_get_info(UINT32 state, cpuinfo *info);
+void e132xt_get_info(UINT32 state, cpuinfo *info);
+void e132xs_get_info(UINT32 state, cpuinfo *info);
+void e132xsr_get_info(UINT32 state, cpuinfo *info);
+void gms30c2116_get_info(UINT32 state, cpuinfo *info);
+void gms30c2132_get_info(UINT32 state, cpuinfo *info);
+void gms30c2216_get_info(UINT32 state, cpuinfo *info);
+void gms30c2232_get_info(UINT32 state, cpuinfo *info);
+void i386_get_info(UINT32 state, cpuinfo *info);
+void i486_get_info(UINT32 state, cpuinfo *info);
+void pentium_get_info(UINT32 state, cpuinfo *info);
+void mediagx_get_info(UINT32 state, cpuinfo *info);
+void i960_get_info(UINT32 state, cpuinfo *info);
+void h8_3002_get_info(UINT32 state, cpuinfo *info);
+void v810_get_info(UINT32 state, cpuinfo *info);
+void m37702_get_info(UINT32 state, cpuinfo *info);
+void m37710_get_info(UINT32 state, cpuinfo *info);
+void ppc403_get_info(UINT32 state, cpuinfo *info);
+void ppc601_get_info(UINT32 state, cpuinfo *info);
+void ppc602_get_info(UINT32 state, cpuinfo *info);
+void ppc603_get_info(UINT32 state, cpuinfo *info);
+void mpc8240_get_info(UINT32 state, cpuinfo *info);
+void SE3208_get_info(UINT32 state, cpuinfo *info);
+void mc68hc11_get_info(UINT32 state, cpuinfo *info);
+void adsp21062_get_info(UINT32 state, cpuinfo *info);
+void dsp56k_get_info(UINT32 state, cpuinfo *info);
+void rsp_get_info(UINT32 state, cpuinfo *info);
+void alpha8201_get_info(UINT32 state, cpuinfo *info);
+void alpha8301_get_info(UINT32 state, cpuinfo *info);
+void cdp1802_get_info(UINT32 state, cpuinfo *info);
+void cop420_get_info(UINT32 state, cpuinfo *info);
+void cop410_get_info(UINT32 state, cpuinfo *info);
+void cop411_get_info(UINT32 state, cpuinfo *info);
+void tmp90840_get_info(UINT32 state, cpuinfo *info);
+void tmp90841_get_info(UINT32 state, cpuinfo *info);
+void tmp91640_get_info(UINT32 state, cpuinfo *info);
+void tmp91641_get_info(UINT32 state, cpuinfo *info);
+void apexc_get_info(UINT32 state, cpuinfo *info);
+void cp1610_get_info(UINT32 state, cpuinfo *info);
+void f8_get_info(UINT32 state, cpuinfo *info);
+void lh5801_get_info(UINT32 state, cpuinfo *info);
+void pdp1_get_info(UINT32 state, cpuinfo *info);
+void saturn_get_info(UINT32 state, cpuinfo *info);
+void sc61860_get_info(UINT32 state, cpuinfo *info);
+void tx0_64kw_get_info(UINT32 state, cpuinfo *info);
+void tx0_8kw_get_info(UINT32 state, cpuinfo *info);
+void z80gb_get_info(UINT32 state, cpuinfo *info);
+void tms7000_get_info(UINT32 state, cpuinfo *info);
+void tms7000_exl_get_info(UINT32 state, cpuinfo *info);
+void sm8500_get_info(UINT32 state, cpuinfo *info);
+void v30mz_get_info(UINT32 state, cpuinfo *info);
+void mb8841_get_info(UINT32 state, cpuinfo *info);
+void mb8842_get_info(UINT32 state, cpuinfo *info);
+void mb8843_get_info(UINT32 state, cpuinfo *info);
+void mb8844_get_info(UINT32 state, cpuinfo *info);
+void mb86233_get_info(UINT32 state, cpuinfo *info);
+void ssp1610_get_info(UINT32 state, cpuinfo *info);
+void minx_get_info(UINT32 state, cpuinfo *info);
+
+
+
+/*************************************
+ *
+ * Debug logging
+ *
+ *************************************/
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+
+/*************************************
+ *
+ * Macros to help verify active CPU
+ *
+ *************************************/
+
+#define VERIFY_ACTIVECPU(name) \
+ assert_always(activecpu >= 0, #name "() called with no active cpu!")
+
+#define VERIFY_CPUNUM(name) \
+ assert_always(cpunum >= 0 && cpunum < totalcpu, #name "() called for invalid cpu num!")
+
+#define VERIFY_CPUTYPE(name) \
+ assert_always(cputype >= 0 && cputype < CPU_COUNT, #name "() called for invalid cpu type!")
+
+
+
+/*************************************
+ *
+ * Internal CPU info type
+ *
+ *************************************/
+
+typedef struct _cpuintrf_data cpuintrf_data;
+struct _cpuintrf_data
+{
+ cpu_interface intf; /* copy of the interface data */
+ cpu_type cputype; /* type index of this CPU */
+ int family; /* family index of this CPU */
+ void *context; /* dynamically allocated context buffer */
+};
+
+
+
+/*************************************
+ *
+ * The core list of CPU interfaces
+ *
+ *************************************/
+
+cpu_interface cpuintrf[CPU_COUNT];
+
+static const struct
+{
+ int cputype;
+ void (*get_info)(UINT32 state, cpuinfo *info);
+} cpuintrf_map[] =
+{
+ { CPU_DUMMY, dummy_get_info },
+#if (HAS_Z80)
+ { CPU_Z80, z80_get_info },
+#endif
+#if (HAS_Z180)
+ { CPU_Z180, z180_get_info },
+#endif
+#if (HAS_8080)
+ { CPU_8080, i8080_get_info },
+#endif
+#if (HAS_8085A)
+ { CPU_8085A, i8085_get_info },
+#endif
+#if (HAS_M6502)
+ { CPU_M6502, m6502_get_info },
+#endif
+#if (HAS_M65C02)
+ { CPU_M65C02, m65c02_get_info },
+#endif
+#if (HAS_M65SC02)
+ { CPU_M65SC02, m65sc02_get_info },
+#endif
+#if (HAS_M65CE02)
+ { CPU_M65CE02, m65ce02_get_info },
+#endif
+#if (HAS_M6509)
+ { CPU_M6509, m6509_get_info },
+#endif
+#if (HAS_M6510)
+ { CPU_M6510, m6510_get_info },
+#endif
+#if (HAS_M6510T)
+ { CPU_M6510T, m6510t_get_info },
+#endif
+#if (HAS_M7501)
+ { CPU_M7501, m7501_get_info },
+#endif
+#if (HAS_M8502)
+ { CPU_M8502, m8502_get_info },
+#endif
+#if (HAS_N2A03)
+ { CPU_N2A03, n2a03_get_info },
+#endif
+#if (HAS_DECO16)
+ { CPU_DECO16, deco16_get_info },
+#endif
+#if (HAS_M4510)
+ { CPU_M4510, m4510_get_info },
+#endif
+#if (HAS_H6280)
+ { CPU_H6280, h6280_get_info },
+#endif
+#if (HAS_I8086)
+ { CPU_I8086, i8086_get_info },
+#endif
+#if (HAS_I8088)
+ { CPU_I8088, i8088_get_info },
+#endif
+#if (HAS_I80186)
+ { CPU_I80186, i80186_get_info },
+#endif
+#if (HAS_I80188)
+ { CPU_I80188, i80188_get_info },
+#endif
+#if (HAS_I80286)
+ { CPU_I80286, i80286_get_info },
+#endif
+#if (HAS_V20)
+ { CPU_V20, v20_get_info },
+#endif
+#if (HAS_V25)
+ { CPU_V25, v25_get_info },
+#endif
+#if (HAS_V30)
+ { CPU_V30, v30_get_info },
+#endif
+#if (HAS_V33)
+ { CPU_V33, v33_get_info },
+#endif
+#if (HAS_V35)
+ { CPU_V35, v35_get_info },
+#endif
+#if (HAS_V60)
+ { CPU_V60, v60_get_info },
+#endif
+#if (HAS_V70)
+ { CPU_V70, v70_get_info },
+#endif
+#if (HAS_I8035)
+ { CPU_I8035, i8035_get_info },
+#endif
+#if (HAS_I8039)
+ { CPU_I8039, i8039_get_info },
+#endif
+#if (HAS_I8048)
+ { CPU_I8048, i8048_get_info },
+#endif
+#if (HAS_N7751)
+ { CPU_N7751, n7751_get_info },
+#endif
+#if (HAS_I8X41)
+ { CPU_I8X41, i8x41_get_info },
+#endif
+#if (HAS_I8051)
+ { CPU_I8051, i8051_get_info },
+#endif
+#if (HAS_I8052)
+ { CPU_I8052, i8052_get_info },
+#endif
+#if (HAS_I8751)
+ { CPU_I8751, i8751_get_info },
+#endif
+#if (HAS_I8752)
+ { CPU_I8752, i8752_get_info },
+#endif
+#if (HAS_M6800)
+ { CPU_M6800, m6800_get_info },
+#endif
+#if (HAS_M6801)
+ { CPU_M6801, m6801_get_info },
+#endif
+#if (HAS_M6802)
+ { CPU_M6802, m6802_get_info },
+#endif
+#if (HAS_M6803)
+ { CPU_M6803, m6803_get_info },
+#endif
+#if (HAS_M6808)
+ { CPU_M6808, m6808_get_info },
+#endif
+#if (HAS_HD63701)
+ { CPU_HD63701, hd63701_get_info },
+#endif
+#if (HAS_NSC8105)
+ { CPU_NSC8105, nsc8105_get_info },
+#endif
+#if (HAS_M6805)
+ { CPU_M6805, m6805_get_info },
+#endif
+#if (HAS_M68705)
+ { CPU_M68705, m68705_get_info },
+#endif
+#if (HAS_HD63705)
+ { CPU_HD63705, hd63705_get_info },
+#endif
+#if (HAS_HD6309)
+ { CPU_HD6309, hd6309_get_info },
+#endif
+#if (HAS_M6809)
+ { CPU_M6809, m6809_get_info },
+#endif
+#if (HAS_M6809E)
+ { CPU_M6809E, m6809e_get_info },
+#endif
+#if (HAS_KONAMI)
+ { CPU_KONAMI, konami_get_info },
+#endif
+#if (HAS_M68000)
+ { CPU_M68000, m68000_get_info },
+#endif
+#if (HAS_M68008)
+ { CPU_M68008, m68008_get_info },
+#endif
+#if (HAS_M68010)
+ { CPU_M68010, m68010_get_info },
+#endif
+#if (HAS_M68EC020)
+ { CPU_M68EC020, m68ec020_get_info },
+#endif
+#if (HAS_M68020)
+ { CPU_M68020, m68020_get_info },
+#endif
+#if (HAS_M68040)
+ { CPU_M68040, m68040_get_info },
+#endif
+#if (HAS_T11)
+ { CPU_T11, t11_get_info },
+#endif
+#if (HAS_S2650)
+ { CPU_S2650, s2650_get_info },
+#endif
+#if (HAS_TMS34010)
+ { CPU_TMS34010, tms34010_get_info },
+#endif
+#if (HAS_TMS34020)
+ { CPU_TMS34020, tms34020_get_info },
+#endif
+#if (HAS_TI990_10)
+ { CPU_TI990_10, ti990_10_get_info },
+#endif
+#if (HAS_TMS9900)
+ { CPU_TMS9900, tms9900_get_info },
+#endif
+#if (HAS_TMS9940)
+ { CPU_TMS9940, tms9940_get_info },
+#endif
+#if (HAS_TMS9980)
+ { CPU_TMS9980, tms9980a_get_info },
+#endif
+#if (HAS_TMS9985)
+ { CPU_TMS9985, tms9985_get_info },
+#endif
+#if (HAS_TMS9989)
+ { CPU_TMS9989, tms9989_get_info },
+#endif
+#if (HAS_TMS9995)
+ { CPU_TMS9995, tms9995_get_info },
+#endif
+#if (HAS_TMS99105A)
+ { CPU_TMS99105A, tms99105a_get_info },
+#endif
+#if (HAS_TMS99110A)
+ { CPU_TMS99110A, tms99110a_get_info },
+#endif
+#if (HAS_Z8000)
+ { CPU_Z8000, z8000_get_info },
+#endif
+#if (HAS_TMS32010)
+ { CPU_TMS32010, tms32010_get_info },
+#endif
+#if (HAS_TMS32025)
+ { CPU_TMS32025, tms32025_get_info },
+#endif
+#if (HAS_TMS32026)
+ { CPU_TMS32026, tms32026_get_info },
+#endif
+#if (HAS_TMS32031)
+ { CPU_TMS32031, tms32031_get_info },
+#endif
+#if (HAS_TMS32032)
+ { CPU_TMS32032, tms32032_get_info },
+#endif
+#if (HAS_TMS32051)
+ { CPU_TMS32051, tms32051_get_info },
+#endif
+#if (HAS_CCPU)
+ { CPU_CCPU, ccpu_get_info },
+#endif
+#if (HAS_ADSP2100)
+ { CPU_ADSP2100, adsp2100_get_info },
+#endif
+#if (HAS_ADSP2101)
+ { CPU_ADSP2101, adsp2101_get_info },
+#endif
+#if (HAS_ADSP2104)
+ { CPU_ADSP2104, adsp2104_get_info },
+#endif
+#if (HAS_ADSP2105)
+ { CPU_ADSP2105, adsp2105_get_info },
+#endif
+#if (HAS_ADSP2115)
+ { CPU_ADSP2115, adsp2115_get_info },
+#endif
+#if (HAS_ADSP2181)
+ { CPU_ADSP2181, adsp2181_get_info },
+#endif
+#if (HAS_PSXCPU)
+ { CPU_PSXCPU, psxcpu_get_info },
+#endif
+#if (HAS_ASAP)
+ { CPU_ASAP, asap_get_info },
+#endif
+#if (HAS_UPD7810)
+ { CPU_UPD7810, upd7810_get_info },
+#endif
+#if (HAS_UPD7807)
+ { CPU_UPD7807, upd7807_get_info },
+#endif
+#if (HAS_JAGUAR)
+ { CPU_JAGUARGPU, jaguargpu_get_info },
+ { CPU_JAGUARDSP, jaguardsp_get_info },
+#endif
+#if (HAS_R3000)
+ { CPU_R3000BE, r3000be_get_info },
+ { CPU_R3000LE, r3000le_get_info },
+#endif
+#if (HAS_R4600)
+ { CPU_R4600BE, r4600be_get_info },
+ { CPU_R4600LE, r4600le_get_info },
+#endif
+#if (HAS_R4650)
+ { CPU_R4650BE, r4650be_get_info },
+ { CPU_R4650LE, r4650le_get_info },
+#endif
+#if (HAS_R4700)
+ { CPU_R4700BE, r4700be_get_info },
+ { CPU_R4700LE, r4700le_get_info },
+#endif
+#if (HAS_R5000)
+ { CPU_R5000BE, r5000be_get_info },
+ { CPU_R5000LE, r5000le_get_info },
+#endif
+#if (HAS_QED5271)
+ { CPU_QED5271BE, qed5271be_get_info },
+ { CPU_QED5271LE, qed5271le_get_info },
+#endif
+#if (HAS_RM7000)
+ { CPU_RM7000BE, rm7000be_get_info },
+ { CPU_RM7000LE, rm7000le_get_info },
+#endif
+#if (HAS_ARM)
+ { CPU_ARM, arm_get_info },
+#endif
+#if (HAS_ARM7)
+ { CPU_ARM7, arm7_get_info },
+#endif
+#if (HAS_SH2)
+ { CPU_SH2, sh2_get_info },
+#endif
+#if (HAS_SH4)
+ { CPU_SH4, sh4_get_info },
+#endif
+#if (HAS_DSP32C)
+ { CPU_DSP32C, dsp32c_get_info },
+#endif
+#if (HAS_PIC16C54)
+ { CPU_PIC16C54, pic16C54_get_info },
+#endif
+#if (HAS_PIC16C55)
+ { CPU_PIC16C55, pic16C55_get_info },
+#endif
+#if (HAS_PIC16C56)
+ { CPU_PIC16C56, pic16C56_get_info },
+#endif
+#if (HAS_PIC16C57)
+ { CPU_PIC16C57, pic16C57_get_info },
+#endif
+#if (HAS_PIC16C58)
+ { CPU_PIC16C58, pic16C58_get_info },
+#endif
+#if (HAS_G65816)
+ { CPU_G65816, g65816_get_info },
+#endif
+#if (HAS_SPC700)
+ { CPU_SPC700, spc700_get_info },
+#endif
+#if (HAS_E116T)
+ { CPU_E116T, e116t_get_info },
+#endif
+#if (HAS_E116XT)
+ { CPU_E116XT, e116xt_get_info },
+#endif
+#if (HAS_E116XS)
+ { CPU_E116XS, e116xs_get_info },
+#endif
+#if (HAS_E116XSR)
+ { CPU_E116XSR, e116xsr_get_info },
+#endif
+#if (HAS_E132N)
+ { CPU_E132N, e132n_get_info },
+#endif
+#if (HAS_E132T)
+ { CPU_E132T, e132t_get_info },
+#endif
+#if (HAS_E132XN)
+ { CPU_E132XN, e132xn_get_info },
+#endif
+#if (HAS_E132XT)
+ { CPU_E132XT, e132xt_get_info },
+#endif
+#if (HAS_E132XS)
+ { CPU_E132XS, e132xs_get_info },
+#endif
+#if (HAS_E132XSR)
+ { CPU_E132XSR, e132xsr_get_info },
+#endif
+#if (HAS_GMS30C2116)
+ { CPU_GMS30C2116, gms30c2116_get_info },
+#endif
+#if (HAS_GMS30C2132)
+ { CPU_GMS30C2132, gms30c2132_get_info },
+#endif
+#if (HAS_GMS30C2216)
+ { CPU_GMS30C2216, gms30c2216_get_info },
+#endif
+#if (HAS_GMS30C2232)
+ { CPU_GMS30C2232, gms30c2232_get_info },
+#endif
+#if (HAS_I386)
+ { CPU_I386, i386_get_info },
+#endif
+#if (HAS_I486)
+ { CPU_I486, i486_get_info },
+#endif
+#if (HAS_PENTIUM)
+ { CPU_PENTIUM, pentium_get_info },
+#endif
+#if (HAS_MEDIAGX)
+ { CPU_MEDIAGX, mediagx_get_info },
+#endif
+#if (HAS_I960)
+ { CPU_I960, i960_get_info },
+#endif
+#if (HAS_H83002)
+ { CPU_H83002, h8_3002_get_info },
+#endif
+#if (HAS_V810)
+ { CPU_V810, v810_get_info },
+#endif
+#if (HAS_M37702)
+ { CPU_M37702, m37702_get_info },
+#endif
+#if (HAS_M37710)
+ { CPU_M37710, m37710_get_info },
+#endif
+#if (HAS_PPC403)
+ { CPU_PPC403, ppc403_get_info },
+#endif
+#if (HAS_PPC601)
+ { CPU_PPC601, ppc601_get_info },
+#endif
+#if (HAS_PPC602)
+ { CPU_PPC602, ppc602_get_info },
+#endif
+#if (HAS_PPC603)
+ { CPU_PPC603, ppc603_get_info },
+#endif
+#if (HAS_MPC8240)
+ { CPU_MPC8240, mpc8240_get_info },
+#endif
+#if (HAS_SE3208)
+ { CPU_SE3208, SE3208_get_info },
+#endif
+#if (HAS_MC68HC11)
+ { CPU_MC68HC11, mc68hc11_get_info },
+#endif
+#if (HAS_ADSP21062)
+ { CPU_ADSP21062, adsp21062_get_info },
+#endif
+#if (HAS_DSP56156)
+ { CPU_DSP56156, dsp56k_get_info },
+#endif
+#if (HAS_RSP)
+ { CPU_RSP, rsp_get_info },
+#endif
+#if (HAS_ALPHA8201)
+ { CPU_ALPHA8201, alpha8201_get_info },
+#endif
+#if (HAS_ALPHA8301)
+ { CPU_ALPHA8301, alpha8301_get_info },
+#endif
+#if (HAS_CDP1802)
+ { CPU_CDP1802, cdp1802_get_info },
+#endif
+#if (HAS_COP420)
+ { CPU_COP420, cop420_get_info },
+#endif
+#if (HAS_COP410)
+ { CPU_COP410, cop410_get_info },
+#endif
+#if (HAS_COP411)
+ { CPU_COP411, cop411_get_info },
+#endif
+#if (HAS_TLCS90)
+ { CPU_TMP90840, tmp90840_get_info },
+ { CPU_TMP90841, tmp90841_get_info },
+ { CPU_TMP91640, tmp91640_get_info },
+ { CPU_TMP91641, tmp91641_get_info },
+#endif
+#if (HAS_APEXC)
+ { CPU_APEXC, apexc_get_info },
+#endif
+#if (HAS_CP1610)
+ { CPU_CP1610, cp1610_get_info },
+#endif
+#if (HAS_F8)
+ { CPU_F8, f8_get_info },
+#endif
+#if (HAS_LH5801)
+ { CPU_LH5801, lh5801_get_info },
+#endif
+#if (HAS_PDP1)
+ { CPU_PDP1, pdp1_get_info },
+#endif
+#if (HAS_SATURN)
+ { CPU_SATURN, saturn_get_info },
+#endif
+#if (HAS_SC61860)
+ { CPU_SC61860, sc61860_get_info },
+#endif
+#if (HAS_TX0_64KW)
+ { CPU_TX0_64KW, tx0_64kw_get_info },
+#endif
+#if (HAS_TX0_8KW)
+ { CPU_TX0_8KW, tx0_8kw_get_info },
+#endif
+#if (HAS_Z80GB)
+ { CPU_Z80GB, z80gb_get_info },
+#endif
+#if (HAS_TMS7000)
+ { CPU_TMS7000, tms7000_get_info },
+#endif
+#if (HAS_TMS7000_EXL)
+ { CPU_TMS7000_EXL, tms7000_exl_get_info },
+#endif
+#if (HAS_SM8500)
+ { CPU_SM8500, sm8500_get_info },
+#endif
+#if (HAS_V30MZ)
+ { CPU_V30MZ, v30mz_get_info },
+#endif
+#if (HAS_MB8841)
+ { CPU_MB8841, mb8841_get_info },
+#endif
+#if (HAS_MB8842)
+ { CPU_MB8842, mb8842_get_info },
+#endif
+#if (HAS_MB8843)
+ { CPU_MB8843, mb8843_get_info },
+#endif
+#if (HAS_MB8844)
+ { CPU_MB8844, mb8844_get_info },
+#endif
+#if (HAS_MB86233)
+ { CPU_MB86233, mb86233_get_info },
+#endif
+#if (HAS_SSP1610)
+ { CPU_SSP1610, ssp1610_get_info },
+#endif
+#if (HAS_MINX)
+ { CPU_MINX, minx_get_info },
+#endif
+};
+
+
+
+/*************************************
+ *
+ * Other variables we own
+ *
+ *************************************/
+
+int activecpu; /* index of active CPU (or -1) */
+int executingcpu; /* index of executing CPU (or -1) */
+int totalcpu; /* total number of CPUs */
+
+static cpuintrf_data cpu[MAX_CPU];
+
+static int cpu_active_context[CPU_COUNT];
+static int cpu_context_stack[4];
+static int cpu_context_stack_ptr;
+
+static offs_t (*cpu_dasm_override[CPU_COUNT])(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+
+#define TEMP_STRING_POOL_ENTRIES 16
+static char temp_string_pool[TEMP_STRING_POOL_ENTRIES][256];
+static int temp_string_pool_index;
+
+
+
+/*************************************
+ *
+ * Set a new CPU context
+ *
+ *************************************/
+
+INLINE void set_cpu_context(int cpunum)
+{
+ int newfamily = cpu[cpunum].family;
+ int oldcontext = cpu_active_context[newfamily];
+
+ /* if we need to change contexts, save the one that was there */
+ if (oldcontext != cpunum && oldcontext != -1)
+ (*cpu[oldcontext].intf.get_context)(cpu[oldcontext].context);
+
+ /* swap memory spaces */
+ activecpu = cpunum;
+ memory_set_context(cpunum);
+
+ /* if the new CPU's context is not swapped in, do it now */
+ if (oldcontext != cpunum)
+ {
+ (*cpu[cpunum].intf.set_context)(cpu[cpunum].context);
+ cpu_active_context[newfamily] = cpunum;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Push/pop to a new CPU context
+ *
+ *************************************/
+
+void cpuintrf_push_context(int cpunum)
+{
+ /* push the old context onto the stack */
+ cpu_context_stack[cpu_context_stack_ptr++] = activecpu;
+
+ /* do the rest only if this isn't the activecpu */
+ if (cpunum != activecpu && cpunum != -1)
+ set_cpu_context(cpunum);
+
+ /* this is now the active CPU */
+ activecpu = cpunum;
+}
+
+
+void cpuintrf_pop_context(void)
+{
+ /* push the old context onto the stack */
+ int cpunum = cpu_context_stack[--cpu_context_stack_ptr];
+
+ /* do the rest only if this isn't the activecpu */
+ if (cpunum != activecpu && cpunum != -1)
+ set_cpu_context(cpunum);
+
+ /* this is now the active CPU */
+ activecpu = cpunum;
+}
+
+
+
+/*************************************
+ *
+ * Global temp string pool
+ *
+ *************************************/
+
+char *cpuintrf_temp_str(void)
+{
+ char *string = &temp_string_pool[temp_string_pool_index++ % TEMP_STRING_POOL_ENTRIES][0];
+ string[0] = 0;
+ return string;
+}
+
+
+
+/*************************************
+ *
+ * Initialize the global interface
+ *
+ *************************************/
+
+void cpuintrf_init(running_machine *machine)
+{
+ int mapindex;
+
+ /* reset the cpuintrf array */
+ memset(cpuintrf, 0, sizeof(cpuintrf));
+
+ /* build the cpuintrf array */
+ for (mapindex = 0; mapindex < sizeof(cpuintrf_map) / sizeof(cpuintrf_map[0]); mapindex++)
+ {
+ cpu_type cputype = cpuintrf_map[mapindex].cputype;
+ cpu_interface *intf = &cpuintrf[cputype];
+ cpuinfo info;
+
+ /* start with the get_info routine */
+ intf->get_info = cpuintrf_map[mapindex].get_info;
+
+ /* bootstrap the rest of the function pointers */
+ info.setinfo = NULL;
+ (*intf->get_info)(CPUINFO_PTR_SET_INFO, &info);
+ intf->set_info = info.setinfo;
+
+ info.getcontext = NULL;
+ (*intf->get_info)(CPUINFO_PTR_GET_CONTEXT, &info);
+ intf->get_context = info.getcontext;
+
+ info.setcontext = NULL;
+ (*intf->get_info)(CPUINFO_PTR_SET_CONTEXT, &info);
+ intf->set_context = info.setcontext;
+
+ info.init = NULL;
+ (*intf->get_info)(CPUINFO_PTR_INIT, &info);
+ intf->init = info.init;
+
+ info.reset = NULL;
+ (*intf->get_info)(CPUINFO_PTR_RESET, &info);
+ intf->reset = info.reset;
+
+ info.exit = NULL;
+ (*intf->get_info)(CPUINFO_PTR_EXIT, &info);
+ intf->exit = info.exit;
+
+ info.execute = NULL;
+ (*intf->get_info)(CPUINFO_PTR_EXECUTE, &info);
+ intf->execute = info.execute;
+
+ info.burn = NULL;
+ (*intf->get_info)(CPUINFO_PTR_BURN, &info);
+ intf->burn = info.burn;
+
+ info.disassemble = NULL;
+ (*intf->get_info)(CPUINFO_PTR_DISASSEMBLE, &info);
+ intf->disassemble = info.disassemble;
+
+ info.translate = NULL;
+ (*intf->get_info)(CPUINFO_PTR_TRANSLATE, &info);
+ intf->translate = info.translate;
+
+ /* get other miscellaneous stuff */
+ intf->context_size = cputype_context_size(cputype);
+ intf->address_shift = cputype_addrbus_shift(cputype, ADDRESS_SPACE_PROGRAM);
+
+ /* also reset the active CPU context info */
+ cpu_active_context[cputype] = -1;
+ }
+
+ /* fill in any empty entries with the dummy CPU */
+ for (mapindex = 0; mapindex < CPU_COUNT; mapindex++)
+ if (cpuintrf[mapindex].get_info == NULL)
+ cpuintrf[mapindex] = cpuintrf[CPU_DUMMY];
+
+ /* zap the CPU data structure */
+ memset(cpu, 0, sizeof(cpu));
+ totalcpu = 0;
+ memset(cpu_dasm_override, 0, sizeof(cpu_dasm_override));
+
+ /* reset the context stack */
+ memset(cpu_context_stack, -1, sizeof(cpu_context_stack));
+ cpu_context_stack_ptr = 0;
+
+ /* nothing active, nothing executing */
+ activecpu = -1;
+ executingcpu = -1;
+ totalcpu = 0;
+
+ /* compute information about the CPUs now if we have a machine */
+ if (Machine != NULL)
+ {
+ /* loop over all defined CPUs */
+ for (totalcpu = 0; totalcpu < CPU_COUNT; totalcpu++)
+ {
+ cpu_type cputype = Machine->drv->cpu[totalcpu].type;
+ char familyname[256];
+ int j;
+
+ /* stop when we hit a dummy */
+ if (cputype == CPU_DUMMY)
+ break;
+
+ /* fill in the type and interface */
+ cpu[totalcpu].intf = cpuintrf[cputype];
+ cpu[totalcpu].cputype = cputype;
+
+ /* determine the family index */
+ strcpy(familyname, cputype_core_file(cputype));
+ for (j = 0; j < CPU_COUNT; j++)
+ if (!strcmp(familyname, cputype_core_file(j)))
+ {
+ cpu[totalcpu].family = j;
+ break;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Set the disassembly override proc
+ *
+ *************************************/
+
+void cpuintrf_set_dasm_override(int cpunum, offs_t (*dasm_override)(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram))
+{
+ cpu_dasm_override[cpunum] = dasm_override;
+}
+
+
+
+/*************************************
+ *
+ * Initialize a single CPU
+ *
+ *************************************/
+
+int cpuintrf_init_cpu(int cpunum, cpu_type cputype, int clock, const void *config, int (*irqcallback)(int))
+{
+ cpuinfo info;
+
+ /* allocate a context buffer for the CPU */
+ cpu[cpunum].context = auto_malloc(cpu[cpunum].intf.context_size);
+ memset(cpu[cpunum].context, 0, cpu[cpunum].intf.context_size);
+
+ /* initialize the CPU and stash the context */
+ activecpu = cpunum;
+ (*cpu[cpunum].intf.init)(cpunum, clock, config, irqcallback);
+ (*cpu[cpunum].intf.get_context)(cpu[cpunum].context);
+ activecpu = -1;
+
+ /* get the instruction count pointer */
+ info.icount = NULL;
+ (*cpu[cpunum].intf.get_info)(CPUINFO_PTR_INSTRUCTION_COUNTER, &info);
+ cpu[cpunum].intf.icount = info.icount;
+
+ /* clear out the registered CPU for this family */
+ cpu_active_context[cpu[cpunum].family] = -1;
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Exit/free a single CPU
+ *
+ *************************************/
+
+void cpuintrf_exit_cpu(int cpunum)
+{
+ /* if the CPU core defines an exit function, call it now */
+ if (cpu[cpunum].intf.exit)
+ {
+ /* switch contexts to the CPU during the exit */
+ cpuintrf_push_context(cpunum);
+ (*cpu[cpunum].intf.exit)();
+ cpuintrf_pop_context();
+ }
+}
+
+
+
+/*************************************
+ *
+ * Interfaces to the active CPU
+ *
+ *************************************/
+
+/*--------------------------
+ Get info accessors
+--------------------------*/
+
+INT64 activecpu_get_info_int(UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_ACTIVECPU(activecpu_get_info_int);
+ info.i = 0;
+ (*cpu[activecpu].intf.get_info)(state, &info);
+ return info.i;
+}
+
+void *activecpu_get_info_ptr(UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_ACTIVECPU(activecpu_get_info_ptr);
+ info.p = NULL;
+ (*cpu[activecpu].intf.get_info)(state, &info);
+ return info.p;
+}
+
+genf *activecpu_get_info_fct(UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_ACTIVECPU(activecpu_get_info_fct);
+ info.f = NULL;
+ (*cpu[activecpu].intf.get_info)(state, &info);
+ return info.f;
+}
+
+const char *activecpu_get_info_string(UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_ACTIVECPU(activecpu_get_info_string);
+ info.s = cpuintrf_temp_str();
+ (*cpu[activecpu].intf.get_info)(state, &info);
+ return info.s;
+}
+
+
+/*--------------------------
+ Set info accessors
+--------------------------*/
+
+void activecpu_set_info_int(UINT32 state, INT64 data)
+{
+ cpuinfo info;
+ VERIFY_ACTIVECPU(activecpu_set_info_int);
+ info.i = data;
+ (*cpu[activecpu].intf.set_info)(state, &info);
+}
+
+void activecpu_set_info_ptr(UINT32 state, void *data)
+{
+ cpuinfo info;
+ VERIFY_ACTIVECPU(activecpu_set_info_ptr);
+ info.p = data;
+ (*cpu[activecpu].intf.set_info)(state, &info);
+}
+
+void activecpu_set_info_fct(UINT32 state, genf *data)
+{
+ cpuinfo info;
+ VERIFY_ACTIVECPU(activecpu_set_info_fct);
+ info.f = data;
+ (*cpu[activecpu].intf.set_info)(state, &info);
+}
+
+
+/*--------------------------
+ Adjust/get icount
+--------------------------*/
+
+void activecpu_adjust_icount(int delta)
+{
+ VERIFY_ACTIVECPU(activecpu_adjust_icount);
+ *cpu[activecpu].intf.icount += delta;
+}
+
+
+int activecpu_get_icount(void)
+{
+ VERIFY_ACTIVECPU(activecpu_get_icount);
+ return *cpu[activecpu].intf.icount;
+}
+
+
+/*--------------------------
+ Reset banking pointers
+--------------------------*/
+
+void activecpu_reset_banking(void)
+{
+ VERIFY_ACTIVECPU(activecpu_reset_banking);
+ memory_set_opbase(activecpu_get_physical_pc_byte());
+}
+
+
+/*--------------------------
+ Input line setting
+--------------------------*/
+
+void activecpu_set_input_line(int irqline, int state)
+{
+ VERIFY_ACTIVECPU(activecpu_set_input_line);
+ if (state != INTERNAL_CLEAR_LINE && state != INTERNAL_ASSERT_LINE)
+ {
+ logerror("activecpu_set_input_line called when cpu_set_input_line should have been used!\n");
+ return;
+ }
+ activecpu_set_info_int(CPUINFO_INT_INPUT_STATE + irqline, state - INTERNAL_CLEAR_LINE);
+}
+
+
+/*--------------------------
+ Get/set PC
+--------------------------*/
+
+offs_t activecpu_get_physical_pc_byte(void)
+{
+ offs_t pc;
+ int shift;
+
+ VERIFY_ACTIVECPU(activecpu_get_physical_pc_byte);
+ shift = cpu[activecpu].intf.address_shift;
+ pc = activecpu_get_reg(REG_PC);
+ if (shift < 0)
+ pc <<= -shift;
+ else
+ pc >>= shift;
+ if (cpu[activecpu].intf.translate)
+ (*cpu[activecpu].intf.translate)(ADDRESS_SPACE_PROGRAM, &pc);
+ return pc;
+}
+
+
+void activecpu_set_opbase(unsigned val)
+{
+ VERIFY_ACTIVECPU(activecpu_set_opbase);
+ memory_set_opbase(val);
+}
+
+
+/*--------------------------
+ Disassembly
+--------------------------*/
+
+offs_t activecpu_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ unsigned result;
+
+ VERIFY_ACTIVECPU(activecpu_dasm);
+
+ /* check for disassembler override */
+ if (cpu_dasm_override[activecpu])
+ {
+ result = (*cpu_dasm_override[activecpu])(buffer, pc, oprom, opram);
+ if (result != 0)
+ return result;
+ }
+
+ if (cpu[activecpu].intf.disassemble != NULL)
+ {
+ result = (*cpu[activecpu].intf.disassemble)(buffer, pc, oprom, opram);
+ }
+ else
+ {
+ /* if no disassembler present, dump vanilla bytes */
+ switch (activecpu_min_instruction_bytes())
+ {
+ case 1:
+ default:
+ sprintf(buffer, "$%02X", (unsigned) *((UINT8 *) oprom));
+ result = 1;
+ break;
+
+ case 2:
+ sprintf(buffer, "$%04X", (unsigned) *((UINT16 *) oprom));
+ result = 2;
+ break;
+
+ case 4:
+ sprintf(buffer, "$%08X", (unsigned) *((UINT32 *) oprom));
+ result = 4;
+ break;
+ }
+ }
+
+ /* make sure we get good results */
+ assert((result & DASMFLAG_LENGTHMASK) != 0);
+#ifdef MAME_DEBUG
+{
+ int shift = activecpu_addrbus_shift(ADDRESS_SPACE_PROGRAM);
+ int bytes = (shift < 0) ? ((result & DASMFLAG_LENGTHMASK) << -shift) : ((result & DASMFLAG_LENGTHMASK) >> shift);
+ assert(bytes >= activecpu_min_instruction_bytes());
+ assert(bytes <= activecpu_max_instruction_bytes());
+ (void) bytes; /* appease compiler */
+}
+#endif
+
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Interfaces to a specific CPU
+ *
+ *************************************/
+
+/*--------------------------
+ Get info accessors
+--------------------------*/
+
+INT64 cpunum_get_info_int(int cpunum, UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_CPUNUM(cpunum_get_info_int);
+ cpuintrf_push_context(cpunum);
+ info.i = 0;
+ (*cpu[cpunum].intf.get_info)(state, &info);
+ cpuintrf_pop_context();
+ return info.i;
+}
+
+void *cpunum_get_info_ptr(int cpunum, UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_CPUNUM(cpunum_get_info_ptr);
+ cpuintrf_push_context(cpunum);
+ info.p = NULL;
+ (*cpu[cpunum].intf.get_info)(state, &info);
+ cpuintrf_pop_context();
+ return info.p;
+}
+
+genf *cpunum_get_info_fct(int cpunum, UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_CPUNUM(cpunum_get_info_fct);
+ cpuintrf_push_context(cpunum);
+ info.f = NULL;
+ (*cpu[cpunum].intf.get_info)(state, &info);
+ cpuintrf_pop_context();
+ return info.f;
+}
+
+const char *cpunum_get_info_string(int cpunum, UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_CPUNUM(cpunum_get_info_string);
+ cpuintrf_push_context(cpunum);
+ info.s = cpuintrf_temp_str();
+ (*cpu[cpunum].intf.get_info)(state, &info);
+ cpuintrf_pop_context();
+ return info.s;
+}
+
+
+/*--------------------------
+ Set info accessors
+--------------------------*/
+
+void cpunum_set_info_int(int cpunum, UINT32 state, INT64 data)
+{
+ cpuinfo info;
+ VERIFY_CPUNUM(cpunum_set_info_int);
+ info.i = data;
+ cpuintrf_push_context(cpunum);
+ (*cpu[cpunum].intf.set_info)(state, &info);
+ cpuintrf_pop_context();
+}
+
+void cpunum_set_info_ptr(int cpunum, UINT32 state, void *data)
+{
+ cpuinfo info;
+ VERIFY_CPUNUM(cpunum_set_info_ptr);
+ info.p = data;
+ cpuintrf_push_context(cpunum);
+ (*cpu[cpunum].intf.set_info)(state, &info);
+ cpuintrf_pop_context();
+}
+
+void cpunum_set_info_fct(int cpunum, UINT32 state, genf *data)
+{
+ cpuinfo info;
+ VERIFY_CPUNUM(cpunum_set_info_ptr);
+ info.f = data;
+ cpuintrf_push_context(cpunum);
+ (*cpu[cpunum].intf.set_info)(state, &info);
+ cpuintrf_pop_context();
+}
+
+
+/*--------------------------
+ Execute
+--------------------------*/
+
+int cpunum_execute(int cpunum, int cycles)
+{
+ int ran;
+ VERIFY_CPUNUM(cpunum_execute);
+ cpuintrf_push_context(cpunum);
+ executingcpu = cpunum;
+ memory_set_opbase(activecpu_get_physical_pc_byte());
+ ran = (*cpu[cpunum].intf.execute)(cycles);
+ executingcpu = -1;
+ cpuintrf_pop_context();
+ return ran;
+}
+
+
+/*--------------------------
+ Reset and set IRQ ack
+--------------------------*/
+
+void cpunum_reset(int cpunum)
+{
+ VERIFY_CPUNUM(cpunum_reset);
+ cpuintrf_push_context(cpunum);
+ memory_set_opbase(0);
+ (*cpu[cpunum].intf.reset)();
+ cpuintrf_pop_context();
+}
+
+
+/*--------------------------
+ Read a byte
+--------------------------*/
+
+UINT8 cpunum_read_byte(int cpunum, offs_t address)
+{
+ int result;
+ VERIFY_CPUNUM(cpunum_read_byte);
+ cpuintrf_push_context(cpunum);
+ result = program_read_byte(address);
+ cpuintrf_pop_context();
+ return result;
+}
+
+
+/*--------------------------
+ Write a byte
+--------------------------*/
+
+void cpunum_write_byte(int cpunum, offs_t address, UINT8 data)
+{
+ VERIFY_CPUNUM(cpunum_write_byte);
+ cpuintrf_push_context(cpunum);
+ program_write_byte(address, data);
+ cpuintrf_pop_context();
+}
+
+
+/*--------------------------
+ Get context pointer
+--------------------------*/
+
+void *cpunum_get_context_ptr(int cpunum)
+{
+ VERIFY_CPUNUM(cpunum_get_context_ptr);
+ return (cpu_active_context[cpu[cpunum].family] == cpunum) ? NULL : cpu[cpunum].context;
+}
+
+
+/*--------------------------
+ Get/set PC
+--------------------------*/
+
+offs_t cpunum_get_physical_pc_byte(int cpunum)
+{
+ offs_t pc;
+ int shift;
+
+ VERIFY_CPUNUM(cpunum_get_physical_pc_byte);
+ shift = cpu[cpunum].intf.address_shift;
+ cpuintrf_push_context(cpunum);
+ pc = activecpu_get_info_int(CPUINFO_INT_PC);
+ if (shift < 0)
+ pc <<= -shift;
+ else
+ pc >>= shift;
+ if (cpu[activecpu].intf.translate)
+ (*cpu[activecpu].intf.translate)(ADDRESS_SPACE_PROGRAM, &pc);
+ cpuintrf_pop_context();
+ return pc;
+}
+
+
+void cpunum_set_opbase(int cpunum, unsigned val)
+{
+ VERIFY_CPUNUM(cpunum_set_opbase);
+ cpuintrf_push_context(cpunum);
+ memory_set_opbase(val);
+ cpuintrf_pop_context();
+}
+
+
+/*--------------------------
+ Disassembly
+--------------------------*/
+
+offs_t cpunum_dasm(int cpunum, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ unsigned result;
+ VERIFY_CPUNUM(cpunum_dasm);
+ cpuintrf_push_context(cpunum);
+ result = activecpu_dasm(buffer, pc, oprom, opram);
+ cpuintrf_pop_context();
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Interfaces to a specific CPU type
+ *
+ *************************************/
+
+/*--------------------------
+ Get info accessors
+--------------------------*/
+
+INT64 cputype_get_info_int(cpu_type cputype, UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_CPUTYPE(cputype_get_info_int);
+ info.i = 0;
+ (*cpuintrf[cputype].get_info)(state, &info);
+ return info.i;
+}
+
+void *cputype_get_info_ptr(cpu_type cputype, UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_CPUTYPE(cputype_get_info_ptr);
+ info.p = NULL;
+ (*cpuintrf[cputype].get_info)(state, &info);
+ return info.p;
+}
+
+genf *cputype_get_info_fct(cpu_type cputype, UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_CPUTYPE(cputype_get_info_fct);
+ info.f = NULL;
+ (*cpuintrf[cputype].get_info)(state, &info);
+ return info.f;
+}
+
+const char *cputype_get_info_string(cpu_type cputype, UINT32 state)
+{
+ cpuinfo info;
+
+ VERIFY_CPUTYPE(cputype_get_info_string);
+ info.s = cpuintrf_temp_str();
+ (*cpuintrf[cputype].get_info)(state, &info);
+ return info.s;
+}
+
+
+
+/*************************************
+ *
+ * Dummy CPU definition
+ *
+ *************************************/
+
+struct dummy_context
+{
+ UINT32 dummy;
+};
+
+static struct dummy_context dummy_state;
+static int dummy_icount;
+
+static void dummy_init(int index, int clock, const void *config, int (*irqcallback)(int)) { }
+static void dummy_reset(void) { }
+static void dummy_exit(void) { }
+static int dummy_execute(int cycles) { return cycles; }
+static void dummy_get_context(void *regs) { }
+static void dummy_set_context(void *regs) { }
+
+static offs_t dummy_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ strcpy(buffer, "???");
+ return 1;
+}
+
+static void dummy_set_info(UINT32 state, cpuinfo *info)
+{
+}
+
+void dummy_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(dummy_state); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0; break;
+ case CPUINFO_INT_PC: info->i = 0; break;
+ case CPUINFO_INT_SP: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = dummy_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = dummy_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = dummy_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = dummy_init; break;
+ case CPUINFO_PTR_RESET: info->reset = dummy_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = dummy_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = dummy_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = dummy_dasm; break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &dummy_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, ""); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "no CPU"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "The MAME team"); break;
+
+ case CPUINFO_STR_FLAGS: strcpy(info->s, "--"); break;
+ }
+}
diff --git a/src/emu/cpuintrf.h b/src/emu/cpuintrf.h
new file mode 100644
index 00000000000..c93308a9e34
--- /dev/null
+++ b/src/emu/cpuintrf.h
@@ -0,0 +1,516 @@
+/***************************************************************************
+
+ cpuintrf.h
+
+ Core CPU interface functions and definitions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CPUINTRF_H__
+#define __CPUINTRF_H__
+
+#include "cpuint.h"
+#include "cpuexec.h"
+#include "mame.h"
+#include "state.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_CPU 8
+
+
+/* Interrupt line constants */
+enum
+{
+ /* line states */
+ CLEAR_LINE = 0, /* clear (a fired, held or pulsed) line */
+ ASSERT_LINE, /* assert an interrupt immediately */
+ HOLD_LINE, /* hold interrupt line until acknowledged */
+ PULSE_LINE, /* pulse interrupt line for one instruction */
+
+ /* internal flags (not for use by drivers!) */
+ INTERNAL_CLEAR_LINE = 100 + CLEAR_LINE,
+ INTERNAL_ASSERT_LINE = 100 + ASSERT_LINE,
+
+ /* input lines */
+ MAX_INPUT_LINES = 32+3,
+ INPUT_LINE_IRQ0 = 0,
+ INPUT_LINE_IRQ1 = 1,
+ INPUT_LINE_IRQ2 = 2,
+ INPUT_LINE_IRQ3 = 3,
+ INPUT_LINE_IRQ4 = 4,
+ INPUT_LINE_IRQ5 = 5,
+ INPUT_LINE_IRQ6 = 6,
+ INPUT_LINE_IRQ7 = 7,
+ INPUT_LINE_IRQ8 = 8,
+ INPUT_LINE_IRQ9 = 9,
+ INPUT_LINE_NMI = MAX_INPUT_LINES - 3,
+
+ /* special input lines that are implemented in the core */
+ INPUT_LINE_RESET = MAX_INPUT_LINES - 2,
+ INPUT_LINE_HALT = MAX_INPUT_LINES - 1,
+
+ /* output lines */
+ MAX_OUTPUT_LINES = 32
+};
+
+
+/* Maximum number of registers of any CPU */
+enum
+{
+ MAX_REGS = 256
+};
+
+
+/* CPU information constants */
+enum
+{
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ CPUINFO_INT_FIRST = 0x00000,
+
+ CPUINFO_INT_CONTEXT_SIZE = CPUINFO_INT_FIRST, /* R/O: size of CPU context in bytes */
+ CPUINFO_INT_INPUT_LINES, /* R/O: number of input lines */
+ CPUINFO_INT_OUTPUT_LINES, /* R/O: number of output lines */
+ CPUINFO_INT_DEFAULT_IRQ_VECTOR, /* R/O: default IRQ vector */
+ CPUINFO_INT_ENDIANNESS, /* R/O: either CPU_IS_BE or CPU_IS_LE */
+ CPUINFO_INT_CLOCK_DIVIDER, /* R/O: internal clock divider */
+ CPUINFO_INT_MIN_INSTRUCTION_BYTES, /* R/O: minimum bytes per instruction */
+ CPUINFO_INT_MAX_INSTRUCTION_BYTES, /* R/O: maximum bytes per instruction */
+ CPUINFO_INT_MIN_CYCLES, /* R/O: minimum cycles for a single instruction */
+ CPUINFO_INT_MAX_CYCLES, /* R/O: maximum cycles for a single instruction */
+
+ CPUINFO_INT_DATABUS_WIDTH, /* R/O: data bus size for each address space (8,16,32,64) */
+ CPUINFO_INT_DATABUS_WIDTH_LAST = CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACES - 1,
+ CPUINFO_INT_ADDRBUS_WIDTH, /* R/O: address bus size for each address space (12-32) */
+ CPUINFO_INT_ADDRBUS_WIDTH_LAST = CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACES - 1,
+ CPUINFO_INT_ADDRBUS_SHIFT, /* R/O: shift applied to addresses each address space (+3 means >>3, -1 means <<1) */
+ CPUINFO_INT_ADDRBUS_SHIFT_LAST = CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACES - 1,
+ CPUINFO_INT_LOGADDR_WIDTH, /* R/O: address bus size for logical accesses in each space (0=same as physical) */
+ CPUINFO_INT_LOGADDR_WIDTH_LAST = CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACES - 1,
+ CPUINFO_INT_PAGE_SHIFT, /* R/O: size of a page log 2 (i.e., 12=4096), or 0 if paging not supported */
+ CPUINFO_INT_PAGE_SHIFT_LAST = CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACES - 1,
+
+ CPUINFO_INT_SP, /* R/W: the current stack pointer value */
+ CPUINFO_INT_PC, /* R/W: the current PC value */
+ CPUINFO_INT_PREVIOUSPC, /* R/W: the previous PC value */
+ CPUINFO_INT_INPUT_STATE, /* R/W: states for each input line */
+ CPUINFO_INT_INPUT_STATE_LAST = CPUINFO_INT_INPUT_STATE + MAX_INPUT_LINES - 1,
+ CPUINFO_INT_OUTPUT_STATE, /* R/W: states for each output line */
+ CPUINFO_INT_OUTPUT_STATE_LAST = CPUINFO_INT_OUTPUT_STATE + MAX_OUTPUT_LINES - 1,
+ CPUINFO_INT_REGISTER, /* R/W: values of up to MAX_REGs registers */
+ CPUINFO_INT_REGISTER_LAST = CPUINFO_INT_REGISTER + MAX_REGS - 1,
+
+ CPUINFO_INT_CPU_SPECIFIC = 0x08000, /* R/W: CPU-specific values start here */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ CPUINFO_PTR_FIRST = 0x10000,
+
+ CPUINFO_PTR_SET_INFO = CPUINFO_PTR_FIRST, /* R/O: void (*set_info)(UINT32 state, INT64 data, void *ptr) */
+ CPUINFO_PTR_GET_CONTEXT, /* R/O: void (*get_context)(void *buffer) */
+ CPUINFO_PTR_SET_CONTEXT, /* R/O: void (*set_context)(void *buffer) */
+ CPUINFO_PTR_INIT, /* R/O: void (*init)(int index, int clock, const void *config, int (*irqcallback)(int)) */
+ CPUINFO_PTR_RESET, /* R/O: void (*reset)(void) */
+ CPUINFO_PTR_EXIT, /* R/O: void (*exit)(void) */
+ CPUINFO_PTR_EXECUTE, /* R/O: int (*execute)(int cycles) */
+ CPUINFO_PTR_BURN, /* R/O: void (*burn)(int cycles) */
+ CPUINFO_PTR_DISASSEMBLE, /* R/O: offs_t (*disassemble)(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram) */
+ CPUINFO_PTR_TRANSLATE, /* R/O: int (*translate)(int space, offs_t *address) */
+ CPUINFO_PTR_READ, /* R/O: int (*read)(int space, UINT32 offset, int size, UINT64 *value) */
+ CPUINFO_PTR_WRITE, /* R/O: int (*write)(int space, UINT32 offset, int size, UINT64 value) */
+ CPUINFO_PTR_READOP, /* R/O: int (*readop)(UINT32 offset, int size, UINT64 *value) */
+ CPUINFO_PTR_DEBUG_SETUP_COMMANDS, /* R/O: void (*setup_commands)(void) */
+ CPUINFO_PTR_INSTRUCTION_COUNTER, /* R/O: int *icount */
+ CPUINFO_PTR_INTERNAL_MEMORY_MAP, /* R/O: construct_map_t map */
+ CPUINFO_PTR_INTERNAL_MEMORY_MAP_LAST = CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACES - 1,
+ CPUINFO_PTR_DEBUG_REGISTER_LIST, /* R/O: int *list: list of registers for the debugger */
+
+ CPUINFO_PTR_CPU_SPECIFIC = 0x18000, /* R/W: CPU-specific values start here */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ CPUINFO_STR_FIRST = 0x20000,
+
+ CPUINFO_STR_NAME = CPUINFO_STR_FIRST, /* R/O: name of the CPU */
+ CPUINFO_STR_CORE_FAMILY, /* R/O: family of the CPU */
+ CPUINFO_STR_CORE_VERSION, /* R/O: version of the CPU core */
+ CPUINFO_STR_CORE_FILE, /* R/O: file containing the CPU core */
+ CPUINFO_STR_CORE_CREDITS, /* R/O: credits for the CPU core */
+ CPUINFO_STR_FLAGS, /* R/O: string representation of the main flags value */
+ CPUINFO_STR_REGISTER, /* R/O: string representation of up to MAX_REGs registers */
+ CPUINFO_STR_REGISTER_LAST = CPUINFO_STR_REGISTER + MAX_REGS - 1,
+
+ CPUINFO_STR_CPU_SPECIFIC = 0x28000 /* R/W: CPU-specific values start here */
+};
+
+
+/* get_reg/set_reg constants */
+enum
+{
+ /* This value is passed to activecpu_get_reg to retrieve the previous
+ * program counter value, ie. before a CPU emulation started
+ * to fetch opcodes and arguments for the current instrution. */
+ REG_PREVIOUSPC = CPUINFO_INT_PREVIOUSPC - CPUINFO_INT_REGISTER,
+
+ /* This value is passed to activecpu_get_reg to retrieve the current
+ * program counter value. */
+ REG_PC = CPUINFO_INT_PC - CPUINFO_INT_REGISTER,
+
+ /* This value is passed to activecpu_get_reg to retrieve the current
+ * stack pointer value. */
+ REG_SP = CPUINFO_INT_SP - CPUINFO_INT_REGISTER
+};
+
+
+/* Endianness constants */
+enum
+{
+ CPU_IS_LE = 0, /* emulated CPU is little endian */
+ CPU_IS_BE /* emulated CPU is big endian */
+};
+
+
+/* Disassembler constants */
+#define DASMFLAG_SUPPORTED 0x80000000 /* are disassembly flags supported? */
+#define DASMFLAG_STEP_OUT 0x40000000 /* this instruction should be the end of a step out sequence */
+#define DASMFLAG_STEP_OVER 0x20000000 /* this instruction should be stepped over by setting a breakpoint afterwards */
+#define DASMFLAG_OVERINSTMASK 0x18000000 /* number of extra instructions to skip when stepping over */
+#define DASMFLAG_OVERINSTSHIFT 27 /* bits to shift after masking to get the value */
+#define DASMFLAG_LENGTHMASK 0x0000ffff /* the low 16-bits contain the actual length */
+#define DASMFLAG_STEP_OVER_EXTRA(x) ((x) << DASMFLAG_OVERINSTSHIFT)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* forward declaration of this union */
+typedef union _cpuinfo cpuinfo;
+
+
+/* define the various callback functions */
+typedef void (*cpufunc_get_info)(UINT32 state, cpuinfo *info);
+typedef void (*cpufunc_set_info)(UINT32 state, cpuinfo *info);
+typedef void (*cpufunc_get_context)(void *buffer);
+typedef void (*cpufunc_set_context)(void *buffer);
+typedef void (*cpufunc_init)(int index, int clock, const void *config, int (*irqcallback)(int));
+typedef void (*cpufunc_reset)(void);
+typedef void (*cpufunc_exit)(void);
+typedef int (*cpufunc_execute)(int cycles);
+typedef void (*cpufunc_burn)(int cycles);
+typedef offs_t (*cpufunc_disassemble)(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+typedef int (*cpufunc_translate)(int space, offs_t *address);
+typedef int (*cpufunc_read)(int space, UINT32 offset, int size, UINT64 *value);
+typedef int (*cpufunc_write)(int space, UINT32 offset, int size, UINT64 value);
+typedef int (*cpufunc_readop)(UINT32 offset, int size, UINT64 *value);
+typedef void (*cpufunc_setup_commands)(void);
+
+
+/* cpuinfo union used to pass data to/from the get_info/set_info functions */
+union _cpuinfo
+{
+ INT64 i; /* generic integers */
+ void * p; /* generic pointers */
+ genf * f; /* generic function pointers */
+ char * s; /* generic strings */
+
+ cpufunc_set_info setinfo; /* CPUINFO_PTR_SET_INFO */
+ cpufunc_get_context getcontext; /* CPUINFO_PTR_GET_CONTEXT */
+ cpufunc_set_context setcontext; /* CPUINFO_PTR_SET_CONTEXT */
+ cpufunc_init init; /* CPUINFO_PTR_INIT */
+ cpufunc_reset reset; /* CPUINFO_PTR_RESET */
+ cpufunc_exit exit; /* CPUINFO_PTR_EXIT */
+ cpufunc_execute execute; /* CPUINFO_PTR_EXECUTE */
+ cpufunc_burn burn; /* CPUINFO_PTR_BURN */
+ cpufunc_disassemble disassemble; /* CPUINFO_PTR_DISASSEMBLE */
+ cpufunc_translate translate; /* CPUINFO_PTR_TRANSLATE */
+ cpufunc_read read; /* CPUINFO_PTR_READ */
+ cpufunc_write write; /* CPUINFO_PTR_WRITE */
+ cpufunc_readop readop; /* CPUINFO_PTR_READOP */
+ cpufunc_setup_commands setup_commands; /* CPUINFO_PTR_DEBUG_SETUP_COMMANDS */
+ int * icount; /* CPUINFO_PTR_INSTRUCTION_COUNTER */
+ construct_map_t internal_map; /* CPUINFO_PTR_INTERNAL_MEMORY_MAP */
+};
+
+
+typedef struct _cpu_interface cpu_interface;
+struct _cpu_interface
+{
+ /* table of core functions */
+ cpufunc_get_info get_info;
+ cpufunc_set_info set_info;
+ cpufunc_get_context get_context;
+ cpufunc_set_context set_context;
+ cpufunc_init init;
+ cpufunc_reset reset;
+ cpufunc_exit exit;
+ cpufunc_execute execute;
+ cpufunc_burn burn;
+ cpufunc_disassemble disassemble;
+ cpufunc_translate translate;
+
+ /* other info */
+ size_t context_size;
+ INT8 address_shift;
+ int * icount;
+};
+
+
+
+/***************************************************************************
+ CORE CPU INTERFACE FUNCTIONS
+***************************************************************************/
+
+/* reset the internal CPU tracking */
+void cpuintrf_init(running_machine *machine);
+
+/* set up the interface for one CPU of a given type */
+int cpuintrf_init_cpu(int cpunum, cpu_type cputype, int clock, const void *config, int (*irqcallback)(int));
+
+/* clean up the interface for one CPU */
+void cpuintrf_exit_cpu(int cpunum);
+
+/* remember the previous context and set a new one */
+void cpuintrf_push_context(int cpunum);
+
+/* restore the previous context */
+void cpuintrf_pop_context(void);
+
+/* circular string buffer */
+char *cpuintrf_temp_str(void);
+
+/* set the dasm override handler */
+void cpuintrf_set_dasm_override(int cpunum, offs_t (*dasm_override)(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram));
+
+
+
+/***************************************************************************
+ ACTIVE CPU ACCCESSORS
+***************************************************************************/
+
+/* get info accessors */
+INT64 activecpu_get_info_int(UINT32 state);
+void *activecpu_get_info_ptr(UINT32 state);
+genf *activecpu_get_info_fct(UINT32 state);
+const char *activecpu_get_info_string(UINT32 state);
+
+/* set info accessors */
+void activecpu_set_info_int(UINT32 state, INT64 data);
+void activecpu_set_info_ptr(UINT32 state, void *data);
+void activecpu_set_info_fct(UINT32 state, genf *data);
+
+/* apply a +/- to the current icount */
+void activecpu_adjust_icount(int delta);
+
+/* return the current icount */
+int activecpu_get_icount(void);
+
+/* ensure banking is reset properly */
+void activecpu_reset_banking(void);
+
+/* set the input line on a CPU -- drivers use cpu_set_input_line() */
+void activecpu_set_input_line(int irqline, int state);
+
+/* return the PC, corrected to a byte offset, on the active CPU */
+offs_t activecpu_get_physical_pc_byte(void);
+
+/* update the banking on the active CPU */
+void activecpu_set_opbase(offs_t val);
+
+/* disassemble a line at a given PC on the active CPU */
+offs_t activecpu_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+
+#define activecpu_context_size() activecpu_get_info_int(CPUINFO_INT_CONTEXT_SIZE)
+#define activecpu_input_lines() activecpu_get_info_int(CPUINFO_INT_INPUT_LINES)
+#define activecpu_output_lines() activecpu_get_info_int(CPUINFO_INT_OUTPUT_LINES)
+#define activecpu_default_irq_vector() activecpu_get_info_int(CPUINFO_INT_DEFAULT_IRQ_VECTOR)
+#define activecpu_endianness() activecpu_get_info_int(CPUINFO_INT_ENDIANNESS)
+#define activecpu_clock_divider() activecpu_get_info_int(CPUINFO_INT_CLOCK_DIVIDER)
+#define activecpu_min_instruction_bytes() activecpu_get_info_int(CPUINFO_INT_MIN_INSTRUCTION_BYTES)
+#define activecpu_max_instruction_bytes() activecpu_get_info_int(CPUINFO_INT_MAX_INSTRUCTION_BYTES)
+#define activecpu_min_cycles() activecpu_get_info_int(CPUINFO_INT_MIN_CYCLES)
+#define activecpu_max_cycles() activecpu_get_info_int(CPUINFO_INT_MAX_CYCLES)
+#define activecpu_databus_width(space) activecpu_get_info_int(CPUINFO_INT_DATABUS_WIDTH + (space))
+#define activecpu_addrbus_width(space) activecpu_get_info_int(CPUINFO_INT_ADDRBUS_WIDTH + (space))
+#define activecpu_addrbus_shift(space) activecpu_get_info_int(CPUINFO_INT_ADDRBUS_SHIFT + (space))
+#define activecpu_logaddr_width(space) activecpu_get_info_int(CPUINFO_INT_LOGADDR_WIDTH + (space))
+#define activecpu_page_shift(space) activecpu_get_info_int(CPUINFO_INT_PAGE_SHIFT + (space))
+#define activecpu_get_reg(reg) activecpu_get_info_int(CPUINFO_INT_REGISTER + (reg))
+#define activecpu_debug_register_list() activecpu_get_info_ptr(CPUINFO_PTR_DEBUG_REGISTER_LIST)
+#define activecpu_name() activecpu_get_info_string(CPUINFO_STR_NAME)
+#define activecpu_core_family() activecpu_get_info_string(CPUINFO_STR_CORE_FAMILY)
+#define activecpu_core_version() activecpu_get_info_string(CPUINFO_STR_CORE_VERSION)
+#define activecpu_core_file() activecpu_get_info_string(CPUINFO_STR_CORE_FILE)
+#define activecpu_core_credits() activecpu_get_info_string(CPUINFO_STR_CORE_CREDITS)
+#define activecpu_flags() activecpu_get_info_string(CPUINFO_STR_FLAGS)
+#define activecpu_irq_string(irq) activecpu_get_info_string(CPUINFO_STR_IRQ_STATE + (irq))
+#define activecpu_reg_string(reg) activecpu_get_info_string(CPUINFO_STR_REGISTER + (reg))
+
+#define activecpu_set_reg(reg, val) activecpu_set_info_int(CPUINFO_INT_REGISTER + (reg), (val))
+
+
+
+/***************************************************************************
+ SPECIFIC CPU ACCCESSORS
+***************************************************************************/
+
+/* get info accessors */
+INT64 cpunum_get_info_int(int cpunum, UINT32 state);
+void *cpunum_get_info_ptr(int cpunum, UINT32 state);
+genf *cpunum_get_info_fct(int cpunum, UINT32 state);
+const char *cpunum_get_info_string(int cpunum, UINT32 state);
+
+/* set info accessors */
+void cpunum_set_info_int(int cpunum, UINT32 state, INT64 data);
+void cpunum_set_info_ptr(int cpunum, UINT32 state, void *data);
+void cpunum_set_info_fct(int cpunum, UINT32 state, genf *data);
+
+/* execute the requested cycles on a given CPU */
+int cpunum_execute(int cpunum, int cycles);
+
+/* signal a reset for a given CPU */
+void cpunum_reset(int cpunum);
+
+/* read a byte from another CPU's memory space */
+UINT8 cpunum_read_byte(int cpunum, offs_t address);
+
+/* write a byte from another CPU's memory space */
+void cpunum_write_byte(int cpunum, offs_t address, UINT8 data);
+
+/* return a pointer to the saved context of a given CPU, or NULL if the
+ context is active (and contained within the CPU core */
+void *cpunum_get_context_ptr(int cpunum);
+
+/* return the PC, corrected to a byte offset, on a given CPU */
+offs_t cpunum_get_physical_pc_byte(int cpunum);
+
+/* update the banking on a given CPU */
+void cpunum_set_opbase(int cpunum, offs_t val);
+
+/* disassemble a line at a given PC on a given CPU */
+offs_t cpunum_dasm(int cpunum, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
+
+#define cpunum_context_size(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_CONTEXT_SIZE)
+#define cpunum_input_lines(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_INPUT_LINES)
+#define cpunum_output_lines(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_OUTPUT_LINES)
+#define cpunum_default_irq_vector(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_DEFAULT_IRQ_VECTOR)
+#define cpunum_endianness(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_ENDIANNESS)
+#define cpunum_clock_divider(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_CLOCK_DIVIDER)
+#define cpunum_min_instruction_bytes(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_MIN_INSTRUCTION_BYTES)
+#define cpunum_max_instruction_bytes(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_MAX_INSTRUCTION_BYTES)
+#define cpunum_min_cycles(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_MIN_CYCLES)
+#define cpunum_max_cycles(cpunum) cpunum_get_info_int(cpunum, CPUINFO_INT_MAX_CYCLES)
+#define cpunum_databus_width(cpunum, space) cpunum_get_info_int(cpunum, CPUINFO_INT_DATABUS_WIDTH + (space))
+#define cpunum_addrbus_width(cpunum, space) cpunum_get_info_int(cpunum, CPUINFO_INT_ADDRBUS_WIDTH + (space))
+#define cpunum_addrbus_shift(cpunum, space) cpunum_get_info_int(cpunum, CPUINFO_INT_ADDRBUS_SHIFT + (space))
+#define cpunum_logaddr_width(cpunum, space) cpunum_get_info_int(cpunum, CPUINFO_INT_LOGADDR_WIDTH + (space))
+#define cpunum_page_shift(cpunum, space) cpunum_get_info_int(cpunum, CPUINFO_INT_PAGE_SHIFT + (space))
+#define cpunum_get_reg(cpunum, reg) cpunum_get_info_int(cpunum, CPUINFO_INT_REGISTER + (reg))
+#define cpunum_debug_register_list(cpunum) cpunum_get_info_ptr(cpunum, CPUINFO_PTR_DEBUG_REGISTER_LIST)
+#define cpunum_name(cpunum) cpunum_get_info_string(cpunum, CPUINFO_STR_NAME)
+#define cpunum_core_family(cpunum) cpunum_get_info_string(cpunum, CPUINFO_STR_CORE_FAMILY)
+#define cpunum_core_version(cpunum) cpunum_get_info_string(cpunum, CPUINFO_STR_CORE_VERSION)
+#define cpunum_core_file(cpunum) cpunum_get_info_string(cpunum, CPUINFO_STR_CORE_FILE)
+#define cpunum_core_credits(cpunum) cpunum_get_info_string(cpunum, CPUINFO_STR_CORE_CREDITS)
+#define cpunum_flags(cpunum) cpunum_get_info_string(cpunum, CPUINFO_STR_FLAGS)
+#define cpunum_irq_string(cpunum, irq) cpunum_get_info_string(cpunum, CPUINFO_STR_IRQ_STATE + (irq))
+#define cpunum_reg_string(cpunum, reg) cpunum_get_info_string(cpunum, CPUINFO_STR_REGISTER + (reg))
+
+#define cpunum_set_reg(cpunum, reg, val) cpunum_set_info_int(cpunum, CPUINFO_INT_REGISTER + (reg), (val))
+
+
+
+/***************************************************************************
+ CPU TYPE ACCCESSORS
+***************************************************************************/
+
+/* get info accessors */
+INT64 cputype_get_info_int(cpu_type cputype, UINT32 state);
+void *cputype_get_info_ptr(cpu_type cputype, UINT32 state);
+genf *cputype_get_info_fct(cpu_type cputype, UINT32 state);
+const char *cputype_get_info_string(cpu_type cputype, UINT32 state);
+
+#define cputype_context_size(cputype) cputype_get_info_int(cputype, CPUINFO_INT_CONTEXT_SIZE)
+#define cputype_input_lines(cputype) cputype_get_info_int(cputype, CPUINFO_INT_INPUT_LINES)
+#define cputype_output_lines(cputype) cputype_get_info_int(cputype, CPUINFO_INT_OUTPUT_LINES)
+#define cputype_default_irq_vector(cputype) cputype_get_info_int(cputype, CPUINFO_INT_DEFAULT_IRQ_VECTOR)
+#define cputype_endianness(cputype) cputype_get_info_int(cputype, CPUINFO_INT_ENDIANNESS)
+#define cputype_clock_divider(cputype) cputype_get_info_int(cputype, CPUINFO_INT_CLOCK_DIVIDER)
+#define cputype_min_instruction_bytes(cputype) cputype_get_info_int(cputype, CPUINFO_INT_MIN_INSTRUCTION_BYTES)
+#define cputype_max_instruction_bytes(cputype) cputype_get_info_int(cputype, CPUINFO_INT_MAX_INSTRUCTION_BYTES)
+#define cputype_min_cycles(cputype) cputype_get_info_int(cputype, CPUINFO_INT_MIN_CYCLES)
+#define cputype_max_cycles(cputype) cputype_get_info_int(cputype, CPUINFO_INT_MAX_CYCLES)
+#define cputype_databus_width(cputype, space) cputype_get_info_int(cputype, CPUINFO_INT_DATABUS_WIDTH + (space))
+#define cputype_addrbus_width(cputype, space) cputype_get_info_int(cputype, CPUINFO_INT_ADDRBUS_WIDTH + (space))
+#define cputype_addrbus_shift(cputype, space) cputype_get_info_int(cputype, CPUINFO_INT_ADDRBUS_SHIFT + (space))
+#define cputype_page_shift(cputype, space) cputype_get_info_int(cputype, CPUINFO_INT_PAGE_SHIFT + (space))
+#define cputype_debug_register_list(cputype) cputype_get_info_ptr(cputype, CPUINFO_PTR_DEBUG_REGISTER_LIST)
+#define cputype_name(cputype) cputype_get_info_string(cputype, CPUINFO_STR_NAME)
+#define cputype_core_family(cputype) cputype_get_info_string(cputype, CPUINFO_STR_CORE_FAMILY)
+#define cputype_core_version(cputype) cputype_get_info_string(cputype, CPUINFO_STR_CORE_VERSION)
+#define cputype_core_file(cputype) cputype_get_info_string(cputype, CPUINFO_STR_CORE_FILE)
+#define cputype_core_credits(cputype) cputype_get_info_string(cputype, CPUINFO_STR_CORE_CREDITS)
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define activecpu_get_previouspc() ((offs_t)activecpu_get_reg(REG_PREVIOUSPC))
+#define activecpu_get_pc() ((offs_t)activecpu_get_reg(REG_PC))
+#define activecpu_get_sp() activecpu_get_reg(REG_SP)
+
+
+
+/***************************************************************************
+ CPU INTERFACE ACCESSORS
+***************************************************************************/
+
+/* return a pointer to the interface struct for a given CPU type */
+INLINE const cpu_interface *cputype_get_interface(cpu_type cputype)
+{
+ extern cpu_interface cpuintrf[];
+ return &cpuintrf[cputype];
+}
+
+
+/* return a the index of the active CPU */
+INLINE int cpu_getactivecpu(void)
+{
+ extern int activecpu;
+ return activecpu;
+}
+
+
+/* return a the index of the executing CPU */
+INLINE int cpu_getexecutingcpu(void)
+{
+ extern int executingcpu;
+ return executingcpu;
+}
+
+
+/* return a the total number of registered CPUs */
+INLINE int cpu_gettotalcpu(void)
+{
+ extern int totalcpu;
+ return totalcpu;
+}
+
+
+/* return the current PC or ~0 if no CPU is active */
+INLINE offs_t safe_activecpu_get_pc(void)
+{
+ return (cpu_getactivecpu() >= 0) ? activecpu_get_pc() : ~0;
+}
+
+
+#endif /* __CPUINTRF_H__ */
diff --git a/src/emu/debug/debugcmd.c b/src/emu/debug/debugcmd.c
new file mode 100644
index 00000000000..41fe159e064
--- /dev/null
+++ b/src/emu/debug/debugcmd.c
@@ -0,0 +1,2200 @@
+/*********************************************************************
+
+ debugcmd.h
+
+ Debugger command interface engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "debugcmd.h"
+#include "debugcmt.h"
+#include "debugcon.h"
+#include "debugcpu.h"
+#include "express.h"
+#include "debughlp.h"
+#include "debugvw.h"
+#include "render.h"
+#include <stdarg.h>
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_GLOBALS 1000
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static struct
+{
+ void * base;
+ UINT32 size;
+} global_array[MAX_GLOBALS];
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void debug_command_exit(running_machine *machine);
+
+static UINT64 execute_min(UINT32 ref, UINT32 params, UINT64 *param);
+static UINT64 execute_max(UINT32 ref, UINT32 params, UINT64 *param);
+static UINT64 execute_if(UINT32 ref, UINT32 params, UINT64 *param);
+
+static UINT64 global_get(UINT32 ref);
+static void global_set(UINT32 ref, UINT64 value);
+
+static void execute_help(int ref, int params, const char **param);
+static void execute_print(int ref, int params, const char **param);
+static void execute_printf(int ref, int params, const char **param);
+static void execute_logerror(int ref, int params, const char **param);
+static void execute_tracelog(int ref, int params, const char **param);
+static void execute_quit(int ref, int params, const char **param);
+static void execute_do(int ref, int params, const char **param);
+static void execute_step(int ref, int params, const char **param);
+static void execute_over(int ref, int params, const char **param);
+static void execute_out(int ref, int params, const char **param);
+static void execute_go(int ref, int params, const char **param);
+static void execute_go_vblank(int ref, int params, const char **param);
+static void execute_go_interrupt(int ref, int params, const char **param);
+static void execute_go_time(int ref, int params, const char *param[]);
+static void execute_focus(int ref, int params, const char **param);
+static void execute_ignore(int ref, int params, const char **param);
+static void execute_observe(int ref, int params, const char **param);
+static void execute_next(int ref, int params, const char **param);
+static void execute_comment(int ref, int params, const char **param);
+static void execute_comment_del(int ref, int params, const char **param);
+static void execute_comment_save(int ref, int params, const char **param);
+static void execute_bpset(int ref, int params, const char **param);
+static void execute_bpclear(int ref, int params, const char **param);
+static void execute_bpdisenable(int ref, int params, const char **param);
+static void execute_bplist(int ref, int params, const char **param);
+static void execute_wpset(int ref, int params, const char **param);
+static void execute_wpclear(int ref, int params, const char **param);
+static void execute_wpdisenable(int ref, int params, const char **param);
+static void execute_wplist(int ref, int params, const char **param);
+static void execute_hotspot(int ref, int params, const char **param);
+static void execute_save(int ref, int params, const char **param);
+static void execute_dump(int ref, int params, const char **param);
+static void execute_dasm(int ref, int params, const char **param);
+static void execute_find(int ref, int params, const char **param);
+static void execute_trace(int ref, int params, const char **param);
+static void execute_traceover(int ref, int params, const char **param);
+static void execute_traceflush(int ref, int params, const char **param);
+static void execute_history(int ref, int params, const char **param);
+static void execute_snap(int ref, int params, const char **param);
+static void execute_source(int ref, int params, const char **param);
+static void execute_map(int ref, int params, const char **param);
+static void execute_memdump(int ref, int params, const char **param);
+static void execute_symlist(int ref, int params, const char **param);
+static void execute_softreset(int ref, int params, const char **param);
+static void execute_hardreset(int ref, int params, const char **param);
+
+
+
+/***************************************************************************
+
+ Initialization
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_command_init - initializes the command
+ system
+-------------------------------------------------*/
+
+void debug_command_init(running_machine *machine)
+{
+ int cpunum, itemnum;
+ const char *name;
+
+ /* add a few simple global functions */
+ symtable_add_function(global_symtable, "min", 0, 2, 2, execute_min);
+ symtable_add_function(global_symtable, "max", 0, 2, 2, execute_max);
+ symtable_add_function(global_symtable, "if", 0, 3, 3, execute_if);
+
+ /* add all single-entry save state globals */
+ for (itemnum = 0; itemnum < MAX_GLOBALS; itemnum++)
+ {
+ UINT32 valsize, valcount;
+ void *base;
+
+ /* stop when we run out of items */
+ name = state_save_get_indexed_item(itemnum, &base, &valsize, &valcount);
+ if (name == NULL)
+ break;
+
+ /* if this is a single-entry global, add it */
+ if (valcount == 1 && strstr(name, "/globals/"))
+ {
+ char symname[100];
+ sprintf(symname, ".%s", strrchr(name, '/') + 1);
+ global_array[itemnum].base = base;
+ global_array[itemnum].size = valsize;
+ symtable_add_register(global_symtable, symname, itemnum, global_get, global_set);
+ }
+ }
+
+ /* add all the commands */
+ debug_console_register_command("help", CMDFLAG_NONE, 0, 0, 1, execute_help);
+ debug_console_register_command("print", CMDFLAG_NONE, 0, 1, MAX_COMMAND_PARAMS, execute_print);
+ debug_console_register_command("printf", CMDFLAG_NONE, 0, 1, MAX_COMMAND_PARAMS, execute_printf);
+ debug_console_register_command("logerror", CMDFLAG_NONE, 0, 1, MAX_COMMAND_PARAMS, execute_logerror);
+ debug_console_register_command("tracelog", CMDFLAG_NONE, 0, 1, MAX_COMMAND_PARAMS, execute_tracelog);
+ debug_console_register_command("quit", CMDFLAG_NONE, 0, 0, 0, execute_quit);
+ debug_console_register_command("do", CMDFLAG_NONE, 0, 1, 1, execute_do);
+ debug_console_register_command("step", CMDFLAG_NONE, 0, 0, 1, execute_step);
+ debug_console_register_command("s", CMDFLAG_NONE, 0, 0, 1, execute_step);
+ debug_console_register_command("over", CMDFLAG_NONE, 0, 0, 1, execute_over);
+ debug_console_register_command("o", CMDFLAG_NONE, 0, 0, 1, execute_over);
+ debug_console_register_command("out" , CMDFLAG_NONE, 0, 0, 0, execute_out);
+ debug_console_register_command("go", CMDFLAG_NONE, 0, 0, 1, execute_go);
+ debug_console_register_command("g", CMDFLAG_NONE, 0, 0, 1, execute_go);
+ debug_console_register_command("gvblank", CMDFLAG_NONE, 0, 0, 0, execute_go_vblank);
+ debug_console_register_command("gv", CMDFLAG_NONE, 0, 0, 0, execute_go_vblank);
+ debug_console_register_command("gint", CMDFLAG_NONE, 0, 0, 1, execute_go_interrupt);
+ debug_console_register_command("gi", CMDFLAG_NONE, 0, 0, 1, execute_go_interrupt);
+ debug_console_register_command("gtime", CMDFLAG_NONE, 0, 0, 1, execute_go_time);
+ debug_console_register_command("gt", CMDFLAG_NONE, 0, 0, 1, execute_go_time);
+ debug_console_register_command("next", CMDFLAG_NONE, 0, 0, 0, execute_next);
+ debug_console_register_command("n", CMDFLAG_NONE, 0, 0, 0, execute_next);
+ debug_console_register_command("focus", CMDFLAG_NONE, 0, 1, 1, execute_focus);
+ debug_console_register_command("ignore", CMDFLAG_NONE, 0, 0, MAX_COMMAND_PARAMS, execute_ignore);
+ debug_console_register_command("observe", CMDFLAG_NONE, 0, 0, MAX_COMMAND_PARAMS, execute_observe);
+
+ debug_console_register_command("comadd", CMDFLAG_NONE, 0, 1, 2, execute_comment);
+ debug_console_register_command("//", CMDFLAG_NONE, 0, 1, 2, execute_comment);
+ debug_console_register_command("comdelete", CMDFLAG_NONE, 0, 1, 1, execute_comment_del);
+ debug_console_register_command("comsave", CMDFLAG_NONE, 0, 0, 0, execute_comment_save);
+
+ debug_console_register_command("bpset", CMDFLAG_NONE, 0, 1, 3, execute_bpset);
+ debug_console_register_command("bp", CMDFLAG_NONE, 0, 1, 3, execute_bpset);
+ debug_console_register_command("bpclear", CMDFLAG_NONE, 0, 0, 1, execute_bpclear);
+ debug_console_register_command("bpdisable", CMDFLAG_NONE, 0, 0, 1, execute_bpdisenable);
+ debug_console_register_command("bpenable", CMDFLAG_NONE, 1, 0, 1, execute_bpdisenable);
+ debug_console_register_command("bplist", CMDFLAG_NONE, 0, 0, 0, execute_bplist);
+
+ debug_console_register_command("wpset", CMDFLAG_NONE, ADDRESS_SPACE_PROGRAM, 3, 5, execute_wpset);
+ debug_console_register_command("wp", CMDFLAG_NONE, ADDRESS_SPACE_PROGRAM, 3, 5, execute_wpset);
+ debug_console_register_command("wpdset", CMDFLAG_NONE, ADDRESS_SPACE_DATA, 3, 5, execute_wpset);
+ debug_console_register_command("wpd", CMDFLAG_NONE, ADDRESS_SPACE_DATA, 3, 5, execute_wpset);
+ debug_console_register_command("wpiset", CMDFLAG_NONE, ADDRESS_SPACE_IO, 3, 5, execute_wpset);
+ debug_console_register_command("wpi", CMDFLAG_NONE, ADDRESS_SPACE_IO, 3, 5, execute_wpset);
+ debug_console_register_command("wpclear", CMDFLAG_NONE, 0, 0, 1, execute_wpclear);
+ debug_console_register_command("wpdisable", CMDFLAG_NONE, 0, 0, 1, execute_wpdisenable);
+ debug_console_register_command("wpenable", CMDFLAG_NONE, 1, 0, 1, execute_wpdisenable);
+ debug_console_register_command("wplist", CMDFLAG_NONE, 0, 0, 0, execute_wplist);
+
+ debug_console_register_command("hotspot", CMDFLAG_NONE, 0, 0, 3, execute_hotspot);
+
+ debug_console_register_command("save", CMDFLAG_NONE, ADDRESS_SPACE_PROGRAM, 3, 4, execute_save);
+ debug_console_register_command("saved", CMDFLAG_NONE, ADDRESS_SPACE_DATA, 3, 4, execute_save);
+ debug_console_register_command("savei", CMDFLAG_NONE, ADDRESS_SPACE_IO, 3, 4, execute_save);
+
+ debug_console_register_command("dump", CMDFLAG_NONE, ADDRESS_SPACE_PROGRAM, 3, 6, execute_dump);
+ debug_console_register_command("dumpd", CMDFLAG_NONE, ADDRESS_SPACE_DATA, 3, 6, execute_dump);
+ debug_console_register_command("dumpi", CMDFLAG_NONE, ADDRESS_SPACE_IO, 3, 6, execute_dump);
+
+ debug_console_register_command("f", CMDFLAG_KEEP_QUOTES, ADDRESS_SPACE_PROGRAM, 3, MAX_COMMAND_PARAMS, execute_find);
+ debug_console_register_command("find", CMDFLAG_KEEP_QUOTES, ADDRESS_SPACE_PROGRAM, 3, MAX_COMMAND_PARAMS, execute_find);
+ debug_console_register_command("fd", CMDFLAG_KEEP_QUOTES, ADDRESS_SPACE_DATA, 3, MAX_COMMAND_PARAMS, execute_find);
+ debug_console_register_command("findd", CMDFLAG_KEEP_QUOTES, ADDRESS_SPACE_DATA, 3, MAX_COMMAND_PARAMS, execute_find);
+ debug_console_register_command("fi", CMDFLAG_KEEP_QUOTES, ADDRESS_SPACE_IO, 3, MAX_COMMAND_PARAMS, execute_find);
+ debug_console_register_command("findi", CMDFLAG_KEEP_QUOTES, ADDRESS_SPACE_IO, 3, MAX_COMMAND_PARAMS, execute_find);
+
+ debug_console_register_command("dasm", CMDFLAG_NONE, 0, 3, 5, execute_dasm);
+
+ debug_console_register_command("trace", CMDFLAG_NONE, 0, 1, 3, execute_trace);
+ debug_console_register_command("traceover", CMDFLAG_NONE, 0, 1, 3, execute_traceover);
+ debug_console_register_command("traceflush",CMDFLAG_NONE, 0, 0, 0, execute_traceflush);
+
+ debug_console_register_command("history", CMDFLAG_NONE, 0, 0, 2, execute_history);
+
+ debug_console_register_command("snap", CMDFLAG_NONE, 0, 0, 1, execute_snap);
+
+ debug_console_register_command("source", CMDFLAG_NONE, 0, 1, 1, execute_source);
+
+ debug_console_register_command("map", CMDFLAG_NONE, ADDRESS_SPACE_PROGRAM, 1, 1, execute_map);
+ debug_console_register_command("mapd", CMDFLAG_NONE, ADDRESS_SPACE_DATA, 1, 1, execute_map);
+ debug_console_register_command("mapi", CMDFLAG_NONE, ADDRESS_SPACE_IO, 1, 1, execute_map);
+ debug_console_register_command("memdump", CMDFLAG_NONE, 0, 0, 1, execute_memdump);
+
+ debug_console_register_command("symlist", CMDFLAG_NONE, 0, 0, 1, execute_symlist);
+
+ debug_console_register_command("softreset", CMDFLAG_NONE, 0, 0, 1, execute_softreset);
+ debug_console_register_command("hardreset", CMDFLAG_NONE, 0, 0, 1, execute_hardreset);
+
+ /* ask all the CPUs if they would like to register functions or symbols */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ void (*setup_commands)(void);
+ setup_commands = cpunum_get_info_fct(cpunum, CPUINFO_PTR_DEBUG_SETUP_COMMANDS);
+ if (setup_commands)
+ setup_commands();
+ }
+
+ add_exit_callback(machine, debug_command_exit);
+
+ /* set up the initial debugscript if specified */
+ name = options_get_string(mame_options(), OPTION_DEBUGSCRIPT);
+ if (name[0] != 0)
+ debug_source_script(name);
+}
+
+
+/*-------------------------------------------------
+ debug_command_exit - exit-time cleanup
+-------------------------------------------------*/
+
+static void debug_command_exit(running_machine *machine)
+{
+ int cpunum;
+
+ /* turn off all traces */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ debug_cpu_trace(cpunum, NULL, 0, NULL);
+}
+
+
+
+/***************************************************************************
+
+ Simple Global Functions
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ execute_min - return the minimum of two values
+-------------------------------------------------*/
+
+static UINT64 execute_min(UINT32 ref, UINT32 params, UINT64 *param)
+{
+ return (param[0] < param[1]) ? param[0] : param[1];
+}
+
+
+/*-------------------------------------------------
+ execute_max - return the maximum of two values
+-------------------------------------------------*/
+
+static UINT64 execute_max(UINT32 ref, UINT32 params, UINT64 *param)
+{
+ return (param[0] > param[1]) ? param[0] : param[1];
+}
+
+
+/*-------------------------------------------------
+ execute_if - if (a) return b; else return c;
+-------------------------------------------------*/
+
+static UINT64 execute_if(UINT32 ref, UINT32 params, UINT64 *param)
+{
+ return param[0] ? param[1] : param[2];
+}
+
+
+
+/***************************************************************************
+
+ Global accessors
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ global_get - symbol table getter for globals
+-------------------------------------------------*/
+
+static UINT64 global_get(UINT32 ref)
+{
+ assert(ref < MAX_GLOBALS);
+ switch (global_array[ref].size)
+ {
+ case 1: return *(UINT8 *)global_array[ref].base;
+ case 2: return *(UINT16 *)global_array[ref].base;
+ case 4: return *(UINT32 *)global_array[ref].base;
+ case 8: return *(UINT64 *)global_array[ref].base;
+ }
+ return ~0;
+}
+
+
+/*-------------------------------------------------
+ global_set - symbol table setter for globals
+-------------------------------------------------*/
+
+static void global_set(UINT32 ref, UINT64 value)
+{
+ assert(ref < MAX_GLOBALS);
+ switch (global_array[ref].size)
+ {
+ case 1: *(UINT8 *)global_array[ref].base = value; break;
+ case 2: *(UINT16 *)global_array[ref].base = value; break;
+ case 4: *(UINT32 *)global_array[ref].base = value; break;
+ case 8: *(UINT64 *)global_array[ref].base = value; break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Parameter Validation Helpers
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_command_parameter_number - validates a
+ number parameter
+-------------------------------------------------*/
+
+int debug_command_parameter_number(const char *param, UINT64 *result)
+{
+ EXPRERR err = expression_evaluate(param, debug_get_cpu_info(cpu_getactivecpu())->symtable, result);
+ if (err == EXPRERR_NONE)
+ return 1;
+ debug_console_printf("Error in expression: %s\n", param);
+ debug_console_printf(" %*s^", EXPRERR_ERROR_OFFSET(err), "");
+ debug_console_printf("%s\n", exprerr_to_string(err));
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ debug_command_parameter_expression - validates
+ an expression parameter
+-------------------------------------------------*/
+
+static int debug_command_parameter_expression(const char *param, parsed_expression **result)
+{
+ EXPRERR err = expression_parse(param, debug_get_cpu_info(cpu_getactivecpu())->symtable, result);
+ if (err == EXPRERR_NONE)
+ return 1;
+ debug_console_printf("Error in expression: %s\n", param);
+ debug_console_printf(" %*s^", EXPRERR_ERROR_OFFSET(err), "");
+ debug_console_printf("%s\n", exprerr_to_string(err));
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ debug_command_parameter_command - validates a
+ command parameter
+-------------------------------------------------*/
+
+static int debug_command_parameter_command(const char *param)
+{
+ CMDERR err = debug_console_validate_command(param);
+ if (err == CMDERR_NONE)
+ return 1;
+ debug_console_printf("Error in command: %s\n", param);
+ debug_console_printf(" %*s^", CMDERR_ERROR_OFFSET(err), "");
+ debug_console_printf("%s\n", debug_cmderr_to_string(err));
+ return 0;
+}
+
+
+
+/***************************************************************************
+
+ Command Helpers
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ execute_help - execute the help command
+-------------------------------------------------*/
+
+static void execute_help(int ref, int params, const char *param[])
+{
+ if (params == 0)
+ debug_console_printf_wrap(80, "%s\n", debug_get_help(""));
+ else
+ debug_console_printf_wrap(80, "%s\n", debug_get_help(param[0]));
+}
+
+
+/*-------------------------------------------------
+ execute_print - execute the print command
+-------------------------------------------------*/
+
+static void execute_print(int ref, int params, const char *param[])
+{
+ UINT64 values[MAX_COMMAND_PARAMS];
+ int i;
+
+ /* validate the other parameters */
+ for (i = 0; i < params; i++)
+ if (!debug_command_parameter_number(param[i], &values[i]))
+ return;
+
+ /* then print each one */
+ for (i = 0; i < params; i++)
+ {
+ if ((values[i] >> 32) != 0)
+ debug_console_printf("%X%08X ", (UINT32)(values[i] >> 32), (UINT32)values[i]);
+ else
+ debug_console_printf("%X ", (UINT32)values[i]);
+ }
+ debug_console_printf("\n");
+}
+
+
+/*-------------------------------------------------
+ mini_printf - safe printf to a buffer
+-------------------------------------------------*/
+
+static int mini_printf(char *buffer, const char *format, int params, UINT64 *param)
+{
+ const char *f = format;
+ char *p = buffer;
+
+ /* parse the string looking for % signs */
+ for (;;)
+ {
+ char c = *f++;
+ if (!c) break;
+
+ /* escape sequences */
+ if (c == '\\')
+ {
+ c = *f++;
+ if (!c) break;
+ switch (c)
+ {
+ case '\\': *p++ = c; break;
+ case 'n': *p++ = '\n'; break;
+ default: break;
+ }
+ continue;
+ }
+
+ /* formatting */
+ else if (c == '%')
+ {
+ int width = 0;
+ int zerofill = 0;
+
+ /* parse out the width */
+ for (;;)
+ {
+ c = *f++;
+ if (!c || c < '0' || c > '9') break;
+ if (c == '0' && width == 0)
+ zerofill = 1;
+ width = width * 10 + (c - '0');
+ }
+ if (!c) break;
+
+ /* get the format */
+ switch (c)
+ {
+ case '%':
+ *p++ = c;
+ break;
+
+ case 'X':
+ case 'x':
+ if (params == 0)
+ {
+ debug_console_printf("Not enough parameters for format!\n");
+ return 0;
+ }
+ if ((UINT32)(*param >> 32) != 0)
+ p += sprintf(p, zerofill ? "%0*X" : "%*X", (width <= 8) ? 1 : width - 8, (UINT32)(*param >> 32));
+ else if (width > 8)
+ p += sprintf(p, zerofill ? "%0*X" : "%*X", width - 8, 0);
+ p += sprintf(p, zerofill ? "%0*X" : "%*X", (width < 8) ? width : 8, (UINT32)*param);
+ param++;
+ params--;
+ break;
+
+ case 'D':
+ case 'd':
+ if (params == 0)
+ {
+ debug_console_printf("Not enough parameters for format!\n");
+ return 0;
+ }
+ p += sprintf(p, zerofill ? "%0*d" : "%*d", width, (UINT32)*param);
+ param++;
+ params--;
+ break;
+ }
+ }
+
+ /* normal stuff */
+ else
+ *p++ = c;
+ }
+
+ /* NULL-terminate and exit */
+ *p = 0;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ execute_printf - execute the printf command
+-------------------------------------------------*/
+
+static void execute_printf(int ref, int params, const char *param[])
+{
+ UINT64 values[MAX_COMMAND_PARAMS];
+ char buffer[1024];
+ int i;
+
+ /* validate the other parameters */
+ for (i = 1; i < params; i++)
+ if (!debug_command_parameter_number(param[i], &values[i]))
+ return;
+
+ /* then do a printf */
+ if (mini_printf(buffer, param[0], params - 1, &values[1]))
+ debug_console_printf("%s\n", buffer);
+}
+
+
+/*-------------------------------------------------
+ execute_logerror - execute the logerror command
+-------------------------------------------------*/
+
+static void execute_logerror(int ref, int params, const char *param[])
+{
+ UINT64 values[MAX_COMMAND_PARAMS];
+ char buffer[1024];
+ int i;
+
+ /* validate the other parameters */
+ for (i = 1; i < params; i++)
+ if (!debug_command_parameter_number(param[i], &values[i]))
+ return;
+
+ /* then do a printf */
+ if (mini_printf(buffer, param[0], params - 1, &values[1]))
+ logerror("%s", buffer);
+}
+
+
+/*-------------------------------------------------
+ execute_tracelog - execute the tracelog command
+-------------------------------------------------*/
+
+static void execute_tracelog(int ref, int params, const char *param[])
+{
+ FILE *file = debug_get_cpu_info(cpu_getactivecpu())->trace.file;
+ UINT64 values[MAX_COMMAND_PARAMS];
+ char buffer[1024];
+ int i;
+
+ /* if no tracefile, skip */
+ if (!file)
+ return;
+
+ /* validate the other parameters */
+ for (i = 1; i < params; i++)
+ if (!debug_command_parameter_number(param[i], &values[i]))
+ return;
+
+ /* then do a printf */
+ if (mini_printf(buffer, param[0], params - 1, &values[1]))
+ fprintf(file, "%s", buffer);
+}
+
+
+/*-------------------------------------------------
+ execute_quit - execute the quit command
+-------------------------------------------------*/
+
+static void execute_quit(int ref, int params, const char *param[])
+{
+ mame_printf_error("Exited via the debugger\n");
+ mame_schedule_exit(Machine);
+}
+
+
+/*-------------------------------------------------
+ execute_do - execute the do command
+-------------------------------------------------*/
+
+static void execute_do(int ref, int params, const char *param[])
+{
+ UINT64 dummy;
+ debug_command_parameter_number(param[0], &dummy);
+}
+
+
+/*-------------------------------------------------
+ execute_step - execute the step command
+-------------------------------------------------*/
+
+static void execute_step(int ref, int params, const char *param[])
+{
+ UINT64 steps = 1;
+
+ /* if we have a parameter, use it instead */
+ if (params > 0 && !debug_command_parameter_number(param[0], &steps))
+ return;
+
+ debug_cpu_single_step(steps);
+}
+
+
+/*-------------------------------------------------
+ execute_over - execute the over command
+-------------------------------------------------*/
+
+static void execute_over(int ref, int params, const char *param[])
+{
+ UINT64 steps = 1;
+
+ /* if we have a parameter, use it instead */
+ if (params > 0 && !debug_command_parameter_number(param[0], &steps))
+ return;
+
+ debug_cpu_single_step_over(steps);
+}
+
+
+/*-------------------------------------------------
+ execute_out - execute the out command
+-------------------------------------------------*/
+
+static void execute_out(int ref, int params, const char *param[])
+{
+ debug_cpu_single_step_out();
+}
+
+
+/*-------------------------------------------------
+ execute_go - execute the go command
+-------------------------------------------------*/
+
+static void execute_go(int ref, int params, const char *param[])
+{
+ UINT64 addr = ~0;
+
+ /* if we have a parameter, use it instead */
+ if (params > 0 && !debug_command_parameter_number(param[0], &addr))
+ return;
+
+ debug_cpu_go(addr);
+}
+
+
+/*-------------------------------------------------
+ execute_go_vblank - execute the govblank
+ command
+-------------------------------------------------*/
+
+static void execute_go_vblank(int ref, int params, const char *param[])
+{
+ debug_cpu_go_vblank();
+}
+
+
+/*-------------------------------------------------
+ execute_go_interrupt - execute the goint command
+-------------------------------------------------*/
+
+static void execute_go_interrupt(int ref, int params, const char *param[])
+{
+ UINT64 irqline = -1;
+
+ /* if we have a parameter, use it instead */
+ if (params > 0 && !debug_command_parameter_number(param[0], &irqline))
+ return;
+
+ debug_cpu_go_interrupt(irqline);
+}
+
+
+/*-------------------------------------------------
+ execute_go_time - execute the gtime command
+-------------------------------------------------*/
+
+static void execute_go_time(int ref, int params, const char *param[])
+{
+ UINT64 milliseconds = -1;
+
+ /* if we have a parameter, use it instead */
+ if (params > 0 && !debug_command_parameter_number(param[0], &milliseconds))
+ return;
+
+ debug_cpu_go_milliseconds(milliseconds);
+}
+
+
+/*-------------------------------------------------
+ execute_next - execute the next command
+-------------------------------------------------*/
+
+static void execute_next(int ref, int params, const char *param[])
+{
+ debug_cpu_next_cpu();
+}
+
+
+/*-------------------------------------------------
+ execute_focus - execute the focus command
+-------------------------------------------------*/
+
+static void execute_focus(int ref, int params, const char *param[])
+{
+ UINT64 cpuwhich;
+ int cpunum;
+
+ /* validate params */
+ if (!debug_command_parameter_number(param[0], &cpuwhich))
+ return;
+ if (cpuwhich >= cpu_gettotalcpu())
+ {
+ debug_console_printf("Invalid CPU number!\n");
+ return;
+ }
+
+ /* first clear the ignore flag on the focused CPU */
+ debug_cpu_ignore_cpu(cpuwhich, 0);
+
+ /* then loop over CPUs and set the ignore flags on all other CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *info = debug_get_cpu_info(cpunum);
+ if (info && info->valid && cpunum != cpuwhich)
+ debug_cpu_ignore_cpu(cpunum, 1);
+ }
+ debug_console_printf("Now focused on CPU %d\n", (int)cpuwhich);
+}
+
+
+/*-------------------------------------------------
+ execute_ignore - execute the ignore command
+-------------------------------------------------*/
+
+static void execute_ignore(int ref, int params, const char *param[])
+{
+ UINT64 cpuwhich[MAX_COMMAND_PARAMS];
+ int cpunum, paramnum;
+ char buffer[100];
+ int buflen = 0;
+
+ /* if there are no parameters, dump the ignore list */
+ if (params == 0)
+ {
+ /* loop over all CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *info = debug_get_cpu_info(cpunum);
+
+ /* build up a comma-separated list */
+ if (info && info->valid && info->ignoring)
+ {
+ if (buflen == 0) buflen += sprintf(&buffer[buflen], "Currently ignoring CPU %d", cpunum);
+ else buflen += sprintf(&buffer[buflen], ",%d", cpunum);
+ }
+ }
+
+ /* special message for none */
+ if (buflen == 0)
+ sprintf(&buffer[buflen], "Not currently ignoring any CPUs");
+ debug_console_printf("%s\n", buffer);
+ }
+
+ /* otherwise clear the ignore flag on all requested CPUs */
+ else
+ {
+ /* validate parameters */
+ for (paramnum = 0; paramnum < params; paramnum++)
+ {
+ if (!debug_command_parameter_number(param[paramnum], &cpuwhich[paramnum]))
+ return;
+ if (cpuwhich[paramnum] >= cpu_gettotalcpu())
+ {
+ debug_console_printf("Invalid CPU number! (%d)\n", (int)cpuwhich[paramnum]);
+ return;
+ }
+ }
+
+ /* set the ignore flags */
+ for (paramnum = 0; paramnum < params; paramnum++)
+ {
+ /* make sure this isn't the last live CPU */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *info = debug_get_cpu_info(cpunum);
+ if (cpunum != cpuwhich[paramnum] && info && info->valid && !info->ignoring)
+ break;
+ }
+ if (cpunum == MAX_CPU)
+ {
+ debug_console_printf("Can't ignore all CPUs!\n");
+ return;
+ }
+
+ debug_cpu_ignore_cpu(cpuwhich[paramnum], 1);
+ debug_console_printf("Now ignoring CPU %d\n", (int)cpuwhich[paramnum]);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_observe - execute the observe command
+-------------------------------------------------*/
+
+static void execute_observe(int ref, int params, const char *param[])
+{
+ UINT64 cpuwhich[MAX_COMMAND_PARAMS];
+ int cpunum, paramnum;
+ char buffer[100];
+ int buflen = 0;
+
+ /* if there are no parameters, dump the ignore list */
+ if (params == 0)
+ {
+ /* loop over all CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *info = debug_get_cpu_info(cpunum);
+
+ /* build up a comma-separated list */
+ if (info && info->valid && !info->ignoring)
+ {
+ if (buflen == 0) buflen += sprintf(&buffer[buflen], "Currently observing CPU %d", cpunum);
+ else buflen += sprintf(&buffer[buflen], ",%d", cpunum);
+ }
+ }
+
+ /* special message for none */
+ if (buflen == 0)
+ buflen += sprintf(&buffer[buflen], "Not currently observing any CPUs");
+ debug_console_printf("%s\n", buffer);
+ }
+
+ /* otherwise set the ignore flag on all requested CPUs */
+ else
+ {
+ /* validate parameters */
+ for (paramnum = 0; paramnum < params; paramnum++)
+ {
+ if (!debug_command_parameter_number(param[paramnum], &cpuwhich[paramnum]))
+ return;
+ if (cpuwhich[paramnum] >= cpu_gettotalcpu())
+ {
+ debug_console_printf("Invalid CPU number! (%d)\n", (int)cpuwhich[paramnum]);
+ return;
+ }
+ }
+
+ /* clear the ignore flags */
+ for (paramnum = 0; paramnum < params; paramnum++)
+ {
+ debug_cpu_ignore_cpu(cpuwhich[paramnum], 0);
+ debug_console_printf("Now observing CPU %d\n", (int)cpuwhich[paramnum]);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_comment - add a comment to a line
+-------------------------------------------------*/
+
+static void execute_comment(int ref, int params, const char *param[])
+{
+ UINT64 address;
+
+ /* param 1 is the address for the comment */
+ if (!debug_command_parameter_number(param[0], &address))
+ return;
+
+ /* make sure param 2 exists */
+ if (strlen(param[1]) == 0)
+ {
+ debug_console_printf("Error : comment text empty\n");
+ return;
+ }
+
+ /* Now try adding the comment */
+ debug_comment_add(cpu_getactivecpu(), address, param[1], 0x00ff0000, debug_comment_get_opcode_crc32(address));
+ debug_view_update_type(DVT_DISASSEMBLY);
+}
+
+
+/*------------------------------------------------------
+ execute_comment_del - remove a comment from an addr
+--------------------------------------------------------*/
+
+static void execute_comment_del(int ref, int params, const char *param[])
+{
+ UINT64 address;
+
+ /* param 1 can either be a command or the address for the comment */
+ if (!debug_command_parameter_number(param[0], &address))
+ return;
+
+ /* If it's a number, it must be an address */
+ /* The bankoff and cbn will be pulled from what's currently active */
+ debug_comment_remove(cpu_getactivecpu(), address, debug_comment_get_opcode_crc32(address));
+ debug_view_update_type(DVT_DISASSEMBLY);
+}
+
+
+/*-------------------------------------------------
+ execute_comment - add a comment to a line
+-------------------------------------------------*/
+
+static void execute_comment_save(int ref, int params, const char *param[])
+{
+ if (debug_comment_save())
+ debug_console_printf("Comments successfully saved\n");
+}
+
+
+/*-------------------------------------------------
+ execute_bpset - execute the breakpoint set
+ command
+-------------------------------------------------*/
+
+static void execute_bpset(int ref, int params, const char *param[])
+{
+ parsed_expression *condition = NULL;
+ const char *action = NULL;
+ UINT64 address;
+ int bpnum;
+
+ /* make sure that there is an active CPU */
+ if (cpu_getactivecpu() < 0)
+ {
+ debug_console_printf("No active CPU!\n");
+ return;
+ }
+
+ /* param 1 is the address */
+ if (!debug_command_parameter_number(param[0], &address))
+ return;
+
+ /* param 2 is the condition */
+ if (params > 1 && !debug_command_parameter_expression(param[1], &condition))
+ return;
+
+ /* param 3 is the action */
+ if (params > 2 && !debug_command_parameter_command(action = param[2]))
+ return;
+
+ /* set the breakpoint */
+ bpnum = debug_breakpoint_set(cpu_getactivecpu(), address, condition, action);
+ debug_console_printf("Breakpoint %X set\n", bpnum);
+}
+
+
+/*-------------------------------------------------
+ execute_bpclear - execute the breakpoint
+ clear command
+-------------------------------------------------*/
+
+static void execute_bpclear(int ref, int params, const char *param[])
+{
+ UINT64 bpindex;
+
+ /* if 0 parameters, clear all */
+ if (params == 0)
+ {
+ int cpunum;
+
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(cpunum);
+ if (cpuinfo->valid)
+ {
+ debug_cpu_breakpoint *bp;
+ while ((bp = cpuinfo->first_bp) != NULL)
+ debug_breakpoint_clear(bp->index);
+ }
+ }
+ debug_console_printf("Cleared all breakpoints\n");
+ }
+
+ /* otherwise, clear the specific one */
+ else if (!debug_command_parameter_number(param[0], &bpindex))
+ return;
+ else
+ {
+ int found = debug_breakpoint_clear(bpindex);
+ if (found)
+ debug_console_printf("Breakpoint %X cleared\n", (UINT32)bpindex);
+ else
+ debug_console_printf("Invalid breakpoint number %X\n", (UINT32)bpindex);
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_bpdisenable - execute the breakpoint
+ disable/enable commands
+-------------------------------------------------*/
+
+static void execute_bpdisenable(int ref, int params, const char *param[])
+{
+ UINT64 bpindex;
+
+ /* if 0 parameters, clear all */
+ if (params == 0)
+ {
+ int cpunum;
+
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(cpunum);
+ if (cpuinfo->valid)
+ {
+ debug_cpu_breakpoint *bp;
+ for (bp = cpuinfo->first_bp; bp; bp = bp->next)
+ debug_breakpoint_enable(bp->index, ref);
+ }
+ }
+ if (ref == 0)
+ debug_console_printf("Disabled all breakpoints\n");
+ else
+ debug_console_printf("Enabled all breakpoints\n");
+ }
+
+ /* otherwise, clear the specific one */
+ else if (!debug_command_parameter_number(param[0], &bpindex))
+ return;
+ else
+ {
+ int found = debug_breakpoint_enable(bpindex, ref);
+ if (found)
+ debug_console_printf("Breakpoint %X %s\n", (UINT32)bpindex, ref ? "enabled" : "disabled");
+ else
+ debug_console_printf("Invalid breakpoint number %X\n", (UINT32)bpindex);
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_bplist - execute the breakpoint list
+ command
+-------------------------------------------------*/
+
+static void execute_bplist(int ref, int params, const char *param[])
+{
+ int cpunum, printed = 0;
+ char buffer[256];
+
+ /* loop over all CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(cpunum);
+
+ if (cpuinfo->valid && cpuinfo->first_bp)
+ {
+ debug_cpu_breakpoint *bp;
+
+ debug_console_printf("CPU %d breakpoints:\n", cpunum);
+
+ /* loop over the breakpoints */
+ for (bp = cpuinfo->first_bp; bp; bp = bp->next)
+ {
+ int buflen;
+ buflen = sprintf(buffer, "%c%4X @ %08X", bp->enabled ? ' ' : 'D', bp->index, bp->address);
+ if (bp->condition)
+ buflen += sprintf(&buffer[buflen], " if %s", expression_original_string(bp->condition));
+ if (bp->action)
+ buflen += sprintf(&buffer[buflen], " do %s", bp->action);
+ debug_console_printf("%s\n", buffer);
+ printed++;
+ }
+ }
+ }
+
+ if (!printed)
+ debug_console_printf("No breakpoints currently installed\n");
+}
+
+
+/*-------------------------------------------------
+ execute_wpset - execute the watchpoint set
+ command
+-------------------------------------------------*/
+
+static void execute_wpset(int ref, int params, const char *param[])
+{
+ parsed_expression *condition = NULL;
+ const char *action = NULL;
+ UINT64 address, length;
+ int type = 0;
+ int wpnum;
+
+ /* param 1 is the address */
+ if (!debug_command_parameter_number(param[0], &address))
+ return;
+
+ /* param 2 is the length */
+ if (!debug_command_parameter_number(param[1], &length))
+ return;
+
+ /* param 3 is the type */
+ if (!strcmp(param[2], "r"))
+ type = WATCHPOINT_READ;
+ else if (!strcmp(param[2], "w"))
+ type = WATCHPOINT_WRITE;
+ else if (!strcmp(param[2], "rw") || !strcmp(param[2], "wr"))
+ type = WATCHPOINT_READWRITE;
+ else
+ {
+ debug_console_printf("Invalid watchpoint type: expected r, w, or rw\n");
+ return;
+ }
+
+ /* param 4 is the condition */
+ if (params > 3 && !debug_command_parameter_expression(param[3], &condition))
+ return;
+
+ /* param 5 is the action */
+ if (params > 4 && !debug_command_parameter_command(action = param[4]))
+ return;
+
+ /* set the watchpoint */
+ wpnum = debug_watchpoint_set(cpu_getactivecpu(), ref, type, address, length, condition, action);
+ debug_console_printf("Watchpoint %X set\n", wpnum);
+}
+
+
+/*-------------------------------------------------
+ execute_wpclear - execute the watchpoint
+ clear command
+-------------------------------------------------*/
+
+static void execute_wpclear(int ref, int params, const char *param[])
+{
+ UINT64 wpindex;
+
+ /* if 0 parameters, clear all */
+ if (params == 0)
+ {
+ int cpunum;
+
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(cpunum);
+ if (cpuinfo->valid)
+ {
+ int spacenum;
+
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ {
+ debug_cpu_watchpoint *wp;
+ while ((wp = cpuinfo->space[spacenum].first_wp) != NULL)
+ debug_watchpoint_clear(wp->index);
+ }
+ }
+ }
+ debug_console_printf("Cleared all watchpoints\n");
+ }
+
+ /* otherwise, clear the specific one */
+ else if (!debug_command_parameter_number(param[0], &wpindex))
+ return;
+ else
+ {
+ int found = debug_watchpoint_clear(wpindex);
+ if (found)
+ debug_console_printf("Watchpoint %X cleared\n", (UINT32)wpindex);
+ else
+ debug_console_printf("Invalid watchpoint number %X\n", (UINT32)wpindex);
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_wpdisenable - execute the watchpoint
+ disable/enable commands
+-------------------------------------------------*/
+
+static void execute_wpdisenable(int ref, int params, const char *param[])
+{
+ UINT64 wpindex;
+
+ /* if 0 parameters, clear all */
+ if (params == 0)
+ {
+ int cpunum;
+
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(cpunum);
+ if (cpuinfo->valid)
+ {
+ int spacenum;
+
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ {
+ debug_cpu_watchpoint *wp;
+ for (wp = cpuinfo->space[spacenum].first_wp; wp; wp = wp->next)
+ debug_watchpoint_enable(wp->index, ref);
+ }
+ }
+ }
+ if (ref == 0)
+ debug_console_printf("Disabled all watchpoints\n");
+ else
+ debug_console_printf("Enabled all watchpoints\n");
+ }
+
+ /* otherwise, clear the specific one */
+ else if (!debug_command_parameter_number(param[0], &wpindex))
+ return;
+ else
+ {
+ int found = debug_watchpoint_enable(wpindex, ref);
+ if (found)
+ debug_console_printf("Watchpoint %X %s\n", (UINT32)wpindex, ref ? "enabled" : "disabled");
+ else
+ debug_console_printf("Invalid watchpoint number %X\n", (UINT32)wpindex);
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_wplist - execute the watchpoint list
+ command
+-------------------------------------------------*/
+
+static void execute_wplist(int ref, int params, const char *param[])
+{
+ static const char *spacenames[ADDRESS_SPACES] = { "program", "data", "I/O" };
+ int cpunum, printed = 0;
+ char buffer[256];
+
+ /* loop over all CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(cpunum);
+
+ if (cpuinfo->valid)
+ {
+ int spacenum;
+
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ {
+ if (cpuinfo->space[spacenum].first_wp)
+ {
+ static const char *types[] = { "unkn ", "read ", "write", "r/w " };
+ debug_cpu_watchpoint *wp;
+
+ debug_console_printf("CPU %d %s space watchpoints:\n", cpunum, spacenames[spacenum]);
+
+ /* loop over the watchpoints */
+ for (wp = cpuinfo->space[spacenum].first_wp; wp; wp = wp->next)
+ {
+ int buflen;
+ buflen = sprintf(buffer, "%c%4X @ %08X-%08X %s", wp->enabled ? ' ' : 'D',
+ wp->index, BYTE2ADDR(wp->address, cpuinfo, spacenum), BYTE2ADDR(wp->address + wp->length, cpuinfo, spacenum) - 1, types[wp->type & 3]);
+ if (wp->condition)
+ buflen += sprintf(&buffer[buflen], " if %s", expression_original_string(wp->condition));
+ if (wp->action)
+ buflen += sprintf(&buffer[buflen], " do %s", wp->action);
+ debug_console_printf("%s\n", buffer);
+ printed++;
+ }
+ }
+ }
+ }
+ }
+
+ if (!printed)
+ debug_console_printf("No watchpoints currently installed\n");
+}
+
+
+/*-------------------------------------------------
+ execute_hotspot - execute the hotspot
+ command
+-------------------------------------------------*/
+
+static void execute_hotspot(int ref, int params, const char *param[])
+{
+ UINT64 threshhold;
+ UINT64 cpunum;
+ UINT64 count;
+
+ /* if no params, and there are live hotspots, clear them */
+ if (params == 0)
+ {
+ int cleared = FALSE;
+
+ /* loop over CPUs and find live spots */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(cpunum);
+
+ if (cpuinfo->valid && cpuinfo->hotspots)
+ {
+ debug_hotspot_track(cpunum, 0, 0);
+ debug_console_printf("Cleared hotspot tracking on CPU %d\n", (int)cpunum);
+ cleared = TRUE;
+ }
+ }
+
+ /* if we cleared, we're done */
+ if (cleared)
+ return;
+ }
+
+ /* extract parameters */
+ cpunum = cpu_getactivecpu();
+ count = 64;
+ threshhold = 250;
+ if (params > 0 && !debug_command_parameter_number(param[0], &cpunum))
+ return;
+ if (params > 1 && !debug_command_parameter_number(param[1], &count))
+ return;
+ if (params > 2 && !debug_command_parameter_number(param[2], &threshhold))
+ return;
+
+ /* attempt to install */
+ if (debug_hotspot_track(cpunum, count, threshhold))
+ debug_console_printf("Now tracking hotspots on CPU %d using %d slots with a threshhold of %d\n", (int)cpunum, (int)count, (int)threshhold);
+ else
+ debug_console_printf("Error setting up the hotspot tracking\n");
+}
+
+
+/*-------------------------------------------------
+ execute_save - execute the save command
+-------------------------------------------------*/
+
+static void execute_save(int ref, int params, const char *param[])
+{
+ UINT64 offset, endoffset, length, cpunum = cpu_getactivecpu();
+ const debug_cpu_info *info;
+ int spacenum = ref;
+ FILE *f;
+ UINT64 i;
+
+ /* validate parameters */
+ if (!debug_command_parameter_number(param[1], &offset))
+ return;
+ if (!debug_command_parameter_number(param[2], &length))
+ return;
+ if (params > 3 && !debug_command_parameter_number(param[3], &cpunum))
+ return;
+
+ /* determine the addresses to write */
+ info = debug_get_cpu_info(cpunum);
+ endoffset = ADDR2BYTE_MASKED(offset + length - 1, info, spacenum);
+ offset = ADDR2BYTE_MASKED(offset, info, spacenum);
+
+ /* open the file */
+ f = fopen(param[0], "wb");
+ if (!f)
+ {
+ debug_console_printf("Error opening file '%s'\n", param[0]);
+ return;
+ }
+
+ /* now write the data out */
+ cpuintrf_push_context(cpunum);
+ for (i = offset; i <= endoffset; i++)
+ {
+ UINT8 byte = debug_read_byte(spacenum, i, TRUE);
+ fwrite(&byte, 1, 1, f);
+ }
+ cpuintrf_pop_context();
+
+ /* close the file */
+ fclose(f);
+ debug_console_printf("Data saved successfully\n");
+}
+
+
+/*-------------------------------------------------
+ execute_dump - execute the dump command
+-------------------------------------------------*/
+
+static void execute_dump(int ref, int params, const char *param[])
+{
+ UINT64 offset, endoffset, length, width = 0, ascii = 1, cpunum = cpu_getactivecpu();
+ const debug_cpu_info *info;
+ int spacenum = ref;
+ FILE *f = NULL;
+ UINT64 i, j;
+
+ /* validate parameters */
+ if (!debug_command_parameter_number(param[1], &offset))
+ return;
+ if (!debug_command_parameter_number(param[2], &length))
+ return;
+ if (params > 3 && !debug_command_parameter_number(param[3], &width))
+ return;
+ if (params > 4 && !debug_command_parameter_number(param[4], &ascii))
+ return;
+ if (params > 5 && !debug_command_parameter_number(param[5], &cpunum))
+ return;
+
+ /* further validation */
+ if (cpunum >= cpu_gettotalcpu())
+ {
+ debug_console_printf("Invalid CPU number!\n");
+ return;
+ }
+ info = debug_get_cpu_info(cpunum);
+ if (width == 0)
+ width = info->space[spacenum].databytes;
+ if (width < ADDR2BYTE(1, info, spacenum))
+ width = ADDR2BYTE(1, info, spacenum);
+ if (width != 1 && width != 2 && width != 4 && width != 8)
+ {
+ debug_console_printf("Invalid width! (must be 1,2,4 or 8)\n");
+ return;
+ }
+ endoffset = ADDR2BYTE_MASKED(offset + length - 1, info, spacenum);
+ offset = ADDR2BYTE_MASKED(offset, info, spacenum);
+
+ /* open the file */
+ f = fopen(param[0], "w");
+ if (!f)
+ {
+ debug_console_printf("Error opening file '%s'\n", param[0]);
+ return;
+ }
+
+ /* now write the data out */
+ cpuintrf_push_context(cpunum);
+ for (i = offset; i <= endoffset; i += 16)
+ {
+ char output[200];
+ int outdex = 0;
+
+ /* print the address */
+ outdex += sprintf(&output[outdex], "%0*X: ", info->space[spacenum].logchars, (UINT32)BYTE2ADDR(i, info, spacenum));
+
+ /* print the bytes */
+ switch (width)
+ {
+ case 1:
+ for (j = 0; j < 16; j++)
+ {
+ if (i + j <= endoffset)
+ {
+ offs_t curaddr = i + j;
+ if (!info->translate || (*info->translate)(spacenum, &curaddr))
+ {
+ UINT8 byte = debug_read_byte(ref, i + j, TRUE);
+ outdex += sprintf(&output[outdex], " %02X", byte);
+ }
+ else
+ outdex += sprintf(&output[outdex], " **");
+ }
+ else
+ outdex += sprintf(&output[outdex], " ");
+ }
+ break;
+
+ case 2:
+ for (j = 0; j < 16; j += 2)
+ {
+ if (i + j <= endoffset)
+ {
+ offs_t curaddr = i + j;
+ if (!info->translate || (*info->translate)(spacenum, &curaddr))
+ {
+ UINT16 word = debug_read_word(ref, i + j, TRUE);
+ outdex += sprintf(&output[outdex], " %04X", word);
+ }
+ else
+ outdex += sprintf(&output[outdex], " ****");
+ }
+ else
+ outdex += sprintf(&output[outdex], " ");
+ }
+ break;
+
+ case 4:
+ for (j = 0; j < 16; j += 4)
+ {
+ if (i + j <= endoffset)
+ {
+ offs_t curaddr = i + j;
+ if (!info->translate || (*info->translate)(spacenum, &curaddr))
+ {
+ UINT32 dword = debug_read_dword(ref, i + j, TRUE);
+ outdex += sprintf(&output[outdex], " %08X", dword);
+ }
+ else
+ outdex += sprintf(&output[outdex], " ********");
+ }
+ else
+ outdex += sprintf(&output[outdex], " ");
+ }
+ break;
+
+ case 8:
+ for (j = 0; j < 16; j += 8)
+ {
+ if (i + j <= endoffset)
+ {
+ offs_t curaddr = i + j;
+ if (!info->translate || (*info->translate)(spacenum, &curaddr))
+ {
+ UINT64 qword = debug_read_qword(ref, i + j, TRUE);
+ outdex += sprintf(&output[outdex], " %08X%08X", (UINT32)(qword >> 32), (UINT32)qword);
+ }
+ else
+ outdex += sprintf(&output[outdex], " ****************");
+ }
+ else
+ outdex += sprintf(&output[outdex], " ");
+ }
+ break;
+ }
+
+ /* print the ASCII */
+ if (ascii)
+ {
+ outdex += sprintf(&output[outdex], " ");
+ for (j = 0; j < 16 && (i + j) <= endoffset; j++)
+ {
+ offs_t curaddr = i + j;
+ if (!info->translate || (*info->translate)(spacenum, &curaddr))
+ {
+ UINT8 byte = debug_read_byte(ref, i + j, TRUE);
+ outdex += sprintf(&output[outdex], "%c", (byte >= 32 && byte < 128) ? byte : '.');
+ }
+ else
+ outdex += sprintf(&output[outdex], " ");
+ }
+ }
+
+ /* output the result */
+ fprintf(f, "%s\n", output);
+ }
+ cpuintrf_pop_context();
+
+ /* close the file */
+ fclose(f);
+ debug_console_printf("Data dumped successfully\n");
+}
+
+
+/*-------------------------------------------------
+ execute_find - execute the find command
+-------------------------------------------------*/
+
+static void execute_find(int ref, int params, const char *param[])
+{
+ UINT64 offset, endoffset, length, cpunum = cpu_getactivecpu();
+ const debug_cpu_info *info;
+ UINT64 data_to_find[256];
+ UINT8 data_size[256];
+ int cur_data_size;
+ int data_count = 0;
+ int spacenum = ref;
+ int found = 0;
+ UINT64 i, j;
+
+ /* validate parameters */
+ if (!debug_command_parameter_number(param[0], &offset))
+ return;
+ if (!debug_command_parameter_number(param[1], &length))
+ return;
+
+ /* further validation */
+ if (cpunum >= cpu_gettotalcpu())
+ {
+ debug_console_printf("Invalid CPU number!\n");
+ return;
+ }
+ info = debug_get_cpu_info(cpunum);
+ endoffset = ADDR2BYTE_MASKED(offset + length - 1, info, spacenum);
+ offset = ADDR2BYTE_MASKED(offset, info, spacenum);
+ cur_data_size = ADDR2BYTE(1, info, spacenum);
+ if (cur_data_size == 0)
+ cur_data_size = 1;
+
+ /* parse the data parameters */
+ for (i = 2; i < params; i++)
+ {
+ const char *pdata = param[i];
+
+ /* check for a string */
+ if (pdata[0] == '"' && pdata[strlen(pdata) - 1] == '"')
+ {
+ for (j = 1; j < strlen(pdata) - 1; j++)
+ {
+ data_to_find[data_count] = pdata[j];
+ data_size[data_count++] = 1;
+ }
+ }
+
+ /* otherwise, validate as a number */
+ else
+ {
+ /* check for a 'b','w','d',or 'q' prefix */
+ data_size[data_count] = cur_data_size;
+ if (tolower(pdata[0]) == 'b' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 1; pdata += 2; }
+ if (tolower(pdata[0]) == 'w' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 2; pdata += 2; }
+ if (tolower(pdata[0]) == 'd' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 4; pdata += 2; }
+ if (tolower(pdata[0]) == 'q' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 8; pdata += 2; }
+
+ /* look for a wildcard */
+ if (!strcmp(pdata, "?"))
+ data_size[data_count++] |= 0x10;
+
+ /* otherwise, validate as a number */
+ else if (!debug_command_parameter_number(pdata, &data_to_find[data_count++]))
+ return;
+ }
+ }
+
+ /* now search */
+ cpuintrf_push_context(cpunum);
+ for (i = offset; i <= endoffset; i += data_size[0])
+ {
+ int suboffset = 0;
+ int match = 1;
+
+ /* find the entire string */
+ for (j = 0; j < data_count && match; j++)
+ {
+ switch (data_size[j])
+ {
+ case 1: match = ((UINT8)debug_read_byte(spacenum, i + suboffset, TRUE) == (UINT8)data_to_find[j]); break;
+ case 2: match = ((UINT16)debug_read_word(spacenum, i + suboffset, TRUE) == (UINT16)data_to_find[j]); break;
+ case 4: match = ((UINT32)debug_read_dword(spacenum, i + suboffset, TRUE) == (UINT32)data_to_find[j]); break;
+ case 8: match = ((UINT64)debug_read_qword(spacenum, i + suboffset, TRUE) == (UINT64)data_to_find[j]); break;
+ default: /* all other cases are wildcards */ break;
+ }
+ suboffset += data_size[j] & 0x0f;
+ }
+
+ /* did we find it? */
+ if (match)
+ {
+ found++;
+ debug_console_printf("Found at %*X\n", info->space[spacenum].logchars, (UINT32)BYTE2ADDR(i, info, spacenum));
+ }
+ }
+ cpuintrf_pop_context();
+
+ /* print something if not found */
+ if (found == 0)
+ debug_console_printf("Not found\n");
+}
+
+
+/*-------------------------------------------------
+ execute_dasm - execute the dasm command
+-------------------------------------------------*/
+
+static void execute_dasm(int ref, int params, const char *param[])
+{
+ UINT64 offset, length, bytes = 1, cpunum = cpu_getactivecpu();
+ const debug_cpu_info *info;
+ int minbytes, maxbytes, byteswidth;
+ FILE *f = NULL;
+ int i, j;
+
+ /* validate parameters */
+ if (!debug_command_parameter_number(param[1], &offset))
+ return;
+ if (!debug_command_parameter_number(param[2], &length))
+ return;
+ if (params > 3 && !debug_command_parameter_number(param[3], &bytes))
+ return;
+ if (params > 4 && !debug_command_parameter_number(param[4], &cpunum))
+ return;
+
+ /* further validation */
+ if (cpunum >= cpu_gettotalcpu())
+ {
+ debug_console_printf("Invalid CPU number!\n");
+ return;
+ }
+ info = debug_get_cpu_info(cpunum);
+
+ /* determine the width of the bytes */
+ minbytes = cpunum_min_instruction_bytes(cpunum);
+ maxbytes = cpunum_max_instruction_bytes(cpunum);
+ byteswidth = 0;
+ if (bytes)
+ {
+ byteswidth = (maxbytes + (minbytes - 1)) / minbytes;
+ byteswidth *= (2 * minbytes) + 1;
+ }
+
+ /* open the file */
+ f = fopen(param[0], "w");
+ if (!f)
+ {
+ debug_console_printf("Error opening file '%s'\n", param[0]);
+ return;
+ }
+
+ /* now write the data out */
+ cpuintrf_push_context(cpunum);
+ for (i = 0; i < length; )
+ {
+ int pcbyte = ADDR2BYTE_MASKED(offset + i, info, ADDRESS_SPACE_PROGRAM);
+ char output[200+DEBUG_COMMENT_MAX_LINE_LENGTH], disasm[200];
+ const char *comment;
+ offs_t tempaddr;
+ int outdex = 0;
+ int numbytes = 0;
+
+ /* print the address */
+ outdex += sprintf(&output[outdex], "%0*X: ", info->space[ADDRESS_SPACE_PROGRAM].logchars, (UINT32)BYTE2ADDR(pcbyte, info, ADDRESS_SPACE_PROGRAM));
+
+ /* make sure we can translate the address */
+ tempaddr = pcbyte;
+ if (!info->translate || (*info->translate)(ADDRESS_SPACE_PROGRAM, &tempaddr))
+ {
+ UINT8 opbuf[64], argbuf[64];
+
+ /* fetch the bytes up to the maximum */
+ for (numbytes = 0; numbytes < maxbytes; numbytes++)
+ {
+ opbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, FALSE);
+ argbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, TRUE);
+ }
+
+ /* disassemble the result */
+ i += numbytes = activecpu_dasm(disasm, offset + i, opbuf, argbuf) & DASMFLAG_LENGTHMASK;
+ }
+
+ /* print the bytes */
+ if (bytes)
+ {
+ int startdex = outdex;
+ numbytes = ADDR2BYTE(numbytes, info, ADDRESS_SPACE_PROGRAM);
+ switch (minbytes)
+ {
+ case 1:
+ for (j = 0; j < numbytes; j++)
+ outdex += sprintf(&output[outdex], "%02X ", (UINT32)debug_read_opcode(pcbyte + j, 1, FALSE));
+ break;
+
+ case 2:
+ for (j = 0; j < numbytes; j += 2)
+ outdex += sprintf(&output[outdex], "%04X ", (UINT32)debug_read_opcode(pcbyte + j, 2, FALSE));
+ break;
+
+ case 4:
+ for (j = 0; j < numbytes; j += 4)
+ outdex += sprintf(&output[outdex], "%08X ", (UINT32)debug_read_opcode(pcbyte + j, 4, FALSE));
+ break;
+
+ case 8:
+ for (j = 0; j < numbytes; j += 8)
+ {
+ UINT64 val = debug_read_opcode(pcbyte + j, 8, FALSE);
+ outdex += sprintf(&output[outdex], "%08X%08X ", (UINT32)(val >> 32), (UINT32)val);
+ }
+ break;
+ }
+ if (outdex - startdex < byteswidth)
+ outdex += sprintf(&output[outdex], "%*s", byteswidth - (outdex - startdex), "");
+ outdex += sprintf(&output[outdex], " ");
+ }
+
+ /* add the disassembly */
+ sprintf(&output[outdex], "%s", disasm);
+
+ /* attempt to add the comment */
+ comment = debug_comment_get_text(cpunum, tempaddr, debug_comment_get_opcode_crc32(tempaddr));
+ if (comment != NULL)
+ {
+ /* somewhat arbitrary guess as to how long most disassembly lines will be [column 60] */
+ if (strlen(output) < 60)
+ {
+ /* pad the comment space out to 60 characters and null-terminate */
+ for (outdex = (int)strlen(output); outdex < 60; outdex++)
+ output[outdex] = ' ' ;
+ output[outdex] = 0 ;
+
+ sprintf(&output[strlen(output)], "// %s", comment) ;
+ }
+ else
+ sprintf(&output[strlen(output)], "\t// %s", comment) ;
+ }
+
+ /* output the result */
+ fprintf(f, "%s\n", output);
+ }
+ cpuintrf_pop_context();
+
+ /* close the file */
+ fclose(f);
+ debug_console_printf("Data dumped successfully\n");
+}
+
+
+/*-------------------------------------------------
+ execute_trace_internal - functionality for
+ trace over and trace info
+-------------------------------------------------*/
+
+static void execute_trace_internal(int ref, int params, const char *param[], int trace_over)
+{
+ const char *action = NULL, *filename = param[0];
+ FILE *f = NULL;
+ const char *mode;
+ UINT64 cpunum;
+
+ cpunum = cpu_getactivecpu();
+
+ /* validate parameters */
+ if (params > 1 && !debug_command_parameter_number(param[1], &cpunum))
+ return;
+ if (params > 2 && !debug_command_parameter_command(action = param[2]))
+ return;
+
+ /* further validation */
+ if (!mame_stricmp(filename, "off"))
+ filename = NULL;
+ if (cpunum >= cpu_gettotalcpu())
+ {
+ debug_console_printf("Invalid CPU number!\n");
+ return;
+ }
+
+ /* open the file */
+ if (filename)
+ {
+ mode = "w";
+
+ /* opening for append? */
+ if ((filename[0] == '>') && (filename[1] == '>'))
+ {
+ mode = "a";
+ filename += 2;
+ }
+
+ f = fopen(filename, mode);
+ if (!f)
+ {
+ debug_console_printf("Error opening file '%s'\n", param[0]);
+ return;
+ }
+ }
+
+ /* do it */
+ debug_cpu_trace(cpunum, f, trace_over, action);
+ if (f)
+ debug_console_printf("Tracing CPU %d to file %s\n", (int)cpunum, filename);
+ else
+ debug_console_printf("Stopped tracing on CPU %d\n", (int)cpunum);
+}
+
+
+/*-------------------------------------------------
+ execute_trace - execute the trace command
+-------------------------------------------------*/
+
+static void execute_trace(int ref, int params, const char *param[])
+{
+ execute_trace_internal(ref, params, param, 0);
+}
+
+
+/*-------------------------------------------------
+ execute_traceover - execute the trace over command
+-------------------------------------------------*/
+
+static void execute_traceover(int ref, int params, const char *param[])
+{
+ execute_trace_internal(ref, params, param, 1);
+}
+
+
+/*-------------------------------------------------
+ execute_traceflush - execute the trace flush command
+-------------------------------------------------*/
+
+static void execute_traceflush(int ref, int params, const char *param[])
+{
+ debug_flush_traces();
+}
+
+
+/*-------------------------------------------------
+ execute_history - execute the history command
+-------------------------------------------------*/
+
+static void execute_history(int ref, int params, const char *param[])
+{
+ UINT64 count = DEBUG_HISTORY_SIZE;
+ const debug_cpu_info *info;
+ UINT64 cpunum;
+ int i;
+
+ cpunum = cpu_getactivecpu();
+
+ /* validate parameters */
+ if (params > 0 && !debug_command_parameter_number(param[0], &cpunum))
+ return;
+ if (params > 1 && !debug_command_parameter_number(param[1], &count))
+ return;
+
+ /* further validation */
+ if (cpunum >= cpu_gettotalcpu())
+ {
+ debug_console_printf("Invalid CPU number!\n");
+ return;
+ }
+ if (count > DEBUG_HISTORY_SIZE)
+ count = DEBUG_HISTORY_SIZE;
+
+ info = debug_get_cpu_info(cpunum);
+
+ /* loop over lines */
+ cpuintrf_push_context(cpunum);
+ for (i = 0; i < count; i++)
+ {
+ offs_t pc = info->pc_history[(info->pc_history_index + DEBUG_HISTORY_SIZE - count + i) % DEBUG_HISTORY_SIZE];
+ int maxbytes = activecpu_max_instruction_bytes();
+ UINT8 opbuf[64], argbuf[64];
+ char buffer[200];
+ offs_t pcbyte;
+ int numbytes;
+
+ /* fetch the bytes up to the maximum */
+ pcbyte = ADDR2BYTE_MASKED(pc, info, ADDRESS_SPACE_PROGRAM);
+ for (numbytes = 0; numbytes < maxbytes; numbytes++)
+ {
+ opbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, FALSE);
+ argbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, TRUE);
+ }
+
+ activecpu_dasm(buffer, pc, opbuf, argbuf);
+
+ debug_console_printf("%0*X: %s\n", info->space[ADDRESS_SPACE_PROGRAM].logchars, pc, buffer);
+ }
+ cpuintrf_pop_context();
+}
+
+
+/*-------------------------------------------------
+ execute_snap - execute the trace over command
+-------------------------------------------------*/
+
+static void execute_snap(int ref, int params, const char *param[])
+{
+ /* if no params, use the default behavior */
+ if (params == 0)
+ {
+ video_save_active_screen_snapshots(Machine);
+ debug_console_printf("Saved snapshot\n");
+ }
+
+ /* otherwise, we have to open the file ourselves */
+ else
+ {
+ file_error filerr;
+ mame_file *fp;
+ const char *filename = param[0];
+ int scrnum = (params > 1) ? atoi(param[1]) : 0;
+ UINT32 mask = render_get_live_screens_mask();
+ astring *fname;
+
+ if (scrnum < 0 || scrnum >= MAX_SCREENS || !(mask & (1 << scrnum)))
+ {
+ debug_console_printf("Invalid screen number '%d'\n", scrnum);
+ return;
+ }
+
+ fname = astring_dupc(filename);
+ if (astring_findc(fname, 0, ".png") == -1)
+ astring_catc(fname, ".png");
+ filerr = mame_fopen(SEARCHPATH_SCREENSHOT, astring_c(fname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &fp);
+ astring_free(fname);
+
+ if (filerr != FILERR_NONE)
+ {
+ debug_console_printf("Error creating file '%s'\n", filename);
+ return;
+ }
+
+ video_screen_save_snapshot(Machine, fp, scrnum);
+ mame_fclose(fp);
+ debug_console_printf("Saved screen #%d snapshot as '%s'\n", scrnum, filename);
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_source - execute the source command
+-------------------------------------------------*/
+
+static void execute_source(int ref, int params, const char *param[])
+{
+ debug_source_script(param[0]);
+}
+
+
+/*-------------------------------------------------
+ execute_map - execute the map command
+-------------------------------------------------*/
+
+static void execute_map(int ref, int params, const char *param[])
+{
+ UINT64 address, cpunum = cpu_getactivecpu();
+ const debug_cpu_info *info;
+ int spacenum = ref;
+ offs_t taddress;
+
+ /* validate parameters */
+ if (!debug_command_parameter_number(param[0], &address))
+ return;
+ info = debug_get_cpu_info(cpunum);
+
+ /* do the translation first */
+ taddress = ADDR2BYTE_MASKED(address, info, spacenum);
+ if (info->translate)
+ {
+ if ((*info->translate)(spacenum, &taddress))
+ debug_console_printf("%08X logical -> %08X physical\n", (UINT32)address, BYTE2ADDR(taddress, info, spacenum));
+ else
+ {
+ debug_console_printf("%08X logical -> unmapped\n", (UINT32)address);
+ return;
+ }
+ }
+ else
+ debug_console_printf("%08X physical\n", BYTE2ADDR(taddress, info, spacenum));
+
+ /* now do the mapping */
+ debug_console_printf(" -> read: %s\n", memory_get_handler_string(0, cpunum, spacenum, taddress));
+ debug_console_printf(" -> write: %s\n", memory_get_handler_string(1, cpunum, spacenum, taddress));
+}
+
+
+/*-------------------------------------------------
+ execute_memdump - execute the memdump command
+-------------------------------------------------*/
+
+static void execute_memdump(int ref, int params, const char **param)
+{
+ FILE *file;
+ const char *filename;
+
+ filename = (params == 0) ? "memdump.log" : param[0];
+
+ debug_console_printf("Dumping memory to %s\n", filename);
+
+ file = fopen(filename, "w");
+ if (file)
+ {
+ memory_dump(file);
+ fclose(file);
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_symlist - execute the symlist command
+-------------------------------------------------*/
+
+static int CLIB_DECL symbol_sort_compare(const void *item1, const void *item2)
+{
+ const char *str1 = *(const char **)item1;
+ const char *str2 = *(const char **)item2;
+ return strcmp(str1, str2);
+}
+
+static void execute_symlist(int ref, int params, const char **param)
+{
+ const char *namelist[1000];
+ symbol_table *symtable;
+ UINT64 cpunum = 100000;
+ int symnum, count = 0;
+
+ /* validate parameters */
+ if (params > 0 && !debug_command_parameter_number(param[0], &cpunum))
+ return;
+ if (cpunum != 100000 && cpunum >= cpu_gettotalcpu())
+ {
+ debug_console_printf("Invalid CPU number!\n");
+ return;
+ }
+ symtable = (cpunum == 100000) ? global_symtable : debug_get_cpu_info(cpunum)->symtable;
+
+ if (symtable == global_symtable)
+ debug_console_printf("Global symbols:\n");
+ else
+ debug_console_printf("CPU #%d symbols:\n", (UINT32)cpunum);
+
+ /* gather names for all symbols */
+ for (symnum = 0; symnum < 100000; symnum++)
+ {
+ const symbol_entry *entry;
+ const char *name = symtable_find_indexed(symtable, symnum, &entry);
+
+ /* if we didn't get anything, we're done */
+ if (name == NULL)
+ break;
+
+ /* only display "register" type symbols */
+ if (entry->type == SMT_REGISTER)
+ {
+ namelist[count++] = name;
+ if (count >= ARRAY_LENGTH(namelist))
+ break;
+ }
+ }
+
+ /* sort the symbols */
+ if (count > 1)
+ qsort((void *)namelist, count, sizeof(namelist[0]), symbol_sort_compare);
+
+ /* iterate over symbols and print out relevant ones */
+ for (symnum = 0; symnum < count; symnum++)
+ {
+ const symbol_entry *entry = symtable_find(symtable, namelist[symnum]);
+ UINT64 value = (*entry->info.reg.getter)(entry->ref);
+ assert(entry != NULL);
+
+ /* only display "register" type symbols */
+ debug_console_printf("%s = ", namelist[symnum]);
+ if ((value >> 32) != 0)
+ debug_console_printf("%X%08X", (UINT32)(value >> 32), (UINT32)value);
+ else
+ debug_console_printf("%X", (UINT32)value);
+ if (entry->info.reg.setter == NULL)
+ debug_console_printf(" (read-only)");
+ debug_console_printf("\n");
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_softreset - execute the softreset command
+-------------------------------------------------*/
+
+static void execute_softreset(int ref, int params, const char **param)
+{
+ mame_schedule_soft_reset(Machine);
+}
+
+
+/*-------------------------------------------------
+ execute_hardreset - execute the hardreset command
+-------------------------------------------------*/
+
+static void execute_hardreset(int ref, int params, const char **param)
+{
+ mame_schedule_hard_reset(Machine);
+}
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
new file mode 100644
index 00000000000..b59587718f8
--- /dev/null
+++ b/src/emu/debug/debugcmd.h
@@ -0,0 +1,26 @@
+/*********************************************************************
+
+ debugcmd.h
+
+ Debugger command interface engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#ifndef __DEBUGCMD_H__
+#define __DEBUGCMD_H__
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* initialization */
+void debug_command_init(running_machine *machine);
+
+/* parameter validation */
+int debug_command_parameter_number(const char *param, UINT64 *result);
+
+#endif
diff --git a/src/emu/debug/debugcmt.c b/src/emu/debug/debugcmt.c
new file mode 100644
index 00000000000..fd532f1d904
--- /dev/null
+++ b/src/emu/debug/debugcmt.c
@@ -0,0 +1,570 @@
+/***************************************************************************
+
+ debugcmt.c
+
+ Debugger code-comment management functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Debugger comment file format:
+
+ (from comment struct - assuming (MAX_COMMENT_LINE_LENGTH == 128))
+ 0 - valid byte
+ 1:4 - address
+ 5:133 - comment
+ 134:138 - color
+ 139:142 - instruction crc
+
+***************************************************************************/
+
+#include "driver.h"
+#include "xmlfile.h"
+#include "debugcmt.h"
+#include "debugcpu.h"
+#include "debugvw.h"
+#include "info.h"
+#include <zlib.h>
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+//#define VERBOSE
+
+#ifdef VERBOSE
+#define TRACE(x) do {x;} while (0)
+#else
+#define TRACE(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define COMMENT_VERSION (1)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _debug_comment debug_comment;
+struct _debug_comment
+{
+ UINT8 is_valid;
+ UINT32 address;
+ char text[DEBUG_COMMENT_MAX_LINE_LENGTH];
+ rgb_t color;
+ UINT32 crc;
+};
+
+typedef struct _comment_group comment_group;
+struct _comment_group
+{
+ int comment_count;
+ UINT32 change_count;
+ debug_comment *comment_info[DEBUG_COMMENT_MAX_NUM];
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static comment_group *debug_comments;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int debug_comment_load_xml(mame_file *file);
+static void debug_comment_exit(running_machine *machine);
+static void debug_comment_free(void);
+
+
+
+/***************************************************************************
+
+ Initialization
+
+***************************************************************************/
+
+/*-------------------------------------------------------------------------
+ debug_comment_init - initializes the comment memory and
+ loads any existing comment file
+-------------------------------------------------------------------------*/
+
+int debug_comment_init(running_machine *machine)
+{
+ /* allocate enough comment groups for the total # of cpu's */
+ debug_comments = (comment_group*) auto_malloc(cpu_gettotalcpu() * sizeof(comment_group));
+ memset(debug_comments, 0, cpu_gettotalcpu() * sizeof(comment_group));
+
+ /* automatically load em up */
+ debug_comment_load();
+
+ add_exit_callback(machine, debug_comment_exit);
+
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_add - adds a comment to the list at the given address.
+ use debug_comment_get_opcode_crc32(addr) to get
+ the proper crc32
+-------------------------------------------------------------------------*/
+
+int debug_comment_add(int cpu_num, offs_t addr, const char *comment, rgb_t color, UINT32 c_crc)
+{
+ int i = 0;
+ int insert_point = debug_comments[cpu_num].comment_count;
+ int match = 0;
+
+ /* Create a new item to insert into the list */
+ debug_comment *insert_me = (debug_comment*) malloc_or_die(sizeof(debug_comment));
+ insert_me->color = color;
+ insert_me->is_valid = 1;
+ insert_me->address = addr;
+ insert_me->crc = c_crc;
+ strcpy(insert_me->text, comment);
+
+ /* Find the insert point */
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (insert_me->address < debug_comments[cpu_num].comment_info[i]->address)
+ {
+ insert_point = i;
+ break;
+ }
+ else if (insert_me->address == debug_comments[cpu_num].comment_info[i]->address &&
+ insert_me->crc == debug_comments[cpu_num].comment_info[i]->crc)
+ {
+ insert_point = i;
+ match = 1;
+ break;
+ }
+ }
+
+ /* Got an exact match? Just replace */
+ if (match == 1)
+ {
+ free(debug_comments[cpu_num].comment_info[insert_point]);
+ debug_comments[cpu_num].comment_info[insert_point] = insert_me;
+ debug_comments[cpu_num].change_count++;
+
+ /* force an update of disassembly views */
+ debug_view_update_type(DVT_DISASSEMBLY);
+ return 1;
+ }
+
+ /* Otherwise insert */
+ /* First, shift the list down */
+ for (i = debug_comments[cpu_num].comment_count; i >= insert_point; i--)
+ debug_comments[cpu_num].comment_info[i] = debug_comments[cpu_num].comment_info[i-1];
+
+ /* do the insertion */
+ debug_comments[cpu_num].comment_info[insert_point] = insert_me;
+ debug_comments[cpu_num].comment_count++;
+ debug_comments[cpu_num].change_count++;
+
+ /* force an update of disassembly views */
+ debug_view_update_type(DVT_DISASSEMBLY);
+
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_remove - removes a comment at a given address
+ use debug_comment_get_opcode_crc32(addr) to get
+ the proper crc32
+-------------------------------------------------------------------------*/
+
+int debug_comment_remove(int cpu_num, offs_t addr, UINT32 c_crc)
+{
+ int i;
+ int remove_index = -1;
+
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (debug_comments[cpu_num].comment_info[i]->address == addr) /* got an address match */
+ {
+ if (debug_comments[cpu_num].comment_info[i]->crc == c_crc)
+ {
+ remove_index = i;
+ }
+ }
+ }
+
+ /* The comment doesn't exist? */
+ if (remove_index == -1)
+ return 0;
+
+ /* Okay, it's there, now remove it */
+ free(debug_comments[cpu_num].comment_info[remove_index]);
+
+ for (i = remove_index; i < debug_comments[cpu_num].comment_count-1; i++)
+ {
+ debug_comments[cpu_num].comment_info[i] = debug_comments[cpu_num].comment_info[i+1];
+ }
+
+ debug_comments[cpu_num].comment_count--;
+ debug_comments[cpu_num].change_count++;
+
+ /* force an update of disassembly views */
+ debug_view_update_type(DVT_DISASSEMBLY);
+
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_get_text - returns the comment for a given addresses
+ use debug_comment_get_opcode_crc32(addr) to get
+ the proper crc32
+-------------------------------------------------------------------------*/
+
+const char *debug_comment_get_text(int cpu_num, offs_t addr, UINT32 c_crc)
+{
+ int i;
+
+ /* inefficient - should use bsearch - but will be a little tricky with multiple comments per addr */
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (debug_comments[cpu_num].comment_info[i]->address == addr) /* got an address match */
+ {
+ /* now check the bank information to be sure */
+ if (debug_comments[cpu_num].comment_info[i]->crc == c_crc)
+ {
+ return debug_comments[cpu_num].comment_info[i]->text;
+ }
+ }
+ }
+
+ return 0x00;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_get_count - returns the number of comments
+ for a given cpu number
+-------------------------------------------------------------------------*/
+
+int debug_comment_get_count(int cpu_num)
+{
+ return debug_comments[cpu_num].comment_count;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_get_change_count - returns the change counter
+ for a given cpu number
+-------------------------------------------------------------------------*/
+
+UINT32 debug_comment_get_change_count(int cpu_num)
+{
+ return debug_comments[cpu_num].change_count;
+}
+
+/*-------------------------------------------------------------------------
+ debug_comment_all_change_count - returns the change counter
+ for all cpu's
+-------------------------------------------------------------------------*/
+
+UINT32 debug_comment_all_change_count(void)
+{
+ int i ;
+ UINT32 retVal = 0;
+
+ for (i = 0; i < cpu_gettotalcpu(); i++)
+ retVal += debug_comments[i].change_count ;
+
+ return retVal;
+}
+
+/*-------------------------------------------------------------------------
+ debug_comment_get_opcode_crc32 - magic function that takes all the
+ current state of the debugger and returns a crc32
+ for the opcode at the requested address.
+-------------------------------------------------------------------------*/
+
+UINT32 debug_comment_get_opcode_crc32(offs_t address)
+{
+ const debug_cpu_info *info = debug_get_cpu_info(cpu_getactivecpu());
+ int i;
+ UINT32 crc;
+ UINT8 opbuf[64], argbuf[64];
+ char buff[256];
+ offs_t numbytes;
+ int maxbytes = activecpu_max_instruction_bytes();
+ UINT32 addrmask = (debug_get_cpu_info(cpu_getactivecpu()))->space[ADDRESS_SPACE_PROGRAM].logaddrmask;
+
+ memset(opbuf, 0x00, sizeof(opbuf));
+ memset(argbuf, 0x00, sizeof(argbuf));
+
+ // fetch the bytes up to the maximum
+ for (i = 0; i < maxbytes; i++)
+ {
+ opbuf[i] = debug_read_opcode(address + i, 1, FALSE);
+ argbuf[i] = debug_read_opcode(address + i, 1, TRUE);
+ }
+
+ numbytes = activecpu_dasm(buff, address & addrmask, opbuf, argbuf) & DASMFLAG_LENGTHMASK;
+ numbytes = ADDR2BYTE(numbytes, info, ADDRESS_SPACE_PROGRAM);
+
+ crc = crc32(0, argbuf, numbytes);
+
+ return crc;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_dump - debugging function to dump junk to the command line
+-------------------------------------------------------------------------*/
+
+void debug_comment_dump(int cpu_num, offs_t addr)
+{
+ int i;
+ int ff = 0;
+
+ if (addr == -1)
+ {
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (debug_comments[cpu_num].comment_info[i]->is_valid)
+ {
+ logerror("%d : %s (%d %d)\n", i, debug_comments[cpu_num].comment_info[i]->text,
+ debug_comments[cpu_num].comment_info[i]->address,
+ debug_comments[cpu_num].comment_info[i]->crc);
+ }
+ }
+ }
+ else
+ {
+ UINT32 c_crc = debug_comment_get_opcode_crc32(addr);
+
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (debug_comments[cpu_num].comment_info[i]->address == addr) /* got an address match */
+ {
+ /* now check the bank information to be sure */
+ if (debug_comments[cpu_num].comment_info[i]->crc == c_crc)
+ {
+ logerror("%d : %s (%d %d)\n", addr,
+ debug_comments[cpu_num].comment_info[addr]->text,
+ debug_comments[cpu_num].comment_info[addr]->address,
+ debug_comments[cpu_num].comment_info[addr]->crc);
+ ff = 1;
+ }
+ }
+ }
+
+ if (!ff) logerror("No comment exists for address : 0x%x\n", addr);
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_save - comment file saving
+-------------------------------------------------------------------------*/
+
+int debug_comment_save(void)
+{
+ int i, j;
+ char crc_buf[20];
+ xml_data_node *root = xml_file_create();
+ xml_data_node *commentnode, *systemnode;
+ int total_comments = 0;
+
+ /* if we don't have a root, bail */
+ if (!root)
+ return 0;
+
+ /* create a comment node */
+ commentnode = xml_add_child(root, "mamecommentfile", NULL);
+ if (!commentnode)
+ goto error;
+ xml_set_attribute_int(commentnode, "version", COMMENT_VERSION);
+
+ /* create a system node */
+ systemnode = xml_add_child(commentnode, "system", NULL);
+ if (!systemnode)
+ goto error;
+ xml_set_attribute(systemnode, "name", Machine->gamedrv->name);
+
+ /* for each cpu */
+ for (i = 0; i < cpu_gettotalcpu(); i++)
+ {
+ xml_data_node *curnode = xml_add_child(systemnode, "cpu", NULL);
+ if (!curnode)
+ goto error;
+ xml_set_attribute_int(curnode, "num", i);
+
+ for (j = 0; j < debug_comments[i].comment_count; j++)
+ {
+ xml_data_node *datanode = xml_add_child(curnode, "comment", xml_normalize_string(debug_comments[i].comment_info[j]->text));
+ if (!datanode)
+ goto error;
+ xml_set_attribute_int(datanode, "address", debug_comments[i].comment_info[j]->address);
+ xml_set_attribute_int(datanode, "color", debug_comments[i].comment_info[j]->color);
+ sprintf(crc_buf, "%08X", debug_comments[i].comment_info[j]->crc);
+ xml_set_attribute(datanode, "crc", crc_buf);
+ total_comments++;
+ }
+ }
+
+ /* flush the file */
+ if (total_comments > 0)
+ {
+ file_error filerr;
+ astring *fname;
+ mame_file *fp;
+
+ fname = astring_assemble_2(astring_alloc(), Machine->basename, ".cmt");
+ filerr = mame_fopen(SEARCHPATH_COMMENT, astring_c(fname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &fp);
+ astring_free(fname);
+
+ if (filerr == FILERR_NONE)
+ {
+ xml_file_write(root, mame_core_file(fp));
+ mame_fclose(fp);
+ }
+ }
+
+ /* free and get out of here */
+ xml_file_free(root);
+ return 1;
+
+error:
+ xml_file_free(root);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_load(_xml) - comment file loading
+-------------------------------------------------------------------------*/
+
+int debug_comment_load(void)
+{
+ file_error filerr;
+ mame_file *fp;
+ astring *fname;
+
+ fname = astring_assemble_2(astring_alloc(), Machine->basename, ".cmt");
+ filerr = mame_fopen(SEARCHPATH_COMMENT, astring_c(fname), OPEN_FLAG_READ, &fp);
+ astring_free(fname);
+
+ if (filerr != FILERR_NONE) return 0;
+ debug_comment_load_xml(fp);
+ mame_fclose(fp);
+
+ return 1;
+}
+
+static int debug_comment_load_xml(mame_file *fp)
+{
+ int i, j;
+ xml_data_node *root, *commentnode, *systemnode, *cpunode, *datanode;
+ const char *name;
+ int version;
+
+ /* read the file */
+ root = xml_file_read(mame_core_file(fp), NULL);
+ if (!root)
+ goto error;
+
+ /* find the config node */
+ commentnode = xml_get_sibling(root->child, "mamecommentfile");
+ if (!commentnode)
+ goto error;
+
+ /* validate the config data version */
+ version = xml_get_attribute_int(commentnode, "version", 0);
+ if (version != COMMENT_VERSION)
+ goto error;
+
+ /* check to make sure the file is applicable */
+ systemnode = xml_get_sibling(commentnode->child, "system");
+ name = xml_get_attribute_string(systemnode, "name", "");
+ if (strcmp(name, Machine->gamedrv->name) != 0)
+ goto error;
+
+ i = 0;
+
+ for (cpunode = xml_get_sibling(systemnode->child, "cpu"); cpunode; cpunode = xml_get_sibling(cpunode->next, "cpu"))
+ {
+ j = 0;
+
+ for (datanode = xml_get_sibling(cpunode->child, "comment"); datanode; datanode = xml_get_sibling(datanode->next, "comment"))
+ {
+ /* Malloc the comment */
+ debug_comments[i].comment_info[j] = (debug_comment*) malloc(sizeof(debug_comment));
+
+ debug_comments[i].comment_info[j]->address = xml_get_attribute_int(datanode, "address", 0);
+ debug_comments[i].comment_info[j]->color = xml_get_attribute_int(datanode, "color", 0);
+ sscanf(xml_get_attribute_string(datanode, "crc", 0), "%08X", &debug_comments[i].comment_info[j]->crc);
+ strcpy(debug_comments[i].comment_info[j]->text, datanode->value);
+ debug_comments[i].comment_info[j]->is_valid = 1;
+
+ j++;
+ }
+
+ debug_comments[i].comment_count = j;
+
+ i++;
+ }
+
+ /* free the parser */
+ xml_file_free(root);
+
+ return 1;
+
+error:
+ if (root)
+ xml_file_free(root);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_exit - saves the comments and frees memory
+-------------------------------------------------------------------------*/
+
+static void debug_comment_exit(running_machine *machine)
+{
+ debug_comment_save();
+ debug_comment_free();
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_free - cleans up memory
+-------------------------------------------------------------------------*/
+
+static void debug_comment_free(void)
+{
+ int i, j;
+
+ for (i = 0; i < cpu_gettotalcpu(); i++)
+ {
+ for (j = 0; j < debug_comments[i].comment_count; j++)
+ {
+ free(debug_comments[i].comment_info[j]);
+ }
+
+ debug_comments[i].comment_count = 0;
+ }
+}
diff --git a/src/emu/debug/debugcmt.h b/src/emu/debug/debugcmt.h
new file mode 100644
index 00000000000..39a7153203d
--- /dev/null
+++ b/src/emu/debug/debugcmt.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+
+ debugcmt.h
+
+ Debugger code-comment management functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __DEBUGCMT_H__
+#define __DEBUGCMT_H__
+
+#define DEBUG_COMMENT_MAX_LINE_LENGTH (128) /* 128 characters per comment - 50 are displayed at once */
+#define DEBUG_COMMENT_MAX_NUM (0x10000) /* 64k comments should be good for awhile */
+
+/* init and exit */
+int debug_comment_init(running_machine *machine);
+
+/* load and save */
+int debug_comment_save(void);
+int debug_comment_load(void);
+
+/* comment interface functions */
+int debug_comment_add(int cpu_num, offs_t addr, const char *comment, rgb_t color, UINT32 c_crc);
+int debug_comment_remove(int cpu_num, offs_t addr, UINT32 c_crc);
+
+const char *debug_comment_get_text(int cpu_num, offs_t addr, UINT32 c_crc);
+int debug_comment_get_count(int cpu_num);
+UINT32 debug_comment_get_change_count(int cpu_num);
+UINT32 debug_comment_all_change_count(void);
+
+/* local functionality */
+UINT32 debug_comment_get_opcode_crc32(offs_t address); /* pull a crc for the opcode at a given address */
+void debug_comment_dump(int cpu_num, offs_t addr); /* dump all (or a single) comment to the command line */
+
+#endif
diff --git a/src/emu/debug/debugcon.c b/src/emu/debug/debugcon.c
new file mode 100644
index 00000000000..98bf9c8ce30
--- /dev/null
+++ b/src/emu/debug/debugcon.c
@@ -0,0 +1,533 @@
+/*********************************************************************
+
+ debugcon.c
+
+ Debugger console engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "debugcon.h"
+#include "debugcpu.h"
+#include "debughlp.h"
+#include "debugvw.h"
+#include "textbuf.h"
+#include <stdarg.h>
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define CONSOLE_BUF_SIZE (1024 * 1024)
+#define CONSOLE_MAX_LINES (CONSOLE_BUF_SIZE / 20)
+
+#define ERRORLOG_BUF_SIZE (1024 * 1024)
+#define ERRORLOG_MAX_LINES (ERRORLOG_BUF_SIZE / 20)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _debug_command debug_command;
+struct _debug_command
+{
+ debug_command * next;
+ char command[32];
+ const char * params;
+ const char * help;
+ void (*handler)(int ref, int params, const char **param);
+ void (*handler_ex)(int ref);
+ UINT32 flags;
+ int ref;
+ int minparams;
+ int maxparams;
+};
+
+
+
+/***************************************************************************
+ LOCAL VARIABLES
+***************************************************************************/
+
+static text_buffer *console_textbuf;
+static text_buffer *errorlog_textbuf;
+
+static debug_command *commandlist;
+
+
+
+/***************************************************************************
+
+ Initialization and tear down
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_console_init - initializes the console
+ system
+-------------------------------------------------*/
+
+void debug_console_init(running_machine *machine)
+{
+ /* allocate text buffers */
+ console_textbuf = text_buffer_alloc(CONSOLE_BUF_SIZE, CONSOLE_MAX_LINES);
+ if (!console_textbuf)
+ return;
+
+ errorlog_textbuf = text_buffer_alloc(ERRORLOG_BUF_SIZE, ERRORLOG_MAX_LINES);
+ if (!errorlog_textbuf)
+ return;
+
+ /* print the opening lines */
+ debug_console_printf("MAME new debugger version %s\n", build_version);
+ debug_console_printf("Currently targeting %s (%s)\n", Machine->gamedrv->name, Machine->gamedrv->description);
+
+ /* request callback upon exiting */
+ add_exit_callback(machine, debug_console_exit);
+}
+
+
+/*-------------------------------------------------
+ debug_console_exit - frees the console
+ system
+-------------------------------------------------*/
+
+void debug_console_exit(running_machine *machine)
+{
+ /* free allocated memory */
+ if (console_textbuf)
+ text_buffer_free(console_textbuf);
+ console_textbuf = NULL;
+
+ if (errorlog_textbuf)
+ text_buffer_free(errorlog_textbuf);
+ errorlog_textbuf = NULL;
+
+ /* free the command list */
+ commandlist = NULL;
+}
+
+
+
+/***************************************************************************
+
+ Command Handling
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ trim_parameter - executes a
+ command
+-------------------------------------------------*/
+
+static void trim_parameter(char **paramptr, int keep_quotes)
+{
+ char *param = *paramptr;
+ size_t len = strlen(param);
+ int repeat;
+
+ /* loop until all adornments are gone */
+ do
+ {
+ repeat = 0;
+
+ /* check for begin/end quotes */
+ if (len >= 2 && param[0] == '"' && param[len - 1] == '"')
+ {
+ if (!keep_quotes)
+ {
+ param[len - 1] = 0;
+ param++;
+ len -= 2;
+ }
+ }
+
+ /* check for start/end braces */
+ else if (len >= 2 && param[0] == '{' && param[len - 1] == '}')
+ {
+ param[len - 1] = 0;
+ param++;
+ len -= 2;
+ repeat = 1;
+ }
+
+ /* check for leading spaces */
+ else if (len >= 1 && param[0] == ' ')
+ {
+ param++;
+ len--;
+ repeat = 1;
+ }
+
+ /* check for trailing spaces */
+ else if (len >= 1 && param[len - 1] == ' ')
+ {
+ param[len - 1] = 0;
+ len--;
+ repeat = 1;
+ }
+ } while (repeat);
+
+ *paramptr = param;
+}
+
+
+/*-------------------------------------------------
+ internal_execute_command - executes a
+ command
+-------------------------------------------------*/
+
+static CMDERR internal_execute_command(int execute, int params, char **param)
+{
+ debug_command *cmd, *found = NULL;
+ int i, foundcount = 0;
+ char *p, *command;
+ size_t len;
+
+ /* no params is an error */
+ if (params == 0)
+ return CMDERR_NONE;
+
+ /* the first parameter has the command and the real first parameter; separate them */
+ for (p = param[0]; *p && isspace(*p); p++) { }
+ for (command = p; *p && !isspace(*p); p++) { }
+ if (*p != 0)
+ {
+ *p++ = 0;
+ for ( ; *p && isspace(*p); p++) { }
+ if (*p != 0)
+ param[0] = p;
+ else
+ params = 0;
+ }
+ else
+ params = 0;
+
+ /* search the command list */
+ len = strlen(command);
+ for (cmd = commandlist; cmd != NULL; cmd = cmd->next)
+ if (!strncmp(command, cmd->command, len))
+ {
+ foundcount++;
+ found = cmd;
+ if (strlen(cmd->command) == len)
+ {
+ foundcount = 1;
+ break;
+ }
+ }
+
+ /* error if not found */
+ if (!found)
+ return MAKE_CMDERR_UNKNOWN_COMMAND(0);
+ if (foundcount > 1)
+ return MAKE_CMDERR_AMBIGUOUS_COMMAND(0);
+
+ /* NULL-terminate and trim space around all the parameters */
+ for (i = 1; i < params; i++)
+ *param[i]++ = 0;
+
+ /* now go back and trim quotes and braces and any spaces they reveal*/
+ for (i = 0; i < params; i++)
+ trim_parameter(&param[i], found->flags & CMDFLAG_KEEP_QUOTES);
+
+ /* see if we have the right number of parameters */
+ if (params < found->minparams)
+ return MAKE_CMDERR_NOT_ENOUGH_PARAMS(0);
+ if (params > found->maxparams)
+ return MAKE_CMDERR_TOO_MANY_PARAMS(0);
+
+ /* execute the handler */
+ if (execute)
+ (*found->handler)(found->ref, params, (const char **)param);
+ return CMDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ internal_parse_command - parses a command
+ and either executes or just validates it
+-------------------------------------------------*/
+
+static CMDERR internal_parse_command(const char *original_command, int execute)
+{
+ char command[MAX_COMMAND_LENGTH], parens[MAX_COMMAND_LENGTH];
+ char *params[MAX_COMMAND_PARAMS];
+ CMDERR result = CMDERR_NONE;
+ char *command_start;
+ char *p, c = 0;
+
+ /* make a copy of the command */
+ strcpy(command, original_command);
+
+ /* loop over all semicolon-separated stuff */
+ for (p = command; *p != 0; )
+ {
+ int paramcount = 0, foundend = FALSE, instring = FALSE, isexpr = FALSE, parendex = 0;
+
+ /* find a semicolon or the end */
+ for (params[paramcount++] = p; !foundend; p++)
+ {
+ c = *p;
+ if (instring)
+ {
+ if (c == '"' && p[-1] != '\\')
+ instring = FALSE;
+ }
+ else
+ {
+ switch (c)
+ {
+ case '"': instring = TRUE; break;
+ case '(':
+ case '[':
+ case '{': parens[parendex++] = c; break;
+ case ')': if (parendex == 0 || parens[--parendex] != '(') return MAKE_CMDERR_UNBALANCED_PARENS(p - command); break;
+ case ']': if (parendex == 0 || parens[--parendex] != '[') return MAKE_CMDERR_UNBALANCED_PARENS(p - command); break;
+ case '}': if (parendex == 0 || parens[--parendex] != '{') return MAKE_CMDERR_UNBALANCED_PARENS(p - command); break;
+ case ',': if (parendex == 0) params[paramcount++] = p; break;
+ case ';': if (parendex == 0) foundend = TRUE; break;
+ case '-': if (parendex == 0 && paramcount == 1 && p[1] == '-') isexpr = TRUE; *p = c; break;
+ case '+': if (parendex == 0 && paramcount == 1 && p[1] == '+') isexpr = TRUE; *p = c; break;
+ case '=': if (parendex == 0 && paramcount == 1) isexpr = TRUE; *p = c; break;
+ case 0: foundend = TRUE; break;
+ default: *p = tolower(c); break;
+ }
+ }
+ }
+
+ /* check for unbalanced parentheses or quotes */
+ if (instring)
+ return MAKE_CMDERR_UNBALANCED_QUOTES(p - command);
+ if (parendex != 0)
+ return MAKE_CMDERR_UNBALANCED_PARENS(p - command);
+
+ /* NULL-terminate if we ended in a semicolon */
+ p--;
+ if (c == ';') *p++ = 0;
+
+ /* process the command */
+ command_start = params[0];
+
+ /* allow for "do" commands */
+ if (tolower(command_start[0] == 'd') && tolower(command_start[1] == 'o') && isspace(command_start[2]))
+ {
+ isexpr = TRUE;
+ command_start += 3;
+ }
+
+ /* if it smells like an assignment expression, treat it as such */
+ if (isexpr && paramcount == 1)
+ {
+ UINT64 expresult;
+ EXPRERR exprerr = expression_evaluate(command_start, debug_get_cpu_info(cpu_getactivecpu())->symtable, &expresult);
+ if (exprerr != EXPRERR_NONE)
+ return MAKE_CMDERR_EXPRESSION_ERROR(EXPRERR_ERROR_OFFSET(exprerr));
+ }
+ else
+ {
+ result = internal_execute_command(execute, paramcount, &params[0]);
+ if (result != CMDERR_NONE)
+ return MAKE_CMDERR(CMDERR_ERROR_CLASS(result), command_start - command);
+ }
+ }
+ return CMDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ debug_console_execute_command - execute a
+ command string
+-------------------------------------------------*/
+
+CMDERR debug_console_execute_command(const char *command, int echo)
+{
+ CMDERR result;
+
+ /* echo if requested */
+ if (echo)
+ debug_console_printf(">%s\n", command);
+
+ /* parse and execute */
+ result = internal_parse_command(command, TRUE);
+
+ /* display errors */
+ if (result != CMDERR_NONE)
+ {
+ if (!echo)
+ debug_console_printf(">%s\n", command);
+ debug_console_printf(" %*s^\n", CMDERR_ERROR_OFFSET(result), "");
+ debug_console_printf("%s\n", debug_cmderr_to_string(result));
+ }
+
+ /* update all views */
+ if (echo)
+ {
+ debug_view_update_all();
+ debug_refresh_display();
+ }
+ return result;
+}
+
+
+/*-------------------------------------------------
+ debug_console_validate_command - validate a
+ command string
+-------------------------------------------------*/
+
+CMDERR debug_console_validate_command(const char *command)
+{
+ return internal_parse_command(command, FALSE);
+}
+
+
+/*-------------------------------------------------
+ debug_console_register_command - register a
+ command handler
+-------------------------------------------------*/
+
+void debug_console_register_command(const char *command, UINT32 flags, int ref, int minparams, int maxparams, void (*handler)(int ref, int params, const char **param))
+{
+ debug_command *cmd;
+
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call debug_console_register_command() at init time!");
+ assert_always(Machine->debug_mode, "Cannot call debug_console_register_command() when debugger is not running");
+
+ cmd = auto_malloc(sizeof(*cmd));
+ memset(cmd, 0, sizeof(*cmd));
+
+ /* fill in the command */
+ strcpy(cmd->command, command);
+ cmd->flags = flags;
+ cmd->ref = ref;
+ cmd->minparams = minparams;
+ cmd->maxparams = maxparams;
+ cmd->handler = handler;
+
+ /* link it */
+ cmd->next = commandlist;
+ commandlist = cmd;
+}
+
+
+
+/***************************************************************************
+
+ Error Handling
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_cmderr_to_string - return a friendly
+ string for a given command error
+-------------------------------------------------*/
+
+const char *debug_cmderr_to_string(CMDERR error)
+{
+ switch (CMDERR_ERROR_CLASS(error))
+ {
+ case CMDERR_UNKNOWN_COMMAND: return "unknown command";
+ case CMDERR_AMBIGUOUS_COMMAND: return "ambiguous command";
+ case CMDERR_UNBALANCED_PARENS: return "unbalanced parentheses";
+ case CMDERR_UNBALANCED_QUOTES: return "unbalanced quotes";
+ case CMDERR_NOT_ENOUGH_PARAMS: return "not enough parameters for command";
+ case CMDERR_TOO_MANY_PARAMS: return "too many parameters for command";
+ case CMDERR_EXPRESSION_ERROR: return "error in assignment expression";
+ default: return "unknown error";
+ }
+}
+
+
+
+/***************************************************************************
+
+ Console Management
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_console_printf - printfs the given
+ arguments using the format to the debug
+ console
+-------------------------------------------------*/
+
+void CLIB_DECL debug_console_printf(const char *format, ...)
+{
+ va_list arg;
+
+ va_start(arg, format);
+ vsprintf(giant_string_buffer, format, arg);
+ va_end(arg);
+
+ text_buffer_print(console_textbuf, giant_string_buffer);
+
+ /* force an update of any console views */
+ debug_view_update_type(DVT_CONSOLE);
+}
+
+
+/*-------------------------------------------------
+ debug_console_printf_wrap - printfs the given
+ arguments using the format to the debug
+ console
+-------------------------------------------------*/
+
+void CLIB_DECL debug_console_printf_wrap(int wrapcol, const char *format, ...)
+{
+ va_list arg;
+
+ va_start(arg, format);
+ vsprintf(giant_string_buffer, format, arg);
+ va_end(arg);
+
+ text_buffer_print_wrap(console_textbuf, giant_string_buffer, wrapcol);
+
+ /* force an update of any console views */
+ debug_view_update_type(DVT_CONSOLE);
+}
+
+
+/*-------------------------------------------------
+ debug_console_get_textbuf - return a pointer
+ to the console text buffer
+-------------------------------------------------*/
+
+text_buffer *debug_console_get_textbuf(void)
+{
+ return console_textbuf;
+}
+
+
+/*-------------------------------------------------
+ debug_errorlog_write_line - writes a line to
+ the errorlog ring buffer
+-------------------------------------------------*/
+
+void debug_errorlog_write_line(running_machine *machine, const char *line)
+{
+ if (errorlog_textbuf)
+ text_buffer_print(errorlog_textbuf, line);
+
+ /* force an update of any log views */
+ debug_view_update_type(DVT_LOG);
+}
+
+
+/*-------------------------------------------------
+ debug_errorlog_get_textbuf - return a pointer
+ to the errorlog text buffer
+-------------------------------------------------*/
+
+text_buffer *debug_errorlog_get_textbuf(void)
+{
+ return errorlog_textbuf;
+}
+
diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h
new file mode 100644
index 00000000000..1cb2a8f1e8f
--- /dev/null
+++ b/src/emu/debug/debugcon.h
@@ -0,0 +1,97 @@
+/*********************************************************************
+
+ debugcon.h
+
+ Debugger console engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#ifndef __DEBUGCON_H__
+#define __DEBUGCON_H__
+
+#include "textbuf.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_COMMAND_LENGTH 512
+#define MAX_COMMAND_PARAMS 16
+
+/* flags for command parsing */
+#define CMDFLAG_NONE (0x0000)
+#define CMDFLAG_KEEP_QUOTES (0x0001)
+
+/* values for the error code in a command error */
+#define CMDERR_NONE (0)
+#define CMDERR_UNKNOWN_COMMAND (1)
+#define CMDERR_AMBIGUOUS_COMMAND (2)
+#define CMDERR_UNBALANCED_PARENS (3)
+#define CMDERR_UNBALANCED_QUOTES (4)
+#define CMDERR_NOT_ENOUGH_PARAMS (5)
+#define CMDERR_TOO_MANY_PARAMS (6)
+#define CMDERR_EXPRESSION_ERROR (7)
+
+/* parameter separator macros */
+#define CMDPARAM_SEPARATOR "\0"
+#define CMDPARAM_TERMINATOR "\0\0"
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* command error assembly/disassembly macros */
+#define CMDERR_ERROR_CLASS(x) ((x) >> 16)
+#define CMDERR_ERROR_OFFSET(x) ((x) & 0xffff)
+#define MAKE_CMDERR(a,b) (((a) << 16) | ((b) & 0xffff))
+
+/* macros to assemble specific error conditions */
+#define MAKE_CMDERR_UNKNOWN_COMMAND(x) MAKE_CMDERR(CMDERR_UNKNOWN_COMMAND, (x))
+#define MAKE_CMDERR_AMBIGUOUS_COMMAND(x) MAKE_CMDERR(CMDERR_AMBIGUOUS_COMMAND, (x))
+#define MAKE_CMDERR_UNBALANCED_PARENS(x) MAKE_CMDERR(CMDERR_UNBALANCED_PARENS, (x))
+#define MAKE_CMDERR_UNBALANCED_QUOTES(x) MAKE_CMDERR(CMDERR_UNBALANCED_QUOTES, (x))
+#define MAKE_CMDERR_NOT_ENOUGH_PARAMS(x) MAKE_CMDERR(CMDERR_NOT_ENOUGH_PARAMS, (x))
+#define MAKE_CMDERR_TOO_MANY_PARAMS(x) MAKE_CMDERR(CMDERR_TOO_MANY_PARAMS, (x))
+#define MAKE_CMDERR_EXPRESSION_ERROR(x) MAKE_CMDERR(CMDERR_EXPRESSION_ERROR, (x))
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* CMDERR is an error code for command evaluation */
+typedef UINT32 CMDERR;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* initialization */
+void debug_console_init(running_machine *machine);
+void debug_console_exit(running_machine *machine);
+
+/* command handling */
+CMDERR debug_console_execute_command(const char *command, int echo);
+CMDERR debug_console_validate_command(const char *command);
+void debug_console_register_command(const char *command, UINT32 flags, int ref, int minparams, int maxparams, void (*handler)(int ref, int params, const char **param));
+const char * debug_cmderr_to_string(CMDERR error);
+
+/* console management */
+void CLIB_DECL debug_console_printf(const char *format, ...) ATTR_PRINTF(1,2);
+void CLIB_DECL debug_console_printf_wrap(int wrapcol, const char *format, ...) ATTR_PRINTF(2,3);
+text_buffer * debug_console_get_textbuf(void);
+
+/* errorlog management */
+void debug_errorlog_write_line(running_machine *machine, const char *line);
+text_buffer * debug_errorlog_get_textbuf(void);
+
+#endif
diff --git a/src/emu/debug/debugcpu.c b/src/emu/debug/debugcpu.c
new file mode 100644
index 00000000000..d65b07c216e
--- /dev/null
+++ b/src/emu/debug/debugcpu.c
@@ -0,0 +1,2195 @@
+/*********************************************************************
+
+ debugcpu.c
+
+ Debugger CPU/memory interface engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "osdepend.h"
+#include "driver.h"
+#include "debugcpu.h"
+#include "debugcmd.h"
+#include "debugcmt.h"
+#include "debugcon.h"
+#include "express.h"
+#include "debugvw.h"
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define NUM_TEMP_VARIABLES 10
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+
+
+/***************************************************************************
+ LOCAL VARIABLES
+***************************************************************************/
+
+FILE *debug_source_file;
+symbol_table *global_symtable;
+
+static const char *address_space_name[] = { "program", "data", "I/O" };
+
+static UINT64 wpdata;
+static UINT64 wpaddr;
+
+static int execution_state;
+static UINT32 execution_counter;
+static int next_index = 1;
+static int within_debugger_code = FALSE;
+static int last_cpunum;
+static int last_stopped_cpunum;
+static int steps_until_stop;
+static offs_t step_overout_breakpoint;
+static int step_overout_cpunum;
+static int key_check_counter;
+static osd_ticks_t last_periodic_update_time;
+static int break_on_vblank;
+static int break_on_interrupt;
+static int break_on_interrupt_cpunum;
+static int break_on_interrupt_irqline;
+static int break_on_time;
+static attotime break_on_time_target;
+static int memory_modified;
+static int memory_hook_cpunum;
+
+static debug_cpu_info debug_cpuinfo[MAX_CPU];
+
+static UINT64 tempvar[NUM_TEMP_VARIABLES];
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void debug_cpu_exit(running_machine *machine);
+static void perform_trace(debug_cpu_info *info);
+static void prepare_for_step_overout(void);
+static void process_source_file(void);
+static UINT64 get_wpaddr(UINT32 ref);
+static UINT64 get_wpdata(UINT32 ref);
+static UINT64 get_cycles(UINT32 ref);
+static UINT64 get_cpunum(UINT32 ref);
+static UINT64 get_tempvar(UINT32 ref);
+static UINT64 get_logunmap(UINT32 ref);
+static UINT64 get_beamx(UINT32 ref);
+static UINT64 get_beamy(UINT32 ref);
+static void set_tempvar(UINT32 ref, UINT64 value);
+static void set_logunmap(UINT32 ref, UINT64 value);
+static UINT64 get_current_pc(UINT32 ref);
+static UINT64 get_cpu_reg(UINT32 ref);
+static void set_cpu_reg(UINT32 ref, UINT64 value);
+static void check_watchpoints(int cpunum, int spacenum, int type, offs_t address, offs_t size, UINT64 value_to_write);
+static void check_hotspots(int cpunum, int spacenum, offs_t address);
+
+
+
+/***************************************************************************
+ FRONTENDS FOR OLDER FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_debug_init - start up all subsections
+-------------------------------------------------*/
+
+void mame_debug_init(running_machine *machine)
+{
+ /* initialize the various subsections */
+ debug_cpu_init(machine);
+ debug_command_init(machine);
+ debug_console_init(machine);
+ debug_view_init(machine);
+ debug_comment_init(machine);
+ atexit(debug_flush_traces);
+ add_logerror_callback(machine, debug_errorlog_write_line);
+}
+
+
+/*-------------------------------------------------
+ mame_debug_break - break into the debugger
+-------------------------------------------------*/
+
+void mame_debug_break(void)
+{
+ debug_halt_on_next_instruction();
+}
+
+
+/*-------------------------------------------------
+ mame_debug_is_active - true if the debugger
+ is currently live
+-------------------------------------------------*/
+
+int mame_debug_is_active(void)
+{
+ return within_debugger_code;
+}
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_cpu_init - initialize the CPU
+ information for debugging
+-------------------------------------------------*/
+
+void debug_cpu_init(running_machine *machine)
+{
+ int cpunum, spacenum, regnum;
+
+ /* reset globals */
+ execution_state = EXECUTION_STATE_STOPPED;
+ execution_counter = 0;
+ next_index = 1;
+ within_debugger_code = FALSE;
+ last_cpunum = 0;
+ last_stopped_cpunum = 0;
+ steps_until_stop = 0;
+ step_overout_breakpoint = ~0;
+ step_overout_cpunum = 0;
+ key_check_counter = 0;
+
+ /* create a global symbol table */
+ global_symtable = symtable_alloc(NULL);
+
+ /* add "wpaddr", "wpdata", "cycles", "cpunum", "logunmap" to the global symbol table */
+ symtable_add_register(global_symtable, "wpaddr", 0, get_wpaddr, NULL);
+ symtable_add_register(global_symtable, "wpdata", 0, get_wpdata, NULL);
+ symtable_add_register(global_symtable, "cycles", 0, get_cycles, NULL);
+ symtable_add_register(global_symtable, "cpunum", 0, get_cpunum, NULL);
+ symtable_add_register(global_symtable, "logunmap", ADDRESS_SPACE_PROGRAM, get_logunmap, set_logunmap);
+ symtable_add_register(global_symtable, "logunmapd", ADDRESS_SPACE_DATA, get_logunmap, set_logunmap);
+ symtable_add_register(global_symtable, "logunmapi", ADDRESS_SPACE_IO, get_logunmap, set_logunmap);
+ symtable_add_register(global_symtable, "beamx", 0, get_beamx, NULL);
+ symtable_add_register(global_symtable, "beamy", 0, get_beamy, NULL);
+
+ /* add the temporary variables to the global symbol table */
+ for (regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++)
+ {
+ char symname[10];
+ sprintf(symname, "temp%d", regnum);
+ symtable_add_register(global_symtable, symname, regnum, get_tempvar, set_tempvar);
+ }
+
+ /* reset the CPU info */
+ memset(debug_cpuinfo, 0, sizeof(debug_cpuinfo));
+
+ /* loop over CPUs and build up their info */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ cpu_type cputype = Machine->drv->cpu[cpunum].type;
+
+ /* if this is a dummy, stop looking */
+ if (cputype == CPU_DUMMY)
+ break;
+
+ /* reset the PC data */
+ debug_cpuinfo[cpunum].valid = 1;
+ debug_cpuinfo[cpunum].endianness = cpunum_endianness(cpunum);
+ debug_cpuinfo[cpunum].opwidth = cpunum_min_instruction_bytes(cpunum);
+ debug_cpuinfo[cpunum].ignoring = 0;
+ debug_cpuinfo[cpunum].temp_breakpoint_pc = ~0;
+
+ /* fetch the memory accessors */
+ debug_cpuinfo[cpunum].translate = (int (*)(int, offs_t *))cpunum_get_info_fct(cpunum, CPUINFO_PTR_TRANSLATE);
+ debug_cpuinfo[cpunum].read = (int (*)(int, UINT32, int, UINT64 *))cpunum_get_info_fct(cpunum, CPUINFO_PTR_READ);
+ debug_cpuinfo[cpunum].write = (int (*)(int, UINT32, int, UINT64))cpunum_get_info_fct(cpunum, CPUINFO_PTR_WRITE);
+ debug_cpuinfo[cpunum].readop = (int (*)(UINT32, int, UINT64 *))cpunum_get_info_fct(cpunum, CPUINFO_PTR_READOP);
+
+ /* allocate a symbol table */
+ debug_cpuinfo[cpunum].symtable = symtable_alloc(global_symtable);
+
+ /* add a global symbol for the current instruction pointer */
+ symtable_add_register(debug_cpuinfo[cpunum].symtable, "curpc", 0, get_current_pc, 0);
+
+ /* add all registers into it */
+ for (regnum = 0; regnum < MAX_REGS; regnum++)
+ {
+ const char *str = cpunum_reg_string(cpunum, regnum);
+ const char *colon;
+ char symname[256];
+ int charnum;
+
+ /* skip if we don't get a valid string, or one without a colon */
+ if (str == NULL)
+ continue;
+ if (str[0] == '~')
+ str++;
+ colon = strchr(str, ':');
+ if (colon == NULL)
+ continue;
+
+ /* strip all spaces from the name and convert to lowercase */
+ for (charnum = 0; charnum < sizeof(symname) - 1 && str < colon; str++)
+ if (!isspace(*str))
+ symname[charnum++] = tolower(*str);
+ symname[charnum] = 0;
+
+ /* add the symbol to the table */
+ symtable_add_register(debug_cpuinfo[cpunum].symtable, symname, regnum, get_cpu_reg, set_cpu_reg);
+ }
+
+ /* loop over address spaces and get info */
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ {
+ debug_space_info *spaceinfo = &debug_cpuinfo[cpunum].space[spacenum];
+ int datawidth = cpunum_databus_width(cpunum, spacenum);
+ int logwidth = cpunum_logaddr_width(cpunum, spacenum);
+ int physwidth = cpunum_addrbus_width(cpunum, spacenum);
+ int addrshift = cpunum_addrbus_shift(cpunum, spacenum);
+ int pageshift = cpunum_page_shift(cpunum, spacenum);
+
+ if (logwidth == 0)
+ logwidth = physwidth;
+
+ spaceinfo->databytes = datawidth / 8;
+ spaceinfo->pageshift = pageshift;
+
+ /* left/right shifts to convert addresses to bytes */
+ spaceinfo->addr2byte_lshift = (addrshift < 0) ? -addrshift : 0;
+ spaceinfo->addr2byte_rshift = (addrshift > 0) ? addrshift : 0;
+
+ /* number of character used to display addresses */
+ spaceinfo->physchars = (physwidth + 3) / 4;
+ spaceinfo->logchars = (logwidth + 3) / 4;
+
+ /* masks to apply to addresses */
+ spaceinfo->physaddrmask = (0xfffffffful >> (32 - physwidth));
+ spaceinfo->logaddrmask = (0xfffffffful >> (32 - logwidth));
+
+ /* masks to apply to byte addresses */
+ spaceinfo->physbytemask = ((spaceinfo->physaddrmask << spaceinfo->addr2byte_lshift) | ((1 << spaceinfo->addr2byte_lshift) - 1)) >> spaceinfo->addr2byte_rshift;
+ spaceinfo->logbytemask = ((spaceinfo->logaddrmask << spaceinfo->addr2byte_lshift) | ((1 << spaceinfo->addr2byte_lshift) - 1)) >> spaceinfo->addr2byte_rshift;
+ }
+ }
+
+ add_exit_callback(machine, debug_cpu_exit);
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_exit - free all memory
+-------------------------------------------------*/
+
+void debug_cpu_exit(running_machine *machine)
+{
+ int cpunum, spacenum;
+
+ /* loop over all watchpoints and breakpoints to free their memory */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ /* close any tracefiles */
+ if (debug_cpuinfo[cpunum].trace.file)
+ fclose(debug_cpuinfo[cpunum].trace.file);
+ if (debug_cpuinfo[cpunum].trace.action)
+ free(debug_cpuinfo[cpunum].trace.action);
+
+ /* free the symbol table */
+ if (debug_cpuinfo[cpunum].symtable)
+ symtable_free(debug_cpuinfo[cpunum].symtable);
+
+ /* free all breakpoints */
+ while (debug_cpuinfo[cpunum].first_bp)
+ debug_breakpoint_clear(debug_cpuinfo[cpunum].first_bp->index);
+
+ /* loop over all address spaces */
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ {
+ /* free all watchpoints */
+ while (debug_cpuinfo[cpunum].space[spacenum].first_wp)
+ debug_watchpoint_clear(debug_cpuinfo[cpunum].space[spacenum].first_wp->index);
+ }
+ }
+
+ /* free the global symbol table */
+ if (global_symtable)
+ symtable_free(global_symtable);
+}
+
+
+
+/***************************************************************************
+ EXECUTION CONTROL
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_cpu_single_step - single step past the
+ requested number of instructions
+-------------------------------------------------*/
+
+void debug_cpu_single_step(int numsteps)
+{
+ if (!within_debugger_code)
+ return;
+ steps_until_stop = numsteps;
+ execution_state = EXECUTION_STATE_STEP_INTO;
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_single_step_over - single step over
+ a single instruction
+-------------------------------------------------*/
+
+void debug_cpu_single_step_over(int numsteps)
+{
+ if (!within_debugger_code)
+ return;
+ steps_until_stop = numsteps;
+ step_overout_cpunum = cpu_getactivecpu();
+ execution_state = EXECUTION_STATE_STEP_OVER;
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_single_step_out - single step out of
+ the current function
+-------------------------------------------------*/
+
+void debug_cpu_single_step_out(void)
+{
+ if (!within_debugger_code)
+ return;
+ steps_until_stop = 100;
+ step_overout_cpunum = cpu_getactivecpu();
+ execution_state = EXECUTION_STATE_STEP_OUT;
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_go - resume execution
+-------------------------------------------------*/
+
+void debug_cpu_go(offs_t targetpc)
+{
+ if (!within_debugger_code)
+ return;
+ execution_state = EXECUTION_STATE_RUNNING;
+ debug_cpuinfo[cpu_getactivecpu()].temp_breakpoint_pc = targetpc;
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_go_vblank - run until the next
+ VBLANK
+-------------------------------------------------*/
+
+void debug_cpu_go_vblank(void)
+{
+ if (!within_debugger_code)
+ return;
+ execution_state = EXECUTION_STATE_RUNNING;
+ debug_cpuinfo[cpu_getactivecpu()].temp_breakpoint_pc = ~0;
+ break_on_vblank = 1;
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_go_interrupt - run until the
+ specified interrupt fires
+-------------------------------------------------*/
+
+void debug_cpu_go_interrupt(int irqline)
+{
+ if (!within_debugger_code)
+ return;
+ execution_state = EXECUTION_STATE_RUNNING;
+ debug_cpuinfo[cpu_getactivecpu()].temp_breakpoint_pc = ~0;
+ break_on_interrupt = 1;
+ break_on_interrupt_cpunum = cpu_getactivecpu();
+ break_on_interrupt_irqline = irqline;
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_go_milliseconds - run until the
+ specified delay elapses
+-------------------------------------------------*/
+
+void debug_cpu_go_milliseconds(UINT64 milliseconds)
+{
+ if (!within_debugger_code)
+ return;
+ execution_state = EXECUTION_STATE_RUNNING;
+ debug_cpuinfo[cpu_getactivecpu()].temp_breakpoint_pc = ~0;
+ break_on_time = 1;
+ break_on_time_target = attotime_add(
+ timer_get_time(),
+ attotime_make(milliseconds / 1000, (milliseconds % 1000) * (ATTOSECONDS_PER_SECOND / 1000)));
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_next_cpu - execute until we hit
+ the next CPU
+-------------------------------------------------*/
+
+void debug_cpu_next_cpu(void)
+{
+ if (!within_debugger_code)
+ return;
+ execution_state = EXECUTION_STATE_NEXT_CPU;
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_ignore_cpu - ignore/observe a given
+ CPU
+-------------------------------------------------*/
+
+void debug_cpu_ignore_cpu(int cpunum, int ignore)
+{
+ debug_cpuinfo[cpunum].ignoring = ignore;
+ if (!within_debugger_code)
+ return;
+ if (cpunum == cpu_getactivecpu() && debug_cpuinfo[cpunum].ignoring)
+ execution_state = EXECUTION_STATE_NEXT_CPU;
+}
+
+
+/*-------------------------------------------------
+ debug_cpu_trace - trace execution of a given
+ CPU
+-------------------------------------------------*/
+
+void debug_cpu_trace(int cpunum, FILE *file, int trace_over, const char *action)
+{
+ /* close existing files and delete expressions */
+ if (debug_cpuinfo[cpunum].trace.file)
+ fclose(debug_cpuinfo[cpunum].trace.file);
+ debug_cpuinfo[cpunum].trace.file = NULL;
+
+ if (debug_cpuinfo[cpunum].trace.action)
+ free(debug_cpuinfo[cpunum].trace.action);
+ debug_cpuinfo[cpunum].trace.action = NULL;
+
+ /* open any new files */
+ debug_cpuinfo[cpunum].trace.file = file;
+ debug_cpuinfo[cpunum].trace.action = NULL;
+ if (action)
+ {
+ debug_cpuinfo[cpunum].trace.action = malloc(strlen(action) + 1);
+ if (debug_cpuinfo[cpunum].trace.action)
+ strcpy(debug_cpuinfo[cpunum].trace.action, action);
+ }
+
+ /* specify trace over */
+ debug_cpuinfo[cpunum].trace.trace_over_target = trace_over ? ~0 : 0;
+}
+
+
+
+/***************************************************************************
+ UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_get_cpu_info - returns the cpu info
+ block for a given CPU
+-------------------------------------------------*/
+
+const debug_cpu_info *debug_get_cpu_info(int cpunum)
+{
+ return &debug_cpuinfo[cpunum];
+}
+
+
+/*-------------------------------------------------
+ debug_halt_on_next_instruction - halt in
+ the debugger on the next instruction
+-------------------------------------------------*/
+
+void debug_halt_on_next_instruction(void)
+{
+ debug_console_printf("Internal breakpoint\n");
+ execution_state = EXECUTION_STATE_STOPPED;
+}
+
+
+/*-------------------------------------------------
+ debug_refresh_display - redraw the current
+ video display
+-------------------------------------------------*/
+
+void debug_refresh_display(void)
+{
+ video_frame_update();
+}
+
+
+/*-------------------------------------------------
+ debug_get_execution_state - return the
+ current execution state
+-------------------------------------------------*/
+
+int debug_get_execution_state(void)
+{
+ return execution_state;
+}
+
+
+/*-------------------------------------------------
+ debug_get_execution_counter - return the
+ current execution counter
+-------------------------------------------------*/
+
+UINT32 debug_get_execution_counter(void)
+{
+ return execution_counter;
+}
+
+
+/*-------------------------------------------------
+ get_wpaddr - getter callback for the
+ 'wpaddr' symbol
+-------------------------------------------------*/
+
+static UINT64 get_wpaddr(UINT32 ref)
+{
+ return wpaddr;
+}
+
+
+/*-------------------------------------------------
+ get_wpdata - getter callback for the
+ 'wpdata' symbol
+-------------------------------------------------*/
+
+static UINT64 get_wpdata(UINT32 ref)
+{
+ return wpdata;
+}
+
+
+/*-------------------------------------------------
+ get_cycles - getter callback for the
+ 'cycles' symbol
+-------------------------------------------------*/
+
+static UINT64 get_cycles(UINT32 ref)
+{
+ return activecpu_get_icount();
+}
+
+
+/*-------------------------------------------------
+ get_cpunum - getter callback for the
+ 'cpunum' symbol
+-------------------------------------------------*/
+
+static UINT64 get_cpunum(UINT32 ref)
+{
+ return cpu_getactivecpu();
+}
+
+
+/*-------------------------------------------------
+ get_tempvar - getter callback for the
+ 'tempX' symbols
+-------------------------------------------------*/
+
+static UINT64 get_tempvar(UINT32 ref)
+{
+ return tempvar[ref];
+}
+
+
+/*-------------------------------------------------
+ set_tempvar - setter callback for the
+ 'tempX' symbols
+-------------------------------------------------*/
+
+static void set_tempvar(UINT32 ref, UINT64 value)
+{
+ tempvar[ref] = value;
+}
+
+
+/*-------------------------------------------------
+ get_logunmap - getter callback for the logumap
+ symbols
+-------------------------------------------------*/
+
+static UINT64 get_logunmap(UINT32 ref)
+{
+ return memory_get_log_unmap(ref);
+}
+
+
+/*-------------------------------------------------
+ get_beamx - get beam horizontal position
+-------------------------------------------------*/
+
+static UINT64 get_beamx(UINT32 ref)
+{
+ return video_screen_get_hpos(ref);
+}
+
+
+/*-------------------------------------------------
+ get_beamy - get beam vertical position
+-------------------------------------------------*/
+
+static UINT64 get_beamy(UINT32 ref)
+{
+ return video_screen_get_vpos(ref);
+}
+
+
+/*-------------------------------------------------
+ set_logunmap - setter callback for the logumap
+ symbols
+-------------------------------------------------*/
+
+static void set_logunmap(UINT32 ref, UINT64 value)
+{
+ memory_set_log_unmap(ref, value ? 1 : 0);
+}
+
+
+/*-------------------------------------------------
+ get_current_pc - getter callback for a CPU's
+ current instruction pointer
+-------------------------------------------------*/
+
+static UINT64 get_current_pc(UINT32 ref)
+{
+ return activecpu_get_pc();
+}
+
+
+/*-------------------------------------------------
+ get_cpu_reg - getter callback for a CPU's
+ register symbols
+-------------------------------------------------*/
+
+static UINT64 get_cpu_reg(UINT32 ref)
+{
+ return activecpu_get_reg(ref);
+}
+
+
+/*-------------------------------------------------
+ set_cpu_reg - setter callback for a CPU's
+ register symbols
+-------------------------------------------------*/
+
+static void set_cpu_reg(UINT32 ref, UINT64 value)
+{
+ activecpu_set_reg(ref, value);
+}
+
+
+
+/***************************************************************************
+ MAIN CPU CALLBACK
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_debug_hook - called by the CPU cores
+ before executing each instruction
+-------------------------------------------------*/
+
+void mame_debug_hook(void)
+{
+ int cpunum = cpu_getactivecpu();
+ offs_t curpc = activecpu_get_pc();
+ debug_cpu_info *info = &debug_cpuinfo[cpunum];
+
+ /* update the history */
+ info->pc_history[info->pc_history_index++ % DEBUG_HISTORY_SIZE] = curpc;
+
+ /* quick out if we are ignoring */
+ if (info->ignoring)
+ return;
+
+ /* note that we are in the debugger code */
+ within_debugger_code = TRUE;
+
+ /* bump the counter */
+ execution_counter++;
+
+ /* are we tracing? */
+ if (info->trace.file)
+ perform_trace(info);
+
+ /* per-instruction hook? */
+ if (info->instrhook != NULL && (*info->instrhook)(curpc))
+ execution_state = EXECUTION_STATE_STOPPED;
+
+ /* check for execution breakpoints */
+ if (execution_state != EXECUTION_STATE_STOPPED)
+ {
+ /* see if we hit an interrupt break */
+ if (break_on_interrupt == 2 && break_on_interrupt_cpunum == cpunum)
+ {
+ debug_console_printf("Stopped on interrupt (CPU %d, IRQ %d)\n", break_on_interrupt_cpunum, break_on_interrupt_irqline);
+ break_on_interrupt = 0;
+ execution_state = EXECUTION_STATE_STOPPED;
+ }
+
+ /* see if we hit a target time */
+ if (break_on_time && attotime_compare(timer_get_time(), break_on_time_target) > 0)
+ {
+ debug_console_printf("Stopped at time interval %.1g\n", attotime_to_double(timer_get_time()));
+ break_on_time = 0;
+ execution_state = EXECUTION_STATE_STOPPED;
+ }
+
+ /* see if the CPU changed and break if we are waiting for that to happen */
+ if (cpunum != last_cpunum)
+ {
+ if (execution_state == EXECUTION_STATE_NEXT_CPU)
+ execution_state = EXECUTION_STATE_STOPPED;
+ last_cpunum = cpunum;
+ }
+
+ /* check the temp running breakpoint and break if we hit it */
+ if (info->temp_breakpoint_pc != ~0 && execution_state == EXECUTION_STATE_RUNNING && curpc == info->temp_breakpoint_pc)
+ {
+ execution_state = EXECUTION_STATE_STOPPED;
+ debug_console_printf("Stopped at temporary breakpoint %X on CPU %d\n", info->temp_breakpoint_pc, cpunum);
+ info->temp_breakpoint_pc = ~0;
+ }
+
+ /* check for execution breakpoints */
+ if (info->first_bp)
+ debug_check_breakpoints(cpunum, curpc);
+
+ /* handle single stepping */
+ if (steps_until_stop > 0 && (execution_state >= EXECUTION_STATE_STEP_INTO && execution_state <= EXECUTION_STATE_STEP_OUT))
+ {
+ /* is this an actual step? */
+ if (step_overout_breakpoint == ~0 || (cpunum == step_overout_cpunum && curpc == step_overout_breakpoint))
+ {
+ /* decrement the count and reset the breakpoint */
+ steps_until_stop--;
+ step_overout_breakpoint = ~0;
+
+ /* if we hit 0, stop; otherwise, we might want to update everything */
+ if (steps_until_stop == 0)
+ execution_state = EXECUTION_STATE_STOPPED;
+ else if (execution_state != EXECUTION_STATE_STEP_OUT && (steps_until_stop < 200 || steps_until_stop % 100 == 0))
+ {
+ debug_view_update_all();
+ debug_refresh_display();
+ }
+ }
+ }
+
+ /* check for debug keypresses */
+ if (execution_state != EXECUTION_STATE_STOPPED && ++key_check_counter > 10000)
+ {
+ key_check_counter = 0;
+ if (input_ui_pressed(IPT_UI_DEBUG_BREAK))
+ {
+ execution_state = EXECUTION_STATE_STOPPED;
+ debug_console_printf("User-initiated break\n");
+ }
+
+ /* while we're here, check for a periodic update */
+ if (cpunum == last_stopped_cpunum && execution_state != EXECUTION_STATE_STOPPED && osd_ticks() > last_periodic_update_time + osd_ticks_per_second()/4)
+ {
+ debug_view_update_all();
+ last_periodic_update_time = osd_ticks();
+ }
+ }
+ }
+
+ /* if we are supposed to halt, do it now */
+ if (execution_state == EXECUTION_STATE_STOPPED)
+ {
+ /* reset the state */
+ steps_until_stop = 0;
+ step_overout_breakpoint = ~0;
+
+ /* update all views */
+ debug_view_update_all();
+ debug_refresh_display();
+
+ /* wait for the debugger; during this time, disable sound output */
+ sound_mute(TRUE);
+ while (execution_state == EXECUTION_STATE_STOPPED)
+ {
+ /* clear the memory modified flag and wait */
+ memory_modified = 0;
+ osd_wait_for_debugger();
+
+ /* if something modified memory, update the screen */
+ if (memory_modified)
+ debug_refresh_display();
+
+ /* check for commands in the source file */
+ process_source_file();
+
+ /* if an event got scheduled, resume */
+ if (mame_is_scheduled_event_pending(Machine))
+ execution_state = EXECUTION_STATE_RUNNING;
+ }
+ sound_mute(FALSE);
+
+ /* remember the last cpunum where we stopped */
+ last_stopped_cpunum = cpunum;
+ }
+
+ /* handle step out/over on the instruction we are about to execute */
+ if ((execution_state == EXECUTION_STATE_STEP_OVER || execution_state == EXECUTION_STATE_STEP_OUT) && cpunum == step_overout_cpunum && step_overout_breakpoint == ~0)
+ prepare_for_step_overout();
+
+ /* no longer in debugger code */
+ within_debugger_code = FALSE;
+}
+
+
+/*-------------------------------------------------
+ perform_trace - log to the tracefile the
+ data for a given instruction
+-------------------------------------------------*/
+
+static UINT32 dasm_wrapped(char *buffer, offs_t pc)
+{
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(cpu_getactivecpu());
+ int maxbytes = activecpu_max_instruction_bytes();
+ UINT8 opbuf[64], argbuf[64];
+ offs_t pcbyte;
+ int numbytes;
+
+ /* fetch the bytes up to the maximum */
+ pcbyte = ADDR2BYTE_MASKED(pc, cpuinfo, ADDRESS_SPACE_PROGRAM);
+ for (numbytes = 0; numbytes < maxbytes; numbytes++)
+ {
+ opbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, FALSE);
+ argbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, TRUE);
+ }
+
+ return activecpu_dasm(buffer, pc, opbuf, argbuf);
+}
+
+
+static void perform_trace(debug_cpu_info *info)
+{
+ offs_t pc = activecpu_get_pc();
+ int offset, count, i;
+ char buffer[100];
+ offs_t dasmresult;
+
+ /* are we in trace over mode and in a subroutine? */
+ if (info->trace.trace_over_target && (info->trace.trace_over_target != ~0))
+ {
+ if (info->trace.trace_over_target != pc)
+ return;
+ info->trace.trace_over_target = ~0;
+ }
+
+ /* check for a loop condition */
+ for (i = count = 0; i < TRACE_LOOPS; i++)
+ if (info->trace.history[i] == pc)
+ count++;
+
+ /* if no more than 1 hit, process normally */
+ if (count <= 1)
+ {
+ /* if we just finished looping, indicate as much */
+ if (info->trace.loops)
+ fprintf(info->trace.file, "\n (loops for %d instructions)\n\n", info->trace.loops);
+ info->trace.loops = 0;
+
+ /* execute any trace actions first */
+ if (info->trace.action)
+ debug_console_execute_command(info->trace.action, 0);
+
+ /* print the address */
+ offset = sprintf(buffer, "%0*X: ", info->space[ADDRESS_SPACE_PROGRAM].logchars, pc);
+
+ /* print the disassembly */
+ dasmresult = dasm_wrapped(&buffer[offset], pc);
+
+ /* output the result */
+ fprintf(info->trace.file, "%s\n", buffer);
+
+ /* do we need to step the trace over this instruction? */
+ if (info->trace.trace_over_target && (dasmresult & DASMFLAG_SUPPORTED)
+ && (dasmresult & DASMFLAG_STEP_OVER))
+ {
+ int extraskip = (dasmresult & DASMFLAG_OVERINSTMASK) >> DASMFLAG_OVERINSTSHIFT;
+ offs_t trace_over_target = pc + (dasmresult & DASMFLAG_LENGTHMASK);
+
+ /* if we need to skip additional instructions, advance as requested */
+ while (extraskip-- > 0)
+ trace_over_target += dasm_wrapped(buffer, trace_over_target) & DASMFLAG_LENGTHMASK;
+
+ info->trace.trace_over_target = trace_over_target;
+ }
+
+ /* log this PC */
+ info->trace.nextdex = (info->trace.nextdex + 1) % TRACE_LOOPS;
+ info->trace.history[info->trace.nextdex] = pc;
+ }
+
+ /* else just count the loop */
+ else
+ info->trace.loops++;
+}
+
+
+/*-------------------------------------------------
+ prepare_for_step_overout - prepare things for
+ stepping over an instruction
+-------------------------------------------------*/
+
+static void prepare_for_step_overout(void)
+{
+ offs_t pc = activecpu_get_pc();
+ char dasmbuffer[100];
+ offs_t dasmresult;
+
+ /* disassemble the current instruction and get the flags */
+ dasmresult = dasm_wrapped(dasmbuffer, pc);
+
+ /* if flags are supported and it's a call-style opcode, set a temp breakpoint after that instruction */
+ if ((dasmresult & DASMFLAG_SUPPORTED) && (dasmresult & DASMFLAG_STEP_OVER))
+ {
+ int extraskip = (dasmresult & DASMFLAG_OVERINSTMASK) >> DASMFLAG_OVERINSTSHIFT;
+ pc += dasmresult & DASMFLAG_LENGTHMASK;
+
+ /* if we need to skip additional instructions, advance as requested */
+ while (extraskip-- > 0)
+ pc += dasm_wrapped(dasmbuffer, pc) & DASMFLAG_LENGTHMASK;
+ step_overout_breakpoint = pc;
+ }
+
+ /* if we're stepping out and this isn't a step out instruction, reset the steps until stop to a high number */
+ if (execution_state == EXECUTION_STATE_STEP_OUT)
+ {
+ if ((dasmresult & DASMFLAG_SUPPORTED) && !(dasmresult & DASMFLAG_STEP_OUT))
+ steps_until_stop = 100;
+ else
+ steps_until_stop = 1;
+ }
+}
+
+
+/*-------------------------------------------------
+ process_source_file - executes commands from
+ a source file
+-------------------------------------------------*/
+
+static void process_source_file(void)
+{
+ /* loop until the file is exhausted or until we are executing again */
+ while (debug_source_file && (execution_state == EXECUTION_STATE_STOPPED))
+ {
+ char buf[512];
+ int i;
+ char *s;
+
+ /* stop at the end of file */
+ if (feof(debug_source_file))
+ {
+ fclose(debug_source_file);
+ debug_source_file = NULL;
+ return;
+ }
+
+ /* fetch the next line */
+ memset(buf, 0, sizeof(buf));
+ fgets(buf, sizeof(buf), debug_source_file);
+
+ /* strip out comments (text after '//') */
+ s = strstr(buf, "//");
+ if (s)
+ *s = '\0';
+
+ /* strip whitespace */
+ i = (int)strlen(buf);
+ while((i > 0) && (isspace(buf[i-1])))
+ buf[--i] = '\0';
+
+ /* execute the command */
+ if (buf[0])
+ debug_console_execute_command(buf, 1);
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_vblank_hook - called when the real
+ VBLANK hits
+-------------------------------------------------*/
+
+void debug_vblank_hook(void)
+{
+ /* if we're configured to stop on VBLANK, break */
+ if (break_on_vblank)
+ {
+ execution_state = EXECUTION_STATE_STOPPED;
+ debug_console_printf("Stopped at VBLANK\n");
+ break_on_vblank = 0;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_vblank_hook - called when an interrupt
+ is acknowledged
+-------------------------------------------------*/
+
+void debug_interrupt_hook(int cpunum, int irqline)
+{
+ /* if we're configured to stop on interrupt, break */
+ if (break_on_interrupt && cpunum == break_on_interrupt_cpunum && (break_on_interrupt_irqline == -1 || irqline == break_on_interrupt_irqline))
+ {
+ break_on_interrupt = 2;
+ break_on_interrupt_irqline = irqline;
+ }
+}
+
+
+/*-------------------------------------------------
+ standard_debug_hook_read - standard read hook
+-------------------------------------------------*/
+
+static void standard_debug_hook_read(int spacenum, int size, offs_t address)
+{
+ debug_cpu_info *info = &debug_cpuinfo[memory_hook_cpunum];
+
+ /* check watchpoints */
+ if (info->read_watchpoints)
+ check_watchpoints(memory_hook_cpunum, spacenum, WATCHPOINT_READ, address, size, 0);
+
+ /* check hotspots */
+ if (info->hotspots)
+ check_hotspots(memory_hook_cpunum, spacenum, address);
+}
+
+
+/*-------------------------------------------------
+ standard_debug_hook_write - standard write hook
+-------------------------------------------------*/
+
+static void standard_debug_hook_write(int spacenum, int size, offs_t address, UINT64 data)
+{
+ debug_cpu_info *info = &debug_cpuinfo[memory_hook_cpunum];
+
+ /* check watchpoints */
+ if (info->write_watchpoints)
+ check_watchpoints(memory_hook_cpunum, spacenum, WATCHPOINT_WRITE, address, size, data);
+}
+
+
+/*-------------------------------------------------
+ debug_get_memory_hooks - get memory hooks
+ for the specified CPU
+-------------------------------------------------*/
+
+void debug_get_memory_hooks(int cpunum, debug_hook_read_ptr *read, debug_hook_write_ptr *write)
+{
+ memory_hook_cpunum = cpunum;
+
+ if (debug_cpuinfo[cpunum].read_watchpoints || debug_cpuinfo[cpunum].hotspots)
+ *read = standard_debug_hook_read;
+ else
+ *read = NULL;
+
+ if (debug_cpuinfo[cpunum].write_watchpoints)
+ *write = standard_debug_hook_write;
+ else
+ *write = NULL;
+}
+
+
+/*-------------------------------------------------
+ debug_set_instruction_hook - set a hook to
+ be called on each instruction for a given CPU
+-------------------------------------------------*/
+
+void debug_set_instruction_hook(int cpunum, int (*hook)(offs_t pc))
+{
+ debug_cpuinfo[cpunum].instrhook = hook;
+}
+
+
+
+/***************************************************************************
+ BREAKPOINTS
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_check_breakpoints - check the
+ breakpoints for a given CPU
+-------------------------------------------------*/
+
+void debug_check_breakpoints(int cpunum, offs_t pc)
+{
+ debug_cpu_breakpoint *bp;
+ UINT64 result;
+
+ /* see if we match */
+ for (bp = debug_cpuinfo[cpunum].first_bp; bp; bp = bp->next)
+ if (bp->enabled && bp->address == pc)
+
+ /* if we do, evaluate the condition */
+ if (bp->condition == NULL || (expression_execute(bp->condition, &result) == EXPRERR_NONE && result))
+ {
+ /* halt in the debugger by default */
+ execution_state = EXECUTION_STATE_STOPPED;
+
+ /* if we hit, evaluate the action */
+ if (bp->action != NULL)
+ debug_console_execute_command(bp->action, 0);
+
+ /* print a notification, unless the action made us go again */
+ if (execution_state == EXECUTION_STATE_STOPPED)
+ debug_console_printf("Stopped at breakpoint %X\n", bp->index);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_breakpoint_first - find the first
+ breakpoint for a given CPU
+-------------------------------------------------*/
+
+static debug_cpu_breakpoint *find_breakpoint(int bpnum)
+{
+ debug_cpu_breakpoint *bp;
+ int cpunum;
+
+ /* loop over CPUs and find the requested breakpoint */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ for (bp = debug_cpuinfo[cpunum].first_bp; bp; bp = bp->next)
+ if (bp->index == bpnum)
+ return bp;
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ debug_breakpoint_first - return the first
+ breakpoint for a given CPU
+-------------------------------------------------*/
+
+debug_cpu_breakpoint *debug_breakpoint_first(int cpunum)
+{
+ return (cpunum < MAX_CPU) ? debug_cpuinfo[cpunum].first_bp : NULL;
+}
+
+
+/*-------------------------------------------------
+ debug_breakpoint_set - set a new breakpoint
+-------------------------------------------------*/
+
+int debug_breakpoint_set(int cpunum, offs_t address, parsed_expression *condition, const char *action)
+{
+ debug_cpu_breakpoint *bp;
+
+ assert_always((cpunum >= 0) && (cpunum < cpu_gettotalcpu()), "debug_breakpoint_set() called with invalid cpunum!");
+
+ /* allocate breakpoint */
+ bp = malloc(sizeof(*bp));
+
+ /* if we can't allocate, return failure */
+ if (!bp)
+ return 0;
+
+ /* fill in the structure */
+ bp->index = next_index++;
+ bp->enabled = 1;
+ bp->address = address;
+ bp->condition = condition;
+ bp->action = NULL;
+ if (action)
+ {
+ bp->action = malloc(strlen(action) + 1);
+ if (bp->action)
+ strcpy(bp->action, action);
+ }
+
+ /* hook us in */
+ bp->next = debug_cpuinfo[cpunum].first_bp;
+ debug_cpuinfo[cpunum].first_bp = bp;
+ return bp->index;
+}
+
+
+/*-------------------------------------------------
+ debug_breakpoint_clear - clear a breakpoint
+-------------------------------------------------*/
+
+int debug_breakpoint_clear(int bpnum)
+{
+ debug_cpu_breakpoint *bp, *pbp;
+ int cpunum;
+
+ /* loop over CPUs and find the requested breakpoint */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ for (pbp = NULL, bp = debug_cpuinfo[cpunum].first_bp; bp; pbp = bp, bp = bp->next)
+ if (bp->index == bpnum)
+ {
+ /* unlink us from the list */
+ if (pbp == NULL)
+ debug_cpuinfo[cpunum].first_bp = bp->next;
+ else
+ pbp->next = bp->next;
+
+ /* free the memory */
+ if (bp->condition)
+ expression_free(bp->condition);
+ if (bp->action)
+ free(bp->action);
+ free(bp);
+ return 1;
+ }
+
+ /* we didn't find it; return an error */
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ debug_breakpoint_enable - enable/disable a
+ breakpoint
+-------------------------------------------------*/
+
+int debug_breakpoint_enable(int bpnum, int enable)
+{
+ debug_cpu_breakpoint *bp = find_breakpoint(bpnum);
+
+ /* if we found it, set it */
+ if (bp != NULL)
+ {
+ bp->enabled = (enable != 0);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+/***************************************************************************
+ WATCHPOINTS
+***************************************************************************/
+
+/*-------------------------------------------------
+ check_watchpoints - check the
+ breakpoints for a given CPU and address space
+-------------------------------------------------*/
+
+static void check_watchpoints(int cpunum, int spacenum, int type, offs_t address, offs_t size, UINT64 value_to_write)
+{
+ debug_cpu_watchpoint *wp;
+ UINT64 result;
+
+ /* if we're within debugger code, don't stop */
+ if (within_debugger_code)
+ return;
+
+ within_debugger_code = TRUE;
+
+ /* if we are a write watchpoint, stash the value that will be written */
+ wpaddr = address;
+ if (type & WATCHPOINT_WRITE)
+ wpdata = value_to_write;
+
+ /* see if we match */
+ for (wp = debug_cpuinfo[cpunum].space[spacenum].first_wp; wp; wp = wp->next)
+ if (wp->enabled && (wp->type & type) && address + size > wp->address && address < wp->address + wp->length)
+
+ /* if we do, evaluate the condition */
+ if (wp->condition == NULL || (expression_execute(wp->condition, &result) == EXPRERR_NONE && result))
+ {
+ static const char *sizes[] =
+ {
+ "0bytes", "byte", "word", "3bytes", "dword", "5bytes", "6bytes", "7bytes", "qword"
+ };
+ char buffer[100];
+
+ /* halt in the debugger by default */
+ execution_state = EXECUTION_STATE_STOPPED;
+
+ /* if we hit, evaluate the action */
+ if (wp->action != NULL)
+ debug_console_execute_command(wp->action, 0);
+
+ /* print a notification, unless the action made us go again */
+ if (execution_state == EXECUTION_STATE_STOPPED)
+ {
+ if (type & WATCHPOINT_WRITE)
+ {
+ sprintf(buffer, "Stopped at watchpoint %X writing %s to %08X (PC=%X)", wp->index, sizes[size], BYTE2ADDR(address, &debug_cpuinfo[cpunum], spacenum), activecpu_get_pc());
+ if (value_to_write >> 32)
+ sprintf(&buffer[strlen(buffer)], " (data=%X%08X)", (UINT32)(value_to_write >> 32), (UINT32)value_to_write);
+ else
+ sprintf(&buffer[strlen(buffer)], " (data=%X)", (UINT32)value_to_write);
+ }
+ else
+ sprintf(buffer, "Stopped at watchpoint %X reading %s from %08X (PC=%X)", wp->index, sizes[size], BYTE2ADDR(address, &debug_cpuinfo[cpunum], spacenum), activecpu_get_pc());
+ debug_console_printf("%s\n", buffer);
+ }
+ break;
+ }
+
+ within_debugger_code = FALSE;
+}
+
+
+/*-------------------------------------------------
+ debug_watchpoint_first - find the first
+ watchpoint for a given CPU
+-------------------------------------------------*/
+
+static debug_cpu_watchpoint *find_watchpoint(int wpnum)
+{
+ debug_cpu_watchpoint *wp;
+ int cpunum, spacenum;
+
+ /* loop over CPUs and address spaces and find the requested watchpoint */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ for (wp = debug_cpuinfo[cpunum].space[spacenum].first_wp; wp; wp = wp->next)
+ if (wp->index == wpnum)
+ return wp;
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ debug_watchpoint_first - return the first
+ watchpoint for a given CPU
+-------------------------------------------------*/
+
+debug_cpu_watchpoint *debug_watchpoint_first(int cpunum, int spacenum)
+{
+ return (cpunum < MAX_CPU && spacenum < ADDRESS_SPACES) ? debug_cpuinfo[cpunum].space[spacenum].first_wp : NULL;
+}
+
+
+/*-------------------------------------------------
+ debug_watchpoint_set - set a new watchpoint
+-------------------------------------------------*/
+
+int debug_watchpoint_set(int cpunum, int spacenum, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action)
+{
+ debug_cpu_watchpoint *wp = malloc(sizeof(*wp));
+
+ /* if we can't allocate, return failure */
+ if (!wp)
+ return 0;
+
+ /* fill in the structure */
+ wp->index = next_index++;
+ wp->enabled = 1;
+ wp->type = type;
+ wp->address = ADDR2BYTE_MASKED(address, &debug_cpuinfo[cpunum], spacenum);
+ wp->length = ADDR2BYTE(length, &debug_cpuinfo[cpunum], spacenum);
+ wp->condition = condition;
+ wp->action = NULL;
+ if (action)
+ {
+ wp->action = malloc(strlen(action) + 1);
+ if (wp->action)
+ strcpy(wp->action, action);
+ }
+
+ /* hook us in */
+ wp->next = debug_cpuinfo[cpunum].space[spacenum].first_wp;
+ debug_cpuinfo[cpunum].space[spacenum].first_wp = wp;
+ if (wp->type & WATCHPOINT_READ)
+ debug_cpuinfo[cpunum].read_watchpoints++;
+ if (wp->type & WATCHPOINT_WRITE)
+ debug_cpuinfo[cpunum].write_watchpoints++;
+
+ /* force debug_get_memory_hooks() to be called */
+ cpuintrf_push_context(-1);
+ cpuintrf_pop_context();
+
+ return wp->index;
+}
+
+
+/*-------------------------------------------------
+ debug_watchpoint_clear - clear a watchpoint
+-------------------------------------------------*/
+
+int debug_watchpoint_clear(int wpnum)
+{
+ debug_cpu_watchpoint *wp, *pwp;
+ int cpunum, spacenum;
+
+ /* loop over CPUs and find the requested watchpoint */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ for (pwp = NULL, wp = debug_cpuinfo[cpunum].space[spacenum].first_wp; wp; pwp = wp, wp = wp->next)
+ if (wp->index == wpnum)
+ {
+ /* unlink us from the list */
+ if (pwp == NULL)
+ debug_cpuinfo[cpunum].space[spacenum].first_wp = wp->next;
+ else
+ pwp->next = wp->next;
+
+ /* free the memory */
+ if (wp->condition)
+ expression_free(wp->condition);
+ if (wp->action)
+ free(wp->action);
+ if (wp->type & WATCHPOINT_READ)
+ debug_cpuinfo[cpunum].read_watchpoints--;
+ if (wp->type & WATCHPOINT_WRITE)
+ debug_cpuinfo[cpunum].write_watchpoints--;
+ free(wp);
+
+ /* force debug_get_memory_hooks() to be called */
+ cpuintrf_push_context(-1);
+ cpuintrf_pop_context();
+
+ return 1;
+ }
+
+ /* we didn't find it; return an error */
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ debug_watchpoint_enable - enable/disable a
+ watchpoint
+-------------------------------------------------*/
+
+int debug_watchpoint_enable(int wpnum, int enable)
+{
+ debug_cpu_watchpoint *wp = find_watchpoint(wpnum);
+
+ /* if we found it, set it */
+ if (wp != NULL)
+ {
+ wp->enabled = (enable != 0);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+/***************************************************************************
+ HOTSPOTS
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_hotspot_track - enable/disable tracking
+ of hotspots
+-------------------------------------------------*/
+
+int debug_hotspot_track(int cpunum, int numspots, int threshhold)
+{
+ debug_cpu_info *info = &debug_cpuinfo[cpunum];
+
+ /* if we already have tracking info, kill it */
+ if (info->hotspots)
+ free(info->hotspots);
+ info->hotspots = NULL;
+
+ /* only start tracking if we have a non-zero count */
+ if (numspots > 0)
+ {
+ /* allocate memory for hotspots */
+ info->hotspots = malloc_or_die(sizeof(*info->hotspots) * numspots);
+ memset(info->hotspots, 0xff, sizeof(*info->hotspots) * numspots);
+
+ /* fill in the info */
+ info->hotspot_count = numspots;
+ info->hotspot_threshhold = threshhold;
+ }
+
+ /* force debug_get_memory_hooks() to be called */
+ cpuintrf_push_context(-1);
+ cpuintrf_pop_context();
+
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ check_hotspots - check for
+ hotspots on a memory read access
+-------------------------------------------------*/
+
+static void check_hotspots(int cpunum, int spacenum, offs_t address)
+{
+ debug_cpu_info *info = &debug_cpuinfo[cpunum];
+ offs_t pc = activecpu_get_pc();
+ int hotindex;
+
+ /* see if we have a match in our list */
+ for (hotindex = 0; hotindex < info->hotspot_count; hotindex++)
+ if (info->hotspots[hotindex].access == address && info->hotspots[hotindex].pc == pc && info->hotspots[hotindex].spacenum == spacenum)
+ break;
+
+ /* if we didn't find any, make a new entry */
+ if (hotindex == info->hotspot_count)
+ {
+ /* if the bottom of the list is over the threshhold, print it */
+ debug_hotspot_entry *spot = &info->hotspots[info->hotspot_count - 1];
+ if (spot->count > info->hotspot_threshhold)
+ debug_console_printf("Hotspot @ %s %08X (PC=%08X) hit %d times (fell off bottom)\n", address_space_name[spot->spacenum], spot->access, spot->pc, spot->count);
+
+ /* move everything else down and insert this one at the top */
+ memmove(&info->hotspots[1], &info->hotspots[0], sizeof(info->hotspots[0]) * (info->hotspot_count - 1));
+ info->hotspots[0].access = address;
+ info->hotspots[0].pc = pc;
+ info->hotspots[0].spacenum = spacenum;
+ info->hotspots[0].count = 1;
+ }
+
+ /* if we did find one, increase the count and move it to the top */
+ else
+ {
+ info->hotspots[hotindex].count++;
+ if (hotindex != 0)
+ {
+ debug_hotspot_entry temp = info->hotspots[hotindex];
+ memmove(&info->hotspots[1], &info->hotspots[0], sizeof(info->hotspots[0]) * hotindex);
+ info->hotspots[0] = temp;
+ }
+ }
+}
+
+
+/***************************************************************************
+ MEMORY ACCESSORS
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_read_byte - return a byte from the
+ current cpu in the specified memory space
+-------------------------------------------------*/
+
+UINT8 debug_read_byte(int spacenum, offs_t address, int apply_translation)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+ UINT64 custom;
+ UINT8 result;
+
+ /* mask against the logical byte mask */
+ address &= info->space[spacenum].logbytemask;
+
+ /* all accesses from this point on are for the debugger */
+ memory_set_debugger_access(1);
+
+ /* translate if necessary; if not mapped, return 0xff */
+ if (apply_translation && info->translate != NULL && !(*info->translate)(spacenum, &address))
+ result = 0xff;
+
+ /* if there is a custom read handler, and it returns TRUE, use that value */
+ else if (info->read && (*info->read)(spacenum, address, 1, &custom))
+ result = custom;
+
+ /* otherwise, call the byte reading function for the translated address */
+ else
+ result = (*active_address_space[spacenum].accessors->read_byte)(address);
+
+ /* no longer accessing via the debugger */
+ memory_set_debugger_access(0);
+ return result;
+}
+
+
+/*-------------------------------------------------
+ debug_read_word - return a word from the
+ current cpu in the specified memory space
+-------------------------------------------------*/
+
+UINT16 debug_read_word(int spacenum, offs_t address, int apply_translation)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+ UINT64 custom;
+ UINT16 result;
+
+ /* mask against the logical byte mask */
+ address &= info->space[spacenum].logbytemask;
+
+ /* if this is misaligned read, or if there are no word readers, just read two bytes */
+ if ((address & 1) || !active_address_space[spacenum].accessors->read_word)
+ {
+ UINT8 byte0 = debug_read_byte(spacenum, address + 0, apply_translation);
+ UINT8 byte1 = debug_read_byte(spacenum, address + 1, apply_translation);
+
+ /* based on the endianness, the result is assembled differently */
+ if (debug_cpuinfo[cpu_getactivecpu()].endianness == CPU_IS_LE)
+ result = byte0 | (byte1 << 8);
+ else
+ result = byte1 | (byte0 << 8);
+ }
+
+ /* otherwise, this proceeds like the byte case */
+ else
+ {
+ /* all accesses from this point on are for the debugger */
+ memory_set_debugger_access(1);
+
+ /* translate if necessary; if not mapped, return 0xffff */
+ if (apply_translation && info->translate != NULL && !(*info->translate)(spacenum, &address))
+ result = 0xffff;
+
+ /* if there is a custom read handler, and it returns TRUE, use that value */
+ else if (info->read && (*info->read)(spacenum, address, 2, &custom))
+ result = custom;
+
+ /* otherwise, call the byte reading function for the translated address */
+ else
+ result = (*active_address_space[spacenum].accessors->read_word)(address);
+
+ /* no longer accessing via the debugger */
+ memory_set_debugger_access(0);
+ }
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ debug_read_dword - return a dword from the
+ current cpu in the specified memory space
+-------------------------------------------------*/
+
+UINT32 debug_read_dword(int spacenum, offs_t address, int apply_translation)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+ UINT64 custom;
+ UINT32 result;
+
+ /* mask against the logical byte mask */
+ address &= info->space[spacenum].logbytemask;
+
+ /* if this is misaligned read, or if there are no dword readers, just read two words */
+ if ((address & 3) || !active_address_space[spacenum].accessors->read_dword)
+ {
+ UINT16 word0 = debug_read_word(spacenum, address + 0, apply_translation);
+ UINT16 word1 = debug_read_word(spacenum, address + 2, apply_translation);
+
+ /* based on the endianness, the result is assembled differently */
+ if (debug_cpuinfo[cpu_getactivecpu()].endianness == CPU_IS_LE)
+ result = word0 | (word1 << 16);
+ else
+ result = word1 | (word0 << 16);
+ }
+
+ /* otherwise, this proceeds like the byte case */
+ else
+ {
+ /* all accesses from this point on are for the debugger */
+ memory_set_debugger_access(1);
+
+ /* translate if necessary; if not mapped, return 0xffffffff */
+ if (apply_translation && info->translate != NULL && !(*info->translate)(spacenum, &address))
+ result = 0xffffffff;
+
+ /* if there is a custom read handler, and it returns TRUE, use that value */
+ else if (info->read && (*info->read)(spacenum, address, 4, &custom))
+ result = custom;
+
+ /* otherwise, call the byte reading function for the translated address */
+ else
+ result = (*active_address_space[spacenum].accessors->read_dword)(address);
+
+ /* no longer accessing via the debugger */
+ memory_set_debugger_access(0);
+ }
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ debug_read_qword - return a qword from the
+ current cpu in the specified memory space
+-------------------------------------------------*/
+
+UINT64 debug_read_qword(int spacenum, offs_t address, int apply_translation)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+ UINT64 custom;
+ UINT64 result;
+
+ /* mask against the logical byte mask */
+ address &= info->space[spacenum].logbytemask;
+
+ /* if this is misaligned read, or if there are no qword readers, just read two dwords */
+ if ((address & 7) || !active_address_space[spacenum].accessors->read_qword)
+ {
+ UINT32 dword0 = debug_read_dword(spacenum, address + 0, apply_translation);
+ UINT32 dword1 = debug_read_dword(spacenum, address + 4, apply_translation);
+
+ /* based on the endianness, the result is assembled differently */
+ if (debug_cpuinfo[cpu_getactivecpu()].endianness == CPU_IS_LE)
+ result = dword0 | ((UINT64)dword1 << 32);
+ else
+ result = dword1 | ((UINT64)dword0 << 32);
+ }
+
+ /* otherwise, this proceeds like the byte case */
+ else
+ {
+ /* all accesses from this point on are for the debugger */
+ memory_set_debugger_access(1);
+
+ /* translate if necessary; if not mapped, return 0xffffffffffffffff */
+ if (apply_translation && info->translate != NULL && !(*info->translate)(spacenum, &address))
+ result = ~(UINT64)0;
+
+ /* if there is a custom read handler, and it returns TRUE, use that value */
+ else if (info->read && (*info->read)(spacenum, address, 8, &custom))
+ result = custom;
+
+ /* otherwise, call the byte reading function for the translated address */
+ else
+ result = (*active_address_space[spacenum].accessors->read_qword)(address);
+
+ /* no longer accessing via the debugger */
+ memory_set_debugger_access(0);
+ }
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ debug_write_byte - write a byte to the
+ current cpu in the specified memory space
+-------------------------------------------------*/
+
+void debug_write_byte(int spacenum, offs_t address, UINT8 data, int apply_translation)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+
+ /* mask against the logical byte mask */
+ address &= info->space[spacenum].logbytemask;
+
+ /* all accesses from this point on are for the debugger */
+ memory_set_debugger_access(1);
+
+ /* translate if necessary; if not mapped, we're done */
+ if (apply_translation && info->translate != NULL && !(*info->translate)(spacenum, &address))
+ ;
+
+ /* if there is a custom write handler, and it returns TRUE, use that */
+ else if (info->write && (*info->write)(spacenum, address, 1, data))
+ ;
+
+ /* otherwise, call the byte reading function for the translated address */
+ else
+ (*active_address_space[spacenum].accessors->write_byte)(address, data);
+
+ /* no longer accessing via the debugger */
+ memory_set_debugger_access(0);
+ memory_modified = 1;
+}
+
+
+/*-------------------------------------------------
+ debug_write_word - write a word to the
+ current cpu in the specified memory space
+-------------------------------------------------*/
+
+void debug_write_word(int spacenum, offs_t address, UINT16 data, int apply_translation)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+
+ /* mask against the logical byte mask */
+ address &= info->space[spacenum].logbytemask;
+
+ /* if this is a misaligned write, or if there are no word writers, just read two bytes */
+ if ((address & 1) || !active_address_space[spacenum].accessors->write_word)
+ {
+ if (debug_cpuinfo[cpu_getactivecpu()].endianness == CPU_IS_LE)
+ {
+ debug_write_byte(spacenum, address + 0, data >> 0, apply_translation);
+ debug_write_byte(spacenum, address + 1, data >> 8, apply_translation);
+ }
+ else
+ {
+ debug_write_byte(spacenum, address + 0, data >> 8, apply_translation);
+ debug_write_byte(spacenum, address + 1, data >> 0, apply_translation);
+ }
+ }
+
+ /* otherwise, this proceeds like the byte case */
+ else
+ {
+ /* all accesses from this point on are for the debugger */
+ memory_set_debugger_access(1);
+
+ /* translate if necessary; if not mapped, we're done */
+ if (apply_translation && info->translate && !(*info->translate)(spacenum, &address))
+ ;
+
+ /* if there is a custom write handler, and it returns TRUE, use that */
+ else if (info->write && (*info->write)(spacenum, address, 2, data))
+ ;
+
+ /* otherwise, call the byte reading function for the translated address */
+ else
+ (*active_address_space[spacenum].accessors->write_word)(address, data);
+
+ /* no longer accessing via the debugger */
+ memory_set_debugger_access(0);
+ memory_modified = 1;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_write_dword - write a dword to the
+ current cpu in the specified memory space
+-------------------------------------------------*/
+
+void debug_write_dword(int spacenum, offs_t address, UINT32 data, int apply_translation)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+
+ /* mask against the logical byte mask */
+ address &= info->space[spacenum].logbytemask;
+
+ /* if this is a misaligned write, or if there are no dword writers, just read two words */
+ if ((address & 3) || !active_address_space[spacenum].accessors->write_dword)
+ {
+ if (debug_cpuinfo[cpu_getactivecpu()].endianness == CPU_IS_LE)
+ {
+ debug_write_word(spacenum, address + 0, data >> 0, apply_translation);
+ debug_write_word(spacenum, address + 2, data >> 16, apply_translation);
+ }
+ else
+ {
+ debug_write_word(spacenum, address + 0, data >> 16, apply_translation);
+ debug_write_word(spacenum, address + 2, data >> 0, apply_translation);
+ }
+ }
+
+ /* otherwise, this proceeds like the byte case */
+ else
+ {
+ /* all accesses from this point on are for the debugger */
+ memory_set_debugger_access(1);
+
+ /* translate if necessary; if not mapped, we're done */
+ if (apply_translation && info->translate && !(*info->translate)(spacenum, &address))
+ ;
+
+ /* if there is a custom write handler, and it returns TRUE, use that */
+ else if (info->write && (*info->write)(spacenum, address, 4, data))
+ ;
+
+ /* otherwise, call the byte reading function for the translated address */
+ else
+ (*active_address_space[spacenum].accessors->write_dword)(address, data);
+
+ /* no longer accessing via the debugger */
+ memory_set_debugger_access(0);
+ memory_modified = 1;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_write_qword - write a qword to the
+ current cpu in the specified memory space
+-------------------------------------------------*/
+
+void debug_write_qword(int spacenum, offs_t address, UINT64 data, int apply_translation)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+
+ /* mask against the logical byte mask */
+ address &= info->space[spacenum].logbytemask;
+
+ /* if this is a misaligned write, or if there are no qword writers, just read two dwords */
+ if ((address & 7) || !active_address_space[spacenum].accessors->write_qword)
+ {
+ if (debug_cpuinfo[cpu_getactivecpu()].endianness == CPU_IS_LE)
+ {
+ debug_write_dword(spacenum, address + 0, data >> 0, apply_translation);
+ debug_write_dword(spacenum, address + 4, data >> 32, apply_translation);
+ }
+ else
+ {
+ debug_write_dword(spacenum, address + 0, data >> 32, apply_translation);
+ debug_write_dword(spacenum, address + 4, data >> 0, apply_translation);
+ }
+ }
+ /* otherwise, this proceeds like the byte case */
+ else
+ {
+ /* all accesses from this point on are for the debugger */
+ memory_set_debugger_access(1);
+
+ /* translate if necessary; if not mapped, we're done */
+ if (apply_translation && info->translate && !(*info->translate)(spacenum, &address))
+ ;
+
+ /* if there is a custom write handler, and it returns TRUE, use that */
+ else if (info->write && (*info->write)(spacenum, address, 8, data))
+ ;
+
+ /* otherwise, call the byte reading function for the translated address */
+ else
+ (*active_address_space[spacenum].accessors->write_qword)(address, data);
+
+ /* no longer accessing via the debugger */
+ memory_set_debugger_access(0);
+ memory_modified = 1;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_read_opcode - read 1,2,4 or 8 bytes at
+ the given offset from opcode space
+-------------------------------------------------*/
+
+UINT64 debug_read_opcode(offs_t address, int size, int arg)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+ offs_t lowbits_mask;
+ const void *ptr;
+
+ /* keep in logical range */
+ address &= info->space[ADDRESS_SPACE_PROGRAM].logbytemask;
+
+ /* shortcut if we have a custom routine */
+ if (info->readop)
+ {
+ UINT64 result;
+ if ((*info->readop)(address, size, &result))
+ return result;
+ }
+
+ /* if we're bigger than the address bus, break into smaller pieces */
+ if (size > info->space[ADDRESS_SPACE_PROGRAM].databytes)
+ {
+ int halfsize = size / 2;
+ UINT64 r0 = debug_read_opcode(address + 0, halfsize, arg);
+ UINT64 r1 = debug_read_opcode(address + halfsize, halfsize, arg);
+
+ if (info->endianness == CPU_IS_LE)
+ return r0 | (r1 << (8 * halfsize));
+ else
+ return r1 | (r0 << (8 * halfsize));
+ }
+
+ /* translate to physical first */
+ if (info->translate && !(*info->translate)(ADDRESS_SPACE_PROGRAM, &address))
+ return ~(UINT64)0 & (~(UINT64)0 >> (64 - 8*size));
+
+ /* keep in physical range */
+ address &= info->space[ADDRESS_SPACE_PROGRAM].physbytemask;
+
+ /* adjust the address */
+ memory_set_opbase(address);
+
+ switch (info->space[ADDRESS_SPACE_PROGRAM].databytes * 10 + size)
+ {
+ /* dump opcodes in bytes from a byte-sized bus */
+ case 11:
+ break;
+
+ /* dump opcodes in bytes from a word-sized bus */
+ case 21:
+ address ^= (info->endianness == CPU_IS_LE) ? BYTE_XOR_LE(0) : BYTE_XOR_BE(0);
+ break;
+
+ /* dump opcodes in words from a word-sized bus */
+ case 22:
+ break;
+
+ /* dump opcodes in bytes from a dword-sized bus */
+ case 41:
+ address ^= (info->endianness == CPU_IS_LE) ? BYTE4_XOR_LE(0) : BYTE4_XOR_BE(0);
+ break;
+
+ /* dump opcodes in words from a dword-sized bus */
+ case 42:
+ address ^= (info->endianness == CPU_IS_LE) ? WORD_XOR_LE(0) : WORD_XOR_BE(0);
+ break;
+
+ /* dump opcodes in dwords from a dword-sized bus */
+ case 44:
+ break;
+
+ /* dump opcodes in bytes from a qword-sized bus */
+ case 81:
+ address ^= (info->endianness == CPU_IS_LE) ? BYTE8_XOR_LE(0) : BYTE8_XOR_BE(0);
+ break;
+
+ /* dump opcodes in words from a qword-sized bus */
+ case 82:
+ address ^= (info->endianness == CPU_IS_LE) ? WORD2_XOR_LE(0) : WORD2_XOR_BE(0);
+ break;
+
+ /* dump opcodes in dwords from a qword-sized bus */
+ case 84:
+ address ^= (info->endianness == CPU_IS_LE) ? DWORD_XOR_LE(0) : DWORD_XOR_BE(0);
+ break;
+
+ /* dump opcodes in qwords from a qword-sized bus */
+ case 88:
+ break;
+
+ default:
+ fatalerror("debug_read_opcode: unknown type = %d", info->space[ADDRESS_SPACE_PROGRAM].databytes * 10 + size);
+ break;
+ }
+
+ /* get pointer to data */
+ /* note that we query aligned to the bus width, and then add back the low bits */
+ lowbits_mask = info->space[ADDRESS_SPACE_PROGRAM].databytes - 1;
+ ptr = memory_get_op_ptr(cpu_getactivecpu(), address & ~lowbits_mask, arg);
+ if (!ptr)
+ return ~(UINT64)0 & (~(UINT64)0 >> (64 - 8*size));
+ ptr = (UINT8 *)ptr + (address & lowbits_mask);
+
+ /* gross! */
+// if (osd_is_bad_read_ptr(ptr, size))
+// fatalerror("debug_read_opcode: cpu %d address %x mapped to invalid memory %p", cpu_getactivecpu(), address, ptr);
+
+ /* return based on the size */
+ switch (size)
+ {
+ case 1: return *(UINT8 *) ptr;
+ case 2: return *(UINT16 *)ptr;
+ case 4: return *(UINT32 *)ptr;
+ case 8: return *(UINT64 *)ptr;
+ }
+
+ return 0; /* appease compiler */
+}
+
+
+/*-------------------------------------------------
+ external_read_memory - read 1,2,4 or 8 bytes at
+ the given offset in the given address space
+-------------------------------------------------*/
+
+UINT64 external_read_memory(int space, UINT32 offset, int size)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+ if (info->space[space].databytes == 0)
+ return ~0;
+
+ /* adjust the address into a byte address */
+ offset = ADDR2BYTE(offset, info, space);
+ switch (size)
+ {
+ case 1: return debug_read_byte(space, offset, TRUE);
+ case 2: return debug_read_word(space, offset, TRUE);
+ case 4: return debug_read_dword(space, offset, TRUE);
+ case 8: return debug_read_qword(space, offset, TRUE);
+ }
+ return ~0;
+}
+
+
+/*-------------------------------------------------
+ external_write_memory - write 1,2,4 or 8 bytes to
+ the given offset in the given address space
+-------------------------------------------------*/
+
+void external_write_memory(int space, UINT32 offset, int size, UINT64 value)
+{
+ const debug_cpu_info *info = &debug_cpuinfo[cpu_getactivecpu()];
+ if (info->space[space].databytes == 0)
+ return;
+
+ /* adjust the address into a byte address */
+ offset = ADDR2BYTE(offset, info, space);
+ switch (size)
+ {
+ case 1: debug_write_byte(space, offset, value, TRUE); break;
+ case 2: debug_write_word(space, offset, value, TRUE); break;
+ case 4: debug_write_dword(space, offset, value, TRUE); break;
+ case 8: debug_write_qword(space, offset, value, TRUE); break;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_trace_printf - writes text to a given
+ CPU's trace file
+-------------------------------------------------*/
+
+void debug_trace_printf(int cpunum, const char *fmt, ...)
+{
+ va_list va;
+
+ debug_cpu_info *info = &debug_cpuinfo[cpunum];
+
+ if (info->trace.file)
+ {
+ va_start(va, fmt);
+ vfprintf(info->trace.file, fmt, va);
+ va_end(va);
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_source_script - specifies a debug command
+ script to use
+-------------------------------------------------*/
+
+void debug_source_script(const char *file)
+{
+ if (debug_source_file)
+ {
+ fclose(debug_source_file);
+ debug_source_file = NULL;
+ }
+
+ if (file)
+ {
+ debug_source_file = fopen(file, "r");
+ if (!debug_source_file)
+ {
+ if (mame_get_phase(Machine) == MAME_PHASE_RUNNING)
+ debug_console_printf("Cannot open command file '%s'\n", file);
+ else
+ fatalerror("Cannot open command file '%s'", file);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_flush_traces - flushes all traces; this is
+ useful if a trace is going on when we fatalerror
+-------------------------------------------------*/
+
+void debug_flush_traces(void)
+{
+ int cpunum;
+
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ if (debug_cpuinfo[cpunum].trace.file)
+ fflush(debug_cpuinfo[cpunum].trace.file);
+ }
+}
diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h
new file mode 100644
index 00000000000..e401d7d942f
--- /dev/null
+++ b/src/emu/debug/debugcpu.h
@@ -0,0 +1,231 @@
+/*********************************************************************
+
+ debugcpu.h
+
+ Debugger CPU/memory interface engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __DEBUGCPU_H__
+#define __DEBUGCPU_H__
+
+#include "express.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define TRACE_LOOPS 64
+#define DEBUG_HISTORY_SIZE 256
+
+#define WATCHPOINT_READ 1
+#define WATCHPOINT_WRITE 2
+#define WATCHPOINT_READWRITE (WATCHPOINT_READ | WATCHPOINT_WRITE)
+
+enum
+{
+ EXECUTION_STATE_STOPPED,
+ EXECUTION_STATE_RUNNING,
+ EXECUTION_STATE_NEXT_CPU,
+ EXECUTION_STATE_STEP_INTO,
+ EXECUTION_STATE_STEP_OVER,
+ EXECUTION_STATE_STEP_OUT
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define ADDR2BYTE(val,info,spc) (((val) << (info)->space[spc].addr2byte_lshift) >> (info)->space[spc].addr2byte_rshift)
+#define ADDR2BYTE_MASKED(val,info,spc) (ADDR2BYTE(val,info,spc) & (info)->space[spc].logbytemask)
+#define BYTE2ADDR(val,info,spc) (((val) << (info)->space[spc].addr2byte_rshift) >> (info)->space[spc].addr2byte_lshift)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef void (*debug_hook_read_ptr)(int spacenum, int size, offs_t address);
+typedef void (*debug_hook_write_ptr)(int spacenum, int size, offs_t address, UINT64 data);
+
+
+typedef struct _debug_trace_info debug_trace_info;
+typedef struct _debug_space_info debug_space_info;
+typedef struct _debug_hotspot_entry debug_hotspot_entry;
+typedef struct _debug_cpu_info debug_cpu_info;
+typedef struct _debug_cpu_breakpoint debug_cpu_breakpoint;
+typedef struct _debug_cpu_watchpoint debug_cpu_watchpoint;
+
+
+struct _debug_trace_info
+{
+ FILE * file; /* tracing file for this CPU */
+ char * action; /* action to perform during a trace */
+ offs_t history[TRACE_LOOPS]; /* history of recent PCs */
+ int loops; /* number of instructions in a loop */
+ int nextdex; /* next index */
+ offs_t trace_over_target; /* target for tracing over
+ (0 = not tracing over,
+ ~0 = not currently tracing over) */
+};
+
+
+struct _debug_space_info
+{
+ UINT8 databytes; /* width of the data bus, in bytes */
+ UINT8 pageshift; /* page shift */
+ UINT8 addr2byte_lshift; /* left shift to convert CPU address to a byte value */
+ UINT8 addr2byte_rshift; /* right shift to convert CPU address to a byte value */
+ UINT8 physchars; /* number of characters to use for physical addresses */
+ UINT8 logchars; /* number of characters to use for logical addresses */
+ offs_t physaddrmask; /* physical address mask */
+ offs_t logaddrmask; /* logical address mask */
+ offs_t physbytemask; /* physical byte mask */
+ offs_t logbytemask; /* logical byte mask */
+ debug_cpu_watchpoint *first_wp; /* first watchpoint */
+};
+
+
+struct _debug_hotspot_entry
+{
+ offs_t access; /* access address */
+ offs_t pc; /* PC of the access */
+ int spacenum; /* space where the access occurred */
+ UINT32 count; /* number of hits */
+};
+
+
+struct _debug_cpu_info
+{
+ UINT8 valid; /* are we valid? */
+ UINT8 endianness; /* little or bigendian */
+ UINT8 opwidth; /* width of an opcode */
+ UINT8 ignoring; /* are we ignoring this CPU's execution? */
+ offs_t temp_breakpoint_pc; /* temporary breakpoint PC */
+ int read_watchpoints; /* total read watchpoints on this CPU */
+ int write_watchpoints; /* total write watchpoints on this CPU */
+ symbol_table * symtable; /* symbol table for expression evaluation */
+ debug_trace_info trace; /* trace info */
+ debug_cpu_breakpoint *first_bp; /* first breakpoint */
+ debug_space_info space[ADDRESS_SPACES]; /* per-address space info */
+ debug_hotspot_entry *hotspots; /* hotspot list */
+ offs_t pc_history[DEBUG_HISTORY_SIZE]; /* history of recent PCs */
+ UINT32 pc_history_index; /* current history index */
+ int hotspot_count; /* number of hotspots */
+ int hotspot_threshhold; /* threshhold for the number of hits to print */
+ int (*translate)(int space, offs_t *address);/* address translation routine */
+ int (*read)(int space, UINT32 offset, int size, UINT64 *value); /* memory read routine */
+ int (*write)(int space, UINT32 offset, int size, UINT64 value); /* memory write routine */
+ int (*readop)(UINT32 offset, int size, UINT64 *value); /* opcode read routine */
+ int (*instrhook)(offs_t pc); /* per-instruction callback hook */
+};
+
+
+struct _debug_cpu_breakpoint
+{
+ int index; /* user reported index */
+ UINT8 enabled; /* enabled? */
+ offs_t address; /* execution address */
+ parsed_expression *condition; /* condition */
+ char * action; /* action */
+ debug_cpu_breakpoint *next; /* next in the list */
+};
+
+
+struct _debug_cpu_watchpoint
+{
+ int index; /* user reported index */
+ UINT8 enabled; /* enabled? */
+ UINT8 type; /* type (read/write) */
+ offs_t address; /* start address */
+ offs_t length; /* length of watch area */
+ parsed_expression *condition; /* condition */
+ char * action; /* action */
+ debug_cpu_watchpoint *next; /* next in the list */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+extern FILE *debug_source_file;
+extern symbol_table *global_symtable;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* initialization */
+void debug_cpu_init(running_machine *machine);
+
+/* utilities */
+const debug_cpu_info *debug_get_cpu_info(int cpunum);
+void debug_halt_on_next_instruction(void);
+void debug_refresh_display(void);
+int debug_get_execution_state(void);
+UINT32 debug_get_execution_counter(void);
+void debug_trace_printf(int cpunum, const char *fmt, ...);
+void debug_source_script(const char *file);
+void debug_flush_traces(void);
+
+/* debugging hooks */
+void debug_vblank_hook(void);
+void debug_interrupt_hook(int cpunum, int irqline);
+void debug_get_memory_hooks(int cpunum, debug_hook_read_ptr *read, debug_hook_write_ptr *write);
+void debug_set_instruction_hook(int cpunum, int (*hook)(offs_t pc));
+
+/* execution control */
+void debug_cpu_single_step(int numsteps);
+void debug_cpu_single_step_over(int numsteps);
+void debug_cpu_single_step_out(void);
+void debug_cpu_go(offs_t targetpc);
+void debug_cpu_go_vblank(void);
+void debug_cpu_go_interrupt(int irqline);
+void debug_cpu_go_milliseconds(UINT64 milliseconds);
+void debug_cpu_next_cpu(void);
+void debug_cpu_ignore_cpu(int cpunum, int ignore);
+
+/* tracing support */
+void debug_cpu_trace(int cpunum, FILE *file, int trace_over, const char *action);
+
+/* breakpoints */
+void debug_check_breakpoints(int cpunum, offs_t pc);
+debug_cpu_breakpoint *debug_breakpoint_first(int cpunum);
+int debug_breakpoint_set(int cpunum, offs_t address, parsed_expression *condition, const char *action);
+int debug_breakpoint_clear(int bpnum);
+int debug_breakpoint_enable(int bpnum, int enable);
+
+/* watchpoints */
+debug_cpu_watchpoint *debug_watchpoint_first(int cpunum, int spacenum);
+int debug_watchpoint_set(int cpunum, int spacenum, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action);
+int debug_watchpoint_clear(int wpnum);
+int debug_watchpoint_enable(int wpnum, int enable);
+
+/* hotspots */
+int debug_hotspot_track(int cpunum, int numspots, int threshhold);
+
+/* memory accessors */
+UINT8 debug_read_byte(int spacenum, offs_t address, int apply_translation);
+UINT16 debug_read_word(int spacenum, offs_t address, int apply_translation);
+UINT32 debug_read_dword(int spacenum, offs_t address, int apply_translation);
+UINT64 debug_read_qword(int spacenum, offs_t address, int apply_translation);
+void debug_write_byte(int spacenum, offs_t address, UINT8 data, int apply_translation);
+void debug_write_word(int spacenum, offs_t address, UINT16 data, int apply_translation);
+void debug_write_dword(int spacenum, offs_t address, UINT32 data, int apply_translation);
+void debug_write_qword(int spacenum, offs_t address, UINT64 data, int apply_translation);
+UINT64 debug_read_opcode(UINT32 offset, int size, int arg);
+
+#endif
diff --git a/src/emu/debug/debughlp.c b/src/emu/debug/debughlp.c
new file mode 100644
index 00000000000..68e188130da
--- /dev/null
+++ b/src/emu/debug/debughlp.c
@@ -0,0 +1,1075 @@
+/*********************************************************************
+
+ debughlp.c
+
+ Debugger help engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "debughlp.h"
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define CONSOLE_HISTORY (10000)
+#define CONSOLE_LINE_CHARS (100)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _help_item help_item;
+struct _help_item
+{
+ const char * tag;
+ const char * help;
+};
+
+
+
+/***************************************************************************
+ LOCAL VARIABLES
+***************************************************************************/
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+
+/***************************************************************************
+ TABLE OF HELP
+***************************************************************************/
+
+static help_item static_help_list[] =
+{
+ {
+ "",
+ "\n"
+ "MAME Debugger Help\n"
+ " help [<topic>] -- get help on a particular topic\n"
+ "\n"
+ "Topics:\n"
+ " General\n"
+ " Memory\n"
+ " Execution\n"
+ " Breakpoints\n"
+ " Watchpoints\n"
+ " Expressions\n"
+ " Comments\n"
+ },
+ {
+ "general",
+ "\n"
+ "General Debugger Help\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " help [<topic>] -- get help on a particular topic\n"
+ " do <expression> -- evaluates the given expression\n"
+ " symlist [<cpunum>] -- lists registered symbols\n"
+ " print <item>[,...] -- prints one or more <item>s to the console\n"
+ " printf <format>[,<item>[,...]] -- prints one or more <item>s to the console using <format>\n"
+ " logerror <format>[,<item>[,...]] -- outputs one or more <item>s to the error.log\n"
+ " tracelog <format>[,<item>[,...]] -- outputs one or more <item>s to the trace file using <format>\n"
+ " snap [<filename>] -- save a screen snapshot\n"
+ " quit -- exits MAME and the debugger\n"
+ },
+ {
+ "memory",
+ "\n"
+ "Memory Commands\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " dasm <filename>,<address>,<length>[,<opcodes>[,<cpunum>]] -- disassemble to the given file\n"
+ " f[ind] <address>,<length>[,<data>[,...]] -- search program memory for data\n"
+ " f[ind]d <address>,<length>[,<data>[,...]] -- search data memory for data\n"
+ " f[ind]i <address>,<length>[,<data>[,...]] -- search I/O memory for data\n"
+ " dump <filename>,<address>,<length>[,<size>[,<ascii>[,<cpunum>]]] -- dump program memory as text\n"
+ " dumpd <filename>,<address>,<length>[,<size>[,<ascii>[,<cpunum>]]] -- dump data memory as text\n"
+ " dumpi <filename>,<address>,<length>[,<size>[,<ascii>[,<cpunum>]]] -- dump I/O memory as text\n"
+ " save <filename>,<address>,<length>[,<cpunum>] -- save binary program memory to the given file\n"
+ " saved <filename>,<address>,<length>[,<cpunum>] -- save binary data memory to the given file\n"
+ " savei <filename>,<address>,<length>[,<cpunum>] -- save binary I/O memory to the given file\n"
+ " map <address> -- map logical program address to physical address and bank\n"
+ " mapd <address> -- map logical data address to physical address and bank\n"
+ " mapi <address> -- map logical I/O address to physical address and bank\n"
+ " memdump [<filename>] -- dump the current memory map to <filename>\n"
+ },
+ {
+ "execution",
+ "\n"
+ "Execution Commands\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " s[tep] [<count>=1] -- single steps for <count> instructions (F12)\n"
+ " o[ver] [<count>=1] -- single steps over <count> instructions (F11)\n"
+ " out -- single steps until the current subroutine/exception handler is exited (Shift-F11)\n"
+ " g[o] [<address>] -- resumes execution, sets temp breakpoint at <address> (F5)\n"
+ " gi[nt] [<irqline>] -- resumes execution, setting temp breakpoint if <irqline> is taken (F7)\n"
+ " gv[blank] -- resumes execution, setting temp breakpoint on the next VBLANK (F8)\n"
+ " n[ext] -- executes until the next CPU switch (F6)\n"
+ " focus <cpunum> -- focuses debugger only on <cpunum>\n"
+ " ignore [<cpunum>[,<cpunum>[,...]]] -- stops debugging on <cpunum>\n"
+ " observe [<cpunum>[,<cpunum>[,...]]] -- resumes debugging on <cpunum>\n"
+ " trace {<filename>|OFF}[,<cpunum>[,<action>]] -- trace the given CPU to a file (defaults to active CPU)\n"
+ },
+ {
+ "breakpoints",
+ "\n"
+ "Breakpoint Commands\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " bp[set] <address>[,<condition>[,<action>]] -- sets breakpoint at <address>\n"
+ " bpclear [<bpnum>] -- clears a given breakpoint or all if no <bpnum> specified\n"
+ " bpdisable [<bpnum>] -- disables a given breakpoint or all if no <bpnum> specified\n"
+ " bpenable [<bpnum>] -- enables a given breakpoint or all if no <bpnum> specified\n"
+ " bplist -- lists all the breakpoints\n"
+ },
+ {
+ "watchpoints",
+ "\n"
+ "Watchpoint Commands\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " wp[set] <address>,<length>,<type>[,<condition>[,<action>]] -- sets program space watchpoint\n"
+ " wpd[set] <address>,<length>,<type>[,<condition>[,<action>]] -- sets data space watchpoint\n"
+ " wpi[set] <address>,<length>,<type>[,<condition>[,<action>]] -- sets I/O space watchpoint\n"
+ " wpclear [<wpnum>] -- clears a given watchpoint or all if no <wpnum> specified\n"
+ " wpdisable [<wpnum>] -- disables a given watchpoint or all if no <wpnum> specified\n"
+ " wpenable [<wpnum>] -- enables a given watchpoint or all if no <wpnum> specified\n"
+ " wplist -- lists all the watchpoints\n"
+ " hotspot [<cpunum>,[<depth>[,<hits>]]] -- attempt to find hotspots\n"
+ },
+ {
+ "expressions",
+ "\n"
+ "Expressions can be used anywhere a numeric parameter is expected. The syntax for expressions is "
+ "very close to standard C-style syntax with full operator ordering and parentheses. There are a "
+ "few operators missing (notably the trinary ? : operator), and a few new ones (memory accessors). "
+ "The table below lists all the operators in their order, highest precedence operators first.\n"
+ "\n"
+ " ( ) : standard parentheses\n"
+ " ++ -- : postfix increment/decrement\n"
+ " ++ -- ~ ! - + b@ w@ d@ q@ : prefix inc/dec, binary NOT, logical NOT, unary +/-, memory access\n"
+ " * / % : multiply, divide, modulus\n"
+ " + - : add, subtract\n"
+ " << >> : shift left/right\n"
+ " < <= > >= : less than, less than or equal, greater than, greater than or equal\n"
+ " == != : equal, not equal\n"
+ " & : binary AND\n"
+ " ^ : binary XOR\n"
+ " | : binary OR\n"
+ " && : logical AND\n"
+ " || : logical OR\n"
+ " = *= /= %= += -= <<= >>= &= |= ^= : assignment\n"
+ " , : separate terms, function parameters\n"
+ "\n"
+ "These are the differences from C behaviors. First, All math is performed on full 64-bit unsigned "
+ "values, so things like a < 0 won't work as expected. Second, the logical operators && and || do "
+ "not have short-circuit properties -- both halves are always evaluated. Finally, the new memory "
+ "operators work like this: b@<addr> refers to the byte read from <addr>. Similarly, w@ refers to "
+ "a word in memory, d@ refers to a dword in memory, and q@ refers to a qword in memory. The memory "
+ "operators can be used as both lvalues and rvalues, so you can write b@100 = ff to store a byte "
+ "in memory. By default these operators read from the program memory space, but you can override "
+ "that by prefixing them with a 'd' or an 'i'. So dw@300 refers to data memory word at address "
+ "300 and id@400 refers to an I/O memory dword at address 400.\n"
+ },
+ {
+ "comments",
+ "\n"
+ "Code annotation commands\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " comadd[//] <address>,<comment> -- adds a comment to the disassembled code at given address\n"
+ " comdelete <address> -- removes a comment from the given address\n"
+ " comsave -- save the current comments to a file\n"
+ "\n"
+ },
+ {
+ "do",
+ "\n"
+ " do <expression>\n"
+ "\n"
+ "The do command simply evaluates the given <expression>. This is typically used to set or modify "
+ "variables.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "do pc = 0\n"
+ " Sets the register 'pc' to 0.\n"
+ },
+ {
+ "symlist",
+ "\n"
+ " symlist [<cpunum>]\n"
+ "\n"
+ "Lists registered symbols. If <cpunum> is not specified, then symbols in the global symbol table are "
+ "displayed; otherwise, the symbols for <cpunum>'s specific CPU are displayed. Symbols are listed "
+ "alphabetically. Read-only symbols are flagged with an asterisk.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "symlist\n"
+ " Displays the global symbol table.\n"
+ "\n"
+ "symlist 2\n"
+ " Displays the symbols specific to CPU #2.\n"
+ },
+ {
+ "softreset",
+ "\n"
+ " softreset\n"
+ "\n"
+ "Executes a soft reset.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "softreset\n"
+ " Executes a soft reset.\n"
+ },
+ {
+ "hardreset",
+ "\n"
+ " hardreset\n"
+ "\n"
+ "Executes a hard reset.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "hardreset\n"
+ " Executes a hard reset.\n"
+ },
+ {
+ "print",
+ "\n"
+ " print <item>[,...]\n"
+ "\n"
+ "The print command prints the results of one or more expressions to the debugger console as hexadecimal "
+ "values.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "print pc\n"
+ " Prints the value of 'pc' to the console as a hex number.\n"
+ "\n"
+ "print a,b,a+b\n"
+ " Prints a, b, and the value of a+b to the console as hex numbers.\n"
+ },
+ {
+ "printf",
+ "\n"
+ " printf <format>[,<item>[,...]]\n"
+ "\n"
+ "The printf command performs a C-style printf to the debugger console. Only a very limited set of "
+ "formatting options are available:\n"
+ "\n"
+ " %[0][<n>]d -- prints <item> as a decimal value with optional digit count and zero-fill\n"
+ " %[0][<n>]x -- prints <item> as a hexadecimal value with optional digit count and zero-fill\n"
+ "\n"
+ "All remaining formatting options are ignored. Use %% together to output a % character. Multiple "
+ "lines can be printed by embedding a \\n in the text.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "printf \"PC=%04X\",pc\n"
+ " Prints PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
+ "\n"
+ "printf \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
+ " Prints A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
+ },
+ {
+ "logerror",
+ "\n"
+ " logerror <format>[,<item>[,...]]\n"
+ "\n"
+ "The logerror command performs a C-style printf to the error log. Only a very limited set of "
+ "formatting options are available:\n"
+ "\n"
+ " %[0][<n>]d -- logs <item> as a decimal value with optional digit count and zero-fill\n"
+ " %[0][<n>]x -- logs <item> as a hexadecimal value with optional digit count and zero-fill\n"
+ "\n"
+ "All remaining formatting options are ignored. Use %% together to output a % character. Multiple "
+ "lines can be printed by embedding a \\n in the text.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "logerror \"PC=%04X\",pc\n"
+ " Logs PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
+ "\n"
+ "logerror \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
+ " Logs A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
+ },
+ {
+ "tracelog",
+ "\n"
+ " tracelog <format>[,<item>[,...]]\n"
+ "\n"
+ "The tracelog command performs a C-style printf and routes the output to the currently open trace "
+ "file (see the 'trace' command for details). If no file is currently open, tracelog does nothing. "
+ "Only a very limited set of formatting options are available. See the 'printf' help for details.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "tracelog \"PC=%04X\",pc\n"
+ " Outputs PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
+ "\n"
+ "printf \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
+ " Outputs A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
+ },
+ {
+ "snap",
+ "\n"
+ " snap [[<filename>], <scrnum>]\n"
+ "\n"
+ "The snap command takes a snapshot of the current video display and saves it to the configured "
+ "snapshot directory. If <filename> is specified explicitly, a single screenshot for <scrnum> is "
+ "saved under the requested filename. If <filename> is omitted, all screens are saved using the "
+ "same default rules as the \"save snapshot\" key in MAME proper.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "snap\n"
+ " Takes a snapshot of the current video screen and saves to the next non-conflicting filename "
+ " in the configured snapshot directory.\n"
+ "\n"
+ "snap shinobi\n"
+ " Takes a snapshot of the current video screen and saves it as 'shinobi.png' in the configured "
+ " snapshot directory.\n"
+ },
+ {
+ "source",
+ "\n"
+ " source <filename>\n"
+ "\n"
+ "The source command reads in a set of debugger commands from a file and executes them one by "
+ "one, similar to a batch file.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "source break_and_trace.cmd\n"
+ " Reads in debugger commands from break_and_trace.cmd and executes them.\n"
+ },
+ {
+ "quit",
+ "\n"
+ " quit\n"
+ "\n"
+ "The quit command exits MAME immediately.\n"
+ },
+ {
+ "dasm",
+ "\n"
+ " dasm <filename>,<address>,<length>[,<opcodes>[,<cpunum>]]\n"
+ "\n"
+ "The dasm command disassembles program memory to the file specified in the <filename> parameter. "
+ "<address> indicates the address of the start of disassembly, and <length> indicates how much "
+ "memory to disassemble. The range <address> through <address>+<length>-1 inclusive will be "
+ "output to the file. By default, the raw opcode data is output with each line. The optional "
+ "<opcodes> parameter can be used to enable (1) or disable(0) this feature. Finally, you can "
+ "disassemble code from another CPU by specifying the <cpunum> parameter.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "dasm venture.asm,0,10000\n"
+ " Disassembles addresses 0-ffff in the current CPU, including raw opcode data, to the "
+ "file 'venture.asm'.\n"
+ "\n"
+ "dasm harddriv.asm,3000,1000,0,2\n"
+ " Disassembles addresses 3000-3fff from CPU #2, with no raw opcode data, to the file "
+ "'harddriv.asm'.\n"
+ },
+ {
+ "find",
+ "\n"
+ " f[ind][{d|i}] <address>,<length>[,<data>[,...]]\n"
+ "\n"
+ "The find/findd/findi commands search through memory for the specified sequence of data. "
+ "'find' will search program space memory, while 'findd' will search data space memory "
+ "and 'findi' will search I/O space memory. <address> indicates the address to begin searching, "
+ "and <length> indicates how much memory to search. <data> can either be a quoted string "
+ "or a numeric value or expression or the wildcard character '?'. Strings by default imply a "
+ "byte-sized search; non-string data is searched by default in the native word size of the CPU. "
+ "To override the search size for non-strings, you can prefix the value with b. to force byte- "
+ "sized search, w. for word-sized search, d. for dword-sized, and q. for qword-sized. Overrides "
+ "are remembered, so if you want to search for a series of words, you need only to prefix the "
+ "first value with a w. Note also that you can intermix sizes in order to perform more complex "
+ "searches. The entire range <address> through <address>+<length>-1 inclusive will be searched "
+ "for the sequence, and all occurrences will be displayed.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "find 0,10000,\"HIGH SCORE\",0\n"
+ " Searches the address range 0-ffff in the current CPU for the string \"HIGH SCORE\" followed "
+ "by a 0 byte.\n"
+ "\n"
+ "findd 3000,1000,w.abcd,4567\n"
+ " Searches the data memory address range 3000-3fff for the word-sized value abcd followed by "
+ "the word-sized value 4567.\n"
+ "\n"
+ "find 0,8000,\"AAR\",d.0,\"BEN\",w.0\n"
+ " Searches the address range 0000-7fff for the string \"AAR\" followed by a dword-sized 0 "
+ "followed by the string \"BEN\", followed by a word-sized 0.\n"
+ },
+ {
+ "dump",
+ "\n"
+ " dump[{d|i}] <filename>,<address>,<length>[,<size>[,<ascii>[,<cpunum>]]]\n"
+ "\n"
+ "The dump/dumpd/dumpi commands dump memory to the text file specified in the <filename> "
+ "parameter. 'dump' will dump program space memory, while 'dumpd' will dump data space memory "
+ "and 'dumpi' will dump I/O space memory. <address> indicates the address of the start of dumping, "
+ "and <length> indicates how much memory to dump. The range <address> through <address>+<length>-1 "
+ "inclusive will be output to the file. By default, the data will be output in byte format, unless "
+ "the underlying address space is word/dword/qword-only. You can override this by specifying the "
+ "<size> parameter, which can be used to group the data in 1, 2, 4 or 8-byte chunks. The optional "
+ "<ascii> parameter can be used to enable (1) or disable (0) the output of ASCII characters to the "
+ "right of each line; by default, this is enabled. Finally, you can dump memory from another CPU "
+ "by specifying the <cpunum> parameter.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "dump venture.dmp,0,10000\n"
+ " Dumps addresses 0-ffff in the current CPU in 1-byte chunks, including ASCII data, to "
+ "the file 'venture.dmp'.\n"
+ "\n"
+ "dumpd harddriv.dmp,3000,1000,4,0,3\n"
+ " Dumps data memory addresses 3000-3fff from CPU #3 in 4-byte chunks, with no ASCII data, "
+ "to the file 'harddriv.dmp'.\n"
+ },
+ {
+ "save",
+ "\n"
+ " save[{d|i}] <filename>,<address>,<length>[,<cpunum>]\n"
+ "\n"
+ "The save/saved/savei commands save raw memory to the binary file specified in the <filename> "
+ "parameter. 'save' will save program space memory, while 'saved' will save data space memory "
+ "and 'savei' will save I/O space memory. <address> indicates the address of the start of saving, "
+ "and <length> indicates how much memory to save. The range <address> through <address>+<length>-1 "
+ "inclusive will be output to the file. You can also save memory from another CPU by specifying the "
+ "<cpunum> parameter.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "save venture.bin,0,10000\n"
+ " Saves addresses 0-ffff in the current CPU to the binary file 'venture.bin'.\n"
+ "\n"
+ "saved harddriv.bin,3000,1000,3\n"
+ " Saves data memory addresses 3000-3fff from CPU #3 to the binary file 'harddriv.bin'.\n"
+ },
+ {
+ "step",
+ "\n"
+ " s[tep] [<count>=1]\n"
+ "\n"
+ "The step command single steps one or more instructions in the currently executing CPU. By "
+ "default, step executes one instruction each time it is issued. You can also tell step to step "
+ "multiple instructions by including the optional <count> parameter.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "s\n"
+ " Steps forward one instruction on the current CPU.\n"
+ "\n"
+ "step 4\n"
+ " Steps forward four instructions on the current CPU.\n"
+ },
+ {
+ "over",
+ "\n"
+ " o[ver] [<count>=1]\n"
+ "\n"
+ "The over command single steps \"over\" one or more instructions in the currently executing CPU, "
+ "stepping over subroutine calls and exception handler traps and counting them as a single "
+ "instruction. Note that when stepping over a subroutine call, code may execute on other CPUs "
+ "before the subroutine call completes. By default, over executes one instruction each time it is "
+ "issued. You can also tell step to step multiple instructions by including the optional <count> "
+ "parameter.\n"
+ "\n"
+ "Note that the step over functionality may not be implemented on all CPU types. If it is not "
+ "implemented, then 'over' will behave exactly like 'step'.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "o\n"
+ " Steps forward over one instruction on the current CPU.\n"
+ "\n"
+ "over 4\n"
+ " Steps forward over four instructions on the current CPU.\n"
+ },
+ {
+ "out",
+ "\n"
+ " out\n"
+ "\n"
+ "The out command single steps until it encounters a return from subroutine or return from "
+ "exception instruction. Note that because it detects return from exception conditions, if you "
+ "attempt to step out of a subroutine and an interrupt/exception occurs before you hit the end, "
+ "then you may stop prematurely at the end of the exception handler.\n"
+ "\n"
+ "Note that the step out functionality may not be implemented on all CPU types. If it is not "
+ "implemented, then 'out' will behave exactly like 'step'.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "out\n"
+ " Steps until the current subroutine or exception handler returns.\n"
+ },
+ {
+ "go",
+ "\n"
+ " g[o] [<address>]\n"
+ "\n"
+ "The go command resumes execution of the current code. Control will not be returned to the "
+ "debugger until a breakpoint or watchpoint is hit, or until you manually break in using the "
+ "assigned key. The go command takes an optional <address> parameter which is a temporary "
+ "unconditional breakpoint that is set before executing, and automatically removed when hit. "
+ "\n"
+ "Examples:\n"
+ "\n"
+ "g\n"
+ " Resume execution until the next break/watchpoint or until a manual break.\n"
+ "\n"
+ "g 1234\n"
+ " Resume execution, stopping at address 1234 unless something else stops us first.\n"
+ },
+ {
+ "gvblank",
+ "\n"
+ " gv[blank]\n"
+ "\n"
+ "The gvblank command resumes execution of the current code. Control will not be returned to "
+ "the debugger until a breakpoint or watchpoint is hit, or until the next VBLANK occurs in the "
+ "emulator.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gv\n"
+ " Resume execution until the next break/watchpoint or until the next VBLANK.\n"
+ },
+ {
+ "gint",
+ "\n"
+ " gi[nt] [<irqline>]\n"
+ "\n"
+ "The gint command resumes execution of the current code. Control will not be returned to the "
+ "debugger until a breakpoint or watchpoint is hit, or until an IRQ is asserted and acknowledged "
+ "on the current CPU. You can specify <irqline> if you wish to stop execution only on a particular "
+ "IRQ line being asserted and acknowledged. If <irqline> is omitted, then any IRQ line will stop "
+ "execution.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gi\n"
+ " Resume execution until the next break/watchpoint or until any IRQ is asserted and acknowledged "
+ "on the current CPU.\n"
+ "\n"
+ "gint 4\n"
+ " Resume execution until the next break/watchpoint or until IRQ line 4 is asserted and "
+ "acknowledged on the current CPU.\n"
+ },
+ {
+ "gtime",
+ "\n"
+ " gt[ime] <milliseconds>\n"
+ "\n"
+ "The gtime command resumes execution of the current code. Control will not be returned to the "
+ "debugger until a specified delay has elapsed. The delay is in milliseconds.\n"
+ "\n"
+ "Example:\n"
+ "\n"
+ "gtime #10000\n"
+ " Resume execution for ten seconds\n"
+ },
+ {
+ "next",
+ "\n"
+ " n[ext]\n"
+ "\n"
+ "The next command resumes execution and continues executing until the next time a different "
+ "CPU is scheduled. Note that if you have used 'ignore' to ignore certain CPUs, you will not "
+ "stop until a non-'ignore'd CPU is scheduled.\n"
+ },
+ {
+ "focus",
+ "\n"
+ " focus <cpunum>\n"
+ "\n"
+ "Sets the debugger focus exclusively to the given <cpunum>. This is equivalent to specifying "
+ "'ignore' on all other CPUs.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "focus 1\n"
+ " Focus exclusively CPU #1 while ignoring all other CPUs when using the debugger.\n"
+ },
+ {
+ "ignore",
+ "\n"
+ " ignore [<cpunum>[,<cpunum>[,...]]]\n"
+ "\n"
+ "Ignores the specified <cpunum> in the debugger. This means that you won't ever see execution "
+ "on that CPU, nor will you be able to set breakpoints on that CPU. To undo this change use "
+ "the 'observe' command. You can specify multiple <cpunum>s in a single command. Note also that "
+ "you are not permitted to ignore all CPUs; at least one must be active at all times.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "ignore 1\n"
+ " Ignore CPU #1 when using the debugger.\n"
+ "\n"
+ "ignore 2,3,4\n"
+ " Ignore CPU #2, #3 and #4 when using the debugger.\n"
+ "\n"
+ "ignore\n"
+ " List the CPUs that are currently ignored.\n"
+ },
+ {
+ "observe",
+ "\n"
+ " observe [<cpunum>[,<cpunum>[,...]]]\n"
+ "\n"
+ "Re-enables interaction with the specified <cpunum> in the debugger. This command undoes the "
+ "effects of the 'ignore' command. You can specify multiple <cpunum>s in a single command.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "observe 1\n"
+ " Stop ignoring CPU #1 when using the debugger.\n"
+ "\n"
+ "observe 2,3,4\n"
+ " Stop ignoring CPU #2, #3 and #4 when using the debugger.\n"
+ "\n"
+ "observe\n"
+ " List the CPUs that are currently observed.\n"
+ },
+ {
+ "trace",
+ "\n"
+ " trace {<filename>|OFF}[,<cpunum>[,<action>]]\n"
+ "\n"
+ "Starts or stops tracing of the execution of the specified <cpunum>. If <cpunum> is omitted, "
+ "the currently active CPU is specified. When enabling tracing, specify the filename in the "
+ "<filename> parameter. To disable tracing, substitute the keyword 'off' for <filename>. If you "
+ "wish to log additional information on each trace, you can append an <action> parameter which "
+ "is a command that is executed before each trace is logged. Generally, this is used to include "
+ "a 'tracelog' command. Note that you may need to embed the action within braces { } in order "
+ "to prevent commas and semicolons from being interpreted as applying to the trace command "
+ "itself.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "trace dribling.tr,0\n"
+ " Begin tracing the execution of CPU #0, logging output to dribling.tr.\n"
+ "\n"
+ "trace joust.tr\n"
+ " Begin tracing the currently active CPU, logging output to joust.tr.\n"
+ "\n"
+ "trace >>pigskin.tr\n"
+ " Begin tracing the currently active CPU, appending log output to pigskin.tr.\n"
+ "\n"
+ "trace off,0\n"
+ " Turn off tracing on CPU #0.\n"
+ "\n"
+ "trace asteroid.tr,0,{tracelog \"A=%02X \",a}\n"
+ " Begin tracing the execution of CPU #0, logging output to asteroid.tr. Before each line, "
+ "output A=<aval> to the tracelog.\n"
+ },
+ {
+ "traceover",
+ "\n"
+ " traceover {<filename>|OFF}[,<cpunum>[,<action>]]\n"
+ "\n"
+ "Starts or stops tracing of the execution of the specified <cpunum>. When tracing reaches "
+ "a subroutine or call, tracing will skip over the subroutine. The same algorithm is used as is "
+ "used in the step over command. This means that traceover will not work properly when calls "
+ "are recusive or the return address is not immediately following the call instruction. If "
+ "<cpunum> is omitted, the currently active CPU is specified. When enabling tracing, specify the "
+ "filename in the <filename> parameter. To disable tracing, substitute the keyword 'off' for "
+ "<filename>. If you wish to log additional information on each trace, you can append an <action> "
+ "parameter which is a command that is executed before each trace is logged. Generally, this is "
+ "used to include a 'tracelog' command. Note that you may need to embed the action within braces "
+ "{ } in order to prevent commas and semicolons from being interpreted as applying to the trace "
+ "command itself.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "traceover dribling.tr,0\n"
+ " Begin tracing the execution of CPU #0, logging output to dribling.tr.\n"
+ "\n"
+ "traceover joust.tr\n"
+ " Begin tracing the currently active CPU, logging output to joust.tr.\n"
+ "\n"
+ "traceover off,0\n"
+ " Turn off tracing on CPU #0.\n"
+ "\n"
+ "traceover asteroid.tr,0,{tracelog \"A=%02X \",a}\n"
+ " Begin tracing the execution of CPU #0, logging output to asteroid.tr. Before each line, "
+ "output A=<aval> to the tracelog.\n"
+ },
+ {
+ "traceflush",
+ "\n"
+ " traceflush\n"
+ "\n"
+ "Flushes all open trace files.\n"
+ },
+ {
+ "bpset",
+ "\n"
+ " bp[set] <address>[,<condition>[,<action>]]\n"
+ "\n"
+ "Sets a new execution breakpoint at the specified <address>. The optional <condition> "
+ "parameter lets you specify an expression that will be evaluated each time the breakpoint is "
+ "hit. If the result of the expression is true (non-zero), the breakpoint will actually halt "
+ "execution; otherwise, execution will continue with no notification. The optional <action> "
+ "parameter provides a command that is executed whenever the breakpoint is hit and the "
+ "<condition> is true. Note that you may need to embed the action within braces { } in order "
+ "to prevent commas and semicolons from being interpreted as applying to the bpset command "
+ "itself. Each breakpoint that is set is assigned an index which can be used in other "
+ "breakpoint commands to reference this breakpoint.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "bp 1234\n"
+ " Set a breakpoint that will halt execution whenever the PC is equal to 1234.\n"
+ "\n"
+ "bp 23456,a0 == 0 && a1 == 0\n"
+ " Set a breakpoint that will halt execution whenever the PC is equal to 23456 AND the "
+ "expression (a0 == 0 && a1 == 0) is true.\n"
+ "\n"
+ "bp 3456,1,{printf \"A0=%08X\\n\",a0; g}\n"
+ " Set a breakpoint that will halt execution whenever the PC is equal to 3456. When "
+ "this happens, print A0=<a0val> and continue executing.\n"
+ "\n"
+ "bp 45678,a0==100,{a0 = ff; g}\n"
+ " Set a breakpoint that will halt execution whenever the PC is equal to 45678 AND the "
+ "expression (a0 == 100) is true. When that happens, set a0 to ff and resume execution.\n"
+ "\n"
+ "temp0 = 0; bp 567890,++temp0 >= 10\n"
+ " Set a breakpoint that will halt execution whenever the PC is equal to 567890 AND the "
+ "expression (++temp0 >= 10) is true. This effectively breaks only after the breakpoint "
+ "has been hit 16 times.\n"
+ },
+ {
+ "bpclear",
+ "\n"
+ " bpclear [<bpnum>]\n"
+ "\n"
+ "The bpclear command clears a breakpoint. If <bpnum> is specified, only the requested "
+ "breakpoint is cleared, otherwise all breakpoints are cleared.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "bpclear 3\n"
+ " Clear breakpoint index 3.\n"
+ "\n"
+ "bpclear\n"
+ " Clear all breakpoints.\n"
+ },
+ {
+ "bpdisable",
+ "\n"
+ " bpdisable [<bpnum>]\n"
+ "\n"
+ "The bpdisable command disables a breakpoint. If <bpnum> is specified, only the requested "
+ "breakpoint is disabled, otherwise all breakpoints are disabled. Note that disabling a "
+ "breakpoint does not delete it, it just temporarily marks the breakpoint as inactive.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "bpdisable 3\n"
+ " Disable breakpoint index 3.\n"
+ "\n"
+ "bpdisable\n"
+ " Disable all breakpoints.\n"
+ },
+ {
+ "bpenable",
+ "\n"
+ " bpenable [<bpnum>]\n"
+ "\n"
+ "The bpenable command enables a breakpoint. If <bpnum> is specified, only the requested "
+ "breakpoint is enabled, otherwise all breakpoints are enabled.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "bpenable 3\n"
+ " Enable breakpoint index 3.\n"
+ "\n"
+ "bpenable\n"
+ " Enable all breakpoints.\n"
+ },
+ {
+ "bplist",
+ "\n"
+ " bplist\n"
+ "\n"
+ "The bplist command lists all the current breakpoints, along with their index and any "
+ "conditions or actions attached to them.\n"
+ },
+ {
+ "wpset",
+ "\n"
+ " wp[{d|i}][set] <address>,<length>,<type>[,<condition>[,<action>]]\n"
+ "\n"
+ "Sets a new watchpoint starting at the specified <address> and extending for <length>. The "
+ "inclusive range of the watchpoint is <address> through <address> + <length> - 1. The 'wpset' "
+ "command sets a watchpoint on program memory; the 'wpdset' command sets a watchpoint on data "
+ "memory; and the 'wpiset' sets a watchpoint on I/O memory. The <type> parameter specifies "
+ "which sort of accesses to trap on. It can be one of three values: 'r' for a read watchpoint "
+ "'w' for a write watchpoint, and 'rw' for a read/write watchpoint.\n"
+ "\n"
+ "The optional <condition> parameter lets you specify an expression that will be evaluated each "
+ "time the watchpoint is hit. If the result of the expression is true (non-zero), the watchpoint "
+ "will actually halt execution; otherwise, execution will continue with no notification. The "
+ "optional <action> parameter provides a command that is executed whenever the watchpoint is hit "
+ "and the <condition> is true. Note that you may need to embed the action within braces { } in "
+ "order to prevent commas and semicolons from being interpreted as applying to the wpset command "
+ "itself. Each watchpoint that is set is assigned an index which can be used in other "
+ "watchpoint commands to reference this watchpoint.\n"
+ "\n"
+ "In order to help <condition> expressions, two variables are available. For all watchpoints, "
+ "the variable 'wpaddr' is set to the address that actually triggered the watchpoint. For write "
+ "watchpoints, the variable 'wpdata' is set to the data that is being written.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "wp 1234,6,rw\n"
+ " Set a watchpoint that will halt execution whenever a read or write occurs in the address "
+ "range 1234-1239 inclusive.\n"
+ "\n"
+ "wp 23456,a,w,wpdata == 1\n"
+ " Set a watchpoint that will halt execution whenever a write occurs in the address range "
+ "23456-2345f AND the data written is equal to 1.\n"
+ "\n"
+ "wp 3456,20,r,1,{printf \"Read @ %08X\\n\",wpaddr; g}\n"
+ " Set a watchpoint that will halt execution whenever a read occurs in the address range "
+ "3456-3475. When this happens, print Read @ <wpaddr> and continue executing.\n"
+ "\n"
+ "temp0 = 0; wp 45678,1,writeval==f0,{temp0++; g}\n"
+ " Set a watchpoint that will halt execution whenever a write occurs to the address 45678 AND "
+ "the value being written is equal to f0. When that happens, increment the variable temp0 and "
+ "resume execution.\n"
+ },
+ {
+ "wpclear",
+ "\n"
+ " wpclear [<wpnum>]\n"
+ "\n"
+ "The wpclear command clears a watchpoint. If <wpnum> is specified, only the requested "
+ "watchpoint is cleared, otherwise all watchpoints are cleared.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "wpclear 3\n"
+ " Clear watchpoint index 3.\n"
+ "\n"
+ "wpclear\n"
+ " Clear all watchpoints.\n"
+ },
+ {
+ "wpdisable",
+ "\n"
+ " wpdisable [<wpnum>]\n"
+ "\n"
+ "The wpdisable command disables a watchpoint. If <wpnum> is specified, only the requested "
+ "watchpoint is disabled, otherwise all watchpoints are disabled. Note that disabling a "
+ "watchpoint does not delete it, it just temporarily marks the watchpoint as inactive.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "wpdisable 3\n"
+ " Disable watchpoint index 3.\n"
+ "\n"
+ "wpdisable\n"
+ " Disable all watchpoints.\n"
+ },
+ {
+ "wpenable",
+ "\n"
+ " wpenable [<wpnum>]\n"
+ "\n"
+ "The wpenable command enables a watchpoint. If <wpnum> is specified, only the requested "
+ "watchpoint is enabled, otherwise all watchpoints are enabled.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "wpenable 3\n"
+ " Enable watchpoint index 3.\n"
+ "\n"
+ "wpenable\n"
+ " Enable all watchpoints.\n"
+ },
+ {
+ "wplist",
+ "\n"
+ " wplist\n"
+ "\n"
+ "The wplist command lists all the current watchpoints, along with their index and any "
+ "conditions or actions attached to them.\n"
+ },
+ {
+ "hotspot",
+ "\n"
+ " hotspot [<cpunum>,[<depth>[,<hits>]]]\n"
+ "\n"
+ "The hotspot command attempts to help locate hotspots in the code where speedup opportunities "
+ "might be present. <cpunum>, which defaults to the currently active CPU, specified which "
+ "processor's memory to track. <depth>, which defaults to 64, controls the depth of the search "
+ "buffer. The search buffer tracks the last <depth> memory reads from unique PCs. The <hits> "
+ "parameter, which defaults to 250, specifies the minimum number of hits to report.\n"
+ "\n"
+ "The basic theory of operation is like this: each memory read is trapped by the debugger and "
+ "logged in the search buffer according to the address which was read and the PC that executed "
+ "the opcode. If the search buffer already contains a matching entry, that entry's count is "
+ "incremented and the entry is moved to the top of the list. If the search buffer does not "
+ "contain a matching entry, the entry from the bottom of the list is removed, and a new entry "
+ "is created at the top with an initial count of 1. Entries which fall off the bottom are "
+ "examined and if their count is larger than <hits>, they are reported to the debugger "
+ "console.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "hotspot 0,10\n"
+ " Looks for hotspots on CPU 0 using a search buffer of 16 entries, reporting any entries which "
+ "end up with 250 or more hits.\n"
+ "\n"
+ "hotspot 1,40,#1000\n"
+ " Looks for hotspots on CPU 1 using a search buffer of 64 entries, reporting any entries which "
+ "end up with 1000 or more hits.\n"
+ },
+ {
+ "map",
+ "\n"
+ " map[{d|i}] <address>\n"
+ "\n"
+ "The map/mapd/mapi commands map a logical address in memory to the correct physical address, as "
+ "well as specifying the bank. 'map' will map program space memory, while 'mapd' will map data space "
+ "memory and 'mapi' will map I/O space memory.\n"
+ "\n"
+ "Example:\n"
+ "\n"
+ "map 152d0\n"
+ " Gives physical address and bank for logical address 152d0 in program memory\n"
+ },
+ {
+ "memdump",
+ "\n"
+ " memdump [<filename>]\n"
+ "\n"
+ "Dumps the current memory map to <filename>. If <filename> is omitted, then dumps\n"
+ "to memdump.log"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "memdump mylog.log\n"
+ " Dumps memory to mylog.log.\n"
+ "\n"
+ "memdump\n"
+ " Dumps memory to memdump.log.\n"
+ },
+ {
+ "comadd",
+ "\n"
+ " comadd[//] <address>,<comment>\n"
+ "\n"
+ "Adds a string <comment> to the disassembled code at <address>. The shortcut for this command is simply "
+ "'//'\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "comadd 0, hello world.\n"
+ " Adds the comment 'hello world.' to the code at address 0x0\n"
+ "\n"
+ "// 10, undocumented opcode!\n"
+ " Adds the comment 'undocumented opcode!' to the code at address 0x10\n"
+ "\n"
+ },
+ {
+ "comsave",
+ "\n"
+ " comsave\n"
+ "\n"
+ "Saves the working comments to the driver's XML comment file.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "comsave\n"
+ " Saves the comments to the driver's comment file\n"
+ "\n"
+ },
+ {
+ "comdelete",
+ "\n"
+ " comdelete\n"
+ "\n"
+ "Deletes the comment at the specified memory offset. "
+ "The comment which is deleted is in the currently active memory bank.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "comdelete 10\n"
+ " Deletes the comment at code address 0x10 (using the current memory bank settings)\n"
+ "\n"
+ }
+};
+
+
+
+/***************************************************************************
+ CODE
+***************************************************************************/
+
+const char *debug_get_help(const char *tag)
+{
+ static char ambig_message[1024];
+ help_item *found = NULL;
+ int i, msglen, foundcount = 0;
+ int taglen = (int)strlen(tag);
+ char tagcopy[256];
+
+ /* make a lowercase copy of the tag */
+ for (i = 0; i <= taglen; i++)
+ tagcopy[i] = tolower(tag[i]);
+
+ /* find a match */
+ for (i = 0; i < sizeof(static_help_list) / sizeof(static_help_list[0]); i++)
+ if (!strncmp(static_help_list[i].tag, tagcopy, taglen))
+ {
+ foundcount++;
+ found = &static_help_list[i];
+ if (strlen(found->tag) == taglen)
+ {
+ foundcount = 1;
+ break;
+ }
+ }
+
+ /* only a single match makes sense */
+ if (foundcount == 1)
+ return found->help;
+
+ /* if not found, return the first entry */
+ if (foundcount == 0)
+ return static_help_list[0].help;
+
+ /* otherwise, indicate ambiguous help */
+ msglen = sprintf(ambig_message, "Ambiguous help request, did you mean:\n");
+ for (i = 0; i < sizeof(static_help_list) / sizeof(static_help_list[0]); i++)
+ if (!strncmp(static_help_list[i].tag, tagcopy, taglen))
+ msglen += sprintf(&ambig_message[msglen], " help %s?\n", static_help_list[i].tag);
+ return ambig_message;
+}
+
diff --git a/src/emu/debug/debughlp.h b/src/emu/debug/debughlp.h
new file mode 100644
index 00000000000..a2d9f022da6
--- /dev/null
+++ b/src/emu/debug/debughlp.h
@@ -0,0 +1,23 @@
+/*********************************************************************
+
+ debughlp.h
+
+ Debugger help engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#ifndef __DEBUGHLP_H__
+#define __DEBUGHLP_H__
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* help management */
+const char * debug_get_help(const char *tag);
+
+#endif
diff --git a/src/emu/debug/debugvw.c b/src/emu/debug/debugvw.c
new file mode 100644
index 00000000000..2814591cba5
--- /dev/null
+++ b/src/emu/debug/debugvw.c
@@ -0,0 +1,3187 @@
+/*********************************************************************
+
+ debugvw.c
+
+ Debugger view engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "debugvw.h"
+#include "debugcmd.h"
+#include "debugcmt.h"
+#include "debugcpu.h"
+#include "debugcon.h"
+#include "express.h"
+#include "textbuf.h"
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define DEFAULT_DASM_LINES (1000)
+#define DEFAULT_DASM_WIDTH (50)
+#define DASM_MAX_BYTES (16)
+#define MEM_MAX_LINE_WIDTH (1024)
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* debug_view_callbacks contains calbacks specific to a given view */
+typedef struct _debug_view_callbacks debug_view_callbacks;
+struct _debug_view_callbacks
+{
+ int (*alloc)(debug_view *); /* allocate memory */
+ void (*free)(debug_view *); /* free memory */
+ void (*update)(debug_view *); /* update contents */
+ void (*getprop)(debug_view *, UINT32, debug_property_info *value); /* get property */
+ void (*setprop)(debug_view *, UINT32, debug_property_info value); /* set property */
+};
+
+
+/* debug_view describes a single text-based view */
+/* typedef struct _debug_view debug_view -- defined in debugvw.h */
+struct _debug_view
+{
+ debug_view * next; /* link to the next view */
+ UINT8 type; /* type of view */
+ void * extra_data; /* extra view-specific data */
+ debug_view_callbacks cb; /* callback for this view */
+ void * osd_private_data; /* OSD-managed private data */
+
+ /* visibility info */
+ UINT32 visible_rows; /* number of currently visible rows */
+ UINT32 visible_cols; /* number of currently visible columns */
+ UINT32 total_rows; /* total number of rows */
+ UINT32 total_cols; /* total number of columns */
+ UINT32 top_row; /* current top row */
+ UINT32 left_col; /* current left column */
+ UINT32 supports_cursor; /* does this view support a cursor? */
+ UINT32 cursor_visible; /* is the cursor visible? */
+ UINT32 cursor_row; /* cursor row */
+ UINT32 cursor_col; /* cursor column */
+
+ /* update info */
+ UINT8 update_level; /* update level; updates when this hits 0 */
+ UINT8 update_pending; /* true if there is a pending update */
+ void (*update_func)(debug_view *);/* callback for the update */
+ debug_view_char *viewdata; /* current array of view data */
+ int viewdata_size; /* number of elements of the viewdata array */
+};
+
+
+/* debug_view_registers contains data specific to a register view */
+typedef struct _debug_view_register debug_view_register;
+struct _debug_view_register
+{
+ UINT64 lastval; /* last value */
+ UINT64 currval; /* current value */
+ UINT32 regnum; /* index */
+ UINT8 tagstart; /* starting tag char */
+ UINT8 taglen; /* number of tag chars */
+ UINT8 valstart; /* starting value char */
+ UINT8 vallen; /* number of value chars */
+};
+
+
+typedef struct _debug_view_registers debug_view_registers;
+struct _debug_view_registers
+{
+ UINT8 recompute; /* do we need to recompute the layout the next change? */
+ UINT8 cpunum; /* target CPU number */
+ int divider; /* dividing column */
+ UINT32 last_update; /* execution counter at last update */
+ debug_view_register reg[MAX_REGS]; /* register data */
+};
+
+
+/* debug_view_disasm contains data specific to a disassembly view */
+typedef struct _debug_view_disasm debug_view_disasm;
+struct _debug_view_disasm
+{
+ UINT8 recompute; /* do we need to recompute the layout the next change? */
+ UINT8 cpunum; /* target CPU number */
+ UINT8 right_column; /* right column? */
+ UINT32 backwards_steps; /* number of backwards steps */
+ UINT32 dasm_width; /* width of the disassembly area */
+ UINT8 * last_opcode_base; /* last opcode base */
+ UINT8 * last_opcode_arg_base; /* last opcode arg base */
+ UINT32 last_change_count; /* last comment change count */
+ offs_t last_pcbyte; /* last PC byte value */
+ UINT32 active_address; /* the address cursor_row is pointing to */
+ int divider1, divider2; /* left and right divider columns */
+ int divider3; /* comment divider column */
+ UINT8 live_tracking; /* track the value of the live expression? */
+ UINT64 last_result; /* last result from the expression */
+ parsed_expression *expression; /* expression to compute */
+ char * expression_string; /* copy of the expression string */
+ UINT8 expression_dirty; /* true if the expression needs to be re-evaluated */
+ UINT32 allocated_rows; /* allocated rows */
+ UINT32 allocated_cols; /* allocated columns */
+ offs_t * address; /* addresses of the instructions */
+ char * dasm; /* disassembled instructions */
+};
+
+
+/* debug_view_memory contains data specific to a memory view */
+typedef struct _debug_view_memory debug_view_memory;
+struct _debug_view_memory
+{
+ UINT8 recompute; /* do we need to recompute the layout the next change? */
+ UINT8 cpunum; /* target CPU number */
+ int divider1, divider2; /* left and right divider columns */
+ UINT8 spacenum; /* target address space */
+ UINT8 bytes_per_chunk; /* bytes per unit */
+ UINT16 chunks_displayed; /* number of chunks displayed per line */
+ UINT8 reverse_view; /* reverse-endian view? */
+ UINT8 ascii_view; /* display ASCII characters? */
+ UINT8 live_tracking; /* track the value of the live expression? */
+ UINT8 byte_offset; /* byte offset within each row */
+ UINT8 no_translation; /* don't run addresses through the cpu translation hook */
+ UINT64 last_result; /* last result from the expression */
+ parsed_expression *expression; /* expression to compute */
+ char * expression_string; /* copy of the expression string */
+ UINT8 expression_dirty; /* true if the expression needs to be re-evaluated */
+ void * raw_base; /* base of raw memory view (overrides CPU/space) */
+ UINT32 raw_length; /* length of raw memory view */
+ UINT8 raw_offset_xor; /* xor to apply to offsets */
+ UINT8 raw_little_endian; /* little endian data? */
+};
+
+
+/* debug_view_textbuf contains data specific to a textbuffer view */
+typedef struct _debug_view_textbuf debug_view_textbuf;
+struct _debug_view_textbuf
+{
+ text_buffer * textbuf; /* pointer to the text buffer */
+ UINT8 at_bottom; /* are we tracking new stuff being added? */
+ UINT32 topseq; /* sequence number of the top line */
+};
+
+
+
+/***************************************************************************
+ LOCAL VARIABLES
+***************************************************************************/
+
+static debug_view *first_view;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int console_alloc(debug_view *view);
+
+static int log_alloc(debug_view *view);
+
+static int registers_alloc(debug_view *view);
+static void registers_free(debug_view *view);
+static void registers_update(debug_view *view);
+static void registers_getprop(debug_view *view, UINT32 property, debug_property_info *value);
+static void registers_setprop(debug_view *view, UINT32 property, debug_property_info value);
+
+static int disasm_alloc(debug_view *view);
+static void disasm_free(debug_view *view);
+static void disasm_update(debug_view *view);
+static void disasm_getprop(debug_view *view, UINT32 property, debug_property_info *value);
+static void disasm_setprop(debug_view *view, UINT32 property, debug_property_info value);
+
+static int memory_alloc(debug_view *view);
+static void memory_free(debug_view *view);
+static void memory_update(debug_view *view);
+static void memory_getprop(debug_view *view, UINT32 property, debug_property_info *value);
+static void memory_setprop(debug_view *view, UINT32 property, debug_property_info value);
+
+static int textbuf_alloc(debug_view *view, text_buffer *textbuf);
+static void textbuf_free(debug_view *view);
+static void textbuf_update(debug_view *view);
+static void textbuf_getprop(debug_view *view, UINT32 property, debug_property_info *value);
+static void textbuf_setprop(debug_view *view, UINT32 property, debug_property_info value);
+
+static const debug_view_callbacks callback_table[] =
+{
+ { NULL, NULL, NULL, NULL, NULL },
+ { console_alloc, textbuf_free, textbuf_update, textbuf_getprop, textbuf_setprop },
+ { registers_alloc, registers_free, registers_update, registers_getprop, registers_setprop },
+ { disasm_alloc, disasm_free, disasm_update, disasm_getprop, disasm_setprop },
+ { memory_alloc, memory_free, memory_update, memory_getprop, memory_setprop },
+ { log_alloc, textbuf_free, textbuf_update, textbuf_getprop, textbuf_setprop }
+};
+
+
+
+/***************************************************************************
+
+ Initialization and shutdown
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_view_init - initializes the view system
+-------------------------------------------------*/
+
+void debug_view_init(running_machine *machine)
+{
+ /* reset the initial list */
+ first_view = NULL;
+ add_exit_callback(machine, debug_view_exit);
+}
+
+
+/*-------------------------------------------------
+ debug_view_exit - exits the view system
+-------------------------------------------------*/
+
+void debug_view_exit(running_machine *machine)
+{
+ /* kill all the views */
+ while (first_view != NULL)
+ debug_view_free(first_view);
+}
+
+
+
+/***************************************************************************
+
+ View creation/deletion
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_view_alloc - allocate a new debug
+ view
+-------------------------------------------------*/
+
+debug_view *debug_view_alloc(int type)
+{
+ debug_view *view;
+
+ /* allocate memory for the view */
+ view = malloc(sizeof(*view));
+ if (!view)
+ return NULL;
+ memset(view, 0, sizeof(*view));
+
+ /* set the view type information */
+ view->type = type;
+ view->cb = callback_table[type];
+
+ /* set up some reasonable defaults */
+ view->visible_rows = 10;
+ view->visible_cols = 10;
+ view->total_rows = 10;
+ view->total_cols = 10;
+
+ /* allocate memory for the buffer */
+ view->viewdata_size = view->visible_rows*view->visible_cols;
+ view->viewdata = malloc(sizeof(view->viewdata[0]) * view->viewdata_size);
+ if (!view->viewdata)
+ {
+ free(view);
+ return NULL;
+ }
+
+ /* allocate extra memory */
+ if (view->cb.alloc && !(*view->cb.alloc)(view))
+ {
+ free(view->viewdata);
+ free(view);
+ return NULL;
+ }
+
+ /* link it in */
+ view->next = first_view;
+ first_view = view;
+
+ return view;
+}
+
+
+/*-------------------------------------------------
+ debug_view_free - free a debug view
+-------------------------------------------------*/
+
+void debug_view_free(debug_view *view)
+{
+ debug_view *curview, *prevview;
+
+ /* find the view */
+ for (prevview = NULL, curview = first_view; curview != NULL; prevview = curview, curview = curview->next)
+ if (curview == view)
+ {
+ /* unlink */
+ if (prevview != NULL)
+ prevview->next = curview->next;
+ else
+ first_view = curview->next;
+
+ /* free memory */
+ if (view->cb.free)
+ (*view->cb.free)(view);
+ if (view->viewdata)
+ free(view->viewdata);
+ free(view);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Property management
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_view_get_property - return the value
+ of a given property
+-------------------------------------------------*/
+
+void debug_view_get_property(debug_view *view, int property, debug_property_info *value)
+{
+ switch (property)
+ {
+ case DVP_VISIBLE_ROWS:
+ value->i = view->visible_rows;
+ break;
+
+ case DVP_VISIBLE_COLS:
+ value->i = view->visible_cols;
+ break;
+
+ case DVP_TOTAL_ROWS:
+ value->i = view->total_rows;
+ break;
+
+ case DVP_TOTAL_COLS:
+ value->i = view->total_cols;
+ break;
+
+ case DVP_TOP_ROW:
+ value->i = view->top_row;
+ break;
+
+ case DVP_LEFT_COL:
+ value->i = view->left_col;
+ break;
+
+ case DVP_UPDATE_CALLBACK:
+ value->f = (genf *) view->update_func;
+ break;
+
+ case DVP_VIEW_DATA:
+ value->p = (void *) view->viewdata;
+ break;
+
+ case DVP_SUPPORTS_CURSOR:
+ value->i = view->supports_cursor;
+ break;
+
+ case DVP_CURSOR_VISIBLE:
+ value->i = view->cursor_visible;
+ break;
+
+ case DVP_CURSOR_ROW:
+ value->i = view->cursor_row;
+ break;
+
+ case DVP_CURSOR_COL:
+ value->i = view->cursor_col;
+ break;
+
+ case DVP_OSD_PRIVATE:
+ value->p = view->osd_private_data;
+ break;
+
+ default:
+ if (view->cb.getprop)
+ (*view->cb.getprop)(view, property, value);
+ else
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_view_set_property - set the value
+ of a given property
+-------------------------------------------------*/
+
+void debug_view_set_property(debug_view *view, int property, debug_property_info value)
+{
+ switch (property)
+ {
+ case DVP_VISIBLE_ROWS:
+ if (value.i != view->visible_rows)
+ {
+ debug_view_begin_update(view);
+ view->visible_rows = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_VISIBLE_COLS:
+ if (value.i != view->visible_cols)
+ {
+ debug_view_begin_update(view);
+ view->visible_cols = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_TOTAL_ROWS:
+ if (value.i != view->total_rows)
+ {
+ debug_view_begin_update(view);
+ view->total_rows = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_TOTAL_COLS:
+ if (value.i != view->total_cols)
+ {
+ debug_view_begin_update(view);
+ view->total_cols = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_TOP_ROW:
+ if (value.i != view->top_row)
+ {
+ debug_view_begin_update(view);
+ view->top_row = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_LEFT_COL:
+ if (value.i != view->left_col)
+ {
+ debug_view_begin_update(view);
+ view->left_col = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_UPDATE_CALLBACK:
+ debug_view_begin_update(view);
+ view->update_func = (void (*)(debug_view *)) value.f;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_VIEW_DATA:
+ /* read-only */
+ break;
+
+ case DVP_SUPPORTS_CURSOR:
+ /* read-only */
+ break;
+
+ case DVP_CURSOR_VISIBLE:
+ if (value.i != view->cursor_visible)
+ {
+ debug_view_begin_update(view);
+ view->cursor_visible = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_CURSOR_ROW:
+ if (value.i != view->cursor_row)
+ {
+ debug_view_begin_update(view);
+ view->cursor_row = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ if (view->type == DVT_DISASSEMBLY)
+ {
+ debug_view_disasm *dasmdata = view->extra_data;
+ dasmdata->active_address = dasmdata->address[view->cursor_row];
+ }
+ break;
+
+ case DVP_CURSOR_COL:
+ if (value.i != view->cursor_col)
+ {
+ debug_view_begin_update(view);
+ view->cursor_col = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_OSD_PRIVATE:
+ view->osd_private_data = value.p;
+ break;
+
+ default:
+ if (view->cb.setprop)
+ (*view->cb.setprop)(view, property, value);
+ else
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Update management
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_view_begin_update - bracket a sequence
+ of changes so that only one update occurs
+-------------------------------------------------*/
+
+void debug_view_begin_update(debug_view *view)
+{
+ /* bump the level */
+ view->update_level++;
+}
+
+
+/*-------------------------------------------------
+ debug_view_end_update - bracket a sequence
+ of changes so that only one update occurs
+-------------------------------------------------*/
+
+void debug_view_end_update(debug_view *view)
+{
+ /* if we hit zero, call the update function */
+ if (view->update_level == 1)
+ {
+ while (view->update_pending)
+ {
+ int size;
+
+ /* no longer pending */
+ view->update_pending = 0;
+
+ /* resize the viewdata if needed */
+ size = view->visible_rows*view->visible_cols;
+ if (size > view->viewdata_size)
+ {
+ view->viewdata_size = size;
+ view->viewdata = realloc(view->viewdata, sizeof(view->viewdata[0]) * view->viewdata_size);
+ }
+
+ /* update the view */
+ if (view->cb.update)
+ (*view->cb.update)(view);
+
+ /* update the owner */
+ if (view->update_func)
+ (*view->update_func)(view);
+ }
+ }
+
+ /* decrement the level */
+ view->update_level--;
+}
+
+
+/*-------------------------------------------------
+ debug_view_update_all - force all views to
+ refresh
+-------------------------------------------------*/
+
+void debug_view_update_all(void)
+{
+ debug_view *view;
+
+ /* loop over each view and force an update */
+ for (view = first_view; view != NULL; view = view->next)
+ {
+ debug_view_begin_update(view);
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_view_update_type - force all views of
+ a given type to refresh
+-------------------------------------------------*/
+
+void debug_view_update_type(int type)
+{
+ debug_view *view;
+
+ /* loop over each view and force an update */
+ for (view = first_view; view != NULL; view = view->next)
+ if (view->type == type)
+ {
+ debug_view_begin_update(view);
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Console view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ console_alloc - allocate memory for the log view
+-------------------------------------------------*/
+
+static int console_alloc(debug_view *view)
+{
+ return textbuf_alloc(view, debug_console_get_textbuf());
+}
+
+
+
+/***************************************************************************
+
+ Log view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ log_alloc - allocate memory for the log view
+-------------------------------------------------*/
+
+static int log_alloc(debug_view *view)
+{
+ return textbuf_alloc(view, debug_errorlog_get_textbuf());
+}
+
+
+
+/***************************************************************************
+
+ Generic text buffer view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ textbuf_alloc - allocate memory for a text
+ buffer view
+-------------------------------------------------*/
+
+static int textbuf_alloc(debug_view *view, text_buffer *textbuf)
+{
+ debug_view_textbuf *textdata;
+
+ /* allocate memory */
+ textdata = malloc(sizeof(*textdata));
+ if (!textdata)
+ return 0;
+ memset(textdata, 0, sizeof(*textdata));
+
+ /* by default we track live */
+ textdata->textbuf = textbuf;
+ textdata->at_bottom = TRUE;
+
+ /* stash the extra data pointer */
+ view->extra_data = textdata;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ textbuf_free - free memory for the log view
+-------------------------------------------------*/
+
+static void textbuf_free(debug_view *view)
+{
+ debug_view_textbuf *textdata = view->extra_data;
+
+ /* free any memory we callocated */
+ if (textdata)
+ free(textdata);
+ view->extra_data = NULL;
+}
+
+
+/*-------------------------------------------------
+ textbuf_update - update the log view
+-------------------------------------------------*/
+
+static void textbuf_update(debug_view *view)
+{
+ debug_view_textbuf *textdata = view->extra_data;
+ debug_view_char *dest = view->viewdata;
+ UINT32 curseq = 0, row;
+
+ /* update the console info */
+ view->total_rows = text_buffer_num_lines(textdata->textbuf);
+ view->total_cols = text_buffer_max_width(textdata->textbuf);
+ if (view->total_cols < 80)
+ view->total_cols = 80;
+
+ /* determine the starting sequence number */
+ if (!textdata->at_bottom)
+ {
+ curseq = textdata->topseq;
+ if (!text_buffer_get_seqnum_line(textdata->textbuf, curseq))
+ textdata->at_bottom = TRUE;
+ }
+ if (textdata->at_bottom)
+ {
+ curseq = text_buffer_line_index_to_seqnum(textdata->textbuf, view->total_rows - 1);
+ if (view->total_rows < view->visible_rows)
+ curseq -= view->total_rows - 1;
+ else
+ curseq -= view->visible_rows - 1;
+ }
+ view->top_row = curseq - text_buffer_line_index_to_seqnum(textdata->textbuf, 0);
+
+ /* loop over visible rows */
+ for (row = 0; row < view->visible_rows; row++)
+ {
+ const char *line = text_buffer_get_seqnum_line(textdata->textbuf, curseq++);
+ UINT32 col = 0;
+
+ /* if this visible row is valid, add it to the buffer */
+ if (line != NULL)
+ {
+ size_t len = strlen(line);
+ UINT32 effcol = view->left_col;
+
+ /* copy data */
+ while (col < view->visible_cols && effcol < len)
+ {
+ dest->byte = line[effcol++];
+ dest->attrib = DCA_NORMAL;
+ dest++;
+ col++;
+ }
+ }
+
+ /* fill the rest with blanks */
+ while (col < view->visible_cols)
+ {
+ dest->byte = ' ';
+ dest->attrib = DCA_NORMAL;
+ dest++;
+ col++;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ textbuf_getprop - return the value
+ of a given property
+-------------------------------------------------*/
+
+static void textbuf_getprop(debug_view *view, UINT32 property, debug_property_info *value)
+{
+ debug_view_textbuf *textdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_TEXTBUF_LINE_LOCK:
+ value->i = textdata->at_bottom ? (UINT32)-1 : textdata->topseq - text_buffer_line_index_to_seqnum(textdata->textbuf, 0);
+ break;
+
+ default:
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ textbuf_setprop - set the value
+ of a given property
+-------------------------------------------------*/
+
+static void textbuf_setprop(debug_view *view, UINT32 property, debug_property_info value)
+{
+ debug_view_textbuf *textdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_TEXTBUF_LINE_LOCK:
+ if (value.i == (UINT32)-1)
+ {
+ if (!textdata->at_bottom)
+ {
+ debug_view_begin_update(view);
+ textdata->at_bottom = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ }
+ else
+ {
+ UINT32 seq = text_buffer_line_index_to_seqnum(textdata->textbuf, value.i);
+ if (seq != textdata->topseq || textdata->at_bottom)
+ {
+ debug_view_begin_update(view);
+ textdata->topseq = seq;
+ textdata->at_bottom = FALSE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ }
+ break;
+
+ default:
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Registers view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ registers_alloc - allocate memory for the
+ registers view
+-------------------------------------------------*/
+
+static int registers_alloc(debug_view *view)
+{
+ debug_view_registers *regdata;
+
+ /* allocate memory */
+ regdata = malloc(sizeof(*regdata));
+ if (!regdata)
+ return 0;
+ memset(regdata, 0, sizeof(*regdata));
+
+ /* initialize */
+ regdata->recompute = TRUE;
+
+ /* stash the extra data pointer */
+ view->extra_data = regdata;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ registers_free - free memory for the
+ registers view
+-------------------------------------------------*/
+
+static void registers_free(debug_view *view)
+{
+ debug_view_registers *regdata = view->extra_data;
+
+ /* free any memory we callocated */
+ if (regdata)
+ free(regdata);
+ view->extra_data = NULL;
+}
+
+
+/*-------------------------------------------------
+ add_register - adds a register to the
+ registers view
+-------------------------------------------------*/
+
+static void add_register(debug_view *view, int regnum, const char *str)
+{
+ debug_view_registers *regdata = view->extra_data;
+ int tagstart, taglen, valstart, vallen;
+ const char *colon;
+
+ colon = strchr(str, ':');
+
+ /* if no colon, mark everything as tag */
+ if (!colon)
+ {
+ tagstart = 0;
+ taglen = (int)strlen(str);
+ valstart = 0;
+ vallen = 0;
+ }
+
+ /* otherwise, break the string at the colon */
+ else
+ {
+ tagstart = 0;
+ taglen = colon - str;
+ valstart = (colon + 1) - str;
+ vallen = (int)strlen(colon + 1);
+ }
+
+ /* now trim spaces */
+ while (isspace(str[tagstart]) && taglen > 0)
+ tagstart++, taglen--;
+ while (isspace(str[tagstart + taglen - 1]) && taglen > 0)
+ taglen--;
+ while (isspace(str[valstart]) && vallen > 0)
+ valstart++, vallen--;
+ while (isspace(str[valstart + vallen - 1]) && vallen > 0)
+ vallen--;
+ if (str[valstart] == '!')
+ valstart++, vallen--;
+
+ /* note the register number and info */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = cpunum_get_reg(regdata->cpunum, regnum);
+ regdata->reg[view->total_rows].regnum = regnum;
+ regdata->reg[view->total_rows].tagstart = tagstart;
+ regdata->reg[view->total_rows].taglen = taglen;
+ regdata->reg[view->total_rows].valstart = valstart;
+ regdata->reg[view->total_rows].vallen = vallen;
+ view->total_rows++;
+
+ /* adjust the divider and total cols, if necessary */
+ regdata->divider = MAX(regdata->divider, 1 + taglen + 1);
+ view->total_cols = MAX(view->total_cols, 1 + taglen + 2 + vallen + 1);
+}
+
+
+/*-------------------------------------------------
+ registers_recompute - recompute all info
+ for the registers view
+-------------------------------------------------*/
+
+static void registers_recompute(debug_view *view)
+{
+ debug_view_registers *regdata = view->extra_data;
+ const int *list = cpunum_debug_register_list(regdata->cpunum);
+ int regnum, maxtaglen, maxvallen;
+
+ /* reset the view parameters */
+ view->top_row = 0;
+ view->left_col = 0;
+ view->total_rows = 0;
+ view->total_cols = 0;
+ regdata->divider = 0;
+
+ /* add a cycles entry: cycles:99999999 */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS + 1;
+ regdata->reg[view->total_rows].tagstart = 0;
+ regdata->reg[view->total_rows].taglen = 6;
+ regdata->reg[view->total_rows].valstart = 7;
+ regdata->reg[view->total_rows].vallen = 8;
+ maxtaglen = regdata->reg[view->total_rows].taglen;
+ maxvallen = regdata->reg[view->total_rows].vallen;
+ view->total_rows++;
+
+ /* add a beam entry: beamx:123 */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS + 2;
+ regdata->reg[view->total_rows].tagstart = 0;
+ regdata->reg[view->total_rows].taglen = 5;
+ regdata->reg[view->total_rows].valstart = 6;
+ regdata->reg[view->total_rows].vallen = 3;
+ maxtaglen = MAX(maxtaglen, regdata->reg[view->total_rows].taglen);
+ maxvallen = MAX(maxvallen, regdata->reg[view->total_rows].vallen);
+ view->total_rows++;
+
+ /* add a beam entry: beamy:456 */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS + 3;
+ regdata->reg[view->total_rows].tagstart = 0;
+ regdata->reg[view->total_rows].taglen = 5;
+ regdata->reg[view->total_rows].valstart = 6;
+ regdata->reg[view->total_rows].vallen = 3;
+ maxtaglen = MAX(maxtaglen, regdata->reg[view->total_rows].taglen);
+ maxvallen = MAX(maxvallen, regdata->reg[view->total_rows].vallen);
+ view->total_rows++;
+
+ /* add a flags entry: flags:xxxxxxxx */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS + 4;
+ regdata->reg[view->total_rows].tagstart = 0;
+ regdata->reg[view->total_rows].taglen = 5;
+ regdata->reg[view->total_rows].valstart = 6;
+ regdata->reg[view->total_rows].vallen = (UINT32)strlen(cpunum_flags(regdata->cpunum));
+ maxtaglen = MAX(maxtaglen, regdata->reg[view->total_rows].taglen);
+ maxvallen = MAX(maxvallen, regdata->reg[view->total_rows].vallen);
+ view->total_rows++;
+
+ /* add a divider entry */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS;
+ view->total_rows++;
+
+ /* set the current divider and total cols */
+ regdata->divider = 1 + maxtaglen + 1;
+ view->total_cols = 1 + maxtaglen + 2 + maxvallen + 1;
+
+ /* add all registers into it */
+ for (regnum = 0; regnum < MAX_REGS; regnum++)
+ {
+ const char *str = NULL;
+ int regid;
+
+ /* identify the register id */
+ regid = list ? list[regnum] : regnum;
+ if (regid < 0)
+ break;
+
+ /* retrieve the string for this register */
+ str = cpunum_reg_string(regdata->cpunum, regid);
+
+ /* did we get a string? */
+ if (str && str[0] != '\0' && str[0] != '~')
+ add_register(view, regid, str);
+ }
+
+ /* no longer need to recompute */
+ regdata->recompute = FALSE;
+}
+
+
+/*-------------------------------------------------
+ registers_update - update the contents of
+ the register view
+-------------------------------------------------*/
+
+static void registers_update(debug_view *view)
+{
+ UINT32 execution_counter = debug_get_execution_counter();
+ debug_view_registers *regdata = view->extra_data;
+ debug_view_char *dest = view->viewdata;
+ UINT32 row, i;
+ int scrnum = 0;
+
+ /* cannot update if no active CPU */
+ if (cpu_getactivecpu() < 0)
+ return;
+
+ /* if our assumptions changed, revisit them */
+ if (regdata->recompute)
+ registers_recompute(view);
+
+ /* loop over visible rows */
+ for (row = 0; row < view->visible_rows; row++)
+ {
+ UINT32 effrow = view->top_row + row;
+ UINT32 col = 0;
+
+ /* if this visible row is valid, add it to the buffer */
+ if (effrow < view->total_rows)
+ {
+ debug_view_register *reg = &regdata->reg[effrow];
+ UINT32 effcol = view->left_col;
+ char temp[256], dummy[100];
+ UINT8 attrib = DCA_NORMAL;
+ UINT32 len = 0;
+ char *data = dummy;
+
+ /* get the effective string */
+ dummy[0] = 0;
+ if (reg->regnum >= MAX_REGS)
+ {
+ reg->lastval = reg->currval;
+ switch (reg->regnum)
+ {
+ case MAX_REGS:
+ reg->tagstart = reg->valstart = reg->vallen = 0;
+ reg->taglen = view->total_cols;
+ for (i = 0; i < view->total_cols; i++)
+ dummy[i] = '-';
+ dummy[i] = 0;
+ break;
+
+ case MAX_REGS + 1:
+ sprintf(dummy, "cycles:%-8d", activecpu_get_icount());
+ reg->currval = activecpu_get_icount();
+ break;
+
+ case MAX_REGS + 2:
+ if (video_screen_exists(scrnum))
+ sprintf(dummy, "beamx:%3d", video_screen_get_hpos(scrnum));
+ break;
+
+ case MAX_REGS + 3:
+ if (video_screen_exists(scrnum))
+ sprintf(dummy, "beamy:%3d", video_screen_get_vpos(scrnum));
+ break;
+
+ case MAX_REGS + 4:
+ sprintf(dummy, "flags:%s", activecpu_flags());
+ break;
+ }
+ }
+ else
+ {
+ data = (char *)cpunum_reg_string(regdata->cpunum, reg->regnum);
+ if (regdata->last_update != execution_counter)
+ reg->lastval = reg->currval;
+ reg->currval = cpunum_get_reg(regdata->cpunum, reg->regnum);
+ }
+
+ /* see if we changed */
+ if (reg->lastval != reg->currval)
+ attrib = DCA_CHANGED;
+
+ /* build up a string */
+ if (reg->taglen < regdata->divider - 1)
+ {
+ memset(&temp[len], ' ', regdata->divider - 1 - reg->taglen);
+ len += regdata->divider - 1 - reg->taglen;
+ }
+
+ memcpy(&temp[len], &data[reg->tagstart], reg->taglen);
+ len += reg->taglen;
+
+ temp[len++] = ' ';
+ temp[len++] = ' ';
+
+ memcpy(&temp[len], &data[reg->valstart], reg->vallen);
+ len += reg->vallen;
+
+ temp[len++] = ' ';
+ temp[len] = 0;
+
+ /* copy data */
+ while (col < view->visible_cols && effcol < len)
+ {
+ dest->byte = temp[effcol++];
+ dest->attrib = attrib | ((effcol <= regdata->divider) ? DCA_ANCILLARY : DCA_NORMAL);
+ dest++;
+ col++;
+ }
+ }
+
+ /* fill the rest with blanks */
+ while (col < view->visible_cols)
+ {
+ dest->byte = ' ';
+ dest->attrib = DCA_NORMAL;
+ dest++;
+ col++;
+ }
+ }
+
+ /* remember the last update */
+ regdata->last_update = execution_counter;
+}
+
+
+/*-------------------------------------------------
+ registers_getprop - return the value
+ of a given property
+-------------------------------------------------*/
+
+static void registers_getprop(debug_view *view, UINT32 property, debug_property_info *value)
+{
+ debug_view_registers *regdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_REGS_CPUNUM:
+ value->i = regdata->cpunum;
+ break;
+
+ default:
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ registers_getprop - set the value
+ of a given property
+-------------------------------------------------*/
+
+static void registers_setprop(debug_view *view, UINT32 property, debug_property_info value)
+{
+ debug_view_registers *regdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_REGS_CPUNUM:
+ if (value.i != regdata->cpunum)
+ {
+ debug_view_begin_update(view);
+ regdata->cpunum = value.i;
+ regdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ default:
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Disassembly view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ disasm_alloc - allocate disasm for the
+ disassembly view
+-------------------------------------------------*/
+
+static int disasm_alloc(debug_view *view)
+{
+ debug_view_disasm *dasmdata;
+ int total_comments = 0;
+ int i;
+
+ /* allocate disasm */
+ dasmdata = malloc(sizeof(*dasmdata));
+ if (!dasmdata)
+ return 0;
+ memset(dasmdata, 0, sizeof(*dasmdata));
+
+ /* count the number of comments */
+ for (i = 0; i < cpu_gettotalcpu(); i++)
+ total_comments += debug_comment_get_count(i);
+
+ /* initialize */
+ dasmdata->recompute = TRUE;
+ dasmdata->right_column = (total_comments > 0) ? DVP_DASM_RIGHTCOL_COMMENTS : DVP_DASM_RIGHTCOL_RAW;
+ dasmdata->backwards_steps = 3;
+ dasmdata->dasm_width = DEFAULT_DASM_WIDTH;
+ dasmdata->active_address = 0;
+
+ /* stash the extra data pointer */
+ view->total_rows = DEFAULT_DASM_LINES;
+ view->extra_data = dasmdata;
+
+ /* we support cursors */
+ view->supports_cursor = TRUE;
+
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ disasm_free - free disasm for the
+ disassembly view
+-------------------------------------------------*/
+
+static void disasm_free(debug_view *view)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+
+ /* free any disasm we callocated */
+ if (dasmdata)
+ {
+ if (dasmdata->expression)
+ expression_free(dasmdata->expression);
+ if (dasmdata->expression_string)
+ free(dasmdata->expression_string);
+ if (dasmdata->address)
+ free(dasmdata->address);
+ if (dasmdata->dasm)
+ free(dasmdata->dasm);
+ free(dasmdata);
+ }
+ view->extra_data = NULL;
+}
+
+
+/*-------------------------------------------------
+ disasm_back_up - back up the specified number
+ of instructions from the given PC
+-------------------------------------------------*/
+
+static offs_t disasm_back_up(int cpunum, const debug_cpu_info *cpuinfo, offs_t startpc, int numinstrs)
+{
+ int minlen = BYTE2ADDR(activecpu_min_instruction_bytes(), cpuinfo, ADDRESS_SPACE_PROGRAM);
+ int maxlen = BYTE2ADDR(activecpu_max_instruction_bytes(), cpuinfo, ADDRESS_SPACE_PROGRAM);
+ UINT32 addrmask = cpuinfo->space[ADDRESS_SPACE_PROGRAM].logaddrmask;
+ offs_t curpc, lastgoodpc = startpc, temppc;
+ UINT8 opbuf[1024], argbuf[1024];
+ char dasmbuffer[100];
+
+ /* compute the increment */
+ if (minlen == 0) minlen = 1;
+ if (maxlen == 0) maxlen = 1;
+
+ /* start off numinstrs back */
+ curpc = startpc - minlen * numinstrs;
+ if (curpc > startpc)
+ curpc = 0;
+
+ /* prefetch the opcode bytes */
+ for (temppc = curpc; temppc < startpc; temppc++)
+ {
+ opbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, FALSE);
+ argbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, TRUE);
+ }
+
+ /* loop until we hit it */
+ while (1)
+ {
+ offs_t testpc, nextcurpc, instlen, instcount = 0;
+
+ /* loop until we get past the target instruction */
+ for (testpc = curpc; testpc < startpc; testpc += instlen)
+ {
+ /* convert PC to a byte offset */
+ offs_t pcbyte = ADDR2BYTE_MASKED(testpc, cpuinfo, ADDRESS_SPACE_PROGRAM);
+
+ /* get the disassembly, but only if mapped */
+ instlen = 1;
+ if (!cpuinfo->translate || (*cpuinfo->translate)(ADDRESS_SPACE_PROGRAM, &pcbyte))
+ instlen = activecpu_dasm(dasmbuffer, testpc & addrmask, &opbuf[1000 + testpc - startpc], &argbuf[1000 + testpc - startpc]) & DASMFLAG_LENGTHMASK;
+
+ /* count this one */
+ instcount++;
+ }
+
+ /* if we ended up right on startpc, this is a good candidate */
+ if (testpc == startpc && instcount <= numinstrs)
+ lastgoodpc = curpc;
+
+ /* we're also done if we go back too far */
+ if (startpc - curpc >= numinstrs * maxlen)
+ break;
+
+ /* and if we hit 0, we're done */
+ if (curpc == 0)
+ break;
+
+ /* back up one more and try again */
+ nextcurpc = curpc - minlen;
+ if (nextcurpc > startpc)
+ nextcurpc = 0;
+
+ /* prefetch the opcode bytes */
+ for (temppc = nextcurpc; temppc < curpc; temppc++)
+ {
+ opbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, FALSE);
+ argbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, TRUE);
+ }
+
+ /* update curpc once we're done fetching */
+ curpc = nextcurpc;
+ }
+
+ return lastgoodpc;
+}
+
+
+/*-------------------------------------------------
+ disasm_generate_bytes - generate the opcode
+ byte values
+-------------------------------------------------*/
+
+static void disasm_generate_bytes(offs_t pcbyte, int numbytes, const debug_cpu_info *cpuinfo, int minbytes, char *string, int maxchars, int encrypted)
+{
+ int byte, offset = 0;
+ UINT64 val;
+
+ switch (minbytes)
+ {
+ case 1:
+ if (maxchars >= 2)
+ offset = sprintf(string, "%02X", (UINT32)debug_read_opcode(pcbyte, 1, FALSE));
+ for (byte = 1; byte < numbytes && offset + 3 < maxchars; byte++)
+ offset += sprintf(&string[offset], " %02X", (UINT32)debug_read_opcode(pcbyte + byte, 1, encrypted));
+ break;
+
+ case 2:
+ if (maxchars >= 4)
+ offset = sprintf(string, "%04X", (UINT32)debug_read_opcode(pcbyte, 2, FALSE));
+ for (byte = 2; byte < numbytes && offset + 5 < maxchars; byte += 2)
+ offset += sprintf(&string[offset], " %04X", (UINT32)debug_read_opcode(pcbyte + byte, 2, encrypted));
+ break;
+
+ case 4:
+ if (maxchars >= 8)
+ offset = sprintf(string, "%08X", (UINT32)debug_read_opcode(pcbyte, 4, FALSE));
+ for (byte = 4; byte < numbytes && offset + 9 < maxchars; byte += 4)
+ offset += sprintf(&string[offset], " %08X", (UINT32)debug_read_opcode(pcbyte + byte, 4, encrypted));
+ break;
+
+ case 8:
+ val = debug_read_opcode(pcbyte, 8, FALSE);
+ if (maxchars >= 16)
+ offset = sprintf(string, "%08X%08X", (UINT32)(val >> 32), (UINT32)val);
+ for (byte = 8; byte < numbytes && offset + 17 < maxchars; byte += 8)
+ {
+ val = debug_read_opcode(pcbyte + byte, 8, encrypted);
+ offset += sprintf(&string[offset], " %08X%08X", (UINT32)(val >> 32), (UINT32)val);
+ }
+ break;
+
+ default:
+ fatalerror("disasm_generate_bytes: unknown size = %d", minbytes);
+ break;
+ }
+
+ /* if we ran out of room, indicate more */
+ string[maxchars - 1] = 0;
+ if (byte < numbytes && maxchars > 3)
+ string[maxchars - 2] = string[maxchars - 3] = string[maxchars - 4] = '.';
+}
+
+
+/*-------------------------------------------------
+ disasm_recompute - recompute selected info
+ for the disassembly view
+-------------------------------------------------*/
+
+static int disasm_recompute(debug_view *view, offs_t pc, int startline, int lines, int original_cpunum)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(dasmdata->cpunum);
+ int chunksize, minbytes, maxbytes, maxbytes_clamped;
+ int changed = FALSE;
+ UINT32 addrmask;
+ int line;
+
+ /* switch to the context of the CPU in question */
+ addrmask = cpuinfo->space[ADDRESS_SPACE_PROGRAM].logaddrmask;
+
+ /* determine how many characters we need for an address and set the divider */
+ dasmdata->divider1 = 1 + cpuinfo->space[ADDRESS_SPACE_PROGRAM].logchars + 1;
+
+ /* assume a fixed number of characters for the disassembly */
+ dasmdata->divider2 = dasmdata->divider1 + 1 + dasmdata->dasm_width + 1;
+
+ /* determine how many bytes we might need to display */
+ minbytes = activecpu_min_instruction_bytes();
+ maxbytes = activecpu_max_instruction_bytes();
+
+ /* set the width of the third column according to display mode */
+ if (dasmdata->right_column == DVP_DASM_RIGHTCOL_RAW || dasmdata->right_column == DVP_DASM_RIGHTCOL_ENCRYPTED)
+ {
+ chunksize = activecpu_databus_width(ADDRESS_SPACE_PROGRAM) / 8;
+ maxbytes_clamped = maxbytes;
+ if (maxbytes_clamped > DASM_MAX_BYTES)
+ maxbytes_clamped = DASM_MAX_BYTES;
+ view->total_cols = dasmdata->divider2 + 1 + 2 * maxbytes_clamped + (maxbytes_clamped / minbytes - 1) + 1;
+ }
+ else if (dasmdata->right_column == DVP_DASM_RIGHTCOL_COMMENTS)
+ view->total_cols = dasmdata->divider2 + 1 + 50; /* DEBUG_COMMENT_MAX_LINE_LENGTH */
+ else
+ view->total_cols = dasmdata->divider2 + 1;
+
+ /* reallocate memory if we don't have enough */
+ if (dasmdata->allocated_rows < view->total_rows || dasmdata->allocated_cols < view->total_cols)
+ {
+ /* update our values */
+ dasmdata->allocated_rows = view->total_rows;
+ dasmdata->allocated_cols = view->total_cols;
+
+ /* allocate address array */
+ if (dasmdata->address)
+ free(dasmdata->address);
+ dasmdata->address = malloc_or_die(sizeof(dasmdata->address[0]) * dasmdata->allocated_rows);
+
+ /* allocate disassembly buffer */
+ if (dasmdata->dasm)
+ free(dasmdata->dasm);
+ dasmdata->dasm = malloc_or_die(sizeof(dasmdata->dasm[0]) * dasmdata->allocated_rows * dasmdata->allocated_cols);
+ }
+
+ /* iterate over lines */
+ for (line = 0; line < lines; line++)
+ {
+ offs_t pcbyte, tempaddr;
+ char buffer[100];
+ int numbytes = 0;
+ int instr = startline + line;
+ char oldbuf[100];
+ char *destbuf = &dasmdata->dasm[instr * dasmdata->allocated_cols];
+
+ /* convert PC to a byte offset */
+ pcbyte = ADDR2BYTE_MASKED(pc, cpuinfo, ADDRESS_SPACE_PROGRAM);
+
+ /* save a copy of the previous line as a backup if we're only doing one line */
+ if (lines == 1)
+ strncpy(oldbuf, destbuf, MIN(sizeof(oldbuf), dasmdata->allocated_cols));
+
+ /* convert back and set the address of this instruction */
+ dasmdata->address[instr] = pcbyte; // ! This might make more sense as the following : BYTE2ADDR(pcbyte, cpuinfo, ADDRESS_SPACE_PROGRAM); !
+ sprintf(&destbuf[0], " %0*X ", cpuinfo->space[ADDRESS_SPACE_PROGRAM].logchars, BYTE2ADDR(pcbyte, cpuinfo, ADDRESS_SPACE_PROGRAM));
+
+ /* make sure we can translate the address */
+ tempaddr = pcbyte;
+ if (!cpuinfo->translate || (*cpuinfo->translate)(ADDRESS_SPACE_PROGRAM, &tempaddr))
+ {
+ UINT8 opbuf[64], argbuf[64];
+
+ /* fetch the bytes up to the maximum */
+ for (numbytes = 0; numbytes < maxbytes; numbytes++)
+ {
+ opbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, FALSE);
+ argbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, TRUE);
+ }
+
+ /* disassemble the result */
+ pc += numbytes = activecpu_dasm(buffer, pc & addrmask, opbuf, argbuf) & DASMFLAG_LENGTHMASK;
+ }
+ else
+ sprintf(buffer, "<unmapped>");
+
+ sprintf(&destbuf[dasmdata->divider1 + 1], "%-*s ", dasmdata->dasm_width, buffer);
+
+ if (dasmdata->right_column == DVP_DASM_RIGHTCOL_RAW || dasmdata->right_column == DVP_DASM_RIGHTCOL_ENCRYPTED)
+ {
+ /* get the bytes */
+ numbytes = ADDR2BYTE(numbytes, cpuinfo, ADDRESS_SPACE_PROGRAM);
+ disasm_generate_bytes(pcbyte, numbytes, cpuinfo, minbytes, &destbuf[dasmdata->divider2], dasmdata->allocated_cols - dasmdata->divider2, dasmdata->right_column == DVP_DASM_RIGHTCOL_ENCRYPTED);
+ }
+ else if (dasmdata->right_column == DVP_DASM_RIGHTCOL_COMMENTS)
+ {
+ offs_t comment_address = BYTE2ADDR(dasmdata->address[instr], cpuinfo, ADDRESS_SPACE_PROGRAM) ;
+
+ /* get and add the comment */
+ if (debug_comment_get_text(cpu_getactivecpu(), comment_address, debug_comment_get_opcode_crc32(comment_address)) != 0x00)
+ {
+ int i ;
+ char bob[DEBUG_COMMENT_MAX_LINE_LENGTH] ;
+ char pre[8] ;
+
+ // Stick in the 'comment' symbol
+ sprintf(pre, "// ") ;
+ for (i = 0; i < strlen(pre); i++)
+ destbuf[dasmdata->divider2+i] = pre[i] ;
+
+ // Stick in the comment itself
+ strcpy(bob, debug_comment_get_text(cpu_getactivecpu(), comment_address, debug_comment_get_opcode_crc32(comment_address))) ;
+ for (i = 0; i < (dasmdata->allocated_cols - dasmdata->divider2 - strlen(pre) - 1); i++)
+ destbuf[dasmdata->divider2+i+strlen(pre)] = bob[i] ;
+ }
+ else
+ sprintf(&destbuf[dasmdata->divider2], " ");
+ }
+
+ /* see if the line changed at all */
+ if (lines == 1 && strncmp(oldbuf, destbuf, MIN(sizeof(oldbuf), dasmdata->allocated_cols)) != 0)
+ changed = TRUE;
+ }
+
+ /* reset the opcode base */
+ if (dasmdata->cpunum == original_cpunum)
+ memory_set_opbase(activecpu_get_physical_pc_byte());
+
+ /* update opcode base information */
+ dasmdata->last_opcode_base = opcode_base;
+ dasmdata->last_opcode_arg_base = opcode_arg_base;
+ dasmdata->last_change_count = debug_comment_all_change_count();
+
+ /* now longer need to recompute */
+ dasmdata->recompute = FALSE;
+ return changed;
+}
+
+
+/*-------------------------------------------------
+ disasm_update - update the contents of
+ the disassembly view
+-------------------------------------------------*/
+
+static void disasm_update(debug_view *view)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(dasmdata->cpunum);
+ offs_t pc = cpunum_get_reg(dasmdata->cpunum, REG_PC);
+ offs_t pcbyte = ADDR2BYTE_MASKED(pc, cpuinfo, ADDRESS_SPACE_PROGRAM);
+ debug_view_char *dest = view->viewdata;
+ int original_cpunum = cpu_getactivecpu();
+ int recomputed_this_time = FALSE;
+ EXPRERR exprerr;
+ UINT32 row;
+
+ /* switch to the CPU's context */
+ cpuintrf_push_context(dasmdata->cpunum);
+
+ /* if our expression is dirty, fix it */
+ if (dasmdata->expression_dirty && dasmdata->expression_string)
+ {
+ parsed_expression *expr;
+
+ /* parse the new expression */
+ exprerr = expression_parse(dasmdata->expression_string, debug_get_cpu_info(dasmdata->cpunum)->symtable, &expr);
+
+ /* if it worked, update the expression */
+ if (exprerr == EXPRERR_NONE)
+ {
+ if (dasmdata->expression)
+ expression_free(dasmdata->expression);
+ dasmdata->expression = expr;
+ }
+ }
+
+ /* if we're tracking a value, make sure it is visible */
+ if (dasmdata->expression && (dasmdata->live_tracking || dasmdata->expression_dirty))
+ {
+ UINT64 result;
+
+ /* recompute the value of the expression */
+ exprerr = expression_execute(dasmdata->expression, &result);
+ if (exprerr == EXPRERR_NONE && result != dasmdata->last_result)
+ {
+ offs_t resultbyte = ADDR2BYTE_MASKED(result, cpuinfo, ADDRESS_SPACE_PROGRAM);
+
+ /* update the result */
+ dasmdata->last_result = result;
+
+ /* see if the new result is an address we already have */
+ for (row = 0; row < dasmdata->allocated_rows; row++)
+ if (dasmdata->address[row] == resultbyte)
+ break;
+
+ /* if we didn't find it, or if it's really close to the bottom, recompute */
+ if (row == dasmdata->allocated_rows || row >= view->total_rows - view->visible_rows)
+ dasmdata->recompute = TRUE;
+
+ /* otherwise, if it's not visible, adjust the view so it is */
+ else if (row < view->top_row || row >= view->top_row + view->visible_rows - 2)
+ view->top_row = (row > 3) ? row - 3 : 0;
+ }
+
+ /* no longer dirty */
+ dasmdata->expression_dirty = FALSE;
+ }
+
+ /* if the opcode base has changed, rework things */
+ if (opcode_base != dasmdata->last_opcode_base || opcode_arg_base != dasmdata->last_opcode_arg_base)
+ dasmdata->recompute = TRUE;
+
+ /* if the comments have changed, redo it */
+ if (dasmdata->last_change_count != debug_comment_all_change_count())
+ dasmdata->recompute = TRUE;
+
+ /* if we need to recompute, do it */
+recompute:
+ if (dasmdata->recompute)
+ {
+ /* determine the addresses of what we will display */
+ offs_t backpc = disasm_back_up(dasmdata->cpunum, cpuinfo, (UINT32)dasmdata->last_result, dasmdata->backwards_steps);
+
+ /* recompute the view */
+ if (dasmdata->last_change_count != debug_comment_all_change_count())
+ {
+ /* smoosh us against the left column, but not the top row */
+ view->left_col = 0;
+
+ /* recompute from where we last recomputed! */
+ disasm_recompute(view, BYTE2ADDR(dasmdata->address[0], cpuinfo, ADDRESS_SPACE_PROGRAM), 0, view->total_rows, original_cpunum);
+ }
+ else
+ {
+ /* put ourselves back in the top left */
+ view->top_row = 0;
+ view->left_col = 0;
+
+ disasm_recompute(view, backpc, 0, view->total_rows, original_cpunum);
+ }
+ recomputed_this_time = TRUE;
+ }
+
+ /* figure out the row where the PC is and recompute the disassembly */
+ if (pcbyte != dasmdata->last_pcbyte)
+ {
+ /* find the row with the PC on it */
+ for (row = 0; row < view->visible_rows; row++)
+ {
+ UINT32 effrow = view->top_row + row;
+ if (effrow >= dasmdata->allocated_rows)
+ break;
+ if (pcbyte == dasmdata->address[effrow])
+ {
+ /* see if we changed */
+ int changed = disasm_recompute(view, pc, effrow, 1, original_cpunum);
+ if (changed && !recomputed_this_time)
+ {
+ dasmdata->recompute = TRUE;
+ goto recompute;
+ }
+
+ /* set the effective row and PC */
+ view->cursor_row = effrow;
+ dasmdata->active_address = pcbyte;
+ }
+ }
+ dasmdata->last_pcbyte = pcbyte;
+ }
+
+ /* loop over visible rows */
+ for (row = 0; row < view->visible_rows; row++)
+ {
+ UINT32 effrow = view->top_row + row;
+ UINT8 attrib = DCA_NORMAL;
+ debug_cpu_breakpoint *bp;
+ UINT32 col = 0;
+
+ /* if this visible row is valid, add it to the buffer */
+ if (effrow < dasmdata->allocated_rows)
+ {
+ const char *data = &dasmdata->dasm[effrow * dasmdata->allocated_cols];
+ UINT32 effcol = view->left_col;
+ UINT32 len = 0;
+
+ /* if we're on the line with the PC, recompute and hilight it */
+ if (pcbyte == dasmdata->address[effrow])
+ attrib = DCA_CURRENT;
+
+ /* if we're on a line with a breakpoint, tag it changed */
+ else
+ {
+ for (bp = cpuinfo->first_bp; bp; bp = bp->next)
+ if (dasmdata->address[effrow] == ADDR2BYTE_MASKED(bp->address, cpuinfo, ADDRESS_SPACE_PROGRAM))
+ attrib = DCA_CHANGED;
+ }
+
+ /* if we're on the active column and everything is couth, highlight it */
+ if (view->cursor_visible && effrow == view->cursor_row)
+ {
+ if (dasmdata->active_address == dasmdata->address[effrow])
+ attrib |= DCA_SELECTED;
+ }
+
+ /* get the effective string */
+ len = (UINT32)strlen(data);
+
+ /* copy data */
+ while (col < view->visible_cols && effcol < len)
+ {
+ dest->byte = data[effcol++];
+ dest->attrib = (effcol <= dasmdata->divider1 || effcol >= dasmdata->divider2) ? (attrib | DCA_ANCILLARY) : attrib;
+
+ /* comments are just green for now - maybe they shouldn't even be this? */
+ if (effcol >= dasmdata->divider2 && dasmdata->right_column == DVP_DASM_RIGHTCOL_COMMENTS)
+ attrib |= DCA_COMMENT;
+
+ dest++;
+ col++;
+ }
+ }
+
+ /* fill the rest with blanks */
+ while (col < view->visible_cols)
+ {
+ dest->byte = ' ';
+ dest->attrib = (effrow < view->total_rows) ? (attrib | DCA_ANCILLARY) : attrib;
+ dest++;
+ col++;
+ }
+ }
+
+ /* restore the original CPU context */
+ cpuintrf_pop_context();
+}
+
+
+/*-------------------------------------------------
+ disasm_handle_char - handle a character typed
+ within the current view
+-------------------------------------------------*/
+
+static void disasm_handle_char(debug_view *view, char chval)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+ UINT8 end_buffer = 3;
+ INT32 temp;
+
+ switch (chval)
+ {
+ case DCH_UP:
+ if (view->cursor_row > 0)
+ view->cursor_row--;
+ break;
+
+ case DCH_DOWN:
+ if (view->cursor_row < view->total_rows - 1)
+ view->cursor_row++;
+ break;
+
+ case DCH_PUP:
+ temp = view->cursor_row - (view->visible_rows - end_buffer);
+
+ if (temp < 0)
+ view->cursor_row = 0;
+ else
+ view->cursor_row = temp;
+ break;
+
+ case DCH_PDOWN:
+ temp = view->cursor_row + (view->visible_rows - end_buffer);
+
+ if (temp > (view->total_rows - 1))
+ view->cursor_row = (view->total_rows - 1);
+ else
+ view->cursor_row = temp;
+ break;
+
+ case DCH_HOME: /* set the active column to the PC */
+ {
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(dasmdata->cpunum);
+ offs_t pc = cpunum_get_reg(dasmdata->cpunum, REG_PC);
+ int i;
+
+ pc = ADDR2BYTE_MASKED(pc, cpuinfo, ADDRESS_SPACE_PROGRAM);
+
+ /* figure out which row the pc is on */
+ for (i = 0; i < dasmdata->allocated_rows; i++)
+ {
+ if (dasmdata->address[i] == pc)
+ view->cursor_row = i;
+ }
+ break;
+ }
+
+ case DCH_CTRLHOME:
+ view->cursor_row = 0;
+ break;
+
+ case DCH_CTRLEND:
+ view->cursor_row = view->total_rows - 1;
+ break;
+ }
+
+ /* get the address under the cursor_row */
+ dasmdata->active_address = dasmdata->address[view->cursor_row];
+
+ /* scroll if out of range */
+ if (view->cursor_row < view->top_row)
+ view->top_row = view->cursor_row;
+ if (view->cursor_row >= view->top_row + view->visible_rows - end_buffer)
+ view->top_row = view->cursor_row - view->visible_rows + end_buffer;
+}
+
+
+/*-------------------------------------------------
+ disasm_getprop - return the value
+ of a given property
+-------------------------------------------------*/
+
+static void disasm_getprop(debug_view *view, UINT32 property, debug_property_info *value)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_DASM_CPUNUM:
+ value->i = dasmdata->cpunum;
+ break;
+
+ case DVP_DASM_EXPRESSION:
+ value->s = dasmdata->expression_string;
+ break;
+
+ case DVP_DASM_TRACK_LIVE:
+ value->i = dasmdata->live_tracking;
+ break;
+
+ case DVP_DASM_RIGHT_COLUMN:
+ value->i = dasmdata->right_column;
+ break;
+
+ case DVP_DASM_BACKWARD_STEPS:
+ value->i = dasmdata->backwards_steps;
+ break;
+
+ case DVP_DASM_WIDTH:
+ value->i = dasmdata->dasm_width;
+ break;
+
+ case DVP_DASM_ACTIVE_ADDRESS:
+ value->i = dasmdata->active_address;
+ break;
+
+ default:
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ disasm_setprop - set the value
+ of a given property
+-------------------------------------------------*/
+
+static void disasm_setprop(debug_view *view, UINT32 property, debug_property_info value)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_DASM_CPUNUM:
+ if (value.i != dasmdata->cpunum)
+ {
+ debug_view_begin_update(view);
+ dasmdata->cpunum = value.i;
+
+ /* we need to recompute the expression in the context of the new CPU */
+ dasmdata->expression_dirty = TRUE;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_DASM_EXPRESSION:
+ debug_view_begin_update(view);
+
+ /* free the old expression string and allocate a new one */
+ if (dasmdata->expression_string)
+ free(dasmdata->expression_string);
+ dasmdata->expression_string = malloc(strlen(value.s) + 1);
+ if (dasmdata->expression_string)
+ strcpy(dasmdata->expression_string, value.s);
+
+ /* update everything as a result */
+ dasmdata->expression_dirty = TRUE;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_DASM_TRACK_LIVE:
+ if (value.i != dasmdata->live_tracking)
+ {
+ debug_view_begin_update(view);
+ dasmdata->live_tracking = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_DASM_RIGHT_COLUMN:
+ if (value.i != dasmdata->right_column && value.i >= DVP_DASM_RIGHTCOL_NONE && value.i <= DVP_DASM_RIGHTCOL_COMMENTS)
+ {
+ debug_view_begin_update(view);
+ dasmdata->right_column = value.i;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_DASM_BACKWARD_STEPS:
+ if (value.i != dasmdata->backwards_steps)
+ {
+ debug_view_begin_update(view);
+ dasmdata->backwards_steps = value.i;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_DASM_WIDTH:
+ if (value.i != dasmdata->dasm_width)
+ {
+ debug_view_begin_update(view);
+ dasmdata->dasm_width = value.i;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_CHARACTER:
+ debug_view_begin_update(view);
+ disasm_handle_char(view, value.i);
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_DASM_ACTIVE_ADDRESS:
+ debug_view_begin_update(view);
+ dasmdata->active_address = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ default:
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_disasm_update_all - force all disasm
+ views to update
+-------------------------------------------------*/
+
+void debug_disasm_update_all(void)
+{
+ debug_view *view;
+
+ /* this is brute force */
+ for (view = first_view; view != NULL; view = view->next)
+ if (view->type == DVT_DISASSEMBLY)
+ {
+ debug_view_disasm *dasmdata = view->extra_data;
+ debug_view_begin_update(view);
+ view->update_pending = TRUE;
+ dasmdata->recompute = TRUE;
+ dasmdata->last_pcbyte = ~0;
+ debug_view_end_update(view);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Memory view
+
+***************************************************************************/
+
+/*
+00000000 00 11 22 33 44 55 66 77-88 99 aa bb cc dd ee ff 0123456789abcdef
+00000000 0011 2233 4455 6677- 8899 aabb ccdd eeff 0123456789abcdef
+00000000 00112233 44556677 - 8899aabb ccddeeff 0123456789abcdef
+00000000 0011223344556677 - 8899aabbccddeeff 0123456789abcdef
+*/
+
+/*-------------------------------------------------
+ memory_alloc - allocate memory for the
+ memory view
+-------------------------------------------------*/
+
+static int memory_alloc(debug_view *view)
+{
+ debug_view_memory *memdata;
+
+ /* allocate memory */
+ memdata = malloc(sizeof(*memdata));
+ if (!memdata)
+ return 0;
+ memset(memdata, 0, sizeof(*memdata));
+
+ /* by default we track live */
+ memdata->live_tracking = TRUE;
+ memdata->ascii_view = TRUE;
+
+ /* stash the extra data pointer */
+ view->extra_data = memdata;
+
+ /* we support cursors */
+ view->supports_cursor = TRUE;
+
+ /* start out with 16 bytes in a single column */
+ memdata->chunks_displayed = 16;
+
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ memory_free - free memory for the
+ memory view
+-------------------------------------------------*/
+
+static void memory_free(debug_view *view)
+{
+ debug_view_memory *memdata = view->extra_data;
+
+ /* free any memory we callocated */
+ if (memdata)
+ {
+ if (memdata->expression)
+ expression_free(memdata->expression);
+ if (memdata->expression_string)
+ free(memdata->expression_string);
+ free(memdata);
+ }
+ view->extra_data = NULL;
+}
+
+
+/*-------------------------------------------------
+ memory_get_cursor_pos - return the cursor
+ position as an address and a shift value
+-------------------------------------------------*/
+
+static int memory_get_cursor_pos(debug_view *view, offs_t *address, UINT8 *shift)
+{
+ debug_view_memory *memdata = view->extra_data;
+ int curx = view->cursor_col, cury = view->cursor_row;
+ UINT32 bytes_per_row;
+ int modval;
+
+ /* if not in the middle section, punt */
+ if (curx <= memdata->divider1)
+ curx = memdata->divider1 + 1;
+ if (curx >= memdata->divider2)
+ curx = memdata->divider2 - 1;
+ curx -= memdata->divider1;
+
+ /* compute the base address */
+ bytes_per_row = memdata->chunks_displayed * memdata->bytes_per_chunk;
+ *address = bytes_per_row * cury + memdata->byte_offset;
+
+ /* the rest depends on the current format */
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ modval = curx % 3;
+ if (modval == 0) modval = 1;
+ modval -= 1;
+ if (!memdata->reverse_view)
+ *address += curx / 3;
+ else
+ *address += 15 - curx / 3;
+ *shift = 8-4 - 4 * modval;
+ break;
+
+ case 2:
+ modval = curx % 6;
+ if (modval <= 1) modval = 2;
+ modval -= 2;
+ if (!memdata->reverse_view)
+ *address += 2 * (curx / 6);
+ else
+ *address += 14 - 2 * (curx / 6);
+ *shift = 16-4 - 4 * modval;
+ break;
+
+ case 4:
+ modval = curx % 12;
+ if (modval <= 2) modval = 3;
+ if (modval == 11) modval = 10;
+ modval -= 3;
+ if (!memdata->reverse_view)
+ *address += 4 * (curx / 12);
+ else
+ *address += 12 - 4 * (curx / 12);
+ *shift = 32-4 - 4 * modval;
+ break;
+
+ case 8:
+ modval = curx % 24;
+ if (modval <= 4) modval = 5;
+ if (modval >= 21) modval = 20;
+ modval -= 5;
+ if (!memdata->reverse_view)
+ *address += 8 * (curx / 24);
+ else
+ *address += 8 - 8 * (curx / 24);
+ *shift = 64-4 - 4 * modval;
+ break;
+ }
+
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ memory_set_cursor_pos - set the cursor
+ position as a function of an address and a
+ shift value
+-------------------------------------------------*/
+
+static void memory_set_cursor_pos(debug_view *view, offs_t address, UINT8 shift)
+{
+ debug_view_memory *memdata = view->extra_data;
+ UINT32 bytes_per_row;
+ int curx, cury;
+ UINT8 end_buffer = 2;
+
+ /* offset the address by the byte offset */
+ address -= memdata->byte_offset;
+
+ /* compute the y coordinate */
+ bytes_per_row = memdata->chunks_displayed * memdata->bytes_per_chunk;
+ cury = address / bytes_per_row;
+
+ /* the rest depends on the current format */
+
+ /* non-reverse case */
+ if (!memdata->reverse_view)
+ {
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ curx = memdata->divider1 + 1 + 3 * (address % bytes_per_row) + (1 - (shift / 4));
+ break;
+
+ case 2:
+ curx = memdata->divider1 + 2 + 6 * ((address % bytes_per_row) / 2) + (3 - (shift / 4));
+ break;
+
+ case 4:
+ curx = memdata->divider1 + 3 + 12 * ((address % bytes_per_row) / 4) + (7 - (shift / 4));
+ break;
+
+ case 8:
+ curx = memdata->divider1 + 5 + 24 * ((address % bytes_per_row) / 8) + (15 - (shift / 4));
+ break;
+ }
+ }
+ else
+ {
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ curx = memdata->divider1 + 1 + 3 * (15 - address % bytes_per_row) + (1 - (shift / 4));
+ break;
+
+ case 2:
+ curx = memdata->divider1 + 2 + 6 * (7 - (address % bytes_per_row) / 2) + (3 - (shift / 4));
+ break;
+
+ case 4:
+ curx = memdata->divider1 + 3 + 12 * (3 - (address % bytes_per_row) / 4) + (7 - (shift / 4));
+ break;
+
+ case 8:
+ curx = memdata->divider1 + 5 + 24 * (1 - (address % bytes_per_row) / 8) + (15 - (shift / 4));
+ break;
+ }
+ }
+
+ /* set the position, clamping to the window bounds */
+ view->cursor_col = (curx < 0) ? 0 : (curx >= view->total_cols) ? (view->total_cols - end_buffer) : curx;
+ view->cursor_row = (cury < 0) ? 0 : (cury >= view->total_rows) ? (view->total_rows - end_buffer) : cury;
+
+ /* scroll if out of range */
+ if (view->cursor_row < view->top_row)
+ view->top_row = view->cursor_row;
+ if (view->cursor_row >= view->top_row + view->visible_rows - end_buffer)
+ view->top_row = view->cursor_row - view->visible_rows + end_buffer;
+}
+
+
+/*-------------------------------------------------
+ memory_read_byte - generic byte reader
+-------------------------------------------------*/
+
+static UINT8 memory_read_byte(debug_view_memory *memdata, offs_t offs, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ return debug_read_byte(memdata->spacenum, offs, apply_translation);
+
+ /* all 0xff if out of bounds */
+ offs ^= memdata->raw_offset_xor;
+ if (offs >= memdata->raw_length)
+ return 0xff;
+ return *((UINT8 *)memdata->raw_base + offs);
+}
+
+
+/*-------------------------------------------------
+ memory_read_word - generic word reader
+-------------------------------------------------*/
+
+static UINT16 memory_read_word(debug_view_memory *memdata, offs_t offs, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ return debug_read_word(memdata->spacenum, offs, apply_translation);
+
+ /* otherwise, decompose into bytes */
+ if (memdata->raw_little_endian)
+ return memory_read_byte(memdata, offs + 0, apply_translation) | (memory_read_byte(memdata, offs + 1, apply_translation) << 8);
+ else
+ return memory_read_byte(memdata, offs + 1, apply_translation) | (memory_read_byte(memdata, offs + 0, apply_translation) << 8);
+}
+
+
+/*-------------------------------------------------
+ memory_read_dword - generic dword reader
+-------------------------------------------------*/
+
+static UINT32 memory_read_dword(debug_view_memory *memdata, offs_t offs, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ return debug_read_dword(memdata->spacenum, offs, apply_translation);
+
+ /* otherwise, decompose into words */
+ if (memdata->raw_little_endian)
+ return memory_read_word(memdata, offs + 0, apply_translation) | (memory_read_word(memdata, offs + 2, apply_translation) << 16);
+ else
+ return memory_read_word(memdata, offs + 2, apply_translation) | (memory_read_word(memdata, offs + 0, apply_translation) << 16);
+}
+
+
+/*-------------------------------------------------
+ memory_read_qword - generic qword reader
+-------------------------------------------------*/
+
+static UINT64 memory_read_qword(debug_view_memory *memdata, offs_t offs, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ return debug_read_qword(memdata->spacenum, offs, apply_translation);
+
+ /* otherwise, decompose into dwords */
+ if (memdata->raw_little_endian)
+ return memory_read_dword(memdata, offs + 0, apply_translation) | ((UINT64)memory_read_dword(memdata, offs + 4, apply_translation) << 32);
+ else
+ return memory_read_dword(memdata, offs + 4, apply_translation) | ((UINT64)memory_read_dword(memdata, offs + 0, apply_translation) << 32);
+}
+
+
+/*-------------------------------------------------
+ memory_write_byte - generic byte writer
+-------------------------------------------------*/
+
+static void memory_write_byte(debug_view_memory *memdata, offs_t offs, UINT8 data, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ {
+ debug_write_byte(memdata->spacenum, offs, data, apply_translation);
+ return;
+ }
+
+ /* ignore if out of bounds */
+ offs ^= memdata->raw_offset_xor;
+ if (offs >= memdata->raw_length)
+ return;
+ *((UINT8 *)memdata->raw_base + offs) = data;
+
+/* hack for FD1094 editing */
+#ifdef FD1094_HACK
+ if (memdata->raw_base == memory_region(REGION_USER2))
+ {
+ extern void fd1094_regenerate_key(void);
+ fd1094_regenerate_key();
+ }
+#endif
+}
+
+
+/*-------------------------------------------------
+ memory_write_word - generic word writer
+-------------------------------------------------*/
+
+static void memory_write_word(debug_view_memory *memdata, offs_t offs, UINT16 data, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ {
+ debug_write_word(memdata->spacenum, offs, data, apply_translation);
+ return;
+ }
+
+ /* otherwise, decompose into bytes */
+ if (memdata->raw_little_endian)
+ {
+ memory_write_byte(memdata, offs + 0, data, apply_translation);
+ memory_write_byte(memdata, offs + 1, data >> 8, apply_translation);
+ }
+ else
+ {
+ memory_write_byte(memdata, offs + 1, data, apply_translation);
+ memory_write_byte(memdata, offs + 0, data >> 8, apply_translation);
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_write_dword - generic dword writer
+-------------------------------------------------*/
+
+static void memory_write_dword(debug_view_memory *memdata, offs_t offs, UINT32 data, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ {
+ debug_write_dword(memdata->spacenum, offs, data, apply_translation);
+ return;
+ }
+
+ /* otherwise, decompose into words */
+ if (memdata->raw_little_endian)
+ {
+ memory_write_word(memdata, offs + 0, data, apply_translation);
+ memory_write_word(memdata, offs + 2, data >> 16, apply_translation);
+ }
+ else
+ {
+ memory_write_word(memdata, offs + 2, data, apply_translation);
+ memory_write_word(memdata, offs + 0, data >> 16, apply_translation);
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_write_qword - generic qword writer
+-------------------------------------------------*/
+
+static void memory_write_qword(debug_view_memory *memdata, offs_t offs, UINT64 data, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ {
+ debug_write_qword(memdata->spacenum, offs, data, apply_translation);
+ return;
+ }
+
+ /* otherwise, decompose into dwords */
+ if (memdata->raw_little_endian)
+ {
+ memory_write_dword(memdata, offs + 0, data, apply_translation);
+ memory_write_dword(memdata, offs + 4, data >> 32, apply_translation);
+ }
+ else
+ {
+ memory_write_dword(memdata, offs + 4, data, apply_translation);
+ memory_write_dword(memdata, offs + 0, data >> 32, apply_translation);
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_handle_char - handle a character typed
+ within the current view
+-------------------------------------------------*/
+
+static void memory_handle_char(debug_view *view, char chval)
+{
+ debug_view_memory *memdata = view->extra_data;
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(memdata->cpunum);
+ static const char hexvals[] = "0123456789abcdef";
+ char *hexchar = strchr(hexvals, tolower(chval));
+ UINT32 bytes_per_row;
+ UINT32 tempaddr;
+ offs_t maxaddr;
+ offs_t address;
+ UINT8 shift;
+
+ /* determine the max address */
+ maxaddr = memdata->raw_base ? (memdata->raw_length - 1) : cpuinfo->space[memdata->spacenum].logbytemask;
+
+ /* get the position */
+ if (!memory_get_cursor_pos(view, &address, &shift))
+ return;
+
+ /* handle the incoming key */
+ /* up/down work the same regardless */
+ bytes_per_row = memdata->chunks_displayed * memdata->bytes_per_chunk;
+
+ switch (chval)
+ {
+ case DCH_UP:
+ if (view->cursor_row > 0)
+ address -= bytes_per_row;
+ break;
+
+ case DCH_DOWN:
+ if (view->cursor_row < view->total_rows - 1)
+ address += bytes_per_row;
+ break;
+
+ case DCH_PUP:
+ tempaddr = address - (bytes_per_row * (view->visible_rows-2)) ;
+ if (tempaddr > address) /* unsigned wraparound */
+ address = address % bytes_per_row;
+ else
+ address = tempaddr;
+ break;
+
+ case DCH_PDOWN:
+ tempaddr = address + (bytes_per_row * (view->visible_rows-2)) ;
+ if (tempaddr > maxaddr)
+ address = (maxaddr - (bytes_per_row-1)) + (address % bytes_per_row);
+ else
+ address = tempaddr;
+ break;
+
+ case DCH_HOME:
+ address -= address % bytes_per_row;
+ shift = (memdata->bytes_per_chunk * 8) - 1;
+ break;
+
+ case DCH_CTRLHOME:
+ address = 0;
+ shift = (memdata->bytes_per_chunk * 8) - 1;
+ break;
+
+ case DCH_END:
+ address += (bytes_per_row - (address % bytes_per_row) - 1);
+ shift = 0;
+ break;
+
+ case DCH_CTRLEND:
+ address = maxaddr;
+ shift = 0;
+ break;
+
+ case DCH_CTRLRIGHT:
+ if (address < maxaddr-memdata->bytes_per_chunk)
+ address += memdata->bytes_per_chunk;
+ break;
+
+ case DCH_CTRLLEFT:
+ if (address >= memdata->bytes_per_chunk)
+ address -= memdata->bytes_per_chunk;
+ break;
+ }
+
+ /* switch off of the current chunk size */
+ cpuintrf_push_context(memdata->cpunum);
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ if (hexchar)
+ memory_write_byte(memdata, address, (memory_read_byte(memdata, address, !memdata->no_translation) & ~(0xf << shift)) | ((hexchar - hexvals) << shift), !memdata->no_translation);
+ if (hexchar || chval == DCH_RIGHT)
+ {
+ if (shift == 0) { shift = 8-4; if (address != maxaddr) address++; }
+ else shift -= 4;
+ }
+ else if (chval == DCH_LEFT)
+ {
+ if (shift == 8-4) { shift = 0; if (address != 0) address--; }
+ else shift += 4;
+ }
+ break;
+
+ case 2:
+ if (hexchar)
+ memory_write_word(memdata, address, (memory_read_word(memdata, address, !memdata->no_translation) & ~(0xf << shift)) | ((hexchar - hexvals) << shift), !memdata->no_translation);
+ if (hexchar || chval == DCH_RIGHT)
+ {
+ if (shift == 0) { shift = 16-4; if (address != maxaddr) address += 2; }
+ else shift -= 4;
+ }
+ else if (chval == DCH_LEFT)
+ {
+ if (shift == 16-4) { shift = 0; if (address != 0) address -= 2; }
+ else shift += 4;
+ }
+ break;
+
+ case 4:
+ if (hexchar)
+ memory_write_dword(memdata, address, (memory_read_dword(memdata, address, !memdata->no_translation) & ~(0xf << shift)) | ((hexchar - hexvals) << shift), !memdata->no_translation);
+ if (hexchar || chval == DCH_RIGHT)
+ {
+ if (shift == 0) { shift = 32-4; if (address != maxaddr) address += 4; }
+ else shift -= 4;
+ }
+ else if (chval == DCH_LEFT)
+ {
+ if (shift == 32-4) { shift = 0; if (address != 0) address -= 4; }
+ else shift += 4;
+ }
+ break;
+
+ case 8:
+ if (hexchar)
+ memory_write_qword(memdata, address, (memory_read_qword(memdata, address, !memdata->no_translation) & ~((UINT64)0xf << shift)) | ((UINT64)(hexchar - hexvals) << shift), !memdata->no_translation);
+ if (hexchar || chval == DCH_RIGHT)
+ {
+ if (shift == 0) { shift = 64-4; if (address != maxaddr) address += 8; }
+ else shift -= 4;
+ }
+ else if (chval == DCH_LEFT)
+ {
+ if (shift == 64-4) { shift = 0; if (address != 0) address -= 8; }
+ else shift += 4;
+ }
+ break;
+ }
+ cpuintrf_pop_context();
+
+ /* set a new position */
+ memory_set_cursor_pos(view, address, shift);
+}
+
+
+/*-------------------------------------------------
+ memory_update - update the contents of
+ the register view
+-------------------------------------------------*/
+
+static void memory_update(debug_view *view)
+{
+ debug_view_memory *memdata = view->extra_data;
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(memdata->cpunum);
+ debug_view_char *dest = view->viewdata;
+ char addrformat[16];
+ EXPRERR exprerr;
+ UINT8 addrchars;
+ UINT32 maxaddr;
+ offs_t addrmask;
+ UINT32 row;
+ UINT32 memory_display_width;
+ UINT32 bytes_per_line;
+
+ /* switch to the CPU's context */
+ if (memdata->raw_base == NULL)
+ cpuintrf_push_context(memdata->cpunum);
+
+ /* determine maximum address and number of characters for that */
+ if (memdata->raw_base != NULL)
+ {
+ maxaddr = memdata->raw_length - 1;
+ sprintf(addrformat, "%X", maxaddr);
+ addrchars = (UINT8)strlen(addrformat);
+ addrmask = maxaddr;
+ for (row = 0; row < 32; row++)
+ addrmask |= addrmask >> row;
+ }
+ else
+ {
+ maxaddr = cpuinfo->space[memdata->spacenum].logbytemask;
+ addrchars = cpuinfo->space[memdata->spacenum].logchars;
+ addrmask = cpuinfo->space[memdata->spacenum].logbytemask;
+
+ /* clamp the bytes per chunk */
+ if (memdata->bytes_per_chunk < (1 << cpuinfo->space[memdata->spacenum].addr2byte_lshift))
+ memdata->bytes_per_chunk = (1 << cpuinfo->space[memdata->spacenum].addr2byte_lshift);
+ }
+
+ /* determine how many characters we need for an address and set the divider */
+ sprintf(addrformat, " %*s%%0%dX ", 8 - addrchars, "", addrchars);
+
+ /* determine how wide the memory display area is */
+ bytes_per_line = memdata->chunks_displayed * memdata->bytes_per_chunk;
+ memory_display_width = 1 + (bytes_per_line * 3) + 1; /* characters + spaces */
+
+ /* compute total displayed rows and columns */
+ view->total_rows = (maxaddr / bytes_per_line) + 1;
+ view->total_cols = (1 + 8 + 1) + memory_display_width;
+ view->total_cols += memdata->ascii_view ? 1 + bytes_per_line : 0 ; /* +1 ??? */ /* 77 : 59; */
+
+ /* set up the dividers */
+ memdata->divider1 = 1 + 8 + 1;
+ memdata->divider2 = memdata->divider1 + memory_display_width;
+ if (memdata->reverse_view)
+ {
+ int temp = view->total_cols + 1 - memdata->divider2;
+ memdata->divider2 = view->total_cols + 1 - memdata->divider1;
+ memdata->divider1 = temp;
+ }
+
+ /* if our expression is dirty, fix it */
+ if (memdata->expression_dirty && memdata->expression_string)
+ {
+ parsed_expression *expr;
+
+ /* parse the new expression */
+ exprerr = expression_parse(memdata->expression_string, debug_get_cpu_info(memdata->cpunum)->symtable, &expr);
+
+ /* if it worked, update the expression */
+ if (exprerr == EXPRERR_NONE)
+ {
+ if (memdata->expression)
+ expression_free(memdata->expression);
+ memdata->expression = expr;
+ memdata->expression_dirty = FALSE;
+ memdata->recompute = TRUE;
+ }
+ }
+
+ /* if we're tracking a value, make sure it is visible */
+ if (memdata->expression && (memdata->live_tracking || memdata->recompute))
+ {
+ UINT64 result;
+
+ /* recompute the value of the expression */
+ exprerr = expression_execute(memdata->expression, &result);
+
+ /* reset the row number */
+ if (result != memdata->last_result || memdata->expression_dirty || memdata->cpunum != memdata->cpunum)
+ {
+ memdata->last_result = result;
+ if (memdata->raw_base == NULL)
+ result = ADDR2BYTE_MASKED(memdata->last_result, cpuinfo, memdata->spacenum);
+ view->top_row = result / bytes_per_line;
+ memdata->byte_offset = result % bytes_per_line;
+ view->cursor_row = view->top_row;
+ }
+ memdata->recompute = FALSE;
+ }
+
+ /* loop over visible rows */
+ for (row = 0; row < view->visible_rows; row++)
+ {
+ UINT32 effrow = view->top_row + row;
+ offs_t addrbyte = effrow * bytes_per_line + memdata->byte_offset;
+ UINT8 attrib = DCA_NORMAL;
+ UINT32 col = 0;
+
+ /* if this visible row is valid, add it to the buffer */
+ if (effrow < view->total_rows)
+ {
+ UINT32 effcol = view->left_col;
+ UINT32 len = 0;
+ char data[MEM_MAX_LINE_WIDTH];
+ int i;
+
+ /* generate the string */
+ if (!memdata->reverse_view)
+ {
+ len = sprintf(&data[len], addrformat, BYTE2ADDR(addrbyte & addrmask, cpuinfo, memdata->spacenum));
+ len += sprintf(&data[len], " ");
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ for (i = 0; i < memdata->chunks_displayed; i++)
+ {
+ offs_t curaddr = addrbyte + i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], "%02X ", memory_read_byte(memdata, addrbyte + i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], "** ");
+ }
+ break;
+
+ case 2:
+ for (i = 0; i < memdata->chunks_displayed; i++)
+ {
+ offs_t curaddr = addrbyte + 2 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], " %04X ", memory_read_word(memdata, addrbyte + 2 * i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], " **** ");
+ }
+ break;
+
+ case 4:
+ for (i = 0; i < memdata->chunks_displayed; i++)
+ {
+ offs_t curaddr = addrbyte + 4 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], " %08X ", memory_read_dword(memdata, addrbyte + 4 * i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], " ******** ");
+ }
+ break;
+
+ case 8:
+ for (i = 0; i < memdata->chunks_displayed; i++)
+ {
+ offs_t curaddr = addrbyte + 8 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ {
+ UINT64 qword = memory_read_qword(memdata, addrbyte + 8 * i, !memdata->no_translation);
+ len += sprintf(&data[len], " %08X%08X ", (UINT32)(qword >> 32), (UINT32)qword);
+ }
+ else
+ len += sprintf(&data[len], " **************** ");
+ }
+ break;
+ }
+ len += sprintf(&data[len], " ");
+ if (memdata->ascii_view)
+ {
+ for (i = 0; i < bytes_per_line; i++)
+ {
+ if (addrbyte + i <= maxaddr)
+ {
+ char c = memory_read_byte(memdata, addrbyte + i, !memdata->no_translation);
+ len += sprintf(&data[len], "%c", isprint((UINT8)c) ? c : '.');
+ }
+ else
+ len += sprintf(&data[len], " ");
+ }
+ len += sprintf(&data[len], " ");
+ }
+ }
+ else
+ {
+ len = sprintf(&data[len], " ");
+ if (memdata->ascii_view)
+ {
+ for (i = 0; i < bytes_per_line; i++)
+ {
+ if (addrbyte + i <= maxaddr)
+ {
+ char c = memory_read_byte(memdata, addrbyte + i, !memdata->no_translation);
+ len += sprintf(&data[len], "%c", isprint((UINT8)c) ? c : '.');
+ }
+ else
+ len += sprintf(&data[len], " ");
+ }
+ len += sprintf(&data[len], " ");
+ }
+ len += sprintf(&data[len], " ");
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ for (i = memdata->chunks_displayed - 1; i >= 0; i--)
+ {
+ offs_t curaddr = addrbyte + i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], "%02X ", memory_read_byte(memdata, addrbyte + i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], "** ");
+ }
+ break;
+
+ case 2:
+ for (i = memdata->chunks_displayed - 1; i >= 0; i--)
+ {
+ offs_t curaddr = addrbyte + 2 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], " %04X ", memory_read_word(memdata, addrbyte + 2 * i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], " **** ");
+ }
+ break;
+
+ case 4:
+ for (i = memdata->chunks_displayed - 1; i >= 0; i--)
+ {
+ offs_t curaddr = addrbyte + 4 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], " %08X ", memory_read_dword(memdata, addrbyte + 4 * i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], " ******** ");
+ }
+ break;
+
+ case 8:
+ for (i = memdata->chunks_displayed - 1; i >= 0; i--)
+ {
+ offs_t curaddr = addrbyte + 8 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ {
+ UINT64 qword = memory_read_qword(memdata, addrbyte + 8 * i, !memdata->no_translation);
+ len += sprintf(&data[len], " %08X%08X ", (UINT32)(qword >> 32), (UINT32)qword);
+ }
+ else
+ len += sprintf(&data[len], " **************** ");
+ }
+ break;
+ }
+ len += sprintf(&data[len], addrformat, BYTE2ADDR(addrbyte & addrmask, cpuinfo, memdata->spacenum));
+ }
+
+ /* copy data */
+ while (col < view->visible_cols && effcol < len)
+ {
+ dest->byte = data[effcol++];
+ if (effcol <= memdata->divider1 || effcol >= memdata->divider2)
+ dest->attrib = attrib | DCA_ANCILLARY;
+ else if (view->cursor_visible && effcol - 1 == view->cursor_col && effrow == view->cursor_row && dest->byte != ' ')
+ dest->attrib = attrib | DCA_SELECTED;
+ else
+ dest->attrib = attrib;
+ dest++;
+ col++;
+ }
+ }
+
+ /* fill the rest with blanks */
+ while (col < view->visible_cols)
+ {
+ dest->byte = ' ';
+ dest->attrib = (effrow < view->total_rows) ? (attrib | DCA_ANCILLARY) : attrib;
+ dest++;
+ col++;
+ }
+ }
+
+ /* restore the context */
+ if (memdata->raw_base == NULL)
+ cpuintrf_pop_context();
+}
+
+
+/*-------------------------------------------------
+ memory_getprop - return the value
+ of a given property
+-------------------------------------------------*/
+
+static void memory_getprop(debug_view *view, UINT32 property, debug_property_info *value)
+{
+ debug_view_memory *memdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_MEM_EXPRESSION:
+ value->s = memdata->expression_string;
+ break;
+
+ case DVP_MEM_TRACK_LIVE:
+ value->i = memdata->live_tracking;
+ break;
+
+ case DVP_MEM_NO_TRANSLATION:
+ value->i = memdata->no_translation;
+ break;
+
+ case DVP_MEM_CPUNUM:
+ value->i = memdata->cpunum;
+ break;
+
+ case DVP_MEM_SPACENUM:
+ value->i = memdata->spacenum;
+ break;
+
+ case DVP_MEM_BYTES_PER_CHUNK:
+ value->i = memdata->bytes_per_chunk;
+ break;
+
+ case DVP_MEM_REVERSE_VIEW:
+ value->i = memdata->reverse_view;
+ break;
+
+ case DVP_MEM_ASCII_VIEW:
+ value->i = memdata->ascii_view;
+ break;
+
+ case DVP_MEM_RAW_BASE:
+ value->p = memdata->raw_base;
+ break;
+
+ case DVP_MEM_RAW_LENGTH:
+ value->i = memdata->raw_length;
+ break;
+
+ case DVP_MEM_RAW_OFFSET_XOR:
+ value->i = memdata->raw_offset_xor;
+ break;
+
+ case DVP_MEM_RAW_LITTLE_ENDIAN:
+ value->i = memdata->raw_little_endian;
+ break;
+
+ case DVP_MEM_WIDTH:
+ value->i = memdata->chunks_displayed;
+ break;
+
+ default:
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_setprop - set the value
+ of a given property
+-------------------------------------------------*/
+
+static void memory_setprop(debug_view *view, UINT32 property, debug_property_info value)
+{
+ debug_view_memory *memdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_MEM_EXPRESSION:
+ debug_view_begin_update(view);
+
+ /* free the old expression and allocate a new copy */
+ if (memdata->expression_string)
+ free(memdata->expression_string);
+ memdata->expression_string = malloc(strlen(value.s) + 1);
+ if (memdata->expression_string)
+ strcpy(memdata->expression_string, value.s);
+
+ memdata->expression_dirty = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_MEM_NO_TRANSLATION:
+ if (value.i != memdata->no_translation)
+ {
+ debug_view_begin_update(view);
+ memdata->no_translation = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_TRACK_LIVE:
+ if (value.i != memdata->live_tracking)
+ {
+ debug_view_begin_update(view);
+ memdata->live_tracking = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_CPUNUM:
+ if (value.i != memdata->cpunum)
+ {
+ debug_view_begin_update(view);
+ memdata->cpunum = value.i;
+ view->update_pending = TRUE;
+ memdata->expression_dirty = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_SPACENUM:
+ if (value.i != memdata->spacenum)
+ {
+ debug_view_begin_update(view);
+ memdata->spacenum = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_BYTES_PER_CHUNK:
+ if (value.i != memdata->bytes_per_chunk)
+ {
+ debug_view_begin_update(view);
+
+ /* Change chunks_displayed based on the new bytes_per_chunk */
+ memdata->chunks_displayed = memdata->chunks_displayed *
+ memdata->bytes_per_chunk / value.i;
+
+ if (memdata->chunks_displayed <= 0)
+ memdata->chunks_displayed = 1;
+
+ memdata->bytes_per_chunk = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_REVERSE_VIEW:
+ if (value.i != memdata->reverse_view)
+ {
+ debug_view_begin_update(view);
+ memdata->reverse_view = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_ASCII_VIEW:
+ if (value.i != memdata->ascii_view)
+ {
+ debug_view_begin_update(view);
+ memdata->ascii_view = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_RAW_BASE:
+ if (value.p != memdata->raw_base)
+ {
+ debug_view_begin_update(view);
+ memdata->raw_base = value.p;
+ memdata->expression_dirty = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_RAW_LENGTH:
+ if (value.i != memdata->raw_length)
+ {
+ debug_view_begin_update(view);
+ memdata->raw_length = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_RAW_OFFSET_XOR:
+ if (value.i != memdata->raw_offset_xor)
+ {
+ debug_view_begin_update(view);
+ memdata->raw_offset_xor = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_RAW_LITTLE_ENDIAN:
+ if (value.i != memdata->raw_little_endian)
+ {
+ debug_view_begin_update(view);
+ memdata->raw_little_endian = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_CHARACTER:
+ debug_view_begin_update(view);
+ memory_handle_char(view, value.i);
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_MEM_WIDTH:
+ if (value.i != memdata->chunks_displayed)
+ {
+ /* lower bounds check - maybe upper bounds check someday? */
+ if (value.i < 1) break;
+
+ debug_view_begin_update(view);
+ memdata->chunks_displayed = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+
+ default:
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
diff --git a/src/emu/debug/debugvw.h b/src/emu/debug/debugvw.h
new file mode 100644
index 00000000000..ce57fc33bc1
--- /dev/null
+++ b/src/emu/debug/debugvw.h
@@ -0,0 +1,228 @@
+/*********************************************************************
+
+ debugvw.h
+
+ Debugger view engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#ifndef __DEBUGVIEW_H__
+#define __DEBUGVIEW_H__
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* types passed to debug_view_alloc */
+#define DVT_CONSOLE (1)
+#define DVT_REGISTERS (2)
+#define DVT_DISASSEMBLY (3)
+#define DVT_MEMORY (4)
+#define DVT_LOG (5)
+#define DVT_TIMERS (6)
+#define DVT_ALLOCS (7)
+
+/* properties available for all views */
+#define DVP_VISIBLE_ROWS (1) /* r/w - UINT32 */
+#define DVP_VISIBLE_COLS (2) /* r/w - UINT32 */
+#define DVP_TOTAL_ROWS (3) /* r/w - UINT32 */
+#define DVP_TOTAL_COLS (4) /* r/w - UINT32 */
+#define DVP_TOP_ROW (5) /* r/w - UINT32 */
+#define DVP_LEFT_COL (6) /* r/w - UINT32 */
+#define DVP_UPDATE_CALLBACK (7) /* r/w - void (*update)(debug_view *) */
+#define DVP_VIEW_DATA (8) /* r/o - debug_view_char * */
+#define DVP_SUPPORTS_CURSOR (9) /* r/o - UINT32 */
+#define DVP_CURSOR_VISIBLE (10) /* r/w - UINT32 */
+#define DVP_CURSOR_ROW (11) /* r/w - UINT32 */
+#define DVP_CURSOR_COL (12) /* r/w - UINT32 */
+#define DVP_CHARACTER (13) /* w/o - UINT32 */
+#define DVP_OSD_PRIVATE (14) /* r/w - void * */
+
+/* properties available for register views */
+#define DVP_REGS_CPUNUM (100) /* r/w - UINT32 */
+
+/* properties available for disassembly views */
+#define DVP_DASM_CPUNUM (100) /* r/w - UINT32 */
+#define DVP_DASM_EXPRESSION (101) /* r/w - const char * */
+#define DVP_DASM_TRACK_LIVE (102) /* r/w - UINT32 */
+#define DVP_DASM_RIGHT_COLUMN (103) /* r/w - UINT32 */
+#define DVP_DASM_RIGHTCOL_NONE (0)
+#define DVP_DASM_RIGHTCOL_RAW (1)
+#define DVP_DASM_RIGHTCOL_ENCRYPTED (2)
+#define DVP_DASM_RIGHTCOL_COMMENTS (3)
+#define DVP_DASM_BACKWARD_STEPS (104) /* r/w - UINT32 */
+#define DVP_DASM_WIDTH (105) /* r/w - UINT32 */
+#define DVP_DASM_ACTIVE_ADDRESS (112) /* r/w - UINT32 */
+
+/* properties available for memory views */
+#define DVP_MEM_CPUNUM (100) /* r/w - UINT32 */
+#define DVP_MEM_EXPRESSION (101) /* r/w - const char * */
+#define DVP_MEM_TRACK_LIVE (102) /* r/w - UINT32 */
+#define DVP_MEM_SPACENUM (103) /* r/w - UINT32 */
+#define DVP_MEM_BYTES_PER_CHUNK (104) /* r/w - UINT32 */
+#define DVP_MEM_REVERSE_VIEW (105) /* r/w - UINT32 */
+#define DVP_MEM_ASCII_VIEW (106) /* r/w - UINT32 */
+#define DVP_MEM_RAW_BASE (107) /* r/w - void * */
+#define DVP_MEM_RAW_LENGTH (108) /* r/w - UINT32 */
+#define DVP_MEM_RAW_OFFSET_XOR (109) /* r/w - UINT32 */
+#define DVP_MEM_RAW_LITTLE_ENDIAN (110) /* r/w - UINT32 */
+#define DVP_MEM_WIDTH (111) /* r/w - UINT32 */
+#define DVP_MEM_NO_TRANSLATION (113) /* r/w - UINT32 */
+
+/* properties available for textbuffer views */
+#define DVP_TEXTBUF_LINE_LOCK (100) /* r/w - UINT32 */
+
+/* attribute bits for debug_view_char.attrib */
+#define DCA_NORMAL (0x00) /* in Windows: black on white */
+#define DCA_CHANGED (0x01) /* in Windows: red foreground */
+#define DCA_SELECTED (0x02) /* in Windows: light red background */
+#define DCA_INVALID (0x04) /* in Windows: dark blue foreground */
+#define DCA_DISABLED (0x08) /* in Windows: darker foreground */
+#define DCA_ANCILLARY (0x10) /* in Windows: grey background */
+#define DCA_CURRENT (0x20) /* in Windows: yellow background */
+#define DCA_COMMENT (0x40) /* in Windows: green foreground */
+
+/* special characters that can be passed as a DVP_CHARACTER */
+#define DCH_UP (1) /* up arrow */
+#define DCH_DOWN (2) /* down arrow */
+#define DCH_LEFT (3) /* left arrow */
+#define DCH_RIGHT (4) /* right arrow */
+#define DCH_PUP (5) /* page up */
+#define DCH_PDOWN (6) /* page down */
+#define DCH_HOME (7) /* home */
+#define DCH_CTRLHOME (8) /* ctrl+home */
+#define DCH_END (9) /* end */
+#define DCH_CTRLEND (10) /* ctrl+end */
+#define DCH_CTRLRIGHT (11) /* ctrl+right */
+#define DCH_CTRLLEFT (12) /* ctrl+left */
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* opaque structure representing a debug view */
+typedef struct _debug_view debug_view;
+
+
+/* a single "character" in the debug view has an ASCII value and an attribute byte */
+struct _debug_view_char
+{
+ UINT8 byte;
+ UINT8 attrib;
+};
+typedef struct _debug_view_char debug_view_char;
+
+
+union _debug_property_info
+{
+ UINT32 i;
+ const char *s;
+ void *p;
+ genf *f;
+};
+typedef union _debug_property_info debug_property_info;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* initialization */
+void debug_view_init(running_machine *machine);
+void debug_view_exit(running_machine *machine);
+
+/* view creation/deletion */
+debug_view * debug_view_alloc(int type);
+void debug_view_free(debug_view *view);
+
+/* property management */
+void debug_view_get_property(debug_view *view, int property, debug_property_info *value);
+void debug_view_set_property(debug_view *view, int property, debug_property_info value);
+
+/* update management */
+void debug_view_begin_update(debug_view *view);
+void debug_view_end_update(debug_view *view);
+void debug_view_update_all(void);
+void debug_view_update_type(int type);
+
+/* misc stuff */
+void debug_disasm_update_all(void);
+
+
+
+/***************************************************************************
+ INLINE HELPERS
+***************************************************************************/
+
+INLINE UINT32 debug_view_get_property_UINT32(debug_view *view, int property)
+{
+ debug_property_info value;
+ debug_view_get_property(view, property, &value);
+ return value.i;
+}
+
+INLINE void debug_view_set_property_UINT32(debug_view *view, int property, UINT32 value)
+{
+ debug_property_info info;
+ info.i = value;
+ debug_view_set_property(view, property, info);
+}
+
+
+INLINE const char *debug_view_get_property_string(debug_view *view, int property)
+{
+ debug_property_info value;
+ debug_view_get_property(view, property, &value);
+ return value.s;
+}
+
+INLINE void debug_view_set_property_string(debug_view *view, int property, const char *value)
+{
+ debug_property_info info;
+ info.s = value;
+ debug_view_set_property(view, property, info);
+}
+
+
+INLINE void *debug_view_get_property_ptr(debug_view *view, int property)
+{
+ debug_property_info value;
+ debug_view_get_property(view, property, &value);
+ return value.p;
+}
+
+INLINE void debug_view_set_property_ptr(debug_view *view, int property, void *value)
+{
+ debug_property_info info;
+ info.s = value;
+ debug_view_set_property(view, property, info);
+}
+
+
+INLINE genf *debug_view_get_property_fct(debug_view *view, int property)
+{
+ debug_property_info value;
+ debug_view_get_property(view, property, &value);
+ return value.f;
+}
+
+INLINE void debug_view_set_property_fct(debug_view *view, int property, genf *value)
+{
+ debug_property_info info;
+ info.f = value;
+ debug_view_set_property(view, property, info);
+}
+
+#endif
diff --git a/src/emu/debug/express.c b/src/emu/debug/express.c
new file mode 100644
index 00000000000..22aa49d9782
--- /dev/null
+++ b/src/emu/debug/express.c
@@ -0,0 +1,1953 @@
+/***************************************************************************
+
+ express.c
+ Generic expressions engine.
+ Written by Aaron Giles
+ Copyright (c) 2005, Aaron Giles
+
+***************************************************************************/
+
+#include "express.h"
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define DEBUG_TOKENS 0
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#ifndef DEFAULT_BASE
+#define DEFAULT_BASE 16 /* hex unless otherwise specified */
+#endif
+
+#define MAX_TOKENS 128
+#define MAX_STACK_DEPTH 128
+#define MAX_STRING_LENGTH 256
+#define MAX_EXPRESSION_STRINGS 64
+#define MAX_SYMBOL_LENGTH 64
+
+#define SYM_TABLE_HASH_SIZE 97
+
+/* token.type values */
+enum
+{
+ TOK_INVALID = 0,
+ TOK_END,
+ TOK_NUMBER,
+ TOK_STRING,
+ TOK_MEMORY,
+ TOK_SYMBOL,
+ TOK_OPERATOR
+};
+
+
+/* token.info values */
+enum
+{
+ TIN_PRECEDENCE_MASK = 0x001f,
+ TIN_PRECEDENCE_0 = 0x0000, /* ( ) */
+ TIN_PRECEDENCE_1 = 0x0001, /* ++ (postfix), -- (postfix) */
+ TIN_PRECEDENCE_2 = 0x0002, /* ++ (prefix), -- (prefix), ~, !, - (unary), + (unary), b@, w@, d@, q@ */
+ TIN_PRECEDENCE_3 = 0x0003, /* *, /, % */
+ TIN_PRECEDENCE_4 = 0x0004, /* + - */
+ TIN_PRECEDENCE_5 = 0x0005, /* << >> */
+ TIN_PRECEDENCE_6 = 0x0006, /* < <= > >= */
+ TIN_PRECEDENCE_7 = 0x0007, /* == != */
+ TIN_PRECEDENCE_8 = 0x0008, /* & */
+ TIN_PRECEDENCE_9 = 0x0009, /* ^ */
+ TIN_PRECEDENCE_10 = 0x000a, /* | */
+ TIN_PRECEDENCE_11 = 0x000b, /* && */
+ TIN_PRECEDENCE_12 = 0x000c, /* || */
+ TIN_PRECEDENCE_13 = 0x000d, /* = *= /= %= += -= <<= >>= &= |= ^= */
+ TIN_PRECEDENCE_14 = 0x000e, /* , */
+ TIN_PRECEDENCE_15 = 0x000f, /* func() */
+
+ TIN_RIGHT_TO_LEFT = 0x0040,
+ TIN_FUNCTION = 0x0080,
+
+ TIN_MEMORY_SIZE_SHIFT = 8,
+ TIN_MEMORY_SIZE_MASK = (3 << TIN_MEMORY_SIZE_SHIFT),
+ TIN_MEMORY_BYTE = (0 << TIN_MEMORY_SIZE_SHIFT),
+ TIN_MEMORY_WORD = (1 << TIN_MEMORY_SIZE_SHIFT),
+ TIN_MEMORY_DWORD = (2 << TIN_MEMORY_SIZE_SHIFT),
+ TIN_MEMORY_QWORD = (3 << TIN_MEMORY_SIZE_SHIFT),
+
+ TIN_MEMORY_SPACE_SHIFT = 10,
+ TIN_MEMORY_SPACE_MASK = (3 << TIN_MEMORY_SPACE_SHIFT),
+ TIN_MEMORY_PROGRAM = (EXPSPACE_PROGRAM << TIN_MEMORY_SPACE_SHIFT),
+ TIN_MEMORY_DATA = (EXPSPACE_DATA << TIN_MEMORY_SPACE_SHIFT),
+ TIN_MEMORY_IO = (EXPSPACE_IO << TIN_MEMORY_SPACE_SHIFT),
+};
+
+
+/* token.value values if token.type == TOK_OPERATOR */
+enum
+{
+ TVL_LPAREN,
+ TVL_RPAREN,
+ TVL_PLUSPLUS,
+ TVL_MINUSMINUS,
+ TVL_PREINCREMENT,
+ TVL_PREDECREMENT,
+ TVL_POSTINCREMENT,
+ TVL_POSTDECREMENT,
+ TVL_COMPLEMENT,
+ TVL_NOT,
+ TVL_UPLUS,
+ TVL_UMINUS,
+ TVL_MULTIPLY,
+ TVL_DIVIDE,
+ TVL_MODULO,
+ TVL_ADD,
+ TVL_SUBTRACT,
+ TVL_LSHIFT,
+ TVL_RSHIFT,
+ TVL_LESS,
+ TVL_LESSOREQUAL,
+ TVL_GREATER,
+ TVL_GREATEROREQUAL,
+ TVL_EQUAL,
+ TVL_NOTEQUAL,
+ TVL_BAND,
+ TVL_BXOR,
+ TVL_BOR,
+ TVL_LAND,
+ TVL_LOR,
+ TVL_ASSIGN,
+ TVL_ASSIGNMULTIPLY,
+ TVL_ASSIGNDIVIDE,
+ TVL_ASSIGNMODULO,
+ TVL_ASSIGNADD,
+ TVL_ASSIGNSUBTRACT,
+ TVL_ASSIGNLSHIFT,
+ TVL_ASSIGNRSHIFT,
+ TVL_ASSIGNBAND,
+ TVL_ASSIGNBXOR,
+ TVL_ASSIGNBOR,
+ TVL_COMMA,
+ TVL_MEMORYAT,
+ TVL_EXECUTEFUNC
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef union _int_ptr int_ptr;
+union _int_ptr
+{
+ void * p; /* pointer value */
+ UINT64 i; /* integer value */
+};
+
+
+typedef struct _parse_token parse_token;
+struct _parse_token
+{
+ UINT16 type; /* type of token */
+ UINT16 info; /* info for token */
+ UINT32 offset; /* offset within the string */
+ int_ptr value; /* value of token */
+};
+
+
+typedef struct _internal_symbol_entry internal_symbol_entry;
+struct _internal_symbol_entry
+{
+ internal_symbol_entry *next; /* pointer to the next entry */
+ const char * name; /* name of the symbol */
+ symbol_entry entry; /* actual entry data */
+};
+
+
+/* typedef struct _symbol_table symbol_table -- defined in express.h */
+struct _symbol_table
+{
+ symbol_table *parent; /* pointer to the parent symbol table */
+ internal_symbol_entry *hash[SYM_TABLE_HASH_SIZE]; /* hash table */
+};
+
+
+/* typedef struct _parsed_expression parsed_expression -- defined in express.h */
+struct _parsed_expression
+{
+ const symbol_table *table; /* symbol table */
+ char * original_string;/* original string (prior to parsing) */
+ char * string[MAX_EXPRESSION_STRINGS]; /* string table */
+ parse_token token[MAX_TOKENS];/* array of tokens */
+ int token_stack_ptr;/* stack poointer */
+ parse_token token_stack[MAX_STACK_DEPTH];/* token stack */
+};
+
+
+
+/***************************************************************************
+ STACK MANIPULATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ init_token_stack - reset the token stack
+-------------------------------------------------*/
+
+INLINE void init_token_stack(parsed_expression *expr)
+{
+ expr->token_stack_ptr = 0;
+}
+
+
+/*-------------------------------------------------
+ push_token - push a token onto the stack
+-------------------------------------------------*/
+
+INLINE EXPRERR push_token(parsed_expression *expr, parse_token *token)
+{
+ /* check for overflow */
+ if (expr->token_stack_ptr >= MAX_STACK_DEPTH)
+ return MAKE_EXPRERR_STACK_OVERFLOW(token->offset);
+
+ /* push */
+ expr->token_stack[expr->token_stack_ptr++] = *token;
+ return EXPRERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ pop_token - pop a token off the stack
+-------------------------------------------------*/
+
+INLINE EXPRERR pop_token(parsed_expression *expr, parse_token *token)
+{
+ /* check for underflow */
+ if (expr->token_stack_ptr == 0)
+ return MAKE_EXPRERR_STACK_UNDERFLOW(token->offset);
+
+ /* push */
+ *token = expr->token_stack[--expr->token_stack_ptr];
+ return EXPRERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ peek_token - look at a token some number of
+ entries up the stack
+-------------------------------------------------*/
+
+INLINE parse_token *peek_token(parsed_expression *expr, int count)
+{
+ if (expr->token_stack_ptr <= count)
+ return NULL;
+ return &expr->token_stack[expr->token_stack_ptr - count - 1];
+}
+
+
+
+/***************************************************************************
+ LVAL/RVAL EVALUATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ pop_token_lval - pop a token off the stack
+ and ensure that it is a proper lval
+-------------------------------------------------*/
+
+INLINE EXPRERR pop_token_lval(parsed_expression *expr, parse_token *token, const symbol_table *table)
+{
+ /* check for underflow */
+ if (expr->token_stack_ptr == 0)
+ return MAKE_EXPRERR_STACK_UNDERFLOW(token->offset);
+
+ /* pop */
+ *token = expr->token_stack[--expr->token_stack_ptr];
+
+ /* to be an lval, the token must be a valid read/write symbol or a memory token */
+ if (token->type == TOK_SYMBOL)
+ {
+ symbol_entry *symbol = token->value.p;
+ if (symbol == NULL || symbol->type != SMT_REGISTER || symbol->info.reg.setter == NULL)
+ return MAKE_EXPRERR_NOT_LVAL(token->offset);
+ }
+ else if (token->type != TOK_MEMORY)
+ return MAKE_EXPRERR_NOT_LVAL(token->offset);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ pop_token_rval - pop a token off the stack
+ and ensure that it is a proper rval
+-------------------------------------------------*/
+
+INLINE EXPRERR pop_token_rval(parsed_expression *expr, parse_token *token, const symbol_table *table)
+{
+ /* check for underflow */
+ if (expr->token_stack_ptr == 0)
+ return MAKE_EXPRERR_STACK_UNDERFLOW(token->offset);
+
+ /* pop */
+ *token = expr->token_stack[--expr->token_stack_ptr];
+
+ /* symbol tokens get resolved down to number tokens */
+ if (token->type == TOK_SYMBOL)
+ {
+ symbol_entry *symbol = token->value.p;
+ if (symbol == NULL || (symbol->type != SMT_REGISTER && symbol->type != SMT_VALUE))
+ return MAKE_EXPRERR_NOT_RVAL(token->offset);
+ token->type = TOK_NUMBER;
+ if (symbol->type == SMT_REGISTER)
+ token->value.i = (*symbol->info.reg.getter)(symbol->ref);
+ else
+ token->value.i = symbol->info.gen.value;
+ }
+
+ /* memory tokens get resolved down to number tokens */
+ else if (token->type == TOK_MEMORY)
+ {
+ int space = (token->info & TIN_MEMORY_SPACE_MASK) >> TIN_MEMORY_SPACE_SHIFT;
+ int size = (token->info & TIN_MEMORY_SIZE_MASK) >> TIN_MEMORY_SIZE_SHIFT;
+ token->type = TOK_NUMBER;
+ token->value.i = external_read_memory(space, token->value.i, 1 << size);
+ }
+
+ /* to be an rval, the token must be a number */
+ if (token->type != TOK_NUMBER)
+ return MAKE_EXPRERR_NOT_RVAL(token->offset);
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ get_lval_value - call the getter function
+ for a SYMBOL token
+-------------------------------------------------*/
+
+INLINE UINT64 get_lval_value(parse_token *token, const symbol_table *table)
+{
+ if (token->type == TOK_SYMBOL)
+ {
+ symbol_entry *symbol = token->value.p;
+ if (symbol != NULL && symbol->type == SMT_REGISTER)
+ return (*symbol->info.reg.getter)(symbol->ref);
+ }
+ else if (token->type == TOK_MEMORY)
+ {
+ int space = (token->info & TIN_MEMORY_SPACE_MASK) >> TIN_MEMORY_SPACE_SHIFT;
+ int size = (token->info & TIN_MEMORY_SIZE_MASK) >> TIN_MEMORY_SIZE_SHIFT;
+ return external_read_memory(space, token->value.i, 1 << size);
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ set_lval_value - call the setter function
+ for a SYMBOL token
+-------------------------------------------------*/
+
+INLINE void set_lval_value(parse_token *token, const symbol_table *table, UINT64 value)
+{
+ if (token->type == TOK_SYMBOL)
+ {
+ symbol_entry *symbol = token->value.p;
+ if (symbol != NULL && symbol->type == SMT_REGISTER && symbol->info.reg.setter)
+ (*symbol->info.reg.setter)(symbol->ref, value);
+ }
+ else if (token->type == TOK_MEMORY)
+ {
+ int space = (token->info & TIN_MEMORY_SPACE_MASK) >> TIN_MEMORY_SPACE_SHIFT;
+ int size = (token->info & TIN_MEMORY_SIZE_MASK) >> TIN_MEMORY_SIZE_SHIFT;
+ external_write_memory(space, token->value.i, 1 << size, value);
+ }
+}
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+/*-------------------------------------------------
+ print_token - debugging took to print a
+ human readable token representation
+-------------------------------------------------*/
+
+static void print_tokens(FILE *out, parsed_expression *expr)
+{
+#if DEBUG_TOKENS
+ parse_token *token = expr->token;
+
+ mame_printf_debug("----\n");
+ while (token->type != TOK_END)
+ {
+ switch (token->type)
+ {
+ default:
+ case TOK_INVALID:
+ fprintf(out, "INVALID\n");
+ break;
+
+ case TOK_END:
+ fprintf(out, "END\n");
+ break;
+
+ case TOK_NUMBER:
+ fprintf(out, "NUMBER: %08X%08X\n", (UINT32)(token->value.i >> 32), (UINT32)token->value.i);
+ break;
+
+ case TOK_STRING:
+ fprintf(out, "STRING: ""%s""\n", (char *)token->value.p);
+ break;
+
+ case TOK_SYMBOL:
+ fprintf(out, "SYMBOL: %08X%08X\n", (UINT32)(token->value.i >> 32), (UINT32)token->value.i);
+ break;
+
+ case TOK_OPERATOR:
+ switch (token->value.i)
+ {
+ case TVL_LPAREN: fprintf(out, "(\n"); break;
+ case TVL_RPAREN: fprintf(out, ")\n"); break;
+ case TVL_PLUSPLUS: fprintf(out, "++ (unspecified)\n"); break;
+ case TVL_MINUSMINUS: fprintf(out, "-- (unspecified)\n"); break;
+ case TVL_PREINCREMENT: fprintf(out, "++ (prefix)\n"); break;
+ case TVL_PREDECREMENT: fprintf(out, "-- (prefix)\n"); break;
+ case TVL_POSTINCREMENT: fprintf(out, "++ (postfix)\n"); break;
+ case TVL_POSTDECREMENT: fprintf(out, "-- (postfix)\n"); break;
+ case TVL_COMPLEMENT: fprintf(out, "!\n"); break;
+ case TVL_NOT: fprintf(out, "~\n"); break;
+ case TVL_UPLUS: fprintf(out, "+ (unary)\n"); break;
+ case TVL_UMINUS: fprintf(out, "- (unary)\n"); break;
+ case TVL_MULTIPLY: fprintf(out, "*\n"); break;
+ case TVL_DIVIDE: fprintf(out, "/\n"); break;
+ case TVL_MODULO: fprintf(out, "%%\n"); break;
+ case TVL_ADD: fprintf(out, "+\n"); break;
+ case TVL_SUBTRACT: fprintf(out, "-\n"); break;
+ case TVL_LSHIFT: fprintf(out, "<<\n"); break;
+ case TVL_RSHIFT: fprintf(out, ">>\n"); break;
+ case TVL_LESS: fprintf(out, "<\n"); break;
+ case TVL_LESSOREQUAL: fprintf(out, "<=\n"); break;
+ case TVL_GREATER: fprintf(out, ">\n"); break;
+ case TVL_GREATEROREQUAL:fprintf(out, ">=\n"); break;
+ case TVL_EQUAL: fprintf(out, "==\n"); break;
+ case TVL_NOTEQUAL: fprintf(out, "!=\n"); break;
+ case TVL_BAND: fprintf(out, "&\n"); break;
+ case TVL_BXOR: fprintf(out, "^\n"); break;
+ case TVL_BOR: fprintf(out, "|\n"); break;
+ case TVL_LAND: fprintf(out, "&&\n"); break;
+ case TVL_LOR: fprintf(out, "||\n"); break;
+ case TVL_ASSIGN: fprintf(out, "=\n"); break;
+ case TVL_ASSIGNMULTIPLY:fprintf(out, "*=\n"); break;
+ case TVL_ASSIGNDIVIDE: fprintf(out, "/=\n"); break;
+ case TVL_ASSIGNMODULO: fprintf(out, "%%=\n"); break;
+ case TVL_ASSIGNADD: fprintf(out, "+=\n"); break;
+ case TVL_ASSIGNSUBTRACT:fprintf(out, "-=\n"); break;
+ case TVL_ASSIGNLSHIFT: fprintf(out, "<<=\n"); break;
+ case TVL_ASSIGNRSHIFT: fprintf(out, ">>=\n"); break;
+ case TVL_ASSIGNBAND: fprintf(out, "&=\n"); break;
+ case TVL_ASSIGNBXOR: fprintf(out, "^=\n"); break;
+ case TVL_ASSIGNBOR: fprintf(out, "|=\n"); break;
+ case TVL_COMMA: fprintf(out, ",\n"); break;
+ case TVL_MEMORYAT: fprintf(out, "mem@\n"); break;
+ case TVL_EXECUTEFUNC: fprintf(out, "execute\n"); break;
+ default: fprintf(out, "INVALID OPERATOR\n"); break;
+ }
+ break;
+ }
+ token++;
+ }
+ mame_printf_debug("----\n");
+#endif
+}
+
+
+
+/***************************************************************************
+ TOKENIZING
+***************************************************************************/
+
+/*-------------------------------------------------
+ parse_memory_operator - parse the several
+ forms of memory operators
+-------------------------------------------------*/
+
+static int parse_memory_operator(const char *buffer, UINT16 *flags)
+{
+ int length = (int)strlen(buffer);
+ int space = 'p', size;
+
+ *flags = 0;
+
+ /* length 2 means space, then size */
+ if (length == 2)
+ {
+ space = buffer[0];
+ size = buffer[1];
+ }
+
+ /* length 1 means size */
+ else if (length == 1)
+ size = buffer[0];
+
+ /* anything else is invalid */
+ else
+ return 0;
+
+ /* convert the space to flags */
+ switch (space)
+ {
+ case 'p': *flags |= TIN_MEMORY_PROGRAM; break;
+ case 'd': *flags |= TIN_MEMORY_DATA; break;
+ case 'i': *flags |= TIN_MEMORY_IO; break;
+ default: return 0;
+ }
+
+ /* convert the size to flags */
+ switch (size)
+ {
+ case 'b': *flags |= TIN_MEMORY_BYTE; break;
+ case 'w': *flags |= TIN_MEMORY_WORD; break;
+ case 'd': *flags |= TIN_MEMORY_DWORD; break;
+ case 'q': *flags |= TIN_MEMORY_QWORD; break;
+ default: return 0;
+ }
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ parse_string_into_tokens - take an expression
+ string and break it into a sequence of tokens
+-------------------------------------------------*/
+
+static EXPRERR parse_string_into_tokens(const char *stringstart, parsed_expression *expr, const symbol_table *table)
+{
+ #define SET_TOKEN_INFO(_length, _type, _value, _info) \
+ do { \
+ token->type = _type; \
+ token->value.i = _value; \
+ token->info = _info; \
+ string += _length; \
+ } while (0)
+
+ parse_token *token = expr->token;
+ const char *string = stringstart;
+
+ /* zap expression object */
+ memset(expr, 0, sizeof(*expr));
+
+ /* stash the symbol table pointer */
+ expr->table = table;
+
+ /* make a copy of the original string */
+ expr->original_string = malloc(strlen(stringstart) + 1);
+ if (!expr->original_string)
+ return MAKE_EXPRERR_OUT_OF_MEMORY(0);
+ strcpy(expr->original_string, stringstart);
+
+ /* loop until done */
+ while (string[0] != 0 && token - expr->token < MAX_TOKENS)
+ {
+ /* ignore any whitespace */
+ while (string[0] != 0 && isspace(string[0]))
+ string++;
+ if (string[0] == 0)
+ break;
+
+ /* initialize the current token object */
+ SET_TOKEN_INFO(0, TOK_INVALID, 0, 0);
+ token->offset = string - stringstart;
+
+ /* switch off the first character */
+ switch (tolower(string[0]))
+ {
+ case '(':
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_LPAREN, TIN_PRECEDENCE_0);
+ break;
+
+ case ')':
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_RPAREN, TIN_PRECEDENCE_0);
+ break;
+
+ case '~':
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_NOT, TIN_PRECEDENCE_2);
+ break;
+
+ case ',':
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_COMMA, TIN_PRECEDENCE_14);
+ break;
+
+ case '+':
+ if (string[1] == '+')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_PLUSPLUS, TIN_PRECEDENCE_1);
+ else if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNADD, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_ADD, TIN_PRECEDENCE_4);
+ break;
+
+ case '-':
+ if (string[1] == '-')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_MINUSMINUS, TIN_PRECEDENCE_1);
+ else if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNSUBTRACT, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_SUBTRACT, TIN_PRECEDENCE_4);
+ break;
+
+ case '*':
+ if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNMULTIPLY, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_MULTIPLY, TIN_PRECEDENCE_3);
+ break;
+
+ case '/':
+ if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNDIVIDE, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_DIVIDE, TIN_PRECEDENCE_3);
+ break;
+
+ case '%':
+ if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNMODULO, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_MODULO, TIN_PRECEDENCE_3);
+ break;
+
+ case '<':
+ if (string[1] == '<' && string[2] == '=')
+ SET_TOKEN_INFO(3, TOK_OPERATOR, TVL_ASSIGNLSHIFT, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else if (string[1] == '<')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_LSHIFT, TIN_PRECEDENCE_5);
+ else if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_LESSOREQUAL, TIN_PRECEDENCE_6);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_LESS, TIN_PRECEDENCE_6);
+ break;
+
+ case '>':
+ if (string[1] == '>' && string[2] == '=')
+ SET_TOKEN_INFO(3, TOK_OPERATOR, TVL_ASSIGNRSHIFT, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else if (string[1] == '>')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_RSHIFT, TIN_PRECEDENCE_5);
+ else if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_GREATEROREQUAL, TIN_PRECEDENCE_6);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_GREATER, TIN_PRECEDENCE_6);
+ break;
+
+ case '=':
+ if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_EQUAL, TIN_PRECEDENCE_7);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_ASSIGN, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ break;
+
+ case '!':
+ if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_NOTEQUAL, TIN_PRECEDENCE_7);
+ else
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_COMPLEMENT, TIN_PRECEDENCE_2);
+ break;
+
+ case '&':
+ if (string[1] == '&')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_LAND, TIN_PRECEDENCE_11);
+ else if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNBAND, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_BAND, TIN_PRECEDENCE_8);
+ break;
+
+ case '|':
+ if (string[1] == '|')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_LOR, TIN_PRECEDENCE_12);
+ else if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNBOR, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_BOR, TIN_PRECEDENCE_10);
+ break;
+
+ case '^':
+ if (string[1] == '=')
+ SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNBXOR, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT);
+ else
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_BXOR, TIN_PRECEDENCE_9);
+ break;
+
+ case '"':
+ {
+ char buffer[MAX_STRING_LENGTH];
+ int bufindex = 0, strindex;
+
+ /* find a free string entry */
+ for (strindex = 0; strindex < MAX_EXPRESSION_STRINGS; strindex++)
+ if (expr->string[strindex] == NULL)
+ break;
+ if (strindex == MAX_EXPRESSION_STRINGS)
+ return MAKE_EXPRERR_TOO_MANY_STRINGS(token->offset);
+
+ /* accumulate a copy of the string */
+ string++;
+ while (string[0] != 0 && bufindex < MAX_STRING_LENGTH)
+ {
+ /* allow "" to mean a nested double-quote */
+ if (string[0] == '"')
+ {
+ if (string[1] != '"')
+ break;
+ string++;
+ }
+ buffer[bufindex++] = *string++;
+ }
+
+ /* if we didn't find the ending quote, report an error */
+ if (string[0] != '"')
+ return MAKE_EXPRERR_UNBALANCED_QUOTES(token->offset);
+ string++;
+
+ /* terminate the string and allocate memory */
+ buffer[bufindex++] = 0;
+ expr->string[strindex] = malloc(bufindex);
+ if (!expr->string[strindex])
+ return MAKE_EXPRERR_OUT_OF_MEMORY(token->offset);
+
+ /* copy the string in and make the token */
+ strcpy(expr->string[strindex], buffer);
+ token->type = TOK_STRING;
+ token->value.p = expr->string[strindex];
+ break;
+ }
+
+ case '\'':
+ {
+ UINT64 value = 0;
+
+ /* accumulate the value of the character token */
+ string++;
+ while (string[0] != 0)
+ {
+ /* allow '' to mean a nested single quote */
+ if (string[0] == '\'')
+ {
+ if (string[1] != '\'')
+ break;
+ string++;
+ }
+ value = (value << 8) | (UINT8)*string++;
+ }
+
+ /* if we didn't find the ending quote, report an error */
+ if (string[0] != '\'')
+ return MAKE_EXPRERR_UNBALANCED_QUOTES(token->offset);
+ string++;
+
+ /* make it a number token */
+ token->type = TOK_NUMBER;
+ token->value.i = value;
+ break;
+ }
+
+ default:
+ {
+ static const char valid[] = "abcdefghijklmnopqrstuvwxyz0123456789_$#.";
+ static const char numbers[] = "0123456789abcdef";
+ int bufindex = 0, must_be_number = 0, numbase = DEFAULT_BASE;
+ char buffer[MAX_SYMBOL_LENGTH];
+ UINT64 value;
+
+ /* accumulate a lower-case version of the symbol */
+ while (1)
+ {
+ char val = tolower(string[0]);
+ if (val == 0 || strchr(valid, val) == NULL)
+ break;
+ buffer[bufindex++] = val;
+ string++;
+ }
+ buffer[bufindex] = 0;
+
+ /* check for memory @ operators */
+ if (string[0] == '@')
+ {
+ UINT16 info;
+ if (parse_memory_operator(buffer, &info))
+ {
+ SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_MEMORYAT, TIN_PRECEDENCE_2 | info);
+ break;
+ }
+ }
+
+ /* empty string is automatically invalid */
+ if (buffer[0] == 0)
+ return MAKE_EXPRERR_INVALID_TOKEN(token->offset);
+ else
+ {
+ /* if we have a number prefix, assume it is a number */
+ bufindex = 0;
+ if (buffer[0] == '$') { numbase = 16; bufindex++; must_be_number = 1; }
+ else if (buffer[0] == '0' && buffer[1] == 'x') { numbase = 16; bufindex += 2; must_be_number = 1; }
+ else if (buffer[0] == '#') { numbase = 10; bufindex++; must_be_number = 1; }
+
+ /* if we're not forced to be a number, check for a symbol match first */
+ if (!must_be_number)
+ {
+ const symbol_entry *symbol = symtable_find(expr->table, buffer);
+ if (symbol != NULL)
+ {
+ token->type = TOK_SYMBOL;
+ token->value.p = (void *)symbol;
+
+ /* if this is a function symbol, synthesize an execute function operator */
+ if (symbol->type == SMT_FUNCTION)
+ {
+ token++;
+ SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_EXECUTEFUNC, TIN_PRECEDENCE_0);
+ }
+ }
+ }
+
+ /* see if we parse as a number */
+ if (token->type == TOK_INVALID)
+ {
+ value = 0;
+ while (buffer[bufindex] != 0)
+ {
+ const char *ptr = strchr(numbers, tolower(buffer[bufindex]));
+ int digit;
+
+ if (ptr == NULL)
+ break;
+ digit = ptr - numbers;
+ if (digit >= numbase)
+ break;
+ value = (value * (UINT64)numbase) + digit;
+ bufindex++;
+ }
+
+ /* if we succeeded as a number, make it so */
+ if (buffer[bufindex] == 0)
+ {
+ token->type = TOK_NUMBER;
+ token->value.i = value;
+ }
+ }
+
+ /* report errors */
+ if (token->type == TOK_INVALID)
+ {
+ if (must_be_number)
+ return MAKE_EXPRERR_INVALID_NUMBER(token->offset);
+ else
+ return MAKE_EXPRERR_UNKNOWN_SYMBOL(token->offset);
+ }
+ }
+ break;
+ }
+ }
+
+ /* advance to the next token */
+ token++;
+ }
+
+ /* add an ending token */
+ token->type = TOK_END;
+ token->value.i = 0;
+ return EXPRERR_NONE;
+}
+
+
+
+/***************************************************************************
+ INFIX TO POSTFIX CONVERSION
+***************************************************************************/
+
+/*-------------------------------------------------
+ normalize_operator - resolve operator
+ ambiguities based on neighboring tokens
+-------------------------------------------------*/
+
+static EXPRERR normalize_operator(parsed_expression *expr, int tokindex)
+{
+ parse_token *thistoken = &expr->token[tokindex];
+ parse_token *nexttoken = thistoken + 1;
+ parse_token *prevtoken = (tokindex == 0) ? NULL : (thistoken - 1);
+
+ switch (thistoken->value.i)
+ {
+ /* Determine if an open paren is part of a function or not */
+ case TVL_LPAREN:
+ if (prevtoken != NULL && prevtoken->type == TOK_OPERATOR && prevtoken->value.i == TVL_EXECUTEFUNC)
+ thistoken->info |= TIN_FUNCTION;
+ break;
+
+ /* Determine if ++ is a pre or post increment */
+ case TVL_PLUSPLUS:
+ if (nexttoken->type == TOK_SYMBOL || (nexttoken->type == TOK_OPERATOR && nexttoken->value.i == TVL_MEMORYAT))
+ {
+ thistoken->value.i = TVL_PREINCREMENT;
+ thistoken->info = TIN_PRECEDENCE_2;
+ }
+ else if (prevtoken != NULL && (prevtoken->type == TOK_SYMBOL || (prevtoken->type == TOK_OPERATOR && prevtoken->value.i == TVL_MEMORYAT)))
+ {
+ thistoken->value.i = TVL_POSTINCREMENT;
+ thistoken->info = TIN_PRECEDENCE_1;
+ }
+ else
+ return MAKE_EXPRERR_SYNTAX(thistoken->offset);
+ break;
+
+ /* Determine if -- is a pre or post decrement */
+ case TVL_MINUSMINUS:
+ if (nexttoken->type == TOK_SYMBOL || (nexttoken->type == TOK_OPERATOR && nexttoken->value.i == TVL_MEMORYAT))
+ {
+ thistoken->value.i = TVL_PREDECREMENT;
+ thistoken->info = TIN_PRECEDENCE_2;
+ }
+ else if (prevtoken != NULL && (prevtoken->type == TOK_SYMBOL || (prevtoken->type == TOK_OPERATOR && prevtoken->value.i == TVL_MEMORYAT)))
+ {
+ thistoken->value.i = TVL_POSTDECREMENT;
+ thistoken->info = TIN_PRECEDENCE_1;
+ }
+ else
+ return MAKE_EXPRERR_SYNTAX(thistoken->offset);
+ break;
+
+ /* Determine if +/- is a unary or binary */
+ case TVL_ADD:
+ case TVL_SUBTRACT:
+ /* Assume we're unary if we are the first token, or if the previous token is not
+ a symbol, a number, or a right parenthesis */
+ if (prevtoken == NULL ||
+ (prevtoken->type != TOK_SYMBOL && prevtoken->type != TOK_NUMBER &&
+ (prevtoken->type != TOK_OPERATOR || prevtoken->value.i != TVL_RPAREN)))
+ {
+ thistoken->value.i = (thistoken->value.i == TVL_ADD) ? TVL_UPLUS : TVL_UMINUS;
+ thistoken->info = TIN_PRECEDENCE_2;
+ }
+ break;
+
+ /* Determine if , refers to a function parameter */
+ case TVL_COMMA:
+ {
+ int lookback;
+
+ for (lookback = 0; lookback < MAX_STACK_DEPTH; lookback++)
+ {
+ parse_token *peek = peek_token(expr, lookback);
+ if (!peek)
+ break;
+ if (peek->value.i == TVL_LPAREN)
+ {
+ if (peek->info & TIN_FUNCTION)
+ thistoken->info |= TIN_FUNCTION;
+ break;
+ }
+ if (peek->value.i == TVL_EXECUTEFUNC)
+ {
+ thistoken->info |= TIN_FUNCTION;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return EXPRERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ infix_to_postfix - convert an infix sequence
+ of tokens to a postfix sequence for processing
+-------------------------------------------------*/
+
+static EXPRERR infix_to_postfix(parsed_expression *expr)
+{
+ parse_token *dest = expr->token;
+ parse_token dummy;
+ parse_token *peek;
+ int tokindex = 0;
+ EXPRERR exprerr;
+
+ /* start with an empty stack */
+ init_token_stack(expr);
+
+ /* loop over all the original tokens */
+ for ( ; expr->token[tokindex].type != TOK_END; tokindex++)
+ {
+ parse_token *token = &expr->token[tokindex];
+
+ /* If the character is an operand, append it to the result string */
+ if (token->type == TOK_NUMBER || token->type == TOK_SYMBOL || token->type == TOK_STRING)
+ *dest++ = *token;
+
+ /* If this is an operator, process it */
+ else if (token->type == TOK_OPERATOR)
+ {
+ int exprerr = normalize_operator(expr, tokindex);
+ if (exprerr != 0)
+ return exprerr;
+
+ /* If the token is an opening parenthesis, push it onto the stack. */
+ if (token->value.i == TVL_LPAREN)
+ {
+ exprerr = push_token(expr, token);
+ if (exprerr != 0)
+ return exprerr;
+ }
+
+ /* If the token is a closing parenthesis, pop all operators until we
+ reach an opening parenthesis and append them to the result string. */
+ else if (token->value.i == TVL_RPAREN)
+ {
+ /* loop until we can't peek at the stack anymore */
+ while ((peek = peek_token(expr, 0)) != NULL)
+ {
+ if (peek->value.i == TVL_LPAREN)
+ break;
+ exprerr = pop_token(expr, dest++);
+ if (exprerr != 0)
+ return exprerr;
+ }
+
+ /* if we didn't find an open paren, it's an error */
+ if (peek == NULL)
+ return MAKE_EXPRERR_UNBALANCED_PARENS(token->offset);
+
+ /* pop the open paren off the stack */
+ exprerr = pop_token(expr, &dummy);
+ if (exprerr != 0)
+ return exprerr;
+ }
+
+ /* If the token is an operator, pop operators until we reach an opening parenthesis,
+ an operator of lower precedence, or a right associative symbol of equal precedence.
+ Push the operator onto the stack. */
+ else
+ {
+ int our_precedence = token->info & TIN_PRECEDENCE_MASK;
+
+ /* loop until we can't peek at the stack anymore */
+ while ((peek = peek_token(expr, 0)) != NULL)
+ {
+ int stack_precedence = peek->info & TIN_PRECEDENCE_MASK;
+
+ /* break if any of the above conditions are true */
+ if (peek->value.i == TVL_LPAREN)
+ break;
+ if (stack_precedence > our_precedence)
+ break;
+ if (stack_precedence == our_precedence && (peek->info & TIN_RIGHT_TO_LEFT))
+ break;
+
+ /* pop this token */
+ exprerr = pop_token(expr, dest++);
+ if (exprerr != 0)
+ return exprerr;
+ }
+
+ /* push the new operator */
+ exprerr = push_token(expr, token);
+ if (exprerr != 0)
+ return exprerr;
+ }
+ }
+ }
+
+ /* finish popping the stack */
+ while ((peek = peek_token(expr, 0)) != NULL)
+ {
+ /* it is an error to have a left parenthesis still on the stack */
+ if (peek->value.i == TVL_LPAREN)
+ return MAKE_EXPRERR_UNBALANCED_PARENS(peek->offset);
+
+ /* pop this token */
+ exprerr = pop_token(expr, dest++);
+ if (exprerr != 0)
+ return exprerr;
+ }
+
+ /* copy the end token to the final stream */
+ *dest++ = expr->token[tokindex];
+ return EXPRERR_NONE;
+}
+
+
+
+/***************************************************************************
+ EXPRESSION EVALUATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ execute_function - handle an execute function
+ operator
+-------------------------------------------------*/
+
+static EXPRERR execute_function(parsed_expression *expr, parse_token *token)
+{
+ UINT64 funcparams[MAX_FUNCTION_PARAMS];
+ symbol_entry *symbol = NULL;
+ int paramcount = 0;
+ parse_token t1;
+ EXPRERR exprerr;
+
+ /* pop off all pushed parameters */
+ while (paramcount < MAX_FUNCTION_PARAMS)
+ {
+ /* peek at the next token on the stack */
+ parse_token *peek = peek_token(expr, 0);
+ if (!peek)
+ return MAKE_EXPRERR_INVALID_PARAM_COUNT(token->offset);
+
+ /* if it is a function symbol, break out of the loop */
+ if (peek->type == TOK_SYMBOL)
+ {
+ symbol = peek->value.p;
+ if (symbol != NULL && symbol->type == SMT_FUNCTION)
+ {
+ pop_token(expr, &t1);
+ break;
+ }
+ }
+
+ /* otherwise, pop as a standard rval */
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ funcparams[MAX_FUNCTION_PARAMS - (++paramcount)] = t1.value.i;
+ }
+
+ /* if we didn't find the symbol, fail */
+ if (paramcount == MAX_FUNCTION_PARAMS)
+ return MAKE_EXPRERR_INVALID_PARAM_COUNT(token->offset);
+
+ /* validate the number of parameters */
+ if (paramcount < symbol->info.func.minparams || paramcount > symbol->info.func.maxparams)
+ return MAKE_EXPRERR_INVALID_PARAM_COUNT(token->offset);
+
+ /* execute the function and push the result */
+ t1.type = TOK_NUMBER;
+ t1.offset = token->offset;
+ t1.value.i = (*symbol->info.func.execute)(symbol->ref, paramcount, &funcparams[MAX_FUNCTION_PARAMS - paramcount]);
+ push_token(expr, &t1);
+
+ return EXPRERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ execute_tokens - execute a postfix sequence
+ of tokens
+-------------------------------------------------*/
+
+static EXPRERR execute_tokens(parsed_expression *expr, UINT64 *result)
+{
+ parse_token t1, t2, tempnum, tempmem;
+ EXPRERR exprerr;
+ int tokindex;
+
+ /* reset the token stack */
+ init_token_stack(expr);
+
+ /* create a temporary token for holding intermediate number and memory values */
+ tempnum.type = TOK_NUMBER;
+ tempnum.offset = 0;
+ tempnum.info = 0;
+ tempmem.type = TOK_MEMORY;
+ tempmem.offset = 0;
+ tempmem.info = 0;
+
+ /* loop over the entire sequence */
+ for (tokindex = 0; expr->token[tokindex].type != TOK_END; tokindex++)
+ {
+ parse_token *token = &expr->token[tokindex];
+
+ switch (token->type)
+ {
+ default:
+ case TOK_INVALID:
+ return MAKE_EXPRERR_INVALID_TOKEN(token->offset);
+
+ case TOK_SYMBOL:
+ case TOK_NUMBER:
+ case TOK_STRING:
+ exprerr = push_token(expr, token);
+ if (exprerr != 0)
+ return exprerr;
+ break;
+
+ case TOK_OPERATOR:
+ switch (token->value.i)
+ {
+ case TVL_PREINCREMENT:
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table) + 1;
+ tempnum.offset = t1.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_PREDECREMENT:
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table) - 1;
+ tempnum.offset = t1.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_POSTINCREMENT:
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.offset = t1.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i + 1);
+ break;
+
+ case TVL_POSTDECREMENT:
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.offset = t1.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i - 1);
+ break;
+
+ case TVL_COMPLEMENT:
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = !t1.value.i;
+ tempnum.offset = t1.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_NOT:
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = ~t1.value.i;
+ tempnum.offset = t1.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_UPLUS:
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i;
+ tempnum.offset = t1.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_UMINUS:
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = -t1.value.i;
+ tempnum.offset = t1.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_MULTIPLY:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i * t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_DIVIDE:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ if (t2.value.i == 0) return MAKE_EXPRERR_DIVIDE_BY_ZERO(t2.offset);
+ tempnum.value.i = t1.value.i / t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_MODULO:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ if (t2.value.i == 0) return MAKE_EXPRERR_DIVIDE_BY_ZERO(t2.offset);
+ tempnum.value.i = t1.value.i % t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_ADD:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i + t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_SUBTRACT:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i - t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_LSHIFT:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i << t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_RSHIFT:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i >> t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_LESS:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i < t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_LESSOREQUAL:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i <= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_GREATER:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i > t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_GREATEROREQUAL:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i >= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_EQUAL:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i == t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_NOTEQUAL:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i != t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_BAND:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i & t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_BXOR:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i ^ t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_BOR:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i | t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_LAND:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i && t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_LOR:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = t1.value.i || t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_ASSIGN:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ push_token(expr, &t2);
+ set_lval_value(&t1, expr->table, t2.value.i);
+ break;
+
+ case TVL_ASSIGNMULTIPLY:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.value.i *= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_ASSIGNDIVIDE:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ if (t2.value.i == 0) return MAKE_EXPRERR_DIVIDE_BY_ZERO(t2.offset);
+ tempnum.value.i /= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_ASSIGNMODULO:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ if (t2.value.i == 0) return MAKE_EXPRERR_DIVIDE_BY_ZERO(t2.offset);
+ tempnum.value.i %= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_ASSIGNADD:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.value.i += t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_ASSIGNSUBTRACT:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.value.i -= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_ASSIGNLSHIFT:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.value.i <<= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_ASSIGNRSHIFT:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.value.i >>= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_ASSIGNBAND:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.value.i &= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_ASSIGNBXOR:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.value.i ^= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_ASSIGNBOR:
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempnum.value.i = get_lval_value(&t1, expr->table);
+ tempnum.value.i |= t2.value.i;
+ tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset;
+ exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr;
+ set_lval_value(&t1, expr->table, tempnum.value.i);
+ break;
+
+ case TVL_COMMA:
+ if (!(token->info & TIN_FUNCTION))
+ {
+ exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ exprerr = push_token(expr, &t2); if (exprerr != 0) return exprerr;
+ }
+ break;
+
+ case TVL_MEMORYAT:
+ exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr;
+ tempmem.value.i = t1.value.i;
+ tempmem.info = token->info;
+ exprerr = push_token(expr, &tempmem); if (exprerr != 0) return exprerr;
+ break;
+
+ case TVL_EXECUTEFUNC:
+ exprerr = execute_function(expr, token); if (exprerr != 0) return exprerr;
+ break;
+
+ default:
+ return MAKE_EXPRERR_SYNTAX(token->offset);
+ }
+ break;
+ }
+ }
+
+ /* pop the final result */
+ exprerr = pop_token_rval(expr, &tempnum, expr->table);
+ if (exprerr != 0)
+ return exprerr;
+
+ /* error if our stack isn't empty */
+ if (peek_token(expr, 0) != NULL)
+ return MAKE_EXPRERR_SYNTAX(0);
+
+ *result = tempnum.value.i;
+ return EXPRERR_NONE;
+}
+
+
+
+/***************************************************************************
+ MISC HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ free_expression_strings - free all strings
+ allocated to an expression
+-------------------------------------------------*/
+
+static void free_expression_strings(parsed_expression *expr)
+{
+ int strindex;
+
+ /* free the original expression */
+ if (expr->original_string != NULL)
+ free(expr->original_string);
+ expr->original_string = NULL;
+
+ /* free all strings */
+ for (strindex = 0; strindex < MAX_EXPRESSION_STRINGS; strindex++)
+ if (expr->string[strindex] != NULL)
+ {
+ free(expr->string[strindex]);
+ expr->string[strindex] = NULL;
+ }
+}
+
+
+
+/***************************************************************************
+ CORE WRAPPER FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ expression_evaluate - evaluate a string
+ expression using the passed symbol table
+-------------------------------------------------*/
+
+EXPRERR expression_evaluate(const char *expression, const symbol_table *table, UINT64 *result)
+{
+ parsed_expression temp_expression;
+ EXPRERR exprerr;
+
+ /* first parse the tokens into the token array in order */
+ exprerr = parse_string_into_tokens(expression, &temp_expression, table);
+ if (exprerr != EXPRERR_NONE)
+ goto cleanup;
+
+ /* debugging */
+ print_tokens(stdout, &temp_expression);
+
+ /* convert the infix order to postfix order */
+ exprerr = infix_to_postfix(&temp_expression);
+ if (exprerr != EXPRERR_NONE)
+ goto cleanup;
+
+ /* debugging */
+ print_tokens(stdout, &temp_expression);
+
+ /* execute the expression to get the result */
+ exprerr = execute_tokens(&temp_expression, result);
+
+cleanup:
+ free_expression_strings(&temp_expression);
+ return exprerr;
+}
+
+
+/*-------------------------------------------------
+ expression_parse - parse an expression and
+ return an allocated token array
+-------------------------------------------------*/
+
+EXPRERR expression_parse(const char *expression, const symbol_table *table, parsed_expression **result)
+{
+ parsed_expression temp_expression;
+ EXPRERR exprerr;
+
+ /* first parse the tokens into the token array in order */
+ exprerr = parse_string_into_tokens(expression, &temp_expression, table);
+ if (exprerr != EXPRERR_NONE)
+ goto cleanup;
+
+ /* convert the infix order to postfix order */
+ exprerr = infix_to_postfix(&temp_expression);
+ if (exprerr != EXPRERR_NONE)
+ goto cleanup;
+
+ /* allocate memory for the result */
+ *result = malloc(sizeof(temp_expression));
+ if (!*result)
+ {
+ exprerr = MAKE_EXPRERR_OUT_OF_MEMORY(0);
+ goto cleanup;
+ }
+
+ /* copy the final expression and return */
+ **result = temp_expression;
+ return EXPRERR_NONE;
+
+cleanup:
+ free_expression_strings(&temp_expression);
+ return exprerr;
+}
+
+
+/*-------------------------------------------------
+ expression_execute - execute a
+ previously-parsed expression
+-------------------------------------------------*/
+
+EXPRERR expression_execute(parsed_expression *expr, UINT64 *result)
+{
+ /* execute the expression to get the result */
+ return execute_tokens(expr, result);
+}
+
+
+/*-------------------------------------------------
+ expression_free - free a previously
+ allocated parsed expression
+-------------------------------------------------*/
+
+void expression_free(parsed_expression *expr)
+{
+ if (expr)
+ {
+ free_expression_strings(expr);
+ free(expr);
+ }
+}
+
+
+/*-------------------------------------------------
+ expression_original_string - return a
+ pointer to the original expression string
+-------------------------------------------------*/
+
+const char *expression_original_string(parsed_expression *expr)
+{
+ return expr->original_string;
+}
+
+
+
+/***************************************************************************
+ ERROR HANDLING
+***************************************************************************/
+
+/*-------------------------------------------------
+ exprerr_to_string - return a friendly
+ string for a given expression error
+-------------------------------------------------*/
+
+const char *exprerr_to_string(EXPRERR error)
+{
+ switch (EXPRERR_ERROR_CLASS(error))
+ {
+ case EXPRERR_NOT_LVAL: return "not an lvalue";
+ case EXPRERR_NOT_RVAL: return "not an rvalue";
+ case EXPRERR_SYNTAX: return "syntax error";
+ case EXPRERR_UNKNOWN_SYMBOL: return "unknown symbol";
+ case EXPRERR_INVALID_NUMBER: return "invalid number";
+ case EXPRERR_INVALID_TOKEN: return "invalid token";
+ case EXPRERR_STACK_OVERFLOW: return "stack overflow";
+ case EXPRERR_STACK_UNDERFLOW: return "stack underflow";
+ case EXPRERR_UNBALANCED_PARENS: return "unbalanced parentheses";
+ case EXPRERR_DIVIDE_BY_ZERO: return "divide by zero";
+ case EXPRERR_OUT_OF_MEMORY: return "out of memory";
+ case EXPRERR_INVALID_PARAM_COUNT: return "invalid number of parameters";
+ case EXPRERR_UNBALANCED_QUOTES: return "unbalanced quotes";
+ case EXPRERR_TOO_MANY_STRINGS: return "too many strings";
+ default: return "unknown error";
+ }
+}
+
+
+
+/***************************************************************************
+ SYMBOL TABLES
+***************************************************************************/
+
+/*-------------------------------------------------
+ hash_string - simple string hash
+-------------------------------------------------*/
+
+INLINE UINT32 hash_string(const char *string)
+{
+ UINT32 hash = 0;
+ while (*string)
+ hash = (hash * 31) + *string++;
+ return hash;
+}
+
+
+/*-------------------------------------------------
+ symtable_alloc - allocate a symbol table
+-------------------------------------------------*/
+
+symbol_table *symtable_alloc(symbol_table *parent)
+{
+ symbol_table *table;
+
+ /* allocate memory for the table */
+ table = malloc(sizeof(*table));
+ if (!table)
+ return NULL;
+
+ /* initialize the data */
+ memset(table, 0, sizeof(*table));
+ table->parent = parent;
+ return table;
+}
+
+
+/*-------------------------------------------------
+ symtable_add - add a new symbol to a
+ symbol table
+-------------------------------------------------*/
+
+int symtable_add(symbol_table *table, const char *name, const symbol_entry *entry)
+{
+ internal_symbol_entry *symbol;
+ symbol_entry *oldentry;
+ char *newstring;
+ UINT32 hash_index;
+ int strindex;
+ int all_digits, i;
+
+ /* we cannot add numeric symbols */
+ all_digits = TRUE;
+ for (i = 0; name[i]; i++)
+ {
+ if (!isdigit(name[i]))
+ {
+ all_digits = FALSE;
+ break;
+ }
+ }
+ assert_always(!all_digits, "All-digit symbols are not allowed");
+
+ /* see if we already have an entry and just overwrite it if we do */
+ oldentry = (symbol_entry *)symtable_find(table, name);
+ if (oldentry)
+ {
+ *oldentry = *entry;
+ return 1;
+ }
+
+ /* otherwise, allocate a new entry */
+ symbol = malloc(sizeof(*symbol));
+ if (!symbol)
+ return 0;
+ memset(symbol, 0, sizeof(*symbol));
+
+ /* allocate space for a copy of the string */
+ newstring = malloc(strlen(name) + 1);
+ if (!newstring)
+ {
+ free(symbol);
+ return 0;
+ }
+
+ /* copy the string, converting to lowercase */
+ for (strindex = 0; name[strindex] != 0; strindex++)
+ newstring[strindex] = tolower(name[strindex]);
+ newstring[strindex] = 0;
+
+ /* fill in the details */
+ symbol->name = newstring;
+ symbol->entry = *entry;
+
+ /* add the entry to the hash table */
+ hash_index = hash_string(newstring) % SYM_TABLE_HASH_SIZE;
+ symbol->next = table->hash[hash_index];
+ table->hash[hash_index] = symbol;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ symtable_add_register - add a new
+ register symbol to a symbol table
+-------------------------------------------------*/
+
+int symtable_add_register(symbol_table *table, const char *name, UINT32 ref, UINT64 (*getter)(UINT32), void (*setter)(UINT32, UINT64))
+{
+ symbol_entry symbol;
+
+ symbol.ref = ref;
+ symbol.type = SMT_REGISTER;
+ symbol.info.reg.getter = getter;
+ symbol.info.reg.setter = setter;
+ return symtable_add(table, name, &symbol);
+}
+
+
+/*-------------------------------------------------
+ symtable_add_function - add a new
+ function symbol to a symbol table
+-------------------------------------------------*/
+
+int symtable_add_function(symbol_table *table, const char *name, UINT32 ref, UINT16 minparams, UINT16 maxparams, UINT64 (*execute)(UINT32, UINT32, UINT64 *))
+{
+ symbol_entry symbol;
+
+ symbol.ref = ref;
+ symbol.type = SMT_FUNCTION;
+ symbol.info.func.minparams = minparams;
+ symbol.info.func.maxparams = maxparams;
+ symbol.info.func.execute = execute;
+ return symtable_add(table, name, &symbol);
+}
+
+
+/*-------------------------------------------------
+ symtable_add_value - add a new
+ value symbol to a symbol table
+-------------------------------------------------*/
+
+int symtable_add_value(symbol_table *table, const char *name, UINT64 value)
+{
+ symbol_entry symbol;
+
+ symbol.ref = 0;
+ symbol.type = SMT_VALUE;
+ symbol.info.gen.value = value;
+ return symtable_add(table, name, &symbol);
+}
+
+
+/*-------------------------------------------------
+ symtable_find - find a symbol in a symbol
+ table
+-------------------------------------------------*/
+
+const symbol_entry *symtable_find(const symbol_table *table, const char *name)
+{
+ UINT32 hash_index = hash_string(name) % SYM_TABLE_HASH_SIZE;
+ const internal_symbol_entry *symbol;
+
+ /* loop until we run out of tables */
+ while (table)
+ {
+ /* search linearly within this hash entry */
+ for (symbol = table->hash[hash_index]; symbol; symbol = symbol->next)
+ if (!strcmp(symbol->name, name))
+ return &symbol->entry;
+
+ /* look in the parent */
+ table = table->parent;
+ }
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ symtable_find_indexed - find an indexed symbol
+ in a symbol table
+-------------------------------------------------*/
+
+const char *symtable_find_indexed(const symbol_table *table, int index, const symbol_entry **entry)
+{
+ const internal_symbol_entry *symbol;
+ int hash_index;
+
+ /* loop over hash entries, then over entries within each bucket */
+ for (hash_index = 0; hash_index < SYM_TABLE_HASH_SIZE; hash_index++)
+ for (symbol = table->hash[hash_index]; symbol; symbol = symbol->next)
+ if (index-- == 0)
+ {
+ if (entry)
+ *entry = &symbol->entry;
+ return symbol->name;
+ }
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ symtable_free - free a symbol table
+-------------------------------------------------*/
+
+void symtable_free(symbol_table *table)
+{
+ internal_symbol_entry *entry, *next;
+ int hash_index;
+
+ /* free all the entries in the hash table */
+ for (hash_index = 0; hash_index < SYM_TABLE_HASH_SIZE; hash_index++)
+ for (entry = table->hash[hash_index]; entry; entry = next)
+ {
+ /* free the allocated name */
+ if (entry->name)
+ free((void *)entry->name);
+
+ /* remove from this list and put on the free list */
+ next = entry->next;
+ free(entry);
+ }
+
+ /* free the structure */
+ free(table);
+}
diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h
new file mode 100644
index 00000000000..53364aea14d
--- /dev/null
+++ b/src/emu/debug/express.h
@@ -0,0 +1,160 @@
+/***************************************************************************
+
+ express.h
+ Generic expressions engine.
+ Written by Aaron Giles
+ Copyright (c) 2006, Aaron Giles
+
+***************************************************************************/
+
+#ifndef __EXPRESS_H__
+#define __EXPRESS_H__
+
+#include "mamecore.h"
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* maximum number of parameters in a function call */
+#define MAX_FUNCTION_PARAMS (16)
+
+/* values for symbol_entry.type */
+#define SMT_REGISTER (0)
+#define SMT_FUNCTION (1)
+#define SMT_VALUE (2)
+
+/* values for the error code in an expression error */
+#define EXPRERR_NONE (0)
+#define EXPRERR_NOT_LVAL (1)
+#define EXPRERR_NOT_RVAL (2)
+#define EXPRERR_SYNTAX (3)
+#define EXPRERR_UNKNOWN_SYMBOL (4)
+#define EXPRERR_INVALID_NUMBER (5)
+#define EXPRERR_INVALID_TOKEN (6)
+#define EXPRERR_STACK_OVERFLOW (7)
+#define EXPRERR_STACK_UNDERFLOW (8)
+#define EXPRERR_UNBALANCED_PARENS (9)
+#define EXPRERR_DIVIDE_BY_ZERO (10)
+#define EXPRERR_OUT_OF_MEMORY (11)
+#define EXPRERR_INVALID_PARAM_COUNT (12)
+#define EXPRERR_UNBALANCED_QUOTES (13)
+#define EXPRERR_TOO_MANY_STRINGS (14)
+
+/* values for the address space passed to external_read/write_memory */
+#define EXPSPACE_PROGRAM (0)
+#define EXPSPACE_DATA (1)
+#define EXPSPACE_IO (2)
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* expression error assembly/disassembly macros */
+#define EXPRERR_ERROR_CLASS(x) ((x) >> 16)
+#define EXPRERR_ERROR_OFFSET(x) ((x) & 0xffff)
+#define MAKE_EXPRERR(a,b) (((a) << 16) | ((b) & 0xffff))
+
+/* macros to assemble specific error conditions */
+#define MAKE_EXPRERR_NOT_LVAL(x) MAKE_EXPRERR(EXPRERR_NOT_LVAL, (x))
+#define MAKE_EXPRERR_NOT_RVAL(x) MAKE_EXPRERR(EXPRERR_NOT_RVAL, (x))
+#define MAKE_EXPRERR_SYNTAX(x) MAKE_EXPRERR(EXPRERR_SYNTAX, (x))
+#define MAKE_EXPRERR_UNKNOWN_SYMBOL(x) MAKE_EXPRERR(EXPRERR_UNKNOWN_SYMBOL, (x))
+#define MAKE_EXPRERR_INVALID_NUMBER(x) MAKE_EXPRERR(EXPRERR_INVALID_NUMBER, (x))
+#define MAKE_EXPRERR_INVALID_TOKEN(x) MAKE_EXPRERR(EXPRERR_INVALID_TOKEN, (x))
+#define MAKE_EXPRERR_STACK_OVERFLOW(x) MAKE_EXPRERR(EXPRERR_STACK_OVERFLOW, (x))
+#define MAKE_EXPRERR_STACK_UNDERFLOW(x) MAKE_EXPRERR(EXPRERR_STACK_UNDERFLOW, (x))
+#define MAKE_EXPRERR_UNBALANCED_PARENS(x) MAKE_EXPRERR(EXPRERR_UNBALANCED_PARENS, (x))
+#define MAKE_EXPRERR_DIVIDE_BY_ZERO(x) MAKE_EXPRERR(EXPRERR_DIVIDE_BY_ZERO, (x))
+#define MAKE_EXPRERR_OUT_OF_MEMORY(x) MAKE_EXPRERR(EXPRERR_OUT_OF_MEMORY, (x))
+#define MAKE_EXPRERR_INVALID_PARAM_COUNT(x) MAKE_EXPRERR(EXPRERR_INVALID_PARAM_COUNT, (x))
+#define MAKE_EXPRERR_UNBALANCED_QUOTES(x) MAKE_EXPRERR(EXPRERR_UNBALANCED_QUOTES, (x))
+#define MAKE_EXPRERR_TOO_MANY_STRINGS(x) MAKE_EXPRERR(EXPRERR_TOO_MANY_STRINGS, (x))
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* symbol_entry describes a symbol in a symbol table */
+typedef struct _symbol_entry symbol_entry;
+struct _symbol_entry
+{
+ UINT32 ref; /* internal reference */
+ UINT32 type; /* type of symbol */
+ union
+ {
+ /* register info */
+ struct
+ {
+ UINT64 (*getter)(UINT32); /* value getter */
+ void (*setter)(UINT32, UINT64); /* value setter */
+ } reg;
+
+ /* function info */
+ struct
+ {
+ UINT16 minparams; /* minimum expected parameters */
+ UINT16 maxparams; /* maximum expected parameters */
+ UINT64 (*execute)(UINT32, UINT32, UINT64 *);/* execute */
+ } func;
+
+ /* generic info */
+ struct generic_info
+ {
+ void * ptr; /* generic pointer */
+ UINT64 value; /* generic value */
+ } gen;
+ } info;
+};
+
+
+/* symbol_table is an opaque structure for holding a collection of symbols */
+typedef struct _symbol_table symbol_table;
+
+
+/* parsed_expression is an opaque structure for holding a pre-parsed expression */
+typedef struct _parsed_expression parsed_expression;
+
+
+/* EXPRERR is an error code for expression evaluation */
+typedef UINT32 EXPRERR;
+
+
+
+/***************************************************************************
+ EXTERNAL DEPENDENCIES
+***************************************************************************/
+
+/* These must be provided by the caller */
+UINT64 external_read_memory(int space, UINT32 offset, int size);
+void external_write_memory(int space, UINT32 offset, int size, UINT64 value);
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* expression evaluation */
+EXPRERR expression_evaluate(const char *expression, const symbol_table *table, UINT64 *result);
+EXPRERR expression_parse(const char *expression, const symbol_table *table, parsed_expression **result);
+EXPRERR expression_execute(parsed_expression *expr, UINT64 *result);
+void expression_free(parsed_expression *expr);
+const char * expression_original_string(parsed_expression *expr);
+const char * exprerr_to_string(EXPRERR error);
+
+/* symbol table manipulation */
+symbol_table * symtable_alloc(symbol_table *parent);
+int symtable_add(symbol_table *table, const char *name, const symbol_entry *entry);
+int symtable_add_register(symbol_table *table, const char *name, UINT32 ref, UINT64 (*getter)(UINT32), void (*setter)(UINT32, UINT64));
+int symtable_add_function(symbol_table *table, const char *name, UINT32 ref, UINT16 minparams, UINT16 maxparams, UINT64 (*execute)(UINT32, UINT32, UINT64 *));
+int symtable_add_value(symbol_table *table, const char *name, UINT64 value);
+const symbol_entry * symtable_find(const symbol_table *table, const char *name);
+const char * symtable_find_indexed(const symbol_table *table, int index, const symbol_entry **entry);
+void symtable_free(symbol_table *table);
+
+#endif
diff --git a/src/emu/debug/textbuf.c b/src/emu/debug/textbuf.c
new file mode 100644
index 00000000000..25e7dacd9f5
--- /dev/null
+++ b/src/emu/debug/textbuf.c
@@ -0,0 +1,326 @@
+/***************************************************************************
+
+ textbuf.c
+
+ Debugger text buffering engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "mamecore.h"
+#include "textbuf.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_LINE_LENGTH 250
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* typedef struct _text_buffer text_buffer; -- declared in textbuf.h */
+struct _text_buffer
+{
+ char * buffer;
+ INT32 * lineoffs;
+ INT32 bufsize;
+ INT32 bufstart;
+ INT32 bufend;
+ INT32 linesize;
+ INT32 linestart;
+ INT32 lineend;
+ UINT32 linestartseq;
+ INT32 maxwidth;
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ buffer_used - return the number of bytes
+ currently held in the buffer
+-------------------------------------------------*/
+
+INLINE INT32 buffer_used(text_buffer *text)
+{
+ INT32 used = text->bufend - text->bufstart;
+ if (used < 0)
+ used += text->bufsize;
+ return used;
+}
+
+
+/*-------------------------------------------------
+ buffer_space - return the number of bytes
+ available in the buffer
+-------------------------------------------------*/
+
+INLINE INT32 buffer_space(text_buffer *text)
+{
+ return text->bufsize - buffer_used(text);
+}
+
+
+
+/***************************************************************************
+
+ Buffer object management
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ text_buffer_alloc - allocate a new text buffer
+-------------------------------------------------*/
+
+text_buffer *text_buffer_alloc(UINT32 bytes, UINT32 lines)
+{
+ text_buffer *text;
+
+ /* allocate memory for the text buffer object */
+ text = malloc(sizeof(*text));
+ if (!text)
+ return NULL;
+
+ /* allocate memory for the buffer itself */
+ text->buffer = malloc(bytes);
+ if (!text->buffer)
+ {
+ free(text);
+ return NULL;
+ }
+
+ /* allocate memory for the lines array */
+ text->lineoffs = malloc(lines * sizeof(text->lineoffs[0]));
+ if (!text->lineoffs)
+ {
+ free(text->buffer);
+ free(text);
+ return NULL;
+ }
+
+ /* initialize the buffer description */
+ text->bufsize = bytes;
+ text->linesize = lines;
+ text_buffer_clear(text);
+
+ return text;
+}
+
+
+/*-------------------------------------------------
+ text_buffer_free - free a previously allocated
+ text buffer
+-------------------------------------------------*/
+
+void text_buffer_free(text_buffer *text)
+{
+ if (text->lineoffs)
+ free(text->lineoffs);
+ if (text->buffer)
+ free(text->buffer);
+ free(text);
+}
+
+
+/*-------------------------------------------------
+ text_buffer_clear - clear a text buffer
+-------------------------------------------------*/
+
+void text_buffer_clear(text_buffer *text)
+{
+ /* reset all the buffer pointers and other bits */
+ text->bufstart = 0;
+ text->bufend = 0;
+
+ text->linestart = 0;
+ text->lineend = 0;
+ text->linestartseq = 0;
+
+ text->maxwidth = 0;
+
+ /* create the initial line */
+ text->lineoffs[0] = 0;
+ text->buffer[text->lineoffs[0]] = 0;
+}
+
+
+
+/***************************************************************************
+
+ Adding data to the buffer
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ text_buffer_print - print data to the text
+ buffer
+-------------------------------------------------*/
+
+void text_buffer_print(text_buffer *text, const char *data)
+{
+ text_buffer_print_wrap(text, data, 10000);
+}
+
+
+/*-------------------------------------------------
+ text_buffer_print_wrap - print data to the
+ text buffer with word wrapping to a given
+ column
+-------------------------------------------------*/
+
+void text_buffer_print_wrap(text_buffer *text, const char *data, int wrapcol)
+{
+ INT32 stopcol = (wrapcol < MAX_LINE_LENGTH) ? wrapcol : MAX_LINE_LENGTH;
+ INT32 needed_space;
+
+ /* we need to ensure there is enough space for this string plus enough for the max line length */
+ needed_space = (INT32)strlen(data) + MAX_LINE_LENGTH;
+
+ /* make space in the buffer if we need to */
+ while (buffer_space(text) < needed_space && text->linestart != text->lineend)
+ {
+ text->linestartseq++;
+ if (++text->linestart >= text->linesize)
+ text->linestart = 0;
+ text->bufstart = text->lineoffs[text->linestart];
+ }
+
+ /* now add the data */
+ for ( ; *data; data++)
+ {
+ int ch = *data;
+ int linelen;
+
+ /* a CR resets our position */
+ if (ch == '\r')
+ text->bufend = text->lineoffs[text->lineend];
+
+ /* non-CR data is just characters */
+ else if (ch != '\n')
+ text->buffer[text->bufend++] = ch;
+
+ /* an explicit newline or line-too-long condition inserts a newline */
+ linelen = text->bufend - text->lineoffs[text->lineend];
+ if (ch == '\n' || linelen >= stopcol)
+ {
+ int overflow = 0;
+
+ /* if we're wrapping, back off until we hit a space */
+ if (linelen >= wrapcol)
+ {
+ /* scan backwards, removing characters along the way */
+ overflow = 1;
+ while (overflow < linelen && text->buffer[text->bufend - overflow] != ' ')
+ overflow++;
+
+ /* if we found a space, take it; otherwise, reset and pretend we didn't try */
+ if (overflow < linelen)
+ linelen -= overflow;
+ else
+ overflow = 0;
+ }
+
+ /* did we beat the max width */
+ if (linelen > text->maxwidth)
+ text->maxwidth = linelen;
+
+ /* append a terminator */
+ if (overflow == 0)
+ text->buffer[text->bufend++] = 0;
+ else
+ text->buffer[text->bufend - overflow] = 0;
+
+ /* determine what the next line will be */
+ if (++text->lineend >= text->linesize)
+ text->lineend = 0;
+
+ /* if we're out of lines, consume the next one */
+ if (text->lineend == text->linestart)
+ {
+ text->linestartseq++;
+ if (++text->linestart >= text->linesize)
+ text->linestart = 0;
+ text->bufstart = text->lineoffs[text->linestart];
+ }
+
+ /* if we don't have enough room in the buffer for a max line, wrap to the start */
+ if (text->bufend + MAX_LINE_LENGTH + 1 >= text->bufsize)
+ text->bufend = 0;
+
+ /* create a new empty line */
+ text->lineoffs[text->lineend] = text->bufend - (overflow ? (overflow - 1) : 0);
+ }
+ }
+
+ /* NULL terminate what we have on this line */
+ text->buffer[text->bufend] = 0;
+}
+
+
+
+/***************************************************************************
+
+ Reading data from the buffer
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ text_buffer_max_width - return the maximum
+ width of all lines seen so far
+-------------------------------------------------*/
+
+UINT32 text_buffer_max_width(text_buffer *text)
+{
+ return text->maxwidth;
+}
+
+
+/*-------------------------------------------------
+ text_buffer_num_lines - return the number of
+ lines in the text buffer
+-------------------------------------------------*/
+
+UINT32 text_buffer_num_lines(text_buffer *text)
+{
+ INT32 lines = text->lineend + 1 - text->linestart;
+ if (lines <= 0)
+ lines += text->linesize;
+ return lines;
+}
+
+
+/*-------------------------------------------------
+ text_buffer_line_index_to_seqnum - convert a
+ line index into a sequence number
+-------------------------------------------------*/
+
+UINT32 text_buffer_line_index_to_seqnum(text_buffer *text, UINT32 index)
+{
+ return text->linestartseq + index;
+}
+
+
+/*-------------------------------------------------
+ text_buffer_get_seqnum_line - get a pointer to
+ an indexed line in the buffer
+-------------------------------------------------*/
+
+const char *text_buffer_get_seqnum_line(text_buffer *text, UINT32 seqnum)
+{
+ UINT32 numlines = text_buffer_num_lines(text);
+ UINT32 index = seqnum - text->linestartseq;
+ if (index >= numlines)
+ return NULL;
+ return &text->buffer[text->lineoffs[(text->linestart + index) % text->linesize]];
+}
diff --git a/src/emu/debug/textbuf.h b/src/emu/debug/textbuf.h
new file mode 100644
index 00000000000..2504e2a535c
--- /dev/null
+++ b/src/emu/debug/textbuf.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+
+ textbuf.h
+
+ Debugger text buffering engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __TEXTBUF_H__
+#define __TEXTBUF_H__
+
+#include "osd_cpu.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _text_buffer text_buffer;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* allocate a new text buffer */
+text_buffer *text_buffer_alloc(UINT32 bytes, UINT32 lines);
+
+/* free a text buffer */
+void text_buffer_free(text_buffer *text);
+
+/* clear a text buffer */
+void text_buffer_clear(text_buffer *text);
+
+/* "print" data to a text buffer */
+void text_buffer_print(text_buffer *text, const char *data);
+
+/* "print" data to a text buffer with word wrapping to a given column */
+void text_buffer_print_wrap(text_buffer *text, const char *data, int wrapcol);
+
+/* get the maximum width of lines seen so far */
+UINT32 text_buffer_max_width(text_buffer *text);
+
+/* get the current number of lines in the buffer */
+UINT32 text_buffer_num_lines(text_buffer *text);
+
+/* get an absolute sequence number for a given line */
+UINT32 text_buffer_line_index_to_seqnum(text_buffer *text, UINT32 index);
+
+/* get a sequenced line from the text buffer */
+const char *text_buffer_get_seqnum_line(text_buffer *text, UINT32 seqnum);
+
+
+#endif /* __TEXTBUF_H__ */
diff --git a/src/emu/debugger.h b/src/emu/debugger.h
new file mode 100644
index 00000000000..d1e5243f6a3
--- /dev/null
+++ b/src/emu/debugger.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+
+ debugger.h
+
+ General debugging interfaces
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************/
+
+#pragma once
+
+#ifndef __DEBUGGER_H__
+#define __DEBUGGER_H__
+
+#include "mame.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* handy macro for hard-coding debugger breaks */
+#ifdef MAME_DEBUG
+#define DEBUGGER_BREAK if (Machine->debug_mode) mame_debug_break();
+#else
+#define DEBUGGER_BREAK
+#endif
+
+
+/* handy macro for CPU cores */
+#ifdef MAME_DEBUG
+#define CALL_MAME_DEBUG if (Machine->debug_mode) mame_debug_hook();
+#else
+#define CALL_MAME_DEBUG
+#endif
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* initialize the debugger */
+void mame_debug_init(running_machine *machine);
+
+/* call this once per instruction from CPU cores */
+void mame_debug_hook(void);
+
+/* call this to break into the debugger as soon as possible */
+void mame_debug_break(void);
+
+/* call this to determine if the debugger is currently active (broken) */
+int mame_debug_is_active(void);
+
+
+
+/***************************************************************************
+ STUBS
+***************************************************************************/
+
+#ifndef MAME_DEBUG
+#define mame_debug_init(m) do { } while (0)
+#define mame_debug_hook() do { } while (0)
+#define mame_debug_break() do { } while (0)
+#define mame_debug_is_active() FALSE
+#endif
+
+
+#endif /* __DEBUGGER_H__ */
diff --git a/src/emu/drawgfx.c b/src/emu/drawgfx.c
new file mode 100644
index 00000000000..89a9f3231ea
--- /dev/null
+++ b/src/emu/drawgfx.c
@@ -0,0 +1,5859 @@
+/*********************************************************************
+
+ drawgfx.c
+
+ Generic graphic functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#ifndef DECLARE
+
+#include "driver.h"
+#include "profiler.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#ifdef LSB_FIRST
+#define SHIFT0 0
+#define SHIFT1 8
+#define SHIFT2 16
+#define SHIFT3 24
+#else
+#define SHIFT3 0
+#define SHIFT2 8
+#define SHIFT1 16
+#define SHIFT0 24
+#endif
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+UINT8 gfx_drawmode_table[256];
+UINT8 gfx_alpharange_table[256];
+
+static UINT8 is_raw[TRANSPARENCY_MODES];
+
+alpha_cache drawgfx_alpha_cache;
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ write_dword - safely write an unaligned DWORD
+-------------------------------------------------*/
+
+#ifdef ALIGN_INTS /* GSL 980108 read/write nonaligned dword routine for ARM processor etc */
+
+INLINE void write_dword(void *address, UINT32 data)
+{
+ if ((FPTR)address & 3)
+ {
+ *((UINT8 *)address) = (data>>SHIFT0);
+ *((UINT8 *)address+1) = (data>>SHIFT1);
+ *((UINT8 *)address+2) = (data>>SHIFT2);
+ *((UINT8 *)address+3) = (data>>SHIFT3);
+ return;
+ }
+ else
+ *(UINT32 *)address = data;
+}
+
+#else
+
+#define write_dword(address,data) *(int *)address=data
+
+#endif
+
+
+/*-------------------------------------------------
+ readbit - read a single bit from a base
+ offset
+-------------------------------------------------*/
+
+INLINE int readbit(const UINT8 *src, int bitnum)
+{
+ return src[bitnum / 8] & (0x80 >> (bitnum % 8));
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+void drawgfx_init(running_machine *machine)
+{
+ /* fill in the raw drawing mode table */
+ is_raw[TRANSPARENCY_NONE_RAW] = 1;
+ is_raw[TRANSPARENCY_PEN_RAW] = 1;
+ is_raw[TRANSPARENCY_PENS_RAW] = 1;
+ is_raw[TRANSPARENCY_PEN_TABLE_RAW] = 1;
+ is_raw[TRANSPARENCY_BLEND_RAW] = 1;
+
+ /* initialize the alpha drawing table */
+ alpha_set_level(255);
+}
+
+
+
+/***************************************************************************
+ GRAPHICS DECODING
+***************************************************************************/
+
+/*-------------------------------------------------
+ calc_penusage - calculate the pen usage for
+ a given graphics tile
+-------------------------------------------------*/
+
+static void calc_penusage(gfx_element *gfx, int num)
+{
+ const UINT8 *dp = gfx->gfxdata + num * gfx->char_modulo;
+ UINT32 usage = 0;
+ int x, y;
+
+ /* if nothing allocated, don't do it */
+ if (!gfx->pen_usage)
+ return;
+
+ /* packed case */
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ for (y = 0; y < gfx->height; y++)
+ {
+ for (x = 0; x < gfx->width/2; x++)
+ usage |= (1 << (dp[x] & 0x0f)) | (1 << (dp[x] >> 4));
+
+ dp += gfx->line_modulo;
+ }
+ }
+
+ /* unpacked case */
+ else
+ {
+ for (y = 0; y < gfx->height; y++)
+ {
+ for (x = 0; x < gfx->width; x++)
+ usage |= 1 << dp[x];
+
+ dp += gfx->line_modulo;
+ }
+ }
+
+ /* store the final result */
+ gfx->pen_usage[num] = usage;
+}
+
+
+/*-------------------------------------------------
+ decodechar - decode a single character based
+ on a specified layout
+-------------------------------------------------*/
+
+void decodechar(gfx_element *gfx, int num, const UINT8 *src, const gfx_layout *gl)
+{
+ const UINT32 *xoffset = gl->extxoffs ? gl->extxoffs : gl->xoffset;
+ const UINT32 *yoffset = gl->extyoffs ? gl->extyoffs : gl->yoffset;
+ UINT8 *dp = gfx->gfxdata + num * gfx->char_modulo;
+ int plane, x, y;
+
+ /* zap the data to 0 */
+ memset(dp, 0, gfx->char_modulo);
+
+ /* packed case */
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ for (plane = 0; plane < gl->planes; plane++)
+ {
+ int planebit = 1 << (gl->planes - 1 - plane);
+ int planeoffs = num * gl->charincrement + gl->planeoffset[plane];
+
+ for (y = 0; y < gfx->height; y++)
+ {
+ int yoffs = planeoffs + yoffset[y];
+
+ dp = gfx->gfxdata + num * gfx->char_modulo + y * gfx->line_modulo;
+ for (x = 0; x < gfx->width; x += 2)
+ {
+ if (readbit(src, yoffs + xoffset[x+0]))
+ dp[x+0] |= planebit;
+ if (readbit(src, yoffs + xoffset[x+1]))
+ dp[x+1] |= planebit;
+ }
+ }
+ }
+ }
+
+ /* unpacked case */
+ else
+ {
+ for (plane = 0; plane < gl->planes; plane++)
+ {
+ int planebit = 1 << (gl->planes - 1 - plane);
+ int planeoffs = num * gl->charincrement + gl->planeoffset[plane];
+
+ for (y = 0; y < gfx->height; y++)
+ {
+ int yoffs = planeoffs + yoffset[y];
+
+ dp = gfx->gfxdata + num * gfx->char_modulo + y * gfx->line_modulo;
+ for (x = 0; x < gfx->width; x++)
+ if (readbit(src, yoffs + xoffset[x]))
+ dp[x] |= planebit;
+ }
+ }
+ }
+
+ /* compute pen usage */
+ calc_penusage(gfx, num);
+}
+
+
+
+/***************************************************************************
+ GRAPHICS SETS
+***************************************************************************/
+
+/*-------------------------------------------------
+ allocgfx - allocate a gfx_element structure
+ based on a given layout
+-------------------------------------------------*/
+
+gfx_element *allocgfx(const gfx_layout *gl)
+{
+ gfx_element *gfx;
+
+ /* allocate memory for the gfx_element structure */
+ gfx = malloc_or_die(sizeof(*gfx));
+ memset(gfx, 0, sizeof(*gfx));
+
+ /* copy the layout */
+ gfx->layout = *gl;
+ if (gl->extxoffs != NULL)
+ {
+ UINT32 *buffer = malloc_or_die(sizeof(buffer[0]) * gl->width);
+ memcpy(buffer, gl->extxoffs, sizeof(gfx->layout.extxoffs[0]) * gl->width);
+ gfx->layout.extxoffs = buffer;
+ }
+ if (gl->extyoffs != NULL)
+ {
+ UINT32 *buffer = malloc_or_die(sizeof(buffer[0]) * gl->height);
+ memcpy(buffer, gl->extyoffs, sizeof(gfx->layout.extyoffs[0]) * gl->height);
+ gfx->layout.extyoffs = buffer;
+ }
+
+ /* fill in the rest */
+ gfx->width = gl->width;
+ gfx->height = gl->height;
+ gfx->total_elements = gl->total;
+ gfx->color_base = 0;
+ gfx->color_depth = 1 << gl->planes;
+ gfx->color_granularity = 1 << gl->planes;
+ if (gfx->color_depth <= 32)
+ gfx->pen_usage = malloc_or_die(gfx->total_elements * sizeof(*gfx->pen_usage));
+
+ /* raw graphics case */
+ if (gl->planeoffset[0] == GFX_RAW)
+ {
+ /* modulos are determined for us by the layout */
+ gfx->line_modulo = (gl->extyoffs ? gl->extyoffs[0] : gl->yoffset[0]) / 8;
+ gfx->char_modulo = gl->charincrement / 8;
+
+ /* don't free the data because we will get a pointer at decode time */
+ gfx->flags |= GFX_ELEMENT_DONT_FREE;
+ if (gl->planes <= 4)
+ gfx->flags |= GFX_ELEMENT_PACKED;
+ }
+
+ /* decoded graphics case */
+ else
+ {
+ /* we get to pick our own modulos */
+ gfx->line_modulo = gfx->width;
+ gfx->char_modulo = gfx->line_modulo * gfx->height;
+
+ /* allocate memory for the data */
+ gfx->gfxdata = malloc_or_die(gfx->total_elements * gfx->char_modulo * sizeof(UINT8));
+ }
+
+ return gfx;
+}
+
+
+/*-------------------------------------------------
+ decodegfx - decode a series of tiles from
+ a particular gfx_element
+-------------------------------------------------*/
+
+void decodegfx(gfx_element *gfx, const UINT8 *src, UINT32 first, UINT32 count)
+{
+ int last = first + count - 1;
+ int c;
+
+ assert(gfx);
+ assert(first < gfx->total_elements);
+ assert(last < gfx->total_elements);
+
+ /* if this is raw graphics data, just set the pointer and compute pen usage */
+ if (gfx->flags & GFX_ELEMENT_DONT_FREE)
+ {
+ /* if we got a pointer, set it */
+ if (first == 0 && src)
+ gfx->gfxdata = (UINT8 *)src;
+
+ /* compute pen usage for everything */
+ for (c = first; c <= last; c++)
+ calc_penusage(gfx, c);
+ }
+
+ /* otherwise, we get to manually decode */
+ else
+ {
+ for (c = first; c <= last; c++)
+ decodechar(gfx, c, src, &gfx->layout);
+ }
+}
+
+
+/*-------------------------------------------------
+ freegfx - free a gfx_element
+-------------------------------------------------*/
+
+void freegfx(gfx_element *gfx)
+{
+ /* ignore NULL frees */
+ if (gfx == NULL)
+ return;
+
+ /* free our data */
+ if (gfx->layout.extyoffs)
+ free((void *)gfx->layout.extyoffs);
+ if (gfx->layout.extxoffs)
+ free((void *)gfx->layout.extxoffs);
+ if (gfx->pen_usage)
+ free(gfx->pen_usage);
+ if (!(gfx->flags & GFX_ELEMENT_DONT_FREE))
+ free(gfx->gfxdata);
+ free(gfx);
+}
+
+
+
+/***************************************************************************
+ BLOCKMOVE PRIMITIVES
+***************************************************************************/
+
+INLINE void blockmove_NtoN_transpen_noremap8(
+ const UINT8 *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ UINT8 *dstdata,int dstmodulo,
+ int transpen)
+{
+ UINT8 *end;
+ int trans4;
+ UINT32 *sd4;
+
+ srcmodulo -= srcwidth;
+ dstmodulo -= srcwidth;
+
+ trans4 = transpen * 0x01010101;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (((FPTR)srcdata & 3) && dstdata < end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) *dstdata = col;
+ dstdata++;
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata <= end - 4)
+ {
+ UINT32 col4;
+
+ if ((col4 = *(sd4++)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if( (xod4&0x000000ff) && (xod4&0x0000ff00) &&
+ (xod4&0x00ff0000) && (xod4&0xff000000) )
+ {
+ write_dword((UINT32 *)dstdata,col4);
+ }
+ else
+ {
+ if (xod4 & (0xff<<SHIFT0)) dstdata[0] = col4>>SHIFT0;
+ if (xod4 & (0xff<<SHIFT1)) dstdata[1] = col4>>SHIFT1;
+ if (xod4 & (0xff<<SHIFT2)) dstdata[2] = col4>>SHIFT2;
+ if (xod4 & (0xff<<SHIFT3)) dstdata[3] = col4>>SHIFT3;
+ }
+ }
+ dstdata += 4;
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) *dstdata = col;
+ dstdata++;
+ }
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+}
+
+INLINE void blockmove_NtoN_transpen_noremap_flipx8(
+ const UINT8 *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ UINT8 *dstdata,int dstmodulo,
+ int transpen)
+{
+ UINT8 *end;
+ int trans4;
+ UINT32 *sd4;
+
+ srcmodulo += srcwidth;
+ dstmodulo -= srcwidth;
+ //srcdata += srcwidth-1;
+ srcdata -= 3;
+
+ trans4 = transpen * 0x01010101;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (((FPTR)srcdata & 3) && dstdata < end) /* longword align */
+ {
+ int col;
+
+ col = srcdata[3];
+ srcdata--;
+ if (col != transpen) *dstdata = col;
+ dstdata++;
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata <= end - 4)
+ {
+ UINT32 col4;
+
+ if ((col4 = *(sd4--)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if (xod4 & (0xff<<SHIFT0)) dstdata[3] = (col4>>SHIFT0);
+ if (xod4 & (0xff<<SHIFT1)) dstdata[2] = (col4>>SHIFT1);
+ if (xod4 & (0xff<<SHIFT2)) dstdata[1] = (col4>>SHIFT2);
+ if (xod4 & (0xff<<SHIFT3)) dstdata[0] = (col4>>SHIFT3);
+ }
+ dstdata += 4;
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = srcdata[3];
+ srcdata--;
+ if (col != transpen) *dstdata = col;
+ dstdata++;
+ }
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+}
+
+
+INLINE void blockmove_NtoN_transpen_noremap16(
+ const UINT16 *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ UINT16 *dstdata,int dstmodulo,
+ int transpen)
+{
+ UINT16 *end;
+
+ srcmodulo -= srcwidth;
+ dstmodulo -= srcwidth;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) *dstdata = col;
+ dstdata++;
+ }
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+}
+
+INLINE void blockmove_NtoN_transpen_noremap_flipx16(
+ const UINT16 *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ UINT16 *dstdata,int dstmodulo,
+ int transpen)
+{
+ UINT16 *end;
+
+ srcmodulo += srcwidth;
+ dstmodulo -= srcwidth;
+ //srcdata += srcwidth-1;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata--);
+ if (col != transpen) *dstdata = col;
+ dstdata++;
+ }
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+}
+
+INLINE void blockmove_NtoN_transpen_noremap32(
+ const UINT32 *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ UINT32 *dstdata,int dstmodulo,
+ int transpen)
+{
+ UINT32 *end;
+
+ srcmodulo -= srcwidth;
+ dstmodulo -= srcwidth;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) *dstdata = col;
+ dstdata++;
+ }
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+}
+
+INLINE void blockmove_NtoN_transpen_noremap_flipx32(
+ const UINT32 *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ UINT32 *dstdata,int dstmodulo,
+ int transpen)
+{
+ UINT32 *end;
+
+ srcmodulo += srcwidth;
+ dstmodulo -= srcwidth;
+ //srcdata += srcwidth-1;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata--);
+ if (col != transpen) *dstdata = col;
+ dstdata++;
+ }
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+}
+
+
+
+static int afterdrawmask = 31;
+int pdrawgfx_shadow_lowpri = 0;
+
+
+/* 8-bit version */
+#define DATA_TYPE UINT8
+#define DEPTH 8
+
+#define DECLARE(function,args,body)
+#define DECLAREG(function,args,body)
+
+#define HMODULO 1
+#define VMODULO dstmodulo
+#define COMMON_ARGS \
+ const UINT8 *srcdata,int srcwidth,int srcheight,int srcmodulo, \
+ int leftskip,int topskip,int flipx,int flipy, \
+ DATA_TYPE *dstdata,int dstwidth,int dstheight,int dstmodulo
+
+#define COLOR_ARG unsigned int colorbase,UINT8 *pridata,UINT32 pmask
+#define INCREMENT_DST(n) {dstdata+=(n);pridata += (n);}
+#define LOOKUP(n) (colorbase + (n))
+#define SETPIXELCOLOR(dest,n) { if (((1 << (pridata[dest] & 0x1f)) & pmask) == 0) { if (pridata[dest] & 0x80) { dstdata[dest] = palette_shadow_table[n];} else { dstdata[dest] = (n);} } pridata[dest] = (pridata[dest] & 0x7f) | afterdrawmask; }
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##_raw_pri8 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef SETPIXELCOLOR
+
+#define COLOR_ARG const pen_t *paldata,UINT8 *pridata,UINT32 pmask
+#define LOOKUP(n) (paldata[n])
+#define SETPIXELCOLOR(dest,n) { if (((1 << (pridata[dest] & 0x1f)) & pmask) == 0) { if (pridata[dest] & 0x80) { dstdata[dest] = palette_shadow_table[n];} else { dstdata[dest] = (n);} } pridata[dest] = (pridata[dest] & 0x7f) | afterdrawmask; }
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##_pri8 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef INCREMENT_DST
+#undef SETPIXELCOLOR
+
+#define COLOR_ARG unsigned int colorbase
+#define INCREMENT_DST(n) {dstdata+=(n);}
+#define LOOKUP(n) (colorbase + (n))
+#define SETPIXELCOLOR(dest,n) {dstdata[dest] = (n);}
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##_raw8 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef SETPIXELCOLOR
+
+#define COLOR_ARG const pen_t *paldata
+#define LOOKUP(n) (paldata[n])
+#define SETPIXELCOLOR(dest,n) {dstdata[dest] = (n);}
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##8 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef INCREMENT_DST
+#undef SETPIXELCOLOR
+
+#undef HMODULO
+#undef VMODULO
+#undef COMMON_ARGS
+#undef DECLARE
+#undef DECLAREG
+
+#define DECLARE(function,args,body) void function##8 args body
+#define DECLAREG(function,args,body) void function##8 args body
+#define DECLARE_SWAP_RAW_PRI(function,args,body)
+#define BLOCKMOVE(function,flipx,args) \
+ if (flipx) blockmove_##function##_flipx##8 args ; \
+ else blockmove_##function##8 args
+#define BLOCKMOVELU(function,args) \
+ blockmove_##function##8 args
+#define BLOCKMOVERAW(function,args) \
+ blockmove_##function##_raw##8 args
+#define BLOCKMOVEPRI(function,args) \
+ blockmove_##function##_pri##8 args
+#define BLOCKMOVERAWPRI(function,args) \
+ blockmove_##function##_raw_pri##8 args
+#include "drawgfx.c"
+#undef DECLARE
+#undef DECLARE_SWAP_RAW_PRI
+#undef DECLAREG
+#undef BLOCKMOVE
+#undef BLOCKMOVELU
+#undef BLOCKMOVERAW
+#undef BLOCKMOVEPRI
+#undef BLOCKMOVERAWPRI
+
+#undef DEPTH
+#undef DATA_TYPE
+
+/* 16-bit version */
+#define DATA_TYPE UINT16
+#define DEPTH 16
+#define alpha_blend_r alpha_blend_r16
+#define alpha_blend alpha_blend16
+
+#define DECLARE(function,args,body)
+#define DECLAREG(function,args,body)
+
+#define HMODULO 1
+#define VMODULO dstmodulo
+#define COMMON_ARGS \
+ const UINT8 *srcdata,int srcwidth,int srcheight,int srcmodulo, \
+ int leftskip,int topskip,int flipx,int flipy, \
+ DATA_TYPE *dstdata,int dstwidth,int dstheight,int dstmodulo
+
+#define COLOR_ARG unsigned int colorbase,UINT8 *pridata,UINT32 pmask
+#define INCREMENT_DST(n) {dstdata+=(n);pridata += (n);}
+#define LOOKUP(n) (colorbase + (n))
+#define SETPIXELCOLOR(dest,n) { if (((1 << (pridata[dest] & 0x1f)) & pmask) == 0) { if (pridata[dest] & 0x80) { dstdata[dest] = palette_shadow_table[n];} else { dstdata[dest] = (n);} } pridata[dest] = (pridata[dest] & 0x7f) | afterdrawmask; }
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##_raw_pri16 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef SETPIXELCOLOR
+
+#define COLOR_ARG const pen_t *paldata,UINT8 *pridata,UINT32 pmask
+#define LOOKUP(n) (paldata[n])
+#define SETPIXELCOLOR(dest,n) { if (((1 << (pridata[dest] & 0x1f)) & pmask) == 0) { if (pridata[dest] & 0x80) { dstdata[dest] = palette_shadow_table[n];} else { dstdata[dest] = (n);} } pridata[dest] = (pridata[dest] & 0x7f) | afterdrawmask; }
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##_pri16 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef INCREMENT_DST
+#undef SETPIXELCOLOR
+
+#define COLOR_ARG unsigned int colorbase
+#define INCREMENT_DST(n) {dstdata+=(n);}
+#define LOOKUP(n) (colorbase + (n))
+#define SETPIXELCOLOR(dest,n) {dstdata[dest] = (n);}
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##_raw16 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef SETPIXELCOLOR
+
+#define COLOR_ARG const pen_t *paldata
+#define LOOKUP(n) (paldata[n])
+#define SETPIXELCOLOR(dest,n) {dstdata[dest] = (n);}
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##16 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef INCREMENT_DST
+#undef SETPIXELCOLOR
+
+#undef HMODULO
+#undef VMODULO
+#undef COMMON_ARGS
+#undef DECLARE
+#undef DECLAREG
+
+#define DECLARE(function,args,body) void function##16 args body
+#define DECLAREG(function,args,body) void function##16 args body
+#define DECLARE_SWAP_RAW_PRI(function,args,body)
+#define BLOCKMOVE(function,flipx,args) \
+ if (flipx) blockmove_##function##_flipx##16 args ; \
+ else blockmove_##function##16 args
+#define BLOCKMOVELU(function,args) \
+ blockmove_##function##16 args
+#define BLOCKMOVERAW(function,args) \
+ blockmove_##function##_raw##16 args
+#define BLOCKMOVEPRI(function,args) \
+ blockmove_##function##_pri##16 args
+#define BLOCKMOVERAWPRI(function,args) \
+ blockmove_##function##_raw_pri##16 args
+#include "drawgfx.c"
+#undef DECLARE
+#undef DECLARE_SWAP_RAW_PRI
+#undef DECLAREG
+#undef BLOCKMOVE
+#undef BLOCKMOVELU
+#undef BLOCKMOVERAW
+#undef BLOCKMOVEPRI
+#undef BLOCKMOVERAWPRI
+
+#undef DEPTH
+#undef DATA_TYPE
+#undef alpha_blend_r
+#undef alpha_blend
+
+/* 32-bit version */
+//* AAT032503: added limited 32-bit shadow and highlight support
+INLINE UINT32 SHADOW32(pen_t *shadow_table, UINT32 c) {
+ c = (c>>9&0x7c00) | (c>>6&0x03e0) | (c>>3&0x001f);
+ return(shadow_table[c]); }
+
+#define DATA_TYPE UINT32
+#define DEPTH 32
+#define alpha_blend_r alpha_blend_r32
+#define alpha_blend alpha_blend32
+
+#define DECLARE(function,args,body)
+#define DECLAREG(function,args,body)
+
+#define HMODULO 1
+#define VMODULO dstmodulo
+#define COMMON_ARGS \
+ const UINT8 *srcdata,int srcwidth,int srcheight,int srcmodulo, \
+ int leftskip,int topskip,int flipx,int flipy, \
+ DATA_TYPE *dstdata,int dstwidth,int dstheight,int dstmodulo
+
+#define COLOR_ARG unsigned int colorbase,UINT8 *pridata,UINT32 pmask
+#define INCREMENT_DST(n) {dstdata+=(n);pridata += (n);}
+#define LOOKUP(n) (colorbase + (n))
+#define SETPIXELCOLOR(dest,n) { UINT8 r8=pridata[dest]; if(!(1<<(r8&0x1f)&pmask)){ if(afterdrawmask){ r8&=0x7f; r8|=0x1f; dstdata[dest]=(n); pridata[dest]=r8; } else if(!(r8&0x80)){ dstdata[dest]=SHADOW32(palette_shadow_table,n); pridata[dest]|=0x80; } } }
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##_raw_pri32 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef SETPIXELCOLOR
+
+#define COLOR_ARG const pen_t *paldata,UINT8 *pridata,UINT32 pmask
+#define LOOKUP(n) (paldata[n])
+#define SETPIXELCOLOR(dest,n) { UINT8 r8=pridata[dest]; if(!(1<<(r8&0x1f)&pmask)){ if(afterdrawmask){ r8&=0x7f; r8|=0x1f; dstdata[dest]=(n); pridata[dest]=r8; } else if(!(r8&0x80)){ dstdata[dest]=SHADOW32(palette_shadow_table,n); pridata[dest]|=0x80; } } }
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##_pri32 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef INCREMENT_DST
+#undef SETPIXELCOLOR
+
+#define COLOR_ARG unsigned int colorbase
+#define INCREMENT_DST(n) {dstdata+=(n);}
+#define LOOKUP(n) (colorbase + (n))
+#define SETPIXELCOLOR(dest,n) {dstdata[dest] = (n);}
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##_raw32 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef SETPIXELCOLOR
+
+#define COLOR_ARG const pen_t *paldata
+#define LOOKUP(n) (paldata[n])
+#define SETPIXELCOLOR(dest,n) {dstdata[dest] = (n);}
+#define DECLARE_SWAP_RAW_PRI(function,args,body) void function##32 args body
+#include "drawgfx.c"
+#undef DECLARE_SWAP_RAW_PRI
+#undef COLOR_ARG
+#undef LOOKUP
+#undef INCREMENT_DST
+#undef SETPIXELCOLOR
+
+#undef HMODULO
+#undef VMODULO
+#undef COMMON_ARGS
+#undef DECLARE
+#undef DECLAREG
+
+#define DECLARE(function,args,body) void function##32 args body
+#define DECLAREG(function,args,body) void function##32 args body
+#define DECLARE_SWAP_RAW_PRI(function,args,body)
+#define BLOCKMOVE(function,flipx,args) \
+ if (flipx) blockmove_##function##_flipx##32 args ; \
+ else blockmove_##function##32 args
+#define BLOCKMOVELU(function,args) \
+ blockmove_##function##32 args
+#define BLOCKMOVERAW(function,args) \
+ blockmove_##function##_raw##32 args
+#define BLOCKMOVEPRI(function,args) \
+ blockmove_##function##_pri##32 args
+#define BLOCKMOVERAWPRI(function,args) \
+ blockmove_##function##_raw_pri##32 args
+#include "drawgfx.c"
+#undef DECLARE
+#undef DECLARE_SWAP_RAW_PRI
+#undef DECLAREG
+#undef BLOCKMOVE
+#undef BLOCKMOVELU
+#undef BLOCKMOVERAW
+#undef BLOCKMOVEPRI
+#undef BLOCKMOVERAWPRI
+
+#undef DEPTH
+#undef DATA_TYPE
+#undef alpha_blend_r
+#undef alpha_blend
+
+
+/***************************************************************************
+
+ Draw graphic elements in the specified bitmap.
+
+ transparency == TRANSPARENCY_NONE - no transparency.
+ transparency == TRANSPARENCY_PEN - bits whose _original_ value is == transparent_color
+ are transparent. This is the most common kind of
+ transparency.
+ transparency == TRANSPARENCY_PENS - as above, but transparent_color is a mask of
+ transparent pens.
+ transparency == TRANSPARENCY_COLOR - bits whose _remapped_ palette index (taken from
+ Machine->game_colortable) is == transparent_color
+
+ transparency == TRANSPARENCY_PEN_TABLE - the transparency condition is same as TRANSPARENCY_PEN
+ A special drawing is done according to gfx_drawmode_table[source pixel].
+ DRAWMODE_NONE transparent
+ DRAWMODE_SOURCE normal, draw source pixel.
+ DRAWMODE_SHADOW destination is changed through palette_shadow_table[]
+
+***************************************************************************/
+
+INLINE void common_drawgfx(mame_bitmap *dest,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,
+ mame_bitmap *pri_buffer,UINT32 pri_mask)
+{
+ assert_always(gfx, "drawgfx() gfx == 0");
+
+ code %= gfx->total_elements;
+ if (!is_raw[transparency])
+ color %= gfx->total_colors;
+
+ if ((dest->format == BITMAP_FORMAT_INDEXED8 || dest->format == BITMAP_FORMAT_INDEXED16 || dest->format == BITMAP_FORMAT_INDEXED32) &&
+ (transparency == TRANSPARENCY_ALPHA || transparency == TRANSPARENCY_ALPHARANGE))
+ {
+ transparency = TRANSPARENCY_PEN;
+ transparent_color &= 0xff;
+ }
+
+ 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;
+ }
+
+ if (dest->bpp == 8)
+ drawgfx_core8(dest,gfx,code,color,flipx,flipy,sx,sy,clip,transparency,transparent_color,pri_buffer,pri_mask);
+ else if (dest->bpp == 16)
+ drawgfx_core16(dest,gfx,code,color,flipx,flipy,sx,sy,clip,transparency,transparent_color,pri_buffer,pri_mask);
+ else if (dest->bpp == 32)
+ drawgfx_core32(dest,gfx,code,color,flipx,flipy,sx,sy,clip,transparency,transparent_color,pri_buffer,pri_mask);
+}
+
+void drawgfx(mame_bitmap *dest,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color)
+{
+ profiler_mark(PROFILER_DRAWGFX);
+ common_drawgfx(dest,gfx,code,color,flipx,flipy,sx,sy,clip,transparency,transparent_color,NULL,0);
+ profiler_mark(PROFILER_END);
+}
+
+void pdrawgfx(mame_bitmap *dest,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,UINT32 priority_mask)
+{
+ profiler_mark(PROFILER_DRAWGFX);
+ common_drawgfx(dest,gfx,code,color,flipx,flipy,sx,sy,clip,transparency,transparent_color,priority_bitmap,priority_mask | (1<<31));
+ profiler_mark(PROFILER_END);
+}
+
+void mdrawgfx(mame_bitmap *dest,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,UINT32 priority_mask)
+{
+ profiler_mark(PROFILER_DRAWGFX);
+ common_drawgfx(dest,gfx,code,color,flipx,flipy,sx,sy,clip,transparency,transparent_color,priority_bitmap,priority_mask);
+ profiler_mark(PROFILER_END);
+}
+
+
+/***************************************************************************
+
+ Use drawgfx() to copy a bitmap onto another at the given position.
+ This function will very likely change in the future.
+
+***************************************************************************/
+void copybitmap(mame_bitmap *dest,mame_bitmap *src,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color)
+{
+ /* translate to proper transparency here */
+ if (transparency == TRANSPARENCY_NONE)
+ transparency = TRANSPARENCY_NONE_RAW;
+ else if (transparency == TRANSPARENCY_PEN)
+ transparency = TRANSPARENCY_PEN_RAW;
+ else if (transparency == TRANSPARENCY_COLOR)
+ {
+ transparent_color = Machine->pens[transparent_color];
+ transparency = TRANSPARENCY_PEN_RAW;
+ }
+
+ copybitmap_remap(dest,src,flipx,flipy,sx,sy,clip,transparency,transparent_color);
+}
+
+
+void copybitmap_remap(mame_bitmap *dest,mame_bitmap *src,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color)
+{
+ profiler_mark(PROFILER_COPYBITMAP);
+
+ if (dest->bpp == 8)
+ copybitmap_core8(dest,src,flipx,flipy,sx,sy,clip,transparency,transparent_color);
+ else if (dest->bpp == 16)
+ copybitmap_core16(dest,src,flipx,flipy,sx,sy,clip,transparency,transparent_color);
+ else if (dest->bpp == 32)
+ copybitmap_core32(dest,src,flipx,flipy,sx,sy,clip,transparency,transparent_color);
+
+ profiler_mark(PROFILER_END);
+}
+
+
+
+/***************************************************************************
+
+ Copy a bitmap onto another with scroll and wraparound.
+ This function supports multiple independently scrolling rows/columns.
+ "rows" is the number of indepentently scrolling rows. "rowscroll" is an
+ array of integers telling how much to scroll each row. Same thing for
+ "cols" and "colscroll".
+ If the bitmap cannot scroll in one direction, set rows or columns to 0.
+ If the bitmap scrolls as a whole, set rows and/or cols to 1.
+ Bidirectional scrolling is, of course, supported only if the bitmap
+ scrolls as a whole in at least one direction.
+
+***************************************************************************/
+void copyscrollbitmap(mame_bitmap *dest,mame_bitmap *src,
+ int rows,const int *rowscroll,int cols,const int *colscroll,
+ const rectangle *clip,int transparency,int transparent_color)
+{
+ /* translate to proper transparency here */
+ if (transparency == TRANSPARENCY_NONE)
+ transparency = TRANSPARENCY_NONE_RAW;
+ else if (transparency == TRANSPARENCY_PEN)
+ transparency = TRANSPARENCY_PEN_RAW;
+ else if (transparency == TRANSPARENCY_COLOR)
+ {
+ transparent_color = Machine->pens[transparent_color];
+ transparency = TRANSPARENCY_PEN_RAW;
+ }
+
+ copyscrollbitmap_remap(dest,src,rows,rowscroll,cols,colscroll,clip,transparency,transparent_color);
+}
+
+void copyscrollbitmap_remap(mame_bitmap *dest,mame_bitmap *src,
+ int rows,const int *rowscroll,int cols,const int *colscroll,
+ const rectangle *clip,int transparency,int transparent_color)
+{
+ int srcwidth,srcheight,destwidth,destheight;
+ rectangle orig_clip;
+
+
+ if (clip)
+ {
+ orig_clip.min_x = clip->min_x;
+ orig_clip.max_x = clip->max_x;
+ orig_clip.min_y = clip->min_y;
+ orig_clip.max_y = clip->max_y;
+ }
+ else
+ {
+ orig_clip.min_x = 0;
+ orig_clip.max_x = dest->width-1;
+ orig_clip.min_y = 0;
+ orig_clip.max_y = dest->height-1;
+ }
+ clip = &orig_clip;
+
+ if (rows == 0 && cols == 0)
+ {
+ copybitmap(dest,src,0,0,0,0,clip,transparency,transparent_color);
+ return;
+ }
+
+ profiler_mark(PROFILER_COPYBITMAP);
+
+ srcwidth = src->width;
+ srcheight = src->height;
+ destwidth = dest->width;
+ destheight = dest->height;
+
+ if (rows == 0)
+ {
+ /* scrolling columns */
+ int col,colwidth;
+ rectangle myclip;
+
+
+ colwidth = srcwidth / cols;
+
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ col = 0;
+ while (col < cols)
+ {
+ int cons,scroll;
+
+
+ /* count consecutive columns scrolled by the same amount */
+ scroll = colscroll[col];
+ cons = 1;
+ while (col + cons < cols && colscroll[col + cons] == scroll)
+ cons++;
+
+ if (scroll < 0) scroll = srcheight - (-scroll) % srcheight;
+ else scroll %= srcheight;
+
+ myclip.min_x = col * colwidth;
+ if (myclip.min_x < clip->min_x) myclip.min_x = clip->min_x;
+ myclip.max_x = (col + cons) * colwidth - 1;
+ if (myclip.max_x > clip->max_x) myclip.max_x = clip->max_x;
+
+ copybitmap(dest,src,0,0,0,scroll,&myclip,transparency,transparent_color);
+ copybitmap(dest,src,0,0,0,scroll - srcheight,&myclip,transparency,transparent_color);
+
+ col += cons;
+ }
+ }
+ else if (cols == 0)
+ {
+ /* scrolling rows */
+ int row,rowheight;
+ rectangle myclip;
+
+
+ rowheight = srcheight / rows;
+
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+
+ row = 0;
+ while (row < rows)
+ {
+ int cons,scroll;
+
+
+ /* count consecutive rows scrolled by the same amount */
+ scroll = rowscroll[row];
+ cons = 1;
+ while (row + cons < rows && rowscroll[row + cons] == scroll)
+ cons++;
+
+ if (scroll < 0) scroll = srcwidth - (-scroll) % srcwidth;
+ else scroll %= srcwidth;
+
+ myclip.min_y = row * rowheight;
+ if (myclip.min_y < clip->min_y) myclip.min_y = clip->min_y;
+ myclip.max_y = (row + cons) * rowheight - 1;
+ if (myclip.max_y > clip->max_y) myclip.max_y = clip->max_y;
+
+ copybitmap(dest,src,0,0,scroll,0,&myclip,transparency,transparent_color);
+ copybitmap(dest,src,0,0,scroll - srcwidth,0,&myclip,transparency,transparent_color);
+
+ row += cons;
+ }
+ }
+ else if (rows == 1 && cols == 1)
+ {
+ /* XY scrolling playfield */
+ int scrollx,scrolly,sx,sy;
+
+
+ if (rowscroll[0] < 0) scrollx = srcwidth - (-rowscroll[0]) % srcwidth;
+ else scrollx = rowscroll[0] % srcwidth;
+
+ if (colscroll[0] < 0) scrolly = srcheight - (-colscroll[0]) % srcheight;
+ else scrolly = colscroll[0] % srcheight;
+
+ for (sx = scrollx - srcwidth;sx < destwidth;sx += srcwidth)
+ for (sy = scrolly - srcheight;sy < destheight;sy += srcheight)
+ copybitmap(dest,src,0,0,sx,sy,clip,transparency,transparent_color);
+ }
+ else if (rows == 1)
+ {
+ /* scrolling columns + horizontal scroll */
+ int col,colwidth;
+ int scrollx;
+ rectangle myclip;
+
+
+ if (rowscroll[0] < 0) scrollx = srcwidth - (-rowscroll[0]) % srcwidth;
+ else scrollx = rowscroll[0] % srcwidth;
+
+ colwidth = srcwidth / cols;
+
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ col = 0;
+ while (col < cols)
+ {
+ int cons,scroll;
+
+
+ /* count consecutive columns scrolled by the same amount */
+ scroll = colscroll[col];
+ cons = 1;
+ while (col + cons < cols && colscroll[col + cons] == scroll)
+ cons++;
+
+ if (scroll < 0) scroll = srcheight - (-scroll) % srcheight;
+ else scroll %= srcheight;
+
+ myclip.min_x = col * colwidth + scrollx;
+ if (myclip.min_x < clip->min_x) myclip.min_x = clip->min_x;
+ myclip.max_x = (col + cons) * colwidth - 1 + scrollx;
+ if (myclip.max_x > clip->max_x) myclip.max_x = clip->max_x;
+
+ copybitmap(dest,src,0,0,scrollx,scroll,&myclip,transparency,transparent_color);
+ copybitmap(dest,src,0,0,scrollx,scroll - srcheight,&myclip,transparency,transparent_color);
+
+ myclip.min_x = col * colwidth + scrollx - srcwidth;
+ if (myclip.min_x < clip->min_x) myclip.min_x = clip->min_x;
+ myclip.max_x = (col + cons) * colwidth - 1 + scrollx - srcwidth;
+ if (myclip.max_x > clip->max_x) myclip.max_x = clip->max_x;
+
+ copybitmap(dest,src,0,0,scrollx - srcwidth,scroll,&myclip,transparency,transparent_color);
+ copybitmap(dest,src,0,0,scrollx - srcwidth,scroll - srcheight,&myclip,transparency,transparent_color);
+
+ col += cons;
+ }
+ }
+ else if (cols == 1)
+ {
+ /* scrolling rows + vertical scroll */
+ int row,rowheight;
+ int scrolly;
+ rectangle myclip;
+
+
+ if (colscroll[0] < 0) scrolly = srcheight - (-colscroll[0]) % srcheight;
+ else scrolly = colscroll[0] % srcheight;
+
+ rowheight = srcheight / rows;
+
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+
+ row = 0;
+ while (row < rows)
+ {
+ int cons,scroll;
+
+
+ /* count consecutive rows scrolled by the same amount */
+ scroll = rowscroll[row];
+ cons = 1;
+ while (row + cons < rows && rowscroll[row + cons] == scroll)
+ cons++;
+
+ if (scroll < 0) scroll = srcwidth - (-scroll) % srcwidth;
+ else scroll %= srcwidth;
+
+ myclip.min_y = row * rowheight + scrolly;
+ if (myclip.min_y < clip->min_y) myclip.min_y = clip->min_y;
+ myclip.max_y = (row + cons) * rowheight - 1 + scrolly;
+ if (myclip.max_y > clip->max_y) myclip.max_y = clip->max_y;
+
+ copybitmap(dest,src,0,0,scroll,scrolly,&myclip,transparency,transparent_color);
+ copybitmap(dest,src,0,0,scroll - srcwidth,scrolly,&myclip,transparency,transparent_color);
+
+ myclip.min_y = row * rowheight + scrolly - srcheight;
+ if (myclip.min_y < clip->min_y) myclip.min_y = clip->min_y;
+ myclip.max_y = (row + cons) * rowheight - 1 + scrolly - srcheight;
+ if (myclip.max_y > clip->max_y) myclip.max_y = clip->max_y;
+
+ copybitmap(dest,src,0,0,scroll,scrolly - srcheight,&myclip,transparency,transparent_color);
+ copybitmap(dest,src,0,0,scroll - srcwidth,scrolly - srcheight,&myclip,transparency,transparent_color);
+
+ row += cons;
+ }
+ }
+
+ profiler_mark(PROFILER_END);
+}
+
+
+/* notes:
+ - startx and starty MUST be UINT32 for calculations to work correctly
+ - srcbitmap->width and height are assumed to be a power of 2 to speed up wraparound
+ */
+void copyrozbitmap(mame_bitmap *dest,mame_bitmap *src,
+ UINT32 startx,UINT32 starty,int incxx,int incxy,int incyx,int incyy,int wraparound,
+ const rectangle *clip,int transparency,int transparent_color,UINT32 priority)
+{
+ profiler_mark(PROFILER_COPYBITMAP);
+
+ /* cheat, the core doesn't support TRANSPARENCY_NONE yet */
+ if (transparency == TRANSPARENCY_NONE)
+ {
+ transparency = TRANSPARENCY_PEN;
+ transparent_color = -1;
+ }
+
+ /* if necessary, remap the transparent color */
+ if (transparency == TRANSPARENCY_COLOR)
+ {
+ transparency = TRANSPARENCY_PEN;
+ transparent_color = Machine->pens[transparent_color];
+ }
+
+ if (transparency != TRANSPARENCY_PEN)
+ {
+ popmessage("copyrozbitmap unsupported trans %02x",transparency);
+ return;
+ }
+
+ if (dest->bpp == 8)
+ copyrozbitmap_core8(dest,src,startx,starty,incxx,incxy,incyx,incyy,wraparound,clip,transparency,transparent_color,priority);
+ else if (dest->bpp == 16)
+ copyrozbitmap_core16(dest,src,startx,starty,incxx,incxy,incyx,incyy,wraparound,clip,transparency,transparent_color,priority);
+ else if (dest->bpp == 32)
+ copyrozbitmap_core32(dest,src,startx,starty,incxx,incxy,incyx,incyy,wraparound,clip,transparency,transparent_color,priority);
+
+ profiler_mark(PROFILER_END);
+}
+
+
+
+INLINE void common_drawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ unsigned int code,unsigned int 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)
+{
+ rectangle myclip;
+
+ UINT8 ah, al;
+
+ al = (pdrawgfx_shadow_lowpri) ? 0 : 0x80;
+
+ if (!scalex || !scaley) return;
+
+ if (scalex == 0x10000 && scaley == 0x10000)
+ {
+ common_drawgfx(dest_bmp,gfx,code,color,flipx,flipy,sx,sy,clip,transparency,transparent_color,pri_buffer,pri_mask);
+ return;
+ }
+
+ if (transparency != TRANSPARENCY_PEN && transparency != TRANSPARENCY_PEN_RAW
+ && transparency != TRANSPARENCY_PENS && transparency != TRANSPARENCY_COLOR
+ && transparency != TRANSPARENCY_PEN_TABLE && transparency != TRANSPARENCY_PEN_TABLE_RAW
+ && transparency != TRANSPARENCY_BLEND_RAW
+ && transparency != TRANSPARENCY_ALPHA && transparency != TRANSPARENCY_ALPHARANGE
+ && transparency != TRANSPARENCY_NONE)
+ {
+ popmessage("drawgfxzoom unsupported trans %02x",transparency);
+ return;
+ }
+
+ if ((dest_bmp->format == BITMAP_FORMAT_INDEXED8 || dest_bmp->format == BITMAP_FORMAT_INDEXED16 || dest_bmp->format == BITMAP_FORMAT_INDEXED32) &&
+ (transparency == TRANSPARENCY_ALPHA || transparency == TRANSPARENCY_ALPHARANGE))
+ {
+ transparency = TRANSPARENCY_PEN;
+ transparent_color &= 0xff;
+ }
+
+ if (transparency == TRANSPARENCY_COLOR)
+ transparent_color = Machine->pens[transparent_color];
+
+
+ /*
+ 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;
+ }
+
+
+ /* ASG 980209 -- added 16-bit version */
+ if (dest_bmp->bpp == 8)
+ {
+ 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 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 (pri_buffer)
+ {
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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++ )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = pal[(source[x_index>>17] >> ((x_index & 0x10000) >> 14)) & 0x0f];
+ pri[x] = 31;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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++ )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = pal[source[x_index>>16]];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+ else
+ {
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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;
+ UINT8 *dest = BITMAP_ADDR8(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 (pri_buffer)
+ {
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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>>17] >> ((x_index & 0x10000) >> 14)) & 0x0f;
+ 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 = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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
+ {
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *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>>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;
+ UINT8 *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 != transparent_color ) dest[x] = pal[c];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+ }
+
+ /* case 1b: TRANSPARENCY_PEN_RAW */
+ if (transparency == TRANSPARENCY_PEN_RAW)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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] = color + c;
+ pri[x] = 31;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *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 != transparent_color ) dest[x] = color + c;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 1c: TRANSPARENCY_BLEND_RAW */
+ if (transparency == TRANSPARENCY_BLEND_RAW)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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] |= (color + c);
+ pri[x] = 31;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *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 != transparent_color ) dest[x] |= (color + c);
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 2: TRANSPARENCY_PENS */
+ if (transparency == TRANSPARENCY_PENS)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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 (((1 << c) & transparent_color) == 0)
+ {
+ 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 = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *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 (((1 << c) & transparent_color) == 0)
+ dest[x] = pal[c];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 3: TRANSPARENCY_COLOR */
+ else if (transparency == TRANSPARENCY_COLOR)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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 = pal[source[x_index>>16]];
+ if( c != transparent_color )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = c;
+ pri[x] = 31;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = pal[source[x_index>>16]];
+ if( c != transparent_color ) dest[x] = c;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 4: TRANSPARENCY_PEN_TABLE */
+ if (transparency == TRANSPARENCY_PEN_TABLE)
+ {
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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 )
+ {
+ switch(gfx_drawmode_table[c])
+ {
+ case DRAWMODE_SOURCE:
+ if (((1 << (pri[x] & 0x1f)) & pri_mask) == 0)
+ {
+ if (pri[x] & 0x80)
+ dest[x] = palette_shadow_table[pal[c]];
+ else
+ dest[x] = pal[c];
+ }
+ pri[x] = (pri[x] & 0x7f) | 31;
+ break;
+ case DRAWMODE_SHADOW:
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = palette_shadow_table[dest[x]];
+ pri[x] |= al;
+ break;
+ }
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *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 != transparent_color )
+ {
+ switch(gfx_drawmode_table[c])
+ {
+ case DRAWMODE_SOURCE:
+ dest[x] = pal[c];
+ break;
+ case DRAWMODE_SHADOW:
+ dest[x] = palette_shadow_table[dest[x]];
+ break;
+ }
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 4b: TRANSPARENCY_PEN_TABLE_RAW */
+ if (transparency == TRANSPARENCY_PEN_TABLE_RAW)
+ {
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(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 )
+ {
+ switch(gfx_drawmode_table[c])
+ {
+ case DRAWMODE_SOURCE:
+ if (((1 << (pri[x] & 0x1f)) & pri_mask) == 0)
+ {
+ if (pri[x] & 0x80)
+ dest[x] = palette_shadow_table[color + c];
+ else
+ dest[x] = color + c;
+ }
+ pri[x] = (pri[x] & 0x7f) | 31;
+ break;
+ case DRAWMODE_SHADOW:
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = palette_shadow_table[dest[x]];
+ pri[x] |= al;
+ break;
+ }
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT8 *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 != transparent_color )
+ {
+ switch(gfx_drawmode_table[c])
+ {
+ case DRAWMODE_SOURCE:
+ dest[x] = color + c;
+ break;
+ case DRAWMODE_SHADOW:
+ dest[x] = palette_shadow_table[dest[x]];
+ break;
+ }
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* ASG 980209 -- new 16-bit part */
+ else if (dest_bmp->bpp == 16)
+ {
+ 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 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 (pri_buffer)
+ {
+ 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);
+ UINT8 *pri = BITMAP_ADDR8(pri_buffer, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = pal[(source[x_index>>17] >> ((x_index & 0x10000) >> 14)) & 0x0f];
+ pri[x] = 31;
+ 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);
+ UINT8 *pri = BITMAP_ADDR8(pri_buffer, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = pal[source[x_index>>16]];
+ pri[x] = 31;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+ else
+ {
+ 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 (pri_buffer)
+ {
+ 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);
+ 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>>17] >> ((x_index & 0x10000) >> 14)) & 0x0f;
+ 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 = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(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
+ {
+ 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 1b: TRANSPARENCY_PEN_RAW */
+ if (transparency == TRANSPARENCY_PEN_RAW)
+ {
+ if (pri_buffer)
+ {
+ 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(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] = color + c;
+ pri[x] = 31;
+ }
+ 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] = color + c;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 1c: TRANSPARENCY_BLEND_RAW */
+ if (transparency == TRANSPARENCY_BLEND_RAW)
+ {
+ if (pri_buffer)
+ {
+ 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(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] |= color + c;
+ pri[x] = 31;
+ }
+ 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] |= color + c;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 2: TRANSPARENCY_PENS */
+ if (transparency == TRANSPARENCY_PENS)
+ {
+ if (pri_buffer)
+ {
+ 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(pri_buffer, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if (((1 << c) & transparent_color) == 0)
+ {
+ 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 = 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 (((1 << c) & transparent_color) == 0)
+ dest[x] = pal[c];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 3: TRANSPARENCY_COLOR */
+ else if (transparency == TRANSPARENCY_COLOR)
+ {
+ if (pri_buffer)
+ {
+ 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(pri_buffer, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = pal[source[x_index>>16]];
+ if( c != transparent_color )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = c;
+ pri[x] = 31;
+ }
+ 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 = pal[source[x_index>>16]];
+ if( c != transparent_color ) dest[x] = c;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 4: TRANSPARENCY_PEN_TABLE */
+ if (transparency == TRANSPARENCY_PEN_TABLE)
+ {
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ if (pri_buffer)
+ {
+ 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(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 )
+ {
+ switch(gfx_drawmode_table[c])
+ {
+ case DRAWMODE_SOURCE:
+ ah = pri[x];
+ if (((1 << (ah & 0x1f)) & pri_mask) == 0)
+ {
+ if (ah & 0x80)
+ dest[x] = palette_shadow_table[pal[c]];
+ else
+ dest[x] = pal[c];
+ }
+ pri[x] = (ah & 0x7f) | 31;
+ break;
+ case DRAWMODE_SHADOW:
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = palette_shadow_table[dest[x]];
+ pri[x] |= al;
+ break;
+ }
+ }
+ 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 )
+ {
+ switch(gfx_drawmode_table[c])
+ {
+ case DRAWMODE_SOURCE:
+ dest[x] = pal[c];
+ break;
+ case DRAWMODE_SHADOW:
+ dest[x] = palette_shadow_table[dest[x]];
+ break;
+ }
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 4b: TRANSPARENCY_PEN_TABLE_RAW */
+ if (transparency == TRANSPARENCY_PEN_TABLE_RAW)
+ {
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ if (pri_buffer)
+ {
+ 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(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 )
+ {
+ switch(gfx_drawmode_table[c])
+ {
+ case DRAWMODE_SOURCE:
+ ah = pri[x];
+ if (((1 << (ah & 0x1f)) & pri_mask) == 0)
+ {
+ if (ah & 0x80)
+ dest[x] = palette_shadow_table[color + c];
+ else
+ dest[x] = color + c;
+ }
+ pri[x] = (ah & 0x7f) | 31;
+ break;
+ case DRAWMODE_SHADOW:
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = palette_shadow_table[dest[x]];
+ pri[x] |= al;
+ break;
+ }
+ }
+ 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 )
+ {
+ switch(gfx_drawmode_table[c])
+ {
+ case DRAWMODE_SOURCE:
+ dest[x] = color + c;
+ break;
+ case DRAWMODE_SHADOW:
+ dest[x] = palette_shadow_table[dest[x]];
+ break;
+ }
+ }
+ 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 = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(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_blend16(dest[x], pal[c]);
+ pri[x] = 31;
+ }
+ 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] = alpha_blend16(dest[x], pal[c]);
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* pjp 31/5/02 */
+ /* case 7: TRANSPARENCY_ALPHARANGE */
+ if (transparency == TRANSPARENCY_ALPHARANGE)
+ {
+ if (pri_buffer)
+ {
+ 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(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)
+ {
+ if( gfx_alpharange_table[c] == 0xff )
+ dest[x] = pal[c];
+ else
+ dest[x] = alpha_blend_r16(dest[x], pal[c], gfx_alpharange_table[c]);
+ }
+ pri[x] = 31;
+ }
+ 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 )
+ {
+ if( gfx_alpharange_table[c] == 0xff )
+ dest[x] = pal[c];
+ else
+ dest[x] = alpha_blend_r16(dest[x], pal[c], gfx_alpharange_table[c]);
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ 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 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 (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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++ )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = pal[source[x_index>>16]];
+ pri[x] = 31;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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++ )
+ {
+ dest[x] = pal[source[x_index>>16]];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 1: TRANSPARENCY_PEN */
+ if (transparency == TRANSPARENCY_PEN)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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 = 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 1b: TRANSPARENCY_PEN_RAW */
+ if (transparency == TRANSPARENCY_PEN_RAW)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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] = color + c;
+ pri[x] = 31;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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] = color + c;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 1c: TRANSPARENCY_BLEND_RAW */
+ if (transparency == TRANSPARENCY_BLEND_RAW)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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] |= color + c;
+ pri[x] = 31;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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] |= color + c;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 2: TRANSPARENCY_PENS */
+ if (transparency == TRANSPARENCY_PENS)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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 (((1 << c) & transparent_color) == 0)
+ {
+ 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 = 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 (((1 << c) & transparent_color) == 0)
+ dest[x] = pal[c];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 3: TRANSPARENCY_COLOR */
+ else if (transparency == TRANSPARENCY_COLOR)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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 = pal[source[x_index>>16]];
+ if( c != transparent_color )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = c;
+ pri[x] = 31;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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 = pal[source[x_index>>16]];
+ if( c != transparent_color ) dest[x] = c;
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 4: TRANSPARENCY_PEN_TABLE */
+ if (transparency == TRANSPARENCY_PEN_TABLE)
+ {
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ UINT8 *source, *pri;
+ UINT32 *dest;
+ int c, x, x_index;
+
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ source = source_base + (y_index>>16) * gfx->line_modulo;
+ y_index += dy;
+ dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ pri = BITMAP_ADDR8(pri_buffer, y, 0);
+ x_index = x_index_base;
+
+ for( x=sx; x<ex; x++ )
+ {
+ int ebx = x_index;
+ x_index += dx;
+ ebx >>= 16;
+ al = pri[x];
+ c = source[ebx];
+ ah = al;
+ al &= 0x1f;
+
+ if (gfx_drawmode_table[c] == DRAWMODE_NONE) continue;
+
+ if (!(1<<al & pri_mask))
+ {
+ if (gfx_drawmode_table[c] == DRAWMODE_SOURCE)
+ {
+ ah &= 0x7f;
+ ebx = pal[c];
+ ah |= 0x1f;
+ dest[x] = ebx;
+ pri[x] = ah;
+ }
+ else if (!(ah & 0x80))
+ {
+ ebx = SHADOW32(palette_shadow_table,dest[x]);
+ pri[x] |= 0x80;
+ dest[x] = ebx;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ source = source_base + (y_index>>16) * gfx->line_modulo;
+ y_index += dy;
+ dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ x_index = x_index_base;
+
+ for( x=sx; x<ex; x++ )
+ {
+ c = source[x_index>>16];
+ x_index += dx;
+
+ if (gfx_drawmode_table[c] == DRAWMODE_NONE) continue;
+ if (gfx_drawmode_table[c] == DRAWMODE_SOURCE)
+ dest[x] = pal[c];
+ else
+ dest[x] = SHADOW32(palette_shadow_table,dest[x]);
+ }
+ }
+ }
+ }
+
+ /* case 4b: TRANSPARENCY_PEN_TABLE_RAW */
+ if (transparency == TRANSPARENCY_PEN_TABLE_RAW)
+ {
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ UINT8 *source, *pri;
+ UINT32 *dest;
+ int c, x, x_index;
+
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ source = source_base + (y_index>>16) * gfx->line_modulo;
+ y_index += dy;
+ dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ pri = BITMAP_ADDR8(pri_buffer, y, 0);
+ x_index = x_index_base;
+
+ for( x=sx; x<ex; x++ )
+ {
+ int ebx = x_index;
+ x_index += dx;
+ ebx >>= 16;
+ al = pri[x];
+ c = source[ebx];
+ ah = al;
+ al &= 0x1f;
+
+ if (gfx_drawmode_table[c] == DRAWMODE_NONE) continue;
+
+ if (!(1<<al & pri_mask))
+ {
+ if (gfx_drawmode_table[c] == DRAWMODE_SOURCE)
+ {
+ ah &= 0x7f;
+ ebx = color + c;
+ ah |= 0x1f;
+ dest[x] = ebx;
+ pri[x] = ah;
+ }
+ else if (!(ah & 0x80))
+ {
+ ebx = SHADOW32(palette_shadow_table,dest[x]);
+ pri[x] |= 0x80;
+ dest[x] = ebx;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ source = source_base + (y_index>>16) * gfx->line_modulo;
+ y_index += dy;
+ dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ x_index = x_index_base;
+
+ for( x=sx; x<ex; x++ )
+ {
+ c = source[x_index>>16];
+ x_index += dx;
+
+ if (gfx_drawmode_table[c] == DRAWMODE_NONE) continue;
+ if (gfx_drawmode_table[c] == DRAWMODE_SOURCE)
+ dest[x] = color + c;
+ else
+ dest[x] = SHADOW32(palette_shadow_table,dest[x]);
+ }
+ }
+ }
+ }
+
+
+ /* case 6: TRANSPARENCY_ALPHA */
+ if (transparency == TRANSPARENCY_ALPHA)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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 = 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;
+ }
+ }
+ }
+
+ /* pjp 31/5/02 */
+ /* case 7: TRANSPARENCY_ALPHARANGE */
+ if (transparency == TRANSPARENCY_ALPHARANGE)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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)
+ {
+ 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] = 31;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = 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 )
+ {
+ 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;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void drawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,int scalex, int scaley)
+{
+ profiler_mark(PROFILER_DRAWGFX);
+ common_drawgfxzoom(dest_bmp,gfx,code,color,flipx,flipy,sx,sy,
+ clip,transparency,transparent_color,scalex,scaley,NULL,0);
+ profiler_mark(PROFILER_END);
+}
+
+void pdrawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,int scalex, int scaley,
+ UINT32 priority_mask)
+{
+ profiler_mark(PROFILER_DRAWGFX);
+ common_drawgfxzoom(dest_bmp,gfx,code,color,flipx,flipy,sx,sy,
+ clip,transparency,transparent_color,scalex,scaley,priority_bitmap,priority_mask | (1<<31));
+ profiler_mark(PROFILER_END);
+}
+
+void mdrawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,int scalex, int scaley,
+ UINT32 priority_mask)
+{
+ profiler_mark(PROFILER_DRAWGFX);
+ common_drawgfxzoom(dest_bmp,gfx,code,color,flipx,flipy,sx,sy,
+ clip,transparency,transparent_color,scalex,scaley,priority_bitmap,priority_mask);
+ profiler_mark(PROFILER_END);
+}
+
+
+#else /* DECLARE */
+
+/* -------------------- included inline section --------------------- */
+
+/* this is #included to generate 8-bit and 16-bit versions */
+
+#define ADJUST_8 \
+ int ydir; \
+ if (flipy) \
+ { \
+ INCREMENT_DST(VMODULO * (dstheight-1)) \
+ srcdata += (srcheight - dstheight - topskip) * srcmodulo; \
+ ydir = -1; \
+ } \
+ else \
+ { \
+ srcdata += topskip * srcmodulo; \
+ ydir = 1; \
+ } \
+ if (flipx) \
+ { \
+ INCREMENT_DST(HMODULO * (dstwidth-1)) \
+ srcdata += (srcwidth - dstwidth - leftskip); \
+ } \
+ else \
+ srcdata += leftskip; \
+ srcmodulo -= dstwidth;
+
+
+#define ADJUST_4 \
+ int ydir; \
+ if (flipy) \
+ { \
+ INCREMENT_DST(VMODULO * (dstheight-1)) \
+ srcdata += (srcheight - dstheight - topskip) * srcmodulo; \
+ ydir = -1; \
+ } \
+ else \
+ { \
+ srcdata += topskip * srcmodulo; \
+ ydir = 1; \
+ } \
+ if (flipx) \
+ { \
+ INCREMENT_DST(HMODULO * (dstwidth-1)) \
+ srcdata += (srcwidth - dstwidth - leftskip)/2; \
+ leftskip = (srcwidth - dstwidth - leftskip) & 1; \
+ } \
+ else \
+ { \
+ srcdata += leftskip/2; \
+ leftskip &= 1; \
+ } \
+ srcmodulo -= (dstwidth+leftskip)/2;
+
+
+
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_opaque,(COMMON_ARGS,
+ COLOR_ARG),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (dstdata >= end + 8*HMODULO)
+ {
+ INCREMENT_DST(-8*HMODULO)
+ SETPIXELCOLOR(8*HMODULO,LOOKUP(srcdata[0]))
+ SETPIXELCOLOR(7*HMODULO,LOOKUP(srcdata[1]))
+ SETPIXELCOLOR(6*HMODULO,LOOKUP(srcdata[2]))
+ SETPIXELCOLOR(5*HMODULO,LOOKUP(srcdata[3]))
+ SETPIXELCOLOR(4*HMODULO,LOOKUP(srcdata[4]))
+ SETPIXELCOLOR(3*HMODULO,LOOKUP(srcdata[5]))
+ SETPIXELCOLOR(2*HMODULO,LOOKUP(srcdata[6]))
+ SETPIXELCOLOR(1*HMODULO,LOOKUP(srcdata[7]))
+ srcdata += 8;
+ }
+ while (dstdata > end)
+ {
+ SETPIXELCOLOR(0,LOOKUP(*srcdata))
+ srcdata++;
+ INCREMENT_DST(-HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (dstdata <= end - 8*HMODULO)
+ {
+ SETPIXELCOLOR(0*HMODULO,LOOKUP(srcdata[0]))
+ SETPIXELCOLOR(1*HMODULO,LOOKUP(srcdata[1]))
+ SETPIXELCOLOR(2*HMODULO,LOOKUP(srcdata[2]))
+ SETPIXELCOLOR(3*HMODULO,LOOKUP(srcdata[3]))
+ SETPIXELCOLOR(4*HMODULO,LOOKUP(srcdata[4]))
+ SETPIXELCOLOR(5*HMODULO,LOOKUP(srcdata[5]))
+ SETPIXELCOLOR(6*HMODULO,LOOKUP(srcdata[6]))
+ SETPIXELCOLOR(7*HMODULO,LOOKUP(srcdata[7]))
+ srcdata += 8;
+ INCREMENT_DST(8*HMODULO)
+ }
+ while (dstdata < end)
+ {
+ SETPIXELCOLOR(0,LOOKUP(*srcdata))
+ srcdata++;
+ INCREMENT_DST(HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+})
+
+DECLARE_SWAP_RAW_PRI(blockmove_4toN_opaque,(COMMON_ARGS,
+ COLOR_ARG),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_4
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ if (leftskip)
+ {
+ SETPIXELCOLOR(0,LOOKUP(*srcdata>>4))
+ srcdata++;
+ INCREMENT_DST(-HMODULO)
+ }
+ while (dstdata >= end + 8*HMODULO)
+ {
+ INCREMENT_DST(-8*HMODULO)
+ SETPIXELCOLOR(8*HMODULO,LOOKUP(srcdata[0]&0x0f))
+ SETPIXELCOLOR(7*HMODULO,LOOKUP(srcdata[0]>>4))
+ SETPIXELCOLOR(6*HMODULO,LOOKUP(srcdata[1]&0x0f))
+ SETPIXELCOLOR(5*HMODULO,LOOKUP(srcdata[1]>>4))
+ SETPIXELCOLOR(4*HMODULO,LOOKUP(srcdata[2]&0x0f))
+ SETPIXELCOLOR(3*HMODULO,LOOKUP(srcdata[2]>>4))
+ SETPIXELCOLOR(2*HMODULO,LOOKUP(srcdata[3]&0x0f))
+ SETPIXELCOLOR(1*HMODULO,LOOKUP(srcdata[3]>>4))
+ srcdata += 4;
+ }
+ while (dstdata > end)
+ {
+ SETPIXELCOLOR(0,LOOKUP(*srcdata&0x0f))
+ INCREMENT_DST(-HMODULO)
+ if (dstdata > end)
+ {
+ SETPIXELCOLOR(0,LOOKUP(*srcdata>>4))
+ srcdata++;
+ INCREMENT_DST(-HMODULO)
+ }
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ if (leftskip)
+ {
+ SETPIXELCOLOR(0,LOOKUP(*srcdata>>4))
+ srcdata++;
+ INCREMENT_DST(HMODULO)
+ }
+ while (dstdata <= end - 8*HMODULO)
+ {
+ SETPIXELCOLOR(0*HMODULO,LOOKUP(srcdata[0]&0x0f))
+ SETPIXELCOLOR(1*HMODULO,LOOKUP(srcdata[0]>>4))
+ SETPIXELCOLOR(2*HMODULO,LOOKUP(srcdata[1]&0x0f))
+ SETPIXELCOLOR(3*HMODULO,LOOKUP(srcdata[1]>>4))
+ SETPIXELCOLOR(4*HMODULO,LOOKUP(srcdata[2]&0x0f))
+ SETPIXELCOLOR(5*HMODULO,LOOKUP(srcdata[2]>>4))
+ SETPIXELCOLOR(6*HMODULO,LOOKUP(srcdata[3]&0x0f))
+ SETPIXELCOLOR(7*HMODULO,LOOKUP(srcdata[3]>>4))
+ srcdata += 4;
+ INCREMENT_DST(8*HMODULO)
+ }
+ while (dstdata < end)
+ {
+ SETPIXELCOLOR(0,LOOKUP(*srcdata&0x0f))
+ INCREMENT_DST(HMODULO)
+ if (dstdata < end)
+ {
+ SETPIXELCOLOR(0,LOOKUP(*srcdata>>4))
+ srcdata++;
+ INCREMENT_DST(HMODULO)
+ }
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+})
+
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_transpen,(COMMON_ARGS,
+ COLOR_ARG,int transpen),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+ int trans4;
+ UINT32 *sd4;
+
+ trans4 = transpen * 0x01010101;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata > end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata >= end + 4*HMODULO)
+ {
+ UINT32 col4;
+
+ INCREMENT_DST(-4*HMODULO)
+ if ((col4 = *(sd4++)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if (xod4 & (0xff<<SHIFT0)) SETPIXELCOLOR(4*HMODULO,LOOKUP((col4>>SHIFT0) & 0xff))
+ if (xod4 & (0xff<<SHIFT1)) SETPIXELCOLOR(3*HMODULO,LOOKUP((col4>>SHIFT1) & 0xff))
+ if (xod4 & (0xff<<SHIFT2)) SETPIXELCOLOR(2*HMODULO,LOOKUP((col4>>SHIFT2) & 0xff))
+ if (xod4 & (0xff<<SHIFT3)) SETPIXELCOLOR(1*HMODULO,LOOKUP((col4>>SHIFT3) & 0xff))
+ }
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata > end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+ int trans4;
+ UINT32 *sd4;
+
+ trans4 = transpen * 0x01010101;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata < end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata <= end - 4*HMODULO)
+ {
+ UINT32 col4;
+
+ if ((col4 = *(sd4++)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if (xod4 & (0xff<<SHIFT0)) SETPIXELCOLOR(0*HMODULO,LOOKUP((col4>>SHIFT0) & 0xff))
+ if (xod4 & (0xff<<SHIFT1)) SETPIXELCOLOR(1*HMODULO,LOOKUP((col4>>SHIFT1) & 0xff))
+ if (xod4 & (0xff<<SHIFT2)) SETPIXELCOLOR(2*HMODULO,LOOKUP((col4>>SHIFT2) & 0xff))
+ if (xod4 & (0xff<<SHIFT3)) SETPIXELCOLOR(3*HMODULO,LOOKUP((col4>>SHIFT3) & 0xff))
+ }
+ INCREMENT_DST(4*HMODULO)
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+})
+
+DECLARE_SWAP_RAW_PRI(blockmove_4toN_transpen,(COMMON_ARGS,
+ COLOR_ARG,int transpen),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_4
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ int col;
+
+ end = dstdata - dstwidth*HMODULO;
+ if (leftskip)
+ {
+ col = *(srcdata++)>>4;
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ }
+ while (dstdata > end)
+ {
+ col = *(srcdata)&0x0f;
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ if (dstdata > end)
+ {
+ col = *(srcdata++)>>4;
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ }
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ int col;
+
+ end = dstdata + dstwidth*HMODULO;
+ if (leftskip)
+ {
+ col = *(srcdata++)>>4;
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ }
+ while (dstdata < end)
+ {
+ col = *(srcdata)&0x0f;
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ if (dstdata < end)
+ {
+ col = *(srcdata++)>>4;
+ if (col != transpen) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ }
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+})
+
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_transblend,(COMMON_ARGS,
+ COLOR_ARG,int transpen),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+ int trans4;
+ UINT32 *sd4;
+
+ trans4 = transpen * 0x01010101;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata > end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,*dstdata | LOOKUP(col))
+ INCREMENT_DST(-HMODULO);
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata >= end + 4*HMODULO)
+ {
+ UINT32 col4;
+
+ INCREMENT_DST(-4*HMODULO);
+ if ((col4 = *(sd4++)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if (xod4 & (0xff<<SHIFT0)) SETPIXELCOLOR(4*HMODULO,dstdata[4*HMODULO] | LOOKUP((col4>>SHIFT0) & 0xff))
+ if (xod4 & (0xff<<SHIFT1)) SETPIXELCOLOR(3*HMODULO,dstdata[3*HMODULO] | LOOKUP((col4>>SHIFT1) & 0xff))
+ if (xod4 & (0xff<<SHIFT2)) SETPIXELCOLOR(2*HMODULO,dstdata[2*HMODULO] | LOOKUP((col4>>SHIFT2) & 0xff))
+ if (xod4 & (0xff<<SHIFT3)) SETPIXELCOLOR(1*HMODULO,dstdata[1*HMODULO] | LOOKUP((col4>>SHIFT3) & 0xff))
+ }
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata > end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,*dstdata | LOOKUP(col))
+ INCREMENT_DST(-HMODULO);
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+ int trans4;
+ UINT32 *sd4;
+
+ trans4 = transpen * 0x01010101;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata < end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,*dstdata | LOOKUP(col))
+ INCREMENT_DST(HMODULO);
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata <= end - 4*HMODULO)
+ {
+ UINT32 col4;
+
+ if ((col4 = *(sd4++)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if (xod4 & (0xff<<SHIFT0)) SETPIXELCOLOR(0*HMODULO,dstdata[0*HMODULO] | LOOKUP((col4>>SHIFT0) & 0xff))
+ if (xod4 & (0xff<<SHIFT1)) SETPIXELCOLOR(1*HMODULO,dstdata[1*HMODULO] | LOOKUP((col4>>SHIFT1) & 0xff))
+ if (xod4 & (0xff<<SHIFT2)) SETPIXELCOLOR(2*HMODULO,dstdata[2*HMODULO] | LOOKUP((col4>>SHIFT2) & 0xff))
+ if (xod4 & (0xff<<SHIFT3)) SETPIXELCOLOR(3*HMODULO,dstdata[3*HMODULO] | LOOKUP((col4>>SHIFT3) & 0xff))
+ }
+ INCREMENT_DST(4*HMODULO);
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,*dstdata | LOOKUP(col))
+ INCREMENT_DST(HMODULO);
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+})
+
+
+#define PEN_IS_OPAQUE ((1<<col)&transmask) == 0
+
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_transmask,(COMMON_ARGS,
+ COLOR_ARG,int transmask),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+ UINT32 *sd4;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata > end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata >= end + 4*HMODULO)
+ {
+ int col;
+ UINT32 col4;
+
+ INCREMENT_DST(-4*HMODULO)
+ col4 = *(sd4++);
+ col = (col4 >> SHIFT0) & 0xff;
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(4*HMODULO,LOOKUP(col))
+ col = (col4 >> SHIFT1) & 0xff;
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(3*HMODULO,LOOKUP(col))
+ col = (col4 >> SHIFT2) & 0xff;
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(2*HMODULO,LOOKUP(col))
+ col = (col4 >> SHIFT3) & 0xff;
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(1*HMODULO,LOOKUP(col))
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata > end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+ UINT32 *sd4;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata < end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata <= end - 4*HMODULO)
+ {
+ int col;
+ UINT32 col4;
+
+ col4 = *(sd4++);
+ col = (col4 >> SHIFT0) & 0xff;
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(0*HMODULO,LOOKUP(col))
+ col = (col4 >> SHIFT1) & 0xff;
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(1*HMODULO,LOOKUP(col))
+ col = (col4 >> SHIFT2) & 0xff;
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(2*HMODULO,LOOKUP(col))
+ col = (col4 >> SHIFT3) & 0xff;
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(3*HMODULO,LOOKUP(col))
+ INCREMENT_DST(4*HMODULO)
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (PEN_IS_OPAQUE) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+})
+
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_transcolor,(COMMON_ARGS,
+ COLOR_ARG,const UINT16 *colortable,int transcolor),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (dstdata > end)
+ {
+ if (colortable[*srcdata] != transcolor) SETPIXELCOLOR(0,LOOKUP(*srcdata))
+ srcdata++;
+ INCREMENT_DST(-HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (dstdata < end)
+ {
+ if (colortable[*srcdata] != transcolor) SETPIXELCOLOR(0,LOOKUP(*srcdata))
+ srcdata++;
+ INCREMENT_DST(HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+})
+
+DECLARE_SWAP_RAW_PRI(blockmove_4toN_transcolor,(COMMON_ARGS,
+ COLOR_ARG,const UINT16 *colortable,int transcolor),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_4
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ int col;
+
+ end = dstdata - dstwidth*HMODULO;
+ if (leftskip)
+ {
+ col = *(srcdata++)>>4;
+ if (colortable[col] != transcolor) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ }
+ while (dstdata > end)
+ {
+ col = *(srcdata)&0x0f;
+ if (colortable[col] != transcolor) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ if (dstdata > end)
+ {
+ col = *(srcdata++)>>4;
+ if (colortable[col] != transcolor) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(-HMODULO)
+ }
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ int col;
+
+ end = dstdata + dstwidth*HMODULO;
+ if (leftskip)
+ {
+ col = *(srcdata++)>>4;
+ if (colortable[col] != transcolor) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ }
+ while (dstdata < end)
+ {
+ col = *(srcdata)&0x0f;
+ if (colortable[col] != transcolor) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ if (dstdata < end)
+ {
+ col = *(srcdata++)>>4;
+ if (colortable[col] != transcolor) SETPIXELCOLOR(0,LOOKUP(col))
+ INCREMENT_DST(HMODULO)
+ }
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+})
+
+#if DEPTH == 32
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_pen_table,(COMMON_ARGS,
+ COLOR_ARG,int transcolor),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (dstdata > end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transcolor)
+ {
+ switch(gfx_drawmode_table[col])
+ {
+ case DRAWMODE_SOURCE:
+ SETPIXELCOLOR(0,LOOKUP(col))
+ break;
+ case DRAWMODE_SHADOW:
+ afterdrawmask = 0;
+ SETPIXELCOLOR(0,*dstdata)
+ afterdrawmask = 31;
+ break;
+ }
+ }
+ INCREMENT_DST(-HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transcolor)
+ {
+ switch(gfx_drawmode_table[col])
+ {
+ case DRAWMODE_SOURCE:
+ SETPIXELCOLOR(0,LOOKUP(col))
+ break;
+ case DRAWMODE_SHADOW:
+ afterdrawmask = 0;
+ SETPIXELCOLOR(0,*dstdata)
+ afterdrawmask = 31;
+ break;
+ }
+ }
+ INCREMENT_DST(HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+})
+#else
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_pen_table,(COMMON_ARGS,
+ COLOR_ARG,int transcolor),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ int eax = (pdrawgfx_shadow_lowpri) ? 0 : 0x80;
+
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (dstdata > end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transcolor)
+ {
+ switch(gfx_drawmode_table[col])
+ {
+ case DRAWMODE_SOURCE:
+ SETPIXELCOLOR(0,LOOKUP(col))
+ break;
+ case DRAWMODE_SHADOW:
+ afterdrawmask = eax;
+ SETPIXELCOLOR(0,palette_shadow_table[*dstdata])
+ afterdrawmask = 31;
+ break;
+ }
+ }
+ INCREMENT_DST(-HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transcolor)
+ {
+ switch(gfx_drawmode_table[col])
+ {
+ case DRAWMODE_SOURCE:
+ SETPIXELCOLOR(0,LOOKUP(col))
+ break;
+ case DRAWMODE_SHADOW:
+ afterdrawmask = eax;
+ SETPIXELCOLOR(0,palette_shadow_table[*dstdata])
+ afterdrawmask = 31;
+ break;
+ }
+ }
+ INCREMENT_DST(HMODULO)
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO)
+ dstheight--;
+ }
+ }
+})
+#endif
+
+#if DEPTH >= 16
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_alphaone,(COMMON_ARGS,
+ COLOR_ARG,int transpen, int alphapen),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+ int trans4;
+ UINT32 *sd4;
+ UINT32 alphacolor = LOOKUP(alphapen);
+
+ trans4 = transpen * 0x01010101;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata > end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen)
+ {
+ if (col == alphapen)
+ SETPIXELCOLOR(0,alpha_blend(*dstdata,alphacolor))
+ else
+ SETPIXELCOLOR(0,LOOKUP(col))
+ }
+ INCREMENT_DST(-HMODULO);
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata >= end + 4*HMODULO)
+ {
+ UINT32 col4;
+
+ INCREMENT_DST(-4*HMODULO);
+ if ((col4 = *(sd4++)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if (xod4 & (0xff<<SHIFT0))
+ {
+ if (((col4>>SHIFT0) & 0xff) == alphapen)
+ SETPIXELCOLOR(4*HMODULO,alpha_blend(dstdata[4*HMODULO], alphacolor))
+ else
+ SETPIXELCOLOR(4*HMODULO,LOOKUP((col4>>SHIFT0) & 0xff))
+ }
+ if (xod4 & (0xff<<SHIFT1))
+ {
+ if (((col4>>SHIFT1) & 0xff) == alphapen)
+ SETPIXELCOLOR(3*HMODULO,alpha_blend(dstdata[3*HMODULO], alphacolor))
+ else
+ SETPIXELCOLOR(3*HMODULO,LOOKUP((col4>>SHIFT1) & 0xff))
+ }
+ if (xod4 & (0xff<<SHIFT2))
+ {
+ if (((col4>>SHIFT2) & 0xff) == alphapen)
+ SETPIXELCOLOR(2*HMODULO,alpha_blend(dstdata[2*HMODULO], alphacolor))
+ else
+ SETPIXELCOLOR(2*HMODULO,LOOKUP((col4>>SHIFT2) & 0xff))
+ }
+ if (xod4 & (0xff<<SHIFT3))
+ {
+ if (((col4>>SHIFT3) & 0xff) == alphapen)
+ SETPIXELCOLOR(1*HMODULO,alpha_blend(dstdata[1*HMODULO], alphacolor))
+ else
+ SETPIXELCOLOR(1*HMODULO,LOOKUP((col4>>SHIFT3) & 0xff))
+ }
+ }
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata > end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen)
+ {
+ if (col == alphapen)
+ SETPIXELCOLOR(0,alpha_blend(*dstdata, alphacolor))
+ else
+ SETPIXELCOLOR(0,LOOKUP(col))
+ }
+ INCREMENT_DST(-HMODULO);
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+ int trans4;
+ UINT32 *sd4;
+ UINT32 alphacolor = LOOKUP(alphapen);
+
+ trans4 = transpen * 0x01010101;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata < end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen)
+ {
+ if (col == alphapen)
+ SETPIXELCOLOR(0,alpha_blend(*dstdata, alphacolor))
+ else
+ SETPIXELCOLOR(0,LOOKUP(col))
+ }
+ INCREMENT_DST(HMODULO);
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata <= end - 4*HMODULO)
+ {
+ UINT32 col4;
+
+ if ((col4 = *(sd4++)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if (xod4 & (0xff<<SHIFT0))
+ {
+ if (((col4>>SHIFT0) & 0xff) == alphapen)
+ SETPIXELCOLOR(0*HMODULO,alpha_blend(dstdata[0*HMODULO], alphacolor))
+ else
+ SETPIXELCOLOR(0*HMODULO,LOOKUP((col4>>SHIFT0) & 0xff))
+ }
+ if (xod4 & (0xff<<SHIFT1))
+ {
+ if (((col4>>SHIFT1) & 0xff) == alphapen)
+ SETPIXELCOLOR(1*HMODULO,alpha_blend(dstdata[1*HMODULO], alphacolor))
+ else
+ SETPIXELCOLOR(1*HMODULO,LOOKUP((col4>>SHIFT1) & 0xff))
+ }
+ if (xod4 & (0xff<<SHIFT2))
+ {
+ if (((col4>>SHIFT2) & 0xff) == alphapen)
+ SETPIXELCOLOR(2*HMODULO,alpha_blend(dstdata[2*HMODULO], alphacolor))
+ else
+ SETPIXELCOLOR(2*HMODULO,LOOKUP((col4>>SHIFT2) & 0xff))
+ }
+ if (xod4 & (0xff<<SHIFT3))
+ {
+ if (((col4>>SHIFT3) & 0xff) == alphapen)
+ SETPIXELCOLOR(3*HMODULO,alpha_blend(dstdata[3*HMODULO], alphacolor))
+ else
+ SETPIXELCOLOR(3*HMODULO,LOOKUP((col4>>SHIFT3) & 0xff))
+ }
+ }
+ INCREMENT_DST(4*HMODULO);
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen)
+ {
+ if (col == alphapen)
+ SETPIXELCOLOR(0,alpha_blend(*dstdata, alphacolor))
+ else
+ SETPIXELCOLOR(0,LOOKUP(col))
+ }
+ INCREMENT_DST(HMODULO);
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+})
+
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_alpha,(COMMON_ARGS,
+ COLOR_ARG,int transpen),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+ int trans4;
+ UINT32 *sd4;
+
+ trans4 = transpen * 0x01010101;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata > end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,alpha_blend(*dstdata, LOOKUP(col)));
+ INCREMENT_DST(-HMODULO);
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata >= end + 4*HMODULO)
+ {
+ UINT32 col4;
+
+ INCREMENT_DST(-4*HMODULO);
+ if ((col4 = *(sd4++)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if (xod4 & (0xff<<SHIFT0)) SETPIXELCOLOR(4*HMODULO,alpha_blend(dstdata[4*HMODULO], LOOKUP((col4>>SHIFT0) & 0xff)));
+ if (xod4 & (0xff<<SHIFT1)) SETPIXELCOLOR(3*HMODULO,alpha_blend(dstdata[3*HMODULO], LOOKUP((col4>>SHIFT1) & 0xff)));
+ if (xod4 & (0xff<<SHIFT2)) SETPIXELCOLOR(2*HMODULO,alpha_blend(dstdata[2*HMODULO], LOOKUP((col4>>SHIFT2) & 0xff)));
+ if (xod4 & (0xff<<SHIFT3)) SETPIXELCOLOR(1*HMODULO,alpha_blend(dstdata[1*HMODULO], LOOKUP((col4>>SHIFT3) & 0xff)));
+ }
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata > end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,alpha_blend(*dstdata, LOOKUP(col)));
+ INCREMENT_DST(-HMODULO);
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+ int trans4;
+ UINT32 *sd4;
+
+ trans4 = transpen * 0x01010101;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (((FPTR)srcdata & 3) && dstdata < end) /* longword align */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,alpha_blend(*dstdata, LOOKUP(col)));
+ INCREMENT_DST(HMODULO);
+ }
+ sd4 = (UINT32 *)srcdata;
+ while (dstdata <= end - 4*HMODULO)
+ {
+ UINT32 col4;
+
+ if ((col4 = *(sd4++)) != trans4)
+ {
+ UINT32 xod4;
+
+ xod4 = col4 ^ trans4;
+ if (xod4 & (0xff<<SHIFT0)) SETPIXELCOLOR(0*HMODULO,alpha_blend(dstdata[0*HMODULO], LOOKUP((col4>>SHIFT0) & 0xff)));
+ if (xod4 & (0xff<<SHIFT1)) SETPIXELCOLOR(1*HMODULO,alpha_blend(dstdata[1*HMODULO], LOOKUP((col4>>SHIFT1) & 0xff)));
+ if (xod4 & (0xff<<SHIFT2)) SETPIXELCOLOR(2*HMODULO,alpha_blend(dstdata[2*HMODULO], LOOKUP((col4>>SHIFT2) & 0xff)));
+ if (xod4 & (0xff<<SHIFT3)) SETPIXELCOLOR(3*HMODULO,alpha_blend(dstdata[3*HMODULO], LOOKUP((col4>>SHIFT3) & 0xff)));
+ }
+ INCREMENT_DST(4*HMODULO);
+ }
+ srcdata = (UINT8 *)sd4;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen) SETPIXELCOLOR(0,alpha_blend(*dstdata, LOOKUP(col)));
+ INCREMENT_DST(HMODULO);
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+})
+
+/* pjp 02/06/02 */
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_alpharange,(COMMON_ARGS,
+ COLOR_ARG,int transpen),
+{
+ pen_t *palette_shadow_table = Machine->shadow_table;
+ ADJUST_8
+
+ (void)palette_shadow_table;
+
+ if (flipx)
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata - dstwidth*HMODULO;
+ while (dstdata > end) /* Note that I'm missing the optimisations present in the other alpha functions */
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen)
+ {
+ if (gfx_alpharange_table[col] == 0xff)
+ SETPIXELCOLOR(0,LOOKUP(col))
+ else
+ SETPIXELCOLOR(0,alpha_blend_r(*dstdata,LOOKUP(col),gfx_alpharange_table[col]))
+ }
+ INCREMENT_DST(-HMODULO);
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO + dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+ else
+ {
+ DATA_TYPE *end;
+
+ while (dstheight)
+ {
+ end = dstdata + dstwidth*HMODULO;
+ while (dstdata < end)
+ {
+ int col;
+
+ col = *(srcdata++);
+ if (col != transpen)
+ {
+ if (gfx_alpharange_table[col] == 0xff)
+ SETPIXELCOLOR(0,LOOKUP(col))
+ else
+ SETPIXELCOLOR(0,alpha_blend_r(*dstdata,LOOKUP(col),gfx_alpharange_table[col]))
+ }
+ INCREMENT_DST(HMODULO);
+ }
+
+ srcdata += srcmodulo;
+ INCREMENT_DST(ydir*VMODULO - dstwidth*HMODULO);
+ dstheight--;
+ }
+ }
+})
+
+#else
+
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_alphaone,(COMMON_ARGS,
+ COLOR_ARG,int transpen, int alphapen),{})
+
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_alpha,(COMMON_ARGS,
+ COLOR_ARG,int transpen),{})
+
+DECLARE_SWAP_RAW_PRI(blockmove_8toN_alpharange,(COMMON_ARGS,
+ COLOR_ARG,int transpen),{})
+
+#endif
+
+DECLARE(blockmove_NtoN_opaque_noremap,(
+ const DATA_TYPE *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ DATA_TYPE *dstdata,int dstmodulo),
+{
+ while (srcheight)
+ {
+ memcpy(dstdata,srcdata,srcwidth * sizeof(DATA_TYPE));
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+})
+
+DECLARE(blockmove_NtoN_opaque_noremap_flipx,(
+ const DATA_TYPE *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ DATA_TYPE *dstdata,int dstmodulo),
+{
+ DATA_TYPE *end;
+
+ srcmodulo += srcwidth;
+ dstmodulo -= srcwidth;
+ //srcdata += srcwidth-1;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata <= end - 8)
+ {
+ srcdata -= 8;
+ dstdata[0] = srcdata[8];
+ dstdata[1] = srcdata[7];
+ dstdata[2] = srcdata[6];
+ dstdata[3] = srcdata[5];
+ dstdata[4] = srcdata[4];
+ dstdata[5] = srcdata[3];
+ dstdata[6] = srcdata[2];
+ dstdata[7] = srcdata[1];
+ dstdata += 8;
+ }
+ while (dstdata < end)
+ *(dstdata++) = *(srcdata--);
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+})
+
+DECLARE(blockmove_NtoN_opaque_remap,(
+ const DATA_TYPE *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ DATA_TYPE *dstdata,int dstmodulo,
+ const pen_t *paldata),
+{
+ DATA_TYPE *end;
+
+ srcmodulo -= srcwidth;
+ dstmodulo -= srcwidth;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata <= end - 8)
+ {
+ dstdata[0] = paldata[srcdata[0]];
+ dstdata[1] = paldata[srcdata[1]];
+ dstdata[2] = paldata[srcdata[2]];
+ dstdata[3] = paldata[srcdata[3]];
+ dstdata[4] = paldata[srcdata[4]];
+ dstdata[5] = paldata[srcdata[5]];
+ dstdata[6] = paldata[srcdata[6]];
+ dstdata[7] = paldata[srcdata[7]];
+ dstdata += 8;
+ srcdata += 8;
+ }
+ while (dstdata < end)
+ *(dstdata++) = paldata[*(srcdata++)];
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+})
+
+DECLARE(blockmove_NtoN_opaque_remap_flipx,(
+ const DATA_TYPE *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ DATA_TYPE *dstdata,int dstmodulo,
+ const pen_t *paldata),
+{
+ DATA_TYPE *end;
+
+ srcmodulo += srcwidth;
+ dstmodulo -= srcwidth;
+ //srcdata += srcwidth-1;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata <= end - 8)
+ {
+ srcdata -= 8;
+ dstdata[0] = paldata[srcdata[8]];
+ dstdata[1] = paldata[srcdata[7]];
+ dstdata[2] = paldata[srcdata[6]];
+ dstdata[3] = paldata[srcdata[5]];
+ dstdata[4] = paldata[srcdata[4]];
+ dstdata[5] = paldata[srcdata[3]];
+ dstdata[6] = paldata[srcdata[2]];
+ dstdata[7] = paldata[srcdata[1]];
+ dstdata += 8;
+ }
+ while (dstdata < end)
+ *(dstdata++) = paldata[*(srcdata--)];
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+})
+
+
+DECLARE(blockmove_NtoN_blend_noremap,(
+ const DATA_TYPE *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ DATA_TYPE *dstdata,int dstmodulo,
+ int srcshift),
+{
+ DATA_TYPE *end;
+
+ srcmodulo -= srcwidth;
+ dstmodulo -= srcwidth;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata <= end - 8)
+ {
+ dstdata[0] |= srcdata[0] << srcshift;
+ dstdata[1] |= srcdata[1] << srcshift;
+ dstdata[2] |= srcdata[2] << srcshift;
+ dstdata[3] |= srcdata[3] << srcshift;
+ dstdata[4] |= srcdata[4] << srcshift;
+ dstdata[5] |= srcdata[5] << srcshift;
+ dstdata[6] |= srcdata[6] << srcshift;
+ dstdata[7] |= srcdata[7] << srcshift;
+ dstdata += 8;
+ srcdata += 8;
+ }
+ while (dstdata < end)
+ *(dstdata++) |= *(srcdata++) << srcshift;
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+})
+
+DECLARE(blockmove_NtoN_blend_noremap_flipx,(
+ const DATA_TYPE *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ DATA_TYPE *dstdata,int dstmodulo,
+ int srcshift),
+{
+ DATA_TYPE *end;
+
+ srcmodulo += srcwidth;
+ dstmodulo -= srcwidth;
+ //srcdata += srcwidth-1;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata <= end - 8)
+ {
+ srcdata -= 8;
+ dstdata[0] |= srcdata[8] << srcshift;
+ dstdata[1] |= srcdata[7] << srcshift;
+ dstdata[2] |= srcdata[6] << srcshift;
+ dstdata[3] |= srcdata[5] << srcshift;
+ dstdata[4] |= srcdata[4] << srcshift;
+ dstdata[5] |= srcdata[3] << srcshift;
+ dstdata[6] |= srcdata[2] << srcshift;
+ dstdata[7] |= srcdata[1] << srcshift;
+ dstdata += 8;
+ }
+ while (dstdata < end)
+ *(dstdata++) |= *(srcdata--) << srcshift;
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+})
+
+DECLARE(blockmove_NtoN_blend_remap,(
+ const DATA_TYPE *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ DATA_TYPE *dstdata,int dstmodulo,
+ const pen_t *paldata,int srcshift),
+{
+ DATA_TYPE *end;
+
+ srcmodulo -= srcwidth;
+ dstmodulo -= srcwidth;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata <= end - 8)
+ {
+ dstdata[0] = paldata[dstdata[0] | (srcdata[0] << srcshift)];
+ dstdata[1] = paldata[dstdata[1] | (srcdata[1] << srcshift)];
+ dstdata[2] = paldata[dstdata[2] | (srcdata[2] << srcshift)];
+ dstdata[3] = paldata[dstdata[3] | (srcdata[3] << srcshift)];
+ dstdata[4] = paldata[dstdata[4] | (srcdata[4] << srcshift)];
+ dstdata[5] = paldata[dstdata[5] | (srcdata[5] << srcshift)];
+ dstdata[6] = paldata[dstdata[6] | (srcdata[6] << srcshift)];
+ dstdata[7] = paldata[dstdata[7] | (srcdata[7] << srcshift)];
+ dstdata += 8;
+ srcdata += 8;
+ }
+ while (dstdata < end)
+ {
+ *dstdata = paldata[*dstdata | (*(srcdata++) << srcshift)];
+ dstdata++;
+ }
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+
+})
+
+DECLARE(blockmove_NtoN_blend_remap_flipx,(
+ const DATA_TYPE *srcdata,int srcwidth,int srcheight,int srcmodulo,
+ DATA_TYPE *dstdata,int dstmodulo,
+ const pen_t *paldata,int srcshift),
+{
+ DATA_TYPE *end;
+
+ srcmodulo += srcwidth;
+ dstmodulo -= srcwidth;
+ //srcdata += srcwidth-1;
+
+ while (srcheight)
+ {
+ end = dstdata + srcwidth;
+ while (dstdata <= end - 8)
+ {
+ srcdata -= 8;
+ dstdata[0] = paldata[dstdata[0] | (srcdata[8] << srcshift)];
+ dstdata[1] = paldata[dstdata[1] | (srcdata[7] << srcshift)];
+ dstdata[2] = paldata[dstdata[2] | (srcdata[6] << srcshift)];
+ dstdata[3] = paldata[dstdata[3] | (srcdata[5] << srcshift)];
+ dstdata[4] = paldata[dstdata[4] | (srcdata[4] << srcshift)];
+ dstdata[5] = paldata[dstdata[5] | (srcdata[3] << srcshift)];
+ dstdata[6] = paldata[dstdata[6] | (srcdata[2] << srcshift)];
+ dstdata[7] = paldata[dstdata[7] | (srcdata[1] << srcshift)];
+ dstdata += 8;
+ }
+ while (dstdata < end)
+ {
+ *dstdata = paldata[*dstdata | (*(srcdata--) << srcshift)];
+ dstdata++;
+ }
+
+ srcdata += srcmodulo;
+ dstdata += dstmodulo;
+ srcheight--;
+ }
+})
+
+
+
+
+
+DECLARE(drawgfx_core,(
+ mame_bitmap *dest,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,
+ mame_bitmap *pri_buffer,UINT32 pri_mask),
+{
+ int ox;
+ int oy;
+ int ex;
+ int ey;
+
+
+ /* check bounds */
+ ox = sx;
+ oy = sy;
+
+ ex = sx + gfx->width-1;
+ if (sx < 0) sx = 0;
+ if (clip && sx < clip->min_x) sx = clip->min_x;
+ if (ex >= dest->width) ex = dest->width-1;
+ if (clip && ex > clip->max_x) ex = clip->max_x;
+ if (sx > ex) return;
+
+ ey = sy + gfx->height-1;
+ if (sy < 0) sy = 0;
+ if (clip && sy < clip->min_y) sy = clip->min_y;
+ if (ey >= dest->height) ey = dest->height-1;
+ if (clip && ey > clip->max_y) ey = clip->max_y;
+ if (sy > ey) return;
+
+ {
+ UINT8 *sd = gfx->gfxdata + code * gfx->char_modulo; /* source data */
+ int sw = gfx->width; /* source width */
+ int sh = gfx->height; /* source height */
+ int sm = gfx->line_modulo; /* source modulo */
+ int ls = sx-ox; /* left skip */
+ int ts = sy-oy; /* top skip */
+ DATA_TYPE *dd = BITMAP_ADDR(dest, DATA_TYPE, sy, sx); /* dest data */
+ int dw = ex-sx+1; /* dest width */
+ int dh = ey-sy+1; /* dest height */
+ int dm = dest->rowpixels; /* dest modulo */
+ const pen_t *paldata = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * color];
+ UINT8 *pribuf = (pri_buffer) ? BITMAP_ADDR8(pri_buffer, sy, sx) : NULL;
+
+ /* optimizations for 1:1 mapping */
+ if (Machine->drv->color_table_len == 0 &&
+ dest->format == BITMAP_FORMAT_INDEXED16 &&
+ paldata >= Machine->remapped_colortable &&
+ paldata < Machine->remapped_colortable + Machine->drv->total_colors)
+ {
+ switch (transparency)
+ {
+ case TRANSPARENCY_NONE:
+ transparency = TRANSPARENCY_NONE_RAW;
+ color = paldata - Machine->remapped_colortable;
+ break;
+ case TRANSPARENCY_PEN:
+ transparency = TRANSPARENCY_PEN_RAW;
+ color = paldata - Machine->remapped_colortable;
+ break;
+ case TRANSPARENCY_PENS:
+ transparency = TRANSPARENCY_PENS_RAW;
+ color = paldata - Machine->remapped_colortable;
+ break;
+ case TRANSPARENCY_PEN_TABLE:
+ transparency = TRANSPARENCY_PEN_TABLE_RAW;
+ color = paldata - Machine->remapped_colortable;
+ break;
+ }
+ }
+
+ switch (transparency)
+ {
+ case TRANSPARENCY_NONE:
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ if (pribuf)
+ BLOCKMOVEPRI(4toN_opaque,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask));
+ else
+ BLOCKMOVELU(4toN_opaque,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata));
+ }
+ else
+ {
+ if (pribuf)
+ BLOCKMOVEPRI(8toN_opaque,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask));
+ else
+ BLOCKMOVELU(8toN_opaque,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata));
+ }
+ break;
+
+ case TRANSPARENCY_NONE_RAW:
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ if (pribuf)
+ BLOCKMOVERAWPRI(4toN_opaque,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,pribuf,pri_mask));
+ else
+ BLOCKMOVERAW(4toN_opaque,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color));
+ }
+ else
+ {
+ if (pribuf)
+ BLOCKMOVERAWPRI(8toN_opaque,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,pribuf,pri_mask));
+ else
+ BLOCKMOVERAW(8toN_opaque,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color));
+ }
+ break;
+
+ case TRANSPARENCY_PEN:
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ if (pribuf)
+ BLOCKMOVEPRI(4toN_transpen,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVELU(4toN_transpen,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,transparent_color));
+ }
+ else
+ {
+ if (pribuf)
+ BLOCKMOVEPRI(8toN_transpen,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVELU(8toN_transpen,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,transparent_color));
+ }
+ break;
+
+ case TRANSPARENCY_PEN_RAW:
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ if (pribuf)
+ BLOCKMOVERAWPRI(4toN_transpen,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVERAW(4toN_transpen,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,transparent_color));
+ }
+ else
+ {
+ if (pribuf)
+ BLOCKMOVERAWPRI(8toN_transpen,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVERAW(8toN_transpen,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,transparent_color));
+ }
+ break;
+
+ case TRANSPARENCY_PENS:
+ if (pribuf)
+ BLOCKMOVEPRI(8toN_transmask,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVELU(8toN_transmask,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,transparent_color));
+ break;
+
+ case TRANSPARENCY_PENS_RAW:
+ if (pribuf)
+ BLOCKMOVERAWPRI(8toN_transmask,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVERAW(8toN_transmask,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,transparent_color));
+ break;
+
+ case TRANSPARENCY_COLOR:
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ if (pribuf)
+ BLOCKMOVEPRI(4toN_transcolor,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask,Machine->game_colortable + (paldata - Machine->remapped_colortable),transparent_color));
+ else
+ BLOCKMOVELU(4toN_transcolor,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,Machine->game_colortable + (paldata - Machine->remapped_colortable),transparent_color));
+ }
+ else
+ {
+ if (pribuf)
+ BLOCKMOVEPRI(8toN_transcolor,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask,Machine->game_colortable + (paldata - Machine->remapped_colortable),transparent_color));
+ else
+ BLOCKMOVELU(8toN_transcolor,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,Machine->game_colortable + (paldata - Machine->remapped_colortable),transparent_color));
+ }
+ break;
+
+ case TRANSPARENCY_PEN_TABLE:
+ if (pribuf)
+ BLOCKMOVEPRI(8toN_pen_table,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVELU(8toN_pen_table,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,transparent_color));
+ break;
+
+ case TRANSPARENCY_PEN_TABLE_RAW:
+ if (pribuf)
+ BLOCKMOVERAWPRI(8toN_pen_table,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVERAW(8toN_pen_table,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,transparent_color));
+ break;
+
+ case TRANSPARENCY_BLEND_RAW:
+ if (pribuf)
+ BLOCKMOVERAWPRI(8toN_transblend,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVERAW(8toN_transblend,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,color,transparent_color));
+ break;
+
+ case TRANSPARENCY_ALPHA:
+ if (pribuf)
+ BLOCKMOVEPRI(8toN_alpha,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVELU(8toN_alpha,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,transparent_color));
+ break;
+
+ case TRANSPARENCY_ALPHARANGE:
+ if (pribuf)
+ BLOCKMOVEPRI(8toN_alpharange,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,pribuf,pri_mask,transparent_color));
+ else
+ BLOCKMOVELU(8toN_alpharange,(sd,sw,sh,sm,ls,ts,flipx,flipy,dd,dw,dh,dm,paldata,transparent_color));
+ break;
+
+ default:
+ if (pribuf)
+ popmessage("pdrawgfx pen mode not supported");
+ else
+ popmessage("drawgfx pen mode not supported");
+ break;
+ }
+ }
+})
+
+DECLARE(copybitmap_core,(
+ mame_bitmap *dest,mame_bitmap *src,
+ int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color),
+{
+ int ox;
+ int oy;
+ int ex;
+ int ey;
+
+
+ /* check bounds */
+ ox = sx;
+ oy = sy;
+
+ ex = sx + src->width-1;
+ if (sx < 0) sx = 0;
+ if (clip && sx < clip->min_x) sx = clip->min_x;
+ if (ex >= dest->width) ex = dest->width-1;
+ if (clip && ex > clip->max_x) ex = clip->max_x;
+ if (sx > ex) return;
+
+ ey = sy + src->height-1;
+ if (sy < 0) sy = 0;
+ if (clip && sy < clip->min_y) sy = clip->min_y;
+ if (ey >= dest->height) ey = dest->height-1;
+ if (clip && ey > clip->max_y) ey = clip->max_y;
+ if (sy > ey) return;
+
+ {
+ DATA_TYPE *sd = (DATA_TYPE *)src->base; /* source data */
+ int sw = ex-sx+1; /* source width */
+ int sh = ey-sy+1; /* source height */
+ int sm = src->rowpixels; /* source modulo */
+ DATA_TYPE *dd = BITMAP_ADDR(dest, DATA_TYPE, sy, sx); /* dest data */
+ int dm = dest->rowpixels; /* dest modulo */
+
+ if (flipx)
+ {
+ //if ((sx-ox) == 0) sd += gfx->width - sw;
+ sd += src->width -1 -(sx-ox);
+ }
+ else
+ sd += (sx-ox);
+
+ if (flipy)
+ {
+ //if ((sy-oy) == 0) sd += sm * (gfx->height - sh);
+ //dd += dm * (sh - 1);
+ //dm = -dm;
+ sd += sm * (src->height -1 -(sy-oy));
+ sm = -sm;
+ }
+ else
+ sd += sm * (sy-oy);
+
+ switch (transparency)
+ {
+ case TRANSPARENCY_NONE:
+ BLOCKMOVE(NtoN_opaque_remap,flipx,(sd,sw,sh,sm,dd,dm,Machine->pens));
+ break;
+
+ case TRANSPARENCY_NONE_RAW:
+ BLOCKMOVE(NtoN_opaque_noremap,flipx,(sd,sw,sh,sm,dd,dm));
+ break;
+
+ case TRANSPARENCY_PEN_RAW:
+ BLOCKMOVE(NtoN_transpen_noremap,flipx,(sd,sw,sh,sm,dd,dm,transparent_color));
+ break;
+
+ case TRANSPARENCY_BLEND:
+ BLOCKMOVE(NtoN_blend_remap,flipx,(sd,sw,sh,sm,dd,dm,Machine->pens,transparent_color));
+ break;
+
+ case TRANSPARENCY_BLEND_RAW:
+ BLOCKMOVE(NtoN_blend_noremap,flipx,(sd,sw,sh,sm,dd,dm,transparent_color));
+ break;
+
+ default:
+ popmessage("copybitmap pen mode not supported");
+ break;
+ }
+ }
+})
+
+DECLARE(copyrozbitmap_core,(mame_bitmap *bitmap,mame_bitmap *srcbitmap,
+ UINT32 startx,UINT32 starty,int incxx,int incxy,int incyx,int incyy,int wraparound,
+ const rectangle *clip,int transparency,int transparent_color,UINT32 priority),
+{
+ 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 = srcbitmap->width << 16;
+ const int heightshifted = srcbitmap->height << 16;
+ DATA_TYPE *dest;
+
+
+ if (clip)
+ {
+ startx += clip->min_x * incxx + clip->min_y * incyx;
+ starty += clip->min_x * incxy + clip->min_y * incyy;
+
+ sx = clip->min_x;
+ sy = clip->min_y;
+ ex = clip->max_x;
+ ey = clip->max_y;
+ }
+ else
+ {
+ sx = 0;
+ sy = 0;
+ ex = bitmap->width-1;
+ ey = bitmap->height-1;
+ }
+
+
+ if (incxy == 0 && incyx == 0 && !wraparound)
+ {
+ /* optimized loop for the not rotated case */
+
+ if (incxx == 0x10000)
+ {
+ /* optimized loop for the not zoomed case */
+
+ /* startx is unsigned */
+ startx = ((INT32)startx) >> 16;
+
+ if (startx >= srcbitmap->width)
+ {
+ sx += -startx;
+ startx = 0;
+ }
+
+ if (sx <= ex)
+ {
+ while (sy <= ey)
+ {
+ if (starty < heightshifted)
+ {
+ x = sx;
+ cx = startx;
+ cy = starty >> 16;
+ dest = BITMAP_ADDR(bitmap, DATA_TYPE, sy, sx);
+ if (priority)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, sy, sx);
+ DATA_TYPE *src = BITMAP_ADDR(srcbitmap, DATA_TYPE, cy, 0);
+
+ while (x <= ex && cx < srcbitmap->width)
+ {
+ int c = src[cx];
+
+ if (c != transparent_color)
+ {
+ *dest = c;
+ *pri |= priority;
+ }
+
+ cx++;
+ x++;
+ dest++;
+ pri++;
+ }
+ }
+ else
+ {
+ DATA_TYPE *src = BITMAP_ADDR(srcbitmap, DATA_TYPE, cy, 0);
+
+ while (x <= ex && cx < srcbitmap->width)
+ {
+ int c = src[cx];
+
+ if (c != transparent_color)
+ *dest = c;
+
+ cx++;
+ x++;
+ dest++;
+ }
+ }
+ }
+ starty += incyy;
+ sy++;
+ }
+ }
+ }
+ else
+ {
+ while (startx >= widthshifted && sx <= ex)
+ {
+ startx += incxx;
+ sx++;
+ }
+
+ if (sx <= ex)
+ {
+ while (sy <= ey)
+ {
+ if (starty < heightshifted)
+ {
+ x = sx;
+ cx = startx;
+ cy = starty >> 16;
+ dest = BITMAP_ADDR(bitmap, DATA_TYPE, sy, sx);
+ if (priority)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, sy, sx);
+ DATA_TYPE *src = BITMAP_ADDR(srcbitmap, DATA_TYPE, cy, 0);
+
+ while (x <= ex && cx < widthshifted)
+ {
+ int c = src[cx >> 16];
+
+ if (c != transparent_color)
+ {
+ *dest = c;
+ *pri |= priority;
+ }
+
+ cx += incxx;
+ x++;
+ dest++;
+ pri++;
+ }
+ }
+ else
+ {
+ DATA_TYPE *src = BITMAP_ADDR(srcbitmap, DATA_TYPE, cy, 0);
+
+ while (x <= ex && cx < widthshifted)
+ {
+ int c = src[cx >> 16];
+
+ if (c != transparent_color)
+ *dest = c;
+
+ cx += incxx;
+ x++;
+ dest++;
+ }
+ }
+ }
+ starty += incyy;
+ sy++;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (wraparound)
+ {
+ /* plot with wraparound */
+ while (sy <= ey)
+ {
+ x = sx;
+ cx = startx;
+ cy = starty;
+ dest = BITMAP_ADDR(bitmap, DATA_TYPE, sy, sx);
+ if (priority)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, sy, sx);
+
+ while (x <= ex)
+ {
+ int c = *BITMAP_ADDR(srcbitmap, DATA_TYPE, (cy >> 16) & ymask, (cx >> 16) & xmask);
+
+ if (c != transparent_color)
+ {
+ *dest = c;
+ *pri |= priority;
+ }
+
+ cx += incxx;
+ cy += incxy;
+ x++;
+ dest++;
+ pri++;
+ }
+ }
+ else
+ {
+ while (x <= ex)
+ {
+ int c = *BITMAP_ADDR(srcbitmap, DATA_TYPE, (cy >> 16) & ymask, (cx >> 16) & xmask);
+
+ if (c != transparent_color)
+ *dest = c;
+
+ cx += incxx;
+ cy += incxy;
+ x++;
+ dest++;
+ }
+ }
+ startx += incyx;
+ starty += incyy;
+ sy++;
+ }
+ }
+ else
+ {
+ while (sy <= ey)
+ {
+ x = sx;
+ cx = startx;
+ cy = starty;
+ if (priority)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, sy, sx);
+
+ while (x <= ex)
+ {
+ if (cx < widthshifted && cy < heightshifted)
+ {
+ int c = *BITMAP_ADDR(srcbitmap, DATA_TYPE, cy >> 16, cx >> 16);
+
+ if (c != transparent_color)
+ {
+ dest = BITMAP_ADDR(bitmap, DATA_TYPE, sy, x);
+ *dest = c;
+ *pri |= priority;
+ }
+ }
+
+ cx += incxx;
+ cy += incxy;
+ x++;
+ pri++;
+ }
+ }
+ else
+ {
+ while (x <= ex)
+ {
+ if (cx < widthshifted && cy < heightshifted)
+ {
+ int c = *BITMAP_ADDR(srcbitmap, DATA_TYPE, cy >> 16, cx >> 16);
+
+ if (c != transparent_color)
+ {
+ dest = BITMAP_ADDR(bitmap, DATA_TYPE, sy, x);
+ *dest = c;
+ }
+ }
+
+ cx += incxx;
+ cy += incxy;
+ x++;
+ }
+ }
+ startx += incyx;
+ starty += incyy;
+ sy++;
+ }
+ }
+ }
+})
+
+DECLAREG(draw_scanline, (
+ mame_bitmap *bitmap,int x,int y,int length,
+ const DATA_TYPE *src,const pen_t *pens,int transparent_pen),
+{
+ /* 8bpp destination */
+ if (bitmap->bpp == 8)
+ {
+ UINT8 *dst = BITMAP_ADDR8(bitmap, y, x);
+ int xadv = 1;
+
+ /* with pen lookups */
+ if (pens)
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dst = pens[*src++];
+ dst += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ *dst = pens[spixel];
+ dst += xadv;
+ }
+ }
+
+ /* without pen lookups */
+ else
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dst = *src++;
+ dst += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ *dst = spixel;
+ dst += xadv;
+ }
+ }
+ }
+
+ /* 16bpp destination */
+ else if (bitmap->bpp == 16)
+ {
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, x);
+ int xadv = 1;
+
+ /* with pen lookups */
+ if (pens)
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dst = pens[*src++];
+ dst += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ *dst = pens[spixel];
+ dst += xadv;
+ }
+ }
+
+ /* without pen lookups */
+ else
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dst = *src++;
+ dst += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ *dst = spixel;
+ dst += xadv;
+ }
+ }
+ }
+
+ /* 32bpp destination */
+ else if (bitmap->bpp == 32)
+ {
+ UINT32 *dst = BITMAP_ADDR32(bitmap, y, x);
+ int xadv = 1;
+
+ /* with pen lookups */
+ if (pens)
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dst = pens[*src++];
+ dst += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ *dst = pens[spixel];
+ dst += xadv;
+ }
+ }
+
+ /* without pen lookups */
+ else
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dst = *src++;
+ dst += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ *dst = spixel;
+ dst += xadv;
+ }
+ }
+ }
+})
+
+DECLAREG(pdraw_scanline, (
+ mame_bitmap *bitmap,int x,int y,int length,
+ const DATA_TYPE *src,const pen_t *pens,int transparent_pen,int pri),
+{
+ /* 8bpp destination */
+ if (bitmap->bpp == 8)
+ {
+ UINT8 *dsti = BITMAP_ADDR8(bitmap, y, x);
+ UINT8 *dstp = BITMAP_ADDR8(priority_bitmap, y, x);
+ int xadv = 1;
+
+ /* 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)
+ {
+ UINT16 *dsti = BITMAP_ADDR16(bitmap, y, x);
+ UINT8 *dstp = BITMAP_ADDR8(priority_bitmap, y, x);
+ int xadv = 1;
+
+ /* 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 if (bitmap->bpp == 32)
+ {
+ UINT32 *dsti = BITMAP_ADDR32(bitmap, y, x);
+ UINT8 *dstp = BITMAP_ADDR8(priority_bitmap, y, x);
+ int xadv = 1;
+
+ /* 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;
+ }
+ }
+ }
+}
+)
+
+DECLAREG(extract_scanline, (
+ mame_bitmap *bitmap,int x,int y,int length,
+ DATA_TYPE *dst),
+{
+ /* 8bpp destination */
+ if (bitmap->bpp == 8)
+ {
+ UINT8 *src = BITMAP_ADDR8(bitmap, y, x);
+ int xadv = 1;
+
+ while (length--)
+ {
+ *dst++ = *src;
+ src += xadv;
+ }
+ }
+
+ /* 16bpp destination */
+ else if (bitmap->bpp == 16)
+ {
+ UINT16 *src = BITMAP_ADDR16(bitmap, y, x);
+ int xadv = 1;
+
+ while (length--)
+ {
+ *dst++ = *src;
+ src += xadv;
+ }
+ }
+
+ /* 32bpp destination */
+ else if (bitmap->bpp == 32)
+ {
+ UINT32 *src = BITMAP_ADDR32(bitmap, y, x);
+ int xadv = 1;
+
+ while (length--)
+ {
+ *dst++ = *src;
+ src += xadv;
+ }
+ }
+})
+
+#endif /* DECLARE */
diff --git a/src/emu/drawgfx.h b/src/emu/drawgfx.h
new file mode 100644
index 00000000000..513b7b289df
--- /dev/null
+++ b/src/emu/drawgfx.h
@@ -0,0 +1,331 @@
+/*********************************************************************
+
+ drawgfx.h
+
+ Generic graphic functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __DRAWGFX_H__
+#define __DRAWGFX_H__
+
+#include "mamecore.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_GFX_PLANES 8
+#define MAX_GFX_SIZE 32
+#define MAX_ABS_GFX_SIZE 1024
+
+#define EXTENDED_XOFFS { 0 }
+#define EXTENDED_YOFFS { 0 }
+
+#define GFX_ELEMENT_PACKED 1 /* two 4bpp pixels are packed in one byte of gfxdata */
+#define GFX_ELEMENT_DONT_FREE 2 /* gfxdata was not malloc()ed, so don't free it on exit */
+
+#define GFX_RAW 0x12345678
+/* When planeoffset[0] is set to GFX_RAW, the gfx data is left as-is, with no conversion.
+ No buffer is allocated for the decoded data, and gfxdata is set to point to the source
+ data; therefore, you must not use ROMREGION_DISPOSE.
+ xoffset[0] is an optional displacement (*8) from the beginning of the source data, while
+ yoffset[0] is the line modulo (*8) and charincrement the char modulo (*8). They are *8
+ for consistency with the usual behaviour, but the bottom 3 bits are not used.
+ GFX_ELEMENT_PACKED is automatically set if planes is <= 4.
+
+ This special mode can be used to save memory in games that require several different
+ handlings of the same ROM data (e.g. metro.c can use both 4bpp and 8bpp tiles, and both
+ 8x8 and 16x16; cps.c has 8x8, 16x16 and 32x32 tiles all fetched from the same ROMs).
+ Note, however, that performance will suffer in rotated games, since the gfx data will
+ not be prerotated and will rely on GFX_SWAPXY.
+*/
+
+enum
+{
+ TRANSPARENCY_NONE, /* opaque with remapping */
+ TRANSPARENCY_NONE_RAW, /* opaque with no remapping */
+ TRANSPARENCY_PEN, /* single pen transparency with remapping */
+ TRANSPARENCY_PEN_RAW, /* single pen transparency with no remapping */
+ TRANSPARENCY_PENS, /* multiple pen transparency with remapping */
+ TRANSPARENCY_PENS_RAW, /* multiple pen transparency with no remapping */
+ TRANSPARENCY_COLOR, /* single remapped pen transparency with remapping */
+ TRANSPARENCY_PEN_TABLE, /* special pen remapping modes (see DRAWMODE_xxx below) with remapping */
+ TRANSPARENCY_PEN_TABLE_RAW, /* special pen remapping modes (see DRAWMODE_xxx below) with no remapping */
+ TRANSPARENCY_BLEND, /* blend two bitmaps, shifting the source and ORing to the dest with remapping */
+ TRANSPARENCY_BLEND_RAW, /* blend two bitmaps, shifting the source and ORing to the dest with no remapping */
+ TRANSPARENCY_ALPHA, /* single pen transparency, other pens alpha */
+ TRANSPARENCY_ALPHARANGE, /* single pen transparency, multiple pens alpha depending on array, see psikyosh.c */
+
+ TRANSPARENCY_MODES /* total number of modes; must be last */
+};
+
+enum
+{
+ DRAWMODE_NONE,
+ DRAWMODE_SOURCE,
+ DRAWMODE_SHADOW
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* map old fillbitmap to new shared bitmap_fill code */
+#define fillbitmap(dest, pen, clip) bitmap_fill(dest, clip, pen)
+
+/* these macros describe gfx_layouts in terms of fractions of a region */
+/* they can be used for total, planeoffset, xoffset, yoffset */
+#define RGN_FRAC(num,den) (0x80000000 | (((num) & 0x0f) << 27) | (((den) & 0x0f) << 23))
+#define IS_FRAC(offset) ((offset) & 0x80000000)
+#define FRAC_NUM(offset) (((offset) >> 27) & 0x0f)
+#define FRAC_DEN(offset) (((offset) >> 23) & 0x0f)
+#define FRAC_OFFSET(offset) ((offset) & 0x007fffff)
+
+/* these macros are useful in gfx_layouts */
+#define STEP2(START,STEP) (START),(START)+(STEP)
+#define STEP4(START,STEP) STEP2(START,STEP),STEP2((START)+2*(STEP),STEP)
+#define STEP8(START,STEP) STEP4(START,STEP),STEP4((START)+4*(STEP),STEP)
+#define STEP16(START,STEP) STEP8(START,STEP),STEP8((START)+8*(STEP),STEP)
+#define STEP32(START,STEP) STEP16(START,STEP),STEP16((START)+16*(STEP),STEP)
+
+/* these macros are used for declaring gfx_decode_entry_entry info arrays. */
+#define GFXDECODE_EXTERN( name ) extern const gfx_decode_entry gfxdecodeinfo_##name[]
+#define GFXDECODE_START( name ) const gfx_decode_entry gfxdecodeinfo_##name[] = {
+#define GFXDECODE_ENTRY(region,offset,layout,start,colors) { region, offset, &layout, start, colors, 0, 0 },
+#define GFXDECODE_SCALE(region,offset,layout,start,colors,xscale,yscale) { region, offset, &layout, start, colors, xscale, yscale },
+#define GFXDECODE_END { -1 } };
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _gfx_layout gfx_layout;
+struct _gfx_layout
+{
+ UINT16 width; /* pixel width of each element */
+ UINT16 height; /* pixel height of each element */
+ UINT32 total; /* total number of elements, or RGN_FRAC() */
+ UINT16 planes; /* number of bitplanes */
+ UINT32 planeoffset[MAX_GFX_PLANES]; /* bit offset of each bitplane */
+ UINT32 xoffset[MAX_GFX_SIZE]; /* bit offset of each horizontal pixel */
+ UINT32 yoffset[MAX_GFX_SIZE]; /* bit offset of each vertical pixel */
+ UINT32 charincrement; /* distance between two consecutive elements (in bits) */
+ const UINT32 * extxoffs; /* extended X offset array for really big layouts */
+ const UINT32 * extyoffs; /* extended Y offset array for really big layouts */
+};
+
+
+/* In mamecore.h: typedef struct _gfx_element gfx_element; */
+struct _gfx_element
+{
+ UINT16 width; /* pixel width of each element */
+ UINT16 height; /* pixel height of each element */
+ UINT8 flags; /* one of the GFX_ELEMENT_* flags above */
+ UINT32 total_elements; /* total number of decoded elements */
+
+ UINT32 color_base; /* base color for rendering */
+ UINT16 color_depth; /* number of colors each pixel can represent */
+ UINT16 color_granularity; /* number of colors for each color code */
+ UINT32 total_colors; /* number of color codes */
+
+ UINT32 * pen_usage; /* bitmask of pens that are used (pens 0-31 only) */
+
+ UINT8 * gfxdata; /* pixel data, 8bpp or 4bpp (if GFX_ELEMENT_PACKED) */
+ UINT32 line_modulo; /* bytes between each row of data */
+ UINT32 char_modulo; /* bytes between each element */
+ gfx_layout layout; /* copy of the original layout */
+};
+
+
+typedef struct _gfx_decode_entry gfx_decode_entry;
+struct _gfx_decode_entry
+{
+ int memory_region; /* memory region where the data resides; -1 marks the end of array */
+ UINT32 start; /* offset of beginning of data to decode */
+ const gfx_layout *gfxlayout; /* pointer to gfx_layout describing the layout */
+ UINT16 color_codes_start; /* offset in the color lookup table where color codes start */
+ UINT16 total_color_codes; /* total number of color codes */
+ UINT8 xscale; /* optional horizontal scaling factor; 0 means 1x */
+ UINT8 yscale; /* optional vertical scaling factor; 0 means 1x */
+};
+
+
+typedef struct _alpha_cache alpha_cache;
+struct _alpha_cache
+{
+ int alphas;
+ int alphad;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* drawing mode case TRANSPARENCY_ALPHARANGE */
+extern UINT8 gfx_alpharange_table[256];
+
+/* drawing mode case TRANSPARENCY_PEN_TABLE */
+extern UINT8 gfx_drawmode_table[256];
+
+/* By default, when drawing sprites with pdrawgfx, shadows affect the sprites below them. */
+/* Set this flag to 1 to make shadows only affect the background, leaving sprites at full brightness. */
+extern int pdrawgfx_shadow_lowpri;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void drawgfx_init(running_machine *machine);
+
+
+void decodechar(gfx_element *gfx,int num,const unsigned char *src,const gfx_layout *gl);
+gfx_element *allocgfx(const gfx_layout *gl);
+void decodegfx(gfx_element *gfx, const UINT8 *src, UINT32 first, UINT32 count);
+void freegfx(gfx_element *gfx);
+
+
+void drawgfx(mame_bitmap *dest,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color);
+void pdrawgfx(mame_bitmap *dest,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,
+ UINT32 priority_mask);
+void mdrawgfx(mame_bitmap *dest,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,
+ UINT32 priority_mask);
+
+
+void drawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,int scalex,int scaley);
+void pdrawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,int scalex,int scaley,
+ UINT32 priority_mask);
+void mdrawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,int scalex,int scaley,
+ UINT32 priority_mask);
+
+
+void draw_scanline8(mame_bitmap *bitmap,int x,int y,int length,const UINT8 *src,const pen_t *pens,int transparent_pen);
+void draw_scanline16(mame_bitmap *bitmap,int x,int y,int length,const UINT16 *src,const pen_t *pens,int transparent_pen);
+void pdraw_scanline8(mame_bitmap *bitmap,int x,int y,int length,const UINT8 *src,const pen_t *pens,int transparent_pen,int pri);
+void pdraw_scanline16(mame_bitmap *bitmap,int x,int y,int length,const UINT16 *src,const pen_t *pens,int transparent_pen,int pri);
+void extract_scanline8(mame_bitmap *bitmap,int x,int y,int length,UINT8 *dst);
+void extract_scanline16(mame_bitmap *bitmap,int x,int y,int length,UINT16 *dst);
+
+
+void copybitmap(mame_bitmap *dest,mame_bitmap *src,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color);
+void copybitmap_remap(mame_bitmap *dest,mame_bitmap *src,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color);
+void copyscrollbitmap(mame_bitmap *dest,mame_bitmap *src,
+ int rows,const int *rowscroll,int cols,const int *colscroll,
+ const rectangle *clip,int transparency,int transparent_color);
+void copyscrollbitmap_remap(mame_bitmap *dest,mame_bitmap *src,
+ int rows,const int *rowscroll,int cols,const int *colscroll,
+ const rectangle *clip,int transparency,int transparent_color);
+
+/*
+ Copy a bitmap applying rotation, zooming, and arbitrary distortion.
+ This function works in a way that mimics some real hardware like the Konami
+ 051316, so it requires little or no further processing on the caller side.
+
+ Two 16.16 fixed point counters are used to keep track of the position on
+ the source bitmap. startx and starty are the initial values of those counters,
+ indicating the source pixel that will be drawn at coordinates (0,0) in the
+ destination bitmap. The destination bitmap is scanned left to right, top to
+ bottom; every time the cursor moves one pixel to the right, incxx is added
+ to startx and incxy is added to starty. Every time the cursor moves to the
+ next line, incyx is added to startx and incyy is added to startyy.
+
+ What this means is that if incxy and incyx are both 0, the bitmap will be
+ copied with only zoom and no rotation. If e.g. incxx and incyy are both 0x8000,
+ the source bitmap will be doubled.
+
+ Rotation is performed this way:
+ incxx = 0x10000 * cos(theta)
+ incxy = 0x10000 * -sin(theta)
+ incyx = 0x10000 * sin(theta)
+ incyy = 0x10000 * cos(theta)
+ this will perform a rotation around (0,0), you'll have to adjust startx and
+ starty to move the center of rotation elsewhere.
+
+ Optionally the bitmap can be tiled across the screen instead of doing a single
+ copy. This is obtained by setting the wraparound parameter to true.
+ */
+void copyrozbitmap(mame_bitmap *dest,mame_bitmap *src,
+ UINT32 startx,UINT32 starty,int incxx,int incxy,int incyx,int incyy,int wraparound,
+ const rectangle *clip,int transparency,int transparent_color,UINT32 priority);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/* Alpha blending functions */
+INLINE void alpha_set_level(int level)
+{
+ extern struct _alpha_cache drawgfx_alpha_cache;
+ assert(level >= 0 && level <= 256);
+ drawgfx_alpha_cache.alphas = level;
+ drawgfx_alpha_cache.alphad = 256 - level;
+}
+
+
+INLINE UINT32 alpha_blend16(UINT32 d, UINT32 s)
+{
+ extern struct _alpha_cache drawgfx_alpha_cache;
+ return ((((s & 0x001f) * drawgfx_alpha_cache.alphas + (d & 0x001f) * drawgfx_alpha_cache.alphad) >> 8)) |
+ ((((s & 0x03e0) * drawgfx_alpha_cache.alphas + (d & 0x03e0) * drawgfx_alpha_cache.alphad) >> 8) & 0x03e0) |
+ ((((s & 0x7c00) * drawgfx_alpha_cache.alphas + (d & 0x7c00) * drawgfx_alpha_cache.alphad) >> 8) & 0x7c00);
+}
+
+
+INLINE UINT32 alpha_blend32(UINT32 d, UINT32 s)
+{
+ extern struct _alpha_cache drawgfx_alpha_cache;
+ return ((((s & 0x0000ff) * drawgfx_alpha_cache.alphas + (d & 0x0000ff) * drawgfx_alpha_cache.alphad) >> 8)) |
+ ((((s & 0x00ff00) * drawgfx_alpha_cache.alphas + (d & 0x00ff00) * drawgfx_alpha_cache.alphad) >> 8) & 0x00ff00) |
+ ((((s & 0xff0000) * drawgfx_alpha_cache.alphas + (d & 0xff0000) * drawgfx_alpha_cache.alphad) >> 8) & 0xff0000);
+}
+
+
+INLINE UINT32 alpha_blend_r16(UINT32 d, UINT32 s, UINT8 level)
+{
+ int alphad = 256 - level;
+ return ((((s & 0x001f) * level + (d & 0x001f) * alphad) >> 8)) |
+ ((((s & 0x03e0) * level + (d & 0x03e0) * alphad) >> 8) & 0x03e0) |
+ ((((s & 0x7c00) * level + (d & 0x7c00) * alphad) >> 8) & 0x7c00);
+}
+
+
+INLINE UINT32 alpha_blend_r32( UINT32 d, UINT32 s, UINT8 level )
+{
+ int alphad = 256 - level;
+ return ((((s & 0x0000ff) * level + (d & 0x0000ff) * alphad) >> 8)) |
+ ((((s & 0x00ff00) * level + (d & 0x00ff00) * alphad) >> 8) & 0x00ff00) |
+ ((((s & 0xff0000) * level + (d & 0xff0000) * alphad) >> 8) & 0xff0000);
+}
+
+
+#endif /* __DRAWGFX_H__ */
diff --git a/src/emu/driver.c b/src/emu/driver.c
new file mode 100644
index 00000000000..d527ed766b9
--- /dev/null
+++ b/src/emu/driver.c
@@ -0,0 +1,520 @@
+/***************************************************************************
+
+ driver.c
+
+ Driver construction helpers.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define DRIVER_LRU_SIZE 10
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static int driver_lru[DRIVER_LRU_SIZE];
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int penalty_compare(const char *source, const char *target);
+
+
+
+/***************************************************************************
+ MISCELLANEOUS BITS & PIECES
+***************************************************************************/
+
+/*-------------------------------------------------
+ expand_machine_driver - construct a machine
+ driver from the macroized state
+-------------------------------------------------*/
+
+void expand_machine_driver(void (*constructor)(machine_config *), machine_config *output)
+{
+ /* initialize the tag on the first screen */
+ memset(output, 0, sizeof(*output));
+ output->watchdog_time = attotime_zero;
+
+ /* keeping this function allows us to pre-init the driver before constructing it */
+ (*constructor)(output);
+
+ /* if no screen tagged, tag screen 0 as main */
+ if (output->screen[0].tag == NULL && output->screen[0].defstate.format != BITMAP_FORMAT_INVALID)
+ output->screen[0].tag = "main";
+
+ /* if no screens, set a dummy refresh for the main screen */
+ if (output->screen[0].tag == NULL)
+ output->screen[0].defstate.refresh = HZ_TO_ATTOSECONDS(60);
+}
+
+
+/*-------------------------------------------------
+ driver_add_cpu - add a CPU during machine
+ driver expansion
+-------------------------------------------------*/
+
+cpu_config *driver_add_cpu(machine_config *machine, const char *tag, cpu_type type, int cpuclock)
+{
+ int cpunum;
+
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ if (machine->cpu[cpunum].type == CPU_DUMMY)
+ {
+ machine->cpu[cpunum].tag = tag;
+ machine->cpu[cpunum].type = type;
+ machine->cpu[cpunum].clock = cpuclock;
+ return &machine->cpu[cpunum];
+ }
+
+ fatalerror("Out of CPU's!\n");
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ driver_find_cpu - find a tagged CPU during
+ machine driver expansion
+-------------------------------------------------*/
+
+cpu_config *driver_find_cpu(machine_config *machine, const char *tag)
+{
+ int cpunum;
+
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ if (machine->cpu[cpunum].tag && strcmp(machine->cpu[cpunum].tag, tag) == 0)
+ return &machine->cpu[cpunum];
+
+ fatalerror("Can't find CPU '%s'!\n", tag);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ driver_remove_cpu - remove a tagged CPU
+ during machine driver expansion
+-------------------------------------------------*/
+
+void driver_remove_cpu(machine_config *machine, const char *tag)
+{
+ int cpunum;
+
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ if (machine->cpu[cpunum].tag && strcmp(machine->cpu[cpunum].tag, tag) == 0)
+ {
+ memmove(&machine->cpu[cpunum], &machine->cpu[cpunum + 1], sizeof(machine->cpu[0]) * (MAX_CPU - cpunum - 1));
+ memset(&machine->cpu[MAX_CPU - 1], 0, sizeof(machine->cpu[0]));
+ return;
+ }
+
+ fatalerror("Can't find CPU '%s'!\n", tag);
+}
+
+
+/*-------------------------------------------------
+ driver_add_speaker - add a speaker during
+ machine driver expansion
+-------------------------------------------------*/
+
+speaker_config *driver_add_speaker(machine_config *machine, const char *tag, float x, float y, float z)
+{
+ int speakernum;
+
+ for (speakernum = 0; speakernum < MAX_SPEAKER; speakernum++)
+ if (machine->speaker[speakernum].tag == NULL)
+ {
+ machine->speaker[speakernum].tag = tag;
+ machine->speaker[speakernum].x = x;
+ machine->speaker[speakernum].y = y;
+ machine->speaker[speakernum].z = z;
+ return &machine->speaker[speakernum];
+ }
+
+ fatalerror("Out of speakers!\n");
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ driver_find_speaker - find a tagged speaker
+ system during machine driver expansion
+-------------------------------------------------*/
+
+speaker_config *driver_find_speaker(machine_config *machine, const char *tag)
+{
+ int speakernum;
+
+ for (speakernum = 0; speakernum < MAX_SPEAKER; speakernum++)
+ if (machine->speaker[speakernum].tag && strcmp(machine->speaker[speakernum].tag, tag) == 0)
+ return &machine->speaker[speakernum];
+
+ fatalerror("Can't find speaker '%s'!\n", tag);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ driver_remove_speaker - remove a tagged speaker
+ system during machine driver expansion
+-------------------------------------------------*/
+
+void driver_remove_speaker(machine_config *machine, const char *tag)
+{
+ int speakernum;
+
+ for (speakernum = 0; speakernum < MAX_SPEAKER; speakernum++)
+ if (machine->speaker[speakernum].tag && strcmp(machine->speaker[speakernum].tag, tag) == 0)
+ {
+ memmove(&machine->speaker[speakernum], &machine->speaker[speakernum + 1], sizeof(machine->speaker[0]) * (MAX_SPEAKER - speakernum - 1));
+ memset(&machine->speaker[MAX_SPEAKER - 1], 0, sizeof(machine->speaker[0]));
+ return;
+ }
+
+ fatalerror("Can't find speaker '%s'!\n", tag);
+}
+
+
+/*-------------------------------------------------
+ driver_add_sound - add a sound system during
+ machine driver expansion
+-------------------------------------------------*/
+
+sound_config *driver_add_sound(machine_config *machine, const char *tag, sound_type type, int clock)
+{
+ int soundnum;
+
+ for (soundnum = 0; soundnum < MAX_SOUND; soundnum++)
+ if (machine->sound[soundnum].type == SOUND_DUMMY)
+ {
+ machine->sound[soundnum].tag = tag;
+ machine->sound[soundnum].type = type;
+ machine->sound[soundnum].clock = clock;
+ machine->sound[soundnum].config = NULL;
+ machine->sound[soundnum].routes = 0;
+ return &machine->sound[soundnum];
+ }
+
+ fatalerror("Out of sounds!\n");
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ driver_find_sound - find a tagged sound
+ system during machine driver expansion
+-------------------------------------------------*/
+
+sound_config *driver_find_sound(machine_config *machine, const char *tag)
+{
+ int soundnum;
+
+ for (soundnum = 0; soundnum < MAX_SOUND; soundnum++)
+ if (machine->sound[soundnum].tag && strcmp(machine->sound[soundnum].tag, tag) == 0)
+ return &machine->sound[soundnum];
+
+ fatalerror("Can't find sound '%s'!\n", tag);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ driver_remove_sound - remove a tagged sound
+ system during machine driver expansion
+-------------------------------------------------*/
+
+void driver_remove_sound(machine_config *machine, const char *tag)
+{
+ int soundnum;
+
+ for (soundnum = 0; soundnum < MAX_SOUND; soundnum++)
+ if (machine->sound[soundnum].tag && strcmp(machine->sound[soundnum].tag, tag) == 0)
+ {
+ memmove(&machine->sound[soundnum], &machine->sound[soundnum + 1], sizeof(machine->sound[0]) * (MAX_SOUND - soundnum - 1));
+ memset(&machine->sound[MAX_SOUND - 1], 0, sizeof(machine->sound[0]));
+ return;
+ }
+
+ fatalerror("Can't find sound '%s'!\n", tag);
+}
+
+
+/*-------------------------------------------------
+ driver_add_screen - add a screen during
+ machine driver expansion
+-------------------------------------------------*/
+
+screen_config *driver_add_screen(machine_config *machine, const char *tag, int palbase)
+{
+ int screennum;
+
+ for (screennum = 0; screennum < MAX_SCREENS; screennum++)
+ if (machine->screen[screennum].tag == NULL)
+ {
+ machine->screen[screennum].tag = tag;
+ machine->screen[screennum].palette_base = palbase;
+ return &machine->screen[screennum];
+ }
+
+ fatalerror("Out of screens!\n");
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ driver_find_screen - find a tagged screen
+ during machine driver expansion
+-------------------------------------------------*/
+
+screen_config *driver_find_screen(machine_config *machine, const char *tag)
+{
+ int screennum;
+
+ for (screennum = 0; screennum < MAX_SCREENS; screennum++)
+ if (machine->screen[screennum].tag && strcmp(machine->screen[screennum].tag, tag) == 0)
+ return &machine->screen[screennum];
+
+ fatalerror("Can't find screen '%s'!\n", tag);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ driver_remove_screen - remove a tagged screen
+ during machine driver expansion
+-------------------------------------------------*/
+
+void driver_remove_screen(machine_config *machine, const char *tag)
+{
+ int screennum;
+
+ for (screennum = 0; screennum < MAX_SCREENS; screennum++)
+ if (machine->screen[screennum].tag && strcmp(machine->screen[screennum].tag, tag) == 0)
+ {
+ memmove(&machine->screen[screennum], &machine->screen[screennum + 1], sizeof(machine->screen[0]) * (MAX_SCREENS - screennum - 1));
+ memset(&machine->screen[MAX_SCREENS - 1], 0, sizeof(machine->screen[0]));
+ return;
+ }
+
+ fatalerror("Can't find screen '%s'!\n", tag);
+}
+
+
+/*-------------------------------------------------
+ driver_get_name - return a pointer to a
+ driver given its name
+-------------------------------------------------*/
+
+const game_driver *driver_get_name(const char *name)
+{
+ int lurnum, drvnum;
+
+ /* scan the LRU list first */
+ for (lurnum = 0; lurnum < DRIVER_LRU_SIZE; lurnum++)
+ if (mame_stricmp(drivers[driver_lru[lurnum]]->name, name) == 0)
+ {
+ /* if not first, swap with the head */
+ if (lurnum != 0)
+ {
+ int temp = driver_lru[0];
+ driver_lru[0] = driver_lru[lurnum];
+ driver_lru[lurnum] = temp;
+ }
+ return drivers[driver_lru[0]];
+ }
+
+ /* scan for a match in the drivers -- slow! */
+ for (drvnum = 0; drivers[drvnum] != NULL; drvnum++)
+ if (mame_stricmp(drivers[drvnum]->name, name) == 0)
+ {
+ memmove((void *)&driver_lru[1], (void *)&driver_lru[0], sizeof(driver_lru[0]) * (DRIVER_LRU_SIZE - 1));
+ driver_lru[0] = drvnum;
+ return drivers[drvnum];
+ }
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ driver_get_clone - return a pointer to the
+ clone of a game driver.
+-------------------------------------------------*/
+
+const game_driver *driver_get_clone(const game_driver *driver)
+{
+ /* if no clone, easy out */
+ if (driver->parent == NULL || (driver->parent[0] == '0' && driver->parent[1] == 0))
+ return NULL;
+
+ /* convert the name to a game_driver */
+ return driver_get_name(driver->parent);
+}
+
+
+/*-------------------------------------------------
+ driver_list_get_approx_matches - find the best
+ n matches to a driver name.
+-------------------------------------------------*/
+
+void driver_list_get_approx_matches(const game_driver * const driverlist[], const char *name, int matches, const game_driver **list)
+{
+#undef rand
+
+ int matchnum, drvnum;
+ int *penalty;
+
+ /* if no name, pick random entries */
+ if (name == NULL || name[0] == 0)
+ {
+ const game_driver **templist;
+ int driver_count;
+ int shufnum;
+
+ /* allocate a temporary list */
+ templist = malloc_or_die(driver_list_get_count(driverlist) * sizeof(*templist));
+
+ /* build up a list of valid entries */
+ for (drvnum = driver_count = 0; driverlist[drvnum] != NULL; drvnum++)
+ if ((driverlist[drvnum]->flags & GAME_NO_STANDALONE) == 0)
+ templist[driver_count++] = driverlist[drvnum];
+
+ /* seed the RNG first */
+ srand(osd_ticks());
+
+ /* shuffle */
+ for (shufnum = 0; shufnum < 4 * driver_count; shufnum++)
+ {
+ int item1 = rand() % driver_count;
+ int item2 = rand() % driver_count;
+ const game_driver *temp;
+
+ temp = templist[item1];
+ templist[item1] = templist[item2];
+ templist[item2] = temp;
+ }
+
+ /* copy out the first few entries */
+ for (matchnum = 0; matchnum < matches; matchnum++)
+ list[matchnum] = templist[matchnum % driver_count];
+
+ free((void *)templist);
+ return;
+ }
+
+ /* allocate some temp memory */
+ penalty = malloc_or_die(matches * sizeof(*penalty));
+
+ /* initialize everyone's states */
+ for (matchnum = 0; matchnum < matches; matchnum++)
+ {
+ penalty[matchnum] = 9999;
+ list[matchnum] = NULL;
+ }
+
+ /* scan the entire drivers array */
+ for (drvnum = 0; driverlist[drvnum] != NULL; drvnum++)
+ {
+ int curpenalty, tmp;
+
+ /* skip things that can't run */
+ if ((driverlist[drvnum]->flags & GAME_NO_STANDALONE) != 0)
+ continue;
+
+ /* pick the best match between driver name and description */
+ curpenalty = penalty_compare(name, driverlist[drvnum]->description);
+ tmp = penalty_compare(name, driverlist[drvnum]->name);
+ curpenalty = MIN(curpenalty, tmp);
+
+ /* insert into the sorted table of matches */
+ for (matchnum = matches - 1; matchnum >= 0; matchnum--)
+ {
+ /* stop if we're worse than the current entry */
+ if (curpenalty >= penalty[matchnum])
+ break;
+
+ /* as lng as this isn't the last entry, bump this one down */
+ if (matchnum < matches - 1)
+ {
+ penalty[matchnum + 1] = penalty[matchnum];
+ list[matchnum + 1] = list[matchnum];
+ }
+ list[matchnum] = driverlist[drvnum];
+ penalty[matchnum] = curpenalty;
+ }
+ }
+
+ /* free our temp memory */
+ free(penalty);
+}
+
+
+/*-------------------------------------------------
+ penalty_compare - compare two strings for
+ closeness and assign a score.
+-------------------------------------------------*/
+
+static int penalty_compare(const char *source, const char *target)
+{
+ int gaps = 1;
+ int last = TRUE;
+
+ /* scan the strings */
+ for ( ; *source && *target; target++)
+ {
+ /* do a case insensitive match */
+ int match = (tolower(*source) == tolower(*target));
+
+ /* if we matched, advance the source */
+ if (match)
+ source++;
+
+ /* if the match state changed, count gaps */
+ if (match != last)
+ {
+ last = match;
+ if (!match)
+ gaps++;
+ }
+ }
+
+ /* penalty if short string does not completely fit in */
+ for ( ; *source; source++)
+ gaps++;
+
+ /* if we matched perfectly, gaps == 0 */
+ if (gaps == 1 && *source == 0 && *target == 0)
+ gaps = 0;
+
+ return gaps;
+}
+
+
+/*-------------------------------------------------
+ driver_list_get_count - returns the amount of
+ drivers
+-------------------------------------------------*/
+
+int driver_list_get_count(const game_driver * const driverlist[])
+{
+ int count;
+
+ for (count = 0; driverlist[count] != NULL; count++) ;
+ return count;
+}
diff --git a/src/emu/driver.h b/src/emu/driver.h
new file mode 100644
index 00000000000..5833b4a1455
--- /dev/null
+++ b/src/emu/driver.h
@@ -0,0 +1,587 @@
+/***************************************************************************
+
+ driver.h
+
+ Include this with all MAME files. Includes all the core system pieces.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __DRIVER_H__
+#define __DRIVER_H__
+
+
+/***************************************************************************
+ MACROS (must be *before* the includes below)
+***************************************************************************/
+
+#define DRIVER_INIT(name) void driver_init_##name(running_machine *machine)
+
+#define NVRAM_HANDLER(name) void nvram_handler_##name(running_machine *machine, mame_file *file, int read_or_write)
+
+#define MEMCARD_HANDLER(name) void memcard_handler_##name(running_machine *machine, mame_file *file, int action)
+
+#define MACHINE_START(name) void machine_start_##name(running_machine *machine)
+#define MACHINE_RESET(name) void machine_reset_##name(running_machine *machine)
+
+#define SOUND_START(name) void sound_start_##name(running_machine *machine)
+#define SOUND_RESET(name) void sound_reset_##name(running_machine *machine)
+
+#define VIDEO_START(name) void video_start_##name(running_machine *machine)
+#define VIDEO_RESET(name) void video_reset_##name(running_machine *machine)
+
+#define PALETTE_INIT(name) void palette_init_##name(running_machine *machine, UINT16 *colortable, const UINT8 *color_prom)
+#define VIDEO_EOF(name) void video_eof_##name(running_machine *machine)
+#define VIDEO_UPDATE(name) UINT32 video_update_##name(running_machine *machine, int screen, mame_bitmap *bitmap, const rectangle *cliprect)
+
+/* NULL versions */
+#define driver_init_NULL NULL
+#define nvram_handler_NULL NULL
+#define memcard_handler_NULL NULL
+#define machine_start_NULL NULL
+#define machine_reset_NULL NULL
+#define sound_start_NULL NULL
+#define sound_reset_NULL NULL
+#define video_start_NULL NULL
+#define video_reset_NULL NULL
+#define palette_init_NULL NULL
+#define video_eof_NULL NULL
+#define video_update_NULL NULL
+
+
+
+/***************************************************************************
+ INCLUDES
+***************************************************************************/
+
+#include "cpuintrf.h"
+#include "sndintrf.h"
+#include "fileio.h"
+#include "drawgfx.h"
+#include "emupal.h"
+#include "sound.h"
+#include "input.h"
+#include "inptport.h"
+#include "output.h"
+#include "tilemap.h"
+#include "romload.h"
+#include "machine/generic.h"
+#include "audio/generic.h"
+#include "video/generic.h"
+
+#ifdef MESS
+#include "messdrv.h"
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* maxima */
+#define MAX_DRIVER_NAME_CHARS 8
+#define MAX_SPEAKER 4
+
+/* watchdog constants */
+#define DEFAULT_60HZ_3S_VBLANK_WATCHDOG 180
+#define DEFAULT_30HZ_3S_VBLANK_WATCHDOG 90
+
+
+
+/* ----- VBLANK constants ----- */
+
+/*
+ VBLANK is the period when the video beam is outside of the visible area
+ and returns from the bottom-right to the top-left of the screen to
+ prepare for a new video frame. The duration of VBLANK is an important
+ factor in how the game renders itself. In many cases, the game does
+ video-related operations during this time, such as swapping buffers or
+ updating sprite lists.
+
+ Below are some predefined, TOTALLY ARBITRARY values for vblank_duration,
+ which should be OK for most cases. I have NO IDEA how accurate they are
+ compared to the real hardware, they could be completely wrong.
+*/
+
+/* The default is to have no VBLANK timing -- this is historical, and a bad idea */
+#define DEFAULT_60HZ_VBLANK_DURATION ATTOSECONDS_IN_USEC(0)
+#define DEFAULT_30HZ_VBLANK_DURATION ATTOSECONDS_IN_USEC(0)
+
+/* If you use IPT_VBLANK, you need a duration different from 0 */
+#define DEFAULT_REAL_60HZ_VBLANK_DURATION ATTOSECONDS_IN_USEC(2500)
+#define DEFAULT_REAL_30HZ_VBLANK_DURATION ATTOSECONDS_IN_USEC(2500)
+
+
+
+/* ----- flags for video_attributes ----- */
+
+/* is the video hardware raser or vector base? */
+#define VIDEO_TYPE_RASTER 0x0000
+#define VIDEO_TYPE_VECTOR 0x0001
+
+/* should VIDEO_UPDATE by called at the start of VBLANK or at the end? */
+#define VIDEO_UPDATE_BEFORE_VBLANK 0x0000
+#define VIDEO_UPDATE_AFTER_VBLANK 0x0002
+
+/* indicates VIDEO_UPDATE will add container bits its */
+#define VIDEO_SELF_RENDER 0x0004
+
+/* automatically extend the palette creating a darker copy for shadows */
+#define VIDEO_HAS_SHADOWS 0x0010
+
+/* automatically extend the palette creating a brighter copy for highlights */
+#define VIDEO_HAS_HIGHLIGHTS 0x0020
+
+/* Mish 181099: See comments in video/generic.c for details */
+#define VIDEO_BUFFERS_SPRITERAM 0x0040
+
+/* force VIDEO_UPDATE to be called even for skipped frames */
+#define VIDEO_ALWAYS_UPDATE 0x0080
+
+
+
+/* ----- flags for game drivers ----- */
+
+#define ORIENTATION_MASK 0x0007
+#define GAME_NOT_WORKING 0x0008
+#define GAME_UNEMULATED_PROTECTION 0x0010 /* game's protection not fully emulated */
+#define GAME_WRONG_COLORS 0x0020 /* colors are totally wrong */
+#define GAME_IMPERFECT_COLORS 0x0040 /* colors are not 100% accurate, but close */
+#define GAME_IMPERFECT_GRAPHICS 0x0080 /* graphics are wrong/incomplete */
+#define GAME_NO_COCKTAIL 0x0100 /* screen flip support is missing */
+#define GAME_NO_SOUND 0x0200 /* sound is missing */
+#define GAME_IMPERFECT_SOUND 0x0400 /* sound is known to be wrong */
+#define GAME_SUPPORTS_SAVE 0x0800 /* game supports save states */
+#define GAME_IS_BIOS_ROOT 0x1000 /* this driver entry is a BIOS root */
+#define GAME_NO_STANDALONE 0x2000 /* this driver cannot stand alone */
+
+#ifdef MESS
+#define GAME_COMPUTER 0x8000 /* Driver is a computer (needs full keyboard) */
+#define GAME_COMPUTER_MODIFIED 0x0800 /* Official? Hack */
+#endif
+
+
+
+/* ----- flags to return from video_update ----- */
+#define UPDATE_HAS_NOT_CHANGED 0x0001 /* the video has not changed */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* In mamecore.h: typedef struct _machine_config machine_config; */
+struct _machine_config
+{
+ UINT32 driver_data_size; /* amount of memory needed for driver_data */
+
+ cpu_config cpu[MAX_CPU]; /* array of CPUs in the system */
+ UINT32 cpu_slices_per_frame; /* number of times to interleave execution per frame */
+ INT32 watchdog_vblank_count; /* number of VBLANKs until the watchdog kills us */
+ attotime watchdog_time; /* length of time until the watchdog kills us */
+
+ void (*machine_start)(running_machine *machine); /* one-time machine start callback */
+ void (*machine_reset)(running_machine *machine); /* machine reset callback */
+
+ void (*nvram_handler)(running_machine *machine, mame_file *file, int read_or_write); /* NVRAM save/load callback */
+ void (*memcard_handler)(running_machine *machine, mame_file *file, int action); /* memory card save/load callback */
+
+ UINT32 video_attributes; /* flags describing the video system */
+ const gfx_decode_entry *gfxdecodeinfo; /* pointer to array of graphics decoding information */
+ UINT32 total_colors; /* total number of colors in the palette */
+ UINT32 color_table_len; /* length of the color indirection table */
+ const char * default_layout; /* default layout for this machine */
+ screen_config screen[MAX_SCREENS]; /* total number of screens */
+
+ void (*init_palette)(running_machine *machine, UINT16 *colortable, const UINT8 *color_prom); /* one-time palette init callback */
+ void (*video_start)(running_machine *machine); /* one-time video start callback */
+ void (*video_reset)(running_machine *machine); /* video reset callback */
+ void (*video_eof)(running_machine *machine); /* end-of-frame video callback */
+ UINT32 (*video_update)(running_machine *machine, int screen, mame_bitmap *bitmap, const rectangle *cliprect); /* video update callback */
+
+ sound_config sound[MAX_SOUND]; /* array of sound chips in the system */
+ speaker_config speaker[MAX_SPEAKER]; /* array of speakers in the system */
+
+ void (*sound_start)(running_machine *machine); /* one-time sound start callback */
+ void (*sound_reset)(running_machine *machine); /* sound reset callback */
+};
+
+
+/* In mamecore.h: typedef struct _game_driver game_driver; */
+struct _game_driver
+{
+ const char * source_file; /* set this to __FILE__ */
+ const char * parent; /* if this is a clone, the name of the parent */
+ const char * name; /* short (8-character) name of the game */
+ const char * description; /* full name of the game */
+ const char * year; /* year the game was released */
+ const char * manufacturer; /* manufacturer of the game */
+ void (*drv)(machine_config *); /* machine driver constructor */
+ const input_port_token *ipt; /* pointer to array of input port tokens */
+ void (*driver_init)(running_machine *machine); /* DRIVER_INIT callback */
+ const rom_entry * rom; /* pointer to list of ROMs for the game */
+
+#ifdef MESS
+ void (*sysconfig_ctor)(struct SystemConfigurationParamBlock *cfg);
+ const char * compatible_with;
+#endif
+
+ UINT32 flags; /* orientation and other flags; see defines below */
+ const char * default_layout; /* default internally defined layout */
+};
+
+
+
+/***************************************************************************
+ MACROS FOR BUILDING MACHINE DRIVERS
+***************************************************************************/
+
+/* use this to declare external references to a machine driver */
+#define MACHINE_DRIVER_EXTERN(game) \
+ void construct_##game(machine_config *machine) \
+
+
+/* start/end tags for the machine driver */
+#define MACHINE_DRIVER_START(game) \
+ void construct_##game(machine_config *machine) \
+ { \
+ cpu_config *cpu = NULL; \
+ sound_config *sound = NULL; \
+ screen_config *screen = &machine->screen[0]; \
+ (void)cpu; \
+ (void)sound; \
+ (void)screen; \
+
+#define MACHINE_DRIVER_END \
+ } \
+
+
+/* importing data from other machine drivers */
+#define MDRV_IMPORT_FROM(game) \
+ construct_##game(machine); \
+
+
+/* add/modify/remove/replace CPUs */
+#define MDRV_CPU_ADD_TAG(tag, type, clock) \
+ cpu = driver_add_cpu(machine, (tag), CPU_##type, (clock)); \
+
+#define MDRV_CPU_ADD(type, clock) \
+ MDRV_CPU_ADD_TAG(NULL, type, clock) \
+
+#define MDRV_CPU_MODIFY(tag) \
+ cpu = driver_find_cpu(machine, tag); \
+
+#define MDRV_CPU_REMOVE(tag) \
+ driver_remove_cpu(machine, tag); \
+ cpu = NULL; \
+
+#define MDRV_CPU_REPLACE(tag, _type, _clock) \
+ cpu = driver_find_cpu(machine, tag); \
+ cpu->type = (CPU_##_type); \
+ cpu->clock = (_clock); \
+
+
+/* CPU parameters */
+#define MDRV_CPU_FLAGS(_flags) \
+ if (cpu) \
+ cpu->flags = (_flags); \
+
+#define MDRV_CPU_CONFIG(config) \
+ if (cpu) \
+ cpu->reset_param = &(config); \
+
+#define MDRV_CPU_PROGRAM_MAP(readmem, writemem) \
+ if (cpu) \
+ { \
+ cpu->construct_map[ADDRESS_SPACE_PROGRAM][0] = (construct_map_##readmem); \
+ cpu->construct_map[ADDRESS_SPACE_PROGRAM][1] = (construct_map_##writemem); \
+ } \
+
+#define MDRV_CPU_DATA_MAP(readmem, writemem) \
+ if (cpu) \
+ { \
+ cpu->construct_map[ADDRESS_SPACE_DATA][0] = (construct_map_##readmem); \
+ cpu->construct_map[ADDRESS_SPACE_DATA][1] = (construct_map_##writemem); \
+ } \
+
+#define MDRV_CPU_IO_MAP(readmem, writemem) \
+ if (cpu) \
+ { \
+ cpu->construct_map[ADDRESS_SPACE_IO][0] = (construct_map_##readmem); \
+ cpu->construct_map[ADDRESS_SPACE_IO][1] = (construct_map_##writemem); \
+ } \
+
+#define MDRV_CPU_VBLANK_INT(func, rate) \
+ if (cpu) \
+ { \
+ cpu->vblank_interrupt = func; \
+ cpu->vblank_interrupts_per_frame = (rate); \
+ } \
+
+#define MDRV_CPU_PERIODIC_INT(func, rate) \
+ if (cpu) \
+ { \
+ cpu->timed_interrupt = func; \
+ cpu->timed_interrupt_period = HZ_TO_ATTOSECONDS(rate); \
+ } \
+
+
+/* core parameters */
+#define MDRV_DRIVER_DATA(_struct) \
+ machine->driver_data_size = sizeof(_struct); \
+
+#define MDRV_INTERLEAVE(interleave) \
+ machine->cpu_slices_per_frame = (interleave); \
+
+#define MDRV_WATCHDOG_VBLANK_INIT(watch_count) \
+ machine->watchdog_vblank_count = (watch_count); \
+
+#define MDRV_WATCHDOG_TIME_INIT(time) \
+ machine->watchdog_time = (time); \
+
+
+/* core functions */
+#define MDRV_MACHINE_START(name) \
+ machine->machine_start = machine_start_##name; \
+
+#define MDRV_MACHINE_RESET(name) \
+ machine->machine_reset = machine_reset_##name; \
+
+#define MDRV_NVRAM_HANDLER(name) \
+ machine->nvram_handler = nvram_handler_##name; \
+
+#define MDRV_MEMCARD_HANDLER(name) \
+ machine->memcard_handler = memcard_handler_##name; \
+
+
+/* core video parameters */
+#define MDRV_VIDEO_ATTRIBUTES(flags) \
+ machine->video_attributes = (flags); \
+
+#define MDRV_GFXDECODE(gfx) \
+ machine->gfxdecodeinfo = (gfxdecodeinfo_##gfx); \
+
+#define MDRV_PALETTE_LENGTH(length) \
+ machine->total_colors = (length); \
+
+#define MDRV_COLORTABLE_LENGTH(length) \
+ machine->color_table_len = (length); \
+
+#define MDRV_DEFAULT_LAYOUT(layout) \
+ machine->default_layout = &(layout)[0]; \
+
+
+/* core video functions */
+#define MDRV_PALETTE_INIT(name) \
+ machine->init_palette = palette_init_##name; \
+
+#define MDRV_VIDEO_START(name) \
+ machine->video_start = video_start_##name; \
+
+#define MDRV_VIDEO_RESET(name) \
+ machine->video_reset = video_reset_##name; \
+
+#define MDRV_VIDEO_EOF(name) \
+ machine->video_eof = video_eof_##name; \
+
+#define MDRV_VIDEO_UPDATE(name) \
+ machine->video_update = video_update_##name; \
+
+
+/* add/remove screens */
+#define MDRV_SCREEN_ADD(tag, palbase) \
+ screen = driver_add_screen(machine, (tag), (palbase)); \
+
+#define MDRV_SCREEN_REMOVE(tag) \
+ driver_remove_screen(machine, tag); \
+
+#define MDRV_SCREEN_MODIFY(tag) \
+ screen = driver_find_screen(machine, tag); \
+
+#define MDRV_SCREEN_FORMAT(_format) \
+ screen->defstate.format = (_format); \
+
+#define MDRV_SCREEN_RAW_PARAMS(pixclock, htotal, hbend, hbstart, vtotal, vbend, vbstart) \
+ screen->defstate.refresh = HZ_TO_ATTOSECONDS(pixclock) * (htotal) * (vtotal); \
+ screen->defstate.vblank = (screen->defstate.refresh / (vtotal)) * ((vtotal) - ((vbstart) - (vbend))); \
+ screen->defstate.width = (htotal); \
+ screen->defstate.height = (vtotal); \
+ screen->defstate.visarea.min_x = (hbend); \
+ screen->defstate.visarea.max_x = (hbstart) - 1; \
+ screen->defstate.visarea.min_y = (vbend); \
+ screen->defstate.visarea.max_y = (vbstart) - 1; \
+
+#define MDRV_SCREEN_REFRESH_RATE(rate) \
+ screen->defstate.refresh = HZ_TO_ATTOSECONDS(rate); \
+
+#define MDRV_SCREEN_VBLANK_TIME(time) \
+ screen->defstate.vblank = time; \
+ screen->defstate.oldstyle_vblank_supplied = 1; \
+
+#define MDRV_SCREEN_SIZE(_width, _height) \
+ screen->defstate.width = (_width); \
+ screen->defstate.height = (_height); \
+
+#define MDRV_SCREEN_VISIBLE_AREA(minx, maxx, miny, maxy) \
+ screen->defstate.visarea.min_x = (minx); \
+ screen->defstate.visarea.max_x = (maxx); \
+ screen->defstate.visarea.min_y = (miny); \
+ screen->defstate.visarea.max_y = (maxy); \
+
+#define MDRV_SCREEN_DEFAULT_POSITION(_xscale, _xoffs, _yscale, _yoffs) \
+ screen->xoffset = (_xoffs); \
+ screen->xscale = (_xscale); \
+ screen->yoffset = (_yoffs); \
+ screen->yscale = (_yscale); \
+
+
+/* add/remove speakers */
+#define MDRV_SPEAKER_ADD(tag, x, y, z) \
+ driver_add_speaker(machine, (tag), (x), (y), (z)); \
+
+#define MDRV_SPEAKER_REMOVE(tag) \
+ driver_remove_speaker(machine, (tag)); \
+
+#define MDRV_SPEAKER_STANDARD_MONO(tag) \
+ MDRV_SPEAKER_ADD(tag, 0.0, 0.0, 1.0) \
+
+#define MDRV_SPEAKER_STANDARD_STEREO(tagl, tagr) \
+ MDRV_SPEAKER_ADD(tagl, -0.2, 0.0, 1.0) \
+ MDRV_SPEAKER_ADD(tagr, 0.2, 0.0, 1.0) \
+
+
+/* core sound functions */
+#define MDRV_SOUND_START(name) \
+ machine->sound_start = sound_start_##name; \
+
+#define MDRV_SOUND_RESET(name) \
+ machine->sound_reset = sound_reset_##name; \
+
+
+/* add/remove/replace sounds */
+#define MDRV_SOUND_ADD_TAG(tag, type, clock) \
+ sound = driver_add_sound(machine, (tag), SOUND_##type, (clock)); \
+
+#define MDRV_SOUND_ADD(type, clock) \
+ MDRV_SOUND_ADD_TAG(NULL, type, clock) \
+
+#define MDRV_SOUND_REMOVE(tag) \
+ driver_remove_sound(machine, tag); \
+
+#define MDRV_SOUND_MODIFY(tag) \
+ sound = driver_find_sound(machine, tag); \
+ sound->routes = 0; \
+
+#define MDRV_SOUND_CONFIG(_config) \
+ if (sound) \
+ sound->config = &(_config); \
+
+#define MDRV_SOUND_REPLACE(tag, _type, _clock) \
+ sound = driver_find_sound(machine, tag); \
+ if (sound) \
+ { \
+ sound->type = SOUND_##_type; \
+ sound->clock = (_clock); \
+ sound->config = NULL; \
+ sound->routes = 0; \
+ } \
+
+#define MDRV_SOUND_ROUTE(_output, _target, _gain) \
+ if (sound) \
+ { \
+ sound->route[sound->routes].output = (_output); \
+ sound->route[sound->routes].target = (_target); \
+ sound->route[sound->routes].gain = (_gain); \
+ sound->routes++; \
+ } \
+
+
+
+/***************************************************************************
+ MACROS FOR BUILDING GAME DRIVERS
+***************************************************************************/
+
+#define GAME(YEAR,NAME,PARENT,MACHINE,INPUT,INIT,MONITOR,COMPANY,FULLNAME,FLAGS) \
+game_driver driver_##NAME = \
+{ \
+ __FILE__, \
+ #PARENT, \
+ #NAME, \
+ FULLNAME, \
+ #YEAR, \
+ COMPANY, \
+ construct_##MACHINE, \
+ ipt_##INPUT, \
+ driver_init_##INIT, \
+ rom_##NAME, \
+ (MONITOR)|(FLAGS), \
+ NULL \
+};
+
+#define GAMEL(YEAR,NAME,PARENT,MACHINE,INPUT,INIT,MONITOR,COMPANY,FULLNAME,FLAGS,LAYOUT) \
+game_driver driver_##NAME = \
+{ \
+ __FILE__, \
+ #PARENT, \
+ #NAME, \
+ FULLNAME, \
+ #YEAR, \
+ COMPANY, \
+ construct_##MACHINE, \
+ ipt_##INPUT, \
+ driver_init_##INIT, \
+ rom_##NAME, \
+ (MONITOR)|(FLAGS), \
+ &LAYOUT[0] \
+};
+
+/* this allows to leave the INIT field empty in the GAME() macro call */
+#define driver_init_0 0
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+extern const game_driver * const drivers[];
+
+extern game_driver driver_empty;
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void expand_machine_driver(void (*constructor)(machine_config *), machine_config *output);
+
+cpu_config *driver_add_cpu(machine_config *machine, const char *tag, cpu_type type, int cpuclock);
+cpu_config *driver_find_cpu(machine_config *machine, const char *tag);
+void driver_remove_cpu(machine_config *machine, const char *tag);
+
+speaker_config *driver_add_speaker(machine_config *machine, const char *tag, float x, float y, float z);
+speaker_config *driver_find_speaker(machine_config *machine, const char *tag);
+void driver_remove_speaker(machine_config *machine, const char *tag);
+
+sound_config *driver_add_sound(machine_config *machine, const char *tag, sound_type type, int clock);
+sound_config *driver_find_sound(machine_config *machine, const char *tag);
+void driver_remove_sound(machine_config *machine, const char *tag);
+
+screen_config *driver_add_screen(machine_config *machine, const char *tag, int palbase);
+screen_config *driver_find_screen(machine_config *machine, const char *tag);
+void driver_remove_screen(machine_config *machine, const char *tag);
+
+const game_driver *driver_get_name(const char *name);
+const game_driver *driver_get_clone(const game_driver *driver);
+
+void driver_list_get_approx_matches(const game_driver * const driverlist[], const char *name, int matches, const game_driver **list);
+int driver_list_get_count(const game_driver * const driverlist[]);
+
+
+#endif /* __DRIVER_H__ */
diff --git a/src/emu/drivers/empty.c b/src/emu/drivers/empty.c
new file mode 100644
index 00000000000..037117ae722
--- /dev/null
+++ b/src/emu/drivers/empty.c
@@ -0,0 +1,81 @@
+/*************************************************************************
+
+ empty.c
+
+ Empty driver.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**************************************************************************/
+
+#include "driver.h"
+#include "uimenu.h"
+
+
+/*************************************
+ *
+ * Machine "start"
+ *
+ *************************************/
+
+static MACHINE_START( empty )
+{
+ /* force the UI to show the game select screen */
+ ui_menu_force_game_select();
+}
+
+
+
+/*************************************
+ *
+ * Machine drivers
+ *
+ *************************************/
+
+static MACHINE_DRIVER_START( empty )
+
+ MDRV_MACHINE_START(empty)
+
+ /* video hardware */
+ MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER)
+
+ MDRV_SCREEN_ADD("main", 0)
+ MDRV_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
+ MDRV_SCREEN_SIZE(640,480)
+ MDRV_SCREEN_VISIBLE_AREA(0,639, 0,479)
+ MDRV_SCREEN_REFRESH_RATE(30)
+MACHINE_DRIVER_END
+
+
+
+/*************************************
+ *
+ * Input ports
+ *
+ *************************************/
+
+static INPUT_PORTS_START( empty )
+INPUT_PORTS_END
+
+
+
+/*************************************
+ *
+ * ROM definitions
+ *
+ *************************************/
+
+ROM_START( empty )
+ ROM_REGION( 0x10, REGION_USER1, 0 )
+ROM_END
+
+
+
+/*************************************
+ *
+ * Game drivers
+ *
+ *************************************/
+
+GAME( 2007, empty, 0, empty, empty, 0, ROT0, "MAME", "No Driver Loaded", 0 )
diff --git a/src/emu/eigccppc.h b/src/emu/eigccppc.h
new file mode 100644
index 00000000000..13b4deffe62
--- /dev/null
+++ b/src/emu/eigccppc.h
@@ -0,0 +1,434 @@
+/***************************************************************************
+
+ eigccppc.h
+
+ PowerPC (32 and 64-bit) inline implementations for GCC compilers. This
+ code is automatically included if appropriate by eminline.h.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __EIGCCPPC__
+#define __EIGCCPPC__
+
+
+/***************************************************************************
+ INLINE MATH FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mul_32x32 - perform a signed 32 bit x 32 bit
+ multiply and return the full 64 bit result
+-------------------------------------------------*/
+
+/* TBD */
+
+
+/*-------------------------------------------------
+ mulu_32x32 - perform an unsigned 32 bit x
+ 32 bit multiply and return the full 64 bit
+ result
+-------------------------------------------------*/
+
+/* TBD */
+
+
+/*-------------------------------------------------
+ mul_32x32_hi - perform a signed 32 bit x 32 bit
+ multiply and return the upper 32 bits of the
+ result
+-------------------------------------------------*/
+
+#define mul_32x32_hi _mul_32x32_hi
+INLINE INT32 _mul_32x32_hi(INT32 val1, INT32 val2)
+{
+ INT32 result;
+
+ __asm__ (
+ " mulhw %[result], %[val1], %[val2] \n"
+ : [result] "=r" (result)
+ : [val1] "%r" (val1)
+ , [val2] "r" (val2)
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ mulu_32x32_hi - perform an unsigned 32 bit x
+ 32 bit multiply and return the upper 32 bits
+ of the result
+-------------------------------------------------*/
+
+#define mulu_32x32_hi _mulu_32x32_hi
+INLINE UINT32 _mulu_32x32_hi(UINT32 val1, UINT32 val2)
+{
+ UINT32 result;
+
+ __asm__ (
+ " mulhwu %[result], %[val1], %[val2] \n"
+ : [result] "=r" (result)
+ : [val1] "%r" (val1)
+ , [val2] "r" (val2)
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ mul_32x32_shift - perform a signed 32 bit x
+ 32 bit multiply and shift the result by the
+ given number of bits before truncating the
+ result to 32 bits
+-------------------------------------------------*/
+
+#if !defined(__ppc64__) && !defined(__PPC64__) && !defined(_ARCH_PPC64)
+#define mul_32x32_shift _mul_32x32_shift
+INLINE INT32 _mul_32x32_shift(INT32 val1, INT32 val2, UINT8 shift)
+{
+ INT32 result;
+
+ __asm__ (
+ " mullw %[result], %[val1], %[val2] \n"
+ " mulhw %[val1], %[val1], %[val2] \n"
+ " srw %[result], %[result], %[shift] \n"
+ " subfic %[shift], %[shift], 0x20 \n"
+ " slw %[val1], %[val1], %[shift] \n"
+ " or %[result], %[result], %[val1] \n"
+ : [result] "=&r" (result)
+ , [shift] "+r" (shift)
+ , [val1] "+r" (val1)
+ : [val2] "r" (val2)
+ : "xer"
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ mulu_32x32_shift - perform an unsigned 32 bit x
+ 32 bit multiply and shift the result by the
+ given number of bits before truncating the
+ result to 32 bits
+-------------------------------------------------*/
+
+#if !defined(__ppc64__) && !defined(__PPC64__) && !defined(_ARCH_PPC64)
+#define mulu_32x32_shift _mulu_32x32_shift
+INLINE UINT32 _mulu_32x32_shift(UINT32 val1, UINT32 val2, UINT8 shift)
+{
+ UINT32 result;
+
+ __asm__ (
+ " mullw %[result], %[val1], %[val2] \n"
+ " mulhwu %[val1], %[val1], %[val2] \n"
+ " srw %[result], %[result], %[shift] \n"
+ " subfic %[shift], %[shift], 0x20 \n"
+ " slw %[val1], %[val1], %[shift] \n"
+ " or %[result], %[result], %[val1] \n"
+ : [result] "=&r" (result)
+ , [shift] "+r" (shift)
+ , [val1] "+r" (val1)
+ : [val2] "r" (val2)
+ : "xer"
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ div_64x32 - perform a signed 64 bit x 32 bit
+ divide and return the 32 bit quotient
+-------------------------------------------------*/
+
+/* TBD */
+
+
+/*-------------------------------------------------
+ divu_64x32 - perform an unsigned 64 bit x 32 bit
+ divide and return the 32 bit quotient
+-------------------------------------------------*/
+
+/* TBD */
+
+
+/*-------------------------------------------------
+ div_32x32_shift - perform a signed divide of
+ two 32 bit values, shifting the first before
+ division, and returning the 32 bit quotient
+-------------------------------------------------*/
+
+/* TBD */
+
+
+/*-------------------------------------------------
+ divu_32x32_shift - perform an unsigned divide of
+ two 32 bit values, shifting the first before
+ division, and returning the 32 bit quotient
+-------------------------------------------------*/
+
+/* TBD */
+
+
+/*-------------------------------------------------
+ mod_64x32 - perform a signed 64 bit x 32 bit
+ divide and return the 32 bit remainder
+-------------------------------------------------*/
+
+/* TBD */
+
+
+/*-------------------------------------------------
+ modu_64x32 - perform an unsigned 64 bit x 32 bit
+ divide and return the 32 bit remainder
+-------------------------------------------------*/
+
+/* TBD */
+
+
+/*-------------------------------------------------
+ recip_approx - compute an approximate floating
+ point reciprocal
+-------------------------------------------------*/
+
+#define recip_approx _recip_approx
+INLINE float _recip_approx(float value)
+{
+ float result;
+
+ __asm__ (
+ " fres %[result], %[value] \n"
+ : [result] "=f" (result)
+ : [value] "f" (value)
+ );
+
+ return result;
+}
+
+
+
+/***************************************************************************
+ INLINE BIT MANIPULATION FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ count_leading_zeros - return the number of
+ leading zero bits in a 32-bit value
+-------------------------------------------------*/
+
+#define count_leading_zeros _count_leading_zeros
+INLINE UINT8 _count_leading_zeros(UINT32 value)
+{
+ UINT32 result;
+
+ __asm__ (
+ " cntlzw %[result], %[value] \n"
+ : [result] "=r" (result) /* result can be in any register */
+ : [value] "r" (value) /* 'value' can be in any register */
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ count_leading_ones - return the number of
+ leading one bits in a 32-bit value
+-------------------------------------------------*/
+
+#define count_leading_ones _count_leading_ones
+INLINE UINT8 _count_leading_ones(UINT32 value)
+{
+ UINT32 result;
+
+ __asm__ (
+ " not %[result], %[value] \n"
+ " cntlzw %[result], %[result] \n"
+ : [result] "=r" (result) /* result can be in any register */
+ : [value] "r" (value) /* 'value' can be in any register */
+ );
+
+ return result;
+}
+
+
+
+/***************************************************************************
+ INLINE SYNCHRONIZATION FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ compare_exchange32 - compare the 'compare'
+ value against the memory at 'ptr'; if equal,
+ swap in the 'exchange' value. Regardless,
+ return the previous value at 'ptr'.
+-------------------------------------------------*/
+
+#define compare_exchange32 _compare_exchange32
+INLINE INT32 _compare_exchange32(INT32 volatile *ptr, INT32 compare, INT32 exchange)
+{
+ register INT32 result;
+
+ __asm__ __volatile__ (
+ "1: lwarx %[result], 0, %[ptr] \n"
+ " cmpw %[compare], %[result] \n"
+ " bne 2f \n"
+ " sync \n"
+ " stwcx. %[exchange], 0, %[ptr] \n"
+ " bne- 1b \n"
+ "2: "
+ : [result] "=&r" (result)
+ : [ptr] "r" (ptr)
+ , [exchange] "r" (exchange)
+ , [compare] "r" (compare)
+ : "cr0"
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ compare_exchange64 - compare the 'compare'
+ value against the memory at 'ptr'; if equal,
+ swap in the 'exchange' value. Regardless,
+ return the previous value at 'ptr'.
+-------------------------------------------------*/
+
+#if defined(__ppc64__) || defined(__PPC64__)
+#define compare_exchange64 _compare_exchange64
+INLINE INT64 _compare_exchange64(INT64 volatile *ptr, INT64 compare, INT64 exchange)
+{
+ register INT64 result;
+
+ __asm__ __volatile__ (
+ "1: ldarx %[result], 0, %[ptr] \n"
+ " cmpd %[compare], %[result] \n"
+ " bne 2f \n"
+ " stdcx. %[exchange], 0, %[ptr] \n"
+ " bne-- 1b \n"
+ "2: "
+ : [result] "=&r" (result)
+ : [ptr] "r" (ptr)
+ , [exchange] "r" (exchange)
+ , [compare] "r" (compare)
+ : "cr0"
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ atomic_exchange32 - atomically exchange the
+ exchange value with the memory at 'ptr',
+ returning the original value.
+-------------------------------------------------*/
+
+#define atomic_exchange32 _atomic_exchange32
+INLINE INT32 _atomic_exchange32(INT32 volatile *ptr, INT32 exchange)
+{
+ register INT32 result;
+
+ __asm__ __volatile__ (
+ "1: lwarx %[result], 0, %[ptr] \n"
+ " sync \n"
+ " stwcx. %[exchange], 0, %[ptr] \n"
+ " bne- 1b \n"
+ : [result] "=&r" (result)
+ : [ptr] "r" (ptr)
+ , [exchange] "r" (exchange)
+ : "cr0"
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ atomic_add32 - atomically add the delta value
+ to the memory at 'ptr', returning the final
+ result.
+-------------------------------------------------*/
+
+#define atomic_add32 _atomic_add32
+INLINE INT32 _atomic_add32(INT32 volatile *ptr, INT32 delta)
+{
+ register INT32 result;
+
+ __asm__ __volatile__ (
+ "1: lwarx %[result], 0, %[ptr] \n"
+ " add %[result], %[result], %[delta] \n"
+ " sync \n"
+ " stwcx. %[result], 0, %[ptr] \n"
+ " bne- 1b \n"
+ : [result] "=&b" (result)
+ : [ptr] "r" (ptr)
+ , [delta] "r" (delta)
+ : "cr0"
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ atomic_increment32 - atomically increment the
+ 32-bit value in memory at 'ptr', returning the
+ final result.
+-------------------------------------------------*/
+
+#define atomic_increment32 _atomic_increment32
+INLINE INT32 _atomic_increment32(INT32 volatile *ptr)
+{
+ register INT32 result;
+
+ __asm__ __volatile__ (
+ "1: lwarx %[result], 0, %[ptr] \n"
+ " addi %[result], %[result], 1 \n"
+ " sync \n"
+ " stwcx. %[result], 0, %[ptr] \n"
+ " bne- 1b \n"
+ : [result] "=&b" (result)
+ : [ptr] "r" (ptr)
+ : "cr0"
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ atomic_decrement32 - atomically decrement the
+ 32-bit value in memory at 'ptr', returning the
+ final result.
+-------------------------------------------------*/
+
+#define atomic_decrement32 _atomic_decrement32
+INLINE INT32 _atomic_decrement32(INT32 volatile *ptr)
+{
+ register INT32 result;
+
+ __asm__ __volatile__ (
+ "1: lwarx %[result], 0, %[ptr] \n"
+ " addi %[result], %[result], -1 \n"
+ " sync \n"
+ " stwcx. %[result], 0, %[ptr] \n"
+ " bne- 1b \n"
+ : [result] "=&b" (result)
+ : [ptr] "r" (ptr)
+ : "cr0"
+ );
+
+ return result;
+}
+
+#endif /* __EIGCCPPC__ */
diff --git a/src/emu/eigccx86.h b/src/emu/eigccx86.h
new file mode 100644
index 00000000000..75d6ed0074d
--- /dev/null
+++ b/src/emu/eigccx86.h
@@ -0,0 +1,610 @@
+/***************************************************************************
+
+ eigccx86.h
+
+ x86 (32 and 64-bit) inline implementations for GCC compilers. This
+ code is automatically included if appropriate by eminline.h.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __EIGCCX86__
+#define __EIGCCX86__
+
+/* Include MMX/SSE intrinsics headers */
+
+#ifdef __SSE2__
+#include <mmintrin.h> /* MMX */
+#include <xmmintrin.h> /* SSE */
+#include <emmintrin.h> /* SSE2 */
+#endif
+
+
+/***************************************************************************
+ INLINE MATH FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mul_32x32 - perform a signed 32 bit x 32 bit
+ multiply and return the full 64 bit result
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define mul_32x32 _mul_32x32
+INLINE INT64 _mul_32x32(INT32 a, INT32 b)
+{
+ INT64 result;
+
+ __asm__ (
+ " imull %[b] ;"
+ : [result] "=A" (result) /* result in edx:eax */
+ : [a] "%a" (a) /* 'a' should also be in eax on entry */
+ , [b] "rm" (b) /* 'b' can be memory or register */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ mulu_32x32 - perform an unsigned 32 bit x
+ 32 bit multiply and return the full 64 bit
+ result
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define mulu_32x32 _mulu_32x32
+INLINE UINT64 _mulu_32x32(UINT32 a, UINT32 b)
+{
+ UINT64 result;
+
+ __asm__ (
+ " mull %[b] ;"
+ : [result] "=A" (result) /* result in edx:eax */
+ : [a] "%a" (a) /* 'a' should also be in eax on entry */
+ , [b] "rm" (b) /* 'b' can be memory or register */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ mul_32x32_hi - perform a signed 32 bit x 32 bit
+ multiply and return the upper 32 bits of the
+ result
+-------------------------------------------------*/
+
+#define mul_32x32_hi _mul_32x32_hi
+INLINE INT32 _mul_32x32_hi(INT32 a, INT32 b)
+{
+ INT32 result;
+
+ __asm__ (
+ " imull %[b] ;"
+ : [result] "=d" (result) /* result in edx */
+ , [a] "+%a" (a) /* 'a' should be in eax on entry (clobbered) */
+ : [b] "rm" (b) /* 'b' can be memory or register */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ mulu_32x32_hi - perform an unsigned 32 bit x
+ 32 bit multiply and return the upper 32 bits
+ of the result
+-------------------------------------------------*/
+
+#define mulu_32x32_hi _mulu_32x32_hi
+INLINE UINT32 _mulu_32x32_hi(UINT32 a, UINT32 b)
+{
+ UINT32 result;
+
+ __asm__ (
+ " mull %[b] ;"
+ : [result] "=d" (result) /* result in edx */
+ , [a] "+%a" (a) /* 'a' should be in eax on entry (clobbered) */
+ : [b] "rm" (b) /* 'b' can be memory or register */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ mul_32x32_shift - perform a signed 32 bit x
+ 32 bit multiply and shift the result by the
+ given number of bits before truncating the
+ result to 32 bits
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define mul_32x32_shift _mul_32x32_shift
+INLINE INT32 _mul_32x32_shift(INT32 a, INT32 b, UINT8 shift)
+{
+ INT32 result;
+
+ __asm__ (
+ " imull %[b] ;"
+ " shrdl %[shift], %%edx, %[result] ;"
+ : [result] "=a" (result) /* result ends up in eax */
+ : [a] "%0" (a) /* 'a' should also be in eax on entry */
+ , [b] "rm" (b) /* 'b' can be memory or register */
+ , [shift] "Ic" (shift) /* 'shift' must be constant in 0-31 range or in cl */
+ : "%edx", "%cc" /* clobbers edx and condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ mulu_32x32_shift - perform an unsigned 32 bit x
+ 32 bit multiply and shift the result by the
+ given number of bits before truncating the
+ result to 32 bits
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define mulu_32x32_shift _mulu_32x32_shift
+INLINE UINT32 _mulu_32x32_shift(UINT32 a, UINT32 b, UINT8 shift)
+{
+ UINT32 result;
+
+ __asm__ (
+ " mull %[b] ;"
+ " shrdl %[shift], %%edx, %[result] ;"
+ : [result] "=a" (result) /* result ends up in eax */
+ : [a] "%0" (a) /* 'a' should also be in eax on entry */
+ , [b] "rm" (b) /* 'b' can be memory or register */
+ , [shift] "Ic" (shift) /* 'shift' must be constant in 0-31 range or in cl */
+ : "%edx", "%cc" /* clobbers edx and condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ div_64x32 - perform a signed 64 bit x 32 bit
+ divide and return the 32 bit quotient
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define div_64x32 _div_64x32
+INLINE INT32 _div_64x32(INT64 a, INT32 b)
+{
+ INT32 result, temp;
+
+ __asm__ (
+ " idivl %[b] ;"
+ : [result] "=a" (result) /* Result ends up in eax */
+ , [temp] "=d" (temp) /* This is effectively a clobber */
+ : [a] "A" (a) /* 'a' in edx:eax */
+ , [b] "rm" (b) /* 'b' in register or memory */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ divu_64x32 - perform an unsigned 64 bit x 32 bit
+ divide and return the 32 bit quotient
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define divu_64x32 _divu_64x32
+INLINE UINT32 _divu_64x32(UINT64 a, UINT32 b)
+{
+ UINT32 result, temp;
+
+ __asm__ (
+ " divl %[b] ;"
+ : [result] "=a" (result) /* Result ends up in eax */
+ , [temp] "=d" (temp) /* This is effectively a clobber */
+ : [a] "A" (a) /* 'a' in edx:eax */
+ , [b] "rm" (b) /* 'b' in register or memory */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ div_64x32_rem - perform a signed 64 bit x 32
+ bit divide and return the 32 bit quotient and
+ 32 bit remainder
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define div_64x32_rem _div_64x32_rem
+INLINE INT32 _div_64x32_rem(INT64 dividend, INT32 divisor, INT32 *remainder)
+{
+ INT32 quotient;
+
+ __asm__ (
+ " idivl %[divisor] ;"
+ : [result] "=a" (quotient) /* Quotient ends up in eax */
+ , [remainder] "=d" (*remainder) /* Remainder ends up in edx */
+ : [dividend] "A" (dividend) /* 'dividend' in edx:eax */
+ , [divisor] "rm" (divisor) /* 'divisor' in register or memory */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return quotient;
+}
+#endif
+
+
+/*-------------------------------------------------
+ divu_64x32_rem - perform an unsigned 64 bit x
+ 32 bit divide and return the 32 bit quotient
+ and 32 bit remainder
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define divu_64x32_rem _divu_64x32_rem
+INLINE UINT32 _divu_64x32_rem(UINT64 dividend, UINT32 divisor, UINT32 *remainder)
+{
+ UINT32 quotient;
+
+ __asm__ (
+ " divl %[divisor] ;"
+ : [result] "=a" (quotient) /* Quotient ends up in eax */
+ , [remainder] "=d" (*remainder) /* Remainder ends up in edx */
+ : [dividend] "A" (dividend) /* 'dividend' in edx:eax */
+ , [divisor] "rm" (divisor) /* 'divisor' in register or memory */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return quotient;
+}
+#endif
+
+
+/*-------------------------------------------------
+ div_32x32_shift - perform a signed divide of
+ two 32 bit values, shifting the first before
+ division, and returning the 32 bit quotient
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define div_32x32_shift _div_32x32_shift
+INLINE INT32 _div_32x32_shift(INT32 a, INT32 b, UINT8 shift)
+{
+ INT32 result;
+
+ __asm__ (
+ " cdq ;"
+ " shldl %[shift], %[a], %%edx ;"
+ " shll %[shift], %[a] ;"
+ " idivl %[b] ;"
+ : [result] "=&a" (result) /* result ends up in eax */
+ : [a] "0" (a) /* 'a' should also be in eax on entry */
+ , [b] "rm" (b) /* 'b' can be memory or register */
+ , [shift] "Ic" (shift) /* 'shift' must be constant in 0-31 range or in cl */
+ : "%edx", "%cc" /* clobbers edx and condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ divu_32x32_shift - perform an unsigned divide of
+ two 32 bit values, shifting the first before
+ division, and returning the 32 bit quotient
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define divu_32x32_shift _divu_32x32_shift
+INLINE UINT32 _divu_32x32_shift(UINT32 a, UINT32 b, UINT8 shift)
+{
+ INT32 result;
+
+ __asm__ (
+ " clr %%edx ;"
+ " shldl %[shift], %[a], %%edx ;"
+ " shll %[shift], %[a] ;"
+ " divl %[b] ;"
+ : [result] "=&a" (result) /* result ends up in eax */
+ : [a] "0" (a) /* 'a' should also be in eax on entry */
+ , [b] "rm" (b) /* 'b' can be memory or register */
+ , [shift] "Ic" (shift) /* 'shift' must be constant in 0-31 range or in cl */
+ : "%edx", "%cc" /* clobbers edx and condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ mod_64x32 - perform a signed 64 bit x 32 bit
+ divide and return the 32 bit remainder
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define mod_64x32 _mod_64x32
+INLINE INT32 _mod_64x32(INT64 a, INT32 b)
+{
+ INT32 result, temp;
+
+ __asm__ (
+ " idivl %[b] ;"
+ : [result] "=d" (result) /* Result ends up in edx */
+ , [temp] "=a" (temp) /* This is effectively a clobber */
+ : [a] "A" (a) /* 'a' in edx:eax */
+ , [b] "rm" (b) /* 'b' in register or memory */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ modu_64x32 - perform an unsigned 64 bit x 32 bit
+ divide and return the 32 bit remainder
+-------------------------------------------------*/
+
+#ifndef __x86_64__
+#define modu_64x32 _modu_64x32
+INLINE UINT32 _modu_64x32(UINT64 a, UINT32 b)
+{
+ UINT32 result, temp;
+
+ __asm__ (
+ " divl %[b] ;"
+ : [result] "=d" (result) /* Result ends up in edx */
+ , [temp] "=a" (temp) /* This is effectively a clobber */
+ : [a] "A" (a) /* 'a' in edx:eax */
+ , [b] "rm" (b) /* 'b' in register or memory */
+ : "%cc" /* Clobbers condition codes */
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ recip_approx - compute an approximate floating
+ point reciprocal
+-------------------------------------------------*/
+
+#ifdef __SSE2__
+#define recip_approx _recip_approx
+INLINE float _recip_approx(float value)
+{
+ __m128 value_xmm = _mm_set_ss(value);
+ __m128 result_xmm = _mm_rcp_ss(value_xmm);
+ float result;
+ _mm_store_ss(&result, result_xmm);
+ return result;
+}
+#endif
+
+
+
+/***************************************************************************
+ INLINE BIT MANIPULATION FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ count_leading_zeros - return the number of
+ leading zero bits in a 32-bit value
+-------------------------------------------------*/
+
+#define count_leading_zeros _count_leading_zeros
+INLINE UINT8 _count_leading_zeros(UINT32 value)
+{
+ UINT32 result;
+
+ __asm__ (
+ " bsrl %[value], %[result] ;"
+ " jnz 1f ;"
+ " movl $63, %[result] ;"
+ "1: xorl $31, %[result] ;"
+ : [result] "=r" (result) /* result can be in any register */
+ : [value] "rm" (value) /* 'value' can be register or memory */
+ : "%cc" /* clobbers condition codes */
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ count_leading_ones - return the number of
+ leading one bits in a 32-bit value
+-------------------------------------------------*/
+
+#define count_leading_ones _count_leading_ones
+INLINE UINT8 _count_leading_ones(UINT32 value)
+{
+ UINT32 result;
+
+ __asm__ (
+ " movl %[value], %[result] ;"
+ " notl %[result] ;"
+ " bsrl %[result], %[result] ;"
+ " jnz 1f ;"
+ " movl $63, %[result] ;"
+ "1: xorl $31, %[result] ;"
+ : [result] "=r" (result) /* result can be in any register */
+ : [value] "rmi" (value) /* 'value' can be register, memory or immediate */
+ : "%cc" /* clobbers condition codes */
+ );
+
+ return result;
+}
+
+
+
+/***************************************************************************
+ INLINE SYNCHRONIZATION FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ compare_exchange32 - compare the 'compare'
+ value against the memory at 'ptr'; if equal,
+ swap in the 'exchange' value. Regardless,
+ return the previous value at 'ptr'.
+-------------------------------------------------*/
+
+#define compare_exchange32 _compare_exchange32
+INLINE INT32 _compare_exchange32(INT32 volatile *ptr, INT32 compare, INT32 exchange)
+{
+ register INT32 result;
+
+ __asm__ __volatile__ (
+ " lock ; cmpxchg %[exchange], %[ptr] ;"
+ : [ptr] "+m" (*ptr)
+ , [result] "=a" (result)
+ : [compare] "1" (compare)
+ , [exchange] "q" (exchange)
+ : "%cc"
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ compare_exchange64 - compare the 'compare'
+ value against the memory at 'ptr'; if equal,
+ swap in the 'exchange' value. Regardless,
+ return the previous value at 'ptr'.
+-------------------------------------------------*/
+
+#ifdef __x86_64__
+#define compare_exchange64 _compare_exchange64
+INLINE INT64 _compare_exchange64(INT64 volatile *ptr, INT64 compare, INT64 exchange)
+{
+ register INT64 result;
+
+ __asm__ __volatile__ (
+ " lock ; cmpxchg %[exchange], %[ptr] ;"
+ : [ptr] "+m" (*ptr)
+ , [result] "=a" (result)
+ : [compare] "1" (compare)
+ , [exchange] "q" (exchange)
+ : "%cc"
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ atomic_exchange32 - atomically exchange the
+ exchange value with the memory at 'ptr',
+ returning the original value.
+-------------------------------------------------*/
+
+#define atomic_exchange32 _atomic_exchange32
+INLINE INT32 _atomic_exchange32(INT32 volatile *ptr, INT32 exchange)
+{
+ register INT32 result;
+
+ __asm__ __volatile__ (
+ " lock ; xchg %[exchange], %[ptr] ;"
+ : [ptr] "+m" (*ptr)
+ , [result] "=r" (result)
+ : [exchange] "1" (exchange)
+ );
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ atomic_add32 - atomically add the delta value
+ to the memory at 'ptr', returning the final
+ result.
+-------------------------------------------------*/
+
+#define atomic_add32 _atomic_add32
+INLINE INT32 _atomic_add32(INT32 volatile *ptr, INT32 delta)
+{
+ register INT32 result = delta;
+
+ __asm__ __volatile__ (
+ " lock ; xadd %[result], %[ptr] ;"
+ : [ptr] "+m" (*ptr)
+ , [result] "+r" (result)
+ :
+ : "%cc"
+ );
+
+ return result + delta;
+}
+
+
+/*-------------------------------------------------
+ atomic_increment32 - atomically increment the
+ 32-bit value in memory at 'ptr', returning the
+ final result.
+-------------------------------------------------*/
+
+#define atomic_increment32 _atomic_increment32
+INLINE INT32 _atomic_increment32(INT32 volatile *ptr)
+{
+ register INT32 result = 1;
+
+ __asm__ __volatile__ (
+ " lock ; xadd %[result], %[ptr] ;"
+ : [ptr] "+m" (*ptr)
+ , [result] "+r" (result)
+ :
+ : "%cc"
+ );
+
+ return result + 1;
+}
+
+
+/*-------------------------------------------------
+ atomic_decrement32 - atomically decrement the
+ 32-bit value in memory at 'ptr', returning the
+ final result.
+-------------------------------------------------*/
+
+#define atomic_decrement32 _atomic_decrement32
+INLINE INT32 _atomic_decrement32(INT32 volatile *ptr)
+{
+ register INT32 result = -1;
+
+ __asm__ __volatile__ (
+ " lock ; xadd %[result], %[ptr] ;"
+ : [ptr] "+m" (*ptr)
+ , [result] "+r" (result)
+ :
+ : "%cc"
+ );
+
+ return result - 1;
+}
+
+#endif /* __EIGCCX86__ */
diff --git a/src/emu/eminline.h b/src/emu/eminline.h
new file mode 100644
index 00000000000..bc3a4eb90c0
--- /dev/null
+++ b/src/emu/eminline.h
@@ -0,0 +1,433 @@
+/***************************************************************************
+
+ eminline.h
+
+ Definitions for inline functions that can be overriden by OSD-
+ specific code.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __EMINLINE__
+#define __EMINLINE__
+
+/* we come with implementations for GCC x86 and PPC */
+#ifdef __GNUC__
+
+#if defined(__i386__) || defined(__x86_64__)
+#include "eigccx86.h"
+#elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__)
+#include "eigccppc.h"
+#else
+#include "osinline.h"
+#endif
+
+#else
+
+#include "osinline.h"
+
+#endif
+
+
+/***************************************************************************
+ INLINE MATH FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mul_32x32 - perform a signed 32 bit x 32 bit
+ multiply and return the full 64 bit result
+-------------------------------------------------*/
+
+#ifndef mul_32x32
+INLINE INT64 mul_32x32(INT32 a, INT32 b)
+{
+ return (INT64)a * (INT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ mulu_32x32 - perform an unsigned 32 bit x
+ 32 bit multiply and return the full 64 bit
+ result
+-------------------------------------------------*/
+
+#ifndef mulu_32x32
+INLINE UINT64 mulu_32x32(UINT32 a, UINT32 b)
+{
+ return (UINT64)a * (UINT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ mul_32x32_hi - perform a signed 32 bit x 32 bit
+ multiply and return the upper 32 bits of the
+ result
+-------------------------------------------------*/
+
+#ifndef mul_32x32_hi
+INLINE INT32 mul_32x32_hi(INT32 a, INT32 b)
+{
+ return (UINT32)(((INT64)a * (INT64)b) >> 32);
+}
+#endif
+
+
+/*-------------------------------------------------
+ mulu_32x32_hi - perform an unsigned 32 bit x
+ 32 bit multiply and return the upper 32 bits
+ of the result
+-------------------------------------------------*/
+
+#ifndef mulu_32x32_hi
+INLINE UINT32 mulu_32x32_hi(UINT32 a, UINT32 b)
+{
+ return (UINT32)(((UINT64)a * (UINT64)b) >> 32);
+}
+#endif
+
+
+/*-------------------------------------------------
+ mul_32x32_shift - perform a signed 32 bit x
+ 32 bit multiply and shift the result by the
+ given number of bits before truncating the
+ result to 32 bits
+-------------------------------------------------*/
+
+#ifndef mul_32x32_shift
+INLINE INT32 mul_32x32_shift(INT32 a, INT32 b, UINT8 shift)
+{
+ return (INT32)(((INT64)a * (INT64)b) >> shift);
+}
+#endif
+
+
+/*-------------------------------------------------
+ mulu_32x32_shift - perform an unsigned 32 bit x
+ 32 bit multiply and shift the result by the
+ given number of bits before truncating the
+ result to 32 bits
+-------------------------------------------------*/
+
+#ifndef mulu_32x32_shift
+INLINE UINT32 mulu_32x32_shift(UINT32 a, UINT32 b, UINT8 shift)
+{
+ return (UINT32)(((UINT64)a * (UINT64)b) >> shift);
+}
+#endif
+
+
+/*-------------------------------------------------
+ div_64x32 - perform a signed 64 bit x 32 bit
+ divide and return the 32 bit quotient
+-------------------------------------------------*/
+
+#ifndef div_64x32
+INLINE INT32 div_64x32(INT64 a, INT32 b)
+{
+ return a / (INT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ divu_64x32 - perform an unsigned 64 bit x 32 bit
+ divide and return the 32 bit quotient
+-------------------------------------------------*/
+
+#ifndef divu_64x32
+INLINE UINT32 divu_64x32(UINT64 a, UINT32 b)
+{
+ return a / (UINT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ div_64x32_rem - perform a signed 64 bit x 32
+ bit divide and return the 32 bit quotient and
+ 32 bit remainder
+-------------------------------------------------*/
+
+#ifndef div_64x32_rem
+INLINE INT32 div_64x32_rem(INT64 a, INT32 b, INT32 *remainder)
+{
+ *remainder = a % (INT64)b;
+ return a / (INT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ divu_64x32_rem - perform an unsigned 64 bit x
+ 32 bit divide and return the 32 bit quotient
+ and 32 bit remainder
+-------------------------------------------------*/
+
+#ifndef divu_64x32_rem
+INLINE UINT32 divu_64x32_rem(UINT64 a, UINT32 b, UINT32 *remainder)
+{
+ *remainder = a % (UINT64)b;
+ return a / (UINT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ div_32x32_shift - perform a signed divide of
+ two 32 bit values, shifting the first before
+ division, and returning the 32 bit quotient
+-------------------------------------------------*/
+
+#ifndef div_32x32_shift
+INLINE INT32 div_32x32_shift(INT32 a, INT32 b, UINT8 shift)
+{
+ return ((INT64)a << shift) / (INT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ divu_32x32_shift - perform an unsigned divide of
+ two 32 bit values, shifting the first before
+ division, and returning the 32 bit quotient
+-------------------------------------------------*/
+
+#ifndef divu_32x32_shift
+INLINE UINT32 divu_32x32_shift(UINT32 a, UINT32 b, UINT8 shift)
+{
+ return ((UINT64)a << shift) / (UINT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ mod_64x32 - perform a signed 64 bit x 32 bit
+ divide and return the 32 bit remainder
+-------------------------------------------------*/
+
+#ifndef mod_64x32
+INLINE INT32 mod_64x32(INT64 a, INT32 b)
+{
+ return a % (INT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ modu_64x32 - perform an unsigned 64 bit x 32 bit
+ divide and return the 32 bit remainder
+-------------------------------------------------*/
+
+#ifndef modu_64x32
+INLINE UINT32 modu_64x32(UINT64 a, UINT32 b)
+{
+ return a % (UINT64)b;
+}
+#endif
+
+
+/*-------------------------------------------------
+ recip_approx - compute an approximate floating
+ point reciprocal
+-------------------------------------------------*/
+
+#ifndef recip_approx
+INLINE float recip_approx(float value)
+{
+ return 1.0f / value;
+}
+#endif
+
+
+
+/***************************************************************************
+ INLINE BIT MANIPULATION FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ count_leading_zeros - return the number of
+ leading zero bits in a 32-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_zeros
+INLINE UINT8 count_leading_zeros(UINT32 val)
+{
+ UINT8 count;
+ for (count = 0; (INT32)val >= 0; count++) val <<= 1;
+ return count;
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_ones - return the number of
+ leading one bits in a 32-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_ones
+INLINE UINT8 count_leading_ones(UINT32 val)
+{
+ UINT8 count;
+ for (count = 0; (INT32)val < 0; count++) val <<= 1;
+ return count;
+}
+#endif
+
+
+
+/***************************************************************************
+ INLINE SYNCHRONIZATION FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ compare_exchange32 - compare the 'compare'
+ value against the memory at 'ptr'; if equal,
+ swap in the 'exchange' value. Regardless,
+ return the previous value at 'ptr'.
+
+ Note that the default implementation does
+ no synchronization. You MUST override this
+ in osinline.h for it to be useful in a
+ multithreaded environment!
+-------------------------------------------------*/
+
+#ifndef compare_exchange32
+INLINE INT32 compare_exchange32(INT32 volatile *ptr, INT32 compare, INT32 exchange)
+{
+ INT32 oldval = *ptr;
+ if (*ptr == compare)
+ *ptr = exchange;
+ return oldval;
+}
+#endif
+
+
+/*-------------------------------------------------
+ compare_exchange64 - compare the 'compare'
+ value against the memory at 'ptr'; if equal,
+ swap in the 'exchange' value. Regardless,
+ return the previous value at 'ptr'.
+
+ Note that the default implementation does
+ no synchronization. You MUST override this
+ in osinline.h for it to be useful in a
+ multithreaded environment!
+-------------------------------------------------*/
+
+#ifdef PTR64
+#ifndef compare_exchange64
+INLINE INT64 compare_exchange64(INT64 volatile *ptr, INT64 compare, INT64 exchange)
+{
+ INT64 oldval = *ptr;
+ if (*ptr == compare)
+ *ptr = exchange;
+ return oldval;
+}
+#endif
+#endif
+
+
+/*-------------------------------------------------
+ compare_exchange_ptr - compare the 'compare'
+ value against the memory at 'ptr'; if equal,
+ swap in the 'exchange' value. Regardless,
+ return the previous value at 'ptr'.
+-------------------------------------------------*/
+
+#ifndef compare_exchange_ptr
+INLINE void *compare_exchange_ptr(void * volatile *ptr, void *compare, void *exchange)
+{
+#ifdef PTR64
+ INT64 result;
+ result = compare_exchange64((INT64 volatile *)ptr, (INT64)compare, (INT64)exchange);
+#else
+ INT32 result;
+ result = compare_exchange32((INT32 volatile *)ptr, (INT32)compare, (INT32)exchange);
+#endif
+ return (void *)result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ atomic_exchange32 - atomically exchange the
+ exchange value with the memory at 'ptr',
+ returning the original value.
+
+ Note that the default implementation does
+ no synchronization. You MUST override this
+ in osinline.h for it to be useful in a
+ multithreaded environment!
+-------------------------------------------------*/
+
+#ifndef atomic_exchange32
+INLINE INT32 atomic_exchange32(INT32 volatile *ptr, INT32 exchange)
+{
+ INT32 oldval = *ptr;
+ *ptr = exchange;
+ return oldval;
+}
+#endif
+
+
+/*-------------------------------------------------
+ atomic_add32 - atomically add the delta value
+ to the memory at 'ptr', returning the final
+ result.
+
+ Note that the default implementation does
+ no synchronization. You MUST override this
+ in osinline.h for it to be useful in a
+ multithreaded environment!
+-------------------------------------------------*/
+
+#ifndef atomic_add32
+INLINE INT32 atomic_add32(INT32 volatile *ptr, INT32 delta)
+{
+ return (*ptr += delta);
+}
+#endif
+
+
+/*-------------------------------------------------
+ atomic_increment32 - atomically increment the
+ 32-bit value in memory at 'ptr', returning the
+ final result.
+
+ Note that the default implementation does
+ no synchronization. You MUST override this
+ in osinline.h for it to be useful in a
+ multithreaded environment!
+-------------------------------------------------*/
+
+#ifndef atomic_increment32
+INLINE INT32 atomic_increment32(INT32 volatile *ptr)
+{
+ return atomic_add32(ptr, 1);
+}
+#endif
+
+
+/*-------------------------------------------------
+ atomic_decrement32 - atomically decrement the
+ 32-bit value in memory at 'ptr', returning the
+ final result.
+
+ Note that the default implementation does
+ no synchronization. You MUST override this
+ in osinline.h for it to be useful in a
+ multithreaded environment!
+-------------------------------------------------*/
+
+#ifndef atomic_decrement32
+INLINE INT32 atomic_decrement32(INT32 volatile *ptr)
+{
+ return atomic_add32(ptr, -1);
+}
+#endif
+
+#endif /* __EMINLINE__ */
diff --git a/src/emu/emu.mak b/src/emu/emu.mak
new file mode 100644
index 00000000000..1962eea223f
--- /dev/null
+++ b/src/emu/emu.mak
@@ -0,0 +1,237 @@
+###########################################################################
+#
+# emu.mak
+#
+# MAME emulation core makefile
+#
+# Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+# Visit http://mamedev.org for licensing and usage restrictions.
+#
+###########################################################################
+
+
+EMUSRC = $(SRC)/emu
+EMUOBJ = $(OBJ)/emu
+
+EMUAUDIO = $(EMUOBJ)/audio
+EMUDRIVERS = $(EMUOBJ)/drivers
+EMULAYOUT = $(EMUOBJ)/layout
+EMUMACHINE = $(EMUOBJ)/machine
+EMUVIDEO = $(EMUOBJ)/video
+
+OBJDIRS += \
+ $(EMUOBJ)/cpu \
+ $(EMUOBJ)/sound \
+ $(EMUOBJ)/debug \
+ $(EMUOBJ)/audio \
+ $(EMUOBJ)/drivers \
+ $(EMUOBJ)/machine \
+ $(EMUOBJ)/layout \
+ $(EMUOBJ)/video \
+
+
+
+#-------------------------------------------------
+# emulator core objects
+#-------------------------------------------------
+
+EMUOBJS = \
+ $(EMUOBJ)/attotime.o \
+ $(EMUOBJ)/audit.o \
+ $(EMUOBJ)/cheat.o \
+ $(EMUOBJ)/clifront.o \
+ $(EMUOBJ)/config.o \
+ $(EMUOBJ)/cpuexec.o \
+ $(EMUOBJ)/cpuint.o \
+ $(EMUOBJ)/cpuintrf.o \
+ $(EMUOBJ)/drawgfx.o \
+ $(EMUOBJ)/driver.o \
+ $(EMUOBJ)/emuopts.o \
+ $(EMUOBJ)/emupal.o \
+ $(EMUOBJ)/fileio.o \
+ $(EMUOBJ)/hash.o \
+ $(EMUOBJ)/info.o \
+ $(EMUOBJ)/input.o \
+ $(EMUOBJ)/inputseq.o \
+ $(EMUOBJ)/inptport.o \
+ $(EMUOBJ)/mame.o \
+ $(EMUOBJ)/mamecore.o \
+ $(EMUOBJ)/memory.o \
+ $(EMUOBJ)/output.o \
+ $(EMUOBJ)/render.o \
+ $(EMUOBJ)/rendfont.o \
+ $(EMUOBJ)/rendlay.o \
+ $(EMUOBJ)/rendutil.o \
+ $(EMUOBJ)/restrack.o \
+ $(EMUOBJ)/romload.o \
+ $(EMUOBJ)/sound.o \
+ $(EMUOBJ)/sndintrf.o \
+ $(EMUOBJ)/state.o \
+ $(EMUOBJ)/streams.o \
+ $(EMUOBJ)/tilemap.o \
+ $(EMUOBJ)/timer.o \
+ $(EMUOBJ)/ui.o \
+ $(EMUOBJ)/uigfx.o \
+ $(EMUOBJ)/uimenu.o \
+ $(EMUOBJ)/uitext.o \
+ $(EMUOBJ)/validity.o \
+ $(EMUOBJ)/video.o \
+
+ifdef PROFILER
+EMUOBJS += \
+ $(EMUOBJ)/profiler.o
+endif
+
+ifdef DEBUG
+EMUOBJS += \
+ $(EMUOBJ)/debug/debugcmd.o \
+ $(EMUOBJ)/debug/debugcmt.o \
+ $(EMUOBJ)/debug/debugcon.o \
+ $(EMUOBJ)/debug/debugcpu.o \
+ $(EMUOBJ)/debug/debughlp.o \
+ $(EMUOBJ)/debug/debugvw.o \
+ $(EMUOBJ)/debug/express.o \
+ $(EMUOBJ)/debug/textbuf.o
+endif
+
+EMUSOUNDOBJS = \
+ $(EMUOBJ)/sound/filter.o \
+ $(EMUOBJ)/sound/flt_vol.o \
+ $(EMUOBJ)/sound/flt_rc.o \
+ $(EMUOBJ)/sound/wavwrite.o \
+
+EMUAUDIOOBJS = \
+ $(EMUAUDIO)/generic.o \
+
+EMUDRIVEROBJS = \
+ $(EMUDRIVERS)/empty.o \
+
+EMUMACHINEOBJS = \
+ $(EMUMACHINE)/53c810.o \
+ $(EMUMACHINE)/6532riot.o \
+ $(EMUMACHINE)/6522via.o \
+ $(EMUMACHINE)/6526cia.o \
+ $(EMUMACHINE)/6821pia.o \
+ $(EMUMACHINE)/6840ptm.o \
+ $(EMUMACHINE)/6850acia.o \
+ $(EMUMACHINE)/7474.o \
+ $(EMUMACHINE)/74123.o \
+ $(EMUMACHINE)/74148.o \
+ $(EMUMACHINE)/74153.o \
+ $(EMUMACHINE)/74181.o \
+ $(EMUMACHINE)/8042kbdc.o \
+ $(EMUMACHINE)/8237dma.o \
+ $(EMUMACHINE)/8255ppi.o \
+ $(EMUMACHINE)/adc083x.o \
+ $(EMUMACHINE)/adc1213x.o \
+ $(EMUMACHINE)/am53cf96.o \
+ $(EMUMACHINE)/at28c16.o \
+ $(EMUMACHINE)/ds1302.o \
+ $(EMUMACHINE)/ds2401.o \
+ $(EMUMACHINE)/ds2404.o \
+ $(EMUMACHINE)/eeprom.o \
+ $(EMUMACHINE)/generic.o \
+ $(EMUMACHINE)/i2cmem.o \
+ $(EMUMACHINE)/idectrl.o \
+ $(EMUMACHINE)/intelfsh.o \
+ $(EMUMACHINE)/laserdsc.o \
+ $(EMUMACHINE)/mb3773.o \
+ $(EMUMACHINE)/mb87078.o \
+ $(EMUMACHINE)/mc146818.o \
+ $(EMUMACHINE)/msm6242.o \
+ $(EMUMACHINE)/pc16552d.o \
+ $(EMUMACHINE)/pci.o \
+ $(EMUMACHINE)/pic8259.o \
+ $(EMUMACHINE)/pit8253.o \
+ $(EMUMACHINE)/pd4990a.o \
+ $(EMUMACHINE)/roc10937.o \
+ $(EMUMACHINE)/rp5h01.o \
+ $(EMUMACHINE)/rtc65271.o \
+ $(EMUMACHINE)/scsi.o \
+ $(EMUMACHINE)/scsicd.o \
+ $(EMUMACHINE)/scsidev.o \
+ $(EMUMACHINE)/scsihd.o \
+ $(EMUMACHINE)/cr589.o \
+ $(EMUMACHINE)/smc91c9x.o \
+ $(EMUMACHINE)/timekpr.o \
+ $(EMUMACHINE)/tmp68301.o \
+ $(EMUMACHINE)/upd4701.o \
+ $(EMUMACHINE)/wd33c93.o \
+ $(EMUMACHINE)/x76f041.o \
+ $(EMUMACHINE)/x76f100.o \
+ $(EMUMACHINE)/z80ctc.o \
+ $(EMUMACHINE)/z80pio.o \
+ $(EMUMACHINE)/z80sio.o \
+
+EMUVIDEOOBJS = \
+ $(EMUVIDEO)/cdp1869.o \
+ $(EMUVIDEO)/crtc6845.o \
+ $(EMUVIDEO)/generic.o \
+ $(EMUVIDEO)/poly.o \
+ $(EMUVIDEO)/resnet.o \
+ $(EMUVIDEO)/s2636.o \
+ $(EMUVIDEO)/tlc34076.o \
+ $(EMUVIDEO)/tms34061.o \
+ $(EMUVIDEO)/tms9928a.o \
+ $(EMUVIDEO)/v9938.o \
+ $(EMUVIDEO)/vector.o \
+ $(EMUVIDEO)/voodoo.o \
+
+$(LIBEMU): $(EMUOBJS) $(EMUSOUNDOBJS) $(EMUAUDIOOBJS) $(EMUDRIVEROBJS) $(EMUMACHINEOBJS) $(EMUVIDEOOBJS)
+
+
+
+#-------------------------------------------------
+# CPU core objects
+#-------------------------------------------------
+
+include $(EMUSRC)/cpu/cpu.mak
+
+$(LIBCPU): $(CPUOBJS)
+
+ifdef DEBUG
+$(LIBCPU): $(DBGOBJS)
+endif
+
+
+
+#-------------------------------------------------
+# sound core objects
+#-------------------------------------------------
+
+include $(EMUSRC)/sound/sound.mak
+
+$(LIBSOUND): $(SOUNDOBJS)
+
+
+
+#-------------------------------------------------
+# additional dependencies
+#-------------------------------------------------
+
+$(EMUOBJ)/rendfont.o: $(EMUOBJ)/uismall.fh
+
+$(EMUOBJ)/video.o: $(EMUSRC)/rendersw.c
+
+
+
+#-------------------------------------------------
+# core layouts
+#-------------------------------------------------
+
+$(EMUOBJ)/rendlay.o: $(EMULAYOUT)/dualhovu.lh \
+ $(EMULAYOUT)/dualhsxs.lh \
+ $(EMULAYOUT)/dualhuov.lh \
+ $(EMULAYOUT)/horizont.lh \
+ $(EMULAYOUT)/triphsxs.lh \
+ $(EMULAYOUT)/vertical.lh \
+ $(EMULAYOUT)/ho20ffff.lh \
+ $(EMULAYOUT)/ho2eff2e.lh \
+ $(EMULAYOUT)/ho4f893d.lh \
+ $(EMULAYOUT)/ho88ffff.lh \
+ $(EMULAYOUT)/hoa0a0ff.lh \
+ $(EMULAYOUT)/hoffe457.lh \
+ $(EMULAYOUT)/hoffff20.lh \
+ $(EMULAYOUT)/voffff20.lh \
+
+$(EMUOBJ)/video.o: $(EMULAYOUT)/snap.lh
diff --git a/src/emu/emuopts.c b/src/emu/emuopts.c
new file mode 100644
index 00000000000..1b75f35b245
--- /dev/null
+++ b/src/emu/emuopts.c
@@ -0,0 +1,226 @@
+/***************************************************************************
+
+ emuopts.c
+
+ Options file and command line management.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "mamecore.h"
+#include "mame.h"
+#include "fileio.h"
+#include "emuopts.h"
+
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ BUILT-IN (CORE) OPTIONS
+***************************************************************************/
+
+const options_entry mame_core_options[] =
+{
+ /* unadorned options - only a single one supported at the moment */
+ { "<UNADORNED0>", NULL, 0, NULL },
+
+ /* config options */
+ { NULL, NULL, OPTION_HEADER, "CORE CONFIGURATION OPTIONS" },
+ { "readconfig;rc", "1", OPTION_BOOLEAN, "enable loading of configuration files" },
+
+ /* seach path options */
+ { NULL, NULL, OPTION_HEADER, "CORE SEARCH PATH OPTIONS" },
+ { "rompath;rp;biospath;bp", "roms", 0, "path to ROMsets and hard disk images" },
+#ifdef MESS
+ { "hashpath;hash_directory;hash","hash", 0, "path to hash files" },
+#endif /* MESS */
+ { "samplepath;sp", "samples", 0, "path to samplesets" },
+ { "artpath;artwork_directory", "artwork", 0, "path to artwork files" },
+ { "ctrlrpath;ctrlr_directory", "ctrlr", 0, "path to controller definitions" },
+ { "inipath", ".;ini", 0, "path to ini files" },
+ { "fontpath", ".", 0, "path to font files" },
+
+ /* output directory options */
+ { NULL, NULL, OPTION_HEADER, "CORE OUTPUT DIRECTORY OPTIONS" },
+ { "cfg_directory", "cfg", 0, "directory to save configurations" },
+ { "nvram_directory", "nvram", 0, "directory to save nvram contents" },
+ { "memcard_directory", "memcard", 0, "directory to save memory card contents" },
+ { "input_directory", "inp", 0, "directory to save input device logs" },
+ { "state_directory", "sta", 0, "directory to save states" },
+ { "snapshot_directory", "snap", 0, "directory to save screenshots" },
+ { "diff_directory", "diff", 0, "directory to save hard drive image difference files" },
+ { "comment_directory", "comments", 0, "directory to save debugger comments" },
+
+ /* filename options */
+ { NULL, NULL, OPTION_HEADER, "CORE FILENAME OPTIONS" },
+ { "cheat_file", "cheat.dat", 0, "cheat filename" },
+
+ /* state/playback options */
+ { NULL, NULL, OPTION_HEADER, "CORE STATE/PLAYBACK OPTIONS" },
+ { "state", NULL, 0, "saved state to load" },
+ { "autosave", "0", OPTION_BOOLEAN, "enable automatic restore at startup, and automatic save at exit time" },
+ { "playback;pb", NULL, 0, "playback an input file" },
+ { "record;rec", NULL, 0, "record an input file" },
+ { "mngwrite", NULL, 0, "optional filename to write a MNG movie of the current session" },
+ { "wavwrite", NULL, 0, "optional filename to write a WAV file of the current session" },
+
+ /* performance options */
+ { NULL, NULL, OPTION_HEADER, "CORE PERFORMANCE OPTIONS" },
+ { "autoframeskip;afs", "0", OPTION_BOOLEAN, "enable automatic frameskip selection" },
+ { "frameskip;fs(0-10)", "0", 0, "set frameskip to fixed value, 0-12 (autoframeskip must be disabled)" },
+ { "seconds_to_run;str", "0", 0, "number of emulated seconds to run before automatically exiting" },
+ { "throttle", "1", OPTION_BOOLEAN, "enable throttling to keep game running in sync with real time" },
+ { "sleep", "1", OPTION_BOOLEAN, "enable sleeping, which gives time back to other applications when idle" },
+ { "speed(0.01-100)", "1.0", 0, "controls the speed of gameplay, relative to realtime; smaller numbers are slower" },
+ { "refreshspeed;rs", "0", OPTION_BOOLEAN, "automatically adjusts the speed of gameplay to keep the refresh rate lower than the screen" },
+
+ /* rotation options */
+ { NULL, NULL, OPTION_HEADER, "CORE ROTATION OPTIONS" },
+ { "rotate", "1", OPTION_BOOLEAN, "rotate the game screen according to the game's orientation needs it" },
+ { "ror", "0", OPTION_BOOLEAN, "rotate screen clockwise 90 degrees" },
+ { "rol", "0", OPTION_BOOLEAN, "rotate screen counterclockwise 90 degrees" },
+ { "autoror", "0", OPTION_BOOLEAN, "automatically rotate screen clockwise 90 degrees if vertical" },
+ { "autorol", "0", OPTION_BOOLEAN, "automatically rotate screen counterclockwise 90 degrees if vertical" },
+ { "flipx", "0", OPTION_BOOLEAN, "flip screen left-right" },
+ { "flipy", "0", OPTION_BOOLEAN, "flip screen upside-down" },
+
+ /* artwork options */
+ { NULL, NULL, OPTION_HEADER, "CORE ARTWORK OPTIONS" },
+ { "artwork_crop;artcrop", "0", OPTION_BOOLEAN, "crop artwork to game screen size" },
+ { "use_backdrops;backdrop", "1", OPTION_BOOLEAN, "enable backdrops if artwork is enabled and available" },
+ { "use_overlays;overlay", "1", OPTION_BOOLEAN, "enable overlays if artwork is enabled and available" },
+ { "use_bezels;bezel", "1", OPTION_BOOLEAN, "enable bezels if artwork is enabled and available" },
+
+ /* screen options */
+ { NULL, NULL, OPTION_HEADER, "CORE SCREEN OPTIONS" },
+ { "brightness(0.1-2.0)", "1.0", 0, "default game screen brightness correction" },
+ { "contrast(0.1-2.0)", "1.0", 0, "default game screen contrast correction" },
+ { "gamma(0.1-3.0)", "1.0", 0, "default game screen gamma correction" },
+ { "pause_brightness(0.0-1.0)", "0.65", 0, "amount to scale the screen brightness when paused" },
+
+ /* vector options */
+ { NULL, NULL, OPTION_HEADER, "CORE VECTOR OPTIONS" },
+ { "antialias;aa", "1", OPTION_BOOLEAN, "use antialiasing when drawing vectors" },
+ { "beam", "1.0", 0, "set vector beam width" },
+ { "flicker", "0", 0, "set vector flicker effect" },
+
+ /* sound options */
+ { NULL, NULL, OPTION_HEADER, "CORE SOUND OPTIONS" },
+ { "sound", "1", OPTION_BOOLEAN, "enable sound output" },
+ { "samplerate;sr(1000-1000000)", "48000", 0, "set sound output sample rate" },
+ { "samples", "1", OPTION_BOOLEAN, "enable the use of external samples if available" },
+ { "volume;vol", "0", 0, "sound volume in decibels (-32 min, 0 max)" },
+
+ /* input options */
+ { NULL, NULL, OPTION_HEADER, "CORE INPUT OPTIONS" },
+ { "ctrlr", NULL, 0, "preconfigure for specified controller" },
+ { "mouse", "0", OPTION_BOOLEAN, "enable mouse input" },
+ { "joystick;joy", "0", OPTION_BOOLEAN, "enable joystick input" },
+ { "lightgun;gun", "0", OPTION_BOOLEAN, "enable lightgun input" },
+ { "multikeyboard;multikey", "0", OPTION_BOOLEAN, "enable separate input from each keyboard device (if present)" },
+ { "multimouse", "0", OPTION_BOOLEAN, "enable separate input from each mouse device (if present)" },
+ { "steadykey;steady", "0", OPTION_BOOLEAN, "enable steadykey support" },
+ { "offscreen_reload;reload", "0", OPTION_BOOLEAN, "convert lightgun button 2 into offscreen reload" },
+ { "joystick_map;joymap", "auto", 0, "explicit joystick map, or auto to auto-select" },
+ { "joystick_deadzone;joy_deadzone;jdz", "0.3", 0, "center deadzone range for joystick where change is ignored (0.0 center, 1.0 end)" },
+ { "joystick_saturation;joy_saturation;jsat", "0.85", 0, "end of axis saturation range for joystick where change is ignored (0.0 center, 1.0 end)" },
+
+ /* input autoenable options */
+ { NULL, NULL, OPTION_HEADER, "CORE INPUT AUTOMATIC ENABLE OPTIONS" },
+ { "paddle_device;paddle", "keyboard", 0, "enable (keyboard|mouse|joystick) if a paddle control is present" },
+ { "adstick_device;adstick", "keyboard", 0, "enable (keyboard|mouse|joystick) if an analog joystick control is present" },
+ { "pedal_device;pedal", "keyboard", 0, "enable (keyboard|mouse|joystick) if a pedal control is present" },
+ { "dial_device;dial", "keyboard", 0, "enable (keyboard|mouse|joystick) if a dial control is present" },
+ { "trackball_device;trackball", "keyboard", 0, "enable (keyboard|mouse|joystick) if a trackball control is present" },
+ { "lightgun_device", "keyboard", 0, "enable (keyboard|mouse|joystick) if a lightgun control is present" },
+ { "positional_device", "keyboard", 0, "enable (keyboard|mouse|joystick) if a positional control is present" },
+ { "mouse_device", "mouse", 0, "enable (keyboard|mouse|joystick) if a mouse control is present" },
+
+ /* debugging options */
+ { NULL, NULL, OPTION_HEADER, "CORE DEBUGGING OPTIONS" },
+ { "log", "0", OPTION_BOOLEAN, "generate an error.log file" },
+ { "verbose;v", "0", OPTION_BOOLEAN, "display additional diagnostic information" },
+#ifdef MAME_DEBUG
+ { "debug;d", "1", OPTION_BOOLEAN, "enable/disable debugger" },
+ { "debugscript", NULL, 0, "script for debugger" },
+#else
+ { "debug;d", "1", OPTION_DEPRECATED, "(debugger-only command)" },
+ { "debugscript", NULL, OPTION_DEPRECATED, "(debugger-only command)" },
+#endif
+
+ /* misc options */
+ { NULL, NULL, OPTION_HEADER, "CORE MISC OPTIONS" },
+ { "bios", "default", 0, "select the system BIOS to use" },
+ { "cheat;c", "0", OPTION_BOOLEAN, "enable cheat subsystem" },
+ { "skip_gameinfo", "0", OPTION_BOOLEAN, "skip displaying the information screen at startup" },
+
+ { NULL }
+};
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ memory_error - report a memory error
+-------------------------------------------------*/
+
+static void memory_error(const char *message)
+{
+ fatalerror("%s", message);
+}
+
+
+
+/*-------------------------------------------------
+ mame_puts_info
+ mame_puts_warning
+ mame_puts_error
+-------------------------------------------------*/
+
+static void mame_puts_info(const char *s)
+{
+ mame_printf_info("%s", s);
+}
+
+static void mame_puts_warning(const char *s)
+{
+ mame_printf_warning("%s", s);
+}
+
+static void mame_puts_error(const char *s)
+{
+ mame_printf_error("%s", s);
+}
+
+
+
+/*-------------------------------------------------
+ mame_options_init - create core MAME options
+-------------------------------------------------*/
+
+core_options *mame_options_init(const options_entry *entries)
+{
+ /* create MAME core options */
+ core_options *opts = options_create(memory_error);
+
+ /* set up output callbacks */
+ options_set_output_callback(opts, OPTMSG_INFO, mame_puts_info);
+ options_set_output_callback(opts, OPTMSG_WARNING, mame_puts_warning);
+ options_set_output_callback(opts, OPTMSG_ERROR, mame_puts_error);
+
+ options_add_entries(opts, mame_core_options);
+ if (entries != NULL)
+ options_add_entries(opts, entries);
+
+#ifdef MESS
+ mess_options_init(opts);
+#endif /* MESS */
+
+ return opts;
+}
diff --git a/src/emu/emuopts.h b/src/emu/emuopts.h
new file mode 100644
index 00000000000..982f2556826
--- /dev/null
+++ b/src/emu/emuopts.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+
+ emuopts.h
+
+ Options file and command line management.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __EMUOPTS_H__
+#define __EMUOPTS_H__
+
+#include "mamecore.h"
+#include "options.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* option priorities */
+#define OPTION_PRIORITY_CMDLINE OPTION_PRIORITY_HIGH
+#define OPTION_PRIORITY_INI OPTION_PRIORITY_NORMAL
+
+
+/* core options */
+#define OPTION_GAMENAME OPTION_UNADORNED(0)
+
+/* core configuration options */
+#define OPTION_READCONFIG "readconfig"
+
+/* core search path options */
+#define OPTION_ROMPATH "rompath"
+#ifdef MESS
+#define OPTION_HASHPATH "hashpath"
+#endif
+#define OPTION_SAMPLEPATH "samplepath"
+#define OPTION_ARTPATH "artpath"
+#define OPTION_CTRLRPATH "ctrlrpath"
+#define OPTION_INIPATH "inipath"
+#define OPTION_FONTPATH "fontpath"
+
+/* core directory options */
+#define OPTION_CFG_DIRECTORY "cfg_directory"
+#define OPTION_NVRAM_DIRECTORY "nvram_directory"
+#define OPTION_MEMCARD_DIRECTORY "memcard_directory"
+#define OPTION_INPUT_DIRECTORY "input_directory"
+#define OPTION_STATE_DIRECTORY "state_directory"
+#define OPTION_SNAPSHOT_DIRECTORY "snapshot_directory"
+#define OPTION_DIFF_DIRECTORY "diff_directory"
+#define OPTION_COMMENT_DIRECTORY "comment_directory"
+
+/* core filename options */
+#define OPTION_CHEAT_FILE "cheat_file"
+
+/* core state/playback options */
+#define OPTION_STATE "state"
+#define OPTION_AUTOSAVE "autosave"
+#define OPTION_PLAYBACK "playback"
+#define OPTION_RECORD "record"
+#define OPTION_MNGWRITE "mngwrite"
+#define OPTION_WAVWRITE "wavwrite"
+
+/* core performance options */
+#define OPTION_AUTOFRAMESKIP "autoframeskip"
+#define OPTION_FRAMESKIP "frameskip"
+#define OPTION_SECONDS_TO_RUN "seconds_to_run"
+#define OPTION_THROTTLE "throttle"
+#define OPTION_SLEEP "sleep"
+#define OPTION_SPEED "speed"
+#define OPTION_REFRESHSPEED "refreshspeed"
+
+/* core rotation options */
+#define OPTION_ROTATE "rotate"
+#define OPTION_ROR "ror"
+#define OPTION_ROL "rol"
+#define OPTION_AUTOROR "autoror"
+#define OPTION_AUTOROL "autorol"
+#define OPTION_FLIPX "flipx"
+#define OPTION_FLIPY "flipy"
+
+/* core artwork options */
+#define OPTION_ARTWORK_CROP "artwork_crop"
+#define OPTION_USE_BACKDROPS "use_backdrops"
+#define OPTION_USE_OVERLAYS "use_overlays"
+#define OPTION_USE_BEZELS "use_bezels"
+
+/* core screen options */
+#define OPTION_BRIGHTNESS "brightness"
+#define OPTION_CONTRAST "contrast"
+#define OPTION_GAMMA "gamma"
+#define OPTION_PAUSE_BRIGHTNESS "pause_brightness"
+
+/* core vector options */
+#define OPTION_ANTIALIAS "antialias"
+#define OPTION_BEAM "beam"
+#define OPTION_FLICKER "flicker"
+
+/* core sound options */
+#define OPTION_SOUND "sound"
+#define OPTION_SAMPLERATE "samplerate"
+#define OPTION_SAMPLES "samples"
+#define OPTION_VOLUME "volume"
+
+/* core input options */
+#define OPTION_CTRLR "ctrlr"
+#define OPTION_MOUSE "mouse"
+#define OPTION_JOYSTICK "joystick"
+#define OPTION_LIGHTGUN "lightgun"
+#define OPTION_MULTIKEYBOARD "multikeyboard"
+#define OPTION_MULTIMOUSE "multimouse"
+#define OPTION_PADDLE_DEVICE "paddle_device"
+#define OPTION_ADSTICK_DEVICE "adstick_device"
+#define OPTION_PEDAL_DEVICE "pedal_device"
+#define OPTION_DIAL_DEVICE "dial_device"
+#define OPTION_TRACKBALL_DEVICE "trackball_device"
+#define OPTION_LIGHTGUN_DEVICE "lightgun_device"
+#define OPTION_POSITIONAL_DEVICE "positional_device"
+#define OPTION_MOUSE_DEVICE "mouse_device"
+#define OPTION_JOYSTICK_MAP "joystick_map"
+#define OPTION_JOYSTICK_DEADZONE "joystick_deadzone"
+#define OPTION_JOYSTICK_SATURATION "joystick_saturation"
+#define OPTION_STEADYKEY "steadykey"
+#define OPTION_OFFSCREEN_RELOAD "offscreen_reload"
+
+/* core debugging options */
+#define OPTION_VERBOSE "verbose"
+#define OPTION_LOG "log"
+#define OPTION_DEBUG "debug"
+#define OPTION_DEBUGSCRIPT "debugscript"
+
+/* core misc options */
+#define OPTION_BIOS "bios"
+#define OPTION_CHEAT "cheat"
+#define OPTION_SKIP_GAMEINFO "skip_gameinfo"
+
+
+
+/***************************************************************************
+ GLOBALS
+***************************************************************************/
+
+extern const options_entry mame_core_options[];
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+core_options *mame_options_init(const options_entry *entries);
+
+#endif /* __EMUOPTS_H__ */
diff --git a/src/emu/emupal.c b/src/emu/emupal.c
new file mode 100644
index 00000000000..78440c3aa0c
--- /dev/null
+++ b/src/emu/emupal.c
@@ -0,0 +1,796 @@
+/******************************************************************************
+
+ emupal.c
+
+ Emulator palette handling functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+******************************************************************************/
+
+#include "driver.h"
+#include <math.h>
+
+#define VERBOSE 0
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define PEN_BRIGHTNESS_BITS 8
+#define MAX_PEN_BRIGHTNESS (4 << PEN_BRIGHTNESS_BITS)
+#define MAX_SHADOW_PRESETS 4
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* information about a shadow table */
+typedef struct _shadow_table_data shadow_table_data;
+struct _shadow_table_data
+{
+ UINT32 * base; /* pointer to the base of the table */
+ INT16 dr; /* delta red value */
+ INT16 dg; /* delta green value */
+ INT16 db; /* delta blue value */
+ UINT8 noclip; /* clip? */
+};
+
+
+/* typedef struct _palette_private palette_private; */
+struct _palette_private
+{
+ bitmap_format format; /* format assumed for palette data */
+
+ UINT32 shadow_group; /* index of the shadow group, or 0 if none */
+ UINT32 hilight_group; /* index of the hilight group, or 0 if none */
+
+ pen_t black_pen; /* precomputed black pen value */
+ pen_t white_pen; /* precomputed white pen value */
+
+ shadow_table_data shadow_table[MAX_SHADOW_PRESETS]; /* array of shadow table data */
+
+ pen_t * save_pen; /* pens for save/restore */
+ float * save_bright; /* brightness for save/restore */
+};
+
+
+/* typedef struct _colortable colortable; */
+struct _colortable
+{
+ running_machine * machine; /* associated machine */
+ UINT32 entries; /* number of entries */
+ UINT32 palentries; /* number of palette entries */
+ UINT16 * raw; /* raw data about each entry */
+ rgb_t * palette; /* palette entries */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void palette_presave(void);
+static void palette_postload(void);
+static void palette_exit(running_machine *machine);
+static void allocate_palette(running_machine *machine, palette_private *palette);
+static void allocate_color_tables(running_machine *machine, palette_private *palette);
+static void allocate_shadow_tables(running_machine *machine, palette_private *palette);
+static void configure_rgb_shadows(running_machine *machine, int mode, float factor);
+
+
+
+/***************************************************************************
+ INITIALIZATION AND CONFIGURATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_init - palette initialization that
+ takes place before the display is created
+-------------------------------------------------*/
+
+void palette_init(running_machine *machine)
+{
+ palette_private *palette = auto_malloc(sizeof(*palette));
+
+ /* request cleanup */
+ machine->palette_data = palette;
+ add_exit_callback(machine, palette_exit);
+
+ /* reset all our data */
+ memset(palette, 0, sizeof(*palette));
+ palette->format = machine->screen[0].format;
+
+ /* determine the color mode */
+ switch (palette->format)
+ {
+ case BITMAP_FORMAT_INDEXED16:
+ /* indexed modes are fine for everything */
+ break;
+
+ case BITMAP_FORMAT_RGB15:
+ case BITMAP_FORMAT_RGB32:
+ /* RGB modes can't use color tables */
+ assert(machine->drv->color_table_len == 0);
+ break;
+
+ case BITMAP_FORMAT_INVALID:
+ /* invalid format means no palette - or at least it should */
+ assert(machine->drv->total_colors == 0);
+ assert(machine->drv->color_table_len == 0);
+ return;
+
+ default:
+ fatalerror("Unsupported screen bitmap format!");
+ break;
+ }
+
+ /* allocate all the data structures */
+ if (machine->drv->total_colors > 0)
+ {
+ int numcolors;
+
+ allocate_palette(machine, palette);
+ allocate_color_tables(machine, palette);
+ allocate_shadow_tables(machine, palette);
+
+ /* set up save/restore of the palette */
+ numcolors = palette_get_num_colors(machine->palette);
+ palette->save_pen = auto_malloc(sizeof(*palette->save_pen) * numcolors);
+ palette->save_bright = auto_malloc(sizeof(*palette->save_bright) * numcolors);
+ state_save_register_global_pointer(palette->save_pen, numcolors);
+ state_save_register_global_pointer(palette->save_bright, numcolors);
+ state_save_register_func_presave(palette_presave);
+ state_save_register_func_postload(palette_postload);
+ }
+}
+
+
+/*-------------------------------------------------
+ palette_config - palette initialization that
+ takes place after the display is created
+-------------------------------------------------*/
+
+void palette_config(running_machine *machine)
+{
+ int total_colors = (machine->palette == NULL) ? 0 : palette_get_num_colors(machine->palette) * palette_get_num_groups(machine->palette);
+ pen_t *remapped_colortable = NULL;
+ UINT16 *colortable = NULL;
+ int i;
+
+ /* allocate memory for the colortables, if needed */
+ if (machine->drv->color_table_len > 0)
+ {
+ /* first for the raw colortable */
+ colortable = auto_malloc(machine->drv->color_table_len * sizeof(colortable[0]));
+ for (i = 0; i < machine->drv->color_table_len; i++)
+ colortable[i] = i % total_colors;
+
+ /* then for the remapped colortable */
+ remapped_colortable = auto_malloc(machine->drv->color_table_len * sizeof(remapped_colortable[0]));
+ }
+
+ /* now let the driver modify the initial palette and colortable */
+ if (machine->drv->init_palette)
+ (*machine->drv->init_palette)(machine, colortable, memory_region(REGION_PROMS));
+
+ /* now compute the remapped_colortable */
+ for (i = 0; i < machine->drv->color_table_len; i++)
+ {
+ pen_t color = colortable[i];
+
+ /* check for invalid colors set by machine->drv->init_palette */
+ assert(color < total_colors);
+ remapped_colortable[i] = machine->pens[color];
+ }
+
+ /* now we can set the final colortables */
+ machine->game_colortable = colortable;
+ machine->remapped_colortable = (remapped_colortable != NULL) ? remapped_colortable : machine->pens;
+
+ /* set the color table base for each graphics element */
+ for (i = 0; i < MAX_GFX_ELEMENTS; i++)
+ if (machine->gfx[i] != NULL)
+ machine->gfx[i]->color_base = machine->drv->gfxdecodeinfo[i].color_codes_start;
+}
+
+
+
+/***************************************************************************
+ SHADOW/HIGHLIGHT CONFIGURATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_set_shadow_factor - set the global
+ shadow brightness factor
+-------------------------------------------------*/
+
+void palette_set_shadow_factor(running_machine *machine, double factor)
+{
+ palette_private *palette = machine->palette_data;
+
+ assert(palette->shadow_group != 0);
+ palette_group_set_contrast(machine->palette, palette->shadow_group, factor);
+}
+
+
+/*-------------------------------------------------
+ palette_set_highlight_factor - set the global
+ highlight brightness factor
+-------------------------------------------------*/
+
+void palette_set_highlight_factor(running_machine *machine, double factor)
+{
+ palette_private *palette = machine->palette_data;
+
+ assert(palette->hilight_group != 0);
+ palette_group_set_contrast(machine->palette, palette->hilight_group, factor);
+}
+
+
+
+/***************************************************************************
+ SHADOW TABLE CONFIGURATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_set_shadow_mode(mode)
+
+ mode: 0 = use preset 0 (default shadow)
+ 1 = use preset 1 (default highlight)
+ 2 = use preset 2 *
+ 3 = use preset 3 *
+
+ * Preset 2 & 3 work independently under 32bpp,
+ supporting up to four different types of
+ shadows at one time. They mirror preset 1 & 2
+ in lower depth settings to maintain
+ compatibility.
+
+
+ palette_set_shadow_dRGB32(mode, dr, dg, db, noclip)
+
+ mode: 0 to 3 (which preset to configure)
+
+ dr: -255 to 255 ( red displacement )
+ dg: -255 to 255 ( green displacement )
+ db: -255 to 255 ( blue displacement )
+
+ noclip: 0 = resultant RGB clipped at 0x00/0xff
+ 1 = resultant RGB wraparound 0x00/0xff
+
+
+ * Color shadows only work under 32bpp.
+ This function has no effect in lower color
+ depths where
+
+ palette_set_shadow_factor() or
+ palette_set_highlight_factor()
+
+ should be used instead.
+
+ * 32-bit shadows are lossy. Even with zero RGB
+ displacements the affected area will still look
+ slightly darkened.
+
+ Drivers should ensure all shadow pens in
+ gfx_drawmode_table[] are set to DRAWMODE_NONE
+ when RGB displacements are zero to avoid the
+ darkening effect.
+-------------------------------------------------*/
+
+/*-------------------------------------------------
+ palette_set_shadow_mode - select 1 of 4
+ different live shadow tables
+-------------------------------------------------*/
+
+void palette_set_shadow_mode(running_machine *machine, int mode)
+{
+ palette_private *palette = machine->palette_data;
+ assert(mode >= 0 && mode < MAX_SHADOW_PRESETS);
+ machine->shadow_table = palette->shadow_table[mode].base;
+}
+
+
+/*-------------------------------------------------
+ palette_set_shadow_dRGB32 - configure delta
+ RGB values for 1 of 4 shadow tables
+-------------------------------------------------*/
+
+void palette_set_shadow_dRGB32(running_machine *machine, int mode, int dr, int dg, int db, int noclip)
+{
+ palette_private *palette = machine->palette_data;
+ shadow_table_data *stable = &palette->shadow_table[mode];
+ int i;
+
+ /* only applies to RGB direct modes */
+ assert(palette->format != BITMAP_FORMAT_INDEXED16);
+ assert(stable->base != NULL);
+
+ /* clamp the deltas (why?) */
+ if (dr < -0xff) dr = -0xff; else if (dr > 0xff) dr = 0xff;
+ if (dg < -0xff) dg = -0xff; else if (dg > 0xff) dg = 0xff;
+ if (db < -0xff) db = -0xff; else if (db > 0xff) db = 0xff;
+
+ /* early exit if nothing changed */
+ if (dr == stable->dr && dg == stable->dg && db == stable->db && noclip == stable->noclip)
+ return;
+ stable->dr = dr;
+ stable->dg = dg;
+ stable->db = db;
+ stable->noclip = noclip;
+
+ #if VERBOSE
+ popmessage("shadow %d recalc %d %d %d %02x", mode, dr, dg, db, noclip);
+ #endif
+
+ /* regenerate the table */
+ for (i = 0; i < 32768; i++)
+ {
+ int r = pal5bit(i >> 10) + dr;
+ int g = pal5bit(i >> 5) + dg;
+ int b = pal5bit(i >> 0) + db;
+ pen_t final;
+
+ /* apply clipping */
+ if (!noclip)
+ {
+ r = rgb_clamp(r);
+ g = rgb_clamp(g);
+ b = rgb_clamp(b);
+ }
+ final = MAKE_RGB(r, g, b);
+
+ /* store either 16 or 32 bit */
+ if (palette->format == BITMAP_FORMAT_RGB32)
+ stable->base[i] = final;
+ else
+ stable->base[i] = rgb_to_rgb15(final);
+ }
+}
+
+
+
+/***************************************************************************
+ COLORTABLE MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ colortable_alloc - allocate a new colortable
+ with the given number of entries
+-------------------------------------------------*/
+
+colortable *colortable_alloc(running_machine *machine, UINT32 palettesize)
+{
+ colortable *ctable;
+ UINT32 index;
+
+ /* allocate the colortable */
+ ctable = auto_malloc(sizeof(*ctable));
+ memset(ctable, 0, sizeof(*ctable));
+
+ /* fill in the basics */
+ ctable->machine = machine;
+ ctable->entries = machine->drv->total_colors;
+ ctable->palentries = palettesize;
+
+ /* allocate the raw colortable */
+ ctable->raw = auto_malloc(ctable->entries * sizeof(*ctable->raw));
+ for (index = 0; index < ctable->entries; index++)
+ ctable->raw[index] = index % ctable->palentries;
+ state_save_register_global_pointer(ctable->raw, ctable->entries);
+
+ /* allocate the palette */
+ ctable->palette = auto_malloc(ctable->palentries * sizeof(*ctable->palette));
+ for (index = 0; index < ctable->palentries; index++)
+ ctable->palette[index] = MAKE_ARGB(0x80,0xff,0xff,0xff);
+ state_save_register_global_pointer(ctable->palette, ctable->palentries);
+
+ return ctable;
+}
+
+
+/*-------------------------------------------------
+ colortable_entry_set_value - set the value
+ of a colortable entry
+-------------------------------------------------*/
+
+void colortable_entry_set_value(colortable *ctable, UINT32 entry, UINT16 value)
+{
+ /* ensure values are within range */
+ assert(entry < ctable->entries);
+ assert(value < ctable->palentries);
+
+ /* update if it has changed */
+ if (ctable->raw[entry] != value)
+ {
+ ctable->raw[entry] = value;
+ palette_set_color(ctable->machine, entry, ctable->palette[value]);
+ }
+}
+
+
+/*-------------------------------------------------
+ colortable_entry_get_value - return the value
+ of a colortable entry
+-------------------------------------------------*/
+
+UINT16 colortable_entry_get_value(colortable *ctable, UINT32 entry)
+{
+ assert(entry < ctable->entries);
+ return ctable->raw[entry];
+}
+
+
+/*-------------------------------------------------
+ colortable_palette_set_color - change the
+ color of a colortable palette entry
+-------------------------------------------------*/
+
+void colortable_palette_set_color(colortable *ctable, UINT32 entry, rgb_t color)
+{
+ /* ensure values are within range */
+ assert(entry < ctable->palentries);
+
+ /* alpha doesn't matter */
+ color &= 0xffffff;
+
+ /* update if it has changed */
+ if (ctable->palette[entry] != color)
+ {
+ UINT32 index;
+
+ ctable->palette[entry] = color;
+
+ /* update the palette for any colortable entries that reference it */
+ for (index = 0; index < ctable->entries; index++)
+ if (ctable->raw[index] == entry)
+ palette_set_color(ctable->machine, index, color);
+ }
+}
+
+
+/*-------------------------------------------------
+ colortable_entry_get_value - return the color
+ of a colortable palette entry
+-------------------------------------------------*/
+
+rgb_t colortable_palette_get_color(colortable *ctable, UINT32 entry)
+{
+ assert(entry < ctable->palentries);
+ return ctable->palette[entry];
+}
+
+
+/*-------------------------------------------------
+ colortable_get_transpen_mask - return a 32-bit
+ transparency mask for a given gfx element and
+ color
+-------------------------------------------------*/
+
+UINT32 colortable_get_transpen_mask(colortable *ctable, const gfx_element *gfx, int color, int transcolor)
+{
+ UINT32 entry = gfx->color_base + (color % gfx->total_colors) * gfx->color_granularity;
+ UINT32 mask = 0;
+ UINT32 count, bit;
+
+ /* make sure we are in range */
+ assert(entry < ctable->entries);
+ assert(gfx->color_depth <= 32);
+
+ /* either gfx->color_depth entries or as many as we can get up until the end */
+ count = MIN(gfx->color_depth, ctable->entries - entry);
+
+ /* set a bit anywhere the transcolor matches */
+ for (bit = 0; bit < count; bit++)
+ if (ctable->raw[entry++] == transcolor)
+ mask |= 1 << bit;
+
+ /* return the final mask */
+ return mask;
+}
+
+
+/*-------------------------------------------------
+ colortable_configure_tilemap_groups -
+ configure groups in a tilemap to represent
+ transparency based on colortable entries
+ (each group maps to a gfx color)
+-------------------------------------------------*/
+
+void colortable_configure_tilemap_groups(colortable *ctable, tilemap *tmap, const gfx_element *gfx, int transcolor)
+{
+ int color;
+
+ assert(gfx->total_colors <= TILEMAP_NUM_GROUPS);
+
+ /* iterate over all colors in the tilemap */
+ for (color = 0; color < gfx->total_colors; color++)
+ tilemap_set_transmask(tmap, color, colortable_get_transpen_mask(ctable, gfx, color, transcolor), 0);
+}
+
+
+
+/***************************************************************************
+ UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ get_black_pen - return the pen for a fixed
+ black color
+-------------------------------------------------*/
+
+pen_t get_black_pen(running_machine *machine)
+{
+ palette_private *palette = machine->palette_data;
+ return palette->black_pen;
+}
+
+
+/*-------------------------------------------------
+ get_white_pen - return the pen for a fixed
+ white color
+-------------------------------------------------*/
+
+pen_t get_white_pen(running_machine *machine)
+{
+ palette_private *palette = machine->palette_data;
+ return palette->white_pen;
+}
+
+
+
+/***************************************************************************
+ INTERNAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_presave - prepare the save arrays
+ for saving
+-------------------------------------------------*/
+
+static void palette_presave(void)
+{
+ int numcolors = palette_get_num_colors(Machine->palette);
+ palette_private *palette = Machine->palette_data;
+ int index;
+
+ /* fill the save arrays with updated pen and brightness information */
+ for (index = 0; index < numcolors; index++)
+ {
+ palette->save_pen[index] = palette_entry_get_color(Machine->palette, index);
+ palette->save_bright[index] = palette_entry_get_contrast(Machine->palette, index);
+ }
+}
+
+
+/*-------------------------------------------------
+ palette_postload - called after restore to
+ actually update the palette
+-------------------------------------------------*/
+
+static void palette_postload(void)
+{
+ int numcolors = palette_get_num_colors(Machine->palette);
+ palette_private *palette = Machine->palette_data;
+ int index;
+
+ /* reset the pen and brightness for each entry */
+ for (index = 0; index < numcolors; index++)
+ {
+ palette_entry_set_color(Machine->palette, index, palette->save_pen[index]);
+ palette_entry_set_contrast(Machine->palette, index, palette->save_bright[index]);
+ }
+}
+
+
+/*-------------------------------------------------
+ palette_exit - free any allocated memory
+-------------------------------------------------*/
+
+static void palette_exit(running_machine *machine)
+{
+ /* dereference the palette */
+ if (machine->palette != NULL)
+ palette_deref(machine->palette);
+}
+
+
+/*-------------------------------------------------
+ allocate_palette - allocate and configure the
+ palette object itself
+-------------------------------------------------*/
+
+static void allocate_palette(running_machine *machine, palette_private *palette)
+{
+ int numgroups, index;
+
+ /* determine the number of groups we need */
+ numgroups = 1;
+ if (machine->drv->video_attributes & VIDEO_HAS_SHADOWS)
+ palette->shadow_group = numgroups++;
+ if (machine->drv->video_attributes & VIDEO_HAS_HIGHLIGHTS)
+ palette->hilight_group = numgroups++;
+ assert_always(machine->drv->total_colors * numgroups <= 65536, "Error: palette has more than 65536 colors.");
+
+ /* allocate a palette object containing all the colors and groups */
+ machine->palette = palette_alloc(machine->drv->total_colors, numgroups);
+ assert_always(machine->palette != NULL, "Failed to allocate system palette");
+
+ /* configure the groups */
+ if (palette->shadow_group != 0)
+ palette_group_set_contrast(machine->palette, palette->shadow_group, PALETTE_DEFAULT_SHADOW_FACTOR);
+ if (palette->hilight_group != 0)
+ palette_group_set_contrast(machine->palette, palette->hilight_group, PALETTE_DEFAULT_HIGHLIGHT_FACTOR);
+
+ /* set the initial colors to a standard rainbow */
+ for (index = 0; index < machine->drv->total_colors; index++)
+ palette_entry_set_color(machine->palette, index, MAKE_RGB(pal1bit(index >> 0), pal1bit(index >> 1), pal1bit(index >> 2)));
+
+ /* switch off the color mode */
+ switch (palette->format)
+ {
+ /* 16-bit paletteized case */
+ case BITMAP_FORMAT_INDEXED16:
+ palette->black_pen = palette_get_black_entry(machine->palette);
+ palette->white_pen = palette_get_white_entry(machine->palette);
+ if (palette->black_pen >= 65536)
+ palette->black_pen = 0;
+ if (palette->white_pen >= 65536)
+ palette->white_pen = 65536;
+ break;
+
+ /* 15-bit direct case */
+ case BITMAP_FORMAT_RGB15:
+ palette->black_pen = rgb_to_rgb15(MAKE_RGB(0x00,0x00,0x00));
+ palette->white_pen = rgb_to_rgb15(MAKE_RGB(0xff,0xff,0xff));
+ break;
+
+ /* 32-bit direct case */
+ case BITMAP_FORMAT_RGB32:
+ palette->black_pen = MAKE_RGB(0x00,0x00,0x00);
+ palette->white_pen = MAKE_RGB(0xff,0xff,0xff);
+ break;
+
+ /* screenless case */
+ case BITMAP_FORMAT_INVALID:
+ default:
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ allocate_color_tables - allocate memory for
+ pen and color tables
+-------------------------------------------------*/
+
+static void allocate_color_tables(running_machine *machine, palette_private *palette)
+{
+ int total_colors = palette_get_num_colors(machine->palette) * palette_get_num_groups(machine->palette);
+ pen_t *pentable;
+ int i;
+
+ /* allocate memory for the pen table */
+ switch (palette->format)
+ {
+ case BITMAP_FORMAT_INDEXED16:
+ /* create a dummy 1:1 mapping */
+ machine->pens = pentable = auto_malloc((total_colors + 2) * sizeof(machine->pens[0]));
+ for (i = 0; i < total_colors + 2; i++)
+ pentable[i] = i;
+ break;
+
+ case BITMAP_FORMAT_RGB15:
+ machine->pens = palette_entry_list_adjusted_rgb15(machine->palette);
+ break;
+
+ case BITMAP_FORMAT_RGB32:
+ machine->pens = palette_entry_list_adjusted(machine->palette);
+ break;
+
+ default:
+ machine->pens = NULL;
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ allocate_shadow_tables - allocate memory for
+ shadow tables
+-------------------------------------------------*/
+
+static void allocate_shadow_tables(running_machine *machine, palette_private *palette)
+{
+ /* if we have shadows, allocate shadow tables */
+ if (machine->drv->video_attributes & VIDEO_HAS_SHADOWS)
+ {
+ pen_t *table = auto_malloc(65536 * sizeof(*table));
+ int i;
+
+ /* palettized mode gets a single 64k table in slots 0 and 2 */
+ if (palette->format == BITMAP_FORMAT_INDEXED16)
+ {
+ palette->shadow_table[0].base = palette->shadow_table[2].base = table;
+ for (i = 0; i < 65536; i++)
+ table[i] = (i < machine->drv->total_colors) ? (i + machine->drv->total_colors) : i;
+ }
+
+ /* RGB mode gets two 32k tables in slots 0 and 2 */
+ else
+ {
+ palette->shadow_table[0].base = table;
+ palette->shadow_table[2].base = table + 32768;
+ configure_rgb_shadows(machine, 0, PALETTE_DEFAULT_SHADOW_FACTOR);
+ }
+ }
+
+ /* if we have hilights, allocate shadow tables */
+ if (machine->drv->video_attributes & VIDEO_HAS_HIGHLIGHTS)
+ {
+ pen_t *table = auto_malloc(65536 * sizeof(*table));
+ int i;
+
+ /* palettized mode gets a single 64k table in slots 1 and 3 */
+ if (palette->format == BITMAP_FORMAT_INDEXED16)
+ {
+ palette->shadow_table[1].base = palette->shadow_table[3].base = table;
+ for (i = 0; i < 65536; i++)
+ table[i] = (i < machine->drv->total_colors) ? (i + 2 * machine->drv->total_colors) : i;
+ }
+
+ /* RGB mode gets two 32k tables in slots 1 and 3 */
+ else
+ {
+ palette->shadow_table[1].base = table;
+ palette->shadow_table[3].base = table + 32768;
+ configure_rgb_shadows(machine, 1, PALETTE_DEFAULT_HIGHLIGHT_FACTOR);
+ }
+ }
+
+ /* set the default table */
+ machine->shadow_table = palette->shadow_table[0].base;
+}
+
+
+/*-------------------------------------------------
+ configure_rgb_shadows - configure shadows
+ for the RGB tables
+-------------------------------------------------*/
+
+static void configure_rgb_shadows(running_machine *machine, int mode, float factor)
+{
+ palette_private *palette = machine->palette_data;
+ shadow_table_data *stable = &palette->shadow_table[mode];
+ int ifactor = (int)(factor * 256.0f);
+ int i;
+
+ /* only applies to RGB direct modes */
+ assert(palette->format != BITMAP_FORMAT_INDEXED16);
+ assert(stable->base != NULL);
+
+ #if VERBOSE
+ popmessage("shadow %d recalc %d %d %d %02x", mode, dr, dg, db, noclip);
+ #endif
+
+ /* regenerate the table */
+ for (i = 0; i < 32768; i++)
+ {
+ UINT8 r = rgb_clamp((pal5bit(i >> 10) * ifactor) >> 8);
+ UINT8 g = rgb_clamp((pal5bit(i >> 5) * ifactor) >> 8);
+ UINT8 b = rgb_clamp((pal5bit(i >> 0) * ifactor) >> 8);
+ pen_t final = MAKE_RGB(r, g, b);
+
+ /* store either 16 or 32 bit */
+ if (palette->format == BITMAP_FORMAT_RGB32)
+ stable->base[i] = final;
+ else
+ stable->base[i] = rgb_to_rgb15(final);
+ }
+}
diff --git a/src/emu/emupal.h b/src/emu/emupal.h
new file mode 100644
index 00000000000..8e6a58b7fa4
--- /dev/null
+++ b/src/emu/emupal.h
@@ -0,0 +1,250 @@
+/******************************************************************************
+
+ emupal.h
+
+ Emulator palette handling functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ There are several levels of abstraction in the way MAME handles the palette,
+ and several display modes which can be used by the drivers.
+
+ Palette
+ -------
+ Note: in the following text, "color" refers to a color in the emulated
+ game's virtual palette. For example, a game might be able to display 1024
+ colors at the same time. If the game uses RAM to change the available
+ colors, the term "palette" refers to the colors available at any given time,
+ not to the whole range of colors which can be produced by the hardware. The
+ latter is referred to as "color space".
+ The term "pen" refers to one of the maximum MAX_PENS colors that can be
+ used to generate the display.
+
+ So, to summarize, the three layers of palette abstraction are:
+
+ P1) The game virtual palette (the "colors")
+ P2) MAME's MAX_PENS colors palette (the "pens")
+ P3) The OS specific hardware color registers (the "OS specific pens")
+
+ The array Machine->pens[] is a lookup table which maps game colors to OS
+ specific pens (P1 to P3). When you are working on bitmaps at the pixel level,
+ *always* use Machine->pens to map the color numbers. *Never* use constants.
+ For example if you want to make pixel (x,y) of color 3, do:
+ *BITMAP_ADDR(bitmap, <type>, y, x) = Machine->pens[3];
+
+
+ Lookup table
+ ------------
+ Palettes are only half of the story. To map the gfx data to colors, the
+ graphics routines use a lookup table. For example if we have 4bpp tiles,
+ which can have 256 different color codes, the lookup table for them will have
+ 256 * 2^4 = 4096 elements. For games using a palette RAM, the lookup table is
+ usually a 1:1 map. For games using PROMs, the lookup table is often larger
+ than the palette itself so for example the game can display 256 colors out
+ of a palette of 16.
+
+ The palette and the lookup table are initialized to default values by the
+ main core, but can be initialized by the driver using the function
+ MachineDriver->vh_init_palette(). For games using palette RAM, that
+ function is usually not needed, and the lookup table can be set up by
+ properly initializing the color_codes_start and total_color_codes fields in
+ the GfxDecodeInfo array.
+ When vh_init_palette() initializes the lookup table, it maps gfx codes
+ to game colors (P1 above). The lookup table will be converted by the core to
+ map to OS specific pens (P3 above), and stored in Machine->remapped_colortable.
+
+
+ Display modes
+ -------------
+ The available display modes can be summarized in three categories:
+ 1) Static palette. Use this for games which use PROMs for color generation.
+ The palette is initialized by palette_init(), and never changed
+ again.
+ 2) Dynamic palette. Use this for games which use RAM for color generation.
+ The palette can be dynamically modified by the driver using the function
+ palette_set_color().
+ 3) Direct mapped 16-bit or 32-bit color. This should only be used in special
+ cases, e.g. to support alpha blending.
+ MachineDriver->video_attributes must contain VIDEO_RGB_DIRECT.
+
+
+ Shadows(Highlights) Quick Reference
+ -----------------------------------
+
+ 1) declare MDRV_VIDEO_ATTRIBUTES( ... VIDEO_HAS_SHADOWS | VIDEO_HAS_HIGHLIGHTS ... )
+
+ 2) set gfx_drawmode_table[0-n] to DRAWMODE_NONE, DRAWMODE_SOURCE or DRAWMODE_SHADOW
+
+ 3) (optional) set shadow darkness or highlight brightness by
+ palette_set_shadow_factor(0.0-1.0) or
+ palette_set_highlight_factor(1.0-n.n)
+
+ 4) before calling drawgfx use
+ palette_set_shadow_mode(0) to arm shadows or
+ palette_set_shadow_mode(1) to arm highlights
+
+ 5) call drawgfx with the TRANSPARENCY_PEN_TABLE flag
+ drawgfx( ..., cliprect, TRANSPARENCY_PEN_TABLE, transparent_color )
+
+******************************************************************************/
+
+#pragma once
+
+#ifndef __EMUPAL_H__
+#define __EMUPAL_H__
+
+#include "palette.h"
+#include "memory.h"
+#include "tilemap.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define PALETTE_DEFAULT_SHADOW_FACTOR (0.6)
+#define PALETTE_DEFAULT_HIGHLIGHT_FACTOR (1/PALETTE_DEFAULT_SHADOW_FACTOR)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _colortable colortable;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- initialization and configuration ----- */
+
+/* palette initialization that takes place before the display is created */
+void palette_init(running_machine *machine);
+
+/* palette initialization that takes place after the display is created */
+void palette_config(running_machine *machine);
+
+
+
+/* ----- shadow/hilight configuration ----- */
+
+/* set the global shadow brightness factor */
+void palette_set_shadow_factor(running_machine *machine, double factor);
+
+/* set the global highlight brightness factor */
+void palette_set_highlight_factor(running_machine *machine, double factor);
+
+
+
+/* ----- shadow table configuration ----- */
+
+/* select 1 of 4 different live shadow tables */
+void palette_set_shadow_mode(running_machine *machine, int mode);
+
+/* configure delta RGB values for 1 of 4 shadow tables */
+void palette_set_shadow_dRGB32(running_machine *machine, int mode, int dr, int dg, int db, int noclip);
+
+
+
+/* ----- colortable management ----- */
+
+/* allocate a new colortable with the given number of entries */
+colortable *colortable_alloc(running_machine *machine, UINT32 palettesize);
+
+/* set the value of a colortable entry */
+void colortable_entry_set_value(colortable *ctable, UINT32 entry, UINT16 value);
+
+/* return the value of a colortable entry */
+UINT16 colortable_entry_get_value(colortable *ctable, UINT32 entry);
+
+/* change the color of a colortable palette entry */
+void colortable_palette_set_color(colortable *ctable, UINT32 entry, rgb_t color);
+
+/* return the color of a colortable palette entry */
+rgb_t colortable_palette_get_color(colortable *ctable, UINT32 entry);
+
+/* return a 32-bit transparency mask for a given gfx element and color */
+UINT32 colortable_get_transpen_mask(colortable *ctable, const gfx_element *gfx, int color, int transcolor);
+
+/* configure groups in a tilemap to represent transparency based on colortable entries (each group maps to a gfx color) */
+void colortable_configure_tilemap_groups(colortable *ctable, tilemap *tmap, const gfx_element *gfx, int transcolor);
+
+
+
+/* ----- utilities ----- */
+
+/* return the pen for a fixed black color */
+pen_t get_black_pen(running_machine *machine);
+
+/* return the pen for a fixed white color */
+pen_t get_white_pen(running_machine *machine);
+
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_set_color - set a single palette
+ entry
+-------------------------------------------------*/
+
+INLINE void palette_set_color(running_machine *machine, pen_t pen, rgb_t rgb)
+{
+ palette_entry_set_color(machine->palette, pen, rgb);
+}
+
+
+/*-------------------------------------------------
+ palette_set_color_rgb - set a single palette
+ entry with individual R,G,B components
+-------------------------------------------------*/
+
+INLINE void palette_set_color_rgb(running_machine *machine, pen_t pen, UINT8 r, UINT8 g, UINT8 b)
+{
+ palette_entry_set_color(machine->palette, pen, MAKE_RGB(r, g, b));
+}
+
+
+/*-------------------------------------------------
+ palette_get_color - return a single palette
+ entry
+-------------------------------------------------*/
+
+INLINE rgb_t palette_get_color(running_machine *machine, pen_t pen)
+{
+ return palette_entry_get_color(machine->palette, pen);
+}
+
+
+/*-------------------------------------------------
+ palette_set_brightness - set the per-pen
+ brightness factor
+-------------------------------------------------*/
+
+INLINE void palette_set_brightness(running_machine *machine, pen_t pen, double bright)
+{
+ palette_entry_set_contrast(machine->palette, pen, bright);
+}
+
+
+/*-------------------------------------------------
+ palette_set_colors - set multiple palette
+ entries from an array of rgb_t values
+-------------------------------------------------*/
+
+INLINE void palette_set_colors(running_machine *machine, pen_t color_base, const rgb_t *colors, int color_count)
+{
+ while (color_count--)
+ palette_entry_set_color(machine->palette, color_base++, *colors++);
+}
+
+
+#endif /* __PALETTE_H__ */
diff --git a/src/emu/fileio.c b/src/emu/fileio.c
new file mode 100644
index 00000000000..482e12804fd
--- /dev/null
+++ b/src/emu/fileio.c
@@ -0,0 +1,839 @@
+/***************************************************************************
+
+ fileio.c
+
+ File access functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "osdepend.h"
+#include "corefile.h"
+#include "astring.h"
+#include "driver.h"
+#include "chd.h"
+#include "hash.h"
+#include "unzip.h"
+#include "options.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define PLAIN_FILE 0
+#define ZIPPED_FILE 1
+
+#define OPEN_FLAG_HAS_CRC 0x10000
+
+#ifdef MAME_DEBUG
+#define DEBUG_COOKIE 0xbaadf00d
+#endif
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* typedef struct _mame_file mame_file -- declared in fileio.h */
+struct _mame_file
+{
+#ifdef DEBUG_COOKIE
+ UINT32 debug_cookie; /* sanity checking for debugging */
+#endif
+ core_file * file; /* core file pointer */
+ UINT32 openflags; /* flags we used for the open */
+ char hash[HASH_BUF_SIZE]; /* hash data for the file */
+ zip_file * zipfile; /* ZIP file pointer */
+ UINT8 * zipdata; /* ZIP file data */
+ UINT64 ziplength; /* ZIP file length */
+};
+
+
+typedef struct _path_iterator path_iterator;
+struct _path_iterator
+{
+ const char * base;
+ const char * cur;
+ int index;
+};
+
+
+/* typedef struct _mame_path mame_path -- declared in fileio.h */
+struct _mame_path
+{
+ path_iterator iterator;
+ osd_directory * curdir;
+ astring * pathbuffer;
+ int buflen;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* core functions */
+static void fileio_exit(running_machine *machine);
+
+/* file open/close */
+static file_error fopen_internal(core_options *opts, const char *searchpath, const char *filename, UINT32 crc, UINT32 flags, mame_file **file);
+static file_error fopen_attempt_zipped(astring *fullname, UINT32 crc, UINT32 openflags, mame_file *file);
+
+/* path iteration */
+static void path_iterator_init(path_iterator *iterator, core_options *opts, const char *searchpath);
+static int path_iterator_get_next(path_iterator *iterator, astring *buffer);
+
+/* misc helpers */
+static file_error load_zipped_file(mame_file *file);
+static int zip_filename_match(const zip_file_header *header, const astring *afilename);
+
+
+
+/***************************************************************************
+ CORE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ fileio_init - initialize the internal file
+ I/O system; note that the OS layer is free to
+ call mame_fopen before fileio_init
+-------------------------------------------------*/
+
+void fileio_init(running_machine *machine)
+{
+ add_exit_callback(machine, fileio_exit);
+}
+
+
+/*-------------------------------------------------
+ fileio_exit - clean up behind ourselves
+-------------------------------------------------*/
+
+static void fileio_exit(running_machine *machine)
+{
+ zip_file_cache_clear();
+}
+
+
+
+/***************************************************************************
+ FILE OPEN/CLOSE
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_fopen - open a file for access and
+ return an error code
+-------------------------------------------------*/
+
+file_error mame_fopen(const char *searchpath, const char *filename, UINT32 openflags, mame_file **file)
+{
+ return fopen_internal(mame_options(), searchpath, filename, 0, openflags, file);
+}
+
+
+/*-------------------------------------------------
+ mame_fopen_crc - open a file by name or CRC
+ and return an error code
+-------------------------------------------------*/
+
+file_error mame_fopen_crc(const char *searchpath, const char *filename, UINT32 crc, UINT32 openflags, mame_file **file)
+{
+ return mame_fopen_crc_options(mame_options(), searchpath, filename, crc, openflags, file);
+}
+
+
+/*-------------------------------------------------
+ mame_fopen_options - open a file for access and
+ return an error code
+-------------------------------------------------*/
+
+file_error mame_fopen_options(core_options *opts, const char *searchpath, const char *filename, UINT32 openflags, mame_file **file)
+{
+ return fopen_internal(opts, searchpath, filename, 0, openflags, file);
+}
+
+
+/*-------------------------------------------------
+ mame_fopen_crc_options - open a file by name
+ or CRC and return an error code
+-------------------------------------------------*/
+
+file_error mame_fopen_crc_options(core_options *opts, const char *searchpath, const char *filename, UINT32 crc, UINT32 openflags, mame_file **file)
+{
+ return fopen_internal(opts, searchpath, filename, crc, openflags | OPEN_FLAG_HAS_CRC, file);
+}
+
+
+/*-------------------------------------------------
+ mame_fopen_ram - open a "file" which is
+ actually just an array of data in RAM
+-------------------------------------------------*/
+
+file_error mame_fopen_ram(const void *data, UINT32 length, UINT32 openflags, mame_file **file)
+{
+ file_error filerr;
+
+ /* allocate the file itself */
+ *file = malloc(sizeof(**file));
+ if (*file == NULL)
+ return FILERR_OUT_OF_MEMORY;
+
+ /* reset the file handle */
+ memset(*file, 0, sizeof(**file));
+ (*file)->openflags = openflags;
+#ifdef DEBUG_COOKIE
+ (*file)->debug_cookie = DEBUG_COOKIE;
+#endif
+
+ /* attempt to open the file directly */
+ filerr = core_fopen_ram(data, length, openflags, &(*file)->file);
+ if (filerr == FILERR_NONE)
+ goto error;
+
+ /* handle errors and return */
+error:
+ if (filerr != FILERR_NONE)
+ {
+ mame_fclose(*file);
+ *file = NULL;
+ }
+ return filerr;
+}
+
+
+/*-------------------------------------------------
+ fopen_internal - open a file
+-------------------------------------------------*/
+
+static file_error fopen_internal(core_options *opts, const char *searchpath, const char *filename, UINT32 crc, UINT32 openflags, mame_file **file)
+{
+ file_error filerr = FILERR_NOT_FOUND;
+ path_iterator iterator;
+ astring *fullname;
+
+ /* can either have a hash or open for write, but not both */
+ if ((openflags & OPEN_FLAG_HAS_CRC) && (openflags & OPEN_FLAG_WRITE))
+ return FILERR_INVALID_ACCESS;
+
+ /* allocate the file itself */
+ *file = malloc(sizeof(**file));
+ if (*file == NULL)
+ return FILERR_OUT_OF_MEMORY;
+
+ /* reset the file handle */
+ memset(*file, 0, sizeof(**file));
+ (*file)->openflags = openflags;
+#ifdef DEBUG_COOKIE
+ (*file)->debug_cookie = DEBUG_COOKIE;
+#endif
+
+ /* if the path is absolute, null out the search path */
+ if (searchpath != NULL && osd_is_absolute_path(searchpath))
+ searchpath = NULL;
+
+ /* determine the maximum length of a composed filename, plus some extra space for .zip extensions */
+ path_iterator_init(&iterator, opts, searchpath);
+
+ /* loop over paths */
+ fullname = astring_alloc();
+ while (path_iterator_get_next(&iterator, fullname))
+ {
+ /* compute the full pathname */
+ if (astring_len(fullname) > 0)
+ astring_catc(fullname, PATH_SEPARATOR);
+ astring_catc(fullname, filename);
+
+ /* attempt to open the file directly */
+ filerr = core_fopen(astring_c(fullname), openflags, &(*file)->file);
+ if (filerr == FILERR_NONE)
+ break;
+
+ /* if we're opening for read-only we have other options */
+ if ((openflags & (OPEN_FLAG_READ | OPEN_FLAG_WRITE)) == OPEN_FLAG_READ)
+ {
+ filerr = fopen_attempt_zipped(fullname, crc, openflags, *file);
+ if (filerr == FILERR_NONE)
+ break;
+ }
+ }
+ astring_free(fullname);
+
+ /* handle errors and return */
+ if (filerr != FILERR_NONE)
+ {
+ mame_fclose(*file);
+ *file = NULL;
+ }
+ return filerr;
+}
+
+
+/*-------------------------------------------------
+ fopen_attempt_zipped - attempt to open a
+ ZIPped file
+-------------------------------------------------*/
+
+static file_error fopen_attempt_zipped(astring *fullname, UINT32 crc, UINT32 openflags, mame_file *file)
+{
+ astring *filename = astring_alloc();
+ zip_error ziperr;
+ zip_file *zip;
+
+ /* loop over directory parts up to the start of filename */
+ while (1)
+ {
+ const zip_file_header *header;
+ int dirsep;
+
+ /* find the final path separator */
+ dirsep = astring_rchr(fullname, 0, PATH_SEPARATOR[0]);
+ if (dirsep == -1)
+ {
+ astring_free(filename);
+ return FILERR_NOT_FOUND;
+ }
+
+ /* insert the part from the right of the separator into the head of the filename */
+ if (astring_len(filename) > 0)
+ astring_insc(filename, 0, "/");
+ astring_inssubstr(filename, 0, fullname, dirsep + 1, -1);
+
+ /* remove this part of the filename and append a .zip extension */
+ astring_substr(fullname, 0, dirsep);
+ astring_catc(fullname, ".zip");
+
+ /* attempt to open the ZIP file */
+ ziperr = zip_file_open(astring_c(fullname), &zip);
+
+ /* chop the .zip back off the filename before continuing */
+ astring_substr(fullname, 0, dirsep);
+
+ /* if we failed to open this file, continue scanning */
+ if (ziperr != ZIPERR_NONE)
+ continue;
+
+ /* see if we can find a file with the right name and (if available) crc */
+ for (header = zip_file_first_file(zip); header != NULL; header = zip_file_next_file(zip))
+ if (zip_filename_match(header, filename) && (!(openflags & OPEN_FLAG_HAS_CRC) || header->crc == crc))
+ break;
+
+ /* if that failed, look for a file with the right crc, but the wrong filename */
+ if (header == NULL && (openflags & OPEN_FLAG_HAS_CRC))
+ for (header = zip_file_first_file(zip); header != NULL; header = zip_file_next_file(zip))
+ if (header->crc == crc)
+ break;
+
+ /* if that failed, look for a file with the right name; reporting a bad checksum */
+ /* is more helpful and less confusing than reporting "rom not found" */
+ if (header == NULL)
+ for (header = zip_file_first_file(zip); header != NULL; header = zip_file_next_file(zip))
+ if (zip_filename_match(header, filename))
+ break;
+
+ /* if we got it, read the data */
+ if (header != NULL)
+ {
+ UINT8 crcs[4];
+
+ file->zipfile = zip;
+ file->ziplength = header->uncompressed_length;
+
+ /* build a hash with just the CRC */
+ hash_data_clear(file->hash);
+ crcs[0] = header->crc >> 24;
+ crcs[1] = header->crc >> 16;
+ crcs[2] = header->crc >> 8;
+ crcs[3] = header->crc >> 0;
+ hash_data_insert_binary_checksum(file->hash, HASH_CRC, crcs);
+
+ astring_free(filename);
+ return FILERR_NONE;
+ }
+
+ /* close up the ZIP file and try the next level */
+ zip_file_close(zip);
+ }
+}
+
+
+/*-------------------------------------------------
+ mame_fclose - closes a file
+-------------------------------------------------*/
+
+void mame_fclose(mame_file *file)
+{
+#ifdef DEBUG_COOKIE
+ assert(file->debug_cookie == DEBUG_COOKIE);
+ file->debug_cookie = 0;
+#endif
+
+ /* close files and free memory */
+ if (file->zipfile != NULL)
+ zip_file_close(file->zipfile);
+ if (file->file != NULL)
+ core_fclose(file->file);
+ if (file->zipdata != NULL)
+ free(file->zipdata);
+ free(file);
+}
+
+
+
+/***************************************************************************
+ FILE POSITIONING
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_fseek - seek within a file
+-------------------------------------------------*/
+
+int mame_fseek(mame_file *file, INT64 offset, int whence)
+{
+ /* load the ZIP file now if we haven't yet */
+ if (file->zipfile != NULL)
+ load_zipped_file(file);
+
+ /* seek if we can */
+ if (file->file != NULL)
+ return core_fseek(file->file, offset, whence);
+
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ mame_ftell - return the current file position
+-------------------------------------------------*/
+
+UINT64 mame_ftell(mame_file *file)
+{
+ /* load the ZIP file now if we haven't yet */
+ if (file->zipfile != NULL)
+ load_zipped_file(file);
+
+ /* tell if we can */
+ if (file->file != NULL)
+ return core_ftell(file->file);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ mame_feof - return 1 if we're at the end
+ of file
+-------------------------------------------------*/
+
+int mame_feof(mame_file *file)
+{
+ /* load the ZIP file now if we haven't yet */
+ if (file->zipfile != NULL)
+ load_zipped_file(file);
+
+ /* return EOF if we can */
+ if (file->file != NULL)
+ return core_feof(file->file);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ mame_fsize - returns the size of a file
+-------------------------------------------------*/
+
+UINT64 mame_fsize(mame_file *file)
+{
+ /* use the ZIP length if present */
+ if (file->zipfile != NULL)
+ return file->ziplength;
+
+ /* return length if we can */
+ if (file->file != NULL)
+ return core_fsize(file->file);
+
+ return 0;
+}
+
+
+
+/***************************************************************************
+ FILE READ
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_fread - read from a file
+-------------------------------------------------*/
+
+UINT32 mame_fread(mame_file *file, void *buffer, UINT32 length)
+{
+ /* load the ZIP file now if we haven't yet */
+ if (file->zipfile != NULL)
+ load_zipped_file(file);
+
+ /* read the data if we can */
+ if (file->file != NULL)
+ return core_fread(file->file, buffer, length);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ mame_fgetc - read a character from a file
+-------------------------------------------------*/
+
+int mame_fgetc(mame_file *file)
+{
+ /* load the ZIP file now if we haven't yet */
+ if (file->zipfile != NULL)
+ load_zipped_file(file);
+
+ /* read the data if we can */
+ if (file->file != NULL)
+ return core_fgetc(file->file);
+
+ return EOF;
+}
+
+
+/*-------------------------------------------------
+ mame_ungetc - put back a character read from
+ a file
+-------------------------------------------------*/
+
+int mame_ungetc(int c, mame_file *file)
+{
+ /* load the ZIP file now if we haven't yet */
+ if (file->zipfile != NULL)
+ load_zipped_file(file);
+
+ /* read the data if we can */
+ if (file->file != NULL)
+ return core_ungetc(c, file->file);
+
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ mame_fgets - read a line from a text file
+-------------------------------------------------*/
+
+char *mame_fgets(char *s, int n, mame_file *file)
+{
+ /* load the ZIP file now if we haven't yet */
+ if (file->zipfile != NULL)
+ load_zipped_file(file);
+
+ /* read the data if we can */
+ if (file->file != NULL)
+ return core_fgets(s, n, file->file);
+
+ return NULL;
+}
+
+
+
+/***************************************************************************
+ FILE WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_fwrite - write to a file
+-------------------------------------------------*/
+
+UINT32 mame_fwrite(mame_file *file, const void *buffer, UINT32 length)
+{
+ /* write the data if we can */
+ if (file->file != NULL)
+ return core_fwrite(file->file, buffer, length);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ mame_fputs - write a line to a text file
+-------------------------------------------------*/
+
+int mame_fputs(mame_file *file, const char *s)
+{
+ /* write the data if we can */
+ if (file->file != NULL)
+ return core_fputs(file->file, s);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ mame_vfprintf - vfprintf to a text file
+-------------------------------------------------*/
+
+static int mame_vfprintf(mame_file *file, const char *fmt, va_list va)
+{
+ /* write the data if we can */
+ return (file->file != NULL) ? core_vfprintf(file->file, fmt, va) : 0;
+}
+
+
+/*-------------------------------------------------
+ mame_fprintf - vfprintf to a text file
+-------------------------------------------------*/
+
+int CLIB_DECL mame_fprintf(mame_file *file, const char *fmt, ...)
+{
+ int rc;
+ va_list va;
+ va_start(va, fmt);
+ rc = mame_vfprintf(file, fmt, va);
+ va_end(va);
+ return rc;
+}
+
+
+
+/***************************************************************************
+ FILE ENUMERATION
+***************************************************************************/
+
+
+/*-------------------------------------------------
+ mame_openpath - open a search path (multiple
+ directories) for iteration
+-------------------------------------------------*/
+
+mame_path *mame_openpath(core_options *opts, const char *searchpath)
+{
+ mame_path *path;
+
+ /* allocate a new mame_path */
+ path = malloc(sizeof(*path));
+ if (path == NULL)
+ return NULL;
+ memset(path, 0, sizeof(*path));
+
+ /* initialize the iterator */
+ path_iterator_init(&path->iterator, opts, searchpath);
+
+ /* allocate a buffer to hold the current path */
+ path->pathbuffer = astring_alloc();
+ return path;
+}
+
+
+/*-------------------------------------------------
+ mame_readpath - return information about the
+ next file in the search path
+-------------------------------------------------*/
+
+const osd_directory_entry *mame_readpath(mame_path *path)
+{
+ const osd_directory_entry *result;
+
+ /* loop over potentially empty directories */
+ while (1)
+ {
+ /* if no open directory, get the next path */
+ while (path->curdir == NULL)
+ {
+ /* if we fail to get anything more, we're done */
+ if (!path_iterator_get_next(&path->iterator, path->pathbuffer))
+ return NULL;
+
+ /* open the path */
+ path->curdir = osd_opendir(astring_c(path->pathbuffer));
+ }
+
+ /* get the next entry from the current directory */
+ result = osd_readdir(path->curdir);
+ if (result != NULL)
+ return result;
+
+ /* we're done; close this directory */
+ osd_closedir(path->curdir);
+ path->curdir = NULL;
+ }
+}
+
+
+/*-------------------------------------------------
+ mame_closepath - close an open seach path
+-------------------------------------------------*/
+
+void mame_closepath(mame_path *path)
+{
+ /* close anything open */
+ if (path->curdir != NULL)
+ osd_closedir(path->curdir);
+
+ /* free memory */
+ if (path->pathbuffer != NULL)
+ astring_free(path->pathbuffer);
+ free(path);
+}
+
+
+
+/***************************************************************************
+ MISCELLANEOUS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_core_file - return the core_file
+ underneath the mame_file
+-------------------------------------------------*/
+
+core_file *mame_core_file(mame_file *file)
+{
+ /* load the ZIP file now if we haven't yet */
+ if (file->zipfile != NULL)
+ load_zipped_file(file);
+
+ /* return the core file */
+ return file->file;
+}
+
+
+/*-------------------------------------------------
+ mame_fhash - returns the hash for a file
+-------------------------------------------------*/
+
+const char *mame_fhash(mame_file *file, UINT32 functions)
+{
+ const UINT8 *filedata;
+ UINT32 wehave;
+
+ /* if we already have the functions we need, just return */
+ wehave = hash_data_used_functions(file->hash);
+ if ((wehave & functions) == functions)
+ return file->hash;
+
+ /* load the ZIP file now if we haven't yet */
+ if (file->zipfile != NULL)
+ load_zipped_file(file);
+ if (file->file == NULL)
+ return file->hash;
+
+ /* read the data if we can */
+ filedata = core_fbuffer(file->file);
+ if (filedata == NULL)
+ return file->hash;
+
+ /* compute the hash */
+ hash_compute(file->hash, filedata, core_fsize(file->file), wehave | functions);
+ return file->hash;
+}
+
+
+
+/***************************************************************************
+ PATH ITERATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ path_iterator_init - prepare to iterate over
+ a given path type
+-------------------------------------------------*/
+
+static void path_iterator_init(path_iterator *iterator, core_options *opts, const char *searchpath)
+{
+ /* reset the structure */
+ memset(iterator, 0, sizeof(*iterator));
+ iterator->base = (searchpath != NULL) ? options_get_string(opts, searchpath) : "";
+ iterator->cur = iterator->base;
+}
+
+
+/*-------------------------------------------------
+ path_iterator_get_next - get the next entry
+ in a multipath sequence
+-------------------------------------------------*/
+
+static int path_iterator_get_next(path_iterator *iterator, astring *buffer)
+{
+ const char *semi;
+
+ /* if none left, return FALSE to indicate we are done */
+ if (iterator->index != 0 && *iterator->cur == 0)
+ return FALSE;
+
+ /* copy up to the next semicolon */
+ semi = strchr(iterator->cur, ';');
+ if (semi == NULL)
+ semi = iterator->cur + strlen(iterator->cur);
+ astring_cpych(buffer, iterator->cur, semi - iterator->cur);
+ iterator->cur = (*semi == 0) ? semi : semi + 1;
+
+ /* bump the index and return TRUE */
+ iterator->index++;
+ return TRUE;
+}
+
+
+
+/***************************************************************************
+ MISC HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ load_zipped_file - load a ZIPped file
+-------------------------------------------------*/
+
+static file_error load_zipped_file(mame_file *file)
+{
+ file_error filerr;
+ zip_error ziperr;
+
+ assert(file->file == NULL);
+ assert(file->zipdata == NULL);
+ assert(file->zipfile != NULL);
+
+ /* allocate some memory */
+ file->zipdata = malloc(file->ziplength);
+ if (file->zipdata == NULL)
+ return FILERR_OUT_OF_MEMORY;
+
+ /* read the data into our buffer and return */
+ ziperr = zip_file_decompress(file->zipfile, file->zipdata, file->ziplength);
+ if (ziperr != ZIPERR_NONE)
+ {
+ free(file->zipdata);
+ file->zipdata = NULL;
+ return FILERR_FAILURE;
+ }
+
+ /* convert to RAM file */
+ filerr = core_fopen_ram(file->zipdata, file->ziplength, file->openflags, &file->file);
+ if (filerr != FILERR_NONE)
+ {
+ free(file->zipdata);
+ file->zipdata = NULL;
+ return FILERR_FAILURE;
+ }
+
+ /* close out the ZIP file */
+ zip_file_close(file->zipfile);
+ file->zipfile = NULL;
+ return FILERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ zip_filename_match - compare zip filename
+ to expected filename, ignoring any directory
+-------------------------------------------------*/
+
+static int zip_filename_match(const zip_file_header *header, const astring *filename)
+{
+ const char *zipfile = header->filename + header->filename_length - astring_len(filename);
+
+ return (zipfile >= header->filename && astring_icmpc(filename, zipfile) == 0 &&
+ (zipfile == header->filename || zipfile[-1] == '/'));
+}
diff --git a/src/emu/fileio.h b/src/emu/fileio.h
new file mode 100644
index 00000000000..7c0f4a23b92
--- /dev/null
+++ b/src/emu/fileio.h
@@ -0,0 +1,170 @@
+/***************************************************************************
+
+ fileio.h
+
+ Core file I/O interface functions and definitions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __FILEIO_H__
+#define __FILEIO_H__
+
+#include "mamecore.h"
+#include "osdcore.h"
+#include "corefile.h"
+#include "mame.h"
+#include "emuopts.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* search paths */
+#define SEARCHPATH_RAW NULL
+#define SEARCHPATH_CHEAT NULL
+#define SEARCHPATH_LANGUAGE NULL
+#define SEARCHPATH_DEBUGLOG NULL
+
+#define SEARCHPATH_ROM OPTION_ROMPATH
+#ifdef MESS
+#define SEARCHPATH_IMAGE NULL
+#define SEARCHPATH_HASH OPTION_HASHPATH
+#else
+#define SEARCHPATH_IMAGE OPTION_ROMPATH
+#define SEARCHPATH_HASH NULL
+#endif
+#define SEARCHPATH_SAMPLE OPTION_SAMPLEPATH
+#define SEARCHPATH_ARTWORK OPTION_ARTPATH
+#define SEARCHPATH_CTRLR OPTION_CTRLRPATH
+#define SEARCHPATH_INI OPTION_INIPATH
+#define SEARCHPATH_FONT OPTION_FONTPATH
+
+#define SEARCHPATH_IMAGE_DIFF OPTION_DIFF_DIRECTORY
+#define SEARCHPATH_NVRAM OPTION_NVRAM_DIRECTORY
+#define SEARCHPATH_CONFIG OPTION_CFG_DIRECTORY
+#define SEARCHPATH_INPUTLOG OPTION_INPUT_DIRECTORY
+#define SEARCHPATH_STATE OPTION_STATE_DIRECTORY
+#define SEARCHPATH_MEMCARD OPTION_MEMCARD_DIRECTORY
+#define SEARCHPATH_SCREENSHOT OPTION_SNAPSHOT_DIRECTORY
+#define SEARCHPATH_MOVIE OPTION_SNAPSHOT_DIRECTORY
+#define SEARCHPATH_COMMENT OPTION_COMMENT_DIRECTORY
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _mame_path mame_path;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- core initialization ----- */
+
+/* initialize the fileio system */
+void fileio_init(running_machine *machine);
+
+
+
+/* ----- file open/close ----- */
+
+/* open a file in the given search path with the specified filename */
+file_error mame_fopen(const char *searchpath, const char *filename, UINT32 openflags, mame_file **file);
+
+/* open a file in the given search path with the specified filename or a matching CRC */
+file_error mame_fopen_crc(const char *searchpath, const char *filename, UINT32 crc, UINT32 openflags, mame_file **file);
+
+/* open a file in the given search path with the specified filename, using the specified options */
+file_error mame_fopen_options(core_options *opts, const char *searchpath, const char *filename, UINT32 openflags, mame_file **file);
+
+/* open a file in the given search path with the specified filename or a matching CRC, using the specified options */
+file_error mame_fopen_crc_options(core_options *opts, const char *searchpath, const char *filename, UINT32 crc, UINT32 openflags, mame_file **file);
+
+/* open a "file" which is actually data in RAM */
+file_error mame_fopen_ram(const void *data, UINT32 length, UINT32 openflags, mame_file **file);
+
+/* close an open file */
+void mame_fclose(mame_file *file);
+
+
+
+/* ----- file positioning ----- */
+
+/* adjust the file pointer within the file */
+int mame_fseek(mame_file *file, INT64 offset, int whence);
+
+/* return the current file pointer */
+UINT64 mame_ftell(mame_file *file);
+
+/* return true if we are at the EOF */
+int mame_feof(mame_file *file);
+
+/* return the total size of the file */
+UINT64 mame_fsize(mame_file *file);
+
+
+
+/* ----- file read ----- */
+
+/* standard binary read from a file */
+UINT32 mame_fread(mame_file *file, void *buffer, UINT32 length);
+
+/* read one character from the file */
+int mame_fgetc(mame_file *file);
+
+/* put back one character from the file */
+int mame_ungetc(int c, mame_file *file);
+
+/* read a full line of text from the file */
+char *mame_fgets(char *s, int n, mame_file *file);
+
+
+
+/* ----- file write ----- */
+
+/* standard binary write to a file */
+UINT32 mame_fwrite(mame_file *file, const void *buffer, UINT32 length);
+
+/* write a line of text to the file */
+int mame_fputs(mame_file *f, const char *s);
+
+/* printf-style text write to a file */
+int CLIB_DECL mame_fprintf(mame_file *f, const char *fmt, ...);
+
+
+
+/* ----- file enumeration ----- */
+
+/* open a search path (multiple directories) for iteration */
+mame_path *mame_openpath(core_options *opts, const char *searchpath);
+
+/* return information about the next file in the search path */
+const osd_directory_entry *mame_readpath(mame_path *path);
+
+/* close an open seach path */
+void mame_closepath(mame_path *path);
+
+
+
+/* ----- file misc ----- */
+
+/* return the core_file underneath the mame_file */
+core_file *mame_core_file(mame_file *file);
+
+/* return a hash string for the file with the given functions */
+const char *mame_fhash(mame_file *file, UINT32 functions);
+
+
+#endif /* __FILEIO_H__ */
diff --git a/src/emu/hash.c b/src/emu/hash.c
new file mode 100644
index 00000000000..5c3a293d604
--- /dev/null
+++ b/src/emu/hash.c
@@ -0,0 +1,713 @@
+/*********************************************************************
+
+ hash.c
+
+ Function to handle hash functions (checksums)
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ Started by Farfetch'd
+
+*********************************************************************/
+
+/*
+ * Changelog:
+ *
+ * 20030314: Farfetch'd
+ * First release
+ *
+ */
+
+/*
+ * DONE:
+ *
+ * hash.c/h: New files, implement the new hashing engine with flexible
+ * support for more functions (for now, CRC, SHA1 and MD5).
+ *
+ * common.h: transparently support the new RomModule structure through
+ * ROM_* macros, so that old the legacy code still work
+ *
+ * common.c: updated ROM loading engine to support the new hash engine,
+ * using it to verify ROM integrity at load-time. Updated printromlist()
+ * (-listroms) to dump all the available checksums, and if a ROM is
+ * known to be bad or not.
+ *
+ * info.c: -listinfo now supports any hashing function correctly
+ * (both text and XML mode). Notice that XML header should be
+ * rewritten to automatically define the new tags when new
+ * functions are added, but I couldn't be bothered for now.
+ * It also displays informations about baddump/nodump
+ *
+ * audit.c/h: Updated audit engine (-verifyroms) to use the new
+ * hash functions.
+ *
+ * fileio.c/h: Updated file engine to use the new hash functions.
+ * It is now possible to load by any specified checksum (in case
+ * later we support other archivers with SHA1 signatures or
+ * equivalent). If the file is open with flag VERIFY_ONLY and
+ * the file is within an archive (zip), only the checksums
+ * available in the archive header are used.
+ *
+ * windows/fronthlp.c: Updated -identrom to the new hash engine, now
+ * support any hash function available.
+ * Added -listsha1 and -listmd5. It would be possible to add
+ * also a -listbad now, to list bad dumps (ROMS we need a
+ * redump for)
+ * Updated -listdupcrc to check for all the available checksums.
+ * The output is also a bit more useful and readable, even if it
+ * is still not optimal.
+ * Update -listwrongmerge to check for all the available checksums.
+ *
+ * windows/fileio.c: Removed check for FILE_TYPE_NOCRC (does not exist
+ * anymore).
+ *
+ *
+ *
+ * Technical details:
+ *
+ * Checksum informations are now stored inside a string. They are
+ * stored in "printable hex format", which means that they use
+ * more memory than before (since a CRC needs 8 characters to
+ * be printed, instead of 4 bytes of raw information). In the
+ * driver, they are defined with handy macros which rely on
+ * automatic string pasting.
+ *
+ * Additional flags can also be stored in the string: for now we
+ * support NO_DUMP and BAD_DUMP, which replace, respectively,
+ * a CRC of 0 and a bit-inverted CRC.
+ *
+ * All the code that handles hash data is in hash.c. The rest of
+ * the core treats the data as an 'opaque type', so that the
+ * pointers are just passed along through functions but no
+ * operation is performed on the data outside hash.c. This
+ * is important in case we want to change the string
+ * representation later in the future.
+ *
+ * When loading a ROM, MAME will calculate and compare the
+ * checksum using any function for which the driver has declared
+ * an expected checksum. This happens because it would be useless
+ * to calculate a checksum if we cannot verify its correctness.
+ * For developers, it also means that MAME will not compute the
+ * SHA1 for you unless you specify a bogus one in the driver
+ * (like SHA1(0)).
+ *
+ * When verifying a ROM, MAME will use only the checksums available
+ * in the archive header (if zip, CRC). This is by design because
+ * -verifyroms has always been very fast. It is feasible to add
+ * a -fullverifyroms at a later moment, which will decompress the
+ * files and compute every checksum that has been declared in the
+ * driver.
+ *
+ * I have also prepared a little tool (SHA1Merger) which takes care
+ * of the following tasks:
+ *
+ * - Given an existing driver in old syntax (0.66 compatible), it will
+ * convert all the existing ROM_LOAD entries in the new format, and
+ * it will automatically compute and add SHA1 checksum for you if
+ * it can find the romset.
+ *
+ * - Given a romset (ZIP file), it will prepare a ROM definition
+ * skeleton for a driver, containing already rom names, lengths, and
+ * checksums (both CRC and SHA1).
+ *
+ * The tool is available on www.mame.net as platform-independent source code
+ * (in Python), or win32 standalone executable.
+ *
+ */
+
+#include <stddef.h>
+#include <ctype.h>
+#include <zlib.h>
+#include "hash.h"
+#include "md5.h"
+#include "sha1.h"
+#include "mame.h"
+#include "romload.h"
+
+#define ASSERT(x)
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+struct _hash_function_desc
+{
+ const char* name; // human-readable name
+ char code; // single-char code used within the hash string
+ unsigned int size; // checksum size in bytes
+
+ // Functions used to calculate the hash of a memory block
+ void (*calculate_begin)(void);
+ void (*calculate_buffer)(const void* mem, unsigned long len);
+ void (*calculate_end)(UINT8* bin_chksum);
+
+};
+typedef struct _hash_function_desc hash_function_desc;
+
+static void h_crc_begin(void);
+static void h_crc_buffer(const void* mem, unsigned long len);
+static void h_crc_end(UINT8* chksum);
+
+static void h_sha1_begin(void);
+static void h_sha1_buffer(const void* mem, unsigned long len);
+static void h_sha1_end(UINT8* chksum);
+
+static void h_md5_begin(void);
+static void h_md5_buffer(const void* mem, unsigned long len);
+static void h_md5_end(UINT8* chksum);
+
+static const hash_function_desc hash_descs[HASH_NUM_FUNCTIONS] =
+{
+ {
+ "crc", 'c', 4,
+ h_crc_begin,
+ h_crc_buffer,
+ h_crc_end
+ },
+
+ {
+ "sha1", 's', 20,
+ h_sha1_begin,
+ h_sha1_buffer,
+ h_sha1_end
+ },
+
+ {
+ "md5", 'm', 16,
+ h_md5_begin,
+ h_md5_buffer,
+ h_md5_end
+ },
+};
+
+static const char* info_strings[] =
+{
+ "$ND$", // No dump
+ "$BD$" // Bad dump
+};
+
+static const char binToStr[] = "0123456789abcdef";
+
+
+static const hash_function_desc* hash_get_function_desc(unsigned int function)
+{
+ unsigned int idx = 0;
+
+ // Calling with zero in here is mostly an internal error
+ ASSERT(function != 0);
+
+ // Compute the index of only one function
+ while (!(function & 1))
+ {
+ idx++;
+ function >>= 1;
+ }
+
+ // Specify only one bit or die
+ ASSERT(function == 1);
+
+ return &hash_descs[idx];
+}
+
+const char* hash_function_name(unsigned int function)
+{
+ const hash_function_desc* info = hash_get_function_desc(function);
+
+ return info->name;
+}
+
+int hash_data_has_checksum(const char* data, unsigned int function)
+{
+ const hash_function_desc* info = hash_get_function_desc(function);
+ char str[3];
+ const char* res;
+
+ str[0] = info->code;
+ str[1] = ':';
+ str[2] = '\0';
+
+ // Check if the specified hash function is used within this data
+ res = strstr(data, str);
+
+ if (!res)
+ return 0;
+
+ // Return the offset within the string where the checksum begins
+ return (res - data + 2);
+}
+
+static int hash_data_add_binary_checksum(char* d, unsigned int function, const UINT8* checksum)
+{
+ const hash_function_desc* desc = hash_get_function_desc(function);
+ char* start = d;
+ unsigned i;
+
+ *d++ = desc->code;
+ *d++ = ':';
+
+ for (i=0;i<desc->size;i++)
+ {
+ UINT8 c = *checksum++;
+
+ *d++ = binToStr[(c >> 4) & 0xF];
+ *d++ = binToStr[(c >> 0) & 0xF];
+ }
+
+ *d++ = '#';
+
+ // Return the number of written bytes
+ return (d - start);
+}
+
+
+static int hash_compare_checksum(const char* chk1, const char* chk2, int length)
+{
+ char c1, c2;
+
+ // The printable format is twice as longer
+ length *= 2;
+
+ // This is basically a case-insensitive string compare
+ while (length--)
+ {
+ c1 = *chk1++;
+ c2 = *chk2++;
+
+ if (tolower(c1) != tolower(c2))
+ return 0;
+ if (!c1)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+// Compare two hashdata
+int hash_data_is_equal(const char* d1, const char* d2, unsigned int functions)
+{
+ int i;
+ char incomplete = 0;
+ char ok = 0;
+
+ // If no function is specified, it means we need to check for all
+ // of them
+ if (!functions)
+ functions = ~functions;
+
+ for (i=1; i != (1<<HASH_NUM_FUNCTIONS); i<<=1)
+ if (functions & i)
+ {
+ int offs1, offs2;
+
+ // Check if both hashdata contain the current function's checksum
+ offs1 = hash_data_has_checksum(d1, i);
+ offs2 = hash_data_has_checksum(d2, i);
+
+ if (offs1 && offs2)
+ {
+ const hash_function_desc* info = hash_get_function_desc(i);
+
+ if (!hash_compare_checksum(d1+offs1, d2+offs2, info->size))
+ return 0;
+
+ ok = 1;
+ }
+ // If the function was contained only in one, remember that our comparison
+ // is incomplete
+ else if (offs1 || offs2)
+ {
+ incomplete = 1;
+ }
+ }
+
+ // If we could not compare any function, return error
+ if (!ok)
+ return 0;
+
+ // Return success code
+ return (incomplete ? 2 : 1);
+}
+
+
+int hash_data_extract_printable_checksum(const char* data, unsigned int function, char* checksum)
+{
+ unsigned int i;
+ const hash_function_desc* info;
+ int offs;
+
+ // Check if the hashdata contains the requested function
+ offs = hash_data_has_checksum(data, function);
+
+ if (!offs)
+ return 0;
+
+ // Move to the beginning of the checksum
+ data += offs;
+
+ info = hash_get_function_desc(function);
+
+ // Return the number of required bytes
+ if (!checksum)
+ return info->size*2+1;
+
+ // If the terminator is not found at the right position,
+ // return a full-zero checksum and warn about it. This is mainly
+ // for developers putting checksums of '0' or '1' to ask MAME
+ // to compute the correct values for them.
+ if (data[info->size*2] != '#')
+ {
+ memset(checksum, '0', info->size*2);
+ checksum[info->size*2] = '\0';
+ return 2;
+ }
+
+ // If it contains invalid hexadecimal characters,
+ // treat the checksum as zero and return warning
+ for (i=0;i<info->size*2;i++)
+ if (!(data[i]>='0' && data[i]<='9') &&
+ !(data[i]>='a' && data[i]<='f') &&
+ !(data[i]>='A' && data[i]<='F'))
+ {
+ memset(checksum, '0', info->size*2);
+ checksum[info->size*2] = '\0';
+ return 2;
+ }
+
+ // Copy the checksum (and make it lowercase)
+ for (i=0;i<info->size*2;i++)
+ checksum[i] = tolower(data[i]);
+
+ checksum[info->size*2] = '\0';
+
+ return 1;
+}
+
+static int hex_string_to_binary(unsigned char* binary, const char* data, int size)
+{
+ unsigned int i;
+ char c;
+
+ for (i = 0; i < size * 2; i++)
+ {
+ c = tolower(*data++);
+
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c -= 'a' - 10;
+ else
+ return 1;
+
+ if (i % 2 == 0)
+ binary[i / 2] = c * 16;
+ else
+ binary[i / 2] += c;
+ }
+ return 0;
+}
+
+int hash_data_extract_binary_checksum(const char* data, unsigned int function, unsigned char* checksum)
+{
+ const hash_function_desc* info;
+ int offs;
+
+ // Check if the hashdata contains the requested function
+ offs = hash_data_has_checksum(data, function);
+
+ if (!offs)
+ return 0;
+
+ // Move to the beginning of the checksum
+ data += offs;
+
+ info = hash_get_function_desc(function);
+
+ // Return the number of required bytes
+ if (!checksum)
+ return info->size;
+
+ // Clear the checksum array
+ memset(checksum, 0, info->size);
+
+ // If the terminator is not found at the right position,
+ // return a full-zero checksum and warn about it. This is mainly
+ // for developers putting checksums of '0' or '1' to ask MAME
+ // to compute the correct values for them.
+ if (data[info->size*2] != '#')
+ {
+ memset(checksum, '\0', info->size);
+ return 2;
+ }
+
+ // Convert hex string into binary
+ if (hex_string_to_binary(checksum, data, info->size))
+ {
+ // Invalid character: the checksum is treated as zero,
+ // and a warning is returned
+ memset(checksum, '\0', info->size);
+ return 2;
+ }
+
+ return 1;
+}
+
+int hash_data_has_info(const char* data, unsigned int info)
+{
+ char* res = strstr(data, info_strings[info]);
+
+ if (!res)
+ return 0;
+
+ return 1;
+}
+
+void hash_data_copy(char* dst, const char* src)
+{
+ // Copying string is enough
+ strcpy(dst, src);
+}
+
+void hash_data_clear(char* dst)
+{
+ // Clear the buffer
+ memset(dst, 0, HASH_BUF_SIZE);
+}
+
+unsigned int hash_data_used_functions(const char* data)
+{
+ int i;
+ unsigned int res = 0;
+
+ if (!data)
+ return 0;
+
+ for (i=0;i<HASH_NUM_FUNCTIONS;i++)
+ if (hash_data_has_checksum(data, 1<<i))
+ res |= 1<<i;
+
+ return res;
+}
+
+int hash_data_insert_printable_checksum(char* d, unsigned int function, const char* checksum)
+{
+ const hash_function_desc* desc;
+ UINT8 binary_checksum[20];
+
+ desc = hash_get_function_desc(function);
+
+ ASSERT(desc->size <= sizeof(binary_checksum));
+
+ if (hex_string_to_binary(binary_checksum, checksum, desc->size))
+ return 2;
+
+ return hash_data_insert_binary_checksum(d, function, binary_checksum);
+}
+
+int hash_data_insert_binary_checksum(char* d, unsigned int function, const UINT8* checksum)
+{
+ int offset;
+
+ offset = hash_data_has_checksum(d, function);
+
+ if (!offset)
+ {
+ d += strlen(d);
+ d += hash_data_add_binary_checksum(d, function, checksum);
+ *d = '\0';
+
+ return 1;
+ }
+ else
+ {
+ // Move to the start of the whole checksum signature, not only to the checksum
+ // itself
+ d += offset - 2;
+
+ // Overwrite previous checksum with new one
+ hash_data_add_binary_checksum(d, function, checksum);
+
+ return 2;
+ }
+}
+
+void hash_compute(char* dst, const unsigned char* data, unsigned long length, unsigned int functions)
+{
+ int i;
+
+ hash_data_clear(dst);
+
+ // Zero means use all the functions
+ if (functions == 0)
+ functions = ~functions;
+
+ for (i=0;i<HASH_NUM_FUNCTIONS;i++)
+ {
+ unsigned func = 1 << i;
+
+ if (functions & func)
+ {
+ const hash_function_desc* desc = hash_get_function_desc(func);
+ UINT8 chksum[256];
+
+ desc->calculate_begin();
+ desc->calculate_buffer(data, length);
+ desc->calculate_end(chksum);
+
+ dst += hash_data_add_binary_checksum(dst, func, chksum);
+ }
+ }
+
+ *dst = '\0';
+}
+
+void hash_data_print(const char* data, unsigned int functions, char* buffer)
+{
+ int i, j;
+ char first = 1;
+
+ if (functions == 0)
+ functions = ~functions;
+
+ buffer[0] = '\0';
+
+ for (i=0;i<HASH_NUM_FUNCTIONS;i++)
+ {
+ unsigned func = 1 << i;
+
+ if ((functions & func) && hash_data_has_checksum(data, func))
+ {
+ char temp[256];
+
+ if (!first)
+ strcat(buffer, " ");
+ first = 0;
+
+ strcpy(temp, hash_function_name(func));
+ for (j = 0; temp[j]; j++)
+ temp[j] = toupper(temp[j]);
+ strcat(buffer, temp);
+ strcat(buffer, "(");
+
+ hash_data_extract_printable_checksum(data, func, temp);
+ strcat(buffer, temp);
+ strcat(buffer, ")");
+ }
+ }
+}
+
+int hash_verify_string(const char *hash)
+{
+ int len, i;
+
+ if (!hash)
+ return FALSE;
+
+ while(*hash)
+ {
+ if (*hash == '$')
+ {
+ if (memcmp(hash, NO_DUMP, 4) && memcmp(hash, BAD_DUMP, 4))
+ return FALSE;
+ hash += 4;
+ }
+ else
+ {
+ /* first make sure that the next char is a colon */
+ if (hash[1] != ':')
+ return FALSE;
+
+ /* search for a hash function for this code */
+ for (i = 0; i < sizeof(hash_descs) / sizeof(hash_descs[0]); i++)
+ {
+ if (*hash == hash_descs[i].code)
+ break;
+ }
+ if (i >= sizeof(hash_descs) / sizeof(hash_descs[0]))
+ return FALSE;
+
+ /* we have a proper code */
+ len = hash_descs[i].size * 2;
+ hash += 2;
+
+ for (i = 0; (hash[i] != '#') && (i < len); i++)
+ {
+ if (!isxdigit(hash[i]))
+ return FALSE;
+ }
+ if (hash[i] != '#')
+ return FALSE;
+
+ hash += i+1;
+ }
+ }
+ return TRUE;
+}
+
+
+
+/*********************************************************************
+ Hash functions - Wrappers
+ *********************************************************************/
+
+static UINT32 crc;
+
+static void h_crc_begin(void)
+{
+ crc = 0;
+}
+
+static void h_crc_buffer(const void* mem, unsigned long len)
+{
+ crc = crc32(crc, (UINT8*)mem, len);
+}
+
+static void h_crc_end(UINT8* bin_chksum)
+{
+ bin_chksum[0] = (UINT8)(crc >> 24);
+ bin_chksum[1] = (UINT8)(crc >> 16);
+ bin_chksum[2] = (UINT8)(crc >> 8);
+ bin_chksum[3] = (UINT8)(crc >> 0);
+}
+
+
+static struct sha1_ctx sha1ctx;
+
+static void h_sha1_begin(void)
+{
+ sha1_init(&sha1ctx);
+}
+
+static void h_sha1_buffer(const void* mem, unsigned long len)
+{
+ sha1_update(&sha1ctx, len, (UINT8*)mem);
+}
+
+static void h_sha1_end(UINT8* bin_chksum)
+{
+ sha1_final(&sha1ctx);
+ sha1_digest(&sha1ctx, 20, bin_chksum);
+}
+
+
+static struct MD5Context md5_ctx;
+
+static void h_md5_begin(void)
+{
+ MD5Init(&md5_ctx);
+}
+
+static void h_md5_buffer(const void* mem, unsigned long len)
+{
+ MD5Update(&md5_ctx, (md5byte*)mem, len);
+}
+
+static void h_md5_end(UINT8* bin_chksum)
+{
+ MD5Final(bin_chksum, &md5_ctx);
+}
diff --git a/src/emu/hash.h b/src/emu/hash.h
new file mode 100644
index 00000000000..0dfdab70751
--- /dev/null
+++ b/src/emu/hash.h
@@ -0,0 +1,79 @@
+/*********************************************************************
+
+ hash.h
+
+ Function to handle hash functions (checksums)
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __HASH_H__
+#define __HASH_H__
+
+#define HASH_INFO_NO_DUMP 0
+#define HASH_INFO_BAD_DUMP 1
+
+#define HASH_CRC (1 << 0)
+#define HASH_SHA1 (1 << 1)
+#define HASH_MD5 (1 << 2)
+
+#define HASH_NUM_FUNCTIONS 3
+
+// Standard size of a hash data buffer, all the manipulated buffers
+// must respect this size
+#define HASH_BUF_SIZE 256
+
+// Get function name of the specified function
+const char* hash_function_name(unsigned int function);
+
+// Check if const char* contains the checksum for a specific function
+int hash_data_has_checksum(const char* d, unsigned int function);
+
+// Extract the binary or printable checksum of a specific function from a hash data. If the checksum information
+// is not available, the functions return 0. If the pointer to the output buffer is NULL, the function will
+// return the minimum size of the output buffer required to store the informations. Otherwise, the buffer
+// will be filled and the function will return 1 as success code.
+int hash_data_extract_binary_checksum(const char* d, unsigned int function, unsigned char* checksum);
+int hash_data_extract_printable_checksum(const char* d, unsigned int function, char* checksum);
+
+// Insert an already computed binary checksum inside a hash data. This is useful when we already have
+// checksum informations (e.g, from archive headers) and we want to prepare a hash data to compare
+// with another const char* (e.g. the expected checksums). Returns 0 in case of error, 1 if the checksum
+// was added correctly, 2 if the checksum was added overwriting a previously existing checksum for the
+// the same function
+int hash_data_insert_binary_checksum(char* d, unsigned int function, const unsigned char* checksum);
+int hash_data_insert_printable_checksum(char* d, unsigned int function, const char* checksum);
+
+// Check if the hash data contains the requested info
+int hash_data_has_info(const char* d, unsigned int info);
+
+// Compare two hash data to check if they are the same. 'functions' can be either a combination of the
+// hash function bits (HASH_CRC, etc) or zero to ask to check for all the available checksums
+int hash_data_is_equal(const char* d1, const char* d2, unsigned int functions);
+
+// Print hash data informations in a standard format. 'functions' can be either a combination of the
+// hash function bits (HASH_CRC, etc) or zero to ask to print all the available checksums
+void hash_data_print(const char* d, unsigned int functions, char* buffer);
+
+// Copy hash data informations
+void hash_data_copy(char* dst, const char* src);
+
+// Clear hash data informations
+void hash_data_clear(char* dst);
+
+// Check which functions we have a checksum of inside the data
+unsigned int hash_data_used_functions(const char* d);
+
+// Compute hash of a data chunk in memory. Parameter 'functions' specifies which hashing functions
+// we want the checksum of.
+void hash_compute(char* dst, const unsigned char* data, unsigned long length, unsigned int functions);
+
+// Verifies that a hash string is valid
+int hash_verify_string(const char *hash);
+
+
+#endif /* __HASH_H__ */
diff --git a/src/emu/info.c b/src/emu/info.c
new file mode 100644
index 00000000000..a8ce2549af7
--- /dev/null
+++ b/src/emu/info.c
@@ -0,0 +1,1009 @@
+/***************************************************************************
+
+ info.c
+
+ Dumps the MAME internal data as an XML file.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include <ctype.h>
+
+#include "driver.h"
+#include "sound/samples.h"
+#include "info.h"
+#include "xmlfile.h"
+#include "hash.h"
+
+/* MESS/MAME configuration */
+#ifdef MESS
+#define XML_ROOT "mess"
+#define XML_TOP "machine"
+#else
+#define XML_ROOT "mame"
+#define XML_TOP "game"
+#endif
+
+#ifdef MESS
+void print_game_device(FILE* out, const game_driver* game);
+void print_game_ramoptions(FILE* out, const game_driver* game);
+#endif /* MESS */
+
+/* Print a free format string */
+
+static void print_game_switch(FILE* out, const game_driver* game)
+{
+ const input_port_entry* input;
+
+ begin_resource_tracking();
+
+ input = input_port_allocate(game->ipt, NULL);
+
+ while (input->type != IPT_END)
+ {
+ if (input->type==IPT_DIPSWITCH_NAME)
+ {
+ int def = input->default_value;
+
+ fprintf(out, "\t\t<dipswitch");
+
+ fprintf(out, " name=\"%s\"", xml_normalize_string(input->name));
+ ++input;
+
+ fprintf(out, ">\n");
+
+ while (input->type==IPT_DIPSWITCH_SETTING)
+ {
+ fprintf(out, "\t\t\t<dipvalue");
+ fprintf(out, " name=\"%s\"", xml_normalize_string(input->name));
+ if (def == input->default_value)
+ fprintf(out, " default=\"yes\"");
+
+ fprintf(out, "/>\n");
+
+ ++input;
+ }
+
+ fprintf(out, "\t\t</dipswitch>\n");
+ }
+ else
+ ++input;
+ }
+
+ end_resource_tracking();
+}
+
+static void print_game_input(FILE* out, const game_driver* game)
+{
+enum {cjoy, cdoublejoy, cAD_stick, cdial, ctrackball, cpaddle, clightgun, cpedal, ENDCONTROLTYPES};
+ const input_port_entry* input;
+ int nplayer = 0;
+ int nbutton = 0;
+ int ncoin = 0;
+ int controlsyes = 0;
+ int analogcontrol = 0;
+ int i;
+ const char* service = 0;
+ const char* tilt = 0;
+ const char* control_types[] = {"joy", "doublejoy", "stick", "dial", "trackball", "paddle", "lightgun", "pedal"};
+ static struct _input_info
+ {
+ const char * type; /* general type of input */
+ const char * Xway; /* 2, 4, or 8 way */
+ int analog;
+ int min; /* analog minimum value */
+ int max; /* analog maximum value */
+ int sensitivity; /* default analog sensitivity */
+ int keydelta; /* default analog keydelta */
+ int reverse; /* default analog reverse setting */
+ } control[ENDCONTROLTYPES];
+
+ for (i=0;i<ENDCONTROLTYPES;i++)
+ {
+ control[i].type = control_types[i];
+ control[i].Xway = 0;
+ control[i].analog = 0;
+ control[i].min = 0;
+ control[i].max = 0;
+ control[i].sensitivity = 0;
+ control[i].keydelta = 0;
+ control[i].reverse = 0;
+ }
+
+ begin_resource_tracking();
+
+ input = input_port_allocate(game->ipt, NULL);
+
+ while (input->type != IPT_END)
+ {
+ if (nplayer < input->player+1)
+ nplayer = input->player+1;
+
+ switch (input->type)
+ {
+ case IPT_JOYSTICK_LEFT:
+ case IPT_JOYSTICK_RIGHT:
+
+ /* if control not defined, start it off as horizontal 2-way */
+ if (!control[cjoy].Xway)
+ control[cjoy].Xway = "joy2way";
+ else if (strcmp(control[cjoy].Xway,"joy2way") == 0)
+ ;
+ /* if already defined as vertical, make it 4 or 8 way */
+ else if (strcmp(control[cjoy].Xway,"vjoy2way") == 0)
+ {
+ if (input->way == 4)
+ control[cjoy].Xway = "joy4way";
+ else
+ control[cjoy].Xway = "joy8way";
+ }
+ controlsyes = 1;
+ break;
+
+ case IPT_JOYSTICK_UP:
+ case IPT_JOYSTICK_DOWN:
+
+ /* if control not defined, start it off as vertical 2-way */
+ if (!control[cjoy].Xway)
+ control[cjoy].Xway= "vjoy2way";
+ else if (strcmp(control[cjoy].Xway,"vjoy2way") == 0)
+ ;
+ /* if already defined as horiz, make it 4 or 8way */
+ else if (strcmp(control[cjoy].Xway,"joy2way")==0)
+ {
+ if (input->way == 4)
+ control[cjoy].Xway = "joy4way";
+ else
+ control[cjoy].Xway = "joy8way";
+ }
+ controlsyes = 1;
+ break;
+
+ case IPT_JOYSTICKRIGHT_UP:
+ case IPT_JOYSTICKRIGHT_DOWN:
+ case IPT_JOYSTICKLEFT_UP:
+ case IPT_JOYSTICKLEFT_DOWN:
+
+ /* if control not defined, start it off as vertical 2way */
+ if (!control[cdoublejoy].Xway)
+ control[cdoublejoy].Xway= "vdoublejoy2way";
+ else if (strcmp(control[cdoublejoy].Xway,"vdoublejoy2way") == 0)
+ ;
+ /* if already defined as horiz, make it 4 or 8 way */
+ else if (strcmp(control[cdoublejoy].Xway,"doublejoy2way") == 0)
+ {
+ if (input->way == 4)
+ control[cdoublejoy].Xway = "doublejoy4way";
+ else
+ control[cdoublejoy].Xway = "doublejoy8way";
+ }
+ controlsyes = 1;
+ break;
+
+ case IPT_JOYSTICKRIGHT_LEFT:
+ case IPT_JOYSTICKRIGHT_RIGHT:
+ case IPT_JOYSTICKLEFT_LEFT:
+ case IPT_JOYSTICKLEFT_RIGHT:
+
+ /* if control not defined, start it off as horiz 2-way */
+ if (!control[cdoublejoy].Xway)
+ control[cdoublejoy].Xway="doublejoy2way";
+ else if (strcmp(control[cdoublejoy].Xway,"doublejoy2way") == 0)
+ ;
+ /* if already defined as vertical, make it 4 or 8 way */
+ else if (strcmp(control[cdoublejoy].Xway,"vdoublejoy2way") == 0)
+ {
+ if (input->way == 4)
+ control[cdoublejoy].Xway = "doublejoy4way";
+ else
+ control[cdoublejoy].Xway = "doublejoy8way";
+ }
+ controlsyes = 1;
+ break;
+
+ /* mark as an analog input, and get analog stats after switch */
+ case IPT_PADDLE:
+ analogcontrol = cpaddle;
+ break;
+ case IPT_DIAL:
+ analogcontrol = cdial;
+ break;
+ case IPT_TRACKBALL_X:
+ case IPT_TRACKBALL_Y:
+ analogcontrol = ctrackball;
+ break;
+ case IPT_AD_STICK_X:
+ case IPT_AD_STICK_Y:
+ analogcontrol = cAD_stick;
+ break;
+ case IPT_LIGHTGUN_X:
+ case IPT_LIGHTGUN_Y:
+ analogcontrol = clightgun;
+ break;
+ case IPT_PEDAL:
+ case IPT_PEDAL2:
+ case IPT_PEDAL3:
+ analogcontrol = cpedal;
+ break;
+
+ case IPT_BUTTON1:
+ if (nbutton<1) nbutton = 1;
+ break;
+ case IPT_BUTTON2:
+ if (nbutton<2) nbutton = 2;
+ break;
+ case IPT_BUTTON3:
+ if (nbutton<3) nbutton = 3;
+ break;
+ case IPT_BUTTON4:
+ if (nbutton<4) nbutton = 4;
+ break;
+ case IPT_BUTTON5:
+ if (nbutton<5) nbutton = 5;
+ break;
+ case IPT_BUTTON6:
+ if (nbutton<6) nbutton = 6;
+ break;
+ case IPT_BUTTON7:
+ if (nbutton<7) nbutton = 7;
+ break;
+ case IPT_BUTTON8:
+ if (nbutton<8) nbutton = 8;
+ break;
+ case IPT_BUTTON9:
+ if (nbutton<9) nbutton = 9;
+ break;
+ case IPT_BUTTON10:
+ if (nbutton<10) nbutton = 10;
+ break;
+
+ case IPT_COIN1:
+ if (ncoin < 1) ncoin = 1;
+ break;
+ case IPT_COIN2:
+ if (ncoin < 2) ncoin = 2;
+ break;
+ case IPT_COIN3:
+ if (ncoin < 3) ncoin = 3;
+ break;
+ case IPT_COIN4:
+ if (ncoin < 4) ncoin = 4;
+ break;
+ case IPT_COIN5:
+ if (ncoin < 5) ncoin = 5;
+ break;
+ case IPT_COIN6:
+ if (ncoin < 6) ncoin = 6;
+ break;
+ case IPT_COIN7:
+ if (ncoin < 7) ncoin = 7;
+ break;
+ case IPT_COIN8:
+ if (ncoin < 8) ncoin = 8;
+ break;
+ case IPT_SERVICE :
+ service = "yes";
+ break;
+ case IPT_TILT :
+ tilt = "yes";
+ break;
+ }
+
+ /* get the analog stats */
+ if (analogcontrol)
+ {
+ controlsyes = 1;
+ control[analogcontrol].analog = 1;
+
+ if (input->analog.min)
+ control[analogcontrol].min = input->analog.min;
+ if (input->analog.max)
+ control[analogcontrol].max = input->analog.max;
+ if (input->analog.sensitivity)
+ control[analogcontrol].sensitivity = input->analog.sensitivity;
+ if (input->analog.delta)
+ control[analogcontrol].keydelta = input->analog.delta;
+ if (input->analog.reverse)
+ control[analogcontrol].reverse = 1;
+
+ analogcontrol = 0;
+ }
+
+ ++input;
+ }
+
+ fprintf(out, "\t\t<input");
+ fprintf(out, " players=\"%d\"", nplayer );
+ if (nbutton)
+ fprintf(out, " buttons=\"%d\"", nbutton );
+ if (ncoin)
+ fprintf(out, " coins=\"%d\"", ncoin );
+ if (service)
+ fprintf(out, " service=\"%s\"", xml_normalize_string(service) );
+ if (tilt)
+ fprintf(out, " tilt=\"%s\"", xml_normalize_string(tilt) );
+ fprintf(out, ">\n");
+
+ for (i=0;i<ENDCONTROLTYPES;i++)
+ {
+ if (control[i].Xway)
+ fprintf(out, "\t\t\t<control type=\"%s\"/>\n", xml_normalize_string(control[i].Xway) );
+ if (control[i].analog)
+ {
+ fprintf(out, "\t\t\t<control type=\"%s\"", xml_normalize_string(control_types[i]) );
+ if (control[i].min || control[i].max)
+ {
+ fprintf(out, " minimum=\"%d\"", control[i].min);
+ fprintf(out, " maximum=\"%d\"", control[i].max);
+ }
+ if (control[i].sensitivity)
+ fprintf(out, " sensitivity=\"%d\"", control[i].sensitivity);
+ if (control[i].keydelta)
+ fprintf(out, " keydelta=\"%d\"", control[i].keydelta);
+ if (control[i].reverse)
+ fprintf(out, " reverse=\"yes\"");
+
+ fprintf(out, "/>\n");
+ }
+ }
+ fprintf(out, "\t\t</input>\n");
+
+ end_resource_tracking();
+}
+
+static void print_game_bios(FILE* out, const game_driver* game)
+{
+ const rom_entry *rom;
+
+ if (game->rom != NULL)
+ {
+ for (rom = game->rom; !ROMENTRY_ISEND(rom); rom++)
+ if (ROMENTRY_ISSYSTEM_BIOS(rom))
+ {
+ const char *name = ROM_GETHASHDATA(rom);
+ const char *description = name + strlen(name) + 1;
+
+ fprintf(out, "\t\t<biosset");
+ fprintf(out, " name=\"%s\"", xml_normalize_string(name));
+ fprintf(out, " description=\"%s\"", xml_normalize_string(description));
+ if (ROM_GETBIOSFLAGS(rom) == 1)
+ fprintf(out, " default=\"yes\"");
+ fprintf(out, "/>\n");
+ }
+ }
+}
+
+static void print_game_rom(FILE* out, const game_driver* game)
+{
+ const rom_entry *region, *rom, *chunk;
+ const rom_entry *pregion, *prom, *fprom=NULL;
+ const game_driver *clone_of;
+ int rom_type;
+
+ if (!game->rom)
+ return;
+
+ clone_of = driver_get_clone(game);
+ for (rom_type = 0; rom_type < 3; rom_type++)
+ {
+ for (region = rom_first_region(game); region; region = rom_next_region(region))
+ for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ {
+ int offset, length, in_parent, is_disk, is_bios, found_bios, i;
+ char name[100], bios_name[100];
+
+ strcpy(name,ROM_GETNAME(rom));
+ offset = ROM_GETOFFSET(rom);
+ is_disk = ROMREGION_ISDISKDATA(region);
+ is_bios = ROM_GETBIOSFLAGS(rom);
+
+ switch (rom_type)
+ {
+ case 0: /* rom_type 0 = BIOS */
+ if (is_disk || !is_bios)
+ continue;
+ break;
+ case 1: /* rom_type 1 = ROM */
+ if (is_disk || is_bios)
+ continue;
+ break;
+ case 2: /* rom_type 1 = DISK */
+ if (!is_disk || is_bios)
+ continue;
+ break;
+ }
+
+ in_parent = 0;
+ length = 0;
+ for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk))
+ length += ROM_GETLENGTH(chunk);
+
+ if (!ROM_NOGOODDUMP(rom) && clone_of)
+ {
+ fprom=NULL;
+ for (pregion = rom_first_region(clone_of); pregion; pregion = rom_next_region(pregion))
+ for (prom = rom_first_file(pregion); prom; prom = rom_next_file(prom))
+ if (hash_data_is_equal(ROM_GETHASHDATA(rom), ROM_GETHASHDATA(prom), 0))
+ {
+ if (!fprom || !strcmp(ROM_GETNAME(prom), name))
+ fprom=prom;
+ in_parent = 1;
+ }
+ }
+
+ found_bios = 0;
+ if(!is_disk && is_bios)
+ {
+ /* Scan backwards for name */
+ for (prom = rom-1; prom != game->rom; prom--)
+ if (ROMENTRY_ISSYSTEM_BIOS(prom))
+ {
+ strcpy(bios_name, ROM_GETHASHDATA(prom));
+ found_bios = 1;
+ break;
+ }
+ }
+
+
+ if (!is_disk)
+ fprintf(out, "\t\t<rom");
+ else
+ fprintf(out, "\t\t<disk");
+
+ if (*name)
+ fprintf(out, " name=\"%s\"", xml_normalize_string(name));
+ if (in_parent)
+ fprintf(out, " merge=\"%s\"", xml_normalize_string(ROM_GETNAME(fprom)));
+ if (!is_disk && found_bios)
+ fprintf(out, " bios=\"%s\"", xml_normalize_string(bios_name));
+ if (!is_disk)
+ fprintf(out, " size=\"%d\"", length);
+
+ /* dump checksum information only if there is a known dump */
+ if (!hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP))
+ {
+ for (i=0;i<HASH_NUM_FUNCTIONS;i++)
+ {
+ int func = 1<<i;
+ const char* func_name = hash_function_name(func);
+ char checksum[1000];
+
+ if (hash_data_extract_printable_checksum(ROM_GETHASHDATA(rom), func, checksum))
+ {
+ fprintf(out, " %s=\"%s\"", func_name, checksum);
+ }
+ }
+ }
+
+ switch (ROMREGION_GETTYPE(region))
+ {
+ case REGION_CPU1: fprintf(out, " region=\"cpu1\""); break;
+ case REGION_CPU2: fprintf(out, " region=\"cpu2\""); break;
+ case REGION_CPU3: fprintf(out, " region=\"cpu3\""); break;
+ case REGION_CPU4: fprintf(out, " region=\"cpu4\""); break;
+ case REGION_CPU5: fprintf(out, " region=\"cpu5\""); break;
+ case REGION_CPU6: fprintf(out, " region=\"cpu6\""); break;
+ case REGION_CPU7: fprintf(out, " region=\"cpu7\""); break;
+ case REGION_CPU8: fprintf(out, " region=\"cpu8\""); break;
+ case REGION_GFX1: fprintf(out, " region=\"gfx1\""); break;
+ case REGION_GFX2: fprintf(out, " region=\"gfx2\""); break;
+ case REGION_GFX3: fprintf(out, " region=\"gfx3\""); break;
+ case REGION_GFX4: fprintf(out, " region=\"gfx4\""); break;
+ case REGION_GFX5: fprintf(out, " region=\"gfx5\""); break;
+ case REGION_GFX6: fprintf(out, " region=\"gfx6\""); break;
+ case REGION_GFX7: fprintf(out, " region=\"gfx7\""); break;
+ case REGION_GFX8: fprintf(out, " region=\"gfx8\""); break;
+ case REGION_PROMS: fprintf(out, " region=\"proms\""); break;
+ case REGION_PLDS: fprintf(out, " region=\"plds\""); break;
+ case REGION_SOUND1: fprintf(out, " region=\"sound1\""); break;
+ case REGION_SOUND2: fprintf(out, " region=\"sound2\""); break;
+ case REGION_SOUND3: fprintf(out, " region=\"sound3\""); break;
+ case REGION_SOUND4: fprintf(out, " region=\"sound4\""); break;
+ case REGION_SOUND5: fprintf(out, " region=\"sound5\""); break;
+ case REGION_SOUND6: fprintf(out, " region=\"sound6\""); break;
+ case REGION_SOUND7: fprintf(out, " region=\"sound7\""); break;
+ case REGION_SOUND8: fprintf(out, " region=\"sound8\""); break;
+ case REGION_USER1: fprintf(out, " region=\"user1\""); break;
+ case REGION_USER2: fprintf(out, " region=\"user2\""); break;
+ case REGION_USER3: fprintf(out, " region=\"user3\""); break;
+ case REGION_USER4: fprintf(out, " region=\"user4\""); break;
+ case REGION_USER5: fprintf(out, " region=\"user5\""); break;
+ case REGION_USER6: fprintf(out, " region=\"user6\""); break;
+ case REGION_USER7: fprintf(out, " region=\"user7\""); break;
+ case REGION_USER8: fprintf(out, " region=\"user8\""); break;
+ case REGION_USER9: fprintf(out, " region=\"user9\""); break;
+ case REGION_USER10: fprintf(out, " region=\"user10\""); break;
+ case REGION_USER11: fprintf(out, " region=\"user11\""); break;
+ case REGION_USER12: fprintf(out, " region=\"user12\""); break;
+ case REGION_USER13: fprintf(out, " region=\"user13\""); break;
+ case REGION_USER14: fprintf(out, " region=\"user14\""); break;
+ case REGION_USER15: fprintf(out, " region=\"user15\""); break;
+ case REGION_USER16: fprintf(out, " region=\"user16\""); break;
+ case REGION_USER17: fprintf(out, " region=\"user17\""); break;
+ case REGION_USER18: fprintf(out, " region=\"user18\""); break;
+ case REGION_USER19: fprintf(out, " region=\"user19\""); break;
+ case REGION_USER20: fprintf(out, " region=\"user20\""); break;
+ case REGION_DISKS: fprintf(out, " region=\"disks\""); break;
+ default: fprintf(out, " region=\"0x%x\"", (int)ROMREGION_GETTYPE(region)); break;
+ }
+
+ if (hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP))
+ fprintf(out, " status=\"nodump\"");
+ if (hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_BAD_DUMP))
+ fprintf(out, " status=\"baddump\"");
+
+ if (!is_disk)
+ {
+ if (ROMREGION_GETFLAGS(region) & ROMREGION_DISPOSE)
+ fprintf(out, " dispose=\"yes\"");
+
+ fprintf(out, " offset=\"%x\"", offset);
+ }
+ else
+ {
+ fprintf(out, " index=\"%x\"", DISK_GETINDEX(rom));
+ }
+ fprintf(out, "/>\n");
+ }
+ }
+}
+
+static void print_game_sampleof(FILE* out, const game_driver* game)
+{
+#if (HAS_SAMPLES)
+ machine_config drv;
+ int i;
+
+ expand_machine_driver(game->drv, &drv);
+
+ for( i = 0; i < MAX_SOUND && drv.sound[i].type != SOUND_DUMMY; i++ )
+ {
+ const char **samplenames = NULL;
+ if( drv.sound[i].type == SOUND_SAMPLES )
+ samplenames = ((struct Samplesinterface *)drv.sound[i].config)->samplenames;
+ if (samplenames != 0 && samplenames[0] != 0) {
+ int k = 0;
+ if (samplenames[k][0]=='*')
+ {
+ /* output sampleof only if different from game name */
+ if (strcmp(samplenames[k] + 1, game->name)!=0)
+ fprintf(out, " sampleof=\"%s\"", xml_normalize_string(samplenames[k] + 1));
+ ++k;
+ }
+ }
+ }
+#endif
+}
+
+static void print_game_sample(FILE* out, const game_driver* game)
+{
+#if (HAS_SAMPLES)
+ machine_config drv;
+ int i;
+
+ expand_machine_driver(game->drv, &drv);
+
+ for( i = 0; i < MAX_SOUND && drv.sound[i].type != SOUND_DUMMY; i++ )
+ {
+ const char **samplenames = NULL;
+ if( drv.sound[i].type == SOUND_SAMPLES )
+ samplenames = ((struct Samplesinterface *)drv.sound[i].config)->samplenames;
+ if (samplenames != 0 && samplenames[0] != 0) {
+ int k = 0;
+ if (samplenames[k][0]=='*')
+ {
+ ++k;
+ }
+ while (samplenames[k] != 0) {
+ /* check if is not empty */
+ if (*samplenames[k]) {
+ /* check if sample is duplicate */
+ int l = 0;
+ while (l<k && strcmp(samplenames[k],samplenames[l])!=0)
+ ++l;
+ if (l==k)
+ fprintf(out, "\t\t<sample name=\"%s\"/>\n", xml_normalize_string(samplenames[k]));
+ }
+ ++k;
+ }
+ }
+ }
+#endif
+}
+
+static void print_game_micro(FILE* out, const game_driver* game)
+{
+ machine_config driver;
+ const cpu_config* cpu;
+ const sound_config* sound;
+ int j;
+
+ expand_machine_driver(game->drv, &driver);
+ cpu = driver.cpu;
+ sound = driver.sound;
+
+ for(j=0;j<MAX_CPU;++j)
+ {
+ if (cpu[j].type != CPU_DUMMY)
+ {
+ fprintf(out, "\t\t<chip");
+ fprintf(out, " type=\"cpu\"");
+
+ fprintf(out, " name=\"%s\"", xml_normalize_string(cputype_name(cpu[j].type)));
+
+ fprintf(out, " clock=\"%d\"", cpu[j].clock);
+ fprintf(out, "/>\n");
+ }
+ }
+
+ for(j=0;j<MAX_SOUND;++j)
+ {
+ if (sound[j].type != SOUND_DUMMY)
+ {
+ fprintf(out, "\t\t<chip");
+ fprintf(out, " type=\"audio\"");
+ fprintf(out, " name=\"%s\"", xml_normalize_string(sndtype_name(sound[j].type)));
+ if (sound[j].clock)
+ fprintf(out, " clock=\"%d\"", sound[j].clock);
+ fprintf(out, "/>\n");
+ }
+ }
+}
+
+static void print_game_display(FILE* out, const game_driver* game)
+{
+ machine_config driver;
+
+ int dx;
+ int dy;
+ int scrnum;
+
+ expand_machine_driver(game->drv, &driver);
+
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ if (driver.screen[scrnum].tag != NULL)
+ {
+ fprintf(out, "\t\t<display");
+
+ fprintf(out, " type=\"%s\"", (driver.video_attributes & VIDEO_TYPE_VECTOR) ? "vector" : "raster" );
+
+ switch (game->flags & ORIENTATION_MASK) {
+ case ORIENTATION_FLIP_X:
+ fprintf(out, " rotate=\"0\" flipx=\"yes\"");
+ break;
+ case ORIENTATION_FLIP_Y:
+ fprintf(out, " rotate=\"180\" flipx=\"yes\"");
+ break;
+ case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y:
+ fprintf(out, " rotate=\"180\"");
+ break;
+ case ORIENTATION_SWAP_XY:
+ fprintf(out, " rotate=\"90\" flipx=\"yes\"");
+ break;
+ case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X:
+ fprintf(out, " rotate=\"90\"");
+ break;
+ case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y:
+ fprintf(out, " rotate=\"270\"");
+ break;
+ case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y:
+ fprintf(out, " rotate=\"270\" flipx=\"yes\"");
+ break;
+ default:
+ fprintf(out, " rotate=\"0\"");
+ break;
+ }
+
+ /* output width and height only for games that are not vector */
+ if (! (driver.video_attributes & VIDEO_TYPE_VECTOR) )
+ {
+ dx = driver.screen[scrnum].defstate.visarea.max_x - driver.screen[scrnum].defstate.visarea.min_x + 1;
+ dy = driver.screen[scrnum].defstate.visarea.max_y - driver.screen[scrnum].defstate.visarea.min_y + 1;
+ fprintf(out, " width=\"%d\"", dx);
+ fprintf(out, " height=\"%d\"", dy);
+ }
+
+ fprintf(out, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(driver.screen[scrnum].defstate.refresh));
+
+ fprintf(out, " />\n");
+ }
+}
+
+static void print_game_sound(FILE* out, const game_driver* game)
+{
+ machine_config driver;
+ const cpu_config* cpu;
+ const sound_config* sound;
+
+ /* check if the game have sound emulation */
+ int has_sound = 0;
+ int i;
+
+ expand_machine_driver(game->drv, &driver);
+ cpu = driver.cpu;
+ sound = driver.sound;
+
+ i = 0;
+ while (i < MAX_SOUND && !has_sound)
+ {
+ if (sound[i].type != SOUND_DUMMY)
+ has_sound = 1;
+ ++i;
+ }
+
+ fprintf(out, "\t\t<sound");
+
+ /* sound channel */
+ if (has_sound)
+ {
+ int speakers;
+ for (speakers = 0; speakers < MAX_SPEAKER; speakers++)
+ if (driver.speaker[speakers].tag == NULL)
+ break;
+ fprintf(out, " channels=\"%d\"", speakers);
+ }
+ else
+ fprintf(out, " channels=\"0\"");
+
+ fprintf(out, "/>\n");
+}
+
+static void print_game_driver(FILE* out, const game_driver* game)
+{
+ machine_config driver;
+
+ expand_machine_driver(game->drv, &driver);
+
+ fprintf(out, "\t\t<driver");
+
+ /* The status entry is an hint for frontend authors */
+ /* to select working and not working games without */
+ /* the need to know all the other status entries. */
+ /* Games marked as status=good are perfectly emulated, games */
+ /* marked as status=imperfect are emulated with only */
+ /* some minor issues, games marked as status=preliminary */
+ /* don't work or have major emulation problems. */
+
+ if (game->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_NO_SOUND | GAME_WRONG_COLORS))
+ fprintf(out, " status=\"preliminary\"");
+ else if (game->flags & (GAME_IMPERFECT_COLORS | GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS))
+ fprintf(out, " status=\"imperfect\"");
+ else
+ fprintf(out, " status=\"good\"");
+
+ if (game->flags & GAME_NOT_WORKING)
+ fprintf(out, " emulation=\"preliminary\"");
+ else
+ fprintf(out, " emulation=\"good\"");
+
+ if (game->flags & GAME_WRONG_COLORS)
+ fprintf(out, " color=\"preliminary\"");
+ else if (game->flags & GAME_IMPERFECT_COLORS)
+ fprintf(out, " color=\"imperfect\"");
+ else
+ fprintf(out, " color=\"good\"");
+
+ if (game->flags & GAME_NO_SOUND)
+ fprintf(out, " sound=\"preliminary\"");
+ else if (game->flags & GAME_IMPERFECT_SOUND)
+ fprintf(out, " sound=\"imperfect\"");
+ else
+ fprintf(out, " sound=\"good\"");
+
+ if (game->flags & GAME_IMPERFECT_GRAPHICS)
+ fprintf(out, " graphic=\"imperfect\"");
+ else
+ fprintf(out, " graphic=\"good\"");
+
+ if (game->flags & GAME_NO_COCKTAIL)
+ fprintf(out, " cocktail=\"preliminary\"");
+
+ if (game->flags & GAME_UNEMULATED_PROTECTION)
+ fprintf(out, " protection=\"preliminary\"");
+
+ if (game->flags & GAME_SUPPORTS_SAVE)
+ fprintf(out, " savestate=\"supported\"");
+ else
+ fprintf(out, " savestate=\"unsupported\"");
+
+ fprintf(out, " palettesize=\"%d\"", driver.total_colors);
+
+ fprintf(out, "/>\n");
+}
+
+/* Print the MAME info record for a game */
+static void print_game_info(FILE* out, const game_driver* game)
+{
+ const char *start;
+ const game_driver *clone_of;
+
+ /* No action if not a game */
+ if (game->flags & GAME_NO_STANDALONE)
+ return;
+
+ fprintf(out, "\t<" XML_TOP);
+
+ fprintf(out, " name=\"%s\"", xml_normalize_string(game->name) );
+
+ start = strrchr(game->source_file, '/');
+ if (!start)
+ start = strrchr(game->source_file, '\\');
+ if (!start)
+ start = game->source_file - 1;
+ fprintf(out, " sourcefile=\"%s\"", xml_normalize_string(start + 1));
+
+ if (game->flags & GAME_IS_BIOS_ROOT)
+ fprintf(out, " isbios=\"yes\"");
+
+ if (game->flags & GAME_NO_STANDALONE)
+ fprintf(out, " runnable=\"no\"");
+
+ clone_of = driver_get_clone(game);
+ if (clone_of && !(clone_of->flags & GAME_IS_BIOS_ROOT))
+ fprintf(out, " cloneof=\"%s\"", xml_normalize_string(clone_of->name));
+
+ if (clone_of)
+ fprintf(out, " romof=\"%s\"", xml_normalize_string(clone_of->name));
+
+ print_game_sampleof(out, game);
+
+ fprintf(out, ">\n");
+
+ if (game->description)
+ fprintf(out, "\t\t<description>%s</description>\n", xml_normalize_string(game->description));
+
+ /* print the year only if is a number */
+ if (game->year && strspn(game->year,"0123456789")==strlen(game->year))
+ fprintf(out, "\t\t<year>%s</year>\n", xml_normalize_string(game->year) );
+
+ if (game->manufacturer)
+ fprintf(out, "\t\t<manufacturer>%s</manufacturer>\n", xml_normalize_string(game->manufacturer));
+
+ print_game_bios(out, game);
+ print_game_rom(out, game);
+ print_game_sample(out, game);
+ print_game_micro(out, game);
+ print_game_display(out, game);
+ print_game_sound(out, game);
+ print_game_input(out, game);
+ print_game_switch(out, game);
+ print_game_driver(out, game);
+#ifdef MESS
+ print_game_device(out, game);
+ print_game_ramoptions(out, game);
+#endif
+
+ fprintf(out, "\t</" XML_TOP ">\n");
+}
+
+static void print_mame_data(FILE* out, const game_driver* const games[], const char *gamename)
+{
+ int j;
+
+ /* print games */
+ for(j=0;games[j];++j)
+ if (mame_strwildcmp(gamename, games[j]->name) == 0)
+ print_game_info(out, games[j]);
+}
+
+/* Print the MAME database in XML format */
+void print_mame_xml(FILE* out, const game_driver* const games[], const char *gamename)
+{
+ fprintf(out,
+ "<?xml version=\"1.0\"?>\n"
+ "<!DOCTYPE " XML_ROOT " [\n"
+ "<!ELEMENT " XML_ROOT " (" XML_TOP "+)>\n"
+ "\t<!ATTLIST " XML_ROOT " build CDATA #IMPLIED>\n"
+ "\t<!ATTLIST " XML_ROOT " debug (yes|no) \"no\">\n"
+#ifdef MESS
+ "\t<!ELEMENT " XML_TOP " (description, year?, manufacturer, biosset*, rom*, disk*, sample*, chip*, display*, sound?, input?, dipswitch*, driver?, device*, ramoption*)>\n"
+#else
+ "\t<!ELEMENT " XML_TOP " (description, year?, manufacturer, biosset*, rom*, disk*, sample*, chip*, display*, sound?, input?, dipswitch*, driver?)>\n"
+#endif
+ "\t\t<!ATTLIST " XML_TOP " name CDATA #REQUIRED>\n"
+ "\t\t<!ATTLIST " XML_TOP " sourcefile CDATA #IMPLIED>\n"
+ "\t\t<!ATTLIST " XML_TOP " isbios (yes|no) \"no\">\n"
+ "\t\t<!ATTLIST " XML_TOP " runnable (yes|no) \"yes\">\n"
+ "\t\t<!ATTLIST " XML_TOP " cloneof CDATA #IMPLIED>\n"
+ "\t\t<!ATTLIST " XML_TOP " romof CDATA #IMPLIED>\n"
+ "\t\t<!ATTLIST " XML_TOP " sampleof CDATA #IMPLIED>\n"
+ "\t\t<!ELEMENT description (#PCDATA)>\n"
+ "\t\t<!ELEMENT year (#PCDATA)>\n"
+ "\t\t<!ELEMENT manufacturer (#PCDATA)>\n"
+ "\t\t<!ELEMENT biosset EMPTY>\n"
+ "\t\t\t<!ATTLIST biosset name CDATA #REQUIRED>\n"
+ "\t\t\t<!ATTLIST biosset description CDATA #REQUIRED>\n"
+ "\t\t\t<!ATTLIST biosset default (yes|no) \"no\">\n"
+ "\t\t<!ELEMENT rom EMPTY>\n"
+ "\t\t\t<!ATTLIST rom name CDATA #REQUIRED>\n"
+ "\t\t\t<!ATTLIST rom bios CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST rom size CDATA #REQUIRED>\n"
+ "\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST rom md5 CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST rom merge CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST rom region CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n"
+ "\t\t\t<!ATTLIST rom dispose (yes|no) \"no\">\n"
+ "\t\t<!ELEMENT disk EMPTY>\n"
+ "\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n"
+ "\t\t\t<!ATTLIST disk md5 CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST disk merge CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST disk region CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST disk index CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n"
+ "\t\t<!ELEMENT sample EMPTY>\n"
+ "\t\t\t<!ATTLIST sample name CDATA #REQUIRED>\n"
+ "\t\t<!ELEMENT chip EMPTY>\n"
+ "\t\t\t<!ATTLIST chip name CDATA #REQUIRED>\n"
+ "\t\t\t<!ATTLIST chip type (cpu|audio) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST chip clock CDATA #IMPLIED>\n"
+ "\t\t<!ELEMENT display EMPTY>\n"
+ "\t\t\t<!ATTLIST display type (raster|vector) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST display rotate (0|90|180|270) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST display flipx (yes|no) \"no\">\n"
+ "\t\t\t<!ATTLIST display width CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST display height CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST display refresh CDATA #REQUIRED>\n"
+ "\t\t<!ELEMENT sound EMPTY>\n"
+ "\t\t\t<!ATTLIST sound channels CDATA #REQUIRED>\n"
+ "\t\t<!ELEMENT input (control*)>\n"
+ "\t\t\t<!ATTLIST input service (yes|no) \"no\">\n"
+ "\t\t\t<!ATTLIST input tilt (yes|no) \"no\">\n"
+ "\t\t\t<!ATTLIST input players CDATA #REQUIRED>\n"
+ "\t\t\t<!ATTLIST input buttons CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST input coins CDATA #IMPLIED>\n"
+ "\t\t\t<!ELEMENT control EMPTY>\n"
+ "\t\t\t\t<!ATTLIST control type CDATA #REQUIRED>\n"
+ "\t\t\t\t<!ATTLIST control minimum CDATA #IMPLIED>\n"
+ "\t\t\t\t<!ATTLIST control maximum CDATA #IMPLIED>\n"
+ "\t\t\t\t<!ATTLIST control sensitivity CDATA #IMPLIED>\n"
+ "\t\t\t\t<!ATTLIST control keydelta CDATA #IMPLIED>\n"
+ "\t\t\t\t<!ATTLIST control reverse (yes|no) \"no\">\n"
+ "\t\t<!ELEMENT dipswitch (dipvalue*)>\n"
+ "\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n"
+ "\t\t\t<!ELEMENT dipvalue EMPTY>\n"
+ "\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n"
+ "\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n"
+ "\t\t<!ELEMENT driver EMPTY>\n"
+ "\t\t\t<!ATTLIST driver status (good|imperfect|preliminary) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST driver emulation (good|imperfect|preliminary) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST driver color (good|imperfect|preliminary) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST driver sound (good|imperfect|preliminary) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST driver graphic (good|imperfect|preliminary) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST driver cocktail (good|imperfect|preliminary) #IMPLIED>\n"
+ "\t\t\t<!ATTLIST driver protection (good|imperfect|preliminary) #IMPLIED>\n"
+ "\t\t\t<!ATTLIST driver savestate (supported|unsupported) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST driver palettesize CDATA #REQUIRED>\n"
+#ifdef MESS
+ "\t\t<!ELEMENT device (instance*, extension*)>\n"
+ "\t\t\t<!ATTLIST device type CDATA #REQUIRED>\n"
+ "\t\t\t<!ATTLIST device tag CDATA #IMPLIED>\n"
+ "\t\t\t<!ATTLIST device mandatory CDATA #IMPLIED>\n"
+ "\t\t\t<!ELEMENT instance EMPTY>\n"
+ "\t\t\t\t<!ATTLIST instance name CDATA #REQUIRED>\n"
+ "\t\t\t\t<!ATTLIST instance briefname CDATA #REQUIRED>\n"
+ "\t\t\t<!ELEMENT extension EMPTY>\n"
+ "\t\t\t\t<!ATTLIST extension name CDATA #REQUIRED>\n"
+ "\t\t<!ELEMENT ramoption (#PCDATA)>\n"
+ "\t\t\t<!ATTLIST ramoption default CDATA #IMPLIED>\n"
+#endif
+ "]>\n\n"
+ "<" XML_ROOT " build=\"%s\" debug=\""
+#ifdef MAME_DEBUG
+ "yes"
+#else
+ "no"
+#endif
+ "\">\n",
+ xml_normalize_string(build_version)
+ );
+
+ print_mame_data(out, games, gamename);
+
+ fprintf(out, "</" XML_ROOT ">\n");
+}
diff --git a/src/emu/info.h b/src/emu/info.h
new file mode 100644
index 00000000000..76ca3b9e7f3
--- /dev/null
+++ b/src/emu/info.h
@@ -0,0 +1,22 @@
+/***************************************************************************
+
+ info.h
+
+ Dumps the MAME internal data as an XML file.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __INFO_H__
+#define __INFO_H__
+
+#include "mamecore.h"
+
+/* Print the MAME database in XML format */
+void print_mame_xml(FILE* out, const game_driver* const games[], const char *gamename);
+
+#endif /* __INFO_H__ */
diff --git a/src/emu/inptport.c b/src/emu/inptport.c
new file mode 100644
index 00000000000..4c698e96ef8
--- /dev/null
+++ b/src/emu/inptport.c
@@ -0,0 +1,3610 @@
+/***************************************************************************
+
+ inptport.c
+
+ Input port handling.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Theory of operation
+
+ ------------
+ OSD controls
+ ------------
+
+ There are three types of controls that the OSD can provide as potential
+ input devices: digital controls, absolute analog controls, and relative
+ analog controls.
+
+ Digital controls have only two states: on or off. They are generally
+ mapped to buttons and digital joystick directions (like a gamepad or a
+ joystick hat). The OSD layer must return either 0 (off) or 1 (on) for
+ these types of controls.
+
+ Absolute analog controls are analog in the sense that they return a
+ range of values depending on how much a given control is moved, but they
+ are physically bounded. This means that there is a minimum and maximum
+ limit to how far the control can be moved. They are generally mapped to
+ analog joystick axes, lightguns, most PC steering wheels, and pedals.
+ The OSD layer must determine the minimum and maximum range of each
+ analog device and scale that to a value between -65536 and +65536
+ representing the position of the control. -65536 generally refers to
+ the topmost or leftmost position, while +65536 refers to the bottommost
+ or rightmost position. Note that pedals are a special case here, the
+ OSD layer needs to return half axis as full -65536 to + 65536 range.
+
+ Relative analog controls are analog as well, but are not physically
+ bounded. They can be moved continually in one direction without limit.
+ They are generally mapped to trackballs and mice. Because they are
+ unbounded, the OSD layer can only return delta values since the last
+ read. Because of this, it is difficult to scale appropriately. For
+ MAME's purposes, when mapping a mouse devices to a relative analog
+ control, one pixel of movement should correspond to 512 units. Other
+ analog control types should be scaled to return values of a similar
+ magnitude. Like absolute analog controls, negative values refer to
+ upward or leftward movement, while positive values refer to downward
+ or rightward movement.
+
+ -------------
+ Game controls
+ -------------
+
+ Similarly, the types of controls used by arcade games fall into the same
+ three categories: digital, absolute analog, and relative analog. The
+ tricky part is how to map any arbitrary type of OSD control to an
+ arbitrary type of game control.
+
+ Digital controls: used for game buttons and standard 4/8-way joysticks,
+ as well as many other types of game controls. Mapping an OSD digital
+ control to a game's OSD control is trivial. For OSD analog controls,
+ the MAME core does not directly support mapping any OSD analog devices
+ to digital controls. However, the OSD layer is free to enumerate digital
+ equivalents for analog devices. For example, each analog axis in the
+ Windows OSD code enumerates to two digital controls, one for the
+ negative direction (up/left) and one for the position direction
+ (down/right). When these "digital" inputs are queried, the OSD layer
+ checks the axis position against the center, adding in a dead zone,
+ and returns 0 or 1 to indicate its position.
+
+ Absolute analog controls: used for analog joysticks, lightguns, pedals,
+ and wheel controls. Mapping an OSD absolute analog control to this type
+ is easy. OSD relative analog controls can be mapped here as well by
+ accumulating the deltas and bounding the results. OSD digital controls
+ are mapped to these types of controls in pairs, one for a decrement and
+ one for an increment, but apart from that, operate the same as the OSD
+ relative analog controls by accumulating deltas and applying bounds.
+ The speed of the digital delta is user-configurable per analog input.
+ In addition, most absolute analog control types have an autocentering
+ feature that is activated when using the digital increment/decrement
+ sequences, which returns the control back to the center at a user-
+ controllable speed if no digital sequences are pressed.
+
+ Relative analog controls: used for trackballs and dial controls. Again,
+ mapping an OSD relative analog control to this type is straightforward.
+ OSD absolute analog controls can't map directly to these, but if the OSD
+ layer provides a digital equivalent for each direction, it can be done.
+ OSD digital controls map just like they do for absolute analog controls,
+ except that the accumulated deltas are not bounded, but rather wrap.
+
+***************************************************************************/
+
+#include "osdepend.h"
+#include "driver.h"
+#include "config.h"
+#include "xmlfile.h"
+#include "profiler.h"
+#include "inputseq.h"
+#include "ui.h"
+#include <math.h>
+#include <ctype.h>
+#include <time.h>
+
+#ifdef MESS
+#include "inputx.h"
+#endif
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define DIGITAL_JOYSTICKS_PER_PLAYER 3
+
+/* these constants must match the order of the joystick directions in the IPT definition */
+#define JOYDIR_UP 0
+#define JOYDIR_DOWN 1
+#define JOYDIR_LEFT 2
+#define JOYDIR_RIGHT 3
+
+#define JOYDIR_UP_BIT (1 << JOYDIR_UP)
+#define JOYDIR_DOWN_BIT (1 << JOYDIR_DOWN)
+#define JOYDIR_LEFT_BIT (1 << JOYDIR_LEFT)
+#define JOYDIR_RIGHT_BIT (1 << JOYDIR_RIGHT)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _analog_port_info analog_port_info;
+struct _analog_port_info
+{
+ analog_port_info * next; /* linked list */
+ input_port_entry * port; /* pointer to the input port referenced */
+ double accum; /* accumulated value (including relative adjustments) */
+ double previous; /* previous adjusted value */
+ INT32 previousanalog; /* previous analog value */
+ INT32 minimum; /* minimum adjusted value */
+ INT32 maximum; /* maximum adjusted value */
+ INT32 center; /* center adjusted value for autocentering */
+ INT32 reverse_val; /* value where we subtract from to reverse directions */
+ double scalepos; /* scale factor to apply to positive adjusted values */
+ double scaleneg; /* scale factor to apply to negative adjusted values */
+ double keyscalepos; /* scale factor to apply to the key delta field when pos */
+ double keyscaleneg; /* scale factor to apply to the key delta field when neg */
+ double positionalscale;/* scale factor to divide a joystick into positions */
+ UINT8 shift; /* left shift to apply to the final result */
+ UINT8 bits; /* how many bits of resolution are expected? */
+ UINT8 absolute; /* is this an absolute or relative input? */
+ UINT8 wraps; /* does the control wrap around? */
+ UINT8 one_of_x; /* is this a 1 of X positional input? */
+ UINT8 autocenter; /* autocenter this input? */
+ UINT8 single_scale; /* scale joystick differently if default is between min/max */
+ UINT8 interpolate; /* should we do linear interpolation for mid-frame reads? */
+ UINT8 lastdigital; /* was the last modification caused by a digital form? */
+ UINT32 crosshair_pos; /* position of fake crosshair */
+};
+
+
+typedef struct _custom_port_info custom_port_info;
+struct _custom_port_info
+{
+ custom_port_info * next; /* linked list */
+ input_port_entry * port; /* pointer to the input port referenced */
+ UINT8 shift; /* left shift to apply to the final result */
+};
+
+
+typedef struct _input_bit_info input_bit_info;
+struct _input_bit_info
+{
+ input_port_entry * port; /* port for this input */
+ UINT8 impulse; /* counter for impulse controls */
+ UINT8 last; /* were we pressed last time? */
+};
+
+
+typedef struct _changed_callback_info changed_callback_info;
+struct _changed_callback_info
+{
+ changed_callback_info *next; /* linked list */
+ UINT32 mask; /* mask we care about */
+ void (*callback)(void *, UINT32, UINT32); /* callback */
+ void * param; /* parameter */
+};
+
+
+typedef struct _input_port_info input_port_info;
+struct _input_port_info
+{
+ const char * tag; /* tag for this port */
+ UINT32 defvalue; /* default value of all the bits */
+ UINT32 analog; /* value from analog inputs */
+ UINT32 analogmask; /* mask of all analog inputs */
+ UINT32 digital; /* value from digital inputs */
+ UINT32 vblank; /* value of all IPT_VBLANK bits */
+ UINT32 playback; /* current playback override */
+ UINT8 has_custom; /* do we have any custom ports? */
+ input_bit_info bit[MAX_BITS_PER_PORT]; /* info about each bit in the port */
+ analog_port_info * analoginfo; /* pointer to linked list of analog port info */
+ custom_port_info * custominfo; /* pointer to linked list of custom port info */
+ changed_callback_info *change_notify;/* list of people to notify if things change */
+ UINT32 changed_last_value;
+};
+
+
+typedef struct _digital_joystick_info digital_joystick_info;
+struct _digital_joystick_info
+{
+ input_port_entry * port[4]; /* port for up,down,left,right respectively */
+ UINT8 inuse; /* is this joystick used? */
+ UINT8 current; /* current value */
+ UINT8 current4way;/* current 4-way value */
+ UINT8 previous; /* previous value */
+};
+
+
+struct _input_port_init_params
+{
+ input_port_entry * ports; /* base of the port array */
+ int max_ports; /* maximum number of ports we can support */
+ int current_port;/* current port index */
+};
+
+/* Support for eXtended INP format */
+struct ext_header
+{
+ char header[7]; // must be "XINP" followed by NULLs
+ char shortname[9]; // game shortname
+ char version[32]; // MAME version string
+ long starttime; // approximate INP start time
+ char dummy[32]; // for possible future expansion
+};
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define IS_ANALOG(in) ((in)->type >= __ipt_analog_start && (in)->type <= __ipt_analog_end)
+#define IS_DIGITAL_JOYSTICK(in) ((in)->type >= __ipt_digital_joystick_start && (in)->type <= __ipt_digital_joystick_end)
+#define JOYSTICK_INFO_FOR_PORT(in) (&joystick_info[(in)->player][((in)->type - __ipt_digital_joystick_start) / 4])
+#define JOYSTICK_DIR_FOR_PORT(in) (((in)->type - __ipt_digital_joystick_start) % 4)
+
+#define APPLY_SENSITIVITY(x,s) (((double)(x) * (s)) / 100)
+#define APPLY_INVERSE_SENSITIVITY(x,s) (((double)(x) * 100) / (s))
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* current value of all the ports */
+static input_port_info port_info[MAX_INPUT_PORTS];
+
+/* additiona tracking information for special types of controls */
+static digital_joystick_info joystick_info[MAX_PLAYERS][DIGITAL_JOYSTICKS_PER_PLAYER];
+
+/* memory for UI keys */
+static UINT8 ui_memory[__ipt_max];
+
+/* XML attributes for the different types */
+static const char *seqtypestrings[] = { "standard", "decrement", "increment" };
+
+/* original input_ports without modifications */
+static input_port_entry *input_ports_default;
+
+/* recorded speed read from an INP file */
+static double rec_speed;
+
+/* set to 1 if INP file being played is a standard MAME INP file */
+static int no_extended_inp;
+
+/* for average speed calculations */
+static int framecount;
+static double totalspeed;
+
+
+/***************************************************************************
+ PORT HANDLER TABLES
+***************************************************************************/
+
+static const read8_handler port_handler8[] =
+{
+ input_port_0_r, input_port_1_r, input_port_2_r, input_port_3_r,
+ input_port_4_r, input_port_5_r, input_port_6_r, input_port_7_r,
+ input_port_8_r, input_port_9_r, input_port_10_r, input_port_11_r,
+ input_port_12_r, input_port_13_r, input_port_14_r, input_port_15_r,
+ input_port_16_r, input_port_17_r, input_port_18_r, input_port_19_r,
+ input_port_20_r, input_port_21_r, input_port_22_r, input_port_23_r,
+ input_port_24_r, input_port_25_r, input_port_26_r, input_port_27_r,
+ input_port_28_r, input_port_29_r, input_port_30_r, input_port_31_r
+};
+
+
+static const read16_handler port_handler16[] =
+{
+ input_port_0_word_r, input_port_1_word_r, input_port_2_word_r, input_port_3_word_r,
+ input_port_4_word_r, input_port_5_word_r, input_port_6_word_r, input_port_7_word_r,
+ input_port_8_word_r, input_port_9_word_r, input_port_10_word_r, input_port_11_word_r,
+ input_port_12_word_r, input_port_13_word_r, input_port_14_word_r, input_port_15_word_r,
+ input_port_16_word_r, input_port_17_word_r, input_port_18_word_r, input_port_19_word_r,
+ input_port_20_word_r, input_port_21_word_r, input_port_22_word_r, input_port_23_word_r,
+ input_port_24_word_r, input_port_25_word_r, input_port_26_word_r, input_port_27_word_r,
+ input_port_28_word_r, input_port_29_word_r, input_port_30_word_r, input_port_31_word_r
+};
+
+
+static const read32_handler port_handler32[] =
+{
+ input_port_0_dword_r, input_port_1_dword_r, input_port_2_dword_r, input_port_3_dword_r,
+ input_port_4_dword_r, input_port_5_dword_r, input_port_6_dword_r, input_port_7_dword_r,
+ input_port_8_dword_r, input_port_9_dword_r, input_port_10_dword_r, input_port_11_dword_r,
+ input_port_12_dword_r, input_port_13_dword_r, input_port_14_dword_r, input_port_15_dword_r,
+ input_port_16_dword_r, input_port_17_dword_r, input_port_18_dword_r, input_port_19_dword_r,
+ input_port_20_dword_r, input_port_21_dword_r, input_port_22_dword_r, input_port_23_dword_r,
+ input_port_24_dword_r, input_port_25_dword_r, input_port_26_dword_r, input_port_27_dword_r,
+ input_port_28_dword_r, input_port_29_dword_r, input_port_30_dword_r, input_port_31_dword_r
+};
+
+
+
+/***************************************************************************
+ COMMON SHARED STRINGS
+***************************************************************************/
+
+static const struct
+{
+ UINT32 id;
+ const char *string;
+} input_port_default_strings[] =
+{
+ { INPUT_STRING_Off, "Off" },
+ { INPUT_STRING_On, "On" },
+ { INPUT_STRING_No, "No" },
+ { INPUT_STRING_Yes, "Yes" },
+ { INPUT_STRING_Lives, "Lives" },
+ { INPUT_STRING_Bonus_Life, "Bonus Life" },
+ { INPUT_STRING_Difficulty, "Difficulty" },
+ { INPUT_STRING_Demo_Sounds, "Demo Sounds" },
+ { INPUT_STRING_Coinage, "Coinage" },
+ { INPUT_STRING_Coin_A, "Coin A" },
+ { INPUT_STRING_Coin_B, "Coin B" },
+ { INPUT_STRING_9C_1C, "9 Coins/1 Credit" },
+ { INPUT_STRING_8C_1C, "8 Coins/1 Credit" },
+ { INPUT_STRING_7C_1C, "7 Coins/1 Credit" },
+ { INPUT_STRING_6C_1C, "6 Coins/1 Credit" },
+ { INPUT_STRING_5C_1C, "5 Coins/1 Credit" },
+ { INPUT_STRING_4C_1C, "4 Coins/1 Credit" },
+ { INPUT_STRING_3C_1C, "3 Coins/1 Credit" },
+ { INPUT_STRING_8C_3C, "8 Coins/3 Credits" },
+ { INPUT_STRING_4C_2C, "4 Coins/2 Credits" },
+ { INPUT_STRING_2C_1C, "2 Coins/1 Credit" },
+ { INPUT_STRING_5C_3C, "5 Coins/3 Credits" },
+ { INPUT_STRING_3C_2C, "3 Coins/2 Credits" },
+ { INPUT_STRING_4C_3C, "4 Coins/3 Credits" },
+ { INPUT_STRING_4C_4C, "4 Coins/4 Credits" },
+ { INPUT_STRING_3C_3C, "3 Coins/3 Credits" },
+ { INPUT_STRING_2C_2C, "2 Coins/2 Credits" },
+ { INPUT_STRING_1C_1C, "1 Coin/1 Credit" },
+ { INPUT_STRING_4C_5C, "4 Coins/5 Credits" },
+ { INPUT_STRING_3C_4C, "3 Coins/4 Credits" },
+ { INPUT_STRING_2C_3C, "2 Coins/3 Credits" },
+ { INPUT_STRING_4C_7C, "4 Coins/7 Credits" },
+ { INPUT_STRING_2C_4C, "2 Coins/4 Credits" },
+ { INPUT_STRING_1C_2C, "1 Coin/2 Credits" },
+ { INPUT_STRING_2C_5C, "2 Coins/5 Credits" },
+ { INPUT_STRING_2C_6C, "2 Coins/6 Credits" },
+ { INPUT_STRING_1C_3C, "1 Coin/3 Credits" },
+ { INPUT_STRING_2C_7C, "2 Coins/7 Credits" },
+ { INPUT_STRING_2C_8C, "2 Coins/8 Credits" },
+ { INPUT_STRING_1C_4C, "1 Coin/4 Credits" },
+ { INPUT_STRING_1C_5C, "1 Coin/5 Credits" },
+ { INPUT_STRING_1C_6C, "1 Coin/6 Credits" },
+ { INPUT_STRING_1C_7C, "1 Coin/7 Credits" },
+ { INPUT_STRING_1C_8C, "1 Coin/8 Credits" },
+ { INPUT_STRING_1C_9C, "1 Coin/9 Credits" },
+ { INPUT_STRING_Free_Play, "Free Play" },
+ { INPUT_STRING_Cabinet, "Cabinet" },
+ { INPUT_STRING_Upright, "Upright" },
+ { INPUT_STRING_Cocktail, "Cocktail" },
+ { INPUT_STRING_Flip_Screen, "Flip Screen" },
+ { INPUT_STRING_Service_Mode, "Service Mode" },
+ { INPUT_STRING_Pause, "Pause" },
+ { INPUT_STRING_Test, "Test" },
+ { INPUT_STRING_Tilt, "Tilt" },
+ { INPUT_STRING_Version, "Version" },
+ { INPUT_STRING_Region, "Region" },
+ { INPUT_STRING_International, "International" },
+ { INPUT_STRING_Japan, "Japan" },
+ { INPUT_STRING_USA, "USA" },
+ { INPUT_STRING_Europe, "Europe" },
+ { INPUT_STRING_Asia, "Asia" },
+ { INPUT_STRING_World, "World" },
+ { INPUT_STRING_Hispanic, "Hispanic" },
+ { INPUT_STRING_Language, "Language" },
+ { INPUT_STRING_English, "English" },
+ { INPUT_STRING_Japanese, "Japanese" },
+ { INPUT_STRING_German, "German" },
+ { INPUT_STRING_French, "French" },
+ { INPUT_STRING_Italian, "Italian" },
+ { INPUT_STRING_Spanish, "Spanish" },
+ { INPUT_STRING_Very_Easy, "Very Easy" },
+ { INPUT_STRING_Easiest, "Easiest" },
+ { INPUT_STRING_Easier, "Easier" },
+ { INPUT_STRING_Easy, "Easy" },
+ { INPUT_STRING_Normal, "Normal" },
+ { INPUT_STRING_Medium, "Medium" },
+ { INPUT_STRING_Hard, "Hard" },
+ { INPUT_STRING_Harder, "Harder" },
+ { INPUT_STRING_Hardest, "Hardest" },
+ { INPUT_STRING_Very_Hard, "Very Hard" },
+ { INPUT_STRING_Very_Low, "Very Low" },
+ { INPUT_STRING_Low, "Low" },
+ { INPUT_STRING_High, "High" },
+ { INPUT_STRING_Higher, "Higher" },
+ { INPUT_STRING_Highest, "Highest" },
+ { INPUT_STRING_Very_High, "Very High" },
+ { INPUT_STRING_Players, "Players" },
+ { INPUT_STRING_Controls, "Controls" },
+ { INPUT_STRING_Dual, "Dual" },
+ { INPUT_STRING_Single, "Single" },
+ { INPUT_STRING_Game_Time, "Game Time" },
+ { INPUT_STRING_Continue_Price, "Continue Price" },
+ { INPUT_STRING_Controller, "Controller" },
+ { INPUT_STRING_Light_Gun, "Light Gun" },
+ { INPUT_STRING_Joystick, "Joystick" },
+ { INPUT_STRING_Trackball, "Trackball" },
+ { INPUT_STRING_Continues, "Continues" },
+ { INPUT_STRING_Allow_Continue, "Allow Continue" },
+ { INPUT_STRING_Level_Select, "Level Select" },
+ { INPUT_STRING_Infinite, "Infinite" },
+ { INPUT_STRING_Stereo, "Stereo" },
+ { INPUT_STRING_Mono, "Mono" },
+ { INPUT_STRING_Unused, "Unused" },
+ { INPUT_STRING_Unknown, "Unknown" },
+ { INPUT_STRING_Standard, "Standard" },
+ { INPUT_STRING_Reverse, "Reverse" },
+ { INPUT_STRING_Alternate, "Alternate" },
+ { INPUT_STRING_None, "None" }
+};
+
+
+
+/***************************************************************************
+ DEFAULT INPUT PORTS
+***************************************************************************/
+
+#define INPUT_PORT_DIGITAL_DEF(player_,group_,type_,name_,seq_) \
+ { IPT_##type_, group_, (player_ == 0) ? player_ : (player_) - 1, (player_ == 0) ? #type_ : ("P" #player_ "_" #type_), name_, seq_, SEQ_DEF_0, SEQ_DEF_0 },
+
+#define INPUT_PORT_ANALOG_DEF(player_,group_,type_,name_,seq_,decseq_,incseq_) \
+ { IPT_##type_, group_, (player_ == 0) ? player_ : (player_) - 1, (player_ == 0) ? #type_ : ("P" #player_ "_" #type_), name_, seq_, incseq_, decseq_ },
+
+#define INDEXED(a,b) INPUT_CODE_SET_DEVINDEX(a,b)
+
+static const input_port_default_entry default_ports_builtin[] =
+{
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICK_UP, "P1 Up", SEQ_DEF_3(KEYCODE_UP, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICK_DOWN, "P1 Down", SEQ_DEF_3(KEYCODE_DOWN, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICK_LEFT, "P1 Left", SEQ_DEF_3(KEYCODE_LEFT, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICK_RIGHT, "P1 Right", SEQ_DEF_3(KEYCODE_RIGHT, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICKRIGHT_UP, "P1 Right/Up", SEQ_DEF_3(KEYCODE_I, SEQCODE_OR, INDEXED(JOYCODE_BUTTON2, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICKRIGHT_DOWN, "P1 Right/Down", SEQ_DEF_3(KEYCODE_K, SEQCODE_OR, INDEXED(JOYCODE_BUTTON3, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICKRIGHT_LEFT, "P1 Right/Left", SEQ_DEF_3(KEYCODE_J, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICKRIGHT_RIGHT,"P1 Right/Right", SEQ_DEF_3(KEYCODE_L, SEQCODE_OR, INDEXED(JOYCODE_BUTTON4, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICKLEFT_UP, "P1 Left/Up", SEQ_DEF_3(KEYCODE_E, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICKLEFT_DOWN, "P1 Left/Down", SEQ_DEF_3(KEYCODE_D, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICKLEFT_LEFT, "P1 Left/Left", SEQ_DEF_3(KEYCODE_S, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, JOYSTICKLEFT_RIGHT, "P1 Left/Right", SEQ_DEF_3(KEYCODE_F, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON1, "P1 Button 1", SEQ_DEF_7(KEYCODE_LCONTROL, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 0), SEQCODE_OR, INDEXED(MOUSECODE_BUTTON1, 0), SEQCODE_OR, INDEXED(GUNCODE_BUTTON1, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON2, "P1 Button 2", SEQ_DEF_7(KEYCODE_LALT, SEQCODE_OR, INDEXED(JOYCODE_BUTTON2, 0), SEQCODE_OR, INDEXED(MOUSECODE_BUTTON3, 0), SEQCODE_OR, INDEXED(GUNCODE_BUTTON2, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON3, "P1 Button 3", SEQ_DEF_5(KEYCODE_SPACE, SEQCODE_OR, INDEXED(JOYCODE_BUTTON3, 0), SEQCODE_OR, INDEXED(MOUSECODE_BUTTON2, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON4, "P1 Button 4", SEQ_DEF_3(KEYCODE_LSHIFT, SEQCODE_OR, INDEXED(JOYCODE_BUTTON4, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON5, "P1 Button 5", SEQ_DEF_3(KEYCODE_Z, SEQCODE_OR, INDEXED(JOYCODE_BUTTON5, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON6, "P1 Button 6", SEQ_DEF_3(KEYCODE_X, SEQCODE_OR, INDEXED(JOYCODE_BUTTON6, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON7, "P1 Button 7", SEQ_DEF_3(KEYCODE_C, SEQCODE_OR, INDEXED(JOYCODE_BUTTON7, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON8, "P1 Button 8", SEQ_DEF_3(KEYCODE_V, SEQCODE_OR, INDEXED(JOYCODE_BUTTON8, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON9, "P1 Button 9", SEQ_DEF_3(KEYCODE_B, SEQCODE_OR, INDEXED(JOYCODE_BUTTON9, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON10, "P1 Button 10", SEQ_DEF_3(KEYCODE_N, SEQCODE_OR, INDEXED(JOYCODE_BUTTON10, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON11, "P1 Button 11", SEQ_DEF_3(KEYCODE_M, SEQCODE_OR, INDEXED(JOYCODE_BUTTON11, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON12, "P1 Button 12", SEQ_DEF_3(KEYCODE_COMMA, SEQCODE_OR, INDEXED(JOYCODE_BUTTON12, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON13, "P1 Button 13", SEQ_DEF_3(KEYCODE_STOP, SEQCODE_OR, INDEXED(JOYCODE_BUTTON13, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON14, "P1 Button 14", SEQ_DEF_3(KEYCODE_SLASH, SEQCODE_OR, INDEXED(JOYCODE_BUTTON14, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON15, "P1 Button 15", SEQ_DEF_3(KEYCODE_RSHIFT, SEQCODE_OR, INDEXED(JOYCODE_BUTTON15, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, BUTTON16, "P1 Button 16", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON16, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, START, "P1 Start", SEQ_DEF_3(KEYCODE_1, SEQCODE_OR, INDEXED(JOYCODE_START, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, SELECT, "P1 Select", SEQ_DEF_3(KEYCODE_5, SEQCODE_OR, INDEXED(JOYCODE_SELECT, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_A, "P1 Mahjong A", SEQ_DEF_1(KEYCODE_A) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_B, "P1 Mahjong B", SEQ_DEF_1(KEYCODE_B) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_C, "P1 Mahjong C", SEQ_DEF_1(KEYCODE_C) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_D, "P1 Mahjong D", SEQ_DEF_1(KEYCODE_D) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_E, "P1 Mahjong E", SEQ_DEF_1(KEYCODE_E) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_F, "P1 Mahjong F", SEQ_DEF_1(KEYCODE_F) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_G, "P1 Mahjong G", SEQ_DEF_1(KEYCODE_G) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_H, "P1 Mahjong H", SEQ_DEF_1(KEYCODE_H) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_I, "P1 Mahjong I", SEQ_DEF_1(KEYCODE_I) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_J, "P1 Mahjong J", SEQ_DEF_1(KEYCODE_J) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_K, "P1 Mahjong K", SEQ_DEF_1(KEYCODE_K) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_L, "P1 Mahjong L", SEQ_DEF_1(KEYCODE_L) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_M, "P1 Mahjong M", SEQ_DEF_1(KEYCODE_M) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_N, "P1 Mahjong N", SEQ_DEF_1(KEYCODE_N) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_O, "P1 Mahjong O", SEQ_DEF_1(KEYCODE_O) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_P, "P1 Mahjong P", SEQ_DEF_1(KEYCODE_COLON) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_Q, "P1 Mahjong Q", SEQ_DEF_1(KEYCODE_Q) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_KAN, "P1 Mahjong Kan", SEQ_DEF_1(KEYCODE_LCONTROL) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_PON, "P1 Mahjong Pon", SEQ_DEF_1(KEYCODE_LALT) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_CHI, "P1 Mahjong Chi", SEQ_DEF_1(KEYCODE_SPACE) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_REACH, "P1 Mahjong Reach", SEQ_DEF_1(KEYCODE_LSHIFT) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_RON, "P1 Mahjong Ron", SEQ_DEF_1(KEYCODE_Z) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_BET, "P1 Mahjong Bet", SEQ_DEF_1(KEYCODE_2) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_LAST_CHANCE,"P1 Mahjong Last Chance",SEQ_DEF_1(KEYCODE_RALT) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_SCORE, "P1 Mahjong Score", SEQ_DEF_1(KEYCODE_RCONTROL) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_DOUBLE_UP, "P1 Mahjong Double Up", SEQ_DEF_1(KEYCODE_RSHIFT) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_FLIP_FLOP, "P1 Mahjong Flip Flop", SEQ_DEF_1(KEYCODE_Y) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_BIG, "P1 Mahjong Big", SEQ_DEF_1(KEYCODE_ENTER) )
+ INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, MAHJONG_SMALL, "P1 Mahjong Small", SEQ_DEF_1(KEYCODE_BACKSPACE) )
+
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICK_UP, "P2 Up", SEQ_DEF_3(KEYCODE_R, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICK_DOWN, "P2 Down", SEQ_DEF_3(KEYCODE_F, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICK_LEFT, "P2 Left", SEQ_DEF_3(KEYCODE_D, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICK_RIGHT, "P2 Right", SEQ_DEF_3(KEYCODE_G, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICKRIGHT_UP, "P2 Right/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICKRIGHT_DOWN, "P2 Right/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICKRIGHT_LEFT, "P2 Right/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICKRIGHT_RIGHT,"P2 Right/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICKLEFT_UP, "P2 Left/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICKLEFT_DOWN, "P2 Left/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICKLEFT_LEFT, "P2 Left/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, JOYSTICKLEFT_RIGHT, "P2 Left/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON1, "P2 Button 1", SEQ_DEF_7(KEYCODE_A, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 1), SEQCODE_OR, INDEXED(MOUSECODE_BUTTON1, 1), SEQCODE_OR, INDEXED(GUNCODE_BUTTON1, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON2, "P2 Button 2", SEQ_DEF_7(KEYCODE_S, SEQCODE_OR, INDEXED(JOYCODE_BUTTON2, 1), SEQCODE_OR, INDEXED(MOUSECODE_BUTTON3, 1), SEQCODE_OR, INDEXED(GUNCODE_BUTTON2, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON3, "P2 Button 3", SEQ_DEF_5(KEYCODE_Q, SEQCODE_OR, INDEXED(JOYCODE_BUTTON3, 1), SEQCODE_OR, INDEXED(MOUSECODE_BUTTON2, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON4, "P2 Button 4", SEQ_DEF_3(KEYCODE_W, SEQCODE_OR, INDEXED(JOYCODE_BUTTON4, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON5, "P2 Button 5", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON5, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON6, "P2 Button 6", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON6, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON7, "P2 Button 7", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON7, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON8, "P2 Button 8", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON8, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON9, "P2 Button 9", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON9, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON10, "P2 Button 10", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON10, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON11, "P2 Button 11", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON11, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON12, "P2 Button 12", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON12, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON13, "P2 Button 13", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON13, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON14, "P2 Button 14", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON14, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON15, "P2 Button 15", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON15, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, BUTTON16, "P2 Button 16", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON16, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, START, "P2 Start", SEQ_DEF_3(KEYCODE_2, SEQCODE_OR, INDEXED(JOYCODE_START, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, SELECT, "P2 Select", SEQ_DEF_3(KEYCODE_6, SEQCODE_OR, INDEXED(JOYCODE_SELECT, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_A, "P2 Mahjong A", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_B, "P2 Mahjong B", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_C, "P2 Mahjong C", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_D, "P2 Mahjong D", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_E, "P2 Mahjong E", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_F, "P2 Mahjong F", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_G, "P2 Mahjong G", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_H, "P2 Mahjong H", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_I, "P2 Mahjong I", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_J, "P2 Mahjong J", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_K, "P2 Mahjong K", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_L, "P2 Mahjong L", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_M, "P2 Mahjong M", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_N, "P2 Mahjong N", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_O, "P2 Mahjong O", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_P, "P2 Mahjong P", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_Q, "P2 Mahjong Q", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_KAN, "P2 Mahjong Kan", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_PON, "P2 Mahjong Pon", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_CHI, "P2 Mahjong Chi", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_REACH, "P2 Mahjong Reach", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_RON, "P2 Mahjong Ron", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_BET, "P2 Mahjong Bet", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_LAST_CHANCE,"P2 Mahjong Last Chance",SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_SCORE, "P2 Mahjong Score", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_DOUBLE_UP, "P2 Mahjong Double Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_FLIP_FLOP, "P2 Mahjong Flip Flop", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_BIG, "P2 Mahjong Big", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, MAHJONG_SMALL, "P2 Mahjong Small", SEQ_DEF_0 )
+
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICK_UP, "P3 Up", SEQ_DEF_3(KEYCODE_I, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICK_DOWN, "P3 Down", SEQ_DEF_3(KEYCODE_K, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICK_LEFT, "P3 Left", SEQ_DEF_3(KEYCODE_J, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICK_RIGHT, "P3 Right", SEQ_DEF_3(KEYCODE_L, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICKRIGHT_UP, "P3 Right/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICKRIGHT_DOWN, "P3 Right/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICKRIGHT_LEFT, "P3 Right/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICKRIGHT_RIGHT,"P3 Right/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICKLEFT_UP, "P3 Left/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICKLEFT_DOWN, "P3 Left/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICKLEFT_LEFT, "P3 Left/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, JOYSTICKLEFT_RIGHT, "P3 Left/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON1, "P3 Button 1", SEQ_DEF_5(KEYCODE_RCONTROL, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 2), SEQCODE_OR, INDEXED(GUNCODE_BUTTON1, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON2, "P3 Button 2", SEQ_DEF_5(KEYCODE_RSHIFT, SEQCODE_OR, INDEXED(JOYCODE_BUTTON2, 2), SEQCODE_OR, INDEXED(GUNCODE_BUTTON2, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON3, "P3 Button 3", SEQ_DEF_3(KEYCODE_ENTER, SEQCODE_OR, INDEXED(JOYCODE_BUTTON3, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON4, "P3 Button 4", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON4, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON5, "P3 Button 5", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON5, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON6, "P3 Button 6", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON6, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON7, "P3 Button 7", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON7, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON8, "P3 Button 8", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON8, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON9, "P3 Button 9", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON9, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON10, "P3 Button 10", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON10, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON11, "P3 Button 11", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON11, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON12, "P3 Button 12", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON12, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON13, "P3 Button 13", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON13, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON14, "P3 Button 14", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON14, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON15, "P3 Button 15", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON15, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, BUTTON16, "P3 Button 16", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON16, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, START, "P3 Start", SEQ_DEF_3(KEYCODE_3, SEQCODE_OR, INDEXED(JOYCODE_START, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 3, IPG_PLAYER3, SELECT, "P3 Select", SEQ_DEF_3(KEYCODE_7, SEQCODE_OR, INDEXED(JOYCODE_SELECT, 2)) )
+
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICK_UP, "P4 Up", SEQ_DEF_3(KEYCODE_8_PAD, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICK_DOWN, "P4 Down", SEQ_DEF_3(KEYCODE_2_PAD, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICK_LEFT, "P4 Left", SEQ_DEF_3(KEYCODE_4_PAD, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICK_RIGHT, "P4 Right", SEQ_DEF_3(KEYCODE_6_PAD, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICKRIGHT_UP, "P4 Right/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICKRIGHT_DOWN, "P4 Right/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICKRIGHT_LEFT, "P4 Right/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICKRIGHT_RIGHT,"P4 Right/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICKLEFT_UP, "P4 Left/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICKLEFT_DOWN, "P4 Left/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICKLEFT_LEFT, "P4 Left/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, JOYSTICKLEFT_RIGHT, "P4 Left/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON1, "P4 Button 1", SEQ_DEF_3(KEYCODE_0_PAD, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON2, "P4 Button 2", SEQ_DEF_3(KEYCODE_DEL_PAD, SEQCODE_OR, INDEXED(JOYCODE_BUTTON2, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON3, "P4 Button 3", SEQ_DEF_3(KEYCODE_ENTER_PAD, SEQCODE_OR, INDEXED(JOYCODE_BUTTON3, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON4, "P4 Button 4", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON4, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON5, "P4 Button 5", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON5, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON6, "P4 Button 6", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON6, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON7, "P4 Button 7", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON7, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON8, "P4 Button 8", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON8, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON9, "P4 Button 9", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON9, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON10, "P4 Button 10", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON10, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON11, "P4 Button 11", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON11, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON12, "P4 Button 12", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON12, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON13, "P4 Button 13", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON13, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON14, "P4 Button 14", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON14, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON15, "P4 Button 15", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON15, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, BUTTON16, "P4 Button 16", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON16, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, START, "P4 Start", SEQ_DEF_3(KEYCODE_4, SEQCODE_OR, INDEXED(JOYCODE_START, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 4, IPG_PLAYER4, SELECT, "P4 Select", SEQ_DEF_3(KEYCODE_8, SEQCODE_OR, INDEXED(JOYCODE_SELECT, 3)) )
+
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICK_UP, "P5 Up", SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICK_DOWN, "P5 Down", SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICK_LEFT, "P5 Left", SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICK_RIGHT, "P5 Right", SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICKRIGHT_UP, "P5 Right/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICKRIGHT_DOWN, "P5 Right/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICKRIGHT_LEFT, "P5 Right/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICKRIGHT_RIGHT,"P5 Right/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICKLEFT_UP, "P5 Left/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICKLEFT_DOWN, "P5 Left/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICKLEFT_LEFT, "P5 Left/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, JOYSTICKLEFT_RIGHT, "P5 Left/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON1, "P5 Button 1", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON1, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON2, "P5 Button 2", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON2, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON3, "P5 Button 3", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON3, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON4, "P5 Button 4", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON4, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON5, "P5 Button 5", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON5, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON6, "P5 Button 6", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON6, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON7, "P5 Button 7", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON7, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON8, "P5 Button 8", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON8, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON9, "P5 Button 9", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON9, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON10, "P5 Button 10", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON10, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON11, "P5 Button 11", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON11, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON12, "P5 Button 12", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON12, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON13, "P5 Button 13", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON13, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON14, "P5 Button 14", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON14, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON15, "P5 Button 15", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON15, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, BUTTON16, "P5 Button 16", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON16, 4)) )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, START, "P5 Start", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 5, IPG_PLAYER5, SELECT, "P5 Select", SEQ_DEF_0 )
+
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICK_UP, "P6 Up", SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICK_DOWN, "P6 Down", SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICK_LEFT, "P6 Left", SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICK_RIGHT, "P6 Right", SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICKRIGHT_UP, "P6 Right/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICKRIGHT_DOWN, "P6 Right/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICKRIGHT_LEFT, "P6 Right/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICKRIGHT_RIGHT,"P6 Right/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICKLEFT_UP, "P6 Left/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICKLEFT_DOWN, "P6 Left/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICKLEFT_LEFT, "P6 Left/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, JOYSTICKLEFT_RIGHT, "P6 Left/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON1, "P6 Button 1", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON1, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON2, "P6 Button 2", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON2, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON3, "P6 Button 3", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON3, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON4, "P6 Button 4", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON4, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON5, "P6 Button 5", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON5, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON6, "P6 Button 6", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON6, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON7, "P6 Button 7", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON7, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON8, "P6 Button 8", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON8, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON9, "P6 Button 9", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON9, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON10, "P6 Button 10", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON10, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON11, "P6 Button 11", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON11, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON12, "P6 Button 12", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON12, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON13, "P6 Button 13", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON13, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON14, "P6 Button 14", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON14, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON15, "P6 Button 15", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON15, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, BUTTON16, "P6 Button 16", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON16, 5)) )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, START, "P6 Start", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 6, IPG_PLAYER6, SELECT, "P6 Select", SEQ_DEF_0 )
+
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICK_UP, "P7 Up", SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICK_DOWN, "P7 Down", SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICK_LEFT, "P7 Left", SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICK_RIGHT, "P7 Right", SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICKRIGHT_UP, "P7 Right/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICKRIGHT_DOWN, "P7 Right/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICKRIGHT_LEFT, "P7 Right/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICKRIGHT_RIGHT,"P7 Right/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICKLEFT_UP, "P7 Left/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICKLEFT_DOWN, "P7 Left/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICKLEFT_LEFT, "P7 Left/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, JOYSTICKLEFT_RIGHT, "P7 Left/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON1, "P7 Button 1", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON1, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON2, "P7 Button 2", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON2, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON3, "P7 Button 3", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON3, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON4, "P7 Button 4", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON4, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON5, "P7 Button 5", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON5, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON6, "P7 Button 6", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON6, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON7, "P7 Button 7", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON7, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON8, "P7 Button 8", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON8, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON9, "P7 Button 9", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON9, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON10, "P7 Button 10", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON10, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON11, "P7 Button 11", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON11, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON12, "P7 Button 12", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON12, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON13, "P7 Button 13", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON13, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON14, "P7 Button 14", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON14, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON15, "P7 Button 15", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON15, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, BUTTON16, "P7 Button 16", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON16, 6)) )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, START, "P7 Start", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 7, IPG_PLAYER7, SELECT, "P7 Select", SEQ_DEF_0 )
+
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICK_UP, "P8 Up", SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICK_DOWN, "P8 Down", SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICK_LEFT, "P8 Left", SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICK_RIGHT, "P8 Right", SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICKRIGHT_UP, "P8 Right/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICKRIGHT_DOWN, "P8 Right/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICKRIGHT_LEFT, "P8 Right/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICKRIGHT_RIGHT,"P8 Right/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICKLEFT_UP, "P8 Left/Up", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICKLEFT_DOWN, "P8 Left/Down", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICKLEFT_LEFT, "P8 Left/Left", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, JOYSTICKLEFT_RIGHT, "P8 Left/Right", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON1, "P8 Button 1", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON1, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON2, "P8 Button 2", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON2, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON3, "P8 Button 3", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON3, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON4, "P8 Button 4", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON4, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON5, "P8 Button 5", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON5, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON6, "P8 Button 6", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON6, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON7, "P8 Button 7", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON7, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON8, "P8 Button 8", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON8, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON9, "P8 Button 9", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON9, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON10, "P8 Button 10", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON10, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON11, "P8 Button 11", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON11, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON12, "P8 Button 12", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON12, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON13, "P8 Button 13", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON13, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON14, "P8 Button 14", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON14, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON15, "P8 Button 15", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON15, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, BUTTON16, "P8 Button 16", SEQ_DEF_1(INDEXED(JOYCODE_BUTTON16, 7)) )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, START, "P8 Start", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 8, IPG_PLAYER8, SELECT, "P8 Select", SEQ_DEF_0 )
+
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, START1, "1 Player Start", SEQ_DEF_3(KEYCODE_1, SEQCODE_OR, INDEXED(JOYCODE_START, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, START2, "2 Players Start", SEQ_DEF_3(KEYCODE_2, SEQCODE_OR, INDEXED(JOYCODE_START, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, START3, "3 Players Start", SEQ_DEF_3(KEYCODE_3, SEQCODE_OR, INDEXED(JOYCODE_START, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, START4, "4 Players Start", SEQ_DEF_3(KEYCODE_4, SEQCODE_OR, INDEXED(JOYCODE_START, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, START5, "5 Players Start", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, START6, "6 Players Start", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, START7, "7 Players Start", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, START8, "8 Players Start", SEQ_DEF_0 )
+
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, COIN1, "Coin 1", SEQ_DEF_3(KEYCODE_5, SEQCODE_OR, INDEXED(JOYCODE_SELECT, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, COIN2, "Coin 2", SEQ_DEF_3(KEYCODE_6, SEQCODE_OR, INDEXED(JOYCODE_SELECT, 1)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, COIN3, "Coin 3", SEQ_DEF_3(KEYCODE_7, SEQCODE_OR, INDEXED(JOYCODE_SELECT, 2)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, COIN4, "Coin 4", SEQ_DEF_3(KEYCODE_8, SEQCODE_OR, INDEXED(JOYCODE_SELECT, 3)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, COIN5, "Coin 5", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, COIN6, "Coin 6", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, COIN7, "Coin 7", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, COIN8, "Coin 8", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, BILL1, "Bill 1", SEQ_DEF_1(KEYCODE_BACKSPACE) )
+
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, SERVICE1, "Service 1", SEQ_DEF_1(KEYCODE_9) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, SERVICE2, "Service 2", SEQ_DEF_1(KEYCODE_0) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, SERVICE3, "Service 3", SEQ_DEF_1(KEYCODE_MINUS) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, SERVICE4, "Service 4", SEQ_DEF_1(KEYCODE_EQUALS) )
+
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, SERVICE, "Service", SEQ_DEF_1(KEYCODE_F2) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, TILT, "Tilt", SEQ_DEF_1(KEYCODE_T) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, INTERLOCK, "Door Interlock", SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, VOLUME_DOWN, "Volume Down", SEQ_DEF_1(KEYCODE_MINUS) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, VOLUME_UP, "Volume Up", SEQ_DEF_1(KEYCODE_EQUALS) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, PEDAL, "P1 Pedal 1", SEQ_DEF_1(INDEXED(JOYCODE_Y_NEG_ABSOLUTE, 0)), SEQ_DEF_0, SEQ_DEF_3(KEYCODE_LCONTROL, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, PEDAL, "P2 Pedal 1", SEQ_DEF_1(INDEXED(JOYCODE_Y_NEG_ABSOLUTE, 1)), SEQ_DEF_0, SEQ_DEF_3(KEYCODE_A, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, PEDAL, "P3 Pedal 1", SEQ_DEF_1(INDEXED(JOYCODE_Y_NEG_ABSOLUTE, 2)), SEQ_DEF_0, SEQ_DEF_3(KEYCODE_RCONTROL, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, PEDAL, "P4 Pedal 1", SEQ_DEF_1(INDEXED(JOYCODE_Y_NEG_ABSOLUTE, 3)), SEQ_DEF_0, SEQ_DEF_3(KEYCODE_0_PAD, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, PEDAL, "P5 Pedal 1", SEQ_DEF_1(INDEXED(JOYCODE_Y_NEG_ABSOLUTE, 4)), SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON1, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, PEDAL, "P6 Pedal 1", SEQ_DEF_1(INDEXED(JOYCODE_Y_NEG_ABSOLUTE, 5)), SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON1, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, PEDAL, "P7 Pedal 1", SEQ_DEF_1(INDEXED(JOYCODE_Y_NEG_ABSOLUTE, 6)), SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON1, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, PEDAL, "P8 Pedal 1", SEQ_DEF_1(INDEXED(JOYCODE_Y_NEG_ABSOLUTE, 7)), SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON1, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, PEDAL2, "P1 Pedal 2", SEQ_DEF_1(INDEXED(JOYCODE_Y_POS_ABSOLUTE, 0)), SEQ_DEF_0, SEQ_DEF_3(KEYCODE_LALT, SEQCODE_OR, INDEXED(JOYCODE_BUTTON2, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, PEDAL2, "P2 Pedal 2", SEQ_DEF_1(INDEXED(JOYCODE_Y_POS_ABSOLUTE, 1)), SEQ_DEF_0, SEQ_DEF_3(KEYCODE_S, SEQCODE_OR, INDEXED(JOYCODE_BUTTON2, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, PEDAL2, "P3 Pedal 2", SEQ_DEF_1(INDEXED(JOYCODE_Y_POS_ABSOLUTE, 2)), SEQ_DEF_0, SEQ_DEF_3(KEYCODE_RSHIFT, SEQCODE_OR, INDEXED(JOYCODE_BUTTON2, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, PEDAL2, "P4 Pedal 2", SEQ_DEF_1(INDEXED(JOYCODE_Y_POS_ABSOLUTE, 3)), SEQ_DEF_0, SEQ_DEF_3(KEYCODE_DEL_PAD, SEQCODE_OR, INDEXED(JOYCODE_BUTTON2, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, PEDAL2, "P5 Pedal 2", SEQ_DEF_1(INDEXED(JOYCODE_Y_POS_ABSOLUTE, 4)), SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON2, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, PEDAL2, "P6 Pedal 2", SEQ_DEF_1(INDEXED(JOYCODE_Y_POS_ABSOLUTE, 5)), SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON2, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, PEDAL2, "P7 Pedal 2", SEQ_DEF_1(INDEXED(JOYCODE_Y_POS_ABSOLUTE, 6)), SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON2, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, PEDAL2, "P8 Pedal 2", SEQ_DEF_1(INDEXED(JOYCODE_Y_POS_ABSOLUTE, 7)), SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON2, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, PEDAL3, "P1 Pedal 3", SEQ_DEF_0, SEQ_DEF_0, SEQ_DEF_3(KEYCODE_SPACE, SEQCODE_OR, INDEXED(JOYCODE_BUTTON3, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, PEDAL3, "P2 Pedal 3", SEQ_DEF_0, SEQ_DEF_0, SEQ_DEF_3(KEYCODE_Q, SEQCODE_OR, INDEXED(JOYCODE_BUTTON3, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, PEDAL3, "P3 Pedal 3", SEQ_DEF_0, SEQ_DEF_0, SEQ_DEF_3(KEYCODE_ENTER, SEQCODE_OR, INDEXED(JOYCODE_BUTTON3, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, PEDAL3, "P4 Pedal 3", SEQ_DEF_0, SEQ_DEF_0, SEQ_DEF_3(KEYCODE_ENTER_PAD, SEQCODE_OR, INDEXED(JOYCODE_BUTTON3, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, PEDAL3, "P5 Pedal 3", SEQ_DEF_0, SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON3, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, PEDAL3, "P6 Pedal 3", SEQ_DEF_0, SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON3, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, PEDAL3, "P7 Pedal 3", SEQ_DEF_0, SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON3, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, PEDAL3, "P8 Pedal 3", SEQ_DEF_0, SEQ_DEF_0, SEQ_DEF_1(INDEXED(JOYCODE_BUTTON3, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, PADDLE, "Paddle", SEQ_DEF_3(INDEXED(MOUSECODE_X, 0), SEQCODE_OR, INDEXED(JOYCODE_X, 0)), SEQ_DEF_3(KEYCODE_LEFT, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)), SEQ_DEF_3(KEYCODE_RIGHT, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, PADDLE, "Paddle 2", SEQ_DEF_3(INDEXED(MOUSECODE_X, 1), SEQCODE_OR, INDEXED(JOYCODE_X, 1)), SEQ_DEF_3(KEYCODE_D, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 1)), SEQ_DEF_3(KEYCODE_G, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, PADDLE, "Paddle 3", SEQ_DEF_3(INDEXED(MOUSECODE_X, 2), SEQCODE_OR, INDEXED(JOYCODE_X, 2)), SEQ_DEF_3(KEYCODE_J, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 2)), SEQ_DEF_3(KEYCODE_L, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, PADDLE, "Paddle 4", SEQ_DEF_3(INDEXED(MOUSECODE_X, 3), SEQCODE_OR, INDEXED(JOYCODE_X, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, PADDLE, "Paddle 5", SEQ_DEF_3(INDEXED(MOUSECODE_X, 4), SEQCODE_OR, INDEXED(JOYCODE_X, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, PADDLE, "Paddle 6", SEQ_DEF_3(INDEXED(MOUSECODE_X, 5), SEQCODE_OR, INDEXED(JOYCODE_X, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, PADDLE, "Paddle 7", SEQ_DEF_3(INDEXED(MOUSECODE_X, 6), SEQCODE_OR, INDEXED(JOYCODE_X, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, PADDLE, "Paddle 8", SEQ_DEF_3(INDEXED(MOUSECODE_X, 7), SEQCODE_OR, INDEXED(JOYCODE_X, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, PADDLE_V, "Paddle V", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 0), SEQCODE_OR, INDEXED(JOYCODE_Y, 0)), SEQ_DEF_3(KEYCODE_UP, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)), SEQ_DEF_3(KEYCODE_DOWN, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, PADDLE_V, "Paddle V 2", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 1), SEQCODE_OR, INDEXED(JOYCODE_Y, 1)), SEQ_DEF_3(KEYCODE_R, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 1)), SEQ_DEF_3(KEYCODE_F, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, PADDLE_V, "Paddle V 3", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 2), SEQCODE_OR, INDEXED(JOYCODE_Y, 2)), SEQ_DEF_3(KEYCODE_I, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 2)), SEQ_DEF_3(KEYCODE_K, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, PADDLE_V, "Paddle V 4", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 3), SEQCODE_OR, INDEXED(JOYCODE_Y, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, PADDLE_V, "Paddle V 5", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 4), SEQCODE_OR, INDEXED(JOYCODE_Y, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, PADDLE_V, "Paddle V 6", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 5), SEQCODE_OR, INDEXED(JOYCODE_Y, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, PADDLE_V, "Paddle V 7", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 6), SEQCODE_OR, INDEXED(JOYCODE_Y, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, PADDLE_V, "Paddle V 8", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 7), SEQCODE_OR, INDEXED(JOYCODE_Y, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, POSITIONAL, "Positional", SEQ_DEF_3(INDEXED(MOUSECODE_X, 0), SEQCODE_OR, INDEXED(JOYCODE_X, 0)), SEQ_DEF_3(KEYCODE_LEFT, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)), SEQ_DEF_3(KEYCODE_RIGHT, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, POSITIONAL, "Positional 2", SEQ_DEF_3(INDEXED(MOUSECODE_X, 1), SEQCODE_OR, INDEXED(JOYCODE_X, 1)), SEQ_DEF_3(KEYCODE_D, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 1)), SEQ_DEF_3(KEYCODE_G, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, POSITIONAL, "Positional 3", SEQ_DEF_3(INDEXED(MOUSECODE_X, 2), SEQCODE_OR, INDEXED(JOYCODE_X, 2)), SEQ_DEF_3(KEYCODE_J, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 2)), SEQ_DEF_3(KEYCODE_L, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, POSITIONAL, "Positional 4", SEQ_DEF_3(INDEXED(MOUSECODE_X, 3), SEQCODE_OR, INDEXED(JOYCODE_X, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, POSITIONAL, "Positional 5", SEQ_DEF_3(INDEXED(MOUSECODE_X, 4), SEQCODE_OR, INDEXED(JOYCODE_X, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, POSITIONAL, "Positional 6", SEQ_DEF_3(INDEXED(MOUSECODE_X, 5), SEQCODE_OR, INDEXED(JOYCODE_X, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, POSITIONAL, "Positional 7", SEQ_DEF_3(INDEXED(MOUSECODE_X, 6), SEQCODE_OR, INDEXED(JOYCODE_X, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, POSITIONAL, "Positional 8", SEQ_DEF_3(INDEXED(MOUSECODE_X, 7), SEQCODE_OR, INDEXED(JOYCODE_X, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, POSITIONAL_V, "Positional V", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 0), SEQCODE_OR, INDEXED(JOYCODE_Y, 0)), SEQ_DEF_3(KEYCODE_UP, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)), SEQ_DEF_3(KEYCODE_DOWN, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, POSITIONAL_V, "Positional V 2", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 1), SEQCODE_OR, INDEXED(JOYCODE_Y, 1)), SEQ_DEF_3(KEYCODE_R, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 1)), SEQ_DEF_3(KEYCODE_F, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, POSITIONAL_V, "Positional V 3", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 2), SEQCODE_OR, INDEXED(JOYCODE_Y, 2)), SEQ_DEF_3(KEYCODE_I, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 2)), SEQ_DEF_3(KEYCODE_K, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, POSITIONAL_V, "Positional V 4", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 3), SEQCODE_OR, INDEXED(JOYCODE_Y, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, POSITIONAL_V, "Positional V 5", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 4), SEQCODE_OR, INDEXED(JOYCODE_Y, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, POSITIONAL_V, "Positional V 6", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 5), SEQCODE_OR, INDEXED(JOYCODE_Y, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, POSITIONAL_V, "Positional V 7", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 6), SEQCODE_OR, INDEXED(JOYCODE_Y, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, POSITIONAL_V, "Positional V 8", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 7), SEQCODE_OR, INDEXED(JOYCODE_Y, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, DIAL, "Dial", SEQ_DEF_3(INDEXED(MOUSECODE_X, 0), SEQCODE_OR, INDEXED(JOYCODE_X, 0)), SEQ_DEF_3(KEYCODE_LEFT, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)), SEQ_DEF_3(KEYCODE_RIGHT, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, DIAL, "Dial 2", SEQ_DEF_3(INDEXED(MOUSECODE_X, 1), SEQCODE_OR, INDEXED(JOYCODE_X, 1)), SEQ_DEF_3(KEYCODE_D, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 1)), SEQ_DEF_3(KEYCODE_G, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, DIAL, "Dial 3", SEQ_DEF_3(INDEXED(MOUSECODE_X, 2), SEQCODE_OR, INDEXED(JOYCODE_X, 2)), SEQ_DEF_3(KEYCODE_J, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 2)), SEQ_DEF_3(KEYCODE_L, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, DIAL, "Dial 4", SEQ_DEF_3(INDEXED(MOUSECODE_X, 3), SEQCODE_OR, INDEXED(JOYCODE_X, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, DIAL, "Dial 5", SEQ_DEF_3(INDEXED(MOUSECODE_X, 4), SEQCODE_OR, INDEXED(JOYCODE_X, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, DIAL, "Dial 6", SEQ_DEF_3(INDEXED(MOUSECODE_X, 5), SEQCODE_OR, INDEXED(JOYCODE_X, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, DIAL, "Dial 7", SEQ_DEF_3(INDEXED(MOUSECODE_X, 6), SEQCODE_OR, INDEXED(JOYCODE_X, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, DIAL, "Dial 8", SEQ_DEF_3(INDEXED(MOUSECODE_X, 7), SEQCODE_OR, INDEXED(JOYCODE_X, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, DIAL_V, "Dial V", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 0), SEQCODE_OR, INDEXED(JOYCODE_Y, 0)), SEQ_DEF_3(KEYCODE_UP, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)), SEQ_DEF_3(KEYCODE_DOWN, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, DIAL_V, "Dial V 2", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 1), SEQCODE_OR, INDEXED(JOYCODE_Y, 1)), SEQ_DEF_3(KEYCODE_R, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 1)), SEQ_DEF_3(KEYCODE_F, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, DIAL_V, "Dial V 3", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 2), SEQCODE_OR, INDEXED(JOYCODE_Y, 2)), SEQ_DEF_3(KEYCODE_I, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 2)), SEQ_DEF_3(KEYCODE_K, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, DIAL_V, "Dial V 4", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 3), SEQCODE_OR, INDEXED(JOYCODE_Y, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, DIAL_V, "Dial V 5", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 4), SEQCODE_OR, INDEXED(JOYCODE_Y, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, DIAL_V, "Dial V 6", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 5), SEQCODE_OR, INDEXED(JOYCODE_Y, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, DIAL_V, "Dial V 7", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 6), SEQCODE_OR, INDEXED(JOYCODE_Y, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, DIAL_V, "Dial V 8", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 7), SEQCODE_OR, INDEXED(JOYCODE_Y, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, TRACKBALL_X, "Track X", SEQ_DEF_3(INDEXED(MOUSECODE_X, 0), SEQCODE_OR, INDEXED(JOYCODE_X, 0)), SEQ_DEF_3(KEYCODE_LEFT, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)), SEQ_DEF_3(KEYCODE_RIGHT, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, TRACKBALL_X, "Track X 2", SEQ_DEF_3(INDEXED(MOUSECODE_X, 1), SEQCODE_OR, INDEXED(JOYCODE_X, 1)), SEQ_DEF_3(KEYCODE_D, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 1)), SEQ_DEF_3(KEYCODE_G, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, TRACKBALL_X, "Track X 3", SEQ_DEF_3(INDEXED(MOUSECODE_X, 2), SEQCODE_OR, INDEXED(JOYCODE_X, 2)), SEQ_DEF_3(KEYCODE_J, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 2)), SEQ_DEF_3(KEYCODE_L, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, TRACKBALL_X, "Track X 4", SEQ_DEF_3(INDEXED(MOUSECODE_X, 3), SEQCODE_OR, INDEXED(JOYCODE_X, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, TRACKBALL_X, "Track X 5", SEQ_DEF_3(INDEXED(MOUSECODE_X, 4), SEQCODE_OR, INDEXED(JOYCODE_X, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, TRACKBALL_X, "Track X 6", SEQ_DEF_3(INDEXED(MOUSECODE_X, 5), SEQCODE_OR, INDEXED(JOYCODE_X, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, TRACKBALL_X, "Track X 7", SEQ_DEF_3(INDEXED(MOUSECODE_X, 6), SEQCODE_OR, INDEXED(JOYCODE_X, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, TRACKBALL_X, "Track X 8", SEQ_DEF_3(INDEXED(MOUSECODE_X, 7), SEQCODE_OR, INDEXED(JOYCODE_X, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, TRACKBALL_Y, "Track Y", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 0), SEQCODE_OR, INDEXED(JOYCODE_Y, 0)), SEQ_DEF_3(KEYCODE_UP, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)), SEQ_DEF_3(KEYCODE_DOWN, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, TRACKBALL_Y, "Track Y 2", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 1), SEQCODE_OR, INDEXED(JOYCODE_Y, 1)), SEQ_DEF_3(KEYCODE_R, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 1)), SEQ_DEF_3(KEYCODE_F, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, TRACKBALL_Y, "Track Y 3", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 2), SEQCODE_OR, INDEXED(JOYCODE_Y, 2)), SEQ_DEF_3(KEYCODE_I, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 2)), SEQ_DEF_3(KEYCODE_K, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, TRACKBALL_Y, "Track Y 4", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 3), SEQCODE_OR, INDEXED(JOYCODE_Y, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, TRACKBALL_Y, "Track Y 5", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 4), SEQCODE_OR, INDEXED(JOYCODE_Y, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, TRACKBALL_Y, "Track Y 6", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 5), SEQCODE_OR, INDEXED(JOYCODE_Y, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, TRACKBALL_Y, "Track Y 7", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 6), SEQCODE_OR, INDEXED(JOYCODE_Y, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, TRACKBALL_Y, "Track Y 8", SEQ_DEF_3(INDEXED(MOUSECODE_Y, 7), SEQCODE_OR, INDEXED(JOYCODE_Y, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, AD_STICK_X, "AD Stick X", SEQ_DEF_3(INDEXED(JOYCODE_X, 0), SEQCODE_OR, INDEXED(MOUSECODE_X, 0)), SEQ_DEF_3(KEYCODE_LEFT, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)), SEQ_DEF_3(KEYCODE_RIGHT, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, AD_STICK_X, "AD Stick X 2", SEQ_DEF_3(INDEXED(JOYCODE_X, 1), SEQCODE_OR, INDEXED(MOUSECODE_X, 1)), SEQ_DEF_3(KEYCODE_D, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 1)), SEQ_DEF_3(KEYCODE_G, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, AD_STICK_X, "AD Stick X 3", SEQ_DEF_3(INDEXED(JOYCODE_X, 2), SEQCODE_OR, INDEXED(MOUSECODE_X, 2)), SEQ_DEF_3(KEYCODE_J, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 2)), SEQ_DEF_3(KEYCODE_L, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, AD_STICK_X, "AD Stick X 4", SEQ_DEF_3(INDEXED(JOYCODE_X, 3), SEQCODE_OR, INDEXED(MOUSECODE_X, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, AD_STICK_X, "AD Stick X 5", SEQ_DEF_3(INDEXED(JOYCODE_X, 4), SEQCODE_OR, INDEXED(MOUSECODE_X, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, AD_STICK_X, "AD Stick X 6", SEQ_DEF_3(INDEXED(JOYCODE_X, 5), SEQCODE_OR, INDEXED(MOUSECODE_X, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, AD_STICK_X, "AD Stick X 7", SEQ_DEF_3(INDEXED(JOYCODE_X, 6), SEQCODE_OR, INDEXED(MOUSECODE_X, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, AD_STICK_X, "AD Stick X 8", SEQ_DEF_3(INDEXED(JOYCODE_X, 7), SEQCODE_OR, INDEXED(MOUSECODE_X, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, AD_STICK_Y, "AD Stick Y", SEQ_DEF_3(INDEXED(JOYCODE_Y, 0), SEQCODE_OR, INDEXED(MOUSECODE_Y, 0)), SEQ_DEF_3(KEYCODE_UP, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)), SEQ_DEF_3(KEYCODE_DOWN, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, AD_STICK_Y, "AD Stick Y 2", SEQ_DEF_3(INDEXED(JOYCODE_Y, 1), SEQCODE_OR, INDEXED(MOUSECODE_Y, 1)), SEQ_DEF_3(KEYCODE_R, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 1)), SEQ_DEF_3(KEYCODE_F, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, AD_STICK_Y, "AD Stick Y 3", SEQ_DEF_3(INDEXED(JOYCODE_Y, 2), SEQCODE_OR, INDEXED(MOUSECODE_Y, 2)), SEQ_DEF_3(KEYCODE_I, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 2)), SEQ_DEF_3(KEYCODE_K, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, AD_STICK_Y, "AD Stick Y 4", SEQ_DEF_3(INDEXED(JOYCODE_Y, 3), SEQCODE_OR, INDEXED(MOUSECODE_Y, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, AD_STICK_Y, "AD Stick Y 5", SEQ_DEF_3(INDEXED(JOYCODE_Y, 4), SEQCODE_OR, INDEXED(MOUSECODE_Y, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, AD_STICK_Y, "AD Stick Y 6", SEQ_DEF_3(INDEXED(JOYCODE_Y, 5), SEQCODE_OR, INDEXED(MOUSECODE_Y, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, AD_STICK_Y, "AD Stick Y 7", SEQ_DEF_3(INDEXED(JOYCODE_Y, 6), SEQCODE_OR, INDEXED(MOUSECODE_Y, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, AD_STICK_Y, "AD Stick Y 8", SEQ_DEF_3(INDEXED(JOYCODE_Y, 7), SEQCODE_OR, INDEXED(MOUSECODE_Y, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, AD_STICK_Z, "AD Stick Z", SEQ_DEF_1(INDEXED(JOYCODE_Z, 0)), SEQ_DEF_0, SEQ_DEF_0 )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, AD_STICK_Z, "AD Stick Z 2", SEQ_DEF_1(INDEXED(JOYCODE_Z, 1)), SEQ_DEF_0, SEQ_DEF_0 )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, AD_STICK_Z, "AD Stick Z 3", SEQ_DEF_1(INDEXED(JOYCODE_Z, 2)), SEQ_DEF_0, SEQ_DEF_0 )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, AD_STICK_Z, "AD Stick Z 4", SEQ_DEF_1(INDEXED(JOYCODE_Z, 3)), SEQ_DEF_0, SEQ_DEF_0 )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, AD_STICK_Z, "AD Stick Z 5", SEQ_DEF_1(INDEXED(JOYCODE_Z, 4)), SEQ_DEF_0, SEQ_DEF_0 )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, AD_STICK_Z, "AD Stick Z 6", SEQ_DEF_1(INDEXED(JOYCODE_Z, 5)), SEQ_DEF_0, SEQ_DEF_0 )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, AD_STICK_Z, "AD Stick Z 7", SEQ_DEF_1(INDEXED(JOYCODE_Z, 6)), SEQ_DEF_0, SEQ_DEF_0 )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, AD_STICK_Z, "AD Stick Z 8", SEQ_DEF_1(INDEXED(JOYCODE_Z, 7)), SEQ_DEF_0, SEQ_DEF_0 )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, LIGHTGUN_X, "Lightgun X", SEQ_DEF_5(INDEXED(GUNCODE_X, 0), SEQCODE_OR, INDEXED(MOUSECODE_X, 0), SEQCODE_OR, INDEXED(JOYCODE_X, 0)), SEQ_DEF_3(KEYCODE_LEFT, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)), SEQ_DEF_3(KEYCODE_RIGHT, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, LIGHTGUN_X, "Lightgun X 2", SEQ_DEF_5(INDEXED(GUNCODE_X, 1), SEQCODE_OR, INDEXED(MOUSECODE_X, 1), SEQCODE_OR, INDEXED(JOYCODE_X, 1)), SEQ_DEF_3(KEYCODE_D, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 1)), SEQ_DEF_3(KEYCODE_G, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, LIGHTGUN_X, "Lightgun X 3", SEQ_DEF_5(INDEXED(GUNCODE_X, 2), SEQCODE_OR, INDEXED(MOUSECODE_X, 2), SEQCODE_OR, INDEXED(JOYCODE_X, 2)), SEQ_DEF_3(KEYCODE_J, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 2)), SEQ_DEF_3(KEYCODE_L, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, LIGHTGUN_X, "Lightgun X 4", SEQ_DEF_5(INDEXED(GUNCODE_X, 3), SEQCODE_OR, INDEXED(MOUSECODE_X, 3), SEQCODE_OR, INDEXED(JOYCODE_X, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, LIGHTGUN_X, "Lightgun X 5", SEQ_DEF_5(INDEXED(GUNCODE_X, 4), SEQCODE_OR, INDEXED(MOUSECODE_X, 4), SEQCODE_OR, INDEXED(JOYCODE_X, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, LIGHTGUN_X, "Lightgun X 6", SEQ_DEF_5(INDEXED(GUNCODE_X, 5), SEQCODE_OR, INDEXED(MOUSECODE_X, 5), SEQCODE_OR, INDEXED(JOYCODE_X, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, LIGHTGUN_X, "Lightgun X 7", SEQ_DEF_5(INDEXED(GUNCODE_X, 6), SEQCODE_OR, INDEXED(MOUSECODE_X, 6), SEQCODE_OR, INDEXED(JOYCODE_X, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, LIGHTGUN_X, "Lightgun X 8", SEQ_DEF_5(INDEXED(GUNCODE_X, 7), SEQCODE_OR, INDEXED(MOUSECODE_X, 7), SEQCODE_OR, INDEXED(JOYCODE_X, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, LIGHTGUN_Y, "Lightgun Y", SEQ_DEF_5(INDEXED(GUNCODE_Y, 0), SEQCODE_OR, INDEXED(MOUSECODE_Y, 0), SEQCODE_OR, INDEXED(JOYCODE_Y, 0)), SEQ_DEF_3(KEYCODE_UP, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)), SEQ_DEF_3(KEYCODE_DOWN, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, LIGHTGUN_Y, "Lightgun Y 2", SEQ_DEF_5(INDEXED(GUNCODE_Y, 1), SEQCODE_OR, INDEXED(MOUSECODE_Y, 1), SEQCODE_OR, INDEXED(JOYCODE_Y, 1)), SEQ_DEF_3(KEYCODE_R, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 1)), SEQ_DEF_3(KEYCODE_F, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, LIGHTGUN_Y, "Lightgun Y 3", SEQ_DEF_5(INDEXED(GUNCODE_Y, 2), SEQCODE_OR, INDEXED(MOUSECODE_Y, 2), SEQCODE_OR, INDEXED(JOYCODE_Y, 2)), SEQ_DEF_3(KEYCODE_I, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 2)), SEQ_DEF_3(KEYCODE_K, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, LIGHTGUN_Y, "Lightgun Y 4", SEQ_DEF_5(INDEXED(GUNCODE_Y, 3), SEQCODE_OR, INDEXED(MOUSECODE_Y, 3), SEQCODE_OR, INDEXED(JOYCODE_Y, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, LIGHTGUN_Y, "Lightgun Y 5", SEQ_DEF_5(INDEXED(GUNCODE_Y, 4), SEQCODE_OR, INDEXED(MOUSECODE_Y, 4), SEQCODE_OR, INDEXED(JOYCODE_Y, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, LIGHTGUN_Y, "Lightgun Y 6", SEQ_DEF_5(INDEXED(GUNCODE_Y, 5), SEQCODE_OR, INDEXED(MOUSECODE_Y, 5), SEQCODE_OR, INDEXED(JOYCODE_Y, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, LIGHTGUN_Y, "Lightgun Y 7", SEQ_DEF_5(INDEXED(GUNCODE_Y, 6), SEQCODE_OR, INDEXED(MOUSECODE_Y, 6), SEQCODE_OR, INDEXED(JOYCODE_Y, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, LIGHTGUN_Y, "Lightgun Y 8", SEQ_DEF_5(INDEXED(GUNCODE_Y, 7), SEQCODE_OR, INDEXED(MOUSECODE_Y, 7), SEQCODE_OR, INDEXED(JOYCODE_Y, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, MOUSE_X, "Mouse X", SEQ_DEF_1(INDEXED(MOUSECODE_X, 0)), SEQ_DEF_3(KEYCODE_LEFT, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)), SEQ_DEF_3(KEYCODE_RIGHT, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, MOUSE_X, "Mouse X 2", SEQ_DEF_1(INDEXED(MOUSECODE_X, 1)), SEQ_DEF_3(KEYCODE_D, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 1)), SEQ_DEF_3(KEYCODE_G, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, MOUSE_X, "Mouse X 3", SEQ_DEF_1(INDEXED(MOUSECODE_X, 2)), SEQ_DEF_3(KEYCODE_J, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 2)), SEQ_DEF_3(KEYCODE_L, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, MOUSE_X, "Mouse X 4", SEQ_DEF_1(INDEXED(MOUSECODE_X, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, MOUSE_X, "Mouse X 5", SEQ_DEF_1(INDEXED(MOUSECODE_X, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, MOUSE_X, "Mouse X 6", SEQ_DEF_1(INDEXED(MOUSECODE_X, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, MOUSE_X, "Mouse X 7", SEQ_DEF_1(INDEXED(MOUSECODE_X, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, MOUSE_X, "Mouse X 8", SEQ_DEF_1(INDEXED(MOUSECODE_X, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_LEFT_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_X_RIGHT_SWITCH, 7)) )
+
+ INPUT_PORT_ANALOG_DEF ( 1, IPG_PLAYER1, MOUSE_Y, "Mouse Y", SEQ_DEF_1(INDEXED(MOUSECODE_Y, 0)), SEQ_DEF_3(KEYCODE_UP, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)), SEQ_DEF_3(KEYCODE_DOWN, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_ANALOG_DEF ( 2, IPG_PLAYER2, MOUSE_Y, "Mouse Y 2", SEQ_DEF_1(INDEXED(MOUSECODE_Y, 1)), SEQ_DEF_3(KEYCODE_R, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 1)), SEQ_DEF_3(KEYCODE_F, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 1)) )
+ INPUT_PORT_ANALOG_DEF ( 3, IPG_PLAYER3, MOUSE_Y, "Mouse Y 3", SEQ_DEF_1(INDEXED(MOUSECODE_Y, 2)), SEQ_DEF_3(KEYCODE_I, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 2)), SEQ_DEF_3(KEYCODE_K, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 2)) )
+ INPUT_PORT_ANALOG_DEF ( 4, IPG_PLAYER4, MOUSE_Y, "Mouse Y 4", SEQ_DEF_1(INDEXED(MOUSECODE_Y, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 3)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 3)) )
+ INPUT_PORT_ANALOG_DEF ( 5, IPG_PLAYER5, MOUSE_Y, "Mouse Y 5", SEQ_DEF_1(INDEXED(MOUSECODE_Y, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 4)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 4)) )
+ INPUT_PORT_ANALOG_DEF ( 6, IPG_PLAYER6, MOUSE_Y, "Mouse Y 6", SEQ_DEF_1(INDEXED(MOUSECODE_Y, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 5)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 5)) )
+ INPUT_PORT_ANALOG_DEF ( 7, IPG_PLAYER7, MOUSE_Y, "Mouse Y 7", SEQ_DEF_1(INDEXED(MOUSECODE_Y, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 6)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 6)) )
+ INPUT_PORT_ANALOG_DEF ( 8, IPG_PLAYER8, MOUSE_Y, "Mouse Y 8", SEQ_DEF_1(INDEXED(MOUSECODE_Y, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_UP_SWITCH, 7)), SEQ_DEF_1(INDEXED(JOYCODE_Y_DOWN_SWITCH, 7)) )
+
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_OTHER, KEYBOARD, "Keyboard", SEQ_DEF_0 )
+
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_ON_SCREEN_DISPLAY,"On Screen Display", SEQ_DEF_1(KEYCODE_TILDE) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_DEBUG_BREAK, "Break in Debugger", SEQ_DEF_1(KEYCODE_TILDE) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_CONFIGURE, "Config Menu", SEQ_DEF_1(KEYCODE_TAB) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_PAUSE, "Pause", SEQ_DEF_1(KEYCODE_P) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_RESET_MACHINE, "Reset Game", SEQ_DEF_2(KEYCODE_F3, KEYCODE_LSHIFT) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_SOFT_RESET, "Soft Reset", SEQ_DEF_3(KEYCODE_F3, SEQCODE_NOT, KEYCODE_LSHIFT) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_SHOW_GFX, "Show Gfx", SEQ_DEF_1(KEYCODE_F4) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_FRAMESKIP_DEC, "Frameskip Dec", SEQ_DEF_1(KEYCODE_F8) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_FRAMESKIP_INC, "Frameskip Inc", SEQ_DEF_1(KEYCODE_F9) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_THROTTLE, "Throttle", SEQ_DEF_1(KEYCODE_F10) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_FAST_FORWARD, "Fast Forward", SEQ_DEF_1(KEYCODE_INSERT) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_SHOW_FPS, "Show FPS", SEQ_DEF_5(KEYCODE_F11, SEQCODE_NOT, KEYCODE_LCONTROL, SEQCODE_NOT, KEYCODE_LSHIFT) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_SNAPSHOT, "Save Snapshot", SEQ_DEF_3(KEYCODE_F12, SEQCODE_NOT, KEYCODE_LSHIFT) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_RECORD_MOVIE, "Record Movie", SEQ_DEF_2(KEYCODE_F12, KEYCODE_LSHIFT) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_TOGGLE_CHEAT, "Toggle Cheat", SEQ_DEF_1(KEYCODE_F6) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_UP, "UI Up", SEQ_DEF_3(KEYCODE_UP, SEQCODE_OR, INDEXED(JOYCODE_Y_UP_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_DOWN, "UI Down", SEQ_DEF_3(KEYCODE_DOWN, SEQCODE_OR, INDEXED(JOYCODE_Y_DOWN_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_LEFT, "UI Left", SEQ_DEF_3(KEYCODE_LEFT, SEQCODE_OR, INDEXED(JOYCODE_X_LEFT_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_RIGHT, "UI Right", SEQ_DEF_3(KEYCODE_RIGHT, SEQCODE_OR, INDEXED(JOYCODE_X_RIGHT_SWITCH, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_HOME, "UI Home", SEQ_DEF_1(KEYCODE_HOME) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_END, "UI End", SEQ_DEF_1(KEYCODE_END) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_PAGE_UP, "UI Page Up", SEQ_DEF_1(KEYCODE_PGUP) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_PAGE_DOWN, "UI Page Down", SEQ_DEF_1(KEYCODE_PGDN) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_SELECT, "UI Select", SEQ_DEF_3(KEYCODE_ENTER, SEQCODE_OR, INDEXED(JOYCODE_BUTTON1, 0)) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_CANCEL, "UI Cancel", SEQ_DEF_1(KEYCODE_ESC) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_CLEAR, "UI Clear", SEQ_DEF_1(KEYCODE_DEL) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_ZOOM_IN, "UI Zoom In", SEQ_DEF_1(KEYCODE_EQUALS) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_ZOOM_OUT, "UI Zoom Out", SEQ_DEF_1(KEYCODE_MINUS) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_PREV_GROUP, "UI Previous Group", SEQ_DEF_1(KEYCODE_OPENBRACE) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_NEXT_GROUP, "UI Next Group", SEQ_DEF_1(KEYCODE_CLOSEBRACE) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_ROTATE, "UI Rotate", SEQ_DEF_1(KEYCODE_R) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_SHOW_PROFILER, "Show Profiler", SEQ_DEF_2(KEYCODE_F11, KEYCODE_LSHIFT) )
+#ifdef MESS
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_TOGGLE_UI, "UI Toggle", SEQ_DEF_1(KEYCODE_SCRLOCK) )
+#endif
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_TOGGLE_DEBUG, "Toggle Debugger", SEQ_DEF_1(KEYCODE_F5) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_SAVE_STATE, "Save State", SEQ_DEF_2(KEYCODE_F7, KEYCODE_LSHIFT) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_LOAD_STATE, "Load State", SEQ_DEF_3(KEYCODE_F7, SEQCODE_NOT, KEYCODE_LSHIFT) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_ADD_CHEAT, "Add Cheat", SEQ_DEF_1(KEYCODE_A) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_DELETE_CHEAT, "Delete Cheat", SEQ_DEF_1(KEYCODE_D) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_SAVE_CHEAT, "Save Cheat", SEQ_DEF_1(KEYCODE_S) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_WATCH_VALUE, "Watch Value", SEQ_DEF_1(KEYCODE_W) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_EDIT_CHEAT, "Edit Cheat", SEQ_DEF_1(KEYCODE_E) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_RELOAD_CHEAT, "Reload Database", SEQ_DEF_1(KEYCODE_L) )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, UI_TOGGLE_CROSSHAIR, "Toggle Crosshair", SEQ_DEF_1(KEYCODE_F1) )
+
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_1, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_2, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_3, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_4, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_5, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_6, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_7, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_8, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_9, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_10, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_11, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_12, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_13, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_14, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_15, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_UI, OSD_16, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_INVALID, UNKNOWN, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_INVALID, SPECIAL, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_INVALID, OTHER, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_INVALID, DIPSWITCH_NAME, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_INVALID, CONFIG_NAME, NULL, SEQ_DEF_0 )
+ INPUT_PORT_DIGITAL_DEF( 0, IPG_INVALID, END, NULL, SEQ_DEF_0 )
+};
+
+
+static input_port_default_entry default_ports[ARRAY_LENGTH(default_ports_builtin)];
+static input_port_default_entry default_ports_backup[ARRAY_LENGTH(default_ports_builtin)];
+static const int input_port_count = ARRAY_LENGTH(default_ports_builtin);
+static int default_ports_lookup[__ipt_max][MAX_PLAYERS];
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void setup_playback(running_machine *machine);
+static void setup_record(running_machine *machine);
+static void input_port_exit(running_machine *machine);
+static void input_port_load(int config_type, xml_data_node *parentnode);
+static void input_port_save(int config_type, xml_data_node *parentnode);
+static void update_digital_joysticks(void);
+static void update_analog_port(int port);
+static void interpolate_analog_port(int port);
+static void autoselect_device(const input_port_entry *ipt, int type1, int type2, int type3, const char *option, const char *ananame);
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*************************************
+ *
+ * Input port initialize
+ *
+ *************************************/
+
+void input_port_init(running_machine *machine, const input_port_token *ipt)
+{
+ int ipnum, player;
+
+ /* add an exit callback */
+ add_exit_callback(machine, input_port_exit);
+
+ /* start with the raw defaults and ask the OSD to customize them in the backup array */
+ memcpy(default_ports_backup, default_ports_builtin, sizeof(default_ports_backup));
+ osd_customize_inputport_list(default_ports_backup);
+
+ /* propogate these changes forward to the final input list */
+ memcpy(default_ports, default_ports_backup, sizeof(default_ports));
+
+ /* make a lookup table mapping type/player to the default port list entry */
+ for (ipnum = 0; ipnum < __ipt_max; ipnum++)
+ for (player = 0; player < MAX_PLAYERS; player++)
+ default_ports_lookup[ipnum][player] = -1;
+ for (ipnum = 0; default_ports[ipnum].type != IPT_END; ipnum++)
+ default_ports_lookup[default_ports[ipnum].type][default_ports[ipnum].player] = ipnum;
+
+ /* reset the port info */
+ memset(port_info, 0, sizeof(port_info));
+
+ /* if we have inputs, process them now */
+ if (ipt != NULL)
+ {
+ const char *joystick_map_default = options_get_string(mame_options(), OPTION_JOYSTICK_MAP);
+ input_port_entry *port;
+ int portnum;
+
+ /* allocate input ports */
+ machine->input_ports = input_port_allocate(ipt, NULL);
+
+ /* allocate default input ports */
+ input_ports_default = input_port_allocate(ipt, NULL);
+
+ /* handle autoselection of devices */
+ autoselect_device(machine->input_ports, IPT_PADDLE, IPT_PADDLE_V, 0, OPTION_PADDLE_DEVICE, "paddle");
+ autoselect_device(machine->input_ports, IPT_AD_STICK_X, IPT_AD_STICK_Y, IPT_AD_STICK_Z, OPTION_ADSTICK_DEVICE, "analog joystick");
+ autoselect_device(machine->input_ports, IPT_LIGHTGUN_X, IPT_LIGHTGUN_Y, 0, OPTION_LIGHTGUN_DEVICE, "lightgun");
+ autoselect_device(machine->input_ports, IPT_PEDAL, IPT_PEDAL2, IPT_PEDAL3, OPTION_PEDAL_DEVICE, "pedal");
+ autoselect_device(machine->input_ports, IPT_DIAL, IPT_DIAL_V, 0, OPTION_DIAL_DEVICE, "dial");
+ autoselect_device(machine->input_ports, IPT_TRACKBALL_X, IPT_TRACKBALL_Y, 0, OPTION_TRACKBALL_DEVICE, "trackball");
+ autoselect_device(machine->input_ports, IPT_POSITIONAL, IPT_POSITIONAL_V, 0, OPTION_POSITIONAL_DEVICE, "positional");
+ autoselect_device(machine->input_ports, IPT_MOUSE_X, IPT_MOUSE_Y, 0, OPTION_MOUSE_DEVICE, "mouse");
+
+ /* look for 4-way joysticks and change the default map if we find any */
+ if (joystick_map_default[0] == 0 || strcmp(joystick_map_default, "auto") == 0)
+ for (port = machine->input_ports; port->type != IPT_END; port++)
+ if (IS_DIGITAL_JOYSTICK(port) && port->way == 4)
+ {
+ input_device_set_joystick_map(-1, port->rotated ? joystick_map_4way_diagonal : joystick_map_4way_sticky);
+ break;
+ }
+
+ /* identify all the tagged ports up front so the memory system can access them */
+ portnum = 0;
+ for (port = machine->input_ports; port->type != IPT_END; port++)
+ if (port->type == IPT_PORT)
+ port_info[portnum++].tag = port->start.tag;
+
+ /* look up all the tags referenced in conditions */
+ for (port = machine->input_ports; port->type != IPT_END; port++)
+ if (port->condition.tag)
+ {
+ int tag = port_tag_to_index(port->condition.tag);
+ if (tag == -1)
+ fatalerror("Conditional port references invalid tag '%s'", port->condition.tag);
+ port->condition.portnum = tag;
+ }
+ }
+
+ /* register callbacks for when we load configurations */
+ config_register("input", input_port_load, input_port_save);
+
+ /* open playback and record files if specified */
+ setup_playback(machine);
+ setup_record(machine);
+}
+
+
+/*************************************
+ *
+ * Set up for playback
+ *
+ *************************************/
+
+static void setup_playback(running_machine *machine)
+{
+ const char *filename = options_get_string(mame_options(), OPTION_PLAYBACK);
+ inp_header inpheader;
+ file_error filerr;
+
+ struct ext_header xheader;
+ char check[7];
+
+ /* if no file, nothing to do */
+ if (filename[0] == 0)
+ return;
+
+ /* open the playback file */
+ filerr = mame_fopen(SEARCHPATH_INPUTLOG, filename, OPEN_FLAG_READ, &machine->playback_file);
+ assert_always(filerr == FILERR_NONE, "Failed to open file for playback");
+
+ // read first four bytes to check INP type
+ mame_fread(Machine->playback_file, check, 7);
+ mame_fseek(Machine->playback_file, 0, SEEK_SET);
+
+ /* Check if input file is an eXtended INP file */
+ if (strncmp(check,"XINP\0\0\0",7) != 0)
+ {
+ no_extended_inp = 1;
+ mame_printf_info("This INP file is not an extended INP file, extra info not available\n");
+
+ /* read playback header */
+ mame_fread(machine->playback_file, &inpheader, sizeof(inpheader));
+
+ /* if the first byte is not alphanumeric, it's an old INP file with no header */
+ if (!isalnum(inpheader.name[0]))
+ mame_fseek(machine->playback_file, 0, SEEK_SET);
+
+ /* else verify the header against the current game */
+ else if (strcmp(machine->gamedrv->name, inpheader.name) != 0)
+ fatalerror("Input file is for " GAMENOUN " '%s', not for current " GAMENOUN " '%s'\n", inpheader.name, machine->gamedrv->name);
+
+ /* otherwise, print a message indicating what's happening */
+ else
+ mame_printf_info("Playing back previously recorded " GAMENOUN " %s\n", machine->gamedrv->name);
+ }
+ else
+ {
+ no_extended_inp = 0;
+ mame_printf_info("Extended INP file info:\n");
+
+ // read header
+ mame_fread(Machine->playback_file, &xheader, sizeof(struct ext_header));
+
+ // output info to console
+ mame_printf_info("Version string: %s\n",xheader.version);
+ mame_printf_info("Start time: %s\n", ctime((const time_t *)&xheader.starttime));
+
+ // verify header against current game
+ if (strcmp(machine->gamedrv->name, xheader.shortname) != 0)
+ fatalerror("Input file is for " GAMENOUN " '%s', not for current " GAMENOUN " '%s'\n", xheader.shortname, machine->gamedrv->name);
+ else
+ mame_printf_info("Playing back previously recorded " GAMENOUN " %s\n", machine->gamedrv->name);
+ }
+
+}
+
+
+/*************************************
+ *
+ * Set up for recording
+ *
+ *************************************/
+
+static void setup_record(running_machine *machine)
+{
+ const char *filename = options_get_string(mame_options(), OPTION_RECORD);
+ inp_header inpheader;
+ file_error filerr;
+
+ /* if no file, nothing to do */
+ if (filename[0] == 0)
+ return;
+
+ /* open the record file */
+ filerr = mame_fopen(SEARCHPATH_INPUTLOG, filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &machine->record_file);
+ assert_always(filerr == FILERR_NONE, "Failed to open file for recording");
+
+ /* create a header */
+ memset(&inpheader, 0, sizeof(inpheader));
+ strcpy(inpheader.name, machine->gamedrv->name);
+ mame_fwrite(machine->record_file, &inpheader, sizeof(inpheader));
+}
+
+
+
+/*************************************
+ *
+ * Input port exit
+ *
+ *************************************/
+
+void input_port_exit(running_machine *machine)
+{
+ /* close any playback or recording files */
+ if (machine->playback_file != NULL)
+ mame_fclose(machine->playback_file);
+ if (machine->record_file != NULL)
+ mame_fclose(machine->record_file);
+}
+
+
+
+/*************************************
+ *
+ * Input port initialization
+ *
+ *************************************/
+
+static void input_port_postload(void)
+{
+ input_port_entry *port;
+ int portnum, bitnum;
+ UINT32 mask;
+
+ /* reset the pointers */
+ memset(&joystick_info, 0, sizeof(joystick_info));
+
+ /* loop over the ports and identify all the analog inputs */
+ portnum = -1;
+ bitnum = 0;
+ for (port = Machine->input_ports; port->type != IPT_END; port++)
+ {
+ /* if this is IPT_PORT, increment the port number */
+ if (port->type == IPT_PORT)
+ {
+ portnum++;
+ bitnum = 0;
+ }
+
+ /* if this is not a DIP setting or config setting, add it to the list */
+ else if (port->type != IPT_DIPSWITCH_SETTING && port->type != IPT_CONFIG_SETTING)
+ {
+ /* fatal error if we didn't hit an IPT_PORT */
+ if (portnum < 0)
+ fatalerror("Error in InputPort definition: expecting PORT_START");
+
+ /* fatal error if too many bits */
+ if (bitnum >= MAX_BITS_PER_PORT)
+ fatalerror("Error in InputPort definition: too many bits for a port (%d max)", MAX_BITS_PER_PORT);
+
+ /* fill in the bit info */
+ port_info[portnum].bit[bitnum].port = port;
+ port_info[portnum].bit[bitnum].impulse = 0;
+ port_info[portnum].bit[bitnum++].last = 0;
+
+ /* if this is a custom input, add it to the list */
+ if (port->custom != NULL)
+ {
+ custom_port_info *info;
+
+ /* allocate memory */
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ /* fill in the data */
+ info->port = port;
+ for (mask = port->mask; !(mask & 1); mask >>= 1)
+ info->shift++;
+
+ /* hook in the list */
+ info->next = port_info[portnum].custominfo;
+ port_info[portnum].custominfo = info;
+ }
+
+ /* if this is an analog port, create an info struct for it */
+ else if (IS_ANALOG(port))
+ {
+ analog_port_info *info;
+
+ /* allocate memory */
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ /* fill in the data */
+ info->port = port;
+ for (mask = port->mask; !(mask & 1); mask >>= 1)
+ info->shift++;
+ for ( ; mask & 1; mask >>= 1)
+ info->bits++;
+
+ /* based on the port type determine if we need absolute or relative coordinates */
+ info->minimum = INPUT_ABSOLUTE_MIN;
+ info->maximum = INPUT_ABSOLUTE_MAX;
+ info->interpolate = 1;
+
+ /* adjust default, min, and max so they fall in the bitmask range */
+ port->default_value = (port->default_value & port->mask) >> info->shift;
+ if (port->type != IPT_POSITIONAL && port->type != IPT_POSITIONAL_V)
+ {
+ port->analog.min = (port->analog.min & port->mask) >> info->shift;
+ port->analog.max = (port->analog.max & port->mask) >> info->shift;
+ }
+
+ switch (port->type)
+ {
+ /* pedals start at and autocenter to the min range*/
+ case IPT_PEDAL:
+ case IPT_PEDAL2:
+ case IPT_PEDAL3:
+ info->center = INPUT_ABSOLUTE_MIN;
+ /* force pedals to start at their scaled minimum */
+ info->accum = APPLY_INVERSE_SENSITIVITY(info->center, port->analog.sensitivity);
+ /* fall through to complete setup */
+
+ /* pedals, paddles and analog joysticks are absolute and autocenter */
+ case IPT_AD_STICK_X:
+ case IPT_AD_STICK_Y:
+ case IPT_AD_STICK_Z:
+ case IPT_PADDLE:
+ case IPT_PADDLE_V:
+ info->absolute = 1;
+ info->autocenter = 1;
+ break;
+
+ /* lightguns are absolute as well, but don't autocenter and don't interpolate their values */
+ case IPT_LIGHTGUN_X:
+ case IPT_LIGHTGUN_Y:
+ info->absolute = 1;
+ info->interpolate = 0;
+ break;
+
+ /* dials, mice and trackballs are relative devices */
+ /* these have fixed "min" and "max" values based on how many bits are in the port */
+ /* in addition, we set the wrap around min/max values to 512 * the min/max values */
+ /* this takes into account the mapping that one mouse unit ~= 512 analog units */
+ case IPT_DIAL:
+ case IPT_DIAL_V:
+ case IPT_MOUSE_X:
+ case IPT_MOUSE_Y:
+ case IPT_TRACKBALL_X:
+ case IPT_TRACKBALL_Y:
+ info->absolute = 0;
+ info->wraps = 1;
+ break;
+
+ /* positional devices are abolute, but can also wrap like relative devices */
+ /* set each position to be 512 units */
+ case IPT_POSITIONAL:
+ case IPT_POSITIONAL_V:
+ info->positionalscale = (double)(port->analog.max) / (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN);
+ /* force to only use PORT_POSITIONS data */
+ port->analog.min = 0;
+ port->analog.max--;
+ info->autocenter = !port->analog.wraps;
+ info->wraps = port->analog.wraps;
+ break;
+
+ default:
+ fatalerror("Unknown analog port type -- don't know if it is absolute or not");
+ break;
+ }
+
+ if (info->absolute)
+ {
+ /* if we are receiving data from the OSD input as absolute,
+ * and the emulated port type is absolute,
+ * and the default port value is between min/max,
+ * we need to scale differently for the +/- directions.
+ * All other absolute types use a 1:1 scale */
+ info->single_scale = (port->default_value == port->analog.min) || (port->default_value == port->analog.max);
+
+ if (!info->single_scale)
+ {
+ /* axis moves in both directions from the default value */
+
+ /* unsigned */
+ info->scalepos = ((double)port->analog.max - (double)port->default_value) / (double)(INPUT_ABSOLUTE_MAX - 0);
+ info->scaleneg = ((double)port->default_value - (double)port->analog.min) / (double)(0 - INPUT_ABSOLUTE_MIN);
+
+ if (port->analog.min > port->analog.max)
+ {
+ /* signed */
+ info->scaleneg *= -1;
+ }
+
+ /* reverse from center */
+ info->reverse_val = 0;
+ }
+ else
+ {
+ /* single axis that increases from default */
+ info->scalepos = (double)(port->analog.max - port->analog.min) / (double)(INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN);
+
+ /* move from default */
+ if (port->default_value == port->analog.max)
+ info->scalepos *= -1;
+
+ /* make the scaling the same for easier coding when we need to scale */
+ info->scaleneg = info->scalepos;
+
+ /* reverse from max */
+ info->reverse_val = info->maximum;
+ }
+ }
+
+ /* relative and positional controls all map directly with a 512x scale factor */
+ else
+ {
+ /* The relative code is set up to allow specifing PORT_MINMAX and default values. */
+ /* The validity checks are purposely set up to not allow you to use anything other */
+ /* a default of 0 and PORT_MINMAX(0,mask). This is in case the need arises to use */
+ /* this feature in the future. Keeping the code in does not hurt anything. */
+ if (port->analog.min > port->analog.max)
+ /* adjust for signed */
+ port->analog.min *= -1;
+
+ info->minimum = (port->analog.min - port->default_value) * 512;
+ info->maximum = (port->analog.max - port->default_value) * 512;
+
+ /* make the scaling the same for easier coding when we need to scale */
+ info->scaleneg = info->scalepos = 1.0 / 512.0;
+
+ if (port->analog.reset)
+ /* delta values reverse from center */
+ info->reverse_val = 0;
+ else
+ {
+ /* positional controls reverse from their max range */
+ info->reverse_val = info->maximum + info->minimum;
+
+ /* relative controls reverse from 1 past their max range */
+ if (info->positionalscale == 0) info->reverse_val += 512;
+ }
+ }
+
+ /* compute scale for keypresses */
+ info->keyscalepos = 1.0 / info->scalepos;
+ info->keyscaleneg = 1.0 / info->scaleneg;
+
+ /* hook in the list */
+ info->next = port_info[portnum].analoginfo;
+ port_info[portnum].analoginfo = info;
+ }
+
+ /* if this is a digital joystick port, update info on it */
+ else if (IS_DIGITAL_JOYSTICK(port))
+ {
+ digital_joystick_info *info = JOYSTICK_INFO_FOR_PORT(port);
+ info->port[JOYSTICK_DIR_FOR_PORT(port)] = port;
+ info->inuse = 1;
+ }
+ }
+ }
+
+ /* run an initial update */
+ input_port_vblank_start();
+}
+
+
+
+/*************************************
+ *
+ * Identifies which port types are
+ * saved/loaded
+ *
+ *************************************/
+
+static int save_this_port_type(int type)
+{
+ switch (type)
+ {
+ case IPT_UNUSED:
+ case IPT_END:
+ case IPT_PORT:
+ case IPT_DIPSWITCH_SETTING:
+ case IPT_CONFIG_SETTING:
+ case IPT_CATEGORY_SETTING:
+ case IPT_VBLANK:
+ case IPT_UNKNOWN:
+ return 0;
+ }
+ return 1;
+}
+
+
+
+/*************************************
+ *
+ * Input port configuration read
+ *
+ *************************************/
+
+INLINE input_code get_default_code(int config_type, int type)
+{
+ switch (type)
+ {
+ case IPT_DIPSWITCH_NAME:
+ case IPT_CATEGORY_NAME:
+ return SEQCODE_END;
+
+ default:
+ if (config_type != CONFIG_TYPE_GAME)
+ return SEQCODE_END;
+ else
+ return SEQCODE_DEFAULT;
+ }
+ return SEQCODE_END;
+}
+
+
+INLINE int string_to_seq_index(const char *string)
+{
+ int seqindex;
+
+ for (seqindex = 0; seqindex < ARRAY_LENGTH(seqtypestrings); seqindex++)
+ if (!mame_stricmp(string, seqtypestrings[seqindex]))
+ return seqindex;
+
+ return -1;
+}
+
+
+static void apply_remaps(int count, const input_code *oldtable, const input_code *newtable)
+{
+ int remapnum;
+
+ /* loop over the remapping table, operating only if something was specified */
+ for (remapnum = 0; remapnum < count; remapnum++)
+ {
+ input_code oldcode = oldtable[remapnum];
+ input_code newcode = newtable[remapnum];
+ int portnum;
+
+ /* loop over all default ports, remapping the requested keys */
+ for (portnum = 0; default_ports[portnum].type != IPT_END; portnum++)
+ {
+ input_port_default_entry *defport = &default_ports[portnum];
+ int seqnum;
+
+ /* remap anything in the default sequences */
+ for (seqnum = 0; seqnum < ARRAY_LENGTH(defport->defaultseq.code); seqnum++)
+ if (defport->defaultseq.code[seqnum] == oldcode)
+ defport->defaultseq.code[seqnum] = newcode;
+ for (seqnum = 0; seqnum < ARRAY_LENGTH(defport->defaultdecseq.code); seqnum++)
+ if (defport->defaultdecseq.code[seqnum] == oldcode)
+ defport->defaultdecseq.code[seqnum] = newcode;
+ for (seqnum = 0; seqnum < ARRAY_LENGTH(defport->defaultincseq.code); seqnum++)
+ if (defport->defaultincseq.code[seqnum] == oldcode)
+ defport->defaultincseq.code[seqnum] = newcode;
+ }
+ }
+}
+
+
+
+static int apply_config_to_default(xml_data_node *portnode, int type, int player, input_seq *newseq)
+{
+ int portnum;
+
+ /* find a matching port in the list */
+ for (portnum = 0; portnum < ARRAY_LENGTH(default_ports_backup); portnum++)
+ {
+ input_port_default_entry *updateport = &default_ports[portnum];
+ if (updateport->type == type && updateport->player == player)
+ {
+ /* copy the sequence(s) that were specified */
+ if (input_seq_get_1(&newseq[0]) != INPUT_CODE_INVALID)
+ updateport->defaultseq = newseq[0];
+ if (input_seq_get_1(&newseq[1]) != INPUT_CODE_INVALID)
+ updateport->defaultdecseq = newseq[1];
+ if (input_seq_get_1(&newseq[2]) != INPUT_CODE_INVALID)
+ updateport->defaultincseq = newseq[2];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static int apply_config_to_current(xml_data_node *portnode, int type, int player, input_seq *newseq)
+{
+ input_port_entry *updateport;
+ int mask, defvalue, index;
+
+ /* read the mask, index, and defvalue attributes */
+ index = xml_get_attribute_int(portnode, "index", 0);
+ mask = xml_get_attribute_int(portnode, "mask", 0);
+ defvalue = xml_get_attribute_int(portnode, "defvalue", 0);
+
+ /* find the indexed port; we scan the array to make sure we don't read past the end */
+ for (updateport = input_ports_default; updateport->type != IPT_END; updateport++)
+ if (index-- == 0)
+ break;
+
+ /* verify that it matches */
+ if (updateport->type == type && updateport->player == player &&
+ updateport->mask == mask && (updateport->default_value & mask) == (defvalue & mask))
+ {
+ const char *revstring;
+
+ /* point to the real port */
+ updateport = Machine->input_ports + (updateport - input_ports_default);
+
+ /* fill in the data from the attributes */
+ if (!port_type_is_analog(updateport->type))
+ updateport->default_value = xml_get_attribute_int(portnode, "value", updateport->default_value);
+ updateport->analog.delta = xml_get_attribute_int(portnode, "keydelta", updateport->analog.delta);
+ updateport->analog.centerdelta = xml_get_attribute_int(portnode, "centerdelta", updateport->analog.centerdelta);
+ updateport->analog.sensitivity = xml_get_attribute_int(portnode, "sensitivity", updateport->analog.sensitivity);
+ revstring = xml_get_attribute_string(portnode, "reverse", NULL);
+ if (revstring)
+ updateport->analog.reverse = (strcmp(revstring, "yes") == 0);
+
+ /* copy the sequence(s) that were specified */
+ if (input_seq_get_1(&newseq[0]) != INPUT_CODE_INVALID)
+ updateport->seq = newseq[0];
+ if (input_seq_get_1(&newseq[1]) != INPUT_CODE_INVALID)
+ updateport->analog.decseq = newseq[1];
+ if (input_seq_get_1(&newseq[2]) != INPUT_CODE_INVALID)
+ updateport->analog.incseq = newseq[2];
+ return 1;
+ }
+ return 0;
+}
+
+
+static void input_port_load(int config_type, xml_data_node *parentnode)
+{
+ xml_data_node *portnode;
+ int seqnum;
+
+ /* in the completion phase, we finish the initialization with the final ports */
+ if (config_type == CONFIG_TYPE_FINAL)
+ input_port_postload();
+
+ /* early exit if no data to parse */
+ if (!parentnode)
+ return;
+
+ /* iterate over all the remap nodes for controller configs only */
+ if (config_type == CONFIG_TYPE_CONTROLLER)
+ {
+ input_code *oldtable, *newtable;
+ xml_data_node *remapnode;
+ int count;
+
+ /* count items first so we can allocate */
+ count = 0;
+ for (remapnode = xml_get_sibling(parentnode->child, "remap"); remapnode; remapnode = xml_get_sibling(remapnode->next, "remap"))
+ count++;
+
+ /* if we have some, deal with them */
+ if (count > 0)
+ {
+ /* allocate tables */
+ oldtable = malloc_or_die(count * sizeof(*oldtable));
+ newtable = malloc_or_die(count * sizeof(*newtable));
+
+ /* build up the remap table */
+ count = 0;
+ for (remapnode = xml_get_sibling(parentnode->child, "remap"); remapnode; remapnode = xml_get_sibling(remapnode->next, "remap"))
+ {
+ input_code origcode = input_code_from_token(xml_get_attribute_string(remapnode, "origcode", ""));
+ input_code newcode = input_code_from_token(xml_get_attribute_string(remapnode, "newcode", ""));
+ if (origcode != INPUT_CODE_INVALID && newcode != INPUT_CODE_INVALID)
+ {
+ oldtable[count] = origcode;
+ newtable[count] = newcode;
+ count++;
+ }
+ }
+
+ /* apply it then free the tables */
+ apply_remaps(count, oldtable, newtable);
+ free(oldtable);
+ free(newtable);
+ }
+ }
+
+ /* iterate over all the port nodes */
+ for (portnode = xml_get_sibling(parentnode->child, "port"); portnode; portnode = xml_get_sibling(portnode->next, "port"))
+ {
+ input_seq newseq[3], tempseq;
+ xml_data_node *seqnode;
+ int type, player;
+
+ /* get the basic port info from the attributes */
+ type = token_to_port_type(xml_get_attribute_string(portnode, "type", ""), &player);
+
+ /* initialize sequences to invalid defaults */
+ for (seqnum = 0; seqnum < 3; seqnum++)
+ input_seq_set_1(&newseq[seqnum], INPUT_CODE_INVALID);
+
+ /* loop over new sequences */
+ for (seqnode = xml_get_sibling(portnode->child, "newseq"); seqnode; seqnode = xml_get_sibling(seqnode->next, "newseq"))
+ {
+ /* with a valid type, parse out the new sequence */
+ seqnum = string_to_seq_index(xml_get_attribute_string(seqnode, "type", ""));
+ if (seqnum != -1)
+ if (seqnode->value != NULL)
+ {
+ if (strcmp(seqnode->value, "NONE") == 0)
+ input_seq_set_0(&newseq[seqnum]);
+ else if (input_seq_from_tokens(seqnode->value, &tempseq) != 0)
+ newseq[seqnum] = tempseq;
+ }
+ }
+
+ /* if we're loading default ports, apply to the default_ports */
+ if (config_type != CONFIG_TYPE_GAME)
+ apply_config_to_default(portnode, type, player, newseq);
+ else
+ apply_config_to_current(portnode, type, player, newseq);
+ }
+
+ /* after applying the controller config, push that back into the backup, since that is */
+ /* what we will diff against */
+ if (config_type == CONFIG_TYPE_CONTROLLER)
+ memcpy(default_ports_backup, default_ports, sizeof(default_ports_backup));
+}
+
+
+
+/*************************************
+ *
+ * Input port configuration write
+ *
+ *************************************/
+
+static void add_sequence(xml_data_node *parentnode, int type, int porttype, const input_seq *seq)
+{
+ astring *seqstring = astring_alloc();
+ xml_data_node *seqnode;
+
+ /* get the string for the sequence */
+ if (input_seq_get_1(seq) == SEQCODE_END)
+ astring_cpyc(seqstring, "NONE");
+ else
+ input_seq_to_tokens(seqstring, seq);
+
+ /* add the new node */
+ seqnode = xml_add_child(parentnode, "newseq", astring_c(seqstring));
+ if (seqnode)
+ xml_set_attribute(seqnode, "type", seqtypestrings[type]);
+ astring_free(seqstring);
+}
+
+
+static void save_default_inputs(xml_data_node *parentnode)
+{
+ int portnum;
+
+ /* iterate over ports */
+ for (portnum = 0; portnum < ARRAY_LENGTH(default_ports_backup); portnum++)
+ {
+ input_port_default_entry *defport = &default_ports_backup[portnum];
+ input_port_default_entry *curport = &default_ports[portnum];
+
+ /* only save if something has changed and this port is a type we save */
+ if (save_this_port_type(defport->type) &&
+ (input_seq_cmp(&defport->defaultseq, &curport->defaultseq) != 0 ||
+ input_seq_cmp(&defport->defaultdecseq, &curport->defaultdecseq) != 0 ||
+ input_seq_cmp(&defport->defaultincseq, &curport->defaultincseq) != 0))
+ {
+ /* add a new port node */
+ xml_data_node *portnode = xml_add_child(parentnode, "port", NULL);
+ if (portnode)
+ {
+ /* add the port information and attributes */
+ xml_set_attribute(portnode, "type", port_type_to_token(defport->type, defport->player));
+
+ /* add only the sequences that have changed from the defaults */
+ if (input_seq_cmp(&defport->defaultseq, &curport->defaultseq) != 0)
+ add_sequence(portnode, 0, defport->type, &curport->defaultseq);
+ if (input_seq_cmp(&defport->defaultdecseq, &curport->defaultdecseq) != 0)
+ add_sequence(portnode, 1, defport->type, &curport->defaultdecseq);
+ if (input_seq_cmp(&defport->defaultincseq, &curport->defaultincseq) != 0)
+ add_sequence(portnode, 2, defport->type, &curport->defaultincseq);
+ }
+ }
+ }
+}
+
+
+static void save_game_inputs(xml_data_node *parentnode)
+{
+ int portnum;
+
+ /* iterate over ports */
+ for (portnum = 0; input_ports_default[portnum].type != IPT_END; portnum++)
+ {
+ input_port_entry *defport = &input_ports_default[portnum];
+ input_port_entry *curport = &Machine->input_ports[portnum];
+
+ /* only save if something has changed and this port is a type we save */
+ if (save_this_port_type(defport->type) &&
+ ((!port_type_is_analog(defport->type) && (defport->default_value & defport->mask) != (curport->default_value & defport->mask)) ||
+ defport->analog.delta != curport->analog.delta ||
+ defport->analog.centerdelta != curport->analog.centerdelta ||
+ defport->analog.sensitivity != curport->analog.sensitivity ||
+ defport->analog.reverse != curport->analog.reverse ||
+ input_seq_cmp(&defport->seq, &curport->seq) != 0 ||
+ input_seq_cmp(&defport->analog.decseq, &curport->analog.decseq) != 0 ||
+ input_seq_cmp(&defport->analog.incseq, &curport->analog.incseq) != 0))
+ {
+ /* add a new port node */
+ xml_data_node *portnode = xml_add_child(parentnode, "port", NULL);
+ if (portnode)
+ {
+ /* add the port information and attributes */
+ xml_set_attribute(portnode, "type", port_type_to_token(defport->type, defport->player));
+ xml_set_attribute_int(portnode, "mask", defport->mask);
+ xml_set_attribute_int(portnode, "index", portnum);
+ xml_set_attribute_int(portnode, "defvalue", defport->default_value & defport->mask);
+
+ /* if the value has changed, add it as well */
+ if (!port_type_is_analog(defport->type) && defport->default_value != curport->default_value)
+ xml_set_attribute_int(portnode, "value", curport->default_value & defport->mask);
+
+ /* add analog-specific attributes if they have changed */
+ if (port_type_is_analog(defport->type))
+ {
+ if (defport->analog.delta != curport->analog.delta)
+ xml_set_attribute_int(portnode, "keydelta", curport->analog.delta);
+ if (defport->analog.centerdelta != curport->analog.centerdelta)
+ xml_set_attribute_int(portnode, "centerdelta", curport->analog.centerdelta);
+ if (defport->analog.sensitivity != curport->analog.sensitivity)
+ xml_set_attribute_int(portnode, "sensitivity", curport->analog.sensitivity);
+ if (defport->analog.reverse != curport->analog.reverse)
+ xml_set_attribute(portnode, "reverse", curport->analog.reverse ? "yes" : "no");
+ }
+
+ /* add only the sequences that have changed from the defaults */
+ if (input_seq_cmp(&defport->seq, &curport->seq) != 0)
+ add_sequence(portnode, 0, defport->type, &curport->seq);
+ if (input_seq_cmp(&defport->analog.decseq, &curport->analog.decseq) != 0)
+ add_sequence(portnode, 1, defport->type, &curport->analog.decseq);
+ if (input_seq_cmp(&defport->analog.incseq, &curport->analog.incseq) != 0)
+ add_sequence(portnode, 2, defport->type, &curport->analog.incseq);
+ }
+ }
+ }
+}
+
+
+static void input_port_save(int config_type, xml_data_node *parentnode)
+{
+ if (parentnode)
+ {
+ /* default ports save differently */
+ if (config_type == CONFIG_TYPE_DEFAULT)
+ save_default_inputs(parentnode);
+ else
+ save_game_inputs(parentnode);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Token to default string
+ *
+ *************************************/
+
+const char *input_port_string_from_token(const input_port_token token)
+{
+ int index;
+
+ if (token == 0)
+ return NULL;
+ if ((FPTR)token >= INPUT_STRING_COUNT)
+ return (const char *)token;
+ for (index = 0; index < ARRAY_LENGTH(input_port_default_strings); index++)
+ if (input_port_default_strings[index].id == (FPTR)token)
+ return input_port_default_strings[index].string;
+ return "(Unknown Default)";
+}
+
+
+
+/*************************************
+ *
+ * Input port detokenizer
+ *
+ *************************************/
+
+static void input_port_detokenize(input_port_init_params *param, const input_port_token *ipt)
+{
+ UINT32 entrytype = INPUT_TOKEN_INVALID;
+ input_port_entry *port = NULL;
+ const char *modify_tag = NULL;
+ int seq_index[3] = {0};
+
+ /* loop over tokens until we hit the end */
+ while (entrytype != INPUT_TOKEN_END)
+ {
+ UINT32 mask, defval, type, val;
+
+ /* the entry is the first of a UINT32 pair */
+ /* note that we advance IPT assuming that there is no second half */
+ entrytype = INPUT_PORT_PAIR_ITEM(ipt++, 0);
+ switch (entrytype)
+ {
+ /* end */
+ case INPUT_TOKEN_END:
+ break;
+
+ /* including */
+ case INPUT_TOKEN_INCLUDE:
+ input_port_detokenize(param, (const input_port_token *)*ipt++);
+ break;
+
+ /* start of a new input port */
+ case INPUT_TOKEN_START:
+ case INPUT_TOKEN_START_TAG:
+ modify_tag = NULL;
+ port = input_port_initialize(param, IPT_PORT, NULL, 0, 0);
+ if (entrytype == INPUT_TOKEN_START_TAG)
+ port->start.tag = (const char *)*ipt++;
+ break;
+
+ /* modify an existing port */
+ case INPUT_TOKEN_MODIFY:
+ modify_tag = (const char *)*ipt++;
+ break;
+
+ /* input bit definition */
+ case INPUT_TOKEN_BIT:
+ type = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ mask = INPUT_PORT_PAIR_ITEM(ipt, 0);
+ defval = INPUT_PORT_PAIR_ITEM(ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+
+ port = input_port_initialize(param, type, modify_tag, mask, defval);
+ seq_index[0] = seq_index[1] = seq_index[2] = 0;
+ break;
+
+ /* append a code */
+ case INPUT_TOKEN_CODE:
+ val = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ if (seq_index[0] > 0)
+ port->seq.code[seq_index[0]++] = SEQCODE_OR;
+ port->seq.code[seq_index[0]++] = val;
+ break;
+
+ case INPUT_TOKEN_CODE_DEC:
+ val = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ if (seq_index[1] > 0)
+ port->analog.decseq.code[seq_index[1]++] = SEQCODE_OR;
+ port->analog.decseq.code[seq_index[1]++] = val;
+ break;
+
+ case INPUT_TOKEN_CODE_INC:
+ val = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ if (seq_index[2] > 0)
+ port->analog.incseq.code[seq_index[2]++] = SEQCODE_OR;
+ port->analog.incseq.code[seq_index[2]++] = val;
+ break;
+
+ /* joystick flags */
+ case INPUT_TOKEN_2WAY:
+ case INPUT_TOKEN_4WAY:
+ case INPUT_TOKEN_8WAY:
+ case INPUT_TOKEN_16WAY:
+ port->way = 2 << (entrytype - INPUT_TOKEN_2WAY);
+ break;
+
+ case INPUT_TOKEN_ROTATED:
+ port->rotated = TRUE;
+ break;
+
+ /* general flags */
+ case INPUT_TOKEN_NAME:
+ port->name = input_port_string_from_token(*ipt++);
+ break;
+
+ case INPUT_TOKEN_PLAYER1:
+ case INPUT_TOKEN_PLAYER2:
+ case INPUT_TOKEN_PLAYER3:
+ case INPUT_TOKEN_PLAYER4:
+ case INPUT_TOKEN_PLAYER5:
+ case INPUT_TOKEN_PLAYER6:
+ case INPUT_TOKEN_PLAYER7:
+ case INPUT_TOKEN_PLAYER8:
+ port->player = entrytype - INPUT_TOKEN_PLAYER1;
+ break;
+
+ case INPUT_TOKEN_COCKTAIL:
+ port->cocktail = TRUE;
+ port->player = 1;
+ break;
+
+ case INPUT_TOKEN_TOGGLE:
+ port->toggle = TRUE;
+ break;
+
+ case INPUT_TOKEN_IMPULSE:
+ port->impulse = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ break;
+
+ case INPUT_TOKEN_REVERSE:
+ port->analog.reverse = TRUE;
+ break;
+
+ case INPUT_TOKEN_RESET:
+ port->analog.reset = TRUE;
+ break;
+
+ case INPUT_TOKEN_UNUSED:
+ port->unused = TRUE;
+ break;
+
+ /* analog settings */
+ case INPUT_TOKEN_MINMAX:
+ port->analog.min = INPUT_PORT_PAIR_ITEM(ipt, 0);
+ port->analog.max = INPUT_PORT_PAIR_ITEM(ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ break;
+
+ case INPUT_TOKEN_SENSITIVITY:
+ port->analog.sensitivity = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ break;
+
+ case INPUT_TOKEN_KEYDELTA:
+ port->analog.delta = port->analog.centerdelta = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ break;
+
+ case INPUT_TOKEN_CENTERDELTA:
+ port->analog.centerdelta = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ break;
+
+ case INPUT_TOKEN_CROSSHAIR:
+ port->analog.crossaxis = INPUT_PORT_PAIR_ITEM(--ipt, 1) & 0xff;
+ port->analog.crossaltaxis = (float)((INT32)INPUT_PORT_PAIR_ITEM(ipt, 1) >> 8) / 65536.0f;
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ port->analog.crossscale = (float)(INT32)INPUT_PORT_PAIR_ITEM(ipt, 0) / 65536.0f;
+ port->analog.crossoffset = (float)(INT32)INPUT_PORT_PAIR_ITEM(ipt, 1) / 65536.0f;
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ break;
+
+ case INPUT_TOKEN_FULL_TURN_COUNT:
+ port->analog.full_turn_count = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ break;
+
+ case INPUT_TOKEN_POSITIONS:
+ port->analog.max = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ break;
+
+ case INPUT_TOKEN_WRAPS:
+ port->analog.wraps = TRUE;
+ break;
+
+ case INPUT_TOKEN_REMAP_TABLE:
+ port->analog.remap_table = (UINT32 *)*ipt++;
+ break;
+
+ case INPUT_TOKEN_INVERT:
+ port->analog.invert = TRUE;
+ break;
+
+ /* custom callbacks */
+ case INPUT_TOKEN_CUSTOM:
+ port->custom = (UINT32 (*)(void *))*ipt++;
+ port->custom_param = (void *)*ipt++;
+ break;
+
+ /* dip switch definition */
+ case INPUT_TOKEN_DIPNAME:
+ mask = INPUT_PORT_PAIR_ITEM(ipt, 0);
+ defval = INPUT_PORT_PAIR_ITEM(ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+
+ port = input_port_initialize(param, IPT_DIPSWITCH_NAME, modify_tag, mask, defval);
+ seq_index[0] = seq_index[1] = seq_index[2] = 0;
+ port->name = input_port_string_from_token(*ipt++);
+ break;
+
+ case INPUT_TOKEN_DIPSETTING:
+ defval = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+
+ port = input_port_initialize(param, IPT_DIPSWITCH_SETTING, modify_tag, 0, defval);
+ seq_index[0] = seq_index[1] = seq_index[2] = 0;
+ port->name = input_port_string_from_token(*ipt++);
+ break;
+
+ /* physical location */
+ case INPUT_TOKEN_DIPLOCATION:
+ input_port_parse_diplocation(port, (const char *)*ipt++);
+ break;
+
+ /* conditionals for dip switch settings */
+ case INPUT_TOKEN_CONDITION:
+ port->condition.condition = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ port->condition.mask = INPUT_PORT_PAIR_ITEM(ipt, 0);
+ port->condition.value = INPUT_PORT_PAIR_ITEM(ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ port->condition.tag = (const char *)*ipt++;
+ break;
+
+ /* analog adjuster definition */
+ case INPUT_TOKEN_ADJUSTER:
+ defval = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+
+ port = input_port_initialize(param, IPT_ADJUSTER, modify_tag, 0xff, defval | (defval << 8));
+ seq_index[0] = seq_index[1] = seq_index[2] = 0;
+ port->name = input_port_string_from_token(*ipt++);
+ break;
+
+ /* configuration definition */
+ case INPUT_TOKEN_CONFNAME:
+ mask = INPUT_PORT_PAIR_ITEM(ipt, 0);
+ defval = INPUT_PORT_PAIR_ITEM(ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+
+ port = input_port_initialize(param, IPT_CONFIG_NAME, modify_tag, mask, defval);
+ seq_index[0] = seq_index[1] = seq_index[2] = 0;
+ port->name = input_port_string_from_token(*ipt++);
+ break;
+
+ case INPUT_TOKEN_CONFSETTING:
+ defval = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+
+ port = input_port_initialize(param, IPT_CONFIG_SETTING, modify_tag, 0, defval);
+ seq_index[0] = seq_index[1] = seq_index[2] = 0;
+ port->name = input_port_string_from_token(*ipt++);
+ break;
+
+#ifdef MESS
+ case INPUT_TOKEN_CHAR:
+ val = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+
+ {
+ int ch;
+ for (ch = 0; port->keyboard.chars[ch] != 0; ch++)
+ ;
+ port->keyboard.chars[ch] = (unicode_char) val;
+ }
+ break;
+
+ /* category definition */
+ case INPUT_TOKEN_CATEGORY:
+ port->category = (UINT16) INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+ break;
+
+ case INPUT_TOKEN_CATEGORY_NAME:
+ mask = INPUT_PORT_PAIR_ITEM(ipt, 0);
+ defval = INPUT_PORT_PAIR_ITEM(ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+
+ port = input_port_initialize(param, IPT_CATEGORY_NAME, modify_tag, mask, defval);
+ seq_index[0] = seq_index[1] = seq_index[2] = 0;
+ port->name = input_port_string_from_token(*ipt++);
+ break;
+
+ case INPUT_TOKEN_CATEGORY_SETTING:
+ defval = INPUT_PORT_PAIR_ITEM(--ipt, 1);
+ ipt += INPUT_PORT_PAIR_TOKENS;
+
+ port = input_port_initialize(param, IPT_CATEGORY_SETTING, modify_tag, 0, defval);
+ seq_index[0] = seq_index[1] = seq_index[2] = 0;
+ port->name = input_port_string_from_token(*ipt++);
+ break;
+#endif /* MESS */
+
+ default:
+ fatalerror("unknown port entry type");
+ break;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Input port construction
+ *
+ *************************************/
+
+input_port_entry *input_port_initialize(input_port_init_params *iip, UINT32 type, const char *tag, UINT32 mask, UINT32 defval)
+{
+ /* this function is used within an INPUT_PORT callback to set up a single port */
+ input_port_entry *port;
+ input_code code;
+
+ /* are we modifying an existing port? */
+ if (tag != NULL)
+ {
+ int portnum, deleting;
+
+ /* find the matching port */
+ for (portnum = 0; portnum < iip->current_port; portnum++)
+ if (iip->ports[portnum].type == IPT_PORT && iip->ports[portnum].start.tag != NULL && !strcmp(iip->ports[portnum].start.tag, tag))
+ break;
+ if (portnum >= iip->current_port)
+ fatalerror("Could not find port to modify: '%s'", tag);
+
+ /* nuke any matching masks */
+ for (portnum++, deleting = 0; portnum < iip->current_port && iip->ports[portnum].type != IPT_PORT; portnum++)
+ {
+ deleting = (iip->ports[portnum].mask & mask) || (deleting && iip->ports[portnum].mask == 0);
+ if (deleting)
+ {
+ iip->current_port--;
+ memmove(&iip->ports[portnum], &iip->ports[portnum + 1], (iip->current_port - portnum) * sizeof(iip->ports[0]));
+ portnum--;
+ }
+ }
+
+ /* allocate space for a new port at the end of this entry */
+ if (iip->current_port >= iip->max_ports)
+ fatalerror("Too many input ports");
+ if (portnum < iip->current_port)
+ {
+ memmove(&iip->ports[portnum + 1], &iip->ports[portnum], (iip->current_port - portnum) * sizeof(iip->ports[0]));
+ iip->current_port++;
+ port = &iip->ports[portnum];
+ }
+ else
+ port = &iip->ports[iip->current_port++];
+ }
+
+ /* otherwise, just allocate a new one from the end */
+ else
+ {
+ if (iip->current_port >= iip->max_ports)
+ fatalerror("Too many input ports");
+ port = &iip->ports[iip->current_port++];
+ }
+
+ /* set up defaults */
+ memset(port, 0, sizeof(*port));
+ port->name = IP_NAME_DEFAULT;
+ port->type = type;
+ port->mask = mask;
+ port->default_value = defval;
+
+ /* default min to 0 and max to the mask value */
+ /* they can be overwritten by PORT_MINMAX */
+ if (port_type_is_analog(port->type) && !port->analog.min && !port->analog.max)
+ port->analog.max = port->mask;
+
+ /* sets up default port codes */
+ switch (port->type)
+ {
+ case IPT_DIPSWITCH_NAME:
+ case IPT_DIPSWITCH_SETTING:
+ case IPT_CONFIG_NAME:
+ case IPT_CONFIG_SETTING:
+ code = SEQCODE_END;
+ break;
+
+ default:
+ code = SEQCODE_DEFAULT;
+ break;
+ }
+
+ /* set the default codes */
+ input_seq_set_1(&port->seq, code);
+ input_seq_set_1(&port->analog.incseq, code);
+ input_seq_set_1(&port->analog.decseq, code);
+ return port;
+}
+
+
+input_port_entry *input_port_allocate(const input_port_token *ipt, input_port_entry *memory)
+{
+ input_port_init_params iip;
+
+ /* set up the port parameter structure */
+ iip.max_ports = MAX_INPUT_PORTS * MAX_BITS_PER_PORT;
+ iip.current_port = 0;
+
+ /* allocate memory for the input ports */
+ if (memory == NULL)
+ iip.ports = (input_port_entry *)auto_malloc(iip.max_ports * sizeof(*iip.ports));
+ else
+ iip.ports = memory;
+ memset(iip.ports, 0, iip.max_ports * sizeof(*iip.ports));
+
+ /* construct the ports */
+ input_port_detokenize(&iip, ipt);
+
+ /* append final IPT_END */
+ input_port_initialize(&iip, IPT_END, NULL, 0, 0);
+
+#ifdef MESS
+ /* process MESS specific extensions to the port */
+ inputx_handle_mess_extensions(iip.ports);
+#endif
+
+ return iip.ports;
+}
+
+
+void input_port_parse_diplocation(input_port_entry *in, const char *location)
+{
+ char *curname = NULL, tempbuf[100];
+ const char *entry;
+ int index, val, bits;
+ UINT32 temp;
+
+ /* if nothing present, bail */
+ if (!location)
+ return;
+ memset(in->diploc, 0, sizeof(in->diploc));
+
+ /* parse the string */
+ for (index = 0, entry = location; *entry && index < ARRAY_LENGTH(in->diploc); index++)
+ {
+ const char *comma, *colon, *number;
+
+ /* find the end of this entry */
+ comma = strchr(entry, ',');
+ if (comma == NULL)
+ comma = entry + strlen(entry);
+
+ /* extract it to tempbuf */
+ strncpy(tempbuf, entry, comma - entry);
+ tempbuf[comma - entry] = 0;
+
+ /* first extract the switch name if present */
+ number = tempbuf;
+ colon = strchr(tempbuf, ':');
+ if (colon != NULL)
+ {
+ curname = auto_malloc(colon - tempbuf + 1);
+ strncpy(curname, tempbuf, colon - tempbuf);
+ curname[colon - tempbuf] = 0;
+ number = colon + 1;
+ }
+
+ /* if we don't have a name by now, we're screwed */
+ if (curname == NULL)
+ fatalerror("Switch location '%s' missing switch name!", location);
+
+ /* if the number is preceded by a '!' it's active high */
+ if (*number == '!')
+ {
+ in->diploc[index].invert = 1;
+ number++;
+ }
+ else
+ in->diploc[index].invert = 0;
+
+ /* now scan the switch number */
+ if (sscanf(number, "%d", &val) != 1)
+ fatalerror("Switch location '%s' has invalid format!", location);
+
+ /* fill the entry and bump the index */
+ in->diploc[index].swname = curname;
+ in->diploc[index].swnum = val;
+
+ /* advance to the next item */
+ entry = comma;
+ if (*entry)
+ entry++;
+ }
+
+ /* then verify the number of bits in the mask matches */
+ for (bits = 0, temp = in->mask; temp && bits < 32; bits++)
+ temp &= temp - 1;
+ if (bits != index)
+ fatalerror("Switch location '%s' does not describe enough bits for mask %X\n", location, in->mask);
+}
+
+
+
+/*************************************
+ *
+ * List access
+ *
+ *************************************/
+
+input_port_default_entry *get_input_port_list(void)
+{
+ return default_ports;
+}
+
+
+const input_port_default_entry *get_input_port_list_defaults(void)
+{
+ return default_ports_backup;
+}
+
+
+
+/*************************************
+ *
+ * Input port tokens
+ *
+ *************************************/
+
+const char *port_type_to_token(int type, int player)
+{
+ static char tempbuf[32];
+ int defindex;
+
+ /* look up the port and return the token */
+ defindex = default_ports_lookup[type][player];
+ if (defindex != -1)
+ return default_ports[defindex].token;
+
+ /* if that fails, carry on */
+ sprintf(tempbuf, "TYPE_OTHER(%d,%d)", type, player);
+ return tempbuf;
+}
+
+
+int token_to_port_type(const char *string, int *player)
+{
+ int ipnum;
+
+ /* check for our failsafe case first */
+ if (sscanf(string, "TYPE_OTHER(%d,%d)", &ipnum, player) == 2)
+ return ipnum;
+
+ /* find the token in the list */
+ for (ipnum = 0; ipnum < input_port_count; ipnum++)
+ if (default_ports[ipnum].token != NULL && !strcmp(default_ports[ipnum].token, string))
+ {
+ *player = default_ports[ipnum].player;
+ return default_ports[ipnum].type;
+ }
+
+ /* if we fail, return IPT_UNKNOWN */
+ *player = 0;
+ return IPT_UNKNOWN;
+}
+
+
+
+/*************************************
+ *
+ * Input port getters
+ *
+ *************************************/
+
+int input_port_active(const input_port_entry *port)
+{
+ return (input_port_name(port) != NULL && !port->unused);
+}
+
+
+int port_type_is_analog(int type)
+{
+ return (type >= __ipt_analog_start && type <= __ipt_analog_end);
+}
+
+
+int port_type_is_analog_absolute(int type)
+{
+ return (type >= __ipt_analog_absolute_start && type <= __ipt_analog_absolute_end);
+}
+
+
+int port_type_in_use(int type)
+{
+ input_port_entry *port;
+ for (port = Machine->input_ports; port->type != IPT_END; port++)
+ if (port->type == type)
+ return 1;
+ return 0;
+}
+
+
+int port_type_to_group(int type, int player)
+{
+ int defindex = default_ports_lookup[type][player];
+ if (defindex != -1)
+ return default_ports[defindex].group;
+ return IPG_INVALID;
+}
+
+
+int port_tag_to_index(const char *tag)
+{
+ int port;
+
+ /* find the matching tag */
+ for (port = 0; port < MAX_INPUT_PORTS; port++)
+ if (port_info[port].tag != NULL && !strcmp(port_info[port].tag, tag))
+ return port;
+ return -1;
+}
+
+
+read8_handler port_tag_to_handler8(const char *tag)
+{
+ int port = port_tag_to_index(tag);
+ return (port == -1) ? MRA8_NOP : port_handler8[port];
+}
+
+
+read16_handler port_tag_to_handler16(const char *tag)
+{
+ int port = port_tag_to_index(tag);
+ return (port == -1) ? MRA16_NOP : port_handler16[port];
+}
+
+
+read32_handler port_tag_to_handler32(const char *tag)
+{
+ int port = port_tag_to_index(tag);
+ return (port == -1) ? MRA32_NOP : port_handler32[port];
+}
+
+
+read64_handler port_tag_to_handler64(const char *tag)
+{
+ return MRA64_NOP;
+}
+
+
+const char *input_port_name(const input_port_entry *port)
+{
+ int defindex;
+
+ /* if we have a non-default name, use that */
+ if (port->name != IP_NAME_DEFAULT)
+ return port->name;
+
+ /* if the port exists, return the default name */
+ defindex = default_ports_lookup[port->type][port->player];
+ if (defindex != -1)
+ return default_ports[defindex].name;
+
+ /* should never get here */
+ return NULL;
+}
+
+
+input_seq *input_port_seq(input_port_entry *port, int seqtype)
+{
+ static input_seq ip_none = SEQ_DEF_0;
+ input_seq *portseq;
+
+ /* if port is disabled, return no key */
+ if (port->unused)
+ return &ip_none;
+
+ /* handle the various seq types */
+ switch (seqtype)
+ {
+ case SEQ_TYPE_STANDARD:
+ portseq = &port->seq;
+ break;
+
+ case SEQ_TYPE_INCREMENT:
+ if (!IS_ANALOG(port))
+ return &ip_none;
+ portseq = &port->analog.incseq;
+ break;
+
+ case SEQ_TYPE_DECREMENT:
+ if (!IS_ANALOG(port))
+ return &ip_none;
+ portseq = &port->analog.decseq;
+ break;
+
+ default:
+ return &ip_none;
+ }
+
+ /* does this override the default? if so, return it directly */
+ if (input_seq_get_1(portseq) != SEQCODE_DEFAULT)
+ return portseq;
+
+ /* otherwise find the default setting */
+ return input_port_default_seq(port->type, port->player, seqtype);
+}
+
+
+input_seq *input_port_default_seq(int type, int player, int seqtype)
+{
+ static input_seq ip_none = SEQ_DEF_0;
+
+ /* find the default setting */
+ int defindex = default_ports_lookup[type][player];
+ if (defindex != -1)
+ {
+ switch (seqtype)
+ {
+ case SEQ_TYPE_STANDARD:
+ return &default_ports[defindex].defaultseq;
+ case SEQ_TYPE_INCREMENT:
+ return &default_ports[defindex].defaultincseq;
+ case SEQ_TYPE_DECREMENT:
+ return &default_ports[defindex].defaultdecseq;
+ }
+ }
+ return &ip_none;
+}
+
+
+int input_port_condition(const input_port_entry *in)
+{
+ switch (in->condition.condition)
+ {
+ case PORTCOND_EQUALS:
+ return ((readinputport(in->condition.portnum) & in->condition.mask) == in->condition.value);
+ case PORTCOND_NOTEQUALS:
+ return ((readinputport(in->condition.portnum) & in->condition.mask) != in->condition.value);
+ }
+ return 1;
+}
+
+
+
+/*************************************
+ *
+ * Key sequence handlers
+ *
+ *************************************/
+
+int input_port_type_pressed(int type, int player)
+{
+ int defindex = default_ports_lookup[type][player];
+ if (defindex != -1)
+ return input_seq_pressed(&default_ports[defindex].defaultseq);
+
+ return 0;
+}
+
+
+int input_ui_pressed(int code)
+{
+ int pressed;
+
+profiler_mark(PROFILER_INPUT);
+
+ /* get the status of this key (assumed to be only in the defaults) */
+ pressed = input_seq_pressed(input_port_default_seq(code, 0, SEQ_TYPE_STANDARD));
+
+ /* if pressed, handle it specially */
+ if (pressed)
+ {
+ /* if this is the first press, leave pressed = 1 */
+ if (ui_memory[code] == 0)
+ ui_memory[code] = 1;
+
+ /* otherwise, reset pressed = 0 */
+ else
+ pressed = 0;
+ }
+
+ /* if we're not pressed, reset the memory field */
+ else
+ ui_memory[code] = 0;
+
+profiler_mark(PROFILER_END);
+
+ return pressed;
+}
+
+
+int input_ui_pressed_repeat(int code, int speed)
+{
+ static osd_ticks_t lastdown;
+ static osd_ticks_t keydelay;
+ int pressed;
+
+profiler_mark(PROFILER_INPUT);
+
+ /* get the status of this key (assumed to be only in the defaults) */
+ pressed = input_seq_pressed(input_port_default_seq(code, 0, SEQ_TYPE_STANDARD));
+
+ /* if so, handle it specially */
+ if (pressed)
+ {
+ /* if this is the first press, set a 3x delay and leave pressed = 1 */
+ if (ui_memory[code] == 0)
+ {
+ ui_memory[code] = 1;
+ lastdown = osd_ticks();
+ keydelay = 3 * speed * osd_ticks_per_second() / 60;
+ }
+
+ /* if this is an autorepeat case, set a 1x delay and leave pressed = 1 */
+ else if (osd_ticks() - lastdown >= keydelay)
+ {
+ lastdown += keydelay;
+ keydelay = 1 * speed * osd_ticks_per_second() / 60;
+ }
+
+ /* otherwise, reset pressed = 0 */
+ else
+ pressed = 0;
+ }
+
+ /* if we're not pressed, reset the memory field */
+ else
+ ui_memory[code] = 0;
+
+profiler_mark(PROFILER_END);
+
+ return pressed;
+}
+
+
+
+/*************************************
+ *
+ * Playback/record helper
+ *
+ *************************************/
+
+static void update_playback_record(int portnum, UINT32 portvalue)
+{
+ /* handle playback */
+ if (Machine->playback_file != NULL)
+ {
+ UINT32 result;
+
+ /* a successful read goes into the playback field which overrides everything else */
+ if (mame_fread(Machine->playback_file, &result, sizeof(result)) == sizeof(result))
+ portvalue = port_info[portnum].playback = BIG_ENDIANIZE_INT32(result);
+
+ /* a failure causes us to close the playback file and stop playback */
+ else
+ {
+ mame_fclose(Machine->playback_file);
+ Machine->playback_file = NULL;
+ if(no_extended_inp)
+ popmessage("End of playback");
+ else
+ {
+ popmessage("End of playback - %i frames - Average speed %f%%",framecount,(double)totalspeed/framecount);
+ printf("End of playback - %i frames - Average speed %f%%\n",framecount,(double)totalspeed/framecount);
+ }
+ }
+ }
+
+ /* handle recording */
+ if (Machine->record_file != NULL)
+ {
+ UINT32 result = BIG_ENDIANIZE_INT32(portvalue);
+
+ /* a successful write just works */
+ if (mame_fwrite(Machine->record_file, &result, sizeof(result)) == sizeof(result))
+ ;
+
+ /* a failure causes us to close the record file and stop recording */
+ else
+ {
+ mame_fclose(Machine->record_file);
+ Machine->record_file = NULL;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Update default ports
+ *
+ *************************************/
+
+void input_port_update_defaults(void)
+{
+ int loopnum, portnum;
+
+ /* two passes to catch conditionals properly */
+ for (loopnum = 0; loopnum < 2; loopnum++)
+
+ /* loop over all input ports */
+ for (portnum = 0; portnum < MAX_INPUT_PORTS; portnum++)
+ {
+ input_port_info *portinfo = &port_info[portnum];
+ input_bit_info *info;
+ int bitnum;
+
+ /* only clear on the first pass */
+ if (loopnum == 0)
+ portinfo->defvalue = 0;
+
+ /* first compute the default value for the entire port */
+ for (bitnum = 0, info = &portinfo->bit[0]; bitnum < MAX_BITS_PER_PORT && info->port; bitnum++, info++)
+ if (input_port_condition(info->port))
+ portinfo->defvalue = (portinfo->defvalue & ~info->port->mask) | (info->port->default_value & info->port->mask);
+ }
+}
+
+
+
+/*************************************
+ *
+ * VBLANK start routine
+ *
+ *************************************/
+
+void input_port_vblank_start(void)
+{
+ int ui_visible = ui_is_menu_active() || ui_is_slider_active();
+ int portnum, bitnum;
+
+profiler_mark(PROFILER_INPUT);
+
+ /* update the digital joysticks first */
+ update_digital_joysticks();
+
+ /* compute default values for all the ports */
+ input_port_update_defaults();
+
+ /* loop over all input ports */
+ for (portnum = 0; portnum < MAX_INPUT_PORTS; portnum++)
+ {
+ input_port_info *portinfo = &port_info[portnum];
+ input_bit_info *info;
+
+ /* compute the VBLANK mask */
+ portinfo->vblank = 0;
+ for (bitnum = 0, info = &portinfo->bit[0]; bitnum < MAX_BITS_PER_PORT && info->port; bitnum++, info++)
+ if (info->port->type == IPT_VBLANK)
+ {
+ portinfo->vblank ^= info->port->mask;
+ if (Machine->screen[0].vblank == 0)
+ logerror("Warning: you are using IPT_VBLANK with vblank_time = 0. You need to increase vblank_time for IPT_VBLANK to work.\n");
+ }
+
+ /* now loop back and modify based on the inputs */
+ portinfo->digital = 0;
+ for (bitnum = 0, info = &portinfo->bit[0]; bitnum < MAX_BITS_PER_PORT && info->port; bitnum++, info++)
+ if (input_port_condition(info->port))
+ {
+ input_port_entry *port = info->port;
+
+ /* handle non-analog types, but only when the UI isn't visible */
+ if (port->type != IPT_VBLANK && !IS_ANALOG(port) && !ui_visible)
+ {
+ /* if the sequence for this port is currently pressed.... */
+ if (input_seq_pressed(input_port_seq(port, SEQ_TYPE_STANDARD)))
+ {
+#ifdef MESS
+ /* (MESS-specific) check for disabled keyboard */
+ if (port->type == IPT_KEYBOARD && osd_keyboard_disabled())
+ continue;
+#endif
+ /* skip locked-out coin inputs */
+ if (port->type >= IPT_COIN1 && port->type <= IPT_COIN8 && coinlockedout[port->type - IPT_COIN1])
+ continue;
+ if (port->type >= IPT_SERVICE1 && port->type <= IPT_SERVICE4 && servicecoinlockedout[port->type - IPT_SERVICE1])
+ continue;
+
+ /* if this is a downward press and we're an impulse control, reset the count */
+ if (port->impulse)
+ {
+ if (info->last == 0)
+ info->impulse = port->impulse;
+ }
+
+ /* if this is a downward press and we're a toggle control, toggle the value */
+ else if (port->toggle)
+ {
+ if (info->last == 0)
+ {
+ port->default_value ^= port->mask;
+ portinfo->digital ^= port->mask;
+ }
+ }
+
+ /* if this is a digital joystick type, apply either standard or 4-way rules */
+ else if (IS_DIGITAL_JOYSTICK(port))
+ {
+ digital_joystick_info *joyinfo = JOYSTICK_INFO_FOR_PORT(port);
+ UINT8 mask;
+ switch( port->way )
+ {
+ case 4:
+ mask = joyinfo->current4way;
+ break;
+ case 16:
+ mask = 0xff;
+ break;
+ default:
+ mask = joyinfo->current;
+ break;
+ }
+ if ((mask >> JOYSTICK_DIR_FOR_PORT(port)) & 1)
+ portinfo->digital ^= port->mask;
+ }
+
+ /* otherwise, just set it raw */
+ else
+ portinfo->digital ^= port->mask;
+
+ /* track the last value */
+ info->last = 1;
+ }
+ else
+ info->last = 0;
+
+ /* handle the impulse countdown */
+ if (port->impulse && info->impulse > 0)
+ {
+ info->impulse--;
+ info->last = 1;
+ portinfo->digital ^= port->mask;
+ }
+ }
+
+ /* note that analog ports are handled instantaneously at port read time */
+ }
+ }
+
+#ifdef MESS
+ /* less MESS to MESSy things */
+ inputx_update();
+#endif
+
+ /* call changed handlers */
+ for (portnum = 0; portnum < MAX_INPUT_PORTS; portnum++)
+ if (port_info[portnum].change_notify != NULL)
+ {
+ changed_callback_info *cbinfo;
+ UINT32 newvalue = readinputport(portnum);
+ UINT32 oldvalue = port_info[portnum].changed_last_value;
+ UINT32 delta = newvalue ^ oldvalue;
+
+ /* call all the callbacks whose mask matches the requested mask */
+ for (cbinfo = port_info[portnum].change_notify; cbinfo; cbinfo = cbinfo->next)
+ if (delta & cbinfo->mask)
+ (*cbinfo->callback)(cbinfo->param, oldvalue & cbinfo->mask, newvalue & cbinfo->mask);
+
+ port_info[portnum].changed_last_value = newvalue;
+ }
+
+ /* handle playback/record */
+ for (portnum = 0; portnum < MAX_INPUT_PORTS; portnum++)
+ {
+ /* analog ports automatically update on every read */
+ if (port_info[portnum].analoginfo)
+ readinputport(portnum);
+
+ /* non-analog ports must be manually updated */
+ else
+ update_playback_record(portnum, readinputport(portnum));
+ }
+
+ /* store speed read from INP file, if extended INP */
+ if (Machine->playback_file != NULL && !no_extended_inp)
+ {
+ long dummy;
+ mame_fread(Machine->playback_file,&rec_speed,sizeof(double));
+ mame_fread(Machine->playback_file,&dummy,sizeof(long));
+ framecount++;
+ rec_speed *= 100;
+ totalspeed += rec_speed;
+ }
+
+profiler_mark(PROFILER_END);
+}
+
+
+
+/*************************************
+ *
+ * VBLANK end routine
+ *
+ *************************************/
+
+void input_port_vblank_end(void)
+{
+ int ui_visible = ui_is_menu_active() || ui_is_slider_active();
+ int port;
+
+profiler_mark(PROFILER_INPUT);
+
+ /* update all analog ports if the UI isn't visible */
+ if (!ui_visible)
+ for (port = 0; port < MAX_INPUT_PORTS; port++)
+ update_analog_port(port);
+
+profiler_mark(PROFILER_END);
+}
+
+
+
+/*************************************
+ *
+ * Digital joystick updating
+ *
+ *************************************/
+
+static void update_digital_joysticks(void)
+{
+ int player, joyindex;
+
+ /* loop over all the joysticks */
+ for (player = 0; player < MAX_PLAYERS; player++)
+ for (joyindex = 0; joyindex < DIGITAL_JOYSTICKS_PER_PLAYER; joyindex++)
+ {
+ digital_joystick_info *info = &joystick_info[player][joyindex];
+ if (info->inuse)
+ {
+ info->previous = info->current;
+ info->current = 0;
+
+ /* read all the associated ports */
+ if (info->port[JOYDIR_UP] != NULL && input_seq_pressed(input_port_seq(info->port[JOYDIR_UP], SEQ_TYPE_STANDARD)))
+ info->current |= JOYDIR_UP_BIT;
+ if (info->port[JOYDIR_DOWN] != NULL && input_seq_pressed(input_port_seq(info->port[JOYDIR_DOWN], SEQ_TYPE_STANDARD)))
+ info->current |= JOYDIR_DOWN_BIT;
+ if (info->port[JOYDIR_LEFT] != NULL && input_seq_pressed(input_port_seq(info->port[JOYDIR_LEFT], SEQ_TYPE_STANDARD)))
+ info->current |= JOYDIR_LEFT_BIT;
+ if (info->port[JOYDIR_RIGHT] != NULL && input_seq_pressed(input_port_seq(info->port[JOYDIR_RIGHT], SEQ_TYPE_STANDARD)))
+ info->current |= JOYDIR_RIGHT_BIT;
+
+ /* lock out opposing directions (left + right or up + down) */
+ if ((info->current & (JOYDIR_UP_BIT | JOYDIR_DOWN_BIT)) == (JOYDIR_UP_BIT | JOYDIR_DOWN_BIT))
+ info->current &= ~(JOYDIR_UP_BIT | JOYDIR_DOWN_BIT);
+ if ((info->current & (JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT)) == (JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT))
+ info->current &= ~(JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT);
+
+ /* only update 4-way case if joystick has moved */
+ if (info->current != info->previous)
+ {
+ info->current4way = info->current;
+
+ /*
+ If joystick is pointing at a diagonal, acknowledge that the player moved
+ the joystick by favoring a direction change. This minimizes frustration
+ when using a keyboard for input, and maximizes responsiveness.
+
+ For example, if you are holding "left" then switch to "up" (where both left
+ and up are briefly pressed at the same time), we'll transition immediately
+ to "up."
+
+ Zero any switches that didn't change from the previous to current state.
+ */
+ if ((info->current4way & (JOYDIR_UP_BIT | JOYDIR_DOWN_BIT)) &&
+ (info->current4way & (JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT)))
+ {
+ info->current4way ^= info->current4way & info->previous;
+ }
+
+ /*
+ If we are still pointing at a diagonal, we are in an indeterminant state.
+
+ This could happen if the player moved the joystick from the idle position directly
+ to a diagonal, or from one diagonal directly to an extreme diagonal.
+
+ The chances of this happening with a keyboard are slim, but we still need to
+ constrain this case.
+
+ For now, just resolve randomly.
+ */
+ if ((info->current4way & (JOYDIR_UP_BIT | JOYDIR_DOWN_BIT)) &&
+ (info->current4way & (JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT)))
+ {
+ if (mame_rand(Machine) & 1)
+ info->current4way &= ~(JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT);
+ else
+ info->current4way &= ~(JOYDIR_UP_BIT | JOYDIR_DOWN_BIT);
+ }
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Analog minimum/maximum clamping
+ *
+ *************************************/
+
+INLINE INT32 apply_analog_min_max(const analog_port_info *info, double value)
+{
+ const input_port_entry *port = info->port;
+ double adjmax, adjmin, adj1, adjdif;
+
+ /* take the analog minimum and maximum values and apply the inverse of the */
+ /* sensitivity so that we can clamp against them before applying sensitivity */
+ adjmin = APPLY_INVERSE_SENSITIVITY(info->minimum, port->analog.sensitivity);
+ adjmax = APPLY_INVERSE_SENSITIVITY(info->maximum, port->analog.sensitivity);
+ adj1 = APPLY_INVERSE_SENSITIVITY(512, port->analog.sensitivity);
+
+ /* for absolute devices, clamp to the bounds absolutely */
+ if (!info->wraps)
+ {
+ if (value > adjmax)
+ value = adjmax;
+ else if (value < adjmin)
+ value = adjmin;
+ }
+
+ /* for relative devices, wrap around when we go past the edge */
+ else
+ {
+ adjdif = adjmax - adjmin + adj1;
+ if (port->analog.reverse)
+ {
+ while (value <= adjmin - adj1)
+ value += adjdif;
+ while (value > adjmax)
+ value -= adjdif;
+ }
+ else
+ {
+ while (value >= adjmax + adj1)
+ value -= adjdif;
+ while (value < adjmin)
+ value += adjdif;
+ }
+ }
+
+ return value;
+}
+
+
+
+/*************************************
+ *
+ * Analog port updating
+ *
+ *************************************/
+
+static void update_analog_port(int portnum)
+{
+ analog_port_info *info;
+
+ /* loop over all analog ports in this port number */
+ for (info = port_info[portnum].analoginfo; info != NULL; info = info->next)
+ {
+ input_port_entry *port = info->port;
+ INT32 rawvalue;
+ double delta = 0, keyscale;
+ int keypressed = 0;
+ input_item_class itemclass;
+
+ /* clamp the previous value to the min/max range and remember it */
+ info->previous = info->accum = apply_analog_min_max(info, info->accum);
+
+ /* get the new raw analog value and its type */
+ rawvalue = input_seq_axis_value(input_port_seq(port, SEQ_TYPE_STANDARD), &itemclass);
+
+ /* if we got an absolute input, it overrides everything else */
+ if (itemclass == ITEM_CLASS_ABSOLUTE)
+ {
+ if (info->previousanalog != rawvalue)
+ {
+ /* only update if analog value changed */
+ info->previousanalog = rawvalue;
+
+ /* apply the inverse of the sensitivity to the raw value so that */
+ /* it will still cover the full min->max range requested after */
+ /* we apply the sensitivity adjustment */
+ if (info->absolute || port->analog.reset)
+ {
+ /* if port is absolute, then just return the absolute data supplied */
+ info->accum = APPLY_INVERSE_SENSITIVITY(rawvalue, port->analog.sensitivity);
+ }
+ else if (info->positionalscale != 0)
+ {
+ /* if port is positional, we will take the full analog control and divide it */
+ /* into positions, that way as the control is moved full scale, */
+ /* it moves through all the positions */
+ rawvalue = info->positionalscale * (rawvalue - INPUT_ABSOLUTE_MIN) * 512 + info->minimum;
+
+ /* clamp the high value so it does not roll over */
+ if (rawvalue > info->maximum) rawvalue = info->maximum;
+ info->accum = APPLY_INVERSE_SENSITIVITY(rawvalue, port->analog.sensitivity);
+ }
+ else
+ /* if port is relative, we use the value to simulate the speed of relative movement */
+ /* sensitivity adjustment is allowed for this mode */
+ info->accum += rawvalue;
+
+ info->lastdigital = 0;
+ /* do not bother with other control types if the analog data is changing */
+ return;
+ }
+ else
+ {
+ /* we still have to update fake relative from joystick control */
+ if (!info->absolute && info->positionalscale == 0) info->accum += rawvalue;
+ }
+ }
+
+ /* if we got it from a relative device, use that as the starting delta */
+ /* also note that the last input was not a digital one */
+ if (itemclass == ITEM_CLASS_RELATIVE && rawvalue != 0)
+ {
+ delta = rawvalue;
+ info->lastdigital = 0;
+ }
+
+ keyscale = (info->accum >= 0) ? info->keyscalepos : info->keyscaleneg;
+
+ /* if the decrement code sequence is pressed, add the key delta to */
+ /* the accumulated delta; also note that the last input was a digital one */
+ if (input_seq_pressed(input_port_seq(info->port, SEQ_TYPE_DECREMENT)))
+ {
+ keypressed = 1;
+ if (port->analog.delta)
+ delta -= (double)(port->analog.delta) * keyscale;
+ else if (info->lastdigital != 1)
+ /* decrement only once when first pressed */
+ delta -= keyscale;
+ info->lastdigital = 1;
+ }
+
+ /* same for the increment code sequence */
+ if (input_seq_pressed(input_port_seq(info->port, SEQ_TYPE_INCREMENT)))
+ {
+ keypressed = 1;
+ if (port->analog.delta)
+ delta += (double)(port->analog.delta) * keyscale;
+ else if (info->lastdigital != 2)
+ /* increment only once when first pressed */
+ delta += keyscale;
+ info->lastdigital = 2;
+ }
+
+ /* if resetting is requested, clear the accumulated position to 0 before */
+ /* applying the deltas so that we only return this frame's delta */
+ /* note that centering only works for relative controls */
+ /* no need to check if absolute here because it is checked by the validity tests */
+ if (port->analog.reset)
+ info->accum = 0;
+
+ /* apply the delta to the accumulated value */
+ info->accum += delta;
+
+ /* if our last movement was due to a digital input, and if this control */
+ /* type autocenters, and if neither the increment nor the decrement seq */
+ /* was pressed, apply autocentering */
+ if (info->autocenter)
+ {
+ double center = APPLY_INVERSE_SENSITIVITY(info->center, port->analog.sensitivity);
+ if (info->lastdigital && !keypressed)
+ {
+ /* autocenter from positive values */
+ if (info->accum >= center)
+ {
+ info->accum -= (double)(port->analog.centerdelta) * info->keyscalepos;
+ if (info->accum < center)
+ {
+ info->accum = center;
+ info->lastdigital = 0;
+ }
+ }
+
+ /* autocenter from negative values */
+ else
+ {
+ info->accum += (double)(port->analog.centerdelta) * info->keyscaleneg;
+ if (info->accum > center)
+ {
+ info->accum = center;
+ info->lastdigital = 0;
+ }
+ }
+ }
+ }
+ else if (!keypressed)
+ info->lastdigital = 0;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Analog port interpolation
+ *
+ *************************************/
+
+static void interpolate_analog_port(int portnum)
+{
+ analog_port_info *info;
+
+profiler_mark(PROFILER_INPUT);
+
+ /* set the default mask and value */
+ port_info[portnum].analogmask = 0;
+ port_info[portnum].analog = 0;
+
+ /* loop over all analog ports in this port number */
+ for (info = port_info[portnum].analoginfo; info != NULL; info = info->next)
+ {
+ input_port_entry *port = info->port;
+
+ if (input_port_condition(info->port))
+ {
+ double current;
+ INT32 value;
+
+ /* interpolate or not */
+ if (info->interpolate && !port->analog.reset)
+ current = info->previous + cpu_scalebyfcount(info->accum - info->previous);
+ else
+ current = info->accum;
+
+ /* apply the min/max and then the sensitivity */
+ current = apply_analog_min_max(info, current);
+ current = APPLY_SENSITIVITY(current, port->analog.sensitivity);
+
+ /* apply reversal if needed */
+ if (port->analog.reverse)
+ current = info->reverse_val - current;
+ else
+ if (info->single_scale)
+ /* it's a pedal or the default value is equal to min/max */
+ /* so we need to adjust the center to the minimum */
+ current -= INPUT_ABSOLUTE_MIN;
+
+ /* map differently for positive and negative values */
+ if (current >= 0 )
+ value = (INT32)(current * info->scalepos);
+ else
+ value = (INT32)(current * info->scaleneg);
+ value += port->default_value;
+
+ /* store croshair position before any remapping */
+ info->crosshair_pos = (INT32)value & (port->mask >> info->shift);
+
+ /* remap the value if needed */
+ if (port->analog.remap_table)
+ value = info->port->analog.remap_table[value];
+
+ /* invert bits if needed */
+ if (port->analog.invert)
+ value = ~value;
+
+ /* insert into the port */
+ port_info[portnum].analogmask |= info->port->mask;
+ port_info[portnum].analog = (port_info[portnum].analog & ~port->mask) | ((value << info->shift) & port->mask);
+ }
+ }
+
+profiler_mark(PROFILER_END);
+}
+
+
+
+/*************************************
+ *
+ * Input port reading
+ *
+ *************************************/
+
+UINT32 readinputport(int port)
+{
+ input_port_info *portinfo = &port_info[port];
+ custom_port_info *custom;
+ UINT32 result;
+
+ /* interpolate analog values */
+ interpolate_analog_port(port);
+
+ /* update custom values */
+ for (custom = portinfo->custominfo; custom; custom = custom->next)
+ if (input_port_condition(custom->port))
+ {
+ /* replace the bits with bits from the custom routine */
+ input_port_entry *port = custom->port;
+ portinfo->digital &= ~port->mask;
+ portinfo->digital |= ((*port->custom)(port->custom_param) << custom->shift) & port->mask;
+ }
+
+ /* compute the current result: default value XOR the digital, merged with the analog */
+ result = ((portinfo->defvalue ^ portinfo->digital) & ~portinfo->analogmask) | portinfo->analog;
+
+ /* if we have analog data, update the recording state */
+ if (port_info[port].analoginfo)
+ update_playback_record(port, result);
+
+ /* if we're playing back, use the recorded value for inputs instead */
+ if (Machine->playback_file != NULL)
+ result = portinfo->playback;
+
+ /* handle VBLANK bits after inputs */
+ if (portinfo->vblank)
+ {
+ /* reset the VBLANK bits to their default value, regardless of inputs */
+ result = (result & ~portinfo->vblank) | (portinfo->defvalue & portinfo->vblank);
+
+ /* toggle VBLANK if we're in a VBLANK state */
+ if (Machine->screen[0].oldstyle_vblank_supplied)
+ {
+ int cpu_getvblank(void);
+
+ if (cpu_getvblank())
+ result ^= portinfo->vblank;
+ }
+ else
+ {
+ if (video_screen_get_vblank(0))
+ result ^= portinfo->vblank;
+ }
+ }
+ return result;
+}
+
+
+UINT32 readinputportbytag(const char *tag)
+{
+ int port = port_tag_to_index(tag);
+ if (port != -1)
+ return readinputport(port);
+
+ /* otherwise fail horribly */
+ fatalerror("Unable to locate input port '%s'", tag);
+ return -1;
+}
+
+
+UINT32 readinputportbytag_safe(const char *tag, UINT32 defvalue)
+{
+ int port = port_tag_to_index(tag);
+ if (port != -1)
+ return readinputport(port);
+ return defvalue;
+}
+
+
+
+/*************************************
+ *
+ * Input port writing
+ *
+ *************************************/
+
+void input_port_set_digital_value(int portnum, UINT32 value, UINT32 mask)
+{
+ input_port_info *portinfo = &port_info[portnum];
+ portinfo->digital &= ~mask;
+ portinfo->digital |= value;
+}
+
+
+
+/*************************************
+ *
+ * Input port callbacks
+ *
+ *************************************/
+
+void input_port_set_changed_callback(int port, UINT32 mask, void (*callback)(void *, UINT32, UINT32), void *param)
+{
+ input_port_info *portinfo = &port_info[port];
+ changed_callback_info *cbinfo;
+
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call input_port_set_changed_callback() at init time!");
+ assert_always((port >= 0) && (port < MAX_INPUT_PORTS), "Invalid port number passed to input_port_set_changed_callback()!");
+
+ cbinfo = auto_malloc(sizeof(*cbinfo));
+ cbinfo->next = portinfo->change_notify;
+ cbinfo->mask = mask;
+ cbinfo->callback = callback;
+ cbinfo->param = param;
+
+ portinfo->change_notify = cbinfo;
+}
+
+
+
+/*************************************
+ *
+ * Return position of crosshair axis
+ *
+ *************************************/
+
+UINT32 get_crosshair_pos(int port_num, UINT8 player, UINT8 axis)
+{
+ input_port_info *portinfo = &port_info[port_num];
+ analog_port_info *info;
+ input_port_entry *port;
+ UINT32 result = 0;
+
+ for (info = portinfo->analoginfo; info; info = info->next)
+ {
+ port = info->port;
+ if (port->player == player && port->analog.crossaxis == axis)
+ {
+ result = info->crosshair_pos;
+ break;
+ }
+ }
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ autoselect_device - autoselect a single
+ device based on the input port list passed
+ in and the corresponding option
+-------------------------------------------------*/
+
+static void autoselect_device(const input_port_entry *ipt, int type1, int type2, int type3, const char *option, const char *ananame)
+{
+ const char *stemp = options_get_string(mame_options(), option);
+ input_device_class autoenable = DEVICE_CLASS_KEYBOARD;
+ const char *autostring = "keyboard";
+
+ /* if nothing specified, ignore the option */
+ if (stemp[0] == 0)
+ return;
+
+ /* extract valid strings */
+ if (strcmp(stemp, "mouse") == 0)
+ {
+ autoenable = DEVICE_CLASS_MOUSE;
+ autostring = "mouse";
+ }
+ else if (strcmp(stemp, "joystick") == 0)
+ {
+ autoenable = DEVICE_CLASS_JOYSTICK;
+ autostring = "joystick";
+ }
+ else if (strcmp(stemp, "lightgun") == 0)
+ {
+ autoenable = DEVICE_CLASS_LIGHTGUN;
+ autostring = "lightgun";
+ }
+ else if (strcmp(stemp, "none") == 0)
+ {
+ /* nothing specified */
+ return;
+ }
+ else if (strcmp(stemp, "keyboard") != 0)
+ mame_printf_error("Invalid %s value %s; reverting to keyboard\n", option, stemp);
+
+ /* only scan the list if we haven't already enabled this class of control */
+ if (!input_device_class_enabled(autoenable))
+ for ( ; ipt->type != IPT_END; ipt++)
+
+ /* if this port type is in use, apply the autoselect criteria */
+ if ((type1 != 0 && ipt->type == type1) ||
+ (type2 != 0 && ipt->type == type2) ||
+ (type3 != 0 && ipt->type == type3))
+ {
+ mame_printf_verbose("Input: Autoenabling %s due to presence of a %s\n", autostring, ananame);
+ input_device_class_enable(autoenable, TRUE);
+ break;
+ }
+}
diff --git a/src/emu/inptport.h b/src/emu/inptport.h
new file mode 100644
index 00000000000..527bcf453eb
--- /dev/null
+++ b/src/emu/inptport.h
@@ -0,0 +1,903 @@
+/***************************************************************************
+
+ inptport.h
+
+ Handle input ports and mappings.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __INPTPORT_H__
+#define __INPTPORT_H__
+
+#include "memory.h"
+#include "inputseq.h"
+
+#ifdef MESS
+#include "unicode.h"
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_INPUT_PORTS 32
+#define MAX_PLAYERS 8
+#define MAX_BITS_PER_PORT 32
+
+#define IP_ACTIVE_HIGH 0x00000000
+#define IP_ACTIVE_LOW 0xffffffff
+
+
+/* sequence types for input_port_seq() call */
+enum
+{
+ SEQ_TYPE_STANDARD = 0,
+ SEQ_TYPE_INCREMENT = 1,
+ SEQ_TYPE_DECREMENT = 2
+};
+
+
+/* conditions for DIP switches */
+enum
+{
+ PORTCOND_ALWAYS = 0,
+ PORTCOND_EQUALS,
+ PORTCOND_NOTEQUALS
+};
+
+
+/* crosshair types */
+enum
+{
+ CROSSHAIR_AXIS_NONE = 0,
+ CROSSHAIR_AXIS_X,
+ CROSSHAIR_AXIS_Y
+};
+
+
+/* groups for input ports */
+enum
+{
+ IPG_UI = 0,
+ IPG_PLAYER1,
+ IPG_PLAYER2,
+ IPG_PLAYER3,
+ IPG_PLAYER4,
+ IPG_PLAYER5,
+ IPG_PLAYER6,
+ IPG_PLAYER7,
+ IPG_PLAYER8,
+ IPG_OTHER,
+ IPG_TOTAL_GROUPS,
+ IPG_INVALID
+};
+
+
+/* various input port types */
+enum
+{
+ /* pseudo-port types */
+ IPT_INVALID = 0,
+ IPT_UNUSED,
+ IPT_END,
+ IPT_UNKNOWN,
+ IPT_PORT,
+ IPT_DIPSWITCH_NAME,
+ IPT_DIPSWITCH_SETTING,
+ IPT_VBLANK,
+ IPT_CONFIG_NAME, /* MESS only */
+ IPT_CONFIG_SETTING, /* MESS only */
+ IPT_CATEGORY_NAME, /* MESS only */
+ IPT_CATEGORY_SETTING, /* MESS only */
+
+ /* start buttons */
+ IPT_START1,
+ IPT_START2,
+ IPT_START3,
+ IPT_START4,
+ IPT_START5,
+ IPT_START6,
+ IPT_START7,
+ IPT_START8,
+
+ /* coin slots */
+ IPT_COIN1,
+ IPT_COIN2,
+ IPT_COIN3,
+ IPT_COIN4,
+ IPT_COIN5,
+ IPT_COIN6,
+ IPT_COIN7,
+ IPT_COIN8,
+ IPT_BILL1,
+
+ /* service coin */
+ IPT_SERVICE1,
+ IPT_SERVICE2,
+ IPT_SERVICE3,
+ IPT_SERVICE4,
+
+ /* misc other digital inputs */
+ IPT_SERVICE,
+ IPT_TILT,
+ IPT_INTERLOCK,
+ IPT_VOLUME_UP,
+ IPT_VOLUME_DOWN,
+ IPT_START, /* MESS only */
+ IPT_SELECT, /* MESS only */
+ IPT_KEYBOARD, /* MESS only */
+
+#define __ipt_digital_joystick_start IPT_JOYSTICK_UP
+ /* use IPT_JOYSTICK for panels where the player has one single joystick */
+ IPT_JOYSTICK_UP,
+ IPT_JOYSTICK_DOWN,
+ IPT_JOYSTICK_LEFT,
+ IPT_JOYSTICK_RIGHT,
+
+ /* use IPT_JOYSTICKLEFT and IPT_JOYSTICKRIGHT for dual joystick panels */
+ IPT_JOYSTICKRIGHT_UP,
+ IPT_JOYSTICKRIGHT_DOWN,
+ IPT_JOYSTICKRIGHT_LEFT,
+ IPT_JOYSTICKRIGHT_RIGHT,
+ IPT_JOYSTICKLEFT_UP,
+ IPT_JOYSTICKLEFT_DOWN,
+ IPT_JOYSTICKLEFT_LEFT,
+ IPT_JOYSTICKLEFT_RIGHT,
+#define __ipt_digital_joystick_end IPT_JOYSTICKLEFT_RIGHT
+
+ /* action buttons */
+ IPT_BUTTON1,
+ IPT_BUTTON2,
+ IPT_BUTTON3,
+ IPT_BUTTON4,
+ IPT_BUTTON5,
+ IPT_BUTTON6,
+ IPT_BUTTON7,
+ IPT_BUTTON8,
+ IPT_BUTTON9,
+ IPT_BUTTON10,
+ IPT_BUTTON11,
+ IPT_BUTTON12,
+ IPT_BUTTON13,
+ IPT_BUTTON14,
+ IPT_BUTTON15,
+ IPT_BUTTON16,
+
+ /* mahjong inputs */
+ IPT_MAHJONG_A,
+ IPT_MAHJONG_B,
+ IPT_MAHJONG_C,
+ IPT_MAHJONG_D,
+ IPT_MAHJONG_E,
+ IPT_MAHJONG_F,
+ IPT_MAHJONG_G,
+ IPT_MAHJONG_H,
+ IPT_MAHJONG_I,
+ IPT_MAHJONG_J,
+ IPT_MAHJONG_K,
+ IPT_MAHJONG_L,
+ IPT_MAHJONG_M,
+ IPT_MAHJONG_N,
+ IPT_MAHJONG_O,
+ IPT_MAHJONG_P,
+ IPT_MAHJONG_Q,
+ IPT_MAHJONG_KAN,
+ IPT_MAHJONG_PON,
+ IPT_MAHJONG_CHI,
+ IPT_MAHJONG_REACH,
+ IPT_MAHJONG_RON,
+ IPT_MAHJONG_BET,
+ IPT_MAHJONG_LAST_CHANCE,
+ IPT_MAHJONG_SCORE,
+ IPT_MAHJONG_DOUBLE_UP,
+ IPT_MAHJONG_FLIP_FLOP,
+ IPT_MAHJONG_BIG,
+ IPT_MAHJONG_SMALL,
+
+ /* analog inputs */
+#define __ipt_analog_start IPT_PADDLE
+#define __ipt_analog_absolute_start IPT_PADDLE
+ IPT_PADDLE, /* absolute */
+ IPT_PADDLE_V, /* absolute */
+ IPT_AD_STICK_X, /* absolute */
+ IPT_AD_STICK_Y, /* absolute */
+ IPT_AD_STICK_Z, /* absolute */
+ IPT_LIGHTGUN_X, /* absolute */
+ IPT_LIGHTGUN_Y, /* absolute */
+ IPT_PEDAL, /* absolute */
+ IPT_PEDAL2, /* absolute */
+ IPT_PEDAL3, /* absolute */
+ IPT_POSITIONAL, /* absolute */
+ IPT_POSITIONAL_V, /* absolute */
+#define __ipt_analog_absolute_end IPT_POSITIONAL_V
+
+ IPT_DIAL, /* relative */
+ IPT_DIAL_V, /* relative */
+ IPT_TRACKBALL_X, /* relative */
+ IPT_TRACKBALL_Y, /* relative */
+ IPT_MOUSE_X, /* relative */
+ IPT_MOUSE_Y, /* relative */
+#define __ipt_analog_end IPT_MOUSE_Y
+
+ /* analog adjuster support */
+ IPT_ADJUSTER,
+
+ /* the following are special codes for user interface handling - not to be used by drivers! */
+ IPT_UI_CONFIGURE,
+ IPT_UI_ON_SCREEN_DISPLAY,
+ IPT_UI_DEBUG_BREAK,
+ IPT_UI_PAUSE,
+ IPT_UI_RESET_MACHINE,
+ IPT_UI_SOFT_RESET,
+ IPT_UI_SHOW_GFX,
+ IPT_UI_FRAMESKIP_DEC,
+ IPT_UI_FRAMESKIP_INC,
+ IPT_UI_THROTTLE,
+ IPT_UI_FAST_FORWARD,
+ IPT_UI_SHOW_FPS,
+ IPT_UI_SNAPSHOT,
+ IPT_UI_RECORD_MOVIE,
+ IPT_UI_TOGGLE_CHEAT,
+ IPT_UI_UP,
+ IPT_UI_DOWN,
+ IPT_UI_LEFT,
+ IPT_UI_RIGHT,
+ IPT_UI_HOME,
+ IPT_UI_END,
+ IPT_UI_PAGE_UP,
+ IPT_UI_PAGE_DOWN,
+ IPT_UI_SELECT,
+ IPT_UI_CANCEL,
+ IPT_UI_CLEAR,
+ IPT_UI_ZOOM_IN,
+ IPT_UI_ZOOM_OUT,
+ IPT_UI_PREV_GROUP,
+ IPT_UI_NEXT_GROUP,
+ IPT_UI_ROTATE,
+ IPT_UI_SHOW_PROFILER,
+ IPT_UI_TOGGLE_UI,
+ IPT_UI_TOGGLE_DEBUG,
+ IPT_UI_SAVE_STATE,
+ IPT_UI_LOAD_STATE,
+ IPT_UI_ADD_CHEAT,
+ IPT_UI_DELETE_CHEAT,
+ IPT_UI_SAVE_CHEAT,
+ IPT_UI_WATCH_VALUE,
+ IPT_UI_EDIT_CHEAT,
+ IPT_UI_RELOAD_CHEAT,
+ IPT_UI_TOGGLE_CROSSHAIR,
+
+ /* additional OSD-specified UI port types (up to 16) */
+ IPT_OSD_1,
+ IPT_OSD_2,
+ IPT_OSD_3,
+ IPT_OSD_4,
+ IPT_OSD_5,
+ IPT_OSD_6,
+ IPT_OSD_7,
+ IPT_OSD_8,
+ IPT_OSD_9,
+ IPT_OSD_10,
+ IPT_OSD_11,
+ IPT_OSD_12,
+ IPT_OSD_13,
+ IPT_OSD_14,
+ IPT_OSD_15,
+ IPT_OSD_16,
+
+ /* other meaning not mapped to standard defaults */
+ IPT_OTHER,
+
+ /* special meaning handled by custom code */
+ IPT_SPECIAL,
+
+ __ipt_max
+};
+
+
+/* token types */
+enum
+{
+ INPUT_TOKEN_INVALID,
+ INPUT_TOKEN_END,
+ INPUT_TOKEN_INCLUDE,
+ INPUT_TOKEN_START,
+ INPUT_TOKEN_START_TAG,
+ INPUT_TOKEN_MODIFY,
+ INPUT_TOKEN_BIT,
+ INPUT_TOKEN_CODE,
+ INPUT_TOKEN_CODE_DEC,
+ INPUT_TOKEN_CODE_INC,
+ INPUT_TOKEN_2WAY,
+ INPUT_TOKEN_4WAY,
+ INPUT_TOKEN_8WAY,
+ INPUT_TOKEN_16WAY,
+ INPUT_TOKEN_ROTATED,
+ INPUT_TOKEN_PLAYER1,
+ INPUT_TOKEN_PLAYER2,
+ INPUT_TOKEN_PLAYER3,
+ INPUT_TOKEN_PLAYER4,
+ INPUT_TOKEN_PLAYER5,
+ INPUT_TOKEN_PLAYER6,
+ INPUT_TOKEN_PLAYER7,
+ INPUT_TOKEN_PLAYER8,
+ INPUT_TOKEN_COCKTAIL,
+ INPUT_TOKEN_TOGGLE,
+ INPUT_TOKEN_NAME,
+ INPUT_TOKEN_IMPULSE,
+ INPUT_TOKEN_REVERSE,
+ INPUT_TOKEN_RESET,
+ INPUT_TOKEN_MINMAX,
+ INPUT_TOKEN_SENSITIVITY,
+ INPUT_TOKEN_KEYDELTA,
+ INPUT_TOKEN_CENTERDELTA,
+ INPUT_TOKEN_CROSSHAIR,
+ INPUT_TOKEN_FULL_TURN_COUNT,
+ INPUT_TOKEN_POSITIONS,
+ INPUT_TOKEN_WRAPS,
+ INPUT_TOKEN_REMAP_TABLE,
+ INPUT_TOKEN_INVERT,
+ INPUT_TOKEN_UNUSED,
+ INPUT_TOKEN_CUSTOM,
+ INPUT_TOKEN_DIPNAME,
+ INPUT_TOKEN_DIPSETTING,
+ INPUT_TOKEN_DIPLOCATION,
+ INPUT_TOKEN_CONDITION,
+ INPUT_TOKEN_ADJUSTER,
+ INPUT_TOKEN_CONFNAME,
+ INPUT_TOKEN_CONFSETTING,
+#ifdef MESS
+ INPUT_TOKEN_CHAR,
+ INPUT_TOKEN_CATEGORY,
+ INPUT_TOKEN_CATEGORY_NAME,
+ INPUT_TOKEN_CATEGORY_SETTING,
+#endif /* MESS */
+};
+
+
+/* default strings used in port definitions */
+enum
+{
+ INPUT_STRING_Off = 1,
+ INPUT_STRING_On,
+ INPUT_STRING_No,
+ INPUT_STRING_Yes,
+ INPUT_STRING_Lives,
+ INPUT_STRING_Bonus_Life,
+ INPUT_STRING_Difficulty,
+ INPUT_STRING_Demo_Sounds,
+ INPUT_STRING_Coinage,
+ INPUT_STRING_Coin_A,
+ INPUT_STRING_Coin_B,
+ INPUT_STRING_9C_1C,
+ INPUT_STRING_8C_1C,
+ INPUT_STRING_7C_1C,
+ INPUT_STRING_6C_1C,
+ INPUT_STRING_5C_1C,
+ INPUT_STRING_4C_1C,
+ INPUT_STRING_3C_1C,
+ INPUT_STRING_8C_3C,
+ INPUT_STRING_4C_2C,
+ INPUT_STRING_2C_1C,
+ INPUT_STRING_5C_3C,
+ INPUT_STRING_3C_2C,
+ INPUT_STRING_4C_3C,
+ INPUT_STRING_4C_4C,
+ INPUT_STRING_3C_3C,
+ INPUT_STRING_2C_2C,
+ INPUT_STRING_1C_1C,
+ INPUT_STRING_4C_5C,
+ INPUT_STRING_3C_4C,
+ INPUT_STRING_2C_3C,
+ INPUT_STRING_4C_7C,
+ INPUT_STRING_2C_4C,
+ INPUT_STRING_1C_2C,
+ INPUT_STRING_2C_5C,
+ INPUT_STRING_2C_6C,
+ INPUT_STRING_1C_3C,
+ INPUT_STRING_2C_7C,
+ INPUT_STRING_2C_8C,
+ INPUT_STRING_1C_4C,
+ INPUT_STRING_1C_5C,
+ INPUT_STRING_1C_6C,
+ INPUT_STRING_1C_7C,
+ INPUT_STRING_1C_8C,
+ INPUT_STRING_1C_9C,
+ INPUT_STRING_Free_Play,
+ INPUT_STRING_Cabinet,
+ INPUT_STRING_Upright,
+ INPUT_STRING_Cocktail,
+ INPUT_STRING_Flip_Screen,
+ INPUT_STRING_Service_Mode,
+ INPUT_STRING_Pause,
+ INPUT_STRING_Test,
+ INPUT_STRING_Tilt,
+ INPUT_STRING_Version,
+ INPUT_STRING_Region,
+ INPUT_STRING_International,
+ INPUT_STRING_Japan,
+ INPUT_STRING_USA,
+ INPUT_STRING_Europe,
+ INPUT_STRING_Asia,
+ INPUT_STRING_World,
+ INPUT_STRING_Hispanic,
+ INPUT_STRING_Language,
+ INPUT_STRING_English,
+ INPUT_STRING_Japanese,
+ INPUT_STRING_German,
+ INPUT_STRING_French,
+ INPUT_STRING_Italian,
+ INPUT_STRING_Spanish,
+ INPUT_STRING_Very_Easy,
+ INPUT_STRING_Easiest,
+ INPUT_STRING_Easier,
+ INPUT_STRING_Easy,
+ INPUT_STRING_Normal,
+ INPUT_STRING_Medium,
+ INPUT_STRING_Hard,
+ INPUT_STRING_Harder,
+ INPUT_STRING_Hardest,
+ INPUT_STRING_Very_Hard,
+ INPUT_STRING_Very_Low,
+ INPUT_STRING_Low,
+ INPUT_STRING_High,
+ INPUT_STRING_Higher,
+ INPUT_STRING_Highest,
+ INPUT_STRING_Very_High,
+ INPUT_STRING_Players,
+ INPUT_STRING_Controls,
+ INPUT_STRING_Dual,
+ INPUT_STRING_Single,
+ INPUT_STRING_Game_Time,
+ INPUT_STRING_Continue_Price,
+ INPUT_STRING_Controller,
+ INPUT_STRING_Light_Gun,
+ INPUT_STRING_Joystick,
+ INPUT_STRING_Trackball,
+ INPUT_STRING_Continues,
+ INPUT_STRING_Allow_Continue,
+ INPUT_STRING_Level_Select,
+ INPUT_STRING_Infinite,
+ INPUT_STRING_Stereo,
+ INPUT_STRING_Mono,
+ INPUT_STRING_Unused,
+ INPUT_STRING_Unknown,
+ INPUT_STRING_Standard,
+ INPUT_STRING_Reverse,
+ INPUT_STRING_Alternate,
+ INPUT_STRING_None,
+
+ INPUT_STRING_COUNT
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* this is an opaque type */
+typedef struct _input_port_init_params input_port_init_params;
+
+
+/* this type is used to encode input port definitions */
+typedef struct _input_port_token *input_port_token;
+
+
+/* In mamecore.h: typedef struct _input_port_default_entry input_port_default_entry; */
+struct _input_port_default_entry
+{
+ UINT32 type; /* type of port; see enum above */
+ UINT8 group; /* which group the port belongs to */
+ UINT8 player; /* player number (0 is player 1) */
+ const char *token; /* token used to store settings */
+ const char *name; /* user-friendly name */
+ input_seq defaultseq; /* default input sequence */
+ input_seq defaultincseq; /* default input sequence to increment (analog ports only) */
+ input_seq defaultdecseq; /* default input sequence to decrement (analog ports only) */
+};
+
+
+/* In mamecore.h: typedef struct _input_port_entry input_port_entry; */
+struct _input_port_entry
+{
+ UINT32 mask; /* bits affected */
+ UINT32 default_value; /* default value for the bits affected */
+ /* you can also use one of the IP_ACTIVE defines above */
+ UINT32 type; /* see enum above */
+ UINT8 unused; /* The bit is not used by this game, but is used */
+ /* by other games running on the same hardware. */
+ /* This is different from IPT_UNUSED, which marks */
+ /* bits not connected to anything. */
+ UINT8 cocktail; /* the bit is used in cocktail mode only */
+ UINT8 player; /* the player associated with this port; note that */
+ /* player 1 is '0' */
+ UINT8 toggle; /* When this is set, the key acts as a toggle - press */
+ /* it once and it goes on, press it again and it goes off. */
+ /* useful e.g. for some Test Mode dip switches. */
+ UINT8 impulse; /* When this is set, when the key corresponding to */
+ /* the input bit is pressed it will be reported as */
+ /* pressed for a certain number of video frames and */
+ /* then released, regardless of the real status of */
+ /* the key. This is useful e.g. for some coin inputs. */
+ /* The number of frames the signal should stay active */
+ /* is specified in the "arg" field. */
+ UINT8 way; /* Joystick modes of operation. 8WAY is the default, */
+ /* it prevents left/right or up/down to be pressed at */
+ /* the same time. 4WAY prevents diagonal directions. */
+ /* 2WAY should be used for joysticks wich move only */
+ /* on one axis (e.g. Battle Zone) */
+ UINT8 rotated; /* Indicates the control is rotated 45 degrees. This */
+ /* is used as a hint for joystick mapping. */
+ UINT16 category; /* (MESS-specific) category */
+ const char *name; /* user-friendly name to display */
+ input_seq seq; /* input sequence affecting the input bits */
+ UINT32 (*custom)(void *);/* custom callback routine */
+ void * custom_param; /* parameter for callback routine */
+
+ /* valid if type is between __ipt_analog_start and __ipt_analog_end */
+ struct
+ {
+ INT32 min; /* minimum value for absolute axes */
+ INT32 max; /* maximum value for absolute axes */
+ INT32 sensitivity; /* sensitivity (100=normal) */
+ INT32 delta; /* delta to apply each frame a digital inc/dec key is pressed */
+ INT32 centerdelta; /* delta to apply each frame no digital inputs are pressed */
+ UINT8 reverse; /* reverse the sense of the analog axis */
+ UINT8 reset; /* always preload in->default for relative axes, returning only deltas */
+ UINT8 crossaxis; /* crosshair axis */
+ float crossscale; /* crosshair scale */
+ float crossoffset; /* crosshair offset */
+ float crossaltaxis; /* crosshair alternate axis value */
+ input_seq incseq; /* increment sequence */
+ input_seq decseq; /* decrement sequence */
+ UINT8 wraps; /* positional count wraps around */
+ UINT8 invert; /* bitwise invert bits */
+ UINT16 full_turn_count; /* number of optical counts for 1 full turn of the original control */
+ const UINT32 *remap_table; /* pointer to an array that remaps the port value */
+ } analog;
+
+ /* valid if type is IPT_PORT */
+ struct
+ {
+ const char *tag; /* used to tag PORT_START declarations */
+ } start;
+
+ /* valid for most types */
+ struct
+ {
+ const char *tag; /* port tag to use for condition */
+ UINT8 portnum; /* port number for condition */
+ UINT8 condition; /* condition to use */
+ UINT32 mask; /* mask to apply to the port */
+ UINT32 value; /* value to compare against */
+ } condition;
+
+ /* valid for IPT_DIPNAME */
+ struct
+ {
+ const char *swname; /* name of the physical DIP switch */
+ UINT8 swnum; /* physical switch number */
+ UINT8 invert; /* is this an active-high DIP? */
+ } diploc[8];
+
+ /* valid if type is IPT_KEYBOARD */
+#ifdef MESS
+ struct
+ {
+ unicode_char chars[3];/* (MESS-specific) unicode key data */
+ } keyboard;
+#endif /* MESS */
+};
+
+
+typedef struct _inp_header inp_header;
+struct _inp_header
+{
+ char name[9]; /* 8 bytes for game->name + NUL */
+ char version[3]; /* byte[0] = 0, byte[1] = version byte[2] = beta_version */
+ char reserved[20]; /* for future use, possible store game options? */
+};
+
+
+
+/***************************************************************************
+ MACROS FOR BUILDING INPUT PORTS
+***************************************************************************/
+
+#define IP_NAME_DEFAULT NULL
+
+/* single pointers and UINT32s are just encoded straight */
+#define INPUT_PORT_PTR(x) ((input_port_token)(x))
+#define INPUT_PORT_UINT32(x) ((input_port_token)(FPTR)(UINT32)(FPTR)(x))
+
+#ifdef PTR64
+/* on 64-bit platforms, pairs of UINT32s are encoded into a single 64-bit pointer */
+#define INPUT_PORT_UINT32_PAIR(x,y) ((input_port_token)((UINT32)(x) | ((UINT64)(y) << 32)))
+#define INPUT_PORT_PAIR_ITEM(vptr,x) ((UINT32)((FPTR)*(vptr) >> (32 * (x))))
+#define INPUT_PORT_PAIR_TOKENS 1
+#else
+/* on 32-bit platforms, pairs of UINT32s are encoded in two consecutive 32-bit pointers */
+#define INPUT_PORT_UINT32_PAIR(x,y) INPUT_PORT_UINT32(x), INPUT_PORT_UINT32(y)
+#define INPUT_PORT_PAIR_ITEM(vptr,x) ((UINT32)((vptr)[x]))
+#define INPUT_PORT_PAIR_TOKENS 2
+#endif
+
+/* start of table */
+#define INPUT_PORTS_START(name) \
+ const input_port_token ipt_##name[] = {
+
+/* end of table */
+#define INPUT_PORTS_END \
+ INPUT_PORT_UINT32(INPUT_TOKEN_END) };
+
+/* aliasing */
+#define INPUT_PORTS_EXTERN(name) \
+ extern const input_port_token ipt_##name[]
+
+/* including */
+#define PORT_INCLUDE(name) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_INCLUDE), INPUT_PORT_PTR(&ipt_##name[0]),
+
+/* start of a new input port */
+#define PORT_START \
+ INPUT_PORT_UINT32(INPUT_TOKEN_START),
+
+/* start of a new input port (with included tag) */
+#define PORT_START_TAG(tag_) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_START_TAG), INPUT_PORT_PTR(tag_),
+
+/* modify an existing port */
+#define PORT_MODIFY(tag_) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_MODIFY), INPUT_PORT_PTR(tag_),
+
+/* input bit definition */
+#define PORT_BIT(mask_,default_,type_) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_BIT, type_), INPUT_PORT_UINT32_PAIR(mask_, default_),
+
+/* append a code */
+#define PORT_CODE(code) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CODE, code),
+
+#define PORT_CODE_DEC(code) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CODE_DEC, code),
+
+#define PORT_CODE_INC(code) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CODE_INC, code),
+
+/* joystick flags */
+#define PORT_2WAY \
+ INPUT_PORT_UINT32(INPUT_TOKEN_2WAY),
+
+#define PORT_4WAY \
+ INPUT_PORT_UINT32(INPUT_TOKEN_4WAY),
+
+#define PORT_8WAY \
+ INPUT_PORT_UINT32(INPUT_TOKEN_8WAY),
+
+#define PORT_16WAY \
+ INPUT_PORT_UINT32(INPUT_TOKEN_16WAY),
+
+#define PORT_ROTATED \
+ INPUT_PORT_UINT32(INPUT_TOKEN_ROTATED),
+
+/* general flags */
+#define PORT_NAME(name_) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_NAME), INPUT_PORT_PTR(name_),
+
+#define PORT_PLAYER(player_) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_PLAYER1 + (((player_) - 1) % MAX_PLAYERS)),
+
+#define PORT_COCKTAIL \
+ INPUT_PORT_UINT32(INPUT_TOKEN_COCKTAIL),
+
+#define PORT_TOGGLE \
+ INPUT_PORT_UINT32(INPUT_TOKEN_TOGGLE),
+
+#define PORT_IMPULSE(duration_) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_IMPULSE, duration_),
+
+#define PORT_REVERSE \
+ INPUT_PORT_UINT32(INPUT_TOKEN_REVERSE),
+
+#define PORT_RESET \
+ INPUT_PORT_UINT32(INPUT_TOKEN_RESET),
+
+#define PORT_UNUSED \
+ INPUT_PORT_UINT32(INPUT_TOKEN_UNUSED),
+
+/* analog settings */
+/* if this macro is not used, the minimum defaluts to 0 and maximum defaluts to the mask value */
+#define PORT_MINMAX(min_,max_) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_MINMAX), INPUT_PORT_UINT32_PAIR(min_, max_),
+
+#define PORT_SENSITIVITY(sensitivity_) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_SENSITIVITY, sensitivity_),
+
+#define PORT_KEYDELTA(delta_) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_KEYDELTA, delta_),
+
+/* note that PORT_CENTERDELTA must appear after PORT_KEYDELTA */
+#define PORT_CENTERDELTA(delta_) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CENTERDELTA, delta_),
+
+#define PORT_CROSSHAIR(axis, scale, offset, altaxis) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CROSSHAIR, CROSSHAIR_AXIS_##axis | ((INT32)((altaxis) * 65536.0f) << 8)), \
+ INPUT_PORT_UINT32_PAIR((INT32)((scale) * 65536.0f), (INT32)((offset) * 65536.0f)),
+
+/* how many optical counts for 1 full turn of the control */
+#define PORT_FULL_TURN_COUNT(count_) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_FULL_TURN_COUNT, count_),
+
+/* positional controls can be binary or 1 of X */
+/* 1 of X not completed yet */
+/* if it is specified as PORT_REMAP_TABLE then it is binary, but remapped */
+/* otherwise it is binary */
+#define PORT_POSITIONS(positions_) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_POSITIONS, positions_),
+
+/* positional control wraps at min/max */
+#define PORT_WRAPS \
+ INPUT_PORT_UINT32(INPUT_TOKEN_WRAPS),
+
+/* positional control uses this remap table */
+#define PORT_REMAP_TABLE(table_) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_REMAP_TABLE), INPUT_PORT_PTR(table_),
+
+/* positional control bits are active low */
+#define PORT_INVERT \
+ INPUT_PORT_UINT32(INPUT_TOKEN_INVERT),
+
+/* custom callbacks */
+#define PORT_CUSTOM(callback_, param_) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_CUSTOM), INPUT_PORT_PTR(callback_), INPUT_PORT_PTR(param_),
+
+/* dip switch definition */
+#define PORT_DIPNAME(mask,default,name) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_DIPNAME), INPUT_PORT_UINT32_PAIR(mask, default), INPUT_PORT_PTR(name),
+
+#define PORT_DIPSETTING(default,name) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_DIPSETTING, default), INPUT_PORT_PTR(name),
+
+/* physical location, of the form: name:[!]sw,[name:][!]sw,... */
+/* note that these are specified LSB-first */
+#define PORT_DIPLOCATION(location_) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_DIPLOCATION), INPUT_PORT_PTR(location_),
+
+/* conditionals for dip switch settings */
+#define PORT_CONDITION(tag_,mask_,condition_,value_) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CONDITION, condition_), INPUT_PORT_UINT32_PAIR(mask_, value_), INPUT_PORT_PTR(tag_),
+
+/* analog adjuster definition */
+#define PORT_ADJUSTER(default,name) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_ADJUSTER, default), INPUT_PORT_PTR(name),
+
+/* config definition */
+#define PORT_CONFNAME(mask,default,name) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_CONFNAME), INPUT_PORT_UINT32_PAIR(mask, default), INPUT_PORT_PTR(name),
+
+#define PORT_CONFSETTING(default,name) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CONFSETTING, default), INPUT_PORT_PTR(name),
+
+#ifdef MESS
+/* keyboard chars */
+#define PORT_CHAR(ch) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CHAR, ch),
+
+/* categories */
+#define PORT_CATEGORY(category) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CATEGORY, category),
+
+#define PORT_CATEGORY_CLASS(mask,default,name) \
+ INPUT_PORT_UINT32(INPUT_TOKEN_CATEGORY_NAME), INPUT_PORT_UINT32_PAIR(mask, default), INPUT_PORT_PTR(name),
+
+#define PORT_CATEGORY_ITEM(default,name,category) \
+ INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CATEGORY_SETTING, default), INPUT_PORT_PTR(name), INPUT_PORT_UINT32_PAIR(INPUT_TOKEN_CATEGORY, category),
+#endif /* MESS */
+
+
+
+/***************************************************************************
+ HELPER MACROS
+***************************************************************************/
+
+#define PORT_SERVICE_DIPLOC(mask,default,loc) \
+ PORT_BIT( mask, mask & default, IPT_DIPSWITCH_NAME ) PORT_NAME( DEF_STR( Service_Mode )) PORT_CODE(KEYCODE_F2) PORT_TOGGLE PORT_DIPLOCATION(loc) \
+ PORT_DIPSETTING( mask & default, DEF_STR( Off ) ) \
+ PORT_DIPSETTING( mask &~default, DEF_STR( On ) )
+
+#define PORT_SERVICE(mask,default) \
+ PORT_BIT( mask, mask & default, IPT_DIPSWITCH_NAME ) PORT_NAME( DEF_STR( Service_Mode )) PORT_CODE(KEYCODE_F2) PORT_TOGGLE \
+ PORT_DIPSETTING( mask & default, DEF_STR( Off ) ) \
+ PORT_DIPSETTING( mask &~default, DEF_STR( On ) )
+
+#define PORT_SERVICE_NO_TOGGLE(mask,default) \
+ PORT_BIT( mask, mask & default, IPT_SERVICE ) PORT_NAME( DEF_STR( Service_Mode ))
+
+#define PORT_DIPUNUSED_DIPLOC(mask,default,loc) \
+ PORT_BIT( mask, mask & default, IPT_DIPSWITCH_NAME ) PORT_NAME( DEF_STR( Unused )) PORT_DIPLOCATION(loc) \
+ PORT_DIPSETTING( mask & default, DEF_STR( Off ) ) \
+ PORT_DIPSETTING( mask &~default, DEF_STR( On ) )
+
+#define PORT_DIPUNUSED(mask,default) \
+ PORT_BIT( mask, mask & default, IPT_DIPSWITCH_NAME ) PORT_NAME( DEF_STR( Unused )) \
+ PORT_DIPSETTING( mask & default, DEF_STR( Off ) ) \
+ PORT_DIPSETTING( mask &~default, DEF_STR( On ) )
+
+#define PORT_DIPUNKNOWN_DIPLOC(mask,default,loc) \
+ PORT_BIT( mask, mask & default, IPT_DIPSWITCH_NAME ) PORT_NAME( DEF_STR( Unknown )) PORT_DIPLOCATION(loc) \
+ PORT_DIPSETTING( mask & default, DEF_STR( Off ) ) \
+ PORT_DIPSETTING( mask &~default, DEF_STR( On ) )
+
+#define PORT_DIPUNKNOWN(mask,default) \
+ PORT_BIT( mask, mask & default, IPT_DIPSWITCH_NAME ) PORT_NAME( DEF_STR( Unknown )) \
+ PORT_DIPSETTING( mask & default, DEF_STR( Off ) ) \
+ PORT_DIPSETTING( mask &~default, DEF_STR( On ) )
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+#define DEF_STR(str_num) ((const char *)INPUT_STRING_##str_num)
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void input_port_init(running_machine *machine, const input_port_token *ipt);
+const char *input_port_string_from_token(const input_port_token token);
+
+input_port_entry *input_port_initialize(input_port_init_params *params, UINT32 type, const char *tag, UINT32 mask, UINT32 defval);
+input_port_entry *input_port_allocate(const input_port_token *ipt, input_port_entry *memory);
+void input_port_parse_diplocation(input_port_entry *in, const char *location);
+
+input_port_default_entry *get_input_port_list(void);
+const input_port_default_entry *get_input_port_list_defaults(void);
+
+int input_port_active(const input_port_entry *in);
+int port_type_is_analog(int type);
+int port_type_is_analog_absolute(int type);
+int port_type_in_use(int type);
+int port_type_to_group(int type, int player);
+int port_tag_to_index(const char *tag);
+read8_handler port_tag_to_handler8(const char *tag);
+read16_handler port_tag_to_handler16(const char *tag);
+read32_handler port_tag_to_handler32(const char *tag);
+read64_handler port_tag_to_handler64(const char *tag);
+const char *input_port_name(const input_port_entry *in);
+input_seq *input_port_seq(input_port_entry *in, int seqtype);
+input_seq *input_port_default_seq(int type, int player, int seqtype);
+int input_port_condition(const input_port_entry *in);
+void input_port_set_changed_callback(int port, UINT32 mask, void (*callback)(void *, UINT32, UINT32), void *param);
+
+const char *port_type_to_token(int type, int player);
+int token_to_port_type(const char *string, int *player);
+
+int input_port_type_pressed(int type, int player);
+int input_ui_pressed(int code);
+int input_ui_pressed_repeat(int code, int speed);
+
+void input_port_update_defaults(void);
+void input_port_vblank_start(void); /* called by cpuintrf.c - not for external use */
+void input_port_vblank_end(void); /* called by cpuintrf.c - not for external use */
+
+void input_port_set_digital_value(int port, UINT32 value, UINT32 mask);
+
+UINT32 get_crosshair_pos(int port_num, UINT8 player, UINT8 axis);
+
+UINT32 readinputport(int port);
+UINT32 readinputportbytag(const char *tag);
+UINT32 readinputportbytag_safe(const char *tag, UINT32 defvalue);
+
+#endif /* __INPTPORT_H__ */
diff --git a/src/emu/input.c b/src/emu/input.c
new file mode 100644
index 00000000000..9a961ea0b7a
--- /dev/null
+++ b/src/emu/input.c
@@ -0,0 +1,1603 @@
+/***************************************************************************
+
+ input.c
+
+ Handle input from the user.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ To do:
+ * auto-selecting joystick configs
+ * per-joystick configs?
+ * test half-axis selections
+ * add input test menu
+ * get rid of osd_customize_inputport_list
+
+***************************************************************************/
+
+#include "input.h"
+#include "mame.h"
+#include "emuopts.h"
+#include "profiler.h"
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* joystick mapping codes */
+#define JOYSTICK_MAP_NEUTRAL 0x00
+#define JOYSTICK_MAP_LEFT 0x01
+#define JOYSTICK_MAP_RIGHT 0x02
+#define JOYSTICK_MAP_UP 0x04
+#define JOYSTICK_MAP_DOWN 0x08
+#define JOYSTICK_MAP_STICKY 0x0f
+
+/* the largest number of tracked pressed switches for memory */
+#define MAX_PRESSED_SWITCHES 16
+
+/* invalid memory value for axis polling */
+#define INVALID_AXIS_VALUE 0x7fffffff
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* single device item */
+typedef struct _input_device_item input_device_item;
+struct _input_device_item
+{
+ input_device_class devclass; /* device class of parent item */
+ int devindex; /* device index of parent item */
+ astring * name; /* string name of item */
+ astring * token; /* tokenized name for non-standard items */
+ void * internal; /* internal callback pointer */
+ input_item_class itemclass; /* class of the item */
+ input_item_id itemid; /* originally specified item id */
+ item_get_state_cb getstate; /* get state callback */
+ INT32 current; /* current raw value */
+ INT32 memory; /* "memory" value, to remember where we started during polling */
+ INT32 oncelatch; /* latched "once" value, cleared after each read */
+
+ /* keyboard information */
+ INT32 steadykey; /* the live steadykey state */
+ INT32 oldkey; /* old live state */
+};
+
+
+/* a 9x9 joystick map */
+typedef struct _joystick_map joystick_map;
+struct _joystick_map
+{
+ UINT8 map[9][9]; /* 9x9 grid */
+};
+
+
+/* a single input device */
+struct _input_device
+{
+ astring * name; /* string name of device */
+ input_device_class devclass; /* class of this device */
+ int devindex; /* device index of this device */
+ input_device_item * item[ITEM_ID_ABSOLUTE_MAXIMUM]; /* array of pointers to items */
+ input_item_id maxitem; /* maximum item index */
+ void * internal; /* internal callback pointer */
+
+ /* joystick information */
+ joystick_map joymap; /* joystick map for this device */
+ UINT8 lastmap; /* last joystick map value for this device */
+};
+
+
+/* a list of devices as an array */
+typedef struct _input_device_list input_device_list;
+struct _input_device_list
+{
+ input_device * list; /* the array */
+ int count; /* elements in the array */
+ UINT8 enabled; /* is this class enabled? */
+ UINT8 multi; /* are multiple instances of this class allowed? */
+};
+
+
+/* code <-> string matching */
+typedef struct _code_string_table code_string_table;
+struct _code_string_table
+{
+ UINT32 code;
+ const char * string;
+};
+
+
+
+/***************************************************************************
+ TOKEN/STRING TABLES
+***************************************************************************/
+
+/* token strings for device classes */
+static const code_string_table devclass_token_table[] =
+{
+ { DEVICE_CLASS_KEYBOARD, "KEYCODE" },
+ { DEVICE_CLASS_MOUSE, "MOUSECODE" },
+ { DEVICE_CLASS_LIGHTGUN, "GUNCODE" },
+ { DEVICE_CLASS_JOYSTICK, "JOYCODE" },
+ { ~0, "UNKCODE" }
+};
+
+/* friendly strings for device classes */
+static const code_string_table devclass_string_table[] =
+{
+ { DEVICE_CLASS_KEYBOARD, "Kbd" },
+ { DEVICE_CLASS_MOUSE, "Mouse" },
+ { DEVICE_CLASS_LIGHTGUN, "Gun" },
+ { DEVICE_CLASS_JOYSTICK, "Joy" },
+ { ~0, "Unk" }
+};
+
+/* token strings for item modifiers */
+static const code_string_table modifier_token_table[] =
+{
+ { ITEM_MODIFIER_POS, "POS" },
+ { ITEM_MODIFIER_NEG, "NEG" },
+ { ITEM_MODIFIER_LEFT, "LEFT" },
+ { ITEM_MODIFIER_RIGHT, "RIGHT" },
+ { ITEM_MODIFIER_UP, "UP" },
+ { ITEM_MODIFIER_DOWN, "DOWN" },
+ { ~0, "" }
+};
+
+/* friendly strings for item modifiers */
+static const code_string_table modifier_string_table[] =
+{
+ { ITEM_MODIFIER_POS, "+" },
+ { ITEM_MODIFIER_NEG, "-" },
+ { ITEM_MODIFIER_LEFT, "Left" },
+ { ITEM_MODIFIER_RIGHT, "Right" },
+ { ITEM_MODIFIER_UP, "Up" },
+ { ITEM_MODIFIER_DOWN, "Down" },
+ { ~0, "" }
+};
+
+/* token strings for item classes */
+static const code_string_table itemclass_token_table[] =
+{
+ { ITEM_CLASS_SWITCH, "SWITCH" },
+ { ITEM_CLASS_ABSOLUTE, "ABSOLUTE" },
+ { ITEM_CLASS_RELATIVE, "RELATIVE" },
+ { ~0, "" }
+};
+
+/* token strings for standard item ids */
+static const code_string_table itemid_token_table[] =
+{
+ /* standard keyboard codes */
+ { ITEM_ID_A, "A" },
+ { ITEM_ID_B, "B" },
+ { ITEM_ID_C, "C" },
+ { ITEM_ID_D, "D" },
+ { ITEM_ID_E, "E" },
+ { ITEM_ID_F, "F" },
+ { ITEM_ID_G, "G" },
+ { ITEM_ID_H, "H" },
+ { ITEM_ID_I, "I" },
+ { ITEM_ID_J, "J" },
+ { ITEM_ID_K, "K" },
+ { ITEM_ID_L, "L" },
+ { ITEM_ID_M, "M" },
+ { ITEM_ID_N, "N" },
+ { ITEM_ID_O, "O" },
+ { ITEM_ID_P, "P" },
+ { ITEM_ID_Q, "Q" },
+ { ITEM_ID_R, "R" },
+ { ITEM_ID_S, "S" },
+ { ITEM_ID_T, "T" },
+ { ITEM_ID_U, "U" },
+ { ITEM_ID_V, "V" },
+ { ITEM_ID_W, "W" },
+ { ITEM_ID_X, "X" },
+ { ITEM_ID_Y, "Y" },
+ { ITEM_ID_Z, "Z" },
+ { ITEM_ID_0, "0" },
+ { ITEM_ID_1, "1" },
+ { ITEM_ID_2, "2" },
+ { ITEM_ID_3, "3" },
+ { ITEM_ID_4, "4" },
+ { ITEM_ID_5, "5" },
+ { ITEM_ID_6, "6" },
+ { ITEM_ID_7, "7" },
+ { ITEM_ID_8, "8" },
+ { ITEM_ID_9, "9" },
+ { ITEM_ID_F1, "F1" },
+ { ITEM_ID_F2, "F2" },
+ { ITEM_ID_F3, "F3" },
+ { ITEM_ID_F4, "F4" },
+ { ITEM_ID_F5, "F5" },
+ { ITEM_ID_F6, "F6" },
+ { ITEM_ID_F7, "F7" },
+ { ITEM_ID_F8, "F8" },
+ { ITEM_ID_F9, "F9" },
+ { ITEM_ID_F10, "F10" },
+ { ITEM_ID_F11, "F11" },
+ { ITEM_ID_F12, "F12" },
+ { ITEM_ID_F13, "F13" },
+ { ITEM_ID_F14, "F14" },
+ { ITEM_ID_F15, "F15" },
+ { ITEM_ID_ESC, "ESC" },
+ { ITEM_ID_TILDE, "TILDE" },
+ { ITEM_ID_MINUS, "MINUS" },
+ { ITEM_ID_EQUALS, "EQUALS" },
+ { ITEM_ID_BACKSPACE, "BACKSPACE" },
+ { ITEM_ID_TAB, "TAB" },
+ { ITEM_ID_OPENBRACE, "OPENBRACE" },
+ { ITEM_ID_CLOSEBRACE, "CLOSEBRACE" },
+ { ITEM_ID_ENTER, "ENTER" },
+ { ITEM_ID_COLON, "COLON" },
+ { ITEM_ID_QUOTE, "QUOTE" },
+ { ITEM_ID_BACKSLASH, "BACKSLASH" },
+ { ITEM_ID_BACKSLASH2, "BACKSLASH2" },
+ { ITEM_ID_COMMA, "COMMA" },
+ { ITEM_ID_STOP, "STOP" },
+ { ITEM_ID_SLASH, "SLASH" },
+ { ITEM_ID_SPACE, "SPACE" },
+ { ITEM_ID_INSERT, "INSERT" },
+ { ITEM_ID_DEL, "DEL" },
+ { ITEM_ID_HOME, "HOME" },
+ { ITEM_ID_END, "END" },
+ { ITEM_ID_PGUP, "PGUP" },
+ { ITEM_ID_PGDN, "PGDN" },
+ { ITEM_ID_LEFT, "LEFT" },
+ { ITEM_ID_RIGHT, "RIGHT" },
+ { ITEM_ID_UP, "UP" },
+ { ITEM_ID_DOWN, "DOWN" },
+ { ITEM_ID_0_PAD, "0PAD" },
+ { ITEM_ID_1_PAD, "1PAD" },
+ { ITEM_ID_2_PAD, "2PAD" },
+ { ITEM_ID_3_PAD, "3PAD" },
+ { ITEM_ID_4_PAD, "4PAD" },
+ { ITEM_ID_5_PAD, "5PAD" },
+ { ITEM_ID_6_PAD, "6PAD" },
+ { ITEM_ID_7_PAD, "7PAD" },
+ { ITEM_ID_8_PAD, "8PAD" },
+ { ITEM_ID_9_PAD, "9PAD" },
+ { ITEM_ID_SLASH_PAD, "SLASHPAD" },
+ { ITEM_ID_ASTERISK, "ASTERISK" },
+ { ITEM_ID_MINUS_PAD, "MINUSPAD" },
+ { ITEM_ID_PLUS_PAD, "PLUSPAD" },
+ { ITEM_ID_DEL_PAD, "DELPAD" },
+ { ITEM_ID_ENTER_PAD, "ENTERPAD" },
+ { ITEM_ID_PRTSCR, "PRTSCR" },
+ { ITEM_ID_PAUSE, "PAUSE" },
+ { ITEM_ID_LSHIFT, "LSHIFT" },
+ { ITEM_ID_RSHIFT, "RSHIFT" },
+ { ITEM_ID_LCONTROL, "LCONTROL" },
+ { ITEM_ID_RCONTROL, "RCONTROL" },
+ { ITEM_ID_LALT, "LALT" },
+ { ITEM_ID_RALT, "RALT" },
+ { ITEM_ID_SCRLOCK, "SCRLOCK" },
+ { ITEM_ID_NUMLOCK, "NUMLOCK" },
+ { ITEM_ID_CAPSLOCK, "CAPSLOCK" },
+ { ITEM_ID_LWIN, "LWIN" },
+ { ITEM_ID_RWIN, "RWIN" },
+ { ITEM_ID_MENU, "MENU" },
+ { ITEM_ID_CANCEL, "CANCEL" },
+
+ /* standard mouse/joystick/gun codes */
+ { ITEM_ID_XAXIS, "XAXIS" },
+ { ITEM_ID_YAXIS, "YAXIS" },
+ { ITEM_ID_ZAXIS, "ZAXIS" },
+ { ITEM_ID_RXAXIS, "RXAXIS" },
+ { ITEM_ID_RYAXIS, "RYAXIS" },
+ { ITEM_ID_RZAXIS, "RZAXIS" },
+ { ITEM_ID_SLIDER1, "SLIDER1" },
+ { ITEM_ID_SLIDER2, "SLIDER2" },
+ { ITEM_ID_BUTTON1, "BUTTON1" },
+ { ITEM_ID_BUTTON2, "BUTTON2" },
+ { ITEM_ID_BUTTON3, "BUTTON3" },
+ { ITEM_ID_BUTTON4, "BUTTON4" },
+ { ITEM_ID_BUTTON5, "BUTTON5" },
+ { ITEM_ID_BUTTON6, "BUTTON6" },
+ { ITEM_ID_BUTTON7, "BUTTON7" },
+ { ITEM_ID_BUTTON8, "BUTTON8" },
+ { ITEM_ID_BUTTON9, "BUTTON9" },
+ { ITEM_ID_BUTTON10, "BUTTON10" },
+ { ITEM_ID_BUTTON11, "BUTTON11" },
+ { ITEM_ID_BUTTON12, "BUTTON12" },
+ { ITEM_ID_BUTTON13, "BUTTON13" },
+ { ITEM_ID_BUTTON14, "BUTTON14" },
+ { ITEM_ID_BUTTON15, "BUTTON15" },
+ { ITEM_ID_BUTTON16, "BUTTON16" },
+ { ITEM_ID_START, "START" },
+ { ITEM_ID_SELECT, "SELECT" },
+
+ { ~0, NULL }
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* array of devices for each class */
+static input_device_list device_list[DEVICE_CLASS_MAXIMUM];
+static input_code code_pressed_memory[MAX_PRESSED_SWITCHES];
+
+/* device configuration */
+static UINT8 steadykey_enabled;
+static UINT8 lightgun_reload_button;
+static const char * joystick_map_default;
+static INT32 joystick_deadzone;
+static INT32 joystick_saturation;
+
+/* standard joystick mappings */
+const char * joystick_map_8way = "7778...4445";
+const char * joystick_map_4way_sticky = "s8.4s8.44s8.4445";
+const char * joystick_map_4way_diagonal = "4444s8888..444458888.444555888.ss5.222555666.222256666.2222s6666.2222s6666";
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void input_frame(running_machine *machine);
+static input_device_item *input_code_item(input_code code);
+static INT32 convert_absolute_value(input_code code, input_device_item *item);
+static INT32 convert_relative_value(input_code code, input_device_item *item);
+static INT32 convert_switch_value(input_code code, input_device_item *item);
+static INT32 apply_deadzone_and_saturation(input_code code, INT32 result);
+static int joystick_map_parse(const char *mapstring, joystick_map *map);
+static void joystick_map_print(const char *header, const char *origstring, const joystick_map *map);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_code_device - given an input_code return
+ a pointer to the associated device
+-------------------------------------------------*/
+
+INLINE input_device *input_code_device(input_code code)
+{
+ /* if the class is valid... */
+ input_device_class devclass = INPUT_CODE_DEVCLASS(code);
+ if (devclass > DEVICE_CLASS_INVALID && devclass < DEVICE_CLASS_MAXIMUM)
+ {
+ /* ...and the index is valid for that class, return a pointer to the device */
+ int devindex = INPUT_CODE_DEVINDEX(code);
+ if (devindex < device_list[devclass].count)
+ return &device_list[devclass].list[devindex];
+ }
+
+ /* otherwise, return NULL */
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ device_item_to_code - convert a device/item
+ pair to a standard code
+-------------------------------------------------*/
+
+INLINE input_code device_item_to_code(input_device *device, input_item_id itemid)
+{
+ int devindex = device->devindex;
+
+ assert(devindex < device_list[device->devclass].count);
+ assert(itemid < ITEM_ID_ABSOLUTE_MAXIMUM);
+ assert(device->item[itemid] != NULL);
+
+ return INPUT_CODE(device->devclass, devindex, device->item[itemid]->itemclass, ITEM_MODIFIER_NONE, itemid);
+}
+
+
+/*-------------------------------------------------
+ input_item_standard_class - return the class
+ of a standard item
+-------------------------------------------------*/
+
+INLINE input_item_class input_item_standard_class(input_device_class devclass, input_item_id itemid)
+{
+ /* most everything standard is a switch, apart from the axes */
+ if (itemid == ITEM_ID_OTHER_SWITCH || itemid < ITEM_ID_XAXIS || itemid > ITEM_ID_SLIDER2)
+ return ITEM_CLASS_SWITCH;
+
+ /* standard mouse axes are relative */
+ else if (devclass == DEVICE_CLASS_MOUSE || itemid == ITEM_ID_OTHER_AXIS_RELATIVE)
+ return ITEM_CLASS_RELATIVE;
+
+ /* all other standard axes are absolute */
+ else
+ return ITEM_CLASS_ABSOLUTE;
+}
+
+
+/*-------------------------------------------------
+ input_item_update_value - update the value
+ of an input item
+-------------------------------------------------*/
+
+INLINE void input_item_update_value(input_device_item *item)
+{
+ item->current = (*item->getstate)(device_list[item->devclass].list[item->devindex].internal, item->internal);
+}
+
+
+/*-------------------------------------------------
+ code_pressed_memory_reset - reset the array
+ of memory for pressed switches
+-------------------------------------------------*/
+
+INLINE void code_pressed_memory_reset(void)
+{
+ int memnum;
+ for (memnum = 0; memnum < MAX_PRESSED_SWITCHES; memnum++)
+ code_pressed_memory[memnum] = INPUT_CODE_INVALID;
+}
+
+
+/*-------------------------------------------------
+ string_to_code - convert a string to a code
+ via table lookup
+-------------------------------------------------*/
+
+INLINE UINT32 string_to_code(const code_string_table *table, const char *string)
+{
+ /* find a matching string */
+ for ( ; table->code != ~0; table++)
+ if (strcmp(string, table->string) == 0)
+ return table->code;
+
+ /* on failure, return ~0 */
+ return ~0;
+}
+
+
+/*-------------------------------------------------
+ code_to_string - convert a code to a string
+ via table lookup
+-------------------------------------------------*/
+
+INLINE const char *code_to_string(const code_string_table *table, UINT32 code)
+{
+ /* find a matching code, or */
+ for ( ; table->code != ~0; table++)
+ if (table->code == code)
+ return table->string;
+
+ /* return the default string */
+ return table->string;
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_init - initialize the input lists
+-------------------------------------------------*/
+
+void input_init(running_machine *machine)
+{
+ joystick_map map;
+
+ /* reset the device lists */
+ memset(device_list, 0, sizeof(device_list));
+
+ /* reset code memory */
+ code_pressed_memory_reset();
+
+ /* request a per-frame callback for bookkeeping */
+ add_frame_callback(machine, input_frame);
+
+ /* read input enable options */
+ device_list[DEVICE_CLASS_KEYBOARD].enabled = TRUE;
+ device_list[DEVICE_CLASS_MOUSE].enabled = options_get_bool(mame_options(), OPTION_MOUSE);
+ device_list[DEVICE_CLASS_LIGHTGUN].enabled = options_get_bool(mame_options(), OPTION_LIGHTGUN);
+ device_list[DEVICE_CLASS_JOYSTICK].enabled = options_get_bool(mame_options(), OPTION_JOYSTICK);
+
+ /* read input device multi options */
+ device_list[DEVICE_CLASS_KEYBOARD].multi = options_get_bool(mame_options(), OPTION_MULTIKEYBOARD);
+ device_list[DEVICE_CLASS_MOUSE].multi = options_get_bool(mame_options(), OPTION_MULTIMOUSE);
+ device_list[DEVICE_CLASS_LIGHTGUN].multi = TRUE;
+ device_list[DEVICE_CLASS_JOYSTICK].multi = TRUE;
+
+ /* read other input options */
+ steadykey_enabled = options_get_bool(mame_options(), OPTION_STEADYKEY);
+ lightgun_reload_button = options_get_bool(mame_options(), OPTION_OFFSCREEN_RELOAD);
+ joystick_deadzone = (INT32)(options_get_float(mame_options(), OPTION_JOYSTICK_DEADZONE) * INPUT_ABSOLUTE_MAX);
+ joystick_saturation = (INT32)(options_get_float(mame_options(), OPTION_JOYSTICK_SATURATION) * INPUT_ABSOLUTE_MAX);
+
+ /* get the default joystick map */
+ joystick_map_default = options_get_string(mame_options(), OPTION_JOYSTICK_MAP);
+ if (joystick_map_default[0] == 0 || strcmp(joystick_map_default, "auto") == 0)
+ joystick_map_default = joystick_map_8way;
+ if (!joystick_map_parse(joystick_map_default, &map))
+ mame_printf_error("Invalid joystick map: %s\n", joystick_map_default);
+ else if (joystick_map_default != joystick_map_8way)
+ joystick_map_print("Input: Default joystick map", joystick_map_default, &map);
+}
+
+
+/*-------------------------------------------------
+ input_device_class_enable - enable or disable
+ a device class
+-------------------------------------------------*/
+
+void input_device_class_enable(input_device_class devclass, UINT8 enable)
+{
+ assert(devclass > DEVICE_CLASS_INVALID && devclass < DEVICE_CLASS_MAXIMUM);
+ device_list[devclass].enabled = enable;
+}
+
+
+/*-------------------------------------------------
+ input_enable_device_class - is a device class
+ enabled?
+-------------------------------------------------*/
+
+UINT8 input_device_class_enabled(input_device_class devclass)
+{
+ assert(devclass > DEVICE_CLASS_INVALID && devclass < DEVICE_CLASS_MAXIMUM);
+ return device_list[devclass].enabled;
+}
+
+
+/*-------------------------------------------------
+ input_device_set_joystick_map - set the
+ joystick map for a device
+-------------------------------------------------*/
+
+int input_device_set_joystick_map(int devindex, const char *mapstring)
+{
+ int startindex = devindex;
+ int stopindex = devindex;
+ joystick_map map;
+ int joynum;
+
+ /* parse the map */
+ if (!joystick_map_parse(mapstring, &map))
+ return FALSE;
+
+ /* devindex -1 means set the same for all */
+ if (devindex == -1)
+ {
+ startindex = 0;
+ stopindex = device_list[DEVICE_CLASS_JOYSTICK].count - 1;
+ joystick_map_print("Input: Changing default joystick map", mapstring, &map);
+ }
+
+ /* ignore if out of range */
+ else if (devindex >= device_list[DEVICE_CLASS_JOYSTICK].count)
+ return TRUE;
+
+ /* iterate over joysticks and set the map */
+ for (joynum = startindex; joynum <= stopindex; joynum++)
+ device_list[DEVICE_CLASS_JOYSTICK].list[joynum].joymap = map;
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ input_frame - per-frame callback for various
+ bookkeeping
+-------------------------------------------------*/
+
+static void input_frame(running_machine *machine)
+{
+ /* if steadykey is enabled, do processing here */
+ if (steadykey_enabled)
+ {
+ int devnum;
+
+ /* iterate over keyboards */
+ for (devnum = 0; devnum < device_list[DEVICE_CLASS_KEYBOARD].count; devnum++)
+ {
+ input_device *device = &device_list[DEVICE_CLASS_KEYBOARD].list[devnum];
+ input_item_id itemid;
+ int changed = FALSE;
+
+ /* update the state of all the keys and see if any changed state */
+ for (itemid = ITEM_ID_INVALID + 1; itemid <= device->maxitem; itemid++)
+ {
+ input_device_item *item = device->item[itemid];
+ if (item != NULL && item->itemclass == ITEM_CLASS_SWITCH)
+ {
+ input_item_update_value(item);
+ if ((item->current ^ item->oldkey) & 1)
+ {
+ changed = TRUE;
+
+ /* if the keypress was missed, turn it on for one frame */
+ if (((item->current | item->steadykey) & 1) == 0)
+ item->steadykey = 1;
+ }
+ }
+ }
+
+ /* if the keyboard state is stable, copy it over */
+ for (itemid = ITEM_ID_INVALID + 1; itemid <= device->maxitem; itemid++)
+ {
+ input_device_item *item = device->item[itemid];
+ if (item != NULL && item->itemclass == ITEM_CLASS_SWITCH)
+ {
+ if (!changed)
+ item->steadykey = item->current;
+ item->oldkey = item->current;
+ }
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ OSD CONFIGURATION AND ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_device_add - add a new input device
+-------------------------------------------------*/
+
+input_device *input_device_add(input_device_class devclass, const char *name, void *internal)
+{
+ input_device_list *devlist = &device_list[devclass];
+ input_device *device;
+
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call input_device_add at init time!");
+ assert(name != NULL);
+ assert(devclass != DEVICE_CLASS_INVALID && devclass < DEVICE_CLASS_MAXIMUM);
+
+ /* allocate a new device */
+ devlist->list = auto_realloc(devlist->list, (devlist->count + 1) * sizeof(devlist->list[0]));
+ device = &devlist->list[devlist->count++];
+ memset(device, 0, sizeof(*device));
+
+ /* fill in the data */
+ device->name = astring_cpyc(auto_astring_alloc(), name);
+ device->devclass = devclass;
+ device->devindex = devlist->count - 1;
+ device->internal = internal;
+
+ /* default to 8-way map for joysticks */
+ if (devclass == DEVICE_CLASS_JOYSTICK)
+ {
+ joystick_map_parse(joystick_map_default, &device->joymap);
+ device->lastmap = JOYSTICK_MAP_NEUTRAL;
+ }
+
+ mame_printf_verbose("Input: Adding %s #%d: %s\n", code_to_string(devclass_string_table, devclass), devlist->count, astring_c(device->name));
+ return device;
+}
+
+
+/*-------------------------------------------------
+ input_device_item_add - add a new item to an
+ input device
+-------------------------------------------------*/
+
+void input_device_item_add(input_device *device, const char *name, void *internal, input_item_id itemid, item_get_state_cb getstate)
+{
+ input_device_item *item;
+
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call input_device_item_add at init time!");
+ assert(name != NULL);
+ assert(itemid > ITEM_ID_INVALID && itemid < ITEM_ID_MAXIMUM);
+ assert(getstate != NULL);
+
+ /* if we have a generic ID, pick a new internal one */
+ if (itemid >= ITEM_ID_OTHER_SWITCH && itemid <= ITEM_ID_OTHER_AXIS_RELATIVE)
+ for (itemid = ITEM_ID_MAXIMUM + 1; itemid <= ITEM_ID_ABSOLUTE_MAXIMUM; itemid++)
+ if (device->item[itemid] == NULL)
+ break;
+ assert(itemid <= ITEM_ID_ABSOLUTE_MAXIMUM);
+
+ /* make sure we don't have any overlap */
+ assert(device->item[itemid] == NULL);
+
+ /* allocate a new item and copy data into it */
+ item = auto_malloc(sizeof(*item));
+ memset(item, 0, sizeof(*item));
+ device->item[itemid] = item;
+ device->maxitem = MAX(device->maxitem, itemid);
+
+ /* copy in the data passed in from the item list */
+ item->devclass = device->devclass;
+ item->devindex = device->devindex;
+ item->name = astring_cpyc(auto_astring_alloc(), name);
+ item->token = NULL;
+ item->internal = internal;
+ item->itemclass = input_item_standard_class(device->devclass, itemid);
+ item->itemid = itemid;
+ item->getstate = getstate;
+
+ /* if we're custom, create a tokenized name */
+ if (itemid > ITEM_ID_MAXIMUM)
+ {
+ /* copy the item name, removing spaces/underscores and making all caps */
+ item->token = astring_toupper(astring_cpyc(auto_astring_alloc(), name));
+ astring_delchr(item->token, ' ');
+ astring_delchr(item->token, '_');
+ }
+
+ /* otherwise, make sure we have a valid standard token */
+ else
+ {
+ assert(code_to_string(itemid_token_table, itemid) != NULL);
+ }
+}
+
+
+
+/***************************************************************************
+ STATE QUERIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_code_value - return the value of a
+ given input code
+-------------------------------------------------*/
+
+INT32 input_code_value(input_code code)
+{
+ input_device_class devclass = INPUT_CODE_DEVCLASS(code);
+ int startindex = INPUT_CODE_DEVINDEX(code);
+ int stopindex = startindex;
+ INT32 result = 0;
+ int curindex;
+
+ profiler_mark(PROFILER_INPUT);
+
+ /* return 0 for any disabled or invalid device classes */
+ if (devclass <= DEVICE_CLASS_INVALID || devclass >= DEVICE_CLASS_MAXIMUM || !device_list[devclass].enabled)
+ goto exit;
+ if (startindex >= device_list[devclass].count)
+ goto exit;
+
+ /* if this is not a multi device, only return data for item 0 */
+ if (!device_list[devclass].multi)
+ {
+ if (startindex != 0)
+ goto exit;
+
+ /* otherwise, iterate over all */
+ startindex = 0;
+ stopindex = device_list[devclass].count - 1;
+ }
+
+ /* iterate over all indices */
+ for (curindex = startindex; curindex <= stopindex; curindex++)
+ {
+ /* lookup the item for the appropriate index */
+ input_device_item *item = input_code_item(INPUT_CODE_SET_DEVINDEX(code, curindex));
+ if (item == NULL)
+ continue;
+
+ /* update the value of this item */
+ input_item_update_value(item);
+
+ /* process items according to their native type */
+ switch (item->itemclass)
+ {
+ case ITEM_CLASS_ABSOLUTE:
+ result = convert_absolute_value(code, item);
+ break;
+
+ case ITEM_CLASS_RELATIVE:
+ result += convert_relative_value(code, item);
+ break;
+
+ case ITEM_CLASS_SWITCH:
+ result |= convert_switch_value(code, item);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+exit:
+ profiler_mark(PROFILER_END);
+ return result;
+}
+
+
+/*-------------------------------------------------
+ input_code_pressed - return non-zero if a
+ given input code has been pressed
+-------------------------------------------------*/
+
+int input_code_pressed(input_code code)
+{
+ return (input_code_value(code) != 0);
+}
+
+
+/*-------------------------------------------------
+ input_code_pressed_once - return non-zero if a
+ given input code has transitioned from off to
+ on since the last call
+-------------------------------------------------*/
+
+int input_code_pressed_once(input_code code)
+{
+ int curvalue = input_code_pressed(code);
+ int memnum, empty = -1;
+
+ /* look for the code in the memory */
+ for (memnum = 0; memnum < MAX_PRESSED_SWITCHES; memnum++)
+ {
+ /* were we previous pressed on the last time through here? */
+ if (code_pressed_memory[memnum] == code)
+ {
+ /* if no longer pressed, clear entry */
+ if (!curvalue)
+ code_pressed_memory[memnum] = INPUT_CODE_INVALID;
+
+ /* always return 0 */
+ return 0;
+ }
+
+ /* remember the first empty entry */
+ if (empty == -1 && code_pressed_memory[memnum] == INPUT_CODE_INVALID)
+ empty = memnum;
+ }
+
+ /* if we get here, we were not previously pressed; if still not pressed, return 0 */
+ if (!curvalue)
+ return 0;
+
+ /* otherwise, add ourself to the memory and return 1 */
+ assert(empty != -1);
+ if (empty != -1)
+ code_pressed_memory[empty] = code;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ input_code_poll_switches - poll for any input
+-------------------------------------------------*/
+
+input_code input_code_poll_switches(int reset)
+{
+ input_device_class devclass;
+
+ /* if resetting memory, do it now */
+ if (reset)
+ code_pressed_memory_reset();
+
+ /* iterate over device classes and devices */
+ for (devclass = DEVICE_CLASS_INVALID + 1; devclass < DEVICE_CLASS_MAXIMUM; devclass++)
+ {
+ input_device_list *devlist = &device_list[devclass];
+ int devnum;
+
+ /* iterate over devices within each class */
+ for (devnum = 0; devnum < devlist->count; devnum++)
+ {
+ input_device *device = &devlist->list[devnum];
+ input_item_id itemid;
+
+ /* iterate over items within each device */
+ for (itemid = ITEM_ID_INVALID + 1; itemid <= device->maxitem; itemid++)
+ {
+ input_device_item *item = device->item[itemid];
+ if (item != NULL)
+ {
+ input_code code = device_item_to_code(device, itemid);
+
+ /* if the item is natively a switch, poll it */
+ if (item->itemclass == ITEM_CLASS_SWITCH)
+ {
+ if (input_code_pressed_once(code))
+ return code;
+ }
+
+ /* otherwise, poll axes digitally */
+ else
+ {
+ code = INPUT_CODE_SET_ITEMCLASS(code, ITEM_CLASS_SWITCH);
+
+ /* if this is a joystick X axis, check with left/right modifiers */
+ if (devclass == DEVICE_CLASS_JOYSTICK && INPUT_CODE_ITEMID(code) == ITEM_ID_XAXIS)
+ {
+ code = INPUT_CODE_SET_MODIFIER(code, ITEM_MODIFIER_LEFT);
+ if (input_code_pressed_once(code))
+ return code;
+ code = INPUT_CODE_SET_MODIFIER(code, ITEM_MODIFIER_RIGHT);
+ if (input_code_pressed_once(code))
+ return code;
+ }
+
+ /* if this is a joystick Y axis, check with up/down modifiers */
+ else if (devclass == DEVICE_CLASS_JOYSTICK && INPUT_CODE_ITEMID(code) == ITEM_ID_YAXIS)
+ {
+ code = INPUT_CODE_SET_MODIFIER(code, ITEM_MODIFIER_UP);
+ if (input_code_pressed_once(code))
+ return code;
+ code = INPUT_CODE_SET_MODIFIER(code, ITEM_MODIFIER_DOWN);
+ if (input_code_pressed_once(code))
+ return code;
+ }
+
+ /* any other axis, check with pos/neg modifiers */
+ else
+ {
+ code = INPUT_CODE_SET_MODIFIER(code, ITEM_MODIFIER_POS);
+ if (input_code_pressed_once(code))
+ return code;
+ code = INPUT_CODE_SET_MODIFIER(code, ITEM_MODIFIER_NEG);
+ if (input_code_pressed_once(code))
+ return code;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* if nothing, return an invalid code */
+ return INPUT_CODE_INVALID;
+}
+
+
+/*-------------------------------------------------
+ input_code_poll_axes - poll for any input
+-------------------------------------------------*/
+
+input_code input_code_poll_axes(int reset)
+{
+ input_device_class devclass;
+
+ /* iterate over device classes and devices */
+ for (devclass = DEVICE_CLASS_INVALID + 1; devclass < DEVICE_CLASS_MAXIMUM; devclass++)
+ {
+ input_device_list *devlist = &device_list[devclass];
+ int devnum;
+
+ /* iterate over devices within each class */
+ for (devnum = 0; devnum < devlist->count; devnum++)
+ {
+ input_device *device = &devlist->list[devnum];
+ input_item_id itemid;
+
+ /* iterate over items within each device */
+ for (itemid = ITEM_ID_INVALID + 1; itemid <= device->maxitem; itemid++)
+ {
+ input_device_item *item = device->item[itemid];
+ if (item != NULL)
+ {
+ input_code code = device_item_to_code(device, itemid);
+ INT32 curval, diff;
+
+ /* skip any switches or already-reported axes */
+ if (item->itemclass == ITEM_CLASS_SWITCH)
+ continue;
+
+ /* poll the current value and reset the memory */
+ curval = input_code_value(code);
+ if (reset)
+ item->memory = curval;
+
+ /* if we've already reported this one, don't bother */
+ if (item->memory == INVALID_AXIS_VALUE)
+ continue;
+
+ /* compute the diff against memory */
+ diff = curval - item->memory;
+ if (diff < 0)
+ diff = -diff;
+
+ /* for absolute axes, look for 25% of maximum */
+ if (item->itemclass == ITEM_CLASS_ABSOLUTE && diff > (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN) / 4)
+ {
+ item->memory = INVALID_AXIS_VALUE;
+ return code;
+ }
+
+ /* for relative axes, look for ~20 pixels movement */
+ if (item->itemclass == ITEM_CLASS_RELATIVE && diff > 20 * INPUT_RELATIVE_PER_PIXEL)
+ {
+ item->memory = INVALID_AXIS_VALUE;
+ return code;
+ }
+ }
+ }
+ }
+ }
+
+ /* if nothing, return an invalid code */
+ return INPUT_CODE_INVALID;
+}
+
+
+
+/***************************************************************************
+ STRINGS AND TOKENIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_code_name - convert an input code into
+ a friendly name
+-------------------------------------------------*/
+
+astring *input_code_name(astring *string, input_code code)
+{
+ input_device_item *item = input_code_item(code);
+ const char *devclass;
+ const char *devcode;
+ const char *modifier;
+ char devindex[10];
+
+ /* if nothing there, return an empty string */
+ if (item == NULL)
+ return astring_reset(string);
+
+ /* determine the devclass part */
+ devclass = code_to_string(devclass_string_table, INPUT_CODE_DEVCLASS(code));
+
+ /* determine the devindex part */
+ sprintf(devindex, "%d", INPUT_CODE_DEVINDEX(code) + 1);
+
+ /* if we're unifying all devices, don't display a number */
+ if (!device_list[INPUT_CODE_DEVCLASS(code)].multi)
+ devindex[0] = 0;
+
+ /* keyboard 0 doesn't show a class or index if it is the only one */
+ if (item->devclass == DEVICE_CLASS_KEYBOARD && device_list[DEVICE_CLASS_KEYBOARD].count == 1)
+ {
+ devclass = "";
+ devindex[0] = 0;
+ }
+
+ /* devcode part comes from the item name */
+ devcode = astring_c(item->name);
+
+ /* determine the modifier part */
+ modifier = code_to_string(modifier_string_table, INPUT_CODE_MODIFIER(code));
+
+ /* devcode is redundant with joystick switch left/right/up/down */
+ if (item->devclass == DEVICE_CLASS_JOYSTICK && INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_SWITCH)
+ if (INPUT_CODE_MODIFIER(code) >= ITEM_MODIFIER_LEFT && INPUT_CODE_MODIFIER(code) <= ITEM_MODIFIER_DOWN)
+ devcode = "";
+
+ /* concatenate the strings */
+ astring_cpyc(string, devclass);
+ if (devindex[0] != 0)
+ astring_catc(astring_catc(string, " "), devindex);
+ if (devcode[0] != 0)
+ astring_catc(astring_catc(string, " "), devcode);
+ if (modifier[0] != 0)
+ astring_catc(astring_catc(string, " "), modifier);
+
+ /* delete any leading spaces */
+ return astring_trimspace(string);
+}
+
+
+/*-------------------------------------------------
+ input_code_to_token - create a token for
+ a given code
+-------------------------------------------------*/
+
+astring *input_code_to_token(astring *string, input_code code)
+{
+ input_device_item *item = input_code_item(code);
+ const char *devclass;
+ const char *devcode;
+ const char *itemclass;
+ const char *modifier;
+ char devindex[10];
+
+ /* determine the devclass part */
+ devclass = code_to_string(devclass_token_table, INPUT_CODE_DEVCLASS(code));
+
+ /* determine the devindex part; keyboard 0 doesn't show an index */
+ sprintf(devindex, "%d", INPUT_CODE_DEVINDEX(code) + 1);
+ if (INPUT_CODE_DEVCLASS(code) == DEVICE_CLASS_KEYBOARD && INPUT_CODE_DEVINDEX(code) == 0)
+ devindex[0] = 0;
+
+ /* determine the itemid part; look up in the table if we don't have a token */
+ if (item != NULL && item->token != NULL)
+ devcode = astring_c(item->token);
+ else
+ devcode = code_to_string(itemid_token_table, INPUT_CODE_ITEMID(code));
+ assert(devcode != NULL);
+
+ /* determine the modifier part */
+ modifier = code_to_string(modifier_token_table, INPUT_CODE_MODIFIER(code));
+
+ /* determine the itemclass part; if we match the native class, we don't include this */
+ if (item == NULL || item->itemclass == INPUT_CODE_ITEMCLASS(code))
+ itemclass = "";
+ else
+ itemclass = code_to_string(itemclass_token_table, INPUT_CODE_ITEMCLASS(code));
+
+ /* concatenate the strings */
+ astring_cpyc(string, devclass);
+ if (devindex[0] != 0)
+ astring_catc(astring_catc(string, "_"), devindex);
+ if (devcode[0] != 0)
+ astring_catc(astring_catc(string, "_"), devcode);
+ if (modifier[0] != 0)
+ astring_catc(astring_catc(string, "_"), modifier);
+ if (itemclass[0] != 0)
+ astring_catc(astring_catc(string, "_"), itemclass);
+ return string;
+}
+
+
+/*-------------------------------------------------
+ input_code_from_token - extract an input
+ code from a token
+-------------------------------------------------*/
+
+input_code input_code_from_token(const char *_token)
+{
+ UINT32 devclass, itemid, devindex, modifier, standard;
+ UINT32 itemclass = ITEM_CLASS_INVALID;
+ input_code code = INPUT_CODE_INVALID;
+ astring *token[6] = { NULL };
+ int numtokens, curtok;
+
+ /* copy the token and break it into pieces */
+ for (numtokens = 0; numtokens < ARRAY_LENGTH(token); )
+ {
+ /* make a token up to the next underscore */
+ char *score = strchr(_token, '_');
+ token[numtokens++] = astring_dupch(_token, (score == NULL) ? strlen(_token) : (score - _token));
+
+ /* if we hit the end, we're done, else advance our pointer */
+ if (score == NULL)
+ break;
+ _token = score + 1;
+ }
+
+ /* first token should be the devclass */
+ curtok = 0;
+ devclass = string_to_code(devclass_token_table, astring_c(token[curtok++]));
+ if (devclass == ~0)
+ goto exit;
+
+ /* second token might be index; look for number */
+ devindex = 0;
+ if (numtokens > 2 && sscanf(astring_c(token[curtok]), "%d", &devindex) == 1)
+ {
+ curtok++;
+ devindex--;
+ }
+ if (curtok >= numtokens)
+ goto exit;
+
+ /* next token is the item ID */
+ itemid = string_to_code(itemid_token_table, astring_c(token[curtok]));
+ standard = (itemid != ~0);
+
+ /* if we're a standard code, default the itemclass based on it */
+ if (standard)
+ itemclass = input_item_standard_class(devclass, itemid);
+
+ /* otherwise, keep parsing */
+ else
+ {
+ input_device *device;
+
+ /* if this is an invalid device, we have nothing to look up */
+ if (devindex >= device_list[devclass].count)
+ goto exit;
+ device = &device_list[devclass].list[devindex];
+
+ /* if not a standard code, look it up in the device specific codes */
+ for (itemid = ITEM_ID_INVALID + 1; itemid <= device->maxitem; itemid++)
+ {
+ input_device_item *item = device->item[itemid];
+ if (item != NULL && item->token != NULL && astring_cmp(token[curtok], item->token) == 0)
+ {
+ /* take the itemclass from the item */
+ itemclass = item->itemclass;
+ break;
+ }
+ }
+
+ /* bail on fail */
+ if (itemid > device->maxitem)
+ goto exit;
+ }
+ curtok++;
+
+ /* if we have another token, it is probably a modifier */
+ modifier = ITEM_MODIFIER_NONE;
+ if (curtok < numtokens)
+ {
+ modifier = string_to_code(modifier_token_table, astring_c(token[curtok]));
+ if (modifier != ~0)
+ curtok++;
+ else
+ modifier = ITEM_MODIFIER_NONE;
+ }
+
+ /* if we have another token, it is the item class */
+ if (curtok < numtokens)
+ {
+ UINT32 temp = string_to_code(itemclass_token_table, astring_c(token[curtok]));
+ if (temp != ~0)
+ {
+ curtok++;
+ itemclass = temp;
+ }
+ }
+
+ /* we should have consumed all tokens */
+ if (curtok != numtokens)
+ goto exit;
+
+ /* assemble the final code */
+ code = INPUT_CODE(devclass, devindex, itemclass, modifier, itemid);
+
+exit:
+ for (curtok = 0; curtok < ARRAY_LENGTH(token); curtok++)
+ if (token[curtok] != NULL)
+ astring_free(token[curtok]);
+ return code;
+}
+
+
+
+/***************************************************************************
+ INTERNAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_code_item - get a pointer to the item
+ from the code
+-------------------------------------------------*/
+
+static input_device_item *input_code_item(input_code code)
+{
+ input_device *device = input_code_device(code);
+ input_item_id itemid;
+
+ /* if no device, we fail */
+ if (device == NULL)
+ return NULL;
+
+ /* if the devcode is in range, return a pointer to the item */
+ itemid = INPUT_CODE_ITEMID(code);
+ if (itemid < ARRAY_LENGTH(device->item))
+ return device->item[itemid];
+
+ /* otherwise fail with NULL */
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ convert_absolute_value - convert an absolute
+ value into the class specified by code
+-------------------------------------------------*/
+
+static INT32 convert_absolute_value(input_code code, input_device_item *item)
+{
+ /* make sure values are valid */
+ assert(item->current >= INPUT_ABSOLUTE_MIN && item->current <= INPUT_ABSOLUTE_MAX);
+
+ /* relative value conversion not supported */
+ if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_RELATIVE)
+ return 0;
+
+ /* if we want the absolute value, process it according to the modifier field */
+ else if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_ABSOLUTE)
+ {
+ input_item_modifier modifier = INPUT_CODE_MODIFIER(code);
+ INT32 result = apply_deadzone_and_saturation(code, item->current);
+
+ /* if we're doing a lightgun reload hack, override the value */
+ if (lightgun_reload_button && item->devclass == DEVICE_CLASS_LIGHTGUN)
+ {
+ input_device_item *button2_item = device_list[item->devclass].list[item->devindex].item[ITEM_ID_BUTTON2];
+ if (button2_item != NULL)
+ {
+ /* if it is pressed, return (min,max) */
+ input_item_update_value(button2_item);
+ if (button2_item->current)
+ result = (INPUT_CODE_ITEMID(code) == ITEM_ID_XAXIS) ? INPUT_ABSOLUTE_MIN : INPUT_ABSOLUTE_MAX;
+ }
+ }
+
+ /* standard axis: apply deadzone and saturation */
+ if (modifier == ITEM_MODIFIER_NONE)
+ return result;
+
+ /* positive/negative: scale to full axis */
+ else if (modifier == ITEM_MODIFIER_POS)
+ return MAX(result, 0) * 2 + INPUT_ABSOLUTE_MIN;
+ else if (modifier == ITEM_MODIFIER_NEG)
+ return MAX(-result, 0) * 2 + INPUT_ABSOLUTE_MIN;
+ }
+
+ /* if we want a switch value, process it according to the modifier field */
+ else if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_SWITCH)
+ {
+ input_item_modifier modifier = INPUT_CODE_MODIFIER(code);
+
+ /* left/right/up/down: if this is a joystick, fetch the paired X/Y axis values and convert */
+ if (modifier >= ITEM_MODIFIER_LEFT && modifier <= ITEM_MODIFIER_DOWN && item->devclass == DEVICE_CLASS_JOYSTICK)
+ {
+ input_device *device = &device_list[item->devclass].list[item->devindex];
+ input_device_item *xaxis_item = device->item[ITEM_ID_XAXIS];
+ input_device_item *yaxis_item = device->item[ITEM_ID_YAXIS];
+ if (xaxis_item != NULL && yaxis_item != NULL)
+ {
+ INT32 xaxisval, yaxisval;
+ UINT8 mapval;
+
+ /* determine which item we didn't update, and update it */
+ assert(item == xaxis_item || item == yaxis_item);
+ input_item_update_value((item == xaxis_item) ? yaxis_item : xaxis_item);
+
+ /* now map the X and Y axes to a 9x9 grid */
+ xaxisval = ((xaxis_item->current - INPUT_ABSOLUTE_MIN) * 9) / (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN + 1);
+ yaxisval = ((yaxis_item->current - INPUT_ABSOLUTE_MIN) * 9) / (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN + 1);
+ mapval = device->joymap.map[yaxisval][xaxisval];
+
+ /* handle stickiness */
+ if (mapval == JOYSTICK_MAP_STICKY)
+ mapval = device->lastmap;
+ else
+ device->lastmap = mapval;
+
+ /* return based on whether the appropriate bit is set */
+ return (mapval >> (modifier - ITEM_MODIFIER_LEFT)) & 1;
+ }
+ }
+
+ /* positive/negative: TRUE if past the deadzone in either direction */
+ if (modifier == ITEM_MODIFIER_POS || modifier == ITEM_MODIFIER_RIGHT || modifier == ITEM_MODIFIER_DOWN)
+ return (apply_deadzone_and_saturation(code, item->current) > 0);
+ else if (modifier == ITEM_MODIFIER_NEG || modifier == ITEM_MODIFIER_LEFT || modifier == ITEM_MODIFIER_UP)
+ return (apply_deadzone_and_saturation(code, item->current) < 0);
+ }
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ convert_relative_value - convert a relative
+ value into the class specified by code
+-------------------------------------------------*/
+
+static INT32 convert_relative_value(input_code code, input_device_item *item)
+{
+ /* if we want relative values, take it as-is */
+ if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_RELATIVE)
+ return item->current;
+
+ /* absolute value conversion not supported */
+ else if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_ABSOLUTE)
+ return 0;
+
+ /* if we want a switch value, process it according to the modifier field */
+ else if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_SWITCH)
+ {
+ input_item_modifier modifier = INPUT_CODE_MODIFIER(code);
+
+ /* positive/negative: TRUE if non-zero in either direction */
+ if (modifier == ITEM_MODIFIER_POS || modifier == ITEM_MODIFIER_RIGHT || modifier == ITEM_MODIFIER_DOWN)
+ return (item->current > 0);
+ else if (modifier == ITEM_MODIFIER_NEG || modifier == ITEM_MODIFIER_LEFT || modifier == ITEM_MODIFIER_UP)
+ return (item->current < 0);
+ }
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ convert_switch_value - convert a switch
+ value into the class specified by code
+-------------------------------------------------*/
+
+static INT32 convert_switch_value(input_code code, input_device_item *item)
+{
+ /* only a switch is supported */
+ if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_SWITCH)
+ {
+ /* if we're doing a lightgun reload hack, button 1 and 2 operate differently */
+ if (lightgun_reload_button && item->devclass == DEVICE_CLASS_LIGHTGUN)
+ {
+ /* button 1 is pressed if either button 1 or 2 are active */
+ if (INPUT_CODE_ITEMID(code) == ITEM_ID_BUTTON1)
+ {
+ input_device_item *button2_item = device_list[item->devclass].list[item->devindex].item[ITEM_ID_BUTTON2];
+ if (button2_item != NULL)
+ {
+ input_item_update_value(button2_item);
+ return item->current | button2_item->current;
+ }
+ }
+
+ /* button 2 is never officially pressed */
+ if (INPUT_CODE_ITEMID(code) == ITEM_ID_BUTTON2)
+ return 0;
+ }
+
+ /* steadykey for keyboards */
+ if (steadykey_enabled && item->devclass == DEVICE_CLASS_KEYBOARD)
+ return item->steadykey;
+
+ /* everything else is just the current value as-is */
+ return item->current;
+ }
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ apply_deadzone_and_saturation - apply global
+ deadzone and saturation parameters to an
+ absolute value
+-------------------------------------------------*/
+
+static INT32 apply_deadzone_and_saturation(input_code code, INT32 result)
+{
+ int negative = FALSE;
+
+ /* ignore if not a joystick */
+ if (INPUT_CODE_DEVCLASS(code) != DEVICE_CLASS_JOYSTICK)
+ return result;
+
+ /* properties are symmetric */
+ if (result < 0)
+ {
+ negative = TRUE;
+ result = -result;
+ }
+
+ /* if in the deadzone, return 0 */
+ if (result < joystick_deadzone)
+ result = 0;
+
+ /* if saturated, return the max */
+ else if (result > joystick_saturation)
+ result = INPUT_ABSOLUTE_MAX;
+
+ /* otherwise, scale */
+ else
+ result = (INT64)(result - joystick_deadzone) * (INT64)INPUT_ABSOLUTE_MAX / (INT64)(joystick_saturation - joystick_deadzone);
+
+ /* apply sign and return */
+ return negative ? -result : result;
+}
+
+
+/*-------------------------------------------------
+ joystick_map_parse - parse a string into
+ a joystick map
+-------------------------------------------------*/
+
+static int joystick_map_parse(const char *mapstring, joystick_map *map)
+{
+ int rownum, colnum;
+
+ /* iterate over rows */
+ for (rownum = 0; rownum < 9; rownum++)
+ {
+ /* if we're done, copy from another row */
+ if (*mapstring == 0 || *mapstring == '.')
+ {
+ int symmetric = (rownum >= 5 && *mapstring == 0);
+ const UINT8 *srcrow = &map->map[symmetric ? (8 - rownum) : (rownum - 1)][0];
+
+ /* if this is row 0, we don't have a source row -- invalid */
+ if (rownum == 0)
+ return FALSE;
+
+ /* copy from the srcrow, applying up/down symmetry if in the bottom half */
+ for (colnum = 0; colnum < 9; colnum++)
+ {
+ UINT8 val = srcrow[colnum];
+ if (symmetric)
+ val = (val & (JOYSTICK_MAP_LEFT | JOYSTICK_MAP_RIGHT)) | ((val & JOYSTICK_MAP_UP) << 1) | ((val & JOYSTICK_MAP_DOWN) >> 1);
+ map->map[rownum][colnum] = val;
+ }
+ }
+
+ /* otherwise, parse this column */
+ else
+ {
+ for (colnum = 0; colnum < 9; colnum++)
+ {
+ /* if we're at the end of row, copy previous to the middle, then apply left/right symmetry */
+ if (*mapstring == 0 || *mapstring == '.')
+ {
+ int symmetric = (colnum >= 5);
+ UINT8 val = map->map[rownum][symmetric ? (8 - colnum) : (colnum - 1)];
+ if (symmetric)
+ val = (val & (JOYSTICK_MAP_UP | JOYSTICK_MAP_DOWN)) | ((val & JOYSTICK_MAP_LEFT) << 1) | ((val & JOYSTICK_MAP_RIGHT) >> 1);
+ map->map[rownum][colnum] = val;
+ }
+
+ /* otherwise, convert the character to its value */
+ else
+ {
+ static const UINT8 charmap[] =
+ {
+ JOYSTICK_MAP_UP | JOYSTICK_MAP_LEFT,
+ JOYSTICK_MAP_UP,
+ JOYSTICK_MAP_UP | JOYSTICK_MAP_RIGHT,
+ JOYSTICK_MAP_LEFT,
+ JOYSTICK_MAP_NEUTRAL,
+ JOYSTICK_MAP_RIGHT,
+ JOYSTICK_MAP_DOWN | JOYSTICK_MAP_LEFT,
+ JOYSTICK_MAP_DOWN,
+ JOYSTICK_MAP_DOWN | JOYSTICK_MAP_RIGHT,
+ JOYSTICK_MAP_STICKY
+ };
+ static const char *validchars = "789456123s";
+ const char *ptr = strchr(validchars, *mapstring++);
+
+ /* invalid characters exit immediately */
+ if (ptr == NULL)
+ return FALSE;
+ map->map[rownum][colnum] = charmap[ptr - validchars];
+ }
+ }
+ }
+
+ /* if we ended with a period, advance to the next row */
+ if (*mapstring == '.')
+ mapstring++;
+ }
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ joystick_map_print - print a joystick map via
+ the verbose output
+-------------------------------------------------*/
+
+static void joystick_map_print(const char *header, const char *origstring, const joystick_map *map)
+{
+ int rownum, colnum;
+
+ mame_printf_verbose("%s = %s\n", header, origstring);
+ for (rownum = 0; rownum < 9; rownum++)
+ {
+ mame_printf_verbose(" ");
+ for (colnum = 0; colnum < 9; colnum++)
+ switch (map->map[rownum][colnum])
+ {
+ case JOYSTICK_MAP_UP | JOYSTICK_MAP_LEFT: mame_printf_verbose("7"); break;
+ case JOYSTICK_MAP_UP: mame_printf_verbose("8"); break;
+ case JOYSTICK_MAP_UP | JOYSTICK_MAP_RIGHT: mame_printf_verbose("9"); break;
+ case JOYSTICK_MAP_LEFT: mame_printf_verbose("4"); break;
+ case JOYSTICK_MAP_NEUTRAL: mame_printf_verbose("5"); break;
+ case JOYSTICK_MAP_RIGHT: mame_printf_verbose("6"); break;
+ case JOYSTICK_MAP_DOWN | JOYSTICK_MAP_LEFT: mame_printf_verbose("1"); break;
+ case JOYSTICK_MAP_DOWN: mame_printf_verbose("2"); break;
+ case JOYSTICK_MAP_DOWN | JOYSTICK_MAP_RIGHT:mame_printf_verbose("3"); break;
+ case JOYSTICK_MAP_STICKY: mame_printf_verbose("s"); break;
+ default: mame_printf_verbose("?"); break;
+ }
+
+ mame_printf_verbose("\n");
+ }
+}
diff --git a/src/emu/input.h b/src/emu/input.h
new file mode 100644
index 00000000000..4f2c82086d8
--- /dev/null
+++ b/src/emu/input.h
@@ -0,0 +1,555 @@
+/***************************************************************************
+
+ input.h
+
+ Handle input from the user.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __INPUT_H__
+#define __INPUT_H__
+
+#include "mamecore.h"
+#include "astring.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* make sure RELATIVE and ABSOLUTE aren't defined elsewhere; otherwise it fouls up our macros */
+#undef RELATIVE
+#undef ABSOLUTE
+
+/* relative devices return ~512 units per onscreen pixel */
+#define INPUT_RELATIVE_PER_PIXEL 512
+
+/* absolute devices return values between -65536 and +65536 */
+#define INPUT_ABSOLUTE_MIN -65536
+#define INPUT_ABSOLUTE_MAX 65536
+
+/* flags in the top 4 bits of the input code */
+#define INPUT_CODE_INTERNAL (1 << 31)
+
+/* extract components of the input code */
+#define INPUT_CODE_IS_INTERNAL(c) (((c) & INPUT_CODE_INTERNAL) != 0)
+#define INPUT_CODE_DEVCLASS(c) ((input_device_class)(((c) >> 24) & 0x0f))
+#define INPUT_CODE_DEVINDEX(c) ((UINT8)(((c) >> 20) & 0x0f))
+#define INPUT_CODE_ITEMCLASS(c) ((input_item_class)(((c) >> 16) & 0x0f))
+#define INPUT_CODE_MODIFIER(c) ((input_item_modifier)(((c) >> 12) & 0x0f))
+#define INPUT_CODE_ITEMID(c) ((int)((c) & 0xfff))
+
+/* build or modify input codes */
+#define INPUT_CODE(d,x,i,m,o) ((((d) & 0x0f) << 24) | (((x) & 0x0f) << 20) | (((i) & 0x0f) << 16) | (((m) & 0x0f) << 12) | ((o) & 0xfff))
+#define INPUT_CODE_SET_DEVINDEX(c,x) (((c) & ~(0xf << 20)) | (((x) & 0x0f) << 20))
+#define INPUT_CODE_SET_ITEMCLASS(c,i) (((c) & ~(0xf << 16)) | (((i) & 0x0f) << 16))
+#define INPUT_CODE_SET_MODIFIER(c,m) (((c) & ~(0xf << 12)) | (((m) & 0x0f) << 12))
+#define INPUT_CODE_SET_ITEMID(c,d) (((c) & ~0xfff) | ((d) & 0xfff))
+
+/* standard code building */
+#define STANDARD_CODE(d,x,i,m,o) (INPUT_CODE(DEVICE_CLASS_##d, x, ITEM_CLASS_##i, ITEM_MODIFIER_##m, ITEM_ID_##o))
+#define INTERNAL_CODE(x) (INPUT_CODE_INTERNAL | ((x) & 0xfff))
+#define INPUT_CODE_INVALID STANDARD_CODE(INVALID, 0, INVALID, NONE, INVALID)
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* input device classes */
+enum _input_device_class
+{
+ DEVICE_CLASS_INVALID,
+ DEVICE_CLASS_KEYBOARD,
+ DEVICE_CLASS_MOUSE,
+ DEVICE_CLASS_LIGHTGUN,
+ DEVICE_CLASS_JOYSTICK,
+ DEVICE_CLASS_MAXIMUM
+};
+typedef enum _input_device_class input_device_class;
+
+
+/* input item classes */
+enum _input_item_class
+{
+ ITEM_CLASS_INVALID,
+ ITEM_CLASS_SWITCH,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_CLASS_RELATIVE,
+ ITEM_CLASS_MAXIMUM
+};
+typedef enum _input_item_class input_item_class;
+
+
+/* input item modifiers */
+enum _input_item_modifier
+{
+ ITEM_MODIFIER_NONE,
+ ITEM_MODIFIER_POS,
+ ITEM_MODIFIER_NEG,
+ ITEM_MODIFIER_LEFT,
+ ITEM_MODIFIER_RIGHT,
+ ITEM_MODIFIER_UP,
+ ITEM_MODIFIER_DOWN,
+ ITEM_MODIFIER_MAXIMUM
+};
+typedef enum _input_item_modifier input_item_modifier;
+
+
+/* standard item IDs */
+enum _input_item_id
+{
+ ITEM_ID_INVALID,
+
+ /* standard keyboard IDs */
+ ITEM_ID_A,
+ ITEM_ID_B,
+ ITEM_ID_C,
+ ITEM_ID_D,
+ ITEM_ID_E,
+ ITEM_ID_F,
+ ITEM_ID_G,
+ ITEM_ID_H,
+ ITEM_ID_I,
+ ITEM_ID_J,
+ ITEM_ID_K,
+ ITEM_ID_L,
+ ITEM_ID_M,
+ ITEM_ID_N,
+ ITEM_ID_O,
+ ITEM_ID_P,
+ ITEM_ID_Q,
+ ITEM_ID_R,
+ ITEM_ID_S,
+ ITEM_ID_T,
+ ITEM_ID_U,
+ ITEM_ID_V,
+ ITEM_ID_W,
+ ITEM_ID_X,
+ ITEM_ID_Y,
+ ITEM_ID_Z,
+ ITEM_ID_0,
+ ITEM_ID_1,
+ ITEM_ID_2,
+ ITEM_ID_3,
+ ITEM_ID_4,
+ ITEM_ID_5,
+ ITEM_ID_6,
+ ITEM_ID_7,
+ ITEM_ID_8,
+ ITEM_ID_9,
+ ITEM_ID_F1,
+ ITEM_ID_F2,
+ ITEM_ID_F3,
+ ITEM_ID_F4,
+ ITEM_ID_F5,
+ ITEM_ID_F6,
+ ITEM_ID_F7,
+ ITEM_ID_F8,
+ ITEM_ID_F9,
+ ITEM_ID_F10,
+ ITEM_ID_F11,
+ ITEM_ID_F12,
+ ITEM_ID_F13,
+ ITEM_ID_F14,
+ ITEM_ID_F15,
+ ITEM_ID_ESC,
+ ITEM_ID_TILDE,
+ ITEM_ID_MINUS,
+ ITEM_ID_EQUALS,
+ ITEM_ID_BACKSPACE,
+ ITEM_ID_TAB,
+ ITEM_ID_OPENBRACE,
+ ITEM_ID_CLOSEBRACE,
+ ITEM_ID_ENTER,
+ ITEM_ID_COLON,
+ ITEM_ID_QUOTE,
+ ITEM_ID_BACKSLASH,
+ ITEM_ID_BACKSLASH2,
+ ITEM_ID_COMMA,
+ ITEM_ID_STOP,
+ ITEM_ID_SLASH,
+ ITEM_ID_SPACE,
+ ITEM_ID_INSERT,
+ ITEM_ID_DEL,
+ ITEM_ID_HOME,
+ ITEM_ID_END,
+ ITEM_ID_PGUP,
+ ITEM_ID_PGDN,
+ ITEM_ID_LEFT,
+ ITEM_ID_RIGHT,
+ ITEM_ID_UP,
+ ITEM_ID_DOWN,
+ ITEM_ID_0_PAD,
+ ITEM_ID_1_PAD,
+ ITEM_ID_2_PAD,
+ ITEM_ID_3_PAD,
+ ITEM_ID_4_PAD,
+ ITEM_ID_5_PAD,
+ ITEM_ID_6_PAD,
+ ITEM_ID_7_PAD,
+ ITEM_ID_8_PAD,
+ ITEM_ID_9_PAD,
+ ITEM_ID_SLASH_PAD,
+ ITEM_ID_ASTERISK,
+ ITEM_ID_MINUS_PAD,
+ ITEM_ID_PLUS_PAD,
+ ITEM_ID_DEL_PAD,
+ ITEM_ID_ENTER_PAD,
+ ITEM_ID_PRTSCR,
+ ITEM_ID_PAUSE,
+ ITEM_ID_LSHIFT,
+ ITEM_ID_RSHIFT,
+ ITEM_ID_LCONTROL,
+ ITEM_ID_RCONTROL,
+ ITEM_ID_LALT,
+ ITEM_ID_RALT,
+ ITEM_ID_SCRLOCK,
+ ITEM_ID_NUMLOCK,
+ ITEM_ID_CAPSLOCK,
+ ITEM_ID_LWIN,
+ ITEM_ID_RWIN,
+ ITEM_ID_MENU,
+ ITEM_ID_CANCEL,
+
+ /* standard mouse/joystick/gun IDs */
+ ITEM_ID_XAXIS,
+ ITEM_ID_YAXIS,
+ ITEM_ID_ZAXIS,
+ ITEM_ID_RXAXIS,
+ ITEM_ID_RYAXIS,
+ ITEM_ID_RZAXIS,
+ ITEM_ID_SLIDER1,
+ ITEM_ID_SLIDER2,
+ ITEM_ID_BUTTON1,
+ ITEM_ID_BUTTON2,
+ ITEM_ID_BUTTON3,
+ ITEM_ID_BUTTON4,
+ ITEM_ID_BUTTON5,
+ ITEM_ID_BUTTON6,
+ ITEM_ID_BUTTON7,
+ ITEM_ID_BUTTON8,
+ ITEM_ID_BUTTON9,
+ ITEM_ID_BUTTON10,
+ ITEM_ID_BUTTON11,
+ ITEM_ID_BUTTON12,
+ ITEM_ID_BUTTON13,
+ ITEM_ID_BUTTON14,
+ ITEM_ID_BUTTON15,
+ ITEM_ID_BUTTON16,
+ ITEM_ID_START,
+ ITEM_ID_SELECT,
+
+ /* generic other IDs */
+ ITEM_ID_OTHER_SWITCH,
+ ITEM_ID_OTHER_AXIS_ABSOLUTE,
+ ITEM_ID_OTHER_AXIS_RELATIVE,
+ ITEM_ID_MAXIMUM,
+
+ /* absolute maximum ID */
+ ITEM_ID_ABSOLUTE_MAXIMUM = INPUT_CODE_ITEMID(~0)
+};
+typedef enum _input_item_id input_item_id;
+
+
+/* expanded codes referencing specific devices for input definitions */
+/* note that these all implcitly refer to device 0; to reference additional */
+/* devices, wrap the code in INPUT_CODE_SET_DEVINDEX() */
+enum
+{
+ /* keyboard codes */
+ KEYCODE_A = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, A),
+ KEYCODE_B = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, B),
+ KEYCODE_C = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, C),
+ KEYCODE_D = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, D),
+ KEYCODE_E = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, E),
+ KEYCODE_F = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F),
+ KEYCODE_G = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, G),
+ KEYCODE_H = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, H),
+ KEYCODE_I = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, I),
+ KEYCODE_J = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, J),
+ KEYCODE_K = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, K),
+ KEYCODE_L = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, L),
+ KEYCODE_M = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, M),
+ KEYCODE_N = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, N),
+ KEYCODE_O = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, O),
+ KEYCODE_P = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, P),
+ KEYCODE_Q = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, Q),
+ KEYCODE_R = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, R),
+ KEYCODE_S = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, S),
+ KEYCODE_T = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, T),
+ KEYCODE_U = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, U),
+ KEYCODE_V = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, V),
+ KEYCODE_W = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, W),
+ KEYCODE_X = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, X),
+ KEYCODE_Y = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, Y),
+ KEYCODE_Z = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, Z),
+ KEYCODE_0 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 0),
+ KEYCODE_1 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 1),
+ KEYCODE_2 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 2),
+ KEYCODE_3 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 3),
+ KEYCODE_4 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 4),
+ KEYCODE_5 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 5),
+ KEYCODE_6 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 6),
+ KEYCODE_7 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 7),
+ KEYCODE_8 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 8),
+ KEYCODE_9 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 9),
+ KEYCODE_F1 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F1),
+ KEYCODE_F2 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F2),
+ KEYCODE_F3 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F3),
+ KEYCODE_F4 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F4),
+ KEYCODE_F5 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F5),
+ KEYCODE_F6 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F6),
+ KEYCODE_F7 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F7),
+ KEYCODE_F8 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F8),
+ KEYCODE_F9 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F9),
+ KEYCODE_F10 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F10),
+ KEYCODE_F11 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F11),
+ KEYCODE_F12 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F12),
+ KEYCODE_F13 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F13),
+ KEYCODE_F14 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F14),
+ KEYCODE_F15 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, F15),
+ KEYCODE_ESC = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, ESC),
+ KEYCODE_TILDE = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, TILDE),
+ KEYCODE_MINUS = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, MINUS),
+ KEYCODE_EQUALS = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, EQUALS),
+ KEYCODE_BACKSPACE = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, BACKSPACE),
+ KEYCODE_TAB = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, TAB),
+ KEYCODE_OPENBRACE = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, OPENBRACE),
+ KEYCODE_CLOSEBRACE = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, CLOSEBRACE),
+ KEYCODE_ENTER = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, ENTER),
+ KEYCODE_COLON = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, COLON),
+ KEYCODE_QUOTE = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, QUOTE),
+ KEYCODE_BACKSLASH = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, BACKSLASH),
+ KEYCODE_BACKSLASH2 = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, BACKSLASH2),
+ KEYCODE_COMMA = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, COMMA),
+ KEYCODE_STOP = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, STOP),
+ KEYCODE_SLASH = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, SLASH),
+ KEYCODE_SPACE = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, SPACE),
+ KEYCODE_INSERT = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, INSERT),
+ KEYCODE_DEL = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, DEL),
+ KEYCODE_HOME = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, HOME),
+ KEYCODE_END = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, END),
+ KEYCODE_PGUP = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, PGUP),
+ KEYCODE_PGDN = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, PGDN),
+ KEYCODE_LEFT = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, LEFT),
+ KEYCODE_RIGHT = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, RIGHT),
+ KEYCODE_UP = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, UP),
+ KEYCODE_DOWN = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, DOWN),
+ KEYCODE_0_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 0_PAD),
+ KEYCODE_1_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 1_PAD),
+ KEYCODE_2_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 2_PAD),
+ KEYCODE_3_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 3_PAD),
+ KEYCODE_4_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 4_PAD),
+ KEYCODE_5_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 5_PAD),
+ KEYCODE_6_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 6_PAD),
+ KEYCODE_7_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 7_PAD),
+ KEYCODE_8_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 8_PAD),
+ KEYCODE_9_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, 9_PAD),
+ KEYCODE_SLASH_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, SLASH_PAD),
+ KEYCODE_ASTERISK = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, ASTERISK),
+ KEYCODE_MINUS_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, MINUS_PAD),
+ KEYCODE_PLUS_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, PLUS_PAD),
+ KEYCODE_DEL_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, DEL_PAD),
+ KEYCODE_ENTER_PAD = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, ENTER_PAD),
+ KEYCODE_PRTSCR = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, PRTSCR),
+ KEYCODE_PAUSE = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, PAUSE),
+ KEYCODE_LSHIFT = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, LSHIFT),
+ KEYCODE_RSHIFT = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, RSHIFT),
+ KEYCODE_LCONTROL = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, LCONTROL),
+ KEYCODE_RCONTROL = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, RCONTROL),
+ KEYCODE_LALT = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, LALT),
+ KEYCODE_RALT = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, RALT),
+ KEYCODE_SCRLOCK = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, SCRLOCK),
+ KEYCODE_NUMLOCK = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, NUMLOCK),
+ KEYCODE_CAPSLOCK = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, CAPSLOCK),
+ KEYCODE_LWIN = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, LWIN),
+ KEYCODE_RWIN = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, RWIN),
+ KEYCODE_MENU = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, MENU),
+ KEYCODE_CANCEL = STANDARD_CODE(KEYBOARD, 0, SWITCH, NONE, CANCEL),
+
+ /* mouse axes as relative devices */
+ MOUSECODE_X = STANDARD_CODE(MOUSE, 0, RELATIVE, NONE, XAXIS),
+ MOUSECODE_Y = STANDARD_CODE(MOUSE, 0, RELATIVE, NONE, YAXIS),
+ MOUSECODE_Z = STANDARD_CODE(MOUSE, 0, RELATIVE, NONE, ZAXIS),
+
+ /* mouse axes as switches in +/- direction */
+ MOUSECODE_X_POS_SWITCH = STANDARD_CODE(MOUSE, 0, SWITCH, POS, XAXIS),
+ MOUSECODE_X_NEG_SWITCH = STANDARD_CODE(MOUSE, 0, SWITCH, NEG, XAXIS),
+ MOUSECODE_Y_POS_SWITCH = STANDARD_CODE(MOUSE, 0, SWITCH, POS, YAXIS),
+ MOUSECODE_Y_NEG_SWITCH = STANDARD_CODE(MOUSE, 0, SWITCH, NEG, YAXIS),
+ MOUSECODE_Z_POS_SWITCH = STANDARD_CODE(MOUSE, 0, SWITCH, POS, ZAXIS),
+ MOUSECODE_Z_NEG_SWITCH = STANDARD_CODE(MOUSE, 0, SWITCH, NEG, ZAXIS),
+
+ /* mouse buttons */
+ MOUSECODE_BUTTON1 = STANDARD_CODE(MOUSE, 0, SWITCH, NONE, BUTTON1),
+ MOUSECODE_BUTTON2 = STANDARD_CODE(MOUSE, 0, SWITCH, NONE, BUTTON2),
+ MOUSECODE_BUTTON3 = STANDARD_CODE(MOUSE, 0, SWITCH, NONE, BUTTON3),
+ MOUSECODE_BUTTON4 = STANDARD_CODE(MOUSE, 0, SWITCH, NONE, BUTTON4),
+ MOUSECODE_BUTTON5 = STANDARD_CODE(MOUSE, 0, SWITCH, NONE, BUTTON5),
+ MOUSECODE_BUTTON6 = STANDARD_CODE(MOUSE, 0, SWITCH, NONE, BUTTON6),
+ MOUSECODE_BUTTON7 = STANDARD_CODE(MOUSE, 0, SWITCH, NONE, BUTTON7),
+ MOUSECODE_BUTTON8 = STANDARD_CODE(MOUSE, 0, SWITCH, NONE, BUTTON8),
+
+ /* gun axes as absolute devices */
+ GUNCODE_X = STANDARD_CODE(LIGHTGUN, 0, ABSOLUTE, NONE, XAXIS),
+ GUNCODE_Y = STANDARD_CODE(LIGHTGUN, 0, ABSOLUTE, NONE, YAXIS),
+
+ /* gun buttons */
+ GUNCODE_BUTTON1 = STANDARD_CODE(LIGHTGUN, 0, SWITCH, NONE, BUTTON1),
+ GUNCODE_BUTTON2 = STANDARD_CODE(LIGHTGUN, 0, SWITCH, NONE, BUTTON2),
+ GUNCODE_BUTTON3 = STANDARD_CODE(LIGHTGUN, 0, SWITCH, NONE, BUTTON3),
+ GUNCODE_BUTTON4 = STANDARD_CODE(LIGHTGUN, 0, SWITCH, NONE, BUTTON4),
+ GUNCODE_BUTTON5 = STANDARD_CODE(LIGHTGUN, 0, SWITCH, NONE, BUTTON5),
+ GUNCODE_BUTTON6 = STANDARD_CODE(LIGHTGUN, 0, SWITCH, NONE, BUTTON6),
+ GUNCODE_BUTTON7 = STANDARD_CODE(LIGHTGUN, 0, SWITCH, NONE, BUTTON7),
+ GUNCODE_BUTTON8 = STANDARD_CODE(LIGHTGUN, 0, SWITCH, NONE, BUTTON8),
+
+ /* joystick axes as absolute devices */
+ JOYCODE_X = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NONE, XAXIS),
+ JOYCODE_Y = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NONE, YAXIS),
+ JOYCODE_Z = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NONE, ZAXIS),
+ JOYCODE_U = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NONE, RXAXIS),
+ JOYCODE_V = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NONE, RYAXIS),
+
+ /* joystick axes as absolute half-axes */
+ JOYCODE_X_POS_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, POS, XAXIS),
+ JOYCODE_X_NEG_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NEG, XAXIS),
+ JOYCODE_Y_POS_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, POS, YAXIS),
+ JOYCODE_Y_NEG_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NEG, YAXIS),
+ JOYCODE_Z_POS_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, POS, ZAXIS),
+ JOYCODE_Z_NEG_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NEG, ZAXIS),
+ JOYCODE_U_POS_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, POS, RXAXIS),
+ JOYCODE_U_NEG_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NEG, RXAXIS),
+ JOYCODE_V_POS_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, POS, RYAXIS),
+ JOYCODE_V_NEG_ABSOLUTE = STANDARD_CODE(JOYSTICK, 0, ABSOLUTE, NEG, RYAXIS),
+
+ /* joystick axes as switches; X/Y are specially handled for left/right/up/down mapping */
+ JOYCODE_X_LEFT_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, LEFT, XAXIS),
+ JOYCODE_X_RIGHT_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, RIGHT, XAXIS),
+ JOYCODE_Y_UP_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, UP, YAXIS),
+ JOYCODE_Y_DOWN_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, DOWN, YAXIS),
+ JOYCODE_Z_POS_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, POS, ZAXIS),
+ JOYCODE_Z_NEG_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, NEG, ZAXIS),
+ JOYCODE_U_POS_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, POS, RXAXIS),
+ JOYCODE_U_NEG_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, NEG, RXAXIS),
+ JOYCODE_V_POS_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, POS, RYAXIS),
+ JOYCODE_V_NEG_SWITCH = STANDARD_CODE(JOYSTICK, 0, SWITCH, NEG, RYAXIS),
+
+ /* joystick buttons */
+ JOYCODE_BUTTON1 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON1),
+ JOYCODE_BUTTON2 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON2),
+ JOYCODE_BUTTON3 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON3),
+ JOYCODE_BUTTON4 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON4),
+ JOYCODE_BUTTON5 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON5),
+ JOYCODE_BUTTON6 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON6),
+ JOYCODE_BUTTON7 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON7),
+ JOYCODE_BUTTON8 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON8),
+ JOYCODE_BUTTON9 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON9),
+ JOYCODE_BUTTON10 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON10),
+ JOYCODE_BUTTON11 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON11),
+ JOYCODE_BUTTON12 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON12),
+ JOYCODE_BUTTON13 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON13),
+ JOYCODE_BUTTON14 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON14),
+ JOYCODE_BUTTON15 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON15),
+ JOYCODE_BUTTON16 = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, BUTTON16),
+ JOYCODE_START = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, START),
+ JOYCODE_SELECT = STANDARD_CODE(JOYSTICK, 0, SWITCH, NONE, SELECT)
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* input codes are UINT32 */
+typedef UINT32 input_code;
+
+/* callback for getting the value of an item on a device */
+typedef INT32 (*item_get_state_cb)(void *device_internal, void *item_internal);
+
+/* (opaque) input device object */
+typedef struct _input_device input_device;
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* joystick maps */
+extern const char * joystick_map_8way;
+extern const char * joystick_map_4way_sticky;
+extern const char * joystick_map_4way_diagonal;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- initialization and configuration ----- */
+
+/* core initialization, prior to calling osd_init() */
+void input_init(running_machine *machine);
+
+/* enable or disable a device class */
+void input_device_class_enable(input_device_class devclass, UINT8 enable);
+
+/* is a device class enabled? */
+UINT8 input_device_class_enabled(input_device_class devclass);
+
+/* configure default joystick maps */
+int input_device_set_joystick_map(int devindex, const char *mapstring);
+
+
+/* ----- OSD configuration and access ----- */
+
+/* add a new input device */
+input_device *input_device_add(input_device_class devclass, const char *name, void *internal);
+
+/* add a new item to an input device */
+void input_device_item_add(input_device *device, const char *name, void *internal, input_item_id itemid, item_get_state_cb getstate);
+
+
+
+/* ----- state queries ----- */
+
+/* return the value of a particular input code */
+INT32 input_code_value(input_code code);
+
+/* return TRUE if the given input code has been pressed */
+INT32 input_code_pressed(input_code code);
+
+/* same as above, but returns TRUE only on the first call after an off->on transition */
+INT32 input_code_pressed_once(input_code code);
+
+/* poll for any switch input, optionally resetting internal memory */
+input_code input_code_poll_switches(int reset);
+
+/* poll for any axis input, optionally resetting internal memory */
+input_code input_code_poll_axes(int reset);
+
+
+
+/* ----- strings and tokenization ----- */
+
+/* generate the friendly name of an input code, returning the length (buffer can be NULL) */
+astring *input_code_name(astring *buffer, input_code code);
+
+/* convert an input code to a token, returning the length (buffer can be NULL) */
+astring *input_code_to_token(astring *buffer, input_code code);
+
+/* convert a token back to an input code */
+input_code input_code_from_token(const char *_token);
+
+
+#endif /* __INPUT_H__ */
diff --git a/src/emu/inputseq.c b/src/emu/inputseq.c
new file mode 100644
index 00000000000..d979f2d5434
--- /dev/null
+++ b/src/emu/inputseq.c
@@ -0,0 +1,630 @@
+/***************************************************************************
+
+ inputseq.c
+
+ Input sequence abstractions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "inputseq.h"
+#include "restrack.h"
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* max time between key presses */
+#define RECORD_TIME (osd_ticks_per_second() * 2 / 3)
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* information about the current sequence being recorded */
+static input_seq record_seq;
+static osd_ticks_t record_last;
+static input_item_class record_class;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* internal functions */
+static int input_seq_is_valid(const input_seq *seq);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_seq_length - return the length of the
+ sequence
+-------------------------------------------------*/
+
+INLINE int input_seq_length(const input_seq *seq)
+{
+ int seqnum;
+
+ /* find the end token; error if none found */
+ for (seqnum = 0; seqnum < ARRAY_LENGTH(seq->code); seqnum++)
+ if (seq->code[seqnum] == SEQCODE_END)
+ return seqnum;
+ return ARRAY_LENGTH(seq->code);
+}
+
+
+/*-------------------------------------------------
+ input_seq_append - append a code to the end
+ of an input sequence
+-------------------------------------------------*/
+
+INLINE int input_seq_append(input_seq *seq, input_code code)
+{
+ int length = input_seq_length(seq);
+
+ /* if not enough room, return FALSE */
+ if (length >= ARRAY_LENGTH(seq->code) - 1)
+ return FALSE;
+
+ /* otherwise, append the code and add a new end */
+ seq->code[length++] = code;
+ seq->code[length] = SEQCODE_END;
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ input_seq_get_last - return the last code
+ in a sequence
+-------------------------------------------------*/
+
+INLINE input_code input_seq_get_last(const input_seq *seq)
+{
+ int length = input_seq_length(seq);
+ return (length == 0) ? SEQCODE_END : seq->code[length - 1];
+}
+
+
+/*-------------------------------------------------
+ input_seq_backspace - "backspace" over the
+ last entry in a sequence
+-------------------------------------------------*/
+
+INLINE void input_seq_backspace(input_seq *seq)
+{
+ int length = input_seq_length(seq);
+
+ /* if we have at least one entry, remove it */
+ if (length > 0)
+ seq->code[length - 1] = SEQCODE_END;
+}
+
+
+
+/***************************************************************************
+ STATE QUERIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_seq_pressed - return true if the given
+ sequence of switch inputs is "pressed"
+-------------------------------------------------*/
+
+int input_seq_pressed(const input_seq *seq)
+{
+ int result = FALSE;
+ int invert = FALSE;
+ int first = TRUE;
+ int codenum;
+
+ /* iterate over all of the codes */
+ for (codenum = 0; codenum < ARRAY_LENGTH(seq->code); codenum++)
+ {
+ input_code code = seq->code[codenum];
+
+ /* handle NOT */
+ if (code == SEQCODE_NOT)
+ invert = TRUE;
+
+ /* handle OR and END */
+ else if (code == SEQCODE_OR || code == SEQCODE_END)
+ {
+ /* if we have a positive result from the previous set, we're done */
+ if (result || code == SEQCODE_END)
+ break;
+
+ /* otherwise, reset our state */
+ result = FALSE;
+ invert = FALSE;
+ first = TRUE;
+ }
+
+ /* handle everything else as a series of ANDs */
+ else
+ {
+ /* if this is the first in the sequence, result is set equal */
+ if (first)
+ result = input_code_pressed(code) ^ invert;
+
+ /* further values are ANDed */
+ else if (result)
+ result &= input_code_pressed(code) ^ invert;
+
+ /* no longer first, and clear the invert flag */
+ first = invert = FALSE;
+ }
+ }
+
+ /* return the result if we queried at least one switch */
+ return result;
+}
+
+
+/*-------------------------------------------------
+ input_seq_axis_value - return the value of an
+ axis defined in an input sequence
+-------------------------------------------------*/
+
+INT32 input_seq_axis_value(const input_seq *seq, input_item_class *itemclass_ptr)
+{
+ input_item_class itemclasszero = ITEM_CLASS_ABSOLUTE;
+ input_item_class itemclass = ITEM_CLASS_INVALID;
+ int result = 0;
+ int invert = FALSE;
+ int enable = TRUE;
+ int codenum;
+
+ /* iterate over all of the codes */
+ for (codenum = 0; codenum < ARRAY_LENGTH(seq->code); codenum++)
+ {
+ input_code code = seq->code[codenum];
+
+ /* handle NOT */
+ if (code == SEQCODE_NOT)
+ invert = TRUE;
+
+ /* handle OR and END */
+ else if (code == SEQCODE_OR || code == SEQCODE_END)
+ {
+ /* if we have a positive result from the previous set, we're done */
+ if (itemclass != ITEM_CLASS_INVALID || code == SEQCODE_END)
+ break;
+
+ /* otherwise, reset our state */
+ result = 0;
+ invert = FALSE;
+ enable = TRUE;
+ }
+
+ /* handle everything else only if we're still enabled */
+ else if (enable)
+ {
+ /* switch codes serve as enables */
+ if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_SWITCH)
+ {
+ /* AND against previous digital codes */
+ if (enable)
+ enable &= input_code_pressed(code) ^ invert;
+ }
+
+ /* non-switch codes are analog values */
+ else
+ {
+ INT32 value = input_code_value(code);
+
+ /* if we got a 0 value, don't do anything except remember the first type */
+ if (value == 0)
+ {
+ if (itemclasszero == ITEM_CLASS_INVALID)
+ itemclasszero = INPUT_CODE_ITEMCLASS(code);
+ }
+
+ /* non-zero absolute values stick */
+ else if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_ABSOLUTE)
+ {
+ itemclass = ITEM_CLASS_ABSOLUTE;
+ result = value;
+ }
+
+ /* non-zero relative values accumulate */
+ else if (INPUT_CODE_ITEMCLASS(code) == ITEM_CLASS_RELATIVE)
+ {
+ itemclass = ITEM_CLASS_RELATIVE;
+ result += value;
+ }
+ }
+
+ /* clear the invert flag */
+ invert = FALSE;
+ }
+ }
+
+ /* if the caller wants to know the type, provide it */
+ if (itemclass_ptr != NULL)
+ *itemclass_ptr = (result == 0) ? itemclasszero : itemclass;
+ return result;
+}
+
+
+
+/***************************************************************************
+ SEQUENCE POLLING
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_seq_poll_start - begin polling for a
+ new sequence of the given itemclass
+-------------------------------------------------*/
+
+void input_seq_poll_start(input_item_class itemclass, const input_seq *startseq)
+{
+ input_code dummycode;
+
+ assert(itemclass == ITEM_CLASS_SWITCH || itemclass == ITEM_CLASS_ABSOLUTE || itemclass == ITEM_CLASS_RELATIVE);
+
+ /* reset the recording count and the clock */
+ record_last = 0;
+ record_class = itemclass;
+
+ /* grab the starting sequence to append to */
+ if (startseq != NULL)
+ record_seq = *startseq;
+ else
+ input_seq_set_0(&record_seq);
+
+ /* append an OR if this is not a NULL sequence */
+ if (input_seq_length(&record_seq) > 0)
+ input_seq_append(&record_seq, SEQCODE_OR);
+
+ /* flush out any goobers */
+ dummycode = (record_class == ITEM_CLASS_SWITCH) ? input_code_poll_switches(TRUE) : input_code_poll_axes(TRUE);
+ while (dummycode != INPUT_CODE_INVALID)
+ dummycode = (record_class == ITEM_CLASS_SWITCH) ? input_code_poll_switches(FALSE) : input_code_poll_axes(FALSE);
+}
+
+
+/*-------------------------------------------------
+ input_seq_poll - continue polling
+-------------------------------------------------*/
+
+int input_seq_poll(input_seq *finalseq)
+{
+ input_code lastcode = input_seq_get_last(&record_seq);
+ input_code newcode;
+
+ /* switch case: see if we have a new code to process */
+ if (record_class == ITEM_CLASS_SWITCH)
+ {
+ newcode = input_code_poll_switches(FALSE);
+ if (newcode != INPUT_CODE_INVALID)
+ {
+ /* if code is duplicate, toggle the NOT state on the code */
+ if (input_seq_length(&record_seq) > 0 && newcode == lastcode)
+ {
+ /* back up over the code */
+ input_seq_backspace(&record_seq);
+
+ /* if there was a NOT preceding it, just delete it, otherwise append one */
+ if (input_seq_get_last(&record_seq) == SEQCODE_NOT)
+ input_seq_backspace(&record_seq);
+ else
+ input_seq_append(&record_seq, SEQCODE_NOT);
+ }
+ }
+ }
+
+ /* absolute/relative case: see if we have an analog change of sufficient amount */
+ else
+ {
+ newcode = input_code_poll_axes(FALSE);
+
+ /* if the last code doesn't match absolute/relative of this code, ignore the new one */
+ if ((INPUT_CODE_ITEMCLASS(lastcode) == ITEM_CLASS_ABSOLUTE && INPUT_CODE_ITEMCLASS(newcode) != ITEM_CLASS_ABSOLUTE) ||
+ (INPUT_CODE_ITEMCLASS(lastcode) == ITEM_CLASS_RELATIVE && INPUT_CODE_ITEMCLASS(newcode) != ITEM_CLASS_RELATIVE))
+ newcode = INPUT_CODE_INVALID;
+
+ if (newcode != INPUT_CODE_INVALID)
+ {
+ /* if code is duplicate and an absolute control, toggle to half axis */
+ if (input_seq_length(&record_seq) > 0 && INPUT_CODE_ITEMCLASS(newcode) == ITEM_CLASS_ABSOLUTE)
+ if (newcode == INPUT_CODE_SET_MODIFIER(lastcode, ITEM_MODIFIER_NONE))
+ {
+ /* increment the modifier, wrapping back to none */
+ input_item_modifier oldmod = INPUT_CODE_MODIFIER(lastcode);
+ input_item_modifier newmod = (oldmod < ITEM_MODIFIER_NEG) ? oldmod + 1 : ITEM_MODIFIER_NONE;
+ newcode = INPUT_CODE_SET_MODIFIER(newcode, newmod);
+
+ /* back up over the previous code so we can re-append */
+ input_seq_backspace(&record_seq);
+ }
+ }
+ }
+
+ /* if we got a new code to append it, append it and reset the timer */
+ if (newcode != INPUT_CODE_INVALID)
+ {
+ input_seq_append(&record_seq, newcode);
+ record_last = osd_ticks();
+ }
+
+ /* if we're recorded at least one item and the RECORD_TIME has passed, we're done */
+ if (record_last != 0 && osd_ticks() > record_last + RECORD_TIME)
+ {
+ /* if the final result is invalid, reset to nothing */
+ if (!input_seq_is_valid(&record_seq))
+ input_seq_set_0(&record_seq);
+
+ /* return TRUE to indicate that we are finished */
+ *finalseq = record_seq;
+ return TRUE;
+ }
+
+ /* return FALSE to indicate we are still polling */
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ STRINGS AND TOKENIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_seq_name - generate the friendly name
+ of a sequence
+-------------------------------------------------*/
+
+astring *input_seq_name(astring *string, const input_seq *seq)
+{
+ astring *codestr = astring_alloc();
+ int codenum, copycodenum;
+ input_seq seqcopy;
+
+ /* walk the sequence first, removing any pieces that are invalid */
+ for (codenum = copycodenum = 0; codenum < ARRAY_LENGTH(seq->code) && seq->code[codenum] != SEQCODE_END; codenum++)
+ {
+ input_code code = seq->code[codenum];
+
+ /* if this is a code item which is not valid, don't copy it and remove any preceding ORs/NOTs */
+ if (!INPUT_CODE_IS_INTERNAL(code) && astring_len(input_code_name(codestr, code)) == 0)
+ {
+ while (copycodenum > 0 && INPUT_CODE_IS_INTERNAL(seqcopy.code[copycodenum - 1]))
+ copycodenum--;
+ }
+ else if (copycodenum > 0 || !INPUT_CODE_IS_INTERNAL(code))
+ seqcopy.code[copycodenum++] = code;
+ }
+ seqcopy.code[copycodenum] = SEQCODE_END;
+
+ /* special case: empty */
+ if (copycodenum == 0)
+ {
+ astring_free(codestr);
+ return astring_cpyc(string, (seq->code[0] == SEQCODE_END) ? "None" : "n/a");
+ }
+
+ /* start with an empty buffer */
+ astring_reset(string);
+
+ /* loop until we hit the end */
+ for (codenum = 0; codenum < ARRAY_LENGTH(seqcopy.code) && seqcopy.code[codenum] != SEQCODE_END; codenum++)
+ {
+ input_code code = seqcopy.code[codenum];
+
+ /* append a space if not the first code */
+ if (codenum != 0)
+ astring_catc(string, " ");
+
+ /* handle OR/NOT codes here */
+ if (code == SEQCODE_OR)
+ astring_catc(string, "or");
+ else if (code == SEQCODE_NOT)
+ astring_catc(string, "not");
+
+ /* otherwise, assume it is an input code and ask the input system to generate it */
+ else
+ astring_cat(string, input_code_name(codestr, code));
+ }
+
+ astring_free(codestr);
+ return string;
+}
+
+
+/*-------------------------------------------------
+ input_seq_to_tokens - generate the tokenized
+ form of a sequence
+-------------------------------------------------*/
+
+astring *input_seq_to_tokens(astring *string, const input_seq *seq)
+{
+ astring *codestr = astring_alloc();
+ int codenum;
+
+ /* start with an empty buffer */
+ astring_reset(string);
+
+ /* loop until we hit the end */
+ for (codenum = 0; codenum < ARRAY_LENGTH(seq->code) && seq->code[codenum] != SEQCODE_END; codenum++)
+ {
+ input_code code = seq->code[codenum];
+
+ /* append a space if not the first code */
+ if (codenum != 0)
+ astring_catc(string, " ");
+
+ /* handle OR/NOT codes here */
+ if (code == SEQCODE_OR)
+ astring_catc(string, "OR");
+ else if (code == SEQCODE_NOT)
+ astring_catc(string, "NOT");
+ else if (code == SEQCODE_DEFAULT)
+ astring_catc(string, "DEFAULT");
+
+ /* otherwise, assume it is an input code and ask the input system to generate it */
+ else
+ astring_cat(string, input_code_to_token(codestr, code));
+ }
+
+ astring_free(codestr);
+ return string;
+}
+
+
+/*-------------------------------------------------
+ input_seq_from_tokens - generate the tokenized
+ form of a sequence
+-------------------------------------------------*/
+
+int input_seq_from_tokens(const char *string, input_seq *seq)
+{
+ char *strcopy = malloc_or_die(strlen(string) + 1);
+ char *str = strcopy;
+ int result = FALSE;
+
+ /* start with a blank sequence */
+ input_seq_set_0(seq);
+
+ /* loop until we're done */
+ strcpy(strcopy, string);
+ while (1)
+ {
+ input_code code;
+ char origspace;
+ char *strtemp;
+
+ /* trim any leading spaces */
+ while (*str != 0 && isspace(*str))
+ str++;
+
+ /* bail if we're done */
+ if (*str == 0)
+ {
+ result = TRUE;
+ break;
+ }
+
+ /* find the end of the token and make it upper-case along the way */
+ for (strtemp = str; *strtemp != 0 && !isspace(*strtemp); strtemp++)
+ *strtemp = toupper(*strtemp);
+ origspace = *strtemp;
+ *strtemp = 0;
+
+ /* look for common stuff */
+ if (strcmp(str, "OR") == 0)
+ code = SEQCODE_OR;
+ else if (strcmp(str, "NOT") == 0)
+ code = SEQCODE_NOT;
+ else if (strcmp(str, "DEFAULT") == 0)
+ code = SEQCODE_DEFAULT;
+ else
+ code = input_code_from_token(str);
+
+ /* translate and add to the sequence */
+ input_seq_append(seq, code);
+
+ /* advance */
+ if (origspace == 0)
+ {
+ result = TRUE;
+ break;
+ }
+ str = strtemp + 1;
+ }
+
+ free(strcopy);
+ return result;
+}
+
+
+
+/***************************************************************************
+ INTERNAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_seq_is_valid - return TRUE if a given
+ sequence is valid
+-------------------------------------------------*/
+
+static int input_seq_is_valid(const input_seq *seq)
+{
+ input_item_class lastclass = ITEM_CLASS_INVALID;
+ input_code lastcode = INPUT_CODE_INVALID;
+ int positive_code_count = 0;
+ int seqnum;
+
+ /* scan the sequence for valid codes */
+ for (seqnum = 0; seqnum < ARRAY_LENGTH(seq->code); seqnum++)
+ {
+ input_code code = seq->code[seqnum];
+
+ /* invalid codes are invalid */
+ if (code == INPUT_CODE_INVALID)
+ return FALSE;
+
+ /* if we hit an OR or the end, validate the previous chunk */
+ if (code == SEQCODE_OR || code == SEQCODE_END)
+ {
+ /* must be at least one positive code */
+ if (positive_code_count == 0)
+ return FALSE;
+
+ /* last code must not have been an internal code */
+ if (INPUT_CODE_IS_INTERNAL(lastcode))
+ return FALSE;
+
+ /* if this is the end, we're ok */
+ if (code == SEQCODE_END)
+ return TRUE;
+
+ /* reset the state for the next chunk */
+ positive_code_count = 0;
+ lastclass = ITEM_CLASS_INVALID;
+ }
+
+ /* if we hit a NOT, make sure we don't have a double */
+ else if (code == SEQCODE_NOT)
+ {
+ if (lastcode == SEQCODE_NOT)
+ return FALSE;
+ }
+
+ /* anything else */
+ else
+ {
+ input_item_class itemclass = INPUT_CODE_ITEMCLASS(code);
+
+ /* count positive codes */
+ if (lastcode != SEQCODE_NOT)
+ positive_code_count++;
+
+ /* non-switch items can't have a NOT */
+ if (itemclass != ITEM_CLASS_SWITCH && lastcode == SEQCODE_NOT)
+ return FALSE;
+
+ /* absolute/relative items must all be the same class */
+ if ((lastclass == ITEM_CLASS_ABSOLUTE && itemclass != ITEM_CLASS_ABSOLUTE) ||
+ (lastclass == ITEM_CLASS_RELATIVE && itemclass != ITEM_CLASS_RELATIVE))
+ return FALSE;
+ }
+
+ /* remember the last code */
+ lastcode = code;
+ }
+
+ /* if we got here, we were missing an END token; fail */
+ return FALSE;
+}
diff --git a/src/emu/inputseq.h b/src/emu/inputseq.h
new file mode 100644
index 00000000000..748b0440e8d
--- /dev/null
+++ b/src/emu/inputseq.h
@@ -0,0 +1,177 @@
+/***************************************************************************
+
+ inputseq.h
+
+ Input sequence abstractions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __INPUTSEQ_H__
+#define __INPUTSEQ_H__
+
+#include "input.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* additional expanded input codes for sequences */
+enum
+{
+ /* special codes */
+ SEQCODE_END = INTERNAL_CODE(0),
+ SEQCODE_DEFAULT = INTERNAL_CODE(1),
+ SEQCODE_NOT = INTERNAL_CODE(2),
+ SEQCODE_OR = INTERNAL_CODE(3)
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* a sequence of inputs */
+typedef struct _input_seq input_seq;
+struct _input_seq
+{
+ input_code code[16];
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define SEQ_DEF_7(a,b,c,d,e,f,g) {{ a, b, c, d, e, f, g, SEQCODE_END }}
+#define SEQ_DEF_6(a,b,c,d,e,f) {{ a, b, c, d, e, f, SEQCODE_END }}
+#define SEQ_DEF_5(a,b,c,d,e) {{ a, b, c, d, e, SEQCODE_END }}
+#define SEQ_DEF_4(a,b,c,d) {{ a, b, c, d, SEQCODE_END }}
+#define SEQ_DEF_3(a,b,c) {{ a, b, c, SEQCODE_END }}
+#define SEQ_DEF_2(a,b) {{ a, b, SEQCODE_END }}
+#define SEQ_DEF_1(a) {{ a, SEQCODE_END }}
+#define SEQ_DEF_0 {{ SEQCODE_END }}
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- state queries ----- */
+
+/* return TRUE if the given switch sequence has been pressed */
+int input_seq_pressed(const input_seq *seq);
+
+/* return the value of an axis sequence */
+INT32 input_seq_axis_value(const input_seq *seq, input_item_class *itemclass_ptr);
+
+
+
+/* ----- sequence polling ----- */
+
+/* begin polling for a new sequence of the given itemclass */
+void input_seq_poll_start(input_item_class itemclass, const input_seq *startseq);
+
+/* continue polling for a sequence */
+int input_seq_poll(input_seq *finalseq);
+
+
+
+/* ----- strings and tokenization ----- */
+
+/* generate the friendly name of an input sequence */
+astring *input_seq_name(astring *string, const input_seq *seq);
+
+/* convert an input sequence to tokens, returning the length */
+astring *input_seq_to_tokens(astring *string, const input_seq *seq);
+
+/* convert a set of tokens back to an input sequence */
+int input_seq_from_tokens(const char *string, input_seq *seq);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ input_seq_get_1 - fetch the first item of an
+ input sequence
+-------------------------------------------------*/
+
+INLINE input_code input_seq_get_1(const input_seq *seq)
+{
+ return seq->code[0];
+}
+
+
+/*-------------------------------------------------
+ input_seq_set_n - set a sequence of n codes
+ as an input sequence
+-------------------------------------------------*/
+
+INLINE void input_seq_set_5(input_seq *seq, input_code code0, input_code code1, input_code code2, input_code code3, input_code code4)
+{
+ int codenum;
+ seq->code[0] = code0;
+ seq->code[1] = code1;
+ seq->code[2] = code2;
+ seq->code[3] = code3;
+ seq->code[4] = code4;
+ for (codenum = 5; codenum < ARRAY_LENGTH(seq->code); codenum++)
+ seq->code[codenum] = SEQCODE_END;
+}
+
+INLINE void input_seq_set_4(input_seq *seq, input_code code0, input_code code1, input_code code2, input_code code3)
+{
+ input_seq_set_5(seq, code0, code1, code2, code3, SEQCODE_END);
+}
+
+INLINE void input_seq_set_3(input_seq *seq, input_code code0, input_code code1, input_code code2)
+{
+ input_seq_set_5(seq, code0, code1, code2, SEQCODE_END, SEQCODE_END);
+}
+
+INLINE void input_seq_set_2(input_seq *seq, input_code code0, input_code code1)
+{
+ input_seq_set_5(seq, code0, code1, SEQCODE_END, SEQCODE_END, SEQCODE_END);
+}
+
+INLINE void input_seq_set_1(input_seq *seq, input_code code0)
+{
+ input_seq_set_5(seq, code0, SEQCODE_END, SEQCODE_END, SEQCODE_END, SEQCODE_END);
+}
+
+INLINE void input_seq_set_0(input_seq *seq)
+{
+ input_seq_set_5(seq, SEQCODE_END, SEQCODE_END, SEQCODE_END, SEQCODE_END, SEQCODE_END);
+}
+
+
+/*-------------------------------------------------
+ input_seq_cmp - compare two input sequences
+-------------------------------------------------*/
+
+INLINE int input_seq_cmp(const input_seq *seqa, const input_seq *seqb)
+{
+ int codenum;
+ for (codenum = 0; codenum < ARRAY_LENGTH(seqa->code); codenum++)
+ {
+ if (seqa->code[codenum] != seqb->code[codenum])
+ return -1;
+ if (seqa->code[codenum] == SEQCODE_END)
+ break;
+ }
+ return 0;
+}
+
+#endif /* __INPUTSEQ_H__ */
diff --git a/src/emu/layout/dualhovu.lay b/src/emu/layout/dualhovu.lay
new file mode 100644
index 00000000000..d4be6a75e8e
--- /dev/null
+++ b/src/emu/layout/dualhovu.lay
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <view name="Screen 0 Standard (4:3)">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Screen 1 Standard (4:3)">
+ <screen index="1">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Screen 0 Pixel Aspect (~scr0nativexaspect~:~scr0nativeyaspect~)">
+ <screen index="0">
+ <bounds left="0" top="0" right="~scr0width~" bottom="~scr0height~" />
+ </screen>
+ </view>
+
+ <view name="Screen 1 Pixel Aspect (~scr1nativexaspect~:~scr1nativeyaspect~)">
+ <screen index="1">
+ <bounds left="0" top="0" right="~scr1width~" bottom="~scr1height~" />
+ </screen>
+ </view>
+
+ <view name="Dual Over-Under">
+ <screen index="0">
+ <bounds x="0" y="-3.03" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Dual Over-Under (Gapless)">
+ <screen index="0">
+ <bounds x="0" y="-3" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Dual Side-by-Side">
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="4.03" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Dual Side-by-Side (Gapless)">
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="4" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Cocktail">
+ <screen index="1">
+ <bounds x="0" y="-3.03" width="4" height="3" />
+ <orientation rotate="180" />
+ </screen>
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/dualhsxs.lay b/src/emu/layout/dualhsxs.lay
new file mode 100644
index 00000000000..37b4f7b9499
--- /dev/null
+++ b/src/emu/layout/dualhsxs.lay
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <view name="Screen 0 Standard (4:3)">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Screen 1 Standard (4:3)">
+ <screen index="1">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Screen 0 Pixel Aspect (~scr0nativexaspect~:~scr0nativeyaspect~)">
+ <screen index="0">
+ <bounds left="0" top="0" right="~scr0width~" bottom="~scr0height~" />
+ </screen>
+ </view>
+
+ <view name="Screen 1 Pixel Aspect (~scr1nativexaspect~:~scr1nativeyaspect~)">
+ <screen index="1">
+ <bounds left="0" top="0" right="~scr1width~" bottom="~scr1height~" />
+ </screen>
+ </view>
+
+ <view name="Dual Side-by-Side">
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="4.03" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Dual Side-by-Side (Gapless)">
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="4" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Dual Over-Under">
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="0" y="-3.03" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Dual Over-Under (Gapless)">
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="0" y="-3" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Cocktail">
+ <screen index="1">
+ <bounds x="0" y="-3.03" width="4" height="3" />
+ <orientation rotate="180" />
+ </screen>
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/dualhuov.lay b/src/emu/layout/dualhuov.lay
new file mode 100644
index 00000000000..1eced2b16ff
--- /dev/null
+++ b/src/emu/layout/dualhuov.lay
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <view name="Screen 0 Standard (4:3)">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Screen 1 Standard (4:3)">
+ <screen index="1">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Screen 0 Pixel Aspect (~scr0nativexaspect~:~scr0nativeyaspect~)">
+ <screen index="0">
+ <bounds left="0" top="0" right="~scr0width~" bottom="~scr0height~" />
+ </screen>
+ </view>
+
+ <view name="Screen 1 Pixel Aspect (~scr1nativexaspect~:~scr1nativeyaspect~)">
+ <screen index="1">
+ <bounds left="0" top="0" right="~scr1width~" bottom="~scr1height~" />
+ </screen>
+ </view>
+
+ <view name="Dual Under-Over">
+ <screen index="1">
+ <bounds x="0" y="-3.03" width="4" height="3" />
+ </screen>
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Dual Under-Over (Gapless)">
+ <screen index="1">
+ <bounds x="0" y="-3" width="4" height="3" />
+ </screen>
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Dual Side-by-Side">
+ <screen index="1">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="0">
+ <bounds x="4.03" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Dual Side-by-Side (Gapless)">
+ <screen index="1">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="0">
+ <bounds x="4" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Cocktail">
+ <screen index="0">
+ <bounds x="0" y="-3.03" width="4" height="3" />
+ <orientation rotate="180" />
+ </screen>
+ <screen index="1">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/ho20ffff.lay b/src/emu/layout/ho20ffff.lay
new file mode 100644
index 00000000000..03e947099c5
--- /dev/null
+++ b/src/emu/layout/ho20ffff.lay
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <element name="overlay">
+ <rect>
+ <bounds left="0" top="0" right="1" bottom="1" />
+ <color red="0.125" green="1.0" blue="1.0" />
+ </rect>
+ </element>
+
+ <view name="Color Overlay">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ <overlay element="overlay">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </overlay>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/ho2eff2e.lay b/src/emu/layout/ho2eff2e.lay
new file mode 100644
index 00000000000..c530ff1eb6f
--- /dev/null
+++ b/src/emu/layout/ho2eff2e.lay
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <element name="overlay">
+ <rect>
+ <bounds left="0" top="0" right="1" bottom="1" />
+ <color red="0.180" green="1" blue="0.180" />
+ </rect>
+ </element>
+
+ <view name="Color Overlay">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ <overlay element="overlay">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </overlay>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/ho4f893d.lay b/src/emu/layout/ho4f893d.lay
new file mode 100644
index 00000000000..6a96bab0ad9
--- /dev/null
+++ b/src/emu/layout/ho4f893d.lay
@@ -0,0 +1,21 @@
+<mamelayout version="2">
+
+ <element name="overlay">
+ <rect>
+ <bounds left="0" top="0" right="4" bottom="3" />
+ <color red=".310" green=".537" blue=".239" />
+ </rect>
+ </element>
+
+
+ <view name="Color Overlay">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ <overlay element="overlay">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </overlay>
+ </view>
+
+
+</mamelayout>
diff --git a/src/emu/layout/ho88ffff.lay b/src/emu/layout/ho88ffff.lay
new file mode 100644
index 00000000000..711dc65b96a
--- /dev/null
+++ b/src/emu/layout/ho88ffff.lay
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <element name="overlay">
+ <rect>
+ <bounds left="0" top="0" right="1" bottom="1" />
+ <color red="0.5333" green="1.0" blue="1.0" />
+ </rect>
+ </element>
+
+ <view name="Color Overlay">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ <overlay element="overlay">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </overlay>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/hoa0a0ff.lay b/src/emu/layout/hoa0a0ff.lay
new file mode 100644
index 00000000000..dc1ccafde5a
--- /dev/null
+++ b/src/emu/layout/hoa0a0ff.lay
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <element name="overlay">
+ <rect>
+ <bounds left="0" top="0" right="1" bottom="1" />
+ <color red="0.625" green="0.625" blue="1" />
+ </rect>
+ </element>
+
+ <view name="Color Overlay">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ <overlay element="overlay">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </overlay>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/hoffe457.lay b/src/emu/layout/hoffe457.lay
new file mode 100644
index 00000000000..304801126bf
--- /dev/null
+++ b/src/emu/layout/hoffe457.lay
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <element name="overlay">
+ <rect>
+ <bounds left="0" top="0" right="1" bottom="1" />
+ <color red="1.0" green="0.894" blue="0.341" />
+ </rect>
+ </element>
+
+ <view name="Color Overlay">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ <overlay element="overlay">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </overlay>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/hoffff20.lay b/src/emu/layout/hoffff20.lay
new file mode 100644
index 00000000000..dea4ab2b0f7
--- /dev/null
+++ b/src/emu/layout/hoffff20.lay
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <element name="overlay">
+ <rect>
+ <bounds left="0" top="0" right="1" bottom="1" />
+ <color red="1.0" green="1.0" blue="0.125" />
+ </rect>
+ </element>
+
+ <view name="Color Overlay">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ <overlay element="overlay">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </overlay>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/horizont.lay b/src/emu/layout/horizont.lay
new file mode 100644
index 00000000000..908804832af
--- /dev/null
+++ b/src/emu/layout/horizont.lay
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <view name="Standard (4:3)">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Pixel Aspect (~scr0nativexaspect~:~scr0nativeyaspect~)">
+ <screen index="0">
+ <bounds left="0" top="0" right="~scr0width~" bottom="~scr0height~" />
+ </screen>
+ </view>
+
+ <view name="Cocktail">
+ <screen index="0">
+ <bounds x="0" y="-3.03" width="4" height="3" />
+ <orientation rotate="180" />
+ </screen>
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/snap.lay b/src/emu/layout/snap.lay
new file mode 100644
index 00000000000..76dfb93d60c
--- /dev/null
+++ b/src/emu/layout/snap.lay
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <view name="s0">
+ <screen index="0">
+ <bounds left="0" top="0" right="1" bottom="1" />
+ </screen>
+ </view>
+
+ <view name="s1">
+ <screen index="1">
+ <bounds left="0" top="0" right="1" bottom="1" />
+ </screen>
+ </view>
+
+ <view name="s2">
+ <screen index="2">
+ <bounds left="0" top="0" right="1" bottom="1" />
+ </screen>
+ </view>
+
+ <view name="s3">
+ <screen index="3">
+ <bounds left="0" top="0" right="1" bottom="1" />
+ </screen>
+ </view>
+
+ <view name="s4">
+ <screen index="4">
+ <bounds left="0" top="0" right="1" bottom="1" />
+ </screen>
+ </view>
+
+ <view name="s5">
+ <screen index="5">
+ <bounds left="0" top="0" right="1" bottom="1" />
+ </screen>
+ </view>
+
+ <view name="s6">
+ <screen index="6">
+ <bounds left="0" top="0" right="1" bottom="1" />
+ </screen>
+ </view>
+
+ <view name="s7">
+ <screen index="7">
+ <bounds left="0" top="0" right="1" bottom="1" />
+ </screen>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/triphsxs.lay b/src/emu/layout/triphsxs.lay
new file mode 100644
index 00000000000..fe0c9237273
--- /dev/null
+++ b/src/emu/layout/triphsxs.lay
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <view name="Screen 0 Standard (4:3)">
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Screen 1 Standard (4:3)">
+ <screen index="1">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Screen 2 Standard (4:3)">
+ <screen index="2">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Screen 0 Pixel Aspect (~scr0nativexaspect~:~scr0nativeyaspect~)">
+ <screen index="0">
+ <bounds left="0" top="0" right="~scr0width~" bottom="~scr0height~" />
+ </screen>
+ </view>
+
+ <view name="Screen 1 Pixel Aspect (~scr1nativexaspect~:~scr1nativeyaspect~)">
+ <screen index="1">
+ <bounds left="0" top="0" right="~scr1width~" bottom="~scr1height~" />
+ </screen>
+ </view>
+
+ <view name="Screen 2 Pixel Aspect (~scr2nativexaspect~:~scr2nativeyaspect~)">
+ <screen index="2">
+ <bounds left="0" top="0" right="~scr2width~" bottom="~scr2height~" />
+ </screen>
+ </view>
+
+ <view name="Triple Side-by-Side">
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="4.03" y="0" width="4" height="3" />
+ </screen>
+ <screen index="2">
+ <bounds x="8.06" y="0" width="4" height="3" />
+ </screen>
+ </view>
+
+ <view name="Triple Side-by-Side (Gapless)">
+ <screen index="0">
+ <bounds x="0" y="0" width="4" height="3" />
+ </screen>
+ <screen index="1">
+ <bounds x="4" y="0" width="4" height="3" />
+ </screen>
+ <screen index="2">
+ <bounds x="8" y="0" width="4" height="3" />
+ </screen>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/vertical.lay b/src/emu/layout/vertical.lay
new file mode 100644
index 00000000000..2f6b3d88602
--- /dev/null
+++ b/src/emu/layout/vertical.lay
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <view name="Standard (3:4)">
+ <screen index="0">
+ <bounds left="0" top="0" right="3" bottom="4" />
+ </screen>
+ </view>
+
+ <view name="Pixel Aspect (~scr0nativeyaspect~:~scr0nativexaspect~)">
+ <screen index="0">
+ <bounds left="0" top="0" right="~scr0height~" bottom="~scr0width~" />
+ </screen>
+ </view>
+
+ <view name="Cocktail">
+ <screen index="0">
+ <bounds x="-3.03" y="0" width="3" height="4" />
+ <orientation rotate="180" />
+ </screen>
+ <screen index="0">
+ <bounds x="0" y="0" width="3" height="4" />
+ </screen>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/voffff20.lay b/src/emu/layout/voffff20.lay
new file mode 100644
index 00000000000..72ed5d25ee3
--- /dev/null
+++ b/src/emu/layout/voffff20.lay
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<mamelayout version="2">
+ <element name="overlay">
+ <rect>
+ <bounds left="0" top="0" right="1" bottom="1" />
+ <color red="1.0" green="1.0" blue="0.125" />
+ </rect>
+ </element>
+
+ <view name="Color Overlay">
+ <screen index="0">
+ <bounds left="0" top="0" right="3" bottom="4" />
+ </screen>
+ <overlay element="overlay">
+ <bounds left="0" top="0" right="3" bottom="4" />
+ </overlay>
+ </view>
+</mamelayout>
diff --git a/src/emu/machine/53c810.c b/src/emu/machine/53c810.c
new file mode 100644
index 00000000000..ec8b30fe50e
--- /dev/null
+++ b/src/emu/machine/53c810.c
@@ -0,0 +1,896 @@
+/* LSI Logic LSI53C810A PCI to SCSI I/O Processor */
+
+#include "driver.h"
+#include "53c810.h"
+
+#define DMA_MAX_ICOUNT 512 /* Maximum number of DMA Scripts opcodes to run */
+#define DASM_OPCODES 0
+
+static SCSIInstance *devices[8]; /* SCSI IDs 0-7 */
+static struct LSI53C810interface *intf;
+static UINT8 last_id;
+
+static struct {
+ UINT8 scntl0;
+ UINT8 scntl1;
+ UINT8 scntl2;
+ UINT8 scntl3;
+ UINT8 scid;
+ UINT8 socl;
+ UINT8 istat;
+ UINT8 dstat;
+ UINT8 sstat0;
+ UINT8 sstat1;
+ UINT8 sstat2;
+ UINT8 dien;
+ UINT8 dcntl;
+ UINT8 dmode;
+ UINT32 temp;
+ UINT32 dsa;
+ UINT32 dsp;
+ UINT32 dsps;
+ UINT32 dcmd;
+ UINT8 sien0;
+ UINT8 sien1;
+ UINT8 stime0;
+ UINT8 respid;
+ UINT8 stest1;
+ UINT8 scratch_a[4];
+ UINT8 scratch_b[4];
+ int dma_icount;
+ int halted;
+ int carry;
+ UINT32 (* fetch)(UINT32 dsp);
+ void (* irq_callback)(void);
+ void (* dma_callback)(UINT32, UINT32, int, int);
+} lsi810;
+
+static void (* dma_opcode[256])(void);
+
+
+INLINE UINT32 FETCH(void)
+{
+ UINT32 r = intf->fetch(lsi810.dsp);
+ lsi810.dsp += 4;
+ return r;
+}
+
+#ifdef UNUSED_FUNCTION
+static UINT32 sign_extend24(UINT32 val)
+{
+ if (val & 0x00800000)
+ val |= 0xFF000000;
+ else
+ val &= ~0xFF000000;
+ return val;
+}
+#endif
+
+static void dmaop_invalid(void)
+{
+ fatalerror("LSI53C810: Invalid SCRIPTS DMA opcode %08X at %08X", lsi810.dcmd, lsi810.dsp);
+}
+
+static void dmaop_move_memory(void)
+{
+ UINT32 src = FETCH();
+ UINT32 dst = FETCH();
+ int count;
+
+ count = lsi810.dcmd & 0xffffff;
+ if(intf->dma_callback != NULL) {
+ intf->dma_callback(src, dst, count, 1);
+ }
+}
+
+static void dmaop_interrupt(void)
+{
+ if(lsi810.dcmd & 0x100000) {
+ fatalerror("LSI53C810: INTFLY opcode not implemented");
+ }
+ lsi810.dsps = FETCH();
+
+ lsi810.istat |= 0x1; /* DMA interrupt pending */
+ lsi810.dstat |= 0x4; /* SIR (SCRIPTS Interrupt Instruction Received) */
+
+ if(intf->irq_callback != NULL) {
+ intf->irq_callback();
+ }
+ lsi810.dma_icount = 0;
+ lsi810.halted = 1;
+}
+
+static void dmaop_block_move(void)
+{
+ UINT32 address;
+ UINT32 count;
+ INT32 dsps;
+
+ address = FETCH();
+ count = lsi810.dcmd & 0x00ffffff;
+
+ // normal indirect
+ if (lsi810.dcmd & 0x20000000)
+ address = intf->fetch(address);
+
+ // table indirect
+ if (lsi810.dcmd & 0x10000000)
+ {
+ dsps = (INT32)address&0xffffff;
+ // sign extend
+ if (dsps & 0x00800000)
+ {
+ dsps |= 0xff000000;
+ }
+ logerror("table offset: %x, DSA = %x\n", dsps, lsi810.dsa);
+ dsps += lsi810.dsa;
+
+ logerror("Loading from table at %x\n", dsps);
+ count = lsi810.fetch(dsps);
+ address = lsi810.fetch(dsps+4);
+ }
+
+ logerror("block move: address %x count %x phase %x\n", address, count, (lsi810.dcmd>>24)&7);
+
+ if (lsi810.scntl0 & 0x01)
+ {
+ /* target mode */
+ fatalerror("LSI53C810: dmaop_block_move not implemented in target mode");
+ }
+ else
+ {
+ /* initiator mode */
+ logerror("53c810: block_move not actually implemented\n");
+ }
+}
+
+static void dmaop_select(void)
+{
+ UINT32 operand;
+
+ operand = FETCH();
+
+ if (lsi810.scntl0 & 0x01)
+ {
+ /* target mode */
+ logerror("LSI53C810: reselect ID #%d\n", (lsi810.dcmd >> 16) & 0x07);
+ }
+ else
+ {
+ /* initiator mode */
+ logerror("53c810: SELECT: our ID %d, target ID %d\n", lsi810.scid&7, (lsi810.dcmd>>16)&7);
+
+ lsi810.sstat1 &= ~0x07; // clear current bus phase
+ if (lsi810.dcmd & 0x01000000) // select with ATN
+ {
+ mame_printf_debug("53c810: want select with ATN, setting message phase\n");
+ lsi810.sstat1 |= 0x7; // ATN means we want message in phase
+ }
+ }
+}
+
+static void dmaop_wait_disconnect(void)
+{
+ UINT32 operand;
+
+ operand = FETCH();
+
+ if (lsi810.scntl0 & 0x01)
+ {
+ /* target mode */
+ fatalerror("LSI53C810: dmaop_wait_disconnect not implemented in target mode");
+ }
+ else
+ {
+ /* initiator mode */
+ fatalerror("LSI53C810: dmaop_wait_disconnect not implemented");
+ }
+}
+
+static void dmaop_wait_reselect(void)
+{
+ UINT32 operand;
+
+ operand = FETCH();
+
+ if (lsi810.scntl0 & 0x01)
+ {
+ /* target mode */
+ fatalerror("LSI53C810: dmaop_wait_reselect not implemented in target mode");
+ }
+ else
+ {
+ /* initiator mode */
+ fatalerror("LSI53C810: dmaop_wait_reselect not implemented");
+ }
+}
+
+static void dmaop_set(void)
+{
+ UINT32 operand;
+
+ operand = FETCH();
+
+ /* initiator mode */
+ if (lsi810.dcmd & 0x8)
+ {
+ // set ATN in SOCL
+ lsi810.socl |= 0x08;
+ }
+ if (lsi810.dcmd & 0x40)
+ {
+ // set ACK in SOCL
+ lsi810.socl |= 0x40;
+ }
+ if (lsi810.dcmd & 0x200)
+ {
+ // set target mode
+ lsi810.scntl0 |= 0x01;
+ }
+ if (lsi810.dcmd & 0x400)
+ {
+ // set carry in ALU
+ lsi810.carry = 1;
+ }
+}
+
+static void dmaop_clear(void)
+{
+ UINT32 operand;
+
+ operand = FETCH();
+
+ /* initiator mode */
+ if (lsi810.dcmd & 0x8)
+ {
+ // clear ATN in SOCL
+ lsi810.socl &= ~0x08;
+ }
+ if (lsi810.dcmd & 0x40)
+ {
+ // clear ACK in SOCL
+ lsi810.socl &= ~0x40;
+ }
+ if (lsi810.dcmd & 0x200)
+ {
+ // clear target mode
+ lsi810.scntl0 &= ~0x01;
+ }
+ if (lsi810.dcmd & 0x400)
+ {
+ // clear carry in ALU
+ lsi810.carry = 0;
+ }
+}
+
+static void dmaop_move_from_sfbr(void)
+{
+ fatalerror("LSI53C810: dmaop_move_from_sfbr not implemented in target mode");
+}
+
+static void dmaop_move_to_sfbr(void)
+{
+ fatalerror("LSI53C810: dmaop_move_to_sfbr not implemented");
+}
+
+static void dmaop_read_modify_write(void)
+{
+ fatalerror("LSI53C810: dmaop_read_modify_write not implemented");
+}
+
+static int scripts_compute_branch(void)
+{
+ int dtest, ptest, wanted, passed;
+
+// |jump if true
+// 878b0000 ||compare data
+// 1000 0111 1000 1011 0000 0000 0000 0000
+// | |rel ||wait valid phase
+// | |compare phase
+// |desired phase: message in
+
+ if (lsi810.dcmd & 0x00200000)
+ {
+ fatalerror("LSI53C810: jump with carry test not implemented");
+ }
+
+ if (lsi810.dcmd & 0x00100000)
+ {
+ fatalerror("LSI53C810: jump with interrupt on the fly not implemented");
+ }
+
+ // set desired result to take jump
+ wanted = (lsi810.dcmd & 0x00080000) ? 1 : 0;
+ // default to passing the tests in case they're disabled
+ dtest = ptest = wanted;
+
+ // phase test?
+ if (lsi810.dcmd & 0x00020000)
+ {
+ logerror("53c810: phase test. current: %x. target: %x\n", lsi810.sstat1 & 7, (lsi810.dcmd>>24)&7);
+
+ // do the phases match?
+ if (((lsi810.dcmd>>24)&7) == (lsi810.sstat1 & 7))
+ {
+ ptest = 1;
+ }
+ else
+ {
+ ptest = 0;
+ }
+ }
+
+ // data test?
+ if (lsi810.dcmd & 0x00040000)
+ {
+ logerror("53c810: data test. target: %x [not yet implemented]\n", lsi810.dcmd&0xff);
+}
+
+ // if all conditions go, take the jump
+ passed = 0;
+ if ((ptest == dtest) && (dtest == wanted))
+ {
+ passed = 1;
+ }
+
+ logerror("53c810: phase test %d data test %d wanted %d => pass %d\n", ptest, dtest, wanted, passed);
+
+ return passed;
+}
+
+static UINT32 scripts_get_jump_dest(void)
+{
+ INT32 dsps;
+ UINT32 dest;
+
+ dsps = FETCH();
+
+ /* relative or absolute addressing? */
+ if (lsi810.dcmd & 0x00800000)
+ {
+ // sign-extend the 24-bit value
+ if (dsps & 0x00800000)
+ {
+ dsps |= 0xff000000;
+ }
+
+ logerror("dsps = %x, dsp = %x\n", dsps, lsi810.dsp);
+ dsps += lsi810.dsp;
+}
+
+ dest = (UINT32)dsps;
+
+ logerror("cur DSP %x, dest %x\n", lsi810.dsp, dest);
+
+ return dest;
+}
+
+static void dmaop_jump(void)
+{
+ if (scripts_compute_branch())
+{
+ lsi810.dsp = scripts_get_jump_dest();
+ }
+ else
+ {
+ FETCH(); // skip operand to continue on
+ }
+}
+
+static void dmaop_call(void)
+{
+ if (scripts_compute_branch())
+ {
+ // save return address
+ lsi810.temp = lsi810.dsp;
+
+ // and go
+ lsi810.dsp = scripts_get_jump_dest();
+ }
+ else
+ {
+ FETCH(); // skip operand to continue on
+ }
+}
+
+static void dmaop_return(void)
+{
+ // is this correct? return only happens if the condition is true?
+ if (scripts_compute_branch())
+ {
+ // restore return address
+ lsi810.dsp = lsi810.temp;
+ }
+ else
+ {
+ FETCH(); // skip operand to continue on
+ }
+}
+
+static void dmaop_store(void)
+{
+ fatalerror("LSI53C810: dmaop_store not implemented");
+}
+
+static void dmaop_load(void)
+{
+ fatalerror("LSI53C810: dmaop_load not implemented");
+}
+
+
+
+static void dma_exec(void)
+{
+ lsi810.dma_icount = DMA_MAX_ICOUNT;
+
+ while(lsi810.dma_icount > 0)
+ {
+ int op;
+
+ if (DASM_OPCODES)
+ {
+ char buf[256];
+ lsi53c810_dasm(buf, lsi810.dsp);
+ logerror("0x%08X: %s\n", lsi810.dsp, buf);
+ }
+
+ lsi810.dcmd = FETCH();
+
+ op = (lsi810.dcmd >> 24) & 0xff;
+ dma_opcode[op]();
+
+ lsi810.dma_icount--;
+ }
+}
+
+UINT8 lsi53c810_reg_r(int reg)
+{
+ logerror("53c810: read reg %d:0x%x (PC=%x)\n", reg, reg, activecpu_get_pc());
+ switch(reg)
+ {
+ case 0x00: /* SCNTL0 */
+ return lsi810.scntl0;
+ case 0x01: /* SCNTL1 */
+ return lsi810.scntl1;
+ case 0x02: /* SCNTL2 */
+ return lsi810.scntl2;
+ case 0x03: /* SCNTL3 */
+ return lsi810.scntl3;
+ case 0x04: /* SCID */
+ return lsi810.scid;
+ case 0x09: /* SOCL */
+ return lsi810.socl;
+ case 0x0c: /* DSTAT */
+ return lsi810.dstat;
+ case 0x0d: /* SSTAT0 */
+ return lsi810.sstat0;
+ case 0x0e: /* SSTAT1 */
+ return lsi810.sstat1;
+ case 0x0f: /* SSTAT2 */
+ return lsi810.sstat2;
+ case 0x10: /* DSA [7-0] */
+ return lsi810.dsa & 0xff;
+ case 0x11: /* DSA [15-8] */
+ return (lsi810.dsa >> 8) & 0xff;
+ case 0x12: /* DSA [23-16] */
+ return (lsi810.dsa >> 16) & 0xff;
+ case 0x13: /* DSA [31-24] */
+ return (lsi810.dsa >> 24) & 0xff;
+ case 0x14: /* ISTAT */
+ return lsi810.istat;
+ case 0x2c: /* DSP [7-0] */
+ return lsi810.dsp & 0xff;
+ case 0x2d: /* DSP [15-8] */
+ return (lsi810.dsp >> 8) & 0xff;
+ case 0x2e: /* DSP [23-16] */
+ return (lsi810.dsp >> 16) & 0xff;
+ case 0x2f: /* DSP [31-24] */
+ return (lsi810.dsp >> 24) & 0xff;
+ case 0x34: /* SCRATCH A */
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ return lsi810.scratch_a[reg % 4];
+ case 0x39: /* DIEN */
+ return lsi810.dien;
+ case 0x3b: /* DCNTL */
+ return lsi810.dcntl;
+ case 0x40: /* SIEN0 */
+ return lsi810.sien0;
+ case 0x41: /* SIEN1 */
+ return lsi810.sien1;
+ case 0x48: /* STIME0 */
+ return lsi810.stime0;
+ case 0x4a: /* RESPID */
+ return lsi810.respid;
+ case 0x4d: /* STEST1 */
+ return lsi810.stest1;
+ case 0x5c: /* SCRATCH B */
+ case 0x5d:
+ case 0x5e:
+ case 0x5f:
+ return lsi810.scratch_b[reg % 4];
+
+ default:
+ fatalerror("LSI53C810: reg_r: Unknown reg %02X", reg);
+ }
+
+ return 0;
+}
+
+void lsi53c810_reg_w(int reg, UINT8 value)
+{
+ logerror("53c810: %02x to reg %d:0x%x (PC=%x)\n", value, reg, reg, activecpu_get_pc());
+ switch(reg)
+ {
+ case 0x00: /* SCNTL0 */
+ lsi810.scntl0 = value;
+ break;
+ case 0x01: /* SCNTL1 */
+ lsi810.scntl1 = value;
+ break;
+ case 0x02: /* SCNTL2 */
+ lsi810.scntl2 = value;
+ break;
+ case 0x03: /* SCNTL3 */
+ lsi810.scntl3 = value;
+ break;
+ case 0x04: /* SCID */
+ lsi810.scid = value;
+ break;
+ case 0x09: /* SOCL */
+ lsi810.socl = value;
+ break;
+ case 0x0d: /* SSTAT0 */
+ lsi810.sstat0 = value;
+ break;
+ case 0x0e: /* SSTAT1 */
+ lsi810.sstat1 = value;
+ break;
+ case 0x0f: /* SSTAT2 */
+ lsi810.sstat2 = value;
+ break;
+ case 0x10: /* DSA [7-0] */
+ lsi810.dsa &= 0xffffff00;
+ lsi810.dsa |= value;
+ break;
+ case 0x11: /* DSA [15-8] */
+ lsi810.dsa &= 0xffff00ff;
+ lsi810.dsa |= value << 8;
+ break;
+ case 0x12: /* DSA [23-16] */
+ lsi810.dsa &= 0xff00ffff;
+ lsi810.dsa |= value << 16;
+ break;
+ case 0x13: /* DSA [31-24] */
+ lsi810.dsa &= 0x00ffffff;
+ lsi810.dsa |= value << 24;
+ break;
+ case 0x14: /* ISTAT */
+ lsi810.istat = value;
+ break;
+ case 0x2c: /* DSP [7-0] */
+ lsi810.dsp &= 0xffffff00;
+ lsi810.dsp |= value;
+ break;
+ case 0x2d: /* DSP [15-8] */
+ lsi810.dsp &= 0xffff00ff;
+ lsi810.dsp |= value << 8;
+ break;
+ case 0x2e: /* DSP [23-16] */
+ lsi810.dsp &= 0xff00ffff;
+ lsi810.dsp |= value << 16;
+ break;
+ case 0x2f: /* DSP [31-24] */
+ lsi810.dsp &= 0x00ffffff;
+ lsi810.dsp |= value << 24;
+ lsi810.halted = 0;
+ if((lsi810.dmode & 0x1) == 0 && !lsi810.halted) {
+ dma_exec();
+ }
+ break;
+ case 0x34: /* SCRATCH A */
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ lsi810.scratch_a[reg % 4] = value;
+ break;
+ case 0x38: /* DMODE */
+ lsi810.dmode = value;
+ break;
+ case 0x39: /* DIEN */
+ lsi810.dien = value;
+ break;
+ case 0x3b: /* DCNTL */
+ lsi810.dcntl = value;
+
+ if(lsi810.dcntl & 0x14 && !lsi810.halted) /* single-step & start DMA */
+ {
+ int op;
+ lsi810.dcmd = FETCH();
+ op = (lsi810.dcmd >> 24) & 0xff;
+ dma_opcode[op]();
+
+ lsi810.istat |= 0x3; /* DMA interrupt pending */
+ lsi810.dstat |= 0x8; /* SSI (Single Step Interrupt) */
+ if(intf->irq_callback != NULL) {
+ intf->irq_callback();
+ }
+ }
+ else if(lsi810.dcntl & 0x04 && !lsi810.halted) /* manual start DMA */
+ {
+ dma_exec();
+ }
+ break;
+ case 0x40: /* SIEN0 */
+ lsi810.sien0 = value;
+ break;
+ case 0x41: /* SIEN1 */
+ lsi810.sien1 = value;
+ break;
+ case 0x48: /* STIME0 */
+ lsi810.stime0 = value;
+ break;
+ case 0x4a: /* RESPID */
+ lsi810.respid = value;
+ break;
+ case 0x4d: /* STEST1 */
+ lsi810.stest1 = value;
+ break;
+ case 0x5c: /* SCRATCH B */
+ case 0x5d:
+ case 0x5e:
+ case 0x5f:
+ lsi810.scratch_b[reg % 4] = value;
+ break;
+
+ default:
+ fatalerror("LSI53C810: reg_w: Unknown reg %02X, %02X", reg, value);
+ }
+}
+
+static void add_opcode(UINT8 op, UINT8 mask, void (* handler)(void))
+{
+ int i;
+ for(i=0; i < 256; i++) {
+ if((i & mask) == op) {
+ dma_opcode[i] = handler;
+ }
+ }
+}
+
+extern void lsi53c810_init(struct LSI53C810interface *interface)
+{
+ int i;
+
+ // save interface pointer for later
+ intf = interface;
+
+ memset(&lsi810, 0, sizeof(lsi810));
+ for(i = 0; i < 256; i++)
+ {
+ dma_opcode[i] = dmaop_invalid;
+ }
+
+ add_opcode(0x00, 0xc0, dmaop_block_move);
+ add_opcode(0x40, 0xf8, dmaop_select);
+ add_opcode(0x48, 0xf8, dmaop_wait_disconnect);
+ add_opcode(0x50, 0xf8, dmaop_wait_reselect);
+ add_opcode(0x58, 0xf8, dmaop_set);
+ add_opcode(0x60, 0xf8, dmaop_clear);
+ add_opcode(0x68, 0xf8, dmaop_move_from_sfbr);
+ add_opcode(0x70, 0xf8, dmaop_move_to_sfbr);
+ add_opcode(0x78, 0xf8, dmaop_read_modify_write);
+ add_opcode(0x80, 0xf8, dmaop_jump);
+ add_opcode(0x88, 0xf8, dmaop_call);
+ add_opcode(0x90, 0xf8, dmaop_return);
+ add_opcode(0x98, 0xf8, dmaop_interrupt);
+ add_opcode(0xc0, 0xfe, dmaop_move_memory);
+ add_opcode(0xe0, 0xed, dmaop_store);
+ add_opcode(0xe1, 0xed, dmaop_load);
+
+ memset(devices, 0, sizeof(devices));
+
+ // try to open the devices
+ for (i = 0; i < interface->scsidevs->devs_present; i++)
+ {
+ SCSIAllocInstance( interface->scsidevs->devices[i].scsiClass, &devices[interface->scsidevs->devices[i].scsiID], interface->scsidevs->devices[i].diskID );
+ }
+}
+
+void lsi53c810_read_data(int bytes, UINT8 *pData)
+{
+ if (devices[last_id])
+ {
+ SCSIReadData( devices[last_id], pData, bytes);
+ }
+ else
+ {
+ logerror("lsi53c810: read unknown device SCSI ID %d\n", last_id);
+ }
+}
+
+void lsi53c810_write_data(int bytes, UINT8 *pData)
+{
+ if (devices[last_id])
+ {
+ SCSIWriteData( devices[last_id], pData, bytes );
+ }
+ else
+ {
+ logerror("lsi53c810: write to unknown device SCSI ID %d\n", last_id);
+ }
+}
+
+void *lsi53c810_get_device(int id)
+{
+ void *ret;
+
+ if (devices[id])
+ {
+ logerror("lsi53c810: fetching dev pointer for SCSI ID %d\n", id);
+ SCSIGetDevice( devices[id], &ret );
+
+ return ret;
+ }
+
+ return NULL;
+}
+
+/*************************************
+ *
+ * Disassembler
+ *
+ *************************************/
+
+static UINT32 lsi53c810_dasm_fetch(UINT32 pc)
+{
+ return intf->fetch(pc);
+}
+
+unsigned lsi53c810_dasm(char *buf, UINT32 pc)
+{
+ unsigned result = 0;
+ const char *op_mnemonic = NULL;
+ UINT32 op = lsi53c810_dasm_fetch(pc);
+ UINT32 dest;
+ int i;
+
+ static const char *phases[] =
+ {
+ "DATA_OUT", "DATA_IN", "CMD", "STATUS",
+ "RESERVED_OUT??", "RESERVED_IN??", "MSG_OUT", "MSG_IN"
+ };
+
+ if ((op & 0xF8000000) == 0x40000000)
+ {
+ /* SELECT */
+ dest = lsi53c810_dasm_fetch(pc + 4);
+
+ buf += sprintf(buf, "SELECT%s %d, 0x%08X",
+ (op & 0x01000000) ? " ATN" : "",
+ (op >> 16) & 0x07,
+ dest);
+
+ result = 8;
+ }
+ else if (((op & 0xF8000000) == 0x58000000)
+ | ((op & 0xF8000000) == 0x60000000))
+ {
+ static struct
+ {
+ UINT32 flag;
+ const char *text;
+ } flags[] =
+ {
+ { 0x00000008, "ATN" },
+ { 0x00000040, "ACK" },
+ { 0x00000200, "TARGET" },
+ { 0x00000400, "CARRY" }
+ };
+ int need_cojunction = FALSE;
+
+ /* SET/CLEAR */
+ switch(op & 0xF8000000)
+ {
+ case 0x58000000: op_mnemonic = "SET"; break;
+ case 0x60000000: op_mnemonic = "CLEAR"; break;
+ }
+
+ buf += sprintf(buf, "%s ", op_mnemonic);
+ need_cojunction = FALSE;
+
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++)
+ {
+ if (op & flags[i].flag)
+ {
+ if (need_cojunction)
+ buf += sprintf(buf, " AND ");
+ else
+ need_cojunction = TRUE;
+ buf += sprintf(buf, "%s", flags[i].text);
+ }
+ }
+ }
+ else if (((op & 0xF8000000) == 0x80000000)
+ | ((op & 0xF8000000) == 0x88000000)
+ | ((op & 0xF8000000) == 0x98000000))
+ {
+ /* JUMP/CALL/INT */
+ switch(op & 0xF8000000)
+ {
+ case 0x80000000: op_mnemonic = "JUMP"; break;
+ case 0x88000000: op_mnemonic = "CALL"; break;
+ case 0x98000000: op_mnemonic = "INT"; break;
+ }
+
+ dest = lsi53c810_dasm_fetch(pc + 4);
+
+ if (op & 0x00800000)
+ {
+ /* relative */
+ if (dest & 0x00800000)
+ dest |= 0xFF000000;
+ else
+ dest &= 0x00FFFFFF;
+ dest = (pc + 8) + dest;
+ buf += sprintf(buf, "%s REL(0x%08X)", op_mnemonic, dest);
+ }
+ else
+ {
+ /* absolute */
+ buf += sprintf(buf, "%s 0x%08X", op_mnemonic, dest);
+ }
+
+ switch(op & 0x000B0000)
+ {
+ case 0x00000000:
+ buf += sprintf(buf, ", NOT??");
+ break;
+
+ case 0x00080000:
+ break;
+
+ case 0x00020000:
+ case 0x00030000:
+ case 0x000A0000:
+ case 0x000B0000:
+ buf += sprintf(buf, ", %s%s %s",
+ (op & 0x00010000) ? "WHEN" : "IF",
+ (op & 0x00080000) ? "" : " NOT",
+ phases[(op >> 24) & 0x07]);
+ break;
+
+ default:
+ fatalerror("unknown op 0x%08X", op);
+ break;
+ }
+ result = 8;
+ }
+ else if ((op & 0xE0000000) == 0x00000000)
+ {
+ /* MOVE FROM */
+ dest = lsi53c810_dasm_fetch(pc + 4);
+
+ buf += sprintf(buf, "MOVE FROM 0x%08X, WHEN %s",
+ dest, phases[(op >> 24) & 0x07]);
+
+ result = 8;
+ }
+ else if ((op & 0xE0000000) == 0x20000000)
+ {
+ /* MOVE PTR */
+ dest = lsi53c810_dasm_fetch(pc + 4);
+
+ buf += sprintf(buf, "MOVE 0x%08X, PTR 0x%08X, WHEN %s",
+ (op & 0x00FFFFFF), dest, phases[(op >> 24) & 0x07]);
+
+ result = 8;
+ }
+ else
+ {
+ fatalerror("unknown op 0x%08X", op);
+ }
+ return result;
+}
+
diff --git a/src/emu/machine/53c810.h b/src/emu/machine/53c810.h
new file mode 100644
index 00000000000..8cbb6065146
--- /dev/null
+++ b/src/emu/machine/53c810.h
@@ -0,0 +1,26 @@
+#ifndef LSI53C810_H
+#define LSI53C810_H
+
+#include "machine/scsi.h"
+
+struct LSI53C810interface
+{
+ SCSIConfigTable *scsidevs; /* SCSI devices */
+ void (*irq_callback)(void); /* IRQ callback */
+ void (*dma_callback)(UINT32, UINT32, int, int); /* DMA callback */
+ UINT32 (*fetch)(UINT32 dsp);
+};
+
+extern void lsi53c810_init(struct LSI53C810interface *interface);
+
+extern void lsi53c810_read_data(int bytes, UINT8 *pData);
+extern void lsi53c810_write_data(int bytes, UINT8 *pData);
+
+extern void *lsi53c810_get_device(int id);
+
+UINT8 lsi53c810_reg_r(int reg);
+void lsi53c810_reg_w(int reg, UINT8 value);
+
+unsigned lsi53c810_dasm(char *buf, UINT32 pc);
+
+#endif
diff --git a/src/emu/machine/6522via.c b/src/emu/machine/6522via.c
new file mode 100644
index 00000000000..21a067d8d3b
--- /dev/null
+++ b/src/emu/machine/6522via.c
@@ -0,0 +1,1153 @@
+/**********************************************************************
+
+ Rockwell 6522 VIA interface and emulation
+
+ This function emulates the functionality of up to 8 6522
+ versatile interface adapters.
+
+ This is based on the M6821 emulation in MAME.
+
+ To do:
+
+ T2 pulse counting mode
+ Pulse mode handshake output
+ More shift register
+
+**********************************************************************/
+
+/*
+ 1999-Dec-22 PeT
+ vc20 random number generation only partly working
+ (reads (uninitialized) timer 1 and timer 2 counter)
+ timer init, reset, read changed
+ */
+
+#include "driver.h"
+#include "6522via.h"
+
+//#define TRACE_VIA
+
+/******************* internal VIA data structure *******************/
+
+struct via6522
+{
+ const struct via6522_interface *intf;
+
+ UINT8 in_a;
+ UINT8 in_ca1;
+ UINT8 in_ca2;
+ UINT8 out_a;
+ UINT8 out_ca2;
+ UINT8 ddr_a;
+
+ UINT8 in_b;
+ UINT8 in_cb1;
+ UINT8 in_cb2;
+ UINT8 out_b;
+ UINT8 out_cb2;
+ UINT8 ddr_b;
+
+ UINT8 t1cl;
+ UINT8 t1ch;
+ UINT8 t1ll;
+ UINT8 t1lh;
+ UINT8 t2cl;
+ UINT8 t2ch;
+ UINT8 t2ll;
+ UINT8 t2lh;
+
+ UINT8 sr;
+ UINT8 pcr;
+ UINT8 acr;
+ UINT8 ier;
+ UINT8 ifr;
+
+ emu_timer *t1;
+ attotime time1;
+ UINT8 t1_active;
+ emu_timer *t2;
+ attotime time2;
+ UINT8 t2_active;
+ UINT8 shift_counter;
+
+ int clock;
+};
+
+
+/******************* convenince macros and defines *******************/
+
+/* Macros for PCR */
+#define CA1_LOW_TO_HIGH(c) (c & 0x01)
+#define CA1_HIGH_TO_LOW(c) (!(c & 0x01))
+
+#define CB1_LOW_TO_HIGH(c) (c & 0x10)
+#define CB1_HIGH_TO_LOW(c) (!(c & 0x10))
+
+#define CA2_INPUT(c) (!(c & 0x08))
+#define CA2_LOW_TO_HIGH(c) ((c & 0x0c) == 0x04)
+#define CA2_HIGH_TO_LOW(c) ((c & 0x0c) == 0x00)
+#define CA2_IND_IRQ(c) ((c & 0x0a) == 0x02)
+
+#define CA2_OUTPUT(c) (c & 0x08)
+#define CA2_AUTO_HS(c) ((c & 0x0c) == 0x08)
+#define CA2_HS_OUTPUT(c) ((c & 0x0e) == 0x08)
+#define CA2_PULSE_OUTPUT(c) ((c & 0x0e) == 0x0a)
+#define CA2_FIX_OUTPUT(c) ((c & 0x0c) == 0x0c)
+#define CA2_OUTPUT_LEVEL(c) ((c & 0x02) >> 1)
+
+#define CB2_INPUT(c) (!(c & 0x80))
+#define CB2_LOW_TO_HIGH(c) ((c & 0xc0) == 0x40)
+#define CB2_HIGH_TO_LOW(c) ((c & 0xc0) == 0x00)
+#define CB2_IND_IRQ(c) ((c & 0xa0) == 0x20)
+
+#define CB2_OUTPUT(c) (c & 0x80)
+#define CB2_AUTO_HS(c) ((c & 0xc0) == 0x80)
+#define CB2_HS_OUTPUT(c) ((c & 0xe0) == 0x80)
+#define CB2_PULSE_OUTPUT(c) ((c & 0xe0) == 0xa0)
+#define CB2_FIX_OUTPUT(c) ((c & 0xc0) == 0xc0)
+#define CB2_OUTPUT_LEVEL(c) ((c & 0x20) >> 5)
+
+/* Macros for ACR */
+#define PA_LATCH_ENABLE(c) (c & 0x01)
+#define PB_LATCH_ENABLE(c) (c & 0x02)
+
+#define SR_DISABLED(c) (!(c & 0x1c))
+#define SI_T2_CONTROL(c) ((c & 0x1c) == 0x04)
+#define SI_O2_CONTROL(c) ((c & 0x1c) == 0x08)
+#define SI_EXT_CONTROL(c) ((c & 0x1c) == 0x0c)
+#define SO_T2_RATE(c) ((c & 0x1c) == 0x10)
+#define SO_T2_CONTROL(c) ((c & 0x1c) == 0x14)
+#define SO_O2_CONTROL(c) ((c & 0x1c) == 0x18)
+#define SO_EXT_CONTROL(c) ((c & 0x1c) == 0x1c)
+
+#define T1_SET_PB7(c) (c & 0x80)
+#define T1_CONTINUOUS(c) (c & 0x40)
+#define T2_COUNT_PB6(c) (c & 0x20)
+
+/* Interrupt flags */
+#define INT_CA2 0x01
+#define INT_CA1 0x02
+#define INT_SR 0x04
+#define INT_CB2 0x08
+#define INT_CB1 0x10
+#define INT_T2 0x20
+#define INT_T1 0x40
+#define INT_ANY 0x80
+
+#define CLR_PA_INT(v, which) via_clear_int (which, INT_CA1 | ((!CA2_IND_IRQ(v->pcr)) ? INT_CA2: 0))
+#define CLR_PB_INT(v, which) via_clear_int (which, INT_CB1 | ((!CB2_IND_IRQ(v->pcr)) ? INT_CB2: 0))
+
+#define IFR_DELAY 3
+
+#define TIMER1_VALUE(v) (v->t1ll+(v->t1lh<<8))
+#define TIMER2_VALUE(v) (v->t2ll+(v->t2lh<<8))
+
+/******************* static variables *******************/
+
+static struct via6522 via[MAX_VIA];
+
+/******************* configuration *******************/
+
+void via_set_clock(int which,int clock)
+{
+ via[which].clock = clock;
+}
+
+void via_config(int which, const struct via6522_interface *intf)
+{
+ assert(which < MAX_VIA);
+
+ via[which].intf = intf;
+ via[which].t1ll = 0xf3; /* via at 0x9110 in vic20 show these values */
+ via[which].t1lh = 0xb5; /* ports are not written by kernel! */
+ via[which].t2ll = 0xff; /* taken from vice */
+ via[which].t2lh = 0xff;
+ via[which].time2 = via[which].time1 = timer_get_time();
+
+ /* Default clock is from CPU1 */
+ via_set_clock (which, Machine->drv->cpu[0].clock);
+}
+
+/******************* external interrupt check *******************/
+
+static void via_set_int (int which, int data)
+{
+ struct via6522 *v = via + which;
+
+
+ v->ifr |= data;
+#ifdef TRACE_VIA
+logerror("6522VIA chip %d: IFR = %02X. PC: %08X\n", which, v->ifr, safe_activecpu_get_pc());
+#endif
+
+ if (v->ier & v->ifr)
+ {
+ v->ifr |= INT_ANY;
+ if (v->intf->irq_func)
+ (*v->intf->irq_func)(ASSERT_LINE);
+ else
+ logerror("6522VIA chip %d: Interrupt is asserted but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+}
+
+static void via_clear_int (int which, int data)
+{
+ struct via6522 *v = via + which;
+
+
+ v->ifr = (v->ifr & ~data) & 0x7f;
+#ifdef TRACE_VIA
+logerror("6522VIA chip %d: IFR = %02X. PC: %08X\n", which, v->ifr, safe_activecpu_get_pc());
+#endif
+
+ if (v->ifr & v->ier)
+ v->ifr |= INT_ANY;
+ else
+ {
+ if (v->intf->irq_func)
+ (*v->intf->irq_func)(CLEAR_LINE);
+// else
+// logerror("6522VIA chip %d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+}
+
+
+INLINE attotime v_cycles_to_time(struct via6522 *v, int c)
+{
+ return attotime_mul(ATTOTIME_IN_HZ(v->clock), c);
+}
+
+
+INLINE UINT32 v_time_to_cycles(struct via6522 *v, attotime t)
+{
+ return attotime_to_double(attotime_mul(t, v->clock));
+}
+
+
+/************************ shift register ************************/
+
+static TIMER_CALLBACK( via_shift_callback );
+
+static void via_shift(int which)
+{
+ struct via6522 *v = via + which;
+
+ if (SO_O2_CONTROL(v->acr))
+ {
+ v->out_cb2 = (v->sr >> 7) & 1;
+ v->sr = (v->sr << 1) | v->out_cb2;
+
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, v->out_cb2);
+
+ v->in_cb1=1;
+ if (v->intf->out_cb1_func)
+ {
+ /* this should be one cycle wide */
+ v->intf->out_cb1_func(0, 0);
+ v->intf->out_cb1_func(0, 1);
+ }
+
+ v->shift_counter = (v->shift_counter + 1) % 8;
+
+ if (v->shift_counter)
+ timer_set(v_cycles_to_time(v, 2), which, via_shift_callback);
+ else
+ {
+ if (!(v->ifr & INT_SR))
+ via_set_int(which, INT_SR);
+ }
+ }
+ if (SO_EXT_CONTROL(v->acr))
+ {
+ v->out_cb2 = (v->sr >> 7) & 1;
+ v->sr = (v->sr << 1) | v->out_cb2;
+
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, v->out_cb2);
+
+ v->shift_counter = (v->shift_counter + 1) % 8;
+
+ if (v->shift_counter == 0)
+ {
+ if (!(v->ifr & INT_SR))
+ via_set_int(which, INT_SR);
+ }
+ }
+ if (SI_EXT_CONTROL(v->acr))
+ {
+ if (v->intf->in_cb2_func)
+ v->in_cb2 = v->intf->in_cb2_func(0);
+
+ v->sr = (v->sr << 1) | (v->in_cb2 & 1);
+
+ v->shift_counter = (v->shift_counter + 1) % 8;
+
+ if (v->shift_counter == 0)
+ {
+ if (!(v->ifr & INT_SR))
+ {
+ via_set_int(which, INT_SR);
+ }
+ }
+ }
+}
+
+static TIMER_CALLBACK( via_shift_callback )
+{
+ via_shift(param);
+}
+
+/******************* Timer timeouts *************************/
+
+static TIMER_CALLBACK( via_t1_timeout )
+{
+ int which = param;
+ struct via6522 *v = via + which;
+
+
+ if (T1_CONTINUOUS (v->acr))
+ {
+ if (T1_SET_PB7(v->acr))
+ v->out_b ^= 0x80;
+ timer_adjust(v->t1, v_cycles_to_time(v, TIMER1_VALUE(v) + IFR_DELAY), which, attotime_zero);
+ }
+ else
+ {
+ if (T1_SET_PB7(v->acr))
+ v->out_b |= 0x80;
+ v->t1_active = 0;
+ v->time1 = timer_get_time();
+ }
+ if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+
+ if (!(v->ifr & INT_T1))
+ via_set_int (which, INT_T1);
+}
+
+static TIMER_CALLBACK( via_t2_timeout )
+{
+ int which = param;
+ struct via6522 *v = via + which;
+
+ v->t2_active = 0;
+ v->time2 = timer_get_time();
+
+ if (!(v->ifr & INT_T2))
+ via_set_int (which, INT_T2);
+}
+
+/******************* reset *******************/
+
+void via_reset(void)
+{
+ int i;
+ struct via6522 v;
+
+ memset(&v, 0, sizeof(v));
+
+ for (i = 0; i < MAX_VIA; i++)
+ {
+ v.intf = via[i].intf;
+ v.t1ll = via[i].t1ll;
+ v.t1lh = via[i].t1lh;
+ v.t2ll = via[i].t2ll;
+ v.t2lh = via[i].t2lh;
+ v.time1 = via[i].time1;
+ v.time2 = via[i].time2;
+ v.clock = via[i].clock;
+
+ v.t1 = timer_alloc(via_t1_timeout);
+ v.t1_active = 0;
+ v.t2 = timer_alloc(via_t2_timeout);
+ v.t2_active = 0;
+
+ via[i] = v;
+ }
+}
+
+/******************* CPU interface for VIA read *******************/
+
+int via_read(int which, int offset)
+{
+ struct via6522 *v = via + which;
+ int val = 0;
+
+ offset &= 0xf;
+
+ switch (offset)
+ {
+ case VIA_PB:
+ /* update the input */
+ if (PB_LATCH_ENABLE(v->acr) == 0)
+ {
+ if (v->intf->in_b_func)
+ v->in_b = v->intf->in_b_func(0);
+ else
+ logerror("6522VIA chip %d: Port B is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ CLR_PB_INT(v, which);
+
+ /* combine input and output values, hold DDRB bit 7 high if T1_SET_PB7 */
+ if (T1_SET_PB7(v->acr))
+ val = (v->out_b & (v->ddr_b | 0x80)) | (v->in_b & ~(v->ddr_b | 0x80));
+ else
+ val = (v->out_b & v->ddr_b) + (v->in_b & ~v->ddr_b);
+ break;
+
+ case VIA_PA:
+ /* update the input */
+ if (PA_LATCH_ENABLE(v->acr) == 0)
+ {
+ if (v->intf->in_a_func)
+ v->in_a = v->intf->in_a_func(0);
+ else
+ logerror("6522VIA chip %d: Port A is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ /* combine input and output values */
+ val = (v->out_a & v->ddr_a) + (v->in_a & ~v->ddr_a);
+
+ CLR_PA_INT(v, which);
+
+ /* If CA2 is configured as output and in pulse or handshake mode,
+ CA2 is set now */
+ if (CA2_AUTO_HS(v->pcr))
+ {
+ if (v->out_ca2)
+ {
+ /* set CA2 */
+ v->out_ca2 = 0;
+
+ /* call the CA2 output function */
+ if (v->intf->out_ca2_func)
+ v->intf->out_ca2_func(0, 0);
+ else
+ logerror("6522VIA chip %d: Port CA2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 0);
+ }
+ }
+
+ break;
+
+ case VIA_PANH:
+ /* update the input */
+ if (PA_LATCH_ENABLE(v->acr) == 0)
+ {
+ if (v->intf->in_a_func)
+ v->in_a = v->intf->in_a_func(0);
+ else
+ logerror("6522VIA chip %d: Port A is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ /* combine input and output values */
+ val = (v->out_a & v->ddr_a) + (v->in_a & ~v->ddr_a);
+ break;
+
+ case VIA_DDRB:
+ val = v->ddr_b;
+ break;
+
+ case VIA_DDRA:
+ val = v->ddr_a;
+ break;
+
+ case VIA_T1CL:
+ via_clear_int (which, INT_T1);
+ if (v->t1_active)
+ val = v_time_to_cycles(v, timer_timeleft(v->t1)) & 0xff;
+ else
+ {
+ if ( T1_CONTINUOUS(v->acr) )
+ val = (TIMER1_VALUE(v) - (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time1)) % TIMER1_VALUE(v)) - 1) & 0xff;
+ else
+ val = (0x10000 - (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time1)) & 0xffff) - 1) & 0xff;
+ }
+ break;
+
+ case VIA_T1CH:
+ if (v->t1_active)
+ val = v_time_to_cycles(v, timer_timeleft(v->t1)) >> 8;
+ else
+ {
+ if ( T1_CONTINUOUS(v->acr) )
+ val = (TIMER1_VALUE(v)- (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time1)) % TIMER1_VALUE(v)) - 1) >> 8;
+ else
+ val = (0x10000- (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time1)) & 0xffff) - 1) >> 8;
+ }
+ break;
+
+ case VIA_T1LL:
+ val = v->t1ll;
+ break;
+
+ case VIA_T1LH:
+ val = v->t1lh;
+ break;
+
+ case VIA_T2CL:
+ via_clear_int (which, INT_T2);
+ if (v->t2_active)
+ val = v_time_to_cycles(v, timer_timeleft(v->t2)) & 0xff;
+ else
+ {
+ if (T2_COUNT_PB6(v->acr))
+ val = v->t2cl;
+ else
+ val = (0x10000- (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time2)) & 0xffff) - 1) & 0xff;
+ }
+ break;
+
+ case VIA_T2CH:
+ if (v->t2_active)
+ val = v_time_to_cycles(v, timer_timeleft(v->t2)) >> 8;
+ else
+ {
+ if (T2_COUNT_PB6(v->acr))
+ val = v->t2ch;
+ else
+ val = (0x10000- (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time2)) & 0xffff) - 1) >> 8;
+ }
+ break;
+
+ case VIA_SR:
+ val = v->sr;
+ via_clear_int(which, INT_SR);
+ if (SO_O2_CONTROL(v->acr))
+ {
+ v->shift_counter=0;
+ timer_set(v_cycles_to_time(v, 2), which,via_shift_callback);
+ }
+ break;
+
+ case VIA_PCR:
+ val = v->pcr;
+ break;
+
+ case VIA_ACR:
+ val = v->acr;
+ break;
+
+ case VIA_IER:
+ val = v->ier | 0x80;
+ break;
+
+ case VIA_IFR:
+ val = v->ifr;
+ break;
+ }
+ return val;
+}
+
+
+/******************* CPU interface for VIA write *******************/
+
+void via_write(int which, int offset, int data)
+{
+ struct via6522 *v = via + which;
+
+ offset &=0x0f;
+
+ switch (offset)
+ {
+ case VIA_PB:
+ if (T1_SET_PB7(v->acr))
+ v->out_b = (v->out_b & 0x80) | (data & 0x7f);
+ else
+ v->out_b = data;
+
+ if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+
+ CLR_PB_INT(v, which);
+
+ /* If CB2 is configured as output and in pulse or handshake mode,
+ CB2 is set now */
+ if (CB2_AUTO_HS(v->pcr))
+ {
+ if (v->out_cb2)
+ {
+ /* set CB2 */
+ v->out_cb2 = 0;
+
+ /* call the CB2 output function */
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, 0);
+ else
+ logerror("6522VIA chip %d: Port CB2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 0);
+ }
+ }
+ break;
+
+ case VIA_PA:
+ v->out_a = data;
+
+ if (v->ddr_a)
+ {
+ UINT8 write_data = (v->out_a & v->ddr_a) | (v->ddr_a ^ 0xff);
+
+ if (v->intf->out_a_func)
+ v->intf->out_a_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port A is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+
+ CLR_PA_INT(v, which);
+
+ /* If CA2 is configured as output and in pulse or handshake mode,
+ CA2 is set now */
+ if (CA2_PULSE_OUTPUT(v->pcr))
+ {
+ /* call the CA2 output function */
+ if (v->intf->out_ca2_func)
+ {
+ v->intf->out_ca2_func(0, 0);
+ v->intf->out_ca2_func(0, 1);
+ }
+ else
+ logerror("6522VIA chip %d: Port CA2 is being pulsed but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+
+ /* set CA2 (shouldn't be needed) */
+ v->out_ca2 = 1;
+ }
+ else if (CA2_AUTO_HS(v->pcr))
+ {
+ if (v->out_ca2)
+ {
+ /* set CA2 */
+ v->out_ca2 = 0;
+
+ /* call the CA2 output function */
+ if (v->intf->out_ca2_func)
+ v->intf->out_ca2_func(0, 0);
+ else
+ logerror("6522VIA chip %d: Port CA2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 0);
+ }
+ }
+
+ break;
+
+ case VIA_PANH:
+ v->out_a = data;
+
+ if (v->ddr_a)
+ {
+ UINT8 write_data = (v->out_a & v->ddr_a) | (v->ddr_a ^ 0xff);
+
+ if (v->intf->out_a_func)
+ v->intf->out_a_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port A is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+
+ break;
+
+ case VIA_DDRB:
+ /* EHC 03/04/2000 - If data direction changed, present output on the lines */
+ if ( data != v->ddr_b )
+ {
+ v->ddr_b = data;
+
+ //if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ }
+ break;
+
+ case VIA_DDRA:
+ /* EHC 03/04/2000 - If data direction changed, present output on the lines */
+ if ( data != v->ddr_a )
+ {
+ v->ddr_a = data;
+
+ //if (v->ddr_a)
+ {
+ UINT8 write_data = (v->out_a & v->ddr_a) | (v->ddr_a ^ 0xff);
+
+ if (v->intf->out_a_func)
+ v->intf->out_a_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port A is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ }
+ break;
+
+ case VIA_T1CL:
+ case VIA_T1LL:
+ v->t1ll = data;
+ break;
+
+ case VIA_T1LH:
+ v->t1lh = data;
+ via_clear_int (which, INT_T1);
+ break;
+
+ case VIA_T1CH:
+ v->t1ch = v->t1lh = data;
+ v->t1cl = v->t1ll;
+
+ via_clear_int (which, INT_T1);
+
+ if (T1_SET_PB7(v->acr))
+ {
+ v->out_b &= 0x7f;
+
+ //if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ }
+ timer_adjust(v->t1, v_cycles_to_time(v, TIMER1_VALUE(v) + IFR_DELAY), which, attotime_zero);
+ v->t1_active = 1;
+ break;
+
+ case VIA_T2CL:
+ v->t2ll = data;
+ break;
+
+ case VIA_T2CH:
+ v->t2ch = v->t2lh = data;
+ v->t2cl = v->t2ll;
+
+ via_clear_int (which, INT_T2);
+
+ if (!T2_COUNT_PB6(v->acr))
+ {
+ timer_adjust(v->t2, v_cycles_to_time(v, TIMER2_VALUE(v) + IFR_DELAY), which, attotime_zero);
+ v->t2_active = 1;
+ }
+ else
+ {
+ v->time2 = timer_get_time();
+ }
+ break;
+
+ case VIA_SR:
+ v->sr = data;
+ v->shift_counter=0;
+ via_clear_int(which, INT_SR);
+ if (SO_O2_CONTROL(v->acr))
+ {
+ timer_set(v_cycles_to_time(v, 2), which,via_shift_callback);
+ }
+ break;
+
+ case VIA_PCR:
+ v->pcr = data;
+#ifdef TRACE_VIA
+logerror("6522VIA chip %d: PCR = %02X. PC: %08X\n", which, data, safe_activecpu_get_pc());
+#endif
+
+ if (CA2_FIX_OUTPUT(data) && CA2_OUTPUT_LEVEL(data) ^ v->out_ca2)
+ {
+ v->out_ca2 = CA2_OUTPUT_LEVEL(data);
+ if (v->intf->out_ca2_func)
+ v->intf->out_ca2_func(0, v->out_ca2);
+ else
+ logerror("6522VIA chip %d: Port CA2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), v->out_ca2);
+ }
+
+ if (CB2_FIX_OUTPUT(data) && CB2_OUTPUT_LEVEL(data) ^ v->out_cb2)
+ {
+ v->out_cb2 = CB2_OUTPUT_LEVEL(data);
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, v->out_cb2);
+ else
+ logerror("6522VIA chip %d: Port CB2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), v->out_cb2);
+ }
+ break;
+
+ case VIA_ACR:
+ v->acr = data;
+ if (T1_SET_PB7(v->acr))
+ {
+ if (v->t1_active)
+ v->out_b &= ~0x80;
+ else
+ v->out_b |= 0x80;
+
+ //if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ }
+ if (T1_CONTINUOUS(data))
+ {
+ timer_adjust(v->t1, v_cycles_to_time(v, TIMER1_VALUE(v) + IFR_DELAY), which, attotime_zero);
+ v->t1_active = 1;
+ }
+ break;
+
+ case VIA_IER:
+ if (data & 0x80)
+ v->ier |= data & 0x7f;
+ else
+ v->ier &= ~(data & 0x7f);
+
+ if (v->ifr & INT_ANY)
+ {
+ if (((v->ifr & v->ier) & 0x7f) == 0)
+ {
+ v->ifr &= ~INT_ANY;
+ if (v->intf->irq_func)
+ (*v->intf->irq_func)(CLEAR_LINE);
+// else
+// logerror("6522VIA chip %d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+ }
+ else
+ {
+ if ((v->ier & v->ifr) & 0x7f)
+ {
+ v->ifr |= INT_ANY;
+ if (v->intf->irq_func)
+ (*v->intf->irq_func)(ASSERT_LINE);
+ else
+ logerror("6522VIA chip %d: Interrupt is asserted but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+ }
+ break;
+
+ case VIA_IFR:
+ if (data & INT_ANY)
+ data = 0x7f;
+ via_clear_int (which, data);
+ break;
+ }
+}
+
+/******************* interface setting VIA port A input *******************/
+
+void via_set_input_a(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* set the input, what could be easier? */
+ v->in_a = data;
+}
+
+/******************* interface setting VIA port CA1 input *******************/
+
+void via_set_input_ca1(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* handle the active transition */
+ if (data != v->in_ca1)
+ {
+#ifdef TRACE_VIA
+logerror("6522VIA chip %d: CA1 = %02X. PC: %08X\n", which, data, safe_activecpu_get_pc());
+#endif
+ if ((CA1_LOW_TO_HIGH(v->pcr) && data) || (CA1_HIGH_TO_LOW(v->pcr) && !data))
+ {
+ if (PA_LATCH_ENABLE(v->acr))
+ {
+ if (v->intf->in_a_func)
+ v->in_a = v->intf->in_a_func(0);
+ else
+ logerror("6522VIA chip %d: Port A is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ via_set_int (which, INT_CA1);
+
+ /* CA2 is configured as output and in pulse or handshake mode,
+ CA2 is cleared now */
+ if (CA2_AUTO_HS(v->pcr))
+ {
+ if (!v->out_ca2)
+ {
+ /* clear CA2 */
+ v->out_ca2 = 1;
+
+ /* call the CA2 output function */
+ if (v->intf->out_ca2_func)
+ v->intf->out_ca2_func(0, 1);
+ else
+ logerror("6522VIA chip %d: Port CA2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 1);
+ }
+ }
+ }
+
+ v->in_ca1 = data;
+ }
+}
+
+/******************* interface setting VIA port CA2 input *******************/
+
+void via_set_input_ca2(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* CA2 is in input mode */
+ if (CA2_INPUT(v->pcr))
+ {
+ /* the new state has caused a transition */
+ if (v->in_ca2 != data)
+ {
+ /* handle the active transition */
+ if ((data && CA2_LOW_TO_HIGH(v->pcr)) || (!data && CA2_HIGH_TO_LOW(v->pcr)))
+ {
+ /* mark the IRQ */
+ via_set_int (which, INT_CA2);
+ }
+ /* set the new value for CA2 */
+ v->in_ca2 = data;
+ }
+ }
+
+
+}
+
+/******************* interface setting VIA port B input *******************/
+
+void via_set_input_b(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* set the input, what could be easier? */
+ v->in_b = data;
+}
+
+
+
+/******************* interface setting VIA port CB1 input *******************/
+
+void via_set_input_cb1(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* handle the active transition */
+ if (data != v->in_cb1)
+ {
+ if ((CB1_LOW_TO_HIGH(v->pcr) && data) || (CB1_HIGH_TO_LOW(v->pcr) && !data))
+ {
+ if (PB_LATCH_ENABLE(v->acr))
+ {
+ if (v->intf->in_b_func)
+ v->in_b = v->intf->in_b_func(0);
+ else
+ logerror("6522VIA chip %d: Port B is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+ if (SO_EXT_CONTROL(v->acr) || SI_EXT_CONTROL(v->acr))
+ via_shift (which);
+
+ via_set_int (which, INT_CB1);
+
+ /* CB2 is configured as output and in pulse or handshake mode,
+ CB2 is cleared now */
+ if (CB2_AUTO_HS(v->pcr))
+ {
+ if (!v->out_cb2)
+ {
+ /* clear CB2 */
+ v->out_cb2 = 1;
+
+ /* call the CB2 output function */
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, 1);
+ else
+ logerror("6522VIA chip %d: Port CB2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 1);
+ }
+ }
+ }
+ v->in_cb1 = data;
+ }
+}
+
+/******************* interface setting VIA port CB2 input *******************/
+
+void via_set_input_cb2(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* CB2 is in input mode */
+ if (CB2_INPUT(v->pcr))
+ {
+ /* the new state has caused a transition */
+ if (v->in_cb2 != data)
+ {
+ /* handle the active transition */
+ if ((data && CB2_LOW_TO_HIGH(v->pcr)) || (!data && CB2_HIGH_TO_LOW(v->pcr)))
+ {
+ /* mark the IRQ */
+ via_set_int (which, INT_CB2);
+ }
+ /* set the new value for CB2 */
+ v->in_cb2 = data;
+ }
+ }
+}
+
+/******************* Standard 8-bit CPU interfaces, D0-D7 *******************/
+
+READ8_HANDLER( via_0_r) { return via_read(0, offset); }
+READ8_HANDLER( via_1_r) { return via_read(1, offset); }
+READ8_HANDLER( via_2_r) { return via_read(2, offset); }
+READ8_HANDLER( via_3_r) { return via_read(3, offset); }
+READ8_HANDLER( via_4_r) { return via_read(4, offset); }
+READ8_HANDLER( via_5_r) { return via_read(5, offset); }
+READ8_HANDLER( via_6_r) { return via_read(6, offset); }
+READ8_HANDLER( via_7_r) { return via_read(7, offset); }
+
+WRITE8_HANDLER( via_0_w) { via_write(0, offset, data); }
+WRITE8_HANDLER( via_1_w) { via_write(1, offset, data); }
+WRITE8_HANDLER( via_2_w) { via_write(2, offset, data); }
+WRITE8_HANDLER( via_3_w) { via_write(3, offset, data); }
+WRITE8_HANDLER( via_4_w) { via_write(4, offset, data); }
+WRITE8_HANDLER( via_5_w) { via_write(5, offset, data); }
+WRITE8_HANDLER( via_6_w) { via_write(6, offset, data); }
+WRITE8_HANDLER( via_7_w) { via_write(7, offset, data); }
+
+/******************* 8-bit A/B port interfaces *******************/
+
+WRITE8_HANDLER( via_0_porta_w) { via_set_input_a(0, data); }
+WRITE8_HANDLER( via_1_porta_w) { via_set_input_a(1, data); }
+WRITE8_HANDLER( via_2_porta_w) { via_set_input_a(2, data); }
+WRITE8_HANDLER( via_3_porta_w) { via_set_input_a(3, data); }
+WRITE8_HANDLER( via_4_porta_w) { via_set_input_a(4, data); }
+WRITE8_HANDLER( via_5_porta_w) { via_set_input_a(5, data); }
+WRITE8_HANDLER( via_6_porta_w) { via_set_input_a(6, data); }
+WRITE8_HANDLER( via_7_porta_w) { via_set_input_a(7, data); }
+
+WRITE8_HANDLER( via_0_portb_w) { via_set_input_b(0, data); }
+WRITE8_HANDLER( via_1_portb_w) { via_set_input_b(1, data); }
+WRITE8_HANDLER( via_2_portb_w) { via_set_input_b(2, data); }
+WRITE8_HANDLER( via_3_portb_w) { via_set_input_b(3, data); }
+WRITE8_HANDLER( via_4_portb_w) { via_set_input_b(4, data); }
+WRITE8_HANDLER( via_5_portb_w) { via_set_input_b(5, data); }
+WRITE8_HANDLER( via_6_portb_w) { via_set_input_b(6, data); }
+WRITE8_HANDLER( via_7_portb_w) { via_set_input_b(7, data); }
+
+READ8_HANDLER( via_0_porta_r) { return via[0].in_a; }
+READ8_HANDLER( via_1_porta_r) { return via[1].in_a; }
+READ8_HANDLER( via_2_porta_r) { return via[2].in_a; }
+READ8_HANDLER( via_3_porta_r) { return via[3].in_a; }
+READ8_HANDLER( via_4_porta_r) { return via[4].in_a; }
+READ8_HANDLER( via_5_porta_r) { return via[5].in_a; }
+READ8_HANDLER( via_6_porta_r) { return via[6].in_a; }
+READ8_HANDLER( via_7_porta_r) { return via[7].in_a; }
+
+READ8_HANDLER( via_0_portb_r) { return via[0].in_b; }
+READ8_HANDLER( via_1_portb_r) { return via[1].in_b; }
+READ8_HANDLER( via_2_portb_r) { return via[2].in_b; }
+READ8_HANDLER( via_3_portb_r) { return via[3].in_b; }
+READ8_HANDLER( via_4_portb_r) { return via[4].in_b; }
+READ8_HANDLER( via_5_portb_r) { return via[5].in_b; }
+READ8_HANDLER( via_6_portb_r) { return via[6].in_b; }
+READ8_HANDLER( via_7_portb_r) { return via[7].in_b; }
+
+/******************* 1-bit CA1/CA2/CB1/CB2 port interfaces *******************/
+
+WRITE8_HANDLER( via_0_ca1_w) { via_set_input_ca1(0, data); }
+WRITE8_HANDLER( via_1_ca1_w) { via_set_input_ca1(1, data); }
+WRITE8_HANDLER( via_2_ca1_w) { via_set_input_ca1(2, data); }
+WRITE8_HANDLER( via_3_ca1_w) { via_set_input_ca1(3, data); }
+WRITE8_HANDLER( via_4_ca1_w) { via_set_input_ca1(4, data); }
+WRITE8_HANDLER( via_5_ca1_w) { via_set_input_ca1(5, data); }
+WRITE8_HANDLER( via_6_ca1_w) { via_set_input_ca1(6, data); }
+WRITE8_HANDLER( via_7_ca1_w) { via_set_input_ca1(7, data); }
+WRITE8_HANDLER( via_0_ca2_w) { via_set_input_ca2(0, data); }
+WRITE8_HANDLER( via_1_ca2_w) { via_set_input_ca2(1, data); }
+WRITE8_HANDLER( via_2_ca2_w) { via_set_input_ca2(2, data); }
+WRITE8_HANDLER( via_3_ca2_w) { via_set_input_ca2(3, data); }
+WRITE8_HANDLER( via_4_ca2_w) { via_set_input_ca2(4, data); }
+WRITE8_HANDLER( via_5_ca2_w) { via_set_input_ca2(5, data); }
+WRITE8_HANDLER( via_6_ca2_w) { via_set_input_ca2(6, data); }
+WRITE8_HANDLER( via_7_ca2_w) { via_set_input_ca2(7, data); }
+
+WRITE8_HANDLER( via_0_cb1_w) { via_set_input_cb1(0, data); }
+WRITE8_HANDLER( via_1_cb1_w) { via_set_input_cb1(1, data); }
+WRITE8_HANDLER( via_2_cb1_w) { via_set_input_cb1(2, data); }
+WRITE8_HANDLER( via_3_cb1_w) { via_set_input_cb1(3, data); }
+WRITE8_HANDLER( via_4_cb1_w) { via_set_input_cb1(4, data); }
+WRITE8_HANDLER( via_5_cb1_w) { via_set_input_cb1(5, data); }
+WRITE8_HANDLER( via_6_cb1_w) { via_set_input_cb1(6, data); }
+WRITE8_HANDLER( via_7_cb1_w) { via_set_input_cb1(7, data); }
+WRITE8_HANDLER( via_0_cb2_w) { via_set_input_cb2(0, data); }
+WRITE8_HANDLER( via_1_cb2_w) { via_set_input_cb2(1, data); }
+WRITE8_HANDLER( via_2_cb2_w) { via_set_input_cb2(2, data); }
+WRITE8_HANDLER( via_3_cb2_w) { via_set_input_cb2(3, data); }
+WRITE8_HANDLER( via_4_cb2_w) { via_set_input_cb2(4, data); }
+WRITE8_HANDLER( via_5_cb2_w) { via_set_input_cb2(5, data); }
+WRITE8_HANDLER( via_6_cb2_w) { via_set_input_cb2(6, data); }
+WRITE8_HANDLER( via_7_cb2_w) { via_set_input_cb2(7, data); }
+
+READ8_HANDLER( via_0_ca1_r) { return via[0].in_ca1; }
+READ8_HANDLER( via_1_ca1_r) { return via[1].in_ca1; }
+READ8_HANDLER( via_2_ca1_r) { return via[2].in_ca1; }
+READ8_HANDLER( via_3_ca1_r) { return via[3].in_ca1; }
+READ8_HANDLER( via_4_ca1_r) { return via[4].in_ca1; }
+READ8_HANDLER( via_5_ca1_r) { return via[5].in_ca1; }
+READ8_HANDLER( via_6_ca1_r) { return via[6].in_ca1; }
+READ8_HANDLER( via_7_ca1_r) { return via[7].in_ca1; }
+READ8_HANDLER( via_0_ca2_r) { return via[0].in_ca2; }
+READ8_HANDLER( via_1_ca2_r) { return via[1].in_ca2; }
+READ8_HANDLER( via_2_ca2_r) { return via[2].in_ca2; }
+READ8_HANDLER( via_3_ca2_r) { return via[3].in_ca2; }
+READ8_HANDLER( via_4_ca2_r) { return via[4].in_ca2; }
+READ8_HANDLER( via_5_ca2_r) { return via[5].in_ca2; }
+READ8_HANDLER( via_6_ca2_r) { return via[6].in_ca2; }
+READ8_HANDLER( via_7_ca2_r) { return via[7].in_ca2; }
+
+READ8_HANDLER( via_0_cb1_r) { return via[0].in_cb1; }
+READ8_HANDLER( via_1_cb1_r) { return via[1].in_cb1; }
+READ8_HANDLER( via_2_cb1_r) { return via[2].in_cb1; }
+READ8_HANDLER( via_3_cb1_r) { return via[3].in_cb1; }
+READ8_HANDLER( via_4_cb1_r) { return via[4].in_cb1; }
+READ8_HANDLER( via_5_cb1_r) { return via[5].in_cb1; }
+READ8_HANDLER( via_6_cb1_r) { return via[6].in_cb1; }
+READ8_HANDLER( via_7_cb1_r) { return via[7].in_cb1; }
+READ8_HANDLER( via_0_cb2_r) { return via[0].in_cb2; }
+READ8_HANDLER( via_1_cb2_r) { return via[1].in_cb2; }
+READ8_HANDLER( via_2_cb2_r) { return via[2].in_cb2; }
+READ8_HANDLER( via_3_cb2_r) { return via[3].in_cb2; }
+READ8_HANDLER( via_4_cb2_r) { return via[4].in_cb2; }
+READ8_HANDLER( via_5_cb2_r) { return via[5].in_cb2; }
+READ8_HANDLER( via_6_cb2_r) { return via[6].in_cb2; }
+READ8_HANDLER( via_7_cb2_r) { return via[7].in_cb2; }
+
+
+#undef TRACE_VIA
diff --git a/src/emu/machine/6522via.h b/src/emu/machine/6522via.h
new file mode 100644
index 00000000000..f4e52b6db6c
--- /dev/null
+++ b/src/emu/machine/6522via.h
@@ -0,0 +1,195 @@
+/**********************************************************************
+
+ Rockwell 6522 VIA interface and emulation
+
+ This function emulates all the functionality of up to 8 6522
+ versatile interface adapters.
+
+ This is based on the M6821 emulation in MAME.
+
+ Written by Mathis Rosenhauer
+
+**********************************************************************/
+
+#ifndef VIA_6522
+#define VIA_6522
+
+
+#define MAX_VIA 8
+
+#define VIA_PB 0
+#define VIA_PA 1
+#define VIA_DDRB 2
+#define VIA_DDRA 3
+#define VIA_T1CL 4
+#define VIA_T1CH 5
+#define VIA_T1LL 6
+#define VIA_T1LH 7
+#define VIA_T2CL 8
+#define VIA_T2CH 9
+#define VIA_SR 10
+#define VIA_ACR 11
+#define VIA_PCR 12
+#define VIA_IFR 13
+#define VIA_IER 14
+#define VIA_PANH 15
+
+struct via6522_interface
+{
+ read8_handler in_a_func;
+ read8_handler in_b_func;
+ read8_handler in_ca1_func;
+ read8_handler in_cb1_func;
+ read8_handler in_ca2_func;
+ read8_handler in_cb2_func;
+ write8_handler out_a_func;
+ write8_handler out_b_func;
+ write8_handler out_ca1_func;
+ write8_handler out_cb1_func;
+ write8_handler out_ca2_func;
+ write8_handler out_cb2_func;
+ void (*irq_func)(int state);
+};
+
+void via_set_clock(int which,int clck);
+void via_config(int which, const struct via6522_interface *intf);
+void via_reset(void);
+int via_read(int which, int offset);
+void via_write(int which, int offset, int data);
+void via_set_input_a(int which, int data);
+void via_set_input_ca1(int which, int data);
+void via_set_input_ca2(int which, int data);
+void via_set_input_b(int which, int data);
+void via_set_input_cb1(int which, int data);
+void via_set_input_cb2(int which, int data);
+
+/******************* Standard 8-bit CPU interfaces, D0-D7 *******************/
+
+READ8_HANDLER( via_0_r );
+READ8_HANDLER( via_1_r );
+READ8_HANDLER( via_2_r );
+READ8_HANDLER( via_3_r );
+READ8_HANDLER( via_4_r );
+READ8_HANDLER( via_5_r );
+READ8_HANDLER( via_6_r );
+READ8_HANDLER( via_7_r );
+
+WRITE8_HANDLER( via_0_w );
+WRITE8_HANDLER( via_1_w );
+WRITE8_HANDLER( via_2_w );
+WRITE8_HANDLER( via_3_w );
+WRITE8_HANDLER( via_4_w );
+WRITE8_HANDLER( via_5_w );
+WRITE8_HANDLER( via_6_w );
+WRITE8_HANDLER( via_7_w );
+
+/******************* 8-bit A/B port interfaces *******************/
+
+WRITE8_HANDLER( via_0_porta_w );
+WRITE8_HANDLER( via_1_porta_w );
+WRITE8_HANDLER( via_2_porta_w );
+WRITE8_HANDLER( via_3_porta_w );
+WRITE8_HANDLER( via_4_porta_w );
+WRITE8_HANDLER( via_5_porta_w );
+WRITE8_HANDLER( via_6_porta_w );
+WRITE8_HANDLER( via_7_porta_w );
+
+WRITE8_HANDLER( via_0_portb_w );
+WRITE8_HANDLER( via_1_portb_w );
+WRITE8_HANDLER( via_2_portb_w );
+WRITE8_HANDLER( via_3_portb_w );
+WRITE8_HANDLER( via_4_portb_w );
+WRITE8_HANDLER( via_5_portb_w );
+WRITE8_HANDLER( via_6_portb_w );
+WRITE8_HANDLER( via_7_portb_w );
+
+READ8_HANDLER( via_0_porta_r );
+READ8_HANDLER( via_1_porta_r );
+READ8_HANDLER( via_2_porta_r );
+READ8_HANDLER( via_3_porta_r );
+READ8_HANDLER( via_4_porta_r );
+READ8_HANDLER( via_5_porta_r );
+READ8_HANDLER( via_6_porta_r );
+READ8_HANDLER( via_7_porta_r );
+
+READ8_HANDLER( via_0_portb_r );
+READ8_HANDLER( via_1_portb_r );
+READ8_HANDLER( via_2_portb_r );
+READ8_HANDLER( via_3_portb_r );
+READ8_HANDLER( via_4_portb_r );
+READ8_HANDLER( via_5_portb_r );
+READ8_HANDLER( via_6_portb_r );
+READ8_HANDLER( via_7_portb_r );
+
+/******************* 1-bit CA1/CA2/CB1/CB2 port interfaces *******************/
+
+WRITE8_HANDLER( via_0_ca1_w );
+WRITE8_HANDLER( via_1_ca1_w );
+WRITE8_HANDLER( via_2_ca1_w );
+WRITE8_HANDLER( via_3_ca1_w );
+WRITE8_HANDLER( via_4_ca1_w );
+WRITE8_HANDLER( via_5_ca1_w );
+WRITE8_HANDLER( via_6_ca1_w );
+WRITE8_HANDLER( via_7_ca1_w );
+WRITE8_HANDLER( via_0_ca2_w );
+WRITE8_HANDLER( via_1_ca2_w );
+WRITE8_HANDLER( via_2_ca2_w );
+WRITE8_HANDLER( via_3_ca2_w );
+WRITE8_HANDLER( via_4_ca2_w );
+WRITE8_HANDLER( via_5_ca2_w );
+WRITE8_HANDLER( via_6_ca2_w );
+WRITE8_HANDLER( via_7_ca2_w );
+
+WRITE8_HANDLER( via_0_cb1_w );
+WRITE8_HANDLER( via_1_cb1_w );
+WRITE8_HANDLER( via_2_cb1_w );
+WRITE8_HANDLER( via_3_cb1_w );
+WRITE8_HANDLER( via_4_cb1_w );
+WRITE8_HANDLER( via_5_cb1_w );
+WRITE8_HANDLER( via_6_cb1_w );
+WRITE8_HANDLER( via_7_cb1_w );
+WRITE8_HANDLER( via_0_cb2_w );
+WRITE8_HANDLER( via_1_cb2_w );
+WRITE8_HANDLER( via_2_cb2_w );
+WRITE8_HANDLER( via_3_cb2_w );
+WRITE8_HANDLER( via_4_cb2_w );
+WRITE8_HANDLER( via_5_cb2_w );
+WRITE8_HANDLER( via_6_cb2_w );
+WRITE8_HANDLER( via_7_cb2_w );
+
+READ8_HANDLER( via_0_ca1_r );
+READ8_HANDLER( via_1_ca1_r );
+READ8_HANDLER( via_2_ca1_r );
+READ8_HANDLER( via_3_ca1_r );
+READ8_HANDLER( via_4_ca1_r );
+READ8_HANDLER( via_5_ca1_r );
+READ8_HANDLER( via_6_ca1_r );
+READ8_HANDLER( via_7_ca1_r );
+READ8_HANDLER( via_0_ca2_r );
+READ8_HANDLER( via_1_ca2_r );
+READ8_HANDLER( via_2_ca2_r );
+READ8_HANDLER( via_3_ca2_r );
+READ8_HANDLER( via_4_ca2_r );
+READ8_HANDLER( via_5_ca2_r );
+READ8_HANDLER( via_6_ca2_r );
+READ8_HANDLER( via_7_ca2_r );
+
+READ8_HANDLER( via_0_cb1_r );
+READ8_HANDLER( via_1_cb1_r );
+READ8_HANDLER( via_2_cb1_r );
+READ8_HANDLER( via_3_cb1_r );
+READ8_HANDLER( via_4_cb1_r );
+READ8_HANDLER( via_5_cb1_r );
+READ8_HANDLER( via_6_cb1_r );
+READ8_HANDLER( via_7_cb1_r );
+READ8_HANDLER( via_0_cb2_r );
+READ8_HANDLER( via_1_cb2_r );
+READ8_HANDLER( via_2_cb2_r );
+READ8_HANDLER( via_3_cb2_r );
+READ8_HANDLER( via_4_cb2_r );
+READ8_HANDLER( via_5_cb2_r );
+READ8_HANDLER( via_6_cb2_r );
+READ8_HANDLER( via_7_cb2_r );
+
+#endif
+
diff --git a/src/emu/machine/6526cia.c b/src/emu/machine/6526cia.c
new file mode 100644
index 00000000000..0b3e1af3af2
--- /dev/null
+++ b/src/emu/machine/6526cia.c
@@ -0,0 +1,782 @@
+/**********************************************************************
+
+ MOS 6526/8520 CIA interface and emulation
+
+ This function emulates all the functionality of up to 2 MOS6526 or
+ MOS8520 complex interface adapters.
+
+**********************************************************************/
+
+#include "driver.h"
+#include "6526cia.h"
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+/* CIA registers */
+#define CIA_PRA 0
+#define CIA_PRB 1
+#define CIA_DDRA 2
+#define CIA_DDRB 3
+#define CIA_TALO 4
+#define CIA_TAHI 5
+#define CIA_TBLO 6
+#define CIA_TBHI 7
+#define CIA_TOD0 8 /* 6526: 1/10 seconds 8520: bits 0- 7 */
+#define CIA_TOD1 9 /* 6526: seconds 8520: bits 8-15 */
+#define CIA_TOD2 10 /* 6526: minutes 8520: bits 16-23 */
+#define CIA_TOD3 11 /* 6526: hours 8520: N/A */
+#define CIA_SDR 12
+#define CIA_ICR 13
+#define CIA_CRA 14
+#define CIA_CRB 15
+
+
+
+/*************************************
+ *
+ * Type definitions
+ *
+ *************************************/
+
+typedef struct _cia_timer cia_timer;
+typedef struct _cia_port cia_port;
+typedef struct _cia_state cia_state;
+
+struct _cia_timer
+{
+ UINT16 latch;
+ UINT16 count;
+ UINT8 mode;
+ UINT8 irq;
+ emu_timer *timer;
+ cia_state * cia;
+};
+
+struct _cia_port
+{
+ UINT8 ddr;
+ UINT8 latch;
+ UINT8 in;
+ UINT8 out;
+ UINT8 (*read)(void);
+ void (*write)(UINT8);
+};
+
+struct _cia_state
+{
+ int active;
+ cia_type_t type;
+ void (*irq_func)(int state);
+ int clock;
+
+ cia_port port[2];
+ cia_timer timer[2];
+
+ /* Time Of the Day clock (TOD) */
+ UINT32 tod;
+ UINT32 tod_latch;
+ UINT8 tod_latched;
+ UINT8 tod_running;
+ UINT32 alarm;
+
+ /* Interrupts */
+ UINT8 icr;
+ UINT8 ics;
+ UINT8 irq;
+
+ /* Serial */
+ UINT8 loaded;
+ UINT8 sdr;
+ UINT8 sp;
+ UINT8 cnt;
+ UINT8 shift;
+ UINT8 serial;
+};
+
+
+
+/*************************************
+ *
+ * Globals
+ *
+ *************************************/
+
+static cia_state cia_array[2];
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static TIMER_CALLBACK_PTR( cia_timer_proc );
+static void cia_timer_underflow(cia_state *cia, int timer);
+static TIMER_CALLBACK( cia_clock_tod_callback );
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+
+/***************************************************************************
+
+ Setup and reset
+
+***************************************************************************/
+
+static void cia_exit(running_machine *machine)
+{
+ memset(cia_array, 0, sizeof(*cia_array));
+}
+
+
+
+void cia_config(int which, const cia6526_interface *intf)
+{
+ int t, p;
+ cia_state *cia = &cia_array[which];
+
+ /* sanity checks */
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call cia_config at init time!");
+ assert_always((which >= 0) && (which < (sizeof(cia_array) / sizeof(cia_array[0]))),
+ "cia_config called on an invalid CIA!");
+
+ /* clear out CIA structure, and copy the interface */
+ memset(cia, 0, sizeof(*cia));
+ cia->active = TRUE;
+ cia->type = intf->type;
+ cia->clock = (intf->clock != 0) ? intf->clock : cpunum_get_clock(0);
+ cia->irq_func = intf->irq_func;
+
+ /* setup ports */
+ for (p = 0; p < (sizeof(cia->port) / sizeof(cia->port[0])); p++)
+ {
+ cia->port[p].read = intf->port[p].read;
+ cia->port[p].write = intf->port[p].write;
+ }
+
+ /* setup timers */
+ for (t = 0; t < (sizeof(cia->timer) / sizeof(cia->timer[0])); t++)
+ {
+ cia_timer *timer = &cia->timer[t];
+ timer->timer = timer_alloc_ptr(cia_timer_proc, timer);
+ timer->cia = cia;
+ timer->irq = 0x01 << t;
+ }
+
+ /* setup TOD timer, if appropriate */
+ if (intf->tod_clock)
+ timer_pulse(ATTOTIME_IN_HZ(intf->tod_clock), which, cia_clock_tod_callback);
+
+ /* special case; for the first CIA, set up an exit handler to clear things out */
+ if (which == 0)
+ add_exit_callback(Machine, cia_exit);
+
+ /* state save support */
+ state_save_register_item("6526cia", which, cia->port[0].ddr);
+ state_save_register_item("6526cia", which, cia->port[0].latch);
+ state_save_register_item("6526cia", which, cia->port[0].in);
+ state_save_register_item("6526cia", which, cia->port[0].out);
+ state_save_register_item("6526cia", which, cia->port[1].ddr);
+ state_save_register_item("6526cia", which, cia->port[1].latch);
+ state_save_register_item("6526cia", which, cia->port[1].in);
+ state_save_register_item("6526cia", which, cia->port[1].out);
+ state_save_register_item("6526cia", which, cia->timer[0].latch);
+ state_save_register_item("6526cia", which, cia->timer[0].count);
+ state_save_register_item("6526cia", which, cia->timer[0].mode);
+ state_save_register_item("6526cia", which, cia->timer[0].irq);
+ state_save_register_item("6526cia", which, cia->timer[1].latch);
+ state_save_register_item("6526cia", which, cia->timer[1].count);
+ state_save_register_item("6526cia", which, cia->timer[1].mode);
+ state_save_register_item("6526cia", which, cia->timer[1].irq);
+ state_save_register_item("6526cia", which, cia->tod);
+ state_save_register_item("6526cia", which, cia->tod_latch);
+ state_save_register_item("6526cia", which, cia->tod_latched);
+ state_save_register_item("6526cia", which, cia->tod_running);
+ state_save_register_item("6526cia", which, cia->alarm);
+ state_save_register_item("6526cia", which, cia->icr);
+ state_save_register_item("6526cia", which, cia->ics);
+ state_save_register_item("6526cia", which, cia->irq);
+ state_save_register_item("6526cia", which, cia->loaded);
+ state_save_register_item("6526cia", which, cia->sdr);
+ state_save_register_item("6526cia", which, cia->sp);
+ state_save_register_item("6526cia", which, cia->cnt);
+ state_save_register_item("6526cia", which, cia->shift);
+ state_save_register_item("6526cia", which, cia->serial);
+}
+
+
+
+void cia_reset(void)
+{
+ int i, t;
+
+ /* loop over and set up initial values */
+ for (i = 0; i < (sizeof(cia_array) / sizeof(cia_array[0])); i++)
+ {
+ cia_state *cia = &cia_array[i];
+
+ if (cia->active)
+ {
+ /* clear things out */
+ cia->port[0].latch = 0x00;
+ cia->port[0].in = 0x00;
+ cia->port[0].out = 0x00;
+ cia->port[1].latch = 0x00;
+ cia->port[1].in = 0x00;
+ cia->port[1].out = 0x00;
+ cia->tod = 0;
+ cia->tod_latch = 0;
+ cia->alarm = 0;
+ cia->icr = 0x00;
+ cia->ics = 0x00;
+ cia->irq = 0;
+
+ /* initialize data direction registers */
+ cia->port[0].ddr = (i == 0) ? 0x03 : 0xff;
+ cia->port[1].ddr = (i == 0) ? 0x00 : 0xff;
+
+ /* TOD running by default */
+ cia->tod_running = TRUE;
+
+ /* initialize timers */
+ for (t = 0; t < 2; t++)
+ {
+ cia_timer *timer = &cia->timer[t];
+
+ timer->latch = 0xffff;
+ timer->count = 0x0000;
+ timer->mode = 0x00;
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+
+ CIA runtime
+
+***************************************************************************/
+
+static void cia_update_interrupts(cia_state *cia)
+{
+ UINT8 new_irq;
+
+ /* always update the high bit of ICS */
+ if (cia->ics & 0x7f)
+ cia->ics |= 0x80;
+ else
+ cia->ics &= ~0x80;
+
+ /* based on what is enabled, set/clear the IRQ via the custom chip */
+ new_irq = (cia->ics & cia->icr) ? 1 : 0;
+ if (cia->irq != new_irq)
+ {
+ cia->irq = new_irq;
+ if (cia->irq_func)
+ cia->irq_func(cia->irq);
+ }
+}
+
+
+static int is_timer_active(emu_timer *timer)
+{
+ attotime t = timer_firetime(timer);
+ return attotime_compare(t, attotime_never) != 0;
+}
+
+
+/* updates the count and emu_timer for a given CIA timer */
+static void cia_timer_update(cia_timer *timer, INT32 new_count)
+{
+ int which = timer - timer->cia->timer;
+
+ /* sanity check arguments */
+ assert((new_count >= -1) && (new_count <= 0xffff));
+
+ /* update the timer count, if necessary */
+ if ((new_count == -1) && is_timer_active(timer->timer))
+ {
+ UINT16 current_count = attotime_to_double(attotime_mul(timer_timeelapsed(timer->timer), timer->cia->clock));
+ timer->count = timer->count - MIN(timer->count, current_count);
+ }
+
+ /* set the timer if we are instructed to */
+ if (new_count != -1)
+ timer->count = new_count;
+
+ /* now update the MAME timer */
+ if ((timer->mode & 0x01) && ((timer->mode & (which ? 0x60 : 0x20)) == 0x00))
+ {
+ /* timer is on and is connected to clock */
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(timer->cia->clock), (timer->count ? timer->count : 0x10000));
+ timer_adjust_ptr(timer->timer, period, attotime_zero);
+ }
+ else
+ {
+ /* timer is off or not connected to clock */
+ timer_adjust_ptr(timer->timer, attotime_never, attotime_zero);
+ }
+}
+
+
+static void cia_timer_bump(cia_state *cia, int timer)
+{
+ cia_timer_update(&cia->timer[timer], -1);
+
+ if (cia->timer[timer].count == 0x00)
+ cia_timer_underflow(cia, timer);
+ else
+ cia_timer_update(&cia->timer[timer], cia->timer[timer].count - 1);
+}
+
+
+static void cia_timer_underflow(cia_state *cia, int timer)
+{
+ assert((timer == 0) || (timer == 1));
+
+ /* set the status and update interrupts */
+ cia->ics |= cia->timer[timer].irq;
+ cia_update_interrupts(cia);
+
+ /* if one-shot mode, turn it off */
+ if (cia->timer[timer].mode & 0x08)
+ cia->timer[timer].mode &= 0xfe;
+
+ /* reload the timer */
+ cia_timer_update(&cia->timer[timer], cia->timer[timer].latch);
+
+ /* timer A has some interesting properties */
+ if (timer == 0)
+ {
+ /* such as cascading to timer B */
+ if ((cia->timer[1].mode & 0x41) == 0x41)
+ {
+ if (cia->cnt || !(cia->timer[1].mode & 0x20))
+ cia_timer_bump(cia, 1);
+ }
+
+ /* also the serial line */
+ if ((cia->timer[timer].irq == 0x01) && (cia->timer[timer].mode & 0x40))
+ {
+ if (cia->shift || cia->loaded)
+ {
+ if (cia->cnt)
+ {
+ if (cia->shift == 0)
+ {
+ cia->loaded = 0;
+ cia->serial = cia->sdr;
+ }
+ cia->sp = (cia->serial & 0x80) ? 1 : 0;
+ cia->shift++;
+ cia->serial <<= 1;
+ cia->cnt = 0;
+ }
+ else
+ {
+ cia->cnt = 1;
+ if (cia->shift == 8)
+ {
+ cia->ics |= 0x08;
+ cia_update_interrupts(cia);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static TIMER_CALLBACK_PTR( cia_timer_proc )
+{
+ cia_timer *timer = param;
+ cia_state *cia = timer->cia;
+
+ cia_timer_underflow(cia, timer - cia->timer);
+}
+
+
+static UINT8 bcd_increment(UINT8 value)
+{
+ value++;
+ if ((value & 0x0f) >= 0x0a)
+ value += 0x10 - 0x0a;
+ return value;
+}
+
+
+static void cia6526_increment(cia_state *cia)
+{
+ /* break down TOD value into components */
+ UINT8 subsecond = (UINT8) (cia->tod >> 0);
+ UINT8 second = (UINT8) (cia->tod >> 8);
+ UINT8 minute = (UINT8) (cia->tod >> 16);
+ UINT8 hour = (UINT8) (cia->tod >> 24);
+
+ subsecond = bcd_increment(subsecond);
+ if (subsecond >= 0x10)
+ {
+ subsecond = 0x00;
+ second = bcd_increment(second);
+ if (second >= ((cia->timer[0].mode & 0x80) ? 0x50 : 0x60))
+ {
+ second = 0x00;
+ minute = bcd_increment(minute);
+ if (minute >= 0x60)
+ {
+ minute = 0x00;
+ if (hour == 0x91)
+ hour = 0x00;
+ else if (hour == 0x89)
+ hour = 0x90;
+ else if (hour == 0x11)
+ hour = 0x80;
+ else if (hour == 0x09)
+ hour = 0x10;
+ else
+ hour++;
+ }
+ }
+ }
+
+ /* update the TOD with new value */
+ cia->tod = (((UINT32) subsecond) << 0)
+ | (((UINT32) second) << 8)
+ | (((UINT32) minute) << 16)
+ | (((UINT32) hour) << 24);
+}
+
+
+/* Update TOD on CIA A */
+void cia_clock_tod(int which)
+{
+ cia_state *cia;
+
+ cia = &cia_array[which];
+
+ if (cia->tod_running)
+ {
+ switch(cia->type)
+ {
+ case CIA6526:
+ /* The 6526 split the value into hours, minutes, seconds and
+ * subseconds */
+ cia6526_increment(cia);
+ break;
+
+ case CIA8520:
+ /* the 8520 has a straight 24-bit counter */
+ cia->tod++;
+ cia->tod &= 0xffffff;
+ break;
+ }
+
+ if (cia->tod == cia->alarm)
+ {
+ cia->ics |= 0x04;
+ cia_update_interrupts(cia);
+ }
+ }
+}
+
+
+static TIMER_CALLBACK( cia_clock_tod_callback )
+{
+ cia_clock_tod(param);
+}
+
+
+void cia_issue_index(int which)
+{
+ cia_state *cia = &cia_array[which];
+ cia->ics |= 0x10;
+ cia_update_interrupts(cia);
+}
+
+
+void cia_set_input_sp(int which, int data)
+{
+ cia_state *cia = &cia_array[which];
+ cia->sp = data;
+}
+
+
+void cia_set_input_cnt(int which, int data)
+{
+ cia_state *cia = &cia_array[which];
+
+ /* is this a rising edge? */
+ if (!cia->cnt && data)
+ {
+ /* does timer #0 bump on CNT? */
+ if ((cia->timer[0].mode & 0x21) == 0x21)
+ cia_timer_bump(cia, 0);
+
+ /* does timer #1 bump on CNT? */
+ if ((cia->timer[1].mode & 0x61) == 0x21)
+ cia_timer_bump(cia, 1);
+
+ /* if the serial port is set to output, the CNT will shift the port */
+ if (!(cia->timer[0].mode & 0x40))
+ {
+ cia->serial >>= 1;
+ if (cia->sp)
+ cia->serial |= 0x80;
+
+ if (++cia->shift == 8)
+ {
+ cia->sdr = cia->serial;
+ cia->serial = 0;
+ cia->shift = 0;
+ cia->ics |= 0x08;
+ cia_update_interrupts(cia);
+ }
+ }
+ }
+ cia->cnt = data ? 1 : 0;
+}
+
+
+UINT8 cia_read(int which, offs_t offset)
+{
+ cia_timer *timer;
+ cia_state *cia;
+ cia_port *port;
+ UINT8 data = 0x00;
+
+ cia = &cia_array[which];
+ offset &= 0x0F;
+
+ switch(offset)
+ {
+ /* port A/B data */
+ case CIA_PRA:
+ case CIA_PRB:
+ port = &cia->port[offset & 1];
+ data = port->read ? (*port->read)() : 0;
+ //data = data & (port->latch | ~port->ddr);
+ data = (data & ~port->ddr) | (port->latch & port->ddr);
+ port->in = data;
+
+ if (offset == CIA_PRB)
+ {
+ /* timer #0 can change PB6 */
+ if (cia->timer[0].mode & 0x02)
+ {
+ cia_timer_update(&cia->timer[0], -1);
+ if (cia->timer[0].count != 0)
+ data |= 0x40;
+ else
+ data &= ~0x40;
+ }
+
+ /* timer #1 can change PB7 */
+ if (cia->timer[1].mode & 0x02)
+ {
+ cia_timer_update(&cia->timer[1], -1);
+ if (cia->timer[1].count != 0)
+ data |= 0x80;
+ else
+ data &= ~0x80;
+ }
+ }
+ break;
+
+ /* port A/B direction */
+ case CIA_DDRA:
+ case CIA_DDRB:
+ port = &cia->port[offset & 1];
+ data = port->ddr;
+ break;
+
+ /* timer A/B low byte */
+ case CIA_TALO:
+ case CIA_TBLO:
+ timer = &cia->timer[(offset >> 1) & 1];
+ cia_timer_update(timer, -1);
+ data = timer->count >> 0;
+ break;
+
+ /* timer A/B high byte */
+ case CIA_TAHI:
+ case CIA_TBHI:
+ timer = &cia->timer[(offset >> 1) & 1];
+ cia_timer_update(timer, -1);
+ data = timer->count >> 8;
+ break;
+
+ /* TOD counter */
+ case CIA_TOD0:
+ case CIA_TOD1:
+ case CIA_TOD2:
+ case CIA_TOD3:
+ if (offset == CIA_TOD2)
+ {
+ cia->tod_latch = cia->tod;
+ cia->tod_latched = TRUE;
+ }
+ else if (offset == CIA_TOD0)
+ cia->tod_latched = FALSE;
+
+ if (cia->tod_latched)
+ data = cia->tod_latch >> ((offset - CIA_TOD0) * 8);
+ else
+ data = cia->tod >> ((offset - CIA_TOD0) * 8);
+ break;
+
+ /* serial data ready */
+ case CIA_SDR:
+ data = cia->sdr;
+ break;
+
+ /* interrupt status/clear */
+ case CIA_ICR:
+ data = cia->ics;
+ cia->ics = 0; /* clear on read */
+ cia_update_interrupts(cia);
+ break;
+
+ /* timer A/B mode */
+ case CIA_CRA:
+ case CIA_CRB:
+ timer = &cia->timer[offset & 1];
+ data = timer->mode;
+ break;
+ }
+ return data;
+}
+
+
+
+void cia_write(int which, offs_t offset, UINT8 data)
+{
+ cia_timer *timer;
+ cia_state *cia;
+ cia_port *port;
+ int shift;
+
+ cia = &cia_array[which];
+ offset &= 0x0F;
+
+ switch(offset)
+ {
+ /* port A/B data */
+ case CIA_PRA:
+ case CIA_PRB:
+ port = &cia->port[offset & 1];
+ port->latch = data;
+ port->out = (data & port->ddr) | (port->in & ~port->ddr);
+ if (port->write)
+ (*port->write)(port->out);
+ break;
+
+ /* port A/B direction */
+ case CIA_DDRA:
+ case CIA_DDRB:
+ port = &cia->port[offset & 1];
+ port->ddr = data;
+ break;
+
+ /* timer A/B latch low */
+ case CIA_TALO:
+ case CIA_TBLO:
+ timer = &cia->timer[(offset >> 1) & 1];
+ timer->latch = (timer->latch & 0xff00) | (data << 0);
+ break;
+
+ /* timer A latch high */
+ case CIA_TAHI:
+ case CIA_TBHI:
+ timer = &cia->timer[(offset >> 1) & 1];
+ timer->latch = (timer->latch & 0x00ff) | (data << 8);
+
+ /* if the timer is one-shot, then force a start on it */
+ if (timer->mode & 0x08)
+ {
+ timer->mode |= 1;
+ cia_timer_update(timer, timer->latch);
+ }
+ else
+ {
+ /* if the timer is off, update the count */
+ if (!(timer->mode & 0x01))
+ cia_timer_update(timer, timer->latch);
+ }
+ break;
+
+ /* time of day latches */
+ case CIA_TOD0:
+ case CIA_TOD1:
+ case CIA_TOD2:
+ shift = 8 * ((offset - CIA_TOD0));
+
+ /* alarm setting mode? */
+ if (cia->timer[1].mode & 0x80)
+ cia->alarm = (cia->alarm & ~(0xff << shift)) | (data << shift);
+
+ /* counter setting mode */
+ else
+ {
+ cia->tod = (cia->tod & ~(0xff << shift)) | (data << shift);
+
+ /* only enable the TOD once the LSB is written */
+ cia->tod_running = (shift == 0);
+ }
+ break;
+
+ /* serial data ready */
+ case CIA_SDR:
+ cia->sdr = data;
+ if (cia->timer[0].mode & 0x40)
+ cia->loaded = 1;
+ break;
+
+ /* interrupt control register */
+ case CIA_ICR:
+ if (data & 0x80)
+ cia->icr |= data & 0x7f;
+ else
+ cia->icr &= ~(data & 0x7f);
+ cia_update_interrupts(cia);
+ break;
+
+ /* timer A/B modes */
+ case CIA_CRA:
+ case CIA_CRB:
+ timer = &cia->timer[offset & 1];
+ timer->mode = data & 0xef;
+
+ /* force load? */
+ if (data & 0x10)
+ cia_timer_update(timer, timer->latch);
+ else
+ cia_timer_update(timer, -1);
+ break;
+ }
+}
+
+
+
+UINT8 cia_get_output_a(int which) { return cia_array[which].port[0].out; }
+UINT8 cia_get_output_b(int which) { return cia_array[which].port[1].out; }
+int cia_get_irq(int which) { return cia_array[which].irq; }
+
+READ8_HANDLER( cia_0_r ) { return cia_read(0, offset); }
+READ8_HANDLER( cia_1_r ) { return cia_read(1, offset); }
+
+WRITE8_HANDLER( cia_0_w ) { cia_write(0, offset, data); }
+WRITE8_HANDLER( cia_1_w ) { cia_write(1, offset, data); }
diff --git a/src/emu/machine/6526cia.h b/src/emu/machine/6526cia.h
new file mode 100644
index 00000000000..8f6acf0b5aa
--- /dev/null
+++ b/src/emu/machine/6526cia.h
@@ -0,0 +1,58 @@
+/**********************************************************************
+
+ MOS 6526/8520 CIA interface and emulation
+
+ This function emulates all the functionality of up to 2 MOS6526 or
+ MOS8520 complex interface adapters.
+
+**********************************************************************/
+
+#ifndef _6526CIA_H_
+#define _6526CIA_H_
+
+typedef enum
+{
+ CIA6526,
+ CIA8520
+} cia_type_t;
+
+typedef struct _cia6526_interface cia6526_interface;
+struct _cia6526_interface
+{
+ cia_type_t type;
+ void (*irq_func)(int state);
+ int clock;
+ int tod_clock;
+
+ struct
+ {
+ UINT8 (*read)(void);
+ void (*write)(UINT8);
+ } port[2];
+};
+
+/* configuration and reset */
+void cia_config(int which, const cia6526_interface *intf);
+void cia_reset(void);
+
+/* reading and writing */
+UINT8 cia_read(int which, offs_t offset);
+void cia_write(int which, offs_t offset, UINT8 data);
+void cia_clock_tod(int which);
+void cia_issue_index(int which);
+void cia_set_input_cnt(int which, int data);
+void cia_set_input_sp(int which, int data);
+
+/* accessors */
+UINT8 cia_get_output_a(int which);
+UINT8 cia_get_output_b(int which);
+int cia_get_irq(int which);
+
+/* standard handlers */
+READ8_HANDLER( cia_0_r );
+READ8_HANDLER( cia_1_r );
+
+WRITE8_HANDLER( cia_0_w );
+WRITE8_HANDLER( cia_1_w );
+
+#endif /* _6526CIA_H_ */
diff --git a/src/emu/machine/6532riot.c b/src/emu/machine/6532riot.c
new file mode 100644
index 00000000000..42abec15464
--- /dev/null
+++ b/src/emu/machine/6532riot.c
@@ -0,0 +1,373 @@
+/***************************************************************************
+
+ RIOT 6532 emulation
+
+The timer seems to follow these rules:
+- When the timer flag changes from 0 to 1 the timer continues to count
+ down at a 1 cycle rate.
+- When the timer is being read or written the timer flag is reset.
+- When the timer flag is set and the timer contents are 0, the counting
+ stops.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "machine/6532riot.h"
+
+struct riot6532
+{
+ const struct riot6532_interface *intf;
+
+ UINT8 in_a;
+ UINT8 out_a;
+ UINT8 in_b;
+ UINT8 out_b;
+ UINT8 ddr_a;
+ UINT8 ddr_b;
+
+ int shift;
+
+ int pa7_enable;
+ int pa7_direction; /* 0x80 = high-to-low, 0x00 = low-to-high */
+ int pa7_flag;
+ UINT8 pa7;
+
+ int timer_irq_enable;
+ int timer_irq;
+ emu_timer *counter_timer;
+
+ int clock;
+};
+
+
+static struct riot6532 r6532[MAX_R6532];
+
+
+INLINE void r6532_set_timer(int which, UINT8 count)
+{
+ timer_adjust( r6532[which].counter_timer, attotime_mul(ATTOTIME_IN_HZ(r6532[which].clock), (count << r6532[which].shift) + 1), which, attotime_zero );
+}
+
+
+static TIMER_CALLBACK( r6532_irq_timer_callback )
+{
+ int which = param;
+
+ if ( r6532[which].timer_irq_enable )
+ {
+ r6532[which].timer_irq = 1;
+ if (r6532[which].intf->irq_func)
+ (*r6532[which].intf->irq_func)(ASSERT_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is asserted but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+}
+
+
+static void r6532_pa7_check(int which){
+ UINT8 data = ( ( r6532[which].ddr_a & r6532[which].out_a ) | ( ~r6532[which].ddr_a & r6532[which].in_a ) ) & 0x80;
+ if ((r6532[which].pa7 ^ data) && (r6532[which].pa7_direction ^ data))
+ {
+ r6532[which].pa7_flag = 1;
+ if (r6532[which].pa7_enable)
+ {
+ if (r6532[which].intf->irq_func)
+ (*r6532[which].intf->irq_func)(ASSERT_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is asserted but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+ }
+ r6532[which].pa7 = data;
+}
+
+
+void r6532_write(int which, offs_t offset, UINT8 data)
+{
+ if (offset & 4)
+ {
+ if (offset & 0x10)
+ {
+ switch (offset & 3)
+ {
+ case 0:
+ r6532[which].shift = 0;
+ break;
+ case 1:
+ r6532[which].shift = 3;
+ break;
+ case 2:
+ r6532[which].shift = 6;
+ break;
+ case 3:
+ r6532[which].shift = 10;
+ break;
+ }
+ r6532[which].timer_irq_enable = (offset & 8);
+ r6532_set_timer( which, data );
+ }
+ else
+ {
+ r6532[which].pa7_enable = (offset & 2) >> 1;
+ r6532[which].pa7_direction = ( offset & 1 ) << 7;
+ }
+ }
+ else
+ {
+ offset &= 3;
+
+ switch (offset)
+ {
+ case 0:
+ r6532[which].out_a = data;
+ if (r6532[which].ddr_a)
+ {
+ UINT8 write_data = ( r6532[which].ddr_a & r6532[which].out_a ) | ( ~r6532[which].ddr_a & 0xFF );
+ if (r6532[which].intf->out_a_func)
+ r6532[which].intf->out_a_func(0, write_data);
+ else
+ logerror("6532RIOT chip #%d: Port A is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ /* Check for PA7 change */
+ r6532_pa7_check(which);
+ }
+ break;
+ case 1:
+ r6532[which].ddr_a = data;
+ r6532_pa7_check(which);
+ break;
+ case 2:
+ r6532[which].out_b = data;
+ if (r6532[which].ddr_b)
+ {
+ UINT8 write_data = ( r6532[which].ddr_b & r6532[which].out_b ) | ( ~r6532[which].ddr_b & 0xFF );
+ if (r6532[which].intf->out_b_func)
+ r6532[which].intf->out_b_func(0, write_data);
+ else
+ logerror("6532RIOT chip #%d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ break;
+ case 3:
+ r6532[which].ddr_b = data;
+ break;
+ }
+ }
+}
+
+
+INLINE UINT8 r6532_read_timer(int which)
+{
+ int timer_cycles_left = ( attotime_to_double(timer_timeleft( r6532[which].counter_timer )) * r6532[which].clock ) - 1;
+ if ( timer_cycles_left >= 0)
+ {
+ timer_cycles_left = timer_cycles_left >> r6532[which].shift;
+ }
+ else
+ {
+ if (timer_cycles_left != -1)
+ {
+ if (r6532[which].intf->irq_func && r6532[which].timer_irq)
+ (*r6532[which].intf->irq_func)(CLEAR_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+
+ /* Timer flag is cleared, so adjust the target */
+ timer_cycles_left = ( timer_cycles_left > -256 ) ? timer_cycles_left & 0xFF : 0;
+ r6532_set_timer( which, timer_cycles_left );
+ }
+ }
+ return timer_cycles_left;
+}
+
+
+void r6532_set_input_a(int which, UINT8 data)
+{
+ r6532[which].in_a = data;
+ /* Check for PA7 change */
+ r6532_pa7_check(which);
+}
+
+
+void r6532_set_input_b(int which, UINT8 data)
+{
+ r6532[which].in_b = data;
+}
+
+
+INLINE UINT8 r6532_read_irq_flags(int which)
+{
+ int timer_cycles_left = ( attotime_to_double(timer_timeleft( r6532[which].counter_timer )) * r6532[which].clock ) - 1;
+ int res = 0;
+
+ if ( timer_cycles_left < 0 )
+ {
+ res |= 0x80;
+ if ( timer_cycles_left < -1 )
+ {
+ if ( r6532[which].intf->irq_func)
+ (*r6532[which].intf->irq_func)(CLEAR_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+
+ /* Timer flag is cleared, so adjust the target */
+ r6532_set_timer( which, timer_cycles_left > -256 ? timer_cycles_left & 0xFF : 0 );
+ }
+ }
+
+ if (r6532[which].pa7_flag)
+ {
+ res |= 0x40;
+ r6532[which].pa7_flag = 0;
+
+ if (r6532[which].intf->irq_func && timer_cycles_left != -1)
+ (*r6532[which].intf->irq_func)(CLEAR_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ return res;
+}
+
+
+UINT8 r6532_read(int which, offs_t offset)
+{
+ UINT8 val = 0;
+
+ switch (offset & 7)
+ {
+ case 0:
+ if (r6532[which].intf->in_a_func)
+ r6532[which].in_a = r6532[which].intf->in_a_func(0);
+ else
+ logerror("6532RIOT chip #%d: Port A is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ val = ( r6532[which].ddr_a & r6532[which].out_a ) | ( ~r6532[which].ddr_a & r6532[which].in_a );
+ /* Check for PA7 change */
+ r6532_pa7_check(which);
+ break;
+ case 1:
+ val = r6532[which].ddr_a;
+ break;
+ case 2:
+ if (r6532[which].intf->in_b_func)
+ r6532[which].in_b = r6532[which].intf->in_b_func(0);
+ else
+ logerror("6532RIOT chip #%d: Port B is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+
+ val = ( r6532[which].ddr_b & r6532[which].out_b ) | ( ~r6532[which].ddr_b & r6532[which].in_b );
+ break;
+ case 3:
+ val = r6532[which].ddr_b;
+ break;
+ case 4:
+ case 6:
+ r6532[which].timer_irq_enable = offset & 8;
+ val = r6532_read_timer(which);
+ break;
+ case 5:
+ case 7:
+ val = r6532_read_irq_flags(which);
+ break;
+ }
+
+ return val;
+}
+
+
+void r6532_set_clock(int which, int clock)
+{
+ r6532[which].clock = clock;
+}
+
+
+void r6532_reset(int which)
+{
+ r6532[which].out_a = 0;
+ r6532[which].out_b = 0;
+ r6532[which].ddr_a = 0;
+ r6532[which].ddr_b = 0;
+
+ r6532[which].shift = 10;
+
+ r6532[which].counter_timer = timer_alloc(r6532_irq_timer_callback);
+
+ r6532_set_timer( which, 0xFF );
+
+ r6532[which].pa7_enable = 0;
+ r6532[which].pa7_direction = 0x80;
+ r6532[which].pa7_flag = 0;
+ r6532[which].pa7 = 0;
+
+ r6532[which].timer_irq_enable = 0;
+ r6532[which].timer_irq = 0;
+
+ if (r6532[which].intf->irq_func)
+ (*r6532[which].intf->irq_func)(CLEAR_LINE);
+ else
+ logerror("6532RIOT chip #%d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+}
+
+
+void r6532_config(int which, const struct riot6532_interface* intf)
+{
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call r6532_init at init time!");
+ assert_always( which < MAX_R6532, "which exceeds maximum number of configured r6532s!" );
+
+ r6532[which].intf = intf;
+
+ /* Default clock is CPU #0 clock */
+ r6532_set_clock( which, Machine->drv->cpu[0].clock );
+}
+
+
+WRITE8_HANDLER( r6532_0_w ) { r6532_write(0, offset, data); }
+WRITE8_HANDLER( r6532_1_w ) { r6532_write(1, offset, data); }
+WRITE8_HANDLER( r6532_2_w ) { r6532_write(2, offset, data); }
+WRITE8_HANDLER( r6532_3_w ) { r6532_write(3, offset, data); }
+WRITE8_HANDLER( r6532_4_w ) { r6532_write(4, offset, data); }
+WRITE8_HANDLER( r6532_5_w ) { r6532_write(5, offset, data); }
+WRITE8_HANDLER( r6532_6_w ) { r6532_write(6, offset, data); }
+WRITE8_HANDLER( r6532_7_w ) { r6532_write(7, offset, data); }
+
+READ8_HANDLER( r6532_0_r ) { return r6532_read(0, offset); }
+READ8_HANDLER( r6532_1_r ) { return r6532_read(1, offset); }
+READ8_HANDLER( r6532_2_r ) { return r6532_read(2, offset); }
+READ8_HANDLER( r6532_3_r ) { return r6532_read(3, offset); }
+READ8_HANDLER( r6532_4_r ) { return r6532_read(4, offset); }
+READ8_HANDLER( r6532_5_r ) { return r6532_read(5, offset); }
+READ8_HANDLER( r6532_6_r ) { return r6532_read(6, offset); }
+READ8_HANDLER( r6532_7_r ) { return r6532_read(7, offset); }
+
+WRITE8_HANDLER( r6532_0_porta_w) { r6532_set_input_a(0, data); }
+WRITE8_HANDLER( r6532_1_porta_w) { r6532_set_input_a(1, data); }
+WRITE8_HANDLER( r6532_2_porta_w) { r6532_set_input_a(2, data); }
+WRITE8_HANDLER( r6532_3_porta_w) { r6532_set_input_a(3, data); }
+WRITE8_HANDLER( r6532_4_porta_w) { r6532_set_input_a(4, data); }
+WRITE8_HANDLER( r6532_5_porta_w) { r6532_set_input_a(5, data); }
+WRITE8_HANDLER( r6532_6_porta_w) { r6532_set_input_a(6, data); }
+WRITE8_HANDLER( r6532_7_porta_w) { r6532_set_input_a(7, data); }
+
+WRITE8_HANDLER( r6532_0_portb_w) { r6532_set_input_b(0, data); }
+WRITE8_HANDLER( r6532_1_portb_w) { r6532_set_input_b(1, data); }
+WRITE8_HANDLER( r6532_2_portb_w) { r6532_set_input_b(2, data); }
+WRITE8_HANDLER( r6532_3_portb_w) { r6532_set_input_b(3, data); }
+WRITE8_HANDLER( r6532_4_portb_w) { r6532_set_input_b(4, data); }
+WRITE8_HANDLER( r6532_5_portb_w) { r6532_set_input_b(5, data); }
+WRITE8_HANDLER( r6532_6_portb_w) { r6532_set_input_b(6, data); }
+WRITE8_HANDLER( r6532_7_portb_w) { r6532_set_input_b(7, data); }
+
+READ8_HANDLER( r6532_0_porta_r) { return r6532[0].in_a; }
+READ8_HANDLER( r6532_1_porta_r) { return r6532[1].in_a; }
+READ8_HANDLER( r6532_2_porta_r) { return r6532[2].in_a; }
+READ8_HANDLER( r6532_3_porta_r) { return r6532[3].in_a; }
+READ8_HANDLER( r6532_4_porta_r) { return r6532[4].in_a; }
+READ8_HANDLER( r6532_5_porta_r) { return r6532[5].in_a; }
+READ8_HANDLER( r6532_6_porta_r) { return r6532[6].in_a; }
+READ8_HANDLER( r6532_7_porta_r) { return r6532[7].in_a; }
+
+READ8_HANDLER( r6532_0_portb_r) { return r6532[0].in_b; }
+READ8_HANDLER( r6532_1_portb_r) { return r6532[1].in_b; }
+READ8_HANDLER( r6532_2_portb_r) { return r6532[2].in_b; }
+READ8_HANDLER( r6532_3_portb_r) { return r6532[3].in_b; }
+READ8_HANDLER( r6532_4_portb_r) { return r6532[4].in_b; }
+READ8_HANDLER( r6532_5_portb_r) { return r6532[5].in_b; }
+READ8_HANDLER( r6532_6_portb_r) { return r6532[6].in_b; }
+READ8_HANDLER( r6532_7_portb_r) { return r6532[7].in_b; }
+
diff --git a/src/emu/machine/6532riot.h b/src/emu/machine/6532riot.h
new file mode 100644
index 00000000000..707263c5299
--- /dev/null
+++ b/src/emu/machine/6532riot.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+
+ RIOT 6532 emulation
+
+***************************************************************************/
+
+#ifndef RIOT_6532
+#define RIOT_6532
+
+#define MAX_R6532 8
+
+struct riot6532_interface
+{
+ read8_handler in_a_func;
+ read8_handler in_b_func;
+ write8_handler out_a_func;
+ write8_handler out_b_func;
+ void (*irq_func)(int state);
+};
+
+void r6532_set_clock(int which, int clock);
+void r6532_reset(int which);
+void r6532_config(int which, const struct riot6532_interface* intf);
+UINT8 r6532_read(int which, offs_t offset);
+void r6532_write(int which, offs_t offset, UINT8 data);
+void r6532_set_input_a(int which, UINT8 data);
+void r6532_set_input_b(int which, UINT8 data);
+
+/******************* Standard 8-bit CPU interfaces, D0-D7 *******************/
+
+READ8_HANDLER( r6532_0_r );
+READ8_HANDLER( r6532_1_r );
+READ8_HANDLER( r6532_2_r );
+READ8_HANDLER( r6532_3_r );
+READ8_HANDLER( r6532_4_r );
+READ8_HANDLER( r6532_5_r );
+READ8_HANDLER( r6532_6_r );
+READ8_HANDLER( r6532_7_r );
+
+WRITE8_HANDLER( r6532_0_w );
+WRITE8_HANDLER( r6532_1_w );
+WRITE8_HANDLER( r6532_2_w );
+WRITE8_HANDLER( r6532_3_w );
+WRITE8_HANDLER( r6532_4_w );
+WRITE8_HANDLER( r6532_5_w );
+WRITE8_HANDLER( r6532_6_w );
+WRITE8_HANDLER( r6532_7_w );
+
+/******************* 8-bit A/B port interfaces *******************/
+
+WRITE8_HANDLER( r6532_0_porta_w );
+WRITE8_HANDLER( r6532_1_porta_w );
+WRITE8_HANDLER( r6532_2_porta_w );
+WRITE8_HANDLER( r6532_3_porta_w );
+WRITE8_HANDLER( r6532_4_porta_w );
+WRITE8_HANDLER( r6532_5_porta_w );
+WRITE8_HANDLER( r6532_6_porta_w );
+WRITE8_HANDLER( r6532_7_porta_w );
+
+WRITE8_HANDLER( r6532_0_portb_w );
+WRITE8_HANDLER( r6532_1_portb_w );
+WRITE8_HANDLER( r6532_2_portb_w );
+WRITE8_HANDLER( r6532_3_portb_w );
+WRITE8_HANDLER( r6532_4_portb_w );
+WRITE8_HANDLER( r6532_5_portb_w );
+WRITE8_HANDLER( r6532_6_portb_w );
+WRITE8_HANDLER( r6532_7_portb_w );
+
+READ8_HANDLER( r6532_0_porta_r );
+READ8_HANDLER( r6532_1_porta_r );
+READ8_HANDLER( r6532_2_porta_r );
+READ8_HANDLER( r6532_3_porta_r );
+READ8_HANDLER( r6532_4_porta_r );
+READ8_HANDLER( r6532_5_porta_r );
+READ8_HANDLER( r6532_6_porta_r );
+READ8_HANDLER( r6532_7_porta_r );
+
+READ8_HANDLER( r6532_0_portb_r );
+READ8_HANDLER( r6532_1_portb_r );
+READ8_HANDLER( r6532_2_portb_r );
+READ8_HANDLER( r6532_3_portb_r );
+READ8_HANDLER( r6532_4_portb_r );
+READ8_HANDLER( r6532_5_portb_r );
+READ8_HANDLER( r6532_6_portb_r );
+READ8_HANDLER( r6532_7_portb_r );
+
+#endif
diff --git a/src/emu/machine/6821pia.c b/src/emu/machine/6821pia.c
new file mode 100644
index 00000000000..0985ff68391
--- /dev/null
+++ b/src/emu/machine/6821pia.c
@@ -0,0 +1,1353 @@
+/**********************************************************************
+
+ Motorola 6821 PIA interface and emulation
+
+**********************************************************************/
+
+#include "driver.h"
+#include "6821pia.h"
+
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+
+/*************************************
+ *
+ * Internal PIA data structure
+ *
+ *************************************/
+
+typedef struct _pia6821 pia6821;
+struct _pia6821
+{
+ const pia6821_interface *intf;
+
+ UINT8 in_a;
+ UINT8 in_ca1;
+ UINT8 in_ca2;
+ UINT8 out_a;
+ UINT8 out_ca2;
+ UINT8 port_a_z_mask;
+ UINT8 ddr_a;
+ UINT8 ctl_a;
+ UINT8 irq_a1;
+ UINT8 irq_a2;
+ UINT8 irq_a_state;
+
+ UINT8 in_b;
+ UINT8 in_cb1;
+ UINT8 in_cb2;
+ UINT8 out_b;
+ UINT8 out_cb2;
+ UINT8 last_out_cb2_z;
+ UINT8 ddr_b;
+ UINT8 ctl_b;
+ UINT8 irq_b1;
+ UINT8 irq_b2;
+ UINT8 irq_b_state;
+
+ /* variables that indicate if access a line externally -
+ used to for logging purposes ONLY */
+ UINT8 in_a_pushed;
+ UINT8 out_a_needs_pulled;
+ UINT8 in_ca1_pushed;
+ UINT8 in_ca2_pushed;
+ UINT8 out_ca2_needs_pulled;
+ UINT8 in_b_pushed;
+ UINT8 out_b_needs_pulled;
+ UINT8 in_cb1_pushed;
+ UINT8 in_cb2_pushed;
+ UINT8 out_cb2_needs_pulled;
+ UINT8 logged_port_a_not_connected;
+ UINT8 logged_port_b_not_connected;
+ UINT8 logged_ca1_not_connected;
+ UINT8 logged_ca2_not_connected;
+ UINT8 logged_cb1_not_connected;
+ UINT8 logged_cb2_not_connected;
+};
+
+
+
+/*************************************
+ *
+ * Convenince macros and defines
+ *
+ *************************************/
+
+#define PIA_IRQ1 (0x80)
+#define PIA_IRQ2 (0x40)
+
+#define IRQ1_ENABLED(c) ( (((c) >> 0) & 0x01))
+#define C1_LOW_TO_HIGH(c) ( (((c) >> 1) & 0x01))
+#define C1_HIGH_TO_LOW(c) (!(((c) >> 1) & 0x01))
+#define OUTPUT_SELECTED(c) ( (((c) >> 2) & 0x01))
+#define IRQ2_ENABLED(c) ( (((c) >> 3) & 0x01))
+#define STROBE_E_RESET(c) ( (((c) >> 3) & 0x01))
+#define STROBE_C1_RESET(c) (!(((c) >> 3) & 0x01))
+#define C2_SET(c) ( (((c) >> 3) & 0x01))
+#define C2_LOW_TO_HIGH(c) ( (((c) >> 4) & 0x01))
+#define C2_HIGH_TO_LOW(c) (!(((c) >> 4) & 0x01))
+#define C2_SET_MODE(c) ( (((c) >> 4) & 0x01))
+#define C2_STROBE_MODE(c) (!(((c) >> 4) & 0x01))
+#define C2_OUTPUT(c) ( (((c) >> 5) & 0x01))
+#define C2_INPUT(c) (!(((c) >> 5) & 0x01))
+
+
+
+/*************************************
+ *
+ * Static variables
+ *
+ *************************************/
+
+static pia6821 pias[MAX_PIA];
+
+
+
+/*************************************
+ *
+ * Configuration
+ *
+ *************************************/
+
+void pia_config(int which, const pia6821_interface *intf)
+{
+ pia6821 *p;
+
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call pia_config at init time!");
+ assert_always((which >= 0) && (which < MAX_PIA), "pia_config called on an invalid PIA!");
+ assert_always(intf, "pia_config called with an invalid interface!");
+
+ p = &pias[which];
+ memset(p, 0, sizeof(pias[0]));
+
+ p->intf = intf;
+
+ state_save_register_item("6821pia", which, p->in_a);
+ state_save_register_item("6821pia", which, p->in_ca1);
+ state_save_register_item("6821pia", which, p->in_ca2);
+ state_save_register_item("6821pia", which, p->out_a);
+ state_save_register_item("6821pia", which, p->out_ca2);
+ state_save_register_item("6821pia", which, p->port_a_z_mask);
+ state_save_register_item("6821pia", which, p->ddr_a);
+ state_save_register_item("6821pia", which, p->ctl_a);
+ state_save_register_item("6821pia", which, p->irq_a1);
+ state_save_register_item("6821pia", which, p->irq_a2);
+ state_save_register_item("6821pia", which, p->irq_a_state);
+ state_save_register_item("6821pia", which, p->in_b);
+ state_save_register_item("6821pia", which, p->in_cb1);
+ state_save_register_item("6821pia", which, p->in_cb2);
+ state_save_register_item("6821pia", which, p->out_b);
+ state_save_register_item("6821pia", which, p->out_cb2);
+ state_save_register_item("6821pia", which, p->last_out_cb2_z);
+ state_save_register_item("6821pia", which, p->ddr_b);
+ state_save_register_item("6821pia", which, p->ctl_b);
+ state_save_register_item("6821pia", which, p->irq_b1);
+ state_save_register_item("6821pia", which, p->irq_b2);
+ state_save_register_item("6821pia", which, p->irq_b_state);
+ state_save_register_item("6821pia", which, p->in_a_pushed);
+ state_save_register_item("6821pia", which, p->out_a_needs_pulled);
+ state_save_register_item("6821pia", which, p->in_ca1_pushed);
+ state_save_register_item("6821pia", which, p->in_ca2_pushed);
+ state_save_register_item("6821pia", which, p->out_ca2_needs_pulled);
+ state_save_register_item("6821pia", which, p->in_b_pushed);
+ state_save_register_item("6821pia", which, p->out_b_needs_pulled);
+ state_save_register_item("6821pia", which, p->in_cb1_pushed);
+ state_save_register_item("6821pia", which, p->in_cb2_pushed);
+ state_save_register_item("6821pia", which, p->out_cb2_needs_pulled);
+}
+
+
+
+/*************************************
+ *
+ * Reset
+ *
+ *************************************/
+
+void pia_reset(void)
+{
+ int i;
+
+ /* zap each structure, preserving the interface and swizzle */
+ for (i = 0; i < MAX_PIA; i++)
+ {
+ const pia6821_interface *intf = pias[i].intf;
+
+ memset(&pias[i], 0, sizeof(pias[i]));
+
+ pias[i].intf = intf;
+
+ /*
+ * set default read values.
+ *
+ * ports A,CA1,CA2 default to 1
+ * ports B,CB1,CB2 are three-state and undefined (set to 0)
+ */
+ pias[i].in_a = 0xff;
+ pias[i].in_ca1 = TRUE;
+ pias[i].in_ca2 = TRUE;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Wire-OR for all interrupt handlers
+ *
+ *************************************/
+
+static void update_shared_irq_handler(void (*irq_func)(int state))
+{
+ int i;
+
+ /* search all PIAs for this same IRQ function */
+ for (i = 0; i < MAX_PIA; i++)
+ {
+ if (pias[i].intf)
+ {
+ /* check IRQ A */
+ if ((pias[i].intf->irq_a_func == irq_func) && pias[i].irq_a_state)
+ {
+ (*irq_func)(TRUE);
+ return;
+ }
+
+ /* check IRQ B */
+ if ((pias[i].intf->irq_b_func == irq_func) && pias[i].irq_b_state)
+ {
+ (*irq_func)(TRUE);
+ return;
+ }
+ }
+ }
+
+ /* if we found nothing, the state is off */
+ (*irq_func)(FALSE);
+}
+
+
+
+/*************************************
+ *
+ * External interrupt check
+ *
+ *************************************/
+
+static void update_interrupts(pia6821 *p)
+{
+ int new_state;
+
+ /* start with IRQ A */
+ new_state = (p->irq_a1 && IRQ1_ENABLED(p->ctl_a)) || (p->irq_a2 && IRQ2_ENABLED(p->ctl_a));
+
+ if (new_state != p->irq_a_state)
+ {
+ p->irq_a_state = new_state;
+
+ if (p->intf->irq_a_func) update_shared_irq_handler(p->intf->irq_a_func);
+ }
+
+ /* then do IRQ B */
+ new_state = (p->irq_b1 && IRQ1_ENABLED(p->ctl_b)) || (p->irq_b2 && IRQ2_ENABLED(p->ctl_b));
+
+ if (new_state != p->irq_b_state)
+ {
+ p->irq_b_state = new_state;
+
+ if (p->intf->irq_b_func) update_shared_irq_handler(p->intf->irq_b_func);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Port A/B input pins
+ *
+ *************************************/
+
+static UINT8 get_in_a_value(int which)
+{
+ pia6821 *p = &pias[which];
+ UINT8 port_a_data = 0;
+ UINT8 ret;
+
+ /* update the input */
+ if (p->intf->in_a_func)
+ port_a_data = p->intf->in_a_func(0);
+ else
+ {
+ if (p->in_a_pushed)
+ port_a_data = p->in_a;
+ else
+ {
+ /* mark all pins disconnected */
+ p->port_a_z_mask = 0xff;
+
+ if (!p->logged_port_a_not_connected && (p->ddr_a != 0xff))
+ {
+ logerror("cpu #%d (PC=%08X): PIA #%d: Warning! No port A read handler. Assuming pins 0x%02X not connected\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, p->ddr_a ^ 0xff);
+ p->logged_port_a_not_connected = TRUE;
+ }
+ }
+ }
+
+ /* - connected pins are always read
+ - disconnected pins read the output buffer in output mode
+ - disconnected pins are HI in input mode */
+ ret = (~p->port_a_z_mask & port_a_data) |
+ ( p->port_a_z_mask & p->ddr_a & p->out_a) |
+ ( p->port_a_z_mask & ~p->ddr_a);
+
+ return ret;
+}
+
+
+static UINT8 get_in_b_value(int which)
+{
+ pia6821 *p = &pias[which];
+ UINT8 ret;
+
+ if (p->ddr_b == 0xff)
+ /* all output, just return buffer */
+ ret = p->out_b;
+ else
+ {
+ UINT8 port_b_data;
+
+ /* update the input */
+ if (p->intf->in_b_func)
+ port_b_data = p->intf->in_b_func(0);
+ else
+ {
+ if (p->in_b_pushed)
+ port_b_data = p->in_b;
+ else
+ {
+ if (!p->logged_port_b_not_connected && (p->ddr_b != 0xff))
+ {
+ logerror("cpu #%d (PC=%08X): PIA #%d: Error! No port B read handler. Three-state pins 0x%02X are undefined\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, p->ddr_b ^ 0xff);
+ p->logged_port_b_not_connected = TRUE;
+ }
+
+ /* undefined -- need to return something */
+ port_b_data = 0x00;
+ }
+ }
+
+ /* the DDR determines if the pin or the output buffer is read */
+ ret = (p->out_b & p->ddr_b) | (port_b_data & ~p->ddr_b);
+ }
+
+ return ret;
+}
+
+
+
+/*************************************
+ *
+ * Port A/B output pins
+ *
+ *************************************/
+
+static UINT8 get_out_a_value(int which)
+{
+ UINT8 ret;
+ pia6821 *p = &pias[which];
+
+ if (p->ddr_a == 0xff)
+ /* all output */
+ ret = p->out_a;
+ else
+ /* input pins don't change */
+ ret = (p->out_a & p->ddr_a) | (get_in_a_value(which) & ~p->ddr_a);
+
+ return ret;
+}
+
+
+static UINT8 get_out_b_value(int which)
+{
+ pia6821 *p = &pias[which];
+
+ /* input pins are high-impedance - we just send them as zeros for backwards compatibility */
+ return p->out_b & p->ddr_b;
+}
+
+
+
+/*************************************
+ *
+ * Sets C2 state value and call
+ * callbacks if changed
+ *
+ *************************************/
+
+static void set_out_ca2(int which, int data)
+{
+ pia6821 *p = &pias[which];
+
+ if (data != p->out_ca2)
+ {
+ p->out_ca2 = data;
+
+ /* send to output function */
+ if (p->intf->out_ca2_func)
+ p->intf->out_ca2_func(0, p->out_ca2);
+ else
+ {
+ if (p->out_ca2_needs_pulled)
+ logerror("cpu #%d (PC=%08X): PIA #%d: Warning! No port CA2 write handler. Previous value has been lost!\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which);
+
+ p->out_ca2_needs_pulled = TRUE;
+ }
+ }
+}
+
+
+static void set_out_cb2(int which, int data)
+{
+ pia6821 *p = &pias[which];
+
+ int z = pia_get_output_cb2_z(which);
+
+ if ((data != p->out_cb2) || (z != p->last_out_cb2_z))
+ {
+ p->out_cb2 = data;
+ p->last_out_cb2_z = z;
+
+ /* send to output function */
+ if (p->intf->out_cb2_func)
+ p->intf->out_cb2_func(0, p->out_cb2);
+ else
+ {
+ if (p->out_cb2_needs_pulled)
+ logerror("cpu #%d (PC=%08X): PIA #%d: Warning! No port CB2 write handler. Previous value has been lost!\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which);
+
+ p->out_cb2_needs_pulled = TRUE;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * CPU interface for reading from the PIA
+ *
+ *************************************/
+
+static UINT8 port_a_r(int which)
+{
+ pia6821 *p = &pias[which];
+
+ UINT8 ret = get_in_a_value(which);
+
+ /* IRQ flags implicitly cleared by a read */
+ p->irq_a1 = FALSE;
+ p->irq_a2 = FALSE;
+ update_interrupts(p);
+
+ /* CA2 is configured as output and in read strobe mode */
+ if (C2_OUTPUT(p->ctl_a) && C2_STROBE_MODE(p->ctl_a))
+ {
+ /* this will cause a transition low */
+ set_out_ca2(which, FALSE);
+
+ /* if the CA2 strobe is cleared by the E, reset it right away */
+ if (STROBE_E_RESET(p->ctl_a))
+ set_out_ca2(which, TRUE);
+ }
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: port A read = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, ret));
+
+ return ret;
+}
+
+
+static UINT8 ddr_a_r(int which)
+{
+ pia6821 *p = &pias[which];
+
+ UINT8 ret = p->ddr_a;
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: DDR A read = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, ret));
+
+ return ret;
+}
+
+
+static UINT8 port_b_r(int which)
+{
+ pia6821 *p = &pias[which];
+
+ UINT8 ret = get_in_b_value(which);
+
+ /* This read will implicitly clear the IRQ B1 flag. If CB2 is in write-strobe
+ mode with CB1 restore, and a CB1 active transition set the flag,
+ clearing it will cause CB2 to go high again. Note that this is different
+ from what happens with port A. */
+ if (p->irq_b1 && C2_STROBE_MODE(p->ctl_b) && STROBE_C1_RESET(p->ctl_b))
+ set_out_cb2(which, TRUE);
+
+ /* IRQ flags implicitly cleared by a read */
+ p->irq_b1 = FALSE;
+ p->irq_b2 = FALSE;
+ update_interrupts(p);
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: port B read = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, ret));
+
+ return ret;
+}
+
+
+static UINT8 ddr_b_r(int which)
+{
+ pia6821 *p = &pias[which];
+
+ UINT8 ret = p->ddr_b;
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: DDR B read = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, ret));
+
+ return ret;
+}
+
+
+static UINT8 control_a_r(int which)
+{
+ pia6821 *p = &pias[which];
+ UINT8 ret;
+
+ /* update CA1 & CA2 if callback exists, these in turn may update IRQ's */
+ if (p->intf->in_ca1_func)
+ pia_set_input_ca1(which, p->intf->in_ca1_func(0));
+ else if (!p->logged_ca1_not_connected && (!p->in_ca1_pushed))
+ {
+ logerror("cpu #%d (PC=%08X): PIA #%d: Warning! No CA1 read handler. Assuming pin not connected\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which);
+ p->logged_ca1_not_connected = TRUE;
+ }
+
+ if (p->intf->in_ca2_func)
+ pia_set_input_ca2(which, p->intf->in_ca2_func(0));
+ else if ( !p->logged_ca2_not_connected && C2_INPUT(p->ctl_a) && !p->in_ca2_pushed)
+ {
+ logerror("cpu #%d (PC=%08X): PIA #%d: Warning! No CA2 read handler. Assuming pin not connected\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which);
+ p->logged_ca2_not_connected = TRUE;
+ }
+
+ /* read control register */
+ ret = p->ctl_a;
+
+ /* set the IRQ flags if we have pending IRQs */
+ if (p->irq_a1)
+ ret |= PIA_IRQ1;
+
+ if (p->irq_a2 && C2_INPUT(p->ctl_a))
+ ret |= PIA_IRQ2;
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: control A read = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, ret));
+
+ return ret;
+}
+
+
+static UINT8 control_b_r(int which)
+{
+ pia6821 *p = &pias[which];
+ UINT8 ret;
+
+ /* update CB1 & CB2 if callback exists, these in turn may update IRQ's */
+ if (p->intf->in_cb1_func)
+ pia_set_input_cb1(which, p->intf->in_cb1_func(0));
+ else if (!p->logged_cb1_not_connected && !p->in_cb1_pushed)
+ {
+ logerror("cpu #%d (PC=%08X): PIA #%d: Error! no CB1 read handler. Three-state pin is undefined\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which);
+ p->logged_cb1_not_connected = TRUE;
+ }
+
+ if (p->intf->in_cb2_func)
+ pia_set_input_cb2(which, p->intf->in_cb2_func(0));
+ else if (!p->logged_cb2_not_connected && C2_INPUT(p->ctl_b) && !p->in_cb2_pushed)
+ {
+ logerror("cpu #%d (PC=%08X): PIA #%d: Error! No CB2 read handler. Three-state pin is undefined\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which);
+ p->logged_cb2_not_connected = TRUE;
+ }
+
+ /* read control register */
+ ret = p->ctl_b;
+
+ /* set the IRQ flags if we have pending IRQs */
+ if (p->irq_b1)
+ ret |= PIA_IRQ1;
+
+ if (p->irq_b2 && C2_INPUT(p->ctl_b))
+ ret |= PIA_IRQ2;
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: control B read = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, ret));
+
+ return ret;
+}
+
+
+UINT8 pia_read(int which, offs_t offset)
+{
+ pia6821 *p = &pias[which];
+ UINT8 ret;
+
+ switch (offset & 0x03)
+ {
+ default: /* impossible */
+ case 0x00:
+ if (OUTPUT_SELECTED(p->ctl_a))
+ ret = port_a_r(which);
+ else
+ ret = ddr_a_r(which);
+ break;
+
+ case 0x01:
+ ret = control_a_r(which);
+ break;
+
+ case 0x02:
+ if (OUTPUT_SELECTED(p->ctl_b))
+ ret = port_b_r(which);
+ else
+ ret = ddr_b_r(which);
+ break;
+
+ case 0x03:
+ ret = control_b_r(which);
+ break;
+ }
+
+ return ret;
+}
+
+
+UINT8 pia_alt_read(int which, offs_t offset)
+{
+ return pia_read(which, ((offset << 1) & 0x02) | ((offset >> 1) & 0x01));
+}
+
+
+UINT8 pia_get_port_b_z_mask(int which)
+{
+ pia6821 *p = &pias[which];
+
+ return ~p->ddr_b;
+}
+
+
+
+/*************************************
+ *
+ * CPU interface for writing to the PIA
+ *
+ *************************************/
+
+static void send_to_out_a_func(int which, const char* message)
+{
+ pia6821 *p = &pias[which];
+
+ /* input pins are pulled high */
+ UINT8 data = get_out_a_value(which);
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: %s = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, message, data));
+
+ if (p->intf->out_a_func)
+ p->intf->out_a_func(0, data);
+ else
+ {
+ if (p->out_a_needs_pulled)
+ logerror("cpu #%d (PC=%08X): PIA #%d: Warning! No port A write handler. Previous value has been lost!\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which);
+
+ p->out_a_needs_pulled = TRUE;
+ }
+}
+
+
+static void send_to_out_b_func(int which, const char* message)
+{
+ pia6821 *p = &pias[which];
+
+ /* input pins are high-impedance - we just send them as zeros for backwards compatibility */
+ UINT8 data = get_out_b_value(which);
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: %s = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, message, data));
+
+ if (p->intf->out_b_func)
+ p->intf->out_b_func(0, data);
+ else
+ {
+ if (p->out_b_needs_pulled)
+ logerror("cpu #%d (PC=%08X): PIA #%d: Warning! No port B write handler. Previous value has been lost!\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which);
+
+ p->out_b_needs_pulled = TRUE;
+ }
+}
+
+
+static void port_a_w(int which, UINT8 data)
+{
+ pia6821 *p = &pias[which];
+
+ /* buffer the output value */
+ p->out_a = data;
+
+ send_to_out_a_func(which, "port A write");
+}
+
+
+static void ddr_a_w(int which, UINT8 data)
+{
+ pia6821 *p = &pias[which];
+
+ if (data == 0x00)
+ LOG(("cpu #%d (PC=%08X): PIA #%d: DDR A write = %02X (input mode)\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, data));
+ else if (data == 0xff)
+ LOG(("cpu #%d (PC=%08X): PIA #%d: DDR A write = %02X (output mode)\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, data));
+ else
+ LOG(("cpu #%d (PC=%08X): PIA #%d: DDR A write = %02X (mixed mode)\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, data));
+
+ if (p->ddr_a != data)
+ {
+ /* DDR changed, call the callback again */
+ p->ddr_a = data;
+ p->logged_port_a_not_connected = FALSE;
+ send_to_out_a_func(which, "port A write due to DDR change");
+ }
+}
+
+
+static void port_b_w(int which, UINT8 data)
+{
+ pia6821 *p = &pias[which];
+
+ /* buffer the output value */
+ p->out_b = data;
+
+ send_to_out_b_func(which, "port B write");
+
+ /* CB2 in write strobe mode */
+ if (C2_STROBE_MODE(p->ctl_b))
+ {
+ /* this will cause a transition low */
+ set_out_cb2(which, FALSE);
+
+ /* if the CB2 strobe is cleared by the E, reset it right away */
+ if (STROBE_E_RESET(p->ctl_b))
+ set_out_cb2(which, TRUE);
+ }
+}
+
+
+static void ddr_b_w(int which, UINT8 data)
+{
+ pia6821 *p = &pias[which];
+
+ if (data == 0x00)
+ LOG(("cpu #%d (PC=%08X): PIA #%d: DDR B write = %02X (input mode)\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, data));
+ else if (data == 0xff)
+ LOG(("cpu #%d (PC=%08X): PIA #%d: DDR B write = %02X (output mode)\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, data));
+ else
+ LOG(("cpu #%d (PC=%08X): PIA #%d: DDR B write = %02X (mixed mode)\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, data));
+
+ if (p->ddr_b != data)
+ {
+ /* DDR changed, call the callback again */
+ p->ddr_b = data;
+ p->logged_port_b_not_connected = FALSE;
+ send_to_out_b_func(which, "port B write due to DDR change");
+ }
+}
+
+
+static void control_a_w(int which, UINT8 data)
+{
+ pia6821 *p = &pias[which];
+
+ /* bit 7 and 6 are read only */
+ data &= 0x3f;
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: control A write = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, data));
+
+ /* update the control register */
+ p->ctl_a = data;
+
+ /* CA2 is configured as output */
+ if (C2_OUTPUT(p->ctl_a))
+ {
+ int temp;
+
+ if (C2_SET_MODE(p->ctl_a))
+ /* set/reset mode - bit value determines the new output */
+ temp = C2_SET(p->ctl_a);
+ else
+ /* strobe mode - output is always high unless strobed */
+ temp = TRUE;
+
+ set_out_ca2(which, temp);
+ }
+
+ /* update externals */
+ update_interrupts(p);
+}
+
+
+static void control_b_w(int which, UINT8 data)
+{
+ pia6821 *p = &pias[which];
+ int temp;
+
+ /* bit 7 and 6 are read only */
+ data &= 0x3f;
+
+ LOG(("cpu #%d (PC=%08X): PIA #%d: control B write = %02X\n", cpu_getactivecpu(), safe_activecpu_get_pc(), which, data));
+
+ /* update the control register */
+ p->ctl_b = data;
+
+ if (C2_SET_MODE(p->ctl_b))
+ /* set/reset mode - bit value determines the new output */
+ temp = C2_SET(p->ctl_b);
+ else
+ /* strobe mode - output is always high unless strobed */
+ temp = TRUE;
+
+ set_out_cb2(which, temp);
+
+ /* update externals */
+ update_interrupts(p);
+}
+
+
+void pia_write(int which, offs_t offset, UINT8 data)
+{
+ pia6821 *p = &pias[which];
+
+ switch (offset & 0x03)
+ {
+ default: /* impossible */
+ case 0x00:
+ if (OUTPUT_SELECTED(p->ctl_a))
+ port_a_w(which, data);
+ else
+ ddr_a_w(which, data);
+ break;
+
+ case 0x01:
+ control_a_w(which, data);
+ break;
+
+ case 0x02:
+ if (OUTPUT_SELECTED(p->ctl_b))
+ port_b_w(which, data);
+ else
+ ddr_b_w(which, data);
+ break;
+
+ case 0x03:
+ control_b_w(which, data);
+ break;
+ }
+}
+
+
+void pia_alt_write(int which, offs_t offset, UINT8 data)
+{
+ pia_write(which, ((offset << 1) & 0x02) | ((offset >> 1) & 0x01), data);
+}
+
+
+void pia_set_port_a_z_mask(int which, UINT8 data)
+{
+ pia6821 *p = &pias[which];
+
+ p->port_a_z_mask = data;
+}
+
+
+
+/*************************************
+ *
+ * Device interface to port A
+ *
+ *************************************/
+
+void pia_set_input_a(int which, UINT8 data, UINT8 z_mask)
+{
+ pia6821 *p = &pias[which];
+
+ assert_always(p->intf->in_a_func == NULL, "pia_set_input_a() called when in_a_func implemented");
+
+ p->in_a = data;
+ p->port_a_z_mask = z_mask;
+ p->in_a_pushed = TRUE;
+}
+
+
+UINT8 pia_get_output_a(int which)
+{
+ pia6821 *p = &pias[which];
+
+ p->out_a_needs_pulled = FALSE;
+
+ return get_out_a_value(which);
+}
+
+
+
+/*************************************
+ *
+ * Device interface to the CA1 pin
+ *
+ *************************************/
+
+void pia_set_input_ca1(int which, int data)
+{
+ pia6821 *p = &pias[which];
+
+ /* limit the data to 0 or 1 */
+ data = data ? TRUE : FALSE;
+
+ /* the new state has caused a transition */
+ if ((p->in_ca1 != data) &&
+ ((data && C1_LOW_TO_HIGH(p->ctl_a)) || (!data && C1_HIGH_TO_LOW(p->ctl_a))))
+ {
+ /* mark the IRQ */
+ p->irq_a1 = TRUE;
+
+ /* update externals */
+ update_interrupts(p);
+
+ /* CA2 is configured as output and in read strobe mode and cleared by a CA1 transition */
+ if (C2_OUTPUT(p->ctl_a) && C2_STROBE_MODE(p->ctl_a) && STROBE_C1_RESET(p->ctl_a))
+ set_out_ca2(which, TRUE);
+ }
+
+ /* set the new value for CA1 */
+ p->in_ca1 = data;
+ p->in_ca1_pushed = TRUE;
+}
+
+
+
+/*************************************
+ *
+ * Device interface to the CA2 pin
+ *
+ *************************************/
+
+void pia_set_input_ca2(int which, int data)
+{
+ pia6821 *p = &pias[which];
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* if input mode and the new state has caused a transition */
+ if (C2_INPUT(p->ctl_a) &&
+ (p->in_ca2 != data) &&
+ ((data && C2_LOW_TO_HIGH(p->ctl_a)) || (!data && C2_HIGH_TO_LOW(p->ctl_a))))
+ {
+ /* mark the IRQ */
+ p->irq_a2 = TRUE;
+
+ /* update externals */
+ update_interrupts(p);
+ }
+
+ /* set the new value for CA2 */
+ p->in_ca2 = data;
+ p->in_ca2_pushed = TRUE;
+}
+
+
+int pia_get_output_ca2(int which)
+{
+ pia6821 *p = &pias[which];
+
+ p->out_ca2_needs_pulled = FALSE;
+
+ return p->out_ca2;
+}
+
+
+
+/*************************************
+ *
+ * Device interface to port B
+ *
+ *************************************/
+
+void pia_set_input_b(int which, UINT8 data)
+{
+ pia6821 *p = &pias[which];
+
+ assert_always(p->intf->in_b_func == NULL, "pia_set_input_b() called when in_b_func implemented");
+
+ p->in_b = data;
+ p->in_b_pushed = TRUE;
+}
+
+
+
+UINT8 pia_get_output_b(int which)
+{
+ pia6821 *p = &pias[which];
+
+ p->out_b_needs_pulled = FALSE;
+
+ return get_out_b_value(which);
+}
+
+
+
+/*************************************
+ *
+ * Device interface to the CB1 pin
+ *
+ *************************************/
+
+void pia_set_input_cb1(int which, int data)
+{
+ pia6821 *p = &pias[which];
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* the new state has caused a transition */
+ if ((p->in_cb1 != data) &&
+ ((data && C1_LOW_TO_HIGH(p->ctl_b)) || (!data && C1_HIGH_TO_LOW(p->ctl_b))))
+ {
+ /* mark the IRQ */
+ p->irq_b1 = 1;
+
+ /* update externals */
+ update_interrupts(p);
+
+ /* If CB2 is configured as a write-strobe output which is reset by a CB1
+ transition, this reset will only happen when a read from port B implicitly
+ clears the IRQ B1 flag. So we handle the CB2 reset there. Note that this
+ is different from what happens with port A. */
+ }
+
+ /* set the new value for CB1 */
+ p->in_cb1 = data;
+ p->in_cb1_pushed = TRUE;
+}
+
+
+
+/*************************************
+ *
+ * Device interface to the CB2 pin
+ *
+ *************************************/
+
+void pia_set_input_cb2(int which, int data)
+{
+ pia6821 *p = &pias[which];
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* if input mode and the new state has caused a transition */
+ if (C2_INPUT(p->ctl_b) &&
+ (p->in_cb2 != data) &&
+ ((data && C2_LOW_TO_HIGH(p->ctl_b)) || (!data && C2_HIGH_TO_LOW(p->ctl_b))))
+ {
+ /* mark the IRQ */
+ p->irq_b2 = 1;
+
+ /* update externals */
+ update_interrupts(p);
+ }
+
+ /* set the new value for CA2 */
+ p->in_cb2 = data;
+ p->in_cb2_pushed = TRUE;
+}
+
+
+int pia_get_output_cb2(int which)
+{
+ pia6821 *p = &pias[which];
+
+ p->out_cb2_needs_pulled = FALSE;
+
+ return p->out_cb2;
+}
+
+
+int pia_get_output_cb2_z(int which)
+{
+ pia6821 *p = &pias[which];
+
+ return !C2_OUTPUT(p->ctl_b);
+}
+
+
+
+/*************************************
+ *
+ * Convinience interface for
+ * retrieving the IRQ state
+ *
+ *************************************/
+
+int pia_get_irq_a(int which)
+{
+ pia6821 *p = &pias[which];
+
+ return p->irq_a_state;
+}
+
+
+int pia_get_irq_b(int which)
+{
+ pia6821 *p = &pias[which];
+
+ return p->irq_b_state;
+}
+
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+READ8_HANDLER( pia_0_r ) { return pia_read(0, offset); }
+READ8_HANDLER( pia_1_r ) { return pia_read(1, offset); }
+READ8_HANDLER( pia_2_r ) { return pia_read(2, offset); }
+READ8_HANDLER( pia_3_r ) { return pia_read(3, offset); }
+READ8_HANDLER( pia_4_r ) { return pia_read(4, offset); }
+READ8_HANDLER( pia_5_r ) { return pia_read(5, offset); }
+READ8_HANDLER( pia_6_r ) { return pia_read(6, offset); }
+READ8_HANDLER( pia_7_r ) { return pia_read(7, offset); }
+
+WRITE8_HANDLER( pia_0_w ) { pia_write(0, offset, data); }
+WRITE8_HANDLER( pia_1_w ) { pia_write(1, offset, data); }
+WRITE8_HANDLER( pia_2_w ) { pia_write(2, offset, data); }
+WRITE8_HANDLER( pia_3_w ) { pia_write(3, offset, data); }
+WRITE8_HANDLER( pia_4_w ) { pia_write(4, offset, data); }
+WRITE8_HANDLER( pia_5_w ) { pia_write(5, offset, data); }
+WRITE8_HANDLER( pia_6_w ) { pia_write(6, offset, data); }
+WRITE8_HANDLER( pia_7_w ) { pia_write(7, offset, data); }
+
+READ8_HANDLER( pia_0_alt_r ) { return pia_alt_read(0, offset); }
+READ8_HANDLER( pia_1_alt_r ) { return pia_alt_read(1, offset); }
+READ8_HANDLER( pia_2_alt_r ) { return pia_alt_read(2, offset); }
+READ8_HANDLER( pia_3_alt_r ) { return pia_alt_read(3, offset); }
+READ8_HANDLER( pia_4_alt_r ) { return pia_alt_read(4, offset); }
+READ8_HANDLER( pia_5_alt_r ) { return pia_alt_read(5, offset); }
+READ8_HANDLER( pia_6_alt_r ) { return pia_alt_read(6, offset); }
+READ8_HANDLER( pia_7_alt_r ) { return pia_alt_read(7, offset); }
+
+WRITE8_HANDLER( pia_0_alt_w ) { pia_alt_write(0, offset, data); }
+WRITE8_HANDLER( pia_1_alt_w ) { pia_alt_write(1, offset, data); }
+WRITE8_HANDLER( pia_2_alt_w ) { pia_alt_write(2, offset, data); }
+WRITE8_HANDLER( pia_3_alt_w ) { pia_alt_write(3, offset, data); }
+WRITE8_HANDLER( pia_4_alt_w ) { pia_alt_write(4, offset, data); }
+WRITE8_HANDLER( pia_5_alt_w ) { pia_alt_write(5, offset, data); }
+WRITE8_HANDLER( pia_6_alt_w ) { pia_alt_write(6, offset, data); }
+WRITE8_HANDLER( pia_7_alt_w ) { pia_alt_write(7, offset, data); }
+
+/******************* Standard 16-bit CPU interfaces, D0-D7 *******************/
+
+READ16_HANDLER( pia_0_lsb_r ) { return pia_read(0, offset); }
+READ16_HANDLER( pia_1_lsb_r ) { return pia_read(1, offset); }
+READ16_HANDLER( pia_2_lsb_r ) { return pia_read(2, offset); }
+READ16_HANDLER( pia_3_lsb_r ) { return pia_read(3, offset); }
+READ16_HANDLER( pia_4_lsb_r ) { return pia_read(4, offset); }
+READ16_HANDLER( pia_5_lsb_r ) { return pia_read(5, offset); }
+READ16_HANDLER( pia_6_lsb_r ) { return pia_read(6, offset); }
+READ16_HANDLER( pia_7_lsb_r ) { return pia_read(7, offset); }
+
+WRITE16_HANDLER( pia_0_lsb_w ) { if (ACCESSING_LSB) pia_write(0, offset, data); }
+WRITE16_HANDLER( pia_1_lsb_w ) { if (ACCESSING_LSB) pia_write(1, offset, data); }
+WRITE16_HANDLER( pia_2_lsb_w ) { if (ACCESSING_LSB) pia_write(2, offset, data); }
+WRITE16_HANDLER( pia_3_lsb_w ) { if (ACCESSING_LSB) pia_write(3, offset, data); }
+WRITE16_HANDLER( pia_4_lsb_w ) { if (ACCESSING_LSB) pia_write(4, offset, data); }
+WRITE16_HANDLER( pia_5_lsb_w ) { if (ACCESSING_LSB) pia_write(5, offset, data); }
+WRITE16_HANDLER( pia_6_lsb_w ) { if (ACCESSING_LSB) pia_write(6, offset, data); }
+WRITE16_HANDLER( pia_7_lsb_w ) { if (ACCESSING_LSB) pia_write(7, offset, data); }
+
+READ16_HANDLER( pia_0_lsb_alt_r ) { return pia_alt_read(0, offset); }
+READ16_HANDLER( pia_1_lsb_alt_r ) { return pia_alt_read(1, offset); }
+READ16_HANDLER( pia_2_lsb_alt_r ) { return pia_alt_read(2, offset); }
+READ16_HANDLER( pia_3_lsb_alt_r ) { return pia_alt_read(3, offset); }
+READ16_HANDLER( pia_4_lsb_alt_r ) { return pia_alt_read(4, offset); }
+READ16_HANDLER( pia_5_lsb_alt_r ) { return pia_alt_read(5, offset); }
+READ16_HANDLER( pia_6_lsb_alt_r ) { return pia_alt_read(6, offset); }
+READ16_HANDLER( pia_7_lsb_alt_r ) { return pia_alt_read(7, offset); }
+
+WRITE16_HANDLER( pia_0_lsb_alt_w ) { if (ACCESSING_LSB) pia_alt_write(0, offset, data); }
+WRITE16_HANDLER( pia_1_lsb_alt_w ) { if (ACCESSING_LSB) pia_alt_write(1, offset, data); }
+WRITE16_HANDLER( pia_2_lsb_alt_w ) { if (ACCESSING_LSB) pia_alt_write(2, offset, data); }
+WRITE16_HANDLER( pia_3_lsb_alt_w ) { if (ACCESSING_LSB) pia_alt_write(3, offset, data); }
+WRITE16_HANDLER( pia_4_lsb_alt_w ) { if (ACCESSING_LSB) pia_alt_write(4, offset, data); }
+WRITE16_HANDLER( pia_5_lsb_alt_w ) { if (ACCESSING_LSB) pia_alt_write(5, offset, data); }
+WRITE16_HANDLER( pia_6_lsb_alt_w ) { if (ACCESSING_LSB) pia_alt_write(6, offset, data); }
+WRITE16_HANDLER( pia_7_lsb_alt_w ) { if (ACCESSING_LSB) pia_alt_write(7, offset, data); }
+
+/******************* Standard 16-bit CPU interfaces, D8-D15 *******************/
+
+READ16_HANDLER( pia_0_msb_r ) { return pia_read(0, offset) << 8; }
+READ16_HANDLER( pia_1_msb_r ) { return pia_read(1, offset) << 8; }
+READ16_HANDLER( pia_2_msb_r ) { return pia_read(2, offset) << 8; }
+READ16_HANDLER( pia_3_msb_r ) { return pia_read(3, offset) << 8; }
+READ16_HANDLER( pia_4_msb_r ) { return pia_read(4, offset) << 8; }
+READ16_HANDLER( pia_5_msb_r ) { return pia_read(5, offset) << 8; }
+READ16_HANDLER( pia_6_msb_r ) { return pia_read(6, offset) << 8; }
+READ16_HANDLER( pia_7_msb_r ) { return pia_read(7, offset) << 8; }
+
+WRITE16_HANDLER( pia_0_msb_w ) { if (ACCESSING_MSB) pia_write(0, offset, data >> 8); }
+WRITE16_HANDLER( pia_1_msb_w ) { if (ACCESSING_MSB) pia_write(1, offset, data >> 8); }
+WRITE16_HANDLER( pia_2_msb_w ) { if (ACCESSING_MSB) pia_write(2, offset, data >> 8); }
+WRITE16_HANDLER( pia_3_msb_w ) { if (ACCESSING_MSB) pia_write(3, offset, data >> 8); }
+WRITE16_HANDLER( pia_4_msb_w ) { if (ACCESSING_MSB) pia_write(4, offset, data >> 8); }
+WRITE16_HANDLER( pia_5_msb_w ) { if (ACCESSING_MSB) pia_write(5, offset, data >> 8); }
+WRITE16_HANDLER( pia_6_msb_w ) { if (ACCESSING_MSB) pia_write(6, offset, data >> 8); }
+WRITE16_HANDLER( pia_7_msb_w ) { if (ACCESSING_MSB) pia_write(7, offset, data >> 8); }
+
+READ16_HANDLER( pia_0_msb_alt_r ) { return pia_alt_read(0, offset) << 8; }
+READ16_HANDLER( pia_1_msb_alt_r ) { return pia_alt_read(1, offset) << 8; }
+READ16_HANDLER( pia_2_msb_alt_r ) { return pia_alt_read(2, offset) << 8; }
+READ16_HANDLER( pia_3_msb_alt_r ) { return pia_alt_read(3, offset) << 8; }
+READ16_HANDLER( pia_4_msb_alt_r ) { return pia_alt_read(4, offset) << 8; }
+READ16_HANDLER( pia_5_msb_alt_r ) { return pia_alt_read(5, offset) << 8; }
+READ16_HANDLER( pia_6_msb_alt_r ) { return pia_alt_read(6, offset) << 8; }
+READ16_HANDLER( pia_7_msb_alt_r ) { return pia_alt_read(7, offset) << 8; }
+
+WRITE16_HANDLER( pia_0_msb_alt_w ) { if (ACCESSING_MSB) pia_alt_write(0, offset, data >> 8); }
+WRITE16_HANDLER( pia_1_msb_alt_w ) { if (ACCESSING_MSB) pia_alt_write(1, offset, data >> 8); }
+WRITE16_HANDLER( pia_2_msb_alt_w ) { if (ACCESSING_MSB) pia_alt_write(2, offset, data >> 8); }
+WRITE16_HANDLER( pia_3_msb_alt_w ) { if (ACCESSING_MSB) pia_alt_write(3, offset, data >> 8); }
+WRITE16_HANDLER( pia_4_msb_alt_w ) { if (ACCESSING_MSB) pia_alt_write(4, offset, data >> 8); }
+WRITE16_HANDLER( pia_5_msb_alt_w ) { if (ACCESSING_MSB) pia_alt_write(5, offset, data >> 8); }
+WRITE16_HANDLER( pia_6_msb_alt_w ) { if (ACCESSING_MSB) pia_alt_write(6, offset, data >> 8); }
+WRITE16_HANDLER( pia_7_msb_alt_w ) { if (ACCESSING_MSB) pia_alt_write(7, offset, data >> 8); }
+
+/******************* 8-bit A/B port interfaces *******************/
+
+WRITE8_HANDLER( pia_0_porta_w ) { pia_set_input_a(0, data, 0); }
+WRITE8_HANDLER( pia_1_porta_w ) { pia_set_input_a(1, data, 0); }
+WRITE8_HANDLER( pia_2_porta_w ) { pia_set_input_a(2, data, 0); }
+WRITE8_HANDLER( pia_3_porta_w ) { pia_set_input_a(3, data, 0); }
+WRITE8_HANDLER( pia_4_porta_w ) { pia_set_input_a(4, data, 0); }
+WRITE8_HANDLER( pia_5_porta_w ) { pia_set_input_a(5, data, 0); }
+WRITE8_HANDLER( pia_6_porta_w ) { pia_set_input_a(6, data, 0); }
+WRITE8_HANDLER( pia_7_porta_w ) { pia_set_input_a(7, data, 0); }
+
+WRITE8_HANDLER( pia_0_portb_w ) { pia_set_input_b(0, data); }
+WRITE8_HANDLER( pia_1_portb_w ) { pia_set_input_b(1, data); }
+WRITE8_HANDLER( pia_2_portb_w ) { pia_set_input_b(2, data); }
+WRITE8_HANDLER( pia_3_portb_w ) { pia_set_input_b(3, data); }
+WRITE8_HANDLER( pia_4_portb_w ) { pia_set_input_b(4, data); }
+WRITE8_HANDLER( pia_5_portb_w ) { pia_set_input_b(5, data); }
+WRITE8_HANDLER( pia_6_portb_w ) { pia_set_input_b(6, data); }
+WRITE8_HANDLER( pia_7_portb_w ) { pia_set_input_b(7, data); }
+
+READ8_HANDLER( pia_0_porta_r ) { return pias[0].in_a; }
+READ8_HANDLER( pia_1_porta_r ) { return pias[1].in_a; }
+READ8_HANDLER( pia_2_porta_r ) { return pias[2].in_a; }
+READ8_HANDLER( pia_3_porta_r ) { return pias[3].in_a; }
+READ8_HANDLER( pia_4_porta_r ) { return pias[4].in_a; }
+READ8_HANDLER( pia_5_porta_r ) { return pias[5].in_a; }
+READ8_HANDLER( pia_6_porta_r ) { return pias[6].in_a; }
+READ8_HANDLER( pia_7_porta_r ) { return pias[7].in_a; }
+
+READ8_HANDLER( pia_0_portb_r ) { return pias[0].in_b; }
+READ8_HANDLER( pia_1_portb_r ) { return pias[1].in_b; }
+READ8_HANDLER( pia_2_portb_r ) { return pias[2].in_b; }
+READ8_HANDLER( pia_3_portb_r ) { return pias[3].in_b; }
+READ8_HANDLER( pia_4_portb_r ) { return pias[4].in_b; }
+READ8_HANDLER( pia_5_portb_r ) { return pias[5].in_b; }
+READ8_HANDLER( pia_6_portb_r ) { return pias[6].in_b; }
+READ8_HANDLER( pia_7_portb_r ) { return pias[7].in_b; }
+
+/******************* 1-bit CA1/CA2/CB1/CB2 port interfaces *******************/
+
+WRITE8_HANDLER( pia_0_ca1_w ) { pia_set_input_ca1(0, data); }
+WRITE8_HANDLER( pia_1_ca1_w ) { pia_set_input_ca1(1, data); }
+WRITE8_HANDLER( pia_2_ca1_w ) { pia_set_input_ca1(2, data); }
+WRITE8_HANDLER( pia_3_ca1_w ) { pia_set_input_ca1(3, data); }
+WRITE8_HANDLER( pia_4_ca1_w ) { pia_set_input_ca1(4, data); }
+WRITE8_HANDLER( pia_5_ca1_w ) { pia_set_input_ca1(5, data); }
+WRITE8_HANDLER( pia_6_ca1_w ) { pia_set_input_ca1(6, data); }
+WRITE8_HANDLER( pia_7_ca1_w ) { pia_set_input_ca1(7, data); }
+
+WRITE8_HANDLER( pia_0_ca2_w ) { pia_set_input_ca2(0, data); }
+WRITE8_HANDLER( pia_1_ca2_w ) { pia_set_input_ca2(1, data); }
+WRITE8_HANDLER( pia_2_ca2_w ) { pia_set_input_ca2(2, data); }
+WRITE8_HANDLER( pia_3_ca2_w ) { pia_set_input_ca2(3, data); }
+WRITE8_HANDLER( pia_4_ca2_w ) { pia_set_input_ca2(4, data); }
+WRITE8_HANDLER( pia_5_ca2_w ) { pia_set_input_ca2(5, data); }
+WRITE8_HANDLER( pia_6_ca2_w ) { pia_set_input_ca2(6, data); }
+WRITE8_HANDLER( pia_7_ca2_w ) { pia_set_input_ca2(7, data); }
+
+WRITE8_HANDLER( pia_0_cb1_w ) { pia_set_input_cb1(0, data); }
+WRITE8_HANDLER( pia_1_cb1_w ) { pia_set_input_cb1(1, data); }
+WRITE8_HANDLER( pia_2_cb1_w ) { pia_set_input_cb1(2, data); }
+WRITE8_HANDLER( pia_3_cb1_w ) { pia_set_input_cb1(3, data); }
+WRITE8_HANDLER( pia_4_cb1_w ) { pia_set_input_cb1(4, data); }
+WRITE8_HANDLER( pia_5_cb1_w ) { pia_set_input_cb1(5, data); }
+WRITE8_HANDLER( pia_6_cb1_w ) { pia_set_input_cb1(6, data); }
+WRITE8_HANDLER( pia_7_cb1_w ) { pia_set_input_cb1(7, data); }
+
+WRITE8_HANDLER( pia_0_cb2_w ) { pia_set_input_cb2(0, data); }
+WRITE8_HANDLER( pia_1_cb2_w ) { pia_set_input_cb2(1, data); }
+WRITE8_HANDLER( pia_2_cb2_w ) { pia_set_input_cb2(2, data); }
+WRITE8_HANDLER( pia_3_cb2_w ) { pia_set_input_cb2(3, data); }
+WRITE8_HANDLER( pia_4_cb2_w ) { pia_set_input_cb2(4, data); }
+WRITE8_HANDLER( pia_5_cb2_w ) { pia_set_input_cb2(5, data); }
+WRITE8_HANDLER( pia_6_cb2_w ) { pia_set_input_cb2(6, data); }
+WRITE8_HANDLER( pia_7_cb2_w ) { pia_set_input_cb2(7, data); }
+
+READ8_HANDLER( pia_0_ca1_r ) { return pias[0].in_ca1; }
+READ8_HANDLER( pia_1_ca1_r ) { return pias[1].in_ca1; }
+READ8_HANDLER( pia_2_ca1_r ) { return pias[2].in_ca1; }
+READ8_HANDLER( pia_3_ca1_r ) { return pias[3].in_ca1; }
+READ8_HANDLER( pia_4_ca1_r ) { return pias[4].in_ca1; }
+READ8_HANDLER( pia_5_ca1_r ) { return pias[5].in_ca1; }
+READ8_HANDLER( pia_6_ca1_r ) { return pias[6].in_ca1; }
+READ8_HANDLER( pia_7_ca1_r ) { return pias[7].in_ca1; }
+
+READ8_HANDLER( pia_0_ca2_r ) { return pias[0].in_ca2; }
+READ8_HANDLER( pia_1_ca2_r ) { return pias[1].in_ca2; }
+READ8_HANDLER( pia_2_ca2_r ) { return pias[2].in_ca2; }
+READ8_HANDLER( pia_3_ca2_r ) { return pias[3].in_ca2; }
+READ8_HANDLER( pia_4_ca2_r ) { return pias[4].in_ca2; }
+READ8_HANDLER( pia_5_ca2_r ) { return pias[5].in_ca2; }
+READ8_HANDLER( pia_6_ca2_r ) { return pias[6].in_ca2; }
+READ8_HANDLER( pia_7_ca2_r ) { return pias[7].in_ca2; }
+
+READ8_HANDLER( pia_0_cb1_r ) { return pias[0].in_cb1; }
+READ8_HANDLER( pia_1_cb1_r ) { return pias[1].in_cb1; }
+READ8_HANDLER( pia_2_cb1_r ) { return pias[2].in_cb1; }
+READ8_HANDLER( pia_3_cb1_r ) { return pias[3].in_cb1; }
+READ8_HANDLER( pia_4_cb1_r ) { return pias[4].in_cb1; }
+READ8_HANDLER( pia_5_cb1_r ) { return pias[5].in_cb1; }
+READ8_HANDLER( pia_6_cb1_r ) { return pias[6].in_cb1; }
+READ8_HANDLER( pia_7_cb1_r ) { return pias[7].in_cb1; }
+
+READ8_HANDLER( pia_0_cb2_r ) { return pias[0].in_cb2; }
+READ8_HANDLER( pia_1_cb2_r ) { return pias[1].in_cb2; }
+READ8_HANDLER( pia_2_cb2_r ) { return pias[2].in_cb2; }
+READ8_HANDLER( pia_3_cb2_r ) { return pias[3].in_cb2; }
+READ8_HANDLER( pia_4_cb2_r ) { return pias[4].in_cb2; }
+READ8_HANDLER( pia_5_cb2_r ) { return pias[5].in_cb2; }
+READ8_HANDLER( pia_6_cb2_r ) { return pias[6].in_cb2; }
+READ8_HANDLER( pia_7_cb2_r ) { return pias[7].in_cb2; }
diff --git a/src/emu/machine/6821pia.h b/src/emu/machine/6821pia.h
new file mode 100644
index 00000000000..1960591cd2f
--- /dev/null
+++ b/src/emu/machine/6821pia.h
@@ -0,0 +1,359 @@
+/**********************************************************************
+
+ Motorola 6821 PIA interface and emulation
+
+ Notes:
+ * pia_get_port_b_z_mask() gives the caller the bitmask
+ that show which bits are high-impendance when
+ reading port B, thus neither 0 or 1.
+ pia_get_output_cb2_z() returns the same
+ information for the CB2 pin
+ * pia_set_port_a_z_mask allows the input callback to
+ indicate which port A bits are disconnected.
+ For these bit, the read operation will return the
+ output buffer's contents
+ * the 'alt' interface functions are used when the A0 and A1
+ address bits are swapped
+ * all 'int' data or return values are Boolean
+
+**********************************************************************/
+
+#ifndef PIA_6821
+#define PIA_6821
+
+
+#define MAX_PIA 8
+
+
+/*------------- PIA interface structure -----------------*/
+
+typedef struct _pia6821_interface pia6821_interface;
+struct _pia6821_interface
+{
+ read8_handler in_a_func;
+ read8_handler in_b_func;
+ read8_handler in_ca1_func;
+ read8_handler in_cb1_func;
+ read8_handler in_ca2_func;
+ read8_handler in_cb2_func;
+ write8_handler out_a_func;
+ write8_handler out_b_func;
+ write8_handler out_ca2_func;
+ write8_handler out_cb2_func;
+ void (*irq_a_func)(int state);
+ void (*irq_b_func)(int state);
+};
+
+
+
+/*------------------ Configuration -----------------------*/
+
+void pia_config(int which, const pia6821_interface *intf);
+
+
+
+/*----------------------- Reset --------------------------*/
+
+void pia_reset(void);
+
+
+
+/*-------------- CPU interface for PIA read --------------*/
+
+UINT8 pia_read(int which, offs_t offset);
+UINT8 pia_alt_read(int which, offs_t offset);
+UINT8 pia_get_port_b_z_mask(int which); /* see first note */
+
+
+
+/*------------- CPU interface for PIA write --------------*/
+
+void pia_write(int which, offs_t offset, UINT8 data);
+void pia_alt_write(int which, offs_t offset, UINT8 data);
+void pia_set_port_a_z_mask(int which, UINT8 data); /* see second note */
+
+
+
+/*------------- Device interface for port A --------------*/
+
+void pia_set_input_a(int which, UINT8 data, UINT8 z_mask);
+UINT8 pia_get_output_a(int which);
+
+
+
+/*----------- Device interface for the CA1 pin -----------*/
+
+void pia_set_input_ca1(int which, int data);
+
+
+
+/*----------- Device interface for the CA2 pin -----------*/
+
+void pia_set_input_ca2(int which, int data);
+int pia_get_output_ca2(int which);
+
+
+
+/*------------- Device interface for port A --------------*/
+
+void pia_set_input_b(int which, UINT8 data);
+UINT8 pia_get_output_b(int which);
+
+
+
+/*----------- Device interface for the CB1 pin -----------*/
+
+void pia_set_input_cb1(int which, int data);
+
+
+
+/*----------- Device interface for the CB2 pin -----------*/
+
+void pia_set_input_cb2(int which, int data);
+int pia_get_output_cb2(int which);
+int pia_get_output_cb2_z(int which); /* see first note */
+
+
+
+/*-- Convinience interface for retrieving the IRQ state --*/
+
+int pia_get_irq_a(int which);
+int pia_get_irq_b(int which);
+
+
+
+/*---------- Standard 8-bit CPU interfaces, D0-D7 --------*/
+
+READ8_HANDLER( pia_0_r );
+READ8_HANDLER( pia_1_r );
+READ8_HANDLER( pia_2_r );
+READ8_HANDLER( pia_3_r );
+READ8_HANDLER( pia_4_r );
+READ8_HANDLER( pia_5_r );
+READ8_HANDLER( pia_6_r );
+READ8_HANDLER( pia_7_r );
+
+WRITE8_HANDLER( pia_0_w );
+WRITE8_HANDLER( pia_1_w );
+WRITE8_HANDLER( pia_2_w );
+WRITE8_HANDLER( pia_3_w );
+WRITE8_HANDLER( pia_4_w );
+WRITE8_HANDLER( pia_5_w );
+WRITE8_HANDLER( pia_6_w );
+WRITE8_HANDLER( pia_7_w );
+
+READ8_HANDLER( pia_0_alt_r );
+READ8_HANDLER( pia_1_alt_r );
+READ8_HANDLER( pia_2_alt_r );
+READ8_HANDLER( pia_3_alt_r );
+READ8_HANDLER( pia_4_alt_r );
+READ8_HANDLER( pia_5_alt_r );
+READ8_HANDLER( pia_6_alt_r );
+READ8_HANDLER( pia_7_alt_r );
+
+WRITE8_HANDLER( pia_0_alt_w );
+WRITE8_HANDLER( pia_1_alt_w );
+WRITE8_HANDLER( pia_2_alt_w );
+WRITE8_HANDLER( pia_3_alt_w );
+WRITE8_HANDLER( pia_4_alt_w );
+WRITE8_HANDLER( pia_5_alt_w );
+WRITE8_HANDLER( pia_6_alt_w );
+WRITE8_HANDLER( pia_7_alt_w );
+
+
+
+/*---------- Standard 16-bit CPU interfaces, D0-D7 -------*/
+
+READ16_HANDLER( pia_0_lsb_r );
+READ16_HANDLER( pia_1_lsb_r );
+READ16_HANDLER( pia_2_lsb_r );
+READ16_HANDLER( pia_3_lsb_r );
+READ16_HANDLER( pia_4_lsb_r );
+READ16_HANDLER( pia_5_lsb_r );
+READ16_HANDLER( pia_6_lsb_r );
+READ16_HANDLER( pia_7_lsb_r );
+
+WRITE16_HANDLER( pia_0_lsb_w );
+WRITE16_HANDLER( pia_1_lsb_w );
+WRITE16_HANDLER( pia_2_lsb_w );
+WRITE16_HANDLER( pia_3_lsb_w );
+WRITE16_HANDLER( pia_4_lsb_w );
+WRITE16_HANDLER( pia_5_lsb_w );
+WRITE16_HANDLER( pia_6_lsb_w );
+WRITE16_HANDLER( pia_7_lsb_w );
+
+READ16_HANDLER( pia_0_lsb_alt_r );
+READ16_HANDLER( pia_1_lsb_alt_r );
+READ16_HANDLER( pia_2_lsb_alt_r );
+READ16_HANDLER( pia_3_lsb_alt_r );
+READ16_HANDLER( pia_4_lsb_alt_r );
+READ16_HANDLER( pia_5_lsb_alt_r );
+READ16_HANDLER( pia_6_lsb_alt_r );
+READ16_HANDLER( pia_7_lsb_alt_r );
+
+WRITE16_HANDLER( pia_0_lsb_alt_w );
+WRITE16_HANDLER( pia_1_lsb_alt_w );
+WRITE16_HANDLER( pia_2_lsb_alt_w );
+WRITE16_HANDLER( pia_3_lsb_alt_w );
+WRITE16_HANDLER( pia_4_lsb_alt_w );
+WRITE16_HANDLER( pia_5_lsb_alt_w );
+WRITE16_HANDLER( pia_6_lsb_alt_w );
+WRITE16_HANDLER( pia_7_lsb_alt_w );
+
+
+
+/*--------- Standard 16-bit CPU interfaces, D8-D15 -------*/
+
+READ16_HANDLER( pia_0_msb_r );
+READ16_HANDLER( pia_1_msb_r );
+READ16_HANDLER( pia_2_msb_r );
+READ16_HANDLER( pia_3_msb_r );
+READ16_HANDLER( pia_4_msb_r );
+READ16_HANDLER( pia_5_msb_r );
+READ16_HANDLER( pia_6_msb_r );
+READ16_HANDLER( pia_7_msb_r );
+
+WRITE16_HANDLER( pia_0_msb_w );
+WRITE16_HANDLER( pia_1_msb_w );
+WRITE16_HANDLER( pia_2_msb_w );
+WRITE16_HANDLER( pia_3_msb_w );
+WRITE16_HANDLER( pia_4_msb_w );
+WRITE16_HANDLER( pia_5_msb_w );
+WRITE16_HANDLER( pia_6_msb_w );
+WRITE16_HANDLER( pia_7_msb_w );
+
+READ16_HANDLER( pia_0_msb_alt_r );
+READ16_HANDLER( pia_1_msb_alt_r );
+READ16_HANDLER( pia_2_msb_alt_r );
+READ16_HANDLER( pia_3_msb_alt_r );
+READ16_HANDLER( pia_4_msb_alt_r );
+READ16_HANDLER( pia_5_msb_alt_r );
+READ16_HANDLER( pia_6_msb_alt_r );
+READ16_HANDLER( pia_7_msb_alt_r );
+
+WRITE16_HANDLER( pia_0_msb_alt_w );
+WRITE16_HANDLER( pia_1_msb_alt_w );
+WRITE16_HANDLER( pia_2_msb_alt_w );
+WRITE16_HANDLER( pia_3_msb_alt_w );
+WRITE16_HANDLER( pia_4_msb_alt_w );
+WRITE16_HANDLER( pia_5_msb_alt_w );
+WRITE16_HANDLER( pia_6_msb_alt_w );
+WRITE16_HANDLER( pia_7_msb_alt_w );
+
+
+
+/*--------------- 8-bit A/B port interfaces -------------*/
+
+WRITE8_HANDLER( pia_0_porta_w );
+WRITE8_HANDLER( pia_1_porta_w );
+WRITE8_HANDLER( pia_2_porta_w );
+WRITE8_HANDLER( pia_3_porta_w );
+WRITE8_HANDLER( pia_4_porta_w );
+WRITE8_HANDLER( pia_5_porta_w );
+WRITE8_HANDLER( pia_6_porta_w );
+WRITE8_HANDLER( pia_7_porta_w );
+
+WRITE8_HANDLER( pia_0_portb_w );
+WRITE8_HANDLER( pia_1_portb_w );
+WRITE8_HANDLER( pia_2_portb_w );
+WRITE8_HANDLER( pia_3_portb_w );
+WRITE8_HANDLER( pia_4_portb_w );
+WRITE8_HANDLER( pia_5_portb_w );
+WRITE8_HANDLER( pia_6_portb_w );
+WRITE8_HANDLER( pia_7_portb_w );
+
+READ8_HANDLER( pia_0_porta_r );
+READ8_HANDLER( pia_1_porta_r );
+READ8_HANDLER( pia_2_porta_r );
+READ8_HANDLER( pia_3_porta_r );
+READ8_HANDLER( pia_4_porta_r );
+READ8_HANDLER( pia_5_porta_r );
+READ8_HANDLER( pia_6_porta_r );
+READ8_HANDLER( pia_7_porta_r );
+
+READ8_HANDLER( pia_0_portb_r );
+READ8_HANDLER( pia_1_portb_r );
+READ8_HANDLER( pia_2_portb_r );
+READ8_HANDLER( pia_3_portb_r );
+READ8_HANDLER( pia_4_portb_r );
+READ8_HANDLER( pia_5_portb_r );
+READ8_HANDLER( pia_6_portb_r );
+READ8_HANDLER( pia_7_portb_r );
+
+
+
+/*--------- 1-bit CA1/CA2/CB1/CB2 port interfaces -------*/
+
+WRITE8_HANDLER( pia_0_ca1_w );
+WRITE8_HANDLER( pia_1_ca1_w );
+WRITE8_HANDLER( pia_2_ca1_w );
+WRITE8_HANDLER( pia_3_ca1_w );
+WRITE8_HANDLER( pia_4_ca1_w );
+WRITE8_HANDLER( pia_5_ca1_w );
+WRITE8_HANDLER( pia_6_ca1_w );
+WRITE8_HANDLER( pia_7_ca1_w );
+
+WRITE8_HANDLER( pia_0_ca2_w );
+WRITE8_HANDLER( pia_1_ca2_w );
+WRITE8_HANDLER( pia_2_ca2_w );
+WRITE8_HANDLER( pia_3_ca2_w );
+WRITE8_HANDLER( pia_4_ca2_w );
+WRITE8_HANDLER( pia_5_ca2_w );
+WRITE8_HANDLER( pia_6_ca2_w );
+WRITE8_HANDLER( pia_7_ca2_w );
+
+WRITE8_HANDLER( pia_0_cb1_w );
+WRITE8_HANDLER( pia_1_cb1_w );
+WRITE8_HANDLER( pia_2_cb1_w );
+WRITE8_HANDLER( pia_3_cb1_w );
+WRITE8_HANDLER( pia_4_cb1_w );
+WRITE8_HANDLER( pia_5_cb1_w );
+WRITE8_HANDLER( pia_6_cb1_w );
+WRITE8_HANDLER( pia_7_cb1_w );
+
+WRITE8_HANDLER( pia_0_cb2_w );
+WRITE8_HANDLER( pia_1_cb2_w );
+WRITE8_HANDLER( pia_2_cb2_w );
+WRITE8_HANDLER( pia_3_cb2_w );
+WRITE8_HANDLER( pia_4_cb2_w );
+WRITE8_HANDLER( pia_5_cb2_w );
+WRITE8_HANDLER( pia_6_cb2_w );
+WRITE8_HANDLER( pia_7_cb2_w );
+
+READ8_HANDLER( pia_0_ca1_r );
+READ8_HANDLER( pia_1_ca1_r );
+READ8_HANDLER( pia_2_ca1_r );
+READ8_HANDLER( pia_3_ca1_r );
+READ8_HANDLER( pia_4_ca1_r );
+READ8_HANDLER( pia_5_ca1_r );
+READ8_HANDLER( pia_6_ca1_r );
+READ8_HANDLER( pia_7_ca1_r );
+
+READ8_HANDLER( pia_0_ca2_r );
+READ8_HANDLER( pia_1_ca2_r );
+READ8_HANDLER( pia_2_ca2_r );
+READ8_HANDLER( pia_3_ca2_r );
+READ8_HANDLER( pia_4_ca2_r );
+READ8_HANDLER( pia_5_ca2_r );
+READ8_HANDLER( pia_6_ca2_r );
+READ8_HANDLER( pia_7_ca2_r );
+
+READ8_HANDLER( pia_0_cb1_r );
+READ8_HANDLER( pia_1_cb1_r );
+READ8_HANDLER( pia_2_cb1_r );
+READ8_HANDLER( pia_3_cb1_r );
+READ8_HANDLER( pia_4_cb1_r );
+READ8_HANDLER( pia_5_cb1_r );
+READ8_HANDLER( pia_6_cb1_r );
+READ8_HANDLER( pia_7_cb1_r );
+
+READ8_HANDLER( pia_0_cb2_r );
+READ8_HANDLER( pia_1_cb2_r );
+READ8_HANDLER( pia_2_cb2_r );
+READ8_HANDLER( pia_3_cb2_r );
+READ8_HANDLER( pia_4_cb2_r );
+READ8_HANDLER( pia_5_cb2_r );
+READ8_HANDLER( pia_6_cb2_r );
+READ8_HANDLER( pia_7_cb2_r );
+
+#endif
diff --git a/src/emu/machine/6840ptm.c b/src/emu/machine/6840ptm.c
new file mode 100644
index 00000000000..8fff877fdcf
--- /dev/null
+++ b/src/emu/machine/6840ptm.c
@@ -0,0 +1,703 @@
+/**********************************************************************
+
+
+ Motorola 6840 PTM interface and emulation
+
+ This function is a simple emulation of up to 4 MC6840
+ Programmable Timer Modules
+
+ Written By El Condor based on previous work by Aaron Giles,
+ 'Re-Animator' and Mathis Rosenhauer.
+
+ Todo:
+ Confirm handling for 'Single Shot' operation.
+ (Datasheet suggests that output starts high, going low
+ on timeout, opposite of continuous case)
+ Establish whether ptm6840_set_c? routines can replace
+ hard coding of external clock frequencies.
+
+
+ Operation:
+ The interface is arranged as follows:
+
+ Internal Clock frequency,
+ Clock 1 frequency, Clock 2 frequency, Clock 3 frequency,
+ Clock 1 output, Clock 2 output, Clock 3 output,
+ IRQ function
+
+ If the external clock frequencies are not fixed, they should be
+ entered as '0', and the ptm6840_set_c?(which, state) functions
+ should be used instead if necessary (This should allow the VBLANK
+ clock on the MCR units to operate).
+
+**********************************************************************/
+
+#include "driver.h"
+#include "6840ptm.h"
+
+#ifdef MAME_DEBUG
+#define PTMVERBOSE 1
+#else
+#define PTMVERBOSE 0
+#endif
+
+#if PTMVERBOSE
+#define PLOG(x) logerror x
+#else
+#define PLOG(x)
+#endif
+
+#define PTM_6840_CTRL1 0
+#define PTM_6840_CTRL2 1
+#define PTM_6840_MSBBUF1 2
+#define PTM_6840_LSB1 3
+#define PTM_6840_MSBBUF2 4
+#define PTM_6840_LSB2 5
+#define PTM_6840_MSBBUF3 6
+#define PTM_6840_LSB3 7
+
+typedef struct _ptm6840 ptm6840;
+struct _ptm6840
+{
+ const ptm6840_interface *intf;
+
+ UINT8 control_reg[3];
+ UINT8 output[3]; // output states
+ UINT8 gate[3]; // input gate states
+ UINT8 clock[3]; // clock states
+ UINT8 enabled[3];
+ UINT8 mode[3];
+ UINT8 fired[3];
+ UINT8 t3_divisor;
+ UINT8 IRQ;
+ UINT8 status_reg;
+ UINT8 status_read_since_int;
+ UINT8 lsb_buffer;
+ UINT8 msb_buffer;
+
+ int internal_clock;
+ int external_clock[3];
+
+ // each PTM has 3 timers
+ emu_timer *timer[3];
+
+ UINT16 latch[3];
+ UINT16 counter[3];
+};
+
+// local prototypes ///////////////////////////////////////////////////////
+
+static void ptm6840_timeout(int which, int idx);
+static TIMER_CALLBACK( ptm6840_t1_timeout );
+static TIMER_CALLBACK( ptm6840_t2_timeout );
+static TIMER_CALLBACK( ptm6840_t3_timeout );
+
+// local vars /////////////////////////////////////////////////////////////
+
+static ptm6840 ptm[PTM_6840_MAX];
+
+#if PTMVERBOSE
+static const char *opmode[] =
+{
+ "000 continous mode",
+ "001 freq comparison mode",
+ "010 continous mode",
+ "011 pulse width comparison mode",
+ "100 single shot mode",
+ "101 freq comparison mode",
+ "110 single shot mode",
+ "111 pulse width comparison mode"
+};
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// Get enabled status //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+int ptm6840_get_status(int which, int clock)
+{
+ ptm6840 *p = ptm + which;
+ return p->enabled[clock-1];
+}
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// Subtract from Counter //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+static void subtract_from_counter(int counter, int count, int which)
+{
+ int clock;
+ ptm6840 *currptr = ptm + which;
+
+ /* determine the clock frequency for this timer */
+ if (currptr->control_reg[counter] & 0x02)
+ clock = currptr->internal_clock;
+ else
+ clock = currptr->external_clock[counter];
+
+ /* dual-byte mode */
+ if (currptr->control_reg[counter] & 0x04)
+ {
+ int lsb = currptr->counter[counter] & 0xff;
+ int msb = currptr->counter[counter] >> 8;
+
+ /* count the clocks */
+ lsb -= count;
+
+ /* loop while we're less than zero */
+ while (lsb < 0)
+ {
+ /* borrow from the MSB */
+ lsb += (currptr->latch[counter] & 0xff) + 1;
+ msb--;
+ /* if MSB goes less than zero, we've expired */
+ if (msb < 0)
+ {
+ ptm6840_timeout(which, counter);
+ msb = (currptr->latch[counter] >> 8) + 1;
+ }
+ }
+
+ /* store the result */
+ currptr->counter[counter] = (msb << 8) | lsb;
+ timer_adjust(currptr->timer[counter], attotime_mul(ATTOTIME_IN_HZ(clock), currptr->counter[counter]), which, attotime_zero);
+ }
+
+ /* word mode */
+ else
+ {
+ attotime duration;
+ int word = currptr->counter[counter];
+
+ /* count the clocks */
+ word -= count;
+
+ /* loop while we're less than zero */
+ while (word < 0)
+ {
+ /* borrow from the MSB */
+ word += currptr->latch[counter] + 1;
+
+ /* we've expired */
+ ptm6840_timeout(which, counter);
+ }
+
+ /* store the result */
+ currptr->counter[counter] = word;
+ duration = attotime_mul(ATTOTIME_IN_HZ(clock), currptr->counter[counter]);
+ if (counter == 2) duration = attotime_mul(duration, currptr->t3_divisor);
+ timer_adjust(currptr->timer[counter], duration, which, attotime_zero);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// Update Internal Interrupts //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+INLINE void update_interrupts(int which)
+{
+ ptm6840 *currptr = ptm + which;
+ currptr->status_reg &= ~0x80;
+
+ if ((currptr->status_reg & 0x01) && (currptr->control_reg[0] & 0x40)) currptr->status_reg |= 0x80;
+ if ((currptr->status_reg & 0x02) && (currptr->control_reg[1] & 0x40)) currptr->status_reg |= 0x80;
+ if ((currptr->status_reg & 0x04) && (currptr->control_reg[2] & 0x40)) currptr->status_reg |= 0x80;
+
+ currptr->IRQ = currptr->status_reg >> 7;
+
+ if ( currptr->intf->irq_func )
+ {
+ currptr->intf->irq_func(currptr->IRQ);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// Compute Counter //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+static UINT16 compute_counter(int counter, int which)
+{
+ ptm6840 *currptr = ptm + which;
+
+ int clock;
+ int remaining=0;
+
+ /* if there's no timer, return the count */
+ if (!currptr->enabled[counter])
+ return currptr->counter[counter];
+
+ /* determine the clock frequency for this timer */
+ if (currptr->control_reg[counter] & 0x02)
+ {
+ clock = currptr->internal_clock;
+ PLOG(("MC6840 #%d: %d internal clock freq %d \n", which,counter,clock));
+ }
+ else
+ {
+ clock = currptr->external_clock[counter];
+ PLOG(("MC6840 #%d: %d external clock freq %d \n", which,counter,clock));
+ }
+ /* see how many are left */
+ remaining = attotime_to_double(attotime_mul(timer_timeleft(currptr->timer[counter]), clock));
+
+ /* adjust the count for dual byte mode */
+ if (currptr->control_reg[counter] & 0x04)
+ {
+ int divisor = (currptr->counter[counter] & 0xff) + 1;
+ int msb = remaining / divisor;
+ int lsb = remaining % divisor;
+ remaining = (msb << 8) | lsb;
+ }
+ PLOG(("MC6840 #%d: read counter(%d): %d\n", which, counter, remaining));
+ return remaining;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// Reload Counter //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+static void reload_count(int idx, int which)
+{
+ int clock;
+ int count;
+ attotime duration;
+ ptm6840 *currptr = ptm + which;
+
+ /* copy the latched value in */
+ currptr->counter[idx] = currptr->latch[idx];
+
+ /* determine the clock frequency for this timer */
+ if (currptr->control_reg[idx] & 0x02)
+ {
+ clock = currptr->internal_clock;
+ PLOG(("MC6840 #%d: %d internal clock freq %d \n", which,idx, clock));
+ }
+ else
+ {
+ clock = currptr->external_clock[idx];
+ PLOG(("MC6840 #%d: %d external clock freq %d \n", which,idx, clock));
+ }
+
+ /* determine the number of clock periods before we expire */
+ count = currptr->counter[idx];
+ if (currptr->control_reg[idx] & 0x04)
+ count = ((count >> 8) + 1) * ((count & 0xff) + 1);
+ else
+ count = count + 1;
+
+ currptr->fired[idx]=0;
+
+ if ((currptr->mode[idx] == 4)|(currptr->mode[idx] == 6))
+ {
+ currptr->output[idx] = 1;
+ if ( currptr->intf->out_func[idx] ) currptr->intf->out_func[idx](0, currptr->output[idx]);
+ }
+
+ /* set the timer */
+ PLOG(("MC6840 #%d: reload_count(%d): clock = %d count = %d\n", which, idx, clock, count));
+
+ duration = attotime_mul(ATTOTIME_IN_HZ(clock), count);
+ if (idx == 2) duration = attotime_mul(duration, currptr->t3_divisor);
+ timer_adjust(currptr->timer[idx], duration, which, attotime_zero);
+ PLOG(("MC6840 #%d: reload_count(%d): output = %lf\n", which, idx, attotime_to_double(duration)));
+
+ if (!currptr->control_reg[idx] & 0x02)
+ {
+ if (!currptr->intf->external_clock[idx])
+ {
+ currptr->enabled[idx] = 0;
+ timer_enable(currptr->timer[idx],FALSE);
+ }
+ }
+ else
+ {
+ currptr->enabled[idx] = 1;
+ timer_enable(currptr->timer[idx],TRUE);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// Configure Timer //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+void ptm6840_config(int which, const ptm6840_interface *intf)
+{
+ int i;
+ ptm6840 *currptr = ptm + which;
+
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call ptm6840_config at init time!");
+ assert_always((which >= 0) && (which < PTM_6840_MAX), "ptm6840_config called on an invalid PTM!");
+ assert_always(intf, "ptm6840_config called with an invalid interface!");
+ ptm[which].intf = intf;
+ ptm[which].internal_clock = currptr->intf->internal_clock;
+
+ for (i = 0; i < 3; i++)
+ {
+ if ( currptr->intf->external_clock[i] )
+ {
+ ptm[which].external_clock[i] = currptr->intf->external_clock[i];
+ }
+ else
+ {
+ ptm[which].external_clock[i] = 1;
+ }
+ }
+
+ ptm[which].timer[0] = timer_alloc(ptm6840_t1_timeout);
+ ptm[which].timer[1] = timer_alloc(ptm6840_t2_timeout);
+ ptm[which].timer[2] = timer_alloc(ptm6840_t3_timeout);
+
+ for (i = 0; i < 3; i++)
+ timer_enable(ptm[which].timer[i], FALSE);
+
+ state_save_register_item("6840ptm", which, currptr->lsb_buffer);
+ state_save_register_item("6840ptm", which, currptr->msb_buffer);
+ state_save_register_item("6840ptm", which, currptr->status_read_since_int);
+ state_save_register_item("6840ptm", which, currptr->status_reg);
+ state_save_register_item("6840ptm", which, currptr->t3_divisor);
+ state_save_register_item("6840ptm", which, currptr->internal_clock);
+ state_save_register_item("6840ptm", which, currptr->IRQ);
+
+ state_save_register_item_array("6840ptm", which, currptr->control_reg);
+ state_save_register_item_array("6840ptm", which, currptr->output);
+ state_save_register_item_array("6840ptm", which, currptr->gate);
+ state_save_register_item_array("6840ptm", which, currptr->clock);
+ state_save_register_item_array("6840ptm", which, currptr->mode);
+ state_save_register_item_array("6840ptm", which, currptr->fired);
+ state_save_register_item_array("6840ptm", which, currptr->enabled);
+ state_save_register_item_array("6840ptm", which, currptr->external_clock);
+ state_save_register_item_array("6840ptm", which, currptr->counter);
+ state_save_register_item_array("6840ptm", which, currptr->latch);
+
+ ptm6840_reset(which);
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// Reset Timer //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+void ptm6840_reset(int which)
+{
+ int i;
+ ptm[which].control_reg[2] = 0x00;
+ ptm[which].control_reg[1] = 0x00;
+ ptm[which].control_reg[0] = 0x01;
+ ptm[which].status_reg = 0x00;
+ ptm[which].t3_divisor = 1;
+ ptm[which].status_read_since_int = 0x00;
+
+ for ( i = 0; i < 3; i++ )
+ {
+ ptm[which].counter[i] = 0xffff;
+ ptm[which].latch[i] = 0xffff;
+ ptm[which].output[i] = 0;
+ ptm[which].fired[i] = 0;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// Read Timer //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+int ptm6840_read(int which, int offset)
+{
+ int val;
+ ptm6840 *currptr = ptm + which;
+ switch ( offset )
+ {
+ case PTM_6840_CTRL1 ://0
+ {
+ val = 0;
+ break;
+ }
+
+ case PTM_6840_CTRL2 ://1
+ {
+ PLOG(("%06X: MC6840 #%d: Status read = %04X\n", activecpu_get_previouspc(), which, currptr->status_reg));
+ currptr->status_read_since_int |= currptr->status_reg & 0x07;
+ val = currptr->status_reg;
+ break;
+ }
+
+ case PTM_6840_MSBBUF1://2
+ case PTM_6840_MSBBUF2://4
+ case PTM_6840_MSBBUF3://6
+ {
+ int idx = (offset - 2)/2;
+ int result = compute_counter(idx, which);
+
+ /* clear the interrupt if the status has been read */
+ if (currptr->status_read_since_int & (1 << idx))
+ {
+ currptr->status_reg &= ~(1 << idx);
+ update_interrupts(which);
+ }
+
+ currptr->lsb_buffer = result & 0xff;
+
+ PLOG(("%06X: MC6840 #%d: Counter %d read = %04X\n", activecpu_get_previouspc(), which, idx, result >> 8));
+ val = result >> 8;
+ break;
+ }
+
+ case PTM_6840_LSB1://3
+ case PTM_6840_LSB2://5
+ case PTM_6840_LSB3://7
+ {
+ val = currptr->lsb_buffer;
+ break;
+ }
+
+ default:
+ {
+ val = 0;
+ break;
+ }
+
+ }
+ return val;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// Write Timer //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+void ptm6840_write (int which, int offset, int data)
+{
+ ptm6840 *currptr = ptm + which;
+
+ int idx;
+ int i;
+ UINT8 diffs;
+
+ switch ( offset )
+ {
+ case PTM_6840_CTRL1 ://0
+ case PTM_6840_CTRL2 ://1
+ {
+ idx = (offset == 1) ? 1 : (currptr->control_reg[1] & 0x01) ? 0 : 2;
+ diffs = data ^ currptr->control_reg[idx];
+ currptr->t3_divisor = (currptr->control_reg[2] & 0x01) ? 8 : 1;
+ currptr->mode[idx] = (data>>3)&0x07;
+ currptr->control_reg[idx] = data;
+
+ PLOG(("MC6840 #%d : Control register %d selected\n",which,idx));
+ PLOG(("operation mode = %s\n", opmode[ currptr->mode[idx] ]));
+ PLOG(("value = %04X\n", currptr->control_reg[idx]));
+ PLOG(("t3divisor = %d\n", currptr->t3_divisor));
+
+ if (!(currptr->control_reg[idx] & 0x80 ))
+ { // output cleared
+ if ( currptr->intf )
+ {
+ if ( currptr->intf->out_func[idx] ) currptr->intf->out_func[idx](0, 0);
+ }
+ }
+ /* reset? */
+ if (idx == 0 && (diffs & 0x01))
+ {
+ /* holding reset down */
+ if (data & 0x01)
+ {
+ PLOG(("MC6840 #%d : Timer reset\n",which));
+ for (i = 0; i < 3; i++)
+ {
+ timer_enable(currptr->timer[i],FALSE);
+ currptr->enabled[i]=0;
+ }
+ }
+
+ /* releasing reset */
+ else
+ {
+ for (i = 0; i < 3; i++)
+ {
+ reload_count(i,which);
+ }
+ }
+
+ currptr->status_reg = 0;
+ update_interrupts(which);
+
+ /* changing the clock source? (e.g. Zwackery) */
+ if (diffs & 0x02)
+ reload_count(idx,which);
+ }
+ break;
+ }
+
+ /* offsets 2, 4, and 6 are MSB buffer registers */
+ case PTM_6840_MSBBUF1://2
+ case PTM_6840_MSBBUF2://4
+ case PTM_6840_MSBBUF3://6
+ {
+ PLOG(("MC6840 #%d msbbuf%d = %02X\n", which, offset/2, data));
+ currptr->msb_buffer = data;
+ break;
+ }
+
+ /* offsets 3, 5, and 7 are Write Timer Latch commands */
+
+ case PTM_6840_LSB1://3
+ case PTM_6840_LSB2://5
+ case PTM_6840_LSB3://7
+ {
+ idx = (offset - 3)/2;
+ currptr->latch[idx] = (currptr->msb_buffer << 8) | (data & 0xff);
+ /* clear the interrupt */
+ currptr->status_reg &= ~(1 << idx);
+ update_interrupts(which);
+ /* reload the count if in an appropriate mode */
+ if (!(currptr->control_reg[idx] & 0x10))
+ {
+ reload_count(idx, which);
+ }
+ PLOG(("%06X:MC6840 #%d: Counter %d latch = %04X\n", activecpu_get_previouspc(), which, idx, currptr->latch[idx]));
+ break;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// ptm6840_timeout: called if timer is mature //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+static void ptm6840_timeout(int which, int idx)
+{
+ ptm6840 *p = ptm + which;
+
+ PLOG(("**ptm6840 %d t%d timeout**\n", which, idx+1));
+
+ if ( p->control_reg[idx] & 0x40 )
+ { // interrupt enabled
+ p->status_reg |= (1 << idx);
+ p->status_read_since_int &= ~(1 << idx);
+ update_interrupts(which);
+ }
+
+ if ( p->control_reg[idx] & 0x80 )
+ { // output enabled
+ if ( p->intf )
+ {
+ if ((p->mode[idx] == 0)|(p->mode[idx] == 2))
+ {
+ p->output[idx] = p->output[idx]?0:1;
+ PLOG(("**ptm6840 %d t%d output %d **\n", which, idx+1, p->output[idx]));
+ if ( p->intf->out_func[idx] ) p->intf->out_func[idx](0, p->output[idx]);
+ }
+ if ((p->mode[idx] == 4)|(p->mode[idx] == 6))
+ {
+ if (!p->fired[idx])
+ {
+ p->output[idx] = 1;
+ PLOG(("**ptm6840 %d t%d output %d **\n", which, idx+1, p->output[idx]));
+ if ( p->intf->out_func[idx] ) p->intf->out_func[idx](0, p->output[idx]);
+ p->fired[idx]=1;//no changes in output until reinit
+ }
+ }
+ }
+ }
+ p->enabled[idx]= 0;
+ reload_count(idx,which);
+}
+
+static TIMER_CALLBACK( ptm6840_t1_timeout ) { ptm6840_timeout(param, 0); }
+static TIMER_CALLBACK( ptm6840_t2_timeout ) { ptm6840_timeout(param, 1); }
+static TIMER_CALLBACK( ptm6840_t3_timeout ) { ptm6840_timeout(param, 2); }
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// ptm6840_set_gate: set gate status (0 or 1) //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+INLINE void ptm6840_set_gate(int which, int state, int idx)
+{
+ ptm6840 *p = ptm + which;
+
+ if ((p->mode[idx] == 0)|(p->mode[idx] == 2)|(p->mode[0] == 4)|(p->mode[idx] == 6))
+ {
+ if (state == 0 && p->gate[idx])
+ reload_count(idx,which);
+ }
+ p->gate[idx] = state;
+}
+
+void ptm6840_set_g1(int which, int state) { ptm6840_set_gate(which, state, 0); }
+void ptm6840_set_g2(int which, int state) { ptm6840_set_gate(which, state, 1); }
+void ptm6840_set_g3(int which, int state) { ptm6840_set_gate(which, state, 2); }
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// ptm6840_set_clock: set clock status (0 or 1) //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+INLINE void ptm6840_set_clock(int which, int state, int idx)
+{
+ ptm6840 *p = ptm + which;
+
+ p->clock[idx] = state;
+
+ if (!(p->control_reg[idx] & 0x02))
+ {
+ if (state) subtract_from_counter(idx,1,which);
+ }
+}
+
+void ptm6840_set_c1(int which, int state) { ptm6840_set_clock(which, state, 0); }
+void ptm6840_set_c2(int which, int state) { ptm6840_set_clock(which, state, 1); }
+void ptm6840_set_c3(int which, int state) { ptm6840_set_clock(which, state, 2); }
+
+///////////////////////////////////////////////////////////////////////////
+
+READ8_HANDLER( ptm6840_0_r ) { return ptm6840_read(0, offset); }
+READ8_HANDLER( ptm6840_1_r ) { return ptm6840_read(1, offset); }
+READ8_HANDLER( ptm6840_2_r ) { return ptm6840_read(2, offset); }
+READ8_HANDLER( ptm6840_3_r ) { return ptm6840_read(3, offset); }
+
+WRITE8_HANDLER( ptm6840_0_w ) { ptm6840_write(0, offset, data); }
+WRITE8_HANDLER( ptm6840_1_w ) { ptm6840_write(1, offset, data); }
+WRITE8_HANDLER( ptm6840_2_w ) { ptm6840_write(2, offset, data); }
+WRITE8_HANDLER( ptm6840_3_w ) { ptm6840_write(3, offset, data); }
+
+READ16_HANDLER( ptm6840_0_msb_r ) { return ptm6840_read(0, offset); }
+READ16_HANDLER( ptm6840_1_msb_r ) { return ptm6840_read(1, offset); }
+READ16_HANDLER( ptm6840_2_msb_r ) { return ptm6840_read(2, offset); }
+READ16_HANDLER( ptm6840_3_msb_r ) { return ptm6840_read(3, offset); }
+
+WRITE16_HANDLER( ptm6840_0_msb_w ) { if (ACCESSING_MSB) ptm6840_write(0, offset, (data >> 8) & 0xff); }
+WRITE16_HANDLER( ptm6840_1_msb_w ) { if (ACCESSING_MSB) ptm6840_write(1, offset, (data >> 8) & 0xff); }
+WRITE16_HANDLER( ptm6840_2_msb_w ) { if (ACCESSING_MSB) ptm6840_write(2, offset, (data >> 8) & 0xff); }
+WRITE16_HANDLER( ptm6840_3_msb_w ) { if (ACCESSING_MSB) ptm6840_write(3, offset, (data >> 8) & 0xff); }
+
+READ16_HANDLER( ptm6840_0_lsb_r ) { return ptm6840_read(0, offset << 8 | 0x00ff); }
+READ16_HANDLER( ptm6840_1_lsb_r ) { return ptm6840_read(1, offset << 8 | 0x00ff); }
+READ16_HANDLER( ptm6840_2_lsb_r ) { return ptm6840_read(2, offset << 8 | 0x00ff); }
+READ16_HANDLER( ptm6840_3_lsb_r ) { return ptm6840_read(3, offset << 8 | 0x00ff); }
+
+WRITE16_HANDLER( ptm6840_0_lsb_w ) {if (ACCESSING_LSB) ptm6840_write(0, offset, data & 0xff);}
+WRITE16_HANDLER( ptm6840_1_lsb_w ) {if (ACCESSING_LSB) ptm6840_write(1, offset, data & 0xff);}
+WRITE16_HANDLER( ptm6840_2_lsb_w ) {if (ACCESSING_LSB) ptm6840_write(2, offset, data & 0xff);}
+WRITE16_HANDLER( ptm6840_3_lsb_w ) {if (ACCESSING_LSB) ptm6840_write(3, offset, data & 0xff);}
diff --git a/src/emu/machine/6840ptm.h b/src/emu/machine/6840ptm.h
new file mode 100644
index 00000000000..3b8f3f5f117
--- /dev/null
+++ b/src/emu/machine/6840ptm.h
@@ -0,0 +1,75 @@
+/**********************************************************************
+
+ Motorola 6840 PTM interface and emulation
+
+ This function is a simple emulation of up to 4 MC6840 PTM
+ (Programmable Timer Module)
+
+ based on ( 6522 and 6821 PTM )
+
+**********************************************************************/
+
+#ifndef PTM_6840
+#define PTM_6840
+
+#define PTM_6840_MAX 4 // maximum number of chips to emulate
+
+typedef struct _ptm6840_interface ptm6840_interface;
+struct _ptm6840_interface
+{
+ int internal_clock;
+ int external_clock[3];
+
+ write8_handler out_func[3]; // function to call when output[idx] changes
+
+ void (*irq_func)(int state); // function called if IRQ line changes
+};
+
+void ptm6840_config( int which, const ptm6840_interface *intf);
+void ptm6840_reset( int which);
+int ptm6840_read( int which, int offset);
+void ptm6840_write( int which, int offset, int data);
+
+int ptm6840_get_status(int which, int clock); // get whether timer is enabled
+void ptm6840_set_g1(int which, int state); // set gate1 state
+void ptm6840_set_c1(int which, int state); // set clock1 state
+
+void ptm6840_set_g2(int which, int state); // set gate2 state
+void ptm6840_set_c2(int which, int state); // set clock2 state
+
+void ptm6840_set_g3(int which, int state); // set gate3 state
+void ptm6840_set_c3(int which, int state); // set clock3 state
+
+/*-------------------------------------------------------------------------*/
+
+READ8_HANDLER( ptm6840_0_r );
+READ8_HANDLER( ptm6840_1_r );
+READ8_HANDLER( ptm6840_2_r );
+READ8_HANDLER( ptm6840_3_r );
+
+READ16_HANDLER( ptm6840_0_lsb_r );
+READ16_HANDLER( ptm6840_1_lsb_r );
+READ16_HANDLER( ptm6840_2_lsb_r );
+READ16_HANDLER( ptm6840_3_lsb_r );
+
+READ16_HANDLER( ptm6840_0_msb_r );
+READ16_HANDLER( ptm6840_1_msb_r );
+READ16_HANDLER( ptm6840_2_msb_r );
+READ16_HANDLER( ptm6840_3_msb_r );
+
+WRITE8_HANDLER( ptm6840_0_w );
+WRITE8_HANDLER( ptm6840_1_w );
+WRITE8_HANDLER( ptm6840_2_w );
+WRITE8_HANDLER( ptm6840_3_w );
+
+WRITE16_HANDLER( ptm6840_0_lsb_w );
+WRITE16_HANDLER( ptm6840_1_lsb_w );
+WRITE16_HANDLER( ptm6840_2_lsb_w );
+WRITE16_HANDLER( ptm6840_3_lsb_w );
+
+WRITE16_HANDLER( ptm6840_0_msb_w );
+WRITE16_HANDLER( ptm6840_1_msb_w );
+WRITE16_HANDLER( ptm6840_2_msb_w );
+WRITE16_HANDLER( ptm6840_3_msb_w );
+
+#endif /* PTM_6840 */
diff --git a/src/emu/machine/6850acia.c b/src/emu/machine/6850acia.c
new file mode 100644
index 00000000000..17686e96020
--- /dev/null
+++ b/src/emu/machine/6850acia.c
@@ -0,0 +1,691 @@
+/*
+ 6850 ACIA
+*/
+
+#include "driver.h"
+#include "timer.h"
+#include "6850acia.h"
+
+#define CR1_0 0x03
+#define CR4_2 0x1C
+#define CR6_5 0x60
+#define CR7 0x80
+
+enum serial_state
+{
+ START,
+ DATA,
+ PARITY,
+ STOP,
+ STOP2,
+};
+
+enum parity_type
+{
+ NONE,
+ ODD,
+ EVEN
+};
+
+static const int ACIA6850_DIVIDE[3] = { 1, 16, 64 };
+
+static const int ACIA6850_WORD[8][3] =
+{
+ { 7, EVEN, 2 },
+ { 7, ODD, 2 },
+ { 7, EVEN, 1 },
+ { 7, ODD, 1 },
+ { 8, NONE, 2 },
+ { 8, NONE, 1 },
+ { 8, EVEN, 1 },
+ { 8, ODD, 1 }
+};
+
+typedef struct _acia_6850_
+{
+ UINT8 ctrl;
+ UINT8 status;
+
+ UINT8 *rx_pin;
+ UINT8 *tx_pin;
+ UINT8 *cts_pin;
+ UINT8 *rts_pin;
+ UINT8 *dcd_pin;
+
+ UINT8 tdr;
+ UINT8 rdr;
+ UINT8 rx_shift;
+ UINT8 tx_shift;
+
+ int rx_clock;
+ int tx_clock;
+
+ int divide;
+
+ /* Counters */
+ int tx_bits;
+ int rx_bits;
+ int tx_parity;
+ int rx_parity;
+
+ /* TX/RX state */
+ int bits;
+ enum parity_type parity;
+ int stopbits;
+ int tx_int;
+
+ /* Signals */
+ int overrun;
+ int reset;
+ int rts;
+ int brk;
+ int first_reset;
+ int status_read;
+ enum serial_state rx_state;
+ enum serial_state tx_state;
+
+ emu_timer *rx_timer;
+ emu_timer *tx_timer;
+
+ void (*int_callback)(int param);
+} acia_6850;
+
+static acia_6850 acia[MAX_ACIA];
+
+static TIMER_CALLBACK( receive_event );
+static TIMER_CALLBACK( transmit_event );
+
+/*
+ Reset the chip
+*/
+static void acia6850_reset(int which)
+{
+ acia_6850 *acia_p = &acia[which];
+ int cts = 0, dcd = 0;
+
+ if (acia_p->cts_pin)
+ {
+ cts = *acia_p->cts_pin;
+ }
+
+ if (acia_p->dcd_pin)
+ {
+ dcd = *acia_p->dcd_pin;
+ }
+
+ acia_p->status = (cts << 3) | (dcd << 2) | ACIA6850_STATUS_TDRE;
+ acia_p->tdr = 0;
+ acia_p->rdr = 0;
+ acia_p->tx_shift = 0;
+ acia_p->rx_shift = 0;
+ *acia_p->tx_pin = 1;
+ acia_p->overrun = 0;
+ acia_p->status_read = 0;
+ acia_p->brk = 0;
+
+ acia_p->rx_state = START;
+ acia_p->tx_state = START;
+
+ if (acia_p->int_callback)
+ {
+ acia_p->int_callback(1);
+ }
+
+ if (acia_p->first_reset)
+ {
+ acia_p->first_reset = 0;
+
+ if (acia_p->rts_pin)
+ {
+ *acia_p->rts_pin = 1;
+ }
+ }
+ else
+ {
+ if (acia_p->rts_pin)
+ {
+ *acia_p->rts_pin = acia_p->rts;
+ }
+ }
+}
+
+/*
+ Called by drivers
+*/
+void acia6850_config(int which, const struct acia6850_interface *intf)
+{
+ acia_6850 *acia_p = &acia[which];
+
+ if (which >= MAX_ACIA)
+ {
+ return;
+ }
+
+ acia_p->rx_clock = intf->rx_clock;
+ acia_p->tx_clock = intf->tx_clock;
+ acia_p->rx_pin = intf->rx_pin;
+ acia_p->tx_pin = intf->tx_pin;
+ acia_p->cts_pin = intf->cts_pin;
+ acia_p->rts_pin = intf->rts_pin;
+ acia_p->dcd_pin = intf->dcd_pin;
+ acia_p->rx_timer = timer_alloc(receive_event);
+ acia_p->tx_timer = timer_alloc(transmit_event);
+ acia_p->int_callback = intf->int_callback;
+ acia_p->first_reset = 1;
+ acia_p->status_read = 0;
+ acia_p->brk = 0;
+
+ timer_reset(acia_p->rx_timer, attotime_never);
+ timer_reset(acia_p->tx_timer, attotime_never);
+
+ state_save_register_item("acia6850", which, acia_p->ctrl);
+ state_save_register_item("acia6850", which, acia_p->status);
+ state_save_register_item("acia6850", which, acia_p->rx_clock);
+ state_save_register_item("acia6850", which, acia_p->tx_clock);
+ state_save_register_item("acia6850", which, acia_p->rx_shift);
+ state_save_register_item("acia6850", which, acia_p->tx_shift);
+ state_save_register_item("acia6850", which, acia_p->rdr);
+ state_save_register_item("acia6850", which, acia_p->tdr);
+ state_save_register_item("acia6850", which, acia_p->rx_bits);
+ state_save_register_item("acia6850", which, acia_p->tx_bits);
+ state_save_register_item("acia6850", which, acia_p->rx_parity);
+ state_save_register_item("acia6850", which, acia_p->tx_parity);
+ state_save_register_item("acia6850", which, acia_p->tx_int);
+
+ state_save_register_item("acia6850", which, acia_p->divide);
+ state_save_register_item("acia6850", which, acia_p->overrun);
+ state_save_register_item("acia6850", which, acia_p->reset);
+ state_save_register_item("acia6850", which, acia_p->first_reset);
+ state_save_register_item("acia6850", which, acia_p->rts);
+ state_save_register_item("acia6850", which, acia_p->brk);
+ state_save_register_item("acia6850", which, acia_p->status_read);
+}
+
+/*
+ Read Status Register
+*/
+static UINT8 acia6850_stat_r(int which)
+{
+ acia_6850 *acia_p = &acia[which];
+
+ acia_p->status_read = 1;
+
+ return acia_p->status;
+}
+
+/*
+ Write Control Register
+*/
+static void acia6850_ctrl_w(int which, UINT8 data)
+{
+ acia_6850 *acia_p = &acia[which];
+
+ int wordsel;
+ int divide;
+
+ acia_p->ctrl = data;
+
+ // Counter Divide Select Bits
+
+ divide = data & CR1_0;
+
+ if (divide == 3)
+ {
+ acia_p->reset = 1;
+ acia6850_reset(which);
+ }
+ else
+ {
+ acia_p->reset = 0;
+ acia_p->divide = ACIA6850_DIVIDE[divide];
+ }
+
+ // Word Select Bits
+
+ wordsel = (data & CR4_2) >> 2;
+
+ acia_p->bits = ACIA6850_WORD[wordsel][0];
+ acia_p->parity = ACIA6850_WORD[wordsel][1];
+ acia_p->stopbits = ACIA6850_WORD[wordsel][2];
+
+ // Transmitter Control Bits
+
+ switch ((data & CR6_5) >> 5)
+ {
+ case 0:
+ if (acia_p->rts_pin)
+ {
+ *acia_p->rts_pin = acia_p->rts = 0;
+ }
+
+ acia_p->tx_int = 0;
+ acia_p->brk = 0;
+ break;
+
+ case 1:
+ if (acia_p->rts_pin)
+ {
+ *acia_p->rts_pin = acia_p->rts = 0;
+ }
+
+ acia_p->tx_int = 1;
+ acia_p->brk = 0;
+ break;
+
+ case 2:
+ if (acia_p->rts_pin)
+ {
+ *acia_p->rts_pin = acia_p->rts = 1;
+ }
+
+ acia_p->tx_int = 0;
+ acia_p->brk = 0;
+ break;
+
+ case 3:
+ if (acia_p->rts_pin)
+ {
+ *acia_p->rts_pin = acia_p->rts = 0;
+ }
+
+ acia_p->tx_int = 0;
+ acia_p->brk = 1;
+ break;
+ }
+
+ // After writing the word type, start receive clock
+
+ if (!acia_p->reset)
+ {
+ attotime rx_period = attotime_mul(ATTOTIME_IN_HZ(acia_p->rx_clock), acia_p->divide);
+ attotime tx_period = attotime_mul(ATTOTIME_IN_HZ(acia_p->tx_clock), acia_p->divide);
+ timer_adjust(acia_p->rx_timer, rx_period, which, rx_period);
+ timer_adjust(acia_p->tx_timer, tx_period, which, tx_period);
+ }
+}
+
+static void acia6850_check_interrupts(int which)
+{
+ acia_6850 *acia_p = &acia[which];
+
+ int irq = (acia_p->tx_int && (acia_p->status & ACIA6850_STATUS_TDRE)) ||
+ ((acia_p->ctrl & 0x80) && ((acia_p->status & (ACIA6850_STATUS_RDRF|ACIA6850_STATUS_DCD)) || acia_p->overrun));
+
+ if (irq)
+ {
+ acia_p->status |= ACIA6850_STATUS_IRQ;
+
+ if (acia_p->int_callback)
+ {
+ acia_p->int_callback(0);
+ }
+ }
+ else
+ {
+ acia_p->status &= ~ACIA6850_STATUS_IRQ;
+
+ if (acia_p->int_callback)
+ {
+ acia_p->int_callback(1);
+ }
+ }
+}
+
+/*
+ Write transmit register
+*/
+static void acia6850_data_w(int which, UINT8 data)
+{
+ acia_6850 *acia_p = &acia[which];
+
+ if (!acia_p->reset)
+ {
+ acia_p->tdr = data;
+ acia_p->status &= ~ACIA6850_STATUS_TDRE;
+ acia6850_check_interrupts(which);
+ }
+ else
+ {
+ logerror("ACIA %d: Data write while in reset! (%x)\n", which, activecpu_get_previouspc());
+ }
+}
+
+/*
+ Read character
+*/
+static UINT8 acia6850_data_r(int which)
+{
+ acia_6850 *acia_p = &acia[which];
+
+ acia_p->status &= ~(ACIA6850_STATUS_RDRF | ACIA6850_STATUS_IRQ | ACIA6850_STATUS_PE);
+
+ if (acia_p->status_read)
+ {
+ acia_p->status_read = 0;
+ acia_p->status &= ~(ACIA6850_STATUS_OVRN | ACIA6850_STATUS_DCD);
+
+ if (acia_p->dcd_pin && *acia_p->dcd_pin)
+ {
+ acia_p->status |= ACIA6850_STATUS_DCD;
+ }
+ }
+
+ if (acia_p->overrun == 1)
+ {
+ acia_p->status |= ACIA6850_STATUS_OVRN;
+ acia_p->overrun = 0;
+ }
+
+ acia6850_check_interrupts(which);
+
+ return acia_p->rdr;
+}
+
+/*
+ Transmit a bit
+*/
+static TIMER_CALLBACK( transmit_event )
+{
+ int which = param;
+ acia_6850 *acia_p = &acia[which];
+
+ switch (acia_p->tx_state)
+ {
+ case START:
+ {
+ if (acia_p->brk)
+ {
+ // transmit break
+
+ *acia_p->tx_pin = 0;
+ }
+ else
+ {
+ if (acia_p->status & ACIA6850_STATUS_TDRE)
+ {
+ // transmitter idle
+
+ *acia_p->tx_pin = 1;
+ }
+ else
+ {
+ // transmit character
+
+ //logerror("ACIA6850 #%u: TX DATA %x\n", which, acia_p->tdr);
+ //logerror("ACIA6850 #%u: TX START BIT\n", which);
+
+ *acia_p->tx_pin = 0;
+
+ acia_p->tx_bits = acia_p->bits;
+ acia_p->tx_shift = acia_p->tdr;
+
+ // inhibit TDRE bit if Clear-to-Send is high
+
+ if (!(acia_p->status & ACIA6850_STATUS_CTS))
+ {
+ acia_p->status |= ACIA6850_STATUS_TDRE;
+ }
+
+ acia6850_check_interrupts(which);
+
+ acia_p->tx_state = DATA;
+ }
+ }
+ break;
+ }
+ case DATA:
+ {
+ int val = acia_p->tx_shift & 1;
+ //logerror("ACIA6850 #%u: TX DATA BIT %x\n", which, val);
+
+ *acia_p->tx_pin = val;
+ acia_p->tx_parity ^= val;
+ acia_p->tx_shift >>= 1;
+
+ if (--(acia_p->tx_bits) == 0)
+ {
+ acia_p->tx_state = (acia_p->parity == NONE) ? STOP : PARITY;
+ }
+
+ break;
+ }
+ case PARITY:
+ {
+ if (acia_p->parity == EVEN)
+ {
+ *acia_p->tx_pin = (acia_p->tx_parity & 1) ? 1 : 0;
+ }
+ else
+ {
+ *acia_p->tx_pin = (acia_p->tx_parity & 1) ? 0 : 1;
+ }
+
+ //logerror("ACIA6850 #%u: TX PARITY BIT %x\n", which, *acia_p->tx_pin);
+ acia_p->tx_parity = 0;
+ acia_p->tx_state = STOP;
+ break;
+ }
+ case STOP:
+ {
+ //logerror("ACIA6850 #%u: TX STOP BIT\n", which);
+ *acia_p->tx_pin = 1;
+
+ if (acia_p->stopbits == 1)
+ {
+ acia_p->tx_state = START;
+ }
+ else
+ {
+ acia_p->tx_state = STOP2;
+ }
+ break;
+ }
+ case STOP2:
+ {
+ //logerror("ACIA6850 #%u: TX STOP BIT\n", which);
+ *acia_p->tx_pin = 1;
+ acia_p->tx_state = START;
+ break;
+ }
+ }
+}
+
+/* Called on receive timer event */
+static TIMER_CALLBACK( receive_event )
+{
+ int which = param;
+ acia_6850 *acia_p = &acia[which];
+
+ if (acia_p->dcd_pin && *acia_p->dcd_pin)
+ {
+ acia_p->status |= ACIA6850_STATUS_DCD;
+ acia6850_check_interrupts(which);
+ }
+ else if ((acia_p->status & (ACIA6850_STATUS_DCD|ACIA6850_STATUS_IRQ)) == ACIA6850_STATUS_DCD)
+ {
+ acia_p->status &= ~ACIA6850_STATUS_DCD;
+ }
+
+ if (acia_p->status & ACIA6850_STATUS_DCD)
+ {
+ acia_p->rx_state = START;
+ }
+ else
+ {
+ switch (acia_p->rx_state)
+ {
+ case START:
+ {
+ if (*acia_p->rx_pin == 0)
+ {
+ //logerror("ACIA6850 #%u: RX START BIT\n", which);
+ acia_p->rx_shift = 0;
+ acia_p->rx_parity = 0;
+ acia_p->rx_bits = acia_p->bits;
+ acia_p->rx_state = DATA;
+ }
+ break;
+ }
+ case DATA:
+ {
+ //logerror("ACIA6850 #%u: RX DATA BIT %x\n", which, *acia_p->rx_pin);
+ acia_p->rx_shift |= *acia_p->rx_pin ? 0x80 : 0;
+ acia_p->rx_parity ^= *acia_p->rx_pin;
+
+ if (--acia_p->rx_bits == 0)
+ {
+ if (acia_p->status & ACIA6850_STATUS_RDRF)
+ {
+ acia_p->overrun = 1;
+ acia6850_check_interrupts(which);
+ }
+
+ acia_p->rx_state = acia_p->parity == NONE ? STOP : PARITY;
+ }
+ else
+ {
+ acia_p->rx_shift >>= 1;
+ }
+ break;
+ }
+ case PARITY:
+ {
+ //logerror("ACIA6850 #%u: RX PARITY BIT %x\n", which, *acia_p->rx_pin);
+ acia_p->rx_parity ^= *acia_p->rx_pin;
+
+ if (acia_p->parity == EVEN)
+ {
+ if (acia_p->rx_parity)
+ {
+ acia_p->status |= ACIA6850_STATUS_PE;
+ }
+ }
+ else
+ {
+ if (!acia_p->rx_parity)
+ {
+ acia_p->status |= ACIA6850_STATUS_PE;
+ }
+ }
+
+ acia_p->rx_state = STOP;
+ break;
+ }
+ case STOP:
+ {
+ if (*acia_p->rx_pin == 1)
+ {
+ //logerror("ACIA6850 #%u: RX STOP BIT\n", which);
+ if (acia_p->stopbits == 1)
+ {
+ acia_p->status &= ~ACIA6850_STATUS_FE;
+
+ if (!(acia_p->status & ACIA6850_STATUS_RDRF))
+ {
+ //logerror("ACIA6850 #%u: RX DATA %x\n", which, acia_p->rx_shift);
+ acia_p->rdr = acia_p->rx_shift;
+ acia_p->status |= ACIA6850_STATUS_RDRF;
+ acia6850_check_interrupts(which);
+ }
+
+ acia_p->rx_state = START;
+ }
+ else
+ {
+ acia_p->rx_state = STOP2;
+ }
+ }
+ else
+ {
+ acia_p->status |= ACIA6850_STATUS_FE;
+ acia_p->rx_state = START;
+ }
+ break;
+ }
+ case STOP2:
+ {
+ if (*acia_p->rx_pin == 1)
+ {
+ //logerror("ACIA6850 #%u: RX STOP BIT\n", which);
+ acia_p->status &= ~ACIA6850_STATUS_FE;
+
+ if (!(acia_p->status & ACIA6850_STATUS_RDRF))
+ {
+ //logerror("ACIA6850 #%u: RX DATA %x\n", which, acia_p->rx_shift);
+ acia_p->rdr = acia_p->rx_shift;
+ acia_p->status |= ACIA6850_STATUS_RDRF;
+ acia6850_check_interrupts(which);
+ }
+
+ acia_p->rx_state = START;
+ }
+ else
+ {
+ acia_p->status |= ACIA6850_STATUS_FE;
+ acia_p->rx_state = START;
+ }
+ break;
+ }
+ }
+ }
+}
+
+WRITE8_HANDLER( acia6850_0_ctrl_w ) { acia6850_ctrl_w(0, data); }
+WRITE8_HANDLER( acia6850_1_ctrl_w ) { acia6850_ctrl_w(1, data); }
+WRITE8_HANDLER( acia6850_2_ctrl_w ) { acia6850_ctrl_w(2, data); }
+WRITE8_HANDLER( acia6850_3_ctrl_w ) { acia6850_ctrl_w(3, data); }
+
+WRITE8_HANDLER( acia6850_0_data_w ) { acia6850_data_w(0, data); }
+WRITE8_HANDLER( acia6850_1_data_w ) { acia6850_data_w(1, data); }
+WRITE8_HANDLER( acia6850_2_data_w ) { acia6850_data_w(2, data); }
+WRITE8_HANDLER( acia6850_3_data_w ) { acia6850_data_w(3, data); }
+
+READ8_HANDLER( acia6850_0_stat_r ) { return acia6850_stat_r(0); }
+READ8_HANDLER( acia6850_1_stat_r ) { return acia6850_stat_r(1); }
+READ8_HANDLER( acia6850_2_stat_r ) { return acia6850_stat_r(2); }
+READ8_HANDLER( acia6850_3_stat_r ) { return acia6850_stat_r(3); }
+
+READ8_HANDLER( acia6850_0_data_r ) { return acia6850_data_r(0); }
+READ8_HANDLER( acia6850_1_data_r ) { return acia6850_data_r(1); }
+READ8_HANDLER( acia6850_2_data_r ) { return acia6850_data_r(2); }
+READ8_HANDLER( acia6850_3_data_r ) { return acia6850_data_r(3); }
+
+READ16_HANDLER( acia6850_0_stat_lsb_r ) { return acia6850_stat_r(0); }
+READ16_HANDLER( acia6850_1_stat_lsb_r ) { return acia6850_stat_r(1); }
+READ16_HANDLER( acia6850_2_stat_lsb_r ) { return acia6850_stat_r(2); }
+READ16_HANDLER( acia6850_3_stat_lsb_r ) { return acia6850_stat_r(3); }
+
+READ16_HANDLER( acia6850_0_stat_msb_r ) { return acia6850_stat_r(0) << 8; }
+READ16_HANDLER( acia6850_1_stat_msb_r ) { return acia6850_stat_r(1) << 8; }
+READ16_HANDLER( acia6850_2_stat_msb_r ) { return acia6850_stat_r(2) << 8; }
+READ16_HANDLER( acia6850_3_stat_msb_r ) { return acia6850_stat_r(3) << 8; }
+
+READ16_HANDLER( acia6850_0_data_lsb_r ) { return acia6850_data_r(0); }
+READ16_HANDLER( acia6850_1_data_lsb_r ) { return acia6850_data_r(1); }
+READ16_HANDLER( acia6850_2_data_lsb_r ) { return acia6850_data_r(2); }
+READ16_HANDLER( acia6850_3_data_lsb_r ) { return acia6850_data_r(3); }
+
+READ16_HANDLER( acia6850_0_data_msb_r ) { return acia6850_data_r(0) << 8; }
+READ16_HANDLER( acia6850_1_data_msb_r ) { return acia6850_data_r(1) << 8; }
+READ16_HANDLER( acia6850_2_data_msb_r ) { return acia6850_data_r(2) << 8; }
+READ16_HANDLER( acia6850_3_data_msb_r ) { return acia6850_data_r(3) << 8; }
+
+WRITE16_HANDLER( acia6850_0_ctrl_msb_w ) { if (ACCESSING_MSB) acia6850_ctrl_w(0, (data >> 8) & 0xff); }
+WRITE16_HANDLER( acia6850_1_ctrl_msb_w ) { if (ACCESSING_MSB) acia6850_ctrl_w(1, (data >> 8) & 0xff); }
+WRITE16_HANDLER( acia6850_2_ctrl_msb_w ) { if (ACCESSING_MSB) acia6850_ctrl_w(2, (data >> 8) & 0xff); }
+WRITE16_HANDLER( acia6850_3_ctrl_msb_w ) { if (ACCESSING_MSB) acia6850_ctrl_w(3, (data >> 8) & 0xff); }
+
+WRITE16_HANDLER( acia6850_0_ctrl_lsb_w ) { if (ACCESSING_LSB) acia6850_ctrl_w(0, data & 0xff); }
+WRITE16_HANDLER( acia6850_1_ctrl_lsb_w ) { if (ACCESSING_LSB) acia6850_ctrl_w(1, data & 0xff); }
+WRITE16_HANDLER( acia6850_2_ctrl_lsb_w ) { if (ACCESSING_LSB) acia6850_ctrl_w(2, data & 0xff); }
+WRITE16_HANDLER( acia6850_3_ctrl_lsb_w ) { if (ACCESSING_LSB) acia6850_ctrl_w(3, data & 0xff); }
+
+WRITE16_HANDLER( acia6850_0_data_msb_w ) { if (ACCESSING_MSB) acia6850_data_w(0, (data >> 8) & 0xff); }
+WRITE16_HANDLER( acia6850_1_data_msb_w ) { if (ACCESSING_MSB) acia6850_data_w(1, (data >> 8) & 0xff); }
+WRITE16_HANDLER( acia6850_2_data_msb_w ) { if (ACCESSING_MSB) acia6850_data_w(2, (data >> 8) & 0xff); }
+WRITE16_HANDLER( acia6850_3_data_msb_w ) { if (ACCESSING_MSB) acia6850_data_w(3, (data >> 8) & 0xff); }
+
+WRITE16_HANDLER( acia6850_0_data_lsb_w ) { if (ACCESSING_LSB) acia6850_data_w(0, data & 0xff); }
+WRITE16_HANDLER( acia6850_1_data_lsb_w ) { if (ACCESSING_LSB) acia6850_data_w(1, data & 0xff); }
+WRITE16_HANDLER( acia6850_2_data_lsb_w ) { if (ACCESSING_LSB) acia6850_data_w(2, data & 0xff); }
+WRITE16_HANDLER( acia6850_3_data_lsb_w ) { if (ACCESSING_LSB) acia6850_data_w(3, data & 0xff); }
diff --git a/src/emu/machine/6850acia.h b/src/emu/machine/6850acia.h
new file mode 100644
index 00000000000..9a8e1756f48
--- /dev/null
+++ b/src/emu/machine/6850acia.h
@@ -0,0 +1,90 @@
+#ifndef ACIA6850_H
+#define ACIA6850_H
+
+#define MAX_ACIA 4
+
+#define ACIA6850_STATUS_RDRF 0x01
+#define ACIA6850_STATUS_TDRE 0x02
+#define ACIA6850_STATUS_DCD 0x04
+#define ACIA6850_STATUS_CTS 0x08
+#define ACIA6850_STATUS_FE 0x10
+#define ACIA6850_STATUS_OVRN 0x20
+#define ACIA6850_STATUS_PE 0x40
+#define ACIA6850_STATUS_IRQ 0x80
+
+struct acia6850_interface
+{
+ int tx_clock;
+ int rx_clock;
+
+ UINT8 *rx_pin;
+ UINT8 *tx_pin;
+ UINT8 *cts_pin;
+ UINT8 *rts_pin;
+ UINT8 *dcd_pin;
+
+ void (*int_callback)(int state);
+};
+
+void acia6850_config(int which, const struct acia6850_interface *intf);
+
+WRITE8_HANDLER( acia6850_0_ctrl_w );
+WRITE8_HANDLER( acia6850_1_ctrl_w );
+WRITE8_HANDLER( acia6850_2_ctrl_w );
+WRITE8_HANDLER( acia6850_3_ctrl_w );
+
+WRITE8_HANDLER( acia6850_0_data_w );
+WRITE8_HANDLER( acia6850_1_data_w );
+WRITE8_HANDLER( acia6850_2_data_w );
+WRITE8_HANDLER( acia6850_3_data_w );
+
+READ8_HANDLER( acia6850_0_stat_r );
+READ8_HANDLER( acia6850_1_stat_r );
+READ8_HANDLER( acia6850_2_stat_r );
+READ8_HANDLER( acia6850_3_stat_r );
+
+READ8_HANDLER( acia6850_0_data_r );
+READ8_HANDLER( acia6850_1_data_r );
+READ8_HANDLER( acia6850_2_data_r );
+READ8_HANDLER( acia6850_3_data_r );
+
+READ16_HANDLER( acia6850_0_stat_lsb_r );
+READ16_HANDLER( acia6850_1_stat_lsb_r );
+READ16_HANDLER( acia6850_2_stat_lsb_r );
+READ16_HANDLER( acia6850_3_stat_lsb_r );
+
+READ16_HANDLER( acia6850_0_stat_msb_r );
+READ16_HANDLER( acia6850_1_stat_msb_r );
+READ16_HANDLER( acia6850_2_stat_msb_r );
+READ16_HANDLER( acia6850_3_stat_msb_r );
+
+READ16_HANDLER( acia6850_0_data_lsb_r );
+READ16_HANDLER( acia6850_1_data_lsb_r );
+READ16_HANDLER( acia6850_2_data_lsb_r );
+READ16_HANDLER( acia6850_3_data_lsb_r );
+
+READ16_HANDLER( acia6850_0_data_msb_r );
+READ16_HANDLER( acia6850_1_data_msb_r );
+READ16_HANDLER( acia6850_2_data_msb_r );
+READ16_HANDLER( acia6850_3_data_msb_r );
+
+WRITE16_HANDLER( acia6850_0_ctrl_msb_w );
+WRITE16_HANDLER( acia6850_1_ctrl_msb_w );
+WRITE16_HANDLER( acia6850_2_ctrl_msb_w );
+WRITE16_HANDLER( acia6850_3_ctrl_msb_w );
+
+WRITE16_HANDLER( acia6850_0_ctrl_lsb_w );
+WRITE16_HANDLER( acia6850_1_ctrl_lsb_w );
+WRITE16_HANDLER( acia6850_2_ctrl_lsb_w );
+WRITE16_HANDLER( acia6850_3_ctrl_lsb_w );
+
+WRITE16_HANDLER( acia6850_0_data_msb_w );
+WRITE16_HANDLER( acia6850_1_data_msb_w );
+WRITE16_HANDLER( acia6850_2_data_msb_w );
+WRITE16_HANDLER( acia6850_3_data_msb_w );
+
+WRITE16_HANDLER( acia6850_0_data_lsb_w );
+WRITE16_HANDLER( acia6850_1_data_lsb_w );
+WRITE16_HANDLER( acia6850_2_data_lsb_w );
+WRITE16_HANDLER( acia6850_3_data_lsb_w );
+#endif
diff --git a/src/emu/machine/74123.c b/src/emu/machine/74123.c
new file mode 100644
index 00000000000..c6199233665
--- /dev/null
+++ b/src/emu/machine/74123.c
@@ -0,0 +1,190 @@
+/*****************************************************************************
+
+ 74123 monoflop emulator - see 74123.h for pin out and truth table
+
+ Formulas came from the TI datasheet revised on March 1998
+
+ *****************************************************************************/
+
+#include "driver.h"
+#include "machine/74123.h"
+#include "rescap.h"
+
+
+#define LOG (0)
+
+
+typedef struct _TTL74123_state TTL74123_state;
+
+struct _TTL74123_state
+{
+ const TTL74123_interface *intf;
+ int which;
+
+ UINT8 A; /* pin 1/9 */
+ UINT8 B; /* pin 2/10 */
+ UINT8 clear; /* pin 3/11 */
+ emu_timer *timer;
+};
+
+static TTL74123_state chips[MAX_TTL74123];
+
+
+static attotime compute_duration(TTL74123_state *chip)
+{
+ double duration;
+
+ switch (chip->intf->connection_type)
+ {
+ case TTL74123_NOT_GROUNDED_NO_DIODE:
+ duration = 0.28 * chip->intf->res * chip->intf->cap * (1.0 + (0.7 / chip->intf->res));
+ break;
+
+ case TTL74123_NOT_GROUNDED_DIODE:
+ duration = 0.25 * chip->intf->res * chip->intf->cap * (1.0 + (0.7 / chip->intf->res));
+ break;
+
+ case TTL74123_GROUNDED:
+ default:
+ if (chip->intf->cap < CAP_U(0.1))
+ /* this is really a curve - a very flat one in the 0.1uF-.01uF range */
+ duration = 0.32 * chip->intf->res * chip->intf->cap;
+ else
+ duration = 0.33 * chip->intf->res * chip->intf->cap;
+ break;
+ }
+
+ return double_to_attotime(duration);
+}
+
+
+static int timer_running(TTL74123_state *chip)
+{
+ return (attotime_compare(timer_timeleft(chip->timer), attotime_zero) > 0) &&
+ (attotime_compare(timer_timeleft(chip->timer), attotime_never) != 0);
+}
+
+
+static void set_output(TTL74123_state *chip)
+{
+ int output = timer_running(chip);
+
+ chip->intf->output_changed_cb(output);
+
+ if (LOG) logerror("74123 #%d: Output: %d\n", chip->which, output);
+}
+
+
+static TIMER_CALLBACK_PTR( clear_callback )
+{
+ TTL74123_state *chip = param;
+
+ set_output(chip);
+}
+
+
+void TTL74123_config(int which, const TTL74123_interface *intf)
+{
+ TTL74123_state *chip;
+
+ assert_always(which < MAX_TTL74123, "Exceeded maximum number of 74123 chips");
+ assert_always(intf, "No interface specified");
+ assert_always((intf->connection_type == TTL74123_GROUNDED) && (intf->cap >= CAP_U(0.01)), "Only capacitors >= 0.01uF supported for GROUNDED type");
+ assert_always(intf->cap >= CAP_P(1000), "Only capacitors >= 1000pF supported ");
+
+ chip = &chips[which];
+
+ chip->intf = intf;
+ chip->which = which;
+ chip->timer = timer_alloc_ptr(clear_callback, chip);
+
+ /* start with the defaults */
+ chip->A = intf->A;
+ chip->B = intf->B;
+ chip->clear = intf->clear;
+
+ /* register for state saving */
+ state_save_register_item("TTL74123", which, chip->A);
+ state_save_register_item("TTL74123", which, chip->B);
+ state_save_register_item("TTL74123", which, chip->clear);
+}
+
+
+void TTL74123_reset(int which)
+{
+ TTL74123_state *chip = &chips[which];
+
+ set_output(chip);
+}
+
+
+static void start_pulse(TTL74123_state *chip)
+{
+ attotime duration = compute_duration(chip);
+
+ if (timer_running(chip))
+ {
+ /* retriggering, but not if we are called to quickly */
+ attotime delay_time = attotime_make(0, ATTOSECONDS_PER_SECOND * chip->intf->cap * 220);
+
+ if (attotime_compare(timer_timeelapsed(chip->timer), delay_time) >= 0)
+ {
+ timer_adjust_ptr(chip->timer, duration, attotime_never);
+
+ if (LOG) logerror("74123 #%d: Retriggering pulse. Duration: %f\n", chip->which, attotime_to_double(duration));
+ }
+ else
+ {
+ if (LOG) logerror("74123 #%d: Retriggering failed.\n", chip->which);
+ }
+ }
+ else
+ {
+ /* starting */
+ timer_adjust_ptr(chip->timer, duration, attotime_never);
+
+ set_output(chip);
+
+ if (LOG) logerror("74123 #%d: Starting pulse. Duration: %f\n", chip->which, attotime_to_double(duration));
+ }
+}
+
+
+void TTL74123_A_w(int which, int data)
+{
+ TTL74123_state *chip = &chips[which];
+
+ /* start/regtrigger pulse if B=HI and falling edge on A (while clear is HI) */
+ if (!data && chip->A && chip->B && chip->clear)
+ start_pulse(chip);
+
+ chip->A = data;
+}
+
+
+void TTL74123_B_w(int which, int data)
+{
+ TTL74123_state *chip = &chips[which];
+
+ /* start/regtrigger pulse if A=LO and rising edge on B (while clear is HI) */
+ if (data && !chip->B && !chip->A && chip->clear)
+ start_pulse(chip);
+
+ chip->B = data;
+}
+
+
+void TTL74123_clear_w(int which, int data)
+{
+ TTL74123_state *chip = &chips[which];
+
+ /* clear the output if A=LO, B=HI and falling edge on clear */
+ if (!data && chip->clear && chip->B && !chip->A && !chip->clear)
+ {
+ timer_adjust_ptr(chip->timer, attotime_zero, attotime_never);
+
+ if (LOG) logerror("74123 #%d: Cleared\n", which);
+ }
+
+ chip->clear = data;
+}
diff --git a/src/emu/machine/74123.h b/src/emu/machine/74123.h
new file mode 100644
index 00000000000..eb54e8de037
--- /dev/null
+++ b/src/emu/machine/74123.h
@@ -0,0 +1,80 @@
+/*****************************************************************************
+
+ 74123 monoflop emulator
+
+ There are 2 monoflops per chips.
+
+ Pin out:
+
+ +--------+
+ B1 |1 | | 16| Vcc
+ A1 o|2 - 15| RCext1
+ Clear1 o|3 14| Cext1
+ *Output1 o|4 13| Output1
+ Output2 |5 12|o *Output2
+ Cext2 |6 11|o Clear2
+ RCext2 |7 10| B2
+ GND |8 9|o A2
+ +--------+
+
+ All resistor values in Ohms.
+ All capacitor values in Farads.
+
+
+ Truth table:
+
+ C A B | Q /Q
+ ----------|-------
+ L X X | L H
+ X H X | L H
+ X X L | L H
+ H L _- |_-_ -_-
+ H -_ H |_-_ -_-
+ _- L H |_-_ -_-
+ ------------------
+ C = clear
+ L = LO (0)
+ H = HI (1)
+ X = any state
+ _- = raising edge
+ -_ = falling edge
+ _-_ = positive pulse
+ -_- = negative pulse
+
+*****************************************************************************/
+
+#ifndef TTL74123_H
+#define TTL74123_H
+
+#define MAX_TTL74123 4
+
+
+/* constants for the different ways the cap/res can be connected.
+ This determines the formula for calculating the pulse width */
+#define TTL74123_NOT_GROUNDED_NO_DIODE (1)
+#define TTL74123_NOT_GROUNDED_DIODE (2)
+#define TTL74123_GROUNDED (3)
+
+
+typedef struct _TTL74123_interface TTL74123_interface;
+struct _TTL74123_interface
+{
+ int connection_type; /* the hook up type - one of the constants above */
+ double res; /* resistor connected to RCext */
+ double cap; /* capacitor connected to Cext and RCext */
+ int A; /* initial/constant value of the A pin */
+ int B; /* initial/constant value of the B pin */
+ int clear; /* initial/constant value of the Clear pin */
+ void (*output_changed_cb)(int output);
+};
+
+
+void TTL74123_config(int which, const TTL74123_interface *intf);
+void TTL74123_reset(int which);
+
+void TTL74123_A_w(int which, int data);
+void TTL74123_B_w(int which, int data);
+void TTL74123_clear_w(int which, int data);
+
+
+#endif
diff --git a/src/emu/machine/74148.c b/src/emu/machine/74148.c
new file mode 100644
index 00000000000..d7eae2e7f53
--- /dev/null
+++ b/src/emu/machine/74148.c
@@ -0,0 +1,193 @@
+/*****************************************************************************
+
+ 74148 8-line-to-3-line priority encoder
+
+
+ Pin layout and functions to access pins:
+
+ input_line_w(4) [1] /IN4 VCC [16]
+ input_line_w(5) [2] /IN5 /EO [15] enable_output_r
+ input_line_w(6) [3] /IN6 /GS [14] output_valid_r
+ input_line_w(7) [4] /IN7 /IN3 [13] input_line_w(3)
+ enable_input_w [5] /EI /IN2 [12] input_line_w(2)
+ output_r [6] /A2 /IN1 [11] input_line_w(1)
+ output_r [7] /A1 /IN0 [10] input_line_w(0)
+ [8] GND /A0 [9] output_r
+
+
+ Truth table (all logic levels indicate the actual voltage on the line):
+
+ INPUTS | OUTPUTS
+ |
+ EI I0 I1 I2 I3 I4 I5 I6 I7 | A2 A1 A0 | GS EO
+ ----------------------------+----------+------
+ 1 H X X X X X X X X | H H H | H H
+ 2 L H H H H H H H H | H H H | H L
+ 3 L X X X X X X X L | L L L | L H
+ 4 L X X X X X X L H | L L H | L H
+ 5 L X X X X X L H H | L H L | L H
+ 6 L X X X X L H H H | L H H | L H
+ 7 L X X X L H H H H | H L L | L H
+ 8 L X X L H H H H H | H L H | L H
+ 9 L X L H H H H H H | H H L | L H
+ 10 L L H H H H H H H | H H H | L H
+ ----------------------------+----------+------
+ L = lo (0)
+ H = hi (1)
+ X = any state
+
+*****************************************************************************/
+
+#include "driver.h"
+#include "machine/74148.h"
+
+
+#define MAX_TTL74148 4
+
+struct TTL74148
+{
+ /* callback */
+ void (*output_cb)(void);
+
+ /* inputs */
+ int input_lines[8]; /* pins 1-4,10-13 */
+ int enable_input; /* pin 5 */
+
+ /* outputs */
+ int output; /* pins 6,7,9 */
+ int output_valid; /* pin 14 */
+ int enable_output; /* pin 15 */
+
+ /* internals */
+ int last_output;
+ int last_output_valid;
+ int last_enable_output;
+};
+
+static struct TTL74148 chips[MAX_TTL74148];
+
+
+void TTL74148_update(int which)
+{
+ if (chips[which].enable_input)
+ {
+ // row 1 in truth table
+ chips[which].output = 0x07;
+ chips[which].output_valid = 1;
+ chips[which].enable_output = 1;
+ }
+ else
+ {
+ int bit0, bit1, bit2;
+
+ /* this comes straight off the data sheet schematics */
+ bit0 = !((!chips[which].input_lines[1] &
+ chips[which].input_lines[2] &
+ chips[which].input_lines[4] &
+ chips[which].input_lines[6]) |
+ (!chips[which].input_lines[3] &
+ chips[which].input_lines[4] &
+ chips[which].input_lines[6]) |
+ (!chips[which].input_lines[5] &
+ chips[which].input_lines[6]) |
+ (!chips[which].input_lines[7]));
+
+ bit1 = !((!chips[which].input_lines[2] &
+ chips[which].input_lines[4] &
+ chips[which].input_lines[5]) |
+ (!chips[which].input_lines[3] &
+ chips[which].input_lines[4] &
+ chips[which].input_lines[5]) |
+ (!chips[which].input_lines[6]) |
+ (!chips[which].input_lines[7]));
+
+ bit2 = !((!chips[which].input_lines[4]) |
+ (!chips[which].input_lines[5]) |
+ (!chips[which].input_lines[6]) |
+ (!chips[which].input_lines[7]));
+
+ chips[which].output = (bit2 << 2) | (bit1 << 1) | bit0;
+
+ chips[which].output_valid = (chips[which].input_lines[0] &
+ chips[which].input_lines[1] &
+ chips[which].input_lines[2] &
+ chips[which].input_lines[3] &
+ chips[which].input_lines[4] &
+ chips[which].input_lines[5] &
+ chips[which].input_lines[6] &
+ chips[which].input_lines[7]);
+
+ chips[which].enable_output = !chips[which].output_valid;
+ }
+
+
+ /* call callback if any of the outputs changed */
+ if ( chips[which].output_cb &&
+ ((chips[which].output != chips[which].last_output) ||
+ (chips[which].output_valid != chips[which].last_output_valid) ||
+ (chips[which].enable_output != chips[which].last_enable_output)))
+ {
+ chips[which].last_output = chips[which].output;
+ chips[which].last_output_valid = chips[which].output_valid;
+ chips[which].last_enable_output = chips[which].enable_output;
+
+ chips[which].output_cb();
+ }
+}
+
+
+void TTL74148_input_line_w(int which, int input_line, int data)
+{
+ chips[which].input_lines[input_line] = data ? 1 : 0;
+}
+
+
+void TTL74148_enable_input_w(int which, int data)
+{
+ chips[which].enable_input = data ? 1 : 0;
+}
+
+
+int TTL74148_output_r(int which)
+{
+ return chips[which].output;
+}
+
+
+int TTL74148_output_valid_r(int which)
+{
+ return chips[which].output_valid;
+}
+
+
+int TTL74148_enable_output_r(int which)
+{
+ return chips[which].enable_output;
+}
+
+
+
+void TTL74148_config(int which, const struct TTL74148_interface *intf)
+{
+ if (which >= MAX_TTL74148)
+ {
+ logerror("Only %d 74148's are supported at this time.\n", MAX_TTL74148);
+ return;
+ }
+
+
+ chips[which].output_cb = (intf ? intf->output_cb : 0);
+ chips[which].enable_input = 1;
+ chips[which].input_lines[0] = 1;
+ chips[which].input_lines[1] = 1;
+ chips[which].input_lines[2] = 1;
+ chips[which].input_lines[3] = 1;
+ chips[which].input_lines[4] = 1;
+ chips[which].input_lines[5] = 1;
+ chips[which].input_lines[6] = 1;
+ chips[which].input_lines[7] = 1;
+
+ chips[which].last_output = -1;
+ chips[which].last_output_valid = -1;
+ chips[which].last_enable_output = -1;
+}
diff --git a/src/emu/machine/74148.h b/src/emu/machine/74148.h
new file mode 100644
index 00000000000..027e89692fb
--- /dev/null
+++ b/src/emu/machine/74148.h
@@ -0,0 +1,63 @@
+/*****************************************************************************
+
+ 74148 8-line-to-3-line priority encoder
+
+
+ Pin layout and functions to access pins:
+
+ input_line_w(4) [1] /IN4 VCC [16]
+ input_line_w(5) [2] /IN5 /EO [15] enable_output_r
+ input_line_w(6) [3] /IN6 /GS [14] output_valid_r
+ input_line_w(7) [4] /IN7 /IN3 [13] input_line_w(3)
+ enable_input_w [5] /EI /IN2 [12] input_line_w(2)
+ output_r [6] /A2 /IN1 [11] input_line_w(1)
+ output_r [7] /A1 /IN0 [10] input_line_w(0)
+ [8] GND /A0 [9] output_r
+
+
+ Truth table (all logic levels indicate the actual voltage on the line):
+
+ INPUTS | OUTPUTS
+ |
+ EI I0 I1 I2 I3 I4 I5 I6 I7 | A2 A1 A0 | GS EO
+ ----------------------------+----------+------
+ H X X X X X X X X | H H H | H H
+ L H H H H H H H H | H H H | H L
+ L X X X X X X X L | L L L | L H
+ L X X X X X X L H | L L H | L H
+ L X X X X X L H H | L H L | L H
+ L X X X X L H H H | L H H | L H
+ L X X X L H H H H | H L L | L H
+ L X X L H H H H H | H L H | L H
+ L X L H H H H H H | H H L | L H
+ L L H H H H H H H | H H H | L H
+ ----------------------------+----------+------
+ L = lo (0)
+ H = hi (1)
+ X = any state
+
+*****************************************************************************/
+
+#ifndef TTL74148_H
+#define TTL74148_H
+
+
+/* The interface structure */
+struct TTL74148_interface
+{
+ void (*output_cb)(void);
+};
+
+
+void TTL74148_config(int which, const struct TTL74148_interface *intf);
+
+/* must call TTL74148_update() after setting the inputs */
+void TTL74148_update(int which);
+
+void TTL74148_input_line_w(int which, int input_line, int data);
+void TTL74148_enable_input_w(int which, int data);
+int TTL74148_output_r(int which);
+int TTL74148_output_valid_r(int which);
+int TTL74148_enable_output_r(int which);
+
+#endif
diff --git a/src/emu/machine/74153.c b/src/emu/machine/74153.c
new file mode 100644
index 00000000000..b8f1109d830
--- /dev/null
+++ b/src/emu/machine/74153.c
@@ -0,0 +1,151 @@
+/*****************************************************************************
+
+ 74153 Dual 4-line to 1-line data selectors/multiplexers
+
+
+ Pin layout and functions to access pins:
+
+ enable_w(0) [1] /1G VCC [16]
+ b_w [2] B /2G [15] enable_w(1)
+ input_line_w(0,3) [3] 1C3 A [14] a_w
+ input_line_w(0,2) [4] 1C2 2C3 [13] input_line_w(1,3)
+ input_line_w(0,1) [5] 1C1 2C2 [12] input_line_w(1,2)
+ input_line_w(0,0) [6] 1C0 2C1 [11] input_line_w(1,1)
+ output_r(0) [7] 1Y 2C0 [10] input_line_w(1,0)
+ [8] GND 2Y [9] output_r(1)
+
+
+ Truth table (all logic levels indicate the actual voltage on the line):
+
+ INPUTS | OUTPUT
+ |
+ G | B A | C0 C1 C2 C3 | Y
+ --+------+-------------+---
+1 H | X X | X X X X | L
+2 L | L L | X X X X | C0
+3 L | L H | X X X X | C1
+4 L | H L | X X X X | C2
+5 L | H H | X X X X | C3
+ --+------+-------------+---
+ L = lo (0)
+ H = hi (1)
+ X = any state
+
+*****************************************************************************/
+
+#include "driver.h"
+#include "machine/74153.h"
+
+
+#define MAX_TTL74153 9
+
+struct TTL74153
+{
+ /* callback */
+ void (*output_cb)(void);
+
+ /* inputs */
+ int a; /* pin 14 */
+ int b; /* pin 2 */
+ int input_lines[2][4]; /* pins 3-6,10-13 */
+ int enable[2]; /* pins 1,15 */
+
+ /* output */
+ int output[2]; /* pins 7,9 */
+
+ /* internals */
+ int last_output[2];
+};
+
+static struct TTL74153 chips[MAX_TTL74153];
+
+
+void TTL74153_update(int which)
+{
+ int sel;
+ int section;
+
+
+ sel = (chips[which].b << 1) | chips[which].a;
+
+
+ /* process both sections */
+ for (section = 0; section < 2; section++)
+ {
+ if (chips[which].enable[section])
+ chips[which].output[section] = 0; // row 1 in truth table
+ else
+ chips[which].output[section] = chips[which].input_lines[section][sel];
+ }
+
+
+ /* call callback if either of the outputs changed */
+ if ( chips[which].output_cb &&
+ ((chips[which].output[0] != chips[which].last_output[0]) ||
+ (chips[which].output[1] != chips[which].last_output[1])))
+ {
+ chips[which].last_output[0] = chips[which].output[0];
+ chips[which].last_output[1] = chips[which].output[1];
+
+ chips[which].output_cb();
+ }
+}
+
+
+void TTL74153_a_w(int which, int data)
+{
+ chips[which].a = data ? 1 : 0;
+}
+
+
+void TTL74153_b_w(int which, int data)
+{
+ chips[which].b = data ? 1 : 0;
+}
+
+
+void TTL74153_input_line_w(int which, int section, int input_line, int data)
+{
+ chips[which].input_lines[section][input_line] = data ? 1 : 0;
+}
+
+
+void TTL74153_enable_w(int which, int section, int data)
+{
+ chips[which].enable[section] = data ? 1 : 0;
+}
+
+
+int TTL74153_output_r(int which, int section)
+{
+ return chips[which].output[section];
+}
+
+
+
+void TTL74153_config(int which, const struct TTL74153_interface *intf)
+{
+ if (which >= MAX_TTL74153)
+ {
+ logerror("Only %d 74153's are supported at this time.\n", MAX_TTL74153);
+ return;
+ }
+
+
+ chips[which].output_cb = (intf ? intf->output_cb : 0);
+ chips[which].a = 1;
+ chips[which].b = 1;
+ chips[which].enable[0] = 1;
+ chips[which].enable[1] = 1;
+ chips[which].input_lines[0][0] = 1;
+ chips[which].input_lines[0][1] = 1;
+ chips[which].input_lines[0][2] = 1;
+ chips[which].input_lines[0][3] = 1;
+ chips[which].input_lines[1][0] = 1;
+ chips[which].input_lines[1][1] = 1;
+ chips[which].input_lines[1][2] = 1;
+ chips[which].input_lines[1][3] = 1;
+
+ chips[which].last_output[0] = -1;
+ chips[which].last_output[1] = -1;
+}
diff --git a/src/emu/machine/74153.h b/src/emu/machine/74153.h
new file mode 100644
index 00000000000..2e7d9bdb487
--- /dev/null
+++ b/src/emu/machine/74153.h
@@ -0,0 +1,58 @@
+/*****************************************************************************
+
+ 74153 Dual 4-line to 1-line data selectors/multiplexers
+
+
+ Pin layout and functions to access pins:
+
+ enable_w(0) [1] /1G VCC [16]
+ b_w [2] B /2G [15] enable_w(1)
+ input_line_w(0,3) [3] 1C3 A [14] a_w
+ input_line_w(0,2) [4] 1C2 2C3 [13] input_line_w(1,3)
+ input_line_w(0,1) [5] 1C1 2C2 [12] input_line_w(1,2)
+ input_line_w(0,0) [6] 1C0 2C1 [11] input_line_w(1,1)
+ output_r(0) [7] 1Y 2C0 [10] input_line_w(1,0)
+ [8] GND 2Y [9] output_r(1)
+
+
+ Truth table (all logic levels indicate the actual voltage on the line):
+
+ INPUTS | OUTPUT
+ |
+ G | B A | C0 C1 C2 C3 | Y
+ --+------+-------------+---
+ H | X X | X X X X | L
+ L | L L | X X X X | C0
+ L | L H | X X X X | C1
+ L | H L | X X X X | C2
+ L | H H | X X X X | C3
+ --+------+-------------+---
+ L = lo (0)
+ H = hi (1)
+ X = any state
+
+*****************************************************************************/
+
+#ifndef TTL74153_H
+#define TTL74153_H
+
+
+/* The interface structure */
+struct TTL74153_interface
+{
+ void (*output_cb)(void);
+};
+
+
+void TTL74153_config(int which, const struct TTL74153_interface *intf);
+
+/* must call TTL74153_update() after setting the inputs */
+void TTL74153_update(int which);
+
+void TTL74153_a_w(int which, int data);
+void TTL74153_b_w(int which, int data);
+void TTL74153_input_line_w(int which, int section, int input_line, int data);
+void TTL74153_enable_w(int which, int section, int data);
+int TTL74153_output_r(int which, int section);
+
+#endif
diff --git a/src/emu/machine/74181.c b/src/emu/machine/74181.c
new file mode 100644
index 00000000000..2c730e8f45f
--- /dev/null
+++ b/src/emu/machine/74181.c
@@ -0,0 +1,165 @@
+/*
+ * 74181
+ *
+ * 4-bit arithmetic Logic Unit
+ *
+ */
+
+#include "driver.h"
+#include "74181.h"
+
+
+
+#define TTL74181_MAX_CHIPS (2)
+#define TTL74181_INPUT_TOTAL (14)
+#define TTL74181_OUTPUT_TOTAL (8)
+
+
+
+typedef struct _TTL74181_state TTL74181_state;
+struct _TTL74181_state
+{
+ UINT8 inputs[TTL74181_INPUT_TOTAL];
+ UINT8 outputs[TTL74181_OUTPUT_TOTAL];
+ UINT8 dirty;
+};
+
+static TTL74181_state chips[TTL74181_MAX_CHIPS];
+
+
+void TTL74181_config(int which, void *intf)
+{
+ TTL74181_state *c;
+
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call at init time!");
+ assert_always(intf == 0, "Interface must be NULL");
+ assert_always((which >= 0) && (which < TTL74181_MAX_CHIPS), "Exceeded maximum number of 74181 chips");
+
+ c = &chips[which];
+
+ c->dirty = 1;
+
+ state_save_register_item_array("TTL74181", which, c->inputs);
+ state_save_register_item_array("TTL74181", which, c->outputs);
+ state_save_register_item ("TTL74181", which, c->dirty);
+}
+
+
+void TTL74181_reset(int which)
+{
+ /* nothing to do */
+}
+
+
+static void TTL74181_update(int which)
+{
+ TTL74181_state *c = &chips[which];
+
+ UINT8 a0 = c->inputs[TTL74181_INPUT_A0];
+ UINT8 a1 = c->inputs[TTL74181_INPUT_A1];
+ UINT8 a2 = c->inputs[TTL74181_INPUT_A2];
+ UINT8 a3 = c->inputs[TTL74181_INPUT_A3];
+
+ UINT8 b0 = c->inputs[TTL74181_INPUT_B0];
+ UINT8 b1 = c->inputs[TTL74181_INPUT_B1];
+ UINT8 b2 = c->inputs[TTL74181_INPUT_B2];
+ UINT8 b3 = c->inputs[TTL74181_INPUT_B3];
+
+ UINT8 s0 = c->inputs[TTL74181_INPUT_S0];
+ UINT8 s1 = c->inputs[TTL74181_INPUT_S1];
+ UINT8 s2 = c->inputs[TTL74181_INPUT_S2];
+ UINT8 s3 = c->inputs[TTL74181_INPUT_S3];
+
+ UINT8 cp = c->inputs[TTL74181_INPUT_C];
+ UINT8 mp = !c->inputs[TTL74181_INPUT_M];
+
+ UINT8 ap0 = !(a0 | (b0 & s0) | (s1 & !b0));
+ UINT8 bp0 = !((!b0 & s2 & a0) | (a0 & b0 & s3));
+ UINT8 ap1 = !(a1 | (b1 & s0) | (s1 & !b1));
+ UINT8 bp1 = !((!b1 & s2 & a1) | (a1 & b1 & s3));
+ UINT8 ap2 = !(a2 | (b2 & s0) | (s1 & !b2));
+ UINT8 bp2 = !((!b2 & s2 & a2) | (a2 & b2 & s3));
+ UINT8 ap3 = !(a3 | (b3 & s0) | (s1 & !b3));
+ UINT8 bp3 = !((!b3 & s2 & a3) | (a3 & b3 & s3));
+
+ UINT8 fp0 = !(cp & mp) ^ (!ap0 & bp0);
+ UINT8 fp1 = (!((mp & ap0) | (mp & bp0 & cp))) ^ (!ap1 & bp1);
+ UINT8 fp2 = (!((mp & ap1) | (mp & ap0 & bp1) | (mp & cp & bp0 & bp1))) ^ (!ap2 & bp2);
+ UINT8 fp3 = (!((mp & ap2) | (mp & ap1 & bp2) | (mp & ap0 & bp1 & bp2) | (mp & cp & bp0 & bp1 & bp2))) ^ (!ap3 & bp3);
+
+ UINT8 aeqb = fp0 & fp1 & fp2 & fp3;
+ UINT8 pp = !(bp0 & bp1 & bp2 & bp3);
+ UINT8 gp = !((ap0 & bp1 & bp2 & bp3) | (ap1 & bp2 & bp3) | (ap2 & bp3) | ap3);
+ UINT8 cn4 = (!(cp & bp0 & bp1 & bp2 & bp3)) | gp;
+
+ c->outputs[TTL74181_OUTPUT_F0] = fp0;
+ c->outputs[TTL74181_OUTPUT_F1] = fp1;
+ c->outputs[TTL74181_OUTPUT_F2] = fp2;
+ c->outputs[TTL74181_OUTPUT_F3] = fp3;
+ c->outputs[TTL74181_OUTPUT_AEQB] = aeqb;
+ c->outputs[TTL74181_OUTPUT_P] = pp;
+ c->outputs[TTL74181_OUTPUT_G] = gp;
+ c->outputs[TTL74181_OUTPUT_CN4] = cn4;
+}
+
+
+void TTL74181_write(int which, int startline, int lines, UINT8 data)
+{
+ int line;
+ TTL74181_state *c;
+
+ assert_always((which >= 0) && (which < TTL74181_MAX_CHIPS), "Chip index out of range");
+
+ c = &chips[which];
+
+ assert_always(c != NULL, "Invalid index - chip has not been configured");
+ assert_always(lines >= 1, "Must set at least one line");
+ assert_always(lines <= 4, "Can't set more than 4 lines at once");
+ assert_always((startline + lines) <= TTL74181_INPUT_TOTAL, "Input line index out of range");
+
+ for (line = 0; line < lines; line++)
+ {
+ UINT8 input = (data >> line) & 0x01;
+
+ if (c->inputs[startline + line] != input)
+ {
+ c->inputs[startline + line] = input;
+
+ c->dirty = 1;
+ }
+ }
+}
+
+
+UINT8 TTL74181_read(int which, int startline, int lines)
+{
+ int line;
+ UINT8 data;
+ TTL74181_state *c;
+
+ assert_always((which >= 0) && (which < TTL74181_MAX_CHIPS), "Chip index out of range");
+
+ c = &chips[which];
+
+ assert_always(c != NULL, "Invalid index - chip has not been configured");
+ assert_always(lines >= 1, "Must read at least one line");
+ assert_always(lines <= 4, "Can't read more than 4 lines at once");
+ assert_always((startline + lines) <= TTL74181_OUTPUT_TOTAL, "Output line index out of range");
+
+ if (c->dirty)
+ {
+ TTL74181_update(which);
+
+ c->dirty = 0;
+ }
+
+
+ data = 0;
+
+ for (line = 0; line < lines; line++)
+ {
+ data = data | (c->outputs[startline + line] << line);
+ }
+
+ return data;
+}
diff --git a/src/emu/machine/74181.h b/src/emu/machine/74181.h
new file mode 100644
index 00000000000..21a5e59719d
--- /dev/null
+++ b/src/emu/machine/74181.h
@@ -0,0 +1,40 @@
+/*
+ * 74181
+ *
+ * 4-Bit Arithmetic Logic Unit
+ *
+ */
+
+
+/* constants for setting input lines */
+#define TTL74181_INPUT_A0 (0)
+#define TTL74181_INPUT_A1 (1)
+#define TTL74181_INPUT_A2 (2)
+#define TTL74181_INPUT_A3 (3)
+#define TTL74181_INPUT_B0 (4)
+#define TTL74181_INPUT_B1 (5)
+#define TTL74181_INPUT_B2 (6)
+#define TTL74181_INPUT_B3 (7)
+#define TTL74181_INPUT_S0 (8)
+#define TTL74181_INPUT_S1 (9)
+#define TTL74181_INPUT_S2 (10)
+#define TTL74181_INPUT_S3 (11)
+#define TTL74181_INPUT_C (12)
+#define TTL74181_INPUT_M (13)
+
+/* constants for reads output lines */
+#define TTL74181_OUTPUT_F0 (0)
+#define TTL74181_OUTPUT_F1 (1)
+#define TTL74181_OUTPUT_F2 (2)
+#define TTL74181_OUTPUT_F3 (3)
+#define TTL74181_OUTPUT_AEQB (4)
+#define TTL74181_OUTPUT_P (5)
+#define TTL74181_OUTPUT_G (6)
+#define TTL74181_OUTPUT_CN4 (7)
+
+
+void TTL74181_config(int chip, void *interface);
+void TTL74181_reset(int chip);
+
+void TTL74181_write(int chip, int startline, int lines, UINT8 data);
+UINT8 TTL74181_read(int chip, int startline, int lines);
diff --git a/src/emu/machine/7474.c b/src/emu/machine/7474.c
new file mode 100644
index 00000000000..700bb7bb879
--- /dev/null
+++ b/src/emu/machine/7474.c
@@ -0,0 +1,173 @@
+/*****************************************************************************
+
+ 7474 positive-edge-triggered D-type flip-flop with preset, clear and
+ complementary outputs. There are 2 flip-flops per chips
+
+
+ Pin layout and functions to access pins:
+
+ clear_w [1] /1CLR VCC [14]
+ d_w [2] 1D /2CLR [13] clear_w
+ clock_w [3] 1CLK 2D [12] d_w
+ preset_w [4] /1PR 2CLK [11] clock_w
+ output_r [5] 1Q /2PR [10] preset_w
+ output_comp_r [6] /1Q 2Q [9] output_r
+ [7] GND /2Q [8] output_comp_r
+
+
+ Truth table (all logic levels indicate the actual voltage on the line):
+
+ INPUTS | OUTPUTS
+ |
+ PR CLR CLK D | Q /Q
+ --------------+-------
+ 1 L H X X | H L
+ 2 H L X X | L H
+ 3 L L X X | H H (Note 1)
+ 4 H H _- X | D /D
+ 5 H H L X | Q0 /Q0
+ --------------+-------
+ L = lo (0)
+ H = hi (1)
+ X = any state
+ _- = raising edge
+ Q0 = previous state
+
+ Note 1: Non-stable configuration
+
+*****************************************************************************/
+
+#include "driver.h"
+#include "7474.h"
+
+
+#define MAX_TTL7474 12
+
+struct TTL7474
+{
+ /* callback */
+ void (*output_cb)(void);
+
+ /* inputs */
+ UINT8 clear; /* pin 1/13 */
+ UINT8 preset; /* pin 4/10 */
+ UINT8 clock; /* pin 3/11 */
+ UINT8 d; /* pin 2/12 */
+
+ /* outputs */
+ UINT8 output; /* pin 5/9 */
+ UINT8 output_comp; /* pin 6/8 */
+
+ /* internal */
+ UINT8 last_clock;
+ UINT8 last_output;
+ UINT8 last_output_comp;
+};
+
+static struct TTL7474 chips[MAX_TTL7474];
+
+
+void TTL7474_update(int which)
+{
+ if (!chips[which].preset && chips[which].clear) /* line 1 in truth table */
+ {
+ chips[which].output = 1;
+ chips[which].output_comp = 0;
+ }
+ else if (chips[which].preset && !chips[which].clear) /* line 2 in truth table */
+ {
+ chips[which].output = 0;
+ chips[which].output_comp = 1;
+ }
+ else if (!chips[which].preset && !chips[which].clear) /* line 3 in truth table */
+ {
+ chips[which].output = 1;
+ chips[which].output_comp = 1;
+ }
+ else if (!chips[which].last_clock && chips[which].clock) /* line 4 in truth table */
+ {
+ chips[which].output = chips[which].d;
+ chips[which].output_comp = !chips[which].d;
+ }
+
+ chips[which].last_clock = chips[which].clock;
+
+
+ /* call callback if any of the outputs changed */
+ if ( chips[which].output_cb &&
+ ((chips[which].output != chips[which].last_output) ||
+ (chips[which].output_comp != chips[which].last_output_comp)))
+ {
+ chips[which].last_output = chips[which].output;
+ chips[which].last_output_comp = chips[which].output_comp;
+
+ chips[which].output_cb();
+ }
+}
+
+
+void TTL7474_clear_w(int which, int data)
+{
+ chips[which].clear = data ? 1 : 0;
+}
+
+void TTL7474_preset_w(int which, int data)
+{
+ chips[which].preset = data ? 1 : 0;
+}
+
+void TTL7474_clock_w(int which, int data)
+{
+ chips[which].clock = data ? 1 : 0;
+}
+
+void TTL7474_d_w(int which, int data)
+{
+ chips[which].d = data ? 1 : 0;
+}
+
+
+int TTL7474_output_r(int which)
+{
+ return chips[which].output;
+}
+
+int TTL7474_output_comp_r(int which)
+{
+ return chips[which].output_comp;
+}
+
+
+void TTL7474_config(int which, const struct TTL7474_interface *intf)
+{
+ struct TTL7474 *chip = &chips[which];
+
+ if (which >= MAX_TTL7474)
+ {
+ logerror("Only %d 7474's are supported at this time.\n", MAX_TTL7474);
+ return;
+ }
+
+
+ chip->output_cb = (intf ? intf->output_cb : 0);
+
+ /* all inputs are open first */
+ chip->clear = 1;
+ chip->preset = 1;
+ chip->clock = 1;
+ chip->d = 1;
+
+ chip->last_clock = 1;
+ chip->last_output = -1;
+ chip->last_output_comp = -1;
+
+ state_save_register_item("ttl7474", which, chip->clear);
+ state_save_register_item("ttl7474", which, chip->preset);
+ state_save_register_item("ttl7474", which, chip->clock);
+ state_save_register_item("ttl7474", which, chip->d);
+ state_save_register_item("ttl7474", which, chip->output);
+ state_save_register_item("ttl7474", which, chip->output_comp);
+ state_save_register_item("ttl7474", which, chip->last_clock);
+ state_save_register_item("ttl7474", which, chip->last_output);
+ state_save_register_item("ttl7474", which, chip->last_output_comp);
+}
diff --git a/src/emu/machine/7474.h b/src/emu/machine/7474.h
new file mode 100644
index 00000000000..77ada157ce7
--- /dev/null
+++ b/src/emu/machine/7474.h
@@ -0,0 +1,63 @@
+/*****************************************************************************
+
+ 7474 positive-edge-triggered D-type flip-flop with preset, clear and
+ complementary outputs. There are 2 flip-flops per chips
+
+
+ Pin layout and functions to access pins:
+
+ clear_w [1] /1CLR VCC [14]
+ d_w [2] 1D /2CLR [13] clear_w
+ clock_w [3] 1CLK 2D [12] d_w
+ preset_w [4] /1PR 2CLK [11] clock_w
+ output_r [5] 1Q /2PR [10] preset_w
+ output_comp_r [6] /1Q 2Q [9] output_r
+ [7] GND /2Q [8] output_comp_r
+
+
+ Truth table (all logic levels indicate the actual voltage on the line):
+
+ INPUTS | OUTPUTS
+ |
+ PR CLR CLK D | Q /Q
+ --------------+-------
+ L H X X | H L
+ H L X X | L H
+ L L X X | H H (Note 1)
+ H H _- X | D /D
+ H H L X | Q0 /Q0
+ --------------+-------
+ L = lo (0)
+ H = hi (1)
+ X = any state
+ _- = raising edge
+ Q0 = previous state
+
+ Note 1: Non-stable configuration
+
+*****************************************************************************/
+
+#ifndef TTL7474_H
+#define TTL7474_H
+
+
+/* The interface structure */
+struct TTL7474_interface
+{
+ void (*output_cb)(void);
+};
+
+
+void TTL7474_config(int which, const struct TTL7474_interface *intf);
+
+/* must call TTL7474_update() after setting the inputs */
+void TTL7474_update(int which);
+
+void TTL7474_clear_w(int which, int data);
+void TTL7474_preset_w(int which, int data);
+void TTL7474_clock_w(int which, int data);
+void TTL7474_d_w(int which, int data);
+int TTL7474_output_r(int which);
+int TTL7474_output_comp_r(int which); /* NOT strictly the same as !TTL7474_output_r() */
+
+#endif
diff --git a/src/emu/machine/8042kbdc.c b/src/emu/machine/8042kbdc.c
new file mode 100644
index 00000000000..392acbe7c9a
--- /dev/null
+++ b/src/emu/machine/8042kbdc.c
@@ -0,0 +1,622 @@
+/*********************************************************************
+
+ ibmat.c
+
+ Code specific to fun IBM AT stuff
+
+
+ PeT's notes about various Power On Self Tests (POSTs)
+
+ at post
+ -------
+ f81d2 01
+ f82e6 05
+ f8356 07
+ f83e5 0a
+ f847e 0e
+ f8e7c 10
+ f8f3a 13
+ f9058 1a
+ f913a 1e
+ fa8ba 30
+ fa96c 36
+ fa9d3 3c
+ fa9f4 3e
+ ff122 50
+ ff226 5b
+ ff29f 5f
+ f9228 70
+ f92b2 74 ide?
+
+ ibm at bios
+ -----------
+ f0101 after switch to real mode jump back!!!!!!!!!!
+ jumping table
+ f0123
+ f098e memory tests
+ f10b4 ???
+ not reached
+ f1050
+ f1617
+ f0119
+ f10d8
+ f10b7 system board error
+
+ f019f
+ f025b
+ f02e6
+ f0323
+ f03b3 0e
+ f03d7 0f
+ f058d
+ at8042 signal timing test
+ sets errorcode!
+
+ f0655
+ f06a3 postcode 15
+ f06ba 16
+ f0747 18
+ f0763 enter pm! (0x81, 0x85)
+ f0766 1a
+ f07b3 first 640kb memory test
+ f084c 1c
+ f086e extended memory test
+ f0928 1f
+ f097d 20
+ ???
+ f0ff4 34
+ ???
+ f1675 f0
+ f16cb f2
+ illegal access trap test!!!!
+ f16fe f3
+ task descriptor test!!!!
+ f174a f4
+ f17af f5
+ f1800 f6 writing to non write segment
+ f1852 f7 arpl
+ f1880 f8 lar, lsl
+ f18ca fa
+ f10d8
+ f10ec 35
+ f1106 36
+ f1137 !!!!!!!keyboard test fails
+
+ f11aa 3a
+ f1240 3c harddisk controller test!!!
+ f13f3 3b
+ f1a6d xthdd bios init
+ f1429
+ f1462
+ f1493 40
+ f1532
+ keyboard lock
+ f1 to unlock
+ f155c
+ jumps to f0050 (reset) without enabling of the a20 gate --> hangs
+ 0412 bit 5 must be set to reach f1579
+ f1579
+ f15c3 41
+ f1621 43
+
+ routines
+ f1945 read cmos ram
+ f195f write to cmos al value ah
+ f1a3a poll 0x61 bit 4
+ f1a49 sets something in cmos ram
+ f1d30 switch to protected mode
+
+ neat
+ ----
+ f80b9
+
+ at386
+ -----
+ fd28c fd
+ fd2c3 fc
+ f40dc
+ fd949
+ fd8e3
+ fd982
+ f4219 01
+ f4296 03
+ f42f3 04
+ f4377 05
+ f43ec 06
+ f4430 08
+ f6017 switches to PM
+ f4456 09
+ f55a2
+ f44ec 0d
+ f4557 20
+ f462d 27 my special friend, the keyboard controller once more
+ ed0a1
+ f4679 28
+ fa16a
+ f46d6
+ f4768 2c
+ f47f0 2e
+ f5081
+ fa16a
+ f9a83
+ Message: "Checksum Error on Extended CMOS"
+ f4840 34
+ f488c 35
+ reset
+ f48ee
+ f493e 3a
+ f49cd
+ f4fc7
+ fe842
+ f4a5a
+ f4b01 38
+ (Memory Test)
+ f4b41 3b
+ f4c0f
+ Message: "Invalid configuration information - please run SETUP program"
+ f4c5c
+ f86fc
+ f8838
+ f4c80
+ f4ca2
+ f4d4c
+ f4e15 (int 19h)
+
+ [f9a83 output text at return address!, return after text]
+
+
+ at486
+ -----
+ f81a5 03
+ f1096 0f 09 wbinvd i486 instruction
+
+*********************************************************************/
+
+
+#include "driver.h"
+#include "memconv.h"
+
+#include "machine/pckeybrd.h"
+#include "machine/8042kbdc.h"
+#include "machine/pit8253.h"
+#include "machine/pcshare.h"
+
+
+/***************************************************************************
+
+ Constants & macros
+
+***************************************************************************/
+
+#define PS2_MOUSE_ON 1
+#define KEYBOARD_ON 1
+
+#define LOG_KEYBOARD 0
+#define LOG_ACCESSES 0
+
+
+
+/***************************************************************************
+
+ Type definitions
+
+***************************************************************************/
+
+static struct
+{
+ kbdc8042_type_t type;
+ void (*set_gate_a20)(int a20);
+ void (*keyboard_interrupt)(int state);
+
+ UINT8 inport, outport, data, command;
+
+ struct {
+ int received;
+ int on;
+ } keyboard;
+ struct {
+ int received;
+ int on;
+ } mouse;
+
+ int last_write_to_control;
+ int sending;
+ int send_to_mouse;
+
+ int operation_write_state;
+ int status_read_mode;
+
+ int speaker;
+
+ /* temporary hack */
+ int offset1;
+} kbdc8042;
+
+static void at_8042_check_keyboard(void);
+
+
+
+/***************************************************************************
+
+ Code
+
+***************************************************************************/
+
+static void at_8042_set_outport(UINT8 data, int initial)
+{
+ UINT8 change;
+ change = initial ? 0xFF : (kbdc8042.outport ^ data);
+ kbdc8042.outport = data;
+ if (change & 0x02)
+ {
+ if (kbdc8042.set_gate_a20)
+ kbdc8042.set_gate_a20(data & 0x02 ? 1 : 0);
+ }
+}
+
+
+
+static TIMER_CALLBACK( kbdc8042_time )
+{
+ at_keyboard_polling();
+ at_8042_check_keyboard();
+}
+
+
+
+void kbdc8042_init(const struct kbdc8042_interface *intf)
+{
+ memset(&kbdc8042, 0, sizeof(kbdc8042));
+ kbdc8042.type = intf->type;
+ kbdc8042.set_gate_a20 = intf->set_gate_a20;
+ kbdc8042.keyboard_interrupt = intf->keyboard_interrupt;
+
+ /* ibmat bios wants 0x20 set! (keyboard locked when not set) 0x80 */
+ kbdc8042.inport = 0xa0;
+ at_8042_set_outport(0xfe, 1);
+
+ timer_pulse(ATTOTIME_IN_HZ(60), 0, kbdc8042_time);
+}
+
+static void at_8042_receive(UINT8 data)
+{
+ if (LOG_KEYBOARD)
+ logerror("at_8042_receive Received 0x%02x\n", data);
+
+ kbdc8042.data = data;
+ kbdc8042.keyboard.received = 1;
+
+ if (kbdc8042.keyboard_interrupt)
+ {
+ kbdc8042.keyboard_interrupt(1);
+ kbdc8042.keyboard_interrupt(0);
+ }
+}
+
+static void at_8042_check_keyboard(void)
+{
+ int data;
+
+ if (!kbdc8042.keyboard.received
+ && !kbdc8042.mouse.received)
+ {
+ if ( (data = at_keyboard_read())!=-1)
+ at_8042_receive(data);
+ }
+}
+
+
+
+static void at_8042_clear_keyboard_received(void)
+{
+ if (kbdc8042.keyboard.received)
+ {
+ if (LOG_KEYBOARD)
+ logerror("kbdc8042_8_r(): Clearing kbdc8042.keyboard.received\n");
+ }
+
+ kbdc8042.keyboard.received = 0;
+ kbdc8042.mouse.received = 0;
+}
+
+
+
+/* **************************************************************************
+ * Port 0x60 Input and Output Buffer (keyboard and mouse data)
+ * Port 0x64 Read Status Register
+ * Write operation for controller
+ *
+ * Output port controller:
+ * 7: Keyboard data
+ * 6: Keyboard clock
+ * 5: Mouse buffer full
+ * 4: Keyboard buffer full
+ * 3: Mouse clock
+ * 2: Mouse data
+ * 1: 0 A20 cleared
+ * 0: 0 system reset
+ *
+ * Input port controller
+ * 7: 0=Keyboard Locked
+ * 6: 1 = Monochrome 0 = Color (true for real IBM, clones are undefined and use CMOS RAM data)
+ * 5..2: reserved
+ * 1: Mouse data in
+ * 0: Keyboard data in
+ */
+
+READ8_HANDLER(kbdc8042_8_r)
+{
+ static int poll_delay = 10;
+ UINT8 data = 0;
+
+ switch (offset) {
+ case 0:
+ data = kbdc8042.data;
+ if (kbdc8042.type != KBDC8042_AT386 || (data != 0x55))
+ {
+ /* at386 self test doesn't like this */
+ at_8042_clear_keyboard_received();
+ }
+ at_8042_check_keyboard();
+ break;
+
+ case 1:
+ data = kbdc8042.speaker;
+ data &= ~0xc0; /* AT BIOS don't likes this being set */
+
+ /* needed for AMI BIOS, maybe only some keyboard controller revisions! */
+ at_8042_clear_keyboard_received();
+
+ /* polled for changes in ibmat bios */
+ if (--poll_delay < 0)
+ {
+ if (kbdc8042.type != KBDC8042_PS2)
+ poll_delay = 4; /* ibmat */
+ else
+ poll_delay = 8; /* ibm ps2m30 */
+ kbdc8042.offset1 ^= 0x10;
+ }
+ data = (data & ~0x10) | kbdc8042.offset1;
+
+ if (kbdc8042.speaker & 1)
+ data |= 0x20;
+ else
+ data &= ~0x20; /* ps2m30 wants this */
+ break;
+
+ case 2:
+ if (pit8253_get_output(0, 2))
+ data |= 0x20;
+ else
+ data &= ~0x20;
+ break;
+
+ case 4:
+ at_8042_check_keyboard();
+
+ if (kbdc8042.keyboard.received || kbdc8042.mouse.received)
+ data |= 1;
+ if (kbdc8042.sending)
+ data |= 2;
+
+ kbdc8042.sending = 0; /* quicker than normal */
+ data |= 4; /* selftest ok */
+
+ if (kbdc8042.last_write_to_control)
+ data |= 8;
+
+ switch (kbdc8042.status_read_mode) {
+ case 0:
+ if (!kbdc8042.keyboard.on) data|=0x10;
+ if (kbdc8042.mouse.received) data|=0x20;
+ break;
+ case 1:
+ data |= kbdc8042.inport&0xf;
+ break;
+ case 2:
+ data |= kbdc8042.inport<<4;
+ break;
+ }
+ break;
+ }
+
+ if (LOG_ACCESSES)
+ logerror("kbdc8042_8_r(): offset=%d data=0x%02x\n", offset, (unsigned) data);
+ return data;
+}
+
+
+
+WRITE8_HANDLER(kbdc8042_8_w)
+{
+ switch (offset) {
+ case 0:
+ kbdc8042.last_write_to_control = 0;
+ kbdc8042.status_read_mode = 0;
+ switch (kbdc8042.operation_write_state) {
+ case 0:
+ /* normal case */
+ kbdc8042.data = data;
+ kbdc8042.sending=1;
+ at_keyboard_write(data);
+ break;
+
+ case 1:
+ /* preceeded by writing 0xD1 to port 60h
+ * |7|6|5|4|3|2|1|0| 8042 Output Port
+ * | | | | | | | `---- system reset line
+ * | | | | | | `----- gate A20
+ * | | | | `-------- undefined
+ * | | | `--------- output buffer full
+ * | | `---------- input buffer empty
+ * | `----------- keyboard clock (output)
+ * `------------ keyboard data (output)
+ */
+ at_8042_set_outport(data, 0);
+ break;
+
+ case 2:
+ /* preceeded by writing 0xD2 to port 60h */
+ kbdc8042.data = data;
+ kbdc8042.sending=1;
+ at_keyboard_write(data);
+ break;
+
+ case 3:
+ /* preceeded by writing 0xD3 to port 60h */
+ kbdc8042.data = data;
+ break;
+
+ case 4:
+ /* preceeded by writing 0xD4 to port 60h */
+ kbdc8042.data = data;
+ break;
+
+ case 5:
+ /* preceeded by writing 0x60 to port 60h */
+ kbdc8042.command = data;
+ break;
+ }
+ kbdc8042.operation_write_state = 0;
+ break;
+
+ case 1:
+ kbdc8042.speaker = data;
+#ifdef MESS
+ pc_sh_speaker(data&3);
+#endif /* MESS */
+ break;
+
+ case 4:
+ kbdc8042.last_write_to_control=0;
+
+ /* switch based on the command */
+ switch(data) {
+ case 0x20: /* current 8042 command byte is placed on port 60h */
+ kbdc8042.data = kbdc8042.command;
+ break;
+ case 0x60: /* next data byte is placed in 8042 command byte */
+ kbdc8042.operation_write_state = 5;
+ kbdc8042.send_to_mouse = 0;
+ break;
+ case 0xa7: /* disable auxilary interface */
+ kbdc8042.mouse.on = 0;
+ break;
+ case 0xa8: /* enable auxilary interface */
+ kbdc8042.mouse.on = 1;
+ break;
+ case 0xa9: /* test mouse */
+ at_8042_receive(PS2_MOUSE_ON ? 0x00 : 0xff);
+ break;
+ case 0xaa: /* selftest */
+ at_8042_receive(0x55);
+ break;
+ case 0xab: /* test keyboard */
+ at_8042_receive(KEYBOARD_ON ? 0x00 : 0xff);
+ break;
+ case 0xad: /* disable keyboard interface */
+ kbdc8042.keyboard.on = 0;
+ break;
+ case 0xae: /* enable keyboard interface */
+ kbdc8042.keyboard.on = 1;
+ break;
+ case 0xc0: /* read input port */
+ /* |7|6|5|4|3 2 1 0| 8042 Input Port
+ * | | | | |
+ * | | | | `------- undefined
+ * | | | |
+ * | | | `--------- 1=enable 2nd 256k of Motherboard RAM
+ * | | `---------- 1=manufacturing jumper installed
+ * | `----------- 1=primary display is MDA, 0=CGA
+ * `------------ 1=keyboard not inhibited; 0=inhibited
+ */
+ at_8042_receive(kbdc8042.inport);
+ break;
+ case 0xc1: /* read input port 3..0 until write to 0x60 */
+ kbdc8042.status_read_mode = 1;
+ break;
+ case 0xc2: /* read input port 7..4 until write to 0x60 */
+ kbdc8042.status_read_mode = 2;
+ break;
+ case 0xd0: /* read output port */
+ at_8042_receive(kbdc8042.outport);
+ break;
+ case 0xd1:
+ /* write output port; next byte written to port 60h is placed on
+ * 8042 output port */
+ kbdc8042.operation_write_state = 1;
+ break;
+ case 0xd2:
+ /* write keyboard output register; on PS/2 systems next port 60h
+ * write is written to port 60h output register as if initiated
+ * by a device; invokes interrupt if enabled */
+ kbdc8042.operation_write_state = 2;
+ kbdc8042.send_to_mouse = 0;
+ break;
+ case 0xd3:
+ /* write auxillary output register; on PS/2 systems next port 60h
+ * write is written to port 60h input register as if initiated
+ * by a device; invokes interrupt if enabled */
+ kbdc8042.operation_write_state = 3;
+ kbdc8042.send_to_mouse = 1;
+ break;
+ case 0xd4:
+ /* write auxillary device; on PS/2 systems the next data byte
+ * written to input register a port at 60h is sent to the
+ * auxiliary device */
+ kbdc8042.operation_write_state = 4;
+ break;
+ case 0xe0:
+ /* read test inputs; read T1/T0 test inputs into bit 1/0 */
+ at_8042_receive(0x00);
+ break;
+
+ case 0xf0:
+ case 0xf2:
+ case 0xf4:
+ case 0xf6:
+ case 0xf8:
+ case 0xfa:
+ case 0xfc:
+ case 0xfe:
+ /* Commands 0xF0...0xFF causes certain output lines to be pulsed
+ * low for six milliseconds. The bits pulsed low correspond to
+ * the bits low set in the command byte. The only pulse that has
+ * an effect currently is bit 0, which pulses the CPU's reset line
+ */
+ cpunum_set_input_line(0, INPUT_LINE_RESET, PULSE_LINE);
+ at_8042_set_outport(kbdc8042.outport | 0x02, 0);
+ break;
+ }
+ kbdc8042.sending = 1;
+ break;
+ }
+}
+
+
+
+READ32_HANDLER( kbdc8042_32le_r )
+{
+ return read32le_with_read8_handler(kbdc8042_8_r, offset, mem_mask);
+}
+
+
+
+WRITE32_HANDLER( kbdc8042_32le_w )
+{
+ write32le_with_write8_handler(kbdc8042_8_w, offset, data, mem_mask);
+}
+
+
+
+READ64_HANDLER( kbdc8042_64be_r )
+{
+ return read64be_with_read8_handler(kbdc8042_8_r, offset, mem_mask);
+}
+
+
+
+WRITE64_HANDLER( kbdc8042_64be_w )
+{
+ write64be_with_write8_handler(kbdc8042_8_w, offset, data, mem_mask);
+}
diff --git a/src/emu/machine/8042kbdc.h b/src/emu/machine/8042kbdc.h
new file mode 100644
index 00000000000..50113e88790
--- /dev/null
+++ b/src/emu/machine/8042kbdc.h
@@ -0,0 +1,40 @@
+/**********************************************************************
+
+ 8042 Keyboard Controller Emulation
+
+ This is the keyboard controller used in the IBM AT and further
+ models. It is a popular controller for PC style keyboards
+
+**********************************************************************/
+
+#ifndef KBDC8042_H
+#define KBDC8042_H
+
+typedef enum
+{
+ KBDC8042_STANDARD,
+ KBDC8042_PS2, /* another timing of integrated controller */
+ KBDC8042_AT386 /* hack for at386 driver */
+} kbdc8042_type_t;
+
+
+struct kbdc8042_interface
+{
+ kbdc8042_type_t type;
+ void (*set_gate_a20)(int a20);
+ void (*keyboard_interrupt)(int state);
+};
+
+
+
+void kbdc8042_init(const struct kbdc8042_interface *intf);
+
+READ8_HANDLER(kbdc8042_8_r);
+WRITE8_HANDLER(kbdc8042_8_w);
+READ32_HANDLER(kbdc8042_32le_r);
+WRITE32_HANDLER(kbdc8042_32le_w);
+READ64_HANDLER(kbdc8042_64be_r);
+WRITE64_HANDLER(kbdc8042_64be_w);
+
+#endif /* KBDC8042_H */
+
diff --git a/src/emu/machine/8237dma.c b/src/emu/machine/8237dma.c
new file mode 100644
index 00000000000..12303219ba9
--- /dev/null
+++ b/src/emu/machine/8237dma.c
@@ -0,0 +1,450 @@
+/**********************************************************************
+
+ 8237 DMA interface and emulation
+
+ The DMA works like this:
+ (summarized from http://www.infran.ru/TechInfo/BSD/handbook258.html#410)
+
+ 1. The device asserts the DRQn line
+ 2. The DMA clears the TC (terminal count) line
+ 3. The DMA asserts the CPU's HRQ (halt request) line
+ 4. Upon acknowledgement of the halt, the DMA will let the device
+ know that it needs to send information by asserting the DACKn
+ line
+ 5. The DMA will read the byte from the device
+ 6. The device clears the DRQn line
+ 7. The DMA clears the CPU's HRQ line
+ 8. (steps 3-7 are repeated for every byte in the chain)
+
+**********************************************************************/
+
+#include "driver.h"
+#include "memconv.h"
+#include "8237dma.h"
+
+struct dma8237
+{
+ const struct dma8237_interface *intf;
+ emu_timer *timer;
+ emu_timer *msbflip_timer;
+
+ struct
+ {
+ UINT16 address;
+ UINT16 count;
+ UINT8 mode;
+ } chan[4];
+
+ UINT32 msb : 1;
+ UINT32 eop : 1;
+ UINT8 temp;
+ UINT8 command;
+ UINT8 drq;
+ UINT8 mask;
+
+ /* bits 0- 3 : Terminal count for channels 0-3
+ * bits 4- 7 : Transfer in progress for channels 0-3 */
+ UINT8 status;
+};
+
+static struct dma8237 *dma;
+static int dma_count;
+
+
+#define DMA_MODE_CHANNEL(mode) ((mode) & 0x03)
+#define DMA_MODE_OPERATION(mode) (((mode) >> 2) & 0x03)
+#define DMA_MODE_DIRECTION(mode) (((mode) & 0x20) ? -1 : +1)
+#define DMA_MODE_TRANSFERMODE(mode) (((mode) >> 6) & 0x03)
+
+
+
+static TIMER_CALLBACK( dma8237_timerproc );
+static TIMER_CALLBACK( dma8237_msbflip_timerproc );
+static void dma8237_update_status(int which);
+
+/* ----------------------------------------------------------------------- */
+
+int dma8237_init(int count)
+{
+ int which;
+
+ dma = auto_malloc(count * sizeof(struct dma8237));
+ memset(dma, 0, count * sizeof(struct dma8237));
+ dma_count = count;
+
+ for (which = 0; which < dma_count; which++)
+ {
+ dma[which].status = 0x0F;
+ dma[which].timer = timer_alloc(dma8237_timerproc);
+ dma[which].msbflip_timer = timer_alloc(dma8237_msbflip_timerproc);
+ dma[which].eop = 1;
+ }
+ return 0;
+}
+
+
+
+void dma8237_config(int which, const struct dma8237_interface *intf)
+{
+ dma[which].intf = intf;
+}
+
+
+
+void dma8237_reset(void)
+{
+ int which;
+
+ for (which = 0; which < dma_count; which++)
+ {
+ dma[which].mask = 0x00;
+ dma[which].status = 0x0F;
+ dma[which].chan[0].mode = 0;
+ dma[which].chan[1].mode = 0;
+ dma[which].chan[2].mode = 0;
+ dma[which].chan[3].mode = 0;
+ dma8237_update_status(which);
+ }
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+
+
+static int dma8237_do_operation(int which, int channel)
+{
+ int done;
+ UINT8 data;
+ UINT8 mode;
+
+ mode = dma[which].chan[channel].mode;
+
+ switch(DMA_MODE_OPERATION(mode)) {
+ case 1:
+ data = dma[which].intf->channel_read_func[channel]();
+ dma[which].intf->memory_write_func(channel, dma[which].chan[channel].address, data);
+
+ dma[which].chan[channel].address += DMA_MODE_DIRECTION(mode);
+ dma[which].chan[channel].count--;
+ done = (dma[which].chan[channel].count == 0xFFFF);
+ break;
+
+ case 2:
+ data = dma[which].intf->memory_read_func(channel, dma[which].chan[channel].address);
+ dma[which].intf->channel_write_func[channel](data);
+
+ dma[which].chan[channel].address += DMA_MODE_DIRECTION(mode);
+ dma[which].chan[channel].count--;
+ done = (dma[which].chan[channel].count == 0xFFFF);
+ break;
+
+ default:
+ done = TRUE;
+ break;
+ }
+ return done;
+}
+
+
+
+static TIMER_CALLBACK( dma8237_timerproc )
+{
+ int which = param / 4;
+ int channel = param % 4;
+ int done;
+
+ done = dma8237_do_operation(which, channel);
+
+ if (done)
+ {
+ dma[which].status &= ~(0x10 << channel);
+ dma[which].status |= (0x01 << channel);
+ dma[which].drq &= ~(0x01 << channel);
+ dma8237_update_status(which);
+ }
+}
+
+
+
+static TIMER_CALLBACK( dma8237_msbflip_timerproc )
+{
+ dma[param].msb ^= 1;
+}
+
+
+
+static void dma8237_update_status(int which)
+{
+ UINT16 pending_transfer;
+ int channel;
+ UINT32 new_eop;
+
+ if ((dma[which].status & 0xF0) == 0)
+ {
+ /* no transfer is active right now; is there a transfer pending right now? */
+ pending_transfer = dma[which].drq & ~dma[which].mask;
+
+ if (pending_transfer)
+ {
+ /* we do have a transfer in progress */
+ for (channel = 3; (pending_transfer & (1 << channel)) == 0; channel--)
+ ;
+
+ dma[which].status |= 0x10 << channel;
+ dma[which].status &= ~(0x01 << channel);
+
+ timer_adjust(dma[which].timer,
+ attotime_zero,
+ which * 4 + channel,
+ double_to_attotime(dma[which].intf->bus_speed));
+ }
+ else
+ {
+ /* no transfers active right now */
+ timer_reset(dma[which].timer, attotime_never);
+ }
+
+ /* set the halt line */
+ if (dma[which].intf && dma[which].intf->cpunum >= 0)
+ {
+ cpunum_set_input_line(dma[which].intf->cpunum, INPUT_LINE_HALT,
+ pending_transfer ? ASSERT_LINE : CLEAR_LINE);
+ }
+
+ /* set the eop line, if it has changed */
+ new_eop = (dma[which].status & 0x0F) == 0x0F ? 1 : 0;
+ if (dma[which].eop != new_eop)
+ {
+ dma[which].eop = new_eop;
+ if (dma[which].intf->out_eop_func)
+ dma[which].intf->out_eop_func(new_eop ? ASSERT_LINE : CLEAR_LINE);
+ }
+ }
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+static void dma8237_verify(int which)
+{
+}
+
+
+
+static void prepare_msb_flip(int which)
+{
+ timer_adjust(dma[which].msbflip_timer, attotime_zero, which, attotime_zero);
+}
+
+
+
+static UINT8 dma8237_read(int which, offs_t offset)
+{
+ UINT8 data = 0xFF;
+ UINT8 mode;
+
+ dma8237_verify(which);
+ offset &= 0x0F;
+
+ switch(offset) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ /* DMA address register */
+ data = dma[which].chan[offset / 2].address >> (dma[which].msb ? 8 : 0);
+ prepare_msb_flip(which);
+
+ /* hack simulating refresh activity for 'ibmxt' BIOS; I do not know
+ * why this is needed; but in any case, the ibmxt driver does not load
+ * if this code is not present */
+ mode = dma[which].chan[0].mode;
+ if ((DMA_MODE_OPERATION(mode) == 2) && (offset == 0))
+ {
+ dma[which].chan[0].address++;
+ dma[which].chan[0].count--;
+ }
+ break;
+
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ /* DMA count register */
+ data = dma[which].chan[offset / 2].count >> (dma[which].msb ? 8 : 0);
+ prepare_msb_flip(which);
+ break;
+
+ case 8:
+ /* DMA status register */
+ data = (UINT8) dma[which].status;
+ break;
+
+ case 10:
+ /* DMA mask register */
+ data = dma[which].mask;
+ break;
+
+ case 13:
+ /* DMA master clear */
+ data = dma[which].temp;
+ break;
+
+ case 9: /* DMA write request register */
+ case 11: /* DMA mode register */
+ case 12: /* DMA clear byte pointer flip-flop */
+ case 14: /* DMA clear mask register */
+ case 15: /* DMA write mask register */
+ data = 0xFF;
+ break;
+ }
+ return data;
+}
+
+
+
+static void dma8237_write(int which, offs_t offset, UINT8 data)
+{
+ int channel;
+
+ dma8237_verify(which);
+ offset &= 0x0F;
+
+ switch(offset) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ /* DMA address register */
+ if (dma[which].msb)
+ dma[which].chan[offset / 2].address |= ((UINT16) data) << 8;
+ else
+ dma[which].chan[offset / 2].address = data;
+ prepare_msb_flip(which);
+ break;
+
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ /* DMA count register */
+ if (dma[which].msb)
+ dma[which].chan[offset / 2].count |= ((UINT16) data) << 8;
+ else
+ dma[which].chan[offset / 2].count = data;
+ prepare_msb_flip(which);
+ break;
+
+ case 8:
+ /* DMA command register */
+ dma[which].command = data;
+ break;
+
+ case 10:
+ /* DMA mask register */
+ channel = DMA_MODE_CHANNEL(data);
+ if (data & 0x04)
+ dma[which].mask |= 0x11 << channel;
+ else
+ dma[which].mask &= ~(0x11 << channel);
+ break;
+
+ case 11:
+ /* DMA mode register */
+ channel = DMA_MODE_CHANNEL(data);
+ dma[which].chan[channel].mode = data;
+ break;
+
+ case 12:
+ /* DMA clear byte pointer flip-flop */
+ dma[which].temp = data;
+ dma[which].msb = 0;
+ break;
+
+ case 13:
+ /* DMA master clear */
+ dma[which].msb = 0;
+ break;
+
+ case 14:
+ /* DMA clear mask register */
+ dma[which].mask &= ~data;
+ dma8237_update_status(which);
+ break;
+
+ case 15:
+ /* DMA write mask register */
+ dma[which].mask |= data;
+ break;
+ }
+}
+
+
+
+static void dma8237_drq_write_callback(int param)
+{
+ int which = param >> 3;
+ int channel = (param >> 1) & 0x03;
+ int state = param & 0x01;
+
+ /* normalize state */
+ if (state)
+ dma[which].drq |= 0x01 << channel;
+ else
+ dma[which].drq &= ~(0x01 << channel);
+
+ dma8237_update_status(which);
+}
+
+
+
+void dma8237_drq_write(int which, int channel, int state)
+{
+ int param;
+
+ param = (which << 3) | (channel << 1) | (state ? 1 : 0);
+ //timer_call_after_resynch(param, dma8237_drq_write_callback);
+ dma8237_drq_write_callback(param);
+}
+
+
+
+/******************* Unfortunate hacks *******************/
+
+void dma8237_run_transfer(int which, int channel)
+{
+ dma[which].status |= 0x10 << channel; /* reset DMA running flag */
+
+ while(!dma8237_do_operation(which, channel))
+ ;
+
+ dma[which].status &= ~(0x10 << channel);
+ dma[which].status |= (0x01 << channel);
+}
+
+
+
+/******************* Standard 8-bit/32-bit/64-bit CPU interfaces *******************/
+
+READ8_HANDLER( dma8237_0_r ) { return dma8237_read(0, offset); }
+READ8_HANDLER( dma8237_1_r ) { return dma8237_read(1, offset); }
+WRITE8_HANDLER( dma8237_0_w ) { dma8237_write(0, offset, data); }
+WRITE8_HANDLER( dma8237_1_w ) { dma8237_write(1, offset, data); }
+
+READ16_HANDLER( dma8237_16le_0_r ) { return read16le_with_read8_handler(dma8237_0_r, offset, mem_mask); }
+READ16_HANDLER( dma8237_16le_1_r ) { return read16le_with_read8_handler(dma8237_1_r, offset, mem_mask); }
+WRITE16_HANDLER( dma8237_16le_0_w ) { write16le_with_write8_handler(dma8237_0_w, offset, data, mem_mask); }
+WRITE16_HANDLER( dma8237_16le_1_w ) { write16le_with_write8_handler(dma8237_1_w, offset, data, mem_mask); }
+
+READ32_HANDLER( dma8237_32le_0_r ) { return read32le_with_read8_handler(dma8237_0_r, offset, mem_mask); }
+READ32_HANDLER( dma8237_32le_1_r ) { return read32le_with_read8_handler(dma8237_1_r, offset, mem_mask); }
+WRITE32_HANDLER( dma8237_32le_0_w ) { write32le_with_write8_handler(dma8237_0_w, offset, data, mem_mask); }
+WRITE32_HANDLER( dma8237_32le_1_w ) { write32le_with_write8_handler(dma8237_1_w, offset, data, mem_mask); }
+
+READ64_HANDLER( dma8237_64be_0_r ) { return read64be_with_read8_handler(dma8237_0_r, offset, mem_mask); }
+READ64_HANDLER( dma8237_64be_1_r ) { return read64be_with_read8_handler(dma8237_1_r, offset, mem_mask); }
+WRITE64_HANDLER( dma8237_64be_0_w ) { write64be_with_write8_handler(dma8237_0_w, offset, data, mem_mask); }
+WRITE64_HANDLER( dma8237_64be_1_w ) { write64be_with_write8_handler(dma8237_1_w, offset, data, mem_mask); }
diff --git a/src/emu/machine/8237dma.h b/src/emu/machine/8237dma.h
new file mode 100644
index 00000000000..65af5083ffe
--- /dev/null
+++ b/src/emu/machine/8237dma.h
@@ -0,0 +1,61 @@
+/**********************************************************************
+
+ 8237 DMA interface and emulation
+
+**********************************************************************/
+
+#ifndef DMA8237_H
+#define DMA8237_H
+
+struct dma8237_interface
+{
+ /* CPU to halt when DMA is active */
+ int cpunum;
+
+ /* speed of DMA accesses (per byte) */
+ double bus_speed;
+
+ /* accessors to main memory */
+ UINT8 (*memory_read_func)(int channel, offs_t offset);
+ void (*memory_write_func)(int channel, offs_t offset, UINT8 data);
+
+ /* channel accesors */
+ int (*channel_read_func[4])(void);
+ void (*channel_write_func[4])(int data);
+
+ /* function to call when DMA completes */
+ void (*out_eop_func)(int state);
+};
+
+
+
+int dma8237_init(int count);
+void dma8237_config(int which, const struct dma8237_interface *intf);
+void dma8237_reset(void);
+
+void dma8237_drq_write(int which, int channel, int state);
+
+/* unfortunate hack for the interim for PC HDC */
+void dma8237_run_transfer(int which, int channel);
+
+READ8_HANDLER( dma8237_0_r );
+READ8_HANDLER( dma8237_1_r );
+WRITE8_HANDLER( dma8237_0_w );
+WRITE8_HANDLER( dma8237_1_w );
+
+READ16_HANDLER( dma8237_16le_0_r );
+READ16_HANDLER( dma8237_16le_1_r );
+WRITE16_HANDLER( dma8237_16le_0_w );
+WRITE16_HANDLER( dma8237_16le_1_w );
+
+READ32_HANDLER( dma8237_32le_0_r );
+READ32_HANDLER( dma8237_32le_1_r );
+WRITE32_HANDLER( dma8237_32le_0_w );
+WRITE32_HANDLER( dma8237_32le_1_w );
+
+READ64_HANDLER( dma8237_64be_0_r );
+READ64_HANDLER( dma8237_64be_1_r );
+WRITE64_HANDLER( dma8237_64be_0_w );
+WRITE64_HANDLER( dma8237_64be_1_w );
+
+#endif /* DMA8237_H */
diff --git a/src/emu/machine/8255ppi.c b/src/emu/machine/8255ppi.c
new file mode 100644
index 00000000000..592c9153239
--- /dev/null
+++ b/src/emu/machine/8255ppi.c
@@ -0,0 +1,589 @@
+/*********************************************************************
+
+ 8255ppi.c
+
+ Intel 8255 PPI I/O chip
+
+
+ NOTE: When port is input, then data present on the ports
+ outputs is 0xff
+
+ The 8255 PPI has three basic modes:
+
+ Mode 0: Basic Input/Output
+ Mode 1: Strobed Input/Output
+ Mode 2: Strobed Bi-directional Bus
+
+ Control Word:
+
+ bit 7 - Mode set flag (1=active)
+ bit 6-5 - Group A Mode selection
+ 00 - Mode 0
+ 01 - Mode 1
+ 1x - Mode 2
+ bit 4 - Port A direction (1=input 0=output)
+ bit 3 - Port C upper direction (1=input 0=output)
+ bit 2 - Group B Mode selection
+ 0 - Mode 0
+ 1 - Mode 1
+ bit 1 - Port B direction (1=input 0=output)
+ bit 0 - Port C lower direction (1=input 0=output)
+
+ Port A and Port C upper are in group A, and Port B and Port C lower
+ are in group B
+
+
+ Mode 0: Basic Input/Output
+ In Mode 0, each of the ports (A, B and C) operate as independent
+ ports for whom direction can be set independently.
+
+ Port C Usage In Mode 0:
+
+ bits 7-4 Input/Output A (direction specified by ctrl bit 3)
+ bits 3-0 Input/Output B (direction specified by ctrl bit 0)
+
+ Mode 1: Strobed Input/Output
+ In Mode 1, Port A and Port B use their resepective parts of Port C to
+ either generate or accept handshaking signals. The STB (strobe) input
+ "loads" data into the port, and the IBF (input buffer full) output is
+ then asserted, and the INTR (interrupt request) output is triggered if
+ interrupts are enabled. Bits 7-6 of Port C remain usable as
+ conventional IO.
+
+ Group A Port C Usage In Mode 1:
+
+ bits 7-6 Input/Output (direction specified by ctrl bit 3)
+ bit 5 IBFa (input buffer full A) output
+ bit 4 !STBa (strobe A) input
+ bit 3 INTRa (interrupt request A) output
+
+ Group B Port C Usage In Mode 1:
+
+ bit 2 !STBb (strobe B) input
+ bit 1 IBFb (input buffer full B) output
+ bit 0 INTRb (interrupt request B) output
+
+
+ Mode 2: Strobed Bi-directional Bus
+ Mode 2 is used to implement a two way handshaking bus.
+
+ When data is written to port A, the OBF (output buffer full) output
+ will be asserted by the PPI. However, port A will not be asserted
+ unless the ACK input is asserted, otherwise port A will be high
+ impedence.
+
+ The STB input and IBF output behaves similar to how it does under mode
+ 1. Bits 2-0 of Port C remain usable as conventional IO.
+
+ Port C Usage In Mode 2:
+
+ bit 7 !OBFa (output buffer full A) output
+ bit 6 !ACKa (acknowledge A) input
+ bit 5 IBFa (interrupt buffer full A) output
+ bit 4 !STBa (strobe A) input
+ bit 3 INTRa (interrupt A) output
+ bit 2-0 Reserved by Group B
+
+ KT 10/01/2000 - Added bit set/reset feature for control port
+ - Added more accurate port i/o data handling
+ - Added output reset when control mode is programmed
+
+*********************************************************************/
+
+#include "driver.h"
+#include "8255ppi.h"
+#include "memconv.h"
+
+
+static int num;
+
+typedef struct
+{
+ read8_handler port_read[3];
+ write8_handler port_write[3];
+
+ /* mode flags */
+ UINT8 groupA_mode;
+ UINT8 groupB_mode;
+ UINT8 portA_dir;
+ UINT8 portB_dir;
+ UINT8 portCH_dir;
+ UINT8 portCL_dir;
+
+ /* handshake signals (1=asserted; 0=non-asserted) */
+ UINT8 obf_a;
+ UINT8 obf_b;
+ UINT8 ibf_a;
+ UINT8 ibf_b;
+ UINT8 inte_a;
+ UINT8 inte_b;
+
+ UINT8 in_mask[3]; /* input mask */
+ UINT8 out_mask[3]; /* output mask */
+ UINT8 read[3]; /* data read from ports */
+ UINT8 latch[3]; /* data written to ports */
+ UINT8 output[3]; /* actual output data */
+} ppi8255;
+
+static ppi8255 chips[MAX_8255];
+
+static void set_mode(int which, int data, int call_handlers);
+static void ppi8255_write_port(ppi8255 *chip, int port);
+
+
+void ppi8255_init( const ppi8255_interface *intfce )
+{
+ int i;
+
+ num = intfce->num;
+
+ for (i = 0; i < num; i++)
+ {
+ ppi8255 *chip = &chips[i];
+
+ memset(chip, 0, sizeof(*chip));
+
+ chip->port_read[0] = intfce->portAread[i];
+ chip->port_read[1] = intfce->portBread[i];
+ chip->port_read[2] = intfce->portCread[i];
+ chip->port_write[0] = intfce->portAwrite[i];
+ chip->port_write[1] = intfce->portBwrite[i];
+ chip->port_write[2] = intfce->portCwrite[i];
+
+ set_mode(i, 0x1b, 0); /* Mode 0, all ports set to input */
+
+ state_save_register_item("ppi8255", i, chip->groupA_mode);
+ state_save_register_item("ppi8255", i, chip->groupB_mode);
+ state_save_register_item("ppi8255", i, chip->portA_dir);
+ state_save_register_item("ppi8255", i, chip->portB_dir);
+ state_save_register_item("ppi8255", i, chip->portCH_dir);
+ state_save_register_item("ppi8255", i, chip->portCL_dir);
+ state_save_register_item("ppi8255", i, chip->obf_a);
+ state_save_register_item("ppi8255", i, chip->obf_b);
+ state_save_register_item("ppi8255", i, chip->ibf_a);
+ state_save_register_item("ppi8255", i, chip->ibf_b);
+ state_save_register_item("ppi8255", i, chip->inte_a);
+ state_save_register_item("ppi8255", i, chip->inte_b);
+ state_save_register_item_array("ppi8255", i, chip->in_mask);
+ state_save_register_item_array("ppi8255", i, chip->out_mask);
+ state_save_register_item_array("ppi8255", i, chip->read);
+ state_save_register_item_array("ppi8255", i, chip->latch);
+ }
+}
+
+
+
+static void ppi8255_get_handshake_signals(ppi8255 *chip, int is_read, UINT8 *result)
+{
+ UINT8 handshake = 0x00;
+ UINT8 mask = 0x00;
+
+ /* group A */
+ if (chip->groupA_mode == 1)
+ {
+ if (chip->portA_dir)
+ {
+ handshake |= chip->ibf_a ? 0x20 : 0x00;
+ handshake |= (chip->ibf_a && chip->inte_a) ? 0x08 : 0x00;
+ mask |= 0x28;
+ }
+ else
+ {
+ handshake |= chip->obf_a ? 0x00 : 0x80;
+ handshake |= (chip->obf_a && chip->inte_a) ? 0x08 : 0x00;
+ mask |= 0x88;
+ }
+ }
+ else if (chip->groupA_mode == 2)
+ {
+ handshake |= chip->inte_a ? 0x08 : 0x00;
+ handshake |= chip->obf_a ? 0x00 : 0x80;
+ handshake |= chip->ibf_a ? 0x20 : 0x00;
+ mask |= 0xA8;
+ }
+
+ /* group B */
+ if (chip->groupB_mode == 1)
+ {
+ if (chip->portA_dir)
+ {
+ handshake |= chip->ibf_b ? 0x02 : 0x00;
+ handshake |= (chip->ibf_b && chip->inte_b) ? 0x01 : 0x00;
+ mask |= 0x03;
+ }
+ else
+ {
+ handshake |= chip->obf_b ? 0x00 : 0x02;
+ handshake |= (chip->obf_b && chip->inte_b) ? 0x01 : 0x00;
+ mask |= 0x03;
+ }
+ }
+
+ *result &= ~mask;
+ *result |= handshake & mask;
+}
+
+
+
+static void ppi8255_input(ppi8255 *chip, int port, UINT8 data)
+{
+ int changed = 0;
+
+ chip->read[port] = data;
+
+ /* port C is special */
+ if (port == 2)
+ {
+ if (((chip->groupA_mode == 1) && (chip->portA_dir == 0)) || (chip->groupA_mode == 2))
+ {
+ /* is !ACKA asserted? */
+ if (chip->obf_a && !(data & 0x40))
+ {
+ chip->obf_a = 0;
+ changed = 1;
+ }
+ }
+
+ if ((chip->groupB_mode == 1) && (chip->portB_dir == 0))
+ {
+ /* is !ACKB asserted? */
+ if (chip->obf_b && !(data & 0x04))
+ {
+ chip->obf_b = 0;
+ changed = 1;
+ }
+ }
+
+ if (changed)
+ ppi8255_write_port(chip, 2);
+ }
+}
+
+
+
+static UINT8 ppi8255_read_port(ppi8255 *chip, int port)
+{
+ UINT8 result = 0x00;
+
+ if (chip->in_mask[port])
+ {
+ if (chip->port_read[port])
+ ppi8255_input(chip, port, chip->port_read[port](0));
+
+ result |= chip->read[port] & chip->in_mask[port];
+ }
+ result |= chip->latch[port] & chip->out_mask[port];
+
+ /* read special port 2 signals */
+ if (port == 2)
+ ppi8255_get_handshake_signals(chip, 1, &result);
+
+ return result;
+}
+
+
+
+UINT8 ppi8255_r(int which, offs_t offset)
+{
+ ppi8255 *chip = &chips[which];
+ UINT8 result = 0;
+
+ /* some bounds checking */
+ if (which > num)
+ {
+ logerror("Attempting to access an unmapped 8255 chip. PC: %04X\n", activecpu_get_pc());
+ return 0xff;
+ }
+
+ offset %= 4;
+
+ switch(offset)
+ {
+ case 0: /* Port A read */
+ case 1: /* Port B read */
+ case 2: /* Port C read */
+ result = ppi8255_read_port(chip, offset);
+ break;
+
+ case 3: /* Control word */
+ result = 0xFF;
+ break;
+ }
+
+ return result;
+}
+
+
+
+static void ppi8255_write_port(ppi8255 *chip, int port)
+{
+ UINT8 write_data;
+
+ write_data = chip->latch[port] & chip->out_mask[port];
+ write_data |= 0xFF & ~chip->out_mask[port];
+
+ /* write out special port 2 signals */
+ if (port == 2)
+ ppi8255_get_handshake_signals(chip, 0, &write_data);
+
+ chip->output[port] = write_data;
+ if (chip->port_write[port])
+ chip->port_write[port](0, write_data);
+}
+
+
+
+void ppi8255_w(int which, offs_t offset, UINT8 data)
+{
+ ppi8255 *chip = &chips[which];
+
+ /* Some bounds checking */
+ if (which > num)
+ {
+ logerror("Attempting to access an unmapped 8255 chip. PC: %04X\n", activecpu_get_pc());
+ return;
+ }
+
+ offset %= 4;
+
+ switch( offset )
+ {
+ case 0: /* Port A write */
+ case 1: /* Port B write */
+ case 2: /* Port C write */
+ chip->latch[offset] = data;
+ ppi8255_write_port(chip, offset);
+
+ switch(offset)
+ {
+ case 0:
+ if (!chip->portA_dir && (chip->groupA_mode != 0))
+ {
+ chip->obf_a = 1;
+ ppi8255_write_port(chip, 2);
+ }
+ break;
+
+ case 1:
+ if (!chip->portB_dir && (chip->groupB_mode != 0))
+ {
+ chip->obf_b = 1;
+ ppi8255_write_port(chip, 2);
+ }
+ break;
+ }
+ break;
+
+ case 3: /* Control word */
+ if (data & 0x80)
+ {
+ set_mode(which, data & 0x7f, 1);
+ }
+ else
+ {
+ /* bit set/reset */
+ int bit;
+
+ bit = (data >> 1) & 0x07;
+
+ if (data & 1)
+ chip->latch[2] |= (1<<bit); /* set bit */
+ else
+ chip->latch[2] &= ~(1<<bit); /* reset bit */
+
+ ppi8255_write_port(chip, 2);
+ }
+ break;
+ }
+}
+
+#ifdef MESS
+UINT8 ppi8255_peek( int which, offs_t offset )
+{
+ ppi8255 *chip;
+
+
+ /* Some bounds checking */
+ if (which > num)
+ {
+ logerror("Attempting to access an unmapped 8255 chip. PC: %04X\n", activecpu_get_pc());
+ return 0xff;
+ }
+
+ chip = &chips[which];
+
+
+ if (offset > 2)
+ {
+ logerror("Attempting to access an invalid 8255 port. PC: %04X\n", activecpu_get_pc());
+ return 0xff;
+ }
+
+
+ chip = &chips[which];
+
+ return chip->latch[offset];
+}
+#endif
+
+
+void ppi8255_set_portAread(int which, read8_handler portAread)
+{
+ chips[which].port_read[0] = portAread;
+}
+
+void ppi8255_set_portBread(int which, read8_handler portBread)
+{
+ chips[which].port_read[1] = portBread;
+}
+
+void ppi8255_set_portCread(int which, read8_handler portCread)
+{
+ chips[which].port_read[2] = portCread;
+}
+
+
+void ppi8255_set_portAwrite(int which, write8_handler portAwrite)
+{
+ chips[which].port_write[0] = portAwrite;
+}
+
+void ppi8255_set_portBwrite(int which, write8_handler portBwrite)
+{
+ chips[which].port_write[1] = portBwrite;
+}
+
+void ppi8255_set_portCwrite(int which, write8_handler portCwrite)
+{
+ chips[which].port_write[2] = portCwrite;
+}
+
+
+static void set_mode(int which, int data, int call_handlers)
+{
+ ppi8255 *chip = &chips[which];
+ int i;
+
+ /* parse out mode */
+ chip->groupA_mode = (data >> 5) & 3;
+ chip->groupB_mode = (data >> 2) & 1;
+ chip->portA_dir = (data >> 4) & 1;
+ chip->portB_dir = (data >> 1) & 1;
+ chip->portCH_dir = (data >> 3) & 1;
+ chip->portCL_dir = (data >> 0) & 1;
+
+ /* normalize groupA_mode */
+ if (chip->groupA_mode == 3)
+ chip->groupA_mode = 2;
+
+ /* Port A direction */
+ if (chip->portA_dir)
+ chip->in_mask[0] = 0xFF, chip->out_mask[0] = 0x00; /* input */
+ else
+ chip->in_mask[0] = 0x00, chip->out_mask[0] = 0xFF; /* output */
+
+ /* Port B direction */
+ if (chip->portB_dir)
+ chip->in_mask[1] = 0xFF, chip->out_mask[1] = 0x00; /* input */
+ else
+ chip->in_mask[1] = 0x00, chip->out_mask[1] = 0xFF; /* output */
+
+ /* Port C upper direction */
+ if (chip->portCH_dir)
+ chip->in_mask[2] = 0xF0, chip->out_mask[2] = 0x00; /* input */
+ else
+ chip->in_mask[2] = 0x00, chip->out_mask[2] = 0xF0; /* output */
+
+ /* Port C lower direction */
+ if (chip->portCL_dir)
+ chip->in_mask[2] |= 0x0F; /* input */
+ else
+ chip->out_mask[2] |= 0x0F; /* output */
+
+ /* now depending on the group modes, certain Port C lines may be replaced
+ * with varying control signals */
+ switch(chip->groupA_mode)
+ {
+ case 0: /* Group A mode 0 */
+ /* no changes */
+ break;
+
+ case 1: /* Group A mode 1 */
+ /* bits 5-3 are reserved by Group A mode 1 */
+ chip->in_mask[2] &= ~0x38;
+ chip->out_mask[2] &= ~0x38;
+ break;
+
+ case 2: /* Group A mode 2 */
+ /* bits 7-3 are reserved by Group A mode 2 */
+ chip->in_mask[2] &= ~0xF8;
+ chip->out_mask[2] &= ~0xF8;
+ break;
+ }
+
+ switch(chip->groupB_mode)
+ {
+ case 0: /* Group B mode 0 */
+ /* no changes */
+ break;
+
+ case 1: /* Group B mode 1 */
+ /* bits 2-0 are reserved by Group B mode 1 */
+ chip->in_mask[2] &= ~0x07;
+ chip->out_mask[2] &= ~0x07;
+ break;
+ }
+
+ /* KT: 25-Dec-99 - 8255 resets latches when mode set */
+ chip->latch[0] = chip->latch[1] = chip->latch[2] = 0;
+
+ if (call_handlers)
+ {
+ for (i = 0; i < 3; i++)
+ ppi8255_write_port(chip, i);
+ }
+}
+
+
+void ppi8255_set_portA( int which, UINT8 data ) { ppi8255_input(&chips[which], 0, data); }
+void ppi8255_set_portB( int which, UINT8 data ) { ppi8255_input(&chips[which], 1, data); }
+void ppi8255_set_portC( int which, UINT8 data ) { ppi8255_input(&chips[which], 2, data); }
+
+UINT8 ppi8255_get_portA( int which ) { return chips[which].output[0]; }
+UINT8 ppi8255_get_portB( int which ) { return chips[which].output[1]; }
+UINT8 ppi8255_get_portC( int which ) { return chips[which].output[2]; }
+
+/* Helpers */
+READ8_HANDLER( ppi8255_0_r ) { return ppi8255_r( 0, offset ); }
+READ8_HANDLER( ppi8255_1_r ) { return ppi8255_r( 1, offset ); }
+READ8_HANDLER( ppi8255_2_r ) { return ppi8255_r( 2, offset ); }
+READ8_HANDLER( ppi8255_3_r ) { return ppi8255_r( 3, offset ); }
+READ8_HANDLER( ppi8255_4_r ) { return ppi8255_r( 4, offset ); }
+READ8_HANDLER( ppi8255_5_r ) { return ppi8255_r( 5, offset ); }
+READ8_HANDLER( ppi8255_6_r ) { return ppi8255_r( 6, offset ); }
+READ8_HANDLER( ppi8255_7_r ) { return ppi8255_r( 7, offset ); }
+WRITE8_HANDLER( ppi8255_0_w ) { ppi8255_w( 0, offset, data ); }
+WRITE8_HANDLER( ppi8255_1_w ) { ppi8255_w( 1, offset, data ); }
+WRITE8_HANDLER( ppi8255_2_w ) { ppi8255_w( 2, offset, data ); }
+WRITE8_HANDLER( ppi8255_3_w ) { ppi8255_w( 3, offset, data ); }
+WRITE8_HANDLER( ppi8255_4_w ) { ppi8255_w( 4, offset, data ); }
+WRITE8_HANDLER( ppi8255_5_w ) { ppi8255_w( 5, offset, data ); }
+WRITE8_HANDLER( ppi8255_6_w ) { ppi8255_w( 6, offset, data ); }
+WRITE8_HANDLER( ppi8255_7_w ) { ppi8255_w( 7, offset, data ); }
+
+READ16_HANDLER( ppi8255_16le_0_r ) { return read16le_with_read8_handler(ppi8255_0_r, offset, mem_mask); }
+READ16_HANDLER( ppi8255_16le_1_r ) { return read16le_with_read8_handler(ppi8255_1_r, offset, mem_mask); }
+READ16_HANDLER( ppi8255_16le_2_r ) { return read16le_with_read8_handler(ppi8255_2_r, offset, mem_mask); }
+READ16_HANDLER( ppi8255_16le_3_r ) { return read16le_with_read8_handler(ppi8255_3_r, offset, mem_mask); }
+READ16_HANDLER( ppi8255_16le_4_r ) { return read16le_with_read8_handler(ppi8255_4_r, offset, mem_mask); }
+READ16_HANDLER( ppi8255_16le_5_r ) { return read16le_with_read8_handler(ppi8255_5_r, offset, mem_mask); }
+READ16_HANDLER( ppi8255_16le_6_r ) { return read16le_with_read8_handler(ppi8255_6_r, offset, mem_mask); }
+READ16_HANDLER( ppi8255_16le_7_r ) { return read16le_with_read8_handler(ppi8255_7_r, offset, mem_mask); }
+WRITE16_HANDLER( ppi8255_16le_0_w ) { write16le_with_write8_handler(ppi8255_0_w, offset, data, mem_mask); }
+WRITE16_HANDLER( ppi8255_16le_1_w ) { write16le_with_write8_handler(ppi8255_1_w, offset, data, mem_mask); }
+WRITE16_HANDLER( ppi8255_16le_2_w ) { write16le_with_write8_handler(ppi8255_2_w, offset, data, mem_mask); }
+WRITE16_HANDLER( ppi8255_16le_3_w ) { write16le_with_write8_handler(ppi8255_3_w, offset, data, mem_mask); }
+WRITE16_HANDLER( ppi8255_16le_4_w ) { write16le_with_write8_handler(ppi8255_4_w, offset, data, mem_mask); }
+WRITE16_HANDLER( ppi8255_16le_5_w ) { write16le_with_write8_handler(ppi8255_5_w, offset, data, mem_mask); }
+WRITE16_HANDLER( ppi8255_16le_6_w ) { write16le_with_write8_handler(ppi8255_6_w, offset, data, mem_mask); }
+WRITE16_HANDLER( ppi8255_16le_7_w ) { write16le_with_write8_handler(ppi8255_7_w, offset, data, mem_mask); }
diff --git a/src/emu/machine/8255ppi.h b/src/emu/machine/8255ppi.h
new file mode 100644
index 00000000000..f735fbc32d8
--- /dev/null
+++ b/src/emu/machine/8255ppi.h
@@ -0,0 +1,89 @@
+/*********************************************************************
+
+ 8255ppi.h
+
+ Intel 8255 PPI I/O chip
+
+*********************************************************************/
+
+#ifndef _8255PPI_H_
+#define _8255PPI_H_
+
+#define MAX_8255 8
+
+typedef struct
+{
+ int num; /* number of PPIs to emulate */
+ read8_handler portAread[MAX_8255];
+ read8_handler portBread[MAX_8255];
+ read8_handler portCread[MAX_8255];
+ write8_handler portAwrite[MAX_8255];
+ write8_handler portBwrite[MAX_8255];
+ write8_handler portCwrite[MAX_8255];
+} ppi8255_interface;
+
+
+/* Init */
+void ppi8255_init( const ppi8255_interface *intfce);
+
+/* Read/Write */
+UINT8 ppi8255_r ( int which, offs_t offset );
+void ppi8255_w( int which, offs_t offset, UINT8 data );
+
+void ppi8255_set_portAread( int which, read8_handler portAread);
+void ppi8255_set_portBread( int which, read8_handler portBread);
+void ppi8255_set_portCread( int which, read8_handler portCread);
+
+void ppi8255_set_portAwrite( int which, write8_handler portAwrite);
+void ppi8255_set_portBwrite( int which, write8_handler portBwrite);
+void ppi8255_set_portCwrite( int which, write8_handler portCwrite);
+
+void ppi8255_set_portA( int which, UINT8 data );
+void ppi8255_set_portB( int which, UINT8 data );
+void ppi8255_set_portC( int which, UINT8 data );
+
+UINT8 ppi8255_get_portA( int which );
+UINT8 ppi8255_get_portB( int which );
+UINT8 ppi8255_get_portC( int which );
+
+/* Helpers */
+READ8_HANDLER( ppi8255_0_r );
+READ8_HANDLER( ppi8255_1_r );
+READ8_HANDLER( ppi8255_2_r );
+READ8_HANDLER( ppi8255_3_r );
+READ8_HANDLER( ppi8255_4_r );
+READ8_HANDLER( ppi8255_5_r );
+READ8_HANDLER( ppi8255_6_r );
+READ8_HANDLER( ppi8255_7_r );
+WRITE8_HANDLER( ppi8255_0_w );
+WRITE8_HANDLER( ppi8255_1_w );
+WRITE8_HANDLER( ppi8255_2_w );
+WRITE8_HANDLER( ppi8255_3_w );
+WRITE8_HANDLER( ppi8255_4_w );
+WRITE8_HANDLER( ppi8255_5_w );
+WRITE8_HANDLER( ppi8255_6_w );
+WRITE8_HANDLER( ppi8255_7_w );
+
+READ16_HANDLER( ppi8255_16le_0_r );
+READ16_HANDLER( ppi8255_16le_1_r );
+READ16_HANDLER( ppi8255_16le_2_r );
+READ16_HANDLER( ppi8255_16le_3_r );
+READ16_HANDLER( ppi8255_16le_4_r );
+READ16_HANDLER( ppi8255_16le_5_r );
+READ16_HANDLER( ppi8255_16le_6_r );
+READ16_HANDLER( ppi8255_16le_7_r );
+WRITE16_HANDLER( ppi8255_16le_0_w );
+WRITE16_HANDLER( ppi8255_16le_1_w );
+WRITE16_HANDLER( ppi8255_16le_2_w );
+WRITE16_HANDLER( ppi8255_16le_3_w );
+WRITE16_HANDLER( ppi8255_16le_4_w );
+WRITE16_HANDLER( ppi8255_16le_5_w );
+WRITE16_HANDLER( ppi8255_16le_6_w );
+WRITE16_HANDLER( ppi8255_16le_7_w );
+
+#ifdef MESS
+/* Peek at the ports */
+UINT8 ppi8255_peek( int which, offs_t offset );
+#endif
+
+#endif /* _8255PPI_H_ */
diff --git a/src/emu/machine/adc083x.c b/src/emu/machine/adc083x.c
new file mode 100644
index 00000000000..edb9ea9bdea
--- /dev/null
+++ b/src/emu/machine/adc083x.c
@@ -0,0 +1,465 @@
+/*
+ * ADC0831/ADC0832/ADC0834/ADC0838
+ *
+ * 8-Bit Serial I/O A/D Converters with Muliplexer Options
+ *
+ */
+
+#include <stdarg.h>
+#include "driver.h"
+#include "machine/adc083x.h"
+
+#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 adc083x_chip
+{
+ int type;
+ double (*input_callback)(int input);
+ INT32 CS;
+ INT32 CLK;
+ INT32 DI;
+ INT32 SE;
+ INT32 SARS;
+ INT32 DO;
+ INT32 SGL;
+ INT32 ODD;
+ INT32 SEL1;
+ INT32 SEL0;
+ INT32 state;
+ INT32 bit;
+ INT32 output;
+ INT32 mux_bits;
+};
+
+#define STATE_IDLE ( 0 )
+#define STATE_WAIT_FOR_START ( 1 )
+#define STATE_SHIFT_MUX ( 2 )
+#define STATE_MUX_SETTLE ( 3 )
+#define STATE_OUTPUT_MSB_FIRST ( 4 )
+#define STATE_WAIT_FOR_SE ( 5 )
+#define STATE_OUTPUT_LSB_FIRST ( 6 )
+#define STATE_FINISHED ( 7 )
+
+static struct adc083x_chip adc083x[ MAX_ADC083X_CHIPS ];
+
+void adc083x_init( int chip, int type, double (*input_callback)(int input) )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_init( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ c->type = type;
+ c->input_callback = input_callback;
+ c->CS = 0;
+ c->CLK = 0;
+ c->DI = 0;
+ c->SE = 0;
+ if( c->type == ADC0834 || c->type == ADC0838 )
+ {
+ c->SARS = 1;
+ }
+ else
+ {
+ c->SARS = 0;
+ }
+ c->DO = 1;
+ c->SGL = 0;
+ c->ODD = 0;
+ c->SEL1 = 0;
+ c->SEL0 = 0;
+ c->state = STATE_IDLE;
+ c->bit = 0;
+ c->output = 0;
+
+ switch( c->type )
+ {
+ case ADC0831:
+ c->mux_bits = 0;
+ break;
+ case ADC0832:
+ c->mux_bits = 2;
+ break;
+ case ADC0834:
+ c->mux_bits = 3;
+ break;
+ case ADC0838:
+ c->mux_bits = 4;
+ break;
+ }
+
+ state_save_register_item( "adc083x", chip, c->CS );
+ state_save_register_item( "adc083x", chip, c->CLK );
+ state_save_register_item( "adc083x", chip, c->DI );
+ state_save_register_item( "adc083x", chip, c->SE );
+ state_save_register_item( "adc083x", chip, c->SARS );
+ state_save_register_item( "adc083x", chip, c->DO );
+ state_save_register_item( "adc083x", chip, c->SGL );
+ state_save_register_item( "adc083x", chip, c->ODD );
+ state_save_register_item( "adc083x", chip, c->SEL1 );
+ state_save_register_item( "adc083x", chip, c->SEL0 );
+ state_save_register_item( "adc083x", chip, c->state );
+ state_save_register_item( "adc083x", chip, c->bit );
+ state_save_register_item( "adc083x", chip, c->output );
+}
+
+void adc083x_cs_write( int chip, int cs )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_cs_write( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ if( c->CS != cs )
+ {
+ verboselog( 2, "adc083x_cs_write( %d, %d )\n", chip, cs );
+ }
+
+ if( c->CS == 0 && cs != 0 )
+ {
+ c->state = STATE_IDLE;
+ if( c->type == ADC0834 || c->type == ADC0838 )
+ {
+ c->SARS = 1;
+ }
+ c->DO = 1;
+ }
+ if( c->CS != 0 && cs == 0 )
+ {
+ if( c->type == ADC0831 )
+ {
+ c->state = STATE_MUX_SETTLE;
+ }
+ else
+ {
+ c->state = STATE_WAIT_FOR_START;
+ }
+ if( c->type == ADC0834 || c->type == ADC0838 )
+ {
+ c->SARS = 1;
+ }
+ c->DO = 1;
+ }
+
+ c->CS = cs;
+}
+
+static int adc083x_conversion( int chip )
+{
+ struct adc083x_chip *c = &adc083x[ chip ];
+ int result;
+ int positive_channel = ADC083X_AGND;
+ int negative_channel = ADC083X_AGND;
+ double positive = 0;
+ double negative = 0;
+ double gnd = c->input_callback( ADC083X_AGND );
+ double vref = c->input_callback( ADC083X_VREF );
+
+ switch( c->type )
+ {
+ case ADC0831:
+ positive_channel = ADC083X_CH0;
+ negative_channel = ADC083X_CH1;
+ break;
+ case ADC0832:
+ positive_channel = ADC083X_CH0 + c->ODD;
+ if( c->SGL == 0 )
+ {
+ negative_channel = positive_channel ^ 1;
+ }
+ else
+ {
+ negative_channel = ADC083X_AGND;
+ }
+ break;
+ case ADC0834:
+ positive_channel = ADC083X_CH0 + c->ODD + ( c->SEL1 * 2 );
+ if( c->SGL == 0 )
+ {
+ negative_channel = positive_channel ^ 1;
+ }
+ else
+ {
+ negative_channel = ADC083X_AGND;
+ }
+ break;
+ case ADC0838:
+ positive_channel = ADC083X_CH0 + c->ODD + ( c->SEL0 * 2 ) + ( c->SEL1 * 4 );
+ if( c->SGL == 0 )
+ {
+ negative_channel = positive_channel ^ 1;
+ }
+ else
+ {
+ negative_channel = ADC083X_COM;
+ }
+ break;
+ }
+
+ if( positive_channel != ADC083X_AGND )
+ {
+ positive = c->input_callback( positive_channel ) - gnd;
+ }
+ if( negative_channel != ADC083X_AGND )
+ {
+ negative = c->input_callback( negative_channel ) - gnd;
+ }
+
+ result = (int)( ( ( positive - negative ) * 255 ) / vref );
+ if( result < 0 )
+ {
+ result = 0;
+ }
+ else if( result > 255 )
+ {
+ result = 255;
+ }
+
+ return result;
+}
+
+void adc083x_clk_write( int chip, int clk )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_clk_write( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ if( c->CLK != clk )
+ {
+ verboselog( 2, "adc083x_clk_write( %d, %d )\n", chip, clk );
+ }
+
+ if( c->CS == 0 )
+ {
+ if( c->CLK == 0 && clk != 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_WAIT_FOR_START:
+ if( c->DI != 0 )
+ {
+ verboselog( 1, "adc083x %d got start bit\n", chip );
+ c->state = STATE_SHIFT_MUX;
+ c->SARS = 0;
+ c->SGL = 0;
+ c->ODD = 0;
+ c->SEL1 = 0;
+ c->SEL0 = 0;
+ c->bit = 0;
+ }
+ else
+ {
+ verboselog( 1, "adc083x %d not start bit\n", chip );
+ }
+ break;
+ case STATE_SHIFT_MUX:
+ switch( c->bit )
+ {
+ case 0:
+ if( c->DI != 0 )
+ {
+ c->SGL = 1;
+ }
+ verboselog( 1, "adc083x %d SGL <- %d\n", chip, c->SGL );
+ break;
+ case 1:
+ if( c->DI != 0 )
+ {
+ c->ODD = 1;
+ }
+ verboselog( 1, "adc083x %d ODD <- %d\n", chip, c->ODD );
+ break;
+ case 2:
+ if( c->DI != 0 )
+ {
+ c->SEL1 = 1;
+ }
+ verboselog( 1, "adc083x %d SEL1 <- %d\n", chip, c->SEL1 );
+ break;
+ case 3:
+ if( c->DI != 0 )
+ {
+ c->SEL0 = 1;
+ }
+ verboselog( 1, "adc083x %d SEL0 <- %d\n", chip, c->SEL0 );
+ break;
+ }
+ c->bit++;
+ if( c->bit == c->mux_bits )
+ {
+ c->state = STATE_MUX_SETTLE;
+ }
+ break;
+ case STATE_WAIT_FOR_SE:
+ c->SARS = 0;
+ if( c->type == ADC0838 && c->SE != 0 )
+ {
+ verboselog( 1, "adc083x %d not SE\n", chip );
+ }
+ else
+ {
+ verboselog( 1, "adc083x %d got SE\n", chip );
+ c->state = STATE_OUTPUT_LSB_FIRST;
+ c->bit = 1;
+ }
+ break;
+ }
+ }
+ if( c->CLK != 0 && clk == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_MUX_SETTLE:
+ verboselog( 1, "adc083x %d mux settle\n", chip );
+ c->output = adc083x_conversion( chip );
+ c->state = STATE_OUTPUT_MSB_FIRST;
+ c->bit = 7;
+ if( c->type == ADC0834 || c->type == ADC0838 )
+ {
+ c->SARS = 1;
+ }
+ c->DO = 0;
+ break;
+ case STATE_OUTPUT_MSB_FIRST:
+ c->DO = ( c->output >> c->bit ) & 1;
+ verboselog( 1, "adc083x %d msb %d -> %d\n", chip, c->bit, c->DO );
+ c->bit--;
+ if( c->bit < 0 )
+ {
+ if( c->type == ADC0831 )
+ {
+ c->state = STATE_FINISHED;
+ }
+ else
+ {
+ c->state = STATE_WAIT_FOR_SE;
+ }
+ }
+ break;
+ case STATE_OUTPUT_LSB_FIRST:
+ c->DO = ( c->output >> c->bit ) & 1;
+ verboselog( 1, "adc083x %d lsb %d -> %d\n", chip, c->bit, c->DO );
+ c->bit++;
+ if( c->bit == 8 )
+ {
+ c->state = STATE_FINISHED;
+ }
+ break;
+ case STATE_FINISHED:
+ c->state = STATE_IDLE;
+ c->DO = 0;
+ break;
+ }
+ }
+ }
+
+ c->CLK = clk;
+}
+
+void adc083x_di_write( int chip, int di )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_di_write( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ if( c->DI != di )
+ {
+ verboselog( 2, "adc083x_di_write( %d, %d )\n", chip, di );
+ }
+
+ c->DI = di;
+}
+
+void adc083x_se_write( int chip, int se )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_se_write( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ if( c->SE != se )
+ {
+ verboselog( 2, "adc083x_se_write( %d, %d )\n", chip, se );
+ }
+
+ c->SE = se;
+}
+
+int adc083x_sars_read( int chip )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_sars_read( %d ) chip %d out of range\n", chip );
+ return 0;
+ }
+
+ c = &adc083x[ chip ];
+
+ verboselog( 1, "adc083x_sars_read( %d ) %d\n", chip, c->SARS );
+ return c->SARS;
+}
+
+int adc083x_do_read( int chip )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_do_read( %d ) chip %d out of range\n", chip );
+ return 0;
+ }
+
+ c = &adc083x[ chip ];
+
+ verboselog( 1, "adc083x_do_read( %d ) %d\n", chip, c->DO );
+ return c->DO;
+}
diff --git a/src/emu/machine/adc083x.h b/src/emu/machine/adc083x.h
new file mode 100644
index 00000000000..4d5bc6fe5ca
--- /dev/null
+++ b/src/emu/machine/adc083x.h
@@ -0,0 +1,38 @@
+/*
+ * ADC0831/ADC0832/ADC0834/ADC0838
+ *
+ * 8-Bit Serial I/O A/D Converters with Muliplexer Options
+ *
+ */
+
+#if !defined( ADC083X_H )
+#define ADC083X_H ( 1 )
+
+#define MAX_ADC083X_CHIPS ( 1 )
+
+#define ADC083X_CH0 ( 0 )
+#define ADC083X_CH1 ( 1 )
+#define ADC083X_CH2 ( 2 )
+#define ADC083X_CH3 ( 3 )
+#define ADC083X_CH4 ( 4 )
+#define ADC083X_CH5 ( 5 )
+#define ADC083X_CH6 ( 6 )
+#define ADC083X_CH7 ( 7 )
+#define ADC083X_COM ( 8 )
+#define ADC083X_AGND ( 9 )
+#define ADC083X_VREF ( 10 )
+
+#define ADC0831 ( 0 )
+#define ADC0832 ( 1 )
+#define ADC0834 ( 2 )
+#define ADC0838 ( 3 )
+
+void adc083x_init( int chip, int type, double (*input_callback)( int input ) );
+extern void adc083x_cs_write( int chip, int cs );
+extern void adc083x_clk_write( int chip, int clk );
+extern void adc083x_di_write( int chip, int di );
+extern void adc083x_se_write( int chip, int se );
+extern int adc083x_sars_read( int chip );
+extern int adc083x_do_read( int chip );
+
+#endif
diff --git a/src/emu/machine/adc1213x.c b/src/emu/machine/adc1213x.c
new file mode 100644
index 00000000000..eef2493b03a
--- /dev/null
+++ b/src/emu/machine/adc1213x.c
@@ -0,0 +1,251 @@
+/*
+ ADC12130/ADC12132/ADC12138
+
+ Self-calibrating 12-bit Plus Sign Serial I/O A/D Converters with MUX and Sample/Hold
+
+ TODO:
+ - Only ADC12138 currently supported
+*/
+
+#include "driver.h"
+#include "adc1213x.h"
+
+#define MAX_ADC1213X_CHIPS 4
+
+typedef struct
+{
+ int cycle;
+ int data_out;
+ int data_in;
+ int conv_mode;
+ int auto_cal;
+ int auto_zero;
+ int acq_time;
+ int data_out_sign;
+ int mode;
+ int input_shift_reg;
+ int output_shift_reg;
+ int end_conv;
+
+ double (*input_callback)(int input);
+} ADC1213X;
+
+static ADC1213X adc1213x[MAX_ADC1213X_CHIPS];
+
+#define ADC1213X_CONV_MODE_12_MSB_FIRST 0
+#define ADC1213X_CONV_MODE_16_MSB_FIRST 1
+#define ADC1213X_CONV_MODE_12_LSB_FIRST 2
+#define ADC1213X_CONV_MODE_16_LSB_FIRST 3
+
+#define ADC1213X_ACQUISITION_TIME_6_CCLK 0
+#define ADC1213X_ACQUISITION_TIME_10_CCLK 1
+#define ADC1213X_ACQUISITION_TIME_18_CCLK 2
+#define ADC1213X_ACQUISITION_TIME_34_CCLK 3
+
+int adc1213x_do_r(int chip)
+{
+ //printf("ADC: DO\n");
+ return adc1213x[chip].data_out;
+}
+
+void adc1213x_di_w(int chip, int state)
+{
+ adc1213x[chip].data_in = state & 1;
+}
+
+static void adc1213x_convert(int chip, int channel, int bits16, int lsbfirst)
+{
+ int i;
+ int bits;
+ int input_value;
+ double input;
+
+ if (bits16)
+ fatalerror("ADC1213X: 16-bit mode not supported\n");
+
+ if (lsbfirst)
+ fatalerror("ADC1213X: LSB first not supported\n");
+
+ switch (channel)
+ {
+ case 0x8: // H L L L - CH0 (single-ended)
+ {
+ input = adc1213x[chip].input_callback(0);
+ break;
+ }
+ case 0xc: // H H L L - CH1 (single-ended)
+ {
+ input = adc1213x[chip].input_callback(1);
+ break;
+ }
+ case 0x9: // H L L H - CH2 (single-ended)
+ {
+ input = adc1213x[chip].input_callback(2);
+ break;
+ }
+ case 0xd: // H H L H - CH3 (single-ended)
+ {
+ input = adc1213x[chip].input_callback(3);
+ break;
+ }
+ case 0xa: // H L H L - CH4 (single-ended)
+ {
+ input = adc1213x[chip].input_callback(4);
+ break;
+ }
+ case 0xe: // H H H L - CH5 (single-ended)
+ {
+ input = adc1213x[chip].input_callback(5);
+ break;
+ }
+ case 0xb: // H L H H - CH6 (single-ended)
+ {
+ input = adc1213x[chip].input_callback(6);
+ break;
+ }
+ case 0xf: // H H H H - CH7 (single-ended)
+ {
+ input = adc1213x[chip].input_callback(7);
+ break;
+ }
+ default:
+ {
+ fatalerror("ADC1213X: unsupported channel %02X\n", channel);
+ }
+ }
+
+ input_value = (int)(input * 2047.0);
+
+ bits = 12;
+
+ // sign-extend if needed
+ if (adc1213x[chip].data_out_sign)
+ {
+ input_value = input_value | ((input_value & 0x800) << 1);
+ bits++;
+ }
+
+ adc1213x[chip].output_shift_reg = 0;
+
+ for (i=0; i < bits; i++)
+ {
+ if (input_value & (1 << ((bits-1) - i)))
+ {
+ adc1213x[chip].output_shift_reg |= (1 << i);
+ }
+ }
+
+ adc1213x[chip].data_out = adc1213x[chip].output_shift_reg & 1;
+ adc1213x[chip].output_shift_reg >>= 1;
+}
+
+void adc1213x_cs_w(int chip, int state)
+{
+ if (state)
+ {
+ //printf("ADC: CS\n");
+
+ if (adc1213x[chip].cycle >= 7)
+ {
+ int mode = adc1213x[chip].input_shift_reg >> (adc1213x[chip].cycle - 8);
+
+ switch (mode & 0xf)
+ {
+ case 0x0: // X X X X L L L L - 12 or 13 Bit MSB First conversion
+ {
+ adc1213x_convert(chip, (mode >> 4) & 0xf, 0, 0);
+ break;
+ }
+ case 0x1: // X X X X L L L H - 16 or 17 Bit MSB First conversion
+ {
+ adc1213x_convert(chip, (mode >> 4) & 0xf, 1, 0);
+ break;
+ }
+ case 0x4: // X X X X L H L L - 12 or 13 Bit LSB First conversion
+ {
+ adc1213x_convert(chip, (mode >> 4) & 0xf, 0, 1);
+ break;
+ }
+ case 0x5: // X X X X L H L H - 16 or 17 Bit LSB First conversion
+ {
+ adc1213x_convert(chip, (mode >> 4) & 0xf, 1, 1);
+ break;
+ }
+
+ default:
+ {
+ switch (mode)
+ {
+ case 0x08: // L L L L H L L L - Auto cal
+ {
+ adc1213x[chip].auto_cal = 1;
+ break;
+ }
+
+ case 0x0e: // L L L L H H H L - Acquisition time 6 CCLK cycles
+ {
+ adc1213x[chip].acq_time = ADC1213X_ACQUISITION_TIME_6_CCLK;
+ break;
+ }
+
+ case 0x8d: // H L L L H H L H - Data out with sign
+ {
+ adc1213x[chip].data_out_sign = 1;
+ break;
+ }
+
+ default:
+ {
+ fatalerror("ADC1213X: unknown config mode %02X\n", mode);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ adc1213x[chip].cycle = 0;
+ adc1213x[chip].input_shift_reg = 0;
+
+ adc1213x[chip].end_conv = 0;
+ }
+}
+
+void adc1213x_sclk_w(int chip, int state)
+{
+ if (state)
+ {
+ //printf("ADC: cycle %d, DI = %d\n", adc1213x[chip].cycle, adc1213x[chip].data_in);
+
+ adc1213x[chip].input_shift_reg <<= 1;
+ adc1213x[chip].input_shift_reg |= adc1213x[chip].data_in;
+
+ adc1213x[chip].data_out = adc1213x[chip].output_shift_reg & 1;
+ adc1213x[chip].output_shift_reg >>= 1;
+
+ adc1213x[chip].cycle++;
+ }
+}
+
+void adc1213x_conv_w(int chip, int state)
+{
+ adc1213x[chip].end_conv = 1;
+}
+
+int adc1213x_eoc_r(int chip)
+{
+ return adc1213x[chip].end_conv;
+}
+
+void adc1213x_init(int chip, double (*input_callback)( int input ))
+{
+ memset(&adc1213x[chip], 0, sizeof(ADC1213X));
+
+ adc1213x[chip].conv_mode = ADC1213X_CONV_MODE_12_MSB_FIRST;
+ adc1213x[chip].data_out_sign = 1;
+ adc1213x[chip].auto_cal = 0;
+ adc1213x[chip].auto_zero = 0;
+ adc1213x[chip].acq_time = ADC1213X_ACQUISITION_TIME_10_CCLK;
+
+ adc1213x[chip].input_callback = input_callback;
+}
diff --git a/src/emu/machine/adc1213x.h b/src/emu/machine/adc1213x.h
new file mode 100644
index 00000000000..1b02b3452e0
--- /dev/null
+++ b/src/emu/machine/adc1213x.h
@@ -0,0 +1,18 @@
+/*
+ ADC12130/ADC12132/ADC12138
+
+ Self-calibrating 12-bit Plus Sign Serial I/O A/D Converters with MUX and Sample/Hold
+*/
+
+#ifndef ADC1213X_H
+#define ADC1213X_H
+
+int adc1213x_do_r(int chip);
+void adc1213x_di_w(int chip, int state);
+void adc1213x_cs_w(int chip, int state);
+void adc1213x_sclk_w(int chip, int state);
+void adc1213x_conv_w(int chip, int state);
+int adc1213x_eoc_r(int chip);
+void adc1213x_init(int chip, double (*input_callback)( int input ));
+
+#endif
diff --git a/src/emu/machine/am53cf96.c b/src/emu/machine/am53cf96.c
new file mode 100644
index 00000000000..a902508eb89
--- /dev/null
+++ b/src/emu/machine/am53cf96.c
@@ -0,0 +1,279 @@
+/*
+ * am53cf96.c
+ *
+ * AMD/NCR/Symbios 53CF96 SCSI-2 controller.
+ * Qlogic FAS-236 and Emulex ESP-236 are equivalents
+ *
+ * References:
+ * AMD Am53CF96 manual
+ *
+ */
+
+#include "driver.h"
+#include "am53cf96.h"
+
+static UINT8 scsi_regs[32], fifo[16], fptr = 0, xfer_state, last_id;
+static struct AM53CF96interface *intf;
+
+static SCSIInstance *devices[8]; // SCSI IDs 0-7
+
+// 53CF96 register set
+enum
+{
+ REG_XFERCNTLOW = 0, // read = current xfer count lo byte, write = set xfer count lo byte
+ REG_XFERCNTMID, // read = current xfer count mid byte, write = set xfer count mid byte
+ REG_FIFO, // read/write = FIFO
+ REG_COMMAND, // read/write = command
+
+ REG_STATUS, // read = status, write = destination SCSI ID (4)
+ REG_IRQSTATE, // read = IRQ status, write = timeout (5)
+ REG_INTSTATE, // read = internal state, write = sync xfer period (6)
+ REG_FIFOSTATE, // read = FIFO status, write = sync offset
+ REG_CTRL1, // read/write = control 1
+ REG_CLOCKFCTR, // clock factor (write only)
+ REG_TESTMODE, // test mode (write only)
+ REG_CTRL2, // read/write = control 2
+ REG_CTRL3, // read/write = control 3
+ REG_CTRL4, // read/write = control 4
+ REG_XFERCNTHI, // read = current xfer count hi byte, write = set xfer count hi byte
+ REG_DATAALIGN // data alignment (write only)
+};
+
+READ32_HANDLER( am53cf96_r )
+{
+ int reg, shift, rv;
+ static const int states[] = { 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 0 };
+
+ reg = offset * 2;
+ if (mem_mask == 0xffffff00)
+ {
+ shift = 0;
+ }
+ else
+ {
+ reg++;
+ shift = 16;
+ }
+
+ if (reg == REG_STATUS)
+ {
+ scsi_regs[REG_STATUS] &= ~0x7;
+ scsi_regs[REG_STATUS] |= states[xfer_state];
+ if (xfer_state < 10)
+ {
+ xfer_state++;
+ }
+ }
+
+ rv = scsi_regs[reg]<<shift;
+
+ if (reg == REG_FIFO)
+ {
+// mame_printf_debug("53cf96: read FIFO PC=%x\n", activecpu_get_pc());
+ return 0;
+ }
+
+// logerror("53cf96: read reg %d = %x (PC=%x)\n", reg, rv>>shift, activecpu_get_pc());
+
+ if (reg == REG_IRQSTATE)
+ {
+ scsi_regs[REG_STATUS] &= ~0x80; // clear IRQ flag
+ }
+
+ return rv;
+}
+
+static TIMER_CALLBACK( am53cf96_irq )
+{
+ scsi_regs[REG_IRQSTATE] = 8; // indicate success
+ scsi_regs[REG_STATUS] |= 0x80; // indicate IRQ
+ intf->irq_callback();
+}
+
+WRITE32_HANDLER( am53cf96_w )
+{
+ int reg, val, dma;
+
+ reg = offset * 2;
+ val = data;
+ if (mem_mask == 0xffffff00)
+ {
+ }
+ else
+ {
+ reg++;
+ val >>= 16;
+ }
+ val &= 0xff;
+
+// logerror("53cf96: w %x to reg %d (ofs %02x data %08x mask %08x PC=%x)\n", val, reg, offset, data, mem_mask, activecpu_get_pc());
+
+ // if writing to the target ID, cache it off for later
+ if (reg == REG_STATUS)
+ {
+ last_id = val;
+ }
+
+ if (reg == REG_XFERCNTLOW || reg == REG_XFERCNTMID || reg == REG_XFERCNTHI)
+ {
+ scsi_regs[REG_STATUS] &= ~0x10; // clear CTZ bit
+ }
+
+ // FIFO
+ if (reg == REG_FIFO)
+ {
+// mame_printf_debug("%02x to FIFO @ %02d\n", val, fptr);
+ fifo[fptr++] = val;
+ if (fptr > 15)
+ {
+ fptr = 15;
+ }
+ }
+
+ // command
+ if (reg == REG_COMMAND)
+ {
+ dma = (val & 0x80) ? 1 : 0;
+ fptr = 0;
+ switch (val & 0x7f)
+ {
+ case 0: // NOP
+ scsi_regs[REG_IRQSTATE] = 8; // indicate success
+ xfer_state = 0;
+ break;
+ case 2: // reset device
+ scsi_regs[REG_IRQSTATE] = 8; // indicate success
+
+ logerror("53cf96: reset target ID = %d (PC = %x)\n", last_id, activecpu_get_pc());
+ if (devices[last_id])
+ {
+ SCSIReset( devices[last_id] );
+ }
+ else
+ {
+ logerror("53cf96: reset request for unknown device SCSI ID %d\n", last_id);
+ }
+
+ xfer_state = 0;
+ break;
+ case 3: // reset SCSI bus
+ scsi_regs[REG_INTSTATE] = 4; // command sent OK
+ xfer_state = 0;
+ timer_set( ATTOTIME_IN_HZ( 16384 ), 0, am53cf96_irq );
+ break;
+ case 0x42: // select with ATN steps
+ timer_set( ATTOTIME_IN_HZ( 16384 ), 0, am53cf96_irq );
+ if ((fifo[1] == 0) || (fifo[1] == 0x48) || (fifo[1] == 0x4b))
+ {
+ scsi_regs[REG_INTSTATE] = 6;
+ }
+ else
+ {
+ scsi_regs[REG_INTSTATE] = 4;
+ }
+
+ logerror("53cf96: command %x exec. target ID = %d (PC = %x)\n", fifo[1], last_id, activecpu_get_pc());
+ if (devices[last_id])
+ {
+ int length;
+
+ SCSISetCommand( devices[last_id], &fifo[1], 12 );
+ SCSIExecCommand( devices[last_id], &length );
+ }
+ else
+ {
+ logerror("53cf96: request for unknown device SCSI ID %d\n", last_id);
+ }
+ xfer_state = 0;
+ break;
+ case 0x44: // enable selection/reselection
+ xfer_state = 0;
+ break;
+ case 0x10: // information transfer (must not change xfer_state)
+ case 0x11: // second phase of information transfer
+ case 0x12: // message accepted
+ timer_set( ATTOTIME_IN_HZ( 16384 ), 0, am53cf96_irq );
+ scsi_regs[REG_INTSTATE] = 6; // command sent OK
+ break;
+ default:
+ printf( "unsupported command %02x\n", val );
+ break;
+ }
+ }
+
+ // only update the register mirror if it's not a write-only reg
+ if (reg != REG_STATUS && reg != REG_INTSTATE && reg != REG_IRQSTATE && reg != REG_FIFOSTATE)
+ {
+ scsi_regs[reg] = val;
+ }
+}
+
+void am53cf96_init( struct AM53CF96interface *interface )
+{
+ int i;
+
+ // save interface pointer for later
+ intf = interface;
+
+ memset(scsi_regs, 0, sizeof(scsi_regs));
+ memset(devices, 0, sizeof(devices));
+
+ // try to open the devices
+ for (i = 0; i < interface->scsidevs->devs_present; i++)
+ {
+ SCSIAllocInstance( interface->scsidevs->devices[i].scsiClass, &devices[interface->scsidevs->devices[i].scsiID], interface->scsidevs->devices[i].diskID );
+ }
+
+ state_save_register_global_array(scsi_regs);
+ state_save_register_global_array(fifo);
+ state_save_register_global(fptr);
+ state_save_register_global(xfer_state);
+ state_save_register_global(last_id);
+}
+
+// retrieve data from the SCSI controller
+void am53cf96_read_data(int bytes, UINT8 *pData)
+{
+ scsi_regs[REG_STATUS] |= 0x10; // indicate DMA finished
+
+ if (devices[last_id])
+ {
+ SCSIReadData( devices[last_id], pData, bytes );
+ }
+ else
+ {
+ logerror("53cf96: request for unknown device SCSI ID %d\n", last_id);
+ }
+}
+
+// write data to the SCSI controller
+void am53cf96_write_data(int bytes, UINT8 *pData)
+{
+// int i;
+
+ scsi_regs[REG_STATUS] |= 0x10; // indicate DMA finished
+
+ if (devices[last_id])
+ {
+ SCSIWriteData( devices[last_id], pData, bytes );
+ }
+ else
+ {
+ logerror("53cf96: request for unknown device SCSI ID %d\n", last_id);
+ }
+}
+
+// get the device handle (HD or CD) for the specified SCSI ID
+void *am53cf96_get_device(int id)
+{
+ void *ret;
+
+ if (devices[id])
+ {
+ logerror("53cf96: fetching dev pointer for SCSI ID %d\n", id);
+ SCSIGetDevice( devices[id], &ret );
+ return ret;
+ }
+
+ return NULL;
+}
diff --git a/src/emu/machine/am53cf96.h b/src/emu/machine/am53cf96.h
new file mode 100644
index 00000000000..b3e23de8712
--- /dev/null
+++ b/src/emu/machine/am53cf96.h
@@ -0,0 +1,24 @@
+/*
+ * am53cf96.h
+ *
+ */
+
+#ifndef _AM53CF96_H_
+#define _AM53CF96_H_
+
+#include "scsi.h"
+
+struct AM53CF96interface
+{
+ SCSIConfigTable *scsidevs; /* SCSI devices */
+ void (*irq_callback)(void); /* irq callback */
+};
+
+extern void am53cf96_init( struct AM53CF96interface *interface );
+extern void am53cf96_read_data(int bytes, UINT8 *pData);
+void am53cf96_write_data(int bytes, UINT8 *pData);
+void *am53cf96_get_device(int id);
+extern READ32_HANDLER( am53cf96_r );
+extern WRITE32_HANDLER( am53cf96_w );
+
+#endif
diff --git a/src/emu/machine/at28c16.c b/src/emu/machine/at28c16.c
new file mode 100644
index 00000000000..da8d2d2cc8d
--- /dev/null
+++ b/src/emu/machine/at28c16.c
@@ -0,0 +1,253 @@
+/*
+ * ATMEL AT28C16
+ *
+ * 16K ( 2K x 8 ) Parallel EEPROM
+ *
+ * Todo:
+ * Emulate write timing.
+ *
+ */
+
+#include "driver.h"
+#include "machine/at28c16.h"
+
+#define DATA_SIZE ( 0x800 )
+#define ID_SIZE ( 0x020 )
+#define ID_OFFSET ( DATA_SIZE - ID_SIZE )
+
+struct at28c16_chip
+{
+ UINT8 data[ DATA_SIZE ];
+ UINT8 id[ ID_SIZE ];
+ UINT8 a9_12v;
+};
+
+static struct at28c16_chip at28c16[ MAX_AT28C16_CHIPS ];
+
+void at28c16_a9_12v( int chip, int a9_12v )
+{
+ struct at28c16_chip *c;
+ if( chip >= MAX_AT28C16_CHIPS )
+ {
+ logerror( "at28c16_a9_12v: invalid chip %d\n", chip );
+ return;
+ }
+ c = &at28c16[ chip ];
+
+ c->a9_12v = a9_12v;
+}
+
+/* nvram handlers */
+
+static void at28c16_init( int chip )
+{
+ struct at28c16_chip *c;
+ if( chip >= MAX_AT28C16_CHIPS )
+ {
+ logerror( "at28c16_init: invalid chip %d\n", chip );
+ return;
+ }
+ c = &at28c16[ chip ];
+
+ c->a9_12v = 0;
+ memset( c->data, 0, DATA_SIZE );
+ memset( c->id, 0, ID_SIZE );
+
+ state_save_register_item_array( "at28c16", chip, c->data );
+ state_save_register_item_array( "at28c16", chip, c->id );
+ state_save_register_item( "at28c16", chip, c->a9_12v );
+}
+
+static void nvram_handler_at28c16( running_machine *machine, int chip, mame_file *file, int read_or_write )
+{
+ struct at28c16_chip *c;
+ if( chip >= MAX_AT28C16_CHIPS )
+ {
+ logerror( "at28c16_nvram_handler: invalid chip %d\n", chip );
+ return;
+ }
+ c = &at28c16[ chip ];
+
+ if( read_or_write )
+ {
+ mame_fwrite( file, c->data, DATA_SIZE );
+ mame_fwrite( file, c->id, ID_SIZE );
+ }
+ else
+ {
+ at28c16_init( chip );
+ if( file )
+ {
+ mame_fread( file, c->data, DATA_SIZE );
+ mame_fread( file, c->id, ID_SIZE );
+ }
+ }
+}
+
+NVRAM_HANDLER( at28c16_0 ) { nvram_handler_at28c16( machine, 0, file, read_or_write ); }
+NVRAM_HANDLER( at28c16_1 ) { nvram_handler_at28c16( machine, 1, file, read_or_write ); }
+NVRAM_HANDLER( at28c16_2 ) { nvram_handler_at28c16( machine, 2, file, read_or_write ); }
+NVRAM_HANDLER( at28c16_3 ) { nvram_handler_at28c16( machine, 3, file, read_or_write ); }
+
+/* read / write */
+
+static UINT8 at28c16_read( UINT32 chip, offs_t offset )
+{
+ struct at28c16_chip *c;
+ if( chip >= MAX_AT28C16_CHIPS )
+ {
+ logerror( "at28c16_read( %d, %04x ) chip out of range\n", chip, offset );
+ return 0;
+ }
+ c = &at28c16[ chip ];
+
+ if( offset >= ID_OFFSET && c->a9_12v )
+ {
+ logerror( "at28c16_read( %04x ) id\n", offset );
+ return c->id[ offset - ID_OFFSET ];
+ }
+ else
+ {
+// logerror( "at28c16_read( %04x ) data\n", offset );
+ return c->data[ offset ];
+ }
+}
+
+static void at28c16_write( UINT32 chip, offs_t offset, UINT8 data )
+{
+ struct at28c16_chip *c;
+ if( chip >= MAX_AT28C16_CHIPS )
+ {
+ logerror( "at28c16_write( %d, %04x, %02x ) chip out of range\n", chip, offset, data );
+ return;
+ }
+ c = &at28c16[ chip ];
+
+ if( offset >= ID_OFFSET && c->a9_12v )
+ {
+ logerror( "at28c16_write( %d, %04x, %02x ) id\n", chip, offset, data );
+ c->id[ offset - ID_OFFSET ] = data;
+ }
+ else
+ {
+// logerror( "at28c16_write( %d, %04x, %02x ) data\n", chip, offset, data );
+ c->data[ offset ] = data;
+ }
+}
+
+/* 16bit memory handlers */
+
+static UINT16 at28c16_16msb_read( UINT32 chip, offs_t offset, UINT32 mem_mask )
+{
+ UINT32 data = 0;
+ if( ACCESSING_MSB16 )
+ {
+ data |= at28c16_read( chip, offset ) << 8;
+ }
+ return data;
+}
+
+static void at28c16_16msb_write( UINT32 chip, offs_t offset, UINT32 data, UINT32 mem_mask )
+{
+ if( ACCESSING_MSB16 )
+ {
+ at28c16_write( chip, offset, data >> 8 );
+ }
+}
+
+READ16_HANDLER( at28c16_16msb_0_r ) { return at28c16_16msb_read( 0, offset, mem_mask ); }
+READ16_HANDLER( at28c16_16msb_1_r ) { return at28c16_16msb_read( 1, offset, mem_mask ); }
+READ16_HANDLER( at28c16_16msb_2_r ) { return at28c16_16msb_read( 2, offset, mem_mask ); }
+READ16_HANDLER( at28c16_16msb_3_r ) { return at28c16_16msb_read( 3, offset, mem_mask ); }
+WRITE16_HANDLER( at28c16_16msb_0_w ) { at28c16_16msb_write( 0, offset, data, mem_mask ); }
+WRITE16_HANDLER( at28c16_16msb_1_w ) { at28c16_16msb_write( 1, offset, data, mem_mask ); }
+WRITE16_HANDLER( at28c16_16msb_2_w ) { at28c16_16msb_write( 2, offset, data, mem_mask ); }
+WRITE16_HANDLER( at28c16_16msb_3_w ) { at28c16_16msb_write( 3, offset, data, mem_mask ); }
+
+/* 32bit memory handlers */
+
+static UINT32 at28c16_32le_read( UINT32 chip, offs_t offset, UINT32 mem_mask )
+{
+ UINT32 data = 0;
+ if( ACCESSING_LSB32 )
+ {
+ data |= at28c16_read( chip, ( offset * 4 ) + 0 ) << 0;
+ }
+ if( ( mem_mask & 0x0000ff00 ) == 0 )
+ {
+ data |= at28c16_read( chip, ( offset * 4 ) + 1 ) << 8;
+ }
+ if( ( mem_mask & 0x00ff0000 ) == 0 )
+ {
+ data |= at28c16_read( chip, ( offset * 4 ) + 2 ) << 16;
+ }
+ if( ACCESSING_MSB32 )
+ {
+ data |= at28c16_read( chip, ( offset * 4 ) + 3 ) << 24;
+ }
+ return data;
+}
+
+static void at28c16_32le_write( UINT32 chip, offs_t offset, UINT32 data, UINT32 mem_mask )
+{
+ if( ACCESSING_LSB32 )
+ {
+ at28c16_write( chip, ( offset * 4 ) + 0, data >> 0 );
+ }
+ if( ( mem_mask & 0x0000ff00 ) == 0 )
+ {
+ at28c16_write( chip, ( offset * 4 ) + 1, data >> 8 );
+ }
+ if( ( mem_mask & 0x00ff0000 ) == 0 )
+ {
+ at28c16_write( chip, ( offset * 4 ) + 2, data >> 16 );
+ }
+ if( ACCESSING_MSB32 )
+ {
+ at28c16_write( chip, ( offset * 4 ) + 3, data >> 24 );
+ }
+}
+
+READ32_HANDLER( at28c16_32le_0_r ) { return at28c16_32le_read( 0, offset, mem_mask ); }
+READ32_HANDLER( at28c16_32le_1_r ) { return at28c16_32le_read( 1, offset, mem_mask ); }
+READ32_HANDLER( at28c16_32le_2_r ) { return at28c16_32le_read( 2, offset, mem_mask ); }
+READ32_HANDLER( at28c16_32le_3_r ) { return at28c16_32le_read( 3, offset, mem_mask ); }
+WRITE32_HANDLER( at28c16_32le_0_w ) { at28c16_32le_write( 0, offset, data, mem_mask ); }
+WRITE32_HANDLER( at28c16_32le_1_w ) { at28c16_32le_write( 1, offset, data, mem_mask ); }
+WRITE32_HANDLER( at28c16_32le_2_w ) { at28c16_32le_write( 2, offset, data, mem_mask ); }
+WRITE32_HANDLER( at28c16_32le_3_w ) { at28c16_32le_write( 3, offset, data, mem_mask ); }
+
+static UINT32 at28c16_32le_16lsb_read( UINT32 chip, offs_t offset, UINT32 mem_mask )
+{
+ UINT32 data = 0;
+ if( ACCESSING_LSB32 )
+ {
+ data |= at28c16_read( chip, ( offset * 2 ) + 0 ) << 0;
+ }
+ if( ( mem_mask & 0x00ff0000 ) == 0 )
+ {
+ data |= at28c16_read( chip, ( offset * 2 ) + 1 ) << 16;
+ }
+ return data;
+}
+
+static void at28c16_32le_16lsb_write( UINT32 chip, offs_t offset, UINT32 data, UINT32 mem_mask )
+{
+ if( ACCESSING_LSB32 )
+ {
+ at28c16_write( chip, ( offset * 2 ) + 0, data >> 0 );
+ }
+ if( ( mem_mask & 0x00ff0000 ) == 0 )
+ {
+ at28c16_write( chip, ( offset * 2 ) + 1, data >> 16 );
+ }
+}
+
+READ32_HANDLER( at28c16_32le_16lsb_0_r ) { return at28c16_32le_16lsb_read( 0, offset, mem_mask ); }
+READ32_HANDLER( at28c16_32le_16lsb_1_r ) { return at28c16_32le_16lsb_read( 1, offset, mem_mask ); }
+READ32_HANDLER( at28c16_32le_16lsb_2_r ) { return at28c16_32le_16lsb_read( 2, offset, mem_mask ); }
+READ32_HANDLER( at28c16_32le_16lsb_3_r ) { return at28c16_32le_16lsb_read( 3, offset, mem_mask ); }
+WRITE32_HANDLER( at28c16_32le_16lsb_0_w ) { at28c16_32le_16lsb_write( 0, offset, data, mem_mask ); }
+WRITE32_HANDLER( at28c16_32le_16lsb_1_w ) { at28c16_32le_16lsb_write( 1, offset, data, mem_mask ); }
+WRITE32_HANDLER( at28c16_32le_16lsb_2_w ) { at28c16_32le_16lsb_write( 2, offset, data, mem_mask ); }
+WRITE32_HANDLER( at28c16_32le_16lsb_3_w ) { at28c16_32le_16lsb_write( 3, offset, data, mem_mask ); }
diff --git a/src/emu/machine/at28c16.h b/src/emu/machine/at28c16.h
new file mode 100644
index 00000000000..87e7f200bf8
--- /dev/null
+++ b/src/emu/machine/at28c16.h
@@ -0,0 +1,53 @@
+/*
+ * ATMEL AT28C16
+ *
+ * 16K ( 2K x 8 ) Parallel EEPROM
+ *
+ */
+
+#if !defined( AT28C16_H )
+#define AT28C16_H ( 1 )
+
+#define MAX_AT28C16_CHIPS ( 4 )
+
+extern void at28c16_a9_12v( int chip, int a9_12v );
+
+/* nvram handlers */
+
+NVRAM_HANDLER( at28c16_0 );
+NVRAM_HANDLER( at28c16_1 );
+NVRAM_HANDLER( at28c16_2 );
+NVRAM_HANDLER( at28c16_3 );
+
+/* 16bit memory handlers */
+
+extern READ16_HANDLER( at28c16_16msb_0_r );
+extern READ16_HANDLER( at28c16_16msb_1_r );
+extern READ16_HANDLER( at28c16_16msb_2_r );
+extern READ16_HANDLER( at28c16_16msb_3_r );
+extern WRITE16_HANDLER( at28c16_16msb_0_w );
+extern WRITE16_HANDLER( at28c16_16msb_1_w );
+extern WRITE16_HANDLER( at28c16_16msb_2_w );
+extern WRITE16_HANDLER( at28c16_16msb_3_w );
+
+/* 32bit memory handlers */
+
+extern READ32_HANDLER( at28c16_32le_0_r );
+extern READ32_HANDLER( at28c16_32le_1_r );
+extern READ32_HANDLER( at28c16_32le_2_r );
+extern READ32_HANDLER( at28c16_32le_3_r );
+extern WRITE32_HANDLER( at28c16_32le_0_w );
+extern WRITE32_HANDLER( at28c16_32le_1_w );
+extern WRITE32_HANDLER( at28c16_32le_2_w );
+extern WRITE32_HANDLER( at28c16_32le_3_w );
+
+extern READ32_HANDLER( at28c16_32le_16lsb_0_r );
+extern READ32_HANDLER( at28c16_32le_16lsb_1_r );
+extern READ32_HANDLER( at28c16_32le_16lsb_2_r );
+extern READ32_HANDLER( at28c16_32le_16lsb_3_r );
+extern WRITE32_HANDLER( at28c16_32le_16lsb_0_w );
+extern WRITE32_HANDLER( at28c16_32le_16lsb_1_w );
+extern WRITE32_HANDLER( at28c16_32le_16lsb_2_w );
+extern WRITE32_HANDLER( at28c16_32le_16lsb_3_w );
+
+#endif
diff --git a/src/emu/machine/cr589.c b/src/emu/machine/cr589.c
new file mode 100644
index 00000000000..4ec39d35845
--- /dev/null
+++ b/src/emu/machine/cr589.c
@@ -0,0 +1,152 @@
+/*
+ * Matsushita CR-589
+ *
+ */
+
+#include "driver.h"
+#include "cr589.h"
+
+typedef struct
+{
+ int download;
+ UINT8 buffer[ 65536 ];
+ int bufferOffset;
+} SCSICr589;
+
+static const int identity_offset = 0x3ab;
+static const char *download_identity = "MATSHITA CD98Q4 DOWNLOADGS0N";
+
+static int cr589_exec_command( SCSIInstance *scsiInstance, UINT8 *statusCode )
+{
+ UINT8 *command;
+ int commandLength;
+ SCSICr589 *our_this = SCSIThis( &SCSIClassCr589, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch( command[ 0 ] )
+ {
+ case 0x3b: // WRITE BUFFER
+ our_this->bufferOffset = ( command[ 3 ] << 16 ) | ( command[ 4 ] << 8 ) | command[ 5 ];
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAOUT );
+ return ( command[ 6 ] << 16 ) | ( command[ 7 ] << 8 ) | command[ 8 ];
+
+ case 0x3c: // READ BUFFER
+ our_this->bufferOffset = ( command[ 3 ] << 16 ) | ( command[ 4 ] << 8 ) | command[ 5 ];
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return ( command[ 6 ] << 16 ) | ( command[ 7 ] << 8 ) | command[ 8 ];
+
+ case 0xcc: // FIRMWARE DOWNLOAD ENABLE
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAOUT );
+ return SCSILengthFromUINT16( &command[7] );
+
+ default:
+ return SCSIBase( &SCSIClassCr589, SCSIOP_EXEC_COMMAND, scsiInstance, 0, NULL );
+ }
+}
+
+static void cr589_read_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
+{
+ UINT8 *command;
+ int commandLength;
+ SCSICr589 *our_this = SCSIThis( &SCSIClassCr589, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch( command[ 0 ] )
+ {
+ case 0x12: // INQUIRY
+ SCSIBase( &SCSIClassCr589, SCSIOP_READ_DATA, scsiInstance, dataLength, data );
+
+ if( our_this->download )
+ {
+ memcpy( &data[ 8 ], download_identity, 28 );
+ }
+ else
+ {
+ memcpy( &data[ 8 ], &our_this->buffer[ identity_offset ], 28 );
+ }
+ break;
+
+ case 0x3c: // READ BUFFER
+ memcpy( data, &our_this->buffer[ our_this->bufferOffset ], dataLength );
+ our_this->bufferOffset += dataLength;
+ break;
+
+ default:
+ SCSIBase( &SCSIClassCr589, SCSIOP_READ_DATA, scsiInstance, dataLength, data );
+ break;
+ }
+}
+
+static void cr589_write_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
+{
+ UINT8 *command;
+ int commandLength;
+ SCSICr589 *our_this = SCSIThis( &SCSIClassCr589, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch( command[ 0 ] )
+ {
+ case 0x3b: // WRITE BUFFER
+ memcpy( &our_this->buffer[ our_this->bufferOffset ], data + 32, dataLength - 32 );
+ our_this->bufferOffset += dataLength;
+ break;
+
+ case 0xcc: // FIRMWARE DOWNLOAD ENABLE
+ if( memcmp( data, &our_this->buffer[ identity_offset ], 28 ) == 0 )
+ {
+ our_this->download = 1;
+ }
+ else if( memcmp( data, download_identity, 28 ) == 0 )
+ {
+ our_this->download = 0;
+ }
+ break;
+
+ default:
+ SCSIBase( &SCSIClassCr589, SCSIOP_WRITE_DATA, scsiInstance, dataLength, data );
+ break;
+ }
+}
+
+static void cr589_alloc_instance( SCSIInstance *scsiInstance, int diskId )
+{
+ SCSICr589 *our_this = SCSIThis( &SCSIClassCr589, scsiInstance );
+
+ our_this->download = 0;
+ memcpy( &our_this->buffer[ identity_offset ], "MATSHITACD-ROM CR-589 GS0N", 28 );
+
+ state_save_register_item( "cr589", diskId, our_this->download );
+ state_save_register_item_array( "cr589", diskId, our_this->buffer );
+ state_save_register_item( "cr589", diskId, our_this->bufferOffset );
+}
+
+static int cr589_dispatch( int operation, void *file, INT64 intparm, void *ptrparm )
+{
+ switch( operation )
+ {
+ case SCSIOP_EXEC_COMMAND:
+ return cr589_exec_command( file, ptrparm );
+
+ case SCSIOP_READ_DATA:
+ cr589_read_data( file, ptrparm, intparm );
+ return 0;
+
+ case SCSIOP_WRITE_DATA:
+ cr589_write_data( file, ptrparm, intparm );
+ return 0;
+
+ case SCSIOP_ALLOC_INSTANCE:
+ SCSIBase( &SCSIClassCr589, operation, file, intparm, ptrparm );
+ cr589_alloc_instance( *((SCSIInstance **) ptrparm), intparm );
+ return 0;
+ }
+
+ return SCSIBase( &SCSIClassCr589, operation, file, intparm, ptrparm );
+}
+
+SCSIClass SCSIClassCr589 =
+{
+ &SCSIClassCDROM,
+ cr589_dispatch,
+ sizeof( SCSICr589 )
+};
diff --git a/src/emu/machine/cr589.h b/src/emu/machine/cr589.h
new file mode 100644
index 00000000000..a0e9313abe9
--- /dev/null
+++ b/src/emu/machine/cr589.h
@@ -0,0 +1,3 @@
+#include "scsi.h"
+
+extern SCSIClass SCSIClassCr589;
diff --git a/src/emu/machine/ds1302.c b/src/emu/machine/ds1302.c
new file mode 100644
index 00000000000..4a8dba5a590
--- /dev/null
+++ b/src/emu/machine/ds1302.c
@@ -0,0 +1,140 @@
+#include "driver.h"
+#include "ds1302.h"
+
+/********************
+ DALLAS
+ DS1302
+
+ RTC+BACKUP RAM
+
+ Emulation by ElSemi
+********************/
+
+/********************
+Missing:
+Burst Mode
+Clock programming (useless)
+********************/
+
+static UINT32 ShiftIn=0;
+static UINT8 ShiftOut=0;
+static UINT8 ICount=0;
+static UINT8 LastClk;
+static UINT8 LastCmd=0;
+static UINT8 SRAM[0x20];
+
+
+void DS1302_RST(UINT8 val)
+{
+ if(!val)
+ {
+ ICount=0;
+ LastClk=0;
+ ShiftIn=0;
+ LastCmd=0;
+ }
+}
+
+void DS1302_DAT(UINT8 val)
+{
+ if(val)
+ ShiftIn|=(1<<ICount);
+ else
+ ShiftIn&=~(1<<ICount);
+}
+
+static UINT8 bcd(UINT8 v)
+{
+ return ((v/10)<<4)|(v%10);
+}
+
+void DS1302_CLK(UINT8 val)
+{
+ if(val!=LastClk)
+ {
+ if(val) //Rising, shift in command
+ {
+ ICount++;
+ if(ICount==8) //Command start
+ {
+ mame_system_time systime;
+ mame_get_base_datetime(Machine, &systime);
+
+ switch(ShiftIn)
+ {
+ case 0x81: //Sec
+ ShiftOut=bcd(systime.local_time.second);
+ break;
+ case 0x83: //Min
+ ShiftOut=bcd(systime.local_time.minute);
+ break;
+ case 0x85: //Hour
+ ShiftOut=bcd(systime.local_time.hour);
+ break;
+ case 0x87: //Day
+ ShiftOut=bcd(systime.local_time.mday);
+ break;
+ case 0x89: //Month
+ ShiftOut=bcd(systime.local_time.month+1);
+ break;
+ case 0x8b: //weekday
+ ShiftOut=bcd(systime.local_time.weekday);
+ break;
+ case 0x8d: //Year
+ ShiftOut=bcd(systime.local_time.year%100);
+ break;
+ default:
+ ShiftOut=0x0;
+ }
+ if(ShiftIn>0xc0)
+ ShiftOut=SRAM[(ShiftIn>>1)&0x1f];
+ LastCmd=ShiftIn&0xff;
+ ICount++;
+ }
+ if(ICount==17 && !(LastCmd&1))
+ {
+ UINT8 val=(ShiftIn>>9)&0xff;
+
+ switch(LastCmd)
+ {
+ case 0x80: //Sec
+
+ break;
+ case 0x82: //Min
+
+ break;
+ case 0x84: //Hour
+
+ break;
+ case 0x86: //Day
+
+ break;
+ case 0x88: //Month
+
+ break;
+ case 0x8a: //weekday
+
+ break;
+ case 0x8c: //Year
+
+ break;
+ default:
+ ShiftOut=0x0;
+ }
+ if(LastCmd>0xc0)
+ {
+ SRAM[(LastCmd>>1)&0x1f]=val;
+ }
+
+
+
+ }
+ }
+ }
+ LastClk=val;
+}
+
+UINT8 DS1302_RD(void)
+{
+ return (ShiftOut&(1<<(ICount-9)))?1:0;
+}
diff --git a/src/emu/machine/ds1302.h b/src/emu/machine/ds1302.h
new file mode 100644
index 00000000000..7e77c6588d7
--- /dev/null
+++ b/src/emu/machine/ds1302.h
@@ -0,0 +1,5 @@
+extern void DS1302_RST(UINT8 val);
+extern void DS1302_DAT(UINT8 val);
+extern void DS1302_CLK(UINT8 val);
+extern UINT8 DS1302_RD(void);
+
diff --git a/src/emu/machine/ds2401.c b/src/emu/machine/ds2401.c
new file mode 100644
index 00000000000..baa987a7e19
--- /dev/null
+++ b/src/emu/machine/ds2401.c
@@ -0,0 +1,272 @@
+/*
+ * DS2401
+ *
+ * Dallas Semiconductor
+ * Silicon Serial Number
+ *
+ */
+
+#include <stdarg.h>
+#include "driver.h"
+#include "state.h"
+#include "machine/ds2401.h"
+
+#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 ds2401_chip
+{
+ int state;
+ int bit;
+ int byte;
+ int shift;
+ int rx;
+ int tx;
+ UINT8 *data;
+ emu_timer *timer;
+ emu_timer *reset_timer;
+ attotime t_samp;
+ attotime t_rdv;
+ attotime t_rstl;
+ attotime t_pdh;
+ attotime t_pdl;
+};
+
+#define SIZE_DATA ( 8 )
+
+#define STATE_IDLE ( 0 )
+#define STATE_RESET ( 1 )
+#define STATE_RESET1 ( 2 )
+#define STATE_RESET2 ( 3 )
+#define STATE_COMMAND ( 4 )
+#define STATE_READROM ( 5 )
+
+#define COMMAND_READROM ( 0x33 )
+
+static struct ds2401_chip ds2401[ DS2401_MAXCHIP ];
+
+static TIMER_CALLBACK( ds2401_reset )
+{
+ int which = param;
+ struct ds2401_chip *c = &ds2401[ which ];
+
+ verboselog( 1, "ds2401_reset(%d)\n", which );
+
+ c->state = STATE_RESET;
+ timer_adjust( c->timer, attotime_never, which, attotime_never );
+}
+
+static TIMER_CALLBACK( ds2401_tick )
+{
+ int which = param;
+ struct ds2401_chip *c = &ds2401[ which ];
+
+ switch( c->state )
+ {
+ case STATE_RESET1:
+ verboselog( 2, "ds2401_tick(%d) state_reset1 %d\n", which, c->rx );
+ c->tx = 0;
+ c->state = STATE_RESET2;
+ timer_adjust( c->timer, c->t_pdl, which, attotime_never );
+ break;
+ case STATE_RESET2:
+ verboselog( 2, "ds2401_tick(%d) state_reset2 %d\n", which, c->rx );
+ c->tx = 1;
+ c->bit = 0;
+ c->shift = 0;
+ c->state = STATE_COMMAND;
+ break;
+ case STATE_COMMAND:
+ verboselog( 2, "ds2401_tick(%d) state_command %d\n", which, c->rx );
+ c->shift >>= 1;
+ if( c->rx != 0 )
+ {
+ c->shift |= 0x80;
+ }
+ c->bit++;
+ if( c->bit == 8 )
+ {
+ switch( c->shift )
+ {
+ case COMMAND_READROM:
+ verboselog( 1, "ds2401_tick(%d) readrom\n", which );
+ c->bit = 0;
+ c->byte = 0;
+ c->state = STATE_READROM;
+ break;
+ default:
+ verboselog( 0, "ds2401_tick(%d) command not handled %02x\n", which, c->shift );
+ c->state = STATE_IDLE;
+ break;
+ }
+ }
+ break;
+ case STATE_READROM:
+ c->tx = 1;
+ if( c->byte == 8 )
+ {
+ verboselog( 1, "ds2401_tick(%d) readrom finished\n", which );
+ c->state = STATE_IDLE;
+ }
+ else
+ {
+ verboselog( 2, "ds2401_tick(%d) readrom window closed\n", which );
+ }
+ break;
+ default:
+ verboselog( 0, "ds2401_tick(%d) state not handled: %d\n", which, c->state );
+ break;
+ }
+}
+
+void ds2401_init( int which, UINT8 *data )
+{
+ struct ds2401_chip *c = &ds2401[ which ];
+
+ if( data == NULL )
+ {
+ data = auto_malloc( SIZE_DATA );
+ }
+
+ c->state = STATE_IDLE;
+ c->bit = 0;
+ c->byte = 0;
+ c->shift = 0;
+ c->rx = 1;
+ c->tx = 1;
+ c->data = data;
+ c->t_samp = ATTOTIME_IN_USEC( 15 );
+ c->t_rdv = ATTOTIME_IN_USEC( 15 );
+ c->t_rstl = ATTOTIME_IN_USEC( 480 );
+ c->t_pdh = ATTOTIME_IN_USEC( 15 );
+ c->t_pdl = ATTOTIME_IN_USEC( 60 );
+
+ state_save_register_item( "ds2401", which, c->state );
+ state_save_register_item( "ds2401", which, c->bit );
+ state_save_register_item( "ds2401", which, c->byte );
+ state_save_register_item( "ds2401", which, c->shift );
+ state_save_register_item( "ds2401", which, c->rx );
+ state_save_register_item( "ds2401", which, c->tx );
+ state_save_register_item_pointer( "ds2401", which, data, SIZE_DATA );
+
+ c->timer = timer_alloc( ds2401_tick );
+ c->reset_timer = timer_alloc( ds2401_reset );
+}
+
+void ds2401_write( int which, int data )
+{
+ struct ds2401_chip *c = &ds2401[ which ];
+
+ verboselog( 1, "ds2401_write( %d, %d )\n", which, data );
+
+ if( data == 0 && c->rx != 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_IDLE:
+ break;
+ case STATE_COMMAND:
+ verboselog( 2, "ds2401_write(%d) state_command\n", which );
+ timer_adjust( c->timer, c->t_samp, which, attotime_never );
+ break;
+ case STATE_READROM:
+ if( c->bit == 0 )
+ {
+ c->shift = c->data[ 7 - c->byte ];
+ verboselog( 1, "ds2401_write(%d) <- data %02x\n", which, c->shift );
+ }
+ c->tx = c->shift & 1;
+ c->shift >>= 1;
+ c->bit++;
+ if( c->bit == 8 )
+ {
+ c->bit = 0;
+ c->byte++;
+ }
+ verboselog( 2, "ds2401_write(%d) state_readrom %d\n", which, c->tx );
+ timer_adjust( c->timer, c->t_rdv, which, attotime_never );
+ break;
+ default:
+ verboselog( 0, "ds2401_write(%d) state not handled: %d\n", which, c->state );
+ break;
+ }
+ timer_adjust( c->reset_timer, c->t_rstl, which, attotime_never );
+ }
+ else if( data == 1 && c->rx == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_RESET:
+ c->state = STATE_RESET1;
+ timer_adjust( c->timer, c->t_pdh, which, attotime_never );
+ break;
+ }
+ timer_adjust( c->reset_timer, attotime_never, which, attotime_never );
+ }
+ c->rx = data;
+}
+
+int ds2401_read( int which )
+{
+ struct ds2401_chip *c = &ds2401[ which ];
+
+ verboselog( 2, "ds2401_read( %d ) %d\n", which, c->tx & c->rx );
+ return c->tx & c->rx;
+}
+
+/*
+
+app74.pdf
+
+Under normal circumstances an ibutton will sample the line 30us after the falling edge of the start condition.
+The internal time base of ibutton may deviate from its nominal value. The allowed tollerance band ranges from 15us to 60us.
+This means that the actual slave sampling may occur anywhere from 15 and 60us after the start condition, which is a ratio of 1 to 4.
+During this time frame the voltage on the data line must stay below Vilmax or above Vihmin.
+
+In the 1-Wire system, the logical values 1 and 0 are represented by certain voltages in special waveforms.
+The waveforms needed to write commands or data to ibuttons are called write-1 and write-0 time slots.
+The duration of a low pulse to write a 1 must be shorter than 15us.
+To write a 0, the duration of the low pulse must be at least 60us to cope with worst-case conditions.
+
+The duration of the active part of a time slot can be extended beyond 60us.
+The maximum extension is limited by the fact that a low pulse of a duration of at least eight active time slots ( 480us ) is defined as a Reset Pulse.
+Allowing the same worst-case tolerance ratio, a low pulse of 120us might be sufficient for a reset.
+This limits the extension of the active part of a time slot to a maximum of 120us to prevent misinterpretation with reset.
+
+Commands and data are sent to ibuttons by combining write-0 and write-1 time slots.
+To read data, the master has to generate read-data time slots to define the start condition of each bit.
+The read-data time slots looks essentially the same as a write-1 time slot from the masters point of view.
+Starting at the high-to-low transition, the ibuttons sends 1 bit of its addressed contents.
+If the data bit is a 1, the ibutton leaves the pulse unchanged.
+If the data bit is a 0, the ibutton will pull the data line low for 15us.
+In this time frame data is valid for reading by the master.
+The duration of the low pulse sent by the master should be a minimum of 1us with a maximum value as short as possible to maximize the master sampling window.
+
+The Reset Pulse provides a clear starting condition that supersedes any time slot synchronisation.
+It is defined as single low pulse of minimum duration of eight time slots or 480us followed by a Reset-high time tRSTH of another 480us.
+After a Reset Pulse has been sent, the ibutton will wait for the time tPDH and then generate a Pulse-Presence Pulse of duration tPDL.
+No other communication on the 1-Wire bus is allowed during tRSTH.
+
+There are 1,000 microseconds in a millisecond, and 1,000 milliseconds in a second.
+Thus, there are 1,000,000 microseconds in a second. Why is it "usec"?
+The "u" is supposed to look like the Greek letter Mu that we use for "micro". .
+*/
diff --git a/src/emu/machine/ds2401.h b/src/emu/machine/ds2401.h
new file mode 100644
index 00000000000..52241177e0e
--- /dev/null
+++ b/src/emu/machine/ds2401.h
@@ -0,0 +1,18 @@
+/*
+ * DS2401
+ *
+ * Dallas Semiconductor
+ * Silicon Serial Number
+ *
+ */
+
+#if !defined( DS2401_H )
+#define DS2401_H ( 1 )
+
+#define DS2401_MAXCHIP ( 3 )
+
+extern void ds2401_init( int which, UINT8 *data );
+extern void ds2401_write( int which, int data );
+extern int ds2401_read( int which );
+
+#endif
diff --git a/src/emu/machine/ds2404.c b/src/emu/machine/ds2404.c
new file mode 100644
index 00000000000..fb4fc09696e
--- /dev/null
+++ b/src/emu/machine/ds2404.c
@@ -0,0 +1,320 @@
+/* Dallas DS2404 RTC/NVRAM */
+
+#include "driver.h"
+#include "ds2404.h"
+#include <time.h>
+
+typedef enum {
+ DS2404_STATE_IDLE = 1, /* waiting for ROM command, in 1-wire mode */
+ DS2404_STATE_COMMAND, /* waiting for memory command */
+ DS2404_STATE_ADDRESS1, /* waiting for address bits 0-7 */
+ DS2404_STATE_ADDRESS2, /* waiting for address bits 8-15 */
+ DS2404_STATE_OFFSET, /* waiting for ending offset */
+ DS2404_STATE_INIT_COMMAND,
+ DS2404_STATE_READ_MEMORY, /* Read Memory command active */
+ DS2404_STATE_WRITE_SCRATCHPAD, /* Write Scratchpad command active */
+ DS2404_STATE_READ_SCRATCHPAD, /* Read Scratchpad command active */
+ DS2404_STATE_COPY_SCRATCHPAD /* Copy Scratchpad command active */
+} DS2404_STATE;
+
+typedef struct {
+ UINT16 address;
+ UINT16 offset;
+ UINT16 end_offset;
+ UINT8 a1, a2;
+ UINT8 sram[512]; /* 4096 bits */
+ UINT8 ram[32]; /* scratchpad ram, 256 bits */
+ UINT8 rtc[5]; /* 40-bit RTC counter */
+ DS2404_STATE state[8];
+ int state_ptr;
+} DS2404;
+
+static DS2404 ds2404;
+
+static void ds2404_rom_cmd(UINT8 cmd)
+{
+ switch(cmd)
+ {
+ case 0xcc: /* Skip ROM */
+ ds2404.state[0] = DS2404_STATE_COMMAND;
+ ds2404.state_ptr = 0;
+ break;
+
+ default:
+ fatalerror("DS2404: Unknown ROM command %02X", cmd);
+ break;
+ }
+}
+
+static void ds2404_cmd(UINT8 cmd)
+{
+ switch(cmd)
+ {
+ case 0x0f: /* Write scratchpad */
+ ds2404.state[0] = DS2404_STATE_ADDRESS1;
+ ds2404.state[1] = DS2404_STATE_ADDRESS2;
+ ds2404.state[2] = DS2404_STATE_INIT_COMMAND;
+ ds2404.state[3] = DS2404_STATE_WRITE_SCRATCHPAD;
+ ds2404.state_ptr = 0;
+ break;
+
+ case 0x55: /* Copy scratchpad */
+ ds2404.state[0] = DS2404_STATE_ADDRESS1;
+ ds2404.state[1] = DS2404_STATE_ADDRESS2;
+ ds2404.state[2] = DS2404_STATE_OFFSET;
+ ds2404.state[3] = DS2404_STATE_INIT_COMMAND;
+ ds2404.state[4] = DS2404_STATE_COPY_SCRATCHPAD;
+ ds2404.state_ptr = 0;
+ break;
+
+ case 0xf0: /* Read memory */
+ ds2404.state[0] = DS2404_STATE_ADDRESS1;
+ ds2404.state[1] = DS2404_STATE_ADDRESS2;
+ ds2404.state[2] = DS2404_STATE_INIT_COMMAND;
+ ds2404.state[3] = DS2404_STATE_READ_MEMORY;
+ ds2404.state_ptr = 0;
+ break;
+
+ default:
+ fatalerror("DS2404: Unknown command %02X", cmd);
+ break;
+ }
+}
+
+static UINT8 ds2404_readmem(void)
+{
+ if( ds2404.address < 0x200 )
+ {
+ return ds2404.sram[ ds2404.address ];
+ }
+ else if( ds2404.address >= 0x202 && ds2404.address <= 0x206 )
+ {
+ return ds2404.rtc[ ds2404.address - 0x202 ];
+ }
+ return 0;
+}
+
+static void ds2404_writemem(UINT8 value)
+{
+ if( ds2404.address < 0x200 )
+ {
+ ds2404.sram[ ds2404.address ] = value;
+ }
+ else if( ds2404.address >= 0x202 && ds2404.address <= 0x206 )
+ {
+ ds2404.rtc[ ds2404.address - 0x202 ] = value;
+ }
+}
+
+WRITE8_HANDLER( DS2404_1W_reset_w )
+{
+ ds2404.state[0] = DS2404_STATE_IDLE;
+ ds2404.state_ptr = 0;
+}
+
+WRITE8_HANDLER( DS2404_3W_reset_w )
+{
+ ds2404.state[0] = DS2404_STATE_COMMAND;
+ ds2404.state_ptr = 0;
+}
+
+READ8_HANDLER( DS2404_data_r )
+{
+ UINT8 value;
+ switch( ds2404.state[ds2404.state_ptr] )
+ {
+ case DS2404_STATE_IDLE:
+ case DS2404_STATE_COMMAND:
+ case DS2404_STATE_ADDRESS1:
+ case DS2404_STATE_ADDRESS2:
+ case DS2404_STATE_OFFSET:
+ case DS2404_STATE_INIT_COMMAND:
+ break;
+
+ case DS2404_STATE_READ_MEMORY:
+ value = ds2404_readmem();
+ return value;
+
+ case DS2404_STATE_READ_SCRATCHPAD:
+ if( ds2404.offset < 0x20 ) {
+ value = ds2404.ram[ds2404.offset];
+ ds2404.offset++;
+ return value;
+ }
+ break;
+
+ case DS2404_STATE_WRITE_SCRATCHPAD:
+ break;
+
+ case DS2404_STATE_COPY_SCRATCHPAD:
+ break;
+ }
+ return 0;
+}
+
+WRITE8_HANDLER( DS2404_data_w )
+{
+ int i;
+
+ switch( ds2404.state[ds2404.state_ptr] )
+ {
+ case DS2404_STATE_IDLE:
+ ds2404_rom_cmd(data & 0xff);
+ break;
+
+ case DS2404_STATE_COMMAND:
+ ds2404_cmd(data & 0xff);
+ break;
+
+ case DS2404_STATE_ADDRESS1:
+ ds2404.a1 = data & 0xff;
+ ds2404.state_ptr++;
+ break;
+
+ case DS2404_STATE_ADDRESS2:
+ ds2404.a2 = data & 0xff;
+ ds2404.state_ptr++;
+ break;
+
+ case DS2404_STATE_OFFSET:
+ ds2404.end_offset = data & 0xff;
+ ds2404.state_ptr++;
+ break;
+
+ case DS2404_STATE_INIT_COMMAND:
+ break;
+
+ case DS2404_STATE_READ_MEMORY:
+ break;
+
+ case DS2404_STATE_READ_SCRATCHPAD:
+ break;
+
+ case DS2404_STATE_WRITE_SCRATCHPAD:
+ if( ds2404.offset < 0x20 ) {
+ ds2404.ram[ds2404.offset] = data & 0xff;
+ ds2404.offset++;
+ } else {
+ /* Set OF flag */
+ }
+ break;
+
+ case DS2404_STATE_COPY_SCRATCHPAD:
+ break;
+ }
+
+ if( ds2404.state[ds2404.state_ptr] == DS2404_STATE_INIT_COMMAND ) {
+ switch( ds2404.state[ds2404.state_ptr+1] )
+ {
+ case DS2404_STATE_IDLE:
+ case DS2404_STATE_COMMAND:
+ case DS2404_STATE_ADDRESS1:
+ case DS2404_STATE_ADDRESS2:
+ case DS2404_STATE_OFFSET:
+ case DS2404_STATE_INIT_COMMAND:
+ break;
+
+ case DS2404_STATE_READ_MEMORY:
+ ds2404.address = (ds2404.a2 << 8) | ds2404.a1;
+ ds2404.address -= 1;
+ break;
+
+ case DS2404_STATE_WRITE_SCRATCHPAD:
+ ds2404.address = (ds2404.a2 << 8) | ds2404.a1;
+ ds2404.offset = ds2404.address & 0x1f;
+ break;
+
+ case DS2404_STATE_READ_SCRATCHPAD:
+ ds2404.address = (ds2404.a2 << 8) | ds2404.a1;
+ ds2404.offset = ds2404.address & 0x1f;
+ break;
+
+ case DS2404_STATE_COPY_SCRATCHPAD:
+ ds2404.address = (ds2404.a2 << 8) | ds2404.a1;
+
+ for( i=0; i <= ds2404.end_offset; i++ ) {
+ ds2404_writemem( ds2404.ram[i] );
+ ds2404.address++;
+ }
+ break;
+ }
+ ds2404.state_ptr++;
+ }
+}
+
+WRITE8_HANDLER( DS2404_clk_w )
+{
+ switch( ds2404.state[ds2404.state_ptr] )
+ {
+ case DS2404_STATE_IDLE:
+ case DS2404_STATE_COMMAND:
+ case DS2404_STATE_ADDRESS1:
+ case DS2404_STATE_ADDRESS2:
+ case DS2404_STATE_OFFSET:
+ case DS2404_STATE_INIT_COMMAND:
+ break;
+
+ case DS2404_STATE_READ_MEMORY:
+ ds2404.address++;
+ break;
+
+ case DS2404_STATE_READ_SCRATCHPAD:
+ break;
+
+ case DS2404_STATE_WRITE_SCRATCHPAD:
+ break;
+
+ case DS2404_STATE_COPY_SCRATCHPAD:
+ break;
+ }
+}
+
+static TIMER_CALLBACK( DS2404_tick )
+{
+ int i;
+ for( i = 0; i < 5; i++ )
+ {
+ ds2404.rtc[ i ]++;
+ if( ds2404.rtc[ i ] != 0 )
+ {
+ break;
+ }
+ }
+}
+
+void DS2404_init(int ref_year, int ref_month, int ref_day)
+{
+ struct tm ref_tm;
+ time_t ref_time;
+ time_t current_time;
+ emu_timer *timer;
+
+ memset( &ref_tm, 0, sizeof( ref_tm ) );
+ ref_tm.tm_year = ref_year - 1900;
+ ref_tm.tm_mon = ref_month - 1;
+ ref_tm.tm_mday = ref_day;
+
+ ref_time = mktime( &ref_tm );
+
+ time( &current_time );
+ current_time -= ref_time;
+
+ ds2404.rtc[ 0 ] = 0x0;
+ ds2404.rtc[ 1 ] = ( current_time >> 0 ) & 0xff;
+ ds2404.rtc[ 2 ] = ( current_time >> 8 ) & 0xff;
+ ds2404.rtc[ 3 ] = ( current_time >> 16 ) & 0xff;
+ ds2404.rtc[ 4 ] = ( current_time >> 24 ) & 0xff;
+
+ timer = timer_alloc( DS2404_tick );
+ timer_adjust( timer, ATTOTIME_IN_HZ( 256 ), 0, ATTOTIME_IN_HZ( 256 ) );
+}
+
+void DS2404_load(mame_file *file)
+{
+ mame_fread(file, ds2404.sram, 512);
+}
+
+void DS2404_save(mame_file *file)
+{
+ mame_fwrite(file, ds2404.sram, 512);
+}
diff --git a/src/emu/machine/ds2404.h b/src/emu/machine/ds2404.h
new file mode 100644
index 00000000000..44a88230a9a
--- /dev/null
+++ b/src/emu/machine/ds2404.h
@@ -0,0 +1,18 @@
+#ifndef DS2404_H
+#define DS2404_H
+
+void DS2404_init(int ref_year, int ref_month, int ref_day);
+void DS2404_load(mame_file *file);
+void DS2404_save(mame_file *file);
+
+/* 1-wire interface reset */
+WRITE8_HANDLER( DS2404_1W_reset_w );
+
+/* 3-wire interface reset */
+WRITE8_HANDLER( DS2404_3W_reset_w );
+
+READ8_HANDLER( DS2404_data_r );
+WRITE8_HANDLER( DS2404_data_w );
+WRITE8_HANDLER( DS2404_clk_w );
+
+#endif
diff --git a/src/emu/machine/eeprom.c b/src/emu/machine/eeprom.c
new file mode 100644
index 00000000000..2c065433ec3
--- /dev/null
+++ b/src/emu/machine/eeprom.c
@@ -0,0 +1,378 @@
+#include "driver.h"
+#include "eeprom.h"
+
+#define VERBOSE 0
+
+#define SERIAL_BUFFER_LENGTH 40
+#define MEMORY_SIZE 1024
+
+static struct EEPROM_interface *intf;
+
+static int serial_count;
+static UINT8 serial_buffer[SERIAL_BUFFER_LENGTH];
+static UINT8 eeprom_data[MEMORY_SIZE];
+static int eeprom_data_bits;
+static int eeprom_read_address;
+static int eeprom_clock_count;
+static int latch,reset_line,clock_line,sending;
+static int locked;
+static int reset_delay;
+
+/*
+ EEPROM_command_match:
+
+ Try to match the first (len) digits in the EEPROM serial buffer
+ string (*buf) with an EEPROM command string (*cmd).
+ Return non zero if a match was found.
+
+ The serial buffer only contains '0' or '1' (e.g. "1001").
+ The command can contain: '0' or '1' or these wildcards:
+
+ 'x' : match both '0' and '1'
+ "*1": match "1", "01", "001", "0001" etc.
+ "*0": match "0", "10", "110", "1110" etc.
+
+ Note: (cmd) may be NULL. Return 0 (no match) in this case.
+*/
+static int EEPROM_command_match(const char *buf, const char *cmd, int len)
+{
+ if ( cmd == 0 ) return 0;
+ if ( len == 0 ) return 0;
+
+ for (;len>0;)
+ {
+ char b = *buf;
+ char c = *cmd;
+
+ if ((b==0) || (c==0))
+ return (b==c);
+
+ switch ( c )
+ {
+ case '0':
+ case '1':
+ if (b != c) return 0;
+ case 'X':
+ case 'x':
+ buf++;
+ len--;
+ cmd++;
+ break;
+
+ case '*':
+ c = cmd[1];
+ switch( c )
+ {
+ case '0':
+ case '1':
+ if (b == c) { cmd++; }
+ else { buf++; len--; }
+ break;
+ default: return 0;
+ }
+ }
+ }
+ return (*cmd==0);
+}
+
+
+struct EEPROM_interface eeprom_interface_93C46 =
+{
+ 6, // address bits 6
+ 16, // data bits 16
+ "*110", // read 1 10 aaaaaa
+ "*101", // write 1 01 aaaaaa dddddddddddddddd
+ "*111", // erase 1 11 aaaaaa
+ "*10000xxxx", // lock 1 00 00xxxx
+ "*10011xxxx", // unlock 1 00 11xxxx
+ 1,
+// "*10001xxxx" // write all 1 00 01xxxx dddddddddddddddd
+// "*10010xxxx" // erase all 1 00 10xxxx
+};
+
+struct EEPROM_interface eeprom_interface_93C66B =
+{
+ 8, /* address bits */
+ 16, /* data bits */
+ "*110", /* read command */
+ "*101", /* write command */
+ "*111", /* erase command */
+ "*10000xxxxxx", /* lock command */
+ "*10011xxxxxx", /* unlock command */
+ 1,
+// "*10001xxxxxx", /* write all */
+// "*10010xxxxxx", /* erase all */
+};
+
+NVRAM_HANDLER( 93C46 )
+{
+ if (read_or_write)
+ EEPROM_save(file);
+ else
+ {
+ EEPROM_init(&eeprom_interface_93C46);
+ if (file) EEPROM_load(file);
+ }
+}
+
+NVRAM_HANDLER( 93C66B )
+{
+ if (read_or_write)
+ EEPROM_save(file);
+ else
+ {
+ EEPROM_init(&eeprom_interface_93C66B);
+ if (file) EEPROM_load(file);
+ }
+}
+
+void EEPROM_init(struct EEPROM_interface *interface)
+{
+ intf = interface;
+
+ if ((1 << intf->address_bits) * intf->data_bits / 8 > MEMORY_SIZE)
+ {
+ fatalerror("EEPROM larger than eeprom.c allows");
+ }
+
+ memset(eeprom_data,0xff,(1 << intf->address_bits) * intf->data_bits / 8);
+ serial_count = 0;
+ latch = 0;
+ reset_line = ASSERT_LINE;
+ clock_line = ASSERT_LINE;
+ eeprom_read_address = 0;
+ sending = 0;
+ if (intf->cmd_unlock) locked = 1;
+ else locked = 0;
+
+ state_save_register_global_array(eeprom_data);
+ state_save_register_global_array(serial_buffer);
+ state_save_register_global(clock_line);
+ state_save_register_global(reset_line);
+ state_save_register_global(locked);
+ state_save_register_global(serial_count);
+ state_save_register_global(latch);
+ state_save_register_global(reset_delay);
+ state_save_register_global(eeprom_clock_count);
+ state_save_register_global(eeprom_data_bits);
+ state_save_register_global(eeprom_read_address);
+}
+
+static void EEPROM_write(int bit)
+{
+#if VERBOSE
+logerror("EEPROM write bit %d\n",bit);
+#endif
+
+ if (serial_count >= SERIAL_BUFFER_LENGTH-1)
+ {
+logerror("error: EEPROM serial buffer overflow\n");
+ return;
+ }
+
+ serial_buffer[serial_count++] = (bit ? '1' : '0');
+ serial_buffer[serial_count] = 0; /* nul terminate so we can treat it as a string */
+
+ if ( (serial_count > intf->address_bits) &&
+ EEPROM_command_match((char*)serial_buffer,intf->cmd_read,strlen((char*)serial_buffer)-intf->address_bits) )
+ {
+ int i,address;
+
+ address = 0;
+ for (i = serial_count-intf->address_bits;i < serial_count;i++)
+ {
+ address <<= 1;
+ if (serial_buffer[i] == '1') address |= 1;
+ }
+ if (intf->data_bits == 16)
+ eeprom_data_bits = (eeprom_data[2*address+0] << 8) + eeprom_data[2*address+1];
+ else
+ eeprom_data_bits = eeprom_data[address];
+ eeprom_read_address = address;
+ eeprom_clock_count = 0;
+ sending = 1;
+ serial_count = 0;
+logerror("EEPROM read %04x from address %02x\n",eeprom_data_bits,address);
+ }
+ else if ( (serial_count > intf->address_bits) &&
+ EEPROM_command_match((char*)serial_buffer,intf->cmd_erase,strlen((char*)serial_buffer)-intf->address_bits) )
+ {
+ int i,address;
+
+ address = 0;
+ for (i = serial_count-intf->address_bits;i < serial_count;i++)
+ {
+ address <<= 1;
+ if (serial_buffer[i] == '1') address |= 1;
+ }
+logerror("EEPROM erase address %02x\n",address);
+ if (locked == 0)
+ {
+ if (intf->data_bits == 16)
+ {
+ eeprom_data[2*address+0] = 0x00;
+ eeprom_data[2*address+1] = 0x00;
+ }
+ else
+ eeprom_data[address] = 0x00;
+ }
+ else
+logerror("Error: EEPROM is locked\n");
+ serial_count = 0;
+ }
+ else if ( (serial_count > (intf->address_bits + intf->data_bits)) &&
+ EEPROM_command_match((char*)serial_buffer,intf->cmd_write,strlen((char*)serial_buffer)-(intf->address_bits + intf->data_bits)) )
+ {
+ int i,address,data;
+
+ address = 0;
+ for (i = serial_count-intf->data_bits-intf->address_bits;i < (serial_count-intf->data_bits);i++)
+ {
+ address <<= 1;
+ if (serial_buffer[i] == '1') address |= 1;
+ }
+ data = 0;
+ for (i = serial_count-intf->data_bits;i < serial_count;i++)
+ {
+ data <<= 1;
+ if (serial_buffer[i] == '1') data |= 1;
+ }
+logerror("EEPROM write %04x to address %02x\n",data,address);
+ if (locked == 0)
+ {
+ if (intf->data_bits == 16)
+ {
+ eeprom_data[2*address+0] = data >> 8;
+ eeprom_data[2*address+1] = data & 0xff;
+ }
+ else
+ eeprom_data[address] = data;
+ }
+ else
+logerror("Error: EEPROM is locked\n");
+ serial_count = 0;
+ }
+ else if ( EEPROM_command_match((char*)serial_buffer,intf->cmd_lock,strlen((char*)serial_buffer)) )
+ {
+logerror("EEPROM lock\n");
+ locked = 1;
+ serial_count = 0;
+ }
+ else if ( EEPROM_command_match((char*)serial_buffer,intf->cmd_unlock,strlen((char*)serial_buffer)) )
+ {
+logerror("EEPROM unlock\n");
+ locked = 0;
+ serial_count = 0;
+ }
+}
+
+static void EEPROM_reset(void)
+{
+if (serial_count)
+ logerror("EEPROM reset, buffer = %s\n",serial_buffer);
+
+ serial_count = 0;
+ sending = 0;
+ reset_delay = intf->reset_delay; /* delay a little before returning setting data to 1 (needed by wbeachvl) */
+}
+
+
+void EEPROM_write_bit(int bit)
+{
+#if VERBOSE
+logerror("write bit %d\n",bit);
+#endif
+ latch = bit;
+}
+
+int EEPROM_read_bit(void)
+{
+ int res;
+
+ if (sending)
+ res = (eeprom_data_bits >> intf->data_bits) & 1;
+ else
+ {
+ if (reset_delay > 0)
+ {
+ /* this is needed by wbeachvl */
+ reset_delay--;
+ res = 0;
+ }
+ else
+ res = 1;
+ }
+
+#if VERBOSE
+logerror("read bit %d\n",res);
+#endif
+
+ return res;
+}
+
+void EEPROM_set_cs_line(int state)
+{
+#if VERBOSE
+logerror("set reset line %d\n",state);
+#endif
+ reset_line = state;
+
+ if (reset_line != CLEAR_LINE)
+ EEPROM_reset();
+}
+
+void EEPROM_set_clock_line(int state)
+{
+#if VERBOSE
+logerror("set clock line %d\n",state);
+#endif
+ if (state == PULSE_LINE || (clock_line == CLEAR_LINE && state != CLEAR_LINE))
+ {
+ if (reset_line == CLEAR_LINE)
+ {
+ if (sending)
+ {
+ if (eeprom_clock_count == intf->data_bits && intf->enable_multi_read)
+ {
+ eeprom_read_address = (eeprom_read_address + 1) & ((1 << intf->address_bits) - 1);
+ if (intf->data_bits == 16)
+ eeprom_data_bits = (eeprom_data[2*eeprom_read_address+0] << 8) + eeprom_data[2*eeprom_read_address+1];
+ else
+ eeprom_data_bits = eeprom_data[eeprom_read_address];
+ eeprom_clock_count = 0;
+logerror("EEPROM read %04x from address %02x\n",eeprom_data_bits,eeprom_read_address);
+ }
+ eeprom_data_bits = (eeprom_data_bits << 1) | 1;
+ eeprom_clock_count++;
+ }
+ else
+ EEPROM_write(latch);
+ }
+ }
+
+ clock_line = state;
+}
+
+
+void EEPROM_load(mame_file *f)
+{
+ mame_fread(f,eeprom_data,(1 << intf->address_bits) * intf->data_bits / 8);
+}
+
+void EEPROM_save(mame_file *f)
+{
+ mame_fwrite(f,eeprom_data,(1 << intf->address_bits) * intf->data_bits / 8);
+}
+
+void EEPROM_set_data(const UINT8 *data, int length)
+{
+ memcpy(eeprom_data, data, length);
+}
+
+UINT8 * EEPROM_get_data_pointer(int * length)
+{
+ if(length)
+ *length = MEMORY_SIZE;
+
+ return eeprom_data;
+}
diff --git a/src/emu/machine/eeprom.h b/src/emu/machine/eeprom.h
new file mode 100644
index 00000000000..2e7a69fb609
--- /dev/null
+++ b/src/emu/machine/eeprom.h
@@ -0,0 +1,40 @@
+#ifndef EEPROM_H
+#define EEPROM_H
+
+struct EEPROM_interface
+{
+ int address_bits; /* EEPROM has 2^address_bits cells */
+ int data_bits; /* every cell has this many bits (8 or 16) */
+ const char *cmd_read; /* read command string, e.g. "0110" */
+ const char *cmd_write; /* write command string, e.g. "0111" */
+ const char *cmd_erase; /* erase command string, or 0 if n/a */
+ const char *cmd_lock; /* lock command string, or 0 if n/a */
+ const char *cmd_unlock; /* unlock command string, or 0 if n/a */
+ int enable_multi_read;/* set to 1 to enable multiple values to be read from one read command */
+ int reset_delay; /* number of times EEPROM_read_bit() should return 0 after a reset, */
+ /* before starting to return 1. */
+};
+
+
+void EEPROM_init(struct EEPROM_interface *interface);
+
+void EEPROM_write_bit(int bit);
+int EEPROM_read_bit(void);
+void EEPROM_set_cs_line(int state);
+void EEPROM_set_clock_line(int state);
+
+void EEPROM_load(mame_file *file);
+void EEPROM_save(mame_file *file);
+
+void EEPROM_set_data(const UINT8 *data, int length);
+UINT8 * EEPROM_get_data_pointer(int * length);
+
+/* 93C46 */
+extern struct EEPROM_interface eeprom_interface_93C46;
+NVRAM_HANDLER( 93C46 );
+
+/* 93C66B */
+extern struct EEPROM_interface eeprom_interface_93C66B;
+NVRAM_HANDLER( 93C66B );
+
+#endif
diff --git a/src/emu/machine/generic.c b/src/emu/machine/generic.c
new file mode 100644
index 00000000000..45643b36b11
--- /dev/null
+++ b/src/emu/machine/generic.c
@@ -0,0 +1,820 @@
+/*********************************************************************
+
+ generic.c
+
+ Generic simple machine functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "config.h"
+#include "generic.h"
+#include <stdarg.h>
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* These globals are only kept on a machine basis - LBO 042898 */
+UINT32 dispensed_tickets;
+UINT32 coin_count[COIN_COUNTERS];
+UINT32 coinlockedout[COIN_COUNTERS];
+UINT32 servicecoinlockedout[COIN_COUNTERS];
+static UINT32 lastcoin[COIN_COUNTERS];
+
+/* generic NVRAM */
+size_t generic_nvram_size;
+UINT8 *generic_nvram;
+UINT16 *generic_nvram16;
+UINT32 *generic_nvram32;
+
+/* memory card status */
+static int memcard_inserted;
+
+/* interrupt status */
+static UINT8 interrupt_enable[MAX_CPU];
+
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void counters_load(int config_type, xml_data_node *parentnode);
+static void counters_save(int config_type, xml_data_node *parentnode);
+static void interrupt_reset(running_machine *machine);
+
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ generic_machine_init - initialize globals and
+ register for save states
+-------------------------------------------------*/
+
+void generic_machine_init(running_machine *machine)
+{
+ int counternum;
+
+ /* reset coin counters */
+ for (counternum = 0; counternum < COIN_COUNTERS; counternum++)
+ {
+ lastcoin[counternum] = 0;
+ coinlockedout[counternum] = 0;
+ servicecoinlockedout[counternum] = 0;
+ }
+
+ /* reset NVRAM size and pointers */
+ generic_nvram_size = 0;
+ generic_nvram = NULL;
+ generic_nvram16 = NULL;
+ generic_nvram32 = NULL;
+
+ /* reset memory card info */
+ memcard_inserted = -1;
+
+ /* register a reset callback and save state for interrupt enable */
+ add_reset_callback(machine, interrupt_reset);
+ state_save_register_item_array("cpu", 0, interrupt_enable);
+
+ /* register for configuration */
+ config_register("counters", counters_load, counters_save);
+
+ /* for memory cards, request save state and an exit callback */
+ if (machine->drv->memcard_handler != NULL)
+ {
+ state_save_register_global(memcard_inserted);
+ add_exit_callback(machine, memcard_eject);
+ }
+}
+
+
+
+/***************************************************************************
+ COIN COUNTERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ counters_load - load the state of the counters
+ and tickets
+-------------------------------------------------*/
+
+static void counters_load(int config_type, xml_data_node *parentnode)
+{
+ xml_data_node *coinnode, *ticketnode;
+
+ /* on init, reset the counters */
+ if (config_type == CONFIG_TYPE_INIT)
+ {
+ memset(coin_count, 0, sizeof(coin_count));
+ dispensed_tickets = 0;
+ }
+
+ /* only care about game-specific data */
+ if (config_type != CONFIG_TYPE_GAME)
+ return;
+
+ /* might not have any data */
+ if (!parentnode)
+ return;
+
+ /* iterate over coins nodes */
+ for (coinnode = xml_get_sibling(parentnode->child, "coins"); coinnode; coinnode = xml_get_sibling(coinnode->next, "coins"))
+ {
+ int index = xml_get_attribute_int(coinnode, "index", -1);
+ if (index >= 0 && index < COIN_COUNTERS)
+ coin_count[index] = xml_get_attribute_int(coinnode, "number", 0);
+ }
+
+ /* get the single tickets node */
+ ticketnode = xml_get_sibling(parentnode->child, "tickets");
+ if (ticketnode)
+ dispensed_tickets = xml_get_attribute_int(ticketnode, "number", 0);
+}
+
+
+/*-------------------------------------------------
+ counters_save - save the state of the counters
+ and tickets
+-------------------------------------------------*/
+
+static void counters_save(int config_type, xml_data_node *parentnode)
+{
+ int i;
+
+ /* only care about game-specific data */
+ if (config_type != CONFIG_TYPE_GAME)
+ return;
+
+ /* iterate over coin counters */
+ for (i = 0; i < COIN_COUNTERS; i++)
+ if (coin_count[i] != 0)
+ {
+ xml_data_node *coinnode = xml_add_child(parentnode, "coins", NULL);
+ if (coinnode)
+ {
+ xml_set_attribute_int(coinnode, "index", i);
+ xml_set_attribute_int(coinnode, "number", coin_count[i]);
+ }
+ }
+
+ /* output tickets */
+ if (dispensed_tickets != 0)
+ {
+ xml_data_node *tickets = xml_add_child(parentnode, "tickets", NULL);
+ if (tickets)
+ xml_set_attribute_int(tickets, "number", dispensed_tickets);
+ }
+}
+
+
+/*-------------------------------------------------
+ coin_counter_w - sets input for coin counter
+-------------------------------------------------*/
+
+void coin_counter_w(int num,int on)
+{
+ if (num >= COIN_COUNTERS) return;
+ /* Count it only if the data has changed from 0 to non-zero */
+ if (on && (lastcoin[num] == 0))
+ {
+ coin_count[num]++;
+ }
+ lastcoin[num] = on;
+}
+
+
+/*-------------------------------------------------
+ coin_lockout_w - locks out one coin input
+-------------------------------------------------*/
+
+void coin_lockout_w(int num,int on)
+{
+ if (num >= COIN_COUNTERS) return;
+
+ coinlockedout[num] = on;
+}
+
+
+/*-------------------------------------------------
+ service_coin_lockout_w - locks out one coin input
+-------------------------------------------------*/
+
+void service_coin_lockout_w(int num,int on)
+{
+ if (num >= COIN_COUNTERS) return;
+
+ servicecoinlockedout[num] = on;
+}
+
+
+/*-------------------------------------------------
+ coin_lockout_global_w - locks out all the coin
+ inputs
+-------------------------------------------------*/
+
+void coin_lockout_global_w(int on)
+{
+ int i;
+
+ for (i = 0; i < COIN_COUNTERS; i++)
+ {
+ coin_lockout_w(i,on);
+ }
+}
+
+
+
+/***************************************************************************
+ NVRAM MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ nvram_select - select the right pointer based
+ on which ones are non-NULL
+-------------------------------------------------*/
+
+INLINE void *nvram_select(void)
+{
+ if (generic_nvram)
+ return generic_nvram;
+ if (generic_nvram16)
+ return generic_nvram16;
+ if (generic_nvram32)
+ return generic_nvram32;
+ fatalerror("generic nvram handler called without nvram in the memory map");
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ nvram_fopen - open an NVRAM file directly
+-------------------------------------------------*/
+
+mame_file *nvram_fopen(running_machine *machine, UINT32 openflags)
+{
+ file_error filerr;
+ mame_file *file;
+ astring *fname;
+
+ fname = astring_assemble_2(astring_alloc(), machine->basename, ".nv");
+ filerr = mame_fopen(SEARCHPATH_NVRAM, astring_c(fname), openflags, &file);
+ astring_free(fname);
+
+ return (filerr == FILERR_NONE) ? file : NULL;
+}
+
+
+/*-------------------------------------------------
+ nvram_load - load a system's NVRAM
+-------------------------------------------------*/
+
+void nvram_load(void)
+{
+ if (Machine->drv->nvram_handler != NULL)
+ {
+ mame_file *nvram_file = nvram_fopen(Machine, OPEN_FLAG_READ);
+ (*Machine->drv->nvram_handler)(Machine, nvram_file, 0);
+ if (nvram_file != NULL)
+ mame_fclose(nvram_file);
+ }
+}
+
+
+/*-------------------------------------------------
+ nvram_save - save a system's NVRAM
+-------------------------------------------------*/
+
+void nvram_save(void)
+{
+ if (Machine->drv->nvram_handler != NULL)
+ {
+ mame_file *nvram_file = nvram_fopen(Machine, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ if (nvram_file != NULL)
+ {
+ (*Machine->drv->nvram_handler)(Machine, nvram_file, 1);
+ mame_fclose(nvram_file);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ nvram_handler_generic_0fill - generic NVRAM
+ with a 0 fill
+-------------------------------------------------*/
+
+NVRAM_HANDLER( generic_0fill )
+{
+ if (read_or_write)
+ mame_fwrite(file, nvram_select(), generic_nvram_size);
+ else if (file)
+ mame_fread(file, nvram_select(), generic_nvram_size);
+ else
+ memset(nvram_select(), 0, generic_nvram_size);
+}
+
+
+/*-------------------------------------------------
+ nvram_handler_generic_1fill - generic NVRAM
+ with a 1 fill
+-------------------------------------------------*/
+
+NVRAM_HANDLER( generic_1fill )
+{
+ if (read_or_write)
+ mame_fwrite(file, nvram_select(), generic_nvram_size);
+ else if (file)
+ mame_fread(file, nvram_select(), generic_nvram_size);
+ else
+ memset(nvram_select(), 0xff, generic_nvram_size);
+}
+
+
+/*-------------------------------------------------
+ nvram_handler_generic_randfill - generic NVRAM
+ with a random fill
+-------------------------------------------------*/
+
+NVRAM_HANDLER( generic_randfill )
+{
+ int i;
+
+ if (read_or_write)
+ mame_fwrite(file, nvram_select(), generic_nvram_size);
+ else if (file)
+ mame_fread(file, nvram_select(), generic_nvram_size);
+ else
+ {
+ UINT8 *nvram = nvram_select();
+ for (i = 0; i < generic_nvram_size; i++)
+ nvram[i] = mame_rand(machine);
+ }
+}
+
+
+
+/***************************************************************************
+ MEMORY CARD MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ memcard_name - determine the name of a memcard
+ file
+-------------------------------------------------*/
+
+INLINE void memcard_name(int index, char *buffer)
+{
+ sprintf(buffer, "memcard.%03d", index);
+}
+
+
+/*-------------------------------------------------
+ memcard_create - create a new memory card with
+ the given index
+-------------------------------------------------*/
+
+int memcard_create(int index, int overwrite)
+{
+ file_error filerr;
+ mame_file *file;
+ astring *fname;
+ char name[16];
+
+ /* create a name */
+ memcard_name(index, name);
+
+ /* if we can't overwrite, fail if the file already exists */
+ fname = astring_assemble_3(astring_alloc(), Machine->basename, PATH_SEPARATOR, name);
+ if (!overwrite)
+ {
+ filerr = mame_fopen(SEARCHPATH_MEMCARD, astring_c(fname), OPEN_FLAG_READ, &file);
+ if (filerr == FILERR_NONE)
+ {
+ mame_fclose(file);
+ astring_free(fname);
+ return 1;
+ }
+ }
+
+ /* create a new file */
+ filerr = mame_fopen(SEARCHPATH_MEMCARD, astring_c(fname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
+ astring_free(fname);
+ if (filerr != FILERR_NONE)
+ return 1;
+
+ /* initialize and then save the card */
+ if (Machine->drv->memcard_handler)
+ (*Machine->drv->memcard_handler)(Machine, file, MEMCARD_CREATE);
+
+ /* close the file */
+ mame_fclose(file);
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ memcard_insert - insert an existing memory card
+ with the given index
+-------------------------------------------------*/
+
+int memcard_insert(int index)
+{
+ file_error filerr;
+ mame_file *file;
+ char name[16];
+ astring *fname;
+
+ /* if a card is already inserted, eject it first */
+ if (memcard_inserted != -1)
+ memcard_eject(Machine);
+ assert(memcard_inserted == -1);
+
+ /* create a name */
+ memcard_name(index, name);
+ fname = astring_assemble_3(astring_alloc(), Machine->basename, PATH_SEPARATOR, name);
+
+ /* open the file; if we can't, it's an error */
+ filerr = mame_fopen(SEARCHPATH_MEMCARD, astring_c(fname), OPEN_FLAG_READ, &file);
+ astring_free(fname);
+ if (filerr != FILERR_NONE)
+ return 1;
+
+ /* initialize and then load the card */
+ if (Machine->drv->memcard_handler)
+ (*Machine->drv->memcard_handler)(Machine, file, MEMCARD_INSERT);
+
+ /* close the file */
+ mame_fclose(file);
+ memcard_inserted = index;
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ memcard_eject - eject a memory card, saving
+ its contents along the way
+-------------------------------------------------*/
+
+void memcard_eject(running_machine *machine)
+{
+ file_error filerr;
+ mame_file *file;
+ char name[16];
+ astring *fname;
+
+ /* if no card is preset, just ignore */
+ if (memcard_inserted == -1)
+ return;
+
+ /* create a name */
+ memcard_name(memcard_inserted, name);
+ fname = astring_assemble_3(astring_alloc(), Machine->basename, PATH_SEPARATOR, name);
+
+ /* open the file; if we can't, it's an error */
+ filerr = mame_fopen(SEARCHPATH_MEMCARD, astring_c(fname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
+ astring_free(fname);
+ if (filerr != FILERR_NONE)
+ {
+ mame_fclose(file);
+ return;
+ }
+
+ /* initialize and then load the card */
+ if (machine->drv->memcard_handler)
+ (*machine->drv->memcard_handler)(machine, file, MEMCARD_EJECT);
+
+ /* close the file */
+ mame_fclose(file);
+ memcard_inserted = -1;
+}
+
+
+/*-------------------------------------------------
+ memcard_present - return the currently loaded
+ card index, or -1 if none
+-------------------------------------------------*/
+
+int memcard_present(void)
+{
+ return memcard_inserted;
+}
+
+
+
+/***************************************************************************
+ LED CODE
+***************************************************************************/
+
+/*-------------------------------------------------
+ set_led_status - set the state of a given LED
+-------------------------------------------------*/
+
+void set_led_status(int num, int on)
+{
+ output_set_led_value(num, on);
+}
+
+
+
+/***************************************************************************
+ INTERRUPT ENABLE AND VECTOR HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ interrupt_reset - reset the interrupt enable
+ states on a reset
+-------------------------------------------------*/
+
+static void interrupt_reset(running_machine *machine)
+{
+ int cpunum;
+
+ /* on a reset, enable all interrupts */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ interrupt_enable[cpunum] = 1;
+}
+
+
+/*-------------------------------------------------
+ clear_all_lines - sets the state of all input
+ lines and the NMI line to clear
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( clear_all_lines )
+{
+ int cpunum = param;
+ int inputcount = cpunum_input_lines(cpunum);
+ int line;
+
+ /* clear NMI and all inputs */
+ cpunum_set_input_line(cpunum, INPUT_LINE_NMI, CLEAR_LINE);
+ for (line = 0; line < inputcount; line++)
+ cpunum_set_input_line(cpunum, line, CLEAR_LINE);
+}
+
+
+/*-------------------------------------------------
+ cpu_interrupt_enable - controls the enable/
+ disable value for global interrupts
+-------------------------------------------------*/
+
+void cpu_interrupt_enable(int cpunum, int enabled)
+{
+ assert_always(cpunum >= 0 && cpunum < cpu_gettotalcpu(), "cpu_interrupt_enable() called for invalid cpu num!");
+
+ /* set the new state */
+ interrupt_enable[cpunum] = enabled;
+
+ /* make sure there are no queued interrupts */
+ if (enabled == 0)
+ timer_call_after_resynch(cpunum, clear_all_lines);
+}
+
+
+/*-------------------------------------------------
+ interrupt_enable_w - set the global interrupt
+ enable
+-------------------------------------------------*/
+
+WRITE8_HANDLER( interrupt_enable_w )
+{
+ int activecpu = cpu_getactivecpu();
+ assert_always(activecpu >= 0, "interrupt_enable_w() called with no active cpu!");
+ cpu_interrupt_enable(activecpu, data);
+}
+
+
+/*-------------------------------------------------
+ interrupt_enable_r - read the global interrupt
+ enable
+-------------------------------------------------*/
+
+READ8_HANDLER( interrupt_enable_r )
+{
+ int activecpu = cpu_getactivecpu();
+ assert_always(activecpu >= 0, "interrupt_enable_r() called with no active cpu!");
+ return interrupt_enable[activecpu];
+}
+
+
+
+/***************************************************************************
+ INTERRUPT GENERATION CALLBACK HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ irqn_line_set - set the given IRQ line to the
+ specified state on the active CPU
+-------------------------------------------------*/
+
+INLINE void irqn_line_set(int line, int state)
+{
+ int cpunum = cpu_getactivecpu();
+ if (interrupt_enable[cpunum])
+ cpunum_set_input_line(cpunum, line, state);
+}
+
+
+/*-------------------------------------------------
+ NMI callbacks
+-------------------------------------------------*/
+
+INTERRUPT_GEN( nmi_line_pulse ) { irqn_line_set(INPUT_LINE_NMI, PULSE_LINE); }
+INTERRUPT_GEN( nmi_line_assert ) { irqn_line_set(INPUT_LINE_NMI, ASSERT_LINE); }
+
+
+/*-------------------------------------------------
+ IRQn callbacks
+-------------------------------------------------*/
+
+INTERRUPT_GEN( irq0_line_hold ) { irqn_line_set(0, HOLD_LINE); }
+INTERRUPT_GEN( irq0_line_pulse ) { irqn_line_set(0, PULSE_LINE); }
+INTERRUPT_GEN( irq0_line_assert ) { irqn_line_set(0, ASSERT_LINE); }
+
+INTERRUPT_GEN( irq1_line_hold ) { irqn_line_set(1, HOLD_LINE); }
+INTERRUPT_GEN( irq1_line_pulse ) { irqn_line_set(1, PULSE_LINE); }
+INTERRUPT_GEN( irq1_line_assert ) { irqn_line_set(1, ASSERT_LINE); }
+
+INTERRUPT_GEN( irq2_line_hold ) { irqn_line_set(2, HOLD_LINE); }
+INTERRUPT_GEN( irq2_line_pulse ) { irqn_line_set(2, PULSE_LINE); }
+INTERRUPT_GEN( irq2_line_assert ) { irqn_line_set(2, ASSERT_LINE); }
+
+INTERRUPT_GEN( irq3_line_hold ) { irqn_line_set(3, HOLD_LINE); }
+INTERRUPT_GEN( irq3_line_pulse ) { irqn_line_set(3, PULSE_LINE); }
+INTERRUPT_GEN( irq3_line_assert ) { irqn_line_set(3, ASSERT_LINE); }
+
+INTERRUPT_GEN( irq4_line_hold ) { irqn_line_set(4, HOLD_LINE); }
+INTERRUPT_GEN( irq4_line_pulse ) { irqn_line_set(4, PULSE_LINE); }
+INTERRUPT_GEN( irq4_line_assert ) { irqn_line_set(4, ASSERT_LINE); }
+
+INTERRUPT_GEN( irq5_line_hold ) { irqn_line_set(5, HOLD_LINE); }
+INTERRUPT_GEN( irq5_line_pulse ) { irqn_line_set(5, PULSE_LINE); }
+INTERRUPT_GEN( irq5_line_assert ) { irqn_line_set(5, ASSERT_LINE); }
+
+INTERRUPT_GEN( irq6_line_hold ) { irqn_line_set(6, HOLD_LINE); }
+INTERRUPT_GEN( irq6_line_pulse ) { irqn_line_set(6, PULSE_LINE); }
+INTERRUPT_GEN( irq6_line_assert ) { irqn_line_set(6, ASSERT_LINE); }
+
+INTERRUPT_GEN( irq7_line_hold ) { irqn_line_set(7, HOLD_LINE); }
+INTERRUPT_GEN( irq7_line_pulse ) { irqn_line_set(7, PULSE_LINE); }
+INTERRUPT_GEN( irq7_line_assert ) { irqn_line_set(7, ASSERT_LINE); }
+
+
+
+/***************************************************************************
+ WATCHDOG READ/WRITE HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ 8-bit reset read/write handlers
+-------------------------------------------------*/
+
+WRITE8_HANDLER( watchdog_reset_w ) { watchdog_reset(); }
+READ8_HANDLER( watchdog_reset_r ) { watchdog_reset(); return 0xff; }
+
+
+/*-------------------------------------------------
+ 16-bit reset read/write handlers
+-------------------------------------------------*/
+
+WRITE16_HANDLER( watchdog_reset16_w ) { watchdog_reset(); }
+READ16_HANDLER( watchdog_reset16_r ) { watchdog_reset(); return 0xffff; }
+
+
+/*-------------------------------------------------
+ 32-bit reset read/write handlers
+-------------------------------------------------*/
+
+WRITE32_HANDLER( watchdog_reset32_w ) { watchdog_reset(); }
+READ32_HANDLER( watchdog_reset32_r ) { watchdog_reset(); return 0xffffffff; }
+
+
+
+/***************************************************************************
+ PORT READING HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ 8-bit read handlers
+-------------------------------------------------*/
+
+READ8_HANDLER( input_port_0_r ) { return readinputport(0); }
+READ8_HANDLER( input_port_1_r ) { return readinputport(1); }
+READ8_HANDLER( input_port_2_r ) { return readinputport(2); }
+READ8_HANDLER( input_port_3_r ) { return readinputport(3); }
+READ8_HANDLER( input_port_4_r ) { return readinputport(4); }
+READ8_HANDLER( input_port_5_r ) { return readinputport(5); }
+READ8_HANDLER( input_port_6_r ) { return readinputport(6); }
+READ8_HANDLER( input_port_7_r ) { return readinputport(7); }
+READ8_HANDLER( input_port_8_r ) { return readinputport(8); }
+READ8_HANDLER( input_port_9_r ) { return readinputport(9); }
+READ8_HANDLER( input_port_10_r ) { return readinputport(10); }
+READ8_HANDLER( input_port_11_r ) { return readinputport(11); }
+READ8_HANDLER( input_port_12_r ) { return readinputport(12); }
+READ8_HANDLER( input_port_13_r ) { return readinputport(13); }
+READ8_HANDLER( input_port_14_r ) { return readinputport(14); }
+READ8_HANDLER( input_port_15_r ) { return readinputport(15); }
+READ8_HANDLER( input_port_16_r ) { return readinputport(16); }
+READ8_HANDLER( input_port_17_r ) { return readinputport(17); }
+READ8_HANDLER( input_port_18_r ) { return readinputport(18); }
+READ8_HANDLER( input_port_19_r ) { return readinputport(19); }
+READ8_HANDLER( input_port_20_r ) { return readinputport(20); }
+READ8_HANDLER( input_port_21_r ) { return readinputport(21); }
+READ8_HANDLER( input_port_22_r ) { return readinputport(22); }
+READ8_HANDLER( input_port_23_r ) { return readinputport(23); }
+READ8_HANDLER( input_port_24_r ) { return readinputport(24); }
+READ8_HANDLER( input_port_25_r ) { return readinputport(25); }
+READ8_HANDLER( input_port_26_r ) { return readinputport(26); }
+READ8_HANDLER( input_port_27_r ) { return readinputport(27); }
+READ8_HANDLER( input_port_28_r ) { return readinputport(28); }
+READ8_HANDLER( input_port_29_r ) { return readinputport(29); }
+READ8_HANDLER( input_port_30_r ) { return readinputport(30); }
+READ8_HANDLER( input_port_31_r ) { return readinputport(31); }
+
+
+/*-------------------------------------------------
+ 16-bit read handlers
+-------------------------------------------------*/
+
+READ16_HANDLER( input_port_0_word_r ) { return readinputport(0); }
+READ16_HANDLER( input_port_1_word_r ) { return readinputport(1); }
+READ16_HANDLER( input_port_2_word_r ) { return readinputport(2); }
+READ16_HANDLER( input_port_3_word_r ) { return readinputport(3); }
+READ16_HANDLER( input_port_4_word_r ) { return readinputport(4); }
+READ16_HANDLER( input_port_5_word_r ) { return readinputport(5); }
+READ16_HANDLER( input_port_6_word_r ) { return readinputport(6); }
+READ16_HANDLER( input_port_7_word_r ) { return readinputport(7); }
+READ16_HANDLER( input_port_8_word_r ) { return readinputport(8); }
+READ16_HANDLER( input_port_9_word_r ) { return readinputport(9); }
+READ16_HANDLER( input_port_10_word_r ) { return readinputport(10); }
+READ16_HANDLER( input_port_11_word_r ) { return readinputport(11); }
+READ16_HANDLER( input_port_12_word_r ) { return readinputport(12); }
+READ16_HANDLER( input_port_13_word_r ) { return readinputport(13); }
+READ16_HANDLER( input_port_14_word_r ) { return readinputport(14); }
+READ16_HANDLER( input_port_15_word_r ) { return readinputport(15); }
+READ16_HANDLER( input_port_16_word_r ) { return readinputport(16); }
+READ16_HANDLER( input_port_17_word_r ) { return readinputport(17); }
+READ16_HANDLER( input_port_18_word_r ) { return readinputport(18); }
+READ16_HANDLER( input_port_19_word_r ) { return readinputport(19); }
+READ16_HANDLER( input_port_20_word_r ) { return readinputport(20); }
+READ16_HANDLER( input_port_21_word_r ) { return readinputport(21); }
+READ16_HANDLER( input_port_22_word_r ) { return readinputport(22); }
+READ16_HANDLER( input_port_23_word_r ) { return readinputport(23); }
+READ16_HANDLER( input_port_24_word_r ) { return readinputport(24); }
+READ16_HANDLER( input_port_25_word_r ) { return readinputport(25); }
+READ16_HANDLER( input_port_26_word_r ) { return readinputport(26); }
+READ16_HANDLER( input_port_27_word_r ) { return readinputport(27); }
+READ16_HANDLER( input_port_28_word_r ) { return readinputport(28); }
+READ16_HANDLER( input_port_29_word_r ) { return readinputport(29); }
+READ16_HANDLER( input_port_30_word_r ) { return readinputport(30); }
+READ16_HANDLER( input_port_31_word_r ) { return readinputport(31); }
+
+
+/*-------------------------------------------------
+ 32-bit read handlers
+-------------------------------------------------*/
+
+READ32_HANDLER( input_port_0_dword_r ) { return readinputport(0); }
+READ32_HANDLER( input_port_1_dword_r ) { return readinputport(1); }
+READ32_HANDLER( input_port_2_dword_r ) { return readinputport(2); }
+READ32_HANDLER( input_port_3_dword_r ) { return readinputport(3); }
+READ32_HANDLER( input_port_4_dword_r ) { return readinputport(4); }
+READ32_HANDLER( input_port_5_dword_r ) { return readinputport(5); }
+READ32_HANDLER( input_port_6_dword_r ) { return readinputport(6); }
+READ32_HANDLER( input_port_7_dword_r ) { return readinputport(7); }
+READ32_HANDLER( input_port_8_dword_r ) { return readinputport(8); }
+READ32_HANDLER( input_port_9_dword_r ) { return readinputport(9); }
+READ32_HANDLER( input_port_10_dword_r ) { return readinputport(10); }
+READ32_HANDLER( input_port_11_dword_r ) { return readinputport(11); }
+READ32_HANDLER( input_port_12_dword_r ) { return readinputport(12); }
+READ32_HANDLER( input_port_13_dword_r ) { return readinputport(13); }
+READ32_HANDLER( input_port_14_dword_r ) { return readinputport(14); }
+READ32_HANDLER( input_port_15_dword_r ) { return readinputport(15); }
+READ32_HANDLER( input_port_16_dword_r ) { return readinputport(16); }
+READ32_HANDLER( input_port_17_dword_r ) { return readinputport(17); }
+READ32_HANDLER( input_port_18_dword_r ) { return readinputport(18); }
+READ32_HANDLER( input_port_19_dword_r ) { return readinputport(19); }
+READ32_HANDLER( input_port_20_dword_r ) { return readinputport(20); }
+READ32_HANDLER( input_port_21_dword_r ) { return readinputport(21); }
+READ32_HANDLER( input_port_22_dword_r ) { return readinputport(22); }
+READ32_HANDLER( input_port_23_dword_r ) { return readinputport(23); }
+READ32_HANDLER( input_port_24_dword_r ) { return readinputport(24); }
+READ32_HANDLER( input_port_25_dword_r ) { return readinputport(25); }
+READ32_HANDLER( input_port_26_dword_r ) { return readinputport(26); }
+READ32_HANDLER( input_port_27_dword_r ) { return readinputport(27); }
+READ32_HANDLER( input_port_28_dword_r ) { return readinputport(28); }
+READ32_HANDLER( input_port_29_dword_r ) { return readinputport(29); }
+READ32_HANDLER( input_port_30_dword_r ) { return readinputport(30); }
+READ32_HANDLER( input_port_31_dword_r ) { return readinputport(31); }
+
diff --git a/src/emu/machine/generic.h b/src/emu/machine/generic.h
new file mode 100644
index 00000000000..a9afe14583e
--- /dev/null
+++ b/src/emu/machine/generic.h
@@ -0,0 +1,292 @@
+/*********************************************************************
+
+ generic.h
+
+ Generic simple machine functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __MACHINE_GENERIC_H__
+#define __MACHINE_GENERIC_H__
+
+#include "mamecore.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* total # of coin counters */
+#define COIN_COUNTERS 8
+
+/* memory card actions */
+#define MEMCARD_CREATE 0
+#define MEMCARD_INSERT 1
+#define MEMCARD_EJECT 2
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+extern UINT32 dispensed_tickets;
+extern UINT32 coin_count[COIN_COUNTERS];
+extern UINT32 coinlockedout[COIN_COUNTERS];
+extern UINT32 servicecoinlockedout[COIN_COUNTERS];
+
+extern size_t generic_nvram_size;
+extern UINT8 *generic_nvram;
+extern UINT16 *generic_nvram16;
+extern UINT32 *generic_nvram32;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- initialization ----- */
+
+/* set up all the common systems */
+void generic_machine_init(running_machine *machine);
+
+
+
+/* ----- coin counters ----- */
+
+/* write to a particular coin counter (clocks on active high edge) */
+void coin_counter_w(int num, int on);
+
+/* enable/disable coin lockout for a particular coin */
+void coin_lockout_w(int num, int on);
+
+/* enable/disable coin lockout for a particular coin */
+void service_coin_lockout_w(int num, int on);
+
+/* enable/disable global coin lockout */
+void coin_lockout_global_w(int on);
+
+
+
+/* ----- NVRAM management ----- */
+
+/* open an NVRAM file directly */
+mame_file *nvram_fopen(running_machine *machine, UINT32 openflags);
+
+/* load NVRAM from a file */
+void nvram_load(void);
+
+/* save NVRAM to a file */
+void nvram_save(void);
+
+/* generic NVRAM handler that defaults to a 0 fill */
+NVRAM_HANDLER( generic_0fill );
+
+/* generic NVRAM handler that defaults to a 1 fill */
+NVRAM_HANDLER( generic_1fill );
+
+/* generic NVRAM handler that defaults to a random fill */
+NVRAM_HANDLER( generic_randfill );
+
+
+
+/* ----- memory card management ----- */
+
+/* create a new memory card with the given index */
+int memcard_create(int index, int overwrite);
+
+/* "insert" a memory card with the given index and load its data */
+int memcard_insert(int index);
+
+/* "eject" a memory card and save its data */
+void memcard_eject(running_machine *machine);
+
+/* returns the index of the current memory card, or -1 if none */
+int memcard_present(void);
+
+
+
+/* ----- miscellaneous bits & pieces ----- */
+
+/* set the status of an LED */
+void set_led_status(int num, int value);
+
+
+
+/* ----- interrupt enable and vector helpers ----- */
+
+void cpu_interrupt_enable(int cpu, int enabled);
+READ8_HANDLER( interrupt_enable_r );
+WRITE8_HANDLER( interrupt_enable_w );
+
+
+
+/* ----- common interrupt callbacks ----- */
+
+INTERRUPT_GEN( nmi_line_pulse );
+INTERRUPT_GEN( nmi_line_assert );
+
+INTERRUPT_GEN( irq0_line_hold );
+INTERRUPT_GEN( irq0_line_pulse );
+INTERRUPT_GEN( irq0_line_assert );
+
+INTERRUPT_GEN( irq1_line_hold );
+INTERRUPT_GEN( irq1_line_pulse );
+INTERRUPT_GEN( irq1_line_assert );
+
+INTERRUPT_GEN( irq2_line_hold );
+INTERRUPT_GEN( irq2_line_pulse );
+INTERRUPT_GEN( irq2_line_assert );
+
+INTERRUPT_GEN( irq3_line_hold );
+INTERRUPT_GEN( irq3_line_pulse );
+INTERRUPT_GEN( irq3_line_assert );
+
+INTERRUPT_GEN( irq4_line_hold );
+INTERRUPT_GEN( irq4_line_pulse );
+INTERRUPT_GEN( irq4_line_assert );
+
+INTERRUPT_GEN( irq5_line_hold );
+INTERRUPT_GEN( irq5_line_pulse );
+INTERRUPT_GEN( irq5_line_assert );
+
+INTERRUPT_GEN( irq6_line_hold );
+INTERRUPT_GEN( irq6_line_pulse );
+INTERRUPT_GEN( irq6_line_assert );
+
+INTERRUPT_GEN( irq7_line_hold );
+INTERRUPT_GEN( irq7_line_pulse );
+INTERRUPT_GEN( irq7_line_assert );
+
+
+
+/* ----- generic watchdog reset handlers ----- */
+
+/* 8-bit watchdog read/write handlers */
+WRITE8_HANDLER( watchdog_reset_w );
+READ8_HANDLER( watchdog_reset_r );
+
+/* 16-bit watchdog read/write handlers */
+WRITE16_HANDLER( watchdog_reset16_w );
+READ16_HANDLER( watchdog_reset16_r );
+
+/* 32-bit watchdog read/write handlers */
+WRITE32_HANDLER( watchdog_reset32_w );
+READ32_HANDLER( watchdog_reset32_r );
+
+
+
+/* ----- generic input port read handlers ----- */
+
+/* 8-bit handlers */
+READ8_HANDLER( input_port_0_r );
+READ8_HANDLER( input_port_1_r );
+READ8_HANDLER( input_port_2_r );
+READ8_HANDLER( input_port_3_r );
+READ8_HANDLER( input_port_4_r );
+READ8_HANDLER( input_port_5_r );
+READ8_HANDLER( input_port_6_r );
+READ8_HANDLER( input_port_7_r );
+READ8_HANDLER( input_port_8_r );
+READ8_HANDLER( input_port_9_r );
+READ8_HANDLER( input_port_10_r );
+READ8_HANDLER( input_port_11_r );
+READ8_HANDLER( input_port_12_r );
+READ8_HANDLER( input_port_13_r );
+READ8_HANDLER( input_port_14_r );
+READ8_HANDLER( input_port_15_r );
+READ8_HANDLER( input_port_16_r );
+READ8_HANDLER( input_port_17_r );
+READ8_HANDLER( input_port_18_r );
+READ8_HANDLER( input_port_19_r );
+READ8_HANDLER( input_port_20_r );
+READ8_HANDLER( input_port_21_r );
+READ8_HANDLER( input_port_22_r );
+READ8_HANDLER( input_port_23_r );
+READ8_HANDLER( input_port_24_r );
+READ8_HANDLER( input_port_25_r );
+READ8_HANDLER( input_port_26_r );
+READ8_HANDLER( input_port_27_r );
+READ8_HANDLER( input_port_28_r );
+READ8_HANDLER( input_port_29_r );
+READ8_HANDLER( input_port_30_r );
+READ8_HANDLER( input_port_31_r );
+
+/* 16-bit handlers */
+READ16_HANDLER( input_port_0_word_r );
+READ16_HANDLER( input_port_1_word_r );
+READ16_HANDLER( input_port_2_word_r );
+READ16_HANDLER( input_port_3_word_r );
+READ16_HANDLER( input_port_4_word_r );
+READ16_HANDLER( input_port_5_word_r );
+READ16_HANDLER( input_port_6_word_r );
+READ16_HANDLER( input_port_7_word_r );
+READ16_HANDLER( input_port_8_word_r );
+READ16_HANDLER( input_port_9_word_r );
+READ16_HANDLER( input_port_10_word_r );
+READ16_HANDLER( input_port_11_word_r );
+READ16_HANDLER( input_port_12_word_r );
+READ16_HANDLER( input_port_13_word_r );
+READ16_HANDLER( input_port_14_word_r );
+READ16_HANDLER( input_port_15_word_r );
+READ16_HANDLER( input_port_16_word_r );
+READ16_HANDLER( input_port_17_word_r );
+READ16_HANDLER( input_port_18_word_r );
+READ16_HANDLER( input_port_19_word_r );
+READ16_HANDLER( input_port_20_word_r );
+READ16_HANDLER( input_port_21_word_r );
+READ16_HANDLER( input_port_22_word_r );
+READ16_HANDLER( input_port_23_word_r );
+READ16_HANDLER( input_port_24_word_r );
+READ16_HANDLER( input_port_25_word_r );
+READ16_HANDLER( input_port_26_word_r );
+READ16_HANDLER( input_port_27_word_r );
+READ16_HANDLER( input_port_28_word_r );
+READ16_HANDLER( input_port_29_word_r );
+READ16_HANDLER( input_port_30_word_r );
+READ16_HANDLER( input_port_31_word_r );
+
+/* 32-bit handlers */
+READ32_HANDLER( input_port_0_dword_r );
+READ32_HANDLER( input_port_1_dword_r );
+READ32_HANDLER( input_port_2_dword_r );
+READ32_HANDLER( input_port_3_dword_r );
+READ32_HANDLER( input_port_4_dword_r );
+READ32_HANDLER( input_port_5_dword_r );
+READ32_HANDLER( input_port_6_dword_r );
+READ32_HANDLER( input_port_7_dword_r );
+READ32_HANDLER( input_port_8_dword_r );
+READ32_HANDLER( input_port_9_dword_r );
+READ32_HANDLER( input_port_10_dword_r );
+READ32_HANDLER( input_port_11_dword_r );
+READ32_HANDLER( input_port_12_dword_r );
+READ32_HANDLER( input_port_13_dword_r );
+READ32_HANDLER( input_port_14_dword_r );
+READ32_HANDLER( input_port_15_dword_r );
+READ32_HANDLER( input_port_16_dword_r );
+READ32_HANDLER( input_port_17_dword_r );
+READ32_HANDLER( input_port_18_dword_r );
+READ32_HANDLER( input_port_19_dword_r );
+READ32_HANDLER( input_port_20_dword_r );
+READ32_HANDLER( input_port_21_dword_r );
+READ32_HANDLER( input_port_22_dword_r );
+READ32_HANDLER( input_port_23_dword_r );
+READ32_HANDLER( input_port_24_dword_r );
+READ32_HANDLER( input_port_25_dword_r );
+READ32_HANDLER( input_port_26_dword_r );
+READ32_HANDLER( input_port_27_dword_r );
+READ32_HANDLER( input_port_28_dword_r );
+READ32_HANDLER( input_port_29_dword_r );
+READ32_HANDLER( input_port_30_dword_r );
+READ32_HANDLER( input_port_31_dword_r );
+
+
+#endif /* __MACHINE_GENERIC_H__ */
diff --git a/src/emu/machine/i2cmem.c b/src/emu/machine/i2cmem.c
new file mode 100644
index 00000000000..2764c042256
--- /dev/null
+++ b/src/emu/machine/i2cmem.c
@@ -0,0 +1,438 @@
+/*
+
+I2C Memory
+
+Generic ram/rom/eeprom/flash on an i2c bus. Supports specifying the slave address,
+the data size & the page size for writing.
+
+inputs:
+ e0,e1,e2 lower 3 bits of the slave address
+ sda serial data
+ scl serial clock
+ wc write protect
+
+outputs:
+ sda serial data
+
+The memory address is only 8 bits, devices larger than this have multiple slave addresses.
+The top five address bits are set at manufacture time, two values are standard.
+Up to 4096 bytes can be addressed.
+
+*/
+
+#include <driver.h>
+#include "machine/i2cmem.h"
+
+#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 i2cmem_chip
+{
+ int slave_address;
+ int scl;
+ int sdaw;
+ int e0;
+ int e1;
+ int e2;
+ int wc;
+ int sdar;
+ int state;
+ int bits;
+ int shift;
+ int devsel;
+ int byteaddr;
+ unsigned char *data;
+ int data_size;
+ unsigned char *page;
+ int page_offset;
+ int page_size;
+};
+
+#define STATE_IDLE ( 0 )
+#define STATE_DEVSEL ( 1 )
+#define STATE_BYTEADDR ( 2 )
+#define STATE_DATAIN ( 3 )
+#define STATE_DATAOUT ( 4 )
+
+#define DEVSEL_RW ( 1 )
+#define DEVSEL_ADDRESS ( 0xfe )
+
+static struct i2cmem_chip i2cmem[ I2CMEM_MAXCHIP ];
+
+void i2cmem_init( int chip, int slave_address, int page_size, int data_size, unsigned char *data )
+{
+ struct i2cmem_chip *c;
+ unsigned char *page = NULL;
+
+ if( chip >= I2CMEM_MAXCHIP )
+ {
+ verboselog( 0, "i2cmem_init( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &i2cmem[ chip ];
+
+ if( data == NULL )
+ {
+ data = auto_malloc( data_size );
+ }
+
+ if( page_size > 0 )
+ {
+ page = auto_malloc( page_size );
+ }
+
+ c->slave_address = slave_address;
+ c->data_size = data_size;
+ c->page_size = page_size;
+
+ c->scl = 0;
+ c->sdaw = 0;
+ c->e0 = 0;
+ c->e1 = 0;
+ c->e2 = 0;
+ c->wc = 0;
+ c->sdar = 1;
+ c->state = STATE_IDLE;
+ c->bits = 0;
+ c->shift = 0;
+ c->devsel = 0;
+ c->byteaddr = 0;
+ c->data = data;
+ c->page = page;
+
+ state_save_register_item( "i2cmem", chip, c->scl );
+ state_save_register_item( "i2cmem", chip, c->sdaw );
+ state_save_register_item( "i2cmem", chip, c->e0 );
+ state_save_register_item( "i2cmem", chip, c->e1 );
+ state_save_register_item( "i2cmem", chip, c->e2 );
+ state_save_register_item( "i2cmem", chip, c->wc );
+ state_save_register_item( "i2cmem", chip, c->sdar );
+ state_save_register_item( "i2cmem", chip, c->state );
+ state_save_register_item( "i2cmem", chip, c->bits );
+ state_save_register_item( "i2cmem", chip, c->shift );
+ state_save_register_item( "i2cmem", chip, c->devsel );
+ state_save_register_item( "i2cmem", chip, c->byteaddr );
+ state_save_register_item_pointer( "i2cmem", chip, c->data, c->data_size );
+}
+
+static int select_device( struct i2cmem_chip *c )
+{
+ int device = ( c->slave_address & 0xf0 ) | ( c->e2 << 3 ) | ( c->e1 << 2 ) | ( c->e0 << 1 );
+ int mask = DEVSEL_ADDRESS & ~( ( c->data_size - 1 ) >> 7 );
+
+ if( ( c->devsel & mask ) == ( device & mask ) )
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int data_offset( struct i2cmem_chip *c )
+{
+ return ( ( ( c->devsel << 7 ) & 0xff00 ) | ( c->byteaddr & 0xff ) ) & ( c->data_size - 1 );
+}
+
+void i2cmem_write( int chip, int line, int data )
+{
+ struct i2cmem_chip *c;
+
+ if( chip >= I2CMEM_MAXCHIP )
+ {
+ verboselog( 0, "i2cmem_write( %d, %d, %d ) invalid chip\n", chip, line, data );
+ return;
+ }
+
+ c = &i2cmem[ chip ];
+
+ data &= 1;
+
+ switch( line )
+ {
+ case I2CMEM_E0:
+ if( c->e0 != data )
+ {
+ c->e0 = data;
+ verboselog( 2, "i2cmem_write( %d, I2CMEM_E0, %d )\n", chip, c->e0 );
+ }
+ break;
+
+ case I2CMEM_E1:
+ if( c->e1 != data )
+ {
+ c->e1 = data;
+ verboselog( 2, "i2cmem_write( %d, I2CMEM_E1, %d )\n", chip, c->e1 );
+ }
+ break;
+
+ case I2CMEM_E2:
+ if( c->e2 != data )
+ {
+ c->e2 = data;
+ verboselog( 2, "i2cmem_write( %d, I2CMEM_E2, %d )\n", chip, c->e2 );
+ }
+ break;
+
+ case I2CMEM_SDA:
+ if( c->sdaw != data )
+ {
+ c->sdaw = data;
+ verboselog( 2, "i2cmem_write( %d, I2CMEM_SDA, %d )\n", chip, c->sdaw );
+
+ if( c->scl )
+ {
+ if( c->sdaw )
+ {
+ verboselog( 1, "i2cmem(%d) stop\n", chip );
+ c->state = STATE_IDLE;
+ c->byteaddr = 0;
+ }
+ else
+ {
+ verboselog( 2, "i2cmem(%d) start\n", chip );
+ c->state = STATE_DEVSEL;
+ c->bits = 0;
+ }
+
+ c->sdar = 1;
+ }
+ }
+ break;
+
+ case I2CMEM_SCL:
+ if( c->scl != data )
+ {
+ c->scl = data;
+ verboselog( 2, "i2cmem_write( %d, I2CMEM_SCL, %d )\n", chip, c->scl );
+
+ switch( c->state )
+ {
+ case STATE_DEVSEL:
+ case STATE_BYTEADDR:
+ case STATE_DATAIN:
+ if( c->bits < 8 )
+ {
+ if( c->scl )
+ {
+ c->shift = ( ( c->shift << 1 ) | c->sdaw ) & 0xff;
+ c->bits++;
+ }
+ }
+ else
+ {
+ if( c->scl )
+ {
+ switch( c->state )
+ {
+ case STATE_DEVSEL:
+ c->devsel = c->shift;
+
+ if( !select_device( c ) )
+ {
+ verboselog( 1, "i2cmem(%d) devsel %02x: not this device\n", chip, c->devsel );
+ c->state = STATE_IDLE;
+ }
+ else if( ( c->devsel & DEVSEL_RW ) == 0 )
+ {
+ verboselog( 1, "i2cmem(%d) devsel %02x: write\n", chip, c->devsel );
+ c->state = STATE_BYTEADDR;
+ }
+ else
+ {
+ verboselog( 1, "i2cmem(%d) devsel %02x: read\n", chip, c->devsel );
+ c->state = STATE_DATAOUT;
+ }
+ break;
+
+ case STATE_BYTEADDR:
+ c->byteaddr = c->shift;
+ c->page_offset = 0;
+
+ verboselog( 1, "i2cmem(%d) byteaddr %02x\n", chip, c->byteaddr );
+
+ c->state = STATE_DATAIN;
+ break;
+
+ case STATE_DATAIN:
+ if( c->wc )
+ {
+ verboselog( 0, "i2cmem(%d) write not enabled\n", chip );
+ c->state = STATE_IDLE;
+ }
+ else if( c->page_size > 0 )
+ {
+ c->page[ c->page_offset ] = c->shift;
+ verboselog( 1, "i2cmem(%d) page[ %04x ] <- %02x\n", chip, c->page_offset, c->page[ c->page_offset ] );
+
+ c->page_offset++;
+ if( c->page_offset == c->page_size )
+ {
+ int offset = data_offset( c ) & ~( c->page_size - 1 );
+
+ memcpy( &c->data[ offset ], c->page, c->page_size );
+ verboselog( 1, "i2cmem(%d) data[ %04x to %04x ] = page\n", chip, offset, offset + c->page_size - 1 );
+
+ c->page_offset = 0;
+ }
+ }
+ else
+ {
+ int offset = data_offset( c );
+
+ c->data[ offset ] = c->shift;
+ verboselog( 1, "i2cmem(%d) data[ %04x ] <- %02x\n", chip, offset, c->data[ offset ] );
+
+ c->byteaddr++;
+ }
+ break;
+ }
+
+ c->bits++;
+ }
+ else
+ {
+ if( c->bits == 8 )
+ {
+ c->sdar = 0;
+ }
+ else
+ {
+ c->bits = 0;
+ c->sdar = 1;
+ }
+ }
+ }
+ break;
+
+ case STATE_DATAOUT:
+ if( c->bits < 8 )
+ {
+ if( c->scl )
+ {
+ if( c->bits == 0 )
+ {
+ int offset = data_offset( c );
+
+ c->shift = c->data[ offset ];
+ verboselog( 1, "i2cmem(%d) data[ %04x ] -> %02x\n", chip, offset, c->data[ offset ] );
+ c->byteaddr++;
+ }
+
+ c->sdar = ( c->shift >> 7 ) & 1;
+
+ c->shift = ( c->shift << 1 ) & 0xff;
+ c->bits++;
+ }
+ }
+ else
+ {
+ if( c->scl )
+ {
+ if( c->sdaw )
+ {
+ verboselog( 1, "i2cmem(%d) sleep\n", chip );
+ c->state = STATE_IDLE;
+ }
+
+ c->bits++;
+ }
+ else
+ {
+ if( c->bits == 8 )
+ {
+ c->sdar = 1;
+ }
+ else
+ {
+ c->bits = 0;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case I2CMEM_WC:
+ if( c->wc != data )
+ {
+ c->wc = data;
+ verboselog( 2, "i2cmem_write( %d, I2CMEM_WC, %d )\n", chip, c->wc );
+ }
+ break;
+
+ default:
+ verboselog( 0, "i2cmem_write( %d, %d, %d ) invalid line\n", chip, line, data );
+ break;
+ }
+}
+
+int i2cmem_read( int chip, int line )
+{
+ struct i2cmem_chip *c;
+
+ if( chip >= I2CMEM_MAXCHIP )
+ {
+ verboselog( 0, "i2cmem_read( %d, %d ) invalid chip\n", chip, line );
+ return 0;
+ }
+
+ c = &i2cmem[ chip ];
+
+ switch( line )
+ {
+ case I2CMEM_SDA:
+ verboselog( 2, "i2cmem_read( %d, I2CMEM_SDA ) %d\n", chip, c->sdar & c->sdaw );
+ return c->sdar & c->sdaw;
+
+ default:
+ verboselog( 0, "i2cmem_read( %d, %d ) invalid line\n", chip, line );
+ break;
+ }
+
+ return 0;
+}
+
+static void nvram_handler_i2cmem( int chip, running_machine *machine, mame_file *file, int read_or_write )
+{
+ struct i2cmem_chip *c;
+
+ if( chip >= I2CMEM_MAXCHIP )
+ {
+ verboselog( 0, "nvram_handler_i2cmem( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &i2cmem[ chip ];
+
+ if( read_or_write )
+ {
+ mame_fwrite( file, c->data, c->data_size );
+ }
+ else if( file )
+ {
+ mame_fread( file, c->data, c->data_size );
+ }
+}
+
+NVRAM_HANDLER( i2cmem_0 ) { nvram_handler_i2cmem( 0, machine, file, read_or_write ); }
diff --git a/src/emu/machine/i2cmem.h b/src/emu/machine/i2cmem.h
new file mode 100644
index 00000000000..1a8eb3680a1
--- /dev/null
+++ b/src/emu/machine/i2cmem.h
@@ -0,0 +1,27 @@
+/*
+
+I2C Memory
+
+*/
+
+#if !defined( I2CMEM_H )
+#define I2CMEM_H ( 1 )
+
+#define I2CMEM_E0 ( 1 )
+#define I2CMEM_E1 ( 2 )
+#define I2CMEM_E2 ( 3 )
+#define I2CMEM_SDA ( 5 )
+#define I2CMEM_SCL ( 6 )
+#define I2CMEM_WC ( 7 )
+
+#define I2CMEM_MAXCHIP ( 1 )
+
+#define I2CMEM_SLAVE_ADDRESS ( 0xa0 )
+#define I2CMEM_SLAVE_ADDRESS_ALT ( 0xb0 )
+
+extern void i2cmem_init( int chip, int slave_address, int page_size, int data_size, unsigned char *data );
+extern void i2cmem_write( int chip, int line, int data );
+extern int i2cmem_read( int chip, int line );
+extern NVRAM_HANDLER( i2cmem_0 );
+
+#endif
diff --git a/src/emu/machine/idectrl.c b/src/emu/machine/idectrl.c
new file mode 100644
index 00000000000..e965186b0ab
--- /dev/null
+++ b/src/emu/machine/idectrl.c
@@ -0,0 +1,1793 @@
+/***************************************************************************
+
+ Generic (PC-style) IDE controller implementation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "idectrl.h"
+#include "debugger.h"
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define VERBOSE 0
+#define PRINTF_IDE_COMMANDS 0
+#define PRINTF_IDE_PASSWORD 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(X)
+#endif
+
+#if (VERBOSE && PRINTF_IDE_COMMANDS)
+#define LOGPRINT(x) logerror x; mame_printf_debug x
+#elif PRINTF_IDE_COMMANDS
+#define LOGPRINT(x) mame_printf_debug x
+#else
+#define LOGPRINT(X)
+#endif
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define IDE_DISK_SECTOR_SIZE 512
+
+#define MINIMUM_COMMAND_TIME (ATTOTIME_IN_USEC(10))
+
+#define TIME_PER_SECTOR (ATTOTIME_IN_USEC(100))
+#define TIME_PER_ROTATION (ATTOTIME_IN_HZ(5400/60))
+#define TIME_SECURITY_ERROR (ATTOTIME_IN_MSEC(1000))
+
+#define TIME_SEEK_MULTISECTOR (ATTOTIME_IN_MSEC(13))
+#define TIME_NO_SEEK_MULTISECTOR (ATTOTIME_IN_NSEC(16300))
+
+#define IDE_STATUS_ERROR 0x01
+#define IDE_STATUS_HIT_INDEX 0x02
+#define IDE_STATUS_BUFFER_READY 0x08
+#define IDE_STATUS_SEEK_COMPLETE 0x10
+#define IDE_STATUS_DRIVE_READY 0x40
+#define IDE_STATUS_BUSY 0x80
+
+#define IDE_CONFIG_REGISTERS 0x10
+
+#define IDE_ADDR_CONFIG_UNK 0x034
+#define IDE_ADDR_CONFIG_REGISTER 0x038
+#define IDE_ADDR_CONFIG_DATA 0x03c
+
+#define IDE_ADDR_DATA 0x1f0
+#define IDE_ADDR_ERROR 0x1f1
+#define IDE_ADDR_SECTOR_COUNT 0x1f2
+#define IDE_ADDR_SECTOR_NUMBER 0x1f3
+#define IDE_ADDR_CYLINDER_LSB 0x1f4
+#define IDE_ADDR_CYLINDER_MSB 0x1f5
+#define IDE_ADDR_HEAD_NUMBER 0x1f6
+#define IDE_ADDR_STATUS_COMMAND 0x1f7
+
+#define IDE_ADDR_STATUS_CONTROL 0x3f6
+
+#define IDE_COMMAND_READ_MULTIPLE 0x20
+#define IDE_COMMAND_READ_MULTIPLE_ONCE 0x21
+#define IDE_COMMAND_WRITE_MULTIPLE 0x30
+#define IDE_COMMAND_SET_CONFIG 0x91
+#define IDE_COMMAND_READ_MULTIPLE_BLOCK 0xc4
+#define IDE_COMMAND_WRITE_MULTIPLE_BLOCK 0xc5
+#define IDE_COMMAND_SET_BLOCK_COUNT 0xc6
+#define IDE_COMMAND_READ_DMA 0xc8
+#define IDE_COMMAND_WRITE_DMA 0xca
+#define IDE_COMMAND_GET_INFO 0xec
+#define IDE_COMMAND_SET_FEATURES 0xef
+#define IDE_COMMAND_SECURITY_UNLOCK 0xf2
+#define IDE_COMMAND_UNKNOWN_F9 0xf9
+#define IDE_COMMAND_VERIFY_MULTIPLE 0x40
+#define IDE_COMMAND_ATAPI_IDENTIFY 0xa1
+#define IDE_COMMAND_RECALIBRATE 0x10
+#define IDE_COMMAND_IDLE_IMMEDIATE 0xe1
+
+#define IDE_ERROR_NONE 0x00
+#define IDE_ERROR_DEFAULT 0x01
+#define IDE_ERROR_UNKNOWN_COMMAND 0x04
+#define IDE_ERROR_BAD_LOCATION 0x10
+#define IDE_ERROR_BAD_SECTOR 0x80
+
+#define IDE_BUSMASTER_STATUS_ACTIVE 0x01
+#define IDE_BUSMASTER_STATUS_ERROR 0x02
+#define IDE_BUSMASTER_STATUS_IRQ 0x04
+
+
+
+/*************************************
+ *
+ * Type definitions
+ *
+ *************************************/
+
+struct ide_state
+{
+ UINT8 adapter_control;
+ UINT8 status;
+ UINT8 error;
+ UINT8 command;
+ UINT8 interrupt_pending;
+ UINT8 precomp_offset;
+
+ UINT8 buffer[IDE_DISK_SECTOR_SIZE];
+ UINT8 features[IDE_DISK_SECTOR_SIZE];
+ UINT16 buffer_offset;
+ UINT16 sector_count;
+
+ UINT16 block_count;
+ UINT16 sectors_until_int;
+ UINT8 verify_only;
+
+ UINT8 dma_active;
+ UINT8 dma_cpu;
+ UINT8 dma_address_xor;
+ UINT8 dma_last_buffer;
+ offs_t dma_address;
+ offs_t dma_descriptor;
+ UINT32 dma_bytes_left;
+
+ UINT8 bus_master_command;
+ UINT8 bus_master_status;
+ UINT32 bus_master_descriptor;
+
+ UINT16 cur_cylinder;
+ UINT8 cur_sector;
+ UINT8 cur_head;
+ UINT8 cur_head_reg;
+
+ UINT32 cur_lba;
+
+ UINT16 num_cylinders;
+ UINT8 num_sectors;
+ UINT8 num_heads;
+
+ UINT8 config_unknown;
+ UINT8 config_register[IDE_CONFIG_REGISTERS];
+ UINT8 config_register_num;
+
+ struct ide_interface *intf;
+ hard_disk_file * disk;
+ emu_timer * last_status_timer;
+ emu_timer * reset_timer;
+
+ UINT8 master_password_enable;
+ UINT8 user_password_enable;
+ UINT8 * master_password;
+ UINT8 * user_password;
+};
+
+
+
+/*************************************
+ *
+ * Local variables
+ *
+ *************************************/
+
+static struct ide_state idestate[MAX_IDE_CONTROLLERS];
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static TIMER_CALLBACK_PTR( reset_callback );
+
+static void ide_build_features(struct ide_state *ide);
+
+static void continue_read(struct ide_state *ide);
+static void read_sector_done(struct ide_state *ide);
+static TIMER_CALLBACK_PTR( read_sector_done_callback );
+static void read_first_sector(struct ide_state *ide);
+static void read_next_sector(struct ide_state *ide);
+
+static UINT32 ide_controller_read(struct ide_state *ide, offs_t offset, int size);
+static void ide_controller_write(struct ide_state *ide, offs_t offset, int size, UINT32 data);
+
+
+
+/*************************************
+ *
+ * Interrupts
+ *
+ *************************************/
+
+INLINE void signal_interrupt(struct ide_state *ide)
+{
+ LOG(("IDE interrupt assert\n"));
+
+ /* signal an interrupt */
+ if (ide->intf->interrupt)
+ (*ide->intf->interrupt)(ASSERT_LINE);
+ ide->interrupt_pending = 1;
+ ide->bus_master_status |= IDE_BUSMASTER_STATUS_IRQ;
+}
+
+
+INLINE void clear_interrupt(struct ide_state *ide)
+{
+ LOG(("IDE interrupt clear\n"));
+
+ /* clear an interrupt */
+ if (ide->intf->interrupt)
+ (*ide->intf->interrupt)(CLEAR_LINE);
+ ide->interrupt_pending = 0;
+}
+
+
+
+/*************************************
+ *
+ * Delayed interrupt handling
+ *
+ *************************************/
+
+static TIMER_CALLBACK_PTR( delayed_interrupt )
+{
+ struct ide_state *ide = param;
+ ide->status &= ~IDE_STATUS_BUSY;
+ signal_interrupt(ide);
+}
+
+
+static TIMER_CALLBACK_PTR( delayed_interrupt_buffer_ready )
+{
+ struct ide_state *ide = param;
+ ide->status &= ~IDE_STATUS_BUSY;
+ ide->status |= IDE_STATUS_BUFFER_READY;
+ signal_interrupt(ide);
+}
+
+
+INLINE void signal_delayed_interrupt(struct ide_state *ide, attotime time, int buffer_ready)
+{
+ /* clear buffer ready and set the busy flag */
+ ide->status &= ~IDE_STATUS_BUFFER_READY;
+ ide->status |= IDE_STATUS_BUSY;
+
+ /* set a timer */
+ if (buffer_ready)
+ timer_set_ptr(time, ide, delayed_interrupt_buffer_ready);
+ else
+ timer_set_ptr(time, ide, delayed_interrupt);
+}
+
+
+
+/*************************************
+ *
+ * Initialization & reset
+ *
+ *************************************/
+
+static void ide_controller_exit(running_machine *machine)
+{
+ int i;
+
+ /* close all open hard disks */
+ for (i = 0; i < MAX_IDE_CONTROLLERS; i++)
+ if (idestate[i].disk)
+ {
+ hard_disk_close(idestate[i].disk);
+ idestate[i].disk = NULL;
+ }
+}
+
+
+int ide_controller_init_custom(int which, struct ide_interface *intf, chd_file *diskhandle)
+{
+ struct ide_state *ide = &idestate[which];
+ const hard_disk_info *hdinfo;
+
+ /* must be called during init phase */
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "ide_controller_init can only be called at init time");
+ add_exit_callback(Machine, ide_controller_exit);
+
+ /* NULL interface is immediate failure */
+ if (!intf)
+ return 1;
+
+ /* reset the IDE state */
+ memset(ide, 0, sizeof(*ide));
+ ide->intf = intf;
+
+ /* set MAME harddisk handle */
+ ide->disk = hard_disk_open(diskhandle);
+
+ /* get and copy the geometry */
+ if (ide->disk)
+ {
+ hdinfo = hard_disk_get_info(ide->disk);
+ ide->num_cylinders = hdinfo->cylinders;
+ ide->num_sectors = hdinfo->sectors;
+ ide->num_heads = hdinfo->heads;
+ if (hdinfo->sectorbytes != IDE_DISK_SECTOR_SIZE)
+ /* wrong sector len */
+ return 1;
+#if PRINTF_IDE_COMMANDS
+ mame_printf_debug("CHS: %d %d %d\n", ide->num_cylinders, ide->num_heads, ide->num_sectors);
+#endif
+ }
+
+ /* build the features page */
+ ide_build_features(ide);
+
+ /* create a timer for timing status */
+ ide->last_status_timer = timer_alloc(NULL);
+ ide->reset_timer = timer_alloc_ptr(reset_callback, ide);
+
+ /* register ide status */
+ state_save_register_item("ide", which, ide->adapter_control);
+ state_save_register_item("ide", which, ide->status);
+ state_save_register_item("ide", which, ide->error);
+ state_save_register_item("ide", which, ide->command);
+ state_save_register_item("ide", which, ide->interrupt_pending);
+ state_save_register_item("ide", which, ide->precomp_offset);
+
+ state_save_register_item_array("ide", which, ide->buffer);
+ state_save_register_item_array("ide", which, ide->features);
+ state_save_register_item("ide", which, ide->buffer_offset);
+ state_save_register_item("ide", which, ide->sector_count);
+
+ state_save_register_item("ide", which, ide->block_count);
+ state_save_register_item("ide", which, ide->sectors_until_int);
+
+ state_save_register_item("ide", which, ide->dma_active);
+ state_save_register_item("ide", which, ide->dma_cpu);
+ state_save_register_item("ide", which, ide->dma_address_xor);
+ state_save_register_item("ide", which, ide->dma_last_buffer);
+ state_save_register_item("ide", which, ide->dma_address);
+ state_save_register_item("ide", which, ide->dma_descriptor);
+ state_save_register_item("ide", which, ide->dma_bytes_left);
+
+ state_save_register_item("ide", which, ide->bus_master_command);
+ state_save_register_item("ide", which, ide->bus_master_status);
+ state_save_register_item("ide", which, ide->bus_master_descriptor);
+
+ state_save_register_item("ide", which, ide->cur_cylinder);
+ state_save_register_item("ide", which, ide->cur_sector);
+ state_save_register_item("ide", which, ide->cur_head);
+ state_save_register_item("ide", which, ide->cur_head_reg);
+
+ state_save_register_item("ide", which, ide->cur_lba);
+
+ state_save_register_item("ide", which, ide->num_cylinders);
+ state_save_register_item("ide", which, ide->num_sectors);
+ state_save_register_item("ide", which, ide->num_heads);
+
+ state_save_register_item("ide", which, ide->config_unknown);
+ state_save_register_item_array("ide", which, ide->config_register);
+ state_save_register_item("ide", which, ide->config_register_num);
+
+ state_save_register_item("ide", which, ide->master_password_enable);
+ state_save_register_item("ide", which, ide->user_password_enable);
+
+ return 0;
+}
+
+int ide_controller_init(int which, struct ide_interface *intf)
+{
+ /* we only support one hard disk right now; get a handle to it */
+ return ide_controller_init_custom(which, intf, get_disk_handle(0));
+}
+
+
+static void ide_controller_reset_ptr(struct ide_state *ide)
+{
+ LOG(("IDE controller reset performed\n"));
+
+ /* reset the drive state */
+ ide->status = IDE_STATUS_DRIVE_READY | IDE_STATUS_SEEK_COMPLETE;
+ ide->error = IDE_ERROR_DEFAULT;
+ ide->buffer_offset = 0;
+ ide->master_password_enable = (ide->master_password != NULL);
+ ide->user_password_enable = (ide->user_password != NULL);
+ clear_interrupt(ide);
+}
+
+
+void ide_controller_reset(int which)
+{
+ ide_controller_reset_ptr(&idestate[which]);
+}
+
+
+UINT8 *ide_get_features(int which)
+{
+ struct ide_state *ide = &idestate[which];
+ return ide->features;
+}
+
+
+void ide_set_master_password(int which, UINT8 *password)
+{
+ struct ide_state *ide = &idestate[which];
+
+ ide->master_password = password;
+ ide->master_password_enable = (ide->master_password != NULL);
+}
+
+
+void ide_set_user_password(int which, UINT8 *password)
+{
+ struct ide_state *ide = &idestate[which];
+
+ ide->user_password = password;
+ ide->user_password_enable = (ide->user_password != NULL);
+}
+
+
+static TIMER_CALLBACK_PTR( reset_callback )
+{
+ ide_controller_reset_ptr(param);
+}
+
+
+
+/*************************************
+ *
+ * Convert offset/mem_mask to offset
+ * and size
+ *
+ *************************************/
+
+INLINE int convert_to_offset_and_size32(offs_t *offset, UINT32 mem_mask)
+{
+ int size = 4;
+
+ /* determine which real offset */
+ if (mem_mask & 0x000000ff)
+ {
+ (*offset)++, size = 3;
+ if (mem_mask & 0x0000ff00)
+ {
+ (*offset)++, size = 2;
+ if (mem_mask & 0x00ff0000)
+ (*offset)++, size = 1;
+ }
+ }
+
+ /* determine the real size */
+ if (!(mem_mask & 0xff000000))
+ return size;
+ size--;
+ if (!(mem_mask & 0x00ff0000))
+ return size;
+ size--;
+ if (!(mem_mask & 0x0000ff00))
+ return size;
+ size--;
+ return size;
+}
+
+INLINE int convert_to_offset_and_size16(offs_t *offset, UINT32 mem_mask)
+{
+ int size = 2;
+
+ /* determine which real offset */
+ if (mem_mask & 0x000000ff)
+ (*offset)++, size = 1;
+
+ if (!(mem_mask & 0x0000ff00))
+ return size;
+ size--;
+ return size;
+}
+
+
+
+/*************************************
+ *
+ * Compute the LBA address
+ *
+ *************************************/
+
+INLINE UINT32 lba_address(struct ide_state *ide)
+{
+ /* LBA direct? */
+ if (ide->cur_head_reg & 0x40)
+ return ide->cur_sector + ide->cur_cylinder * 256 + ide->cur_head * 16777216;
+
+ /* standard CHS */
+ else
+ return (ide->cur_cylinder * ide->num_heads + ide->cur_head) * ide->num_sectors + ide->cur_sector - 1;
+}
+
+
+
+/*************************************
+ *
+ * Advance to the next sector
+ *
+ *************************************/
+
+INLINE void next_sector(struct ide_state *ide)
+{
+ /* LBA direct? */
+ if (ide->cur_head_reg & 0x40)
+ {
+ ide->cur_sector++;
+ if (ide->cur_sector == 0)
+ {
+ ide->cur_cylinder++;
+ if (ide->cur_cylinder == 0)
+ ide->cur_head++;
+ }
+ }
+
+ /* standard CHS */
+ else
+ {
+ /* sectors are 1-based */
+ ide->cur_sector++;
+ if (ide->cur_sector > ide->num_sectors)
+ {
+ /* heads are 0 based */
+ ide->cur_sector = 1;
+ ide->cur_head++;
+ if (ide->cur_head >= ide->num_heads)
+ {
+ ide->cur_head = 0;
+ ide->cur_cylinder++;
+ }
+ }
+ }
+
+ ide->cur_lba = lba_address(ide);
+}
+
+
+
+/*************************************
+ *
+ * Build a features page
+ *
+ *************************************/
+
+static void swap_strncpy(UINT8 *dst, const char *src, int field_size_in_words)
+{
+ int i;
+
+ for (i = 0; i < field_size_in_words * 2 && src[i]; i++)
+ dst[i ^ 1] = src[i];
+ for ( ; i < field_size_in_words * 2; i++)
+ dst[i ^ 1] = ' ';
+}
+
+
+static void ide_build_features(struct ide_state *ide)
+{
+ int total_sectors = ide->num_cylinders * ide->num_heads * ide->num_sectors;
+ int sectors_per_track = ide->num_heads * ide->num_sectors;
+
+ memset(ide->buffer, 0, IDE_DISK_SECTOR_SIZE);
+
+ /* basic geometry */
+ ide->features[ 0*2+0] = 0x5a; /* 0: configuration bits */
+ ide->features[ 0*2+1] = 0x04;
+ ide->features[ 1*2+0] = ide->num_cylinders & 0xff; /* 1: logical cylinders */
+ ide->features[ 1*2+1] = ide->num_cylinders >> 8;
+ ide->features[ 2*2+0] = 0; /* 2: reserved */
+ ide->features[ 2*2+1] = 0;
+ ide->features[ 3*2+0] = ide->num_heads & 0xff; /* 3: logical heads */
+ ide->features[ 3*2+1] = 0;/*ide->num_heads >> 8;*/
+ ide->features[ 4*2+0] = 0; /* 4: vendor specific (obsolete) */
+ ide->features[ 4*2+1] = 0;
+ ide->features[ 5*2+0] = 0; /* 5: vendor specific (obsolete) */
+ ide->features[ 5*2+1] = 0;
+ ide->features[ 6*2+0] = ide->num_sectors & 0xff; /* 6: logical sectors per logical track */
+ ide->features[ 6*2+1] = 0;/*ide->num_sectors >> 8;*/
+ ide->features[ 7*2+0] = 0; /* 7: vendor-specific */
+ ide->features[ 7*2+1] = 0;
+ ide->features[ 8*2+0] = 0; /* 8: vendor-specific */
+ ide->features[ 8*2+1] = 0;
+ ide->features[ 9*2+0] = 0; /* 9: vendor-specific */
+ ide->features[ 9*2+1] = 0;
+ swap_strncpy(&ide->features[10*2+0], /* 10-19: serial number */
+ "00000000000000000000", 10);
+ ide->features[20*2+0] = 0; /* 20: vendor-specific */
+ ide->features[20*2+1] = 0;
+ ide->features[21*2+0] = 0; /* 21: vendor-specific */
+ ide->features[21*2+1] = 0;
+ ide->features[22*2+0] = 4; /* 22: # of vendor-specific bytes on read/write long commands */
+ ide->features[22*2+1] = 0;
+ swap_strncpy(&ide->features[23*2+0], /* 23-26: firmware revision */
+ "1.0", 4);
+ swap_strncpy(&ide->features[27*2+0], /* 27-46: model number */
+ "MAME Compressed Hard Disk", 20);
+ ide->features[47*2+0] = 0x01; /* 47: read/write multiple support */
+ ide->features[47*2+1] = 0x80;
+ ide->features[48*2+0] = 0; /* 48: reserved */
+ ide->features[48*2+1] = 0;
+ ide->features[49*2+0] = 0x03; /* 49: capabilities */
+ ide->features[49*2+1] = 0x0f;
+ ide->features[50*2+0] = 0; /* 50: reserved */
+ ide->features[50*2+1] = 0;
+ ide->features[51*2+0] = 2; /* 51: PIO data transfer cycle timing mode */
+ ide->features[51*2+1] = 0;
+ ide->features[52*2+0] = 2; /* 52: single word DMA transfer cycle timing mode */
+ ide->features[52*2+1] = 0;
+ ide->features[53*2+0] = 3; /* 53: field validity */
+ ide->features[53*2+1] = 0;
+ ide->features[54*2+0] = ide->num_cylinders & 0xff; /* 54: number of current logical cylinders */
+ ide->features[54*2+1] = ide->num_cylinders >> 8;
+ ide->features[55*2+0] = ide->num_heads & 0xff; /* 55: number of current logical heads */
+ ide->features[55*2+1] = 0;/*ide->num_heads >> 8;*/
+ ide->features[56*2+0] = ide->num_sectors & 0xff; /* 56: number of current logical sectors per track */
+ ide->features[56*2+1] = 0;/*ide->num_sectors >> 8;*/
+ ide->features[57*2+0] = sectors_per_track & 0xff; /* 57-58: number of current logical sectors per track */
+ ide->features[57*2+1] = sectors_per_track >> 8;
+ ide->features[58*2+0] = sectors_per_track >> 16;
+ ide->features[58*2+1] = sectors_per_track >> 24;
+ ide->features[59*2+0] = 0; /* 59: multiple sector timing */
+ ide->features[59*2+1] = 0;
+ ide->features[60*2+0] = total_sectors & 0xff; /* 60-61: total user addressable sectors */
+ ide->features[60*2+1] = total_sectors >> 8;
+ ide->features[61*2+0] = total_sectors >> 16;
+ ide->features[61*2+1] = total_sectors >> 24;
+ ide->features[62*2+0] = 0x07; /* 62: single word dma transfer */
+ ide->features[62*2+1] = 0x00;
+ ide->features[63*2+0] = 0x07; /* 63: multiword DMA transfer */
+ ide->features[63*2+1] = 0x04;
+ ide->features[64*2+0] = 0x03; /* 64: flow control PIO transfer modes supported */
+ ide->features[64*2+1] = 0x00;
+ ide->features[65*2+0] = 0x78; /* 65: minimum multiword DMA transfer cycle time per word */
+ ide->features[65*2+1] = 0x00;
+ ide->features[66*2+0] = 0x78; /* 66: mfr's recommended multiword DMA transfer cycle time */
+ ide->features[66*2+1] = 0x00;
+ ide->features[67*2+0] = 0x4d; /* 67: minimum PIO transfer cycle time without flow control */
+ ide->features[67*2+1] = 0x01;
+ ide->features[68*2+0] = 0x78; /* 68: minimum PIO transfer cycle time with IORDY */
+ ide->features[68*2+1] = 0x00;
+ ide->features[69*2+0] = 0x00; /* 69-70: reserved */
+ ide->features[69*2+1] = 0x00;
+ ide->features[71*2+0] = 0x00; /* 71: reserved for IDENTIFY PACKET command */
+ ide->features[71*2+1] = 0x00;
+ ide->features[72*2+0] = 0x00; /* 72: reserved for IDENTIFY PACKET command */
+ ide->features[72*2+1] = 0x00;
+ ide->features[73*2+0] = 0x00; /* 73: reserved for IDENTIFY PACKET command */
+ ide->features[73*2+1] = 0x00;
+ ide->features[74*2+0] = 0x00; /* 74: reserved for IDENTIFY PACKET command */
+ ide->features[74*2+1] = 0x00;
+ ide->features[75*2+0] = 0x00; /* 75: queue depth */
+ ide->features[75*2+1] = 0x00;
+ ide->features[76*2+0] = 0x00; /* 76-79: reserved */
+ ide->features[76*2+1] = 0x00;
+ ide->features[80*2+0] = 0x00; /* 80: major version number */
+ ide->features[80*2+1] = 0x00;
+ ide->features[81*2+0] = 0x00; /* 81: minor version number */
+ ide->features[81*2+1] = 0x00;
+ ide->features[82*2+0] = 0x00; /* 82: command set supported */
+ ide->features[82*2+1] = 0x00;
+ ide->features[83*2+0] = 0x00; /* 83: command sets supported */
+ ide->features[83*2+1] = 0x00;
+ ide->features[84*2+0] = 0x00; /* 84: command set/feature supported extension */
+ ide->features[84*2+1] = 0x00;
+ ide->features[85*2+0] = 0x00; /* 85: command set/feature enabled */
+ ide->features[85*2+1] = 0x00;
+ ide->features[86*2+0] = 0x00; /* 86: command set/feature enabled */
+ ide->features[86*2+1] = 0x00;
+ ide->features[87*2+0] = 0x00; /* 87: command set/feature default */
+ ide->features[87*2+1] = 0x00;
+ ide->features[88*2+0] = 0x00; /* 88: additional DMA modes */
+ ide->features[88*2+1] = 0x00;
+ ide->features[89*2+0] = 0x00; /* 89: time required for security erase unit completion */
+ ide->features[89*2+1] = 0x00;
+ ide->features[90*2+0] = 0x00; /* 90: time required for enhanced security erase unit completion */
+ ide->features[90*2+1] = 0x00;
+ ide->features[91*2+0] = 0x00; /* 91: current advanced power management value */
+ ide->features[91*2+1] = 0x00;
+ ide->features[92*2+0] = 0x00; /* 92: master password revision code */
+ ide->features[92*2+1] = 0x00;
+ ide->features[93*2+0] = 0x00; /* 93: hardware reset result */
+ ide->features[93*2+1] = 0x00;
+ ide->features[94*2+0] = 0x00; /* 94: acoustic management values */
+ ide->features[94*2+1] = 0x00;
+ ide->features[95*2+0] = 0x00; /* 95-99: reserved */
+ ide->features[95*2+1] = 0x00;
+ ide->features[100*2+0] = total_sectors & 0xff; /* 100-103: maximum 48-bit LBA */
+ ide->features[100*2+1] = total_sectors >> 8;
+ ide->features[101*2+0] = total_sectors >> 16;
+ ide->features[101*2+1] = total_sectors >> 24;
+ ide->features[102*2+0] = 0x00;
+ ide->features[102*2+1] = 0x00;
+ ide->features[103*2+0] = 0x00;
+ ide->features[103*2+1] = 0x00;
+ ide->features[104*2+0] = 0x00; /* 104-126: reserved */
+ ide->features[104*2+1] = 0x00;
+ ide->features[127*2+0] = 0x00; /* 127: removable media status notification */
+ ide->features[127*2+1] = 0x00;
+ ide->features[128*2+0] = 0x00; /* 128: security status */
+ ide->features[128*2+1] = 0x00;
+ ide->features[129*2+0] = 0x00; /* 129-159: vendor specific */
+ ide->features[129*2+1] = 0x00;
+ ide->features[160*2+0] = 0x00; /* 160: CFA power mode 1 */
+ ide->features[160*2+1] = 0x00;
+ ide->features[161*2+0] = 0x00; /* 161-175: reserved for CompactFlash */
+ ide->features[161*2+1] = 0x00;
+ ide->features[176*2+0] = 0x00; /* 176-205: current media serial number */
+ ide->features[176*2+1] = 0x00;
+ ide->features[206*2+0] = 0x00; /* 206-254: reserved */
+ ide->features[206*2+1] = 0x00;
+ ide->features[255*2+0] = 0x00; /* 255: integrity word */
+ ide->features[255*2+1] = 0x00;
+}
+
+
+
+/*************************************
+ *
+ * security error handling
+ *
+ *************************************/
+
+static TIMER_CALLBACK_PTR( security_error_done )
+{
+ struct ide_state *ide = param;
+
+ /* clear error state */
+ ide->status &= ~IDE_STATUS_ERROR;
+ ide->status |= IDE_STATUS_DRIVE_READY;
+}
+
+static void security_error(struct ide_state *ide)
+{
+ /* set error state */
+ ide->status |= IDE_STATUS_ERROR;
+ ide->status &= ~IDE_STATUS_DRIVE_READY;
+
+ /* just set a timer and mark ourselves error */
+ timer_set_ptr(TIME_SECURITY_ERROR, ide, security_error_done);
+}
+
+
+
+/*************************************
+ *
+ * Sector reading
+ *
+ *************************************/
+
+static void continue_read(struct ide_state *ide)
+{
+ /* reset the totals */
+ ide->buffer_offset = 0;
+
+ /* clear the buffer ready and busy flag */
+ ide->status &= ~IDE_STATUS_BUFFER_READY;
+ ide->status &= ~IDE_STATUS_BUSY;
+
+ if (ide->master_password_enable || ide->user_password_enable)
+ {
+ security_error(ide);
+
+ ide->sector_count = 0;
+ ide->bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE;
+ ide->dma_active = 0;
+
+ return;
+ }
+
+ /* if there is more data to read, keep going */
+ if (ide->sector_count > 0)
+ ide->sector_count--;
+ if (ide->sector_count > 0)
+ read_next_sector(ide);
+ else
+ {
+ ide->bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE;
+ ide->dma_active = 0;
+ }
+}
+
+
+static void write_buffer_to_dma(struct ide_state *ide)
+{
+ int bytesleft = IDE_DISK_SECTOR_SIZE;
+ UINT8 *data = ide->buffer;
+
+// LOG(("Writing sector to %08X\n", ide->dma_address));
+
+ /* loop until we've consumed all bytes */
+ while (bytesleft--)
+ {
+ /* if we're out of space, grab the next descriptor */
+ if (ide->dma_bytes_left == 0)
+ {
+ /* if we're out of buffer space, that's bad */
+ if (ide->dma_last_buffer)
+ {
+ LOG(("DMA Out of buffer space!\n"));
+ return;
+ }
+
+ /* fetch the address */
+ ide->dma_address = cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor);
+ ide->dma_address |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 8;
+ ide->dma_address |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 16;
+ ide->dma_address |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 24;
+ ide->dma_address &= 0xfffffffe;
+
+ /* fetch the length */
+ ide->dma_bytes_left = cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor);
+ ide->dma_bytes_left |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 8;
+ ide->dma_bytes_left |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 16;
+ ide->dma_bytes_left |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 24;
+ ide->dma_last_buffer = (ide->dma_bytes_left >> 31) & 1;
+ ide->dma_bytes_left &= 0xfffe;
+ if (ide->dma_bytes_left == 0)
+ ide->dma_bytes_left = 0x10000;
+
+// LOG(("New DMA descriptor: address = %08X bytes = %04X last = %d\n", ide->dma_address, ide->dma_bytes_left, ide->dma_last_buffer));
+ }
+
+ /* write the next byte */
+ cpunum_write_byte(ide->dma_cpu, ide->dma_address++, *data++);
+ ide->dma_bytes_left--;
+ }
+}
+
+
+static void read_sector_done(struct ide_state *ide)
+{
+ int lba = lba_address(ide), count = 0;
+
+ /* now do the read */
+ if (ide->disk)
+ count = hard_disk_read(ide->disk, lba, ide->buffer);
+
+ /* by default, mark the buffer ready and the seek complete */
+ if (!ide->verify_only)
+ ide->status |= IDE_STATUS_BUFFER_READY;
+ ide->status |= IDE_STATUS_SEEK_COMPLETE;
+
+ /* and clear the busy and error flags */
+ ide->status &= ~IDE_STATUS_ERROR;
+ ide->status &= ~IDE_STATUS_BUSY;
+
+ /* if we succeeded, advance to the next sector and set the nice bits */
+ if (count == 1)
+ {
+ /* advance the pointers, unless this is the last sector */
+ /* Gauntlet: Dark Legacy checks to make sure we stop on the last sector */
+ if (ide->sector_count != 1)
+ next_sector(ide);
+
+ /* clear the error value */
+ ide->error = IDE_ERROR_NONE;
+
+ /* signal an interrupt */
+ if (!ide->verify_only)
+ ide->sectors_until_int--;
+ if (ide->sectors_until_int == 0 || ide->sector_count == 1)
+ {
+ ide->sectors_until_int = ((ide->command == IDE_COMMAND_READ_MULTIPLE_BLOCK) ? ide->block_count : 1);
+ signal_interrupt(ide);
+ }
+
+ /* handle DMA */
+ if (ide->dma_active)
+ write_buffer_to_dma(ide);
+
+ /* if we're just verifying or if we DMA'ed the data, we can read the next sector */
+ if (ide->verify_only || ide->dma_active)
+ continue_read(ide);
+ }
+
+ /* if we got an error, we need to report it */
+ else
+ {
+ /* set the error flag and the error */
+ ide->status |= IDE_STATUS_ERROR;
+ ide->error = IDE_ERROR_BAD_SECTOR;
+ ide->bus_master_status |= IDE_BUSMASTER_STATUS_ERROR;
+ ide->bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE;
+
+ /* signal an interrupt */
+ signal_interrupt(ide);
+ }
+}
+
+
+static TIMER_CALLBACK_PTR( read_sector_done_callback )
+{
+ read_sector_done(param);
+}
+
+
+static void read_first_sector(struct ide_state *ide)
+{
+ /* mark ourselves busy */
+ ide->status |= IDE_STATUS_BUSY;
+
+ /* just set a timer */
+ if (ide->command == IDE_COMMAND_READ_MULTIPLE_BLOCK)
+ {
+ int new_lba = lba_address(ide);
+ attotime seek_time;
+
+ if (new_lba == ide->cur_lba || new_lba == ide->cur_lba + 1)
+ seek_time = TIME_NO_SEEK_MULTISECTOR;
+ else
+ seek_time = TIME_SEEK_MULTISECTOR;
+
+ ide->cur_lba = new_lba;
+ timer_set_ptr(seek_time, ide, read_sector_done_callback);
+ }
+ else
+ timer_set_ptr(TIME_PER_SECTOR, ide, read_sector_done_callback);
+}
+
+
+static void read_next_sector(struct ide_state *ide)
+{
+ /* mark ourselves busy */
+ ide->status |= IDE_STATUS_BUSY;
+
+ if (ide->command == IDE_COMMAND_READ_MULTIPLE_BLOCK)
+ {
+ if (ide->sectors_until_int != 1)
+ /* make ready now */
+ read_sector_done(ide);
+ else
+ /* just set a timer */
+ timer_set_ptr(ATTOTIME_IN_USEC(1), ide, read_sector_done_callback);
+ }
+ else
+ /* just set a timer */
+ timer_set_ptr(TIME_PER_SECTOR, ide, read_sector_done_callback);
+}
+
+
+
+/*************************************
+ *
+ * Sector writing
+ *
+ *************************************/
+
+static void write_sector_done(struct ide_state *ide);
+static TIMER_CALLBACK_PTR( write_sector_done_callback );
+
+static void continue_write(struct ide_state *ide)
+{
+ /* reset the totals */
+ ide->buffer_offset = 0;
+
+ /* clear the buffer ready flag */
+ ide->status &= ~IDE_STATUS_BUFFER_READY;
+ ide->status |= IDE_STATUS_BUSY;
+
+ if (ide->command == IDE_COMMAND_WRITE_MULTIPLE_BLOCK)
+ {
+ if (ide->sectors_until_int != 1)
+ {
+ /* ready to write now */
+ write_sector_done(ide);
+ }
+ else
+ {
+ /* set a timer to do the write */
+ timer_set_ptr(TIME_PER_SECTOR, ide, write_sector_done_callback);
+ }
+ }
+ else
+ {
+ /* set a timer to do the write */
+ timer_set_ptr(TIME_PER_SECTOR, ide, write_sector_done_callback);
+ }
+}
+
+
+static void read_buffer_from_dma(struct ide_state *ide)
+{
+ int bytesleft = IDE_DISK_SECTOR_SIZE;
+ UINT8 *data = ide->buffer;
+
+// LOG(("Reading sector from %08X\n", ide->dma_address));
+
+ /* loop until we've consumed all bytes */
+ while (bytesleft--)
+ {
+ /* if we're out of space, grab the next descriptor */
+ if (ide->dma_bytes_left == 0)
+ {
+ /* if we're out of buffer space, that's bad */
+ if (ide->dma_last_buffer)
+ {
+ LOG(("DMA Out of buffer space!\n"));
+ return;
+ }
+
+ /* fetch the address */
+ ide->dma_address = cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor);
+ ide->dma_address |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 8;
+ ide->dma_address |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 16;
+ ide->dma_address |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 24;
+ ide->dma_address &= 0xfffffffe;
+
+ /* fetch the length */
+ ide->dma_bytes_left = cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor);
+ ide->dma_bytes_left |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 8;
+ ide->dma_bytes_left |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 16;
+ ide->dma_bytes_left |= cpunum_read_byte(ide->dma_cpu, ide->dma_descriptor++ ^ ide->dma_address_xor) << 24;
+ ide->dma_last_buffer = (ide->dma_bytes_left >> 31) & 1;
+ ide->dma_bytes_left &= 0xfffe;
+ if (ide->dma_bytes_left == 0)
+ ide->dma_bytes_left = 0x10000;
+
+// LOG(("New DMA descriptor: address = %08X bytes = %04X last = %d\n", ide->dma_address, ide->dma_bytes_left, ide->dma_last_buffer));
+ }
+
+ /* read the next byte */
+ *data++ = cpunum_read_byte(ide->dma_cpu, ide->dma_address++);
+ ide->dma_bytes_left--;
+ }
+}
+
+
+static void write_sector_done(struct ide_state *ide)
+{
+ int lba = lba_address(ide), count = 0;
+
+ /* now do the write */
+ if (ide->disk)
+ count = hard_disk_write(ide->disk, lba, ide->buffer);
+
+ /* by default, mark the buffer ready and the seek complete */
+ ide->status |= IDE_STATUS_BUFFER_READY;
+ ide->status |= IDE_STATUS_SEEK_COMPLETE;
+
+ /* and clear the busy adn error flags */
+ ide->status &= ~IDE_STATUS_ERROR;
+ ide->status &= ~IDE_STATUS_BUSY;
+
+ /* if we succeeded, advance to the next sector and set the nice bits */
+ if (count == 1)
+ {
+ /* advance the pointers, unless this is the last sector */
+ /* Gauntlet: Dark Legacy checks to make sure we stop on the last sector */
+ if (ide->sector_count != 1)
+ next_sector(ide);
+
+ /* clear the error value */
+ ide->error = IDE_ERROR_NONE;
+
+ /* signal an interrupt */
+ if (--ide->sectors_until_int == 0 || ide->sector_count == 1)
+ {
+ ide->sectors_until_int = ((ide->command == IDE_COMMAND_WRITE_MULTIPLE_BLOCK) ? ide->block_count : 1);
+ signal_interrupt(ide);
+ }
+
+ /* signal an interrupt if there's more data needed */
+ if (ide->sector_count > 0)
+ ide->sector_count--;
+ if (ide->sector_count == 0)
+ ide->status &= ~IDE_STATUS_BUFFER_READY;
+
+ /* keep going for DMA */
+ if (ide->dma_active && ide->sector_count != 0)
+ {
+ read_buffer_from_dma(ide);
+ continue_write(ide);
+ }
+ else
+ ide->dma_active = 0;
+ }
+
+ /* if we got an error, we need to report it */
+ else
+ {
+ /* set the error flag and the error */
+ ide->status |= IDE_STATUS_ERROR;
+ ide->error = IDE_ERROR_BAD_SECTOR;
+ ide->bus_master_status |= IDE_BUSMASTER_STATUS_ERROR;
+ ide->bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE;
+
+ /* signal an interrupt */
+ signal_interrupt(ide);
+ }
+}
+
+
+static TIMER_CALLBACK_PTR( write_sector_done_callback )
+{
+ write_sector_done(param);
+}
+
+
+
+/*************************************
+ *
+ * Handle IDE commands
+ *
+ *************************************/
+
+static void handle_command(struct ide_state *ide, UINT8 command)
+{
+ /* implicitly clear interrupts here */
+ clear_interrupt(ide);
+
+ ide->command = command;
+ switch (command)
+ {
+ case IDE_COMMAND_READ_MULTIPLE:
+ case IDE_COMMAND_READ_MULTIPLE_ONCE:
+ LOGPRINT(("IDE Read multiple: C=%d H=%d S=%d LBA=%d count=%d\n",
+ ide->cur_cylinder, ide->cur_head, ide->cur_sector, lba_address(ide), ide->sector_count));
+
+ /* reset the buffer */
+ ide->buffer_offset = 0;
+ ide->sectors_until_int = 1;
+ ide->dma_active = 0;
+ ide->verify_only = 0;
+
+ /* start the read going */
+ read_first_sector(ide);
+ break;
+
+ case IDE_COMMAND_READ_MULTIPLE_BLOCK:
+ LOGPRINT(("IDE Read multiple block: C=%d H=%d S=%d LBA=%d count=%d\n",
+ ide->cur_cylinder, ide->cur_head, ide->cur_sector, lba_address(ide), ide->sector_count));
+
+ /* reset the buffer */
+ ide->buffer_offset = 0;
+ ide->sectors_until_int = 1;
+ ide->dma_active = 0;
+ ide->verify_only = 0;
+
+ /* start the read going */
+ read_first_sector(ide);
+ break;
+
+ case IDE_COMMAND_VERIFY_MULTIPLE:
+ LOGPRINT(("IDE Read verify multiple with retries: C=%d H=%d S=%d LBA=%d count=%d\n",
+ ide->cur_cylinder, ide->cur_head, ide->cur_sector, lba_address(ide), ide->sector_count));
+
+ /* reset the buffer */
+ ide->buffer_offset = 0;
+ ide->sectors_until_int = 1;
+ ide->dma_active = 0;
+ ide->verify_only = 1;
+
+ /* start the read going */
+ read_first_sector(ide);
+ break;
+
+ case IDE_COMMAND_READ_DMA:
+ LOGPRINT(("IDE Read multiple DMA: C=%d H=%d S=%d LBA=%d count=%d\n",
+ ide->cur_cylinder, ide->cur_head, ide->cur_sector, lba_address(ide), ide->sector_count));
+
+ /* reset the buffer */
+ ide->buffer_offset = 0;
+ ide->sectors_until_int = ide->sector_count;
+ ide->dma_active = 1;
+ ide->verify_only = 0;
+
+ /* start the read going */
+ if (ide->bus_master_command & 1)
+ read_first_sector(ide);
+ break;
+
+ case IDE_COMMAND_WRITE_MULTIPLE:
+ LOGPRINT(("IDE Write multiple: C=%d H=%d S=%d LBA=%d count=%d\n",
+ ide->cur_cylinder, ide->cur_head, ide->cur_sector, lba_address(ide), ide->sector_count));
+
+ /* reset the buffer */
+ ide->buffer_offset = 0;
+ ide->sectors_until_int = 1;
+ ide->dma_active = 0;
+
+ /* mark the buffer ready */
+ ide->status |= IDE_STATUS_BUFFER_READY;
+ break;
+
+ case IDE_COMMAND_WRITE_MULTIPLE_BLOCK:
+ LOGPRINT(("IDE Write multiple block: C=%d H=%d S=%d LBA=%d count=%d\n",
+ ide->cur_cylinder, ide->cur_head, ide->cur_sector, lba_address(ide), ide->sector_count));
+
+ /* reset the buffer */
+ ide->buffer_offset = 0;
+ ide->sectors_until_int = 1;
+ ide->dma_active = 0;
+
+ /* mark the buffer ready */
+ ide->status |= IDE_STATUS_BUFFER_READY;
+ break;
+
+ case IDE_COMMAND_WRITE_DMA:
+ LOGPRINT(("IDE Write multiple DMA: C=%d H=%d S=%d LBA=%d count=%d\n",
+ ide->cur_cylinder, ide->cur_head, ide->cur_sector, lba_address(ide), ide->sector_count));
+
+ /* reset the buffer */
+ ide->buffer_offset = 0;
+ ide->sectors_until_int = ide->sector_count;
+ ide->dma_active = 1;
+
+ /* start the read going */
+ if (ide->bus_master_command & 1)
+ {
+ read_buffer_from_dma(ide);
+ continue_write(ide);
+ }
+ break;
+
+ case IDE_COMMAND_SECURITY_UNLOCK:
+ LOGPRINT(("IDE Security Unlock\n"));
+
+ /* reset the buffer */
+ ide->buffer_offset = 0;
+ ide->sectors_until_int = 0;
+ ide->dma_active = 0;
+
+ /* mark the buffer ready */
+ ide->status |= IDE_STATUS_BUFFER_READY;
+ signal_interrupt(ide);
+ break;
+
+ case IDE_COMMAND_GET_INFO:
+ LOGPRINT(("IDE Read features\n"));
+
+ /* reset the buffer */
+ ide->buffer_offset = 0;
+ ide->sector_count = 1;
+
+ /* build the features page */
+ memcpy(ide->buffer, ide->features, sizeof(ide->buffer));
+
+ /* indicate everything is ready */
+ ide->status |= IDE_STATUS_BUFFER_READY;
+ ide->status |= IDE_STATUS_SEEK_COMPLETE;
+ ide->status |= IDE_STATUS_DRIVE_READY;
+
+ /* and clear the busy adn error flags */
+ ide->status &= ~IDE_STATUS_ERROR;
+ ide->status &= ~IDE_STATUS_BUSY;
+
+ /* clear the error too */
+ ide->error = IDE_ERROR_NONE;
+
+ /* signal an interrupt */
+ signal_delayed_interrupt(ide, MINIMUM_COMMAND_TIME, 1);
+ break;
+
+ case IDE_COMMAND_SET_CONFIG:
+ LOGPRINT(("IDE Set configuration (%d heads, %d sectors)\n", ide->cur_head + 1, ide->sector_count));
+
+ ide->num_sectors = ide->sector_count;
+ ide->num_heads = ide->cur_head + 1;
+
+ /* signal an interrupt */
+ signal_interrupt(ide);
+ break;
+
+ case IDE_COMMAND_UNKNOWN_F9:
+ /* only used by Killer Instinct AFAICT */
+ LOGPRINT(("IDE unknown command (F9)\n"));
+
+ /* signal an interrupt */
+ signal_interrupt(ide);
+ break;
+
+ case IDE_COMMAND_SET_FEATURES:
+ LOGPRINT(("IDE Set features (%02X %02X %02X %02X %02X)\n", ide->precomp_offset, ide->sector_count & 0xff, ide->cur_sector, ide->cur_cylinder & 0xff, ide->cur_cylinder >> 8));
+
+ /* signal an interrupt */
+ signal_delayed_interrupt(ide, MINIMUM_COMMAND_TIME, 0);
+ break;
+
+ case IDE_COMMAND_SET_BLOCK_COUNT:
+ LOGPRINT(("IDE Set block count (%02X)\n", ide->sector_count));
+
+ ide->block_count = ide->sector_count;
+ // judge dredd wants 'drive ready' on this command
+ ide->status |= IDE_STATUS_DRIVE_READY;
+
+ /* signal an interrupt */
+ signal_interrupt(ide);
+ break;
+
+ default:
+ LOGPRINT(("IDE unknown command (%02X)\n", command));
+ DEBUGGER_BREAK;
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * IDE controller read
+ *
+ *************************************/
+
+static UINT32 ide_controller_read(struct ide_state *ide, offs_t offset, int size)
+{
+ UINT32 result = 0;
+
+ /* logit */
+// if (offset != IDE_ADDR_DATA && offset != IDE_ADDR_STATUS_COMMAND && offset != IDE_ADDR_STATUS_CONTROL)
+ LOG(("%08X:IDE read at %03X, size=%d\n", activecpu_get_previouspc(), offset, size));
+
+ switch (offset)
+ {
+ /* unknown config register */
+ case IDE_ADDR_CONFIG_UNK:
+ return ide->config_unknown;
+
+ /* active config register */
+ case IDE_ADDR_CONFIG_REGISTER:
+ return ide->config_register_num;
+
+ /* data from active config register */
+ case IDE_ADDR_CONFIG_DATA:
+ if (ide->config_register_num < IDE_CONFIG_REGISTERS)
+ return ide->config_register[ide->config_register_num];
+ return 0;
+
+ /* read data if there's data to be read */
+ case IDE_ADDR_DATA:
+ if (ide->status & IDE_STATUS_BUFFER_READY)
+ {
+ /* fetch the correct amount of data */
+ result = ide->buffer[ide->buffer_offset++];
+ if (size > 1)
+ result |= ide->buffer[ide->buffer_offset++] << 8;
+ if (size > 2)
+ {
+ result |= ide->buffer[ide->buffer_offset++] << 16;
+ result |= ide->buffer[ide->buffer_offset++] << 24;
+ }
+
+ /* if we're at the end of the buffer, handle it */
+ if (ide->buffer_offset >= IDE_DISK_SECTOR_SIZE)
+ {
+ LOG(("%08X:IDE completed PIO read\n", activecpu_get_previouspc()));
+ continue_read(ide);
+ }
+ }
+ break;
+
+ /* return the current error */
+ case IDE_ADDR_ERROR:
+ return ide->error;
+
+ /* return the current sector count */
+ case IDE_ADDR_SECTOR_COUNT:
+ return ide->sector_count;
+
+ /* return the current sector */
+ case IDE_ADDR_SECTOR_NUMBER:
+ return ide->cur_sector;
+
+ /* return the current cylinder LSB */
+ case IDE_ADDR_CYLINDER_LSB:
+ return ide->cur_cylinder & 0xff;
+
+ /* return the current cylinder MSB */
+ case IDE_ADDR_CYLINDER_MSB:
+ return ide->cur_cylinder >> 8;
+
+ /* return the current head */
+ case IDE_ADDR_HEAD_NUMBER:
+ return ide->cur_head_reg;
+
+ /* return the current status and clear any pending interrupts */
+ case IDE_ADDR_STATUS_COMMAND:
+ /* return the current status but don't clear interrupts */
+ case IDE_ADDR_STATUS_CONTROL:
+ result = ide->status;
+ if (attotime_compare(timer_timeelapsed(ide->last_status_timer), TIME_PER_ROTATION) > 0)
+ {
+ result |= IDE_STATUS_HIT_INDEX;
+ timer_adjust(ide->last_status_timer, attotime_never, 0, attotime_zero);
+ }
+
+ /* clear interrutps only when reading the real status */
+ if (offset == IDE_ADDR_STATUS_COMMAND)
+ {
+ if (ide->interrupt_pending)
+ clear_interrupt(ide);
+ }
+
+ /* take a bit of time to speed up people who poll hard */
+ activecpu_adjust_icount(-100);
+ break;
+
+ /* log anything else */
+ default:
+ logerror("%08X:unknown IDE read at %03X, size=%d\n", activecpu_get_previouspc(), offset, size);
+ break;
+ }
+
+ /* return the result */
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * IDE controller write
+ *
+ *************************************/
+
+static void ide_controller_write(struct ide_state *ide, offs_t offset, int size, UINT32 data)
+{
+ /* logit */
+ if (offset != IDE_ADDR_DATA)
+ LOG(("%08X:IDE write to %03X = %08X, size=%d\n", activecpu_get_previouspc(), offset, data, size));
+
+ switch (offset)
+ {
+ /* unknown config register */
+ case IDE_ADDR_CONFIG_UNK:
+ ide->config_unknown = data;
+ break;
+
+ /* active config register */
+ case IDE_ADDR_CONFIG_REGISTER:
+ ide->config_register_num = data;
+ break;
+
+ /* data from active config register */
+ case IDE_ADDR_CONFIG_DATA:
+ if (ide->config_register_num < IDE_CONFIG_REGISTERS)
+ ide->config_register[ide->config_register_num] = data;
+ break;
+
+ /* write data */
+ case IDE_ADDR_DATA:
+ if (ide->status & IDE_STATUS_BUFFER_READY)
+ {
+ /* store the correct amount of data */
+ ide->buffer[ide->buffer_offset++] = data;
+ if (size > 1)
+ ide->buffer[ide->buffer_offset++] = data >> 8;
+ if (size > 2)
+ {
+ ide->buffer[ide->buffer_offset++] = data >> 16;
+ ide->buffer[ide->buffer_offset++] = data >> 24;
+ }
+
+ /* if we're at the end of the buffer, handle it */
+ if (ide->buffer_offset >= IDE_DISK_SECTOR_SIZE)
+ {
+ LOG(("%08X:IDE completed PIO write\n", activecpu_get_previouspc()));
+ if (ide->command != IDE_COMMAND_SECURITY_UNLOCK)
+ continue_write(ide);
+ else
+ {
+ if (ide->user_password_enable && memcmp(ide->buffer, ide->user_password, 2 + 32) == 0)
+ {
+ LOGPRINT(("IDE Unlocked user password\n"));
+ ide->user_password_enable = 0;
+ }
+ if (ide->master_password_enable && memcmp(ide->buffer, ide->master_password, 2 + 32) == 0)
+ {
+ LOGPRINT(("IDE Unlocked master password\n"));
+ ide->master_password_enable = 0;
+ }
+#if PRINTF_IDE_PASSWORD
+ {
+ int i;
+
+ for (i = 0; i < 34; i += 2)
+ {
+ if (i % 8 == 2)
+ mame_printf_debug("\n");
+
+ mame_printf_debug("0x%02x, 0x%02x, ", ide->buffer[i], ide->buffer[i + 1]);
+ //mame_printf_debug("0x%02x%02x, ", ide->buffer[i], ide->buffer[i + 1]);
+ }
+ mame_printf_debug("\n");
+ }
+#endif
+
+ /* clear the busy adn error flags */
+ ide->status &= ~IDE_STATUS_ERROR;
+ ide->status &= ~IDE_STATUS_BUSY;
+ ide->status &= ~IDE_STATUS_BUFFER_READY;
+
+ if (ide->master_password_enable || ide->user_password_enable)
+ security_error(ide);
+ else
+ ide->status |= IDE_STATUS_DRIVE_READY;
+ }
+ }
+ }
+ break;
+
+ /* precompensation offset?? */
+ case IDE_ADDR_ERROR:
+ ide->precomp_offset = data;
+ break;
+
+ /* sector count */
+ case IDE_ADDR_SECTOR_COUNT:
+ ide->sector_count = data ? data : 256;
+ break;
+
+ /* current sector */
+ case IDE_ADDR_SECTOR_NUMBER:
+ ide->cur_sector = data;
+ break;
+
+ /* current cylinder LSB */
+ case IDE_ADDR_CYLINDER_LSB:
+ ide->cur_cylinder = (ide->cur_cylinder & 0xff00) | (data & 0xff);
+ break;
+
+ /* current cylinder MSB */
+ case IDE_ADDR_CYLINDER_MSB:
+ ide->cur_cylinder = (ide->cur_cylinder & 0x00ff) | ((data & 0xff) << 8);
+ break;
+
+ /* current head */
+ case IDE_ADDR_HEAD_NUMBER:
+ ide->cur_head = data & 0x0f;
+ ide->cur_head_reg = data;
+ // drive index = data & 0x10
+ // LBA mode = data & 0x40
+ break;
+
+ /* command */
+ case IDE_ADDR_STATUS_COMMAND:
+ handle_command(ide, data);
+ break;
+
+ /* adapter control */
+ case IDE_ADDR_STATUS_CONTROL:
+ ide->adapter_control = data;
+
+ /* handle controller reset */
+ //if (data == 0x04)
+ if (data & 0x04)
+ {
+ ide->status |= IDE_STATUS_BUSY;
+ ide->status &= ~IDE_STATUS_DRIVE_READY;
+ timer_adjust_ptr(ide->reset_timer, ATTOTIME_IN_MSEC(5), attotime_zero);
+ }
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Bus master read
+ *
+ *************************************/
+
+static UINT32 ide_bus_master_read(struct ide_state *ide, offs_t offset, int size)
+{
+ LOG(("%08X:ide_bus_master_read(%d, %d)\n", activecpu_get_previouspc(), offset, size));
+
+ /* command register */
+ if (offset == 0)
+ return ide->bus_master_command | (ide->bus_master_status << 16);
+
+ /* status register */
+ if (offset == 2)
+ return ide->bus_master_status;
+
+ /* descriptor table register */
+ if (offset == 4)
+ return ide->bus_master_descriptor;
+
+ return 0xffffffff;
+}
+
+
+
+/*************************************
+ *
+ * Bus master write
+ *
+ *************************************/
+
+static void ide_bus_master_write(struct ide_state *ide, offs_t offset, int size, UINT32 data)
+{
+ LOG(("%08X:ide_bus_master_write(%d, %d, %08X)\n", activecpu_get_previouspc(), offset, size, data));
+
+ /* command register */
+ if (offset == 0)
+ {
+ UINT8 old = ide->bus_master_command;
+ UINT8 val = data & 0xff;
+
+ /* save the read/write bit and the start/stop bit */
+ ide->bus_master_command = (old & 0xf6) | (val & 0x09);
+ ide->bus_master_status = (ide->bus_master_status & ~IDE_BUSMASTER_STATUS_ACTIVE) | (val & 0x01);
+
+ /* handle starting a transfer */
+ if (!(old & 1) && (val & 1))
+ {
+ /* reset all the DMA data */
+ ide->dma_bytes_left = 0;
+ ide->dma_last_buffer = 0;
+ ide->dma_descriptor = ide->bus_master_descriptor;
+ ide->dma_cpu = cpu_getactivecpu();
+ ide->dma_address_xor = (activecpu_endianness() == CPU_IS_LE) ? 0 : 3;
+
+ /* if we're going live, start the pending read/write */
+ if (ide->dma_active)
+ {
+ if (ide->bus_master_command & 8)
+ read_next_sector(ide);
+ else
+ {
+ read_buffer_from_dma(ide);
+ continue_write(ide);
+ }
+ }
+ }
+ }
+
+ /* status register */
+ if (offset <= 2 && offset + size > 2)
+ {
+ UINT8 old = ide->bus_master_status;
+ UINT8 val = data >> (8 * (2 - offset));
+
+ /* save the DMA capable bits */
+ ide->bus_master_status = (old & 0x9f) | (val & 0x60);
+
+ /* clear interrupt and error bits */
+ if (val & IDE_BUSMASTER_STATUS_IRQ)
+ ide->bus_master_status &= ~IDE_BUSMASTER_STATUS_IRQ;
+ if (val & IDE_BUSMASTER_STATUS_ERROR)
+ ide->bus_master_status &= ~IDE_BUSMASTER_STATUS_ERROR;
+ }
+
+ /* descriptor table register */
+ if (offset == 4)
+ ide->bus_master_descriptor = data & 0xfffffffc;
+}
+
+
+
+/*************************************
+ *
+ * IDE direct handlers (16-bit)
+ *
+ *************************************/
+
+/*
+ ide_bus_0_r()
+
+ Read a 16-bit word from the IDE bus directly.
+
+ select: 0->CS1Fx active, 1->CS3Fx active
+ offset: register offset (state of DA2-DA0)
+*/
+int ide_bus_0_r(int select, int offset)
+{
+ offset += select ? 0x3f0 : 0x1f0;
+ return ide_controller_read(&idestate[0], offset, (offset == 0x1f0) ? 2 : 1);
+}
+
+/*
+ ide_bus_0_w()
+
+ Write a 16-bit word to the IDE bus directly.
+
+ select: 0->CS1Fx active, 1->CS3Fx active
+ offset: register offset (state of DA2-DA0)
+ data: data written (state of D0-D15 or D0-D7)
+*/
+void ide_bus_0_w(int select, int offset, int data)
+{
+ offset += select ? 0x3f0 : 0x1f0;
+ if (offset == 0x1f0)
+ ide_controller_write(&idestate[0], offset, 2, data);
+ else
+ ide_controller_write(&idestate[0], offset, 1, data & 0xff);
+}
+
+int ide_controller_0_r(int reg)
+{
+ return ide_controller_read(&idestate[0], reg, 1);
+}
+
+void ide_controller_0_w(int reg, int data)
+{
+ ide_controller_write(&idestate[0], reg, 1, data);
+}
+
+
+/*************************************
+ *
+ * 32-bit IDE handlers
+ *
+ *************************************/
+
+READ32_HANDLER( ide_controller32_0_r )
+{
+ int size;
+
+ offset *= 4;
+ size = convert_to_offset_and_size32(&offset, mem_mask);
+
+ return ide_controller_read(&idestate[0], offset, size) << ((offset & 3) * 8);
+}
+
+
+WRITE32_HANDLER( ide_controller32_0_w )
+{
+ int size;
+
+ offset *= 4;
+ size = convert_to_offset_and_size32(&offset, mem_mask);
+
+ ide_controller_write(&idestate[0], offset, size, data >> ((offset & 3) * 8));
+}
+
+
+READ32_HANDLER( ide_bus_master32_0_r )
+{
+ int size;
+
+ offset *= 4;
+ size = convert_to_offset_and_size32(&offset, mem_mask);
+
+ return ide_bus_master_read(&idestate[0], offset, size) << ((offset & 3) * 8);
+}
+
+
+WRITE32_HANDLER( ide_bus_master32_0_w )
+{
+ int size;
+
+ offset *= 4;
+ size = convert_to_offset_and_size32(&offset, mem_mask);
+
+ ide_bus_master_write(&idestate[0], offset, size, data >> ((offset & 3) * 8));
+}
+
+
+
+/*************************************
+ *
+ * 16-bit IDE handlers
+ *
+ *************************************/
+
+READ16_HANDLER( ide_controller16_0_r )
+{
+ int size;
+
+ offset *= 2;
+ size = convert_to_offset_and_size16(&offset, mem_mask);
+
+ return ide_controller_read(&idestate[0], offset, size) << ((offset & 1) * 8);
+}
+
+
+WRITE16_HANDLER( ide_controller16_0_w )
+{
+ int size;
+
+ offset *= 2;
+ size = convert_to_offset_and_size16(&offset, mem_mask);
+
+ ide_controller_write(&idestate[0], offset, size, data >> ((offset & 1) * 8));
+}
diff --git a/src/emu/machine/idectrl.h b/src/emu/machine/idectrl.h
new file mode 100644
index 00000000000..0112d6d71f4
--- /dev/null
+++ b/src/emu/machine/idectrl.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+
+ Generic (PC-style) IDE controller implementation
+
+***************************************************************************/
+
+#include "harddisk.h"
+
+
+#define MAX_IDE_CONTROLLERS 1
+
+struct ide_interface
+{
+ void (*interrupt)(int state);
+};
+
+int ide_controller_init(int which, struct ide_interface *intf);
+int ide_controller_init_custom(int which, struct ide_interface *intf, chd_file *diskhandle);
+void ide_controller_reset(int which);
+UINT8 *ide_get_features(int which);
+
+void ide_set_master_password(int which, UINT8 *password);
+void ide_set_user_password(int which, UINT8 *password);
+
+int ide_bus_0_r(int select, int offset);
+void ide_bus_0_w(int select, int offset, int data);
+
+int ide_controller_0_r(int reg);
+void ide_controller_0_w(int reg, int data);
+
+READ32_HANDLER( ide_controller32_0_r );
+WRITE32_HANDLER( ide_controller32_0_w );
+READ32_HANDLER( ide_bus_master32_0_r );
+WRITE32_HANDLER( ide_bus_master32_0_w );
+
+READ16_HANDLER( ide_controller16_0_r );
+WRITE16_HANDLER( ide_controller16_0_w );
diff --git a/src/emu/machine/intelfsh.c b/src/emu/machine/intelfsh.c
new file mode 100644
index 00000000000..54b894cb5d7
--- /dev/null
+++ b/src/emu/machine/intelfsh.c
@@ -0,0 +1,493 @@
+/*
+ Flash ROM emulation
+
+ Explicitly supports:
+ Intel 28F016S5 (byte-wide)
+ AMD/Fujitsu 29F016 (byte-wide)
+ Sharp LH28F400 (word-wide)
+
+ Flash ROMs use a standardized command set accross manufacturers,
+ so this emulation should work even for non-Intel and non-Sharp chips
+ as long as the game doesn't query the maker ID.
+*/
+
+#include "driver.h"
+#include "intelfsh.h"
+
+enum
+{
+ FM_NORMAL, // normal read/write
+ FM_READID, // read ID
+ FM_READSTATUS, // read status
+ FM_WRITEPART1, // first half of programming, awaiting second
+ FM_CLEARPART1, // first half of clear, awaiting second
+ FM_SETMASTER, // first half of set master lock, awaiting on/off
+ FM_READAMDID1, // part 1 of alt ID sequence
+ FM_READAMDID2, // part 2 of alt ID sequence
+ FM_READAMDID3, // part 3 of alt ID sequence
+ FM_ERASEAMD1, // part 1 of AMD erase sequence
+ FM_ERASEAMD2, // part 2 of AMD erase sequence
+ FM_ERASEAMD3, // part 3 of AMD erase sequence
+ FM_ERASEAMD4, // part 4 of AMD erase sequence
+ FM_BYTEPROGRAM,
+};
+
+struct flash_chip
+{
+ int type;
+ int size;
+ int bits;
+ int status;
+ INT32 flash_mode;
+ INT32 flash_master_lock;
+ int device_id;
+ int maker_id;
+ emu_timer *timer;
+ void *flash_memory;
+};
+
+static struct flash_chip chips[FLASH_CHIPS_MAX];
+
+static TIMER_CALLBACK_PTR( erase_finished )
+{
+ struct flash_chip *c = param;
+
+ switch( c->flash_mode )
+ {
+ case FM_READSTATUS:
+ c->status = 0x80;
+ break;
+
+ case FM_ERASEAMD4:
+ c->flash_mode = FM_NORMAL;
+ break;
+ }
+}
+
+void* intelflash_getmemptr(int chip)
+{
+ struct flash_chip *c;
+ if( chip >= FLASH_CHIPS_MAX )
+ {
+ logerror( "intelflash_init: invalid chip %d\n", chip );
+ return 0;
+ }
+ c = &chips[ chip ];
+
+ return c->flash_memory;
+}
+
+void intelflash_init(int chip, int type, void *data)
+{
+ struct flash_chip *c;
+ if( chip >= FLASH_CHIPS_MAX )
+ {
+ logerror( "intelflash_init: invalid chip %d\n", chip );
+ return;
+ }
+ c = &chips[ chip ];
+
+ c->type = type;
+ switch( c->type )
+ {
+ case FLASH_INTEL_28F016S5:
+ case FLASH_SHARP_LH28F016S:
+ c->bits = 8;
+ c->size = 0x200000;
+ c->maker_id = 0x89;
+ c->device_id = 0xaa;
+ break;
+ case FLASH_SHARP_LH28F400:
+ c->bits = 16;
+ c->size = 0x80000;
+ c->maker_id = 0xb0;
+ c->device_id = 0xed;
+ break;
+ case FLASH_FUJITSU_29F016A:
+ c->bits = 8;
+ c->size = 0x200000;
+ c->maker_id = 0x04;
+ c->device_id = 0xad;
+ break;
+ case FLASH_INTEL_E28F008SA:
+ c->bits = 8;
+ c->size = 0x100000;
+ c->maker_id = 0x89;
+ c->device_id = 0xa2;
+ break;
+ case FLASH_INTEL_TE28F160:
+ c->bits = 16;
+ c->size = 0x200000;
+ c->maker_id = 0xb0;
+ c->device_id = 0xd0;
+ break;
+ }
+ if( data == NULL )
+ {
+ data = auto_malloc( c->size );
+ memset( data, 0xff, c->size );
+ }
+
+ c->status = 0x80;
+ c->flash_mode = FM_NORMAL;
+ c->flash_master_lock = 0;
+ c->timer = timer_alloc_ptr(erase_finished, c);
+ c->flash_memory = data;
+
+ state_save_register_item( "intelfsh", chip, c->status );
+ state_save_register_item( "intelfsh", chip, c->flash_mode );
+ state_save_register_item( "intelfsh", chip, c->flash_master_lock );
+ state_save_register_memory( "intelfsh", chip, "flash_memory", c->flash_memory, c->bits/8, c->size / (c->bits/8) );
+}
+
+UINT32 intelflash_read(int chip, UINT32 address)
+{
+ UINT32 data = 0;
+ struct flash_chip *c;
+ if( chip >= FLASH_CHIPS_MAX )
+ {
+ logerror( "intelflash_read: invalid chip %d\n", chip );
+ return 0;
+ }
+ c = &chips[ chip ];
+
+ switch( c->flash_mode )
+ {
+ default:
+ case FM_NORMAL:
+ switch( c->bits )
+ {
+ case 8:
+ {
+ UINT8 *flash_memory = c->flash_memory;
+ data = flash_memory[ address ];
+ }
+ break;
+ case 16:
+ {
+ UINT16 *flash_memory = c->flash_memory;
+ data = flash_memory[ address ];
+ }
+ break;
+ }
+ break;
+ case FM_READSTATUS:
+ data = c->status;
+ break;
+ case FM_READAMDID3:
+ switch (address)
+ {
+ case 0: data = c->maker_id; break;
+ case 1: data = c->device_id; break;
+ case 2: data = 0; break;
+ }
+ break;
+ case FM_READID:
+ switch (address)
+ {
+ case 0: // maker ID
+ data = c->maker_id;
+ break;
+ case 1: // chip ID
+ data = c->device_id;
+ break;
+ case 2: // block lock config
+ data = 0; // we don't support this yet
+ break;
+ case 3: // master lock config
+ if (c->flash_master_lock)
+ {
+ data = 1;
+ }
+ else
+ {
+ data = 0;
+ }
+ break;
+ }
+ break;
+ case FM_ERASEAMD4:
+ c->status ^= ( 1 << 6 ) | ( 1 << 2 );
+ data = c->status;
+ break;
+ }
+
+// logerror( "%08x: intelflash_read( %d, %08x ) %08x\n", activecpu_get_pc(), chip, address, data );
+
+ return data;
+}
+
+void intelflash_write(int chip, UINT32 address, UINT32 data)
+{
+ struct flash_chip *c;
+ if( chip >= FLASH_CHIPS_MAX )
+ {
+ logerror( "intelflash_write: invalid chip %d\n", chip );
+ return;
+ }
+ c = &chips[ chip ];
+
+// logerror( "%08x: intelflash_write( %d, %08x, %08x )\n", activecpu_get_pc(), chip, address, data );
+
+ switch( c->flash_mode )
+ {
+ case FM_NORMAL:
+ case FM_READSTATUS:
+ case FM_READID:
+ case FM_READAMDID3:
+ switch( data & 0xff )
+ {
+ case 0xf0:
+ case 0xff: // reset chip mode
+ c->flash_mode = FM_NORMAL;
+ break;
+ case 0x90: // read ID
+ c->flash_mode = FM_READID;
+ break;
+ case 0x40:
+ case 0x10: // program
+ c->flash_mode = FM_WRITEPART1;
+ break;
+ case 0x50: // clear status reg
+ c->status = 0x80;
+ c->flash_mode = FM_READSTATUS;
+ break;
+ case 0x20: // block erase
+ c->flash_mode = FM_CLEARPART1;
+ break;
+ case 0x60: // set master lock
+ c->flash_mode = FM_SETMASTER;
+ break;
+ case 0x70: // read status
+ c->flash_mode = FM_READSTATUS;
+ break;
+ case 0xaa: // AMD ID select part 1
+ if( ( address & 0xffff ) == 0x555 )
+ {
+ c->flash_mode = FM_READAMDID1;
+ }
+ break;
+ default:
+ logerror( "Unknown flash mode byte %x\n", data & 0xff );
+ break;
+ }
+ break;
+ case FM_READAMDID1:
+ if( ( address & 0xffff ) == 0x2aa && ( data & 0xff ) == 0x55 )
+ {
+ c->flash_mode = FM_READAMDID2;
+ }
+ else
+ {
+ logerror( "unexpected %08x=%02x in FM_READAMDID1\n", address, data & 0xff );
+ c->flash_mode = FM_NORMAL;
+ }
+ break;
+ case FM_READAMDID2:
+ if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0x90 )
+ {
+ c->flash_mode = FM_READAMDID3;
+ }
+ else if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0x80 )
+ {
+ c->flash_mode = FM_ERASEAMD1;
+ }
+ else if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0xa0 )
+ {
+ c->flash_mode = FM_BYTEPROGRAM;
+ }
+ else if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0xf0 )
+ {
+ c->flash_mode = FM_NORMAL;
+ }
+ else
+ {
+ logerror( "unexpected %08x=%02x in FM_READAMDID2\n", address, data & 0xff );
+ c->flash_mode = FM_NORMAL;
+ }
+ break;
+ case FM_ERASEAMD1:
+ if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0xaa )
+ {
+ c->flash_mode = FM_ERASEAMD2;
+ }
+ else
+ {
+ logerror( "unexpected %08x=%02x in FM_ERASEAMD1\n", address, data & 0xff );
+ }
+ break;
+ case FM_ERASEAMD2:
+ if( ( address & 0xffff ) == 0x2aa && ( data & 0xff ) == 0x55 )
+ {
+ c->flash_mode = FM_ERASEAMD3;
+ }
+ else
+ {
+ logerror( "unexpected %08x=%02x in FM_ERASEAMD2\n", address, data & 0xff );
+ }
+ break;
+ case FM_ERASEAMD3:
+ if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0x10 )
+ {
+ // chip erase
+ memset( c->flash_memory, 0xff, c->size);
+
+ c->status = 1 << 3;
+ c->flash_mode = FM_ERASEAMD4;
+
+ timer_adjust_ptr( c->timer, ATTOTIME_IN_SEC( 17 ), attotime_zero );
+ }
+ else if( ( data & 0xff ) == 0x30 )
+ {
+ // sector erase
+ // clear the 64k block containing the current address to all 0xffs
+ switch( c->bits )
+ {
+ case 8:
+ {
+ UINT8 *flash_memory = c->flash_memory;
+ memset( &flash_memory[ address & ~0xffff ], 0xff, 64 * 1024 );
+ }
+ break;
+ case 16:
+ {
+ UINT16 *flash_memory = c->flash_memory;
+ memset( &flash_memory[ address & ~0x7fff ], 0xff, 64 * 1024 );
+ }
+ break;
+ }
+
+ c->status = 1 << 3;
+ c->flash_mode = FM_ERASEAMD4;
+
+ timer_adjust_ptr( c->timer, ATTOTIME_IN_SEC( 1 ), attotime_zero );
+ }
+ else
+ {
+ logerror( "unexpected %08x=%02x in FM_ERASEAMD3\n", address, data & 0xff );
+ }
+ break;
+ case FM_BYTEPROGRAM:
+ switch( c->bits )
+ {
+ case 8:
+ {
+ UINT8 *flash_memory = c->flash_memory;
+ flash_memory[ address ] = data;
+ }
+ break;
+ default:
+ logerror( "FM_BYTEPROGRAM not supported when c->bits == %d\n", c->bits );
+ break;
+ }
+ c->flash_mode = FM_NORMAL;
+ break;
+ case FM_WRITEPART1:
+ switch( c->bits )
+ {
+ case 8:
+ {
+ UINT8 *flash_memory = c->flash_memory;
+ flash_memory[ address ] = data;
+ }
+ break;
+ case 16:
+ {
+ UINT16 *flash_memory = c->flash_memory;
+ flash_memory[ address ] = data;
+ }
+ break;
+ default:
+ logerror( "FM_WRITEPART1 not supported when c->bits == %d\n", c->bits );
+ break;
+ }
+ c->status = 0x80;
+ c->flash_mode = FM_READSTATUS;
+ break;
+ case FM_CLEARPART1:
+ if( ( data & 0xff ) == 0xd0 )
+ {
+ // clear the 64k block containing the current address to all 0xffs
+ switch( c->bits )
+ {
+ case 8:
+ {
+ UINT8 *flash_memory = c->flash_memory;
+ memset( &flash_memory[ address & ~0xffff ], 0xff, 64 * 1024 );
+ }
+ break;
+ case 16:
+ {
+ UINT16 *flash_memory = c->flash_memory;
+ memset( &flash_memory[ address & ~0x7fff ], 0xff, 64 * 1024 );
+ }
+ break;
+ default:
+ logerror( "FM_CLEARPART1 not supported when c->bits == %d\n", c->bits );
+ break;
+ }
+ c->status = 0x00;
+ c->flash_mode = FM_READSTATUS;
+
+ timer_adjust_ptr( c->timer, ATTOTIME_IN_SEC( 1 ), attotime_zero );
+ break;
+ }
+ else
+ {
+ logerror( "unexpected %02x in FM_CLEARPART1\n", data & 0xff );
+ }
+ break;
+ case FM_SETMASTER:
+ switch( data & 0xff )
+ {
+ case 0xf1:
+ c->flash_master_lock = 1;
+ break;
+ case 0xd0:
+ c->flash_master_lock = 0;
+ break;
+ default:
+ logerror( "unexpected %08x=%02x in FM_SETMASTER:\n", address, data & 0xff );
+ break;
+ }
+ c->flash_mode = FM_NORMAL;
+ break;
+ }
+}
+
+void nvram_handler_intelflash(running_machine *machine, int chip,mame_file *file,int read_or_write)
+{
+ struct flash_chip *c;
+ if( chip >= FLASH_CHIPS_MAX )
+ {
+ logerror( "intelflash_nvram: invalid chip %d\n", chip );
+ return;
+ }
+ c = &chips[ chip ];
+
+ switch( c->bits )
+ {
+ case 8:
+ if (read_or_write)
+ {
+ mame_fwrite( file, c->flash_memory, c->size );
+ }
+ else if (file)
+ {
+ mame_fread( file, c->flash_memory, c->size );
+ }
+ break;
+ case 16:
+ if (read_or_write)
+ {
+ /// TODO: endian conversion
+ mame_fwrite( file, c->flash_memory, c->size );
+ }
+ else if (file)
+ {
+ mame_fread( file, c->flash_memory, c->size );
+ /// TODO: endian conversion
+ }
+ break;
+ }
+}
diff --git a/src/emu/machine/intelfsh.h b/src/emu/machine/intelfsh.h
new file mode 100644
index 00000000000..f756141e691
--- /dev/null
+++ b/src/emu/machine/intelfsh.h
@@ -0,0 +1,23 @@
+/*
+ Intel Flash ROM emulation
+*/
+
+#ifndef _INTELFLASH_H_
+#define _INTELFLASH_H_
+
+#define FLASH_CHIPS_MAX ( 56 )
+
+#define FLASH_INTEL_28F016S5 ( 0 )
+#define FLASH_SHARP_LH28F400 ( 1 )
+#define FLASH_FUJITSU_29F016A ( 2 )
+#define FLASH_INTEL_E28F008SA ( 3 )
+#define FLASH_INTEL_TE28F160 ( 4 )
+#define FLASH_SHARP_LH28F016S ( 5 )
+
+extern void intelflash_init( int chip, int type, void *data );
+extern UINT32 intelflash_read( int chip, UINT32 address );
+extern void intelflash_write( int chip, UINT32 address, UINT32 value );
+extern void nvram_handler_intelflash( running_machine *machine, int chip, mame_file *file, int read_or_write );
+extern void* intelflash_getmemptr(int chip);
+
+#endif
diff --git a/src/emu/machine/laserdsc.c b/src/emu/machine/laserdsc.c
new file mode 100644
index 00000000000..3ab6eeb7412
--- /dev/null
+++ b/src/emu/machine/laserdsc.c
@@ -0,0 +1,3361 @@
+/*************************************************************************
+
+ laserdsc.c
+
+ Generic laserdisc support.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*************************************************************************/
+
+#include "driver.h"
+#include "laserdsc.h"
+#include "avcomp.h"
+#include "profiler.h"
+#include "streams.h"
+#include "sound/custom.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define PRINTF_COMMANDS 1
+
+#if PRINTF_COMMANDS
+#define CMDPRINTF(x) mame_printf_debug x
+#else
+#define CMDPRINTF(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* fractional track handling */
+#define FRACBITS 12
+#define FRAC_ONE (1 << FRACBITS)
+#define INT_TO_FRAC(x) ((x) << FRACBITS)
+#define FRAC_TO_INT(x) ((x) >> FRACBITS)
+
+/* general laserdisc states */
+enum _laserdisc_state
+{
+ LASERDISC_EJECTED, /* no disc present */
+ LASERDISC_EJECTING, /* in the process of ejecting */
+ LASERDISC_LOADED, /* disc just loaded */
+ LASERDISC_LOADING, /* in the process of loading */
+ LASERDISC_PARKED, /* disc loaded, not playing, head on parked position */
+ LASERDISC_SPINUP, /* disc loaded, spinning up to speed */
+
+ LASERDISC_SEARCHING_FRAME, /* searching (seeking) to a new frame */
+ LASERDISC_SEARCH_FINISHED, /* finished searching; same as stopped */
+
+ LASERDISC_STOPPED, /* stopped (paused) with video visible and no sound */
+ LASERDISC_AUTOSTOPPED, /* autostopped; same as stopped */
+
+ LASERDISC_PLAYING_FORWARD, /* playing at 1x in the forward direction */
+ LASERDISC_PLAYING_REVERSE, /* playing at 1x in the reverse direction */
+ LASERDISC_PLAYING_SLOW_FORWARD, /* playing forward slowly */
+ LASERDISC_PLAYING_SLOW_REVERSE, /* playing backward slowly */
+ LASERDISC_PLAYING_FAST_FORWARD, /* playing fast forward */
+ LASERDISC_PLAYING_FAST_REVERSE, /* playing fast backward */
+ LASERDISC_STEPPING_FORWARD, /* stepping forward */
+ LASERDISC_STEPPING_REVERSE, /* stepping backward */
+ LASERDISC_SCANNING_FORWARD, /* scanning forward at the scan rate */
+ LASERDISC_SCANNING_REVERSE /* scanning backward at the scan rate */
+};
+typedef enum _laserdisc_state laserdisc_state;
+
+/* generic states and configuration */
+#define FRAMEFLAG_PREV_SAME_FRAME 0x01
+#define FRAMEFLAG_NEXT_SAME_FRAME 0x02
+
+#define AUDIO_CH1_ENABLE 0x01
+#define AUDIO_CH2_ENABLE 0x02
+#define AUDIO_EXPLICIT_MUTE 0x04
+#define AUDIO_IMPLICIT_MUTE 0x08
+
+#define VIDEO_ENABLE 0x01
+#define VIDEO_EXPLICIT_MUTE 0x02
+#define VIDEO_IMPLICIT_MUTE 0x04
+
+#define DISPLAY_ENABLE 0x01
+
+#define NULL_TARGET_FRAME 0 /* frame 0 indicates no target */
+#define ONE_TRACK INT_TO_FRAC(1) /* a single track, or track #1 */
+#define STOP_SPEED INT_TO_FRAC(0) /* no movement */
+#define PLAY_SPEED INT_TO_FRAC(1) /* regular playback speed */
+
+#define GENERIC_SPINUP_TIME (attotime_make(3, 0))
+#define GENERIC_LOAD_TIME (attotime_make(10, 0))
+#define GENERIC_RESET_SPEED INT_TO_FRAC(5000)
+
+/* Pioneer PR-7820 specific states */
+#define PR7820_MODE_MANUAL 0
+#define PR7820_MODE_AUTOMATIC 1
+#define PR7820_MODE_PROGRAM 2
+
+#define PR7820_SEARCH_SPEED INT_TO_FRAC(5000)
+
+/* Pioneer PR-8210/LD-V1100 specific states */
+#define PR8210_MODE_GET_1ST 0
+#define PR8210_MODE_GET_2ND 1
+#define PR8210_MODE_GET_3RD 2
+
+#define PR8210_SCAN_SPEED (INT_TO_FRAC(2000) / 30)
+#define PR8210_FAST_SPEED (PLAY_SPEED * 3)
+#define PR8210_SLOW_SPEED (PLAY_SPEED / 5)
+#define PR8210_STEP_SPEED (PLAY_SPEED / 7)
+#define PR8210_SEARCH_SPEED INT_TO_FRAC(5000)
+
+/* Pioneer LD-V1000 specific states */
+#define LDV1000_MODE_STATUS 0
+#define LDV1000_MODE_GET_FRAME 1
+#define LDV1000_MODE_GET_1ST 2
+#define LDV1000_MODE_GET_2ND 3
+#define LDV1000_MODE_GET_RAM 4
+
+#define LDV1000_SCAN_SPEED (INT_TO_FRAC(2000) / 30)
+#define LDV1000_SEARCH_SPEED INT_TO_FRAC(5000)
+
+/* Sony LDP-1450 specific states */
+#define LDP1450_SCAN_SPEED (INT_TO_FRAC(2000) / 30)
+#define LDP1450_FAST_SPEED (PLAY_SPEED * 3)
+#define LDP1450_SLOW_SPEED (PLAY_SPEED / 5)
+#define LDP1450_STEP_SPEED (PLAY_SPEED / 7)
+#define LDP1450_SEARCH_SPEED INT_TO_FRAC(5000)
+
+/* Philips 22VP932 specific states */
+#define VP932_SCAN_SPEED (INT_TO_FRAC(2000) / 30)
+#define VP932_FAST_SPEED (PLAY_SPEED * 3)
+#define VP932_SLOW_SPEED (PLAY_SPEED / 5)
+#define VP932_STEP_SPEED (PLAY_SPEED / 7)
+#define VP932_SEARCH_SPEED INT_TO_FRAC(5000)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* PR-7820-specific data */
+typedef struct _pr7820_info pr7820_info;
+struct _pr7820_info
+{
+ UINT8 mode; /* current mode */
+ UINT32 curpc; /* current PC for automatic execution */
+ INT32 configspeed; /* configured speed */
+ UINT32 activereg; /* active register index */
+ UINT8 ram[1024]; /* RAM */
+};
+
+
+/* PR8210-specific data */
+typedef struct _pr8210_info pr8210_info;
+struct _pr8210_info
+{
+ UINT8 mode; /* current mode */
+ UINT16 commandtriplet[3]; /* current command triplet */
+ attotime commandtime; /* command time */
+ UINT8 commandbits; /* command bit count */
+ UINT8 seekstate; /* state of the seek command */
+};
+
+
+/* LD-V1000-specific data */
+typedef struct _ldv1000_info ldv1000_info;
+struct _ldv1000_info
+{
+ UINT8 mode; /* current mode */
+ UINT32 activereg; /* active register index */
+ UINT8 ram[1024]; /* RAM */
+ UINT32 readpos; /* current read position */
+ UINT32 readtotal; /* current read position */
+ UINT8 readbuf[256]; /* temporary read buffer */
+ UINT8 statusmask; /* status bits mask */
+};
+
+
+/* LDP-1450-specific data */
+typedef struct _ldp1450_info ldp1450_info;
+struct _ldp1450_info
+{
+ UINT32 readpos; /* current read position */
+ UINT32 readtotal; /* current read position */
+ UINT8 readbuf[256]; /* temporary read buffer */
+};
+
+
+/* 22VP932-specific data */
+typedef struct _vp932_info vp932_info;
+struct _vp932_info
+{
+ UINT8 incount; /* number of pending bytes accumulated */
+ UINT8 inbuffer[8]; /* input data */
+ UINT8 outcount; /* number of pending bytes to send */
+ UINT8 outbuffer[8]; /* output data */
+};
+
+
+/* per-field metadata */
+typedef struct _field_metadata field_metadata;
+struct _field_metadata
+{
+ UINT8 version; /* version of the data */
+ UINT8 frameflags; /* per-frame flags */
+ UINT8 whiteflag; /* white flag */
+ UINT32 line16; /* line 16 Philips code */
+ UINT32 line17; /* line 17 Philips code */
+ UINT32 line18; /* line 18 Philips code */
+};
+
+
+/* generic data */
+struct _laserdisc_info
+{
+ /* disc parameters */
+ chd_file * disc; /* handle to the disc itself */
+ av_codec_decompress_config avconfig; /* decompression configuration */
+ UINT8 readpending; /* true if a read is pending */
+ UINT8 * framebuffer; /* buffer to hold one frame */
+ UINT32 maxfractrack; /* maximum track number */
+ UINT32 fieldnum; /* field number (0 or 1) */
+
+ /* video data */
+ mame_bitmap * videoframe[2]; /* currently cached frames */
+ UINT8 videofields[2]; /* number of fields in each frame */
+ UINT32 videoframenum[2]; /* frame number contained in each frame */
+ UINT8 videoindex; /* index of the current video buffer */
+ mame_bitmap * emptyframe; /* blank frame */
+
+ /* audio data */
+ INT16 * audiobuffer[2]; /* buffer for audio samples */
+ UINT32 audiobufsize; /* size of buffer */
+ UINT32 audiobufin; /* input index */
+ UINT32 audiobufout; /* output index */
+ int audiocustom; /* custom sound index */
+
+ /* metadata */
+ field_metadata metadata[2]; /* metadata parsed from the stream, for each field */
+ int last_frame; /* last seen frame number */
+ int last_chapter; /* last seen chapter number */
+
+ /* core states */
+ UINT8 type; /* laserdisc type */
+ laserdisc_state state; /* current player state */
+ UINT8 video; /* video state: bit 0 = on/off */
+ UINT8 audio; /* audio state: bit 0 = audio 1, bit 1 = audio 2 */
+ UINT8 display; /* display state: bit 0 = on/off */
+ attotime lastvsynctime; /* time of the last vsync */
+
+ /* deferred states */
+ attotime holdfinished; /* time when current state will advance */
+ UINT8 postholdstate; /* state to switch into after holding */
+ INT32 postholdfracspeed; /* speed after the hold */
+
+ /* input data */
+ UINT8 datain; /* current input data value */
+ UINT8 linein[LASERDISC_INPUT_LINES]; /* current input line state */
+
+ /* output data */
+ UINT8 dataout; /* current output data value */
+ UINT8 lineout[LASERDISC_OUTPUT_LINES]; /* current output line state */
+
+ /* command and parameter buffering */
+ UINT8 command; /* current command */
+ INT32 parameter; /* command parameter */
+
+ /* playback/search/scan speeds */
+ INT32 curfracspeed; /* current speed the head is moving */
+ INT32 curfractrack; /* current track */
+ INT32 targetframe; /* target frame (0 means no target) */
+
+ /* debugging */
+ char text[100]; /* buffer for the state */
+
+ /* filled in by player-specific init */
+ void (*writedata)(laserdisc_info *info, UINT8 prev, UINT8 new); /* write callback */
+ void (*writeline[LASERDISC_INPUT_LINES])(laserdisc_info *info, UINT8 new); /* write line callback */
+ UINT8 (*readdata)(laserdisc_info *info); /* status callback */
+ UINT8 (*readline[LASERDISC_OUTPUT_LINES])(laserdisc_info *info); /* read line callback */
+ void (*statechanged)(laserdisc_info *info, UINT8 oldstate); /* state changed callback */
+
+ /* some player-specific data */
+ union
+ {
+ pr7820_info pr7820; /* PR-7820-specific info */
+ pr8210_info pr8210; /* PR-8210-specific info */
+ ldv1000_info ldv1000; /* LD-V1000-specific info */
+ ldp1450_info ldp1450; /* LDP-1450-specific info */
+ vp932_info vp932; /* 22VP932-specific info */
+ } u;
+};
+
+
+/* sound callback info */
+typedef struct _sound_token sound_token;
+struct _sound_token
+{
+ sound_stream * stream;
+ laserdisc_info *info;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* generic helper functions */
+static int update_position(laserdisc_info *info);
+static void read_track_data(laserdisc_info *info);
+static void process_track_data(laserdisc_info *info);
+static int parse_metadata(const UINT8 *rawdata, UINT32 track, UINT8 which, field_metadata *metadata);
+static void *custom_start(int clock, const struct CustomSound_interface *config);
+static void custom_stream_callback(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
+
+/* Pioneer PR-7820 implementation */
+static void pr7820_init(laserdisc_info *info);
+static void pr7820_soft_reset(laserdisc_info *info);
+static void pr7820_enter_w(laserdisc_info *info, UINT8 data);
+static UINT8 pr7820_ready_r(laserdisc_info *info);
+static UINT8 pr7820_status_r(laserdisc_info *info);
+
+/* Pioneer PR-8210 implementation */
+static void pr8210_init(laserdisc_info *info);
+static void pr8210_soft_reset(laserdisc_info *info);
+static void pr8210_command(laserdisc_info *info);
+static void pr8210_control_w(laserdisc_info *info, UINT8 data);
+
+/* Pioneer LDV-1000 implementation */
+static void ldv1000_init(laserdisc_info *info);
+static void ldv1000_soft_reset(laserdisc_info *info);
+static void ldv1000_data_w(laserdisc_info *info, UINT8 prev, UINT8 data);
+static UINT8 ldv1000_status_strobe_r(laserdisc_info *info);
+static UINT8 ldv1000_command_strobe_r(laserdisc_info *info);
+static UINT8 ldv1000_status_r(laserdisc_info *info);
+
+/* Sony LDP-1450 implementation */
+static void ldp1450_init(laserdisc_info *info);
+static void ldp1450_soft_reset(laserdisc_info *info);
+static void ldp1450_compute_status(laserdisc_info *info);
+static void ldp1450_data_w(laserdisc_info *info, UINT8 prev, UINT8 data);
+static UINT8 ldp1450_data_avail_r(laserdisc_info *info);
+static UINT8 ldp1450_data_r(laserdisc_info *info);
+static void ldp1450_state_changed(laserdisc_info *info, UINT8 oldstate);
+
+/* Philips 22VP932 implementation */
+static void vp932_init(laserdisc_info *info);
+static void vp932_soft_reset(laserdisc_info *info);
+static void vp932_data_w(laserdisc_info *info, UINT8 prev, UINT8 data);
+static UINT8 vp932_data_avail_r(laserdisc_info *info);
+static UINT8 vp932_data_r(laserdisc_info *info);
+static void vp932_state_changed(laserdisc_info *info, UINT8 oldstate);
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+struct CustomSound_interface laserdisc_custom_interface =
+{
+ custom_start
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ audio_channel_active - return TRUE if the
+ given audio channel should be output
+-------------------------------------------------*/
+
+INLINE int audio_channel_active(laserdisc_info *info, int channel)
+{
+ int result = (info->audio >> channel) & 1;
+
+ /* apply muting */
+ if (info->audio & (AUDIO_EXPLICIT_MUTE | AUDIO_IMPLICIT_MUTE))
+ result = 0;
+
+ /* implicitly muted during some states */
+ switch (info->state)
+ {
+ case LASERDISC_EJECTED:
+ case LASERDISC_EJECTING:
+ case LASERDISC_LOADING:
+ case LASERDISC_SPINUP:
+ case LASERDISC_PARKED:
+ case LASERDISC_LOADED:
+ case LASERDISC_SEARCHING_FRAME:
+ case LASERDISC_SEARCH_FINISHED:
+ case LASERDISC_STOPPED:
+ case LASERDISC_AUTOSTOPPED:
+ case LASERDISC_PLAYING_SLOW_FORWARD:
+ case LASERDISC_PLAYING_SLOW_REVERSE:
+ case LASERDISC_PLAYING_FAST_FORWARD:
+ case LASERDISC_PLAYING_FAST_REVERSE:
+ case LASERDISC_SCANNING_FORWARD:
+ case LASERDISC_SCANNING_REVERSE:
+ case LASERDISC_STEPPING_FORWARD:
+ case LASERDISC_STEPPING_REVERSE:
+ result = 0;
+ break;
+
+ default:
+ break;
+ }
+ return result;
+}
+
+
+/*-------------------------------------------------
+ video_active - return TRUE if the video should
+ be output
+-------------------------------------------------*/
+
+INLINE int video_active(laserdisc_info *info)
+{
+ int result = info->video & VIDEO_ENABLE;
+
+ /* apply muting */
+ if (info->video & (VIDEO_EXPLICIT_MUTE | VIDEO_IMPLICIT_MUTE))
+ result = 0;
+
+ /* implicitly muted during some states */
+ switch (info->state)
+ {
+ case LASERDISC_EJECTED:
+ case LASERDISC_EJECTING:
+ case LASERDISC_LOADING:
+ case LASERDISC_SPINUP:
+ case LASERDISC_PARKED:
+ case LASERDISC_LOADED:
+ case LASERDISC_SEARCHING_FRAME:
+ result = 0;
+ break;
+
+ default:
+ break;
+ }
+ return result;
+}
+
+
+/*-------------------------------------------------
+ laserdisc_ready - return TRUE if the
+ disc is not in a transient state
+-------------------------------------------------*/
+
+INLINE int laserdisc_ready(laserdisc_info *info)
+{
+ switch (info->state)
+ {
+ case LASERDISC_EJECTED:
+ case LASERDISC_EJECTING:
+ case LASERDISC_LOADING:
+ case LASERDISC_SPINUP:
+ case LASERDISC_PARKED:
+ return FALSE;
+
+ case LASERDISC_LOADED:
+ case LASERDISC_SEARCHING_FRAME:
+ case LASERDISC_SEARCH_FINISHED:
+ case LASERDISC_STOPPED:
+ case LASERDISC_AUTOSTOPPED:
+ case LASERDISC_PLAYING_FORWARD:
+ case LASERDISC_PLAYING_REVERSE:
+ case LASERDISC_PLAYING_SLOW_FORWARD:
+ case LASERDISC_PLAYING_SLOW_REVERSE:
+ case LASERDISC_PLAYING_FAST_FORWARD:
+ case LASERDISC_PLAYING_FAST_REVERSE:
+ case LASERDISC_STEPPING_FORWARD:
+ case LASERDISC_STEPPING_REVERSE:
+ case LASERDISC_SCANNING_FORWARD:
+ case LASERDISC_SCANNING_REVERSE:
+ return TRUE;
+ }
+ fatalerror("Unexpected state in laserdisc_ready\n");
+}
+
+
+/*-------------------------------------------------
+ laserdisc_active - return TRUE if the
+ disc is in a playing/spinning state
+-------------------------------------------------*/
+
+INLINE int laserdisc_active(laserdisc_info *info)
+{
+ switch (info->state)
+ {
+ case LASERDISC_EJECTED:
+ case LASERDISC_EJECTING:
+ case LASERDISC_LOADED:
+ case LASERDISC_LOADING:
+ case LASERDISC_SPINUP:
+ case LASERDISC_PARKED:
+ return FALSE;
+
+ case LASERDISC_SEARCHING_FRAME:
+ case LASERDISC_SEARCH_FINISHED:
+ case LASERDISC_STOPPED:
+ case LASERDISC_AUTOSTOPPED:
+ case LASERDISC_PLAYING_FORWARD:
+ case LASERDISC_PLAYING_REVERSE:
+ case LASERDISC_PLAYING_SLOW_FORWARD:
+ case LASERDISC_PLAYING_SLOW_REVERSE:
+ case LASERDISC_PLAYING_FAST_FORWARD:
+ case LASERDISC_PLAYING_FAST_REVERSE:
+ case LASERDISC_STEPPING_FORWARD:
+ case LASERDISC_STEPPING_REVERSE:
+ case LASERDISC_SCANNING_FORWARD:
+ case LASERDISC_SCANNING_REVERSE:
+ return TRUE;
+ }
+ fatalerror("Unexpected state in laserdisc_ready\n");
+}
+
+
+/*-------------------------------------------------
+ set_state - configure the current playback
+ state
+-------------------------------------------------*/
+
+INLINE void set_state(laserdisc_info *info, laserdisc_state state, INT32 fracspeed, INT32 targetframe)
+{
+ info->holdfinished.seconds = 0;
+ info->holdfinished.attoseconds = 0;
+ info->state = state;
+ info->curfracspeed = fracspeed;
+ info->targetframe = targetframe;
+}
+
+
+/*-------------------------------------------------
+ set_hold_state - configure a hold time and
+ a playback state to follow
+-------------------------------------------------*/
+
+INLINE void set_hold_state(laserdisc_info *info, attotime holdtime, laserdisc_state state, INT32 fracspeed)
+{
+ info->holdfinished = attotime_add(timer_get_time(), holdtime);
+ info->postholdstate = state;
+ info->postholdfracspeed = fracspeed;
+}
+
+
+/*-------------------------------------------------
+ add_to_current_track - add a value to the
+ current track, stopping if we hit the min or
+ max
+-------------------------------------------------*/
+
+INLINE int add_to_current_track(laserdisc_info *info, INT32 delta)
+{
+ info->curfractrack += delta;
+ if (info->curfractrack < ONE_TRACK)
+ {
+ info->curfractrack = ONE_TRACK;
+ return TRUE;
+ }
+ else if (info->curfractrack >= info->maxfractrack - ONE_TRACK)
+ {
+ info->curfractrack = info->maxfractrack - ONE_TRACK;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ frame_from_metadata - return the frame number
+ encoded in the metadata, if present, or -1
+-------------------------------------------------*/
+
+INLINE int frame_from_metadata(const field_metadata *metadata)
+{
+ UINT32 data;
+
+ if ((metadata->line17 & 0xf80000) == 0xf80000)
+ data = metadata->line17 & 0x7ffff;
+ else if ((metadata->line18 & 0xf80000) == 0xf80000)
+ data = metadata->line18 & 0x7ffff;
+ else
+ return -1;
+
+ return (((data >> 16) & 0x0f) * 10000) + (((data >> 12) & 0x0f) * 1000) + (((data >> 8) & 0x0f) * 100) + (((data >> 4) & 0x0f) * 10) + (data & 0x0f);
+}
+
+
+/*-------------------------------------------------
+ chapter_from_metadata - return the chapter
+ number encoded in the metadata, if present,
+ or -1
+-------------------------------------------------*/
+
+INLINE int chapter_from_metadata(const field_metadata *metadata)
+{
+ UINT32 data;
+
+ if ((metadata->line17 & 0xf00fff) == 0x800ddd)
+ data = metadata->line17 & 0x7f000;
+ else if ((metadata->line18 & 0xf00fff) == 0x800ddd)
+ data = metadata->line18 & 0x7f000;
+ else
+ return -1;
+
+ return (((data >> 16) & 0x0f) * 10) + ((data >> 12) & 0x0f);
+}
+
+
+/*-------------------------------------------------
+ read_16bits_from_ram_be - read 16 bits from
+ player RAM in big-endian format
+-------------------------------------------------*/
+
+INLINE UINT16 read_16bits_from_ram_be(UINT8 *ram, UINT32 offset)
+{
+ return (ram[offset + 0] << 8) | ram[offset + 1];
+}
+
+
+/*-------------------------------------------------
+ write_16bits_to_ram_be - write 16 bits to
+ player RAM in big endian format
+-------------------------------------------------*/
+
+INLINE void write_16bits_to_ram_be(UINT8 *ram, UINT32 offset, UINT16 data)
+{
+ ram[offset + 0] = data >> 8;
+ ram[offset + 1] = data >> 0;
+}
+
+
+/*-------------------------------------------------
+ fillbitmap_yuy16 - fill a YUY16 bitmap with a
+ given color pattern
+-------------------------------------------------*/
+
+INLINE void fillbitmap_yuy16(mame_bitmap *bitmap, UINT8 yval, UINT8 cr, UINT8 cb)
+{
+ UINT16 color0 = (yval << 8) | cb;
+ UINT16 color1 = (yval << 8) | cr;
+ int x, y;
+
+ /* write 32 bits of color (2 pixels at a time) */
+ for (y = 0; y < bitmap->height; y++)
+ {
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ for (x = 0; x < bitmap->width / 2; x++)
+ {
+ *dest++ = color0;
+ *dest++ = color1;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ GENERIC IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ laserdisc_init - initialize state for
+ laserdisc playback
+-------------------------------------------------*/
+
+laserdisc_info *laserdisc_init(int type, chd_file *chd, int custom_index)
+{
+ int fps = 30, fpsfrac = 0, width = 720, height = 240, interlaced = 1, channels = 2, rate = 44100, metabytes = 0;
+ UINT32 fps_times_1million, max_samples_per_track;
+ laserdisc_info *info;
+ char metadata[256];
+ chd_error err;
+
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call laserdisc_init at init time!");
+
+ /* initialize the info */
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+ info->audiocustom = custom_index;
+
+ /* get the disc metadata and extract the info */
+ info->disc = chd;
+ if (info->disc != NULL)
+ {
+ /* require the A/V codec */
+ if (chd_get_header(info->disc)->compression != CHDCOMPRESSION_AV)
+ fatalerror("Laserdisc video must be compressed with the A/V codec!");
+
+ /* read and extract the metadata */
+ err = chd_get_metadata(info->disc, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL);
+ if (err != CHDERR_NONE)
+ fatalerror("Non-A/V CHD file specified");
+ if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate, &metabytes) != 8)
+ fatalerror("Invalid metadata in CHD file");
+
+ /* require interlaced video */
+ if (!interlaced)
+ fatalerror("Laserdisc video must be interlaced!");
+
+ /* determine the maximum track and allocate a frame buffer */
+ info->maxfractrack = INT_TO_FRAC(chd_get_header(info->disc)->totalhunks / (interlaced + 1));
+ info->framebuffer = auto_malloc(chd_get_header(info->disc)->hunkbytes);
+ }
+ else
+ info->maxfractrack = INT_TO_FRAC(54000);
+
+ /* allocate video frames */
+ info->videoframe[0] = auto_bitmap_alloc(width, height * 2, BITMAP_FORMAT_YUY16);
+ fillbitmap_yuy16(info->videoframe[0], 40, 109, 240);
+ info->videoframe[1] = auto_bitmap_alloc(width, height * 2, BITMAP_FORMAT_YUY16);
+ fillbitmap_yuy16(info->videoframe[1], 40, 109, 240);
+ info->emptyframe = auto_bitmap_alloc(width, height * 2, BITMAP_FORMAT_YUY16);
+ fillbitmap_yuy16(info->emptyframe, 0, 128, 128);
+
+ /* allocate audio buffers */
+ fps_times_1million = fps * 1000000 + fpsfrac;
+ max_samples_per_track = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
+ info->audiobufsize = max_samples_per_track * 4;
+ info->audiobuffer[0] = auto_malloc(info->audiobufsize * sizeof(info->audiobuffer[0][0]));
+ info->audiobuffer[1] = auto_malloc(info->audiobufsize * sizeof(info->audiobuffer[1][0]));
+
+ /* attempt to wire up the audio */
+ if (sndti_exists(SOUND_CUSTOM, info->audiocustom))
+ {
+ sound_token *token = custom_get_token(info->audiocustom);
+ token->info = info;
+ stream_set_sample_rate(token->stream, rate);
+ }
+
+ /* reset the disc */
+ laserdisc_reset(info, type);
+ return info;
+}
+
+
+/*-------------------------------------------------
+ laserdisc_reset - reset laserdisc,
+ potentially changing the type
+-------------------------------------------------*/
+
+void laserdisc_reset(laserdisc_info *info, int type)
+{
+ int i;
+
+ /* set up the general info */
+ if (type != 0)
+ info->type = type;
+ info->video = VIDEO_ENABLE;
+ info->audio = AUDIO_CH1_ENABLE | AUDIO_CH2_ENABLE;
+ info->display = DISPLAY_ENABLE;
+
+ /* seek to frame 1 to start with */
+ set_state(info, LASERDISC_LOADING, GENERIC_RESET_SPEED, 1);
+
+ /* reset the I/O lines */
+ for (i = 0; i < LASERDISC_INPUT_LINES; i++)
+ info->linein[i] = CLEAR_LINE;
+ for (i = 0; i < LASERDISC_OUTPUT_LINES; i++)
+ info->lineout[i] = CLEAR_LINE;
+
+ /* reset callbacks */
+ info->writedata = NULL;
+ memset(info->writeline, 0, sizeof(info->writeline));
+ info->readdata = NULL;
+ memset(info->readline, 0, sizeof(info->readline));
+ info->statechanged = NULL;
+
+ /* each player can init */
+ switch (info->type)
+ {
+ case LASERDISC_TYPE_PR7820:
+ pr7820_init(info);
+ break;
+
+ case LASERDISC_TYPE_LDV1000:
+ ldv1000_init(info);
+ break;
+
+ case LASERDISC_TYPE_LDP1450:
+ ldp1450_init(info);
+ break;
+
+ case LASERDISC_TYPE_PR8210:
+ pr8210_init(info);
+ break;
+
+ case LASERDISC_TYPE_22VP932:
+ vp932_init(info);
+ break;
+
+ default:
+ fatalerror("Invalid laserdisc player type!");
+ break;
+ }
+
+ /* default to track 1 */
+ info->curfractrack = ONE_TRACK;
+}
+
+
+/*-------------------------------------------------
+ laserdisc_exit - cleanup
+-------------------------------------------------*/
+
+void laserdisc_exit(laserdisc_info *info)
+{
+ /* make sure all async operations have completed */
+ if (info->disc != NULL)
+ chd_async_complete(info->disc);
+}
+
+
+/*-------------------------------------------------
+ laserdisc_vsync - call this once per field
+ on the VSYNC signal
+-------------------------------------------------*/
+
+void laserdisc_vsync(laserdisc_info *info)
+{
+ UINT8 origstate = info->state;
+ UINT8 hittarget;
+
+ /* remember the time */
+ info->lastvsynctime = timer_get_time();
+
+ /* if we're holding, stay in this state until finished */
+ if (info->holdfinished.seconds != 0 || info->holdfinished.attoseconds != 0)
+ {
+ if (attotime_compare(info->lastvsynctime, info->holdfinished) < 0)
+ return;
+ info->state = info->postholdstate;
+ info->curfracspeed = info->postholdfracspeed;
+ info->holdfinished.seconds = 0;
+ info->holdfinished.attoseconds = 0;
+ }
+
+ /* wait for previous read and decode to finish */
+ process_track_data(info);
+
+ /* update our position for this field */
+ hittarget = update_position(info);
+
+ /* switch off the state */
+ switch (info->state)
+ {
+ /* parked: do nothing */
+ case LASERDISC_EJECTED:
+ case LASERDISC_EJECTING:
+ case LASERDISC_LOADED:
+ case LASERDISC_PARKED:
+ break;
+
+ /* playing: if we hit our target, indicate so; if we hit the beginning/end, stop */
+ case LASERDISC_STOPPED:
+ case LASERDISC_AUTOSTOPPED:
+ case LASERDISC_SEARCH_FINISHED:
+ case LASERDISC_PLAYING_FORWARD:
+ case LASERDISC_PLAYING_REVERSE:
+ case LASERDISC_PLAYING_SLOW_FORWARD:
+ case LASERDISC_PLAYING_SLOW_REVERSE:
+ case LASERDISC_PLAYING_FAST_FORWARD:
+ case LASERDISC_PLAYING_FAST_REVERSE:
+ case LASERDISC_STEPPING_FORWARD:
+ case LASERDISC_STEPPING_REVERSE:
+ case LASERDISC_SCANNING_FORWARD:
+ case LASERDISC_SCANNING_REVERSE:
+
+ /* autostop if we hit the target frame */
+ if (hittarget)
+ set_state(info, LASERDISC_AUTOSTOPPED, STOP_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ /* loading; keep searching until we hit the target, then go into the stopped state */
+ case LASERDISC_LOADING:
+ case LASERDISC_SPINUP:
+
+ /* if we hit the target, go into search finished state */
+ if (hittarget)
+ set_state(info, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ /* searching; keep seeking until we hit the target */
+ case LASERDISC_SEARCHING_FRAME:
+
+ /* if we hit the target, go into search finished state */
+ if (hittarget)
+ set_state(info, LASERDISC_SEARCH_FINISHED, STOP_SPEED, NULL_TARGET_FRAME);
+ break;
+ }
+
+ /* if the state changed, notify */
+ if (info->state != origstate)
+ {
+ /* on a state change, implicity round to the nearest fraction */
+ info->curfractrack = INT_TO_FRAC(FRAC_TO_INT(info->curfractrack));
+ if (!(info->fieldnum & 1))
+ info->curfractrack += FRAC_ONE / 2;
+
+ /* notify the disc handler */
+ if (info->statechanged != NULL)
+ (*info->statechanged)(info, origstate);
+ }
+
+ /* start reading the track data for the next round */
+ info->fieldnum++;
+ read_track_data(info);
+}
+
+
+/*-------------------------------------------------
+ laserdisc_describe_state - return a text
+ string describing the current state
+-------------------------------------------------*/
+
+const char *laserdisc_describe_state(laserdisc_info *info)
+{
+ static const struct
+ {
+ laserdisc_state state;
+ const char *string;
+ } state_strings[] =
+ {
+ { LASERDISC_EJECTED, "Ejected" },
+ { LASERDISC_EJECTING, "Ejecting" },
+ { LASERDISC_LOADED, "Loaded" },
+ { LASERDISC_LOADING, "Loading" },
+ { LASERDISC_SPINUP, "Spinning Up" },
+ { LASERDISC_PARKED, "Parked" },
+ { LASERDISC_SEARCHING_FRAME, "Searching Frame" },
+ { LASERDISC_SEARCH_FINISHED, "Search Finished" },
+ { LASERDISC_STOPPED, "Stopped" },
+ { LASERDISC_AUTOSTOPPED, "Autostopped" },
+ { LASERDISC_PLAYING_FORWARD, "Playing Forward" },
+ { LASERDISC_PLAYING_REVERSE, "Playing Reverse" },
+ { LASERDISC_PLAYING_SLOW_FORWARD, "Playing Slow Forward x" },
+ { LASERDISC_PLAYING_SLOW_REVERSE, "Playing Slow Reverse x" },
+ { LASERDISC_PLAYING_FAST_FORWARD, "Playing Fast Forward x" },
+ { LASERDISC_PLAYING_FAST_REVERSE, "Playing Fast Reverse x" },
+ { LASERDISC_STEPPING_FORWARD, "Stepping Forward" },
+ { LASERDISC_STEPPING_REVERSE, "Stepping Reverse" },
+ { LASERDISC_SCANNING_FORWARD, "Scanning Forward" },
+ { LASERDISC_SCANNING_REVERSE, "Scanning Reverse" }
+ };
+ const char *description = "Unknown";
+ int i;
+
+ /* find the string */
+ for (i = 0; i < ARRAY_LENGTH(state_strings); i++)
+ if (state_strings[i].state == info->state)
+ description = state_strings[i].string;
+
+ /* construct the string */
+ if (description[strlen(description) - 1] == 'x')
+ sprintf(info->text, "%05d (%s%.1f)", FRAC_TO_INT(info->curfractrack), description, (float)info->curfracspeed / (float)INT_TO_FRAC(1));
+ else
+ sprintf(info->text, "%05d (%s)", FRAC_TO_INT(info->curfractrack), description);
+ return info->text;
+}
+
+
+/*-------------------------------------------------
+ laserdisc_data_w - write data to the given
+ laserdisc player
+-------------------------------------------------*/
+
+void laserdisc_data_w(laserdisc_info *info, UINT8 data)
+{
+ UINT8 prev = info->datain;
+ info->datain = data;
+
+ /* call through to the player-specific write handler */
+ if (info->writedata != NULL)
+ (*info->writedata)(info, prev, data);
+}
+
+
+/*-------------------------------------------------
+ laserdisc_line_w - control an input line
+-------------------------------------------------*/
+
+void laserdisc_line_w(laserdisc_info *info, UINT8 line, UINT8 newstate)
+{
+ assert(line < LASERDISC_INPUT_LINES);
+ assert(newstate == ASSERT_LINE || newstate == CLEAR_LINE || newstate == PULSE_LINE);
+
+ /* assert */
+ if (newstate == ASSERT_LINE || newstate == PULSE_LINE)
+ {
+ if (info->linein[line] != ASSERT_LINE)
+ {
+ /* call through to the player-specific line handler */
+ if (info->writeline[line] != NULL)
+ (*info->writeline[line])(info, ASSERT_LINE);
+ }
+ info->linein[line] = ASSERT_LINE;
+ }
+
+ /* deassert */
+ if (newstate == CLEAR_LINE || newstate == PULSE_LINE)
+ {
+ if (info->linein[line] != CLEAR_LINE)
+ {
+ /* call through to the player-specific line handler */
+ if (info->writeline[line] != NULL)
+ (*info->writeline[line])(info, CLEAR_LINE);
+ }
+ info->linein[line] = CLEAR_LINE;
+ }
+}
+
+
+/*-------------------------------------------------
+ laserdisc_data_r - return the current
+ data byte
+-------------------------------------------------*/
+
+UINT8 laserdisc_data_r(laserdisc_info *info)
+{
+ UINT8 result = info->dataout;
+
+ /* call through to the player-specific data handler */
+ if (info->readdata != NULL)
+ result = (*info->readdata)(info);
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ laserdisc_line_r - return the current state
+ of an output line
+-------------------------------------------------*/
+
+UINT8 laserdisc_line_r(laserdisc_info *info, UINT8 line)
+{
+ UINT8 result;
+
+ assert(line < LASERDISC_OUTPUT_LINES);
+ result = info->lineout[line];
+
+ /* call through to the player-specific data handler */
+ if (info->readline[line] != NULL)
+ result = (*info->readline[line])(info);
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ laserdisc_get_video - return the current
+ video frame
+-------------------------------------------------*/
+
+UINT32 laserdisc_get_video(laserdisc_info *info, mame_bitmap **bitmap)
+{
+ int frameindex;
+
+ /* determine the most recent live set of frames */
+ frameindex = info->videoindex;
+ if (info->videofields[frameindex] < 2)
+ frameindex ^= 1;
+
+ /* if no video present, return the empty frame */
+ if (!video_active(info) || info->videofields[frameindex] < 2)
+ {
+ *bitmap = info->emptyframe;
+ return 0;
+ }
+ else
+ {
+ *bitmap = info->videoframe[frameindex];
+ return info->videoframenum[frameindex];
+ }
+}
+
+
+/*-------------------------------------------------
+ laserdisc_get_field_code - return raw field
+ information read from the disc
+-------------------------------------------------*/
+
+UINT32 laserdisc_get_field_code(laserdisc_info *info, UINT8 code)
+{
+ int field = (info->fieldnum & 1) ^ 1;
+
+ /* if no video present, return */
+ if (!video_active(info))
+ return 0;
+
+ switch (code)
+ {
+ case LASERDISC_CODE_FRAME_FLAGS:
+ return info->metadata[field].frameflags;
+
+ case LASERDISC_CODE_WHITE_FLAG:
+ return info->metadata[field].whiteflag;
+
+ case LASERDISC_CODE_LINE16:
+ return info->metadata[field].line16;
+
+ case LASERDISC_CODE_LINE17:
+ return info->metadata[field].line17;
+
+ case LASERDISC_CODE_LINE18:
+ return info->metadata[field].line18;
+ }
+
+ return 0;
+}
+
+
+
+/***************************************************************************
+ GENERIC HELPER FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ process_number - scan a list of bytecodes
+ and treat them as single digits if we get
+ a match
+-------------------------------------------------*/
+
+static int process_number(laserdisc_info *info, UINT8 byte, const UINT8 numbers[])
+{
+ int value;
+
+ /* look for a match in the list of number values; if we got one, append it to the parameter */
+ for (value = 0; value < 10; value++)
+ if (numbers[value] == byte)
+ {
+ info->parameter = (info->parameter == -1) ? value : (info->parameter * 10 + value);
+ return TRUE;
+ }
+
+ /* no match; return FALSE */
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ update_position - update the head position
+ for this VSYNC
+-------------------------------------------------*/
+
+static int update_position(laserdisc_info *info)
+{
+ UINT32 tracknum = FRAC_TO_INT(info->curfractrack);
+ UINT32 fieldnum = info->fieldnum & 1;
+ INT32 speed = info->curfracspeed;
+ INT32 framedelta;
+
+ /* if video isn't active, we don't need to be careful about fields and frames */
+ if (!video_active(info))
+ {
+ int frame = frame_from_metadata(&info->metadata[fieldnum]);
+ int direction;
+
+ /* if we have no target, don't do anything */
+ if (info->targetframe == 0)
+ return TRUE;
+
+ /* if we didn't get any frame information this field, move onto the next */
+ if (frame == -1)
+ {
+ /* if we're in the lead-in section, advance more aggressively */
+ if (info->metadata[fieldnum].line17 == 0x88ffff || info->metadata[fieldnum].line18 == 0x88ffff)
+ add_to_current_track(info, 10 * ONE_TRACK);
+
+ /* if we're on the second field of a frame, the next frame is on the next track */
+ /* but don't do it if we're seeking to frame 1, since that might be the very first frame */
+ else if (fieldnum == 1 && (info->last_frame == 1 || info->targetframe != 1))
+ add_to_current_track(info, ONE_TRACK);
+ return FALSE;
+ }
+
+ /* if we hit our frame, we're done */
+ if (frame == info->targetframe)
+ {
+ info->curfractrack = INT_TO_FRAC(tracknum);
+ return TRUE;
+ }
+
+ /* determine the frame delta and direction */
+ framedelta = info->targetframe - frame;
+ direction = (framedelta < 0) ? -1 : 1;
+
+ /* if we're going backwards, go back at least 2 frames since we tend to move forward */
+ if (framedelta == -1)
+ framedelta = -2;
+
+ /* if we're only going forward one frame, only advance if we're on the second field */
+ /* otherwise, we might overshoot */
+ else if (framedelta == 1 && fieldnum == 0)
+ framedelta = 0;
+
+ /* scale up to fractional bits */
+ framedelta = INT_TO_FRAC(abs(framedelta));
+
+ /* determine the stepdelta */
+ add_to_current_track(info, MIN(framedelta, speed / 2) * direction);
+ return FALSE;
+ }
+
+ /* only advance on the second field */
+ if (fieldnum != 1)
+ return FALSE;
+
+ /* if we're moving backwards, advance back until we hit track 1 or the target */
+ if (speed < 0)
+ {
+ /* if we've hit the target, stop now */
+ if (info->targetframe != 0 && info->last_frame <= info->targetframe)
+ {
+ info->curfractrack = INT_TO_FRAC(tracknum);
+ return TRUE;
+ }
+
+ /* otherwise, clamp our delta so we don't overshoot */
+ else
+ {
+ framedelta = INT_TO_FRAC((info->targetframe == 0) ? -1000 : (info->targetframe - info->last_frame));
+ add_to_current_track(info, MAX(framedelta, speed));
+ }
+ }
+
+ /* if we're moving forwards, advance forward until we hit the max track or the target */
+ else if (speed > 0)
+ {
+ /* if we've hit the target, stop now */
+ if (info->targetframe != 0 && info->last_frame >= info->targetframe)
+ {
+ info->curfractrack = INT_TO_FRAC(tracknum);
+ return TRUE;
+ }
+
+ /* otherwise, clamp our delta so we don't overshoot */
+ else
+ {
+ framedelta = INT_TO_FRAC((info->targetframe == 0) ? 1000 : (info->targetframe - info->last_frame));
+ add_to_current_track(info, MIN(framedelta, speed));
+ }
+ }
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ read_track_data - read and process data for
+ a particular video track
+-------------------------------------------------*/
+
+static void read_track_data(laserdisc_info *info)
+{
+ UINT32 tracknum = FRAC_TO_INT(info->curfractrack);
+ UINT32 fieldnum = info->fieldnum & 1;
+ UINT32 chdhunk = (tracknum - 1) * 2 + fieldnum;
+ chd_error err;
+
+ /* initialize the decompression structure */
+ info->avconfig.decode_mask = AVCOMP_DECODE_META;
+ info->avconfig.video_buffer = NULL;
+ info->avconfig.video_xor = BYTE_XOR_LE(0);
+ info->avconfig.audio_xor = BYTE_XOR_BE(0);
+
+ /* if video is active, enable video decoding */
+ if (video_active(info))
+ {
+ /* if the flags on the previous field indicate that the next field
+ is part of the same frame, then keep steady; otherwise, bump to
+ the next videoindex */
+ if (info->videofields[info->videoindex] > 0 && !(info->metadata[fieldnum ^ 1].frameflags & FRAMEFLAG_NEXT_SAME_FRAME))
+ {
+ info->videoindex ^= 1;
+ info->videofields[info->videoindex] = 0;
+ }
+
+ /* enable video and configure it to read into the videoframe */
+ info->avconfig.decode_mask |= AVCOMP_DECODE_VIDEO;
+ info->avconfig.video_buffer = (UINT8 *)BITMAP_ADDR16(info->videoframe[info->videoindex], fieldnum, 0);
+ info->avconfig.video_stride = 4 * info->videoframe[info->videoindex]->rowpixels;
+ }
+ else
+ info->videofields[0] = info->videofields[1] = 0;
+
+ /* if audio is active, enable audio decoding */
+ if (audio_channel_active(info, 0))
+ info->avconfig.decode_mask |= AVCOMP_DECODE_AUDIO(0);
+ if (audio_channel_active(info, 1))
+ info->avconfig.decode_mask |= AVCOMP_DECODE_AUDIO(1);
+
+ /* configure the codec and then read */
+ if (info->disc != NULL)
+ {
+ err = chd_codec_config(info->disc, AV_CODEC_DECOMPRESS_CONFIG, &info->avconfig);
+ if (err == CHDERR_NONE)
+ {
+ err = chd_read_async(info->disc, chdhunk, info->framebuffer);
+ info->readpending = TRUE;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ process_track_data - process data from a
+ track after it has been read
+-------------------------------------------------*/
+
+static void process_track_data(laserdisc_info *info)
+{
+ UINT32 tracknum = FRAC_TO_INT(info->curfractrack);
+ UINT32 fieldnum = info->fieldnum & 1;
+ const UINT8 *rawdata = NULL;
+ const INT16 *sampsource[2];
+ int frame, chapter;
+ chd_error chderr;
+ int samples;
+
+ /* wait for the async operation to complete */
+ if (info->disc != NULL && info->readpending)
+ {
+ /* complete the async operation */
+ chderr = chd_async_complete(info->disc);
+ if (chderr == CHDERR_NONE || chderr == CHDERR_NO_ASYNC_OPERATION)
+ rawdata = info->framebuffer;
+ }
+ info->readpending = FALSE;
+
+ /* parse the metadata */
+ parse_metadata(rawdata, tracknum, fieldnum, &info->metadata[fieldnum]);
+
+ /* update the last seen frame and chapter */
+ frame = frame_from_metadata(&info->metadata[fieldnum]);
+ if (frame != -1)
+ info->last_frame = frame;
+ chapter = chapter_from_metadata(&info->metadata[fieldnum]);
+ if (chapter != -1)
+ info->last_chapter = chapter;
+
+ /* update video info */
+ if (rawdata != NULL && (info->avconfig.decode_mask & AVCOMP_DECODE_VIDEO))
+ {
+ info->videofields[info->videoindex]++;
+ info->videoframenum[info->videoindex] = info->last_frame;
+ }
+
+ /* stream the audio into our ring buffers */
+ if (rawdata != NULL)
+ {
+ samples = (rawdata[6] << 8) + rawdata[7];
+ sampsource[0] = (const INT16 *)(rawdata + 12 + rawdata[4]) + 0 * samples;
+ sampsource[1] = sampsource[0] + samples;
+
+ /* loop until all samples are copied */
+ while (samples != 0)
+ {
+ int samples_to_copy = MIN(info->audiobufsize - info->audiobufin, samples);
+ int channum;
+
+ /* don't overrun the output pointer */
+ if (info->audiobufout > info->audiobufin)
+ {
+ samples_to_copy = MIN(samples_to_copy, info->audiobufout - info->audiobufin);
+ if (samples_to_copy == 0)
+ break;
+ }
+
+ /* for reach channel, copy the data or clear to 0 */
+ for (channum = 0; channum < 2; channum++)
+ {
+ if (audio_channel_active(info, channum))
+ {
+ memcpy(&info->audiobuffer[channum][info->audiobufin], sampsource[channum], samples_to_copy * 2);
+ sampsource[channum] += samples_to_copy;
+ }
+ else
+ memset(&info->audiobuffer[channum][info->audiobufin], 0, samples_to_copy * 2);
+ }
+ samples -= samples_to_copy;
+
+ /* point past the data */
+ info->audiobufin += samples_to_copy;
+ if (info->audiobufin >= info->audiobufsize)
+ info->audiobufin = 0;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ parse_metadata - parse raw metadata into
+ something more useful
+-------------------------------------------------*/
+
+static int parse_metadata(const UINT8 *rawdata, UINT32 track, UINT8 which, field_metadata *metadata)
+{
+ /* verify we have data to parse */
+ if (rawdata == NULL || rawdata[4] < 1)
+ goto fakeit;
+
+ /* first byte is the version */
+ metadata->version = rawdata[12+0];
+
+ /* version 1 data */
+ if (metadata->version == 2 && rawdata[4] == 12)
+ {
+ /*
+ 1 byte = version
+ 1 byte = internal flags
+ D0 = prev field is same frame
+ D1 = next field is same frame
+ 1 byte = white flag
+ 3 bytes = line 16 Philips code
+ 3 bytes = line 17 Philips code
+ 3 bytes = line 18 Philips code
+ */
+ metadata->frameflags = rawdata[12+1];
+ metadata->whiteflag = rawdata[12+2];
+ metadata->line16 = (rawdata[12+3] << 16) | (rawdata[12+4] << 8) | rawdata[12+5];
+ metadata->line17 = (rawdata[12+6] << 16) | (rawdata[12+7] << 8) | rawdata[12+8];
+ metadata->line18 = (rawdata[12+9] << 16) | (rawdata[12+10] << 8) | rawdata[12+11];
+ return TRUE;
+ }
+
+fakeit:
+ metadata->frameflags = (which == 0) ? 0x02 : 0x01;
+ metadata->whiteflag = (which == 0) ? 1 : 0;
+ metadata->line16 = 0x000000;
+ if (which == 0)
+ metadata->line17 = metadata->line18 = 0xf80000 | (((track / 10000) % 10) << 16) | (((track / 1000) % 10) << 12) | (((track / 100) % 10) << 8) | (((track / 10) % 10) << 4) | (track % 10);
+ else
+ metadata->line17 = metadata->line18 = 0x000000;
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ custom_start - custom audio start
+ for laserdiscs
+-------------------------------------------------*/
+
+static void *custom_start(int clock, const struct CustomSound_interface *config)
+{
+ sound_token *token = auto_malloc(sizeof(*token));
+ token->stream = stream_create(0, 2, 44100, token, custom_stream_callback);
+ token->info = NULL;
+ return token;
+}
+
+
+/*-------------------------------------------------
+ custom_stream_callback - audio streamer
+ for laserdiscs
+-------------------------------------------------*/
+
+static void custom_stream_callback(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ sound_token *token = param;
+ laserdisc_info *info = token->info;
+ stream_sample_t *dst0 = outputs[0];
+ stream_sample_t *dst1 = outputs[1];
+ int samples_avail = 0;
+
+ /* see if we have enough samples to fill the buffer; if not, drop out */
+ if (info != NULL)
+ {
+ samples_avail = info->audiobufin - info->audiobufout;
+ if (samples_avail < 0)
+ samples_avail += info->audiobufsize;
+ }
+
+ /* if no attached info, just clear the buffers */
+ if (samples_avail < samples)
+ {
+ memset(dst0, 0, samples * sizeof(dst0[0]));
+ memset(dst1, 0, samples * sizeof(dst1[0]));
+ }
+
+ /* otherwise, stream from our buffer */
+ else
+ {
+ const INT16 *buffer0 = info->audiobuffer[0];
+ const INT16 *buffer1 = info->audiobuffer[1];
+ int sampout = info->audiobufout;
+
+ /* copy samples */
+ while (sampout != info->audiobufin && samples-- > 0)
+ {
+ *dst0++ = buffer0[sampout];
+ *dst1++ = buffer1[sampout];
+ sampout++;
+ if (sampout >= info->audiobufsize)
+ sampout = 0;
+ }
+ info->audiobufout = sampout;
+
+ /* clear out the rest of the buffer */
+ if (samples > 0)
+ {
+ int sampout = (info->audiobufout == 0) ? info->audiobufsize - 1 : info->audiobufout - 1;
+ stream_sample_t fill0 = buffer0[sampout];
+ stream_sample_t fill1 = buffer1[sampout];
+
+ while (samples-- > 0)
+ {
+ *dst0++ = fill0;
+ *dst1++ = fill1;
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ PIONEER PR-7820 IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ pr7820_init - Pioneer PR-7820-specific
+ initialization
+-------------------------------------------------*/
+
+static void pr7820_init(laserdisc_info *info)
+{
+ pr7820_info *pr7820 = &info->u.pr7820;
+
+ /* set up the write callbacks */
+ info->writeline[LASERDISC_LINE_ENTER] = pr7820_enter_w;
+
+ /* set up the read callbacks */
+ info->readdata = pr7820_status_r;
+ info->readline[LASERDISC_LINE_READY] = pr7820_ready_r;
+
+ /* do a soft reset */
+ pr7820->configspeed = PLAY_SPEED / 2;
+ pr7820_soft_reset(info);
+}
+
+
+/*-------------------------------------------------
+ pr7820_soft_reset - Pioneer PR-7820-specific
+ soft reset
+-------------------------------------------------*/
+
+static void pr7820_soft_reset(laserdisc_info *info)
+{
+ pr7820_info *pr7820 = &info->u.pr7820;
+
+ info->audio = AUDIO_CH1_ENABLE | AUDIO_CH2_ENABLE;
+ info->display = 0;
+ pr7820->mode = PR7820_MODE_MANUAL;
+ pr7820->activereg = 0;
+ write_16bits_to_ram_be(pr7820->ram, 0, 1);
+}
+
+
+/*-------------------------------------------------
+ pr7820_enter_w - write callback when the
+ ENTER state is asserted
+-------------------------------------------------*/
+
+static void pr7820_enter_w(laserdisc_info *info, UINT8 newstate)
+{
+ static const UINT8 numbers[10] = { 0x3f, 0x0f, 0x8f, 0x4f, 0x2f, 0xaf, 0x6f, 0x1f, 0x9f, 0x5f };
+ pr7820_info *pr7820 = &info->u.pr7820;
+ UINT8 data = (pr7820->mode == PR7820_MODE_AUTOMATIC) ? pr7820->ram[pr7820->curpc++ % 1024] : info->datain;
+
+ /* we only care about assertions */
+ if (newstate != ASSERT_LINE)
+ return;
+
+ /* if we're in program mode, just write data */
+ if (pr7820->mode == PR7820_MODE_PROGRAM && data != 0xef)
+ {
+ pr7820->ram[info->parameter++ % 1024] = data;
+ return;
+ }
+
+ /* look for and process numbers */
+ if (process_number(info, data, numbers))
+ return;
+
+ /* handle commands */
+ switch (data)
+ {
+ case 0x7f: CMDPRINTF(("pr7820: %d Recall\n", info->parameter));
+ /* set the active register */
+ pr7820->activereg = info->parameter;
+ break;
+
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3: CMDPRINTF(("pr7820: Direct audio control %d\n", data & 0x03));
+ /* control both channels directly */
+ info->audio = 0;
+ if (data & 0x01)
+ info->audio |= AUDIO_CH1_ENABLE;
+ if (data & 0x02)
+ info->audio |= AUDIO_CH2_ENABLE;
+ break;
+
+ case 0xbf: CMDPRINTF(("pr7820: %d Halt\n", info->parameter));
+ /* stop automatic mode */
+ pr7820->mode = PR7820_MODE_MANUAL;
+ break;
+
+ case 0xcc: CMDPRINTF(("pr7820: Load\n"));
+ /* load program from disc -- not implemented */
+ break;
+
+ case 0xcf: CMDPRINTF(("pr7820: %d Branch\n", info->parameter));
+ /* branch to a new PC */
+ if (pr7820->mode == PR7820_MODE_AUTOMATIC)
+ pr7820->curpc = (info->parameter == -1) ? 0 : info->parameter;
+ break;
+
+ case 0xdf: CMDPRINTF(("pr7820: %d Write program\n", info->parameter));
+ /* enter program mode */
+ pr7820->mode = PR7820_MODE_PROGRAM;
+ break;
+
+ case 0xe1: CMDPRINTF(("pr7820: Soft Reset\n"));
+ /* soft reset */
+ pr7820_soft_reset(info);
+ break;
+
+ case 0xe3: CMDPRINTF(("pr7820: Display off\n"));
+ /* turn off frame display */
+ info->display = 0x00;
+ break;
+
+ case 0xe4: CMDPRINTF(("pr7820: Display on\n"));
+ /* turn on frame display */
+ info->display = 0x01;
+ break;
+
+ case 0xe5: CMDPRINTF(("pr7820: Audio 2 off\n"));
+ /* turn off audio channel 2 */
+ info->audio &= ~AUDIO_CH2_ENABLE;
+ break;
+
+ case 0xe6: CMDPRINTF(("pr7820: Audio 2 on\n"));
+ /* turn on audio channel 2 */
+ info->audio |= AUDIO_CH2_ENABLE;
+ break;
+
+ case 0xe7: CMDPRINTF(("pr7820: Audio 1 off\n"));
+ /* turn off audio channel 1 */
+ info->audio &= ~AUDIO_CH1_ENABLE;
+ break;
+
+ case 0xe8: CMDPRINTF(("pr7820: Audio 1 on\n"));
+ /* turn on audio channel 1 */
+ info->audio |= AUDIO_CH1_ENABLE;
+ break;
+
+ case 0xe9: CMDPRINTF(("pr7820: %d Dump RAM\n", info->parameter));
+ /* not implemented */
+ break;
+
+ case 0xea: CMDPRINTF(("pr7820: %d Dump frame\n", info->parameter));
+ /* not implemented */
+ break;
+
+ case 0xeb: CMDPRINTF(("pr7820: %d Dump player status\n", info->parameter));
+ /* not implemented */
+ break;
+
+ case 0xef: CMDPRINTF(("pr7820: %d End program\n", info->parameter));
+ /* exit programming mode */
+ pr7820->mode = PR7820_MODE_MANUAL;
+ break;
+
+ case 0xf0: CMDPRINTF(("pr7820: %d Decrement reg\n", info->parameter));
+ /* decrement register; if we hit 0, skip past the next branch statement */
+ if (pr7820->mode == PR7820_MODE_AUTOMATIC)
+ {
+ UINT16 tempreg = read_16bits_from_ram_be(pr7820->ram, (info->parameter * 2) % 1024);
+ tempreg = (tempreg == 0) ? 0 : tempreg - 1;
+ write_16bits_to_ram_be(pr7820->ram, (info->parameter * 2) % 1024, tempreg);
+ if (tempreg == 0)
+ while (pr7820->ram[pr7820->curpc++ % 1024] != 0xcf) ;
+ }
+ break;
+
+ case 0xf1: CMDPRINTF(("pr7820: %d Display\n", info->parameter));
+ /* toggle or set the frame display */
+ info->display = (info->parameter == -1) ? !info->display : (info->parameter & 1);
+ break;
+
+ case 0xf2: CMDPRINTF(("pr7820: %d Slow forward\n", info->parameter));
+ /* play forward at slow speed (controlled by lever on the front of the player) */
+ if (laserdisc_ready(info))
+ {
+ if (info->parameter != -1)
+ set_state(info, LASERDISC_PLAYING_SLOW_FORWARD, pr7820->configspeed, info->parameter);
+ else
+ set_state(info, LASERDISC_PLAYING_SLOW_FORWARD, pr7820->configspeed, NULL_TARGET_FRAME);
+ }
+ break;
+
+ case 0xf3: CMDPRINTF(("pr7820: %d Autostop\n", info->parameter));
+ /* play to a particular location and stop there */
+ if (laserdisc_ready(info))
+ {
+ INT32 targetframe = info->parameter;
+
+ if (targetframe == -1)
+ targetframe = read_16bits_from_ram_be(pr7820->ram, (pr7820->activereg * 2) % 1024);
+ pr7820->activereg++;
+
+ if (targetframe > info->last_frame)
+ set_state(info, LASERDISC_PLAYING_FORWARD, PLAY_SPEED, targetframe);
+ else
+ set_state(info, LASERDISC_SEARCHING_FRAME, PR7820_SEARCH_SPEED, targetframe);
+ }
+ break;
+
+ case 0xf4: CMDPRINTF(("pr7820: %d Audio track 1\n", info->parameter));
+ /* toggle or set the state of audio channel 1 */
+ if (info->parameter == -1)
+ info->audio ^= AUDIO_CH1_ENABLE;
+ else
+ info->audio = (info->audio & ~AUDIO_CH1_ENABLE) | ((info->parameter & 1) ? AUDIO_CH1_ENABLE : 0);
+ break;
+
+ case 0xf5: CMDPRINTF(("pr7820: %d Store\n", info->parameter));
+ /* store either the current frame number or an explicit value into the active register */
+ if (info->parameter == -1)
+ write_16bits_to_ram_be(pr7820->ram, (pr7820->activereg * 2) % 1024, info->last_frame);
+ else
+ write_16bits_to_ram_be(pr7820->ram, (pr7820->activereg * 2) % 1024, info->parameter);
+ pr7820->activereg++;
+ break;
+
+ case 0xf6: CMDPRINTF(("pr7820: Step forward\n"));
+ /* step forward one frame */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_STEPPING_FORWARD, STOP_SPEED, NULL_TARGET_FRAME);
+ add_to_current_track(info, ONE_TRACK);
+ }
+ break;
+
+ case 0xf7: CMDPRINTF(("pr7820: %d Search\n", info->parameter));
+ /* search to a particular frame number */
+ if (laserdisc_ready(info))
+ {
+ INT32 targetframe = info->parameter;
+
+ if (targetframe == -1)
+ targetframe = read_16bits_from_ram_be(pr7820->ram, (pr7820->activereg * 2) % 1024);
+ pr7820->activereg++;
+
+ if (targetframe == 0)
+ targetframe = 1;
+ set_state(info, LASERDISC_SEARCHING_FRAME, PR7820_SEARCH_SPEED, targetframe);
+ }
+ break;
+
+ case 0xf8: CMDPRINTF(("pr7820: %d Input\n", info->parameter));
+ /* wait for user input -- not implemented */
+ break;
+
+ case 0xf9: CMDPRINTF(("pr7820: Reject\n"));
+ /* eject the disc */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_EJECTING, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_LOAD_TIME, LASERDISC_EJECTED, STOP_SPEED);
+ }
+ break;
+
+ case 0xfa: CMDPRINTF(("pr7820: %d Slow reverse\n", info->parameter));
+ /* play backwards at slow speed (controlled by lever on the front of the player) */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_REVERSE, -pr7820->configspeed, (info->parameter != -1) ? info->parameter : NULL_TARGET_FRAME);
+ break;
+
+ case 0xfb: CMDPRINTF(("pr7820: %d Stop/Wait\n", info->parameter));
+ /* pause at the current location for a fixed amount of time (in 1/10ths of a second) */
+ if (laserdisc_ready(info))
+ {
+ laserdisc_state prevstate = info->state;
+ INT32 prevspeed = info->curfracspeed;
+ set_state(info, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
+ if (info->parameter != -1)
+ set_hold_state(info, double_to_attotime(info->parameter * 0.1), prevstate, prevspeed);
+ }
+ break;
+
+ case 0xfc: CMDPRINTF(("pr7820: %d Audio track 2\n", info->parameter));
+ /* toggle or set the state of audio channel 2 */
+ if (info->parameter == -1)
+ info->audio ^= AUDIO_CH2_ENABLE;
+ else
+ info->audio = (info->audio & ~AUDIO_CH2_ENABLE) | ((info->parameter & 1) ? AUDIO_CH2_ENABLE : 0);
+ break;
+
+ case 0xfd: CMDPRINTF(("pr7820: Play\n"));
+ /* begin playing at regular speed, or load the disc if it is parked */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FORWARD, PLAY_SPEED, NULL_TARGET_FRAME);
+ else
+ {
+ if (info->state == LASERDISC_PARKED)
+ {
+ set_state(info, LASERDISC_SPINUP, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_SPINUP_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
+ }
+ else
+ {
+ set_state(info, LASERDISC_LOADING, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_LOAD_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
+ }
+
+ info->curfractrack = ONE_TRACK;
+ }
+ break;
+
+ case 0xfe: CMDPRINTF(("pr7820: Step reverse\n"));
+ /* step backwards one frame */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_STEPPING_REVERSE, STOP_SPEED, NULL_TARGET_FRAME);
+ add_to_current_track(info, -ONE_TRACK);
+ }
+ break;
+
+ default: CMDPRINTF(("pr7820: %d Unknown command %02X\n", info->parameter, data));
+ /* unknown command */
+ break;
+ }
+
+ /* reset the parameter after executing a command */
+ info->parameter = -1;
+}
+
+
+/*-------------------------------------------------
+ pr7820_ready_r - return state of the ready
+ line
+-------------------------------------------------*/
+
+static UINT8 pr7820_ready_r(laserdisc_info *info)
+{
+ return (info->state != LASERDISC_SEARCHING_FRAME) ? ASSERT_LINE : CLEAR_LINE;
+}
+
+
+/*-------------------------------------------------
+ pr7820_status_r - return state of the ready
+ line
+-------------------------------------------------*/
+
+static UINT8 pr7820_status_r(laserdisc_info *info)
+{
+ pr7820_info *pr7820 = &info->u.pr7820;
+
+ /* top 3 bits reflect audio and display states */
+ UINT8 status = (info->audio << 6) | (info->display << 5);
+
+ /* low 5 bits reflect player states */
+
+ /* handle program mode */
+ if (pr7820->mode == PR7820_MODE_PROGRAM)
+ status |= 0x0c;
+ else
+ {
+ /* convert generic status into specific state equivalents */
+ switch (info->state)
+ {
+ case LASERDISC_EJECTED: status |= 0x0d; break;
+ case LASERDISC_EJECTING: status |= 0x0d; break;
+ case LASERDISC_LOADED: status |= 0x01; break;
+ case LASERDISC_SPINUP: status |= 0x01; break;
+ case LASERDISC_LOADING: status |= 0x01; break;
+ case LASERDISC_PARKED: status |= 0x01; break;
+
+ case LASERDISC_SEARCHING_FRAME: status |= 0x06; break;
+ case LASERDISC_SEARCH_FINISHED: status |= 0x07; break;
+
+ case LASERDISC_STOPPED: status |= 0x03; break;
+ case LASERDISC_AUTOSTOPPED: status |= 0x09; break;
+
+ case LASERDISC_PLAYING_FORWARD: status |= 0x02; break;
+ case LASERDISC_PLAYING_REVERSE: status |= 0x02; break;
+ case LASERDISC_PLAYING_SLOW_FORWARD: status |= 0x04; break;
+ case LASERDISC_PLAYING_SLOW_REVERSE: status |= 0x05; break;
+ case LASERDISC_PLAYING_FAST_FORWARD: status |= 0x02; break;
+ case LASERDISC_PLAYING_FAST_REVERSE: status |= 0x02; break;
+ case LASERDISC_STEPPING_FORWARD: status |= 0x03; break;
+ case LASERDISC_STEPPING_REVERSE: status |= 0x03; break;
+ case LASERDISC_SCANNING_FORWARD: status |= 0x02; break;
+ case LASERDISC_SCANNING_REVERSE: status |= 0x02; break;
+ default:
+ fatalerror("Unexpected disc state in pr7820_status_r\n");
+ break;
+ }
+ }
+ return status;
+}
+
+
+/*-------------------------------------------------
+ pr7820_set_slow_speed - set the speed of
+ "slow" playback, which is controlled by a
+ slider on the device
+-------------------------------------------------*/
+
+void pr7820_set_slow_speed(laserdisc_info *info, double frame_rate_scaler)
+{
+ pr7820_info *pr7820 = &info->u.pr7820;
+ pr7820->configspeed = PLAY_SPEED * frame_rate_scaler;
+}
+
+
+
+/***************************************************************************
+ PIONEER PR-8210 IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ pr8210_init - Pioneer PR-8210-specific
+ initialization
+-------------------------------------------------*/
+
+static void pr8210_init(laserdisc_info *info)
+{
+ /* set up the write callbacks */
+ info->writeline[LASERDISC_LINE_CONTROL] = pr8210_control_w; /* serial access */
+
+ /* do a soft reset */
+ pr8210_soft_reset(info);
+}
+
+
+/*-------------------------------------------------
+ pr8210_soft_reset - Pioneer PR-8210-specific
+ soft reset
+-------------------------------------------------*/
+
+static void pr8210_soft_reset(laserdisc_info *info)
+{
+ pr8210_info *pr8210 = &info->u.pr8210;
+
+ info->audio = AUDIO_CH1_ENABLE | AUDIO_CH2_ENABLE;
+ info->display = 0;
+ pr8210->mode = PR8210_MODE_GET_1ST;
+ pr8210->commandtime = timer_get_time();
+ pr8210->commandbits = 0;
+ memset( pr8210->commandtriplet, 0, 3*sizeof(UINT16) );
+ pr8210->seekstate = 0;
+}
+
+
+/*-------------------------------------------------
+ pr8210_command - Pioneer PR-8210-specific
+ command processing
+-------------------------------------------------*/
+
+static void pr8210_command(laserdisc_info *info)
+{
+ pr8210_info *pr8210 = &info->u.pr8210;
+
+ /* if we don't have the entire command triplet yet, keep going */
+ if ( pr8210->mode < PR8210_MODE_GET_3RD )
+ {
+ /* do some sanity checks on the command data */
+ if ( pr8210->mode == PR8210_MODE_GET_2ND )
+ {
+ /* if the commands don't match, then reassign the new command to the first word, then keep fetching */
+ if ( pr8210->commandtriplet[PR8210_MODE_GET_1ST] != pr8210->commandtriplet[PR8210_MODE_GET_2ND] )
+ {
+ pr8210->commandtriplet[PR8210_MODE_GET_1ST] = pr8210->commandtriplet[PR8210_MODE_GET_2ND];
+ pr8210->mode = PR8210_MODE_GET_2ND;
+ return;
+ }
+ }
+
+ pr8210->mode++;
+ }
+ else /* we're ready to process the command */
+ {
+ /* do some sanity checks on the command data */
+ static const UINT8 numbers[10] = { 0x01,0x11,0x09,0x19,0x05,0x15,0x0d,0x1d,0x03,0x13 };
+ UINT16 cmd = pr8210->commandtriplet[PR8210_MODE_GET_1ST];
+
+ /* more sanity checking: bit 7 must be set for a valid command */
+ if ( cmd & 0x80 )
+ {
+ /* extract the actual command number */
+ cmd = ( cmd >> 2 ) & 0x1f;
+
+ /* look for and process numbers */
+ if (!process_number(info, cmd, numbers))
+ {
+ switch( cmd )
+ {
+ case 0x00: CMDPRINTF(("pr8210: EOC\n"));
+ /* EOC marker - can be safely ignored */
+ break;
+
+ case 0x02: CMDPRINTF(("pr8210: Slow reverse\n"));
+ /* slow reverse */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_REVERSE, -PR8210_SLOW_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x04: CMDPRINTF(("pr8210: Step forward\n"));
+ /* step forward */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_STEPPING_FORWARD, PR8210_STEP_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x06 : CMDPRINTF(("pr8210: Chapter\n"));
+ /* chapter -- not implemented */
+ break;
+
+ case 0x08: CMDPRINTF(("pr8210: Scan forward\n"));
+ /* scan forward */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_SCANNING_FORWARD, PR8210_SCAN_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x0a: CMDPRINTF(("pr8210: Pause\n"));
+ /* still picture */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x0b : CMDPRINTF(("pr8210: Frame\n"));
+ /* frame -- not implemented */
+ break;
+
+ case 0x0c: CMDPRINTF(("pr8210: Fast reverse\n"));
+ /* play reverse fast speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FAST_REVERSE, -PR8210_FAST_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x0e: CMDPRINTF(("pr8210: Ch1 toggle\n"));
+ /* channel 1 audio toggle */
+ info->audio ^= AUDIO_CH1_ENABLE;
+ break;
+
+ case 0x10: CMDPRINTF(("pr8210: Fast forward\n"));
+ /* play forward fast speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FAST_FORWARD, PR8210_FAST_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x12: CMDPRINTF(("pr8210: Step reverse\n"));
+ /* step backwards one frame */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_STEPPING_REVERSE, STOP_SPEED, NULL_TARGET_FRAME);
+ add_to_current_track(info, -ONE_TRACK);
+ }
+ break;
+
+ case 0x14: CMDPRINTF(("pr8210: Play\n"));
+ /* begin playing at regular speed, or load the disc if it is parked */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FORWARD, PLAY_SPEED, NULL_TARGET_FRAME);
+ else
+ {
+ /* if we're already spinning up or loading, ignore */
+ if (info->state != LASERDISC_SPINUP && info->state != LASERDISC_LOADING)
+ {
+ if (info->state == LASERDISC_PARKED)
+ {
+ set_state(info, LASERDISC_SPINUP, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_SPINUP_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
+ }
+ else
+ {
+ set_state(info, LASERDISC_LOADING, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_LOAD_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
+ }
+
+ info->curfractrack = ONE_TRACK;
+ }
+ }
+ break;
+
+ case 0x16: CMDPRINTF(("pr8210: Ch2 toggle\n"));
+ /* channel 1 audio toggle */
+ info->audio ^= AUDIO_CH2_ENABLE;
+ break;
+
+ case 0x18: CMDPRINTF(("pr8210: Slow forward\n"));
+ /* slow forward */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_FORWARD, PR8210_SLOW_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x1a: CMDPRINTF(("pr8210: Seek\n"));
+ /* seek */
+ if ( pr8210->seekstate )
+ {
+ CMDPRINTF(("pr8210: Seeking to frame:%d\n", info->parameter));
+ /* we're ready to seek */
+ set_state(info, LASERDISC_SEARCHING_FRAME, PR8210_SEARCH_SPEED, info->parameter);
+ }
+ else
+ {
+ /* waiting for digits indicating position */
+ info->parameter = 0;
+ }
+ pr8210->seekstate ^=1 ;
+ break;
+
+ case 0x1c: CMDPRINTF(("pr8210: Scan reverse\n"));
+ /* scan reverse */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_SCANNING_REVERSE, -PR8210_SCAN_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x1e: CMDPRINTF(("pr8210: Reject\n"));
+ /* eject the disc */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_EJECTING, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_LOAD_TIME, LASERDISC_EJECTED, STOP_SPEED);
+ }
+ break;
+
+ default: CMDPRINTF(("pr8210: Unknown command %02X\n", cmd));
+ /* unknown command */
+ break;
+ }
+ }
+ }
+
+ /* reset our command data */
+ memset( pr8210->commandtriplet, 0, 3*sizeof(UINT16) );
+ pr8210->mode = PR8210_MODE_GET_1ST;
+ }
+}
+
+
+/*-------------------------------------------------
+ pr8210_command_w - write callback when the
+ CONTROL line is toggled
+-------------------------------------------------*/
+
+static void pr8210_control_w(laserdisc_info *info, UINT8 data)
+{
+ pr8210_info *pr8210 = &info->u.pr8210;
+
+ if ( data == ASSERT_LINE )
+ {
+ /* get the time difference from the last assert */
+ attotime delta = attotime_sub(timer_get_time(), pr8210->commandtime);
+
+ /* and update our internal command time */
+ pr8210->commandtime = timer_get_time();
+
+#if 0
+ {
+ int usecdiff = (int)(delta.attoseconds / ATTOSECONDS_IN_USEC(1));
+
+ printf( "bitdelta = %d\n", usecdiff );
+ }
+#endif
+
+ /* if the delay is less than 3 msec, we're receiving data */
+ if ( delta.attoseconds < ATTOTIME_IN_MSEC(3).attoseconds )
+ {
+ /* 0 bit delta is 1.05 msec, 1 bit delta is 2.11 msec */
+ int longpulse = ( delta.attoseconds < ATTOTIME_IN_USEC(1500).attoseconds ) ? 0 : 1;
+ pr8210->commandtriplet[pr8210->mode] <<= 1;
+ pr8210->commandtriplet[pr8210->mode] |= longpulse;
+
+ /* if we received 10 bits, see what we need to do */
+ if ( ++pr8210->commandbits >= 10 )
+ {
+ /* reset bit shift count */
+ pr8210->commandbits = 0;
+
+ /* mask just the 10 bits */
+ pr8210->commandtriplet[pr8210->mode] &= 0x3ff;
+
+ /* execute command */
+ pr8210_command( info );
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ PIONEER LD-V1000 IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ ldv1000_init - Pioneer LDV-1000-specific
+ initialization
+-------------------------------------------------*/
+
+static void ldv1000_init(laserdisc_info *info)
+{
+ /* set up the write callbacks */
+ info->writedata = ldv1000_data_w;
+
+ /* set up the read callbacks */
+ info->readdata = ldv1000_status_r;
+ info->readline[LASERDISC_LINE_STATUS] = ldv1000_status_strobe_r;
+ info->readline[LASERDISC_LINE_COMMAND] = ldv1000_command_strobe_r;
+
+ /* do a soft reset */
+ ldv1000_soft_reset(info);
+}
+
+
+/*-------------------------------------------------
+ ldv1000_soft_reset - Pioneer LDV-1000-specific
+ soft reset
+-------------------------------------------------*/
+
+static void ldv1000_soft_reset(laserdisc_info *info)
+{
+ ldv1000_info *ldv1000 = &info->u.ldv1000;
+
+ info->audio = AUDIO_CH1_ENABLE | AUDIO_CH2_ENABLE;
+ info->display = FALSE;
+ ldv1000->mode = LDV1000_MODE_STATUS;
+ ldv1000->activereg = 0;
+ ldv1000->statusmask = 0xff;
+ write_16bits_to_ram_be(ldv1000->ram, 0, 1);
+}
+
+
+/*-------------------------------------------------
+ ldv1000_data_w - write callback when the
+ ENTER state is written
+-------------------------------------------------*/
+
+static void ldv1000_data_w(laserdisc_info *info, UINT8 prev, UINT8 data)
+{
+ static const UINT8 numbers[10] = { 0x3f, 0x0f, 0x8f, 0x4f, 0x2f, 0xaf, 0x6f, 0x1f, 0x9f, 0x5f };
+ ldv1000_info *ldv1000 = &info->u.ldv1000;
+
+ /* 0xFF bytes are used for synchronization */
+ if (data == 0xff)
+ {
+ ldv1000->statusmask = 0xff; /* EHC 012207: reset our status mask */
+ return;
+ }
+
+ /* if we're not ready, return, otherwise signal ourselves busy */
+ if (ldv1000->statusmask == 0x7f)
+ return;
+ ldv1000->statusmask = 0x7f;
+
+ /* look for and process numbers */
+ if (process_number(info, data, numbers))
+ return;
+
+ /* handle commands */
+ switch (data)
+ {
+ case 0x7f: CMDPRINTF(("ldv1000: %d Recall\n", info->parameter));
+ /* set the active register */
+ ldv1000->activereg = info->parameter;
+ /* should also display the register value */
+ break;
+
+ case 0x20: CMDPRINTF(("ldv1000: x0 reverse (stop) - Badlands special\n"));
+ /* play reverse at 0 speed (stop) */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_REVERSE, STOP_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x21: CMDPRINTF(("ldv1000: x1/4 reverse - Badlands special\n"));
+ /* play reverse at 1/4 speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_REVERSE, -PLAY_SPEED / 4, NULL_TARGET_FRAME);
+ break;
+
+ case 0x22: CMDPRINTF(("ldv1000: x1/2 reverse - Badlands special\n"));
+ /* play reverse at 1/2 speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_REVERSE, -PLAY_SPEED / 2, NULL_TARGET_FRAME);
+ break;
+
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27: CMDPRINTF(("ldv1000: x%d reverse - Badlands special\n", (data & 0x07) - 2));
+ /* play reverse at 1-5x speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FAST_REVERSE, -PLAY_SPEED * ((data & 0x07) - 2), NULL_TARGET_FRAME);
+ break;
+
+ case 0xa0: CMDPRINTF(("ldv1000: x0 forward (stop)\n"));
+ /* play forward at 0 speed (stop) */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_FORWARD, STOP_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0xa1: CMDPRINTF(("ldv1000: x1/4 forward\n"));
+ /* play forward at 1/4 speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_FORWARD, PLAY_SPEED / 4, NULL_TARGET_FRAME);
+ break;
+
+ case 0xa2: CMDPRINTF(("ldv1000: x1/2 forward\n"));
+ /* play forward at 1/2 speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_FORWARD, PLAY_SPEED / 2, NULL_TARGET_FRAME);
+ break;
+
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7: CMDPRINTF(("ldv1000: x%d forward\n", (data & 0x07) - 2));
+ /* play forward at 1-5x speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FAST_FORWARD, PLAY_SPEED * ((data & 0x07) - 2), NULL_TARGET_FRAME);
+ break;
+
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba: CMDPRINTF(("ldv1000: Skip forward %d0\n", data & 0x0f));
+ /* skip forward */
+ if (laserdisc_active(info))
+ {
+ /* note that this skips tracks, not frames; the track->frame count is not 1:1 */
+ /* in the case of 3:2 pulldown or other effects; for now, we just ignore the diff */
+ add_to_current_track(info, INT_TO_FRAC(10 * (data & 0x0f)));
+ }
+ break;
+
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a: CMDPRINTF(("ldv1000: Skip backwards %d0 - Badlands special\n", data & 0x0f));
+ /* skip backward */
+ if (laserdisc_active(info))
+ {
+ /* note that this skips tracks, not frames; the track->frame count is not 1:1 */
+ /* in the case of 3:2 pulldown or other effects; for now, we just ignore the diff */
+ add_to_current_track(info, -INT_TO_FRAC(10 * (data & 0x0f)));
+ }
+ break;
+
+ case 0xbf: CMDPRINTF(("ldv1000: %d Clear\n", info->parameter));
+ /* clears register display and removes pending arguments */
+ break;
+
+ case 0xc2: CMDPRINTF(("ldv1000: Get frame no.\n"));
+ /* returns the current frame number */
+ ldv1000->mode = LDV1000_MODE_GET_FRAME;
+ ldv1000->readpos = 0;
+ ldv1000->readtotal = 5;
+ sprintf((char *)ldv1000->readbuf, "%05d", info->last_frame);
+ break;
+
+ case 0xc3: CMDPRINTF(("ldv1000: Get 2nd display\n"));
+ /* returns the data from the 2nd display line */
+ ldv1000->mode = LDV1000_MODE_GET_2ND;
+ ldv1000->readpos = 0;
+ ldv1000->readtotal = 8;
+ sprintf((char *)ldv1000->readbuf, " \x1c\x1c\x1c");
+ break;
+
+ case 0xc4: CMDPRINTF(("ldv1000: Get 1st display\n"));
+ /* returns the data from the 1st display line */
+ ldv1000->mode = LDV1000_MODE_GET_1ST;
+ ldv1000->readpos = 0;
+ ldv1000->readtotal = 8;
+ sprintf((char *)ldv1000->readbuf, " \x1c\x1c\x1c");
+ break;
+
+ case 0xc8: CMDPRINTF(("ldv1000: Transfer memory\n"));
+ /* returns the data from the 1st display line */
+ ldv1000->mode = LDV1000_MODE_GET_RAM;
+ ldv1000->readpos = 0;
+ ldv1000->readtotal = 1024;
+ break;
+
+ case 0xcc: CMDPRINTF(("ldv1000: Load\n"));
+ /* load program from disc -- not implemented */
+ break;
+
+ case 0xcd: CMDPRINTF(("ldv1000: Display disable\n"));
+ /* disables the display of current command -- not implemented */
+ break;
+
+ case 0xce: CMDPRINTF(("ldv1000: Display enable\n"));
+ /* enables the display of current command -- not implemented */
+ break;
+
+ case 0xf0: CMDPRINTF(("ldv1000: Scan forward\n"));
+ /* scan forward */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_SCANNING_FORWARD, LDV1000_SCAN_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0xf1: CMDPRINTF(("ldv1000: %d Display\n", info->parameter));
+ /* toggle or set the frame display */
+ info->display = (info->parameter == -1) ? !info->display : (info->parameter & 1);
+ break;
+
+ case 0xf3: CMDPRINTF(("ldv1000: %d Autostop\n", info->parameter));
+ /* play to a particular location and stop there */
+ if (laserdisc_ready(info))
+ {
+ INT32 targetframe = info->parameter;
+
+ if (targetframe == -1)
+ targetframe = read_16bits_from_ram_be(ldv1000->ram, (ldv1000->activereg++ * 2) % 1024);
+
+ if (targetframe > info->last_frame)
+ set_state(info, LASERDISC_PLAYING_FORWARD, PLAY_SPEED, targetframe);
+ else
+ set_state(info, LASERDISC_SEARCHING_FRAME, PR7820_SEARCH_SPEED, targetframe);
+ }
+ break;
+
+ case 0xf4: CMDPRINTF(("ldv1000: %d Audio track 1\n", info->parameter));
+ /* toggle or set the state of audio channel 1 */
+ if (info->parameter == -1)
+ info->audio ^= AUDIO_CH1_ENABLE;
+ else
+ info->audio = (info->audio & ~AUDIO_CH1_ENABLE) | ((info->parameter & 1) ? AUDIO_CH1_ENABLE : 0);
+ break;
+
+ case 0xf5: CMDPRINTF(("ldv1000: %d Store\n", info->parameter));
+ /* store either the current frame number or an explicit value into the active register */
+ if (info->parameter == -1)
+ write_16bits_to_ram_be(ldv1000->ram, (ldv1000->activereg * 2) % 1024, info->last_frame);
+ else
+ write_16bits_to_ram_be(ldv1000->ram, (ldv1000->activereg * 2) % 1024, info->parameter);
+ ldv1000->activereg++;
+ break;
+
+ case 0xf6: CMDPRINTF(("ldv1000: Step forward\n"));
+ /* step forward one frame */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_STEPPING_FORWARD, STOP_SPEED, NULL_TARGET_FRAME);
+ add_to_current_track(info, ONE_TRACK);
+ }
+ break;
+
+ case 0xf7: CMDPRINTF(("ldv1000: %d Search\n", info->parameter));
+ /* search to a particular frame number */
+ if (laserdisc_ready(info))
+ {
+ INT32 targetframe = info->parameter;
+
+ if (targetframe == -1)
+ targetframe = read_16bits_from_ram_be(ldv1000->ram, (ldv1000->activereg++ * 2) % 1024);
+ ldv1000->activereg++;
+
+ set_state(info, LASERDISC_SEARCHING_FRAME, LDV1000_SEARCH_SPEED, targetframe);
+ }
+ break;
+
+ case 0xf8: CMDPRINTF(("ldv1000: Scan reverse\n"));
+ /* scan reverse */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_SCANNING_REVERSE, -LDV1000_SCAN_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0xf9: CMDPRINTF(("ldv1000: Reject\n"));
+ /* move the head to parked position, and stop rotation */
+ set_state(info, LASERDISC_PARKED, STOP_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0xfb: CMDPRINTF(("ldv1000: %d Stop/Wait\n", info->parameter));
+ /* pause at the current location for a fixed amount of time (in 1/10ths of a second) */
+ if (laserdisc_ready(info))
+ {
+ laserdisc_state prevstate = info->state;
+ INT32 prevspeed = info->curfracspeed;
+ set_state(info, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
+ if (info->parameter != -1)
+ set_hold_state(info, double_to_attotime(info->parameter * 0.1), prevstate, prevspeed);
+ }
+ break;
+
+ case 0xfc: CMDPRINTF(("ldv1000: %d Audio track 2\n", info->parameter));
+ /* toggle or set the state of audio channel 2 */
+ if (info->parameter == -1)
+ info->audio ^= AUDIO_CH2_ENABLE;
+ else
+ info->audio = (info->audio & ~AUDIO_CH2_ENABLE) | ((info->parameter & 1) ? AUDIO_CH2_ENABLE : 0);
+ break;
+
+ case 0xfd: CMDPRINTF(("ldv1000: Play\n"));
+ /* begin playing at regular speed, or load the disc if it is parked */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FORWARD, PLAY_SPEED, NULL_TARGET_FRAME);
+ else
+ {
+ if (info->state == LASERDISC_PARKED)
+ {
+ set_state(info, LASERDISC_SPINUP, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_SPINUP_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
+ }
+ else
+ {
+ set_state(info, LASERDISC_LOADING, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_LOAD_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
+ }
+
+ info->curfractrack = ONE_TRACK;
+ }
+ break;
+
+ case 0xfe: CMDPRINTF(("ldv1000: Step reverse\n"));
+ /* step backwards one frame */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_STEPPING_REVERSE, STOP_SPEED, NULL_TARGET_FRAME);
+ add_to_current_track(info, -ONE_TRACK);
+ }
+ break;
+
+ default: CMDPRINTF(("ldv1000: %d Unknown command %02X\n", info->parameter, data));
+ /* unknown command */
+ break;
+ }
+
+ /* reset the parameter after executing a command */
+ info->parameter = -1;
+}
+
+
+/*-------------------------------------------------
+ ldv1000_status_strobe_r - return state of the
+ status strobe
+-------------------------------------------------*/
+
+static UINT8 ldv1000_status_strobe_r(laserdisc_info *info)
+{
+ /* the status strobe is asserted (active low) 500-650usec after VSYNC */
+ /* for a duration of 26usec; we pick 600-626usec */
+ attotime delta = attotime_sub(timer_get_time(), info->lastvsynctime);
+ if (delta.attoseconds >= ATTOTIME_IN_USEC(600).attoseconds &&
+ delta.attoseconds < ATTOTIME_IN_USEC(626).attoseconds)
+ return ASSERT_LINE;
+
+ return CLEAR_LINE;
+}
+
+
+/*-------------------------------------------------
+ ldv1000_command_strobe_r - return state of the
+ command strobe
+-------------------------------------------------*/
+
+static UINT8 ldv1000_command_strobe_r(laserdisc_info *info)
+{
+ /* the command strobe is asserted (active low) 54 or 84usec after the status */
+ /* strobe for a duration of 25usec; we pick 600+84 = 684-709usec */
+ /* for a duration of 26usec; we pick 600-626usec */
+ attotime delta = attotime_sub(timer_get_time(), info->lastvsynctime);
+ if (delta.attoseconds >= ATTOTIME_IN_USEC(684).attoseconds &&
+ delta.attoseconds < ATTOTIME_IN_USEC(709).attoseconds)
+ return ASSERT_LINE;
+
+ return CLEAR_LINE;
+}
+
+
+/*-------------------------------------------------
+ ldv1000_status_r - return state of the ready
+ line
+-------------------------------------------------*/
+
+static UINT8 ldv1000_status_r(laserdisc_info *info)
+{
+ ldv1000_info *ldv1000 = &info->u.ldv1000;
+ UINT8 status = 0xff;
+
+ /* switch off the current mode */
+ switch (ldv1000->mode)
+ {
+ /* reading frame number returns 5 characters */
+ /* reading display lines returns 8 characters */
+ case LDV1000_MODE_GET_FRAME:
+ case LDV1000_MODE_GET_1ST:
+ case LDV1000_MODE_GET_2ND:
+ assert(ldv1000->readpos < ldv1000->readtotal);
+ status = ldv1000->readbuf[ldv1000->readpos++];
+ if (ldv1000->readpos == ldv1000->readtotal)
+ ldv1000->mode = LDV1000_MODE_STATUS;
+ break;
+
+ /* reading RAM returns 1024 bytes */
+ case LDV1000_MODE_GET_RAM:
+ assert(ldv1000->readpos < ldv1000->readtotal);
+ status = ldv1000->ram[1023 - ldv1000->readpos++];
+ if (ldv1000->readpos == ldv1000->readtotal)
+ ldv1000->mode = LDV1000_MODE_STATUS;
+ break;
+
+ /* otherwise, we just compute a status code */
+ default:
+ case LDV1000_MODE_STATUS:
+ switch (info->state)
+ {
+ case LASERDISC_EJECTED: status = 0xe0; break;
+ case LASERDISC_EJECTING: status = 0x60; break;
+ case LASERDISC_LOADED: status = 0xc8; break;
+ case LASERDISC_SPINUP:
+ case LASERDISC_LOADING: status = 0x48; break;
+ case LASERDISC_PARKED: status = 0xfc; break;
+
+ case LASERDISC_SEARCHING_FRAME: status = 0x50; break;
+ case LASERDISC_SEARCH_FINISHED: status = 0xd0; break;
+
+ case LASERDISC_STOPPED: status = 0xe5; break;
+ case LASERDISC_AUTOSTOPPED: status = 0x54; break;
+
+ case LASERDISC_PLAYING_FORWARD: status = 0xe4; break;
+ case LASERDISC_PLAYING_REVERSE: status = 0xe4; break;
+ case LASERDISC_PLAYING_SLOW_FORWARD: status = 0xae; break;
+ case LASERDISC_PLAYING_SLOW_REVERSE: status = 0xae; break;
+ case LASERDISC_PLAYING_FAST_FORWARD: status = 0xae; break;
+ case LASERDISC_PLAYING_FAST_REVERSE: status = 0xae; break;
+ case LASERDISC_STEPPING_FORWARD: status = 0xe5; break;
+ case LASERDISC_STEPPING_REVERSE: status = 0xe5; break;
+ case LASERDISC_SCANNING_FORWARD: status = 0x4c; break;
+ case LASERDISC_SCANNING_REVERSE: status = 0x4c; break;
+ default:
+ fatalerror("Unexpected disc state in ldv1000_status_r\n");
+ break;
+ }
+ break;
+ }
+
+ /* bit 7 indicates our busy status */
+ return status & ldv1000->statusmask;
+}
+
+
+
+/***************************************************************************
+ SONY LDP-1450 IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ ldp1450_init - Sony LDP-1450-specific
+ initialization
+-------------------------------------------------*/
+
+static void ldp1450_init(laserdisc_info *info)
+{
+ /* set up the write callbacks */
+ info->writedata = ldp1450_data_w;
+
+ /* set up the read callbacks */
+ info->readdata = ldp1450_data_r;
+ info->readline[LASERDISC_LINE_DATA_AVAIL] = ldp1450_data_avail_r;
+
+ /* use a state changed callback */
+ info->statechanged = ldp1450_state_changed;
+
+ /* do a soft reset */
+ ldp1450_soft_reset(info);
+}
+
+
+/*-------------------------------------------------
+ ldp1450_soft_reset - Sony LDP-1450-specific
+ soft reset
+-------------------------------------------------*/
+
+static void ldp1450_soft_reset(laserdisc_info *info)
+{
+ info->audio = AUDIO_CH1_ENABLE | AUDIO_CH2_ENABLE;
+ info->display = FALSE;
+ set_state(info, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
+ info->curfractrack = ONE_TRACK;
+}
+
+
+/*-------------------------------------------------
+ ldp1450_compute_status - compute the current
+ status bytes on the LDP-1450
+-------------------------------------------------*/
+
+static void ldp1450_compute_status(laserdisc_info *info)
+{
+ /*
+ Byte 0: LDP ready status:
+ 0x80 Ready
+ 0x82 Disc Spinning down
+ 0x86 Tray closed & no disc loaded
+ 0x8A Disc ejecting, tray opening
+ 0x92 Disc loading, tray closing
+ 0x90 Disc spinning up
+ 0xC0 Busy Searching
+
+ Byte 1: Error status:
+ 0x00 No error
+ 0x01 Focus unlock
+ 0x02 Communication Error
+
+ Byte 2: Disc/motor status:
+ 0x01 Motor Off (disc spinning down or tray opening/ed)
+ 0x02 Tray closed & motor Off (no disc loaded)
+ 0x11 Motor On
+
+ Byte 3: Command/argument status:
+ 0x00 Normal
+ 0x01 Relative search or Mark Set pending (Enter not sent)
+ 0x03 Search pending (Enter not sent)
+ 0x05 Repeat pending (Enter not sent) or Memory Search in progress
+ 0x80 FWD or REV Step
+
+ Byte 4: Playback mode:
+ 0x00 Searching, Motor On (spinning up), motor Off (spinning down), tray opened/ing (no motor phase lock)
+ 0x01 FWD Play
+ 0x02 FWD Fast
+ 0x04 FWD Slow
+ 0x08 FWD Step
+ 0x10 FWD Scan
+ 0x20 Still
+ 0x81 REV Play
+ 0x82 REV Fast
+ 0x84 REV Slow
+ 0x88 REV Step
+ 0x90 REV Scan
+ */
+
+ ldp1450_info *ldp1450 = &info->u.ldp1450;
+ UINT32 statusbytes = 0;
+
+ switch (info->state)
+ {
+ case LASERDISC_EJECTED: statusbytes = 0x86000200; break;
+ case LASERDISC_EJECTING: statusbytes = 0x8a000100; break;
+ case LASERDISC_LOADED: statusbytes = 0x80000100; break;
+ case LASERDISC_SPINUP:
+ case LASERDISC_LOADING: statusbytes = 0x92001100; break;
+ case LASERDISC_PARKED: statusbytes = 0x80000100; break;
+ case LASERDISC_SEARCHING_FRAME: statusbytes = 0xc0001100; break;
+
+ case LASERDISC_SEARCH_FINISHED:
+ case LASERDISC_STOPPED:
+ case LASERDISC_AUTOSTOPPED: statusbytes = 0x80001120; break;
+
+ case LASERDISC_PLAYING_FORWARD: statusbytes = 0x80001101; break;
+ case LASERDISC_PLAYING_REVERSE: statusbytes = 0x80001181; break;
+ case LASERDISC_PLAYING_SLOW_FORWARD: statusbytes = 0x80001104; break;
+ case LASERDISC_PLAYING_SLOW_REVERSE: statusbytes = 0x80001184; break;
+ case LASERDISC_PLAYING_FAST_FORWARD: statusbytes = 0x80001102; break;
+ case LASERDISC_PLAYING_FAST_REVERSE: statusbytes = 0x80001182; break;
+ case LASERDISC_STEPPING_FORWARD: statusbytes = 0x80001108; break;
+ case LASERDISC_STEPPING_REVERSE: statusbytes = 0x80001188; break;
+ case LASERDISC_SCANNING_FORWARD: statusbytes = 0x80001110; break;
+ case LASERDISC_SCANNING_REVERSE: statusbytes = 0x80001190; break;
+
+ default:
+ fatalerror("Unexpected disc state in ldp1450_compute_status\n");
+ break;
+ }
+
+ /* copy in the result bytes */
+ ldp1450->readtotal = 0;
+ ldp1450->readbuf[ldp1450->readtotal++] = (statusbytes >> 24) & 0xff;
+ ldp1450->readbuf[ldp1450->readtotal++] = (statusbytes >> 16) & 0xff;
+ ldp1450->readbuf[ldp1450->readtotal++] = (statusbytes >> 8) & 0xff;
+ switch (info->command)
+ {
+ case 0x43: ldp1450->readbuf[ldp1450->readtotal++] = 0x03; break;
+ default: ldp1450->readbuf[ldp1450->readtotal++] = 0x00; break;
+ }
+ ldp1450->readbuf[ldp1450->readtotal++] = (statusbytes >> 0) & 0xff;
+}
+
+
+/*-------------------------------------------------
+ ldp1450_data_w - write callback when the
+ ENTER state is written
+-------------------------------------------------*/
+
+static void ldp1450_data_w(laserdisc_info *info, UINT8 prev, UINT8 data)
+{
+ static const UINT8 numbers[10] = { 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39 };
+ ldp1450_info *ldp1450 = &info->u.ldp1450;
+
+ /* by default, we return an ack on each command */
+ ldp1450->readpos = ldp1450->readtotal = 0;
+ ldp1450->readbuf[ldp1450->readtotal++] = 0x0a;
+
+ /* look for and process numbers */
+ if (process_number(info, data, numbers))
+ {
+ CMDPRINTF(("%c", data));
+ return;
+ }
+
+ /* handle commands */
+ switch (data)
+ {
+ case 0x24: CMDPRINTF(("ldp1450: Audio Mute On\n"));
+ /* mute audio */
+ info->audio |= AUDIO_EXPLICIT_MUTE;
+ break;
+
+ case 0x25: CMDPRINTF(("ldp1450: Audio Mute Off\n"));
+ /* unmute audio */
+ info->audio &= ~AUDIO_EXPLICIT_MUTE;
+ break;
+
+ case 0x26: CMDPRINTF(("ldp1450: Video Mute Off\n"));
+ /* mute video -- not implemented */
+ break;
+
+ case 0x27: CMDPRINTF(("ldp1450: Video Mute On\n"));
+ /* unmute video -- not implemented */
+ break;
+
+ case 0x28: CMDPRINTF(("ldp1450: PSC Enable\n"));
+ /* enable Picture Stop Codes (PSC) -- not implemented */
+ break;
+
+ case 0x29: CMDPRINTF(("ldp1450: PSC Disable\n"));
+ /* disable Picture Stop Codes (PSC) -- not implemented */
+ break;
+
+ case 0x2a: CMDPRINTF(("ldp1450: %d Eject\n", info->parameter));
+ /* eject the disc */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_EJECTING, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_LOAD_TIME, LASERDISC_EJECTED, STOP_SPEED);
+ }
+ break;
+
+ case 0x2b: CMDPRINTF(("ldp1450: %d Step forward\n", info->parameter));
+ /* step forward one frame */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_STEPPING_FORWARD, STOP_SPEED, NULL_TARGET_FRAME);
+ add_to_current_track(info, ONE_TRACK);
+ }
+ break;
+
+ case 0x2c: CMDPRINTF(("ldp1450: %d Step reverse\n", info->parameter));
+ /* step backwards one frame */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_STEPPING_REVERSE, STOP_SPEED, NULL_TARGET_FRAME);
+ add_to_current_track(info, -ONE_TRACK);
+ }
+ break;
+
+ case 0x2d: CMDPRINTF(("ldp1450: %d Search multiple tracks forward\n", info->parameter));
+ /* enable Picture Stop Codes (PSC) -- not implemented */
+ break;
+
+ case 0x2e: CMDPRINTF(("ldp1450: %d Search multiple tracks reverse\n", info->parameter));
+ /* disable Picture Stop Codes (PSC) -- not implemented */
+ break;
+
+ case 0x3a: CMDPRINTF(("ldp1450: %d Play\n", info->parameter));
+ /* begin playing at regular speed, or load the disc if it is parked */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FORWARD, PLAY_SPEED, NULL_TARGET_FRAME);
+ else
+ {
+ if (info->state == LASERDISC_PARKED)
+ {
+ set_state(info, LASERDISC_SPINUP, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_SPINUP_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
+ }
+ else
+ {
+ set_state(info, LASERDISC_LOADING, STOP_SPEED, NULL_TARGET_FRAME);
+ set_hold_state(info, GENERIC_LOAD_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
+ }
+
+ info->curfractrack = ONE_TRACK;
+ }
+ break;
+
+ case 0x3b: CMDPRINTF(("ldp1450: %d Fast forward play\n", info->parameter));
+ /* play forward fast speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FAST_FORWARD, LDP1450_FAST_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x3c: CMDPRINTF(("ldp1450: %d Slow forward play\n", info->parameter));
+ /* play forward slow speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_FORWARD, LDP1450_SLOW_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x3d: CMDPRINTF(("ldp1450: %d Variable forward play\n", info->parameter));
+ /* play forward variable speed */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_STEPPING_FORWARD, LDP1450_STEP_SPEED, NULL_TARGET_FRAME);
+ info->command = 0x3d;
+ }
+ break;
+
+ case 0x3e: CMDPRINTF(("ldp1450: %d Scan forward\n", info->parameter));
+ /* scan forward */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_SCANNING_FORWARD, LDP1450_SCAN_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x3f: CMDPRINTF(("ldp1450: Stop\n"));
+ /* pause at the current location */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x40: CMDPRINTF((" ... Enter\n"));
+ /* Enter -- execute command with parameter */
+ switch (info->command)
+ {
+ case 0x3d: /* forward variable speed */
+ if (info->parameter != 0)
+ info->curfracspeed = PLAY_SPEED / info->parameter;
+ break;
+
+ case 0x43: /* search */
+ set_state(info, LASERDISC_SEARCHING_FRAME, LDP1450_SEARCH_SPEED, info->parameter);
+ break;
+
+ case 0x4d: /* reverse variable speed */
+ if (info->parameter != 0)
+ info->curfracspeed = -PLAY_SPEED / info->parameter;
+ break;
+
+ default: CMDPRINTF(("Unknown command: %02X\n", info->command));
+ break;
+ }
+ break;
+
+ case 0x41: CMDPRINTF(("ldp1450: %d Clear entry\n", info->parameter));
+ /* Clear entry */
+ break;
+
+ case 0x42: CMDPRINTF(("ldp1450: %d Menu\n", info->parameter));
+ /* Menu -- not implemented */
+ break;
+
+ case 0x43: CMDPRINTF(("ldp1450: Search ... "));
+ /* search to a particular frame number */
+ if (laserdisc_ready(info))
+ {
+ info->command = data;
+
+ /* Note that the disc stops as soon as the search command is issued */
+ set_state(info, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
+ }
+ break;
+
+ case 0x44: CMDPRINTF(("ldp1450: %d Repeat\n", info->parameter));
+ /* Repeat -- not implemented */
+ break;
+
+ case 0x46: CMDPRINTF(("ldp1450: Ch1 On\n"));
+ /* channel 1 audio on */
+ info->audio |= AUDIO_CH1_ENABLE;
+ break;
+
+ case 0x47: CMDPRINTF(("ldp1450: Ch1 Off\n"));
+ /* channel 1 audio off */
+ info->audio &= ~AUDIO_CH1_ENABLE;
+ break;
+
+ case 0x48: CMDPRINTF(("ldp1450: Ch2 On\n"));
+ /* channel 1 audio on */
+ info->audio |= AUDIO_CH2_ENABLE;
+ break;
+
+ case 0x49: CMDPRINTF(("ldp1450: Ch2 Off\n"));
+ /* channel 1 audio off */
+ info->audio &= ~AUDIO_CH2_ENABLE;
+ break;
+
+ case 0x4a: CMDPRINTF(("ldp1450: %d Reverse Play\n", info->parameter));
+ /* begin playing at regular speed, or load the disc if it is parked */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_REVERSE, -PLAY_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x4b: CMDPRINTF(("ldp1450: %d Fast reverse play\n", info->parameter));
+ /* play reverse fast speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_FAST_REVERSE, -LDP1450_FAST_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x4c: CMDPRINTF(("ldp1450: %d Slow reverse play\n", info->parameter));
+ /* play reverse slow speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_PLAYING_SLOW_REVERSE, -LDP1450_SLOW_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x4d: CMDPRINTF(("ldp1450: %d Variable reverse play\n", info->parameter));
+ /* play reverse variable speed */
+ if (laserdisc_ready(info))
+ {
+ set_state(info, LASERDISC_STEPPING_REVERSE, -LDP1450_STEP_SPEED, NULL_TARGET_FRAME);
+ info->command = 0x4d;
+ }
+ break;
+
+ case 0x4e: CMDPRINTF(("ldp1450: %d Scan reverse\n", info->parameter));
+ /* play forward variable speed */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_SCANNING_REVERSE, -LDP1450_SCAN_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x4f: CMDPRINTF(("ldp1450: %d Still\n", info->parameter));
+ /* still picture */
+ if (laserdisc_ready(info))
+ set_state(info, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
+ break;
+
+ case 0x50: CMDPRINTF(("ldp1450: Index On\n"));
+ /* index on -- not implemented */
+ break;
+
+ case 0x51: CMDPRINTF(("ldp1450: Index Off\n"));
+ /* index off -- not implemented */
+ break;
+
+ case 0x55: CMDPRINTF(("ldp1450: %d Set to frame number mode\n", info->parameter));
+ /* set to frame number mode -- not implemented */
+ break;
+
+ case 0x56: CMDPRINTF(("ldp1450: %d Clear all\n", info->parameter));
+ /* clear all */
+ ldp1450_soft_reset(info);
+ break;
+
+ case 0x5a: CMDPRINTF(("ldp1450: %d Memory\n", info->parameter));
+ /* memorize current position -- not implemented */
+ break;
+
+ case 0x5b: CMDPRINTF(("ldp1450: %d Memory Search\n", info->parameter));
+ /* locate memorized position -- not implemented */
+ break;
+
+ case 0x60: CMDPRINTF(("ldp1450: %d Address Inquire\n", info->parameter));
+ /* inquire for current address */
+ ldp1450->readtotal = 0;
+ ldp1450->readbuf[ldp1450->readtotal++] = '0' + (info->last_frame / 10000) % 10;
+ ldp1450->readbuf[ldp1450->readtotal++] = '0' + (info->last_frame / 1000) % 10;
+ ldp1450->readbuf[ldp1450->readtotal++] = '0' + (info->last_frame / 100) % 10;
+ ldp1450->readbuf[ldp1450->readtotal++] = '0' + (info->last_frame / 10) % 10;
+ ldp1450->readbuf[ldp1450->readtotal++] = '0' + (info->last_frame / 1) % 10;
+ break;
+
+ case 0x61: CMDPRINTF(("ldp1450: %d Continue\n", info->parameter));
+ /* resume the mode prior to still -- not implemented */
+ break;
+
+ case 0x62: CMDPRINTF(("ldp1450: Motor On\n"));
+ /* motor on -- not implemented */
+ break;
+
+ case 0x63: CMDPRINTF(("ldp1450: Motor Off\n"));
+ /* motor off -- not implemented */
+ break;
+
+ case 0x67: CMDPRINTF(("ldp1450: %d Status Inquire\n", info->parameter));
+ /* inquire status of player */
+ ldp1450_compute_status(info);
+ break;
+
+ case 0x69: CMDPRINTF(("ldp1450: %d Chapter Mode\n", info->parameter));
+ /* set to chapter number mode -- not implemented */
+ break;
+
+ case 0x6e: CMDPRINTF(("ldp1450: CX On\n"));
+ /* CX noise reduction on -- not implemented */
+ break;
+
+ case 0x6f: CMDPRINTF(("ldp1450: CX Off\n"));
+ /* CX noise reduction off -- not implemented */
+ break;
+
+ case 0x71: CMDPRINTF(("ldp1450: %d Non-CF Play\n", info->parameter));
+ /* disengage color framing -- not implemented */
+ break;
+
+ case 0x72: CMDPRINTF(("ldp1450: %d ROM Version\n", info->parameter));
+ /* inquire ROM version -- not implemented */
+ break;
+
+ case 0x73: CMDPRINTF(("ldp1450: %d Mark Set\n", info->parameter));
+ /* set mark position -- not implemented */
+ break;
+
+ case 0x74: CMDPRINTF(("ldp1450: Eject Enable On\n"));
+ /* activate eject function -- not implemented */
+ break;
+
+ case 0x75: CMDPRINTF(("ldp1450: Eject Disable Off\n"));
+ /* deactivate eject function -- not implemented */
+ break;
+
+ case 0x76: CMDPRINTF(("ldp1450: %d Chapter Inquire\n", info->parameter));
+ /* inquire current chapter -- not implemented */
+ break;
+
+ case 0x79: CMDPRINTF(("ldp1450: %d User Code Inquire\n", info->parameter));
+ /* inquire user's code -- not implemented */
+ break;
+
+ case 0x80: CMDPRINTF(("ldp1450: %d User Index Control\n", info->parameter));
+ /* set user defined index -- not implemented */
+ break;
+
+ case 0x81: CMDPRINTF(("ldp1450: Activate user defined index\n"));
+ /* activate eject function -- not implemented */
+ break;
+
+ case 0x82: CMDPRINTF(("ldp1450: Deactivate user defined index\n"));
+ /* deactivate eject function -- not implemented */
+ break;
+
+ default: CMDPRINTF(("ldp1450: %d Unknown command %02X\n", info->parameter, data));
+ /* unknown command -- respond with a NAK */
+ ldp1450->readtotal = 0;
+ ldp1450->readbuf[ldp1450->readtotal++] = 0x0b;
+ break;
+ }
+
+ /* reset the parameter after executing a command */
+ info->parameter = -1;
+}
+
+
+/*-------------------------------------------------
+ ldp1450_data_avail_r - return ASSERT_LINE if
+ serial data is available
+-------------------------------------------------*/
+
+static UINT8 ldp1450_data_avail_r(laserdisc_info *info)
+{
+ ldp1450_info *ldp1450 = &info->u.ldp1450;
+ return (ldp1450->readpos < ldp1450->readtotal) ? ASSERT_LINE : CLEAR_LINE;
+}
+
+
+/*-------------------------------------------------
+ ldp1450_data_r - return data from the player
+-------------------------------------------------*/
+
+static UINT8 ldp1450_data_r(laserdisc_info *info)
+{
+ ldp1450_info *ldp1450 = &info->u.ldp1450;
+
+ if (ldp1450->readpos < ldp1450->readtotal)
+ return ldp1450->readbuf[ldp1450->readpos++];
+ return 0xff;
+}
+
+
+/*-------------------------------------------------
+ ldp1450_state_changed - Sony LDP-1450-specific
+ state changed callback
+-------------------------------------------------*/
+
+static void ldp1450_state_changed(laserdisc_info *info, UINT8 oldstate)
+{
+ ldp1450_info *ldp1450 = &info->u.ldp1450;
+
+ /* look for searching -> search finished state */
+ if (info->state == LASERDISC_SEARCH_FINISHED && oldstate == LASERDISC_SEARCHING_FRAME)
+ {
+ ldp1450->readpos = ldp1450->readtotal = 0;
+ ldp1450->readbuf[ldp1450->readtotal++] = 0x01;
+ }
+}
+
+
+
+/***************************************************************************
+ PHILPS 22VP932 IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ vp932_init - Philips 22VP932-specific
+ initialization
+-------------------------------------------------*/
+
+static void vp932_init(laserdisc_info *info)
+{
+ /* set up the write callbacks */
+ info->writedata = vp932_data_w;
+
+ /* set up the read callbacks */
+ info->readdata = vp932_data_r;
+ info->readline[LASERDISC_LINE_DATA_AVAIL] = vp932_data_avail_r;
+
+ /* use a state changed callback */
+ info->statechanged = vp932_state_changed;
+
+ /* do a soft reset */
+ vp932_soft_reset(info);
+}
+
+
+/*-------------------------------------------------
+ vp932_soft_reset - Philips 22VP932-specific
+ soft reset
+-------------------------------------------------*/
+
+static void vp932_soft_reset(laserdisc_info *info)
+{
+ vp932_info *vp932 = &info->u.vp932;
+
+ info->audio = AUDIO_CH1_ENABLE | AUDIO_CH2_ENABLE;
+ info->display = 0;
+
+ /* reset the pending count */
+ vp932->incount = 0;
+ vp932->outcount = 0;
+}
+
+
+/*-------------------------------------------------
+ vp932_data_w - write callback when data is
+ written
+-------------------------------------------------*/
+
+static void vp932_data_w(laserdisc_info *info, UINT8 prev, UINT8 data)
+{
+ vp932_info *vp932 = &info->u.vp932;
+
+ /* ignore 0's */
+ if (data == 0x00)
+ return;
+
+ /* if this isn't a CR, just accumulate it */
+ if (data != 0x0d)
+ {
+ if (vp932->incount < ARRAY_LENGTH(vp932->inbuffer))
+ vp932->inbuffer[vp932->incount++] = data;
+ }
+
+ /* otherwise, execute the command */
+ else
+ {
+ vp932->inbuffer[vp932->incount] = 0;
+ CMDPRINTF(("22vp932: %s\n", vp932->inbuffer));
+
+ switch (vp932->inbuffer[vp932->incount - 1])
+ {
+ case 'R': /* seek */
+ if (laserdisc_ready(info))
+ {
+ INT32 targetframe = 0, i;
+
+ for (i = 0; i < vp932->incount - 1; i++)
+ if (vp932->inbuffer[i] >= '0' && vp932->inbuffer[i] <= '9')
+ targetframe = (targetframe * 10) + (vp932->inbuffer[i] - '0');
+ set_state(info, LASERDISC_SEARCHING_FRAME, VP932_SEARCH_SPEED, targetframe);
+
+ vp932->outcount = 0;
+ vp932->outbuffer[vp932->outcount++] = 'A';
+ vp932->outbuffer[vp932->outcount++] = '0';
+ vp932->outbuffer[vp932->outcount++] = 0x0d;
+ }
+ break;
+ }
+
+ /* reset the command buffer */
+ vp932->incount = 0;
+ }
+}
+
+
+/*-------------------------------------------------
+ vp932_data_r - read callback when data is
+ returned
+-------------------------------------------------*/
+
+static UINT8 vp932_data_r(laserdisc_info *info)
+{
+ vp932_info *vp932 = &info->u.vp932;
+ UINT8 result = 0;
+
+ /* grab data if we can */
+ if (vp932->outcount > 0)
+ {
+ result = vp932->outbuffer[0];
+ if (--vp932->outcount > 0)
+ memmove(&vp932->outbuffer[0], &vp932->outbuffer[1], vp932->outcount);
+ }
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ vp932_data_avail_r - return ASSERT_LINE if
+ serial data is available
+-------------------------------------------------*/
+
+static UINT8 vp932_data_avail_r(laserdisc_info *info)
+{
+ vp932_info *vp932 = &info->u.vp932;
+ return (vp932->outcount > 0) ? ASSERT_LINE : CLEAR_LINE;
+}
+
+
+/*-------------------------------------------------
+ vp932_state_changed - Sony LDP-1450-specific
+ state changed callback
+-------------------------------------------------*/
+
+static void vp932_state_changed(laserdisc_info *info, UINT8 oldstate)
+{
+ vp932_info *vp932 = &info->u.vp932;
+
+ /* look for searching -> search finished state */
+ if (info->state == LASERDISC_SEARCH_FINISHED && oldstate == LASERDISC_SEARCHING_FRAME)
+ {
+ vp932->outcount = 0;
+ vp932->outbuffer[vp932->outcount++] = 'A';
+ vp932->outbuffer[vp932->outcount++] = '0';
+ vp932->outbuffer[vp932->outcount++] = 0x0d;
+ }
+}
diff --git a/src/emu/machine/laserdsc.h b/src/emu/machine/laserdsc.h
new file mode 100644
index 00000000000..78a404b577d
--- /dev/null
+++ b/src/emu/machine/laserdsc.h
@@ -0,0 +1,86 @@
+/*************************************************************************
+
+ laserdsc.h
+
+ Generic laserdisc support.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*************************************************************************/
+
+#pragma once
+
+#ifndef __LASERDSC_H__
+#define __LASERDSC_H__
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* types of players supported */
+#define LASERDISC_TYPE_PR7820 1 /* Pioneer PR-7820 */
+#define LASERDISC_TYPE_LDV1000 2 /* Pioneer LD-V1000 */
+#define LASERDISC_TYPE_22VP932 3 /* Phillips 22VP932 (PAL) */
+#define LASERDISC_TYPE_LDP1450 4 /* Sony LDP-1450 */
+#define LASERDISC_TYPE_PR8210 5 /* Pioneer PR-8210 / LD-V1100 */
+
+/* laserdisc control lines */
+#define LASERDISC_LINE_ENTER 0 /* "ENTER" key/line */
+#define LASERDISC_LINE_CONTROL 1 /* "CONTROL" line */
+#define LASERDISC_INPUT_LINES 2
+
+/* laserdisc status lines */
+#define LASERDISC_LINE_READY 0 /* "READY" line */
+#define LASERDISC_LINE_STATUS 1 /* "STATUS STROBE" line */
+#define LASERDISC_LINE_COMMAND 2 /* "COMMAND STROBE" line */
+#define LASERDISC_LINE_DATA_AVAIL 3 /* data available "line" */
+#define LASERDISC_OUTPUT_LINES 4
+
+/* laserdisc field codes */
+#define LASERDISC_CODE_FRAME_FLAGS 0
+#define LASERDISC_CODE_WHITE_FLAG 1
+#define LASERDISC_CODE_LINE16 2
+#define LASERDISC_CODE_LINE17 3
+#define LASERDISC_CODE_LINE18 4
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _laserdisc_info laserdisc_info;
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+extern struct CustomSound_interface laserdisc_custom_interface;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+laserdisc_info *laserdisc_init(int type, chd_file *chd, int custom_index);
+void laserdisc_reset(laserdisc_info *info, int type);
+void laserdisc_exit(laserdisc_info *info);
+void laserdisc_vsync(laserdisc_info *info);
+const char *laserdisc_describe_state(laserdisc_info *info);
+UINT32 laserdisc_get_video(laserdisc_info *info, mame_bitmap **bitmap);
+UINT32 laserdisc_get_field_code(laserdisc_info *info, UINT8 code);
+
+void laserdisc_data_w(laserdisc_info *info, UINT8 data);
+void laserdisc_line_w(laserdisc_info *info, UINT8 line, UINT8 newstate);
+UINT8 laserdisc_data_r(laserdisc_info *info);
+UINT8 laserdisc_line_r(laserdisc_info *info, UINT8 line);
+
+void pr7820_set_slow_speed(laserdisc_info *info, double frame_rate_scaler);
+
+#endif /* __LASERDSC_H__ */
diff --git a/src/emu/machine/mb3773.c b/src/emu/machine/mb3773.c
new file mode 100644
index 00000000000..be0d5d7e6cd
--- /dev/null
+++ b/src/emu/machine/mb3773.c
@@ -0,0 +1,39 @@
+/*
+ * mb3773 - Power Supply Monitor with Watch Dog Timer
+ *
+ * Todo:
+ * Calculate the timeout from parameters.
+ *
+ */
+
+#include "driver.h"
+#include "machine/mb3773.h"
+
+static emu_timer *watchdog_timer;
+static UINT8 ck = 0;
+
+static TIMER_CALLBACK( watchdog_timeout )
+{
+ mame_schedule_soft_reset(machine);
+}
+
+static void reset_timer( void )
+{
+ timer_adjust( watchdog_timer, ATTOTIME_IN_SEC( 5 ), 0, attotime_zero );
+}
+
+void mb3773_set_ck( UINT8 new_ck )
+{
+ if( new_ck == 0 && ck != 0 )
+ {
+ reset_timer();
+ }
+ ck = new_ck;
+}
+
+void mb3773_init( void )
+{
+ watchdog_timer = timer_alloc( watchdog_timeout );
+ reset_timer();
+ state_save_register_global( ck );
+}
diff --git a/src/emu/machine/mb3773.h b/src/emu/machine/mb3773.h
new file mode 100644
index 00000000000..90ba5ec5ed8
--- /dev/null
+++ b/src/emu/machine/mb3773.h
@@ -0,0 +1,12 @@
+/*
+ * mb3773 - Power Supply Monitor with Watch Dog Timer
+ *
+ */
+
+#if !defined( MB3773_H )
+#define MB3773_H ( 1 )
+
+extern void mb3773_set_ck( UINT8 new_ck );
+extern void mb3773_init( void );
+
+#endif
diff --git a/src/emu/machine/mb87078.c b/src/emu/machine/mb87078.c
new file mode 100644
index 00000000000..c98eccceccb
--- /dev/null
+++ b/src/emu/machine/mb87078.c
@@ -0,0 +1,169 @@
+/*****************************************************************************
+
+ MB87078 6-bit,4-channel electronic volume controller emulator
+
+ (for more detailed chip description see the mb87078.h file)
+
+ *****************************************************************************/
+
+#include "driver.h"
+#include "machine/mb87078.h"
+
+struct MB87078 {
+ const struct MB87078interface *intf;
+ int gain[4]; /* gain index 0-63,64,65 */
+ int channel_latch; /* current channel */
+ UINT8 latch[4*2]; /* 6bit+3bit 4 data latches */
+ UINT8 reset_comp;
+};
+
+static struct MB87078 chip[MAX_MB87078];
+
+static float MB87078_gain_decibel[66]={
+ 0.0, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0, -3.5,
+ -4.0, -4.5, -5.0, -5.5, -6.0, -6.5, -7.0, -7.5,
+ -8.0, -8.5, -9.0, -9.5,-10.0,-10.5,-11.0,-11.5,
+ -12.0,-12.5,-13.0,-13.5,-14.0,-14.5,-15.0,-15.5,
+ -16.0,-16.5,-17.0,-17.5,-18.0,-18.5,-19.0,-19.5,
+ -20.0,-20.5,-21.0,-21.5,-22.0,-22.5,-23.0,-23.5,
+ -24.0,-24.5,-25.0,-25.5,-26.0,-26.5,-27.0,-27.5,
+ -28.0,-28.5,-29.0,-29.5,-30.0,-30.5,-31.0,-31.5,
+ -32.0, -256.0
+ };
+
+static int MB87078_gain_percent[66]={
+ 100,94,89,84,79,74,70,66,
+ 63,59,56,53,50,47,44,42,
+ 39,37,35,33,31,29,28,26,
+ 25,23,22,21,19,18,17,16,
+ 15,14,14,13,12,11,11,10,
+ 10, 9, 8, 8, 7, 7, 7, 6,
+ 6, 5, 5, 5, 5, 4, 4, 4,
+ 3, 3, 3, 3, 3, 2, 2, 2,
+ 2, 0
+};
+
+#define GAIN_MAX_INDEX 64
+#define GAIN_INFINITY_INDEX 65
+
+
+
+static int calc_gain_index(int data0, int data1)
+{
+//data 0: GD0-GD5
+//data 1: 1 2 4 8 16
+// c1 c2 EN C0 C32
+
+ if (!(data1&4))
+ {
+ return GAIN_INFINITY_INDEX;
+ }
+ else
+ {
+ if ((data1&16))
+ {
+ return GAIN_MAX_INDEX;
+ }
+ else
+ {
+ if ((data1&8))
+ {
+ return 0;
+ }
+ else
+ {
+ return (data0^0x3f);
+ }
+ }
+ }
+}
+
+
+static void gain_recalc(int which)
+{
+ struct MB87078 *c = chip + which;
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ int old_index = c->gain[i];
+ c->gain[i] = calc_gain_index(c->latch[i], c->latch[4+i]);
+ if (old_index != c->gain[i])
+ {
+ (*c->intf->gain_changed_cb)(i, MB87078_gain_percent[c->gain[i]] );
+ }
+ }
+}
+
+
+void MB87078_start(int which, const struct MB87078interface *intf)
+{
+ if (which >= MAX_MB87078) return;
+
+ chip[which].intf = intf;
+
+ /* reset chip */
+ MB87078_reset_comp_w(which,0);
+ MB87078_reset_comp_w(which,1);
+}
+
+
+void MB87078_stop(void)
+{
+ //int i;
+ //for (i = 0; i < MAX_MB87078; i++){ };
+}
+
+
+void MB87078_reset_comp_w(int which, int level)
+{
+ struct MB87078 *c = chip + which;
+
+ c->reset_comp = level;
+
+ /*this seems to be true, according to the datasheets*/
+ if (level==0)
+ {
+ c->latch[0] = 0x3f;
+ c->latch[1] = 0x3f;
+ c->latch[2] = 0x3f;
+ c->latch[3] = 0x3f;
+ c->latch[4] = 0x0 | 0x4;
+ c->latch[5] = 0x1 | 0x4;
+ c->latch[6] = 0x2 | 0x4;
+ c->latch[7] = 0x3 | 0x4;
+ }
+ gain_recalc(which);
+}
+
+
+void MB87078_data_w(int which, int data, int dsel)
+{
+ struct MB87078 *c = chip + which;
+
+ if (c->reset_comp==0) return;
+
+ if (dsel==0)
+ {/*gd0-gd5*/
+ c->latch[0+c->channel_latch] = data & 0x3f;
+ }
+ else
+ {/*dcs1,dsc2,en,c0,c32,X*/
+ c->channel_latch = data & 3;
+ c->latch[4+c->channel_latch] = data & 0x1f; //always zero bit 5
+ }
+ gain_recalc(which);
+}
+
+
+float MB87078_gain_decibel_r(int which, int channel)
+{
+ return MB87078_gain_decibel[ chip[which].gain[channel] ];
+}
+
+
+int MB87078_gain_percent_r(int which, int channel)
+{
+ return MB87078_gain_percent[ chip[which].gain[channel] ];
+}
+
diff --git a/src/emu/machine/mb87078.h b/src/emu/machine/mb87078.h
new file mode 100644
index 00000000000..03b16c5f63d
--- /dev/null
+++ b/src/emu/machine/mb87078.h
@@ -0,0 +1,103 @@
+/*****************************************************************************
+
+ MB87078 6-bit,4-channel electronic volume controller emulator
+
+ An excerpt from the datasheet about the chip functionality:
+ "A digital signal input controls gain every 0.5 dB step from 0dB to -32dB.
+ - Gain variable range: 0 dB to -32 dB by 0.5dB or -infinity
+ - Gain variable range is expanded to connect two channels serially (0 dB to -64 dB)
+ - Each channel gain can be set respectively
+ - Test function is provided (to confirm internal data)
+ - Data is initialized by reset signal (all channels are set to 0dB)
+ - Logic I/O is TTL comatible"
+
+ There are 6 digital data input/output pins and DSEL pin that selects
+ the group (there are two) of internal registers to be read/written.
+
+ Group 0 is 6-bit gain latch
+ Group 1 is 5-bit control latch (2-bits are channel select and 3-bits are volume control)
+
+ Digital I/O Setting:
+ /TC DSEL D0 D1 D2 D3 D4 D5 I/O MODES (when /TC==H ->write)
+ H H DSC1 DSC2 EN C0 C32 X Input mode
+ H L GD0 GD1 GD2 GD3 GD4 GD5 (set)
+ L H DSC1 DSC2 EN C0 C32 L Output mode
+ L L GD0 GD1 GD2 GD3 GD4 GD5 (check)
+
+ Channel Setting:
+ DSC2 DSC1 CHANNEL
+ L L 0
+ L H 1
+ H L 2
+ H H 3
+
+ Electrical Volume Setting:
+ DATA* GAIN
+ GD5 GD4 GD3 GD2 GD1 GD0 EN C0 C32 (dB)
+ 1 1 1 1 1 1 1 0 0 0
+ 1 1 1 1 1 0 1 0 0 -0.5
+ 1 1 1 1 0 1 1 0 0 -1
+ 1 1 1 1 0 0 1 0 0 -1.5
+ 1 1 1 0 1 1 1 0 0 -2
+ [..........................................]
+ 0 0 0 0 0 1 1 0 0 -31
+ 0 0 0 0 0 0 1 0 0 -31.5
+ X X X X X X 1 X 1 -32
+ X X X X X X 1 1 0 0
+ X X X X X X 0 X X -infinity
+
+ X=don't care
+ * When reset, DATA is set to 0 dB (code 111111 100)
+
+
+ MB87078 pins and assigned interface variables/functions
+
+ /[ 1] D0 /TC [24]
+ | [ 2] D1 /WR [23]
+ MB87078_data_w()| [ 3] D2 /CE [22]
+ MB87078_data_r()| [ 4] D3 DSEL [21]-MB87078_data_w()/data_r() parameter
+ | [ 5] D4 /RESET [20]-MB87078_reset_comp_w()
+ \[ 6] D5 /PD [19]
+ [ 7] DGND VDD [18]
+ [ 8] AGND 1/2 VDD [17]
+ [ 9] AIN0 AOUT3 [16]
+ [10] AOUT0 AIN3 [15]
+ [11] AIN1 AOUT2 [14]
+ [12] AOUT1 AIN2 [13]
+
+*****************************************************************************/
+
+#ifndef MB87078_H
+#define MB87078_H
+
+#define MAX_MB87078 4
+
+/* The interface structure */
+struct MB87078interface {
+ void (*gain_changed_cb)(int channel, int percent /*, float decibels*/);
+};
+
+
+void MB87078_stop(void);
+void MB87078_start(int which, const struct MB87078interface *intf);
+
+void MB87078_data_w(int which, int data, int dsel);
+void MB87078_reset_comp_w(int which, int level);
+
+
+/* MB87078_gain_decibel_r will return 'channel' gain on chip 'which'.
+ Returned value represnts channel gain expressed in decibels,
+ Range from 0 to -32.0 (or -256.0 for -infinity)
+*/
+float MB87078_gain_decibel_r(int which, int channel);
+
+
+/* MB87078_gain_percent_r will return 'channel' gain on chip 'which'.
+ Returned value represents channel gain expressed in percents of maximum volume.
+ Range from 100 to 0. (100 = 0dB; 50 = -6dB; 0 = -infinity)
+
+ This function is designed for use with MAME mixer_xxx() functions.
+*/
+int MB87078_gain_percent_r(int which, int channel);
+
+#endif
diff --git a/src/emu/machine/mc146818.c b/src/emu/machine/mc146818.c
new file mode 100644
index 00000000000..eaf2cc98773
--- /dev/null
+++ b/src/emu/machine/mc146818.c
@@ -0,0 +1,392 @@
+/*********************************************************************
+
+ mc146818.c
+
+ Implementation of the MC146818 chip
+
+ Real time clock chip with battery buffered ram (or CMOS)
+ Used in IBM PC/AT, several PC clones, Amstrad NC200
+
+ Nathan Woods (npwoods@mess.org)
+ Peter Trauner (peter.trauner@jk.uni-linz.ac.at)
+
+ PC CMOS info (based on info from Padgett Peterson):
+
+ Clock Related:
+ 0x00 Seconds (BCD 00-59, Hex 00-3B) Note: Bit 7 is read only
+ 0x01 Second Alarm (BCD 00-59, Hex 00-3B; "don't care" if C0-FF)
+ 0x02 Minutes (BCD 00-59, Hex 00-3B)
+ 0x03 Minute Alarm (BCD 00-59, Hex 00-3B; "don't care" if C0-FF))
+ 0x04 Hours (BCD 00-23, Hex 00-17 if 24 hr mode)
+ (BCD 01-12, Hex 01-0C if 12 hr am)
+ (BCD 81-92. Hex 81-8C if 12 hr pm)
+ 0x05 Hour Alarm (same as hours; "don't care" if C0-FF))
+ 0x06 Day of Week (01-07 Sunday=1)
+ 0x07 Date of Month (BCD 01-31, Hex 01-1F)
+ 0x08 Month (BCD 01-12, Hex 01-0C)
+ 0x09 Year (BCD 00-99, Hex 00-63)
+ 0x0B Status Register B (read/write)
+ Bit 7 - 1 enables cycle update, 0 disables
+ Bit 6 - 1 enables periodic interrupt
+ Bit 5 - 1 enables alarm interrupt
+ Bit 4 - 1 enables update-ended interrupt
+ Bit 3 - 1 enables square wave output
+ Bit 2 - Data Mode - 0: BCD, 1: Binary
+ Bit 1 - 24/12 hour selection - 1 enables 24 hour mode
+ Bit 0 - Daylight Savings Enable - 1 enables
+ 0x0C Status Register C (Read only)
+ Bit 7 - Interrupt request flag - 1 when any or all of bits 6-4 are
+ 1 and appropriate enables (Register B) are set to 1. Generates
+ IRQ 8 when triggered.
+ Bit 6 - Periodic Interrupt flag
+ Bit 5 - Alarm Interrupt flag
+ Bit 4 - Update-Ended Interrupt Flag
+ Bit 3-0 ???
+ 0x0D Status Register D (read only)
+ Bit 7 - Valid RAM - 1 indicates batery power good, 0 if dead or
+ disconnected.
+ Bit 6-0 ???
+
+ Non-clock related:
+ 0x0E (PS/2) Diagnostic Status Byte
+ Bit 7 - When set (1) indicates clock has lost power
+ Bit 6 - (1) indicates incorrect checksum
+ Bit 5 - (1) indicates that equipment configuration is incorrect
+ power-on check requires that atleast one floppy be installed
+ Bit 4 - (1) indicates error in memory size
+ Bit 3 - (1) indicates that controller or disk drive failed initialization
+ Bit 2 - (1) indicates that time is invalid
+ Bit 1 - (1) indicates installed adaptors do not match configuration
+ Bit 0 - (1) indicates a time-out while reading adaptor ID
+ 0x0E (AMSTRAD) 6 BYTEs time and date machine last used
+ 0x0F Reset Code (IBM PS/2 "Shutdown Status Byte")
+ 0x00-0x03 perform power-on reset
+ 0x04 INT 19h reboot
+ 0x05 flush keyboard and jump via 0040:0067
+ 0x06-0x07 reserved
+ 0x08 used by POST during protected-mode RAM test
+ 0x09 used for INT 15/87h (block move) support
+ 0x0A jump via 0040:0067
+ 0x0B-0xFF perform power-on reset
+
+*********************************************************************/
+
+#include "driver.h"
+#include "memconv.h"
+#include "machine/mc146818.h"
+
+
+
+#define LOG_MC146818 0
+#define MC146818_DATA_SIZE 0x80
+
+struct mc146818_chip
+{
+ MC146818_TYPE type;
+
+ UINT8 index;
+ UINT8 data[MC146818_DATA_SIZE];
+
+ UINT16 eindex;
+ UINT8 edata[0x2000];
+
+ attotime last_refresh;
+};
+
+static struct mc146818_chip *mc146818;
+
+
+
+#define HOURS_24 (mc146818->data[0xb]&2)
+#define BCD_MODE !(mc146818->data[0xb]&4) // book has other description!
+#define CENTURY mc146818->data[50]
+#define YEAR mc146818->data[9]
+#define MONTH mc146818->data[8]
+#define DAY mc146818->data[7]
+#define WEEK_DAY mc146818->data[6]
+
+
+
+static void mc146818_set_base_datetime(void);
+
+static TIMER_CALLBACK( mc146818_timer )
+{
+ int year, month;
+
+ if (BCD_MODE)
+ {
+ mc146818->data[0]=bcd_adjust(mc146818->data[0]+1);
+ if (mc146818->data[0]>=0x60)
+ {
+ mc146818->data[0]=0;
+ mc146818->data[2]=bcd_adjust(mc146818->data[2]+1);
+ if (mc146818->data[2]>=0x60)
+ {
+ mc146818->data[2]=0;
+ mc146818->data[4]=bcd_adjust(mc146818->data[4]+1);
+ // different handling of hours
+ if (mc146818->data[4]>=0x24)
+ {
+ mc146818->data[4]=0;
+ WEEK_DAY=bcd_adjust(WEEK_DAY+1)%7;
+ DAY=bcd_adjust(DAY+1);
+ month=bcd_2_dec(MONTH);
+ year=bcd_2_dec(YEAR);
+ if (mc146818->type!=MC146818_IGNORE_CENTURY) year+=bcd_2_dec(CENTURY)*100;
+ else year+=2000; // save for julian_days_in_month calculation
+ DAY=bcd_adjust(DAY+1);
+ if (DAY>gregorian_days_in_month(MONTH, year))
+ {
+ DAY=1;
+ MONTH=bcd_adjust(MONTH+1);
+ if (MONTH>0x12)
+ {
+ MONTH=1;
+ YEAR=year=bcd_adjust(YEAR+1);
+ if (mc146818->type!=MC146818_IGNORE_CENTURY)
+ {
+ if (year>=0x100)
+ {
+ CENTURY=bcd_adjust(CENTURY+1);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ mc146818->data[0]=mc146818->data[0]+1;
+ if (mc146818->data[0]>=60)
+ {
+ mc146818->data[0]=0;
+ mc146818->data[2]=mc146818->data[2]+1;
+ if (mc146818->data[2]>=60) {
+ mc146818->data[2]=0;
+ mc146818->data[4]=mc146818->data[4]+1;
+ // different handling of hours //?
+ if (mc146818->data[4]>=24) {
+ mc146818->data[4]=0;
+ WEEK_DAY=(WEEK_DAY+1)%7;
+ year=YEAR;
+ if (mc146818->type!=MC146818_IGNORE_CENTURY) year+=CENTURY*100;
+ else year+=2000; // save for julian_days_in_month calculation
+ if (++DAY>gregorian_days_in_month(MONTH, year)) {
+ DAY=1;
+ if (++MONTH>12) {
+ MONTH=1;
+ YEAR++;
+ if (mc146818->type!=MC146818_IGNORE_CENTURY) {
+ if (YEAR>=100) { CENTURY++;YEAR=0; }
+ } else {
+ YEAR%=100;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ mc146818->last_refresh = timer_get_time();
+}
+
+
+
+void mc146818_init(MC146818_TYPE type)
+{
+ mc146818 = auto_malloc(sizeof(*mc146818));
+ memset(mc146818, 0, sizeof(*mc146818));
+ mc146818->type = type;
+ mc146818->last_refresh = timer_get_time();
+ timer_pulse(ATTOTIME_IN_HZ(1), 0, mc146818_timer);
+ mc146818_set_base_datetime();
+}
+
+
+
+void mc146818_load(void)
+{
+ mame_file *file;
+
+ file = nvram_fopen(Machine, OPEN_FLAG_READ);
+ if (file)
+ {
+ mc146818_load_stream(file);
+ mame_fclose(file);
+ }
+}
+
+
+
+void mc146818_load_stream(mame_file *file)
+{
+ mame_fread(file, mc146818->data, sizeof(mc146818->data));
+}
+
+
+
+static int dec_2_local(int a)
+{
+ return BCD_MODE ? dec_2_bcd(a) : a;
+}
+
+
+
+static void mc146818_set_base_datetime(void)
+{
+ mame_system_time systime;
+
+ mame_get_base_datetime(Machine, &systime);
+
+ if (HOURS_24 || (systime.local_time.hour < 12))
+ mc146818->data[4] = dec_2_local(systime.local_time.hour);
+ else
+ mc146818->data[4] = dec_2_local(systime.local_time.hour - 12) | 0x80;
+
+ if (mc146818->type != MC146818_IGNORE_CENTURY)
+ CENTURY = dec_2_local(systime.local_time.year /100);
+
+ mc146818->data[0] = dec_2_local(systime.local_time.second);
+ mc146818->data[2] = dec_2_local(systime.local_time.minute);
+ DAY = dec_2_local(systime.local_time.day);
+ MONTH = dec_2_local(systime.local_time.month + 1);
+ YEAR = dec_2_local(systime.local_time.year % 100);
+
+ WEEK_DAY = systime.local_time.weekday;
+ if (systime.local_time.is_dst)
+ mc146818->data[0xb] |= 1;
+ else
+ mc146818->data[0xb] &= ~1;
+}
+
+
+
+void mc146818_save(void)
+{
+ mame_file *file;
+
+ file = nvram_fopen(Machine, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ if (file)
+ {
+ mame_fwrite(file, mc146818->data, sizeof(mc146818->data));
+ mame_fclose(file);
+ }
+}
+
+
+
+void mc146818_save_stream(mame_file *file)
+{
+ mame_fwrite(file, mc146818->data, sizeof(mc146818->data));
+}
+
+
+
+NVRAM_HANDLER( mc146818 )
+{
+ if (file == NULL)
+ {
+ mc146818_set_base_datetime();
+ // init only
+ }
+ else if (read_or_write)
+ {
+ mc146818_save_stream(file);
+ }
+ else
+ {
+ mc146818_load_stream(file);
+ }
+}
+
+
+
+READ8_HANDLER(mc146818_port_r)
+{
+ UINT8 data = 0;
+ switch (offset) {
+ case 0:
+ data = mc146818->index;
+ break;
+
+ case 1:
+ switch (mc146818->index % MC146818_DATA_SIZE) {
+ case 0xa:
+ data = mc146818->data[mc146818->index % MC146818_DATA_SIZE];
+ if (attotime_compare(attotime_sub(timer_get_time(), mc146818->last_refresh), ATTOTIME_IN_HZ(32768)) < 0)
+ data |= 0x80;
+#if 0
+ /* for pc1512 bios realtime clock test */
+ mc146818->data[mc146818->index % MC146818_DATA_SIZE] ^= 0x80; /* 0x80 update in progress */
+#endif
+ break;
+
+ case 0xd:
+ /* battery ok */
+ data = mc146818->data[mc146818->index % MC146818_DATA_SIZE] | 0x80;
+ break;
+
+ default:
+ data = mc146818->data[mc146818->index % MC146818_DATA_SIZE];
+ break;
+ }
+ break;
+ }
+
+ if (LOG_MC146818)
+ logerror("mc146818_port_r(): index=0x%02x data=0x%02x\n", mc146818->index, data);
+ return data;
+}
+
+
+
+WRITE8_HANDLER(mc146818_port_w)
+{
+ if (LOG_MC146818)
+ logerror("mc146818_port_w(): index=0x%02x data=0x%02x\n", mc146818->index, data);
+
+ switch (offset) {
+ case 0:
+ mc146818->index = data;
+ break;
+
+ case 1:
+ mc146818->data[mc146818->index % MC146818_DATA_SIZE] = data;
+ break;
+ }
+}
+
+
+
+READ16_HANDLER(mc146818_port16le_r)
+{
+ return read16le_with_read8_handler(mc146818_port_r, offset, mem_mask);
+}
+
+WRITE16_HANDLER(mc146818_port16le_w)
+{
+ write16le_with_write8_handler(mc146818_port_w, offset, data, mem_mask);
+}
+
+READ32_HANDLER(mc146818_port32le_r)
+{
+ return read32le_with_read8_handler(mc146818_port_r, offset, mem_mask);
+}
+
+WRITE32_HANDLER(mc146818_port32le_w)
+{
+ write32le_with_write8_handler(mc146818_port_w, offset, data, mem_mask);
+}
+
+READ64_HANDLER(mc146818_port64be_r)
+{
+ return read64be_with_read8_handler(mc146818_port_r, offset, mem_mask);
+}
+
+WRITE64_HANDLER(mc146818_port64be_w)
+{
+ write64be_with_write8_handler(mc146818_port_w, offset, data, mem_mask);
+}
diff --git a/src/emu/machine/mc146818.h b/src/emu/machine/mc146818.h
new file mode 100644
index 00000000000..0f83135571b
--- /dev/null
+++ b/src/emu/machine/mc146818.h
@@ -0,0 +1,55 @@
+/*********************************************************************
+
+ mc146818.h
+
+ Implementation of the MC146818 chip
+
+ Real time clock chip with batteru buffered ram
+ Used in IBM PC/AT, several PC clones, Amstrad NC200
+
+ Peter Trauner (peter.trauner@jk.uni-linz.ac.at)
+
+*********************************************************************/
+
+#ifndef MC146818_H
+#define MC146818_H
+
+typedef enum
+{
+ MC146818_STANDARD,
+ MC146818_IGNORE_CENTURY, // century is NOT set, for systems having other usage of this byte
+ MC146818_ENHANCED
+} MC146818_TYPE;
+
+
+
+/* initialize mc146818 emulation, call only once at beginning */
+void mc146818_init(MC146818_TYPE type);
+
+/* loads data from standard nvram file */
+void mc146818_load(void);
+
+/* loads data from file stream */
+void mc146818_load_stream(mame_file *file);
+
+/* saves data into standard nvram file */
+void mc146818_save(void);
+
+/* saves data into file stream */
+void mc146818_save_stream(mame_file *file);
+
+NVRAM_HANDLER( mc146818 );
+
+READ8_HANDLER(mc146818_port_r);
+WRITE8_HANDLER(mc146818_port_w);
+
+READ16_HANDLER(mc146818_port16le_r);
+WRITE16_HANDLER(mc146818_port16le_w);
+
+READ32_HANDLER(mc146818_port32le_r);
+WRITE32_HANDLER(mc146818_port32le_w);
+
+READ64_HANDLER(mc146818_port64be_r);
+WRITE64_HANDLER(mc146818_port64be_w);
+
+#endif /* MC146818_H */
diff --git a/src/emu/machine/msm6242.c b/src/emu/machine/msm6242.c
new file mode 100644
index 00000000000..e367e0775af
--- /dev/null
+++ b/src/emu/machine/msm6242.c
@@ -0,0 +1,139 @@
+/***************************************************************************
+
+ MSM6242 Real Time Clock
+
+***************************************************************************/
+
+#include "driver.h"
+#include "machine/msm6242.h"
+
+static UINT8 msm6264_reg[3] = { 0, 0, 0 };
+static mame_system_time msm6264_hold_time = { 0 };
+
+enum
+{
+ MSM6264_REG_S1 = 0,
+ MSM6264_REG_S10,
+ MSM6264_REG_MI1,
+ MSM6264_REG_MI10,
+ MSM6264_REG_H1,
+ MSM6264_REG_H10,
+ MSM6264_REG_D1,
+ MSM6264_REG_D10,
+ MSM6264_REG_MO1,
+ MSM6264_REG_MO10,
+ MSM6264_REG_Y1,
+ MSM6264_REG_Y10,
+ MSM6264_REG_W,
+ MSM6264_REG_CD,
+ MSM6264_REG_CE,
+ MSM6264_REG_CF
+};
+
+READ8_HANDLER( msm6242_r )
+{
+ mame_system_time curtime, *systime = &curtime;
+
+ if ( msm6264_reg[0] & 1 ) /* if HOLD is set, use the hold time */
+ {
+ systime = &msm6264_hold_time;
+ }
+ else /* otherwise, use the current time */
+ {
+ mame_get_current_datetime(Machine, &curtime);
+ }
+
+ switch(offset)
+ {
+ case MSM6264_REG_S1: return systime->local_time.second % 10;
+ case MSM6264_REG_S10: return systime->local_time.second / 10;
+ case MSM6264_REG_MI1: return systime->local_time.minute % 10;
+ case MSM6264_REG_MI10: return systime->local_time.minute / 10;
+ case MSM6264_REG_H1:
+ case MSM6264_REG_H10:
+ {
+ /* check for 12/24 hour mode */
+ if ( (msm6264_reg[2] & 0x04) == 0 ) /* 12 hour mode? */
+ {
+ int hour = systime->local_time.hour;
+ int pm = (hour >= 12) ? 1 : 0;
+
+ if ( pm ) hour -= 12;
+ if ( hour == 0 ) hour = 12;
+
+ if ( offset == MSM6264_REG_H1 )
+ return hour % 10;
+
+ return (hour / 10) | (pm << 2);
+ }
+
+ if ( offset == MSM6264_REG_H1 )
+ return systime->local_time.hour % 10;
+
+ return systime->local_time.hour / 10;
+ }
+
+ case MSM6264_REG_D1: return systime->local_time.mday % 10;
+ case MSM6264_REG_D10: return systime->local_time.mday / 10;
+ case MSM6264_REG_MO1: return (systime->local_time.month+1) % 10;
+ case MSM6264_REG_MO10: return (systime->local_time.month+1) / 10;
+ case MSM6264_REG_Y1: return (systime->local_time.year - 1900) % 10;
+ case MSM6264_REG_Y10: return (systime->local_time.year - 1900) / 10;
+ case MSM6264_REG_W: return systime->local_time.weekday;
+ case MSM6264_REG_CD: return msm6264_reg[0];
+ case MSM6264_REG_CE: return msm6264_reg[1];
+ case MSM6264_REG_CF: return msm6264_reg[2];
+ }
+
+ logerror("%04x: MSM6242 unmapped offset %02X read\n",activecpu_get_pc(),offset);
+ return 0;
+}
+
+WRITE8_HANDLER( msm6242_w )
+{
+ switch(offset)
+ {
+ case MSM6264_REG_CD:
+ {
+ msm6264_reg[0] = data;
+
+ if ( data & 1 ) /* was Hold set? */
+ {
+ mame_get_current_datetime(Machine, &msm6264_hold_time);
+ }
+
+ return;
+ }
+
+ case MSM6264_REG_CE: msm6264_reg[1] = data; return;
+
+ case MSM6264_REG_CF:
+ {
+ /* the 12/24 mode bit can only be changed while REST is 1 */
+ if ( (data ^ msm6264_reg[2]) & 0x04 )
+ {
+ if ( msm6264_reg[2] & 1 )
+ msm6264_reg[2] = data;
+ }
+ else
+ {
+ msm6264_reg[2] = data;
+ }
+ return;
+ }
+ }
+
+ logerror("%04x: MSM6242 unmapped offset %02X written with %02X\n",activecpu_get_pc(),offset,data);
+}
+
+
+READ16_HANDLER( msm6242_lsb_r )
+{
+ return msm6242_r(offset);
+}
+
+WRITE16_HANDLER( msm6242_lsb_w )
+{
+ if (ACCESSING_LSB)
+ msm6242_w(offset,data);
+}
diff --git a/src/emu/machine/msm6242.h b/src/emu/machine/msm6242.h
new file mode 100644
index 00000000000..c0b817f5d73
--- /dev/null
+++ b/src/emu/machine/msm6242.h
@@ -0,0 +1,10 @@
+#ifndef MSM6242_INCLUDE
+#define MSM6242_INCLUDE
+
+READ8_HANDLER( msm6242_r );
+WRITE8_HANDLER( msm6242_w );
+
+READ16_HANDLER( msm6242_lsb_r );
+WRITE16_HANDLER( msm6242_lsb_w );
+
+#endif
diff --git a/src/emu/machine/pc16552d.c b/src/emu/machine/pc16552d.c
new file mode 100644
index 00000000000..85159a51b69
--- /dev/null
+++ b/src/emu/machine/pc16552d.c
@@ -0,0 +1,433 @@
+/*
+ National Semiconductor PC16552D
+ Dual Universal Asynchronous Receiver/Transmitter with FIFOs
+
+ Written by Ville Linde
+*/
+
+#include "driver.h"
+#include "pc16552d.h"
+
+#define REG_RECV_BUFFER 0x0 // Read
+#define REG_XMIT_HOLD 0x0 // Write
+#define REG_INT_ENABLE 0x1
+#define REG_FIFO_CTRL 0x2 // Write
+#define REG_LINE_CTRL 0x3
+#define REG_MODEL_CTRL 0x4
+#define REG_LINE_STATUS 0x5
+#define REG_MODEM_STATUS 0x6
+#define REG_SCRATCH 0x7
+#define REG_DIV_LATCH_LSB 0x0 // When DLAB == 1
+#define REG_DIV_LATCH_MSB 0x1 // When DLAB == 1
+#define REG_ALT_FUNCTION 0x2 // When DLAB == 1
+
+#define LINE_CTRL_DLAB 0x80
+
+#define IRQ_RX_LINE_STATUS 0x1
+#define IRQ_RX_DATA_AVAILABLE 0x2
+#define IRQ_CHARACTER_TIMEOUT 0x4
+#define IRQ_TX_HOLDING_REG_EMPTY 0x8
+#define IRQ_MODEM_STATUS 0x10
+
+#define INT_ENABLE_RX_DATA 0x01
+#define INT_ENABLE_TX_EMPTY 0x02
+#define INT_ENABLE_RX_LINE_STATUS 0x04
+#define INT_ENABLE_MODEM_STATUS 0x08
+
+typedef struct
+{
+ UINT16 divisor;
+ UINT8 reg[8];
+ UINT8 rx_fifo[16];
+ UINT8 tx_fifo[16];
+ int pending_interrupt;
+ int rx_fifo_read_ptr;
+ int rx_fifo_write_ptr;
+ int rx_fifo_num;
+ int tx_fifo_read_ptr;
+ int tx_fifo_write_ptr;
+ int tx_fifo_num;
+ emu_timer *tx_fifo_timer;
+} PC16552D_CHANNEL;
+
+typedef struct
+{
+ PC16552D_CHANNEL ch[2];
+ int frequency;
+ void (* irq_handler)(int channel, int value);
+} PC16552D_REGS;
+
+#define MAX_PC16552D_CHIPS 4
+
+static PC16552D_REGS duart[MAX_PC16552D_CHIPS];
+
+
+
+static const int rx_trigger_level[4] = { 1, 4, 8, 14 };
+
+
+static void check_interrupts(int chip, int channel)
+{
+ PC16552D_CHANNEL *ch = &duart[chip].ch[channel];
+
+ if (ch->pending_interrupt != 0)
+ {
+ if (((ch->reg[REG_INT_ENABLE] & INT_ENABLE_RX_DATA) && (ch->pending_interrupt & IRQ_RX_DATA_AVAILABLE)) ||
+ ((ch->reg[REG_INT_ENABLE] & INT_ENABLE_TX_EMPTY) && (ch->pending_interrupt & IRQ_TX_HOLDING_REG_EMPTY)) ||
+ ((ch->reg[REG_INT_ENABLE] & INT_ENABLE_RX_LINE_STATUS) && (ch->pending_interrupt & IRQ_RX_LINE_STATUS)) ||
+ ((ch->reg[REG_INT_ENABLE] & INT_ENABLE_MODEM_STATUS) && (ch->pending_interrupt & IRQ_MODEM_STATUS)))
+ {
+ if (duart[chip].irq_handler != NULL)
+ {
+ duart[chip].irq_handler(channel, 0);
+ }
+ }
+ }
+}
+
+static void duart_push_rx_fifo(int chip, int channel, UINT8 data)
+{
+ PC16552D_CHANNEL *ch = &duart[chip].ch[channel];
+
+ if (ch->rx_fifo_num >= 16)
+ {
+ printf("duart_push_rx_fifo: %d, %d, %02X, FIFO overflow\n", chip, channel, data);
+ return;
+ }
+
+ ch->rx_fifo[ch->rx_fifo_write_ptr++] = data;
+ if (ch->rx_fifo_write_ptr == 16)
+ {
+ ch->rx_fifo_write_ptr = 0;
+ }
+ ch->rx_fifo_num++;
+
+ if (ch->rx_fifo_num == rx_trigger_level[(ch->reg[REG_FIFO_CTRL] >> 6) & 3])
+ {
+ ch->pending_interrupt |= IRQ_RX_DATA_AVAILABLE; // INT ID: received data available
+
+ check_interrupts(chip, channel);
+ }
+}
+
+static UINT8 duart_pop_rx_fifo(int chip, int channel)
+{
+ UINT8 r;
+ PC16552D_CHANNEL *ch = &duart[chip].ch[channel];
+
+ if (ch->rx_fifo_num == 0)
+ {
+ printf("duart_pop_rx_fifo: %d, %d, FIFO underflow\n", chip, channel);
+ return 0;
+ }
+
+ r = ch->rx_fifo[ch->rx_fifo_read_ptr++];
+ if (ch->rx_fifo_read_ptr == 16)
+ {
+ ch->rx_fifo_read_ptr = 0;
+ }
+ ch->rx_fifo_num--;
+
+ if (ch->rx_fifo_num < rx_trigger_level[(ch->reg[REG_FIFO_CTRL] >> 6) & 3])
+ {
+ ch->pending_interrupt &= ~IRQ_RX_DATA_AVAILABLE;
+
+ check_interrupts(chip, channel);
+ }
+
+ return r;
+}
+
+static TIMER_CALLBACK( tx_fifo_timer_callback )
+{
+ PC16552D_CHANNEL *ch;
+ int chip = param >> 1;
+ int channel = param & 1;
+
+ ch = &duart[chip].ch[channel];
+
+ ch->tx_fifo_num = 0;
+
+ // set transmitter empty interrupt
+ ch->pending_interrupt |= IRQ_TX_HOLDING_REG_EMPTY;
+ check_interrupts(chip, channel);
+
+ timer_adjust(duart[chip].ch[channel].tx_fifo_timer, attotime_never, (chip * 2) + channel, attotime_never);
+}
+
+static void duart_push_tx_fifo(int chip, int channel, UINT8 data)
+{
+ attotime period;
+ PC16552D_CHANNEL *ch = &duart[chip].ch[channel];
+
+ ch->tx_fifo_num++;
+
+ period = attotime_mul(ATTOTIME_IN_HZ(duart[chip].frequency), ch->divisor * 16 * 16 * 8);
+
+ timer_adjust(duart[chip].ch[channel].tx_fifo_timer, period, (chip * 2) + channel, attotime_zero);
+}
+
+#ifdef UNUSED_FUNCTION
+static UINT8 duart_pop_tx_fifo(int chip, int channel, UINT8 data)
+{
+ return 0;
+}
+#endif
+
+
+static UINT8 duart_r(int chip, int reg)
+{
+ int channel = (reg >> 3) & 1;
+ PC16552D_CHANNEL *ch = &duart[chip].ch[channel];
+ reg &= 7;
+
+// printf("duart_r: chip %d, ch %d, reg %d\n", chip, channel, reg);
+
+ switch (reg)
+ {
+ case 0:
+ {
+ if (ch->reg[REG_LINE_CTRL] & LINE_CTRL_DLAB)
+ {
+ // Divisor Latch (LSB)
+ return ch->divisor & 0xff;
+ }
+ else
+ {
+ // Receiver Buffer
+ ch->pending_interrupt &= ~IRQ_RX_DATA_AVAILABLE;
+
+ check_interrupts(chip, channel);
+
+ return duart_pop_rx_fifo(chip, channel);
+ }
+ break;
+ }
+ case 1:
+ {
+ if (ch->reg[REG_LINE_CTRL] & LINE_CTRL_DLAB)
+ {
+ // Divisor Latch (MSB)
+ return (ch->divisor >> 8) & 0xff;
+ }
+ else
+ {
+
+ }
+ break;
+ }
+
+ case 2:
+ {
+ if (ch->reg[REG_LINE_CTRL] & LINE_CTRL_DLAB)
+ {
+ // Alternate Function
+ }
+ else
+ {
+ // Interrupt Identification Register
+ int i;
+ UINT8 r = 0x01;
+
+ for (i=0; i < 5; i++)
+ {
+ if (ch->pending_interrupt & (1 << i))
+ {
+ switch (i)
+ {
+ case 0: r = 0x06; break; // Receiver Line Status
+ case 1: r = 0x04; break; // Received Data Available
+ case 2: r = 0x0c; break; // Character Timeout Indication
+ case 3: r = 0x02; break; // Transmitter Holding Register Empty
+ case 4: r = 0x00; break; // MODEM Status
+ }
+ break;
+ }
+ }
+
+ if (ch->reg[REG_FIFO_CTRL] & 1)
+ {
+ r |= 0xc0;
+ }
+
+ return r;
+ }
+ break;
+ }
+
+ case 5: // Line Status Register
+ {
+ UINT8 r = 0;
+
+ // set Data Ready flag
+ if (ch->rx_fifo_num > 0)
+ {
+ r |= 0x1;
+ }
+
+ // set Transmitter Holding Register Empty flag
+ if (ch->tx_fifo_num == 0)
+ {
+ r |= 0x20;
+ }
+
+ // set Transmitter Empty flag
+ if (ch->tx_fifo_num == 0)
+ {
+ r |= 0x40;
+ }
+
+ return r;
+ }
+ }
+
+ return ch->reg[reg];
+}
+
+static void duart_w(int chip, int reg, UINT8 data)
+{
+ int channel = (reg >> 3) & 1;
+ PC16552D_CHANNEL *ch = &duart[chip].ch[channel];
+ reg &= 7;
+
+// printf("duart_w: chip %d, ch %d, reg %d, data %02X\n", chip, channel, reg, data);
+
+ switch (reg)
+ {
+ case 0:
+ {
+ if (ch->reg[REG_LINE_CTRL] & LINE_CTRL_DLAB)
+ {
+ // Divisor Latch (LSB)
+ ch->divisor &= 0xff00;
+ ch->divisor |= data;
+
+ return;
+ }
+ else
+ {
+ // Transmitter Holding Register
+ duart_push_tx_fifo(chip, channel, data);
+
+ ch->pending_interrupt &= ~IRQ_TX_HOLDING_REG_EMPTY;
+ check_interrupts(chip, channel);
+
+ return;
+ }
+ break;
+ }
+ case 1:
+ {
+ if (ch->reg[REG_LINE_CTRL] & LINE_CTRL_DLAB)
+ {
+ // Divisor Latch (MSB)
+ ch->divisor &= 0x00ff;
+ ch->divisor |= data << 8;
+
+ // printf("DUART %d %d bps\n", chip, duart[chip].frequency / (ch->divisor * 16));
+ return;
+ }
+ else
+ {
+ // Interrupt enable
+ ch->reg[REG_INT_ENABLE] = data;
+
+ check_interrupts(chip, channel);
+ return;
+ }
+ break;
+ }
+
+ case 2:
+ {
+ if (ch->reg[REG_LINE_CTRL] & LINE_CTRL_DLAB)
+ {
+ // Alternate Function
+
+ return;
+ }
+ else
+ {
+ // FIFO control
+ if (data & 0x02)
+ {
+ ch->rx_fifo_write_ptr = 0;
+ ch->rx_fifo_read_ptr = 0;
+ ch->rx_fifo_num = 0;
+ }
+ if (data & 0x04)
+ {
+ ch->tx_fifo_write_ptr = 0;
+ ch->tx_fifo_read_ptr = 0;
+ ch->tx_fifo_num = 0;
+
+
+ }
+
+ /*if (data & 0x1 && (ch->reg[reg] & 0x1) == 0)
+ {
+ // cause transmitter empty IRQ
+ ch->pending_interrupt |= IRQ_TX_HOLDING_REG_EMPTY;
+
+ check_interrupts(chip, channel);
+ }
+ */
+ }
+ break;
+ }
+ }
+
+ ch->reg[reg] = data;
+}
+
+/*****************************************************************************/
+
+void pc16552d_init(int chip, int frequency, void (* irq_handler)(int channel, int value))
+{
+ memset(&duart[chip], 0, sizeof(PC16552D_REGS));
+
+ duart[chip].frequency = frequency;
+ duart[chip].irq_handler = irq_handler;
+
+ // clear interrupts
+ duart[chip].ch[0].pending_interrupt = 0;
+ duart[chip].ch[1].pending_interrupt = 0;
+
+ // allocate transmit timers
+ duart[chip].ch[0].tx_fifo_timer = timer_alloc(tx_fifo_timer_callback);
+ timer_adjust(duart[chip].ch[0].tx_fifo_timer, attotime_never, (chip * 2) + 0, attotime_never);
+
+ duart[chip].ch[1].tx_fifo_timer = timer_alloc(tx_fifo_timer_callback);
+ timer_adjust(duart[chip].ch[1].tx_fifo_timer, attotime_never, (chip * 2) + 1, attotime_never);
+}
+
+void pc16552d_rx_data(int chip, int channel, UINT8 data)
+{
+ if (duart[chip].ch[channel].reg[REG_FIFO_CTRL] & 0x01) // RCVR & XMIT FIFO enable
+ {
+ duart_push_rx_fifo(chip, channel, data);
+ }
+}
+
+/*****************************************************************************/
+/* Read/Write handlers */
+
+READ8_HANDLER(pc16552d_0_r)
+{
+ return duart_r(0, offset);
+}
+
+WRITE8_HANDLER(pc16552d_0_w)
+{
+ duart_w(0, offset, data);
+}
+
+READ8_HANDLER(pc16552d_1_r)
+{
+ return duart_r(1, offset);
+}
+
+WRITE8_HANDLER(pc16552d_1_w)
+{
+ duart_w(1, offset, data);
+}
diff --git a/src/emu/machine/pc16552d.h b/src/emu/machine/pc16552d.h
new file mode 100644
index 00000000000..1dd30017a7f
--- /dev/null
+++ b/src/emu/machine/pc16552d.h
@@ -0,0 +1,12 @@
+#ifndef PC16552D_H
+#define PC16552D_H
+
+void pc16552d_init(int chip, int frequency, void (* irq_handler)(int channel, int value));
+void pc16552d_rx_data(int chip, int channel, UINT8 data);
+
+READ8_HANDLER(pc16552d_0_r);
+WRITE8_HANDLER(pc16552d_0_w);
+READ8_HANDLER(pc16552d_1_r);
+WRITE8_HANDLER(pc16552d_1_w);
+
+#endif
diff --git a/src/emu/machine/pci.c b/src/emu/machine/pci.c
new file mode 100644
index 00000000000..454bf8949e6
--- /dev/null
+++ b/src/emu/machine/pci.c
@@ -0,0 +1,197 @@
+/***************************************************************************
+
+ machine/pci.c
+
+ PCI bus
+
+ The PCI bus is a 32-bit bus introduced by Intel, so it is little endian
+
+ Control word:
+ bit 31: Enable bit
+ bits 30-24: Reserved
+ bits 23-16: PCI bus number
+ bits 15-11: PCI device number
+ bits 10- 8: PCI function number
+ bits 7- 0: Offset address
+
+ Standard PCI registers:
+ 0x00 2 Vendor ID
+ 0x02 2 Device ID
+ 0x04 2 PCI Command
+ 0x06 2 PCI Status
+ 0x08 1 Revision ID
+ 0x09 1 Programming Interface
+ 0x0A 1 Subclass Code
+ 0x0B 1 Class Code
+
+ Class Code/Subclass Code/Programming Interface
+ 0x00XXXX Pre-PCI 2.0 devices
+ 0x000000 Non-VGA device
+ 0x000101 VGA device
+ 0x01XXXX Storage Controller
+ 0x010000 SCSI
+ 0x0101XX IDE
+ 0x0102XX Floppy
+ 0x0103XX IPI
+ 0x0104XX RAID
+ 0x0180XX Other
+ 0x02XXXX Network Card
+ 0x020000 Ethernet
+ 0x020100 Tokenring
+ 0x020200 FDDI
+ 0x020300 ATM
+ 0x028000 Other
+ 0x03XXXX Display Controller
+ 0x030000 VGA
+ 0x030001 8514 Compatible
+ 0x030100 XGA
+ 0x038000 Other
+ 0x04XXXX Multimedia
+ 0x040000 Video
+ 0x040100 Audio
+ 0x048000 Other
+ 0x05XXXX Memory Controller
+ 0x050000 RAM
+ 0x050100 Flash
+ 0x058000 Other
+ 0x06XXXX Bridge
+ 0x060000 Host/PCI
+ 0x060100 PCI/ISA
+ 0x060200 PCI/EISA
+ 0x060300 PCI/Micro Channel
+ 0x060400 PCI/PCI
+ 0x060500 PCI/PCMCIA
+ 0x060600 PCI/NuBus
+ 0x060700 PCI/CardBus
+ 0x068000 Other
+
+ Information on PCI vendors can be found at http://www.pcidatabase.com/
+
+***************************************************************************/
+
+#include "driver.h"
+#include "memconv.h"
+#include "machine/pci.h"
+
+#define LOG_PCI 0
+
+struct pci_device_entry
+{
+ struct pci_device_entry *next;
+ int bus, device, function;
+ struct pci_device_info callbacks;
+};
+
+static struct pci_device_entry *pci_devices;
+static struct pci_device_entry *pci_current_device;
+static UINT32 pci_address;
+
+
+
+void pci_init(void)
+{
+ pci_devices = NULL;
+ pci_current_device = NULL;
+ pci_address = 0;
+}
+
+
+
+void pci_add_device(int bus, int device, const struct pci_device_info *devinfo)
+{
+ struct pci_device_entry *pfi;
+
+ pfi = (struct pci_device_entry *) auto_malloc(sizeof(*pfi));
+ pfi->next = pci_devices;
+ pfi->bus = bus;
+ pfi->device = device;
+ pfi->callbacks = *devinfo;
+
+ pci_devices = pfi;
+}
+
+
+
+READ32_HANDLER(pci_32le_r)
+{
+ UINT32 result = 0xFFFFFFFF;
+ int function, reg;
+
+ offset %= 2;
+
+ switch(offset)
+ {
+ case 0:
+ result = pci_address;
+ break;
+
+ case 1:
+ if (pci_current_device && pci_current_device->callbacks.read_callback)
+ {
+ function = (pci_address >> 8) & 0x07;
+ reg = (pci_address >> 0) & 0xFC;
+ result = pci_current_device->callbacks.read_callback(function, reg, mem_mask);
+ }
+ break;
+ }
+
+ if (LOG_PCI)
+ {
+ logerror("pci_32le_r(): CPU #%d pc=0x%08X offset=%d result=0x%08X\n",
+ cpu_getactivecpu(), (unsigned) activecpu_get_reg(REG_PC), offset, result);
+ }
+ return result;
+}
+
+
+
+WRITE32_HANDLER(pci_32le_w)
+{
+ struct pci_device_entry *pfi;
+ int bus, device, function, reg;
+
+ offset %= 2;
+
+ if (LOG_PCI)
+ {
+ logerror("pci_32le_w(): CPU #%d pc=0x%08X offset=%d data=0x%08X\n",
+ cpu_getactivecpu(), (unsigned) activecpu_get_reg(REG_PC), offset, data);
+ }
+
+ switch(offset)
+ {
+ case 0:
+ pci_address = data;
+ pfi = NULL;
+
+ /* lookup current device */
+ if (pci_address & 0x80000000)
+ {
+ bus = (pci_address >> 16) & 0xFF;
+ device = (pci_address >> 11) & 0x1F;
+
+ for (pfi = pci_devices; pfi; pfi = pfi->next)
+ {
+ if ((pfi->bus == bus) && (pfi->device == device))
+ break;
+ }
+ }
+ pci_current_device = pfi;
+ break;
+
+ case 1:
+ if (pci_current_device && pci_current_device->callbacks.write_callback)
+ {
+ function = (pci_address >> 8) & 0x07;
+ reg = (pci_address >> 0) & 0xFC;
+ pci_current_device->callbacks.write_callback(function, reg, data, mem_mask);
+ }
+ break;
+
+ }
+}
+
+
+
+READ64_HANDLER(pci_64be_r) { return read64be_with_32le_handler(pci_32le_r, offset, mem_mask); }
+WRITE64_HANDLER(pci_64be_w) { write64be_with_32le_handler(pci_32le_w, offset, data, mem_mask); }
diff --git a/src/emu/machine/pci.h b/src/emu/machine/pci.h
new file mode 100644
index 00000000000..57a00a8cbd6
--- /dev/null
+++ b/src/emu/machine/pci.h
@@ -0,0 +1,30 @@
+/***************************************************************************
+
+ machine/pci.h
+
+ PCI bus
+
+***************************************************************************/
+
+#ifndef PCI_H
+#define PCI_H
+
+struct pci_device_info
+{
+ UINT32 (*read_callback)(int function, int reg, UINT32 mem_mask);
+ void (*write_callback)(int function, int reg, UINT32 data, UINT32 mem_mask);
+};
+
+
+void pci_init(void);
+void pci_add_device(int bus, int device, const struct pci_device_info *devinfo);
+
+READ32_HANDLER(pci_32le_r);
+WRITE32_HANDLER(pci_32le_w);
+
+READ64_HANDLER(pci_64be_r);
+WRITE64_HANDLER(pci_64be_w);
+
+#endif /* PCI_H */
+
+
diff --git a/src/emu/machine/pd4990a.c b/src/emu/machine/pd4990a.c
new file mode 100644
index 00000000000..22010476975
--- /dev/null
+++ b/src/emu/machine/pd4990a.c
@@ -0,0 +1,352 @@
+/*
+ * Emulation for the NEC PD4990A.
+ *
+ * The PD4990A is a serial I/O Calendar & Clock IC used in the
+ * NEO GEO and probably a couple of other machines.
+
+
+ Completed by ElSemi.
+
+ I haven't found any schematics for this device
+ so I had to make some assumptions about how it works.
+
+ The three input bits seem to be used for a serial protocol
+
+ bit 0 - data
+ bit 1 - clock
+ bit 2 - command end (?)
+
+ the commands I've found so far are:
+
+ 0x0 - ?? sent after 2
+ 0x1 - Reset the (probable) shift register used for output
+ 0x2 - Store the contents of the shift reg to the current date
+ 0x3 - Load Shift register with current date
+
+ 0x7 - Switch test bit every frame
+ 0x8 - Switch test bit every half-second
+
+
+
+ */
+
+#include "driver.h"
+#include "machine/pd4990a.h"
+
+
+/* Set the data in the chip to Monday 09/09/73 00:00:00 */
+/* If you ever read this Leejanne, you know what I mean :-) */
+struct pd4990a_s pd4990a =
+{
+ 0x00, /* seconds BCD */
+ 0x00, /* minutes BCD */
+ 0x00, /* hours BCD */
+ 0x09, /* days BCD */
+ 9, /* month Hexadecimal form */
+ 0x73, /* year BCD */
+ 1 /* weekday BCD */
+};
+
+static UINT32 shiftlo,shifthi;
+
+static int retraces = 0; /* Assumes 60 retraces a second */
+static int testwaits= 0;
+static int maxwaits= 1; /*switch test every frame*/
+static int testbit = 0; /* Pulses a bit in order to simulate */
+ /* test output */
+static int outputbit=0;
+static int bitno=0;
+static INT8 reading=0;
+static INT8 writting=0;
+
+static int clock_line=0;
+static int command_line=0; //??
+
+#define DATA_BIT 0x1
+#define CLOCK_BIT 0x2
+#define END_BIT 0x4
+
+void pd4990a_addretrace()
+{
+ ++testwaits;
+ if(testwaits>=maxwaits)
+ {
+ testbit ^= 1;
+ testwaits=0;
+ }
+ retraces++;
+ if (retraces < 60)
+ return;
+ retraces = 0;
+ pd4990a.seconds++;
+ if ( (pd4990a.seconds & 0x0f) < 10 )
+ return;
+ pd4990a.seconds &= 0xf0;
+ pd4990a.seconds += 0x10;
+ if (pd4990a.seconds < 0x60)
+ return;
+ pd4990a.seconds = 0;
+ pd4990a.minutes++;
+ if ( (pd4990a.minutes & 0x0f) < 10 )
+ return;
+ pd4990a.minutes &= 0xf0;
+ pd4990a.minutes += 0x10;
+ if (pd4990a.minutes < 0x60)
+ return;
+ pd4990a.minutes = 0;
+ pd4990a.hours++;
+ if ( (pd4990a.hours & 0x0f) < 10 )
+ return;
+ pd4990a.hours &= 0xf0;
+ pd4990a.hours += 0x10;
+ if (pd4990a.hours < 0x24)
+ return;
+ pd4990a.hours = 0;
+ pd4990a_increment_day();
+}
+
+void pd4990a_increment_day(void)
+{
+ int real_year;
+
+ pd4990a.days++;
+ if ((pd4990a.days & 0x0f) >= 10)
+ {
+ pd4990a.days &= 0xf0;
+ pd4990a.days += 0x10;
+ }
+
+ pd4990a.weekday++;
+ if (pd4990a.weekday == 7)
+ pd4990a.weekday=0;
+
+ switch(pd4990a.month)
+ {
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ if (pd4990a.days == 0x32)
+ {
+ pd4990a.days = 1;
+ pd4990a_increment_month();
+ }
+ break;
+ case 2:
+ real_year = (pd4990a.year>>4)*10 + (pd4990a.year&0xf);
+ if ((real_year % 4) && (!(real_year % 100) || (real_year % 400)))
+ {
+ if (pd4990a.days == 0x29)
+ {
+ pd4990a.days = 1;
+ pd4990a_increment_month();
+ }
+ }
+ else
+ {
+ if (pd4990a.days == 0x30)
+ {
+ pd4990a.days = 1;
+ pd4990a_increment_month();
+ }
+ }
+ break;
+ case 4: case 6: case 9: case 11:
+ if (pd4990a.days == 0x31)
+ {
+ pd4990a.days = 1;
+ pd4990a_increment_month();
+ }
+ break;
+ }
+}
+
+void pd4990a_increment_month(void)
+{
+ pd4990a.month++;
+ if (pd4990a.month == 13)
+ {
+ pd4990a.month = 1;
+ pd4990a.year++;
+ if ( (pd4990a.year & 0x0f) >= 10 )
+ {
+ pd4990a.year &= 0xf0;
+ pd4990a.year += 0x10;
+ }
+ if (pd4990a.year == 0xA0)
+ pd4990a.year = 0;
+ }
+}
+
+READ8_HANDLER( pd4990a_testbit_r )
+{
+ return (testbit);
+}
+
+READ8_HANDLER( pd4990a_databit_r )
+{
+ return (outputbit);
+}
+
+static void pd4990a_readbit(void)
+{
+ switch(bitno)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ outputbit=(pd4990a.seconds >> bitno) & 0x01;
+ break;
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ outputbit=(pd4990a.minutes >> (bitno-0x08)) & 0x01;
+ break;
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ outputbit=(pd4990a.hours >> (bitno-0x10)) & 0x01;
+ break;
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ outputbit=(pd4990a.days >> (bitno-0x18)) & 0x01;
+ break;
+ case 0x20: case 0x21: case 0x22: case 0x23:
+ outputbit=(pd4990a.weekday >> (bitno-0x20)) & 0x01;
+ break;
+ case 0x24: case 0x25: case 0x26: case 0x27:
+ outputbit=(pd4990a.month >> (bitno-0x24)) & 0x01;
+ break;
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ outputbit=(pd4990a.year >> (bitno-0x28)) & 0x01;
+ break;
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ //unknown
+ break;
+ }
+}
+
+
+
+
+static void pd4990a_resetbitstream(void)
+{
+ shiftlo=0;
+ shifthi=0;
+ bitno=0;
+}
+
+static void pd4990a_writebit(UINT8 bit)
+{
+ if(bitno<=31) //low part
+ shiftlo|=bit<<bitno;
+ else //high part
+ shifthi|=bit<<(bitno-32);
+}
+
+static void pd4990a_nextbit(void)
+{
+ ++bitno;
+ if(reading)
+ pd4990a_readbit();
+ if(reading && bitno==0x34)
+ {
+ reading=0;
+ pd4990a_resetbitstream();
+ }
+
+}
+
+static UINT8 pd4990a_getcommand(void)
+{
+ //Warning: problems if the 4 bits are in different
+ //parts, It's very strange that this case could happen.
+ if(bitno<=31)
+ return shiftlo>>(bitno-4);
+ else
+ return shifthi>>(bitno-32-4);
+}
+
+static void pd4990a_update_date(void)
+{
+ pd4990a.seconds=(shiftlo>>0 )&0xff;
+ pd4990a.minutes=(shiftlo>>8 )&0xff;
+ pd4990a.hours =(shiftlo>>16)&0xff;
+ pd4990a.days =(shiftlo>>24)&0xff;
+ pd4990a.weekday=(shifthi>>0 )&0x0f;
+ pd4990a.month =(shifthi>>4 )&0x0f;
+ pd4990a.year =(shifthi>>8 )&0xff;
+}
+
+static void pd4990a_process_command(void)
+{
+ switch(pd4990a_getcommand())
+ {
+ case 0x1: //load output register
+ bitno=0;
+ if(reading)
+ pd4990a_readbit(); //prepare first bit
+ shiftlo=0;
+ shifthi=0;
+ break;
+ case 0x2:
+ writting=0; //store register to current date
+ pd4990a_update_date();
+ break;
+ case 0x3: //start reading
+ reading=1;
+ break;
+ case 0x7: //switch testbit every frame
+ maxwaits=1;
+ break;
+ case 0x8: //switch testbit every half-second
+ maxwaits=30;
+ break;
+ }
+ pd4990a_resetbitstream();
+}
+
+
+static void pd4990a_serial_control(UINT8 data)
+{
+ //Check for command end
+ if(command_line && !(data&END_BIT)) //end of command
+ {
+ pd4990a_process_command();
+ }
+ command_line=data&END_BIT;
+
+ if(clock_line && !(data&CLOCK_BIT)) //clock lower edge
+ {
+ pd4990a_writebit(data&DATA_BIT);
+ pd4990a_nextbit();
+ }
+ clock_line=data&CLOCK_BIT;
+}
+
+WRITE16_HANDLER( pd4990a_control_16_w )
+{
+ pd4990a_serial_control(data&0x7);
+}
+
+void pd4990a_init(void)
+{
+ state_save_register_item("pd4990a", 0, pd4990a.seconds);
+ state_save_register_item("pd4990a", 0, pd4990a.minutes);
+ state_save_register_item("pd4990a", 0, pd4990a.hours);
+ state_save_register_item("pd4990a", 0, pd4990a.days);
+ state_save_register_item("pd4990a", 0, pd4990a.month);
+ state_save_register_item("pd4990a", 0, pd4990a.year);
+ state_save_register_item("pd4990a", 0, pd4990a.weekday);
+
+ state_save_register_item("pd4990a", 0, shiftlo);
+ state_save_register_item("pd4990a", 0, shifthi);
+
+ state_save_register_item("pd4990a", 0, retraces);
+ state_save_register_item("pd4990a", 0, testwaits);
+ state_save_register_item("pd4990a", 0, maxwaits);
+ state_save_register_item("pd4990a", 0, testbit);
+
+ state_save_register_item("pd4990a", 0, outputbit);
+ state_save_register_item("pd4990a", 0, bitno);
+ state_save_register_item("pd4990a", 0, reading);
+ state_save_register_item("pd4990a", 0, writting);
+
+ state_save_register_item("pd4990a", 0, clock_line);
+ state_save_register_item("pd4990a", 0, command_line);
+}
diff --git a/src/emu/machine/pd4990a.h b/src/emu/machine/pd4990a.h
new file mode 100644
index 00000000000..10428528d6f
--- /dev/null
+++ b/src/emu/machine/pd4990a.h
@@ -0,0 +1,26 @@
+/*
+ * Header file for the PD4990A Serial I/O calendar & clock.
+ */
+
+
+struct pd4990a_s
+{
+ int seconds;
+ int minutes;
+ int hours;
+ int days;
+ int month;
+ int year;
+ int weekday;
+};
+
+extern struct pd4990a_s pd4990a;
+
+void pd4990a_addretrace (void);
+void pd4990a_init(void);
+READ8_HANDLER( pd4990a_testbit_r );
+READ8_HANDLER( pd4990a_databit_r );
+WRITE16_HANDLER( pd4990a_control_16_w );
+void pd4990a_increment_day(void);
+void pd4990a_increment_month(void);
+
diff --git a/src/emu/machine/pic8259.c b/src/emu/machine/pic8259.c
new file mode 100644
index 00000000000..7630404491a
--- /dev/null
+++ b/src/emu/machine/pic8259.c
@@ -0,0 +1,397 @@
+/**********************************************************************
+
+ 8259 PIC interface and emulation
+
+ The 8259 is a programmable interrupt controller used to multiplex
+ interrupts for x86 and other computers. The chip is set up by
+ writing a series of Initialization Command Words (ICWs) after which
+ the chip is operational and capable of dispatching interrupts. After
+ this, Operation Command Words (OCWs) can be written to control further
+ behavior.
+
+**********************************************************************/
+
+#include "driver.h"
+#include "memconv.h"
+#include "machine/pic8259.h"
+
+#define IRQ_COUNT 8
+
+#define LOG_ICW 0
+#define LOG_OCW 0
+#define LOG_GENERAL 0
+
+typedef enum
+{
+ STATE_ICW1,
+ STATE_ICW2,
+ STATE_ICW3,
+ STATE_ICW4,
+ STATE_READY
+} pic8259_state_t;
+
+struct pic8259
+{
+ emu_timer *timer;
+ void (*set_int_line)(int which, int interrupt);
+
+ pic8259_state_t state;
+
+ UINT8 irq_lines;
+ UINT8 in_service;
+ UINT8 pending;
+ UINT8 prio;
+ UINT8 interrupt_mask;
+
+ UINT8 input;
+ UINT32 special : 1;
+
+ /* ICW1 state */
+ UINT32 level_trig_mode : 1;
+ UINT32 vector_size : 1;
+ UINT32 cascade : 1;
+ UINT32 icw4_needed : 1;
+
+ /* ICW2 state */
+ UINT8 base;
+
+ /* ICW3 state */
+ UINT8 slave;
+
+ /* ICW4 state */
+ UINT32 nested : 1;
+ UINT32 mode : 2;
+ UINT32 auto_eoi : 1;
+ UINT32 is_x86 : 1;
+};
+
+static struct pic8259 *pic;
+
+static TIMER_CALLBACK( pic8259_timerproc );
+
+
+/* initializer */
+int pic8259_init(int count, void (*set_int_line)(int which, int interrupt))
+{
+ int i;
+
+ /* allocate pic structures */
+ pic = auto_malloc(count * sizeof(struct pic8259));
+ memset(pic, 0, count * sizeof(struct pic8259));
+
+ for (i = 0; i < count; i++)
+ {
+ pic[i].timer = timer_alloc(pic8259_timerproc);
+ pic[i].set_int_line = set_int_line;
+ }
+
+ return 0;
+}
+
+
+
+static TIMER_CALLBACK( pic8259_timerproc )
+{
+ int which = param;
+ struct pic8259 *p = &pic[which];
+ int irq;
+ UINT8 mask;
+
+ /* check the various IRQs */
+ for (irq = 0; irq < IRQ_COUNT; irq++)
+ {
+ mask = 1 << irq;
+
+ /* is this IRQ in service? */
+ if (p->in_service & mask)
+ {
+ if (LOG_GENERAL)
+ logerror("pic8259_timerproc(): PIC #%d IRQ #%d still in service\n", which, irq);
+ return;
+ }
+
+ /* is this IRQ pending and enabled? */
+ if ((p->state == STATE_READY) && (p->pending & mask) && !(p->interrupt_mask & mask))
+ {
+ if (LOG_GENERAL)
+ logerror("pic8259_timerproc(): PIC #%d triggering IRQ #%d\n", which, irq);
+ if (p->set_int_line)
+ p->set_int_line(which, 1);
+ return;
+ }
+ }
+ if (p->set_int_line)
+ p->set_int_line(which, 0);
+}
+
+
+
+static void pic8259_set_timer(int which)
+{
+ timer_adjust(pic[which].timer, attotime_zero, which, attotime_zero);
+}
+
+
+
+void pic8259_set_irq_line(int which, int irq, int state)
+{
+ if (state)
+ {
+ /* setting IRQ line */
+ if (!(pic[which].irq_lines & (1 << irq)))
+ {
+ if (LOG_GENERAL)
+ logerror("pic8259_set_irq_line(): PIC #%d set IRQ line #%d\n", which, irq);
+
+ pic[which].irq_lines |= 1 << irq;
+ pic[which].pending |= 1 << irq;
+ pic8259_set_timer(which);
+ }
+ }
+ else
+ {
+ /* clearing IRQ line */
+ if (pic[which].irq_lines & (1 << irq))
+ {
+ if (LOG_GENERAL)
+ logerror("pic8259_set_irq_line(): PIC #%d cleared IRQ line #%d\n", which, irq);
+
+ pic[which].irq_lines &= ~(1 << irq);
+ pic8259_set_timer(which);
+ }
+ }
+}
+
+
+
+int pic8259_acknowledge(int which)
+{
+ struct pic8259 *p = &pic[which];
+ UINT8 mask;
+ int irq;
+
+ for (irq = 0; irq < IRQ_COUNT; irq++)
+ {
+ mask = 1 << irq;
+
+ /* is this IRQ pending and enabled? */
+ if ((p->pending & mask) && !(p->interrupt_mask & mask))
+ {
+ if (LOG_GENERAL)
+ logerror("pic8259_acknowledge(): PIC #%d acknowledge IRQ #%d\n", which, irq);
+
+ p->pending &= ~mask;
+ if (!p->auto_eoi)
+ p->in_service |= mask;
+
+ return irq + p->base;
+ }
+ }
+ return 0;
+}
+
+
+
+static UINT8 pic8259_read(int which, offs_t offset)
+{
+ struct pic8259 *p = &pic[which];
+
+ /* NPW 18-May-2003 - Changing 0xFF to 0x00 as per Ruslan */
+ UINT8 data = 0x00;
+
+ switch(offset)
+ {
+ case 0: /* PIC acknowledge IRQ */
+ if (p->special)
+ {
+ p->special = 0;
+ data = p->input;
+ }
+ break;
+
+ case 1: /* PIC mask register */
+ data = p->interrupt_mask;
+ break;
+ }
+ return data;
+}
+
+
+
+static void pic8259_write(int which, offs_t offset, UINT8 data )
+{
+ struct pic8259 *p = &pic[which];
+
+ switch(offset)
+ {
+ case 0: /* PIC acknowledge IRQ */
+ if (data & 0x10)
+ {
+ /* write ICW1 - this pretty much resets the chip */
+ if (LOG_ICW)
+ logerror("pic8259_write(): ICW1; which=%d data=0x%02X\n", which, data);
+
+ p->interrupt_mask = 0x00;
+ p->level_trig_mode = (data & 0x08) ? 1 : 0;
+ p->vector_size = (data & 0x04) ? 1 : 0;
+ p->cascade = (data & 0x02) ? 0 : 1;
+ p->icw4_needed = (data & 0x01) ? 1 : 0;
+ p->state = STATE_ICW2;
+ }
+ else if (p->state == STATE_READY)
+ {
+ if ((data & 0x98) == 0x08)
+ {
+ /* write OCW3 */
+ if (LOG_OCW)
+ logerror("pic8259_write(): OCW3; which=%d data=0x%02X\n", which, data);
+
+ switch (data & 0x03)
+ {
+ case 0x02:
+ p->special = 1;
+ p->input = p->pending;
+ break;
+ case 0x03:
+ p->special = 1;
+ p->input = p->in_service & ~p->interrupt_mask;
+ break;
+ }
+ }
+ else if ((data & 0x18) == 0x00)
+ {
+ int n = data & 7;
+ UINT8 mask = 1 << n;
+
+ /* write OCW2 */
+ if (LOG_OCW)
+ logerror("pic8259_write(): OCW2; which=%d data=0x%02X\n", which, data);
+
+ switch (data & 0xe0)
+ {
+ case 0x00:
+ p->prio = 0;
+ break;
+ case 0x20:
+ for (n = 0, mask = 1<<p->prio; n < 8; n++, mask = (mask<<1) | (mask>>7))
+ {
+ if (p->in_service & mask)
+ {
+ p->in_service &= ~mask;
+ break;
+ }
+ }
+ break;
+ case 0x40:
+ break;
+ case 0x60:
+ if( p->in_service & mask )
+ {
+ p->in_service &= ~mask;
+ }
+ break;
+ case 0x80:
+ p->prio = ++p->prio & 7;
+ break;
+ case 0xa0:
+ for (n = 0, mask = 1<<p->prio; n < 8; n++, mask = (mask<<1) | (mask>>7))
+ {
+ if( p->in_service & mask )
+ {
+ p->in_service &= ~mask;
+ p->prio = ++p->prio & 7;
+ break;
+ }
+ }
+ break;
+ case 0xc0:
+ p->prio = n & 7;
+ break;
+ case 0xe0:
+ if( p->in_service & mask )
+ {
+ p->in_service &= ~mask;
+ p->pending &= ~mask;
+ p->prio = ++p->prio & 7;
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ case 1:
+ switch(p->state)
+ {
+ case STATE_ICW1:
+ break;
+
+ case STATE_ICW2:
+ /* write ICW2 */
+ if (LOG_ICW)
+ logerror("pic8259_write(): ICW2; which=%d data=0x%02X\n", which, data);
+
+ p->base = data & 0xf8;
+ if (p->cascade)
+ p->state = STATE_ICW3;
+ else
+ p->state = p->icw4_needed ? STATE_ICW4 : STATE_READY;
+ break;
+
+ case STATE_ICW3:
+ /* write ICW3 */
+ if (LOG_ICW)
+ logerror("pic8259_write(): ICW3; which=%d data=0x%02X\n", which, data);
+
+ p->slave = data;
+ p->state = p->icw4_needed ? STATE_ICW4 : STATE_READY;
+ break;
+
+ case STATE_ICW4:
+ /* write ICW4 */
+ if (LOG_ICW)
+ logerror("pic8259_write(): ICW4; which=%d data=0x%02X\n", which, data);
+
+ p->nested = (data & 0x10) ? 1 : 0;
+ p->mode = (data >> 2) & 3;
+ p->auto_eoi = (data & 0x02) ? 1 : 0;
+ p->is_x86 = (data & 0x01) ? 1 : 0;
+ p->state = STATE_READY;
+ break;
+
+ case STATE_READY:
+ /* write OCW1 - set interrupt mask register */
+ if (LOG_OCW)
+ logerror("pic8259_write(): OCW1; which=%d data=0x%02X\n", which, data);
+
+ p->interrupt_mask = data;
+ break;
+ }
+ break;
+ }
+ pic8259_set_timer(which);
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+READ8_HANDLER ( pic8259_0_r ) { return pic8259_read(0, offset); }
+READ8_HANDLER ( pic8259_1_r ) { return pic8259_read(1, offset); }
+WRITE8_HANDLER ( pic8259_0_w ) { pic8259_write(0, offset, data); }
+WRITE8_HANDLER ( pic8259_1_w ) { pic8259_write(1, offset, data); }
+
+READ16_HANDLER ( pic8259_16le_0_r ) { return read16le_with_read8_handler(pic8259_0_r, offset, mem_mask); }
+READ16_HANDLER ( pic8259_16le_1_r ) { return read16le_with_read8_handler(pic8259_1_r, offset, mem_mask); }
+WRITE16_HANDLER ( pic8259_16le_0_w ) { write16le_with_write8_handler(pic8259_0_w, offset, data, mem_mask); }
+WRITE16_HANDLER ( pic8259_16le_1_w ) { write16le_with_write8_handler(pic8259_1_w, offset, data, mem_mask); }
+
+READ32_HANDLER ( pic8259_32le_0_r ) { return read32le_with_read8_handler(pic8259_0_r, offset, mem_mask); }
+READ32_HANDLER ( pic8259_32le_1_r ) { return read32le_with_read8_handler(pic8259_1_r, offset, mem_mask); }
+WRITE32_HANDLER ( pic8259_32le_0_w ) { write32le_with_write8_handler(pic8259_0_w, offset, data, mem_mask); }
+WRITE32_HANDLER ( pic8259_32le_1_w ) { write32le_with_write8_handler(pic8259_1_w, offset, data, mem_mask); }
+
+READ64_HANDLER ( pic8259_64be_0_r ) { return read64be_with_read8_handler(pic8259_0_r, offset, mem_mask); }
+READ64_HANDLER ( pic8259_64be_1_r ) { return read64be_with_read8_handler(pic8259_1_r, offset, mem_mask); }
+WRITE64_HANDLER ( pic8259_64be_0_w ) { write64be_with_write8_handler(pic8259_0_w, offset, data, mem_mask); }
+WRITE64_HANDLER ( pic8259_64be_1_w ) { write64be_with_write8_handler(pic8259_1_w, offset, data, mem_mask); }
diff --git a/src/emu/machine/pic8259.h b/src/emu/machine/pic8259.h
new file mode 100644
index 00000000000..faae4712962
--- /dev/null
+++ b/src/emu/machine/pic8259.h
@@ -0,0 +1,34 @@
+/**********************************************************************
+
+ 8259 PIC interface and emulation
+
+**********************************************************************/
+
+#ifndef PIC8259_H
+#define PIC8259_H
+
+int pic8259_init(int count, void (*set_int_line)(int which, int interrupt));
+int pic8259_acknowledge(int which);
+void pic8259_set_irq_line(int which, int irq, int state);
+
+READ8_HANDLER ( pic8259_0_r );
+READ8_HANDLER ( pic8259_1_r );
+WRITE8_HANDLER ( pic8259_0_w );
+WRITE8_HANDLER ( pic8259_1_w );
+
+READ16_HANDLER ( pic8259_16le_0_r );
+READ16_HANDLER ( pic8259_16le_1_r );
+WRITE16_HANDLER ( pic8259_16le_0_w );
+WRITE16_HANDLER ( pic8259_16le_1_w );
+
+READ32_HANDLER ( pic8259_32le_0_r );
+READ32_HANDLER ( pic8259_32le_1_r );
+WRITE32_HANDLER ( pic8259_32le_0_w );
+WRITE32_HANDLER ( pic8259_32le_1_w );
+
+READ64_HANDLER ( pic8259_64be_0_r );
+READ64_HANDLER ( pic8259_64be_1_r );
+WRITE64_HANDLER ( pic8259_64be_0_w );
+WRITE64_HANDLER ( pic8259_64be_1_w );
+
+#endif /* PIC8259_H */
diff --git a/src/emu/machine/pit8253.c b/src/emu/machine/pit8253.c
new file mode 100644
index 00000000000..4499d66d3c6
--- /dev/null
+++ b/src/emu/machine/pit8253.c
@@ -0,0 +1,1216 @@
+/*****************************************************************************
+ *
+ * Programmable Interval Timer 8253/8254
+ *
+ * Three Independent Timers
+ * (gate, clock, out pins)
+ *
+ * 8254 has an additional readback feature
+ *
+ * Revision History
+ * 8-Jul-2004 - AJ: Fixed some bugs. Styx now runs correctly.
+ * Implemented 8254 features.
+ * 1-Mar-2004 - NPW: Did an almost total rewrite and cleaned out much
+ * of the ugliness in the previous design. Bug #430
+ * seems to be fixed
+ * 1-Jul-2000 - PeT: Split off from PC driver and componentized
+ *
+ *****************************************************************************/
+
+#include <math.h>
+#include "driver.h"
+#include "memconv.h"
+#include "machine/pit8253.h"
+
+
+
+/***************************************************************************
+
+ Structures & macros
+
+***************************************************************************/
+
+#define MAX_TIMER 3
+#define VERBOSE 0
+
+#if (VERBOSE == 2)
+#define LOG1(msg) logerror msg
+#define LOG2(msg) logerror msg
+#elif (VERBOSE == 1)
+#define LOG1(msg) logerror msg
+#define LOG2(msg) (void)(0)
+#else
+#define LOG1(msg) (void)(0)
+#define LOG2(msg) (void)(0)
+#endif
+
+
+#define TIMER_TIME_NEVER ((UINT64) -1)
+
+#define CYCLES_NEVER ((UINT32) -1)
+
+struct pit8253_timer
+{
+ double clockin; /* input clock frequency in Hz */
+
+ void (*output_callback)(int); /* callback function for when output changes */
+ void (*freq_callback)(double); /* callback function for when output frequency changes */
+
+ attotime last_updated; /* time when last updated */
+
+ emu_timer *outputtimer; /* MAME timer for output change callback */
+ emu_timer *freqtimer; /* MAME timer for output frequency change callback */
+
+ UINT16 value; /* current counter value ("CE" in Intel docs) */
+ UINT16 latch; /* latched counter value ("OL" in Intel docs) */
+ UINT16 count; /* new counter value ("CR" in Intel docs) */
+ UINT8 control; /* 6-bit control byte */
+ UINT8 status; /* status byte - 8254 only */
+ UINT8 lowcount; /* LSB of new counter value for 16-bit writes */
+ INT32 rmsb; /* 1 = Next read is MSB of 16-bit value */
+ INT32 wmsb; /* 1 = Next write is MSB of 16-bit value */
+ INT32 output; /* 0 = low, 1 = high */
+
+ INT32 gate; /* gate input (0 = low, 1 = high) */
+ INT32 latched_count; /* number of bytes of count latched */
+ INT32 latched_status; /* 1 = status latched (8254 only) */
+ INT32 null_count; /* 1 = mode control or count written, 0 = count loaded */
+ INT32 phase; /* see phase definition tables in simulate2(), below */
+
+ UINT32 cycles_to_output; /* cycles until output callback called */
+ UINT32 cycles_to_freq; /* cycles until frequency callback called */
+ UINT32 freq_count; /* counter period for periodic modes, 0 if counter non-periodic */
+};
+
+struct pit8253
+{
+ const struct pit8253_config *config;
+ struct pit8253_timer timers[MAX_TIMER];
+};
+
+#define CTRL_ACCESS(control) (((control) >> 4) & 0x03)
+#define CTRL_MODE(control) (((control) >> 1) & (((control) & 0x04) ? 0x03 : 0x07))
+#define CTRL_BCD(control) (((control) >> 0) & 0x01)
+
+
+static int pit_count;
+static struct pit8253 *pits;
+
+
+
+/***************************************************************************
+
+ Functions
+
+***************************************************************************/
+
+static struct pit8253 *get_pit(int which)
+{
+ return &pits[which];
+}
+
+
+static struct pit8253_timer *get_timer(struct pit8253 *pit,int which)
+{
+ which &= 3;
+ if (which < MAX_TIMER)
+ return &pit->timers[which];
+ return NULL;
+}
+
+
+static UINT32 decimal_from_bcd(UINT16 val)
+{
+ /* In BCD mode, a nybble loaded with value A-F counts down the same as in
+ binary mode, but wraps around to 9 instead of F after 0, so loading the
+ count register with 0xFFFF gives a period of
+ 0xF - for the units to count down to 0
+ + 10*0xF - for the tens to count down to 0
+ + 100*0xF - for the hundreds to count down to 0
+ + 1000*0xF - for the thousands to count down to 0
+ = 16665 cycles
+ */
+ return
+ ((val>>12) & 0xF) * 1000 +
+ ((val>> 8) & 0xF) * 100 +
+ ((val>> 4) & 0xF) * 10 +
+ ( val & 0xF);
+}
+
+
+static UINT32 adjusted_count(int bcd,UINT16 val)
+{
+ if (bcd == 0)
+ return val == 0 ? 0x10000 : val;
+ return val == 0 ? 10000 : decimal_from_bcd(val);
+}
+
+
+/* This function subtracts 1 from timer->value "cycles" times, taking into
+ account binary or BCD operation, and wrapping around from 0 to 0xFFFF or
+ 0x9999 as necessary. */
+static void decrease_counter_value(struct pit8253_timer *timer,UINT64 cycles)
+{
+ UINT16 value;
+ int units, tens, hundreds, thousands;
+
+ if (CTRL_BCD(timer->control) == 0)
+ {
+ timer->value -= (cycles & 0xFFFF);
+ return;
+ }
+
+ value = timer->value;
+ units = value & 0xF;
+ tens = (value >> 4) & 0xF;
+ hundreds = (value >> 8) & 0xF;
+ thousands = (value >> 12) & 0xF;
+
+ if (cycles <= units)
+ {
+ units -= cycles;
+ }
+ else
+ {
+ cycles -= units;
+ units = (10 - cycles%10)%10;
+
+ cycles =(cycles+9)/10; /* the +9 is so we get a carry if cycles%10 wasn't 0 */
+ if (cycles <= tens)
+ {
+ tens -= cycles;
+ }
+ else
+ {
+ cycles -= tens;
+ tens = (10 - cycles%10) % 10;
+
+ cycles = (cycles+9) / 10;
+ if (cycles <= hundreds)
+ {
+ hundreds -= cycles;
+ }
+ else
+ {
+ cycles -= hundreds;
+ hundreds = (10 - cycles%10)%10;
+ cycles=(cycles+9)/10;
+ thousands = (10 + thousands - cycles%10)%10;
+ }
+ }
+ }
+
+ timer->value = (thousands << 12) | (hundreds << 8) | (tens << 4) | units;
+}
+
+
+static double get_frequency(struct pit8253_timer *timer)
+{
+ LOG2(("pit8253: get_frequency() : %lf\n",(double)(timer->freq_count == 0 ? 0 : timer->clockin / timer->freq_count)));
+ return timer->freq_count == 0 ? 0 : timer->clockin / timer->freq_count;
+}
+
+
+/* Call the frequency callback in "cycles" cycles */
+static void freq_callback_in(struct pit8253_timer *timer,UINT32 cycles)
+{
+ LOG2(("pit8253: freq_callback_in(): %d cycles\n",cycles));
+
+ if (timer->freq_callback == NULL)
+ {
+ return;
+ }
+
+ if (timer->clockin == 0 || cycles == CYCLES_NEVER)
+ {
+ timer_reset(timer->freqtimer,attotime_never);
+ }
+ else
+ {
+ timer_reset(timer->freqtimer,double_to_attotime(cycles / timer->clockin));
+ }
+ timer->cycles_to_freq = cycles;
+}
+
+
+static void set_freq_count(struct pit8253_timer *timer)
+{
+ int mode = CTRL_MODE(timer->control);
+ UINT32 freq_count;
+
+ if ((mode == 2 || mode == 3) && timer->gate != 0 && timer->phase != 0)
+ {
+ freq_count = adjusted_count(CTRL_BCD(timer->control),timer->count);
+ }
+ else
+ {
+ freq_count = 0;
+ }
+
+ if (freq_count != timer->freq_count)
+ {
+ timer->freq_count = freq_count;
+ if (timer->freq_callback != NULL)
+ {
+ timer->freq_callback(get_frequency(timer));
+ freq_callback_in(timer,CYCLES_NEVER);
+ }
+ }
+
+ LOG2(("pit8253: set_freq_count() : %d\n",freq_count));
+}
+
+
+/* Call the output callback in "cycles" cycles */
+static void trigger_countdown(struct pit8253_timer *timer)
+{
+ LOG2(("pit8253: trigger_countdown()\n"));
+
+ timer->phase = 1;
+ timer->value = timer->count;
+ if (CTRL_MODE(timer->control) == 3 && timer->output == 0)
+ timer->value &= 0xfffe;
+
+ set_freq_count(timer);
+}
+
+
+static void set_output(struct pit8253_timer *timer,int output)
+{
+ if (output != timer->output)
+ {
+ timer->output = output;
+ if (timer->output_callback != NULL)
+ {
+ timer->output_callback(output);
+ }
+ }
+}
+
+
+/* This emulates timer "timer" for "elapsed_cycles" cycles and assumes no
+ callbacks occur during that time. */
+static void simulate2(struct pit8253_timer *timer,UINT64 elapsed_cycles)
+{
+ UINT32 adjusted_value;
+ int bcd = CTRL_BCD(timer->control);
+ int mode = CTRL_MODE(timer->control);
+ int cycles_to_output = 0;
+
+ if (timer->cycles_to_freq != CYCLES_NEVER)
+ {
+ timer->cycles_to_freq -= elapsed_cycles;
+ }
+
+ LOG2(("pit8253: simulate2(): simulating %d cycles in mode %d, bcd = %d, phase = %d, gate = %d, value = 0x%04x\n",
+ (int)elapsed_cycles,mode,bcd,timer->phase,timer->gate,timer->value));
+
+ switch (mode) {
+ case 0:
+ /* Mode 0: (Interrupt on Terminal Count)
+
+ +------------------
+ |
+ ----------+
+ <- n+1 ->
+
+ ^
+ +- counter load
+
+ phase|output|length |value|next|comment
+ -----+------+--------+-----+----+----------------------------------
+ 0|low |infinity| |1 |waiting for count
+ 1|low |1 | |2 |internal delay when counter loaded
+ 2|low |n |n..1 |3 |counting down
+ 3|high |infinity|0..1 |3 |counting down
+
+ Gate level sensitive only. Low disables counting, high enables it. */
+
+ if (timer->gate == 0 || timer->phase == 0)
+ {
+ cycles_to_output = CYCLES_NEVER;
+ }
+ else
+ {
+ if (elapsed_cycles > 0 && timer->phase == 1)
+ {
+ --elapsed_cycles;
+ timer->phase = 2;
+ }
+
+ if (timer->phase == 2)
+ {
+ adjusted_value = adjusted_count(bcd,timer->value);
+ if (elapsed_cycles < adjusted_value)
+ {
+ /* Counter didn't wrap */
+ decrease_counter_value(timer,elapsed_cycles);
+ }
+ else
+ {
+ /* Counter wrapped, output goes high */
+ elapsed_cycles -= adjusted_value;
+ timer->phase = 3;
+ timer->value = 0;
+ }
+ }
+
+ if (timer->phase == 3)
+ {
+ decrease_counter_value(timer,elapsed_cycles);
+ cycles_to_output = CYCLES_NEVER;
+ }
+ else
+ {
+ cycles_to_output = adjusted_count(bcd,timer->value) + (timer->phase == 1 ? 1 : 0);
+ }
+ }
+
+ set_output(timer,timer->phase == 3 ? 1 : 0);
+ break;
+
+
+ case 1:
+ /* Mode 1: (Hardware Retriggerable One-Shot a.k.a. Programmable One-Shot)
+
+ --+ +------------------
+ | |
+ +-------+
+ <- n ->
+
+ ^
+ +- trigger
+
+ phase|output|length |value|next|comment
+ -----+------+--------+-----+----+----------------------------------
+ 0|high |infinity|0..1 |1 |counting down
+ 1|low |n |n..1 |0 |counting down
+
+ Gate rising-edge sensitive only.
+ Rising edge initiates counting and resets output after next clock. */
+
+ adjusted_value = adjusted_count(bcd,timer->value);
+ if (elapsed_cycles < adjusted_value)
+ {
+ /* Counter didn't wrap */
+ decrease_counter_value(timer,elapsed_cycles);
+ cycles_to_output = (timer->phase == 0 ? CYCLES_NEVER : adjusted_count(bcd,timer->value));
+ }
+ else
+ {
+ /* Counter wrapped, output goes high */
+ elapsed_cycles -= adjusted_value;
+ timer->phase = 0;
+ timer->value = 0;
+ decrease_counter_value(timer,elapsed_cycles);
+ cycles_to_output = CYCLES_NEVER;
+ }
+ set_output(timer,timer->phase == 0 ? 1 : 0);
+ break;
+
+
+ case 2:
+ /* Mode 2: (Rate Generator)
+
+ --------------+ +---------+ +----
+ | | | |
+ +-+ +-+
+ <- n -X- n ->
+ <1>
+ ^
+ +- counter load or trigger
+
+ phase|output|length |value|next|comment
+ -----+------+--------+-----+----+----------------------------------
+ 0|high |infinity| |1 |waiting for count
+ 1|v!=1 |n |n..1 |1 |counting down
+
+ Counter rewrite has no effect until repeated
+
+ Gate rising-edge and level sensitive.
+ Gate low disables counting and sets output immediately high.
+ Rising-edge reloads count and initiates counting
+ Gate high enables counting. */
+
+ if (timer->gate == 0 || timer->phase == 0)
+ {
+ /* Gate low or mode control write forces output high */
+ set_output(timer,1);
+ cycles_to_output = CYCLES_NEVER;
+ }
+ else
+ {
+ adjusted_value = adjusted_count(bcd,timer->value);
+ if (elapsed_cycles < adjusted_value)
+ {
+ /* Counter didn't wrap */
+ decrease_counter_value(timer,elapsed_cycles);
+ }
+ else
+ {
+ /* Counter wrapped around one or more times */
+ elapsed_cycles -= adjusted_value;
+ trigger_countdown(timer);
+ decrease_counter_value(timer,elapsed_cycles % adjusted_count(bcd,timer->count));
+ }
+ cycles_to_output = (timer->value == 1 ? 1 : (adjusted_count(bcd,timer->value) - 1));
+
+ set_output(timer,timer->value != 1 ? 1 : 0);
+ }
+ break;
+
+
+ case 3:
+ /* Mode 3: (Square Wave Generator)
+
+ ----------------+ +-----------+ +----
+ | | | |
+ +-----------+ +-----------+
+ <- (n+1)/2 -X- n/2 ->
+ ^
+ +- counter load or trigger
+
+ phase|output|length |value|next|comment
+ -----+------+--------+-----+----+----------------------------------
+ 0|high |infinity| |1 |waiting for count
+ 1| |infinity|n..0 |1 |counting down double speed
+
+ Counter rewrite has no effect until repeated (output falling or rising)
+
+ Gate rising-edge and level sensitive.
+ Gate low disables counting and sets output immediately high.
+ Rising-edge reloads count and initiates counting
+ Gate high enables counting. */
+
+ if (timer->gate == 0 || timer->phase == 0)
+ {
+ /* Gate low or mode control write forces output high */
+ set_output(timer,1);
+ cycles_to_output = CYCLES_NEVER;
+ }
+ else
+ {
+ adjusted_value = adjusted_count(bcd,timer->value);
+ if ((elapsed_cycles<<1) < adjusted_value)
+ {
+ /* Counter didn't wrap around */
+ decrease_counter_value(timer,elapsed_cycles<<1);
+ }
+ else
+ {
+ /* Counter wrapped around one or more times */
+ elapsed_cycles -= ((adjusted_value+1)>>1);
+
+ set_output(timer,1 - timer->output);
+ trigger_countdown(timer);
+
+ elapsed_cycles %= adjusted_count(bcd,timer->count);
+ adjusted_value = adjusted_count(bcd,timer->value);
+ if ((elapsed_cycles<<1) >= adjusted_value)
+ {
+ /* Counter wrapped around an even number of times */
+ elapsed_cycles -= ((adjusted_value+1)>>1);
+
+ set_output(timer,1 - timer->output);
+ trigger_countdown(timer);
+ }
+ decrease_counter_value(timer,elapsed_cycles<<1);
+ }
+ cycles_to_output = (adjusted_count(bcd,timer->value) + 1) >> 1;
+ }
+ break;
+
+
+ case 4:
+ case 5:
+ /* Mode 4: (Software Trigger Strobe)
+ Mode 5: (Hardware Trigger Strobe)
+
+ --------------+ +--------------------
+ | |
+ +-+
+ <- n+1 ->
+ ^ <1>
+ +- counter load (mode 4) or trigger (mode 5)
+
+ phase|output|length |value|next|comment
+ -----+------+--------+-----+----+----------------------------------
+ 0|high |infinity|0..1 |0 |waiting for count
+ 1|high |1 | |2 |internal delay when counter loaded
+ 2|high |n |n..1 |3 |counting down
+ 3|low |1 |0 |0 |strobe
+
+ Mode 4 only: counter rewrite loads new counter
+ Mode 5 only: count not reloaded immediately.
+ Mode control write doesn't stop count but sets output high
+
+ Mode 4 only: Gate level sensitive only. Low disables counting, high enables it.
+ Mode 5 only: Gate rising-edge sensitive only. Rising edge initiates counting */
+
+ if (timer->gate == 0 && mode == 4)
+ {
+ cycles_to_output = CYCLES_NEVER;
+ }
+ else
+ {
+ if (elapsed_cycles > 0 && timer->phase == 1)
+ {
+ --elapsed_cycles;
+ timer->phase = 2;
+ }
+
+ if (elapsed_cycles > 0 && timer->phase == 3)
+ {
+ --elapsed_cycles;
+ timer->phase = 0;
+ decrease_counter_value(timer,1);
+ }
+
+ if (timer->value == 0 && timer->phase == 2)
+ adjusted_value = 0;
+ else
+ adjusted_value = adjusted_count(bcd,timer->value);
+
+ if (elapsed_cycles < adjusted_value)
+ {
+ /* Counter didn't wrap */
+ decrease_counter_value(timer,elapsed_cycles);
+ }
+ else
+ {
+ elapsed_cycles -= adjusted_value;
+ timer->value = 0;
+ if (elapsed_cycles == 0)
+ {
+ /* We hit the strobe cycle */
+ timer->phase = 3;
+ }
+ else
+ {
+ decrease_counter_value(timer,elapsed_cycles);
+ timer->phase = 0;
+ }
+ }
+ switch(timer->phase) {
+ case 0:
+ cycles_to_output = CYCLES_NEVER;
+ break;
+ case 1:
+ cycles_to_output = adjusted_count(bcd,timer->value) + 1;
+ break;
+ case 2:
+ cycles_to_output = adjusted_count(bcd,timer->value);
+ break;
+ case 3:
+ cycles_to_output = 1;
+ break;
+ }
+ }
+ set_output(timer,timer->phase != 3 ? 1 : 0);
+ break;
+ }
+
+ if (timer->output_callback != NULL)
+ {
+ timer->cycles_to_output = cycles_to_output;
+ if (cycles_to_output == CYCLES_NEVER || timer->clockin == 0)
+ {
+ timer_reset(timer->outputtimer,attotime_never);
+ }
+ else
+ {
+ timer_reset(timer->outputtimer,
+ double_to_attotime(cycles_to_output / timer->clockin));
+ }
+ }
+
+ if (timer->cycles_to_freq == 0)
+ timer->cycles_to_freq = CYCLES_NEVER;
+}
+
+
+/* This emulates timer "timer" for "elapsed_cycles" cycles, broken down into
+ sections punctuated by callbacks.
+
+ The loop technically should never execute even once. It's here to eliminate
+ the following potential bug:
+
+ 1) The mame timer isn't perfectly accurate.
+ 2) The output callback is executed too late, after an update which
+ brings the timer's local time past the callback time.
+ 3) A short pulse is skipped.
+ 4) That short pulse would have triggered an interrupt. The interrupt is
+ skipped.
+
+ This is a loop instead of an "if" statement in case the mame timer is
+ inaccurate by more than one cycle, and the output changed multiple
+ times during the discrepancy. In practice updates should still be O(1).
+*/
+static void simulate(struct pit8253_timer *timer,UINT64 elapsed_cycles)
+{
+ while ((timer->cycles_to_output != CYCLES_NEVER &&
+ timer->cycles_to_output <= elapsed_cycles) ||
+ (timer->cycles_to_freq != CYCLES_NEVER &&
+ timer->cycles_to_freq <= elapsed_cycles))
+ {
+ UINT32 cycles_to_callback;
+
+ if (timer->cycles_to_output < timer->cycles_to_freq &&
+ timer->cycles_to_output != CYCLES_NEVER)
+ {
+ cycles_to_callback = timer->cycles_to_output;
+ }
+ else
+ {
+ cycles_to_callback = timer->cycles_to_freq;
+ }
+
+ simulate2(timer,cycles_to_callback);
+ elapsed_cycles -= cycles_to_callback;
+ }
+ simulate2(timer,elapsed_cycles);
+}
+
+
+/* This brings timer "timer" up to date */
+static void update(struct pit8253_timer *timer)
+{
+ /* With the 82C54's maximum clockin of 10MHz, 64 bits is nearly 60,000
+ years of time. Should be enough for now. */
+ attotime now = timer_get_time();
+ attotime elapsed_time = attotime_sub(now,timer->last_updated);
+ INT64 elapsed_cycles = attotime_to_double(elapsed_time) * timer->clockin;
+
+ timer->last_updated = attotime_add(timer->last_updated,double_to_attotime(elapsed_cycles/timer->clockin));
+
+ simulate(timer,elapsed_cycles);
+}
+
+
+void pit8253_reset(int which)
+{
+ struct pit8253 *pit = get_pit(which);
+ struct pit8253_timer *timer;
+ int i;
+
+ LOG1(("pit8253_reset(): resetting pit %d\n", which));
+
+ for (i = 0; i < MAX_TIMER; i++)
+ {
+ timer = get_timer(pit,i);
+ /* According to Intel's 8254 docs, the state of a timer is undefined
+ until the first mode control word is written. Here we define this
+ undefined behaviour */
+ timer->control = timer->status = 0x30;
+ timer->rmsb = timer->wmsb = 0;
+ timer->count = timer->value = timer->latch = 0;
+ timer->lowcount = 0;
+ timer->gate = 1;
+ timer->output = 0;
+ timer->latched_count = 0;
+ timer->latched_status = 0;
+ timer->null_count = 1;
+ timer->cycles_to_output = timer->cycles_to_freq = CYCLES_NEVER;
+
+ timer->last_updated = timer_get_time();
+
+ update(timer);
+ }
+}
+
+
+static TIMER_CALLBACK( freqcallback )
+{
+ struct pit8253_timer *timer = get_timer(get_pit(param & 0x0F),(param >> 4) & 0x0F);
+ INT64 cycles = timer->cycles_to_freq;
+ double t;
+
+ LOG2(("pit8253: freqcallback(): pit %d, timer %d, %d cycles\n",param & 0xf,(param >> 4) & 0xf,(UINT32)cycles));
+
+ simulate(timer,cycles);
+
+ t = cycles / timer->clockin;
+
+ timer->last_updated = attotime_add(timer->last_updated, double_to_attotime(t));
+}
+
+
+static TIMER_CALLBACK( outputcallback )
+{
+ struct pit8253_timer *timer = get_timer(get_pit(param & 0x0F),(param >> 4) & 0x0F);
+ INT64 cycles = timer->cycles_to_output;
+ double t;
+
+ LOG2(("pit8253: outputcallback(): pit %d, timer %d, %d cycles\n",param & 0xf,(param >> 4) & 0xf,(UINT32)cycles));
+
+ simulate(timer,cycles);
+
+ t = cycles / timer->clockin;
+
+ timer->last_updated = attotime_add(timer->last_updated, double_to_attotime(t));
+}
+
+
+int pit8253_init(int count, const struct pit8253_config *config)
+{
+ int i, timerno, n=0;
+ struct pit8253 *pit;
+ struct pit8253_timer *timer;
+
+ LOG2(("pit8253_init(): initializing %d pit(s)\n", count));
+
+ pit_count = count;
+ pits = auto_malloc(count * sizeof(struct pit8253));
+
+ memset(pits, 0, count * sizeof(struct pit8253));
+
+ for (i = 0; i < count; i++)
+ {
+ pit = get_pit(i);
+ pit->config = &config[i];
+
+ for (timerno = 0; timerno < MAX_TIMER; timerno++)
+ {
+ timer = get_timer(pit,timerno);
+
+ timer->clockin = pit->config->timer[timerno].clockin;
+ timer->output_callback = pit->config->timer[timerno].output_callback;
+ timer->freq_callback = pit->config->timer[timerno].clock_callback;
+
+ if (timer->output_callback == NULL)
+ timer->outputtimer = NULL;
+ else
+ {
+ timer->outputtimer = timer_alloc(outputcallback);
+ timer_adjust(timer->outputtimer, attotime_never, i | (timerno<<4), attotime_zero);
+ }
+ if (timer->freq_callback == NULL)
+ timer->freqtimer = NULL;
+ else
+ {
+ timer->freqtimer = timer_alloc(freqcallback);
+ timer_adjust(timer->freqtimer, attotime_never, i | (timerno<<4), attotime_zero);
+ }
+
+ /* set up state save values */
+ state_save_register_item("pit8253", n, timer->clockin);
+ state_save_register_item("pit8253", n, timer->control);
+ state_save_register_item("pit8253", n, timer->status);
+ state_save_register_item("pit8253", n, timer->lowcount);
+ state_save_register_item("pit8253", n, timer->latch);
+ state_save_register_item("pit8253", n, timer->count);
+ state_save_register_item("pit8253", n, timer->value);
+ state_save_register_item("pit8253", n, timer->wmsb);
+ state_save_register_item("pit8253", n, timer->rmsb);
+ state_save_register_item("pit8253", n, timer->output);
+ state_save_register_item("pit8253", n, timer->gate);
+ state_save_register_item("pit8253", n, timer->latched_count);
+ state_save_register_item("pit8253", n, timer->latched_status);
+ state_save_register_item("pit8253", n, timer->null_count);
+ state_save_register_item("pit8253", n, timer->phase);
+ state_save_register_item("pit8253", n, timer->cycles_to_output);
+ state_save_register_item("pit8253", n, timer->cycles_to_freq);
+ state_save_register_item("pit8253", n, timer->freq_count);
+ state_save_register_item("pit8253", n, timer->last_updated.seconds);
+ state_save_register_item("pit8253", n, timer->last_updated.attoseconds);
+ ++n;
+ }
+ pit8253_reset(i);
+ }
+
+ LOG1(("pit8253_init(): initialized successfully\n"));
+
+ return 0;
+}
+
+
+/* We recycle bit 0 of timer->value to hold the phase in mode 3 when count is
+ odd. Since read commands in mode 3 always return even numbers, we need to
+ mask this bit off. */
+static UINT16 masked_value(struct pit8253_timer *timer)
+{
+ LOG2(("pit8253: masked_value\n"));
+
+ if (CTRL_MODE(timer->control) == 3)
+ return timer->value & 0xfffe;
+ return timer->value;
+}
+
+/* Reads only affect the following bits of the counter state:
+ latched_status
+ latched_count
+ rmsb
+ so they don't affect any timer operations except other reads. */
+static UINT8 pit8253_read(int which,offs_t offset)
+{
+ struct pit8253 *pit = get_pit(which);
+ struct pit8253_timer *timer = get_timer(pit,offset);
+ UINT8 data;
+ UINT16 value;
+
+ LOG2(("pit8253_read(): pit %d, offset %d\n",which,offset));
+
+ if (timer == NULL)
+ {
+ /* Reading mode control register is illegal according to docs */
+ /* Experimentally determined: reading it returns 0 */
+ data = 0;
+ }
+ else
+ {
+ update(timer);
+
+ if (timer->latched_status)
+ {
+ /* Read status register (8254 only) */
+ data = timer->status;
+ timer->latched_status = 0;
+ }
+ else
+ {
+ if (timer->latched_count != 0)
+ {
+ /* Read back latched count */
+ data = (timer->latch >> (timer->rmsb != 0 ? 8 : 0)) & 0xff;
+ timer->rmsb = 1 - timer->rmsb;
+ --timer->latched_count;
+ }
+ else {
+ value = masked_value(timer);
+
+ /* Read back current count */
+ switch(CTRL_ACCESS(timer->control)) {
+ case 0:
+ default:
+ /* This should never happen */
+ data = 0; /* Appease compiler */
+ break;
+
+ case 1:
+ /* read counter bits 0-7 only */
+ data = (value >> 0) & 0xff;
+ break;
+
+ case 2:
+ /* read counter bits 8-15 only */
+ data = (value >> 8) & 0xff;
+ break;
+
+ case 3:
+ /* read bits 0-7 first, then 8-15 */
+ data = (value >> (timer->rmsb != 0 ? 8 : 0)) & 0xff;
+ timer->rmsb = 1 - timer->rmsb;
+ break;
+ }
+ }
+ }
+ }
+
+ LOG2(("pit8253_read(): PIT #%d offset=%d data=0x%02x\n", which, (int) offset, (unsigned) data));
+ return data;
+}
+
+
+/* Loads a new value from the bus to the count register (CR) */
+static void load_count(struct pit8253_timer *timer, UINT16 newcount)
+{
+ int mode = CTRL_MODE(timer->control);
+
+ LOG1(("pit8253: load_count(): %04x\n",newcount));
+
+ if (newcount == 1)
+ {
+ /* Count of 1 is illegal in modes 2 and 3. What happens here was
+ determined experimentally. */
+ if (mode == 2)
+ newcount = 2;
+ if (mode == 3)
+ newcount = 0;
+ }
+ timer->count = newcount;
+ timer->null_count = 1;
+ if (mode == 2 || mode == 3)
+ {
+ if (timer->phase == 0)
+ {
+ trigger_countdown(timer);
+ }
+ else
+ {
+ int bcd = CTRL_BCD(timer->control);
+ if (mode == 2)
+ {
+ freq_callback_in(timer,adjusted_count(bcd,timer->value));
+ }
+ else
+ {
+ freq_callback_in(timer,(adjusted_count(bcd,timer->value) + 1) >> 1);
+ }
+ }
+ }
+ else
+ {
+ if (mode == 0 || mode == 4)
+ {
+ trigger_countdown(timer);
+ }
+ }
+}
+
+
+static void readback(struct pit8253_timer *timer,int command)
+{
+ UINT16 value;
+ update(timer);
+
+ if ((command & 1) == 0)
+ {
+ /* readback status command */
+ if (timer->latched_status == 0)
+ {
+ timer->status = timer->control | (timer->output != 0 ? 0x80 : 0) | (timer->null_count != 0 ? 0x40 : 0);
+ }
+
+ timer->latched_status = 1;
+ }
+ /* Experimentally determined: the read latch command seems to have no
+ effect if we're halfway through a 16-bit read */
+ if ((command & 2) == 0 && timer->rmsb == 0)
+ {
+ /* readback count command */
+
+ if (timer->latched_count == 0)
+ {
+ value = masked_value(timer);
+ switch(CTRL_ACCESS(timer->control)) {
+ case 0:
+ /* This should never happen */
+ break;
+
+ case 1:
+ /* latch bits 0-7 only */
+ timer->latch = ((value << 8) & 0xff00) | (value & 0xff);
+ timer->latched_count = 1;
+ break;
+
+ case 2:
+ /* read bits 8-15 only */
+ timer->latch = (value & 0xff00) | ((value >> 8) & 0xff);
+ timer->latched_count = 1;
+ break;
+
+ case 3:
+ /* latch all 16 bits */
+ timer->latch = value;
+ timer->latched_count = 2;
+ break;
+ }
+ }
+ }
+}
+
+
+static void pit8253_write(int which, offs_t offset, int data)
+{
+ struct pit8253 *pit = get_pit(which);
+ struct pit8253_timer *timer = get_timer(pit,offset);
+ int read_command;
+
+ LOG2(("pit8253_write(): PIT #%d offset=%d data=0x%02x\n", which, (int) offset, (unsigned) data));
+
+ if (timer == NULL) {
+ /* Write to mode control register */
+ timer = get_timer(pit, (data >> 6) & 3);
+ if (timer == NULL)
+ {
+ /* Readback command. Illegal on 8253 */
+ /* Todo: find out what (if anything) the 8253 hardware actually does here. */
+ if (pit->config->type == TYPE8254)
+ {
+ LOG1(("pit8253_write(): PIT #%d readback %02x\n", which, data & 0x3f));
+
+ /* Bit 0 of data must be 0. Todo: find out what the hardware does if it isn't. */
+ read_command = (data >> 4) & 3;
+ if ((data & 2) != 0)
+ readback(get_timer(pit,0),read_command);
+ if ((data & 4) != 0)
+ readback(get_timer(pit,1),read_command);
+ if ((data & 8) != 0)
+ readback(get_timer(pit,2),read_command);
+ }
+ return;
+ }
+
+ update(timer);
+
+ if (CTRL_ACCESS(data) == 0)
+ {
+ LOG1(("pit8253_write(): PIT #%d timer=%d readback\n", which, (data >> 6) & 3));
+
+ /* Latch current timer value */
+ /* Experimentally verified: this command does not affect the mode control register */
+ readback(timer,1);
+ }
+ else {
+ LOG1(("pit8253_write(): PIT #%d timer=%d bytes=%d mode=%d bcd=%d\n", which, (data >> 6) & 3, (data >> 4) & 3, (data >> 1) & 7,data & 1));
+
+ timer->control = (data & 0x3f);
+ timer->null_count = 1;
+ timer->wmsb = timer->rmsb = 0;
+ /* Phase 0 is always the phase after a mode control write */
+ timer->phase = 0;
+ set_output(timer,1);
+ set_freq_count(timer);
+ }
+ }
+ else
+ {
+ update(timer);
+
+ switch(CTRL_ACCESS(timer->control)) {
+ case 0:
+ /* This should never happen */
+ break;
+
+ case 1:
+ /* read/write counter bits 0-7 only */
+ load_count(timer,data);
+ break;
+
+ case 2:
+ /* read/write counter bits 8-15 only */
+ load_count(timer,data << 8);
+ break;
+
+ case 3:
+ /* read/write bits 0-7 first, then 8-15 */
+ if (timer->wmsb != 0)
+ {
+ load_count(timer,timer->lowcount | (data << 8));
+ }
+ else
+ {
+ timer->lowcount = data;
+ if (CTRL_MODE(timer->control) == 0)
+ {
+ /* The Intel docs say that writing the MSB in mode 0, phase
+ 2 won't stop the count, but this was experimentally
+ determined to be false. */
+ timer->phase = 0;
+ }
+ }
+ timer->wmsb = 1 - timer->wmsb;
+ break;
+ }
+ }
+ update(timer);
+}
+
+
+static void pit8253_gate_write(int which,int offset,int data)
+{
+ struct pit8253_timer *timer = get_timer(get_pit(which),offset);
+ int mode;
+ int gate = (data!=0 ? 1 : 0);
+
+ LOG2(("pit8253_gate_write(): PIT #%d offset=%d gate=%d\n", which, (int) offset, (unsigned) data));
+
+ if (timer == NULL)
+ return;
+
+ mode = CTRL_MODE(timer->control);
+
+ if (gate != timer->gate)
+ {
+ update(timer);
+ timer->gate = gate;
+ set_freq_count(timer);
+ if (gate != 0 &&
+ (mode == 1 || mode == 5 ||
+ (timer->phase == 1 && (mode == 2 || mode == 3))))
+ {
+ trigger_countdown(timer);
+ }
+ update(timer);
+ }
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+int pit8253_get_frequency(int which, int timerno)
+{
+ struct pit8253_timer *timer = get_timer(get_pit(which),timerno);
+
+ update(timer);
+ return get_frequency(timer);
+}
+
+
+
+int pit8253_get_output(int which, int timerno)
+{
+ struct pit8253_timer *timer = get_timer(get_pit(which),timerno);
+ int result;
+
+ update(timer);
+ result = timer->output;
+ LOG2(("pit8253_get_output(): PIT #%d timer=%d result=%d\n", which, timerno, result));
+ return result;
+}
+
+
+
+void pit8253_set_clockin(int which, int timerno, double new_clockin)
+{
+ struct pit8253_timer *timer = get_timer(get_pit(which),timerno);
+
+ LOG2(("pit8253_set_clockin(): PIT #%d timer=%d, clockin = %lf\n", which, (int) timerno,new_clockin));
+
+ update(timer);
+ timer->clockin = new_clockin;
+ update(timer);
+
+ if (timer->freq_callback != NULL)
+ {
+ timer->freq_callback(get_frequency(timer));
+ if (timer->cycles_to_freq != CYCLES_NEVER)
+ {
+ freq_callback_in(timer,timer->cycles_to_freq);
+ }
+ }
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+READ8_HANDLER ( pit8253_0_r ) { return pit8253_read(0, offset); }
+READ8_HANDLER ( pit8253_1_r ) { return pit8253_read(1, offset); }
+WRITE8_HANDLER ( pit8253_0_w ) { pit8253_write(0, offset, data); }
+WRITE8_HANDLER ( pit8253_1_w ) { pit8253_write(1, offset, data); }
+
+READ16_HANDLER ( pit8253_0_lsb_r ) { return pit8253_read(0, offset); }
+READ16_HANDLER ( pit8253_1_lsb_r ) { return pit8253_read(1, offset); }
+WRITE16_HANDLER ( pit8253_0_lsb_w ) { if (ACCESSING_LSB) pit8253_write(0, offset, data); }
+WRITE16_HANDLER ( pit8253_1_lsb_w ) { if (ACCESSING_LSB) pit8253_write(1, offset, data); }
+
+READ16_HANDLER ( pit8253_16le_0_r ) { return read16le_with_read8_handler(pit8253_0_r, offset, mem_mask); }
+READ16_HANDLER ( pit8253_16le_1_r ) { return read16le_with_read8_handler(pit8253_1_r, offset, mem_mask); }
+WRITE16_HANDLER ( pit8253_16le_0_w ) { write16le_with_write8_handler(pit8253_0_w, offset, data, mem_mask); }
+WRITE16_HANDLER ( pit8253_16le_1_w ) { write16le_with_write8_handler(pit8253_1_w, offset, data, mem_mask); }
+
+READ32_HANDLER ( pit8253_32le_0_r ) { return read32le_with_read8_handler(pit8253_0_r, offset, mem_mask); }
+READ32_HANDLER ( pit8253_32le_1_r ) { return read32le_with_read8_handler(pit8253_1_r, offset, mem_mask); }
+WRITE32_HANDLER ( pit8253_32le_0_w ) { write32le_with_write8_handler(pit8253_0_w, offset, data, mem_mask); }
+WRITE32_HANDLER ( pit8253_32le_1_w ) { write32le_with_write8_handler(pit8253_1_w, offset, data, mem_mask); }
+
+READ64_HANDLER ( pit8253_64be_0_r ) { return read64be_with_read8_handler(pit8253_0_r, offset, mem_mask); }
+READ64_HANDLER ( pit8253_64be_1_r ) { return read64be_with_read8_handler(pit8253_1_r, offset, mem_mask); }
+WRITE64_HANDLER ( pit8253_64be_0_w ) { write64be_with_write8_handler(pit8253_0_w, offset, data, mem_mask); }
+WRITE64_HANDLER ( pit8253_64be_1_w ) { write64be_with_write8_handler(pit8253_1_w, offset, data, mem_mask); }
+
+WRITE8_HANDLER ( pit8253_0_gate_w ) { pit8253_gate_write(0, offset, data); }
+WRITE8_HANDLER ( pit8253_1_gate_w ) { pit8253_gate_write(1, offset, data); }
+
diff --git a/src/emu/machine/pit8253.h b/src/emu/machine/pit8253.h
new file mode 100644
index 00000000000..a99024b071f
--- /dev/null
+++ b/src/emu/machine/pit8253.h
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ *
+ * Programmable Interval Timer 8253/8254
+ *
+ *****************************************************************************/
+
+#ifndef PIT8253_H
+#define PIT8253_H
+
+typedef enum { TYPE8253, TYPE8254 } PIT8253_TYPE;
+
+struct pit8253_config
+{
+ PIT8253_TYPE type;
+ struct
+ {
+ double clockin;
+ void (*output_callback)(int state);
+ void (*clock_callback)(double clockout);
+ } timer[3];
+};
+
+
+
+int pit8253_init(int count, const struct pit8253_config *config);
+void pit8253_reset(int which);
+
+READ8_HANDLER ( pit8253_0_r );
+READ8_HANDLER ( pit8253_1_r );
+WRITE8_HANDLER ( pit8253_0_w );
+WRITE8_HANDLER ( pit8253_1_w );
+
+READ16_HANDLER ( pit8253_0_lsb_r );
+READ16_HANDLER ( pit8253_1_lsb_r );
+WRITE16_HANDLER ( pit8253_0_lsb_w );
+WRITE16_HANDLER ( pit8253_1_lsb_w );
+
+READ16_HANDLER ( pit8253_16le_0_r );
+READ16_HANDLER ( pit8253_16le_1_r );
+WRITE16_HANDLER ( pit8253_16le_0_w );
+WRITE16_HANDLER ( pit8253_16le_1_w );
+
+READ32_HANDLER ( pit8253_32le_0_r );
+READ32_HANDLER ( pit8253_32le_1_r );
+WRITE32_HANDLER ( pit8253_32le_0_w );
+WRITE32_HANDLER ( pit8253_32le_1_w );
+
+READ64_HANDLER ( pit8253_64be_0_r );
+READ64_HANDLER ( pit8253_64be_1_r );
+WRITE64_HANDLER ( pit8253_64be_0_w );
+WRITE64_HANDLER ( pit8253_64be_1_w );
+
+WRITE8_HANDLER ( pit8253_0_gate_w );
+WRITE8_HANDLER ( pit8253_1_gate_w );
+
+int pit8253_get_frequency(int which, int timer);
+int pit8253_get_output(int which, int timer);
+void pit8253_set_clockin(int which, int timer, double new_clockin);
+
+
+#endif /* PIT8253_H */
+
diff --git a/src/emu/machine/roc10937.c b/src/emu/machine/roc10937.c
new file mode 100644
index 00000000000..59a44b7a04a
--- /dev/null
+++ b/src/emu/machine/roc10937.c
@@ -0,0 +1,407 @@
+/**********************************************************************
+
+ Rockwell 10937/10957 interface and emulation by J.Wallace
+ OKI MSC1937 is a clone of this chip
+
+**********************************************************************/
+
+#include "driver.h"
+#include "roc10937.h"
+
+static struct
+{
+ UINT8 type, // type of alpha display
+
+ reversed, // Allows for the data being written from right to left, not left to right.
+
+ changed, // flag <>0, if contents are changed
+ window_start, // display window start pos 0-15
+ window_end, // display window end pos 0-15
+ window_size; // window size
+
+ INT8 pcursor_pos, // previous cursor pos
+ cursor_pos; // current cursor pos
+
+ UINT16 brightness; // display brightness level 0-31 (31=MAX)
+
+ UINT8 string[18]; // text buffer
+ UINT32 segments[16], // segments
+ outputs[16]; // standardised outputs
+
+ UINT8 count, // bit counter
+ data; // receive register
+
+} roc10937[MAX_ROCK_ALPHAS];
+
+//
+// Rockwell 10937 charset to ASCII conversion table
+//
+static const char roc10937ASCII[]=
+//0123456789ABCDEF0123456789ABC DEF01 23456789ABCDEF0123456789ABCDEF
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ ?\"#$%%'()*+;-./0123456789&%<=>?"\
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ ?\"#$%%'()*+;-./0123456789&%<=>?"\
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ ?\"#$%%'()*+;-./0123456789&%<=>?";
+
+/*
+ Rockwell 10937 16 segment charset lookup table
+ 0 1
+ ---- ----
+ |\ | /|
+ 7 | \F |8 /9| 2
+ | \ | / |
+ -E-- --A-
+ | / | \ |
+ 6 | /D |C \B| 3
+ |/ | \|
+ ---- ---- .11
+ 5 4 ,10
+
+In 14 segment mode, 0 represents the whole top line,
+and 5 the bottom line, allowing both modes to share
+a charset.
+
+Note that, although we call this a 16 segment display,
+we actually have 18 segments, including the semicolon portions.
+This means our segment maths needs to be more than 16-bit to work!
+*/
+
+static UINT32 roc10937charset[]=
+{ // 11 10 FEDC BA98 7654 3210
+ 0x0507F, // 0 0 0101 0000 0111 1111 @.
+ 0x044CF, // 0 0 0100 0100 1100 1111 A.
+ 0x0153F, // 0 0 0001 0101 0011 1111 B.
+ 0x000F3, // 0 0 0000 0000 1111 0011 C.
+ 0x0113F, // 0 0 0001 0001 0011 1111 D.
+ 0x040F3, // 0 0 0100 0000 1111 0011 E.
+ 0x040C3, // 0 0 0100 0000 1100 0011 F.
+ 0x004FB, // 0 0 0000 0100 1111 1011 G.
+ 0x044CC, // 0 0 0100 0100 1100 1100 H.
+ 0x01133, // 0 0 0001 0001 0011 0011 I.
+ 0x0007C, // 0 0 0000 0000 0111 1100 J.
+ 0x04AC0, // 0 0 0100 1010 1100 0000 K.
+ 0x000F0, // 0 0 0000 0000 1111 0000 L.
+ 0x082CC, // 0 0 1000 0010 1100 1100 M.
+ 0x088CC, // 0 0 1000 1000 1100 1100 N.
+ 0x000FF, // 0 0 0000 0000 1111 1111 O.
+ 0x044C7, // 0 0 0100 0100 1100 0111 P.
+ 0x008FF, // 0 0 0000 1000 1111 1111 Q.
+ 0x04CC7, // 0 0 0100 1100 1100 0111 R.
+ 0x044BB, // 0 0 0100 0100 1011 1011 S.
+ 0x01103, // 0 0 0001 0001 0000 0011 T.
+ 0x000FC, // 0 0 0000 0000 1111 1100 U.
+ 0x022C0, // 0 0 0010 0010 1100 0000 V.
+ 0x028CC, // 0 0 0010 1000 1100 1100 W.
+ 0x0AA00, // 0 0 1010 1010 0000 0000 X.
+ 0x09200, // 0 0 1001 0010 0000 0000 Y.
+ 0x02233, // 0 0 0010 0010 0011 0011 Z.
+ 0x000E1, // 0 0 0000 0000 1110 0001 [.
+ 0x08800, // 0 0 1000 1000 0000 0000 \.
+ 0x0001E, // 0 0 0000 0000 0001 1110 ].
+ 0x02800, // 0 0 0010 1000 0000 0000 ^.
+ 0x00030, // 0 0 0000 0000 0011 0000 _.
+ 0x00000, // 0 0 0000 0000 0000 0000 dummy.
+ 0x08121, // 0 0 1000 0001 0010 0001 Unknown symbol.
+ 0x00180, // 0 0 0000 0001 1000 0000 ".
+ 0x0553C, // 0 0 0101 0101 0011 1100 #.
+ 0x055BB, // 0 0 0101 0101 1011 1011 $.
+ 0x07799, // 0 0 0111 0111 1001 1001 %.
+ 0x0C979, // 0 0 1100 1001 0111 1001 &.
+ 0x00200, // 0 0 0000 0010 0000 0000 '.
+ 0x00A00, // 0 0 0000 1010 0000 0000 (.
+ 0x0A050, // 0 0 1010 0000 0000 0000 ).
+ 0x0FF00, // 0 0 1111 1111 0000 0000 *.
+ 0x05500, // 0 0 0101 0101 0000 0000 +.
+ 0x30000, // 1 1 0000 0000 0000 0000 ;.
+ 0x04400, // 0 0 0100 0100 0000 0000 --.
+ 0x20000, // 1 0 0000 0000 0000 0000 . .
+ 0x02200, // 0 0 0010 0010 0000 0000 /.
+ 0x022FF, // 0 0 0010 0010 1111 1111 0.
+ 0x01100, // 0 0 0001 0001 0000 0000 1.
+ 0x04477, // 0 0 0100 0100 0111 0111 2.
+ 0x0443F, // 0 0 0100 0100 0011 1111 3.
+ 0x0448C, // 0 0 0100 0100 1000 1100 4.
+ 0x044BB, // 0 0 0100 0100 1011 1011 5.
+ 0x044FB, // 0 0 0100 0100 1111 1011 6.
+ 0x0000E, // 0 0 0000 0000 0000 1110 7.
+ 0x044FF, // 0 0 0100 0100 1111 1111 8.
+ 0x044BF, // 0 0 0100 0100 1011 1111 9.
+ 0x00021, // 0 0 0000 0000 0010 0001 -
+ // -.
+ 0x02001, // 0 0 0010 0000 0000 0001 -
+ // /.
+ 0x02430, // 0 0 0010 0100 0011 0000 <.
+ 0x04430, // 0 0 0100 0100 0011 0000 =.
+ 0x08830, // 0 0 1000 1000 0011 0000 >.
+ 0x01407, // 0 0 0001 0100 0000 0111 ?.
+};
+
+static const int roc10937poslut[]=
+{
+ 1,//0
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 0//15
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+void ROC10937_init(int id, int type,int reversed)
+{
+ assert_always((id >= 0) && (id < MAX_ROCK_ALPHAS), "roc10937_init called on an invalid display ID!");
+
+ memset( &roc10937[id], 0, sizeof(roc10937[0]));
+
+ roc10937[id].type = type;
+ roc10937[id].reversed = reversed;
+ ROC10937_reset(id);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+void ROC10937_reset(int id)
+{
+ roc10937[id].window_end = 15;
+ roc10937[id].window_size = (roc10937[id].window_end - roc10937[id].window_start)+1;
+ memset(roc10937[id].string, ' ', 16);
+
+ roc10937[id].brightness = 31;
+ roc10937[id].count = 0;
+
+ roc10937[id].changed |= 1;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+UINT32 *ROC10937_get_segments(int id)
+{
+ return roc10937[id].segments;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+UINT32 *ROC10937_get_outputs(int id)
+{
+ return roc10937[id].outputs;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+UINT32 *ROC10937_set_outputs(int id)
+{
+ int cursor,val;
+ for (cursor = 0; cursor < 16; cursor++)
+ {
+ if (!roc10937[id].reversed)//Output to the screen is naturally backwards, so we need to invert it
+ {
+ val = 15-cursor;
+ }
+ else
+ {
+ //If the controller is reversed, things look normal.
+ val = cursor;
+ }
+
+ if ( ROC10937_get_segments(id)[val] & 0x0001 ) roc10937[id].outputs[cursor] |= 0x0001;
+ else roc10937[id].outputs[cursor] &= ~0x0001;
+ if ( ROC10937_get_segments(id)[val] & 0x0002 ) roc10937[id].outputs[cursor] |= 0x0002;
+ else roc10937[id].outputs[cursor] &= ~0x0002;
+ if ( ROC10937_get_segments(id)[val] & 0x0004 ) roc10937[id].outputs[cursor] |= 0x0004;
+ else roc10937[id].outputs[cursor] &= ~0x0004;
+ if ( ROC10937_get_segments(id)[val] & 0x0008 ) roc10937[id].outputs[cursor] |= 0x0008;
+ else roc10937[id].outputs[cursor] &= ~0x0008;
+ if ( ROC10937_get_segments(id)[val] & 0x0010 ) roc10937[id].outputs[cursor] |= 0x0010;
+ else roc10937[id].outputs[cursor] &= ~0x0010;
+ if ( ROC10937_get_segments(id)[val] & 0x0020 ) roc10937[id].outputs[cursor] |= 0x0020;
+ else roc10937[id].outputs[cursor] &= ~0x0020;
+ if ( ROC10937_get_segments(id)[val] & 0x0040 ) roc10937[id].outputs[cursor] |= 0x0040;
+ else roc10937[id].outputs[cursor] &= ~0x0040;
+ if ( ROC10937_get_segments(id)[val] & 0x0080 ) roc10937[id].outputs[cursor] |= 0x0080;
+ else roc10937[id].outputs[cursor] &= ~0x0080;
+ if ( ROC10937_get_segments(id)[val] & 0x4000 ) roc10937[id].outputs[cursor] |= 0x0100;
+ else roc10937[id].outputs[cursor] &= ~0x0100;
+ if ( ROC10937_get_segments(id)[val] & 0x0400 ) roc10937[id].outputs[cursor] |= 0x0200;
+ else roc10937[id].outputs[cursor] &= ~0x0200;
+ if ( ROC10937_get_segments(id)[val] & 0x0100 ) roc10937[id].outputs[cursor] |= 0x0400;
+ else roc10937[id].outputs[cursor] &= ~0x0400;
+ if ( ROC10937_get_segments(id)[val] & 0x1000 ) roc10937[id].outputs[cursor] |= 0x0800;
+ else roc10937[id].outputs[cursor] &= ~0x0800;
+ if ( ROC10937_get_segments(id)[val] & 0x2000 ) roc10937[id].outputs[cursor] |= 0x1000;
+ else roc10937[id].outputs[cursor] &= ~0x1000;
+ if ( ROC10937_get_segments(id)[val] & 0x8000 ) roc10937[id].outputs[cursor] |= 0x2000;
+ else roc10937[id].outputs[cursor] &= ~0x2000;
+ if ( ROC10937_get_segments(id)[val] & 0x0200 ) roc10937[id].outputs[cursor] |= 0x4000;
+ else roc10937[id].outputs[cursor] &= ~0x4000;
+ if ( ROC10937_get_segments(id)[val] & 0x0800 ) roc10937[id].outputs[cursor] |= 0x8000;
+ else roc10937[id].outputs[cursor] &= ~0x8000;
+
+ if ( ROC10937_get_segments(id)[val] & 0x10000 ) roc10937[id].outputs[cursor] |= 0x10000;
+ else roc10937[id].outputs[cursor] &= ~0x10000;
+ if ( ROC10937_get_segments(id)[val] & 0x20000 ) roc10937[id].outputs[cursor] |= 0x20000;
+ else roc10937[id].outputs[cursor] &= ~0x20000;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+char *ROC10937_get_string( int id)
+{
+ return (char *)roc10937[id].string;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+void ROC10937_shift_data(int id, int data)
+{
+ roc10937[id].data <<= 1;
+
+ if ( !data ) roc10937[id].data |= 1;
+
+ if ( ++roc10937[id].count >= 8 )
+ {
+ if ( ROC10937_newdata(id, roc10937[id].data) )
+ {
+ roc10937[id].changed |= 1;
+ }
+
+ roc10937[id].count = 0;
+ roc10937[id].data = 0;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+int ROC10937_newdata(int id, int data)
+{
+ int change = 0;
+
+ if ( data & 0x80 )
+ { // Control data received
+ if ( (data & 0xF0) == 0xA0 ) // 1010 xxxx
+ { // 1010 xxxx Buffer Pointer control
+ roc10937[id].cursor_pos = roc10937poslut[data & 0x0F];
+ }
+ else if ( (data & 0xF0) == 0xC0 ) // 1100 xxxx
+ { // 1100 xxxx Set number of digits
+ data &= 0x07;
+
+ if ( data == 0 ) roc10937[id].window_size = 16;
+ else roc10937[id].window_size = data+8;
+ roc10937[id].window_start = 0;
+ roc10937[id].window_end = roc10937[id].window_size-1;
+ }
+ else if ( (data & 0xE0) == 0xE0 ) // 111x xxxx
+ { // 111x xxxx Set duty cycle ( brightness )
+ roc10937[id].brightness = (data & 0xF)*2;
+ change = 1;
+ }
+ else if ( (data & 0xE0) == 0x80 ) // 100x ---
+ { // 100x xxxx Test mode
+ }
+ }
+ else
+ { // Display data
+ data &= 0x3F;
+ change = 1;
+
+ switch ( data )
+ {
+ case 0x2C: // ;
+ roc10937[id].segments[roc10937[id].pcursor_pos] |= (1<<17);//.
+ roc10937[id].segments[roc10937[id].pcursor_pos] |= (1<<18);//,
+ break;
+ case 0x2E: //
+ roc10937[id].segments[roc10937[id].pcursor_pos] |= (1<<17);//.
+ break;
+ case 0x6C: // ;
+ roc10937[id].segments[roc10937[id].pcursor_pos] |= (1<<17);//.
+ if ( roc10937[id].type == ROCKWELL10937)
+ {
+ roc10937[id].segments[roc10937[id].pcursor_pos] |= (1<<18);//,
+ }
+ break;
+ case 0x6E: //
+ if ( roc10937[id].type == ROCKWELL10937)
+ {
+ roc10937[id].segments[roc10937[id].pcursor_pos] |= (1<<17);//.
+ }
+ else
+ {
+ roc10937[id].segments[roc10937[id].pcursor_pos] |= (1<<18);//,
+ }
+ break;
+ default :
+ roc10937[id].pcursor_pos = roc10937[id].cursor_pos;
+ roc10937[id].string[ roc10937[id].cursor_pos ] = roc10937ASCII[data];
+ roc10937[id].segments[roc10937[id].cursor_pos] = roc10937charset[data & 0x3F];
+
+ roc10937[id].cursor_pos++;
+ if ( roc10937[id].cursor_pos > roc10937[id].window_end )
+ {
+ roc10937[id].cursor_pos = 0;
+ }
+ break;
+ }
+
+ }
+ return change;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static void ROC10937_plot(int id, int power)
+{
+ int cursor;
+ ROC10937_set_outputs(id);
+
+ for (cursor = 0; cursor < 16; cursor++)
+ {
+ output_set_indexed_value("vfd", (id*16)+cursor, power?ROC10937_get_outputs(id)[cursor]:0x00000);
+
+ if (ROC10937_get_outputs(id)[cursor] & 0x40000)
+ {
+ //activate flashing (unimplemented, just toggle on and off)
+ }
+ else
+ {
+ //deactivate flashing (unimplemented)
+ }
+ }
+}
+static void ROC10937_draw(int id, int segs)
+{
+ int cycle;
+ for (cycle = 0; cycle < 32; cycle++)
+ {
+ if ((roc10937[id].brightness < cycle)||(roc10937[id].brightness == cycle))
+ {
+ ROC10937_plot(id,1);
+ }
+ else
+ {
+ ROC10937_plot(id,0);
+ }
+ }
+}
+
+//Helper functions
+void ROC10937_draw_16seg(int id)
+{
+ ROC10937_draw(id,16);
+}
+void ROC10937_draw_14seg(int id)
+{
+ ROC10937_draw(id,14);
+}
diff --git a/src/emu/machine/roc10937.h b/src/emu/machine/roc10937.h
new file mode 100644
index 00000000000..9b7d8516787
--- /dev/null
+++ b/src/emu/machine/roc10937.h
@@ -0,0 +1,34 @@
+/**********************************************************************
+
+ Rockwell 10937/10957 interface and emulation by J.Wallace
+ OKI MSC1937 is a clone of this chip
+
+**********************************************************************/
+
+#ifndef ROC10937
+#define ROC10937
+
+#define MAX_ROCK_ALPHAS 3 // max number of displays emulated
+
+#define ROCKWELL10937 0 // Rockwell 10937
+#define MSC1937 0 // OKI MSC1937 clone of Rockwell 10937
+#define ROCKWELL10957 1 // Rockwell 10957
+
+void ROC10937_init( int id, int type,int reversed ); // setup a display
+
+void ROC10937_reset( int id); // reset the alpha
+
+void ROC10937_shift_data(int id, int data); // clock in a bit of data
+
+int ROC10937_newdata( int id, int data); // clock in 8 bits of data
+
+UINT32 *ROC10937_get_segments(int id); // get current segments displayed
+UINT32 *ROC10937_set_outputs(int id); // convert segments to standard for display
+UINT32 *ROC10937_get_outputs(int id); // get converted segments
+
+char *ROC10937_get_string( int id); // get current string displayed (not as accurate)
+
+void ROC10937_draw_16seg(int id);
+void ROC10937_draw_14seg(int id);
+#endif
+
diff --git a/src/emu/machine/rp5h01.c b/src/emu/machine/rp5h01.c
new file mode 100644
index 00000000000..32b46da62ec
--- /dev/null
+++ b/src/emu/machine/rp5h01.c
@@ -0,0 +1,207 @@
+#include "driver.h"
+#include "machine/rp5h01.h"
+
+/****************************************************************************/
+
+/* local copy of the interface pointer */
+static struct RP5H01_interface *intf;
+
+/* these also work as the address masks */
+enum {
+ COUNTER_MODE_6_BITS = 0x3f,
+ COUNTER_MODE_7_BITS = 0x7f
+};
+
+typedef struct _RP5H01 {
+ int counter;
+ int counter_mode; /* test pin */
+ int enabled; /* chip enable */
+ int old_reset; /* reset pin state (level-triggered) */
+ int old_clock; /* clock pin state (level-triggered) */
+ UINT8 *data;
+} RP5H01;
+
+static RP5H01 RP5H01_state[MAX_RP5H01];
+
+/****************************************************************************/
+
+int RP5H01_init( struct RP5H01_interface *interface ) {
+ int i;
+
+ /* setup our local copy of the interface */
+ intf = interface;
+
+ if ( intf->num > MAX_RP5H01 ) {
+ logerror( "Requested number of RP5H01's is bigger than the supported amount\n" );
+ return -1;
+ }
+
+ /* initialize the state */
+ for( i = 0; i < intf->num; i++ ) {
+ RP5H01_state[i].counter = 0;
+ RP5H01_state[i].counter_mode = COUNTER_MODE_6_BITS;
+ RP5H01_state[i].data = &( memory_region( intf->region[i] )[ intf->offset[i] ] );
+ RP5H01_state[i].enabled = 0;
+ RP5H01_state[i].old_reset = -1;
+ RP5H01_state[i].old_clock = -1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+
+void RP5H01_enable_w( int which, int data ) {
+ RP5H01 *chip;
+
+ if ( which >= intf->num ) {
+ logerror( "RP5H01_enable: trying to access an unmapped chip\n" );
+ return;
+ }
+
+ /* get the chip */
+ chip = &RP5H01_state[which];
+
+ /* process the /CE signal and enable/disable the IC */
+ chip->enabled = ( data == 0 ) ? 1 : 0;
+}
+
+void RP5H01_reset_w( int which, int data ) {
+ RP5H01 *chip;
+ int newstate = ( data == 0 ) ? 0 : 1;
+
+ if ( which >= intf->num ) {
+ logerror( "RP5H01_enable: trying to access an unmapped chip\n" );
+ return;
+ }
+
+ /* get the chip */
+ chip = &RP5H01_state[which];
+
+ /* if it's not enabled, ignore */
+ if ( !chip->enabled )
+ return;
+
+ /* now look for a 0->1 transition */
+ if ( chip->old_reset == 0 && newstate == 1 ) {
+ /* reset the counter */
+ chip->counter = 0;
+ }
+
+ /* update the pin */
+ chip->old_reset = newstate;
+}
+
+void RP5H01_clock_w( int which, int data ) {
+ RP5H01 *chip;
+ int newstate = ( data == 0 ) ? 0 : 1;
+
+ if ( which >= intf->num ) {
+ logerror( "RP5H01_enable: trying to access an unmapped chip\n" );
+ return;
+ }
+
+ /* get the chip */
+ chip = &RP5H01_state[which];
+
+ /* if it's not enabled, ignore */
+ if ( !chip->enabled )
+ return;
+
+ /* now look for a 1->0 transition */
+ if ( chip->old_clock == 1 && newstate == 0 ) {
+ /* increment the counter, and mask it with the mode */
+ chip->counter++;
+ }
+
+ /* update the pin */
+ chip->old_clock = newstate;
+}
+
+void RP5H01_test_w( int which, int data ) {
+ RP5H01 *chip;
+
+ if ( which >= intf->num ) {
+ logerror( "RP5H01_enable: trying to access an unmapped chip\n" );
+ return;
+ }
+
+ /* get the chip */
+ chip = &RP5H01_state[which];
+
+ /* if it's not enabled, ignore */
+ if ( !chip->enabled )
+ return;
+
+ /* process the test signal and change the counter mode */
+ chip->counter_mode = ( data == 0 ) ? COUNTER_MODE_6_BITS : COUNTER_MODE_7_BITS;
+}
+
+int RP5H01_counter_r( int which ) {
+ RP5H01 *chip;
+
+ if ( which >= intf->num ) {
+ logerror( "RP5H01_enable: trying to access an unmapped chip\n" );
+ return 0;
+ }
+
+ /* get the chip */
+ chip = &RP5H01_state[which];
+
+ /* if it's not enabled, ignore */
+ if ( !chip->enabled )
+ return 0; /* ? (should be high impedance) */
+
+ /* return A5 */
+ return ( chip->counter >> 5 ) & 1;
+}
+
+int RP5H01_data_r( int which ) {
+ RP5H01 *chip;
+ int byte, bit;
+
+ if ( which >= intf->num ) {
+ logerror( "RP5H01_enable: trying to access an unmapped chip\n" );
+ return 0;
+ }
+
+ /* get the chip */
+ chip = &RP5H01_state[which];
+
+ /* if it's not enabled, ignore */
+ if ( !chip->enabled )
+ return 0; /* ? (should be high impedance) */
+
+ /* get the byte offset and bit offset */
+ byte = ( chip->counter & chip->counter_mode) >> 3;
+ bit = 7 - ( chip->counter & 7 );
+
+ /* return the data */
+ return ( chip->data[byte] >> bit ) & 1;
+}
+
+/****************************************************************************/
+
+WRITE8_HANDLER( RP5H01_0_enable_w ) {
+ RP5H01_enable_w( 0, data );
+}
+
+WRITE8_HANDLER( RP5H01_0_reset_w ) {
+ RP5H01_reset_w( 0, data );
+}
+
+WRITE8_HANDLER( RP5H01_0_clock_w ) {
+ RP5H01_clock_w( 0, data );
+}
+
+WRITE8_HANDLER( RP5H01_0_test_w ) {
+ RP5H01_test_w( 0, data );
+}
+
+READ8_HANDLER( RP5H01_0_counter_r ) {
+ return RP5H01_counter_r( 0 );
+}
+
+READ8_HANDLER( RP5H01_0_data_r ) {
+ return RP5H01_data_r( 0 );
+}
diff --git a/src/emu/machine/rp5h01.h b/src/emu/machine/rp5h01.h
new file mode 100644
index 00000000000..b0bb3898c89
--- /dev/null
+++ b/src/emu/machine/rp5h01.h
@@ -0,0 +1,29 @@
+#ifndef __RP5H01_H__
+#define __RP5H01_H__
+
+/* max simultaneous chips supported. change if you need more */
+#define MAX_RP5H01 1
+
+struct RP5H01_interface {
+ int num; /* number of chips */
+ int region[MAX_RP5H01]; /* memory region where data resides */
+ int offset[MAX_RP5H01]; /* memory offset within the above region where data resides */
+};
+
+int RP5H01_init( struct RP5H01_interface *interface );
+void RP5H01_enable_w( int which, int data ); /* /CE */
+void RP5H01_reset_w( int which, int data ); /* RESET */
+void RP5H01_clock_w( int which, int data ); /* DATA CLOCK (active low) */
+void RP5H01_test_w( int which, int data ); /* TEST */
+int RP5H01_counter_r( int which ); /* COUNTER OUT */
+int RP5H01_data_r( int which ); /* DATA */
+
+/* direct-access stubs */
+WRITE8_HANDLER( RP5H01_0_enable_w );
+WRITE8_HANDLER( RP5H01_0_reset_w );
+WRITE8_HANDLER( RP5H01_0_clock_w );
+WRITE8_HANDLER( RP5H01_0_test_w );
+READ8_HANDLER( RP5H01_0_counter_r );
+READ8_HANDLER( RP5H01_0_data_r );
+
+#endif /* __RP5H01_H__ */
diff --git a/src/emu/machine/rtc65271.c b/src/emu/machine/rtc65271.c
new file mode 100644
index 00000000000..5352a91c6d5
--- /dev/null
+++ b/src/emu/machine/rtc65271.c
@@ -0,0 +1,654 @@
+/*
+ rtc65271 emulation
+
+ This chip is an RTC for computer built by Epson and Spezial-Electronic (I
+ think SE is the second source here).
+
+ Reference:
+ * Realtime Clock Module RTC-65271 Application Manual
+ <http://www.bgmicro.com/pdf/rtc65271.pdf>
+
+ Todo:
+ * Support square wave pin output?
+ * Support DSE mode?
+
+ Raphael Nabet, 2003-2004
+*/
+
+#include "driver.h"
+#include "rtc65271.h"
+
+static void field_interrupts(void);
+static TIMER_CALLBACK( rtc_SQW_callback );
+static TIMER_CALLBACK( rtc_begin_update_callback );
+static TIMER_CALLBACK( rtc_end_update_callback );
+
+/* Delay between the beginning (UIP asserted) and the end (UIP cleared and
+update interrupt asserted) of the update cycle */
+#define UPDATE_CYCLE_TIME ATTOTIME_IN_USEC(1984)
+/* Delay between the assertion of UIP and the effective start of the update
+cycle */
+/*#define UPDATE_CYCLE_DELAY ATTOTIME_IN_USEC(244)*/
+
+static struct
+{
+ /* 64 8-bit registers (10 clock registers, 4 control/status registers, and
+ 50 bytes of user RAM) */
+ UINT8 regs[64];
+ int cur_reg;
+
+ /* extended RAM: 4kbytes of battery-backed RAM (in pages of 32 bytes) */
+ UINT8 *xram;
+ int cur_xram_page;
+
+ /* update timer: called every second */
+ emu_timer *update_timer;
+
+ /* SQW timer: called every periodic clock half-period */
+ emu_timer *SQW_timer;
+ int SQW_internal_state;
+
+ /* callback called when interrupt pin state changes (may be NULL) */
+ void (*interrupt_callback)(int state);
+} rtc;
+
+enum
+{
+ reg_second = 0,
+ reg_alarm_second,
+ reg_minute,
+ reg_alarm_minute,
+ reg_hour,
+ reg_alarm_hour,
+ reg_weekday,
+ reg_monthday,
+ reg_month,
+ reg_year,
+ reg_A,
+ reg_B,
+ reg_C,
+ reg_D
+};
+
+enum
+{
+ reg_A_UIP = 0x80,
+ reg_A_DV = 0x70,
+ reg_A_RS = 0x0F,
+
+ reg_B_SET = 0x80,
+ reg_B_PIE = 0x40,
+ reg_B_AIE = 0x20,
+ reg_B_UIE = 0x10,
+ reg_B_SQW = 0x08,
+ reg_B_DM = 0x04,
+ reg_B_24h = 0x02,
+ reg_B_DSE = 0x01,
+
+ reg_C_IRQF = 0x80,
+ reg_C_PF = 0x40,
+ reg_C_AF = 0x20,
+ reg_C_UF = 0x10,
+
+ reg_D_VRT = 0x80
+};
+
+static const int SQW_freq_table[16] =
+{
+ 0,
+ 256,
+ 128,
+ 8192,
+ 4096,
+ 2048,
+ 1024,
+ 512,
+ 256,
+ 128,
+ 64,
+ 32,
+ 16,
+ 8,
+ 4,
+ 2,
+};
+
+
+/*
+ BCD utilities
+*/
+
+/*
+ Increment a binary-encoded UINT8
+*/
+static UINT8 increment_binary(UINT8 data)
+{
+ return data+1;
+}
+
+
+/*
+ Increment a BCD-encoded UINT8
+*/
+static UINT8 increment_BCD(UINT8 data)
+{
+ if ((data & 0x0f) < 0x09)
+ {
+ if ((data & 0xf0) < 0xa0)
+ data++;
+ else
+ data = data + 0x01 - 0xa0;
+ }
+ else
+ {
+ if ((data & 0xf0) < 0xa0)
+ data = data - 0x09 + 0x10;
+ else
+ data = data - 0x09 - 0x90;
+ }
+ return data;
+}
+
+
+/*
+ Convert a binary-encoded UINT8 to BCD
+*/
+static UINT8 binary_to_BCD(UINT8 data)
+{
+ data %= 100;
+
+ return ((data / 10) << 4) | (data %10);
+}
+
+
+/*
+ Convert a BCD-encoded UINT8 to binary
+*/
+static UINT8 BCD_to_binary(UINT8 data)
+{
+ if ((data & 0x0f) >= 0x0a)
+ data = data - 0x0a + 0x10;
+ if ((data & 0xf0) >= 0xa0)
+ data = data - 0xa0;
+
+ return (data & 0x0f) + (((data & 0xf0) >> 4) * 10);
+}
+
+
+/*
+ Public functions
+*/
+
+
+/*
+ load the SRAM and register contents from file
+*/
+int rtc65271_file_load(mame_file *file)
+{
+ UINT8 buf;
+
+
+ /* version flag */
+ if (mame_fread(file, & buf, 1) != 1)
+ return 1;
+ if (buf != 0)
+ return 1;
+
+ /* control registers */
+ if (mame_fread(file, &buf, 1) != 1)
+ return 1;
+ rtc.regs[reg_A] = buf & (reg_A_DV /*| reg_A_RS*/);
+ if (mame_fread(file, &buf, 1) != 1)
+ return 1;
+ rtc.regs[reg_B] = buf & (reg_B_SET | reg_B_DM | reg_B_24h | reg_B_DSE);
+
+ /* alarm registers */
+ if (mame_fread(file, &rtc.regs[reg_alarm_second], 1) != 1)
+ return 1;
+ if (mame_fread(file, &rtc.regs[reg_alarm_minute], 1) != 1)
+ return 1;
+ if (mame_fread(file, &rtc.regs[reg_alarm_hour], 1) != 1)
+ return 1;
+
+ /* user RAM */
+ if (mame_fread(file, rtc.regs+14, 50) != 50)
+ return 1;
+
+ /* extended RAM */
+ if (mame_fread(file, rtc.xram, 4096) != 4096)
+ return 1;
+
+ rtc.regs[reg_D] |= reg_D_VRT; /* the data was backed up successfully */
+ /*rtc.dirty = FALSE;*/
+
+ {
+ mame_system_time systime;
+
+ /* get the current date/time from the core */
+ mame_get_current_datetime(Machine, &systime);
+
+ /* set clock registers */
+ rtc.regs[reg_second] = systime.local_time.second;
+ rtc.regs[reg_minute] = systime.local_time.minute;
+ if (rtc.regs[reg_B] & reg_B_24h)
+ /* 24-hour mode */
+ rtc.regs[reg_hour] = systime.local_time.hour;
+ else
+ { /* 12-hour mode */
+ if (systime.local_time.hour >= 12)
+ {
+ rtc.regs[reg_hour] = 0x80;
+ systime.local_time.hour -= 12;
+ }
+ else
+ rtc.regs[reg_hour] = 0;
+ rtc.regs[reg_hour] |= systime.local_time.hour ? systime.local_time.hour : 12;
+ }
+ rtc.regs[reg_weekday] = systime.local_time.weekday + 1;
+ rtc.regs[reg_monthday] = systime.local_time.mday;
+ rtc.regs[reg_month] = systime.local_time.month + 1;
+ rtc.regs[reg_year] = systime.local_time.year % 100;
+ if (! (rtc.regs[reg_B] & reg_B_DM))
+ { /* BCD mode */
+ rtc.regs[reg_second] = binary_to_BCD(rtc.regs[reg_second]);
+ rtc.regs[reg_minute] = binary_to_BCD(rtc.regs[reg_minute]);
+ rtc.regs[reg_hour] = (rtc.regs[reg_hour] & 0x80) | binary_to_BCD(rtc.regs[reg_hour] & 0x7f);
+ /*rtc.regs[reg_weekday] = binary_to_BCD(rtc.regs[reg_weekday]);*/
+ rtc.regs[reg_monthday] = binary_to_BCD(rtc.regs[reg_monthday]);
+ rtc.regs[reg_month] = binary_to_BCD(rtc.regs[reg_month]);
+ rtc.regs[reg_year] = binary_to_BCD(rtc.regs[reg_year]);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ save the SRAM and register contents to file
+*/
+int rtc65271_file_save(mame_file *file)
+{
+ UINT8 buf;
+
+
+ /* version flag */
+ buf = 0;
+ if (mame_fwrite(file, & buf, 1) != 1)
+ return 1;
+
+ /* control registers */
+ buf = rtc.regs[reg_A] & (reg_A_DV | reg_A_RS);
+ if (mame_fwrite(file, &buf, 1) != 1)
+ return 1;
+ buf = rtc.regs[reg_B] & (reg_B_SET | reg_B_DM | reg_B_24h | reg_B_DSE);
+ if (mame_fwrite(file, &buf, 1) != 1)
+ return 1;
+
+ /* alarm registers */
+ if (mame_fwrite(file, &rtc.regs[reg_alarm_second], 1) != 1)
+ return 1;
+ if (mame_fwrite(file, &rtc.regs[reg_alarm_minute], 1) != 1)
+ return 1;
+ if (mame_fwrite(file, &rtc.regs[reg_alarm_hour], 1) != 1)
+ return 1;
+
+ /* user RAM */
+ if (mame_fwrite(file, rtc.regs+14, 50) != 50)
+ return 1;
+
+ /* extended RAM */
+ if (mame_fwrite(file, rtc.xram, 4096) != 4096)
+ return 1;
+
+ return 0;
+}
+
+/*
+ Initialize clock
+
+ xram: pointer to 4kb RAM area
+ interrupt_callback: callback called when interrupt pin state changes (may
+ be NULL)
+*/
+void rtc65271_init(UINT8 *xram, void (*interrupt_callback)(int state))
+{
+ memset(&rtc, 0, sizeof(rtc));
+
+ rtc.xram = xram;
+
+ rtc.update_timer = timer_alloc(rtc_begin_update_callback);
+ timer_adjust(rtc.update_timer, ATTOTIME_IN_SEC(1), 0, ATTOTIME_IN_SEC(1));
+ rtc.SQW_timer = timer_alloc(rtc_SQW_callback);
+ rtc.interrupt_callback = interrupt_callback;
+}
+
+/*
+ Read a byte from clock
+
+ xramsel: select RTC register if 0, XRAM if 1
+ offset: address (A0-A5 pins)
+*/
+UINT8 rtc65271_r(int xramsel, offs_t offset)
+{
+ int reply;
+
+ if (xramsel)
+ {
+ if (offset & 0x20)
+ /* XRAM page register */
+ reply = rtc.cur_xram_page;
+ else
+ /* XRAM data */
+ reply = rtc.xram[(offset & 0x1f) + 0x0020*rtc.cur_xram_page];
+ }
+ else
+ {
+ if (offset & 0x01)
+ /* data register */
+ switch (rtc.cur_reg)
+ {
+ case reg_C:
+ reply = rtc.regs[rtc.cur_reg];
+ rtc.regs[rtc.cur_reg] = 0;
+ field_interrupts();
+ break;
+ case reg_D:
+ reply = rtc.regs[rtc.cur_reg];
+ rtc.regs[rtc.cur_reg] = /*0*/reg_D_VRT; /* set VRT flag so that the computer does not complain that the battery is low */
+ break;
+
+ default:
+ reply = rtc.regs[rtc.cur_reg];
+ break;
+ }
+ else
+ /* indirect address register */
+ reply = rtc.cur_reg;
+ }
+
+ return reply;
+}
+
+
+/*
+ Read a byte from clock
+
+ xramsel: select RTC register if 0, XRAM if 1
+ offset: address (A0-A5 pins)
+*/
+void rtc65271_w(int xramsel, offs_t offset, UINT8 data)
+{
+ if (xramsel)
+ {
+ if (offset & 0x20)
+ /* XRAM page register */
+ rtc.cur_xram_page = data & 0x7f;
+ else
+ /* XRAM data */
+ rtc.xram[(offset & 0x1f) + 0x0020*rtc.cur_xram_page] = data;
+ }
+ else
+ {
+ if (offset & 0x01)
+ /* data register */
+ switch (rtc.cur_reg)
+ {
+ case reg_second:
+ /* the data sheet says bit 7 is read-only. (I have no idea of
+ the reason why it is.) */
+ rtc.regs[reg_second] = data & 0x7f;
+ break;
+
+ case reg_A:
+ if ((data & reg_A_RS) != (rtc.regs[rtc.cur_reg] & reg_A_RS))
+ {
+ if (data & reg_A_RS)
+ {
+ attotime period = ATTOTIME_IN_HZ(SQW_freq_table[data & reg_A_RS]);
+ attotime half_period = attotime_div(period, 2);
+ attotime elapsed = timer_timeelapsed(rtc.update_timer);
+
+ if (attotime_compare(half_period, elapsed) > 0)
+ timer_adjust(rtc.SQW_timer, attotime_sub(half_period, elapsed), 0, attotime_never);
+ else
+ timer_adjust(rtc.SQW_timer, half_period, 0, attotime_never);
+ }
+ else
+ {
+ rtc.SQW_internal_state = 0; /* right??? */
+
+ /* Stop the divider used for SQW and periodic interrupts. */
+ timer_adjust(rtc.SQW_timer, attotime_never, 0, attotime_never);
+ }
+ }
+ /* The UIP bit is read-only */
+ rtc.regs[reg_A] = (data & ~reg_A_UIP) | (rtc.regs[reg_A] & reg_A_UIP);
+ break;
+
+ case reg_B:
+ rtc.regs[rtc.cur_reg] = data;
+ if (data & reg_B_SET)
+ {
+ /* if we are in SET mode, clear update cycle */
+ rtc.regs[reg_A] &= ~reg_A_UIP;
+ rtc.regs[reg_B] &= ~reg_B_UIE; /* the data sheet tells this, but I wonder how much sense it makes */
+ field_interrupts();
+ }
+ break;
+
+ case reg_C:
+ case reg_D:
+ break;
+
+ default:
+ rtc.regs[rtc.cur_reg] = data;
+ break;
+ }
+ else
+ /* indirect address register */
+ rtc.cur_reg = data & 0x3f;
+ }
+}
+
+static void field_interrupts(void)
+{
+ if (rtc.regs[reg_C] & rtc.regs[reg_B] & (reg_C_PF | reg_C_AF | reg_C_UF))
+ {
+ rtc.regs[reg_C] |= reg_C_IRQF;
+ if (rtc.interrupt_callback)
+ rtc.interrupt_callback(1);
+ }
+ else
+ {
+ rtc.regs[reg_C] &= ~reg_C_IRQF;
+ if (rtc.interrupt_callback)
+ rtc.interrupt_callback(0);
+ }
+}
+
+
+/*
+ Timer handlers
+*/
+
+/*
+ Update SQW output state each half-period and assert periodic interrupt each
+ period.
+*/
+static TIMER_CALLBACK( rtc_SQW_callback )
+{
+ attotime half_period;
+
+ rtc.SQW_internal_state = ! rtc.SQW_internal_state;
+ if (! rtc.SQW_internal_state)
+ {
+ /* high-to-low??? transition -> interrupt (or should it be low-to-high?) */
+ rtc.regs[reg_C] |= reg_C_PF;
+ field_interrupts();
+ }
+
+ half_period = attotime_div(ATTOTIME_IN_HZ(SQW_freq_table[rtc.regs[reg_A] & reg_A_RS]), 2);
+ timer_adjust(rtc.SQW_timer, half_period, 0, attotime_never);
+}
+
+/*
+ Begin update cycle (called every second)
+*/
+static TIMER_CALLBACK( rtc_begin_update_callback )
+{
+ if (((rtc.regs[reg_A] & reg_A_DV) == 0x20) && ! (rtc.regs[reg_B] & reg_B_SET))
+ {
+ rtc.regs[reg_A] |= reg_A_UIP;
+
+ /* schedule end of update cycle */
+ timer_set(UPDATE_CYCLE_TIME, 0, rtc_end_update_callback);
+ }
+}
+
+/*
+ End update cycle (called UPDATE_CYCLE_TIME = 1948us after start of update
+ cycle)
+*/
+static TIMER_CALLBACK( rtc_end_update_callback )
+{
+ static const int days_in_month_table[12] =
+ {
+ 31,28,31, 30,31,30,
+ 31,31,30, 31,30,31
+ };
+ UINT8 (*increment)(UINT8 data);
+ int c59, c23, c12, c11, c29;
+
+ if (! (rtc.regs[reg_A] & reg_A_UIP))
+ /* abort if update cycle has been canceled */
+ return;
+
+ if (rtc.regs[reg_B] & reg_B_DM)
+ {
+ /* binary mode */
+ increment = increment_binary;
+ c59 = 59;
+ c23 = 23;
+ c12 = 12;
+ c11 = 11;
+ c29 = 29;
+ }
+ else
+ {
+ /* BCD mode */
+ increment = increment_BCD;
+ c59 = 0x59;
+ c23 = 0x23;
+ c12 = 0x12;
+ c11 = 0x11;
+ c29 = 0x29;
+ }
+
+ /* increment second */
+ if (rtc.regs[reg_second] < c59)
+ rtc.regs[reg_second] = (*increment)(rtc.regs[reg_second]);
+ else
+ {
+ rtc.regs[reg_second] = 0;
+
+ /* increment minute */
+ if (rtc.regs[reg_minute] < c59)
+ rtc.regs[reg_minute] = (*increment)(rtc.regs[reg_minute]);
+ else
+ {
+ rtc.regs[reg_minute] = 0;
+
+ /* increment hour */
+ if (rtc.regs[reg_B] & reg_B_24h)
+ {
+ /* 24 hour mode */
+ if (rtc.regs[reg_hour] < c23)
+ rtc.regs[reg_hour] = (*increment)(rtc.regs[reg_hour]);
+ else
+ rtc.regs[reg_hour] = 0;
+ }
+ else
+ {
+ /* 12 hour mode */
+ if (rtc.regs[reg_hour] < c12)
+ {
+ if ((rtc.regs[reg_hour] & 0x7f) == c11)
+ rtc.regs[reg_hour] ^= 0x80;
+ rtc.regs[reg_hour] = ((*increment)(rtc.regs[reg_hour] & 0x7f) & 0x7f)
+ | (rtc.regs[reg_hour] & 0x80);
+ }
+ else
+ rtc.regs[reg_hour] = 1 | (rtc.regs[reg_hour] & 0x80);
+ }
+
+ /* increment day if needed */
+ if (rtc.regs[reg_hour] == ((rtc.regs[reg_B] & reg_B_24h) ? 0 : c12))
+ {
+ /* increment day */
+ int days_in_month;
+
+ if (rtc.regs[reg_weekday] < 7)
+ rtc.regs[reg_weekday]++;
+ else
+ rtc.regs[reg_weekday] = 1;
+
+ if ((rtc.regs[reg_month] != 2) || (rtc.regs[reg_year] & 0x03))
+ {
+ if (rtc.regs[reg_B] & reg_B_DM)
+ {
+ /* binary mode */
+ days_in_month = days_in_month_table[rtc.regs[reg_month] - 1];
+ }
+ else
+ {
+ /* BCD mode */
+ days_in_month = binary_to_BCD(days_in_month_table[BCD_to_binary(rtc.regs[reg_month]) - 1]);
+ }
+ }
+ else
+ days_in_month = c29;
+
+ if (rtc.regs[reg_monthday] < days_in_month)
+ rtc.regs[reg_monthday] = (*increment)(rtc.regs[reg_monthday]);
+ else
+ {
+ /* increment month */
+ rtc.regs[reg_monthday] = 1;
+
+ if (rtc.regs[reg_month] < c12)
+ rtc.regs[reg_month] = (*increment)(rtc.regs[reg_month]);
+ else
+ {
+ /* increment year */
+ rtc.regs[reg_month] = 1;
+
+ if (rtc.regs[reg_B] & reg_B_DM)
+ {
+ /* binary mode */
+ if (rtc.regs[reg_year] < 99)
+ rtc.regs[reg_year]++;
+ else
+ rtc.regs[reg_year] = 0;
+ }
+ else
+ {
+ /* BCD mode */
+ rtc.regs[reg_year] = increment_BCD(rtc.regs[reg_year]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ rtc.regs[reg_A] &= ~reg_A_UIP;
+ rtc.regs[reg_C] |= reg_C_UF;
+
+ /* test for alarm (values in range 0xc0-0xff mean "don't care") */
+ if ((((rtc.regs[reg_alarm_second] & 0xc0) == 0xc0) || (rtc.regs[reg_alarm_second] == rtc.regs[reg_second]))
+ && (((rtc.regs[reg_alarm_minute] & 0xc0) == 0xc0) || (rtc.regs[reg_alarm_minute] == rtc.regs[reg_minute]))
+ && (((rtc.regs[reg_alarm_hour] & 0xc0) == 0xc0) || (rtc.regs[reg_alarm_hour] == rtc.regs[reg_hour])))
+ rtc.regs[reg_C] |= reg_C_AF;
+
+ field_interrupts();
+}
diff --git a/src/emu/machine/rtc65271.h b/src/emu/machine/rtc65271.h
new file mode 100644
index 00000000000..34aedbbd410
--- /dev/null
+++ b/src/emu/machine/rtc65271.h
@@ -0,0 +1,9 @@
+/*
+ rtc65271.h: include file for rtc65271.c
+*/
+
+extern int rtc65271_file_load(mame_file *file);
+extern int rtc65271_file_save(mame_file *file);
+extern void rtc65271_init(UINT8 *xram, void (*interrupt_callback)(int state));
+extern UINT8 rtc65271_r(int xramsel, offs_t offset);
+extern void rtc65271_w(int xramsel, offs_t offset, UINT8 data);
diff --git a/src/emu/machine/scsi.c b/src/emu/machine/scsi.c
new file mode 100644
index 00000000000..f01f60d5390
--- /dev/null
+++ b/src/emu/machine/scsi.c
@@ -0,0 +1,119 @@
+#include "scsi.h"
+
+void SCSIAllocInstance( SCSIClass *scsiClass, SCSIInstance **instance, int diskId )
+{
+ scsiClass->dispatch( SCSIOP_ALLOC_INSTANCE, scsiClass, diskId, instance );
+}
+
+void SCSIDeleteInstance( SCSIInstance *instance )
+{
+ instance->scsiClass->dispatch( SCSIOP_DELETE_INSTANCE, instance, 0, NULL );
+}
+
+void SCSISetDevice( SCSIInstance *instance, void *device )
+{
+ instance->scsiClass->dispatch( SCSIOP_SET_DEVICE, instance, 0, device );
+}
+
+void SCSIGetDevice( SCSIInstance *instance, void **device )
+{
+ instance->scsiClass->dispatch( SCSIOP_GET_DEVICE, instance, 0, device );
+}
+
+void SCSIReset( SCSIInstance *instance )
+{
+ instance->scsiClass->dispatch( SCSIOP_RESET_DEVICE, instance, 0, NULL );
+}
+
+void SCSIExecCommand( SCSIInstance *instance, int *resultLength )
+{
+ *resultLength = instance->scsiClass->dispatch( SCSIOP_EXEC_COMMAND, instance, 0, NULL );
+}
+
+void SCSISetCommand( SCSIInstance *instance, UINT8 *command, int commandLength )
+{
+ instance->scsiClass->dispatch( SCSIOP_SET_COMMAND, instance, commandLength, command );
+}
+
+void SCSIGetCommand( SCSIInstance *instance, UINT8 **command, int *commandLength )
+{
+ *commandLength = instance->scsiClass->dispatch( SCSIOP_GET_COMMAND, instance, 0, command );
+}
+
+void SCSIWriteData( SCSIInstance *instance, void *data, int dataLength )
+{
+ instance->scsiClass->dispatch( SCSIOP_WRITE_DATA, instance, dataLength, data );
+}
+
+void SCSIReadData( SCSIInstance *instance, void *data, int dataLength )
+{
+ instance->scsiClass->dispatch( SCSIOP_READ_DATA, instance, dataLength, data );
+}
+
+void SCSISetPhase( SCSIInstance *instance, int phase )
+{
+ instance->scsiClass->dispatch( SCSIOP_SET_PHASE, instance, phase, NULL );
+}
+
+void SCSIGetPhase( SCSIInstance *instance, int *phase )
+{
+ *phase = instance->scsiClass->dispatch( SCSIOP_GET_PHASE, instance, 0, NULL );
+}
+
+int SCSIBase( SCSIClass *scsiClass, int operation, void *file, INT64 intparm, UINT8 *ptrparm )
+{
+ return scsiClass->baseClass->dispatch( operation, file, intparm, ptrparm );
+}
+
+SCSIInstance *SCSIMalloc( SCSIClass *scsiClass )
+{
+ SCSIInstance *scsiInstance = (SCSIInstance *) malloc_or_die( SCSISizeof( scsiClass ) );
+ scsiInstance->scsiClass = scsiClass;
+ return scsiInstance;
+}
+
+void *SCSIThis( SCSIClass *scsiClass, SCSIInstance *instance )
+{
+ if( instance != NULL )
+ {
+ int sizeofBase = sizeof( SCSIInstance );
+
+ while( scsiClass->baseClass != NULL )
+ {
+ scsiClass = scsiClass->baseClass;
+ sizeofBase += scsiClass->sizeofData;
+ }
+
+ return ( (UINT8*)instance ) + sizeofBase;
+ }
+
+ return NULL;
+}
+
+int SCSISizeof( SCSIClass *scsiClass )
+{
+ int sizeofData = sizeof( SCSIInstance );
+
+ while( scsiClass != NULL )
+ {
+ sizeofData += scsiClass->sizeofData;
+ scsiClass = scsiClass->baseClass;
+ }
+
+ return sizeofData;
+}
+
+int SCSILengthFromUINT8( UINT8 *length )
+{
+ if( *length == 0 )
+ {
+ return 256;
+ }
+
+ return *length;
+}
+
+int SCSILengthFromUINT16( UINT8 *length )
+{
+ return ( *(length) << 8 ) | *(length + 1 );
+}
diff --git a/src/emu/machine/scsi.h b/src/emu/machine/scsi.h
new file mode 100644
index 00000000000..7097cf38147
--- /dev/null
+++ b/src/emu/machine/scsi.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+
+ scsi.h - Header which defines the interface between SCSI device handlers
+ and SCSI interfaces.
+
+***************************************************************************/
+
+#ifndef _SCSI_H_
+#define _SCSI_H_
+
+#include "driver.h"
+
+typedef int (*pSCSIDispatch)( int operation, void *file, INT64 intparm, void *ptrparm );
+
+typedef struct _SCSIClass
+{
+ struct _SCSIClass *baseClass;
+ pSCSIDispatch dispatch;
+ int sizeofData;
+} SCSIClass;
+
+typedef struct
+{
+ SCSIClass *scsiClass;
+} SCSIInstance;
+
+// commands accepted by a SCSI device's dispatch handler
+enum
+{
+ SCSIOP_EXEC_COMMAND = 0, // execute a command packet
+ SCSIOP_SET_COMMAND, // set a command packet
+ SCSIOP_GET_COMMAND, // get a command packet
+ SCSIOP_READ_DATA, // data transfer from the device
+ SCSIOP_WRITE_DATA, // data transfer to the device
+ SCSIOP_ALLOC_INSTANCE, // allocate an instance of the device
+ SCSIOP_DELETE_INSTANCE, // delete an instance of the device
+ SCSIOP_GET_DEVICE, // get the device's internal device (CDROM or HDD pointer)
+ SCSIOP_SET_DEVICE, // set the device's internal device (CDROM or HDD pointer)
+ SCSIOP_RESET_DEVICE, // reset the device
+ SCSIOP_SET_PHASE,
+ SCSIOP_GET_PHASE,
+};
+
+typedef struct scsiconfigitem
+{
+ int scsiID;
+ int diskID;
+ SCSIClass *scsiClass;
+} SCSIConfigItem;
+
+#define SCSI_MAX_DEVICES (16)
+
+typedef struct scsiconfigtable
+{
+ int devs_present;
+ SCSIConfigItem devices[SCSI_MAX_DEVICES];
+} SCSIConfigTable;
+
+// SCSI IDs
+enum
+{
+ SCSI_ID_0 = 0,
+ SCSI_ID_1,
+ SCSI_ID_2,
+ SCSI_ID_3,
+ SCSI_ID_4,
+ SCSI_ID_5,
+ SCSI_ID_6,
+ SCSI_ID_7
+};
+
+
+#define SCSI_PHASE_DATAOUT ( 0 )
+#define SCSI_PHASE_DATAIN ( 1 )
+#define SCSI_PHASE_COMMAND ( 2 )
+#define SCSI_PHASE_STATUS ( 3 )
+#define SCSI_PHASE_MESSAGE_OUT ( 6 )
+#define SCSI_PHASE_MESSAGE_IN ( 7 )
+
+extern void SCSIAllocInstance( SCSIClass *scsiClass, SCSIInstance **instance, int diskId );
+extern void SCSIDeleteInstance( SCSIInstance *instance );
+extern void SCSISetDevice( SCSIInstance *instance, void *device );
+extern void SCSIGetDevice( SCSIInstance *instance, void **device );
+extern void SCSIReset( SCSIInstance *instance );
+extern void SCSISetCommand( SCSIInstance *instance, UINT8 *command, int commandLength );
+extern void SCSIGetCommand( SCSIInstance *instance, UINT8 **command, int *commandLength );
+extern void SCSIExecCommand( SCSIInstance *instance, int *resultLength );
+extern void SCSIWriteData( SCSIInstance *instance, void *data, int dataLength );
+extern void SCSIReadData( SCSIInstance *instance, void *data, int dataLength );
+extern void SCSISetPhase( SCSIInstance *instance, int phase );
+extern void SCSIGetPhase( SCSIInstance *instance, int *phase );
+
+extern SCSIInstance *SCSIMalloc( SCSIClass *scsiClass );
+extern int SCSIBase( SCSIClass *scsiClass, int operation, void *file, INT64 intparm, UINT8 *ptrparm );
+extern void *SCSIThis( SCSIClass *scsiClass, SCSIInstance *instance );
+extern int SCSISizeof( SCSIClass *scsiClass );
+extern int SCSILengthFromUINT8( UINT8 *length );
+extern int SCSILengthFromUINT16( UINT8 *length );
+
+#endif
+
+// include these here to avoid changing the drivers.
+#include "machine/scsicd.h"
+#include "machine/scsihd.h"
diff --git a/src/emu/machine/scsicd.c b/src/emu/machine/scsicd.c
new file mode 100644
index 00000000000..b611eac5614
--- /dev/null
+++ b/src/emu/machine/scsicd.c
@@ -0,0 +1,768 @@
+/***************************************************************************
+
+ scsicd.c - Implementation of a SCSI CD-ROM device, using MAME's cdrom.c primitives
+
+***************************************************************************/
+
+#include "state.h"
+#include "scsidev.h"
+#include "cdrom.h"
+#include "sound/cdda.h"
+#ifdef MESS
+#include "devices/chd_cd.h"
+#endif
+
+typedef struct
+{
+ UINT32 lba;
+ UINT32 blocks;
+ UINT32 last_lba;
+ UINT32 bytes_per_sector;
+ UINT32 num_subblocks;
+ UINT32 cur_subblock;
+ UINT32 play_err_flag;
+ cdrom_file *cdrom;
+} SCSICd;
+
+static void phys_frame_to_msf(int phys_frame, int *m, int *s, int *f)
+{
+ *m = phys_frame / (60*75);
+ phys_frame -= (*m * 60 * 75);
+ *s = phys_frame / 75;
+ *f = phys_frame % 75;
+}
+
+
+// scsicd_exec_command
+//
+// Execute a SCSI command.
+
+static int scsicd_exec_command( SCSIInstance *scsiInstance, UINT8 *statusCode )
+{
+ UINT8 *command;
+ int commandLength;
+ SCSICd *our_this = SCSIThis( &SCSIClassCDROM, scsiInstance );
+
+ cdrom_file *cdrom = our_this->cdrom;
+ int cddanum;
+ int trk;
+
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch ( command[0] )
+ {
+ case 0x03: // REQUEST SENSE
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return SCSILengthFromUINT8( &command[ 4 ] );
+
+ case 0x12: // INQUIRY
+ logerror("SCSICD: REQUEST SENSE\n");
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return SCSILengthFromUINT8( &command[ 4 ] );
+
+ case 0x15: // MODE SELECT(6)
+ logerror("SCSICD: MODE SELECT(6) length %x control %x\n", command[4], command[5]);
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAOUT );
+ return SCSILengthFromUINT8( &command[ 4 ] );
+
+ case 0x1a: // MODE SENSE(6)
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return SCSILengthFromUINT8( &command[ 4 ] );
+
+ case 0x1b: // START STOP UNIT
+ cddanum = cdda_num_from_cdrom(cdrom);
+ if (cddanum != -1)
+ {
+ cdda_stop_audio(cddanum);
+ }
+ SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
+ return 0;
+
+ case 0x1e: // PREVENT ALLOW MEDIUM REMOVAL
+ SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
+ return 0;
+
+ case 0x25: // READ CAPACITY
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return 8;
+
+ case 0x28: // READ(10)
+
+ our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ our_this->blocks = SCSILengthFromUINT16( &command[7] );
+
+ logerror("SCSICD: READ(10) at LBA %x for %d blocks (%d bytes)\n", our_this->lba, our_this->blocks, our_this->blocks * our_this->bytes_per_sector);
+
+ if (our_this->num_subblocks > 1)
+ {
+ our_this->cur_subblock = our_this->lba % our_this->num_subblocks;
+ our_this->lba /= our_this->num_subblocks;
+ }
+ else
+ {
+ our_this->cur_subblock = 0;
+ }
+
+ cddanum = cdda_num_from_cdrom(cdrom);
+ if (cddanum != -1)
+ {
+ cdda_stop_audio(cddanum);
+ }
+
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return our_this->blocks * our_this->bytes_per_sector;
+
+ case 0x42: // READ SUB-CHANNEL
+// logerror("SCSICD: READ SUB-CHANNEL type %d\n", command[3]);
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return SCSILengthFromUINT16( &command[ 7 ] );
+
+ case 0x43: // READ TOC
+ {
+ int start_trk = command[6];
+ int end_trk = cdrom_get_last_track(cdrom);
+ int length;
+ int allocation_length = SCSILengthFromUINT16( &command[ 7 ] );
+
+ if( start_trk == 0 )
+ {
+ start_trk = 1;
+ }
+ if( start_trk == 0xaa )
+ {
+ end_trk = start_trk;
+ }
+
+ length = 4 + ( 8 * ( ( end_trk - start_trk ) + 1 ) );
+ if( length > allocation_length )
+ {
+ length = allocation_length;
+ }
+ else if( length < 4 )
+ {
+ length = 4;
+ }
+
+ cddanum = cdda_num_from_cdrom(cdrom);
+ if (cddanum != -1)
+ {
+ cdda_stop_audio(cddanum);
+ }
+
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return length;
+ }
+ case 0x45: // PLAY AUDIO(10)
+ our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ our_this->blocks = SCSILengthFromUINT16( &command[7] );
+
+ // special cases: lba of 0 means MSF of 00:02:00
+ if (our_this->lba == 0)
+ {
+ our_this->lba = 150;
+ }
+ else if (our_this->lba == 0xffffffff)
+ {
+ logerror("SCSICD: play audio from current not implemented!\n");
+ }
+
+ logerror("SCSICD: PLAY AUDIO(10) at LBA %x for %x blocks\n", our_this->lba, our_this->blocks);
+
+ trk = cdrom_get_track(cdrom, our_this->lba);
+
+ if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO)
+ {
+ our_this->play_err_flag = 0;
+ cddanum = cdda_num_from_cdrom(cdrom);
+ if (cddanum != -1)
+ cdda_start_audio(cddanum, our_this->lba, our_this->blocks);
+ }
+ else
+ {
+ logerror("SCSICD: track is NOT audio!\n");
+ our_this->play_err_flag = 1;
+ }
+
+ SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
+ return 0;
+
+ case 0x48: // PLAY AUDIO TRACK/INDEX
+ // be careful: tracks here are zero-based, but the SCSI command
+ // uses the real CD track number which is 1-based!
+ our_this->lba = cdrom_get_track_start(cdrom, command[4]-1);
+ our_this->blocks = cdrom_get_track_start(cdrom, command[7]-1) - our_this->lba;
+ if (command[4] > command[7])
+ {
+ our_this->blocks = 0;
+ }
+
+ if (command[4] == command[7])
+ {
+ our_this->blocks = cdrom_get_track_start(cdrom, command[4]) - our_this->lba;
+ }
+
+ if (our_this->blocks && cdrom)
+ {
+ cddanum = cdda_num_from_cdrom(cdrom);
+ if (cddanum != -1)
+ cdda_start_audio(cddanum, our_this->lba, our_this->blocks);
+ }
+
+ logerror("SCSICD: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], our_this->blocks);
+ SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
+ return 0;
+
+ case 0x4b: // PAUSE/RESUME
+ if (cdrom)
+ {
+ cddanum = cdda_num_from_cdrom(cdrom);
+ if (cddanum != -1)
+ cdda_pause_audio(cddanum, (command[8] & 0x01) ^ 0x01);
+ }
+
+ logerror("SCSICD: PAUSE/RESUME: %s\n", command[8]&1 ? "RESUME" : "PAUSE");
+ SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
+ return 0;
+
+ case 0x55: // MODE SELECT(10)
+ logerror("SCSICD: MODE SELECT length %x control %x\n", command[7]<<8 | command[8], command[1]);
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAOUT );
+ return SCSILengthFromUINT16( &command[ 7 ] );
+
+ case 0x5a: // MODE SENSE(10)
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return SCSILengthFromUINT16( &command[ 7 ] );
+
+ case 0xa5: // PLAY AUDIO(12)
+ our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ our_this->blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9];
+
+ // special cases: lba of 0 means MSF of 00:02:00
+ if (our_this->lba == 0)
+ {
+ our_this->lba = 150;
+ }
+ else if (our_this->lba == 0xffffffff)
+ {
+ logerror("SCSICD: play audio from current not implemented!\n");
+ }
+
+ logerror("SCSICD: PLAY AUDIO(12) at LBA %x for %x blocks\n", our_this->lba, our_this->blocks);
+
+ trk = cdrom_get_track(cdrom, our_this->lba);
+
+ if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO)
+ {
+ our_this->play_err_flag = 0;
+ cddanum = cdda_num_from_cdrom(cdrom);
+ if (cddanum != -1)
+ cdda_start_audio(cddanum, our_this->lba, our_this->blocks);
+ }
+ else
+ {
+ logerror("SCSICD: track is NOT audio!\n");
+ our_this->play_err_flag = 1;
+ }
+ SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
+ return 0;
+
+ case 0xa8: // READ(12)
+ our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ our_this->blocks = command[7]<<16 | command[8]<<8 | command[9];
+
+ logerror("SCSICD: READ(12) at LBA %x for %x blocks (%x bytes)\n", our_this->lba, our_this->blocks, our_this->blocks * our_this->bytes_per_sector);
+
+ if (our_this->num_subblocks > 1)
+ {
+ our_this->cur_subblock = our_this->lba % our_this->num_subblocks;
+ our_this->lba /= our_this->num_subblocks;
+ }
+ else
+ {
+ our_this->cur_subblock = 0;
+ }
+
+ cddanum = cdda_num_from_cdrom(cdrom);
+ if (cddanum != -1)
+ {
+ cdda_stop_audio(cddanum);
+ }
+
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return our_this->blocks * our_this->bytes_per_sector;
+
+ case 0xbb: // SET CD SPEED
+ logerror("SCSICD: SET CD SPEED to %d kbytes/sec.\n", command[2]<<8 | command[3]);
+ SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
+ return 0;
+
+ default:
+ return SCSIBase( &SCSIClassCDROM, SCSIOP_EXEC_COMMAND, scsiInstance, 0, NULL );
+ }
+}
+
+// scsicd_read_data
+//
+// Read data from the device resulting from the execution of a command
+
+static void scsicd_read_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
+{
+ UINT8 *command;
+ int commandLength;
+ SCSICd *our_this = SCSIThis( &SCSIClassCDROM, scsiInstance );
+
+ int i;
+ UINT32 last_phys_frame;
+ cdrom_file *cdrom = our_this->cdrom;
+ UINT32 temp;
+ UINT8 tmp_buffer[2048];
+ int cddanum;
+
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch ( command[0] )
+ {
+ case 0x03: // REQUEST SENSE
+ logerror("SCSICD: Reading REQUEST SENSE data\n");
+
+ memset( data, 0, dataLength );
+
+ data[0] = 0x71; // deferred error
+
+ cddanum = cdda_num_from_cdrom(cdrom);
+ if (cddanum != -1 && cdda_audio_active(cddanum))
+ {
+ data[12] = 0x00;
+ data[13] = 0x11; // AUDIO PLAY OPERATION IN PROGRESS
+ }
+ else if (our_this->play_err_flag)
+ {
+ our_this->play_err_flag = 0;
+ data[12] = 0x64; // ILLEGAL MODE FOR THIS TRACK
+ data[13] = 0x00;
+ }
+ // (else 00/00 means no error to report)
+ break;
+
+ case 0x12: // INQUIRY
+ memset( data, 0, dataLength );
+ data[0] = 0x05; // device is present, device is CD/DVD (MMC-3)
+ data[1] = 0x80; // media is removable
+ data[2] = 0x05; // device complies with SPC-3 standard
+ data[3] = 0x02; // response data format = SPC-3 standard
+ // some Konami games freak out if this isn't "Sony", so we'll lie
+ // this is the actual drive on my Nagano '98 board
+ strcpy((char *)&data[8], "Sony");
+ strcpy((char *)&data[16], "CDU-76S");
+ strcpy((char *)&data[32], "1.0");
+ break;
+
+ case 0x25: // READ CAPACITY
+ logerror("SCSICD: READ CAPACITY\n");
+
+ temp = cdrom_get_track_start(cdrom, 0xaa);
+ temp--; // return the last used block on the disc
+
+ data[0] = (temp>>24) & 0xff;
+ data[1] = (temp>>16) & 0xff;
+ data[2] = (temp>>8) & 0xff;
+ data[3] = (temp & 0xff);
+ data[4] = 0;
+ data[5] = 0;
+ data[6] = (our_this->bytes_per_sector>>8)&0xff;
+ data[7] = (our_this->bytes_per_sector & 0xff);
+ break;
+
+ case 0x28: // READ(10)
+ case 0xa8: // READ(12)
+ logerror("SCSICD: read %x dataLength, \n", dataLength);
+ if ((our_this->cdrom) && (our_this->blocks))
+ {
+ while (dataLength > 0)
+ {
+ if (!cdrom_read_data(our_this->cdrom, our_this->lba, tmp_buffer, CD_TRACK_MODE1))
+ {
+ logerror("SCSICD: CD read error!\n");
+ }
+
+ logerror("True LBA: %d, buffer half: %d\n", our_this->lba, our_this->cur_subblock * our_this->bytes_per_sector);
+
+ memcpy(data, &tmp_buffer[our_this->cur_subblock * our_this->bytes_per_sector], our_this->bytes_per_sector);
+
+ our_this->cur_subblock++;
+ if (our_this->cur_subblock >= our_this->num_subblocks)
+ {
+ our_this->cur_subblock = 0;
+
+ our_this->lba++;
+ our_this->blocks--;
+ }
+
+ our_this->last_lba = our_this->lba;
+ dataLength -= our_this->bytes_per_sector;
+ data += our_this->bytes_per_sector;
+ }
+ }
+ break;
+
+ case 0x42: // READ SUB-CHANNEL
+ switch (command[3])
+ {
+ case 1: // return current position
+ {
+ int audio_active;
+ int msf;
+
+ if (!cdrom)
+ {
+ return;
+ }
+
+ logerror("SCSICD: READ SUB-CHANNEL Time = %x, SUBQ = %x\n", command[1], command[2]);
+
+ msf = command[1] & 0x2;
+
+ cddanum = cdda_num_from_cdrom(cdrom);
+ audio_active = cddanum != -1 && cdda_audio_active(cddanum);
+ if (audio_active)
+ {
+ if (cdda_audio_paused(cddanum))
+ {
+ data[1] = 0x12; // audio is paused
+ }
+ else
+ {
+ data[1] = 0x11; // audio in progress
+ }
+ }
+ else
+ {
+ if (cddanum != -1 && cdda_audio_ended(cddanum))
+ {
+ data[1] = 0x13; // ended successfully
+ }
+ else
+ {
+// data[1] = 0x14; // stopped due to error
+ data[1] = 0x15; // No current audio status to return
+ }
+ }
+
+ // if audio is playing, get the latest LBA from the CDROM layer
+ if (audio_active)
+ {
+ our_this->last_lba = cdda_get_audio_lba(cddanum);
+ }
+ else
+ {
+ our_this->last_lba = 0;
+ }
+
+ data[2] = 0;
+ data[3] = 12; // data length
+ data[4] = 0x01; // sub-channel format code
+ data[5] = 0x10 | (audio_active ? 0 : 4);
+ data[6] = cdrom_get_track(cdrom, our_this->last_lba) + 1; // track
+ data[7] = 0; // index
+
+ last_phys_frame = our_this->last_lba;
+
+ if (msf)
+ {
+ int m,s,f;
+ phys_frame_to_msf(last_phys_frame, &m, &s, &f);
+ data[8] = 0;
+ data[9] = m;
+ data[10] = s;
+ data[11] = f;
+ }
+ else
+ {
+ data[8] = last_phys_frame>>24;
+ data[9] = (last_phys_frame>>16)&0xff;
+ data[10] = (last_phys_frame>>8)&0xff;
+ data[11] = last_phys_frame&0xff;
+ }
+
+ last_phys_frame -= cdrom_get_track_start(cdrom, data[6] - 1);
+
+ if (msf)
+ {
+ int m,s,f;
+ phys_frame_to_msf(last_phys_frame, &m, &s, &f);
+ data[12] = 0;
+ data[13] = m;
+ data[14] = s;
+ data[15] = f;
+ }
+ else
+ {
+ data[12] = last_phys_frame>>24;
+ data[13] = (last_phys_frame>>16)&0xff;
+ data[14] = (last_phys_frame>>8)&0xff;
+ data[15] = last_phys_frame&0xff;
+ }
+ break;
+ }
+ default:
+ logerror("SCSICD: Unknown subchannel type %d requested\n", command[3]);
+ }
+ break;
+
+ case 0x43: // READ TOC
+ /*
+ Track numbers are problematic here: 0 = lead-in, 0xaa = lead-out.
+ That makes sense in terms of how real-world CDs are referred to, but
+ our internal routines for tracks use "0" as track 1. That probably
+ should be fixed...
+ */
+ logerror("SCSICD: READ TOC, format = %d time=%d\n", command[2]&0xf,(command[1]>>1)&1);
+ switch (command[2] & 0x0f)
+ {
+ case 0: // normal
+ {
+ int start_trk;
+ int end_trk;
+ int len;
+ int in_len;
+ int dptr;
+ UINT32 tstart;
+
+ start_trk = command[6];
+ if( start_trk == 0 )
+ {
+ start_trk = 1;
+ }
+
+ end_trk = cdrom_get_last_track(cdrom);
+ len = (end_trk * 8) + 2;
+
+ // the returned TOC DATA LENGTH must be the full amount,
+ // regardless of how much we're able to pass back due to in_len
+ dptr = 0;
+ data[dptr++] = (len>>8) & 0xff;
+ data[dptr++] = (len & 0xff);
+ data[dptr++] = 1;
+ data[dptr++] = end_trk;
+
+ if( start_trk == 0xaa )
+ {
+ end_trk = 0xaa;
+ }
+
+ in_len = command[7]<<8 | command[8];
+
+ for (i = start_trk; i <= end_trk; i++)
+ {
+ int cdrom_track = i;
+ if( cdrom_track != 0xaa )
+ {
+ cdrom_track--;
+ }
+
+ if( dptr >= in_len )
+ {
+ break;
+ }
+
+ data[dptr++] = 0;
+ data[dptr++] = cdrom_get_adr_control(cdrom, cdrom_track);
+ data[dptr++] = i;
+ data[dptr++] = 0;
+
+ tstart = cdrom_get_track_start(cdrom, cdrom_track);
+ if ((command[1]&2)>>1)
+ tstart = lba_to_msf(tstart);
+ data[dptr++] = (tstart>>24) & 0xff;
+ data[dptr++] = (tstart>>16) & 0xff;
+ data[dptr++] = (tstart>>8) & 0xff;
+ data[dptr++] = (tstart & 0xff);
+ }
+ }
+ break;
+ default:
+ logerror("SCSICD: Unhandled READ TOC format %d\n", command[2]&0xf);
+ break;
+ }
+ break;
+
+ case 0x1a: // MODE SENSE(6)
+ case 0x5a: // MODE SENSE(10)
+ logerror("SCSICD: MODE SENSE page code = %x, PC = %x\n", command[2] & 0x3f, (command[2]&0xc0)>>6);
+
+ switch (command[2] & 0x3f)
+ {
+ case 0xe: // CD Audio control page
+ data[0] = 0x8e; // page E, parameter is savable
+ data[1] = 0x0e; // page length
+ data[2] = 0x04; // IMMED = 1, SOTC = 0
+ data[3] = data[4] = data[5] = data[6] = data[7] = 0; // reserved
+
+ // connect each audio channel to 1 output port
+ data[8] = 1;
+ data[10] = 2;
+ data[12] = 4;
+ data[14] = 8;
+
+ // indicate max volume
+ data[9] = data[11] = data[13] = data[15] = 0xff;
+ break;
+
+ default:
+ logerror("SCSICD: MODE SENSE unknown page %x\n", command[2] & 0x3f);
+ break;
+ }
+ break;
+
+ default:
+ SCSIBase( &SCSIClassCDROM, SCSIOP_READ_DATA, scsiInstance, dataLength, data );
+ break;
+ }
+}
+
+// scsicd_write_data
+//
+// Write data to the CD-ROM device as part of the execution of a command
+
+static void scsicd_write_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
+{
+ UINT8 *command;
+ int commandLength;
+ SCSICd *our_this = SCSIThis( &SCSIClassCDROM, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch (command[ 0 ])
+ {
+ case 0x15: // MODE SELECT(6)
+ case 0x55: // MODE SELECT(10)
+ logerror("SCSICD: MODE SELECT page %x\n", data[0] & 0x3f);
+
+ switch (data[0] & 0x3f)
+ {
+ case 0x0: // vendor-specific
+ // check for SGI extension to force 512-byte blocks
+ if ((data[3] == 8) && (data[10] == 2))
+ {
+ logerror("SCSICD: Experimental SGI 512-byte block extension enabled\n");
+
+ our_this->bytes_per_sector = 512;
+ our_this->num_subblocks = 4;
+ }
+ else
+ {
+ logerror("SCSICD: Unknown vendor-specific page!\n");
+ }
+ break;
+
+ case 0xe: // audio page
+ logerror("Ch 0 route: %x vol: %x\n", data[8], data[9]);
+ logerror("Ch 1 route: %x vol: %x\n", data[10], data[11]);
+ logerror("Ch 2 route: %x vol: %x\n", data[12], data[13]);
+ logerror("Ch 3 route: %x vol: %x\n", data[14], data[15]);
+ break;
+ }
+ break;
+
+ default:
+ SCSIBase( &SCSIClassCDROM, SCSIOP_WRITE_DATA, scsiInstance, dataLength, data );
+ break;
+ }
+}
+
+static void scsicd_alloc_instance( SCSIInstance *scsiInstance, int diskId )
+{
+ SCSICd *our_this = SCSIThis( &SCSIClassCDROM, scsiInstance );
+
+ our_this->lba = 0;
+ our_this->blocks = 0;
+ our_this->last_lba = 0;
+ our_this->bytes_per_sector = 2048;
+ our_this->num_subblocks = 1;
+ our_this->cur_subblock = 0;
+ our_this->play_err_flag = 0;
+
+ state_save_register_item( "scsicd", diskId, our_this->lba );
+ state_save_register_item( "scsicd", diskId, our_this->blocks );
+ state_save_register_item( "scsicd", diskId, our_this->last_lba );
+ state_save_register_item( "scsicd", diskId, our_this->bytes_per_sector );
+ state_save_register_item( "scsicd", diskId, our_this->num_subblocks );
+ state_save_register_item( "scsicd", diskId, our_this->cur_subblock );
+ state_save_register_item( "scsicd", diskId, our_this->play_err_flag );
+
+#ifdef MESS
+ our_this->cdrom = mess_cd_get_cdrom_file_by_number( diskId );
+#else
+ our_this->cdrom = cdrom_open(get_disk_handle( diskId ));
+
+ if (!our_this->cdrom)
+ {
+ logerror("SCSICD: no CD found!\n");
+ }
+#endif
+}
+
+static void scsicd_delete_instance( SCSIInstance *scsiInstance )
+{
+#ifndef MESS
+ SCSICd *our_this = SCSIThis( &SCSIClassCDROM, scsiInstance );
+ if( our_this->cdrom )
+ {
+ cdrom_close( our_this->cdrom );
+ }
+#endif
+}
+
+static void scsicd_get_device( SCSIInstance *scsiInstance, cdrom_file **cdrom )
+{
+ SCSICd *our_this = SCSIThis( &SCSIClassCDROM, scsiInstance );
+ *cdrom = our_this->cdrom;
+}
+
+static void scsicd_set_device( SCSIInstance *scsiInstance, cdrom_file *cdrom )
+{
+ SCSICd *our_this = SCSIThis( &SCSIClassCDROM, scsiInstance );
+ our_this->cdrom = cdrom;
+}
+
+static int scsicd_dispatch(int operation, void *file, INT64 intparm, void *ptrparm)
+{
+ switch (operation)
+ {
+ case SCSIOP_EXEC_COMMAND:
+ return scsicd_exec_command( file, ptrparm );
+
+ case SCSIOP_READ_DATA:
+ scsicd_read_data( file, ptrparm, intparm );
+ return 0;
+
+ case SCSIOP_WRITE_DATA:
+ scsicd_write_data( file, ptrparm, intparm );
+ return 0;
+
+ case SCSIOP_ALLOC_INSTANCE:
+ SCSIBase( &SCSIClassCDROM, operation, file, intparm, ptrparm );
+ scsicd_alloc_instance( *((SCSIInstance **) ptrparm), intparm );
+ return 0;
+
+ case SCSIOP_DELETE_INSTANCE:
+ scsicd_delete_instance( file );
+ break;
+
+ case SCSIOP_GET_DEVICE:
+ scsicd_get_device( file, ptrparm );
+ return 0;
+
+ case SCSIOP_SET_DEVICE:
+ scsicd_set_device( file, ptrparm );
+ return 0;
+ }
+
+ return SCSIBase( &SCSIClassCDROM, operation, file, intparm, ptrparm );
+}
+
+SCSIClass SCSIClassCDROM =
+{
+ &SCSIClassDevice,
+ scsicd_dispatch,
+ sizeof( SCSICd )
+};
diff --git a/src/emu/machine/scsicd.h b/src/emu/machine/scsicd.h
new file mode 100644
index 00000000000..5300a9563b1
--- /dev/null
+++ b/src/emu/machine/scsicd.h
@@ -0,0 +1,17 @@
+/***************************************************************************
+
+ scsicd.h
+
+***************************************************************************/
+
+#ifndef _SCSICD_H_
+#define _SCSICD_H_
+
+#include "machine/scsi.h"
+
+// CD-ROM handler
+extern SCSIClass SCSIClassCDROM;
+#define SCSI_DEVICE_CDROM &SCSIClassCDROM
+
+#endif
+
diff --git a/src/emu/machine/scsidev.c b/src/emu/machine/scsidev.c
new file mode 100644
index 00000000000..11ac55b1193
--- /dev/null
+++ b/src/emu/machine/scsidev.c
@@ -0,0 +1,155 @@
+/***************************************************************************
+
+ scsidev.c - Base class for scsi devices.
+
+***************************************************************************/
+
+#include "scsidev.h"
+
+typedef struct
+{
+ UINT8 command[16];
+ int commandLength;
+ int phase;
+} SCSIDev;
+
+static int scsidev_exec_command( SCSIInstance *scsiInstance, UINT8 *statusCode )
+{
+ UINT8 *command;
+ int commandLength;
+// SCSIDev *our_this = SCSIThis( &SCSIClassDevice, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch( command[ 0 ] )
+ {
+ case 0x00: // TEST UNIT READY
+ SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
+ return 0;
+
+ default:
+ logerror( "%08x: SCSIDEV unknown command %02x\n", activecpu_get_pc(), command[ 0 ] );
+ return 0;
+ }
+}
+
+static void scsidev_read_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
+{
+ UINT8 *command;
+ int commandLength;
+// SCSIDev *our_this = SCSIThis( &SCSIClassDevice, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch( command[ 0 ] )
+ {
+ default:
+ logerror( "%08x: SCSIDEV unknown read %02x\n", activecpu_get_pc(), command[ 0 ] );
+ break;
+ }
+}
+
+static void scsidev_write_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
+{
+ UINT8 *command;
+ int commandLength;
+// SCSIDev *our_this = SCSIThis( &SCSIClassDevice, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch( command[ 0 ] )
+ {
+ default:
+ logerror( "%08x: SCSIDEV unknown write %02x\n", activecpu_get_pc(), command[ 0 ] );
+ break;
+ }
+}
+
+static void scsidev_set_phase( SCSIInstance *scsiInstance, int phase )
+{
+ SCSIDev *our_this = SCSIThis( &SCSIClassDevice, scsiInstance );
+ our_this->phase = phase;
+}
+
+static int scsidev_get_phase( SCSIInstance *scsiInstance )
+{
+ SCSIDev *our_this = SCSIThis( &SCSIClassDevice, scsiInstance );
+ return our_this->phase;
+}
+
+static void scsidev_set_command( SCSIInstance *scsiInstance, void *command, int commandLength )
+{
+ SCSIDev *our_this = SCSIThis( &SCSIClassDevice, scsiInstance );
+
+ if( commandLength > sizeof( our_this->command ) )
+ {
+ /// TODO: output an error.
+ return;
+ }
+
+ memcpy( our_this->command, command, commandLength );
+ our_this->commandLength = commandLength;
+
+ SCSISetPhase( scsiInstance, SCSI_PHASE_COMMAND );
+}
+
+static int scsidev_get_command( SCSIInstance *scsiInstance, void **command )
+{
+ SCSIDev *our_this = SCSIThis( &SCSIClassDevice, scsiInstance );
+ *command = our_this->command;
+ return our_this->commandLength;
+}
+
+static void scsidev_alloc_instance( SCSIInstance *scsiInstance, int diskId )
+{
+ SCSIDev *our_this = SCSIThis( &SCSIClassDevice, scsiInstance );
+
+ state_save_register_item_array( "scsidev", diskId, our_this->command );
+ state_save_register_item( "scsidev", diskId, our_this->commandLength );
+ state_save_register_item( "scsidev", diskId, our_this->phase );
+}
+
+static int scsidev_dispatch( int operation, void *file, INT64 intparm, void *ptrparm )
+{
+ switch( operation )
+ {
+ case SCSIOP_EXEC_COMMAND:
+ return scsidev_exec_command( file, ptrparm );
+
+ case SCSIOP_READ_DATA:
+ scsidev_read_data( file, ptrparm, intparm );
+ break;
+
+ case SCSIOP_WRITE_DATA:
+ scsidev_write_data( file, ptrparm, intparm );
+ break;
+
+ case SCSIOP_SET_PHASE:
+ scsidev_set_phase( file, intparm );
+ return 0;
+
+ case SCSIOP_GET_PHASE:
+ return scsidev_get_phase( file );
+
+ case SCSIOP_SET_COMMAND:
+ scsidev_set_command( file, ptrparm, intparm );
+ return 0;
+
+ case SCSIOP_GET_COMMAND:
+ return scsidev_get_command( file, ptrparm );
+
+ case SCSIOP_ALLOC_INSTANCE:
+ *((SCSIInstance **) ptrparm) = SCSIMalloc( file );
+ scsidev_alloc_instance( *((SCSIInstance **) ptrparm), intparm );
+ return 0;
+
+ case SCSIOP_DELETE_INSTANCE:
+ free( file );
+ return 0;
+ }
+ return 0;
+}
+
+SCSIClass SCSIClassDevice =
+{
+ NULL,
+ scsidev_dispatch,
+ sizeof( SCSIDev )
+};
diff --git a/src/emu/machine/scsidev.h b/src/emu/machine/scsidev.h
new file mode 100644
index 00000000000..f765e187cbe
--- /dev/null
+++ b/src/emu/machine/scsidev.h
@@ -0,0 +1,15 @@
+/***************************************************************************
+
+ scsidev.h
+
+***************************************************************************/
+
+#ifndef _SCSIDEV_H_
+#define _SCSIDEV_H_
+
+#include "machine/scsi.h"
+
+// base handler
+extern SCSIClass SCSIClassDevice;
+
+#endif
diff --git a/src/emu/machine/scsihd.c b/src/emu/machine/scsihd.c
new file mode 100644
index 00000000000..81d3770eb71
--- /dev/null
+++ b/src/emu/machine/scsihd.c
@@ -0,0 +1,311 @@
+/***************************************************************************
+
+ scsihd.c - Implementation of a SCSI hard disk drive
+
+***************************************************************************/
+
+#include "driver.h"
+#include "scsidev.h"
+#include "harddisk.h"
+
+#ifdef MESS
+#include "devices/harddriv.h"
+#endif
+
+typedef struct
+{
+ UINT32 lba;
+ UINT32 blocks;
+ hard_disk_file *disk;
+} SCSIHd;
+
+
+// scsihd_exec_command
+
+static int scsihd_exec_command( SCSIInstance *scsiInstance, UINT8 *statusCode )
+{
+ UINT8 *command;
+ int commandLength;
+ SCSIHd *our_this = SCSIThis( &SCSIClassHARDDISK, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch ( command[0] )
+ {
+ case 0x03: // REQUEST SENSE
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return SCSILengthFromUINT8( &command[ 4 ] );
+
+ case 0x04: // FORMAT UNIT
+ SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
+ return 0;
+
+ case 0x08: // READ(6)
+ our_this->lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3];
+ our_this->blocks = SCSILengthFromUINT8( &command[4] );
+
+ logerror("SCSIHD: READ at LBA %x for %x blocks\n", our_this->lba, our_this->blocks);
+
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return our_this->blocks * 512;
+
+ case 0x0a: // WRITE(6)
+ our_this->lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3];
+ our_this->blocks = SCSILengthFromUINT8( &command[4] );
+
+ logerror("SCSIHD: WRITE to LBA %x for %x blocks\n", our_this->lba, our_this->blocks);
+
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAOUT );
+ return our_this->blocks * 512;
+
+ case 0x12: // INQUIRY
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return SCSILengthFromUINT8( &command[ 4 ] );
+
+ case 0x15: // MODE SELECT (used to set CDDA volume)
+ logerror("SCSIHD: MODE SELECT length %x control %x\n", command[4], command[5]);
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAOUT );
+ return SCSILengthFromUINT8( &command[ 4 ] );
+
+ case 0x1a: // MODE SENSE(6)
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return SCSILengthFromUINT8( &command[ 4 ] );
+
+ case 0x25: // READ CAPACITY
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return 8;
+
+ case 0x28: // READ(10)
+ our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ our_this->blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9];
+
+ logerror("SCSIHD: READ at LBA %x for %x blocks\n", our_this->lba, our_this->blocks);
+
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return our_this->blocks * 512;
+
+ case 0xa8: // READ(12)
+ our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ our_this->blocks = SCSILengthFromUINT16( &command[7] );
+
+ logerror("SCSIHD: READ at LBA %x for %x blocks\n", our_this->lba, our_this->blocks);
+
+ SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
+ return our_this->blocks * 512;
+
+ default:
+ return SCSIBase( &SCSIClassHARDDISK, SCSIOP_EXEC_COMMAND, scsiInstance, 0, NULL );
+ }
+}
+
+static void scsihd_read_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
+{
+ int i;
+ UINT8 *command;
+ int commandLength;
+ SCSIHd *our_this = SCSIThis( &SCSIClassHARDDISK, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch ( command[0] )
+ {
+ case 0x03: // REQUEST SENSE
+ data[0] = 0x80; // valid sense
+ for (i = 1; i < 12; i++)
+ {
+ data[i] = 0;
+ }
+ break;
+
+ case 0x12: // INQUIRY
+ memset( data, 0, dataLength );
+ data[0] = 0x00; // device is direct-access (e.g. hard disk)
+ data[1] = 0x00; // media is not removable
+ data[2] = 0x05; // device complies with SPC-3 standard
+ data[3] = 0x02; // response data format = SPC-3 standard
+ // Apple HD SC setup utility needs to see this
+ strcpy((char *)&data[8], " SEAGATE");
+ strcpy((char *)&data[16], " ST225N");
+ strcpy((char *)&data[32], "1.0");
+ break;
+
+ case 0x1a: // MODE SENSE (6 byte)
+ // special Apple ID page. this is a vendor-specific page,
+ // so unless collisions occur there should be no need
+ // to change it.
+ if ((command[2] & 0x3f) == 0x30)
+ {
+ memset(data, 0, 40);
+ data[0] = 0x14;
+ strcpy((char *)&data[14], "APPLE COMPUTER, INC.");
+ }
+ break;
+
+ case 0x08: // READ(6)
+ case 0x28: // READ(10)
+ case 0xa8: // READ(12)
+ if ((our_this->disk) && (our_this->blocks))
+ {
+ while (dataLength > 0)
+ {
+ if (!hard_disk_read(our_this->disk, our_this->lba, data))
+ {
+ logerror("SCSIHD: HD read error!\n");
+ }
+ our_this->lba++;
+ our_this->blocks--;
+ dataLength -= 512;
+ data += 512;
+ }
+ }
+ break;
+
+
+ case 0x25: // READ CAPACITY
+ {
+ hard_disk_info *info;
+ UINT32 temp;
+
+ info = hard_disk_get_info(our_this->disk);
+
+ logerror("SCSIHD: READ CAPACITY\n");
+
+ // get # of sectors
+ temp = info->cylinders * info->heads * info->sectors;
+ temp--;
+
+ data[0] = (temp>>24) & 0xff;
+ data[1] = (temp>>16) & 0xff;
+ data[2] = (temp>>8) & 0xff;
+ data[3] = (temp & 0xff);
+ data[4] = (info->sectorbytes>>24)&0xff;
+ data[5] = (info->sectorbytes>>16)&0xff;
+ data[6] = (info->sectorbytes>>8)&0xff;
+ data[7] = (info->sectorbytes & 0xff);
+ }
+ break;
+
+ default:
+ SCSIBase( &SCSIClassHARDDISK, SCSIOP_READ_DATA, scsiInstance, dataLength, data );
+ break;
+ }
+}
+
+static void scsihd_write_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
+{
+ UINT8 *command;
+ int commandLength;
+ SCSIHd *our_this = SCSIThis( &SCSIClassHARDDISK, scsiInstance );
+ SCSIGetCommand( scsiInstance, &command, &commandLength );
+
+ switch ( command[0] )
+ {
+ case 0x0a: // WRITE(6)
+ if ((our_this->disk) && (our_this->blocks))
+ {
+ while (dataLength > 0)
+ {
+ if (!hard_disk_write(our_this->disk, our_this->lba, data))
+ {
+ logerror("SCSIHD: HD write error!\n");
+ }
+ our_this->lba++;
+ our_this->blocks--;
+ dataLength -= 512;
+ data += 512;
+ }
+ }
+ break;
+
+ default:
+ SCSIBase( &SCSIClassHARDDISK, SCSIOP_WRITE_DATA, scsiInstance, dataLength, data );
+ break;
+ }
+}
+
+static void scsihd_alloc_instance( SCSIInstance *scsiInstance, int diskId )
+{
+ SCSIHd *our_this = SCSIThis( &SCSIClassHARDDISK, scsiInstance );
+
+ our_this->lba = 0;
+ our_this->blocks = 0;
+
+ state_save_register_item( "scsihd", diskId, our_this->lba );
+ state_save_register_item( "scsihd", diskId, our_this->blocks );
+
+#ifdef MESS
+ our_this->disk = mess_hd_get_hard_disk_file_by_number( diskId );
+#else
+ our_this->disk = hard_disk_open(get_disk_handle( diskId ));
+
+ if (!our_this->disk)
+ {
+ logerror("SCSIHD: no HD found!\n");
+ }
+#endif
+}
+
+static void scsihd_delete_instance( SCSIInstance *scsiInstance )
+{
+#ifndef MESS
+ SCSIHd *our_this = SCSIThis( &SCSIClassHARDDISK, scsiInstance );
+
+ if( our_this->disk )
+ {
+ hard_disk_close( our_this->disk );
+ }
+#endif
+}
+
+static void scsihd_get_device( SCSIInstance *scsiInstance, hard_disk_file **disk )
+{
+ SCSIHd *our_this = SCSIThis( &SCSIClassHARDDISK, scsiInstance );
+ *disk = our_this->disk;
+}
+
+static void scsihd_set_device( SCSIInstance *scsiInstance, hard_disk_file *disk )
+{
+ SCSIHd *our_this = SCSIThis( &SCSIClassHARDDISK, scsiInstance );
+ our_this->disk = disk;
+}
+
+static int scsihd_dispatch(int operation, void *file, INT64 intparm, void *ptrparm)
+{
+ switch (operation)
+ {
+ case SCSIOP_EXEC_COMMAND:
+ return scsihd_exec_command( file, ptrparm );
+
+ case SCSIOP_READ_DATA:
+ scsihd_read_data( file, ptrparm, intparm );
+ return 0;
+
+ case SCSIOP_WRITE_DATA:
+ scsihd_write_data( file, ptrparm, intparm );
+ return 0;
+
+ case SCSIOP_ALLOC_INSTANCE:
+ SCSIBase( &SCSIClassHARDDISK, operation, file, intparm, ptrparm );
+ scsihd_alloc_instance( *((SCSIInstance **) ptrparm), intparm );
+ return 0;
+
+ case SCSIOP_DELETE_INSTANCE:
+ scsihd_delete_instance( file );
+ break;
+
+ case SCSIOP_GET_DEVICE:
+ scsihd_get_device( file, ptrparm );
+ return 0;
+
+ case SCSIOP_SET_DEVICE:
+ scsihd_set_device( file, ptrparm );
+ return 0;
+ }
+
+ return SCSIBase( &SCSIClassHARDDISK, operation, file, intparm, ptrparm );
+}
+
+SCSIClass SCSIClassHARDDISK =
+{
+ &SCSIClassDevice,
+ scsihd_dispatch,
+ sizeof( SCSIHd )
+};
diff --git a/src/emu/machine/scsihd.h b/src/emu/machine/scsihd.h
new file mode 100644
index 00000000000..4adb0c8fbd3
--- /dev/null
+++ b/src/emu/machine/scsihd.h
@@ -0,0 +1,16 @@
+/***************************************************************************
+
+ scsihd.h
+
+***************************************************************************/
+
+#ifndef _SCSIHD_H_
+#define _SCSIHD_H_
+
+#include "machine/scsi.h"
+
+// CD-ROM handler
+extern SCSIClass SCSIClassHARDDISK;
+#define SCSI_DEVICE_HARDDISK &SCSIClassHARDDISK
+
+#endif
diff --git a/src/emu/machine/smc91c9x.c b/src/emu/machine/smc91c9x.c
new file mode 100644
index 00000000000..4735863fe7f
--- /dev/null
+++ b/src/emu/machine/smc91c9x.c
@@ -0,0 +1,564 @@
+/*************************************************************************
+
+ SMC91C9X ethernet controller implementation
+
+ by Aaron Giles
+
+***************************************************************************
+
+ Notes:
+ * only loopback mode really works
+
+**************************************************************************/
+
+#include "driver.h"
+#include "smc91c9x.h"
+
+
+
+/*************************************
+ *
+ * Debugging constants
+ *
+ *************************************/
+
+#define LOG_ETHERNET (0)
+#define DISPLAY_STATS (0)
+
+
+
+/*************************************
+ *
+ * Ethernet constants
+ *
+ *************************************/
+
+#define ETHER_BUFFER_SIZE (2048)
+#define ETHER_RX_BUFFERS (4)
+
+/* Ethernet registers - bank 0 */
+#define EREG_TCR (0*8 + 0)
+#define EREG_EPH_STATUS (0*8 + 1)
+#define EREG_RCR (0*8 + 2)
+#define EREG_COUNTER (0*8 + 3)
+#define EREG_MIR (0*8 + 4)
+#define EREG_MCR (0*8 + 5)
+#define EREG_BANK (0*8 + 7)
+
+/* Ethernet registers - bank 1 */
+#define EREG_CONFIG (1*8 + 0)
+#define EREG_BASE (1*8 + 1)
+#define EREG_IA0_1 (1*8 + 2)
+#define EREG_IA2_3 (1*8 + 3)
+#define EREG_IA4_5 (1*8 + 4)
+#define EREG_GENERAL_PURP (1*8 + 5)
+#define EREG_CONTROL (1*8 + 6)
+
+/* Ethernet registers - bank 2 */
+#define EREG_MMU_COMMAND (2*8 + 0)
+#define EREG_PNR_ARR (2*8 + 1)
+#define EREG_FIFO_PORTS (2*8 + 2)
+#define EREG_POINTER (2*8 + 3)
+#define EREG_DATA_0 (2*8 + 4)
+#define EREG_DATA_1 (2*8 + 5)
+#define EREG_INTERRUPT (2*8 + 6)
+
+/* Ethernet registers - bank 3 */
+#define EREG_MT0_1 (3*8 + 0)
+#define EREG_MT2_3 (3*8 + 1)
+#define EREG_MT4_5 (3*8 + 2)
+#define EREG_MT6_7 (3*8 + 3)
+#define EREG_MGMT (3*8 + 4)
+#define EREG_REVISION (3*8 + 5)
+#define EREG_ERCV (3*8 + 6)
+
+/* Ethernet MMU commands */
+#define ECMD_NOP 0
+#define ECMD_ALLOCATE 1
+#define ECMD_RESET_MMU 2
+#define ECMD_REMOVE 3
+#define ECMD_REMOVE_RELEASE 4
+#define ECMD_RELEASE_PACKET 5
+#define ECMD_ENQUEUE_PACKET 6
+#define ECMD_RESET_FIFOS 7
+
+/* Ethernet interrupt bits */
+#define EINT_RCV 0x01
+#define EINT_TX 0x02
+#define EINT_TX_EMPTY 0x04
+#define EINT_ALLOC 0x08
+#define EINT_RX_OVRN 0x10
+#define EINT_EPH 0x20
+#define EINT_ERCV 0x40
+
+/* Ethernet register names */
+static const char *ethernet_regname[64] =
+{
+ "TCR", "EPH STATUS", "RCR", "COUNTER", "MIR", "MCR", "(0.6)", "BANK",
+ "CONFIG", "BASE", "IA0-1", "IA2-3", "IA4-5", "GENERAL PURPOSE", "CONTROL", "BANK",
+ "MMU COMMAND", "PNR ARR", "FIFO PORTS", "POINTER", "DATA", "DATA", "INTERRUPT", "BANK",
+ "MT0-1", "MT2-3", "MT4-5", "MT6-7", "MGMT", "REVISION", "ERCV", "BANK",
+ "(4.0)", "(4.1)", "(4.2)", "(4.3)", "(4.4)", "(4.5)", "(4.6)", "BANK",
+ "(5.0)", "(5.1)", "(5.2)", "(5.3)", "(5.4)", "(5.5)", "(5.6)", "BANK",
+ "(6.0)", "(6.1)", "(6.2)", "(6.3)", "(6.4)", "(6.5)", "(6.6)", "BANK",
+ "(7.0)", "(7.1)", "(7.2)", "(7.3)", "(7.4)", "(7.5)", "(7.6)", "BANK"
+};
+
+
+
+/*************************************
+ *
+ * Structures
+ *
+ *************************************/
+
+struct smc91c94_data
+{
+ void (*irq_handler)(int state);
+
+ /* raw register data and masks */
+ UINT16 reg[64];
+ UINT16 regmask[64];
+
+ /* IRQ information */
+ UINT8 irq_state;
+
+ /* allocate information */
+ UINT8 alloc_count;
+
+ /* transmit/receive FIFOs */
+ UINT8 fifo_count;
+ UINT8 rx[ETHER_BUFFER_SIZE * ETHER_RX_BUFFERS];
+ UINT8 tx[ETHER_BUFFER_SIZE];
+
+ /* counters */
+ UINT32 sent;
+ UINT32 recd;
+};
+
+
+
+/*************************************
+ *
+ * Local variables
+ *
+ *************************************/
+
+static struct smc91c94_data ethernet;
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static void update_ethernet_irq(void);
+
+
+
+/*************************************
+ *
+ * Initialization
+ *
+ *************************************/
+
+void smc91c94_init(struct smc91c9x_interface *config)
+{
+ ethernet.irq_handler = config->irq_handler;
+}
+
+
+
+/*************************************
+ *
+ * Reset
+ *
+ *************************************/
+
+void smc91c94_reset(void)
+{
+ void (*saved_handler)(int) = ethernet.irq_handler;
+ memset(&ethernet, 0, sizeof(ethernet));
+ ethernet.irq_handler = saved_handler;
+
+ ethernet.reg[EREG_TCR] = 0x0000; ethernet.regmask[EREG_TCR] = 0x3d87;
+ ethernet.reg[EREG_EPH_STATUS] = 0x0000; ethernet.regmask[EREG_EPH_STATUS] = 0x0000;
+ ethernet.reg[EREG_RCR] = 0x0000; ethernet.regmask[EREG_RCR] = 0xc307;
+ ethernet.reg[EREG_COUNTER] = 0x0000; ethernet.regmask[EREG_COUNTER] = 0x0000;
+ ethernet.reg[EREG_MIR] = 0x1212; ethernet.regmask[EREG_MIR] = 0x0000;
+ ethernet.reg[EREG_MCR] = 0x3300; ethernet.regmask[EREG_MCR] = 0x00ff;
+ ethernet.reg[EREG_BANK] = 0x3300; ethernet.regmask[EREG_BANK] = 0x0007;
+
+ ethernet.reg[EREG_CONFIG] = 0x0030; ethernet.regmask[EREG_CONFIG] = 0x17c6;
+ ethernet.reg[EREG_BASE] = 0x1866; ethernet.regmask[EREG_BASE] = 0xfffe;
+ ethernet.reg[EREG_IA0_1] = 0x0000; ethernet.regmask[EREG_IA0_1] = 0xffff;
+ ethernet.reg[EREG_IA2_3] = 0x0000; ethernet.regmask[EREG_IA2_3] = 0xffff;
+ ethernet.reg[EREG_IA4_5] = 0x0000; ethernet.regmask[EREG_IA4_5] = 0xffff;
+ ethernet.reg[EREG_GENERAL_PURP] = 0x0000; ethernet.regmask[EREG_GENERAL_PURP] = 0xffff;
+ ethernet.reg[EREG_CONTROL] = 0x0100; ethernet.regmask[EREG_CONTROL] = 0x68e7;
+
+ ethernet.reg[EREG_MMU_COMMAND] = 0x0000; ethernet.regmask[EREG_MMU_COMMAND] = 0x00e7;
+ ethernet.reg[EREG_PNR_ARR] = 0x8000; ethernet.regmask[EREG_PNR_ARR] = 0x00ff;
+ ethernet.reg[EREG_FIFO_PORTS] = 0x8080; ethernet.regmask[EREG_FIFO_PORTS] = 0x0000;
+ ethernet.reg[EREG_POINTER] = 0x0000; ethernet.regmask[EREG_POINTER] = 0xf7ff;
+ ethernet.reg[EREG_DATA_0] = 0x0000; ethernet.regmask[EREG_DATA_0] = 0xffff;
+ ethernet.reg[EREG_DATA_1] = 0x0000; ethernet.regmask[EREG_DATA_1] = 0xffff;
+ ethernet.reg[EREG_INTERRUPT] = 0x0004; ethernet.regmask[EREG_INTERRUPT] = 0x7f00;
+
+ ethernet.reg[EREG_MT0_1] = 0x0000; ethernet.regmask[EREG_MT0_1] = 0xffff;
+ ethernet.reg[EREG_MT2_3] = 0x0000; ethernet.regmask[EREG_MT2_3] = 0xffff;
+ ethernet.reg[EREG_MT4_5] = 0x0000; ethernet.regmask[EREG_MT4_5] = 0xffff;
+ ethernet.reg[EREG_MT6_7] = 0x0000; ethernet.regmask[EREG_MT6_7] = 0xffff;
+ ethernet.reg[EREG_MGMT] = 0x3030; ethernet.regmask[EREG_MGMT] = 0x0f0f;
+ ethernet.reg[EREG_REVISION] = 0x3340; ethernet.regmask[EREG_REVISION] = 0x0000;
+ ethernet.reg[EREG_ERCV] = 0x331f; ethernet.regmask[EREG_ERCV] = 0x009f;
+
+ update_ethernet_irq();
+}
+
+
+
+/*************************************
+ *
+ * Internal IRQ handling
+ *
+ *************************************/
+
+static void update_ethernet_irq(void)
+{
+ UINT8 mask = ethernet.reg[EREG_INTERRUPT] >> 8;
+ UINT8 state = ethernet.reg[EREG_INTERRUPT] & 0xff;
+
+ /* update the IRQ state */
+ ethernet.irq_state = ((mask & state) != 0);
+ if (ethernet.irq_handler)
+ (*ethernet.irq_handler)(ethernet.irq_state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+/*************************************
+ *
+ * Draw the stats
+ *
+ *************************************/
+
+static void update_stats(void)
+{
+ if (DISPLAY_STATS)
+ popmessage("Sent:%d Rec'd:%d", ethernet.sent, ethernet.recd);
+}
+
+
+
+
+/*************************************
+ *
+ * Complete an enqueued packet
+ *
+ *************************************/
+
+static void finish_enqueue(int param)
+{
+ int is_broadcast = (ethernet.tx[4] == 0xff && ethernet.tx[5] == 0xff && ethernet.tx[6] == 0xff &&
+ ethernet.tx[7] == 0xff && ethernet.tx[8] == 0xff && ethernet.tx[9] == 0xff);
+
+ /* update the EPH register and stuff it in the first transmit word */
+ ethernet.reg[EREG_EPH_STATUS] = 0x0001;
+ if (is_broadcast)
+ ethernet.reg[EREG_EPH_STATUS] |= 0x0040;
+ ethernet.tx[0] = ethernet.reg[EREG_EPH_STATUS];
+ ethernet.tx[1] = ethernet.reg[EREG_EPH_STATUS] >> 8;
+
+ /* signal a transmit interrupt and mark the transmit buffer empty */
+ ethernet.reg[EREG_INTERRUPT] |= EINT_TX;
+ ethernet.reg[EREG_INTERRUPT] |= EINT_TX_EMPTY;
+ ethernet.reg[EREG_FIFO_PORTS] |= 0x0080;
+ ethernet.sent++;
+ update_stats();
+
+ /* loopback? */
+ if (ethernet.reg[EREG_TCR] & 0x2002)
+ if (ethernet.fifo_count < ETHER_RX_BUFFERS)
+ {
+ int buffer_len = ((ethernet.tx[3] << 8) | ethernet.tx[2]) & 0x7ff;
+ UINT8 *packet = &ethernet.rx[ethernet.fifo_count++ * ETHER_BUFFER_SIZE];
+ int packet_len;
+
+ /* compute the packet length */
+ packet_len = buffer_len - 6;
+ if (packet[buffer_len - 1] & 0x20)
+ packet_len++;
+
+ /* build up the packet */
+ packet[0] = 0x0000;
+ packet[1] = 0x0000;
+ packet[2] = buffer_len;
+ packet[3] = buffer_len >> 8;
+ memcpy(&packet[4], &ethernet.tx[4], 6);
+ memcpy(&packet[10], &ethernet.tx[10], 6);
+ memcpy(&packet[16], &ethernet.tx[16], buffer_len - 16);
+
+ /* set the broadcast flag */
+ if (is_broadcast)
+ packet[1] |= 0x40;
+
+ /* pad? */
+ if (ethernet.reg[EREG_TCR & 0x0080])
+ if (packet_len < 64)
+ {
+ memset(&packet[buffer_len], 0, 64+6 - buffer_len);
+ packet[buffer_len - 1] = 0;
+ buffer_len = 64+6;
+ packet[2] = buffer_len;
+ packet[3] = buffer_len >> 8;
+ }
+
+ /* signal a receive */
+ ethernet.reg[EREG_INTERRUPT] |= EINT_RCV;
+ ethernet.reg[EREG_FIFO_PORTS] &= ~0x8000;
+ }
+ update_ethernet_irq();
+}
+
+
+
+/*************************************
+ *
+ * MMU command processing
+ *
+ *************************************/
+
+static void process_command(UINT16 data)
+{
+ switch ((data >> 5) & 7)
+ {
+ case ECMD_NOP:
+ if (LOG_ETHERNET)
+ logerror(" NOP\n");
+ break;
+
+ case ECMD_ALLOCATE:
+ if (LOG_ETHERNET)
+ logerror(" ALLOCATE MEMORY FOR TX (%d)\n", (data & 7));
+ ethernet.reg[EREG_PNR_ARR] &= ~0xff00;
+ ethernet.reg[EREG_PNR_ARR] |= ethernet.alloc_count++ << 8;
+ ethernet.reg[EREG_INTERRUPT] |= 0x0008;
+ update_ethernet_irq();
+ break;
+
+ case ECMD_RESET_MMU:
+ if (LOG_ETHERNET)
+ logerror(" RESET MMU\n");
+ break;
+
+ case ECMD_REMOVE:
+ if (LOG_ETHERNET)
+ logerror(" REMOVE FRAME FROM RX FIFO\n");
+ break;
+
+ case ECMD_REMOVE_RELEASE:
+ if (LOG_ETHERNET)
+ logerror(" REMOVE AND RELEASE FRAME FROM RX FIFO\n");
+ ethernet.reg[EREG_INTERRUPT] &= ~EINT_RCV;
+ if (ethernet.fifo_count > 0)
+ ethernet.fifo_count--;
+ if (ethernet.fifo_count > 0)
+ {
+ memmove(&ethernet.rx[0], &ethernet.rx[ETHER_BUFFER_SIZE], ethernet.fifo_count * ETHER_BUFFER_SIZE);
+ ethernet.reg[EREG_INTERRUPT] |= EINT_RCV;
+ ethernet.reg[EREG_FIFO_PORTS] &= ~0x8000;
+ }
+ else
+ ethernet.reg[EREG_FIFO_PORTS] |= 0x8000;
+ update_ethernet_irq();
+ ethernet.recd++;
+ update_stats();
+ break;
+
+ case ECMD_RELEASE_PACKET:
+ if (LOG_ETHERNET)
+ logerror(" RELEASE SPECIFIC PACKET\n");
+ break;
+
+ case ECMD_ENQUEUE_PACKET:
+ if (LOG_ETHERNET)
+ logerror(" ENQUEUE TX PACKET\n");
+ finish_enqueue(0);
+ break;
+
+ case ECMD_RESET_FIFOS:
+ if (LOG_ETHERNET)
+ logerror(" RESET TX FIFOS\n");
+ break;
+ }
+ ethernet.reg[EREG_MMU_COMMAND] &= ~0x0001;
+}
+
+
+
+/*************************************
+ *
+ * Core read handler
+ *
+ *************************************/
+
+READ16_HANDLER( smc91c94_r )
+{
+ UINT32 result = ~0;
+
+ /* determine the effective register */
+ offset %= 8;
+ if (offset != EREG_BANK)
+ offset += 8 * (ethernet.reg[EREG_BANK] & 7);
+ result = ethernet.reg[offset];
+
+ switch (offset)
+ {
+ case EREG_PNR_ARR:
+ if (!(mem_mask & 0xff00))
+ {
+ ethernet.reg[EREG_INTERRUPT] &= ~0x0008;
+ update_ethernet_irq();
+ }
+ break;
+
+ case EREG_DATA_0: /* data register */
+ case EREG_DATA_1: /* data register */
+ {
+ UINT8 *buffer = (ethernet.reg[EREG_POINTER] & 0x8000) ? ethernet.rx : ethernet.tx;
+ int addr = ethernet.reg[EREG_POINTER] & 0x7ff;
+ result = buffer[addr++];
+ if (!(mem_mask & 0xff00))
+ result |= buffer[addr++] << 8;
+ if (ethernet.reg[EREG_POINTER] & 0x4000)
+ ethernet.reg[EREG_POINTER] = (ethernet.reg[EREG_POINTER] & ~0x7ff) | (addr & 0x7ff);
+ break;
+ }
+ }
+
+ if (LOG_ETHERNET && offset != EREG_BANK)
+ logerror("%08X:ethernet_r(%s) = %04X & %04X\n", activecpu_get_pc(), ethernet_regname[offset], result, mem_mask ^ 0xffff);
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Core write handler
+ *
+ *************************************/
+
+WRITE16_HANDLER( smc91c94_w )
+{
+ UINT16 olddata;
+
+ /* determine the effective register */
+ offset %= 8;
+ if (offset != EREG_BANK)
+ offset += 8 * (ethernet.reg[EREG_BANK] & 7);
+
+ /* update the data generically */
+ olddata = ethernet.reg[offset];
+ mem_mask |= ~ethernet.regmask[offset];
+ COMBINE_DATA(&ethernet.reg[offset]);
+
+ if (LOG_ETHERNET && offset != 7)
+ logerror("%08X:ethernet_w(%s) = %04X & %04X\n", activecpu_get_pc(), ethernet_regname[offset], data, mem_mask ^ 0xffff);
+
+ /* handle it */
+ switch (offset)
+ {
+ case EREG_TCR: /* transmit control register */
+ if (LOG_ETHERNET)
+ {
+ if (data & 0x2000) logerror(" EPH LOOP\n");
+ if (data & 0x1000) logerror(" STP SQET\n");
+ if (data & 0x0800) logerror(" FDUPLX\n");
+ if (data & 0x0400) logerror(" MON_CSN\n");
+ if (data & 0x0100) logerror(" NOCRC\n");
+ if (data & 0x0080) logerror(" PAD_EN\n");
+ if (data & 0x0004) logerror(" FORCOL\n");
+ if (data & 0x0002) logerror(" LOOP\n");
+ if (data & 0x0001) logerror(" TXENA\n");
+ }
+ break;
+
+ case EREG_RCR: /* receive control register */
+ if (LOG_ETHERNET)
+ {
+ if (data & 0x8000) smc91c94_reset();
+ if (data & 0x8000) logerror(" SOFT RST\n");
+ if (data & 0x4000) logerror(" FILT_CAR\n");
+ if (data & 0x0200) logerror(" STRIP CRC\n");
+ if (data & 0x0100) logerror(" RXEN\n");
+ if (data & 0x0004) logerror(" ALMUL\n");
+ if (data & 0x0002) logerror(" PRMS\n");
+ if (data & 0x0001) logerror(" RX_ABORT\n");
+ }
+ break;
+
+ case EREG_CONFIG: /* configuration register */
+ if (LOG_ETHERNET)
+ {
+ if (data & 0x1000) logerror(" NO WAIT\n");
+ if (data & 0x0400) logerror(" FULL STEP\n");
+ if (data & 0x0200) logerror(" SET SQLCH\n");
+ if (data & 0x0100) logerror(" AUI SELECT\n");
+ if (data & 0x0080) logerror(" 16 BIT\n");
+ if (data & 0x0040) logerror(" DIS LINK\n");
+ if (data & 0x0004) logerror(" INT SEL1\n");
+ if (data & 0x0002) logerror(" INT SEL0\n");
+ }
+ break;
+
+ case EREG_BASE: /* base address register */
+ if (LOG_ETHERNET)
+ {
+ logerror(" base = $%04X\n", (data & 0xe000) | ((data & 0x1f00) >> 3));
+ logerror(" romsize = %d\n", ((data & 0xc0) >> 6));
+ logerror(" romaddr = $%05X\n", ((data & 0x3e) << 13));
+ }
+ break;
+
+ case EREG_CONTROL: /* control register */
+ if (LOG_ETHERNET)
+ {
+ if (data & 0x4000) logerror(" RCV_BAD\n");
+ if (data & 0x2000) logerror(" PWRDN\n");
+ if (data & 0x0800) logerror(" AUTO RELEASE\n");
+ if (data & 0x0080) logerror(" LE ENABLE\n");
+ if (data & 0x0040) logerror(" CR ENABLE\n");
+ if (data & 0x0020) logerror(" TE ENABLE\n");
+ if (data & 0x0004) logerror(" EEPROM SELECT\n");
+ if (data & 0x0002) logerror(" RELOAD\n");
+ if (data & 0x0001) logerror(" STORE\n");
+ }
+ break;
+
+ case EREG_MMU_COMMAND: /* command register */
+ process_command(data);
+ break;
+
+ case EREG_DATA_0: /* data register */
+ case EREG_DATA_1: /* data register */
+ {
+ UINT8 *buffer = (ethernet.reg[EREG_POINTER] & 0x8000) ? ethernet.rx : ethernet.tx;
+ int addr = ethernet.reg[EREG_POINTER] & 0x7ff;
+ buffer[addr++] = data;
+ if (!(mem_mask & 0xff00))
+ buffer[addr++] = data >> 8;
+ if (ethernet.reg[EREG_POINTER] & 0x4000)
+ ethernet.reg[EREG_POINTER] = (ethernet.reg[EREG_POINTER] & ~0x7ff) | (addr & 0x7ff);
+ break;
+ }
+
+ case EREG_INTERRUPT:
+ ethernet.reg[EREG_INTERRUPT] &= ~(data & 0x56);
+ update_ethernet_irq();
+ break;
+ }
+}
diff --git a/src/emu/machine/smc91c9x.h b/src/emu/machine/smc91c9x.h
new file mode 100644
index 00000000000..2cef861294c
--- /dev/null
+++ b/src/emu/machine/smc91c9x.h
@@ -0,0 +1,22 @@
+/*************************************************************************
+
+ SMC91C9X ethernet controller implementation
+
+ by Aaron Giles
+
+**************************************************************************/
+
+#ifndef __SMC91C9X__
+#define __SMC91C9X__
+
+struct smc91c9x_interface
+{
+ void (*irq_handler)(int state);
+};
+
+void smc91c94_init(struct smc91c9x_interface *config);
+void smc91c94_reset(void);
+READ16_HANDLER( smc91c94_r );
+WRITE16_HANDLER( smc91c94_w );
+
+#endif
diff --git a/src/emu/machine/timekpr.c b/src/emu/machine/timekpr.c
new file mode 100644
index 00000000000..125ac7308a6
--- /dev/null
+++ b/src/emu/machine/timekpr.c
@@ -0,0 +1,483 @@
+/*
+ * STmicroelectronics TIMEKEEPER SRAM
+ *
+ * Supports: MK48T08, M48T02 & M48T58
+ *
+ */
+
+#include "driver.h"
+#include "machine/timekpr.h"
+
+struct timekeeper_chip
+{
+ UINT8 control;
+ UINT8 seconds;
+ UINT8 minutes;
+ UINT8 hours;
+ UINT8 day;
+ UINT8 date;
+ UINT8 month;
+ UINT8 year;
+ UINT8 century;
+ UINT8 *data;
+ int type;
+ int size;
+ int offset_control;
+ int offset_seconds;
+ int offset_minutes;
+ int offset_hours;
+ int offset_day;
+ int offset_date;
+ int offset_month;
+ int offset_year;
+ int offset_century;
+ int offset_flags;
+};
+
+struct timekeeper_chip timekeeper[ MAX_TIMEKEEPER_CHIPS ];
+
+#define MASK_SECONDS ( 0x7f )
+#define MASK_MINUTES ( 0x7f )
+#define MASK_HOURS ( 0x3f )
+#define MASK_DAY ( 0x07 )
+#define MASK_DATE ( 0x3f )
+#define MASK_MONTH ( 0x1f )
+#define MASK_YEAR ( 0xff )
+#define MASK_CENTURY ( 0xff )
+
+#define CONTROL_W ( 0x80 )
+#define CONTROL_R ( 0x40 )
+#define CONTROL_S ( 0x20 ) /* not emulated */
+#define CONTROL_CALIBRATION ( 0x1f ) /* not emulated */
+
+#define SECONDS_ST ( 0x80 )
+
+#define DAY_FT ( 0x40 ) /* not emulated */
+#define DAY_CEB ( 0x20 ) /* M48T58 */
+#define DAY_CB ( 0x10 ) /* M48T58 */
+
+#define DATE_BLE ( 0x80 ) /* M48T58: not emulated */
+#define DATE_BL ( 0x40 ) /* M48T58: not emulated */
+
+#define FLAGS_BL ( 0x10 ) /* MK48T08: not emulated */
+
+INLINE UINT8 make_bcd(UINT8 data)
+{
+ return ( ( ( data / 10 ) % 10 ) << 4 ) + ( data % 10 );
+}
+
+INLINE UINT8 from_bcd( UINT8 data )
+{
+ return ( ( ( data >> 4 ) & 15 ) * 10 ) + ( data & 15 );
+}
+
+static int inc_bcd( UINT8 *data, int mask, int min, int max )
+{
+ int bcd;
+ int carry;
+
+ bcd = ( *( data ) + 1 ) & mask;
+ carry = 0;
+
+ if( ( bcd & 0x0f ) > 9 )
+ {
+ bcd &= 0xf0;
+ bcd += 0x10;
+ if( bcd > max )
+ {
+ bcd = min;
+ carry = 1;
+ }
+ }
+
+ *( data ) = ( *( data ) & ~mask ) | ( bcd & mask );
+ return carry;
+}
+
+static void counter_to_ram( UINT8 *data, int offset, int counter )
+{
+ if( offset >= 0 )
+ {
+ data[ offset ] = counter;
+ }
+}
+
+static void counters_to_ram( struct timekeeper_chip *c )
+{
+ counter_to_ram( c->data, c->offset_control, c->control );
+ counter_to_ram( c->data, c->offset_seconds, c->seconds );
+ counter_to_ram( c->data, c->offset_minutes, c->minutes );
+ counter_to_ram( c->data, c->offset_hours, c->hours );
+ counter_to_ram( c->data, c->offset_day, c->day );
+ counter_to_ram( c->data, c->offset_date, c->date );
+ counter_to_ram( c->data, c->offset_month, c->month );
+ counter_to_ram( c->data, c->offset_year, c->year );
+ counter_to_ram( c->data, c->offset_century, c->century );
+}
+
+static int counter_from_ram( UINT8 *data, int offset )
+{
+ if( offset >= 0 )
+ {
+ return data[ offset ];
+ }
+ return 0;
+}
+
+static void counters_from_ram( int chip )
+{
+ struct timekeeper_chip *c = &timekeeper[ chip ];
+
+ c->control = counter_from_ram( c->data, c->offset_control );
+ c->seconds = counter_from_ram( c->data, c->offset_seconds );
+ c->minutes = counter_from_ram( c->data, c->offset_minutes );
+ c->hours = counter_from_ram( c->data, c->offset_hours );
+ c->day = counter_from_ram( c->data, c->offset_day );
+ c->date = counter_from_ram( c->data, c->offset_date );
+ c->month = counter_from_ram( c->data, c->offset_month );
+ c->year = counter_from_ram( c->data, c->offset_year );
+ c->century = counter_from_ram( c->data, c->offset_century );
+}
+
+static TIMER_CALLBACK_PTR( timekeeper_tick )
+{
+ struct timekeeper_chip *c = param;
+
+ int carry;
+
+ if( ( c->seconds & SECONDS_ST ) != 0 ||
+ ( c->control & CONTROL_W ) != 0 )
+ {
+ return;
+ }
+
+ carry = inc_bcd( &c->seconds, MASK_SECONDS, 0x00, 0x59 );
+ if( carry )
+ {
+ carry = inc_bcd( &c->minutes, MASK_MINUTES, 0x00, 0x59 );
+ }
+ if( carry )
+ {
+ carry = inc_bcd( &c->hours, MASK_HOURS, 0x00, 0x23 );
+ }
+
+ if( carry )
+ {
+ UINT8 month;
+ UINT8 year;
+ UINT8 maxdays;
+ static const UINT8 daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 };
+
+ inc_bcd( &c->day, MASK_DAY, 0x01, 0x07 );
+
+ month = from_bcd( c->month );
+ year = from_bcd( c->year );
+
+ if( month == 2 && ( year % 4 ) == 0 )
+ {
+ maxdays = 0x29;
+ }
+ else if( month >= 1 && month <= 12 )
+ {
+ maxdays = daysinmonth[ month - 1 ];
+ }
+ else
+ {
+ maxdays = 0x31;
+ }
+
+ carry = inc_bcd( &c->date, MASK_DATE, 0x01, maxdays );
+ }
+ if( carry )
+ {
+ carry = inc_bcd( &c->month, MASK_MONTH, 0x01, 0x12 );
+ }
+ if( carry )
+ {
+ carry = inc_bcd( &c->year, MASK_YEAR, 0x00, 0x99 );
+ }
+ if( carry )
+ {
+ carry = inc_bcd( &c->century, MASK_CENTURY, 0x00, 0x99 );
+ if( c->type == TIMEKEEPER_M48T58 && ( c->day & DAY_CEB ) != 0 )
+ {
+ c->day ^= DAY_CB;
+ }
+ }
+
+ if( ( c->control & CONTROL_R ) == 0 )
+ {
+ counters_to_ram( c );
+ }
+}
+
+void timekeeper_init( int chip, int type, UINT8 *data )
+{
+ emu_timer *timer;
+ attotime duration;
+ mame_system_time systime;
+ struct timekeeper_chip *c;
+
+ if( chip >= MAX_TIMEKEEPER_CHIPS )
+ {
+ logerror( "timekeeper_init( %d ) invalid chip\n", chip );
+ return;
+ }
+ c = &timekeeper[ chip ];
+
+ c->type = type;
+
+ switch( c->type )
+ {
+ case TIMEKEEPER_M48T02:
+ c->offset_control = 0x7f8;
+ c->offset_seconds = 0x7f9;
+ c->offset_minutes = 0x7fa;
+ c->offset_hours = 0x7fb;
+ c->offset_day = 0x7fc;
+ c->offset_date = 0x7fd;
+ c->offset_month = 0x7fe;
+ c->offset_year = 0x7ff;
+ c->offset_century = -1;
+ c->offset_flags = -1;
+ c->size = 0x800;
+ break;
+ case TIMEKEEPER_M48T58:
+ c->offset_control = 0x1ff8;
+ c->offset_seconds = 0x1ff9;
+ c->offset_minutes = 0x1ffa;
+ c->offset_hours = 0x1ffb;
+ c->offset_day = 0x1ffc;
+ c->offset_date = 0x1ffd;
+ c->offset_month = 0x1ffe;
+ c->offset_year = 0x1fff;
+ c->offset_century = -1;
+ c->offset_flags = -1;
+ c->size = 0x2000;
+ break;
+ case TIMEKEEPER_MK48T08:
+ c->offset_control = 0x1ff8;
+ c->offset_seconds = 0x1ff9;
+ c->offset_minutes = 0x1ffa;
+ c->offset_hours = 0x1ffb;
+ c->offset_day = 0x1ffc;
+ c->offset_date = 0x1ffd;
+ c->offset_month = 0x1ffe;
+ c->offset_year = 0x1fff;
+ c->offset_century = 0x1ff1;
+ c->offset_flags = 0x1ff0;
+ c->size = 0x2000;
+ break;
+ }
+
+ if( data == NULL )
+ {
+ data = auto_malloc( c->size );
+ memset( data, 0xff, c->size );
+ }
+ c->data = data;
+
+ mame_get_base_datetime(Machine, &systime);
+
+ c->control = 0;
+ c->seconds = make_bcd( systime.local_time.second );
+ c->minutes = make_bcd( systime.local_time.minute );
+ c->hours = make_bcd( systime.local_time.hour );
+ c->day = make_bcd( systime.local_time.weekday + 1 );
+ c->date = make_bcd( systime.local_time.mday );
+ c->month = make_bcd( systime.local_time.month + 1 );
+ c->year = make_bcd( systime.local_time.year % 100 );
+ c->century = make_bcd( systime.local_time.year / 100 );
+
+ state_save_register_item( "timekeeper", chip, c->control );
+ state_save_register_item( "timekeeper", chip, c->seconds );
+ state_save_register_item( "timekeeper", chip, c->minutes );
+ state_save_register_item( "timekeeper", chip, c->hours );
+ state_save_register_item( "timekeeper", chip, c->day );
+ state_save_register_item( "timekeeper", chip, c->date );
+ state_save_register_item( "timekeeper", chip, c->month );
+ state_save_register_item( "timekeeper", chip, c->year );
+ state_save_register_item( "timekeeper", chip, c->century );
+ state_save_register_item_pointer( "timekeeper", chip, c->data, c->size );
+
+ timer = timer_alloc_ptr( timekeeper_tick, c );
+ duration = ATTOTIME_IN_SEC(1);
+ timer_adjust_ptr( timer, duration, duration );
+}
+
+static void timekeeper_nvram( int chip, mame_file *file, int read_or_write )
+{
+ struct timekeeper_chip *c;
+ if( chip >= MAX_TIMEKEEPER_CHIPS )
+ {
+ logerror( "timekeeper_nvram( %d ) invalid chip\n", chip );
+ return;
+ }
+ c = &timekeeper[ chip ];
+
+ if( read_or_write )
+ {
+ mame_fwrite( file, c->data, c->size );
+ }
+ else
+ {
+ if( file )
+ {
+ mame_fread( file, c->data, c->size );
+ }
+ counters_to_ram( c );
+ }
+}
+
+NVRAM_HANDLER( timekeeper_0 ) { timekeeper_nvram( 0, file, read_or_write ); }
+
+static UINT8 timekeeper_read( UINT32 chip, offs_t offset )
+{
+ UINT8 data;
+ struct timekeeper_chip *c;
+ if( chip >= MAX_TIMEKEEPER_CHIPS )
+ {
+ logerror( "%08x: timekeeper_read( %d, %04x ) chip out of range\n", activecpu_get_pc(), chip, offset );
+ return 0;
+ }
+ c = &timekeeper[ chip ];
+
+ data = c->data[ offset ];
+// logerror( "%08x: timekeeper_read( %d, %04x ) %02x\n", activecpu_get_pc(), chip, offset, data );
+ return data;
+}
+
+static void timekeeper_write( UINT32 chip, offs_t offset, UINT8 data )
+{
+ struct timekeeper_chip *c;
+ if( chip >= MAX_TIMEKEEPER_CHIPS )
+ {
+ logerror( "%08x: timekeeper_write( %d, %04x, %02x ) chip out of range\n", activecpu_get_pc(), chip, offset, data );
+ return;
+ }
+ c = &timekeeper[ chip ];
+
+ if( offset == c->offset_control )
+ {
+ if( ( c->control & CONTROL_W ) != 0 &&
+ ( data & CONTROL_W ) == 0 )
+ {
+ counters_from_ram( chip );
+ }
+ c->control = data;
+ }
+ else if( c->type == TIMEKEEPER_M48T58 && offset == c->offset_day )
+ {
+ c->day = ( c->day & ~DAY_CEB ) | ( data & DAY_CEB );
+ }
+ else if( c->type == TIMEKEEPER_M48T58 && offset == c->offset_date )
+ {
+ data &= ~DATE_BL;
+ }
+ else if( c->type == TIMEKEEPER_MK48T08 && offset == c->offset_flags )
+ {
+ data &= ~FLAGS_BL;
+ }
+
+// logerror( "%08x: timekeeper_write( %d, %04x, %02x )\n", activecpu_get_pc(), chip, offset, data );
+ c->data[ offset ] = data;
+}
+
+/* 16bit memory handlers */
+
+static UINT16 timekeeper_msb16_read( UINT32 chip, offs_t offset, UINT16 mem_mask )
+{
+ UINT16 data = 0;
+ if( ACCESSING_MSB16 )
+ {
+ data |= timekeeper_read( chip, offset ) << 8;
+ }
+ return data;
+}
+
+static void timekeeper_msb16_write( UINT32 chip, offs_t offset, UINT16 data, UINT16 mem_mask )
+{
+ if( ACCESSING_MSB16 )
+ {
+ timekeeper_write( chip, offset, data >> 8 );
+ }
+}
+
+READ16_HANDLER( timekeeper_0_msb16_r ) { return timekeeper_msb16_read( 0, offset, mem_mask ); }
+WRITE16_HANDLER( timekeeper_0_msb16_w ) { timekeeper_msb16_write( 0, offset, data, mem_mask ); }
+
+/* 32bit memory handlers */
+
+static UINT32 timekeeper_32be_read( UINT32 chip, offs_t offset, UINT32 mem_mask )
+{
+ UINT32 data = 0;
+ if( ACCESSING_MSB32 )
+ {
+ data |= timekeeper_read( chip, ( offset * 4 ) + 0 ) << 24;
+ }
+ if( ( mem_mask & 0x00ff0000 ) == 0 )
+ {
+ data |= timekeeper_read( chip, ( offset * 4 ) + 1 ) << 16;
+ }
+ if( ( mem_mask & 0x0000ff00 ) == 0 )
+ {
+ data |= timekeeper_read( chip, ( offset * 4 ) + 2 ) << 8;
+ }
+ if( ACCESSING_LSB32 )
+ {
+ data |= timekeeper_read( chip, ( offset * 4 ) + 3 ) << 0;
+ }
+ return data;
+}
+
+static void timekeeper_32be_write( UINT32 chip, offs_t offset, UINT32 data, UINT32 mem_mask )
+{
+ if( ACCESSING_MSB32 )
+ {
+ timekeeper_write( chip, ( offset * 4 ) + 0, data >> 24 );
+ }
+ if( ( mem_mask & 0x00ff0000 ) == 0 )
+ {
+ timekeeper_write( chip, ( offset * 4 ) + 1, data >> 16 );
+ }
+ if( ( mem_mask & 0x0000ff00 ) == 0 )
+ {
+ timekeeper_write( chip, ( offset * 4 ) + 2, data >> 8 );
+ }
+ if( ACCESSING_LSB32 )
+ {
+ timekeeper_write( chip, ( offset * 4 ) + 3, data >> 0 );
+ }
+}
+
+READ32_HANDLER( timekeeper_0_32be_r ) { return timekeeper_32be_read( 0, offset, mem_mask ); }
+WRITE32_HANDLER( timekeeper_0_32be_w ) { timekeeper_32be_write( 0, offset, data, mem_mask ); }
+
+static UINT32 timekeeper_32le_lsb16_read( UINT32 chip, offs_t offset, UINT32 mem_mask )
+{
+ UINT32 data = 0;
+ if( ACCESSING_LSB32 )
+ {
+ data |= timekeeper_read( chip, ( offset * 2 ) + 0 ) << 0;
+ }
+ if( ( mem_mask & 0x00ff0000 ) == 0 )
+ {
+ data |= timekeeper_read( chip, ( offset * 2 ) + 1 ) << 16;
+ }
+ return data;
+}
+
+static void timekeeper_32le_lsb16_write( UINT32 chip, offs_t offset, UINT32 data, UINT32 mem_mask )
+{
+ if( ACCESSING_LSB32 )
+ {
+ timekeeper_write( chip, ( offset * 2 ) + 0, data >> 0 );
+ }
+ if( ( mem_mask & 0x00ff0000 ) == 0 )
+ {
+ timekeeper_write( chip, ( offset * 2 ) + 1, data >> 16 );
+ }
+}
+
+READ32_HANDLER( timekeeper_0_32le_lsb16_r ) { return timekeeper_32le_lsb16_read( 0, offset, mem_mask ); }
+WRITE32_HANDLER( timekeeper_0_32le_lsb16_w ) { timekeeper_32le_lsb16_write( 0, offset, data, mem_mask ); }
diff --git a/src/emu/machine/timekpr.h b/src/emu/machine/timekpr.h
new file mode 100644
index 00000000000..f651168fa80
--- /dev/null
+++ b/src/emu/machine/timekpr.h
@@ -0,0 +1,35 @@
+/*
+ * STmicroelectronics TIMEKEEPER SRAM
+ *
+ * Supports: MK48T08, M48T02 & M48T58
+ *
+ */
+
+#if !defined( TIMEKPR_H )
+#define TIMEKPR_H ( 1 )
+
+extern void timekeeper_init( int chip, int type, UINT8 *data );
+
+#define MAX_TIMEKEEPER_CHIPS ( 1 )
+
+#define TIMEKEEPER_M48T58 ( 1 )
+#define TIMEKEEPER_M48T02 ( 2 )
+#define TIMEKEEPER_MK48T08 ( 3 )
+
+/* nvram handlers */
+
+extern NVRAM_HANDLER( timekeeper_0 );
+
+/* 16bit memory handlers */
+
+extern READ16_HANDLER( timekeeper_0_msb16_r );
+extern WRITE16_HANDLER( timekeeper_0_msb16_w );
+
+/* 32bit memory handlers */
+
+extern READ32_HANDLER( timekeeper_0_32be_r );
+extern WRITE32_HANDLER( timekeeper_0_32be_w );
+extern READ32_HANDLER( timekeeper_0_32le_lsb16_r );
+extern WRITE32_HANDLER( timekeeper_0_32le_lsb16_w );
+
+#endif
diff --git a/src/emu/machine/tmp68301.c b/src/emu/machine/tmp68301.c
new file mode 100644
index 00000000000..f8bbb01f2d9
--- /dev/null
+++ b/src/emu/machine/tmp68301.c
@@ -0,0 +1,179 @@
+/***************************************************************************
+
+ TMP68301 basic emulation + Interrupt Handling
+
+ The Toshiba TMP68301 is a 68HC000 + serial I/O, parallel I/O,
+ 3 timers, address decoder, wait generator, interrupt controller,
+ all integrated in a single chip.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "machine/tmp68301.h"
+
+UINT16 *tmp68301_regs;
+
+static UINT8 tmp68301_IE[3]; // 3 External Interrupt Lines
+static emu_timer *tmp68301_timer[3]; // 3 Timers
+
+static int tmp68301_irq_vector[8];
+
+static void tmp68301_update_timer( int i );
+
+static int tmp68301_irq_callback(int int_level)
+{
+ int vector = tmp68301_irq_vector[int_level];
+// logerror("CPU #0 PC %06X: irq callback returns %04X for level %x\n",activecpu_get_pc(),vector,int_level);
+ return vector;
+}
+
+static TIMER_CALLBACK( tmp68301_timer_callback )
+{
+ int i = param;
+ UINT16 TCR = tmp68301_regs[(0x200 + i * 0x20)/2];
+ UINT16 IMR = tmp68301_regs[0x94/2]; // Interrupt Mask Register (IMR)
+ UINT16 ICR = tmp68301_regs[0x8e/2+i]; // Interrupt Controller Register (ICR7..9)
+ UINT16 IVNR = tmp68301_regs[0x9a/2]; // Interrupt Vector Number Register (IVNR)
+
+// logerror("CPU #0 PC %06X: callback timer %04X, j = %d\n",activecpu_get_pc(),i,tcount);
+
+ if ( (TCR & 0x0004) && // INT
+ !(IMR & (0x100<<i))
+ )
+ {
+ int level = ICR & 0x0007;
+
+ // Interrupt Vector Number Register (IVNR)
+ tmp68301_irq_vector[level] = IVNR & 0x00e0;
+ tmp68301_irq_vector[level] += 4+i;
+
+ cpunum_set_input_line(0,level,HOLD_LINE);
+ }
+
+ if (TCR & 0x0080) // N/1
+ {
+ // Repeat
+ tmp68301_update_timer(i);
+ }
+ else
+ {
+ // One Shot
+ }
+}
+
+void tmp68301_update_timer( int i )
+{
+ UINT16 TCR = tmp68301_regs[(0x200 + i * 0x20)/2];
+ UINT16 MAX1 = tmp68301_regs[(0x204 + i * 0x20)/2];
+ UINT16 MAX2 = tmp68301_regs[(0x206 + i * 0x20)/2];
+
+ int max = 0;
+ attotime duration = attotime_zero;
+
+ timer_adjust(tmp68301_timer[i],attotime_never,i,attotime_never);
+
+ // timers 1&2 only
+ switch( (TCR & 0x0030)>>4 ) // MR2..1
+ {
+ case 1:
+ max = MAX1;
+ break;
+ case 2:
+ max = MAX2;
+ break;
+ }
+
+ switch ( (TCR & 0xc000)>>14 ) // CK2..1
+ {
+ case 0: // System clock (CLK)
+ if (max)
+ {
+ int scale = (TCR & 0x3c00)>>10; // P4..1
+ if (scale > 8) scale = 8;
+ duration = attotime_mul(ATTOTIME_IN_HZ(Machine->drv->cpu[0].clock), (1 << scale) * max);
+ }
+ break;
+ }
+
+// logerror("CPU #0 PC %06X: TMP68301 Timer %d, duration %lf, max %04X\n",activecpu_get_pc(),i,duration,max);
+
+ if (!(TCR & 0x0002)) // CS
+ {
+ if (attotime_compare(duration, attotime_zero))
+ timer_adjust(tmp68301_timer[i],duration,i,attotime_zero);
+ else
+ logerror("CPU #0 PC %06X: TMP68301 error, timer %d duration is 0\n",activecpu_get_pc(),i);
+ }
+}
+
+MACHINE_RESET( tmp68301 )
+{
+ int i;
+ for (i = 0; i < 3; i++)
+ tmp68301_timer[i] = timer_alloc(tmp68301_timer_callback);
+
+ for (i = 0; i < 3; i++)
+ tmp68301_IE[i] = 0;
+
+ cpunum_set_irq_callback(0, tmp68301_irq_callback);
+}
+
+/* Update the IRQ state based on all possible causes */
+static void update_irq_state(void)
+{
+ int i;
+
+ /* Take care of external interrupts */
+
+ UINT16 IMR = tmp68301_regs[0x94/2]; // Interrupt Mask Register (IMR)
+ UINT16 IVNR = tmp68301_regs[0x9a/2]; // Interrupt Vector Number Register (IVNR)
+
+ for (i = 0; i < 3; i++)
+ {
+ if ( (tmp68301_IE[i]) &&
+ !(IMR & (1<<i))
+ )
+ {
+ UINT16 ICR = tmp68301_regs[0x80/2+i]; // Interrupt Controller Register (ICR0..2)
+
+ // Interrupt Controller Register (ICR0..2)
+ int level = ICR & 0x0007;
+
+ // Interrupt Vector Number Register (IVNR)
+ tmp68301_irq_vector[level] = IVNR & 0x00e0;
+ tmp68301_irq_vector[level] += i;
+
+ tmp68301_IE[i] = 0; // Interrupts are edge triggerred
+
+ cpunum_set_input_line(0,level,HOLD_LINE);
+ }
+ }
+}
+
+WRITE16_HANDLER( tmp68301_regs_w )
+{
+ COMBINE_DATA(&tmp68301_regs[offset]);
+
+ if (!ACCESSING_LSB) return;
+
+// logerror("CPU #0 PC %06X: TMP68301 Reg %04X<-%04X & %04X\n",activecpu_get_pc(),offset*2,data,mem_mask^0xffff);
+
+ switch( offset * 2 )
+ {
+ // Timers
+ case 0x200:
+ case 0x220:
+ case 0x240:
+ {
+ int i = ((offset*2) >> 5) & 3;
+
+ tmp68301_update_timer( i );
+ }
+ break;
+ }
+}
+
+void tmp68301_external_interrupt_0() { tmp68301_IE[0] = 1; update_irq_state(); }
+void tmp68301_external_interrupt_1() { tmp68301_IE[1] = 1; update_irq_state(); }
+void tmp68301_external_interrupt_2() { tmp68301_IE[2] = 1; update_irq_state(); }
+
diff --git a/src/emu/machine/tmp68301.h b/src/emu/machine/tmp68301.h
new file mode 100644
index 00000000000..55efe169220
--- /dev/null
+++ b/src/emu/machine/tmp68301.h
@@ -0,0 +1,16 @@
+#ifndef TMP68301_H
+#define TMP68301_H
+
+// Machine init
+MACHINE_RESET( tmp68301 );
+
+// Hardware Registers
+extern UINT16 *tmp68301_regs;
+WRITE16_HANDLER( tmp68301_regs_w );
+
+// Interrupts
+void tmp68301_external_interrupt_0(void);
+void tmp68301_external_interrupt_1(void);
+void tmp68301_external_interrupt_2(void);
+
+#endif
diff --git a/src/emu/machine/upd4701.c b/src/emu/machine/upd4701.c
new file mode 100644
index 00000000000..591561913dc
--- /dev/null
+++ b/src/emu/machine/upd4701.c
@@ -0,0 +1,307 @@
+/*
+ * uPD4701
+ *
+ * Incremental Encoder Control
+ *
+ */
+
+#include "driver.h"
+#include "machine/upd4701.h"
+
+struct uPD4701_chip
+{
+ int cs;
+ int xy;
+ int ul;
+ int resetx;
+ int resety;
+ int latchx;
+ int latchy;
+ int startx;
+ int starty;
+ int x;
+ int y;
+ int switches;
+ int latchswitches;
+ int cf;
+};
+
+struct uPD4701_chip uPD4701[ UPD4701_MAXCHIP ];
+
+#define MASK_SWITCHES ( 7 )
+#define MASK_COUNTER ( 0xfff )
+
+void uPD4701_init( int chip )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_init( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &uPD4701[ chip ];
+
+ c->cs = 1;
+ c->xy = 0;
+ c->ul = 0;
+ c->resetx = 0;
+ c->resety = 0;
+ c->latchx = 0;
+ c->latchy = 0;
+ c->startx = 0;
+ c->starty = 0;
+ c->x = 0;
+ c->y = 0;
+ c->switches = 0;
+ c->latchswitches = 0;
+ c->cf = 1;
+
+ state_save_register_item( "uPD4701", chip, c->cs );
+ state_save_register_item( "uPD4701", chip, c->xy );
+ state_save_register_item( "uPD4701", chip, c->ul );
+ state_save_register_item( "uPD4701", chip, c->resetx );
+ state_save_register_item( "uPD4701", chip, c->resety );
+ state_save_register_item( "uPD4701", chip, c->latchx );
+ state_save_register_item( "uPD4701", chip, c->latchy );
+ state_save_register_item( "uPD4701", chip, c->startx );
+ state_save_register_item( "uPD4701", chip, c->starty );
+ state_save_register_item( "uPD4701", chip, c->x );
+ state_save_register_item( "uPD4701", chip, c->y );
+ state_save_register_item( "uPD4701", chip, c->switches );
+ state_save_register_item( "uPD4701", chip, c->latchswitches );
+ state_save_register_item( "uPD4701", chip, c->cf );
+}
+
+void uPD4701_ul_w( int chip, int ul )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_ul_w( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &uPD4701[ chip ];
+ c->ul = ul;
+}
+
+void uPD4701_xy_w( int chip, int xy )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_xy_w( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &uPD4701[ chip ];
+ c->xy = xy;
+}
+
+void uPD4701_cs_w( int chip, int cs )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_cs_w( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &uPD4701[ chip ];
+ if( cs != c->cs )
+ {
+ c->cs = cs;
+
+ if( !c->cs )
+ {
+ c->latchx = ( c->x - c->startx ) & MASK_COUNTER;
+ c->latchy = ( c->y - c->starty ) & MASK_COUNTER;
+
+ c->latchswitches = ( ~c->switches ) & MASK_SWITCHES;
+ if( c->latchswitches != 0 )
+ {
+ c->latchswitches |= 8;
+ }
+
+ c->cf = 1;
+ }
+ }
+}
+
+void uPD4701_resetx_w( int chip, int resetx )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_resetx_w( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &uPD4701[ chip ];
+ if( c->resetx != resetx )
+ {
+ c->resetx = resetx;
+
+ if( c->resetx )
+ {
+ c->startx = c->x;
+ }
+ }
+}
+
+void uPD4701_resety_w( int chip, int resety )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_resety_w( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &uPD4701[ chip ];
+ if( c->resety != resety )
+ {
+ c->resety = resety;
+
+ if( c->resety )
+ {
+ c->starty = c->y;
+ }
+ }
+}
+
+int uPD4701_d_r( int chip )
+{
+ int data;
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_d_r( %d ) invalid chip\n", chip );
+ return 0;
+ }
+
+ c = &uPD4701[ chip ];
+ if( c->cs )
+ {
+ return 0xff;
+ }
+
+ if( c->xy )
+ {
+ data = c->latchy;
+ }
+ else
+ {
+ data = c->latchx;
+ }
+
+ data |= c->latchswitches << 12;
+
+ if( c->ul )
+ {
+ return data >> 8;
+ }
+ else
+ {
+ return data & 0xff;
+ }
+}
+
+int uPD4701_sf_r( int chip )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_sf_r( %d ) invalid chip\n", chip );
+ return 0;
+ }
+
+ c = &uPD4701[ chip ];
+ if( ( c->switches & MASK_SWITCHES ) != MASK_SWITCHES )
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+int uPD4701_cf_r( int chip )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_cf_r( %d ) invalid chip\n", chip );
+ return 0;
+ }
+
+ c = &uPD4701[ chip ];
+ return c->cf;
+}
+
+void uPD4701_x_add( int chip, int dx )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_x_add( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &uPD4701[ chip ];
+ if( !c->resetx && dx != 0 )
+ {
+ c->x += dx;
+
+ if( c->cs )
+ {
+ c->cf = 0;
+ }
+ }
+}
+
+void uPD4701_y_add( int chip, int dy )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_y_add( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &uPD4701[ chip ];
+ if( !c->resety && dy != 0 )
+ {
+ c->y += dy;
+
+ if( c->cs )
+ {
+ c->cf = 0;
+ }
+ }
+}
+
+void uPD4701_switches_set( int chip, int switches )
+{
+ struct uPD4701_chip *c;
+
+ if( chip < 0 || chip >= UPD4701_MAXCHIP )
+ {
+ logerror( "uPD4701_switches_set( %d ) invalid chip\n", chip );
+ return;
+ }
+
+ c = &uPD4701[ chip ];
+ c->switches = switches;
+}
diff --git a/src/emu/machine/upd4701.h b/src/emu/machine/upd4701.h
new file mode 100644
index 00000000000..ec038965cc1
--- /dev/null
+++ b/src/emu/machine/upd4701.h
@@ -0,0 +1,27 @@
+/*
+ * uPD4701
+ *
+ * Incremental Encoder Control
+ *
+ */
+
+#if !defined( UPD4701_H )
+
+#define UPD4701_MAXCHIP ( 1 )
+
+extern void uPD4701_init( int chip );
+extern void uPD4701_cs_w( int chip, int cs );
+extern void uPD4701_xy_w( int chip, int xy );
+extern void uPD4701_ul_w( int chip, int ul );
+extern void uPD4701_resetx_w( int chip, int resetx );
+extern void uPD4701_resety_w( int chip, int resety );
+extern int uPD4701_d_r( int chip );
+extern int uPD4701_cf_r( int chip );
+extern int uPD4701_sf_r( int chip );
+
+extern void uPD4701_x_add( int chip, int dx );
+extern void uPD4701_y_add( int chip, int dy );
+extern void uPD4701_switches_set( int chip, int switches );
+
+#define UPD4701_H
+#endif
diff --git a/src/emu/machine/wd33c93.c b/src/emu/machine/wd33c93.c
new file mode 100644
index 00000000000..6aab9dcab00
--- /dev/null
+++ b/src/emu/machine/wd33c93.c
@@ -0,0 +1,872 @@
+/*
+ * wd33c93.c
+ *
+ * WD/AMD 33c93 SCSI controller, as seen in
+ * early PCs, some MSX add-ons, NEC PC-88, and SGI
+ * Indigo, Indigo2, and Indy systems.
+ *
+ * References:
+ * WD 33c93 manual
+ * NetBSD 33c93 driver
+ *
+ */
+
+#include "driver.h"
+#include "state.h"
+#include "wd33c93.h"
+
+#define VERBOSE 0
+
+static SCSIInstance *devices[8]; // SCSI IDs 0-7
+static struct WD33C93interface *intf;
+
+/* wd register names */
+#define WD_OWN_ID 0x00
+#define WD_CONTROL 0x01
+#define WD_TIMEOUT_PERIOD 0x02
+#define WD_CDB_1 0x03
+#define WD_CDB_2 0x04
+#define WD_CDB_3 0x05
+#define WD_CDB_4 0x06
+#define WD_CDB_5 0x07
+#define WD_CDB_6 0x08
+#define WD_CDB_7 0x09
+#define WD_CDB_8 0x0a
+#define WD_CDB_9 0x0b
+#define WD_CDB_10 0x0c
+#define WD_CDB_11 0x0d
+#define WD_CDB_12 0x0e
+#define WD_TARGET_LUN 0x0f
+#define WD_COMMAND_PHASE 0x10
+#define WD_SYNCHRONOUS_TRANSFER 0x11
+#define WD_TRANSFER_COUNT_MSB 0x12
+#define WD_TRANSFER_COUNT 0x13
+#define WD_TRANSFER_COUNT_LSB 0x14
+#define WD_DESTINATION_ID 0x15
+#define WD_SOURCE_ID 0x16
+#define WD_SCSI_STATUS 0x17
+#define WD_COMMAND 0x18
+#define WD_DATA 0x19
+#define WD_QUEUE_TAG 0x1a
+#define WD_AUXILIARY_STATUS 0x1f
+
+/* WD commands */
+#define WD_CMD_RESET 0x00
+#define WD_CMD_ABORT 0x01
+#define WD_CMD_ASSERT_ATN 0x02
+#define WD_CMD_NEGATE_ACK 0x03
+#define WD_CMD_DISCONNECT 0x04
+#define WD_CMD_RESELECT 0x05
+#define WD_CMD_SEL_ATN 0x06
+#define WD_CMD_SEL 0x07
+#define WD_CMD_SEL_ATN_XFER 0x08
+#define WD_CMD_SEL_XFER 0x09
+#define WD_CMD_RESEL_RECEIVE 0x0a
+#define WD_CMD_RESEL_SEND 0x0b
+#define WD_CMD_WAIT_SEL_RECEIVE 0x0c
+#define WD_CMD_SSCC 0x0d
+#define WD_CMD_SND_DISC 0x0e
+#define WD_CMD_SET_IDI 0x0f
+#define WD_CMD_RCV_CMD 0x10
+#define WD_CMD_RCV_DATA 0x11
+#define WD_CMD_RCV_MSG_OUT 0x12
+#define WD_CMD_RCV 0x13
+#define WD_CMD_SND_STATUS 0x14
+#define WD_CMD_SND_DATA 0x15
+#define WD_CMD_SND_MSG_IN 0x16
+#define WD_CMD_SND 0x17
+#define WD_CMD_TRANS_ADDR 0x18
+#define WD_CMD_XFER_PAD 0x19
+#define WD_CMD_TRANS_INFO 0x20
+#define WD_CMD_TRANSFER_PAD 0x21
+#define WD_CMD_SBT_MODE 0x80
+
+/* ASR register */
+#define ASR_INT 0x80
+#define ASR_LCI 0x40
+#define ASR_BSY 0x20
+#define ASR_CIP 0x10
+#define ASR_PE 0x02
+#define ASR_DBR 0x01
+
+/* SCSI Bus Phases */
+#define PHS_DATA_OUT 0x00
+#define PHS_DATA_IN 0x01
+#define PHS_COMMAND 0x02
+#define PHS_STATUS 0x03
+#define PHS_MESS_OUT 0x06
+#define PHS_MESS_IN 0x07
+
+/* Command Status Register definitions */
+
+ /* reset state interrupts */
+#define CSR_RESET 0x00
+#define CSR_RESET_AF 0x01
+
+ /* successful completion interrupts */
+#define CSR_RESELECT 0x10
+#define CSR_SELECT 0x11
+#define CSR_SEL_XFER_DONE 0x16
+#define CSR_XFER_DONE 0x18
+
+ /* paused or aborted interrupts */
+#define CSR_MSGIN 0x20
+#define CSR_SDP 0x21
+#define CSR_SEL_ABORT 0x22
+#define CSR_RESEL_ABORT 0x25
+#define CSR_RESEL_ABORT_AM 0x27
+#define CSR_ABORT 0x28
+
+ /* terminated interrupts */
+#define CSR_INVALID 0x40
+#define CSR_UNEXP_DISC 0x41
+#define CSR_TIMEOUT 0x42
+#define CSR_PARITY 0x43
+#define CSR_PARITY_ATN 0x44
+#define CSR_BAD_STATUS 0x45
+#define CSR_UNEXP 0x48
+
+ /* service required interrupts */
+#define CSR_RESEL 0x80
+#define CSR_RESEL_AM 0x81
+#define CSR_DISC 0x85
+#define CSR_SRV_REQ 0x88
+
+ /* Own ID/CDB Size register */
+#define OWNID_EAF 0x08
+#define OWNID_EHP 0x10
+#define OWNID_RAF 0x20
+#define OWNID_FS_8 0x00
+#define OWNID_FS_12 0x40
+#define OWNID_FS_16 0x80
+
+ /* Control register */
+#define CTRL_HSP 0x01
+#define CTRL_HA 0x02
+#define CTRL_IDI 0x04
+#define CTRL_EDI 0x08
+#define CTRL_HHP 0x10
+#define CTRL_POLLED 0x00
+#define CTRL_BURST 0x20
+#define CTRL_BUS 0x40
+#define CTRL_DMA 0x80
+
+ /* Synchronous Transfer Register */
+#define STR_FSS 0x80
+
+ /* Destination ID register */
+#define DSTID_DPD 0x40
+#define DATA_OUT_DIR 0
+#define DATA_IN_DIR 1
+#define DSTID_SCC 0x80
+
+ /* Source ID register */
+#define SRCID_MASK 0x07
+#define SRCID_SIV 0x08
+#define SRCID_DSP 0x20
+#define SRCID_ES 0x40
+#define SRCID_ER 0x80
+
+/* command handler definition */
+typedef void (*cmd_handler)(void);
+
+#define TEMP_INPUT_LEN 65536
+#define FIFO_SIZE 12
+
+/* internal controller data definition */
+typedef struct
+{
+ UINT8 sasr;
+ UINT8 regs[WD_AUXILIARY_STATUS+1];
+ UINT8 fifo[FIFO_SIZE];
+ int fifo_pos;
+ UINT8 *temp_input;
+ int temp_input_pos;
+ UINT8 busphase;
+ UINT8 identify;
+ int read_pending;
+ emu_timer *cmd_timer;
+} _wd33c93_data;
+
+/* local instance of controller data */
+static _wd33c93_data scsi_data;
+
+
+/* convernience functions */
+static UINT8 wd33c93_getunit( void )
+{
+ /* return the destination unit id */
+ return scsi_data.regs[WD_DESTINATION_ID] & SRCID_MASK;
+}
+
+static void wd33c93_set_xfer_count( int count )
+{
+ /* set the count */
+ scsi_data.regs[ WD_TRANSFER_COUNT_LSB ] = count & 0xff;
+ scsi_data.regs[ WD_TRANSFER_COUNT ] = ( count >> 8 ) & 0xff;
+ scsi_data.regs[ WD_TRANSFER_COUNT_MSB ] = ( count >> 16 ) & 0xff;
+}
+
+static int wd33c93_get_xfer_count( void )
+{
+ /* get the count */
+ int count = scsi_data.regs[ WD_TRANSFER_COUNT_MSB ];
+
+ count <<= 8;
+ count |= scsi_data.regs[ WD_TRANSFER_COUNT ];
+ count <<= 8;
+ count |= scsi_data.regs[ WD_TRANSFER_COUNT_LSB ];
+
+ return count;
+}
+
+static void wd33c93_read_data(int bytes, UINT8 *pData)
+{
+ UINT8 unit = wd33c93_getunit();
+
+ if ( devices[unit] )
+ {
+ SCSIReadData( devices[unit], pData, bytes );
+ }
+ else
+ {
+ logerror("wd33c93: request for unknown device SCSI ID %d\n", unit);
+ }
+}
+
+static void wd33c93_complete_immediate( int status )
+{
+ /* reset our timer */
+ timer_reset( scsi_data.cmd_timer, attotime_never );
+
+ /* set the new status */
+ scsi_data.regs[WD_SCSI_STATUS] = status & 0xff;
+
+ /* set interrupt pending */
+ scsi_data.regs[WD_AUXILIARY_STATUS] |= ASR_INT;
+
+ /* check for error conditions */
+ if ( wd33c93_get_xfer_count() > 0 )
+ {
+ /* set data buffer ready */
+ scsi_data.regs[WD_AUXILIARY_STATUS] |= ASR_DBR;
+ }
+ else
+ {
+ /* clear data buffer ready */
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR;
+ }
+
+ /* clear command in progress and bus busy */
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY);
+
+ /* if we have a callback, call it */
+ if (intf && intf->irq_callback)
+ {
+ intf->irq_callback(1);
+ }
+}
+
+static TIMER_CALLBACK(wd33c93_complete_cb)
+{
+ wd33c93_complete_immediate( param );
+}
+
+static TIMER_CALLBACK(wd33c93_service_request)
+{
+ /* issue a message out request */
+ wd33c93_complete_immediate(CSR_SRV_REQ | scsi_data.busphase);
+}
+
+static TIMER_CALLBACK(wd33c93_deassert_cip)
+{
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~ASR_CIP;
+}
+
+static void wd33c93_complete_cmd( UINT8 status )
+{
+ /* fire off a timer to complete the command */
+ timer_adjust( scsi_data.cmd_timer, ATTOTIME_IN_USEC(1), status, attotime_zero );
+}
+
+/* command handlers */
+static void wd33c93_invalid_cmd( void )
+{
+ logerror( "Unknown/Unimplemented SCSI controller command: %02x (PC=%x)\n", scsi_data.regs[WD_COMMAND], activecpu_get_pc() );
+
+ /* complete the command */
+ wd33c93_complete_cmd( CSR_INVALID );
+}
+
+static void wd33c93_reset_cmd( void )
+{
+ int advanced = 0;
+
+ /* see if it wants us to reset with advanced features */
+ if ( scsi_data.regs[WD_OWN_ID] & OWNID_EAF )
+ {
+ advanced = 1;
+ }
+
+ /* clear out all registers */
+ memset( scsi_data.regs, 0, sizeof( scsi_data.regs ) );
+
+ /* complete the command */
+ wd33c93_complete_cmd(advanced ? CSR_RESET_AF : CSR_RESET);
+}
+
+static void wd33c93_abort_cmd( void )
+{
+ /* complete the command */
+ wd33c93_complete_cmd(CSR_ABORT);
+}
+
+static void wd33c93_disconnect_cmd( void )
+{
+ /* complete the command */
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY);
+}
+
+static void wd33c93_select_cmd( void )
+{
+ UINT8 unit = wd33c93_getunit();
+ UINT8 newstatus;
+
+ /* see if we can select that device */
+ if ( devices[unit] )
+ {
+ /* device is available - signal selection done */
+ newstatus = CSR_SELECT;
+
+ /* determine the next bus phase depending on the command */
+ if ( (scsi_data.regs[WD_COMMAND] & 0x7f) == WD_CMD_SEL_ATN )
+ {
+ /* /ATN asserted during select: Move to Message Out Phase to read identify */
+ scsi_data.busphase = PHS_MESS_OUT;
+ }
+ else
+ {
+ /* No /ATN asserted: Move to Command Phase */
+ scsi_data.busphase = PHS_COMMAND;
+ }
+
+ /* queue up a service request out in the future */
+ timer_set( ATTOTIME_IN_USEC(50), 0, wd33c93_service_request );
+ }
+ else
+ {
+ /* device is not available */
+ newstatus = CSR_TIMEOUT;
+ }
+
+ /* complete the command */
+ wd33c93_complete_cmd(newstatus);
+}
+
+static void wd33c93_selectxfer_cmd( void )
+{
+ UINT8 unit = wd33c93_getunit();
+ UINT8 newstatus;
+
+ /* see if we can select that device */
+ if ( devices[unit] )
+ {
+ if ( scsi_data.regs[WD_COMMAND_PHASE] < 0x45 )
+ {
+ /* device is available */
+ int xfercount;
+ int phase;
+
+ /* do the request */
+ SCSISetCommand( devices[unit], &scsi_data.regs[WD_CDB_1], 12 );
+ SCSIExecCommand( devices[unit], &xfercount );
+ SCSIGetPhase( devices[unit], &phase );
+
+ /* set transfer count */
+ if ( wd33c93_get_xfer_count() > TEMP_INPUT_LEN )
+ {
+ logerror( "WD33C93: Transfer count too big. Please increase TEMP_INPUT_LEN (size=%d)\n", wd33c93_get_xfer_count() );
+ wd33c93_set_xfer_count( TEMP_INPUT_LEN );
+ }
+
+ switch( phase )
+ {
+ case SCSI_PHASE_DATAIN:
+ scsi_data.read_pending = 1;
+ break;
+ }
+ }
+
+ if ( scsi_data.read_pending )
+ {
+ int len = TEMP_INPUT_LEN;
+
+ if ( wd33c93_get_xfer_count() < len ) len = wd33c93_get_xfer_count();
+
+ memset( &scsi_data.temp_input[0], 0, TEMP_INPUT_LEN );
+ wd33c93_read_data( len, &scsi_data.temp_input[0] );
+ scsi_data.temp_input_pos = 0;
+ scsi_data.read_pending = 0;
+ }
+
+ scsi_data.regs[WD_TARGET_LUN] = 0;
+ scsi_data.regs[WD_CONTROL] |= CTRL_EDI;
+ scsi_data.regs[WD_COMMAND_PHASE] = 0x60;
+
+ /* signal transfer ready */
+ newstatus = CSR_SEL_XFER_DONE;
+
+ /* if allowed disconnect, queue a service request */
+ if ( scsi_data.identify & 0x40 )
+ {
+ /* queue disconnect message in */
+ scsi_data.busphase = PHS_MESS_IN;
+
+ /* queue up a service request out in the future */
+ timer_set( ATTOTIME_IN_MSEC(50), 0, wd33c93_service_request );
+ }
+ }
+ else
+ {
+ /* device is not available */
+ newstatus = CSR_TIMEOUT;
+
+ wd33c93_set_xfer_count( 0 );
+ }
+
+ /* complete the command */
+ wd33c93_complete_cmd(newstatus);
+}
+
+static void wd33c93_negate_ack( void )
+{
+ logerror( "WD33C93: ACK Negated\n" );
+
+ /* complete the command */
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY);
+}
+
+static void wd33c93_xferinfo_cmd( void )
+{
+ /* make the buffer available right away */
+ scsi_data.regs[WD_AUXILIARY_STATUS] |= ASR_DBR;
+ scsi_data.regs[WD_AUXILIARY_STATUS] |= ASR_CIP;
+
+ /* the command will be completed once the data is transferred */
+ timer_set( ATTOTIME_IN_MSEC(1), 0, wd33c93_deassert_cip );
+}
+
+/* Command handlers */
+static cmd_handler wd33c93_cmds[0x22] =
+{
+ &wd33c93_reset_cmd, /* 0x00 - WD_CMD_RESET */
+ &wd33c93_abort_cmd, /* 0x01 - WD_CMD_ABORT */
+ &wd33c93_invalid_cmd, /* 0x02 - WD_CMD_ASSERT_ATN (uninmplemented) */
+ &wd33c93_negate_ack, /* 0x03 - WD_CMD_NEGATE_ACK */
+ &wd33c93_disconnect_cmd,/* 0x04 - WD_CMD_DISCONNECT */
+ &wd33c93_invalid_cmd, /* 0x05 - WD_CMD_RESELECT (uninmplemented) */
+ &wd33c93_select_cmd, /* 0x06 - WD_CMD_SEL_ATN */
+ &wd33c93_select_cmd, /* 0x07 - WD_CMD_SEL */
+ &wd33c93_selectxfer_cmd,/* 0x08 - WD_CMD_SEL_ATN_XFER */
+ &wd33c93_selectxfer_cmd,/* 0x09 - WD_CMD_SEL_XFER */
+ &wd33c93_invalid_cmd, /* 0x0a - WD_CMD_RESEL_RECEIVE (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x0b - WD_CMD_RESEL_SEND (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x0c - WD_CMD_WAIT_SEL_RECEIVE (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x0d - WD_CMD_SSCC (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x0e - WD_CMD_SND_DISC (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x0f - WD_CMD_SET_IDI (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x10 - WD_CMD_RCV_CMD (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x11 - WD_CMD_RCV_DATA (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x12 - WD_CMD_RCV_MSG_OUT (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x13 - WD_CMD_RCV (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x14 - WD_CMD_SND_STATUS (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x15 - WD_CMD_SND_DATA (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x16 - WD_CMD_SND_MSG_IN (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x17 - WD_CMD_SND (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x18 - WD_CMD_TRANS_ADDR (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x19 - WD_CMD_XFER_PAD (uninmplemented) */
+ &wd33c93_invalid_cmd, /* 0x1a - invalid */
+ &wd33c93_invalid_cmd, /* 0x1b - invalid */
+ &wd33c93_invalid_cmd, /* 0x1c - invalid */
+ &wd33c93_invalid_cmd, /* 0x1d - invalid */
+ &wd33c93_invalid_cmd, /* 0x1e - invalid */
+ &wd33c93_invalid_cmd, /* 0x1f - invalid */
+ &wd33c93_xferinfo_cmd, /* 0x20 - WD_CMD_TRANS_INFO) */
+ &wd33c93_invalid_cmd /* 0x21 - WD_CMD_TRANSFER_PAD (uninmplemented) */
+};
+
+/* Handle pending commands */
+static void wd33c93_command( void )
+{
+ /* get the command */
+ UINT8 cmd = scsi_data.regs[WD_COMMAND];
+
+ /* check if its within valid bounds */
+ if ( (cmd & 0x7F) > WD_CMD_TRANSFER_PAD )
+ {
+ wd33c93_invalid_cmd();
+ return;
+ }
+
+ /* call the command handler */
+ (*wd33c93_cmds[cmd & 0x7F])();
+}
+
+WRITE8_HANDLER(wd33c93_w)
+{
+ switch( offset )
+ {
+ case 0:
+ {
+ /* update register select */
+ scsi_data.sasr = data & 0x1f;
+ }
+ break;
+
+ case 1:
+ {
+#if VERBOSE
+ logerror( "WD33C93: PC=%08x - Write REG=%02x, data = %02x\n", safe_activecpu_get_pc(), scsi_data.sasr, data );
+#endif
+
+ /* update the register */
+ scsi_data.regs[scsi_data.sasr] = data;
+
+ /* if we receive a command, schedule to process it */
+ if ( scsi_data.sasr == WD_COMMAND )
+ {
+#if VERBOSE
+ logerror( "WDC33C93: PC=%08x - Executing command %08x - unit %d\n", safe_activecpu_get_pc(), data, wd33c93_getunit() );
+#endif
+
+ /* signal we're processing it */
+ scsi_data.regs[WD_AUXILIARY_STATUS] |= ASR_CIP;
+
+ /* process the command */
+ wd33c93_command();
+ }
+ else if ( scsi_data.sasr == WD_CDB_1 )
+ {
+ scsi_data.regs[WD_COMMAND_PHASE] = 0;
+ }
+ else if ( scsi_data.sasr == WD_DATA )
+ {
+ /* if data was written, and we have a count, send to device */
+ int count = wd33c93_get_xfer_count();
+
+ if ( scsi_data.regs[WD_COMMAND] & 0x80 )
+ count = 1;
+
+ if ( count-- > 0 )
+ {
+ /* write to FIFO */
+ if ( scsi_data.fifo_pos < FIFO_SIZE )
+ {
+ scsi_data.fifo[scsi_data.fifo_pos++] = data;
+ }
+
+ /* update count */
+ wd33c93_set_xfer_count( count );
+
+ /* if we're done with the write, see where we're at */
+ if ( count == 0 )
+ {
+ scsi_data.regs[WD_AUXILIARY_STATUS] |= ASR_INT;
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR;
+
+ switch( scsi_data.busphase )
+ {
+ case PHS_MESS_OUT:
+ {
+ /* reset fifo */
+ scsi_data.fifo_pos = 0;
+
+ /* Message out phase. Data is probably SCSI Identify. Move to command phase. */
+ scsi_data.busphase = PHS_COMMAND;
+
+ scsi_data.identify = scsi_data.fifo[0];
+ }
+ break;
+
+ case PHS_COMMAND:
+ {
+ UINT8 unit = wd33c93_getunit();
+ int xfercount;
+ int phase;
+
+ /* Execute the command. Depending on the command, we'll move to data in or out */
+ SCSISetCommand( devices[unit], &scsi_data.fifo[0], 12 );
+ SCSIExecCommand( devices[unit], &xfercount );
+ SCSIGetPhase( devices[unit], &phase );
+
+ /* reset fifo */
+ scsi_data.fifo_pos = 0;
+
+ /* set the new count */
+ wd33c93_set_xfer_count( xfercount );
+
+ switch( phase )
+ {
+ case SCSI_PHASE_STATUS:
+ scsi_data.busphase = PHS_STATUS;
+ break;
+
+ case SCSI_PHASE_DATAIN:
+ scsi_data.busphase = PHS_DATA_IN;
+ scsi_data.read_pending = 1;
+ break;
+
+ case SCSI_PHASE_DATAOUT:
+ scsi_data.busphase = PHS_DATA_OUT;
+ break;
+ }
+ }
+ break;
+
+ case PHS_DATA_OUT:
+ {
+ /* write data out to device */
+ wd33c93_write_data( scsi_data.fifo_pos, scsi_data.fifo );
+
+ /* reset fifo */
+ scsi_data.fifo_pos = 0;
+
+ /* move to status phase */
+ scsi_data.busphase = PHS_STATUS;
+ }
+ break;
+ }
+
+ /* complete the command */
+ wd33c93_complete_immediate(CSR_XFER_DONE | scsi_data.busphase);
+ }
+ }
+ else
+ {
+ logerror( "WD33C93: Sending data to device with transfer count = 0!. Ignoring...\n" );
+ }
+ }
+
+ /* auto-increment register select if not on special registers */
+ if ( scsi_data.sasr != WD_COMMAND && scsi_data.sasr != WD_DATA && scsi_data.sasr != WD_AUXILIARY_STATUS )
+ {
+ scsi_data.sasr = ( scsi_data.sasr + 1 ) & 0x1f;
+ }
+ }
+ break;
+
+ default:
+ {
+ logerror( "WD33C93: Write to invalid offset %d (data=%02x)\n", offset, data );
+ }
+ break;
+ }
+}
+
+READ8_HANDLER(wd33c93_r)
+{
+ switch( offset )
+ {
+ case 0:
+ {
+ /* read aux status */
+ return scsi_data.regs[WD_AUXILIARY_STATUS];
+ }
+ break;
+
+ case 1:
+ {
+ UINT8 ret;
+
+ /* if reading status, clear irq flag */
+ if ( scsi_data.sasr == WD_SCSI_STATUS )
+ {
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~ASR_INT;
+
+ if (intf && intf->irq_callback)
+ {
+ intf->irq_callback(0);
+ }
+
+#if VERBOSE
+ logerror( "WD33C93: PC=%08x - Status read (%02x)\n", safe_activecpu_get_pc(), scsi_data.regs[WD_SCSI_STATUS] );
+#endif
+ }
+ else if ( scsi_data.sasr == WD_DATA )
+ {
+ /* we're going to be doing synchronous reads */
+
+ /* get the transfer count */
+ int count = wd33c93_get_xfer_count();
+
+ /* initialize the return value */
+ scsi_data.regs[WD_DATA] = 0;
+
+ if ( count <= 0 && scsi_data.busphase == PHS_MESS_IN )
+ {
+ /* move to disconnect */
+ wd33c93_complete_cmd(CSR_DISC);
+ }
+ else if ( count == 1 && scsi_data.busphase == PHS_STATUS )
+ {
+ /* update the count */
+ wd33c93_set_xfer_count( 0 );
+
+ /* move to message in phase */
+ scsi_data.busphase = PHS_MESS_IN;
+
+ /* complete the command */
+ wd33c93_complete_cmd(CSR_XFER_DONE | scsi_data.busphase);
+ }
+ else if ( count-- > 0 ) /* make sure we still have data to send */
+ {
+ if ( scsi_data.read_pending )
+ {
+ int len = TEMP_INPUT_LEN;
+
+ if ( (count+1) < len ) len = count+1;
+ wd33c93_read_data( len, &scsi_data.temp_input[0] );
+ scsi_data.temp_input_pos = 0;
+ scsi_data.read_pending = 0;
+ }
+
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~ASR_INT;
+
+ /* read in one byte */
+ if ( scsi_data.temp_input_pos < TEMP_INPUT_LEN )
+ scsi_data.regs[WD_DATA] = scsi_data.temp_input[scsi_data.temp_input_pos++];
+
+ /* update the count */
+ wd33c93_set_xfer_count( count );
+
+ /* transfer finished, see where we're at */
+ if ( count == 0 )
+ {
+ if ( scsi_data.regs[WD_COMMAND_PHASE] != 0x60 )
+ {
+ /* move to status phase */
+ scsi_data.busphase = PHS_STATUS;
+
+ /* complete the command */
+ wd33c93_complete_cmd(CSR_XFER_DONE | scsi_data.busphase);
+ }
+ else
+ {
+ scsi_data.regs[WD_AUXILIARY_STATUS] |= ASR_INT;
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR;
+ }
+ }
+ }
+ }
+
+#if VERBOSE
+ logerror( "WD33C93: PC=%08x - Data read (%02x)\n", safe_activecpu_get_pc(), scsi_data.regs[WD_DATA] );
+#endif
+
+ /* get the register value */
+ ret = scsi_data.regs[scsi_data.sasr];
+
+ /* auto-increment register select if not on special registers */
+ if ( scsi_data.sasr != WD_COMMAND && scsi_data.sasr != WD_DATA && scsi_data.sasr != WD_AUXILIARY_STATUS )
+ {
+ scsi_data.sasr = ( scsi_data.sasr + 1 ) & 0x1f;
+ }
+
+ return ret;
+ }
+
+ default:
+ {
+ logerror( "WD33C93: Read from invalid offset %d\n", offset );
+ }
+ break;
+ }
+
+ return 0;
+}
+
+extern void wd33c93_init( struct WD33C93interface *interface )
+{
+ int i;
+
+ // save interface pointer for later
+ intf = interface;
+
+ memset(&scsi_data, 0, sizeof(scsi_data));
+ memset(devices, 0, sizeof(devices));
+
+ // try to open the devices
+ for (i = 0; i < interface->scsidevs->devs_present; i++)
+ {
+ SCSIAllocInstance( interface->scsidevs->devices[i].scsiClass, &devices[interface->scsidevs->devices[i].scsiID], interface->scsidevs->devices[i].diskID );
+ }
+
+ /* allocate a timer for commands */
+ scsi_data.cmd_timer = timer_alloc(wd33c93_complete_cb);
+
+ scsi_data.temp_input = auto_malloc( TEMP_INPUT_LEN );
+
+// state_save_register_item_array("wd33c93", 0, scsi_data);
+}
+
+void wd33c93_get_dma_data( int bytes, UINT8 *pData )
+{
+ int len = bytes;
+
+ if ( len >= wd33c93_get_xfer_count() )
+ len = wd33c93_get_xfer_count();
+
+ if ( len == 0 )
+ return;
+
+ if ( (scsi_data.temp_input_pos+len) >= TEMP_INPUT_LEN )
+ {
+ logerror( "Reading past end of buffer, increase TEMP_INPUT_LEN size\n" );
+ len = TEMP_INPUT_LEN - len;
+ }
+
+ memcpy( pData, &scsi_data.temp_input[scsi_data.temp_input_pos], len );
+
+ scsi_data.temp_input_pos += len;
+ len = wd33c93_get_xfer_count() - len;
+ wd33c93_set_xfer_count(len);
+}
+
+void wd33c93_write_data(int bytes, UINT8 *pData)
+{
+ UINT8 unit = wd33c93_getunit();
+
+ if (devices[unit])
+ {
+ SCSIWriteData( devices[unit], pData, bytes );
+ }
+ else
+ {
+ logerror("wd33c93: request for unknown device SCSI ID %d\n", unit);
+ }
+}
+
+void *wd33c93_get_device(int id)
+{
+ void *ret;
+
+ if (devices[id])
+ {
+ SCSIGetDevice( devices[id], &ret );
+ return ret;
+ }
+
+ return NULL;
+}
+
+void wd33c93_clear_dma(void)
+{
+ /* indicate DMA completed by clearing the transfer count */
+ wd33c93_set_xfer_count(0);
+ scsi_data.regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR;
+}
+
+int wd33c93_get_dma_count(void)
+{
+ return wd33c93_get_xfer_count();
+}
diff --git a/src/emu/machine/wd33c93.h b/src/emu/machine/wd33c93.h
new file mode 100644
index 00000000000..99f13944b9d
--- /dev/null
+++ b/src/emu/machine/wd33c93.h
@@ -0,0 +1,26 @@
+/*
+ * wd33c93.h
+ *
+ */
+
+#ifndef _WD33C93_H_
+#define _WD33C93_H_
+
+#include "machine/scsi.h"
+
+struct WD33C93interface
+{
+ SCSIConfigTable *scsidevs; /* SCSI devices */
+ void (*irq_callback)(int state); /* irq callback */
+};
+
+extern void wd33c93_init( struct WD33C93interface *interface );
+extern void wd33c93_get_dma_data(int bytes, UINT8 *pData);
+extern void wd33c93_write_data(int bytes, UINT8 *pData);
+extern void *wd33c93_get_device(int id);
+extern void wd33c93_clear_dma(void);
+extern int wd33c93_get_dma_count(void);
+extern READ8_HANDLER(wd33c93_r);
+extern WRITE8_HANDLER(wd33c93_w);
+
+#endif
diff --git a/src/emu/machine/x76f041.c b/src/emu/machine/x76f041.c
new file mode 100644
index 00000000000..e277e06f676
--- /dev/null
+++ b/src/emu/machine/x76f041.c
@@ -0,0 +1,623 @@
+/*
+ * x76f041.c
+ *
+ * Secure SerialFlash
+ *
+ * The X76F041 is a Password Access Security Supervisor, containing four 128 x 8 bit SecureFlash arrays.
+ * Access can be controlled by three 64-bit programmable passwords, one for read operations, one for write
+ * operations and one for device configuration.
+ *
+ * The data sheet has an incorrect diagrams for sequential read with password, there shouldn't be an extra address after the 0xc0 command.
+ *
+ */
+
+#include "driver.h"
+#include "machine/x76f041.h"
+
+#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 );
+ }
+ }
+}
+
+#define SIZE_WRITE_BUFFER ( 8 )
+
+struct x76f041_chip
+{
+ int cs;
+ int rst;
+ int scl;
+ int sdaw;
+ int sdar;
+ int state;
+ int shift;
+ int bit;
+ int byte;
+ int command;
+ int address;
+ UINT8 write_buffer[ SIZE_WRITE_BUFFER ];
+ UINT8 *response_to_reset;
+ UINT8 *write_password;
+ UINT8 *read_password;
+ UINT8 *configuration_password;
+ UINT8 *configuration_registers;
+ UINT8 *data;
+};
+
+#define SIZE_RESPONSE_TO_RESET ( 4 )
+#define SIZE_WRITE_PASSWORD ( SIZE_WRITE_BUFFER )
+#define SIZE_READ_PASSWORD ( SIZE_WRITE_BUFFER )
+#define SIZE_CONFIGURATION_PASSWORD ( SIZE_WRITE_BUFFER )
+#define SIZE_CONFIGURATION_REGISTERS ( SIZE_WRITE_BUFFER )
+#define SIZE_DATA ( 512 )
+
+#define CONFIG_BCR1 ( 0 )
+#define CONFIG_BCR2 ( 1 )
+#define CONFIG_CR ( 2 )
+#define CONFIG_RR ( 3 )
+#define CONFIG_RC ( 4 )
+
+#define BCR_X ( 8 )
+#define BCR_Y ( 4 )
+#define BCR_Z ( 2 )
+#define BCR_T ( 1 )
+
+struct x76f041_chip x76f041[ X76F041_MAXCHIP ];
+
+#define COMMAND_WRITE ( 0x00 )
+#define COMMAND_READ ( 0x20 )
+#define COMMAND_WRITE_USE_CONFIGURATION_PASSWORD ( 0x40 )
+#define COMMAND_READ_USE_CONFIGURATION_PASSWORD ( 0x60 )
+#define COMMAND_CONFIGURATION ( 0x80 )
+
+#define CONFIGURATION_PROGRAM_WRITE_PASSWORD ( 0x00 )
+#define CONFIGURATION_PROGRAM_READ_PASSWORD ( 0x10 )
+#define CONFIGURATION_PROGRAM_CONFIGURATION_PASSWORD ( 0x20 )
+#define CONFIGURATION_RESET_WRITE_PASSWORD ( 0x30 )
+#define CONFIGURATION_RESET_READ_PASSWORD ( 0x40 )
+#define CONFIGURATION_PROGRAM_CONFIGURATION_REGISTERS ( 0x50 )
+#define CONFIGURATION_READ_CONFIGURATION_REGISTERS ( 0x60 )
+#define CONFIGURATION_MASS_PROGRAM ( 0x70 )
+#define CONFIGURATION_MASS_ERASE ( 0x80 )
+
+#define STATE_STOP ( 0 )
+#define STATE_RESPONSE_TO_RESET ( 1 )
+#define STATE_LOAD_COMMAND ( 2 )
+#define STATE_LOAD_ADDRESS ( 3 )
+#define STATE_LOAD_PASSWORD ( 4 )
+#define STATE_VERIFY_PASSWORD ( 5 )
+#define STATE_READ_DATA ( 6 )
+#define STATE_WRITE_DATA ( 7 )
+#define STATE_READ_CONFIGURATION_REGISTERS ( 8 )
+#define STATE_WRITE_CONFIGURATION_REGISTERS ( 9 )
+
+void x76f041_init( int chip, UINT8 *data )
+{
+ int offset;
+ struct x76f041_chip *c;
+
+ if( chip >= X76F041_MAXCHIP )
+ {
+ verboselog( 0, "x76f041_init( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f041[ chip ];
+
+ if( data == NULL )
+ {
+ data = auto_malloc(
+ SIZE_RESPONSE_TO_RESET +
+ SIZE_READ_PASSWORD +
+ SIZE_WRITE_PASSWORD +
+ SIZE_CONFIGURATION_PASSWORD +
+ SIZE_CONFIGURATION_REGISTERS +
+ SIZE_DATA );
+ }
+
+ c->cs = 0;
+ c->rst = 0;
+ c->scl = 0;
+ c->sdaw = 0;
+ c->sdar = 0;
+ c->state = STATE_STOP;
+ c->shift = 0;
+ c->bit = 0;
+ c->byte = 0;
+ c->command = 0;
+ c->address = 0;
+ memset( c->write_buffer, 0, SIZE_WRITE_BUFFER );
+
+ offset = 0;
+ c->response_to_reset = &data[ offset ]; offset += SIZE_RESPONSE_TO_RESET;
+ c->write_password = &data[ offset ]; offset += SIZE_WRITE_PASSWORD;
+ c->read_password = &data[ offset ]; offset += SIZE_READ_PASSWORD;
+ c->configuration_password = &data[ offset ]; offset += SIZE_CONFIGURATION_PASSWORD;
+ c->configuration_registers = &data[ offset ]; offset += SIZE_CONFIGURATION_REGISTERS;
+ c->data = &data[ offset ]; offset += SIZE_DATA;
+
+ state_save_register_item( "x76f041", chip, c->cs );
+ state_save_register_item( "x76f041", chip, c->rst );
+ state_save_register_item( "x76f041", chip, c->scl );
+ state_save_register_item( "x76f041", chip, c->sdaw );
+ state_save_register_item( "x76f041", chip, c->sdar );
+ state_save_register_item( "x76f041", chip, c->state );
+ state_save_register_item( "x76f041", chip, c->shift );
+ state_save_register_item( "x76f041", chip, c->bit );
+ state_save_register_item( "x76f041", chip, c->byte );
+ state_save_register_item( "x76f041", chip, c->command );
+ state_save_register_item( "x76f041", chip, c->address );
+ state_save_register_item_array( "x76f041", chip, c->write_buffer );
+ state_save_register_item_pointer( "x76f041", chip, c->response_to_reset, SIZE_RESPONSE_TO_RESET );
+ state_save_register_item_pointer( "x76f041", chip, c->write_password, SIZE_WRITE_PASSWORD );
+ state_save_register_item_pointer( "x76f041", chip, c->read_password, SIZE_READ_PASSWORD );
+ state_save_register_item_pointer( "x76f041", chip, c->configuration_password, SIZE_CONFIGURATION_PASSWORD );
+ state_save_register_item_pointer( "x76f041", chip, c->configuration_registers, SIZE_CONFIGURATION_REGISTERS );
+ state_save_register_item_pointer( "x76f041", chip, c->data, SIZE_DATA );
+}
+
+void x76f041_cs_write( int chip, int cs )
+{
+ struct x76f041_chip *c;
+
+ if( chip >= X76F041_MAXCHIP )
+ {
+ verboselog( 0, "x76f041_cs_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f041[ chip ];
+
+ if( c->cs != cs )
+ {
+ verboselog( 2, "x76f041(%d) cs=%d\n", chip, cs );
+ }
+ if( c->cs != 0 && cs == 0 )
+ {
+ /* enable chip */
+ c->state = STATE_STOP;
+ }
+ if( c->cs == 0 && cs != 0 )
+ {
+ /* disable chip */
+ c->state = STATE_STOP;
+ /* high impendence? */
+ c->sdar = 0;
+ }
+ c->cs = cs;
+}
+
+void x76f041_rst_write( int chip, int rst )
+{
+ struct x76f041_chip *c;
+
+ if( chip >= X76F041_MAXCHIP )
+ {
+ verboselog( 0, "x76f041_rst_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f041[ chip ];
+
+ if( c->rst != rst )
+ {
+ verboselog( 2, "x76f041(%d) rst=%d\n", chip, rst );
+ }
+ if( c->rst == 0 && rst != 0 && c->cs == 0 )
+ {
+ verboselog( 1, "x76f041(%d) goto response to reset\n", chip );
+ c->state = STATE_RESPONSE_TO_RESET;
+ c->bit = 0;
+ c->byte = 0;
+ }
+ c->rst = rst;
+}
+
+static UINT8 *x76f041_password( struct x76f041_chip *c )
+{
+ switch( c->command & 0xe0 )
+ {
+ case COMMAND_WRITE:
+ return c->write_password;
+ case COMMAND_READ:
+ return c->read_password;
+ default:
+ return c->configuration_password;
+ }
+}
+
+static void x76f041_password_ok( struct x76f041_chip *c )
+{
+ switch( c->command & 0xe0 )
+ {
+ case COMMAND_WRITE:
+ c->state = STATE_WRITE_DATA;
+ break;
+ case COMMAND_READ:
+ c->state = STATE_READ_DATA;
+ break;
+ case COMMAND_WRITE_USE_CONFIGURATION_PASSWORD:
+ c->state = STATE_WRITE_DATA;
+ break;
+ case COMMAND_READ_USE_CONFIGURATION_PASSWORD:
+ c->state = STATE_READ_DATA;
+ break;
+ case COMMAND_CONFIGURATION:
+ switch( c->address )
+ {
+ case CONFIGURATION_PROGRAM_WRITE_PASSWORD:
+ break;
+ case CONFIGURATION_PROGRAM_READ_PASSWORD:
+ break;
+ case CONFIGURATION_PROGRAM_CONFIGURATION_PASSWORD:
+ break;
+ case CONFIGURATION_RESET_WRITE_PASSWORD:
+ break;
+ case CONFIGURATION_RESET_READ_PASSWORD:
+ break;
+ case CONFIGURATION_PROGRAM_CONFIGURATION_REGISTERS:
+ c->state = STATE_WRITE_CONFIGURATION_REGISTERS;
+ c->byte = 0;
+ break;
+ case CONFIGURATION_READ_CONFIGURATION_REGISTERS:
+ c->state = STATE_READ_CONFIGURATION_REGISTERS;
+ c->byte = 0;
+ break;
+ case CONFIGURATION_MASS_PROGRAM:
+ break;
+ case CONFIGURATION_MASS_ERASE:
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void x76f041_load_address( int chip )
+{
+ /* todo: handle other bcr bits */
+ struct x76f041_chip *c = &x76f041[ chip ];
+ int bcr;
+
+ c->address = c->shift;
+
+ verboselog( 1, "x76f041(%d) -> address: %02x\n", chip, c->address );
+
+ if( ( c->command & 1 ) == 0 )
+ {
+ bcr = c->configuration_registers[ CONFIG_BCR1 ];
+ }
+ else
+ {
+ bcr = c->configuration_registers[ CONFIG_BCR2 ];
+ }
+ if( ( c->address & 0x80 ) != 0 )
+ {
+ bcr >>= 4;
+ }
+
+ if( ( ( c->command & 0xe0 ) == COMMAND_READ && ( bcr & BCR_Z ) != 0 && ( bcr & BCR_T ) != 0 ) ||
+ ( ( c->command & 0xe0 ) == COMMAND_WRITE && ( bcr & BCR_Z ) != 0 ) )
+ {
+ /* todo: find out when this is really checked. */
+ verboselog( 1, "x76f041(%d) command not allowed\n", chip );
+ c->state = STATE_STOP;
+ c->sdar = 0;
+ }
+ else if( ( ( c->command & 0xe0 ) == COMMAND_WRITE && ( bcr & BCR_X ) == 0 ) ||
+ ( ( c->command & 0xe0 ) == COMMAND_READ && ( bcr & BCR_Y ) == 0 ) )
+ {
+ verboselog( 1, "x76f041(%d) password not required\n", chip );
+ x76f041_password_ok( c );
+ }
+ else
+ {
+ verboselog( 1, "x76f041(%d) send password\n", chip );
+ c->state = STATE_LOAD_PASSWORD;
+ c->byte = 0;
+ }
+}
+
+static int x76f041_data_offset( struct x76f041_chip *c )
+{
+ int block_offset = ( ( c->command & 1 ) << 8 ) + c->address;
+
+ // TODO: confirm block_start doesn't wrap.
+
+ return ( block_offset & 0x180 ) | ( ( block_offset + c->byte ) & 0x7f );
+}
+
+void x76f041_scl_write( int chip, int scl )
+{
+ struct x76f041_chip *c;
+
+ if( chip >= X76F041_MAXCHIP )
+ {
+ verboselog( 0, "x76f041_scl_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f041[ chip ];
+
+ if( c->scl != scl )
+ {
+ verboselog( 2, "x76f041(%d) scl=%d\n", chip, scl );
+ }
+ if( c->cs == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_STOP:
+ break;
+ case STATE_RESPONSE_TO_RESET:
+ if( c->scl != 0 && scl == 0 )
+ {
+ c->sdar = ( c->response_to_reset[ c->byte ] >> c->bit ) & 1;
+ verboselog( 2, "x76f041(%d) in response to reset %d (%d/%d)\n", chip, c->sdar, c->byte, c->bit );
+ c->bit++;
+ if( c->bit == 8 )
+ {
+ c->bit = 0;
+ c->byte++;
+ if( c->byte == 4 )
+ {
+ c->byte = 0;
+ }
+ }
+ }
+ break;
+ case STATE_LOAD_COMMAND:
+ case STATE_LOAD_ADDRESS:
+ case STATE_LOAD_PASSWORD:
+ case STATE_VERIFY_PASSWORD:
+ case STATE_WRITE_DATA:
+ case STATE_WRITE_CONFIGURATION_REGISTERS:
+ if( c->scl == 0 && scl != 0 )
+ {
+ if( c->bit < 8 )
+ {
+ verboselog( 2, "x76f041(%d) clock\n", chip );
+ c->shift <<= 1;
+ if( c->sdaw != 0 )
+ {
+ c->shift |= 1;
+ }
+ c->bit++;
+ }
+ else
+ {
+ c->sdar = 0;
+
+ switch( c->state )
+ {
+ case STATE_LOAD_COMMAND:
+ c->command = c->shift;
+ verboselog( 1, "x76f041(%d) -> command: %02x\n", chip, c->command );
+ /* todo: verify command is valid? */
+ c->state = STATE_LOAD_ADDRESS;
+ break;
+ case STATE_LOAD_ADDRESS:
+ x76f041_load_address( chip );
+ break;
+ case STATE_LOAD_PASSWORD:
+ verboselog( 1, "x76f041(%d) -> password: %02x\n", chip, c->shift );
+ c->write_buffer[ c->byte++ ] = c->shift;
+ if( c->byte == SIZE_WRITE_BUFFER )
+ {
+ c->state = STATE_VERIFY_PASSWORD;
+ }
+ break;
+ case STATE_VERIFY_PASSWORD:
+ verboselog( 1, "x76f041(%d) -> verify password: %02x\n", chip, c->shift );
+ /* todo: this should probably be handled as a command */
+ if( c->shift == 0xc0 )
+ {
+ /* todo: this should take 10ms before it returns ok. */
+ if( memcmp( x76f041_password( c ), c->write_buffer, SIZE_WRITE_BUFFER ) == 0 )
+ {
+ x76f041_password_ok( c );
+ }
+ else
+ {
+ c->sdar = 1;
+ }
+ }
+ break;
+ case STATE_WRITE_DATA:
+ verboselog( 1, "x76f041(%d) -> data: %02x\n", chip, c->shift );
+ c->write_buffer[ c->byte++ ] = c->shift;
+ if( c->byte == SIZE_WRITE_BUFFER )
+ {
+ for( c->byte = 0; c->byte < SIZE_WRITE_BUFFER; c->byte++ )
+ {
+ c->data[ x76f041_data_offset( c ) ] = c->write_buffer[ c->byte ];
+ }
+ c->byte = 0;
+
+ verboselog( 1, "x76f041(%d) data flushed\n", chip );
+ }
+ break;
+ case STATE_WRITE_CONFIGURATION_REGISTERS:
+ verboselog( 1, "x76f041(%d) -> configuration register: %02x\n", chip, c->shift );
+ /* todo: write after all bytes received? */
+ c->configuration_registers[ c->byte++ ] = c->shift;
+ if( c->byte == SIZE_CONFIGURATION_REGISTERS )
+ {
+ c->byte = 0;
+ }
+ break;
+ }
+
+ c->bit = 0;
+ c->shift = 0;
+ }
+ }
+ break;
+ case STATE_READ_DATA:
+ case STATE_READ_CONFIGURATION_REGISTERS:
+ if( c->scl == 0 && scl != 0 )
+ {
+ if( c->bit < 8 )
+ {
+ if( c->bit == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_READ_DATA:
+ c->shift = c->data[ x76f041_data_offset( c ) ];
+ verboselog( 1, "x76f041(%d) <- data: %02x\n", chip, c->shift );
+ break;
+ case STATE_READ_CONFIGURATION_REGISTERS:
+ c->shift = c->configuration_registers[ c->byte & 7 ];
+ verboselog( 1, "x76f041(%d) <- configuration register: %02x\n", chip, c->shift );
+ break;
+ }
+ }
+ c->sdar = ( c->shift >> 7 ) & 1;
+ c->shift <<= 1;
+ c->bit++;
+ }
+ else
+ {
+ c->bit = 0;
+ c->sdar = 0;
+ if( c->sdaw == 0 )
+ {
+ verboselog( 2, "x76f041(%d) ack <-\n", chip );
+ c->byte++;
+ }
+ else
+ {
+ verboselog( 2, "x76f041(%d) nak <-\n", chip );
+ }
+ }
+ }
+ break;
+ }
+ }
+ c->scl = scl;
+}
+
+void x76f041_sda_write( int chip, int sda )
+{
+ struct x76f041_chip *c;
+
+ if( chip >= X76F041_MAXCHIP )
+ {
+ verboselog( 0, "x76f041_sda_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f041[ chip ];
+
+ if( c->sdaw != sda )
+ {
+ verboselog( 2, "x76f041(%d) sdaw=%d\n", chip, sda );
+ }
+ if( c->cs == 0 && c->scl != 0 )
+ {
+ if( c->sdaw == 0 && sda != 0 )
+ {
+ verboselog( 1, "x76f041(%d) goto stop\n", chip );
+ c->state = STATE_STOP;
+ c->sdar = 0;
+ }
+ if( c->sdaw != 0 && sda == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_STOP:
+ verboselog( 1, "x76f041(%d) goto start\n", chip );
+ c->state = STATE_LOAD_COMMAND;
+ break;
+ case STATE_LOAD_PASSWORD:
+ /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */
+ verboselog( 1, "x76f041(%d) goto start\n", chip );
+ break;
+ case STATE_READ_DATA:
+ verboselog( 1, "x76f041(%d) goto load address\n", chip );
+ c->state = STATE_LOAD_ADDRESS;
+ break;
+ default:
+ verboselog( 1, "x76f041(%d) skipped start (default)\n", chip );
+ break;
+ }
+
+ c->bit = 0;
+ c->byte = 0;
+ c->shift = 0;
+ c->sdar = 0;
+ }
+ }
+ c->sdaw = sda;
+}
+
+int x76f041_sda_read( int chip )
+{
+ struct x76f041_chip *c;
+
+ if( chip >= X76F041_MAXCHIP )
+ {
+ verboselog( 0, "x76f041_sda_read( %d ) chip out of range\n", chip );
+ return 1;
+ }
+
+ c = &x76f041[ chip ];
+
+ if( c->cs != 0 )
+ {
+ verboselog( 2, "x76f041(%d) not selected\n", chip );
+ return 1;
+ }
+ verboselog( 2, "x76f041(%d) sdar=%d\n", chip, c->sdar );
+ return c->sdar;
+}
+
+static void nvram_handler_x76f041( int chip, running_machine *machine, mame_file *file, int read_or_write )
+{
+ struct x76f041_chip *c;
+
+ if( chip >= X76F041_MAXCHIP )
+ {
+ verboselog( 0, "nvram_handler_x76f041( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f041[ chip ];
+
+ if( read_or_write )
+ {
+ mame_fwrite( file, c->write_password, SIZE_WRITE_PASSWORD );
+ mame_fwrite( file, c->read_password, SIZE_READ_PASSWORD );
+ mame_fwrite( file, c->configuration_password, SIZE_CONFIGURATION_PASSWORD );
+ mame_fwrite( file, c->configuration_registers, SIZE_CONFIGURATION_REGISTERS );
+ mame_fwrite( file, c->data, SIZE_DATA );
+ }
+ else if( file )
+ {
+ mame_fread( file, c->write_password, SIZE_WRITE_PASSWORD );
+ mame_fread( file, c->read_password, SIZE_READ_PASSWORD );
+ mame_fread( file, c->configuration_password, SIZE_CONFIGURATION_PASSWORD );
+ mame_fread( file, c->configuration_registers, SIZE_CONFIGURATION_REGISTERS );
+ mame_fread( file, c->data, SIZE_DATA );
+ }
+}
+
+NVRAM_HANDLER( x76f041_0 ) { nvram_handler_x76f041( 0, machine, file, read_or_write ); }
+NVRAM_HANDLER( x76f041_1 ) { nvram_handler_x76f041( 1, machine, file, read_or_write ); }
diff --git a/src/emu/machine/x76f041.h b/src/emu/machine/x76f041.h
new file mode 100644
index 00000000000..f41ea45efdb
--- /dev/null
+++ b/src/emu/machine/x76f041.h
@@ -0,0 +1,22 @@
+/*
+ * x76f041.h
+ *
+ * Secure SerialFlash
+ *
+ */
+
+#if !defined( X76F041_H )
+
+#define X76F041_MAXCHIP ( 2 )
+
+extern void x76f041_init( int chip, UINT8 *data );
+extern void x76f041_cs_write( int chip, int cs );
+extern void x76f041_rst_write( int chip, int rst );
+extern void x76f041_scl_write( int chip, int scl );
+extern void x76f041_sda_write( int chip, int sda );
+extern int x76f041_sda_read( int chip );
+extern NVRAM_HANDLER( x76f041_0 );
+extern NVRAM_HANDLER( x76f041_1 );
+
+#define X76F041_H
+#endif
diff --git a/src/emu/machine/x76f100.c b/src/emu/machine/x76f100.c
new file mode 100644
index 00000000000..d9cca5d33a5
--- /dev/null
+++ b/src/emu/machine/x76f100.c
@@ -0,0 +1,497 @@
+/*
+ * x76f100.c
+ *
+ * Secure SerialFlash
+ *
+ * The X76F100 is a Password Access Security Supervisor, containing one 896-bit Secure SerialFlash array.
+ * Access to the memory array can be controlled by two 64-bit passwords. These passwords protect read and
+ * write operations of the memory array.
+ *
+ */
+
+#include "driver.h"
+#include "machine/x76f100.h"
+
+#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 );
+ }
+ }
+}
+
+#define SIZE_WRITE_BUFFER ( 8 )
+
+struct x76f100_chip
+{
+ int cs;
+ int rst;
+ int scl;
+ int sdaw;
+ int sdar;
+ int state;
+ int shift;
+ int bit;
+ int byte;
+ int command;
+ UINT8 write_buffer[ SIZE_WRITE_BUFFER ];
+ UINT8 *response_to_reset;
+ UINT8 *write_password;
+ UINT8 *read_password;
+ UINT8 *data;
+};
+
+#define SIZE_RESPONSE_TO_RESET ( 4 )
+#define SIZE_WRITE_PASSWORD ( SIZE_WRITE_BUFFER )
+#define SIZE_READ_PASSWORD ( SIZE_WRITE_BUFFER )
+#define SIZE_DATA ( 112 )
+
+struct x76f100_chip x76f100[ X76F100_MAXCHIP ];
+
+#define COMMAND_WRITE ( 0x80 )
+#define COMMAND_READ ( 0x81 )
+#define COMMAND_CHANGE_WRITE_PASSWORD ( 0xfc )
+#define COMMAND_CHANGE_READ_PASSWORD ( 0xfe )
+#define COMMAND_ACK_PASSWORD ( 0x55 )
+
+#define STATE_STOP ( 0 )
+#define STATE_RESPONSE_TO_RESET ( 1 )
+#define STATE_LOAD_COMMAND ( 2 )
+#define STATE_LOAD_PASSWORD ( 4 )
+#define STATE_VERIFY_PASSWORD ( 5 )
+#define STATE_READ_DATA ( 6 )
+#define STATE_WRITE_DATA ( 7 )
+
+void x76f100_init( int chip, UINT8 *data )
+{
+ int offset;
+ struct x76f100_chip *c;
+
+ if( chip >= X76F100_MAXCHIP )
+ {
+ verboselog( 0, "x76f100_init( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f100[ chip ];
+
+ if( data == NULL )
+ {
+ data = auto_malloc(
+ SIZE_RESPONSE_TO_RESET +
+ SIZE_READ_PASSWORD +
+ SIZE_WRITE_PASSWORD +
+ SIZE_DATA );
+ }
+
+ c->cs = 0;
+ c->rst = 0;
+ c->scl = 0;
+ c->sdaw = 0;
+ c->sdar = 0;
+ c->state = STATE_STOP;
+ c->shift = 0;
+ c->bit = 0;
+ c->byte = 0;
+ c->command = 0;
+ memset( c->write_buffer, 0, SIZE_WRITE_BUFFER );
+
+ offset = 0;
+ c->response_to_reset = &data[ offset ]; offset += SIZE_RESPONSE_TO_RESET;
+ c->write_password = &data[ offset ]; offset += SIZE_WRITE_PASSWORD;
+ c->read_password = &data[ offset ]; offset += SIZE_READ_PASSWORD;
+ c->data = &data[ offset ]; offset += SIZE_DATA;
+
+ state_save_register_item( "x76f100", chip, c->cs );
+ state_save_register_item( "x76f100", chip, c->rst );
+ state_save_register_item( "x76f100", chip, c->scl );
+ state_save_register_item( "x76f100", chip, c->sdaw );
+ state_save_register_item( "x76f100", chip, c->sdar );
+ state_save_register_item( "x76f100", chip, c->state );
+ state_save_register_item( "x76f100", chip, c->shift );
+ state_save_register_item( "x76f100", chip, c->bit );
+ state_save_register_item( "x76f100", chip, c->byte );
+ state_save_register_item( "x76f100", chip, c->command );
+ state_save_register_item_array( "x76f100", chip, c->write_buffer );
+ state_save_register_item_pointer( "x76f100", chip, c->response_to_reset, SIZE_RESPONSE_TO_RESET );
+ state_save_register_item_pointer( "x76f100", chip, c->write_password, SIZE_WRITE_PASSWORD );
+ state_save_register_item_pointer( "x76f100", chip, c->read_password, SIZE_READ_PASSWORD );
+ state_save_register_item_pointer( "x76f100", chip, c->data, SIZE_DATA );
+}
+
+void x76f100_cs_write( int chip, int cs )
+{
+ struct x76f100_chip *c;
+
+ if( chip >= X76F100_MAXCHIP )
+ {
+ verboselog( 0, "x76f100_cs_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f100[ chip ];
+
+ if( c->cs != cs )
+ {
+ verboselog( 2, "x76f100(%d) cs=%d\n", chip, cs );
+ }
+ if( c->cs != 0 && cs == 0 )
+ {
+ /* enable chip */
+ c->state = STATE_STOP;
+ }
+ if( c->cs == 0 && cs != 0 )
+ {
+ /* disable chip */
+ c->state = STATE_STOP;
+ /* high impendence? */
+ c->sdar = 0;
+ }
+ c->cs = cs;
+}
+
+void x76f100_rst_write( int chip, int rst )
+{
+ struct x76f100_chip *c;
+
+ if( chip >= X76F100_MAXCHIP )
+ {
+ verboselog( 0, "x76f100_rst_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f100[ chip ];
+
+ if( c->rst != rst )
+ {
+ verboselog( 2, "x76f100(%d) rst=%d\n", chip, rst );
+ }
+ if( c->rst == 0 && rst != 0 && c->cs == 0 )
+ {
+ verboselog( 1, "x76f100(%d) goto response to reset\n", chip );
+ c->state = STATE_RESPONSE_TO_RESET;
+ c->bit = 0;
+ c->byte = 0;
+ }
+ c->rst = rst;
+}
+
+static UINT8 *x76f100_password( struct x76f100_chip *c )
+{
+ if( ( c->command & 0xe1 ) == COMMAND_READ )
+ {
+ return c->read_password;
+ }
+
+ return c->write_password;
+}
+
+static void x76f100_password_ok( struct x76f100_chip *c )
+{
+ if( ( c->command & 0xe1 ) == COMMAND_READ )
+ {
+ c->state = STATE_READ_DATA;
+ }
+ else if( ( c->command & 0xe1 ) == COMMAND_WRITE )
+ {
+ c->state = STATE_WRITE_DATA;
+ }
+ else
+ {
+ /* TODO: */
+ }
+}
+
+static int x76f100_data_offset( struct x76f100_chip *c )
+{
+ int block_offset = ( c->command >> 1 ) & 0x0f;
+
+ return ( block_offset * SIZE_WRITE_BUFFER ) + c->byte;
+}
+
+void x76f100_scl_write( int chip, int scl )
+{
+ struct x76f100_chip *c;
+
+ if( chip >= X76F100_MAXCHIP )
+ {
+ verboselog( 0, "x76f100_scl_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f100[ chip ];
+
+ if( c->scl != scl )
+ {
+ verboselog( 2, "x76f100(%d) scl=%d\n", chip, scl );
+ }
+ if( c->cs == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_STOP:
+ break;
+
+ case STATE_RESPONSE_TO_RESET:
+ if( c->scl != 0 && scl == 0 )
+ {
+ if( c->bit == 0 )
+ {
+ c->shift = c->response_to_reset[ c->byte ];
+ verboselog( 1, "x76f100(%d) <- response_to_reset[%d]: %02x\n", chip, c->byte, c->shift );
+ }
+
+ c->sdar = c->shift & 1;
+ c->shift >>= 1;
+ c->bit++;
+
+ if( c->bit == 8 )
+ {
+ c->bit = 0;
+ c->byte++;
+ if( c->byte == 4 )
+ {
+ c->byte = 0;
+ }
+ }
+ }
+ break;
+
+ case STATE_LOAD_COMMAND:
+ case STATE_LOAD_PASSWORD:
+ case STATE_VERIFY_PASSWORD:
+ case STATE_WRITE_DATA:
+ if( c->scl == 0 && scl != 0 )
+ {
+ if( c->bit < 8 )
+ {
+ verboselog( 2, "x76f100(%d) clock\n", chip );
+ c->shift <<= 1;
+ if( c->sdaw != 0 )
+ {
+ c->shift |= 1;
+ }
+ c->bit++;
+ }
+ else
+ {
+ c->sdar = 0;
+
+ switch( c->state )
+ {
+ case STATE_LOAD_COMMAND:
+ c->command = c->shift;
+ verboselog( 1, "x76f100(%d) -> command: %02x\n", chip, c->command );
+ /* todo: verify command is valid? */
+ c->state = STATE_LOAD_PASSWORD;
+ break;
+
+ case STATE_LOAD_PASSWORD:
+ verboselog( 1, "x76f100(%d) -> password: %02x\n", chip, c->shift );
+ c->write_buffer[ c->byte++ ] = c->shift;
+ if( c->byte == SIZE_WRITE_BUFFER )
+ {
+ c->state = STATE_VERIFY_PASSWORD;
+ }
+ break;
+
+ case STATE_VERIFY_PASSWORD:
+ verboselog( 1, "x76f100(%d) -> verify password: %02x\n", chip, c->shift );
+ /* todo: this should probably be handled as a command */
+ if( c->shift == COMMAND_ACK_PASSWORD )
+ {
+ /* todo: this should take 10ms before it returns ok. */
+ if( memcmp( x76f100_password( c ), c->write_buffer, SIZE_WRITE_BUFFER ) == 0 )
+ {
+ x76f100_password_ok( c );
+ }
+ else
+ {
+ c->sdar = 1;
+ }
+ }
+ break;
+
+ case STATE_WRITE_DATA:
+ verboselog( 1, "x76f100(%d) -> data: %02x\n", chip, c->shift );
+ c->write_buffer[ c->byte++ ] = c->shift;
+ if( c->byte == SIZE_WRITE_BUFFER )
+ {
+ for( c->byte = 0; c->byte < SIZE_WRITE_BUFFER; c->byte++ )
+ {
+ c->data[ x76f100_data_offset( c ) ] = c->write_buffer[ c->byte ];
+ }
+ c->byte = 0;
+
+ verboselog( 1, "x76f100(%d) data flushed\n", chip );
+ }
+ break;
+ }
+
+ c->bit = 0;
+ c->shift = 0;
+ }
+ }
+ break;
+
+ case STATE_READ_DATA:
+ if( c->scl == 0 && scl != 0 )
+ {
+ if( c->bit < 8 )
+ {
+ if( c->bit == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_READ_DATA:
+ c->shift = c->data[ x76f100_data_offset( c ) ];
+ verboselog( 1, "x76f100(%d) <- data: %02x\n", chip, c->shift );
+ break;
+ }
+ }
+ c->sdar = ( c->shift >> 7 ) & 1;
+ c->shift <<= 1;
+ c->bit++;
+ }
+ else
+ {
+ c->bit = 0;
+ c->sdar = 0;
+ if( c->sdaw == 0 )
+ {
+ verboselog( 2, "x76f100(%d) ack <-\n", chip );
+ c->byte++;
+ }
+ else
+ {
+ verboselog( 2, "x76f100(%d) nak <-\n", chip );
+ }
+ }
+ }
+ break;
+ }
+ }
+ c->scl = scl;
+}
+
+void x76f100_sda_write( int chip, int sda )
+{
+ struct x76f100_chip *c;
+
+ if( chip >= X76F100_MAXCHIP )
+ {
+ verboselog( 0, "x76f100_sda_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f100[ chip ];
+
+ if( c->sdaw != sda )
+ {
+ verboselog( 2, "x76f100(%d) sdaw=%d\n", chip, sda );
+ }
+ if( c->cs == 0 && c->scl != 0 )
+ {
+ if( c->sdaw == 0 && sda != 0 )
+ {
+ verboselog( 1, "x76f100(%d) goto stop\n", chip );
+ c->state = STATE_STOP;
+ c->sdar = 0;
+ }
+ if( c->sdaw != 0 && sda == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_STOP:
+ verboselog( 1, "x76f100(%d) goto start\n", chip );
+ c->state = STATE_LOAD_COMMAND;
+ break;
+
+ case STATE_LOAD_PASSWORD:
+ /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */
+ verboselog( 1, "x76f100(%d) goto start\n", chip );
+ break;
+
+ case STATE_READ_DATA:
+ verboselog( 1, "x76f100(%d) continue reading??\n", chip );
+// verboselog( 1, "x76f100(%d) goto load address\n", chip );
+// c->state = STATE_LOAD_ADDRESS;
+ break;
+
+ default:
+ verboselog( 1, "x76f100(%d) skipped start (default)\n", chip );
+ break;
+ }
+
+ c->bit = 0;
+ c->byte = 0;
+ c->shift = 0;
+ c->sdar = 0;
+ }
+ }
+ c->sdaw = sda;
+}
+
+int x76f100_sda_read( int chip )
+{
+ struct x76f100_chip *c;
+
+ if( chip >= X76F100_MAXCHIP )
+ {
+ verboselog( 0, "x76f100_sda_read( %d ) chip out of range\n", chip );
+ return 1;
+ }
+
+ c = &x76f100[ chip ];
+
+ if( c->cs != 0 )
+ {
+ verboselog( 2, "x76f100(%d) not selected\n", chip );
+ return 1;
+ }
+ verboselog( 2, "x76f100(%d) sdar=%d\n", chip, c->sdar );
+ return c->sdar;
+}
+
+static void nvram_handler_x76f100( int chip, running_machine *machine, mame_file *file, int read_or_write )
+{
+ struct x76f100_chip *c;
+
+ if( chip >= X76F100_MAXCHIP )
+ {
+ verboselog( 0, "nvram_handler_x76f100( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &x76f100[ chip ];
+
+ if( read_or_write )
+ {
+ mame_fwrite( file, c->write_password, SIZE_WRITE_PASSWORD );
+ mame_fwrite( file, c->read_password, SIZE_READ_PASSWORD );
+ mame_fwrite( file, c->data, SIZE_DATA );
+ }
+ else if( file )
+ {
+ mame_fread( file, c->write_password, SIZE_WRITE_PASSWORD );
+ mame_fread( file, c->read_password, SIZE_READ_PASSWORD );
+ mame_fread( file, c->data, SIZE_DATA );
+ }
+}
+
+NVRAM_HANDLER( x76f100_0 ) { nvram_handler_x76f100( 0, machine, file, read_or_write ); }
+NVRAM_HANDLER( x76f100_1 ) { nvram_handler_x76f100( 1, machine, file, read_or_write ); }
diff --git a/src/emu/machine/x76f100.h b/src/emu/machine/x76f100.h
new file mode 100644
index 00000000000..1232556ac99
--- /dev/null
+++ b/src/emu/machine/x76f100.h
@@ -0,0 +1,22 @@
+/*
+ * x76f100.h
+ *
+ * Secure SerialFlash
+ *
+ */
+
+#if !defined( X76F100_H )
+
+#define X76F100_MAXCHIP ( 2 )
+
+extern void x76f100_init( int chip, UINT8 *data );
+extern void x76f100_cs_write( int chip, int cs );
+extern void x76f100_rst_write( int chip, int rst );
+extern void x76f100_scl_write( int chip, int scl );
+extern void x76f100_sda_write( int chip, int sda );
+extern int x76f100_sda_read( int chip );
+extern NVRAM_HANDLER( x76f100_0 );
+extern NVRAM_HANDLER( x76f100_1 );
+
+#define X76F100_H
+#endif
diff --git a/src/emu/machine/z80ctc.c b/src/emu/machine/z80ctc.c
new file mode 100644
index 00000000000..8ff9351e821
--- /dev/null
+++ b/src/emu/machine/z80ctc.c
@@ -0,0 +1,483 @@
+/***************************************************************************
+
+ Z80 CTC (Z8430) implementation
+
+ based on original version (c) 1997, Tatsuyuki Satoh
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "z80ctc.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define VPRINTF(x) logerror x
+#else
+#define VPRINTF(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* these are the bits of the incoming commands to the CTC */
+#define INTERRUPT 0x80
+#define INTERRUPT_ON 0x80
+#define INTERRUPT_OFF 0x00
+
+#define MODE 0x40
+#define MODE_TIMER 0x00
+#define MODE_COUNTER 0x40
+
+#define PRESCALER 0x20
+#define PRESCALER_256 0x20
+#define PRESCALER_16 0x00
+
+#define EDGE 0x10
+#define EDGE_FALLING 0x00
+#define EDGE_RISING 0x10
+
+#define TRIGGER 0x08
+#define TRIGGER_AUTO 0x00
+#define TRIGGER_CLOCK 0x08
+
+#define CONSTANT 0x04
+#define CONSTANT_LOAD 0x04
+#define CONSTANT_NONE 0x00
+
+#define RESET 0x02
+#define RESET_CONTINUE 0x00
+#define RESET_ACTIVE 0x02
+
+#define CONTROL 0x01
+#define CONTROL_VECTOR 0x00
+#define CONTROL_WORD 0x01
+
+/* these extra bits help us keep things accurate */
+#define WAITING_FOR_TRIG 0x100
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _z80ctc z80ctc;
+struct _z80ctc
+{
+ UINT8 vector; /* interrupt vector */
+ UINT32 clock; /* system clock */
+ attotime period16; /* 16/system clock */
+ attotime period256; /* 256/system clock */
+ void (*intr)(int which); /* interrupt callback */
+ write8_handler zc[4]; /* zero crossing callbacks */
+ UINT8 notimer; /* no timer masks */
+ UINT16 mode[4]; /* current mode */
+ UINT16 tconst[4]; /* time constant */
+ UINT16 down[4]; /* down counter (clock mode only) */
+ UINT8 extclk[4]; /* current signal from the external clock */
+ emu_timer *timer[4]; /* array of active timers */
+ UINT8 int_state[4]; /* interrupt status (for daisy chain) */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static z80ctc ctcs[MAX_CTC];
+
+
+
+/***************************************************************************
+ INTERNAL STATE MANAGEMENT
+***************************************************************************/
+
+static void interrupt_check(int which)
+{
+ z80ctc *ctc = ctcs + which;
+
+ /* if we have a callback, update it with the current state */
+ if (ctc->intr)
+ (*ctc->intr)((z80ctc_irq_state(which) & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+static TIMER_CALLBACK( timercallback )
+{
+ int which = param >> 2;
+ int ch = param & 3;
+ z80ctc *ctc = ctcs + which;
+
+ /* down counter has reached zero - see if we should interrupt */
+ if ((ctc->mode[ch] & INTERRUPT) == INTERRUPT_ON)
+ {
+ ctc->int_state[ch] |= Z80_DAISY_INT;
+ VPRINTF(("CTC timer ch%d\n", ch));
+ interrupt_check(which);
+ }
+
+ /* generate the clock pulse */
+ if (ctc->zc[ch])
+ {
+ (*ctc->zc[ch])(0,1);
+ (*ctc->zc[ch])(0,0);
+ }
+
+ /* reset the down counter */
+ ctc->down[ch] = ctc->tconst[ch];
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION/CONFIGURATION
+***************************************************************************/
+
+void z80ctc_init(int which, z80ctc_interface *intf)
+{
+ z80ctc *ctc = &ctcs[which];
+
+ assert(which < MAX_CTC);
+
+ memset(ctc, 0, sizeof(*ctc));
+
+ ctc->clock = intf->baseclock;
+ ctc->period16 = attotime_mul(ATTOTIME_IN_HZ(intf->baseclock), 16);
+ ctc->period256 = attotime_mul(ATTOTIME_IN_HZ(intf->baseclock), 256);
+ ctc->notimer = intf->notimer;
+ ctc->intr = intf->intr;
+ ctc->timer[0] = timer_alloc(timercallback);
+ ctc->timer[1] = timer_alloc(timercallback);
+ ctc->timer[2] = timer_alloc(timercallback);
+ ctc->timer[3] = timer_alloc(timercallback);
+ ctc->zc[0] = intf->zc0;
+ ctc->zc[1] = intf->zc1;
+ ctc->zc[2] = intf->zc2;
+ ctc->zc[3] = 0;
+ z80ctc_reset(which);
+
+ state_save_register_item("z80ctc", which, ctc->vector);
+ state_save_register_item_array("z80ctc", which, ctc->mode);
+ state_save_register_item_array("z80ctc", which, ctc->tconst);
+ state_save_register_item_array("z80ctc", which, ctc->down);
+ state_save_register_item_array("z80ctc", which, ctc->extclk);
+ state_save_register_item_array("z80ctc", which, ctc->int_state);
+}
+
+
+void z80ctc_reset(int which)
+{
+ z80ctc *ctc = ctcs + which;
+ int i;
+
+ /* set up defaults */
+ for (i = 0; i < 4; i++)
+ {
+ ctc->mode[i] = RESET_ACTIVE;
+ ctc->tconst[i] = 0x100;
+ timer_adjust(ctc->timer[i], attotime_never, 0, attotime_never);
+ ctc->int_state[i] = 0;
+ }
+ interrupt_check(which);
+ VPRINTF(("CTC Reset\n"));
+}
+
+
+attotime z80ctc_getperiod(int which, int ch)
+{
+ z80ctc *ctc = ctcs + which;
+ attotime period;
+
+ /* if reset active, no period */
+ if ((ctc->mode[ch] & RESET) == RESET_ACTIVE)
+ return attotime_zero;
+
+ /* if counter mode, no real period */
+ if ((ctc->mode[ch] & MODE) == MODE_COUNTER)
+ {
+ logerror("CTC %d is CounterMode : Can't calculate period\n", ch );
+ return attotime_zero;
+ }
+
+ /* compute the period */
+ period = ((ctc->mode[ch] & PRESCALER) == PRESCALER_16) ? ctc->period16 : ctc->period256;
+ return attotime_mul(period, ctc->tconst[ch]);
+}
+
+
+
+/***************************************************************************
+ WRITE HANDLERS
+***************************************************************************/
+
+void z80ctc_w(int which, int ch, UINT8 data)
+{
+ z80ctc *ctc = ctcs + which;
+ int mode;
+
+ /* get the current mode */
+ mode = ctc->mode[ch];
+
+ /* if we're waiting for a time constant, this is it */
+ if ((mode & CONSTANT) == CONSTANT_LOAD)
+ {
+ VPRINTF(("CTC ch.%d constant = %02x\n", ch, data));
+
+ /* set the time constant (0 -> 0x100) */
+ ctc->tconst[ch] = data ? data : 0x100;
+
+ /* clear the internal mode -- we're no longer waiting */
+ ctc->mode[ch] &= ~CONSTANT;
+
+ /* also clear the reset, since the constant gets it going again */
+ ctc->mode[ch] &= ~RESET;
+
+ /* if we're in timer mode.... */
+ if ((mode & MODE) == MODE_TIMER)
+ {
+ /* if we're triggering on the time constant, reset the down counter now */
+ if ((mode & TRIGGER) == TRIGGER_AUTO)
+ {
+ if (!(ctc->notimer & (1<<ch)))
+ {
+ attotime period = ((mode & PRESCALER) == PRESCALER_16) ? ctc->period16 : ctc->period256;
+ period = attotime_mul(period, ctc->tconst[ch]);
+
+ timer_adjust(ctc->timer[ch], period, (which << 2) + ch, period);
+ }
+ else
+ timer_adjust(ctc->timer[ch], attotime_never, 0, attotime_never);
+ }
+
+ /* else set the bit indicating that we're waiting for the appropriate trigger */
+ else
+ ctc->mode[ch] |= WAITING_FOR_TRIG;
+ }
+
+ /* also set the down counter in case we're clocking externally */
+ ctc->down[ch] = ctc->tconst[ch];
+
+ /* all done here */
+ return;
+ }
+
+ /* if we're writing the interrupt vector, handle it specially */
+#if 0 /* Tatsuyuki Satoh changes */
+ /* The 'Z80family handbook' wrote, */
+ /* interrupt vector is able to set for even channel (0 or 2) */
+ if ((data & CONTROL) == CONTROL_VECTOR && (ch&1) == 0)
+#else
+ if ((data & CONTROL) == CONTROL_VECTOR && ch == 0)
+#endif
+ {
+ ctc->vector = data & 0xf8;
+ logerror("CTC Vector = %02x\n", ctc->vector);
+ return;
+ }
+
+ /* this must be a control word */
+ if ((data & CONTROL) == CONTROL_WORD)
+ {
+ /* set the new mode */
+ ctc->mode[ch] = data;
+ VPRINTF(("CTC ch.%d mode = %02x\n", ch, data));
+
+ /* if we're being reset, clear out any pending timers for this channel */
+ if ((data & RESET) == RESET_ACTIVE)
+ {
+ timer_adjust(ctc->timer[ch], attotime_never, 0, attotime_zero);
+ /* note that we don't clear the interrupt state here! */
+ }
+
+ /* all done here */
+ return;
+ }
+}
+
+WRITE8_HANDLER( z80ctc_0_w ) { z80ctc_w(0, offset, data); }
+WRITE8_HANDLER( z80ctc_1_w ) { z80ctc_w(1, offset, data); }
+
+
+
+/***************************************************************************
+ READ HANDLERS
+***************************************************************************/
+
+UINT8 z80ctc_r(int which, int ch)
+{
+ z80ctc *ctc = ctcs + which;
+
+ /* if we're in counter mode, just return the count */
+ if ((ctc->mode[ch] & MODE) == MODE_COUNTER || (ctc->mode[ch] & WAITING_FOR_TRIG))
+ return ctc->down[ch];
+
+ /* else compute the down counter value */
+ else
+ {
+ attotime period = ((ctc->mode[ch] & PRESCALER) == PRESCALER_16) ? ctc->period16 : ctc->period256;
+
+ VPRINTF(("CTC clock %f\n",ATTOSECONDS_TO_HZ(period.attoseconds)));
+
+ if (ctc->timer[ch])
+ return ((int)(attotime_to_double(timer_timeleft(ctc->timer[ch])) * attotime_to_double(period)) + 1) & 0xff;
+ else
+ return 0;
+ }
+}
+
+READ8_HANDLER( z80ctc_0_r ) { return z80ctc_r(0, offset); }
+READ8_HANDLER( z80ctc_1_r ) { return z80ctc_r(1, offset); }
+
+
+
+/***************************************************************************
+ EXTERNAL TRIGGERS
+***************************************************************************/
+
+void z80ctc_trg_w(int which, int ch, UINT8 data)
+{
+ z80ctc *ctc = ctcs + which;
+
+ /* normalize data */
+ data = data ? 1 : 0;
+
+ /* see if the trigger value has changed */
+ if (data != ctc->extclk[ch])
+ {
+ ctc->extclk[ch] = data;
+
+ /* see if this is the active edge of the trigger */
+ if (((ctc->mode[ch] & EDGE) == EDGE_RISING && data) || ((ctc->mode[ch] & EDGE) == EDGE_FALLING && !data))
+ {
+ /* if we're waiting for a trigger, start the timer */
+ if ((ctc->mode[ch] & WAITING_FOR_TRIG) && (ctc->mode[ch] & MODE) == MODE_TIMER)
+ {
+ VPRINTF(("CTC clock %f\n",1.0/clock));
+
+ if (!(ctc->notimer & (1<<ch)))
+ {
+ attotime period = ((ctc->mode[ch] & PRESCALER) == PRESCALER_16) ? ctc->period16 : ctc->period256;
+ period = attotime_mul(period, ctc->tconst[ch]);
+
+ timer_adjust(ctc->timer[ch], period, (which << 2) + ch, period);
+ }
+ else
+ timer_adjust(ctc->timer[ch], attotime_never, 0, attotime_never);
+ }
+
+ /* we're no longer waiting */
+ ctc->mode[ch] &= ~WAITING_FOR_TRIG;
+
+ /* if we're clocking externally, decrement the count */
+ if ((ctc->mode[ch] & MODE) == MODE_COUNTER)
+ {
+ ctc->down[ch]--;
+
+ /* if we hit zero, do the same thing as for a timer interrupt */
+ if (!ctc->down[ch])
+ timercallback(Machine, (which << 2) + ch);
+ }
+ }
+ }
+}
+
+WRITE8_HANDLER( z80ctc_0_trg0_w ) { z80ctc_trg_w(0, 0, data); }
+WRITE8_HANDLER( z80ctc_0_trg1_w ) { z80ctc_trg_w(0, 1, data); }
+WRITE8_HANDLER( z80ctc_0_trg2_w ) { z80ctc_trg_w(0, 2, data); }
+WRITE8_HANDLER( z80ctc_0_trg3_w ) { z80ctc_trg_w(0, 3, data); }
+WRITE8_HANDLER( z80ctc_1_trg0_w ) { z80ctc_trg_w(1, 0, data); }
+WRITE8_HANDLER( z80ctc_1_trg1_w ) { z80ctc_trg_w(1, 1, data); }
+WRITE8_HANDLER( z80ctc_1_trg2_w ) { z80ctc_trg_w(1, 2, data); }
+WRITE8_HANDLER( z80ctc_1_trg3_w ) { z80ctc_trg_w(1, 3, data); }
+
+
+
+/***************************************************************************
+ DAISY CHAIN INTERFACE
+***************************************************************************/
+
+int z80ctc_irq_state(int which)
+{
+ z80ctc *ctc = ctcs + which;
+ int state = 0;
+ int ch;
+
+ VPRINTF(("CTC IRQ state = %d%d%d%d\n", ctc->int_state[0], ctc->int_state[1], ctc->int_state[2], ctc->int_state[3]));
+
+ /* loop over all channels */
+ for (ch = 0; ch < 4; ch++)
+ {
+ /* if we're servicing a request, don't indicate more interrupts */
+ if (ctc->int_state[ch] & Z80_DAISY_IEO)
+ {
+ state |= Z80_DAISY_IEO;
+ break;
+ }
+ state |= ctc->int_state[ch];
+ }
+
+ return state;
+}
+
+
+int z80ctc_irq_ack(int which)
+{
+ z80ctc *ctc = ctcs + which;
+ int ch;
+
+ /* loop over all channels */
+ for (ch = 0; ch < 4; ch++)
+
+ /* find the first channel with an interrupt requested */
+ if (ctc->int_state[ch] & Z80_DAISY_INT)
+ {
+ VPRINTF(("CTC IRQAck ch%d\n", ch));
+
+ /* clear interrupt, switch to the IEO state, and update the IRQs */
+ ctc->int_state[ch] = Z80_DAISY_IEO;
+ interrupt_check(which);
+ return ctc->vector + ch * 2;
+ }
+
+ logerror("z80ctc_irq_ack: failed to find an interrupt to ack!\n");
+ return ctc->vector;
+}
+
+
+void z80ctc_irq_reti(int which)
+{
+ z80ctc *ctc = ctcs + which;
+ int ch;
+
+ /* loop over all channels */
+ for (ch = 0; ch < 4; ch++)
+
+ /* find the first channel with an IEO pending */
+ if (ctc->int_state[ch] & Z80_DAISY_IEO)
+ {
+ VPRINTF(("CTC IRQReti ch%d\n", ch));
+
+ /* clear the IEO state and update the IRQs */
+ ctc->int_state[ch] &= ~Z80_DAISY_IEO;
+ interrupt_check(which);
+ return;
+ }
+
+ logerror("z80ctc_irq_reti: failed to find an interrupt to clear IEO on!\n");
+}
diff --git a/src/emu/machine/z80ctc.h b/src/emu/machine/z80ctc.h
new file mode 100644
index 00000000000..ff2a6d52aec
--- /dev/null
+++ b/src/emu/machine/z80ctc.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+
+ Z80 CTC (Z8430) implementation
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_CTC 2
+
+#define NOTIMER_0 (1<<0)
+#define NOTIMER_1 (1<<1)
+#define NOTIMER_2 (1<<2)
+#define NOTIMER_3 (1<<3)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct
+{
+ int baseclock; /* timer clock */
+ int notimer; /* timer disablers */
+ void (*intr)(int which); /* callback when change interrupt status */
+ write8_handler zc0; /* ZC/TO0 callback */
+ write8_handler zc1; /* ZC/TO1 callback */
+ write8_handler zc2; /* ZC/TO2 callback */
+} z80ctc_interface;
+
+
+
+/***************************************************************************
+ INITIALIZATION/CONFIGURATION
+***************************************************************************/
+
+void z80ctc_init(int which, z80ctc_interface *intf);
+void z80ctc_reset(int which);
+attotime z80ctc_getperiod (int which, int ch);
+
+
+
+/***************************************************************************
+ WRITE HANDLERS
+***************************************************************************/
+
+void z80ctc_w(int which, int ch, UINT8 data);
+WRITE8_HANDLER( z80ctc_0_w );
+WRITE8_HANDLER( z80ctc_1_w );
+
+
+
+/***************************************************************************
+ READ HANDLERS
+***************************************************************************/
+
+UINT8 z80ctc_r(int which, int ch);
+READ8_HANDLER( z80ctc_0_r );
+READ8_HANDLER( z80ctc_1_r );
+
+
+
+/***************************************************************************
+ EXTERNAL TRIGGERS
+***************************************************************************/
+
+void z80ctc_trg_w(int which, int trg, UINT8 data);
+WRITE8_HANDLER( z80ctc_0_trg0_w );
+WRITE8_HANDLER( z80ctc_0_trg1_w );
+WRITE8_HANDLER( z80ctc_0_trg2_w );
+WRITE8_HANDLER( z80ctc_0_trg3_w );
+WRITE8_HANDLER( z80ctc_1_trg0_w );
+WRITE8_HANDLER( z80ctc_1_trg1_w );
+WRITE8_HANDLER( z80ctc_1_trg2_w );
+WRITE8_HANDLER( z80ctc_1_trg3_w );
+
+
+
+/***************************************************************************
+ DAISY CHAIN INTERFACE
+***************************************************************************/
+
+int z80ctc_irq_state(int which);
+int z80ctc_irq_ack(int which);
+void z80ctc_irq_reti(int which);
diff --git a/src/emu/machine/z80pio.c b/src/emu/machine/z80pio.c
new file mode 100644
index 00000000000..81f293b83c9
--- /dev/null
+++ b/src/emu/machine/z80pio.c
@@ -0,0 +1,537 @@
+/***************************************************************************
+
+ Z80 PIO implementation
+
+ based on original version (c) 1997, Tatsuyuki Satoh
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "z80pio.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define VPRINTF(x) logerror x
+#else
+#define VPRINTF(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define PIO_MODE0 0x00 /* output mode */
+#define PIO_MODE1 0x01 /* input mode */
+#define PIO_MODE2 0x02 /* i/o mode */
+#define PIO_MODE3 0x03 /* bit mode */
+
+/* pio controll port operation (bit 0-3) */
+#define PIO_OP_MODE 0x0f /* mode select */
+#define PIO_OP_INTC 0x07 /* interrupt controll */
+#define PIO_OP_INTE 0x03 /* interrupt enable */
+
+/* pio interrupt controll nit */
+#define PIO_INT_ENABLE 0x80 /* ENABLE : 0=disable , 1=enable */
+#define PIO_INT_AND 0x40 /* LOGIC : 0=OR , 1=AND */
+#define PIO_INT_HIGH 0x20 /* LEVEL : 0=low , 1=high */
+#define PIO_INT_MASK 0x10 /* MASK : 0=off , 1=on */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct _z80pio
+{
+ UINT8 vector[2]; /* interrupt vector */
+ void (*intr)(int which); /* interrupt callbacks */
+ void (*rdyr[2])(int data); /* RDY active callback */
+ UINT8 mode[2]; /* mode 00=in,01=out,02=i/o,03=bit*/
+ UINT8 enable[2]; /* interrupt enable */
+ UINT8 mask[2]; /* mask folowers */
+ UINT8 dir[2]; /* direction (bit mode) */
+ UINT8 rdy[2]; /* ready pin level */
+ UINT8 in[2]; /* input port data */
+ UINT8 out[2]; /* output port */
+ UINT8 strobe[2]; /* strobe inputs */
+ UINT8 int_state[2]; /* interrupt status (daisy chain) */
+};
+typedef struct _z80pio z80pio;
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static z80pio pios[MAX_PIO];
+
+
+
+/***************************************************************************
+ INTERNAL STATE MANAGEMENT
+***************************************************************************/
+
+static void set_rdy(z80pio *pio, int ch, int state)
+{
+ /* set state */
+ pio->rdy[ch] = state;
+
+ /* call callback with state */
+ if (pio->rdyr[ch])
+ (*pio->rdyr[ch])(pio->rdy[ch]);
+}
+
+
+static void interrupt_check(int which)
+{
+ z80pio *pio = pios + which;
+
+ /* if we have a callback, update it with the current state */
+ if (pio->intr)
+ (*pio->intr)((z80pio_irq_state(which) & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+static void update_irq_state(z80pio *pio, int ch)
+{
+ int old_state = pio->int_state[ch];
+ int irq = 0;
+ int data;
+ if (pio->mode[ch] == 0x13) return;
+
+ /* only check if interrupts are enabled */
+ if (pio->enable[ch] & PIO_INT_ENABLE)
+ {
+ /* in mode 3, interrupts are tricky */
+ if (pio->mode[ch] == PIO_MODE3)
+ {
+ /* fetch input data (ignore output lines) */
+ data = pio->in[ch] & pio->dir[ch];
+
+ /* keep only relevant bits */
+ data &= ~pio->mask[ch];
+
+ /* if active low, invert the bits */
+ if (!(pio->enable[ch] & PIO_INT_HIGH))
+ data ^= pio->mask[ch];
+
+ /* if AND logic, interrupt if all bits are set */
+ if (pio->enable[ch] & PIO_INT_AND)
+ irq = (data == pio->mask[ch]);
+
+ /* otherwise, interrupt if at least one bit is set */
+ else
+ irq = (data != 0);
+
+ /* if portB, portA mode 2 check */
+ if (ch && (pio->mode[0] == PIO_MODE2))
+ {
+ if (pio->rdy[ch] == 0)
+ irq = 1;
+ }
+ }
+
+ /* otherwise, just interrupt when ready is cleared */
+ else
+ irq = (pio->rdy[ch] == 0);
+ }
+
+ if (irq)
+ pio->int_state[ch] |= Z80_DAISY_INT;
+ else
+ pio->int_state[ch] &= ~Z80_DAISY_INT;
+
+ if (old_state != pio->int_state[ch])
+ interrupt_check(pio - pios);
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION/CONFIGURATION
+***************************************************************************/
+
+void z80pio_init(int which, z80pio_interface *intf)
+{
+ z80pio *pio = pios + which;
+
+ assert(which < MAX_PIO);
+
+ memset(pio, 0, sizeof(*pio));
+
+ pio->intr = intf->intr;
+ pio->rdyr[0] = intf->rdyA;
+ pio->rdyr[1] = intf->rdyB;
+ z80pio_reset(which);
+
+ state_save_register_item_array("z80pio", which, pio->vector);
+ state_save_register_item_array("z80pio", which, pio->mode);
+ state_save_register_item_array("z80pio", which, pio->enable);
+ state_save_register_item_array("z80pio", which, pio->mask);
+ state_save_register_item_array("z80pio", which, pio->dir);
+ state_save_register_item_array("z80pio", which, pio->rdy);
+ state_save_register_item_array("z80pio", which, pio->in);
+ state_save_register_item_array("z80pio", which, pio->out);
+ state_save_register_item_array("z80pio", which, pio->strobe);
+ state_save_register_item_array("z80pio", which, pio->int_state);
+}
+
+
+void z80pio_reset(int which)
+{
+ z80pio *pio = pios + which;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ pio->mask[i] = 0xff; /* mask all on */
+ pio->enable[i] = 0x00; /* disable */
+ pio->mode[i] = 0x01; /* mode input */
+ pio->dir[i] = 0x01; /* dir input */
+ set_rdy(pio, i, 0); /* RDY = low */
+ pio->out[i] = 0x00; /* outdata = 0 */
+ pio->int_state[i] = 0;
+ pio->strobe[i] = 0;
+ }
+ interrupt_check(which);
+}
+
+
+
+/***************************************************************************
+ CONTROL REGISTER READ/WRITE
+***************************************************************************/
+
+void z80pio_c_w(int which, int ch, UINT8 data)
+{
+ z80pio *pio = pios + which;
+
+ /* load direction phase ? */
+ if (pio->mode[ch] == 0x13)
+ {
+ logerror("PIO-%c Bits %02x\n", 'A' + ch, data);
+ pio->dir[ch] = data;
+ pio->mode[ch] = 0x03;
+ return;
+ }
+
+ /* load mask folows phase ? */
+ if (pio->enable[ch] & PIO_INT_MASK)
+ {
+ /* load mask folows */
+ pio->mask[ch] = data;
+ pio->enable[ch] &= ~PIO_INT_MASK;
+ logerror("PIO-%c interrupt mask %02x\n",'A'+ch,data );
+ return;
+ }
+
+ switch (data & 0x0f)
+ {
+ case PIO_OP_MODE: /* mode select 0=out,1=in,2=i/o,3=bit */
+ pio->mode[ch] = (data >> 6);
+ logerror("PIO-%c Mode %x\n", 'A' + ch, pio->mode[ch]);
+ if (pio->mode[ch] == 0x03)
+ pio->mode[ch] = 0x13;
+ return;
+
+ case PIO_OP_INTC: /* interrupt control */
+ pio->enable[ch] = data & 0xf0;
+ pio->mask[ch] = 0x00;
+ /* when interrupt enable , set vector request flag */
+ logerror("PIO-%c Controll %02x\n", 'A' + ch, data);
+ break;
+
+ case PIO_OP_INTE: /* interrupt enable controll */
+ pio->enable[ch] &= ~PIO_INT_ENABLE;
+ pio->enable[ch] |= (data & PIO_INT_ENABLE);
+ logerror("PIO-%c enable %02x\n", 'A' + ch, data & 0x80);
+ break;
+
+ default:
+ if (!(data & 1))
+ {
+ pio->vector[ch] = data;
+ logerror("PIO-%c vector %02x\n", 'A' + ch, data);
+ }
+ else
+ logerror("PIO-%c illegal command %02x\n", 'A' + ch, data);
+ break;
+ }
+
+ /* interrupt check */
+ update_irq_state(pio, ch);
+}
+
+
+UINT8 z80pio_c_r(int which, int ch)
+{
+ logerror("PIO-%c controll read\n", 'A' + ch );
+ return 0;
+}
+
+
+
+/***************************************************************************
+ DATA REGISTER READ/WRITE
+***************************************************************************/
+
+void z80pio_d_w(int which, int ch, UINT8 data)
+{
+ z80pio *pio = pios + which;
+
+ pio->out[ch] = data; /* latch out data */
+ switch (pio->mode[ch])
+ {
+ case PIO_MODE0: /* mode 0 output */
+ case PIO_MODE2: /* mode 2 i/o */
+ set_rdy(pio, ch, 1); /* ready = H */
+ update_irq_state(pio, ch);
+ return;
+
+ case PIO_MODE1: /* mode 1 input */
+ case PIO_MODE3: /* mode 0 bit */
+ return;
+
+ default:
+ logerror("PIO-%c data write,bad mode\n",'A'+ch );
+ }
+}
+
+
+UINT8 z80pio_d_r(int which, int ch)
+{
+ z80pio *pio = pios + which;
+
+ switch (pio->mode[ch])
+ {
+ case PIO_MODE0: /* mode 0 output */
+ return pio->out[ch];
+
+ case PIO_MODE1: /* mode 1 input */
+ set_rdy(pio, ch, 1); /* ready = H */
+ update_irq_state(pio, ch);
+ return pio->in[ch];
+
+ case PIO_MODE2: /* mode 2 i/o */
+ if (ch) logerror("PIO-B mode 2 \n");
+ set_rdy(pio, 1, 1); /* brdy = H */
+ update_irq_state(pio, ch);
+ return pio->in[ch];
+
+ case PIO_MODE3: /* mode 3 bit */
+ return (pio->in[ch] & pio->dir[ch]) | (pio->out[ch] & ~pio->dir[ch]);
+ }
+ logerror("PIO-%c data read,bad mode\n",'A'+ch );
+ return 0;
+}
+
+
+
+/***************************************************************************
+ PORT I/O
+***************************************************************************/
+
+void z80pio_p_w(int which, UINT8 ch, UINT8 data)
+{
+ z80pio *pio = pios + which;
+
+ pio->in[ch] = data;
+ switch (pio->mode[ch])
+ {
+ case PIO_MODE0:
+ logerror("PIO-%c OUTPUT mode and data write\n",'A'+ch );
+ break;
+
+ case PIO_MODE2: /* only port A */
+ ch = 1; /* handshake and IRQ is use portB */
+
+ case PIO_MODE1:
+ set_rdy(pio, ch, 0);
+ update_irq_state(pio, ch);
+ break;
+
+ case PIO_MODE3:
+ /* irq check */
+ update_irq_state(pio, ch);
+ break;
+ }
+}
+
+
+int z80pio_p_r(int which, UINT8 ch)
+{
+ z80pio *pio = pios + which;
+
+ switch (pio->mode[ch])
+ {
+ case PIO_MODE2: /* port A only */
+ case PIO_MODE0:
+ set_rdy(pio, ch, 0);
+ update_irq_state(pio, ch);
+ break;
+
+ case PIO_MODE1:
+ logerror("PIO-%c INPUT mode and data read\n",'A'+ch );
+ break;
+
+ case PIO_MODE3:
+ return (pio->in[ch] & pio->dir[ch]) | (pio->out[ch] & ~pio->dir[ch]);
+ }
+ return pio->out[ch];
+}
+
+
+WRITE8_HANDLER( z80pioA_0_p_w ) { z80pio_p_w(0, 0, data); }
+WRITE8_HANDLER( z80pioB_0_p_w ) { z80pio_p_w(0, 1, data); }
+READ8_HANDLER( z80pioA_0_p_r ) { return z80pio_p_r(0, 0); }
+READ8_HANDLER( z80pioB_0_p_r ) { return z80pio_p_r(0, 1); }
+
+WRITE8_HANDLER( z80pioA_1_p_w ) { z80pio_p_w(1, 0, data); }
+WRITE8_HANDLER( z80pioB_1_p_w ) { z80pio_p_w(1, 1, data); }
+READ8_HANDLER( z80pioA_1_p_r ) { return z80pio_p_r(1, 0); }
+READ8_HANDLER( z80pioB_1_p_r ) { return z80pio_p_r(1, 1); }
+
+
+
+/***************************************************************************
+ STROBE STATE MANAGEMENT
+***************************************************************************/
+
+static void z80pio_update_strobe(int which, int ch, int state)
+{
+ z80pio *pio = pios + which;
+
+ switch (pio->mode[ch])
+ {
+ /* output mode: a positive edge is used by peripheral to acknowledge
+ the receipt of data */
+ case PIO_MODE0:
+ {
+ /* ensure valid */
+ state = state & 0x01;
+
+ /* strobe changed state? */
+ if ((pio->strobe[ch] ^ state) != 0)
+ {
+ /* yes */
+ if (state != 0)
+ {
+ /* positive edge */
+ logerror("PIO-%c positive strobe\n",'A' + ch);
+
+ /* ready is now inactive */
+ set_rdy(pio, ch, 0);
+
+ /* int enabled? */
+ if (pio->enable[ch] & PIO_INT_ENABLE)
+ {
+ /* trigger an int request */
+ pio->int_state[ch] |= Z80_DAISY_INT;
+ }
+ }
+ }
+
+ /* store strobe state */
+ pio->strobe[ch] = state;
+
+ /* check interrupt */
+ interrupt_check(which);
+ }
+ break;
+
+ /* input mode: strobe is used by peripheral to load data from the peripheral
+ into port a input register, data loaded into pio when signal is active */
+
+ default:
+ break;
+ }
+}
+
+
+void z80pio_astb_w(int which, int state) { z80pio_update_strobe(which, 0, state); }
+void z80pio_bstb_w(int which, int state) { z80pio_update_strobe(which, 1, state); }
+
+
+
+/***************************************************************************
+ DAISY CHAIN INTERFACE
+***************************************************************************/
+
+int z80pio_irq_state(int which)
+{
+ z80pio *pio = pios + which;
+ int state = 0;
+ int ch;
+
+ /* loop over all channels */
+ for (ch = 0; ch < 2; ch++)
+ {
+ /* if we're servicing a request, don't indicate more interrupts */
+ if (pio->int_state[ch] & Z80_DAISY_IEO)
+ {
+ state |= Z80_DAISY_IEO;
+ break;
+ }
+ state |= pio->int_state[ch];
+ }
+ return state;
+}
+
+
+int z80pio_irq_ack(int which)
+{
+ z80pio *pio = pios + which;
+ int ch;
+
+ /* loop over all channels */
+ for (ch = 0; ch < 2; ch++)
+
+ /* find the first channel with an interrupt requested */
+ if (pio->int_state[ch] & Z80_DAISY_INT)
+ {
+ /* clear interrupt, switch to the IEO state, and update the IRQs */
+ pio->int_state[ch] = Z80_DAISY_IEO;
+ interrupt_check(which);
+ return pio->vector[ch];
+ }
+
+ logerror("z80pio_irq_ack: failed to find an interrupt to ack!");
+ return pio->vector[0];
+}
+
+
+void z80pio_irq_reti(int which)
+{
+ z80pio *pio = pios + which;
+ int ch;
+
+ /* loop over all channels */
+ for (ch = 0; ch < 2; ch++)
+
+ /* find the first channel with an IEO pending */
+ if (pio->int_state[ch] & Z80_DAISY_IEO)
+ {
+ /* clear the IEO state and update the IRQs */
+ pio->int_state[ch] &= ~Z80_DAISY_IEO;
+ interrupt_check(which);
+ return;
+ }
+
+ logerror("z80pio_irq_reti: failed to find an interrupt to clear IEO on!");
+}
diff --git a/src/emu/machine/z80pio.h b/src/emu/machine/z80pio.h
new file mode 100644
index 00000000000..e699ce0de03
--- /dev/null
+++ b/src/emu/machine/z80pio.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+
+ Z80 PIO implementation
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_PIO 2
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct _z80pio_interface
+{
+ void (*intr)(int which); /* callback when change interrupt status */
+ void (*rdyA)(int data); /* portA ready active callback (do not support yet)*/
+ void (*rdyB)(int data); /* portB ready active callback (do not support yet)*/
+};
+typedef struct _z80pio_interface z80pio_interface;
+
+
+
+/***************************************************************************
+ INITIALIZATION/CONFIGURATION
+***************************************************************************/
+
+void z80pio_init(int which, z80pio_interface *intf);
+void z80pio_reset(int which);
+
+
+
+/***************************************************************************
+ CONTROL REGISTER READ/WRITE
+***************************************************************************/
+
+void z80pio_c_w(int which, int ch, UINT8 data);
+UINT8 z80pio_c_r(int which, int ch);
+
+
+
+/***************************************************************************
+ DATA REGISTER READ/WRITE
+***************************************************************************/
+
+void z80pio_d_w(int which, int ch, UINT8 data);
+UINT8 z80pio_d_r(int which, int ch);
+
+
+
+/***************************************************************************
+ PORT I/O
+***************************************************************************/
+
+void z80pio_p_w(int which, UINT8 ch, UINT8 data);
+int z80pio_p_r(int which, UINT8 ch);
+
+WRITE8_HANDLER( z80pioA_0_p_w );
+WRITE8_HANDLER( z80pioB_0_p_w );
+READ8_HANDLER( z80pioA_0_p_r );
+READ8_HANDLER( z80pioB_0_p_r );
+WRITE8_HANDLER( z80pioA_1_p_w );
+WRITE8_HANDLER( z80pioB_1_p_w );
+READ8_HANDLER( z80pioA_1_p_r );
+READ8_HANDLER( z80pioB_1_p_r );
+
+
+
+/***************************************************************************
+ STROBE STATE MANAGEMENT
+***************************************************************************/
+
+void z80pio_astb_w(int which, int state);
+void z80pio_bstb_w(int which, int state);
+
+
+
+/***************************************************************************
+ DAISY CHAIN INTERFACE
+***************************************************************************/
+
+int z80pio_irq_state(int which);
+int z80pio_irq_ack(int which);
+void z80pio_irq_reti(int which);
diff --git a/src/emu/machine/z80sio.c b/src/emu/machine/z80sio.c
new file mode 100644
index 00000000000..1da4fa1eb5d
--- /dev/null
+++ b/src/emu/machine/z80sio.c
@@ -0,0 +1,805 @@
+/***************************************************************************
+
+ Z80 SIO (Z8440) implementation
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "z80sio.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE 1
+
+#if VERBOSE
+#define VPRINTF(x) logerror x
+#else
+#define VPRINTF(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* interrupt states */
+#define INT_CHB_TRANSMIT 0x00 /* not confirmed */
+#define INT_CHB_STATUS 0x01
+#define INT_CHB_RECEIVE 0x02
+#define INT_CHB_ERROR 0x03
+
+#define INT_CHA_TRANSMIT 0x04 /* not confirmed */
+#define INT_CHA_STATUS 0x05
+#define INT_CHA_RECEIVE 0x06
+#define INT_CHA_ERROR 0x07
+
+/* SIO write register 0 */
+#define SIO_WR0_RESET_MASK 0xc0 /* D7-D6: Reset control */
+#define SIO_WR0_RESET_NULL 0x00 /* 00 = NULL code */
+#define SIO_WR0_RESET_RX_CRC 0x40 /* 01 = Reset Rx CRC checker */
+#define SIO_WR0_RESET_TX_CRC 0x80 /* 10 = Reset Tx CRC generator */
+#define SIO_WR0_RESET_TX_LATCH 0xc0 /* 11 = Reset Tx Underrun/EOM latch */
+#define SIO_WR0_COMMAND_MASK 0x38 /* D5-D3: Command */
+#define SIO_WR0_COMMAND_NULL 0x00 /* 000 = NULL code */
+#define SIO_WR0_COMMAND_SET_ABORT 0x08 /* 001 = Set abort (SDLC) */
+#define SIO_WR0_COMMAND_RES_STATUS_INT 0x10 /* 010 = reset ext/status interrupts */
+#define SIO_WR0_COMMAND_CH_RESET 0x18 /* 011 = Channel reset */
+#define SIO_WR0_COMMAND_ENA_RX_INT 0x20 /* 100 = Enable int on next Rx character */
+#define SIO_WR0_COMMAND_RES_TX_INT 0x28 /* 101 = Reset Tx int pending */
+#define SIO_WR0_COMMAND_RES_ERROR 0x30 /* 110 = Error reset */
+#define SIO_WR0_COMMAND_RETI 0x38 /* 111 = Return from int (CH-A only) */
+#define SIO_WR0_REGISTER_MASK 0x07 /* D2-D0: Register select (0-7) */
+
+/* SIO write register 1 */
+#define SIO_WR1_READY_WAIT_ENA 0x80 /* D7 = READY/WAIT enable */
+#define SIO_WR1_READY_WAIT_FUNCTION 0x40 /* D6 = READY/WAIT function */
+#define SIO_WR1_READY_WAIT_ON_RT 0x20 /* D5 = READY/WAIT on R/T */
+#define SIO_WR1_RXINT_MASK 0x18 /* D4-D3 = Rx int control */
+#define SIO_WR1_RXINT_DISABLE 0x00 /* 00 = Rx int disable */
+#define SIO_WR1_RXINT_FIRST 0x08 /* 01 = Rx int on first character */
+#define SIO_WR1_RXINT_ALL_PARITY 0x10 /* 10 = int on all Rx characters (parity affects vector) */
+#define SIO_WR1_RXINT_ALL_NOPARITY 0x18 /* 11 = int on all Rx characters (parity ignored) */
+#define SIO_WR1_STATUS_AFFECTS_VECTOR 0x04 /* D2 = Status affects vector (CH-B only) */
+#define SIO_WR1_TXINT_ENABLE 0x02 /* D1 = Tx int enable */
+#define SIO_WR1_STATUSINT_ENABLE 0x01 /* D0 = Ext int enable */
+
+/* SIO write register 2 (CH-B only) */
+#define SIO_WR2_INT_VECTOR_MASK 0xff /* D7-D0 = interrupt vector */
+
+/* SIO write register 3 */
+#define SIO_WR3_RX_DATABITS_MASK 0xc0 /* D7-D6 = Rx Data bits */
+#define SIO_WR3_RX_DATABITS_5 0x00 /* 00 = Rx 5 bits/character */
+#define SIO_WR3_RX_DATABITS_7 0x40 /* 01 = Rx 7 bits/character */
+#define SIO_WR3_RX_DATABITS_6 0x80 /* 10 = Rx 6 bits/character */
+#define SIO_WR3_RX_DATABITS_8 0xc0 /* 11 = Rx 8 bits/character */
+#define SIO_WR3_AUTO_ENABLES 0x20 /* D5 = Auto enables */
+#define SIO_WR3_ENTER_HUNT_PHASE 0x10 /* D4 = Enter hunt phase */
+#define SIO_WR3_RX_CRC_ENABLE 0x08 /* D3 = Rx CRC enable */
+#define SIO_WR3_ADDR_SEARCH_MODE 0x04 /* D2 = Address search mode (SDLC) */
+#define SIO_WR3_SYNC_LOAD_INHIBIT 0x02 /* D1 = Sync character load inhibit */
+#define SIO_WR3_RX_ENABLE 0x01 /* D0 = Rx enable */
+
+/* SIO write register 4 */
+#define SIO_WR4_CLOCK_MODE_MASK 0xc0 /* D7-D6 = Clock mode */
+#define SIO_WR4_CLOCK_MODE_x1 0x00 /* 00 = x1 clock mode */
+#define SIO_WR4_CLOCK_MODE_x16 0x40 /* 01 = x16 clock mode */
+#define SIO_WR4_CLOCK_MODE_x32 0x80 /* 10 = x32 clock mode */
+#define SIO_WR4_CLOCK_MODE_x64 0xc0 /* 11 = x64 clock mode */
+#define SIO_WR4_SYNC_MODE_MASK 0x30 /* D5-D4 = Sync mode */
+#define SIO_WR4_SYNC_MODE_8BIT 0x00 /* 00 = 8 bit sync character */
+#define SIO_WR4_SYNC_MODE_16BIT 0x10 /* 01 = 16 bit sync character */
+#define SIO_WR4_SYNC_MODE_SDLC 0x20 /* 10 = SDLC mode (01111110 flag) */
+#define SIO_WR4_SYNC_MODE_EXTERNAL 0x30 /* 11 = External sync mode */
+#define SIO_WR4_STOPBITS_MASK 0x0c /* D3-D2 = Stop bits */
+#define SIO_WR4_STOPBITS_SYNC 0x00 /* 00 = Sync modes enable */
+#define SIO_WR4_STOPBITS_1 0x04 /* 01 = 1 stop bit/character */
+#define SIO_WR4_STOPBITS_15 0x08 /* 10 = 1.5 stop bits/character */
+#define SIO_WR4_STOPBITS_2 0x0c /* 11 = 2 stop bits/character */
+#define SIO_WR4_PARITY_EVEN 0x02 /* D1 = Parity even/odd */
+#define SIO_WR4_PARITY_ENABLE 0x01 /* D0 = Parity enable */
+
+/* SIO write register 5 */
+#define SIO_WR5_DTR 0x80 /* D7 = DTR */
+#define SIO_WR5_TX_DATABITS_MASK 0x60 /* D6-D5 = Tx Data bits */
+#define SIO_WR5_TX_DATABITS_5 0x00 /* 00 = Tx 5 bits/character */
+#define SIO_WR5_TX_DATABITS_7 0x20 /* 01 = Tx 7 bits/character */
+#define SIO_WR5_TX_DATABITS_6 0x40 /* 10 = Tx 6 bits/character */
+#define SIO_WR5_TX_DATABITS_8 0x60 /* 11 = Tx 8 bits/character */
+#define SIO_WR5_SEND_BREAK 0x10 /* D4 = Send break */
+#define SIO_WR5_TX_ENABLE 0x08 /* D3 = Tx Enable */
+#define SIO_WR5_CRC16_SDLC 0x04 /* D2 = CRC-16/SDLC */
+#define SIO_WR5_RTS 0x02 /* D1 = RTS */
+#define SIO_WR5_TX_CRC_ENABLE 0x01 /* D0 = Tx CRC enable */
+
+/* SIO write register 6 */
+#define SIO_WR6_SYNC_7_0_MASK 0xff /* D7-D0 = Sync bits 7-0 */
+
+/* SIO write register 7 */
+#define SIO_WR7_SYNC_15_8_MASK 0xff /* D7-D0 = Sync bits 15-8 */
+
+/* SIO read register 0 */
+#define SIO_RR0_BREAK_ABORT 0x80 /* D7 = Break/abort */
+#define SIO_RR0_TX_UNDERRUN 0x40 /* D6 = Tx underrun/EOM */
+#define SIO_RR0_CTS 0x20 /* D5 = CTS */
+#define SIO_RR0_SYNC_HUNT 0x10 /* D4 = Sync/hunt */
+#define SIO_RR0_DCD 0x08 /* D3 = DCD */
+#define SIO_RR0_TX_BUFFER_EMPTY 0x04 /* D2 = Tx buffer empty */
+#define SIO_RR0_INT_PENDING 0x02 /* D1 = int pending (CH-A only) */
+#define SIO_RR0_RX_CHAR_AVAILABLE 0x01 /* D0 = Rx character available */
+
+/* SIO read register 1 */
+#define SIO_RR1_END_OF_FRAME 0x80 /* D7 = End of frame (SDLC) */
+#define SIO_RR1_CRC_FRAMING_ERROR 0x40 /* D6 = CRC/Framing error */
+#define SIO_RR1_RX_OVERRUN_ERROR 0x20 /* D5 = Rx overrun error */
+#define SIO_RR1_PARITY_ERROR 0x10 /* D4 = Parity error */
+#define SIO_RR1_IFIELD_BITS_MASK 0x0e /* D3-D1 = I field bits */
+ /* 100 = 0 in prev, 3 in 2nd prev */
+ /* 010 = 0 in prev, 4 in 2nd prev */
+ /* 110 = 0 in prev, 5 in 2nd prev */
+ /* 001 = 0 in prev, 6 in 2nd prev */
+ /* 101 = 0 in prev, 7 in 2nd prev */
+ /* 011 = 0 in prev, 8 in 2nd prev */
+ /* 111 = 1 in prev, 8 in 2nd prev */
+ /* 000 = 2 in prev, 8 in 2nd prev */
+#define SIO_RR1_ALL_SENT 0x01 /* D0 = All sent */
+
+/* SIO read register 2 (CH-B only) */
+#define SIO_RR2_VECTOR_MASK 0xff /* D7-D0 = Interrupt vector */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _sio_channel sio_channel;
+struct _sio_channel
+{
+ UINT8 regs[8]; /* 8 writeable registers */
+ UINT8 status[4]; /* 3 readable registers */
+ int inbuf; /* input buffer */
+ int outbuf; /* output buffer */
+ UINT8 int_on_next_rx; /* interrupt on next rx? */
+ emu_timer *receive_timer; /* timer to clock data in */
+ UINT8 receive_buffer[16]; /* buffer for incoming data */
+ UINT8 receive_inptr; /* index of data coming in */
+ UINT8 receive_outptr; /* index of data going out */
+};
+
+
+typedef struct _z80sio z80sio;
+struct _z80sio
+{
+ sio_channel chan[2]; /* 2 channels */
+ UINT8 int_state[8]; /* interrupt states */
+
+ void (*irq_cb)(int state);
+ write8_handler dtr_changed_cb;
+ write8_handler rts_changed_cb;
+ write8_handler break_changed_cb;
+ write8_handler transmit_cb;
+ int (*receive_poll_cb)(int which);
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static TIMER_CALLBACK( serial_callback );
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static z80sio sios[MAX_SIO];
+
+
+/*
+
+ Interrupt priorities:
+ Ch A receive
+ Ch A transmit
+ Ch A external/status
+ Ch B receive
+ Ch B transmit
+ Ch B external/status
+
+
+ Initial configuration (both channels):
+ 005D:sio_reg_w(0,4) = 44
+ 01 = x16 clock mode
+ 00 = 8 bit sync character
+ 01 = 1 stop bit/character
+ Parity odd
+ Parity disabled
+
+ 005D:sio_reg_w(0,3) = C1
+ 11 = Rx 8 bits/character
+ No auto enables
+ No enter hunt phase
+ No Rx CRC enable
+ No address search mode
+ No sync character load inhibit
+ Rx enable
+
+ 005D:sio_reg_w(0,5) = 68
+ DTR = 0
+ 11 = Tx 8 bits/character
+ No send break
+ Tx enable
+ SDLC
+ No RTS
+ No CRC enable
+
+ 005D:sio_reg_w(0,2) = 40
+ Vector = 0x40
+
+ 005D:sio_reg_w(0,1) = 1D
+ No READY/WAIT
+ No READY/WAIT function
+ No READY/WAIT on R/T
+ 11 = int on all Rx characters (parity ignored)
+ Status affects vector
+ No Tx int enable
+ Ext int enable
+
+*/
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE void interrupt_check(z80sio *sio)
+{
+ /* if we have a callback, update it with the current state */
+ if (sio->irq_cb != NULL)
+ (*sio->irq_cb)((z80sio_irq_state(sio - sios) & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+INLINE attotime compute_time_per_character(z80sio *sio, int which)
+{
+ /* fix me -- should compute properly and include data, stop, parity bits */
+ return attotime_mul(ATTOTIME_IN_HZ(9600), 10);
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION/CONFIGURATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ z80sio_init - initialize a single SIO chip
+-------------------------------------------------*/
+
+void z80sio_init(int which, z80sio_interface *intf)
+{
+ z80sio *sio = sios + which;
+
+ assert(which < MAX_SIO);
+
+ memset(sio, 0, sizeof(*sio));
+
+ sio->chan[0].receive_timer = timer_alloc(serial_callback);
+ sio->chan[1].receive_timer = timer_alloc(serial_callback);
+
+ sio->irq_cb = intf->irq_cb;
+ sio->dtr_changed_cb = intf->dtr_changed_cb;
+ sio->rts_changed_cb = intf->rts_changed_cb;
+ sio->break_changed_cb = intf->break_changed_cb;
+ sio->transmit_cb = intf->transmit_cb;
+ sio->receive_poll_cb = intf->receive_poll_cb;
+
+ z80sio_reset(which);
+}
+
+
+/*-------------------------------------------------
+ reset_channel - reset a single SIO channel
+-------------------------------------------------*/
+
+static void reset_channel(z80sio *sio, int ch)
+{
+ attotime tpc = compute_time_per_character(sio, ch);
+ sio_channel *chan = &sio->chan[ch];
+
+ chan->status[0] = SIO_RR0_TX_BUFFER_EMPTY;
+ chan->status[1] = 0x00;
+ chan->status[2] = 0x00;
+ chan->int_on_next_rx = 0;
+ chan->outbuf = -1;
+
+ sio->int_state[0 + 4*ch] = 0;
+ sio->int_state[1 + 4*ch] = 0;
+ sio->int_state[2 + 4*ch] = 0;
+ sio->int_state[3 + 4*ch] = 0;
+
+ interrupt_check(sio);
+
+ /* start the receive timer running */
+ timer_adjust(chan->receive_timer, tpc, ((sio - sios) << 1) | ch, tpc);
+}
+
+
+/*-------------------------------------------------
+ z80sio_reset - reset a single SIO chip
+-------------------------------------------------*/
+
+void z80sio_reset(int which)
+{
+ z80sio *sio = sios + which;
+ int ch;
+
+ assert(which < MAX_SIO);
+
+ /* loop over channels */
+ for (ch = 0; ch < 2; ch++)
+ reset_channel(sio, ch);
+}
+
+
+
+/***************************************************************************
+ CONTROL REGISTER READ/WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+ z80sio_c_w - write to a control register
+-------------------------------------------------*/
+
+void z80sio_c_w(int which, int ch, UINT8 data)
+{
+ z80sio *sio = sios + which;
+ sio_channel *chan = &sio->chan[ch];
+ int reg = chan->regs[0] & 7;
+ UINT8 old = chan->regs[reg];
+
+ if (reg != 0 || (reg & 0xf8))
+ VPRINTF(("%04X:sio_reg_w(%c,%d) = %02X\n", activecpu_get_pc(), 'A' + ch, reg, data));
+
+ /* write a new value to the selected register */
+ chan->regs[reg] = data;
+
+ /* clear the register number for the next write */
+ if (reg != 0)
+ chan->regs[0] &= ~7;
+
+ /* switch off the register for live state changes */
+ switch (reg)
+ {
+ /* SIO write register 0 */
+ case 0:
+ switch (data & SIO_WR0_COMMAND_MASK)
+ {
+ case SIO_WR0_COMMAND_CH_RESET:
+ VPRINTF(("%04X:SIO reset channel %c\n", activecpu_get_pc(), 'A' + ch));
+ reset_channel(sio, ch);
+ break;
+
+ case SIO_WR0_COMMAND_RES_STATUS_INT:
+ sio->int_state[INT_CHA_STATUS - 4*ch] &= ~Z80_DAISY_INT;
+ interrupt_check(sio);
+ break;
+
+ case SIO_WR0_COMMAND_ENA_RX_INT:
+ chan->int_on_next_rx = TRUE;
+ interrupt_check(sio);
+ break;
+
+ case SIO_WR0_COMMAND_RES_TX_INT:
+ sio->int_state[INT_CHA_TRANSMIT - 4*ch] &= ~Z80_DAISY_INT;
+ interrupt_check(sio);
+ break;
+
+ case SIO_WR0_COMMAND_RES_ERROR:
+ sio->int_state[INT_CHA_ERROR - 4*ch] &= ~Z80_DAISY_INT;
+ interrupt_check(sio);
+ break;
+ }
+ break;
+
+ /* SIO write register 1 */
+ case 1:
+ interrupt_check(sio);
+ break;
+
+ /* SIO write register 5 */
+ case 5:
+ if (((old ^ data) & SIO_WR5_DTR) && sio->dtr_changed_cb)
+ (*sio->dtr_changed_cb)(ch, (data & SIO_WR5_DTR) != 0);
+ if (((old ^ data) & SIO_WR5_SEND_BREAK) && sio->break_changed_cb)
+ (*sio->break_changed_cb)(ch, (data & SIO_WR5_SEND_BREAK) != 0);
+ if (((old ^ data) & SIO_WR5_RTS) && sio->rts_changed_cb)
+ (*sio->rts_changed_cb)(ch, (data & SIO_WR5_RTS) != 0);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ z80sio_c_r - read from a control register
+-------------------------------------------------*/
+
+UINT8 z80sio_c_r(int which, int ch)
+{
+ z80sio *sio = sios + which;
+ sio_channel *chan = &sio->chan[ch];
+ int reg = chan->regs[0] & 7;
+ UINT8 result = chan->status[reg];
+
+ /* switch off the register for live state changes */
+ switch (reg)
+ {
+ /* SIO read register 0 */
+ case 0:
+ result &= ~SIO_RR0_INT_PENDING;
+ if (z80sio_irq_state(which) & Z80_DAISY_INT)
+ result |= SIO_RR0_INT_PENDING;
+ break;
+ }
+
+ VPRINTF(("%04X:sio_reg_r(%c,%d) = %02x\n", activecpu_get_pc(), 'A' + ch, reg, chan->status[reg]));
+
+ return chan->status[reg];
+}
+
+
+
+
+/***************************************************************************
+ DATA REGISTER READ/WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+ z80sio_d_w - write to a data register
+-------------------------------------------------*/
+
+void z80sio_d_w(int which, int ch, UINT8 data)
+{
+ z80sio *sio = sios + which;
+ sio_channel *chan = &sio->chan[ch];
+
+ VPRINTF(("%04X:sio_data_w(%c) = %02X\n", activecpu_get_pc(), 'A' + ch, data));
+
+ /* if tx not enabled, just ignore it */
+ if (!(chan->regs[5] & SIO_WR5_TX_ENABLE))
+ return;
+
+ /* update the status register */
+ chan->status[0] &= ~SIO_RR0_TX_BUFFER_EMPTY;
+
+ /* reset the transmit interrupt */
+ sio->int_state[INT_CHA_TRANSMIT - 4*ch] &= ~Z80_DAISY_INT;
+ interrupt_check(sio);
+
+ /* stash the character */
+ chan->outbuf = data;
+}
+
+
+/*-------------------------------------------------
+ z80sio_d_r - read from a data register
+-------------------------------------------------*/
+
+UINT8 z80sio_d_r(int which, int ch)
+{
+ z80sio *sio = sios + which;
+ sio_channel *chan = &sio->chan[ch];
+
+ /* update the status register */
+ chan->status[0] &= ~SIO_RR0_RX_CHAR_AVAILABLE;
+
+ /* reset the receive interrupt */
+ sio->int_state[INT_CHA_RECEIVE - 4*ch] &= ~Z80_DAISY_INT;
+ interrupt_check(sio);
+
+ VPRINTF(("%04X:sio_data_r(%c) = %02X\n", activecpu_get_pc(), 'A' + ch, chan->inbuf));
+
+ return chan->inbuf;
+}
+
+
+
+/***************************************************************************
+ CONTROL LINE READ/WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+ z80sio_get_dtr - return the state of the DTR
+ line
+-------------------------------------------------*/
+
+int z80sio_get_dtr(int which, int ch)
+{
+ z80sio *sio = sios + which;
+ sio_channel *chan = &sio->chan[ch];
+ return ((chan->regs[5] & SIO_WR5_DTR) != 0);
+}
+
+
+/*-------------------------------------------------
+ z80sio_get_rts - return the state of the RTS
+ line
+-------------------------------------------------*/
+
+int z80sio_get_rts(int which, int ch)
+{
+ z80sio *sio = sios + which;
+ sio_channel *chan = &sio->chan[ch];
+ return ((chan->regs[5] & SIO_WR5_RTS) != 0);
+}
+
+
+/*-------------------------------------------------
+ z80sio_set_cts - set the state of the CTS
+ line
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( change_input_line )
+{
+ z80sio *sio = sios + ((param >> 1) & 0x3f);
+ sio_channel *chan = &sio->chan[param & 1];
+ UINT8 line = (param >> 8) & 0xff;
+ int state = (param >> 7) & 1;
+ int ch = param & 1;
+ UINT8 old;
+
+ VPRINTF(("sio_change_input_line(%c, %s) = %d\n", 'A' + ch, (line == SIO_RR0_CTS) ? "CTS" : "DCD", state));
+
+ /* remember the old value */
+ old = chan->status[0];
+
+ /* set the bit in the status register */
+ chan->status[0] &= ~line;
+ if (state)
+ chan->status[0] |= line;
+
+ /* if state change interrupts are enabled, signal */
+ if (((old ^ chan->status[0]) & line) && (chan->regs[1] & SIO_WR1_STATUSINT_ENABLE))
+ {
+ sio->int_state[INT_CHA_STATUS - 4*ch] |= Z80_DAISY_INT;
+ interrupt_check(sio);
+ }
+}
+
+
+/*-------------------------------------------------
+ z80sio_set_cts - set the state of the CTS
+ line
+-------------------------------------------------*/
+
+void z80sio_set_cts(int which, int ch, int state)
+{
+ /* operate deferred */
+ timer_call_after_resynch((SIO_RR0_CTS << 8) + (state != 0) * 0x80 + which * 2 + ch, change_input_line);
+}
+
+
+/*-------------------------------------------------
+ z80sio_set_dcd - set the state of the DCD
+ line
+-------------------------------------------------*/
+
+void z80sio_set_dcd(int which, int ch, int state)
+{
+ /* operate deferred */
+ timer_call_after_resynch((SIO_RR0_DCD << 8) + (state != 0) * 0x80 + which * 2 + ch, change_input_line);
+}
+
+
+/*-------------------------------------------------
+ z80sio_receive_data - receive data on the
+ input lines
+-------------------------------------------------*/
+
+void z80sio_receive_data(int which, int ch, UINT8 data)
+{
+ z80sio *sio = sios + which;
+ sio_channel *chan = &sio->chan[ch];
+ int newinptr;
+
+ /* put it on the queue */
+ newinptr = (chan->receive_inptr + 1) % ARRAY_LENGTH(chan->receive_buffer);
+ if (newinptr != chan->receive_outptr)
+ {
+ chan->receive_buffer[chan->receive_inptr] = data;
+ chan->receive_inptr = newinptr;
+ }
+ else
+ logerror("z80sio_receive_data: buffer overrun\n");
+}
+
+
+/*-------------------------------------------------
+ serial_callback - callback to pump
+ data through
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( serial_callback )
+{
+ z80sio *sio = sios + (param >> 1);
+ sio_channel *chan = &sio->chan[param & 1];
+ int ch = param & 1;
+ int data = -1;
+
+ /* first perform any outstanding transmits */
+ if (chan->outbuf != -1)
+ {
+ VPRINTF(("serial_callback(%c): Transmitting %02x\n", 'A' + ch, chan->outbuf));
+
+ /* actually transmit the character */
+ if (sio->transmit_cb != NULL)
+ (*sio->transmit_cb)(ch, chan->outbuf);
+
+ /* update the status register */
+ chan->status[0] |= SIO_RR0_TX_BUFFER_EMPTY;
+
+ /* set the transmit buffer empty interrupt if enabled */
+ if (chan->regs[1] & SIO_WR1_TXINT_ENABLE)
+ {
+ sio->int_state[INT_CHA_TRANSMIT - 4*ch] |= Z80_DAISY_INT;
+ interrupt_check(sio);
+ }
+
+ /* reset the output buffer */
+ chan->outbuf = -1;
+ }
+
+ /* ask the polling callback if there is data to receive */
+ if (sio->receive_poll_cb != NULL)
+ data = (*sio->receive_poll_cb)(ch);
+
+ /* if we have buffered data, pull it */
+ if (chan->receive_inptr != chan->receive_outptr)
+ {
+ data = chan->receive_buffer[chan->receive_outptr];
+ chan->receive_outptr = (chan->receive_outptr + 1) % ARRAY_LENGTH(chan->receive_buffer);
+ }
+
+ /* if we have data, receive it */
+ if (data != -1)
+ {
+ VPRINTF(("serial_callback(%c): Receiving %02x\n", 'A' + ch, data));
+
+ /* if rx not enabled, just ignore it */
+ if (!(chan->regs[3] & SIO_WR3_RX_ENABLE))
+ {
+ VPRINTF((" (ignored because receive is disabled)\n"));
+ return;
+ }
+
+ /* stash the data and update the status */
+ chan->inbuf = data;
+ chan->status[0] |= SIO_RR0_RX_CHAR_AVAILABLE;
+
+ /* update our interrupt state */
+ switch (chan->regs[1] & SIO_WR1_RXINT_MASK)
+ {
+ case SIO_WR1_RXINT_FIRST:
+ if (!chan->int_on_next_rx)
+ break;
+
+ case SIO_WR1_RXINT_ALL_NOPARITY:
+ case SIO_WR1_RXINT_ALL_PARITY:
+ sio->int_state[INT_CHA_RECEIVE - 4*ch] |= Z80_DAISY_INT;
+ interrupt_check(sio);
+ break;
+ }
+ chan->int_on_next_rx = FALSE;
+ }
+}
+
+
+
+/***************************************************************************
+ DAISY CHAIN INTERFACE
+***************************************************************************/
+
+static const UINT8 int_priority[] =
+{
+ INT_CHA_RECEIVE,
+ INT_CHA_TRANSMIT,
+ INT_CHA_STATUS,
+ INT_CHA_ERROR,
+ INT_CHB_RECEIVE,
+ INT_CHB_TRANSMIT,
+ INT_CHB_STATUS,
+ INT_CHB_ERROR
+};
+
+
+int z80sio_irq_state(int which)
+{
+ z80sio *sio = sios + which;
+ int state = 0;
+ int i;
+
+ VPRINTF(("sio IRQ state = B:%d%d%d%d A:%d%d%d%d\n",
+ sio->int_state[0], sio->int_state[1], sio->int_state[2], sio->int_state[3],
+ sio->int_state[4], sio->int_state[5], sio->int_state[6], sio->int_state[7]));
+
+ /* loop over all interrupt sources */
+ for (i = 0; i < 8; i++)
+ {
+ int inum = int_priority[i];
+
+ /* if we're servicing a request, don't indicate more interrupts */
+ if (sio->int_state[inum] & Z80_DAISY_IEO)
+ {
+ state |= Z80_DAISY_IEO;
+ break;
+ }
+ state |= sio->int_state[inum];
+ }
+
+ return state;
+}
+
+
+int z80sio_irq_ack(int which)
+{
+ z80sio *sio = sios + which;
+ int i;
+
+ /* loop over all interrupt sources */
+ for (i = 0; i < 8; i++)
+ {
+ int inum = int_priority[i];
+
+ /* find the first channel with an interrupt requested */
+ if (sio->int_state[inum] & Z80_DAISY_INT)
+ {
+ VPRINTF(("sio IRQAck %d\n", inum));
+
+ /* clear interrupt, switch to the IEO state, and update the IRQs */
+ sio->int_state[inum] = Z80_DAISY_IEO;
+ interrupt_check(sio);
+ return sio->chan[1].regs[2] + inum * 2;
+ }
+ }
+
+ logerror("z80sio_irq_ack: failed to find an interrupt to ack!\n");
+ return sio->chan[1].regs[2];
+}
+
+
+void z80sio_irq_reti(int which)
+{
+ z80sio *sio = sios + which;
+ int i;
+
+ /* loop over all interrupt sources */
+ for (i = 0; i < 8; i++)
+ {
+ int inum = int_priority[i];
+
+ /* find the first channel with an IEO pending */
+ if (sio->int_state[inum] & Z80_DAISY_IEO)
+ {
+ VPRINTF(("sio IRQReti %d\n", inum));
+
+ /* clear the IEO state and update the IRQs */
+ sio->int_state[inum] &= ~Z80_DAISY_IEO;
+ interrupt_check(sio);
+ return;
+ }
+ }
+
+ logerror("z80sio_irq_reti: failed to find an interrupt to clear IEO on!\n");
+}
diff --git a/src/emu/machine/z80sio.h b/src/emu/machine/z80sio.h
new file mode 100644
index 00000000000..f30a13d178d
--- /dev/null
+++ b/src/emu/machine/z80sio.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+
+ Z80 SIO (Z8440) implementation
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_SIO 2
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _z80sio_interface z80sio_interface;
+struct _z80sio_interface
+{
+ int baseclock;
+ void (*irq_cb)(int state);
+ write8_handler dtr_changed_cb;
+ write8_handler rts_changed_cb;
+ write8_handler break_changed_cb;
+ write8_handler transmit_cb;
+ int (*receive_poll_cb)(int which);
+};
+
+
+
+/***************************************************************************
+ INITIALIZATION/CONFIGURATION
+***************************************************************************/
+
+void z80sio_init(int which, z80sio_interface *intf);
+void z80sio_reset(int which);
+
+
+
+/***************************************************************************
+ CONTROL REGISTER READ/WRITE
+***************************************************************************/
+
+void z80sio_c_w(int which, int ch, UINT8 data);
+UINT8 z80sio_c_r(int which, int ch);
+
+
+
+/***************************************************************************
+ DATA REGISTER READ/WRITE
+***************************************************************************/
+
+void z80sio_d_w(int which, int ch, UINT8 data);
+UINT8 z80sio_d_r(int which, int ch);
+
+
+
+/***************************************************************************
+ CONTROL LINE READ/WRITE
+***************************************************************************/
+
+int z80sio_get_dtr(int which, int ch);
+int z80sio_get_rts(int which, int ch);
+void z80sio_set_cts(int which, int ch, int state);
+void z80sio_set_dcd(int which, int ch, int state);
+void z80sio_receive_data(int which, int ch, UINT8 data);
+
+
+
+/***************************************************************************
+ DAISY CHAIN INTERFACE
+***************************************************************************/
+
+int z80sio_irq_state(int which);
+int z80sio_irq_ack(int which);
+void z80sio_irq_reti(int which);
diff --git a/src/emu/mame.c b/src/emu/mame.c
new file mode 100644
index 00000000000..bed4dd9ba96
--- /dev/null
+++ b/src/emu/mame.c
@@ -0,0 +1,1889 @@
+/***************************************************************************
+
+ mame.c
+
+ Controls execution of the core MAME system.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Since there has been confusion in the past over the order of
+ initialization and other such things, here it is, all spelled out
+ as of February, 2006:
+
+ main()
+ - does platform-specific init
+ - calls run_game() [mame.c]
+
+ run_game() [mame.c]
+ - calls mame_validitychecks() [validity.c] to perform validity checks on all compiled drivers
+ - calls setjmp to prepare for deep error handling
+ - begins resource tracking (level 1)
+ - calls create_machine [mame.c] to initialize the Machine structure
+ - calls init_machine() [mame.c]
+
+ init_machine() [mame.c]
+ - calls cpuintrf_init() [cpuintrf.c] to determine which CPUs are available
+ - calls sndintrf_init() [sndintrf.c] to determine which sound chips are available
+ - calls fileio_init() [fileio.c] to initialize file I/O info
+ - calls config_init() [config.c] to initialize configuration system
+ - calls output_init() [output.c] to initialize the output system
+ - calls state_init() [state.c] to initialize save state system
+ - calls state_save_allow_registration() [state.c] to allow registrations
+ - calls drawgfx_init() [drawgfx.c] to initialize rendering globals
+ - calls palette_init() [palette.c] to initialize palette system
+ - calls render_init() [render.c] to initialize the rendering system
+ - calls ui_init() [ui.c] to initialize the user interface
+ - calls generic_machine_init() [machine/generic.c] to initialize generic machine structures
+ - calls generic_video_init() [video/generic.c] to initialize generic video structures
+ - calls generic_sound_init() [audio/generic.c] to initialize generic sound structures
+ - calls timer_init() [timer.c] to reset the timer system
+ - calls osd_init() [osdepend.h] to do platform-specific initialization
+ - calls code_init() [input.c] to initialize the input system
+ - calls input_port_init() [inptport.c] to set up the input ports
+ - calls rom_init() [romload.c] to load the game's ROMs
+ - calls memory_init() [memory.c] to process the game's memory maps
+ - calls cpuexec_init() [cpuexec.c] to initialize the CPUs
+ - calls cpuint_init() [cpuint.c] to initialize the CPU interrupts
+ - calls the driver's DRIVER_INIT callback
+ - calls video_init() [video.c] to start the video system
+ - calls sound_init() [sound.c] to start the audio system
+ - calls the driver's MACHINE_START, SOUND_START, and VIDEO_START callbacks
+ - disposes of regions marked as disposable
+ - calls saveload_init() [mame.c] to set up for save/load
+ - calls cheat_init() [cheat.c] to initialize the cheat system
+ - calls mame_debug_init() [debugcpu.c] to set up the debugger
+
+ - calls config_load_settings() [config.c] to load the configuration file
+ - calls nvram_load [machine/generic.c] to load NVRAM
+ - calls ui_init() [ui.c] to initialize the user interface
+ - begins resource tracking (level 2)
+ - calls soft_reset() [mame.c] to reset all systems
+
+ -------------------( at this point, we're up and running )----------------------
+
+ - calls cpuexec_timeslice() [cpuexec.c] over and over until we exit
+ - ends resource tracking (level 2), freeing all auto_mallocs and timers
+ - calls the nvram_save() [machine/generic.c] to save NVRAM
+ - calls config_save_settings() [config.c] to save the game's configuration
+ - calls all registered exit routines [mame.c]
+ - ends resource tracking (level 1), freeing all auto_mallocs and timers
+
+ - exits the program
+
+***************************************************************************/
+
+#include "osdepend.h"
+#include "driver.h"
+#include "config.h"
+#include "cheat.h"
+#include "debugger.h"
+#include "profiler.h"
+#include "render.h"
+#include "ui.h"
+#include "uimenu.h"
+
+#ifdef MAME_DEBUG
+#include "debug/debugcon.h"
+#endif
+
+#include <stdarg.h>
+#include <setjmp.h>
+#include <time.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_MEMORY_REGIONS 32
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _region_info region_info;
+struct _region_info
+{
+ UINT8 * base;
+ UINT32 length;
+ UINT32 type;
+ UINT32 flags;
+};
+
+
+typedef struct _callback_item callback_item;
+struct _callback_item
+{
+ callback_item * next;
+ union
+ {
+ void (*exit)(running_machine *);
+ void (*reset)(running_machine *);
+ void (*frame)(running_machine *);
+ void (*pause)(running_machine *, int);
+ void (*log)(running_machine *, const char *);
+ } func;
+};
+
+
+/* typedef struct _mame_private mame_private; */
+struct _mame_private
+{
+ /* system state */
+ int current_phase;
+ UINT8 paused;
+ UINT8 hard_reset_pending;
+ UINT8 exit_pending;
+ const game_driver *new_driver_pending;
+ astring * saveload_pending_file;
+ emu_timer * soft_reset_timer;
+ mame_file * logfile;
+
+ /* callbacks */
+ callback_item * frame_callback_list;
+ callback_item * reset_callback_list;
+ callback_item * pause_callback_list;
+ callback_item * exit_callback_list;
+ callback_item * logerror_callback_list;
+
+ /* load/save */
+ void (*saveload_schedule_callback)(running_machine *);
+ attotime saveload_schedule_time;
+
+ /* array of memory regions */
+ region_info mem_region[MAX_MEMORY_REGIONS];
+
+ /* error recovery and exiting */
+ jmp_buf fatal_error_jmpbuf;
+ int fatal_error_jmpbuf_valid;
+
+ /* random number seed */
+ UINT32 rand_seed;
+
+ /* base time */
+ time_t base_time;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* the active machine */
+running_machine *Machine;
+
+/* the current options */
+static core_options *mame_opts;
+
+/* started empty? */
+static UINT8 started_empty;
+
+/* output channels */
+static output_callback output_cb[OUTPUT_CHANNEL_COUNT];
+static void *output_cb_param[OUTPUT_CHANNEL_COUNT];
+
+/* the "disclaimer" that should be printed when run with no parameters */
+const char *mame_disclaimer =
+ "MAME is an emulator: it reproduces, more or less faithfully, the behaviour of\n"
+ "several arcade machines. But hardware is useless without software, so an image\n"
+ "of the ROMs which run on that hardware is required. Such ROMs, like any other\n"
+ "commercial software, are copyrighted material and it is therefore illegal to\n"
+ "use them if you don't own the original arcade machine. Needless to say, ROMs\n"
+ "are not distributed together with MAME. Distribution of MAME together with ROM\n"
+ "images is a violation of copyright law and should be promptly reported to the\n"
+ "authors so that appropriate legal action can be taken.\n";
+
+const char *memory_region_names[REGION_MAX] =
+{
+ "REGION_INVALID",
+ "REGION_CPU1",
+ "REGION_CPU2",
+ "REGION_CPU3",
+ "REGION_CPU4",
+ "REGION_CPU5",
+ "REGION_CPU6",
+ "REGION_CPU7",
+ "REGION_CPU8",
+ "REGION_GFX1",
+ "REGION_GFX2",
+ "REGION_GFX3",
+ "REGION_GFX4",
+ "REGION_GFX5",
+ "REGION_GFX6",
+ "REGION_GFX7",
+ "REGION_GFX8",
+ "REGION_PROMS",
+ "REGION_SOUND1",
+ "REGION_SOUND2",
+ "REGION_SOUND3",
+ "REGION_SOUND4",
+ "REGION_SOUND5",
+ "REGION_SOUND6",
+ "REGION_SOUND7",
+ "REGION_SOUND8",
+ "REGION_USER1",
+ "REGION_USER2",
+ "REGION_USER3",
+ "REGION_USER4",
+ "REGION_USER5",
+ "REGION_USER6",
+ "REGION_USER7",
+ "REGION_USER8",
+ "REGION_USER9",
+ "REGION_USER10",
+ "REGION_USER11",
+ "REGION_USER12",
+ "REGION_USER13",
+ "REGION_USER14",
+ "REGION_USER15",
+ "REGION_USER16",
+ "REGION_USER17",
+ "REGION_USER18",
+ "REGION_USER19",
+ "REGION_USER20",
+ "REGION_DISKS",
+ "REGION_PLDS"
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+extern int mame_validitychecks(const game_driver *driver);
+
+static int parse_ini_file(core_options *options, const char *name);
+
+static running_machine *create_machine(const game_driver *driver);
+static void reset_machine(running_machine *machine);
+static void destroy_machine(running_machine *machine);
+static void init_machine(running_machine *machine);
+static TIMER_CALLBACK( soft_reset );
+static void free_callback_list(callback_item **cb);
+
+static void saveload_init(running_machine *machine);
+static void handle_save(running_machine *machine);
+static void handle_load(running_machine *machine);
+
+static void logfile_callback(running_machine *machine, const char *buffer);
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_execute - run the core emulation
+-------------------------------------------------*/
+
+int mame_execute(core_options *options)
+{
+ int exit_pending = FALSE;
+ int error = MAMERR_NONE;
+ int firstgame = TRUE;
+ int firstrun = TRUE;
+
+ /* loop across multiple hard resets */
+ while (error == MAMERR_NONE && !exit_pending)
+ {
+ const game_driver *driver;
+ running_machine *machine;
+ mame_private *mame;
+ callback_item *cb;
+ astring *gamename;
+
+ /* specify the mame_options */
+ mame_opts = options;
+
+ /* convert the specified gamename to a driver */
+ gamename = core_filename_extract_base(astring_alloc(), options_get_string(mame_options(), OPTION_GAMENAME), TRUE);
+ driver = driver_get_name(astring_c(gamename));
+ astring_free(gamename);
+
+ /* if no driver, use the internal empty driver */
+ if (driver == NULL)
+ {
+ driver = &driver_empty;
+ if (firstgame)
+ started_empty = TRUE;
+ }
+
+ /* otherwise, perform validity checks before anything else */
+ else if (mame_validitychecks(driver) != 0)
+ return MAMERR_FAILED_VALIDITY;
+ firstgame = FALSE;
+
+ /* parse any INI files as the first thing */
+ options_revert(mame_options(), OPTION_PRIORITY_INI);
+ mame_parse_ini_files(mame_options(), driver);
+
+ /* create the machine structure and driver */
+ machine = create_machine(driver);
+ reset_machine(machine);
+ mame = machine->mame_data;
+
+ /* start in the "pre-init phase" */
+ mame->current_phase = MAME_PHASE_PREINIT;
+
+ /* looooong term: remove this */
+ Machine = machine;
+
+ init_resource_tracking();
+
+ /* use setjmp/longjmp for deep error recovery */
+ mame->fatal_error_jmpbuf_valid = TRUE;
+ error = setjmp(mame->fatal_error_jmpbuf);
+ if (error == 0)
+ {
+ int settingsloaded;
+
+ /* move to the init phase */
+ mame->current_phase = MAME_PHASE_INIT;
+
+ /* start tracking resources for real */
+ begin_resource_tracking();
+
+ /* if we have a logfile, set up the callback */
+ mame->logerror_callback_list = NULL;
+ if (options_get_bool(mame_options(), OPTION_LOG))
+ {
+ file_error filerr = mame_fopen(SEARCHPATH_DEBUGLOG, "error.log", OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &mame->logfile);
+ assert_always(filerr == FILERR_NONE, "unable to open log file");
+ add_logerror_callback(machine, logfile_callback);
+ }
+
+ /* then finish setting up our local machine */
+ init_machine(machine);
+
+ /* load the configuration settings and NVRAM */
+ settingsloaded = config_load_settings();
+ nvram_load();
+
+ /* display the startup screens */
+ ui_display_startup_screens(firstrun, !settingsloaded);
+ firstrun = FALSE;
+
+ /* start resource tracking; note that soft_reset assumes it can */
+ /* call end_resource_tracking followed by begin_resource_tracking */
+ /* to clear out resources allocated between resets */
+ begin_resource_tracking();
+
+ /* perform a soft reset -- this takes us to the running phase */
+ soft_reset(machine, 0);
+
+ /* run the CPUs until a reset or exit */
+ mame->hard_reset_pending = FALSE;
+ while ((!mame->hard_reset_pending && !mame->exit_pending) || mame->saveload_pending_file != NULL)
+ {
+ profiler_mark(PROFILER_EXTRA);
+
+ /* execute CPUs if not paused */
+ if (!mame->paused)
+ cpuexec_timeslice();
+
+ /* otherwise, just pump video updates through */
+ else
+ video_frame_update();
+
+ /* handle save/load */
+ if (mame->saveload_schedule_callback)
+ (*mame->saveload_schedule_callback)(machine);
+
+ profiler_mark(PROFILER_END);
+ }
+
+ /* and out via the exit phase */
+ mame->current_phase = MAME_PHASE_EXIT;
+
+ /* stop tracking resources at this level */
+ end_resource_tracking();
+
+ /* save the NVRAM and configuration */
+ nvram_save();
+ config_save_settings();
+ }
+ mame->fatal_error_jmpbuf_valid = FALSE;
+
+ /* call all exit callbacks registered */
+ for (cb = mame->exit_callback_list; cb; cb = cb->next)
+ (*cb->func.exit)(machine);
+
+ /* close all inner resource tracking */
+ exit_resource_tracking();
+
+ /* close the logfile */
+ if (mame->logfile != NULL)
+ mame_fclose(mame->logfile);
+
+ /* free our callback lists */
+ free_callback_list(&mame->exit_callback_list);
+ free_callback_list(&mame->pause_callback_list);
+ free_callback_list(&mame->reset_callback_list);
+ free_callback_list(&mame->frame_callback_list);
+
+ /* grab data from the MAME structure before it goes away */
+ if (mame->new_driver_pending != NULL)
+ {
+ options_set_string(mame_options(), OPTION_GAMENAME, mame->new_driver_pending->name, OPTION_PRIORITY_CMDLINE);
+ firstrun = TRUE;
+ }
+ exit_pending = mame->exit_pending;
+
+ /* destroy the machine */
+ destroy_machine(machine);
+
+ /* reset the options */
+ mame_opts = NULL;
+ }
+
+ /* return an error */
+ return error;
+}
+
+
+/*-------------------------------------------------
+ mame_options - accesses the options for the
+ currently running emulation
+-------------------------------------------------*/
+
+core_options *mame_options(void)
+{
+ assert(mame_opts != NULL);
+ return mame_opts;
+}
+
+
+
+/*-------------------------------------------------
+ mame_get_phase - return the current program
+ phase
+-------------------------------------------------*/
+
+int mame_get_phase(running_machine *machine)
+{
+ mame_private *mame = machine->mame_data;
+ return mame->current_phase;
+}
+
+
+/*-------------------------------------------------
+ add_frame_callback - request a callback on
+ frame update
+-------------------------------------------------*/
+
+void add_frame_callback(running_machine *machine, void (*callback)(running_machine *))
+{
+ mame_private *mame = machine->mame_data;
+ callback_item *cb, **cur;
+
+ assert_always(mame_get_phase(machine) == MAME_PHASE_INIT, "Can only call add_frame_callback at init time!");
+
+ /* allocate memory */
+ cb = malloc_or_die(sizeof(*cb));
+
+ /* add us to the end of the list */
+ cb->func.frame = callback;
+ cb->next = NULL;
+ for (cur = &mame->frame_callback_list; *cur; cur = &(*cur)->next) ;
+ *cur = cb;
+}
+
+
+/*-------------------------------------------------
+ add_reset_callback - request a callback on
+ reset
+-------------------------------------------------*/
+
+void add_reset_callback(running_machine *machine, void (*callback)(running_machine *))
+{
+ mame_private *mame = machine->mame_data;
+ callback_item *cb, **cur;
+
+ assert_always(mame_get_phase(machine) == MAME_PHASE_INIT, "Can only call add_reset_callback at init time!");
+
+ /* allocate memory */
+ cb = malloc_or_die(sizeof(*cb));
+
+ /* add us to the end of the list */
+ cb->func.reset = callback;
+ cb->next = NULL;
+ for (cur = &mame->reset_callback_list; *cur; cur = &(*cur)->next) ;
+ *cur = cb;
+}
+
+
+/*-------------------------------------------------
+ add_pause_callback - request a callback on
+ pause
+-------------------------------------------------*/
+
+void add_pause_callback(running_machine *machine, void (*callback)(running_machine *, int))
+{
+ mame_private *mame = machine->mame_data;
+ callback_item *cb, **cur;
+
+ assert_always(mame_get_phase(machine) == MAME_PHASE_INIT, "Can only call add_pause_callback at init time!");
+
+ /* allocate memory */
+ cb = malloc_or_die(sizeof(*cb));
+
+ /* add us to the end of the list */
+ cb->func.pause = callback;
+ cb->next = NULL;
+ for (cur = &mame->pause_callback_list; *cur; cur = &(*cur)->next) ;
+ *cur = cb;
+}
+
+
+/*-------------------------------------------------
+ add_exit_callback - request a callback on
+ termination
+-------------------------------------------------*/
+
+void add_exit_callback(running_machine *machine, void (*callback)(running_machine *))
+{
+ mame_private *mame = machine->mame_data;
+ callback_item *cb;
+
+ assert_always(mame_get_phase(machine) == MAME_PHASE_INIT, "Can only call add_exit_callback at init time!");
+
+ /* allocate memory */
+ cb = malloc_or_die(sizeof(*cb));
+
+ /* add us to the head of the list */
+ cb->func.exit = callback;
+ cb->next = mame->exit_callback_list;
+ mame->exit_callback_list = cb;
+}
+
+
+/*-------------------------------------------------
+ mame_frame_update - handle update tasks for a
+ frame boundary
+-------------------------------------------------*/
+
+void mame_frame_update(running_machine *machine)
+{
+ callback_item *cb;
+
+ /* call all registered reset callbacks */
+ for (cb = machine->mame_data->frame_callback_list; cb; cb = cb->next)
+ (*cb->func.frame)(machine);
+}
+
+
+
+/***************************************************************************
+ GLOBAL SYSTEM STATES
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_schedule_exit - schedule a clean exit
+-------------------------------------------------*/
+
+void mame_schedule_exit(running_machine *machine)
+{
+ mame_private *mame = machine->mame_data;
+
+ /* if we are in-game but we started with the select game menu, return to that instead */
+ if (started_empty && options_get_string(mame_options(), OPTION_GAMENAME)[0] != 0)
+ {
+ options_set_string(mame_options(), OPTION_GAMENAME, "", OPTION_PRIORITY_CMDLINE);
+ ui_menu_force_game_select();
+ }
+
+ /* otherwise, exit for real */
+ else
+ mame->exit_pending = TRUE;
+
+ /* if we're executing, abort out immediately */
+ if (cpu_getactivecpu() >= 0)
+ activecpu_adjust_icount(-activecpu_get_icount() - 1);
+
+ /* if we're autosaving on exit, schedule a save as well */
+ if (options_get_bool(mame_options(), OPTION_AUTOSAVE) && (machine->gamedrv->flags & GAME_SUPPORTS_SAVE))
+ mame_schedule_save(machine, "auto");
+}
+
+
+/*-------------------------------------------------
+ mame_schedule_hard_reset - schedule a hard-
+ reset of the system
+-------------------------------------------------*/
+
+void mame_schedule_hard_reset(running_machine *machine)
+{
+ mame_private *mame = machine->mame_data;
+ mame->hard_reset_pending = TRUE;
+
+ /* if we're executing, abort out immediately */
+ if (cpu_getactivecpu() >= 0)
+ activecpu_adjust_icount(-activecpu_get_icount() - 1);
+}
+
+
+/*-------------------------------------------------
+ mame_schedule_soft_reset - schedule a soft-
+ reset of the system
+-------------------------------------------------*/
+
+void mame_schedule_soft_reset(running_machine *machine)
+{
+ mame_private *mame = machine->mame_data;
+
+ timer_adjust(mame->soft_reset_timer, attotime_zero, 0, attotime_zero);
+
+ /* we can't be paused since the timer needs to fire */
+ mame_pause(machine, FALSE);
+
+ /* if we're executing, abort out immediately */
+ if (cpu_getactivecpu() >= 0)
+ activecpu_adjust_icount(-activecpu_get_icount() - 1);
+}
+
+
+/*-------------------------------------------------
+ mame_schedule_new_driver - schedule a new game
+ to be loaded
+-------------------------------------------------*/
+
+void mame_schedule_new_driver(running_machine *machine, const game_driver *driver)
+{
+ mame_private *mame = machine->mame_data;
+ mame->hard_reset_pending = TRUE;
+ mame->new_driver_pending = driver;
+
+ /* if we're executing, abort out immediately */
+ if (cpu_getactivecpu() >= 0)
+ activecpu_adjust_icount(-activecpu_get_icount() - 1);
+}
+
+
+/*-------------------------------------------------
+ mame_schedule_save - schedule a save to
+ occur as soon as possible
+-------------------------------------------------*/
+
+void mame_schedule_save(running_machine *machine, const char *filename)
+{
+ mame_private *mame = machine->mame_data;
+
+ /* free any existing request and allocate a copy of the requested name */
+ if (mame->saveload_pending_file != NULL)
+ astring_free(mame->saveload_pending_file);
+ mame->saveload_pending_file = astring_assemble_4(astring_alloc(), machine->basename, PATH_SEPARATOR, filename, ".sta");
+
+ /* note the start time and set a timer for the next timeslice to actually schedule it */
+ mame->saveload_schedule_callback = handle_save;
+ mame->saveload_schedule_time = timer_get_time();
+
+ /* we can't be paused since we need to clear out anonymous timers */
+ mame_pause(machine, FALSE);
+}
+
+
+/*-------------------------------------------------
+ mame_schedule_load - schedule a load to
+ occur as soon as possible
+-------------------------------------------------*/
+
+void mame_schedule_load(running_machine *machine, const char *filename)
+{
+ mame_private *mame = machine->mame_data;
+
+ /* free any existing request and allocate a copy of the requested name */
+ if (mame->saveload_pending_file != NULL)
+ astring_free(mame->saveload_pending_file);
+ mame->saveload_pending_file = astring_assemble_4(astring_alloc(), machine->basename, PATH_SEPARATOR, filename, ".sta");
+
+ /* note the start time and set a timer for the next timeslice to actually schedule it */
+ mame->saveload_schedule_callback = handle_load;
+ mame->saveload_schedule_time = timer_get_time();
+
+ /* we can't be paused since we need to clear out anonymous timers */
+ mame_pause(machine, FALSE);
+}
+
+
+/*-------------------------------------------------
+ mame_is_scheduled_event_pending - is a
+ scheduled event pending?
+-------------------------------------------------*/
+
+int mame_is_scheduled_event_pending(running_machine *machine)
+{
+ /* we can't check for saveload_pending_file here because it will bypass */
+ /* required UI screens if a state is queued from the command line */
+ mame_private *mame = machine->mame_data;
+ return mame->exit_pending || mame->hard_reset_pending;
+}
+
+
+/*-------------------------------------------------
+ mame_pause - pause or resume the system
+-------------------------------------------------*/
+
+void mame_pause(running_machine *machine, int pause)
+{
+ mame_private *mame = machine->mame_data;
+ callback_item *cb;
+
+ /* ignore if nothing has changed */
+ if (mame->paused == pause)
+ return;
+ mame->paused = pause;
+
+ /* call all registered pause callbacks */
+ for (cb = mame->pause_callback_list; cb; cb = cb->next)
+ (*cb->func.pause)(machine, mame->paused);
+}
+
+
+/*-------------------------------------------------
+ mame_is_paused - the system paused?
+-------------------------------------------------*/
+
+int mame_is_paused(running_machine *machine)
+{
+ mame_private *mame = machine->mame_data;
+ return (mame->current_phase != MAME_PHASE_RUNNING) || mame->paused;
+}
+
+
+
+/***************************************************************************
+ MEMORY REGIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ memory_region_to_index - returns an index
+ given either an index or a REGION_* identifier
+-------------------------------------------------*/
+
+static int memory_region_to_index(mame_private *mame, int num)
+{
+ int i;
+
+ /* if we're already an index, stop there */
+ if (num < MAX_MEMORY_REGIONS)
+ return num;
+
+ /* scan for a match */
+ for (i = 0; i < MAX_MEMORY_REGIONS; i++)
+ if (mame->mem_region[i].type == num)
+ return i;
+
+ return -1;
+}
+
+
+/*-------------------------------------------------
+ new_memory_region - allocates memory for a
+ region
+-------------------------------------------------*/
+
+UINT8 *new_memory_region(running_machine *machine, int type, UINT32 length, UINT32 flags)
+{
+ mame_private *mame = machine->mame_data;
+ int num;
+
+ assert(type >= MAX_MEMORY_REGIONS);
+
+ /* find a free slot */
+ for (num = 0; num < MAX_MEMORY_REGIONS; num++)
+ if (mame->mem_region[num].base == NULL)
+ break;
+ if (num < 0)
+ fatalerror("Out of memory regions!");
+
+ /* allocate the region */
+ mame->mem_region[num].length = length;
+ mame->mem_region[num].type = type;
+ mame->mem_region[num].flags = flags;
+ mame->mem_region[num].base = malloc_or_die(length);
+ return mame->mem_region[num].base;
+}
+
+
+/*-------------------------------------------------
+ free_memory_region - releases memory for a
+ region
+-------------------------------------------------*/
+
+void free_memory_region(running_machine *machine, int num)
+{
+ mame_private *mame = machine->mame_data;
+
+ /* convert to an index and bail if invalid */
+ num = memory_region_to_index(mame, num);
+ if (num < 0)
+ return;
+
+ /* free the region in question */
+ free(mame->mem_region[num].base);
+ memset(&mame->mem_region[num], 0, sizeof(mame->mem_region[num]));
+}
+
+
+/*-------------------------------------------------
+ memory_region - returns pointer to a memory
+ region
+-------------------------------------------------*/
+
+UINT8 *memory_region(int num)
+{
+ running_machine *machine = Machine;
+ mame_private *mame = machine->mame_data;
+
+ /* convert to an index and return the result */
+ num = memory_region_to_index(mame, num);
+ return (num >= 0) ? mame->mem_region[num].base : NULL;
+}
+
+
+/*-------------------------------------------------
+ memory_region_length - returns length of a
+ memory region
+-------------------------------------------------*/
+
+UINT32 memory_region_length(int num)
+{
+ running_machine *machine = Machine;
+ mame_private *mame = machine->mame_data;
+
+ /* convert to an index and return the result */
+ num = memory_region_to_index(mame, num);
+ return (num >= 0) ? mame->mem_region[num].length : 0;
+}
+
+
+/*-------------------------------------------------
+ memory_region_type - returns the type of a
+ memory region
+-------------------------------------------------*/
+
+UINT32 memory_region_type(running_machine *machine, int num)
+{
+ mame_private *mame = machine->mame_data;
+
+ /* convert to an index and return the result */
+ num = memory_region_to_index(mame, num);
+ return (num >= 0) ? mame->mem_region[num].type : 0;
+}
+
+
+/*-------------------------------------------------
+ memory_region_flags - returns flags for a
+ memory region
+-------------------------------------------------*/
+
+UINT32 memory_region_flags(running_machine *machine, int num)
+{
+ mame_private *mame = machine->mame_data;
+
+ /* convert to an index and return the result */
+ num = memory_region_to_index(mame, num);
+ return (num >= 0) ? mame->mem_region[num].flags : 0;
+}
+
+
+
+/***************************************************************************
+ OUTPUT MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_set_output_channel - configure an output
+ channel
+-------------------------------------------------*/
+
+void mame_set_output_channel(output_channel channel, output_callback callback, void *param, output_callback *prevcb, void **prevparam)
+{
+ assert(channel < OUTPUT_CHANNEL_COUNT);
+ assert(callback != NULL);
+
+ /* return the originals if requested */
+ if (prevcb != NULL)
+ *prevcb = output_cb[channel];
+ if (prevparam != NULL)
+ *prevparam = output_cb_param[channel];
+
+ /* set the new ones */
+ output_cb[channel] = callback;
+ output_cb_param[channel] = param;
+}
+
+
+/*-------------------------------------------------
+ mame_file_output_callback - default callback
+ for file output
+-------------------------------------------------*/
+
+void mame_file_output_callback(void *param, const char *format, va_list argptr)
+{
+ vfprintf((FILE *)param, format, argptr);
+}
+
+
+/*-------------------------------------------------
+ mame_null_output_callback - default callback
+ for no output
+-------------------------------------------------*/
+
+void mame_null_output_callback(void *param, const char *format, va_list argptr)
+{
+}
+
+
+/*-------------------------------------------------
+ mame_printf_error - output an error to the
+ appropriate callback
+-------------------------------------------------*/
+
+void mame_printf_error(const char *format, ...)
+{
+ va_list argptr;
+
+ /* by default, we go to stderr */
+ if (output_cb[OUTPUT_CHANNEL_ERROR] == NULL)
+ {
+ output_cb[OUTPUT_CHANNEL_ERROR] = mame_file_output_callback;
+ output_cb_param[OUTPUT_CHANNEL_ERROR] = stderr;
+ }
+
+ /* do the output */
+ va_start(argptr, format);
+ (*output_cb[OUTPUT_CHANNEL_ERROR])(output_cb_param[OUTPUT_CHANNEL_ERROR], format, argptr);
+ va_end(argptr);
+}
+
+
+/*-------------------------------------------------
+ mame_printf_warning - output a warning to the
+ appropriate callback
+-------------------------------------------------*/
+
+void mame_printf_warning(const char *format, ...)
+{
+ va_list argptr;
+
+ /* by default, we go to stderr */
+ if (output_cb[OUTPUT_CHANNEL_WARNING] == NULL)
+ {
+ output_cb[OUTPUT_CHANNEL_WARNING] = mame_file_output_callback;
+ output_cb_param[OUTPUT_CHANNEL_WARNING] = stderr;
+ }
+
+ /* do the output */
+ va_start(argptr, format);
+ (*output_cb[OUTPUT_CHANNEL_WARNING])(output_cb_param[OUTPUT_CHANNEL_WARNING], format, argptr);
+ va_end(argptr);
+}
+
+
+/*-------------------------------------------------
+ mame_printf_info - output info text to the
+ appropriate callback
+-------------------------------------------------*/
+
+void mame_printf_info(const char *format, ...)
+{
+ va_list argptr;
+
+ /* by default, we go to stdout */
+ if (output_cb[OUTPUT_CHANNEL_INFO] == NULL)
+ {
+ output_cb[OUTPUT_CHANNEL_INFO] = mame_file_output_callback;
+ output_cb_param[OUTPUT_CHANNEL_INFO] = stdout;
+ }
+
+ /* do the output */
+ va_start(argptr, format);
+ (*output_cb[OUTPUT_CHANNEL_INFO])(output_cb_param[OUTPUT_CHANNEL_INFO], format, argptr);
+ va_end(argptr);
+}
+
+
+/*-------------------------------------------------
+ mame_printf_verbose - output verbose text to
+ the appropriate callback
+-------------------------------------------------*/
+
+void mame_printf_verbose(const char *format, ...)
+{
+ va_list argptr;
+
+ /* if we're not verbose, skip it */
+ if (mame_opts == NULL || !options_get_bool(mame_options(), OPTION_VERBOSE))
+ return;
+
+ /* by default, we go to stdout */
+ if (output_cb[OUTPUT_CHANNEL_VERBOSE] == NULL)
+ {
+ output_cb[OUTPUT_CHANNEL_VERBOSE] = mame_file_output_callback;
+ output_cb_param[OUTPUT_CHANNEL_VERBOSE] = stdout;
+ }
+
+ /* do the output */
+ va_start(argptr, format);
+ (*output_cb[OUTPUT_CHANNEL_VERBOSE])(output_cb_param[OUTPUT_CHANNEL_VERBOSE], format, argptr);
+ va_end(argptr);
+}
+
+
+/*-------------------------------------------------
+ mame_printf_debug - output debug text to the
+ appropriate callback
+-------------------------------------------------*/
+
+void mame_printf_debug(const char *format, ...)
+{
+ va_list argptr;
+
+ /* by default, we go to stderr */
+ if (output_cb[OUTPUT_CHANNEL_DEBUG] == NULL)
+ {
+#ifdef MAME_DEBUG
+ output_cb[OUTPUT_CHANNEL_DEBUG] = mame_file_output_callback;
+ output_cb_param[OUTPUT_CHANNEL_DEBUG] = stdout;
+#else
+ output_cb[OUTPUT_CHANNEL_DEBUG] = mame_null_output_callback;
+ output_cb_param[OUTPUT_CHANNEL_DEBUG] = NULL;
+#endif
+ }
+
+ /* do the output */
+ va_start(argptr, format);
+ (*output_cb[OUTPUT_CHANNEL_DEBUG])(output_cb_param[OUTPUT_CHANNEL_DEBUG], format, argptr);
+ va_end(argptr);
+}
+
+
+/*-------------------------------------------------
+ mame_printf_log - output log text to the
+ appropriate callback
+-------------------------------------------------*/
+
+void mame_printf_log(const char *format, ...)
+{
+ va_list argptr;
+
+ /* by default, we go to stderr */
+ if (output_cb[OUTPUT_CHANNEL_LOG] == NULL)
+ {
+ output_cb[OUTPUT_CHANNEL_LOG] = mame_file_output_callback;
+ output_cb_param[OUTPUT_CHANNEL_LOG] = stderr;
+ }
+
+ /* do the output */
+ va_start(argptr, format);
+ (*output_cb[OUTPUT_CHANNEL_LOG])(output_cb_param[OUTPUT_CHANNEL_LOG], format, argptr);
+ va_end(argptr);
+}
+
+
+
+/***************************************************************************
+ MISCELLANEOUS
+***************************************************************************/
+
+/*-------------------------------------------------
+ fatalerror - print a message and escape back
+ to the OSD layer
+-------------------------------------------------*/
+
+DECL_NORETURN static void fatalerror_common(running_machine *machine, int exitcode, const char *buffer) ATTR_NORETURN;
+
+static void fatalerror_common(running_machine *machine, int exitcode, const char *buffer)
+{
+ /* output and return */
+ mame_printf_error("%s\n", giant_string_buffer);
+
+ /* break into the debugger if attached */
+ osd_break_into_debugger(giant_string_buffer);
+
+ /* longjmp back if we can; otherwise, exit */
+ if (machine != NULL && machine->mame_data != NULL && machine->mame_data->fatal_error_jmpbuf_valid)
+ longjmp(machine->mame_data->fatal_error_jmpbuf, exitcode);
+ else
+ exit(exitcode);
+}
+
+
+void CLIB_DECL fatalerror(const char *text, ...)
+{
+ running_machine *machine = Machine;
+ va_list arg;
+
+ /* dump to the buffer; assume no one writes >2k lines this way */
+ va_start(arg, text);
+ vsnprintf(giant_string_buffer, GIANT_STRING_BUFFER_SIZE, text, arg);
+ va_end(arg);
+
+ fatalerror_common(machine, MAMERR_FATALERROR, giant_string_buffer);
+}
+
+
+void CLIB_DECL fatalerror_exitcode(int exitcode, const char *text, ...)
+{
+ running_machine *machine = Machine;
+ va_list arg;
+
+ /* dump to the buffer; assume no one writes >2k lines this way */
+ va_start(arg, text);
+ vsnprintf(giant_string_buffer, GIANT_STRING_BUFFER_SIZE, text, arg);
+ va_end(arg);
+
+ fatalerror_common(machine, exitcode, giant_string_buffer);
+}
+
+
+/*-------------------------------------------------
+ popmessage - pop up a user-visible message
+-------------------------------------------------*/
+
+void CLIB_DECL popmessage(const char *text, ...)
+{
+ extern void CLIB_DECL ui_popup(const char *text, ...) ATTR_PRINTF(1,2);
+ va_list arg;
+
+ /* dump to the buffer */
+ va_start(arg, text);
+ vsnprintf(giant_string_buffer, GIANT_STRING_BUFFER_SIZE, text, arg);
+ va_end(arg);
+
+ /* pop it in the UI */
+ ui_popup("%s", giant_string_buffer);
+}
+
+
+/*-------------------------------------------------
+ logerror - log to the debugger and any other
+ OSD-defined output streams
+-------------------------------------------------*/
+
+void CLIB_DECL logerror(const char *text, ...)
+{
+ running_machine *machine = Machine;
+
+ /* currently, we need a machine to do this */
+ if (machine != NULL)
+ {
+ mame_private *mame = machine->mame_data;
+ callback_item *cb;
+
+ /* process only if there is a target */
+ if (mame->logerror_callback_list != NULL)
+ {
+ va_list arg;
+
+ profiler_mark(PROFILER_LOGERROR);
+
+ /* dump to the buffer */
+ va_start(arg, text);
+ vsnprintf(giant_string_buffer, GIANT_STRING_BUFFER_SIZE, text, arg);
+ va_end(arg);
+
+ /* log to all callbacks */
+ for (cb = mame->logerror_callback_list; cb; cb = cb->next)
+ (*cb->func.log)(machine, giant_string_buffer);
+
+ profiler_mark(PROFILER_END);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ add_logerror_callback - adds a callback to be
+ called on logerror()
+-------------------------------------------------*/
+
+void add_logerror_callback(running_machine *machine, void (*callback)(running_machine *, const char *))
+{
+ mame_private *mame = machine->mame_data;
+ callback_item *cb, **cur;
+
+ assert_always(mame_get_phase(machine) == MAME_PHASE_INIT, "Can only call add_logerror_callback at init time!");
+
+ cb = auto_malloc(sizeof(*cb));
+ cb->func.log = callback;
+ cb->next = NULL;
+
+ for (cur = &mame->logerror_callback_list; *cur; cur = &(*cur)->next) ;
+ *cur = cb;
+}
+
+
+/*-------------------------------------------------
+ logfile_callback - callback for logging to
+ logfile
+-------------------------------------------------*/
+
+static void logfile_callback(running_machine *machine, const char *buffer)
+{
+ mame_private *mame = machine->mame_data;
+ if (mame->logfile != NULL)
+ mame_fputs(mame->logfile, buffer);
+}
+
+
+/*-------------------------------------------------
+ mame_find_cpu_index - return the index of the
+ given CPU, or -1 if not found
+-------------------------------------------------*/
+
+int mame_find_cpu_index(running_machine *machine, const char *tag)
+{
+ int cpunum;
+
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ if (machine->drv->cpu[cpunum].tag && strcmp(machine->drv->cpu[cpunum].tag, tag) == 0)
+ return cpunum;
+
+ return -1;
+}
+
+
+/*-------------------------------------------------
+ mame_rand - standardized random numbers
+-------------------------------------------------*/
+
+UINT32 mame_rand(running_machine *machine)
+{
+ mame_private *mame = machine->mame_data;
+ mame->rand_seed = 1664525 * mame->rand_seed + 1013904223;
+
+ /* return rotated by 16 bits; the low bits have a short period
+ and are frequently used */
+ return (mame->rand_seed >> 16) | (mame->rand_seed << 16);
+}
+
+
+
+/***************************************************************************
+ INTERNAL INITIALIZATION LOGIC
+***************************************************************************/
+
+/*-------------------------------------------------
+ mame_parse_ini_files - parse the relevant INI
+ files and apply their options
+-------------------------------------------------*/
+
+void mame_parse_ini_files(core_options *options, const game_driver *driver)
+{
+ /* parse the INI file defined by the platform (e.g., "mame.ini") */
+ /* we do this twice so that the first file can change the INI path */
+ parse_ini_file(options, CONFIGNAME);
+ parse_ini_file(options, CONFIGNAME);
+
+ /* debug builds: parse "debug.ini" as well */
+#ifdef MAME_DEBUG
+ parse_ini_file(options, "debug");
+#endif
+
+ /* if we have a valid game driver, parse game-specific INI files */
+ if (driver != NULL)
+ {
+ const game_driver *parent = driver_get_clone(driver);
+ const game_driver *gparent = (parent != NULL) ? driver_get_clone(parent) : NULL;
+ astring *sourcename;
+ machine_config drv;
+
+ /* expand the machine driver to look at the info */
+ expand_machine_driver(driver->drv, &drv);
+
+ /* parse "vector.ini" for vector games */
+ if (drv.video_attributes & VIDEO_TYPE_VECTOR)
+ parse_ini_file(options, "vector");
+
+ /* next parse "source/<sourcefile>.ini"; if that doesn't exist, try <sourcefile>.ini */
+ sourcename = core_filename_extract_base(astring_alloc(), driver->source_file, TRUE);
+ astring_insc(sourcename, 0, "source" PATH_SEPARATOR);
+ if (!parse_ini_file(options, astring_c(sourcename)))
+ {
+ core_filename_extract_base(sourcename, driver->source_file, TRUE);
+ parse_ini_file(options, astring_c(sourcename));
+ }
+ astring_free(sourcename);
+
+ /* then parent the grandparent, parent, and game-specific INIs */
+ if (gparent != NULL)
+ parse_ini_file(options, gparent->name);
+ if (parent != NULL)
+ parse_ini_file(options, parent->name);
+ parse_ini_file(options, driver->name);
+ }
+}
+
+
+/*-------------------------------------------------
+ parse_ini_file - parse a single INI file
+-------------------------------------------------*/
+
+static int parse_ini_file(core_options *options, const char *name)
+{
+ file_error filerr;
+ mame_file *file;
+ astring *fname;
+
+ /* don't parse if it has been disabled */
+ if (!options_get_bool(options, OPTION_READCONFIG))
+ return FALSE;
+
+ /* open the file; if we fail, that's ok */
+ fname = astring_assemble_2(astring_alloc(), name, ".ini");
+ filerr = mame_fopen_options(options, SEARCHPATH_INI, astring_c(fname), OPEN_FLAG_READ, &file);
+ astring_free(fname);
+ if (filerr != FILERR_NONE)
+ return FALSE;
+
+ /* parse the file and close it */
+ mame_printf_verbose("Parsing %s.ini\n", name);
+ options_parse_ini_file(options, mame_core_file(file), OPTION_PRIORITY_INI);
+ mame_fclose(file);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ create_machine - create the running machine
+ object and initialize it based on options
+-------------------------------------------------*/
+
+static running_machine *create_machine(const game_driver *driver)
+{
+ running_machine *machine;
+
+ /* allocate memory for the machine */
+ machine = malloc(sizeof(*machine));
+ if (machine == NULL)
+ goto error;
+ memset(machine, 0, sizeof(*machine));
+
+ /* allocate memory for the internal mame_data */
+ machine->mame_data = malloc(sizeof(*machine->mame_data));
+ if (machine->mame_data == NULL)
+ goto error;
+ memset(machine->mame_data, 0, sizeof(*machine->mame_data));
+
+ /* initialize the driver-related variables in the machine */
+ machine->gamedrv = driver;
+ machine->drv = malloc(sizeof(*machine->drv));
+ if (machine->drv == NULL)
+ goto error;
+ machine->basename = mame_strdup(machine->gamedrv->name);
+ expand_machine_driver(machine->gamedrv->drv, (machine_config *)machine->drv);
+
+ /* allocate the driver data */
+ if (machine->drv->driver_data_size != 0)
+ {
+ machine->driver_data = malloc(machine->drv->driver_data_size);
+ if (machine->driver_data == NULL)
+ goto error;
+ }
+ return machine;
+
+error:
+ if (machine->driver_data != NULL)
+ free(machine->driver_data);
+ if (machine->drv != NULL)
+ free((machine_config *)machine->drv);
+ if (machine->mame_data != NULL)
+ free(machine->mame_data);
+ if (machine != NULL)
+ free(machine);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ reset_machine - reset the state of the
+ machine object
+-------------------------------------------------*/
+
+static void reset_machine(running_machine *machine)
+{
+ int scrnum;
+
+ /* reset most portions of the machine */
+
+ /* video-related information */
+ memset(machine->gfx, 0, sizeof(machine->gfx));
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ machine->screen[scrnum] = machine->drv->screen[scrnum].defstate;
+
+ /* palette-related information */
+ machine->pens = NULL;
+ machine->game_colortable = NULL;
+ machine->remapped_colortable = NULL;
+ machine->shadow_table = NULL;
+
+ /* audio-related information */
+ machine->sample_rate = options_get_int(mame_options(), OPTION_SAMPLERATE);
+
+ /* input-related information */
+ machine->input_ports = NULL;
+ machine->record_file = NULL;
+ machine->playback_file = NULL;
+
+ /* debugger-related information */
+#ifdef MAME_DEBUG
+ machine->debug_mode = options_get_bool(mame_options(), OPTION_DEBUG);
+#else
+ machine->debug_mode = 0;
+#endif
+
+ /* reset the global MAME data and clear the other privates */
+ memset(machine->mame_data, 0, sizeof(*machine->mame_data));
+ machine->video_data = NULL;
+ machine->palette_data = NULL;
+ machine->streams_data = NULL;
+
+ /* reset the driver data */
+ if (machine->drv->driver_data_size != 0)
+ memset(machine->driver_data, 0, machine->drv->driver_data_size);
+}
+
+
+
+/*-------------------------------------------------
+ destroy_machine - free the machine data
+-------------------------------------------------*/
+
+static void destroy_machine(running_machine *machine)
+{
+ assert(machine == Machine);
+ if (machine->driver_data != NULL)
+ free(machine->driver_data);
+ if (machine->drv != NULL)
+ free((machine_config *)machine->drv);
+ if (machine->mame_data != NULL)
+ free(machine->mame_data);
+ if (machine->basename != NULL)
+ free((void *)machine->basename);
+ free(machine);
+ Machine = NULL;
+}
+
+
+/*-------------------------------------------------
+ init_machine - initialize the emulated machine
+-------------------------------------------------*/
+
+static void init_machine(running_machine *machine)
+{
+ mame_private *mame = machine->mame_data;
+ int num;
+
+ /* initialize basic can't-fail systems here */
+ cpuintrf_init(machine);
+ sndintrf_init(machine);
+ fileio_init(machine);
+ config_init(machine);
+ input_init(machine);
+ output_init(machine);
+ state_init(machine);
+ state_save_allow_registration(TRUE);
+ drawgfx_init(machine);
+ palette_init(machine);
+ render_init(machine);
+ ui_init(machine);
+ generic_machine_init(machine);
+ generic_video_init(machine);
+ generic_sound_init();
+ mame->rand_seed = 0x9d14abd7;
+
+ /* initialize the timers and allocate a soft_reset timer */
+ /* this must be done before cpu_init so that CPU's can allocate timers */
+ timer_init(machine);
+ mame->soft_reset_timer = timer_alloc(soft_reset);
+
+ /* init the osd layer */
+ osd_init(machine);
+
+ /* initialize the input system and input ports for the game */
+ /* this must be done before memory_init in order to allow specifying */
+ /* callbacks based on input port tags */
+ input_port_init(machine, machine->gamedrv->ipt);
+
+ /* initialize the base time (if not doing record/playback) */
+ if (machine->record_file == NULL && machine->playback_file == NULL)
+ time(&mame->base_time);
+ else
+ mame->base_time = 0;
+
+ /* first load ROMs, then populate memory, and finally initialize CPUs */
+ /* these operations must proceed in this order */
+ rom_init(machine, machine->gamedrv->rom);
+ memory_init(machine);
+ cpuexec_init(machine);
+ cpuint_init(machine);
+
+#ifdef MESS
+ /* initialize the devices */
+ devices_init(machine);
+#endif
+
+#ifdef MAME_DEBUG
+ /* initialize the debugger */
+ if (machine->debug_mode)
+ mame_debug_init(machine);
+#endif
+
+ /* call the game driver's init function */
+ /* this is where decryption is done and memory maps are altered */
+ /* so this location in the init order is important */
+ ui_set_startup_text("Initializing...", TRUE);
+ if (machine->gamedrv->driver_init != NULL)
+ (*machine->gamedrv->driver_init)(machine);
+
+ /* start the video and audio hardware */
+ video_init(machine);
+ sound_init(machine);
+
+ /* call the driver's _START callbacks */
+ if (machine->drv->machine_start != NULL) (*machine->drv->machine_start)(machine);
+ if (machine->drv->sound_start != NULL) (*machine->drv->sound_start)(machine);
+ if (machine->drv->video_start != NULL) (*machine->drv->video_start)(machine);
+
+ /* free memory regions allocated with REGIONFLAG_DISPOSE (typically gfx roms) */
+ for (num = 0; num < MAX_MEMORY_REGIONS; num++)
+ if (mame->mem_region[num].flags & ROMREGION_DISPOSE)
+ free_memory_region(machine, num);
+
+ /* initialize miscellaneous systems */
+ saveload_init(machine);
+ if (options_get_bool(mame_options(), OPTION_CHEAT))
+ cheat_init(machine);
+}
+
+
+/*-------------------------------------------------
+ soft_reset - actually perform a soft-reset
+ of the system
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( soft_reset )
+{
+ mame_private *mame = machine->mame_data;
+ callback_item *cb;
+
+ logerror("Soft reset\n");
+
+ /* temporarily in the reset phase */
+ mame->current_phase = MAME_PHASE_RESET;
+
+ /* a bit gross -- back off of the resource tracking, and put it back at the end */
+ assert(get_resource_tag() == 2);
+ end_resource_tracking();
+ begin_resource_tracking();
+
+ /* allow save state registrations during the reset */
+ state_save_allow_registration(TRUE);
+
+ /* unfortunately, we can't rely on callbacks to reset the interrupt */
+ /* structures, as these need to happen before we call the reset */
+ /* functions registered by the drivers */
+ cpuint_reset();
+
+ /* run the driver's reset callbacks */
+ if (machine->drv->machine_reset != NULL)
+ (*machine->drv->machine_reset)(machine);
+ if (machine->drv->sound_reset != NULL)
+ (*machine->drv->sound_reset)(machine);
+ if (machine->drv->video_reset != NULL)
+ (*machine->drv->video_reset)(machine);
+
+ /* call all registered reset callbacks */
+ for (cb = machine->mame_data->reset_callback_list; cb; cb = cb->next)
+ (*cb->func.reset)(machine);
+
+ /* disallow save state registrations starting here */
+ state_save_allow_registration(FALSE);
+
+ /* now we're running */
+ mame->current_phase = MAME_PHASE_RUNNING;
+
+ /* set the global time to the current time */
+ /* this allows 0-time queued callbacks to run before any CPUs execute */
+ timer_set_global_time(timer_get_time());
+}
+
+
+/*-------------------------------------------------
+ free_callback_list - free a list of callbacks
+-------------------------------------------------*/
+
+static void free_callback_list(callback_item **cb)
+{
+ while (*cb)
+ {
+ callback_item *temp = *cb;
+ *cb = (*cb)->next;
+ free(temp);
+ }
+}
+
+
+
+/***************************************************************************
+ SAVE/RESTORE
+***************************************************************************/
+
+/*-------------------------------------------------
+ saveload_init - initialize the save/load logic
+-------------------------------------------------*/
+
+static void saveload_init(running_machine *machine)
+{
+ const char *savegame = options_get_string(mame_options(), OPTION_STATE);
+
+ /* if we're coming in with a savegame request, process it now */
+ if (savegame[0] != 0)
+ mame_schedule_load(machine, savegame);
+
+ /* if we're in autosave mode, schedule a load */
+ else if (options_get_bool(mame_options(), OPTION_AUTOSAVE) && (machine->gamedrv->flags & GAME_SUPPORTS_SAVE))
+ mame_schedule_load(machine, "auto");
+}
+
+
+/*-------------------------------------------------
+ handle_save - attempt to perform a save
+-------------------------------------------------*/
+
+static void handle_save(running_machine *machine)
+{
+ mame_private *mame = machine->mame_data;
+ file_error filerr;
+ mame_file *file;
+
+ /* if no name, bail */
+ if (mame->saveload_pending_file == NULL)
+ {
+ mame->saveload_schedule_callback = NULL;
+ return;
+ }
+
+ /* if there are anonymous timers, we can't save just yet */
+ if (timer_count_anonymous() > 0)
+ {
+ /* if more than a second has passed, we're probably screwed */
+ if (attotime_sub(timer_get_time(), mame->saveload_schedule_time).seconds > 0)
+ {
+ popmessage("Unable to save due to pending anonymous timers. See error.log for details.");
+ goto cancel;
+ }
+ return;
+ }
+
+ /* open the file */
+ filerr = mame_fopen(SEARCHPATH_STATE, astring_c(mame->saveload_pending_file), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
+ if (filerr == FILERR_NONE)
+ {
+ int cpunum;
+
+ /* write the save state */
+ if (state_save_save_begin(file) != 0)
+ {
+ popmessage("Error: Unable to save state due to illegal registrations. See error.log for details.");
+ mame_fclose(file);
+ goto cancel;
+ }
+
+ /* write the default tag */
+ state_save_push_tag(0);
+ state_save_save_continue();
+ state_save_pop_tag();
+
+ /* loop over CPUs */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ cpuintrf_push_context(cpunum);
+
+ /* make sure banking is set */
+ activecpu_reset_banking();
+
+ /* save the CPU data */
+ state_save_push_tag(cpunum + 1);
+ state_save_save_continue();
+ state_save_pop_tag();
+
+ cpuintrf_pop_context();
+ }
+
+ /* finish and close */
+ state_save_save_finish();
+ mame_fclose(file);
+
+ /* pop a warning if the game doesn't support saves */
+ if (!(machine->gamedrv->flags & GAME_SUPPORTS_SAVE))
+ popmessage("State successfully saved.\nWarning: Save states are not officially supported for this game.");
+ else
+ popmessage("State successfully saved.");
+ }
+ else
+ popmessage("Error: Failed to save state");
+
+cancel:
+ /* unschedule the save */
+ astring_free(mame->saveload_pending_file);
+ mame->saveload_pending_file = NULL;
+ mame->saveload_schedule_callback = NULL;
+}
+
+
+/*-------------------------------------------------
+ handle_load - attempt to perform a load
+-------------------------------------------------*/
+
+static void handle_load(running_machine *machine)
+{
+ mame_private *mame = machine->mame_data;
+ file_error filerr;
+ mame_file *file;
+
+ /* if no name, bail */
+ if (mame->saveload_pending_file == NULL)
+ {
+ mame->saveload_schedule_callback = NULL;
+ return;
+ }
+
+ /* if there are anonymous timers, we can't load just yet because the timers might */
+ /* overwrite data we have loaded */
+ if (timer_count_anonymous() > 0)
+ {
+ /* if more than a second has passed, we're probably screwed */
+ if (attotime_sub(timer_get_time(), mame->saveload_schedule_time).seconds > 0)
+ {
+ popmessage("Unable to load due to pending anonymous timers. See error.log for details.");
+ goto cancel;
+ }
+ return;
+ }
+
+ /* open the file */
+ filerr = mame_fopen(SEARCHPATH_STATE, astring_c(mame->saveload_pending_file), OPEN_FLAG_READ, &file);
+ if (filerr == FILERR_NONE)
+ {
+ /* start loading */
+ if (state_save_load_begin(file) == 0)
+ {
+ int cpunum;
+
+ /* read tag 0 */
+ state_save_push_tag(0);
+ state_save_load_continue();
+ state_save_pop_tag();
+
+ /* loop over CPUs */
+ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
+ {
+ cpuintrf_push_context(cpunum);
+
+ /* make sure banking is set */
+ activecpu_reset_banking();
+
+ /* load the CPU data */
+ state_save_push_tag(cpunum + 1);
+ state_save_load_continue();
+ state_save_pop_tag();
+
+ /* make sure banking is set */
+ activecpu_reset_banking();
+
+ cpuintrf_pop_context();
+ }
+
+ /* finish and close */
+ state_save_load_finish();
+ popmessage("State successfully loaded.");
+ }
+ else
+ popmessage("Error: Failed to load state");
+ mame_fclose(file);
+ }
+ else
+ popmessage("Error: Failed to load state");
+
+cancel:
+ /* unschedule the load */
+ astring_free(mame->saveload_pending_file);
+ mame->saveload_pending_file = NULL;
+ mame->saveload_schedule_callback = NULL;
+}
+
+
+
+/***************************************************************************
+ SYSTEM TIME
+***************************************************************************/
+
+/*-------------------------------------------------
+ get_tm_time - converts a MAME
+-------------------------------------------------*/
+
+static void get_tm_time(struct tm *t, mame_system_tm *systm)
+{
+ systm->second = t->tm_sec;
+ systm->minute = t->tm_min;
+ systm->hour = t->tm_hour;
+ systm->mday = t->tm_mday;
+ systm->month = t->tm_mon;
+ systm->year = t->tm_year + 1900;
+ systm->weekday = t->tm_wday;
+ systm->day = t->tm_yday;
+ systm->is_dst = t->tm_isdst;
+}
+
+
+
+/*-------------------------------------------------
+ fill_systime - fills out a mame_system_time
+ structure
+-------------------------------------------------*/
+
+static void fill_systime(mame_system_time *systime, time_t t)
+{
+ systime->time = t;
+ get_tm_time(localtime(&t), &systime->local_time);
+ get_tm_time(gmtime(&t), &systime->utc_time);
+}
+
+
+
+/*-------------------------------------------------
+ mame_get_base_datetime - retrieve the time of
+ the host system; useful for RTC implementations
+-------------------------------------------------*/
+
+void mame_get_base_datetime(running_machine *machine, mame_system_time *systime)
+{
+ mame_private *mame = machine->mame_data;
+ fill_systime(systime, mame->base_time);
+}
+
+
+
+/*-------------------------------------------------
+ mame_get_current_datetime - retrieve the current
+ time (offsetted by the baes); useful for RTC
+ implementations
+-------------------------------------------------*/
+
+void mame_get_current_datetime(running_machine *machine, mame_system_time *systime)
+{
+ mame_private *mame = machine->mame_data;
+ fill_systime(systime, mame->base_time + timer_get_time().seconds);
+}
diff --git a/src/emu/mame.h b/src/emu/mame.h
new file mode 100644
index 00000000000..940c3fd4fb5
--- /dev/null
+++ b/src/emu/mame.h
@@ -0,0 +1,400 @@
+/***************************************************************************
+
+ mame.h
+
+ Controls execution of the core MAME system.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __MAME_H__
+#define __MAME_H__
+
+#include "mamecore.h"
+#include "video.h"
+#include "restrack.h"
+#include "options.h"
+#include <stdarg.h>
+
+#ifdef MESS
+#include "device.h"
+#endif /* MESS */
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* return values from run_game */
+#define MAMERR_NONE 0 /* no error */
+#define MAMERR_FAILED_VALIDITY 1 /* failed validity checks */
+#define MAMERR_MISSING_FILES 2 /* missing files */
+#define MAMERR_FATALERROR 3 /* some other fatal error */
+#define MAMERR_DEVICE 4 /* device initialization error (MESS-specific) */
+#define MAMERR_NO_SUCH_GAME 5 /* game was specified but doesn't exist */
+#define MAMERR_INVALID_CONFIG 6 /* some sort of error in configuration */
+#define MAMERR_IDENT_NONROMS 7 /* identified all non-ROM files */
+#define MAMERR_IDENT_PARTIAL 8 /* identified some files but not all */
+#define MAMERR_IDENT_NONE 9 /* identified no files */
+
+
+/* program phases */
+#define MAME_PHASE_PREINIT 0
+#define MAME_PHASE_INIT 1
+#define MAME_PHASE_RESET 2
+#define MAME_PHASE_RUNNING 3
+#define MAME_PHASE_EXIT 4
+
+
+/* maxima */
+#define MAX_GFX_ELEMENTS 32
+#define MAX_MEMORY_REGIONS 32
+
+
+/* MESS vs. MAME abstractions */
+#ifndef MESS
+#define APPNAME "MAME"
+#define APPNAME_LOWER "mame"
+#define CONFIGNAME "mame"
+#define APPLONGNAME "M.A.M.E."
+#define CAPGAMENOUN "GAME"
+#define CAPSTARTGAMENOUN "Game"
+#define GAMENOUN "game"
+#define GAMESNOUN "games"
+#define HISTORYNAME "History"
+#define COPYRIGHT "Copyright 2007, Nicola Salmoria\nand the MAME team\nhttp://mamedev.org"
+#else
+#define APPNAME "MESS"
+#define APPNAME_LOWER "mess"
+#define CONFIGNAME "mess"
+#define APPLONGNAME "M.E.S.S."
+#define CAPGAMENOUN "SYSTEM"
+#define CAPSTARTGAMENOUN "System"
+#define GAMENOUN "system"
+#define GAMESNOUN "systems"
+#define HISTORYNAME "System Info"
+#define COPYRIGHT "Copyright 2007, the MESS team\nhttp://mess.org"
+#endif
+
+
+/* output channels */
+enum _output_channel
+{
+ OUTPUT_CHANNEL_ERROR,
+ OUTPUT_CHANNEL_WARNING,
+ OUTPUT_CHANNEL_INFO,
+ OUTPUT_CHANNEL_DEBUG,
+ OUTPUT_CHANNEL_VERBOSE,
+ OUTPUT_CHANNEL_LOG,
+ OUTPUT_CHANNEL_COUNT
+};
+typedef enum _output_channel output_channel;
+
+
+/* memory region types */
+enum
+{
+ REGION_INVALID = 0x80,
+ REGION_CPU1,
+ REGION_CPU2,
+ REGION_CPU3,
+ REGION_CPU4,
+ REGION_CPU5,
+ REGION_CPU6,
+ REGION_CPU7,
+ REGION_CPU8,
+ REGION_GFX1,
+ REGION_GFX2,
+ REGION_GFX3,
+ REGION_GFX4,
+ REGION_GFX5,
+ REGION_GFX6,
+ REGION_GFX7,
+ REGION_GFX8,
+ REGION_PROMS,
+ REGION_SOUND1,
+ REGION_SOUND2,
+ REGION_SOUND3,
+ REGION_SOUND4,
+ REGION_SOUND5,
+ REGION_SOUND6,
+ REGION_SOUND7,
+ REGION_SOUND8,
+ REGION_USER1,
+ REGION_USER2,
+ REGION_USER3,
+ REGION_USER4,
+ REGION_USER5,
+ REGION_USER6,
+ REGION_USER7,
+ REGION_USER8,
+ REGION_USER9,
+ REGION_USER10,
+ REGION_USER11,
+ REGION_USER12,
+ REGION_USER13,
+ REGION_USER14,
+ REGION_USER15,
+ REGION_USER16,
+ REGION_USER17,
+ REGION_USER18,
+ REGION_USER19,
+ REGION_USER20,
+ REGION_DISKS,
+ REGION_PLDS,
+ REGION_MAX
+};
+
+extern const char *memory_region_names[REGION_MAX];
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* output channel callback */
+typedef void (*output_callback)(void *param, const char *format, va_list argptr);
+
+
+/* forward type declarations */
+typedef struct _mame_private mame_private;
+typedef struct _video_private video_private;
+typedef struct _palette_private palette_private;
+typedef struct _streams_private streams_private;
+typedef struct _devices_private devices_private;
+
+
+/* description of the currently-running machine */
+/* typedef struct _running_machine running_machine; -- in mamecore.h */
+struct _running_machine
+{
+ /* game-related information */
+ const game_driver * gamedrv; /* points to the definition of the game machine */
+ const machine_config * drv; /* points to the constructed machine_config */
+ const char * basename; /* basename used for game-related paths */
+
+ /* video-related information */
+ gfx_element * gfx[MAX_GFX_ELEMENTS];/* array of pointers to graphic sets (chars, sprites) */
+ screen_state screen[MAX_SCREENS];/* current screen state */
+ palette_t * palette; /* global palette object */
+
+ /* palette-related information */
+/* fix me - some games try to modify remapped_colortable directly */
+/* search for "palette hack" to find instances */
+ const pen_t * pens; /* remapped palette pen numbers */
+ const UINT16 * game_colortable; /* lookup table used to map gfx pen numbers to color numbers */
+ const pen_t * remapped_colortable;/* the above, already remapped through Machine->pens */
+ pen_t * shadow_table; /* table for looking up a shadowed pen */
+
+ /* audio-related information */
+ int sample_rate; /* the digital audio sample rate */
+
+ /* input-related information */
+ input_port_entry * input_ports; /* the input ports definition from the driver is copied here and modified */
+ mame_file * record_file; /* recording file (NULL if not recording) */
+ mame_file * playback_file; /* playback file (NULL if not recording) */
+
+ /* debugger-related information */
+ int debug_mode; /* was debug mode enabled? */
+
+ /* MESS-specific information */
+#ifdef MESS
+ struct IODevice * devices;
+#endif /* MESS */
+
+ /* internal core information */
+ mame_private * mame_data; /* internal data from mame.c */
+ video_private * video_data; /* internal data from video.c */
+ palette_private * palette_data; /* internal data from palette.c */
+ streams_private * streams_data; /* internal data from streams.c */
+ devices_private * devices_data; /* internal data from devices.c */
+
+ /* driver-specific information */
+ void * driver_data; /* drivers can hang data off of here instead of using globals */
+};
+
+
+typedef struct _mame_system_tm mame_system_tm;
+struct _mame_system_tm
+{
+ UINT8 second; /* seconds (0-59) */
+ UINT8 minute; /* minutes (0-59) */
+ UINT8 hour; /* hours (0-23) */
+ UINT8 mday; /* day of month (1-31) */
+ UINT8 month; /* month (0-11) */
+ INT32 year; /* year (1=1 AD) */
+ UINT8 weekday; /* day of week (0-6) */
+ UINT16 day; /* day of year (0-365) */
+ UINT8 is_dst; /* is this daylight savings? */
+};
+
+
+typedef struct _mame_system_time mame_system_time;
+struct _mame_system_time
+{
+ INT64 time; /* number of seconds elapsed since midnight, January 1 1970 UTC */
+ mame_system_tm local_time; /* local time */
+ mame_system_tm utc_time; /* UTC coordinated time */
+};
+
+
+
+/***************************************************************************
+ GLOBALS
+***************************************************************************/
+
+extern running_machine *Machine;
+extern const char *mame_disclaimer;
+extern char giant_string_buffer[];
+
+extern char build_version[];
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- core system management ----- */
+
+/* execute as configured by the OPTION_GAMENAME option on the specified options */
+int mame_execute(core_options *options);
+
+/* accesses the core_options for the currently running emulation */
+core_options *mame_options(void);
+
+/* return the current phase */
+int mame_get_phase(running_machine *machine);
+
+/* request callback on frame update */
+void add_frame_callback(running_machine *machine, void (*callback)(running_machine *));
+
+/* request callback on reset */
+void add_reset_callback(running_machine *machine, void (*callback)(running_machine *));
+
+/* request callback on pause */
+void add_pause_callback(running_machine *machine, void (*callback)(running_machine *, int));
+
+/* request callback on termination */
+void add_exit_callback(running_machine *machine, void (*callback)(running_machine *));
+
+/* handle update tasks for a frame boundary */
+void mame_frame_update(running_machine *machine);
+
+
+
+/* ----- global system states ----- */
+
+/* schedule an exit */
+void mame_schedule_exit(running_machine *machine);
+
+/* schedule a hard reset */
+void mame_schedule_hard_reset(running_machine *machine);
+
+/* schedule a soft reset */
+void mame_schedule_soft_reset(running_machine *machine);
+
+/* schedule a new driver */
+void mame_schedule_new_driver(running_machine *machine, const game_driver *driver);
+
+/* schedule a save */
+void mame_schedule_save(running_machine *machine, const char *filename);
+
+/* schedule a load */
+void mame_schedule_load(running_machine *machine, const char *filename);
+
+/* is a scheduled event pending? */
+int mame_is_scheduled_event_pending(running_machine *machine);
+
+/* pause the system */
+void mame_pause(running_machine *machine, int pause);
+
+/* get the current pause state */
+int mame_is_paused(running_machine *machine);
+
+
+
+/* ----- memory region management ----- */
+
+/* allocate a new memory region */
+UINT8 *new_memory_region(running_machine *machine, int type, UINT32 length, UINT32 flags);
+
+/* free an allocated memory region */
+void free_memory_region(running_machine *machine, int num);
+
+/* return a pointer to a specified memory region */
+UINT8 *memory_region(int num);
+
+/* return the size (in bytes) of a specified memory region */
+UINT32 memory_region_length(int num);
+
+/* return the type of a specified memory region */
+UINT32 memory_region_type(running_machine *machine, int num);
+
+/* return the flags (defined in romload.h) for a specified memory region */
+UINT32 memory_region_flags(running_machine *machine, int num);
+
+
+
+/* ----- output management ----- */
+
+/* set the output handler for a channel, returns the current one */
+void mame_set_output_channel(output_channel channel, output_callback callback, void *param, output_callback *prevcb, void **prevparam);
+
+/* built-in default callbacks */
+void mame_file_output_callback(void *param, const char *format, va_list argptr);
+void mame_null_output_callback(void *param, const char *format, va_list argptr);
+
+/* calls to be used by the code */
+void mame_printf_error(const char *format, ...) ATTR_PRINTF(1,2);
+void mame_printf_warning(const char *format, ...) ATTR_PRINTF(1,2);
+void mame_printf_info(const char *format, ...) ATTR_PRINTF(1,2);
+void mame_printf_verbose(const char *format, ...) ATTR_PRINTF(1,2);
+void mame_printf_debug(const char *format, ...) ATTR_PRINTF(1,2);
+
+/* discourage the use of printf directly */
+/* sadly, can't do this because of the ATTR_PRINTF under GCC */
+/*
+#undef printf
+#define printf !MUST_USE_MAME_PRINTF_*_CALLS_WITHIN_THE_CORE!
+*/
+
+
+/* ----- miscellaneous bits & pieces ----- */
+
+/* pop-up a user visible message */
+void CLIB_DECL popmessage(const char *text,...) ATTR_PRINTF(1,2);
+
+/* log to the standard error.log file */
+void CLIB_DECL logerror(const char *text,...) ATTR_PRINTF(1,2);
+
+/* adds a callback to be called on logerror() */
+void add_logerror_callback(running_machine *machine, void (*callback)(running_machine *, const char *));
+
+/* parse the configured INI files */
+void mame_parse_ini_files(core_options *options, const game_driver *driver);
+
+/* standardized random number generator */
+UINT32 mame_rand(running_machine *machine);
+
+/* return the index of the given CPU, or -1 if not found */
+int mame_find_cpu_index(running_machine *machine, const char *tag);
+
+/* retrieve the base system time */
+void mame_get_base_datetime(running_machine *machine, mame_system_time *systime);
+
+/* retrieve the current system time */
+void mame_get_current_datetime(running_machine *machine, mame_system_time *systime);
+
+
+
+#ifdef MESS
+#include "mess.h"
+#endif /* MESS */
+
+#endif /* __MAME_H__ */
diff --git a/src/emu/mamecore.c b/src/emu/mamecore.c
new file mode 100644
index 00000000000..aa3cf98c9d0
--- /dev/null
+++ b/src/emu/mamecore.c
@@ -0,0 +1,17 @@
+/***************************************************************************
+
+ mamecore.c
+
+ Simple core functions that are defined in mamecore.h and which may
+ need to be accessed by other MAME-related tools.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************/
+
+#include "mamecore.h"
+#include <ctype.h>
+
+/* a giant string buffer for temporary strings */
+char giant_string_buffer[GIANT_STRING_BUFFER_SIZE];
diff --git a/src/emu/mamecore.h b/src/emu/mamecore.h
new file mode 100644
index 00000000000..7af71bc2443
--- /dev/null
+++ b/src/emu/mamecore.h
@@ -0,0 +1,350 @@
+/***************************************************************************
+
+ mamecore.h
+
+ General core utilities and macros used throughout MAME.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __MAMECORE_H__
+#define __MAMECORE_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "osdcomm.h"
+#include "bitmap.h"
+#include "coreutil.h"
+#include "corestr.h"
+
+
+/***************************************************************************
+ COMPILER-SPECIFIC NASTINESS
+***************************************************************************/
+
+/* Suppress warnings about redefining the macro 'PPC' on LinuxPPC. */
+#ifdef PPC
+#undef PPC
+#endif
+
+/* Suppress warnings about redefining the macro 'ARM' on ARM. */
+#ifdef ARM
+#undef ARM
+#endif
+
+
+
+/***************************************************************************
+ COMMON TYPES
+***************************************************************************/
+
+/* genf is a type that can be used for function pointer casting in a way
+ that doesn't confuse some compilers */
+typedef void genf(void);
+
+
+/* FPTR is a type that can be used to cast a pointer to a scalar */
+/* 64-bit platforms should define PTR64 */
+#ifdef PTR64
+typedef UINT64 FPTR;
+#else
+typedef UINT32 FPTR;
+#endif
+
+
+/* These are forward struct declarations that are used to break
+ circular dependencies in the code */
+typedef struct _running_machine running_machine;
+typedef struct _mame_display mame_display;
+typedef struct _game_driver game_driver;
+typedef struct _machine_config machine_config;
+typedef struct _rom_load_data rom_load_data;
+typedef struct _osd_create_params osd_create_params;
+typedef struct _gfx_element gfx_element;
+typedef struct _input_port_entry input_port_entry;
+typedef struct _input_port_default_entry input_port_default_entry;
+typedef struct _mame_file mame_file;
+
+
+/* pen_t is used to represent pixel values in bitmaps */
+typedef UINT32 pen_t;
+
+/* stream_sample_t is used to represent a single sample in a sound stream */
+typedef INT32 stream_sample_t;
+
+/* mame_bitmap is just a bitmap_t */
+typedef bitmap_t mame_bitmap;
+
+
+
+/***************************************************************************
+ * Union of UINT8, UINT16 and UINT32 in native endianess of the target
+ * This is used to access bytes and words in a machine independent manner.
+ * The upper bytes h2 and h3 normally contain zero (16 bit CPU cores)
+ * thus PAIR.d can be used to pass arguments to the memory system
+ * which expects 'int' really.
+***************************************************************************/
+typedef union
+{
+#ifdef LSB_FIRST
+ struct { UINT8 l,h,h2,h3; } b;
+ struct { UINT16 l,h; } w;
+#else
+ struct { UINT8 h3,h2,h,l; } b;
+ struct { UINT16 h,l; } w;
+#endif
+ UINT32 d;
+} PAIR;
+
+
+/***************************************************************************
+ * Union of UINT8, UINT16, UINT32, and UINT64 in native endianess of
+ * the target. This is used to access bytes and words in a machine
+ * independent manner.
+***************************************************************************/
+typedef union
+{
+#ifdef LSB_FIRST
+ struct { UINT8 l,h,h2,h3,h4,h5,h6,h7; } b;
+ struct { UINT16 l,h,h2,h3; } w;
+ struct { UINT32 l,h; } d;
+#else
+ struct { UINT8 h7,h6,h5,h4,h3,h2,h,l; } b;
+ struct { UINT16 h3,h2,h,l; } w;
+ struct { UINT32 h,l; } d;
+#endif
+ UINT64 lw;
+} PAIR64;
+
+
+
+/***************************************************************************
+ COMMON CONSTANTS
+***************************************************************************/
+
+/* this is not part of the C/C++ standards and is not present on */
+/* strict ANSI compilers or when compiling under GCC with -ansi */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
+/* orientation of bitmaps */
+#define ORIENTATION_FLIP_X 0x0001 /* mirror everything in the X direction */
+#define ORIENTATION_FLIP_Y 0x0002 /* mirror everything in the Y direction */
+#define ORIENTATION_SWAP_XY 0x0004 /* mirror along the top-left/bottom-right diagonal */
+
+#define ROT0 0
+#define ROT90 (ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X) /* rotate clockwise 90 degrees */
+#define ROT180 (ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y) /* rotate 180 degrees */
+#define ROT270 (ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y) /* rotate counter-clockwise 90 degrees */
+
+
+/* giant global string buffer */
+#define GIANT_STRING_BUFFER_SIZE 65536
+
+
+
+/***************************************************************************
+ COMMON MACROS
+***************************************************************************/
+
+/* Standard MAME assertion macros */
+#undef assert
+#undef assert_always
+
+#ifdef MAME_DEBUG
+#define assert(x) do { if (!(x)) fatalerror("assert: %s:%d: %s", __FILE__, __LINE__, #x); } while (0)
+#define assert_always(x, msg) do { if (!(x)) fatalerror("Fatal error: %s\nCaused by assert: %s:%d: %s", msg, __FILE__, __LINE__, #x); } while (0)
+#else
+#define assert(x)
+#define assert_always(x, msg) do { if (!(x)) fatalerror("Fatal error: %s (%s:%d)", msg, __FILE__, __LINE__); } while (0)
+#endif
+
+
+/* map mame_* helpers to core_* helpers */
+#define mame_stricmp core_stricmp
+#define mame_strnicmp core_strnicmp
+#define mame_strdup core_strdup
+#define mame_strwildcmp core_strwildcmp
+
+
+/* prevent the use of rand() -- use mame_rand() instead */
+#define rand
+
+
+/* macros to convert radians to degrees and degrees to radians */
+#define RADIAN_TO_DEGREE(x) ((180.0 / M_PI) * (x))
+#define DEGREE_TO_RADIAN(x) ((M_PI / 180.0) * (x))
+
+
+/* U64 and S64 are used to wrap long integer constants. */
+#ifdef __GNUC__
+#define U64(val) val##ULL
+#define S64(val) val##LL
+#else
+#define U64(val) val
+#define S64(val) val
+#endif
+
+
+/* Useful macros to deal with bit shuffling encryptions */
+#define BIT(x,n) (((x)>>(n))&1)
+
+#define BITSWAP8(val,B7,B6,B5,B4,B3,B2,B1,B0) \
+ ((BIT(val,B7) << 7) | \
+ (BIT(val,B6) << 6) | \
+ (BIT(val,B5) << 5) | \
+ (BIT(val,B4) << 4) | \
+ (BIT(val,B3) << 3) | \
+ (BIT(val,B2) << 2) | \
+ (BIT(val,B1) << 1) | \
+ (BIT(val,B0) << 0))
+
+#define BITSWAP16(val,B15,B14,B13,B12,B11,B10,B9,B8,B7,B6,B5,B4,B3,B2,B1,B0) \
+ ((BIT(val,B15) << 15) | \
+ (BIT(val,B14) << 14) | \
+ (BIT(val,B13) << 13) | \
+ (BIT(val,B12) << 12) | \
+ (BIT(val,B11) << 11) | \
+ (BIT(val,B10) << 10) | \
+ (BIT(val, B9) << 9) | \
+ (BIT(val, B8) << 8) | \
+ (BIT(val, B7) << 7) | \
+ (BIT(val, B6) << 6) | \
+ (BIT(val, B5) << 5) | \
+ (BIT(val, B4) << 4) | \
+ (BIT(val, B3) << 3) | \
+ (BIT(val, B2) << 2) | \
+ (BIT(val, B1) << 1) | \
+ (BIT(val, B0) << 0))
+
+#define BITSWAP24(val,B23,B22,B21,B20,B19,B18,B17,B16,B15,B14,B13,B12,B11,B10,B9,B8,B7,B6,B5,B4,B3,B2,B1,B0) \
+ ((BIT(val,B23) << 23) | \
+ (BIT(val,B22) << 22) | \
+ (BIT(val,B21) << 21) | \
+ (BIT(val,B20) << 20) | \
+ (BIT(val,B19) << 19) | \
+ (BIT(val,B18) << 18) | \
+ (BIT(val,B17) << 17) | \
+ (BIT(val,B16) << 16) | \
+ (BIT(val,B15) << 15) | \
+ (BIT(val,B14) << 14) | \
+ (BIT(val,B13) << 13) | \
+ (BIT(val,B12) << 12) | \
+ (BIT(val,B11) << 11) | \
+ (BIT(val,B10) << 10) | \
+ (BIT(val, B9) << 9) | \
+ (BIT(val, B8) << 8) | \
+ (BIT(val, B7) << 7) | \
+ (BIT(val, B6) << 6) | \
+ (BIT(val, B5) << 5) | \
+ (BIT(val, B4) << 4) | \
+ (BIT(val, B3) << 3) | \
+ (BIT(val, B2) << 2) | \
+ (BIT(val, B1) << 1) | \
+ (BIT(val, B0) << 0))
+
+#define BITSWAP32(val,B31,B30,B29,B28,B27,B26,B25,B24,B23,B22,B21,B20,B19,B18,B17,B16,B15,B14,B13,B12,B11,B10,B9,B8,B7,B6,B5,B4,B3,B2,B1,B0) \
+ ((BIT(val,B31) << 31) | \
+ (BIT(val,B30) << 30) | \
+ (BIT(val,B29) << 29) | \
+ (BIT(val,B28) << 28) | \
+ (BIT(val,B27) << 27) | \
+ (BIT(val,B26) << 26) | \
+ (BIT(val,B25) << 25) | \
+ (BIT(val,B24) << 24) | \
+ (BIT(val,B23) << 23) | \
+ (BIT(val,B22) << 22) | \
+ (BIT(val,B21) << 21) | \
+ (BIT(val,B20) << 20) | \
+ (BIT(val,B19) << 19) | \
+ (BIT(val,B18) << 18) | \
+ (BIT(val,B17) << 17) | \
+ (BIT(val,B16) << 16) | \
+ (BIT(val,B15) << 15) | \
+ (BIT(val,B14) << 14) | \
+ (BIT(val,B13) << 13) | \
+ (BIT(val,B12) << 12) | \
+ (BIT(val,B11) << 11) | \
+ (BIT(val,B10) << 10) | \
+ (BIT(val, B9) << 9) | \
+ (BIT(val, B8) << 8) | \
+ (BIT(val, B7) << 7) | \
+ (BIT(val, B6) << 6) | \
+ (BIT(val, B5) << 5) | \
+ (BIT(val, B4) << 4) | \
+ (BIT(val, B3) << 3) | \
+ (BIT(val, B2) << 2) | \
+ (BIT(val, B1) << 1) | \
+ (BIT(val, B0) << 0))
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* Used by assert(), so definition here instead of mame.h */
+DECL_NORETURN void CLIB_DECL fatalerror(const char *text, ...) ATTR_PRINTF(1,2) ATTR_NORETURN;
+DECL_NORETURN void CLIB_DECL fatalerror_exitcode(int exitcode, const char *text, ...) ATTR_PRINTF(2,3) ATTR_NORETURN;
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/* convert a series of 32 bits into a float */
+INLINE float u2f(UINT32 v)
+{
+ union {
+ float ff;
+ UINT32 vv;
+ } u;
+ u.vv = v;
+ return u.ff;
+}
+
+
+/* convert a float into a series of 32 bits */
+INLINE UINT32 f2u(float f)
+{
+ union {
+ float ff;
+ UINT32 vv;
+ } u;
+ u.ff = f;
+ return u.vv;
+}
+
+
+/* convert a series of 64 bits into a double */
+INLINE double u2d(UINT64 v)
+{
+ union {
+ double dd;
+ UINT64 vv;
+ } u;
+ u.vv = v;
+ return u.dd;
+}
+
+
+/* convert a double into a series of 64 bits */
+INLINE UINT64 d2u(double d)
+{
+ union {
+ double dd;
+ UINT64 vv;
+ } u;
+ u.dd = d;
+ return u.vv;
+}
+
+#endif /* __MAMECORE_H__ */
diff --git a/src/emu/memconv.h b/src/emu/memconv.h
new file mode 100644
index 00000000000..5b587f376f6
--- /dev/null
+++ b/src/emu/memconv.h
@@ -0,0 +1,1020 @@
+/***************************************************************************
+
+ memconv.h
+
+ Functions which help convert between different handlers.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ ***** VERY IMPORTANT NOTICE *****
+
+ These functions and macros are provided to facilitate the mapping
+ of devices on cpus with different data bus widths.
+ Devices should be implemented using their native data bus width,
+ since that ensures that read/write operations are kept atomic.
+ If we discover you have abused the functionality presented in this
+ file, you *will* be publicly humiliated and your code submission
+ will probably not be accepted. Seriously, please do not abuse these
+ functions/macros.
+
+****************************************************************************
+
+ Conversions supported:
+
+ CW = CPU Data Bus Width in bits
+ CBO = CPU Byte Order
+ DW = Device Data Bus Width in bits
+ DBO = Device Byte Order
+
+ CW | CBO | DW | DBO | Functions to use
+ ---+--------+----+--------+-----------------------------------------------------------
+ 16 | Big | 8 | N/A | read16be_with_read8_handler,write16be_with_write8_handler
+ 16 | Little | 8 | N/A | read16le_with_read8_handler,write16le_with_write8_handler
+ ---+--------+----+--------+-----------------------------------------------------------
+ 32 | Big | 8 | N/A | read32be_with_read8_handler,write32be_with_write8_handler
+ 32 | Little | 8 | N/A | read32le_with_read8_handler,write32le_with_write8_handler
+ 32 | Big | 16 | Big | read32be_with_16be_handler,write32be_with_16be_handler
+ 32 | Little | 16 | Little | read32le_with_16le_handler,write32le_with_16le_handler
+ 32 | Big | 16 | Little | read32be_with_16le_handler,write32be_with_16le_handler
+ 32 | Little | 16 | Big | read32le_with_16be_handler,write32le_with_16be_handler
+ ---+--------+----+--------+-----------------------------------------------------------
+ 64 | Big | 8 | N/A | read64be_with_read8_handler,write64be_with_write8_handler
+ 64 | Little | 8 | N/A | read64le_with_read8_handler,write64le_with_write8_handler
+ 64 | Big | 16 | Big | read64be_with_16be_handler,write64be_with_16be_handler
+ 64 | Little | 16 | Little | read64le_with_16le_handler,write64le_with_16le_handler
+ 64 | Big | 16 | Little | read64be_with_16le_handler,write64be_with_16le_handler
+ 64 | Little | 16 | Big | read64le_with_16be_handler,write64le_with_16be_handler
+ 64 | Big | 32 | Big | read64be_with_32be_handler,write64be_with_32be_handler
+ 64 | Little | 32 | Little | read64le_with_32le_handler,write64le_with_32le_handler
+ 64 | Big | 32 | Little | read64be_with_32le_handler,write64be_with_32le_handler
+ 64 | Little | 32 | Big | read64le_with_32be_handler,write64le_with_32be_handler
+
+ You can also find at the bottom of this file a few convernient
+ macros that will create the stub read and/or write handlers for
+ the most common mappings, that will use the functions above.
+ Here's an example on how to use them: Say you have a 8 bit device
+ whose handlers are device8_r and device8_w, and you want to connect
+ it to a 16 bit, big endian cpu. We'll say the device is mapped on
+ the least significant byte of the data bus (LSB).
+
+ In your driver, you would add:
+
+ READWRITE8TO16BE_LSB( device16, device8_r, device8_w )
+
+ which will create two 16 bit memory handlers, one for read, called
+ device16_r, and one for write, called device16_w, with the proper
+ mapping.
+
+ then in the MEMORY_MAP you would specify:
+
+ AM_RANGE(0x000000, 0x0000ff) AM_READWRITE( device16_r, device16_w )
+
+ And that is all. Your device should be mapped properly.
+ If you need to do custom mappings, or a mapping that is not currently
+ supported in this file, you can always write the stub yourself, and
+ call the above functions to invoke the base handlers.
+
+***************************************************************************/
+
+/*************************************
+ *
+ * 16-bit BE using 8-bit handlers
+ *
+ *************************************/
+
+INLINE UINT16 read16be_with_read8_handler(read8_handler handler, offs_t offset, UINT16 mem_mask)
+{
+ UINT16 result = 0;
+ if ((mem_mask & 0xff00) != 0xff00)
+ result |= ((UINT16)(*handler)(offset * 2 + 0)) << 8;
+ if ((mem_mask & 0x00ff) != 0x00ff)
+ result |= ((UINT16)(*handler)(offset * 2 + 1)) << 0;
+ return result;
+}
+
+
+INLINE void write16be_with_write8_handler(write8_handler handler, offs_t offset, UINT16 data, UINT16 mem_mask)
+{
+ if ((mem_mask & 0xff00) != 0xff00)
+ (*handler)(offset * 2 + 0, data >> 8);
+ if ((mem_mask & 0x00ff) != 0x00ff)
+ (*handler)(offset * 2 + 1, data >> 0);
+}
+
+
+/*************************************
+ *
+ * 16-bit LE using 8-bit handlers
+ *
+ *************************************/
+
+INLINE UINT16 read16le_with_read8_handler(read8_handler handler, offs_t offset, UINT16 mem_mask)
+{
+ UINT16 result = 0;
+ if ((mem_mask & 0x00ff) != 0x00ff)
+ result |= ((UINT16) (*handler)(offset * 2 + 0)) << 0;
+ if ((mem_mask & 0xff00) != 0xff00)
+ result |= ((UINT16) (*handler)(offset * 2 + 1)) << 8;
+ return result;
+}
+
+
+INLINE void write16le_with_write8_handler(write8_handler handler, offs_t offset, UINT16 data, UINT16 mem_mask)
+{
+ if ((mem_mask & 0x00ff) != 0x00ff)
+ (*handler)(offset * 2 + 0, data >> 0);
+ if ((mem_mask & 0xff00) != 0xff00)
+ (*handler)(offset * 2 + 1, data >> 8);
+}
+
+
+/*************************************
+ *
+ * 32-bit BE using 8-bit handlers
+ *
+ *************************************/
+
+INLINE UINT32 read32be_with_read8_handler(read8_handler handler, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result = 0;
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ result |= read16be_with_read8_handler(handler, offset * 2 + 0, mem_mask >> 16) << 16;
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ result |= read16be_with_read8_handler(handler, offset * 2 + 1, mem_mask) << 0;
+ return result;
+}
+
+
+INLINE void write32be_with_write8_handler(write8_handler handler, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ write16be_with_write8_handler(handler, offset * 2 + 0, data >> 16, mem_mask >> 16);
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ write16be_with_write8_handler(handler, offset * 2 + 1, data, mem_mask);
+}
+
+
+/*************************************
+ *
+ * 32-bit LE using 8-bit handlers
+ *
+ *************************************/
+
+INLINE UINT32 read32le_with_read8_handler(read8_handler handler, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result = 0;
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ result |= read16le_with_read8_handler(handler, offset * 2 + 0, mem_mask) << 0;
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ result |= read16le_with_read8_handler(handler, offset * 2 + 1, mem_mask >> 16) << 16;
+ return result;
+}
+
+
+INLINE void write32le_with_write8_handler(write8_handler handler, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ write16le_with_write8_handler(handler, offset * 2 + 0, data, mem_mask);
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ write16le_with_write8_handler(handler, offset * 2 + 1, data >> 16, mem_mask >> 16);
+}
+
+
+/*************************************
+ *
+ * 32-bit BE using 16-bit BE handlers
+ *
+ *************************************/
+
+INLINE UINT32 read32be_with_16be_handler(read16_handler handler, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result = 0;
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ result |= (*handler)(offset * 2 + 0, mem_mask >> 16) << 16;
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ result |= (*handler)(offset * 2 + 1, mem_mask) << 0;
+ return result;
+}
+
+
+INLINE void write32be_with_16be_handler(write16_handler handler, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ (*handler)(offset * 2 + 0, data >> 16, mem_mask >> 16);
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ (*handler)(offset * 2 + 1, data, mem_mask);
+}
+
+
+/*************************************
+ *
+ * 32-bit LE using 16-bit LE handlers
+ *
+ *************************************/
+
+INLINE UINT32 read32le_with_16le_handler(read16_handler handler, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result = 0;
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ result |= (*handler)(offset * 2 + 0, mem_mask) << 0;
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ result |= (*handler)(offset * 2 + 1, mem_mask >> 16) << 16;
+ return result;
+}
+
+
+INLINE void write32le_with_16le_handler(write16_handler handler, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ (*handler)(offset * 2 + 0, data, mem_mask);
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ (*handler)(offset * 2 + 1, data >> 16, mem_mask >> 16);
+}
+
+
+/*************************************
+ *
+ * 32-bit BE using 16-bit LE handlers
+ *
+ *************************************/
+
+INLINE UINT32 read32be_with_16le_handler(read16_handler handler, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result = 0;
+ mem_mask = FLIPENDIAN_INT32(mem_mask);
+ result = read32le_with_16le_handler(handler, offset, mem_mask);
+ return FLIPENDIAN_INT32(result);
+}
+
+
+INLINE void write32be_with_16le_handler(write16_handler handler, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ data = FLIPENDIAN_INT32(data);
+ mem_mask = FLIPENDIAN_INT32(mem_mask);
+ write32le_with_16le_handler(handler, offset, data, mem_mask);
+}
+
+
+/*************************************
+ *
+ * 32-bit LE using 16-bit BE handlers
+ *
+ *************************************/
+
+INLINE UINT32 read32le_with_16be_handler(read16_handler handler, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result = 0;
+ mem_mask = FLIPENDIAN_INT32(mem_mask);
+ result = read32be_with_16be_handler(handler, offset, mem_mask);
+ return FLIPENDIAN_INT32(result);
+}
+
+
+INLINE void write32le_with_16be_handler(write16_handler handler, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ data = FLIPENDIAN_INT32(data);
+ mem_mask = FLIPENDIAN_INT32(mem_mask);
+ write32be_with_16be_handler(handler, offset, data, mem_mask);
+}
+
+
+/*************************************
+ *
+ * 64-bit BE using 8-bit handlers
+ *
+ *************************************/
+
+INLINE UINT64 read64be_with_read8_handler(read8_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)read32be_with_read8_handler(handler, offset * 2 + 0, mem_mask >> 32) << 32;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= (UINT64)read32be_with_read8_handler(handler, offset * 2 + 1, mem_mask) << 0;
+ return result;
+}
+
+
+INLINE void write64be_with_write8_handler(write8_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ write32be_with_write8_handler(handler, offset * 2 + 0, data >> 32, mem_mask >> 32);
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ write32be_with_write8_handler(handler, offset * 2 + 1, data, mem_mask);
+}
+
+
+/*************************************
+ *
+ * 64-bit LE using 8-bit handlers
+ *
+ *************************************/
+
+INLINE UINT64 read64le_with_read8_handler(read8_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= (UINT64)read32le_with_read8_handler(handler, offset * 2 + 0, mem_mask >> 0) << 0;
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)read32le_with_read8_handler(handler, offset * 2 + 1, mem_mask >> 32) << 32;
+ return result;
+}
+
+
+INLINE void write64le_with_write8_handler(write8_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ write32le_with_write8_handler(handler, offset * 2 + 0, data >> 0, mem_mask >> 0);
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ write32le_with_write8_handler(handler, offset * 2 + 1, data >> 32, mem_mask >> 32);
+}
+
+
+/*************************************
+ *
+ * 64-bit BE using 16-bit BE handlers
+ *
+ *************************************/
+
+INLINE UINT32 read64be_with_16be_handler(read16_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)read32be_with_16be_handler(handler, offset * 2 + 0, mem_mask >> 32) << 32;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= (UINT64)read32be_with_16be_handler(handler, offset * 2 + 1, mem_mask >> 0) << 0;
+ return result;
+}
+
+
+INLINE void write64be_with_16be_handler(write16_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ write32be_with_16be_handler(handler, offset * 2 + 0, data >> 32, mem_mask >> 32);
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ write32be_with_16be_handler(handler, offset * 2 + 1, data >> 0, mem_mask >> 0);
+}
+
+
+/*************************************
+ *
+ * 64-bit LE using 16-bit LE handlers
+ *
+ *************************************/
+
+INLINE UINT32 read64le_with_16le_handler(read16_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= (UINT64)read32le_with_16le_handler(handler, offset * 2 + 0, mem_mask >> 0) << 0;
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)read32le_with_16le_handler(handler, offset * 2 + 1, mem_mask >> 32) << 32;
+ return result;
+}
+
+
+INLINE void write64le_with_16le_handler(write16_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ write32le_with_16le_handler(handler, offset * 2 + 0, data >> 0, mem_mask >> 0);
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ write32le_with_16le_handler(handler, offset * 2 + 1, data >> 32, mem_mask >> 32);
+}
+
+
+/*************************************
+ *
+ * 64-bit BE using 16-bit LE handlers
+ *
+ *************************************/
+
+INLINE UINT32 read64be_with_16le_handler(read16_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)read32be_with_16le_handler(handler, offset * 2 + 0, mem_mask >> 32) << 32;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= (UINT64)read32be_with_16le_handler(handler, offset * 2 + 1, mem_mask >> 0) << 0;
+ return result;
+}
+
+
+INLINE void write64be_with_16le_handler(write16_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ write32be_with_16le_handler(handler, offset * 2 + 0, data >> 32, mem_mask >> 32);
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ write32be_with_16le_handler(handler, offset * 2 + 1, data >> 0, mem_mask >> 0);
+}
+
+
+/*************************************
+ *
+ * 64-bit LE using 16-bit BE handlers
+ *
+ *************************************/
+
+INLINE UINT32 read64le_with_16be_handler(read16_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= (UINT64)read32le_with_16be_handler(handler, offset * 2 + 0, mem_mask >> 0) << 0;
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)read32le_with_16be_handler(handler, offset * 2 + 1, mem_mask >> 32) << 32;
+ return result;
+}
+
+
+INLINE void write64le_with_16be_handler(write16_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ write32le_with_16be_handler(handler, offset * 2 + 0, data >> 0, mem_mask >> 0);
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ write32le_with_16be_handler(handler, offset * 2 + 1, data >> 32, mem_mask >> 32);
+}
+
+
+/*************************************
+ *
+ * 64-bit BE using 32-bit BE handlers
+ *
+ *************************************/
+
+INLINE UINT64 read64be_with_32be_handler(read32_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)(*handler)(offset * 2 + 0, mem_mask >> 32) << 32;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= (UINT64)(*handler)(offset * 2 + 1, mem_mask >> 0) << 0;
+ return result;
+}
+
+
+INLINE void write64be_with_32be_handler(write32_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ (*handler)(offset * 2 + 0, data >> 32, mem_mask >> 32);
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ (*handler)(offset * 2 + 1, data >> 0, mem_mask >> 0);
+}
+
+
+/*************************************
+ *
+ * 64-bit LE using 32-bit LE handlers
+ *
+ *************************************/
+
+INLINE UINT64 read64le_with_32le_handler(read32_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result = 0;
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ result |= (UINT64)(*handler)(offset * 2 + 0, mem_mask >> 0) << 0;
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ result |= (UINT64)(*handler)(offset * 2 + 1, mem_mask >> 32) << 32;
+ return result;
+}
+
+
+INLINE void write64le_with_32le_handler(write32_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ if ((mem_mask & U64(0x00000000ffffffff)) != U64(0x00000000ffffffff))
+ (*handler)(offset * 2 + 0, data >> 0, mem_mask >> 0);
+ if ((mem_mask & U64(0xffffffff00000000)) != U64(0xffffffff00000000))
+ (*handler)(offset * 2 + 1, data >> 32, mem_mask >> 32);
+}
+
+
+/*************************************
+ *
+ * 64-bit BE using 32-bit LE handlers
+ *
+ *************************************/
+
+INLINE UINT64 read64be_with_32le_handler(read32_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result;
+ mem_mask = FLIPENDIAN_INT64(mem_mask);
+ result = read64le_with_32le_handler(handler, offset, mem_mask);
+ return FLIPENDIAN_INT64(result);
+}
+
+
+INLINE void write64be_with_32le_handler(write32_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ data = FLIPENDIAN_INT64(data);
+ mem_mask = FLIPENDIAN_INT64(mem_mask);
+ write64le_with_32le_handler(handler, offset, data, mem_mask);
+}
+
+
+/*************************************
+ *
+ * 64-bit LE using 32-bit BE handlers
+ *
+ *************************************/
+
+INLINE UINT64 read64le_with_32be_handler(read32_handler handler, offs_t offset, UINT64 mem_mask)
+{
+ UINT64 result;
+ mem_mask = FLIPENDIAN_INT64(mem_mask);
+ result = read64be_with_32be_handler(handler, offset, mem_mask);
+ return FLIPENDIAN_INT64(result);
+}
+
+
+INLINE void write64le_with_32be_handler(write32_handler handler, offs_t offset, UINT64 data, UINT64 mem_mask)
+{
+ data = FLIPENDIAN_INT64(data);
+ mem_mask = FLIPENDIAN_INT64(mem_mask);
+ write64be_with_32be_handler(handler, offset, data, mem_mask);
+}
+
+
+
+/**************************************************************************
+
+ Utility macros
+
+**************************************************************************/
+
+#define READ_TEMPLATE(bits, name, handler, func) \
+READ##bits##_HANDLER( name##_r ) \
+{ \
+ return func(handler, offset, mem_mask); \
+}
+
+#define READ_TEMPLATE_COND(bits, name, handler, func, cond) \
+READ##bits##_HANDLER( name##_r ) \
+{ \
+ if (cond) \
+ return func(handler, offset, mem_mask); \
+ return 0; \
+}
+
+#define WRITE_TEMPLATE(bits, name, handler, func) \
+WRITE##bits##_HANDLER( name##_w ) \
+{ \
+ func(handler, offset, data, mem_mask); \
+}
+
+#define WRITE_TEMPLATE_COND(bits, name, handler, func, cond) \
+WRITE##bits##_HANDLER( name##_w ) \
+{ \
+ if (cond) \
+ return func(handler, offset, data, mem_mask); \
+}
+
+
+
+/**************************************************************************
+
+ Generic conversions macros
+
+**************************************************************************/
+
+
+/*************************************
+ * 8->16be, 1:1 mapping
+ ************************************/
+
+#define READ8TO16BE( name, read8 ) \
+READ_TEMPLATE( 16, name, read8, read16be_with_read8_handler )
+
+
+#define WRITE8TO16BE( name, write8 ) \
+WRITE_TEMPLATE( 16, name, write8, write16be_with_write8_handler )
+
+
+#define READWRITE8TO16BE( name, read8, write8 ) \
+READ8TO16BE(name,read8) \
+WRITE8TO16BE(name,write8)
+
+
+/*************************************
+ * 8->16le, 1:1 mapping
+ ************************************/
+
+#define READ8TO16LE( name, read8 ) \
+READ_TEMPLATE( 16, name, read8, read16le_with_read8_handler )
+
+
+#define WRITE8TO16LE( name, write8 ) \
+WRITE_TEMPLATE( 16, name, write8, write16le_with_write8_handler )
+
+
+#define READWRITE8TO16LE( name, read8, write8 ) \
+READ8TO16LE(name,read8) \
+WRITE8TO16LE(name,write8)
+
+
+/*************************************
+ * 8->16be, MSB mapping
+ ************************************/
+
+#define READ8TO16BE_MSB( name, read8 ) \
+READ_TEMPLATE_COND( 16, name, read8, read16be_with_read8_handler, ACCESSING_MSB )
+
+
+#define WRITE8TO16BE_MSB( name, write8 ) \
+WRITE_TEMPLATE_COND( 16, name, write8, write16be_with_write8_handler, ACCESSING_MSB )
+
+
+#define READWRITE8TO16BE_MSB( name, read8, write8 ) \
+READ8TO16BE_MSB(name,read8) \
+WRITE8TO16BE_MSB(name,write8)
+
+
+/*************************************
+ * 8->16le, MSB mapping
+ ************************************/
+
+#define READ8TO16LE_MSB( name, read8 ) \
+READ_TEMPLATE_COND( 16, name, read8, read16le_with_read8_handler, ACCESSING_MSB )
+
+
+#define WRITE8TO16LE_MSB( name, write8 ) \
+WRITE_TEMPLATE_COND( 16, name, write8, write16le_with_write8_handler, ACCESSING_MSB )
+
+
+#define READWRITE8TO16LE_MSB( name, read8, write8 ) \
+READ8TO16LE_MSB(name,read8) \
+WRITE8TO16LE_MSB(name,write8)
+
+
+/*************************************
+ * 8->16be, LSB mapping
+ ************************************/
+
+#define READ8TO16BE_LSB( name, read8 ) \
+READ_TEMPLATE_COND( 16, name, read8, read16be_with_read8_handler, ACCESSING_LSB )
+
+
+#define WRITE8TO16BE_LSB( name, write8 ) \
+WRITE_TEMPLATE_COND( 16, name, write8, write16be_with_write8_handler, ACCESSING_LSB )
+
+
+#define READWRITE8TO16BE_LSB( name, read8, write8 ) \
+READ8TO16BE_LSB(name,read8) \
+WRITE8TO16BE_LSB(name,write8)
+
+
+/*************************************
+ * 8->16le, LSB mapping
+ ************************************/
+
+#define READ8TO16LE_LSB( name, read8 ) \
+READ_TEMPLATE_COND( 16, name, read8, read16le_with_read8_handler, ACCESSING_LSB )
+
+
+#define WRITE8TO16LE_LSB( name, write8 ) \
+WRITE_TEMPLATE_COND( 16, name, write8, write16le_with_write8_handler, ACCESSING_LSB )
+
+
+#define READWRITE8TO16LE_LSB( name, read8, write8 ) \
+READ8TO16LE_LSB(name,read8) \
+WRITE8TO16LE_LSB(name,write8)
+
+
+/*************************************
+ * 8->32be, 1:1 mapping
+ ************************************/
+
+#define READ8TO32BE( name, read8 ) \
+READ_TEMPLATE( 32, name, read8, read32be_with_read8_handler )
+
+
+#define WRITE8TO32BE( name, write8 ) \
+WRITE_TEMPLATE( 32, name, write8, write32be_with_write8_handler )
+
+
+#define READWRITE8TO32BE( name, read8, write8 ) \
+READ8TO32BE(name,read8) \
+WRITE8TO32BE(name,write8)
+
+
+/*************************************
+ * 8->32le, 1:1 mapping
+ ************************************/
+
+#define READ8TO32LE( name, read8 ) \
+READ_TEMPLATE( 32, name, read8, read32le_with_read8_handler )
+
+
+#define WRITE8TO32LE( name, write8 ) \
+WRITE_TEMPLATE( 32, name, write8, write32le_with_write8_handler )
+
+
+#define READWRITE8TO32LE( name, read8, write8 ) \
+READ8TO32LE(name,read8) \
+WRITE8TO32LE(name,write8)
+
+
+/*************************************
+ * 8->32be, MSB mapping
+ ************************************/
+
+#define READ8TO32BE_MSB( name, read8 ) \
+READ_TEMPLATE_COND( 32, name, read8, read32be_with_read8_handler, ACCESSING_MSB32 )
+
+
+#define WRITE8TO32BE_MSB( name, write8 ) \
+WRITE_TEMPLATE_COND( 32, name, write8, write32be_with_write8_handler, ACCESSING_MSB32 )
+
+
+#define READWRITE8TO32BE_MSB( name, read8, write8 ) \
+READ8TO32BE_MSB(name,read8) \
+WRITE8TO32BE_MSB(name,write8)
+
+
+/*************************************
+ * 8->32le, MSB mapping
+ ************************************/
+
+#define READ8TO32LE_MSB( name, read8 ) \
+READ_TEMPLATE_COND( 32, name, read8, read32le_with_read8_handler, ACCESSING_MSB32 )
+
+
+#define WRITE8TO32LE_MSB( name, write8 ) \
+WRITE_TEMPLATE_COND( 32, name, write8, write32le_with_write8_handler, ACCESSING_MSB32 )
+
+
+#define READWRITE8TO32LE_MSB( name, read8, write8 ) \
+READ8TO32LE_MSB(name,read8) \
+WRITE8TO32LE_MSB(name,write8)
+
+
+/*************************************
+ * 8->32be, LSB mapping
+ ************************************/
+
+#define READ8TO32BE_LSB( name, read8 ) \
+READ_TEMPLATE_COND( 32, name, read8, read32be_with_read8_handler, ACCESSING_LSB32 )
+
+
+#define WRITE8TO32BE_LSB( name, write8 ) \
+WRITE_TEMPLATE_COND( 32, name, write8, write32be_with_write8_handler, ACCESSING_LSB32 )
+
+
+#define READWRITE8TO32BE_LSB( name, read8, write8 ) \
+READ8TO32BE_LSB(name,read8) \
+WRITE8TO32BE_LSB(name,write8)
+
+
+/*************************************
+ * 8->32le, LSB mapping
+ ************************************/
+
+#define READ8TO32LE_LSB( name, read8 ) \
+READ_TEMPLATE_COND( 32, name, read8, read32le_with_read8_handler, ACCESSING_LSB32 )
+
+
+#define WRITE8TO32LE_LSB( name, write8 ) \
+WRITE_TEMPLATE_COND( 32, name, write8, write32le_with_write8_handler, ACCESSING_LSB32 )
+
+
+#define READWRITE8TO32LE_LSB( name, read8, write8 ) \
+READ8TO32LE_LSB(name,read8) \
+WRITE8TO32LE_LSB(name,write8)
+
+
+/*************************************
+ * 8->64be, 1:1 mapping
+ ************************************/
+
+#define READ8TO64BE( name, read8 ) \
+READ_TEMPLATE( 64, name, read8, read64be_with_read8_handler )
+
+
+#define WRITE8TO64BE( name, write8 ) \
+WRITE_TEMPLATE( 64, name, write8, write64be_with_write8_handler )
+
+
+#define READWRITE8TO64BE( name, read8, write8 ) \
+READ8TO64BE(name,read8) \
+WRITE8TO64BE(name,write8)
+
+
+/*************************************
+ * 8->64le, 1:1 mapping
+ ************************************/
+
+#define READ8TO64LE( name, read8 ) \
+READ_TEMPLATE( 64, name, read8, read64le_with_read8_handler )
+
+
+#define WRITE8TO64LE( name, write8 ) \
+WRITE_TEMPLATE( 64, name, write8, write64le_with_write8_handler )
+
+
+#define READWRITE8TO64LE( name, read8, write8 ) \
+READ8TO64LE(name,read8) \
+WRITE8TO64LE(name,write8)
+
+
+/*************************************
+ * 16be->32be, 1:1 mapping
+ *************************************/
+
+#define READ16BETO32BE( name, read16 ) \
+READ_TEMPLATE( 32, name, read16, read32be_with_16be_handler )
+
+
+#define WRITE16BETO32BE( name, write16 ) \
+WRITE_TEMPLATE( 32, name, write16, write32be_with_16be_handler )
+
+
+#define READWRITE16BETO32BE( name, read16, write16 ) \
+READ16BETO32BE(name,read16) \
+WRITE16BETO32BE(name,write16)
+
+
+/*************************************
+ * 16le->32be, 1:1 mapping
+ *************************************/
+
+#define READ16LETO32BE( name, read16 ) \
+READ_TEMPLATE( 32, name, read16, read32be_with_16le_handler )
+
+
+#define WRITE16LETO32BE( name, write16 ) \
+WRITE_TEMPLATE( 32, name, write16, write32be_with_16le_handler )
+
+
+#define READWRITE16LETO32BE( name, read16, write16 ) \
+READ16LETO32BE(name,read16) \
+WRITE16LETO32BE(name,write16)
+
+
+/*************************************
+ * 16be->32le, 1:1 mapping
+ *************************************/
+
+#define READ16BETO32LE( name, read16 ) \
+READ_TEMPLATE( 32, name, read16, read32le_with_16be_handler )
+
+
+#define WRITE16BETO32LE( name, write16 ) \
+WRITE_TEMPLATE( 32, name, write16, write32le_with_16be_handler )
+
+
+#define READWRITE16BETO32LE( name, read16, write16 ) \
+READ16BETO32LE(name,read16) \
+WRITE16BETO32LE(name,write16)
+
+
+/*************************************
+ * 16le->32le, 1:1 mapping
+ *************************************/
+
+#define READ16LETO32LE( name, read16 ) \
+READ_TEMPLATE( 32, name, read16, read32le_with_16le_handler )
+
+
+#define WRITE16LETO32LE( name, write16 ) \
+WRITE_TEMPLATE( 32, name, write16, write32le_with_16le_handler )
+
+
+#define READWRITE16LETO32LE( name, read16, write16 ) \
+READ16LETO32LE(name,read16) \
+WRITE16LETO32LE(name,write16)
+
+
+/*************************************
+ * 16be->32be, MSW mapping
+ *************************************/
+
+#define READ16BETO32BE_MSW( name, read16 ) \
+READ_TEMPLATE_COND( 32, name, read16, read32be_with_16be_handler, ACCESSING_MSW32 )
+
+
+#define WRITE16BETO32BE_MSW( name, write16 ) \
+WRITE_TEMPLATE_COND( 32, name, write16, write32be_with_16be_handler, ACCESSING_MSW32 )
+
+
+#define READWRITE16BETO32BE_MSW( name, read16, write16 ) \
+READ16BETO32BE_MSW(name,read16) \
+WRITE16BETO32BE_MSW(name,write16)
+
+
+/*************************************
+ * 16le->32be, MSW mapping
+ *************************************/
+
+#define READ16LETO32BE_MSW( name, read16 ) \
+READ_TEMPLATE_COND( 32, name, read16, read32be_with_16le_handler, ACCESSING_MSW32 )
+
+
+#define WRITE16LETO32BE_MSW( name, write16 ) \
+WRITE_TEMPLATE_COND( 32, name, write16, write32be_with_16le_handler, ACCESSING_MSW32 )
+
+
+#define READWRITE16LETO32BE_MSW( name, read16, write16 ) \
+READ16LETO32BE_MSW(name,read16) \
+WRITE16LETO32BE_MSW(name,write16)
+
+
+/*************************************
+ * 16be->32le, MSW mapping
+ *************************************/
+
+#define READ16BETO32LE_MSW( name, read16 ) \
+READ_TEMPLATE_COND( 32, name, read16, read32le_with_16be_handler, ACCESSING_MSW32 )
+
+
+#define WRITE16BETO32LE_MSW( name, write16 ) \
+WRITE_TEMPLATE_COND( 32, name, write16, write32le_with_16be_handler, ACCESSING_MSW32 )
+
+
+#define READWRITE16BETO32LE_MSW( name, read16, write16 ) \
+READ16BETO32LE_MSW(name,read16) \
+WRITE16BETO32LE_MSW(name,write16)
+
+
+/*************************************
+ * 16le->32le, MSW mapping
+ *************************************/
+
+#define READ16LETO32LE_MSW( name, read16 ) \
+READ_TEMPLATE_COND( 32, name, read16, read32le_with_16le_handler, ACCESSING_MSW32 )
+
+
+#define WRITE16LETO32LE_MSW( name, write16 ) \
+WRITE_TEMPLATE_COND( 32, name, write16, write32le_with_16le_handler, ACCESSING_MSW32 )
+
+
+#define READWRITE16LETO32LE_MSW( name, read16, write16 ) \
+READ16LETO32LE_MSW(name,read16) \
+WRITE16LETO32LE_MSW(name,write16)
+
+/*************************************
+ * 16be->32be, LSW mapping
+ *************************************/
+
+#define READ16BETO32BE_LSW( name, read16 ) \
+READ_TEMPLATE_COND( 32, name, read16, read32be_with_16be_handler, ACCESSING_LSW32 )
+
+
+#define WRITE16BETO32BE_LSW( name, write16 ) \
+WRITE_TEMPLATE_COND( 32, name, write16, write32be_with_16be_handler, ACCESSING_LSW32 )
+
+
+#define READWRITE16BETO32BE_LSW( name, read16, write16 ) \
+READ16BETO32BE_LSW(name,read16) \
+WRITE16BETO32BE_LSW(name,write16)
+
+
+/*************************************
+ * 16le->32be, LSW mapping
+ *************************************/
+
+#define READ16LETO32BE_LSW( name, read16 ) \
+READ_TEMPLATE_COND( 32, name, read16, read32be_with_16le_handler, ACCESSING_LSW32 )
+
+
+#define WRITE16LETO32BE_LSW( name, write16 ) \
+WRITE_TEMPLATE_COND( 32, name, write16, write32be_with_16le_handler, ACCESSING_LSW32 )
+
+
+#define READWRITE16LETO32BE_LSW( name, read16, write16 ) \
+READ16LETO32BE_LSW(name,read16) \
+WRITE16LETO32BE_LSW(name,write16)
+
+
+/*************************************
+ * 16be->32le, LSW mapping
+ *************************************/
+
+#define READ16BETO32LE_LSW( name, read16 ) \
+READ_TEMPLATE_COND( 32, name, read16, read32le_with_16be_handler, ACCESSING_LSW32 )
+
+
+#define WRITE16BETO32LE_LSW( name, write16 ) \
+WRITE_TEMPLATE_COND( 32, name, write16, write32le_with_16be_handler, ACCESSING_LSW32 )
+
+
+#define READWRITE16BETO32LE_LSW( name, read16, write16 ) \
+READ16BETO32LE_LSW(name,read16) \
+WRITE16BETO32LE_LSW(name,write16)
+
+
+/*************************************
+ * 16le->32le, LSW mapping
+ *************************************/
+
+#define READ16LETO32LE_LSW( name, read16 ) \
+READ_TEMPLATE_COND( 32, name, read16, read32le_with_16le_handler, ACCESSING_LSW32 )
+
+
+#define WRITE16LETO32LE_LSW( name, write16 ) \
+WRITE_TEMPLATE_COND( 32, name, write16, write32le_with_16le_handler, ACCESSING_LSW32 )
+
+
+#define READWRITE16LETO32LE_LSW( name, read16, write16 ) \
+READ16LETO32LE_LSW(name,read16) \
+WRITE16LETO32LE_LSW(name,write16)
+
diff --git a/src/emu/memory.c b/src/emu/memory.c
new file mode 100644
index 00000000000..d8fdee22a21
--- /dev/null
+++ b/src/emu/memory.c
@@ -0,0 +1,3422 @@
+/***************************************************************************
+
+ memory.c
+
+ Functions which handle the CPU memory access.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ Caveats:
+
+ * If your driver executes an opcode which crosses a bank-switched
+ boundary, it will pull the wrong data out of memory. Although not
+ a common case, you may need to revert to memcpy to work around this.
+ See machine/tnzs.c for an example.
+
+ To do:
+
+ - Add local banks for RAM/ROM to reduce pressure on banking
+ - Always mirror everything out to 32 bits so we don't have to mask the address?
+ - Add the ability to start with another memory map and modify it
+ - Add fourth memory space for encrypted opcodes
+ - Automatically mirror program space into data space if no data space
+ - Get rid of opcode/data separation by using address spaces?
+ - Add support for internal addressing (maybe just accessors - see TMS3202x)
+ - Evaluate min/max opcode ranges and do we include a check in cpu_readop?
+
+****************************************************************************
+
+ Address map fields and restrictions:
+
+ AM_RANGE(start, end)
+ Specifies a range of consecutive addresses beginning with 'start' and
+ ending with 'end' inclusive. An address hits in this bucket if the
+ 'address' >= 'start' and 'address' <= 'end'.
+
+ AM_SPACE(match, mask)
+ Specifies at the bit level (closer to real hardware) how to determine
+ if an address matches a given bit pattern. An address hits in this
+ bucket if 'address' & 'mask' == 'match'
+
+ AM_MASK(mask)
+ Specifies a mask for the addresses in the current bucket. This mask
+ is applied after a positive hit in the bucket specified by AM_RANGE
+ or AM_SPACE, and is computed before accessing the RAM or calling
+ through to the read/write handler. If you use AM_SPACE, the mask
+ is implicitly set equal to the logical NOT of the mask specified in
+ the AM_SPACE macro. If you use AM_MIRROR, below, the mask is ANDed
+ implicitly with the logical NOT of the mirror. The mask specified
+ by this macro is ANDed against any implicit masks.
+
+ AM_MIRROR(mirror)
+ Specifies mirror addresses for the given bucket. The current bucket
+ is mapped repeatedly according to the mirror mask, once where each
+ mirror bit is 0, and once where it is 1. For example, a 'mirror'
+ value of 0x14000 would map the bucket at 0x00000, 0x04000, 0x10000,
+ and 0x14000.
+
+ AM_READ(read)
+ Specifies the read handler for this bucket. All reads will pass
+ through the given callback handler. Special static values representing
+ RAM, ROM, or BANKs are also allowed here.
+
+ AM_WRITE(write)
+ Specifies the write handler for this bucket. All writes will pass
+ through the given callback handler. Special static values representing
+ RAM, ROM, or BANKs are also allowed here.
+
+ AM_REGION(region, offs)
+ Only useful if AM_READ/WRITE point to RAM, ROM, or BANK memory. By
+ default, memory is allocated to back each bucket. By specifying
+ AM_REGION, you can tell the memory system to point the base of the
+ memory backing this bucket to a given memory 'region' at the
+ specified 'offs'.
+
+ AM_SHARE(index)
+ Similar to AM_REGION, this specifies that the memory backing the
+ current bucket is shared with other buckets. The first bucket to
+ specify the share 'index' will use its memory as backing for all
+ future buckets that specify AM_SHARE with the same 'index'.
+
+ AM_BASE(base)
+ Specifies a pointer to a pointer to the base of the memory backing
+ the current bucket.
+
+ AM_SIZE(size)
+ Specifies a pointer to a size_t variable which will be filled in
+ with the size, in bytes, of the current bucket.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+#ifdef MAME_DEBUG
+#include "debug/debugcpu.h"
+#endif
+#include <stdarg.h>
+
+
+#define MEM_DUMP (0)
+#define VERBOSE (0)
+#define ALLOW_ONLY_AUTO_MALLOC_BANKS 0
+
+
+#if VERBOSE
+#define VPRINTF(x) mame_printf_debug x
+#else
+#define VPRINTF(x)
+#endif
+
+
+
+/***************************************************************************
+
+ Basic theory of memory handling:
+
+ An address with up to 32 bits is passed to a memory handler. First,
+ an address mask is applied to the address, removing unused bits.
+
+ Next, the address is broken into two halves, an upper half and a
+ lower half. The number of bits in each half can be controlled via
+ macros in memory.h, but they default to the upper 18 bits and the
+ lower 14 bits. The upper half is then used as an index into the
+ base_lookup table.
+
+ If the value pulled from the table is within the range 192-255, then
+ the lower half of the address is needed to resolve the final handler.
+ The value from the table (192-255) is combined with the lower address
+ bits to form an index into a subtable.
+
+ Table values in the range 0-63 are reserved for internal handling
+ (such as RAM, ROM, NOP, and banking). Table values between 64 and 192
+ are assigned dynamically at startup.
+
+***************************************************************************/
+
+/* macros for the profiler */
+#define MEMREADSTART() do { profiler_mark(PROFILER_MEMREAD); } while (0)
+#define MEMREADEND(ret) do { profiler_mark(PROFILER_END); return ret; } while (0)
+#define MEMWRITESTART() do { profiler_mark(PROFILER_MEMWRITE); } while (0)
+#define MEMWRITEEND(ret) do { (ret); profiler_mark(PROFILER_END); return; } while (0)
+
+/* helper macros */
+#define HANDLER_IS_RAM(h) ((FPTR)(h) == STATIC_RAM)
+#define HANDLER_IS_ROM(h) ((FPTR)(h) == STATIC_ROM)
+#define HANDLER_IS_NOP(h) ((FPTR)(h) == STATIC_NOP)
+#define HANDLER_IS_BANK(h) ((FPTR)(h) >= STATIC_BANK1 && (FPTR)(h) <= STATIC_BANKMAX)
+#define HANDLER_IS_STATIC(h) ((FPTR)(h) < STATIC_COUNT)
+
+#define HANDLER_TO_BANK(h) ((FPTR)(h))
+#define BANK_TO_HANDLER(b) ((genf *)(FPTR)(b))
+
+#define SPACE_SHIFT(s,a) (((s)->ashift < 0) ? ((a) << -(s)->ashift) : ((a) >> (s)->ashift))
+#define SPACE_SHIFT_END(s,a) (((s)->ashift < 0) ? (((a) << -(s)->ashift) | ((1 << -(s)->ashift) - 1)) : ((a) >> (s)->ashift))
+#define INV_SPACE_SHIFT(s,a) (((s)->ashift < 0) ? ((a) >> -(s)->ashift) : ((a) << (s)->ashift))
+
+#define SUBTABLE_PTR(tabledata, entry) (&(tabledata)->table[(1 << LEVEL1_BITS) + (((entry) - SUBTABLE_BASE) << LEVEL2_BITS)])
+
+#ifdef MAME_DEBUG
+#define DEBUG_HOOK_READ(a,b,c) if (debug_hook_read) (*debug_hook_read)(a, b, c)
+#define DEBUG_HOOK_WRITE(a,b,c,d) if (debug_hook_write) (*debug_hook_write)(a, b, c, d)
+#else
+#define DEBUG_HOOK_READ(a,b,c)
+#define DEBUG_HOOK_WRITE(a,b,c,d)
+#endif
+
+
+/*-------------------------------------------------
+ TYPE DEFINITIONS
+-------------------------------------------------*/
+
+typedef struct _memory_block memory_block;
+struct _memory_block
+{
+ UINT8 cpunum; /* which CPU are we associated with? */
+ UINT8 spacenum; /* which address space are we associated with? */
+ UINT8 isallocated; /* did we allocate this ourselves? */
+ offs_t start, end; /* start/end or match/mask for verifying a match */
+ UINT8 * data; /* pointer to the data for this block */
+};
+
+typedef struct _bank_data bank_data;
+struct _bank_data
+{
+ UINT8 used; /* is this bank used? */
+ UINT8 dynamic; /* is this bank allocated dynamically? */
+ UINT8 cpunum; /* the CPU it is used for */
+ UINT8 spacenum; /* the address space it is used for */
+ UINT8 read; /* is this bank used for reads? */
+ UINT8 write; /* is this bank used for writes? */
+ offs_t base; /* the base offset */
+ offs_t end; /* the end offset */
+ UINT16 curentry; /* current entry */
+ void * entry[MAX_BANK_ENTRIES];/* array of entries for this bank */
+ void * entryd[MAX_BANK_ENTRIES];/* array of decrypted entries for this bank */
+};
+
+typedef union _rwhandlers rwhandlers;
+union _rwhandlers
+{
+ genf * generic; /* generic handler void */
+ read_handlers read; /* read handlers */
+ write_handlers write; /* write handlers */
+};
+
+/* In memory.h: typedef struct _handler_data handler_data */
+struct _handler_data
+{
+ rwhandlers handler; /* function pointer for handler */
+ offs_t offset; /* base offset for handler */
+ offs_t top; /* maximum offset for handler */
+ offs_t mask; /* mask against the final address */
+ const char * name; /* name of the handler */
+};
+
+typedef struct _subtable_data subtable_data;
+struct _subtable_data
+{
+ UINT8 checksum_valid; /* is the checksum valid */
+ UINT32 checksum; /* checksum over all the bytes */
+ UINT32 usecount; /* number of times this has been used */
+};
+
+typedef struct _table_data table_data;
+struct _table_data
+{
+ UINT8 * table; /* pointer to base of table */
+ UINT8 subtable_alloc; /* number of subtables allocated */
+ subtable_data subtable[SUBTABLE_COUNT]; /* info about each subtable */
+ handler_data handlers[ENTRY_COUNT]; /* array of user-installed handlers */
+};
+
+typedef struct _addrspace_data addrspace_data;
+struct _addrspace_data
+{
+ UINT8 cpunum; /* CPU index */
+ UINT8 spacenum; /* address space index */
+ INT8 ashift; /* address shift */
+ UINT8 abits; /* address bits */
+ UINT8 dbits; /* data bits */
+ offs_t rawmask; /* raw address mask, before adjusting to bytes */
+ offs_t mask; /* address mask */
+ UINT64 unmap; /* unmapped value */
+ table_data read; /* memory read lookup table */
+ table_data write; /* memory write lookup table */
+ data_accessors * accessors; /* pointer to the memory accessors */
+ address_map * map; /* original memory map */
+ address_map * adjmap; /* adjusted memory map */
+};
+
+typedef struct _cpu_data cpu_data;
+struct _cpu_data
+{
+ opbase_handler opbase; /* opcode base handler */
+
+ void * op_ram; /* dynamic RAM base pointer */
+ void * op_rom; /* dynamic ROM base pointer */
+ offs_t op_mask; /* dynamic ROM address mask */
+ offs_t op_mem_min; /* dynamic ROM/RAM min */
+ offs_t op_mem_max; /* dynamic ROM/RAM max */
+ UINT8 opcode_entry; /* opcode base handler */
+
+ UINT8 spacemask; /* mask of which address spaces are used */
+ addrspace_data space[ADDRESS_SPACES]; /* info about each address space */
+};
+
+
+/*-------------------------------------------------
+ GLOBAL VARIABLES
+-------------------------------------------------*/
+
+UINT8 * opcode_base; /* opcode base */
+UINT8 * opcode_arg_base; /* opcode argument base */
+offs_t opcode_mask; /* mask to apply to the opcode address */
+offs_t opcode_memory_min; /* opcode memory minimum */
+offs_t opcode_memory_max; /* opcode memory maximum */
+UINT8 opcode_entry; /* opcode readmem entry */
+
+address_space active_address_space[ADDRESS_SPACES];/* address space data */
+
+static UINT8 * bank_ptr[STATIC_COUNT]; /* array of bank pointers */
+static UINT8 * bankd_ptr[STATIC_COUNT]; /* array of decrypted bank pointers */
+static void * shared_ptr[MAX_SHARED_POINTERS];/* array of shared pointers */
+
+static memory_block memory_block_list[MAX_MEMORY_BLOCKS];/* array of memory blocks we are tracking */
+static int memory_block_count = 0; /* number of memory_block[] entries used */
+
+static int cur_context; /* current CPU context */
+
+static opbase_handler opbasefunc; /* opcode base override */
+
+static int debugger_access; /* treat accesses as coming from the debugger */
+static int log_unmap[ADDRESS_SPACES]; /* log unmapped memory accesses */
+
+static cpu_data cpudata[MAX_CPU]; /* data gathered for each CPU */
+static bank_data bankdata[STATIC_COUNT]; /* data gathered for each bank */
+
+#ifdef MAME_DEBUG
+static debug_hook_read_ptr debug_hook_read; /* pointer to debugger callback for memory reads */
+static debug_hook_write_ptr debug_hook_write; /* pointer to debugger callback for memory writes */
+#endif
+
+static data_accessors memory_accessors[ADDRESS_SPACES][4][2] =
+{
+ /* program accessors */
+ {
+ {
+ { program_read_byte_8, NULL, NULL, NULL, program_write_byte_8, NULL, NULL, NULL },
+ { program_read_byte_8, NULL, NULL, NULL, program_write_byte_8, NULL, NULL, NULL }
+ },
+ {
+ { program_read_byte_16le, program_read_word_16le, NULL, NULL, program_write_byte_16le, program_write_word_16le, NULL, NULL },
+ { program_read_byte_16be, program_read_word_16be, NULL, NULL, program_write_byte_16be, program_write_word_16be, NULL, NULL }
+ },
+ {
+ { program_read_byte_32le, program_read_word_32le, program_read_dword_32le, NULL, program_write_byte_32le, program_write_word_32le, program_write_dword_32le, NULL },
+ { program_read_byte_32be, program_read_word_32be, program_read_dword_32be, NULL, program_write_byte_32be, program_write_word_32be, program_write_dword_32be, NULL }
+ },
+ {
+ { program_read_byte_64le, program_read_word_64le, program_read_dword_64le, program_read_qword_64le, program_write_byte_64le, program_write_word_64le, program_write_dword_64le, program_write_qword_64le },
+ { program_read_byte_64be, program_read_word_64be, program_read_dword_64be, program_read_qword_64be, program_write_byte_64be, program_write_word_64be, program_write_dword_64be, program_write_qword_64be }
+ }
+ },
+
+ /* data accessors */
+ {
+ {
+ { data_read_byte_8, NULL, NULL, NULL, data_write_byte_8, NULL, NULL, NULL },
+ { data_read_byte_8, NULL, NULL, NULL, data_write_byte_8, NULL, NULL, NULL }
+ },
+ {
+ { data_read_byte_16le, data_read_word_16le, NULL, NULL, data_write_byte_16le, data_write_word_16le, NULL, NULL },
+ { data_read_byte_16be, data_read_word_16be, NULL, NULL, data_write_byte_16be, data_write_word_16be, NULL, NULL }
+ },
+ {
+ { data_read_byte_32le, data_read_word_32le, data_read_dword_32le, NULL, data_write_byte_32le, data_write_word_32le, data_write_dword_32le, NULL },
+ { data_read_byte_32be, data_read_word_32be, data_read_dword_32be, NULL, data_write_byte_32be, data_write_word_32be, data_write_dword_32be, NULL }
+ },
+ {
+ { data_read_byte_64le, data_read_word_64le, data_read_dword_64le, data_read_qword_64le, data_write_byte_64le, data_write_word_64le, data_write_dword_64le, data_write_qword_64le },
+ { data_read_byte_64be, data_read_word_64be, data_read_dword_64be, data_read_qword_64be, data_write_byte_64be, data_write_word_64be, data_write_dword_64be, data_write_qword_64be }
+ }
+ },
+
+ /* I/O accessors */
+ {
+ {
+ { io_read_byte_8, NULL, NULL, NULL, io_write_byte_8, NULL, NULL, NULL },
+ { io_read_byte_8, NULL, NULL, NULL, io_write_byte_8, NULL, NULL, NULL }
+ },
+ {
+ { io_read_byte_16le, io_read_word_16le, NULL, NULL, io_write_byte_16le, io_write_word_16le, NULL, NULL },
+ { io_read_byte_16be, io_read_word_16be, NULL, NULL, io_write_byte_16be, io_write_word_16be, NULL, NULL }
+ },
+ {
+ { io_read_byte_32le, io_read_word_32le, io_read_dword_32le, NULL, io_write_byte_32le, io_write_word_32le, io_write_dword_32le, NULL },
+ { io_read_byte_32be, io_read_word_32be, io_read_dword_32be, NULL, io_write_byte_32be, io_write_word_32be, io_write_dword_32be, NULL }
+ },
+ {
+ { io_read_byte_64le, io_read_word_64le, io_read_dword_64le, io_read_qword_64le, io_write_byte_64le, io_write_word_64le, io_write_dword_64le, io_write_qword_64le },
+ { io_read_byte_64be, io_read_word_64be, io_read_dword_64be, io_read_qword_64be, io_write_byte_64be, io_write_word_64be, io_write_dword_64be, io_write_qword_64be }
+ }
+ },
+};
+
+const char *address_space_names[ADDRESS_SPACES] = { "program", "data", "I/O" };
+
+
+/*-------------------------------------------------
+ FUNCTION PROTOTYPES
+-------------------------------------------------*/
+
+static void init_cpudata(void);
+static void init_addrspace(UINT8 cpunum, UINT8 spacenum);
+static void preflight_memory(void);
+static void populate_memory(void);
+static void install_mem_handler(addrspace_data *space, int iswrite, int databits, int ismatchmask, offs_t start, offs_t end, offs_t mask, offs_t mirror, genf *handler, int isfixed, const char *handler_name);
+static genf *assign_dynamic_bank(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mirror, int isfixed, int ismasked);
+static UINT8 get_handler_index(handler_data *table, genf *handler, const char *handler_name, offs_t start, offs_t end, offs_t mask);
+static void populate_table_range(addrspace_data *space, int iswrite, offs_t start, offs_t stop, UINT8 handler);
+static void populate_table_match(addrspace_data *space, int iswrite, offs_t matchval, offs_t matchmask, UINT8 handler);
+static UINT8 allocate_subtable(table_data *tabledata);
+static void reallocate_subtable(table_data *tabledata, UINT8 subentry);
+static int merge_subtables(table_data *tabledata);
+static void release_subtable(table_data *tabledata, UINT8 subentry);
+static UINT8 *open_subtable(table_data *tabledata, offs_t l1index);
+static void close_subtable(table_data *tabledata, offs_t l1index);
+static void allocate_memory(void);
+static void *allocate_memory_block(int cpunum, int spacenum, offs_t start, offs_t end, void *memory);
+static void register_for_save(int cpunum, int spacenum, offs_t start, void *base, size_t numbytes);
+static address_map *assign_intersecting_blocks(addrspace_data *space, offs_t start, offs_t end, UINT8 *base);
+static void find_memory(void);
+static void *memory_find_base(int cpunum, int spacenum, int readwrite, offs_t offset);
+static genf *get_static_handler(int databits, int readorwrite, int spacenum, int which);
+static void memory_exit(running_machine *machine);
+
+static void mem_dump(void)
+{
+ FILE *file;
+
+ if (MEM_DUMP)
+ {
+ file = fopen("memdump.log", "w");
+ if (file)
+ {
+ memory_dump(file);
+ fclose(file);
+ }
+ }
+}
+
+
+
+/*-------------------------------------------------
+ memory_init - initialize the memory system
+-------------------------------------------------*/
+
+void memory_init(running_machine *machine)
+{
+ int i;
+
+ for (i = 0; i < ADDRESS_SPACES; i++)
+ log_unmap[i] = 1;
+
+ /* no current context to start */
+ cur_context = -1;
+
+ /* reset the shared pointers and bank pointers */
+ memset(shared_ptr, 0, sizeof(shared_ptr));
+ memset(bank_ptr, 0, sizeof(bank_ptr));
+ memset(bankd_ptr, 0, sizeof(bankd_ptr));
+
+ /* reset our hardcoded and allocated pointer tracking */
+ memset(memory_block_list, 0, sizeof(memory_block_list));
+ memory_block_count = 0;
+
+ /* init the CPUs */
+ init_cpudata();
+ add_exit_callback(machine, memory_exit);
+
+ /* preflight the memory handlers and check banks */
+ preflight_memory();
+
+ /* then fill in the tables */
+ populate_memory();
+
+ /* allocate any necessary memory */
+ allocate_memory();
+
+ /* find all the allocated pointers */
+ find_memory();
+
+ /* dump the final memory configuration */
+ mem_dump();
+}
+
+
+/*-------------------------------------------------
+ memory_exit - free memory
+-------------------------------------------------*/
+
+static void memory_exit(running_machine *machine)
+{
+ int cpunum, spacenum;
+
+ /* free all the tables */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ {
+ if (cpudata[cpunum].space[spacenum].read.table)
+ free(cpudata[cpunum].space[spacenum].read.table);
+ if (cpudata[cpunum].space[spacenum].write.table)
+ free(cpudata[cpunum].space[spacenum].write.table);
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_set_context - set the memory context
+-------------------------------------------------*/
+
+void memory_set_context(int activecpu)
+{
+ /* remember dynamic RAM/ROM */
+ if (cur_context != -1)
+ {
+ cpudata[cur_context].op_ram = opcode_arg_base;
+ cpudata[cur_context].op_rom = opcode_base;
+ cpudata[cur_context].op_mask = opcode_mask;
+ cpudata[cur_context].op_mem_min = opcode_memory_min;
+ cpudata[cur_context].op_mem_max = opcode_memory_max;
+ cpudata[cur_context].opcode_entry = opcode_entry;
+ }
+ cur_context = activecpu;
+
+ opcode_arg_base = cpudata[activecpu].op_ram;
+ opcode_base = cpudata[activecpu].op_rom;
+ opcode_mask = cpudata[activecpu].op_mask;
+ opcode_memory_min = cpudata[activecpu].op_mem_min;
+ opcode_memory_max = cpudata[activecpu].op_mem_max;
+ opcode_entry = cpudata[activecpu].opcode_entry;
+
+ /* program address space */
+ active_address_space[ADDRESS_SPACE_PROGRAM].addrmask = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].mask;
+ active_address_space[ADDRESS_SPACE_PROGRAM].readlookup = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].read.table;
+ active_address_space[ADDRESS_SPACE_PROGRAM].writelookup = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].write.table;
+ active_address_space[ADDRESS_SPACE_PROGRAM].readhandlers = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].read.handlers;
+ active_address_space[ADDRESS_SPACE_PROGRAM].writehandlers = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].write.handlers;
+ active_address_space[ADDRESS_SPACE_PROGRAM].accessors = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].accessors;
+
+ /* data address space */
+ if (cpudata[activecpu].spacemask & (1 << ADDRESS_SPACE_DATA))
+ {
+ active_address_space[ADDRESS_SPACE_DATA].addrmask = cpudata[activecpu].space[ADDRESS_SPACE_DATA].mask;
+ active_address_space[ADDRESS_SPACE_DATA].readlookup = cpudata[activecpu].space[ADDRESS_SPACE_DATA].read.table;
+ active_address_space[ADDRESS_SPACE_DATA].writelookup = cpudata[activecpu].space[ADDRESS_SPACE_DATA].write.table;
+ active_address_space[ADDRESS_SPACE_DATA].readhandlers = cpudata[activecpu].space[ADDRESS_SPACE_DATA].read.handlers;
+ active_address_space[ADDRESS_SPACE_DATA].writehandlers = cpudata[activecpu].space[ADDRESS_SPACE_DATA].write.handlers;
+ active_address_space[ADDRESS_SPACE_DATA].accessors = cpudata[activecpu].space[ADDRESS_SPACE_DATA].accessors;
+ }
+
+ /* I/O address space */
+ if (cpudata[activecpu].spacemask & (1 << ADDRESS_SPACE_IO))
+ {
+ active_address_space[ADDRESS_SPACE_IO].addrmask = cpudata[activecpu].space[ADDRESS_SPACE_IO].mask;
+ active_address_space[ADDRESS_SPACE_IO].readlookup = cpudata[activecpu].space[ADDRESS_SPACE_IO].read.table;
+ active_address_space[ADDRESS_SPACE_IO].writelookup = cpudata[activecpu].space[ADDRESS_SPACE_IO].write.table;
+ active_address_space[ADDRESS_SPACE_IO].readhandlers = cpudata[activecpu].space[ADDRESS_SPACE_IO].read.handlers;
+ active_address_space[ADDRESS_SPACE_IO].writehandlers = cpudata[activecpu].space[ADDRESS_SPACE_IO].write.handlers;
+ active_address_space[ADDRESS_SPACE_IO].accessors = cpudata[activecpu].space[ADDRESS_SPACE_IO].accessors;
+ }
+
+ opbasefunc = cpudata[activecpu].opbase;
+
+#ifdef MAME_DEBUG
+ if (activecpu != -1)
+ debug_get_memory_hooks(activecpu, &debug_hook_read, &debug_hook_write);
+ else
+ {
+ debug_hook_read = NULL;
+ debug_hook_write = NULL;
+ }
+#endif
+}
+
+
+/*-------------------------------------------------
+ memory_get_map - return a pointer to a CPU's
+ memory map
+-------------------------------------------------*/
+
+const address_map *memory_get_map(int cpunum, int spacenum)
+{
+ return cpudata[cpunum].space[spacenum].map;
+}
+
+
+/*-------------------------------------------------
+ memory_set_opbase_handler - change op-code
+ memory base
+-------------------------------------------------*/
+
+opbase_handler memory_set_opbase_handler(int cpunum, opbase_handler function)
+{
+ opbase_handler old = cpudata[cpunum].opbase;
+ cpudata[cpunum].opbase = function;
+ if (cpunum == cpu_getactivecpu())
+ opbasefunc = function;
+ return old;
+}
+
+
+/*-------------------------------------------------
+ memory_set_opbase - generic opcode base changer
+-------------------------------------------------*/
+
+void memory_set_opbase(offs_t pc)
+{
+ address_space *space = &active_address_space[ADDRESS_SPACE_PROGRAM];
+
+ UINT8 *base = NULL, *based = NULL;
+ handler_data *handlers;
+ UINT8 entry;
+
+ /* allow overrides */
+ if (opbasefunc)
+ {
+ pc = (*opbasefunc)(pc);
+ if (pc == ~0)
+ return;
+ }
+
+ /* perform the lookup */
+ pc &= space->addrmask;
+ entry = space->readlookup[LEVEL1_INDEX(pc)];
+ if (entry >= SUBTABLE_BASE)
+ entry = space->readlookup[LEVEL2_INDEX(entry,pc)];
+ opcode_entry = entry;
+
+ /* if we don't map to a bank, see if there are any banks we can map to */
+ if (entry < STATIC_BANK1 || entry >= STATIC_RAM)
+ {
+ /* loop over banks and find a match */
+ for (entry = 1; entry < STATIC_COUNT; entry++)
+ {
+ bank_data *bdata = &bankdata[entry];
+ if (bdata->used && bdata->cpunum == cur_context && bdata->spacenum == ADDRESS_SPACE_PROGRAM &&
+ bdata->base < pc && bdata->end > pc)
+ break;
+ }
+
+ /* if nothing was found, leave everything alone */
+ if (entry == STATIC_COUNT)
+ {
+ logerror("cpu #%d (PC=%08X): warning - op-code execute on mapped I/O\n",
+ cpu_getactivecpu(), activecpu_get_pc());
+ return;
+ }
+ }
+
+ /* if no decrypted opcodes, point to the same base */
+ base = bank_ptr[entry];
+ based = bankd_ptr[entry];
+ if (!based)
+ based = base;
+
+ /* compute the adjusted base */
+ handlers = &active_address_space[ADDRESS_SPACE_PROGRAM].readhandlers[entry];
+ opcode_mask = handlers->mask;
+ opcode_arg_base = base - (handlers->offset & opcode_mask);
+ opcode_base = based - (handlers->offset & opcode_mask);
+ opcode_memory_min = handlers->offset;
+ opcode_memory_max = handlers->top;
+}
+
+
+/*-------------------------------------------------
+ memory_set_decrypted_region - sets the
+ decrypted region for the given CPU
+-------------------------------------------------*/
+
+void memory_set_decrypted_region(int cpunum, offs_t start, offs_t end, void *base)
+{
+ int banknum, found = FALSE;
+
+ /* loop over banks looking for a match */
+ for (banknum = 0; banknum < STATIC_COUNT; banknum++)
+ {
+ bank_data *bdata = &bankdata[banknum];
+ if (bdata->used && bdata->cpunum == cpunum && bdata->spacenum == ADDRESS_SPACE_PROGRAM && bdata->read)
+ {
+ if (bdata->base >= start && bdata->end <= end)
+ {
+ bankd_ptr[banknum] = (UINT8 *)base + bdata->base - start;
+ found = TRUE;
+
+ /* if this is live, adjust now */
+ if (cpu_getactivecpu() >= 0 && cpunum == cur_context && opcode_entry == banknum)
+ memory_set_opbase(activecpu_get_physical_pc_byte());
+ }
+ else if (bdata->base < end && bdata->end > start)
+ fatalerror("memory_set_decrypted_region found straddled region %08X-%08X for CPU %d", start, end, cpunum);
+ }
+ }
+
+ if (!found)
+ fatalerror("memory_set_decrypted_region unable to find matching region %08X-%08X for CPU %d", start, end, cpunum);
+}
+
+
+/*-------------------------------------------------
+ memory_get_read_ptr - return a pointer to the
+ base of RAM associated with the given CPU
+ and offset
+-------------------------------------------------*/
+
+void *memory_get_read_ptr(int cpunum, int spacenum, offs_t offset)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ UINT8 entry;
+
+ /* perform the lookup */
+ offset &= space->mask;
+ entry = space->read.table[LEVEL1_INDEX(offset)];
+ if (entry >= SUBTABLE_BASE)
+ entry = space->read.table[LEVEL2_INDEX(entry, offset)];
+
+ /* 8-bit case: RAM/ROM */
+ if (entry >= STATIC_RAM)
+ return NULL;
+ offset = (offset - space->read.handlers[entry].offset) & space->read.handlers[entry].mask;
+ return &bank_ptr[entry][offset];
+}
+
+
+/*-------------------------------------------------
+ memory_get_write_ptr - return a pointer to the
+ base of RAM associated with the given CPU
+ and offset
+-------------------------------------------------*/
+
+void *memory_get_write_ptr(int cpunum, int spacenum, offs_t offset)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ UINT8 entry;
+
+ /* perform the lookup */
+ offset &= space->mask;
+ entry = space->write.table[LEVEL1_INDEX(offset)];
+ if (entry >= SUBTABLE_BASE)
+ entry = space->write.table[LEVEL2_INDEX(entry, offset)];
+
+ /* 8-bit case: RAM/ROM */
+ if (entry >= STATIC_RAM)
+ return NULL;
+ offset = (offset - space->write.handlers[entry].offset) & space->write.handlers[entry].mask;
+ return &bank_ptr[entry][offset];
+}
+
+
+/*-------------------------------------------------
+ memory_get_op_ptr - return a pointer to the
+ base of opcode RAM associated with the given
+ CPU and offset
+-------------------------------------------------*/
+
+void *memory_get_op_ptr(int cpunum, offs_t offset, int arg)
+{
+ addrspace_data *space = &cpudata[cpunum].space[ADDRESS_SPACE_PROGRAM];
+ void *ptr = NULL;
+ UINT8 entry;
+
+ /* if there is a custom mapper, use that */
+ if (cpudata[cpunum].opbase != NULL)
+ {
+ /* need to save opcode info */
+ UINT8 *saved_opcode_base = opcode_base;
+ UINT8 *saved_opcode_arg_base = opcode_arg_base;
+ offs_t saved_opcode_mask = opcode_mask;
+ offs_t saved_opcode_memory_min = opcode_memory_min;
+ offs_t saved_opcode_memory_max = opcode_memory_max;
+ UINT8 saved_opcode_entry = opcode_entry;
+
+ /* query the handler */
+ offs_t new_offset = (*cpudata[cpunum].opbase)(offset);
+
+ /* if it returns ~0, we use whatever data the handler set */
+ if (new_offset == ~0)
+ ptr = arg ? &opcode_arg_base[offset] : &opcode_base[offset];
+
+ /* otherwise, we use the new offset in the generic case below */
+ else
+ offset = new_offset;
+
+ /* restore opcode info */
+ opcode_base = saved_opcode_base;
+ opcode_arg_base = saved_opcode_arg_base;
+ opcode_mask = saved_opcode_mask;
+ opcode_memory_min = saved_opcode_memory_min;
+ opcode_memory_max = saved_opcode_memory_max;
+ opcode_entry = saved_opcode_entry;
+
+ /* if we got our pointer, we're done */
+ if (ptr != NULL)
+ return ptr;
+ }
+
+ /* perform the lookup */
+ offset &= space->mask;
+ entry = space->read.table[LEVEL1_INDEX(offset)];
+ if (entry >= SUBTABLE_BASE)
+ entry = space->read.table[LEVEL2_INDEX(entry, offset)];
+
+ /* if a non-RAM area, return NULL */
+ if (entry >= STATIC_RAM)
+ return NULL;
+
+ /* adjust the offset */
+ offset = (offset - space->read.handlers[entry].offset) & space->read.handlers[entry].mask;
+ return (!arg && bankd_ptr[entry]) ? &bankd_ptr[entry][offset] : &bank_ptr[entry][offset];
+}
+
+
+/*-------------------------------------------------
+ memory_configure_bank - configure the
+ addresses for a bank
+-------------------------------------------------*/
+
+void memory_configure_bank(int banknum, int startentry, int numentries, void *base, offs_t stride)
+{
+ int entrynum;
+
+ /* validation checks */
+ if (banknum < STATIC_BANK1 || banknum > MAX_EXPLICIT_BANKS || !bankdata[banknum].used)
+ fatalerror("memory_configure_bank called with invalid bank %d", banknum);
+ if (bankdata[banknum].dynamic)
+ fatalerror("memory_configure_bank called with dynamic bank %d", banknum);
+ if (startentry < 0 || startentry + numentries > MAX_BANK_ENTRIES)
+ fatalerror("memory_configure_bank called with out-of-range entries %d-%d", startentry, startentry + numentries - 1);
+ if (!base)
+ fatalerror("memory_configure_bank called NULL base");
+
+ /* fill in the requested bank entries */
+ for (entrynum = startentry; entrynum < startentry + numentries; entrynum++)
+ bankdata[banknum].entry[entrynum] = (UINT8 *)base + (entrynum - startentry) * stride;
+}
+
+
+
+/*-------------------------------------------------
+ memory_configure_bank_decrypted - configure
+ the decrypted addresses for a bank
+-------------------------------------------------*/
+
+void memory_configure_bank_decrypted(int banknum, int startentry, int numentries, void *base, offs_t stride)
+{
+ int entrynum;
+
+ /* validation checks */
+ if (banknum < STATIC_BANK1 || banknum > MAX_EXPLICIT_BANKS || !bankdata[banknum].used)
+ fatalerror("memory_configure_bank called with invalid bank %d", banknum);
+ if (bankdata[banknum].dynamic)
+ fatalerror("memory_configure_bank called with dynamic bank %d", banknum);
+ if (startentry < 0 || startentry + numentries > MAX_BANK_ENTRIES)
+ fatalerror("memory_configure_bank called with out-of-range entries %d-%d", startentry, startentry + numentries - 1);
+ if (!base)
+ fatalerror("memory_configure_bank_decrypted called NULL base");
+
+ /* fill in the requested bank entries */
+ for (entrynum = startentry; entrynum < startentry + numentries; entrynum++)
+ bankdata[banknum].entryd[entrynum] = (UINT8 *)base + (entrynum - startentry) * stride;
+}
+
+
+
+/*-------------------------------------------------
+ memory_set_bank - set the base of a bank
+-------------------------------------------------*/
+
+void memory_set_bank(int banknum, int entrynum)
+{
+ /* validation checks */
+ if (banknum < STATIC_BANK1 || banknum > MAX_EXPLICIT_BANKS || !bankdata[banknum].used)
+ fatalerror("memory_set_bank called with invalid bank %d", banknum);
+ if (bankdata[banknum].dynamic)
+ fatalerror("memory_set_bank called with dynamic bank %d", banknum);
+ if (entrynum < 0 || entrynum > MAX_BANK_ENTRIES)
+ fatalerror("memory_set_bank called with out-of-range entry %d", entrynum);
+ if (!bankdata[banknum].entry[entrynum])
+ fatalerror("memory_set_bank called for bank %d with invalid bank entry %d", banknum, entrynum);
+
+ /* set the base */
+ bankdata[banknum].curentry = entrynum;
+ bank_ptr[banknum] = bankdata[banknum].entry[entrynum];
+ bankd_ptr[banknum] = bankdata[banknum].entryd[entrynum];
+
+ /* if we're executing out of this bank, adjust the opbase pointer */
+ if (opcode_entry == banknum && cpu_getactivecpu() >= 0)
+ {
+ opcode_entry = 0xff;
+ memory_set_opbase(activecpu_get_physical_pc_byte());
+ }
+}
+
+
+
+/*-------------------------------------------------
+ memory_set_bankptr - set the base of a bank
+-------------------------------------------------*/
+
+void memory_set_bankptr(int banknum, void *base)
+{
+ /* validation checks */
+ if (banknum < STATIC_BANK1 || banknum > MAX_EXPLICIT_BANKS || !bankdata[banknum].used)
+ fatalerror("memory_set_bankptr called with invalid bank %d", banknum);
+ if (bankdata[banknum].dynamic)
+ fatalerror("memory_set_bankptr called with dynamic bank %d", banknum);
+ if (base == NULL)
+ fatalerror("memory_set_bankptr called NULL base");
+ if (ALLOW_ONLY_AUTO_MALLOC_BANKS)
+ validate_auto_malloc_memory(base, bankdata[banknum].end - bankdata[banknum].base + 1);
+
+ /* set the base */
+ bank_ptr[banknum] = base;
+
+ /* if we're executing out of this bank, adjust the opbase pointer */
+ if (opcode_entry == banknum && cpu_getactivecpu() >= 0)
+ {
+ opcode_entry = 0xff;
+ memory_set_opbase(activecpu_get_physical_pc_byte());
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_set_debugger_access - set debugger access
+-------------------------------------------------*/
+
+void memory_set_debugger_access(int debugger)
+{
+ debugger_access = debugger;
+}
+
+
+/*-------------------------------------------------
+ memory_set_log_unmap - sets whether unmapped
+ memory accesses should be logged or not
+-------------------------------------------------*/
+
+void memory_set_log_unmap(int spacenum, int log)
+{
+ log_unmap[spacenum] = log;
+}
+
+
+/*-------------------------------------------------
+ memory_get_log_unmap - gets whether unmapped
+ memory accesses should be logged or not
+-------------------------------------------------*/
+
+int memory_get_log_unmap(int spacenum)
+{
+ return log_unmap[spacenum];
+}
+
+
+/*-------------------------------------------------
+ memory_install_readX_handler - install dynamic
+ read handler for X-bit case
+-------------------------------------------------*/
+
+void *_memory_install_read_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ if ((handler < 0) || (handler >= STATIC_COUNT))
+ fatalerror("fatal: can only use static banks with memory_install_read_handler()");
+ install_mem_handler(space, 0, space->dbits, 0, start, end, mask, mirror, (genf *)(FPTR)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start));
+}
+
+UINT8 *_memory_install_read8_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 0, 8, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start));
+}
+
+UINT16 *_memory_install_read16_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 0, 16, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start));
+}
+
+UINT32 *_memory_install_read32_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read32_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 0, 32, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start));
+}
+
+UINT64 *_memory_install_read64_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read64_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 0, 64, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start));
+}
+
+
+/*-------------------------------------------------
+ memory_install_writeX_handler - install dynamic
+ write handler for X-bit case
+-------------------------------------------------*/
+
+void *_memory_install_write_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ if ((handler < 0) || (handler >= STATIC_COUNT))
+ fatalerror("fatal: can only use static banks with memory_install_write_handler()");
+ install_mem_handler(space, 1, space->dbits, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start));
+}
+
+UINT8 *_memory_install_write8_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write8_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 1, 8, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start));
+}
+
+UINT16 *_memory_install_write16_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write16_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 1, 16, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start));
+}
+
+UINT32 *_memory_install_write32_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write32_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 1, 32, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start));
+}
+
+UINT64 *_memory_install_write64_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write64_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 1, 64, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start));
+}
+
+
+/*-------------------------------------------------
+ memory_install_readX_matchmask_handler -
+ install dynamic match/mask read handler for
+ X-bit case
+-------------------------------------------------*/
+
+void *_memory_install_read_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ if ((handler < 0) || (handler >= STATIC_COUNT))
+ fatalerror("fatal: can only use static banks with memory_install_read_matchmask_handler()");
+ install_mem_handler(space, 0, space->dbits, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval));
+}
+
+UINT8 *_memory_install_read8_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read8_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 0, 8, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval));
+}
+
+UINT16 *_memory_install_read16_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read16_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 0, 16, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval));
+}
+
+UINT32 *_memory_install_read32_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read32_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 0, 32, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval));
+}
+
+UINT64 *_memory_install_read64_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read64_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 0, 64, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval));
+}
+
+
+/*-------------------------------------------------
+ memory_install_writeX_matchmask_handler -
+ install dynamic match/mask write handler for
+ X-bit case
+-------------------------------------------------*/
+
+void *_memory_install_write_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ if ((handler < 0) || (handler >= STATIC_COUNT))
+ fatalerror("fatal: can only use static banks with memory_install_write_matchmask_handler()");
+ install_mem_handler(space, 1, space->dbits, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval));
+}
+
+UINT8 *_memory_install_write8_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write8_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 1, 8, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval));
+}
+
+UINT16 *_memory_install_write16_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write16_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 1, 16, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval));
+}
+
+UINT32 *_memory_install_write32_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write32_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 1, 32, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval));
+}
+
+UINT64 *_memory_install_write64_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write64_handler handler, const char *handler_name)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ install_mem_handler(space, 1, 64, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name);
+ mem_dump();
+ return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval));
+}
+
+
+/*-------------------------------------------------
+ construct_address_map - build address map
+-------------------------------------------------*/
+
+void construct_address_map(address_map *map, const machine_config *drv, int cpunum, int spacenum)
+{
+ int cputype = drv->cpu[cpunum].type;
+ construct_map_t internal_map = (construct_map_t)cputype_get_info_fct(cputype, CPUINFO_PTR_INTERNAL_MEMORY_MAP + spacenum);
+
+ map->flags = AM_FLAGS_END;
+
+ /* start by constructing the internal CPU map */
+ if (internal_map)
+ map = (*internal_map)(map);
+
+ /* construct the standard map */
+ if (drv->cpu[cpunum].construct_map[spacenum][0])
+ map = (*drv->cpu[cpunum].construct_map[spacenum][0])(map);
+ if (drv->cpu[cpunum].construct_map[spacenum][1])
+ map = (*drv->cpu[cpunum].construct_map[spacenum][1])(map);
+}
+
+
+/*-------------------------------------------------
+ init_cpudata - initialize the cpudata
+ structure for each CPU
+-------------------------------------------------*/
+
+static void init_cpudata(void)
+{
+ int cpunum, spacenum;
+
+ /* zap the cpudata structure */
+ memset(&cpudata, 0, sizeof(cpudata));
+
+ /* loop over CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ {
+ /* set the RAM/ROM base */
+ cpudata[cpunum].op_ram = cpudata[cpunum].op_rom = memory_region(REGION_CPU1 + cpunum);
+ cpudata[cpunum].op_mem_max = memory_region_length(REGION_CPU1 + cpunum);
+ cpudata[cpunum].op_mem_min = 0;
+ cpudata[cpunum].opcode_entry = STATIC_UNMAP;
+ cpudata[cpunum].opbase = NULL;
+
+ /* TODO: make this dynamic */
+ cpudata[cpunum].spacemask = 0;
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ init_addrspace(cpunum, spacenum);
+ cpudata[cpunum].op_mask = cpudata[cpunum].space[ADDRESS_SPACE_PROGRAM].mask;
+ }
+}
+
+
+/*-------------------------------------------------
+ adjust_addresses - adjust addresses for a
+ given address space in a standard fashion
+-------------------------------------------------*/
+
+INLINE void adjust_addresses(addrspace_data *space, int ismatchmask, offs_t *start, offs_t *end, offs_t *mask, offs_t *mirror)
+{
+ /* adjust start/end/mask values */
+ if (*mask == 0)
+ *mask = space->rawmask & ~*mirror;
+ else
+ *mask &= space->rawmask;
+ *start &= ~*mirror & space->rawmask;
+ *end &= ~*mirror & space->rawmask;
+
+ /* adjust to byte values */
+ *mask = SPACE_SHIFT(space, *mask);
+ *start = SPACE_SHIFT(space, *start);
+ *end = ismatchmask ? SPACE_SHIFT(space, *end) : SPACE_SHIFT_END(space, *end);
+ *mirror = SPACE_SHIFT(space, *mirror);
+}
+
+
+/*-------------------------------------------------
+ init_addrspace - initialize the address space
+ data structure
+-------------------------------------------------*/
+
+static void init_addrspace(UINT8 cpunum, UINT8 spacenum)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ cpu_type cputype = Machine->drv->cpu[cpunum].type;
+ int abits = cputype_addrbus_width(cputype, spacenum);
+ int dbits = cputype_databus_width(cputype, spacenum);
+ int accessorindex = (dbits == 8) ? 0 : (dbits == 16) ? 1 : (dbits == 32) ? 2 : 3;
+ int entrynum;
+
+ /* determine the address and data bits */
+ space->cpunum = cpunum;
+ space->spacenum = spacenum;
+ space->ashift = cputype_addrbus_shift(cputype, spacenum);
+ space->abits = abits - space->ashift;
+ space->dbits = dbits;
+ space->rawmask = 0xffffffffUL >> (32 - abits);
+ space->mask = SPACE_SHIFT_END(space, space->rawmask);
+ space->accessors = &memory_accessors[spacenum][accessorindex][cputype_endianness(cputype) == CPU_IS_LE ? 0 : 1];
+ space->map = NULL;
+ space->adjmap = NULL;
+
+ /* if there's nothing here, just punt */
+ if (space->abits == 0)
+ return;
+ cpudata[cpunum].spacemask |= 1 << spacenum;
+
+ /* construct the combined memory map */
+ {
+ /* allocate and clear memory for 2 copies of the map */
+ address_map *map = auto_malloc(sizeof(space->map[0]) * MAX_ADDRESS_MAP_SIZE * 4);
+ memset(map, 0, sizeof(space->map[0]) * MAX_ADDRESS_MAP_SIZE * 4);
+
+ /* make pointers to the standard and adjusted maps */
+ space->map = map;
+ space->adjmap = &map[MAX_ADDRESS_MAP_SIZE * 2];
+
+ construct_address_map(map, Machine->drv, cpunum, spacenum);
+
+ /* convert implicit ROM entries to map to the memory region */
+ if (spacenum == ADDRESS_SPACE_PROGRAM && memory_region(REGION_CPU1 + cpunum))
+ for (map = space->map; !IS_AMENTRY_END(map); map++)
+ if (!IS_AMENTRY_EXTENDED(map) && HANDLER_IS_ROM(map->read.handler) && !map->region)
+ {
+ offs_t end = SPACE_SHIFT_END(space, map->end);
+
+ /* make sure they fit within the memory region before doing so, however */
+ if (end < memory_region_length(REGION_CPU1 + cpunum))
+ {
+ map->region = REGION_CPU1 + cpunum;
+ map->region_offs = SPACE_SHIFT(space, map->start);
+ }
+ }
+
+ /* convert region-relative entries to their memory pointers */
+ for (map = space->map; !IS_AMENTRY_END(map); map++)
+ if (map->region)
+ map->memory = memory_region(map->region) + map->region_offs;
+
+ /* make the adjusted map */
+ memcpy(space->adjmap, space->map, sizeof(space->map[0]) * MAX_ADDRESS_MAP_SIZE * 2);
+ for (map = space->adjmap; !IS_AMENTRY_END(map); map++)
+ if (!IS_AMENTRY_EXTENDED(map))
+ adjust_addresses(space, IS_AMENTRY_MATCH_MASK(map), &map->start, &map->end, &map->mask, &map->mirror);
+
+ /* validate adjusted addresses against implicit regions */
+ for (map = space->adjmap; !IS_AMENTRY_END(map); map++)
+ if (map->region && map->share == 0 && !map->base)
+ {
+ UINT8 *base = memory_region(map->region);
+ offs_t length = memory_region_length(map->region);
+
+ /* validate the region */
+ if (!base)
+ fatalerror("Error: CPU %d space %d memory map entry %X-%X references non-existant region %d", cpunum, spacenum, map->start, map->end, map->region);
+ if (map->region_offs + (map->end - map->start + 1) > length)
+ fatalerror("Error: CPU %d space %d memory map entry %X-%X extends beyond region %d size (%X)", cpunum, spacenum, map->start, map->end, map->region, length);
+ }
+ }
+
+ /* init the static handlers */
+ memset(space->read.handlers, 0, sizeof(space->read.handlers));
+ memset(space->write.handlers, 0, sizeof(space->write.handlers));
+ for (entrynum = 0; entrynum < ENTRY_COUNT; entrynum++)
+ {
+ space->read.handlers[entrynum].handler.generic = get_static_handler(dbits, 0, spacenum, entrynum);
+ space->read.handlers[entrynum].mask = space->mask;
+ space->write.handlers[entrynum].handler.generic = get_static_handler(dbits, 1, spacenum, entrynum);
+ space->write.handlers[entrynum].mask = space->mask;
+ }
+
+ /* allocate memory */
+ space->read.table = malloc_or_die(1 << LEVEL1_BITS);
+ space->write.table = malloc_or_die(1 << LEVEL1_BITS);
+
+ /* initialize everything to unmapped */
+ memset(space->read.table, STATIC_UNMAP, 1 << LEVEL1_BITS);
+ memset(space->write.table, STATIC_UNMAP, 1 << LEVEL1_BITS);
+}
+
+
+/*-------------------------------------------------
+ preflight_memory - verify the memory structs
+ and track which banks are referenced
+-------------------------------------------------*/
+
+static void preflight_memory(void)
+{
+ int cpunum, spacenum, entrynum;
+
+ /* zap the bank data */
+ memset(&bankdata, 0, sizeof(bankdata));
+
+ /* loop over CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ if (cpudata[cpunum].spacemask & (1 << spacenum))
+ {
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ const address_map *map;
+
+ /* scan the adjusted map */
+ for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++)
+ {
+ /* look for extended flags */
+ if (IS_AMENTRY_EXTENDED(map))
+ {
+ UINT32 flags = AM_EXTENDED_FLAGS(map);
+ UINT32 val;
+
+ /* if we specify an address space, make sure it matches the current space */
+ if (flags & AMEF_SPECIFIES_SPACE)
+ {
+ val = (flags & AMEF_SPACE_MASK) >> AMEF_SPACE_SHIFT;
+ if (val != spacenum)
+ fatalerror("cpu #%d has address space %d handlers in place of address space %d handlers!", cpunum, val, spacenum);
+ }
+
+ /* if we specify an databus width, make sure it matches the current address space's */
+ if (flags & AMEF_SPECIFIES_DBITS)
+ {
+ val = (flags & AMEF_DBITS_MASK) >> AMEF_DBITS_SHIFT;
+ val = (val + 1) * 8;
+ if (val != space->dbits)
+ fatalerror("cpu #%d uses wrong %d-bit handlers for address space %d (should be %d-bit)!", cpunum, val, spacenum, space->dbits);
+ }
+
+ /* if we specify an addressbus width, adjust the mask */
+ if (flags & AMEF_SPECIFIES_ABITS)
+ {
+ space->rawmask = 0xffffffffUL >> (32 - ((flags & AMEF_ABITS_MASK) >> AMEF_ABITS_SHIFT));
+ space->mask = SPACE_SHIFT_END(space, space->rawmask);
+ }
+
+ /* if we specify an unmap value, set it */
+ if (flags & AMEF_SPECIFIES_UNMAP)
+ space->unmap = ((flags & AMEF_UNMAP_MASK) == 0) ? (UINT64)0 : (UINT64)-1;
+ }
+
+ /* otherwise, just track banks and hardcoded memory pointers */
+ else
+ {
+ int bank = -1;
+
+ /* look for a bank handler in eithe read or write */
+ if (HANDLER_IS_BANK(map->read.handler))
+ bank = HANDLER_TO_BANK(map->read.handler);
+ else if (HANDLER_IS_BANK(map->write.handler))
+ bank = HANDLER_TO_BANK(map->write.handler);
+
+ /* if we got one, add the data */
+ if (bank >= 1 && bank <= MAX_EXPLICIT_BANKS)
+ {
+ bank_data *bdata = &bankdata[bank];
+
+ /* wire up state saving for the entry the first time we see it */
+ if (!bdata->used)
+ state_save_register_item("memory", bank, bdata->curentry);
+
+ bdata->used = TRUE;
+ bdata->dynamic = FALSE;
+ bdata->cpunum = cpunum;
+ bdata->spacenum = spacenum;
+ if (bank == HANDLER_TO_BANK(map->read.handler))
+ bdata->read = TRUE;
+ if (bank == HANDLER_TO_BANK(map->write.handler))
+ bdata->write = TRUE;
+ bdata->base = map->start;
+ bdata->end = map->end;
+ bdata->curentry = MAX_BANK_ENTRIES;
+ }
+ }
+ }
+
+ /* now loop over all the handlers and enforce the address mask (which may have changed) */
+ for (entrynum = 0; entrynum < ENTRY_COUNT; entrynum++)
+ {
+ space->read.handlers[entrynum].mask &= space->mask;
+ space->write.handlers[entrynum].mask &= space->mask;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ populate_memory - populate the memory mapping
+ tables with entries
+-------------------------------------------------*/
+
+static void populate_memory(void)
+{
+ int cpunum, spacenum;
+
+ /* loop over CPUs and address spaces */
+ for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ if (cpudata[cpunum].spacemask & (1 << spacenum))
+ {
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ const address_map *map;
+
+ /* install the handlers, using the original, unadjusted memory map */
+ if (space->map != NULL)
+ {
+ /* first find the end */
+ for (map = space->map; !IS_AMENTRY_END(map); map++) ;
+
+ /* then work backwards, populating the address map */
+ for (map--; map >= space->map; map--)
+ if (!IS_AMENTRY_EXTENDED(map))
+ {
+ int ismatchmask = ((map->flags & AM_FLAGS_MATCH_MASK) != 0);
+ int isfixed = (map->memory != NULL) || (map->share != 0);
+ if (map->read.handler != NULL)
+ install_mem_handler(space, 0, space->dbits, ismatchmask, map->start, map->end, map->mask, map->mirror, map->read.handler, isfixed, map->read_name);
+ if (map->write.handler != NULL)
+ install_mem_handler(space, 1, space->dbits, ismatchmask, map->start, map->end, map->mask, map->mirror, map->write.handler, isfixed, map->write_name);
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ install_mem_handler - installs a handler for
+ memory operations
+-------------------------------------------------*/
+
+static void install_mem_handler(addrspace_data *space, int iswrite, int databits, int ismatchmask, offs_t start, offs_t end, offs_t mask, offs_t mirror, genf *handler, int isfixed, const char *handler_name)
+{
+ offs_t lmirrorbit[LEVEL2_BITS], lmirrorbits, hmirrorbit[32 - LEVEL2_BITS], hmirrorbits, lmirrorcount, hmirrorcount;
+ table_data *tabledata = iswrite ? &space->write : &space->read;
+ UINT8 idx, prev_entry = STATIC_INVALID;
+ int cur_index, prev_index = 0;
+ int ismasked = (mask != 0);
+ int i;
+
+ /* sanity check */
+ if (space->dbits != databits)
+ fatalerror("fatal: install_mem_handler called with a %d-bit handler for a %d-bit address space", databits, space->dbits);
+ if (start > end)
+ fatalerror("fatal: install_mem_handler called with start greater than end");
+
+ /* if we're installing a new bank, make sure we mark it */
+ if (HANDLER_IS_BANK(handler))
+ {
+ bank_data *bdata = &bankdata[HANDLER_TO_BANK(handler)];
+
+ /* if this is the first time we've seen this bank, create a new entry */
+ if (!bdata->used)
+ {
+ bdata->used = TRUE;
+ bdata->dynamic = FALSE;
+ bdata->cpunum = space->cpunum;
+ bdata->spacenum = space->spacenum;
+ bdata->base = start;
+ bdata->end = end;
+ bdata->curentry = MAX_BANK_ENTRIES;
+
+ /* if we're allowed to, wire up state saving for the entry */
+ if (state_save_registration_allowed())
+ state_save_register_item("memory", HANDLER_TO_BANK(handler), bdata->curentry);
+
+ VPRINTF(("Allocated new bank %d\n", HANDLER_TO_BANK(handler)));
+ }
+ }
+
+ /* adjust the incoming addresses */
+ adjust_addresses(space, ismatchmask, &start, &end, &mask, &mirror);
+
+ /* sanity check */
+ if (HANDLER_IS_RAM(handler))
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "RAM/ROM memory handlers can only be installed at init time");
+
+ /* translate ROM to RAM/UNMAP here */
+ if (HANDLER_IS_ROM(handler))
+ handler = iswrite ? (genf *)STATIC_UNMAP : (genf *)MRA8_RAM;
+
+ /* assign banks for RAM/ROM areas */
+ if (HANDLER_IS_RAM(handler))
+ {
+ handler = (genf *)assign_dynamic_bank(space->cpunum, space->spacenum, start, end, mirror, isfixed, ismasked);
+ if (!bank_ptr[HANDLER_TO_BANK(handler)])
+ bank_ptr[HANDLER_TO_BANK(handler)] = memory_find_base(space->cpunum, space->spacenum, iswrite, start);
+ }
+
+ /* if this ended up a bank handler, tag it for reads or writes */
+ if (HANDLER_IS_BANK(handler))
+ {
+ bank_data *bdata = &bankdata[HANDLER_TO_BANK(handler)];
+
+ /* track whether reads or writes are going here */
+ if (!iswrite)
+ bdata->read = TRUE;
+ else
+ bdata->write = TRUE;
+ }
+
+ /* determine the mirror bits */
+ hmirrorbits = lmirrorbits = 0;
+ for (i = 0; i < LEVEL2_BITS; i++)
+ if (mirror & (1 << i))
+ lmirrorbit[lmirrorbits++] = 1 << i;
+ for (i = LEVEL2_BITS; i < 32; i++)
+ if (mirror & (1 << i))
+ hmirrorbit[hmirrorbits++] = 1 << i;
+
+ /* get the final handler index */
+ idx = get_handler_index(tabledata->handlers, handler, handler_name, start, end, mask);
+
+ /* loop over mirrors in the level 2 table */
+ for (hmirrorcount = 0; hmirrorcount < (1 << hmirrorbits); hmirrorcount++)
+ {
+ /* compute the base of this mirror */
+ offs_t hmirrorbase = 0;
+ for (i = 0; i < hmirrorbits; i++)
+ if (hmirrorcount & (1 << i))
+ hmirrorbase |= hmirrorbit[i];
+
+ /* if this is not our first time through, and the level 2 entry matches the previous
+ level 2 entry, just do a quick map and get out; note that this only works for entries
+ which don't span multiple level 1 table entries */
+ cur_index = LEVEL1_INDEX(start + hmirrorbase);
+ if (cur_index == LEVEL1_INDEX(end + hmirrorbase))
+ {
+ if (hmirrorcount != 0 && prev_entry == tabledata->table[cur_index])
+ {
+ VPRINTF(("Quick mapping subtable at %08X to match subtable at %08X\n", cur_index << LEVEL2_BITS, prev_index << LEVEL2_BITS));
+
+ /* release the subtable if the old value was a subtable */
+ if (tabledata->table[cur_index] >= SUBTABLE_BASE)
+ release_subtable(tabledata, tabledata->table[cur_index]);
+
+ /* reallocate the subtable if the new value is a subtable */
+ if (tabledata->table[prev_index] >= SUBTABLE_BASE)
+ reallocate_subtable(tabledata, tabledata->table[prev_index]);
+
+ /* set the new value and short-circuit the mapping step */
+ tabledata->table[cur_index] = tabledata->table[prev_index];
+ continue;
+ }
+ prev_index = cur_index;
+ prev_entry = tabledata->table[cur_index];
+ }
+
+ /* loop over mirrors in the level 1 table */
+ for (lmirrorcount = 0; lmirrorcount < (1 << lmirrorbits); lmirrorcount++)
+ {
+ /* compute the base of this mirror */
+ offs_t lmirrorbase = hmirrorbase;
+ for (i = 0; i < lmirrorbits; i++)
+ if (lmirrorcount & (1 << i))
+ lmirrorbase |= lmirrorbit[i];
+
+ /* populate the tables */
+ if (!ismatchmask)
+ populate_table_range(space, iswrite, start + lmirrorbase, end + lmirrorbase, idx);
+ else
+ populate_table_match(space, iswrite, start + lmirrorbase, end + lmirrorbase, idx);
+ }
+ }
+
+ /* if this is being installed to a live CPU, update the context */
+ if (space->cpunum == cur_context)
+ memory_set_context(cur_context);
+}
+
+
+/*-------------------------------------------------
+ assign_dynamic_bank - finds a free or exact
+ matching bank
+-------------------------------------------------*/
+
+static genf *assign_dynamic_bank(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mirror, int isfixed, int ismasked)
+{
+ int bank;
+
+ /* loop over banks, searching for an exact match or an empty */
+ for (bank = MAX_BANKS; bank >= 1; bank--)
+ if (!bankdata[bank].used || (bankdata[bank].dynamic && bankdata[bank].cpunum == cpunum && bankdata[bank].spacenum == spacenum && bankdata[bank].base == start))
+ {
+ bankdata[bank].used = TRUE;
+ bankdata[bank].dynamic = TRUE;
+ bankdata[bank].cpunum = cpunum;
+ bankdata[bank].spacenum = spacenum;
+ bankdata[bank].base = start;
+ bankdata[bank].end = end;
+ VPRINTF(("Assigned bank %d to %d,%d,%08X\n", bank, cpunum, spacenum, start));
+ return BANK_TO_HANDLER(bank);
+ }
+
+ /* if we got here, we failed */
+ fatalerror("cpu #%d: ran out of banks for RAM/ROM regions!", cpunum);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ get_handler_index - finds the index of a
+ handler, or allocates a new one as necessary
+-------------------------------------------------*/
+
+static UINT8 get_handler_index(handler_data *table, genf *handler, const char *handler_name, offs_t start, offs_t end, offs_t mask)
+{
+ int i;
+
+ start &= mask;
+
+ /* all static handlers are hardcoded */
+ if (HANDLER_IS_STATIC(handler))
+ {
+ i = (FPTR)handler;
+ if (HANDLER_IS_BANK(handler))
+ {
+ table[i].offset = start;
+ table[i].top = end;
+ table[i].mask = mask;
+ table[i].name = handler_name;
+ }
+ return i;
+ }
+
+ /* otherwise, we have to search */
+ for (i = STATIC_COUNT; i < SUBTABLE_BASE; i++)
+ {
+ if (table[i].handler.generic == NULL)
+ {
+ table[i].handler.generic = handler;
+ table[i].offset = start;
+ table[i].top = end;
+ table[i].mask = mask;
+ table[i].name = handler_name;
+ return i;
+ }
+ if (table[i].handler.generic == handler && table[i].offset == start && table[i].mask == mask)
+ return i;
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ populate_table_range - assign a memory handler
+ to a range of addresses
+-------------------------------------------------*/
+
+static void populate_table_range(addrspace_data *space, int iswrite, offs_t start, offs_t stop, UINT8 handler)
+{
+ table_data *tabledata = iswrite ? &space->write : &space->read;
+ offs_t l2mask = (1 << LEVEL2_BITS) - 1;
+ offs_t l1start = start >> LEVEL2_BITS;
+ offs_t l2start = start & l2mask;
+ offs_t l1stop = stop >> LEVEL2_BITS;
+ offs_t l2stop = stop & l2mask;
+ offs_t l1index;
+
+ /* sanity check */
+ if (start > stop)
+ return;
+
+ /* handle the starting edge if it's not on a block boundary */
+ if (l2start != 0)
+ {
+ UINT8 *subtable = open_subtable(tabledata, l1start);
+
+ /* if the start and stop end within the same block, handle that */
+ if (l1start == l1stop)
+ {
+ memset(&subtable[l2start], handler, l2stop - l2start + 1);
+ close_subtable(tabledata, l1start);
+ return;
+ }
+
+ /* otherwise, fill until the end */
+ memset(&subtable[l2start], handler, (1 << LEVEL2_BITS) - l2start);
+ close_subtable(tabledata, l1start);
+ if (l1start != (offs_t)~0) l1start++;
+ }
+
+ /* handle the trailing edge if it's not on a block boundary */
+ if (l2stop != l2mask)
+ {
+ UINT8 *subtable = open_subtable(tabledata, l1stop);
+
+ /* fill from the beginning */
+ memset(&subtable[0], handler, l2stop + 1);
+ close_subtable(tabledata, l1stop);
+
+ /* if the start and stop end within the same block, handle that */
+ if (l1start == l1stop)
+ return;
+ if (l1stop != 0) l1stop--;
+ }
+
+ /* now fill in the middle tables */
+ for (l1index = l1start; l1index <= l1stop; l1index++)
+ {
+ /* if we have a subtable here, release it */
+ if (tabledata->table[l1index] >= SUBTABLE_BASE)
+ release_subtable(tabledata, tabledata->table[l1index]);
+ tabledata->table[l1index] = handler;
+ }
+}
+
+
+/*-------------------------------------------------
+ populate_table_match - assign a memory handler
+ to a range of addresses
+-------------------------------------------------*/
+
+static void populate_table_match(addrspace_data *space, int iswrite, offs_t matchval, offs_t matchmask, UINT8 handler)
+{
+ table_data *tabledata = iswrite ? &space->write : &space->read;
+ int lowermask, lowermatch;
+ int uppermask, uppermatch;
+ int l1index, l2index;
+
+ /* clear out any ignored bits in the matchval */
+ matchval &= matchmask;
+
+ /* compute the lower half of the match/mask pair */
+ lowermask = matchmask & ((1<<LEVEL2_BITS)-1);
+ lowermatch = matchval & ((1<<LEVEL2_BITS)-1);
+
+ /* compute the upper half of the match/mask pair */
+ uppermask = matchmask >> LEVEL2_BITS;
+ uppermatch = matchval >> LEVEL2_BITS;
+
+ /* if the lower bits of the mask are all 0, we can work exclusively at the top level */
+ if (lowermask == 0)
+ {
+ /* loop over top level matches */
+ for (l1index = 0; l1index <= (space->mask >> LEVEL2_BITS); l1index++)
+ if ((l1index & uppermatch) == uppermask)
+ {
+ /* if we have a subtable here, release it */
+ if (tabledata->table[l1index] >= SUBTABLE_BASE)
+ release_subtable(tabledata, tabledata->table[l1index]);
+ tabledata->table[l1index] = handler;
+ }
+ }
+
+ /* okay, we need to work at both levels */
+ else
+ {
+ /* loop over top level matches */
+ for (l1index = 0; l1index <= (space->mask >> LEVEL2_BITS); l1index++)
+ if ((l1index & uppermatch) == uppermask)
+ {
+ UINT8 *subtable = open_subtable(tabledata, l1index);
+
+ /* now loop over lower level matches */
+ for (l2index = 0; l2index < (1 << LEVEL2_BITS); l2index++)
+ if ((l2index & lowermask) == lowermatch)
+ subtable[l2index] = handler;
+ close_subtable(tabledata, l1index);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ allocate_subtable - allocate a fresh subtable
+ and set its usecount to 1
+-------------------------------------------------*/
+
+static UINT8 allocate_subtable(table_data *tabledata)
+{
+ /* loop */
+ while (1)
+ {
+ UINT8 subindex;
+
+ /* find a subtable with a usecount of 0 */
+ for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++)
+ if (tabledata->subtable[subindex].usecount == 0)
+ {
+ /* if this is past our allocation budget, allocate some more */
+ if (subindex >= tabledata->subtable_alloc)
+ {
+ tabledata->subtable_alloc += SUBTABLE_ALLOC;
+ tabledata->table = realloc(tabledata->table, (1 << LEVEL1_BITS) + (tabledata->subtable_alloc << LEVEL2_BITS));
+ if (!tabledata->table)
+ fatalerror("error: ran out of memory allocating memory subtable");
+ }
+
+ /* bump the usecount and return */
+ tabledata->subtable[subindex].usecount++;
+ return subindex + SUBTABLE_BASE;
+ }
+
+ /* merge any subtables we can */
+ if (!merge_subtables(tabledata))
+ fatalerror("Ran out of subtables!");
+ }
+
+ /* hopefully this never happens */
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ reallocate_subtable - increment the usecount on
+ a subtable
+-------------------------------------------------*/
+
+static void reallocate_subtable(table_data *tabledata, UINT8 subentry)
+{
+ UINT8 subindex = subentry - SUBTABLE_BASE;
+
+ /* sanity check */
+ if (tabledata->subtable[subindex].usecount <= 0)
+ fatalerror("Called reallocate_subtable on a table with a usecount of 0");
+
+ /* increment the usecount */
+ tabledata->subtable[subindex].usecount++;
+}
+
+
+/*-------------------------------------------------
+ merge_subtables - merge any duplicate
+ subtables
+-------------------------------------------------*/
+
+static int merge_subtables(table_data *tabledata)
+{
+ int merged = 0;
+ UINT8 subindex;
+
+ VPRINTF(("Merging subtables....\n"));
+
+ /* okay, we failed; update all the checksums and merge tables */
+ for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++)
+ if (!tabledata->subtable[subindex].checksum_valid && tabledata->subtable[subindex].usecount != 0)
+ {
+ UINT32 *subtable = (UINT32 *)SUBTABLE_PTR(tabledata, subindex + SUBTABLE_BASE);
+ UINT32 checksum = 0;
+ int l2index;
+
+ /* update the checksum */
+ for (l2index = 0; l2index < (1 << LEVEL2_BITS)/4; l2index++)
+ checksum += subtable[l2index];
+ tabledata->subtable[subindex].checksum = checksum;
+ tabledata->subtable[subindex].checksum_valid = 1;
+ }
+
+ /* see if there's a matching checksum */
+ for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++)
+ if (tabledata->subtable[subindex].usecount != 0)
+ {
+ UINT8 *subtable = SUBTABLE_PTR(tabledata, subindex + SUBTABLE_BASE);
+ UINT32 checksum = tabledata->subtable[subindex].checksum;
+ UINT8 sumindex;
+
+ for (sumindex = subindex + 1; sumindex < SUBTABLE_COUNT; sumindex++)
+ if (tabledata->subtable[sumindex].usecount != 0 &&
+ tabledata->subtable[sumindex].checksum == checksum &&
+ !memcmp(subtable, SUBTABLE_PTR(tabledata, sumindex + SUBTABLE_BASE), 1 << LEVEL2_BITS))
+ {
+ int l1index;
+
+ VPRINTF(("Merging subtable %d and %d....\n", subindex, sumindex));
+
+ /* find all the entries in the L1 tables that pointed to the old one, and point them to the merged table */
+ for (l1index = 0; l1index <= (0xffffffffUL >> LEVEL2_BITS); l1index++)
+ if (tabledata->table[l1index] == sumindex + SUBTABLE_BASE)
+ {
+ release_subtable(tabledata, sumindex + SUBTABLE_BASE);
+ reallocate_subtable(tabledata, subindex + SUBTABLE_BASE);
+ tabledata->table[l1index] = subindex + SUBTABLE_BASE;
+ merged++;
+ }
+ }
+ }
+
+ return merged;
+}
+
+
+/*-------------------------------------------------
+ release_subtable - decrement the usecount on
+ a subtable and free it if we're done
+-------------------------------------------------*/
+
+static void release_subtable(table_data *tabledata, UINT8 subentry)
+{
+ UINT8 subindex = subentry - SUBTABLE_BASE;
+
+ /* sanity check */
+ if (tabledata->subtable[subindex].usecount <= 0)
+ fatalerror("Called release_subtable on a table with a usecount of 0");
+
+ /* decrement the usecount and clear the checksum if we're at 0 */
+ tabledata->subtable[subindex].usecount--;
+ if (tabledata->subtable[subindex].usecount == 0)
+ tabledata->subtable[subindex].checksum = 0;
+}
+
+
+/*-------------------------------------------------
+ open_subtable - gain access to a subtable for
+ modification
+-------------------------------------------------*/
+
+static UINT8 *open_subtable(table_data *tabledata, offs_t l1index)
+{
+ UINT8 subentry = tabledata->table[l1index];
+
+ /* if we don't have a subtable yet, allocate a new one */
+ if (subentry < SUBTABLE_BASE)
+ {
+ UINT8 newentry = allocate_subtable(tabledata);
+ memset(SUBTABLE_PTR(tabledata, newentry), subentry, 1 << LEVEL2_BITS);
+ tabledata->table[l1index] = newentry;
+ tabledata->subtable[newentry - SUBTABLE_BASE].checksum = (subentry + (subentry << 8) + (subentry << 16) + (subentry << 24)) * ((1 << LEVEL2_BITS)/4);
+ subentry = newentry;
+ }
+
+ /* if we're sharing this subtable, we also need to allocate a fresh copy */
+ else if (tabledata->subtable[subentry - SUBTABLE_BASE].usecount > 1)
+ {
+ UINT8 newentry = allocate_subtable(tabledata);
+
+ /* allocate may cause some additional merging -- look up the subentry again */
+ /* when we're done; it should still require a split */
+ subentry = tabledata->table[l1index];
+ assert(subentry >= SUBTABLE_BASE);
+ assert(tabledata->subtable[subentry - SUBTABLE_BASE].usecount > 1);
+
+ memcpy(SUBTABLE_PTR(tabledata, newentry), SUBTABLE_PTR(tabledata, subentry), 1 << LEVEL2_BITS);
+ release_subtable(tabledata, subentry);
+ tabledata->table[l1index] = newentry;
+ tabledata->subtable[newentry - SUBTABLE_BASE].checksum = tabledata->subtable[subentry - SUBTABLE_BASE].checksum;
+ subentry = newentry;
+ }
+
+ /* mark the table dirty */
+ tabledata->subtable[subentry - SUBTABLE_BASE].checksum_valid = 0;
+
+ /* return the pointer to the subtable */
+ return SUBTABLE_PTR(tabledata, subentry);
+}
+
+
+/*-------------------------------------------------
+ close_subtable - stop access to a subtable
+-------------------------------------------------*/
+
+static void close_subtable(table_data *tabledata, offs_t l1index)
+{
+ /* defer any merging until we run out of tables */
+}
+
+
+/*-------------------------------------------------
+ Return whether a given memory map entry implies
+ the need of allocating and registering memory
+-------------------------------------------------*/
+
+static int amentry_needs_backing_store(int cpunum, int spacenum, const address_map *map)
+{
+ FPTR handler;
+
+ if (IS_AMENTRY_EXTENDED(map))
+ return 0;
+ if (map->base)
+ return 1;
+
+ handler = (FPTR)map->write.handler;
+ if (handler >= 0 && handler < STATIC_COUNT)
+ {
+ if (handler != STATIC_INVALID &&
+ handler != STATIC_ROM &&
+ handler != STATIC_NOP &&
+ handler != STATIC_UNMAP)
+ return 1;
+ }
+
+ handler = (FPTR)map->read.handler;
+ if (handler >= 0 && handler < STATIC_COUNT)
+ {
+ if (handler != STATIC_INVALID &&
+ (handler < STATIC_BANK1 || handler > STATIC_BANK1 + MAX_BANKS - 1) &&
+ (handler != STATIC_ROM || spacenum != ADDRESS_SPACE_PROGRAM || map->start >= memory_region_length(REGION_CPU1 + cpunum)) &&
+ handler != STATIC_NOP &&
+ handler != STATIC_UNMAP)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ allocate_memory - allocate memory for
+ CPU address spaces
+-------------------------------------------------*/
+
+static void allocate_memory(void)
+{
+ int cpunum, spacenum;
+
+ /* loop over all CPUs and memory spaces */
+ for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ if (cpudata[cpunum].spacemask & (1 << spacenum))
+ {
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ address_map *map, *unassigned = NULL;
+ int start_count = memory_block_count;
+ int i;
+
+ /* make a first pass over the memory map and track blocks with hardcoded pointers */
+ /* we do this to make sure they are found by memory_find_base first */
+ for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++)
+ if (!IS_AMENTRY_EXTENDED(map) && map->memory != NULL)
+ {
+ if (!IS_AMENTRY_MATCH_MASK(map))
+ allocate_memory_block(cpunum, spacenum, map->start, map->end, map->memory);
+ else
+ allocate_memory_block(cpunum, spacenum, map->start, map->start + map->mask, map->memory);
+ }
+
+ /* loop over all blocks just allocated and assign pointers from them */
+ for (i = start_count; i < memory_block_count; i++)
+ unassigned = assign_intersecting_blocks(space, memory_block_list[i].start, memory_block_list[i].end, memory_block_list[i].data);
+
+ /* if we don't have an unassigned pointer yet, try to find one */
+ if (!unassigned)
+ unassigned = assign_intersecting_blocks(space, ~0, 0, NULL);
+
+ /* loop until we've assigned all memory in this space */
+ while (unassigned)
+ {
+ offs_t curstart, curend;
+ int changed;
+ void *block;
+
+ /* work in MEMORY_BLOCK_SIZE-sized chunks */
+ curstart = unassigned->start / MEMORY_BLOCK_SIZE;
+ if (!IS_AMENTRY_MATCH_MASK(unassigned))
+ curend = unassigned->end / MEMORY_BLOCK_SIZE;
+ else
+ curend = (unassigned->start + unassigned->mask) / MEMORY_BLOCK_SIZE;
+
+ /* loop while we keep finding unassigned blocks in neighboring MEMORY_BLOCK_SIZE chunks */
+ do
+ {
+ changed = 0;
+
+ /* scan for unmapped blocks in the adjusted map */
+ for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++)
+ if (!IS_AMENTRY_EXTENDED(map) && map->memory == NULL && map != unassigned && amentry_needs_backing_store(cpunum, spacenum, map))
+ {
+ offs_t blockstart, blockend;
+
+ /* get block start/end blocks for this block */
+ blockstart = map->start / MEMORY_BLOCK_SIZE;
+ if (!IS_AMENTRY_MATCH_MASK(map))
+ blockend = map->end / MEMORY_BLOCK_SIZE;
+ else
+ blockend = (map->start + map->mask) / MEMORY_BLOCK_SIZE;
+
+ /* if we intersect or are adjacent, adjust the start/end */
+ if (blockstart <= curend + 1 && blockend >= curstart - 1)
+ {
+ if (blockstart < curstart)
+ curstart = blockstart, changed = 1;
+ if (blockend > curend)
+ curend = blockend, changed = 1;
+ }
+ }
+ } while (changed);
+
+ /* we now have a block to allocate; do it */
+ curstart = curstart * MEMORY_BLOCK_SIZE;
+ curend = curend * MEMORY_BLOCK_SIZE + (MEMORY_BLOCK_SIZE - 1);
+ block = allocate_memory_block(cpunum, spacenum, curstart, curend, NULL);
+
+ /* assign memory that intersected the new block */
+ unassigned = assign_intersecting_blocks(space, curstart, curend, block);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ allocate_memory_block - allocate a single
+ memory block of data
+-------------------------------------------------*/
+
+static void *allocate_memory_block(int cpunum, int spacenum, offs_t start, offs_t end, void *memory)
+{
+ memory_block *block = &memory_block_list[memory_block_count];
+ int allocatemem = (memory == NULL);
+ int region;
+
+ VPRINTF(("allocate_memory_block(%d,%d,%08X,%08X,%08X)\n", cpunum, spacenum, start, end, (UINT32)memory));
+
+ /* if we weren't passed a memory block, allocate one and clear it to zero */
+ if (allocatemem)
+ {
+ memory = auto_malloc(end - start + 1);
+ memset(memory, 0, end - start + 1);
+ }
+
+ /* register for saving, but only if we're not part of a memory region */
+ for (region = 0; region < MAX_MEMORY_REGIONS; region++)
+ {
+ UINT8 *region_base = memory_region(region);
+ UINT32 region_length = memory_region_length(region);
+ if (region_base != NULL && region_length != 0 && (UINT8 *)memory >= region_base && ((UINT8 *)memory + (end - start + 1)) < region_base + region_length)
+ {
+ VPRINTF(("skipping save of this memory block as it is covered by a memory region\n"));
+ break;
+ }
+ }
+ if (region == MAX_MEMORY_REGIONS)
+ register_for_save(cpunum, spacenum, start, memory, end - start + 1);
+
+ /* fill in the tracking block */
+ block->cpunum = cpunum;
+ block->spacenum = spacenum;
+ block->isallocated = allocatemem;
+ block->start = start;
+ block->end = end;
+ block->data = memory;
+ memory_block_count++;
+ return memory;
+}
+
+
+/*-------------------------------------------------
+ register_for_save - register a block of
+ memory for save states
+-------------------------------------------------*/
+
+static void register_for_save(int cpunum, int spacenum, offs_t start, void *base, size_t numbytes)
+{
+ int bytes_per_element = cpudata[cpunum].space[spacenum].dbits/8;
+ char name[256];
+
+ sprintf(name, "%d.%08x-%08x", spacenum, start, (int)(start + numbytes - 1));
+ state_save_register_memory("memory", cpunum, name, base, bytes_per_element, (UINT32)numbytes / bytes_per_element);
+}
+
+
+/*-------------------------------------------------
+ assign_intersecting_blocks - find all
+ intersecting blocks and assign their pointers
+-------------------------------------------------*/
+
+static address_map *assign_intersecting_blocks(addrspace_data *space, offs_t start, offs_t end, UINT8 *base)
+{
+ address_map *map, *unassigned = NULL;
+
+ /* loop over the adjusted map and assign memory to any blocks we can */
+ for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++)
+ if (!IS_AMENTRY_EXTENDED(map))
+ {
+ /* if we haven't assigned this block yet, do it against the last block */
+ if (map->memory == NULL)
+ {
+ /* inherit shared pointers first */
+ if (map->share && shared_ptr[map->share])
+ {
+ map->memory = shared_ptr[map->share];
+ VPRINTF(("memory range %08X-%08X -> shared_ptr[%d] [%08X]\n", map->start, map->end, map->share, (UINT32)map->memory));
+ }
+
+ /* otherwise, look for a match in this block */
+ else
+ {
+ if (!IS_AMENTRY_MATCH_MASK(map))
+ {
+ if (map->start >= start && map->end <= end)
+ {
+ map->memory = base + (map->start - start);
+ VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%08X]\n", map->start, map->end, start, end, (UINT32)map->memory));
+ }
+ }
+ else
+ {
+ if (map->start >= start && map->start + map->mask <= end)
+ {
+ map->memory = base + (map->start - start);
+ VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%08X]\n", map->start, map->end, start, end, (UINT32)map->memory));
+ }
+ }
+ }
+ }
+
+ /* if we're the first match on a shared pointer, assign it now */
+ if (map->memory != NULL && map->share && !shared_ptr[map->share])
+ shared_ptr[map->share] = map->memory;
+
+ /* keep track of the first unassigned entry */
+ if (map->memory == NULL && !unassigned && amentry_needs_backing_store(space->cpunum, space->spacenum, map))
+ unassigned = map;
+ }
+
+ return unassigned;
+}
+
+
+/*-------------------------------------------------
+ reattach_banks - reconnect banks after a load
+-------------------------------------------------*/
+
+static void reattach_banks(void)
+{
+ int banknum;
+
+ /* once this is done, find the starting bases for the banks */
+ for (banknum = 1; banknum <= MAX_BANKS; banknum++)
+ if (bankdata[banknum].used && !bankdata[banknum].dynamic)
+ {
+ /* if this entry has a changed entry, set the appropriate pointer */
+ if (bankdata[banknum].curentry != MAX_BANK_ENTRIES)
+ bank_ptr[banknum] = bankdata[banknum].entry[bankdata[banknum].curentry];
+ }
+}
+
+
+/*-------------------------------------------------
+ find_memory - find all the requested pointers
+ into the final allocated memory
+-------------------------------------------------*/
+
+static void find_memory(void)
+{
+ int cpunum, spacenum, banknum;
+
+ /* loop over CPUs and address spaces */
+ for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ if (cpudata[cpunum].spacemask & (1 << spacenum))
+ {
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ const address_map *map;
+
+ /* fill in base/size entries, and handle shared memory */
+ for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++)
+ if (!IS_AMENTRY_EXTENDED(map))
+ {
+ /* assign base/size values */
+ if (map->base != NULL)
+ *map->base = map->memory;
+ if (map->size)
+ {
+ if (!IS_AMENTRY_MATCH_MASK(map))
+ *map->size = map->end - map->start + 1;
+ else
+ *map->size = map->mask + 1;
+ }
+ }
+ }
+
+ /* once this is done, find the starting bases for the banks */
+ for (banknum = 1; banknum <= MAX_BANKS; banknum++)
+ if (bankdata[banknum].used)
+ {
+ address_map *map;
+
+ /* set the initial bank pointer */
+ for (map = cpudata[bankdata[banknum].cpunum].space[bankdata[banknum].spacenum].adjmap; map && !IS_AMENTRY_END(map); map++)
+ if (!IS_AMENTRY_EXTENDED(map) && map->start == bankdata[banknum].base)
+ {
+ bank_ptr[banknum] = map->memory;
+ VPRINTF(("assigned bank %d pointer to memory from range %08X-%08X [%08X]\n", banknum, map->start, map->end, (UINT32)map->memory));
+ break;
+ }
+
+ /* if the entry was set ahead of time, override the automatically found pointer */
+ if (!bankdata[banknum].dynamic && bankdata[banknum].curentry != MAX_BANK_ENTRIES)
+ bank_ptr[banknum] = bankdata[banknum].entry[bankdata[banknum].curentry];
+ }
+
+ /* request a callback to fix up the banks when done */
+ state_save_register_func_postload(reattach_banks);
+}
+
+
+/*-------------------------------------------------
+ memory_find_base - return a pointer to the
+ base of RAM associated with the given CPU
+ and offset
+-------------------------------------------------*/
+
+static void *memory_find_base(int cpunum, int spacenum, int readwrite, offs_t offset)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ address_map *map;
+ memory_block *block;
+ int blocknum;
+
+ VPRINTF(("memory_find_base(%d,%d,%d,%08X) -> ", cpunum, spacenum, readwrite, offset));
+
+ /* look in the adjusted map */
+ for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++)
+ if (!IS_AMENTRY_EXTENDED(map))
+ {
+ offs_t maskoffs = offset & map->mask;
+ if (!IS_AMENTRY_MATCH_MASK(map))
+ {
+ if (maskoffs >= map->start && maskoffs <= map->end)
+ {
+ VPRINTF(("found in entry %08X-%08X [%08X]\n", map->start, map->end, (UINT32)map->memory + (maskoffs - map->start)));
+ return (UINT8 *)map->memory + (maskoffs - map->start);
+ }
+ }
+ else
+ {
+ if ((maskoffs & map->end) == map->start)
+ {
+ VPRINTF(("found in entry %08X-%08X [%08X]\n", map->start, map->end, (UINT32)map->memory + (maskoffs - map->start)));
+ return (UINT8 *)map->memory + (maskoffs - map->start);
+ }
+ }
+ }
+
+ /* if not found there, look in the allocated blocks */
+ for (blocknum = 0, block = memory_block_list; blocknum < memory_block_count; blocknum++, block++)
+ if (block->cpunum == cpunum && block->spacenum == spacenum && block->start <= offset && block->end > offset)
+ {
+ VPRINTF(("found in allocated memory block %08X-%08X [%08X]\n", block->start, block->end, (UINT32)block->data + (offset - block->start)));
+ return block->data + offset - block->start;
+ }
+
+ VPRINTF(("did not find\n"));
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ PERFORM_LOOKUP - common lookup procedure
+-------------------------------------------------*/
+
+#define PERFORM_LOOKUP(lookup,space,extraand) \
+ /* perform lookup */ \
+ address &= space.addrmask & extraand; \
+ entry = space.lookup[LEVEL1_INDEX(address)]; \
+ if (entry >= SUBTABLE_BASE) \
+ entry = space.lookup[LEVEL2_INDEX(entry,address)]; \
+
+
+/*-------------------------------------------------
+ READBYTE - generic byte-sized read handler
+-------------------------------------------------*/
+
+#define READBYTE8(name,spacenum) \
+UINT8 name(offs_t original_address) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMREADSTART(); \
+ PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~0); \
+ DEBUG_HOOK_READ(spacenum, 1, address); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMREADEND(bank_ptr[entry][address]); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler8)(address));\
+ return 0; \
+} \
+
+#define READBYTE(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \
+UINT8 name(offs_t original_address) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMREADSTART(); \
+ PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~0); \
+ DEBUG_HOOK_READ(spacenum, 1, address); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMREADEND(bank_ptr[entry][xormacro(address)]); \
+ \
+ /* fall back to the handler */ \
+ else \
+ { \
+ int shift = 8 * (shiftbytes); \
+ MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handlertype)(address >> (ignorebits), ~((masktype)0xff << shift)) >> shift);\
+ } \
+ return 0; \
+} \
+
+#define READBYTE16BE(name,space) READBYTE(name,space,BYTE_XOR_BE, handler16,1,~address & 1,UINT16)
+#define READBYTE16LE(name,space) READBYTE(name,space,BYTE_XOR_LE, handler16,1, address & 1,UINT16)
+#define READBYTE32BE(name,space) READBYTE(name,space,BYTE4_XOR_BE,handler32,2,~address & 3,UINT32)
+#define READBYTE32LE(name,space) READBYTE(name,space,BYTE4_XOR_LE,handler32,2, address & 3,UINT32)
+#define READBYTE64BE(name,space) READBYTE(name,space,BYTE8_XOR_BE,handler64,3,~address & 7,UINT64)
+#define READBYTE64LE(name,space) READBYTE(name,space,BYTE8_XOR_LE,handler64,3, address & 7,UINT64)
+
+
+/*-------------------------------------------------
+ READWORD - generic word-sized read handler
+ (16-bit, 32-bit and 64-bit aligned only!)
+-------------------------------------------------*/
+
+#define READWORD16(name,spacenum) \
+UINT16 name(offs_t original_address) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMREADSTART(); \
+ PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~1); \
+ DEBUG_HOOK_READ(spacenum, 2, address); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMREADEND(*(UINT16 *)&bank_ptr[entry][address]); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler16)(address >> 1,0));\
+ return 0; \
+} \
+
+#define READWORD(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \
+UINT16 name(offs_t original_address) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMREADSTART(); \
+ PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~1); \
+ DEBUG_HOOK_READ(spacenum, 2, address); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMREADEND(*(UINT16 *)&bank_ptr[entry][xormacro(address)]); \
+ \
+ /* fall back to the handler */ \
+ else \
+ { \
+ int shift = 8 * (shiftbytes); \
+ MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handlertype)(address >> (ignorebits), ~((masktype)0xffff << shift)) >> shift);\
+ } \
+ return 0; \
+} \
+
+#define READWORD32BE(name,space) READWORD(name,space,WORD_XOR_BE, handler32,2,~address & 2,UINT32)
+#define READWORD32LE(name,space) READWORD(name,space,WORD_XOR_LE, handler32,2, address & 2,UINT32)
+#define READWORD64BE(name,space) READWORD(name,space,WORD2_XOR_BE,handler64,3,~address & 6,UINT64)
+#define READWORD64LE(name,space) READWORD(name,space,WORD2_XOR_LE,handler64,3, address & 6,UINT64)
+
+
+/*-------------------------------------------------
+ READDWORD - generic dword-sized read handler
+ (32-bit and 64-bit aligned only!)
+-------------------------------------------------*/
+
+#define READDWORD32(name,spacenum) \
+UINT32 name(offs_t original_address) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMREADSTART(); \
+ PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~3); \
+ DEBUG_HOOK_READ(spacenum, 4, address); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMREADEND(*(UINT32 *)&bank_ptr[entry][address]); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler32)(address >> 2,0));\
+ return 0; \
+} \
+
+#define READMASKED32(name,spacenum) \
+UINT32 name(offs_t original_address, UINT32 mem_mask) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMREADSTART(); \
+ PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~3); \
+ DEBUG_HOOK_READ(spacenum, 4, address); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMREADEND(*(UINT32 *)&bank_ptr[entry][address]); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler32)(address >> 2, mem_mask));\
+ return 0; \
+} \
+
+#define READDWORD(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \
+UINT32 name(offs_t original_address) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMREADSTART(); \
+ PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~3); \
+ DEBUG_HOOK_READ(spacenum, 4, address); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMREADEND(*(UINT32 *)&bank_ptr[entry][xormacro(address)]); \
+ \
+ /* fall back to the handler */ \
+ else \
+ { \
+ int shift = 8 * (shiftbytes); \
+ MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handlertype)(address >> (ignorebits), ~((masktype)0xffffffff << shift)) >> shift);\
+ } \
+ return 0; \
+} \
+
+#define READDWORD64BE(name,space) READDWORD(name,space,DWORD_XOR_BE,handler64,3,~address & 4,UINT64)
+#define READDWORD64LE(name,space) READDWORD(name,space,DWORD_XOR_LE,handler64,3, address & 4,UINT64)
+
+
+/*-------------------------------------------------
+ READQWORD - generic qword-sized read handler
+ (64-bit aligned only!)
+-------------------------------------------------*/
+
+#define READQWORD64(name,spacenum) \
+UINT64 name(offs_t original_address) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMREADSTART(); \
+ PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~7); \
+ DEBUG_HOOK_READ(spacenum, 8, address); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMREADEND(*(UINT64 *)&bank_ptr[entry][address]); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler64)(address >> 3,0));\
+ return 0; \
+} \
+
+#define READMASKED64(name,spacenum) \
+UINT64 name(offs_t original_address, UINT64 mem_mask) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMREADSTART(); \
+ PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~7); \
+ DEBUG_HOOK_READ(spacenum, 8, address); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMREADEND(*(UINT64 *)&bank_ptr[entry][address]); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler64)(address >> 3, mem_mask));\
+ return 0; \
+} \
+
+
+/*-------------------------------------------------
+ WRITEBYTE - generic byte-sized write handler
+-------------------------------------------------*/
+
+#define WRITEBYTE8(name,spacenum) \
+void name(offs_t original_address, UINT8 data) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMWRITESTART(); \
+ PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~0); \
+ DEBUG_HOOK_WRITE(spacenum, 1, address, data); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMWRITEEND(bank_ptr[entry][address] = data); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler8)(address, data));\
+} \
+
+#define WRITEBYTE(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \
+void name(offs_t original_address, UINT8 data) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMWRITESTART(); \
+ PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~0); \
+ DEBUG_HOOK_WRITE(spacenum, 1, address, data); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMWRITEEND(bank_ptr[entry][xormacro(address)] = data); \
+ \
+ /* fall back to the handler */ \
+ else \
+ { \
+ int shift = 8 * (shiftbytes); \
+ MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handlertype)(address >> (ignorebits), (masktype)data << shift, ~((masktype)0xff << shift)));\
+ } \
+} \
+
+#define WRITEBYTE16BE(name,space) WRITEBYTE(name,space,BYTE_XOR_BE, handler16,1,~address & 1,UINT16)
+#define WRITEBYTE16LE(name,space) WRITEBYTE(name,space,BYTE_XOR_LE, handler16,1, address & 1,UINT16)
+#define WRITEBYTE32BE(name,space) WRITEBYTE(name,space,BYTE4_XOR_BE,handler32,2,~address & 3,UINT32)
+#define WRITEBYTE32LE(name,space) WRITEBYTE(name,space,BYTE4_XOR_LE,handler32,2, address & 3,UINT32)
+#define WRITEBYTE64BE(name,space) WRITEBYTE(name,space,BYTE8_XOR_BE,handler64,3,~address & 7,UINT64)
+#define WRITEBYTE64LE(name,space) WRITEBYTE(name,space,BYTE8_XOR_LE,handler64,3, address & 7,UINT64)
+
+
+/*-------------------------------------------------
+ WRITEWORD - generic word-sized write handler
+ (16-bit, 32-bit and 64-bit aligned only!)
+-------------------------------------------------*/
+
+#define WRITEWORD16(name,spacenum) \
+void name(offs_t original_address, UINT16 data) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMWRITESTART(); \
+ PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~1); \
+ DEBUG_HOOK_WRITE(spacenum, 2, address, data); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMWRITEEND(*(UINT16 *)&bank_ptr[entry][address] = data); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler16)(address >> 1, data, 0));\
+} \
+
+#define WRITEWORD(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \
+void name(offs_t original_address, UINT16 data) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMWRITESTART(); \
+ PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~1); \
+ DEBUG_HOOK_WRITE(spacenum, 2, address, data); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMWRITEEND(*(UINT16 *)&bank_ptr[entry][xormacro(address)] = data); \
+ \
+ /* fall back to the handler */ \
+ else \
+ { \
+ int shift = 8 * (shiftbytes); \
+ MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handlertype)(address >> (ignorebits), (masktype)data << shift, ~((masktype)0xffff << shift)));\
+ } \
+} \
+
+#define WRITEWORD32BE(name,space) WRITEWORD(name,space,WORD_XOR_BE, handler32,2,~address & 2,UINT32)
+#define WRITEWORD32LE(name,space) WRITEWORD(name,space,WORD_XOR_LE, handler32,2, address & 2,UINT32)
+#define WRITEWORD64BE(name,space) WRITEWORD(name,space,WORD2_XOR_BE,handler64,3,~address & 6,UINT64)
+#define WRITEWORD64LE(name,space) WRITEWORD(name,space,WORD2_XOR_LE,handler64,3, address & 6,UINT64)
+
+
+/*-------------------------------------------------
+ WRITEDWORD - dword-sized write handler
+ (32-bit and 64-bit aligned only!)
+-------------------------------------------------*/
+
+#define WRITEDWORD32(name,spacenum) \
+void name(offs_t original_address, UINT32 data) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMWRITESTART(); \
+ PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~3); \
+ DEBUG_HOOK_WRITE(spacenum, 4, address, data); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMWRITEEND(*(UINT32 *)&bank_ptr[entry][address] = data); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler32)(address >> 2, data, 0));\
+} \
+
+#define WRITEMASKED32(name,spacenum) \
+void name(offs_t original_address, UINT32 data, UINT32 mem_mask) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMWRITESTART(); \
+ PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~3); \
+ DEBUG_HOOK_WRITE(spacenum, 4, address, data); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ { \
+ UINT32 *dest = (UINT32 *)&bank_ptr[entry][address]; \
+ MEMWRITEEND(*dest = (*dest & mem_mask) | (data & ~mem_mask)); \
+ } \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler32)(address >> 2, data, mem_mask));\
+} \
+
+#define WRITEDWORD(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \
+void name(offs_t original_address, UINT32 data) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMWRITESTART(); \
+ PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~3); \
+ DEBUG_HOOK_WRITE(spacenum, 4, address, data); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMWRITEEND(*(UINT32 *)&bank_ptr[entry][xormacro(address)] = data); \
+ \
+ /* fall back to the handler */ \
+ else \
+ { \
+ int shift = 8 * (shiftbytes); \
+ MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handlertype)(address >> (ignorebits), (masktype)data << shift, ~((masktype)0xffffffff << shift)));\
+ } \
+} \
+
+#define WRITEDWORD64BE(name,space) WRITEDWORD(name,space,DWORD_XOR_BE,handler64,3,~address & 4,UINT64)
+#define WRITEDWORD64LE(name,space) WRITEDWORD(name,space,DWORD_XOR_LE,handler64,3, address & 4,UINT64)
+
+
+/*-------------------------------------------------
+ WRITEQWORD - qword-sized write handler
+ (64-bit aligned only!)
+-------------------------------------------------*/
+
+#define WRITEQWORD64(name,spacenum) \
+void name(offs_t original_address, UINT64 data) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMWRITESTART(); \
+ PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~7); \
+ DEBUG_HOOK_WRITE(spacenum, 8, address, data); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ MEMWRITEEND(*(UINT64 *)&bank_ptr[entry][address] = data); \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler64)(address >> 3, data, 0));\
+} \
+
+#define WRITEMASKED64(name,spacenum) \
+void name(offs_t original_address, UINT64 data, UINT64 mem_mask) \
+{ \
+ offs_t address = original_address; \
+ UINT32 entry; \
+ MEMWRITESTART(); \
+ PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~7); \
+ DEBUG_HOOK_WRITE(spacenum, 8, address, data); \
+ \
+ /* handle banks inline */ \
+ address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\
+ if (entry < STATIC_RAM) \
+ { \
+ UINT64 *dest = (UINT64 *)&bank_ptr[entry][address]; \
+ MEMWRITEEND(*dest = (*dest & mem_mask) | (data & ~mem_mask)); \
+ } \
+ \
+ /* fall back to the handler */ \
+ else \
+ MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler64)(address >> 3, data, mem_mask));\
+} \
+
+
+/*-------------------------------------------------
+ Program memory handlers
+-------------------------------------------------*/
+
+ READBYTE8(program_read_byte_8, ADDRESS_SPACE_PROGRAM)
+ WRITEBYTE8(program_write_byte_8, ADDRESS_SPACE_PROGRAM)
+
+ READBYTE16BE(program_read_byte_16be, ADDRESS_SPACE_PROGRAM)
+ READWORD16(program_read_word_16be, ADDRESS_SPACE_PROGRAM)
+ WRITEBYTE16BE(program_write_byte_16be, ADDRESS_SPACE_PROGRAM)
+ WRITEWORD16(program_write_word_16be, ADDRESS_SPACE_PROGRAM)
+
+ READBYTE16LE(program_read_byte_16le, ADDRESS_SPACE_PROGRAM)
+ READWORD16(program_read_word_16le, ADDRESS_SPACE_PROGRAM)
+ WRITEBYTE16LE(program_write_byte_16le, ADDRESS_SPACE_PROGRAM)
+ WRITEWORD16(program_write_word_16le, ADDRESS_SPACE_PROGRAM)
+
+ READBYTE32BE(program_read_byte_32be, ADDRESS_SPACE_PROGRAM)
+ READWORD32BE(program_read_word_32be, ADDRESS_SPACE_PROGRAM)
+ READDWORD32(program_read_dword_32be, ADDRESS_SPACE_PROGRAM)
+ READMASKED32(program_read_masked_32be, ADDRESS_SPACE_PROGRAM)
+ WRITEBYTE32BE(program_write_byte_32be, ADDRESS_SPACE_PROGRAM)
+ WRITEWORD32BE(program_write_word_32be, ADDRESS_SPACE_PROGRAM)
+ WRITEDWORD32(program_write_dword_32be, ADDRESS_SPACE_PROGRAM)
+ WRITEMASKED32(program_write_masked_32be,ADDRESS_SPACE_PROGRAM)
+
+ READBYTE32LE(program_read_byte_32le, ADDRESS_SPACE_PROGRAM)
+ READWORD32LE(program_read_word_32le, ADDRESS_SPACE_PROGRAM)
+ READDWORD32(program_read_dword_32le, ADDRESS_SPACE_PROGRAM)
+ READMASKED32(program_read_masked_32le, ADDRESS_SPACE_PROGRAM)
+ WRITEBYTE32LE(program_write_byte_32le, ADDRESS_SPACE_PROGRAM)
+ WRITEWORD32LE(program_write_word_32le, ADDRESS_SPACE_PROGRAM)
+ WRITEDWORD32(program_write_dword_32le, ADDRESS_SPACE_PROGRAM)
+ WRITEMASKED32(program_write_masked_32le,ADDRESS_SPACE_PROGRAM)
+
+ READBYTE64BE(program_read_byte_64be, ADDRESS_SPACE_PROGRAM)
+ READWORD64BE(program_read_word_64be, ADDRESS_SPACE_PROGRAM)
+ READDWORD64BE(program_read_dword_64be, ADDRESS_SPACE_PROGRAM)
+ READQWORD64(program_read_qword_64be, ADDRESS_SPACE_PROGRAM)
+ READMASKED64(program_read_masked_64be, ADDRESS_SPACE_PROGRAM)
+ WRITEBYTE64BE(program_write_byte_64be, ADDRESS_SPACE_PROGRAM)
+ WRITEWORD64BE(program_write_word_64be, ADDRESS_SPACE_PROGRAM)
+WRITEDWORD64BE(program_write_dword_64be, ADDRESS_SPACE_PROGRAM)
+ WRITEQWORD64(program_write_qword_64be, ADDRESS_SPACE_PROGRAM)
+ WRITEMASKED64(program_write_masked_64be,ADDRESS_SPACE_PROGRAM)
+
+ READBYTE64LE(program_read_byte_64le, ADDRESS_SPACE_PROGRAM)
+ READWORD64LE(program_read_word_64le, ADDRESS_SPACE_PROGRAM)
+ READDWORD64LE(program_read_dword_64le, ADDRESS_SPACE_PROGRAM)
+ READQWORD64(program_read_qword_64le, ADDRESS_SPACE_PROGRAM)
+ READMASKED64(program_read_masked_64le, ADDRESS_SPACE_PROGRAM)
+ WRITEBYTE64LE(program_write_byte_64le, ADDRESS_SPACE_PROGRAM)
+ WRITEWORD64LE(program_write_word_64le, ADDRESS_SPACE_PROGRAM)
+WRITEDWORD64LE(program_write_dword_64le, ADDRESS_SPACE_PROGRAM)
+ WRITEQWORD64(program_write_qword_64le, ADDRESS_SPACE_PROGRAM)
+ WRITEMASKED64(program_write_masked_64le,ADDRESS_SPACE_PROGRAM)
+
+
+/*-------------------------------------------------
+ Data memory handlers
+-------------------------------------------------*/
+
+ READBYTE8(data_read_byte_8, ADDRESS_SPACE_DATA)
+ WRITEBYTE8(data_write_byte_8, ADDRESS_SPACE_DATA)
+
+ READBYTE16BE(data_read_byte_16be, ADDRESS_SPACE_DATA)
+ READWORD16(data_read_word_16be, ADDRESS_SPACE_DATA)
+ WRITEBYTE16BE(data_write_byte_16be, ADDRESS_SPACE_DATA)
+ WRITEWORD16(data_write_word_16be, ADDRESS_SPACE_DATA)
+
+ READBYTE16LE(data_read_byte_16le, ADDRESS_SPACE_DATA)
+ READWORD16(data_read_word_16le, ADDRESS_SPACE_DATA)
+ WRITEBYTE16LE(data_write_byte_16le, ADDRESS_SPACE_DATA)
+ WRITEWORD16(data_write_word_16le, ADDRESS_SPACE_DATA)
+
+ READBYTE32BE(data_read_byte_32be, ADDRESS_SPACE_DATA)
+ READWORD32BE(data_read_word_32be, ADDRESS_SPACE_DATA)
+ READDWORD32(data_read_dword_32be, ADDRESS_SPACE_DATA)
+ READMASKED32(data_read_masked_32be, ADDRESS_SPACE_DATA)
+ WRITEBYTE32BE(data_write_byte_32be, ADDRESS_SPACE_DATA)
+ WRITEWORD32BE(data_write_word_32be, ADDRESS_SPACE_DATA)
+ WRITEDWORD32(data_write_dword_32be, ADDRESS_SPACE_DATA)
+ WRITEMASKED32(data_write_masked_32be,ADDRESS_SPACE_DATA)
+
+ READBYTE32LE(data_read_byte_32le, ADDRESS_SPACE_DATA)
+ READWORD32LE(data_read_word_32le, ADDRESS_SPACE_DATA)
+ READDWORD32(data_read_dword_32le, ADDRESS_SPACE_DATA)
+ READMASKED32(data_read_masked_32le, ADDRESS_SPACE_DATA)
+ WRITEBYTE32LE(data_write_byte_32le, ADDRESS_SPACE_DATA)
+ WRITEWORD32LE(data_write_word_32le, ADDRESS_SPACE_DATA)
+ WRITEDWORD32(data_write_dword_32le, ADDRESS_SPACE_DATA)
+ WRITEMASKED32(data_write_masked_32le,ADDRESS_SPACE_DATA)
+
+ READBYTE64BE(data_read_byte_64be, ADDRESS_SPACE_DATA)
+ READWORD64BE(data_read_word_64be, ADDRESS_SPACE_DATA)
+ READDWORD64BE(data_read_dword_64be, ADDRESS_SPACE_DATA)
+ READQWORD64(data_read_qword_64be, ADDRESS_SPACE_DATA)
+ READMASKED64(data_read_masked_64be, ADDRESS_SPACE_DATA)
+ WRITEBYTE64BE(data_write_byte_64be, ADDRESS_SPACE_DATA)
+ WRITEWORD64BE(data_write_word_64be, ADDRESS_SPACE_DATA)
+WRITEDWORD64BE(data_write_dword_64be, ADDRESS_SPACE_DATA)
+ WRITEQWORD64(data_write_qword_64be, ADDRESS_SPACE_DATA)
+ WRITEMASKED64(data_write_masked_64be,ADDRESS_SPACE_DATA)
+
+ READBYTE64LE(data_read_byte_64le, ADDRESS_SPACE_DATA)
+ READWORD64LE(data_read_word_64le, ADDRESS_SPACE_DATA)
+ READDWORD64LE(data_read_dword_64le, ADDRESS_SPACE_DATA)
+ READQWORD64(data_read_qword_64le, ADDRESS_SPACE_DATA)
+ READMASKED64(data_read_masked_64le, ADDRESS_SPACE_DATA)
+ WRITEBYTE64LE(data_write_byte_64le, ADDRESS_SPACE_DATA)
+ WRITEWORD64LE(data_write_word_64le, ADDRESS_SPACE_DATA)
+WRITEDWORD64LE(data_write_dword_64le, ADDRESS_SPACE_DATA)
+ WRITEQWORD64(data_write_qword_64le, ADDRESS_SPACE_DATA)
+ WRITEMASKED64(data_write_masked_64le,ADDRESS_SPACE_DATA)
+
+
+/*-------------------------------------------------
+ I/O memory handlers
+-------------------------------------------------*/
+
+ READBYTE8(io_read_byte_8, ADDRESS_SPACE_IO)
+ WRITEBYTE8(io_write_byte_8, ADDRESS_SPACE_IO)
+
+ READBYTE16BE(io_read_byte_16be, ADDRESS_SPACE_IO)
+ READWORD16(io_read_word_16be, ADDRESS_SPACE_IO)
+ WRITEBYTE16BE(io_write_byte_16be, ADDRESS_SPACE_IO)
+ WRITEWORD16(io_write_word_16be, ADDRESS_SPACE_IO)
+
+ READBYTE16LE(io_read_byte_16le, ADDRESS_SPACE_IO)
+ READWORD16(io_read_word_16le, ADDRESS_SPACE_IO)
+ WRITEBYTE16LE(io_write_byte_16le, ADDRESS_SPACE_IO)
+ WRITEWORD16(io_write_word_16le, ADDRESS_SPACE_IO)
+
+ READBYTE32BE(io_read_byte_32be, ADDRESS_SPACE_IO)
+ READWORD32BE(io_read_word_32be, ADDRESS_SPACE_IO)
+ READDWORD32(io_read_dword_32be, ADDRESS_SPACE_IO)
+ READMASKED32(io_read_masked_32be, ADDRESS_SPACE_IO)
+ WRITEBYTE32BE(io_write_byte_32be, ADDRESS_SPACE_IO)
+ WRITEWORD32BE(io_write_word_32be, ADDRESS_SPACE_IO)
+ WRITEDWORD32(io_write_dword_32be, ADDRESS_SPACE_IO)
+ WRITEMASKED32(io_write_masked_32be,ADDRESS_SPACE_IO)
+
+ READBYTE32LE(io_read_byte_32le, ADDRESS_SPACE_IO)
+ READWORD32LE(io_read_word_32le, ADDRESS_SPACE_IO)
+ READDWORD32(io_read_dword_32le, ADDRESS_SPACE_IO)
+ READMASKED32(io_read_masked_32le, ADDRESS_SPACE_IO)
+ WRITEBYTE32LE(io_write_byte_32le, ADDRESS_SPACE_IO)
+ WRITEWORD32LE(io_write_word_32le, ADDRESS_SPACE_IO)
+ WRITEDWORD32(io_write_dword_32le, ADDRESS_SPACE_IO)
+ WRITEMASKED32(io_write_masked_32le,ADDRESS_SPACE_IO)
+
+ READBYTE64BE(io_read_byte_64be, ADDRESS_SPACE_IO)
+ READWORD64BE(io_read_word_64be, ADDRESS_SPACE_IO)
+ READDWORD64BE(io_read_dword_64be, ADDRESS_SPACE_IO)
+ READQWORD64(io_read_qword_64be, ADDRESS_SPACE_IO)
+ READMASKED64(io_read_masked_64be, ADDRESS_SPACE_IO)
+ WRITEBYTE64BE(io_write_byte_64be, ADDRESS_SPACE_IO)
+ WRITEWORD64BE(io_write_word_64be, ADDRESS_SPACE_IO)
+WRITEDWORD64BE(io_write_dword_64be, ADDRESS_SPACE_IO)
+ WRITEQWORD64(io_write_qword_64be, ADDRESS_SPACE_IO)
+ WRITEMASKED64(io_write_masked_64be,ADDRESS_SPACE_IO)
+
+ READBYTE64LE(io_read_byte_64le, ADDRESS_SPACE_IO)
+ READWORD64LE(io_read_word_64le, ADDRESS_SPACE_IO)
+ READDWORD64LE(io_read_dword_64le, ADDRESS_SPACE_IO)
+ READQWORD64(io_read_qword_64le, ADDRESS_SPACE_IO)
+ READMASKED64(io_read_masked_64le, ADDRESS_SPACE_IO)
+ WRITEBYTE64LE(io_write_byte_64le, ADDRESS_SPACE_IO)
+ WRITEWORD64LE(io_write_word_64le, ADDRESS_SPACE_IO)
+WRITEDWORD64LE(io_write_dword_64le, ADDRESS_SPACE_IO)
+ WRITEQWORD64(io_write_qword_64le, ADDRESS_SPACE_IO)
+ WRITEMASKED64(io_write_masked_64le,ADDRESS_SPACE_IO)
+
+
+/*-------------------------------------------------
+ safe opcode reading
+-------------------------------------------------*/
+
+UINT8 cpu_readop_safe(offs_t offset)
+{
+ activecpu_set_opbase(offset);
+ return cpu_readop_unsafe(offset);
+}
+
+UINT16 cpu_readop16_safe(offs_t offset)
+{
+ activecpu_set_opbase(offset);
+ return cpu_readop16_unsafe(offset);
+}
+
+UINT32 cpu_readop32_safe(offs_t offset)
+{
+ activecpu_set_opbase(offset);
+ return cpu_readop32_unsafe(offset);
+}
+
+UINT64 cpu_readop64_safe(offs_t offset)
+{
+ activecpu_set_opbase(offset);
+ return cpu_readop64_unsafe(offset);
+}
+
+UINT8 cpu_readop_arg_safe(offs_t offset)
+{
+ activecpu_set_opbase(offset);
+ return cpu_readop_arg_unsafe(offset);
+}
+
+UINT16 cpu_readop_arg16_safe(offs_t offset)
+{
+ activecpu_set_opbase(offset);
+ return cpu_readop_arg16_unsafe(offset);
+}
+
+UINT32 cpu_readop_arg32_safe(offs_t offset)
+{
+ activecpu_set_opbase(offset);
+ return cpu_readop_arg32_unsafe(offset);
+}
+
+UINT64 cpu_readop_arg64_safe(offs_t offset)
+{
+ activecpu_set_opbase(offset);
+ return cpu_readop_arg64_unsafe(offset);
+}
+
+
+/*-------------------------------------------------
+ unmapped memory handlers
+-------------------------------------------------*/
+
+static READ8_HANDLER( mrh8_unmap_program )
+{
+ if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory byte read from %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset));
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap;
+}
+static READ16_HANDLER( mrh16_unmap_program )
+{
+ if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory word read from %08X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*2), mem_mask ^ 0xffff);
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap;
+}
+static READ32_HANDLER( mrh32_unmap_program )
+{
+ if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory dword read from %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*4), mem_mask ^ 0xffffffff);
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap;
+}
+static READ64_HANDLER( mrh64_unmap_program )
+{
+ if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory qword read from %08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*8), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff);
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap;
+}
+
+static WRITE8_HANDLER( mwh8_unmap_program )
+{
+ if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory byte write to %08X = %02X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset), data);
+}
+static WRITE16_HANDLER( mwh16_unmap_program )
+{
+ if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory word write to %08X = %04X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*2), data, mem_mask ^ 0xffff);
+}
+static WRITE32_HANDLER( mwh32_unmap_program )
+{
+ if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory dword write to %08X = %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*4), data, mem_mask ^ 0xffffffff);
+}
+static WRITE64_HANDLER( mwh64_unmap_program )
+{
+ if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory qword write to %08X = %08X%08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*8), (int)(data >> 32), (int)(data & 0xffffffff), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff);
+}
+
+static READ8_HANDLER( mrh8_unmap_data )
+{
+ if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory byte read from %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset));
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap;
+}
+static READ16_HANDLER( mrh16_unmap_data )
+{
+ if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory word read from %08X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*2), mem_mask ^ 0xffff);
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap;
+}
+static READ32_HANDLER( mrh32_unmap_data )
+{
+ if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory dword read from %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*4), mem_mask ^ 0xffffffff);
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap;
+}
+static READ64_HANDLER( mrh64_unmap_data )
+{
+ if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory qword read from %08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*8), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff);
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap;
+}
+
+static WRITE8_HANDLER( mwh8_unmap_data )
+{
+ if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory byte write to %08X = %02X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset), data);
+}
+static WRITE16_HANDLER( mwh16_unmap_data )
+{
+ if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory word write to %08X = %04X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*2), data, mem_mask ^ 0xffff);
+}
+static WRITE32_HANDLER( mwh32_unmap_data )
+{
+ if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory dword write to %08X = %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*4), data, mem_mask ^ 0xffffffff);
+}
+static WRITE64_HANDLER( mwh64_unmap_data )
+{
+ if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory qword write to %08X = %08X%08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*8), (int)(data >> 32), (int)(data & 0xffffffff), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff);
+}
+
+static READ8_HANDLER( mrh8_unmap_io )
+{
+ if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O byte read from %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset));
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap;
+}
+static READ16_HANDLER( mrh16_unmap_io )
+{
+ if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O word read from %08X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*2), mem_mask ^ 0xffff);
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap;
+}
+static READ32_HANDLER( mrh32_unmap_io )
+{
+ if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O dword read from %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*4), mem_mask ^ 0xffffffff);
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap;
+}
+static READ64_HANDLER( mrh64_unmap_io )
+{
+ if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O qword read from %08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*8), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff);
+ return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap;
+}
+
+static WRITE8_HANDLER( mwh8_unmap_io )
+{
+ if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O byte write to %08X = %02X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset), data);
+}
+static WRITE16_HANDLER( mwh16_unmap_io )
+{
+ if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O word write to %08X = %04X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*2), data, mem_mask ^ 0xffff);
+}
+static WRITE32_HANDLER( mwh32_unmap_io )
+{
+ if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O dword write to %08X = %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*4), data, mem_mask ^ 0xffffffff);
+}
+static WRITE64_HANDLER( mwh64_unmap_io )
+{
+ if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O qword write to %08X = %08X%08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*8), (int)(data >> 32), (int)(data & 0xffffffff), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff);
+}
+
+
+/*-------------------------------------------------
+ no-op memory handlers
+-------------------------------------------------*/
+
+static READ8_HANDLER( mrh8_nop_program ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; }
+static READ16_HANDLER( mrh16_nop_program ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; }
+static READ32_HANDLER( mrh32_nop_program ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; }
+static READ64_HANDLER( mrh64_nop_program ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; }
+
+static READ8_HANDLER( mrh8_nop_data ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; }
+static READ16_HANDLER( mrh16_nop_data ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; }
+static READ32_HANDLER( mrh32_nop_data ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; }
+static READ64_HANDLER( mrh64_nop_data ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; }
+
+static READ8_HANDLER( mrh8_nop_io ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; }
+static READ16_HANDLER( mrh16_nop_io ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; }
+static READ32_HANDLER( mrh32_nop_io ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; }
+static READ64_HANDLER( mrh64_nop_io ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; }
+
+static WRITE8_HANDLER( mwh8_nop ) { }
+static WRITE16_HANDLER( mwh16_nop ) { }
+static WRITE32_HANDLER( mwh32_nop ) { }
+static WRITE64_HANDLER( mwh64_nop ) { }
+
+
+/*-------------------------------------------------
+ get_static_handler - returns points to static
+ memory handlers
+-------------------------------------------------*/
+
+static genf *get_static_handler(int databits, int readorwrite, int spacenum, int which)
+{
+ static const struct
+ {
+ UINT8 databits;
+ UINT8 handlernum;
+ UINT8 spacenum;
+ genf * read;
+ genf * write;
+ } static_handler_list[] =
+ {
+ { 8, STATIC_UNMAP, ADDRESS_SPACE_PROGRAM, (genf *)mrh8_unmap_program, (genf *)mwh8_unmap_program },
+ { 8, STATIC_UNMAP, ADDRESS_SPACE_DATA, (genf *)mrh8_unmap_data, (genf *)mwh8_unmap_data },
+ { 8, STATIC_UNMAP, ADDRESS_SPACE_IO, (genf *)mrh8_unmap_io, (genf *)mwh8_unmap_io },
+ { 8, STATIC_NOP, ADDRESS_SPACE_PROGRAM, (genf *)mrh8_nop_program, (genf *)mwh8_nop },
+ { 8, STATIC_NOP, ADDRESS_SPACE_DATA, (genf *)mrh8_nop_data, (genf *)mwh8_nop },
+ { 8, STATIC_NOP, ADDRESS_SPACE_IO, (genf *)mrh8_nop_io, (genf *)mwh8_nop },
+
+ { 16, STATIC_UNMAP, ADDRESS_SPACE_PROGRAM, (genf *)mrh16_unmap_program,(genf *)mwh16_unmap_program },
+ { 16, STATIC_UNMAP, ADDRESS_SPACE_DATA, (genf *)mrh16_unmap_data, (genf *)mwh16_unmap_data },
+ { 16, STATIC_UNMAP, ADDRESS_SPACE_IO, (genf *)mrh16_unmap_io, (genf *)mwh16_unmap_io },
+ { 16, STATIC_NOP, ADDRESS_SPACE_PROGRAM, (genf *)mrh16_nop_program, (genf *)mwh16_nop },
+ { 16, STATIC_NOP, ADDRESS_SPACE_DATA, (genf *)mrh16_nop_data, (genf *)mwh16_nop },
+ { 16, STATIC_NOP, ADDRESS_SPACE_IO, (genf *)mrh16_nop_io, (genf *)mwh16_nop },
+
+ { 32, STATIC_UNMAP, ADDRESS_SPACE_PROGRAM, (genf *)mrh32_unmap_program,(genf *)mwh32_unmap_program },
+ { 32, STATIC_UNMAP, ADDRESS_SPACE_DATA, (genf *)mrh32_unmap_data, (genf *)mwh32_unmap_data },
+ { 32, STATIC_UNMAP, ADDRESS_SPACE_IO, (genf *)mrh32_unmap_io, (genf *)mwh32_unmap_io },
+ { 32, STATIC_NOP, ADDRESS_SPACE_PROGRAM, (genf *)mrh32_nop_program, (genf *)mwh32_nop },
+ { 32, STATIC_NOP, ADDRESS_SPACE_DATA, (genf *)mrh32_nop_data, (genf *)mwh32_nop },
+ { 32, STATIC_NOP, ADDRESS_SPACE_IO, (genf *)mrh32_nop_io, (genf *)mwh32_nop },
+
+ { 64, STATIC_UNMAP, ADDRESS_SPACE_PROGRAM, (genf *)mrh64_unmap_program,(genf *)mwh64_unmap_program },
+ { 64, STATIC_UNMAP, ADDRESS_SPACE_DATA, (genf *)mrh64_unmap_data, (genf *)mwh64_unmap_data },
+ { 64, STATIC_UNMAP, ADDRESS_SPACE_IO, (genf *)mrh64_unmap_io, (genf *)mwh64_unmap_io },
+ { 64, STATIC_NOP, ADDRESS_SPACE_PROGRAM, (genf *)mrh64_nop_program, (genf *)mwh64_nop },
+ { 64, STATIC_NOP, ADDRESS_SPACE_DATA, (genf *)mrh64_nop_data, (genf *)mwh64_nop },
+ { 64, STATIC_NOP, ADDRESS_SPACE_IO, (genf *)mrh64_nop_io, (genf *)mwh64_nop },
+ };
+ int tablenum;
+
+ for (tablenum = 0; tablenum < sizeof(static_handler_list) / sizeof(static_handler_list[0]); tablenum++)
+ if (static_handler_list[tablenum].databits == databits && static_handler_list[tablenum].handlernum == which)
+ if (static_handler_list[tablenum].spacenum == 0xff || static_handler_list[tablenum].spacenum == spacenum)
+ return readorwrite ? static_handler_list[tablenum].write : static_handler_list[tablenum].read;
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ debugging
+-------------------------------------------------*/
+
+static const char *handler_to_string(const table_data *table, UINT8 entry)
+{
+ static const char *strings[] =
+ {
+ "invalid", "bank 1", "bank 2", "bank 3",
+ "bank 4", "bank 5", "bank 6", "bank 7",
+ "bank 8", "bank 9", "bank 10", "bank 11",
+ "bank 12", "bank 13", "bank 14", "bank 15",
+ "bank 16", "bank 17", "bank 18", "bank 19",
+ "bank 20", "bank 21", "bank 22", "bank 23",
+ "bank 24", "bank 25", "bank 26", "bank 27",
+ "bank 28", "bank 29", "bank 30", "bank 31",
+ "bank 32", "ram[33]", "ram[34]", "ram[35]",
+ "ram[36]", "ram[37]", "ram[38]", "ram[39]",
+ "ram[40]", "ram[41]", "ram[42]", "ram[43]",
+ "ram[44]", "ram[45]", "ram[46]", "ram[47]",
+ "ram[48]", "ram[49]", "ram[50]", "ram[51]",
+ "ram[52]", "ram[53]", "ram[54]", "ram[55]",
+ "ram[56]", "ram[57]", "ram[58]", "ram[59]",
+ "ram[60]", "ram[61]", "ram[62]", "ram[63]",
+ "ram[64]", "ram[65]", "ram[66]", "ram[67]",
+ "ram[68]", "rom", "nop", "unmapped"
+ };
+
+ /* constant strings for lower entries */
+ if (entry < STATIC_COUNT)
+ return strings[entry];
+ else
+ return table->handlers[entry].name ? table->handlers[entry].name : "???";
+}
+
+static void dump_map(FILE *file, const addrspace_data *space, const table_data *table)
+{
+ int l1count = 1 << LEVEL1_BITS;
+ int l2count = 1 << LEVEL2_BITS;
+ UINT8 lastentry = STATIC_UNMAP;
+ int entrymatches = 0;
+ int i, j;
+
+ /* dump generic information */
+ fprintf(file, " Address bits = %d\n", space->abits);
+ fprintf(file, " Data bits = %d\n", space->dbits);
+ fprintf(file, " L1 bits = %d\n", LEVEL1_BITS);
+ fprintf(file, " L2 bits = %d\n", LEVEL2_BITS);
+ fprintf(file, " Address mask = %X\n", space->mask);
+ fprintf(file, "\n");
+
+ /* loop over level 1 entries */
+ for (i = 0; i < l1count; i++)
+ {
+ UINT8 entry = table->table[i];
+
+ /* if this entry matches the previous one, just count it */
+ if (entry < SUBTABLE_BASE && entry == lastentry)
+ {
+ entrymatches++;
+ continue;
+ }
+
+ /* otherwise, print accumulated info */
+ if (lastentry < SUBTABLE_BASE && lastentry != STATIC_UNMAP)
+ fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n",
+ (i - entrymatches) << LEVEL2_BITS,
+ (i << LEVEL2_BITS) - 1,
+ lastentry,
+ handler_to_string(table, lastentry),
+ table->handlers[lastentry].offset);
+
+ /* start counting with this entry */
+ lastentry = entry;
+ entrymatches = 1;
+
+ /* if we're a subtable, we need to drill down */
+ if (entry >= SUBTABLE_BASE)
+ {
+ UINT8 lastentry2 = STATIC_UNMAP;
+ int entry2matches = 0;
+
+ /* loop over level 2 entries */
+ entry -= SUBTABLE_BASE;
+ for (j = 0; j < l2count; j++)
+ {
+ UINT8 entry2 = table->table[(1 << LEVEL1_BITS) + (entry << LEVEL2_BITS) + j];
+
+ /* if this entry matches the previous one, just count it */
+ if (entry2 < SUBTABLE_BASE && entry2 == lastentry2)
+ {
+ entry2matches++;
+ continue;
+ }
+
+ /* otherwise, print accumulated info */
+ if (lastentry2 < SUBTABLE_BASE && lastentry2 != STATIC_UNMAP)
+ fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n",
+ ((i << LEVEL2_BITS) | (j - entry2matches)),
+ ((i << LEVEL2_BITS) | (j - 1)),
+ lastentry2,
+ handler_to_string(table, lastentry2),
+ table->handlers[lastentry2].offset);
+
+ /* start counting with this entry */
+ lastentry2 = entry2;
+ entry2matches = 1;
+ }
+
+ /* flush the last entry */
+ if (lastentry2 < SUBTABLE_BASE && lastentry2 != STATIC_UNMAP)
+ fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n",
+ ((i << LEVEL2_BITS) | (j - entry2matches)),
+ ((i << LEVEL2_BITS) | (j - 1)),
+ lastentry2,
+ handler_to_string(table, lastentry2),
+ table->handlers[lastentry2].offset);
+ }
+ }
+
+ /* flush the last entry */
+ if (lastentry < SUBTABLE_BASE && lastentry != STATIC_UNMAP)
+ fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n",
+ (i - entrymatches) << LEVEL2_BITS,
+ (i << LEVEL2_BITS) - 1,
+ lastentry,
+ handler_to_string(table, lastentry),
+ table->handlers[lastentry].offset);
+}
+
+void memory_dump(FILE *file)
+{
+ int cpunum, spacenum;
+
+ /* skip if we can't open the file */
+ if (!file)
+ return;
+
+ /* loop over CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++)
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ if (cpudata[cpunum].space[spacenum].abits)
+ {
+ fprintf(file, "\n\n"
+ "=========================================\n"
+ "CPU %d address space %d read handler dump\n"
+ "=========================================\n", cpunum, spacenum);
+ dump_map(file, &cpudata[cpunum].space[spacenum], &cpudata[cpunum].space[spacenum].read);
+
+ fprintf(file, "\n\n"
+ "==========================================\n"
+ "CPU %d address space %d write handler dump\n"
+ "==========================================\n", cpunum, spacenum);
+ dump_map(file, &cpudata[cpunum].space[spacenum], &cpudata[cpunum].space[spacenum].write);
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_get_handler_string - return a string
+ describing the handler at a particular offset
+-------------------------------------------------*/
+
+const char *memory_get_handler_string(int read0_or_write1, int cpunum, int spacenum, offs_t offset)
+{
+ addrspace_data *space = &cpudata[cpunum].space[spacenum];
+ const table_data *table = read0_or_write1 ? &space->write : &space->read;
+ UINT8 entry;
+
+ /* perform the lookup */
+ offset &= space->mask;
+ entry = table->table[LEVEL1_INDEX(offset)];
+ if (entry >= SUBTABLE_BASE)
+ entry = table->table[LEVEL2_INDEX(entry, offset)];
+
+ /* 8-bit case: RAM/ROM */
+ return handler_to_string(table, entry);
+}
diff --git a/src/emu/memory.h b/src/emu/memory.h
new file mode 100644
index 00000000000..ffe03d46136
--- /dev/null
+++ b/src/emu/memory.h
@@ -0,0 +1,1166 @@
+/***************************************************************************
+
+ memory.h
+
+ Functions which handle the CPU memory accesses.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __MEMORY_H__
+#define __MEMORY_H__
+
+#include "mamecore.h"
+
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#ifdef MAME_DEBUG
+#define CPUREADOP_SAFETY_NONE 0
+#define CPUREADOP_SAFETY_PARTIAL 0
+#define CPUREADOP_SAFETY_FULL 1
+#elif defined(MESS)
+#define CPUREADOP_SAFETY_NONE 0
+#define CPUREADOP_SAFETY_PARTIAL 1
+#define CPUREADOP_SAFETY_FULL 0
+#else
+#define CPUREADOP_SAFETY_NONE 1
+#define CPUREADOP_SAFETY_PARTIAL 0
+#define CPUREADOP_SAFETY_FULL 0
+#endif
+
+
+
+/***************************************************************************
+ BASIC TYPE DEFINITIONS
+***************************************************************************/
+
+/* ----- typedefs for data and offset types ----- */
+typedef UINT32 offs_t;
+
+/* ----- typedefs for the various common data access handlers ----- */
+typedef UINT8 (*read8_handler) (ATTR_UNUSED offs_t offset);
+typedef void (*write8_handler) (ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT8 data);
+typedef UINT16 (*read16_handler) (ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT16 mem_mask);
+typedef void (*write16_handler)(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT16 data, ATTR_UNUSED UINT16 mem_mask);
+typedef UINT32 (*read32_handler) (ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT32 mem_mask);
+typedef void (*write32_handler)(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT32 data, ATTR_UNUSED UINT32 mem_mask);
+typedef UINT64 (*read64_handler) (ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT64 mem_mask);
+typedef void (*write64_handler)(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT64 data, ATTR_UNUSED UINT64 mem_mask);
+typedef offs_t (*opbase_handler) (ATTR_UNUSED offs_t address);
+
+/* ----- this struct contains pointers to the live read/write routines ----- */
+struct _data_accessors
+{
+ UINT8 (*read_byte)(offs_t offset);
+ UINT16 (*read_word)(offs_t offset);
+ UINT32 (*read_dword)(offs_t offset);
+ UINT64 (*read_qword)(offs_t offset);
+
+ void (*write_byte)(offs_t offset, UINT8 data);
+ void (*write_word)(offs_t offset, UINT16 data);
+ void (*write_dword)(offs_t offset, UINT32 data);
+ void (*write_qword)(offs_t offset, UINT64 data);
+};
+typedef struct _data_accessors data_accessors;
+
+
+
+/***************************************************************************
+ BASIC MACROS
+***************************************************************************/
+
+/* ----- macros for declaring the various common data access handlers ----- */
+#define READ8_HANDLER(name) UINT8 name(ATTR_UNUSED offs_t offset)
+#define WRITE8_HANDLER(name) void name(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT8 data)
+#define READ16_HANDLER(name) UINT16 name(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT16 mem_mask)
+#define WRITE16_HANDLER(name) void name(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT16 data, ATTR_UNUSED UINT16 mem_mask)
+#define READ32_HANDLER(name) UINT32 name(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT32 mem_mask)
+#define WRITE32_HANDLER(name) void name(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT32 data, ATTR_UNUSED UINT32 mem_mask)
+#define READ64_HANDLER(name) UINT64 name(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT64 mem_mask)
+#define WRITE64_HANDLER(name) void name(ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT64 data, ATTR_UNUSED UINT64 mem_mask)
+#define OPBASE_HANDLER(name) offs_t name(ATTR_UNUSED offs_t address)
+
+/* ----- macros for accessing bytes and words within larger chunks ----- */
+#ifdef LSB_FIRST
+ #define BYTE_XOR_BE(a) ((a) ^ 1) /* read/write a byte to a 16-bit space */
+ #define BYTE_XOR_LE(a) (a)
+ #define BYTE4_XOR_BE(a) ((a) ^ 3) /* read/write a byte to a 32-bit space */
+ #define BYTE4_XOR_LE(a) (a)
+ #define WORD_XOR_BE(a) ((a) ^ 2) /* read/write a word to a 32-bit space */
+ #define WORD_XOR_LE(a) (a)
+ #define BYTE8_XOR_BE(a) ((a) ^ 7) /* read/write a byte to a 64-bit space */
+ #define BYTE8_XOR_LE(a) (a)
+ #define WORD2_XOR_BE(a) ((a) ^ 6) /* read/write a word to a 64-bit space */
+ #define WORD2_XOR_LE(a) (a)
+ #define DWORD_XOR_BE(a) ((a) ^ 4) /* read/write a dword to a 64-bit space */
+ #define DWORD_XOR_LE(a) (a)
+#else
+ #define BYTE_XOR_BE(a) (a)
+ #define BYTE_XOR_LE(a) ((a) ^ 1) /* read/write a byte to a 16-bit space */
+ #define BYTE4_XOR_BE(a) (a)
+ #define BYTE4_XOR_LE(a) ((a) ^ 3) /* read/write a byte to a 32-bit space */
+ #define WORD_XOR_BE(a) (a)
+ #define WORD_XOR_LE(a) ((a) ^ 2) /* read/write a word to a 32-bit space */
+ #define BYTE8_XOR_BE(a) (a)
+ #define BYTE8_XOR_LE(a) ((a) ^ 7) /* read/write a byte to a 64-bit space */
+ #define WORD2_XOR_BE(a) (a)
+ #define WORD2_XOR_LE(a) ((a) ^ 6) /* read/write a word to a 64-bit space */
+ #define DWORD_XOR_BE(a) (a)
+ #define DWORD_XOR_LE(a) ((a) ^ 4) /* read/write a dword to a 64-bit space */
+#endif
+
+
+
+/***************************************************************************
+ ADDRESS ARRAY CONSTANTS
+****************************************************************************
+ These apply to values in the array of read/write handlers that is
+ declared within each driver.
+***************************************************************************/
+
+/* ----- definitions for the flags in the address maps ----- */
+#define AM_FLAGS_EXTENDED 0x01 /* this is an extended entry with the below flags in the start field */
+#define AM_FLAGS_MATCH_MASK 0x02 /* this entry should have the start/end pair treated as a match/mask pair */
+#define AM_FLAGS_END 0x04 /* this is the terminating entry in the array */
+
+/* ----- definitions for the extended flags in the address maps ----- */
+#define AMEF_SPECIFIES_SPACE 0x00000001 /* set if the address space is specified */
+#define AMEF_SPECIFIES_ABITS 0x00000002 /* set if the number of address space bits is specified */
+#define AMEF_SPECIFIES_DBITS 0x00000004 /* set if the databus width is specified */
+#define AMEF_SPECIFIES_UNMAP 0x00000008 /* set if the unmap value is specified */
+
+/* ----- definitions for specifying the address space in the extended flags ----- */
+#define AMEF_SPACE_SHIFT 8 /* shift to get at the address space */
+#define AMEF_SPACE_MASK (0x0f << AMEF_SPACE_SHIFT) /* mask to get at the address space */
+#define AMEF_SPACE(x) (((x) << AMEF_SPACE_SHIFT) | AMEF_SPECIFIES_SPACE) /* specifies a given address space */
+
+/* ----- definitions for specifying the address bus width in the extended flags ----- */
+#define AMEF_ABITS_SHIFT 12 /* shift to get the address bits count */
+#define AMEF_ABITS_MASK (0x3f << AMEF_ABITS_SHIFT) /* mask to get at the address bits count */
+#define AMEF_ABITS(n) (((n) << AMEF_ABITS_SHIFT) | AMEF_SPECIFIES_ABITS) /* specifies a given number of address */
+
+/* ----- definitions for specifying the data bus width in the extended flags ----- */
+#define AMEF_DBITS_SHIFT 18 /* shift to get the data bits count */
+#define AMEF_DBITS_MASK (0x07 << AMEF_DBITS_SHIFT) /* mask to get at the data bits count */
+#define AMEF_DBITS(n) ((((n)/8-1) << AMEF_DBITS_SHIFT) | AMEF_SPECIFIES_DBITS) /* specifies a given data bus width */
+
+/* ----- definitions for specifying the unmap value in the extended flags ----- */
+#define AMEF_UNMAP_SHIFT 21 /* shift to get the unmap value */
+#define AMEF_UNMAP_MASK (1 << AMEF_UNMAP_SHIFT) /* mask to get at the unmap value */
+#define AMEF_UNMAP(x) (((x) << AMEF_UNMAP_SHIFT) | AMEF_SPECIFIES_UNMAP) /* specifies a given unmap value */
+
+/* ----- static data access handler constants ----- */
+#define STATIC_INVALID 0 /* invalid - should never be used */
+#define STATIC_BANK1 1 /* banked memory #1 */
+#define STATIC_BANK2 2 /* banked memory #2 */
+#define STATIC_BANK3 3 /* banked memory #3 */
+#define STATIC_BANK4 4 /* banked memory #4 */
+#define STATIC_BANK5 5 /* banked memory #5 */
+#define STATIC_BANK6 6 /* banked memory #6 */
+#define STATIC_BANK7 7 /* banked memory #7 */
+#define STATIC_BANK8 8 /* banked memory #8 */
+#define STATIC_BANK9 9 /* banked memory #9 */
+#define STATIC_BANK10 10 /* banked memory #10 */
+#define STATIC_BANK11 11 /* banked memory #11 */
+#define STATIC_BANK12 12 /* banked memory #12 */
+#define STATIC_BANK13 13 /* banked memory #13 */
+#define STATIC_BANK14 14 /* banked memory #14 */
+#define STATIC_BANK15 15 /* banked memory #15 */
+#define STATIC_BANK16 16 /* banked memory #16 */
+#define STATIC_BANK17 17 /* banked memory #17 */
+#define STATIC_BANK18 18 /* banked memory #18 */
+#define STATIC_BANK19 19 /* banked memory #19 */
+#define STATIC_BANK20 20 /* banked memory #20 */
+#define STATIC_BANK21 21 /* banked memory #21 */
+#define STATIC_BANK22 22 /* banked memory #22 */
+#define STATIC_BANK23 23 /* banked memory #23 */
+#define STATIC_BANK24 24 /* banked memory #24 */
+#define STATIC_BANK25 25 /* banked memory #25 */
+#define STATIC_BANK26 26 /* banked memory #26 */
+#define STATIC_BANK27 27 /* banked memory #27 */
+#define STATIC_BANK28 28 /* banked memory #28 */
+#define STATIC_BANK29 29 /* banked memory #29 */
+#define STATIC_BANK30 30 /* banked memory #30 */
+#define STATIC_BANK31 31 /* banked memory #31 */
+#define STATIC_BANK32 32 /* banked memory #32 */
+/* entries 33-67 are reserved for dynamically allocated internal banks */
+#define STATIC_RAM 68 /* RAM - standard reads/writes */
+#define STATIC_ROM 69 /* ROM - standard reads, no writes */
+#define STATIC_NOP 70 /* unmapped - all unmapped memory goes here */
+#define STATIC_UNMAP 71 /* unmapped - all unmapped memory goes here */
+#define STATIC_COUNT 72 /* total number of static handlers */
+
+/* ----- banking constants ----- */
+#define MAX_BANKS 66 /* maximum number of banks */
+#define MAX_BANK_ENTRIES 256 /* maximum number of possible bank values */
+#define MAX_EXPLICIT_BANKS 32 /* maximum number of explicitly-defined banks */
+#define STATIC_BANKMAX (STATIC_RAM - 1) /* handler constant of last bank */
+
+
+
+/***************************************************************************
+ STATIC ENTRY CONSTANTS
+****************************************************************************
+ The first 32 entries in the address lookup table are reserved for
+ "static" handlers. These are internal handlers for RAM, ROM, banks,
+ and unmapped areas in the address space. The following definitions
+ are the properly-casted versions of the STATIC_ constants above.
+***************************************************************************/
+
+/* 8-bit reads */
+#define MRA8_BANK1 ((read8_handler)STATIC_BANK1)
+#define MRA8_BANK2 ((read8_handler)STATIC_BANK2)
+#define MRA8_BANK3 ((read8_handler)STATIC_BANK3)
+#define MRA8_BANK4 ((read8_handler)STATIC_BANK4)
+#define MRA8_BANK5 ((read8_handler)STATIC_BANK5)
+#define MRA8_BANK6 ((read8_handler)STATIC_BANK6)
+#define MRA8_BANK7 ((read8_handler)STATIC_BANK7)
+#define MRA8_BANK8 ((read8_handler)STATIC_BANK8)
+#define MRA8_BANK9 ((read8_handler)STATIC_BANK9)
+#define MRA8_BANK10 ((read8_handler)STATIC_BANK10)
+#define MRA8_BANK11 ((read8_handler)STATIC_BANK11)
+#define MRA8_BANK12 ((read8_handler)STATIC_BANK12)
+#define MRA8_BANK13 ((read8_handler)STATIC_BANK13)
+#define MRA8_BANK14 ((read8_handler)STATIC_BANK14)
+#define MRA8_BANK15 ((read8_handler)STATIC_BANK15)
+#define MRA8_BANK16 ((read8_handler)STATIC_BANK16)
+#define MRA8_BANK17 ((read8_handler)STATIC_BANK17)
+#define MRA8_BANK18 ((read8_handler)STATIC_BANK18)
+#define MRA8_BANK19 ((read8_handler)STATIC_BANK19)
+#define MRA8_BANK20 ((read8_handler)STATIC_BANK20)
+#define MRA8_BANK21 ((read8_handler)STATIC_BANK21)
+#define MRA8_BANK22 ((read8_handler)STATIC_BANK22)
+#define MRA8_BANK23 ((read8_handler)STATIC_BANK23)
+#define MRA8_BANK24 ((read8_handler)STATIC_BANK24)
+#define MRA8_BANK25 ((read8_handler)STATIC_BANK25)
+#define MRA8_BANK26 ((read8_handler)STATIC_BANK26)
+#define MRA8_BANK27 ((read8_handler)STATIC_BANK27)
+#define MRA8_BANK28 ((read8_handler)STATIC_BANK28)
+#define MRA8_BANK29 ((read8_handler)STATIC_BANK29)
+#define MRA8_BANK30 ((read8_handler)STATIC_BANK30)
+#define MRA8_BANK31 ((read8_handler)STATIC_BANK31)
+#define MRA8_BANK32 ((read8_handler)STATIC_BANK32)
+#define MRA8_RAM ((read8_handler)STATIC_RAM)
+#define MRA8_ROM ((read8_handler)STATIC_ROM)
+#define MRA8_NOP ((read8_handler)STATIC_NOP)
+#define MRA8_UNMAP ((read8_handler)STATIC_UNMAP)
+
+/* 8-bit writes */
+#define MWA8_BANK1 ((write8_handler)STATIC_BANK1)
+#define MWA8_BANK2 ((write8_handler)STATIC_BANK2)
+#define MWA8_BANK3 ((write8_handler)STATIC_BANK3)
+#define MWA8_BANK4 ((write8_handler)STATIC_BANK4)
+#define MWA8_BANK5 ((write8_handler)STATIC_BANK5)
+#define MWA8_BANK6 ((write8_handler)STATIC_BANK6)
+#define MWA8_BANK7 ((write8_handler)STATIC_BANK7)
+#define MWA8_BANK8 ((write8_handler)STATIC_BANK8)
+#define MWA8_BANK9 ((write8_handler)STATIC_BANK9)
+#define MWA8_BANK10 ((write8_handler)STATIC_BANK10)
+#define MWA8_BANK11 ((write8_handler)STATIC_BANK11)
+#define MWA8_BANK12 ((write8_handler)STATIC_BANK12)
+#define MWA8_BANK13 ((write8_handler)STATIC_BANK13)
+#define MWA8_BANK14 ((write8_handler)STATIC_BANK14)
+#define MWA8_BANK15 ((write8_handler)STATIC_BANK15)
+#define MWA8_BANK16 ((write8_handler)STATIC_BANK16)
+#define MWA8_BANK17 ((write8_handler)STATIC_BANK17)
+#define MWA8_BANK18 ((write8_handler)STATIC_BANK18)
+#define MWA8_BANK19 ((write8_handler)STATIC_BANK19)
+#define MWA8_BANK20 ((write8_handler)STATIC_BANK20)
+#define MWA8_BANK21 ((write8_handler)STATIC_BANK21)
+#define MWA8_BANK22 ((write8_handler)STATIC_BANK22)
+#define MWA8_BANK23 ((write8_handler)STATIC_BANK23)
+#define MWA8_BANK24 ((write8_handler)STATIC_BANK24)
+#define MWA8_BANK25 ((write8_handler)STATIC_BANK25)
+#define MWA8_BANK26 ((write8_handler)STATIC_BANK26)
+#define MWA8_BANK27 ((write8_handler)STATIC_BANK27)
+#define MWA8_BANK28 ((write8_handler)STATIC_BANK28)
+#define MWA8_BANK29 ((write8_handler)STATIC_BANK29)
+#define MWA8_BANK30 ((write8_handler)STATIC_BANK30)
+#define MWA8_BANK31 ((write8_handler)STATIC_BANK31)
+#define MWA8_BANK32 ((write8_handler)STATIC_BANK32)
+#define MWA8_RAM ((write8_handler)STATIC_RAM)
+#define MWA8_ROM ((write8_handler)STATIC_ROM)
+#define MWA8_NOP ((write8_handler)STATIC_NOP)
+#define MWA8_UNMAP ((write8_handler)STATIC_UNMAP)
+
+/* 16-bit reads */
+#define MRA16_BANK1 ((read16_handler)STATIC_BANK1)
+#define MRA16_BANK2 ((read16_handler)STATIC_BANK2)
+#define MRA16_BANK3 ((read16_handler)STATIC_BANK3)
+#define MRA16_BANK4 ((read16_handler)STATIC_BANK4)
+#define MRA16_BANK5 ((read16_handler)STATIC_BANK5)
+#define MRA16_BANK6 ((read16_handler)STATIC_BANK6)
+#define MRA16_BANK7 ((read16_handler)STATIC_BANK7)
+#define MRA16_BANK8 ((read16_handler)STATIC_BANK8)
+#define MRA16_BANK9 ((read16_handler)STATIC_BANK9)
+#define MRA16_BANK10 ((read16_handler)STATIC_BANK10)
+#define MRA16_BANK11 ((read16_handler)STATIC_BANK11)
+#define MRA16_BANK12 ((read16_handler)STATIC_BANK12)
+#define MRA16_BANK13 ((read16_handler)STATIC_BANK13)
+#define MRA16_BANK14 ((read16_handler)STATIC_BANK14)
+#define MRA16_BANK15 ((read16_handler)STATIC_BANK15)
+#define MRA16_BANK16 ((read16_handler)STATIC_BANK16)
+#define MRA16_BANK17 ((read16_handler)STATIC_BANK17)
+#define MRA16_BANK18 ((read16_handler)STATIC_BANK18)
+#define MRA16_BANK19 ((read16_handler)STATIC_BANK19)
+#define MRA16_BANK20 ((read16_handler)STATIC_BANK20)
+#define MRA16_BANK21 ((read16_handler)STATIC_BANK21)
+#define MRA16_BANK22 ((read16_handler)STATIC_BANK22)
+#define MRA16_BANK23 ((read16_handler)STATIC_BANK23)
+#define MRA16_BANK24 ((read16_handler)STATIC_BANK24)
+#define MRA16_BANK25 ((read16_handler)STATIC_BANK25)
+#define MRA16_BANK26 ((read16_handler)STATIC_BANK26)
+#define MRA16_BANK27 ((read16_handler)STATIC_BANK27)
+#define MRA16_BANK28 ((read16_handler)STATIC_BANK28)
+#define MRA16_BANK29 ((read16_handler)STATIC_BANK29)
+#define MRA16_BANK30 ((read16_handler)STATIC_BANK30)
+#define MRA16_BANK31 ((read16_handler)STATIC_BANK31)
+#define MRA16_BANK32 ((read16_handler)STATIC_BANK32)
+#define MRA16_RAM ((read16_handler)STATIC_RAM)
+#define MRA16_ROM ((read16_handler)STATIC_ROM)
+#define MRA16_NOP ((read16_handler)STATIC_NOP)
+#define MRA16_UNMAP ((read16_handler)STATIC_UNMAP)
+
+/* 16-bit writes */
+#define MWA16_BANK1 ((write16_handler)STATIC_BANK1)
+#define MWA16_BANK2 ((write16_handler)STATIC_BANK2)
+#define MWA16_BANK3 ((write16_handler)STATIC_BANK3)
+#define MWA16_BANK4 ((write16_handler)STATIC_BANK4)
+#define MWA16_BANK5 ((write16_handler)STATIC_BANK5)
+#define MWA16_BANK6 ((write16_handler)STATIC_BANK6)
+#define MWA16_BANK7 ((write16_handler)STATIC_BANK7)
+#define MWA16_BANK8 ((write16_handler)STATIC_BANK8)
+#define MWA16_BANK9 ((write16_handler)STATIC_BANK9)
+#define MWA16_BANK10 ((write16_handler)STATIC_BANK10)
+#define MWA16_BANK11 ((write16_handler)STATIC_BANK11)
+#define MWA16_BANK12 ((write16_handler)STATIC_BANK12)
+#define MWA16_BANK13 ((write16_handler)STATIC_BANK13)
+#define MWA16_BANK14 ((write16_handler)STATIC_BANK14)
+#define MWA16_BANK15 ((write16_handler)STATIC_BANK15)
+#define MWA16_BANK16 ((write16_handler)STATIC_BANK16)
+#define MWA16_BANK17 ((write16_handler)STATIC_BANK17)
+#define MWA16_BANK18 ((write16_handler)STATIC_BANK18)
+#define MWA16_BANK19 ((write16_handler)STATIC_BANK19)
+#define MWA16_BANK20 ((write16_handler)STATIC_BANK20)
+#define MWA16_BANK21 ((write16_handler)STATIC_BANK21)
+#define MWA16_BANK22 ((write16_handler)STATIC_BANK22)
+#define MWA16_BANK23 ((write16_handler)STATIC_BANK23)
+#define MWA16_BANK24 ((write16_handler)STATIC_BANK24)
+#define MWA16_BANK25 ((write16_handler)STATIC_BANK25)
+#define MWA16_BANK26 ((write16_handler)STATIC_BANK26)
+#define MWA16_BANK27 ((write16_handler)STATIC_BANK27)
+#define MWA16_BANK28 ((write16_handler)STATIC_BANK28)
+#define MWA16_BANK29 ((write16_handler)STATIC_BANK29)
+#define MWA16_BANK30 ((write16_handler)STATIC_BANK30)
+#define MWA16_BANK31 ((write16_handler)STATIC_BANK31)
+#define MWA16_BANK32 ((write16_handler)STATIC_BANK32)
+#define MWA16_RAM ((write16_handler)STATIC_RAM)
+#define MWA16_ROM ((write16_handler)STATIC_ROM)
+#define MWA16_NOP ((write16_handler)STATIC_NOP)
+#define MWA16_UNMAP ((write16_handler)STATIC_UNMAP)
+
+/* 32-bit reads */
+#define MRA32_BANK1 ((read32_handler)STATIC_BANK1)
+#define MRA32_BANK2 ((read32_handler)STATIC_BANK2)
+#define MRA32_BANK3 ((read32_handler)STATIC_BANK3)
+#define MRA32_BANK4 ((read32_handler)STATIC_BANK4)
+#define MRA32_BANK5 ((read32_handler)STATIC_BANK5)
+#define MRA32_BANK6 ((read32_handler)STATIC_BANK6)
+#define MRA32_BANK7 ((read32_handler)STATIC_BANK7)
+#define MRA32_BANK8 ((read32_handler)STATIC_BANK8)
+#define MRA32_BANK9 ((read32_handler)STATIC_BANK9)
+#define MRA32_BANK10 ((read32_handler)STATIC_BANK10)
+#define MRA32_BANK11 ((read32_handler)STATIC_BANK11)
+#define MRA32_BANK12 ((read32_handler)STATIC_BANK12)
+#define MRA32_BANK13 ((read32_handler)STATIC_BANK13)
+#define MRA32_BANK14 ((read32_handler)STATIC_BANK14)
+#define MRA32_BANK15 ((read32_handler)STATIC_BANK15)
+#define MRA32_BANK16 ((read32_handler)STATIC_BANK16)
+#define MRA32_BANK17 ((read32_handler)STATIC_BANK17)
+#define MRA32_BANK18 ((read32_handler)STATIC_BANK18)
+#define MRA32_BANK19 ((read32_handler)STATIC_BANK19)
+#define MRA32_BANK20 ((read32_handler)STATIC_BANK20)
+#define MRA32_BANK21 ((read32_handler)STATIC_BANK21)
+#define MRA32_BANK22 ((read32_handler)STATIC_BANK22)
+#define MRA32_BANK23 ((read32_handler)STATIC_BANK23)
+#define MRA32_BANK24 ((read32_handler)STATIC_BANK24)
+#define MRA32_BANK25 ((read32_handler)STATIC_BANK25)
+#define MRA32_BANK26 ((read32_handler)STATIC_BANK26)
+#define MRA32_BANK27 ((read32_handler)STATIC_BANK27)
+#define MRA32_BANK28 ((read32_handler)STATIC_BANK28)
+#define MRA32_BANK29 ((read32_handler)STATIC_BANK29)
+#define MRA32_BANK30 ((read32_handler)STATIC_BANK30)
+#define MRA32_BANK31 ((read32_handler)STATIC_BANK31)
+#define MRA32_BANK32 ((read32_handler)STATIC_BANK32)
+#define MRA32_RAM ((read32_handler)STATIC_RAM)
+#define MRA32_ROM ((read32_handler)STATIC_ROM)
+#define MRA32_NOP ((read32_handler)STATIC_NOP)
+#define MRA32_UNMAP ((read32_handler)STATIC_UNMAP)
+
+/* 32-bit writes */
+#define MWA32_BANK1 ((write32_handler)STATIC_BANK1)
+#define MWA32_BANK2 ((write32_handler)STATIC_BANK2)
+#define MWA32_BANK3 ((write32_handler)STATIC_BANK3)
+#define MWA32_BANK4 ((write32_handler)STATIC_BANK4)
+#define MWA32_BANK5 ((write32_handler)STATIC_BANK5)
+#define MWA32_BANK6 ((write32_handler)STATIC_BANK6)
+#define MWA32_BANK7 ((write32_handler)STATIC_BANK7)
+#define MWA32_BANK8 ((write32_handler)STATIC_BANK8)
+#define MWA32_BANK9 ((write32_handler)STATIC_BANK9)
+#define MWA32_BANK10 ((write32_handler)STATIC_BANK10)
+#define MWA32_BANK11 ((write32_handler)STATIC_BANK11)
+#define MWA32_BANK12 ((write32_handler)STATIC_BANK12)
+#define MWA32_BANK13 ((write32_handler)STATIC_BANK13)
+#define MWA32_BANK14 ((write32_handler)STATIC_BANK14)
+#define MWA32_BANK15 ((write32_handler)STATIC_BANK15)
+#define MWA32_BANK16 ((write32_handler)STATIC_BANK16)
+#define MWA32_BANK17 ((write32_handler)STATIC_BANK17)
+#define MWA32_BANK18 ((write32_handler)STATIC_BANK18)
+#define MWA32_BANK19 ((write32_handler)STATIC_BANK19)
+#define MWA32_BANK20 ((write32_handler)STATIC_BANK20)
+#define MWA32_BANK21 ((write32_handler)STATIC_BANK21)
+#define MWA32_BANK22 ((write32_handler)STATIC_BANK22)
+#define MWA32_BANK23 ((write32_handler)STATIC_BANK23)
+#define MWA32_BANK24 ((write32_handler)STATIC_BANK24)
+#define MWA32_BANK25 ((write32_handler)STATIC_BANK25)
+#define MWA32_BANK26 ((write32_handler)STATIC_BANK26)
+#define MWA32_BANK27 ((write32_handler)STATIC_BANK27)
+#define MWA32_BANK28 ((write32_handler)STATIC_BANK28)
+#define MWA32_BANK29 ((write32_handler)STATIC_BANK29)
+#define MWA32_BANK30 ((write32_handler)STATIC_BANK30)
+#define MWA32_BANK31 ((write32_handler)STATIC_BANK31)
+#define MWA32_BANK32 ((write32_handler)STATIC_BANK32)
+#define MWA32_RAM ((write32_handler)STATIC_RAM)
+#define MWA32_ROM ((write32_handler)STATIC_ROM)
+#define MWA32_NOP ((write32_handler)STATIC_NOP)
+#define MWA32_UNMAP ((write32_handler)STATIC_UNMAP)
+
+/* 64-bit reads */
+#define MRA64_BANK1 ((read64_handler)STATIC_BANK1)
+#define MRA64_BANK2 ((read64_handler)STATIC_BANK2)
+#define MRA64_BANK3 ((read64_handler)STATIC_BANK3)
+#define MRA64_BANK4 ((read64_handler)STATIC_BANK4)
+#define MRA64_BANK5 ((read64_handler)STATIC_BANK5)
+#define MRA64_BANK6 ((read64_handler)STATIC_BANK6)
+#define MRA64_BANK7 ((read64_handler)STATIC_BANK7)
+#define MRA64_BANK8 ((read64_handler)STATIC_BANK8)
+#define MRA64_BANK9 ((read64_handler)STATIC_BANK9)
+#define MRA64_BANK10 ((read64_handler)STATIC_BANK10)
+#define MRA64_BANK11 ((read64_handler)STATIC_BANK11)
+#define MRA64_BANK12 ((read64_handler)STATIC_BANK12)
+#define MRA64_BANK13 ((read64_handler)STATIC_BANK13)
+#define MRA64_BANK14 ((read64_handler)STATIC_BANK14)
+#define MRA64_BANK15 ((read64_handler)STATIC_BANK15)
+#define MRA64_BANK16 ((read64_handler)STATIC_BANK16)
+#define MRA64_BANK17 ((read64_handler)STATIC_BANK17)
+#define MRA64_BANK18 ((read64_handler)STATIC_BANK18)
+#define MRA64_BANK19 ((read64_handler)STATIC_BANK19)
+#define MRA64_BANK20 ((read64_handler)STATIC_BANK20)
+#define MRA64_BANK21 ((read64_handler)STATIC_BANK21)
+#define MRA64_BANK22 ((read64_handler)STATIC_BANK22)
+#define MRA64_BANK23 ((read64_handler)STATIC_BANK23)
+#define MRA64_BANK24 ((read64_handler)STATIC_BANK24)
+#define MRA64_BANK25 ((read64_handler)STATIC_BANK25)
+#define MRA64_BANK26 ((read64_handler)STATIC_BANK26)
+#define MRA64_BANK27 ((read64_handler)STATIC_BANK27)
+#define MRA64_BANK28 ((read64_handler)STATIC_BANK28)
+#define MRA64_BANK29 ((read64_handler)STATIC_BANK29)
+#define MRA64_BANK30 ((read64_handler)STATIC_BANK30)
+#define MRA64_BANK31 ((read64_handler)STATIC_BANK31)
+#define MRA64_BANK32 ((read64_handler)STATIC_BANK32)
+#define MRA64_RAM ((read64_handler)STATIC_RAM)
+#define MRA64_ROM ((read64_handler)STATIC_ROM)
+#define MRA64_NOP ((read64_handler)STATIC_NOP)
+#define MRA64_UNMAP ((read64_handler)STATIC_UNMAP)
+
+/* 64-bit writes */
+#define MWA64_BANK1 ((write64_handler)STATIC_BANK1)
+#define MWA64_BANK2 ((write64_handler)STATIC_BANK2)
+#define MWA64_BANK3 ((write64_handler)STATIC_BANK3)
+#define MWA64_BANK4 ((write64_handler)STATIC_BANK4)
+#define MWA64_BANK5 ((write64_handler)STATIC_BANK5)
+#define MWA64_BANK6 ((write64_handler)STATIC_BANK6)
+#define MWA64_BANK7 ((write64_handler)STATIC_BANK7)
+#define MWA64_BANK8 ((write64_handler)STATIC_BANK8)
+#define MWA64_BANK9 ((write64_handler)STATIC_BANK9)
+#define MWA64_BANK10 ((write64_handler)STATIC_BANK10)
+#define MWA64_BANK11 ((write64_handler)STATIC_BANK11)
+#define MWA64_BANK12 ((write64_handler)STATIC_BANK12)
+#define MWA64_BANK13 ((write64_handler)STATIC_BANK13)
+#define MWA64_BANK14 ((write64_handler)STATIC_BANK14)
+#define MWA64_BANK15 ((write64_handler)STATIC_BANK15)
+#define MWA64_BANK16 ((write64_handler)STATIC_BANK16)
+#define MWA64_BANK17 ((write64_handler)STATIC_BANK17)
+#define MWA64_BANK18 ((write64_handler)STATIC_BANK18)
+#define MWA64_BANK19 ((write64_handler)STATIC_BANK19)
+#define MWA64_BANK20 ((write64_handler)STATIC_BANK20)
+#define MWA64_BANK21 ((write64_handler)STATIC_BANK21)
+#define MWA64_BANK22 ((write64_handler)STATIC_BANK22)
+#define MWA64_BANK23 ((write64_handler)STATIC_BANK23)
+#define MWA64_BANK24 ((write64_handler)STATIC_BANK24)
+#define MWA64_BANK25 ((write64_handler)STATIC_BANK25)
+#define MWA64_BANK26 ((write64_handler)STATIC_BANK26)
+#define MWA64_BANK27 ((write64_handler)STATIC_BANK27)
+#define MWA64_BANK28 ((write64_handler)STATIC_BANK28)
+#define MWA64_BANK29 ((write64_handler)STATIC_BANK29)
+#define MWA64_BANK30 ((write64_handler)STATIC_BANK30)
+#define MWA64_BANK31 ((write64_handler)STATIC_BANK31)
+#define MWA64_BANK32 ((write64_handler)STATIC_BANK32)
+#define MWA64_RAM ((write64_handler)STATIC_RAM)
+#define MWA64_ROM ((write64_handler)STATIC_ROM)
+#define MWA64_NOP ((write64_handler)STATIC_NOP)
+#define MWA64_UNMAP ((write64_handler)STATIC_UNMAP)
+
+
+
+/***************************************************************************
+ ADDRESS SPACE ARRAY TYPE DEFINITIONS
+****************************************************************************
+ Note that the data access handlers are not passed the actual address
+ where the operation takes place, but the offset from the beginning
+ of the block they are assigned to. This makes handling of mirror
+ addresses easier, and makes the handlers a bit more "object oriented".
+ If you handler needs to read/write the main memory area, provide a
+ "base" pointer: it will be initialized by the main engine to point to
+ the beginning of the memory block assigned to the handler. You may
+ also provide a pointer to "size": it will be set to the length of
+ the memory area processed by the handler.
+***************************************************************************/
+
+typedef struct _handler_data handler_data;
+
+/* ----- a union of all the different read handler types ----- */
+typedef union _read_handlers read_handlers;
+union _read_handlers
+{
+ genf * handler;
+ read8_handler handler8;
+ read16_handler handler16;
+ read32_handler handler32;
+ read64_handler handler64;
+};
+
+/* ----- a union of all the different write handler types ----- */
+typedef union _write_handlers write_handlers;
+union _write_handlers
+{
+ genf * handler;
+ write8_handler handler8;
+ write16_handler handler16;
+ write32_handler handler32;
+ write64_handler handler64;
+};
+
+/* ----- a generic address map type ----- */
+typedef struct _address_map address_map;
+struct _address_map
+{
+ UINT32 flags; /* flags and additional info about this entry */
+ offs_t start, end; /* start/end (or mask/match) values */
+ offs_t mirror; /* mirror bits */
+ offs_t mask; /* mask bits */
+ read_handlers read; /* read handler callback */
+ const char * read_name; /* read handler callback name */
+ write_handlers write; /* write handler callback */
+ const char * write_name; /* write handler callback name */
+ void * memory; /* pointer to memory backing this entry */
+ UINT32 share; /* index of a shared memory block */
+ void ** base; /* receives pointer to memory (optional) */
+ size_t * size; /* receives size of area in bytes (optional) */
+ UINT32 region; /* region containing the memory backing this entry */
+ offs_t region_offs; /* offset within the region */
+};
+
+/* ----- structs to contain internal data ----- */
+typedef struct _address_space address_space;
+struct _address_space
+{
+ offs_t addrmask; /* address mask */
+ UINT8 * readlookup; /* read table lookup */
+ UINT8 * writelookup; /* write table lookup */
+ handler_data * readhandlers; /* read handlers */
+ handler_data * writehandlers; /* write handlers */
+ data_accessors * accessors; /* pointers to the data access handlers */
+};
+
+
+
+/***************************************************************************
+ ADDRESS MAP ARRAY CONSTRUCTORS
+***************************************************************************/
+
+void construct_address_map(address_map *map, const machine_config *drv, int cpunum, int spacenum);
+
+/* ----- a typedef for pointers to these functions ----- */
+typedef address_map *(*construct_map_t)(address_map *map);
+
+/* use this to declare external references to a machine driver */
+#define ADDRESS_MAP_EXTERN(_name) \
+address_map *construct_map_##_name(address_map *map) \
+
+/* ----- macros for starting, ending, and setting map flags ----- */
+#define ADDRESS_MAP_START(_name,_space,_bits) \
+address_map *construct_map_##_name(address_map *map) \
+{ \
+ extern read##_bits##_handler port_tag_to_handler##_bits(const char *); \
+ typedef read##_bits##_handler _rh_t; \
+ typedef write##_bits##_handler _wh_t; \
+ _rh_t read; \
+ _wh_t write; \
+ _rh_t (*port_tag_to_handler)(const char *) = port_tag_to_handler##_bits; \
+ UINT##_bits **base; \
+ \
+ (void)read; (void)write; (void)base; \
+ (void)port_tag_to_handler; \
+ map->flags = AM_FLAGS_EXTENDED; \
+ map->start = AMEF_DBITS(_bits) | AMEF_SPACE(_space); \
+
+#define ADDRESS_MAP_FLAGS(_flags) \
+ map++; \
+ map->flags = AM_FLAGS_EXTENDED; \
+ map->start = (_flags); \
+
+#define ADDRESS_MAP_END \
+ map++; \
+ map->flags = AM_FLAGS_END; \
+ return map; \
+} \
+
+/* ----- each map entry begins with one of these ----- */
+#define AM_RANGE(_start,_end) \
+ map++; \
+ map->flags = 0; \
+ map->start = (_start); \
+ map->end = (_end); \
+
+#define AM_SPACE(_match,_mask) \
+ map++; \
+ map->flags = AM_FLAGS_MATCH_MASK; \
+ map->start = (_match); \
+ map->end = (_mask); \
+
+/* ----- these are optional entries after each map entry ----- */
+#define AM_MASK(_mask) \
+ map->mask = (_mask); \
+
+#define AM_MIRROR(_mirror) \
+ map->mirror = (_mirror); \
+
+#define AM_READ(_handler) \
+ map->read.handler = (genf *)(read = _handler); \
+ map->read_name = #_handler; \
+
+#define AM_READ_PORT(_tag) \
+ AM_READ((*port_tag_to_handler)(_tag))
+
+#define AM_WRITE(_handler) \
+ map->write.handler = (genf *)(write = _handler); \
+ map->write_name = #_handler; \
+
+#define AM_REGION(_region, _offs) \
+ map->region = (_region); \
+ map->region_offs = (_offs); \
+
+#define AM_SHARE(_index) \
+ map->share = _index; \
+
+#define AM_BASE(_base) \
+ map->base = (void **)(base = _base); \
+
+#define AM_BASE_MEMBER(_struct, _member) \
+ if (Machine != NULL && Machine->driver_data != NULL) \
+ map->base = (void **)(base = &((_struct *)Machine->driver_data)->_member);\
+
+#define AM_SIZE(_size) \
+ map->size = _size; \
+
+#define AM_SIZE_MEMBER(_struct, _member) \
+ if (Machine != NULL && Machine->driver_data != NULL) \
+ map->size = &((_struct *)Machine->driver_data)->(_member); \
+
+/* ----- common shortcuts ----- */
+#define AM_READWRITE(_read,_write) AM_READ(_read) AM_WRITE(_write)
+#define AM_ROM AM_READ((_rh_t)STATIC_ROM)
+#define AM_RAM AM_READWRITE((_rh_t)STATIC_RAM, (_wh_t)STATIC_RAM)
+#define AM_UNMAP AM_READWRITE((_rh_t)STATIC_UNMAP, (_wh_t)STATIC_UNMAP)
+#define AM_ROMBANK(_bank) AM_READ((_rh_t)(STATIC_BANK1 + (_bank) - 1))
+#define AM_RAMBANK(_bank) AM_READWRITE((_rh_t)(STATIC_BANK1 + (_bank) - 1), (_wh_t)(STATIC_BANK1 + (_bank) - 1))
+#define AM_NOP AM_READWRITE((_rh_t)STATIC_NOP, (_wh_t)STATIC_NOP)
+#define AM_READNOP AM_READ((_rh_t)STATIC_NOP)
+#define AM_WRITENOP AM_WRITE((_wh_t)STATIC_NOP)
+
+
+
+/***************************************************************************
+ ADDRESS MAP ARRAY HELPER MACROS
+***************************************************************************/
+
+/* ----- macros for identifying address map struct markers ----- */
+#define IS_AMENTRY_EXTENDED(ma) (((ma)->flags & AM_FLAGS_EXTENDED) != 0)
+#define IS_AMENTRY_MATCH_MASK(ma) (((ma)->flags & AM_FLAGS_MATCH_MASK) != 0)
+#define IS_AMENTRY_END(ma) (((ma)->flags & AM_FLAGS_END) != 0)
+
+#define AM_EXTENDED_FLAGS(ma) ((ma)->start)
+
+
+
+/***************************************************************************
+ ADDRESS MAP LOOKUP CONSTANTS
+***************************************************************************/
+
+/* ----- address spaces ----- */
+#define ADDRESS_SPACES 3 /* maximum number of address spaces */
+#define ADDRESS_SPACE_PROGRAM 0 /* program address space */
+#define ADDRESS_SPACE_DATA 1 /* data address space */
+#define ADDRESS_SPACE_IO 2 /* I/O address space */
+
+extern const char *address_space_names[ADDRESS_SPACES];
+
+/* ----- address map lookup table definitions ----- */
+#define SUBTABLE_COUNT 64 /* number of slots reserved for subtables */
+#define SUBTABLE_BASE (256-SUBTABLE_COUNT) /* first index of a subtable */
+#define ENTRY_COUNT (SUBTABLE_BASE) /* number of legitimate (non-subtable) entries */
+#define SUBTABLE_ALLOC 8 /* number of subtables to allocate at a time */
+
+/* ----- bit counts ----- */
+#define LEVEL1_BITS 18 /* number of address bits in the level 1 table */
+#define LEVEL2_BITS (32 - LEVEL1_BITS) /* number of address bits in the level 2 table */
+
+/* ----- other address map constants ----- */
+#define MAX_ADDRESS_MAP_SIZE 256 /* maximum entries in an address map */
+#define MAX_MEMORY_BLOCKS 1024 /* maximum memory blocks we can track */
+#define MAX_SHARED_POINTERS 256 /* maximum number of shared pointers in memory maps */
+#define MEMORY_BLOCK_SIZE 65536 /* size of allocated memory blocks */
+
+
+
+/***************************************************************************
+ ADDRESS MAP LOOKUP MACROS
+***************************************************************************/
+
+/* ----- table lookup helpers ----- */
+#define LEVEL1_INDEX(a) ((a) >> LEVEL2_BITS)
+#define LEVEL2_INDEX(e,a) ((1 << LEVEL1_BITS) + (((e) - SUBTABLE_BASE) << LEVEL2_BITS) + ((a) & ((1 << LEVEL2_BITS) - 1)))
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES FOR CORE READ/WRITE ROUTINES
+***************************************************************************/
+
+/* ----- declare program address space handlers ----- */
+UINT8 program_read_byte_8(offs_t address);
+void program_write_byte_8(offs_t address, UINT8 data);
+
+UINT8 program_read_byte_16be(offs_t address);
+UINT16 program_read_word_16be(offs_t address);
+void program_write_byte_16be(offs_t address, UINT8 data);
+void program_write_word_16be(offs_t address, UINT16 data);
+
+UINT8 program_read_byte_16le(offs_t address);
+UINT16 program_read_word_16le(offs_t address);
+void program_write_byte_16le(offs_t address, UINT8 data);
+void program_write_word_16le(offs_t address, UINT16 data);
+
+UINT8 program_read_byte_32be(offs_t address);
+UINT16 program_read_word_32be(offs_t address);
+UINT32 program_read_dword_32be(offs_t address);
+UINT32 program_read_masked_32be(offs_t address, UINT32 mem_mask);
+void program_write_byte_32be(offs_t address, UINT8 data);
+void program_write_word_32be(offs_t address, UINT16 data);
+void program_write_dword_32be(offs_t address, UINT32 data);
+void program_write_masked_32be(offs_t address, UINT32 data, UINT32 mem_mask);
+
+UINT8 program_read_byte_32le(offs_t address);
+UINT16 program_read_word_32le(offs_t address);
+UINT32 program_read_dword_32le(offs_t address);
+UINT32 program_read_masked_32le(offs_t address, UINT32 mem_mask);
+void program_write_byte_32le(offs_t address, UINT8 data);
+void program_write_word_32le(offs_t address, UINT16 data);
+void program_write_dword_32le(offs_t address, UINT32 data);
+void program_write_masked_32le(offs_t address, UINT32 data, UINT32 mem_mask);
+
+UINT8 program_read_byte_64be(offs_t address);
+UINT16 program_read_word_64be(offs_t address);
+UINT32 program_read_dword_64be(offs_t address);
+UINT64 program_read_qword_64be(offs_t address);
+UINT64 program_read_masked_64be(offs_t address, UINT64 mem_mask);
+void program_write_byte_64be(offs_t address, UINT8 data);
+void program_write_word_64be(offs_t address, UINT16 data);
+void program_write_dword_64be(offs_t address, UINT32 data);
+void program_write_qword_64be(offs_t address, UINT64 data);
+void program_write_masked_64be(offs_t address, UINT64 data, UINT64 mem_mask);
+
+UINT8 program_read_byte_64le(offs_t address);
+UINT16 program_read_word_64le(offs_t address);
+UINT32 program_read_dword_64le(offs_t address);
+UINT64 program_read_qword_64le(offs_t address);
+UINT64 program_read_masked_64le(offs_t address, UINT64 mem_mask);
+void program_write_byte_64le(offs_t address, UINT8 data);
+void program_write_word_64le(offs_t address, UINT16 data);
+void program_write_dword_64le(offs_t address, UINT32 data);
+void program_write_qword_64le(offs_t address, UINT64 data);
+void program_write_masked_64le(offs_t address, UINT64 data, UINT64 mem_mask);
+
+/* ----- declare data address space handlers ----- */
+UINT8 data_read_byte_8(offs_t address);
+void data_write_byte_8(offs_t address, UINT8 data);
+
+UINT8 data_read_byte_16be(offs_t address);
+UINT16 data_read_word_16be(offs_t address);
+void data_write_byte_16be(offs_t address, UINT8 data);
+void data_write_word_16be(offs_t address, UINT16 data);
+
+UINT8 data_read_byte_16le(offs_t address);
+UINT16 data_read_word_16le(offs_t address);
+void data_write_byte_16le(offs_t address, UINT8 data);
+void data_write_word_16le(offs_t address, UINT16 data);
+
+UINT8 data_read_byte_32be(offs_t address);
+UINT16 data_read_word_32be(offs_t address);
+UINT32 data_read_dword_32be(offs_t address);
+UINT32 data_read_masked_32be(offs_t address, UINT32 mem_mask);
+void data_write_byte_32be(offs_t address, UINT8 data);
+void data_write_word_32be(offs_t address, UINT16 data);
+void data_write_dword_32be(offs_t address, UINT32 data);
+void data_write_masked_32be(offs_t address, UINT32 data, UINT32 mem_mask);
+
+UINT8 data_read_byte_32le(offs_t address);
+UINT16 data_read_word_32le(offs_t address);
+UINT32 data_read_dword_32le(offs_t address);
+UINT32 data_read_masked_32le(offs_t address, UINT32 mem_mask);
+void data_write_byte_32le(offs_t address, UINT8 data);
+void data_write_word_32le(offs_t address, UINT16 data);
+void data_write_dword_32le(offs_t address, UINT32 data);
+void data_write_masked_32le(offs_t address, UINT32 data, UINT32 mem_mask);
+
+UINT8 data_read_byte_64be(offs_t address);
+UINT16 data_read_word_64be(offs_t address);
+UINT32 data_read_dword_64be(offs_t address);
+UINT64 data_read_qword_64be(offs_t address);
+UINT64 data_read_masked_64be(offs_t address, UINT64 mem_mask);
+void data_write_byte_64be(offs_t address, UINT8 data);
+void data_write_word_64be(offs_t address, UINT16 data);
+void data_write_dword_64be(offs_t address, UINT32 data);
+void data_write_qword_64be(offs_t address, UINT64 data);
+void data_write_masked_64be(offs_t address, UINT64 data, UINT64 mem_mask);
+
+UINT8 data_read_byte_64le(offs_t address);
+UINT16 data_read_word_64le(offs_t address);
+UINT32 data_read_dword_64le(offs_t address);
+UINT64 data_read_qword_64le(offs_t address);
+UINT64 data_read_masked_64le(offs_t address, UINT64 mem_mask);
+void data_write_byte_64le(offs_t address, UINT8 data);
+void data_write_word_64le(offs_t address, UINT16 data);
+void data_write_dword_64le(offs_t address, UINT32 data);
+void data_write_qword_64le(offs_t address, UINT64 data);
+void data_write_masked_64le(offs_t address, UINT64 data, UINT64 mem_mask);
+
+/* ----- declare I/O address space handlers ----- */
+UINT8 io_read_byte_8(offs_t address);
+void io_write_byte_8(offs_t address, UINT8 data);
+
+UINT8 io_read_byte_16be(offs_t address);
+UINT16 io_read_word_16be(offs_t address);
+void io_write_byte_16be(offs_t address, UINT8 data);
+void io_write_word_16be(offs_t address, UINT16 data);
+
+UINT8 io_read_byte_16le(offs_t address);
+UINT16 io_read_word_16le(offs_t address);
+void io_write_byte_16le(offs_t address, UINT8 data);
+void io_write_word_16le(offs_t address, UINT16 data);
+
+UINT8 io_read_byte_32be(offs_t address);
+UINT16 io_read_word_32be(offs_t address);
+UINT32 io_read_dword_32be(offs_t address);
+UINT32 io_read_masked_32be(offs_t address, UINT32 mem_mask);
+void io_write_byte_32be(offs_t address, UINT8 data);
+void io_write_word_32be(offs_t address, UINT16 data);
+void io_write_dword_32be(offs_t address, UINT32 data);
+void io_write_masked_32be(offs_t address, UINT32 data, UINT32 mem_mask);
+
+UINT8 io_read_byte_32le(offs_t address);
+UINT16 io_read_word_32le(offs_t address);
+UINT32 io_read_dword_32le(offs_t address);
+UINT32 io_read_masked_32le(offs_t address, UINT32 mem_mask);
+void io_write_byte_32le(offs_t address, UINT8 data);
+void io_write_word_32le(offs_t address, UINT16 data);
+void io_write_dword_32le(offs_t address, UINT32 data);
+void io_write_masked_32le(offs_t address, UINT32 data, UINT32 mem_mask);
+
+UINT8 io_read_byte_64be(offs_t address);
+UINT16 io_read_word_64be(offs_t address);
+UINT32 io_read_dword_64be(offs_t address);
+UINT64 io_read_qword_64be(offs_t address);
+UINT64 io_read_masked_64be(offs_t address, UINT64 mem_mask);
+void io_write_byte_64be(offs_t address, UINT8 data);
+void io_write_word_64be(offs_t address, UINT16 data);
+void io_write_dword_64be(offs_t address, UINT32 data);
+void io_write_qword_64be(offs_t address, UINT64 data);
+void io_write_masked_64be(offs_t address, UINT64 data, UINT64 mem_mask);
+
+UINT8 io_read_byte_64le(offs_t address);
+UINT16 io_read_word_64le(offs_t address);
+UINT32 io_read_dword_64le(offs_t address);
+UINT64 io_read_qword_64le(offs_t address);
+UINT64 io_read_masked_64le(offs_t address, UINT64 mem_mask);
+void io_write_byte_64le(offs_t address, UINT8 data);
+void io_write_word_64le(offs_t address, UINT16 data);
+void io_write_dword_64le(offs_t address, UINT32 data);
+void io_write_qword_64le(offs_t address, UINT64 data);
+void io_write_masked_64le(offs_t address, UINT64 data, UINT64 mem_mask);
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES FOR CORE MEMORY FUNCTIONS
+***************************************************************************/
+
+/* ----- memory setup function ----- */
+void memory_init(running_machine *machine);
+void memory_set_context(int activecpu);
+
+/* ----- address map functions ----- */
+const address_map *memory_get_map(int cpunum, int spacenum);
+
+/* ----- opcode base control ---- */
+opbase_handler memory_set_opbase_handler(int cpunum, opbase_handler function);
+void memory_set_opbase(offs_t offset);
+
+/* ----- separate opcode/data encryption helper ---- */
+void memory_set_decrypted_region(int cpunum, offs_t start, offs_t end, void *base);
+
+/* ----- return a base pointer to memory ---- */
+void * memory_get_read_ptr(int cpunum, int spacenum, offs_t offset);
+void * memory_get_write_ptr(int cpunum, int spacenum, offs_t offset);
+void * memory_get_op_ptr(int cpunum, offs_t offset, int arg);
+
+/* ----- memory banking ----- */
+void memory_configure_bank(int banknum, int startentry, int numentries, void *base, offs_t stride);
+void memory_configure_bank_decrypted(int banknum, int startentry, int numentries, void *base, offs_t stride);
+void memory_set_bank(int banknum, int entrynum);
+void memory_set_bankptr(int banknum, void *base);
+
+/* ----- debugging ----- */
+void memory_set_debugger_access(int debugger);
+void memory_set_log_unmap(int spacenum, int log);
+int memory_get_log_unmap(int spacenum);
+
+/* ----- dynamic address space mapping ----- */
+void * _memory_install_read_handler (int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name);
+UINT8 * _memory_install_read8_handler (int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_handler handler, const char *handler_name);
+UINT16 * _memory_install_read16_handler (int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_handler handler, const char *handler_name);
+UINT32 * _memory_install_read32_handler (int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read32_handler handler, const char *handler_name);
+UINT64 * _memory_install_read64_handler (int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read64_handler handler, const char *handler_name);
+void * _memory_install_write_handler (int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name);
+UINT8 * _memory_install_write8_handler (int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write8_handler handler, const char *handler_name);
+UINT16 * _memory_install_write16_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write16_handler handler, const char *handler_name);
+UINT32 * _memory_install_write32_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write32_handler handler, const char *handler_name);
+UINT64 * _memory_install_write64_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write64_handler handler, const char *handler_name);
+
+void * _memory_install_read_matchmask_handler (int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name);
+UINT8 * _memory_install_read8_matchmask_handler (int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read8_handler handler, const char *handler_name);
+UINT16 * _memory_install_read16_matchmask_handler (int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read16_handler handler, const char *handler_name);
+UINT32 * _memory_install_read32_matchmask_handler (int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read32_handler handler, const char *handler_name);
+UINT64 * _memory_install_read64_matchmask_handler (int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read64_handler handler, const char *handler_name);
+void * _memory_install_write_matchmask_handler (int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name);
+UINT8 * _memory_install_write8_matchmask_handler (int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write8_handler handler, const char *handler_name);
+UINT16 * _memory_install_write16_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write16_handler handler, const char *handler_name);
+UINT32 * _memory_install_write32_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write32_handler handler, const char *handler_name);
+UINT64 * _memory_install_write64_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write64_handler handler, const char *handler_name);
+
+/* ----- memory debugging ----- */
+void memory_dump(FILE *file);
+const char *memory_get_handler_string(int read0_or_write1, int cpunum, int spacenum, offs_t offset);
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+extern UINT8 opcode_entry; /* current entry for opcode fetching */
+extern UINT8 * opcode_base; /* opcode ROM base */
+extern UINT8 * opcode_arg_base; /* opcode RAM base */
+extern offs_t opcode_mask; /* mask to apply to the opcode address */
+extern offs_t opcode_memory_min; /* opcode memory minimum */
+extern offs_t opcode_memory_max; /* opcode memory maximum */
+extern address_space active_address_space[]; /* address spaces */
+#define construct_map_0 NULL
+
+
+
+/***************************************************************************
+ HELPER MACROS AND INLINES
+***************************************************************************/
+
+/* ----- 16/32-bit memory accessing ----- */
+#define COMBINE_DATA(varptr) (*(varptr) = (*(varptr) & mem_mask) | (data & ~mem_mask))
+
+/* ----- 16-bit memory accessing ----- */
+#define ACCESSING_LSB16 ((mem_mask & 0x00ff) == 0)
+#define ACCESSING_MSB16 ((mem_mask & 0xff00) == 0)
+#define ACCESSING_LSB ACCESSING_LSB16
+#define ACCESSING_MSB ACCESSING_MSB16
+
+/* ----- 32-bit memory accessing ----- */
+#define ACCESSING_LSW32 ((mem_mask & 0x0000ffff) == 0)
+#define ACCESSING_MSW32 ((mem_mask & 0xffff0000) == 0)
+#define ACCESSING_LSB32 ((mem_mask & 0x000000ff) == 0)
+#define ACCESSING_MSB32 ((mem_mask & 0xff000000) == 0)
+
+/* ----- opcode range safety checks ----- */
+#if CPUREADOP_SAFETY_NONE
+#define address_is_unsafe(A) (0)
+#elif CPUREADOP_SAFETY_PARTIAL
+#define address_is_unsafe(A) (UNEXPECTED((A) > opcode_memory_max))
+#elif CPUREADOP_SAFETY_FULL
+#define address_is_unsafe(A) ((UNEXPECTED((A) < opcode_memory_min) || UNEXPECTED((A) > opcode_memory_max)))
+#else
+#error Must set either CPUREADOP_SAFETY_NONE, CPUREADOP_SAFETY_PARTIAL or CPUREADOP_SAFETY_FULL
+#endif
+
+/* ----- dynamic memory installation ----- */
+#define memory_install_read_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_read8_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read8_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_read16_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read16_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_read32_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read32_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_read64_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read64_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+
+#define memory_install_write_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_write8_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write8_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_write16_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write16_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_write32_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write32_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_write64_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write64_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+
+#define memory_install_readwrite_handler(cpu, space, start, end, mask, mirror, rhandler, whandler) \
+ _memory_install_read_handler(cpu, space, start, end, mask, mirror, rhandler, #rhandler); \
+ _memory_install_write_handler(cpu, space, start, end, mask, mirror, whandler, #whandler)
+#define memory_install_readwrite8_handler(cpu, space, start, end, mask, mirror, rhandler, whandler) \
+ _memory_install_read8_handler(cpu, space, start, end, mask, mirror, rhandler, #rhandler); \
+ _memory_install_write8_handler(cpu, space, start, end, mask, mirror, whandler, #whandler)
+#define memory_install_readwrite16_handler(cpu, space, start, end, mask, mirror, rhandler, whandler) \
+ _memory_install_read16_handler(cpu, space, start, end, mask, mirror, rhandler, #rhandler); \
+ _memory_install_write16_handler(cpu, space, start, end, mask, mirror, whandler, #whandler)
+#define memory_install_readwrite32_handler(cpu, space, start, end, mask, mirror, rhandler, whandler) \
+ _memory_install_read32_handler(cpu, space, start, end, mask, mirror, rhandler, #rhandler); \
+ _memory_install_write32_handler(cpu, space, start, end, mask, mirror, whandler, #whandler)
+#define memory_install_readwrite64_handler(cpu, space, start, end, mask, mirror, rhandler, whandler) \
+ _memory_install_read64_handler(cpu, space, start, end, mask, mirror, rhandler, #rhandler); \
+ _memory_install_write64_handler(cpu, space, start, end, mask, mirror, whandler, #whandler)
+
+#define memory_install_read_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_read8_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read8_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_read16_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read16_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_read32_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read32_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_read64_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_read64_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+
+#define memory_install_write_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_write8_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write8_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_write16_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write16_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_write32_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write32_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+#define memory_install_write64_matchmask_handler(cpu, space, start, end, mask, mirror, handler) \
+ _memory_install_write64_matchmask_handler(cpu, space, start, end, mask, mirror, handler, #handler)
+
+/* ----- generic memory access ----- */
+INLINE UINT8 program_read_byte (offs_t offset) { return (*active_address_space[ADDRESS_SPACE_PROGRAM].accessors->read_byte)(offset); }
+INLINE UINT16 program_read_word (offs_t offset) { return (*active_address_space[ADDRESS_SPACE_PROGRAM].accessors->read_word)(offset); }
+INLINE UINT32 program_read_dword(offs_t offset) { return (*active_address_space[ADDRESS_SPACE_PROGRAM].accessors->read_dword)(offset); }
+INLINE UINT64 program_read_qword(offs_t offset) { return (*active_address_space[ADDRESS_SPACE_PROGRAM].accessors->read_qword)(offset); }
+
+INLINE void program_write_byte (offs_t offset, UINT8 data) { (*active_address_space[ADDRESS_SPACE_PROGRAM].accessors->write_byte)(offset, data); }
+INLINE void program_write_word (offs_t offset, UINT16 data) { (*active_address_space[ADDRESS_SPACE_PROGRAM].accessors->write_word)(offset, data); }
+INLINE void program_write_dword(offs_t offset, UINT32 data) { (*active_address_space[ADDRESS_SPACE_PROGRAM].accessors->write_dword)(offset, data); }
+INLINE void program_write_qword(offs_t offset, UINT64 data) { (*active_address_space[ADDRESS_SPACE_PROGRAM].accessors->write_qword)(offset, data); }
+
+INLINE UINT8 data_read_byte (offs_t offset) { return (*active_address_space[ADDRESS_SPACE_DATA].accessors->read_byte)(offset); }
+INLINE UINT16 data_read_word (offs_t offset) { return (*active_address_space[ADDRESS_SPACE_DATA].accessors->read_word)(offset); }
+INLINE UINT32 data_read_dword(offs_t offset) { return (*active_address_space[ADDRESS_SPACE_DATA].accessors->read_dword)(offset); }
+INLINE UINT64 data_read_qword(offs_t offset) { return (*active_address_space[ADDRESS_SPACE_DATA].accessors->read_qword)(offset); }
+
+INLINE void data_write_byte (offs_t offset, UINT8 data) { (*active_address_space[ADDRESS_SPACE_DATA].accessors->write_byte)(offset, data); }
+INLINE void data_write_word (offs_t offset, UINT16 data) { (*active_address_space[ADDRESS_SPACE_DATA].accessors->write_word)(offset, data); }
+INLINE void data_write_dword(offs_t offset, UINT32 data) { (*active_address_space[ADDRESS_SPACE_DATA].accessors->write_dword)(offset, data); }
+INLINE void data_write_qword(offs_t offset, UINT64 data) { (*active_address_space[ADDRESS_SPACE_DATA].accessors->write_qword)(offset, data); }
+
+INLINE UINT8 io_read_byte (offs_t offset) { return (*active_address_space[ADDRESS_SPACE_IO].accessors->read_byte)(offset); }
+INLINE UINT16 io_read_word (offs_t offset) { return (*active_address_space[ADDRESS_SPACE_IO].accessors->read_word)(offset); }
+INLINE UINT32 io_read_dword(offs_t offset) { return (*active_address_space[ADDRESS_SPACE_IO].accessors->read_dword)(offset); }
+INLINE UINT64 io_read_qword(offs_t offset) { return (*active_address_space[ADDRESS_SPACE_IO].accessors->read_qword)(offset); }
+
+INLINE void io_write_byte (offs_t offset, UINT8 data) { (*active_address_space[ADDRESS_SPACE_IO].accessors->write_byte)(offset, data); }
+INLINE void io_write_word (offs_t offset, UINT16 data) { (*active_address_space[ADDRESS_SPACE_IO].accessors->write_word)(offset, data); }
+INLINE void io_write_dword(offs_t offset, UINT32 data) { (*active_address_space[ADDRESS_SPACE_IO].accessors->write_dword)(offset, data); }
+INLINE void io_write_qword(offs_t offset, UINT64 data) { (*active_address_space[ADDRESS_SPACE_IO].accessors->write_qword)(offset, data); }
+
+/* ----- safe opcode and opcode argument reading ----- */
+UINT8 cpu_readop_safe(offs_t offset);
+UINT16 cpu_readop16_safe(offs_t offset);
+UINT32 cpu_readop32_safe(offs_t offset);
+UINT64 cpu_readop64_safe(offs_t offset);
+UINT8 cpu_readop_arg_safe(offs_t offset);
+UINT16 cpu_readop_arg16_safe(offs_t offset);
+UINT32 cpu_readop_arg32_safe(offs_t offset);
+UINT64 cpu_readop_arg64_safe(offs_t offset);
+
+/* ----- unsafe opcode and opcode argument reading ----- */
+#define cpu_opptr_unsafe(A) ((void *)&opcode_base[(A) & opcode_mask])
+#define cpu_readop_unsafe(A) (opcode_base[(A) & opcode_mask])
+#define cpu_readop16_unsafe(A) (*(UINT16 *)&opcode_base[(A) & opcode_mask])
+#define cpu_readop32_unsafe(A) (*(UINT32 *)&opcode_base[(A) & opcode_mask])
+#define cpu_readop64_unsafe(A) (*(UINT64 *)&opcode_base[(A) & opcode_mask])
+#define cpu_readop_arg_unsafe(A) (opcode_arg_base[(A) & opcode_mask])
+#define cpu_readop_arg16_unsafe(A) (*(UINT16 *)&opcode_arg_base[(A) & opcode_mask])
+#define cpu_readop_arg32_unsafe(A) (*(UINT32 *)&opcode_arg_base[(A) & opcode_mask])
+#define cpu_readop_arg64_unsafe(A) (*(UINT64 *)&opcode_arg_base[(A) & opcode_mask])
+
+/* ----- opcode and opcode argument reading ----- */
+INLINE void * cpu_opptr(offs_t A) { if (address_is_unsafe(A)) { memory_set_opbase(A); } return cpu_opptr_unsafe(A); }
+INLINE UINT8 cpu_readop(offs_t A) { if (address_is_unsafe(A)) { memory_set_opbase(A); } return cpu_readop_unsafe(A); }
+INLINE UINT16 cpu_readop16(offs_t A) { if (address_is_unsafe(A)) { memory_set_opbase(A); } return cpu_readop16_unsafe(A); }
+INLINE UINT32 cpu_readop32(offs_t A) { if (address_is_unsafe(A)) { memory_set_opbase(A); } return cpu_readop32_unsafe(A); }
+INLINE UINT64 cpu_readop64(offs_t A) { if (address_is_unsafe(A)) { memory_set_opbase(A); } return cpu_readop64_unsafe(A); }
+INLINE UINT8 cpu_readop_arg(offs_t A) { if (address_is_unsafe(A)) { memory_set_opbase(A); } return cpu_readop_arg_unsafe(A); }
+INLINE UINT16 cpu_readop_arg16(offs_t A) { if (address_is_unsafe(A)) { memory_set_opbase(A); } return cpu_readop_arg16_unsafe(A); }
+INLINE UINT32 cpu_readop_arg32(offs_t A) { if (address_is_unsafe(A)) { memory_set_opbase(A); } return cpu_readop_arg32_unsafe(A); }
+INLINE UINT64 cpu_readop_arg64(offs_t A) { if (address_is_unsafe(A)) { memory_set_opbase(A); } return cpu_readop_arg64_unsafe(A); }
+
+/* ----- bank switching for CPU cores ----- */
+#define change_pc(pc) \
+do { \
+ if (active_address_space[ADDRESS_SPACE_PROGRAM].readlookup[LEVEL1_INDEX((pc) & active_address_space[ADDRESS_SPACE_PROGRAM].addrmask)] != opcode_entry) \
+ memory_set_opbase(pc); \
+} while (0) \
+
+/* ----- forces the next branch to generate a call to the opbase handler ----- */
+#define catch_nextBranch() (opcode_entry = 0xff)
+
+
+#endif /* __MEMORY_H__ */
diff --git a/src/emu/output.c b/src/emu/output.c
new file mode 100644
index 00000000000..9fb63c490a7
--- /dev/null
+++ b/src/emu/output.c
@@ -0,0 +1,406 @@
+/***************************************************************************
+
+ output.c
+
+ General purpose output routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "output.h"
+#include "mame.h"
+#include <zlib.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define HASH_SIZE 53
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _output_notify output_notify;
+struct _output_notify
+{
+ output_notify * next; /* link to next item */
+ output_notifier notifier; /* callback to call */
+ void * param; /* parameter to pass the callback */
+};
+
+
+typedef struct _output_item output_item;
+struct _output_item
+{
+ output_item * next; /* next item in list */
+ const char * name; /* string name of the item */
+ UINT32 hash; /* hash for this item name */
+ UINT32 id; /* unique ID for this item */
+ INT32 value; /* current value */
+ output_notify * notifylist; /* list of notifier callbacks */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static output_item *itemtable[HASH_SIZE];
+static output_notify *global_notifylist;
+static UINT32 uniqueid = 12345;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void output_pause(running_machine *machine, int pause);
+static void output_exit(running_machine *machine);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ copy_string - make a copy of a string
+-------------------------------------------------*/
+
+INLINE const char *copy_string(const char *string)
+{
+ char *newstring = malloc_or_die(strlen(string) + 1);
+ strcpy(newstring, string);
+ return newstring;
+}
+
+
+/*-------------------------------------------------
+ get_hash - return the hash of an output value
+-------------------------------------------------*/
+
+INLINE UINT32 get_hash(const char *string)
+{
+ return crc32(0, (UINT8 *)string, (UINT32)strlen(string));
+}
+
+
+/*-------------------------------------------------
+ find_item - find an item based on a string
+-------------------------------------------------*/
+
+INLINE output_item *find_item(const char *string)
+{
+ UINT32 hash = get_hash(string);
+ output_item *item;
+
+ /* use the hash as a starting point and find an entry */
+ for (item = itemtable[hash % HASH_SIZE]; item != NULL; item = item->next)
+ if (item->hash == hash && strcmp(string, item->name) == 0)
+ return item;
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ create_new_item - create a new item
+-------------------------------------------------*/
+
+INLINE output_item *create_new_item(const char *outname, INT32 value)
+{
+ output_item *item = malloc_or_die(sizeof(*item));
+ UINT32 hash = get_hash(outname);
+
+ /* fill in the data */
+ item->next = itemtable[hash % HASH_SIZE];
+ item->name = copy_string(outname);
+ item->hash = hash;
+ item->id = uniqueid++;
+ item->value = value;
+ item->notifylist = NULL;
+
+ /* add us to the hash table */
+ itemtable[hash % HASH_SIZE] = item;
+ return item;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ output_init - initialize everything
+-------------------------------------------------*/
+
+void output_init(running_machine *machine)
+{
+ /* add pause callback */
+ add_pause_callback(machine, output_pause);
+
+ /* get a callback when done */
+ add_exit_callback(machine, output_exit);
+
+ /* reset the lists */
+ memset(itemtable, 0, sizeof(itemtable));
+ global_notifylist = NULL;
+}
+
+
+/*-------------------------------------------------
+ output_pause - send pause message
+-------------------------------------------------*/
+
+static void output_pause(running_machine *machine, int pause)
+{
+ output_set_value("pause", pause & 1);
+}
+
+
+/*-------------------------------------------------
+ output_exit - cleanup on exit
+-------------------------------------------------*/
+
+static void output_exit(running_machine *machine)
+{
+ output_notify *notify;
+ output_item *item;
+ int hash;
+
+ /* remove all items */
+ for (hash = 0; hash < HASH_SIZE; hash++)
+ for (item = itemtable[hash]; item != NULL; )
+ {
+ output_item *next = item->next;
+
+ /* remove all notifiers */
+ for (notify = item->notifylist; notify != NULL; )
+ {
+ output_notify *next = notify->next;
+ free(notify);
+ notify = next;
+ }
+
+ /* free the name and the item */
+ if (item->name != NULL)
+ free((void *)item->name);
+ free(item);
+ item = next;
+ }
+
+ /* remove all global notifiers */
+ for (notify = global_notifylist; notify != NULL; )
+ {
+ output_notify *next = notify->next;
+ free(notify);
+ notify = next;
+ }
+}
+
+
+/*-------------------------------------------------
+ output_set_value - set the value of an output
+-------------------------------------------------*/
+
+void output_set_value(const char *outname, INT32 value)
+{
+ output_item *item = find_item(outname);
+ output_notify *notify;
+ INT32 oldval;
+
+ /* if no item of that name, create a new one and send the item's state */
+ if (item == NULL)
+ {
+ item = create_new_item(outname, value);
+ oldval = value + 1;
+ }
+
+ else
+ {
+ /* set the new value */
+ oldval = item->value;
+ item->value = value;
+ }
+
+ /* if the value is different, signal the notifier */
+ if (oldval != value)
+ {
+ /* call the local notifiers first */
+ for (notify = item->notifylist; notify != NULL; notify = notify->next)
+ (*notify->notifier)(outname, value, notify->param);
+
+ /* call the global notifiers next */
+ for (notify = global_notifylist; notify != NULL; notify = notify->next)
+ (*notify->notifier)(outname, value, notify->param);
+ }
+}
+
+
+/*-------------------------------------------------
+ output_set_indexed_value - set the value of an
+ indexed output
+-------------------------------------------------*/
+
+void output_set_indexed_value(const char *basename, int index, int value)
+{
+ char buffer[100];
+ char *dest = buffer;
+
+ /* copy the string */
+ while (*basename != 0)
+ *dest++ = *basename++;
+
+ /* append the index */
+ if (index >= 1000) *dest++ = '0' + ((index / 1000) % 10);
+ if (index >= 100) *dest++ = '0' + ((index / 100) % 10);
+ if (index >= 10) *dest++ = '0' + ((index / 10) % 10);
+ *dest++ = '0' + (index % 10);
+ *dest++ = 0;
+
+ /* set the value */
+ output_set_value(buffer, value);
+}
+
+
+/*-------------------------------------------------
+ output_get_value - return the value of an
+ output
+-------------------------------------------------*/
+
+INT32 output_get_value(const char *outname)
+{
+ output_item *item = find_item(outname);
+
+ /* if no item, value is 0 */
+ if (item == NULL)
+ return 0;
+ return item->value;
+}
+
+
+/*-------------------------------------------------
+ output_get_indexed_value - get the value of an
+ indexed output
+-------------------------------------------------*/
+
+INT32 output_get_indexed_value(const char *basename, int index)
+{
+ char buffer[100];
+ char *dest = buffer;
+
+ /* copy the string */
+ while (*basename != 0)
+ *dest++ = *basename++;
+
+ /* append the index */
+ if (index >= 1000) *dest++ = '0' + ((index / 1000) % 10);
+ if (index >= 100) *dest++ = '0' + ((index / 100) % 10);
+ if (index >= 10) *dest++ = '0' + ((index / 10) % 10);
+ *dest++ = '0' + (index % 10);
+ *dest++ = 0;
+
+ /* set the value */
+ return output_get_value(buffer);
+}
+
+
+/*-------------------------------------------------
+ output_set_notifier - sets a notifier callback
+ for a particular output, or for all outputs
+ if NULL is specified
+-------------------------------------------------*/
+
+void output_set_notifier(const char *outname, output_notifier callback, void *param)
+{
+ output_notify **headptr;
+
+ /* if an item is specified, find it */
+ if (outname != NULL)
+ {
+ output_item *item = find_item(outname);
+
+ /* if no item of that name, create a new one */
+ if (item == NULL)
+ item = create_new_item(outname, 0);
+ headptr = &item->notifylist;
+ }
+
+ /* if no item is specified, we add to the global list */
+ else
+ headptr = &global_notifylist;
+
+ /* find the end of the list and add to it */
+ while (*headptr != NULL)
+ headptr = &(*headptr)->next;
+ *headptr = malloc_or_die(sizeof(**headptr));
+
+ /* fill in the new record */
+ (*headptr)->next = NULL;
+ (*headptr)->notifier = callback;
+ (*headptr)->param = param;
+}
+
+
+/*-------------------------------------------------
+ output_notify_all - immediately call the given
+ notifier for all outputs
+-------------------------------------------------*/
+
+void output_notify_all(output_notifier callback, void *param)
+{
+ output_item *item;
+ int hash;
+
+ /* remove all items */
+ for (hash = 0; hash < HASH_SIZE; hash++)
+ for (item = itemtable[hash]; item != NULL; item = item->next)
+ (*callback)(item->name, item->value, param);
+}
+
+
+/*-------------------------------------------------
+ output_name_to_id - returns a unique ID for
+ a given name
+-------------------------------------------------*/
+
+UINT32 output_name_to_id(const char *outname)
+{
+ output_item *item = find_item(outname);
+
+ /* if no item, ID is 0 */
+ if (item == NULL)
+ return 0;
+ return item->id;
+}
+
+
+/*-------------------------------------------------
+ output_id_to_name - returns a name that maps
+ to a given unique ID
+-------------------------------------------------*/
+
+const char *output_id_to_name(UINT32 id)
+{
+ output_item *item;
+ int hash;
+
+ /* remove all items */
+ for (hash = 0; hash < HASH_SIZE; hash++)
+ for (item = itemtable[hash]; item != NULL; item = item->next)
+ if (item->id == id)
+ return item->name;
+
+ /* nothing found, return NULL */
+ return NULL;
+}
diff --git a/src/emu/output.h b/src/emu/output.h
new file mode 100644
index 00000000000..1f198e6795b
--- /dev/null
+++ b/src/emu/output.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+
+ output.h
+
+ General purpose output routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __OUTPUT_H__
+#define __OUTPUT_H__
+
+#include "mamecore.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef void (*output_notifier)(const char *outname, INT32 value, void *param);
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* core initialization */
+void output_init(running_machine *machine);
+
+/* set the value for a given output */
+void output_set_value(const char *outname, INT32 value);
+
+/* set an indexed value for an output (concatenates basename + index) */
+void output_set_indexed_value(const char *basename, int index, int value);
+
+/* return the current value for a given output */
+INT32 output_get_value(const char *outname);
+
+/* return the current value for a given indexed output */
+INT32 output_get_indexed_value(const char *outname, int index);
+
+/* set a notifier on a particular output, or globally if NULL */
+void output_set_notifier(const char *outname, output_notifier callback, void *param);
+
+/* set a notifier on a particular output, or globally if NULL */
+void output_notify_all(output_notifier callback, void *param);
+
+/* map a name to a unique ID */
+UINT32 output_name_to_id(const char *outname);
+
+/* map a unique ID back to a name */
+const char *output_id_to_name(UINT32 id);
+
+
+
+/***************************************************************************
+ INLINES
+***************************************************************************/
+
+INLINE void output_set_led_value(int index, int value)
+{
+ output_set_indexed_value("led", index, value ? 1 : 0);
+}
+
+INLINE void output_set_lamp_value(int index, int value)
+{
+ output_set_indexed_value("lamp", index, value);
+}
+
+INLINE void output_set_digit_value(int index, int value)
+{
+ output_set_indexed_value("digit", index, value);
+}
+
+
+INLINE INT32 output_get_led_value(int index)
+{
+ return output_get_indexed_value("led", index);
+}
+
+INLINE INT32 output_get_lamp_value(int index)
+{
+ return output_get_indexed_value("lamp", index);
+}
+
+INLINE INT32 output_get_digit_value(int index)
+{
+ return output_get_indexed_value("digit", index);
+}
+
+
+#endif /* __OUTPUT_H__ */
diff --git a/src/emu/profiler.c b/src/emu/profiler.c
new file mode 100644
index 00000000000..7c70ee4abc2
--- /dev/null
+++ b/src/emu/profiler.c
@@ -0,0 +1,205 @@
+/***************************************************************************
+
+ profiler.c
+
+ Functions to manage profiling of MAME execution.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "osdepend.h"
+#include "driver.h"
+#include "profiler.h"
+
+
+/* in usrintf.c */
+static int use_profiler;
+
+
+#define MEMORY 6
+
+typedef struct _profile_data profile_data;
+struct _profile_data
+{
+ UINT64 count[MEMORY][PROFILER_TOTAL];
+ unsigned int cpu_context_switches[MEMORY];
+};
+
+static profile_data profile;
+static int memory;
+
+
+static int FILO_type[10];
+static osd_ticks_t FILO_start[10];
+static int FILO_length;
+
+void profiler_start(void)
+{
+ use_profiler = 1;
+ FILO_length = 0;
+}
+
+void profiler_stop(void)
+{
+ use_profiler = 0;
+}
+
+void profiler_mark(int type)
+{
+ osd_ticks_t curr_ticks;
+
+
+ if (!use_profiler)
+ {
+ FILO_length = 0;
+ return;
+ }
+
+ if (type >= PROFILER_CPU1 && type <= PROFILER_CPU8)
+ profile.cpu_context_switches[memory]++;
+
+ curr_ticks = osd_profiling_ticks();
+
+ if (type != PROFILER_END)
+ {
+ if (FILO_length > 0)
+ {
+ if (FILO_length >= 10)
+ {
+logerror("Profiler error: FILO buffer overflow\n");
+ return;
+ }
+
+ /* handle nested calls */
+ profile.count[memory][FILO_type[FILO_length-1]] += curr_ticks - FILO_start[FILO_length-1];
+ }
+ FILO_type[FILO_length] = type;
+ FILO_start[FILO_length] = curr_ticks;
+ FILO_length++;
+ }
+ else
+ {
+ if (FILO_length <= 0)
+ {
+logerror("Profiler error: FILO buffer underflow\n");
+ return;
+ }
+
+ FILO_length--;
+ profile.count[memory][FILO_type[FILO_length]] += curr_ticks - FILO_start[FILO_length];
+ if (FILO_length > 0)
+ {
+ /* handle nested calls */
+ FILO_start[FILO_length-1] = curr_ticks;
+ }
+ }
+}
+
+const char *profiler_get_text(void)
+{
+ int i,j;
+ UINT64 total,normalize;
+ UINT64 computed;
+ static const char *names[PROFILER_TOTAL] =
+ {
+ "CPU 1 ",
+ "CPU 2 ",
+ "CPU 3 ",
+ "CPU 4 ",
+ "CPU 5 ",
+ "CPU 6 ",
+ "CPU 7 ",
+ "CPU 8 ",
+ "Mem rd ",
+ "Mem wr ",
+ "Video ",
+ "drawgfx",
+ "copybmp",
+ "tmdraw ",
+ "tmdrroz",
+ "tmupdat",
+ "Artwork",
+ "Blit ",
+ "Sound ",
+ "Mixer ",
+ "Callbck",
+ "Input ",
+ "Movie ",
+ "Logerr ",
+ "Extra ",
+ "User1 ",
+ "User2 ",
+ "User3 ",
+ "User4 ",
+ "Profilr",
+ "Idle ",
+ };
+ static int showdelay[PROFILER_TOTAL];
+ static char buf[50*40];
+ char *bufptr = buf;
+
+
+ if (!use_profiler) return "";
+
+ profiler_mark(PROFILER_PROFILER);
+
+ computed = 0;
+ i = 0;
+ while (i < PROFILER_PROFILER)
+ {
+ for (j = 0;j < MEMORY;j++)
+ computed += profile.count[j][i];
+ i++;
+ }
+ normalize = computed;
+ while (i < PROFILER_TOTAL)
+ {
+ for (j = 0;j < MEMORY;j++)
+ computed += profile.count[j][i];
+ i++;
+ }
+ total = computed;
+
+ if (total == 0 || normalize == 0) return ""; /* we have been just reset */
+
+ for (i = 0;i < PROFILER_TOTAL;i++)
+ {
+ computed = 0;
+ {
+ for (j = 0;j < MEMORY;j++)
+ computed += profile.count[j][i];
+ }
+ if (computed || showdelay[i])
+ {
+ if (computed) showdelay[i] = ATTOSECONDS_TO_HZ(Machine->screen[0].refresh);
+ showdelay[i]--;
+
+ if (i < PROFILER_PROFILER)
+ bufptr += sprintf(bufptr,"%02d%% %02d%% %s\n",
+ (int)((computed * 100 + total/2) / total),
+ (int)((computed * 100 + normalize/2) / normalize),
+ names[i]);
+ else
+ bufptr += sprintf(bufptr,"%02d%% %s\n",
+ (int)((computed * 100 + total/2) / total),
+ names[i]);
+ }
+ }
+
+ i = 0;
+ for (j = 0;j < MEMORY;j++)
+ i += profile.cpu_context_switches[j];
+ bufptr += sprintf(bufptr,"%4d CPU switches\n",i / MEMORY);
+
+ /* reset the counters */
+ memory = (memory + 1) % MEMORY;
+ profile.cpu_context_switches[memory] = 0;
+ for (i = 0;i < PROFILER_TOTAL;i++)
+ profile.count[memory][i] = 0;
+
+ profiler_mark(PROFILER_END);
+
+ return buf;
+}
diff --git a/src/emu/profiler.h b/src/emu/profiler.h
new file mode 100644
index 00000000000..d461a63e8ef
--- /dev/null
+++ b/src/emu/profiler.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+
+ profiler.h
+
+ Functions to manage profiling of MAME execution.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __PROFILER_H__
+#define __PROFILER_H__
+
+/* profiling */
+enum
+{
+ PROFILER_END = -1,
+ PROFILER_CPU1 = 0,
+ PROFILER_CPU2,
+ PROFILER_CPU3,
+ PROFILER_CPU4,
+ PROFILER_CPU5,
+ PROFILER_CPU6,
+ PROFILER_CPU7,
+ PROFILER_CPU8,
+ PROFILER_MEMREAD,
+ PROFILER_MEMWRITE,
+ PROFILER_VIDEO,
+ PROFILER_DRAWGFX,
+ PROFILER_COPYBITMAP,
+ PROFILER_TILEMAP_DRAW,
+ PROFILER_TILEMAP_DRAW_ROZ,
+ PROFILER_TILEMAP_UPDATE,
+ PROFILER_ARTWORK,
+ PROFILER_BLIT,
+ PROFILER_SOUND,
+ PROFILER_MIXER,
+ PROFILER_TIMER_CALLBACK,
+ PROFILER_INPUT, /* input.c and inptport.c */
+ PROFILER_MOVIE_REC, /* movie recording */
+ PROFILER_LOGERROR, /* logerror */
+ PROFILER_EXTRA, /* everything else */
+
+ /* the USER types are available to driver writers to profile */
+ /* custom sections of the code */
+ PROFILER_USER1,
+ PROFILER_USER2,
+ PROFILER_USER3,
+ PROFILER_USER4,
+
+ PROFILER_PROFILER,
+ PROFILER_IDLE,
+ PROFILER_TOTAL
+};
+
+
+/*
+To start profiling a certain section, e.g. video:
+profiler_mark(PROFILER_VIDEO);
+
+to end profiling the current section:
+profiler_mark(PROFILER_END);
+
+the profiler handles a FILO list so calls may be nested.
+*/
+
+#ifdef MAME_PROFILER
+void profiler_mark(int type);
+
+/* functions called by usrintf.c */
+void profiler_start(void);
+void profiler_stop(void);
+const char *profiler_get_text(void);
+#else
+#define profiler_mark(type)
+
+#define profiler_start()
+#define profiler_stop()
+#define profiler_get_text() ""
+#endif
+
+
+#endif /* __PROFILER_H__ */
diff --git a/src/emu/render.c b/src/emu/render.c
new file mode 100644
index 00000000000..1dce606007c
--- /dev/null
+++ b/src/emu/render.c
@@ -0,0 +1,2948 @@
+/***************************************************************************
+
+ render.c
+
+ Core rendering system.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Windows-specific to-do:
+ * no fallback if we run out of video memory
+
+ Longer-term to do: (once old renderer is gone)
+ * make vector updates asynchronous
+
+****************************************************************************
+
+ Overview of objects:
+
+ render_target -- This represents a final rendering target. It
+ is specified using integer width/height values, can have
+ non-square pixels, and you can specify its rotation. It is
+ what really determines the final rendering details. The OSD
+ layer creates one or more of these to encapsulate the
+ rendering process. Each render_target holds a list of
+ layout_files that it can use for drawing. When rendering, it
+ makes use of both layout_files and render_containers.
+
+ render_container -- Containers are the top of a hierarchy that is
+ not directly related to the objects above. Containers hold
+ high level primitives that are generated at runtime by the
+ video system. They are used currently for each screen and
+ the user interface. These high-level primitives are broken down
+ into low-level primitives at render time.
+
+***************************************************************************/
+
+#include "render.h"
+#include "rendfont.h"
+#include "rendlay.h"
+#include "rendutil.h"
+#include "config.h"
+#include "output.h"
+#include "xmlfile.h"
+#include <math.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_TEXTURE_SCALES 8
+#define TEXTURE_GROUP_SIZE 256
+
+#define NUM_PRIMLISTS 2
+
+#define MAX_CLEAR_EXTENTS 1000
+
+#define INTERNAL_FLAG_CHAR 0x00000001
+
+enum
+{
+ COMPONENT_TYPE_IMAGE = 0,
+ COMPONENT_TYPE_RECT,
+ COMPONENT_TYPE_DISK,
+ COMPONENT_TYPE_MAX
+};
+
+
+enum
+{
+ CONTAINER_ITEM_LINE = 0,
+ CONTAINER_ITEM_QUAD,
+ CONTAINER_ITEM_MAX
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define ISWAP(var1, var2) do { int temp = var1; var1 = var2; var2 = temp; } while (0)
+#define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* typedef struct _render_texture render_texture; -- defined in render.h */
+/* typedef struct _render_target render_target; -- defined in render.h */
+/* typedef struct _render_container render_container; -- defined in render.h */
+typedef struct _object_transform object_transform;
+typedef struct _scaled_texture scaled_texture;
+typedef struct _container_item container_item;
+
+
+/* a render_ref is an abstract reference to an internal object of some sort */
+struct _render_ref
+{
+ render_ref * next; /* link to the next reference */
+ void * refptr; /* reference pointer */
+};
+
+
+/* an object_transform is used to track transformations when building an object list */
+struct _object_transform
+{
+ float xoffs, yoffs; /* offset transforms */
+ float xscale, yscale; /* scale transforms */
+ render_color color; /* color transform */
+ int orientation; /* orientation transform */
+};
+
+
+/* a scaled_texture contains a single scaled entry for a texture */
+struct _scaled_texture
+{
+ mame_bitmap * bitmap; /* final bitmap */
+ UINT32 seqid; /* sequence number */
+};
+
+
+/* a render_texture is used to track transformations when building an object list */
+struct _render_texture
+{
+ render_texture * next; /* next texture (for free list) */
+ render_texture * base; /* pointer to base of texture group */
+ mame_bitmap * bitmap; /* pointer to the original bitmap */
+ rectangle sbounds; /* source bounds within the bitmap */
+ UINT32 palettebase; /* palette base within the system palette */
+ int format; /* format of the texture data */
+ texture_scaler scaler; /* scaling callback */
+ void * param; /* scaling callback parameter */
+ UINT32 curseq; /* current sequence number */
+ scaled_texture scaled[MAX_TEXTURE_SCALES]; /* array of scaled variants of this texture */
+};
+
+
+/* a render_target describes a surface that is being rendered to */
+struct _render_target
+{
+ render_target * next; /* keep a linked list of targets */
+ layout_view * curview; /* current view */
+ layout_file * filelist; /* list of layout files */
+ UINT32 flags; /* creation flags */
+ render_primitive_list primlist[NUM_PRIMLISTS];/* list of primitives */
+ int listindex; /* index of next primlist to use */
+ INT32 width; /* width in pixels */
+ INT32 height; /* height in pixels */
+ render_bounds bounds; /* bounds of the target */
+ float pixel_aspect; /* aspect ratio of individual pixels */
+ float max_refresh; /* maximum refresh rate, 0 or if none */
+ int orientation; /* orientation */
+ int layerconfig; /* layer configuration */
+ layout_view * base_view; /* the view at the time of first frame */
+ int base_orientation; /* the orientation at the time of first frame */
+ int base_layerconfig; /* the layer configuration at the time of first frame */
+ int maxtexwidth; /* maximum width of a texture */
+ int maxtexheight; /* maximum height of a texture */
+};
+
+
+/* a container_item describes a high level primitive that is added to a container */
+struct _container_item
+{
+ container_item * next; /* pointer to the next element in the list */
+ UINT8 type; /* type of element */
+ render_bounds bounds; /* bounds of the element */
+ render_color color; /* RGBA factors */
+ UINT32 flags; /* option flags */
+ UINT32 internal; /* internal flags */
+ float width; /* width of the line (lines only) */
+ render_texture * texture; /* pointer to the source texture (quads only) */
+};
+
+
+/* a render_container holds a list of items and an orientation for the entire collection */
+struct _render_container
+{
+ container_item * itemlist; /* head of the item list */
+ container_item ** nextitem; /* pointer to the next item to add */
+ int orientation; /* orientation of the container */
+ float brightness; /* brightness of the container */
+ float contrast; /* contrast of the container */
+ float gamma; /* gamma of the container */
+ float xscale; /* X scale factor of the container */
+ float yscale; /* Y scale factor of the container */
+ float xoffset; /* X offset of the container */
+ float yoffset; /* Y offset of the container */
+ mame_bitmap * overlaybitmap; /* overlay bitmap */
+ render_texture * overlaytexture; /* overlay texture */
+ palette_client * palclient; /* client to the system palette */
+ rgb_t bcglookup256[0x400];/* lookup table for brightness/contrast/gamma */
+ rgb_t bcglookup32[0x80]; /* lookup table for brightness/contrast/gamma */
+ rgb_t bcglookup[0x10000]; /* full palette lookup with bcg adjustements */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* array of live targets */
+static render_target *targetlist;
+static render_target *ui_target;
+
+/* notifier callbacks */
+static int (*rescale_notify)(running_machine *, int, int);
+
+/* free lists */
+static render_primitive *render_primitive_free_list;
+static container_item *container_item_free_list;
+static render_ref *render_ref_free_list;
+static render_texture *render_texture_free_list;
+
+/* containers for the UI and for screens */
+static render_container *ui_container;
+static render_container *screen_container[MAX_SCREENS];
+static mame_bitmap *screen_overlay;
+
+/* variables for tracking extents to clear */
+static INT32 clear_extents[MAX_CLEAR_EXTENTS];
+static INT32 clear_extent_count;
+
+/* precomputed UV coordinates for various orientations */
+static const render_quad_texuv oriented_texcoords[8] =
+{
+ { { 0,0 }, { 1,0 }, { 0,1 }, { 1,1 } }, /* 0 */
+ { { 1,0 }, { 0,0 }, { 1,1 }, { 0,1 } }, /* ORIENTATION_FLIP_X */
+ { { 0,1 }, { 1,1 }, { 0,0 }, { 1,0 } }, /* ORIENTATION_FLIP_Y */
+ { { 1,1 }, { 0,1 }, { 1,0 }, { 0,0 } }, /* ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y */
+ { { 0,0 }, { 0,1 }, { 1,0 }, { 1,1 } }, /* ORIENTATION_SWAP_XY */
+ { { 0,1 }, { 0,0 }, { 1,1 }, { 1,0 } }, /* ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X */
+ { { 1,0 }, { 1,1 }, { 0,0 }, { 0,1 } }, /* ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y */
+ { { 1,1 }, { 1,0 }, { 0,1 }, { 0,0 } } /* ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* core system */
+static void render_exit(running_machine *machine);
+static void render_load(int config_type, xml_data_node *parentnode);
+static void render_save(int config_type, xml_data_node *parentnode);
+
+/* render targets */
+static void release_render_list(render_primitive_list *list);
+static int load_layout_files(render_target *target, const char *layoutfile, int singlefile);
+static void add_container_primitives(render_target *target, render_primitive_list *list, const object_transform *xform, render_container *container, int blendmode);
+static void add_element_primitives(render_target *target, render_primitive_list *list, const object_transform *xform, const layout_element *element, int state, int blendmode);
+static void add_clear_and_optimize_primitive_list(render_target *target, render_primitive_list *list);
+
+/* render references */
+static void invalidate_all_render_ref(void *refptr);
+
+/* render textures */
+static int render_texture_get_scaled(render_texture *texture, UINT32 dwidth, UINT32 dheight, render_texinfo *texinfo, render_ref **reflist);
+
+/* render containers */
+static render_container *render_container_alloc(void);
+static void render_container_free(render_container *container);
+static container_item *render_container_item_add_generic(render_container *container, UINT8 type, float x0, float y0, float x1, float y1, rgb_t argb);
+static void render_container_overlay_scale(mame_bitmap *dest, const mame_bitmap *source, const rectangle *sbounds, void *param);
+static void render_container_recompute_lookups(render_container *container);
+static void render_container_update_palette(render_container *container);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ apply_orientation - apply orientation to a
+ set of bounds
+-------------------------------------------------*/
+
+INLINE void apply_orientation(render_bounds *bounds, int orientation)
+{
+ /* swap first */
+ if (orientation & ORIENTATION_SWAP_XY)
+ {
+ FSWAP(bounds->x0, bounds->y0);
+ FSWAP(bounds->x1, bounds->y1);
+ }
+
+ /* apply X flip */
+ if (orientation & ORIENTATION_FLIP_X)
+ {
+ bounds->x0 = 1.0f - bounds->x0;
+ bounds->x1 = 1.0f - bounds->x1;
+ }
+
+ /* apply Y flip */
+ if (orientation & ORIENTATION_FLIP_Y)
+ {
+ bounds->y0 = 1.0f - bounds->y0;
+ bounds->y1 = 1.0f - bounds->y1;
+ }
+}
+
+
+/*-------------------------------------------------
+ normalize_bounds - normalize bounds so that
+ x0/y0 are less than x1/y1
+-------------------------------------------------*/
+
+INLINE void normalize_bounds(render_bounds *bounds)
+{
+ if (bounds->x0 > bounds->x1)
+ FSWAP(bounds->x0, bounds->x1);
+ if (bounds->y0 > bounds->y1)
+ FSWAP(bounds->y0, bounds->y1);
+}
+
+
+/*-------------------------------------------------
+ alloc_container_item - allocate a new
+ container item object
+--------------------------------------------------*/
+
+INLINE container_item *alloc_container_item(void)
+{
+ container_item *result = container_item_free_list;
+
+ /* allocate from the free list if we can; otherwise, malloc a new item */
+ if (result != NULL)
+ container_item_free_list = result->next;
+ else
+ result = malloc_or_die(sizeof(*result));
+
+ memset(result, 0, sizeof(*result));
+ return result;
+}
+
+
+/*-------------------------------------------------
+ container_item_free - free a previously
+ allocated render element object
+-------------------------------------------------*/
+
+INLINE void free_container_item(container_item *item)
+{
+ item->next = container_item_free_list;
+ container_item_free_list = item;
+}
+
+
+/*-------------------------------------------------
+ alloc_render_primitive - allocate a new empty
+ element object
+-------------------------------------------------*/
+
+INLINE render_primitive *alloc_render_primitive(int type)
+{
+ render_primitive *result = render_primitive_free_list;
+
+ /* allocate from the free list if we can; otherwise, malloc a new item */
+ if (result != NULL)
+ render_primitive_free_list = result->next;
+ else
+ result = malloc_or_die(sizeof(*result));
+
+ /* clear to 0 */
+ memset(result, 0, sizeof(*result));
+ result->type = type;
+ return result;
+}
+
+
+/*-------------------------------------------------
+ append_render_primitive - append a primitive
+ to the end of the list
+-------------------------------------------------*/
+
+INLINE void append_render_primitive(render_primitive_list *list, render_primitive *prim)
+{
+ *list->nextptr = prim;
+ list->nextptr = &prim->next;
+}
+
+
+/*-------------------------------------------------
+ free_render_primitive - free a previously
+ allocated render element object
+-------------------------------------------------*/
+
+INLINE void free_render_primitive(render_primitive *element)
+{
+ element->next = render_primitive_free_list;
+ render_primitive_free_list = element;
+}
+
+
+/*-------------------------------------------------
+ add_render_ref - add a new reference
+-------------------------------------------------*/
+
+INLINE void add_render_ref(render_ref **list, void *refptr)
+{
+ render_ref *ref;
+
+ /* skip if we already have one */
+ for (ref = *list; ref != NULL; ref = ref->next)
+ if (ref->refptr == refptr)
+ return;
+
+ /* allocate from the free list if we can; otherwise, malloc a new item */
+ ref = render_ref_free_list;
+ if (ref != NULL)
+ render_ref_free_list = ref->next;
+ else
+ ref = malloc_or_die(sizeof(*ref));
+
+ /* set the refptr and link us into the list */
+ ref->refptr = refptr;
+ ref->next = *list;
+ *list = ref;
+}
+
+
+/*-------------------------------------------------
+ has_render_ref - find a refptr in a reference
+ list
+-------------------------------------------------*/
+
+INLINE int has_render_ref(render_ref *list, void *refptr)
+{
+ render_ref *ref;
+
+ /* skip if we already have one */
+ for (ref = list; ref != NULL; ref = ref->next)
+ if (ref->refptr == refptr)
+ return TRUE;
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ free_render_ref - free a previously
+ allocated render reference
+-------------------------------------------------*/
+
+INLINE void free_render_ref(render_ref *ref)
+{
+ ref->next = render_ref_free_list;
+ render_ref_free_list = ref;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ render_init - allocate base structures for
+ the rendering system
+-------------------------------------------------*/
+
+void render_init(running_machine *machine)
+{
+ int scrnum;
+
+ /* make sure we clean up after ourselves */
+ add_exit_callback(machine, render_exit);
+
+ /* set up the list of render targets */
+ targetlist = NULL;
+
+ /* zap the free lists */
+ render_primitive_free_list = NULL;
+ container_item_free_list = NULL;
+
+ /* zap more variables */
+ ui_target = NULL;
+ memset(screen_container, 0, sizeof(screen_container));
+
+ /* create a UI container */
+ ui_container = render_container_alloc();
+
+ /* create a container for each screen and determine its orientation */
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ if (Machine->drv->screen[scrnum].tag != NULL)
+ {
+ screen_container[scrnum] = render_container_alloc();
+ render_container_set_orientation(screen_container[scrnum], Machine->gamedrv->flags & ORIENTATION_MASK);
+ render_container_set_brightness(screen_container[scrnum], options_get_float(mame_options(), OPTION_BRIGHTNESS));
+ render_container_set_contrast(screen_container[scrnum], options_get_float(mame_options(), OPTION_CONTRAST));
+ render_container_set_gamma(screen_container[scrnum], options_get_float(mame_options(), OPTION_GAMMA));
+ }
+
+ /* register callbacks */
+ config_register("video", render_load, render_save);
+}
+
+
+/*-------------------------------------------------
+ render_exit - free all rendering data
+-------------------------------------------------*/
+
+static void render_exit(running_machine *machine)
+{
+ render_texture **texture_ptr;
+ int screen;
+
+ /* free the UI container */
+ if (ui_container != NULL)
+ render_container_free(ui_container);
+
+ /* free the screen container */
+ for (screen = 0; screen < MAX_SCREENS; screen++)
+ if (screen_container[screen] != NULL)
+ render_container_free(screen_container[screen]);
+
+ /* remove all non-head entries from the texture free list */
+ for (texture_ptr = &render_texture_free_list; *texture_ptr != NULL; texture_ptr = &(*texture_ptr)->next)
+ while (*texture_ptr != NULL && (*texture_ptr)->base != *texture_ptr)
+ *texture_ptr = (*texture_ptr)->next;
+
+ /* free the texture groups */
+ while (render_texture_free_list != NULL)
+ {
+ render_texture *temp = render_texture_free_list;
+ render_texture_free_list = temp->next;
+ free(temp);
+ }
+
+ /* free the render primitives */
+ while (render_primitive_free_list != NULL)
+ {
+ render_primitive *temp = render_primitive_free_list;
+ render_primitive_free_list = temp->next;
+ free(temp);
+ }
+
+ /* free the render refs */
+ while (render_ref_free_list != NULL)
+ {
+ render_ref *temp = render_ref_free_list;
+ render_ref_free_list = temp->next;
+ free(temp);
+ }
+
+ /* free the container items */
+ while (container_item_free_list != NULL)
+ {
+ container_item *temp = container_item_free_list;
+ container_item_free_list = temp->next;
+ free(temp);
+ }
+
+ /* free the targets */
+ while (targetlist != NULL)
+ render_target_free(targetlist);
+
+ /* free the screen overlay */
+ if (screen_overlay != NULL)
+ bitmap_free(screen_overlay);
+ screen_overlay = NULL;
+}
+
+
+/*-------------------------------------------------
+ render_load - read and apply data from the
+ configuration file
+-------------------------------------------------*/
+
+static void render_load(int config_type, xml_data_node *parentnode)
+{
+ xml_data_node *targetnode;
+ xml_data_node *screennode;
+ xml_data_node *uinode;
+ int tmpint;
+
+ /* we only care about game files */
+ if (config_type != CONFIG_TYPE_GAME)
+ return;
+
+ /* might not have any data */
+ if (parentnode == NULL)
+ return;
+
+ /* check the UI target */
+ uinode = xml_get_sibling(parentnode->child, "interface");
+ if (uinode != NULL)
+ {
+ render_target *target = render_target_get_indexed(xml_get_attribute_int(uinode, "target", 0));
+ if (target != NULL)
+ render_set_ui_target(target);
+ }
+
+ /* iterate over target nodes */
+ for (targetnode = xml_get_sibling(parentnode->child, "target"); targetnode; targetnode = xml_get_sibling(targetnode->next, "target"))
+ {
+ render_target *target = render_target_get_indexed(xml_get_attribute_int(targetnode, "index", -1));
+ if (target != NULL)
+ {
+ const char *viewname = xml_get_attribute_string(targetnode, "view", NULL);
+ int viewnum;
+
+ /* find the view */
+ if (viewname != NULL)
+ for (viewnum = 0; viewnum < 1000; viewnum++)
+ {
+ const char *testname = render_target_get_view_name(target, viewnum);
+ if (testname == NULL)
+ break;
+ if (!strcmp(viewname, testname))
+ {
+ render_target_set_view(target, viewnum);
+ break;
+ }
+ }
+
+ /* modify the artwork config */
+ tmpint = xml_get_attribute_int(targetnode, "backdrops", -1);
+ if (tmpint == 0)
+ render_target_set_layer_config(target, target->layerconfig & ~LAYER_CONFIG_ENABLE_BACKDROP);
+ else if (tmpint == 1)
+ render_target_set_layer_config(target, target->layerconfig | LAYER_CONFIG_ENABLE_BACKDROP);
+
+ tmpint = xml_get_attribute_int(targetnode, "overlays", -1);
+ if (tmpint == 0)
+ render_target_set_layer_config(target, target->layerconfig & ~LAYER_CONFIG_ENABLE_OVERLAY);
+ else if (tmpint == 1)
+ render_target_set_layer_config(target, target->layerconfig | LAYER_CONFIG_ENABLE_OVERLAY);
+
+ tmpint = xml_get_attribute_int(targetnode, "bezels", -1);
+ if (tmpint == 0)
+ render_target_set_layer_config(target, target->layerconfig & ~LAYER_CONFIG_ENABLE_BEZEL);
+ else if (tmpint == 1)
+ render_target_set_layer_config(target, target->layerconfig | LAYER_CONFIG_ENABLE_BEZEL);
+
+ tmpint = xml_get_attribute_int(targetnode, "zoom", -1);
+ if (tmpint == 0)
+ render_target_set_layer_config(target, target->layerconfig & ~LAYER_CONFIG_ZOOM_TO_SCREEN);
+ else if (tmpint == 1)
+ render_target_set_layer_config(target, target->layerconfig | LAYER_CONFIG_ZOOM_TO_SCREEN);
+
+ /* apply orientation */
+ tmpint = xml_get_attribute_int(targetnode, "rotate", -1);
+ if (tmpint != -1)
+ {
+ if (tmpint == 90)
+ tmpint = ROT90;
+ else if (tmpint == 180)
+ tmpint = ROT180;
+ else if (tmpint == 270)
+ tmpint = ROT270;
+ else
+ tmpint = ROT0;
+ render_target_set_orientation(target, orientation_add(tmpint, target->orientation));
+
+ /* apply the opposite orientation to the UI */
+ if (target == render_get_ui_target())
+ render_container_set_orientation(ui_container, orientation_add(orientation_reverse(tmpint), ui_container->orientation));
+ }
+ }
+ }
+
+ /* iterate over screen nodes */
+ for (screennode = xml_get_sibling(parentnode->child, "screen"); screennode; screennode = xml_get_sibling(screennode->next, "screen"))
+ {
+ int index = xml_get_attribute_int(screennode, "index", -1);
+ if (index >= 0 && index < MAX_SCREENS && screen_container[index] != NULL)
+ {
+ render_container *container = screen_container[index];
+
+ /* fetch color controls */
+ render_container_set_brightness(container, xml_get_attribute_float(screennode, "brightness", container->brightness));
+ render_container_set_contrast(container, xml_get_attribute_float(screennode, "contrast", container->contrast));
+ render_container_set_gamma(container, xml_get_attribute_float(screennode, "gamma", container->gamma));
+
+ /* fetch positioning controls */
+ render_container_set_xoffset(container, xml_get_attribute_float(screennode, "hoffset", container->xoffset));
+ render_container_set_xscale(container, xml_get_attribute_float(screennode, "hstretch", container->xscale));
+ render_container_set_yoffset(container, xml_get_attribute_float(screennode, "voffset", container->yoffset));
+ render_container_set_yscale(container, xml_get_attribute_float(screennode, "vstretch", container->yscale));
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ render_save - save data to the configuration
+ file
+-------------------------------------------------*/
+
+static void render_save(int config_type, xml_data_node *parentnode)
+{
+ render_target *target;
+ int targetnum = 0;
+ int scrnum;
+
+ /* we only care about game files */
+ if (config_type != CONFIG_TYPE_GAME)
+ return;
+
+ /* write out the interface target */
+ target = render_get_ui_target();
+ if (target != render_target_get_indexed(0))
+ {
+ xml_data_node *uinode;
+
+ /* find the target index */
+ for (targetnum = 0; ; targetnum++)
+ if (render_target_get_indexed(targetnum) == target)
+ break;
+
+ /* create a node for it */
+ uinode = xml_add_child(parentnode, "interface", NULL);
+ if (uinode != NULL)
+ xml_set_attribute_int(uinode, "target", targetnum);
+ }
+
+ /* iterate over targets */
+ for (targetnum = 0; targetnum < 1000; targetnum++)
+ {
+ xml_data_node *targetnode;
+
+ /* get this target and break when we fail */
+ target = render_target_get_indexed(targetnum);
+ if (target == NULL)
+ break;
+
+ /* create a node */
+ targetnode = xml_add_child(parentnode, "target", NULL);
+ if (targetnode != NULL)
+ {
+ int changed = FALSE;
+
+ /* output the basics */
+ xml_set_attribute_int(targetnode, "index", targetnum);
+
+ /* output the view */
+ if (target->curview != target->base_view)
+ {
+ xml_set_attribute(targetnode, "view", target->curview->name);
+ changed = TRUE;
+ }
+
+ /* output the layer config */
+ if (target->layerconfig != target->base_layerconfig)
+ {
+ xml_set_attribute_int(targetnode, "backdrops", (target->layerconfig & LAYER_CONFIG_ENABLE_BACKDROP) != 0);
+ xml_set_attribute_int(targetnode, "overlays", (target->layerconfig & LAYER_CONFIG_ENABLE_OVERLAY) != 0);
+ xml_set_attribute_int(targetnode, "bezels", (target->layerconfig & LAYER_CONFIG_ENABLE_BEZEL) != 0);
+ xml_set_attribute_int(targetnode, "zoom", (target->layerconfig & LAYER_CONFIG_ZOOM_TO_SCREEN) != 0);
+ changed = TRUE;
+ }
+
+ /* output rotation */
+ if (target->orientation != target->base_orientation)
+ {
+ int rotate = 0;
+ if (orientation_add(ROT90, target->base_orientation) == target->orientation)
+ rotate = 90;
+ else if (orientation_add(ROT180, target->base_orientation) == target->orientation)
+ rotate = 180;
+ else if (orientation_add(ROT270, target->base_orientation) == target->orientation)
+ rotate = 270;
+ assert(rotate != 0);
+ xml_set_attribute_int(targetnode, "rotate", rotate);
+ changed = TRUE;
+ }
+
+ /* if nothing changed, kill the node */
+ if (!changed)
+ xml_delete_node(targetnode);
+ }
+ }
+
+ /* iterate over screen containers */
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ {
+ render_container *container = screen_container[scrnum];
+ if (container != NULL)
+ {
+ xml_data_node *screennode;
+
+ /* create a node */
+ screennode = xml_add_child(parentnode, "screen", NULL);
+ if (screennode != NULL)
+ {
+ int changed = FALSE;
+
+ /* output the basics */
+ xml_set_attribute_int(screennode, "index", scrnum);
+
+ /* output the color controls */
+ if (container->brightness != options_get_float(mame_options(), OPTION_BRIGHTNESS))
+ {
+ xml_set_attribute_float(screennode, "brightness", container->brightness);
+ changed = TRUE;
+ }
+ if (container->contrast != options_get_float(mame_options(), OPTION_CONTRAST))
+ {
+ xml_set_attribute_float(screennode, "contrast", container->contrast);
+ changed = TRUE;
+ }
+ if (container->gamma != options_get_float(mame_options(), OPTION_GAMMA))
+ {
+ xml_set_attribute_float(screennode, "gamma", container->gamma);
+ changed = TRUE;
+ }
+
+ /* output the positioning controls */
+ if (container->xoffset != 0.0f)
+ {
+ xml_set_attribute_float(screennode, "hoffset", container->xoffset);
+ changed = TRUE;
+ }
+ if (container->xscale != 1.0f)
+ {
+ xml_set_attribute_float(screennode, "hstretch", container->xscale);
+ changed = TRUE;
+ }
+ if (container->yoffset != 0.0f)
+ {
+ xml_set_attribute_float(screennode, "voffset", container->yoffset);
+ changed = TRUE;
+ }
+ if (container->yscale != 1.0f)
+ {
+ xml_set_attribute_float(screennode, "vstretch", container->yscale);
+ changed = TRUE;
+ }
+
+ /* if nothing changed, kill the node */
+ if (!changed)
+ xml_delete_node(screennode);
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ render_set_rescale_notify - set a notifier
+ that we call before doing long scaling
+ operations
+-------------------------------------------------*/
+
+void render_set_rescale_notify(running_machine *machine, int (*notifier)(running_machine *, int, int))
+{
+ rescale_notify = notifier;
+}
+
+
+/*-------------------------------------------------
+ render_get_live_screens_mask - return a
+ bitmask indicating the live screens
+-------------------------------------------------*/
+
+UINT32 render_get_live_screens_mask(void)
+{
+ render_target *target;
+ UINT32 bitmask = 0;
+
+ /* iterate over all live targets and or together their screen masks */
+ for (target = targetlist; target != NULL; target = target->next)
+ bitmask |= target->curview->screens;
+
+ return bitmask;
+}
+
+
+/*-------------------------------------------------
+ render_get_max_update_rate - return the
+ smallest maximum update rate across all targets
+-------------------------------------------------*/
+
+float render_get_max_update_rate(void)
+{
+ render_target *target;
+ float minimum = 0;
+
+ /* iterate over all live targets and or together their screen masks */
+ for (target = targetlist; target != NULL; target = target->next)
+ if (target->max_refresh != 0)
+ {
+ if (minimum == 0)
+ minimum = target->max_refresh;
+ else
+ minimum = MIN(target->max_refresh, minimum);
+ }
+
+ return minimum;
+}
+
+
+/*-------------------------------------------------
+ render_set_ui_target - select the UI target
+-------------------------------------------------*/
+
+void render_set_ui_target(render_target *target)
+{
+ assert(target != NULL);
+ ui_target = target;
+}
+
+
+/*-------------------------------------------------
+ render_get_ui_target - return the UI target
+-------------------------------------------------*/
+
+render_target *render_get_ui_target(void)
+{
+ assert(ui_target != NULL);
+ return ui_target;
+}
+
+
+/*-------------------------------------------------
+ render_get_ui_aspect - return the aspect
+ ratio for UI fonts
+-------------------------------------------------*/
+
+float render_get_ui_aspect(void)
+{
+ render_target *target = render_get_ui_target();
+ if (target != NULL)
+ {
+ int orient = orientation_add(target->orientation, ui_container->orientation);
+ float aspect;
+
+ /* based on the orientation of the target, compute height/width or width/height */
+ if (!(orient & ORIENTATION_SWAP_XY))
+ aspect = (float)target->height / (float)target->width;
+ else
+ aspect = (float)target->width / (float)target->height;
+
+ /* if we have a valid pixel aspect, apply that and return */
+ if (target->pixel_aspect != 0.0f)
+ return aspect / target->pixel_aspect;
+
+ /* if not, clamp for extreme proportions */
+ if (aspect < 0.66f)
+ aspect = 0.66f;
+ if (aspect > 1.5f)
+ aspect = 1.5f;
+ return aspect;
+ }
+
+ return 1.0f;
+}
+
+
+
+/***************************************************************************
+ RENDER TARGETS
+***************************************************************************/
+
+/*-------------------------------------------------
+ render_target_alloc - allocate a new render
+ target
+-------------------------------------------------*/
+
+render_target *render_target_alloc(const char *layoutfile, UINT32 flags)
+{
+ render_target *target;
+ render_target **nextptr;
+ int listnum;
+
+ /* allocate memory for the target */
+ target = malloc_or_die(sizeof(*target));
+ memset(target, 0, sizeof(*target));
+
+ /* add it to the end of the list */
+ for (nextptr = &targetlist; *nextptr != NULL; nextptr = &(*nextptr)->next) ;
+ *nextptr = target;
+
+ /* fill in the basics with reasonable defaults */
+ target->flags = flags;
+ target->width = 640;
+ target->height = 480;
+ target->pixel_aspect = 0.0f;
+ target->orientation = ROT0;
+ target->layerconfig = LAYER_CONFIG_DEFAULT;
+ target->maxtexwidth = 65536;
+ target->maxtexheight = 65536;
+
+ /* determine the base layer configuration based on options */
+ target->base_layerconfig = LAYER_CONFIG_DEFAULT;
+ if (!options_get_bool(mame_options(), OPTION_USE_BACKDROPS)) target->base_layerconfig &= ~LAYER_CONFIG_ENABLE_BACKDROP;
+ if (!options_get_bool(mame_options(), OPTION_USE_OVERLAYS)) target->base_layerconfig &= ~LAYER_CONFIG_ENABLE_OVERLAY;
+ if (!options_get_bool(mame_options(), OPTION_USE_BEZELS)) target->base_layerconfig &= ~LAYER_CONFIG_ENABLE_BEZEL;
+ if (options_get_bool(mame_options(), OPTION_ARTWORK_CROP)) target->base_layerconfig |= LAYER_CONFIG_ZOOM_TO_SCREEN;
+
+ /* determine the base orientation based on options */
+ target->orientation = ROT0;
+ if (!options_get_bool(mame_options(), OPTION_ROTATE))
+ target->base_orientation = orientation_reverse(Machine->gamedrv->flags & ORIENTATION_MASK);
+
+ /* rotate left/right */
+ if (options_get_bool(mame_options(), OPTION_ROR) || (options_get_bool(mame_options(), OPTION_AUTOROR) && (Machine->gamedrv->flags & ORIENTATION_SWAP_XY)))
+ target->base_orientation = orientation_add(ROT90, target->base_orientation);
+ if (options_get_bool(mame_options(), OPTION_ROL) || (options_get_bool(mame_options(), OPTION_AUTOROL) && (Machine->gamedrv->flags & ORIENTATION_SWAP_XY)))
+ target->base_orientation = orientation_add(ROT270, target->base_orientation);
+
+ /* flip X/Y */
+ if (options_get_bool(mame_options(), OPTION_FLIPX))
+ target->base_orientation ^= ORIENTATION_FLIP_X;
+ if (options_get_bool(mame_options(), OPTION_FLIPY))
+ target->base_orientation ^= ORIENTATION_FLIP_Y;
+
+ /* set the orientation and layerconfig equal to the base */
+ target->orientation = target->base_orientation;
+ target->layerconfig = target->base_layerconfig;
+
+ /* allocate a lock for the primitive list */
+ for (listnum = 0; listnum < NUM_PRIMLISTS; listnum++)
+ target->primlist[listnum].lock = osd_lock_alloc();
+
+ /* load the layout files */
+ if (load_layout_files(target, layoutfile, flags & RENDER_CREATE_SINGLE_FILE))
+ {
+ render_target_free(target);
+ return NULL;
+ }
+
+ /* set the current view to the first one */
+ render_target_set_view(target, 0);
+
+ /* make us the UI target if there is none */
+ if (ui_target == NULL && !(flags & RENDER_CREATE_HIDDEN))
+ render_set_ui_target(target);
+ return target;
+}
+
+
+/*-------------------------------------------------
+ render_target_free - free memory for a render
+ target
+-------------------------------------------------*/
+
+void render_target_free(render_target *target)
+{
+ render_target **curr;
+ int listnum;
+
+ /* remove us from the list */
+ for (curr = &targetlist; *curr != target; curr = &(*curr)->next) ;
+ *curr = target->next;
+
+ /* free any primitives */
+ for (listnum = 0; listnum < NUM_PRIMLISTS; listnum++)
+ {
+ release_render_list(&target->primlist[listnum]);
+ osd_lock_free(target->primlist[listnum].lock);
+ }
+
+ /* free the layout files */
+ while (target->filelist != NULL)
+ {
+ layout_file *temp = target->filelist;
+ target->filelist = temp->next;
+ layout_file_free(temp);
+ }
+
+ /* free the target itself */
+ free(target);
+}
+
+
+/*-------------------------------------------------
+ render_target_get_indexed - get a render_target
+ by index
+-------------------------------------------------*/
+
+render_target *render_target_get_indexed(int index)
+{
+ render_target *target;
+
+ /* count up the targets until we hit the requested index */
+ for (target = targetlist; target != NULL; target = target->next)
+ if (!(target->flags & RENDER_CREATE_HIDDEN))
+ if (index-- == 0)
+ return target;
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ render_target_get_view_name - return the
+ name of the indexed view, or NULL if it
+ doesn't exist
+-------------------------------------------------*/
+
+const char *render_target_get_view_name(render_target *target, int viewindex)
+{
+ layout_file *file;
+ layout_view *view;
+
+ /* return the name from the indexed view */
+ for (file = target->filelist; file != NULL; file = file->next)
+ for (view = file->viewlist; view != NULL; view = view->next)
+ if (!(target->flags & RENDER_CREATE_NO_ART) || !layout_view_has_art(view))
+ if (viewindex-- == 0)
+ return view->name;
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ render_target_get_view_screens - return a
+ bitmask of which screens are visible on a
+ given view
+-------------------------------------------------*/
+
+UINT32 render_target_get_view_screens(render_target *target, int viewindex)
+{
+ layout_file *file;
+ layout_view *view;
+
+ /* return the name from the indexed view */
+ for (file = target->filelist; file != NULL; file = file->next)
+ for (view = file->viewlist; view != NULL; view = view->next)
+ if (!(target->flags & RENDER_CREATE_NO_ART) || !layout_view_has_art(view))
+ if (viewindex-- == 0)
+ return view->screens;
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ render_target_get_bounds - get the bounds and
+ pixel aspect of a target
+-------------------------------------------------*/
+
+void render_target_get_bounds(render_target *target, INT32 *width, INT32 *height, float *pixel_aspect)
+{
+ if (width != NULL)
+ *width = target->width;
+ if (height != NULL)
+ *height = target->height;
+ if (pixel_aspect != NULL)
+ *pixel_aspect = target->pixel_aspect;
+}
+
+
+/*-------------------------------------------------
+ render_target_set_bounds - set the bounds and
+ pixel aspect of a target
+-------------------------------------------------*/
+
+void render_target_set_bounds(render_target *target, INT32 width, INT32 height, float pixel_aspect)
+{
+ target->width = width;
+ target->height = height;
+ target->bounds.x0 = target->bounds.y0 = 0;
+ target->bounds.x1 = (float)width;
+ target->bounds.y1 = (float)height;
+ target->pixel_aspect = pixel_aspect;
+}
+
+
+/*-------------------------------------------------
+ render_target_get_max_update_rate - get the
+ maximum update rate (refresh rate) of a target,
+ or 0 if no maximum
+-------------------------------------------------*/
+
+float render_target_get_max_update_rate(render_target *target)
+{
+ return target->max_refresh;
+}
+
+
+/*-------------------------------------------------
+ render_target_set_max_update_rate - set the
+ maximum update rate (refresh rate) of a target,
+ or 0 if no maximum
+-------------------------------------------------*/
+
+void render_target_set_max_update_rate(render_target *target, float updates_per_second)
+{
+ target->max_refresh = updates_per_second;
+}
+
+
+/*-------------------------------------------------
+ render_target_get_orientation - get the
+ orientation of a target
+-------------------------------------------------*/
+
+int render_target_get_orientation(render_target *target)
+{
+ return target->orientation;
+}
+
+
+/*-------------------------------------------------
+ render_target_set_orientation - set the
+ orientation of a target
+-------------------------------------------------*/
+
+void render_target_set_orientation(render_target *target, int orientation)
+{
+ target->orientation = orientation;
+}
+
+
+/*-------------------------------------------------
+ render_target_get_layer_config - get the
+ layer config of a target
+-------------------------------------------------*/
+
+int render_target_get_layer_config(render_target *target)
+{
+ return target->layerconfig;
+}
+
+
+/*-------------------------------------------------
+ render_target_set_layer_config - set the
+ layer config of a target
+-------------------------------------------------*/
+
+void render_target_set_layer_config(render_target *target, int layerconfig)
+{
+ target->layerconfig = layerconfig;
+ layout_view_recompute(target->curview, layerconfig);
+}
+
+
+/*-------------------------------------------------
+ render_target_get_view - return the currently
+ selected view index
+-------------------------------------------------*/
+
+int render_target_get_view(render_target *target)
+{
+ layout_file *file;
+ layout_view *view;
+ int index = 0;
+
+ /* find the first named match */
+ for (file = target->filelist; file != NULL; file = file->next)
+ for (view = file->viewlist; view != NULL; view = view->next)
+ if (!(target->flags & RENDER_CREATE_NO_ART) || !layout_view_has_art(view))
+ {
+ if (target->curview == view)
+ return index;
+ index++;
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ render_target_set_view - dynamically change
+ the view for a target
+-------------------------------------------------*/
+
+void render_target_set_view(render_target *target, int viewindex)
+{
+ layout_file *file;
+ layout_view *view;
+
+ /* find the first named match */
+ for (file = target->filelist; file != NULL; file = file->next)
+ for (view = file->viewlist; view != NULL; view = view->next)
+ if (!(target->flags & RENDER_CREATE_NO_ART) || !layout_view_has_art(view))
+ if (viewindex-- == 0)
+ {
+ target->curview = view;
+ layout_view_recompute(view, target->layerconfig);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ render_target_set_max_texture_size - set the
+ upper bound on the texture size
+-------------------------------------------------*/
+
+void render_target_set_max_texture_size(render_target *target, int maxwidth, int maxheight)
+{
+ target->maxtexwidth = maxwidth;
+ target->maxtexheight = maxheight;
+}
+
+
+/*-------------------------------------------------
+ render_target_compute_visible_area - compute
+ the visible area for the given target with
+ the current layout and proposed new parameters
+-------------------------------------------------*/
+
+void render_target_compute_visible_area(render_target *target, INT32 target_width, INT32 target_height, float target_pixel_aspect, UINT8 target_orientation, INT32 *visible_width, INT32 *visible_height)
+{
+ float width, height;
+ float scale;
+
+ /* constrained case */
+ if (target_pixel_aspect != 0.0f)
+ {
+ /* start with the aspect ratio of the square pixel layout */
+ width = (target->layerconfig & LAYER_CONFIG_ZOOM_TO_SCREEN) ? target->curview->scraspect : target->curview->aspect;
+ height = 1.0f;
+
+ /* first apply target orientation */
+ if (target_orientation & ORIENTATION_SWAP_XY)
+ FSWAP(width, height);
+
+ /* apply the target pixel aspect ratio */
+ height *= target_pixel_aspect;
+
+ /* based on the height/width ratio of the source and target, compute the scale factor */
+ if (width / height > (float)target_width / (float)target_height)
+ scale = (float)target_width / width;
+ else
+ scale = (float)target_height / height;
+ }
+
+ /* stretch-to-fit case */
+ else
+ {
+ width = (float)target_width;
+ height = (float)target_height;
+ scale = 1.0f;
+ }
+
+ /* set the final width/height */
+ if (visible_width != NULL)
+ *visible_width = render_round_nearest(width * scale);
+ if (visible_height != NULL)
+ *visible_height = render_round_nearest(height * scale);
+}
+
+
+/*-------------------------------------------------
+ render_target_get_minimum_size - get the
+ "minimum" size of a target, which is the
+ smallest bounds that will ensure at least
+ 1 target pixel per source pixel for all
+ included screens
+-------------------------------------------------*/
+
+void render_target_get_minimum_size(render_target *target, INT32 *minwidth, INT32 *minheight)
+{
+ float maxxscale = 1.0f, maxyscale = 1.0f;
+ int layer;
+
+ /* scan the current view for all screens */
+ for (layer = 0; layer < ITEM_LAYER_MAX; layer++)
+ {
+ view_item *item;
+
+ /* iterate over items in the layer */
+ for (item = target->curview->itemlist[layer]; item != NULL; item = item->next)
+ if (item->element == NULL)
+ {
+ const rectangle vectorvis = { 0, 639, 0, 479 };
+ const rectangle *visarea;
+ render_container *container = screen_container[item->index];
+ render_bounds bounds;
+ float xscale, yscale;
+
+ /* we may be called very early, before Machine->visible_area is initialized; handle that case */
+ if ((Machine->drv->video_attributes & VIDEO_TYPE_VECTOR) != 0)
+ visarea = &vectorvis;
+ else if (Machine->screen[item->index].visarea.max_x > Machine->screen[item->index].visarea.min_x)
+ visarea = &Machine->screen[item->index].visarea;
+ else
+ visarea = &Machine->drv->screen[item->index].defstate.visarea;
+
+ /* apply target orientation to the bounds */
+ bounds = item->bounds;
+ apply_orientation(&bounds, target->orientation);
+ normalize_bounds(&bounds);
+
+ /* based on the orientation of the screen container, check the bitmap */
+ if (!(orientation_add(target->orientation, container->orientation) & ORIENTATION_SWAP_XY))
+ {
+ xscale = (float)(visarea->max_x + 1 - visarea->min_x) / (bounds.x1 - bounds.x0);
+ yscale = (float)(visarea->max_y + 1 - visarea->min_y) / (bounds.y1 - bounds.y0);
+ }
+ else
+ {
+ xscale = (float)(visarea->max_y + 1 - visarea->min_y) / (bounds.x1 - bounds.x0);
+ yscale = (float)(visarea->max_x + 1 - visarea->min_x) / (bounds.y1 - bounds.y0);
+ }
+
+ /* pick the greater */
+ if (xscale > maxxscale)
+ maxxscale = xscale;
+ if (yscale > maxyscale)
+ maxyscale = yscale;
+ }
+ }
+
+ /* round up */
+ if (minwidth != NULL)
+ *minwidth = render_round_nearest(maxxscale);
+ if (minheight != NULL)
+ *minheight = render_round_nearest(maxyscale);
+}
+
+
+/*-------------------------------------------------
+ render_target_get_primitives - return a list
+ of primitives for a given render target
+-------------------------------------------------*/
+
+const render_primitive_list *render_target_get_primitives(render_target *target)
+{
+ static const int standard_order[] = { ITEM_LAYER_SCREEN, ITEM_LAYER_OVERLAY, ITEM_LAYER_BACKDROP, ITEM_LAYER_BEZEL };
+ static const int alternate_order[] = { ITEM_LAYER_BACKDROP, ITEM_LAYER_SCREEN, ITEM_LAYER_OVERLAY, ITEM_LAYER_BEZEL };
+ object_transform root_xform, ui_xform;
+ int itemcount[ITEM_LAYER_MAX];
+ const int *layer_order;
+ INT32 viswidth, visheight;
+ int layernum, listnum;
+
+ /* remember the base values if this is the first frame */
+ if (target->base_view == NULL)
+ target->base_view = target->curview;
+
+ /* switch to the next primitive list */
+ listnum = target->listindex;
+ target->listindex = (target->listindex + 1) % NUM_PRIMLISTS;
+ osd_lock_acquire(target->primlist[listnum].lock);
+
+ /* free any previous primitives */
+ release_render_list(&target->primlist[listnum]);
+
+ /* compute the visible width/height */
+ render_target_compute_visible_area(target, target->width, target->height, target->pixel_aspect, target->orientation, &viswidth, &visheight);
+
+ /* create a root transform for the target */
+ root_xform.xoffs = (target->width - viswidth) / 2;
+ root_xform.yoffs = (target->height - visheight) / 2;
+ root_xform.xscale = viswidth;
+ root_xform.yscale = visheight;
+ root_xform.color.r = root_xform.color.g = root_xform.color.b = root_xform.color.a = 1.0f;
+ root_xform.orientation = target->orientation;
+
+ /*
+ if we have multiple backdrop pieces and no overlays, render:
+ backdrop (add) + screens (add) + bezels (alpha)
+ else render:
+ screens (add) + overlays (RGB multiply) + backdrop (add) + bezels (alpha)
+ */
+ layer_order = standard_order;
+ if (target->curview->itemlist[ITEM_LAYER_BACKDROP] != NULL &&
+ target->curview->itemlist[ITEM_LAYER_BACKDROP]->next != NULL &&
+ target->curview->itemlist[ITEM_LAYER_OVERLAY] == NULL)
+ layer_order = alternate_order;
+
+ /* iterate over layers back-to-front, but only if we're running */
+ if (mame_get_phase(Machine) >= MAME_PHASE_RESET)
+ for (layernum = 0; layernum < ITEM_LAYER_MAX; layernum++)
+ {
+ int layer = layer_order[layernum];
+ if (target->curview->layenabled[layer])
+ {
+ int blendmode = BLENDMODE_ALPHA;
+ view_item *item;
+
+ /* pick a blendmode */
+ if (layer == ITEM_LAYER_SCREEN && layer_order == standard_order)
+ blendmode = -1;
+ else if (layer == ITEM_LAYER_SCREEN || (layer == ITEM_LAYER_BACKDROP && layer_order == standard_order))
+ blendmode = BLENDMODE_ADD;
+ else if (layer == ITEM_LAYER_OVERLAY)
+ blendmode = BLENDMODE_RGB_MULTIPLY;
+
+ /* iterate over items in the layer */
+ itemcount[layer] = 0;
+ for (item = target->curview->itemlist[layer]; item != NULL; item = item->next)
+ {
+ object_transform item_xform;
+ render_bounds bounds;
+
+ /* first apply orientation to the bounds */
+ bounds = item->bounds;
+ apply_orientation(&bounds, root_xform.orientation);
+ normalize_bounds(&bounds);
+
+ /* apply the transform to the item */
+ item_xform.xoffs = root_xform.xoffs + bounds.x0 * root_xform.xscale;
+ item_xform.yoffs = root_xform.yoffs + bounds.y0 * root_xform.yscale;
+ item_xform.xscale = (bounds.x1 - bounds.x0) * root_xform.xscale;
+ item_xform.yscale = (bounds.y1 - bounds.y0) * root_xform.yscale;
+ item_xform.color.r = item->color.r * root_xform.color.r;
+ item_xform.color.g = item->color.g * root_xform.color.g;
+ item_xform.color.b = item->color.b * root_xform.color.b;
+ item_xform.color.a = item->color.a * root_xform.color.a;
+ item_xform.orientation = orientation_add(item->orientation, root_xform.orientation);
+
+ /* if there is no associated element, it must be a screen element */
+ if (item->element != NULL)
+ {
+ int state = (item->name[0] == 0) ? 0 : output_get_value(item->name);
+ add_element_primitives(target, &target->primlist[listnum], &item_xform, item->element, state, blendmode);
+ }
+ else
+ add_container_primitives(target, &target->primlist[listnum], &item_xform, screen_container[item->index], blendmode);
+
+ /* keep track of how many items are in the layer */
+ itemcount[layer]++;
+ }
+ }
+ }
+
+ /* if we are not in the running stage, draw an outer box */
+ else
+ {
+ render_primitive *prim;
+
+ prim = alloc_render_primitive(RENDER_PRIMITIVE_QUAD);
+ set_render_bounds_xy(&prim->bounds, 0.0f, 0.0f, (float)target->width, (float)target->height);
+ set_render_color(&prim->color, 1.0f, 1.0f, 1.0f, 1.0f);
+ prim->texture.base = NULL;
+ prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
+ append_render_primitive(&target->primlist[listnum], prim);
+
+ prim = alloc_render_primitive(RENDER_PRIMITIVE_QUAD);
+ set_render_bounds_xy(&prim->bounds, 1.0f, 1.0f, (float)(target->width - 1), (float)(target->height - 1));
+ set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f);
+ prim->texture.base = NULL;
+ prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
+ append_render_primitive(&target->primlist[listnum], prim);
+ }
+
+ /* process the UI if we are the UI target */
+ if (target == render_get_ui_target())
+ {
+ /* compute the transform for the UI */
+ ui_xform.xoffs = 0;
+ ui_xform.yoffs = 0;
+ ui_xform.xscale = target->width;
+ ui_xform.yscale = target->height;
+ ui_xform.color.r = ui_xform.color.g = ui_xform.color.b = ui_xform.color.a = 1.0f;
+ ui_xform.orientation = target->orientation;
+
+ /* add UI elements */
+ add_container_primitives(target, &target->primlist[listnum], &ui_xform, ui_container, BLENDMODE_ALPHA);
+ }
+
+ /* optimize the list before handing it off */
+ add_clear_and_optimize_primitive_list(target, &target->primlist[listnum]);
+ osd_lock_release(target->primlist[listnum].lock);
+ return &target->primlist[listnum];
+}
+
+
+/*-------------------------------------------------
+ load_layout_files - load layout files for a
+ given render target
+-------------------------------------------------*/
+
+static int load_layout_files(render_target *target, const char *layoutfile, int singlefile)
+{
+ layout_file **nextfile = &target->filelist;
+ const game_driver *cloneof;
+
+ /* if there's an explicit file, load that first */
+ if (layoutfile != NULL)
+ {
+ *nextfile = layout_file_load(Machine->basename, layoutfile);
+ if (*nextfile != NULL)
+ nextfile = &(*nextfile)->next;
+ }
+
+ /* if we're only loading this file, we know our final result */
+ if (singlefile)
+ return (nextfile == &target->filelist) ? 1 : 0;
+
+ /* try to load a file based on the driver name */
+ *nextfile = layout_file_load(Machine->basename, Machine->gamedrv->name);
+ if (*nextfile == NULL)
+ *nextfile = layout_file_load(Machine->basename, "default");
+ if (*nextfile != NULL)
+ nextfile = &(*nextfile)->next;
+
+ /* if a default view has been specified, use that as a fallback */
+ if (Machine->gamedrv->default_layout != NULL)
+ {
+ *nextfile = layout_file_load(NULL, Machine->gamedrv->default_layout);
+ if (*nextfile != NULL)
+ nextfile = &(*nextfile)->next;
+ }
+ if (Machine->drv->default_layout != NULL)
+ {
+ *nextfile = layout_file_load(NULL, Machine->drv->default_layout);
+ if (*nextfile != NULL)
+ nextfile = &(*nextfile)->next;
+ }
+
+ /* try to load another file based on the parent driver name */
+ cloneof = driver_get_clone(Machine->gamedrv);
+ if (cloneof != NULL)
+ {
+ *nextfile = layout_file_load(cloneof->name, cloneof->name);
+ if (*nextfile == NULL)
+ *nextfile = layout_file_load(cloneof->name, "default");
+ if (*nextfile != NULL)
+ nextfile = &(*nextfile)->next;
+ }
+
+ /* now do the built-in layouts for single-screen games */
+ if (Machine->drv->screen[0].tag != NULL && Machine->drv->screen[1].tag == NULL)
+ {
+ if (Machine->gamedrv->flags & ORIENTATION_SWAP_XY)
+ *nextfile = layout_file_load(NULL, layout_vertical);
+ else
+ *nextfile = layout_file_load(NULL, layout_horizont);
+ assert_always(*nextfile != NULL, "Couldn't parse default layout??");
+ nextfile = &(*nextfile)->next;
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ release_render_list - release the contents of
+ a render list
+-------------------------------------------------*/
+
+static void release_render_list(render_primitive_list *list)
+{
+ /* take the lock */
+ osd_lock_acquire(list->lock);
+
+ /* free everything on the list */
+ while (list->head != NULL)
+ {
+ render_primitive *temp = list->head;
+ list->head = temp->next;
+ free_render_primitive(temp);
+ }
+ list->nextptr = &list->head;
+
+ /* release all our references */
+ while (list->reflist != NULL)
+ {
+ render_ref *temp = list->reflist;
+ list->reflist = temp->next;
+ free_render_ref(temp);
+ }
+
+ /* let other people at it again */
+ osd_lock_release(list->lock);
+}
+
+
+/*-------------------------------------------------
+ add_container_primitives - add primitives
+ based on the container
+-------------------------------------------------*/
+
+static void add_container_primitives(render_target *target, render_primitive_list *list, const object_transform *xform, render_container *container, int blendmode)
+{
+ object_transform container_xform;
+ render_bounds cliprect;
+ render_primitive *prim;
+ container_item *item;
+
+ /* first update the palette for the container, if it is dirty */
+ render_container_update_palette(container);
+
+ /* compute the clip rect */
+ cliprect.x0 = xform->xoffs;
+ cliprect.y0 = xform->yoffs;
+ cliprect.x1 = xform->xoffs + xform->xscale;
+ cliprect.y1 = xform->yoffs + xform->yscale;
+ sect_render_bounds(&cliprect, &target->bounds);
+
+ /* compute the container transform */
+ container_xform.orientation = orientation_add(container->orientation, xform->orientation);
+ {
+ float xscale = (container_xform.orientation & ORIENTATION_SWAP_XY) ? container->yscale : container->xscale;
+ float yscale = (container_xform.orientation & ORIENTATION_SWAP_XY) ? container->xscale : container->yscale;
+ float xoffs = (container_xform.orientation & ORIENTATION_SWAP_XY) ? container->yoffset : container->xoffset;
+ float yoffs = (container_xform.orientation & ORIENTATION_SWAP_XY) ? container->xoffset : container->yoffset;
+ if (container_xform.orientation & ORIENTATION_FLIP_X) xoffs = -xoffs;
+ if (container_xform.orientation & ORIENTATION_FLIP_Y) yoffs = -yoffs;
+ container_xform.xscale = xform->xscale * xscale;
+ container_xform.yscale = xform->yscale * yscale;
+ container_xform.xoffs = xform->xscale * (0.5f - 0.5f * xscale + xoffs) + xform->xoffs;
+ container_xform.yoffs = xform->yscale * (0.5f - 0.5f * yscale + yoffs) + xform->yoffs;
+ container_xform.color = xform->color;
+ }
+
+ /* iterate over elements */
+ for (item = container->itemlist; item != NULL; item = item->next)
+ {
+ render_bounds bounds;
+ int width, height;
+ int clipped = TRUE;
+
+ /* compute the oriented bounds */
+ bounds = item->bounds;
+ apply_orientation(&bounds, container_xform.orientation);
+
+ /* allocate the primitive and set the transformed bounds/color data */
+ prim = alloc_render_primitive(0);
+ prim->bounds.x0 = render_round_nearest(container_xform.xoffs + bounds.x0 * container_xform.xscale);
+ prim->bounds.y0 = render_round_nearest(container_xform.yoffs + bounds.y0 * container_xform.yscale);
+ if (item->internal & INTERNAL_FLAG_CHAR)
+ {
+ prim->bounds.x1 = prim->bounds.x0 + render_round_nearest((bounds.x1 - bounds.x0) * container_xform.xscale);
+ prim->bounds.y1 = prim->bounds.y0 + render_round_nearest((bounds.y1 - bounds.y0) * container_xform.yscale);
+ }
+ else
+ {
+ prim->bounds.x1 = render_round_nearest(container_xform.xoffs + bounds.x1 * container_xform.xscale);
+ prim->bounds.y1 = render_round_nearest(container_xform.yoffs + bounds.y1 * container_xform.yscale);
+ }
+
+ /* compute the color of the primitive */
+ prim->color.r = container_xform.color.r * item->color.r;
+ prim->color.g = container_xform.color.g * item->color.g;
+ prim->color.b = container_xform.color.b * item->color.b;
+ prim->color.a = container_xform.color.a * item->color.a;
+
+ /* now switch off the type */
+ switch (item->type)
+ {
+ case CONTAINER_ITEM_LINE:
+ /* adjust the color for brightness/contrast/gamma */
+ prim->color.a = apply_brightness_contrast_gamma_fp(prim->color.a, container->brightness, container->contrast, container->gamma);
+ prim->color.r = apply_brightness_contrast_gamma_fp(prim->color.r, container->brightness, container->contrast, container->gamma);
+ prim->color.g = apply_brightness_contrast_gamma_fp(prim->color.g, container->brightness, container->contrast, container->gamma);
+ prim->color.b = apply_brightness_contrast_gamma_fp(prim->color.b, container->brightness, container->contrast, container->gamma);
+
+ /* set the line type */
+ prim->type = RENDER_PRIMITIVE_LINE;
+
+ /* scale the width by the minimum of X/Y scale factors */
+ prim->width = item->width * MIN(container_xform.xscale, container_xform.yscale);
+ prim->flags = item->flags;
+
+ /* clip the primitive */
+ clipped = render_clip_line(&prim->bounds, &cliprect);
+ break;
+
+ case CONTAINER_ITEM_QUAD:
+ /* set the quad type */
+ prim->type = RENDER_PRIMITIVE_QUAD;
+
+ /* normalize the bounds */
+ normalize_bounds(&prim->bounds);
+
+ /* get the scaled bitmap and set the resulting palette */
+ if (item->texture != NULL)
+ {
+ /* determine the final orientation */
+ int finalorient = orientation_add(PRIMFLAG_GET_TEXORIENT(item->flags), container_xform.orientation);
+
+ /* based on the swap values, get the scaled final texture */
+ width = (finalorient & ORIENTATION_SWAP_XY) ? (prim->bounds.y1 - prim->bounds.y0) : (prim->bounds.x1 - prim->bounds.x0);
+ height = (finalorient & ORIENTATION_SWAP_XY) ? (prim->bounds.x1 - prim->bounds.x0) : (prim->bounds.y1 - prim->bounds.y0);
+ width = MIN(width, target->maxtexwidth);
+ height = MIN(height, target->maxtexheight);
+ if (render_texture_get_scaled(item->texture, width, height, &prim->texture, &list->reflist))
+ {
+ /* override the palette with our adjusted palette */
+ switch (item->texture->format)
+ {
+ case TEXFORMAT_PALETTE16: prim->texture.palette = &container->bcglookup[prim->texture.palette - palette_entry_list_adjusted(Machine->palette)]; break;
+ case TEXFORMAT_PALETTEA16: prim->texture.palette = &container->bcglookup[prim->texture.palette - palette_entry_list_adjusted(Machine->palette)]; break;
+ case TEXFORMAT_RGB15: prim->texture.palette = &container->bcglookup32[0]; break;
+ case TEXFORMAT_RGB32: prim->texture.palette = &container->bcglookup256[0]; break;
+ case TEXFORMAT_ARGB32: prim->texture.palette = &container->bcglookup256[0]; break;
+ case TEXFORMAT_YUY16: prim->texture.palette = &container->bcglookup256[0]; break;
+ default: assert(FALSE);
+ }
+
+ /* determine UV coordinates and apply clipping */
+ prim->texcoords = oriented_texcoords[finalorient];
+ clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
+
+ /* apply the final orientation from the quad flags and then build up the final flags */
+ prim->flags = (item->flags & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) |
+ PRIMFLAG_TEXORIENT(finalorient) |
+ PRIMFLAG_TEXFORMAT(item->texture->format);
+ if (blendmode != -1)
+ prim->flags |= PRIMFLAG_BLENDMODE(blendmode);
+ else
+ prim->flags |= PRIMFLAG_BLENDMODE(PRIMFLAG_GET_BLENDMODE(item->flags));
+ }
+ }
+ else
+ {
+ /* adjust the color for brightness/contrast/gamma */
+ prim->color.r = apply_brightness_contrast_gamma_fp(prim->color.r, container->brightness, container->contrast, container->gamma);
+ prim->color.g = apply_brightness_contrast_gamma_fp(prim->color.g, container->brightness, container->contrast, container->gamma);
+ prim->color.b = apply_brightness_contrast_gamma_fp(prim->color.b, container->brightness, container->contrast, container->gamma);
+
+ /* no texture -- set the basic flags */
+ prim->texture.base = NULL;
+ prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
+
+ /* apply clipping */
+ clipped = render_clip_quad(&prim->bounds, &cliprect, NULL);
+ }
+ break;
+ }
+
+ /* add to the list or free if we're clipped out */
+ if (!clipped)
+ append_render_primitive(list, prim);
+ else
+ free_render_primitive(prim);
+ }
+
+ /* add the overlay if it exists */
+ if (container->overlaytexture != NULL && (target->layerconfig & LAYER_CONFIG_ENABLE_SCREEN_OVERLAY))
+ {
+ INT32 width, height;
+
+ /* allocate a primitive */
+ prim = alloc_render_primitive(RENDER_PRIMITIVE_QUAD);
+ set_render_bounds_wh(&prim->bounds, xform->xoffs, xform->yoffs, xform->xscale, xform->yscale);
+ prim->color = container_xform.color;
+ width = render_round_nearest(prim->bounds.x1) - render_round_nearest(prim->bounds.x0);
+ height = render_round_nearest(prim->bounds.y1) - render_round_nearest(prim->bounds.y0);
+ if (render_texture_get_scaled(container->overlaytexture,
+ (container_xform.orientation & ORIENTATION_SWAP_XY) ? height : width,
+ (container_xform.orientation & ORIENTATION_SWAP_XY) ? width : height, &prim->texture, &list->reflist))
+ {
+ /* determine UV coordinates */
+ prim->texcoords = oriented_texcoords[container_xform.orientation];
+
+ /* set the flags and add it to the list */
+ prim->flags = PRIMFLAG_TEXORIENT(container_xform.orientation) |
+ PRIMFLAG_BLENDMODE(BLENDMODE_RGB_MULTIPLY) |
+ PRIMFLAG_TEXFORMAT(container->overlaytexture->format);
+ append_render_primitive(list, prim);
+ }
+ else
+ free_render_primitive(prim);
+ }
+}
+
+
+/*-------------------------------------------------
+ add_element_primitives - add the primitive
+ for an element in the current state
+-------------------------------------------------*/
+
+static void add_element_primitives(render_target *target, render_primitive_list *list, const object_transform *xform, const layout_element *element, int state, int blendmode)
+{
+ INT32 width = render_round_nearest(xform->xscale);
+ INT32 height = render_round_nearest(xform->yscale);
+ render_texture *texture;
+ render_bounds cliprect;
+ int clipped = TRUE;
+
+ /* if we're out of range, bail */
+ if (state > element->maxstate)
+ return;
+ if (state < 0)
+ state = 0;
+
+ /* get a pointer to the relevant texture */
+ texture = element->elemtex[state].texture;
+ if (texture != NULL)
+ {
+ render_primitive *prim = alloc_render_primitive(RENDER_PRIMITIVE_QUAD);
+
+ /* configure the basics */
+ prim->color = xform->color;
+ prim->flags = PRIMFLAG_TEXORIENT(xform->orientation) | PRIMFLAG_BLENDMODE(blendmode) | PRIMFLAG_TEXFORMAT(texture->format);
+
+ /* compute the bounds */
+ set_render_bounds_wh(&prim->bounds, render_round_nearest(xform->xoffs), render_round_nearest(xform->yoffs), width, height);
+ if (xform->orientation & ORIENTATION_SWAP_XY)
+ ISWAP(width, height);
+ width = MIN(width, target->maxtexwidth);
+ height = MIN(height, target->maxtexheight);
+
+ /* get the scaled texture and append it */
+ if (render_texture_get_scaled(texture, width, height, &prim->texture, &list->reflist))
+ {
+ /* compute the clip rect */
+ cliprect.x0 = render_round_nearest(xform->xoffs);
+ cliprect.y0 = render_round_nearest(xform->yoffs);
+ cliprect.x1 = render_round_nearest(xform->xoffs + xform->xscale);
+ cliprect.y1 = render_round_nearest(xform->yoffs + xform->yscale);
+ sect_render_bounds(&cliprect, &target->bounds);
+
+ /* determine UV coordinates and apply clipping */
+ prim->texcoords = oriented_texcoords[xform->orientation];
+ clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
+ }
+
+ /* add to the list or free if we're clipped out */
+ if (!clipped)
+ append_render_primitive(list, prim);
+ else
+ free_render_primitive(prim);
+ }
+}
+
+
+/*-------------------------------------------------
+ init_clear_extents - reset the extents list
+-------------------------------------------------*/
+
+static void init_clear_extents(INT32 width, INT32 height)
+{
+ clear_extents[0] = -height;
+ clear_extents[1] = 1;
+ clear_extents[2] = width;
+ clear_extent_count = 3;
+}
+
+
+/*-------------------------------------------------
+ remove_clear_extent - remove a quad from the
+ list of stuff to clear, unless it overlaps
+ a previous quad
+-------------------------------------------------*/
+
+static int remove_clear_extent(const render_bounds *bounds)
+{
+ INT32 *max = &clear_extents[MAX_CLEAR_EXTENTS];
+ INT32 *last = &clear_extents[clear_extent_count];
+ INT32 *ext = &clear_extents[0];
+ INT32 boundsx0 = ceil(bounds->x0);
+ INT32 boundsx1 = floor(bounds->x1);
+ INT32 boundsy0 = ceil(bounds->y0);
+ INT32 boundsy1 = floor(bounds->y1);
+ INT32 y0, y1 = 0;
+
+ /* loop over Y extents */
+ while (ext < last)
+ {
+ INT32 *linelast;
+
+ /* first entry of each line should always be negative */
+ assert(ext[0] < 0.0f);
+ y0 = y1;
+ y1 = y0 - ext[0];
+
+ /* do we intersect this extent? */
+ if (boundsy0 < y1 && boundsy1 > y0)
+ {
+ INT32 *xext;
+ INT32 x0, x1 = 0;
+
+ /* split the top */
+ if (y0 < boundsy0)
+ {
+ int diff = boundsy0 - y0;
+
+ /* make a copy of this extent */
+ memmove(&ext[ext[1] + 2], &ext[0], (last - ext) * sizeof(*ext));
+ last += ext[1] + 2;
+ assert_always(last < max, "Ran out of clear extents!\n");
+
+ /* split the extent between pieces */
+ ext[ext[1] + 2] = -(-ext[0] - diff);
+ ext[0] = -diff;
+
+ /* advance to the new extent */
+ y0 -= ext[0];
+ ext += ext[1] + 2;
+ y1 = y0 - ext[0];
+ }
+
+ /* split the bottom */
+ if (y1 > boundsy1)
+ {
+ int diff = y1 - boundsy1;
+
+ /* make a copy of this extent */
+ memmove(&ext[ext[1] + 2], &ext[0], (last - ext) * sizeof(*ext));
+ last += ext[1] + 2;
+ assert_always(last < max, "Ran out of clear extents!\n");
+
+ /* split the extent between pieces */
+ ext[ext[1] + 2] = -diff;
+ ext[0] = -(-ext[0] - diff);
+
+ /* recompute y1 */
+ y1 = y0 - ext[0];
+ }
+
+ /* now remove the X extent */
+ linelast = &ext[ext[1] + 2];
+ xext = &ext[2];
+ while (xext < linelast)
+ {
+ x0 = x1;
+ x1 = x0 + xext[0];
+
+ /* do we fully intersect this extent? */
+ if (boundsx0 >= x0 && boundsx1 <= x1)
+ {
+ /* yes; split it */
+ memmove(&xext[2], &xext[0], (last - xext) * sizeof(*xext));
+ last += 2;
+ linelast += 2;
+ assert_always(last < max, "Ran out of clear extents!\n");
+
+ /* split this extent into three parts */
+ xext[0] = boundsx0 - x0;
+ xext[1] = boundsx1 - boundsx0;
+ xext[2] = x1 - boundsx1;
+
+ /* recompute x1 */
+ x1 = boundsx1;
+ xext += 2;
+ }
+
+ /* do we partially intersect this extent? */
+ else if (boundsx0 < x1 && boundsx1 > x0)
+ goto abort;
+
+ /* advance */
+ xext++;
+
+ /* do we partially intersect the next extent (which is a non-clear extent)? */
+ if (xext < linelast)
+ {
+ x0 = x1;
+ x1 = x0 + xext[0];
+ if (boundsx0 < x1 && boundsx1 > x0)
+ goto abort;
+ xext++;
+ }
+ }
+
+ /* update the count */
+ ext[1] = linelast - &ext[2];
+ }
+
+ /* advance to the next row */
+ ext += 2 + ext[1];
+ }
+
+ /* update the total count */
+ clear_extent_count = last - &clear_extents[0];
+ return TRUE;
+
+abort:
+ /* update the total count even on a failure as we may have split extents */
+ clear_extent_count = last - &clear_extents[0];
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ add_clear_extents - add the accumulated
+ extents as a series of quads to clear
+-------------------------------------------------*/
+
+static void add_clear_extents(render_primitive_list *list)
+{
+ render_primitive *clearlist = NULL;
+ render_primitive **clearnext = &clearlist;
+ INT32 *last = &clear_extents[clear_extent_count];
+ INT32 *ext = &clear_extents[0];
+ INT32 y0, y1 = 0;
+
+ /* loop over all extents */
+ while (ext < last)
+ {
+ INT32 *linelast = &ext[ext[1] + 2];
+ INT32 *xext = &ext[2];
+ INT32 x0, x1 = 0;
+
+ /* first entry should always be negative */
+ assert(ext[0] < 0);
+ y0 = y1;
+ y1 = y0 - ext[0];
+
+ /* now remove the X extent */
+ while (xext < linelast)
+ {
+ x0 = x1;
+ x1 = x0 + *xext++;
+
+ /* only add entries for non-zero widths */
+ if (x1 - x0 > 0)
+ {
+ render_primitive *prim = alloc_render_primitive(RENDER_PRIMITIVE_QUAD);
+ set_render_bounds_xy(&prim->bounds, (float)x0, (float)y0, (float)x1, (float)y1);
+ set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f);
+ prim->texture.base = NULL;
+ prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
+ *clearnext = prim;
+ clearnext = &prim->next;
+ }
+
+ /* skip the non-clearing extent */
+ x0 = x1;
+ x1 = x0 + *xext++;
+ }
+
+ /* advance to the next part */
+ ext += 2 + ext[1];
+ }
+
+ /* we know that the first primitive in the list will be the global clip */
+ /* so we insert the clears immediately after */
+ *clearnext = list->head;
+ list->head = clearlist;
+}
+
+
+/*-------------------------------------------------
+ add_clear_and_optimize_primitive_list -
+ optimize the primitive list
+-------------------------------------------------*/
+
+static void add_clear_and_optimize_primitive_list(render_target *target, render_primitive_list *list)
+{
+ render_primitive *prim;
+
+ /* start with the assumption that we need to clear the whole screen */
+ init_clear_extents(target->width, target->height);
+
+ /* scan the list until we hit an intersection quad or a line */
+ for (prim = list->head; prim != NULL; prim = prim->next)
+ {
+ /* switch off the type */
+ switch (prim->type)
+ {
+ case RENDER_PRIMITIVE_LINE:
+ goto done;
+
+ case RENDER_PRIMITIVE_QUAD:
+ {
+ /* stop when we hit an alpha texture */
+ if (PRIMFLAG_GET_TEXFORMAT(prim->flags) == TEXFORMAT_ARGB32 || PRIMFLAG_GET_TEXFORMAT(prim->flags) == TEXFORMAT_PALETTEA16)
+ goto done;
+
+ /* if this quad can't be cleanly removed from the extents list, we're done */
+ if (!remove_clear_extent(&prim->bounds))
+ goto done;
+
+ /* change the blendmode on the first primitive to be NONE */
+ if (PRIMFLAG_GET_BLENDMODE(prim->flags) == BLENDMODE_RGB_MULTIPLY)
+ {
+ /* RGB multiply will multiply against 0, leaving nothing */
+ set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f);
+ prim->texture.base = NULL;
+ prim->flags = (prim->flags & ~PRIMFLAG_BLENDMODE_MASK) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE);
+ }
+ else
+ {
+ /* for alpha or add modes, we will blend against 0 or add to 0; treat it like none */
+ prim->flags = (prim->flags & ~PRIMFLAG_BLENDMODE_MASK) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE);
+ }
+
+ /* since alpha is disabled, premultiply the RGB values and reset the alpha to 1.0 */
+ prim->color.r *= prim->color.a;
+ prim->color.g *= prim->color.a;
+ prim->color.b *= prim->color.a;
+ prim->color.a = 1.0f;
+ break;
+ }
+ }
+ }
+
+done:
+ /* now add the extents to the clear list */
+ add_clear_extents(list);
+}
+
+
+
+/***************************************************************************
+ RENDER REFERENCES
+***************************************************************************/
+
+/*-------------------------------------------------
+ invalidate_all_render_ref - remove all refs
+ to a particular reference pointer
+-------------------------------------------------*/
+
+static void invalidate_all_render_ref(void *refptr)
+{
+ render_target *target;
+ int listnum;
+
+ /* loop over targets */
+ for (target = targetlist; target != NULL; target = target->next)
+ for (listnum = 0; listnum < NUM_PRIMLISTS; listnum++)
+ {
+ render_primitive_list *list = &target->primlist[listnum];
+ osd_lock_acquire(list->lock);
+ if (has_render_ref(list->reflist, refptr))
+ release_render_list(list);
+ osd_lock_release(list->lock);
+ }
+}
+
+
+
+/***************************************************************************
+ RENDER TEXTURES
+***************************************************************************/
+
+/*-------------------------------------------------
+ render_texture_alloc - allocate a new texture
+-------------------------------------------------*/
+
+render_texture *render_texture_alloc(texture_scaler scaler, void *param)
+{
+ render_texture *texture;
+
+ /* if nothing on the free list, add some more */
+ if (render_texture_free_list == NULL)
+ {
+ int texnum;
+
+ /* allocate a new group */
+ texture = malloc_or_die(sizeof(*texture) * TEXTURE_GROUP_SIZE);
+ memset(texture, 0, sizeof(*texture) * TEXTURE_GROUP_SIZE);
+
+ /* add them to the list */
+ for (texnum = 0; texnum < TEXTURE_GROUP_SIZE; texnum++)
+ {
+ texture[texnum].base = texture;
+ texture[texnum].next = render_texture_free_list;
+ render_texture_free_list = &texture[texnum];
+ }
+ }
+
+ /* pull an entry off the free list */
+ texture = render_texture_free_list;
+ render_texture_free_list = texture->next;
+
+ /* fill in the data */
+ texture->scaler = scaler;
+ texture->param = param;
+ texture->format = TEXFORMAT_ARGB32;
+ return texture;
+}
+
+
+/*-------------------------------------------------
+ render_texture_free - free an allocated
+ texture
+-------------------------------------------------*/
+
+void render_texture_free(render_texture *texture)
+{
+ render_texture *base_save;
+ int scalenum;
+
+ /* free all scaled versions */
+ for (scalenum = 0; scalenum < ARRAY_LENGTH(texture->scaled); scalenum++)
+ if (texture->scaled[scalenum].bitmap != NULL)
+ {
+ invalidate_all_render_ref(texture->scaled[scalenum].bitmap);
+ bitmap_free(texture->scaled[scalenum].bitmap);
+ }
+
+ /* invalidate references to the original bitmap as well */
+ if (texture->bitmap != NULL)
+ invalidate_all_render_ref(texture->bitmap);
+
+ /* add ourself back to the free list */
+ base_save = texture->base;
+ memset(texture, 0, sizeof(*texture));
+ texture->next = render_texture_free_list;
+ texture->base = base_save;
+ render_texture_free_list = texture;
+}
+
+
+/*-------------------------------------------------
+ render_texture_set_bitmap - set a new source
+ bitmap
+-------------------------------------------------*/
+
+void render_texture_set_bitmap(render_texture *texture, mame_bitmap *bitmap, const rectangle *sbounds, UINT32 palettebase, int format)
+{
+ int scalenum;
+
+ /* invalidate references to the old bitmap */
+ if (bitmap != texture->bitmap && texture->bitmap != NULL)
+ invalidate_all_render_ref(texture->bitmap);
+
+ /* set the new bitmap/palette */
+ texture->bitmap = bitmap;
+ texture->sbounds.min_x = (sbounds != NULL) ? sbounds->min_x : 0;
+ texture->sbounds.min_y = (sbounds != NULL) ? sbounds->min_y : 0;
+ texture->sbounds.max_x = (sbounds != NULL) ? sbounds->max_x : (bitmap != NULL) ? bitmap->width : 1000;
+ texture->sbounds.max_y = (sbounds != NULL) ? sbounds->max_y : (bitmap != NULL) ? bitmap->height : 1000;
+ texture->palettebase = palettebase;
+ texture->format = format;
+
+ /* invalidate all scaled versions */
+ for (scalenum = 0; scalenum < ARRAY_LENGTH(texture->scaled); scalenum++)
+ {
+ if (texture->scaled[scalenum].bitmap != NULL)
+ {
+ invalidate_all_render_ref(texture->scaled[scalenum].bitmap);
+ bitmap_free(texture->scaled[scalenum].bitmap);
+ }
+ texture->scaled[scalenum].bitmap = NULL;
+ texture->scaled[scalenum].seqid = 0;
+ }
+}
+
+
+/*-------------------------------------------------
+ render_texture_get_scaled - get a scaled
+ bitmap (if we can)
+-------------------------------------------------*/
+
+static int render_texture_get_scaled(render_texture *texture, UINT32 dwidth, UINT32 dheight, render_texinfo *texinfo, render_ref **reflist)
+{
+ UINT8 bpp = (texture->format == TEXFORMAT_PALETTE16 || texture->format == TEXFORMAT_PALETTEA16 || texture->format == TEXFORMAT_RGB15 || texture->format == TEXFORMAT_YUY16) ? 16 : 32;
+ const rgb_t *palbase = (texture->format == TEXFORMAT_PALETTE16 || texture->format == TEXFORMAT_PALETTEA16) ? palette_entry_list_adjusted(Machine->palette) + texture->palettebase : NULL;
+ scaled_texture *scaled = NULL;
+ int swidth, sheight;
+ int scalenum;
+
+ /* source width/height come from the source bounds */
+ swidth = texture->sbounds.max_x - texture->sbounds.min_x;
+ sheight = texture->sbounds.max_y - texture->sbounds.min_y;
+
+ /* ensure height/width are non-zero */
+ if (dwidth < 1) dwidth = 1;
+ if (dheight < 1) dheight = 1;
+
+ /* are we scaler-free? if so, just return the source bitmap */
+ if (texture->scaler == NULL || (texture->bitmap != NULL && swidth == dwidth && sheight == dheight))
+ {
+ /* add a reference and set up the source bitmap */
+ add_render_ref(reflist, texture->bitmap);
+ texinfo->base = (UINT8 *)texture->bitmap->base + (texture->sbounds.min_y * texture->bitmap->rowpixels + texture->sbounds.min_x) * (bpp / 8);
+ texinfo->rowpixels = texture->bitmap->rowpixels;
+ texinfo->width = swidth;
+ texinfo->height = sheight;
+ texinfo->palette = palbase;
+ texinfo->seqid = ++texture->curseq;
+ return TRUE;
+ }
+
+ /* is it a size we already have? */
+ for (scalenum = 0; scalenum < ARRAY_LENGTH(texture->scaled); scalenum++)
+ {
+ scaled = &texture->scaled[scalenum];
+
+ /* we need a non-NULL bitmap with matching dest size */
+ if (scaled->bitmap != NULL && dwidth == scaled->bitmap->width && dheight == scaled->bitmap->height)
+ break;
+ }
+
+ /* did we get one? */
+ if (scalenum == ARRAY_LENGTH(texture->scaled))
+ {
+ int lowest = -1;
+
+ /* ask our notifier if we can scale now */
+ if (rescale_notify != NULL && !(*rescale_notify)(Machine, dwidth, dheight))
+ return FALSE;
+
+ /* didn't find one -- take the entry with the lowest seqnum */
+ for (scalenum = 0; scalenum < ARRAY_LENGTH(texture->scaled); scalenum++)
+ if ((lowest == -1 || texture->scaled[scalenum].seqid < texture->scaled[lowest].seqid) && !has_render_ref(*reflist, texture->scaled[scalenum].bitmap))
+ lowest = scalenum;
+ assert_always(lowest != -1, "Too many live texture instances!");
+
+ /* throw out any existing entries */
+ scaled = &texture->scaled[lowest];
+ if (scaled->bitmap != NULL)
+ {
+ invalidate_all_render_ref(scaled->bitmap);
+ bitmap_free(scaled->bitmap);
+ }
+
+ /* allocate a new bitmap */
+ scaled->bitmap = bitmap_alloc(dwidth, dheight, BITMAP_FORMAT_ARGB32);
+ scaled->seqid = ++texture->curseq;
+
+ /* let the scaler do the work */
+ (*texture->scaler)(scaled->bitmap, texture->bitmap, &texture->sbounds, texture->param);
+ }
+
+ /* finally fill out the new info */
+ add_render_ref(reflist, scaled->bitmap);
+ texinfo->base = scaled->bitmap->base;
+ texinfo->rowpixels = scaled->bitmap->rowpixels;
+ texinfo->width = dwidth;
+ texinfo->height = dheight;
+ texinfo->palette = palbase;
+ texinfo->seqid = scaled->seqid;
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ render_texture_hq_scale - generic high quality
+ resampling scaler
+-------------------------------------------------*/
+
+void render_texture_hq_scale(mame_bitmap *dest, const mame_bitmap *source, const rectangle *sbounds, void *param)
+{
+ render_color color = { 1.0f, 1.0f, 1.0f, 1.0f };
+ render_resample_argb_bitmap_hq(dest->base, dest->rowpixels, dest->width, dest->height, source, sbounds, &color);
+}
+
+
+
+/***************************************************************************
+ RENDER CONTAINERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ render_container_alloc - allocate a render
+ container
+-------------------------------------------------*/
+
+static render_container *render_container_alloc(void)
+{
+ render_container *container;
+ int color;
+
+ /* allocate and clear memory */
+ container = malloc_or_die(sizeof(*container));
+ memset(container, 0, sizeof(*container));
+
+ /* default values */
+ container->brightness = 1.0f;
+ container->contrast = 1.0f;
+ container->gamma = 1.0f;
+ container->xscale = 1.0f;
+ container->yscale = 1.0f;
+
+ /* all palette entries are opaque by default */
+ for (color = 0; color < ARRAY_LENGTH(container->bcglookup); color++)
+ container->bcglookup[color] = MAKE_ARGB(0xff,0x00,0x00,0x00);
+
+ /* make sure it is empty */
+ render_container_empty(container);
+
+ /* allocate a client to the main palette */
+ if (Machine->palette != NULL)
+ container->palclient = palette_client_alloc(Machine->palette);
+ render_container_recompute_lookups(container);
+ return container;
+}
+
+
+/*-------------------------------------------------
+ render_container_free - free a render
+ container
+-------------------------------------------------*/
+
+static void render_container_free(render_container *container)
+{
+ /* free all the container items */
+ render_container_empty(container);
+
+ /* free the overlay texture */
+ if (container->overlaytexture != NULL)
+ render_texture_free(container->overlaytexture);
+
+ /* release our palette client */
+ if (container->palclient != NULL)
+ palette_client_free(container->palclient);
+
+ /* free the container itself */
+ free(container);
+}
+
+
+/*-------------------------------------------------
+ render_container_empty - empty a container
+ in preparation for new stuff
+-------------------------------------------------*/
+
+void render_container_empty(render_container *container)
+{
+ /* free all the container items */
+ while (container->itemlist != NULL)
+ {
+ container_item *temp = container->itemlist;
+ container->itemlist = temp->next;
+ free_container_item(temp);
+ }
+
+ /* reset our newly-added pointer */
+ container->nextitem = &container->itemlist;
+}
+
+
+/*-------------------------------------------------
+ render_container_is_empty - return true if
+ a container has nothing in it
+-------------------------------------------------*/
+
+int render_container_is_empty(render_container *container)
+{
+ return (container->itemlist == NULL);
+}
+
+
+/*-------------------------------------------------
+ render_container_get_orientation - return the
+ orientation of a container
+-------------------------------------------------*/
+
+int render_container_get_orientation(render_container *container)
+{
+ return container->orientation;
+}
+
+
+/*-------------------------------------------------
+ render_container_set_orientation - set the
+ orientation of a container
+-------------------------------------------------*/
+
+void render_container_set_orientation(render_container *container, int orientation)
+{
+ container->orientation = orientation;
+}
+
+
+/*-------------------------------------------------
+ render_container_get_brightness - return the
+ brightness of a container
+-------------------------------------------------*/
+
+float render_container_get_brightness(render_container *container)
+{
+ return container->brightness;
+}
+
+
+/*-------------------------------------------------
+ render_container_set_brightness - set the
+ brightness of a container
+-------------------------------------------------*/
+
+void render_container_set_brightness(render_container *container, float brightness)
+{
+ container->brightness = brightness;
+ render_container_recompute_lookups(container);
+}
+
+
+/*-------------------------------------------------
+ render_container_get_contrast - return the
+ contrast of a container
+-------------------------------------------------*/
+
+float render_container_get_contrast(render_container *container)
+{
+ return container->contrast;
+}
+
+
+/*-------------------------------------------------
+ render_container_set_contrast - set the
+ contrast of a container
+-------------------------------------------------*/
+
+void render_container_set_contrast(render_container *container, float contrast)
+{
+ container->contrast = contrast;
+ render_container_recompute_lookups(container);
+}
+
+
+/*-------------------------------------------------
+ render_container_get_gamma - return the
+ gamma of a container
+-------------------------------------------------*/
+
+float render_container_get_gamma(render_container *container)
+{
+ return container->gamma;
+}
+
+
+/*-------------------------------------------------
+ render_container_set_gamma - set the
+ gamma of a container
+-------------------------------------------------*/
+
+void render_container_set_gamma(render_container *container, float gamma)
+{
+ container->gamma = gamma;
+ render_container_recompute_lookups(container);
+}
+
+
+/*-------------------------------------------------
+ render_container_get_xscale - return the
+ X scale of a container
+-------------------------------------------------*/
+
+float render_container_get_xscale(render_container *container)
+{
+ return container->xscale;
+}
+
+
+/*-------------------------------------------------
+ render_container_set_xscale - set the
+ X scale of a container
+-------------------------------------------------*/
+
+void render_container_set_xscale(render_container *container, float xscale)
+{
+ container->xscale = xscale;
+}
+
+
+/*-------------------------------------------------
+ render_container_get_yscale - return the
+ X scale of a container
+-------------------------------------------------*/
+
+float render_container_get_yscale(render_container *container)
+{
+ return container->yscale;
+}
+
+
+/*-------------------------------------------------
+ render_container_set_yscale - set the
+ X scale of a container
+-------------------------------------------------*/
+
+void render_container_set_yscale(render_container *container, float yscale)
+{
+ container->yscale = yscale;
+}
+
+
+/*-------------------------------------------------
+ render_container_get_xoffset - return the
+ X offset of a container
+-------------------------------------------------*/
+
+float render_container_get_xoffset(render_container *container)
+{
+ return container->xoffset;
+}
+
+
+/*-------------------------------------------------
+ render_container_set_xoffset - set the
+ X offset of a container
+-------------------------------------------------*/
+
+void render_container_set_xoffset(render_container *container, float xoffset)
+{
+ container->xoffset = xoffset;
+}
+
+
+/*-------------------------------------------------
+ render_container_get_yoffset - return the
+ X offset of a container
+-------------------------------------------------*/
+
+float render_container_get_yoffset(render_container *container)
+{
+ return container->yoffset;
+}
+
+
+/*-------------------------------------------------
+ render_container_set_yoffset - set the
+ X offset of a container
+-------------------------------------------------*/
+
+void render_container_set_yoffset(render_container *container, float yoffset)
+{
+ container->yoffset = yoffset;
+}
+
+
+/*-------------------------------------------------
+ render_container_set_overlay - set the
+ overlay bitmap for the container
+-------------------------------------------------*/
+
+void render_container_set_overlay(render_container *container, mame_bitmap *bitmap)
+{
+ /* free any existing texture */
+ if (container->overlaytexture != NULL)
+ render_texture_free(container->overlaytexture);
+
+ /* set the new data and allocate the texture */
+ container->overlaybitmap = bitmap;
+ if (container->overlaybitmap != NULL)
+ {
+ container->overlaytexture = render_texture_alloc(render_container_overlay_scale, NULL);
+ render_texture_set_bitmap(container->overlaytexture, bitmap, NULL, 0, TEXFORMAT_ARGB32);
+ }
+}
+
+
+/*-------------------------------------------------
+ render_container_get_ui - return a pointer
+ to the UI container
+-------------------------------------------------*/
+
+render_container *render_container_get_ui(void)
+{
+ return ui_container;
+}
+
+
+/*-------------------------------------------------
+ render_container_get_screen - return a pointer
+ to the indexed screen container
+-------------------------------------------------*/
+
+render_container *render_container_get_screen(int screen)
+{
+ return screen_container[screen];
+}
+
+
+/*-------------------------------------------------
+ render_container_set_palette_alpha - set the
+ opacity of a given palette entry
+-------------------------------------------------*/
+
+void render_container_set_palette_alpha(render_container *container, UINT32 entry, UINT8 alpha)
+{
+ assert(entry < ARRAY_LENGTH(container->bcglookup));
+ container->bcglookup[entry] = (alpha << 24) | (container->bcglookup[entry] & 0x00ffffff);
+}
+
+
+/*-------------------------------------------------
+ render_container_item_add_generic - add a
+ generic item to a container
+-------------------------------------------------*/
+
+static container_item *render_container_item_add_generic(render_container *container, UINT8 type, float x0, float y0, float x1, float y1, rgb_t argb)
+{
+ container_item *item = alloc_container_item();
+
+ assert(container != NULL);
+
+ /* copy the data into the new item */
+ item->type = type;
+ item->bounds.x0 = x0;
+ item->bounds.y0 = y0;
+ item->bounds.x1 = x1;
+ item->bounds.y1 = y1;
+ item->color.r = (float)RGB_RED(argb) * (1.0f / 255.0f);
+ item->color.g = (float)RGB_GREEN(argb) * (1.0f / 255.0f);
+ item->color.b = (float)RGB_BLUE(argb) * (1.0f / 255.0f);
+ item->color.a = (float)RGB_ALPHA(argb) * (1.0f / 255.0f);
+
+ /* add the item to the container */
+ *container->nextitem = item;
+ container->nextitem = &item->next;
+
+ return item;
+}
+
+
+/*-------------------------------------------------
+ render_container_add_line - add a line item
+ to the specified container
+-------------------------------------------------*/
+
+void render_container_add_line(render_container *container, float x0, float y0, float x1, float y1, float width, rgb_t argb, UINT32 flags)
+{
+ container_item *item = render_container_item_add_generic(container, CONTAINER_ITEM_LINE, x0, y0, x1, y1, argb);
+ item->width = width;
+ item->flags = flags;
+}
+
+
+/*-------------------------------------------------
+ render_container_add_quad - add a quad item
+ to the specified container
+-------------------------------------------------*/
+
+void render_container_add_quad(render_container *container, float x0, float y0, float x1, float y1, rgb_t argb, render_texture *texture, UINT32 flags)
+{
+ container_item *item = render_container_item_add_generic(container, CONTAINER_ITEM_QUAD, x0, y0, x1, y1, argb);
+ item->texture = texture;
+ item->flags = flags;
+}
+
+
+/*-------------------------------------------------
+ render_container_add_char - add a char item
+ to the specified container
+-------------------------------------------------*/
+
+void render_container_add_char(render_container *container, float x0, float y0, float height, float aspect, rgb_t argb, render_font *font, UINT16 ch)
+{
+ render_texture *texture;
+ render_bounds bounds;
+ container_item *item;
+
+ /* compute the bounds of the character cell and get the texture */
+ bounds.x0 = x0;
+ bounds.y0 = y0;
+ texture = render_font_get_char_texture_and_bounds(font, height, aspect, ch, &bounds);
+
+ /* add it like a quad */
+ item = render_container_item_add_generic(container, CONTAINER_ITEM_QUAD, bounds.x0, bounds.y0, bounds.x1, bounds.y1, argb);
+ item->texture = texture;
+ item->flags = PRIMFLAG_TEXORIENT(ROT0) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
+ item->internal = INTERNAL_FLAG_CHAR;
+}
+
+
+/*-------------------------------------------------
+ render_container_overlay_scale - scaler for
+ an overlay
+-------------------------------------------------*/
+
+static void render_container_overlay_scale(mame_bitmap *dest, const mame_bitmap *source, const rectangle *sbounds, void *param)
+{
+ int x, y;
+
+ /* simply replicate the source bitmap over the target */
+ for (y = 0; y < dest->height; y++)
+ {
+ UINT32 *src = (UINT32 *)source->base + (y % source->height) * source->rowpixels;
+ UINT32 *dst = (UINT32 *)dest->base + y * dest->rowpixels;
+ int sx = 0;
+
+ /* loop over columns */
+ for (x = 0; x < dest->width; x++)
+ {
+ *dst++ = src[sx++];
+ if (sx >= source->width)
+ sx = 0;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ render_container_recompute_lookups - recompute
+ the lookup table for the render container
+-------------------------------------------------*/
+
+static void render_container_recompute_lookups(render_container *container)
+{
+ int i;
+
+ /* recompute the 256 entry lookup table */
+ for (i = 0; i < 0x100; i++)
+ {
+ UINT8 adjustedval = apply_brightness_contrast_gamma(i, container->brightness, container->contrast, container->gamma);
+ container->bcglookup256[i + 0x000] = adjustedval << 0;
+ container->bcglookup256[i + 0x100] = adjustedval << 8;
+ container->bcglookup256[i + 0x200] = adjustedval << 16;
+ container->bcglookup256[i + 0x300] = adjustedval << 24;
+ }
+
+ /* recompute the 32 entry lookup table */
+ for (i = 0; i < 0x20; i++)
+ {
+ UINT8 adjustedval = apply_brightness_contrast_gamma(pal5bit(i), container->brightness, container->contrast, container->gamma);
+ container->bcglookup32[i + 0x000] = adjustedval << 0;
+ container->bcglookup32[i + 0x020] = adjustedval << 8;
+ container->bcglookup32[i + 0x040] = adjustedval << 16;
+ container->bcglookup32[i + 0x060] = adjustedval << 24;
+ }
+
+ /* recompute the palette entries */
+ if (container->palclient != NULL)
+ {
+ palette_t *palette = palette_client_get_palette(container->palclient);
+ const pen_t *adjusted_palette = palette_entry_list_adjusted(palette);
+ int colors = palette_get_num_colors(palette) * palette_get_num_groups(palette);
+
+ for (i = 0; i < colors; i++)
+ {
+ pen_t newval = adjusted_palette[i];
+ container->bcglookup[i] = (container->bcglookup[i] & 0xff000000) |
+ container->bcglookup256[0x200 + RGB_RED(newval)] |
+ container->bcglookup256[0x100 + RGB_GREEN(newval)] |
+ container->bcglookup256[0x000 + RGB_BLUE(newval)];
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ render_container_update_palette - update
+ any dirty palette entries
+-------------------------------------------------*/
+
+static void render_container_update_palette(render_container *container)
+{
+ UINT32 mindirty, maxdirty;
+ const UINT32 *dirty;
+
+ /* skip if no client */
+ if (container->palclient == NULL)
+ return;
+
+ /* get the dirty list */
+ dirty = palette_client_get_dirty_list(container->palclient, &mindirty, &maxdirty);
+
+ /* iterate over dirty items and update them */
+ if (dirty != NULL)
+ {
+ palette_t *palette = palette_client_get_palette(container->palclient);
+ const pen_t *adjusted_palette = palette_entry_list_adjusted(palette);
+ UINT32 entry32, entry;
+
+ /* loop over chunks of 32 entries, since we can quickly examine 32 at a time */
+ for (entry32 = mindirty / 32; entry32 <= maxdirty / 32; entry32++)
+ {
+ UINT32 dirtybits = dirty[entry32];
+ if (dirtybits != 0)
+
+ /* this chunk of 32 has dirty entries; fix them up */
+ for (entry = 0; entry < 32; entry++)
+ if (dirtybits & (1 << entry))
+ {
+ UINT32 finalentry = entry32 * 32 + entry;
+ rgb_t newval = adjusted_palette[finalentry];
+ container->bcglookup[finalentry] = (container->bcglookup[finalentry] & 0xff000000) |
+ container->bcglookup256[0x200 + RGB_RED(newval)] |
+ container->bcglookup256[0x100 + RGB_GREEN(newval)] |
+ container->bcglookup256[0x000 + RGB_BLUE(newval)];
+ }
+ }
+ }
+}
diff --git a/src/emu/render.h b/src/emu/render.h
new file mode 100644
index 00000000000..c86f4c62e14
--- /dev/null
+++ b/src/emu/render.h
@@ -0,0 +1,478 @@
+/***************************************************************************
+
+ render.h
+
+ Core rendering routines for MAME.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __RENDER_H__
+#define __RENDER_H__
+
+#include "driver.h"
+#include "osdepend.h"
+
+#include <math.h>
+
+
+
+/***************************************************************************
+
+ Theory of operation
+ -------------------
+
+ A render "target" is described by 5 parameters:
+
+ - width = width, in pixels
+ - height = height, in pixels
+ - bpp = depth, in bits per pixel
+ - orientation = orientation of the target
+ - pixel_aspect = aspect ratio of the pixels
+
+ Width, height, and bpp are self-explanatory. The remaining parameters
+ need some additional explanation.
+
+ Regarding orientation, there are three orientations that need to be
+ dealt with: target orientation, UI orientation, and game orientation.
+ In the current model, the UI orientation tracks the target orientation
+ so that the UI is (in theory) facing the correct direction. The game
+ orientation is specified by the game driver and indicates how the
+ game and artwork are rotated.
+
+ Regarding pixel_aspect, this is the aspect ratio of the individual
+ pixels, not the aspect ratio of the screen. You can determine this by
+ dividing the aspect ratio of the screen by the aspect ratio of the
+ resolution. For example, a 4:3 screen displaying 640x480 gives a
+ pixel aspect ratio of (4/3)/(640/480) = 1.0, meaning the pixels are
+ square. That same screen displaying 1280x1024 would have a pixel
+ aspect ratio of (4/3)/(1280/1024) = 1.06666, meaning the pixels are
+ slightly wider than they are tall.
+
+ Artwork is always assumed to be a 1.0 pixel aspect ratio. The game
+ screens themselves can be variable aspect ratios.
+
+***************************************************************************/
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* render primitive types */
+enum
+{
+ RENDER_PRIMITIVE_LINE, /* a single line */
+ RENDER_PRIMITIVE_QUAD /* a rectilinear quad */
+};
+
+
+/* render creation flags */
+#define RENDER_CREATE_NO_ART 0x01 /* ignore any views that have art in them */
+#define RENDER_CREATE_SINGLE_FILE 0x02 /* only load views from the file specified */
+#define RENDER_CREATE_HIDDEN 0x04 /* don't make this target visible */
+
+/* layer config masks */
+#define LAYER_CONFIG_ENABLE_BACKDROP 0x01 /* enable backdrop layers */
+#define LAYER_CONFIG_ENABLE_OVERLAY 0x02 /* enable overlay layers */
+#define LAYER_CONFIG_ENABLE_BEZEL 0x04 /* enable bezel layers */
+#define LAYER_CONFIG_ZOOM_TO_SCREEN 0x08 /* zoom to screen area by default */
+#define LAYER_CONFIG_ENABLE_SCREEN_OVERLAY 0x10 /* enable screen overlays */
+
+#define LAYER_CONFIG_DEFAULT (LAYER_CONFIG_ENABLE_BACKDROP | \
+ LAYER_CONFIG_ENABLE_OVERLAY | \
+ LAYER_CONFIG_ENABLE_BEZEL | \
+ LAYER_CONFIG_ENABLE_SCREEN_OVERLAY)
+
+/* texture formats */
+#define TEXFORMAT_UNDEFINED 0 /* require a format to be specified */
+#define TEXFORMAT_PALETTE16 1 /* 16bpp palettized, alpha ignored */
+#define TEXFORMAT_PALETTEA16 2 /* 16bpp palettized, alpha respected */
+#define TEXFORMAT_RGB15 3 /* 16bpp 5-5-5 RGB */
+#define TEXFORMAT_RGB32 4 /* 32bpp 8-8-8 RGB */
+#define TEXFORMAT_ARGB32 5 /* 32bpp 8-8-8-8 ARGB */
+#define TEXFORMAT_YUY16 6 /* 16bpp 8-8 Y/Cb, Y/Cr in sequence */
+
+/* blending modes */
+#define BLENDMODE_NONE 0 /* no blending */
+#define BLENDMODE_ALPHA 1 /* standard alpha blend */
+#define BLENDMODE_RGB_MULTIPLY 2 /* apply source alpha to source pix, then multiply RGB values */
+#define BLENDMODE_ADD 3 /* apply source alpha to source pix, then add to destination */
+
+
+/* flags for primitives */
+#define PRIMFLAG_TEXORIENT_SHIFT 0
+#define PRIMFLAG_TEXORIENT_MASK (15 << PRIMFLAG_TEXORIENT_SHIFT)
+#define PRIMFLAG_TEXORIENT(x) ((x) << PRIMFLAG_TEXORIENT_SHIFT)
+#define PRIMFLAG_GET_TEXORIENT(x) (((x) & PRIMFLAG_TEXORIENT_MASK) >> PRIMFLAG_TEXORIENT_SHIFT)
+
+#define PRIMFLAG_TEXFORMAT_SHIFT 4
+#define PRIMFLAG_TEXFORMAT_MASK (15 << PRIMFLAG_TEXFORMAT_SHIFT)
+#define PRIMFLAG_TEXFORMAT(x) ((x) << PRIMFLAG_TEXFORMAT_SHIFT)
+#define PRIMFLAG_GET_TEXFORMAT(x) (((x) & PRIMFLAG_TEXFORMAT_MASK) >> PRIMFLAG_TEXFORMAT_SHIFT)
+
+#define PRIMFLAG_BLENDMODE_SHIFT 8
+#define PRIMFLAG_BLENDMODE_MASK (15 << PRIMFLAG_BLENDMODE_SHIFT)
+#define PRIMFLAG_BLENDMODE(x) ((x) << PRIMFLAG_BLENDMODE_SHIFT)
+#define PRIMFLAG_GET_BLENDMODE(x) (((x) & PRIMFLAG_BLENDMODE_MASK) >> PRIMFLAG_BLENDMODE_SHIFT)
+
+#define PRIMFLAG_ANTIALIAS_SHIFT 12
+#define PRIMFLAG_ANTIALIAS_MASK (1 << PRIMFLAG_ANTIALIAS_SHIFT)
+#define PRIMFLAG_ANTIALIAS(x) ((x) << PRIMFLAG_ANTIALIAS_SHIFT)
+#define PRIMFLAG_GET_ANTIALIAS(x) (((x) & PRIMFLAG_ANTIALIAS_MASK) >> PRIMFLAG_ANTIALIAS_SHIFT)
+
+#define PRIMFLAG_SCREENTEX_SHIFT 13
+#define PRIMFLAG_SCREENTEX_MASK (1 << PRIMFLAG_SCREENTEX_SHIFT)
+#define PRIMFLAG_SCREENTEX(x) ((x) << PRIMFLAG_SCREENTEX_SHIFT)
+#define PRIMFLAG_GET_SCREENTEX(x) (((x) & PRIMFLAG_SCREENTEX_MASK) >> PRIMFLAG_SCREENTEX_SHIFT)
+
+#define PRIMFLAG_TEXWRAP_SHIFT 14
+#define PRIMFLAG_TEXWRAP_MASK (1 << PRIMFLAG_TEXWRAP_SHIFT)
+#define PRIMFLAG_TEXWRAP(x) ((x) << PRIMFLAG_TEXWRAP_SHIFT)
+#define PRIMFLAG_GET_TEXWRAP(x) (((x) & PRIMFLAG_TEXWRAP_MASK) >> PRIMFLAG_TEXWRAP_SHIFT)
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* convenience macros for adding items to the UI container */
+#define render_ui_add_point(x0,y0,diam,argb,flags) render_container_add_line(render_container_get_ui(), x0, y0, x0, y0, diam, argb, flags)
+#define render_ui_add_line(x0,y0,x1,y1,diam,argb,flags) render_container_add_line(render_container_get_ui(), x0, y0, x1, y1, diam, argb, flags)
+#define render_ui_add_rect(x0,y0,x1,y1,argb,flags) render_container_add_quad(render_container_get_ui(), x0, y0, x1, y1, argb, NULL, flags)
+#define render_ui_add_quad(x0,y0,x1,y1,argb,tex,flags) render_container_add_quad(render_container_get_ui(), x0, y0, x1, y1, argb, tex, flags)
+#define render_ui_add_char(x0,y0,ht,asp,argb,font,ch) render_container_add_char(render_container_get_ui(), x0, y0, ht, asp, argb, font, ch)
+
+/* convenience macros for adding items to a screen container */
+#define render_screen_add_point(scr,x0,y0,diam,argb,flags) render_container_add_line(render_container_get_screen(scr), x0, y0, x0, y0, diam, argb, flags)
+#define render_screen_add_line(scr,x0,y0,x1,y1,diam,argb,flags) render_container_add_line(render_container_get_screen(scr), x0, y0, x1, y1, diam, argb, flags)
+#define render_screen_add_rect(scr,x0,y0,x1,y1,argb,flags) render_container_add_quad(render_container_get_screen(scr), x0, y0, x1, y1, argb, NULL, flags)
+#define render_screen_add_quad(scr,x0,y0,x1,y1,argb,tex,flags) render_container_add_quad(render_container_get_screen(scr), x0, y0, x1, y1, argb, tex, flags)
+#define render_screen_add_char(scr,x0,y0,ht,asp,argb,font,ch) render_container_add_char(render_container_get_screen(scr), x0, y0, ht, asp, argb, font, ch)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ callbacks
+-------------------------------------------------*/
+
+/* texture scaling callback */
+typedef void (*texture_scaler)(mame_bitmap *dest, const mame_bitmap *source, const rectangle *sbounds, void *param);
+
+
+
+/*-------------------------------------------------
+ opaque types
+-------------------------------------------------*/
+
+typedef struct _render_container render_container;
+typedef struct _render_target render_target;
+typedef struct _render_texture render_texture;
+typedef struct _render_font render_font;
+typedef struct _render_ref render_ref;
+
+
+
+/*-------------------------------------------------
+ render_bounds - floating point bounding
+ rectangle
+-------------------------------------------------*/
+
+typedef struct _render_bounds render_bounds;
+struct _render_bounds
+{
+ float x0; /* leftmost X coordinate */
+ float y0; /* topmost Y coordinate */
+ float x1; /* rightmost X coordinate */
+ float y1; /* bottommost Y coordinate */
+};
+
+
+/*-------------------------------------------------
+ render_color - floating point set of ARGB
+ values
+-------------------------------------------------*/
+
+typedef struct _render_color render_color;
+struct _render_color
+{
+ float a; /* alpha component (0.0 = transparent, 1.0 = opaque) */
+ float r; /* red component (0.0 = none, 1.0 = max) */
+ float g; /* green component (0.0 = none, 1.0 = max) */
+ float b; /* blue component (0.0 = none, 1.0 = max) */
+};
+
+
+/*-------------------------------------------------
+ render_texuv - floating point set of UV
+ texture coordinates
+-------------------------------------------------*/
+
+typedef struct _render_texuv render_texuv;
+struct _render_texuv
+{
+ float u; /* U coodinate (0.0-1.0) */
+ float v; /* V coordinate (0.0-1.0) */
+};
+
+
+/*-------------------------------------------------
+ render_quad_texuv - floating point set of UV
+ texture coordinates
+-------------------------------------------------*/
+
+typedef struct _render_quad_texuv render_quad_texuv;
+struct _render_quad_texuv
+{
+ render_texuv tl; /* top-left UV coordinate */
+ render_texuv tr; /* top-right UV coordinate */
+ render_texuv bl; /* bottom-left UV coordinate */
+ render_texuv br; /* bottom-right UV coordinate */
+};
+
+
+/*-------------------------------------------------
+ render_texinfo - texture information
+-------------------------------------------------*/
+
+typedef struct _render_texinfo render_texinfo;
+struct _render_texinfo
+{
+ void * base; /* base of the data */
+ UINT32 rowpixels; /* pixels per row */
+ UINT32 width; /* width of the image */
+ UINT32 height; /* height of the image */
+ const rgb_t * palette; /* palette for PALETTE16 textures, LUTs for RGB15/RGB32 */
+ UINT32 seqid; /* sequence ID */
+};
+
+
+/*-------------------------------------------------
+ render_primitive - a single low-level
+ primitive for the rendering engine
+-------------------------------------------------*/
+
+typedef struct _render_primitive render_primitive;
+struct _render_primitive
+{
+ render_primitive * next; /* pointer to next element */
+ int type; /* type of primitive */
+ render_bounds bounds; /* bounds or positions */
+ render_color color; /* RGBA values */
+ UINT32 flags; /* flags */
+ float width; /* width (for line primitives) */
+ render_texinfo texture; /* texture info (for quad primitives) */
+ render_quad_texuv texcoords; /* texture coordinates (for quad primitives) */
+};
+
+
+/*-------------------------------------------------
+ render_primitive_list - an object containing
+ a list head plus a lock
+-------------------------------------------------*/
+
+typedef struct _render_primitive_list render_primitive_list;
+struct _render_primitive_list
+{
+ render_primitive * head; /* head of the list */
+ render_primitive ** nextptr; /* pointer to the next tail pointer */
+ osd_lock * lock; /* should only should be accessed under this lock */
+ render_ref * reflist; /* list of references */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- core implementation ----- */
+
+/* allocate base structures for the rendering system */
+void render_init(running_machine *machine);
+
+/* set a notifier that we call before doing long scaling operations */
+void render_set_rescale_notify(running_machine *machine, int (*notifier)(running_machine *, int, int));
+
+/* return a bitmask indicating the live screens */
+UINT32 render_get_live_screens_mask(void);
+
+/* return the smallest maximum update rate across all targets */
+float render_get_max_update_rate(void);
+
+/* select the UI target */
+void render_set_ui_target(render_target *target);
+
+/* return the UI target */
+render_target *render_get_ui_target(void);
+
+/* return the aspect ratio for UI fonts */
+float render_get_ui_aspect(void);
+
+
+
+/* ----- render target management ----- */
+
+/* allocate a new render target */
+render_target *render_target_alloc(const char *layout, UINT32 flags);
+
+/* free memory for a render target */
+void render_target_free(render_target *target);
+
+/* get a render_target by index */
+render_target *render_target_get_indexed(int index);
+
+/* return the name of the indexed view, or NULL if it doesn't exist */
+const char *render_target_get_view_name(render_target *target, int viewindex);
+
+/* return a bitmask of which screens are visible on a given view */
+UINT32 render_target_get_view_screens(render_target *target, int viewindex);
+
+/* get the bounds and pixel aspect of a target */
+void render_target_get_bounds(render_target *target, INT32 *width, INT32 *height, float *pixel_aspect);
+
+/* set the bounds and pixel aspect of a target */
+void render_target_set_bounds(render_target *target, INT32 width, INT32 height, float pixel_aspect);
+
+/* get the maximum update rate (refresh rate) of a target, or 0 if no maximum */
+float render_target_get_max_update_rate(render_target *target);
+
+/* set the maximum update rate (refresh rate) of a target, or 0 if no maximum */
+void render_target_set_max_update_rate(render_target *target, float updates_per_second);
+
+/* get the orientation of a target */
+int render_target_get_orientation(render_target *target);
+
+/* set the orientation of a target */
+void render_target_set_orientation(render_target *target, int orientation);
+
+/* get the layer config of a target */
+int render_target_get_layer_config(render_target *target);
+
+/* set the layer config of a target */
+void render_target_set_layer_config(render_target *target, int layerconfig);
+
+/* return the currently selected view index */
+int render_target_get_view(render_target *target);
+
+/* dynamically change the view for a target */
+void render_target_set_view(render_target *target, int viewindex);
+
+/* set the upper bound on the texture size */
+void render_target_set_max_texture_size(render_target *target, int maxwidth, int maxheight);
+
+/* compute the visible area for the given target with the current layout and proposed new parameters */
+void render_target_compute_visible_area(render_target *target, INT32 target_width, INT32 target_height, float target_pixel_aspect, UINT8 target_orientation, INT32 *visible_width, INT32 *visible_height);
+
+/* get the "minimum" size of a target, which is the smallest bounds that will ensure at least
+ 1 target pixel per source pixel for all included screens */
+void render_target_get_minimum_size(render_target *target, INT32 *minwidth, INT32 *minheight);
+
+/* return a list of primitives for a given render target */
+const render_primitive_list *render_target_get_primitives(render_target *target);
+
+
+
+/* ----- render texture management ----- */
+
+/* allocate a new texture */
+render_texture *render_texture_alloc(texture_scaler scaler, void *param);
+
+/* free an allocated texture */
+void render_texture_free(render_texture *texture);
+
+/* set a new source bitmap */
+void render_texture_set_bitmap(render_texture *texture, mame_bitmap *bitmap, const rectangle *sbounds, UINT32 palettebase, int format);
+
+/* generic high quality resampling scaler */
+void render_texture_hq_scale(mame_bitmap *dest, const mame_bitmap *source, const rectangle *sbounds, void *param);
+
+
+
+/* ----- render containers ----- */
+
+/* empty a container in preparation for new stuff */
+void render_container_empty(render_container *container);
+
+/* return true if a container has nothing in it */
+int render_container_is_empty(render_container *container);
+
+/* return the orientation of a container */
+int render_container_get_orientation(render_container *container);
+
+/* set the orientation of a container */
+void render_container_set_orientation(render_container *container, int orientation);
+
+/* return the brightness of a container */
+float render_container_get_brightness(render_container *container);
+
+/* set the brightness of a container */
+void render_container_set_brightness(render_container *container, float brightness);
+
+/* return the contrast of a container */
+float render_container_get_contrast(render_container *container);
+
+/* set the contrast of a container */
+void render_container_set_contrast(render_container *container, float contrast);
+
+/* return the gamma of a container */
+float render_container_get_gamma(render_container *container);
+
+/* set the gamma of a container */
+void render_container_set_gamma(render_container *container, float gamma);
+
+/* return the X scale of a container */
+float render_container_get_xscale(render_container *container);
+
+/* set the X scale of a container */
+void render_container_set_xscale(render_container *container, float xscale);
+
+/* return the Y scale of a container */
+float render_container_get_yscale(render_container *container);
+
+/* set the Y scale of a container */
+void render_container_set_yscale(render_container *container, float yscale);
+
+/* return the X offset of a container */
+float render_container_get_xoffset(render_container *container);
+
+/* set the X offset of a container */
+void render_container_set_xoffset(render_container *container, float xoffset);
+
+/* return the Y offset of a container */
+float render_container_get_yoffset(render_container *container);
+
+/* set the Y offset of a container */
+void render_container_set_yoffset(render_container *container, float yoffset);
+
+/* set the overlay bitmap for the container */
+void render_container_set_overlay(render_container *container, mame_bitmap *bitmap);
+
+/* return a pointer to the UI container */
+render_container *render_container_get_ui(void);
+
+/* return a pointer to the indexed screen container */
+render_container *render_container_get_screen(int screen);
+
+/* set the opacity of a given palette entry */
+void render_container_set_palette_alpha(render_container *container, UINT32 entry, UINT8 alpha);
+
+/* add a line item to the specified container */
+void render_container_add_line(render_container *container, float x0, float y0, float x1, float y1, float width, rgb_t argb, UINT32 flags);
+
+/* add a quad item to the specified container */
+void render_container_add_quad(render_container *container, float x0, float y0, float x1, float y1, rgb_t argb, render_texture *texture, UINT32 flags);
+
+/* add a char item to the specified container */
+void render_container_add_char(render_container *container, float x0, float y0, float height, float aspect, rgb_t argb, render_font *font, UINT16 ch);
+
+
+#endif /* __RENDER_H__ */
diff --git a/src/emu/rendersw.c b/src/emu/rendersw.c
new file mode 100644
index 00000000000..af6f71dd371
--- /dev/null
+++ b/src/emu/rendersw.c
@@ -0,0 +1,1942 @@
+/***************************************************************************
+
+ rendersw.c
+
+ Software-only rasterization system.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ This file is not to be directly compiled. Rather, the OSD code should
+ #define the macros below and then #include this file to generate
+ rasterizers that are optimized for a given output format. See
+ windows/rendsoft.c for an example.
+
+***************************************************************************/
+
+
+
+/***************************************************************************
+ USAGE VERIFICATION
+***************************************************************************/
+
+#if !defined(FUNC_PREFIX)
+#error Must define FUNC_PREFIX!
+#endif
+
+#if !defined(PIXEL_TYPE)
+#error Must define PIXEL_TYPE!
+#endif
+
+#if !defined(SRCSHIFT_R) || !defined(SRCSHIFT_G) || !defined(SRCSHIFT_B)
+#error Must define SRCSHIFT_R/SRCSHIFT_G/SRCSHIFT_B!
+#endif
+
+#if !defined(DSTSHIFT_R) || !defined(DSTSHIFT_G) || !defined(DSTSHIFT_B)
+#error Must define DSTSHIFT_R/DSTSHIFT_G/DSTSHIFT_B!
+#endif
+
+#if !defined(NO_DEST_READ)
+#define NO_DEST_READ 0
+#endif
+
+
+
+/***************************************************************************
+ ONE-TIME-ONLY DEFINITIONS
+***************************************************************************/
+
+#ifndef FIRST_TIME
+#define FIRST_TIME
+
+#include "mamecore.h"
+#include "eminline.h"
+#include "render.h"
+#include <math.h>
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0)
+
+#define Tinten(intensity, col) \
+ MAKE_RGB((RGB_RED(col) * (intensity)) >> 8, (RGB_GREEN(col) * (intensity)) >> 8, (RGB_BLUE(col) * (intensity)) >> 8)
+
+#define IS_OPAQUE(a) (a >= (NO_DEST_READ ? 0.5f : 1.0f))
+#define IS_TRANSPARENT(a) (a < (NO_DEST_READ ? 0.5f : 0.0001f))
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _quad_setup_data quad_setup_data;
+struct _quad_setup_data
+{
+ INT32 dudx, dvdx, dudy, dvdy;
+ INT32 startu, startv;
+ INT32 startx, starty;
+ INT32 endx, endy;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static UINT32 cosine_table[2049];
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE float round_nearest(float f)
+{
+ return floor(f + 0.5f);
+}
+
+
+INLINE UINT32 ycc_to_rgb(UINT8 y, UINT8 cb, UINT8 cr)
+{
+ /* original equations:
+
+ C = Y - 16
+ D = Cb - 128
+ E = Cr - 128
+
+ R = clip(( 298 * C + 409 * E + 128) >> 8)
+ G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
+ B = clip(( 298 * C + 516 * D + 128) >> 8)
+
+ R = clip(( 298 * (Y - 16) + 409 * (Cr - 128) + 128) >> 8)
+ G = clip(( 298 * (Y - 16) - 100 * (Cb - 128) - 208 * (Cr - 128) + 128) >> 8)
+ B = clip(( 298 * (Y - 16) + 516 * (Cb - 128) + 128) >> 8)
+
+ R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8)
+ G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
+ B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8)
+
+ R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8)
+ G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
+ B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8)
+ */
+ int r, g, b, common;
+
+ common = 298 * y - 298 * 16;
+ r = (common + 409 * cr - 409 * 128 + 128) >> 8;
+ g = (common - 100 * cb + 100 * 128 - 208 * cr + 208 * 128 + 128) >> 8;
+ b = (common + 516 * cb - 516 * 128 + 128) >> 8;
+
+ if (r < 0) r = 0;
+ else if (r > 255) r = 255;
+ if (g < 0) g = 0;
+ else if (g > 255) g = 255;
+ if (b < 0) b = 0;
+ else if (b > 255) b = 255;
+
+ return MAKE_RGB(r, g, b);
+}
+
+#endif
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* source 15-bit pixels are in MAME standardized format */
+#define SOURCE15_R(pix) (((pix) >> (7 + SRCSHIFT_R)) & (0xf8 >> SRCSHIFT_R))
+#define SOURCE15_G(pix) (((pix) >> (2 + SRCSHIFT_G)) & (0xf8 >> SRCSHIFT_G))
+#if (SRCSHIFT_B < 3)
+#define SOURCE15_B(pix) (((pix) << (3 - SRCSHIFT_B)) & (0xf8 >> SRCSHIFT_B))
+#else
+#define SOURCE15_B(pix) (((pix) >> (SRCSHIFT_B - 3)) & (0xf8 >> SRCSHIFT_B))
+#endif
+
+/* source 32-bit pixels are in MAME standardized format */
+#define SOURCE32_R(pix) (((pix) >> (16 + SRCSHIFT_R)) & (0xff >> SRCSHIFT_R))
+#define SOURCE32_G(pix) (((pix) >> (8 + SRCSHIFT_G)) & (0xff >> SRCSHIFT_G))
+#define SOURCE32_B(pix) (((pix) >> (0 + SRCSHIFT_B)) & (0xff >> SRCSHIFT_B))
+
+/* destination pixels are written based on the values of the macros */
+#define DEST_ASSEMBLE_RGB(r,g,b) (((r) << DSTSHIFT_R) | ((g) << DSTSHIFT_G) | ((b) << DSTSHIFT_B))
+#define DEST_RGB_TO_PIXEL(r,g,b) DEST_ASSEMBLE_RGB((r) >> SRCSHIFT_R, (g) >> SRCSHIFT_G, (b) >> SRCSHIFT_B)
+
+/* destination pixel masks are based on the macros as well */
+#define DEST_R(pix) (((pix) >> DSTSHIFT_R) & (0xff >> SRCSHIFT_R))
+#define DEST_G(pix) (((pix) >> DSTSHIFT_G) & (0xff >> SRCSHIFT_G))
+#define DEST_B(pix) (((pix) >> DSTSHIFT_B) & (0xff >> SRCSHIFT_B))
+
+/* direct 15-bit source to destination pixel conversion */
+#define SOURCE15_TO_DEST(pix) DEST_ASSEMBLE_RGB(SOURCE15_R(pix), SOURCE15_G(pix), SOURCE15_B(pix))
+#ifndef VARIABLE_SHIFT
+#if (SRCSHIFT_R == 3) && (SRCSHIFT_G == 3) && (SRCSHIFT_B == 3) && (DSTSHIFT_R == 10) && (DSTSHIFT_G == 5) && (DSTSHIFT_B == 0)
+#undef SOURCE15_TO_DEST
+#define SOURCE15_TO_DEST(pix) (pix)
+#endif
+#endif
+
+/* direct 32-bit source to destination pixel conversion */
+#define SOURCE32_TO_DEST(pix) DEST_ASSEMBLE_RGB(SOURCE32_R(pix), SOURCE32_G(pix), SOURCE32_B(pix))
+#ifndef VARIABLE_SHIFT
+#if (SRCSHIFT_R == 0) && (SRCSHIFT_G == 0) && (SRCSHIFT_B == 0) && (DSTSHIFT_R == 16) && (DSTSHIFT_G == 8) && (DSTSHIFT_B == 0)
+#undef SOURCE32_TO_DEST
+#define SOURCE32_TO_DEST(pix) (pix)
+#endif
+#endif
+
+
+
+/***************************************************************************
+ LINE RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ draw_aa_pixel - draw an antialiased pixel
+-------------------------------------------------*/
+
+INLINE void FUNC_PREFIX(draw_aa_pixel)(void *dstdata, UINT32 pitch, int x, int y, rgb_t col)
+{
+ UINT32 dpix, dr, dg, db;
+ PIXEL_TYPE *dest;
+
+ dest = (PIXEL_TYPE *)dstdata + y * pitch + x;
+ dpix = NO_DEST_READ ? 0 : *dest;
+ dr = SOURCE32_R(col) + DEST_R(dpix);
+ dg = SOURCE32_G(col) + DEST_G(dpix);
+ db = SOURCE32_B(col) + DEST_B(dpix);
+ dr = (dr | -(dr >> (8 - SRCSHIFT_R))) & (0xff >> SRCSHIFT_R);
+ dg = (dg | -(dg >> (8 - SRCSHIFT_G))) & (0xff >> SRCSHIFT_G);
+ db = (db | -(db >> (8 - SRCSHIFT_B))) & (0xff >> SRCSHIFT_B);
+ *dest = DEST_ASSEMBLE_RGB(dr, dg, db);
+}
+
+
+/*-------------------------------------------------
+ draw_line - draw a line or point
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_line)(const render_primitive *prim, void *dstdata, INT32 width, INT32 height, UINT32 pitch)
+{
+ int dx,dy,sx,sy,cx,cy,bwidth;
+ UINT8 a1;
+ int x1,x2,y1,y2;
+ UINT32 col;
+ int xx,yy;
+ int beam;
+
+ /* compute the start/end coordinates */
+ x1 = (int)(prim->bounds.x0 * 65536.0f);
+ y1 = (int)(prim->bounds.y0 * 65536.0f);
+ x2 = (int)(prim->bounds.x1 * 65536.0f);
+ y2 = (int)(prim->bounds.y1 * 65536.0f);
+
+ /* handle color and intensity */
+ col = MAKE_RGB((int)(255.0f * prim->color.r * prim->color.a), (int)(255.0f * prim->color.g * prim->color.a), (int)(255.0f * prim->color.b * prim->color.a));
+
+ if (PRIMFLAG_GET_ANTIALIAS(prim->flags))
+ {
+ /* build up the cosine table if we haven't yet */
+ if (cosine_table[0] == 0)
+ {
+ int entry;
+ for (entry = 0; entry <= 2048; entry++)
+ cosine_table[entry] = (int)((double)(1.0 / cos(atan((double)(entry) / 2048.0))) * 0x10000000 + 0.5);
+ }
+
+ beam = prim->width * 65536.0f;
+ if (beam < 0x00010000)
+ beam = 0x00010000;
+
+ /* draw an anti-aliased line */
+ dx = abs(x1 - x2);
+ dy = abs(y1 - y2);
+
+ if (dx >= dy)
+ {
+ sx = ((x1 <= x2) ? 1 : -1);
+ sy = (dy == 0) ? 0 : div_32x32_shift(y2 - y1, dx, 16);
+ if (sy < 0)
+ dy--;
+ x1 >>= 16;
+ xx = x2 >> 16;
+ bwidth = mul_32x32_hi(beam << 4, cosine_table[abs(sy) >> 5]);
+ y1 -= bwidth >> 1; /* start back half the diameter */
+ for (;;)
+ {
+ if (x1 >= 0 && x1 < width)
+ {
+ dx = bwidth; /* init diameter of beam */
+ dy = y1 >> 16;
+ if (dy >= 0 && dy < height)
+ FUNC_PREFIX(draw_aa_pixel)(dstdata, pitch, x1, dy, Tinten(0xff & (~y1 >> 8), col));
+ dy++;
+ dx -= 0x10000 - (0xffff & y1); /* take off amount plotted */
+ a1 = (dx >> 8) & 0xff; /* calc remainder pixel */
+ dx >>= 16; /* adjust to pixel (solid) count */
+ while (dx--) /* plot rest of pixels */
+ {
+ if (dy >= 0 && dy < height)
+ FUNC_PREFIX(draw_aa_pixel)(dstdata, pitch, x1, dy, col);
+ dy++;
+ }
+ if (dy >= 0 && dy < height)
+ FUNC_PREFIX(draw_aa_pixel)(dstdata, pitch, x1, dy, Tinten(a1,col));
+ }
+ if (x1 == xx) break;
+ x1 += sx;
+ y1 += sy;
+ }
+ }
+ else
+ {
+ sy = ((y1 <= y2) ? 1: -1);
+ sx = (dx == 0) ? 0 : div_32x32_shift(x2 - x1, dy, 16);
+ if (sx < 0)
+ dx--;
+ y1 >>= 16;
+ yy = y2 >> 16;
+ bwidth = mul_32x32_hi(beam << 4,cosine_table[abs(sx) >> 5]);
+ x1 -= bwidth >> 1; /* start back half the width */
+ for (;;)
+ {
+ if (y1 >= 0 && y1 < height)
+ {
+ dy = bwidth; /* calc diameter of beam */
+ dx = x1 >> 16;
+ if (dx >= 0 && dx < width)
+ FUNC_PREFIX(draw_aa_pixel)(dstdata, pitch, dx, y1, Tinten(0xff & (~x1 >> 8), col));
+ dx++;
+ dy -= 0x10000 - (0xffff & x1); /* take off amount plotted */
+ a1 = (dy >> 8) & 0xff; /* remainder pixel */
+ dy >>= 16; /* adjust to pixel (solid) count */
+ while (dy--) /* plot rest of pixels */
+ {
+ if (dx >= 0 && dx < width)
+ FUNC_PREFIX(draw_aa_pixel)(dstdata, pitch, dx, y1, col);
+ dx++;
+ }
+ if (dx >= 0 && dx < width)
+ FUNC_PREFIX(draw_aa_pixel)(dstdata, pitch, dx, y1, Tinten(a1, col));
+ }
+ if (y1 == yy) break;
+ y1 += sy;
+ x1 += sx;
+ }
+ }
+ }
+ else /* use good old Bresenham for non-antialiasing 980317 BW */
+ {
+ x1 = (x1 + 0x8000) >> 16;
+ y1 = (y1 + 0x8000) >> 16;
+ x2 = (x2 + 0x8000) >> 16;
+ y2 = (y2 + 0x8000) >> 16;
+
+ 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 >= 0 && x1 < width && y1 >= 0 && y1 < height)
+ FUNC_PREFIX(draw_aa_pixel)(dstdata, pitch, x1, y1, col);
+ if (x1 == x2) break;
+ x1 += sx;
+ cx -= dy;
+ if (cx < 0)
+ {
+ y1 += sy;
+ cx += dx;
+ }
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ if (x1 >= 0 && x1 < width && y1 >= 0 && y1 < height)
+ FUNC_PREFIX(draw_aa_pixel)(dstdata, pitch, x1, y1, col);
+ if (y1 == y2) break;
+ y1 += sy;
+ cy -= dx;
+ if (cy < 0)
+ {
+ x1 += sx;
+ cy += dy;
+ }
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ RECT RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ draw_rect - draw a solid rectangle
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_rect)(const render_primitive *prim, void *dstdata, INT32 width, INT32 height, UINT32 pitch)
+{
+ render_bounds fpos = prim->bounds;
+ INT32 startx, starty, endx, endy;
+ INT32 x, y;
+
+ assert(fpos.x0 <= fpos.x1);
+ assert(fpos.y0 <= fpos.y1);
+
+ /* clamp to integers */
+ startx = round_nearest(fpos.x0);
+ starty = round_nearest(fpos.y0);
+ endx = round_nearest(fpos.x1);
+ endy = round_nearest(fpos.y1);
+
+ /* ensure we fit */
+ if (startx < 0) startx = 0;
+ if (startx >= width) startx = width;
+ if (endx < 0) endx = 0;
+ if (endx >= width) endx = width;
+ if (starty < 0) starty = 0;
+ if (starty >= height) starty = height;
+ if (endy < 0) endy = 0;
+ if (endy >= height) endy = height;
+
+ /* bail if nothing left */
+ if (fpos.x0 > fpos.x1 || fpos.y0 > fpos.y1)
+ return;
+
+ /* only support alpha and "none" blendmodes */
+ assert(PRIMFLAG_GET_BLENDMODE(prim->flags) == BLENDMODE_NONE ||
+ PRIMFLAG_GET_BLENDMODE(prim->flags) == BLENDMODE_ALPHA);
+
+ /* fast case: no alpha */
+ if (PRIMFLAG_GET_BLENDMODE(prim->flags) == BLENDMODE_NONE || IS_OPAQUE(prim->color.a))
+ {
+ UINT32 r = (UINT32)(256.0f * prim->color.r);
+ UINT32 g = (UINT32)(256.0f * prim->color.g);
+ UINT32 b = (UINT32)(256.0f * prim->color.b);
+ UINT32 pix;
+
+ /* clamp R,G,B to 0-256 range */
+ if (r > 0xff) { if ((INT32)r < 0) r = 0; else r = 0xff; }
+ if (g > 0xff) { if ((INT32)g < 0) g = 0; else g = 0xff; }
+ if (b > 0xff) { if ((INT32)b < 0) b = 0; else b = 0xff; }
+ pix = DEST_RGB_TO_PIXEL(r, g, b);
+
+ /* loop over rows */
+ for (y = starty; y < endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + startx;
+
+ /* loop over cols */
+ for (x = startx; x < endx; x++)
+ *dest++ = pix;
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else if (!IS_TRANSPARENT(prim->color.a))
+ {
+ UINT32 rmask = DEST_RGB_TO_PIXEL(0xff,0x00,0x00);
+ UINT32 gmask = DEST_RGB_TO_PIXEL(0x00,0xff,0x00);
+ UINT32 bmask = DEST_RGB_TO_PIXEL(0x00,0x00,0xff);
+ UINT32 r = (UINT32)(256.0f * prim->color.r * prim->color.a);
+ UINT32 g = (UINT32)(256.0f * prim->color.g * prim->color.a);
+ UINT32 b = (UINT32)(256.0f * prim->color.b * prim->color.a);
+ UINT32 inva = (UINT32)(256.0f * (1.0f - prim->color.a));
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (r > 0xff) { if ((INT32)r < 0) r = 0; else r = 0xff; }
+ if (g > 0xff) { if ((INT32)g < 0) g = 0; else g = 0xff; }
+ if (b > 0xff) { if ((INT32)b < 0) b = 0; else b = 0xff; }
+ if (inva > 0x100) { if ((INT32)inva < 0) inva = 0; else inva = 0x100; }
+
+ /* pre-shift the RGBA pieces */
+ r = DEST_RGB_TO_PIXEL(r, 0, 0) << 8;
+ g = DEST_RGB_TO_PIXEL(0, g, 0) << 8;
+ b = DEST_RGB_TO_PIXEL(0, 0, b) << 8;
+
+ /* loop over rows */
+ for (y = starty; y < endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + startx;
+
+ /* loop over cols */
+ for (x = startx; x < endx; x++)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 dr = (r + ((dpix & rmask) * inva)) & (rmask << 8);
+ UINT32 dg = (g + ((dpix & gmask) * inva)) & (gmask << 8);
+ UINT32 db = (b + ((dpix & bmask) * inva)) & (bmask << 8);
+ *dest++ = (dr | dg | db) >> 8;
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ 16-BIT PALETTE RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ draw_quad_palette16_none - perform
+ rasterization of a 16bpp palettized texture
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_quad_palette16_none)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
+{
+ UINT16 *texbase = prim->texture.base;
+ const rgb_t *palbase = prim->texture.palette;
+ UINT32 texrp = prim->texture.rowpixels;
+ INT32 dudx = setup->dudx;
+ INT32 dvdx = setup->dvdx;
+ INT32 endx = setup->endx;
+ INT32 x, y;
+
+ /* ensure all parameters are valid */
+ assert(palbase != NULL);
+
+ /* fast case: no coloring, no alpha */
+ if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
+ {
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = palbase[texbase[(curv >> 16) * texrp + (curu >> 16)]];
+ *dest++ = SOURCE32_TO_DEST(pix);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+
+ /* coloring-only case */
+ else if (IS_OPAQUE(prim->color.a))
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b);
+
+ /* clamp R,G,B to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = palbase[texbase[(curv >> 16) * texrp + (curu >> 16)]];
+ UINT32 r = (SOURCE32_R(pix) * sr) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * sg) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * sb) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else if (!IS_TRANSPARENT(prim->color.a))
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r * prim->color.a);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g * prim->color.a);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b * prim->color.a);
+ UINT32 invsa = (UINT32)(256.0f * (1.0f - prim->color.a));
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+ if (invsa > 0x100) { if ((INT32)invsa < 0) invsa = 0; else invsa = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = palbase[texbase[(curv >> 16) * texrp + (curu >> 16)]];
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = (SOURCE32_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * sb + DEST_B(dpix) * invsa) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ draw_quad_palette16_add - perform
+ rasterization of a 16bpp palettized texture
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_quad_palette16_add)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
+{
+ UINT16 *texbase = prim->texture.base;
+ const rgb_t *palbase = prim->texture.palette;
+ UINT32 texrp = prim->texture.rowpixels;
+ INT32 dudx = setup->dudx;
+ INT32 dvdx = setup->dvdx;
+ INT32 endx = setup->endx;
+ INT32 x, y;
+
+ /* ensure all parameters are valid */
+ assert(palbase != NULL);
+
+ /* fast case: no coloring, no alpha */
+ if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
+ {
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = palbase[texbase[(curv >> 16) * texrp + (curu >> 16)]];
+ if ((pix & 0xffffff) != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = SOURCE32_R(pix) + DEST_R(dpix);
+ UINT32 g = SOURCE32_G(pix) + DEST_G(dpix);
+ UINT32 b = SOURCE32_B(pix) + DEST_B(dpix);
+ r = (r | -(r >> (8 - SRCSHIFT_R))) & (0xff >> SRCSHIFT_R);
+ g = (g | -(g >> (8 - SRCSHIFT_G))) & (0xff >> SRCSHIFT_G);
+ b = (b | -(b >> (8 - SRCSHIFT_B))) & (0xff >> SRCSHIFT_B);
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r * prim->color.a);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g * prim->color.a);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b * prim->color.a);
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = palbase[texbase[(curv >> 16) * texrp + (curu >> 16)]];
+ if ((pix & 0xffffff) != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = ((SOURCE32_R(pix) * sr) >> 8) + DEST_R(dpix);
+ UINT32 g = ((SOURCE32_G(pix) * sg) >> 8) + DEST_G(dpix);
+ UINT32 b = ((SOURCE32_B(pix) * sb) >> 8) + DEST_B(dpix);
+ r = (r | -(r >> (8 - SRCSHIFT_R))) & (0xff >> SRCSHIFT_R);
+ g = (g | -(g >> (8 - SRCSHIFT_G))) & (0xff >> SRCSHIFT_G);
+ b = (b | -(b >> (8 - SRCSHIFT_B))) & (0xff >> SRCSHIFT_B);
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ 16-BIT ALPHA PALETTE RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ draw_quad_palettea16_alpha - perform
+ rasterization using standard alpha blending
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_quad_palettea16_alpha)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
+{
+ UINT16 *texbase = prim->texture.base;
+ const rgb_t *palbase = prim->texture.palette;
+ UINT32 texrp = prim->texture.rowpixels;
+ INT32 dudx = setup->dudx;
+ INT32 dvdx = setup->dvdx;
+ INT32 endx = setup->endx;
+ INT32 x, y;
+
+ /* ensure all parameters are valid */
+ assert(palbase != NULL);
+
+ /* fast case: no coloring, no alpha */
+ if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
+ {
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = palbase[texbase[(curv >> 16) * texrp + (curu >> 16)]];
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 invta = 0x100 - ta;
+ UINT32 r = (SOURCE32_R(pix) * ta + DEST_R(dpix) * invta) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * ta + DEST_G(dpix) * invta) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * ta + DEST_B(dpix) * invta) >> 8;
+
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b);
+ UINT32 sa = (UINT32)(256.0f * prim->color.a);
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+ if (sa > 0x100) { if ((INT32)sa < 0) sa = 0; else sa = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = palbase[texbase[(curv >> 16) * texrp + (curu >> 16)]];
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 invsta = (0x10000 - ta) << 8;
+ UINT32 r = (SOURCE32_R(pix) * sr * ta + DEST_R(dpix) * invsta) >> 24;
+ UINT32 g = (SOURCE32_G(pix) * sg * ta + DEST_G(dpix) * invsta) >> 24;
+ UINT32 b = (SOURCE32_B(pix) * sb * ta + DEST_B(dpix) * invsta) >> 24;
+
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ 16-BIT YUY RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ draw_quad_yuy16_none - perform
+ rasterization of a 16bpp YUY image
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_quad_yuy16_none)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
+{
+ UINT16 *texbase = prim->texture.base;
+ const rgb_t *palbase = prim->texture.palette;
+ UINT32 texrp = prim->texture.rowpixels;
+ INT32 dudx = setup->dudx;
+ INT32 dvdx = setup->dvdx;
+ INT32 endx = setup->endx;
+ INT32 x, y;
+
+ /* fast case: no coloring, no alpha */
+ if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
+ {
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ const UINT16 *spix = &texbase[(curv >> 16) * texrp + (curu >> 17) * 2];
+ UINT32 pix = ycc_to_rgb(spix[(curu >> 16) & 1] >> 8, spix[0], spix[1]);
+ *dest++ = SOURCE32_TO_DEST(pix);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ const UINT16 *spix = &texbase[(curv >> 16) * texrp + (curu >> 17) * 2];
+ UINT32 pix = ycc_to_rgb(palbase[spix[(curu >> 16) & 1] >> 8], spix[0], spix[1]);
+ *dest++ = SOURCE32_TO_DEST(pix);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ /* coloring-only case */
+ else if (IS_OPAQUE(prim->color.a))
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b);
+
+ /* clamp R,G,B to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ const UINT16 *spix = &texbase[(curv >> 16) * texrp + (curu >> 17) * 2];
+ UINT32 pix = ycc_to_rgb(spix[(curu >> 16) & 1] >> 8, spix[0], spix[1]);
+ UINT32 r = (SOURCE32_R(pix) * sr) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * sg) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * sb) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ const UINT16 *spix = &texbase[(curv >> 16) * texrp + (curu >> 17) * 2];
+ UINT32 pix = ycc_to_rgb(palbase[spix[(curu >> 16) & 1] >> 8], spix[0], spix[1]);
+ UINT32 r = (SOURCE32_R(pix) * sr) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * sg) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * sb) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else if (!IS_TRANSPARENT(prim->color.a))
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r * prim->color.a);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g * prim->color.a);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b * prim->color.a);
+ UINT32 invsa = (UINT32)(256.0f * (1.0f - prim->color.a));
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+ if (invsa > 0x100) { if ((INT32)invsa < 0) invsa = 0; else invsa = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ const UINT16 *spix = &texbase[(curv >> 16) * texrp + (curu >> 17) * 2];
+ UINT32 pix = ycc_to_rgb(spix[(curu >> 16) & 1] >> 8, spix[0], spix[1]);
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = (SOURCE32_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * sb + DEST_B(dpix) * invsa) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ const UINT16 *spix = &texbase[(curv >> 16) * texrp + (curu >> 17) * 2];
+ UINT32 pix = ycc_to_rgb(palbase[spix[(curu >> 16) & 1] >> 8], spix[0], spix[1]);
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = (SOURCE32_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * sb + DEST_B(dpix) * invsa) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+ 15-BIT RGB QUAD RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ draw_quad_rgb15 - perform rasterization of
+ a 15bpp RGB texture
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_quad_rgb15)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
+{
+ UINT16 *texbase = prim->texture.base;
+ const rgb_t *palbase = prim->texture.palette;
+ UINT32 texrp = prim->texture.rowpixels;
+ INT32 dudx = setup->dudx;
+ INT32 dvdx = setup->dvdx;
+ INT32 endx = setup->endx;
+ INT32 x, y;
+
+ /* fast case: no coloring, no alpha */
+ if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
+ {
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ *dest++ = SOURCE15_TO_DEST(pix);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 r = palbase[(pix >> 10) & 0x1f] >> SRCSHIFT_R;
+ UINT32 g = palbase[(pix >> 5) & 0x1f] >> SRCSHIFT_G;
+ UINT32 b = palbase[(pix >> 0) & 0x1f] >> SRCSHIFT_B;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ /* coloring-only case */
+ else if (IS_OPAQUE(prim->color.a))
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b);
+
+ /* clamp R,G,B to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 r = (SOURCE15_R(pix) * sr) >> 8;
+ UINT32 g = (SOURCE15_G(pix) * sg) >> 8;
+ UINT32 b = (SOURCE15_B(pix) * sb) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 r = (palbase[(pix >> 10) & 0x1f] * sr) >> (8 + SRCSHIFT_R);
+ UINT32 g = (palbase[(pix >> 5) & 0x1f] * sg) >> (8 + SRCSHIFT_G);
+ UINT32 b = (palbase[(pix >> 0) & 0x1f] * sb) >> (8 + SRCSHIFT_B);
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else if (!IS_TRANSPARENT(prim->color.a))
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r * prim->color.a);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g * prim->color.a);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b * prim->color.a);
+ UINT32 invsa = (UINT32)(256.0f * (1.0f - prim->color.a));
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+ if (invsa > 0x100) { if ((INT32)invsa < 0) invsa = 0; else invsa = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = (SOURCE15_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
+ UINT32 g = (SOURCE15_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
+ UINT32 b = (SOURCE15_B(pix) * sb + DEST_B(dpix) * invsa) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = ((palbase[(pix >> 10) & 0x1f] >> SRCSHIFT_R) * sr + DEST_R(dpix) * invsa) >> 8;
+ UINT32 g = ((palbase[(pix >> 5) & 0x1f] >> SRCSHIFT_G) * sg + DEST_G(dpix) * invsa) >> 8;
+ UINT32 b = ((palbase[(pix >> 0) & 0x1f] >> SRCSHIFT_B) * sb + DEST_B(dpix) * invsa) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ 32-BIT RGB QUAD RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ draw_quad_rgb32 - perform rasterization of
+ a 32bpp RGB texture
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_quad_rgb32)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
+{
+ UINT32 *texbase = prim->texture.base;
+ const rgb_t *palbase = prim->texture.palette;
+ UINT32 texrp = prim->texture.rowpixels;
+ INT32 dudx = setup->dudx;
+ INT32 dvdx = setup->dvdx;
+ INT32 endx = setup->endx;
+ INT32 x, y;
+
+ /* fast case: no coloring, no alpha */
+ if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
+ {
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ *dest++ = SOURCE32_TO_DEST(pix);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 r = palbase[(pix >> 16) & 0xff] >> SRCSHIFT_R;
+ UINT32 g = palbase[(pix >> 8) & 0xff] >> SRCSHIFT_G;
+ UINT32 b = palbase[(pix >> 0) & 0xff] >> SRCSHIFT_B;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ /* coloring-only case */
+ else if (IS_OPAQUE(prim->color.a))
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b);
+
+ /* clamp R,G,B to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 r = (SOURCE32_R(pix) * sr) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * sg) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * sb) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 r = (palbase[(pix >> 16) & 0xff] * sr) >> (8 + SRCSHIFT_R);
+ UINT32 g = (palbase[(pix >> 8) & 0xff] * sg) >> (8 + SRCSHIFT_G);
+ UINT32 b = (palbase[(pix >> 0) & 0xff] * sb) >> (8 + SRCSHIFT_B);
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else if (!IS_TRANSPARENT(prim->color.a))
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r * prim->color.a);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g * prim->color.a);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b * prim->color.a);
+ UINT32 invsa = (UINT32)(256.0f * (1.0f - prim->color.a));
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+ if (invsa > 0x100) { if ((INT32)invsa < 0) invsa = 0; else invsa = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = (SOURCE32_R(pix) * sr + DEST_R(dpix) * invsa) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * sg + DEST_G(dpix) * invsa) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * sb + DEST_B(dpix) * invsa) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] >> SRCSHIFT_R) * sr + DEST_R(dpix) * invsa) >> 8;
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] >> SRCSHIFT_G) * sg + DEST_G(dpix) * invsa) >> 8;
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] >> SRCSHIFT_B) * sb + DEST_B(dpix) * invsa) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ 32-BIT ARGB QUAD RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ draw_quad_argb32_alpha - perform
+ rasterization using standard alpha blending
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_quad_argb32_alpha)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
+{
+ UINT32 *texbase = prim->texture.base;
+ const rgb_t *palbase = prim->texture.palette;
+ UINT32 texrp = prim->texture.rowpixels;
+ INT32 dudx = setup->dudx;
+ INT32 dvdx = setup->dvdx;
+ INT32 endx = setup->endx;
+ INT32 x, y;
+
+ /* fast case: no coloring, no alpha */
+ if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
+ {
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 invta = 0x100 - ta;
+ UINT32 r = (SOURCE32_R(pix) * ta + DEST_R(dpix) * invta) >> 8;
+ UINT32 g = (SOURCE32_G(pix) * ta + DEST_G(dpix) * invta) >> 8;
+ UINT32 b = (SOURCE32_B(pix) * ta + DEST_B(dpix) * invta) >> 8;
+
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 invta = 0x100 - ta;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] >> SRCSHIFT_R) * ta + DEST_R(dpix) * invta) >> 8;
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] >> SRCSHIFT_G) * ta + DEST_G(dpix) * invta) >> 8;
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] >> SRCSHIFT_B) * ta + DEST_B(dpix) * invta) >> 8;
+
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b);
+ UINT32 sa = (UINT32)(256.0f * prim->color.a);
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+ if (sa > 0x100) { if ((INT32)sa < 0) sa = 0; else sa = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 invsta = (0x10000 - ta) << 8;
+ UINT32 r = (SOURCE32_R(pix) * sr * ta + DEST_R(dpix) * invsta) >> 24;
+ UINT32 g = (SOURCE32_G(pix) * sg * ta + DEST_G(dpix) * invsta) >> 24;
+ UINT32 b = (SOURCE32_B(pix) * sb * ta + DEST_B(dpix) * invsta) >> 24;
+
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 invsta = (0x10000 - ta) << 8;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] >> SRCSHIFT_R) * sr * ta + DEST_R(dpix) * invsta) >> 24;
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] >> SRCSHIFT_G) * sg * ta + DEST_G(dpix) * invsta) >> 24;
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] >> SRCSHIFT_B) * sb * ta + DEST_B(dpix) * invsta) >> 24;
+
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ draw_quad_argb32_multiply - perform
+ rasterization using RGB multiply
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_quad_argb32_multiply)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
+{
+ UINT32 *texbase = prim->texture.base;
+ const rgb_t *palbase = prim->texture.palette;
+ UINT32 texrp = prim->texture.rowpixels;
+ INT32 dudx = setup->dudx;
+ INT32 dvdx = setup->dvdx;
+ INT32 endx = setup->endx;
+ INT32 x, y;
+
+ /* simply can't do this without reading from the dest */
+ if (NO_DEST_READ)
+ return;
+
+ /* fast case: no coloring, no alpha */
+ if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
+ {
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = (SOURCE32_R(pix) * DEST_R(dpix)) >> (8 - SRCSHIFT_R);
+ UINT32 g = (SOURCE32_G(pix) * DEST_G(dpix)) >> (8 - SRCSHIFT_G);
+ UINT32 b = (SOURCE32_B(pix) * DEST_B(dpix)) >> (8 - SRCSHIFT_B);
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = (palbase[(pix >> 16) & 0xff] * DEST_R(dpix)) >> 8;
+ UINT32 g = (palbase[(pix >> 8) & 0xff] * DEST_G(dpix)) >> 8;
+ UINT32 b = (palbase[(pix >> 0) & 0xff] * DEST_B(dpix)) >> 8;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r * prim->color.a);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g * prim->color.a);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b * prim->color.a);
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = (SOURCE32_R(pix) * sr * DEST_R(dpix)) >> (16 - SRCSHIFT_R);
+ UINT32 g = (SOURCE32_G(pix) * sg * DEST_G(dpix)) >> (16 - SRCSHIFT_G);
+ UINT32 b = (SOURCE32_B(pix) * sb * DEST_B(dpix)) >> (16 - SRCSHIFT_B);
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = (palbase[(pix >> 16) & 0xff] * sr * DEST_R(dpix)) >> 16;
+ UINT32 g = (palbase[(pix >> 8) & 0xff] * sg * DEST_G(dpix)) >> 16;
+ UINT32 b = (palbase[(pix >> 0) & 0xff] * sb * DEST_B(dpix)) >> 16;
+
+ *dest++ = DEST_ASSEMBLE_RGB(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ draw_quad_argb32_add - perform
+ rasterization by using RGB add
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(draw_quad_argb32_add)(const render_primitive *prim, void *dstdata, UINT32 pitch, quad_setup_data *setup)
+{
+ UINT32 *texbase = prim->texture.base;
+ const rgb_t *palbase = prim->texture.palette;
+ UINT32 texrp = prim->texture.rowpixels;
+ INT32 dudx = setup->dudx;
+ INT32 dvdx = setup->dvdx;
+ INT32 endx = setup->endx;
+ INT32 x, y;
+
+ /* simply can't do this without reading from the dest */
+ if (NO_DEST_READ)
+ return;
+
+ /* fast case: no coloring, no alpha */
+ if (prim->color.r >= 1.0f && prim->color.g >= 1.0f && prim->color.b >= 1.0f && IS_OPAQUE(prim->color.a))
+ {
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = ((SOURCE32_R(pix) * ta) >> 8) + DEST_R(dpix);
+ UINT32 g = ((SOURCE32_G(pix) * ta) >> 8) + DEST_G(dpix);
+ UINT32 b = ((SOURCE32_B(pix) * ta) >> 8) + DEST_B(dpix);
+ r = (r | -(r >> (8 - SRCSHIFT_R))) & (0xff >> SRCSHIFT_R);
+ g = (g | -(g >> (8 - SRCSHIFT_G))) & (0xff >> SRCSHIFT_G);
+ b = (b | -(b >> (8 - SRCSHIFT_B))) & (0xff >> SRCSHIFT_B);
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] * ta) >> (8 + SRCSHIFT_R)) + DEST_R(dpix);
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] * ta) >> (8 + SRCSHIFT_G)) + DEST_G(dpix);
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] * ta) >> (8 + SRCSHIFT_B)) + DEST_B(dpix);
+ r = (r | -(r >> (8 - SRCSHIFT_R))) & (0xff >> SRCSHIFT_R);
+ g = (g | -(g >> (8 - SRCSHIFT_G))) & (0xff >> SRCSHIFT_G);
+ b = (b | -(b >> (8 - SRCSHIFT_B))) & (0xff >> SRCSHIFT_B);
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ /* alpha and/or coloring case */
+ else
+ {
+ UINT32 sr = (UINT32)(256.0f * prim->color.r);
+ UINT32 sg = (UINT32)(256.0f * prim->color.g);
+ UINT32 sb = (UINT32)(256.0f * prim->color.b);
+ UINT32 sa = (UINT32)(256.0f * prim->color.a);
+
+ /* clamp R,G,B and inverse A to 0-256 range */
+ if (sr > 0x100) { if ((INT32)sr < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if ((INT32)sg < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if ((INT32)sb < 0) sb = 0; else sb = 0x100; }
+ if (sa > 0x100) { if ((INT32)sa < 0) sa = 0; else sa = 0x100; }
+
+ /* loop over rows */
+ for (y = setup->starty; y < setup->endy; y++)
+ {
+ PIXEL_TYPE *dest = (PIXEL_TYPE *)dstdata + y * pitch + setup->startx;
+ INT32 curu = setup->startu + (y - setup->starty) * setup->dudy;
+ INT32 curv = setup->startv + (y - setup->starty) * setup->dvdy;
+
+ /* no lookup case */
+ if (palbase == NULL)
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = ((SOURCE32_R(pix) * sr * ta) >> 24) + DEST_R(dpix);
+ UINT32 g = ((SOURCE32_G(pix) * sg * ta) >> 24) + DEST_G(dpix);
+ UINT32 b = ((SOURCE32_B(pix) * sb * ta) >> 24) + DEST_B(dpix);
+ r = (r | -(r >> (8 - SRCSHIFT_R))) & (0xff >> SRCSHIFT_R);
+ g = (g | -(g >> (8 - SRCSHIFT_G))) & (0xff >> SRCSHIFT_G);
+ b = (b | -(b >> (8 - SRCSHIFT_B))) & (0xff >> SRCSHIFT_B);
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ /* lookup case */
+ else
+ {
+ /* loop over cols */
+ for (x = setup->startx; x < endx; x++)
+ {
+ UINT32 pix = texbase[(curv >> 16) * texrp + (curu >> 16)];
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = NO_DEST_READ ? 0 : *dest;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] * sr * ta) >> (24 + SRCSHIFT_R)) + DEST_R(dpix);
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] * sr * ta) >> (24 + SRCSHIFT_R)) + DEST_G(dpix);
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] * sr * ta) >> (24 + SRCSHIFT_R)) + DEST_B(dpix);
+ r = (r | -(r >> (8 - SRCSHIFT_R))) & (0xff >> SRCSHIFT_R);
+ g = (g | -(g >> (8 - SRCSHIFT_G))) & (0xff >> SRCSHIFT_G);
+ b = (b | -(b >> (8 - SRCSHIFT_B))) & (0xff >> SRCSHIFT_B);
+ *dest = DEST_ASSEMBLE_RGB(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ CORE QUAD RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ setup_and_draw_textured_quad - perform setup
+ and then dispatch to a texture-mode-specific
+ drawing routine
+-------------------------------------------------*/
+
+static void FUNC_PREFIX(setup_and_draw_textured_quad)(const render_primitive *prim, void *dstdata, INT32 width, INT32 height, UINT32 pitch)
+{
+ float fdudx, fdvdx, fdudy, fdvdy;
+ quad_setup_data setup;
+
+ assert(prim->bounds.x0 <= prim->bounds.x1);
+ assert(prim->bounds.y0 <= prim->bounds.y1);
+
+ /* determine U/V deltas */
+ fdudx = (prim->texcoords.tr.u - prim->texcoords.tl.u) / (prim->bounds.x1 - prim->bounds.x0);
+ fdvdx = (prim->texcoords.tr.v - prim->texcoords.tl.v) / (prim->bounds.x1 - prim->bounds.x0);
+ fdudy = (prim->texcoords.bl.u - prim->texcoords.tl.u) / (prim->bounds.y1 - prim->bounds.y0);
+ fdvdy = (prim->texcoords.bl.v - prim->texcoords.tl.v) / (prim->bounds.y1 - prim->bounds.y0);
+
+ /* clamp to integers */
+ setup.startx = round_nearest(prim->bounds.x0);
+ setup.starty = round_nearest(prim->bounds.y0);
+ setup.endx = round_nearest(prim->bounds.x1);
+ setup.endy = round_nearest(prim->bounds.y1);
+
+ /* ensure we fit */
+ if (setup.startx < 0) setup.startx = 0;
+ if (setup.startx >= width) setup.startx = width;
+ if (setup.endx < 0) setup.endx = 0;
+ if (setup.endx >= width) setup.endx = width;
+ if (setup.starty < 0) setup.starty = 0;
+ if (setup.starty >= height) setup.starty = height;
+ if (setup.endy < 0) setup.endy = 0;
+ if (setup.endy >= height) setup.endy = height;
+
+ /* compute start and delta U,V coordinates now */
+ setup.dudx = round_nearest(65536.0f * (float)prim->texture.width * fdudx);
+ setup.dvdx = round_nearest(65536.0f * (float)prim->texture.height * fdvdx);
+ setup.dudy = round_nearest(65536.0f * (float)prim->texture.width * fdudy);
+ setup.dvdy = round_nearest(65536.0f * (float)prim->texture.height * fdvdy);
+ setup.startu = round_nearest(65536.0f * (float)prim->texture.width * prim->texcoords.tl.u);
+ setup.startv = round_nearest(65536.0f * (float)prim->texture.height * prim->texcoords.tl.v);
+
+ /* advance U/V to the middle of the first pixel */
+ setup.startu += (setup.dudx + setup.dudy) / 2;
+ setup.startv += (setup.dvdx + setup.dvdy) / 2;
+
+ /* render based on the texture coordinates */
+ switch (prim->flags & (PRIMFLAG_TEXFORMAT_MASK | PRIMFLAG_BLENDMODE_MASK))
+ {
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE):
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA):
+ FUNC_PREFIX(draw_quad_palette16_none)(prim, dstdata, pitch, &setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD):
+ FUNC_PREFIX(draw_quad_palette16_add)(prim, dstdata, pitch, &setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTEA16) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA):
+ FUNC_PREFIX(draw_quad_palettea16_alpha)(prim, dstdata, pitch, &setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_YUY16) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE):
+ FUNC_PREFIX(draw_quad_yuy16_none)(prim, dstdata, pitch, &setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB15) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE):
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB15) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA):
+ FUNC_PREFIX(draw_quad_rgb15)(prim, dstdata, pitch, &setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE):
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA):
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE):
+ FUNC_PREFIX(draw_quad_rgb32)(prim, dstdata, pitch, &setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA):
+ FUNC_PREFIX(draw_quad_argb32_alpha)(prim, dstdata, pitch, &setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_RGB_MULTIPLY):
+ FUNC_PREFIX(draw_quad_argb32_multiply)(prim, dstdata, pitch, &setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD):
+ FUNC_PREFIX(draw_quad_argb32_add)(prim, dstdata, pitch, &setup);
+ break;
+
+ default:
+ fatalerror("Unknown texformat(%d)/blendmode(%d) combo\n", PRIMFLAG_GET_TEXFORMAT(prim->flags), PRIMFLAG_GET_BLENDMODE(prim->flags));
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ PRIMARY ENTRY POINT
+***************************************************************************/
+
+/*-------------------------------------------------
+ draw_primitives - draw a series of primitives
+ using a software rasterizer
+-------------------------------------------------*/
+
+void FUNC_PREFIX(draw_primitives)(const render_primitive *primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch)
+{
+ const render_primitive *prim;
+
+ /* loop over the list and render each element */
+ for (prim = primlist; prim != NULL; prim = prim->next)
+ switch (prim->type)
+ {
+ case RENDER_PRIMITIVE_LINE:
+ FUNC_PREFIX(draw_line)(prim, dstdata, width, height, pitch);
+ break;
+
+ case RENDER_PRIMITIVE_QUAD:
+ if (!prim->texture.base)
+ FUNC_PREFIX(draw_rect)(prim, dstdata, width, height, pitch);
+ else
+ FUNC_PREFIX(setup_and_draw_textured_quad)(prim, dstdata, width, height, pitch);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ MACRO UNDOING
+***************************************************************************/
+
+#undef SOURCE15_R
+#undef SOURCE15_G
+#undef SOURCE15_B
+
+#undef SOURCE32_R
+#undef SOURCE32_G
+#undef SOURCE32_B
+
+#undef DEST_ASSEMBLE_RGB
+#undef DEST_RGB_TO_PIXEL
+
+#undef DEST_R
+#undef DEST_G
+#undef DEST_B
+
+#undef SOURCE15_TO_DEST
+#undef SOURCE32_TO_DEST
+
+#undef FUNC_PREFIX
+#undef PIXEL_TYPE
+
+#undef SRCSHIFT_R
+#undef SRCSHIFT_G
+#undef SRCSHIFT_B
+
+#undef DSTSHIFT_R
+#undef DSTSHIFT_G
+#undef DSTSHIFT_B
+
+#undef NO_DEST_READ
+
+#undef VARIABLE_SHIFT
diff --git a/src/emu/rendfont.c b/src/emu/rendfont.c
new file mode 100644
index 00000000000..f20ac9fe63a
--- /dev/null
+++ b/src/emu/rendfont.c
@@ -0,0 +1,853 @@
+/***************************************************************************
+
+ rendfont.c
+
+ Rendering system font management.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "rendfont.h"
+#include "rendutil.h"
+#include "zlib.h"
+
+#include "uismall.fh"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define FONT_FORMAT_TEXT 1
+#define FONT_FORMAT_CACHED 2
+
+#define CACHED_CHAR_SIZE 12
+#define CACHED_HEADER_SIZE 16
+#define CACHED_BDF_HASH_SIZE 1024
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* a render_font contains information about a single character in a font */
+typedef struct _render_font_char render_font_char;
+struct _render_font_char
+{
+ INT32 width; /* width from this character to the next */
+ INT32 xoffs, yoffs; /* X and Y offset from baseline to top,left of bitmap */
+ INT32 bmwidth, bmheight; /* width and height of bitmap */
+ const char * rawdata; /* pointer to the raw data for this one */
+ mame_bitmap * bitmap; /* pointer to the bitmap containing the raw data */
+ render_texture * texture; /* pointer to a texture for rendering and sizing */
+};
+
+
+/* a render_font contains information about a font */
+/*typedef struct _render_font render_font; -- defined in rendfont.h */
+struct _render_font
+{
+ int format; /* format of font data */
+ int height; /* height of the font, from ascent to descent */
+ int yoffs; /* y offset from baseline to descent */
+ float scale; /* 1 / height precomputed */
+ render_font_char * chars[256]; /* array of character subtables */
+ const char * rawdata; /* pointer to the raw data for the font */
+ UINT64 rawsize; /* size of the raw font data */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void render_font_char_expand(render_font *font, render_font_char *ch);
+static int render_font_load_cached_bdf(render_font *font, const char *filename);
+static int render_font_load_bdf(render_font *font);
+static int render_font_load_cached(render_font *font, mame_file *file, UINT32 hash);
+static int render_font_save_cached(render_font *font, const char *filename, UINT32 hash);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ next_line - return a pointer to the start of
+ the next line
+-------------------------------------------------*/
+
+INLINE const char *next_line(const char *ptr)
+{
+ /* scan forward until we hit the end or a carriage return */
+ while (*ptr != 13 && *ptr != 10 && *ptr != 0) ptr++;
+
+ /* if we hit the end, return NULL */
+ if (*ptr == 0)
+ return NULL;
+
+ /* eat the trailing linefeed if present */
+ if (*++ptr == 10)
+ ptr++;
+ return ptr;
+}
+
+
+/*-------------------------------------------------
+ get_char - return a pointer to a character
+ in a font, expanding if necessary
+-------------------------------------------------*/
+
+INLINE render_font_char *get_char(render_font *font, unicode_char chnum)
+{
+ static render_font_char dummy_char;
+ render_font_char *chtable;
+ render_font_char *ch;
+
+ /* grab the table; if none, return the dummy character */
+ chtable = font->chars[chnum / 256];
+ if (chtable == NULL)
+ return &dummy_char;
+
+ /* if the character isn't generated yet, do it now */
+ ch = &chtable[chnum % 256];
+ if (ch->bitmap == NULL)
+ render_font_char_expand(font, ch);
+
+ /* return the resulting character */
+ return ch;
+}
+
+
+
+/***************************************************************************
+ RENDER FONTS
+***************************************************************************/
+
+/*-------------------------------------------------
+ render_font_alloc - allocate a new font
+ and load the BDF file
+-------------------------------------------------*/
+
+render_font *render_font_alloc(const char *filename)
+{
+ file_error filerr;
+ mame_file *ramfile;
+ render_font *font;
+
+ /* allocate and clear memory */
+ font = malloc_or_die(sizeof(*font));
+ memset(font, 0, sizeof(*font));
+
+ /* attempt to load the cached version of the font first */
+ if (filename != NULL && render_font_load_cached_bdf(font, filename) == 0)
+ return font;
+
+ /* if we failed, clean up and realloc */
+ render_font_free(font);
+ font = malloc_or_die(sizeof(*font));
+ memset(font, 0, sizeof(*font));
+
+ /* load the raw data instead */
+ filerr = mame_fopen_ram(font_uismall, sizeof(font_uismall), OPEN_FLAG_READ, &ramfile);
+ if (filerr == FILERR_NONE)
+ {
+ render_font_load_cached(font, ramfile, 0);
+ mame_fclose(ramfile);
+ }
+ return font;
+}
+
+
+/*-------------------------------------------------
+ render_font_free - free an allocated font and
+ all of its owned subobjects
+-------------------------------------------------*/
+
+void render_font_free(render_font *font)
+{
+ int tablenum;
+
+ /* free all the subtables */
+ for (tablenum = 0; tablenum < 256; tablenum++)
+ if (font->chars[tablenum] != NULL)
+ {
+ int charnum;
+
+ /* loop over characters */
+ for (charnum = 0; charnum < 256; charnum++)
+ {
+ render_font_char *ch = &font->chars[tablenum][charnum];
+ if (ch->texture != NULL)
+ render_texture_free(ch->texture);
+ if (ch->bitmap != NULL)
+ bitmap_free(ch->bitmap);
+ }
+
+ /* free the subtable itself */
+ free(font->chars[tablenum]);
+ }
+
+ /* free the raw data and the size itself */
+ if (font->rawdata != NULL)
+ free((void *)font->rawdata);
+ free(font);
+}
+
+
+/*-------------------------------------------------
+ render_font_char_expand - expand the raw data
+ for a character into a bitmap
+-------------------------------------------------*/
+
+static void render_font_char_expand(render_font *font, render_font_char *ch)
+{
+ const char *ptr = ch->rawdata;
+ UINT8 accum = 0, accumbit = 7;
+ int x, y;
+
+ /* punt if nothing there */
+ if (ch->bmwidth == 0 || ch->bmheight == 0 || ch->rawdata == NULL)
+ return;
+
+ /* allocate a new bitmap of the size we need */
+ ch->bitmap = bitmap_alloc(ch->bmwidth, font->height, BITMAP_FORMAT_ARGB32);
+ fillbitmap(ch->bitmap, 0, NULL);
+
+ /* extract the data */
+ for (y = 0; y < ch->bmheight; y++)
+ {
+ int desty = y + font->height + font->yoffs - ch->yoffs - ch->bmheight;
+ UINT32 *dest = (desty >= 0 && desty < font->height) ? BITMAP_ADDR32(ch->bitmap, desty, 0) : NULL;
+
+ /* text format */
+ if (font->format == FONT_FORMAT_TEXT)
+ {
+ /* loop over bytes */
+ for (x = 0; x < ch->bmwidth; x += 4)
+ {
+ int bits = -1;
+
+ /* scan for the next hex digit */
+ while (*ptr != 13 && bits == -1)
+ {
+ if (*ptr >= '0' && *ptr <= '9')
+ bits = *ptr++ - '0';
+ else if (*ptr >= 'A' && *ptr <= 'F')
+ bits = *ptr++ - 'A' + 10;
+ else if (*ptr >= 'a' && *ptr <= 'f')
+ bits = *ptr++ - 'a' + 10;
+ else
+ ptr++;
+ }
+
+ /* expand the four bits */
+ if (dest != NULL)
+ {
+ *dest++ = (bits & 8) ? MAKE_ARGB(0xff,0xff,0xff,0xff) : MAKE_ARGB(0x00,0xff,0xff,0xff);
+ *dest++ = (bits & 4) ? MAKE_ARGB(0xff,0xff,0xff,0xff) : MAKE_ARGB(0x00,0xff,0xff,0xff);
+ *dest++ = (bits & 2) ? MAKE_ARGB(0xff,0xff,0xff,0xff) : MAKE_ARGB(0x00,0xff,0xff,0xff);
+ *dest++ = (bits & 1) ? MAKE_ARGB(0xff,0xff,0xff,0xff) : MAKE_ARGB(0x00,0xff,0xff,0xff);
+ }
+ }
+
+ /* advance to the next line */
+ ptr = next_line(ptr);
+ }
+
+ /* cached format */
+ else if (font->format == FONT_FORMAT_CACHED)
+ {
+ for (x = 0; x < ch->bmwidth; x++)
+ {
+ if (accumbit == 7)
+ accum = *ptr++;
+ if (dest != NULL)
+ *dest++ = (accum & (1 << accumbit)) ? MAKE_ARGB(0xff,0xff,0xff,0xff) : MAKE_ARGB(0x00,0xff,0xff,0xff);
+ accumbit = (accumbit - 1) & 7;
+ }
+ }
+ }
+
+ /* wrap a texture around the bitmap */
+ ch->texture = render_texture_alloc(render_texture_hq_scale, NULL);
+ render_texture_set_bitmap(ch->texture, ch->bitmap, NULL, 0, TEXFORMAT_ARGB32);
+}
+
+
+/*-------------------------------------------------
+ render_font_get_pixel_height - return the
+ height of the font in pixels
+-------------------------------------------------*/
+
+INT32 render_font_get_pixel_height(render_font *font)
+{
+ return font->height;
+}
+
+
+/*-------------------------------------------------
+ render_font_get_char_texture_and_bounds -
+ return the texture for a character and compute
+ the bounds of the final bitmap
+-------------------------------------------------*/
+
+render_texture *render_font_get_char_texture_and_bounds(render_font *font, float height, float aspect, unicode_char chnum, render_bounds *bounds)
+{
+ render_font_char *ch = get_char(font, chnum);
+ float scale = font->scale * height;
+
+ /* on entry, assume x0,y0 are the top,left coordinate of the cell and add */
+ /* the character bounding box to that position */
+ bounds->x0 += (float)ch->xoffs * scale * aspect;
+
+ /* compute x1,y1 from there based on the bitmap size */
+ bounds->x1 = bounds->x0 + (float)ch->bmwidth * scale * aspect;
+ bounds->y1 = bounds->y0 + (float)font->height * scale;
+
+ /* return the texture */
+ return ch->texture;
+}
+
+
+/*-------------------------------------------------
+ render_font_draw_string_to_bitmap - draw a
+ string to a bitmap
+-------------------------------------------------*/
+
+void render_font_get_scaled_bitmap_and_bounds(render_font *font, mame_bitmap *dest, float height, float aspect, unicode_char chnum, rectangle *bounds)
+{
+ render_font_char *ch = get_char(font, chnum);
+ float scale = font->scale * height;
+ INT32 origwidth, origheight;
+
+ /* on entry, assume x0,y0 are the top,left coordinate of the cell and add */
+ /* the character bounding box to that position */
+ bounds->min_x = (float)ch->xoffs * scale * aspect;
+ bounds->min_y = 0;
+
+ /* compute x1,y1 from there based on the bitmap size */
+ bounds->max_x = bounds->min_x + (float)ch->bmwidth * scale * aspect;
+ bounds->max_y = bounds->min_y + (float)font->height * scale;
+
+ /* if the bitmap isn't big enough, bail */
+ if (dest->width < bounds->max_x - bounds->min_x || dest->height < bounds->max_y - bounds->min_y)
+ return;
+
+ /* scale the font */
+ origwidth = dest->width;
+ origheight = dest->height;
+ dest->width = bounds->max_x - bounds->min_x;
+ dest->height = bounds->max_y - bounds->min_y;
+ render_texture_hq_scale(dest, ch->bitmap, NULL, NULL);
+ dest->width = origwidth;
+ dest->height = origheight;
+}
+
+
+/*-------------------------------------------------
+ render_font_char_width - return the width of
+ a character at the given height
+-------------------------------------------------*/
+
+float render_font_get_char_width(render_font *font, float height, float aspect, unicode_char ch)
+{
+ return (float)get_char(font, ch)->width * font->scale * height * aspect;
+}
+
+
+/*-------------------------------------------------
+ render_font_string_width - return the width of
+ a string at the given height
+-------------------------------------------------*/
+
+float render_font_get_string_width(render_font *font, float height, float aspect, const char *string)
+{
+ const unsigned char *ptr;
+ int totwidth = 0;
+
+ /* loop over the string and accumulate widths */
+ for (ptr = (const unsigned char *)string; *ptr != 0; ptr++)
+ totwidth += get_char(font, *ptr)->width;
+
+ /* scale the final result based on height */
+ return (float)totwidth * font->scale * height * aspect;
+}
+
+
+/*-------------------------------------------------
+ render_font_get_utf8string_width - return the
+ width of a UTF8-encoded string at the given
+ height
+-------------------------------------------------*/
+
+float render_font_get_utf8string_width(render_font *font, float height, float aspect, const char *utf8string)
+{
+ int length = strlen(utf8string);
+ unicode_char uchar;
+ int totwidth = 0;
+ int count = 0;
+ int offset;
+
+ /* loop over the string and accumulate widths */
+ for (offset = 0; offset < length; offset += count)
+ {
+ count = uchar_from_utf8(&uchar, utf8string + offset, length - offset);
+ if (count == -1)
+ break;
+ if (uchar < 0x10000)
+ totwidth += get_char(font, uchar)->width;
+ }
+
+ /* scale the final result based on height */
+ return (float)totwidth * font->scale * height * aspect;
+}
+
+
+/*-------------------------------------------------
+ render_font_load_cached_bdf - attempt to load
+ a cached version of the BDF font 'filename';
+ if that fails, fall back on the regular BDF
+ loader and create a new cached version
+-------------------------------------------------*/
+
+static int render_font_load_cached_bdf(render_font *font, const char *filename)
+{
+ file_error filerr;
+ char *cachedname = NULL;
+ char *data = NULL;
+ mame_file *cachefile;
+ mame_file *file;
+ int result = 1;
+ UINT32 bytes;
+ UINT32 hash;
+
+ /* first try to open the BDF itself */
+ filerr = mame_fopen(SEARCHPATH_FONT, filename, OPEN_FLAG_READ, &file);
+ if (filerr != FILERR_NONE)
+ return 1;
+
+ /* determine the file size and allocate memory */
+ font->rawsize = mame_fsize(file);
+ data = malloc_or_die(font->rawsize + 1);
+
+ /* read and hash the first chunk */
+ bytes = mame_fread(file, data, MIN(CACHED_BDF_HASH_SIZE, font->rawsize));
+ if (bytes != MIN(CACHED_BDF_HASH_SIZE, font->rawsize))
+ goto error;
+ hash = crc32(0, (const UINT8*)data, bytes) ^ (UINT32)font->rawsize;
+
+ /* create the cached filename */
+ cachedname = mame_strdup(filename);
+ if (cachedname == NULL)
+ goto error;
+
+ /* change the 'F' to a 'C' on the extension */
+ cachedname[strlen(cachedname) - 1] -= 3;
+
+ /* attempt to load a cached version of the font */
+ filerr = mame_fopen(SEARCHPATH_FONT, cachedname, OPEN_FLAG_READ, &cachefile);
+ if (filerr == FILERR_NONE)
+ {
+ result = render_font_load_cached(font, cachefile, hash);
+ mame_fclose(cachefile);
+ }
+ if (result != 0)
+ {
+ /* if that failed, read the rest of the font and parse it */
+ if (bytes < font->rawsize)
+ {
+ UINT32 read = mame_fread(file, data + bytes, font->rawsize - bytes);
+ if (read != font->rawsize - bytes)
+ goto error;
+ }
+
+ /* NULL-terminate the data and attach it to the font */
+ data[font->rawsize] = 0;
+ font->rawdata = data;
+
+ /* load the BDF */
+ result = render_font_load_bdf(font);
+
+ /* if we loaded okay, create a cached one */
+ if (result == 0)
+ render_font_save_cached(font, cachedname, hash);
+ }
+ else
+ free(data);
+
+ /* close the file */
+ free(cachedname);
+ mame_fclose(file);
+ return result;
+
+error:
+ /* close the file */
+ if (cachedname != NULL)
+ free(cachedname);
+ if (data != NULL)
+ free(data);
+ mame_fclose(file);
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ render_font_load_bdf - parse and load a BDF
+ font
+-------------------------------------------------*/
+
+static int render_font_load_bdf(render_font *font)
+{
+ const char *ptr;
+ int charcount = 0;
+
+ /* set the format to text */
+ font->format = FONT_FORMAT_TEXT;
+
+ /* first find the FONTBOUNDINGBOX tag */
+ for (ptr = font->rawdata; ptr != NULL; ptr = next_line(ptr))
+ {
+ int dummy1, dummy2;
+
+ /* we only care about a tiny few fields */
+ if (strncmp(ptr, "FONTBOUNDINGBOX ", 16) == 0)
+ {
+ if (sscanf(ptr + 16, "%d %d %d %d", &dummy1, &font->height, &dummy2, &font->yoffs) != 4)
+ return 1;
+ break;
+ }
+ }
+
+ /* compute the scale factor */
+ font->scale = 1.0f / (float)font->height;
+
+ /* now scan for characters */
+ for ( ; ptr != NULL; ptr = next_line(ptr))
+ {
+ /* stop at ENDFONT */
+ if (strncmp(ptr, "ENDFONT", 7) == 0)
+ break;
+
+ /* once we hit a STARTCHAR, parse until the end */
+ if (strncmp(ptr, "STARTCHAR ", 10) == 0)
+ {
+ int bmwidth = -1, bmheight = -1, xoffs = -1, yoffs = -1;
+ const char *rawdata = NULL;
+ int charnum = -1;
+ int width = -1;
+ int dummy1;
+
+ /* scan for interesting per-character tags */
+ for ( ; ptr != NULL; ptr = next_line(ptr))
+ {
+ /* ENCODING tells us which character */
+ if (strncmp(ptr, "ENCODING ", 9) == 0)
+ {
+ if (sscanf(ptr + 9, "%d", &charnum) != 1)
+ return 1;
+ }
+
+ /* DWIDTH tells us the width to the next character */
+ else if (strncmp(ptr, "DWIDTH ", 7) == 0)
+ {
+ if (sscanf(ptr + 7, "%d %d", &width, &dummy1) != 2)
+ return 1;
+ }
+
+ /* BBX tells us the height/width of the bitmap and the offsets */
+ else if (strncmp(ptr, "BBX ", 4) == 0)
+ {
+ if (sscanf(ptr + 4, "%d %d %d %d", &bmwidth, &bmheight, &xoffs, &yoffs) != 4)
+ return 1;
+ }
+
+ /* BITMAP is the start of the data */
+ else if (strncmp(ptr, "BITMAP", 6) == 0)
+ {
+ /* stash the raw pointer and scan for the end of the character */
+ for (rawdata = ptr = next_line(ptr); ptr != NULL && strncmp(ptr, "ENDCHAR", 7) != 0; ptr = next_line(ptr)) ;
+ break;
+ }
+ }
+
+ /* if we have everything, allocate a new character */
+ if (charnum >= 0 && charnum < 65536 && rawdata != NULL && bmwidth >= 0 && bmheight >= 0)
+ {
+ render_font_char *ch;
+
+ /* if we don't have a subtable yet, make one */
+ if (font->chars[charnum / 256] == NULL)
+ {
+ font->chars[charnum / 256] = malloc_or_die(256 * sizeof(font->chars[0][0]));
+ memset(font->chars[charnum / 256], 0, 256 * sizeof(font->chars[0][0]));
+ }
+
+ /* fill in the entry */
+ ch = &font->chars[charnum / 256][charnum % 256];
+ ch->width = width;
+ ch->bmwidth = bmwidth;
+ ch->bmheight = bmheight;
+ ch->xoffs = xoffs;
+ ch->yoffs = yoffs;
+ ch->rawdata = rawdata;
+ }
+
+ /* some progress for big fonts */
+ if (++charcount % 256 == 0)
+ mame_printf_warning("Loading BDF font... (%d characters loaded)\n", charcount);
+ }
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ render_font_load_cached - load a font in
+ cached format
+-------------------------------------------------*/
+
+static int render_font_load_cached(render_font *font, mame_file *file, UINT32 hash)
+{
+ UINT8 header[CACHED_HEADER_SIZE];
+ UINT64 offset, filesize;
+ UINT8 *data = NULL;
+ UINT32 bytes_read;
+ int numchars;
+ int chindex;
+
+ /* get the file size */
+ filesize = mame_fsize(file);
+
+ /* first read the header */
+ bytes_read = mame_fread(file, header, CACHED_HEADER_SIZE);
+ if (bytes_read != CACHED_HEADER_SIZE)
+ goto error;
+
+ /* validate the header */
+ if (header[0] != 'f' || header[1] != 'o' || header[2] != 'n' || header[3] != 't')
+ goto error;
+ if (header[4] != (UINT8)(hash >> 24) || header[5] != (UINT8)(hash >> 16) || header[6] != (UINT8)(hash >> 8) || header[7] != (UINT8)hash)
+ goto error;
+ font->height = (header[8] << 8) | header[9];
+ font->scale = 1.0f / (float)font->height;
+ font->yoffs = (INT16)((header[10] << 8) | header[11]);
+ numchars = (header[12] << 24) | (header[13] << 16) | (header[14] << 8) | header[15];
+ if (filesize - CACHED_HEADER_SIZE < numchars * CACHED_CHAR_SIZE)
+ goto error;
+
+ /* now read the rest of the data */
+ data = malloc_or_die(filesize - CACHED_HEADER_SIZE);
+ bytes_read = mame_fread(file, data, filesize - CACHED_HEADER_SIZE);
+ if (bytes_read != filesize - CACHED_HEADER_SIZE)
+ goto error;
+
+ /* extract the data from the data */
+ offset = numchars * CACHED_CHAR_SIZE;
+ for (chindex = 0; chindex < numchars; chindex++)
+ {
+ const UINT8 *info = &data[chindex * CACHED_CHAR_SIZE];
+ int chnum = (info[0] << 8) | info[1];
+ render_font_char *ch;
+
+ /* if we don't have a subtable yet, make one */
+ if (font->chars[chnum / 256] == NULL)
+ {
+ font->chars[chnum / 256] = malloc_or_die(256 * sizeof(font->chars[0][0]));
+ memset(font->chars[chnum / 256], 0, 256 * sizeof(font->chars[0][0]));
+ }
+
+ /* fill in the entry */
+ ch = &font->chars[chnum / 256][chnum % 256];
+ ch->width = (info[2] << 8) | info[3];
+ ch->xoffs = (INT16)((info[4] << 8) | info[5]);
+ ch->yoffs = (INT16)((info[6] << 8) | info[7]);
+ ch->bmwidth = (info[8] << 8) | info[9];
+ ch->bmheight = (info[10] << 8) | info[11];
+ ch->rawdata = (char *)data + offset;
+
+ /* advance the offset past the character */
+ offset += (ch->bmwidth * ch->bmheight + 7) / 8;
+ if (offset > filesize - CACHED_HEADER_SIZE)
+ goto error;
+ }
+
+ /* reuse the chartable as a temporary buffer */
+ font->format = FONT_FORMAT_CACHED;
+ font->rawdata = (char *)data;
+ return 0;
+
+error:
+ if (data != NULL)
+ free(data);
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ render_font_save_cached - save a font in
+ cached format
+-------------------------------------------------*/
+
+static int render_font_save_cached(render_font *font, const char *filename, UINT32 hash)
+{
+ file_error filerr;
+ render_font_char *ch;
+ UINT32 bytes_written;
+ UINT8 *tempbuffer;
+ UINT8 *chartable;
+ mame_file *file;
+ int numchars;
+ UINT8 *dest;
+ int tableindex;
+ int chnum;
+
+ mame_printf_warning("Generating cached BDF font...\n");
+
+ /* attempt to open the file */
+ filerr = mame_fopen(SEARCHPATH_FONT, filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file);
+ if (filerr != FILERR_NONE)
+ return 1;
+
+ /* determine the number of characters */
+ numchars = 0;
+ for (chnum = 0; chnum < 65536; chnum++)
+ {
+ render_font_char *chtable = font->chars[chnum / 256];
+ if (chtable != NULL)
+ {
+ ch = &chtable[chnum % 256];
+ if (ch->width > 0)
+ numchars++;
+ }
+ }
+
+ /* allocate an array to hold the character data */
+ chartable = malloc_or_die(numchars * CACHED_CHAR_SIZE);
+ memset(chartable, 0, numchars * CACHED_CHAR_SIZE);
+
+ /* allocate a temp buffer to compress into */
+ tempbuffer = malloc_or_die(65536);
+
+ /* write the header */
+ dest = tempbuffer;
+ *dest++ = 'f';
+ *dest++ = 'o';
+ *dest++ = 'n';
+ *dest++ = 't';
+ *dest++ = hash >> 24;
+ *dest++ = hash >> 16;
+ *dest++ = hash >> 8;
+ *dest++ = hash & 0xff;
+ *dest++ = font->height >> 8;
+ *dest++ = font->height & 0xff;
+ *dest++ = font->yoffs >> 8;
+ *dest++ = font->yoffs & 0xff;
+ *dest++ = numchars >> 24;
+ *dest++ = numchars >> 16;
+ *dest++ = numchars >> 8;
+ *dest++ = numchars & 0xff;
+ assert(dest - tempbuffer == CACHED_HEADER_SIZE);
+ bytes_written = mame_fwrite(file, tempbuffer, dest - tempbuffer);
+ if (bytes_written != dest - tempbuffer)
+ goto error;
+
+ /* write the empty table to the beginning of the file */
+ bytes_written = mame_fwrite(file, chartable, numchars * CACHED_CHAR_SIZE);
+ if (bytes_written != numchars * CACHED_CHAR_SIZE)
+ goto error;
+
+ /* loop over all characters */
+ tableindex = 0;
+ for (chnum = 0; chnum < 65536; chnum++)
+ {
+ ch = get_char(font, chnum);
+ if (ch != NULL && ch->width > 0)
+ {
+ UINT8 accum, accbit;
+ int x, y;
+
+ /* write out a bit-compressed bitmap if we have one */
+ if (ch->bitmap != NULL)
+ {
+ /* write the data to the tempbuffer */
+ dest = tempbuffer;
+ accum = 0;
+ accbit = 7;
+
+ /* bit-encode the character data */
+ for (y = 0; y < ch->bmheight; y++)
+ {
+ int desty = y + font->height + font->yoffs - ch->yoffs - ch->bmheight;
+ const UINT32 *src = (desty >= 0 && desty < font->height) ? BITMAP_ADDR32(ch->bitmap, desty, 0) : NULL;
+ for (x = 0; x < ch->bmwidth; x++)
+ {
+ if (src != NULL && RGB_ALPHA(src[x]) != 0)
+ accum |= 1 << accbit;
+ if (accbit-- == 0)
+ {
+ *dest++ = accum;
+ accum = 0;
+ accbit = 7;
+ }
+ }
+ }
+
+ /* flush any extra */
+ if (accbit != 7)
+ *dest++ = accum;
+
+ /* write the data */
+ bytes_written = mame_fwrite(file, tempbuffer, dest - tempbuffer);
+ if (bytes_written != dest - tempbuffer)
+ goto error;
+
+ /* free the bitmap and texture */
+ if (ch->texture != NULL)
+ render_texture_free(ch->texture);
+ ch->texture = NULL;
+ bitmap_free(ch->bitmap);
+ ch->bitmap = NULL;
+ }
+
+ /* compute the table entry */
+ dest = &chartable[tableindex++ * CACHED_CHAR_SIZE];
+ *dest++ = chnum >> 8;
+ *dest++ = chnum & 0xff;
+ *dest++ = ch->width >> 8;
+ *dest++ = ch->width & 0xff;
+ *dest++ = ch->xoffs >> 8;
+ *dest++ = ch->xoffs & 0xff;
+ *dest++ = ch->yoffs >> 8;
+ *dest++ = ch->yoffs & 0xff;
+ *dest++ = ch->bmwidth >> 8;
+ *dest++ = ch->bmwidth & 0xff;
+ *dest++ = ch->bmheight >> 8;
+ *dest++ = ch->bmheight & 0xff;
+ }
+ }
+
+ /* seek back to the beginning and rewrite the table */
+ mame_fseek(file, CACHED_HEADER_SIZE, SEEK_SET);
+ bytes_written = mame_fwrite(file, chartable, numchars * CACHED_CHAR_SIZE);
+ if (bytes_written != numchars * CACHED_CHAR_SIZE)
+ goto error;
+
+ /* all done */
+ mame_fclose(file);
+ free(tempbuffer);
+ free(chartable);
+ return 0;
+
+error:
+ mame_fclose(file);
+ osd_rmfile(filename);
+ free(tempbuffer);
+ free(chartable);
+ return 1;
+}
diff --git a/src/emu/rendfont.h b/src/emu/rendfont.h
new file mode 100644
index 00000000000..0c92e1b4a39
--- /dev/null
+++ b/src/emu/rendfont.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+
+ rendfont.h
+
+ Rendering system font management.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __RENDFONT_H__
+#define __RENDFONT_H__
+
+#include "render.h"
+#include "unicode.h"
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+render_font *render_font_alloc(const char *filename);
+void render_font_free(render_font *font);
+INT32 render_font_get_pixel_height(render_font *font);
+render_texture *render_font_get_char_texture_and_bounds(render_font *font, float height, float aspect, unicode_char ch, render_bounds *bounds);
+void render_font_get_scaled_bitmap_and_bounds(render_font *font, mame_bitmap *dest, float height, float aspect, unicode_char chnum, rectangle *bounds);
+float render_font_get_char_width(render_font *font, float height, float aspect, unicode_char ch);
+float render_font_get_string_width(render_font *font, float height, float aspect, const char *string);
+float render_font_get_utf8string_width(render_font *font, float height, float aspect, const char *utf8string);
+
+#endif /* __RENDFONT_H__ */
diff --git a/src/emu/rendlay.c b/src/emu/rendlay.c
new file mode 100644
index 00000000000..95f92443ede
--- /dev/null
+++ b/src/emu/rendlay.c
@@ -0,0 +1,2126 @@
+/***************************************************************************
+
+ rendlay.c
+
+ Core rendering layout parser and manager.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Notes:
+
+ Unlike the old system, the artwork is not rotated with the game
+ orientation. This is to support odd configurations like two
+ monitors in different orientations. You can specify an orientation
+ for a backdrop/screen/overlay/bezel element, but it only applies
+ to the artwork itself, and does not affect coordinates in any way.
+
+
+ Overview of objects:
+
+ layout_file -- A layout_file comprises a list of elements and a
+ list of views. The elements are reusable items that the views
+ reference.
+
+ layout_view -- A layout_view describes a single view within a
+ layout_file. The view is described using arbitrary coordinates
+ that are scaled to fit within the render target. Pixels within
+ a view are assumed to be square.
+
+ view_item -- Each view has four lists of view_items, one for each
+ "layer." Each view item is specified using floating point
+ coordinates in arbitrary units, and is assumed to have square
+ pixels. Each view item can control its orientation independently.
+ Each item can also have an optional name, and can be set at
+ runtime into different "states", which control how the embedded
+ elements are displayed.
+
+ layout_element -- A layout_element is a description of a piece of
+ visible artwork. Most view_items (except for those in the screen
+ layer) have exactly one layout_element which describes the
+ contents of the item. Elements are separate from items because
+ they can be re-used multiple times within a layout. Even though
+ an element can contain a number of components, they are treated
+ as if they were a single bitmap.
+
+ element_component -- Each layout_element contains one or more
+ components. Each component can describe either an image or
+ a rectangle/disk primitive. Each component also has a "state"
+ associated with it, which controls whether or not the component
+ is visible (if the owning item has the same state, it is
+ visible).
+
+***************************************************************************/
+
+#include "render.h"
+#include "rendfont.h"
+#include "rendlay.h"
+#include "rendutil.h"
+#include "output.h"
+#include "xmlfile.h"
+#include "png.h"
+
+
+
+/***************************************************************************
+ STANDARD LAYOUTS
+***************************************************************************/
+
+/* single screen layouts */
+#include "horizont.lh"
+#include "vertical.lh"
+
+/* dual screen layouts */
+#include "dualhsxs.lh"
+#include "dualhovu.lh"
+#include "dualhuov.lh"
+
+/* triple screen layouts */
+#include "triphsxs.lh"
+
+/* generic color overlay layouts */
+#include "ho20ffff.lh"
+#include "ho2eff2e.lh"
+#include "ho4f893d.lh"
+#include "ho88ffff.lh"
+#include "hoa0a0ff.lh"
+#include "hoffe457.lh"
+#include "voffff20.lh"
+#include "hoffff20.lh"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define LAYOUT_VERSION 2
+
+#define LINE_CAP_NONE 0
+#define LINE_CAP_START 1
+#define LINE_CAP_END 2
+
+enum
+{
+ COMPONENT_TYPE_IMAGE = 0,
+ COMPONENT_TYPE_RECT,
+ COMPONENT_TYPE_DISK,
+ COMPONENT_TYPE_TEXT,
+ COMPONENT_TYPE_LED7SEG,
+ COMPONENT_TYPE_LED14SEG,
+ COMPONENT_TYPE_LED16SEG,
+ COMPONENT_TYPE_LED14SEGSC,
+ COMPONENT_TYPE_LED16SEGSC,
+ COMPONENT_TYPE_MAX
+};
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* an element_component represents an image, rectangle, or disk in an element */
+struct _element_component
+{
+ element_component * next; /* link to next component */
+ int type; /* type of component */
+ int state; /* state where this component is visible (-1 means all states) */
+ render_bounds bounds; /* bounds of the element */
+ render_color color; /* color of the element */
+ const char * string; /* string for text components */
+ mame_bitmap * bitmap; /* source bitmap for images */
+ const char * dirname; /* directory name of image file (for lazy loading) */
+ const char * imagefile; /* name of the image file (for lazy loading) */
+ const char * alphafile; /* name of the alpha file (for lazy loading) */
+ int hasalpha; /* is there any alpha component present? */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* layout elements */
+static void layout_element_scale(mame_bitmap *dest, const mame_bitmap *source, const rectangle *sbounds, void *param);
+static void layout_element_draw_rect(mame_bitmap *dest, const rectangle *bounds, const render_color *color);
+static void layout_element_draw_disk(mame_bitmap *dest, const rectangle *bounds, const render_color *color);
+static void layout_element_draw_text(mame_bitmap *dest, const rectangle *bounds, const render_color *color, const char *string);
+static void layout_element_draw_led7seg(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int state);
+static void layout_element_draw_led14seg(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int state);
+static void layout_element_draw_led16seg(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int state);
+static void layout_element_draw_led14segsc(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int state);
+static void layout_element_draw_led16segsc(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int state);
+
+/* layout file parsing */
+static layout_element *load_layout_element(xml_data_node *elemnode, const char *dirname);
+static element_component *load_element_component(xml_data_node *compnode, const char *dirname);
+static layout_view *load_layout_view(xml_data_node *viewnode, layout_element *elemlist);
+static view_item *load_view_item(xml_data_node *itemnode, layout_element *elemlist);
+static mame_bitmap *load_component_bitmap(const char *dirname, const char *file, const char *alphafile, int *hasalpha);
+static int load_bounds(xml_data_node *boundsnode, render_bounds *bounds);
+static int load_color(xml_data_node *colornode, render_color *color);
+static int load_orientation(xml_data_node *orientnode, int *orientation);
+static void layout_view_free(layout_view *view);
+static void layout_element_free(layout_element *element);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ gcd - compute the greatest common divisor (GCD)
+ of two integers using the Euclidean algorithm
+-------------------------------------------------*/
+
+INLINE int gcd(int a, int b)
+{
+ while (b != 0)
+ {
+ int t = b;
+ b = a % b;
+ a = t;
+ }
+ return a;
+}
+
+
+/*-------------------------------------------------
+ reduce_fraction - reduce a fraction by
+ dividing out common factors
+-------------------------------------------------*/
+
+INLINE void reduce_fraction(int *num, int *den)
+{
+ int div;
+
+ /* search the greatest common divisor */
+ div = gcd(*num, *den);
+
+ /* reduce the fraction if a common divisor has been found */
+ if (div > 1)
+ {
+ *num /= div;
+ *den /= div;
+ }
+}
+
+
+/*-------------------------------------------------
+ copy_string - make a copy of a string
+-------------------------------------------------*/
+
+INLINE const char *copy_string(const char *string)
+{
+ char *newstring = malloc_or_die(strlen(string) + 1);
+ strcpy(newstring, string);
+ return newstring;
+}
+
+
+/*-------------------------------------------------
+ view_has_art - true if a render_view contains
+ any non-screen elements
+-------------------------------------------------*/
+
+INLINE int view_has_art(layout_view *view)
+{
+ return (view->itemlist[ITEM_LAYER_BACKDROP] != 0 ||
+ view->itemlist[ITEM_LAYER_OVERLAY] != 0 ||
+ view->itemlist[ITEM_LAYER_BEZEL] != 0);
+}
+
+
+
+/***************************************************************************
+ LAYOUT VIEWS
+***************************************************************************/
+
+/*-------------------------------------------------
+ layout_view_recompute - recompute the bounds
+ and aspect ratio of a view and all of its
+ contained items
+-------------------------------------------------*/
+
+void layout_view_recompute(layout_view *view, int layerconfig)
+{
+ render_bounds target_bounds;
+ float xscale, yscale;
+ float xoffs, yoffs;
+ int scrfirst = TRUE;
+ int first = TRUE;
+ int layer;
+
+ /* reset the bounds */
+ view->bounds.x0 = view->bounds.y0 = view->bounds.x1 = view->bounds.y1 = 0.0f;
+ view->scrbounds.x0 = view->scrbounds.y0 = view->scrbounds.x1 = view->scrbounds.y1 = 0.0f;
+ view->screens = 0;
+
+ /* loop over all layers */
+ for (layer = 0; layer < ITEM_LAYER_MAX; layer++)
+ {
+ static const int layer_mask[ITEM_LAYER_MAX] = { LAYER_CONFIG_ENABLE_BACKDROP, 0, LAYER_CONFIG_ENABLE_OVERLAY, LAYER_CONFIG_ENABLE_BEZEL };
+
+ /* determine if this layer should be visible */
+ view->layenabled[layer] = (layer_mask[layer] == 0 || (layerconfig & layer_mask[layer]));
+
+ /* only do it if requested */
+ if (view->layenabled[layer])
+ {
+ view_item *item;
+
+ for (item = view->itemlist[layer]; item != NULL; item = item->next)
+ {
+ /* accumulate bounds */
+ if (first)
+ view->bounds = item->rawbounds;
+ else
+ union_render_bounds(&view->bounds, &item->rawbounds);
+ first = FALSE;
+
+ /* accumulate screen bounds */
+ if (item->element == NULL)
+ {
+ if (scrfirst)
+ view->scrbounds = item->rawbounds;
+ else
+ union_render_bounds(&view->scrbounds, &item->rawbounds);
+ scrfirst = FALSE;
+ }
+ }
+ }
+ }
+
+ /* if we have an explicit bounds, override it */
+ if (view->expbounds.x1 > view->expbounds.x0)
+ view->bounds = view->expbounds;
+
+ /* compute the aspect ratio of the view */
+ view->aspect = (view->bounds.x1 - view->bounds.x0) / (view->bounds.y1 - view->bounds.y0);
+ view->scraspect = (view->scrbounds.x1 - view->scrbounds.x0) / (view->scrbounds.y1 - view->scrbounds.y0);
+
+ /* if we're handling things normally, the target bounds are (0,0)-(1,1) */
+ if (!(layerconfig & LAYER_CONFIG_ZOOM_TO_SCREEN))
+ {
+ target_bounds.x0 = target_bounds.y0 = 0.0f;
+ target_bounds.x1 = target_bounds.y1 = 1.0f;
+ }
+
+ /* if we're cropping, we want the screen area to fill (0,0)-(1,1) */
+ else
+ {
+ float targwidth = (view->bounds.x1 - view->bounds.x0) / (view->scrbounds.x1 - view->scrbounds.x0);
+ float targheight = (view->bounds.y1 - view->bounds.y0) / (view->scrbounds.y1 - view->scrbounds.y0);
+ target_bounds.x0 = (view->bounds.x0 - view->scrbounds.x0) / (view->bounds.x1 - view->bounds.x0) * targwidth;
+ target_bounds.y0 = (view->bounds.y0 - view->scrbounds.y0) / (view->bounds.y1 - view->bounds.y0) * targheight;
+ target_bounds.x1 = target_bounds.x0 + targwidth;
+ target_bounds.y1 = target_bounds.y0 + targheight;
+ }
+
+ /* determine the scale/offset for normalization */
+ xoffs = view->bounds.x0;
+ yoffs = view->bounds.y0;
+ xscale = (target_bounds.x1 - target_bounds.x0) / (view->bounds.x1 - view->bounds.x0);
+ yscale = (target_bounds.y1 - target_bounds.y0) / (view->bounds.y1 - view->bounds.y0);
+
+ /* normalize all the item bounds */
+ for (layer = 0; layer < ITEM_LAYER_MAX; layer++)
+ {
+ view_item *item;
+
+ /* adjust the bounds for each item */
+ for (item = view->itemlist[layer]; item; item = item->next)
+ {
+ item->bounds.x0 = target_bounds.x0 + (item->rawbounds.x0 - xoffs) * xscale;
+ item->bounds.x1 = target_bounds.x0 + (item->rawbounds.x1 - xoffs) * xscale;
+ item->bounds.y0 = target_bounds.y0 + (item->rawbounds.y0 - yoffs) * yscale;
+ item->bounds.y1 = target_bounds.y0 + (item->rawbounds.y1 - yoffs) * yscale;
+
+ /* accumulate the screens in use while we're scanning */
+ if (item->element == NULL)
+ view->screens |= 1 << item->index;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ LAYOUT ELEMENTS
+***************************************************************************/
+
+/*-------------------------------------------------
+ layout_element_scale - scale an element by
+ rendering all the components at the
+ appropriate resolution
+-------------------------------------------------*/
+
+static void layout_element_scale(mame_bitmap *dest, const mame_bitmap *source, const rectangle *sbounds, void *param)
+{
+ element_texture *elemtex = param;
+ element_component *component;
+
+ /* iterate over components that are part of the current state */
+ for (component = elemtex->element->complist; component != NULL; component = component->next)
+ if (component->state == -1 || component->state == elemtex->state)
+ {
+ rectangle bounds;
+
+ /* get the local scaled bounds */
+ bounds.min_x = render_round_nearest(component->bounds.x0 * dest->width);
+ bounds.min_y = render_round_nearest(component->bounds.y0 * dest->height);
+ bounds.max_x = render_round_nearest(component->bounds.x1 * dest->width);
+ bounds.max_y = render_round_nearest(component->bounds.y1 * dest->height);
+
+ /* based on the component type, add to the texture */
+ switch (component->type)
+ {
+ case COMPONENT_TYPE_IMAGE:
+ if (component->bitmap == NULL)
+ component->bitmap = load_component_bitmap(component->dirname, component->imagefile, component->alphafile, &component->hasalpha);
+ render_resample_argb_bitmap_hq(
+ BITMAP_ADDR32(dest, bounds.min_y, bounds.min_x),
+ dest->rowpixels,
+ bounds.max_x - bounds.min_x,
+ bounds.max_y - bounds.min_y,
+ component->bitmap, NULL, &component->color);
+ break;
+
+ case COMPONENT_TYPE_RECT:
+ layout_element_draw_rect(dest, &bounds, &component->color);
+ break;
+
+ case COMPONENT_TYPE_DISK:
+ layout_element_draw_disk(dest, &bounds, &component->color);
+ break;
+
+ case COMPONENT_TYPE_TEXT:
+ layout_element_draw_text(dest, &bounds, &component->color, component->string);
+ break;
+
+ case COMPONENT_TYPE_LED7SEG:
+ layout_element_draw_led7seg(dest, &bounds, &component->color, elemtex->state);
+ break;
+
+ case COMPONENT_TYPE_LED14SEG:
+ layout_element_draw_led14seg(dest, &bounds, &component->color, elemtex->state);
+ break;
+
+ case COMPONENT_TYPE_LED16SEG:
+ layout_element_draw_led16seg(dest, &bounds, &component->color, elemtex->state);
+ break;
+
+ case COMPONENT_TYPE_LED14SEGSC:
+ layout_element_draw_led14segsc(dest, &bounds, &component->color, elemtex->state);
+ break;
+
+ case COMPONENT_TYPE_LED16SEGSC:
+ layout_element_draw_led16segsc(dest, &bounds, &component->color, elemtex->state);
+ break;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ layout_element_draw_rect - draw a rectangle
+ in the specified color
+-------------------------------------------------*/
+
+static void layout_element_draw_rect(mame_bitmap *dest, const rectangle *bounds, const render_color *color)
+{
+ UINT32 r, g, b, inva;
+ UINT32 x, y;
+
+ /* compute premultiplied colors */
+ r = color->r * color->a * 255.0;
+ g = color->g * color->a * 255.0;
+ b = color->b * color->a * 255.0;
+ inva = (1.0f - color->a) * 255.0;
+
+ /* iterate over X and Y */
+ for (y = bounds->min_y; y < bounds->max_y; y++)
+ for (x = bounds->min_x; x < bounds->max_x; x++)
+ {
+ UINT32 finalr = r;
+ UINT32 finalg = g;
+ UINT32 finalb = b;
+
+ /* if we're translucent, add in the destination pixel contribution */
+ if (inva > 0)
+ {
+ UINT32 dpix = *BITMAP_ADDR32(dest, y, x);
+ finalr += (RGB_RED(dpix) * inva) >> 8;
+ finalg += (RGB_GREEN(dpix) * inva) >> 8;
+ finalb += (RGB_BLUE(dpix) * inva) >> 8;
+ }
+
+ /* store the target pixel, dividing the RGBA values by the overall scale factor */
+ *BITMAP_ADDR32(dest, y, x) = MAKE_ARGB(0xff, finalr, finalg, finalb);
+ }
+}
+
+
+/*-------------------------------------------------
+ layout_element_draw_disk - draw an ellipse
+ in the specified color
+-------------------------------------------------*/
+
+static void layout_element_draw_disk(mame_bitmap *dest, const rectangle *bounds, const render_color *color)
+{
+ float xcenter, ycenter;
+ float xradius, yradius, ooyradius2;
+ UINT32 r, g, b, inva;
+ UINT32 x, y;
+
+ /* compute premultiplied colors */
+ r = color->r * color->a * 255.0;
+ g = color->g * color->a * 255.0;
+ b = color->b * color->a * 255.0;
+ inva = (1.0f - color->a) * 255.0;
+
+ /* find the center */
+ xcenter = (float)(bounds->min_x + bounds->max_x) * 0.5f;
+ ycenter = (float)(bounds->min_y + bounds->max_y) * 0.5f;
+ xradius = (float)(bounds->max_x - bounds->min_x) * 0.5f;
+ yradius = (float)(bounds->max_y - bounds->min_y) * 0.5f;
+ ooyradius2 = 1.0f / (yradius * yradius);
+
+ /* iterate over y */
+ for (y = bounds->min_y; y < bounds->max_y; y++)
+ {
+ float ycoord = ycenter - ((float)y + 0.5f);
+ float xval = xradius * sqrt(1.0f - (ycoord * ycoord) * ooyradius2);
+ INT32 left, right;
+
+ /* compute left/right coordinates */
+ left = (INT32)(xcenter - xval + 0.5f);
+ right = (INT32)(xcenter + xval + 0.5f);
+
+ /* draw this scanline */
+ for (x = left; x < right; x++)
+ {
+ UINT32 finalr = r;
+ UINT32 finalg = g;
+ UINT32 finalb = b;
+
+ /* if we're translucent, add in the destination pixel contribution */
+ if (inva > 0)
+ {
+ UINT32 dpix = *BITMAP_ADDR32(dest, y, x);
+ finalr += (RGB_RED(dpix) * inva) >> 8;
+ finalg += (RGB_GREEN(dpix) * inva) >> 8;
+ finalb += (RGB_BLUE(dpix) * inva) >> 8;
+ }
+
+ /* store the target pixel, dividing the RGBA values by the overall scale factor */
+ *BITMAP_ADDR32(dest, y, x) = MAKE_ARGB(0xff, finalr, finalg, finalb);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ layout_element_draw_text - draw text in the
+ specified color
+-------------------------------------------------*/
+
+static void layout_element_draw_text(mame_bitmap *dest, const rectangle *bounds, const render_color *color, const char *string)
+{
+ render_font *font = render_font_alloc(NULL);
+ mame_bitmap *tempbitmap;
+ UINT32 r, g, b, a;
+ float aspect = 1.0f;
+ INT32 curx, width;
+ const char *s;
+
+ /* compute premultiplied colors */
+ r = color->r * 255.0;
+ g = color->g * 255.0;
+ b = color->b * 255.0;
+ a = color->a * 255.0;
+
+ /* get the width of the string */
+ while (1)
+ {
+ width = render_font_get_string_width(font, bounds->max_y - bounds->min_y, aspect, string);
+ if (width < bounds->max_x - bounds->min_x)
+ break;
+ aspect *= 0.9f;
+ }
+ curx = bounds->min_x + (bounds->max_x - bounds->min_x - width) / 2;
+
+ /* allocate a temporary bitmap */
+ tempbitmap = bitmap_alloc(dest->width, dest->height, BITMAP_FORMAT_ARGB32);
+
+ /* loop over characters */
+ for (s = string; *s != 0; s++)
+ {
+ rectangle chbounds;
+ int x, y;
+
+ /* get the font bitmap */
+ render_font_get_scaled_bitmap_and_bounds(font, tempbitmap, bounds->max_y - bounds->min_y, aspect, *s, &chbounds);
+
+ /* copy the data into the target */
+ for (y = 0; y < chbounds.max_y - chbounds.min_y; y++)
+ {
+ int effy = bounds->min_y + y;
+ if (effy >= bounds->min_y && effy <= bounds->max_y)
+ {
+ UINT32 *s = BITMAP_ADDR32(tempbitmap, y, 0);
+ UINT32 *d = BITMAP_ADDR32(dest, effy, 0);
+ for (x = 0; x < chbounds.max_x - chbounds.min_x; x++)
+ {
+ int effx = curx + x + chbounds.min_x;
+ if (effx >= bounds->min_x && effx <= bounds->max_x)
+ {
+ UINT32 spix = RGB_ALPHA(s[x]);
+ if (spix != 0)
+ {
+ UINT32 dpix = d[effx];
+ UINT32 ta, tr, tg, tb;
+
+ ta = (a * (spix + 1)) >> 8;
+ tr = (r * ta + RGB_RED(dpix) * (0x100 - ta)) >> 8;
+ tg = (g * ta + RGB_GREEN(dpix) * (0x100 - ta)) >> 8;
+ tb = (b * ta + RGB_BLUE(dpix) * (0x100 - ta)) >> 8;
+ d[effx] = MAKE_ARGB(0xff, tr, tg, tb);
+ }
+ }
+ }
+ }
+ }
+
+ /* advance in the X direction */
+ curx += render_font_get_char_width(font, bounds->max_y - bounds->min_y, aspect, *s);
+ }
+
+ /* free the temporary bitmap and font */
+ bitmap_free(tempbitmap);
+ render_font_free(font);
+}
+
+
+/*-------------------------------------------------
+ draw_segment_horizontal_caps - draw a
+ horizontal LED segment with definable end
+ and start points
+-------------------------------------------------*/
+
+static void draw_segment_horizontal_caps(mame_bitmap *dest, int minx, int maxx, int midy, int width, int caps, rgb_t color)
+{
+ int x, y;
+
+ /* loop over the width of the segment */
+ for (y = 0; y < width / 2; y++)
+ {
+ UINT32 *d0 = BITMAP_ADDR32(dest, midy - y, 0);
+ UINT32 *d1 = BITMAP_ADDR32(dest, midy + y, 0);
+ int ty = (y < width / 8) ? width / 8 : y;
+
+ /* loop over the length of the segment */
+ for (x = minx + ((caps & LINE_CAP_START) ? ty : 0); x < maxx - ((caps & LINE_CAP_END) ? ty : 0); x++)
+ d0[x] = d1[x] = color;
+ }
+}
+
+
+/*-------------------------------------------------
+ draw_segment_horizontal - draw a horizontal
+ LED segment
+-------------------------------------------------*/
+
+static void draw_segment_horizontal(mame_bitmap *dest, int minx, int maxx, int midy, int width, rgb_t color)
+{
+ draw_segment_horizontal_caps(dest, minx, maxx, midy, width, LINE_CAP_START | LINE_CAP_END, color);
+}
+
+
+/*-------------------------------------------------
+ draw_segment_vertical_caps - draw a
+ vertical LED segment with definable end
+ and start points
+-------------------------------------------------*/
+
+static void draw_segment_vertical_caps(mame_bitmap *dest, int miny, int maxy, int midx, int width, int caps, rgb_t color)
+{
+ int x, y;
+
+ /* loop over the width of the segment */
+ for (x = 0; x < width / 2; x++)
+ {
+ UINT32 *d0 = BITMAP_ADDR32(dest, 0, midx - x);
+ UINT32 *d1 = BITMAP_ADDR32(dest, 0, midx + x);
+ int tx = (x < width / 8) ? width / 8 : x;
+
+ /* loop over the length of the segment */
+ for (y = miny + ((caps & LINE_CAP_START) ? tx : 0); y < maxy - ((caps & LINE_CAP_END) ? tx : 0); y++)
+ d0[y * dest->rowpixels] = d1[y * dest->rowpixels] = color;
+ }
+}
+
+
+/*-------------------------------------------------
+ draw_segment_vertical - draw a vertical
+ LED segment
+-------------------------------------------------*/
+
+static void draw_segment_vertical(mame_bitmap *dest, int miny, int maxy, int midx, int width, rgb_t color)
+{
+ draw_segment_vertical_caps(dest, miny, maxy, midx, width, LINE_CAP_START | LINE_CAP_END, color);
+}
+
+
+/*-------------------------------------------------
+ draw_segment_diagonal_1 - draw a diagonal
+ LED segment that looks like this: /
+-------------------------------------------------*/
+
+static void draw_segment_diagonal_1(mame_bitmap *dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color)
+{
+ int x, y;
+ float ratio;
+
+ /* compute parameters */
+ width *= 1.5;
+ ratio = (maxy - miny - width) / (float)(maxx - minx);
+
+ /* draw line */
+ for (x = minx; x < maxx; x++)
+ if (x >= 0 && x < dest->width)
+ {
+ UINT32 *d = BITMAP_ADDR32(dest, 0, x);
+ int step = (x - minx) * ratio;
+
+ for (y = maxy - width - step; y < maxy - step; y++)
+ if (y >= 0 && y < dest->height)
+ {
+ d[y * dest->rowpixels] = color;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ draw_segment_diagonal_2 - draw a diagonal
+ LED segment that looks like this: \
+-------------------------------------------------*/
+
+static void draw_segment_diagonal_2(mame_bitmap *dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color)
+{
+ int x, y;
+ float ratio;
+
+ /* compute parameters */
+ width *= 1.5;
+ ratio = (maxy - miny - width) / (float)(maxx - minx);
+
+ /* draw line */
+ for (x = minx; x < maxx; x++)
+ if (x >= 0 && x < dest->width)
+ {
+ UINT32 *d = BITMAP_ADDR32(dest, 0, x);
+ int step = (x - minx) * ratio;
+
+ for (y = miny + step; y < miny + step + width; y++)
+ if (y >= 0 && y < dest->height)
+ {
+ d[y * dest->rowpixels] = color;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ draw_segment_decimal - draw a decimal point
+-------------------------------------------------*/
+
+static void draw_segment_decimal(mame_bitmap *dest, int midx, int midy, int width, rgb_t color)
+{
+ float ooradius2;
+ UINT32 x, y;
+
+ /* compute parameters */
+ width /= 2;
+ ooradius2 = 1.0f / (float)(width * width);
+
+ /* iterate over y */
+ for (y = 0; y <= width; y++)
+ {
+ UINT32 *d0 = BITMAP_ADDR32(dest, midy - y, 0);
+ UINT32 *d1 = BITMAP_ADDR32(dest, midy + y, 0);
+ float xval = width * sqrt(1.0f - (float)(y * y) * ooradius2);
+ INT32 left, right;
+
+ /* compute left/right coordinates */
+ left = midx - (INT32)(xval + 0.5f);
+ right = midx + (INT32)(xval + 0.5f);
+
+ /* draw this scanline */
+ for (x = left; x < right; x++)
+ d0[x] = d1[x] = color;
+ }
+}
+
+/*-------------------------------------------------
+ draw_segment_comma - draw a comma tail
+-------------------------------------------------*/
+#if 0
+static void draw_segment_comma(mame_bitmap *dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color)
+{
+ int x, y;
+ float ratio;
+
+ /* compute parameters */
+ width *= 1.5;
+ ratio = (maxy - miny - width) / (float)(maxx - minx);
+
+ /* draw line */
+ for (x = minx; x < maxx; x++)
+ {
+ UINT32 *d = BITMAP_ADDR32(dest, 0, x);
+ int step = (x - minx) * ratio;
+
+ for (y = maxy; y < maxy - width - step; y--)
+ {
+ d[y * dest->rowpixels] = color;
+ }
+ }
+}
+#endif
+
+
+/*-------------------------------------------------
+ apply_skew - apply skew to a mame_bitmap
+-------------------------------------------------*/
+
+static void apply_skew(mame_bitmap *dest, int skewwidth)
+{
+ int x, y;
+
+ for (y = 0; y < dest->height; y++)
+ {
+ UINT32 *destrow = BITMAP_ADDR32(dest, y, 0);
+ int offs = skewwidth * (dest->height - y) / dest->height;
+ for (x = dest->width - skewwidth - 1; x >= 0; x--)
+ destrow[x + offs] = destrow[x];
+ for (x = 0; x < offs; x++)
+ destrow[x] = 0;
+ }
+}
+
+
+/*-------------------------------------------------
+ layout_element_draw_led7seg - draw a
+ 7-segment LCD
+-------------------------------------------------*/
+
+static void layout_element_draw_led7seg(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int pattern)
+{
+ const rgb_t onpen = MAKE_ARGB(0xff,0xff,0xff,0xff);
+ const rgb_t offpen = MAKE_ARGB(0xff,0x20,0x20,0x20);
+ int bmwidth, bmheight, segwidth, skewwidth;
+ mame_bitmap *tempbitmap;
+
+ /* sizes for computation */
+ bmwidth = 250;
+ bmheight = 400;
+ segwidth = 40;
+ skewwidth = 40;
+
+ /* allocate a temporary bitmap for drawing */
+ tempbitmap = bitmap_alloc(bmwidth + skewwidth, bmheight, BITMAP_FORMAT_ARGB32);
+ fillbitmap(tempbitmap, MAKE_ARGB(0xff,0x00,0x00,0x00), NULL);
+
+ /* top bar */
+ draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, segwidth, (pattern & (1 << 0)) ? onpen : offpen);
+
+ /* top-right bar */
+ draw_segment_vertical(tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, segwidth, (pattern & (1 << 1)) ? onpen : offpen);
+
+ /* bottom-right bar */
+ draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, segwidth, (pattern & (1 << 2)) ? onpen : offpen);
+
+ /* bottom bar */
+ draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, segwidth, (pattern & (1 << 3)) ? onpen : offpen);
+
+ /* bottom-left bar */
+ draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, segwidth, (pattern & (1 << 4)) ? onpen : offpen);
+
+ /* top-left bar */
+ draw_segment_vertical(tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, segwidth, (pattern & (1 << 5)) ? onpen : offpen);
+
+ /* middle bar */
+ draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight/2, segwidth, (pattern & (1 << 6)) ? onpen : offpen);
+
+ /* apply skew */
+ apply_skew(tempbitmap, 40);
+
+ /* decimal point */
+ draw_segment_decimal(tempbitmap, bmwidth + segwidth/2, bmheight - segwidth/2, segwidth, (pattern & (1 << 7)) ? onpen : offpen);
+
+ /* resample to the target size */
+ render_resample_argb_bitmap_hq(dest->base, dest->rowpixels, dest->width, dest->height, tempbitmap, NULL, color);
+
+ bitmap_free(tempbitmap);
+}
+
+
+/*-------------------------------------------------
+ layout_element_draw_led14seg - draw a
+ 14-segment LCD
+-------------------------------------------------*/
+
+static void layout_element_draw_led14seg(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int pattern)
+{
+ const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff);
+ const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20);
+ int bmwidth, bmheight, segwidth, skewwidth;
+ mame_bitmap *tempbitmap;
+
+ /* sizes for computation */
+ bmwidth = 250;
+ bmheight = 400;
+ segwidth = 40;
+ skewwidth = 40;
+
+ /* allocate a temporary bitmap for drawing */
+ tempbitmap = bitmap_alloc(bmwidth + skewwidth, bmheight, BITMAP_FORMAT_ARGB32);
+ fillbitmap(tempbitmap, MAKE_ARGB(0xff, 0x00, 0x00, 0x00), NULL);
+
+ /* top bar */
+ draw_segment_horizontal(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 0)) ? onpen : offpen);
+
+ /* right-top bar */
+ draw_segment_vertical(tempbitmap,
+ 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2,
+ segwidth, (pattern & (1 << 1)) ? onpen : offpen);
+
+ /* right-bottom bar */
+ draw_segment_vertical(tempbitmap,
+ bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2,
+ segwidth, (pattern & (1 << 2)) ? onpen : offpen);
+
+ /* bottom bar */
+ draw_segment_horizontal(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2,
+ segwidth, (pattern & (1 << 3)) ? onpen : offpen);
+
+ /* left-bottom bar */
+ draw_segment_vertical(tempbitmap,
+ bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 4)) ? onpen : offpen);
+
+ /* left-top bar */
+ draw_segment_vertical(tempbitmap,
+ 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 5)) ? onpen : offpen);
+
+ /* horizontal-middle-left bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2,
+ segwidth, LINE_CAP_START, (pattern & (1 << 6)) ? onpen : offpen);
+
+ /* horizontal-middle-right bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2,
+ segwidth, LINE_CAP_END, (pattern & (1 << 7)) ? onpen : offpen);
+
+ /* vertical-middle-top bar */
+ draw_segment_vertical_caps(tempbitmap,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2,
+ segwidth, LINE_CAP_NONE, (pattern & (1 << 8)) ? onpen : offpen);
+
+ /* vertical-middle-bottom bar */
+ draw_segment_vertical_caps(tempbitmap,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2,
+ segwidth, LINE_CAP_NONE, (pattern & (1 << 9)) ? onpen : offpen);
+
+ /* diagonal-left-bottom bar */
+ draw_segment_diagonal_1(tempbitmap,
+ 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3,
+ segwidth, (pattern & (1 << 10)) ? onpen : offpen);
+
+ /* diagonal-left-top bar */
+ draw_segment_diagonal_2(tempbitmap,
+ 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3,
+ segwidth, (pattern & (1 << 11)) ? onpen : offpen);
+
+ /* diagonal-right-top bar */
+ draw_segment_diagonal_1(tempbitmap,
+ bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3,
+ segwidth, (pattern & (1 << 12)) ? onpen : offpen);
+
+ /* diagonal-right-bottom bar */
+ draw_segment_diagonal_2(tempbitmap,
+ bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3,
+ segwidth, (pattern & (1 << 13)) ? onpen : offpen);
+
+ /* apply skew */
+ apply_skew(tempbitmap, 40);
+
+ /* resample to the target size */
+ render_resample_argb_bitmap_hq(dest->base, dest->rowpixels, dest->width, dest->height, tempbitmap, NULL, color);
+
+ bitmap_free(tempbitmap);
+}
+
+
+/*-------------------------------------------------
+ layout_element_draw_led14segsc - draw a
+ 14-segment LCD with semicolon (2 extra segments)
+-------------------------------------------------*/
+
+static void layout_element_draw_led14segsc(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int pattern)
+{
+ const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff);
+ const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20);
+ int bmwidth, bmheight, segwidth, skewwidth;
+ mame_bitmap *tempbitmap;
+
+ /* sizes for computation */
+ bmwidth = 250;
+ bmheight = 400;
+ segwidth = 40;
+ skewwidth = 40;
+
+ /* allocate a temporary bitmap for drawing, adding some extra space for the tail */
+ tempbitmap = bitmap_alloc(bmwidth + skewwidth, bmheight + segwidth, BITMAP_FORMAT_ARGB32);
+ fillbitmap(tempbitmap, MAKE_ARGB(0xff, 0x00, 0x00, 0x00), NULL);
+
+ /* top bar */
+ draw_segment_horizontal(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 0)) ? onpen : offpen);
+
+ /* right-top bar */
+ draw_segment_vertical(tempbitmap,
+ 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2,
+ segwidth, (pattern & (1 << 1)) ? onpen : offpen);
+
+ /* right-bottom bar */
+ draw_segment_vertical(tempbitmap,
+ bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2,
+ segwidth, (pattern & (1 << 2)) ? onpen : offpen);
+
+ /* bottom bar */
+ draw_segment_horizontal(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2,
+ segwidth, (pattern & (1 << 3)) ? onpen : offpen);
+
+ /* left-bottom bar */
+ draw_segment_vertical(tempbitmap,
+ bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 4)) ? onpen : offpen);
+
+ /* left-top bar */
+ draw_segment_vertical(tempbitmap,
+ 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 5)) ? onpen : offpen);
+
+ /* horizontal-middle-left bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2,
+ segwidth, LINE_CAP_START, (pattern & (1 << 6)) ? onpen : offpen);
+
+ /* horizontal-middle-right bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2,
+ segwidth, LINE_CAP_END, (pattern & (1 << 7)) ? onpen : offpen);
+
+ /* vertical-middle-top bar */
+ draw_segment_vertical_caps(tempbitmap,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2,
+ segwidth, LINE_CAP_NONE, (pattern & (1 << 8)) ? onpen : offpen);
+
+ /* vertical-middle-bottom bar */
+ draw_segment_vertical_caps(tempbitmap,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2,
+ segwidth, LINE_CAP_NONE, (pattern & (1 << 9)) ? onpen : offpen);
+
+ /* diagonal-left-bottom bar */
+ draw_segment_diagonal_1(tempbitmap,
+ 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3,
+ segwidth, (pattern & (1 << 10)) ? onpen : offpen);
+
+ /* diagonal-left-top bar */
+ draw_segment_diagonal_2(tempbitmap,
+ 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3,
+ segwidth, (pattern & (1 << 11)) ? onpen : offpen);
+
+ /* diagonal-right-top bar */
+ draw_segment_diagonal_1(tempbitmap,
+ bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3,
+ segwidth, (pattern & (1 << 12)) ? onpen : offpen);
+
+ /* diagonal-right-bottom bar */
+ draw_segment_diagonal_2(tempbitmap,
+ bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3,
+ segwidth, (pattern & (1 << 13)) ? onpen : offpen);
+
+ /* apply skew */
+ apply_skew(tempbitmap, 40);
+
+ /* decimal point */
+ draw_segment_decimal(tempbitmap, bmwidth + segwidth/2, bmheight - segwidth/2, segwidth, (pattern & (1 << 14)) ? onpen : offpen);
+
+ /* comma tail */
+ draw_segment_diagonal_1(tempbitmap,
+ bmwidth - (segwidth/2), bmwidth + segwidth,
+ bmheight - (segwidth), bmheight + segwidth*1.5,
+ segwidth/2, (pattern & (1 << 15)) ? onpen : offpen);
+
+ /* resample to the target size */
+ render_resample_argb_bitmap_hq(dest->base, dest->rowpixels, dest->width, dest->height, tempbitmap, NULL, color);
+
+ bitmap_free(tempbitmap);
+}
+
+
+/*-------------------------------------------------
+ layout_element_draw_led16seg - draw a
+ 16-segment LCD
+-------------------------------------------------*/
+
+static void layout_element_draw_led16seg(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int pattern)
+{
+ const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff);
+ const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20);
+ int bmwidth, bmheight, segwidth, skewwidth;
+ mame_bitmap *tempbitmap;
+
+ /* sizes for computation */
+ bmwidth = 250;
+ bmheight = 400;
+ segwidth = 40;
+ skewwidth = 40;
+
+ /* allocate a temporary bitmap for drawing */
+ tempbitmap = bitmap_alloc(bmwidth + skewwidth, bmheight, BITMAP_FORMAT_ARGB32);
+ fillbitmap(tempbitmap, MAKE_ARGB(0xff, 0x00, 0x00, 0x00), NULL);
+
+ /* top-left bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, 0 + segwidth/2,
+ segwidth, LINE_CAP_START, (pattern & (1 << 0)) ? onpen : offpen);
+
+ /* top-right bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, 0 + segwidth/2,
+ segwidth, LINE_CAP_END, (pattern & (1 << 1)) ? onpen : offpen);
+
+ /* right-top bar */
+ draw_segment_vertical(tempbitmap,
+ 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2,
+ segwidth, (pattern & (1 << 2)) ? onpen : offpen);
+
+ /* right-bottom bar */
+ draw_segment_vertical(tempbitmap,
+ bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2,
+ segwidth, (pattern & (1 << 3)) ? onpen : offpen);
+
+ /* bottom-right bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight - segwidth/2,
+ segwidth, LINE_CAP_END, (pattern & (1 << 4)) ? onpen : offpen);
+
+ /* bottom-left bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight - segwidth/2,
+ segwidth, LINE_CAP_START, (pattern & (1 << 5)) ? onpen : offpen);
+
+ /* left-bottom bar */
+ draw_segment_vertical(tempbitmap,
+ bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 6)) ? onpen : offpen);
+
+ /* left-top bar */
+ draw_segment_vertical(tempbitmap,
+ 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 7)) ? onpen : offpen);
+
+ /* horizontal-middle-left bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2,
+ segwidth, LINE_CAP_START, (pattern & (1 << 8)) ? onpen : offpen);
+
+ /* horizontal-middle-right bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2,
+ segwidth, LINE_CAP_END, (pattern & (1 << 9)) ? onpen : offpen);
+
+ /* vertical-middle-top bar */
+ draw_segment_vertical_caps(tempbitmap,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2,
+ segwidth, LINE_CAP_NONE, (pattern & (1 << 10)) ? onpen : offpen);
+
+ /* vertical-middle-bottom bar */
+ draw_segment_vertical_caps(tempbitmap,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2,
+ segwidth, LINE_CAP_NONE, (pattern & (1 << 11)) ? onpen : offpen);
+
+ /* diagonal-left-bottom bar */
+ draw_segment_diagonal_1(tempbitmap,
+ 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3,
+ segwidth, (pattern & (1 << 12)) ? onpen : offpen);
+
+ /* diagonal-left-top bar */
+ draw_segment_diagonal_2(tempbitmap,
+ 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3,
+ segwidth, (pattern & (1 << 13)) ? onpen : offpen);
+
+ /* diagonal-right-top bar */
+ draw_segment_diagonal_1(tempbitmap,
+ bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3,
+ segwidth, (pattern & (1 << 14)) ? onpen : offpen);
+
+ /* diagonal-right-bottom bar */
+ draw_segment_diagonal_2(tempbitmap,
+ bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3,
+ segwidth, (pattern & (1 << 15)) ? onpen : offpen);
+
+ /* apply skew */
+ apply_skew(tempbitmap, 40);
+
+ /* resample to the target size */
+ render_resample_argb_bitmap_hq(dest->base, dest->rowpixels, dest->width, dest->height, tempbitmap, NULL, color);
+
+ bitmap_free(tempbitmap);
+}
+
+
+/*-------------------------------------------------
+ layout_element_draw_led16segsc - draw a
+ 16-segment LCD with semicolon (2 extra segments)
+-------------------------------------------------*/
+
+static void layout_element_draw_led16segsc(mame_bitmap *dest, const rectangle *bounds, const render_color *color, int pattern)
+{
+ const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff);
+ const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20);
+ int bmwidth, bmheight, segwidth, skewwidth;
+ mame_bitmap *tempbitmap;
+
+ /* sizes for computation */
+ bmwidth = 250;
+ bmheight = 400;
+ segwidth = 40;
+ skewwidth = 40;
+
+ /* allocate a temporary bitmap for drawing */
+ tempbitmap = bitmap_alloc(bmwidth + skewwidth, bmheight + segwidth, BITMAP_FORMAT_ARGB32);
+ fillbitmap(tempbitmap, MAKE_ARGB(0xff, 0x00, 0x00, 0x00), NULL);
+
+ /* top-left bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, 0 + segwidth/2,
+ segwidth, LINE_CAP_START, (pattern & (1 << 0)) ? onpen : offpen);
+
+ /* top-right bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, 0 + segwidth/2,
+ segwidth, LINE_CAP_END, (pattern & (1 << 1)) ? onpen : offpen);
+
+ /* right-top bar */
+ draw_segment_vertical(tempbitmap,
+ 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2,
+ segwidth, (pattern & (1 << 2)) ? onpen : offpen);
+
+ /* right-bottom bar */
+ draw_segment_vertical(tempbitmap,
+ bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2,
+ segwidth, (pattern & (1 << 3)) ? onpen : offpen);
+
+ /* bottom-right bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight - segwidth/2,
+ segwidth, LINE_CAP_END, (pattern & (1 << 4)) ? onpen : offpen);
+
+ /* bottom-left bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight - segwidth/2,
+ segwidth, LINE_CAP_START, (pattern & (1 << 5)) ? onpen : offpen);
+
+ /* left-bottom bar */
+ draw_segment_vertical(tempbitmap,
+ bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 6)) ? onpen : offpen);
+
+ /* left-top bar */
+ draw_segment_vertical(tempbitmap,
+ 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2,
+ segwidth, (pattern & (1 << 7)) ? onpen : offpen);
+
+ /* horizontal-middle-left bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2,
+ segwidth, LINE_CAP_START, (pattern & (1 << 8)) ? onpen : offpen);
+
+ /* horizontal-middle-right bar */
+ draw_segment_horizontal_caps(tempbitmap,
+ 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2,
+ segwidth, LINE_CAP_END, (pattern & (1 << 9)) ? onpen : offpen);
+
+ /* vertical-middle-top bar */
+ draw_segment_vertical_caps(tempbitmap,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2,
+ segwidth, LINE_CAP_NONE, (pattern & (1 << 10)) ? onpen : offpen);
+
+ /* vertical-middle-bottom bar */
+ draw_segment_vertical_caps(tempbitmap,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2,
+ segwidth, LINE_CAP_NONE, (pattern & (1 << 11)) ? onpen : offpen);
+
+ /* diagonal-left-bottom bar */
+ draw_segment_diagonal_1(tempbitmap,
+ 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3,
+ segwidth, (pattern & (1 << 12)) ? onpen : offpen);
+
+ /* diagonal-left-top bar */
+ draw_segment_diagonal_2(tempbitmap,
+ 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3,
+ segwidth, (pattern & (1 << 13)) ? onpen : offpen);
+
+ /* diagonal-right-top bar */
+ draw_segment_diagonal_1(tempbitmap,
+ bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5,
+ 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3,
+ segwidth, (pattern & (1 << 14)) ? onpen : offpen);
+
+ /* diagonal-right-bottom bar */
+ draw_segment_diagonal_2(tempbitmap,
+ bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5,
+ bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3,
+ segwidth, (pattern & (1 << 15)) ? onpen : offpen);
+
+ /* decimal point */
+ draw_segment_decimal(tempbitmap, bmwidth + segwidth/2, bmheight - segwidth/2, segwidth, (pattern & (1 << 16)) ? onpen : offpen);
+
+ /* comma tail */
+ draw_segment_diagonal_1(tempbitmap,
+ bmwidth - (segwidth/2), bmwidth + segwidth,
+ bmheight - (segwidth), bmheight + segwidth*1.5,
+ segwidth/2, (pattern & (1 << 17)) ? onpen : offpen);
+
+ /* apply skew */
+ apply_skew(tempbitmap, 40);
+
+ /* resample to the target size */
+ render_resample_argb_bitmap_hq(dest->base, dest->rowpixels, dest->width, dest->height, tempbitmap, NULL, color);
+
+ bitmap_free(tempbitmap);
+}
+
+
+
+/***************************************************************************
+ LAYOUT FILE PARSING
+***************************************************************************/
+
+/*-------------------------------------------------
+ get_variable_value - compute the value of
+ a variable in an XML attribute
+-------------------------------------------------*/
+
+static int get_variable_value(const char *string, char **outputptr)
+{
+ int num, den, scrnum;
+ char temp[100];
+
+ /* screen 0 parameters */
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ {
+ /* native X aspect factor */
+ sprintf(temp, "~scr%dnativexaspect~", scrnum);
+ if (!strncmp(string, temp, strlen(temp)))
+ {
+ num = Machine->drv->screen[scrnum].defstate.visarea.max_x + 1 - Machine->drv->screen[scrnum].defstate.visarea.min_x;
+ den = Machine->drv->screen[scrnum].defstate.visarea.max_y + 1 - Machine->drv->screen[scrnum].defstate.visarea.min_y;
+ reduce_fraction(&num, &den);
+ *outputptr += sprintf(*outputptr, "%d", num);
+ return strlen(temp);
+ }
+
+ /* native Y aspect factor */
+ sprintf(temp, "~scr%dnativeyaspect~", scrnum);
+ if (!strncmp(string, temp, strlen(temp)))
+ {
+ num = Machine->drv->screen[scrnum].defstate.visarea.max_x + 1 - Machine->drv->screen[scrnum].defstate.visarea.min_x;
+ den = Machine->drv->screen[scrnum].defstate.visarea.max_y + 1 - Machine->drv->screen[scrnum].defstate.visarea.min_y;
+ reduce_fraction(&num, &den);
+ *outputptr += sprintf(*outputptr, "%d", den);
+ return strlen(temp);
+ }
+
+ /* native width */
+ sprintf(temp, "~scr%dwidth~", scrnum);
+ if (!strncmp(string, temp, strlen(temp)))
+ {
+ *outputptr += sprintf(*outputptr, "%d", Machine->drv->screen[scrnum].defstate.visarea.max_x + 1 - Machine->drv->screen[0].defstate.visarea.min_x);
+ return strlen(temp);
+ }
+
+ /* native height */
+ sprintf(temp, "~scr%dheight~", scrnum);
+ if (!strncmp(string, temp, strlen(temp)))
+ {
+ *outputptr += sprintf(*outputptr, "%d", Machine->drv->screen[scrnum].defstate.visarea.max_y + 1 - Machine->drv->screen[0].defstate.visarea.min_y);
+ return strlen(temp);
+ }
+ }
+
+ /* default: copy the first character and continue */
+ **outputptr = *string;
+ *outputptr += 1;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ xml_get_attribute_string_with_subst - analog
+ to xml_get_attribute_string but with variable
+ substitution
+-------------------------------------------------*/
+
+static const char *xml_get_attribute_string_with_subst(xml_data_node *node, const char *attribute, const char *defvalue)
+{
+ const char *str = xml_get_attribute_string(node, attribute, NULL);
+ static char buffer[1000];
+ const char *s;
+ char *d;
+
+ /* if nothing, just return the default */
+ if (str == NULL)
+ return defvalue;
+
+ /* if no tildes, don't worry */
+ if (strchr(str, '~') == NULL)
+ return str;
+
+ /* make a copy of the string, doing substitutions along the way */
+ for (s = str, d = buffer; *s != 0; )
+ {
+ /* if not a variable, just copy */
+ if (*s != '~')
+ *d++ = *s++;
+
+ /* extract the variable */
+ else
+ s += get_variable_value(s, &d);
+ }
+ *d = 0;
+ return buffer;
+}
+
+
+/*-------------------------------------------------
+ xml_get_attribute_int_with_subst - analog
+ to xml_get_attribute_int but with variable
+ substitution
+-------------------------------------------------*/
+
+static int xml_get_attribute_int_with_subst(xml_data_node *node, const char *attribute, int defvalue)
+{
+ const char *string = xml_get_attribute_string_with_subst(node, attribute, NULL);
+ int value;
+
+ if (!string || sscanf(string, "%d", &value) != 1)
+ return defvalue;
+ return value;
+}
+
+
+/*-------------------------------------------------
+ xml_get_attribute_float_with_subst - analog
+ to xml_get_attribute_float but with variable
+ substitution
+-------------------------------------------------*/
+
+static float xml_get_attribute_float_with_subst(xml_data_node *node, const char *attribute, float defvalue)
+{
+ const char *string = xml_get_attribute_string_with_subst(node, attribute, NULL);
+ float value;
+
+ if (!string || sscanf(string, "%f", &value) != 1)
+ return defvalue;
+ return value;
+}
+
+
+/*-------------------------------------------------
+ layout_file_load - parse a layout XML file
+ into a layout_file
+-------------------------------------------------*/
+
+layout_file *layout_file_load(const char *dirname, const char *filename)
+{
+ xml_data_node *rootnode, *mamelayoutnode, *elemnode, *viewnode;
+ layout_element **elemnext;
+ layout_view **viewnext;
+ layout_file *file;
+ int version;
+
+ /* if the first character of the "file" is an open brace, assume it is an XML string */
+ if (filename[0] == '<')
+ rootnode = xml_string_read(filename, NULL);
+
+ /* otherwise, assume it is a file */
+ else
+ {
+ file_error filerr;
+ mame_file *layoutfile;
+ astring *fname;
+
+ fname = astring_assemble_2(astring_alloc(), filename, ".lay");
+ if (dirname != NULL)
+ {
+ astring_insc(fname, 0, PATH_SEPARATOR);
+ astring_insc(fname, 0, dirname);
+ }
+ filerr = mame_fopen(SEARCHPATH_ARTWORK, astring_c(fname), OPEN_FLAG_READ, &layoutfile);
+ astring_free(fname);
+
+ if (filerr != FILERR_NONE)
+ return NULL;
+ rootnode = xml_file_read(mame_core_file(layoutfile), NULL);
+ mame_fclose(layoutfile);
+ }
+
+ /* if unable to parse the file, just bail */
+ if (rootnode == NULL)
+ return NULL;
+
+ /* allocate the layout group object first */
+ file = malloc_or_die(sizeof(*file));
+ memset(file, 0, sizeof(*file));
+
+ /* find the layout node */
+ mamelayoutnode = xml_get_sibling(rootnode->child, "mamelayout");
+ if (mamelayoutnode == NULL)
+ fatalerror("Invalid XML file: missing mamelayout node");
+
+ /* validate the config data version */
+ version = xml_get_attribute_int(mamelayoutnode, "version", 0);
+ if (version != LAYOUT_VERSION)
+ fatalerror("Invalid XML file: unsupported version");
+
+ /* parse all the elements */
+ file->elemlist = NULL;
+ elemnext = &file->elemlist;
+ for (elemnode = xml_get_sibling(mamelayoutnode->child, "element"); elemnode; elemnode = xml_get_sibling(elemnode->next, "element"))
+ {
+ layout_element *element = load_layout_element(elemnode, dirname);
+ if (element == NULL)
+ goto error;
+
+ /* add to the end of the list */
+ *elemnext = element;
+ elemnext = &element->next;
+ }
+
+ /* parse all the views */
+ file->viewlist = NULL;
+ viewnext = &file->viewlist;
+ for (viewnode = xml_get_sibling(mamelayoutnode->child, "view"); viewnode; viewnode = xml_get_sibling(viewnode->next, "view"))
+ {
+ layout_view *view = load_layout_view(viewnode, file->elemlist);
+ if (view == NULL)
+ goto error;
+
+ /* add to the end of the list */
+ *viewnext = view;
+ viewnext = &view->next;
+ }
+ xml_file_free(rootnode);
+ return file;
+
+error:
+ layout_file_free(file);
+ xml_file_free(rootnode);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ load_layout_element - parse an element XML
+ node from the layout file
+-------------------------------------------------*/
+
+static layout_element *load_layout_element(xml_data_node *elemnode, const char *dirname)
+{
+ render_bounds bounds = { 0 };
+ element_component **nextcomp;
+ element_component *component;
+ xml_data_node *compnode;
+ layout_element *element;
+ float xscale, yscale;
+ float xoffs, yoffs;
+ const char *name;
+ int state;
+ int first;
+
+ /* allocate a new element */
+ element = malloc_or_die(sizeof(*element));
+ memset(element, 0, sizeof(*element));
+
+ /* extract the name */
+ name = xml_get_attribute_string_with_subst(elemnode, "name", NULL);
+ if (name == NULL)
+ {
+ logerror("All layout elements must have a name!\n");
+ goto error;
+ }
+ element->name = copy_string(name);
+ element->defstate = xml_get_attribute_int_with_subst(elemnode, "defstate", -1);
+
+ /* parse components in order */
+ first = TRUE;
+ nextcomp = &element->complist;
+ for (compnode = elemnode->child; compnode; compnode = compnode->next)
+ {
+ /* allocate a new component */
+ element_component *component = load_element_component(compnode, dirname);
+ if (component == NULL)
+ goto error;
+
+ /* link it into the list */
+ *nextcomp = component;
+ nextcomp = &component->next;
+
+ /* accumulate bounds */
+ if (first)
+ bounds = component->bounds;
+ else
+ union_render_bounds(&bounds, &component->bounds);
+ first = FALSE;
+
+ /* determine the maximum state */
+ if (component->state > element->maxstate)
+ element->maxstate = component->state;
+ if (component->type == COMPONENT_TYPE_LED7SEG)
+ element->maxstate = 255;
+ if (component->type == COMPONENT_TYPE_LED14SEG)
+ element->maxstate = 16383;
+ if (component->type == COMPONENT_TYPE_LED14SEGSC || component->type == COMPONENT_TYPE_LED16SEG)
+ element->maxstate = 65535;
+ if (component->type == COMPONENT_TYPE_LED16SEGSC)
+ element->maxstate = 262143;
+ }
+
+ /* determine the scale/offset for normalization */
+ xoffs = bounds.x0;
+ yoffs = bounds.y0;
+ xscale = 1.0f / (bounds.x1 - bounds.x0);
+ yscale = 1.0f / (bounds.y1 - bounds.y0);
+
+ /* normalize all the component bounds */
+ for (component = element->complist; component != NULL; component = component->next)
+ {
+ component->bounds.x0 = (component->bounds.x0 - xoffs) * xscale;
+ component->bounds.x1 = (component->bounds.x1 - xoffs) * xscale;
+ component->bounds.y0 = (component->bounds.y0 - yoffs) * yscale;
+ component->bounds.y1 = (component->bounds.y1 - yoffs) * yscale;
+ }
+
+ /* allocate an array of element textures for the states */
+ element->elemtex = malloc_or_die((element->maxstate + 1) * sizeof(element->elemtex[0]));
+ for (state = 0; state <= element->maxstate; state++)
+ {
+ element->elemtex[state].element = element;
+ element->elemtex[state].state = state;
+ element->elemtex[state].texture = render_texture_alloc(layout_element_scale, &element->elemtex[state]);
+ }
+
+ return element;
+
+error:
+ layout_element_free(element);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ load_element_component - parse a component
+ XML node (image/rect/disk)
+-------------------------------------------------*/
+
+static element_component *load_element_component(xml_data_node *compnode, const char *dirname)
+{
+ element_component *component;
+
+ /* allocate memory for the component */
+ component = malloc_or_die(sizeof(*component));
+ memset(component, 0, sizeof(*component));
+
+ /* fetch common data */
+ component->state = xml_get_attribute_int_with_subst(compnode, "state", -1);
+ if (load_bounds(xml_get_sibling(compnode->child, "bounds"), &component->bounds))
+ goto error;
+ if (load_color(xml_get_sibling(compnode->child, "color"), &component->color))
+ goto error;
+
+ /* image nodes */
+ if (strcmp(compnode->name, "image") == 0)
+ {
+ const char *file = xml_get_attribute_string_with_subst(compnode, "file", NULL);
+ const char *afile = xml_get_attribute_string_with_subst(compnode, "alphafile", NULL);
+
+ /* load and allocate the bitmap */
+ component->type = COMPONENT_TYPE_IMAGE;
+ component->dirname = (dirname == NULL) ? NULL : copy_string(dirname);
+ component->imagefile = (file == NULL) ? NULL : copy_string(file);
+ component->alphafile = (afile == NULL) ? NULL : copy_string(afile);
+ }
+
+ /* text nodes */
+ else if (strcmp(compnode->name, "text") == 0)
+ {
+ const char *text = xml_get_attribute_string_with_subst(compnode, "string", "");
+ char *string;
+
+ /* allocate a copy of the string */
+ component->type = COMPONENT_TYPE_TEXT;
+ string = malloc_or_die(strlen(text) + 1);
+ strcpy(string, text);
+ component->string = string;
+ }
+
+ /* led7seg nodes */
+ else if (strcmp(compnode->name, "led7seg") == 0)
+ component->type = COMPONENT_TYPE_LED7SEG;
+
+ /* led14seg nodes */
+ else if (strcmp(compnode->name, "led14seg") == 0)
+ component->type = COMPONENT_TYPE_LED14SEG;
+
+ /* led14segsc nodes */
+ else if (strcmp(compnode->name, "led14segsc") == 0)
+ component->type = COMPONENT_TYPE_LED14SEGSC;
+
+ /* led16seg nodes */
+ else if (strcmp(compnode->name, "led16seg") == 0)
+ component->type = COMPONENT_TYPE_LED16SEG;
+
+ /* led16segsc nodes */
+ else if (strcmp(compnode->name, "led16segsc") == 0)
+ component->type = COMPONENT_TYPE_LED16SEGSC;
+
+ /* rect nodes */
+ else if (strcmp(compnode->name, "rect") == 0)
+ component->type = COMPONENT_TYPE_RECT;
+
+ /* disk nodes */
+ else if (strcmp(compnode->name, "disk") == 0)
+ component->type = COMPONENT_TYPE_DISK;
+
+ /* error otherwise */
+ else
+ fatalerror("Unknown element component: %s", compnode->name);
+
+ return component;
+
+error:
+ free(component);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ load_layout_view - parse a view XML node
+-------------------------------------------------*/
+
+static layout_view *load_layout_view(xml_data_node *viewnode, layout_element *elemlist)
+{
+ xml_data_node *boundsnode;
+ view_item **itemnext;
+ layout_view *view;
+ int layer;
+
+ /* first allocate memory */
+ view = malloc_or_die(sizeof(*view));
+ memset(view, 0, sizeof(*view));
+
+ /* allocate a copy of the name */
+ view->name = copy_string(xml_get_attribute_string_with_subst(viewnode, "name", ""));
+
+ /* if we have a bounds item, load it */
+ boundsnode = xml_get_sibling(viewnode->child, "bounds");
+ if (boundsnode != NULL && load_bounds(xml_get_sibling(boundsnode, "bounds"), &view->expbounds))
+ goto error;
+
+ /* loop over all the layer types we support */
+ for (layer = 0; layer < ITEM_LAYER_MAX; layer++)
+ {
+ static const char *layer_node_name[ITEM_LAYER_MAX] = { "backdrop", "screen", "overlay", "bezel" };
+ xml_data_node *itemnode;
+
+ /* initialize the list */
+ view->itemlist[layer] = NULL;
+ itemnext = &view->itemlist[layer];
+
+ /* parse all of the elements of that type */
+ for (itemnode = xml_get_sibling(viewnode->child, layer_node_name[layer]); itemnode; itemnode = xml_get_sibling(itemnode->next, layer_node_name[layer]))
+ {
+ view_item *item = load_view_item(itemnode, elemlist);
+ if (!item)
+ goto error;
+
+ /* add to the end of the list */
+ *itemnext = item;
+ itemnext = &item->next;
+ }
+ }
+
+ /* recompute the data for the view */
+ layout_view_recompute(view, ~0);
+ return view;
+
+error:
+ layout_view_free(view);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ load_view_item - parse an item XML node
+-------------------------------------------------*/
+
+static view_item *load_view_item(xml_data_node *itemnode, layout_element *elemlist)
+{
+ view_item *item;
+ const char *name;
+
+ /* allocate a new item */
+ item = malloc_or_die(sizeof(*item));
+ memset(item, 0, sizeof(*item));
+
+ /* allocate a copy of the name */
+ item->name = copy_string(xml_get_attribute_string_with_subst(itemnode, "name", ""));
+
+ /* find the associated element */
+ name = xml_get_attribute_string_with_subst(itemnode, "element", NULL);
+ if (name != NULL)
+ {
+ layout_element *element;
+
+ /* search the list of elements for a match */
+ for (element = elemlist; element; element = element->next)
+ if (strcmp(name, element->name) == 0)
+ break;
+
+ /* error if not found */
+ if (element == NULL)
+ fatalerror("Unable to find layout element %s", name);
+ item->element = element;
+ }
+
+ /* fetch common data */
+ item->index = xml_get_attribute_int_with_subst(itemnode, "index", -1);
+ if (item->name[0] != 0 && item->element != 0)
+ output_set_value(item->name, item->element->defstate);
+ if (load_bounds(xml_get_sibling(itemnode->child, "bounds"), &item->rawbounds))
+ goto error;
+ if (load_color(xml_get_sibling(itemnode->child, "color"), &item->color))
+ goto error;
+ if (load_orientation(xml_get_sibling(itemnode->child, "orientation"), &item->orientation))
+ goto error;
+
+ /* sanity checks */
+ if (strcmp(itemnode->name, "screen") == 0)
+ {
+ if (item->index >= MAX_SCREENS)
+ fatalerror("Layout references invalid screen index %d", item->index);
+ }
+ else
+ {
+ if (item->element == NULL)
+ fatalerror("Layout item of type %s require an element tag", itemnode->name);
+ }
+
+ return item;
+
+error:
+ if (item->name != NULL)
+ free((void *)item->name);
+ free(item);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ load_component_bitmap - load a PNG file
+ with artwork for a component
+-------------------------------------------------*/
+
+static mame_bitmap *load_component_bitmap(const char *dirname, const char *file, const char *alphafile, int *hasalpha)
+{
+ mame_bitmap *bitmap;
+
+ /* load the basic bitmap */
+ bitmap = render_load_png(dirname, file, NULL, hasalpha);
+ if (bitmap != NULL && alphafile != NULL)
+
+ /* load the alpha bitmap if specified */
+ if (render_load_png(dirname, alphafile, bitmap, hasalpha) == NULL)
+ {
+ bitmap_free(bitmap);
+ bitmap = NULL;
+ }
+
+ /* if we can't load the bitmap, allocate a dummy one and report an error */
+ if (bitmap == NULL)
+ {
+ int step, line;
+
+ /* draw some stripes in the bitmap */
+ bitmap = bitmap_alloc(100, 100, BITMAP_FORMAT_ARGB32);
+ fillbitmap(bitmap, 0, NULL);
+ for (step = 0; step < 100; step += 25)
+ for (line = 0; line < 100; line++)
+ *BITMAP_ADDR32(bitmap, (step + line) % 100, line % 100) = MAKE_ARGB(0xff,0xff,0xff,0xff);
+
+ /* log an error */
+ if (alphafile == NULL)
+ logerror("Unable to load component bitmap '%s'", file);
+ else
+ logerror("Unable to load component bitmap '%s'/'%s'", file, alphafile);
+ }
+
+ return bitmap;
+}
+
+
+/*-------------------------------------------------
+ load_bounds - parse a bounds XML node
+-------------------------------------------------*/
+
+static int load_bounds(xml_data_node *boundsnode, render_bounds *bounds)
+{
+ /* skip if nothing */
+ if (boundsnode == NULL)
+ {
+ bounds->x0 = bounds->y0 = 0.0f;
+ bounds->x1 = bounds->y1 = 1.0f;
+ return 0;
+ }
+
+ /* parse out the data */
+ if (xml_get_attribute(boundsnode, "left") != NULL)
+ {
+ /* left/right/top/bottom format */
+ bounds->x0 = xml_get_attribute_float_with_subst(boundsnode, "left", 0.0);
+ bounds->x1 = xml_get_attribute_float_with_subst(boundsnode, "right", 1.0);
+ bounds->y0 = xml_get_attribute_float_with_subst(boundsnode, "top", 0.0);
+ bounds->y1 = xml_get_attribute_float_with_subst(boundsnode, "bottom", 1.0);
+ }
+ else if (xml_get_attribute(boundsnode, "x") != NULL)
+ {
+ /* x/y/width/height format */
+ bounds->x0 = xml_get_attribute_float_with_subst(boundsnode, "x", 0.0);
+ bounds->x1 = bounds->x0 + xml_get_attribute_float_with_subst(boundsnode, "width", 1.0);
+ bounds->y0 = xml_get_attribute_float_with_subst(boundsnode, "y", 0.0);
+ bounds->y1 = bounds->y0 + xml_get_attribute_float_with_subst(boundsnode, "height", 1.0);
+ }
+ else
+ {
+ fatalerror("Illegal bounds value in XML");
+ return 1;
+ }
+
+ /* check for errors */
+ if (bounds->x0 > bounds->x1 || bounds->y0 > bounds->y1)
+ {
+ fatalerror("Illegal bounds value in XML: (%f-%f)-(%f-%f)", bounds->x0, bounds->x1, bounds->y0, bounds->y1);
+ return 1;
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ load_color - parse a color XML node
+-------------------------------------------------*/
+
+static int load_color(xml_data_node *colornode, render_color *color)
+{
+ /* skip if nothing */
+ if (colornode == NULL)
+ {
+ color->r = color->g = color->b = color->a = 1.0f;
+ return 0;
+ }
+
+ /* parse out the data */
+ color->r = xml_get_attribute_float_with_subst(colornode, "red", 1.0);
+ color->g = xml_get_attribute_float_with_subst(colornode, "green", 1.0);
+ color->b = xml_get_attribute_float_with_subst(colornode, "blue", 1.0);
+ color->a = xml_get_attribute_float_with_subst(colornode, "alpha", 1.0);
+
+ /* check for errors */
+ if (color->r < 0.0 || color->r > 1.0 || color->g < 0.0 || color->g > 1.0 ||
+ color->b < 0.0 || color->b > 1.0 || color->a < 0.0 || color->a > 1.0)
+ {
+ fatalerror("Illegal ARGB color value in XML: %f,%f,%f,%f", color->r, color->g, color->b, color->a);
+ return 1;
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ load_orientation - parse an orientation XML
+ node
+-------------------------------------------------*/
+
+static int load_orientation(xml_data_node *orientnode, int *orientation)
+{
+ int rotate;
+
+ /* skip if nothing */
+ if (orientnode == NULL)
+ {
+ *orientation = ROT0;
+ return 0;
+ }
+
+ /* parse out the data */
+ rotate = xml_get_attribute_int_with_subst(orientnode, "rotate", 0);
+ switch (rotate)
+ {
+ case 0: *orientation = ROT0; break;
+ case 90: *orientation = ROT90; break;
+ case 180: *orientation = ROT180; break;
+ case 270: *orientation = ROT270; break;
+ default:
+ fatalerror("Invalid rotation in XML orientation node: %d", rotate);
+ return 1;
+ }
+ if (strcmp("yes", xml_get_attribute_string_with_subst(orientnode, "swapxy", "no")) == 0)
+ *orientation ^= ORIENTATION_SWAP_XY;
+ if (strcmp("yes", xml_get_attribute_string_with_subst(orientnode, "flipx", "no")) == 0)
+ *orientation ^= ORIENTATION_FLIP_X;
+ if (strcmp("yes", xml_get_attribute_string_with_subst(orientnode, "flipy", "no")) == 0)
+ *orientation ^= ORIENTATION_FLIP_Y;
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ layout_file_free - free memory for a
+ layout_file and all of its subelements
+-------------------------------------------------*/
+
+void layout_file_free(layout_file *file)
+{
+ /* free each element in the list */
+ while (file->elemlist != NULL)
+ {
+ layout_element *temp = file->elemlist;
+ file->elemlist = temp->next;
+ layout_element_free(temp);
+ }
+
+ /* free each layout */
+ while (file->viewlist != NULL)
+ {
+ layout_view *temp = file->viewlist;
+ file->viewlist = temp->next;
+ layout_view_free(temp);
+ }
+
+ /* free the file itself */
+ free(file);
+}
+
+
+/*-------------------------------------------------
+ layout_view_free - free memory for a
+ layout_view and all of its subelements
+-------------------------------------------------*/
+
+static void layout_view_free(layout_view *view)
+{
+ int layer;
+
+ /* for each layer, free each item in that layer */
+ for (layer = 0; layer < ITEM_LAYER_MAX; layer++)
+ while (view->itemlist[layer] != NULL)
+ {
+ view_item *temp = view->itemlist[layer];
+ view->itemlist[layer] = temp->next;
+ if (temp->name != NULL)
+ free((void *)temp->name);
+ free(temp);
+ }
+
+ /* free the view itself */
+ if (view->name != NULL)
+ free((void *)view->name);
+ free(view);
+}
+
+
+/*-------------------------------------------------
+ layout_element_free - free memory for a
+ layout_element and its components
+-------------------------------------------------*/
+
+static void layout_element_free(layout_element *element)
+{
+ /* free all allocated components */
+ while (element->complist != NULL)
+ {
+ element_component *temp = element->complist;
+ element->complist = temp->next;
+ if (temp->string != NULL)
+ free((void *)temp->string);
+ if (temp->dirname != NULL)
+ free((void *)temp->dirname);
+ if (temp->imagefile != NULL)
+ free((void *)temp->imagefile);
+ if (temp->alphafile != NULL)
+ free((void *)temp->alphafile);
+ if (temp->bitmap != NULL)
+ bitmap_free(temp->bitmap);
+ free(temp);
+ }
+
+ /* free all textures */
+ if (element->elemtex != NULL)
+ {
+ int state;
+
+ /* loop over all states and free their textures */
+ for (state = 0; state <= element->maxstate; state++)
+ if (element->elemtex[state].texture != NULL)
+ render_texture_free(element->elemtex[state].texture);
+
+ free(element->elemtex);
+ }
+
+ /* free the element itself */
+ if (element->name != NULL)
+ free((void *)element->name);
+ free(element);
+}
diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h
new file mode 100644
index 00000000000..6f980d63d50
--- /dev/null
+++ b/src/emu/rendlay.h
@@ -0,0 +1,218 @@
+/***************************************************************************
+
+ rendlay.h
+
+ Core rendering layout parser and manager.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __RENDLAY_H__
+#define __RENDLAY_H__
+
+#include "driver.h"
+#include "osdepend.h"
+#include "render.h"
+
+#include <math.h>
+
+
+
+/***************************************************************************
+
+ Theory of operation
+ -------------------
+
+ A render "target" is described by 5 parameters:
+
+ - width = width, in pixels
+ - height = height, in pixels
+ - bpp = depth, in bits per pixel
+ - orientation = orientation of the target
+ - pixel_aspect = aspect ratio of the pixels
+
+ Width, height, and bpp are self-explanatory. The remaining parameters
+ need some additional explanation.
+
+ Regarding orientation, there are three orientations that need to be
+ dealt with: target orientation, UI orientation, and game orientation.
+ In the current model, the UI orientation tracks the target orientation
+ so that the UI is (in theory) facing the correct direction. The game
+ orientation is specified by the game driver and indicates how the
+ game and artwork are rotated.
+
+ Regarding pixel_aspect, this is the aspect ratio of the individual
+ pixels, not the aspect ratio of the screen. You can determine this by
+ dividing the aspect ratio of the screen by the aspect ratio of the
+ resolution. For example, a 4:3 screen displaying 640x480 gives a
+ pixel aspect ratio of (4/3)/(640/480) = 1.0, meaning the pixels are
+ square. That same screen displaying 1280x1024 would have a pixel
+ aspect ratio of (4/3)/(1280/1024) = 1.06666, meaning the pixels are
+ slightly wider than they are tall.
+
+ Artwork is always assumed to be a 1.0 pixel aspect ratio. The game
+ screens themselves can be variable aspect ratios.
+
+***************************************************************************/
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+enum
+{
+ ITEM_LAYER_BACKDROP = 0,
+ ITEM_LAYER_SCREEN,
+ ITEM_LAYER_OVERLAY,
+ ITEM_LAYER_BEZEL,
+ ITEM_LAYER_MAX
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _element_component element_component;
+typedef struct _element_texture element_texture;
+typedef struct _layout_element layout_element;
+typedef struct _view_item_state view_item_state;
+typedef struct _view_item view_item;
+typedef struct _layout_view layout_view;
+typedef struct _layout_file layout_file;
+
+/* an element_texture encapsulates a texture for a given element in a given state */
+struct _element_texture
+{
+ layout_element * element; /* pointer back to the element */
+ render_texture * texture; /* texture for this state */
+ int state; /* associated state number */
+};
+
+
+/* a layout_element is a single named element, which may have multiple components */
+struct _layout_element
+{
+ layout_element * next; /* link to next element */
+ const char * name; /* name of this element */
+ element_component * complist; /* head of the list of components */
+ int defstate; /* default state of this element */
+ int maxstate; /* maximum state value for all components */
+ element_texture * elemtex; /* array of element textures used for managing the scaled bitmaps */
+};
+
+
+/* a view_item_state contains the string-tagged state of a view item */
+struct _view_item_state
+{
+ view_item_state * next; /* pointer to the next one */
+ const char * name; /* string that was set */
+ int curstate; /* current state */
+};
+
+
+/* a view_item is a single backdrop, screen, overlay, or bezel item */
+struct _view_item
+{
+ view_item * next; /* link to next item */
+ layout_element * element; /* pointer to the associated element (non-screens only) */
+ const char * name; /* name of this item */
+ int index; /* index for this item (screens only) */
+ int orientation; /* orientation of this item */
+ render_bounds bounds; /* bounds of the item */
+ render_bounds rawbounds; /* raw (original) bounds of the item */
+ render_color color; /* color of the item */
+};
+
+
+/* a layout_view encapsulates a named list of items */
+struct _layout_view
+{
+ layout_view * next; /* pointer to next layout in the list */
+ const char * name; /* name of the layout */
+ float aspect; /* X/Y of the layout */
+ float scraspect; /* X/Y of the screen areas */
+ UINT32 screens; /* bitmask of screens used */
+ render_bounds bounds; /* computed bounds of the view */
+ render_bounds scrbounds; /* computed bounds of the screens within the view */
+ render_bounds expbounds; /* explicit bounds of the view */
+ UINT8 layenabled[ITEM_LAYER_MAX]; /* is this layer enabled? */
+ view_item * itemlist[ITEM_LAYER_MAX]; /* list of layout items for each layer */
+};
+
+
+/* a layout_file consists of a list of elements and a list of views */
+struct _layout_file
+{
+ layout_file * next; /* pointer to the next file in the list */
+ layout_element * elemlist; /* list of shared layout elements */
+ layout_view * viewlist; /* list of views */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* ----- layout views ----- */
+void layout_view_recompute(layout_view *view, int layerconfig);
+
+
+/* ----- layout file parsing ----- */
+layout_file *layout_file_load(const char *dirname, const char *filename);
+void layout_file_free(layout_file *file);
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* single screen layouts */
+extern const char layout_horizont[]; /* horizontal 4:3 screens */
+extern const char layout_vertical[]; /* vertical 4:3 screens */
+
+/* dual screen layouts */
+extern const char layout_dualhsxs[]; /* dual 4:3 screens side-by-side */
+extern const char layout_dualhovu[]; /* dual 4:3 screens above and below */
+extern const char layout_dualhuov[]; /* dual 4:3 screens below and above */
+
+/* triple screen layouts */
+extern const char layout_triphsxs[]; /* triple 4:3 screens side-by-side */
+
+/* generic color overlay layouts */
+extern const char layout_ho20ffff[]; /* horizontal 4:3 with 20,FF,FF color overlay */
+extern const char layout_ho2eff2e[]; /* horizontal 4:3 with 2E,FF,2E color overlay */
+extern const char layout_ho4f893d[]; /* horizontal 4:3 with 4F,89,3D color overlay */
+extern const char layout_ho88ffff[]; /* horizontal 4:3 with 88,FF,FF color overlay */
+extern const char layout_hoa0a0ff[]; /* horizontal 4:3 with A0,A0,FF color overlay */
+extern const char layout_hoffe457[]; /* horizontal 4:3 with FF,E4,57 color overlay */
+extern const char layout_hoffff20[]; /* horizontal 4:3 with FF,FF,20 color overlay */
+extern const char layout_voffff20[]; /* vertical 4:3 with FF,FF,20 color overlay */
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ layout_view_has_art - true if a render_view contains
+ any non-screen elements
+-------------------------------------------------*/
+
+INLINE int layout_view_has_art(layout_view *view)
+{
+ return (view->itemlist[ITEM_LAYER_BACKDROP] != 0 ||
+ view->itemlist[ITEM_LAYER_OVERLAY] != 0 ||
+ view->itemlist[ITEM_LAYER_BEZEL] != 0);
+}
+
+
+
+#endif /* __RENDLAY_H__ */
diff --git a/src/emu/rendutil.c b/src/emu/rendutil.c
new file mode 100644
index 00000000000..f5a1727a399
--- /dev/null
+++ b/src/emu/rendutil.c
@@ -0,0 +1,772 @@
+/***************************************************************************
+
+ rendutil.c
+
+ Core rendering utilities.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "render.h"
+#include "rendutil.h"
+#include "png.h"
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* utilities */
+static void resample_argb_bitmap_average(UINT32 *dest, UINT32 drowpixels, UINT32 dwidth, UINT32 dheight, const UINT32 *source, UINT32 srowpixels, UINT32 swidth, UINT32 sheight, const render_color *color, UINT32 dx, UINT32 dy);
+static void resample_argb_bitmap_bilinear(UINT32 *dest, UINT32 drowpixels, UINT32 dwidth, UINT32 dheight, const UINT32 *source, UINT32 srowpixels, UINT32 swidth, UINT32 sheight, const render_color *color, UINT32 dx, UINT32 dy);
+static void copy_png_to_bitmap(mame_bitmap *bitmap, const png_info *png, int *hasalpha);
+static void copy_png_alpha_to_bitmap(mame_bitmap *bitmap, const png_info *png, int *hasalpha);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ compute_brightness - compute the effective
+ brightness for an RGB pixel
+-------------------------------------------------*/
+
+INLINE UINT8 compute_brightness(rgb_t rgb)
+{
+ return (RGB_RED(rgb) * 222 + RGB_GREEN(rgb) * 707 + RGB_BLUE(rgb) * 71) / 1000;
+}
+
+
+
+/***************************************************************************
+ RENDER UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ render_resample_argb_bitmap_hq - perform a high
+ quality resampling of a texture
+-------------------------------------------------*/
+
+void render_resample_argb_bitmap_hq(void *dest, UINT32 drowpixels, UINT32 dwidth, UINT32 dheight, const mame_bitmap *source, const rectangle *orig_sbounds, const render_color *color)
+{
+ UINT32 swidth, sheight;
+ const UINT32 *sbase;
+ rectangle sbounds;
+ UINT32 dx, dy;
+
+ if (dwidth == 0 || dheight == 0)
+ return;
+
+ /* compute the real source bounds */
+ if (orig_sbounds != NULL)
+ sbounds = *orig_sbounds;
+ else
+ {
+ sbounds.min_x = sbounds.min_y = 0;
+ sbounds.max_x = source->width;
+ sbounds.max_y = source->height;
+ }
+
+ /* adjust the source base */
+ sbase = (const UINT32 *)source->base + sbounds.min_y * source->rowpixels + sbounds.min_x;
+
+ /* determine the steppings */
+ swidth = sbounds.max_x - sbounds.min_x;
+ sheight = sbounds.max_y - sbounds.min_y;
+ dx = (swidth << 12) / dwidth;
+ dy = (sheight << 12) / dheight;
+
+ /* if the source is higher res than the target, use full averaging */
+ if (dx > 0x1000 || dy > 0x1000)
+ resample_argb_bitmap_average(dest, drowpixels, dwidth, dheight, sbase, source->rowpixels, swidth, sheight, color, dx, dy);
+ else
+ resample_argb_bitmap_bilinear(dest, drowpixels, dwidth, dheight, sbase, source->rowpixels, swidth, sheight, color, dx, dy);
+}
+
+
+/*-------------------------------------------------
+ resample_argb_bitmap_average - resample a texture
+ by performing a true weighted average over
+ all contributing pixels
+-------------------------------------------------*/
+
+static void resample_argb_bitmap_average(UINT32 *dest, UINT32 drowpixels, UINT32 dwidth, UINT32 dheight, const UINT32 *source, UINT32 srowpixels, UINT32 swidth, UINT32 sheight, const render_color *color, UINT32 dx, UINT32 dy)
+{
+ UINT64 sumscale = (UINT64)dx * (UINT64)dy;
+ UINT32 r, g, b, a;
+ UINT32 x, y;
+
+ /* precompute premultiplied R/G/B/A factors */
+ r = color->r * color->a * 256.0;
+ g = color->g * color->a * 256.0;
+ b = color->b * color->a * 256.0;
+ a = color->a * 256.0;
+
+ /* loop over the target vertically */
+ for (y = 0; y < dheight; y++)
+ {
+ UINT32 starty = y * dy;
+
+ /* loop over the target horizontally */
+ for (x = 0; x < dwidth; x++)
+ {
+ UINT64 sumr = 0, sumg = 0, sumb = 0, suma = 0;
+ UINT32 startx = x * dx;
+ UINT32 xchunk, ychunk;
+ UINT32 curx, cury;
+
+ UINT32 yremaining = dy;
+
+ /* accumulate all source pixels that contribute to this pixel */
+ for (cury = starty; yremaining; cury += ychunk)
+ {
+ UINT32 xremaining = dx;
+
+ /* determine the Y contribution, clamping to the amount remaining */
+ ychunk = 0x1000 - (cury & 0xfff);
+ if (ychunk > yremaining)
+ ychunk = yremaining;
+ yremaining -= ychunk;
+
+ /* loop over all source pixels in the X direction */
+ for (curx = startx; xremaining; curx += xchunk)
+ {
+ UINT32 factor;
+ UINT32 pix;
+
+ /* determine the X contribution, clamping to the amount remaining */
+ xchunk = 0x1000 - (curx & 0xfff);
+ if (xchunk > xremaining)
+ xchunk = xremaining;
+ xremaining -= xchunk;
+
+ /* total contribution = x * y */
+ factor = xchunk * ychunk;
+
+ /* fetch the source pixel */
+ pix = source[(cury >> 12) * srowpixels + (curx >> 12)];
+
+ /* accumulate the RGBA values */
+ sumr += factor * RGB_RED(pix);
+ sumg += factor * RGB_GREEN(pix);
+ sumb += factor * RGB_BLUE(pix);
+ suma += factor * RGB_ALPHA(pix);
+ }
+ }
+
+ /* apply scaling */
+ suma = (suma / sumscale) * a / 256;
+ sumr = (sumr / sumscale) * r / 256;
+ sumg = (sumg / sumscale) * g / 256;
+ sumb = (sumb / sumscale) * b / 256;
+
+ /* if we're translucent, add in the destination pixel contribution */
+ if (a < 256)
+ {
+ UINT32 dpix = dest[y * drowpixels + x];
+ suma += RGB_ALPHA(dpix) * (256 - a);
+ sumr += RGB_RED(dpix) * (256 - a);
+ sumg += RGB_GREEN(dpix) * (256 - a);
+ sumb += RGB_BLUE(dpix) * (256 - a);
+ }
+
+ /* store the target pixel, dividing the RGBA values by the overall scale factor */
+ dest[y * drowpixels + x] = MAKE_ARGB(suma, sumr, sumg, sumb);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ resample_argb_bitmap_bilinear - perform texture
+ sampling via a bilinear filter
+-------------------------------------------------*/
+
+static void resample_argb_bitmap_bilinear(UINT32 *dest, UINT32 drowpixels, UINT32 dwidth, UINT32 dheight, const UINT32 *source, UINT32 srowpixels, UINT32 swidth, UINT32 sheight, const render_color *color, UINT32 dx, UINT32 dy)
+{
+ UINT32 maxx = swidth << 12, maxy = sheight << 12;
+ UINT32 r, g, b, a;
+ UINT32 x, y;
+
+ /* precompute premultiplied R/G/B/A factors */
+ r = color->r * color->a * 256.0;
+ g = color->g * color->a * 256.0;
+ b = color->b * color->a * 256.0;
+ a = color->a * 256.0;
+
+ /* loop over the target vertically */
+ for (y = 0; y < dheight; y++)
+ {
+ UINT32 starty = y * dy;
+
+ /* loop over the target horizontally */
+ for (x = 0; x < dwidth; x++)
+ {
+ UINT32 startx = x * dx;
+ UINT32 pix0, pix1, pix2, pix3;
+ UINT32 sumr, sumg, sumb, suma;
+ UINT32 nextx, nexty;
+ UINT32 curx, cury;
+ UINT32 factor;
+
+ /* adjust start to the center; note that this math will tend to produce */
+ /* negative results on the first pixel, which is why we clamp below */
+ curx = startx + dx / 2 - 0x800;
+ cury = starty + dy / 2 - 0x800;
+
+ /* compute the neighboring pixel */
+ nextx = curx + 0x1000;
+ nexty = cury + 0x1000;
+
+ /* fetch the four relevant pixels */
+ pix0 = pix1 = pix2 = pix3 = 0;
+ if ((INT32)cury >= 0 && cury < maxy && (INT32)curx >= 0 && curx < maxx)
+ pix0 = source[(cury >> 12) * srowpixels + (curx >> 12)];
+ if ((INT32)cury >= 0 && cury < maxy && (INT32)nextx >= 0 && nextx < maxx)
+ pix1 = source[(cury >> 12) * srowpixels + (nextx >> 12)];
+ if ((INT32)nexty >= 0 && nexty < maxy && (INT32)curx >= 0 && curx < maxx)
+ pix2 = source[(nexty >> 12) * srowpixels + (curx >> 12)];
+ if ((INT32)nexty >= 0 && nexty < maxy && (INT32)nextx >= 0 && nextx < maxx)
+ pix3 = source[(nexty >> 12) * srowpixels + (nextx >> 12)];
+
+ /* compute the x/y scaling factors */
+ curx &= 0xfff;
+ cury &= 0xfff;
+
+ /* contributions from pixel 0 (top,left) */
+ factor = (0x1000 - curx) * (0x1000 - cury);
+ sumr = factor * RGB_RED(pix0);
+ sumg = factor * RGB_GREEN(pix0);
+ sumb = factor * RGB_BLUE(pix0);
+ suma = factor * RGB_ALPHA(pix0);
+
+ /* contributions from pixel 1 (top,right) */
+ factor = curx * (0x1000 - cury);
+ sumr += factor * RGB_RED(pix1);
+ sumg += factor * RGB_GREEN(pix1);
+ sumb += factor * RGB_BLUE(pix1);
+ suma += factor * RGB_ALPHA(pix1);
+
+ /* contributions from pixel 2 (bottom,left) */
+ factor = (0x1000 - curx) * cury;
+ sumr += factor * RGB_RED(pix2);
+ sumg += factor * RGB_GREEN(pix2);
+ sumb += factor * RGB_BLUE(pix2);
+ suma += factor * RGB_ALPHA(pix2);
+
+ /* contributions from pixel 3 (bottom,right) */
+ factor = curx * cury;
+ sumr += factor * RGB_RED(pix3);
+ sumg += factor * RGB_GREEN(pix3);
+ sumb += factor * RGB_BLUE(pix3);
+ suma += factor * RGB_ALPHA(pix3);
+
+ /* apply scaling */
+ suma = (suma >> 24) * a / 256;
+ sumr = (sumr >> 24) * r / 256;
+ sumg = (sumg >> 24) * g / 256;
+ sumb = (sumb >> 24) * b / 256;
+
+ /* if we're translucent, add in the destination pixel contribution */
+ if (a < 256)
+ {
+ UINT32 dpix = dest[y * drowpixels + x];
+ suma += RGB_ALPHA(dpix) * (256 - a);
+ sumr += RGB_RED(dpix) * (256 - a);
+ sumg += RGB_GREEN(dpix) * (256 - a);
+ sumb += RGB_BLUE(dpix) * (256 - a);
+ }
+
+ /* store the target pixel, dividing the RGBA values by the overall scale factor */
+ dest[y * drowpixels + x] = MAKE_ARGB(suma, sumr, sumg, sumb);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ render_clip_line - clip a line to a rectangle
+-------------------------------------------------*/
+
+int render_clip_line(render_bounds *bounds, const render_bounds *clip)
+{
+ /* loop until we get a final result */
+ while (1)
+ {
+ UINT8 code0 = 0, code1 = 0;
+ UINT8 thiscode;
+ float x, y;
+
+ /* compute Cohen Sutherland bits for first coordinate */
+ if (bounds->y0 > clip->y1)
+ code0 |= 1;
+ if (bounds->y0 < clip->y0)
+ code0 |= 2;
+ if (bounds->x0 > clip->x1)
+ code0 |= 4;
+ if (bounds->x0 < clip->x0)
+ code0 |= 8;
+
+ /* compute Cohen Sutherland bits for second coordinate */
+ if (bounds->y1 > clip->y1)
+ code1 |= 1;
+ if (bounds->y1 < clip->y0)
+ code1 |= 2;
+ if (bounds->x1 > clip->x1)
+ code1 |= 4;
+ if (bounds->x1 < clip->x0)
+ code1 |= 8;
+
+ /* trivial accept: just return FALSE */
+ if ((code0 | code1) == 0)
+ return FALSE;
+
+ /* trivial reject: just return TRUE */
+ if ((code0 & code1) != 0)
+ return TRUE;
+
+ /* fix one of the OOB cases */
+ thiscode = code0 ? code0 : code1;
+
+ /* off the bottom */
+ if (thiscode & 1)
+ {
+ x = bounds->x0 + (bounds->x1 - bounds->x0) * (clip->y1 - bounds->y0) / (bounds->y1 - bounds->y0);
+ y = clip->y1;
+ }
+
+ /* off the top */
+ else if (thiscode & 2)
+ {
+ x = bounds->x0 + (bounds->x1 - bounds->x0) * (clip->y0 - bounds->y0) / (bounds->y1 - bounds->y0);
+ y = clip->y0;
+ }
+
+ /* off the right */
+ else if (thiscode & 4)
+ {
+ y = bounds->y0 + (bounds->y1 - bounds->y0) * (clip->x1 - bounds->x0) / (bounds->x1 - bounds->x0);
+ x = clip->x1;
+ }
+
+ /* off the left */
+ else
+ {
+ y = bounds->y0 + (bounds->y1 - bounds->y0) * (clip->x0 - bounds->x0) / (bounds->x1 - bounds->x0);
+ x = clip->x0;
+ }
+
+ /* fix the appropriate coordinate */
+ if (thiscode == code0)
+ {
+ bounds->x0 = x;
+ bounds->y0 = y;
+ }
+ else
+ {
+ bounds->x1 = x;
+ bounds->y1 = y;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ render_clip_quad - clip a quad to a rectangle
+-------------------------------------------------*/
+
+int render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords)
+{
+ /* ensure our assumptions about the bounds are correct */
+ assert(bounds->x0 <= bounds->x1);
+ assert(bounds->y0 <= bounds->y1);
+
+ /* trivial reject */
+ if (bounds->y1 < clip->y0)
+ return TRUE;
+ if (bounds->y0 > clip->y1)
+ return TRUE;
+ if (bounds->x1 < clip->x0)
+ return TRUE;
+ if (bounds->x0 > clip->x1)
+ return TRUE;
+
+ /* clip top (x0,y0)-(x1,y1) */
+ if (bounds->y0 < clip->y0)
+ {
+ float frac = (clip->y0 - bounds->y0) / (bounds->y1 - bounds->y0);
+ bounds->y0 = clip->y0;
+ if (texcoords != NULL)
+ {
+ texcoords->tl.u += (texcoords->bl.u - texcoords->tl.u) * frac;
+ texcoords->tl.v += (texcoords->bl.v - texcoords->tl.v) * frac;
+ texcoords->tr.u += (texcoords->br.u - texcoords->tr.u) * frac;
+ texcoords->tr.v += (texcoords->br.v - texcoords->tr.v) * frac;
+ }
+ }
+
+ /* clip bottom (x3,y3)-(x2,y2) */
+ if (bounds->y1 > clip->y1)
+ {
+ float frac = (bounds->y1 - clip->y1) / (bounds->y1 - bounds->y0);
+ bounds->y1 = clip->y1;
+ if (texcoords != NULL)
+ {
+ texcoords->bl.u -= (texcoords->bl.u - texcoords->tl.u) * frac;
+ texcoords->bl.v -= (texcoords->bl.v - texcoords->tl.v) * frac;
+ texcoords->br.u -= (texcoords->br.u - texcoords->tr.u) * frac;
+ texcoords->br.v -= (texcoords->br.v - texcoords->tr.v) * frac;
+ }
+ }
+
+ /* clip left (x0,y0)-(x3,y3) */
+ if (bounds->x0 < clip->x0)
+ {
+ float frac = (clip->x0 - bounds->x0) / (bounds->x1 - bounds->x0);
+ bounds->x0 = clip->x0;
+ if (texcoords != NULL)
+ {
+ texcoords->tl.u += (texcoords->tr.u - texcoords->tl.u) * frac;
+ texcoords->tl.v += (texcoords->tr.v - texcoords->tl.v) * frac;
+ texcoords->bl.u += (texcoords->br.u - texcoords->bl.u) * frac;
+ texcoords->bl.v += (texcoords->br.v - texcoords->bl.v) * frac;
+ }
+ }
+
+ /* clip right (x1,y1)-(x2,y2) */
+ if (bounds->x1 > clip->x1)
+ {
+ float frac = (bounds->x1 - clip->x1) / (bounds->x1 - bounds->x0);
+ bounds->x1 = clip->x1;
+ if (texcoords != NULL)
+ {
+ texcoords->tr.u -= (texcoords->tr.u - texcoords->tl.u) * frac;
+ texcoords->tr.v -= (texcoords->tr.v - texcoords->tl.v) * frac;
+ texcoords->br.u -= (texcoords->br.u - texcoords->bl.u) * frac;
+ texcoords->br.v -= (texcoords->br.v - texcoords->bl.v) * frac;
+ }
+ }
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ render_line_to_quad - convert a line and a
+ width to four points
+-------------------------------------------------*/
+
+void render_line_to_quad(const render_bounds *bounds, float width, render_bounds *bounds0, render_bounds *bounds1)
+{
+ render_bounds modbounds = *bounds;
+ float unitx, unity;
+
+ /*
+ High-level logic -- due to math optimizations, this info is lost below.
+
+ Imagine a thick line of width (w), drawn from (p0) to (p1), with a unit
+ vector (u) indicating the direction from (p0) to (p1).
+
+ B C
+ +---------------- ... ------------------+
+ | ^ |
+ | | |
+ | | |
+ * (p0) ------------> (w)| * (p1)
+ | (u) | |
+ | | |
+ | v |
+ +---------------- ... ------------------+
+ A D
+
+ To convert this into a quad, we need to compute the four points A, B, C
+ and D.
+
+ Starting with point A. We first multiply the unit vector by 0.5w and then
+ rotate the result 90 degrees. Thus, we have:
+
+ A.x = p0.x + 0.5 * w * u.x * cos(90) - 0.5 * w * u.y * sin(90)
+ A.y = p0.y + 0.5 * w * u.x * sin(90) + 0.5 * w * u.y * cos(90)
+
+ Conveniently, sin(90) = 1, and cos(90) = 0, so this simplifies to:
+
+ A.x = p0.x - 0.5 * w * u.y
+ A.y = p0.y + 0.5 * w * u.x
+
+ Working clockwise around the polygon, the same fallout happens all around as
+ we rotate the unit vector by -90 (B), -90 (C), and 90 (D) degrees:
+
+ B.x = p0.x + 0.5 * w * u.y
+ B.y = p0.y - 0.5 * w * u.x
+
+ C.x = p1.x - 0.5 * w * u.y
+ C.y = p1.y + 0.5 * w * u.x
+
+ D.x = p1.x + 0.5 * w * u.y
+ D.y = p1.y - 0.5 * w * u.x
+ */
+
+ /* we only care about the half-width */
+ width *= 0.5f;
+
+ /* compute a vector from point 0 to point 1 */
+ unitx = modbounds.x1 - modbounds.x0;
+ unity = modbounds.y1 - modbounds.y0;
+
+ /* points just use a +1/+1 unit vector; this gives a nice diamond pattern */
+ if (unitx == 0 && unity == 0)
+ {
+ unitx = unity = 0.70710678f * width;
+ modbounds.x0 -= 0.5f * unitx;
+ modbounds.y0 -= 0.5f * unity;
+ modbounds.x1 += 0.5f * unitx;
+ modbounds.y1 += 0.5f * unity;
+ }
+
+ /* lines need to be divided by their length */
+ else
+ {
+ /* prescale unitx and unity by the half-width */
+ float invlength = width / sqrt(unitx * unitx + unity * unity);
+ unitx *= invlength;
+ unity *= invlength;
+ }
+
+ /* rotate the unit vector by 90 degrees and add to point 0 */
+ bounds0->x0 = modbounds.x0 - unity;
+ bounds0->y0 = modbounds.y0 + unitx;
+
+ /* rotate the unit vector by -90 degrees and add to point 0 */
+ bounds0->x1 = modbounds.x0 + unity;
+ bounds0->y1 = modbounds.y0 - unitx;
+
+ /* rotate the unit vector by 90 degrees and add to point 1 */
+ bounds1->x0 = modbounds.x1 - unity;
+ bounds1->y0 = modbounds.y1 + unitx;
+
+ /* rotate the unit vector by -09 degrees and add to point 1 */
+ bounds1->x1 = modbounds.x1 + unity;
+ bounds1->y1 = modbounds.y1 - unitx;
+}
+
+
+/*-------------------------------------------------
+ render_load_png - load a PNG file into a
+ mame_bitmap
+-------------------------------------------------*/
+
+mame_bitmap *render_load_png(const char *dirname, const char *filename, mame_bitmap *alphadest, int *hasalpha)
+{
+ mame_bitmap *bitmap = NULL;
+ file_error filerr;
+ mame_file *file;
+ png_info png;
+ astring *fname;
+ png_error result;
+
+ /* open the file */
+ if (dirname == NULL)
+ fname = astring_dupc(filename);
+ else
+ fname = astring_assemble_3(astring_alloc(), dirname, PATH_SEPARATOR, filename);
+ filerr = mame_fopen(SEARCHPATH_ARTWORK, astring_c(fname), OPEN_FLAG_READ, &file);
+ astring_free(fname);
+ if (filerr != FILERR_NONE)
+ return NULL;
+
+ /* read the PNG data */
+ result = png_read_file(mame_core_file(file), &png);
+ mame_fclose(file);
+ if (result != PNGERR_NONE)
+ return NULL;
+
+ /* verify we can handle this PNG */
+ if (png.bit_depth > 8)
+ {
+ logerror("%s: Unsupported bit depth %d (8 bit max)\n", filename, png.bit_depth);
+ png_free(&png);
+ return NULL;
+ }
+ if (png.interlace_method != 0)
+ {
+ logerror("%s: Interlace unsupported\n", filename);
+ png_free(&png);
+ return NULL;
+ }
+ if (png.color_type != 0 && png.color_type != 3 && png.color_type != 2 && png.color_type != 6)
+ {
+ logerror("%s: Unsupported color type %d\n", filename, png.color_type);
+ png_free(&png);
+ return NULL;
+ }
+
+ /* if less than 8 bits, upsample */
+ png_expand_buffer_8bit(&png);
+
+ /* non-alpha case */
+ if (alphadest == NULL)
+ {
+ bitmap = bitmap_alloc(png.width, png.height, BITMAP_FORMAT_ARGB32);
+ if (bitmap != NULL)
+ copy_png_to_bitmap(bitmap, &png, hasalpha);
+ }
+
+ /* alpha case */
+ else
+ {
+ if (png.width == alphadest->width && png.height == alphadest->height)
+ {
+ bitmap = alphadest;
+ copy_png_alpha_to_bitmap(bitmap, &png, hasalpha);
+ }
+ }
+
+ /* free PNG data */
+ png_free(&png);
+ return bitmap;
+}
+
+
+/*-------------------------------------------------
+ copy_png_to_bitmap - copy the PNG data to a
+ bitmap
+-------------------------------------------------*/
+
+static void copy_png_to_bitmap(mame_bitmap *bitmap, const png_info *png, int *hasalpha)
+{
+ UINT8 accumalpha = 0xff;
+ UINT8 *src;
+ int x, y;
+
+ /* handle 8bpp palettized case */
+ if (png->color_type == 3)
+ {
+ /* loop over width/height */
+ src = png->image;
+ for (y = 0; y < png->height; y++)
+ for (x = 0; x < png->width; x++, src++)
+ {
+ /* determine alpha and expand to 32bpp */
+ UINT8 alpha = (*src < png->num_trans) ? png->trans[*src] : 0xff;
+ accumalpha &= alpha;
+ *BITMAP_ADDR32(bitmap, y, x) = MAKE_ARGB(alpha, png->palette[*src * 3], png->palette[*src * 3 + 1], png->palette[*src * 3 + 2]);
+ }
+ }
+
+ /* handle 8bpp grayscale case */
+ else if (png->color_type == 0)
+ {
+ /* loop over width/height */
+ src = png->image;
+ for (y = 0; y < png->height; y++)
+ for (x = 0; x < png->width; x++, src++)
+ *BITMAP_ADDR32(bitmap, y, x) = MAKE_ARGB(0xff, *src, *src, *src);
+ }
+
+ /* handle 32bpp non-alpha case */
+ else if (png->color_type == 2)
+ {
+ /* loop over width/height */
+ src = png->image;
+ for (y = 0; y < png->height; y++)
+ for (x = 0; x < png->width; x++, src += 3)
+ *BITMAP_ADDR32(bitmap, y, x) = MAKE_ARGB(0xff, src[0], src[1], src[2]);
+ }
+
+ /* handle 32bpp alpha case */
+ else
+ {
+ /* loop over width/height */
+ src = png->image;
+ for (y = 0; y < png->height; y++)
+ for (x = 0; x < png->width; x++, src += 4)
+ {
+ accumalpha &= src[3];
+ *BITMAP_ADDR32(bitmap, y, x) = MAKE_ARGB(src[3], src[0], src[1], src[2]);
+ }
+ }
+
+ /* set the hasalpha flag */
+ if (hasalpha != NULL)
+ *hasalpha = (accumalpha != 0xff);
+}
+
+
+/*-------------------------------------------------
+ copy_png_alpha_to_bitmap - copy the PNG data
+ to the alpha channel of a bitmap
+-------------------------------------------------*/
+
+static void copy_png_alpha_to_bitmap(mame_bitmap *bitmap, const png_info *png, int *hasalpha)
+{
+ UINT8 accumalpha = 0xff;
+ UINT8 *src;
+ int x, y;
+
+ /* handle 8bpp palettized case */
+ if (png->color_type == 3)
+ {
+ /* loop over width/height */
+ src = png->image;
+ for (y = 0; y < png->height; y++)
+ for (x = 0; x < png->width; x++, src++)
+ {
+ rgb_t pixel = *BITMAP_ADDR32(bitmap, y, x);
+ UINT8 alpha = compute_brightness(MAKE_RGB(png->palette[*src * 3], png->palette[*src * 3 + 1], png->palette[*src * 3 + 2]));
+ accumalpha &= alpha;
+ *BITMAP_ADDR32(bitmap, y, x) = MAKE_ARGB(alpha, RGB_RED(pixel), RGB_GREEN(pixel), RGB_BLUE(pixel));
+ }
+ }
+
+ /* handle 8bpp grayscale case */
+ else if (png->color_type == 0)
+ {
+ /* loop over width/height */
+ src = png->image;
+ for (y = 0; y < png->height; y++)
+ for (x = 0; x < png->width; x++, src++)
+ {
+ rgb_t pixel = *BITMAP_ADDR32(bitmap, y, x);
+ accumalpha &= *src;
+ *BITMAP_ADDR32(bitmap, y, x) = MAKE_ARGB(*src, RGB_RED(pixel), RGB_GREEN(pixel), RGB_BLUE(pixel));
+ }
+ }
+
+ /* handle 32bpp non-alpha case */
+ else if (png->color_type == 2)
+ {
+ /* loop over width/height */
+ src = png->image;
+ for (y = 0; y < png->height; y++)
+ for (x = 0; x < png->width; x++, src += 3)
+ {
+ rgb_t pixel = *BITMAP_ADDR32(bitmap, y, x);
+ UINT8 alpha = compute_brightness(MAKE_RGB(src[0], src[1], src[2]));
+ accumalpha &= alpha;
+ *BITMAP_ADDR32(bitmap, y, x) = MAKE_ARGB(alpha, RGB_RED(pixel), RGB_GREEN(pixel), RGB_BLUE(pixel));
+ }
+ }
+
+ /* handle 32bpp alpha case */
+ else
+ {
+ /* loop over width/height */
+ src = png->image;
+ for (y = 0; y < png->height; y++)
+ for (x = 0; x < png->width; x++, src += 4)
+ {
+ rgb_t pixel = *BITMAP_ADDR32(bitmap, y, x);
+ UINT8 alpha = compute_brightness(MAKE_RGB(src[0], src[1], src[2]));
+ accumalpha &= alpha;
+ *BITMAP_ADDR32(bitmap, y, x) = MAKE_ARGB(alpha, RGB_RED(pixel), RGB_GREEN(pixel), RGB_BLUE(pixel));
+ }
+ }
+
+ /* set the hasalpha flag */
+ if (hasalpha != NULL)
+ *hasalpha = (accumalpha != 0xff);
+}
diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h
new file mode 100644
index 00000000000..58c526819ab
--- /dev/null
+++ b/src/emu/rendutil.h
@@ -0,0 +1,204 @@
+/***************************************************************************
+
+ rendutil.h
+
+ Core rendering utilities.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __RENDUTIL_H__
+#define __RENDUTIL_H__
+
+#include "driver.h"
+#include "osdepend.h"
+#include "render.h"
+
+#include <math.h>
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* ----- render utilities ----- */
+
+void render_resample_argb_bitmap_hq(void *dest, UINT32 drowpixels, UINT32 dwidth, UINT32 dheight, const mame_bitmap *source, const rectangle *sbounds, const render_color *color);
+int render_clip_line(render_bounds *bounds, const render_bounds *clip);
+int render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords);
+void render_line_to_quad(const render_bounds *bounds, float width, render_bounds *bounds0, render_bounds *bounds1);
+mame_bitmap *render_load_png(const char *dirname, const char *filename, mame_bitmap *alphadest, int *hasalpha);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ render_round_nearest - floating point
+ round-to-nearest
+-------------------------------------------------*/
+
+INLINE float render_round_nearest(float f)
+{
+ return floor(f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ set_render_bounds_xy - cleaner way to set the
+ bounds
+-------------------------------------------------*/
+
+INLINE void set_render_bounds_xy(render_bounds *bounds, float x0, float y0, float x1, float y1)
+{
+ bounds->x0 = x0;
+ bounds->y0 = y0;
+ bounds->x1 = x1;
+ bounds->y1 = y1;
+}
+
+
+/*-------------------------------------------------
+ set_render_bounds_wh - cleaner way to set the
+ bounds
+-------------------------------------------------*/
+
+INLINE void set_render_bounds_wh(render_bounds *bounds, float x0, float y0, float width, float height)
+{
+ bounds->x0 = x0;
+ bounds->y0 = y0;
+ bounds->x1 = x0 + width;
+ bounds->y1 = y0 + height;
+}
+
+
+/*-------------------------------------------------
+ sect_render_bounds - compute the intersection
+ of two render_bounds
+-------------------------------------------------*/
+
+INLINE void sect_render_bounds(render_bounds *dest, const render_bounds *src)
+{
+ dest->x0 = (dest->x0 > src->x0) ? dest->x0 : src->x0;
+ dest->x1 = (dest->x1 < src->x1) ? dest->x1 : src->x1;
+ dest->y0 = (dest->y0 > src->y0) ? dest->y0 : src->y0;
+ dest->y1 = (dest->y1 < src->y1) ? dest->y1 : src->y1;
+}
+
+
+/*-------------------------------------------------
+ union_render_bounds - compute the union of two
+ render_bounds
+-------------------------------------------------*/
+
+INLINE void union_render_bounds(render_bounds *dest, const render_bounds *src)
+{
+ dest->x0 = (dest->x0 < src->x0) ? dest->x0 : src->x0;
+ dest->x1 = (dest->x1 > src->x1) ? dest->x1 : src->x1;
+ dest->y0 = (dest->y0 < src->y0) ? dest->y0 : src->y0;
+ dest->y1 = (dest->y1 > src->y1) ? dest->y1 : src->y1;
+}
+
+
+/*-------------------------------------------------
+ set_render_color - cleaner way to set a color
+-------------------------------------------------*/
+
+INLINE void set_render_color(render_color *color, float a, float r, float g, float b)
+{
+ color->a = a;
+ color->r = r;
+ color->g = g;
+ color->b = b;
+}
+
+
+/*-------------------------------------------------
+ orientation_swap_flips - swap the X and Y
+ flip flags
+-------------------------------------------------*/
+
+INLINE int orientation_swap_flips(int orientation)
+{
+ return (orientation & ORIENTATION_SWAP_XY) |
+ ((orientation & ORIENTATION_FLIP_X) ? ORIENTATION_FLIP_Y : 0) |
+ ((orientation & ORIENTATION_FLIP_Y) ? ORIENTATION_FLIP_X : 0);
+}
+
+
+/*-------------------------------------------------
+ orientation_reverse - compute the orientation
+ that will undo another orientation
+-------------------------------------------------*/
+
+INLINE int orientation_reverse(int orientation)
+{
+ /* if not swapping X/Y, then just apply the same transform to reverse */
+ if (!(orientation & ORIENTATION_SWAP_XY))
+ return orientation;
+
+ /* if swapping X/Y, then swap X/Y flip bits to get the reverse */
+ else
+ return orientation_swap_flips(orientation);
+}
+
+
+/*-------------------------------------------------
+ orientation_add - compute effective orientation
+ after applying two subsequent orientations
+-------------------------------------------------*/
+
+INLINE int orientation_add(int orientation1, int orientation2)
+{
+ /* if the 2nd transform doesn't swap, just XOR together */
+ if (!(orientation2 & ORIENTATION_SWAP_XY))
+ return orientation1 ^ orientation2;
+
+ /* otherwise, we need to effectively swap the flip bits on the first transform */
+ else
+ return orientation_swap_flips(orientation1) ^ orientation2;
+}
+
+
+/*-------------------------------------------------
+ apply_brightness_contrast_gamma_fp - apply
+ brightness, contrast, and gamma controls to
+ a single RGB component
+-------------------------------------------------*/
+
+INLINE float apply_brightness_contrast_gamma_fp(float srcval, float brightness, float contrast, float gamma)
+{
+ /* first apply gamma */
+ srcval = pow(srcval, 1.0f / gamma);
+
+ /* then contrast/brightness */
+ srcval = (srcval * contrast) + brightness - 1.0f;
+
+ /* clamp and return */
+ if (srcval < 0.0f)
+ srcval = 0.0f;
+ if (srcval > 1.0f)
+ srcval = 1.0f;
+ return srcval;
+}
+
+
+/*-------------------------------------------------
+ apply_brightness_contrast_gamma - apply
+ brightness, contrast, and gamma controls to
+ a single RGB component
+-------------------------------------------------*/
+
+INLINE UINT8 apply_brightness_contrast_gamma(UINT8 src, float brightness, float contrast, float gamma)
+{
+ float srcval = (float)src * (1.0f / 255.0f);
+ float result = apply_brightness_contrast_gamma_fp(srcval, brightness, contrast, gamma);
+ return (UINT8)(result * 255.0f);
+}
+
+
+#endif /* __RENDUTIL_H__ */
diff --git a/src/emu/restrack.c b/src/emu/restrack.c
new file mode 100644
index 00000000000..3c4bdbe42ad
--- /dev/null
+++ b/src/emu/restrack.c
@@ -0,0 +1,368 @@
+/***************************************************************************
+
+ restrack.c
+
+ Core MAME resource tracking.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "restrack.h"
+#include "pool.h"
+#include "timer.h"
+#include "state.h"
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef enum _memory_block_overlap memory_block_overlap;
+enum _memory_block_overlap
+{
+ OVERLAP_NONE,
+ OVERLAP_PARTIAL,
+ OVERLAP_FULL
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* pool list */
+static object_pool *pools[64];
+
+/* resource tracking */
+int resource_tracking_tag = 0;
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+static void astring_destructor(void *object, size_t size);
+static void bitmap_destructor(void *object, size_t size);
+static memory_block_overlap pool_contains_block(object_pool *pool, void *ptr, size_t size, void **found_block, size_t *found_block_size);
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ malloc_or_die_file_line - allocate memory or die
+ trying
+-------------------------------------------------*/
+
+void *malloc_or_die_file_line(size_t size, const char *file, int line)
+{
+ void *result;
+
+ /* fail on attempted allocations of 0 */
+ if (size == 0)
+ fatalerror("Attempted to malloc zero bytes (%s:%d)", file, line);
+
+ /* allocate and return if we succeeded */
+#ifdef MALLOC_DEBUG
+ result = malloc_file_line(size, file, line);
+#else
+ result = malloc(size);
+#endif
+ if (result != NULL)
+ {
+#ifdef MAME_DEBUG
+ rand_memory(result, size);
+#endif
+ return result;
+ }
+
+ /* otherwise, die horribly */
+ fatalerror("Failed to allocate %d bytes (%s:%d)", (int)size, file, line);
+}
+
+
+/*-------------------------------------------------
+ init_resource_tracking - initialize the
+ resource tracking system
+-------------------------------------------------*/
+
+void init_resource_tracking(void)
+{
+ resource_tracking_tag = 0;
+}
+
+
+/*-------------------------------------------------
+ exit_resource_tracking - tear down the
+ resource tracking system
+-------------------------------------------------*/
+
+void exit_resource_tracking(void)
+{
+ while (resource_tracking_tag != 0)
+ end_resource_tracking();
+}
+
+
+/*-------------------------------------------------
+ memory_error - report a memory error
+-------------------------------------------------*/
+
+static void memory_error(const char *message)
+{
+ fatalerror("%s", message);
+}
+
+
+/*-------------------------------------------------
+ begin_resource_tracking - start tracking
+ resources
+-------------------------------------------------*/
+
+void begin_resource_tracking(void)
+{
+ object_pool *new_pool;
+
+ /* sanity check */
+ assert_always(resource_tracking_tag < ARRAY_LENGTH(pools), "Too many memory pools");
+
+ /* create a new pool */
+ new_pool = pool_alloc(memory_error);
+ if (!new_pool)
+ fatalerror("Failed to allocate new memory pool");
+ pools[resource_tracking_tag] = new_pool;
+
+ /* add resource types */
+ pool_type_register(new_pool, OBJTYPE_ASTRING, "String", astring_destructor);
+ pool_type_register(new_pool, OBJTYPE_BITMAP, "Bitmap", bitmap_destructor);
+ pool_type_register(new_pool, OBJTYPE_TIMER, "Timer", timer_destructor);
+ pool_type_register(new_pool, OBJTYPE_STATEREG, "Save State Registration", state_destructor);
+
+ /* increment the tag counter */
+ resource_tracking_tag++;
+}
+
+
+/*-------------------------------------------------
+ end_resource_tracking - stop tracking
+ resources
+-------------------------------------------------*/
+
+void end_resource_tracking(void)
+{
+ /* decrement the tag counter */
+ resource_tracking_tag--;
+
+ /* free the memory pool */
+ pool_free(pools[resource_tracking_tag]);
+ pools[resource_tracking_tag] = NULL;
+}
+
+
+/*-------------------------------------------------
+ current_pool - identifies the current memory
+ pool
+-------------------------------------------------*/
+
+static object_pool *current_pool(void)
+{
+ object_pool *pool;
+ assert_always((resource_tracking_tag > 0) && (resource_tracking_tag <= ARRAY_LENGTH(pools)), "Invalid resource_tracking_tag");
+ pool = pools[resource_tracking_tag - 1];
+ assert_always(pool != NULL, "current_pool() is NULL");
+ return pool;
+}
+
+
+/*-------------------------------------------------
+ restrack_register_object - registers an
+ object with the current pool
+-------------------------------------------------*/
+
+void *restrack_register_object(object_type type, void *ptr, size_t size, const char *file, int line)
+{
+ return pool_object_add_file_line(current_pool(), type, ptr, size, file, line);
+}
+
+
+/*-------------------------------------------------
+ auto_malloc_file_line - allocate auto-
+ freeing memory
+-------------------------------------------------*/
+
+void *auto_malloc_file_line(size_t size, const char *file, int line)
+{
+ return pool_malloc_file_line(current_pool(), size, file, line);
+}
+
+
+/*-------------------------------------------------
+ auto_realloc_file_line - reallocate auto-
+ freeing memory
+-------------------------------------------------*/
+
+void *auto_realloc_file_line(void *ptr, size_t size, const char *file, int line)
+{
+ object_pool *pool = current_pool();
+ if (ptr != NULL)
+ {
+ int tag = resource_tracking_tag;
+ for (; tag > 0; tag--)
+ {
+ pool = pools[tag - 1];
+ if (pool_object_exists(pool, OBJTYPE_MEMORY, ptr))
+ break;
+ }
+ assert_always(tag > 0, "Failed to find alloc in pool");
+ }
+
+ return pool_realloc_file_line(pool, ptr, size, file, line);
+}
+
+
+/*-------------------------------------------------
+ auto_strdup_file_line - allocate auto-freeing
+ string
+-------------------------------------------------*/
+
+char *auto_strdup_file_line(const char *str, const char *file, int line)
+{
+ return pool_strdup_file_line(current_pool(), str, file, line);
+}
+
+
+/*-------------------------------------------------
+ auto_strdup_allow_null_file_line - allocate
+ auto-freeing string if str is null
+-------------------------------------------------*/
+
+char *auto_strdup_allow_null_file_line(const char *str, const char *file, int line)
+{
+ return (str != NULL) ? auto_strdup_file_line(str, file, line) : NULL;
+}
+
+
+/*-------------------------------------------------
+ auto_astring_alloc_file_line - allocate
+ auto-freeing astring
+-------------------------------------------------*/
+
+astring *auto_astring_alloc_file_line(const char *file, int line)
+{
+ return restrack_register_object(OBJTYPE_ASTRING, astring_alloc(), 0, file, line);
+}
+
+
+/*-------------------------------------------------
+ auto_bitmap_alloc_file_line - allocate
+ auto-freeing bitmap
+-------------------------------------------------*/
+
+bitmap_t *auto_bitmap_alloc_file_line(int width, int height, bitmap_format format, const char *file, int line)
+{
+ return restrack_register_object(OBJTYPE_BITMAP, bitmap_alloc(width, height, format), width * height, file, line);
+}
+
+
+/*-------------------------------------------------
+ validate_auto_malloc_memory - validate that a
+ block of memory has been allocated by auto_malloc()
+-------------------------------------------------*/
+
+void validate_auto_malloc_memory(void *memory, size_t memory_size)
+{
+ memory_block_overlap overlap = OVERLAP_NONE;
+ void *block_base = NULL;
+ size_t block_size = 0;
+ int i;
+
+ /* scan all pools for an overlapping block */
+ for (i = 0; overlap == OVERLAP_NONE && i < resource_tracking_tag; i++)
+ overlap = pool_contains_block(pools[i], memory, memory_size, &block_base, &block_size);
+
+ /* fatal error if not a full overlap */
+ switch (overlap)
+ {
+ case OVERLAP_NONE:
+ fatalerror("Memory block [0x%p-0x%p] not found", memory, (UINT8 *)memory + memory_size - 1);
+ break;
+
+ case OVERLAP_PARTIAL:
+ fatalerror("Memory block [0x%p-0x%p] partially overlaps with allocated block [0x%p-0x%p]", memory, (UINT8 *)memory + memory_size - 1, block_base, (UINT8 *)block_base + block_size - 1);
+ break;
+
+ case OVERLAP_FULL:
+ /* expected outcome */
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ astring_destructor - destructor for astring
+ objects
+-------------------------------------------------*/
+
+static void astring_destructor(void *object, size_t size)
+{
+ astring_free(object);
+}
+
+
+/*-------------------------------------------------
+ bitmap_destructor - destructor for bitmap
+ objects
+-------------------------------------------------*/
+
+static void bitmap_destructor(void *object, size_t size)
+{
+ bitmap_free(object);
+}
+
+
+/*-------------------------------------------------
+ pool_contains_block - determines if a pool
+ contains a memory block
+-------------------------------------------------*/
+
+static memory_block_overlap pool_contains_block(object_pool *pool, void *ptr, size_t size, void **found_block, size_t *found_block_size)
+{
+ memory_block_overlap overlap = OVERLAP_NONE;
+ object_pool_iterator *iter;
+ UINT8 *ptrstart = ptr;
+ UINT8 *ptrend = ptrstart + size - 1;
+ void *blockptr = NULL;
+ size_t blocksize = 0;
+
+ /* iterate over memory objects in the pool */
+ for (iter = pool_iterate_begin(pool, OBJTYPE_MEMORY); iter != NULL && pool_iterate_next(iter, &blockptr, &blocksize, NULL); )
+ {
+ int startwithin = (ptrstart >= (UINT8 *)blockptr && ptrstart < (UINT8 *)blockptr + blocksize);
+ int endwithin = (ptrend >= (UINT8 *)blockptr && ptrend < (UINT8 *)blockptr + blocksize);
+
+ /* if the start of the incoming pointer lies within the block... */
+ if (startwithin || endwithin)
+ {
+ overlap = (startwithin && endwithin) ? OVERLAP_FULL : OVERLAP_PARTIAL;
+ break;
+ }
+ }
+ pool_iterate_end(iter);
+
+ /* store the results */
+ if (overlap != OVERLAP_NONE)
+ {
+ if (found_block != NULL)
+ *found_block = blockptr;
+ if (found_block_size != NULL)
+ *found_block_size = blocksize;
+ }
+ return overlap;
+}
diff --git a/src/emu/restrack.h b/src/emu/restrack.h
new file mode 100644
index 00000000000..9453710668b
--- /dev/null
+++ b/src/emu/restrack.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+
+ restrack.h
+
+ Core MAME resource tracking.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __RESTRACK_H__
+#define __RESTRACK_H__
+
+#include "mamecore.h"
+#include "pool.h"
+#include "astring.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define OBJTYPE_ASTRING OBJECT_TYPE('a','s','t','r')
+#define OBJTYPE_BITMAP OBJECT_TYPE('b','i','t','m')
+#define OBJTYPE_TIMER OBJECT_TYPE('t','i','m','r')
+#define OBJTYPE_STATEREG OBJECT_TYPE('s','t','a','t')
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* initialize the resource tracking system */
+void init_resource_tracking(void);
+
+/* tear down the resource tracking system */
+void exit_resource_tracking(void);
+
+/* begin tracking resources */
+void begin_resource_tracking(void);
+
+/* stop tracking resources and free everything since the last begin */
+void end_resource_tracking(void);
+
+/* register an object with the current pool */
+void *restrack_register_object(object_type type, void *ptr, size_t size, const char *file, int line);
+
+/* validate that a block of memory has been allocated by auto_malloc() */
+void validate_auto_malloc_memory(void *memory, size_t memory_size);
+
+/* return the current resource tag */
+INLINE int get_resource_tag(void)
+{
+ extern int resource_tracking_tag;
+ return resource_tracking_tag;
+}
+
+
+/* allocate memory and fatalerror if there's a problem */
+#define malloc_or_die(s) malloc_or_die_file_line(s, __FILE__, __LINE__)
+void *malloc_or_die_file_line(size_t size, const char *file, int line) ATTR_MALLOC;
+
+/* allocate memory that will be freed at the next end_resource_tracking */
+#define auto_malloc(s) auto_malloc_file_line(s, __FILE__, __LINE__)
+void *auto_malloc_file_line(size_t size, const char *file, int line) ATTR_MALLOC;
+
+/* allocate memory that will be freed at the next end_resource_tracking */
+#define auto_realloc(p, s) auto_realloc_file_line(p, s, __FILE__, __LINE__)
+void *auto_realloc_file_line(void *ptr, size_t size, const char *file, int line) ATTR_MALLOC;
+
+/* allocate memory and duplicate a string that will be freed at the next end_resource_tracking */
+#define auto_strdup(s) auto_strdup_file_line(s, __FILE__, __LINE__)
+char *auto_strdup_file_line(const char *str, const char *file, int line) ATTR_MALLOC;
+
+/* auto_strdup() variant that tolerates NULL */
+#define auto_strdup_allow_null(s) auto_strdup_allow_null_file_line(s, __FILE__, __LINE__)
+char *auto_strdup_allow_null_file_line(const char *str, const char *file, int line) ATTR_MALLOC;
+
+/* allocate a bitmap that will be freed at the next end_resource_tracking */
+#define auto_astring_alloc() auto_astring_alloc_file_line(__FILE__, __LINE__)
+astring *auto_astring_alloc_file_line(const char *file, int line);
+
+/* allocate a bitmap that will be freed at the next end_resource_tracking */
+#define auto_bitmap_alloc(w,h,f) auto_bitmap_alloc_file_line(w, h, f, __FILE__, __LINE__)
+bitmap_t *auto_bitmap_alloc_file_line(int width, int height, bitmap_format format, const char *file, int line);
+
+
+#endif /* __RESTRACK_H__ */
diff --git a/src/emu/romload.c b/src/emu/romload.c
new file mode 100644
index 00000000000..344ae0a4901
--- /dev/null
+++ b/src/emu/romload.c
@@ -0,0 +1,1169 @@
+/*********************************************************************
+
+ romload.c
+
+ ROM loading functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "osdepend.h"
+#include "driver.h"
+#include "hash.h"
+#include "png.h"
+#include "harddisk.h"
+#include "config.h"
+#include "ui.h"
+#include <stdarg.h>
+#include <ctype.h>
+
+
+//#define LOG_LOAD
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _open_chd open_chd;
+struct _open_chd
+{
+ open_chd * next; /* pointer to next in the list */
+ chd_file * origchd; /* handle to the original CHD */
+ mame_file * origfile; /* file handle to the original CHD file */
+ chd_file * diffchd; /* handle to the diff CHD */
+ mame_file * difffile; /* file handle to the diff CHD file */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* disks */
+static open_chd *chd_list;
+static open_chd **chd_list_tailptr;
+
+/* system BIOS */
+int system_bios;
+
+static int total_rom_load_warnings;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void rom_exit(running_machine *machine);
+
+
+
+/***************************************************************************
+ HARD DISK HANDLING
+***************************************************************************/
+
+chd_file *get_disk_handle(int diskindex)
+{
+ open_chd *curdisk;
+ for (curdisk = chd_list; curdisk != NULL && diskindex-- != 0; curdisk = curdisk->next) ;
+ if (curdisk != NULL)
+ return (curdisk->diffchd != NULL) ? curdisk->diffchd : curdisk->origchd;
+ return NULL;
+}
+
+
+
+/***************************************************************************
+ ROM LOADING
+***************************************************************************/
+
+/*-------------------------------------------------
+ rom_first_region - return pointer to first ROM
+ region
+-------------------------------------------------*/
+
+const rom_entry *rom_first_region(const game_driver *drv)
+{
+ return (drv->rom != NULL && !ROMENTRY_ISEND(drv->rom)) ? drv->rom : NULL;
+}
+
+
+/*-------------------------------------------------
+ rom_next_region - return pointer to next ROM
+ region
+-------------------------------------------------*/
+
+const rom_entry *rom_next_region(const rom_entry *romp)
+{
+ romp++;
+ while (!ROMENTRY_ISREGIONEND(romp))
+ romp++;
+ return ROMENTRY_ISEND(romp) ? NULL : romp;
+}
+
+
+/*-------------------------------------------------
+ rom_first_file - return pointer to first ROM
+ file
+-------------------------------------------------*/
+
+const rom_entry *rom_first_file(const rom_entry *romp)
+{
+ romp++;
+ while (!ROMENTRY_ISFILE(romp) && !ROMENTRY_ISREGIONEND(romp))
+ romp++;
+ return ROMENTRY_ISREGIONEND(romp) ? NULL : romp;
+}
+
+
+/*-------------------------------------------------
+ rom_next_file - return pointer to next ROM
+ file
+-------------------------------------------------*/
+
+const rom_entry *rom_next_file(const rom_entry *romp)
+{
+ romp++;
+ while (!ROMENTRY_ISFILE(romp) && !ROMENTRY_ISREGIONEND(romp))
+ romp++;
+ return ROMENTRY_ISREGIONEND(romp) ? NULL : romp;
+}
+
+
+/*-------------------------------------------------
+ rom_first_chunk - return pointer to first ROM
+ chunk
+-------------------------------------------------*/
+
+const rom_entry *rom_first_chunk(const rom_entry *romp)
+{
+ return (ROMENTRY_ISFILE(romp)) ? romp : NULL;
+}
+
+
+/*-------------------------------------------------
+ rom_next_chunk - return pointer to next ROM
+ chunk
+-------------------------------------------------*/
+
+const rom_entry *rom_next_chunk(const rom_entry *romp)
+{
+ romp++;
+ return (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp)) ? romp : NULL;
+}
+
+
+/*-------------------------------------------------
+ debugload - log data to a file
+-------------------------------------------------*/
+
+static void CLIB_DECL debugload(const char *string, ...)
+{
+#ifdef LOG_LOAD
+ static int opened;
+ va_list arg;
+ FILE *f;
+
+ f = fopen("romload.log", opened++ ? "a" : "w");
+ if (f)
+ {
+ va_start(arg, string);
+ vfprintf(f, string, arg);
+ va_end(arg);
+ fclose(f);
+ }
+#endif
+}
+
+
+/*-------------------------------------------------
+ determine_bios_rom - determine system_bios
+ from SystemBios structure and OPTION_BIOS
+-------------------------------------------------*/
+
+static int determine_bios_rom(const rom_entry *romp)
+{
+ const char *specbios = options_get_string(mame_options(), OPTION_BIOS);
+ const rom_entry *rom;
+ int bios_count = 0;
+
+ /* set to default */
+ int bios_no = 1;
+
+ for (rom = romp;!ROMENTRY_ISEND(rom);rom++)
+ if (ROMENTRY_ISSYSTEM_BIOS(rom))
+ {
+ const char *biosname = ROM_GETHASHDATA(rom);
+ int bios_flags = ROM_GETBIOSFLAGS(rom);
+ char bios_number[3];
+
+ /* Allow '-bios n' to still be used */
+ sprintf(bios_number, "%d", bios_flags-1);
+ if (strcmp(bios_number, specbios) == 0 || strcmp(biosname, specbios) == 0)
+ bios_no = bios_flags;
+ bios_count++;
+ }
+
+ if (bios_count == 0)
+ bios_no = 0;
+
+ debugload("Using System BIOS: %d\n", bios_no);
+
+ return bios_no;
+}
+
+
+/*-------------------------------------------------
+ count_roms - counts the total number of ROMs
+ that will need to be loaded
+-------------------------------------------------*/
+
+static int count_roms(const rom_entry *romp)
+{
+ const rom_entry *region, *rom;
+ int count = 0;
+
+ /* loop over regions, then over files */
+ for (region = romp; region; region = rom_next_region(region))
+ for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ {
+ int bios_flags = ROM_GETBIOSFLAGS(rom);
+ if (!bios_flags || (bios_flags == system_bios)) /* alternate bios sets */
+ count++;
+ }
+
+ /* return the total count */
+ return count;
+}
+
+
+/*-------------------------------------------------
+ fill_random - fills an area of memory with
+ random data
+-------------------------------------------------*/
+
+static void fill_random(UINT8 *base, UINT32 length)
+{
+ while (length--)
+ *base++ = mame_rand(Machine);
+}
+
+
+/*-------------------------------------------------
+ handle_missing_file - handles error generation
+ for missing files
+-------------------------------------------------*/
+
+static void handle_missing_file(rom_load_data *romdata, const rom_entry *romp)
+{
+ /* optional files are okay */
+ if (ROM_ISOPTIONAL(romp))
+ {
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "OPTIONAL %s NOT FOUND\n", ROM_GETNAME(romp));
+ romdata->warnings++;
+ }
+
+ /* no good dumps are okay */
+ else if (ROM_NOGOODDUMP(romp))
+ {
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s NOT FOUND (NO GOOD DUMP KNOWN)\n", ROM_GETNAME(romp));
+ romdata->warnings++;
+ }
+
+ /* anything else is bad */
+ else
+ {
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s NOT FOUND\n", ROM_GETNAME(romp));
+ romdata->errors++;
+ }
+}
+
+
+/*-------------------------------------------------
+ dump_wrong_and_correct_checksums - dump an
+ error message containing the wrong and the
+ correct checksums for a given ROM
+-------------------------------------------------*/
+
+static void dump_wrong_and_correct_checksums(rom_load_data* romdata, const char* hash, const char* acthash)
+{
+ unsigned i;
+ char chksum[256];
+ unsigned found_functions;
+ unsigned wrong_functions;
+
+ found_functions = hash_data_used_functions(hash) & hash_data_used_functions(acthash);
+
+ hash_data_print(hash, found_functions, chksum);
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], " EXPECTED: %s\n", chksum);
+
+ /* We dump informations only of the functions for which MAME provided
+ a correct checksum. Other functions we might have calculated are
+ useless here */
+ hash_data_print(acthash, found_functions, chksum);
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], " FOUND: %s\n", chksum);
+
+ /* For debugging purposes, we check if the checksums available in the
+ driver are correctly specified or not. This can be done by checking
+ the return value of one of the extract functions. Maybe we want to
+ activate this only in debug buils, but many developers only use
+ release builds, so I keep it as is for now. */
+ wrong_functions = 0;
+ for (i=0;i<HASH_NUM_FUNCTIONS;i++)
+ if (hash_data_extract_printable_checksum(hash, 1<<i, chksum) == 2)
+ wrong_functions |= 1<<i;
+
+ if (wrong_functions)
+ {
+ for (i=0;i<HASH_NUM_FUNCTIONS;i++)
+ if (wrong_functions & (1<<i))
+ {
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)],
+ "\tInvalid %s checksum treated as 0 (check leading zeros)\n",
+ hash_function_name(1<<i));
+
+ romdata->warnings++;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ verify_length_and_hash - verify the length
+ and hash signatures of a file
+-------------------------------------------------*/
+
+static void verify_length_and_hash(rom_load_data *romdata, const char *name, UINT32 explength, const char* hash)
+{
+ UINT32 actlength;
+ const char* acthash;
+
+ /* we've already complained if there is no file */
+ if (!romdata->file)
+ return;
+
+ /* get the length and CRC from the file */
+ actlength = mame_fsize(romdata->file);
+ acthash = mame_fhash(romdata->file, hash_data_used_functions(hash));
+
+ /* verify length */
+ if (explength != actlength)
+ {
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s WRONG LENGTH (expected: %08x found: %08x)\n", name, explength, actlength);
+ romdata->warnings++;
+ }
+
+ /* If there is no good dump known, write it */
+ if (hash_data_has_info(hash, HASH_INFO_NO_DUMP))
+ {
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s NO GOOD DUMP KNOWN\n", name);
+ romdata->warnings++;
+ }
+ /* verify checksums */
+ else if (!hash_data_is_equal(hash, acthash, 0))
+ {
+ /* otherwise, it's just bad */
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s WRONG CHECKSUMS:\n", name);
+
+ dump_wrong_and_correct_checksums(romdata, hash, acthash);
+
+ romdata->warnings++;
+ }
+ /* If it matches, but it is actually a bad dump, write it */
+ else if (hash_data_has_info(hash, HASH_INFO_BAD_DUMP))
+ {
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s ROM NEEDS REDUMP\n",name);
+ romdata->warnings++;
+ }
+}
+
+
+/*-------------------------------------------------
+ display_loading_rom_message - display
+ messages about ROM loading to the user
+-------------------------------------------------*/
+
+static void display_loading_rom_message(const char *name, rom_load_data *romdata)
+{
+ char buffer[200];
+
+ if (name != NULL)
+ sprintf(buffer, "Loading (%d%%)", 100 * romdata->romsloaded / romdata->romstotal);
+ else
+ sprintf(buffer, "Loading Complete");
+
+ ui_set_startup_text(buffer, FALSE);
+}
+
+
+/*-------------------------------------------------
+ display_rom_load_results - display the final
+ results of ROM loading
+-------------------------------------------------*/
+
+static void display_rom_load_results(rom_load_data *romdata)
+{
+ int region;
+
+ /* final status display */
+ display_loading_rom_message(NULL, romdata);
+
+ /* if we had errors, they are fatal */
+ if (romdata->errors != 0)
+ {
+ /* clean up any regions */
+ for (region = 0; region < MAX_MEMORY_REGIONS; region++)
+ free_memory_region(Machine, region);
+
+ /* create the error message and exit fatally */
+ strcat(romdata->errorbuf, "ERROR: required files are missing, the game cannot be run.");
+ fatalerror_exitcode(MAMERR_MISSING_FILES, "%s", romdata->errorbuf);
+ }
+
+ /* if we had warnings, output them, but continue */
+ if (romdata->warnings)
+ {
+ strcat(romdata->errorbuf, "WARNING: the game might not run correctly.");
+ mame_printf_warning("%s\n", romdata->errorbuf);
+ }
+}
+
+
+/*-------------------------------------------------
+ region_post_process - post-process a region,
+ byte swapping and inverting data as necessary
+-------------------------------------------------*/
+
+static void region_post_process(rom_load_data *romdata, const rom_entry *regiondata)
+{
+ int type = ROMREGION_GETTYPE(regiondata);
+ int datawidth = ROMREGION_GETWIDTH(regiondata) / 8;
+ int littleendian = ROMREGION_ISLITTLEENDIAN(regiondata);
+ UINT8 *base;
+ int i, j;
+
+ debugload("+ datawidth=%d little=%d\n", datawidth, littleendian);
+
+ /* if this is a CPU region, override with the CPU width and endianness */
+ if (type >= REGION_CPU1 && type < REGION_CPU1 + MAX_CPU)
+ {
+ cpu_type cputype = Machine->drv->cpu[type - REGION_CPU1].type;
+ if (cputype != CPU_DUMMY)
+ {
+ datawidth = cputype_databus_width(cputype, ADDRESS_SPACE_PROGRAM) / 8;
+ littleendian = (cputype_endianness(cputype) == CPU_IS_LE);
+ debugload("+ CPU region #%d: datawidth=%d little=%d\n", type - REGION_CPU1, datawidth, littleendian);
+ }
+ }
+
+ /* if the region is inverted, do that now */
+ if (ROMREGION_ISINVERTED(regiondata))
+ {
+ debugload("+ Inverting region\n");
+ for (i = 0, base = romdata->regionbase; i < romdata->regionlength; i++)
+ *base++ ^= 0xff;
+ }
+
+ /* swap the endianness if we need to */
+#ifdef LSB_FIRST
+ if (datawidth > 1 && !littleendian)
+#else
+ if (datawidth > 1 && littleendian)
+#endif
+ {
+ debugload("+ Byte swapping region\n");
+ for (i = 0, base = romdata->regionbase; i < romdata->regionlength; i += datawidth)
+ {
+ UINT8 temp[8];
+ memcpy(temp, base, datawidth);
+ for (j = datawidth - 1; j >= 0; j--)
+ *base++ = temp[j];
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ open_rom_file - open a ROM file, searching
+ up the parent and loading by checksum
+-------------------------------------------------*/
+
+static int open_rom_file(rom_load_data *romdata, const rom_entry *romp)
+{
+ file_error filerr = FILERR_NOT_FOUND;
+ const game_driver *drv;
+
+ ++romdata->romsloaded;
+
+ /* update status display */
+ display_loading_rom_message(ROM_GETNAME(romp), romdata);
+
+ /* Attempt reading up the chain through the parents. It automatically also
+ attempts any kind of load by checksum supported by the archives. */
+ romdata->file = NULL;
+ for (drv = Machine->gamedrv; !romdata->file && drv; drv = driver_get_clone(drv))
+ if (drv->name && *drv->name)
+ {
+ UINT8 crcs[4];
+ astring *fname;
+
+ fname = astring_assemble_3(astring_alloc(), drv->name, PATH_SEPARATOR, ROM_GETNAME(romp));
+ if (hash_data_extract_binary_checksum(ROM_GETHASHDATA(romp), HASH_CRC, crcs))
+ {
+ UINT32 crc = (crcs[0] << 24) | (crcs[1] << 16) | (crcs[2] << 8) | crcs[3];
+ filerr = mame_fopen_crc(SEARCHPATH_ROM, astring_c(fname), crc, OPEN_FLAG_READ, &romdata->file);
+ }
+ else
+ filerr = mame_fopen(SEARCHPATH_ROM, astring_c(fname), OPEN_FLAG_READ, &romdata->file);
+ astring_free(fname);
+ }
+
+ /* return the result */
+ return (filerr == FILERR_NONE);
+}
+
+
+/*-------------------------------------------------
+ rom_fread - cheesy fread that fills with
+ random data for a NULL file
+-------------------------------------------------*/
+
+static int rom_fread(rom_load_data *romdata, UINT8 *buffer, int length)
+{
+ /* files just pass through */
+ if (romdata->file)
+ return mame_fread(romdata->file, buffer, length);
+
+ /* otherwise, fill with randomness */
+ else
+ fill_random(buffer, length);
+
+ return length;
+}
+
+
+/*-------------------------------------------------
+ read_rom_data - read ROM data for a single
+ entry
+-------------------------------------------------*/
+
+static int read_rom_data(rom_load_data *romdata, const rom_entry *romp)
+{
+ int datashift = ROM_GETBITSHIFT(romp);
+ int datamask = ((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift;
+ int numbytes = ROM_GETLENGTH(romp);
+ int groupsize = ROM_GETGROUPSIZE(romp);
+ int skip = ROM_GETSKIPCOUNT(romp);
+ int reversed = ROM_ISREVERSED(romp);
+ int numgroups = (numbytes + groupsize - 1) / groupsize;
+ UINT8 *base = romdata->regionbase + ROM_GETOFFSET(romp);
+ int i;
+
+ debugload("Loading ROM data: offs=%X len=%X mask=%02X group=%d skip=%d reverse=%d\n", ROM_GETOFFSET(romp), numbytes, datamask, groupsize, skip, reversed);
+
+ /* make sure the length was an even multiple of the group size */
+ if (numbytes % groupsize != 0)
+ fatalerror("Error in RomModule definition: %s length not an even multiple of group size\n", ROM_GETNAME(romp));
+
+ /* make sure we only fill within the region space */
+ if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > romdata->regionlength)
+ fatalerror("Error in RomModule definition: %s out of memory region space\n", ROM_GETNAME(romp));
+
+ /* make sure the length was valid */
+ if (numbytes == 0)
+ fatalerror("Error in RomModule definition: %s has an invalid length\n", ROM_GETNAME(romp));
+
+ /* special case for simple loads */
+ if (datamask == 0xff && (groupsize == 1 || !reversed) && skip == 0)
+ return rom_fread(romdata, base, numbytes);
+
+ /* chunky reads for complex loads */
+ skip += groupsize;
+ while (numbytes)
+ {
+ int evengroupcount = (sizeof(romdata->tempbuf) / groupsize) * groupsize;
+ int bytesleft = (numbytes > evengroupcount) ? evengroupcount : numbytes;
+ UINT8 *bufptr = romdata->tempbuf;
+
+ /* read as much as we can */
+ debugload(" Reading %X bytes into buffer\n", bytesleft);
+ if (rom_fread(romdata, romdata->tempbuf, bytesleft) != bytesleft)
+ return 0;
+ numbytes -= bytesleft;
+
+ debugload(" Copying to %p\n", base);
+
+ /* unmasked cases */
+ if (datamask == 0xff)
+ {
+ /* non-grouped data */
+ if (groupsize == 1)
+ for (i = 0; i < bytesleft; i++, base += skip)
+ *base = *bufptr++;
+
+ /* grouped data -- non-reversed case */
+ else if (!reversed)
+ while (bytesleft)
+ {
+ for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
+ base[i] = *bufptr++;
+ base += skip;
+ }
+
+ /* grouped data -- reversed case */
+ else
+ while (bytesleft)
+ {
+ for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
+ base[i] = *bufptr++;
+ base += skip;
+ }
+ }
+
+ /* masked cases */
+ else
+ {
+ /* non-grouped data */
+ if (groupsize == 1)
+ for (i = 0; i < bytesleft; i++, base += skip)
+ *base = (*base & ~datamask) | ((*bufptr++ << datashift) & datamask);
+
+ /* grouped data -- non-reversed case */
+ else if (!reversed)
+ while (bytesleft)
+ {
+ for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
+ base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
+ base += skip;
+ }
+
+ /* grouped data -- reversed case */
+ else
+ while (bytesleft)
+ {
+ for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
+ base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
+ base += skip;
+ }
+ }
+ }
+ debugload(" All done\n");
+ return ROM_GETLENGTH(romp);
+}
+
+
+/*-------------------------------------------------
+ fill_rom_data - fill a region of ROM space
+-------------------------------------------------*/
+
+static void fill_rom_data(rom_load_data *romdata, const rom_entry *romp)
+{
+ UINT32 numbytes = ROM_GETLENGTH(romp);
+ UINT8 *base = romdata->regionbase + ROM_GETOFFSET(romp);
+
+ /* make sure we fill within the region space */
+ if (ROM_GETOFFSET(romp) + numbytes > romdata->regionlength)
+ fatalerror("Error in RomModule definition: FILL out of memory region space\n");
+
+ /* make sure the length was valid */
+ if (numbytes == 0)
+ fatalerror("Error in RomModule definition: FILL has an invalid length\n");
+
+ /* fill the data (filling value is stored in place of the hashdata) */
+ memset(base, (FPTR)ROM_GETHASHDATA(romp) & 0xff, numbytes);
+}
+
+
+/*-------------------------------------------------
+ copy_rom_data - copy a region of ROM space
+-------------------------------------------------*/
+
+static void copy_rom_data(rom_load_data *romdata, const rom_entry *romp)
+{
+ UINT8 *base = romdata->regionbase + ROM_GETOFFSET(romp);
+ int srcregion = ROM_GETFLAGS(romp) >> 24;
+ UINT32 numbytes = ROM_GETLENGTH(romp);
+ UINT32 srcoffs = (FPTR)ROM_GETHASHDATA(romp); /* srcoffset in place of hashdata */
+ UINT8 *srcbase;
+
+ /* make sure we copy within the region space */
+ if (ROM_GETOFFSET(romp) + numbytes > romdata->regionlength)
+ fatalerror("Error in RomModule definition: COPY out of target memory region space\n");
+
+ /* make sure the length was valid */
+ if (numbytes == 0)
+ fatalerror("Error in RomModule definition: COPY has an invalid length\n");
+
+ /* make sure the source was valid */
+ srcbase = memory_region(srcregion);
+ if (!srcbase)
+ fatalerror("Error in RomModule definition: COPY from an invalid region\n");
+
+ /* make sure we find within the region space */
+ if (srcoffs + numbytes > memory_region_length(srcregion))
+ fatalerror("Error in RomModule definition: COPY out of source memory region space\n");
+
+ /* fill the data */
+ memcpy(base, srcbase + srcoffs, numbytes);
+}
+
+
+/*-------------------------------------------------
+ process_rom_entries - process all ROM entries
+ for a region
+-------------------------------------------------*/
+
+static void process_rom_entries(rom_load_data *romdata, const rom_entry *romp)
+{
+ UINT32 lastflags = 0;
+
+ /* loop until we hit the end of this region */
+ while (!ROMENTRY_ISREGIONEND(romp))
+ {
+ /* if this is a continue entry, it's invalid */
+ if (ROMENTRY_ISCONTINUE(romp))
+ fatalerror("Error in RomModule definition: ROM_CONTINUE not preceded by ROM_LOAD\n");
+
+ /* if this is an ignore entry, it's invalid */
+ if (ROMENTRY_ISIGNORE(romp))
+ fatalerror("Error in RomModule definition: ROM_IGNORE not preceded by ROM_LOAD\n");
+
+ /* if this is a reload entry, it's invalid */
+ if (ROMENTRY_ISRELOAD(romp))
+ fatalerror("Error in RomModule definition: ROM_RELOAD not preceded by ROM_LOAD\n");
+
+ /* handle fills */
+ if (ROMENTRY_ISFILL(romp))
+ fill_rom_data(romdata, romp++);
+
+ /* handle copies */
+ else if (ROMENTRY_ISCOPY(romp))
+ copy_rom_data(romdata, romp++);
+
+ /* handle files */
+ else if (ROMENTRY_ISFILE(romp))
+ {
+ int bios_flags = ROM_GETBIOSFLAGS(romp);
+ if (!bios_flags || (bios_flags == system_bios)) /* alternate bios sets */
+ {
+ const rom_entry *baserom = romp;
+ int explength = 0;
+
+ /* open the file */
+ debugload("Opening ROM file: %s\n", ROM_GETNAME(romp));
+ if (!open_rom_file(romdata, romp))
+ handle_missing_file(romdata, romp);
+
+ /* loop until we run out of reloads */
+ do
+ {
+ /* loop until we run out of continues/ignores */
+ do
+ {
+ rom_entry modified_romp = *romp++;
+ int readresult;
+
+ /* handle flag inheritance */
+ if (!ROM_INHERITSFLAGS(&modified_romp))
+ lastflags = modified_romp._flags;
+ else
+ modified_romp._flags = (modified_romp._flags & ~ROM_INHERITEDFLAGS) | lastflags;
+
+ explength += ROM_GETLENGTH(&modified_romp);
+
+ /* attempt to read using the modified entry */
+ if (!ROMENTRY_ISIGNORE(&modified_romp))
+ readresult = read_rom_data(romdata, &modified_romp);
+ }
+ while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp));
+
+ /* if this was the first use of this file, verify the length and CRC */
+ if (baserom)
+ {
+ debugload("Verifying length (%X) and checksums\n", explength);
+ verify_length_and_hash(romdata, ROM_GETNAME(baserom), explength, ROM_GETHASHDATA(baserom));
+ debugload("Verify finished\n");
+ }
+
+ /* reseek to the start and clear the baserom so we don't reverify */
+ if (romdata->file)
+ mame_fseek(romdata->file, 0, SEEK_SET);
+ baserom = NULL;
+ explength = 0;
+ }
+ while (ROMENTRY_ISRELOAD(romp));
+
+ /* close the file */
+ if (romdata->file)
+ {
+ debugload("Closing ROM file\n");
+ mame_fclose(romdata->file);
+ romdata->file = NULL;
+ }
+ }
+ else
+ {
+ romp++; /* skip over file */
+ }
+ }
+ else
+ {
+ romp++; /* something else; skip */
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ open_disk_image - open a DISK image, searching
+ up the parent and loading by checksum
+-------------------------------------------------*/
+
+chd_error open_disk_image(const game_driver *gamedrv, const rom_entry *romp, mame_file **image_file, chd_file **image_chd)
+{
+ return open_disk_image_options(mame_options(), gamedrv, romp, image_file, image_chd);
+}
+
+
+/*-------------------------------------------------
+ open_disk_image_options - open a DISK image, searching
+ up the parent and loading by checksum
+-------------------------------------------------*/
+
+chd_error open_disk_image_options(core_options *options, const game_driver *gamedrv, const rom_entry *romp, mame_file **image_file, chd_file **image_chd)
+{
+ const game_driver *drv, *searchdrv;
+ const rom_entry *region, *rom;
+ file_error filerr;
+ chd_error err;
+
+ *image_file = NULL;
+ *image_chd = NULL;
+
+ /* attempt to open the properly named file, scanning up through parent directories */
+ filerr = FILERR_NOT_FOUND;
+ for (searchdrv = gamedrv; searchdrv != NULL && filerr != FILERR_NONE; searchdrv = driver_get_clone(searchdrv))
+ {
+ astring *fname = astring_assemble_4(astring_alloc(), searchdrv->name, PATH_SEPARATOR, ROM_GETNAME(romp), ".chd");
+ filerr = mame_fopen_options(options, SEARCHPATH_IMAGE, astring_c(fname), OPEN_FLAG_READ, image_file);
+ astring_free(fname);
+ }
+
+ /* did the file open succeed? */
+ if (filerr == FILERR_NONE)
+ {
+ /* try to open the CHD */
+ err = chd_open_file(mame_core_file(*image_file), CHD_OPEN_READ, NULL, image_chd);
+ if (err == CHDERR_NONE)
+ return err;
+
+ /* close the file on failure */
+ mame_fclose(*image_file);
+ *image_file = NULL;
+ }
+ else
+ err = CHDERR_FILE_NOT_FOUND;
+
+ /* otherwise, look at our parents for a CHD with an identical checksum */
+ /* and try to open that */
+ for (drv = gamedrv; drv != NULL; drv = driver_get_clone(drv))
+ for (region = rom_first_region(drv); region != NULL; region = rom_next_region(region))
+ if (ROMREGION_ISDISKDATA(region))
+ for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom))
+
+ /* look for a differing name but with the same hash data */
+ if (strcmp(ROM_GETNAME(romp), ROM_GETNAME(rom)) != 0 &&
+ hash_data_is_equal(ROM_GETHASHDATA(romp), ROM_GETHASHDATA(rom), 0))
+ {
+ /* attempt to open the properly named file, scanning up through parent directories */
+ filerr = FILERR_NOT_FOUND;
+ for (searchdrv = drv; searchdrv != NULL && filerr != FILERR_NONE; searchdrv = driver_get_clone(searchdrv))
+ {
+ astring *fname = astring_assemble_4(astring_alloc(), searchdrv->name, PATH_SEPARATOR, ROM_GETNAME(rom), ".chd");
+ filerr = mame_fopen_options(options, SEARCHPATH_IMAGE, astring_c(fname), OPEN_FLAG_READ, image_file);
+ astring_free(fname);
+ }
+
+ /* did the file open succeed? */
+ if (filerr == FILERR_NONE)
+ {
+ /* try to open the CHD */
+ err = chd_open_file(mame_core_file(*image_file), CHD_OPEN_READ, NULL, image_chd);
+ if (err == CHDERR_NONE)
+ return err;
+
+ /* close the file on failure */
+ mame_fclose(*image_file);
+ *image_file = NULL;
+ }
+ }
+
+ return err;
+}
+
+
+/*-------------------------------------------------
+ open_disk_diff - open a DISK diff file
+-------------------------------------------------*/
+
+static chd_error open_disk_diff(const game_driver *drv, const rom_entry *romp, chd_file *source, mame_file **diff_file, chd_file **diff_chd)
+{
+ astring *fname = astring_assemble_2(astring_alloc(), ROM_GETNAME(romp), ".dif");
+ file_error filerr;
+ chd_error err;
+
+ *diff_file = NULL;
+ *diff_chd = NULL;
+
+ /* try to open the diff */
+ debugload("Opening differencing image file: %s\n", astring_c(fname));
+ filerr = mame_fopen(SEARCHPATH_IMAGE_DIFF, astring_c(fname), OPEN_FLAG_READ | OPEN_FLAG_WRITE, diff_file);
+ if (filerr != FILERR_NONE)
+ {
+ /* didn't work; try creating it instead */
+ debugload("Creating differencing image: %s\n", astring_c(fname));
+ filerr = mame_fopen(SEARCHPATH_IMAGE_DIFF, astring_c(fname), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, diff_file);
+ if (filerr != FILERR_NONE)
+ {
+ err = CHDERR_FILE_NOT_FOUND;
+ goto done;
+ }
+
+ /* create the CHD */
+ err = chd_create_file(mame_core_file(*diff_file), 0, 0, CHDCOMPRESSION_NONE, source);
+ if (err != CHDERR_NONE)
+ goto done;
+ }
+
+ debugload("Opening differencing image file: %s\n", astring_c(fname));
+ err = chd_open_file(mame_core_file(*diff_file), CHD_OPEN_READWRITE, source, diff_chd);
+ if (err != CHDERR_NONE)
+ goto done;
+
+done:
+ astring_free(fname);
+ if ((err != CHDERR_NONE) && (*diff_file != NULL))
+ {
+ mame_fclose(*diff_file);
+ *diff_file = NULL;
+ }
+ return err;
+}
+
+
+/*-------------------------------------------------
+ process_disk_entries - process all disk entries
+ for a region
+-------------------------------------------------*/
+
+static void process_disk_entries(rom_load_data *romdata, const rom_entry *romp)
+{
+ /* loop until we hit the end of this region */
+ while (!ROMENTRY_ISREGIONEND(romp))
+ {
+ /* handle files */
+ if (ROMENTRY_ISFILE(romp))
+ {
+ char acthash[HASH_BUF_SIZE];
+ open_chd chd = { 0 };
+ chd_header header;
+ astring *filename;
+ chd_error err;
+
+ /* make the filename of the source */
+ filename = astring_assemble_2(astring_alloc(), ROM_GETNAME(romp), ".chd");
+
+ /* first open the source drive */
+ debugload("Opening disk image: %s\n", astring_c(filename));
+ err = open_disk_image(Machine->gamedrv, romp, &chd.origfile, &chd.origchd);
+ if (err != CHDERR_NONE)
+ {
+ if (err == CHDERR_UNSUPPORTED_VERSION)
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s UNSUPPORTED CHD VERSION\n", astring_c(filename));
+ else
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s NOT FOUND\n", astring_c(filename));
+
+ /* if this is NO_DUMP, keep going, though the system may not be able to handle it */
+ if (hash_data_has_info(ROM_GETHASHDATA(romp), HASH_INFO_NO_DUMP))
+ romdata->warnings++;
+ else
+ romdata->errors++;
+ goto next;
+ }
+
+ /* get the header and extract the MD5/SHA1 */
+ header = *chd_get_header(chd.origchd);
+ hash_data_clear(acthash);
+ hash_data_insert_binary_checksum(acthash, HASH_MD5, header.md5);
+ hash_data_insert_binary_checksum(acthash, HASH_SHA1, header.sha1);
+
+ /* verify the MD5 */
+ if (!hash_data_is_equal(ROM_GETHASHDATA(romp), acthash, 0))
+ {
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s WRONG CHECKSUMS:\n", astring_c(filename));
+ dump_wrong_and_correct_checksums(romdata, ROM_GETHASHDATA(romp), acthash);
+ romdata->warnings++;
+ }
+ else if (hash_data_has_info(ROM_GETHASHDATA(romp), HASH_INFO_BAD_DUMP))
+ {
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s CHD NEEDS REDUMP\n", astring_c(filename));
+ romdata->warnings++;
+ }
+
+ /* if not read-only, make the diff file */
+ if (!DISK_ISREADONLY(romp))
+ {
+ /* try to open or create the diff */
+ err = open_disk_diff(Machine->gamedrv, romp, chd.origchd, &chd.difffile, &chd.diffchd);
+ if (err != CHDERR_NONE)
+ {
+ if (err == CHDERR_UNSUPPORTED_VERSION)
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s UNSUPPORTED CHD VERSION\n", astring_c(filename));
+ else
+ sprintf(&romdata->errorbuf[strlen(romdata->errorbuf)], "%s: CAN'T OPEN DIFF FILE\n", astring_c(filename));
+ romdata->errors++;
+ goto next;
+ }
+ }
+
+ /* we're okay, add to the list of disks */
+ debugload("Assigning to handle %d\n", DISK_GETINDEX(romp));
+ *chd_list_tailptr = auto_malloc(sizeof(**chd_list_tailptr));
+ **chd_list_tailptr = chd;
+ chd_list_tailptr = &(*chd_list_tailptr)->next;
+next:
+ romp++;
+ astring_free(filename);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ rom_init - new, more flexible ROM
+ loading system
+-------------------------------------------------*/
+
+void rom_init(running_machine *machine, const rom_entry *romp)
+{
+ const rom_entry *regionlist[REGION_MAX];
+ const rom_entry *region;
+ static rom_load_data romdata;
+ int regnum;
+
+ /* if no roms, bail */
+ if (romp == NULL)
+ return;
+
+ /* make sure we get called back on the way out */
+ add_exit_callback(machine, rom_exit);
+
+ /* reset the region list */
+ memset((void *)regionlist, 0, sizeof(regionlist));
+
+ /* reset the romdata struct */
+ memset(&romdata, 0, sizeof(romdata));
+
+ /* determine the correct biosset to load based on OPTION_BIOS string */
+ system_bios = determine_bios_rom(romp);
+
+ romdata.romstotal = count_roms(romp);
+
+ /* reset the disk list */
+ chd_list = NULL;
+ chd_list_tailptr = &chd_list;
+
+ /* loop until we hit the end */
+ for (region = romp, regnum = 0; region; region = rom_next_region(region), regnum++)
+ {
+ int regiontype = ROMREGION_GETTYPE(region);
+
+ debugload("Processing region %02X (length=%X)\n", regiontype, ROMREGION_GETLENGTH(region));
+
+ /* the first entry must be a region */
+ assert(ROMENTRY_ISREGION(region));
+
+ /* remember the base and length */
+ romdata.regionbase = new_memory_region(machine, regiontype, ROMREGION_GETLENGTH(region), ROMREGION_GETFLAGS(region));
+ romdata.regionlength = ROMREGION_GETLENGTH(region);
+ debugload("Allocated %X bytes @ %p\n", romdata.regionlength, romdata.regionbase);
+
+ /* clear the region if it's requested */
+ if (ROMREGION_ISERASE(region))
+ memset(romdata.regionbase, ROMREGION_GETERASEVAL(region), romdata.regionlength);
+
+ /* or if it's sufficiently small (<= 4MB) */
+ else if (romdata.regionlength <= 0x400000)
+ memset(romdata.regionbase, 0, romdata.regionlength);
+
+#ifdef MAME_DEBUG
+ /* if we're debugging, fill region with random data to catch errors */
+ else
+ fill_random(romdata.regionbase, romdata.regionlength);
+#endif
+
+ /* now process the entries in the region */
+ if (ROMREGION_ISROMDATA(region))
+ process_rom_entries(&romdata, region + 1);
+ else if (ROMREGION_ISDISKDATA(region))
+ process_disk_entries(&romdata, region + 1);
+
+ /* add this region to the list */
+ if (regiontype < REGION_MAX)
+ regionlist[regiontype] = region;
+ }
+
+ /* post-process the regions */
+ for (regnum = 0; regnum < REGION_MAX; regnum++)
+ if (regionlist[regnum])
+ {
+ debugload("Post-processing region %02X\n", regnum);
+ romdata.regionlength = memory_region_length(regnum);
+ romdata.regionbase = memory_region(regnum);
+ region_post_process(&romdata, regionlist[regnum]);
+ }
+
+ /* display the results and exit */
+ total_rom_load_warnings = romdata.warnings;
+
+ display_rom_load_results(&romdata);
+}
+
+
+/*-------------------------------------------------
+ rom_exit - clean up after ourselves
+-------------------------------------------------*/
+
+static void rom_exit(running_machine *machine)
+{
+ open_chd *curchd;
+ int i;
+
+ /* free the memory allocated for various regions */
+ for (i = 0; i < MAX_MEMORY_REGIONS; i++)
+ free_memory_region(machine, i);
+
+ /* close all hard drives */
+ for (curchd = chd_list; curchd != NULL; curchd = curchd->next)
+ {
+ if (curchd->diffchd != NULL)
+ chd_close(curchd->diffchd);
+ if (curchd->difffile != NULL)
+ mame_fclose(curchd->difffile);
+ if (curchd->origchd != NULL)
+ chd_close(curchd->origchd);
+ if (curchd->origfile != NULL)
+ mame_fclose(curchd->origfile);
+ }
+}
+
+
+int rom_load_warnings(void)
+{
+ return total_rom_load_warnings;
+}
diff --git a/src/emu/romload.h b/src/emu/romload.h
new file mode 100644
index 00000000000..3f1598bd8f6
--- /dev/null
+++ b/src/emu/romload.h
@@ -0,0 +1,300 @@
+/*********************************************************************
+
+ romload.h
+
+ ROM loading functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __ROMLOAD_H__
+#define __ROMLOAD_H__
+
+#include "mamecore.h"
+#include "chd.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* ----- per-entry constants ----- */
+#define ROMENTRYTYPE_REGION 1 /* this entry marks the start of a region */
+#define ROMENTRYTYPE_END 2 /* this entry marks the end of a region */
+#define ROMENTRYTYPE_RELOAD 3 /* this entry reloads the previous ROM */
+#define ROMENTRYTYPE_CONTINUE 4 /* this entry continues loading the previous ROM */
+#define ROMENTRYTYPE_FILL 5 /* this entry fills an area with a constant value */
+#define ROMENTRYTYPE_COPY 6 /* this entry copies data from another region/offset */
+#define ROMENTRYTYPE_CARTRIDGE 7 /* this entry specifies a cartridge (MESS) */
+#define ROMENTRYTYPE_IGNORE 8 /* this entry continues loading the previous ROM but throws the data away */
+#define ROMENTRYTYPE_SYSTEM_BIOS 9 /* this entry specifies a bios */
+#define ROMENTRYTYPE_COUNT 10
+
+
+/* ----- per-region constants ----- */
+#define ROMREGION_WIDTHMASK 0x00000003 /* native width of region, as power of 2 */
+#define ROMREGION_8BIT 0x00000000 /* (non-CPU regions only) */
+#define ROMREGION_16BIT 0x00000001
+#define ROMREGION_32BIT 0x00000002
+#define ROMREGION_64BIT 0x00000003
+
+#define ROMREGION_ENDIANMASK 0x00000004 /* endianness of the region */
+#define ROMREGION_LE 0x00000000 /* (non-CPU regions only) */
+#define ROMREGION_BE 0x00000004
+
+#define ROMREGION_INVERTMASK 0x00000008 /* invert the bits of the region */
+#define ROMREGION_NOINVERT 0x00000000
+#define ROMREGION_INVERT 0x00000008
+
+#define ROMREGION_DISPOSEMASK 0x00000010 /* dispose of the region after init */
+#define ROMREGION_NODISPOSE 0x00000000
+#define ROMREGION_DISPOSE 0x00000010
+
+#define ROMREGION_LOADUPPERMASK 0x00000040 /* load into the upper part of CPU space */
+#define ROMREGION_LOADLOWER 0x00000000 /* (CPU regions only) */
+#define ROMREGION_LOADUPPER 0x00000040
+
+#define ROMREGION_ERASEMASK 0x00000080 /* erase the region before loading */
+#define ROMREGION_NOERASE 0x00000000
+#define ROMREGION_ERASE 0x00000080
+
+#define ROMREGION_ERASEVALMASK 0x0000ff00 /* value to erase the region to */
+#define ROMREGION_ERASEVAL(x) ((((x) & 0xff) << 8) | ROMREGION_ERASE)
+#define ROMREGION_ERASE00 ROMREGION_ERASEVAL(0)
+#define ROMREGION_ERASEFF ROMREGION_ERASEVAL(0xff)
+
+#define ROMREGION_DATATYPEMASK 0x00010000 /* inherit all flags from previous definition */
+#define ROMREGION_DATATYPEROM 0x00000000
+#define ROMREGION_DATATYPEDISK 0x00010000
+
+
+/* ----- per-ROM constants ----- */
+#define DISK_READONLYMASK 0x00000400 /* is the disk read-only? */
+#define DISK_READWRITE 0x00000000
+#define DISK_READONLY 0x00000400
+
+#define ROM_OPTIONALMASK 0x00000800 /* optional - won't hurt if it's not there */
+#define ROM_REQUIRED 0x00000000
+#define ROM_OPTIONAL 0x00000800
+
+#define ROM_GROUPMASK 0x0000f000 /* load data in groups of this size + 1 */
+#define ROM_GROUPSIZE(n) ((((n) - 1) & 15) << 12)
+#define ROM_GROUPBYTE ROM_GROUPSIZE(1)
+#define ROM_GROUPWORD ROM_GROUPSIZE(2)
+#define ROM_GROUPDWORD ROM_GROUPSIZE(4)
+
+#define ROM_SKIPMASK 0x000f0000 /* skip this many bytes after each group */
+#define ROM_SKIP(n) (((n) & 15) << 16)
+#define ROM_NOSKIP ROM_SKIP(0)
+
+#define ROM_REVERSEMASK 0x00100000 /* reverse the byte order within a group */
+#define ROM_NOREVERSE 0x00000000
+#define ROM_REVERSE 0x00100000
+
+#define ROM_BITWIDTHMASK 0x00e00000 /* width of data in bits */
+#define ROM_BITWIDTH(n) (((n) & 7) << 21)
+#define ROM_NIBBLE ROM_BITWIDTH(4)
+#define ROM_FULLBYTE ROM_BITWIDTH(8)
+
+#define ROM_BITSHIFTMASK 0x07000000 /* left-shift count for the bits */
+#define ROM_BITSHIFT(n) (((n) & 7) << 24)
+#define ROM_NOSHIFT ROM_BITSHIFT(0)
+#define ROM_SHIFT_NIBBLE_LO ROM_BITSHIFT(0)
+#define ROM_SHIFT_NIBBLE_HI ROM_BITSHIFT(4)
+
+#define ROM_INHERITFLAGSMASK 0x08000000 /* inherit all flags from previous definition */
+#define ROM_INHERITFLAGS 0x08000000
+
+#define ROM_BIOSFLAGSMASK 0xf0000000 /* only loaded if value matches global bios value */
+#define ROM_BIOS(n) (((n) & 15) << 28)
+
+#define ROM_INHERITEDFLAGS (ROM_GROUPMASK | ROM_SKIPMASK | ROM_REVERSEMASK | ROM_BITWIDTHMASK | ROM_BITSHIFTMASK | ROM_BIOSFLAGSMASK)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _rom_entry rom_entry;
+struct _rom_entry
+{
+ const char * _name; /* name of the file to load */
+ UINT32 _offset; /* offset to load it to */
+ UINT32 _length; /* length of the file */
+ UINT32 _flags; /* flags */
+ const char * _hashdata; /* hashing informations (checksums) */
+};
+
+
+/* In mamecore.h: typedef struct _rom_load_data rom_load_data; */
+struct _rom_load_data
+{
+ int warnings; /* warning count during processing */
+ int errors; /* error count during processing */
+
+ int romsloaded; /* current ROMs loaded count */
+ int romstotal; /* total number of ROMs to read */
+
+ mame_file * file; /* current file */
+
+ UINT8 * regionbase; /* base of current region */
+ UINT32 regionlength; /* length of current region */
+
+ char errorbuf[4096]; /* accumulated errors */
+ UINT8 tempbuf[65536]; /* temporary buffer */
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* ----- per-entry macros ----- */
+#define ROMENTRY_REGION ((const char *)ROMENTRYTYPE_REGION)
+#define ROMENTRY_END ((const char *)ROMENTRYTYPE_END)
+#define ROMENTRY_RELOAD ((const char *)ROMENTRYTYPE_RELOAD)
+#define ROMENTRY_CONTINUE ((const char *)ROMENTRYTYPE_CONTINUE)
+#define ROMENTRY_FILL ((const char *)ROMENTRYTYPE_FILL)
+#define ROMENTRY_COPY ((const char *)ROMENTRYTYPE_COPY)
+#define ROMENTRY_CARTRIDGE ((const char *)ROMENTRYTYPE_CARTRIDGE)
+#define ROMENTRY_IGNORE ((const char *)ROMENTRYTYPE_IGNORE)
+#define ROMENTRY_SYSTEM_BIOS ((const char *)ROMENTRYTYPE_SYSTEM_BIOS)
+
+#define ROMENTRY_GETTYPE(r) ((FPTR)(r)->_name)
+#define ROMENTRY_ISSPECIAL(r) (ROMENTRY_GETTYPE(r) < ROMENTRYTYPE_COUNT)
+#define ROMENTRY_ISFILE(r) (!ROMENTRY_ISSPECIAL(r))
+#define ROMENTRY_ISREGION(r) ((r)->_name == ROMENTRY_REGION)
+#define ROMENTRY_ISEND(r) ((r)->_name == ROMENTRY_END)
+#define ROMENTRY_ISRELOAD(r) ((r)->_name == ROMENTRY_RELOAD)
+#define ROMENTRY_ISCONTINUE(r) ((r)->_name == ROMENTRY_CONTINUE)
+#define ROMENTRY_ISFILL(r) ((r)->_name == ROMENTRY_FILL)
+#define ROMENTRY_ISCOPY(r) ((r)->_name == ROMENTRY_COPY)
+#define ROMENTRY_ISIGNORE(r) ((r)->_name == ROMENTRY_IGNORE)
+#define ROMENTRY_ISSYSTEM_BIOS(r) ((r)->_name == ROMENTRY_SYSTEM_BIOS)
+#define ROMENTRY_ISREGIONEND(r) (ROMENTRY_ISREGION(r) || ROMENTRY_ISEND(r))
+
+/* ----- per-region macros ----- */
+#define ROMREGION_GETTYPE(r) ((FPTR)(r)->_hashdata)
+#define ROMREGION_GETLENGTH(r) ((r)->_length)
+#define ROMREGION_GETFLAGS(r) ((r)->_flags)
+#define ROMREGION_GETWIDTH(r) (8 << (ROMREGION_GETFLAGS(r) & ROMREGION_WIDTHMASK))
+#define ROMREGION_ISLITTLEENDIAN(r) ((ROMREGION_GETFLAGS(r) & ROMREGION_ENDIANMASK) == ROMREGION_LE)
+#define ROMREGION_ISBIGENDIAN(r) ((ROMREGION_GETFLAGS(r) & ROMREGION_ENDIANMASK) == ROMREGION_BE)
+#define ROMREGION_ISINVERTED(r) ((ROMREGION_GETFLAGS(r) & ROMREGION_INVERTMASK) == ROMREGION_INVERT)
+#define ROMREGION_ISDISPOSE(r) ((ROMREGION_GETFLAGS(r) & ROMREGION_DISPOSEMASK) == ROMREGION_DISPOSE)
+#define ROMREGION_ISLOADUPPER(r) ((ROMREGION_GETFLAGS(r) & ROMREGION_LOADUPPERMASK) == ROMREGION_LOADUPPER)
+#define ROMREGION_ISERASE(r) ((ROMREGION_GETFLAGS(r) & ROMREGION_ERASEMASK) == ROMREGION_ERASE)
+#define ROMREGION_GETERASEVAL(r) ((ROMREGION_GETFLAGS(r) & ROMREGION_ERASEVALMASK) >> 8)
+#define ROMREGION_GETDATATYPE(r) (ROMREGION_GETFLAGS(r) & ROMREGION_DATATYPEMASK)
+#define ROMREGION_ISROMDATA(r) (ROMREGION_GETDATATYPE(r) == ROMREGION_DATATYPEROM)
+#define ROMREGION_ISDISKDATA(r) (ROMREGION_GETDATATYPE(r) == ROMREGION_DATATYPEDISK)
+
+
+/* ----- per-ROM macros ----- */
+#define ROM_GETNAME(r) ((r)->_name)
+#define ROM_SAFEGETNAME(r) (ROMENTRY_ISFILL(r) ? "fill" : ROMENTRY_ISCOPY(r) ? "copy" : ROM_GETNAME(r))
+#define ROM_GETOFFSET(r) ((r)->_offset)
+#define ROM_GETLENGTH(r) ((r)->_length)
+#define ROM_GETFLAGS(r) ((r)->_flags)
+#define ROM_GETHASHDATA(r) ((r)->_hashdata)
+#define ROM_ISOPTIONAL(r) ((ROM_GETFLAGS(r) & ROM_OPTIONALMASK) == ROM_OPTIONAL)
+#define ROM_GETGROUPSIZE(r) (((ROM_GETFLAGS(r) & ROM_GROUPMASK) >> 12) + 1)
+#define ROM_GETSKIPCOUNT(r) ((ROM_GETFLAGS(r) & ROM_SKIPMASK) >> 16)
+#define ROM_ISREVERSED(r) ((ROM_GETFLAGS(r) & ROM_REVERSEMASK) == ROM_REVERSE)
+#define ROM_GETBITWIDTH(r) (((ROM_GETFLAGS(r) & ROM_BITWIDTHMASK) >> 21) + 8 * ((ROM_GETFLAGS(r) & ROM_BITWIDTHMASK) == 0))
+#define ROM_GETBITSHIFT(r) ((ROM_GETFLAGS(r) & ROM_BITSHIFTMASK) >> 24)
+#define ROM_INHERITSFLAGS(r) ((ROM_GETFLAGS(r) & ROM_INHERITFLAGSMASK) == ROM_INHERITFLAGS)
+#define ROM_GETBIOSFLAGS(r) ((ROM_GETFLAGS(r) & ROM_BIOSFLAGSMASK) >> 28)
+#define ROM_NOGOODDUMP(r) (hash_data_has_info((r)->_hashdata, HASH_INFO_NO_DUMP))
+
+
+/* ----- per-disk macros ----- */
+#define DISK_GETINDEX(r) ((r)->_offset)
+#define DISK_ISREADONLY(r) ((ROM_GETFLAGS(r) & DISK_READONLYMASK) == DISK_READONLY)
+
+
+/* ----- start/stop macros ----- */
+#define ROM_START(name) static const rom_entry rom_##name[] = {
+#define ROM_END { ROMENTRY_END, 0, 0, 0, NULL } };
+
+
+/* ----- ROM region macros ----- */
+#define ROM_REGION(length,type,flags) { ROMENTRY_REGION, 0, length, flags, (const char*)type },
+#define ROM_REGION16_LE(length,type,flags) ROM_REGION(length, type, (flags) | ROMREGION_16BIT | ROMREGION_LE)
+#define ROM_REGION16_BE(length,type,flags) ROM_REGION(length, type, (flags) | ROMREGION_16BIT | ROMREGION_BE)
+#define ROM_REGION32_LE(length,type,flags) ROM_REGION(length, type, (flags) | ROMREGION_32BIT | ROMREGION_LE)
+#define ROM_REGION32_BE(length,type,flags) ROM_REGION(length, type, (flags) | ROMREGION_32BIT | ROMREGION_BE)
+#define ROM_REGION64_LE(length,type,flags) ROM_REGION(length, type, (flags) | ROMREGION_64BIT | ROMREGION_LE)
+#define ROM_REGION64_BE(length,type,flags) ROM_REGION(length, type, (flags) | ROMREGION_64BIT | ROMREGION_BE)
+
+
+/* ----- core ROM loading macros ----- */
+#define ROMMD5_LOAD(name,offset,length,hash,flags) { name, offset, length, flags, hash },
+#define ROMX_LOAD(name,offset,length,hash,flags) { name, offset, length, flags, hash },
+#define ROM_LOAD(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, 0)
+#define ROM_LOAD_OPTIONAL(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_OPTIONAL)
+#define ROM_CONTINUE(offset,length) ROMX_LOAD(ROMENTRY_CONTINUE, offset, length, 0, ROM_INHERITFLAGS)
+#define ROM_RELOAD(offset,length) ROMX_LOAD(ROMENTRY_RELOAD, offset, length, 0, ROM_INHERITFLAGS)
+#define ROM_FILL(offset,length,value) ROM_LOAD(ROMENTRY_FILL, offset, length, (const char*)value)
+#define ROM_COPY(rgn,srcoffset,offset,length) ROMX_LOAD(ROMENTRY_COPY, offset, length, (const char*)srcoffset, (rgn) << 24)
+#define ROM_IGNORE(length) ROMX_LOAD(ROMENTRY_IGNORE, 0, length, 0, ROM_INHERITFLAGS)
+
+
+/* ----- specialized loading macros ----- */
+#define ROM_LOAD_NIB_HIGH(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_NIBBLE | ROM_SHIFT_NIBBLE_HI)
+#define ROM_LOAD_NIB_LOW(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_NIBBLE | ROM_SHIFT_NIBBLE_LO)
+#define ROM_LOAD16_BYTE(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_SKIP(1))
+#define ROM_LOAD16_WORD(name,offset,length,hash) ROM_LOAD(name, offset, length, hash)
+#define ROM_LOAD16_WORD_SWAP(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_GROUPWORD | ROM_REVERSE)
+#define ROM_LOAD32_BYTE(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_SKIP(3))
+#define ROM_LOAD32_WORD(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_GROUPWORD | ROM_SKIP(2))
+#define ROM_LOAD32_WORD_SWAP(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2))
+#define ROM_LOAD32_DWORD(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_GROUPDWORD)
+
+
+/* ----- system BIOS macros ----- */
+#define ROM_SYSTEM_BIOS(value,name,description) ROMX_LOAD(ROMENTRY_SYSTEM_BIOS, 0, 0, name "\0" description, ROM_BIOS(value+1))
+
+/* ----- disk loading macros ----- */
+#define DISK_REGION(type) ROM_REGION(1, type, ROMREGION_DATATYPEDISK)
+#define DISK_IMAGE(name,idx,hash) ROMMD5_LOAD(name, idx, 0, hash, DISK_READWRITE)
+#define DISK_IMAGE_READONLY(name,idx,hash) ROMMD5_LOAD(name, idx, 0, hash, DISK_READONLY)
+
+
+/* ----- hash macros ----- */
+#define CRC(x) "c:" #x "#"
+#define SHA1(x) "s:" #x "#"
+#define MD5(x) "m:" #x "#"
+#define NO_DUMP "$ND$"
+#define BAD_DUMP "$BD$"
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* disk handling */
+chd_error open_disk_image(const game_driver *gamedrv, const rom_entry *romp, mame_file **image_file, chd_file **image_chd);
+chd_error open_disk_image_options(core_options *options, const game_driver *gamedrv, const rom_entry *romp, mame_file **image_file, chd_file **image_chd);
+chd_file *get_disk_handle(int diskindex);
+
+/* ROM processing */
+void rom_init(running_machine *machine, const rom_entry *romp);
+int rom_load_warnings(void);
+const rom_entry *rom_first_region(const game_driver *drv);
+const rom_entry *rom_next_region(const rom_entry *romp);
+const rom_entry *rom_first_file(const rom_entry *romp);
+const rom_entry *rom_next_file(const rom_entry *romp);
+const rom_entry *rom_first_chunk(const rom_entry *romp);
+const rom_entry *rom_next_chunk(const rom_entry *romp);
+
+
+#endif /* __ROMLOAD_H__ */
diff --git a/src/emu/sndintrf.c b/src/emu/sndintrf.c
new file mode 100644
index 00000000000..9d6c8bf6bcb
--- /dev/null
+++ b/src/emu/sndintrf.c
@@ -0,0 +1,967 @@
+/***************************************************************************
+
+ sndintrf.c
+
+ Core sound interface functions and definitions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Still to do:
+ * fix drivers that used to use ADPCM
+ * many cores do their own resampling; they should stop
+ * many cores mix to a separate buffer; no longer necessary
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE (0)
+
+#if VERBOSE
+#define VPRINTF(x) mame_printf_debug x
+#else
+#define VPRINTF(x)
+#endif
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _sound_interface sound_interface;
+struct _sound_interface
+{
+ /* table of core functions */
+ void (*get_info)(void *token, UINT32 state, sndinfo *info);
+ void (*set_info)(void *token, UINT32 state, sndinfo *info);
+ void * (*start)(int index, int clock, const void *config);
+ void (*stop)(void *token);
+ void (*reset)(void *token);
+};
+
+
+typedef struct _sndintrf_data sndintrf_data;
+struct _sndintrf_data
+{
+ sound_interface intf; /* copy of the interface data */
+ sound_type sndtype; /* type index of this sound chip */
+ sound_type aliastype; /* aliased type index of this sound chip */
+ int index; /* index of this sound chip */
+ int clock; /* clock for this sound chip */
+ void * token; /* dynamically allocated token data */
+};
+
+
+
+/***************************************************************************
+ EXTERNAL PROTOTYPES
+***************************************************************************/
+
+void dummy_sound_get_info(void *token, UINT32 state, sndinfo *info);
+void custom_get_info(void *token, UINT32 state, sndinfo *info);
+void samples_get_info(void *token, UINT32 state, sndinfo *info);
+void dac_get_info(void *token, UINT32 state, sndinfo *info);
+void dmadac_get_info(void *token, UINT32 state, sndinfo *info);
+void discrete_get_info(void *token, UINT32 state, sndinfo *info);
+void ay8910_get_info(void *token, UINT32 state, sndinfo *info);
+void ay8912_get_info(void *token, UINT32 state, sndinfo *info);
+void ay8913_get_info(void *token, UINT32 state, sndinfo *info);
+void ay8930_get_info(void *token, UINT32 state, sndinfo *info);
+void ym2149_get_info(void *token, UINT32 state, sndinfo *info);
+void ym3439_get_info(void *token, UINT32 state, sndinfo *info);
+void ymz284_get_info(void *token, UINT32 state, sndinfo *info);
+void ymz294_get_info(void *token, UINT32 state, sndinfo *info);
+void ym2203_get_info(void *token, UINT32 state, sndinfo *info);
+void ym2151_get_info(void *token, UINT32 state, sndinfo *info);
+void ym2608_get_info(void *token, UINT32 state, sndinfo *info);
+void ym2610_get_info(void *token, UINT32 state, sndinfo *info);
+void ym2610b_get_info(void *token, UINT32 state, sndinfo *info);
+void ym2612_get_info(void *token, UINT32 state, sndinfo *info);
+void ym3438_get_info(void *token, UINT32 state, sndinfo *info);
+void ym2413_get_info(void *token, UINT32 state, sndinfo *info);
+void ym3812_get_info(void *token, UINT32 state, sndinfo *info);
+void ym3526_get_info(void *token, UINT32 state, sndinfo *info);
+void ymz280b_get_info(void *token, UINT32 state, sndinfo *info);
+void y8950_get_info(void *token, UINT32 state, sndinfo *info);
+void sn76477_get_info(void *token, UINT32 state, sndinfo *info);
+void sn76489_get_info(void *token, UINT32 state, sndinfo *info);
+void sn76489a_get_info(void *token, UINT32 state, sndinfo *info);
+void sn76494_get_info(void *token, UINT32 state, sndinfo *info);
+void sn76496_get_info(void *token, UINT32 state, sndinfo *info);
+void gamegear_get_info(void *token, UINT32 state, sndinfo *info);
+void smsiii_get_info(void *token, UINT32 state, sndinfo *info);
+void pokey_get_info(void *token, UINT32 state, sndinfo *info);
+void nesapu_get_info(void *token, UINT32 state, sndinfo *info);
+void astrocade_get_info(void *token, UINT32 state, sndinfo *info);
+void namco_get_info(void *token, UINT32 state, sndinfo *info);
+void namco_15xx_get_info(void *token, UINT32 state, sndinfo *info);
+void namco_cus30_get_info(void *token, UINT32 state, sndinfo *info);
+void namco_52xx_get_info(void *token, UINT32 state, sndinfo *info);
+void namco_63701x_get_info(void *token, UINT32 state, sndinfo *info);
+void namcona_get_info(void *token, UINT32 state, sndinfo *info);
+void tms36xx_get_info(void *token, UINT32 state, sndinfo *info);
+void tms3615_get_info(void *token, UINT32 state, sndinfo *info);
+void tms5110_get_info(void *token, UINT32 state, sndinfo *info);
+void tms5220_get_info(void *token, UINT32 state, sndinfo *info);
+void vlm5030_get_info(void *token, UINT32 state, sndinfo *info);
+void adpcm_get_info(void *token, UINT32 state, sndinfo *info);
+void okim6295_get_info(void *token, UINT32 state, sndinfo *info);
+void msm5205_get_info(void *token, UINT32 state, sndinfo *info);
+void msm5232_get_info(void *token, UINT32 state, sndinfo *info);
+void upd7759_get_info(void *token, UINT32 state, sndinfo *info);
+void hc55516_get_info(void *token, UINT32 state, sndinfo *info);
+void k005289_get_info(void *token, UINT32 state, sndinfo *info);
+void k007232_get_info(void *token, UINT32 state, sndinfo *info);
+void k051649_get_info(void *token, UINT32 state, sndinfo *info);
+void k053260_get_info(void *token, UINT32 state, sndinfo *info);
+void k054539_get_info(void *token, UINT32 state, sndinfo *info);
+void segapcm_get_info(void *token, UINT32 state, sndinfo *info);
+void rf5c68_get_info(void *token, UINT32 state, sndinfo *info);
+void cem3394_get_info(void *token, UINT32 state, sndinfo *info);
+void c140_get_info(void *token, UINT32 state, sndinfo *info);
+void qsound_get_info(void *token, UINT32 state, sndinfo *info);
+void saa1099_get_info(void *token, UINT32 state, sndinfo *info);
+void iremga20_get_info(void *token, UINT32 state, sndinfo *info);
+void es5503_get_info(void *token, UINT32 state, sndinfo *info);
+void es5505_get_info(void *token, UINT32 state, sndinfo *info);
+void es5506_get_info(void *token, UINT32 state, sndinfo *info);
+void bsmt2000_get_info(void *token, UINT32 state, sndinfo *info);
+void ymf262_get_info(void *token, UINT32 state, sndinfo *info);
+void ymf278b_get_info(void *token, UINT32 state, sndinfo *info);
+void gaelco_cg1v_get_info(void *token, UINT32 state, sndinfo *info);
+void gaelco_gae1_get_info(void *token, UINT32 state, sndinfo *info);
+void x1_010_get_info(void *token, UINT32 state, sndinfo *info);
+void multipcm_get_info(void *token, UINT32 state, sndinfo *info);
+void c6280_get_info(void *token, UINT32 state, sndinfo *info);
+void tia_get_info(void *token, UINT32 state, sndinfo *info);
+void sp0250_get_info(void *token, UINT32 state, sndinfo *info);
+void scsp_get_info(void *token, UINT32 state, sndinfo *info);
+void psxspu_get_info(void *token, UINT32 state, sndinfo *info);
+void ymf271_get_info(void *token, UINT32 state, sndinfo *info);
+void cdda_get_info(void *token, UINT32 state, sndinfo *info);
+void ics2115_get_info(void *token, UINT32 state, sndinfo *info);
+void st0016_get_info(void *token, UINT32 state, sndinfo *info);
+void c352_get_info(void *token, UINT32 state, sndinfo *info);
+void vrender0_get_info(void *token, UINT32 state, sndinfo *info);
+void votrax_get_info(void *token, UINT32 state, sndinfo *info);
+void es8712_get_info(void *token, UINT32 state, sndinfo *info);
+void rf5c400_get_info(void *token, UINT32 state, sndinfo *info);
+void speaker_get_info(void *token, UINT32 state, sndinfo *info);
+void cdp1869_get_info(void *token, UINT32 state, sndinfo *info);
+void beep_get_info(void *token, UINT32 state, sndinfo *info);
+void wave_get_info(void *token, UINT32 state, sndinfo *info);
+void sid6581_get_info(void *token, UINT32 state, sndinfo *info);
+void sid8580_get_info(void *token, UINT32 state, sndinfo *info);
+void sp0256_get_info(void *token, UINT32 state, sndinfo *info);
+void s14001a_get_info(void *token, UINT32 state, sndinfo *info);
+
+void filter_volume_get_info(void *token, UINT32 state, sndinfo *info);
+void filter_rc_get_info(void *token, UINT32 state, sndinfo *info);
+
+
+
+/***************************************************************************
+ CORE INTERFACE LIST
+***************************************************************************/
+
+static sound_interface sndintrf[SOUND_COUNT];
+
+static const struct
+{
+ sound_type sndtype;
+ void (*get_info)(void *token, UINT32 state, sndinfo *info);
+} sndintrf_map[] =
+{
+ { SOUND_DUMMY, dummy_sound_get_info },
+#if (HAS_CUSTOM)
+ { SOUND_CUSTOM, custom_get_info },
+#endif
+#if (HAS_SAMPLES)
+ { SOUND_SAMPLES, samples_get_info },
+#endif
+#if (HAS_DAC)
+ { SOUND_DAC, dac_get_info },
+#endif
+#if (HAS_DMADAC)
+ { SOUND_DMADAC, dmadac_get_info },
+#endif
+#if (HAS_DISCRETE)
+ { SOUND_DISCRETE, discrete_get_info },
+#endif
+#if (HAS_AY8910)
+ { SOUND_AY8910, ay8910_get_info },
+ { SOUND_AY8912, ay8912_get_info },
+ { SOUND_AY8913, ay8913_get_info },
+ { SOUND_AY8930, ay8930_get_info },
+ { SOUND_YM2149, ym2149_get_info },
+ { SOUND_YM3439, ym3439_get_info },
+ { SOUND_YMZ284, ymz284_get_info },
+ { SOUND_YMZ294, ymz294_get_info },
+#endif
+#if (HAS_YM2203)
+ { SOUND_YM2203, ym2203_get_info },
+#endif
+#if (HAS_YM2151)
+ { SOUND_YM2151, ym2151_get_info },
+#endif
+#if (HAS_YM2608)
+ { SOUND_YM2608, ym2608_get_info },
+#endif
+#if (HAS_YM2610)
+ { SOUND_YM2610, ym2610_get_info },
+#endif
+#if (HAS_YM2610B)
+ { SOUND_YM2610B, ym2610b_get_info },
+#endif
+#if (HAS_YM2612)
+ { SOUND_YM2612, ym2612_get_info },
+#endif
+#if (HAS_YM3438)
+ { SOUND_YM3438, ym3438_get_info },
+#endif
+#if (HAS_YM2413)
+ { SOUND_YM2413, ym2413_get_info },
+#endif
+#if (HAS_YM3812)
+ { SOUND_YM3812, ym3812_get_info },
+#endif
+#if (HAS_YM3526)
+ { SOUND_YM3526, ym3526_get_info },
+#endif
+#if (HAS_YMZ280B)
+ { SOUND_YMZ280B, ymz280b_get_info },
+#endif
+#if (HAS_Y8950)
+ { SOUND_Y8950, y8950_get_info },
+#endif
+#if (HAS_SN76477)
+ { SOUND_SN76477, sn76477_get_info },
+#endif
+#if (HAS_SN76496)
+ { SOUND_SN76489, sn76489_get_info },
+ { SOUND_SN76489A, sn76489a_get_info },
+ { SOUND_SN76494, sn76494_get_info },
+ { SOUND_SN76496, sn76496_get_info },
+ { SOUND_GAMEGEAR, gamegear_get_info },
+ { SOUND_SMSIII, smsiii_get_info },
+#endif
+#if (HAS_POKEY)
+ { SOUND_POKEY, pokey_get_info },
+#endif
+#if (HAS_NES)
+ { SOUND_NES, nesapu_get_info },
+#endif
+#if (HAS_ASTROCADE)
+ { SOUND_ASTROCADE, astrocade_get_info },
+#endif
+#if (HAS_NAMCO)
+ { SOUND_NAMCO, namco_get_info },
+#endif
+#if (HAS_NAMCO_15XX)
+ { SOUND_NAMCO_15XX, namco_15xx_get_info },
+#endif
+#if (HAS_NAMCO_CUS30)
+ { SOUND_NAMCO_CUS30, namco_cus30_get_info },
+#endif
+#if (HAS_NAMCO_52XX)
+ { SOUND_NAMCO_52XX, namco_52xx_get_info },
+#endif
+#if (HAS_NAMCO_63701X)
+ { SOUND_NAMCO_63701X, namco_63701x_get_info },
+#endif
+#if (HAS_NAMCONA)
+ { SOUND_NAMCONA, namcona_get_info },
+#endif
+#if (HAS_TMS36XX)
+ { SOUND_TMS36XX, tms36xx_get_info },
+#endif
+#if (HAS_TMS3615)
+ { SOUND_TMS3615, tms3615_get_info },
+#endif
+#if (HAS_TMS5110)
+ { SOUND_TMS5110, tms5110_get_info },
+#endif
+#if (HAS_TMS5220)
+ { SOUND_TMS5220, tms5220_get_info },
+#endif
+#if (HAS_VLM5030)
+ { SOUND_VLM5030, vlm5030_get_info },
+#endif
+#if (HAS_OKIM6295)
+ { SOUND_OKIM6295, okim6295_get_info },
+#endif
+#if (HAS_MSM5205)
+ { SOUND_MSM5205, msm5205_get_info },
+#endif
+#if (HAS_MSM5232)
+ { SOUND_MSM5232, msm5232_get_info },
+#endif
+#if (HAS_UPD7759)
+ { SOUND_UPD7759, upd7759_get_info },
+#endif
+#if (HAS_HC55516)
+ { SOUND_HC55516, hc55516_get_info },
+#endif
+#if (HAS_K005289)
+ { SOUND_K005289, k005289_get_info },
+#endif
+#if (HAS_K007232)
+ { SOUND_K007232, k007232_get_info },
+#endif
+#if (HAS_K051649)
+ { SOUND_K051649, k051649_get_info },
+#endif
+#if (HAS_K053260)
+ { SOUND_K053260, k053260_get_info },
+#endif
+#if (HAS_K054539)
+ { SOUND_K054539, k054539_get_info },
+#endif
+#if (HAS_SEGAPCM)
+ { SOUND_SEGAPCM, segapcm_get_info },
+#endif
+#if (HAS_RF5C68)
+ { SOUND_RF5C68, rf5c68_get_info },
+#endif
+#if (HAS_CEM3394)
+ { SOUND_CEM3394, cem3394_get_info },
+#endif
+#if (HAS_C140)
+ { SOUND_C140, c140_get_info },
+#endif
+#if (HAS_QSOUND)
+ { SOUND_QSOUND, qsound_get_info },
+#endif
+#if (HAS_SAA1099)
+ { SOUND_SAA1099, saa1099_get_info },
+#endif
+#if (HAS_IREMGA20)
+ { SOUND_IREMGA20, iremga20_get_info },
+#endif
+#if (HAS_ES5503)
+ { SOUND_ES5503, es5503_get_info },
+#endif
+#if (HAS_ES5505)
+ { SOUND_ES5505, es5505_get_info },
+#endif
+#if (HAS_ES5506)
+ { SOUND_ES5506, es5506_get_info },
+#endif
+#if (HAS_BSMT2000)
+ { SOUND_BSMT2000, bsmt2000_get_info },
+#endif
+#if (HAS_YMF262)
+ { SOUND_YMF262, ymf262_get_info },
+#endif
+#if (HAS_YMF278B)
+ { SOUND_YMF278B, ymf278b_get_info },
+#endif
+#if (HAS_GAELCO_CG1V)
+ { SOUND_GAELCO_CG1V, gaelco_cg1v_get_info },
+#endif
+#if (HAS_GAELCO_GAE1)
+ { SOUND_GAELCO_GAE1, gaelco_gae1_get_info },
+#endif
+#if (HAS_X1_010)
+ { SOUND_X1_010, x1_010_get_info },
+#endif
+#if (HAS_MULTIPCM)
+ { SOUND_MULTIPCM, multipcm_get_info },
+#endif
+#if (HAS_C6280)
+ { SOUND_C6280, c6280_get_info },
+#endif
+#if (HAS_TIA)
+ { SOUND_TIA, tia_get_info },
+#endif
+#if (HAS_SP0250)
+ { SOUND_SP0250, sp0250_get_info },
+#endif
+#if (HAS_SCSP)
+ { SOUND_SCSP, scsp_get_info },
+#endif
+#if (HAS_PSXSPU)
+ { SOUND_PSXSPU, psxspu_get_info },
+#endif
+#if (HAS_YMF271)
+ { SOUND_YMF271, ymf271_get_info },
+#endif
+#if (HAS_CDDA)
+ { SOUND_CDDA, cdda_get_info },
+#endif
+#if (HAS_ICS2115)
+ { SOUND_ICS2115, ics2115_get_info },
+#endif
+#if (HAS_ST0016)
+ { SOUND_ST0016, st0016_get_info },
+#endif
+#if (HAS_C352)
+ { SOUND_C352, c352_get_info },
+#endif
+#if (HAS_VRENDER0)
+ { SOUND_VRENDER0, vrender0_get_info },
+#endif
+#if (HAS_VOTRAX)
+ { SOUND_VOTRAX, votrax_get_info },
+#endif
+#if (HAS_ES8712)
+ { SOUND_ES8712, es8712_get_info },
+#endif
+#if (HAS_RF5C400)
+ { SOUND_RF5C400, rf5c400_get_info },
+#endif
+#if (HAS_SPEAKER)
+ { SOUND_SPEAKER, speaker_get_info },
+#endif
+#if (HAS_CDP1869)
+ { SOUND_CDP1869, cdp1869_get_info },
+#endif
+#if (HAS_S14001A)
+ { SOUND_S14001A, s14001a_get_info },
+#endif
+#if (HAS_BEEP)
+ { SOUND_BEEP, beep_get_info },
+#endif
+#if (HAS_WAVE)
+ { SOUND_WAVE, wave_get_info },
+#endif
+#if (HAS_SID6581)
+ { SOUND_SID6581, sid6581_get_info },
+#endif
+#if (HAS_SID8580)
+ { SOUND_SID8580, sid8580_get_info },
+#endif
+#if (HAS_SP0256)
+ { SOUND_SP0256, sp0256_get_info },
+#endif
+
+ { SOUND_FILTER_VOLUME, filter_volume_get_info },
+ { SOUND_FILTER_RC, filter_rc_get_info },
+};
+
+
+
+/***************************************************************************
+ VALIDATION MACROS
+***************************************************************************/
+
+#define VERIFY_SNDNUM(name) \
+ assert_always(sndnum >= 0 && sndnum < totalsnd, #name "() called with invalid sound num!")
+
+#define VERIFY_SNDTI(name) \
+ assert_always(sndtype >= 0 && sndtype < SOUND_COUNT, #name "() called with invalid sound type!"); \
+ assert_always(sndindex >= 0 && sndindex < totalsnd && sound_matrix[sndtype][sndindex] != 0, #name "() called with invalid (type,index) pair!")
+
+#define VERIFY_SNDTYPE(name) \
+ assert_always(sndtype >= 0 && sndtype < SOUND_COUNT, #name "() called with invalid sound type!")
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static sndintrf_data sound[MAX_SOUND];
+static sndintrf_data *current_sound_start;
+static UINT8 sound_matrix[SOUND_COUNT][MAX_SOUND];
+static int totalsnd;
+
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ sndintrf_init - discover all linked sound
+ systems and build a matrix for sound
+ (type,index) pairs for the current Machine
+-------------------------------------------------*/
+
+void sndintrf_init(running_machine *machine)
+{
+ int mapindex;
+
+ /* reset the sndintrf array */
+ memset(sndintrf, 0, sizeof(sndintrf));
+
+ /* build the sndintrf array */
+ for (mapindex = 0; mapindex < sizeof(sndintrf_map) / sizeof(sndintrf_map[0]); mapindex++)
+ {
+ sound_type sndtype = sndintrf_map[mapindex].sndtype;
+ sound_interface *intf = &sndintrf[sndtype];
+ sndinfo info;
+
+ /* start with the get_info routine */
+ intf->get_info = sndintrf_map[mapindex].get_info;
+
+ /* bootstrap the rest of the function pointers */
+ info.set_info = NULL;
+ (*intf->get_info)(NULL, SNDINFO_PTR_SET_INFO, &info);
+ intf->set_info = info.set_info;
+
+ info.start = NULL;
+ (*intf->get_info)(NULL, SNDINFO_PTR_START, &info);
+ intf->start = info.start;
+
+ info.stop = NULL;
+ (*intf->get_info)(NULL, SNDINFO_PTR_STOP, &info);
+ intf->stop = info.stop;
+
+ info.reset = NULL;
+ (*intf->get_info)(NULL, SNDINFO_PTR_RESET, &info);
+ intf->reset = info.reset;
+ }
+
+ /* fill in any empty entries with the dummy sound */
+ for (mapindex = 0; mapindex < SOUND_COUNT; mapindex++)
+ if (sndintrf[mapindex].get_info == NULL)
+ sndintrf[mapindex] = sndintrf[SOUND_DUMMY];
+
+ /* zap the sound data structures */
+ memset(sound, 0, sizeof(sound));
+ totalsnd = 0;
+
+ /* reset the (type,index) matrix */
+ memset(sound_matrix, 0, sizeof(sound_matrix));
+}
+
+
+/*-------------------------------------------------
+ sndintrf_init_sound - initialize data for a
+ particular sndnum
+-------------------------------------------------*/
+
+int sndintrf_init_sound(int sndnum, sound_type sndtype, int clock, const void *config)
+{
+ sndintrf_data *info = &sound[sndnum];
+ int index;
+
+ /* fill in the type and interface */
+ info->intf = sndintrf[sndtype];
+ info->sndtype = sndtype;
+ info->aliastype = sndtype_get_info_int(sndtype, SNDINFO_INT_ALIAS);
+ if (info->aliastype == 0)
+ info->aliastype = sndtype;
+ info->clock = clock;
+
+ /* find an empty slot in the matrix and add it */
+ totalsnd++;
+ for (index = 0; index < MAX_SOUND; index++)
+ if (sound_matrix[info->aliastype][index] == 0)
+ {
+ sound_matrix[info->aliastype][index] = totalsnd;
+ break;
+ }
+ info->index = index;
+
+ /* start the chip, tagging all its streams */
+ current_sound_start = &sound[sndnum];
+ info->token = (*info->intf.start)(index, clock, config);
+ current_sound_start = NULL;
+ VPRINTF((" token = %p\n", info->token));
+
+ /* if that failed, die */
+ if (!info->token)
+ return 1;
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ sndintrf_exit_sound - tear down data for a
+ particular sndnum
+-------------------------------------------------*/
+
+void sndintrf_exit_sound(int sndnum)
+{
+ /* stop the chip */
+ if (sound[sndnum].intf.stop)
+ (*sound[sndnum].intf.stop)(sound[sndnum].token);
+}
+
+
+
+/***************************************************************************
+ HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ sndintrf_register_token - register a token
+ from within the sound_start routine
+-------------------------------------------------*/
+
+void sndintrf_register_token(void *token)
+{
+ if (current_sound_start)
+ current_sound_start->token = token;
+}
+
+
+/*-------------------------------------------------
+ sndti_exists - return TRUE if a (type,index)
+ pair describes an existing chip
+-------------------------------------------------*/
+
+int sndti_exists(sound_type type, int index)
+{
+ return (sound_matrix[type][index] != 0);
+}
+
+
+/*-------------------------------------------------
+ sndti_to_sndnum - map a (type,index) pair to
+ a sound number
+-------------------------------------------------*/
+
+int sndti_to_sndnum(sound_type type, int index)
+{
+ return sound_matrix[type][index] - 1;
+}
+
+
+/*-------------------------------------------------
+ sndnum_to_sndti - map a sound number to a
+ (type,index) pair
+-------------------------------------------------*/
+
+sound_type sndnum_to_sndti(int sndnum, int *index)
+{
+ if (index != NULL)
+ *index = sound[sndnum].index;
+ return sound[sndnum].aliastype;
+}
+
+
+
+/***************************************************************************
+ CHIP INTERFACES BY INDEX
+***************************************************************************/
+
+/*-------------------------------------------------
+ Get info accessors
+-------------------------------------------------*/
+
+INT64 sndnum_get_info_int(int sndnum, UINT32 state)
+{
+ sndinfo info;
+
+ VERIFY_SNDNUM(sndnum_get_info_int);
+ info.i = 0;
+ (*sound[sndnum].intf.get_info)(sound[sndnum].token, state, &info);
+ return info.i;
+}
+
+void *sndnum_get_info_ptr(int sndnum, UINT32 state)
+{
+ sndinfo info;
+
+ VERIFY_SNDNUM(sndnum_get_info_ptr);
+ info.p = NULL;
+ (*sound[sndnum].intf.get_info)(sound[sndnum].token, state, &info);
+ return info.p;
+}
+
+genf *sndnum_get_info_fct(int sndnum, UINT32 state)
+{
+ sndinfo info;
+
+ VERIFY_SNDNUM(sndnum_get_info_fct);
+ info.f = NULL;
+ (*sound[sndnum].intf.get_info)(sound[sndnum].token, state, &info);
+ return info.f;
+}
+
+const char *sndnum_get_info_string(int sndnum, UINT32 state)
+{
+ sndinfo info;
+
+ VERIFY_SNDNUM(sndnum_get_info_string);
+ info.s = NULL;
+ (*sound[sndnum].intf.get_info)(sound[sndnum].token, state, &info);
+ return info.s;
+}
+
+
+/*-------------------------------------------------
+ Set info accessors
+-------------------------------------------------*/
+
+void sndnum_set_info_int(int sndnum, UINT32 state, INT64 data)
+{
+ sndinfo info;
+ VERIFY_SNDNUM(sndnum_set_info_int);
+ info.i = data;
+ (*sound[sndnum].intf.set_info)(sound[sndnum].token, state, &info);
+}
+
+void sndnum_set_info_ptr(int sndnum, UINT32 state, void *data)
+{
+ sndinfo info;
+ VERIFY_SNDNUM(sndnum_set_info_ptr);
+ info.p = data;
+ (*sound[sndnum].intf.set_info)(sound[sndnum].token, state, &info);
+}
+
+void sndnum_set_info_fct(int sndnum, UINT32 state, genf *data)
+{
+ sndinfo info;
+ VERIFY_SNDNUM(sndnum_set_info_ptr);
+ info.f = data;
+ (*sound[sndnum].intf.set_info)(sound[sndnum].token, state, &info);
+}
+
+
+/*-------------------------------------------------
+ Misc accessors
+-------------------------------------------------*/
+
+void sndnum_reset(int sndnum)
+{
+ VERIFY_SNDNUM(sndnum_reset);
+ if (sound[sndnum].intf.reset)
+ (*sound[sndnum].intf.reset)(sound[sndnum].token);
+}
+
+int sndnum_clock(int sndnum)
+{
+ VERIFY_SNDNUM(sndnum_clock);
+ return sound[sndnum].clock;
+}
+
+void *sndnum_token(int sndnum)
+{
+ VERIFY_SNDNUM(sndnum_token);
+ return sound[sndnum].token;
+}
+
+
+
+/***************************************************************************
+ CHIP INTERFACES BY (TYPE,INDEX) PAIR
+***************************************************************************/
+
+/*-------------------------------------------------
+ Get info accessors
+-------------------------------------------------*/
+
+INT64 sndti_get_info_int(sound_type sndtype, int sndindex, UINT32 state)
+{
+ sndinfo info;
+ int sndnum;
+
+ VERIFY_SNDTI(sndti_get_info_int);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ info.i = 0;
+ (*sound[sndnum].intf.get_info)(sound[sndnum].token, state, &info);
+ return info.i;
+}
+
+void *sndti_get_info_ptr(sound_type sndtype, int sndindex, UINT32 state)
+{
+ sndinfo info;
+ int sndnum;
+
+ VERIFY_SNDTI(sndti_get_info_ptr);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ info.p = NULL;
+ (*sound[sndnum].intf.get_info)(sound[sndnum].token, state, &info);
+ return info.p;
+}
+
+genf *sndti_get_info_fct(sound_type sndtype, int sndindex, UINT32 state)
+{
+ sndinfo info;
+ int sndnum;
+
+ VERIFY_SNDTI(sndti_get_info_fct);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ info.f = NULL;
+ (*sound[sndnum].intf.get_info)(sound[sndnum].token, state, &info);
+ return info.f;
+}
+
+const char *sndti_get_info_string(sound_type sndtype, int sndindex, UINT32 state)
+{
+ sndinfo info;
+ int sndnum;
+
+ VERIFY_SNDTI(sndti_get_info_string);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ info.s = NULL;
+ (*sound[sndnum].intf.get_info)(sound[sndnum].token, state, &info);
+ return info.s;
+}
+
+
+/*-------------------------------------------------
+ Set info accessors
+-------------------------------------------------*/
+
+void sndti_set_info_int(sound_type sndtype, int sndindex, UINT32 state, INT64 data)
+{
+ sndinfo info;
+ int sndnum;
+
+ VERIFY_SNDTI(sndti_set_info_int);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ info.i = data;
+ (*sound[sndnum].intf.set_info)(sound[sndnum].token, state, &info);
+}
+
+void sndti_set_info_ptr(sound_type sndtype, int sndindex, UINT32 state, void *data)
+{
+ sndinfo info;
+ int sndnum;
+
+ VERIFY_SNDTI(sndti_set_info_ptr);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ info.p = data;
+ (*sound[sndnum].intf.set_info)(sound[sndnum].token, state, &info);
+}
+
+void sndti_set_info_fct(sound_type sndtype, int sndindex, UINT32 state, genf *data)
+{
+ sndinfo info;
+ int sndnum;
+
+ VERIFY_SNDTI(sndti_set_info_ptr);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ info.f = data;
+ (*sound[sndnum].intf.set_info)(sound[sndnum].token, state, &info);
+}
+
+
+/*-------------------------------------------------
+ Misc accessors
+-------------------------------------------------*/
+
+void sndti_reset(sound_type sndtype, int sndindex)
+{
+ int sndnum;
+
+ VERIFY_SNDTI(sndti_reset);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ if (sound[sndnum].intf.reset)
+ (*sound[sndnum].intf.reset)(sound[sndnum].token);
+}
+
+int sndti_clock(sound_type sndtype, int sndindex)
+{
+ int sndnum;
+ VERIFY_SNDTI(sndti_clock);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ return sound[sndnum].clock;
+}
+
+void *sndti_token(sound_type sndtype, int sndindex)
+{
+ int sndnum;
+ VERIFY_SNDTI(sndti_token);
+ sndnum = sound_matrix[sndtype][sndindex] - 1;
+ return sound[sndnum].token;
+}
+
+
+
+/***************************************************************************
+ CHIP INTERFACES BY TYPE
+***************************************************************************/
+
+/*-------------------------------------------------
+ Get info accessors
+-------------------------------------------------*/
+
+INT64 sndtype_get_info_int(sound_type sndtype, UINT32 state)
+{
+ sndinfo info;
+
+ VERIFY_SNDTYPE(sndtype_get_info_int);
+ info.i = 0;
+ (*sndintrf[sndtype].get_info)(NULL, state, &info);
+ return info.i;
+}
+
+void *sndtype_get_info_ptr(sound_type sndtype, UINT32 state)
+{
+ sndinfo info;
+
+ VERIFY_SNDTYPE(sndtype_get_info_ptr);
+ info.p = NULL;
+ (*sndintrf[sndtype].get_info)(NULL, state, &info);
+ return info.p;
+}
+
+genf *sndtype_get_info_fct(sound_type sndtype, UINT32 state)
+{
+ sndinfo info;
+
+ VERIFY_SNDTYPE(sndtype_get_info_fct);
+ info.f = NULL;
+ (*sndintrf[sndtype].get_info)(NULL, state, &info);
+ return info.f;
+}
+
+const char *sndtype_get_info_string(sound_type sndtype, UINT32 state)
+{
+ sndinfo info;
+
+ VERIFY_SNDTYPE(sndtype_get_info_string);
+ info.s = NULL;
+ (*sndintrf[sndtype].get_info)(NULL, state, &info);
+ return info.s;
+}
+
+
+
+/***************************************************************************
+ DUMMY INTERFACES
+***************************************************************************/
+
+static void *dummy_sound_start(int index, int clock, const void *config)
+{
+ logerror("Warning: starting a dummy sound core -- you are missing a hookup in sndintrf.c!\n");
+ return auto_malloc(1);
+}
+
+
+static void dummy_sound_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void dummy_sound_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = dummy_sound_set_info; break;
+ case SNDINFO_PTR_START: info->start = dummy_sound_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Dummy"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Dummy"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sndintrf.h b/src/emu/sndintrf.h
new file mode 100644
index 00000000000..746fa65ee57
--- /dev/null
+++ b/src/emu/sndintrf.h
@@ -0,0 +1,285 @@
+/***************************************************************************
+
+ sndintrf.h
+
+ Core sound interface functions and definitions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __SNDINTRF_H__
+#define __SNDINTRF_H__
+
+#include "memory.h"
+#include "mame.h"
+#include "state.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_SOUND 32
+
+/* Enum listing all the sound chips */
+typedef enum _sound_type sound_type;
+enum _sound_type
+{
+ SOUND_DUMMY,
+ SOUND_CUSTOM,
+ SOUND_SAMPLES,
+ SOUND_DAC,
+ SOUND_DMADAC,
+ SOUND_DISCRETE,
+ SOUND_AY8910,
+ SOUND_AY8912,
+ SOUND_AY8913,
+ SOUND_AY8930,
+ SOUND_YM2149,
+ SOUND_YM3439,
+ SOUND_YMZ284,
+ SOUND_YMZ294,
+ SOUND_YM2203,
+ SOUND_YM2151,
+ SOUND_YM2608,
+ SOUND_YM2610,
+ SOUND_YM2610B,
+ SOUND_YM2612,
+ SOUND_YM3438,
+ SOUND_YM2413,
+ SOUND_YM3812,
+ SOUND_YM3526,
+ SOUND_YMZ280B,
+ SOUND_Y8950,
+ SOUND_SN76477,
+ SOUND_SN76489,
+ SOUND_SN76489A,
+ SOUND_SN76494,
+ SOUND_SN76496,
+ SOUND_GAMEGEAR,
+ SOUND_SMSIII,
+ SOUND_POKEY,
+ SOUND_NES,
+ SOUND_ASTROCADE,
+ SOUND_NAMCO,
+ SOUND_NAMCO_15XX,
+ SOUND_NAMCO_CUS30,
+ SOUND_NAMCO_52XX,
+ SOUND_NAMCO_63701X,
+ SOUND_NAMCONA,
+ SOUND_TMS36XX,
+ SOUND_TMS3615,
+ SOUND_TMS5110,
+ SOUND_TMS5220,
+ SOUND_VLM5030,
+ SOUND_OKIM6295,
+ SOUND_MSM5205,
+ SOUND_MSM5232,
+ SOUND_UPD7759,
+ SOUND_HC55516,
+ SOUND_K005289,
+ SOUND_K007232,
+ SOUND_K051649,
+ SOUND_K053260,
+ SOUND_K054539,
+ SOUND_SEGAPCM,
+ SOUND_RF5C68,
+ SOUND_CEM3394,
+ SOUND_C140,
+ SOUND_QSOUND,
+ SOUND_SAA1099,
+ SOUND_IREMGA20,
+ SOUND_ES5503,
+ SOUND_ES5505,
+ SOUND_ES5506,
+ SOUND_BSMT2000,
+ SOUND_YMF262,
+ SOUND_YMF278B,
+ SOUND_GAELCO_CG1V,
+ SOUND_GAELCO_GAE1,
+ SOUND_X1_010,
+ SOUND_MULTIPCM,
+ SOUND_C6280,
+ SOUND_TIA,
+ SOUND_SP0250,
+ SOUND_SCSP,
+ SOUND_PSXSPU,
+ SOUND_YMF271,
+ SOUND_CDDA,
+ SOUND_ICS2115,
+ SOUND_ST0016,
+ SOUND_C352,
+ SOUND_VRENDER0,
+ SOUND_VOTRAX,
+ SOUND_ES8712,
+ SOUND_RF5C400,
+ SOUND_SPEAKER,
+ SOUND_CDP1869,
+ SOUND_BEEP,
+ SOUND_WAVE,
+ SOUND_SID6581,
+ SOUND_SID8580,
+ SOUND_SP0256,
+ SOUND_S14001A,
+
+ /* filters start here */
+ SOUND_FILTER_VOLUME,
+ SOUND_FILTER_RC,
+ SOUND_FILTER_LOWPASS,
+
+ SOUND_COUNT
+};
+
+
+/* Sound information constants */
+enum
+{
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ SNDINFO_INT_FIRST = 0x00000,
+
+ SNDINFO_INT_ALIAS = SNDINFO_INT_FIRST, /* R/O: alias to sound type for (type,index) identification */
+
+ SNDINFO_INT_CORE_SPECIFIC = 0x08000, /* R/W: core-specific values start here */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ SNDINFO_PTR_FIRST = 0x10000,
+
+ SNDINFO_PTR_SET_INFO = SNDINFO_PTR_FIRST, /* R/O: void (*set_info)(void *token, UINT32 state, sndinfo *info) */
+ SNDINFO_PTR_START, /* R/O: void *(*start)(int index, int clock, const void *config) */
+ SNDINFO_PTR_STOP, /* R/O: void (*stop)(void *token) */
+ SNDINFO_PTR_RESET, /* R/O: void (*reset)(void *token) */
+
+ SNDINFO_PTR_CORE_SPECIFIC = 0x18000, /* R/W: core-specific values start here */
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ SNDINFO_STR_FIRST = 0x20000,
+
+ SNDINFO_STR_NAME = SNDINFO_STR_FIRST, /* R/O: name of the sound chip */
+ SNDINFO_STR_CORE_FAMILY, /* R/O: family of the sound chip */
+ SNDINFO_STR_CORE_VERSION, /* R/O: version of the sound core */
+ SNDINFO_STR_CORE_FILE, /* R/O: file containing the sound core */
+ SNDINFO_STR_CORE_CREDITS, /* R/O: credits for the sound core */
+
+ SNDINFO_STR_CORE_SPECIFIC = 0x28000 /* R/W: core-specific values start here */
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef union _sndinfo sndinfo;
+union _sndinfo
+{
+ INT64 i; /* generic integers */
+ void * p; /* generic pointers */
+ genf * f; /* generic function pointers */
+ const char *s; /* generic strings */
+
+ void (*set_info)(void *token, UINT32 state, sndinfo *info);
+ void * (*start)(int index, int clock, const void *config);/* SNDINFO_PTR_START */
+ void (*stop)(void *token); /* SNDINFO_PTR_STOP */
+ void (*reset)(void *token); /* SNDINFO_PTR_RESET */
+};
+
+
+
+/***************************************************************************
+ CHIP INTERFACES BY INDEX
+***************************************************************************/
+
+/* get info accessors */
+INT64 sndnum_get_info_int(int sndnum, UINT32 state);
+void *sndnum_get_info_ptr(int sndnum, UINT32 state);
+genf *sndnum_get_info_fct(int sndnum, UINT32 state);
+const char *sndnum_get_info_string(int sndnum, UINT32 state);
+
+/* set info accessors */
+void sndnum_set_info_int(int sndnum, UINT32 state, INT64 data);
+void sndnum_set_info_ptr(int sndnum, UINT32 state, void *data);
+void sndnum_set_info_fct(int sndnum, UINT32 state, genf *data);
+
+#define sndnum_name(sndnum) sndnum_get_info_string(sndnum, SNDINFO_STR_NAME)
+#define sndnum_core_family(sndnum) sndnum_get_info_string(sndnum, SNDINFO_STR_CORE_FAMILY)
+#define sndnum_core_version(sndnum) sndnum_get_info_string(sndnum, SNDINFO_STR_CORE_VERSION)
+#define sndnum_core_file(sndnum) sndnum_get_info_string(sndnum, SNDINFO_STR_CORE_FILE)
+#define sndnum_core_credits(sndnum) sndnum_get_info_string(sndnum, SNDINFO_STR_CORE_CREDITS)
+
+/* misc accessors */
+void sndnum_reset(int sndnum);
+int sndnum_clock(int sndnum);
+void *sndnum_token(int sndnum);
+
+
+
+/***************************************************************************
+ CHIP INTERFACES BY (TYPE,INDEX) PAIR
+***************************************************************************/
+
+/* get info accessors */
+INT64 sndti_get_info_int(sound_type sndtype, int sndindex, UINT32 state);
+void *sndti_get_info_ptr(sound_type sndtype, int sndindex, UINT32 state);
+genf *sndti_get_info_fct(sound_type sndtype, int sndindex, UINT32 state);
+const char *sndti_get_info_string(sound_type sndtype, int sndindex, UINT32 state);
+
+/* set info accessors */
+void sndti_set_info_int(sound_type sndtype, int sndindex, UINT32 state, INT64 data);
+void sndti_set_info_ptr(sound_type sndtype, int sndindex, UINT32 state, void *data);
+void sndti_set_info_fct(sound_type sndtype, int sndindex, UINT32 state, genf *data);
+
+#define sndti_name(sndtype, sndindex) sndti_get_info_string(sndtype, sndindex, SNDINFO_STR_NAME)
+#define sndti_core_family(sndtype, sndindex) sndti_get_info_string(sndtype, sndindex, SNDINFO_STR_CORE_FAMILY)
+#define sndti_core_version(sndtype, sndindex) sndti_get_info_string(sndtype, sndindex, SNDINFO_STR_CORE_VERSION)
+#define sndti_core_file(sndtype, sndindex) sndti_get_info_string(sndtype, sndindex, SNDINFO_STR_CORE_FILE)
+#define sndti_core_credits(sndtype, sndindex) sndti_get_info_string(sndtype, sndindex, SNDINFO_STR_CORE_CREDITS)
+
+/* misc accessors */
+void sndti_reset(sound_type sndtype, int sndindex);
+int sndti_clock(sound_type sndtype, int sndindex);
+void *sndti_token(sound_type sndtype, int sndindex);
+
+/* driver gain controls on chip outputs */
+void sndti_set_output_gain(sound_type sndtype, int sndindex, int output, float gain);
+
+
+
+/***************************************************************************
+ CHIP INTERFACES BY TYPE
+***************************************************************************/
+
+/* get info accessors */
+INT64 sndtype_get_info_int(sound_type sndtype, UINT32 state);
+void *sndtype_get_info_ptr(sound_type sndtype, UINT32 state);
+genf *sndtype_get_info_fct(sound_type sndtype, UINT32 state);
+const char *sndtype_get_info_string(sound_type sndtype, UINT32 state);
+
+#define sndtype_name(sndtype) sndtype_get_info_string(sndtype, SNDINFO_STR_NAME)
+#define sndtype_core_family(sndtype) sndtype_get_info_string(sndtype, SNDINFO_STR_CORE_FAMILY)
+#define sndtype_core_version(sndtype) sndtype_get_info_string(sndtype, SNDINFO_STR_CORE_VERSION)
+#define sndtype_core_file(sndtype) sndtype_get_info_string(sndtype, SNDINFO_STR_CORE_FILE)
+#define sndtype_core_credits(sndtype) sndtype_get_info_string(sndtype, SNDINFO_STR_CORE_CREDITS)
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* Initialization/Tear down */
+void sndintrf_init(running_machine *machine);
+int sndintrf_init_sound(int sndnum, sound_type sndtype, int clock, const void *config);
+void sndintrf_exit_sound(int sndnum);
+void sndintrf_register_token(void *token);
+
+/* Misc helpers */
+int sndti_exists(sound_type sndtype, int sndindex);
+int sndti_to_sndnum(sound_type type, int index);
+sound_type sndnum_to_sndti(int sndnum, int *index);
+
+
+#endif /* __SNDINTRF_H__ */
diff --git a/src/emu/sound.c b/src/emu/sound.c
new file mode 100644
index 00000000000..df7c9277cff
--- /dev/null
+++ b/src/emu/sound.c
@@ -0,0 +1,955 @@
+/***************************************************************************
+
+ sound.c
+
+ Core sound functions and definitions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "osdepend.h"
+#include "streams.h"
+#include "config.h"
+#include "profiler.h"
+#include "sound/wavwrite.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE (0)
+
+#if VERBOSE
+#define VPRINTF(x) mame_printf_debug x
+#else
+#define VPRINTF(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_MIXER_CHANNELS 100
+#define SOUND_UPDATE_FREQUENCY ATTOTIME_IN_HZ(50)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _sound_output sound_output;
+struct _sound_output
+{
+ sound_stream * stream; /* associated stream */
+ int output; /* output number */
+};
+
+
+typedef struct _sound_info sound_info;
+struct _sound_info
+{
+ const sound_config *sound; /* pointer to the sound info */
+ int outputs; /* number of outputs from this instance */
+ sound_output * output; /* array of output information */
+};
+
+
+typedef struct _speaker_input speaker_input;
+struct _speaker_input
+{
+ float gain; /* current gain */
+ float default_gain; /* default gain */
+ char * name; /* name of this input */
+};
+
+
+typedef struct _speaker_info speaker_info;
+struct _speaker_info
+{
+ const speaker_config *speaker; /* pointer to the speaker info */
+ sound_stream * mixer_stream; /* mixing stream */
+ int inputs; /* number of input streams */
+ speaker_input * input; /* array of input information */
+#ifdef MAME_DEBUG
+ INT32 max_sample; /* largest sample value we've seen */
+ INT32 clipped_samples; /* total number of clipped samples */
+ INT32 total_samples; /* total number of samples */
+#endif
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static emu_timer *sound_update_timer;
+
+static int totalsnd;
+static sound_info sound[MAX_SOUND];
+
+static int totalspeakers;
+static speaker_info speaker[MAX_SPEAKER];
+
+static INT16 *finalmix;
+static UINT32 finalmix_leftover;
+static INT32 *leftmix, *rightmix;
+
+static int sound_muted;
+static int sound_attenuation;
+static int global_sound_enabled;
+static int nosound_mode;
+
+static wav_file *wavfile;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void sound_reset(running_machine *machine);
+static void sound_exit(running_machine *machine);
+static void sound_pause(running_machine *machine, int pause);
+static void sound_load(int config_type, xml_data_node *parentnode);
+static void sound_save(int config_type, xml_data_node *parentnode);
+static TIMER_CALLBACK( sound_update );
+static void start_sound_chips(void);
+static void start_speakers(void);
+static void route_sound(void);
+static void mixer_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ find_speaker_by_tag - find a tagged speaker
+-------------------------------------------------*/
+
+INLINE speaker_info *find_speaker_by_tag(const char *tag)
+{
+ int spknum;
+
+ /* attempt to find the speaker in our list */
+ for (spknum = 0; spknum < totalspeakers; spknum++)
+ if (strcmp(speaker[spknum].speaker->tag, tag) == 0)
+ return &speaker[spknum];
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ find_sound_by_tag - find a tagged sound chip
+-------------------------------------------------*/
+
+INLINE sound_info *find_sound_by_tag(const char *tag)
+{
+ int sndnum;
+
+ /* attempt to find the speaker in our list */
+ for (sndnum = 0; sndnum < totalsnd; sndnum++)
+ if (sound[sndnum].sound->tag && !strcmp(sound[sndnum].sound->tag, tag))
+ return &sound[sndnum];
+ return NULL;
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ sound_init - start up the sound system
+-------------------------------------------------*/
+
+void sound_init(running_machine *machine)
+{
+ attotime update_frequency = SOUND_UPDATE_FREQUENCY;
+ const char *filename;
+
+ /* handle -nosound */
+ nosound_mode = !options_get_bool(mame_options(), OPTION_SOUND);
+ if (nosound_mode)
+ Machine->sample_rate = 11025;
+
+ /* count the speakers */
+ for (totalspeakers = 0; Machine->drv->speaker[totalspeakers].tag; totalspeakers++) ;
+ VPRINTF(("total speakers = %d\n", totalspeakers));
+
+ /* allocate memory for mix buffers */
+ leftmix = auto_malloc(Machine->sample_rate * sizeof(*leftmix));
+ rightmix = auto_malloc(Machine->sample_rate * sizeof(*rightmix));
+ finalmix = auto_malloc(Machine->sample_rate * sizeof(*finalmix));
+
+ /* allocate a global timer for sound timing */
+ sound_update_timer = timer_alloc(sound_update);
+ timer_adjust(sound_update_timer, update_frequency, 0, update_frequency);
+
+ /* initialize the streams engine */
+ VPRINTF(("streams_init\n"));
+ streams_init(machine, update_frequency.attoseconds);
+
+ /* now start up the sound chips and tag their streams */
+ VPRINTF(("start_sound_chips\n"));
+ start_sound_chips();
+
+ /* then create all the speakers */
+ VPRINTF(("start_speakers\n"));
+ start_speakers();
+
+ /* finally, do all the routing */
+ VPRINTF(("route_sound\n"));
+ route_sound();
+
+ /* open the output WAV file if specified */
+ filename = options_get_string(mame_options(), OPTION_WAVWRITE);
+ if (filename[0] != 0)
+ wavfile = wav_open(filename, machine->sample_rate, 2);
+
+ /* enable sound by default */
+ global_sound_enabled = TRUE;
+ sound_muted = FALSE;
+ sound_set_attenuation(options_get_int(mame_options(), OPTION_VOLUME));
+
+ /* register callbacks */
+ config_register("mixer", sound_load, sound_save);
+ add_pause_callback(machine, sound_pause);
+ add_reset_callback(machine, sound_reset);
+ add_exit_callback(machine, sound_exit);
+}
+
+
+/*-------------------------------------------------
+ sound_exit - clean up after ourselves
+-------------------------------------------------*/
+
+static void sound_exit(running_machine *machine)
+{
+ int sndnum;
+
+ /* close any open WAV file */
+ if (wavfile != NULL)
+ wav_close(wavfile);
+
+#ifdef MAME_DEBUG
+{
+ int spknum;
+
+ /* log the maximum sample values for all speakers */
+ for (spknum = 0; spknum < totalspeakers; spknum++)
+ if (speaker[spknum].max_sample > 0)
+ {
+ speaker_info *spk = &speaker[spknum];
+ mame_printf_debug("Speaker \"%s\" - max = %d (gain *= %f) - %d%% samples clipped\n", spk->speaker->tag, spk->max_sample, 32767.0 / (spk->max_sample ? spk->max_sample : 1), (int)((double)spk->clipped_samples * 100.0 / spk->total_samples));
+ }
+}
+#endif /* MAME_DEBUG */
+
+ /* stop all the sound chips */
+ for (sndnum = 0; sndnum < MAX_SOUND; sndnum++)
+ if (Machine->drv->sound[sndnum].type != SOUND_DUMMY)
+ sndintrf_exit_sound(sndnum);
+
+ /* reset variables */
+ totalspeakers = 0;
+ totalsnd = 0;
+ memset(&speaker, 0, sizeof(speaker));
+ memset(&sound, 0, sizeof(sound));
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ start_sound_chips - loop over all sound chips
+ and initialize them
+-------------------------------------------------*/
+
+static void start_sound_chips(void)
+{
+ int sndnum;
+
+ /* reset the sound array */
+ memset(sound, 0, sizeof(sound));
+
+ /* start up all the sound chips */
+ for (sndnum = 0; sndnum < MAX_SOUND; sndnum++)
+ {
+ const sound_config *msound = &Machine->drv->sound[sndnum];
+ sound_info *info;
+ int num_regs;
+ int index;
+
+ /* stop when we hit an empty entry */
+ if (msound->type == SOUND_DUMMY)
+ break;
+ totalsnd++;
+
+ /* zap all the info */
+ info = &sound[sndnum];
+ memset(info, 0, sizeof(*info));
+
+ /* copy in all the relevant info */
+ info->sound = msound;
+
+ /* start the chip, tagging all its streams */
+ VPRINTF(("sndnum = %d -- sound_type = %d\n", sndnum, msound->type));
+ num_regs = state_save_get_reg_count();
+ streams_set_tag(Machine, info);
+ if (sndintrf_init_sound(sndnum, msound->type, msound->clock, msound->config) != 0)
+ fatalerror("Sound chip #%d (%s) failed to initialize!", sndnum, sndnum_name(sndnum));
+
+ /* if no state registered for saving, we can't save */
+ num_regs = state_save_get_reg_count() - num_regs;
+ if (num_regs == 0)
+ {
+ logerror("Sound chip #%d (%s) did not register any state to save!\n", sndnum, sndnum_name(sndnum));
+ if (Machine->gamedrv->flags & GAME_SUPPORTS_SAVE)
+ fatalerror("Sound chip #%d (%s) did not register any state to save!", sndnum, sndnum_name(sndnum));
+ }
+
+ /* now count the outputs */
+ VPRINTF(("Counting outputs\n"));
+ for (index = 0; ; index++)
+ {
+ sound_stream *stream = stream_find_by_tag(info, index);
+ if (!stream)
+ break;
+ info->outputs += stream_get_outputs(stream);
+ VPRINTF((" stream %p, %d outputs\n", stream, stream_get_outputs(stream)));
+ }
+
+ /* if we have outputs, examine them */
+ if (info->outputs)
+ {
+ /* allocate an array to hold them */
+ info->output = auto_malloc(info->outputs * sizeof(*info->output));
+ VPRINTF((" %d outputs total\n", info->outputs));
+
+ /* now fill the array */
+ info->outputs = 0;
+ for (index = 0; ; index++)
+ {
+ sound_stream *stream = stream_find_by_tag(info, index);
+ int outputs, outputnum;
+
+ if (!stream)
+ break;
+ outputs = stream_get_outputs(stream);
+
+ /* fill in an entry for each output */
+ for (outputnum = 0; outputnum < outputs; outputnum++)
+ {
+ info->output[info->outputs].stream = stream;
+ info->output[info->outputs].output = outputnum;
+ info->outputs++;
+ }
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ start_speakers - loop over all speakers and
+ initialize them
+-------------------------------------------------*/
+
+static void start_speakers(void)
+{
+ /* reset the speaker array */
+ memset(speaker, 0, sizeof(speaker));
+
+ /* start up all the speakers */
+ for (totalspeakers = 0; totalspeakers < MAX_SPEAKER; totalspeakers++)
+ {
+ const speaker_config *mspeaker = &Machine->drv->speaker[totalspeakers];
+ speaker_info *info;
+
+ /* stop when we hit an empty entry */
+ if (mspeaker->tag == NULL)
+ break;
+
+ /* zap all the info */
+ info = &speaker[totalspeakers];
+ memset(info, 0, sizeof(*info));
+
+ /* copy in all the relevant info */
+ info->speaker = mspeaker;
+ info->mixer_stream = NULL;
+ info->inputs = 0;
+ }
+}
+
+
+/*-------------------------------------------------
+ route_sound - route sound outputs to target
+ inputs
+-------------------------------------------------*/
+
+static void route_sound(void)
+{
+ int sndnum, spknum, routenum, outputnum;
+
+ /* iterate over all the sound chips */
+ for (sndnum = 0; sndnum < totalsnd; sndnum++)
+ {
+ sound_info *info = &sound[sndnum];
+
+ /* iterate over all routes */
+ for (routenum = 0; routenum < info->sound->routes; routenum++)
+ {
+ const sound_route *mroute = &info->sound->route[routenum];
+ speaker_info *speaker;
+ sound_info *sound;
+
+ /* find the target */
+ speaker = find_speaker_by_tag(mroute->target);
+ sound = find_sound_by_tag(mroute->target);
+
+ /* if neither found, it's fatal */
+ if (speaker == NULL && sound == NULL)
+ fatalerror("Sound route \"%s\" not found!\n", mroute->target);
+
+ /* if we got a speaker, bump its input count */
+ if (speaker != NULL)
+ {
+ if (mroute->output >= 0 && mroute->output < info->outputs)
+ speaker->inputs++;
+ else if (mroute->output == ALL_OUTPUTS)
+ speaker->inputs += info->outputs;
+ }
+ }
+ }
+
+ /* now allocate the mixers and input data */
+ streams_set_tag(Machine, NULL);
+ for (spknum = 0; spknum < totalspeakers; spknum++)
+ {
+ speaker_info *info = &speaker[spknum];
+ if (info->inputs != 0)
+ {
+ info->mixer_stream = stream_create(info->inputs, 1, Machine->sample_rate, info, mixer_update);
+ info->input = auto_malloc(info->inputs * sizeof(*info->input));
+ info->inputs = 0;
+ }
+ else
+ logerror("Warning: speaker \"%s\" has no inputs\n", info->speaker->tag);
+ }
+
+ /* iterate again over all the sound chips */
+ for (sndnum = 0; sndnum < totalsnd; sndnum++)
+ {
+ sound_info *info = &sound[sndnum];
+
+ /* iterate over all routes */
+ for (routenum = 0; routenum < info->sound->routes; routenum++)
+ {
+ const sound_route *mroute = &info->sound->route[routenum];
+ speaker_info *speaker;
+ sound_info *sound;
+
+ /* find the target */
+ speaker = find_speaker_by_tag(mroute->target);
+ sound = find_sound_by_tag(mroute->target);
+
+ /* if it's a speaker, set the input */
+ if (speaker != NULL)
+ {
+ for (outputnum = 0; outputnum < info->outputs; outputnum++)
+ if (mroute->output == outputnum || mroute->output == ALL_OUTPUTS)
+ {
+ char namebuf[256];
+ int index;
+
+ sndnum_to_sndti(sndnum, &index);
+
+ /* fill in the input data on this speaker */
+ speaker->input[speaker->inputs].gain = mroute->gain;
+ speaker->input[speaker->inputs].default_gain = mroute->gain;
+ sprintf(namebuf, "%s:%s #%d.%d", speaker->speaker->tag, sndnum_name(sndnum), index, outputnum);
+ speaker->input[speaker->inputs].name = auto_strdup(namebuf);
+
+ /* connect the output to the input */
+ stream_set_input(speaker->mixer_stream, speaker->inputs++, info->output[outputnum].stream, info->output[outputnum].output, mroute->gain);
+ }
+ }
+
+ /* if it's a sound chip, set the input */
+ else
+ {
+ for (outputnum = 0; outputnum < info->outputs; outputnum++)
+ if (mroute->output == outputnum || mroute->output == ALL_OUTPUTS)
+ stream_set_input(sound->output[0].stream, 0, info->output[outputnum].stream, info->output[outputnum].output, mroute->gain);
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ GLOBAL STATE MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ sound_reset - reset all sound chips
+-------------------------------------------------*/
+
+static void sound_reset(running_machine *machine)
+{
+ int sndnum;
+
+ /* reset all the sound chips */
+ for (sndnum = 0; sndnum < MAX_SOUND; sndnum++)
+ if (Machine->drv->sound[sndnum].type != SOUND_DUMMY)
+ sndnum_reset(sndnum);
+}
+
+
+/*-------------------------------------------------
+ sound_pause - pause sound output
+-------------------------------------------------*/
+
+static void sound_pause(running_machine *machine, int pause)
+{
+ if (pause)
+ sound_muted |= 0x02;
+ else
+ sound_muted &= ~0x02;
+ osd_set_mastervolume(sound_muted ? -32 : sound_attenuation);
+}
+
+
+/*-------------------------------------------------
+ sound_pause - pause sound output
+-------------------------------------------------*/
+
+void sound_mute(int mute)
+{
+ if (mute)
+ sound_muted |= 0x01;
+ else
+ sound_muted &= ~0x01;
+ osd_set_mastervolume(sound_muted ? -32 : sound_attenuation);
+}
+
+
+/*-------------------------------------------------
+ sound_set_attenuation - set the global volume
+-------------------------------------------------*/
+
+void sound_set_attenuation(int attenuation)
+{
+ sound_attenuation = attenuation;
+ osd_set_mastervolume(sound_muted ? -32 : sound_attenuation);
+}
+
+
+/*-------------------------------------------------
+ sound_get_attenuation - return the global
+ volume
+-------------------------------------------------*/
+
+int sound_get_attenuation(void)
+{
+ return sound_attenuation;
+}
+
+
+/*-------------------------------------------------
+ sound_global_enable - enable/disable sound
+ globally
+-------------------------------------------------*/
+
+void sound_global_enable(int enable)
+{
+ global_sound_enabled = enable;
+}
+
+
+
+/***************************************************************************
+ SOUND SAVE/LOAD
+***************************************************************************/
+
+/*-------------------------------------------------
+ sound_load - read and apply data from the
+ configuration file
+-------------------------------------------------*/
+
+static void sound_load(int config_type, xml_data_node *parentnode)
+{
+ xml_data_node *channelnode;
+ int mixernum;
+
+ /* we only care about game files */
+ if (config_type != CONFIG_TYPE_GAME)
+ return;
+
+ /* might not have any data */
+ if (parentnode == NULL)
+ return;
+
+ /* iterate over channel nodes */
+ for (channelnode = xml_get_sibling(parentnode->child, "channel"); channelnode; channelnode = xml_get_sibling(channelnode->next, "channel"))
+ {
+ mixernum = xml_get_attribute_int(channelnode, "index", -1);
+ if (mixernum >= 0 && mixernum < MAX_MIXER_CHANNELS)
+ {
+ float defvol = xml_get_attribute_float(channelnode, "defvol", -1000.0);
+ float newvol = xml_get_attribute_float(channelnode, "newvol", -1000.0);
+ if (defvol == sound_get_default_gain(mixernum) && newvol != -1000.0)
+ sound_set_user_gain(mixernum, newvol);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ sound_save - save data to the configuration
+ file
+-------------------------------------------------*/
+
+static void sound_save(int config_type, xml_data_node *parentnode)
+{
+ int mixernum;
+
+ /* we only care about game files */
+ if (config_type != CONFIG_TYPE_GAME)
+ return;
+
+ /* iterate over mixer channels */
+ if (parentnode != NULL)
+ for (mixernum = 0; mixernum < MAX_MIXER_CHANNELS; mixernum++)
+ {
+ float defvol = sound_get_default_gain(mixernum);
+ float newvol = sound_get_user_gain(mixernum);
+
+ if (defvol != newvol)
+ {
+ xml_data_node *channelnode = xml_add_child(parentnode, "channel", NULL);
+ if (channelnode != NULL)
+ {
+ xml_set_attribute_int(channelnode, "index", mixernum);
+ xml_set_attribute_float(channelnode, "defvol", defvol);
+ xml_set_attribute_float(channelnode, "newvol", newvol);
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ MIXING STAGE
+***************************************************************************/
+
+/*-------------------------------------------------
+ sound_update - mix everything down to
+ its final form and send it to the OSD layer
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( sound_update )
+{
+ UINT32 finalmix_step, finalmix_offset;
+ int samples_this_update = 0;
+ int sample, spknum;
+
+ VPRINTF(("sound_update\n"));
+
+ profiler_mark(PROFILER_SOUND);
+
+ /* force all the speaker streams to generate the proper number of samples */
+ for (spknum = 0; spknum < totalspeakers; spknum++)
+ {
+ speaker_info *spk = &speaker[spknum];
+ const stream_sample_t *stream_buf;
+
+ /* get the output buffer */
+ if (spk->mixer_stream != NULL)
+ {
+ int numsamples;
+
+ /* update the stream, getting the start/end pointers around the operation */
+ stream_buf = stream_get_output_since_last_update(spk->mixer_stream, 0, &numsamples);
+
+ /* set or assert that all streams have the same count */
+ if (samples_this_update == 0)
+ {
+ samples_this_update = numsamples;
+
+ /* reset the mixing streams */
+ memset(leftmix, 0, samples_this_update * sizeof(*leftmix));
+ memset(rightmix, 0, samples_this_update * sizeof(*rightmix));
+ }
+ assert(samples_this_update == numsamples);
+
+#ifdef MAME_DEBUG
+ /* debug version: keep track of the maximum sample */
+ for (sample = 0; sample < samples_this_update; sample++)
+ {
+ if (stream_buf[sample] > spk->max_sample)
+ spk->max_sample = stream_buf[sample];
+ else if (-stream_buf[sample] > spk->max_sample)
+ spk->max_sample = -stream_buf[sample];
+ if (stream_buf[sample] > 32767 || stream_buf[sample] < -32768)
+ spk->clipped_samples++;
+ spk->total_samples++;
+ }
+#endif
+
+ /* mix if sound is enabled */
+ if (global_sound_enabled && !nosound_mode)
+ {
+ /* if the speaker is centered, send to both left and right */
+ if (spk->speaker->x == 0)
+ for (sample = 0; sample < samples_this_update; sample++)
+ {
+ leftmix[sample] += stream_buf[sample];
+ rightmix[sample] += stream_buf[sample];
+ }
+
+ /* if the speaker is to the left, send only to the left */
+ else if (spk->speaker->x < 0)
+ for (sample = 0; sample < samples_this_update; sample++)
+ leftmix[sample] += stream_buf[sample];
+
+ /* if the speaker is to the right, send only to the right */
+ else
+ for (sample = 0; sample < samples_this_update; sample++)
+ rightmix[sample] += stream_buf[sample];
+ }
+ }
+ }
+
+ /* now downmix the final result */
+ finalmix_step = video_get_speed_factor();
+ finalmix_offset = 0;
+ for (sample = finalmix_leftover; sample < samples_this_update * 100; sample += finalmix_step)
+ {
+ int sampindex = sample / 100;
+ INT32 samp;
+
+ /* clamp the left side */
+ samp = leftmix[sampindex];
+ if (samp < -32768)
+ samp = -32768;
+ else if (samp > 32767)
+ samp = 32767;
+ finalmix[finalmix_offset++] = samp;
+
+ /* clamp the right side */
+ samp = rightmix[sampindex];
+ if (samp < -32768)
+ samp = -32768;
+ else if (samp > 32767)
+ samp = 32767;
+ finalmix[finalmix_offset++] = samp;
+ }
+ finalmix_leftover = sample - samples_this_update * 100;
+
+ /* play the result */
+ if (finalmix_offset > 0)
+ {
+ osd_update_audio_stream(finalmix, finalmix_offset / 2);
+ if (wavfile != NULL)
+ wav_add_data_16(wavfile, finalmix, finalmix_offset);
+ }
+
+ /* update the streamer */
+ streams_update(machine);
+
+ profiler_mark(PROFILER_END);
+}
+
+
+/*-------------------------------------------------
+ mixer_update - mix all inputs to one output
+-------------------------------------------------*/
+
+static void mixer_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ speaker_info *speaker = param;
+ int numinputs = speaker->inputs;
+ int pos;
+
+ VPRINTF(("Mixer_update(%d)\n", length));
+
+ /* loop over samples */
+ for (pos = 0; pos < length; pos++)
+ {
+ INT32 sample = inputs[0][pos];
+ int inp;
+
+ /* add up all the inputs */
+ for (inp = 1; inp < numinputs; inp++)
+ sample += inputs[inp][pos];
+ buffer[0][pos] = sample;
+ }
+}
+
+
+
+/***************************************************************************
+ MISCELLANEOUS HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ sndti_set_output_gain - set the gain of a
+ particular output
+-------------------------------------------------*/
+
+void sndti_set_output_gain(sound_type type, int index, int output, float gain)
+{
+ int sndnum = sndti_to_sndnum(type, index);
+
+ if (sndnum < 0)
+ {
+ logerror("sndti_set_output_gain called for invalid sound type %d, index %d\n", type, index);
+ return;
+ }
+ if (output >= sound[sndnum].outputs)
+ {
+ logerror("sndti_set_output_gain called for invalid sound output %d (type %d, index %d)\n", output, type, index);
+ return;
+ }
+ stream_set_output_gain(sound[sndnum].output[output].stream, sound[sndnum].output[output].output, gain);
+}
+
+
+
+/***************************************************************************
+ USER GAIN CONTROLS
+***************************************************************************/
+
+/*-------------------------------------------------
+ index_to_input - map an absolute index to
+ a particular input
+-------------------------------------------------*/
+
+INLINE speaker_info *index_to_input(int index, int *input)
+{
+ int count = 0, speakernum;
+
+ /* scan through the speakers until we find the indexed input */
+ for (speakernum = 0; speakernum < totalspeakers; speakernum++)
+ {
+ if (index < count + speaker[speakernum].inputs)
+ {
+ *input = index - count;
+ return &speaker[speakernum];
+ }
+ count += speaker[speakernum].inputs;
+ }
+
+ /* index out of range */
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ sound_get_user_gain_count - return the number
+ of user-controllable gain parameters
+-------------------------------------------------*/
+
+int sound_get_user_gain_count(void)
+{
+ int count = 0, speakernum;
+
+ /* count up the number of speaker inputs */
+ for (speakernum = 0; speakernum < totalspeakers; speakernum++)
+ count += speaker[speakernum].inputs;
+ return count;
+}
+
+
+/*-------------------------------------------------
+ sound_set_user_gain - set the nth user gain
+ value
+-------------------------------------------------*/
+
+void sound_set_user_gain(int index, float gain)
+{
+ int inputnum;
+ speaker_info *spk = index_to_input(index, &inputnum);
+
+ if (spk != NULL)
+ {
+ spk->input[inputnum].gain = gain;
+ stream_set_input_gain(spk->mixer_stream, inputnum, gain);
+ }
+}
+
+
+/*-------------------------------------------------
+ sound_get_user_gain - get the nth user gain
+ value
+-------------------------------------------------*/
+
+float sound_get_user_gain(int index)
+{
+ int inputnum;
+ speaker_info *spk = index_to_input(index, &inputnum);
+ return (spk != NULL) ? spk->input[inputnum].gain : 0;
+}
+
+
+/*-------------------------------------------------
+ sound_get_default_gain - return the default
+ gain of the nth user value
+-------------------------------------------------*/
+
+float sound_get_default_gain(int index)
+{
+ int inputnum;
+ speaker_info *spk = index_to_input(index, &inputnum);
+ return (spk != NULL) ? spk->input[inputnum].default_gain : 0;
+}
+
+
+/*-------------------------------------------------
+ sound_get_user_gain_name - return the name
+ of the nth user value
+-------------------------------------------------*/
+
+const char *sound_get_user_gain_name(int index)
+{
+ int inputnum;
+ speaker_info *spk = index_to_input(index, &inputnum);
+ return (spk != NULL) ? spk->input[inputnum].name : NULL;
+}
+
+
+/*-------------------------------------------------
+ sound_find_sndnum_by_tag - return a sndnum
+ by finding the appropriate tag
+-------------------------------------------------*/
+
+int sound_find_sndnum_by_tag(const char *tag)
+{
+ int index;
+
+ /* find a match */
+ for (index = 0; index < MAX_SOUND; index++)
+ if (sound[index].sound != NULL && sound[index].sound->tag != NULL)
+ if (strcmp(tag, sound[index].sound->tag) == 0)
+ return index;
+
+ return -1;
+}
diff --git a/src/emu/sound.h b/src/emu/sound.h
new file mode 100644
index 00000000000..041d923d4b8
--- /dev/null
+++ b/src/emu/sound.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+
+ sound.h
+
+ Core sound interface functions and definitions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __SOUND_H__
+#define __SOUND_H__
+
+#include "mamecore.h"
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_ROUTES (16) /* maximum number of streams of any chip */
+#define ALL_OUTPUTS (-1) /* special value indicating all outputs for the current chip */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* Sound route for the machine driver */
+typedef struct _sound_route sound_route;
+struct _sound_route
+{
+ int output; /* output ID */
+ const char *target; /* tag of the target */
+ float gain; /* gain */
+};
+
+
+/* Sound configuration for the machine driver */
+typedef struct _sound_config sound_config;
+struct _sound_config
+{
+ sound_type type; /* what type of sound chip? */
+ int clock; /* clock speed */
+ const void *config; /* configuration for this chip */
+ const char *tag; /* tag for this chip */
+ int routes; /* number of routes we have */
+ sound_route route[MAX_ROUTES]; /* routes for the various streams */
+};
+
+
+/* Speaker configuration for the machine driver */
+typedef struct _speaker_config speaker_config;
+struct _speaker_config
+{
+ const char *tag; /* tag for this speaker */
+ float x, y, z; /* positioning vector */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* core interfaces */
+void sound_init(running_machine *machine);
+
+/* global sound controls */
+void sound_mute(int mute);
+void sound_set_attenuation(int attenuation);
+int sound_get_attenuation(void);
+void sound_global_enable(int enable);
+
+/* user gain controls on speaker inputs for mixing */
+int sound_get_user_gain_count(void);
+void sound_set_user_gain(int index, float gain);
+float sound_get_user_gain(int index);
+float sound_get_default_gain(int index);
+const char *sound_get_user_gain_name(int index);
+
+/* misc helpers */
+int sound_find_sndnum_by_tag(const char *tag);
+
+
+#endif /* __SOUND_H__ */
diff --git a/src/emu/sound/2151intf.c b/src/emu/sound/2151intf.c
new file mode 100644
index 00000000000..682a7221431
--- /dev/null
+++ b/src/emu/sound/2151intf.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+
+ 2151intf.c
+
+ Support interface YM2151(OPM)
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "fm.h"
+#include "2151intf.h"
+#include "ym2151.h"
+
+
+struct ym2151_info
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ const struct YM2151interface *intf;
+};
+
+
+static void ym2151_update(void *param, stream_sample_t **inputs, stream_sample_t **buffers, int length)
+{
+ struct ym2151_info *info = param;
+ YM2151UpdateOne(info->chip, buffers, length);
+}
+
+
+static void ym2151_postload(void *param)
+{
+ struct ym2151_info *info = param;
+ YM2151Postload(info->chip);
+}
+
+
+static void *ym2151_start(int sndindex, int clock, const void *config)
+{
+ static const struct YM2151interface dummy = { 0 };
+ struct ym2151_info *info;
+ int rate;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = config ? config : &dummy;
+
+ rate = clock/64;
+
+ /* stream setup */
+ info->stream = stream_create(0,2,rate,info,ym2151_update);
+
+ info->chip = YM2151Init(sndindex,clock,rate);
+
+ state_save_register_func_postload_ptr(ym2151_postload, info);
+
+ if (info->chip != 0)
+ {
+ YM2151SetIrqHandler(info->chip,info->intf->irqhandler);
+ YM2151SetPortWriteHandler(info->chip,info->intf->portwritehandler);
+ return info;
+ }
+ return NULL;
+}
+
+
+static void ym2151_stop(void *token)
+{
+ struct ym2151_info *info = token;
+ YM2151Shutdown(info->chip);
+}
+
+static void ym2151_reset(void *token)
+{
+ struct ym2151_info *info = token;
+ YM2151ResetChip(info->chip);
+}
+
+static int lastreg0,lastreg1,lastreg2;
+
+READ8_HANDLER( YM2151_status_port_0_r )
+{
+ struct ym2151_info *token = sndti_token(SOUND_YM2151, 0);
+ return YM2151ReadStatus(token->chip);
+}
+
+READ8_HANDLER( YM2151_status_port_1_r )
+{
+ struct ym2151_info *token = sndti_token(SOUND_YM2151, 1);
+ return YM2151ReadStatus(token->chip);
+}
+
+READ8_HANDLER( YM2151_status_port_2_r )
+{
+ struct ym2151_info *token = sndti_token(SOUND_YM2151, 2);
+ return YM2151ReadStatus(token->chip);
+}
+
+WRITE8_HANDLER( YM2151_register_port_0_w )
+{
+ lastreg0 = data;
+}
+WRITE8_HANDLER( YM2151_register_port_1_w )
+{
+ lastreg1 = data;
+}
+WRITE8_HANDLER( YM2151_register_port_2_w )
+{
+ lastreg2 = data;
+}
+
+WRITE8_HANDLER( YM2151_data_port_0_w )
+{
+ struct ym2151_info *token = sndti_token(SOUND_YM2151, 0);
+ stream_update(token->stream);
+ YM2151WriteReg(token->chip,lastreg0,data);
+}
+
+WRITE8_HANDLER( YM2151_data_port_1_w )
+{
+ struct ym2151_info *token = sndti_token(SOUND_YM2151, 1);
+ stream_update(token->stream);
+ YM2151WriteReg(token->chip,lastreg1,data);
+}
+
+WRITE8_HANDLER( YM2151_data_port_2_w )
+{
+ struct ym2151_info *token = sndti_token(SOUND_YM2151, 2);
+ stream_update(token->stream);
+ YM2151WriteReg(token->chip,lastreg2,data);
+}
+
+WRITE8_HANDLER( YM2151_word_0_w )
+{
+ if (offset)
+ YM2151_data_port_0_w(0,data);
+ else
+ YM2151_register_port_0_w(0,data);
+}
+
+WRITE8_HANDLER( YM2151_word_1_w )
+{
+ if (offset)
+ YM2151_data_port_1_w(0,data);
+ else
+ YM2151_register_port_1_w(0,data);
+}
+
+READ16_HANDLER( YM2151_status_port_0_lsb_r )
+{
+ return YM2151_status_port_0_r(0);
+}
+
+READ16_HANDLER( YM2151_status_port_1_lsb_r )
+{
+ return YM2151_status_port_1_r(0);
+}
+
+READ16_HANDLER( YM2151_status_port_2_lsb_r )
+{
+ return YM2151_status_port_2_r(0);
+}
+
+
+WRITE16_HANDLER( YM2151_register_port_0_lsb_w )
+{
+ if (ACCESSING_LSB)
+ YM2151_register_port_0_w(0, data & 0xff);
+}
+
+WRITE16_HANDLER( YM2151_register_port_1_lsb_w )
+{
+ if (ACCESSING_LSB)
+ YM2151_register_port_1_w(0, data & 0xff);
+}
+
+WRITE16_HANDLER( YM2151_register_port_2_lsb_w )
+{
+ if (ACCESSING_LSB)
+ YM2151_register_port_2_w(0, data & 0xff);
+}
+
+WRITE16_HANDLER( YM2151_data_port_0_lsb_w )
+{
+ if (ACCESSING_LSB)
+ YM2151_data_port_0_w(0, data & 0xff);
+}
+
+WRITE16_HANDLER( YM2151_data_port_1_lsb_w )
+{
+ if (ACCESSING_LSB)
+ YM2151_data_port_1_w(0, data & 0xff);
+}
+
+WRITE16_HANDLER( YM2151_data_port_2_lsb_w )
+{
+ if (ACCESSING_LSB)
+ YM2151_data_port_2_w(0, data & 0xff);
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ym2151_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym2151_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym2151_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym2151_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym2151_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym2151_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM2151"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/2151intf.h b/src/emu/sound/2151intf.h
new file mode 100644
index 00000000000..17140c818d7
--- /dev/null
+++ b/src/emu/sound/2151intf.h
@@ -0,0 +1,37 @@
+#ifndef YM2151INTF_H
+#define YM2151INTF_H
+
+struct YM2151interface
+{
+ void (*irqhandler)(int irq);
+ write8_handler portwritehandler;
+};
+
+READ8_HANDLER( YM2151_status_port_0_r );
+READ8_HANDLER( YM2151_status_port_1_r );
+READ8_HANDLER( YM2151_status_port_2_r );
+
+WRITE8_HANDLER( YM2151_register_port_0_w );
+WRITE8_HANDLER( YM2151_register_port_1_w );
+WRITE8_HANDLER( YM2151_register_port_2_w );
+
+WRITE8_HANDLER( YM2151_data_port_0_w );
+WRITE8_HANDLER( YM2151_data_port_1_w );
+WRITE8_HANDLER( YM2151_data_port_2_w );
+
+WRITE8_HANDLER( YM2151_word_0_w );
+WRITE8_HANDLER( YM2151_word_1_w );
+
+READ16_HANDLER( YM2151_status_port_0_lsb_r );
+READ16_HANDLER( YM2151_status_port_1_lsb_r );
+READ16_HANDLER( YM2151_status_port_2_lsb_r );
+
+WRITE16_HANDLER( YM2151_register_port_0_lsb_w );
+WRITE16_HANDLER( YM2151_register_port_1_lsb_w );
+WRITE16_HANDLER( YM2151_register_port_2_lsb_w );
+
+WRITE16_HANDLER( YM2151_data_port_0_lsb_w );
+WRITE16_HANDLER( YM2151_data_port_1_lsb_w );
+WRITE16_HANDLER( YM2151_data_port_2_lsb_w );
+
+#endif
diff --git a/src/emu/sound/2203intf.c b/src/emu/sound/2203intf.c
new file mode 100644
index 00000000000..839802de6eb
--- /dev/null
+++ b/src/emu/sound/2203intf.c
@@ -0,0 +1,348 @@
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "2203intf.h"
+#include "fm.h"
+
+
+struct ym2203_info
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ void * psg;
+ const struct YM2203interface *intf;
+};
+
+
+static void psg_set_clock(void *param, int clock)
+{
+ struct ym2203_info *info = param;
+ ay8910_set_clock_ym(info->psg, clock);
+}
+
+static void psg_write(void *param, int address, int data)
+{
+ struct ym2203_info *info = param;
+ ay8910_write_ym(info->psg, address, data);
+}
+
+static int psg_read(void *param)
+{
+ struct ym2203_info *info = param;
+ return ay8910_read_ym(info->psg);
+}
+
+static void psg_reset(void *param)
+{
+ struct ym2203_info *info = param;
+ ay8910_reset_ym(info->psg);
+}
+
+static const struct ssg_callbacks psgintf =
+{
+ psg_set_clock,
+ psg_write,
+ psg_read,
+ psg_reset
+};
+
+/* IRQ Handler */
+static void IRQHandler(void *param,int irq)
+{
+ struct ym2203_info *info = param;
+ if(info->intf->handler) info->intf->handler(irq);
+}
+
+/* Timer overflow callback from timer.c */
+static TIMER_CALLBACK_PTR( timer_callback_2203_0 )
+{
+ struct ym2203_info *info = param;
+ YM2203TimerOver(info->chip,0);
+}
+
+static TIMER_CALLBACK_PTR( timer_callback_2203_1 )
+{
+ struct ym2203_info *info = param;
+ YM2203TimerOver(info->chip,1);
+}
+
+/* update request from fm.c */
+void YM2203UpdateRequest(void *param)
+{
+ struct ym2203_info *info = param;
+ stream_update(info->stream);
+}
+
+
+static void timer_handler(void *param,int c,int count,int clock)
+{
+ struct ym2203_info *info = param;
+ if( count == 0 )
+ { /* Reset FM Timer */
+ timer_enable(info->timer[c], 0);
+ }
+ else
+ { /* Start FM Timer */
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(clock), count);
+ if (!timer_enable(info->timer[c], 1))
+ timer_adjust_ptr(info->timer[c], period, attotime_zero);
+ }
+}
+
+static void ym2203_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct ym2203_info *info = param;
+ YM2203UpdateOne(info->chip, buffer[0], length);
+}
+
+
+static void ym2203_postload(void *param)
+{
+ struct ym2203_info *info = param;
+ YM2203Postload(info->chip);
+}
+
+
+static void *ym2203_start(int sndindex, int clock, const void *config)
+{
+ static const struct YM2203interface generic_2203 = { 0 };
+ const struct YM2203interface *intf = config ? config : &generic_2203;
+ struct ym2203_info *info;
+ int rate = clock/72; /* ??? */
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = intf;
+ info->psg = ay8910_start_ym(SOUND_YM2203, sndindex, clock, 3, intf->portAread, intf->portBread, intf->portAwrite, intf->portBwrite);
+ if (!info->psg) return NULL;
+
+ /* Timer Handler set */
+ info->timer[0] = timer_alloc_ptr(timer_callback_2203_0, info);
+ info->timer[1] = timer_alloc_ptr(timer_callback_2203_1, info);
+
+ /* stream system initialize */
+ info->stream = stream_create(0,1,rate,info,ym2203_stream_update);
+
+ /* Initialize FM emurator */
+ info->chip = YM2203Init(info,sndindex,clock,rate,timer_handler,IRQHandler,&psgintf);
+
+ state_save_register_func_postload_ptr(ym2203_postload, info);
+
+ if (info->chip)
+ return info;
+
+ /* error */
+ /* stream close */
+ return NULL;
+}
+
+static void ym2203_stop(void *token)
+{
+ struct ym2203_info *info = token;
+ YM2203Shutdown(info->chip);
+ ay8910_stop_ym(info->psg);
+}
+
+static void ym2203_reset(void *token)
+{
+ struct ym2203_info *info = token;
+ YM2203ResetChip(info->chip);
+}
+
+
+
+READ8_HANDLER( YM2203_status_port_0_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 0); return YM2203Read(info->chip,0); }
+READ8_HANDLER( YM2203_status_port_1_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 1); return YM2203Read(info->chip,0); }
+READ8_HANDLER( YM2203_status_port_2_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 2); return YM2203Read(info->chip,0); }
+READ8_HANDLER( YM2203_status_port_3_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 3); return YM2203Read(info->chip,0); }
+READ8_HANDLER( YM2203_status_port_4_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 4); return YM2203Read(info->chip,0); }
+
+READ8_HANDLER( YM2203_read_port_0_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 0); return YM2203Read(info->chip,1); }
+READ8_HANDLER( YM2203_read_port_1_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 1); return YM2203Read(info->chip,1); }
+READ8_HANDLER( YM2203_read_port_2_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 2); return YM2203Read(info->chip,1); }
+READ8_HANDLER( YM2203_read_port_3_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 3); return YM2203Read(info->chip,1); }
+READ8_HANDLER( YM2203_read_port_4_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 4); return YM2203Read(info->chip,1); }
+
+WRITE8_HANDLER( YM2203_control_port_0_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 0);
+ YM2203Write(info->chip,0,data);
+}
+WRITE8_HANDLER( YM2203_control_port_1_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 1);
+ YM2203Write(info->chip,0,data);
+}
+WRITE8_HANDLER( YM2203_control_port_2_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 2);
+ YM2203Write(info->chip,0,data);
+}
+WRITE8_HANDLER( YM2203_control_port_3_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 3);
+ YM2203Write(info->chip,0,data);
+}
+WRITE8_HANDLER( YM2203_control_port_4_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 4);
+ YM2203Write(info->chip,0,data);
+}
+
+WRITE8_HANDLER( YM2203_write_port_0_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 0);
+ YM2203Write(info->chip,1,data);
+}
+WRITE8_HANDLER( YM2203_write_port_1_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 1);
+ YM2203Write(info->chip,1,data);
+}
+WRITE8_HANDLER( YM2203_write_port_2_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 2);
+ YM2203Write(info->chip,1,data);
+}
+WRITE8_HANDLER( YM2203_write_port_3_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 3);
+ YM2203Write(info->chip,1,data);
+}
+WRITE8_HANDLER( YM2203_write_port_4_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 4);
+ YM2203Write(info->chip,1,data);
+}
+
+
+READ16_HANDLER( YM2203_status_port_0_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 0); return YM2203Read(info->chip,0) | 0xff00; }
+READ16_HANDLER( YM2203_status_port_1_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 1); return YM2203Read(info->chip,0) | 0xff00; }
+READ16_HANDLER( YM2203_status_port_2_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 2); return YM2203Read(info->chip,0) | 0xff00; }
+READ16_HANDLER( YM2203_status_port_3_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 3); return YM2203Read(info->chip,0) | 0xff00; }
+READ16_HANDLER( YM2203_status_port_4_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 4); return YM2203Read(info->chip,0) | 0xff00; }
+
+READ16_HANDLER( YM2203_read_port_0_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 0); return YM2203Read(info->chip,1) | 0xff00; }
+READ16_HANDLER( YM2203_read_port_1_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 1); return YM2203Read(info->chip,1) | 0xff00; }
+READ16_HANDLER( YM2203_read_port_2_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 2); return YM2203Read(info->chip,1) | 0xff00; }
+READ16_HANDLER( YM2203_read_port_3_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 3); return YM2203Read(info->chip,1) | 0xff00; }
+READ16_HANDLER( YM2203_read_port_4_lsb_r ) { struct ym2203_info *info = sndti_token(SOUND_YM2203, 4); return YM2203Read(info->chip,1) | 0xff00; }
+
+WRITE16_HANDLER( YM2203_control_port_0_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 0);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,0,data);
+}
+WRITE16_HANDLER( YM2203_control_port_1_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 1);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,0,data);
+}
+WRITE16_HANDLER( YM2203_control_port_2_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 2);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,0,data);
+}
+WRITE16_HANDLER( YM2203_control_port_3_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 3);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,0,data);
+}
+WRITE16_HANDLER( YM2203_control_port_4_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 4);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,0,data);
+}
+
+WRITE16_HANDLER( YM2203_write_port_0_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 0);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,1,data);
+}
+WRITE16_HANDLER( YM2203_write_port_1_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 1);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,1,data);
+}
+WRITE16_HANDLER( YM2203_write_port_2_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 2);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,1,data);
+}
+WRITE16_HANDLER( YM2203_write_port_3_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 3);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,1,data);
+}
+WRITE16_HANDLER( YM2203_write_port_4_lsb_w )
+{
+ struct ym2203_info *info = sndti_token(SOUND_YM2203, 4);
+ if (ACCESSING_LSB)
+ YM2203Write(info->chip,1,data);
+}
+
+
+WRITE8_HANDLER( YM2203_word_0_w )
+{
+ if (offset)
+ YM2203_write_port_0_w(0,data);
+ else
+ YM2203_control_port_0_w(0,data);
+}
+
+WRITE8_HANDLER( YM2203_word_1_w )
+{
+ if (offset)
+ YM2203_write_port_1_w(0,data);
+ else
+ YM2203_control_port_1_w(0,data);
+}
+
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ym2203_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym2203_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym2203_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym2203_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym2203_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym2203_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM2203"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/2203intf.h b/src/emu/sound/2203intf.h
new file mode 100644
index 00000000000..2de7e324011
--- /dev/null
+++ b/src/emu/sound/2203intf.h
@@ -0,0 +1,67 @@
+#ifndef YM2203INTF_H
+#define YM2203INTF_H
+
+#include "ay8910.h"
+
+struct YM2203interface
+{
+ read8_handler portAread;
+ read8_handler portBread;
+ write8_handler portAwrite;
+ write8_handler portBwrite;
+ void (*handler)(int irq);
+};
+
+
+READ8_HANDLER( YM2203_status_port_0_r );
+READ8_HANDLER( YM2203_status_port_1_r );
+READ8_HANDLER( YM2203_status_port_2_r );
+READ8_HANDLER( YM2203_status_port_3_r );
+READ8_HANDLER( YM2203_status_port_4_r );
+
+READ8_HANDLER( YM2203_read_port_0_r );
+READ8_HANDLER( YM2203_read_port_1_r );
+READ8_HANDLER( YM2203_read_port_2_r );
+READ8_HANDLER( YM2203_read_port_3_r );
+READ8_HANDLER( YM2203_read_port_4_r );
+
+WRITE8_HANDLER( YM2203_control_port_0_w );
+WRITE8_HANDLER( YM2203_control_port_1_w );
+WRITE8_HANDLER( YM2203_control_port_2_w );
+WRITE8_HANDLER( YM2203_control_port_3_w );
+WRITE8_HANDLER( YM2203_control_port_4_w );
+
+WRITE8_HANDLER( YM2203_write_port_0_w );
+WRITE8_HANDLER( YM2203_write_port_1_w );
+WRITE8_HANDLER( YM2203_write_port_2_w );
+WRITE8_HANDLER( YM2203_write_port_3_w );
+WRITE8_HANDLER( YM2203_write_port_4_w );
+
+READ16_HANDLER( YM2203_status_port_0_lsb_r );
+READ16_HANDLER( YM2203_status_port_1_lsb_r );
+READ16_HANDLER( YM2203_status_port_2_lsb_r );
+READ16_HANDLER( YM2203_status_port_3_lsb_r );
+READ16_HANDLER( YM2203_status_port_4_lsb_r );
+
+READ16_HANDLER( YM2203_read_port_0_lsb_r );
+READ16_HANDLER( YM2203_read_port_1_lsb_r );
+READ16_HANDLER( YM2203_read_port_2_lsb_r );
+READ16_HANDLER( YM2203_read_port_3_lsb_r );
+READ16_HANDLER( YM2203_read_port_4_lsb_r );
+
+WRITE16_HANDLER( YM2203_control_port_0_lsb_w );
+WRITE16_HANDLER( YM2203_control_port_1_lsb_w );
+WRITE16_HANDLER( YM2203_control_port_2_lsb_w );
+WRITE16_HANDLER( YM2203_control_port_3_lsb_w );
+WRITE16_HANDLER( YM2203_control_port_4_lsb_w );
+
+WRITE16_HANDLER( YM2203_write_port_0_lsb_w );
+WRITE16_HANDLER( YM2203_write_port_1_lsb_w );
+WRITE16_HANDLER( YM2203_write_port_2_lsb_w );
+WRITE16_HANDLER( YM2203_write_port_3_lsb_w );
+WRITE16_HANDLER( YM2203_write_port_4_lsb_w );
+
+WRITE8_HANDLER( YM2203_word_0_w );
+WRITE8_HANDLER( YM2203_word_1_w );
+
+#endif
diff --git a/src/emu/sound/2413intf.c b/src/emu/sound/2413intf.c
new file mode 100644
index 00000000000..2cb51b0af20
--- /dev/null
+++ b/src/emu/sound/2413intf.c
@@ -0,0 +1,186 @@
+/****************************************************************
+
+ MAME / MESS functions
+
+****************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "ym2413.h"
+#include "2413intf.h"
+
+//#define YM2413ISA
+#ifdef YM2413ISA
+ #include <pc.h>
+#endif
+
+
+/* for stream system */
+struct ym2413_info
+{
+ sound_stream * stream;
+ void * chip;
+};
+
+/*
+void YM2413DAC_update(int chip,stream_sample_t **inputs, stream_sample_t **_buffer,int length)
+{
+ INT16 *buffer = _buffer[0];
+ static int out = 0;
+
+ if ( ym2413[chip].reg[0x0F] & 0x01 )
+ {
+ out = ((ym2413[chip].reg[0x10] & 0xF0) << 7);
+ }
+ while (length--) *(buffer++) = out;
+}
+*/
+
+static void ym2413_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffers, int length)
+{
+ struct ym2413_info *info = param;
+ YM2413UpdateOne(info->chip, buffers, length);
+}
+
+static void _stream_update(void *param, int interval)
+{
+ struct ym2413_info *info = param;
+ stream_update(info->stream);
+}
+
+static void *ym2413_start(int sndindex, int clock, const void *config)
+{
+ int rate = clock/72;
+ struct ym2413_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ /* emulator create */
+ info->chip = YM2413Init(clock, rate);
+ if (!info->chip)
+ return NULL;
+
+ /* stream system initialize */
+ info->stream = stream_create(0,2,rate,info,ym2413_stream_update);
+
+ YM2413SetUpdateHandler(info->chip, _stream_update, info);
+
+ return info;
+
+
+
+
+#if 0
+ int i, tst;
+ char name[40];
+
+ num = intf->num;
+
+ tst = YM3812_sh_start (msound);
+ if (tst)
+ return 1;
+
+ for (i=0;i<num;i++)
+ {
+ ym2413_reset (i);
+
+ ym2413[i].DAC_stream = stream_create(0, 1, clock/72, i, YM2413DAC_update);
+
+ if (ym2413[i].DAC_stream == -1)
+ return 1;
+ }
+ return 0;
+#endif
+
+}
+
+static void ym2413_stop (void *chip)
+{
+ struct ym2413_info *info = chip;
+ YM2413Shutdown(info->chip);
+}
+
+static void ym2413_reset (void *chip)
+{
+ struct ym2413_info *info = chip;
+ YM2413ResetChip(info->chip);
+}
+
+
+#ifdef YM2413ISA
+WRITE8_HANDLER( YM2413_register_port_0_w ) {
+int i,a;
+ outportb(0x308,data); // ym2413_write (0, 0, data);
+ //add delay
+ for (i=0; i<0x20; i++)
+ a = inportb(0x80);
+
+ } /* 1st chip */
+#else
+WRITE8_HANDLER( YM2413_register_port_0_w ) { struct ym2413_info *info = sndti_token(SOUND_YM2413, 0); YM2413Write (info->chip, 0, data); } /* 1st chip */
+#endif
+WRITE8_HANDLER( YM2413_register_port_1_w ) { struct ym2413_info *info = sndti_token(SOUND_YM2413, 1); YM2413Write (info->chip, 0, data); } /* 2nd chip */
+WRITE8_HANDLER( YM2413_register_port_2_w ) { struct ym2413_info *info = sndti_token(SOUND_YM2413, 2); YM2413Write (info->chip, 0, data); } /* 3rd chip */
+WRITE8_HANDLER( YM2413_register_port_3_w ) { struct ym2413_info *info = sndti_token(SOUND_YM2413, 3); YM2413Write (info->chip, 0, data); } /* 4th chip */
+
+#ifdef YM2413ISA
+WRITE8_HANDLER( YM2413_data_port_0_w ) {
+int i,a;
+ outportb(0x309,data);// YM2413Write (sndti_token(SOUND_YM2413, 0), 1, data);
+ //add delay
+ for (i=0; i<0x40; i++)
+ a = inportb(0x80);
+ } /* 1st chip */
+#else
+WRITE8_HANDLER( YM2413_data_port_0_w ) { struct ym2413_info *info = sndti_token(SOUND_YM2413, 0); YM2413Write (info->chip, 1, data); } /* 1st chip */
+#endif
+WRITE8_HANDLER( YM2413_data_port_1_w ) { struct ym2413_info *info = sndti_token(SOUND_YM2413, 1); YM2413Write (info->chip, 1, data); } /* 2nd chip */
+WRITE8_HANDLER( YM2413_data_port_2_w ) { struct ym2413_info *info = sndti_token(SOUND_YM2413, 2); YM2413Write (info->chip, 1, data); } /* 3rd chip */
+WRITE8_HANDLER( YM2413_data_port_3_w ) { struct ym2413_info *info = sndti_token(SOUND_YM2413, 3); YM2413Write (info->chip, 1, data); } /* 4th chip */
+
+WRITE16_HANDLER( YM2413_register_port_0_lsb_w ) { if (ACCESSING_LSB) YM2413_register_port_0_w(offset,data & 0xff); }
+WRITE16_HANDLER( YM2413_register_port_0_msb_w ) { if (ACCESSING_MSB) YM2413_register_port_0_w(offset,((data & 0xff00) >> 8)); }
+WRITE16_HANDLER( YM2413_register_port_1_lsb_w ) { if (ACCESSING_LSB) YM2413_register_port_1_w(offset,data & 0xff); }
+WRITE16_HANDLER( YM2413_register_port_2_lsb_w ) { if (ACCESSING_LSB) YM2413_register_port_2_w(offset,data & 0xff); }
+WRITE16_HANDLER( YM2413_register_port_3_lsb_w ) { if (ACCESSING_LSB) YM2413_register_port_3_w(offset,data & 0xff); }
+WRITE16_HANDLER( YM2413_data_port_0_lsb_w ) { if (ACCESSING_LSB) YM2413_data_port_0_w(offset,data & 0xff); }
+WRITE16_HANDLER( YM2413_data_port_0_msb_w ) { if (ACCESSING_MSB) YM2413_data_port_0_w(offset,((data & 0xff00) >> 8)); }
+WRITE16_HANDLER( YM2413_data_port_1_lsb_w ) { if (ACCESSING_LSB) YM2413_data_port_1_w(offset,data & 0xff); }
+WRITE16_HANDLER( YM2413_data_port_2_lsb_w ) { if (ACCESSING_LSB) YM2413_data_port_2_w(offset,data & 0xff); }
+WRITE16_HANDLER( YM2413_data_port_3_lsb_w ) { if (ACCESSING_LSB) YM2413_data_port_3_w(offset,data & 0xff); }
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ym2413_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym2413_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym2413_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym2413_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym2413_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym2413_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM2413"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/2413intf.h b/src/emu/sound/2413intf.h
new file mode 100644
index 00000000000..a1517bedd3b
--- /dev/null
+++ b/src/emu/sound/2413intf.h
@@ -0,0 +1,26 @@
+#ifndef YM2413INTF_H
+#define YM2413INTF_H
+
+
+WRITE8_HANDLER( YM2413_register_port_0_w );
+WRITE8_HANDLER( YM2413_register_port_1_w );
+WRITE8_HANDLER( YM2413_register_port_2_w );
+WRITE8_HANDLER( YM2413_register_port_3_w );
+WRITE8_HANDLER( YM2413_data_port_0_w );
+WRITE8_HANDLER( YM2413_data_port_1_w );
+WRITE8_HANDLER( YM2413_data_port_2_w );
+WRITE8_HANDLER( YM2413_data_port_3_w );
+
+WRITE16_HANDLER( YM2413_register_port_0_lsb_w );
+WRITE16_HANDLER( YM2413_register_port_0_msb_w );
+WRITE16_HANDLER( YM2413_register_port_1_lsb_w );
+WRITE16_HANDLER( YM2413_register_port_2_lsb_w );
+WRITE16_HANDLER( YM2413_register_port_3_lsb_w );
+WRITE16_HANDLER( YM2413_data_port_0_lsb_w );
+WRITE16_HANDLER( YM2413_data_port_0_msb_w );
+WRITE16_HANDLER( YM2413_data_port_1_lsb_w );
+WRITE16_HANDLER( YM2413_data_port_2_lsb_w );
+WRITE16_HANDLER( YM2413_data_port_3_lsb_w );
+
+#endif
+
diff --git a/src/emu/sound/2608intf.c b/src/emu/sound/2608intf.c
new file mode 100644
index 00000000000..13c3d018809
--- /dev/null
+++ b/src/emu/sound/2608intf.c
@@ -0,0 +1,314 @@
+/***************************************************************************
+
+ 2608intf.c
+
+ The YM2608 emulator supports up to 2 chips.
+ Each chip has the following connections:
+ - Status Read / Control Write A
+ - Port Read / Data Write A
+ - Control Write B
+ - Data Write B
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "ay8910.h"
+#include "2608intf.h"
+#include "fm.h"
+
+struct ym2608_info
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ void * psg;
+ const struct YM2608interface *intf;
+};
+
+
+
+static void psg_set_clock(void *param, int clock)
+{
+ struct ym2608_info *info = param;
+ ay8910_set_clock_ym(info->psg, clock);
+}
+
+static void psg_write(void *param, int address, int data)
+{
+ struct ym2608_info *info = param;
+ ay8910_write_ym(info->psg, address, data);
+}
+
+static int psg_read(void *param)
+{
+ struct ym2608_info *info = param;
+ return ay8910_read_ym(info->psg);
+}
+
+static void psg_reset(void *param)
+{
+ struct ym2608_info *info = param;
+ ay8910_reset_ym(info->psg);
+}
+
+static const struct ssg_callbacks psgintf =
+{
+ psg_set_clock,
+ psg_write,
+ psg_read,
+ psg_reset
+};
+
+
+/* IRQ Handler */
+static void IRQHandler(void *param,int irq)
+{
+ struct ym2608_info *info = param;
+ if(info->intf->handler) info->intf->handler(irq);
+}
+
+/* Timer overflow callback from timer.c */
+static TIMER_CALLBACK_PTR( timer_callback_2608_0 )
+{
+ struct ym2608_info *info = param;
+ YM2608TimerOver(info->chip,0);
+}
+
+static TIMER_CALLBACK_PTR( timer_callback_2608_1 )
+{
+ struct ym2608_info *info = param;
+ YM2608TimerOver(info->chip,1);
+}
+
+static void timer_handler(void *param,int c,int count,int clock)
+{
+ struct ym2608_info *info = param;
+ if( count == 0 )
+ { /* Reset FM Timer */
+ timer_enable(info->timer[c], 0);
+ }
+ else
+ { /* Start FM Timer */
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(clock), count);
+ if (!timer_enable(info->timer[c], 1))
+ timer_adjust_ptr(info->timer[c], period, attotime_zero);
+ }
+}
+
+/* update request from fm.c */
+void YM2608UpdateRequest(void *param)
+{
+ struct ym2608_info *info = param;
+ stream_update(info->stream);
+}
+
+static void ym2608_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffers, int length)
+{
+ struct ym2608_info *info = param;
+ YM2608UpdateOne(info->chip, buffers, length);
+}
+
+
+static void ym2608_postload(void *param)
+{
+ struct ym2608_info *info = param;
+ YM2608Postload(info->chip);
+}
+
+
+static void *ym2608_start(int sndindex, int clock, const void *config)
+{
+ static const struct YM2608interface generic_2608 = { 0 };
+ const struct YM2608interface *intf = config ? config : &generic_2608;
+ int rate = clock/72;
+ void *pcmbufa;
+ int pcmsizea;
+
+ struct ym2608_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = intf;
+ info->psg = ay8910_start_ym(SOUND_YM2608, sndindex, clock, 1, intf->portAread, intf->portBread, intf->portAwrite, intf->portBwrite);
+ if (!info->psg) return NULL;
+
+ /* Timer Handler set */
+ info->timer[0] = timer_alloc_ptr(timer_callback_2608_0, info);
+ info->timer[1] = timer_alloc_ptr(timer_callback_2608_1, info);
+
+ /* stream system initialize */
+ info->stream = stream_create(0,2,rate,info,ym2608_stream_update);
+ /* setup adpcm buffers */
+ pcmbufa = (void *)(memory_region(info->intf->pcmrom));
+ pcmsizea = memory_region_length(info->intf->pcmrom);
+
+ /* initialize YM2608 */
+ info->chip = YM2608Init(info,sndindex,clock,rate,
+ pcmbufa,pcmsizea,
+ timer_handler,IRQHandler,&psgintf);
+
+ state_save_register_func_postload_ptr(ym2608_postload, info);
+
+ if (info->chip)
+ return info;
+
+ /* error */
+ return NULL;
+}
+
+static void ym2608_stop(void *token)
+{
+ struct ym2608_info *info = token;
+ YM2608Shutdown(info->chip);
+ ay8910_stop_ym(info->psg);
+}
+
+static void ym2608_reset(void *token)
+{
+ struct ym2608_info *info = token;
+ YM2608ResetChip(info->chip);
+}
+
+/************************************************/
+/* Status Read for YM2608 - Chip 0 */
+/************************************************/
+READ8_HANDLER( YM2608_status_port_0_A_r )
+{
+//logerror("PC %04x: 2608 S0A=%02X\n",activecpu_get_pc(),YM2608Read(sndti_token(SOUND_YM2608, 0),0));
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
+ return YM2608Read(info->chip,0);
+}
+
+READ8_HANDLER( YM2608_status_port_0_B_r )
+{
+//logerror("PC %04x: 2608 S0B=%02X\n",activecpu_get_pc(),YM2608Read(sndti_token(SOUND_YM2608, 0),2));
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
+ return YM2608Read(info->chip,2);
+}
+
+/************************************************/
+/* Status Read for YM2608 - Chip 1 */
+/************************************************/
+READ8_HANDLER( YM2608_status_port_1_A_r ) {
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
+ return YM2608Read(info->chip,0);
+}
+
+READ8_HANDLER( YM2608_status_port_1_B_r ) {
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
+ return YM2608Read(info->chip,2);
+}
+
+/************************************************/
+/* Port Read for YM2608 - Chip 0 */
+/************************************************/
+READ8_HANDLER( YM2608_read_port_0_r ){
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
+ return YM2608Read(info->chip,1);
+}
+
+/************************************************/
+/* Port Read for YM2608 - Chip 1 */
+/************************************************/
+READ8_HANDLER( YM2608_read_port_1_r ){
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
+ return YM2608Read(info->chip,1);
+}
+
+/************************************************/
+/* Control Write for YM2608 - Chip 0 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2608_control_port_0_A_w )
+{
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
+ YM2608Write(info->chip,0,data);
+}
+
+WRITE8_HANDLER( YM2608_control_port_0_B_w )
+{
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
+ YM2608Write(info->chip,2,data);
+}
+
+/************************************************/
+/* Control Write for YM2608 - Chip 1 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2608_control_port_1_A_w ){
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
+ YM2608Write(info->chip,0,data);
+}
+
+WRITE8_HANDLER( YM2608_control_port_1_B_w ){
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
+ YM2608Write(info->chip,2,data);
+}
+
+/************************************************/
+/* Data Write for YM2608 - Chip 0 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2608_data_port_0_A_w )
+{
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
+ YM2608Write(info->chip,1,data);
+}
+
+WRITE8_HANDLER( YM2608_data_port_0_B_w )
+{
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
+ YM2608Write(info->chip,3,data);
+}
+
+/************************************************/
+/* Data Write for YM2608 - Chip 1 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2608_data_port_1_A_w ){
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
+ YM2608Write(info->chip,1,data);
+}
+WRITE8_HANDLER( YM2608_data_port_1_B_w ){
+ struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
+ YM2608Write(info->chip,3,data);
+}
+
+/**************** end of file ****************/
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ym2608_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym2608_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym2608_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym2608_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym2608_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym2608_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM2608"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/2608intf.h b/src/emu/sound/2608intf.h
new file mode 100644
index 00000000000..c829f47998c
--- /dev/null
+++ b/src/emu/sound/2608intf.h
@@ -0,0 +1,38 @@
+#ifndef __2608INTF_H__
+#define __2608INTF_H__
+
+#include "fm.h"
+
+struct YM2608interface
+{
+ read8_handler portAread;
+ read8_handler portBread;
+ write8_handler portAwrite;
+ write8_handler portBwrite;
+ void ( *handler )( int irq ); /* IRQ handler for the YM2608 */
+ int pcmrom; /* Delta-T memory region ram/rom */
+};
+
+/************************************************/
+/* Chip 0 functions */
+/************************************************/
+READ8_HANDLER( YM2608_status_port_0_A_r );
+READ8_HANDLER( YM2608_status_port_0_B_r );
+READ8_HANDLER( YM2608_read_port_0_r );
+WRITE8_HANDLER( YM2608_control_port_0_A_w );
+WRITE8_HANDLER( YM2608_control_port_0_B_w );
+WRITE8_HANDLER( YM2608_data_port_0_A_w );
+WRITE8_HANDLER( YM2608_data_port_0_B_w );
+
+/************************************************/
+/* Chip 1 functions */
+/************************************************/
+READ8_HANDLER( YM2608_status_port_1_A_r );
+READ8_HANDLER( YM2608_status_port_1_B_r );
+READ8_HANDLER( YM2608_read_port_1_r );
+WRITE8_HANDLER( YM2608_control_port_1_A_w );
+WRITE8_HANDLER( YM2608_control_port_1_B_w );
+WRITE8_HANDLER( YM2608_data_port_1_A_w );
+WRITE8_HANDLER( YM2608_data_port_1_B_w );
+
+#endif /* __2608INTF_H__ */
diff --git a/src/emu/sound/2610intf.c b/src/emu/sound/2610intf.c
new file mode 100644
index 00000000000..d180da6607c
--- /dev/null
+++ b/src/emu/sound/2610intf.c
@@ -0,0 +1,520 @@
+/***************************************************************************
+
+ 2610intf.c
+
+ The YM2610 emulator supports up to 2 chips.
+ Each chip has the following connections:
+ - Status Read / Control Write A
+ - Port Read / Data Write A
+ - Control Write B
+ - Data Write B
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "ay8910.h"
+#include "2610intf.h"
+#include "fm.h"
+
+static sound_type chip_type = SOUND_YM2610;
+struct ym2610_info
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ void * psg;
+ const struct YM2610interface *intf;
+};
+
+
+static void psg_set_clock(void *param, int clock)
+{
+ struct ym2610_info *info = param;
+ ay8910_set_clock_ym(info->psg, clock);
+}
+
+static void psg_write(void *param, int address, int data)
+{
+ struct ym2610_info *info = param;
+ ay8910_write_ym(info->psg, address, data);
+}
+
+static int psg_read(void *param)
+{
+ struct ym2610_info *info = param;
+ return ay8910_read_ym(info->psg);
+}
+
+static void psg_reset(void *param)
+{
+ struct ym2610_info *info = param;
+ ay8910_reset_ym(info->psg);
+}
+
+static const struct ssg_callbacks psgintf =
+{
+ psg_set_clock,
+ psg_write,
+ psg_read,
+ psg_reset
+};
+
+/*------------------------- TM2610 -------------------------------*/
+/* IRQ Handler */
+static void IRQHandler(void *param,int irq)
+{
+ struct ym2610_info *info = param;
+ if(info->intf->handler) info->intf->handler(irq);
+}
+
+/* Timer overflow callback from timer.c */
+static TIMER_CALLBACK_PTR( timer_callback_0 )
+{
+ struct ym2610_info *info = param;
+ YM2610TimerOver(info->chip,0);
+}
+
+static TIMER_CALLBACK_PTR( timer_callback_1 )
+{
+ struct ym2610_info *info = param;
+ YM2610TimerOver(info->chip,1);
+}
+
+static void timer_handler(void *param,int c,int count,int clock)
+{
+ struct ym2610_info *info = param;
+ if( count == 0 )
+ { /* Reset FM Timer */
+ timer_enable(info->timer[c], 0);
+ }
+ else
+ { /* Start FM Timer */
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(clock), count);
+
+ if (!timer_enable(info->timer[c], 1))
+ timer_adjust_ptr(info->timer[c], period, attotime_zero);
+ }
+}
+
+/* update request from fm.c */
+void YM2610UpdateRequest(void *param)
+{
+ struct ym2610_info *info = param;
+ stream_update(info->stream);
+}
+
+#if BUILD_YM2610
+static void ym2610_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffers, int length)
+{
+ struct ym2610_info *info = param;
+ YM2610UpdateOne(info->chip, buffers, length);
+}
+
+
+static void ym2610_postload(void *param)
+{
+ struct ym2610_info *info = param;
+ YM2610Postload(info->chip);
+}
+
+
+static void *ym2610_start(int sndindex, int clock, const void *config)
+{
+ static const struct YM2610interface generic_2610 = { 0 };
+ const struct YM2610interface *intf = config ? config : &generic_2610;
+ int rate = clock/72;
+ void *pcmbufa,*pcmbufb;
+ int pcmsizea,pcmsizeb;
+ struct ym2610_info *info;
+
+ chip_type = SOUND_YM2610;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = intf;
+ info->psg = ay8910_start_ym(SOUND_YM2610, sndindex, clock, 1, NULL, NULL, NULL, NULL);
+ if (!info->psg) return NULL;
+
+ /* Timer Handler set */
+ info->timer[0] = timer_alloc_ptr(timer_callback_0, info);
+ info->timer[1] = timer_alloc_ptr(timer_callback_1, info);
+
+ /* stream system initialize */
+ info->stream = stream_create(0,2,rate,info,ym2610_stream_update);
+ /* setup adpcm buffers */
+ pcmbufa = (void *)(memory_region(info->intf->pcmroma));
+ pcmsizea = memory_region_length(info->intf->pcmroma);
+ pcmbufb = (void *)(memory_region(info->intf->pcmromb));
+ pcmsizeb = memory_region_length(info->intf->pcmromb);
+
+ /**** initialize YM2610 ****/
+ info->chip = YM2610Init(info,sndindex,clock,rate,
+ pcmbufa,pcmsizea,pcmbufb,pcmsizeb,
+ timer_handler,IRQHandler,&psgintf);
+
+ state_save_register_func_postload_ptr(ym2610_postload, info);
+
+ if (info->chip)
+ return info;
+
+ /* error */
+ return NULL;
+}
+#endif
+
+#if BUILD_YM2610B
+static void ym2610b_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffers, int length)
+{
+ struct ym2610_info *info = param;
+ YM2610BUpdateOne(info->chip, buffers, length);
+}
+
+static void *ym2610b_start(int sndindex, int clock, const void *config)
+{
+ static const struct YM2610interface generic_2610 = { 0 };
+ const struct YM2610interface *intf = config ? config : &generic_2610;
+ int rate = clock/72;
+ void *pcmbufa,*pcmbufb;
+ int pcmsizea,pcmsizeb;
+ struct ym2610_info *info;
+
+ chip_type = SOUND_YM2610B;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = intf;
+ info->psg = ay8910_start_ym(SOUND_YM2610B, sndindex, clock, 1, NULL, NULL, NULL, NULL);
+ if (!info->psg) return NULL;
+
+ /* Timer Handler set */
+ info->timer[0] =timer_alloc_ptr(timer_callback_0, info);
+ info->timer[1] =timer_alloc_ptr(timer_callback_1, info);
+
+ /* stream system initialize */
+ info->stream = stream_create(0,2,rate,info,ym2610b_stream_update);
+ /* setup adpcm buffers */
+ pcmbufa = (void *)(memory_region(info->intf->pcmroma));
+ pcmsizea = memory_region_length(info->intf->pcmroma);
+ pcmbufb = (void *)(memory_region(info->intf->pcmromb));
+ pcmsizeb = memory_region_length(info->intf->pcmromb);
+
+ /**** initialize YM2610 ****/
+ info->chip = YM2610Init(info,sndindex,clock,rate,
+ pcmbufa,pcmsizea,pcmbufb,pcmsizeb,
+ timer_handler,IRQHandler,&psgintf);
+ if (info->chip)
+ return info;
+
+ /* error */
+ return NULL;
+}
+#endif
+
+static void ym2610_stop(void *token)
+{
+ struct ym2610_info *info = token;
+ YM2610Shutdown(info->chip);
+ ay8910_stop_ym(info->psg);
+}
+
+static void ym2610_reset(void *token)
+{
+ struct ym2610_info *info = token;
+ YM2610ResetChip(info->chip);
+}
+
+/************************************************/
+/* Status Read for YM2610 - Chip 0 */
+/************************************************/
+READ8_HANDLER( YM2610_status_port_0_A_r )
+{
+//logerror("PC %04x: 2610 S0A=%02X\n",activecpu_get_pc(),YM2610Read(sndti_token(chip_type,0,0));
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ return YM2610Read(info->chip,0);
+}
+
+READ16_HANDLER( YM2610_status_port_0_A_lsb_r )
+{
+//logerror("PC %04x: 2610 S0A=%02X\n",activecpu_get_pc(),YM2610Read(sndti_token(chip_type,0,0));
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ return YM2610Read(info->chip,0);
+}
+
+READ8_HANDLER( YM2610_status_port_0_B_r )
+{
+//logerror("PC %04x: 2610 S0B=%02X\n",activecpu_get_pc(),YM2610Read(sndti_token(chip_type,0,2));
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ return YM2610Read(info->chip,2);
+}
+
+READ16_HANDLER( YM2610_status_port_0_B_lsb_r )
+{
+//logerror("PC %04x: 2610 S0B=%02X\n",activecpu_get_pc(),YM2610Read(sndti_token(chip_type,0,2));
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ return YM2610Read(info->chip,2);
+}
+
+/************************************************/
+/* Status Read for YM2610 - Chip 1 */
+/************************************************/
+READ8_HANDLER( YM2610_status_port_1_A_r ) {
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ return YM2610Read(info->chip,0);
+}
+
+READ16_HANDLER( YM2610_status_port_1_A_lsb_r ) {
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ return YM2610Read(info->chip,0);
+}
+
+READ8_HANDLER( YM2610_status_port_1_B_r ) {
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ return YM2610Read(info->chip,2);
+}
+
+READ16_HANDLER( YM2610_status_port_1_B_lsb_r ) {
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ return YM2610Read(info->chip,2);
+}
+
+/************************************************/
+/* Port Read for YM2610 - Chip 0 */
+/************************************************/
+READ8_HANDLER( YM2610_read_port_0_r ){
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ return YM2610Read(info->chip,1);
+}
+
+READ16_HANDLER( YM2610_read_port_0_lsb_r ){
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ return YM2610Read(info->chip,1);
+}
+
+/************************************************/
+/* Port Read for YM2610 - Chip 1 */
+/************************************************/
+READ8_HANDLER( YM2610_read_port_1_r ){
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ return YM2610Read(info->chip,1);
+}
+
+READ16_HANDLER( YM2610_read_port_1_lsb_r ){
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ return YM2610Read(info->chip,1);
+}
+
+/************************************************/
+/* Control Write for YM2610 - Chip 0 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2610_control_port_0_A_w )
+{
+//logerror("PC %04x: 2610 Reg A %02X",activecpu_get_pc(),data);
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ YM2610Write(info->chip,0,data);
+}
+
+WRITE16_HANDLER( YM2610_control_port_0_A_lsb_w )
+{
+//logerror("PC %04x: 2610 Reg A %02X",activecpu_get_pc(),data);
+ if (ACCESSING_LSB)
+ {
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ YM2610Write(info->chip,0,data);
+ }
+}
+
+WRITE8_HANDLER( YM2610_control_port_0_B_w )
+{
+//logerror("PC %04x: 2610 Reg B %02X",activecpu_get_pc(),data);
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ YM2610Write(info->chip,2,data);
+}
+
+WRITE16_HANDLER( YM2610_control_port_0_B_lsb_w )
+{
+//logerror("PC %04x: 2610 Reg B %02X",activecpu_get_pc(),data);
+ if (ACCESSING_LSB)
+ {
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ YM2610Write(info->chip,2,data);
+ }
+}
+
+/************************************************/
+/* Control Write for YM2610 - Chip 1 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2610_control_port_1_A_w ){
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ YM2610Write(info->chip,0,data);
+}
+
+WRITE16_HANDLER( YM2610_control_port_1_A_lsb_w ){
+ if (ACCESSING_LSB)
+ {
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ YM2610Write(info->chip,0,data);
+ }
+}
+
+WRITE8_HANDLER( YM2610_control_port_1_B_w ){
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ YM2610Write(info->chip,2,data);
+}
+
+WRITE16_HANDLER( YM2610_control_port_1_B_lsb_w ){
+ if (ACCESSING_LSB)
+ {
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ YM2610Write(info->chip,2,data);
+ }
+}
+
+/************************************************/
+/* Data Write for YM2610 - Chip 0 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2610_data_port_0_A_w )
+{
+//logerror(" =%02X\n",data);
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ YM2610Write(info->chip,1,data);
+}
+
+WRITE16_HANDLER( YM2610_data_port_0_A_lsb_w )
+{
+//logerror(" =%02X\n",data);
+ if (ACCESSING_LSB)
+ {
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ YM2610Write(info->chip,1,data);
+ }
+}
+
+WRITE8_HANDLER( YM2610_data_port_0_B_w )
+{
+//logerror(" =%02X\n",data);
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ YM2610Write(info->chip,3,data);
+}
+
+WRITE16_HANDLER( YM2610_data_port_0_B_lsb_w )
+{
+//logerror(" =%02X\n",data);
+ if (ACCESSING_LSB)
+ {
+ struct ym2610_info *info = sndti_token(chip_type,0);
+ YM2610Write(info->chip,3,data);
+ }
+}
+
+/************************************************/
+/* Data Write for YM2610 - Chip 1 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2610_data_port_1_A_w ){
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ YM2610Write(info->chip,1,data);
+}
+
+WRITE16_HANDLER( YM2610_data_port_1_A_lsb_w ){
+ if (ACCESSING_LSB)
+ {
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ YM2610Write(info->chip,1,data);
+ }
+}
+
+WRITE8_HANDLER( YM2610_data_port_1_B_w ){
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ YM2610Write(info->chip,3,data);
+}
+
+WRITE16_HANDLER( YM2610_data_port_1_B_lsb_w ){
+ if (ACCESSING_LSB)
+ {
+ struct ym2610_info *info = sndti_token(chip_type,1);
+ YM2610Write(info->chip,3,data);
+ }
+}
+
+/**************** end of file ****************/
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+#if BUILD_YM2610
+static void ym2610_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym2610_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym2610_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym2610_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym2610_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym2610_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM2610"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+#endif
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+#if BUILD_YM2610B
+static void ym2610b_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym2610b_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym2610b_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym2610b_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym2610_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym2610_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM2610B"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+#endif
diff --git a/src/emu/sound/2610intf.h b/src/emu/sound/2610intf.h
new file mode 100644
index 00000000000..eb704269c6c
--- /dev/null
+++ b/src/emu/sound/2610intf.h
@@ -0,0 +1,50 @@
+#ifndef __2610INTF_H__
+#define __2610INTF_H__
+
+#include "fm.h"
+
+struct YM2610interface
+{
+ void ( *handler )( int irq ); /* IRQ handler for the YM2610 */
+ int pcmromb; /* Delta-T rom region */
+ int pcmroma; /* ADPCM rom region */
+};
+
+/************************************************/
+/* Chip 0 functions */
+/************************************************/
+READ8_HANDLER( YM2610_status_port_0_A_r );
+READ16_HANDLER( YM2610_status_port_0_A_lsb_r );
+READ8_HANDLER( YM2610_status_port_0_B_r );
+READ16_HANDLER( YM2610_status_port_0_B_lsb_r );
+READ8_HANDLER( YM2610_read_port_0_r );
+READ16_HANDLER( YM2610_read_port_0_lsb_r );
+WRITE8_HANDLER( YM2610_control_port_0_A_w );
+WRITE16_HANDLER( YM2610_control_port_0_A_lsb_w );
+WRITE8_HANDLER( YM2610_control_port_0_B_w );
+WRITE16_HANDLER( YM2610_control_port_0_B_lsb_w );
+WRITE8_HANDLER( YM2610_data_port_0_A_w );
+WRITE16_HANDLER( YM2610_data_port_0_A_lsb_w );
+WRITE8_HANDLER( YM2610_data_port_0_B_w );
+WRITE16_HANDLER( YM2610_data_port_0_B_lsb_w );
+
+/************************************************/
+/* Chip 1 functions */
+/************************************************/
+READ8_HANDLER( YM2610_status_port_1_A_r );
+READ16_HANDLER( YM2610_status_port_1_A_lsb_r );
+READ8_HANDLER( YM2610_status_port_1_B_r );
+READ16_HANDLER( YM2610_status_port_1_B_lsb_r );
+READ8_HANDLER( YM2610_read_port_1_r );
+READ16_HANDLER( YM2610_read_port_1_lsb_r );
+WRITE8_HANDLER( YM2610_control_port_1_A_w );
+WRITE16_HANDLER( YM2610_control_port_1_A_lsb_w );
+WRITE8_HANDLER( YM2610_control_port_1_B_w );
+WRITE16_HANDLER( YM2610_control_port_1_B_lsb_w );
+WRITE8_HANDLER( YM2610_data_port_1_A_w );
+WRITE16_HANDLER( YM2610_data_port_1_A_lsb_w );
+WRITE8_HANDLER( YM2610_data_port_1_B_w );
+WRITE16_HANDLER( YM2610_data_port_1_B_lsb_w );
+
+#endif
+/**************** end of file ****************/
diff --git a/src/emu/sound/2612intf.c b/src/emu/sound/2612intf.c
new file mode 100644
index 00000000000..fbc9275f4ef
--- /dev/null
+++ b/src/emu/sound/2612intf.c
@@ -0,0 +1,415 @@
+/***************************************************************************
+
+ 2612intf.c
+
+ The YM2612 emulator supports up to 2 chips.
+ Each chip has the following connections:
+ - Status Read / Control Write A
+ - Port Read / Data Write A
+ - Control Write B
+ - Data Write B
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "sound/fm.h"
+#include "sound/2612intf.h"
+
+
+struct ym2612_info
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ const struct YM2612interface *intf;
+};
+
+/*------------------------- TM2612 -------------------------------*/
+/* IRQ Handler */
+static void IRQHandler(void *param,int irq)
+{
+ struct ym2612_info *info = param;
+ if(info->intf->handler) info->intf->handler(irq);
+}
+
+/* Timer overflow callback from timer.c */
+static TIMER_CALLBACK_PTR( timer_callback_2612_0 )
+{
+ struct ym2612_info *info = param;
+ YM2612TimerOver(info->chip,0);
+}
+
+static TIMER_CALLBACK_PTR( timer_callback_2612_1 )
+{
+ struct ym2612_info *info = param;
+ YM2612TimerOver(info->chip,1);
+}
+
+static void timer_handler(void *param,int c,int count,int clock)
+{
+ struct ym2612_info *info = param;
+ if( count == 0 )
+ { /* Reset FM Timer */
+ timer_enable(info->timer[c], 0);
+ }
+ else
+ { /* Start FM Timer */
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(clock), count);
+ if (!timer_enable(info->timer[c], 1))
+ timer_adjust_ptr(info->timer[c], period, attotime_zero);
+ }
+}
+
+/* update request from fm.c */
+void YM2612UpdateRequest(void *param)
+{
+ struct ym2612_info *info = param;
+ stream_update(info->stream);
+}
+
+/***********************************************************/
+/* YM2612 */
+/***********************************************************/
+
+static void ym2612_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffers, int length)
+{
+ struct ym2612_info *info = param;
+ YM2612UpdateOne(info->chip, buffers, length);
+}
+
+
+static void ym2612_postload(void *param)
+{
+ struct ym2612_info *info = param;
+ YM2612Postload(info->chip);
+}
+
+
+static void *ym2612_start(int sndindex, int clock, const void *config)
+{
+ static const struct YM2612interface dummy = { 0 };
+ struct ym2612_info *info;
+ int rate = clock/72;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = config ? config : &dummy;
+
+ /* FM init */
+ /* Timer Handler set */
+ info->timer[0] = timer_alloc_ptr(timer_callback_2612_0, info);
+ info->timer[1] = timer_alloc_ptr(timer_callback_2612_1, info);
+
+ /* stream system initialize */
+ info->stream = stream_create(0,2,rate,info,ym2612_stream_update);
+
+ /**** initialize YM2612 ****/
+ info->chip = YM2612Init(info,sndindex,clock,rate,timer_handler,IRQHandler);
+
+ state_save_register_func_postload_ptr(ym2612_postload, info);
+
+ if (info->chip)
+ return info;
+ /* error */
+ return NULL;
+}
+
+
+static void ym2612_stop(void *token)
+{
+ struct ym2612_info *info = token;
+ YM2612Shutdown(info->chip);
+}
+
+static void ym2612_reset(void *token)
+{
+ struct ym2612_info *info = token;
+ YM2612ResetChip(info->chip);
+}
+
+
+/************************************************/
+/* Status Read for YM2612 - Chip 0 */
+/************************************************/
+READ8_HANDLER( YM2612_status_port_0_A_r )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,0);
+ return YM2612Read(info->chip,0);
+}
+
+READ8_HANDLER( YM2612_status_port_0_B_r )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,0);
+ return YM2612Read(info->chip,2);
+}
+
+/************************************************/
+/* Status Read for YM2612 - Chip 1 */
+/************************************************/
+READ8_HANDLER( YM2612_status_port_1_A_r ) {
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,1);
+ return YM2612Read(info->chip,0);
+}
+
+READ8_HANDLER( YM2612_status_port_1_B_r ) {
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,1);
+ return YM2612Read(info->chip,2);
+}
+
+/************************************************/
+/* Port Read for YM2612 - Chip 0 */
+/************************************************/
+READ8_HANDLER( YM2612_read_port_0_r ){
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,0);
+ return YM2612Read(info->chip,1);
+}
+
+/************************************************/
+/* Port Read for YM2612 - Chip 1 */
+/************************************************/
+READ8_HANDLER( YM2612_read_port_1_r ){
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,1);
+ return YM2612Read(info->chip,1);
+}
+
+/************************************************/
+/* Control Write for YM2612 - Chip 0 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2612_control_port_0_A_w )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,0);
+ YM2612Write(info->chip,0,data);
+}
+
+WRITE8_HANDLER( YM2612_control_port_0_B_w )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,0);
+ YM2612Write(info->chip,2,data);
+}
+
+/************************************************/
+/* Control Write for YM2612 - Chip 1 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2612_control_port_1_A_w ){
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,1);
+ YM2612Write(info->chip,0,data);
+}
+
+WRITE8_HANDLER( YM2612_control_port_1_B_w ){
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,1);
+ YM2612Write(info->chip,2,data);
+}
+
+/************************************************/
+/* Data Write for YM2612 - Chip 0 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2612_data_port_0_A_w )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,0);
+ YM2612Write(info->chip,1,data);
+}
+
+WRITE8_HANDLER( YM2612_data_port_0_B_w )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,0);
+ YM2612Write(info->chip,3,data);
+}
+
+/************************************************/
+/* Data Write for YM2612 - Chip 1 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM2612_data_port_1_A_w ){
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,1);
+ YM2612Write(info->chip,1,data);
+}
+WRITE8_HANDLER( YM2612_data_port_1_B_w ){
+ struct ym2612_info *info = sndti_token(SOUND_YM2612,1);
+ YM2612Write(info->chip,3,data);
+}
+
+#if BUILD_YM3438
+
+/************************************************/
+/* Status Read for YM3438 - Chip 0 */
+/************************************************/
+READ8_HANDLER( YM3438_status_port_0_A_r )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,0);
+ return YM2612Read(info->chip,0);
+}
+
+READ8_HANDLER( YM3438_status_port_0_B_r )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,0);
+ return YM2612Read(info->chip,2);
+}
+
+/************************************************/
+/* Status Read for YM3438 - Chip 1 */
+/************************************************/
+READ8_HANDLER( YM3438_status_port_1_A_r ) {
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,1);
+ return YM2612Read(info->chip,0);
+}
+
+READ8_HANDLER( YM3438_status_port_1_B_r ) {
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,1);
+ return YM2612Read(info->chip,2);
+}
+
+/************************************************/
+/* Port Read for YM3438 - Chip 0 */
+/************************************************/
+READ8_HANDLER( YM3438_read_port_0_r ){
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,0);
+ return YM2612Read(info->chip,1);
+}
+
+/************************************************/
+/* Port Read for YM3438 - Chip 1 */
+/************************************************/
+READ8_HANDLER( YM3438_read_port_1_r ){
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,1);
+ return YM2612Read(info->chip,1);
+}
+
+/************************************************/
+/* Control Write for YM3438 - Chip 0 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM3438_control_port_0_A_w )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,0);
+ YM2612Write(info->chip,0,data);
+}
+
+WRITE8_HANDLER( YM3438_control_port_0_B_w )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,0);
+ YM2612Write(info->chip,2,data);
+}
+
+/************************************************/
+/* Control Write for YM3438 - Chip 1 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM3438_control_port_1_A_w ){
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,1);
+ YM2612Write(info->chip,0,data);
+}
+
+WRITE8_HANDLER( YM3438_control_port_1_B_w ){
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,1);
+ YM2612Write(info->chip,2,data);
+}
+
+/************************************************/
+/* Data Write for YM3438 - Chip 0 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM3438_data_port_0_A_w )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,0);
+ YM2612Write(info->chip,1,data);
+}
+
+WRITE8_HANDLER( YM3438_data_port_0_B_w )
+{
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,0);
+ YM2612Write(info->chip,3,data);
+}
+
+/************************************************/
+/* Data Write for YM3438 - Chip 1 */
+/* Consists of 2 addresses */
+/************************************************/
+WRITE8_HANDLER( YM3438_data_port_1_A_w ){
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,1);
+ YM2612Write(info->chip,1,data);
+}
+WRITE8_HANDLER( YM3438_data_port_1_B_w ){
+ struct ym2612_info *info = sndti_token(SOUND_YM3438,1);
+ YM2612Write(info->chip,3,data);
+}
+
+#endif
+
+/**************** end of file ****************/
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ym2612_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym2612_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym2612_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym2612_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym2612_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym2612_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM2612"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+#if BUILD_YM3438
+
+static void ym3438_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym3438_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym3438_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym2612_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym2612_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym2612_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM3438"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+#endif
diff --git a/src/emu/sound/2612intf.h b/src/emu/sound/2612intf.h
new file mode 100644
index 00000000000..8f9d16a5af0
--- /dev/null
+++ b/src/emu/sound/2612intf.h
@@ -0,0 +1,64 @@
+#ifndef __2612INTF_H__
+#define __2612INTF_H__
+
+struct YM2612interface
+{
+ void (*handler)(int irq);
+};
+
+
+/************************************************/
+/* Chip 0 functions */
+/************************************************/
+READ8_HANDLER( YM2612_status_port_0_A_r ); /* A=0 : OPN status */
+READ8_HANDLER( YM2612_status_port_0_B_r ); /* A=2 : don't care */
+READ8_HANDLER( YM2612_read_port_0_r ); /* A=1 : don't care */
+WRITE8_HANDLER( YM2612_control_port_0_A_w ); /* A=0:OPN address */
+WRITE8_HANDLER( YM2612_control_port_0_B_w ); /* A=2:OPN2 address */
+WRITE8_HANDLER( YM2612_data_port_0_A_w ); /* A=1:OPN data */
+WRITE8_HANDLER( YM2612_data_port_0_B_w ); /* A=3:OPN2 data */
+
+/************************************************/
+/* Chip 1 functions */
+/************************************************/
+READ8_HANDLER( YM2612_status_port_1_A_r );
+READ8_HANDLER( YM2612_status_port_1_B_r );
+READ8_HANDLER( YM2612_read_port_1_r );
+WRITE8_HANDLER( YM2612_control_port_1_A_w );
+WRITE8_HANDLER( YM2612_control_port_1_B_w );
+WRITE8_HANDLER( YM2612_data_port_1_A_w );
+WRITE8_HANDLER( YM2612_data_port_1_B_w );
+
+
+
+struct YM3438interface
+{
+ void (*handler)(int irq);
+};
+
+
+/************************************************/
+/* Chip 0 functions */
+/************************************************/
+READ8_HANDLER( YM3438_status_port_0_A_r ); /* A=0 : OPN status */
+READ8_HANDLER( YM3438_status_port_0_B_r ); /* A=2 : don't care */
+READ8_HANDLER( YM3438_read_port_0_r ); /* A=1 : don't care */
+WRITE8_HANDLER( YM3438_control_port_0_A_w ); /* A=0:OPN address */
+WRITE8_HANDLER( YM3438_control_port_0_B_w ); /* A=2:OPN2 address */
+WRITE8_HANDLER( YM3438_data_port_0_A_w ); /* A=1:OPN data */
+WRITE8_HANDLER( YM3438_data_port_0_B_w ); /* A=3:OPN2 data */
+
+/************************************************/
+/* Chip 1 functions */
+/************************************************/
+READ8_HANDLER( YM3438_status_port_1_A_r );
+READ8_HANDLER( YM3438_status_port_1_B_r );
+READ8_HANDLER( YM3438_read_port_1_r );
+WRITE8_HANDLER( YM3438_control_port_1_A_w );
+WRITE8_HANDLER( YM3438_control_port_1_B_w );
+WRITE8_HANDLER( YM3438_data_port_1_A_w );
+WRITE8_HANDLER( YM3438_data_port_1_B_w );
+
+
+#endif
+/**************** end of file ****************/
diff --git a/src/emu/sound/262intf.c b/src/emu/sound/262intf.c
new file mode 100644
index 00000000000..cc314703ac0
--- /dev/null
+++ b/src/emu/sound/262intf.c
@@ -0,0 +1,189 @@
+/***************************************************************************
+
+ 262intf.c
+
+ MAME interface for YMF262 (OPL3) emulator
+
+***************************************************************************/
+#include "sndintrf.h"
+#include "streams.h"
+#include "262intf.h"
+#include "ymf262.h"
+
+
+struct ymf262_info
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ const struct YMF262interface *intf;
+};
+
+
+
+
+static void IRQHandler_262(void *param,int irq)
+{
+ struct ymf262_info *info = param;
+ if (info->intf->handler) (info->intf->handler)(irq);
+}
+
+static TIMER_CALLBACK_PTR( timer_callback_262_0 )
+{
+ struct ymf262_info *info = param;
+ YMF262TimerOver(info->chip, 0);
+}
+
+static TIMER_CALLBACK_PTR( timer_callback_262_1 )
+{
+ struct ymf262_info *info = param;
+ YMF262TimerOver(info->chip, 1);
+}
+
+static void timer_handler_262(void *param,int timer, attotime period)
+{
+ struct ymf262_info *info = param;
+ if( attotime_compare(period, attotime_zero) == 0 )
+ { /* Reset FM Timer */
+ timer_enable(info->timer[timer], 0);
+ }
+ else
+ { /* Start FM Timer */
+ timer_adjust_ptr(info->timer[timer], period, attotime_zero);
+ }
+}
+
+static void ymf262_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffers, int length)
+{
+ struct ymf262_info *info = param;
+ YMF262UpdateOne(info->chip, buffers, length);
+}
+
+static void _stream_update(void *param, int interval)
+{
+ struct ymf262_info *info = param;
+ stream_update(info->stream);
+}
+
+
+static void *ymf262_start(int sndindex, int clock, const void *config)
+{
+ static const struct YMF262interface dummy = { 0 };
+ struct ymf262_info *info;
+ int rate = clock/288;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = config ? config : &dummy;
+
+ /* stream system initialize */
+ info->chip = YMF262Init(clock,rate);
+ if (info->chip == NULL)
+ return NULL;
+
+ info->stream = stream_create(0,4,rate,info,ymf262_stream_update);
+
+ /* YMF262 setup */
+ YMF262SetTimerHandler (info->chip, timer_handler_262, info);
+ YMF262SetIRQHandler (info->chip, IRQHandler_262, info);
+ YMF262SetUpdateHandler(info->chip, _stream_update, info);
+
+ info->timer[0] = timer_alloc_ptr(timer_callback_262_0, info);
+ info->timer[1] = timer_alloc_ptr(timer_callback_262_1, info);
+
+ return info;
+}
+
+static void ymf262_stop(void *token)
+{
+ struct ymf262_info *info = token;
+ YMF262Shutdown(info->chip);
+}
+
+/* reset */
+static void ymf262_reset(void *token)
+{
+ struct ymf262_info *info = token;
+ YMF262ResetChip(info->chip);
+}
+
+/* chip #0 */
+READ8_HANDLER( YMF262_status_0_r ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 0);
+ return YMF262Read(info->chip, 0);
+}
+WRITE8_HANDLER( YMF262_register_A_0_w ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 0);
+ YMF262Write(info->chip, 0, data);
+}
+WRITE8_HANDLER( YMF262_data_A_0_w ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 0);
+ YMF262Write(info->chip, 1, data);
+}
+WRITE8_HANDLER( YMF262_register_B_0_w ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 0);
+ YMF262Write(info->chip, 2, data);
+}
+WRITE8_HANDLER( YMF262_data_B_0_w ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 0);
+ YMF262Write(info->chip, 3, data);
+}
+
+/* chip #1 */
+READ8_HANDLER( YMF262_status_1_r ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 1);
+ return YMF262Read(info->chip, 0);
+}
+WRITE8_HANDLER( YMF262_register_A_1_w ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 1);
+ YMF262Write(info->chip, 0, data);
+}
+WRITE8_HANDLER( YMF262_data_A_1_w ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 1);
+ YMF262Write(info->chip, 1, data);
+}
+WRITE8_HANDLER( YMF262_register_B_1_w ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 1);
+ YMF262Write(info->chip, 2, data);
+}
+WRITE8_HANDLER( YMF262_data_B_1_w ) {
+ struct ymf262_info *info = sndti_token(SOUND_YMF262, 1);
+ YMF262Write(info->chip, 3, data);
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ymf262_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ymf262_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ymf262_set_info; break;
+ case SNDINFO_PTR_START: info->start = ymf262_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ymf262_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ymf262_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YMF262"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/262intf.h b/src/emu/sound/262intf.h
new file mode 100644
index 00000000000..e179f37a74c
--- /dev/null
+++ b/src/emu/sound/262intf.h
@@ -0,0 +1,27 @@
+#ifndef YMF262INTF_H
+#define YMF262INTF_H
+
+
+struct YMF262interface
+{
+ void (*handler)(int irq);
+};
+
+
+
+/* YMF262 */
+READ8_HANDLER ( YMF262_status_0_r );
+WRITE8_HANDLER( YMF262_register_A_0_w );
+WRITE8_HANDLER( YMF262_register_B_0_w );
+WRITE8_HANDLER( YMF262_data_A_0_w );
+WRITE8_HANDLER( YMF262_data_B_0_w );
+
+
+READ8_HANDLER ( YMF262_status_1_r );
+WRITE8_HANDLER( YMF262_register_A_1_w );
+WRITE8_HANDLER( YMF262_register_B_1_w );
+WRITE8_HANDLER( YMF262_data_A_1_w );
+WRITE8_HANDLER( YMF262_data_B_1_w );
+
+
+#endif
diff --git a/src/emu/sound/3812intf.c b/src/emu/sound/3812intf.c
new file mode 100644
index 00000000000..6ad352864e0
--- /dev/null
+++ b/src/emu/sound/3812intf.c
@@ -0,0 +1,565 @@
+/******************************************************************************
+* FILE
+* Yamaha 3812 emulator interface - MAME VERSION
+*
+* CREATED BY
+* Ernesto Corvi
+*
+* UPDATE LOG
+* JB 28-04-2002 Fixed simultaneous usage of all three different chip types.
+* Used real sample rate when resample filter is active.
+* AAT 12-28-2001 Protected Y8950 from accessing unmapped port and keyboard handlers.
+* CHS 1999-01-09 Fixes new ym3812 emulation interface.
+* CHS 1998-10-23 Mame streaming sound chip update
+* EC 1998 Created Interface
+*
+* NOTES
+*
+******************************************************************************/
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "3812intf.h"
+#include "fm.h"
+#include "sound/fmopl.h"
+
+
+#if BUILD_YM3812
+
+struct ym3812_info
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ const struct YM3812interface *intf;
+};
+
+static void IRQHandler_3812(void *param,int irq)
+{
+ struct ym3812_info *info = param;
+ if (info->intf->handler) (info->intf->handler)(irq ? ASSERT_LINE : CLEAR_LINE);
+}
+static TIMER_CALLBACK_PTR( timer_callback_3812_0 )
+{
+ struct ym3812_info *info = param;
+ YM3812TimerOver(info->chip,0);
+}
+
+static TIMER_CALLBACK_PTR( timer_callback_3812_1 )
+{
+ struct ym3812_info *info = param;
+ YM3812TimerOver(info->chip,1);
+}
+
+static void TimerHandler_3812(void *param,int c,attotime period)
+{
+ struct ym3812_info *info = param;
+ if( attotime_compare(period, attotime_zero) == 0 )
+ { /* Reset FM Timer */
+ timer_enable(info->timer[c], 0);
+ }
+ else
+ { /* Start FM Timer */
+ timer_adjust_ptr(info->timer[c], period, attotime_zero);
+ }
+}
+
+
+static void ym3812_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct ym3812_info *info = param;
+ YM3812UpdateOne(info->chip, buffer[0], length);
+}
+
+static void _stream_update_3812(void * param, int interval)
+{
+ struct ym3812_info *info = param;
+ stream_update(info->stream);
+}
+
+
+static void *ym3812_start(int sndindex, int clock, const void *config)
+{
+ static const struct YM3812interface dummy = { 0 };
+ struct ym3812_info *info;
+ int rate = clock/72;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = config ? config : &dummy;
+
+ /* stream system initialize */
+ info->chip = YM3812Init(sndindex,clock,rate);
+ if (!info->chip)
+ return NULL;
+
+ info->stream = stream_create(0,1,rate,info,ym3812_stream_update);
+
+ /* YM3812 setup */
+ YM3812SetTimerHandler (info->chip, TimerHandler_3812, info);
+ YM3812SetIRQHandler (info->chip, IRQHandler_3812, info);
+ YM3812SetUpdateHandler(info->chip, _stream_update_3812, info);
+
+ info->timer[0] = timer_alloc_ptr(timer_callback_3812_0, info);
+ info->timer[1] = timer_alloc_ptr(timer_callback_3812_1, info);
+
+ return info;
+}
+
+static void ym3812_stop(void *token)
+{
+ struct ym3812_info *info = token;
+ YM3812Shutdown(info->chip);
+}
+
+static void ym3812_reset(void *token)
+{
+ struct ym3812_info *info = token;
+ YM3812ResetChip(info->chip);
+}
+
+WRITE8_HANDLER( YM3812_control_port_0_w ) {
+ struct ym3812_info *info = sndti_token(SOUND_YM3812, 0);
+ YM3812Write(info->chip, 0, data);
+}
+WRITE8_HANDLER( YM3812_write_port_0_w ) {
+ struct ym3812_info *info = sndti_token(SOUND_YM3812, 0);
+ YM3812Write(info->chip, 1, data);
+}
+READ8_HANDLER( YM3812_status_port_0_r ) {
+ struct ym3812_info *info = sndti_token(SOUND_YM3812, 0);
+ return YM3812Read(info->chip, 0);
+}
+READ8_HANDLER( YM3812_read_port_0_r ) {
+ struct ym3812_info *info = sndti_token(SOUND_YM3812, 0);
+ return YM3812Read(info->chip, 1);
+}
+
+
+WRITE8_HANDLER( YM3812_control_port_1_w ) {
+ struct ym3812_info *info = sndti_token(SOUND_YM3812, 1);
+ YM3812Write(info->chip, 0, data);
+}
+WRITE8_HANDLER( YM3812_write_port_1_w ) {
+ struct ym3812_info *info = sndti_token(SOUND_YM3812, 1);
+ YM3812Write(info->chip, 1, data);
+}
+READ8_HANDLER( YM3812_status_port_1_r ) {
+ struct ym3812_info *info = sndti_token(SOUND_YM3812, 1);
+ return YM3812Read(info->chip, 0);
+}
+READ8_HANDLER( YM3812_read_port_1_r ) {
+ struct ym3812_info *info = sndti_token(SOUND_YM3812, 1);
+ return YM3812Read(info->chip, 1);
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ym3812_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym3812_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym3812_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym3812_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym3812_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym3812_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM3812"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+#endif
+
+
+#if BUILD_YM3526
+
+struct ym3526_info
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ const struct YM3526interface *intf;
+};
+
+
+/* IRQ Handler */
+static void IRQHandler_3526(void *param,int irq)
+{
+ struct ym3526_info *info = param;
+ if (info->intf->handler) (info->intf->handler)(irq ? ASSERT_LINE : CLEAR_LINE);
+}
+/* Timer overflow callback from timer.c */
+static TIMER_CALLBACK_PTR( timer_callback_3526_0 )
+{
+ struct ym3526_info *info = param;
+ YM3526TimerOver(info->chip,0);
+}
+static TIMER_CALLBACK_PTR( timer_callback_3526_1 )
+{
+ struct ym3526_info *info = param;
+ YM3526TimerOver(info->chip,1);
+}
+/* TimerHandler from fm.c */
+static void TimerHandler_3526(void *param,int c,attotime period)
+{
+ struct ym3526_info *info = param;
+ if( attotime_compare(period, attotime_zero) == 0 )
+ { /* Reset FM Timer */
+ timer_enable(info->timer[c], 0);
+ }
+ else
+ { /* Start FM Timer */
+ timer_adjust_ptr(info->timer[c], period, attotime_zero);
+ }
+}
+
+
+static void ym3526_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct ym3526_info *info = param;
+ YM3526UpdateOne(info->chip, buffer[0], length);
+}
+
+static void _stream_update_3526(void *param, int interval)
+{
+ struct ym3526_info *info = param;
+ stream_update(info->stream);
+}
+
+
+static void *ym3526_start(int sndindex, int clock, const void *config)
+{
+ static const struct YM3526interface dummy = { 0 };
+ struct ym3526_info *info;
+ int rate = clock/72;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = config ? config : &dummy;
+
+ /* stream system initialize */
+ info->chip = YM3526Init(sndindex,clock,rate);
+ if (!info->chip)
+ return NULL;
+
+ info->stream = stream_create(0,1,rate,info,ym3526_stream_update);
+ /* YM3526 setup */
+ YM3526SetTimerHandler (info->chip, TimerHandler_3526, info);
+ YM3526SetIRQHandler (info->chip, IRQHandler_3526, info);
+ YM3526SetUpdateHandler(info->chip, _stream_update_3526, info);
+
+ info->timer[0] = timer_alloc_ptr(timer_callback_3526_0, info);
+ info->timer[1] = timer_alloc_ptr(timer_callback_3526_1, info);
+
+ return info;
+}
+
+static void ym3526_stop(void *token)
+{
+ struct ym3526_info *info = token;
+ YM3526Shutdown(info->chip);
+}
+
+static void ym3526_reset(void *token)
+{
+ struct ym3526_info *info = token;
+ YM3526ResetChip(info->chip);
+}
+
+WRITE8_HANDLER( YM3526_control_port_0_w ) {
+ struct ym3526_info *info = sndti_token(SOUND_YM3526, 0);
+ YM3526Write(info->chip, 0, data);
+}
+WRITE8_HANDLER( YM3526_write_port_0_w ) {
+ struct ym3526_info *info = sndti_token(SOUND_YM3526, 0);
+ YM3526Write(info->chip, 1, data);
+}
+READ8_HANDLER( YM3526_status_port_0_r ) {
+ struct ym3526_info *info = sndti_token(SOUND_YM3526, 0);
+ return YM3526Read(info->chip, 0);
+}
+READ8_HANDLER( YM3526_read_port_0_r ) {
+ struct ym3526_info *info = sndti_token(SOUND_YM3526, 0);
+ return YM3526Read(info->chip, 1);
+}
+
+
+WRITE8_HANDLER( YM3526_control_port_1_w ) {
+ struct ym3526_info *info = sndti_token(SOUND_YM3526, 1);
+ YM3526Write(info->chip, 0, data);
+}
+WRITE8_HANDLER( YM3526_write_port_1_w ) {
+ struct ym3526_info *info = sndti_token(SOUND_YM3526, 1);
+ YM3526Write(info->chip, 1, data);
+}
+READ8_HANDLER( YM3526_status_port_1_r ) {
+ struct ym3526_info *info = sndti_token(SOUND_YM3526, 1);
+ return YM3526Read(info->chip, 0);
+}
+READ8_HANDLER( YM3526_read_port_1_r ) {
+ struct ym3526_info *info = sndti_token(SOUND_YM3526, 1);
+ return YM3526Read(info->chip, 1);
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ym3526_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ym3526_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ym3526_set_info; break;
+ case SNDINFO_PTR_START: info->start = ym3526_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ym3526_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ym3526_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YM3526"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+#endif
+
+
+#if BUILD_Y8950
+
+struct y8950_info
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ const struct Y8950interface *intf;
+ int index;
+};
+
+static void IRQHandler_8950(void *param,int irq)
+{
+ struct y8950_info *info = param;
+ if (info->intf->handler) (info->intf->handler)(irq ? ASSERT_LINE : CLEAR_LINE);
+}
+static TIMER_CALLBACK_PTR( timer_callback_8950_0 )
+{
+ struct y8950_info *info = param;
+ Y8950TimerOver(info->chip,0);
+}
+static TIMER_CALLBACK_PTR( timer_callback_8950_1 )
+{
+ struct y8950_info *info = param;
+ Y8950TimerOver(info->chip,1);
+}
+static void TimerHandler_8950(void *param,int c,attotime period)
+{
+ struct y8950_info *info = param;
+ if( attotime_compare(period, attotime_zero) == 0 )
+ { /* Reset FM Timer */
+ timer_enable(info->timer[c], 0);
+ }
+ else
+ { /* Start FM Timer */
+ timer_adjust_ptr(info->timer[c], period, attotime_zero);
+ }
+}
+
+
+static unsigned char Y8950PortHandler_r(void *param)
+{
+ struct y8950_info *info = param;
+ if (info->intf->portread)
+ return info->intf->portread(info->index);
+ return 0;
+}
+
+static void Y8950PortHandler_w(void *param,unsigned char data)
+{
+ struct y8950_info *info = param;
+ if (info->intf->portwrite)
+ info->intf->portwrite(info->index,data);
+}
+
+static unsigned char Y8950KeyboardHandler_r(void *param)
+{
+ struct y8950_info *info = param;
+ if (info->intf->keyboardread)
+ return info->intf->keyboardread(info->index);
+ return 0;
+}
+
+static void Y8950KeyboardHandler_w(void *param,unsigned char data)
+{
+ struct y8950_info *info = param;
+ if (info->intf->keyboardwrite)
+ info->intf->keyboardwrite(info->index,data);
+}
+
+static void y8950_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct y8950_info *info = param;
+ Y8950UpdateOne(info->chip, buffer[0], length);
+}
+
+static void _stream_update_8950(void *param, int interval)
+{
+ struct y8950_info *info = param;
+ stream_update(info->stream);
+}
+
+
+static void *y8950_start(int sndindex, int clock, const void *config)
+{
+ static const struct Y8950interface dummy = { 0 };
+ struct y8950_info *info;
+ int rate = clock/72;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = config ? config : &dummy;
+ info->index = sndindex;
+
+ /* stream system initialize */
+ info->chip = Y8950Init(sndindex,clock,rate);
+ if (!info->chip)
+ return NULL;
+
+ /* ADPCM ROM data */
+ Y8950SetDeltaTMemory(info->chip,
+ (void *)(memory_region(info->intf->rom_region)),
+ memory_region_length(info->intf->rom_region) );
+
+ info->stream = stream_create(0,1,rate,info,y8950_stream_update);
+
+ /* port and keyboard handler */
+ Y8950SetPortHandler(info->chip, Y8950PortHandler_w, Y8950PortHandler_r, info);
+ Y8950SetKeyboardHandler(info->chip, Y8950KeyboardHandler_w, Y8950KeyboardHandler_r, info);
+
+ /* Y8950 setup */
+ Y8950SetTimerHandler (info->chip, TimerHandler_8950, info);
+ Y8950SetIRQHandler (info->chip, IRQHandler_8950, info);
+ Y8950SetUpdateHandler(info->chip, _stream_update_8950, info);
+
+ info->timer[0] = timer_alloc_ptr(timer_callback_8950_0, info);
+ info->timer[1] = timer_alloc_ptr(timer_callback_8950_1, info);
+
+ return info;
+}
+
+static void y8950_stop(void *token)
+{
+ struct y8950_info *info = token;
+ Y8950Shutdown(info->chip);
+}
+
+static void y8950_reset(void *token)
+{
+ struct y8950_info *info = token;
+ Y8950ResetChip(info->chip);
+}
+
+WRITE8_HANDLER( Y8950_control_port_0_w ) {
+ struct y8950_info *info = sndti_token(SOUND_Y8950, 0);
+ Y8950Write(info->chip, 0, data);
+}
+WRITE8_HANDLER( Y8950_write_port_0_w ) {
+ struct y8950_info *info = sndti_token(SOUND_Y8950, 0);
+ Y8950Write(info->chip, 1, data);
+}
+READ8_HANDLER( Y8950_status_port_0_r ) {
+ struct y8950_info *info = sndti_token(SOUND_Y8950, 0);
+ return Y8950Read(info->chip, 0);
+}
+READ8_HANDLER( Y8950_read_port_0_r ) {
+ struct y8950_info *info = sndti_token(SOUND_Y8950, 0);
+ return Y8950Read(info->chip, 1);
+}
+
+
+WRITE8_HANDLER( Y8950_control_port_1_w ) {
+ struct y8950_info *info = sndti_token(SOUND_Y8950, 1);
+ Y8950Write(info->chip, 0, data);
+}
+WRITE8_HANDLER( Y8950_write_port_1_w ) {
+ struct y8950_info *info = sndti_token(SOUND_Y8950, 1);
+ Y8950Write(info->chip, 1, data);
+}
+READ8_HANDLER( Y8950_status_port_1_r ) {
+ struct y8950_info *info = sndti_token(SOUND_Y8950, 1);
+ return Y8950Read(info->chip, 0);
+}
+READ8_HANDLER( Y8950_read_port_1_r ) {
+ struct y8950_info *info = sndti_token(SOUND_Y8950, 1);
+ return Y8950Read(info->chip, 1);
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void y8950_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void y8950_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = y8950_set_info; break;
+ case SNDINFO_PTR_START: info->start = y8950_start; break;
+ case SNDINFO_PTR_STOP: info->stop = y8950_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = y8950_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Y8950"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+#endif
diff --git a/src/emu/sound/3812intf.h b/src/emu/sound/3812intf.h
new file mode 100644
index 00000000000..d4ffce65ca4
--- /dev/null
+++ b/src/emu/sound/3812intf.h
@@ -0,0 +1,56 @@
+#ifndef YM3812INTF_H
+#define YM3812INTF_H
+
+
+struct YM3812interface
+{
+ void (*handler)(int linestate);
+};
+
+#define YM3526interface YM3812interface
+
+struct Y8950interface
+{
+ void (*handler)(int linestate);
+
+ int rom_region; /* delta-T ADPCM ROM/RAM region */
+
+ read8_handler keyboardread;
+ write8_handler keyboardwrite;
+ read8_handler portread;
+ write8_handler portwrite;
+};
+
+
+/* YM3812 */
+READ8_HANDLER ( YM3812_status_port_0_r );
+WRITE8_HANDLER( YM3812_control_port_0_w );
+WRITE8_HANDLER( YM3812_write_port_0_w );
+
+READ8_HANDLER ( YM3812_status_port_1_r );
+WRITE8_HANDLER( YM3812_control_port_1_w );
+WRITE8_HANDLER( YM3812_write_port_1_w );
+
+
+/* YM3526 */
+READ8_HANDLER ( YM3526_status_port_0_r );
+WRITE8_HANDLER( YM3526_control_port_0_w );
+WRITE8_HANDLER( YM3526_write_port_0_w );
+
+READ8_HANDLER ( YM3526_status_port_1_r );
+WRITE8_HANDLER( YM3526_control_port_1_w );
+WRITE8_HANDLER( YM3526_write_port_1_w );
+
+
+/* Y8950 */
+READ8_HANDLER ( Y8950_status_port_0_r );
+WRITE8_HANDLER( Y8950_control_port_0_w );
+READ8_HANDLER ( Y8950_read_port_0_r );
+WRITE8_HANDLER( Y8950_write_port_0_w );
+
+READ8_HANDLER ( Y8950_status_port_1_r );
+WRITE8_HANDLER( Y8950_control_port_1_w );
+READ8_HANDLER ( Y8950_read_port_1_r );
+WRITE8_HANDLER( Y8950_write_port_1_w );
+
+#endif
diff --git a/src/emu/sound/5110intf.c b/src/emu/sound/5110intf.c
new file mode 100644
index 00000000000..cfc22302e7a
--- /dev/null
+++ b/src/emu/sound/5110intf.c
@@ -0,0 +1,243 @@
+/******************************************************************************
+
+ TMS5110 interface
+
+ slightly modified from 5220intf by Jarek Burczynski
+
+ Written for MAME by Frank Palazzolo
+ With help from Neill Corlett
+ Additional tweaking by Aaron Giles
+
+******************************************************************************/
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "tms5110.h"
+#include "5110intf.h"
+
+
+#define MAX_SAMPLE_CHUNK 10000
+
+
+/* the state of the streamed output */
+struct tms5110_info
+{
+ const struct TMS5110interface *intf;
+ sound_stream *stream;
+ void *chip;
+};
+
+
+/* static function prototypes */
+static void tms5110_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length);
+
+
+
+/******************************************************************************
+
+ tms5110_start -- allocate buffers and reset the 5110
+
+******************************************************************************/
+
+static void *tms5110_start(int sndindex, int clock, const void *config)
+{
+ static const struct TMS5110interface dummy = { 0 };
+ struct tms5110_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+ info->intf = config ? config : &dummy;
+
+ info->chip = tms5110_create(sndindex);
+ if (!info->chip)
+ return NULL;
+ sndintrf_register_token(info);
+
+ /* initialize a stream */
+ info->stream = stream_create(0, 1, clock / 80, info, tms5110_update);
+
+ if (info->intf->M0_callback==NULL)
+ {
+ logerror("\n file: 5110intf.c, tms5110_start(), line 53:\n Missing _mandatory_ 'M0_callback' function pointer in the TMS5110 interface\n This function is used by TMS5110 to call for a single bits\n needed to generate the speech\n Aborting startup...\n");
+ return NULL;
+ }
+ tms5110_set_M0_callback(info->chip, info->intf->M0_callback );
+
+ /* reset the 5110 */
+ tms5110_reset_chip(info->chip);
+
+ /* request a sound channel */
+ return info;
+}
+
+
+
+/******************************************************************************
+
+ tms5110_stop -- free buffers
+
+******************************************************************************/
+
+static void tms5110_stop(void *chip)
+{
+ struct tms5110_info *info = chip;
+ tms5110_destroy(info->chip);
+}
+
+
+static void tms5110_reset(void *chip)
+{
+ struct tms5110_info *info = chip;
+ tms5110_reset_chip(info->chip);
+}
+
+
+
+/******************************************************************************
+
+ tms5110_CTL_w -- write Control Command to the sound chip
+commands like Speech, Reset, etc., are loaded into the chip via the CTL pins
+
+******************************************************************************/
+
+WRITE8_HANDLER( tms5110_CTL_w )
+{
+ struct tms5110_info *info = sndti_token(SOUND_TMS5110, 0);
+
+ /* bring up to date first */
+ stream_update(info->stream);
+ tms5110_CTL_set(info->chip, data);
+}
+
+/******************************************************************************
+
+ tms5110_PDC_w -- write to PDC pin on the sound chip
+
+******************************************************************************/
+
+WRITE8_HANDLER( tms5110_PDC_w )
+{
+ struct tms5110_info *info = sndti_token(SOUND_TMS5110, 0);
+
+ /* bring up to date first */
+ stream_update(info->stream);
+ tms5110_PDC_set(info->chip, data);
+}
+
+
+
+/******************************************************************************
+
+ tms5110_status_r -- read status from the sound chip
+
+******************************************************************************/
+
+READ8_HANDLER( tms5110_status_r )
+{
+ struct tms5110_info *info = sndti_token(SOUND_TMS5110, 0);
+
+ /* bring up to date first */
+ stream_update(info->stream);
+ return tms5110_status_read(info->chip);
+}
+
+
+
+/******************************************************************************
+
+ tms5110_ready_r -- return the not ready status from the sound chip
+
+******************************************************************************/
+
+int tms5110_ready_r(void)
+{
+ struct tms5110_info *info = sndti_token(SOUND_TMS5110, 0);
+
+ /* bring up to date first */
+ stream_update(info->stream);
+ return tms5110_ready_read(info->chip);
+}
+
+
+
+/******************************************************************************
+
+ tms5110_update -- update the sound chip so that it is in sync with CPU execution
+
+******************************************************************************/
+
+static void tms5110_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct tms5110_info *info = param;
+ INT16 sample_data[MAX_SAMPLE_CHUNK];
+ stream_sample_t *buffer = _buffer[0];
+
+ /* loop while we still have samples to generate */
+ while (length)
+ {
+ int samples = (length > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : length;
+ int index;
+
+ /* generate the samples and copy to the target buffer */
+ tms5110_process(info->chip, sample_data, samples);
+ for (index = 0; index < samples; index++)
+ *buffer++ = sample_data[index];
+
+ /* account for the samples */
+ length -= samples;
+ }
+}
+
+
+
+/******************************************************************************
+
+ tms5110_set_frequency -- adjusts the playback frequency
+
+******************************************************************************/
+
+void tms5110_set_frequency(int frequency)
+{
+ struct tms5110_info *info = sndti_token(SOUND_TMS5110, 0);
+ stream_set_sample_rate(info->stream, frequency / 80);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void tms5110_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void tms5110_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = tms5110_set_info; break;
+ case SNDINFO_PTR_START: info->start = tms5110_start; break;
+ case SNDINFO_PTR_STOP: info->stop = tms5110_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = tms5110_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "TMS5110"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "TI Speech"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/5110intf.h b/src/emu/sound/5110intf.h
new file mode 100644
index 00000000000..704550b4efa
--- /dev/null
+++ b/src/emu/sound/5110intf.h
@@ -0,0 +1,23 @@
+#ifndef intf5110_h
+#define intf5110_h
+
+/* clock rate = 80 * output sample rate, */
+/* usually 640000 for 8000 Hz sample rate or */
+/* usually 800000 for 10000 Hz sample rate. */
+
+struct TMS5110interface
+{
+ void (*irq)(int state); /* IRQ callback function */
+ int (*M0_callback)(void); /* function to be called when chip requests another bit*/
+};
+
+WRITE8_HANDLER( tms5110_CTL_w );
+WRITE8_HANDLER( tms5110_PDC_w );
+
+READ8_HANDLER( tms5110_status_r );
+int tms5110_ready_r(void);
+
+void tms5110_set_frequency(int frequency);
+
+#endif
+
diff --git a/src/emu/sound/5220intf.c b/src/emu/sound/5220intf.c
new file mode 100644
index 00000000000..d6ea6b1cf59
--- /dev/null
+++ b/src/emu/sound/5220intf.c
@@ -0,0 +1,262 @@
+/**********************************************************************************************
+
+ TMS5220 interface
+
+ Written for MAME by Frank Palazzolo
+ With help from Neill Corlett
+ Additional tweaking by Aaron Giles
+ Speech ROM support and a few bug fixes by R Nabet
+
+***********************************************************************************************/
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "tms5220.h"
+#include "5220intf.h"
+
+
+#define MAX_SAMPLE_CHUNK 10000
+
+
+/* the state of the streamed output */
+struct tms5220_info
+{
+ const struct TMS5220interface *intf;
+ sound_stream *stream;
+ int clock;
+ void *chip;
+};
+
+
+/* static function prototypes */
+static void tms5220_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length);
+
+
+
+/**********************************************************************************************
+
+ tms5220_start -- allocate buffers and reset the 5220
+
+***********************************************************************************************/
+
+static void *tms5220_start(int sndindex, int clock, const void *config)
+{
+ static const struct TMS5220interface dummy = { 0 };
+ struct tms5220_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+ info->intf = config ? config : &dummy;
+
+ info->chip = tms5220_create(sndindex);
+ if (!info->chip)
+ return NULL;
+ sndintrf_register_token(info);
+
+ /* initialize a info->stream */
+ info->stream = stream_create(0, 1, clock / 80, info, tms5220_update);
+ info->clock = clock;
+
+ /* reset the 5220 */
+ tms5220_reset_chip(info->chip);
+ tms5220_set_irq(info->chip, info->intf->irq);
+
+ /* init the speech ROM handlers */
+ tms5220_set_read(info->chip, info->intf->read);
+ tms5220_set_load_address(info->chip, info->intf->load_address);
+ tms5220_set_read_and_branch(info->chip, info->intf->read_and_branch);
+
+ /* request a sound channel */
+ return info;
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_stop -- free buffers
+
+***********************************************************************************************/
+
+static void tms5220_stop(void *chip)
+{
+ struct tms5220_info *info = chip;
+ tms5220_destroy(info->chip);
+}
+
+
+
+static void tms5220_reset(void *chip)
+{
+ struct tms5220_info *info = chip;
+ tms5220_reset_chip(info->chip);
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_data_w -- write data to the sound chip
+
+***********************************************************************************************/
+
+WRITE8_HANDLER( tms5220_data_w )
+{
+ struct tms5220_info *info = sndti_token(SOUND_TMS5220, 0);
+ /* bring up to date first */
+ stream_update(info->stream);
+ tms5220_data_write(info->chip, data);
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_status_r -- read status or data from the sound chip
+
+***********************************************************************************************/
+
+READ8_HANDLER( tms5220_status_r )
+{
+ struct tms5220_info *info = sndti_token(SOUND_TMS5220, 0);
+ /* bring up to date first */
+ stream_update(info->stream);
+ return tms5220_status_read(info->chip);
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_ready_r -- return the not ready status from the sound chip
+
+***********************************************************************************************/
+
+int tms5220_ready_r(void)
+{
+ struct tms5220_info *info = sndti_token(SOUND_TMS5220, 0);
+ /* bring up to date first */
+ stream_update(info->stream);
+ return tms5220_ready_read(info->chip);
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_ready_r -- return the time in seconds until the ready line is asserted
+
+***********************************************************************************************/
+
+double tms5220_time_to_ready(void)
+{
+ struct tms5220_info *info = sndti_token(SOUND_TMS5220, 0);
+ double cycles;
+
+ /* bring up to date first */
+ stream_update(info->stream);
+ cycles = tms5220_cycles_to_ready(info->chip);
+ return cycles * 80.0 / info->clock;
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_int_r -- return the int status from the sound chip
+
+***********************************************************************************************/
+
+int tms5220_int_r(void)
+{
+ struct tms5220_info *info = sndti_token(SOUND_TMS5220, 0);
+ /* bring up to date first */
+ stream_update(info->stream);
+ return tms5220_int_read(info->chip);
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_update -- update the sound chip so that it is in sync with CPU execution
+
+***********************************************************************************************/
+
+static void tms5220_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct tms5220_info *info = param;
+ INT16 sample_data[MAX_SAMPLE_CHUNK];
+ stream_sample_t *buffer = _buffer[0];
+
+ /* loop while we still have samples to generate */
+ while (length)
+ {
+ int samples = (length > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : length;
+ int index;
+
+ /* generate the samples and copy to the target buffer */
+ tms5220_process(info->chip, sample_data, samples);
+ for (index = 0; index < samples; index++)
+ *buffer++ = sample_data[index];
+
+ /* account for the samples */
+ length -= samples;
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_set_frequency -- adjusts the playback frequency
+
+***********************************************************************************************/
+
+void tms5220_set_frequency(int frequency)
+{
+ struct tms5220_info *info = sndti_token(SOUND_TMS5220, 0);
+ stream_set_sample_rate(info->stream, frequency / 80);
+ info->clock = frequency;
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void tms5220_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ struct tms5220_info *ti = token;
+
+ switch (state)
+ {
+ case SNDINFO_INT_TMS5220_VARIANT: tms5220_set_variant(ti->chip, (tms5220_variant) info->i); break;
+ }
+}
+
+
+void tms5220_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = tms5220_set_info; break;
+ case SNDINFO_PTR_START: info->start = tms5220_start; break;
+ case SNDINFO_PTR_STOP: info->stop = tms5220_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = tms5220_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "TMS5220"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "TI Speech"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/5220intf.h b/src/emu/sound/5220intf.h
new file mode 100644
index 00000000000..e197201d434
--- /dev/null
+++ b/src/emu/sound/5220intf.h
@@ -0,0 +1,31 @@
+#ifndef intf5220_h
+#define intf5220_h
+
+/* clock rate = 80 * output sample rate, */
+/* usually 640000 for 8000 Hz sample rate or */
+/* usually 800000 for 10000 Hz sample rate. */
+
+struct TMS5220interface
+{
+ void (*irq)(int state); /* IRQ callback function */
+
+ int (*read)(int count); /* speech ROM read callback */
+ void (*load_address)(int data); /* speech ROM load address callback */
+ void (*read_and_branch)(void); /* speech ROM read and branch callback */
+};
+
+WRITE8_HANDLER( tms5220_data_w );
+READ8_HANDLER( tms5220_status_r );
+int tms5220_ready_r(void);
+double tms5220_time_to_ready(void);
+int tms5220_int_r(void);
+
+void tms5220_set_frequency(int frequency);
+
+enum
+{
+ SNDINFO_INT_TMS5220_VARIANT = SNDINFO_INT_CORE_SPECIFIC
+};
+
+#endif
+
diff --git a/src/emu/sound/astrocde.c b/src/emu/sound/astrocde.c
new file mode 100644
index 00000000000..88457451453
--- /dev/null
+++ b/src/emu/sound/astrocde.c
@@ -0,0 +1,355 @@
+/***********************************************************
+
+ Astrocade custom 'IO' chip sound chip driver
+ Aaron Giles
+ based on original work by Frank Palazzolo
+
+************************************************************
+
+ Register Map
+ ============
+
+ Register 0:
+ D7..D0: Master oscillator frequency
+
+ Register 1:
+ D7..D0: Tone generator A frequency
+
+ Register 2:
+ D7..D0: Tone generator B frequency
+
+ Register 3:
+ D7..D0: Tone generator C frequency
+
+ Register 4:
+ D7..D6: Vibrato speed
+ D5..D0: Vibrato depth
+
+ Register 5:
+ D5: Noise AM enable
+ D4: Mux source (0=vibrato, 1=noise)
+ D3..D0: Tone generator C volume
+
+ Register 6:
+ D7..D4: Tone generator B volume
+ D3..D0: Tone generator A volume
+
+ Register 7:
+ D7..D0: Noise volume
+
+***********************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "astrocde.h"
+
+
+struct astrocade_info
+{
+ sound_stream *stream; /* sound stream */
+
+ UINT8 reg[8]; /* 8 control registers */
+
+ UINT8 master_count; /* current master oscillator count */
+ UINT16 vibrato_clock; /* current vibrato clock */
+
+ UINT8 noise_clock; /* current noise generator clock */
+ UINT16 noise_state; /* current noise LFSR state */
+
+ UINT8 a_count; /* current tone generator A count */
+ UINT8 a_state; /* current tone generator A state */
+
+ UINT8 b_count; /* current tone generator B count */
+ UINT8 b_state; /* current tone generator B state */
+
+ UINT8 c_count; /* current tone generator C count */
+ UINT8 c_state; /* current tone generator C state */
+
+ UINT8 bitswap[256]; /* bitswap table */
+};
+
+
+
+/*************************************
+ *
+ * Core sound update
+ *
+ *************************************/
+
+static void astrocade_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int samples)
+{
+ struct astrocade_info *chip = param;
+ stream_sample_t *dest = buffer[0];
+ UINT16 noise_state;
+ UINT8 master_count;
+ UINT8 noise_clock;
+
+ /* load some locals */
+ master_count = chip->master_count;
+ noise_clock = chip->noise_clock;
+ noise_state = chip->noise_state;
+
+ /* loop over samples */
+ while (samples > 0)
+ {
+ stream_sample_t cursample = 0;
+ int samples_this_time;
+ int samp;
+
+ /* compute the number of cycles until the next master oscillator reset */
+ /* or until the next noise boundary */
+ samples_this_time = MIN(samples, 256 - master_count);
+ samples_this_time = MIN(samples_this_time, 64 - noise_clock);
+ samples -= samples_this_time;
+
+ /* sum the output of the tone generators */
+ if (chip->a_state)
+ cursample += chip->reg[6] & 0x0f;
+ if (chip->b_state)
+ cursample += chip->reg[6] >> 4;
+ if (chip->c_state)
+ cursample += chip->reg[5] & 0x0f;
+
+ /* add in the noise if it is enabled, based on the top bit of the LFSR */
+ if ((chip->reg[5] & 0x20) && (noise_state & 0x4000))
+ cursample += chip->reg[7] >> 4;
+
+ /* scale to max and output */
+ cursample = cursample * 32767 / 60;
+ for (samp = 0; samp < samples_this_time; samp++)
+ *dest++ = cursample;
+
+ /* clock the noise; a 2-bit counter clocks a 4-bit counter which clocks the LFSR */
+ noise_clock += samples_this_time;
+ if (noise_clock >= 64)
+ {
+ /* update the noise state; this is a 15-bit LFSR with feedback from */
+ /* the XOR of the top two bits */
+ noise_state = (noise_state << 1) | (~((noise_state >> 14) ^ (noise_state >> 13)) & 1);
+ noise_clock -= 64;
+
+ /* the same clock also controls the vibrato clock, which is a 13-bit counter */
+ chip->vibrato_clock++;
+ }
+
+ /* clock the master oscillator; this is an 8-bit up counter */
+ master_count += samples_this_time;
+ if (master_count == 0)
+ {
+ /* reload based on mux value -- the value from the register is negative logic */
+ master_count = ~chip->reg[0];
+
+ /* mux value 0 means reload based on the vibrato control */
+ if ((chip->reg[5] & 0x10) == 0)
+ {
+ /* vibrato speed (register 4 bits 6-7) selects one of the top 4 bits */
+ /* of the 13-bit vibrato clock to use (0=highest freq, 3=lowest) */
+ if (!((chip->vibrato_clock >> (chip->reg[4] >> 6)) & 0x0200))
+ {
+ /* if the bit is clear, we add the vibrato volume to the counter */
+ master_count += chip->reg[4] & 0x3f;
+ }
+ }
+
+ /* mux value 1 means reload based on the noise control */
+ else
+ {
+ /* the top 8 bits of the noise LFSR are ANDed with the noise volume */
+ /* register and added to the count */
+ master_count += chip->bitswap[(noise_state >> 7) & 0xff] & chip->reg[7];
+ }
+
+ /* clock tone A */
+ if (++chip->a_count == 0)
+ {
+ chip->a_state ^= 1;
+ chip->a_count = ~chip->reg[1];
+ }
+
+ /* clock tone B */
+ if (++chip->b_count == 0)
+ {
+ chip->b_state ^= 1;
+ chip->b_count = ~chip->reg[2];
+ }
+
+ /* clock tone C */
+ if (++chip->c_count == 0)
+ {
+ chip->c_state ^= 1;
+ chip->c_count = ~chip->reg[3];
+ }
+ }
+ }
+
+ /* put back the locals */
+ chip->master_count = master_count;
+ chip->noise_clock = noise_clock;
+ chip->noise_state = noise_state;
+}
+
+
+
+/*************************************
+ *
+ * Chip reset
+ *
+ *************************************/
+
+static void astrocade_reset(void *_chip)
+{
+ struct astrocade_info *chip = _chip;
+
+ memset(chip->reg, 0, sizeof(chip->reg));
+
+ chip->master_count = 0;
+ chip->vibrato_clock = 0;
+
+ chip->noise_clock = 0;
+ chip->noise_state = 0;
+
+ chip->a_count = 0;
+ chip->a_state = 0;
+
+ chip->b_count = 0;
+ chip->b_state = 0;
+
+ chip->c_count = 0;
+ chip->c_state = 0;
+}
+
+
+
+/*************************************
+ *
+ * Save state registration
+ *
+ *************************************/
+
+static void astrocade_state_save_register(struct astrocade_info *chip, int sndindex)
+{
+ state_save_register_item_array("globals", sndindex, chip->reg);
+
+ state_save_register_item_array("astrocade", sndindex, chip->reg);
+
+ state_save_register_item("astrocade", sndindex, chip->master_count);
+ state_save_register_item("astrocade", sndindex, chip->vibrato_clock);
+
+ state_save_register_item("astrocade", sndindex, chip->noise_clock);
+ state_save_register_item("astrocade", sndindex, chip->noise_state);
+
+ state_save_register_item("astrocade", sndindex, chip->a_count);
+ state_save_register_item("astrocade", sndindex, chip->a_state);
+
+ state_save_register_item("astrocade", sndindex, chip->b_count);
+ state_save_register_item("astrocade", sndindex, chip->b_state);
+
+ state_save_register_item("astrocade", sndindex, chip->c_count);
+ state_save_register_item("astrocade", sndindex, chip->c_state);
+}
+
+
+
+/*************************************
+ *
+ * Chip initialization
+ *
+ *************************************/
+
+static void *astrocade_start(int sndindex, int clock, const void *config)
+{
+ struct astrocade_info *chip;
+ int i;
+
+ /* allocate the chip memory */
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ /* generate a bitswap table for the noise */
+ for (i = 0; i < 256; i++)
+ chip->bitswap[i] = BITSWAP8(i, 0,1,2,3,4,5,6,7);
+
+ /* allocate a stream for output */
+ chip->stream = stream_create(0, 1, clock, chip, astrocade_update);
+
+ /* reset state */
+ astrocade_reset(chip);
+ astrocade_state_save_register(chip, sndindex);
+
+ return chip;
+}
+
+
+
+/*************************************
+ *
+ * Sound write accessors
+ *
+ *************************************/
+
+void astrocade_sound_w(UINT8 num, offs_t offset, UINT8 data)
+{
+ struct astrocade_info *chip = sndti_token(SOUND_ASTROCADE, num);
+
+ /* update */
+ stream_update(chip->stream);
+
+ /* stash the new register value */
+ chip->reg[offset & 7] = data;
+}
+
+
+WRITE8_HANDLER( astrocade_sound1_w )
+{
+ if ((offset & 8) != 0)
+ astrocade_sound_w(0, (offset >> 8) & 7, data);
+ else
+ astrocade_sound_w(0, offset & 7, data);
+}
+
+
+WRITE8_HANDLER( astrocade_sound2_w )
+{
+ if ((offset & 8) != 0)
+ astrocade_sound_w(1, (offset >> 8) & 7, data);
+ else
+ astrocade_sound_w(1, offset & 7, data);
+}
+
+
+
+/*************************************
+ *
+ * Get/set info callbacks
+ *
+ *************************************/
+
+static void astrocade_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void astrocade_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = astrocade_set_info; break;
+ case SNDINFO_PTR_START: info->start = astrocade_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = astrocade_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Astrocade"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Bally"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "2.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004-2007, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/astrocde.h b/src/emu/sound/astrocde.h
new file mode 100644
index 00000000000..cfefc75f9d6
--- /dev/null
+++ b/src/emu/sound/astrocde.h
@@ -0,0 +1,8 @@
+
+#ifndef ASTROCADE_H
+#define ASTROCADE_H
+
+WRITE8_HANDLER( astrocade_sound1_w );
+WRITE8_HANDLER( astrocade_sound2_w );
+
+#endif
diff --git a/src/emu/sound/ay8910.c b/src/emu/sound/ay8910.c
new file mode 100644
index 00000000000..0a7d93154d0
--- /dev/null
+++ b/src/emu/sound/ay8910.c
@@ -0,0 +1,899 @@
+/***************************************************************************
+
+ ay8910.c
+
+
+ Emulation of the AY-3-8910 / YM2149 sound chip.
+
+ Based on various code snippets by Ville Hallik, Michael Cuddy,
+ Tatsuyuki Satoh, Fabrice Frances, Nicola Salmoria.
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "ay8910.h"
+
+#define MAX_OUTPUT 0x7fff
+
+#define STEP 2
+
+
+struct AY8910
+{
+ int index;
+ int streams;
+ int ready;
+ sound_stream *Channel;
+ read8_handler PortAread;
+ read8_handler PortBread;
+ write8_handler PortAwrite;
+ write8_handler PortBwrite;
+ INT32 register_latch;
+ UINT8 Regs[16];
+ INT32 lastEnable;
+ INT32 PeriodA,PeriodB,PeriodC,PeriodN,PeriodE;
+ INT32 CountA,CountB,CountC,CountN,CountE;
+ UINT32 VolA,VolB,VolC,VolE;
+ UINT8 EnvelopeA,EnvelopeB,EnvelopeC;
+ UINT8 OutputA,OutputB,OutputC,OutputN;
+ INT8 CountEnv;
+ UINT8 Hold,Alternate,Attack,Holding;
+ INT32 RNG;
+ unsigned int VolTable[32];
+};
+
+/* register id's */
+#define AY_AFINE (0)
+#define AY_ACOARSE (1)
+#define AY_BFINE (2)
+#define AY_BCOARSE (3)
+#define AY_CFINE (4)
+#define AY_CCOARSE (5)
+#define AY_NOISEPER (6)
+#define AY_ENABLE (7)
+#define AY_AVOL (8)
+#define AY_BVOL (9)
+#define AY_CVOL (10)
+#define AY_EFINE (11)
+#define AY_ECOARSE (12)
+#define AY_ESHAPE (13)
+
+#define AY_PORTA (14)
+#define AY_PORTB (15)
+
+
+static void _AYWriteReg(struct AY8910 *PSG, int r, int v)
+{
+ int old;
+
+
+ PSG->Regs[r] = v;
+
+ /* A note about the period of tones, noise and envelope: for speed reasons,*/
+ /* we count down from the period to 0, but careful studies of the chip */
+ /* output prove that it instead counts up from 0 until the counter becomes */
+ /* greater or equal to the period. This is an important difference when the*/
+ /* program is rapidly changing the period to modulate the sound. */
+ /* To compensate for the difference, when the period is changed we adjust */
+ /* our internal counter. */
+ /* Also, note that period = 0 is the same as period = 1. This is mentioned */
+ /* in the YM2203 data sheets. However, this does NOT apply to the Envelope */
+ /* period. In that case, period = 0 is half as period = 1. */
+ switch( r )
+ {
+ case AY_AFINE:
+ case AY_ACOARSE:
+ PSG->Regs[AY_ACOARSE] &= 0x0f;
+ old = PSG->PeriodA;
+ PSG->PeriodA = (PSG->Regs[AY_AFINE] + 256 * PSG->Regs[AY_ACOARSE]) * STEP;
+ if (PSG->PeriodA == 0) PSG->PeriodA = STEP;
+ PSG->CountA += PSG->PeriodA - old;
+ if (PSG->CountA <= 0) PSG->CountA = 1;
+ break;
+ case AY_BFINE:
+ case AY_BCOARSE:
+ PSG->Regs[AY_BCOARSE] &= 0x0f;
+ old = PSG->PeriodB;
+ PSG->PeriodB = (PSG->Regs[AY_BFINE] + 256 * PSG->Regs[AY_BCOARSE]) * STEP;
+ if (PSG->PeriodB == 0) PSG->PeriodB = STEP;
+ PSG->CountB += PSG->PeriodB - old;
+ if (PSG->CountB <= 0) PSG->CountB = 1;
+ break;
+ case AY_CFINE:
+ case AY_CCOARSE:
+ PSG->Regs[AY_CCOARSE] &= 0x0f;
+ old = PSG->PeriodC;
+ PSG->PeriodC = (PSG->Regs[AY_CFINE] + 256 * PSG->Regs[AY_CCOARSE]) * STEP;
+ if (PSG->PeriodC == 0) PSG->PeriodC = STEP;
+ PSG->CountC += PSG->PeriodC - old;
+ if (PSG->CountC <= 0) PSG->CountC = 1;
+ break;
+ case AY_NOISEPER:
+ PSG->Regs[AY_NOISEPER] &= 0x1f;
+ old = PSG->PeriodN;
+ PSG->PeriodN = PSG->Regs[AY_NOISEPER] * STEP;
+ if (PSG->PeriodN == 0) PSG->PeriodN = STEP;
+ PSG->CountN += PSG->PeriodN - old;
+ if (PSG->CountN <= 0) PSG->CountN = 1;
+ break;
+ case AY_ENABLE:
+ if ((PSG->lastEnable == -1) ||
+ ((PSG->lastEnable & 0x40) != (PSG->Regs[AY_ENABLE] & 0x40)))
+ {
+ /* write out 0xff if port set to input */
+ if (PSG->PortAwrite)
+ (*PSG->PortAwrite)(0, (PSG->Regs[AY_ENABLE] & 0x40) ? PSG->Regs[AY_PORTA] : 0xff);
+ }
+
+ if ((PSG->lastEnable == -1) ||
+ ((PSG->lastEnable & 0x80) != (PSG->Regs[AY_ENABLE] & 0x80)))
+ {
+ /* write out 0xff if port set to input */
+ if (PSG->PortBwrite)
+ (*PSG->PortBwrite)(0, (PSG->Regs[AY_ENABLE] & 0x80) ? PSG->Regs[AY_PORTB] : 0xff);
+ }
+
+ PSG->lastEnable = PSG->Regs[AY_ENABLE];
+ break;
+ case AY_AVOL:
+ PSG->Regs[AY_AVOL] &= 0x1f;
+ PSG->EnvelopeA = PSG->Regs[AY_AVOL] & 0x10;
+ PSG->VolA = PSG->EnvelopeA ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_AVOL] ? PSG->Regs[AY_AVOL]*2+1 : 0];
+ break;
+ case AY_BVOL:
+ PSG->Regs[AY_BVOL] &= 0x1f;
+ PSG->EnvelopeB = PSG->Regs[AY_BVOL] & 0x10;
+ PSG->VolB = PSG->EnvelopeB ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_BVOL] ? PSG->Regs[AY_BVOL]*2+1 : 0];
+ break;
+ case AY_CVOL:
+ PSG->Regs[AY_CVOL] &= 0x1f;
+ PSG->EnvelopeC = PSG->Regs[AY_CVOL] & 0x10;
+ PSG->VolC = PSG->EnvelopeC ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_CVOL] ? PSG->Regs[AY_CVOL]*2+1 : 0];
+ break;
+ case AY_EFINE:
+ case AY_ECOARSE:
+ old = PSG->PeriodE;
+ PSG->PeriodE = ((PSG->Regs[AY_EFINE] + 256 * PSG->Regs[AY_ECOARSE])) * STEP;
+ if (PSG->PeriodE == 0) PSG->PeriodE = STEP / 2;
+ PSG->CountE += PSG->PeriodE - old;
+ if (PSG->CountE <= 0) PSG->CountE = 1;
+ break;
+ case AY_ESHAPE:
+ /* envelope shapes:
+ C AtAlH
+ 0 0 x x \___
+
+ 0 1 x x /___
+
+ 1 0 0 0 \\\\
+
+ 1 0 0 1 \___
+
+ 1 0 1 0 \/\/
+ ___
+ 1 0 1 1 \
+
+ 1 1 0 0 ////
+ ___
+ 1 1 0 1 /
+
+ 1 1 1 0 /\/\
+
+ 1 1 1 1 /___
+
+ The envelope counter on the AY-3-8910 has 16 steps. On the YM2149 it
+ has twice the steps, happening twice as fast. Since the end result is
+ just a smoother curve, we always use the YM2149 behaviour.
+ */
+ PSG->Regs[AY_ESHAPE] &= 0x0f;
+ PSG->Attack = (PSG->Regs[AY_ESHAPE] & 0x04) ? 0x1f : 0x00;
+ if ((PSG->Regs[AY_ESHAPE] & 0x08) == 0)
+ {
+ /* if Continue = 0, map the shape to the equivalent one which has Continue = 1 */
+ PSG->Hold = 1;
+ PSG->Alternate = PSG->Attack;
+ }
+ else
+ {
+ PSG->Hold = PSG->Regs[AY_ESHAPE] & 0x01;
+ PSG->Alternate = PSG->Regs[AY_ESHAPE] & 0x02;
+ }
+ PSG->CountE = PSG->PeriodE;
+ PSG->CountEnv = 0x1f;
+ PSG->Holding = 0;
+ PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack];
+ if (PSG->EnvelopeA) PSG->VolA = PSG->VolE;
+ if (PSG->EnvelopeB) PSG->VolB = PSG->VolE;
+ if (PSG->EnvelopeC) PSG->VolC = PSG->VolE;
+ break;
+ case AY_PORTA:
+ if (PSG->Regs[AY_ENABLE] & 0x40)
+ {
+ if (PSG->PortAwrite)
+ (*PSG->PortAwrite)(0, PSG->Regs[AY_PORTA]);
+ else
+ logerror("warning - write %02x to 8910 #%d Port A\n",PSG->Regs[AY_PORTA],PSG->index);
+ }
+ else
+ {
+ logerror("warning: write to 8910 #%d Port A set as input - ignored\n",PSG->index);
+ }
+ break;
+ case AY_PORTB:
+ if (PSG->Regs[AY_ENABLE] & 0x80)
+ {
+ if (PSG->PortBwrite)
+ (*PSG->PortBwrite)(0, PSG->Regs[AY_PORTB]);
+ else
+ logerror("warning - write %02x to 8910 #%d Port B\n",PSG->Regs[AY_PORTB],PSG->index);
+ }
+ else
+ {
+ logerror("warning: write to 8910 #%d Port B set as input - ignored\n",PSG->index);
+ }
+ break;
+ }
+}
+
+
+
+/* AY8910 interface */
+READ8_HANDLER( AY8910_read_port_0_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 0)); }
+READ8_HANDLER( AY8910_read_port_1_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 1)); }
+READ8_HANDLER( AY8910_read_port_2_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 2)); }
+READ8_HANDLER( AY8910_read_port_3_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 3)); }
+READ8_HANDLER( AY8910_read_port_4_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 4)); }
+READ16_HANDLER( AY8910_read_port_0_lsb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 0)); }
+READ16_HANDLER( AY8910_read_port_1_lsb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 1)); }
+READ16_HANDLER( AY8910_read_port_2_lsb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 2)); }
+READ16_HANDLER( AY8910_read_port_3_lsb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 3)); }
+READ16_HANDLER( AY8910_read_port_4_lsb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 4)); }
+READ16_HANDLER( AY8910_read_port_0_msb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 0)) << 8; }
+READ16_HANDLER( AY8910_read_port_1_msb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 1)) << 8; }
+READ16_HANDLER( AY8910_read_port_2_msb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 2)) << 8; }
+READ16_HANDLER( AY8910_read_port_3_msb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 3)) << 8; }
+READ16_HANDLER( AY8910_read_port_4_msb_r ) { return ay8910_read_ym(sndti_token(SOUND_AY8910, 4)) << 8; }
+
+WRITE8_HANDLER( AY8910_control_port_0_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 0),0,data); }
+WRITE8_HANDLER( AY8910_control_port_1_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 1),0,data); }
+WRITE8_HANDLER( AY8910_control_port_2_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 2),0,data); }
+WRITE8_HANDLER( AY8910_control_port_3_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 3),0,data); }
+WRITE8_HANDLER( AY8910_control_port_4_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 4),0,data); }
+WRITE16_HANDLER( AY8910_control_port_0_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 0),0,data & 0xff); }
+WRITE16_HANDLER( AY8910_control_port_1_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 1),0,data & 0xff); }
+WRITE16_HANDLER( AY8910_control_port_2_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 2),0,data & 0xff); }
+WRITE16_HANDLER( AY8910_control_port_3_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 3),0,data & 0xff); }
+WRITE16_HANDLER( AY8910_control_port_4_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 4),0,data & 0xff); }
+WRITE16_HANDLER( AY8910_control_port_0_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 0),0,data >> 8); }
+WRITE16_HANDLER( AY8910_control_port_1_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 1),0,data >> 8); }
+WRITE16_HANDLER( AY8910_control_port_2_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 2),0,data >> 8); }
+WRITE16_HANDLER( AY8910_control_port_3_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 3),0,data >> 8); }
+WRITE16_HANDLER( AY8910_control_port_4_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 4),0,data >> 8); }
+
+WRITE8_HANDLER( AY8910_write_port_0_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 0),1,data); }
+WRITE8_HANDLER( AY8910_write_port_1_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 1),1,data); }
+WRITE8_HANDLER( AY8910_write_port_2_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 2),1,data); }
+WRITE8_HANDLER( AY8910_write_port_3_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 3),1,data); }
+WRITE8_HANDLER( AY8910_write_port_4_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 4),1,data); }
+WRITE16_HANDLER( AY8910_write_port_0_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 0),1,data & 0xff); }
+WRITE16_HANDLER( AY8910_write_port_1_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 1),1,data & 0xff); }
+WRITE16_HANDLER( AY8910_write_port_2_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 2),1,data & 0xff); }
+WRITE16_HANDLER( AY8910_write_port_3_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 3),1,data & 0xff); }
+WRITE16_HANDLER( AY8910_write_port_4_lsb_w ) { if (ACCESSING_LSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 4),1,data & 0xff); }
+WRITE16_HANDLER( AY8910_write_port_0_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 0),1,data >> 8); }
+WRITE16_HANDLER( AY8910_write_port_1_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 1),1,data >> 8); }
+WRITE16_HANDLER( AY8910_write_port_2_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 2),1,data >> 8); }
+WRITE16_HANDLER( AY8910_write_port_3_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 3),1,data >> 8); }
+WRITE16_HANDLER( AY8910_write_port_4_msb_w ) { if (ACCESSING_MSB) ay8910_write_ym(sndti_token(SOUND_AY8910, 4),1,data >> 8); }
+
+
+
+static void AY8910Update(void *param,stream_sample_t **inputs, stream_sample_t **buffer,int length)
+{
+ struct AY8910 *PSG = param;
+ stream_sample_t *buf1,*buf2,*buf3;
+ int outn;
+
+ buf1 = buffer[0];
+ buf2 = NULL;
+ buf3 = NULL;
+ if (PSG->streams == 3)
+ {
+ buf2 = buffer[1];
+ buf3 = buffer[2];
+ }
+
+ /* hack to prevent us from hanging when starting filtered outputs */
+ if (!PSG->ready)
+ {
+ memset(buf1, 0, length * sizeof(*buf1));
+ if (buf2)
+ memset(buf2, 0, length * sizeof(*buf2));
+ if (buf3)
+ memset(buf3, 0, length * sizeof(*buf3));
+ return;
+ }
+
+
+ /* The 8910 has three outputs, each output is the mix of one of the three */
+ /* tone generators and of the (single) noise generator. The two are mixed */
+ /* BEFORE going into the DAC. The formula to mix each channel is: */
+ /* (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). */
+ /* Note that this means that if both tone and noise are disabled, the output */
+ /* is 1, not 0, and can be modulated changing the volume. */
+
+
+ /* If the channels are disabled, set their output to 1, and increase the */
+ /* counter, if necessary, so they will not be inverted during this update. */
+ /* Setting the output to 1 is necessary because a disabled channel is locked */
+ /* into the ON state (see above); and it has no effect if the volume is 0. */
+ /* If the volume is 0, increase the counter, but don't touch the output. */
+ if (PSG->Regs[AY_ENABLE] & 0x01)
+ {
+ if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
+ PSG->OutputA = 1;
+ }
+ else if (PSG->Regs[AY_AVOL] == 0)
+ {
+ /* note that I do count += length, NOT count = length + 1. You might think */
+ /* it's the same since the volume is 0, but doing the latter could cause */
+ /* interferencies when the program is rapidly modulating the volume. */
+ if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
+ }
+ if (PSG->Regs[AY_ENABLE] & 0x02)
+ {
+ if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
+ PSG->OutputB = 1;
+ }
+ else if (PSG->Regs[AY_BVOL] == 0)
+ {
+ if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
+ }
+ if (PSG->Regs[AY_ENABLE] & 0x04)
+ {
+ if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
+ PSG->OutputC = 1;
+ }
+ else if (PSG->Regs[AY_CVOL] == 0)
+ {
+ if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
+ }
+
+ /* for the noise channel we must not touch OutputN - it's also not necessary */
+ /* since we use outn. */
+ if ((PSG->Regs[AY_ENABLE] & 0x38) == 0x38) /* all off */
+ if (PSG->CountN <= length*STEP) PSG->CountN += length*STEP;
+
+ outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
+
+
+ /* buffering loop */
+ while (length)
+ {
+ int vola,volb,volc;
+ int left;
+
+
+ /* vola, volb and volc keep track of how long each square wave stays */
+ /* in the 1 position during the sample period. */
+ vola = volb = volc = 0;
+
+ left = STEP;
+ do
+ {
+ int nextevent;
+
+
+ if (PSG->CountN < left) nextevent = PSG->CountN;
+ else nextevent = left;
+
+ if (outn & 0x08)
+ {
+ if (PSG->OutputA) vola += PSG->CountA;
+ PSG->CountA -= nextevent;
+ /* PeriodA is the half period of the square wave. Here, in each */
+ /* loop I add PeriodA twice, so that at the end of the loop the */
+ /* square wave is in the same status (0 or 1) it was at the start. */
+ /* vola is also incremented by PeriodA, since the wave has been 1 */
+ /* exactly half of the time, regardless of the initial position. */
+ /* If we exit the loop in the middle, OutputA has to be inverted */
+ /* and vola incremented only if the exit status of the square */
+ /* wave is 1. */
+ while (PSG->CountA <= 0)
+ {
+ PSG->CountA += PSG->PeriodA;
+ if (PSG->CountA > 0)
+ {
+ PSG->OutputA ^= 1;
+ if (PSG->OutputA) vola += PSG->PeriodA;
+ break;
+ }
+ PSG->CountA += PSG->PeriodA;
+ vola += PSG->PeriodA;
+ }
+ if (PSG->OutputA) vola -= PSG->CountA;
+ }
+ else
+ {
+ PSG->CountA -= nextevent;
+ while (PSG->CountA <= 0)
+ {
+ PSG->CountA += PSG->PeriodA;
+ if (PSG->CountA > 0)
+ {
+ PSG->OutputA ^= 1;
+ break;
+ }
+ PSG->CountA += PSG->PeriodA;
+ }
+ }
+
+ if (outn & 0x10)
+ {
+ if (PSG->OutputB) volb += PSG->CountB;
+ PSG->CountB -= nextevent;
+ while (PSG->CountB <= 0)
+ {
+ PSG->CountB += PSG->PeriodB;
+ if (PSG->CountB > 0)
+ {
+ PSG->OutputB ^= 1;
+ if (PSG->OutputB) volb += PSG->PeriodB;
+ break;
+ }
+ PSG->CountB += PSG->PeriodB;
+ volb += PSG->PeriodB;
+ }
+ if (PSG->OutputB) volb -= PSG->CountB;
+ }
+ else
+ {
+ PSG->CountB -= nextevent;
+ while (PSG->CountB <= 0)
+ {
+ PSG->CountB += PSG->PeriodB;
+ if (PSG->CountB > 0)
+ {
+ PSG->OutputB ^= 1;
+ break;
+ }
+ PSG->CountB += PSG->PeriodB;
+ }
+ }
+
+ if (outn & 0x20)
+ {
+ if (PSG->OutputC) volc += PSG->CountC;
+ PSG->CountC -= nextevent;
+ while (PSG->CountC <= 0)
+ {
+ PSG->CountC += PSG->PeriodC;
+ if (PSG->CountC > 0)
+ {
+ PSG->OutputC ^= 1;
+ if (PSG->OutputC) volc += PSG->PeriodC;
+ break;
+ }
+ PSG->CountC += PSG->PeriodC;
+ volc += PSG->PeriodC;
+ }
+ if (PSG->OutputC) volc -= PSG->CountC;
+ }
+ else
+ {
+ PSG->CountC -= nextevent;
+ while (PSG->CountC <= 0)
+ {
+ PSG->CountC += PSG->PeriodC;
+ if (PSG->CountC > 0)
+ {
+ PSG->OutputC ^= 1;
+ break;
+ }
+ PSG->CountC += PSG->PeriodC;
+ }
+ }
+
+ PSG->CountN -= nextevent;
+ if (PSG->CountN <= 0)
+ {
+ /* Is noise output going to change? */
+ if ((PSG->RNG + 1) & 2) /* (bit0^bit1)? */
+ {
+ PSG->OutputN = ~PSG->OutputN;
+ outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
+ }
+
+ /* The Random Number Generator of the 8910 is a 17-bit shift */
+ /* register. The input to the shift register is bit0 XOR bit3 */
+ /* (bit0 is the output). This was verified on AY-3-8910 and YM2149 chips. */
+
+ /* The following is a fast way to compute bit17 = bit0^bit3. */
+ /* Instead of doing all the logic operations, we only check */
+ /* bit0, relying on the fact that after three shifts of the */
+ /* register, what now is bit3 will become bit0, and will */
+ /* invert, if necessary, bit14, which previously was bit17. */
+ if (PSG->RNG & 1) PSG->RNG ^= 0x24000; /* This version is called the "Galois configuration". */
+ PSG->RNG >>= 1;
+ PSG->CountN += PSG->PeriodN;
+ }
+
+ left -= nextevent;
+ } while (left > 0);
+
+ /* update envelope */
+ if (PSG->Holding == 0)
+ {
+ PSG->CountE -= STEP;
+ if (PSG->CountE <= 0)
+ {
+ do
+ {
+ PSG->CountEnv--;
+ PSG->CountE += PSG->PeriodE;
+ } while (PSG->CountE <= 0);
+
+ /* check envelope current position */
+ if (PSG->CountEnv < 0)
+ {
+ if (PSG->Hold)
+ {
+ if (PSG->Alternate)
+ PSG->Attack ^= 0x1f;
+ PSG->Holding = 1;
+ PSG->CountEnv = 0;
+ }
+ else
+ {
+ /* if CountEnv has looped an odd number of times (usually 1), */
+ /* invert the output. */
+ if (PSG->Alternate && (PSG->CountEnv & 0x20))
+ PSG->Attack ^= 0x1f;
+
+ PSG->CountEnv &= 0x1f;
+ }
+ }
+
+ PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack];
+ /* reload volume */
+ if (PSG->EnvelopeA) PSG->VolA = PSG->VolE;
+ if (PSG->EnvelopeB) PSG->VolB = PSG->VolE;
+ if (PSG->EnvelopeC) PSG->VolC = PSG->VolE;
+ }
+ }
+
+ if (PSG->streams == 3)
+ {
+ *(buf1++) = (vola * PSG->VolA) / STEP;
+ *(buf2++) = (volb * PSG->VolB) / STEP;
+ *(buf3++) = (volc * PSG->VolC) / STEP;
+ }
+ else
+ *(buf1++) = (vola * PSG->VolA + volb * PSG->VolB + volc * PSG->VolC) / STEP;
+
+ length--;
+ }
+}
+
+
+void AY8910_set_volume(int chip,int channel,int volume)
+{
+ struct AY8910 *PSG = sndti_token(SOUND_AY8910, chip);
+ int ch;
+
+ for (ch = 0; ch < PSG->streams; ch++)
+ if (channel == ch || PSG->streams == 1 || channel == ALL_8910_CHANNELS)
+ stream_set_output_gain(PSG->Channel, ch, volume / 100.0);
+}
+
+
+static void build_mixer_table(struct AY8910 *PSG)
+{
+ int i;
+ double out;
+
+
+ /* calculate the volume->voltage conversion table */
+ /* The AY-3-8910 has 16 levels, in a logarithmic scale (3dB per step) */
+ /* The YM2149 still has 16 levels for the tone generators, but 32 for */
+ /* the envelope generator (1.5dB per step). */
+ out = MAX_OUTPUT;
+ for (i = 31;i > 0;i--)
+ {
+ PSG->VolTable[i] = out + 0.5; /* round to nearest */
+
+ out /= 1.188502227; /* = 10 ^ (1.5/20) = 1.5dB */
+ }
+ PSG->VolTable[0] = 0;
+}
+
+
+
+static void AY8910_init(struct AY8910 *PSG, int streams,
+ int clock,int sample_rate,
+ read8_handler portAread,read8_handler portBread,
+ write8_handler portAwrite,write8_handler portBwrite)
+{
+ PSG->PortAread = portAread;
+ PSG->PortBread = portBread;
+ PSG->PortAwrite = portAwrite;
+ PSG->PortBwrite = portBwrite;
+
+ /* the step clock for the tone and noise generators is the chip clock */
+ /* divided by 8; for the envelope generator of the AY-3-8910, it is half */
+ /* that much (clock/16), but the envelope of the YM2149 goes twice as */
+ /* fast, therefore again clock/8. */
+ PSG->Channel = stream_create(0,streams,clock/8,PSG,AY8910Update);
+
+ ay8910_set_clock_ym(PSG,clock);
+}
+
+
+static void AY8910_statesave(struct AY8910 *PSG, int sndindex)
+{
+ state_save_register_item("AY8910", sndindex, PSG->register_latch);
+ state_save_register_item_array("AY8910", sndindex, PSG->Regs);
+ state_save_register_item("AY8910", sndindex, PSG->lastEnable);
+
+ state_save_register_item("AY8910", sndindex, PSG->PeriodA);
+ state_save_register_item("AY8910", sndindex, PSG->PeriodB);
+ state_save_register_item("AY8910", sndindex, PSG->PeriodC);
+ state_save_register_item("AY8910", sndindex, PSG->PeriodN);
+ state_save_register_item("AY8910", sndindex, PSG->PeriodE);
+
+ state_save_register_item("AY8910", sndindex, PSG->CountA);
+ state_save_register_item("AY8910", sndindex, PSG->CountB);
+ state_save_register_item("AY8910", sndindex, PSG->CountC);
+ state_save_register_item("AY8910", sndindex, PSG->CountN);
+ state_save_register_item("AY8910", sndindex, PSG->CountE);
+
+ state_save_register_item("AY8910", sndindex, PSG->VolA);
+ state_save_register_item("AY8910", sndindex, PSG->VolB);
+ state_save_register_item("AY8910", sndindex, PSG->VolC);
+ state_save_register_item("AY8910", sndindex, PSG->VolE);
+
+ state_save_register_item("AY8910", sndindex, PSG->EnvelopeA);
+ state_save_register_item("AY8910", sndindex, PSG->EnvelopeB);
+ state_save_register_item("AY8910", sndindex, PSG->EnvelopeC);
+
+ state_save_register_item("AY8910", sndindex, PSG->OutputA);
+ state_save_register_item("AY8910", sndindex, PSG->OutputB);
+ state_save_register_item("AY8910", sndindex, PSG->OutputC);
+ state_save_register_item("AY8910", sndindex, PSG->OutputN);
+
+ state_save_register_item("AY8910", sndindex, PSG->CountEnv);
+ state_save_register_item("AY8910", sndindex, PSG->Hold);
+ state_save_register_item("AY8910", sndindex, PSG->Alternate);
+ state_save_register_item("AY8910", sndindex, PSG->Attack);
+ state_save_register_item("AY8910", sndindex, PSG->Holding);
+ state_save_register_item("AY8910", sndindex, PSG->RNG);
+}
+
+
+void *ay8910_start_ym(sound_type chip_type, int sndindex, int clock, int streams,
+ read8_handler portAread, read8_handler portBread,
+ write8_handler portAwrite, write8_handler portBwrite)
+{
+ struct AY8910 *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+ info->index = sndindex;
+ info->streams = streams;
+
+ AY8910_init(info, streams, clock,
+ clock/8,
+ portAread,portBread,
+ portAwrite,portBwrite);
+
+ build_mixer_table(info);
+ AY8910_statesave(info, sndindex);
+
+ return info;
+}
+
+void ay8910_stop_ym(void *chip)
+{
+}
+
+void ay8910_reset_ym(void *chip)
+{
+ struct AY8910 *PSG = chip;
+ int i;
+
+ PSG->register_latch = 0;
+ PSG->RNG = 1;
+ PSG->OutputA = 0;
+ PSG->OutputB = 0;
+ PSG->OutputC = 0;
+ PSG->OutputN = 0xff;
+ PSG->lastEnable = -1; /* force a write */
+ for (i = 0;i < AY_PORTA;i++)
+ _AYWriteReg(PSG,i,0); /* AYWriteReg() uses the timer system; we cannot */
+ /* call it at this time because the timer system */
+ /* has not been initialized. */
+ PSG->ready = 1;
+}
+
+void ay8910_set_clock_ym(void *chip, int clock)
+{
+ struct AY8910 *PSG = chip;
+ stream_set_sample_rate(PSG->Channel, clock/8);
+}
+
+void ay8910_write_ym(void *chip, int addr, int data)
+{
+ struct AY8910 *PSG = chip;
+
+ if (addr & 1)
+ { /* Data port */
+ int r = PSG->register_latch;
+
+ if (r > 15) return;
+ if (r < 14)
+ {
+ if (r == AY_ESHAPE || PSG->Regs[r] != data)
+ {
+ /* update the output buffer before changing the register */
+ stream_update(PSG->Channel);
+ }
+ }
+
+ _AYWriteReg(PSG,r,data);
+ }
+ else
+ { /* Register port */
+ PSG->register_latch = data & 0x0f;
+ }
+}
+
+int ay8910_read_ym(void *chip)
+{
+ struct AY8910 *PSG = chip;
+ int r = PSG->register_latch;
+
+ if (r > 15) return 0;
+
+ switch (r)
+ {
+ case AY_PORTA:
+ if ((PSG->Regs[AY_ENABLE] & 0x40) != 0)
+ logerror("warning: read from 8910 #%d Port A set as output\n",PSG->index);
+ /*
+ even if the port is set as output, we still need to return the external
+ data. Some games, like kidniki, need this to work.
+ */
+ if (PSG->PortAread) PSG->Regs[AY_PORTA] = (*PSG->PortAread)(0);
+ else logerror("PC %04x: warning - read 8910 #%d Port A\n",activecpu_get_pc(),PSG->index);
+ break;
+ case AY_PORTB:
+ if ((PSG->Regs[AY_ENABLE] & 0x80) != 0)
+ logerror("warning: read from 8910 #%d Port B set as output\n",PSG->index);
+ if (PSG->PortBread) PSG->Regs[AY_PORTB] = (*PSG->PortBread)(0);
+ else logerror("PC %04x: warning - read 8910 #%d Port B\n",activecpu_get_pc(),PSG->index);
+ break;
+ }
+ return PSG->Regs[r];
+}
+
+
+
+static void *ay8910_start(int sndindex, int clock, const void *config)
+{
+ static const struct AY8910interface generic_ay8910 = { 0 };
+ const struct AY8910interface *intf = config ? config : &generic_ay8910;
+ return ay8910_start_ym(SOUND_AY8910, sndindex+16, clock, 3, intf->portAread, intf->portBread, intf->portAwrite, intf->portBwrite);
+}
+
+static void ay8910_stop(void *chip)
+{
+ ay8910_stop_ym(chip);
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ay8910_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ay8910_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case SNDINFO_INT_ALIAS: info->i = SOUND_AY8910; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ay8910_set_info; break;
+ case SNDINFO_PTR_START: info->start = ay8910_start; break;
+ case SNDINFO_PTR_STOP: info->stop = ay8910_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = ay8910_reset_ym; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "AY-3-8910A"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "PSG"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+void ay8912_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = ay8910_start; break;
+ case SNDINFO_STR_NAME: info->s = "AY-3-8912A"; break;
+ default: ay8910_get_info(token, state, info); break;
+ }
+}
+
+void ay8913_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = ay8910_start; break;
+ case SNDINFO_STR_NAME: info->s = "AY-3-8913A"; break;
+ default: ay8910_get_info(token, state, info); break;
+ }
+}
+
+void ay8930_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = ay8910_start; break;
+ case SNDINFO_STR_NAME: info->s = "AY8930"; break;
+ default: ay8910_get_info(token, state, info); break;
+ }
+}
+
+void ym2149_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = ay8910_start; break;
+ case SNDINFO_STR_NAME: info->s = "YM2149"; break;
+ default: ay8910_get_info(token, state, info); break;
+ }
+}
+
+void ym3439_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = ay8910_start; break;
+ case SNDINFO_STR_NAME: info->s = "YM3439"; break;
+ default: ay8910_get_info(token, state, info); break;
+ }
+}
+
+void ymz284_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = ay8910_start; break;
+ case SNDINFO_STR_NAME: info->s = "YMZ284"; break;
+ default: ay8910_get_info(token, state, info); break;
+ }
+}
+
+void ymz294_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = ay8910_start; break;
+ case SNDINFO_STR_NAME: info->s = "YMZ294"; break;
+ default: ay8910_get_info(token, state, info); break;
+ }
+}
diff --git a/src/emu/sound/ay8910.h b/src/emu/sound/ay8910.h
new file mode 100644
index 00000000000..e6b9fec4985
--- /dev/null
+++ b/src/emu/sound/ay8910.h
@@ -0,0 +1,90 @@
+#ifndef AY8910_H
+#define AY8910_H
+
+/*
+AY-3-8910A: 2 I/O ports
+AY-3-8912A: 1 I/O port
+AY-3-8913A: 0 I/O port
+AY8930: upper compatible with 8910.
+In extended mode, it has higher resolution and duty ratio setting
+YM2149: higher resolution
+YM3439: same as 2149
+YMZ284: 0 I/O port, different clock divider
+YMZ294: 0 I/O port
+*/
+
+
+#define ALL_8910_CHANNELS -1
+
+struct AY8910interface
+{
+ read8_handler portAread;
+ read8_handler portBread;
+ write8_handler portAwrite;
+ write8_handler portBwrite;
+};
+
+void AY8910_set_volume(int chip,int channel,int volume);
+
+
+READ8_HANDLER( AY8910_read_port_0_r );
+READ8_HANDLER( AY8910_read_port_1_r );
+READ8_HANDLER( AY8910_read_port_2_r );
+READ8_HANDLER( AY8910_read_port_3_r );
+READ8_HANDLER( AY8910_read_port_4_r );
+READ16_HANDLER( AY8910_read_port_0_lsb_r );
+READ16_HANDLER( AY8910_read_port_1_lsb_r );
+READ16_HANDLER( AY8910_read_port_2_lsb_r );
+READ16_HANDLER( AY8910_read_port_3_lsb_r );
+READ16_HANDLER( AY8910_read_port_4_lsb_r );
+READ16_HANDLER( AY8910_read_port_0_msb_r );
+READ16_HANDLER( AY8910_read_port_1_msb_r );
+READ16_HANDLER( AY8910_read_port_2_msb_r );
+READ16_HANDLER( AY8910_read_port_3_msb_r );
+READ16_HANDLER( AY8910_read_port_4_msb_r );
+
+WRITE8_HANDLER( AY8910_control_port_0_w );
+WRITE8_HANDLER( AY8910_control_port_1_w );
+WRITE8_HANDLER( AY8910_control_port_2_w );
+WRITE8_HANDLER( AY8910_control_port_3_w );
+WRITE8_HANDLER( AY8910_control_port_4_w );
+WRITE16_HANDLER( AY8910_control_port_0_lsb_w );
+WRITE16_HANDLER( AY8910_control_port_1_lsb_w );
+WRITE16_HANDLER( AY8910_control_port_2_lsb_w );
+WRITE16_HANDLER( AY8910_control_port_3_lsb_w );
+WRITE16_HANDLER( AY8910_control_port_4_lsb_w );
+WRITE16_HANDLER( AY8910_control_port_0_msb_w );
+WRITE16_HANDLER( AY8910_control_port_1_msb_w );
+WRITE16_HANDLER( AY8910_control_port_2_msb_w );
+WRITE16_HANDLER( AY8910_control_port_3_msb_w );
+WRITE16_HANDLER( AY8910_control_port_4_msb_w );
+
+WRITE8_HANDLER( AY8910_write_port_0_w );
+WRITE8_HANDLER( AY8910_write_port_1_w );
+WRITE8_HANDLER( AY8910_write_port_2_w );
+WRITE8_HANDLER( AY8910_write_port_3_w );
+WRITE8_HANDLER( AY8910_write_port_4_w );
+WRITE16_HANDLER( AY8910_write_port_0_lsb_w );
+WRITE16_HANDLER( AY8910_write_port_1_lsb_w );
+WRITE16_HANDLER( AY8910_write_port_2_lsb_w );
+WRITE16_HANDLER( AY8910_write_port_3_lsb_w );
+WRITE16_HANDLER( AY8910_write_port_4_lsb_w );
+WRITE16_HANDLER( AY8910_write_port_0_msb_w );
+WRITE16_HANDLER( AY8910_write_port_1_msb_w );
+WRITE16_HANDLER( AY8910_write_port_2_msb_w );
+WRITE16_HANDLER( AY8910_write_port_3_msb_w );
+WRITE16_HANDLER( AY8910_write_port_4_msb_w );
+
+/*********** An interface for SSG of YM2203 ***********/
+
+void *ay8910_start_ym(sound_type chip_type, int sndindex, int clock, int streams,
+ read8_handler portAread, read8_handler portBread,
+ write8_handler portAwrite, write8_handler portBwrite);
+
+void ay8910_stop_ym(void *chip);
+void ay8910_reset_ym(void *chip);
+void ay8910_set_clock_ym(void *chip, int clock);
+void ay8910_write_ym(void *chip, int addr, int data);
+int ay8910_read_ym(void *chip);
+
+#endif
diff --git a/src/emu/sound/beep.c b/src/emu/sound/beep.c
new file mode 100644
index 00000000000..1465c964eb8
--- /dev/null
+++ b/src/emu/sound/beep.c
@@ -0,0 +1,197 @@
+/***************************************************************************
+
+ beep.c
+
+ This is used for computers/systems which can only output a constant tone.
+ This tone can be turned on and off.
+ e.g. PCW and PCW16 computer systems
+ KT - 25-Jun-2000
+
+ Sound handler
+
+****************************************************************************/
+
+#include "sndintrf.h"
+#include "sound/beep.h"
+#include "streams.h"
+
+
+#define BEEP_RATE 48000
+
+
+struct beep_sound
+{
+ sound_stream *stream; /* stream number */
+ int enable; /* enable beep */
+ int frequency; /* set frequency - this can be changed using the appropiate function */
+ int incr; /* initial wave state */
+ INT16 signal; /* current signal */
+};
+
+
+
+/*************************************
+ *
+ * Stream updater
+ *
+ *************************************/
+
+static void beep_sound_update(void *param,stream_sample_t **inputs, stream_sample_t **_buffer,int length)
+{
+ struct beep_sound *bs = (struct beep_sound *) param;
+ stream_sample_t *buffer = _buffer[0];
+ INT16 signal = bs->signal;
+ int clock = 0, rate = BEEP_RATE / 2;
+
+ /* get progress through wave */
+ int incr = bs->incr;
+
+ if (bs->frequency > 0)
+ clock = bs->frequency;
+
+ /* if we're not enabled, just fill with 0 */
+ if ( !bs->enable || clock == 0 )
+ {
+ memset( buffer, 0, length * sizeof(*buffer) );
+ return;
+ }
+
+ /* fill in the sample */
+ while( length-- > 0 )
+ {
+ *buffer++ = signal;
+ incr -= clock;
+ while( incr < 0 )
+ {
+ incr += rate;
+ signal = -signal;
+ }
+ }
+
+ /* store progress through wave */
+ bs->incr = incr;
+ bs->signal = signal;
+}
+
+
+
+/*************************************
+ *
+ * Sound handler start
+ *
+ *************************************/
+
+static void *beep_start(int sndindex, int clock, const void *config)
+{
+ struct beep_sound *pBeep;
+
+ pBeep = auto_malloc(sizeof(*pBeep));
+ memset(pBeep, 0, sizeof(*pBeep));
+
+ pBeep->stream = stream_create(0, 1, BEEP_RATE, pBeep, beep_sound_update );
+ pBeep->enable = 0;
+ pBeep->frequency = 3250;
+ pBeep->incr = 0;
+ pBeep->signal = 0x07fff;
+ return pBeep;
+}
+
+
+
+/*************************************
+ *
+ * changing state to on from off will restart tone
+ *
+ *************************************/
+
+void beep_set_state( int num, int on )
+{
+ struct beep_sound *info = sndti_token(SOUND_BEEP, num);
+
+ /* only update if new state is not the same as old state */
+ if (info->enable == on)
+ return;
+
+ stream_update(info->stream);
+
+ info->enable = on;
+ /* restart wave from beginning */
+ info->incr = 0;
+ info->signal = 0x07fff;
+}
+
+
+
+/*************************************
+ *
+ * setting new frequency starts from beginning
+ *
+ *************************************/
+
+void beep_set_frequency(int num,int frequency)
+{
+ struct beep_sound *info = sndti_token(SOUND_BEEP, num);
+
+ if (info->frequency == frequency)
+ return;
+
+ stream_update(info->stream);
+ info->frequency = frequency;
+ info->signal = 0x07fff;
+ info->incr = 0;
+}
+
+
+
+/*************************************
+ *
+ * change a channel volume
+ *
+ *************************************/
+
+void beep_set_volume(int num, int volume)
+{
+ struct beep_sound *info = sndti_token(SOUND_BEEP, num);
+
+ stream_update(info->stream);
+
+ volume = 100 * volume / 7;
+
+ sndti_set_output_gain(SOUND_BEEP, num, 0, volume );
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void beep_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void beep_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = beep_set_info; break;
+ case SNDINFO_PTR_START: info->start = beep_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Beep"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Beep"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2005, The MESS Team"; break;
+ }
+}
diff --git a/src/emu/sound/beep.h b/src/emu/sound/beep.h
new file mode 100644
index 00000000000..5b6453483ad
--- /dev/null
+++ b/src/emu/sound/beep.h
@@ -0,0 +1,16 @@
+#ifndef BEEP_H
+#define BEEP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void beep_set_state(int,int);
+void beep_set_frequency(int,int);
+void beep_set_volume(int,int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/emu/sound/bsmt2000.c b/src/emu/sound/bsmt2000.c
new file mode 100644
index 00000000000..71cc6546fc5
--- /dev/null
+++ b/src/emu/sound/bsmt2000.c
@@ -0,0 +1,529 @@
+/***************************************************************************
+
+ bsmt2000.c
+
+ BSMT2000 sound emulator.
+
+ Copyright (c) Aaron Giles
+
+ Chip is actually a TMS320C15 DSP with embedded mask rom
+ Trivia: BSMT stands for "Brian Schmidt's Mouse Trap"
+
+***************************************************************************/
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "bsmt2000.h"
+
+
+/***************************************************************************
+ DEBUGGING/OPTIONS
+***************************************************************************/
+
+#define LOG_COMMANDS 0
+
+/* NOTE: the original chip did not support interpolation, but it sounds */
+/* nicer if you enable it. For accuracy's sake, we leave it off by default. */
+#define ENABLE_INTERPOLATION 0
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_VOICES (12+1)
+#define ADPCM_VOICE 12
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* struct describing a single playing voice */
+typedef struct _bsmt2000_voice bsmt2000_voice;
+struct _bsmt2000_voice
+{
+ UINT16 pos; /* current position */
+ UINT16 rate; /* stepping value */
+ UINT16 loopend; /* loop end value */
+ UINT16 loopstart; /* loop start value */
+ UINT16 bank; /* bank number */
+ UINT16 leftvol; /* left volume */
+ UINT16 rightvol; /* right volume */
+ UINT16 fraction; /* current fractional position */
+};
+
+typedef struct _bsmt2000_chip bsmt2000_chip;
+struct _bsmt2000_chip
+{
+ sound_stream *stream; /* which stream are we using */
+ UINT8 last_register; /* last register address written */
+
+ INT8 * region_base; /* pointer to the base of the region */
+ int total_banks; /* number of total banks in the region */
+
+ bsmt2000_voice voice[MAX_VOICES]; /* the voices */
+ UINT16 * regmap[128]; /* mapping of registers to voice params */
+
+ UINT32 clock; /* original clock on the chip */
+ UINT8 stereo; /* stereo output? */
+ UINT8 voices; /* number of voices */
+ UINT8 adpcm; /* adpcm enabled? */
+
+ INT32 adpcm_current; /* current ADPCM sample */
+ INT32 adpcm_delta_n; /* current ADPCM scale factor */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+const struct BSMT2000interface bsmt2000_interface_region_1 = { REGION_SOUND1 };
+const struct BSMT2000interface bsmt2000_interface_region_2 = { REGION_SOUND2 };
+const struct BSMT2000interface bsmt2000_interface_region_3 = { REGION_SOUND3 };
+const struct BSMT2000interface bsmt2000_interface_region_4 = { REGION_SOUND4 };
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* core implementation */
+static void *bsmt2000_start(int sndindex, int clock, const void *config);
+static void bsmt2000_reset(void *_chip);
+static void bsmt2000_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length);
+
+/* read/write access */
+static void bsmt2000_reg_write(bsmt2000_chip *chip, offs_t offset, UINT16 data);
+
+/* local functions */
+static void set_mode(bsmt2000_chip *chip);
+static void set_regmap(bsmt2000_chip *chip, UINT8 posbase, UINT8 ratebase, UINT8 endbase, UINT8 loopbase, UINT8 bankbase, UINT8 rvolbase, UINT8 lvolbase);
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ bsmt2000_start - initialization callback
+-------------------------------------------------*/
+
+static void *bsmt2000_start(int sndindex, int clock, const void *config)
+{
+ const struct BSMT2000interface *intf = config;
+ bsmt2000_chip *chip;
+ int voicenum;
+
+ /* allocate the chip */
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ /* create a stream at a nominal sample rate (real one specified later) */
+ chip->stream = stream_create(0, 2, clock / 1000, chip, bsmt2000_update);
+ chip->clock = clock;
+
+ /* initialize the regions */
+ chip->region_base = (INT8 *)memory_region(intf->region);
+ chip->total_banks = memory_region_length(intf->region) / 0x10000;
+
+ /* register chip-wide data for save states */
+ state_save_register_item("bsmt2000", sndindex * 16, chip->last_register);
+ state_save_register_item("bsmt2000", sndindex * 16, chip->stereo);
+ state_save_register_item("bsmt2000", sndindex * 16, chip->voices);
+ state_save_register_item("bsmt2000", sndindex * 16, chip->adpcm);
+ state_save_register_item("bsmt2000", sndindex * 16, chip->adpcm_current);
+ state_save_register_item("bsmt2000", sndindex * 16, chip->adpcm_delta_n);
+
+ /* register voice-specific data for save states */
+ for (voicenum = 0; voicenum < MAX_VOICES; voicenum++)
+ {
+ bsmt2000_voice *voice = &chip->voice[voicenum];
+ int index = sndindex * 16 + voicenum;
+
+ state_save_register_item("bsmt2000", index, voice->pos);
+ state_save_register_item("bsmt2000", index, voice->rate);
+ state_save_register_item("bsmt2000", index, voice->loopend);
+ state_save_register_item("bsmt2000", index, voice->loopstart);
+ state_save_register_item("bsmt2000", index, voice->bank);
+ state_save_register_item("bsmt2000", index, voice->leftvol);
+ state_save_register_item("bsmt2000", index, voice->rightvol);
+ state_save_register_item("bsmt2000", index, voice->fraction);
+ }
+
+ /* reset the chip -- this also configures the default mode */
+ bsmt2000_reset(chip);
+ return chip;
+}
+
+
+/*-------------------------------------------------
+ bsmt2000_reset - chip reset callback
+-------------------------------------------------*/
+
+static void bsmt2000_reset(void *_chip)
+{
+ bsmt2000_chip *chip = _chip;
+ int voicenum;
+
+ /* reset all the voice data */
+ for (voicenum = 0; voicenum < MAX_VOICES; voicenum++)
+ {
+ bsmt2000_voice *voice = &chip->voice[voicenum];
+ memset(voice, 0, sizeof(*voice));
+ voice->leftvol = 0x7fff;
+ voice->rightvol = 0x7fff;
+ }
+
+ /* recompute the mode */
+ set_mode(chip);
+}
+
+
+/*-------------------------------------------------
+ bsmt2000_update - update callback for
+ sample generation
+-------------------------------------------------*/
+
+static void bsmt2000_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ stream_sample_t *left = buffer[0];
+ stream_sample_t *right = buffer[1];
+ bsmt2000_chip *chip = param;
+ bsmt2000_voice *voice;
+ int samp, voicenum;
+
+ /* clear out the accumulator */
+ memset(left, 0, length * sizeof(left[0]));
+ memset(right, 0, length * sizeof(right[0]));
+
+ /* loop over voices */
+ for (voicenum = 0; voicenum < chip->voices; voicenum++)
+ {
+ voice = &chip->voice[voicenum];
+
+ /* compute the region base */
+ if (voice->bank < chip->total_banks)
+ {
+ INT8 *base = &chip->region_base[voice->bank * 0x10000];
+ UINT32 rate = voice->rate;
+ INT32 rvol = voice->rightvol;
+ INT32 lvol = chip->stereo ? voice->leftvol : rvol;
+ UINT16 pos = voice->pos;
+ UINT16 frac = voice->fraction;
+
+ /* loop while we still have samples to generate */
+ for (samp = 0; samp < length; samp++)
+ {
+#if ENABLE_INTERPOLATION
+ INT32 sample = (base[pos] * (0x800 - frac) + (base[pos + 1] * frac)) >> 11;
+#else
+ INT32 sample = base[pos];
+#endif
+ /* apply volumes and add */
+ left[samp] += sample * lvol;
+ right[samp] += sample * rvol;
+
+ /* update position */
+ frac += rate;
+ pos += frac >> 11;
+ frac &= 0x7ff;
+
+ /* check for loop end */
+ if (pos >= voice->loopend)
+ pos += voice->loopstart - voice->loopend;
+ }
+
+ /* update the position */
+ voice->pos = pos;
+ voice->fraction = frac;
+ }
+ }
+
+ /* compressed voice (11-voice model only) */
+ voice = &chip->voice[ADPCM_VOICE];
+ if (chip->adpcm && voice->bank < chip->total_banks && voice->rate)
+ {
+ INT8 *base = &chip->region_base[voice->bank * 0x10000];
+ INT32 rvol = voice->rightvol;
+ INT32 lvol = chip->stereo ? voice->leftvol : rvol;
+ UINT32 pos = voice->pos;
+ UINT32 frac = voice->fraction;
+
+ /* loop while we still have samples to generate */
+ for (samp = 0; samp < length && pos < voice->loopend; samp++)
+ {
+ /* apply volumes and add */
+ left[samp] += (chip->adpcm_current * lvol) >> 8;
+ right[samp] += (chip->adpcm_current * rvol) >> 8;
+
+ /* update position */
+ frac++;
+ if (frac == 6)
+ {
+ pos++;
+ frac = 0;
+ }
+
+ /* every 3 samples, we update the ADPCM state */
+ if (frac == 1 || frac == 4)
+ {
+ static const UINT8 delta_tab[] = { 58,58,58,58,77,102,128,154 };
+ int nibble = base[pos] >> ((frac == 1) ? 4 : 0);
+ int value = (INT8)(nibble << 4) >> 4;
+ int delta;
+
+ /* compute the delta for this sample */
+ delta = chip->adpcm_delta_n * value;
+ if (value > 0)
+ delta += chip->adpcm_delta_n >> 1;
+ else
+ delta -= chip->adpcm_delta_n >> 1;
+
+ /* add and clamp against the sample */
+ chip->adpcm_current += delta;
+ if (chip->adpcm_current >= 32767)
+ chip->adpcm_current = 32767;
+ else if (chip->adpcm_current <= -32768)
+ chip->adpcm_current = -32768;
+
+ /* adjust the delta multiplier */
+ chip->adpcm_delta_n = (chip->adpcm_delta_n * delta_tab[abs(value)]) >> 6;
+ if (chip->adpcm_delta_n > 2000)
+ chip->adpcm_delta_n = 2000;
+ else if (chip->adpcm_delta_n < 1)
+ chip->adpcm_delta_n = 1;
+ }
+ }
+
+ /* update the position */
+ voice->pos = pos;
+ voice->fraction = frac;
+
+ /* "rate" is a control register; clear it to 0 when done */
+ if (pos >= voice->loopend)
+ voice->rate = 0;
+ }
+
+ /* reduce the overall gain */
+ for (samp = 0; samp < length; samp++)
+ {
+ left[samp] >>= 9;
+ right[samp] >>= 9;
+ }
+}
+
+
+
+/***************************************************************************
+ READ/WRITE ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ bsmt2000_reg_write - handle a register write
+-------------------------------------------------*/
+
+static void bsmt2000_reg_write(bsmt2000_chip *chip, offs_t offset, UINT16 data)
+{
+#if LOG_COMMANDS
+ mame_printf_debug("BSMT write: reg %02X = %04X\n", offset, data);
+#endif
+
+ /* remember the last write */
+ chip->last_register = offset;
+
+ /* update the register */
+ if (offset < 0x80 && chip->regmap[offset] != NULL)
+ {
+ UINT16 *dest = chip->regmap[offset];
+
+ /* force an update, then write the data */
+ stream_update(chip->stream);
+ *dest = data;
+
+ /* special case: reset ADPCM parameters when writing to the ADPCM position */
+ if (dest == &chip->voice[ADPCM_VOICE].rate)
+ {
+ chip->adpcm_current = 0;
+ chip->adpcm_delta_n = 10;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ PER-CHIP READ/WRITE HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ BSMT2000_data_0_w - write to chip 0
+-------------------------------------------------*/
+
+WRITE16_HANDLER( BSMT2000_data_0_w )
+{
+ bsmt2000_reg_write(sndti_token(SOUND_BSMT2000, 0), offset, data);
+}
+
+
+
+/***************************************************************************
+ LOCAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ set_mode - set the mode after reset
+-------------------------------------------------*/
+
+static void set_mode(bsmt2000_chip *chip)
+{
+ int sample_rate;
+
+ /* force an update */
+ stream_update(chip->stream);
+
+ /* the mode comes from the address of the last register accessed */
+ switch (chip->last_register)
+ {
+ /* mode 0: 24kHz, 12 channel PCM, 1 channel ADPCM, mono */
+ default:
+ case 0:
+ sample_rate = chip->clock / 1000;
+ chip->stereo = FALSE;
+ chip->voices = 12;
+ chip->adpcm = TRUE;
+ set_regmap(chip, 0x00, 0x18, 0x24, 0x30, 0x3c, 0x48, 0);
+ break;
+
+ /* mode 1: 24kHz, 11 channel PCM, 1 channel ADPCM, stereo */
+ case 1:
+ sample_rate = chip->clock / 1000;
+ chip->stereo = TRUE;
+ chip->voices = 11;
+ chip->adpcm = TRUE;
+ set_regmap(chip, 0x00, 0x16, 0x21, 0x2c, 0x37, 0x42, 0x4d);
+ break;
+
+ /* mode 5: 24kHz, 12 channel PCM, stereo */
+ case 5:
+ sample_rate = chip->clock / 1000;
+ chip->stereo = TRUE;
+ chip->voices = 12;
+ chip->adpcm = FALSE;
+ set_regmap(chip, 0x00, 0x18, 0x24, 0x30, 0x3c, 0x54, 0x60);
+ break;
+
+ /* mode 6: 34kHz, 8 channel PCM, stereo */
+ case 6:
+ sample_rate = chip->clock / 706;
+ chip->stereo = TRUE;
+ chip->voices = 8;
+ chip->adpcm = FALSE;
+ set_regmap(chip, 0x00, 0x10, 0x18, 0x20, 0x28, 0x38, 0x40);
+ break;
+
+ /* mode 7: 32kHz, 9 channel PCM, stereo */
+ case 7:
+ sample_rate = chip->clock / 750;
+ chip->stereo = TRUE;
+ chip->voices = 9;
+ chip->adpcm = FALSE;
+ set_regmap(chip, 0x00, 0x12, 0x1b, 0x24, 0x2d, 0x3f, 0x48);
+ break;
+ }
+
+ /* update the sample rate */
+ stream_set_sample_rate(chip->stream, sample_rate);
+}
+
+
+/*-------------------------------------------------
+ set_regmap - initialize the register mapping
+-------------------------------------------------*/
+
+static void set_regmap(bsmt2000_chip *chip, UINT8 posbase, UINT8 ratebase, UINT8 endbase, UINT8 loopbase, UINT8 bankbase, UINT8 rvolbase, UINT8 lvolbase)
+{
+ int voice;
+
+ /* reset the map */
+ memset(chip->regmap, 0, sizeof(chip->regmap));
+
+ /* iterate over voices */
+ for (voice = 0; voice < chip->voices; voice++)
+ {
+ chip->regmap[posbase + voice] = &chip->voice[voice].pos;
+ chip->regmap[ratebase + voice] = &chip->voice[voice].rate;
+ chip->regmap[endbase + voice] = &chip->voice[voice].loopend;
+ chip->regmap[loopbase + voice] = &chip->voice[voice].loopstart;
+ chip->regmap[bankbase + voice] = &chip->voice[voice].bank;
+ chip->regmap[rvolbase + voice] = &chip->voice[voice].rightvol;
+ if (chip->stereo)
+ chip->regmap[lvolbase + voice] = &chip->voice[voice].leftvol;
+ }
+
+ /* set the ADPCM register */
+ if (chip->adpcm)
+ {
+ chip->regmap[0x6d] = &chip->voice[ADPCM_VOICE].loopend;
+ chip->regmap[0x6f] = &chip->voice[ADPCM_VOICE].bank;
+ chip->regmap[0x73] = &chip->voice[ADPCM_VOICE].rate;
+ chip->regmap[0x74] = &chip->voice[ADPCM_VOICE].rightvol;
+ chip->regmap[0x75] = &chip->voice[ADPCM_VOICE].pos;
+ if (chip->stereo)
+ chip->regmap[0x76] = &chip->voice[ADPCM_VOICE].leftvol;
+ }
+}
+
+
+
+/***************************************************************************
+ GET/SET INFO CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ bsmt2000_set_info - callback for setting chip
+ information
+-------------------------------------------------*/
+
+static void bsmt2000_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+/*-------------------------------------------------
+ bsmt2000_get_info - callback for retrieving
+ chip information
+-------------------------------------------------*/
+
+void bsmt2000_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = bsmt2000_set_info; break;
+ case SNDINFO_PTR_START: info->start = bsmt2000_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = bsmt2000_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "BSMT2000"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Data East Wavetable"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/bsmt2000.h b/src/emu/sound/bsmt2000.h
new file mode 100644
index 00000000000..911848b7979
--- /dev/null
+++ b/src/emu/sound/bsmt2000.h
@@ -0,0 +1,23 @@
+/**********************************************************************************************
+ *
+ * BSMT2000 driver
+ * by Aaron Giles
+ *
+ **********************************************************************************************/
+
+#ifndef BSMT2000_H
+#define BSMT2000_H
+
+struct BSMT2000interface
+{
+ int region; /* memory region where the sample ROM lives */
+};
+
+WRITE16_HANDLER( BSMT2000_data_0_w );
+
+extern const struct BSMT2000interface bsmt2000_interface_region_1;
+extern const struct BSMT2000interface bsmt2000_interface_region_2;
+extern const struct BSMT2000interface bsmt2000_interface_region_3;
+extern const struct BSMT2000interface bsmt2000_interface_region_4;
+
+#endif
diff --git a/src/emu/sound/c140.c b/src/emu/sound/c140.c
new file mode 100644
index 00000000000..180a34b2bab
--- /dev/null
+++ b/src/emu/sound/c140.c
@@ -0,0 +1,520 @@
+/*
+C140.c
+
+Simulator based on AMUSE sources.
+The C140 sound chip is used by Namco System 2 and System 21
+The 219 ASIC (which incorporates a modified C140) is used by Namco NA-1 and NA-2
+This chip controls 24 channels (C140) or 16 (219) of PCM.
+16 bytes are associated with each channel.
+Channels can be 8 bit signed PCM, or 12 bit signed PCM.
+
+Timer behavior is not yet handled.
+
+Unmapped registers:
+ 0x1f8:timer interval? (Nx0.1 ms)
+ 0x1fa:irq ack? timer restart?
+ 0x1fe:timer switch?(0:off 1:on)
+
+--------------
+
+ ASIC "219" notes
+
+ On the 219 ASIC used on NA-1 and NA-2, the high registers have the following
+ meaning instead:
+ 0x1f7: bank for voices 0-3
+ 0x1f1: bank for voices 4-7
+ 0x1f3: bank for voices 8-11
+ 0x1f5: bank for voices 12-15
+
+ Some games (bkrtmaq, xday2) write to 0x1fd for voices 12-15 instead. Probably the bank registers
+ mirror at 1f8, in which case 1ff is also 0-3, 1f9 is also 4-7, 1fb is also 8-11, and 1fd is also 12-15.
+
+ Each bank is 0x20000 (128k), and the voice addresses on the 219 are all multiplied by 2.
+ Additionally, the 219's base pitch is the same as the C352's (42667). But these changes
+ are IMO not sufficient to make this a separate file - all the other registers are
+ fully compatible.
+
+ Finally, the 219 only has 16 voices.
+*/
+/*
+ 2000.06.26 CAB fixed compressed pcm playback
+ 2002.07.20 R.Belmont added support for multiple banking types
+ 2006.01.08 R.Belmont added support for NA-1/2 "219" derivative
+*/
+
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "c140.h"
+
+#define MAX_VOICE 24
+
+struct voice_registers
+{
+ UINT8 volume_right;
+ UINT8 volume_left;
+ UINT8 frequency_msb;
+ UINT8 frequency_lsb;
+ UINT8 bank;
+ UINT8 mode;
+ UINT8 start_msb;
+ UINT8 start_lsb;
+ UINT8 end_msb;
+ UINT8 end_lsb;
+ UINT8 loop_msb;
+ UINT8 loop_lsb;
+ UINT8 reserved[4];
+};
+
+typedef struct
+{
+ long ptoffset;
+ long pos;
+ long key;
+ //--work
+ long lastdt;
+ long prevdt;
+ long dltdt;
+ //--reg
+ long rvol;
+ long lvol;
+ long frequency;
+ long bank;
+ long mode;
+
+ long sample_start;
+ long sample_end;
+ long sample_loop;
+} VOICE;
+
+struct c140_info
+{
+ int sample_rate;
+ sound_stream *stream;
+ int banking_type;
+ /* internal buffers */
+ INT16 *mixer_buffer_left;
+ INT16 *mixer_buffer_right;
+
+ int baserate;
+ void *pRom;
+ UINT8 REG[0x200];
+
+ INT16 pcmtbl[8]; //2000.06.26 CAB
+
+ VOICE voi[MAX_VOICE];
+};
+
+static void init_voice( VOICE *v )
+{
+ v->key=0;
+ v->ptoffset=0;
+ v->rvol=0;
+ v->lvol=0;
+ v->frequency=0;
+ v->bank=0;
+ v->mode=0;
+ v->sample_start=0;
+ v->sample_end=0;
+ v->sample_loop=0;
+}
+READ8_HANDLER( C140_r )
+{
+ struct c140_info *info = sndti_token(SOUND_C140, 0);
+ offset&=0x1ff;
+ return info->REG[offset];
+}
+
+/*
+ find_sample: compute the actual address of a sample given it's
+ address and banking registers, as well as the board type.
+
+ I suspect in "real life" this works like the Sega MultiPCM where the banking
+ is done by a small PAL or GAL external to the sound chip, which can be switched
+ per-game or at least per-PCB revision as addressing range needs grow.
+ */
+static long find_sample(struct c140_info *info, long adrs, long bank, int voice)
+{
+ long newadr = 0;
+
+ static INT16 asic219banks[4] = { 0x1f7, 0x1f1, 0x1f3, 0x1f5 };
+
+ adrs=(bank<<16)+adrs;
+
+ switch (info->banking_type)
+ {
+ case C140_TYPE_SYSTEM2:
+ // System 2 banking
+ newadr = ((adrs&0x200000)>>2)|(adrs&0x7ffff);
+ break;
+
+ case C140_TYPE_SYSTEM21_A:
+ // System 21 type A (simple) banking.
+ // similar to System 2's.
+ newadr = ((adrs&0x300000)>>1)+(adrs&0x7ffff);
+ break;
+
+ case C140_TYPE_SYSTEM21_B:
+ // System 21 type B (chip select) banking
+
+ // get base address of sample inside the bank
+ newadr = ((adrs&0x100000)>>2) + (adrs&0x3ffff);
+
+ // now add the starting bank offsets based on the 2
+ // chip select bits.
+ // 0x40000 picks individual 512k ROMs
+ if (adrs & 0x40000)
+ {
+ newadr += 0x80000;
+ }
+
+ // and 0x200000 which group of chips...
+ if (adrs & 0x200000)
+ {
+ newadr += 0x100000;
+ }
+ break;
+
+ case C140_TYPE_ASIC219:
+ // ASIC219's banking is fairly simple
+ newadr = ((info->REG[asic219banks[voice/4]]&0x3) * 0x20000) + adrs;
+ break;
+ }
+
+ return (newadr);
+}
+WRITE8_HANDLER( C140_w )
+{
+ struct c140_info *info = sndti_token(SOUND_C140, 0);
+ stream_update(info->stream);
+
+ offset&=0x1ff;
+
+ // mirror the bank registers on the 219, fixes bkrtmaq (and probably xday2 based on notes in the HLE)
+ if ((offset >= 0x1f8) && (info->banking_type == C140_TYPE_ASIC219))
+ {
+ offset -= 8;
+ }
+
+ info->REG[offset]=data;
+ if( offset<0x180 )
+ {
+ VOICE *v = &info->voi[offset>>4];
+
+ if( (offset&0xf)==0x5 )
+ {
+ if( data&0x80 )
+ {
+ const struct voice_registers *vreg = (struct voice_registers *) &info->REG[offset&0x1f0];
+ v->key=1;
+ v->ptoffset=0;
+ v->pos=0;
+ v->lastdt=0;
+ v->prevdt=0;
+ v->dltdt=0;
+ v->bank = vreg->bank;
+ v->mode = data;
+
+ // on the 219 asic, addresses are in words
+ if (info->banking_type == C140_TYPE_ASIC219)
+ {
+ v->sample_loop = (vreg->loop_msb*256 + vreg->loop_lsb)*2;
+ v->sample_start = (vreg->start_msb*256 + vreg->start_lsb)*2;
+ v->sample_end = (vreg->end_msb*256 + vreg->end_lsb)*2;
+
+ #if 0
+ logerror("219: play v %d mode %02x start %x loop %x end %x\n",
+ offset>>4, v->mode,
+ find_sample(info, v->sample_start, v->bank, offset>>4),
+ find_sample(info, v->sample_loop, v->bank, offset>>4),
+ find_sample(info, v->sample_end, v->bank, offset>>4));
+ #endif
+ }
+ else
+ {
+ v->sample_loop = vreg->loop_msb*256 + vreg->loop_lsb;
+ v->sample_start = vreg->start_msb*256 + vreg->start_lsb;
+ v->sample_end = vreg->end_msb*256 + vreg->end_lsb;
+ }
+ }
+ else
+ {
+ v->key=0;
+ }
+ }
+ }
+}
+
+void C140_set_base(int which, void *base)
+{
+ struct c140_info *info = sndti_token(SOUND_C140, 0);
+ info->pRom = base;
+}
+
+INLINE int limit(INT32 in)
+{
+ if(in>0x7fff) return 0x7fff;
+ else if(in<-0x8000) return -0x8000;
+ return in;
+}
+
+static void update_stereo(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct c140_info *info = param;
+ int i,j;
+
+ INT32 rvol,lvol;
+ INT32 dt;
+ INT32 sdt;
+ INT32 st,ed,sz;
+
+ INT8 *pSampleData;
+ INT32 frequency,delta,offset,pos;
+ INT32 cnt, voicecnt;
+ INT32 lastdt,prevdt,dltdt;
+ float pbase=(float)info->baserate*2.0 / (float)info->sample_rate;
+
+ INT16 *lmix, *rmix;
+
+ if(length>info->sample_rate) length=info->sample_rate;
+
+ /* zap the contents of the mixer buffer */
+ memset(info->mixer_buffer_left, 0, length * sizeof(INT16));
+ memset(info->mixer_buffer_right, 0, length * sizeof(INT16));
+
+ /* get the number of voices to update */
+ voicecnt = (info->banking_type == C140_TYPE_ASIC219) ? 16 : 24;
+
+ //--- audio update
+ for( i=0;i<voicecnt;i++ )
+ {
+ VOICE *v = &info->voi[i];
+ const struct voice_registers *vreg = (struct voice_registers *)&info->REG[i*16];
+
+ if( v->key )
+ {
+ frequency= vreg->frequency_msb*256 + vreg->frequency_lsb;
+
+ /* Abort voice if no frequency value set */
+ if(frequency==0) continue;
+
+ /* Delta = frequency * ((8MHz/374)*2 / sample rate) */
+ delta=(long)((float)frequency * pbase);
+
+ /* Calculate left/right channel volumes */
+ lvol=(vreg->volume_left*32)/MAX_VOICE; //32ch -> 24ch
+ rvol=(vreg->volume_right*32)/MAX_VOICE;
+
+ /* Set mixer buffer base pointers */
+ lmix = info->mixer_buffer_left;
+ rmix = info->mixer_buffer_right;
+
+ /* Retrieve sample start/end and calculate size */
+ st=v->sample_start;
+ ed=v->sample_end;
+ sz=ed-st;
+
+ /* Retrieve base pointer to the sample data */
+ pSampleData=(signed char*)((FPTR)info->pRom + find_sample(info, st, v->bank, i));
+
+ /* Fetch back previous data pointers */
+ offset=v->ptoffset;
+ pos=v->pos;
+ lastdt=v->lastdt;
+ prevdt=v->prevdt;
+ dltdt=v->dltdt;
+
+ /* Switch on data type - compressed PCM is only for C140 */
+ if ((v->mode&8) && (info->banking_type != C140_TYPE_ASIC219))
+ {
+ //compressed PCM (maybe correct...)
+ /* Loop for enough to fill sample buffer as requested */
+ for(j=0;j<length;j++)
+ {
+ offset += delta;
+ cnt = (offset>>16)&0x7fff;
+ offset &= 0xffff;
+ pos+=cnt;
+ //for(;cnt>0;cnt--)
+ {
+ /* Check for the end of the sample */
+ if(pos >= sz)
+ {
+ /* Check if its a looping sample, either stop or loop */
+ if(v->mode&0x10)
+ {
+ pos = (v->sample_loop - st);
+ }
+ else
+ {
+ v->key=0;
+ break;
+ }
+ }
+
+ /* Read the chosen sample byte */
+ dt=pSampleData[pos];
+
+ /* decompress to 13bit range */ //2000.06.26 CAB
+ sdt=dt>>3; //signed
+ if(sdt<0) sdt = (sdt<<(dt&7)) - info->pcmtbl[dt&7];
+ else sdt = (sdt<<(dt&7)) + info->pcmtbl[dt&7];
+
+ prevdt=lastdt;
+ lastdt=sdt;
+ dltdt=(lastdt - prevdt);
+ }
+
+ /* Caclulate the sample value */
+ dt=((dltdt*offset)>>16)+prevdt;
+
+ /* Write the data to the sample buffers */
+ *lmix++ +=(dt*lvol)>>(5+5);
+ *rmix++ +=(dt*rvol)>>(5+5);
+ }
+ }
+ else
+ {
+ /* linear 8bit signed PCM */
+ for(j=0;j<length;j++)
+ {
+ offset += delta;
+ cnt = (offset>>16)&0x7fff;
+ offset &= 0xffff;
+ pos += cnt;
+ /* Check for the end of the sample */
+ if(pos >= sz)
+ {
+ /* Check if its a looping sample, either stop or loop */
+ if( v->mode&0x10 )
+ {
+ pos = (v->sample_loop - st);
+ }
+ else
+ {
+ v->key=0;
+ break;
+ }
+ }
+
+ if( cnt )
+ {
+ prevdt=lastdt;
+ lastdt=pSampleData[pos];
+ if ((v->mode & 0x40) && (info->banking_type == C140_TYPE_ASIC219))
+ {
+ lastdt ^= 0x80; // flip signedness
+ }
+ dltdt=(lastdt - prevdt);
+ }
+
+ /* Caclulate the sample value */
+ dt=((dltdt*offset)>>16)+prevdt;
+
+ /* Write the data to the sample buffers */
+ *lmix++ +=(dt*lvol)>>5;
+ *rmix++ +=(dt*rvol)>>5;
+ }
+ }
+
+ /* Save positional data for next callback */
+ v->ptoffset=offset;
+ v->pos=pos;
+ v->lastdt=lastdt;
+ v->prevdt=prevdt;
+ v->dltdt=dltdt;
+ }
+ }
+
+ /* render to MAME's stream buffer */
+ lmix = info->mixer_buffer_left;
+ rmix = info->mixer_buffer_right;
+ {
+ stream_sample_t *dest1 = buffer[0];
+ stream_sample_t *dest2 = buffer[1];
+ for (i = 0; i < length; i++)
+ {
+ *dest1++ = limit(8*(*lmix++));
+ *dest2++ = limit(8*(*rmix++));
+ }
+ }
+}
+
+static void *c140_start(int sndindex, int clock, const void *config)
+{
+ const struct C140interface *intf = config;
+ struct c140_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->sample_rate=info->baserate=clock;
+
+ info->banking_type = intf->banking_type;
+
+ info->stream = stream_create(0,2,info->sample_rate,info,update_stereo);
+
+ if (intf->region)
+ info->pRom=memory_region(intf->region);
+
+ /* make decompress pcm table */ //2000.06.26 CAB
+ {
+ int i;
+ INT32 segbase=0;
+ for(i=0;i<8;i++)
+ {
+ info->pcmtbl[i]=segbase; //segment base value
+ segbase += 16<<i;
+ }
+ }
+
+ memset(info->REG,0,0x200 );
+ {
+ int i;
+ for(i=0;i<MAX_VOICE;i++) init_voice( &info->voi[i] );
+ }
+
+ /* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */
+ info->mixer_buffer_left = auto_malloc(2 * sizeof(INT16)*info->sample_rate );
+ info->mixer_buffer_right = info->mixer_buffer_left + info->sample_rate;
+ return info;
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void c140_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void c140_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = c140_set_info; break;
+ case SNDINFO_PTR_START: info->start = c140_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "C140"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Namco PCM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/c140.h b/src/emu/sound/c140.h
new file mode 100644
index 00000000000..bcd0862874f
--- /dev/null
+++ b/src/emu/sound/c140.h
@@ -0,0 +1,24 @@
+/* C140.h */
+
+#ifndef _NAMCO_C140_
+#define _NAMCO_C140_
+
+READ8_HANDLER( C140_r );
+WRITE8_HANDLER( C140_w );
+
+void C140_set_base(int which, void *base);
+
+enum
+{
+ C140_TYPE_SYSTEM2,
+ C140_TYPE_SYSTEM21_A,
+ C140_TYPE_SYSTEM21_B,
+ C140_TYPE_ASIC219
+};
+
+struct C140interface {
+ int banking_type;
+ int region;
+};
+
+#endif
diff --git a/src/emu/sound/c352.c b/src/emu/sound/c352.c
new file mode 100644
index 00000000000..572fd4db3ff
--- /dev/null
+++ b/src/emu/sound/c352.c
@@ -0,0 +1,643 @@
+/*
+ c352.c - Namco C352 custom PCM chip emulation
+ v1.1
+ By R. Belmont
+ Additional code by cync and the hoot development team
+
+ Thanks to Cap of VivaNonno for info and The_Author for preliminary reverse-engineering
+
+ Chip specs:
+ 32 voices
+ Supports 8-bit linear and 8-bit muLaw samples
+ Output: digital, 16 bit, 4 channels
+ Output sample rate is the input clock / 384.
+ */
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "c352.h"
+
+#define VERBOSE (0)
+
+// flags
+
+enum {
+ C352_FLG_BUSY = 0x8000, // channel is busy
+ C352_FLG_KEYON = 0x4000, // Keyon
+ C352_FLG_KEYOFF = 0x2000, // Keyoff
+ C352_FLG_LOOPTRG = 0x1000, // Loop Trigger
+ C352_FLG_LOOPHIST = 0x0800, // Loop History
+ C352_FLG_FM = 0x0400, // Frequency Modulation
+ C352_FLG_PHASERL = 0x0200, // Rear Left invert phase 180 degrees
+ C352_FLG_PHASEFL = 0x0100, // Front Left invert phase 180 degrees
+ C352_FLG_PHASEFR = 0x0080, // invert phase 180 degrees (e.g. flip sign of sample)
+ C352_FLG_LDIR = 0x0040, // loop direction
+ C352_FLG_LINK = 0x0020, // "long-format" sample (can't loop, not sure what else it means)
+ C352_FLG_NOISE = 0x0010, // play noise instead of sample
+ C352_FLG_MULAW = 0x0008, // sample is mulaw instead of linear 8-bit PCM
+ C352_FLG_FILTER = 0x0004, // don't apply filter
+ C352_FLG_REVLOOP = 0x0003, // loop backwards
+ C352_FLG_LOOP = 0x0002, // loop forward
+ C352_FLG_REVERSE = 0x0001, // play sample backwards
+};
+
+typedef struct
+{
+ UINT8 vol_l;
+ UINT8 vol_r;
+ UINT8 vol_l2;
+ UINT8 vol_r2;
+ UINT8 bank;
+ INT16 noise;
+ INT16 noisebuf;
+ UINT16 noisecnt;
+ UINT16 pitch;
+ UINT16 start_addr;
+ UINT16 end_addr;
+ UINT16 repeat_addr;
+ UINT32 flag;
+
+ UINT16 start;
+ UINT16 repeat;
+ UINT32 current_addr;
+ UINT32 pos;
+} c352_ch_t;
+
+struct c352_info
+{
+ sound_stream *stream;
+ c352_ch_t c352_ch[32];
+ unsigned char *c352_rom_samples;
+ int c352_region;
+ int sample_rate_base;
+
+ INT16 level_table[256];
+
+ long channel_l[2048*2];
+ long channel_r[2048*2];
+ long channel_l2[2048*2];
+ long channel_r2[2048*2];
+
+ short mulaw_table[256];
+ unsigned int mseq_reg;
+};
+
+// noise generator
+static int get_mseq_bit(struct c352_info *info)
+{
+ unsigned int mask = (1 << (7 - 1));
+ unsigned int reg = info->mseq_reg;
+ unsigned int bit = reg & (1 << (17 - 1));
+
+ if (bit)
+ {
+ reg = ((reg ^ mask) << 1) | 1;
+ }
+ else
+ {
+ reg = reg << 1;
+ }
+
+ info->mseq_reg = reg;
+
+ return (reg & 1);
+}
+
+static void c352_mix_one_channel(struct c352_info *info, unsigned long ch, long sample_count)
+{
+ int i;
+
+ signed short sample, nextsample;
+ signed short noisebuf;
+ UINT16 noisecnt;
+ INT32 frequency, delta, offset, cnt, flag;
+ UINT32 bank;
+ UINT32 pos;
+
+ frequency = info->c352_ch[ch].pitch;
+ delta=frequency;
+
+ pos = info->c352_ch[ch].current_addr; // sample pointer
+ offset = info->c352_ch[ch].pos; // 16.16 fixed-point offset into the sample
+ flag = info->c352_ch[ch].flag;
+ bank = info->c352_ch[ch].bank << 16;
+
+ noisecnt = info->c352_ch[ch].noisecnt;
+ noisebuf = info->c352_ch[ch].noisebuf;
+
+ for(i = 0 ; (i < sample_count) && (flag & C352_FLG_BUSY) ; i++)
+ {
+ offset += delta;
+ cnt = (offset>>16)&0x7fff;
+ if (cnt) // if there is a whole sample part, chop it off now that it's been applied
+ {
+ offset &= 0xffff;
+ }
+
+ if (pos > (UINT32)memory_region_length(info->c352_region))
+ {
+ info->c352_ch[ch].flag &= ~C352_FLG_BUSY;
+ return;
+ }
+
+ sample = (char)info->c352_rom_samples[pos];
+ nextsample = (char)info->c352_rom_samples[pos+cnt];
+
+ // sample is muLaw, not 8-bit linear (Fighting Layer uses this extensively)
+ if (flag & C352_FLG_MULAW)
+ {
+ sample = info->mulaw_table[(unsigned char)sample];
+ nextsample = info->mulaw_table[(unsigned char)nextsample];
+ }
+ else
+ {
+ sample <<= 8;
+ nextsample <<= 8;
+ }
+
+ // play noise instead of sample data
+ if (flag & C352_FLG_NOISE)
+ {
+ int noise_level = 0x8000;
+ sample = info->c352_ch[ch].noise = (info->c352_ch[ch].noise << 1) | get_mseq_bit(info);
+ sample = (sample & (noise_level - 1)) - (noise_level >> 1);
+ if (sample > 0x7f)
+ {
+ sample = 0x7f;
+ }
+ else if (sample < 0)
+ {
+ sample = 0xff;
+ }
+ sample = info->mulaw_table[(unsigned char)sample];
+
+ if ( (pos+cnt) == pos )
+ {
+ noisebuf += sample;
+ noisecnt++;
+ sample = noisebuf / noisecnt;
+ }
+ else
+ {
+ if ( noisecnt )
+ {
+ sample = noisebuf / noisecnt;
+ }
+ else
+ {
+ sample = info->mulaw_table[0x7f]; // Nearest sound(s) is here.
+ }
+ noisebuf = 0;
+ noisecnt = ( flag & C352_FLG_FILTER ) ? 0 : 1;
+ }
+ }
+
+ // apply linear interpolation
+ if ( (flag & (C352_FLG_FILTER | C352_FLG_NOISE)) == 0 )
+ {
+ sample = (short)(sample + ((nextsample-sample) * (((double)(0x0000ffff&offset) )/0x10000)));
+ }
+
+ if ( flag & C352_FLG_PHASEFL )
+ {
+ info->channel_l[i] += ((-sample * info->c352_ch[ch].vol_l)>>8);
+ }
+ else
+ {
+ info->channel_l[i] += ((sample * info->c352_ch[ch].vol_l)>>8);
+ }
+
+ if ( flag & C352_FLG_PHASEFR )
+ {
+ info->channel_r[i] += ((-sample * info->c352_ch[ch].vol_r)>>8);
+ }
+ else
+ {
+ info->channel_r[i] += ((sample * info->c352_ch[ch].vol_r)>>8);
+ }
+
+ if ( flag & C352_FLG_PHASERL )
+ {
+ info->channel_l2[i] += ((-sample * info->c352_ch[ch].vol_l2)>>8);
+ }
+ else
+ {
+ info->channel_l2[i] += ((sample * info->c352_ch[ch].vol_l2)>>8);
+ }
+ info->channel_r2[i] += ((sample * info->c352_ch[ch].vol_r2)>>8);
+
+ if ( (flag & C352_FLG_REVERSE) && (flag & C352_FLG_LOOP) )
+ {
+ if ( !(flag & C352_FLG_LDIR) )
+ {
+ pos += cnt;
+ if (
+ (((pos&0xFFFF) > info->c352_ch[ch].end_addr) && ((pos&0xFFFF) < info->c352_ch[ch].start) && (info->c352_ch[ch].start > info->c352_ch[ch].end_addr) ) ||
+ (((pos&0xFFFF) > info->c352_ch[ch].end_addr) && ((pos&0xFFFF) > info->c352_ch[ch].start) && (info->c352_ch[ch].start < info->c352_ch[ch].end_addr) ) ||
+ ((pos > (bank|0xFFFF)) && (info->c352_ch[ch].end_addr == 0xFFFF))
+ )
+ {
+ info->c352_ch[ch].flag |= C352_FLG_LDIR;
+ info->c352_ch[ch].flag |= C352_FLG_LOOPHIST;
+ }
+ }
+ else
+ {
+ pos -= cnt;
+ if (
+ (((pos&0xFFFF) < info->c352_ch[ch].repeat) && ((pos&0xFFFF) < info->c352_ch[ch].end_addr) && (info->c352_ch[ch].end_addr > info->c352_ch[ch].start) ) ||
+ (((pos&0xFFFF) < info->c352_ch[ch].repeat) && ((pos&0xFFFF) > info->c352_ch[ch].end_addr) && (info->c352_ch[ch].end_addr < info->c352_ch[ch].start) ) ||
+ ((pos < bank) && (info->c352_ch[ch].repeat == 0x0000))
+ )
+ {
+ info->c352_ch[ch].flag &= ~C352_FLG_LDIR;
+ info->c352_ch[ch].flag |= C352_FLG_LOOPHIST;
+ }
+ }
+ }
+ else if ( flag & C352_FLG_REVERSE )
+ {
+ pos -= cnt;
+ if (
+ (((pos&0xFFFF) < info->c352_ch[ch].end_addr) && ((pos&0xFFFF) < info->c352_ch[ch].start) && (info->c352_ch[ch].start > info->c352_ch[ch].end_addr) ) ||
+ (((pos&0xFFFF) < info->c352_ch[ch].end_addr) && ((pos&0xFFFF) > info->c352_ch[ch].start) && (info->c352_ch[ch].start < info->c352_ch[ch].end_addr) ) ||
+ ((pos < bank) && (info->c352_ch[ch].end_addr == 0x0000))
+ )
+ {
+ if ( (flag & C352_FLG_LINK) && (flag & C352_FLG_LOOP) )
+ {
+ info->c352_ch[ch].bank = info->c352_ch[ch].start_addr & 0xFF;
+ info->c352_ch[ch].start_addr = info->c352_ch[ch].repeat_addr;
+ info->c352_ch[ch].start = info->c352_ch[ch].start_addr;
+ info->c352_ch[ch].repeat = info->c352_ch[ch].repeat_addr;
+ pos = (info->c352_ch[ch].bank<<16) + info->c352_ch[ch].start_addr;
+ info->c352_ch[ch].flag |= C352_FLG_LOOPHIST;
+ }
+ else if (flag & C352_FLG_LOOP)
+ {
+ pos = (pos & 0xFF0000) + info->c352_ch[ch].repeat;
+ info->c352_ch[ch].flag |= C352_FLG_LOOPHIST;
+ }
+ else
+ {
+ info->c352_ch[ch].flag |= C352_FLG_KEYOFF;
+ info->c352_ch[ch].flag &= ~C352_FLG_BUSY;
+ return;
+ }
+ }
+ } else {
+ pos += cnt;
+ if (
+ (((pos&0xFFFF) > info->c352_ch[ch].end_addr) && ((pos&0xFFFF) < info->c352_ch[ch].start) && (info->c352_ch[ch].start > info->c352_ch[ch].end_addr) ) ||
+ (((pos&0xFFFF) > info->c352_ch[ch].end_addr) && ((pos&0xFFFF) > info->c352_ch[ch].start) && (info->c352_ch[ch].start < info->c352_ch[ch].end_addr) ) ||
+ ((pos > (bank|0xFFFF)) && (info->c352_ch[ch].end_addr == 0xFFFF))
+ )
+ {
+ if ( (flag & C352_FLG_LINK) && (flag & C352_FLG_LOOP) )
+ {
+ info->c352_ch[ch].bank = info->c352_ch[ch].start_addr & 0xFF;
+ info->c352_ch[ch].start_addr = info->c352_ch[ch].repeat_addr;
+ info->c352_ch[ch].start = info->c352_ch[ch].start_addr;
+ info->c352_ch[ch].repeat = info->c352_ch[ch].repeat_addr;
+ pos = (info->c352_ch[ch].bank<<16) + info->c352_ch[ch].start_addr;
+ info->c352_ch[ch].flag |= C352_FLG_LOOPHIST;
+ }
+ else if (flag & C352_FLG_LOOP)
+ {
+ pos = (pos & 0xFF0000) + info->c352_ch[ch].repeat;
+ info->c352_ch[ch].flag |= C352_FLG_LOOPHIST;
+ }
+ else
+ {
+ info->c352_ch[ch].flag |= C352_FLG_KEYOFF;
+ info->c352_ch[ch].flag &= ~C352_FLG_BUSY;
+ return;
+ }
+ }
+ }
+ }
+
+ info->c352_ch[ch].noisecnt = noisecnt;
+ info->c352_ch[ch].noisebuf = noisebuf;
+ info->c352_ch[ch].pos = offset;
+ info->c352_ch[ch].current_addr = pos;
+}
+
+
+static void c352_update(void *param, stream_sample_t **inputs, stream_sample_t **buf, int sample_count)
+{
+ struct c352_info *info = param;
+ int i, j;
+ stream_sample_t *bufferl = buf[0];
+ stream_sample_t *bufferr = buf[1];
+ stream_sample_t *bufferl2 = buf[2];
+ stream_sample_t *bufferr2 = buf[3];
+
+ for(i = 0 ; i < sample_count ; i++)
+ {
+ info->channel_l[i] = info->channel_r[i] = info->channel_l2[i] = info->channel_r2[i] = 0;
+ }
+
+ for (j = 0 ; j < 32 ; j++)
+ {
+ c352_mix_one_channel(info, j, sample_count);
+ }
+
+ for(i = 0 ; i < sample_count ; i++)
+ {
+ *bufferl++ = (short) (info->channel_l[i] >>3);
+ *bufferr++ = (short) (info->channel_r[i] >>3);
+ *bufferl2++ = (short) (info->channel_l2[i] >>3);
+ *bufferr2++ = (short) (info->channel_r2[i] >>3);
+ }
+}
+
+static unsigned short c352_read_reg16(struct c352_info *info, unsigned long address)
+{
+ unsigned long chan;
+ unsigned short val;
+
+ stream_update(info->stream);
+
+ chan = (address >> 4) & 0xfff;
+ if (chan > 31)
+ {
+ val = 0;
+ }
+ else
+ {
+ if ((address & 0xf) == 6)
+ {
+ val = info->c352_ch[chan].flag;
+ }
+ else
+ {
+ val = 0;
+ }
+ }
+ return val;
+}
+
+static void c352_write_reg16(struct c352_info *info, unsigned long address, unsigned short val)
+{
+ unsigned long chan;
+ int i;
+
+ stream_update(info->stream);
+
+ chan = (address >> 4) & 0xfff;
+
+ if ( address >= 0x400 )
+ {
+ switch(address)
+ {
+ case 0x404: // execute key-ons/offs
+ for ( i = 0 ; i <= 31 ; i++ )
+ {
+ if ( info->c352_ch[i].flag & C352_FLG_KEYON )
+ {
+ info->c352_ch[i].current_addr = (info->c352_ch[i].bank << 16) + info->c352_ch[i].start_addr;
+ info->c352_ch[i].start = info->c352_ch[i].start_addr;
+ info->c352_ch[i].repeat = info->c352_ch[i].repeat_addr;
+ info->c352_ch[i].noisebuf = 0;
+ info->c352_ch[i].noisecnt = 0;
+ info->c352_ch[i].flag &= ~(C352_FLG_KEYON | C352_FLG_LOOPHIST);
+ info->c352_ch[i].flag |= C352_FLG_BUSY;
+ }
+ else if ( info->c352_ch[i].flag & C352_FLG_KEYOFF )
+ {
+ info->c352_ch[i].flag &= ~C352_FLG_BUSY;
+ info->c352_ch[i].flag &= ~(C352_FLG_KEYOFF);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+
+ if (chan > 31)
+ {
+ #if VERBOSE
+ logerror("C352 CTRL %08x %04x\n", address, val);
+ #endif
+ return;
+ }
+ switch(address & 0xf)
+ {
+ case 0x0:
+ // volumes (output 1)
+ #if VERBOSE
+ logerror("CH %02d LVOL %02x RVOL %02x\n", chan, val & 0xff, val >> 8);
+ #endif
+ info->c352_ch[chan].vol_l = val & 0xff;
+ info->c352_ch[chan].vol_r = val >> 8;
+ break;
+
+ case 0x2:
+ // volumes (output 2)
+ #if VERBOSE
+ logerror("CH %02d RLVOL %02x RRVOL %02x\n", chan, val & 0xff, val >> 8);
+ #endif
+ info->c352_ch[chan].vol_l2 = val & 0xff;
+ info->c352_ch[chan].vol_r2 = val >> 8;
+ break;
+
+ case 0x4:
+ // pitch
+ #if VERBOSE
+ logerror("CH %02d PITCH %04x\n", chan, val);
+ #endif
+ info->c352_ch[chan].pitch = val;
+ break;
+
+ case 0x6:
+ // flags
+ #if VERBOSE
+ logerror("CH %02d FLAG %02x\n", chan, val);
+ #endif
+ info->c352_ch[chan].flag = val;
+ break;
+
+ case 0x8:
+ // bank (bits 16-31 of address);
+ info->c352_ch[chan].bank = val & 0xff;
+ #if VERBOSE
+ logerror("CH %02d BANK %02x", chan, info->c352_ch[chan].bank);
+ #endif
+ break;
+
+ case 0xa:
+ // start address
+ #if VERBOSE
+ logerror("CH %02d SADDR %04x\n", chan, val);
+ #endif
+ info->c352_ch[chan].start_addr = val;
+ break;
+
+ case 0xc:
+ // end address
+ #if VERBOSE
+ logerror("CH %02d EADDR %04x\n", chan, val);
+ #endif
+ info->c352_ch[chan].end_addr = val;
+ break;
+
+ case 0xe:
+ // loop address
+ #if VERBOSE
+ logerror("CH %02d LADDR %04x\n", chan, val);
+ #endif
+ info->c352_ch[chan].repeat_addr = val;
+ break;
+
+ default:
+ #if VERBOSE
+ logerror("CH %02d UNKN %01x %04x", chan, address & 0xf, val);
+ #endif
+ break;
+ }
+}
+
+static void c352_init(struct c352_info *info, int sndindex)
+{
+ int i;
+ double x_max = 32752.0;
+ double y_max = 127.0;
+ double u = 10.0;
+
+ // clear all channels states
+ memset(info->c352_ch, 0, sizeof(c352_ch_t)*32);
+
+ // generate mulaw table for mulaw format samples
+ for (i = 0; i < 256; i++)
+ {
+ double y = (double) (i & 0x7f);
+ double x = (exp (y / y_max * log (1.0 + u)) - 1.0) * x_max / u;
+
+ if (i & 0x80)
+ {
+ x = -x;
+ }
+ info->mulaw_table[i] = (short)x;
+ }
+
+ // init noise generator
+ info->mseq_reg = 0x12345678;
+
+ // register save state info
+ for (i = 0; i < 32; i++)
+ {
+ char cname[32];
+
+ sprintf(cname, "C352 v %02d", i);
+
+ state_save_register_item(cname, sndindex, info->c352_ch[i].vol_l);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].vol_r);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].vol_l2);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].vol_r2);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].bank);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].noise);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].noisebuf);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].noisecnt);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].pitch);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].start_addr);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].end_addr);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].repeat_addr);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].flag);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].start);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].repeat);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].current_addr);
+ state_save_register_item(cname, sndindex, info->c352_ch[i].pos);
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ double max_level = 255.0;
+
+ info->level_table[255-i] = (int) (pow (10.0, (double) i / 256.0 * -20.0 / 20.0) * max_level);
+ }
+}
+
+static void *c352_start(int sndindex, int clock, const void *config)
+{
+ const struct C352interface *intf;
+ struct c352_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ intf = config;
+
+ info->c352_rom_samples = memory_region(intf->region);
+ info->c352_region = intf->region;
+
+ info->sample_rate_base = clock / 192;
+
+ info->stream = stream_create(0, 4, info->sample_rate_base, info, c352_update);
+
+ c352_init(info, sndindex);
+
+ return info;
+}
+
+
+READ16_HANDLER( c352_0_r )
+{
+ return(c352_read_reg16(sndti_token(SOUND_C352, 0), offset*2));
+}
+
+WRITE16_HANDLER( c352_0_w )
+{
+ if (mem_mask == 0)
+ {
+ c352_write_reg16(sndti_token(SOUND_C352, 0), offset*2, data);
+ }
+ else
+ {
+ logerror("C352: byte-wide write unsupported at this time!\n");
+ }
+}
+
+
+
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void c352_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void c352_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = c352_set_info; break;
+ case SNDINFO_PTR_START: info->start = c352_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "C352"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Namco PCM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.1"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004-2007, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/c352.h b/src/emu/sound/c352.h
new file mode 100644
index 00000000000..7ab5896fdd1
--- /dev/null
+++ b/src/emu/sound/c352.h
@@ -0,0 +1,13 @@
+#ifndef _C352_H_
+#define _C352_H_
+
+struct C352interface
+{
+ int region; /* memory region of sample ROMs */
+};
+
+READ16_HANDLER( c352_0_r );
+WRITE16_HANDLER( c352_0_w );
+
+#endif
+
diff --git a/src/emu/sound/c6280.c b/src/emu/sound/c6280.c
new file mode 100644
index 00000000000..e2e01f30ddd
--- /dev/null
+++ b/src/emu/sound/c6280.c
@@ -0,0 +1,370 @@
+/*
+ HuC6280 sound chip emulator
+ by Charles MacDonald
+ E-mail: cgfm2@hotmail.com
+ WWW: http://cgfm2.emuviews.com
+
+ Thanks to:
+
+ - Paul Clifford for his PSG documentation.
+ - Richard Bannister for the TGEmu-specific sound updating code.
+ - http://www.uspto.gov for the PSG patents.
+ - All contributors to the tghack-list.
+
+ Changes:
+
+ (03/30/2003)
+ - Removed TGEmu specific code and added support functions for MAME.
+ - Modified setup code to handle multiple chips with different clock and
+ volume settings.
+
+ Missing features / things to do:
+
+ - Add LFO support. But do any games actually use it?
+
+ - Add shared index for waveform playback and sample writes. Almost every
+ game will reset the index prior to playback so this isn't an issue.
+
+ - While the noise emulation is complete, the data for the pseudo-random
+ bitstream is calculated by mame_rand() and is not a representation of what
+ the actual hardware does.
+
+ For some background on Hudson Soft's C62 chipset:
+
+ - http://www.hudsonsoft.net/ww/about/about.html
+ - http://www.hudson.co.jp/corp/eng/coinfo/history.html
+
+ Legal information:
+
+ Copyright (C) 2002, 2003 Charles MacDonald
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "c6280.h"
+
+typedef struct {
+ UINT16 frequency;
+ UINT8 control;
+ UINT8 balance;
+ UINT8 waveform[32];
+ UINT8 index;
+ INT16 dda;
+ UINT8 noise_control;
+ UINT32 noise_counter;
+ UINT32 counter;
+} t_channel;
+
+typedef struct {
+ sound_stream *stream;
+ UINT8 select;
+ UINT8 balance;
+ UINT8 lfo_frequency;
+ UINT8 lfo_control;
+ t_channel channel[8];
+ INT16 volume_table[32];
+ UINT32 noise_freq_tab[32];
+ UINT32 wave_freq_tab[4096];
+} c6280_t;
+
+/* only needed for io_buffer */
+#include "cpu/h6280/h6280.h"
+
+/* Local function prototypes */
+static void c6280_init(c6280_t *p, double clk, double rate);
+static void c6280_write(c6280_t *p, int offset, int data);
+static void c6280_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length);
+
+
+static void c6280_init(c6280_t *p, double clk, double rate)
+{
+ int i;
+ double step;
+
+ /* Loudest volume level for table */
+ double level = 65535.0 / 6.0 / 32.0;
+
+ /* Clear context */
+ memset(p, 0, sizeof(c6280_t));
+
+ /* Make waveform frequency table */
+ for(i = 0; i < 4096; i += 1)
+ {
+ step = ((clk / rate) * 4096) / (i+1);
+ p->wave_freq_tab[(1 + i) & 0xFFF] = (UINT32)step;
+ }
+
+ /* Make noise frequency table */
+ for(i = 0; i < 32; i += 1)
+ {
+ step = ((clk / rate) * 32) / (i+1);
+ p->noise_freq_tab[i] = (UINT32)step;
+ }
+
+ /* Make volume table */
+ /* PSG has 48dB volume range spread over 32 steps */
+ step = 48.0 / 32.0;
+ for(i = 0; i < 31; i++)
+ {
+ p->volume_table[i] = (UINT16)level;
+ level /= pow(10.0, step / 20.0);
+ }
+ p->volume_table[31] = 0;
+}
+
+
+static void c6280_write(c6280_t *p, int offset, int data)
+{
+ t_channel *q = &p->channel[p->select];
+
+ /* Update stream */
+ stream_update(p->stream);
+
+ switch(offset & 0x0F)
+ {
+ case 0x00: /* Channel select */
+ p->select = data & 0x07;
+ break;
+
+ case 0x01: /* Global balance */
+ p->balance = data;
+ break;
+
+ case 0x02: /* Channel frequency (LSB) */
+ q->frequency = (q->frequency & 0x0F00) | data;
+ q->frequency &= 0x0FFF;
+ break;
+
+ case 0x03: /* Channel frequency (MSB) */
+ q->frequency = (q->frequency & 0x00FF) | (data << 8);
+ q->frequency &= 0x0FFF;
+ break;
+
+ case 0x04: /* Channel control (key-on, DDA mode, volume) */
+
+ /* 1-to-0 transition of DDA bit resets waveform index */
+ if((q->control & 0x40) && ((data & 0x40) == 0))
+ {
+ q->index = 0;
+ }
+ q->control = data;
+ break;
+
+ case 0x05: /* Channel balance */
+ q->balance = data;
+ break;
+
+ case 0x06: /* Channel waveform data */
+
+ switch(q->control & 0xC0)
+ {
+ case 0x00:
+ q->waveform[q->index & 0x1F] = data & 0x1F;
+ q->index = (q->index + 1) & 0x1F;
+ break;
+
+ case 0x40:
+ break;
+
+ case 0x80:
+ q->waveform[q->index & 0x1F] = data & 0x1F;
+ q->index = (q->index + 1) & 0x1F;
+ break;
+
+ case 0xC0:
+ q->dda = data & 0x1F;
+ break;
+ }
+
+ break;
+
+ case 0x07: /* Noise control (enable, frequency) */
+ q->noise_control = data;
+ break;
+
+ case 0x08: /* LFO frequency */
+ p->lfo_frequency = data;
+ break;
+
+ case 0x09: /* LFO control (enable, mode) */
+ p->lfo_control = data;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static void c6280_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ static int scale_tab[] = {
+ 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
+ 0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F
+ };
+ int ch;
+ int i;
+ c6280_t *p = param;
+
+ int lmal = (p->balance >> 4) & 0x0F;
+ int rmal = (p->balance >> 0) & 0x0F;
+ int vll, vlr;
+
+ lmal = scale_tab[lmal];
+ rmal = scale_tab[rmal];
+
+ /* Clear buffer */
+ for(i = 0; i < length; i++)
+ {
+ buffer[0][i] = 0;
+ buffer[1][i] = 0;
+ }
+
+ for(ch = 0; ch < 6; ch++)
+ {
+ /* Only look at enabled channels */
+ if(p->channel[ch].control & 0x80)
+ {
+ int lal = (p->channel[ch].balance >> 4) & 0x0F;
+ int ral = (p->channel[ch].balance >> 0) & 0x0F;
+ int al = p->channel[ch].control & 0x1F;
+
+ lal = scale_tab[lal];
+ ral = scale_tab[ral];
+
+ /* Calculate volume just as the patent says */
+ vll = (0x1F - lal) + (0x1F - al) + (0x1F - lmal);
+ if(vll > 0x1F) vll = 0x1F;
+
+ vlr = (0x1F - ral) + (0x1F - al) + (0x1F - rmal);
+ if(vlr > 0x1F) vlr = 0x1F;
+
+ vll = p->volume_table[vll];
+ vlr = p->volume_table[vlr];
+
+ /* Check channel mode */
+ if((ch >= 4) && (p->channel[ch].noise_control & 0x80))
+ {
+ /* Noise mode */
+ UINT32 step = p->noise_freq_tab[(p->channel[ch].noise_control & 0x1F) ^ 0x1F];
+ for(i = 0; i < length; i += 1)
+ {
+ static int data = 0;
+ p->channel[ch].noise_counter += step;
+ if(p->channel[ch].noise_counter >= 0x800)
+ {
+ data = (mame_rand(Machine) & 1) ? 0x1F : 0;
+ }
+ p->channel[ch].noise_counter &= 0x7FF;
+ buffer[0][i] += (INT16)(vll * (data - 16));
+ buffer[1][i] += (INT16)(vlr * (data - 16));
+ }
+ }
+ else
+ if(p->channel[ch].control & 0x40)
+ {
+ /* DDA mode */
+ for(i = 0; i < length; i++)
+ {
+ buffer[0][i] += (INT16)(vll * (p->channel[ch].dda - 16));
+ buffer[1][i] += (INT16)(vlr * (p->channel[ch].dda - 16));
+ }
+ }
+ else
+ {
+ /* Waveform mode */
+ UINT32 step = p->wave_freq_tab[p->channel[ch].frequency];
+ for(i = 0; i < length; i += 1)
+ {
+ int offset;
+ INT16 data;
+ offset = (p->channel[ch].counter >> 12) & 0x1F;
+ p->channel[ch].counter += step;
+ p->channel[ch].counter &= 0x1FFFF;
+ data = p->channel[ch].waveform[offset];
+ buffer[0][i] += (INT16)(vll * (data - 16));
+ buffer[1][i] += (INT16)(vlr * (data - 16));
+ }
+ }
+ }
+ }
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* MAME specific code */
+/*--------------------------------------------------------------------------*/
+
+static void *c6280_start(int sndindex, int clock, const void *config)
+{
+ int rate = clock/16;
+ c6280_t *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ /* Initialize PSG emulator */
+ c6280_init(info, clock, rate);
+
+ /* Create stereo stream */
+ info->stream = stream_create(0, 2, rate, info, c6280_update);
+
+ return info;
+}
+
+READ8_HANDLER( C6280_r) { return h6280io_get_buffer();}
+WRITE8_HANDLER( C6280_0_w ) { h6280io_set_buffer(data); c6280_write(sndti_token(SOUND_C6280, 0),offset,data); }
+WRITE8_HANDLER( C6280_1_w ) { h6280io_set_buffer(data); c6280_write(sndti_token(SOUND_C6280, 1),offset,data); }
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void c6280_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void c6280_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = c6280_set_info; break;
+ case SNDINFO_PTR_START: info->start = c6280_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "HuC6280"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "????"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/c6280.h b/src/emu/sound/c6280.h
new file mode 100644
index 00000000000..00e020ab2e2
--- /dev/null
+++ b/src/emu/sound/c6280.h
@@ -0,0 +1,8 @@
+#ifndef _C6280_H_
+#define _C6280_H_
+
+/* Function prototypes */
+WRITE8_HANDLER( C6280_0_w );
+WRITE8_HANDLER( C6280_1_w );
+READ8_HANDLER( C6280_r );
+#endif /* _C6280_H_ */
diff --git a/src/emu/sound/cdda.c b/src/emu/sound/cdda.c
new file mode 100644
index 00000000000..57f86d27e49
--- /dev/null
+++ b/src/emu/sound/cdda.c
@@ -0,0 +1,332 @@
+/*
+ CD-DA "Red Book" audio sound hardware handler
+ Relies on the actual CD logic and reading in cdrom.c.
+*/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "cdrom.h"
+#include "cdda.h"
+
+typedef struct _cdda_info cdda_info;
+struct _cdda_info
+{
+ sound_stream * stream;
+ cdrom_file * disc;
+
+ INT8 audio_playing, audio_pause, audio_ended_normally;
+ UINT32 audio_lba, audio_length;
+
+ UINT8 * audio_cache;
+ UINT32 audio_samples;
+ UINT32 audio_bptr;
+};
+
+#define MAX_SECTORS ( 4 )
+
+static void get_audio_data(cdda_info *info, stream_sample_t *bufL, stream_sample_t *bufR, UINT32 samples_wanted);
+
+
+/*-------------------------------------------------
+ cdda_update - stream update callback
+-------------------------------------------------*/
+
+static void cdda_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length)
+{
+ cdda_info *info = param;
+ get_audio_data(info, &outputs[0][0], &outputs[1][0], length);
+}
+
+
+/*-------------------------------------------------
+ cdda_start - audio start callback
+-------------------------------------------------*/
+
+static void *cdda_start(int sndindex, int clock, const void *config)
+{
+ const struct CDDAinterface *intf;
+ cdda_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ /* allocate an audio cache */
+ info->audio_cache = auto_malloc( CD_MAX_SECTOR_DATA * MAX_SECTORS );
+
+ intf = config;
+
+ info->stream = stream_create(0, 2, 44100, info, cdda_update);
+
+ state_save_register_item( "CDDA", sndindex, info->audio_playing );
+ state_save_register_item( "CDDA", sndindex, info->audio_pause );
+ state_save_register_item( "CDDA", sndindex, info->audio_ended_normally );
+ state_save_register_item( "CDDA", sndindex, info->audio_lba );
+ state_save_register_item( "CDDA", sndindex, info->audio_length );
+ state_save_register_item_pointer( "CDDA", sndindex, info->audio_cache, CD_MAX_SECTOR_DATA * MAX_SECTORS );
+ state_save_register_item( "CDDA", sndindex, info->audio_samples );
+ state_save_register_item( "CDDA", sndindex, info->audio_bptr );
+
+ return info;
+}
+
+
+/*-------------------------------------------------
+ cdda_set_cdrom - set the CD-ROM file for the
+ given CDDA stream
+-------------------------------------------------*/
+
+void cdda_set_cdrom(int num, void *file)
+{
+ cdda_info *info = sndti_token(SOUND_CDDA, num);
+ info->disc = (cdrom_file *)file;
+}
+
+
+/*-------------------------------------------------
+ cdda_num_from_cdrom - find the CDDA stream
+ that references the given CD-ROM file
+-------------------------------------------------*/
+
+int cdda_num_from_cdrom(void *file)
+{
+ int index;
+
+ for (index = 0; ; index++)
+ {
+ cdda_info *info;
+
+ if (!sndti_exists(SOUND_CDDA, index))
+ return -1;
+
+ info = sndti_token(SOUND_CDDA, index);
+
+ if (info == NULL)
+ return -1;
+ if (info->disc == file)
+ return index;
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ cdda_start_audio - begin playback of a Red
+ Book audio track
+-------------------------------------------------*/
+
+void cdda_start_audio(int num, UINT32 startlba, UINT32 numblocks)
+{
+ cdda_info *info = sndti_token(SOUND_CDDA, num);
+
+ stream_update(info->stream);
+ info->audio_playing = TRUE;
+ info->audio_pause = FALSE;
+ info->audio_ended_normally = FALSE;
+ info->audio_lba = startlba;
+ info->audio_length = numblocks;
+}
+
+
+/*-------------------------------------------------
+ cdda_stop_audio - stop playback of a Red Book
+ audio track
+-------------------------------------------------*/
+
+void cdda_stop_audio(int num)
+{
+ cdda_info *info = sndti_token(SOUND_CDDA, num);
+
+ stream_update(info->stream);
+ info->audio_playing = FALSE;
+ info->audio_ended_normally = TRUE;
+}
+
+
+/*-------------------------------------------------
+ cdda_pause_audio - pause/unpause playback of
+ a Red Book audio track
+-------------------------------------------------*/
+
+void cdda_pause_audio(int num, int pause)
+{
+ cdda_info *info = sndti_token(SOUND_CDDA, num);
+
+ stream_update(info->stream);
+ info->audio_pause = pause;
+}
+
+
+/*-------------------------------------------------
+ cdda_get_audio_lba - returns the current LBA
+ (physical sector) during Red Book playback
+-------------------------------------------------*/
+
+UINT32 cdda_get_audio_lba(int num)
+{
+ cdda_info *info = sndti_token(SOUND_CDDA, num);
+
+ stream_update(info->stream);
+ return info->audio_lba;
+}
+
+
+/*-------------------------------------------------
+ cdda_audio_active - returns Red Book audio
+ playback status
+-------------------------------------------------*/
+
+int cdda_audio_active(int num)
+{
+ cdda_info *info = sndti_token(SOUND_CDDA, num);
+
+ stream_update(info->stream);
+ return info->audio_playing;
+}
+
+
+/*-------------------------------------------------
+ cdda_audio_paused - returns if Red Book
+ playback is paused
+-------------------------------------------------*/
+
+int cdda_audio_paused(int num)
+{
+ cdda_info *info = sndti_token(SOUND_CDDA, num);
+ return info->audio_pause;
+}
+
+
+/*-------------------------------------------------
+ cdda_audio_ended - returns if a Red Book
+ track reached it's natural end
+-------------------------------------------------*/
+
+int cdda_audio_ended(int num)
+{
+ cdda_info *info = sndti_token(SOUND_CDDA, num);
+ return info->audio_ended_normally;
+}
+
+
+/*-------------------------------------------------
+ get_audio_data - reads Red Book data off
+ the disc if playback is in progress and
+ converts it to 2 16-bit 44.1 kHz streams
+-------------------------------------------------*/
+
+static void get_audio_data(cdda_info *info, stream_sample_t *bufL, stream_sample_t *bufR, UINT32 samples_wanted)
+{
+ int i, sectoread, remaining;
+ INT16 *audio_cache = (INT16 *) info->audio_cache;
+
+ /* if no file, audio not playing, audio paused, or out of disc data,
+ just zero fill */
+ if (!info->disc || !info->audio_playing || info->audio_pause || (!info->audio_length && !info->audio_samples))
+ {
+ if( info->disc && info->audio_playing && !info->audio_pause && !info->audio_length )
+ {
+ info->audio_playing = FALSE;
+ info->audio_ended_normally = TRUE;
+ }
+
+ memset(bufL, 0, sizeof(stream_sample_t)*samples_wanted);
+ memset(bufR, 0, sizeof(stream_sample_t)*samples_wanted);
+ return;
+ }
+
+ /* if we've got enough samples, just feed 'em out */
+ if (samples_wanted <= info->audio_samples)
+ {
+ for (i = 0; i < samples_wanted; i++)
+ {
+ *bufL++ = audio_cache[ info->audio_bptr++ ];
+ *bufR++ = audio_cache[ info->audio_bptr++ ];
+ }
+
+ info->audio_samples -= samples_wanted;
+ return;
+ }
+
+ /* we don't have enough, so first feed what we've got */
+ for (i = 0; i < info->audio_samples; i++)
+ {
+ *bufL++ = audio_cache[ info->audio_bptr++ ];
+ *bufR++ = audio_cache[ info->audio_bptr++ ];
+ }
+
+ /* remember how much left for later */
+ remaining = samples_wanted - info->audio_samples;
+
+ /* reset the buffer and get what we can from the disc */
+ info->audio_samples = 0;
+ if (info->audio_length >= MAX_SECTORS)
+ {
+ sectoread = MAX_SECTORS;
+ }
+ else
+ {
+ sectoread = info->audio_length;
+ }
+
+ for (i = 0; i < sectoread; i++)
+ {
+ cdrom_read_data(info->disc, info->audio_lba, &info->audio_cache[CD_MAX_SECTOR_DATA*i], CD_TRACK_AUDIO);
+
+ info->audio_lba++;
+ }
+
+ info->audio_samples = (CD_MAX_SECTOR_DATA*sectoread)/4;
+ info->audio_length -= sectoread;
+
+ /* CD-DA data on the disc is big-endian, flip if we're not */
+ #ifdef LSB_FIRST
+ for( i = 0; i < info->audio_samples * 2; i++ )
+ {
+ audio_cache[ i ] = BIG_ENDIANIZE_INT16( audio_cache[ i ] );
+ }
+ #endif
+
+ /* reset feedout ptr */
+ info->audio_bptr = 0;
+
+ /* we've got data, feed it out by calling ourselves recursively */
+ get_audio_data(info, bufL, bufR, remaining);
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void cdda_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void cdda_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = cdda_set_info; break;
+ case SNDINFO_PTR_START: info->start = cdda_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "CD/DA"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "CD Audio"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/cdda.h b/src/emu/sound/cdda.h
new file mode 100644
index 00000000000..68069a0757b
--- /dev/null
+++ b/src/emu/sound/cdda.h
@@ -0,0 +1,17 @@
+#ifndef _CDDA_H_
+#define _CDDA_H_
+
+void cdda_set_cdrom(int num, void *file);
+int cdda_num_from_cdrom(void *file);
+
+void cdda_start_audio(int num, UINT32 startlba, UINT32 numblocks);
+void cdda_stop_audio(int num);
+void cdda_pause_audio(int num, int pause);
+
+UINT32 cdda_get_audio_lba(int num);
+int cdda_audio_active(int num);
+int cdda_audio_paused(int num);
+int cdda_audio_ended(int num);
+
+#endif
+
diff --git a/src/emu/sound/cdp1869.c b/src/emu/sound/cdp1869.c
new file mode 100644
index 00000000000..1e6cff1fb1c
--- /dev/null
+++ b/src/emu/sound/cdp1869.c
@@ -0,0 +1,201 @@
+/***************************************************************************
+
+ cdp1869.c
+
+ Sound handler
+
+ TODO:
+
+ - white noise
+
+****************************************************************************/
+
+#include "sndintrf.h"
+#include "sound/cdp1869.h"
+#include "streams.h"
+
+struct CDP1869
+{
+ sound_stream *stream; /* returned by stream_create() */
+ int clock; /* chip's base frequency */
+
+ int incr; /* initial wave state */
+ INT16 signal; /* current signal */
+
+ int toneoff;
+ int wnoff;
+
+ UINT8 tonediv;
+ UINT8 tonefreq;
+ UINT8 toneamp;
+
+ UINT8 wnfreq;
+ UINT8 wnamp;
+};
+
+/*************************************
+ *
+ * Stream update
+ *
+ *************************************/
+
+static void cdp1869_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct CDP1869 *info = (struct CDP1869 *) param;
+ INT16 signal = info->signal;
+ stream_sample_t *buffer = _buffer[0];
+
+ memset( buffer, 0, length * sizeof(*buffer) );
+
+ if (!info->toneoff && info->toneamp)
+ {
+ double frequency = (info->clock / 2) / (512 >> info->tonefreq) / (info->tonediv + 1);
+// double amplitude = info->toneamp * ((0.78*5) / 15);
+
+ int rate = Machine->sample_rate / 2;
+
+ /* get progress through wave */
+ int incr = info->incr;
+
+ if (signal < 0)
+ {
+ signal = -(info->toneamp * (0x07fff / 15));
+ }
+ else
+ {
+ signal = info->toneamp * (0x07fff / 15);
+ }
+
+ while( length-- > 0 )
+ {
+ *buffer++ = signal;
+ incr -= frequency;
+ while( incr < 0 )
+ {
+ incr += rate;
+ signal = -signal;
+ }
+ }
+
+ /* store progress through wave */
+ info->incr = incr;
+ info->signal = signal;
+ }
+/*
+ if (!info->wnoff)
+ {
+ double amplitude = info->wnamp * ((0.78*5) / 15);
+
+ for (int wndiv = 0; wndiv < 128; wndiv++)
+ {
+ double frequency = (info->clock / 2) / (4096 >> info->wnfreq) / (wndiv + 1):
+
+ cdp1869_sum_square_wave(buffer, frequency, amplitude);
+ }
+ }
+*/
+}
+
+/*************************************
+ *
+ * Sound handler start
+ *
+ *************************************/
+
+static void *cdp1869_start(int sndindex, int clock, const void *config)
+{
+ struct CDP1869 *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->stream = stream_create(0, 1, Machine->sample_rate, info, cdp1869_update );
+ info->incr = 0;
+ info->signal = 0x07fff;
+
+ info->clock = clock;
+ info->toneoff = 1;
+ info->wnoff = 1;
+ info->tonediv = 0;
+ info->tonefreq = 0;
+ info->toneamp = 0;
+ info->wnfreq = 0;
+ info->wnamp = 0;
+
+ return info;
+}
+
+void cdp1869_set_toneamp(int which, int value)
+{
+ struct CDP1869 *info = sndti_token(SOUND_CDP1869, which);
+ info->toneamp = value & 0x0f;
+}
+
+void cdp1869_set_tonefreq(int which, int value)
+{
+ struct CDP1869 *info = sndti_token(SOUND_CDP1869, which);
+ info->tonefreq = value & 0x07;
+}
+
+void cdp1869_set_toneoff(int which, int value)
+{
+ struct CDP1869 *info = sndti_token(SOUND_CDP1869, which);
+ info->toneoff = value & 0x01;
+}
+
+void cdp1869_set_tonediv(int which, int value)
+{
+ struct CDP1869 *info = sndti_token(SOUND_CDP1869, which);
+ info->tonediv = value & 0x7f;
+}
+
+void cdp1869_set_wnamp(int which, int value)
+{
+ struct CDP1869 *info = sndti_token(SOUND_CDP1869, which);
+ info->wnamp = value & 0x0f;
+}
+
+void cdp1869_set_wnfreq(int which, int value)
+{
+ struct CDP1869 *info = sndti_token(SOUND_CDP1869, which);
+ info->wnfreq = value & 0x07;
+}
+
+void cdp1869_set_wnoff(int which, int value)
+{
+ struct CDP1869 *info = sndti_token(SOUND_CDP1869, which);
+ info->wnoff = value & 0x01;
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void cdp1869_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+void cdp1869_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = cdp1869_set_info; break;
+ case SNDINFO_PTR_START: info->start = cdp1869_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "CDP1869"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "RCA CDP1869"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2007, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/cdp1869.h b/src/emu/sound/cdp1869.h
new file mode 100644
index 00000000000..c9d2044ecd9
--- /dev/null
+++ b/src/emu/sound/cdp1869.h
@@ -0,0 +1,41 @@
+/*
+
+ ________________ ________________
+ TPA 1 ---| \/ |--- 40 Vdd PREDISPLAY_ 1 ---| \/ |--- 40 Vdd
+ TPB 2 ---| |--- 39 PMSEL *DISPLAY_ 2 ---| |--- 39 PAL/NTSC_
+ MRD_ 3 ---| |--- 38 PMWR_ PCB 3 ---| |--- 38 CPUCLK
+ MWR_ 4 ---| |--- 37 *CMSEL CCB1 4 ---| |--- 37 XTAL (DOT)
+ MA0/8 5 ---| |--- 36 CMWR_ BUS7 5 ---| |--- 36 XTAL (DOT)_
+ MA1/9 6 ---| |--- 35 PMA0 CCB0 6 ---| |--- 35 *ADDRSTB_
+ MA2/10 7 ---| |--- 34 PMA1 BUS6 7 ---| |--- 34 MRD_
+ MA3/11 8 ---| |--- 33 PMA2 CDB5 8 ---| |--- 33 TPB
+ MA4/12 9 ---| |--- 32 PMA3 BUS5 9 ---| |--- 32 *CMSEL
+ MA5/13 10 ---| CDP1869C |--- 31 PMA4 CDB4 10 ---| CDP1870/76C |--- 31 BURST
+ MA6/14 11 ---| top view |--- 30 PMA5 BUS4 11 ---| top view |--- 30 *H SYNC_
+ MA7/15 12 ---| |--- 29 PMA6 CDB3 12 ---| |--- 29 COMPSYNC_
+ N0 13 ---| |--- 28 PMA7 BUS3 13 ---| |--- 28 LUM / (RED)^
+ N1 14 ---| |--- 27 PMA8 CDB2 14 ---| |--- 27 PAL CHROM / (BLUE)^
+ N2 15 ---| |--- 26 PMA9 BUS2 15 ---| |--- 26 NTSC CHROM / (GREEN)^
+ *H SYNC_ 16 ---| |--- 25 CMA3/PMA10 CDB1 16 ---| |--- 25 XTAL_ (CHROM)
+ *DISPLAY_ 17 ---| |--- 24 CMA2 BUS1 17 ---| |--- 24 XTAL (CHROM)
+ *ADDRSTB_ 18 ---| |--- 23 CMA1 CDB0 18 ---| |--- 23 EMS_
+ SOUND 19 ---| |--- 22 CMA0 BUS0 19 ---| |--- 22 EVS_
+ VSS 20 ---|________________|--- 21 *N=3_ Vss 20 ---|________________|--- 21 *N=3_
+
+
+ * = INTERCHIP CONNECTIONS ^ = FOR THE RGB BOND-OUT OPTION (CDP1876C) _ = ACTIVE LOW
+
+*/
+
+#ifndef __CDP1869_SOUND__
+#define __CDP1869_SOUND__
+
+void cdp1869_set_toneamp(int which, int value);
+void cdp1869_set_tonefreq(int which, int value);
+void cdp1869_set_toneoff(int which, int value);
+void cdp1869_set_tonediv(int which, int value);
+void cdp1869_set_wnamp(int which, int value);
+void cdp1869_set_wnfreq(int which, int value);
+void cdp1869_set_wnoff(int which, int value);
+
+#endif
diff --git a/src/emu/sound/cem3394.c b/src/emu/sound/cem3394.c
new file mode 100644
index 00000000000..7e61cae2558
--- /dev/null
+++ b/src/emu/sound/cem3394.c
@@ -0,0 +1,593 @@
+/***************************************************************************
+
+ CEM3394 sound driver.
+
+ This driver handles CEM-3394 analog synth chip. Very crudely.
+
+ Still to do:
+ - adjust the overall volume when multiple waves are being generated
+ - filter internal sound
+ - support resonance (don't understand how it works)
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "cem3394.h"
+#include <math.h>
+
+
+
+/* waveform generation parameters */
+#define ENABLE_PULSE 1
+#define ENABLE_TRIANGLE 1
+#define ENABLE_SAWTOOTH 1
+#define ENABLE_EXTERNAL 1
+
+
+/* pulse shaping parameters */
+/* examples: */
+/* hat trick - skidding ice sounds too loud if minimum width is too big */
+/* snake pit - melody during first level too soft if minimum width is too small */
+/* snake pit - bonus counter at the end of level */
+/* snacks'n jaxson - laugh at end of level is too soft if minimum width is too small */
+
+#define LIMIT_WIDTH 1
+#define MINIMUM_WIDTH 0.25
+#define MAXIMUM_WIDTH 0.75
+
+
+/********************************************************************************
+
+ From the datasheet:
+
+ CEM3394_VCO_FREQUENCY:
+ -4.0 ... +4.0
+ -0.75 V/octave
+ f = exp(V) * 431.894
+
+ CEM3394_MODULATION_AMOUNT
+ 0.0 ... +3.5
+ 0.0 == 0.01 x frequency
+ 3.5 == 2.00 x frequency
+
+ CEM3394_WAVE_SELECT
+ -0.5 ... -0.2 == triangle
+ +0.9 ... +1.5 == triangle + sawtooth
+ +2.3 ... +3.9 == sawtooth
+
+ CEM3394_PULSE_WIDTH
+ 0.0 ... +2.0
+ 0.0 == 0% duty cycle
+ +2.0 == 100% duty cycle
+
+ CEM3394_MIXER_BALANCE
+ -4.0 ... +4.0
+ 0.0 both at -6dB
+ -20 dB/V
+
+ CEM3394_FILTER_RESONANCE
+ 0.0 ... +2.5
+ 0.0 == no resonance
+ +2.5 == oscillation
+
+ CEM3394_FILTER_FREQENCY
+ -3.0 ... +4.0
+ -0.375 V/octave
+ 0.0 == 1300Hz
+
+ CEM3394_FINAL_GAIN
+ 0.0 ... +4.0
+ -20 dB/V
+ 0.0 == -90dB
+ 4.0 == 0dB
+
+ Square wave output = 160 (average is constant regardless of duty cycle)
+ Sawtooth output = 200
+ Triangle output = 250
+ Sawtooth + triangle output = 330
+ Maximum output = 400
+
+********************************************************************************/
+
+
+/* various waveforms */
+#define WAVE_TRIANGLE 1
+#define WAVE_SAWTOOTH 2
+#define WAVE_PULSE 4
+
+/* keep lots of fractional bits */
+#define FRACTION_BITS 28
+#define FRACTION_ONE (1 << FRACTION_BITS)
+#define FRACTION_ONE_D ((double)(1 << FRACTION_BITS))
+#define FRACTION_MASK (FRACTION_ONE - 1)
+#define FRACTION_MULT(a,b) (((a) >> (FRACTION_BITS / 2)) * ((b) >> (FRACTION_BITS - FRACTION_BITS / 2)))
+
+
+/* this structure defines the parameters for a channel */
+typedef struct
+{
+ sound_stream * stream; /* our stream */
+ int index;
+ void (*external)(int, int, short *);/* callback to generate external samples */
+ double vco_zero_freq; /* frequency of VCO at 0.0V */
+ double filter_zero_freq; /* frequency of filter at 0.0V */
+
+ double values[8]; /* raw values of registers */
+ UINT8 wave_select; /* flags which waveforms are enabled */
+
+ UINT32 volume; /* linear overall volume (0-256) */
+ UINT32 mixer_internal; /* linear internal volume (0-256) */
+ UINT32 mixer_external; /* linear external volume (0-256) */
+
+ UINT32 position; /* current VCO frequency position (0.FRACTION_BITS) */
+ UINT32 step; /* per-sample VCO step (0.FRACTION_BITS) */
+
+ UINT32 filter_position; /* current filter frequency position (0.FRACTION_BITS) */
+ UINT32 filter_step; /* per-sample filter step (0.FRACTION_BITS) */
+ UINT32 modulation_depth; /* fraction of total by which we modulate (0.FRACTION_BITS) */
+ INT16 last_ext; /* last external sample we read */
+
+ UINT32 pulse_width; /* fractional pulse width (0.FRACTION_BITS) */
+
+ double inv_sample_rate;
+ int sample_rate;
+
+ INT16 *mixer_buffer;
+ INT16 *external_buffer;
+} sound_chip;
+
+
+/* generate sound to the mix buffer in mono */
+static void cem3394_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ sound_chip *chip = param;
+ int int_volume = (chip->volume * chip->mixer_internal) / 256;
+ int ext_volume = (chip->volume * chip->mixer_external) / 256;
+ UINT32 step = chip->step, position, end_position = 0;
+ stream_sample_t *buffer = _buffer[0];
+ INT16 *mix, *ext;
+ int i;
+
+ /* external volume is effectively 0 if no external function */
+ if (!chip->external || !ENABLE_EXTERNAL)
+ ext_volume = 0;
+
+ /* adjust the volume for the filter */
+ if (step > chip->filter_step)
+ int_volume /= step - chip->filter_step;
+
+ /* bail if nothing's going on */
+ if (int_volume == 0 && ext_volume == 0)
+ {
+ memset(buffer, 0, sizeof(*buffer) * length);
+ return;
+ }
+
+ /* if there's external stuff, fetch and process it now */
+ if (ext_volume != 0)
+ {
+ UINT32 fposition = chip->filter_position, fstep = chip->filter_step, depth;
+ INT16 last_ext = chip->last_ext;
+
+ /* fetch the external data */
+ (*chip->external)(chip->index, length, chip->external_buffer);
+
+ /* compute the modulation depth, and adjust fstep to the maximum frequency */
+ /* we lop off 13 bits of depth so that we can multiply by stepadjust, below, */
+ /* which has 13 bits of precision */
+ depth = FRACTION_MULT(fstep, chip->modulation_depth);
+ fstep += depth;
+ depth >>= 13;
+
+ /* "apply" the filter: note this is pretty cheesy; it basically just downsamples the
+ external sample to filter_freq by allowing only 2 transitions for every cycle */
+ for (i = 0, ext = chip->external_buffer, position = chip->position; i < length; i++, ext++)
+ {
+ UINT32 newposition;
+ INT32 stepadjust;
+
+ /* update the position and compute the adjustment from a triangle wave */
+ if (position & (1 << (FRACTION_BITS - 1)))
+ stepadjust = 0x2000 - ((position >> (FRACTION_BITS - 14)) & 0x1fff);
+ else
+ stepadjust = (position >> (FRACTION_BITS - 14)) & 0x1fff;
+ position += step;
+
+ /* if we cross a half-step boundary, allow the next byte of the external input */
+ newposition = fposition + fstep - (stepadjust * depth);
+ if ((newposition ^ fposition) & ~(FRACTION_MASK >> 1))
+ last_ext = *ext;
+ else
+ *ext = last_ext;
+ fposition = newposition & FRACTION_MASK;
+ }
+
+ /* update the final filter values */
+ chip->filter_position = fposition;
+ chip->last_ext = last_ext;
+ }
+
+ /* if there's internal stuff, generate it */
+ if (int_volume != 0)
+ {
+ if (chip->wave_select == 0 && !ext_volume)
+ logerror("%f V didn't cut it\n", chip->values[CEM3394_WAVE_SELECT]);
+
+ /* handle the pulse component; it maxes out at 0x1932, which is 27% smaller than */
+ /* the sawtooth (since the value is constant, this is the best place to have an */
+ /* odd value for volume) */
+ if (ENABLE_PULSE && (chip->wave_select & WAVE_PULSE))
+ {
+ UINT32 pulse_width = chip->pulse_width;
+
+ /* if the width is wider than the step, we're guaranteed to hit it once per cycle */
+ if (pulse_width >= step)
+ {
+ for (i = 0, mix = chip->mixer_buffer, position = chip->position; i < length; i++, mix++)
+ {
+ if (position < pulse_width)
+ *mix = 0x1932;
+ else
+ *mix = 0x0000;
+ position = (position + step) & FRACTION_MASK;
+ }
+ }
+
+ /* otherwise, we compute a volume and watch for cycle boundary crossings */
+ else
+ {
+ INT16 volume = 0x1932 * pulse_width / step;
+ for (i = 0, mix = chip->mixer_buffer, position = chip->position; i < length; i++, mix++)
+ {
+ UINT32 newposition = position + step;
+ if ((newposition ^ position) & ~FRACTION_MASK)
+ *mix = volume;
+ else
+ *mix = 0x0000;
+ position = newposition & FRACTION_MASK;
+ }
+ }
+ end_position = position;
+ }
+
+ /* otherwise, clear the mixing buffer */
+ else
+ memset(chip->mixer_buffer, 0, sizeof(INT16) * length);
+
+ /* handle the sawtooth component; it maxes out at 0x2000, which is 27% larger */
+ /* than the pulse */
+ if (ENABLE_SAWTOOTH && (chip->wave_select & WAVE_SAWTOOTH))
+ {
+ for (i = 0, mix = chip->mixer_buffer, position = chip->position; i < length; i++, mix++)
+ {
+ *mix += ((position >> (FRACTION_BITS - 14)) & 0x3fff) - 0x2000;
+ position += step;
+ }
+ end_position = position & FRACTION_MASK;
+ }
+
+ /* handle the triangle component; it maxes out at 0x2800, which is 25% larger */
+ /* than the sawtooth (should be 27% according to the specs, but 25% saves us */
+ /* a multiplication) */
+ if (ENABLE_TRIANGLE && (chip->wave_select & WAVE_TRIANGLE))
+ {
+ for (i = 0, mix = chip->mixer_buffer, position = chip->position; i < length; i++, mix++)
+ {
+ INT16 value;
+ if (position & (1 << (FRACTION_BITS - 1)))
+ value = 0x2000 - ((position >> (FRACTION_BITS - 14)) & 0x1fff);
+ else
+ value = (position >> (FRACTION_BITS - 14)) & 0x1fff;
+ *mix += value + (value >> 2);
+ position += step;
+ }
+ end_position = position & FRACTION_MASK;
+ }
+
+ /* update the final position */
+ chip->position = end_position;
+ }
+
+ /* mix it down */
+ mix = chip->mixer_buffer;
+ ext = chip->external_buffer;
+ {
+ /* internal + external */
+ if (ext_volume != 0 && int_volume != 0)
+ {
+ for (i = 0; i < length; i++, mix++, ext++)
+ *buffer++ = (*mix * int_volume + *ext * ext_volume) / 128;
+ }
+ /* internal only */
+ else if (int_volume != 0)
+ {
+ for (i = 0; i < length; i++, mix++)
+ *buffer++ = *mix * int_volume / 128;
+ }
+ /* external only */
+ else
+ {
+ for (i = 0; i < length; i++, ext++)
+ *buffer++ = *ext * ext_volume / 128;
+ }
+ }
+}
+
+
+static void *cem3394_start(int sndindex, int clock, const void *config)
+{
+ const struct cem3394_interface *intf = config;
+ sound_chip *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+ chip->index = sndindex;
+
+ /* copy global parameters */
+ chip->sample_rate = CEM3394_SAMPLE_RATE;
+ chip->inv_sample_rate = 1.0 / (double)chip->sample_rate;
+
+ /* allocate stream channels, 1 per chip */
+ chip->stream = stream_create(0, 1, chip->sample_rate, chip, cem3394_update);
+ chip->external = intf->external;
+ chip->vco_zero_freq = intf->vco_zero_freq;
+ chip->filter_zero_freq = intf->filter_zero_freq;
+
+ /* allocate memory for a mixer buffer and external buffer (1 second should do it!) */
+ chip->mixer_buffer = auto_malloc(chip->sample_rate * sizeof(INT16));
+ chip->external_buffer = auto_malloc(chip->sample_rate * sizeof(INT16));
+
+ state_save_register_item_array("cem3394", sndindex, chip->values);
+ state_save_register_item("cem3394", sndindex, chip->wave_select);
+ state_save_register_item("cem3394", sndindex, chip->volume);
+ state_save_register_item("cem3394", sndindex, chip->mixer_internal);
+ state_save_register_item("cem3394", sndindex, chip->mixer_external);
+ state_save_register_item("cem3394", sndindex, chip->position);
+ state_save_register_item("cem3394", sndindex, chip->step);
+ state_save_register_item("cem3394", sndindex, chip->filter_position);
+ state_save_register_item("cem3394", sndindex, chip->filter_step);
+ state_save_register_item("cem3394", sndindex, chip->modulation_depth);
+ state_save_register_item("cem3394", sndindex, chip->last_ext);
+ state_save_register_item("cem3394", sndindex, chip->pulse_width);
+
+ return chip;
+}
+
+
+INLINE double compute_db(double voltage)
+{
+ /* assumes 0.0 == full off, 4.0 == full on, with linear taper, as described in the datasheet */
+
+ /* above 4.0, maximum volume */
+ if (voltage >= 4.0)
+ return 0.0;
+
+ /* below 0.0, minimum volume */
+ else if (voltage <= 0.0)
+ return 90.0;
+
+ /* between 2.5 and 4.0, linear from 20dB to 0dB */
+ else if (voltage >= 2.5)
+ return (4.0 - voltage) * (1.0 / 1.5) * 20.0;
+
+ /* between 0.0 and 2.5, exponential to 20dB */
+ else
+ {
+ double temp = 20.0 * pow(2.0, 2.5 - voltage);
+ if (temp < 90.0) return 90.0;
+ else return temp;
+ }
+}
+
+
+INLINE UINT32 compute_db_volume(double voltage)
+{
+ double temp;
+
+ /* assumes 0.0 == full off, 4.0 == full on, with linear taper, as described in the datasheet */
+
+ /* above 4.0, maximum volume */
+ if (voltage >= 4.0)
+ return 256;
+
+ /* below 0.0, minimum volume */
+ else if (voltage <= 0.0)
+ return 0;
+
+ /* between 2.5 and 4.0, linear from 20dB to 0dB */
+ else if (voltage >= 2.5)
+ temp = (4.0 - voltage) * (1.0 / 1.5) * 20.0;
+
+ /* between 0.0 and 2.5, exponential to 20dB */
+ else
+ {
+ temp = 20.0 * pow(2.0, 2.5 - voltage);
+ if (temp < 50.0) return 0;
+ }
+
+ /* convert from dB to volume and return */
+ return (UINT32)(256.0 * pow(0.891251, temp));
+}
+
+
+void cem3394_set_voltage(int chipnum, int input, double voltage)
+{
+ sound_chip *chip = sndti_token(SOUND_CEM3394, chipnum);
+ double temp;
+
+ /* don't do anything if no change */
+ if (voltage == chip->values[input])
+ return;
+ chip->values[input] = voltage;
+
+ /* update the stream first */
+ stream_update(chip->stream);
+
+ /* switch off the input */
+ switch (input)
+ {
+ /* frequency varies from -4.0 to +4.0, at 0.75V/octave */
+ case CEM3394_VCO_FREQUENCY:
+ temp = chip->vco_zero_freq * pow(2.0, -voltage * (1.0 / 0.75));
+ chip->step = (UINT32)(temp * chip->inv_sample_rate * FRACTION_ONE_D);
+ break;
+
+ /* wave select determines triangle/sawtooth enable */
+ case CEM3394_WAVE_SELECT:
+ chip->wave_select &= ~(WAVE_TRIANGLE | WAVE_SAWTOOTH);
+ if (voltage >= -0.5 && voltage <= -0.2)
+ chip->wave_select |= WAVE_TRIANGLE;
+ else if (voltage >= 0.9 && voltage <= 1.5)
+ chip->wave_select |= WAVE_TRIANGLE | WAVE_SAWTOOTH;
+ else if (voltage >= 2.3 && voltage <= 3.9)
+ chip->wave_select |= WAVE_SAWTOOTH;
+ break;
+
+ /* pulse width determines duty cycle; 0.0 means 0%, 2.0 means 100% */
+ case CEM3394_PULSE_WIDTH:
+ if (voltage < 0.0)
+ {
+ chip->pulse_width = 0;
+ chip->wave_select &= ~WAVE_PULSE;
+ }
+ else
+ {
+ temp = voltage * 0.5;
+ if (LIMIT_WIDTH)
+ temp = MINIMUM_WIDTH + (MAXIMUM_WIDTH - MINIMUM_WIDTH) * temp;
+ chip->pulse_width = (UINT32)(temp * FRACTION_ONE_D);
+ chip->wave_select |= WAVE_PULSE;
+ }
+ break;
+
+ /* final gain is pretty self-explanatory; 0.0 means ~90dB, 4.0 means 0dB */
+ case CEM3394_FINAL_GAIN:
+ chip->volume = compute_db_volume(voltage);
+ break;
+
+ /* mixer balance is a pan between the external input and the internal input */
+ /* 0.0 is equal parts of both; positive values favor external, negative favor internal */
+ case CEM3394_MIXER_BALANCE:
+ if (voltage >= 0.0)
+ {
+ chip->mixer_internal = compute_db_volume(3.55 - voltage);
+ chip->mixer_external = compute_db_volume(3.55 + 0.45 * (voltage * 0.25));
+ }
+ else
+ {
+ chip->mixer_internal = compute_db_volume(3.55 - 0.45 * (voltage * 0.25));
+ chip->mixer_external = compute_db_volume(3.55 + voltage);
+ }
+ break;
+
+ /* filter frequency varies from -4.0 to +4.0, at 0.375V/octave */
+ case CEM3394_FILTER_FREQENCY:
+ temp = chip->filter_zero_freq * pow(2.0, -voltage * (1.0 / 0.375));
+ chip->filter_step = (UINT32)(temp * chip->inv_sample_rate * FRACTION_ONE_D);
+ break;
+
+ /* modulation depth is 0.01 at 0V and 2.0 at 3.5V; how it grows from one to the other */
+ /* is still unclear at this point */
+ case CEM3394_MODULATION_AMOUNT:
+ if (voltage < 0.0)
+ chip->modulation_depth = (UINT32)(0.01 * FRACTION_ONE_D);
+ else if (voltage > 3.5)
+ chip->modulation_depth = (UINT32)(2.00 * FRACTION_ONE_D);
+ else
+ chip->modulation_depth = (UINT32)(((voltage * (1.0 / 3.5)) * 1.99 + 0.01) * FRACTION_ONE_D);
+ break;
+
+ /* this is not yet implemented */
+ case CEM3394_FILTER_RESONANCE:
+ break;
+ }
+}
+
+
+double cem3394_get_parameter(int chipnum, int input)
+{
+ sound_chip *chip = sndti_token(SOUND_CEM3394, chipnum);
+ double voltage = chip->values[input];
+
+ switch (input)
+ {
+ case CEM3394_VCO_FREQUENCY:
+ return chip->vco_zero_freq * pow(2.0, -voltage * (1.0 / 0.75));
+
+ case CEM3394_WAVE_SELECT:
+ return voltage;
+
+ case CEM3394_PULSE_WIDTH:
+ if (voltage <= 0.0)
+ return 0.0;
+ else if (voltage >= 2.0)
+ return 1.0;
+ else
+ return voltage * 0.5;
+
+ case CEM3394_FINAL_GAIN:
+ return compute_db(voltage);
+
+ case CEM3394_MIXER_BALANCE:
+ return voltage * 0.25;
+
+ case CEM3394_MODULATION_AMOUNT:
+ if (voltage < 0.0)
+ return 0.01;
+ else if (voltage > 3.5)
+ return 2.0;
+ else
+ return (voltage * (1.0 / 3.5)) * 1.99 + 0.01;
+
+ case CEM3394_FILTER_RESONANCE:
+ if (voltage < 0.0)
+ return 0.0;
+ else if (voltage > 2.5)
+ return 1.0;
+ else
+ return voltage * (1.0 / 2.5);
+
+ case CEM3394_FILTER_FREQENCY:
+ return chip->filter_zero_freq * pow(2.0, -voltage * (1.0 / 0.375));
+ }
+ return 0.0;
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void cem3394_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void cem3394_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = cem3394_set_info; break;
+ case SNDINFO_PTR_START: info->start = cem3394_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "CEM3394"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Analog Synth"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/cem3394.h b/src/emu/sound/cem3394.h
new file mode 100644
index 00000000000..adfac9e4a72
--- /dev/null
+++ b/src/emu/sound/cem3394.h
@@ -0,0 +1,45 @@
+#ifndef cem3394_h
+#define cem3394_h
+
+
+#define CEM3394_SAMPLE_RATE (44100*4)
+
+
+/* interface */
+struct cem3394_interface
+{
+ double vco_zero_freq; /* frequency at 0V for VCO */
+ double filter_zero_freq; /* frequency at 0V for filter */
+ void (*external)(int, int, short *);/* external input source */
+};
+
+/* inputs */
+enum
+{
+ CEM3394_VCO_FREQUENCY = 0,
+ CEM3394_MODULATION_AMOUNT,
+ CEM3394_WAVE_SELECT,
+ CEM3394_PULSE_WIDTH,
+ CEM3394_MIXER_BALANCE,
+ CEM3394_FILTER_RESONANCE,
+ CEM3394_FILTER_FREQENCY,
+ CEM3394_FINAL_GAIN
+};
+
+/* set the voltage going to a particular parameter */
+void cem3394_set_voltage(int chip, int input, double voltage);
+
+/* get the translated parameter associated with the given input as follows:
+ CEM3394_VCO_FREQUENCY: frequency in Hz
+ CEM3394_MODULATION_AMOUNT: scale factor, 0.0 to 2.0
+ CEM3394_WAVE_SELECT: voltage from this line
+ CEM3394_PULSE_WIDTH: width fraction, from 0.0 to 1.0
+ CEM3394_MIXER_BALANCE: balance, from -1.0 to 1.0
+ CEM3394_FILTER_RESONANCE: resonance, from 0.0 to 1.0
+ CEM3394_FILTER_FREQENCY: frequency, in Hz
+ CEM3394_FINAL_GAIN: gain, in dB */
+double cem3394_get_parameter(int chip, int input);
+
+
+#endif
+
diff --git a/src/emu/sound/custom.c b/src/emu/sound/custom.c
new file mode 100644
index 00000000000..61231665444
--- /dev/null
+++ b/src/emu/sound/custom.c
@@ -0,0 +1,90 @@
+#include "sndintrf.h"
+#include "custom.h"
+
+
+struct custom_info
+{
+ const struct CustomSound_interface *intf;
+ void * token;
+};
+
+
+
+static void *custom_start(int sndindex, int clock, const void *config)
+{
+ struct custom_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ /* stash a pointer and call the start routine */
+ info->intf = config;
+ if (info->intf->start)
+ {
+ info->token = (*info->intf->start)(clock, config);
+ if (!info->token)
+ return NULL;
+ }
+
+ return info;
+}
+
+
+static void custom_stop(void *token)
+{
+ struct custom_info *info = token;
+ if (info->intf->stop)
+ (*info->intf->stop)(info->token);
+}
+
+
+static void custom_reset(void *token)
+{
+ struct custom_info *info = token;
+ if (info->intf->reset)
+ (*info->intf->reset)(info->token);
+}
+
+
+void *custom_get_token(int index)
+{
+ struct custom_info *token = sndti_token(SOUND_CUSTOM, index);
+ return token->token;
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void custom_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void custom_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = custom_set_info; break;
+ case SNDINFO_PTR_START: info->start = custom_start; break;
+ case SNDINFO_PTR_STOP: info->stop = custom_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = custom_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Custom"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "None"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/custom.h b/src/emu/sound/custom.h
new file mode 100644
index 00000000000..45422b3579d
--- /dev/null
+++ b/src/emu/sound/custom.h
@@ -0,0 +1,15 @@
+#ifndef CUSTOM_H
+#define CUSTOM_H
+
+struct CustomSound_interface
+{
+ void *(*start)(int clock, const struct CustomSound_interface *config);
+ void (*stop)(void *token);
+ void (*reset)(void *token);
+ void *extra_data;
+};
+
+void *custom_get_token(int index);
+
+
+#endif
diff --git a/src/emu/sound/dac.c b/src/emu/sound/dac.c
new file mode 100644
index 00000000000..173f7d02e27
--- /dev/null
+++ b/src/emu/sound/dac.c
@@ -0,0 +1,187 @@
+#include "sndintrf.h"
+#include "streams.h"
+#include "dac.h"
+#include <math.h>
+
+
+/* default to 4x oversampling */
+#define DEFAULT_SAMPLE_RATE (48000 * 4)
+
+
+struct dac_info
+{
+ sound_stream *channel;
+ INT16 output;
+ INT16 UnsignedVolTable[256];
+ INT16 SignedVolTable[256];
+};
+
+
+
+static void DAC_update(void *param,stream_sample_t **inputs, stream_sample_t **_buffer,int length)
+{
+ struct dac_info *info = param;
+ stream_sample_t *buffer = _buffer[0];
+ INT16 out = info->output;
+
+ while (length--) *(buffer++) = out;
+}
+
+
+void DAC_data_w(int num,UINT8 data)
+{
+ struct dac_info *info = sndti_token(SOUND_DAC, num);
+ INT16 out = info->UnsignedVolTable[data];
+
+ if (info->output != out)
+ {
+ /* update the output buffer before changing the registers */
+ stream_update(info->channel);
+ info->output = out;
+ }
+}
+
+
+void DAC_signed_data_w(int num,UINT8 data)
+{
+ struct dac_info *info = sndti_token(SOUND_DAC, num);
+ INT16 out = info->SignedVolTable[data];
+
+ if (info->output != out)
+ {
+ /* update the output buffer before changing the registers */
+ stream_update(info->channel);
+ info->output = out;
+ }
+}
+
+
+void DAC_data_16_w(int num,UINT16 data)
+{
+ struct dac_info *info = sndti_token(SOUND_DAC, num);
+ INT16 out = data >> 1; /* range 0..32767 */
+
+ if (info->output != out)
+ {
+ /* update the output buffer before changing the registers */
+ stream_update(info->channel);
+ info->output = out;
+ }
+}
+
+
+void DAC_signed_data_16_w(int num,UINT16 data)
+{
+ struct dac_info *info = sndti_token(SOUND_DAC, num);
+ INT16 out = (INT32)data - (INT32)0x08000; /* range -32768..32767 */
+ /* casts avoid potential overflow on some ABIs */
+
+ if (info->output != out)
+ {
+ /* update the output buffer before changing the registers */
+ stream_update(info->channel);
+ info->output = out;
+ }
+}
+
+
+static void DAC_build_voltable(struct dac_info *info)
+{
+ int i;
+
+
+ /* build volume table (linear) */
+ for (i = 0;i < 256;i++)
+ {
+ info->UnsignedVolTable[i] = i * 0x101 / 2; /* range 0..32767 */
+ info->SignedVolTable[i] = i * 0x101 - 0x8000; /* range -32768..32767 */
+ }
+}
+
+
+static void *dac_start(int sndindex, int clock, const void *config)
+{
+ struct dac_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ DAC_build_voltable(info);
+
+ info->channel = stream_create(0,1,clock ? clock : DEFAULT_SAMPLE_RATE,info,DAC_update);
+ info->output = 0;
+
+ state_save_register_item("dac", sndindex, info->output);
+
+ return info;
+}
+
+
+
+WRITE8_HANDLER( DAC_0_data_w )
+{
+ DAC_data_w(0,data);
+}
+
+WRITE8_HANDLER( DAC_1_data_w )
+{
+ DAC_data_w(1,data);
+}
+
+WRITE8_HANDLER( DAC_2_data_w )
+{
+ DAC_data_w(2,data);
+}
+
+WRITE8_HANDLER( DAC_0_signed_data_w )
+{
+ DAC_signed_data_w(0,data);
+}
+
+WRITE8_HANDLER( DAC_1_signed_data_w )
+{
+ DAC_signed_data_w(1,data);
+}
+
+WRITE8_HANDLER( DAC_2_signed_data_w )
+{
+ DAC_signed_data_w(2,data);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void dac_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void dac_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = dac_set_info; break;
+ case SNDINFO_PTR_START: info->start = dac_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "DAC"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "TI Speech"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/dac.h b/src/emu/sound/dac.h
new file mode 100644
index 00000000000..3a83baf3394
--- /dev/null
+++ b/src/emu/sound/dac.h
@@ -0,0 +1,16 @@
+#ifndef DAC_H
+#define DAC_H
+
+void DAC_data_w(int num,UINT8 data);
+void DAC_signed_data_w(int num,UINT8 data);
+void DAC_data_16_w(int num,UINT16 data);
+void DAC_signed_data_16_w(int num,UINT16 data);
+
+WRITE8_HANDLER( DAC_0_data_w );
+WRITE8_HANDLER( DAC_1_data_w );
+WRITE8_HANDLER( DAC_2_data_w );
+WRITE8_HANDLER( DAC_0_signed_data_w );
+WRITE8_HANDLER( DAC_1_signed_data_w );
+WRITE8_HANDLER( DAC_2_signed_data_w );
+
+#endif
diff --git a/src/emu/sound/disc_dev.c b/src/emu/sound/disc_dev.c
new file mode 100644
index 00000000000..dd7351f0182
--- /dev/null
+++ b/src/emu/sound/disc_dev.c
@@ -0,0 +1,1372 @@
+/************************************************************************
+ *
+ * MAME - Discrete sound system emulation library
+ *
+ * Written by Keith Wilkins (mame@dysfunction.demon.co.uk)
+ *
+ * (c) K.Wilkins 2000
+ * (c) D.Renaud 2003-2004
+ *
+ ************************************************************************
+ *
+ * DSD_555_ASTBL - NE555 Simulation - Astable mode
+ * DSD_555_MSTBL - NE555 Simulation - Monostable mode
+ * DSD_555_CC - NE555 Constant Current VCO
+ * DSD_555_VCO1 - Op-Amp linear ramp based 555 VCO
+ * DSD_566 - NE566 Simulation
+ *
+ ************************************************************************
+ *
+ * You will notice that the code for a lot of these routines are similar.
+ * I tried to make a common charging routine, but there are too many
+ * minor differences that affect each module.
+ *
+ ************************************************************************/
+
+#define DEFAULT_555_CAP_BLEED RES_M(10)
+
+struct dsd_555_astbl_context
+{
+ int error;
+ int use_ctrlv;
+ int output_type;
+ int output_is_ac;
+ double ac_shift; // DC shift needed to make waveform ac
+ int flip_flop; // 555 flip/flop output state
+ double x_init;
+ double cap_voltage; // voltage on cap
+ double threshold;
+ double trigger;
+ double output_high_voltage; // Logic 1 voltage level
+ double v555;
+};
+
+struct dsd_555_mstbl_context
+{
+ int error;
+ int trig_is_logic;
+ int trig_discharges_cap;
+ int output_type;
+ int output_is_ac;
+ double ac_shift; // DC shift needed to make waveform ac
+ int flip_flop; // 555 flip/flop output state
+ double cap_voltage; // voltage on cap
+ double threshold;
+ double trigger;
+ double output_high_voltage; // Logic 1 voltage level
+};
+
+struct dsd_555_cc_context
+{
+ int error;
+ unsigned int type; // type of 555cc circuit
+ int output_type;
+ int output_is_ac;
+ double ac_shift; // DC shift needed to make waveform ac
+ int flip_flop; // 555 flip/flop output state
+ double x_init;
+ double cap_voltage; // voltage on cap
+ double threshold;
+ double trigger;
+ double output_high_voltage; // Logic 1 voltage level
+};
+
+struct dsd_555_vco1_context
+{
+ int ctrlv_is_node;
+ int output_type;
+ int output_is_ac;
+ double ac_shift; // DC shift needed to make waveform ac
+ int flip_flop; // flip/flop output state
+ double output_high_voltage; // 555 high voltage
+ double threshold; // falling threshold
+ double trigger; // rising threshold
+ double i_charge; // charge current
+ double i_discharge; // discharge current
+ double cap_voltage; // current capacitor voltage
+};
+
+struct dsd_566_context
+{
+ int error;
+ unsigned int state[2]; // keeps track of excess flip_flop changes during the current step
+ int flip_flop; // 566 flip/flop output state
+ double cap_voltage; // voltage on cap
+ double vDiff; // voltage difference between vPlus and vNeg
+ double vSqrLow; // voltage for a squarewave at low
+ double vSqrHigh; // voltage for a squarewave at high
+ double thresholdLow; // falling threshold
+ double thresholdHigh; // rising threshold
+ double triOffset; // used to shift a triangle to AC
+};
+
+
+
+/* Test to see if basic 555 options are valid. */
+static int test_555(double threshold, double trigger, double v555, int node)
+{
+ int error = 0;
+ if (threshold > v555)
+ {
+ logerror("[Threshold > B+]");
+ error = 1;
+ }
+ if (threshold <= trigger)
+ {
+ logerror("[Threshold <= Trigger]");
+ error = 1;
+ }
+ if (trigger < 0)
+ {
+ logerror("[Trigger < 0]");
+ error = 1;
+ }
+ if (v555 <= 0)
+ {
+ logerror("[B+ <= 0]");
+ error = 1;
+ }
+ if (error)
+ logerror(" - NODE_%d DISABLED!\n", node - NODE_00);
+ return error;
+}
+
+
+/************************************************************************
+ *
+ * DSD_555_ASTBL - - 555 Astable simulation
+ *
+ * input[0] - Reset value
+ * input[1] - R1 value
+ * input[2] - R2 value
+ * input[3] - C value
+ * input[4] - Control Voltage value
+ *
+ * also passed discrete_555_desc structure
+ *
+ * Jan 2004, D Renaud.
+ ************************************************************************/
+#define DSD_555_ASTBL__RESET (! *(node->input[0]))
+#define DSD_555_ASTBL__R1 (*(node->input[1]))
+#define DSD_555_ASTBL__R2 (*(node->input[2]))
+#define DSD_555_ASTBL__C (*(node->input[3]))
+#define DSD_555_ASTBL__CTRLV (*(node->input[4]))
+
+void dsd_555_astbl_step(node_description *node)
+{
+ const discrete_555_desc *info = node->custom;
+ struct dsd_555_astbl_context *context = node->context;
+
+ int count_f = 0;
+ int count_r = 0;
+ double dt; // change in time
+ double xTime; // time since change happened
+ double tRC = 0; // RC time constant
+ double vC = context->cap_voltage; // Current voltage on capacitor, before dt
+ double vCnext = 0; // Voltage on capacitor, after dt
+
+ if(DSD_555_ASTBL__RESET || context->error)
+ {
+ /* We are in RESET */
+ /* If there was a fatal INIT error then we will also stay in RESET */
+ node->output = 0;
+ context->flip_flop = 1;
+ context->cap_voltage = 0;
+ return;
+ }
+
+ /* Check: if the Control Voltage node is connected. */
+ if (context->use_ctrlv)
+ {
+ /* If CV is less then .25V, the circuit will oscillate way out of range.
+ * So we will just ignore it when it happens. */
+ if (DSD_555_ASTBL__CTRLV < .25) return;
+ /* If it is a node then calculate thresholds based on Control Voltage */
+ context->threshold = DSD_555_ASTBL__CTRLV;
+ context->trigger = DSD_555_ASTBL__CTRLV / 2.0;
+ /* Since the thresholds may have changed we need to update the FF */
+ if (vC >= context->threshold)
+ {
+ context->flip_flop = 0;
+ count_f++;
+ }
+ else
+ if (vC <= context->trigger)
+ {
+ context->flip_flop = 1;
+ count_r++;
+ }
+ }
+
+ /* Calculate future capacitor voltage.
+ * ref@ http://www.physics.rutgers.edu/ugrad/205/capacitance.html
+ * The formulas from the ref pages have been modified to reflect that we are stepping the change.
+ * dt = time of sample (1/sample frequency)
+ * VC = Voltage across capacitor
+ * VC' = Future voltage across capacitor
+ * Vc = Voltage change
+ * Vr = is the voltage across the resistor. For charging it is Vcc - VC. Discharging it is VC - 0.
+ * R = R1+R2 (for charging) R = R2 for discharging.
+ * Vc = Vr*(1-exp(-dt/(R*C)))
+ * VC' = VC + Vc (for charging) VC' = VC - Vc for discharging.
+ *
+ * We will also need to calculate the amount of time we overshoot the thresholds
+ * dt = amount of time we overshot
+ * Vc = voltage change overshoot
+ * dt = R*C(log(1/(1-(Vc/Vr))))
+ */
+
+ dt = discrete_current_context->sample_time;
+ xTime = context->x_init;
+
+ /* Sometimes a switching network is used to setup the capacitance.
+ * These may select no capacitor, causing oscillation to stop.
+ */
+ if (DSD_555_ASTBL__C == 0)
+ {
+ context->flip_flop = 1;
+ /* The voltage goes high because the cap circuit is open. */
+ vCnext = context->v555;
+ vC = context->v555;
+ context->cap_voltage = 0;
+ }
+ else
+ {
+ /* Keep looping until all toggling in time sample is used up. */
+ do
+ {
+ if (context->flip_flop)
+ {
+ if (DSD_555_ASTBL__R1 == 0)
+ {
+ /* Oscillation disabled because there is no longer any charge resistor. */
+ /* Bleed the cap due to circuit losses. */
+ tRC = DEFAULT_555_CAP_BLEED * DSD_555_ASTBL__C;
+ vCnext = vC - (vC * (1.0 - exp(-(dt / tRC))));
+ dt = 0;
+ }
+ else
+ {
+ /* Charging */
+ /* Use quick charge if specified. */
+ tRC = (DSD_555_ASTBL__R1 + ((info->options & DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE) ? 0 : DSD_555_ASTBL__R2)) * DSD_555_ASTBL__C;
+ vCnext = vC + ((context->v555 - vC) * (1.0 - exp(-(dt / tRC))));
+ dt = 0;
+
+ /* has it charged past upper limit? */
+ if (vCnext > context->threshold)
+ {
+ /* calculate the overshoot time */
+ dt = tRC * log(1.0 / (1.0 - ((vCnext - context->threshold) / (context->v555 - vC))));
+ xTime = dt;
+ vC = context->threshold;
+ context->flip_flop = 0;
+ count_f++;
+ }
+ }
+ }
+ else
+ {
+ /* Discharging */
+ if(DSD_555_ASTBL__R2!=0)
+ {
+ tRC = DSD_555_ASTBL__R2 * DSD_555_ASTBL__C;
+ vCnext = vC - (vC * (1 - exp(-(dt / tRC))));
+ dt = 0;
+ }
+ else
+ {
+ vCnext = context->trigger;
+ dt = 0;
+ }
+
+ /* has it discharged past lower limit? */
+ if (vCnext < context->trigger)
+ {
+ /* calculate the overshoot time */
+ dt = tRC * log(1.0 / (1.0 - ((context->trigger - vCnext) / vC)));
+ xTime = dt;
+ vC = context->trigger;
+ context->flip_flop = 1;
+ count_r++;
+ }
+ }
+ } while(dt);
+
+ context->cap_voltage = vCnext;
+ }
+
+ /* Convert last switch time to a ratio */
+ xTime = xTime / discrete_current_context->sample_time;
+
+ switch (context->output_type)
+ {
+ case DISC_555_OUT_SQW:
+ node->output = context->flip_flop * context->output_high_voltage + context->ac_shift;
+ break;
+ case DISC_555_OUT_CAP:
+ node->output = vCnext;
+ /* Fake it to AC if needed */
+ if (context->output_is_ac)
+ node->output -= context->threshold * 3.0 /4.0;
+ break;
+ case DISC_555_OUT_ENERGY:
+ node->output = context->output_high_voltage * (context->flip_flop ? xTime : (1 - xTime));
+ node->output += context->ac_shift;
+ break;
+ case DISC_555_OUT_LOGIC_X:
+ node->output = context->flip_flop + xTime;
+ break;
+ case DISC_555_OUT_COUNT_F_X:
+ node->output = count_f ? count_f + xTime : count_f;
+ break;
+ case DISC_555_OUT_COUNT_R_X:
+ node->output = count_r ? count_r + xTime : count_r;
+ break;
+ case DISC_555_OUT_COUNT_F:
+ node->output = count_f;
+ break;
+ case DISC_555_OUT_COUNT_R:
+ node->output = count_r;
+ break;
+ }
+}
+
+void dsd_555_astbl_reset(node_description *node)
+{
+ const discrete_555_desc *info = node->custom;
+ struct dsd_555_astbl_context *context = node->context;
+
+ context->use_ctrlv = (node->input_is_node >> 4) & 1;
+ context->output_type = info->options & DISC_555_OUT_MASK;
+
+ /* Use the supplied values or set to defaults. */
+ context->output_high_voltage = (info->v555high == DEFAULT_555_HIGH) ? info->v555 - 1.2 : info->v555high;
+ if ((DSD_555_ASTBL__CTRLV != -1) && !context->use_ctrlv)
+ {
+ /* Setup based on supplied static value */
+ context->threshold = DSD_555_ASTBL__CTRLV;
+ context->trigger = DSD_555_ASTBL__CTRLV / 2.0;
+ }
+ else
+ {
+ /* use values passed in structure */
+ context->threshold = (info->threshold555 == DEFAULT_555_THRESHOLD) ? info->v555 *2 /3 : info->threshold555;
+ context->trigger = (info->trigger555 == DEFAULT_555_TRIGGER) ? info->v555 /3 : info->trigger555;
+ }
+
+ context->output_is_ac = info->options & DISC_555_OUT_AC;
+ /* Calculate DC shift needed to make squarewave waveform AC */
+ context->ac_shift = context->output_is_ac ? -context->output_high_voltage / 2.0 : 0;
+
+ context->error = test_555(context->threshold, context->trigger, info->v555, node->node);
+
+ context->v555 = (info->options & DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE) ? info->v555 - 0.5: info->v555;
+ context->flip_flop = 1;
+ context->cap_voltage = 0;
+
+ /* Used to adjust the ratio depending on if it is the extra percent or energy */
+ context->x_init = 0;
+ if (context->output_type == DISC_555_OUT_ENERGY)
+ context->x_init = discrete_current_context->sample_time;
+
+ /* Step to set the output */
+ dsd_555_astbl_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSD_555_MSTBL - 555 Monostable simulation
+ *
+ * input[0] - Reset value
+ * input[1] - Trigger input
+ * input[2] - R2 value
+ * input[3] - C value
+ *
+ * also passed discrete_555_desc structure
+ *
+ * Oct 2004, D Renaud.
+ ************************************************************************/
+#define DSD_555_MSTBL__RESET (! *(node->input[0]))
+#define DSD_555_MSTBL__TRIGGER (*(node->input[1]))
+#define DSD_555_MSTBL__R (*(node->input[2]))
+#define DSD_555_MSTBL__C (*(node->input[3]))
+
+void dsd_555_mstbl_step(node_description *node)
+{
+ const discrete_555_desc *info = node->custom;
+ struct dsd_555_mstbl_context *context = node->context;
+
+ double vC; // Current voltage on capacitor, before dt
+ double vCnext = 0; // Voltage on capacitor, after dt
+
+ if(DSD_555_MSTBL__RESET || context->error)
+ {
+ /* We are in RESET */
+ /* If there was a fatal INIT error then we will also stay in RESET */
+ node->output = 0;
+ context->flip_flop = 0;
+ context->cap_voltage = 0;
+ }
+ else
+ {
+ int trigger;
+
+ if (context->trig_is_logic)
+ trigger = !DSD_555_MSTBL__TRIGGER;
+ else
+ trigger = DSD_555_MSTBL__TRIGGER < context->trigger;
+
+ if (context->trig_discharges_cap && trigger)
+ context->cap_voltage = 0;
+
+ if (!context->flip_flop)
+ {
+ /* Wait for trigger */
+ if (trigger)
+ context->flip_flop = 1;
+ }
+ else
+ {
+ vC = context->cap_voltage;
+
+ /* Sometimes a switching network is used to setup the capacitance.
+ * These may select 'no' capacitor, causing oscillation to stop.
+ */
+ if (DSD_555_MSTBL__C == 0)
+ {
+ context->flip_flop = 0;
+ /* The voltage goes high because the cap circuit is open. */
+ vCnext = info->v555;
+ vC = info->v555;
+ context->cap_voltage = 0;
+ }
+ else
+ {
+ /* Charging */
+ vCnext = vC + ((info->v555 - vC) * (1.0 - exp(-(discrete_current_context->sample_time / (DSD_555_MSTBL__R * DSD_555_MSTBL__C)))));
+
+ /* Has it charged past upper limit? */
+ /* If trigger is still enabled, then we keep charging,
+ * regardless of threshold. */
+ if ((vCnext >= context->threshold) && !trigger)
+ {
+ vCnext = 0;
+ vC = context->threshold;
+ context->flip_flop = 0;
+ }
+ }
+
+ context->cap_voltage = vCnext;
+
+ switch (info->options & DISC_555_OUT_MASK)
+ {
+ case DISC_555_OUT_SQW:
+ node->output = context->flip_flop * context->output_high_voltage;
+ /* Fake it to AC if needed */
+ if (context->output_is_ac)
+ node->output -= context->output_high_voltage / 2.0;
+ break;
+ case DISC_555_OUT_CAP:
+ node->output = vCnext;
+ /* Fake it to AC if needed */
+ if (context->output_is_ac)
+ node->output -= context->threshold * 3.0 /4.0;
+ break;
+ }
+ }
+ }
+}
+
+void dsd_555_mstbl_reset(node_description *node)
+{
+ const discrete_555_desc *info = node->custom;
+ struct dsd_555_mstbl_context *context = node->context;
+
+ context->output_type = info->options & DISC_555_OUT_MASK;
+ if ((context->output_type == DISC_555_OUT_COUNT_F) || (context->output_type == DISC_555_OUT_COUNT_R))
+ {
+ discrete_log("Invalid Output type in NODE_%d.\n", node->node - NODE_00);
+ context->output_type = DISC_555_OUT_SQW;
+ }
+
+ /* Use the supplied values or set to defaults. */
+ context->threshold = (info->threshold555 == DEFAULT_555_THRESHOLD) ? info->v555 *2 /3 : info->threshold555;
+ context->trigger = (info->trigger555 == DEFAULT_555_TRIGGER) ? info->v555 /3 : info->trigger555;
+ context->output_high_voltage = (info->v555high == DEFAULT_555_HIGH) ? info->v555 - 1.2 : info->v555high;
+
+ context->output_is_ac = info->options & DISC_555_OUT_AC;
+ /* Calculate DC shift needed to make squarewave waveform AC */
+ context->ac_shift = context->output_is_ac ? -context->output_high_voltage / 2.0 : 0;
+
+ context->error = test_555(context->threshold, context->trigger, info->v555, node->node);
+
+ context->trig_is_logic = (info->options & DISC_555_TRIGGER_IS_VOLTAGE) ? 0: 1;
+ context->trig_discharges_cap = (info->options & DISC_555_TRIGGER_DISCHARGES_CAP) ? 1: 0;
+
+ context->flip_flop = 0;
+ context->cap_voltage = 0;
+
+ node->output = 0;
+}
+
+
+/************************************************************************
+ *
+ * DSD_555_CC - Usage of node_description values
+ *
+ * input[0] - Reset input value
+ * input[1] - Voltage input for Constant current source.
+ * input[2] - R value to set CC current.
+ * input[3] - C value
+ * input[4] - rBias value
+ * input[5] - rGnd value
+ * input[6] - rDischarge value
+ *
+ * also passed discrete_555_cc_desc structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DSD_555_CC__RESET (! *(node->input[0]))
+#define DSD_555_CC__VIN (*(node->input[1]))
+#define DSD_555_CC__R (*(node->input[2]))
+#define DSD_555_CC__C (*(node->input[3]))
+#define DSD_555_CC__RBIAS (*(node->input[4]))
+#define DSD_555_CC__RGND (*(node->input[5]))
+#define DSD_555_CC__RDIS (*(node->input[6]))
+
+void dsd_555_cc_step(node_description *node)
+{
+ const discrete_555_cc_desc *info = node->custom;
+ struct dsd_555_cc_context *context = node->context;
+
+ int count_f = 0;
+ int count_r = 0;
+ double i; // Charging current created by vIn
+ double rC = 0; // Equivalent charging resistor
+ double rD = 0; // Equivalent discharging resistor
+ double vi = 0; // Equivalent voltage from current source
+ double vB = 0; // Equivalent voltage from bias voltage
+ double v = 0; // Equivalent voltage total from current source and bias circuit if used
+ double dt; // change in time
+ double xTime; // time since change happened
+ double tRC; // RC time constant
+ double vC; // Current voltage on capacitor, before dt
+ double vCnext = 0; // Voltage on capacitor, after dt
+ double viLimit; // vIn and the junction voltage limit the max charging voltage from i
+ double rTemp; // play thing
+
+
+ if (DSD_555_CC__RESET || context->error)
+ {
+ /* We are in RESET */
+ /* If there was a fatal INIT error then we will also stay in RESET */
+ node->output = 0;
+ context->flip_flop = 1;
+ context->cap_voltage = 0;
+ return;
+ }
+
+ dt = discrete_current_context->sample_time; // Change in time
+ xTime = context->x_init;
+ vC = context->cap_voltage; // Set to voltage before change
+ viLimit = DSD_555_CC__VIN + info->vCCjunction; // the max vC can be and still be charged by i
+ /* Calculate charging current */
+ i = (info->vCCsource - viLimit) / DSD_555_CC__R;
+ if ( i < 0) i = 0;
+
+ if (info->options & DISCRETE_555_CC_TO_CAP)
+ {
+ vi = i * DSD_555_CC__RDIS;
+ }
+ else
+ switch (context->type) // see dsd_555_cc_reset for descriptions
+ {
+ case 1:
+ rD = DSD_555_CC__RDIS;
+ case 0:
+ break;
+ case 3:
+ rD = (DSD_555_CC__RDIS * DSD_555_CC__RGND) / (DSD_555_CC__RDIS + DSD_555_CC__RGND);
+ case 2:
+ rC = DSD_555_CC__RGND;
+ vi = i * rC;
+ break;
+ case 4:
+ rC = DSD_555_CC__RBIAS;
+ vi = i * rC;
+ vB = info->v555;
+ break;
+ case 5:
+ rC = DSD_555_CC__RBIAS + DSD_555_CC__RDIS;
+ vi = i * DSD_555_CC__RBIAS;
+ vB = info->v555;
+ rD = DSD_555_CC__RDIS;
+ break;
+ case 6:
+ rC = (DSD_555_CC__RBIAS * DSD_555_CC__RGND) / (DSD_555_CC__RBIAS + DSD_555_CC__RGND);
+ vi = i * rC;
+ vB = info->v555 * (DSD_555_CC__RGND / (DSD_555_CC__RBIAS + DSD_555_CC__RGND));
+ break;
+ case 7:
+ rTemp = DSD_555_CC__RBIAS + DSD_555_CC__RDIS;
+ rC = (rTemp * DSD_555_CC__RGND) / (rTemp + DSD_555_CC__RGND);
+ rTemp += DSD_555_CC__RGND;
+ rTemp = DSD_555_CC__RGND / rTemp; // now has voltage divider ratio, not resistance
+ vi = i * DSD_555_CC__RBIAS * rTemp;
+ vB = info->v555 * rTemp;
+ rD = (DSD_555_CC__RGND * DSD_555_CC__RDIS) / (DSD_555_CC__RGND + DSD_555_CC__RDIS);
+ break;
+ }
+
+ /* Keep looping until all toggling in time sample is used up. */
+ do
+ {
+ if (context->type <= 1)
+ {
+ /* Standard constant current charge */
+ if (context->flip_flop)
+ {
+ if (i == 0)
+ {
+ /* No charging current, so we have to discharge the cap
+ * due to cap and circuit losses.
+ */
+ tRC = DEFAULT_555_CAP_BLEED * DSD_555_CC__C;
+ vCnext = vC - (vC * (1.0 - exp(-(dt / tRC))));
+ dt = 0;
+ }
+ else
+ {
+ /* Charging */
+ /* iC=C*dv/dt works out to dv=iC*dt/C */
+ vCnext = vC + (i * dt / DSD_555_CC__C);
+ /* Yes, if the cap voltage has reached the max voltage it can,
+ * and the 555 threshold has not been reached, then oscillation stops.
+ * This is the way the actual electronics works.
+ * This is why you never play with the pots after being factory adjusted
+ * to work in the proper range. */
+ if (vCnext > viLimit) vCnext = viLimit;
+ dt = 0;
+
+ /* has it charged past upper limit? */
+ if (vCnext >= context->threshold)
+ {
+ /* calculate the overshoot time */
+ dt = DSD_555_CC__C * (vCnext - context->threshold) / i;
+ xTime = dt;
+ vC = context->threshold;
+ context->flip_flop = 0;
+ count_f++;
+ }
+ }
+ }
+ else if (DSD_555_CC__RDIS)
+ {
+ /* Discharging */
+ tRC = DSD_555_CC__RDIS * DSD_555_CC__C;
+
+ if (info->options & DISCRETE_555_CC_TO_CAP)
+ {
+ /* Asteroids - Special Case */
+ /* Charging in discharge mode */
+ /* If the cap voltage is past the current source charging limit
+ * then only the bias voltage will charge the cap. */
+ v = (vC < viLimit) ? vi : viLimit;
+ vCnext = vC + ((v - vC) * (1.0 - exp(-(dt / tRC))));
+ }
+ else
+ {
+ vCnext = vC - (vC * (1.0 - exp(-(dt / tRC))));
+ }
+
+ dt = 0;
+ /* has it discharged past lower limit? */
+ if (vCnext <= context->trigger)
+ {
+ dt = tRC * log(1.0 / (1.0 - ((context->trigger - vCnext) / vC)));
+ xTime = dt;
+ vC = context->trigger;
+ context->flip_flop = 1;
+ count_r++;
+ }
+ }
+ else // Immediate discharge. No change in dt.
+ {
+ vC = context->trigger;
+ context->flip_flop = 1;
+ count_r++;
+ }
+ }
+ else
+ {
+ /* The constant current gets changed to a voltage due to a load resistor. */
+ if (context->flip_flop)
+ {
+ if ((i == 0) && (DSD_555_CC__RBIAS == 0))
+ {
+ /* No charging current, so we have to discharge the cap
+ * due to rGnd.
+ */
+ tRC = DSD_555_CC__RGND * DSD_555_CC__C;
+ vCnext = vC - (vC * (1.0 - exp(-(dt / tRC))));
+ dt = 0;
+ }
+ else
+ {
+ /* Charging */
+ /* If the cap voltage is past the current source charging limit
+ * then only the bias voltage will charge the cap. */
+ v = vB;
+ if (vC < viLimit) v += vi;
+ else if (context->type <= 3) v = viLimit;
+
+ tRC = rC * DSD_555_CC__C;
+ vCnext = vC + ((v - vC) * (1.0 - exp(-(dt / tRC))));
+ dt = 0;
+
+ /* has it charged past upper limit? */
+ if (vCnext >= context->threshold)
+ {
+ /* calculate the overshoot time */
+ dt = tRC * log(1.0 / (1.0 - ((vCnext - context->threshold) / (v - vC))));
+ xTime = dt;
+ vC = context->threshold;
+ context->flip_flop = 0;
+ count_f++;
+ }
+ }
+ }
+ else /* Discharging */
+ if (rD)
+ {
+ tRC = rD * DSD_555_CC__C;
+ vCnext = vC - (vC * (1.0 - exp(-(dt / tRC))));
+ dt = 0;
+
+ /* has it discharged past lower limit? */
+ if (vCnext <= context->trigger)
+ {
+ /* calculate the overshoot time */
+ dt = tRC * log(1.0 / (1.0 - ((context->trigger - vCnext) / vC)));
+ xTime = dt;
+ vC = context->trigger;
+ context->flip_flop = 1;
+ count_r++;
+ }
+ }
+ else // Immediate discharge. No change in dt.
+ {
+ vC = context->trigger;
+ context->flip_flop = 1;
+ count_r++;
+ }
+ }
+ } while(dt);
+
+ context->cap_voltage = vCnext;
+
+ /* Convert last switch time to a ratio */
+ xTime = xTime / discrete_current_context->sample_time;
+
+ switch (context->output_type)
+ {
+ case DISC_555_OUT_SQW:
+ if (count_r && (~context->type & 0x01))
+ {
+ /* There has been an immediate discharge, so keep low for 1 sample. */
+ node->output = 0;
+ }
+ else
+ node->output = context->flip_flop * context->output_high_voltage;
+ /* Fake it to AC if needed */
+ node->output += context->ac_shift;
+ break;
+ case DISC_555_OUT_CAP:
+ node->output = vCnext + context->ac_shift;
+ break;
+ case DISC_555_OUT_ENERGY:
+ node->output = context->output_high_voltage * (context->flip_flop ? xTime : (1 - xTime));
+ node->output += context->ac_shift;
+ break;
+ case DISC_555_OUT_LOGIC_X:
+ node->output = context->flip_flop + xTime;
+ break;
+ case DISC_555_OUT_COUNT_F_X:
+ node->output = count_f + xTime;
+ break;
+ case DISC_555_OUT_COUNT_R_X:
+ node->output = count_r + xTime;
+ break;
+ case DISC_555_OUT_COUNT_F:
+ node->output = count_f;
+ break;
+ case DISC_555_OUT_COUNT_R:
+ node->output = count_r;
+ break;
+ }
+}
+
+void dsd_555_cc_reset(node_description *node)
+{
+ const discrete_555_cc_desc *info = node->custom;
+ struct dsd_555_cc_context *context = node->context;
+
+ context->flip_flop=1;
+ context->cap_voltage = 0;
+
+ context->output_type = info->options & DISC_555_OUT_MASK;
+
+ /* Used to adjust the ratio depending on if it is the extra percent or energy */
+ context->x_init = 0;
+ if (context->output_type == DISC_555_OUT_ENERGY)
+ context->x_init = discrete_current_context->sample_time;
+
+ /* Use the supplied values or set to defaults. */
+ context->threshold = (info->threshold555 == DEFAULT_555_THRESHOLD) ? info->v555 *2 /3 : info->threshold555;
+ context->trigger = (info->trigger555 == DEFAULT_555_TRIGGER) ? info->v555 /3 : info->trigger555;
+ context->output_high_voltage = (info->v555high == DEFAULT_555_HIGH) ? info->v555 - 1.2 : info->v555high;
+
+ context->output_is_ac = info->options & DISC_555_OUT_AC;
+ /* Calculate DC shift needed to make squarewave waveform AC */
+ context->ac_shift = context->output_is_ac ? -context->output_high_voltage / 2.0 : 0;
+
+ context->error = test_555(context->threshold, context->trigger, info->v555, node->node);
+
+ /* There are 8 different types of basic oscillators
+ * depending on the resistors used. We will determine
+ * the type of circuit at reset, because the ciruit type
+ * is constant. */
+ context->type = (DSD_555_CC__RDIS > 0) | ((DSD_555_CC__RGND > 0) << 1) | ((DSD_555_CC__RBIAS > 0) << 2);
+ /*
+ * TYPES:
+ * Note: These are equivalent circuits shown without the 555 circuitry.
+ * See the schematic in src\sound\discrete.h for full hookup info.
+ *
+ * DISCRETE_555_CC_TO_DISCHARGE_PIN
+ * When the CC source is connected to the discharge pin, it allows the
+ * circuit to charge when the 555 is in charge mode. But when in discharge
+ * mode, the CC source is grounded, disabling it's effect.
+ *
+ * [0]
+ * No resistors. Straight constant current charge of capacitor.
+ * When there is not any charge current, the cap will bleed off.
+ * Once the lower threshold(trigger) is reached, the output will
+ * go high but the cap will continue to discharge due to losses.
+ * .------+---> cap_voltage CHARGING:
+ * | | dv (change in voltage) compared to dt (change in time in seconds).
+ * .---. --- dv = i * dt / C; where i is current in amps and C is capacitance in farads.
+ * | i | --- C cap_voltage = cap_voltage + dv
+ * '---' |
+ * | | DISCHARGING:
+ * gnd gnd instantaneous
+ *
+ * [1]
+ * Same as type 1 but with rDischarge. rDischarge has no effect on the charge rate because
+ * of the constant current source i.
+ * When there is not any charge current, the cap will bleed off.
+ * Once the lower threshold(trigger) is reached, the output will
+ * go high but the cap will continue to discharge due to losses.
+ * .----ZZZ-----+---> cap_voltage CHARGING:
+ * | rDischarge | dv (change in voltage) compared to dt (change in time in seconds).
+ * .---. --- dv = i * dt / C; where i is current in amps and C is capacitance in farads.
+ * | i | --- C cap_voltage = cap_voltage + dv
+ * '---' |
+ * | | DISCHARGING:
+ * gnd gnd thru rDischarge
+ *
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! IMPORTANT NOTE ABOUT TYPES 3 - 7 !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ *
+ * From here on in all the circuits have either an rBias or rGnd resistor.
+ * This converts the constant current into a voltage source.
+ * So all the remaining circuit types will be converted to this circuit.
+ * When discharging, rBias is out of the equation because the 555 is grounding the circuit
+ * after that point.
+ *
+ * .------------. Rc Rc is the equivilent circuit resistance.
+ * | v |----ZZZZ---+---> cap_voltage v is the equivilent circuit voltage.
+ * | | |
+ * '------------' --- Then the standard RC charging formula applies.
+ * | --- C
+ * | | NOTE: All the following types are converted to Rc and v values.
+ * gnd gnd
+ *
+ * [2]
+ * When there is not any charge current, the cap will bleed off.
+ * Once the lower threshold(trigger) is reached, the output will
+ * go high but the cap will continue to discharge due to rGnd.
+ * .-------+------+------> cap_voltage CHARGING:
+ * | | | v = vi = i * rGnd
+ * .---. --- Z Rc = rGnd
+ * | i | --- C Z rGnd
+ * '---' | | DISCHARGING:
+ * | | | instantaneous
+ * gnd gnd gnd
+ *
+ * [3]
+ * When there is not any charge current, the cap will bleed off.
+ * Once the lower threshold(trigger) is reached, the output will
+ * go high but the cap will continue to discharge due to rGnd.
+ * .----ZZZ-----+------+------> cap_voltage CHARGING:
+ * | rDischarge | | v = vi = i * rGnd
+ * .---. --- Z Rc = rGnd
+ * | i | --- C Z rGnd
+ * '---' | | DISCHARGING:
+ * | | | thru rDischarge || rGnd ( || means in parallel)
+ * gnd gnd gnd
+ *
+ * [4]
+ * .---ZZZ---+------------+-------------> cap_voltage CHARGING:
+ * | rBias | | Rc = rBias
+ * .-------. .---. --- vi = i * rBias
+ * | vBias | | i | --- C v = vBias + vi
+ * '-------' '---' |
+ * | | | DISCHARGING:
+ * gnd gnd gnd instantaneous
+ *
+ * [5]
+ * .---ZZZ---+----ZZZ-----+-------------> cap_voltage CHARGING:
+ * | rBias | rDischarge | Rc = rBias + rDischarge
+ * .-------. .---. --- vi = i * rBias
+ * | vBias | | i | --- C v = vBias + vi
+ * '-------' '---' |
+ * | | | DISCHARGING:
+ * gnd gnd gnd thru rDischarge
+ *
+ * [6]
+ * .---ZZZ---+------------+------+------> cap_voltage CHARGING:
+ * | rBias | | | Rc = rBias || rGnd
+ * .-------. .---. --- Z vi = i * Rc
+ * | vBias | | i | --- C Z rGnd v = vBias * (rGnd / (rBias + rGnd)) + vi
+ * '-------' '---' | |
+ * | | | | DISCHARGING:
+ * gnd gnd gnd gnd instantaneous
+ *
+ * [7]
+ * .---ZZZ---+----ZZZ-----+------+------> cap_voltage CHARGING:
+ * | rBias | rDischarge | | Rc = (rBias + rDischarge) || rGnd
+ * .-------. .---. --- Z vi = i * rBias * (rGnd / (rBias + rDischarge + rGnd))
+ * | vBias | | i | --- C Z rGnd v = vBias * (rGnd / (rBias + rDischarge + rGnd)) + vi
+ * '-------' '---' | |
+ * | | | | DISCHARGING:
+ * gnd gnd gnd gnd thru rDischarge || rGnd
+ */
+
+ /*
+ * DISCRETE_555_CC_TO_CAP
+ *
+ * When the CC source is connected to the capacitor, it allows the
+ * current to charge the cap while it is in discharge mode, slowing the
+ * discharge. So in charge mode it charges linearly from the constant
+ * current cource. But when in discharge mode it behaves like circuit
+ * type 2 above.
+ * .-------+------+------> cap_voltage CHARGING:
+ * | | | dv = i * dt / C
+ * .---. --- Z cap_voltage = cap_voltage + dv
+ * | i | --- C Z rDischarge
+ * '---' | | DISCHARGING:
+ * | | | v = vi = i * rGnd
+ * gnd gnd discharge Rc = rDischarge
+ */
+
+ /* Step to set the output */
+ dsd_555_cc_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSD_555_VCO1 - Usage of node_description values
+ *
+ * input[0] - Reset input value
+ * input[1] - Modulation Voltage (Vin1)
+ * input[2] - Control Voltage (Vin2)
+ *
+ * also passed discrete_5555_vco1_desc structure
+ *
+ * Apr 2006, D Renaud.
+ ************************************************************************/
+#define DSD_555_VCO1__RESET (*(node->input[0])) // reset active low
+#define DSD_555_VCO1__VIN1 (*(node->input[1]))
+#define DSD_555_VCO1__VIN2 (*(node->input[2]))
+
+void dsd_555_vco1_step(node_description *node)
+{
+ const discrete_555_vco1_desc *info = node->custom;
+ struct dsd_555_vco1_context *context = node->context;
+
+ int count_f = 0;
+ int count_r = 0;
+ double dt; // change in time
+ double xTime = 0; // time since change happened
+ double vC; // Current voltage on capacitor, before dt
+ double vCnext = 0; // Voltage on capacitor, after dt
+
+ dt = discrete_current_context->sample_time; // Change in time
+ vC = context->cap_voltage;
+
+ /* Check: if the Control Voltage node is connected. */
+ if (context->ctrlv_is_node && DSD_555_VCO1__RESET) // reset active low
+ {
+ /* If CV is less then .25V, the circuit will oscillate way out of range.
+ * So we will just ignore it when it happens. */
+ if (DSD_555_VCO1__VIN2 < .25) return;
+ /* If it is a node then calculate thresholds based on Control Voltage */
+ context->threshold = DSD_555_VCO1__VIN2;
+ context->trigger = DSD_555_VCO1__VIN2 / 2.0;
+ /* Since the thresholds may have changed we need to update the FF */
+ if (vC >= context->threshold)
+ {
+ context->flip_flop = 0;
+ count_f++;
+ }
+ else
+ if (vC <= context->trigger)
+ {
+ context->flip_flop = 1;
+ count_r++;
+ }
+ }
+
+ /* Keep looping until all toggling in time sample is used up. */
+ do
+ {
+ if (context->flip_flop)
+ {
+ // if we are in reset then toggle f/f and discharge
+ if (!DSD_555_VCO1__RESET) // reset active low
+ {
+ context->flip_flop = 0;
+ count_f++;
+ }
+ else
+ {
+ /* Charging */
+ /* iC=C*dv/dt works out to dv=iC*dt/C */
+ vCnext = vC + (context->i_charge * dt / info->c);
+ dt = 0;
+
+ /* has it charged past upper limit? */
+ if (vCnext >= context->threshold)
+ {
+ if (vCnext > context->threshold)
+ {
+ /* calculate the overshoot time */
+ dt = info->c * (vCnext - context->threshold) / context->i_charge;
+ }
+ vC = context->threshold;
+ context->flip_flop = 0;
+ count_f++;
+ xTime = dt;
+ }
+ }
+ }
+ else
+ {
+ /* Discharging */
+ /* iC=C*dv/dt works out to dv=iC*dt/C */
+ vCnext = vC - (context->i_discharge * dt / info->c);
+
+ // if we are in reset, then the cap can discharge to 0
+ if (!DSD_555_VCO1__RESET) // reset active low
+ {
+ if (vCnext < 0) vCnext = 0;
+ dt = 0;
+ }
+ else
+ {
+ // if we are out of reset and the cap voltage is less then
+ // the lower threshold, toggle f/f and start charging
+ if (vC <= context->trigger)
+ {
+ context->flip_flop = 1;
+ count_r++;
+ }
+ else
+ {
+ dt = 0;
+ /* has it discharged past lower limit? */
+ if (vCnext <= context->trigger)
+ {
+ if (vCnext < context->trigger)
+ {
+ /* calculate the overshoot time */
+ dt = info->c * (vCnext - context->trigger) / context->i_discharge;
+ }
+ vC = context->trigger;
+ context->flip_flop = 1;
+ count_r++;
+ xTime = dt;
+ }
+ }
+ }
+ }
+ } while(dt);
+
+ context->cap_voltage = vCnext;
+
+ /* Convert last switch time to a ratio */
+ xTime = xTime / discrete_current_context->sample_time;
+
+ switch (context->output_type)
+ {
+ case DISC_555_OUT_SQW:
+ node->output = context->flip_flop * context->output_high_voltage + context->ac_shift;
+ break;
+ case DISC_555_OUT_CAP:
+ node->output = vCnext;
+ /* Fake it to AC if needed */
+ if (context->output_is_ac)
+ node->output -= context->threshold * 3.0 /4.0;
+ break;
+ case DISC_555_OUT_ENERGY:
+ node->output = context->output_high_voltage * (context->flip_flop ? xTime : (1 - xTime));
+ node->output += context->ac_shift;
+ break;
+ case DISC_555_OUT_LOGIC_X:
+ node->output = context->flip_flop + xTime;
+ break;
+ case DISC_555_OUT_COUNT_F_X:
+ node->output = count_f ? count_f + xTime : count_f;
+ break;
+ case DISC_555_OUT_COUNT_R_X:
+ node->output = count_r ? count_r + xTime : count_r;
+ break;
+ case DISC_555_OUT_COUNT_F:
+ node->output = count_f;
+ break;
+ case DISC_555_OUT_COUNT_R:
+ node->output = count_r;
+ break;
+ }
+}
+
+void dsd_555_vco1_reset(node_description *node)
+{
+ const discrete_555_vco1_desc *info = node->custom;
+ struct dsd_555_vco1_context *context = node->context;
+
+ double v_ratio_r3, v_ratio_r4_1, r_in_1;
+
+ context->output_type = info->options & DISC_555_OUT_MASK;
+ context->output_is_ac = info->options & DISC_555_OUT_AC;
+
+ /* Setup op-amp parameters */
+
+ /* The voltage at op-amp +in is always a fixed ratio of the modulation voltage. */
+ v_ratio_r3 = info->r3 / (info->r2 + info->r3); // +in voltage
+ /* The voltage at op-amp -in is 1 of 2 fixed ratios of the modulation voltage,
+ * based on the 555 Flip-Flop state. */
+ /* If the FF is 0, then only R1 is connected allowing the full modulation volatge to pass. */
+ /* v_ratio_r4_0 = 1 */
+ /* If the FF is 1, then R1 & R4 make a voltage divider similar to R2 & R3 */
+ v_ratio_r4_1 = info->r4 / (info->r1 + info->r4); // -in voltage
+ /* the input resistance to the op amp depends on the FF state */
+ /* r_in_0 = info->r1 when FF = 0 */
+ r_in_1 = 1.0 / (1.0 / info->r1 + 1.0 / info->r4); // input resistance when r4 switched in
+
+ /* Now that we know the voltages entering the op amp and the resistance for the
+ * FF states, we can predetermine the ratios for the charge/discharge currents. */
+ context->i_discharge = (1 - v_ratio_r3) / info->r1;
+ context->i_charge = (v_ratio_r3 - v_ratio_r4_1) / r_in_1;
+
+ /* the cap starts off discharged */
+ context->cap_voltage = 0;
+
+ /* Setup 555 parameters */
+
+ /* There is no charge on the cap so the 555 goes high at init. */
+ context->flip_flop = 1;
+ context->ctrlv_is_node = (node->input_is_node >> 2) & 1;
+ context->output_high_voltage = (info->v555high == DEFAULT_555_HIGH) ? info->v555 - 1.2 : info->v555high;
+
+ /* Calculate 555 thresholds.
+ * If the Control Voltage is a node, then the thresholds will be calculated each step.
+ * If the Control Voltage is a fixed voltage, then the thresholds will be calculated
+ * from that. Otherwise we will use the thresholds specified in the setup info. */
+ if (!context->ctrlv_is_node && (DSD_555_VCO1__VIN2 != -1))
+ {
+ /* Setup based on supplied static value */
+ context->threshold = DSD_555_VCO1__VIN2;
+ context->trigger = DSD_555_VCO1__VIN2 / 2.0;
+ }
+ else
+ {
+ /* use values passed in structure */
+ context->threshold = (info->threshold555 == DEFAULT_555_THRESHOLD) ? info->v555 * 2 /3 : info->threshold555;
+ context->trigger = (info->trigger555 == DEFAULT_555_TRIGGER) ? info->v555 /3 : info->trigger555;
+ }
+
+ /* Calculate DC shift needed to make squarewave waveform AC */
+ context->ac_shift = context->output_is_ac ? -context->output_high_voltage / 2.0 : 0;
+}
+
+/************************************************************************
+ *
+ * DSD_566 - Usage of node_description values
+ *
+ * input[0] - Enable input value
+ * input[1] - Modulation Voltage
+ * input[2] - R value
+ * input[3] - C value
+ *
+ * also passed discrete_566_desc structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DSD_566__ENABLE (*(node->input[0]))
+#define DSD_566__VMOD (*(node->input[1]))
+#define DSD_566__R (*(node->input[2]))
+#define DSD_566__C (*(node->input[3]))
+
+void dsd_566_step(node_description *node)
+{
+ const discrete_566_desc *info = node->custom;
+ struct dsd_566_context *context = node->context;
+
+ double i; // Charging current created by vIn
+ double dt; // change in time
+ double vC; // Current voltage on capacitor, before dt
+ double vCnext = 0; // Voltage on capacitor, after dt
+
+ if (DSD_566__ENABLE && !context->error)
+ {
+ dt = discrete_current_context->sample_time; // Change in time
+ vC = context->cap_voltage; // Set to voltage before change
+ /* Calculate charging current */
+ i = (context->vDiff - DSD_566__VMOD) / DSD_566__R;
+
+ /* Keep looping until all toggling in time sample is used up. */
+ do
+ {
+ if (context->flip_flop)
+ {
+ /* Discharging */
+ vCnext = vC - (i * dt / DSD_566__C);
+ dt = 0;
+
+ /* has it discharged past lower limit? */
+ if (vCnext <= context->thresholdLow)
+ {
+ if (vCnext < context->thresholdLow)
+ {
+ /* calculate the overshoot time */
+ dt = DSD_566__C * (context->thresholdLow - vCnext) / i;
+ }
+ vC = context->thresholdLow;
+ context->flip_flop = 0;
+ /*
+ * If the sampling rate is too low and the desired frequency is too high
+ * then we will start getting too many outputs that can't catch up. We will
+ * limit this to 3. The output is already incorrect because of the low sampling,
+ * but at least this way it can recover.
+ */
+ context->state[0] = (context->state[0] + 1) & 0x03;
+ }
+ }
+ else
+ {
+ /* Charging */
+ /* iC=C*dv/dt works out to dv=iC*dt/C */
+ vCnext = vC + (i * dt / DSD_566__C);
+ dt = 0;
+ /* Yes, if the cap voltage has reached the max voltage it can,
+ * and the 566 threshold has not been reached, then oscillation stops.
+ * This is the way the actual electronics works.
+ * This is why you never play with the pots after being factory adjusted
+ * to work in the proper range. */
+ if (vCnext > DSD_566__VMOD) vCnext = DSD_566__VMOD;
+
+ /* has it charged past upper limit? */
+ if (vCnext >= context->thresholdHigh)
+ {
+ if (vCnext > context->thresholdHigh)
+ {
+ /* calculate the overshoot time */
+ dt = DSD_566__C * (vCnext - context->thresholdHigh) / i;
+ }
+ vC = context->thresholdHigh;
+ context->flip_flop = 1;
+ context->state[1] = (context->state[1] + 1) & 0x03;
+ }
+ }
+ } while(dt);
+
+ context->cap_voltage = vCnext;
+
+ switch (info->options & DISC_566_OUT_MASK)
+ {
+ case DISC_566_OUT_SQUARE:
+ case DISC_566_OUT_LOGIC:
+ /* use up any output states */
+ if (node->output && context->state[0])
+ {
+ node->output = 0;
+ context->state[0]--;
+ }
+ else if (!node->output && context->state[1])
+ {
+ node->output = 1;
+ context->state[1]--;
+ }
+ else
+ {
+ node->output = context->flip_flop;
+ }
+ if ((info->options & DISC_566_OUT_MASK) != DISC_566_OUT_LOGIC)
+ node->output = context->flip_flop ? context->vSqrHigh : context->vSqrLow;
+ break;
+ case DISC_566_OUT_TRIANGLE:
+ /* we can ignore any unused states when
+ * outputting the cap voltage */
+ node->output = vCnext;
+ if (info->options & DISC_566_OUT_AC)
+ node->output -= context->triOffset;
+ break;
+ }
+ }
+ else
+ node->output = 0;
+}
+
+void dsd_566_reset(node_description *node)
+{
+ const discrete_566_desc *info = node->custom;
+ struct dsd_566_context *context = node->context;
+
+ double temp;
+
+ context->error = 0;
+ if (info->vNeg >= info->vPlus)
+ {
+ logerror("[vNeg >= vPlus] - NODE_%d DISABLED!\n", node->node - NODE_00);
+ context->error = 1;
+ }
+
+ context->vDiff = info->vPlus - info->vNeg;
+ context->flip_flop = 0;
+ context->cap_voltage = 0;
+ context->state[0] = 0;
+ context->state[1] = 0;
+
+ /* The data sheets are crap on this IC. I will have to get my hands on a chip
+ * to make real measurements. For now this should work fine for 12V. */
+ context->thresholdHigh = context->vDiff / 2 + info->vNeg;
+ context->thresholdLow = context->thresholdHigh - (0.2 * context->vDiff);
+ context->vSqrHigh = info->vPlus - 0.6;
+ context->vSqrLow = context->thresholdHigh;
+
+ if (info->options & DISC_566_OUT_AC)
+ {
+ temp = (context->vSqrHigh - context->vSqrLow) / 2;
+ context->vSqrHigh = temp;
+ context->vSqrLow = -temp;
+ context->triOffset = context->thresholdHigh - (0.1 * context->vDiff);
+ }
+
+ /* Step the output */
+ dsd_566_step(node);
+}
diff --git a/src/emu/sound/disc_flt.c b/src/emu/sound/disc_flt.c
new file mode 100644
index 00000000000..7c2a6be70c2
--- /dev/null
+++ b/src/emu/sound/disc_flt.c
@@ -0,0 +1,1220 @@
+/************************************************************************
+ *
+ * MAME - Discrete sound system emulation library
+ *
+ * Written by Keith Wilkins (mame@esplexo.co.uk)
+ *
+ * (c) K.Wilkins 2000
+ *
+ ***********************************************************************
+ *
+ * DST_CRFILTER - Simple CR filter & also highpass filter
+ * DST_FILTER1 - Generic 1st order filter
+ * DST_FILTER2 - Generic 2nd order filter
+ * DST_OP_AMP_FILT - Op Amp filter circuits
+ * DST_RCFILTER - Simple RC filter & also lowpass filter
+ * DST_RCDISC - Simple discharging RC
+ * DST_RCDISC2 - Simple charge R1/C, discharge R0/C
+ * DST_RCDISC3 - Simple charge R1/c, discharge R0*R1/(R0+R1)/C
+ * DST_RCDISC4 - Various charge/discharge circuits
+ * DST_RCDISC5 - Diode in series with R//C
+ *
+ ************************************************************************/
+
+struct dss_filter1_context
+{
+ double x1; /* x[k-1], previous input value */
+ double y1; /* y[k-1], previous output value */
+ double a1; /* digital filter coefficients, denominator */
+ double b0, b1; /* digital filter coefficients, numerator */
+};
+
+struct dss_filter2_context
+{
+ double x1, x2; /* x[k-1], x[k-2], previous 2 input values */
+ double y1, y2; /* y[k-1], y[k-2], previous 2 output values */
+ double a1, a2; /* digital filter coefficients, denominator */
+ double b0, b1, b2; /* digital filter coefficients, numerator */
+};
+
+struct dst_op_amp_filt_context
+{
+ int type; // What kind of filter
+ int is_norton; // 1 = Norton op-amps
+ double vRef;
+ double vP;
+ double vN;
+ double rTotal; // All input resistance in parallel.
+ double iFixed; // Current supplied by r3 & r4 if used.
+ double exponentC1;
+ double exponentC2;
+ double exponentC3;
+ double rRatio; // divide ratio of resistance network
+ double vC1; // Charge on C1
+ double vC1b; // Charge on C1, part of C1 charge if needed
+ double vC2; // Charge on C2
+ double vC3; // Charge on C2
+ double gain; // Gain of the filter
+ double x1, x2; /* x[k-1], x[k-2], previous 2 input values */
+ double y1, y2; /* y[k-1], y[k-2], previous 2 output values */
+ double a1,a2; /* digital filter coefficients, denominator */
+ double b0,b1,b2; /* digital filter coefficients, numerator */
+};
+
+struct dst_rcdisc_context
+{
+ int state;
+ double t; // time
+ double f; // RCINTEGRATE
+ double R1; // RCINTEGRATE
+ double R2; // RCINTEGRATE
+ double R3; // RCINTEGRATE
+ double C; // RCINTEGRATE
+ double vCap; // RCDISC_MOD
+ double vCE; // RCINTEGRATE
+ double exponent0;
+ double exponent1;
+};
+
+struct dst_rcdisc4_context
+{
+ int type;
+ double max_out;
+ double vC1;
+ double v[2];
+ double exp[2];
+};
+
+struct dst_rcfilter_context
+{
+ double exponent;
+ double vCap;
+};
+
+
+/************************************************************************
+ *
+ * DST_CRFILTER - Usage of node_description values for CR filter
+ *
+ * input[0] - Enable input value
+ * input[1] - input value
+ * input[2] - Resistor value (initialization only)
+ * input[3] - Capacitor Value (initialization only)
+ * input[4] - Voltage reference. Usually 0V.
+ *
+ ************************************************************************/
+#define DST_CRFILTER__ENABLE (*(node->input[0]))
+#define DST_CRFILTER__IN (*(node->input[1]))
+#define DST_CRFILTER__R (*(node->input[2]))
+#define DST_CRFILTER__C (*(node->input[3]))
+#define DST_CRFILTER__VREF (*(node->input[4]))
+
+void dst_crfilter_step(node_description *node)
+{
+ struct dst_rcfilter_context *context = node->context;
+
+ if(DST_CRFILTER__ENABLE)
+ {
+ node->output = DST_CRFILTER__IN - context->vCap;
+ context->vCap += ((DST_CRFILTER__IN - DST_CRFILTER__VREF) - context->vCap) * context->exponent;
+ }
+ else
+ {
+ node->output = 0;
+ }
+}
+
+void dst_crfilter_reset(node_description *node)
+{
+ struct dst_rcfilter_context *context = node->context;
+
+ context->exponent = -1.0 / (DST_CRFILTER__R * DST_CRFILTER__C * discrete_current_context->sample_rate);
+ context->exponent = 1.0 - exp(context->exponent);
+ context->vCap = 0;
+ node->output = DST_CRFILTER__IN;
+}
+
+
+/************************************************************************
+ *
+ * DST_FILTER1 - Generic 1st order filter
+ *
+ * input[0] - Enable input value
+ * input[1] - input value
+ * input[2] - Frequency value (initialization only)
+ * input[3] - Filter type (initialization only)
+ *
+ ************************************************************************/
+#define DST_FILTER1__ENABLE (*(node->input[0]))
+#define DST_FILTER1__IN (*(node->input[1]))
+#define DST_FILTER1__FREQ (*(node->input[2]))
+#define DST_FILTER1__TYPE (*(node->input[3]))
+
+static void calculate_filter1_coefficients(double fc, double type,
+ double *a1, double *b0, double *b1)
+{
+ double den, w, two_over_T;
+
+ /* calculate digital filter coefficents */
+ /*w = 2.0*M_PI*fc; no pre-warping */
+ w = discrete_current_context->sample_rate*2.0*tan(M_PI*fc/discrete_current_context->sample_rate); /* pre-warping */
+ two_over_T = 2.0*discrete_current_context->sample_rate;
+
+ den = w + two_over_T;
+ *a1 = (w - two_over_T)/den;
+ if (type == DISC_FILTER_LOWPASS)
+ {
+ *b0 = *b1 = w/den;
+ }
+ else if (type == DISC_FILTER_HIGHPASS)
+ {
+ *b0 = two_over_T/den;
+ *b1 = -(*b0);
+ }
+ else
+ {
+ discrete_log("calculate_filter1_coefficients() - Invalid filter type for 1st order filter.");
+ }
+}
+
+void dst_filter1_step(node_description *node)
+{
+ struct dss_filter1_context *context = node->context;
+ double gain = 1.0;
+
+ if (DST_FILTER1__ENABLE == 0.0)
+ {
+ gain = 0.0;
+ }
+
+ node->output = -context->a1*context->y1 + context->b0*gain*DST_FILTER1__IN + context->b1*context->x1;
+
+ context->x1 = gain*DST_FILTER1__IN;
+ context->y1 = node->output;
+}
+
+void dst_filter1_reset(node_description *node)
+{
+ struct dss_filter1_context *context = node->context;
+
+ calculate_filter1_coefficients(DST_FILTER1__FREQ, DST_FILTER1__TYPE, &context->a1, &context->b0, &context->b1);
+ node->output=0;
+}
+
+
+/************************************************************************
+ *
+ * DST_FILTER2 - Generic 2nd order filter
+ *
+ * input[0] - Enable input value
+ * input[1] - input value
+ * input[2] - Frequency value (initialization only)
+ * input[3] - Damping value (initialization only)
+ * input[4] - Filter type (initialization only)
+ *
+ ************************************************************************/
+#define DST_FILTER2__ENABLE (*(node->input[0]))
+#define DST_FILTER2__IN (*(node->input[1]))
+#define DST_FILTER2__FREQ (*(node->input[2]))
+#define DST_FILTER2__DAMP (*(node->input[3]))
+#define DST_FILTER2__TYPE (*(node->input[4]))
+
+static void calculate_filter2_coefficients(double fc, double d, double type,
+ double *a1, double *a2,
+ double *b0, double *b1, double *b2)
+{
+ double w; /* cutoff freq, in radians/sec */
+ double w_squared;
+ double den; /* temp variable */
+ double two_over_T = 2*discrete_current_context->sample_rate;
+ double two_over_T_squared = two_over_T * two_over_T;
+
+ /* calculate digital filter coefficents */
+ /*w = 2.0*M_PI*fc; no pre-warping */
+ w = discrete_current_context->sample_rate*2.0*tan(M_PI*fc/discrete_current_context->sample_rate); /* pre-warping */
+ w_squared = w*w;
+
+ den = two_over_T_squared + d*w*two_over_T + w_squared;
+
+ *a1 = 2.0*(-two_over_T_squared + w_squared)/den;
+ *a2 = (two_over_T_squared - d*w*two_over_T + w_squared)/den;
+
+ if (type == DISC_FILTER_LOWPASS)
+ {
+ *b0 = *b2 = w_squared/den;
+ *b1 = 2.0*(*b0);
+ }
+ else if (type == DISC_FILTER_BANDPASS)
+ {
+ *b0 = d*w*two_over_T/den;
+ *b1 = 0.0;
+ *b2 = -(*b0);
+ }
+ else if (type == DISC_FILTER_HIGHPASS)
+ {
+ *b0 = *b2 = two_over_T_squared/den;
+ *b1 = -2.0*(*b0);
+ }
+ else
+ {
+ discrete_log("calculate_filter2_coefficients() - Invalid filter type for 2nd order filter.");
+ }
+}
+
+void dst_filter2_step(node_description *node)
+{
+ struct dss_filter2_context *context = node->context;
+ double gain = 1.0;
+
+ if (DST_FILTER2__ENABLE == 0.0)
+ {
+ gain = 0.0;
+ }
+
+ node->output = -context->a1*context->y1 - context->a2*context->y2 +
+ context->b0*gain*DST_FILTER2__IN + context->b1*context->x1 + context->b2*context->x2;
+
+ context->x2 = context->x1;
+ context->x1 = gain * DST_FILTER2__IN;
+ context->y2 = context->y1;
+ context->y1 = node->output;
+}
+
+void dst_filter2_reset(node_description *node)
+{
+ struct dss_filter2_context *context = node->context;
+
+ calculate_filter2_coefficients(DST_FILTER2__FREQ, DST_FILTER2__DAMP, DST_FILTER2__TYPE,
+ &context->a1, &context->a2,
+ &context->b0, &context->b1, &context->b2);
+ node->output=0;
+}
+
+
+/************************************************************************
+ *
+ * DST_OP_AMP_FILT - Op Amp filter circuit RC filter
+ *
+ * input[0] - Enable input value
+ * input[1] - IN0 node
+ * input[2] - IN1 node
+ * input[3] - Filter Type
+ *
+ * also passed discrete_op_amp_filt_info structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DST_OP_AMP_FILT__ENABLE (*(node->input[0]))
+#define DST_OP_AMP_FILT__INP1 (*(node->input[1]))
+#define DST_OP_AMP_FILT__INP2 (*(node->input[2]))
+#define DST_OP_AMP_FILT__TYPE (*(node->input[3]))
+
+void dst_op_amp_filt_step(node_description *node)
+{
+ const discrete_op_amp_filt_info *info = node->custom;
+ struct dst_op_amp_filt_context *context = node->context;
+
+ double i, v=0;
+
+ if (DST_OP_AMP_FILT__ENABLE)
+ {
+ if (context->is_norton)
+ {
+ v = DST_OP_AMP_FILT__INP1 - OP_AMP_NORTON_VBE;
+ if (v < 0) v = 0;
+ }
+ else
+ {
+ /* Millman the input voltages. */
+ i = context->iFixed;
+ i += (DST_OP_AMP_FILT__INP1 - context->vRef) / info->r1;
+ if (info->r2 != 0)
+ i += (DST_OP_AMP_FILT__INP2 - context->vRef) / info->r2;
+ v = i * context->rTotal;
+ }
+
+ switch (context->type)
+ {
+ case DISC_OP_AMP_FILTER_IS_LOW_PASS_1:
+ context->vC1 += (v - context->vC1) * context->exponentC1;
+ node->output = context->vC1 * context->gain + info->vRef;
+ break;
+
+ case DISC_OP_AMP_FILTER_IS_HIGH_PASS_1:
+ node->output = (v - context->vC1) * context->gain + info->vRef;
+ context->vC1 += (v - context->vC1) * context->exponentC1;
+ break;
+
+ case DISC_OP_AMP_FILTER_IS_BAND_PASS_1:
+ node->output = (v - context->vC2);
+ context->vC2 += (v - context->vC2) * context->exponentC2;
+ context->vC1 += (node->output - context->vC1) * context->exponentC1;
+ node->output = context->vC1 * context->gain + info->vRef;
+ break;
+
+ case DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON:
+ context->vC1 += (v - context->vC1) * context->exponentC1;
+ context->vC2 += (context->vC1 - context->vC2) * context->exponentC2;
+ v = context->vC2;
+ node->output = v - context->vC3;
+ context->vC3 += (v - context->vC3) * context->exponentC3;
+ i = node->output / context->rTotal;
+ node->output = (context->iFixed - i) * info->rF;
+ break;
+
+ case DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON:
+ node->output = v - context->vC1;
+ context->vC1 += (v - context->vC1) * context->exponentC1;
+ i = node->output / context->rTotal;
+ node->output = (context->iFixed - i) * info->rF;
+ break;
+
+ case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M:
+ case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON:
+ node->output = -context->a1*context->y1 - context->a2*context->y2 +
+ context->b0*v + context->b1*context->x1 + context->b2*context->x2 +
+ context->vRef;
+ context->x2 = context->x1;
+ context->x1 = v;
+ context->y2 = context->y1;
+ break;
+ }
+
+ /* Clip the output to the voltage rails.
+ * This way we get the original distortion in all it's glory.
+ */
+ if (node->output > context->vP) node->output = context->vP;
+ if (node->output < context->vN) node->output = context->vN;
+ context->y1 = node->output - context->vRef;
+ }
+ else
+ node->output = 0;
+
+}
+
+void dst_op_amp_filt_reset(node_description *node)
+{
+ const discrete_op_amp_filt_info *info = node->custom;
+ struct dst_op_amp_filt_context *context = node->context;
+
+ /* Convert the passed filter type into an int for easy use. */
+ context->type = (int)DST_OP_AMP_FILT__TYPE & DISC_OP_AMP_FILTER_TYPE_MASK;
+ context->is_norton = (int)DST_OP_AMP_FILT__TYPE & DISC_OP_AMP_IS_NORTON;
+
+ if (context->is_norton)
+ {
+ context->vRef = 0;
+ context->rTotal = info->r1;
+ if (context->type == (DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON))
+ context->rTotal += info->r2 + info->r3;
+
+ /* Setup the current to the + input. */
+ context->iFixed = (info->vP - OP_AMP_NORTON_VBE) / info->r4;
+
+ /* Set the output max. */
+ context->vP = info->vP - OP_AMP_NORTON_VBE;
+ context->vN = info->vN;
+ }
+ else
+ {
+ context->vRef = info->vRef;
+ /* Set the output max. */
+ context->vP = info->vP - OP_AMP_VP_RAIL_OFFSET;
+ context->vN = info->vN;
+
+ /* Work out the input resistance. It is all input and bias resistors in parallel. */
+ context->rTotal = 1.0 / info->r1; // There has to be an R1. Otherwise the table is wrong.
+ if (info->r2 != 0) context->rTotal += 1.0 / info->r2;
+ if (info->r3 != 0) context->rTotal += 1.0 / info->r3;
+ context->rTotal = 1.0 / context->rTotal;
+
+ context->iFixed = 0;
+
+ context->rRatio = info->rF / (context->rTotal + info->rF);
+ context->gain = -info->rF / context->rTotal;
+ }
+
+ switch (context->type)
+ {
+ case DISC_OP_AMP_FILTER_IS_LOW_PASS_1:
+ context->exponentC1 = -1.0 / (info->rF * info->c1 * discrete_current_context->sample_rate);
+ context->exponentC1 = 1.0 - exp(context->exponentC1);
+ context->exponentC2 = 0;
+ break;
+ case DISC_OP_AMP_FILTER_IS_HIGH_PASS_1:
+ context->exponentC1 = -1.0 / (context->rTotal * info->c1 * discrete_current_context->sample_rate);
+ context->exponentC1 = 1.0 - exp(context->exponentC1);
+ context->exponentC2 = 0;
+ break;
+ case DISC_OP_AMP_FILTER_IS_BAND_PASS_1:
+ context->exponentC1 = -1.0 / (info->rF * info->c1 * discrete_current_context->sample_rate);
+ context->exponentC1 = 1.0 - exp(context->exponentC1);
+ context->exponentC2 = -1.0 / (context->rTotal * info->c2 * discrete_current_context->sample_rate);
+ context->exponentC2 = 1.0 - exp(context->exponentC2);
+ break;
+ case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON:
+ context->rTotal = 1.0 / (1.0 / info->r1 + 1.0 / info->r2);
+ case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M:
+ {
+ double fc = 1.0 / (2 * M_PI * sqrt(context->rTotal * info->rF * info->c1 * info->c2));
+ double d = (info->c1 + info->c2) / sqrt(info->rF / context->rTotal * info->c1 * info->c2);
+ double gain = -info->rF / context->rTotal * info->c2 / (info->c1 + info->c2);
+
+ calculate_filter2_coefficients(fc, d, DISC_FILTER_BANDPASS,
+ &context->a1, &context->a2,
+ &context->b0, &context->b1, &context->b2);
+ context->b0 *= gain;
+ context->b1 *= gain;
+ context->b2 *= gain;
+
+ if (context->is_norton)
+ context->vRef = (info->vP - OP_AMP_NORTON_VBE) / info->r3 * info->rF;
+ else
+ context->vRef = info->vRef;
+
+ break;
+ }
+ case DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON:
+ context->exponentC1 = -1.0 / ((1.0 / (1.0 / info->r1 + 1.0 / (info->r2 + info->r3 + info->r4))) * info->c1 * discrete_current_context->sample_rate);
+ context->exponentC1 = 1.0 - exp(context->exponentC1);
+ context->exponentC2 = -1.0 / ((1.0 / (1.0 / (info->r1 + info->r2) + 1.0 / (info->r3 + info->r4))) * info->c2 * discrete_current_context->sample_rate);
+ context->exponentC2 = 1.0 - exp(context->exponentC2);
+ context->exponentC3 = -1.0 / ((info->r1 + info->r2 + info->r3 + info->r4) * info->c3 * discrete_current_context->sample_rate);
+ context->exponentC3 = 1.0 - exp(context->exponentC3);
+ break;
+ case DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON:
+ context->exponentC1 = -1.0 / (info->r1 * info->c1 * discrete_current_context->sample_rate);
+ context->exponentC1 = 1.0 - exp(context->exponentC1);
+ break;
+ }
+
+ /* At startup there is no charge on the caps and output is 0V in relation to vRef. */
+ context->vC1 = 0;
+ context->vC1b = 0;
+ context->vC2 = 0;
+ context->vC3 = 0;
+
+ node->output = info->vRef;
+}
+
+
+/************************************************************************
+ *
+ * DST_RCDISC - Usage of node_description values for RC discharge
+ * (inverse slope of DST_RCFILTER)
+ *
+ * input[0] - Enable input value
+ * input[1] - input value
+ * input[2] - Resistor value (initialization only)
+ * input[3] - Capacitor Value (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCDISC__ENABLE (*(node->input[0]))
+#define DST_RCDISC__IN (*(node->input[1]))
+#define DST_RCDISC__R (*(node->input[2]))
+#define DST_RCDISC__C (*(node->input[3]))
+
+void dst_rcdisc_step(node_description *node)
+{
+ struct dst_rcdisc_context *context = node->context;
+
+ switch (context->state) {
+ case 0: /* waiting for trigger */
+ if(DST_RCDISC__ENABLE) {
+ context->state = 1;
+ context->t = 0;
+ }
+ node->output=0;
+ break;
+
+ case 1:
+ if (DST_RCDISC__ENABLE) {
+ node->output = DST_RCDISC__IN * exp(context->t / context->exponent0);
+ context->t += discrete_current_context->sample_time;
+ } else {
+ context->state = 0;
+ }
+ }
+}
+
+void dst_rcdisc_reset(node_description *node)
+{
+ struct dst_rcdisc_context *context = node->context;
+
+ node->output=0;
+
+ context->state = 0;
+ context->t = 0;
+ context->exponent0=-1.0 * DST_RCDISC__R * DST_RCDISC__C;
+}
+
+
+/************************************************************************
+ *
+ * DST_RCDISC2 - Usage of node_description values for RC discharge
+ * Has switchable charge resistor/input
+ *
+ * input[0] - Switch input value
+ * input[1] - input[0] value
+ * input[2] - Resistor0 value (initialization only)
+ * input[3] - input[1] value
+ * input[4] - Resistor1 value (initialization only)
+ * input[5] - Capacitor Value (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCDISC2__ENABLE (*(node->input[0]))
+#define DST_RCDISC2__IN0 (*(node->input[1]))
+#define DST_RCDISC2__R0 (*(node->input[2]))
+#define DST_RCDISC2__IN1 (*(node->input[3]))
+#define DST_RCDISC2__R1 (*(node->input[4]))
+#define DST_RCDISC2__C (*(node->input[5]))
+
+void dst_rcdisc2_step(node_description *node)
+{
+ double diff;
+ struct dst_rcdisc_context *context = node->context;
+
+ /* Works differently to other as we are always on, no enable */
+ /* exponential based in difference between input/output */
+
+ diff = ((DST_RCDISC2__ENABLE == 0) ? DST_RCDISC2__IN0 : DST_RCDISC2__IN1) - node->output;
+ diff = diff - (diff * exp(discrete_current_context->sample_time / ((DST_RCDISC2__ENABLE == 0) ? context->exponent0 : context->exponent1)));
+ node->output += diff;
+}
+
+void dst_rcdisc2_reset(node_description *node)
+{
+ struct dst_rcdisc_context *context = node->context;
+
+ node->output=0;
+
+ context->state = 0;
+ context->t = 0;
+ context->exponent0=-1.0 * DST_RCDISC2__R0 * DST_RCDISC2__C;
+ context->exponent1=-1.0 * DST_RCDISC2__R1 * DST_RCDISC2__C;
+}
+
+/************************************************************************
+ *
+ * DST_RCDISC3 - Usage of node_description values for RC discharge
+ *
+ *
+ * input[0] - Enable
+ * input[1] - input value
+ * input[2] - Resistor0 value (initialization only)
+ * input[4] - Resistor1 value (initialization only)
+ * input[5] - Capacitor Value (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCDISC3__ENABLE (*(node->input[0]))
+#define DST_RCDISC3__IN (*(node->input[1]))
+#define DST_RCDISC3__R1 (*(node->input[2]))
+#define DST_RCDISC3__R2 (*(node->input[3]))
+#define DST_RCDISC3__C (*(node->input[4]))
+
+void dst_rcdisc3_step(node_description *node)
+{
+ double diff;
+ struct dst_rcdisc_context *context = node->context;
+
+ /* Exponential based in difference between input/output */
+
+ if(DST_RCDISC3__ENABLE)
+ {
+ diff = DST_RCDISC3__IN - node->output;
+ if( diff > 0 )
+ {
+ diff = diff - (diff * exp(discrete_current_context->sample_time / context->exponent0));
+ } else if( diff < 0)
+ {
+ if(diff < -0.5)
+ diff = diff - (diff * exp(discrete_current_context->sample_time / context->exponent1));
+ else
+ diff = diff - (diff * exp(discrete_current_context->sample_time / context->exponent0));
+ }
+ node->output += diff;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+void dst_rcdisc3_reset(node_description *node)
+{
+ struct dst_rcdisc_context *context = node->context;
+
+ node->output=0;
+
+ context->state = 0;
+ context->t = 0;
+ context->exponent0=-1.0 * DST_RCDISC3__R1 * DST_RCDISC3__C;
+ context->exponent1=-1.0 *(DST_RCDISC3__R1 * DST_RCDISC3__R2)/( DST_RCDISC3__R1 + DST_RCDISC3__R2)* DST_RCDISC3__C;
+}
+
+
+/************************************************************************
+ *
+ * DST_RCDISC4 - Various charge/discharge circuits
+ *
+ * input[0] - Enable input value
+ * input[1] - input value
+ * input[2] - R1 Resistor value (initialization only)
+ * input[2] - R2 Resistor value (initialization only)
+ * input[4] - C1 Capacitor Value (initialization only)
+ * input[4] - vP power source (initialization only)
+ * input[4] - circuit type (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCDISC4__ENABLE (*(node->input[0]))
+#define DST_RCDISC4__IN (*(node->input[1]))
+#define DST_RCDISC4__R1 (*(node->input[2]))
+#define DST_RCDISC4__R2 (*(node->input[3]))
+#define DST_RCDISC4__R3 (*(node->input[4]))
+#define DST_RCDISC4__C1 (*(node->input[5]))
+#define DST_RCDISC4__VP (*(node->input[6]))
+#define DST_RCDISC4__TYPE (*(node->input[7]))
+
+void dst_rcdisc4_step(node_description *node)
+{
+ struct dst_rcdisc4_context *context = node->context;
+ int inp1 = (DST_RCDISC4__IN == 0) ? 0 : 1;
+
+ if (DST_RCDISC4__ENABLE == 0)
+ {
+ node->output = 0;
+ return;
+ }
+
+ switch (context->type)
+ {
+ case 1:
+ case 3:
+ context->vC1 += ((context->v[inp1] - context->vC1) * context->exp[inp1]);
+ node->output = context->vC1;
+ break;
+ }
+
+ /* clip output */
+ if (node->output > context->max_out) node->output = context->max_out;
+ if (node->output < 0) node->output = 0;
+}
+
+void dst_rcdisc4_reset(node_description *node)
+{
+ struct dst_rcdisc4_context *context = node->context;
+ double v, i, r, rT;
+
+ context->type = 0;
+ /* some error checking. */
+ if (DST_RCDISC4__R1 <= 0 || DST_RCDISC4__R2 <= 0 || DST_RCDISC4__C1 <= 0 || (DST_RCDISC4__R3 <= 0 && context->type == 1))
+ {
+ discrete_log("Invalid component values in NODE_%d.\n", node->node - NODE_00);
+ return;
+ }
+ if (DST_RCDISC4__VP < 3)
+ {
+ discrete_log("vP must be >= 3V in NODE_%d.\n", node->node - NODE_00);
+ return;
+ }
+ if (DST_RCDISC4__TYPE < 1 || DST_RCDISC4__TYPE > 3)
+ {
+ discrete_log("Invalid circuit type in NODE_%d.\n", node->node - NODE_00);
+ return;
+ }
+
+ context->vC1 = 0;
+ /* store type as integer */
+ context->type = (int)DST_RCDISC4__TYPE;
+ /* setup the maximum op-amp output. */
+ context->max_out = DST_RCDISC4__VP - OP_AMP_VP_RAIL_OFFSET;
+
+ switch (context->type)
+ {
+ case 1:
+ /* We will simulate this as a voltage divider with 2 states depending
+ * on the input. But we have to take the diodes into account.
+ */
+ v = DST_RCDISC4__VP - .5; /* diode drop */
+
+ /* When the input is 1, both R1 & R3 are basically in parallel. */
+ r = 1.0 / (1.0 / DST_RCDISC4__R1 + 1.0 / DST_RCDISC4__R3);
+ rT = DST_RCDISC4__R2 + r;
+ i = v / rT;
+ context->v[1] = i * r + .5;
+ rT = 1.0 / (1.0 / DST_RCDISC4__R2 + 1.0 / r);
+ context->exp[1] = -1.0 / (rT * DST_RCDISC4__C1 * discrete_current_context->sample_rate);
+ context->exp[1] = 1.0 - exp(context->exp[1]);
+
+ /* When the input is 0, R1 is out of circuit. */
+ rT = DST_RCDISC4__R2 + DST_RCDISC4__R3;
+ i = v / rT;
+ context->v[0] = i * DST_RCDISC4__R3 + .5;
+ rT = 1.0 / (1.0 / DST_RCDISC4__R2 + 1.0 / DST_RCDISC4__R3);
+ context->exp[0] = -1.0 / (rT * DST_RCDISC4__C1 * discrete_current_context->sample_rate);
+ context->exp[0] = 1.0 - exp(context->exp[0]);
+ break;
+
+ case 3:
+ /* We will simulate this as a voltage divider with 2 states depending
+ * on the input. The 1k pullup is in parallel with the internal TTL
+ * resistance, so we will just use .5k in series with R1.
+ */
+ r = 500.0 + DST_RCDISC4__R1;
+ context->v[1] = DST_RCDISC4__R2 / (r + DST_RCDISC4__R2) * (5.0 - 0.5);
+ rT = 1.0 / ( 1.0 / r + 1.0 / DST_RCDISC4__R2);
+ context->exp[1] = -1.0 / (rT * DST_RCDISC4__C1 * discrete_current_context->sample_rate);
+ context->exp[1] = 1.0 - exp(context->exp[1]);
+
+ /* When the input is 0, R1 is out of circuit. */
+ context->v[0] = 0;
+ context->exp[0] = -1.0 / (DST_RCDISC4__R2 * DST_RCDISC4__C1 * discrete_current_context->sample_rate);
+ context->exp[0] = 1.0 - exp(context->exp[0]);
+ break;
+ }
+}
+
+/************************************************************************
+ *
+ * DST_RCDISC5 - Diode in series with R//C
+ *
+ * input[0] - Enable input value
+ * input[1] - input value
+ * input[2] - Resistor value (initialization only)
+ * input[3] - Capacitor Value (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCDISC5__ENABLE (*(node->input[0]))
+#define DST_RCDISC5__IN (*(node->input[1]))
+#define DST_RCDISC5__R (*(node->input[2]))
+#define DST_RCDISC5__C (*(node->input[3]))
+
+void dst_rcdisc5_step(node_description *node)
+{
+ double diff,u;
+ struct dst_rcdisc_context *context = node->context;
+
+ /* Exponential based in difference between input/output */
+
+ if(DST_RCDISC5__ENABLE)
+ {
+ u = DST_RCDISC5__IN - 0.7; /* Diode drop */
+ if( u < 0)
+ u = 0;
+
+ diff = u - node->output;
+
+ if(diff < 0)
+ //diff = diff - (diff * exp(discrete_current_context->sample_time / context->exponent0));
+ diff = -node->output + (node->output * exp(discrete_current_context->sample_time / context->exponent0));
+ node->output += diff;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+void dst_rcdisc5_reset(node_description *node)
+{
+ struct dst_rcdisc_context *context = node->context;
+
+ node->output=0;
+
+ context->state = 0;
+ context->t = 0;
+ context->exponent0=-1.0 * DST_RCDISC5__R * DST_RCDISC5__C;
+}
+
+/************************************************************************
+ *
+ * DST_RCINTEGRATE - Two diode inputs, transistor and a R/C charge
+ * discharge network
+ *
+ * input[0] - Enable input value
+ * input[1] - input value 1
+ * input[2] - input value 2
+ * input[3] - Resistor 1 value (initialization only)
+ * input[4] - Resistor 2 value (initialization only)
+ * input[5] - Capacitor Value (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCINTEGRATE__ENABLE (*(node->input[0]))
+#define DST_RCINTEGRATE__IN1 (*(node->input[1]))
+#define DST_RCINTEGRATE__R1 (*(node->input[2]))
+#define DST_RCINTEGRATE__R2 (*(node->input[3]))
+#define DST_RCINTEGRATE__R3 (*(node->input[4]))
+#define DST_RCINTEGRATE__C (*(node->input[5]))
+#define DST_RCINTEGRATE__VP (*(node->input[6]))
+#define DST_RCINTEGRATE__TYPE (*(node->input[7]))
+
+/* Ebers-Moll large signal model
+ * Couriersud:
+ * The implementation avoids all iterative approaches in order not to burn cycles
+ * We will calculate Ic from vBE and use this as an indication where to go.
+ * The implementation may oscillate if you change the weighting factors at the
+ * end.
+ *
+ * This implementation is not perfect, but does it's job in dkong'
+ */
+
+/* reverse saturation current */
+#define IES 7e-15
+#define ALPHAT 0.99
+#define KT 0.026
+#define EM_IC(x) (ALPHAT * IES * exp( (x) / KT - 1.0 ))
+
+void dst_rcintegrate_step(node_description *node)
+{
+ double diff,u,iQ,iQc,iC,RG,vE;
+ struct dst_rcdisc_context *context = node->context;
+ double dt,vP;
+
+ if(DST_RCINTEGRATE__ENABLE)
+ {
+ u = DST_RCINTEGRATE__IN1;
+ vP = DST_RCINTEGRATE__VP;
+ dt = discrete_current_context->sample_time;
+ if ( u-0.7 < context->vCap*context->R2/(context->R1+context->R2))
+ {
+ /* discharge .... */
+ diff = 0 - context->vCap;
+ iC = 0.0 - context->C / context->exponent1 * diff*exp(dt / context->exponent1); // iC
+ diff = diff - (diff * exp(dt / context->exponent1));
+ context->vCap += diff;
+ iQ = 0;
+ vE = context->vCap*context->R2/(context->R1+context->R2);
+ RG = vE/(-iC);
+ }
+ else
+ {
+ /* charging */
+ diff = (vP - context->vCE) * context->f - context->vCap;
+ iC = 0.0 - context->C / context->exponent0 * diff*exp(dt / context->exponent0); // iC
+ diff = diff - (diff * exp(dt / context->exponent0));
+ context->vCap += diff;
+ iQ = iC + (iC * context->R1 + context->vCap) / context->R2;
+ RG = (vP - context->vCE)/iQ;
+ vE = (RG - context->R3) / RG * (vP - context->vCE);
+ }
+
+
+ u = DST_RCINTEGRATE__IN1;
+ if (u>0.7+vE)
+ vE=u-0.7;
+ iQc = EM_IC(u - vE);
+ context->vCE = MIN(vP-0.1, vP - RG*iQc);
+
+ /* Avoid oscillations
+ * The method tends to largely overshoot - no wonder without
+ * iterative solution approximation
+ */
+
+ context->vCE = MAX(context->vCE, 0.1 );
+ context->vCE = 0.1 * context->vCE +0.9 * (vP - vE - iQ * context->R3);
+
+ switch (context->state)
+ {
+ case DISC_RC_INTEGRATE_TYPE1:
+ node->output = context->vCap;
+ break;
+ case DISC_RC_INTEGRATE_TYPE2:
+ node->output = vE;
+ break;
+ case DISC_RC_INTEGRATE_TYPE3:
+ node->output = MAX(0,vP - iQ * context->R3);
+ break;
+ }
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+void dst_rcintegrate_reset(node_description *node)
+{
+ struct dst_rcdisc_context *context = node->context;
+ double r;
+
+ node->output=0;
+
+ context->state = DST_RCINTEGRATE__TYPE;
+ context->R1 = DST_RCINTEGRATE__R1;
+ context->R2 = DST_RCINTEGRATE__R2;
+ context->R3 = DST_RCINTEGRATE__R3;
+ context->C = DST_RCINTEGRATE__C;
+
+ context->vCap = 0;
+ context->vCE = 0;
+
+ r = context->R1 / context->R2 * context->R3 + context->R1 + context->R3;
+
+ context->f = DST_RCINTEGRATE__R2/(DST_RCINTEGRATE__R2+DST_RCINTEGRATE__R3);
+ context->exponent0 = -1.0 * r * context->f * DST_RCINTEGRATE__C;
+ context->exponent1 = -1.0 * (DST_RCINTEGRATE__R1 + DST_RCINTEGRATE__R2) * DST_RCINTEGRATE__C;
+}
+
+
+/************************************************************************
+ *
+ * DST_RCDISC_MOD - RC triggered by logic and modulated
+ *
+ * input[0] - Enable input value
+ * input[1] - input value 1
+ * input[2] - input value 2
+ * input[3] - Resistor 1 value (initialization only)
+ * input[4] - Resistor 2 value (initialization only)
+ * input[5] - Resistor 3 value (initialization only)
+ * input[6] - Resistor 4 value (initialization only)
+ * input[7] - Capacitor Value (initialization only)
+ * input[8] - Voltage Value (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCDISC_MOD__ENABLE (*(node->input[0]))
+#define DST_RCDISC_MOD__IN1 (*(node->input[1]))
+#define DST_RCDISC_MOD__IN2 (*(node->input[2]))
+#define DST_RCDISC_MOD__R1 (*(node->input[3]))
+#define DST_RCDISC_MOD__R2 (*(node->input[4]))
+#define DST_RCDISC_MOD__R3 (*(node->input[5]))
+#define DST_RCDISC_MOD__R4 (*(node->input[6]))
+#define DST_RCDISC_MOD__C (*(node->input[7]))
+#define DST_RCDISC_MOD__VP (*(node->input[8]))
+
+void dst_rcdisc_mod_step(node_description *node)
+{
+ double diff,Rc,Rc2,vCap,u,vD=0.0;
+ struct dst_rcdisc_context *context = node->context;
+
+ /* Exponential based in difference between input/output */
+ vCap = context->vCap;
+
+ if(DST_RCDISC_MOD__ENABLE)
+ {
+ Rc = (DST_RCDISC_MOD__IN1 > 0.5) ? DST_RCDISC_MOD__R2 : DST_RCDISC_MOD__R1 + DST_RCDISC_MOD__R2;
+ if (Rc<1.0)
+ Rc = 1.0;
+ u = (DST_RCDISC_MOD__IN1 > 0.5) ? 0 : DST_RCDISC_MOD__VP;
+ Rc2 = (DST_RCDISC_MOD__IN2 > 0.6) ? (DST_RCDISC_MOD__R3 * DST_RCDISC_MOD__R4 / (DST_RCDISC_MOD__R3 + DST_RCDISC_MOD__R4)) : DST_RCDISC_MOD__R4;
+ /* Clamp */
+ diff = u - vCap;
+ vD = diff*Rc2/(Rc+Rc2);
+ if (vD<-0.6)
+ {
+ Rc2=0;
+ diff = u + 0.6 - vCap;
+ diff = diff - (diff * exp(0.0-discrete_current_context->sample_time / (DST_RCDISC_MOD__C*Rc)));
+ vCap += diff;
+ node->output = (DST_RCDISC_MOD__IN2 <= 0.6) ? -0.6 : 0;
+ }
+ else
+ {
+ diff = diff - (diff * exp(0.0-discrete_current_context->sample_time / (DST_RCDISC_MOD__C*(Rc+Rc2))));
+ vCap += diff;
+ /* neglecting current through R3 drawn by next node */
+ node->output = (DST_RCDISC_MOD__IN2 <= 0.6) ? (u-vCap)*DST_RCDISC_MOD__R4/(DST_RCDISC_MOD__R4+Rc) : 0;
+ }
+ context->vCap = vCap;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+void dst_rcdisc_mod_reset(node_description *node)
+{
+ struct dst_rcdisc_context *context = node->context;
+
+ node->output=0;
+ context->vCap = 0;
+}
+
+/************************************************************************
+ *
+ * DST_RCFILTER - Usage of node_description values for RC filter
+ *
+ * input[0] - Enable input value
+ * input[1] - input value
+ * input[2] - Resistor value (initialization only)
+ * input[3] - Capacitor Value (initialization only)
+ * input[4] - Voltage reference. Usually 0V.
+ *
+ ************************************************************************/
+#define DST_RCFILTER__ENABLE (*(node->input[0]))
+#define DST_RCFILTER__VIN (*(node->input[1]))
+#define DST_RCFILTER__R (*(node->input[2]))
+#define DST_RCFILTER__C (*(node->input[3]))
+#define DST_RCFILTER__VREF (*(node->input[4]))
+
+void dst_rcfilter_step(node_description *node)
+{
+ struct dst_rcfilter_context *context = node->context;
+
+ /************************************************************************/
+ /* Next Value = PREV + (INPUT_VALUE - PREV)*(1-(EXP(-TIMEDELTA/RC))) */
+ /************************************************************************/
+
+ if(DST_RCFILTER__ENABLE)
+ {
+ context->vCap += ((DST_RCFILTER__VIN - DST_RCFILTER__VREF - context->vCap) * context->exponent);
+ node->output = context->vCap + DST_RCFILTER__VREF;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+void dst_rcfilter_reset(node_description *node)
+{
+ struct dst_rcfilter_context *context = node->context;
+
+ context->exponent = -1.0 / (DST_RCFILTER__R * DST_RCFILTER__C * discrete_current_context->sample_rate);
+ context->exponent = 1.0 - exp(context->exponent);
+ context->vCap = 0;
+ node->output = 0;
+}
+
+
+/* !!!!!!!!!!! NEW FILTERS for testing !!!!!!!!!!!!!!!!!!!!! */
+
+
+/************************************************************************
+ *
+ * DST_RCFILTERN - Usage of node_description values for RC filter
+ *
+ * input[0] - Enable input value
+ * input[1] - input value
+ * input[2] - Resistor value (initialization only)
+ * input[3] - Capacitor Value (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCFILTERN__ENABLE (*(node->input[0]))
+#define DST_RCFILTERN__IN (*(node->input[1]))
+#define DST_RCFILTERN__R (*(node->input[2]))
+#define DST_RCFILTERN__C (*(node->input[3]))
+
+void dst_rcfilterN_reset(node_description *node)
+{
+// double f=1.0/(2*M_PI* DST_RCFILTERN__R * DST_RCFILTERN__C);
+
+// !!!!!!!!!!!!!! CAN'T CHEAT LIKE THIS !!!!!!!!!!!!!!!!
+// Put this stuff in a context
+//
+// node->input[2] = f;
+// node->input[3] = DISC_FILTER_LOWPASS;
+
+ /* Use first order filter */
+ dst_filter1_reset(node);
+}
+
+
+/************************************************************************
+ *
+ * DST_RCDISCN - Usage of node_description values for RC discharge
+ * (inverse slope of DST_RCFILTER)
+ *
+ * input[0] - Enable input value
+ * input[1] - input value
+ * input[2] - Resistor value (initialization only)
+ * input[3] - Capacitor Value (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCDISCN__ENABLE (*(node->input[0]))
+#define DST_RCDISCN__IN (*(node->input[1]))
+#define DST_RCDISCN__R (*(node->input[2]))
+#define DST_RCDISCN__C (*(node->input[3]))
+
+void dst_rcdiscN_reset(node_description *node)
+{
+// double f=1.0/(2*M_PI* DST_RCDISCN__R * DST_RCDISCN__C);
+
+// !!!!!!!!!!!!!! CAN'T CHEAT LIKE THIS !!!!!!!!!!!!!!!!
+// Put this stuff in a context
+//
+// node->input[2] = f;
+// node->input[3] = DISC_FILTER_LOWPASS;
+
+ /* Use first order filter */
+ dst_filter1_reset(node);
+}
+
+void dst_rcdiscN_step(node_description *node)
+{
+ struct dss_filter1_context *context = node->context;
+ double gain = 1.0;
+
+ if (DST_RCDISCN__ENABLE == 0.0)
+ {
+ gain = 0.0;
+ }
+
+ /* A rise in the input signal results in an instant charge, */
+ /* else discharge through the RC to zero */
+ if (gain* DST_RCDISCN__IN > context->x1)
+ node->output = gain* DST_RCDISCN__IN;
+ else
+ node->output = -context->a1*context->y1;
+
+ context->x1 = gain* DST_RCDISCN__IN;
+ context->y1 = node->output;
+}
+
+
+/************************************************************************
+ *
+ * DST_RCDISC2N - Usage of node_description values for RC discharge
+ * Has switchable charge resistor/input
+ *
+ * input[0] - Switch input value
+ * input[1] - input[0] value
+ * input[2] - Resistor0 value (initialization only)
+ * input[3] - input[1] value
+ * input[4] - Resistor1 value (initialization only)
+ * input[5] - Capacitor Value (initialization only)
+ *
+ ************************************************************************/
+#define DST_RCDISC2N__ENABLE (*(node->input[0]))
+#define DST_RCDISC2N__IN0 (*(node->input[1]))
+#define DST_RCDISC2N__R0 (*(node->input[2]))
+#define DST_RCDISC2N__IN1 (*(node->input[3]))
+#define DST_RCDISC2N__R1 (*(node->input[4]))
+#define DST_RCDISC2N__C (*(node->input[5]))
+
+struct dss_rcdisc2_context
+{
+ double x1; /* x[k-1], last input value */
+ double y1; /* y[k-1], last output value */
+ double a1_0, b0_0, b1_0; /* digital filter coefficients, filter #1 */
+ double a1_1, b0_1, b1_1; /* digital filter coefficients, filter #2 */
+};
+
+void dst_rcdisc2N_step(node_description *node)
+{
+ struct dss_rcdisc2_context *context = node->context;
+ double input = ((DST_RCDISC2N__ENABLE == 0) ? DST_RCDISC2N__IN0 : DST_RCDISC2N__IN1);
+
+ if (DST_RCDISC2N__ENABLE == 0)
+ node->output = -context->a1_0*context->y1 + context->b0_0*input + context->b1_0*context->x1;
+ else
+ node->output = -context->a1_1*context->y1 + context->b0_1*input + context->b1_1*context->x1;
+
+ context->x1 = input;
+ context->y1 = node->output;
+}
+
+void dst_rcdisc2N_reset(node_description *node)
+{
+ struct dss_rcdisc2_context *context = node->context;
+ double f1,f2;
+
+ f1=1.0/(2*M_PI* DST_RCDISC2N__R0 * DST_RCDISC2N__C);
+ f2=1.0/(2*M_PI* DST_RCDISC2N__R1 * DST_RCDISC2N__C);
+
+ calculate_filter1_coefficients(f1, DISC_FILTER_LOWPASS, &context->a1_0, &context->b0_0, &context->b1_0);
+ calculate_filter1_coefficients(f2, DISC_FILTER_LOWPASS, &context->a1_1, &context->b0_1, &context->b1_1);
+
+ /* Initialize the object */
+ node->output=0;
+}
diff --git a/src/emu/sound/disc_inp.c b/src/emu/sound/disc_inp.c
new file mode 100644
index 00000000000..856e8077544
--- /dev/null
+++ b/src/emu/sound/disc_inp.c
@@ -0,0 +1,261 @@
+/************************************************************************
+ *
+ * MAME - Discrete sound system emulation library
+ *
+ * Written by Keith Wilkins (mame@esplexo.co.uk)
+ *
+ * (c) K.Wilkins 2000
+ *
+ ***********************************************************************
+ *
+ * DSS_ADJUSTMENT - UI Mapped adjustable input
+ * DSS_CONSTANT - Node based constant - Do we need this ???
+ * DSS_INPUT_x - Input devices
+ * DSS_INPUT_STREAM - Connects external streams to the discrete system
+ *
+ ************************************************************************/
+
+#define DSS_INPUT__GAIN (*(node->input[0]))
+#define DSS_INPUT__OFFSET (*(node->input[1]))
+#define DSS_INPUT__INIT (*(node->input[2]))
+
+
+struct dss_adjustment_context
+{
+ INT32 port;
+ INT32 lastpval;
+ INT32 pmin;
+ double pscale;
+ double min;
+ double scale;
+};
+
+
+READ8_HANDLER(discrete_sound_r)
+{
+ discrete_info *info = sndti_token(SOUND_DISCRETE, 0);
+ node_description *node = discrete_find_node(info, offset);
+ UINT8 data = 0;
+
+ /* Read the node input value if allowed */
+ if (node)
+ {
+ UINT8 *node_data = node->context;
+
+ if ((node->module.type >= DSS_INPUT_DATA) && (node->module.type <= DSS_INPUT_PULSE))
+ {
+ data = *node_data;
+ }
+ }
+ else
+ discrete_log("discrete_sound_r read from non-existent NODE_%02d\n", offset-NODE_00);
+
+ return data;
+}
+
+WRITE8_HANDLER(discrete_sound_w)
+{
+ discrete_info *info = sndti_token(SOUND_DISCRETE, 0);
+ node_description *node = discrete_find_node(info, offset);
+
+ /* Update the node input value if it's a proper input node */
+ if (node)
+ {
+ UINT8 *node_data = node->context;
+ UINT8 last_data = *node_data;
+
+ switch (node->module.type)
+ {
+ case DSS_INPUT_DATA:
+ *node_data = data;
+ break;
+ case DSS_INPUT_LOGIC:
+ case DSS_INPUT_PULSE:
+ *node_data = data ? 1 : 0;
+ break;
+ case DSS_INPUT_NOT:
+ *node_data = data ? 0 : 1;
+ break;
+ }
+
+ /* Bring the system up to now */
+ if (last_data != *node_data)
+ stream_update(info->discrete_stream);
+ }
+ else
+ {
+ discrete_log("discrete_sound_w write to non-existent NODE_%02d\n", offset-NODE_00);
+ }
+}
+
+
+/************************************************************************
+ *
+ * DSS_ADJUSTMENT - UI Adjustable constant node to emulate trimmers
+ *
+ * input[0] - Enable
+ * input[1] - Minimum value
+ * input[2] - Maximum value
+ * input[3] - Log/Linear 0=Linear !0=Log
+ * input[4] - Input Port number
+ * input[5] -
+ * input[6] -
+ *
+ ************************************************************************/
+#define DSS_ADJUSTMENT__ENABLE (*(node->input[0]))
+#define DSS_ADJUSTMENT__MIN (*(node->input[1]))
+#define DSS_ADJUSTMENT__MAX (*(node->input[2]))
+#define DSS_ADJUSTMENT__LOG (*(node->input[3]))
+#define DSS_ADJUSTMENT__PORT (*(node->input[4]))
+#define DSS_ADJUSTMENT__PMIN (*(node->input[5]))
+#define DSS_ADJUSTMENT__PMAX (*(node->input[6]))
+
+void dss_adjustment_step(node_description *node)
+{
+ if (DSS_ADJUSTMENT__ENABLE)
+ {
+ struct dss_adjustment_context *context = node->context;
+ INT32 rawportval = readinputport(context->port);
+
+ /* only recompute if the value changed from last time */
+ if (rawportval != context->lastpval)
+ {
+ double portval = (double)(rawportval - context->pmin) * context->pscale;
+ double scaledval = portval * context->scale + context->min;
+
+ context->lastpval = rawportval;
+ if (DSS_ADJUSTMENT__LOG == 0)
+ node->output = scaledval;
+ else
+ node->output = pow(10, scaledval);
+ }
+ }
+ else
+ {
+ node->output = 0;
+ }
+}
+
+void dss_adjustment_reset(node_description *node)
+{
+ struct dss_adjustment_context *context = node->context;
+ double min, max;
+
+ if (node->custom)
+ {
+ context->port = port_tag_to_index(node->custom);
+ if (context->port == -1)
+ fatalerror("DISCRETE_ADJUSTMENT_TAG - NODE_%d has invalid tag", node->node-NODE_00);
+ }
+ else
+ context->port = DSS_ADJUSTMENT__PORT;
+
+ context->lastpval = 0x7fffffff;
+ context->pmin = DSS_ADJUSTMENT__PMIN;
+ context->pscale = 1.0 / (double)(DSS_ADJUSTMENT__PMAX - DSS_ADJUSTMENT__PMIN);
+
+ /* linear scale */
+ if (DSS_ADJUSTMENT__LOG == 0)
+ {
+ context->min = DSS_ADJUSTMENT__MIN;
+ context->scale = DSS_ADJUSTMENT__MAX - DSS_ADJUSTMENT__MIN;
+ }
+
+ /* logarithmic scale */
+ else
+ {
+ /* force minimum and maximum to be > 0 */
+ min = (DSS_ADJUSTMENT__MIN > 0) ? DSS_ADJUSTMENT__MIN : 1;
+ max = (DSS_ADJUSTMENT__MAX > 0) ? DSS_ADJUSTMENT__MAX : 1;
+ context->min = log10(min);
+ context->scale = log10(max) - log10(min);
+ }
+
+ dss_adjustment_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSS_CONSTANT - This is a constant.
+ *
+ * input[0] - Constant value
+ *
+ ************************************************************************/
+#define DSS_CONSTANT__INIT (*(node->input[0]))
+
+void dss_constant_step(node_description *node)
+{
+ node->output= DSS_CONSTANT__INIT;
+}
+
+
+/************************************************************************
+ *
+ * DSS_INPUT_x - Receives input from discrete_sound_w
+ *
+ * input[0] - Gain value
+ * input[1] - Offset value
+ * input[2] - Starting Position
+ * input[3] - Current data value
+ *
+ ************************************************************************/
+void dss_input_step(node_description *node)
+{
+ UINT8 *node_data = node->context;
+
+ node->output = *node_data * DSS_INPUT__GAIN + DSS_INPUT__OFFSET;
+}
+
+void dss_input_reset(node_description *node)
+{
+ UINT8 *node_data = node->context;
+
+ switch (node->module.type)
+ {
+ case DSS_INPUT_DATA:
+ *node_data = DSS_INPUT__INIT;
+ break;
+ case DSS_INPUT_LOGIC:
+ case DSS_INPUT_PULSE:
+ *node_data = (DSS_INPUT__INIT == 0) ? 0 : 1;
+ break;
+ case DSS_INPUT_NOT:
+ *node_data = (DSS_INPUT__INIT == 0) ? 1 : 0;
+ break;
+ }
+ dss_input_step(node);
+}
+
+void dss_input_pulse_step(node_description *node)
+{
+ UINT8 *node_data = node->context;
+
+ /* Set a valid output */
+ node->output = *node_data;
+ /* Reset the input to default for the next cycle */
+ /* node order is now important */
+ *node_data = DSS_INPUT__INIT;
+}
+
+
+/************************************************************************
+ *
+ * DSS_INPUT_STREAM - Receives input from a routed stream
+ *
+ * input[0] - Input stream number
+ * input[1] - Gain value
+ * input[2] - Offset value
+ *
+ ************************************************************************/
+#define DSS_INPUT_STREAM__STREAM (*(node->input[0]))
+#define DSS_INPUT_STREAM__GAIN (*(node->input[1]))
+#define DSS_INPUT_STREAM__OFFSET (*(node->input[2]))
+
+void dss_input_stream_step(node_description *node)
+{
+ // the context pointer is set to point to the current input stream data in discrete_stream_update
+ stream_sample_t *data = node->context;
+
+ node->output = data ? *data++ * DSS_INPUT_STREAM__GAIN + DSS_INPUT_STREAM__OFFSET : 0;
+}
diff --git a/src/emu/sound/disc_mth.c b/src/emu/sound/disc_mth.c
new file mode 100644
index 00000000000..47c3de9422f
--- /dev/null
+++ b/src/emu/sound/disc_mth.c
@@ -0,0 +1,1968 @@
+/************************************************************************
+ *
+ * MAME - Discrete sound system emulation library
+ *
+ * Written by Keith Wilkins (mame@esplexo.co.uk)
+ *
+ * (c) K.Wilkins 2000
+ * (c) D.Renaud 2003-2004
+ *
+ ************************************************************************
+ *
+ * DST_ADDDER - Multichannel adder
+ * DST_CLAMP - Simple signal clamping circuit
+ * DST_COMP_ADDER - Selectable parallel component circuit
+ * DST_DAC_R1 - R1 Ladder DAC with cap filtering
+ * DST_DIODE_MIX - Diode mixer
+ * DST_DIVIDE - Division function
+ * DST_GAIN - Gain Factor
+ * DST_INTEGRATE - Integration circuits
+ * DST_LOGIC_INV - Logic level invertor
+ * DST_LOGIC_AND - Logic AND gate 4 input
+ * DST_LOGIC_NAND - Logic NAND gate 4 input
+ * DST_LOGIC_OR - Logic OR gate 4 input
+ * DST_LOGIC_NOR - Logic NOR gate 4 input
+ * DST_LOGIC_XOR - Logic XOR gate 2 input
+ * DST_LOGIC_NXOR - Logic NXOR gate 2 input
+ * DST_LOGIC_DFF - Logic D-type flip/flop
+ * DST_LOGIC_JKFF - Logic JK-type flip/flop
+ * DST_LOOKUP_TABLE - Return value from lookup table
+ * DST_MIXER - Final Mixer Stage
+ * DST_MULTIPLEX - 1 of x Multiplexer/switch
+ * DST_ONESHOT - One shot pulse generator
+ * DST_RAMP - Ramp up/down
+ * DST_SAMPHOLD - Sample & Hold Implementation
+ * DST_SWITCH - Switch implementation
+ * DST_ASWITCH - Analog switch
+ * DST_TRANSFORM - Multiple math functions
+ * DST_OP_AMP - Op Amp circuits
+ * DST_OP_AMP_1SHT - Op Amp One Shot
+ * DST_TVCA_OP_AMP - Triggered op amp voltage controlled amplifier
+ *
+ ************************************************************************/
+
+#include <float.h>
+
+struct dst_dac_r1_context
+{
+ double iBias; // current of the bias circuit
+ double exponent; // smoothing curve
+ double rTotal; // all resistors in parallel
+};
+
+struct dst_flipflop_context
+{
+ int last_clk;
+};
+
+struct dst_integrate_context
+{
+ double change;
+ double vMaxIn; // v1 - norton VBE
+ double vMaxInD; // v1 - norton VBE - diode drop
+ double vMaxOut;
+};
+
+#define DISC_MIXER_MAX_INPS 8
+
+struct dst_mixer_context
+{
+ int type;
+ int size;
+ double rTotal;
+ double *rNode[DISC_MIXER_MAX_INPS]; // Either pointer to resistance node output OR NULL
+ double exponent_rc[DISC_MIXER_MAX_INPS]; // For high pass filtering cause by cIn
+ double vCap[DISC_MIXER_MAX_INPS]; // cap voltage of each input
+ double exponent_cF; // Low pass on mixed inputs
+ double exponent_cAmp; // Final high pass caused by out cap and amp input impedance
+ double vCapF; // cap voltage of cF
+ double vCapAmp; // cap voltage of cAmp
+ double gain; // used for DISC_MIXER_IS_OP_AMP_WITH_RI
+};
+
+struct dst_oneshot_context
+{
+ double countdown;
+ int state;
+ int lastTrig;
+};
+
+struct dss_ramp_context
+{
+ double step;
+ int dir; /* 1 if End is higher then Start */
+ int last_en; /* Keep track of the last enable value */
+};
+
+struct dst_samphold_context
+{
+ double lastinput;
+ int clocktype;
+};
+
+struct dst_size_context
+{
+ int size;
+};
+
+struct dst_op_amp_context
+{
+ UINT8 has_cap;
+ UINT8 has_r1;
+ UINT8 has_r4;
+ double vMax;
+ double iFixed;
+ double vCap;
+ double exponent;
+};
+
+struct dst_op_amp_1sht_context
+{
+ double iFixed;
+ double vMax;
+ double r34ratio;
+ double vCap1;
+ double vCap2;
+ double exponent1c;
+ double exponent1d;
+ double exponent2;
+};
+
+struct dst_tvca_op_amp_context
+{
+ double vOutMax; // Maximum output voltage
+ double vTrig[2]; // Voltage used to charge cap1 based on function F3
+ double vTrig2; // Voltage used to charge cap2
+ double vTrig3; // Voltage used to charge cap3
+ double iFixed; // Fixed current going into - input
+ double exponentC[2]; // Charge exponents based on function F3
+ double exponentD[2]; // Discharge exponents based on function F3
+ double exponent2[2]; // Discharge/charge exponents based on function F4
+ double exponent3[2]; // Discharge/charge exponents based on function F5
+ double vCap1; // charge on cap c1
+ double vCap2; // charge on cap c2
+ double vCap3; // charge on cap c3
+ double r67; // = r6 + r7 (for easy use later)
+};
+
+
+/************************************************************************
+ *
+ * DST_ADDER - This is a 4 channel input adder with enable function
+ *
+ * input[0] - Enable input value
+ * input[1] - Channel0 input value
+ * input[2] - Channel1 input value
+ * input[3] - Channel2 input value
+ * input[4] - Channel3 input value
+ *
+ ************************************************************************/
+#define DST_ADDER__ENABLE (*(node->input[0]))
+#define DST_ADDER__IN0 (*(node->input[1]))
+#define DST_ADDER__IN1 (*(node->input[2]))
+#define DST_ADDER__IN2 (*(node->input[3]))
+#define DST_ADDER__IN3 (*(node->input[4]))
+
+void dst_adder_step(node_description *node)
+{
+ if(DST_ADDER__ENABLE)
+ {
+ node->output = DST_ADDER__IN0 + DST_ADDER__IN1 + DST_ADDER__IN2 + DST_ADDER__IN3;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+
+/************************************************************************
+ *
+ * DST_COMP_ADDER - Selectable parallel component adder
+ *
+ * input[0] - Enable input value
+ * input[1] - Bit Select
+ *
+ * Also passed discrete_comp_adder_table structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DST_COMP_ADDER__ENABLE (*(node->input[0]))
+#define DST_COMP_ADDER__SELECT (int)(*(node->input[1]))
+
+void dst_comp_adder_step(node_description *node)
+{
+ const discrete_comp_adder_table *info = node->custom;
+ int bit;
+
+ if(DST_COMP_ADDER__ENABLE)
+ {
+ switch (info->type)
+ {
+ case DISC_COMP_P_CAPACITOR:
+ node->output = info->cDefault;
+ for(bit=0; bit < info->length; bit++)
+ {
+ if (DST_COMP_ADDER__SELECT & (1 << bit)) node->output += info->c[bit];
+ }
+ break;
+ case DISC_COMP_P_RESISTOR:
+ node->output = info->cDefault ? 1.0 / info->cDefault : 0;
+ for(bit=0; bit < info->length; bit++)
+ {
+ if (DST_COMP_ADDER__SELECT & (1 << bit)) node->output += 1.0 / info->c[bit];
+ }
+ if (node->output != 0) node->output = 1.0 / node->output;
+ break;
+ }
+ }
+ else
+ {
+ node->output = 0;
+ }
+}
+
+
+/************************************************************************
+ *
+ * DST_CLAMP - Simple signal clamping circuit
+ *
+ * input[0] - Enable ramp
+ * input[1] - Input value
+ * input[2] - Minimum value
+ * input[3] - Maximum value
+ * input[4] - Clamp output when disabled
+ *
+ ************************************************************************/
+#define DST_CLAMP__ENABLE (*(node->input[0]))
+#define DST_CLAMP__IN (*(node->input[1]))
+#define DST_CLAMP__MIN (*(node->input[2]))
+#define DST_CLAMP__MAX (*(node->input[3]))
+#define DST_CLAMP__CLAMP (*(node->input[4]))
+
+void dst_clamp_step(node_description *node)
+{
+ if(DST_CLAMP__ENABLE)
+ {
+ if(DST_CLAMP__IN < DST_CLAMP__MIN) node->output = DST_CLAMP__MIN;
+ else if(DST_CLAMP__IN > DST_CLAMP__MAX) node->output = DST_CLAMP__MAX;
+ else node->output= DST_CLAMP__IN;
+ }
+ else
+ {
+ node->output = DST_CLAMP__CLAMP;
+ }
+}
+
+
+/************************************************************************
+ *
+ * DST_DAC_R1 - R1 Ladder DAC with cap smoothing
+ *
+ * input[0] - Enable
+ * input[1] - Binary Data Input
+ * input[2] - Data On Voltage (3.4 for TTL)
+ *
+ * also passed discrete_dac_r1_ladder structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DST_DAC_R1__ENABLE (*(node->input[0]))
+#define DST_DAC_R1__DATA (int)(*(node->input[1]))
+#define DST_DAC_R1__VON (*(node->input[2]))
+
+void dst_dac_r1_step(node_description *node)
+{
+ const discrete_dac_r1_ladder *info = node->custom;
+ struct dst_dac_r1_context *context = node->context;
+
+ int bit;
+ double v;
+ double i;
+
+ i = context->iBias;
+
+ if (DST_DAC_R1__ENABLE)
+ {
+ for (bit=0; bit < info->ladderLength; bit++)
+ {
+ /* Add up currents of ON circuits per Millman. */
+ /* Off, being 0V and having no current, can be ignored. */
+ if ((DST_DAC_R1__DATA & (1 << bit)) && info->r[bit])
+ i += DST_DAC_R1__VON / info->r[bit];
+ }
+
+ v = i * context->rTotal;
+
+ /* Filter if needed, else just output voltage */
+ node->output = info->cFilter ? node->output + ((v - node->output) * context->exponent) : v;
+ }
+ else
+ {
+ /*
+ * If module is disabled we will just leave the voltage where it was.
+ * We may want to set it to 0 in the future, but we will probably never
+ * disable this module.
+ */
+ }
+}
+
+void dst_dac_r1_reset(node_description *node)
+{
+ const discrete_dac_r1_ladder *info = node->custom;
+ struct dst_dac_r1_context *context = node->context;
+
+ int bit;
+
+ /* Calculate the Millman current of the bias circuit */
+ if (info->rBias)
+ context->iBias = info->vBias / info->rBias;
+ else
+ context->iBias = 0;
+
+ /*
+ * We will do a small amount of error checking.
+ * But if you are an idiot and pass a bad ladder table
+ * then you deserve a crash.
+ */
+ if (info->ladderLength < 2)
+ {
+ /* You need at least 2 resistors for a ladder */
+ discrete_log("dst_dac_r1_reset - Ladder length too small");
+ }
+ if (info->ladderLength > DISC_LADDER_MAXRES )
+ {
+ discrete_log("dst_dac_r1_reset - Ladder length exceeds DISC_LADDER_MAXRES");
+ }
+
+ /*
+ * Calculate the total of all resistors in parallel.
+ * This is the combined resistance of the voltage sources.
+ * This is used for the charging curve.
+ */
+ context->rTotal = 0;
+ for(bit=0; bit < info->ladderLength; bit++)
+ {
+ if (info->r[bit])
+ context->rTotal += 1.0 / info->r[bit];
+ }
+ if (info->rBias) context->rTotal += 1.0 / info->rBias;
+ if (info->rGnd) context->rTotal += 1.0 / info->rGnd;
+ context->rTotal = 1.0 / context->rTotal;
+
+ node->output = 0;
+
+ if (info->cFilter)
+ {
+ /* Setup filter constants */
+ context->exponent = -1.0 / (context->rTotal * info->cFilter * discrete_current_context->sample_rate);
+ context->exponent = 1.0 - exp(context->exponent);
+ }
+}
+
+
+/************************************************************************
+*
+ * DST_DIODE_MIX - Diode Mixer
+ *
+ * input[0] - Enable input value
+ * input[1] - Diode junction voltage drop
+ * input[2] - Input 0
+ * .....
+ *
+ * Dec 2004, D Renaud.
+ ************************************************************************/
+#define DST_DIODE_MIX__ENABLE (*(node->input[0]))
+#define DST_DIODE_MIX__VJUNC (*(node->input[1]))
+#define DST_DIODE_MIX__INP(addr) (*(node->input[2 + addr]))
+
+void dst_diode_mix_step(node_description *node)
+{
+ struct dst_size_context *context = node->context;
+ double max = 0;
+ int addr;
+
+ if (DST_DIODE_MIX__ENABLE)
+ {
+ for (addr = 0; addr < context->size; addr++)
+ {
+ if (DST_DIODE_MIX__INP(addr) > max) max = DST_DIODE_MIX__INP(addr);
+ }
+ node->output = max - DST_DIODE_MIX__VJUNC;
+ if (node->output < 0) node->output = 0;
+ }
+ else
+ {
+ node->output = 0;
+ }
+}
+
+void dst_diode_mix_reset(node_description *node)
+{
+ struct dst_size_context *context = node->context;
+
+ context->size = node->active_inputs - 2;
+
+ dst_diode_mix_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DST_DIVIDE - Programmable divider with enable
+ *
+ * input[0] - Enable input value
+ * input[1] - Channel0 input value
+ * input[2] - Divisor
+ *
+ ************************************************************************/
+#define DST_DIVIDE__ENABLE (*(node->input[0]))
+#define DST_DIVIDE__IN (*(node->input[1]))
+#define DST_DIVIDE__DIV (*(node->input[2]))
+
+void dst_divide_step(node_description *node)
+{
+ if(DST_DIVIDE__ENABLE)
+ {
+ if(DST_DIVIDE__DIV == 0)
+ {
+ node->output=DBL_MAX; /* Max out but don't break */
+ discrete_log("dst_divider_step() - Divide by Zero attempted in NODE_%02d.\n",node->node-NODE_START);
+ }
+ else
+ {
+ node->output= DST_DIVIDE__IN / DST_DIVIDE__DIV;
+ }
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+
+/************************************************************************
+ *
+ * DST_GAIN - This is a programmable gain module with enable function
+ *
+ * input[0] - Enable input value
+ * input[1] - Channel0 input value
+ * input[2] - Gain value
+ * input[3] - Final addition offset
+ *
+ ************************************************************************/
+#define DST_GAIN__ENABLE (*(node->input[0]))
+#define DST_GAIN__IN (*(node->input[1]))
+#define DST_GAIN__GAIN (*(node->input[2]))
+#define DST_GAIN__OFFSET (*(node->input[3]))
+
+void dst_gain_step(node_description *node)
+{
+ if(DST_GAIN__ENABLE)
+ {
+ node->output = DST_GAIN__IN * DST_GAIN__GAIN;
+ node->output += DST_GAIN__OFFSET;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+
+/************************************************************************
+ *
+ * DST_INTEGRATE - Integration circuits
+ *
+ * input[0] - Trigger 0
+ * input[1] - Trigger 1
+ *
+ * also passed discrete_integrate_info structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DST_INTEGRATE__TRG0 (*(node->input[0]))
+#define DST_INTEGRATE__TRG1 (*(node->input[1]))
+
+int dst_trigger_function(int trig0, int trig1, int trig2, int function)
+{
+ int result = 1;
+ switch (function)
+ {
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG0:
+ result = trig0;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV:
+ result = !trig0;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG1:
+ result = trig1;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG1_INV:
+ result = !trig1;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG2:
+ result = trig2;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG2_INV:
+ result = !trig2;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_AND:
+ result = trig0 && trig1;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_NAND:
+ result = !(trig0 && trig1);
+ break;
+ }
+
+ return (result);
+}
+
+void dst_integrate_step(node_description *node)
+{
+ const discrete_integrate_info *info = node->custom;
+ struct dst_integrate_context *context = node->context;
+
+ int trig0, trig1;
+ double iNeg = 0; // current into - input
+ double iPos = 0; // current into + input
+
+ switch (info->type)
+ {
+ case DISC_INTEGRATE_OP_AMP_1:
+ if (DST_INTEGRATE__TRG0 != 0)
+ {
+ /* This forces the cap to completely charge,
+ * and the output to go to it's max value.
+ */
+ node->output = context->vMaxOut;
+ return;
+ }
+ node->output -= context->change;
+ break;
+
+ case DISC_INTEGRATE_OP_AMP_1 | DISC_OP_AMP_IS_NORTON:
+ iNeg = context->vMaxIn / info->r1;
+ iPos = (DST_INTEGRATE__TRG0 - OP_AMP_NORTON_VBE) / info->r2;
+ if (iPos < 0) iPos = 0;
+ node->output += (iPos - iNeg) / discrete_current_context->sample_rate / info->c;
+ break;
+
+ case DISC_INTEGRATE_OP_AMP_2 | DISC_OP_AMP_IS_NORTON:
+ trig0 = (int)DST_INTEGRATE__TRG0;
+ trig1 = (int)DST_INTEGRATE__TRG1;
+ iNeg = dst_trigger_function(trig0, trig1, 0, info->f0) ? context->vMaxInD / info->r1 : 0;
+ iPos = dst_trigger_function(trig0, trig1, 0, info->f1) ? context->vMaxIn / info->r2 : 0;
+ iPos += dst_trigger_function(trig0, trig1, 0, info->f2) ? context->vMaxInD / info->r3 : 0;
+ node->output += (iPos - iNeg) / discrete_current_context->sample_rate / info->c;
+ break;
+ }
+
+ /* Clip the output. */
+ if (node->output < 0) node->output = 0;
+ if (node->output > context->vMaxOut) node->output = context->vMaxOut;
+}
+
+void dst_integrate_reset(node_description *node)
+{
+ const discrete_integrate_info *info = node->custom;
+ struct dst_integrate_context *context = node->context;
+ double i, v;
+
+ if (info->type & DISC_OP_AMP_IS_NORTON)
+ {
+ context->vMaxOut = info->vP - OP_AMP_NORTON_VBE;
+ context->vMaxIn = info->v1 - OP_AMP_NORTON_VBE;
+ context->vMaxInD = context->vMaxIn - OP_AMP_NORTON_VBE;
+ }
+ else
+ {
+ context->vMaxOut = info->vP - OP_AMP_VP_RAIL_OFFSET;
+
+ v = info->v1 * info->r3 / (info->r2 + info->r3); /* vRef */
+ v = info->v1 - v; /* actual charging voltage */
+ i = v / info->r1;
+ context->change = i / discrete_current_context->sample_rate / info->c;
+ }
+ node->output = 0;
+}
+
+
+/************************************************************************
+ *
+ * DST_LOGIC_INV - Logic invertor gate implementation
+ *
+ * input[0] - Enable
+ * input[1] - input[0] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_INV__ENABLE (*(node->input[0]))
+#define DST_LOGIC_INV__IN (*(node->input[1]))
+
+void dst_logic_inv_step(node_description *node)
+{
+ if(DST_LOGIC_INV__ENABLE)
+ {
+ node->output = DST_LOGIC_INV__IN ? 0.0 : 1.0;
+ }
+ else
+ {
+ node->output=0.0;
+ }
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_AND - Logic AND gate implementation
+ *
+ * input[0] - Enable
+ * input[1] - input[0] value
+ * input[2] - input[1] value
+ * input[3] - input[2] value
+ * input[4] - input[3] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_AND__ENABLE (*(node->input[0]))
+#define DST_LOGIC_AND__IN0 (*(node->input[1]))
+#define DST_LOGIC_AND__IN1 (*(node->input[2]))
+#define DST_LOGIC_AND__IN2 (*(node->input[3]))
+#define DST_LOGIC_AND__IN3 (*(node->input[4]))
+
+void dst_logic_and_step(node_description *node)
+{
+ if(DST_LOGIC_AND__ENABLE)
+ {
+ node->output= (DST_LOGIC_AND__IN0 && DST_LOGIC_AND__IN1 && DST_LOGIC_AND__IN2 && DST_LOGIC_AND__IN3)? 1.0 : 0.0;
+ }
+ else
+ {
+ node->output=0.0;
+ }
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_NAND - Logic NAND gate implementation
+ *
+ * input[0] - Enable
+ * input[1] - input[0] value
+ * input[2] - input[1] value
+ * input[3] - input[2] value
+ * input[4] - input[3] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_NAND__ENABLE (*(node->input[0]))
+#define DST_LOGIC_NAND__IN0 (*(node->input[1]))
+#define DST_LOGIC_NAND__IN1 (*(node->input[2]))
+#define DST_LOGIC_NAND__IN2 (*(node->input[3]))
+#define DST_LOGIC_NAND__IN3 (*(node->input[4]))
+
+void dst_logic_nand_step(node_description *node)
+{
+ if(DST_LOGIC_NAND__ENABLE)
+ {
+ node->output= (DST_LOGIC_NAND__IN0 && DST_LOGIC_NAND__IN1 && DST_LOGIC_NAND__IN2 && DST_LOGIC_NAND__IN3)? 0.0 : 1.0;
+ }
+ else
+ {
+ node->output=0.0;
+ }
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_OR - Logic OR gate implementation
+ *
+ * input[0] - Enable
+ * input[1] - input[0] value
+ * input[2] - input[1] value
+ * input[3] - input[2] value
+ * input[4] - input[3] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_OR__ENABLE (*(node->input[0]))
+#define DST_LOGIC_OR__IN0 (*(node->input[1]))
+#define DST_LOGIC_OR__IN1 (*(node->input[2]))
+#define DST_LOGIC_OR__IN2 (*(node->input[3]))
+#define DST_LOGIC_OR__IN3 (*(node->input[4]))
+
+void dst_logic_or_step(node_description *node)
+{
+ if(DST_LOGIC_OR__ENABLE)
+ {
+ node->output = (DST_LOGIC_OR__IN0 || DST_LOGIC_OR__IN1 || DST_LOGIC_OR__IN2 || DST_LOGIC_OR__IN3) ? 1.0 : 0.0;
+ }
+ else
+ {
+ node->output=0.0;
+ }
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_NOR - Logic NOR gate implementation
+ *
+ * input[0] - Enable
+ * input[1] - input[0] value
+ * input[2] - input[1] value
+ * input[3] - input[2] value
+ * input[4] - input[3] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_NOR__ENABLE (*(node->input[0]))
+#define DST_LOGIC_NOR__IN0 (*(node->input[1]))
+#define DST_LOGIC_NOR__IN1 (*(node->input[2]))
+#define DST_LOGIC_NOR__IN2 (*(node->input[3]))
+#define DST_LOGIC_NOR__IN3 (*(node->input[4]))
+
+void dst_logic_nor_step(node_description *node)
+{
+ if(DST_LOGIC_NOR__ENABLE)
+ {
+ node->output = (DST_LOGIC_NOR__IN0 || DST_LOGIC_NOR__IN1 || DST_LOGIC_NOR__IN2 || DST_LOGIC_NOR__IN3) ? 0.0 : 1.0;
+ }
+ else
+ {
+ node->output=0.0;
+ }
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_XOR - Logic XOR gate implementation
+ *
+ * input[0] - Enable
+ * input[1] - input[0] value
+ * input[2] - input[1] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_XOR__ENABLE (*(node->input[0]))
+#define DST_LOGIC_XOR__IN0 (*(node->input[1]))
+#define DST_LOGIC_XOR__IN1 (*(node->input[2]))
+
+void dst_logic_xor_step(node_description *node)
+{
+ if(DST_LOGIC_XOR__ENABLE)
+ {
+ node->output=((DST_LOGIC_XOR__IN0 && !DST_LOGIC_XOR__IN1) || (!DST_LOGIC_XOR__IN0 && DST_LOGIC_XOR__IN1)) ? 1.0 : 0.0;
+ }
+ else
+ {
+ node->output=0.0;
+ }
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_NXOR - Logic NXOR gate implementation
+ *
+ * input[0] - Enable
+ * input[1] - input[0] value
+ * input[2] - input[1] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_XNOR__ENABLE (*(node->input[0]))
+#define DST_LOGIC_XNOR__IN0 (*(node->input[1]))
+#define DST_LOGIC_XNOR__IN1 (*(node->input[2]))
+
+void dst_logic_nxor_step(node_description *node)
+{
+ if(DST_LOGIC_XNOR__ENABLE)
+ {
+ node->output=((DST_LOGIC_XNOR__IN0 && !DST_LOGIC_XNOR__IN1) || (!DST_LOGIC_XNOR__IN0 && DST_LOGIC_XNOR__IN1)) ? 0.0 : 1.0;
+ }
+ else
+ {
+ node->output=0.0;
+ }
+}
+
+
+/************************************************************************
+ *
+ * DST_LOGIC_DFF - Standard D-type flip-flop implementation
+ *
+ * input[0] - enable
+ * input[1] - /Reset
+ * input[2] - /Set
+ * input[3] - clock
+ * input[4] - data
+ *
+ ************************************************************************/
+#define DST_LOGIC_DFF__ENABLE (*(node->input[0]))
+#define DST_LOGIC_DFF__RESET !(*(node->input[1]))
+#define DST_LOGIC_DFF__SET !(*(node->input[2]))
+#define DST_LOGIC_DFF__CLOCK (*(node->input[3]))
+#define DST_LOGIC_DFF__DATA (*(node->input[4]))
+
+void dst_logic_dff_step(node_description *node)
+{
+ struct dst_flipflop_context *context = node->context;
+ int clk = (int)DST_LOGIC_DFF__CLOCK;
+
+ if (DST_LOGIC_DFF__ENABLE)
+ {
+ if (DST_LOGIC_DFF__RESET)
+ node->output = 0;
+ else if (DST_LOGIC_DFF__SET)
+ node->output = 1;
+ else if (!context->last_clk && clk) /* low to high */
+ {
+ node->output = DST_LOGIC_DFF__DATA;
+ }
+ }
+ else
+ {
+ node->output = 0;
+ }
+ context->last_clk = clk;
+}
+
+void dst_logic_ff_reset(node_description *node)
+{
+ struct dst_flipflop_context *context = node->context;
+ context->last_clk = 0;
+ node->output = 0;
+}
+
+
+/************************************************************************
+ *
+ * DST_LOGIC_JKFF - Standard JK-type flip-flop implementation
+ *
+ * input[0] - enable
+ * input[1] - /Reset
+ * input[2] - /Set
+ * input[3] - clock
+ * input[4] - J
+ * input[5] - K
+ *
+ ************************************************************************/
+#define DST_LOGIC_JKFF__ENABLE (*(node->input[0]))
+#define DST_LOGIC_JKFF__RESET !(*(node->input[1]))
+#define DST_LOGIC_JKFF__SET !(*(node->input[2]))
+#define DST_LOGIC_JKFF__CLOCK (*(node->input[3]))
+#define DST_LOGIC_JKFF__J (*(node->input[4]))
+#define DST_LOGIC_JKFF__K (*(node->input[5]))
+
+void dst_logic_jkff_step(node_description *node)
+{
+ struct dst_flipflop_context *context = node->context;
+ int clk = (int)DST_LOGIC_JKFF__CLOCK;
+ int j = (int)DST_LOGIC_JKFF__J;
+ int k = (int)DST_LOGIC_JKFF__K;
+
+ if (DST_LOGIC_JKFF__ENABLE)
+ {
+ if (DST_LOGIC_JKFF__RESET)
+ node->output = 0;
+ else if (DST_LOGIC_JKFF__SET)
+ node->output = 1;
+ else if (context->last_clk && !clk) /* high to low */
+ {
+ if (!j)
+ {
+ /* J=0, K=0 - Hold */
+ if (k)
+ /* J=0, K=1 - Reset */
+ node->output = 0;
+ }
+ else
+ {
+ if (!k)
+ /* J=1, K=0 - Set */
+ node->output = 1;
+ else
+ /* J=1, K=1 - Toggle */
+ node->output = !(int)node->output;
+ }
+ }
+ }
+ else
+ {
+ node->output=0;
+ }
+ context->last_clk = clk;
+}
+
+
+/************************************************************************
+ *
+ * DST_LOOKUP_TABLE - Return value from lookup table
+ *
+ * input[0] - Enable input value
+ * input[1] - Input 1
+ * input[2] - Table size
+ *
+ * Also passed address of the lookup table
+ *
+ * Feb 2007, D Renaud.
+ ************************************************************************/
+#define DST_LOOKUP_TABLE__ENABLE (*(node->input[0]))
+#define DST_LOOKUP_TABLE__IN (*(node->input[1]))
+#define DST_LOOKUP_TABLE__SIZE (*(node->input[2]))
+
+void dst_lookup_table_step(node_description *node)
+{
+ const double *table = node->custom;
+ int addr = DST_LOOKUP_TABLE__IN;
+
+ if (!DST_LOOKUP_TABLE__ENABLE || addr < 0 || addr >= DST_LOOKUP_TABLE__SIZE)
+ node->output = 0;
+ else
+ node->output = table[addr];
+}
+
+/************************************************************************
+ *
+ * DST_MIXER - Mixer/Gain stage
+ *
+ * input[0] - Enable input value
+ * input[1] - Input 1
+ * input[2] - Input 2
+ * input[3] - Input 3
+ * input[4] - Input 4
+ * input[5] - Input 5
+ * input[6] - Input 6
+ * input[7] - Input 7
+ * input[8] - Input 8
+ *
+ * Also passed discrete_mixer_info structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+/*
+ * The input resistors can be a combination of static values and nodes.
+ * If a node is used then its value is in series with the static value.
+ * Also if a node is used and its value is 0, then that means the
+ * input is disconnected from the circuit.
+ *
+ * There are 3 basic types of mixers, defined by the 2 types. The
+ * op amp mixer is further defined by the prescence of rI. This is a
+ * brief explaination.
+ *
+ * DISC_MIXER_IS_RESISTOR
+ * The inputs are high pass filtered if needed, using (rX || rF) * cX.
+ * Then Millman is used for the voltages.
+ * r = (1/rF + 1/r1 + 1/r2...)
+ * i = (v1/r1 + v2/r2...)
+ * v = i * r
+ *
+ * DISC_MIXER_IS_OP_AMP - no rI
+ * This is just a summing circuit.
+ * The inputs are high pass filtered if needed, using rX * cX.
+ * Then a modified Millman is used for the voltages.
+ * i = ((vRef - v1)/r1 + (vRef - v2)/r2...)
+ * v = i * rF
+ *
+ * DISC_MIXER_IS_OP_AMP_WITH_RI
+ * The inputs are high pass filtered if needed, using (rX + rI) * cX.
+ * Then Millman is used for the voltages including vRef/rI.
+ * r = (1/rI + 1/r1 + 1/r2...)
+ * i = (vRef/rI + v1/r1 + v2/r2...)
+ * The voltage is then modified by an inverting amp formula.
+ * v = vRef + (rF/rI) * (vRef - (i * r))
+ */
+#define DST_MIXER__ENABLE (*(node->input[0]))
+#define DST_MIXER__IN(bit) (*(node->input[bit + 1]))
+
+void dst_mixer_step(node_description *node)
+{
+ const discrete_mixer_desc *info = node->custom;
+ struct dst_mixer_context *context = node->context;
+
+ double v, vTemp, rTotal, rTemp, rTemp2 = 0;
+ double i = 0; // total current of inputs
+ int bit, connected;
+
+ if (DST_MIXER__ENABLE)
+ {
+ rTotal = context->rTotal;
+
+ for(bit=0; bit < context->size; bit++)
+ {
+ rTemp = info->r[bit];
+ connected = 1;
+ vTemp = DST_MIXER__IN(bit);
+
+ if (info->rNode[bit])
+ {
+ /* a node has the posibility of being disconnected from the circuit. */
+ if (*context->rNode[bit] == 0)
+ connected = 0;
+ else
+ {
+ rTemp += *context->rNode[bit];
+ rTotal += 1.0 / rTemp;
+ if (info->c[bit] != 0)
+ {
+ switch (context->type & DISC_MIXER_TYPE_MASK)
+ {
+ case DISC_MIXER_IS_RESISTOR:
+ /* is there an rF? */
+ if (info->rF != 0)
+ {
+ rTemp2 = 1.0 / ((1.0 / rTemp) + (1.0 / info->rF));
+ break;
+ }
+ /* else, fall through and just use the resistor value */
+ case DISC_MIXER_IS_OP_AMP:
+ rTemp2 = rTemp;
+ break;
+ case DISC_MIXER_IS_OP_AMP_WITH_RI:
+ rTemp2 = rTemp + info->rI;
+ break;
+ }
+ /* Re-calculate exponent if resistor is a node */
+ context->exponent_rc[bit] = -1.0 / (rTemp2 * info->c[bit] * discrete_current_context->sample_rate);
+ context->exponent_rc[bit] = 1.0 - exp(context->exponent_rc[bit]);
+ }
+ }
+ }
+
+ if (connected)
+ {
+ if (info->c[bit] != 0)
+ {
+ /* do input high pass filtering if needed. */
+ context->vCap[bit] += (vTemp - info->vRef - context->vCap[bit]) * context->exponent_rc[bit];
+ vTemp -= context->vCap[bit];
+ }
+ i += (((context->type & DISC_MIXER_TYPE_MASK) == DISC_MIXER_IS_OP_AMP) ? info->vRef - vTemp : vTemp) / rTemp;
+ }
+ }
+
+ if ((context->type & DISC_MIXER_TYPE_MASK) == DISC_MIXER_IS_OP_AMP_WITH_RI) i += info->vRef / info->rI;
+ rTotal = 1.0 / rTotal;
+
+ /* If resistor network or has rI then Millman is used.
+ * If op-amp then summing formula is used. */
+ v = i * (((context->type & DISC_MIXER_TYPE_MASK) == DISC_MIXER_IS_OP_AMP) ? info->rF : rTotal);
+
+ if ((context->type & DISC_MIXER_TYPE_MASK) == DISC_MIXER_IS_OP_AMP_WITH_RI)
+ v = info->vRef + (context->gain * (info->vRef - v));
+
+ /* Do the low pass filtering for cF */
+ if (info->cF != 0)
+ {
+ if (context->type & DISC_MIXER_HAS_R_NODE)
+ {
+ /* Re-calculate exponent if resistor nodes are used */
+ context->exponent_cF = -1.0 / (rTotal * info->cF * discrete_current_context->sample_rate);
+ context->exponent_cF = 1.0 - exp(context->exponent_cF);
+ }
+ context->vCapF += (v -info->vRef - context->vCapF) * context->exponent_cF;
+ v = context->vCapF;
+ }
+
+ /* Do the high pass filtering for cAmp */
+ if (info->cAmp != 0)
+ {
+ context->vCapAmp += (v - context->vCapAmp) * context->exponent_cAmp;
+ v -= context->vCapAmp;
+ }
+ node->output = v * info->gain;
+ }
+ else
+ {
+ node->output = 0;
+ }
+}
+
+void dst_mixer_reset(node_description *node)
+{
+ const discrete_mixer_desc *info = node->custom;
+ struct dst_mixer_context *context = node->context;
+ node_description *r_node;
+
+ int bit;
+ double rTemp = 0;
+
+ /* link to rNode outputs */
+ for (bit = 0; bit < 8; bit ++)
+ {
+ r_node = discrete_find_node(NULL, info->rNode[bit]);
+ if (r_node)
+ context->rNode[bit] = &(r_node->output);
+ else
+ context->rNode[bit] = NULL;
+ }
+
+ context->size = node->active_inputs - 1;
+
+ /*
+ * THERE IS NO ERROR CHECKING!!!!!!!!!
+ * If you pass a bad ladder table
+ * then you deserve a crash.
+ */
+
+ context->type = ((info->type == DISC_MIXER_IS_OP_AMP) && info->rI) ? DISC_MIXER_IS_OP_AMP_WITH_RI : info->type;
+
+ /*
+ * Calculate the total of all resistors in parallel.
+ * This is the combined resistance of the voltage sources.
+ * Also calculate the exponents while we are here.
+ */
+ context->rTotal = 0;
+ for(bit=0; bit < context->size; bit++)
+ {
+ if (info->rNode[bit])
+ context->type = context->type | DISC_MIXER_HAS_R_NODE;
+
+ if ((info->r[bit] != 0) && !info->rNode[bit] )
+ {
+ context->rTotal += 1.0 / info->r[bit];
+ }
+
+ context->vCap[bit] = 0;
+ context->exponent_rc[bit] = 0;
+ if ((info->c[bit] != 0) && !info->rNode[bit])
+ {
+ switch (context->type)
+ {
+ case DISC_MIXER_IS_RESISTOR:
+ /* is there an rF? */
+ if (info->rF != 0)
+ {
+ rTemp = 1.0 / ((1.0 / info->r[bit]) + (1.0 / info->rF));
+ break;
+ }
+ /* else, fall through and just use the resistor value */
+ case DISC_MIXER_IS_OP_AMP:
+ rTemp = info->r[bit];
+ break;
+ case DISC_MIXER_IS_OP_AMP_WITH_RI:
+ rTemp = info->r[bit] + info->rI;
+ break;
+ }
+ /* Setup filter constants */
+ context->exponent_rc[bit] = -1.0 / (rTemp * info->c[bit] * discrete_current_context->sample_rate);
+ context->exponent_rc[bit] = 1.0 - exp(context->exponent_rc[bit]);
+ }
+ }
+
+ if (info->rF != 0)
+ {
+ if (info->type == DISC_MIXER_IS_RESISTOR) context->rTotal += 1.0 / info->rF;
+ }
+ if (context->type == DISC_MIXER_IS_OP_AMP_WITH_RI) context->rTotal += 1.0 / info->rI;
+
+ context->vCapF = 0;
+ context->exponent_cF = 0;
+ if (info->cF != 0)
+ {
+ /* Setup filter constants */
+ context->exponent_cF = -1.0 / (((info->type == DISC_MIXER_IS_OP_AMP) ? info->rF : (1.0 / context->rTotal))* info->cF * discrete_current_context->sample_rate);
+ context->exponent_cF = 1.0 - exp(context->exponent_cF);
+ }
+
+ context->vCapAmp = 0;
+ context->exponent_cAmp = 0;
+ if (info->cAmp != 0)
+ {
+ /* Setup filter constants */
+ /* We will use 100000 ohms as an average final stage impedance. */
+ /* Your amp/speaker system will have more effect on incorrect filtering then any value used here. */
+ context->exponent_cAmp = -1.0 / (100000 * info->cAmp * discrete_current_context->sample_rate);
+ context->exponent_cAmp = 1.0 - exp(context->exponent_cAmp);
+ }
+
+ if ((context->type & DISC_MIXER_TYPE_MASK) == DISC_MIXER_IS_OP_AMP_WITH_RI) context->gain = info->rF / info->rI;
+
+ node->output = 0;
+}
+
+
+/************************************************************************
+ *
+ * DST_MULTIPLEX - 1 of x multiplexer/switch
+ *
+ * input[0] - Enable input value
+ * input[1] - switch position
+ * input[2] - input[0]
+ * input[3] - input[1]
+ * .....
+ *
+ * Dec 2004, D Renaud.
+ ************************************************************************/
+#define DST_MULTIPLEX__ENABLE (*(node->input[0]))
+#define DST_MULTIPLEX__ADDR (*(node->input[1]))
+#define DST_MULTIPLEX__INP(addr) (*(node->input[2 + addr]))
+
+void dst_multiplex_step(node_description *node)
+{
+ struct dst_size_context *context = node->context;
+ int addr;
+
+ if(DST_MULTIPLEX__ENABLE)
+ {
+ addr = DST_MULTIPLEX__ADDR; // FP to INT
+ if ((addr >= 0) && (addr < context->size))
+ {
+ node->output = DST_MULTIPLEX__INP(addr);
+ }
+ else
+ {
+ /* Bad address. We will leave the output alone. */
+ discrete_log("NODE_%02d - Address = %d. Out of bounds\n",node->node-NODE_00, addr);
+ }
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+void dst_multiplex_reset(node_description *node)
+{
+ struct dst_size_context *context = node->context;
+
+ context->size = node->active_inputs - 2;
+
+ dst_multiplex_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DST_ONESHOT - Usage of node_description values for one shot pulse
+ *
+ * input[0] - Reset value
+ * input[1] - Trigger value
+ * input[2] - Amplitude value
+ * input[3] - Width of oneshot pulse
+ * input[4] - type R/F edge, Retriggerable?
+ *
+ * Complete re-write Jan 2004, D Renaud.
+ ************************************************************************/
+#define DST_ONESHOT__RESET (*(node->input[0]))
+#define DST_ONESHOT__TRIG (*(node->input[1]))
+#define DST_ONESHOT__AMP (*(node->input[2]))
+#define DST_ONESHOT__WIDTH (*(node->input[3]))
+#define DST_ONESHOT__TYPE (int)(*(node->input[4]))
+
+void dst_oneshot_step(node_description *node)
+{
+ struct dst_oneshot_context *context = node->context;
+ int trigger = (DST_ONESHOT__TRIG != 0);
+
+ /* If the state is triggered we will need to countdown later */
+ int doCount = context->state;
+
+ if (DST_ONESHOT__RESET)
+ {
+ /* Hold in Reset */
+ node->output = 0;
+ context->state = 0;
+ }
+ else
+ {
+ /* are we at an edge? */
+ if (trigger != context->lastTrig)
+ {
+ /* There has been a trigger edge */
+ context->lastTrig = trigger;
+
+ /* Is it the proper edge trigger */
+ if ((DST_ONESHOT__TYPE & DISC_ONESHOT_REDGE) ? trigger : !trigger)
+ {
+ if (!context->state)
+ {
+ /* We have first trigger */
+ context->state = 1;
+ node->output = (DST_ONESHOT__TYPE & DISC_OUT_ACTIVE_LOW) ? 0 : DST_ONESHOT__AMP;
+ context->countdown = DST_ONESHOT__WIDTH;
+ }
+ else
+ {
+ /* See if we retrigger */
+ if (DST_ONESHOT__TYPE & DISC_ONESHOT_RETRIG)
+ {
+ /* Retrigger */
+ context->countdown = DST_ONESHOT__WIDTH;
+ doCount = 0;
+ }
+ }
+ }
+ }
+
+ if (doCount)
+ {
+ context->countdown -= discrete_current_context->sample_time;
+ if(context->countdown <= 0.0)
+ {
+ node->output = (DST_ONESHOT__TYPE & DISC_OUT_ACTIVE_LOW) ? DST_ONESHOT__AMP : 0;
+ context->countdown = 0;
+ context->state = 0;
+ }
+ }
+ }
+}
+
+
+void dst_oneshot_reset(node_description *node)
+{
+ struct dst_oneshot_context *context = node->context;
+ context->countdown = 0;
+ context->state = 0;
+
+ context->lastTrig = 0;
+ node->output = (DST_ONESHOT__TYPE & DISC_OUT_ACTIVE_LOW) ? DST_ONESHOT__AMP : 0;
+}
+
+
+/************************************************************************
+ *
+ * DST_RAMP - Ramp up/down model usage
+ *
+ * input[0] - Enable ramp
+ * input[1] - Ramp Reverse/Forward switch
+ * input[2] - Gradient, change/sec
+ * input[3] - Start value
+ * input[4] - End value
+ * input[5] - Clamp value when disabled
+ *
+ ************************************************************************/
+#define DST_RAMP__ENABLE (*(node->input[0]))
+#define DST_RAMP__DIR (*(node->input[1]))
+#define DST_RAMP__GRAD (*(node->input[2]))
+#define DST_RAMP__START (*(node->input[3]))
+#define DST_RAMP__END (*(node->input[4]))
+#define DST_RAMP__CLAMP (*(node->input[5]))
+
+void dst_ramp_step(node_description *node)
+{
+ struct dss_ramp_context *context = node->context;
+
+ if(DST_RAMP__ENABLE)
+ {
+ if (!context->last_en)
+ {
+ context->last_en = 1;
+ node->output = DST_RAMP__START;
+ }
+ if(context->dir ? DST_RAMP__DIR : !DST_RAMP__DIR) node->output+=context->step;
+ else node->output-=context->step;
+ /* Clamp to min/max */
+ if(context->dir ? (node->output < DST_RAMP__START)
+ : (node->output > DST_RAMP__START)) node->output=DST_RAMP__START;
+ if(context->dir ? (node->output > DST_RAMP__END)
+ : (node->output < DST_RAMP__END)) node->output=DST_RAMP__END;
+ }
+ else
+ {
+ context->last_en = 0;
+ // Disabled so clamp to output
+ node->output=DST_RAMP__CLAMP;
+ }
+}
+
+void dst_ramp_reset(node_description *node)
+{
+ struct dss_ramp_context *context = node->context;
+
+ node->output=DST_RAMP__CLAMP;
+ context->step = DST_RAMP__GRAD / discrete_current_context->sample_rate;
+ context->dir = ((DST_RAMP__END - DST_RAMP__START) == abs(DST_RAMP__END - DST_RAMP__START));
+ context->last_en = 0;
+}
+
+
+/************************************************************************
+ *
+ * DST_SAMPHOLD - Sample & Hold Implementation
+ *
+ * input[0] - Enable
+ * input[1] - input[0] value
+ * input[2] - clock node
+ * input[3] - clock type
+ *
+ ************************************************************************/
+#define DST_SAMPHOLD__ENABLE (*(node->input[0]))
+#define DST_SAMPHOLD__IN0 (*(node->input[1]))
+#define DST_SAMPHOLD__CLOCK (*(node->input[2]))
+#define DST_SAMPHOLD__TYPE (*(node->input[3]))
+
+void dst_samphold_step(node_description *node)
+{
+ struct dst_samphold_context *context = node->context;
+
+ if(DST_SAMPHOLD__ENABLE)
+ {
+ switch(context->clocktype)
+ {
+ case DISC_SAMPHOLD_REDGE:
+ /* Clock the whole time the input is rising */
+ if(DST_SAMPHOLD__CLOCK > context->lastinput) node->output=DST_SAMPHOLD__IN0;
+ break;
+ case DISC_SAMPHOLD_FEDGE:
+ /* Clock the whole time the input is falling */
+ if(DST_SAMPHOLD__CLOCK < context->lastinput) node->output=DST_SAMPHOLD__IN0;
+ break;
+ case DISC_SAMPHOLD_HLATCH:
+ /* Output follows input if clock != 0 */
+ if(DST_SAMPHOLD__CLOCK) node->output=DST_SAMPHOLD__IN0;
+ break;
+ case DISC_SAMPHOLD_LLATCH:
+ /* Output follows input if clock == 0 */
+ if(DST_SAMPHOLD__CLOCK==0) node->output=DST_SAMPHOLD__IN0;
+ break;
+ default:
+ discrete_log("dst_samphold_step - Invalid clocktype passed");
+ break;
+ }
+ }
+ else
+ {
+ node->output=0;
+ }
+ /* Save the last value */
+ context->lastinput=DST_SAMPHOLD__CLOCK;
+}
+
+void dst_samphold_reset(node_description *node)
+{
+ struct dst_samphold_context *context = node->context;
+
+ node->output=0;
+ context->lastinput=-1;
+ /* Only stored in here to speed up and save casting in the step function */
+ context->clocktype=(int)DST_SAMPHOLD__TYPE;
+ dst_samphold_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSS_SWITCH - Programmable 2 pole switch module with enable function
+ *
+ * input[0] - Enable input value
+ * input[1] - switch position
+ * input[2] - input[0]
+ * input[3] - input[1]
+ *
+ ************************************************************************/
+#define DSS_SWITCH__ENABLE (*(node->input[0]))
+#define DSS_SWITCH__SWITCH (*(node->input[1]))
+#define DSS_SWITCH__IN0 (*(node->input[2]))
+#define DSS_SWITCH__IN1 (*(node->input[3]))
+
+void dst_switch_step(node_description *node)
+{
+ if(DSS_SWITCH__ENABLE)
+ {
+ node->output=DSS_SWITCH__SWITCH ? DSS_SWITCH__IN1 : DSS_SWITCH__IN0;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+/************************************************************************
+ *
+ * DSS_ASWITCH - Analog switch
+ *
+ * input[0] - Enable input value
+ * input[1] - Control
+ * input[2] - Input
+ * input[3] - Threshold for enable
+ *
+ ************************************************************************/
+#define DSS_ASWITCH__ENABLE (*(node->input[0]))
+#define DSS_ASWITCH__CTRL (*(node->input[1]))
+#define DSS_ASWITCH__IN (*(node->input[2]))
+#define DSS_ASWITCH__THRESHOLD (*(node->input[3]))
+
+
+void dst_aswitch_step(node_description *node)
+{
+ if(DSS_SWITCH__ENABLE)
+ {
+ node->output=DSS_ASWITCH__CTRL > DSS_ASWITCH__THRESHOLD ? DSS_ASWITCH__IN : 0;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+/************************************************************************
+ *
+ * DST_TRANSFORM - Programmable math module with enable function
+ *
+ * input[0] - Enable input value
+ * input[1] - Channel0 input value
+ * input[2] - Channel1 input value
+ * input[3] - Channel2 input value
+ * input[4] - Channel3 input value
+ * input[5] - Channel4 input value
+ *
+ ************************************************************************/
+#define DST_TRANSFORM__ENABLE (*(node->input[0]))
+#define DST_TRANSFORM__IN0 (*(node->input[1]))
+#define DST_TRANSFORM__IN1 (*(node->input[2]))
+#define DST_TRANSFORM__IN2 (*(node->input[3]))
+#define DST_TRANSFORM__IN3 (*(node->input[4]))
+#define DST_TRANSFORM__IN4 (*(node->input[5]))
+
+#define MAX_TRANS_STACK 16
+
+double dst_transform_pop(double *stack,int *pointer)
+{
+ double value;
+ //decrement THEN read
+ if(*pointer>0) (*pointer)--;
+ value=stack[*pointer];
+ return value;
+}
+
+double dst_transform_push(double *stack,int *pointer,double value)
+{
+ //Store THEN increment
+ if(*pointer<MAX_TRANS_STACK) stack[(*pointer)++]=value;
+ return value;
+}
+
+void dst_transform_step(node_description *node)
+{
+ if(DST_TRANSFORM__ENABLE)
+ {
+ double trans_stack[MAX_TRANS_STACK];
+ double result,number1,number2;
+ int trans_stack_ptr=0;
+
+ const char *fPTR = node->custom;
+ node->output=0;
+
+ while(*fPTR!=0)
+ {
+ switch (*fPTR++)
+ {
+ case '*':
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=number1*number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '/':
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=number1/number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '+':
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=number1+number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '-':
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=number1-number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '0':
+ dst_transform_push(trans_stack,&trans_stack_ptr,DST_TRANSFORM__IN0);
+ break;
+ case '1':
+ dst_transform_push(trans_stack,&trans_stack_ptr,DST_TRANSFORM__IN1);
+ break;
+ case '2':
+ dst_transform_push(trans_stack,&trans_stack_ptr,DST_TRANSFORM__IN2);
+ break;
+ case '3':
+ dst_transform_push(trans_stack,&trans_stack_ptr,DST_TRANSFORM__IN3);
+ break;
+ case '4':
+ dst_transform_push(trans_stack,&trans_stack_ptr,DST_TRANSFORM__IN4);
+ break;
+ case 'P':
+ result=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case 'i': // * -1
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=-number1;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '!': // Logical NOT of Last Value
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=!number1;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '=': // Logical =
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=(int)number1 == (int)number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '>': // Logical >
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=number1 > number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '<': // Logical <
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=number1 < number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '&': // Bitwise AND
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=(int)number1 & (int)number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '|': // Bitwise OR
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=(int)number1 | (int)number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ case '^': // Bitwise XOR
+ number2=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ number1=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ result=(int)number1 ^ (int)number2;
+ dst_transform_push(trans_stack,&trans_stack_ptr,result);
+ break;
+ default:
+ discrete_log("dst_transform_step - Invalid function type/variable passed");
+ node->output = 0;
+ break;
+ }
+ }
+ node->output=dst_transform_pop(trans_stack,&trans_stack_ptr);
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+
+/************************************************************************
+ *
+ * DST_OP_AMP - op amp circuits
+ *
+ * input[0] - Enable
+ * input[1] - Input 0
+ * input[2] - Input 1
+ *
+ * also passed discrete_op_amp_info structure
+ *
+ * Mar 2007, D Renaud.
+ ************************************************************************/
+#define DST_OP_AMP__ENABLE (*(node->input[0]))
+#define DST_OP_AMP__INP0 (*(node->input[1]))
+#define DST_OP_AMP__INP1 (*(node->input[2]))
+
+void dst_op_amp_step(node_description *node)
+{
+ const discrete_op_amp_info *info = node->custom;
+ struct dst_op_amp_context *context = node->context;
+
+ double iPos = 0;
+ double iNeg = 0;
+ double i = 0;
+
+ if (DST_OP_AMP__ENABLE)
+ {
+ switch (info->type)
+ {
+ case DISC_OP_AMP_IS_NORTON:
+ /* work out neg pin current */
+ if (context->has_r1)
+ {
+ iNeg = (DST_OP_AMP__INP0 - OP_AMP_NORTON_VBE) / info->r1;
+ if (iNeg < 0) iNeg = 0;
+ }
+ iNeg += context->iFixed;
+
+ /* work out neg pin current */
+ iPos = (DST_OP_AMP__INP1 - OP_AMP_NORTON_VBE) / info->r2;
+ if (iPos < 0) iPos = 0;
+
+ /* work out current across r4 */
+ i = iPos - iNeg;
+
+ if (context->has_cap)
+ {
+ if (context->has_r4)
+ {
+ /* voltage across r4 charging cap */
+ i *= info->r4;
+ /* exponential charge */
+ context->vCap += (i - context->vCap) * context->exponent;
+ }
+ else
+ /* linear charge */
+ context->vCap += i / context->exponent;
+ node->output = context->vCap;
+ }
+ else
+ node->output = i * info->r4;
+
+ /* clamp output */
+ if (node->output > context->vMax) node->output = context->vMax;
+ else if (node->output < info->vN) node->output = info->vN;
+ context->vCap = node->output;
+ break;
+
+ default:
+ node->output = 0;
+ }
+ }
+ else
+ node->output = 0;
+}
+
+void dst_op_amp_reset(node_description *node)
+{
+ const discrete_op_amp_info *info = node->custom;
+ struct dst_op_amp_context *context = node->context;
+
+ context->has_r1 = info->r1 > 0;
+ context->has_r4 = info->r4 > 0;
+
+ context->vMax = info->vP - OP_AMP_NORTON_VBE;
+
+ context->vCap = 0;
+ if (info->c > 0)
+ {
+ context->has_cap = 1;
+ /* Setup filter constants */
+ if (context->has_r4)
+ {
+ /* exponential charge */
+ context->exponent = -1.0 / (info->r4 * info->c * discrete_current_context->sample_rate);
+ context->exponent = 1.0 - exp(context->exponent);
+ }
+ else
+ /* linear charge */
+ context->exponent = discrete_current_context->sample_rate * info->c;
+ }
+
+ if (info->r3 >= 0)
+ context->iFixed = (info->vP - OP_AMP_NORTON_VBE) / info->r3;
+}
+
+
+/************************************************************************
+ *
+ * DST_OP_AMP_1SHT - op amp one shot circuits
+ *
+ * input[0] - Trigger
+ *
+ * also passed discrete_op_amp_1sht_info structure
+ *
+ * Mar 2007, D Renaud.
+ ************************************************************************/
+#define DST_OP_AMP_1SHT__TRIGGER (*(node->input[0]))
+
+void dst_op_amp_1sht_step(node_description *node)
+{
+ const discrete_op_amp_1sht_info *info = node->custom;
+ struct dst_op_amp_1sht_context *context = node->context;
+
+ double iPos;
+ double iNeg;
+ double v;
+
+ /* update trigger circuit */
+ iPos = (DST_OP_AMP_1SHT__TRIGGER - context->vCap2) / info->r2;
+ iPos += node->output / info->r5;
+ context->vCap2 += (DST_OP_AMP_1SHT__TRIGGER - context->vCap2) * context->exponent2;
+
+ /* calculate currents and output */
+ iNeg = (context->vCap1 - OP_AMP_NORTON_VBE) / info->r3;
+ if (iNeg < 0) iNeg = 0;
+ iNeg += context->iFixed;
+
+ if (iPos > iNeg) node->output = context->vMax;
+ else node->output = info->vN;
+
+ /* update c1 */
+ /* rough value of voltage at anode of diode if discharging */
+ v = node->output + 0.6;
+ if (context->vCap1 > node->output)
+ {
+ /* discharge */
+ if (context->vCap1 > v)
+ /* immediate discharge through diode */
+ context->vCap1 = v;
+ else
+ /* discharge through r4 */
+ context->vCap1 += (node->output - context->vCap1) * context->exponent1d;
+ }
+ else
+ /* charge */
+ context->vCap1 += ((node->output - OP_AMP_NORTON_VBE) * context->r34ratio + OP_AMP_NORTON_VBE - context->vCap1) * context->exponent1c;
+}
+
+void dst_op_amp_1sht_reset(node_description *node)
+{
+ const discrete_op_amp_1sht_info *info = node->custom;
+ struct dst_op_amp_1sht_context *context = node->context;
+
+ context->exponent1c = -1.0 / ((1.0 / (1.0 / info->r3 + 1.0 / info->r4)) * info->c1 * discrete_current_context->sample_rate);
+ context->exponent1c = 1.0 - exp(context->exponent1c);
+ context->exponent1d = -1.0 / (info->r4 * info->c1 * discrete_current_context->sample_rate);
+ context->exponent1d = 1.0 - exp(context->exponent1d);
+ context->exponent2 = -1.0 / (info->r2 * info->c2 * discrete_current_context->sample_rate);
+ context->exponent2 = 1.0 - exp(context->exponent2);
+ context->iFixed = (info->vP - OP_AMP_NORTON_VBE) / info->r1;
+ context->vCap1 = context->vCap2 = 0;
+ context->vMax = info->vP - OP_AMP_NORTON_VBE;
+ context->r34ratio = info->r3 / (info->r3 + info->r4);
+}
+
+
+/************************************************************************
+ *
+ * DST_TVCA_OP_AMP - trigged op-amp VCA
+ *
+ * input[0] - Trigger 0
+ * input[1] - Trigger 1
+ * input[2] - Trigger 2
+ * input[3] - Input 0
+ * input[4] - Input 1
+ *
+ * also passed discrete_op_amp_tvca_info structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DST_TVCA_OP_AMP__TRG0 (*(node->input[0]))
+#define DST_TVCA_OP_AMP__TRG1 (*(node->input[1]))
+#define DST_TVCA_OP_AMP__TRG2 (*(node->input[2]))
+#define DST_TVCA_OP_AMP__INP0 (*(node->input[3]))
+#define DST_TVCA_OP_AMP__INP1 (*(node->input[4]))
+
+void dst_tvca_op_amp_step(node_description *node)
+{
+ const discrete_op_amp_tvca_info *info = node->custom;
+ struct dst_tvca_op_amp_context *context = node->context;
+
+ int trig0, trig1, trig2, f3;
+ double i2 = 0; // current through r2
+ double i3 = 0; // current through r3
+ double iNeg = 0; // current into - input
+ double iPos = 0; // current into + input
+ double iOut = 0; // current at output
+
+ trig0 = (int)DST_TVCA_OP_AMP__TRG0;
+ trig1 = (int)DST_TVCA_OP_AMP__TRG1;
+ trig2 = (int)DST_TVCA_OP_AMP__TRG2;
+ f3 = dst_trigger_function(trig0, trig1, trig2, info->f3);
+
+ if ((info->r2 != 0) && dst_trigger_function(trig0, trig1, trig2, info->f0))
+ {
+ /* r2 is present, so we assume Input 0 is connected and valid. */
+ i2 = (DST_TVCA_OP_AMP__INP0 - OP_AMP_NORTON_VBE) / info->r2;
+ if ( i2 < 0) i2 = 0;
+ }
+
+ if ((info->r3 != 0) && dst_trigger_function(trig0, trig1, trig2, info->f1))
+ {
+ /* r2 is present, so we assume Input 1 is connected and valid. */
+ /* Function F1 is not grounding the circuit. */
+ i3 = (DST_TVCA_OP_AMP__INP1 - OP_AMP_NORTON_VBE) / info->r3;
+ if ( i3 < 0) i3 = 0;
+ }
+
+ /* Calculate current going in to - input. */
+ iNeg = context->iFixed + i2 + i3;
+
+ /* Update the c1 cap voltage. */
+ if (dst_trigger_function(trig0, trig1, trig2, info->f2))
+ {
+ /* F2 is not grounding the circuit so we charge the cap. */
+ context->vCap1 += (context->vTrig[f3] - context->vCap1) * context->exponentC[f3];
+ }
+ else
+ {
+ /* F2 is at ground. The diode blocks this so F2 and r5 are out of circuit.
+ * So now the discharge rate is dependent upon F3.
+ * If F3 is at ground then we discharge to 0V through r6.
+ * If F3 is out of circuit then we discharge to OP_AMP_NORTON_VBE through r6+r7. */
+ context->vCap1 += ((f3 ? OP_AMP_NORTON_VBE : 0.0) - context->vCap1) * context->exponentD[f3];
+ }
+
+ /* Calculate c1 current going in to + input. */
+ iPos = (context->vCap1 - OP_AMP_NORTON_VBE) / context->r67;
+ if ((iPos < 0) || !f3) iPos = 0;
+
+ /* Update the c2 cap voltage and current. */
+ if (info->r9 != 0)
+ {
+ f3 = dst_trigger_function(trig0, trig1, trig2, info->f4);
+ context->vCap2 += ((f3 ? context->vTrig2 : 0) - context->vCap2) * context->exponent2[f3];
+ iPos += context->vCap2 / info->r9;
+ }
+
+ /* Update the c3 cap voltage and current. */
+ if (info->r11 != 0)
+ {
+ f3 = dst_trigger_function(trig0, trig1, trig2, info->f5);
+ context->vCap3 += ((f3 ? context->vTrig3 : 0) - context->vCap3) * context->exponent3[f3];
+ iPos += context->vCap3 / info->r11;
+ }
+
+
+ /* Calculate output current. */
+ iOut = iPos - iNeg;
+ if (iOut < 0) iOut = 0;
+ /* Convert to voltage for final output. */
+ node->output = iOut * info->r4;
+ /* Clip the output if needed. */
+ if (node->output > context->vOutMax) node->output = context->vOutMax;
+}
+
+void dst_tvca_op_amp_reset(node_description *node)
+{
+ const discrete_op_amp_tvca_info *info = node->custom;
+ struct dst_tvca_op_amp_context *context = node->context;
+
+ context->r67 = info->r6 + info->r7;
+
+ context->vOutMax = info->vP - OP_AMP_NORTON_VBE;
+ /* This is probably overkill because R5 is usually much lower then r6 or r7,
+ * but it is better to play it safe. */
+ context->vTrig[0] = (info->v1 - 0.6) * (info->r6 / (info->r6 + info->r5));
+ context->vTrig[1] = (info->v1 - 0.6 - OP_AMP_NORTON_VBE) * (context->r67 / (context->r67 + info->r5)) + OP_AMP_NORTON_VBE;
+ context->iFixed = context->vOutMax / info->r1;
+
+ context->vCap1 = 0;
+ /* Charge rate thru r5 */
+ /* There can be a different charge rates depending on function F3. */
+ context->exponentC[0] = -1.0 / ((1.0 / (1.0 / info->r5 + 1.0 / info->r6)) * info->c1 * discrete_current_context->sample_rate);
+ context->exponentC[0] = 1.0 - exp(context->exponentC[0]);
+ context->exponentC[1] = -1.0 / ((1.0 / (1.0 / info->r5 + 1.0 / context->r67)) * info->c1 * discrete_current_context->sample_rate);
+ context->exponentC[1] = 1.0 - exp(context->exponentC[1]);
+ /* Discharge rate thru r6 + r7 */
+ context->exponentD[1] = -1.0 / (context->r67 * info->c1 * discrete_current_context->sample_rate);
+ context->exponentD[1] = 1.0 - exp(context->exponentD[1]);
+ /* Discharge rate thru r6 */
+ if (info->r6 != 0)
+ {
+ context->exponentD[0] = -1.0 / (info->r6 * info->c1 * discrete_current_context->sample_rate);
+ context->exponentD[0] = 1.0 - exp(context->exponentD[0]);
+ }
+ context->vCap2 = 0;
+ context->vTrig2 = (info->v2 - 0.6 - OP_AMP_NORTON_VBE) * (info->r9 / (info->r8 + info->r9));
+ context->exponent2[0] = -1.0 / (info->r9 * info->c2 * discrete_current_context->sample_rate);
+ context->exponent2[0] = 1.0 - exp(context->exponent2[0]);
+ context->exponent2[1] = -1.0 / ((1.0 / (1.0 / info->r8 + 1.0 / info->r9)) * info->c2 * discrete_current_context->sample_rate);
+ context->exponent2[1] = 1.0 - exp(context->exponent2[1]);
+ context->vCap3 = 0;
+ context->vTrig3 = (info->v3 - 0.6 - OP_AMP_NORTON_VBE) * (info->r11 / (info->r10 + info->r11));
+ context->exponent3[0] = -1.0 / (info->r11 * info->c3 * discrete_current_context->sample_rate);
+ context->exponent3[0] = 1.0 - exp(context->exponent3[0]);
+ context->exponent3[1] = -1.0 / ((1.0 / (1.0 / info->r10 + 1.0 / info->r11)) * info->c3 * discrete_current_context->sample_rate);
+ context->exponent3[1] = 1.0 - exp(context->exponent3[1]);
+
+ dst_tvca_op_amp_step(node);
+}
diff --git a/src/emu/sound/disc_wav.c b/src/emu/sound/disc_wav.c
new file mode 100644
index 00000000000..d397511628f
--- /dev/null
+++ b/src/emu/sound/disc_wav.c
@@ -0,0 +1,1707 @@
+/************************************************************************
+ *
+ * MAME - Discrete sound system emulation library
+ *
+ * Written by Keith Wilkins (mame@esplexo.co.uk)
+ *
+ * (c) K.Wilkins 2000
+ *
+ ************************************************************************
+ *
+ * DSS_COUNTER - External clock Binary Counter
+ * DSS_LFSR_NOISE - Linear Feedback Shift Register Noise
+ * DSS_NOISE - Noise Source - Random source
+ * DSS_NOTE - Note/tone generator
+ * DSS_OP_AMP_OSC - Op Amp oscillator circuits
+ * DSS_SAWTOOTHWAVE - Sawtooth waveform generator
+ * DSS_SCHMITT_OSC - Schmitt Feedback Oscillator
+ * DSS_SINEWAVE - Sinewave generator source code
+ * DSS_SQUAREWAVE - Squarewave generator source code
+ * DSS_SQUAREWFIX - Squarewave generator - fixed frequency
+ * DSS_SQUAREWAVE2 - Squarewave generator - by tOn/tOff
+ * DSS_TRIANGLEWAVE - Triangle waveform generator
+ *
+ ************************************************************************/
+
+struct dss_adsr_context
+{
+ double phase;
+};
+
+struct dss_counter_context
+{
+ int clock_type;
+ int out_type;
+ int is_7492;
+ int last; // Last clock state
+ int count; // current count
+ double t_clock; // fixed counter clock in seconds
+ double t_left; // time unused during last sample in seconds
+};
+
+struct dss_lfsr_context
+{
+ unsigned int lfsr_reg;
+ int last; // Last clock state
+ double t_clock; // fixed counter clock in seconds
+ double t_left; // time unused during last sample in seconds
+ double sampleStep;
+ double shiftStep;
+ double t;
+ UINT8 reset_on_high;
+ UINT8 invert_output;
+ UINT8 out_is_f0;
+};
+
+struct dss_noise_context
+{
+ double phase;
+};
+
+struct dss_note_context
+{
+ int clock_type;
+ int out_type;
+ int last; // Last clock state
+ double t_clock; // fixed counter clock in seconds
+ double t_left; // time unused during last sample in seconds
+ int max1; // Max 1 Count stored as int for easy use.
+ int max2; // Max 2 Count stored as int for easy use.
+ int count1; // current count1
+ int count2; // current count2
+};
+
+struct dss_op_amp_osc_context
+{
+ const double *r1; // pointers to resistor values
+ const double *r2;
+ const double *r3;
+ const double *r4;
+ const double *r5;
+ const double *r6;
+ const double *r7;
+ const double *r8;
+ int type;
+ UINT8 flip_flop; // flip/flop output state
+ UINT8 flip_flopXOR; // flip_flop ^ flip_flopXOR, 0 = discharge, 1 = charge
+ UINT8 is_squarewave;
+ double high_out_V;
+ double thresholdLow; // falling threshold
+ double thresholdHigh; // rising threshold
+ double vCap; // current capacitor voltage
+ double rTotal; // all input resistors in parallel
+ double iFixed; // fixed current at the input
+ double temp1; // Multi purpose
+ double temp2; // Multi purpose
+ double temp3; // Multi purpose
+};
+
+struct dss_sawtoothwave_context
+{
+ double phase;
+ int type;
+};
+
+struct dss_schmitt_osc_context
+{
+ double ratioIn; // ratio of total charging voltage that comes from the input
+ double ratioFeedback; // ratio of total charging voltage that comes from the feedback
+ double vCap; // current capacitor voltage
+ double rc; // r*c
+ double exponent;
+ int state; // state of the output
+ int enable_type;
+ UINT8 input_is_voltage;
+};
+
+struct dss_sinewave_context
+{
+ double phase;
+};
+
+struct dss_squarewave_context
+{
+ double phase;
+ double trigger;
+};
+
+struct dss_squarewfix_context
+{
+ int flip_flop;
+ double sampleStep;
+ double tLeft;
+ double tOff;
+ double tOn;
+};
+
+struct dss_trianglewave_context
+{
+ double phase;
+};
+
+struct dss_inverter_osc_context
+{
+ double w;
+ double wc;
+ double vCap;
+ double vG2_old;
+ double Rp;
+ double R1;
+ double R2;
+ double C;
+ double tf_a;
+ double tf_b;
+};
+
+/************************************************************************
+ *
+ * DSS_COUNTER - External clock Binary Counter
+ *
+ * input0 - Enable input value
+ * input1 - Reset input (active high)
+ * input2 - Clock Input
+ * input3 - Max count
+ * input4 - Direction - 0=down, 1=up
+ * input5 - Reset Value
+ * input6 - Clock type
+ *
+ * Jan 2004, D Renaud.
+ ************************************************************************/
+#define DSS_COUNTER__ENABLE (*(node->input[0]))
+#define DSS_COUNTER__RESET (*(node->input[1]))
+#define DSS_COUNTER__CLOCK (*(node->input[2]))
+#define DSS_COUNTER__MAX (*(node->input[3]))
+#define DSS_COUNTER__DIR (*(node->input[4]))
+#define DSS_COUNTER__INIT (*(node->input[5]))
+#define DSS_COUNTER__CLOCK_TYPE (*(node->input[6]))
+
+static const int disc_7492_count[6] = {0x00, 0x01, 0x02, 0x04, 0x05, 0x06};
+
+void dss_counter_step(node_description *node)
+{
+ struct dss_counter_context *context = node->context;
+ double cycles;
+ int clock = 0, last_count, inc = 0;
+ int max = DSS_COUNTER__MAX;
+ double xTime = 0;
+
+ if (context->clock_type == DISC_CLK_IS_FREQ)
+ {
+ /* We need to keep clocking the internal clock even if disabled. */
+ cycles = (context->t_left + discrete_current_context->sample_time) / context->t_clock;
+ inc = (int)cycles;
+ context->t_left = (cycles - inc) * context->t_clock;
+ if (inc) xTime = context->t_left / discrete_current_context->sample_time;
+ }
+ else
+ {
+ clock = (int)DSS_COUNTER__CLOCK;
+ xTime = DSS_COUNTER__CLOCK - clock;
+ }
+
+
+ /* If reset enabled then set output to the reset value. No xTime in reset. */
+ if (DSS_COUNTER__RESET)
+ {
+ context->count = DSS_COUNTER__INIT;
+ node->output = context->is_7492 ? 0 : context->count;
+ return;
+ }
+
+ /*
+ * Only count if module is enabled.
+ * This has the effect of holding the output at it's current value.
+ */
+ if (DSS_COUNTER__ENABLE)
+ {
+ last_count = context->count;
+
+ switch (context->clock_type)
+ {
+ case DISC_CLK_ON_F_EDGE:
+ case DISC_CLK_ON_R_EDGE:
+ /* See if the clock has toggled to the proper edge */
+ clock = (clock != 0);
+ if (context->last != clock)
+ {
+ context->last = clock;
+ if (context->clock_type == clock)
+ {
+ /* Toggled */
+ inc = 1;
+ }
+ }
+ break;
+
+ case DISC_CLK_BY_COUNT:
+ /* Clock number of times specified. */
+ inc = clock;
+ break;
+ }
+
+ for (clock = 0; clock < inc; clock++)
+ {
+ context->count += DSS_COUNTER__DIR ? 1 : -1; // up/down
+ if (context->count < 0) context->count = max;
+ if (context->count > max) context->count = 0;
+ }
+
+ node->output = context->is_7492 ? disc_7492_count[context->count] : context->count;
+
+ if (context->count != last_count)
+ {
+ /* the xTime is only output if the output changed. */
+ switch (context->out_type)
+ {
+ case DISC_OUT_IS_ENERGY:
+ if (xTime != 0)
+ node->output = (context->count > last_count) ? (last_count + xTime) : (last_count - xTime);
+ break;
+ case DISC_OUT_HAS_XTIME:
+ node->output += xTime;
+ break;
+ }
+ }
+ }
+ else
+ node->output = context->count;
+}
+
+void dss_counter_reset(node_description *node)
+{
+ struct dss_counter_context *context = node->context;
+
+ context->clock_type = (int)DSS_COUNTER__CLOCK_TYPE;
+ if (context->clock_type == DISC_COUNTER_IS_7492)
+ {
+ context->clock_type = DISC_CLK_ON_F_EDGE;
+ context->is_7492 = 1;
+ }
+ else
+ context->is_7492 = 0;
+ if ((context->clock_type < DISC_CLK_ON_F_EDGE) || (context->clock_type > DISC_CLK_IS_FREQ))
+ discrete_log("Invalid clock type passed in NODE_%d\n", node->node - NODE_START);
+ context->last = 0;
+ if (context->clock_type == DISC_CLK_IS_FREQ) context->t_clock = 1.0 / DSS_COUNTER__CLOCK;
+ context->t_left = 0;
+ context->count = DSS_COUNTER__INIT; /* count starts at reset value */
+ node->output = DSS_COUNTER__INIT;
+}
+
+
+/************************************************************************
+ *
+ * DSS_LFSR_NOISE - Usage of node_description values for LFSR noise gen
+ *
+ * input0 - Enable input value
+ * input1 - Register reset
+ * input2 - Clock Input
+ * input3 - Amplitude input value
+ * input4 - Input feed bit
+ * input5 - Bias
+ *
+ * also passed dss_lfsr_context structure
+ *
+ ************************************************************************/
+#define DSS_LFSR_NOISE__ENABLE (*(node->input[0]))
+#define DSS_LFSR_NOISE__RESET (*(node->input[1]))
+#define DSS_LFSR_NOISE__CLOCK (*(node->input[2]))
+#define DSS_LFSR_NOISE__AMP (*(node->input[3]))
+#define DSS_LFSR_NOISE__FEED (*(node->input[4]))
+#define DSS_LFSR_NOISE__BIAS (*(node->input[5]))
+
+int dss_lfsr_function(int myfunc,int in0,int in1,int bitmask)
+{
+ int retval;
+
+ in0&=bitmask;
+ in1&=bitmask;
+
+ switch(myfunc)
+ {
+ case DISC_LFSR_XOR:
+ retval=in0^in1;
+ break;
+ case DISC_LFSR_OR:
+ retval=in0|in1;
+ break;
+ case DISC_LFSR_AND:
+ retval=in0&in1;
+ break;
+ case DISC_LFSR_XNOR:
+ retval=in0^in1;
+ retval=retval^bitmask; /* Invert output */
+ break;
+ case DISC_LFSR_NOR:
+ retval=in0|in1;
+ retval=retval^bitmask; /* Invert output */
+ break;
+ case DISC_LFSR_NAND:
+ retval=in0&in1;
+ retval=retval^bitmask; /* Invert output */
+ break;
+ case DISC_LFSR_IN0:
+ retval=in0;
+ break;
+ case DISC_LFSR_IN1:
+ retval=in1;
+ break;
+ case DISC_LFSR_NOT_IN0:
+ retval=in0^bitmask;
+ break;
+ case DISC_LFSR_NOT_IN1:
+ retval=in1^bitmask;
+ break;
+ case DISC_LFSR_REPLACE:
+ retval=in0&~in1;
+ retval=retval|in1;
+ break;
+ case DISC_LFSR_XOR_INV_IN0:
+ retval = in0^bitmask; /* invert in0 */
+ retval = retval^in1; /* xor in1 */
+ break;
+ case DISC_LFSR_XOR_INV_IN1:
+ retval = in1^bitmask; /* invert in1 */
+ retval = retval^in0; /* xor in0 */
+ break;
+ default:
+ discrete_log("dss_lfsr_function - Invalid function type passed");
+ retval=0;
+ break;
+ }
+ return retval;
+}
+
+/* reset prototype so that it can be used in init function */
+void dss_lfsr_reset(node_description *node);
+
+void dss_lfsr_step(node_description *node)
+{
+ const discrete_lfsr_desc *lfsr_desc = node->custom;
+ struct dss_lfsr_context *context = node->context;
+ double cycles;
+ int clock, inc = 0;
+ int fb0,fb1,fbresult;
+
+ if (lfsr_desc->clock_type == DISC_CLK_IS_FREQ)
+ {
+ /* We need to keep clocking the internal clock even if disabled. */
+ cycles = (context->t_left + discrete_current_context->sample_time) / context->t_clock;
+ inc = (int)cycles;
+ context->t_left = (cycles - inc) * context->t_clock;
+ }
+
+ /* Reset everything if necessary */
+ if((DSS_LFSR_NOISE__RESET ? 1 : 0) == context->reset_on_high)
+ {
+ dss_lfsr_reset(node);
+ return;
+ }
+
+ switch (lfsr_desc->clock_type)
+ {
+ case DISC_CLK_ON_F_EDGE:
+ case DISC_CLK_ON_R_EDGE:
+ /* See if the clock has toggled to the proper edge */
+ clock = (DSS_LFSR_NOISE__CLOCK != 0);
+ if (context->last != clock)
+ {
+ context->last = clock;
+ if (lfsr_desc->clock_type == clock)
+ {
+ /* Toggled */
+ inc = 1;
+ }
+ }
+ break;
+
+ case DISC_CLK_BY_COUNT:
+ /* Clock number of times specified. */
+ inc = (int)DSS_LFSR_NOISE__CLOCK;
+ break;
+ }
+
+ for (clock = 0; clock < inc; clock++)
+ {
+ /* Fetch the last feedback result */
+ fbresult=((context->lfsr_reg)>>(lfsr_desc->bitlength))&0x01;
+
+ /* Stage 2 feedback combine fbresultNew with infeed bit */
+ fbresult=dss_lfsr_function(lfsr_desc->feedback_function1,fbresult,((DSS_LFSR_NOISE__FEED)?0x01:0x00),0x01);
+
+ /* Stage 3 first we setup where the bit is going to be shifted into */
+ fbresult=fbresult*lfsr_desc->feedback_function2_mask;
+ /* Then we left shift the register, */
+ context->lfsr_reg=(context->lfsr_reg)<<1;
+ /* Now move the fbresult into the shift register and mask it to the bitlength */
+ context->lfsr_reg=dss_lfsr_function(lfsr_desc->feedback_function2,fbresult, (context->lfsr_reg), ((1<<(lfsr_desc->bitlength))-1));
+
+ /* Now get and store the new feedback result */
+ /* Fetch the feedback bits */
+ fb0=((context->lfsr_reg)>>(lfsr_desc->feedback_bitsel0))&0x01;
+ fb1=((context->lfsr_reg)>>(lfsr_desc->feedback_bitsel1))&0x01;
+ /* Now do the combo on them */
+ fbresult=dss_lfsr_function(lfsr_desc->feedback_function0,fb0,fb1,0x01);
+ context->lfsr_reg=dss_lfsr_function(DISC_LFSR_REPLACE,(context->lfsr_reg), fbresult<<(lfsr_desc->bitlength), ((2<<(lfsr_desc->bitlength))-1));
+
+ /* Now select the output bit */
+ if (context->out_is_f0)
+ node->output = fbresult & 0x01;
+ else
+ node->output=((context->lfsr_reg)>>(lfsr_desc->output_bit))&0x01;
+
+ /* Final inversion if required */
+ if(context->invert_output) node->output=(node->output)?0.0:1.0;
+
+ /* Gain stage */
+ node->output=(node->output)?(DSS_LFSR_NOISE__AMP)/2:-(DSS_LFSR_NOISE__AMP)/2;
+ /* Bias input as required */
+ node->output=node->output+DSS_LFSR_NOISE__BIAS;
+ }
+
+ if(!DSS_LFSR_NOISE__ENABLE)
+ {
+ node->output=0;
+ }
+}
+
+void dss_lfsr_reset(node_description *node)
+{
+ const discrete_lfsr_desc *lfsr_desc = node->custom;
+ struct dss_lfsr_context *context = node->context;
+ int fb0,fb1,fbresult;
+
+ context->reset_on_high = (lfsr_desc->flags & DISC_LFSR_FLAG_RESET_TYPE_H) ? 1 : 0;
+ context->invert_output = lfsr_desc->flags & DISC_LFSR_FLAG_OUT_INVERT;
+ context->out_is_f0 = (lfsr_desc->flags & DISC_LFSR_FLAG_OUTPUT_F0) ? 1 : 0;
+
+ if ((lfsr_desc->clock_type < DISC_CLK_ON_F_EDGE) || (lfsr_desc->clock_type > DISC_CLK_IS_FREQ))
+ discrete_log("Invalid clock type passed in NODE_%d\n", node->node - NODE_START);
+ context->last = (DSS_COUNTER__CLOCK != 0);
+ if (lfsr_desc->clock_type == DISC_CLK_IS_FREQ) context->t_clock = 1.0 / DSS_LFSR_NOISE__CLOCK;
+ context->t_left = 0;
+
+ context->lfsr_reg=lfsr_desc->reset_value;
+
+ /* Now get and store the new feedback result */
+ /* Fetch the feedback bits */
+ fb0=((context->lfsr_reg)>>(lfsr_desc->feedback_bitsel0))&0x01;
+ fb1=((context->lfsr_reg)>>(lfsr_desc->feedback_bitsel1))&0x01;
+ /* Now do the combo on them */
+ fbresult=dss_lfsr_function(lfsr_desc->feedback_function0,fb0,fb1,0x01);
+ context->lfsr_reg=dss_lfsr_function(DISC_LFSR_REPLACE,(context->lfsr_reg), fbresult<<(lfsr_desc->bitlength), ((2<<(lfsr_desc->bitlength))-1));
+
+ /* Now select and setup the output bit */
+ node->output=((context->lfsr_reg)>>(lfsr_desc->output_bit))&0x01;
+
+ /* Final inversion if required */
+ if(lfsr_desc->flags&DISC_LFSR_FLAG_OUT_INVERT) node->output=(node->output)?0.0:1.0;
+
+ /* Gain stage */
+ node->output=(node->output)?(DSS_LFSR_NOISE__AMP)/2:-(DSS_LFSR_NOISE__AMP)/2;
+ /* Bias input as required */
+ node->output=node->output+DSS_LFSR_NOISE__BIAS;
+}
+
+
+/************************************************************************
+ *
+ * DSS_NOISE - Usage of node_description values for white nose generator
+ *
+ * input0 - Enable input value
+ * input1 - Noise sample frequency
+ * input2 - Amplitude input value
+ * input3 - DC Bias value
+ *
+ ************************************************************************/
+#define DSS_NOISE__ENABLE (*(node->input[0]))
+#define DSS_NOISE__FREQ (*(node->input[1]))
+#define DSS_NOISE__AMP (*(node->input[2]))
+#define DSS_NOISE__BIAS (*(node->input[3]))
+
+void dss_noise_step(node_description *node)
+{
+ struct dss_noise_context *context = node->context;
+
+ if(DSS_NOISE__ENABLE)
+ {
+ /* Only sample noise on rollover to next cycle */
+ if(context->phase > (2.0*M_PI))
+ {
+ /* GCC's rand returns a RAND_MAX value of 0x7fff */
+ int newval = (mame_rand(Machine) & 0x7fff) - 16384;
+
+ /* make sure the peak to peak values are the amplitude */
+ node->output = DSS_NOISE__AMP / 2;
+ if (newval > 0)
+ node->output *= ((double)newval / 16383);
+ else
+ node->output *= ((double)newval / 16384);
+
+ /* Add DC Bias component */
+ node->output += DSS_NOISE__BIAS;
+ }
+ }
+ else
+ {
+ node->output = 0;
+ }
+
+ /* Keep the new phasor in the 2Pi range.*/
+ context->phase = fmod(context->phase, 2.0*M_PI);
+
+ /* The enable input only curtails output, phase rotation still occurs. */
+ /* We allow the phase to exceed 2Pi here, so we can tell when to sample the noise. */
+ context->phase += ((2.0*M_PI * DSS_NOISE__FREQ) / discrete_current_context->sample_rate);
+}
+
+
+void dss_noise_reset(node_description *node)
+{
+ struct dss_noise_context *context = node->context;
+
+ context->phase=0;
+ dss_noise_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSS_NOTE - Note/tone generator
+ *
+ * input0 - Enable input value
+ * input1 - Clock Input
+ * input2 - data value
+ * input3 - Max count 1
+ * input4 - Max count 2
+ * input5 - Clock type
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+ #define DSS_NOTE__ENABLE (*(node->input[0]))
+ #define DSS_NOTE__CLOCK (*(node->input[1]))
+ #define DSS_NOTE__DATA (*(node->input[2]))
+ #define DSS_NOTE__MAX1 (*(node->input[3]))
+ #define DSS_NOTE__MAX2 (*(node->input[4]))
+ #define DSS_NOTE__CLOCK_TYPE (*(node->input[5]))
+
+void dss_note_step(node_description *node)
+{
+ struct dss_note_context *context = node->context;
+
+ double cycles;
+ int clock = 0, last_count2, inc = 0;
+ double xTime = 0;
+
+ if (context->clock_type == DISC_CLK_IS_FREQ)
+ {
+ /* We need to keep clocking the internal clock even if disabled. */
+ cycles = (context->t_left + discrete_current_context->sample_time) / context->t_clock;
+ inc = (int)cycles;
+ context->t_left = (cycles - inc) * context->t_clock;
+ if (inc) xTime = context->t_left / discrete_current_context->sample_time;
+ }
+ else
+ {
+ /* Seperate clock info from xTime info. */
+ clock = (int)DSS_NOTE__CLOCK;
+ xTime = DSS_NOTE__CLOCK - clock;
+ }
+
+ if (DSS_NOTE__ENABLE)
+ {
+ last_count2 = context->count2;
+
+ switch (context->clock_type)
+ {
+ case DISC_CLK_ON_F_EDGE:
+ case DISC_CLK_ON_R_EDGE:
+ /* See if the clock has toggled to the proper edge */
+ clock = (clock != 0);
+ if (context->last != clock)
+ {
+ context->last = clock;
+ if (context->clock_type == clock)
+ {
+ /* Toggled */
+ inc = 1;
+ }
+ }
+ break;
+
+ case DISC_CLK_BY_COUNT:
+ /* Clock number of times specified. */
+ inc = clock;
+ break;
+ }
+
+ /* Count output as long as the data loaded is not already equal to max 1 count. */
+ if (DSS_NOTE__DATA != DSS_NOTE__MAX1)
+ {
+ for (clock = 0; clock < inc; clock++)
+ {
+ context->count1++;
+ if (context->count1 > context->max1)
+ {
+ /* Max 1 count reached. Load Data into counter. */
+ context->count1 = (int)DSS_NOTE__DATA;
+ context->count2 += 1;
+ if (context->count2 > context->max2) context->count2 = 0;
+ }
+ }
+ }
+
+ node->output = context->count2;
+ if (context->count2 != last_count2)
+ {
+ /* the xTime is only output if the output changed. */
+ switch (context->out_type)
+ {
+ case DISC_OUT_IS_ENERGY:
+ if (xTime != 0)
+ node->output = (context->count2 > last_count2) ? (last_count2 + xTime) : (last_count2 - xTime);
+ break;
+ case DISC_OUT_HAS_XTIME:
+ node->output += xTime;
+ break;
+ }
+ }
+ }
+ else
+ node->output = 0;
+}
+
+void dss_note_reset(node_description *node)
+{
+ struct dss_note_context *context = node->context;
+
+ context->clock_type = (int)DSS_NOTE__CLOCK_TYPE & DISC_CLK_MASK;
+ context->out_type = (int)DSS_NOTE__CLOCK_TYPE & DISC_OUT_MASK;
+ context->last = (DSS_NOTE__CLOCK != 0);
+ if (context->clock_type == DISC_CLK_IS_FREQ) context->t_clock = 1.0 / DSS_NOTE__CLOCK;
+ context->t_left = 0;
+
+ context->count1 = (int)DSS_NOTE__DATA;
+ context->count2 = 0;
+ context->max1 = (int)DSS_NOTE__MAX1;
+ context->max2 = (int)DSS_NOTE__MAX2;
+ node->output = 0;
+}
+
+/************************************************************************
+ *
+ * DSS_OP_AMP_OSC - Op Amp Oscillators
+ *
+ * input0 - Enable input value
+ * input1 - vMod1 (if needed)
+ * input2 - vMod2 (if needed)
+ *
+ * also passed discrete_op_amp_osc_info structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DSS_OP_AMP_OSC__ENABLE (*(node->input[0]))
+#define DSS_OP_AMP_OSC__VMOD1 (*(node->input[1]))
+#define DSS_OP_AMP_OSC__VMOD2 (*(node->input[2]))
+
+/* The inputs on a norton op-amp are (info->vP - OP_AMP_NORTON_VBE) */
+/* which is the same as the output high voltage. We will define them */
+/* the same to save a calculation step */
+#define DSS_OP_AMP_OSC_NORTON_VP_IN context->high_out_V
+
+void dss_op_amp_osc_step(node_description *node)
+{
+ const discrete_op_amp_osc_info *info = node->custom;
+ struct dss_op_amp_osc_context *context = node->context;
+
+
+ double i; // Charging current created by vIn
+ double v = 0; // all input voltages mixed
+ double dt; // change in time
+ double vC; // Current voltage on capacitor, before dt
+ double vCnext = 0; // Voltage on capacitor, after dt
+ double iCharge[2] = {0};
+ UINT8 force_charge = 0;
+ UINT8 enable = DSS_OP_AMP_OSC__ENABLE;
+
+ dt = discrete_current_context->sample_time; // Change in time
+ vC = context->vCap; // Set to voltage before change
+
+ /* work out the charge currents for the VCOs. */
+ switch (context->type)
+ {
+ case DISC_OP_AMP_OSCILLATOR_VCO_1:
+ /* Work out the charge rates. */
+ i = DSS_OP_AMP_OSC__VMOD1 * context->temp1; // i is not a current. It is being used as a temp variable.
+ iCharge[0] = (DSS_OP_AMP_OSC__VMOD1 - i) / info->r1;
+ iCharge[1] = (i - (DSS_OP_AMP_OSC__VMOD1 * context->temp2)) / context->temp3;
+ break;
+
+ case DISC_OP_AMP_OSCILLATOR_1 | DISC_OP_AMP_IS_NORTON:
+ {
+ /* resistors can be nodes, so everything needs updating */
+ double i1, i2;
+ /* Work out the charge rates. */
+ iCharge[0] = DSS_OP_AMP_OSC_NORTON_VP_IN / *context->r1;
+ iCharge[1] = (context->high_out_V - OP_AMP_NORTON_VBE) / *context->r2 - iCharge[0];
+ /* Work out the Inverting Schmitt thresholds. */
+ i1 = DSS_OP_AMP_OSC_NORTON_VP_IN / *context->r5;
+ i2 = (0.0 - OP_AMP_NORTON_VBE) / *context->r4;
+ context->thresholdLow = (i1 + i2) * *context->r3 + OP_AMP_NORTON_VBE;
+ i2 = (context->high_out_V - OP_AMP_NORTON_VBE) / *context->r4;
+ context->thresholdHigh = (i1 + i2) * *context->r3 + OP_AMP_NORTON_VBE;
+ break;
+ }
+
+ case DISC_OP_AMP_OSCILLATOR_VCO_1 | DISC_OP_AMP_IS_NORTON:
+ /* Millman the input voltages. */
+ if (info->r7 == 0)
+ {
+ /* No r7 means that the modulation circuit is fed directly into the circuit. */
+ v = DSS_OP_AMP_OSC__VMOD1;
+ }
+ else
+ {
+ /* we need to mix any bias and all modulation voltages together. */
+ i = context->iFixed;
+ i += DSS_OP_AMP_OSC__VMOD1 / info->r7;
+ if (info->r8 != 0)
+ i += DSS_OP_AMP_OSC__VMOD2 / info->r8;
+ v = i * context->rTotal;
+ }
+
+ /* Work out the charge rates. */
+ v -= OP_AMP_NORTON_VBE;
+ iCharge[0] = v / info->r1;
+ iCharge[1] = v / info->r2 - iCharge[0];
+
+ /* use the real enable circuit */
+ force_charge = !enable;
+ enable = 1;
+ break;
+
+ case DISC_OP_AMP_OSCILLATOR_VCO_2 | DISC_OP_AMP_IS_NORTON:
+ /* Work out the charge rates. */
+ i = DSS_OP_AMP_OSC__VMOD1 / info->r1;
+ iCharge[0] = i - context->temp1;
+ iCharge[1] = context->temp2 - i;
+ /* if the negative pin current is less then the positive pin current, */
+ /* then the osc is disabled and the cap keeps charging */
+ if (iCharge[0] < 0)
+ {
+ force_charge = 1;
+ iCharge[0] *= -1;
+ }
+ break;
+
+ case DISC_OP_AMP_OSCILLATOR_VCO_3 | DISC_OP_AMP_IS_NORTON:
+ /* we need to mix any bias and all modulation voltages together. */
+ iCharge[0] = context->iFixed;
+ v = DSS_OP_AMP_OSC__VMOD1 - OP_AMP_NORTON_VBE;
+ iCharge[0] += v / info->r1;
+ if (info->r6 != 0)
+ {
+ v = DSS_OP_AMP_OSC__VMOD2 - OP_AMP_NORTON_VBE;
+ iCharge[0] += v / info->r6;
+ }
+ iCharge[1] = context->temp1 - iCharge[0];
+ break;
+ }
+
+ if (enable)
+ {
+ int toggled = 0;
+ /* Keep looping until all toggling in time sample is used up. */
+ do
+ {
+ if ((context->flip_flop ^ context->flip_flopXOR) || force_charge)
+ {
+ /* Charging */
+ /* iC=C*dv/dt works out to dv=iC*dt/C */
+ vCnext = vC + (iCharge[1] * dt / info->c);
+ dt = 0;
+
+ /* has it charged past upper limit? */
+ if (vCnext > context->thresholdHigh)
+ {
+ context->flip_flop = context->flip_flopXOR;
+ toggled++;
+ if (force_charge)
+ {
+ /* we need to keep charging the cap to the max thereby disabling the circuit */
+ if (vCnext > context->high_out_V)
+ vCnext = context->high_out_V;
+ }
+ else
+ {
+ /* calculate the overshoot time */
+ dt = info->c * (vCnext - context->thresholdHigh) / iCharge[1];
+ vC = context->thresholdHigh;
+ }
+ }
+ }
+ else
+ {
+ /* Discharging */
+ vCnext = vC - (iCharge[0] * dt / info->c);
+ dt = 0;
+
+ /* has it discharged past lower limit? */
+ if (vCnext < context->thresholdLow)
+ {
+ context->flip_flop = !context->flip_flopXOR;
+ toggled++;
+ /* calculate the overshoot time */
+ dt = info->c * (context->thresholdLow - vCnext) / iCharge[0];
+ vC = context->thresholdLow;
+ }
+ }
+ } while(dt);
+
+ context->vCap = vCnext;
+
+ if (context->is_squarewave)
+ {
+ if (toggled == 2)
+ /* Some oscillators have rapid rise or fall times causing 1 part of the */
+ /* squarewave to happen in the sample time causing it to be missed. */
+ /* If we toggle 2 states we force the missed output for 1 sample. */
+ /* If more then 2 states happen, there is no hope, the sample rate is just too low. */
+ node->output = context->high_out_V * (context->flip_flop ? 0 : 1);
+ else
+ node->output = context->high_out_V * context->flip_flop;
+ }
+ else
+ node->output = context->vCap;
+ }
+ else
+ {
+ /* we will just output 0 for oscillators that have no real enable. */
+ node->output = 0;
+ }
+}
+
+void dss_op_amp_osc_reset(node_description *node)
+{
+ const discrete_op_amp_osc_info *info = node->custom;
+ struct dss_op_amp_osc_context *context = node->context;
+ const double *r_info_ptr;
+ const double **r_context_ptr;
+ int loop;
+ node_description *r_node;
+
+ double i1 = 0; // inverting input current
+ double i2 = 0; // non-inverting input current
+
+ /* link to resistor static or node values */
+ r_info_ptr = &info->r1;
+ r_context_ptr = &context->r1;
+ for (loop = 0; loop < 8; loop ++)
+ {
+ if IS_VALUE_A_NODE(*r_info_ptr)
+ {
+ r_node = discrete_find_node(NULL, *r_info_ptr);
+ *r_context_ptr = &(r_node->output);
+ }
+ else
+ *r_context_ptr = r_info_ptr;
+ r_info_ptr++;
+ r_context_ptr++;
+ }
+
+ context->is_squarewave = (info->type & DISC_OP_AMP_OSCILLATOR_OUT_SQW);
+ context->type = info->type & DISC_OP_AMP_OSCILLATOR_TYPE_MASK;
+
+ switch (context->type)
+ {
+ case DISC_OP_AMP_OSCILLATOR_VCO_1:
+ /* The charge rates vary depending on vMod so they are not precalculated. */
+ /* Charges while FlipFlop High */
+ context->flip_flopXOR = 0;
+ /* Work out the Non-inverting Schmitt thresholds. */
+ context->temp1 = (info->vP / 2) / info->r4;
+ context->temp2 = (info->vP - OP_AMP_VP_RAIL_OFFSET) / info->r3;
+ context->temp3 = 1.0 / (1.0 / info->r3 + 1.0 / info->r4);
+ context->thresholdLow = context->temp1 * context->temp3;
+ context->thresholdHigh = (context->temp1 + context->temp2) * context->temp3;
+ /* There is no charge on the cap so the schmitt goes high at init. */
+ context->flip_flop = 1;
+ /* Setup some commonly used stuff */
+ context->temp1 = info->r5 / (info->r2 + info->r5); // voltage ratio across r5
+ context->temp2 = info->r6 / (info->r1 + info->r6); // voltage ratio across r6
+ context->temp3 = 1.0 / (1.0 / info->r1 + 1.0 / info->r6); // input resistance when r6 switched in
+ break;
+
+ case DISC_OP_AMP_OSCILLATOR_1 | DISC_OP_AMP_IS_NORTON:
+ /* Charges while FlipFlop High */
+ context->flip_flopXOR = 0;
+ /* There is no charge on the cap so the schmitt inverter goes high at init. */
+ context->flip_flop = 1;
+ break;
+
+ case DISC_OP_AMP_OSCILLATOR_VCO_1 | DISC_OP_AMP_IS_NORTON:
+ /* Charges while FlipFlop Low */
+ context->flip_flopXOR = 1;
+ /* There is no charge on the cap so the schmitt goes low at init. */
+ context->flip_flop = 0;
+ /* The charge rates vary depending on vMod so they are not precalculated. */
+ /* But we can precalculate the fixed currents. */
+ context->iFixed = 0;
+ if (info->r6 != 0) context->iFixed += info->vP / info->r6;
+ context->iFixed += OP_AMP_NORTON_VBE / info->r1;
+ context->iFixed += OP_AMP_NORTON_VBE / info->r2;
+ /* Work out the input resistance to be used later to calculate the Millman voltage. */
+ context->rTotal = 1.0 / info->r1 + 1.0 / info->r2 + 1.0 / info->r7;
+ if (info->r6) context->rTotal += 1.0 / info->r6;
+ if (info->r8) context->rTotal += 1.0 / info->r8;
+ context->rTotal = 1.0 / context->rTotal;
+ /* Work out the Non-inverting Schmitt thresholds. */
+ i1 = (info->vP - OP_AMP_NORTON_VBE) / info->r5;
+ i2 = (info->vP - OP_AMP_NORTON_VBE - OP_AMP_NORTON_VBE) / info->r4;
+ context->thresholdLow = (i1 - i2) * info->r3 + OP_AMP_NORTON_VBE;
+ i2 = (0.0 - OP_AMP_NORTON_VBE) / info->r4;
+ context->thresholdHigh = (i1 - i2) * info->r3 + OP_AMP_NORTON_VBE;
+ break;
+
+ case DISC_OP_AMP_OSCILLATOR_VCO_2 | DISC_OP_AMP_IS_NORTON:
+ /* Charges while FlipFlop High */
+ context->flip_flopXOR = 0;
+ /* There is no charge on the cap so the schmitt inverter goes high at init. */
+ context->flip_flop = 1;
+ /* Work out the charge rates. */
+ context->temp1 = (info->vP - OP_AMP_NORTON_VBE) / info->r2;
+ context->temp2 = (info->vP - OP_AMP_NORTON_VBE) * (1.0 / info->r2 + 1.0 / info->r6);
+ /* Work out the Inverting Schmitt thresholds. */
+ i1 = (info->vP - OP_AMP_NORTON_VBE) / info->r5;
+ i2 = (0.0 - OP_AMP_NORTON_VBE) / info->r4;
+ context->thresholdLow = (i1 + i2) * info->r3 + OP_AMP_NORTON_VBE;
+ i2 = (info->vP - OP_AMP_NORTON_VBE - OP_AMP_NORTON_VBE) / info->r4;
+ context->thresholdHigh = (i1 + i2) * info->r3 + OP_AMP_NORTON_VBE;
+ break;
+
+ case DISC_OP_AMP_OSCILLATOR_VCO_3 | DISC_OP_AMP_IS_NORTON:
+ /* Charges while FlipFlop High */
+ context->flip_flopXOR = 0;
+ /* There is no charge on the cap so the schmitt inverter goes high at init. */
+ context->flip_flop = 1;
+ /* Work out the charge rates. */
+ /* The charge rates vary depending on vMod so they are not precalculated. */
+ /* But we can precalculate the fixed currents. */
+ if (info->r7 != 0) context->iFixed = (info->vP - OP_AMP_NORTON_VBE) / info->r7;
+ context->temp1 = (info->vP - OP_AMP_NORTON_VBE - OP_AMP_NORTON_VBE) / info->r2;
+ /* Work out the Inverting Schmitt thresholds. */
+ i1 = (info->vP - OP_AMP_NORTON_VBE) / info->r5;
+ i2 = (0.0 - OP_AMP_NORTON_VBE) / info->r4;
+ context->thresholdLow = (i1 + i2) * info->r3 + OP_AMP_NORTON_VBE;
+ i2 = (info->vP - OP_AMP_NORTON_VBE - OP_AMP_NORTON_VBE) / info->r4;
+ context->thresholdHigh = (i1 + i2) * info->r3 + OP_AMP_NORTON_VBE;
+ break;
+ }
+
+ context->high_out_V = info->vP - ((context->type & DISC_OP_AMP_IS_NORTON) ? OP_AMP_NORTON_VBE : OP_AMP_VP_RAIL_OFFSET);
+ context->vCap = 0;
+
+ dss_op_amp_osc_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSS_SAWTOOTHWAVE - Usage of node_description values for step function
+ *
+ * input0 - Enable input value
+ * input1 - Frequency input value
+ * input2 - Amplitde input value
+ * input3 - DC Bias Value
+ * input4 - Gradient
+ * input5 - Initial Phase
+ *
+ ************************************************************************/
+#define DSS_SAWTOOTHWAVE__ENABLE (*(node->input[0]))
+#define DSS_SAWTOOTHWAVE__FREQ (*(node->input[1]))
+#define DSS_SAWTOOTHWAVE__AMP (*(node->input[2]))
+#define DSS_SAWTOOTHWAVE__BIAS (*(node->input[3]))
+#define DSS_SAWTOOTHWAVE__GRAD (*(node->input[4]))
+#define DSS_SAWTOOTHWAVE__PHASE (*(node->input[5]))
+
+void dss_sawtoothwave_step(node_description *node)
+{
+ struct dss_sawtoothwave_context *context = node->context;
+
+ if(DSS_SAWTOOTHWAVE__ENABLE)
+ {
+ node->output=(context->type==0)?context->phase*(DSS_SAWTOOTHWAVE__AMP/(2.0*M_PI)):DSS_SAWTOOTHWAVE__AMP-(context->phase*(DSS_SAWTOOTHWAVE__AMP/(2.0*M_PI)));
+ node->output-=DSS_SAWTOOTHWAVE__AMP/2.0;
+ /* Add DC Bias component */
+ node->output=node->output+DSS_SAWTOOTHWAVE__BIAS;
+ }
+ else
+ {
+ node->output=0;
+ }
+
+ /* Work out the phase step based on phase/freq & sample rate */
+ /* The enable input only curtails output, phase rotation */
+ /* still occurs */
+ /* phase step = 2Pi/(output period/sample period) */
+ /* boils out to */
+ /* phase step = (2Pi*output freq)/sample freq) */
+ /* Also keep the new phasor in the 2Pi range. */
+ context->phase=fmod((context->phase+((2.0*M_PI*DSS_SAWTOOTHWAVE__FREQ)/discrete_current_context->sample_rate)),2.0*M_PI);
+}
+
+void dss_sawtoothwave_reset(node_description *node)
+{
+ struct dss_sawtoothwave_context *context = node->context;
+ double start;
+
+ /* Establish starting phase, convert from degrees to radians */
+ start=(DSS_SAWTOOTHWAVE__PHASE/360.0)*(2.0*M_PI);
+ /* Make sure its always mod 2Pi */
+ context->phase=fmod(start,2.0*M_PI);
+
+ /* Invert gradient depending on sawtooth type /|/|/|/|/| or |\|\|\|\|\ */
+ context->type=(DSS_SAWTOOTHWAVE__GRAD)?1:0;
+
+ /* Step the node to set the output */
+ dss_sawtoothwave_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSS_SCHMITT_OSC - Schmitt feedback oscillator
+ *
+ * input0 - Enable input value
+ * input1 - Vin
+ * input2 - Amplitude
+ *
+ * also passed discrete_schmitt_osc_disc structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DSS_SCHMITT_OSC__ENABLE (int)(*(node->input[0]))
+#define DSS_SCHMITT_OSC__VIN (*(node->input[1]))
+#define DSS_SCHMITT_OSC__AMP (*(node->input[2]))
+
+void dss_schmitt_osc_step(node_description *node)
+{
+ const discrete_schmitt_osc_desc *info = node->custom;
+ struct dss_schmitt_osc_context *context = node->context;
+
+ double supply, vCap, new_vCap, t, exponent;
+
+ /* We will always oscillate. The enable just affects the output. */
+ vCap = context->vCap;
+ exponent = context->exponent;
+
+ /* Keep looping until all toggling in time sample is used up. */
+ do
+ {
+ t = 0;
+ /* The charging voltage to the cap is the sum of the input voltage and the gate
+ * output voltage in the ratios determined by their resistors in a divider network.
+ * The input voltage is selectable as straight voltage in or logic level that will
+ * use vGate as its voltage. Note that ratioIn is just the ratio of the total
+ * voltage and needs to be multipled by the input voltage. ratioFeedback has
+ * already been multiplied by vGate to save time because that voltage never changes. */
+ supply = context->input_is_voltage ? context->ratioIn * DSS_SCHMITT_OSC__VIN : (DSS_SCHMITT_OSC__VIN ? context->ratioIn * info->vGate : 0);
+ supply += (context->state ? context->ratioFeedback : 0);
+ new_vCap = vCap + ((supply - vCap) * exponent);
+ if (context->state)
+ {
+ /* Charging */
+ /* has it charged past upper limit? */
+ if (new_vCap > info->trshRise)
+ {
+ /* calculate the overshoot time */
+ t = context->rc * log(1.0 / (1.0 - ((new_vCap - info->trshRise) / (info->vGate - vCap))));
+ /* calculate new exponent because of reduced time */
+ exponent = 1.0 - exp(-t / context->rc);
+ vCap = new_vCap = info->trshRise;
+ context->state = 0;
+ }
+ }
+ else
+ {
+ /* Discharging */
+ /* has it discharged past lower limit? */
+ if (new_vCap < info->trshFall)
+ {
+ /* calculate the overshoot time */
+ t = context->rc * log(1.0 / (1.0 - ((info->trshFall - new_vCap) / vCap)));
+ /* calculate new exponent because of reduced time */
+ exponent = 1.0 - exp(-t / context->rc);
+ vCap = new_vCap = info->trshFall;
+ context->state = 1;
+ }
+ }
+ } while(t);
+
+ context->vCap = new_vCap;
+
+ switch (context->enable_type)
+ {
+ case DISC_SCHMITT_OSC_ENAB_IS_AND:
+ node->output = DSS_SCHMITT_OSC__ENABLE && context->state;
+ break;
+ case DISC_SCHMITT_OSC_ENAB_IS_NAND:
+ node->output = !(DSS_SCHMITT_OSC__ENABLE && context->state);
+ break;
+ case DISC_SCHMITT_OSC_ENAB_IS_OR:
+ node->output = DSS_SCHMITT_OSC__ENABLE || context->state;
+ break;
+ case DISC_SCHMITT_OSC_ENAB_IS_NOR:
+ node->output = !(DSS_SCHMITT_OSC__ENABLE || context->state);
+ break;
+ }
+ node->output *= DSS_SCHMITT_OSC__AMP;
+}
+
+void dss_schmitt_osc_reset(node_description *node)
+{
+ const discrete_schmitt_osc_desc *info = node->custom;
+ struct dss_schmitt_osc_context *context = node->context;
+ double rSource;
+
+ context->enable_type = info->options & DISC_SCHMITT_OSC_ENAB_MASK;
+ context->input_is_voltage = (info->options & DISC_SCHMITT_OSC_IN_IS_VOLTAGE) ? 1 : 0;
+
+ /* The 2 resistors make a voltage divider, so their ratios add together
+ * to make the charging voltage. */
+ context->ratioIn = info->rFeedback / (info->rIn + info->rFeedback);
+ context->ratioFeedback = info->rIn / (info->rIn + info->rFeedback) * info->vGate;
+
+ /* The voltage source resistance works out to the 2 resistors in parallel.
+ * So use this for the RC charge constant. */
+ rSource = 1.0 / ((1.0 / info->rIn) + (1.0 / info->rFeedback));
+ context->rc = rSource * info->c;
+ context->exponent = -1.0 / (context->rc * discrete_current_context->sample_rate);
+ context->exponent = 1.0 - exp(context->exponent);
+
+ /* Cap is at 0V on power up. Causing output to be high. */
+ context->vCap = 0;
+ context->state = 1;
+
+ node->output = info->options ? 0 : DSS_SCHMITT_OSC__AMP;
+}
+
+
+/************************************************************************
+ *
+ * DSS_SINEWAVE - Usage of node_description values for step function
+ *
+ * input0 - Enable input value
+ * input1 - Frequency input value
+ * input2 - Amplitude input value
+ * input3 - DC Bias
+ * input4 - Starting phase
+ *
+ ************************************************************************/
+#define DSS_SINEWAVE__ENABLE (*(node->input[0]))
+#define DSS_SINEWAVE__FREQ (*(node->input[1]))
+#define DSS_SINEWAVE__AMPL (*(node->input[2]))
+#define DSS_SINEWAVE__BIAS (*(node->input[3]))
+#define DSS_SINEWAVE__PHASE (*(node->input[4]))
+
+void dss_sinewave_step(node_description *node)
+{
+ struct dss_sinewave_context *context = node->context;
+
+ /* Set the output */
+ if(DSS_SINEWAVE__ENABLE)
+ {
+ node->output=(DSS_SINEWAVE__AMPL/2.0) * sin(context->phase);
+ /* Add DC Bias component */
+ node->output=node->output+DSS_SINEWAVE__BIAS;
+ }
+ else
+ {
+ node->output=0;
+ }
+
+ /* Work out the phase step based on phase/freq & sample rate */
+ /* The enable input only curtails output, phase rotation */
+ /* still occurs */
+ /* phase step = 2Pi/(output period/sample period) */
+ /* boils out to */
+ /* phase step = (2Pi*output freq)/sample freq) */
+ /* Also keep the new phasor in the 2Pi range. */
+ context->phase=fmod((context->phase+((2.0*M_PI*DSS_SINEWAVE__FREQ)/discrete_current_context->sample_rate)),2.0*M_PI);
+}
+
+void dss_sinewave_reset(node_description *node)
+{
+ struct dss_sinewave_context *context = node->context;
+ double start;
+
+ /* Establish starting phase, convert from degrees to radians */
+ start=(DSS_SINEWAVE__PHASE/360.0)*(2.0*M_PI);
+ /* Make sure its always mod 2Pi */
+ context->phase=fmod(start,2.0*M_PI);
+ /* Step the output to make it correct */
+ dss_sinewave_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSS_SQUAREWAVE - Usage of node_description values for step function
+ *
+ * input0 - Enable input value
+ * input1 - Frequency input value
+ * input2 - Amplitude input value
+ * input3 - Duty Cycle
+ * input4 - DC Bias level
+ * input5 - Start Phase
+ *
+ ************************************************************************/
+#define DSS_SQUAREWAVE__ENABLE (*(node->input[0]))
+#define DSS_SQUAREWAVE__FREQ (*(node->input[1]))
+#define DSS_SQUAREWAVE__AMP (*(node->input[2]))
+#define DSS_SQUAREWAVE__DUTY (*(node->input[3]))
+#define DSS_SQUAREWAVE__BIAS (*(node->input[4]))
+#define DSS_SQUAREWAVE__PHASE (*(node->input[5]))
+
+void dss_squarewave_step(node_description *node)
+{
+ struct dss_squarewave_context *context = node->context;
+
+ /* Establish trigger phase from duty */
+ context->trigger=((100-DSS_SQUAREWAVE__DUTY)/100)*(2.0*M_PI);
+
+ /* Set the output */
+ if(DSS_SQUAREWAVE__ENABLE)
+ {
+ if(context->phase>context->trigger)
+ node->output=(DSS_SQUAREWAVE__AMP/2.0);
+ else
+ node->output=-(DSS_SQUAREWAVE__AMP/2.0);
+
+ /* Add DC Bias component */
+ node->output=node->output+DSS_SQUAREWAVE__BIAS;
+ }
+ else
+ {
+ node->output=0;
+ }
+
+ /* Work out the phase step based on phase/freq & sample rate */
+ /* The enable input only curtails output, phase rotation */
+ /* still occurs */
+ /* phase step = 2Pi/(output period/sample period) */
+ /* boils out to */
+ /* phase step = (2Pi*output freq)/sample freq) */
+ /* Also keep the new phasor in the 2Pi range. */
+ context->phase=fmod((context->phase+((2.0*M_PI*DSS_SQUAREWAVE__FREQ)/discrete_current_context->sample_rate)),2.0*M_PI);
+}
+
+void dss_squarewave_reset(node_description *node)
+{
+ struct dss_squarewave_context *context = node->context;
+ double start;
+
+ /* Establish starting phase, convert from degrees to radians */
+ start=(DSS_SQUAREWAVE__PHASE/360.0)*(2.0*M_PI);
+ /* Make sure its always mod 2Pi */
+ context->phase=fmod(start,2.0*M_PI);
+
+ /* Step the output */
+ dss_squarewave_step(node);
+}
+
+/************************************************************************
+ *
+ * DSS_SQUAREWFIX - Usage of node_description values for step function
+ *
+ * input0 - Enable input value
+ * input1 - Frequency input value
+ * input2 - Amplitude input value
+ * input3 - Duty Cycle
+ * input4 - DC Bias level
+ * input5 - Start Phase
+ *
+ ************************************************************************/
+#define DSS_SQUAREWFIX__ENABLE (*(node->input[0]))
+#define DSS_SQUAREWFIX__FREQ (*(node->input[1]))
+#define DSS_SQUAREWFIX__AMP (*(node->input[2]))
+#define DSS_SQUAREWFIX__DUTY (*(node->input[3]))
+#define DSS_SQUAREWFIX__BIAS (*(node->input[4]))
+#define DSS_SQUAREWFIX__PHASE (*(node->input[5]))
+
+void dss_squarewfix_step(node_description *node)
+{
+ struct dss_squarewfix_context *context = node->context;
+
+ context->tLeft -= context->sampleStep;
+
+ /* The enable input only curtails output, phase rotation still occurs */
+ while (context->tLeft <= 0)
+ {
+ context->flip_flop = context->flip_flop ? 0 : 1;
+ context->tLeft += context->flip_flop ? context->tOn : context->tOff;
+ }
+
+ if(DSS_SQUAREWFIX__ENABLE)
+ {
+ /* Add gain and DC Bias component */
+
+ context->tOff = 1.0 / DSS_SQUAREWFIX__FREQ; /* cycle time */
+ context->tOn = context->tOff * (DSS_SQUAREWFIX__DUTY / 100.0);
+ context->tOff -= context->tOn;
+
+ node->output = (context->flip_flop ? DSS_SQUAREWFIX__AMP / 2.0 : -(DSS_SQUAREWFIX__AMP / 2.0)) + DSS_SQUAREWFIX__BIAS;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+void dss_squarewfix_reset(node_description *node)
+{
+ struct dss_squarewfix_context *context = node->context;
+
+ context->sampleStep = 1.0 / discrete_current_context->sample_rate;
+ context->flip_flop = 1;
+
+ /* Do the intial time shift and convert freq to off/on times */
+ context->tOff = 1.0 / DSS_SQUAREWFIX__FREQ; /* cycle time */
+ context->tLeft = DSS_SQUAREWFIX__PHASE / 360.0; /* convert start phase to % */
+ context->tLeft = context->tLeft - (int)context->tLeft; /* keep % between 0 & 1 */
+ context->tLeft = (context->tLeft < 0) ? 1.0 + context->tLeft : context->tLeft; /* if - then flip to + phase */
+ context->tLeft *= context->tOff;
+ context->tOn = context->tOff * (DSS_SQUAREWFIX__DUTY / 100.0);
+ context->tOff -= context->tOn;
+
+ context->tLeft = -context->tLeft;
+
+ /* toggle output and work out intial time shift */
+ while (context->tLeft <= 0)
+ {
+ context->flip_flop = context->flip_flop ? 0 : 1;
+ context->tLeft += context->flip_flop ? context->tOn : context->tOff;
+ }
+
+ /* Step the output */
+ dss_squarewfix_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSS_SQUAREWAVE2 - Usage of node_description values
+ *
+ * input0 - Enable input value
+ * input1 - Amplitude input value
+ * input2 - OFF Time
+ * input3 - ON Time
+ * input4 - DC Bias level
+ * input5 - Initial Time Shift
+ *
+ ************************************************************************/
+#define DSS_SQUAREWAVE2__ENABLE (*(node->input[0]))
+#define DSS_SQUAREWAVE2__AMP (*(node->input[1]))
+#define DSS_SQUAREWAVE2__T_OFF (*(node->input[2]))
+#define DSS_SQUAREWAVE2__T_ON (*(node->input[3]))
+#define DSS_SQUAREWAVE2__BIAS (*(node->input[4]))
+#define DSS_SQUAREWAVE2__SHIFT (*(node->input[5]))
+
+void dss_squarewave2_step(node_description *node)
+{
+ struct dss_squarewave_context *context = node->context;
+ double newphase;
+
+ if(DSS_SQUAREWAVE2__ENABLE)
+ {
+ /* Establish trigger phase from time periods */
+ context->trigger=(DSS_SQUAREWAVE2__T_OFF / (DSS_SQUAREWAVE2__T_OFF + DSS_SQUAREWAVE2__T_ON)) * (2.0 * M_PI);
+
+ /* Work out the phase step based on phase/freq & sample rate */
+ /* The enable input only curtails output, phase rotation */
+ /* still occurs */
+
+ /* phase step = 2Pi/(output period/sample period) */
+ /* boils out to */
+ /* phase step = 2Pi/(output period*sample freq) */
+ newphase = context->phase + ((2.0 * M_PI) / ((DSS_SQUAREWAVE2__T_OFF + DSS_SQUAREWAVE2__T_ON) * discrete_current_context->sample_rate));
+ /* Keep the new phasor in the 2Pi range.*/
+ context->phase = fmod(newphase, 2.0 * M_PI);
+
+ if(context->phase>context->trigger)
+ node->output=(DSS_SQUAREWAVE2__AMP/2.0);
+ else
+ node->output=-(DSS_SQUAREWAVE2__AMP/2.0);
+
+ /* Add DC Bias component */
+ node->output = node->output + DSS_SQUAREWAVE2__BIAS;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+void dss_squarewave2_reset(node_description *node)
+{
+ struct dss_squarewave_context *context = node->context;
+ double start;
+
+ /* Establish starting phase, convert from degrees to radians */
+ /* Only valid if we have set the on/off time */
+ if((DSS_SQUAREWAVE2__T_OFF + DSS_SQUAREWAVE2__T_ON) != 0.0)
+ start = (DSS_SQUAREWAVE2__SHIFT / (DSS_SQUAREWAVE2__T_OFF + DSS_SQUAREWAVE2__T_ON)) * (2.0 * M_PI);
+ else
+ start = 0.0;
+ /* Make sure its always mod 2Pi */
+ context->phase = fmod(start, 2.0 * M_PI);
+
+ /* Step the output */
+ dss_squarewave2_step(node);
+}
+
+/************************************************************************
+ *
+ * DSS_INVERTER_OSC - Usage of node_description values
+ *
+ * input0 - Enable input value
+ * input1 - RC Resistor
+ * input2 - RP Resistor
+ * input3 - C Capacitor
+ * input4 - Desc
+ *
+ ************************************************************************/
+#define DSS_INVERTER_OSC__ENABLE (*(node->input[0]))
+#define DSS_INVERTER_OSC__MOD (*(node->input[1]))
+#define DSS_INVERTER_OSC__RC (*(node->input[2]))
+#define DSS_INVERTER_OSC__RP (*(node->input[3]))
+#define DSS_INVERTER_OSC__C (*(node->input[4]))
+#define DSS_INVERTER_OSC__R2 (*(node->input[5]))
+
+static double dss_inverter_tf(node_description *node, double x)
+{
+ const discrete_inverter_osc_desc *info = node->custom;
+ struct dss_inverter_osc_context *context = node->context;
+
+ x = x / info->vB;
+ if (x>0)
+ return info->vB * exp(-context->tf_a * pow(x,context->tf_b));
+ else
+ return info->vB;
+}
+
+void dss_inverter_osc_step(node_description *node)
+{
+ struct dss_inverter_osc_context *context = node->context;
+ const discrete_inverter_osc_desc *info = node->custom;
+ double diff,vG1,vG2, vG3, vI;
+ double vMix, rMix;
+
+ /* Get new state */
+ vI = context->vCap + context->vG2_old;
+ switch (info->options & DISC_OSC_INVERTER_TYPE_MASK)
+ {
+ case DISC_OSC_INVERTER_IS_TYPE1:
+ case DISC_OSC_INVERTER_IS_TYPE3:
+ vG1 = dss_inverter_tf(node,vI);
+ vG2 = dss_inverter_tf(node,vG1);
+ vG3 = dss_inverter_tf(node,vG2);
+ break;
+ case DISC_OSC_INVERTER_IS_TYPE2:
+ vG1 = 0;
+ vG3 = dss_inverter_tf(node,vI);
+ vG2 = dss_inverter_tf(node,vG3);
+ break;
+ case DISC_OSC_INVERTER_IS_TYPE4:
+ vI = MIN(DSS_INVERTER_OSC__ENABLE, vI + 0.7);
+ vG1 = 0;
+ vG3 = dss_inverter_tf(node,vI);
+ vG2 = dss_inverter_tf(node,vG3);
+ break;
+ case DISC_OSC_INVERTER_IS_TYPE5:
+ vI = MAX(DSS_INVERTER_OSC__ENABLE, vI - 0.7);
+ vG1 = 0;
+ vG3 = dss_inverter_tf(node,vI);
+ vG2 = dss_inverter_tf(node,vG3);
+ break;
+ default:
+ fatalerror("DISCRETE_INVERTER_OSC - Wrong type on NODE_%02d", node->node - NODE_00);
+ }
+ switch (info->options & DISC_OSC_INVERTER_TYPE_MASK)
+ {
+ case DISC_OSC_INVERTER_IS_TYPE1:
+ case DISC_OSC_INVERTER_IS_TYPE2:
+ case DISC_OSC_INVERTER_IS_TYPE3:
+ if ((info->clamp >= 0.0) && ((vI< - info->clamp) || (vI> info->vB+info->clamp)))
+ {
+ vI = MAX(vI, (- info->clamp));
+ vI = MIN(vI, info->vB + info->clamp);
+ diff = vG3 * (context->Rp / (context->Rp + context->R1))
+ - (context->vCap + vG2)
+ + vI*(context->R1 / (context->Rp + context->R1));
+ diff = diff - diff * exp(context->wc * discrete_current_context->sample_time);
+ }
+ else
+ {
+ diff = vG3 - (context->vCap + vG2);
+ diff = diff - diff * exp(context->w * discrete_current_context->sample_time);
+ }
+ break;
+ case DISC_OSC_INVERTER_IS_TYPE4:
+ if ((info->clamp >= 0.0) && ((vI< - info->clamp) || (vI> info->vB+info->clamp)))
+ {
+ vI = MAX(vI, (- info->clamp));
+ vI = MIN(vI, info->vB + info->clamp);
+ }
+ // FIXME handle R2 = 0
+ rMix = (context->R1 * context->R2) / (context->R1 + context->R2);
+ vMix = rMix* ((vG3-vG2) / context->R1 + (DSS_INVERTER_OSC__MOD-vG2) / context->R2);
+ if (vMix < (vI-vG2-0.7))
+ {
+ rMix = 1.0/rMix + 1.0/context->Rp;
+ rMix = 1.0 / rMix;
+ vMix = rMix* ( (vG3-vG2) / context->R1 + (DSS_INVERTER_OSC__MOD-vG2) / context->R2 + (vI-0.7-vG2)/context->Rp);
+ }
+ diff = vMix - context->vCap;
+ diff = diff - diff * exp(-discrete_current_context->sample_time/(context->C * rMix));
+ break;
+ case DISC_OSC_INVERTER_IS_TYPE5:
+ if ((info->clamp >= 0.0) && ((vI< - info->clamp) || (vI> info->vB+info->clamp)))
+ {
+ vI = MAX(vI, (- info->clamp));
+ vI = MIN(vI, info->vB + info->clamp);
+ }
+ // FIXME handle R2 = 0
+ rMix = (context->R1 * context->R2) / (context->R1 + context->R2);
+ vMix = rMix* ((vG3-vG2) / context->R1 + (DSS_INVERTER_OSC__MOD-vG2) / context->R2);
+ if (vMix > (vI-vG2+0.7))
+ {
+ rMix = 1.0/rMix + 1.0/context->Rp;
+ rMix = 1.0 / rMix;
+ vMix = rMix* ( (vG3-vG2) / context->R1 + (DSS_INVERTER_OSC__MOD-vG2) / context->R2 + (vI+0.7-vG2)/context->Rp);
+ }
+ diff = vMix - context->vCap;
+ diff = diff - diff * exp(-discrete_current_context->sample_time/(context->C * rMix));
+ break;
+ default:
+ fatalerror("DISCRETE_INVERTER_OSC - Wrong type on NODE_%02d", node->node - NODE_00);
+ }
+ context->vCap += diff;
+ context->vG2_old = vG2;
+ if ((info->options & DISC_OSC_INVERTER_TYPE_MASK)==DISC_OSC_INVERTER_IS_TYPE3)
+ node->output = vG1;
+ else
+ node->output = vG3;
+ if (info->options & DISC_OSC_INVERTER_OUT_IS_LOGIC)
+ node->output = (node->output > info->vInFall);
+}
+
+void dss_inverter_osc_reset(node_description *node)
+{
+ struct dss_inverter_osc_context *context = node->context;
+ const discrete_inverter_osc_desc *info = node->custom;
+
+ /* exponent */
+ context->w = -1.0 / (DSS_INVERTER_OSC__RC * DSS_INVERTER_OSC__C);
+ context->wc = -1.0 / ((DSS_INVERTER_OSC__RC * DSS_INVERTER_OSC__RP) / (DSS_INVERTER_OSC__RP + DSS_INVERTER_OSC__RC) * DSS_INVERTER_OSC__C);
+ node->output = 0;
+ context->vCap = 0;
+ context->vG2_old = 0;
+ context->Rp = DSS_INVERTER_OSC__RP;
+ context->R1 = DSS_INVERTER_OSC__RC;
+ context->R2 = DSS_INVERTER_OSC__R2;
+ context->C = DSS_INVERTER_OSC__C;
+ context->tf_b = (log(0.0 - log(info->vOutLow/info->vB)) - log(0.0 - log((info->vOutHigh/info->vB))) ) / log(info->vInRise / info->vInFall);
+ context->tf_a = log(0.0 - log(info->vOutLow/info->vB)) - context->tf_b * log(info->vInRise/info->vB);
+ context->tf_a = exp(context->tf_a);
+}
+
+/************************************************************************
+ *
+ * DSS_TRIANGLEWAVE - Usage of node_description values for step function
+ *
+ * input0 - Enable input value
+ * input1 - Frequency input value
+ * input2 - Amplitde input value
+ * input3 - DC Bias value
+ * input4 - Initial Phase
+ *
+ ************************************************************************/
+#define DSS_TRIANGLEWAVE__ENABLE (*(node->input[0]))
+#define DSS_TRIANGLEWAVE__FREQ (*(node->input[1]))
+#define DSS_TRIANGLEWAVE__AMP (*(node->input[2]))
+#define DSS_TRIANGLEWAVE__BIAS (*(node->input[3]))
+#define DSS_TRIANGLEWAVE__PHASE (*(node->input[4]))
+
+void dss_trianglewave_step(node_description *node)
+{
+ struct dss_trianglewave_context *context = node->context;
+
+ if(DSS_TRIANGLEWAVE__ENABLE)
+ {
+ node->output=context->phase < M_PI ? (DSS_TRIANGLEWAVE__AMP * (context->phase / (M_PI/2.0) - 1.0))/2.0 :
+ (DSS_TRIANGLEWAVE__AMP * (3.0 - context->phase / (M_PI/2.0)))/2.0 ;
+
+ /* Add DC Bias component */
+ node->output=node->output+DSS_TRIANGLEWAVE__BIAS;
+ }
+ else
+ {
+ node->output=0;
+ }
+
+ /* Work out the phase step based on phase/freq & sample rate */
+ /* The enable input only curtails output, phase rotation */
+ /* still occurs */
+ /* phase step = 2Pi/(output period/sample period) */
+ /* boils out to */
+ /* phase step = (2Pi*output freq)/sample freq) */
+ /* Also keep the new phasor in the 2Pi range. */
+ context->phase=fmod((context->phase+((2.0*M_PI*DSS_TRIANGLEWAVE__FREQ)/discrete_current_context->sample_rate)),2.0*M_PI);
+}
+
+void dss_trianglewave_reset(node_description *node)
+{
+ struct dss_trianglewave_context *context = node->context;
+ double start;
+
+ /* Establish starting phase, convert from degrees to radians */
+ start=(DSS_TRIANGLEWAVE__PHASE/360.0)*(2.0*M_PI);
+ /* Make sure its always mod 2Pi */
+ context->phase=fmod(start,2.0*M_PI);
+
+ /* Step to set the output */
+ dss_trianglewave_step(node);
+}
+
+
+/************************************************************************
+ *
+ * DSS_ADSR - Attack Decay Sustain Release
+ *
+ * input0 - Enable input value
+ * input1 - Trigger value
+ * input2 - gain scaling factor
+ *
+ ************************************************************************/
+#define DSS_ADSR__ENABLE (*(node->input[0]))
+
+void dss_adsrenv_step(node_description *node)
+{
+// struct dss_adsr_context *context = node->context;
+
+ if(DSS_ADSR__ENABLE)
+ {
+ node->output=0;
+ }
+ else
+ {
+ node->output=0;
+ }
+}
+
+
+void dss_adsrenv_reset(node_description *node)
+{
+ dss_adsrenv_step(node);
+}
diff --git a/src/emu/sound/discrete.c b/src/emu/sound/discrete.c
new file mode 100644
index 00000000000..25b3e03024b
--- /dev/null
+++ b/src/emu/sound/discrete.c
@@ -0,0 +1,751 @@
+/************************************************************************
+ *
+ * MAME - Discrete sound system emulation library
+ *
+ * Written by Keith Wilkins (mame@esplexo.co.uk)
+ *
+ * (c) K.Wilkins 2000
+ *
+ * Coding started in November 2000
+ * KW - Added Sawtooth waveforms Feb2003
+ *
+ ***********************************************************************
+ *
+ * SEE DISCRETE.H for documentation on usage
+ *
+ ***********************************************************************
+ *
+ * Each sound primative DSS_xxxx or DST_xxxx has its own implementation
+ * file. All discrete sound primatives MUST implement the following
+ * API:
+ *
+ * dsX_NAME_step(inputs, context,float timestep) - Perform time step
+ * return output value
+ * dsX_NAME_reset(context) - Reset to initial state
+ *
+ * Core software takes care of traversing the netlist in the correct
+ * order
+ *
+ * discrete_start() - Read Node list, initialise & reset
+ * discrete_stop() - Shutdown discrete sound system
+ * discrete_reset() - Put sound system back to time 0
+ * discrete_update() - Update streams to current time
+ * discrete_stream_update() - This does the real update to the sim
+ *
+ ************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "inptport.h"
+#include "wavwrite.h"
+#include "discrete.h"
+#include <stdarg.h>
+#include <math.h>
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define DISCRETE_DEBUGLOG (0)
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+struct _discrete_info
+{
+ /* emulation info */
+ int sndindex;
+ int sample_rate;
+ double sample_time;
+
+ /* internal node tracking */
+ int node_count;
+ node_description **running_order;
+ node_description **indexed_node;
+ node_description *node_list;
+
+ /* the input streams */
+ int discrete_input_streams;
+ stream_sample_t **input_stream_data[DISCRETE_MAX_OUTPUTS];
+
+ /* output node tracking */
+ int discrete_outputs;
+ node_description *output_node[DISCRETE_MAX_OUTPUTS];
+
+ /* the output stream */
+ sound_stream *discrete_stream;
+
+ /* debugging statics */
+ FILE *disclogfile;
+
+ /* csvlog tracking */
+ int num_csvlogs;
+ FILE *disc_csv_file[DISCRETE_MAX_CSVLOGS];
+ node_description *csvlog_node[DISCRETE_MAX_CSVLOGS];
+ INT64 sample_num;
+
+ /* wavelog tracking */
+ int num_wavelogs;
+ wav_file *disc_wav_file[DISCRETE_MAX_WAVELOGS];
+ node_description *wavelog_node[DISCRETE_MAX_WAVELOGS];
+};
+typedef struct _discrete_info discrete_info;
+
+static discrete_info *discrete_current_context;
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static void init_nodes(discrete_info *info, discrete_sound_block *block_list);
+static void find_input_nodes(discrete_info *info, discrete_sound_block *block_list);
+static void setup_output_nodes(discrete_info *info);
+static void setup_disc_logs(discrete_info *info);
+static void discrete_reset(void *chip);
+
+
+
+/*************************************
+ *
+ * Debug logging
+ *
+ *************************************/
+
+static void CLIB_DECL discrete_log(const char *text, ...)
+{
+ if (DISCRETE_DEBUGLOG)
+ {
+ va_list arg;
+ va_start(arg, text);
+
+ if(discrete_current_context->disclogfile)
+ {
+ vfprintf(discrete_current_context->disclogfile, text, arg);
+ fprintf(discrete_current_context->disclogfile, "\n");
+ }
+
+ va_end(arg);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Included simulation objects
+ *
+ *************************************/
+
+#include "disc_wav.c" /* Wave sources - SINE/SQUARE/NOISE/etc */
+#include "disc_mth.c" /* Math Devices - ADD/GAIN/etc */
+#include "disc_inp.c" /* Input Devices - INPUT/CONST/etc */
+#include "disc_flt.c" /* Filter Devices - RCF/HPF/LPF */
+#include "disc_dev.c" /* Popular Devices - NE555/etc */
+
+
+
+/*************************************
+ *
+ * Master module list
+ *
+ *************************************/
+
+static discrete_module module_list[] =
+{
+ { DSO_OUTPUT ,"DSO_OUTPUT" ,0 ,NULL ,NULL },
+ { DSO_CSVLOG ,"DSO_CSVLOG" ,0 ,NULL ,NULL },
+ { DSO_WAVELOG ,"DSO_WAVELOG" ,0 ,NULL ,NULL },
+
+ /* from disc_inp.c */
+ { DSS_ADJUSTMENT ,"DSS_ADJUSTMENT" ,sizeof(struct dss_adjustment_context) ,dss_adjustment_reset ,dss_adjustment_step },
+ { DSS_CONSTANT ,"DSS_CONSTANT" ,0 ,NULL ,dss_constant_step },
+ { DSS_INPUT_DATA ,"DSS_INPUT_DATA" ,sizeof(UINT8) ,dss_input_reset ,dss_input_step },
+ { DSS_INPUT_LOGIC ,"DSS_INPUT_LOGIC" ,sizeof(UINT8) ,dss_input_reset ,dss_input_step },
+ { DSS_INPUT_NOT ,"DSS_INPUT_NOT" ,sizeof(UINT8) ,dss_input_reset ,dss_input_step },
+ { DSS_INPUT_PULSE ,"DSS_INPUT_PULSE" ,sizeof(UINT8) ,dss_input_reset ,dss_input_pulse_step },
+ { DSS_INPUT_STREAM,"DSS_INPUT_STREAM",0 ,NULL ,dss_input_stream_step},
+
+ /* from disc_wav.c */
+ /* Generic modules */
+ { DSS_COUNTER ,"DSS_COUNTER" ,sizeof(struct dss_counter_context) ,dss_counter_reset ,dss_counter_step },
+ { DSS_LFSR_NOISE ,"DSS_LFSR_NOISE" ,sizeof(struct dss_lfsr_context) ,dss_lfsr_reset ,dss_lfsr_step },
+ { DSS_NOISE ,"DSS_NOISE" ,sizeof(struct dss_noise_context) ,dss_noise_reset ,dss_noise_step },
+ { DSS_NOTE ,"DSS_NOTE" ,sizeof(struct dss_note_context) ,dss_note_reset ,dss_note_step },
+ { DSS_SAWTOOTHWAVE,"DSS_SAWTOOTHWAVE",sizeof(struct dss_sawtoothwave_context),dss_sawtoothwave_reset,dss_sawtoothwave_step},
+ { DSS_SINEWAVE ,"DSS_SINEWAVE" ,sizeof(struct dss_sinewave_context) ,dss_sinewave_reset ,dss_sinewave_step },
+ { DSS_SQUAREWAVE ,"DSS_SQUAREWAVE" ,sizeof(struct dss_squarewave_context) ,dss_squarewave_reset ,dss_squarewave_step },
+ { DSS_SQUAREWFIX ,"DSS_SQUAREWFIX" ,sizeof(struct dss_squarewfix_context) ,dss_squarewfix_reset ,dss_squarewfix_step },
+ { DSS_SQUAREWAVE2 ,"DSS_SQUAREWAVE2" ,sizeof(struct dss_squarewave_context) ,dss_squarewave2_reset ,dss_squarewave2_step },
+ { DSS_TRIANGLEWAVE,"DSS_TRIANGLEWAVE",sizeof(struct dss_trianglewave_context),dss_trianglewave_reset,dss_trianglewave_step},
+ /* Component specific modules */
+ { DSS_INVERTER_OSC ,"DSS_INVERTER_OSC" ,sizeof(struct dss_inverter_osc_context) ,dss_inverter_osc_reset ,dss_inverter_osc_step },
+ { DSS_OP_AMP_OSC ,"DSS_OP_AMP_OSC" ,sizeof(struct dss_op_amp_osc_context) ,dss_op_amp_osc_reset ,dss_op_amp_osc_step },
+ { DSS_SCHMITT_OSC ,"DSS_SCHMITT_OSC" ,sizeof(struct dss_schmitt_osc_context) ,dss_schmitt_osc_reset ,dss_schmitt_osc_step },
+ /* Not yet implemented */
+ { DSS_ADSR ,"DSS_ADSR" ,sizeof(struct dss_adsr_context) ,dss_adsrenv_reset ,dss_adsrenv_step },
+
+ /* from disc_mth.c */
+ /* Generic modules */
+ { DST_ADDER ,"DST_ADDER" ,0 ,NULL ,dst_adder_step },
+ { DST_CLAMP ,"DST_CLAMP" ,0 ,NULL ,dst_clamp_step },
+ { DST_DIVIDE ,"DST_DIVIDE" ,0 ,NULL ,dst_divide_step },
+ { DST_GAIN ,"DST_GAIN" ,0 ,NULL ,dst_gain_step },
+ { DST_LOGIC_INV ,"DST_LOGIC_INV" ,0 ,NULL ,dst_logic_inv_step },
+ { DST_LOGIC_AND ,"DST_LOGIC_AND" ,0 ,NULL ,dst_logic_and_step },
+ { DST_LOGIC_NAND ,"DST_LOGIC_NAND" ,0 ,NULL ,dst_logic_nand_step },
+ { DST_LOGIC_OR ,"DST_LOGIC_OR" ,0 ,NULL ,dst_logic_or_step },
+ { DST_LOGIC_NOR ,"DST_LOGIC_NOR" ,0 ,NULL ,dst_logic_nor_step },
+ { DST_LOGIC_XOR ,"DST_LOGIC_XOR" ,0 ,NULL ,dst_logic_xor_step },
+ { DST_LOGIC_NXOR ,"DST_LOGIC_NXOR" ,0 ,NULL ,dst_logic_nxor_step },
+ { DST_LOGIC_DFF ,"DST_LOGIC_DFF" ,sizeof(struct dst_flipflop_context) ,dst_logic_ff_reset ,dst_logic_dff_step },
+ { DST_LOGIC_JKFF ,"DST_LOGIC_JKFF" ,sizeof(struct dst_flipflop_context) ,dst_logic_ff_reset ,dst_logic_jkff_step },
+ { DST_LOOKUP_TABLE,"DST_LOOKUP_TABLE",0 ,NULL ,dst_lookup_table_step},
+ { DST_MULTIPLEX ,"DST_MULTIPLEX" ,sizeof(struct dst_size_context) ,dst_multiplex_reset ,dst_multiplex_step },
+ { DST_ONESHOT ,"DST_ONESHOT" ,sizeof(struct dst_oneshot_context) ,dst_oneshot_reset ,dst_oneshot_step },
+ { DST_RAMP ,"DST_RAMP" ,sizeof(struct dss_ramp_context) ,dst_ramp_reset ,dst_ramp_step },
+ { DST_SAMPHOLD ,"DST_SAMPHOLD" ,sizeof(struct dst_samphold_context) ,dst_samphold_reset ,dst_samphold_step },
+ { DST_SWITCH ,"DST_SWITCH" ,0 ,NULL ,dst_switch_step },
+ { DST_ASWITCH ,"DST_ASWITCH" ,0 ,NULL ,dst_aswitch_step },
+ { DST_TRANSFORM ,"DST_TRANSFORM" ,0 ,NULL ,dst_transform_step },
+ /* Component specific */
+ { DST_COMP_ADDER ,"DST_COMP_ADDER" ,0 ,NULL ,dst_comp_adder_step },
+ { DST_DAC_R1 ,"DST_DAC_R1" ,sizeof(struct dst_dac_r1_context) ,dst_dac_r1_reset ,dst_dac_r1_step },
+ { DST_DIODE_MIX ,"DST_DIODE_MIX" ,sizeof(struct dst_size_context) ,dst_diode_mix_reset ,dst_diode_mix_step },
+ { DST_INTEGRATE ,"DST_INTEGRATE" ,sizeof(struct dst_integrate_context) ,dst_integrate_reset ,dst_integrate_step },
+ { DST_MIXER ,"DST_MIXER" ,sizeof(struct dst_mixer_context) ,dst_mixer_reset ,dst_mixer_step },
+ { DST_OP_AMP ,"DST_OP_AMP" ,sizeof(struct dst_op_amp_context) ,dst_op_amp_reset ,dst_op_amp_step },
+ { DST_OP_AMP_1SHT ,"DST_OP_AMP_1SHT" ,sizeof(struct dst_op_amp_1sht_context) ,dst_op_amp_1sht_reset ,dst_op_amp_1sht_step },
+ { DST_TVCA_OP_AMP ,"DST_TVCA_OP_AMP" ,sizeof(struct dst_tvca_op_amp_context) ,dst_tvca_op_amp_reset ,dst_tvca_op_amp_step },
+ { DST_VCA ,"DST_VCA" ,0 ,NULL ,NULL },
+
+ /* from disc_flt.c */
+ /* Generic modules */
+ { DST_FILTER1 ,"DST_FILTER1" ,sizeof(struct dss_filter1_context) ,dst_filter1_reset ,dst_filter1_step },
+ { DST_FILTER2 ,"DST_FILTER2" ,sizeof(struct dss_filter2_context) ,dst_filter2_reset ,dst_filter2_step },
+ /* Component specific modules */
+ { DST_CRFILTER ,"DST_CRFILTER" ,sizeof(struct dst_rcfilter_context) ,dst_crfilter_reset ,dst_crfilter_step },
+ { DST_OP_AMP_FILT ,"DST_OP_AMP_FILT" ,sizeof(struct dst_op_amp_filt_context) ,dst_op_amp_filt_reset ,dst_op_amp_filt_step },
+ { DST_RCDISC ,"DST_RCDISC" ,sizeof(struct dst_rcdisc_context) ,dst_rcdisc_reset ,dst_rcdisc_step },
+ { DST_RCDISC2 ,"DST_RCDISC2" ,sizeof(struct dst_rcdisc_context) ,dst_rcdisc2_reset ,dst_rcdisc2_step },
+ { DST_RCDISC3 ,"DST_RCDISC3" ,sizeof(struct dst_rcdisc_context) ,dst_rcdisc3_reset ,dst_rcdisc3_step },
+ { DST_RCDISC4 ,"DST_RCDISC4" ,sizeof(struct dst_rcdisc4_context) ,dst_rcdisc4_reset ,dst_rcdisc4_step },
+ { DST_RCDISC5 ,"DST_RCDISC5" ,sizeof(struct dst_rcdisc_context) ,dst_rcdisc5_reset ,dst_rcdisc5_step },
+ { DST_RCINTEGRATE ,"DST_RCINTEGRATE" ,sizeof(struct dst_rcdisc_context) ,dst_rcintegrate_reset ,dst_rcintegrate_step },
+ { DST_RCDISC_MOD ,"DST_RCDISC_MOD" ,sizeof(struct dst_rcdisc_context) ,dst_rcdisc_mod_reset ,dst_rcdisc_mod_step },
+ { DST_RCFILTER ,"DST_RCFILTER" ,sizeof(struct dst_rcfilter_context) ,dst_rcfilter_reset ,dst_rcfilter_step },
+ /* For testing - seem to be buggered. Use versions not ending in N. */
+ { DST_RCFILTERN ,"DST_RCFILTERN" ,sizeof(struct dss_filter1_context) ,dst_rcfilterN_reset ,dst_filter1_step },
+ { DST_RCDISCN ,"DST_RCDISCN" ,sizeof(struct dss_filter1_context) ,dst_rcdiscN_reset ,dst_rcdiscN_step },
+ { DST_RCDISC2N ,"DST_RCDISC2N" ,sizeof(struct dss_rcdisc2_context) ,dst_rcdisc2N_reset ,dst_rcdisc2N_step },
+
+ /* from disc_dev.c */
+ /* generic modules */
+ { DST_CUSTOM ,"DST_CUSTOM" ,0 ,NULL ,NULL },
+ /* Component specific modules */
+ { DSD_555_ASTBL ,"DSD_555_ASTBL" ,sizeof(struct dsd_555_astbl_context) ,dsd_555_astbl_reset ,dsd_555_astbl_step },
+ { DSD_555_MSTBL ,"DSD_555_MSTBL" ,sizeof(struct dsd_555_mstbl_context) ,dsd_555_mstbl_reset ,dsd_555_mstbl_step },
+ { DSD_555_CC ,"DSD_555_CC" ,sizeof(struct dsd_555_cc_context) ,dsd_555_cc_reset ,dsd_555_cc_step },
+ { DSD_555_VCO1 ,"DSD_555_VCO1" ,sizeof(struct dsd_555_vco1_context) ,dsd_555_vco1_reset ,dsd_555_vco1_step },
+ { DSD_566 ,"DSD_566" ,sizeof(struct dsd_566_context) ,dsd_566_reset ,dsd_566_step },
+
+ /* must be the last one */
+ { DSS_NULL ,"DSS_NULL" ,0 ,NULL ,NULL }
+};
+
+
+
+/*************************************
+ *
+ * Find a given node
+ *
+ *************************************/
+
+node_description *discrete_find_node(void *chip, int node)
+{
+ discrete_info *info = chip ? chip : discrete_current_context;
+ if (node < NODE_START || node > NODE_END) return NULL;
+ return info->indexed_node[node - NODE_START];
+}
+
+
+
+/*************************************
+ *
+ * Master discrete system start
+ *
+ *************************************/
+
+static void *discrete_start(int sndindex, int clock, const void *config)
+{
+ discrete_sound_block *intf = (discrete_sound_block *)config;
+ discrete_info *info;
+ char name[32];
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->sndindex = sndindex;
+
+ /* If a clock is specified we will use it, otherwise run at the audio sample rate. */
+ if (clock)
+ info->sample_rate = clock;
+ else
+ info->sample_rate = Machine->sample_rate;
+ info->sample_time = 1.0 / info->sample_rate;
+
+ /* create the logfile */
+ sprintf(name, "discrete%d.log", info->sndindex);
+ if (DISCRETE_DEBUGLOG && !discrete_current_context->disclogfile)
+ discrete_current_context->disclogfile = fopen(name, "w");
+
+ /* first pass through the nodes: sanity check, fill in the indexed_nodes, and make a total count */
+ discrete_log("discrete_start() - Doing node list sanity check");
+ for (info->node_count = 0; intf[info->node_count].type != DSS_NULL; info->node_count++)
+ {
+ /* make sure we don't have too many nodes overall */
+ if (info->node_count > DISCRETE_MAX_NODES)
+ fatalerror("discrete_start() - Upper limit of %d nodes exceeded, have you terminated the interface block?", DISCRETE_MAX_NODES);
+
+ /* make sure the node number is in range */
+ if (intf[info->node_count].node < NODE_START || intf[info->node_count].node > NODE_END)
+ fatalerror("discrete_start() - Invalid node number on node %02d descriptor", info->node_count);
+
+ /* make sure the node type is valid */
+ if (intf[info->node_count].type > DSO_OUTPUT)
+ fatalerror("discrete_start() - Invalid function type on NODE_%02d", intf[info->node_count].node - NODE_START);
+ }
+ info->node_count++;
+ discrete_log("discrete_start() - Sanity check counted %d nodes", info->node_count);
+
+ /* allocate memory for the array of actual nodes */
+ info->node_list = auto_malloc(info->node_count * sizeof(info->node_list[0]));
+ memset(info->node_list, 0, info->node_count * sizeof(info->node_list[0]));
+
+ /* allocate memory for the node execution order array */
+ info->running_order = auto_malloc(info->node_count * sizeof(info->running_order[0]));
+ memset(info->running_order, 0, info->node_count * sizeof(info->running_order[0]));
+
+ /* allocate memory to hold pointers to nodes by index */
+ info->indexed_node = auto_malloc(DISCRETE_MAX_NODES * sizeof(info->indexed_node[0]));
+ memset(info->indexed_node, 0, DISCRETE_MAX_NODES * sizeof(info->indexed_node[0]));
+
+ /* initialize the node data */
+ init_nodes(info, intf);
+
+ /* now go back and find pointers to all input nodes */
+ find_input_nodes(info, intf);
+
+ /* then set up the output nodes */
+ setup_output_nodes(info);
+
+ setup_disc_logs(info);
+
+ /* reset the system, which in turn resets all the nodes and steps them forward one */
+ discrete_reset(info);
+ return info;
+}
+
+
+
+/*************************************
+ *
+ * Master discrete system stop
+ *
+ *************************************/
+
+static void discrete_stop(void *chip)
+{
+ discrete_info *info = chip;
+ int log_num;
+
+ /* close any csv files */
+ for (log_num = 0; log_num < info->num_csvlogs; log_num++)
+ if (info->disc_csv_file[log_num])
+ fclose(info->disc_csv_file[log_num]);
+
+ /* close any wave files */
+ for (log_num = 0; log_num < info->num_wavelogs; log_num++)
+ if (info->disc_wav_file[log_num])
+ wav_close(info->disc_wav_file[log_num]);
+
+ if (DISCRETE_DEBUGLOG)
+ {
+ /* close the debug log */
+ if (discrete_current_context->disclogfile)
+ fclose(discrete_current_context->disclogfile);
+ discrete_current_context->disclogfile = NULL;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Master reset of all nodes
+ *
+ *************************************/
+
+static void discrete_reset(void *chip)
+{
+ discrete_info *info = chip;
+ int nodenum;
+
+ discrete_current_context = info;
+
+ /* loop over all nodes */
+ for (nodenum = 0; nodenum < info->node_count; nodenum++)
+ {
+ node_description *node = info->running_order[nodenum];
+
+ node->output = 0;
+
+ /* if the node has a reset function, call it */
+ if (node->module.reset)
+ (*node->module.reset)(node);
+
+ /* otherwise, just step it */
+ else if (node->module.step)
+ (*node->module.step)(node);
+ }
+
+ discrete_current_context = NULL;
+}
+
+
+
+/*************************************
+ *
+ * Stream update functions
+ *
+ *************************************/
+
+static void discrete_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ discrete_info *info = param;
+ int samplenum, nodenum, outputnum;
+ double val;
+ INT16 wave_data_l, wave_data_r;
+
+ discrete_current_context = info;
+
+ /* Setup any input streams */
+ for (nodenum = 0; nodenum < info->discrete_input_streams; nodenum++)
+ {
+ *info->input_stream_data[nodenum] = inputs[nodenum];
+ }
+
+ /* Now we must do length iterations of the node list, one output for each step */
+ for (samplenum = 0; samplenum < length; samplenum++)
+ {
+ /* loop over all nodes */
+ for (nodenum = 0; nodenum < info->node_count; nodenum++)
+ {
+ node_description *node = info->running_order[nodenum];
+
+ /* Now step the node */
+ if (node->module.step)
+ (*node->module.step)(node);
+ }
+
+ /* Add gain to the output and put into the buffers */
+ /* Clipping will be handled by the main sound system */
+ for (outputnum = 0; outputnum < info->discrete_outputs; outputnum++)
+ {
+ val = (*info->output_node[outputnum]->input[0]) * (*info->output_node[outputnum]->input[1]);
+ buffer[outputnum][samplenum] = val;
+ }
+
+ /* Dump any csv logs */
+ for (outputnum = 0; outputnum < info->num_csvlogs; outputnum++)
+ {
+ fprintf(info->disc_csv_file[outputnum], "%lld", ++info->sample_num);
+ for (nodenum = 0; nodenum < info->csvlog_node[outputnum]->active_inputs; nodenum++)
+ {
+ fprintf(info->disc_csv_file[outputnum], ", %f", *info->csvlog_node[outputnum]->input[nodenum]);
+ }
+ fprintf(info->disc_csv_file[outputnum], "\n");
+ }
+
+ /* Dump any wave logs */
+ for (outputnum = 0; outputnum < info->num_wavelogs; outputnum++)
+ {
+ /* get nodes to be logged and apply gain, then clip to 16 bit */
+ val = (*info->wavelog_node[outputnum]->input[0]) * (*info->wavelog_node[outputnum]->input[1]);
+ val = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val;
+ wave_data_l = (INT16)val;
+ if (info->wavelog_node[outputnum]->active_inputs == 2)
+ {
+ /* DISCRETE_WAVELOG1 */
+ wav_add_data_16(info->disc_wav_file[outputnum], &wave_data_l, 1);
+ }
+ else
+ {
+ /* DISCRETE_WAVELOG2 */
+ val = (*info->wavelog_node[outputnum]->input[2]) * (*info->wavelog_node[outputnum]->input[3]);
+ val = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val;
+ wave_data_r = (INT16)val;
+
+ wav_add_data_16lr(info->disc_wav_file[outputnum], &wave_data_l, &wave_data_r, 1);
+ }
+ }
+ }
+
+ discrete_current_context = NULL;
+}
+
+
+
+/*************************************
+ *
+ * First pass init of nodes
+ *
+ *************************************/
+
+static void init_nodes(discrete_info *info, discrete_sound_block *block_list)
+{
+ int nodenum;
+
+ /* start with no outputs or input streams */
+ info->discrete_outputs = 0;
+ info->discrete_input_streams = 0;
+
+ /* loop over all nodes */
+ for (nodenum = 0; nodenum < info->node_count; nodenum++)
+ {
+ discrete_sound_block *block = &block_list[nodenum];
+ node_description *node = &info->node_list[nodenum];
+ int inputnum, modulenum;
+
+ /* our running order just follows the order specified */
+ info->running_order[nodenum] = node;
+
+ /* keep track of special nodes */
+ if (block->node == NODE_SPECIAL)
+ {
+ switch(block->type)
+ {
+ /* Output Node */
+ case DSO_OUTPUT:
+ if (info->discrete_outputs == DISCRETE_MAX_OUTPUTS)
+ fatalerror("init_nodes() - There can not be more then %d output nodes", DISCRETE_MAX_OUTPUTS);
+ info->output_node[info->discrete_outputs++] = node;
+ break;
+
+ /* CSVlog Node for debugging */
+ case DSO_CSVLOG:
+ if (info->num_csvlogs == DISCRETE_MAX_CSVLOGS)
+ fatalerror("init_nodes() - There can not be more then %d discrete CSV logs.", DISCRETE_MAX_WAVELOGS);
+ info->csvlog_node[info->num_csvlogs++] = node;
+ break;
+
+ /* Wavelog Node for debugging */
+ case DSO_WAVELOG:
+ if (info->num_wavelogs == DISCRETE_MAX_WAVELOGS)
+ fatalerror("init_nodes() - There can not be more then %d discrete wave logs.", DISCRETE_MAX_WAVELOGS);
+ info->wavelog_node[info->num_wavelogs++] = node;
+ break;
+
+ default:
+ fatalerror("init_nodes() - Failed, trying to create unknown special discrete node.");
+ }
+ }
+
+ /* otherwise, make sure we are not a duplicate, and put ourselves into the indexed list */
+ else
+ {
+ if (info->indexed_node[block->node - NODE_START])
+ fatalerror("init_nodes() - Duplicate entries for NODE_%02d", block->node - NODE_START);
+ info->indexed_node[block->node - NODE_START] = node;
+ }
+
+ /* find the requested module */
+ for (modulenum = 0; module_list[modulenum].type != DSS_NULL; modulenum++)
+ if (module_list[modulenum].type == block->type)
+ break;
+ if (module_list[modulenum].type != block->type)
+ fatalerror("init_nodes() - Unable to find discrete module type %d for NODE_%02d", block->type, block->node - NODE_START);
+
+ /* static inits */
+ node->node = block->node;
+ node->module = module_list[modulenum];
+ node->output = 0.0;
+ node->block = block;
+
+ node->active_inputs = block->active_inputs;
+ for (inputnum = 0; inputnum < DISCRETE_MAX_INPUTS; inputnum++)
+ {
+ node->input[inputnum] = &(block->initial[inputnum]);
+ }
+
+ node->context = NULL;
+ node->name = block->name;
+ node->custom = block->custom;
+
+ /* setup module if custom */
+ if (block->type == DST_CUSTOM)
+ {
+ const discrete_custom_info *custom = node->custom;
+ node->module.reset = custom->reset;
+ node->module.step = custom->step;
+ node->module.contextsize = custom->contextsize;
+ node->custom = custom->custom;
+ }
+
+ /* allocate memory if necessary */
+ if (node->module.contextsize)
+ {
+ node->context = auto_malloc(node->module.contextsize);
+ memset(node->context, 0, node->module.contextsize);
+ }
+
+ /* if we are an stream input node, track that */
+ if (block->type == DSS_INPUT_STREAM)
+ {
+ if (info->discrete_input_streams == DISCRETE_MAX_OUTPUTS)
+ fatalerror("init_nodes() - There can not be more then %d input stream nodes", DISCRETE_MAX_OUTPUTS);
+ /* we will use the node's context pointer to point to the input stream data */
+ *info->input_stream_data[info->discrete_input_streams++] = (stream_sample_t *)&node->context;
+ }
+ }
+
+ /* if no outputs, give an error */
+ if (info->discrete_outputs == 0)
+ fatalerror("init_nodes() - Couldn't find an output node");
+}
+
+
+
+/*************************************
+ *
+ * Find and attach all input nodes
+ *
+ *************************************/
+
+static void find_input_nodes(discrete_info *info, discrete_sound_block *block_list)
+{
+ int nodenum, inputnum;
+
+ /* loop over all nodes */
+ for (nodenum = 0; nodenum < info->node_count; nodenum++)
+ {
+ node_description *node = &info->node_list[nodenum];
+ discrete_sound_block *block = &block_list[nodenum];
+
+ /* loop over all active inputs */
+ for (inputnum = 0; inputnum < node->active_inputs; inputnum++)
+ {
+ int inputnode = block->input_node[inputnum];
+
+ /* if this input is node-based, find the node in the indexed list */
+ if IS_VALUE_A_NODE(inputnode)
+ {
+ node_description *node_ref = info->indexed_node[inputnode - NODE_START];
+ if (!node_ref)
+ fatalerror("discrete_start - Node NODE_%02d referenced a non existent node NODE_%02d", node->node - NODE_START, inputnode - NODE_START);
+
+ node->input[inputnum] = &(node_ref->output); // Link referenced node out to input
+ node->input_is_node |= 1 << inputnum; // Bit flag if input is node
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Set up the output nodes
+ *
+ *************************************/
+
+static void setup_output_nodes(discrete_info *info)
+{
+ /* initialize the stream(s) */
+ info->discrete_stream = stream_create(info->discrete_input_streams, info->discrete_outputs, info->sample_rate, info, discrete_stream_update);
+}
+
+
+
+/*************************************
+ *
+ * Set up the logs
+ *
+ *************************************/
+
+static void setup_disc_logs(discrete_info *info)
+{
+ int log_num, node_num;
+ char name[32];
+
+ for (log_num = 0; log_num < info->num_csvlogs; log_num++)
+ {
+ sprintf(name, "discrete%d_%d.csv", info->sndindex, log_num);
+ info->disc_csv_file[log_num] = fopen(name, "w");
+ /* Output some header info */
+ fprintf(info->disc_csv_file[log_num], "\"MAME Discrete System Node Log\"\n");
+ fprintf(info->disc_csv_file[log_num], "\"Log Version\", 1.0\n");
+ fprintf(info->disc_csv_file[log_num], "\"Sample Rate\", %d\n", info->sample_rate);
+ fprintf(info->disc_csv_file[log_num], "\n");
+ fprintf(info->disc_csv_file[log_num], "\"Sample\"");
+ for (node_num = 0; node_num < info->csvlog_node[log_num]->active_inputs; node_num++)
+ {
+ fprintf(info->disc_csv_file[log_num], ", \"NODE_%2d\"", info->csvlog_node[log_num]->block->input_node[node_num] - NODE_START);
+ }
+ fprintf(info->disc_csv_file[log_num], "\n");
+ }
+
+ for (log_num = 0; log_num < info->num_wavelogs; log_num++)
+ {
+ sprintf(name, "discrete%d_%d.wav", info->sndindex, log_num);
+ info->disc_wav_file[log_num] = wav_open(name, info->sample_rate, info->wavelog_node[log_num]->active_inputs/2);
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void discrete_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void discrete_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = discrete_set_info; break;
+ case SNDINFO_PTR_START: info->start = discrete_start; break;
+ case SNDINFO_PTR_STOP: info->stop = discrete_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = discrete_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Discrete"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Analog"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/discrete.h b/src/emu/sound/discrete.h
new file mode 100644
index 00000000000..96661a2a04f
--- /dev/null
+++ b/src/emu/sound/discrete.h
@@ -0,0 +1,3930 @@
+#ifndef _discrete_h_
+#define _discrete_h_
+
+#include "rescap.h"
+
+/***********************************************************************
+ *
+ * MAME - Discrete sound system emulation library
+ *
+ * Written by Keith Wilkins (mame@esplexo.co.uk)
+ *
+ * (c) K.Wilkins 2000
+ *
+ * Coding started in November 2000
+ *
+ * Additions/bugfix February 2003 - D.Renaud, F.Palazzolo, K.Wilkins
+ *
+ ***********************************************************************
+ *
+ * For good free text books on electronic theory check out:
+ * http://www.ibiblio.org/obp/electricCircuits/
+ *
+ ***********************************************************************
+ *
+ * Currently only one instance of a discrete sound system is supported.
+ * If more then one instance is required in the future, then a chip #
+ * will have to be added to the read/writes and the discrete inputs
+ * modified to match. This functionality should never be needed.
+ * There is no real need to run more then 1 discrete system.
+ *
+ * If a clock is specified in the machine driver setup, then this is
+ * used for the simulation sample rate. Otherwise it will default to
+ * run at the audio sample rate.
+ *
+ * Unused/Unconnected input nodes should be set to NODE_NC (No Connect)
+ *
+ * Each node can have many inputs from either constants or other
+ * nodes within the system.
+ *
+ * It should be remembered that the discrete sound system emulation
+ * does not do individual device emulation, but instead does a function
+ * emulation. So you will need to convert the schematic design into
+ * a logic block representation.
+ *
+ * One node point may feed a number of inputs, for example you could
+ * connect the output of a DISCRETE_SINEWAVE to the AMPLITUDE input
+ * of another DISCRETE_SINEWAVE to amplitude modulate its output and
+ * also connect it to the frequecy input of another to frequency
+ * modulate its output, the combinations are endless....
+ *
+ * Consider the circuit below:
+ *
+ * .--------. .----------. .-------.
+ * | | | | | |
+ * | SQUARE | Enable| SINEWAVE | | |
+ * | WAVE |-+---------->| 2000Hz |---------------->| |
+ * | | | | | | ADDER |-->OUT
+ * | NODE11 | | | NODE12 | | |
+ * '--------' | '----------' .->| |
+ * | | |NODE20 |
+ * | .------. .---------. | '-------'
+ * | |Logic | | | | ^
+ * | | INV | Enable | SINEWVE | | |
+ * '->| ERT |------------->| 4000Hz |--' .-------.
+ * | | | | | |
+ * |NODE13| | NODE14 | | INPUT |
+ * '------' '---------' | |
+ * |NODE01 |
+ * '-------'
+ *
+ * This should give you an alternating two tone sound switching
+ * between the 2000Hz and 4000Hz sine waves at the frequency of the
+ * square wave, with the memory mapped enable signal mapped onto NODE07
+ * so discrete_sound_w(NODE_01,1) will enable the sound, and
+ * discrete_sound_w(NODE_01,0) will disable the sound.
+ *
+ * DISCRETE_SOUND_START(test_interface)
+ * DISCRETE_INPUT_LOGIC(NODE_01)
+ * DISCRETE_SQUAREWFIX(NODE_11, 1, 0.5, 1, 50, 1.0/2, 0) // Output 0:1
+ * DISCRETE_SINEWAVE(NODE_12, NODE_11, 2000, 10000, 0, 0)
+ * DISCRETE_LOGIC_INVERT(NODE_13, 1, NODE_11)
+ * DISCRETE_SINEWAVE(NODE_14, NODE_13, 4000, 10000, 0, 0)
+ * DISCRETE_ADDER2(NODE_20, NODE_01, NODE_12, NODE_14)
+ * DISCRETE_OUTPUT(NODE_20, 1)
+ * DISCRETE_SOUND_END
+ *
+ * To aid simulation speed it is preferable to use the enable/disable
+ * inputs to a block rather than setting the output amplitude to zero
+ *
+ * Feedback loops are allowed BUT they will always feeback one time
+ * step later, the loop over the netlist is only performed once per
+ * deltaT so feedback occurs in the next deltaT step. This is not
+ * the perfect solution but saves repeatedly traversing the netlist
+ * until all nodes have settled.
+ *
+ * The best way to work out your system is generally to use a pen and
+ * paper to draw a logical block diagram like the one above, it helps
+ * to understand the system ,map the inputs and outputs and to work
+ * out your node numbering scheme.
+ *
+ * Node numbers NODE_01 to NODE_299 are defined at present.
+ *
+ * It is recomended to put all Inputs at the start of the interface.
+ * That way they are updated first.
+ *
+ * Each sound effects final node should come after all nodes that
+ * create it. The final mixing of all sound effects should come
+ * at the end of the interface.
+ *
+ ***********************************************************************
+ *
+ * LIST OF CURRENTLY IMPLEMENTED DISCRETE BLOCKS
+ * ---------------------------------------------
+ *
+ * DISCRETE_SOUND_START(STRUCTURENAME)
+ * DISCRETE_SOUND_END
+ *
+ * DISCRETE_ADJUSTMENT(NODE,ENAB,MIN,MAX,LOGLIN,PORT)
+ * DISCRETE_ADJUSTMENT_TAG(NODE,ENAB,MIN,MAX,LOGLIN,TAG)
+ * DISCRETE_ADJUSTMENTX(NODE,ENAB,MIN,MAX,LOGLIN,PORT,PMIN,PMAX)
+ * DISCRETE_CONSTANT(NODE,CONST0)
+ * DISCRETE_INPUT_DATA(NODE)
+ * DISCRETE_INPUTX_DATA(NODE,GAIN,OFFSET,INIT)
+ * DISCRETE_INPUT_LOGIC(NODE)
+ * DISCRETE_INPUTX_LOGIC(NODE,GAIN,OFFSET,INIT)
+ * DISCRETE_INPUT_NOT(NODE)
+ * DISCRETE_INPUTX_NOT(NODE,GAIN,OFFSET,INIT)
+ * DISCRETE_INPUT_PULSE(NODE,INIT)
+ * DISCRETE_INPUT_STREAM(NODE)
+ * DISCRETE_INPUTX_STREAM(NODE,GAIN,OFFSET)
+ *
+ * DISCRETE_COUNTER(NODE,ENAB,RESET,CLK,MAX,DIR,INIT0,CLKTYPE)
+ * DISCRETE_COUNTER_7492(NODE,ENAB,RESET,CLK)
+ * DISCRETE_LFSR_NOISE(NODE,ENAB,RESET,CLK,AMPL,FEED,BIAS,LFSRTB)
+ * DISCRETE_NOISE(NODE,ENAB,FREQ,AMP,BIAS)
+ * DISCRETE_NOTE(NODE,ENAB,CLK,DATA,MAX1,MAX2,CLKTYPE)
+ * DISCRETE_SAWTOOTHWAVE(NODE,ENAB,FREQ,AMP,BIAS,GRADIENT,PHASE)
+ * DISCRETE_SINEWAVE(NODE,ENAB,FREQ,AMP,BIAS,PHASE)
+ * DISCRETE_SQUAREWAVE(NODE,ENAB,FREQ,AMP,DUTY,BIAS,PHASE)
+ * DISCRETE_SQUAREWFIX(NODE,ENAB,FREQ,AMP,DUTY,BIAS,PHASE)
+ * DISCRETE_SQUAREWAVE2(NODE,ENAB,AMPL,T_OFF,T_ON,BIAS,TSHIFT)
+ * DISCRETE_TRIANGLEWAVE(NODE,ENAB,FREQ,AMP,BIAS,PHASE)
+ *
+ * DISCRETE_OP_AMP_OSCILLATOR(NODE,ENAB,INFO)
+ * DISCRETE_OP_AMP_VCO1(NODE,ENAB,VMOD1,INFO)
+ * DISCRETE_OP_AMP_VCO2(NODE,ENAB,VMOD1,VMOD2,INFO)
+ * DISCRETE_SCHMITT_OSCILLATOR(NODE,ENAB,INP0,AMPL,TABLE)
+ *
+ * DISCRETE_ADDER2(NODE,ENAB,IN0,IN1)
+ * DISCRETE_ADDER3(NODE,ENAB,IN0,IN1,IN2)
+ * DISCRETE_ADDER4(NODE,ENAB,IN0,IN1,IN2,IN3)
+ * DISCRETE_CLAMP(NODE,ENAB,IN0,MIN,MAX,CLAMP)
+ * DISCRETE_DIVIDE(NODE,ENAB,IN0,IN1)
+ * DISCRETE_GAIN(NODE,IN0,GAIN)
+ * DISCRETE_INVERT(NODE,IN0)
+ * DISCRETE_LOOKUP_TABLE(NODE,ENAB,ADDR,SIZE,TABLE)
+ * DISCRETE_MULTIPLY(NODE,ENAB,IN0,IN1)
+ * DISCRETE_MULTADD(NODE,ENAB,INP0,INP1,INP2)
+ * DISCRETE_ONESHOT(NODE,TRIG,AMPL,WIDTH,TYPE)
+ * DISCRETE_ONESHOTR(NODE,RESET,TRIG,AMPL,WIDTH,TYPE)
+ * DISCRETE_ONOFF(NODE,ENAB,INP0)
+ * DISCRETE_RAMP(NODE,ENAB,RAMP,GRAD,MIN,MAX,CLAMP)
+ * DISCRETE_SAMPLHOLD(NODE,ENAB,INP0,CLOCK,CLKTYPE)
+ * DISCRETE_SWITCH(NODE,ENAB,SWITCH,INP0,INP1)
+ * DISCRETE_TRANSFORM2(NODE,ENAB,INP0,INP1,FUNCT)
+ * DISCRETE_TRANSFORM3(NODE,ENAB,INP0,INP1,INP2,FUNCT)
+ * DISCRETE_TRANSFORM4(NODE,ENAB,INP0,INP1,INP2,INP3,FUNCT)
+ * DISCRETE_TRANSFORM5(NODE,ENAB,INP0,INP1,INP2,INP3,INP4,FUNCT)
+ *
+ * DISCRETE_COMP_ADDER(NODE,ENAB,DATA,TABLE)
+ * DISCRETE_DAC_R1(NODE,ENAB,DATA,VDATA,LADDER)
+ * DISCRETE_DIODE_MIXER2(NODE,ENAB,VJUNC,IN0,IN1)
+ * DISCRETE_DIODE_MIXER3(NODE,ENAB,VJUNC,IN0,IN1,IN2)
+ * DISCRETE_DIODE_MIXER4(NODE,ENAB,VJUNC,IN0,IN1,IN2,IN3)
+ * DISCRETE_INTEGRATE(NODE,TRG0,TRG1,INFO)
+ * DISCRETE_MIXER2(NODE,ENAB,IN0,IN1,INFO)
+ * DISCRETE_MIXER3(NODE,ENAB,IN0,IN1,IN2,INFO)
+ * DISCRETE_MIXER4(NODE,ENAB,IN0,IN1,IN2,IN3,INFO)
+ * DISCRETE_MIXER5(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,INFO)
+ * DISCRETE_MIXER6(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,INFO)
+ * DISCRETE_MIXER7(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,INFO)
+ * DISCRETE_MIXER8(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,INFO)
+ * DISCRETE_OP_AMP(NODE,ENAB,IN0,IN1,INFO)
+ * DISCRETE_OP_AMP_ONESHOT(NODE,TRIG,INFO)
+ * DISCRETE_OP_AMP_TRIG_VCA(NODE,TRG0,TRG1,TRG2,IN0,IN1,INFO)
+ *
+ * DISCRETE_LOGIC_INVERT(NODE,ENAB,INP0)
+ * DISCRETE_LOGIC_AND(NODE,ENAB,INP0,INP1)
+ * DISCRETE_LOGIC_AND3(NODE,ENAB,INP0,INP1,INP2)
+ * DISCRETE_LOGIC_AND4(NODE,ENAB,INP0,INP1,INP2,INP3)
+ * DISCRETE_LOGIC_NAND(NODE,ENAB,INP0,INP1)
+ * DISCRETE_LOGIC_NAND3(NODE,ENAB,INP0,INP1,INP2)
+ * DISCRETE_LOGIC_NAND4(NODE,ENAB,INP0,INP1,INP2,INP3)
+ * DISCRETE_LOGIC_OR(NODE,ENAB,INP0,INP1)
+ * DISCRETE_LOGIC_OR3(NODE,ENAB,INP0,INP1,INP2)
+ * DISCRETE_LOGIC_OR4(NODE,ENAB,INP0,INP1,INP2,INP3)
+ * DISCRETE_LOGIC_NOR(NODE,ENAB,INP0,INP1)
+ * DISCRETE_LOGIC_NOR3(NODE,ENAB,INP0,INP1,INP2)
+ * DISCRETE_LOGIC_NOR4(NODE,ENAB,INP0,INP1,INP2,INP3)
+ * DISCRETE_LOGIC_XOR(NODE,ENAB,INP0,INP1)
+ * DISCRETE_LOGIC_NXOR(NODE,ENAB,INP0,INP1)
+ * DISCRETE_LOGIC_DFLIPFLOP(NODE,ENAB,RESET,SET,CLK,INP)
+ * DISCRETE_LOGIC_JKFLIPFLOP(NODE,ENAB,RESET,SET,CLK,J,K)
+ * DISCRETE_MULTIPLEX2(NODE,ENAB,ADDR,INP0,INP1)
+ * DISCRETE_MULTIPLEX4(NODE,ENAB,ADDR,INP0,INP1,INP2,INP3)
+ * DISCRETE_MULTIPLEX8(NODE,ENAB,ADDR,INP0,INP1,INP2,INP3,INP4,INP5,INP6,INP7)
+ *
+ * DISCRETE_FILTER1(NODE,ENAB,INP0,FREQ,TYPE)
+ * DISCRETE_FILTER2(NODE,ENAB,INP0,FREQ,DAMP,TYPE)
+ *
+ * DISCRETE_CRFILTER(NODE,ENAB,IN0,RVAL,CVAL)
+ * DISCRETE_CRFILTER_VREF(NODE,ENAB,IN0,RVAL,CVAL,VREF)
+ * DISCRETE_OP_AMP_FILTER(NODE,ENAB,INP0,INP1,TYPE,INFO)
+ * DISCRETE_RCDISC(NODE,ENAB,IN0,RVAL,CVAL)
+ * DISCRETE_RCDISC2(NODE,SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL)
+ * DISCRETE_RCDISC3(NODE,ENAB,INP0,RVAL0,RVAL1,CVAL)
+ * DISCRETE_RCDISC4(NODE,ENAB,INP0,RVAL0,RVAL1,RVAL2,CVAL,VP,TYPE)
+ * DISCRETE_RCDISC5(NODE,ENAB,IN0,RVAL,CVAL)
+ * DISCRETE_RCINTEGRATE(NODE,ENAB,IN0,IN1,RVAL0,RVAL1,CVAL)
+ * DISCRETE_RCFILTER(NODE,ENAB,IN0,RVAL,CVAL)
+ * DISCRETE_RCFILTER_VREF(NODE,ENAB,IN0,RVAL,CVAL,VREF)
+ *
+ * DISCRETE_555_ASTABLE(NODE,RESET,R1,R2,C,OPTIONS)
+ * DISCRETE_555_ASTABLE_CV(NODE,RESET,R1,R2,C,CTRLV,OPTIONS)
+ * DISCRETE_555_MSTABLE(NODE,RESET,TRIG,R,C,OPTIONS)
+ * DISCRETE_555_CC(NODE,RESET,VIN,R,C,RBIAS,RGND,RDIS,OPTIONS)
+ * DISCRETE_555_VCO1(NODE,RESET,VIN,OPTIONS)
+ * DISCRETE_555_VCO1_CV(NODE,RESET,VIN,CTRLV,OPTIONS)
+ * DISCRETE_566(NODE,ENAB,VMOD,R,C,OPTIONS)
+ *
+ * DISCRETE_CUSTOM1(NODE,ENAB,IN0,INFO)
+ * DISCRETE_CUSTOM2(NODE,ENAB,IN0,IN1,INFO)
+ * DISCRETE_CUSTOM3(NODE,ENAB,IN0,IN1,IN2,INFO)
+ * DISCRETE_CUSTOM4(NODE,ENAB,IN0,IN1,IN2,IN3,INFO)
+ * DISCRETE_CUSTOM5(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,INFO)
+ *
+ * DISCRETE_CSVLOG1(NODE1)
+ * DISCRETE_CSVLOG2(NODE1,NODE2)
+ * DISCRETE_CSVLOG3(NODE1,NODE2,NODE3)
+ * DISCRETE_CSVLOG4(NODE1,NODE2,NODE3,NODE4)
+ * DISCRETE_CSVLOG5(NODE1,NODE2,NODE3,NODE4,NODE5)
+ * DISCRETE_WAVELOG1(NODE1,GAIN1)
+ * DISCRETE_WAVELOG2(NODE1,GAIN1,NODE2,GAIN2)
+ * DISCRETE_OUTPUT(OPNODE,GAIN)
+ *
+ ***********************************************************************
+ =======================================================================
+ * from from disc_inp.c
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_ADJUSTMENT - Adjustable constant set by the UI [~] menu.
+ * DISCRETE_ADJUSTMENT_TAG - Same as above but referenced by a tag.
+ *
+ * Note: DISCRETE_ADJUSTMENT_TAG is prefered over DISCRETE_ADJUSTMENT.
+ *
+ * .----------.
+ * | |
+ * | ADJUST.. |--------> Netlist node
+ * | |
+ * '----------'
+ * Declaration syntax
+ *
+ * DISCRETE_ADJUSTMENT(name of node,
+ * enable node or static value,
+ * static minimum value the node can take,
+ * static maximum value the node can take,
+ * log/linear scale 0=Linear !0=Logarithmic,
+ * input port number of the adjuster)
+ *
+ * DISCRETE_ADJUSTMENT_TAG(name of node,
+ * enable node or static value,
+ * static minimum value the node can take,
+ * static maximum value the node can take,
+ * log/linear scale 0=Linear !0=Logarithmic,
+ * port tag name of the adjuster)
+ *
+ * Note: When using DISC_LOGADJ, the min/max values must be > 0.
+ * If they are <=0, they will be forced to 1.
+ * Min can be a higher value then max.
+ * Min/max is just how the slider is displayed.
+ *
+ * Example config line
+ *
+ * DISCRETE_ADJUSTMENT(NODE_01,1,0.0,5.0,DISC_LINADJ,0,5)
+ *
+ * Define an adjustment slider that takes a 0-100 input from input
+ * port #5, scaling between 0.0 and 5.0. Adjustment scaling is Linear.
+ *
+ * DISC_LOGADJ 1.0
+ * DISC_LINADJ 0.0
+ *
+ * EXAMPLES: see Hit Me, Fire Truck
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_CONSTANT - Single output, fixed at compile time.
+ * This is usefull as a placeholder for
+ * incomplete circuits.
+ *
+ * .----------.
+ * | |
+ * | CONSTANT |--------> Netlist node
+ * | |
+ * '----------'
+ * Declaration syntax
+ *
+ * DISCRETE_CONSTANT(name of node, constant value)
+ *
+ * Example config line
+ *
+ * DISCRETE_CONSTANT(NODE_01, 100)
+ *
+ * Define a node that has a constant value of 100
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_INPUT_DATA - accepts 8-bit data. Value at reset is 0.
+ * DISCRETE_INPUT_LOGIC - 0 if data=0; 1 if data=1. Value at reset is 0.
+ * DISCRETE_INPUT_NOT - 0 if data=1; 1 if data=0. Value at reset is 1.
+ *
+ * DISCRETE_INPUTX_xx - same as above, but will modify the value by the
+ * given GAIN and OFFSET. At reset the value will
+ * be INIT modified by GAIN and OFFSET.
+ *
+ * DISCRETE_INPUT_PULSE - Same as normal input node but the netlist
+ * node output returns to INIT after a single
+ * cycle of sound output. To allow for scenarios
+ * whereby the register write pulse is used as
+ * a reset to a system.
+ *
+ * .----------.
+ * -----\| |
+ * discrete_sound_w data | INPUT(A) |----> Netlist node
+ * Write -----/| |
+ * '----------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_INPUT_DATA (name of node)
+ * DISCRETE_INPUT_LOGIC (name of node)
+ * DISCRETE_INPUT_NOT (name of node)
+ * DISCRETE_INPUTX_DATA (name of node, gain, offset, initial value)
+ * DISCRETE_INPUTX_LOGIC(name of node, gain, offset, initial value)
+ * DISCRETE_INPUTX_NOT (name of node, gain, offset, initial value)
+ * DISCRETE_INPUT_PULSE (name of node, default value)
+ *
+ * Can be written to with: discrete_sound_w(NODE_xx, data);
+ *
+ ***********************************************************************
+ *
+ * !!!!! NOT WORKING YET !!!!!
+ *
+ * DISCRETE_INPUT_STREAM(NODE) - Accepts a stream input
+ * DISCRETE_INPUTX_STREAM(NODE,GAIN,OFFSET) - Accepts a stream input and
+ * applies a gain and offset.
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_INPUT_STREAM (name of node)
+ * DISCRETE_INPUTX_STREAM(name of node, gain, offset)
+ *
+ * Note: These inputs must be defined in the same order that the sound routes
+ * are defined in the game's MACHINE_DRIVER.
+ * The discrete system is floating point based. So when routing a stream
+ * set it's gain to 100% and then use DISCRETE_INPUTX_STREAM to adjust
+ * it if needed.
+ *
+ * EXAMPLES: see
+ *
+ ***********************************************************************
+ =======================================================================
+ * from from disc_wav.c
+ * Generic modules
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_COUNTER - up/down counter.
+ *
+ * This counter counts up/down from 0 to MAX. When the enable is low, the output
+ * is held at it's last value. When reset is high, the reset value is loaded
+ * into the output. The counter can be clocked internally or externally. It also
+ * supports xTime used by the clock modules to pass on anti-aliasing info.
+ *
+ * Declaration syntax
+ *
+ * where: direction: DISC_COUNT_DOWN = 0 = down
+ * DISC_COUNT_UP = 1 = up
+ *
+ * clock type: DISC_CLK_ON_F_EDGE - toggle on falling edge.
+ * DISC_CLK_ON_R_EDGE - toggle on rising edge.
+ * DISC_CLK_BY_COUNT - toggle specified number of times.
+ * DISC_CLK_IS_FREQ - internally clock at this frequency.
+ * Clock node must be static if
+ * DISC_CLK_IS_FREQ is used.
+ *
+ * DISCRETE_COUNTER(name of node,
+ * enable node or static value,
+ * reset node or static value, (reset when TRUE)
+ * clock node or static value,
+ * max count static value,
+ * direction node or static value,
+ * reset value node or static value,
+ * clock type static value)
+ *
+ * DISCRETE_COUNTER_7492(name of node,
+ * enable node or static value,
+ * reset node or static value,
+ * clock node or static value,
+ * max count static value)
+ *
+ * Note: A 7492 counter outputs a special bit pattern on its /6 stage.
+ * A 7492 clocks on falling edge. This emulates the /6 stage only.
+ * Use another DISCRETE_COUNTER for the /2 stage.
+ *
+ * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug, Polaris
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_LFSR_NOISE - Noise waveform generator node, generates
+ * psuedo random digital stream at the requested
+ * clock frequency.
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_LFSR_NOISE(name of node,
+ * enable node or static value,
+ * reset node or static value,
+ * clock node or static value,
+ * amplitude node or static value,
+ * forced infeed bit to shift reg,
+ * bias node or static value,
+ * LFSR noise descriptor structure)
+ *
+ * discrete_lfsr_desc = {clock type, (see DISCRETE_COUNTER),
+ * bitlength, reset_value,
+ * feedback_bitsel0, feedback_bitsel1,
+ * feedback_function0, feedback_function1, feedback_function2,
+ * feedback_function2_mask, flags, output_bit}
+ *
+ * flags: DISC_LFSR_FLAG_OUT_INVERT - invert output
+ * DISC_LFSR_FLAG_RESET_TYPE_L - reset when LOW (Defalut)
+ * DISC_LFSR_FLAG_RESET_TYPE_H - reset when HIGH
+ * DISC_LFSR_FLAG_OUTPUT_F0 - output is result of F0
+ *
+ * The diagram below outlines the structure of the LFSR model.
+ *
+ * .-------.
+ * FEED | |
+ * ----->| F1 |<--------------------------------------------.
+ * | | |
+ * '-------' BS - Bit Select |
+ * | Fx - Programmable Function |
+ * | .-------. PI - Programmable Inversion |
+ * | | | |
+ * | .---- | SR>>1 |<--------. |
+ * | | | | | |
+ * V V '-------' | .---- |
+ * .------. +->| BS |--. .------. |
+ * BITMASK | | .-------------. | '----' '-| | |
+ * ------->| F2 |-+->| Shift Reg |--+ | F0 |--'
+ * | | | '-------------' | .----. .-| |
+ * '------' | ^ '->| BS |--' '------'
+ * | | '----'
+ * CLOCK | RESET VAL
+ * ----> | .----. .----.
+ * '----------------------| BS |--| PI |--->OUTPUT
+ * '----' '----'
+ *
+ * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug, Polaris
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_NOISE - Noise waveform generator node, generates
+ * random noise of the chosen frequency.
+ *
+ * .------------.
+ * | |
+ * ENABLE -0------>| |
+ * | |
+ * FREQUENCY -1------>| NOISE |----> Netlist node
+ * | |
+ * AMPLITUDE -2------>| |
+ * | |
+ * BIAS -3------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_NOISE(name of node,
+ * enable node or static value,
+ * frequency node or static value,
+ * amplitude node or static value)
+ *
+ * Example config line
+ *
+ * DISCRETE_NOISE(NODE_03,1,5000,NODE_01,0)
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_NOTE - Note generator. This takes a chosen clock, and
+ * clocks an up counter that is preloaded with the data
+ * value at every max 1 count. Every time max 1 count
+ * is reached, the output counts up one and rolls over
+ * to 0 at max 2 count.
+ * When the data value is the same as max count 1, the
+ * counter no longer counts.
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_NOTE(name of node,
+ * enable node or static value,
+ * clock node or static value,
+ * data node or static value,
+ * max 1 count static value,
+ * max 2 count static value,
+ * clock type (see DISCRETE_COUNTER))
+ *
+ * EXAMPLES: see Polaris, Blockade
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_SAWTOOTHWAVE - Saw tooth shape waveform generator, rapid
+ * rise and then graduated fall
+ *
+ * .------------.
+ * | |
+ * ENABLE -0------>| |
+ * | |
+ * FREQUENCY -1------>| |
+ * | |
+ * AMPLITUDE -2------>| SAWTOOTH |----> Netlist Node
+ * | WAVE |
+ * BIAS -3------>| |
+ * | |
+ * GRADIENT -4------>| |
+ * | |
+ * PHASE -5------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_SAWTOOTHWAVE(name of node,
+ * enable node or static value,
+ * frequency node or static value,
+ * amplitude node or static value,
+ * dc bias value for waveform,
+ * gradient of wave ==0 //// !=0 \\\\,
+ * starting phase value in degrees)
+ *
+ * Example config line
+ *
+ * DISCRETE_SAWTOOTHWAVE(NODE_03,1,5000,NODE_01,0,0,90)
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_SINEWAVE - Sinewave waveform generator node, has four
+ * input nodes FREQUENCY, AMPLITUDE, ENABLE and
+ * PHASE, if a node is not connected it will
+ * default to the initialised value in the macro
+ *
+ * .------------.
+ * | |
+ * ENABLE -0------>| |
+ * | |
+ * FREQUENCY -1------>| |
+ * | SINEWAVE |----> Netlist node
+ * AMPLITUDE -2------>| |
+ * | |
+ * BIAS -3------>| |
+ * | |
+ * PHASE -4------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_SINEWAVE (name of node,
+ * enable node or static value,
+ * frequency node or static value,
+ * amplitude node or static value,
+ * dc bias value for waveform,
+ * starting phase value in degrees)
+ *
+ * Example config line
+ *
+ * DISCRETE_SINEWAVE(NODE_03,NODE_01,NODE_02,10000,5000.0,90)
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_SQUAREWAVE - Squarewave waveform generator node.
+ * DISCRETE_SQUAREWFIX Waveform is defined by frequency and duty
+ * cycle.
+ *
+ * .------------.
+ * | |
+ * ENABLE -0------>| |
+ * | |
+ * FREQUENCY -1------>| |
+ * | |
+ * AMPLITUDE -2------>| SQUAREWAVE |----> Netlist node
+ * | |
+ * DUTY CYCLE -3------>| |
+ * | |
+ * BIAS -4------>| |
+ * | |
+ * PHASE -5------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_SQUAREWAVE(name of node,
+ * enable node or static value,
+ * frequency node or static value,
+ * amplitude node or static value,
+ * duty cycle node or static value,
+ * dc bias value for waveform,
+ * starting phase value in degrees)
+ *
+ * Example config line
+ *
+ * DISCRETE_SQUAREWAVE(NODE_03,NODE_01,NODE_02,100,50,0,90)
+ *
+ * NOTE: DISCRETE_SQUAREWFIX is used the same as DISCRETE_SQUAREWAVE.
+ * BUT... It does not stay in sync when you change the freq or
+ * duty values while enabled. This should be used only
+ * when these values are stable while the wave is enabled.
+ * It takes up less CPU time then DISCRETE_SQUAREWAVE and
+ * should be used whenever possible.
+ *
+ * EXAMPLES: see Polaris
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_SQUAREWAVE2 - Squarewave waveform generator node.
+ * Waveform is defined by it's off/on time
+ * periods.
+ *
+ * .------------.
+ * | |
+ * ENABLE -0------>| |
+ * | |
+ * AMPLITUDE -1------>| |
+ * | |
+ * OFF TIME -2------>| SQUAREWAVE |----> Netlist node
+ * | |
+ * ON TIME -3------>| |
+ * | |
+ * BIAS -4------>| |
+ * | |
+ * TIME SHIFT -5------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_SQUAREWAVE2(name of node,
+ * enable node or static value,
+ * amplitude node or static value,
+ * off time node or static value in seconds,
+ * on time node or static value in seconds,
+ * dc bias value for waveform,
+ * starting phase value in seconds)
+ *
+ * Example config line
+ *
+ * DISCRETE_SQUAREWAVE2(NODE_03,NODE_01,NODE_02,0.01,0.001,0.0,0.001)
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_TRIANGLEW - Triagular waveform generator, generates
+ * equal ramp up/down at chosen frequency
+ *
+ * .------------.
+ * | |
+ * ENABLE -0------>| |
+ * | |
+ * FREQUENCY -1------>| TRIANGLE |----> Netlist node
+ * | WAVE |
+ * AMPLITUDE -2------>| |
+ * | |
+ * BIAS -3------>| |
+ * | |
+ * PHASE -4------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_TRIANGLEWAVE(name of node,
+ * enable node or static value,
+ * frequency node or static value,
+ * amplitude node or static value,
+ * dc bias value for waveform,
+ * starting phase value in degrees)
+ *
+ * Example config line
+ *
+ * DISCRETE_TRIANGLEWAVE(NODE_03,1,5000,NODE_01,0.0,0.0)
+ *
+ ***********************************************************************
+ =======================================================================
+ * from from disc_wav.c
+ * Component specific modules
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_OP_AMP_OSCILLATOR - Various single power supply op-amp oscillator circuits
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_OP_AMP_OSCILLATOR(name of node,
+ * enable node or static value,
+ * address of dss_op_amp_osc_context structure)
+ *
+ * discrete_op_amp_osc_info = {type, r1, r2, r3, r4, r5, r6, r7, r8, c, vP}
+ *
+ * Note: Set all unused components to 0.
+ *
+ * Types:
+ *
+ * DISC_OP_AMP_OSCILLATOR_1 | DISC_OP_AMP_IS_NORTON
+ * Basic Norton Op Amp Oscillator circuit.
+ *
+ * vP >-.
+ * | c
+ * Z .---||----+---------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP
+ * Z r1 | |
+ * Z | |\ |
+ * | | | \ | |\
+ * '-----+---|- \ | r3 | \
+ * | >-+----ZZZZ----|- \
+ * |+ / | >--+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW
+ * .---| / .--|+ / |
+ * | |/ r5 | | / |
+ * | vP >--ZZZZ---+ |/ |
+ * Z | |
+ * Z r2 | r4 |
+ * Z '--ZZZZ---+
+ * | |
+ * | |
+ * '-----------------------------'
+ *
+ * Note: R1 - R5 can be nodes.
+ *
+ * EXAMPLES: see Polaris, Amazing Maze
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_OP_AMP_VCOn - Various single power supply op-amp VCO circuits
+ * (n = 1 or 2)
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_OP_AMP_VCOn(name of node,
+ * enable node or static value,
+ * modulation voltage 1 node or static value,
+ * modulation voltage 2 node or static value, [optional]
+ * address of dss_op_amp_osc_context structure)
+ *
+ * discrete_op_amp_osc_info = {type, r1, r2, r3, r4, r5, r6, r7, r8, c, vP}
+ *
+ * Note: Set all unused components to 0.
+ *
+ * Types:
+ *
+ * DISC_OP_AMP_OSCILLATOR_VCO_1
+ * Basic Op Amp Voltage Controlled Oscillator circuit.
+ * Note that this circuit has only 1 modulation voltage.
+ * So it is used only with DISCRETE_OP_AMP_VCO1.
+ *
+ * c
+ * .------------------------+---||----+---------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP
+ * | | |
+ * | | |\ |
+ * | r1 | | \ | |\
+ * | vMod1 >--+--ZZZZ-------+---|- \ | | \
+ * | | | >-+------------|- \
+ * | | r2 |+ / | >--+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW
+ * Z '--ZZZZ--+--------| / .--|+ / |
+ * Z r6 | |/ r4 | | / |
+ * Z Z vP/2 >--ZZZZ---+ |/ |
+ * | Z r5 | |
+ * .----. Z | r3 |
+ * | sw |<--------. | '--ZZZZ---+
+ * '----' | gnd |
+ * | | |
+ * gnd '----------------------------------------'
+ *
+ * Notes: The 'sw' block can be a transistor or 4066 switch. It connects
+ * r6 to ground when 'sw' is high.
+ *
+ * --------------------------------------------------
+ *
+ * DISC_OP_AMP_OSCILLATOR_VCO_1 | DISC_OP_AMP_IS_NORTON
+ * Basic Norton Op Amp Voltage Controlled Oscillator circuit.
+ * When disabled, c discharges and sqw out goes high.
+ *
+ * .---------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP
+ * c |
+ * r6 .---||----+
+ * vP >--ZZZZ---. | | r5 |\
+ * | | |\ | vP >--ZZZZ-. | \
+ * r7 | r1 | | \ | '-|- \
+ * vMod1 >--ZZZZ---+--ZZZZ-------+---|- \ | r3 | >--+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW
+ * | | >-+----ZZZZ----+--|+ / |
+ * r8 | r2 .----. |+ / | | / |
+ * vMod2 >--ZZZZ---+--ZZZZ---| sw |--| / | |/ |
+ * '----' |/ | |
+ * ^ ^ | r4 |
+ * | | '--ZZZZ---+
+ * | | |
+ * Enable >---------' | |
+ * '--------------------------------'
+ *
+ * EXAMPLES: see Polaris
+ *
+ * --------------------------------------------------
+ *
+ * DISC_OP_AMP_OSCILLATOR_VCO_2 | DISC_OP_AMP_IS_NORTON
+ * Basic Norton Op Amp Voltage Controlled Oscillator circuit.
+ * Note that this circuit has only 1 modulation voltage.
+ * So it is used only with DISCRETE_OP_AMP_VCO1.
+ * When vMod1 goes to 0V, the oscillator is disabled.
+ * c fully charges and the sqw out goes low.
+ *
+ * .---------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP
+ * |
+ * | r4
+ * c | .--ZZZZ--.
+ * .---||----+ | |
+ * | | r5 | |\ |
+ * | |\ | vP >--ZZZZ-+ | \ |
+ * r1 | | \ | '-|+ \ |
+ * vMod1 >--ZZZZ-----------------+---|- \ | r3 | >--+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW
+ * | >-+----ZZZZ-------|- / |
+ * r2 |+ / | / |
+ * vP >--ZZZZ-----------------+---| / |/ |
+ * | |/ |
+ * r6 .----. | |
+ * vP >--ZZZZ-----|-sw-|------' |
+ * '----' |
+ * ^ |
+ * | |
+ * '-----------------------------------------'
+ *
+ * EXAMPLES: see Double Play
+ *
+ * --------------------------------------------------
+ *
+ * DISC_OP_AMP_OSCILLATOR_VCO_3 | DISC_OP_AMP_IS_NORTON
+ * Basic Norton Op Amp Voltage Controlled Oscillator circuit.
+ *
+ *
+ * c
+ * r7 .---||----+---------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP
+ * vP >--ZZZZ---. | |
+ * | | |\ |
+ * r1 | | | \ | |\
+ * vMod1 >--ZZZZ---+---------+---|- \ | r3 | \
+ * | | >-+----ZZZZ----|- \
+ * r6 | |+ / | >--+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW
+ * vMod2 >--ZZZZ---' .---| / .--|+ / |
+ * | |/ r5 | | / |
+ * | vP >--ZZZZ---+ |/ |
+ * Z | |
+ * Z r2 | r4 |
+ * Z '--ZZZZ---+
+ * | |
+ * | |
+ * '-----------------------------'
+ *
+ * EXAMPLES: see Space Encounter
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_SCHMITT_OSCILLATOR - Schmitt Inverter gate oscillator
+ *
+ * rFeedback
+ * .---ZZZ----. .--< Amplitude
+ * | | |
+ * | |\ | .------. |
+ * rIn | | \ | 0/1 | AND/ | .-.
+ * INP0 >---ZZZ--+--|S >o---+----->|NAND/ |--->|*|-----> Netlist Node
+ * | | / | OR/ | '-'
+ * | |/ .->| NOR |
+ * --- | '------'
+ * --- C |
+ * | ^
+ * gnd Enable
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_SCHMITT_OSCILLATOR(name of node,
+ * enable node or static value,
+ * Input 0 node or static value,
+ * Amplitude node or static value,
+ * address of discrete_schmitt_osc_desc structure)
+ *
+ * discrete_schmitt_osc_desc = {rIn, rFeedback, c, trshRise, trshFall, vGate, options}
+ *
+ * Note: trshRise, trshFall, vGate can be replaced with one of these common types:
+ * DEFAULT_7414_VALUES or DEFAULT_74LS14_VALUES (the LS makes a difference)
+ * eg: {rIn, rFeedback, c, DEFAULT_7414_VALUES, options}
+ *
+ * Where:
+ * trshRise is the voltage level that triggers the gate input to go high (vGate) on rise.
+ * trshFall is the voltage level that triggers the gate input to go low (0V) on fall.
+ * vGate is the output high voltage of the gate that gets fedback through rFeedback.
+ *
+ * Input Options:
+ * DISC_SCHMITT_OSC_IN_IS_LOGIC (DEFAULT)
+ * DISC_SCHMITT_OSC_IN_IS_VOLTAGE
+ *
+ * Enable Options: (ORed with input options)
+ * DISC_SCHMITT_OSC_ENAB_IS_AND (DEFAULT)
+ * DISC_SCHMITT_OSC_ENAB_IS_NAND
+ * DISC_SCHMITT_OSC_ENAB_IS_OR
+ * DISC_SCHMITT_OSC_ENAB_IS_NOR
+ *
+ * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_INVERTER_OSC - Inverter gate oscillator circuits
+ *
+ * TYPE 1/3
+ * .----------------------------> Netlist Node (Type 3)
+ * |
+ * |\ | |\ |\
+ * | \ | | \ | \
+ * +--| >o--+--|-->o--+--| >o--+--------> Netlist Node (Type 1)
+ * | | / | / | | / |
+ * | |/ |/ | |/ |
+ * Z | |
+ * Z RP --- |
+ * Z --- C |
+ * | | R1 |
+ * '-------------------+----ZZZ--'
+ *
+ * TYPE 2
+ *
+ * |\ |\
+ * | \ | \
+ * +--| >o--+--|-->o--+-------> Netlist Node
+ * | | / | | / |
+ * | |/ | |/ |
+ * Z Z |
+ * Z RP Z R1 ---
+ * Z Z --- C
+ * | | |
+ * '---------+---------'
+ *
+ *
+ * TYPE 4 / see vicdual
+ *
+ * |\ |\
+ * | \ | \
+ * Enable >-+-----+--|>o-+--|-->o--+-------> Netlist Node
+ * | | / | | / |
+ * | |/ | |/ |
+ * Z Z |
+ * Z RP Z R1 ---
+ * Z Z --- C
+ * | D | |
+ * '------|>|---+---------'
+ * |
+ * Mod >-----ZZZ------'
+ * R2
+ *
+ * TYPE 5 / see vicdual
+ * Diode will cause inverted input behaviour and inverted output
+ *
+ * |\ |\
+ * | \ | \
+ * Enable >-+-----+--|>o-+--|-->o--+-------> Netlist Node
+ * | | / | | / |
+ * | |/ | |/ |
+ * Z Z |
+ * Z RP Z R1 ---
+ * Z Z --- C
+ * | D | |
+ * '------|<|---+---------'
+ * |
+ * Mod >-----ZZZ------'
+ * R2
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_INVERTER_OSC( name of node,
+ * enable node or static value,
+ * modulation node or static value (0 when not used),
+ * R1 static value,
+ * RP static value
+ * C static value,
+ * R2 static value (0 when not used),
+ * address of discrete_inverter_osc_desc structure)
+ *
+ * discrete_inverter_osc_desc = {vB, vOutLow, vOutHigh, vInRise, vInFall, clamp, options}
+ *
+ * Where
+ * vB Supply Voltage
+ * vOutLow Low Output voltage
+ * vOutHigh High Output voltage
+ * vInRise voltage that triggers the gate input to go high (vGate) on rise
+ * vInFall voltage that triggers the gate input to go low (0V) on fall
+ * clamp internal diode clamp: [-clamp ... vb+clamp] if clamp>= 0
+ * options bitmaped options
+ *
+ * There is a macro DEFAULT_CD40XX_VALUES(_vB) which may be used to initialize the
+ * structure with .... = { 5, DEFAULT_CD40XX_VALUES(5), DISC_OSC_INVERTER_IS_TYPE1}
+ *
+ * The parameters are used to construct a input/output transfer function.
+ *
+ * Option Values
+ *
+ * DISC_OSC_INVERTER_IS_TYPE1
+ * DISC_OSC_INVERTER_IS_TYPE2
+ * DISC_OSC_INVERTER_IS_TYPE3
+ * DISC_OSC_INVERTER_IS_TYPE4
+ * DISC_OSC_INVERTER_OUT_IS_LOGIC
+ *
+ * EXAMPLES: see dkong
+ *
+ ***********************************************************************
+ =======================================================================
+ * from from disc_wav.c
+ * Not yet implemented
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_ADSR_ENV - Attack Decay Sustain Release envelope generator
+ *
+ * Note: Not yet implemented.
+ *
+ * .------------.
+ * | |
+ * ENABLE -0------>| |
+ * | /\__ |
+ * TRIGGER -1------>| / \ |----> Netlist node
+ * | ADSR |
+ * GAIN -2------>| Env |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_ADSR_ENV (name of node,
+ * enable node or static value,
+ * envelope gain node or static value,
+ * envelope descriptor struct)
+ *
+ * Example config line
+ *
+ * DISCRETE_ADSR_ENV(NODE_3,1,NODE_21,1.0,&adsrdesc)
+ *
+ ***********************************************************************
+ =======================================================================
+ * from from disc_mth.c
+ * Generic modules
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_ADDER - Node addition function, available in three
+ * lovely flavours, ADDER2,ADDER3,ADDER4
+ * that perform a summation of incoming nodes
+ *
+ * .------------.
+ * | |
+ * INPUT0 -0------>| |
+ * | |
+ * INPUT1 -1------>| | |
+ * | -+- |----> Netlist node
+ * INPUT2 -2------>| | |
+ * | |
+ * INPUT3 -3------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_ADDERx (name of node,
+ * (x=2/3/4) enable node or static value,
+ * input0 node or static value,
+ * input1 node or static value,
+ * input2 node or static value, [optional]
+ * input3 node or static value) [optional]
+ *
+ * Example config line
+ *
+ * DISCRETE_ADDER2(NODE_03,1,NODE_12,-2000)
+ *
+ * Always enabled, subtracts 2000 from the output of NODE_12
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_CLAMP - Force a signal to stay within bounds MIN/MAX
+ *
+ * .------------.
+ * | |
+ * ENAB -0------>| |
+ * | |
+ * INP0 -1------>| |
+ * | |
+ * MIN -2------>| CLAMP |----> Netlist node
+ * | |
+ * MAX -3------>| |
+ * | |
+ * CLAMP -4------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_CLAMP(name of node,
+ * enable,
+ * input node,
+ * minimum node or static value,
+ * maximum node or static value,
+ * clamp node or static value when disabled)
+ *
+ * Example config line
+ *
+ * DISCRETE_CLAMP(NODE_9,NODE_10,NODE_11,2.0,10.0,5.0)
+ *
+ * Node10 when not zero will allow clamp to operate forcing the value
+ * on the node output, to be within the MIN/MAX boundard. When enable
+ * is set to zero the node will output the clamp value
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_DIVIDE - Node division function
+ *
+ * .------------.
+ * | |
+ * ENAB -0------>| |
+ * | o |
+ * INPUT1 -1------>| --- |----> Netlist node
+ * | o |
+ * INPUT2 -2------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_DIVIDE (name of node,
+ * enable node or static value,
+ * input0 node or static value,
+ * input1 node or static value)
+ *
+ * Example config line
+ *
+ * DISCRETE_DIVIDE(NODE_03,1.0,NODE_12,50.0)
+ *
+ * Always enabled, divides the input NODE_12 by 50.0. Note that a
+ * divide by zero condition will give a LARGE number output, it
+ * will not stall the machine or simulation. It will also attempt
+ * to write a divide by zero error to the Mame log if enabled.
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_LOGIC_INVERT - Logic invertor
+ * DISCRETE_LOGIC_AND - Logic AND gate (3 & 4 input also available)
+ * DISCRETE_LOGIC_NAND - Logic NAND gate (3 & 4 input also available)
+ * DISCRETE_LOGIC_OR - Logic OR gate (3 & 4 input also available)
+ * DISCRETE_LOGIC_NOR - Logic NOR gate (3 & 4 input also available)
+ * DISCRETE_LOGIC_XOR - Logic XOR gate
+ * DISCRETE_LOGIC_NXOR - Logic NXOR gate
+ *
+ * .------------.
+ * | |
+ * ENAB -0------>| |
+ * | |
+ * INPUT0 -0------>| |
+ * | LOGIC |
+ * [INPUT1] -1------>| FUNCTION |----> Netlist node
+ * | !&|^ |
+ * [INPUT2] -2------>| |
+ * | |
+ * [INPUT3] -3------>| |
+ * | |
+ * [] - Optional '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_LOGIC_XXXn(name of node,
+ * (X=INV/AND/etc) enable node or static value,
+ * (n=Blank/2/3) input0 node or static value,
+ * [input1 node or static value],
+ * [input2 node or static value],
+ * [input3 node or static value])
+ *
+ * Example config lines
+ *
+ * DISCRETE_LOGIC_INVERT(NODE_03,1,NODE_12)
+ * DISCRETE_LOGIC_AND(NODE_03,1,NODE_12,NODE_13)
+ * DISCRETE_LOGIC_NOR4(NODE_03,1,NODE_12,NODE_13,NODE_14,NODE_15)
+ *
+ * Node output is always either 0.0 or 1.0 any input value !=0.0 is
+ * taken as a logic 1.
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_LOGIC_DFLIPFLOP - Standard D-type flip-flop.
+ * Changes on rising edge of clock.
+ *
+ * /SET -2 ------------.
+ * v
+ * .-----o------.
+ * | |
+ * DATA -4 ----->| |
+ * | FLIPFLOP |
+ * | Q|----> Netlist node
+ * | |
+ * CLOCK -3 ----->| |
+ * | |
+ * '-----o------'
+ * ^
+ * /RESET -1 ------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_LOGIC_DFLIPFLOP(name of node,
+ * enable node or static value,
+ * reset node or static value,
+ * set node or static value,
+ * clock node,
+ * data node or static value)
+ *
+ * Example config line
+ *
+ * DISCRETE_LOGIC_DFLIPFLOP(NODE_7,1,NODE_17,0,NODE_13,1)
+ *
+ * A flip-flop that clocks a logic 1 through on the rising edge of
+ * NODE_13. A logic 1 on NODE_17 resets the output to 0.
+ *
+ * EXAMPLES: see Hit Me, Polaris
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_LOGIC_JKFLIPFLOP - Standard JK-type flip-flop.
+ * Changes on falling edge of clock.
+ *
+ * /SET -2 ------------.
+ * v
+ * .-----o------.
+ * | |
+ * J -4 ----->| |
+ * | FLIPFLOP |
+ * CLOCK -3 ----->| Q|----> Netlist node
+ * | |
+ * K -5 ----->| |
+ * | |
+ * '-----o------'
+ * ^
+ * /RESET -1 ------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_LOGIC_JKFLIPFLOP(name of node,
+ * enable node or static value,
+ * reset node or static value,
+ * set node or static value,
+ * clock node,
+ * J node or static value,
+ * K node or static value)
+ *
+ * EXAMPLES: see Amazing Maze
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_LOOKUP_TABLE - returns the value in a table
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_LOOKUP_TABLE(name of node,
+ * enable node or static value,
+ * address node,
+ * size of table static value,
+ * address of table of double values)
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_MULTIPLEX - 1 of 2/4/8 multiplexer
+ *
+ * .-------------.
+ * Input 0 >-----|>-<. |
+ * | \ |
+ * Input 1 >-----|>- \ |
+ * | \ |
+ * Input 2 >-----|>- |\ |
+ * | | \ |
+ * Input 3 >-----|>- | o-->|------> Netlist Node
+ * | | |
+ * Input 4 >-----|>- | |
+ * | | |
+ * Input 5 >-----|>- '------|----< Address
+ * | | (0 shown)
+ * Input 6 >-----|>- |
+ * | |
+ * Input 7 >-----|>- |
+ * '-------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_MULTIPLEXx(name of node,
+ * (x=2/4/8) enable node or static value,
+ * address node,
+ * input 0 node or static value,
+ * input 1 node or static value, ...)
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_GAIN - Node multiplication function output is equal
+ * DISCRETE_MULTIPLY to INPUT0 * INPUT1
+ * DISCRETE_MULTADD to (INPUT0 * INPUT1) + INPUT 2
+ *
+ * .------------.
+ * | |
+ * ENAB -0------>| |
+ * | |
+ * INPUT0 -1------>| \|/ |
+ * | -+- |----> Netlist node
+ * INPUT1 -2------>| /|\ |
+ * | |
+ * INPUT2 -3------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_MULTIPLY (name of node,
+ * enable node or static value,
+ * input0 node or static value,
+ * input1 node or static value)
+ *
+ * DISCRETE_MULTADD (name of node,
+ * enable node or static value,
+ * input0 node or static value,
+ * input1 node or static value,
+ * input2 node or static value)
+ *
+ * DISCRETE_GAIN (name of node,
+ * input0 node or static value,
+ * static value for gain)
+ * Example config line
+ *
+ * DISCRETE_GAIN(NODE_03,NODE_12,112.0)
+ *
+ * Always enabled, multiplies the input NODE_12 by 112.0
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_ONESHOT - Monostable multivibrator, no reset
+ * DISCRETE_ONESHOTR - Monostable multivibrator, with reset
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_ONESHOT (name of node,
+ * trigger node,
+ * amplitude node or static value,
+ * width (in seconds) node or static value,
+ * type of oneshot static value)
+ *
+ * DISCRETE_ONESHOTR (name of node,
+ * reset node or static value,
+ * trigger node,
+ * amplitude node or static value,
+ * width (in seconds) node or static value,
+ * type of oneshot static value)
+ *
+ * Types:
+ *
+ * DISC_ONESHOT_FEDGE 0x00 - trigger on falling edge (DEFAULT)
+ * DISC_ONESHOT_REDGE 0x01 - trigger on rising edge
+ *
+ * DISC_ONESHOT_NORETRIG 0x00 - non-retriggerable (DEFAULT)
+ * DISC_ONESHOT_RETRIG 0x02 - retriggerable
+ *
+ * DISC_OUT_ACTIVE_LOW 0x04 - output active low
+ * DISC_OUT_ACTIVE_HIGH 0x00 - output active high (DEFAULT)
+ *
+ * NOTE: A width of 0 seconds will output a pulse of 1 sample.
+ * This is useful for a guaranteed minimun pulse, regardless
+ * of the sample rate.
+ *
+ * EXAMPLES: see Polaris
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_RAMP - Ramp up/down circuit with clamps & reset
+ *
+ * .------------.
+ * | |
+ * ENAB -0------>| FREE/CLAMP |
+ * | |
+ * RAMP -1------>| FW/REV |
+ * | |
+ * GRAD -2------>| Grad/sec |
+ * | |----> Netlist node
+ * START -3------>| Start clamp|
+ * | |
+ * END -4------>| End clamp |
+ * | |
+ * CLAMP -5------>| off clamp |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_RAMP(name of node,
+ * enable,
+ * ramp forward/reverse node (or value),
+ * gradient node (or static value),
+ * start node or static value,
+ * end node or static value,
+ * clamp node or static value when disabled)
+ *
+ * Example config line
+ *
+ * DISCRETE_RAMP(NODE_9,NODE_10,NODE_11,10.0,-10.0,10.0,0)
+ *
+ * Node10 when not zero will allow ramp to operate, when 0 then output
+ * is clamped to clamp value specified. Node11 ramp when 0 change
+ * gradient from start to end. 1 is reverse. Output is clamped to max-
+ * min values. Gradient is specified in change/second.
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_SAMPHOLD - Sample & Hold circuit
+ *
+ * .------------.
+ * | |
+ * ENAB -0------>| |
+ * | |
+ * INP0 -1------>| SAMPLE |
+ * | & |----> Netlist node
+ * CLOCK -2------>| HOLD |
+ * | |
+ * CLKTYPE -3------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_SAMPHOLD(name of node,
+ * enable,
+ * input node,
+ * clock node or static value,
+ * input clock type)
+ *
+ * Example config line
+ *
+ * DISCRETE_SAMPHOLD(NODE_9,1,NODE_11,NODE_12,DISC_SAMPHOLD_REDGE)
+ *
+ * Node9 will sample the input node 11 on the rising edge (REDGE) of
+ * the input clock signal of node 12.
+ *
+ * DISC_SAMPHOLD_REDGE - Rising edge clock
+ * DISC_SAMPHOLD_FEDGE - Falling edge clock
+ * DISC_SAMPHOLD_HLATCH - Output is latched whilst clock is high
+ * DISC_SAMPHOLD_LLATCH - Output is latched whilst clock is low
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_SWITCH - Node switch function, output node is switched
+ * by switch input to take one node/contst or
+ * other. Can be nodes or constants.
+ *
+ * SWITCH -0--------------.
+ * V
+ * .------------.
+ * | | |
+ * INPUT0 -1------}|----o |
+ * | .--- |----> Netlist node
+ * INPUT1 -2------>|----o / |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_SWITCH (name of node,
+ * enable node or static value,
+ * switch node or static value,
+ * input0 node or static value,
+ * input1 node or static value)
+ *
+ * Example config line
+ *
+ * DISCRETE_SWITCH(NODE_03,1,NODE_10,NODE_90,5.0)
+ *
+ * Always enabled, NODE_10 switches output to be either NODE_90 or
+ * constant value 5.0. Switch==0 inp0=output else inp1=output
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_ASWITCH - Node switch function, output node is same
+ * as input when CTRL is above threshold.
+ *
+ * CTRL -0--------------.
+ * V
+ * .------------.
+ * | | |
+ * INPUT0 -1------ |----- . --- |----> Netlist node
+ * | |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_ASWITCH (name of node,
+ * enable node or static value,
+ * ctrl node or static value,
+ * input node or static value,
+ * threshold satic value )
+ *
+ * Example config line
+ *
+ * DISCRETE_ASWITCH(NODE_03,1,NODE_10,NODE_90, 2.73)
+ *
+ * Always enabled, NODE_10 switches output to be either NODE_90 or
+ * constant value 0.0. Ctrl>2.73 output=NODE_90 else output=0
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_TRANSFORMn - Node arithmatic logic (postfix arithmatic)
+ * (n=2,3,4,5)
+ * .------------.
+ * | |
+ * ENAB -0------>| |
+ * | |
+ * INPUT0 -1------>| |
+ * | |
+ * INPUT1 -2------>| Postfix |
+ * | stack |----> Netlist node
+ * INPUT2 -3------>| maths |
+ * | |
+ * INPUT3 -4------>| |
+ * | |
+ * INPUT4 -5------>| |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_TRANSFORMn(name of node,
+ * enable node or static value,
+ * input0 node or static value,
+ * input1 node or static value,
+ * input2 node or static value, [optional]
+ * input3 node or static value, [optional]
+ * input4 node or static value, [optional]
+ * maths string)
+ *
+ * Example config line
+ *
+ * DISCRETE_TRANSFORM4(NODE_12,1,NODE_22,50.0,120.0,33.33,"01*2+3/")
+ *
+ * Arithmetic uses stack based arithmetic similar to Forth, the maths
+ * has 5 registers 0-4 and various arithmetic operations. The math
+ * string is processed from left to right in the following manner:
+ * 0 - Push input 0 to stack
+ * 1 - Push input 1 to stack
+ * 2 - Push input 2 to stack
+ * 3 - Push input 3 to stack
+ * 4 - Push input 4 to stack
+ * - - Pop two values from stack, subtract and push result to stack
+ * + - Pop two values from stack, add and push result to stack
+ * / - Pop two values from stack, divide and push result to stack
+ * * - Pop two values from stack, multiply and push result to stack
+ * i - Pop one value from stack, multiply -1 and push result to stack
+ * ! - Pop one value from stack, logical invert, push result to stack
+ * = - Pop two values from stack, logical = and push result to stack
+ * > - Pop two values from stack, logical > and push result to stack
+ * < - Pop two values from stack, logical < and push result to stack
+ * & - Pop two values from stack, binary AND and push result to stack
+ * | - Pop two values from stack, binary OR and push result to stack
+ * ^ - Pop two values from stack, binary XOR and push result to stack
+ * P - Push a duplicate of the last stack value back on the stack
+ *
+ * EXAMPLES: see Polaris
+ *
+ ***********************************************************************
+ =======================================================================
+ * from from disc_mth.c
+ * Component specific modules
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_COMP_ADDER - Selecatable parallel component adder.
+ * The total netlist out will be the parallel sum of all
+ * components with their corresponding data bit = 1.
+ * Set cDefault to 0 if not used.
+ *
+ * common >---cDefault---.
+ * data&0x01 >-----c[0]-----+
+ * data&0x02 >-----c[1]-----+
+ * data&0x04 >-----c[2]-----+
+ * data&0x08 >-----c[3]-----+-----> netlist node
+ * data&0x10 >-----c[4]-----+
+ * data&0x20 >-----c[5]-----+
+ * data&0x40 >-----c[6]-----+
+ * data&0x80 >-----c[7]-----'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_COMP_ADDER(name of node,
+ * enable node or static value,
+ * data node (static value is useless),
+ * address of discrete_comp_adder_table structure)
+ *
+ * discrete_comp_adder_table = {type, cDefault, length, c{}}
+ *
+ * Circuit Types:
+ * DISC_COMP_P_CAPACITOR - parallel capacitors
+ * DISC_COMP_P_RESISTOR - parallel resistors
+ *
+ * EXAMPLES: see Hit Me
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_DAC_R1 - R1 ladder DAC with cap smoothing and external bias
+ *
+ * rBias
+ * data&0x01 >--/\R[0]/\--+-----/\/\----< vBias
+ * data&0x02 >--/\R[1]/\--|
+ * data&0x04 >--/\R[2]/\--|
+ * data&0x08 >--/\R[3]/\--|
+ * data&0x10 >--/\R[4]/\--|
+ * data&0x20 >--/\R[5]/\--|
+ * data&0x40 >--/\R[6]/\--|
+ * data&0x80 >--/\R[7]/\--+-------------+-----> Netlist node
+ * | |
+ * Z ---
+ * Z rGnd --- cFilter
+ * | |
+ * gnd gnd
+ *
+ * NOTES: rBias and vBias are used together. If not needed they should
+ * be set to 0. If used, they should both have valid values.
+ * rGnd and cFilter should be 0 if not needed.
+ * A resistor value should be properly set for each resistor
+ * up to the ladder length. Remember 0 is a short circuit.
+ * The data node is bit mapped to the ladder. valid int 0-255.
+ * TTL logic 0 is actually 0.2V but 0V is used. The other parts
+ * have a tolerance that more then makes up for this.
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_DAC_R1(name of node,
+ * enable node or static value,
+ * data node (static value is useless),
+ * vData node or static value (vON),
+ * address of discrete_dac_r1_ladder structure)
+ *
+ * discrete_dac_r1_ladder = {ladderLength, r{}, vBias, rBias, rGnd, cFilter}
+ *
+ * Note: Resistors in the ladder that are set to 0, will be handled like they
+ * are out of circuit. So the bit selecting them will have no effect
+ * on the DAC output voltage.
+ *
+ * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug, Polaris
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_DIODE_MIXER - mixes inputs through diodes
+ *
+ *
+ * input 0 >----|>|---.
+ * |
+ * input 1 >----|>|---+----------> Netlist Node
+ * |
+ * input 2 >----|>|---+
+ * |
+ * input 3 >----|>|---+--/\/\/\--.
+ * |
+ * gnd
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_DIODE_MIXERx(name of node,
+ * (x = 2/3/4) enable node or static value,
+ * voltage drop of the diode junction (static value),
+ * input 0 node,
+ * input 1 node,
+ * ...)
+ *
+ * EXAMPLES: see
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_INTEGRATE - Various Integration circuits
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_INTEGRATE(name of node,
+ * trigger 0 node or static value,
+ * trigger 1 node or static value,
+ * address of discrete_integrate_info)
+ *
+ * discrete_integrate_info = {type, r1, r2, r3, c, v1, vP, f0, f1, f2}
+ *
+ * Note: Set all unused components to 0.
+ * These are all single supply circuits going from gnd(0V) to vP(B+),
+ * so be sure to specify the vP power source.
+ *
+ * Types:
+ *
+ * DISC_INTEGRATE_OP_AMP_1
+ *
+ * v1 >----+-------.
+ * | | c
+ * Z Z .---||----.
+ * Z r1 Z r2 | |
+ * Z Z | |\ |
+ * | | | | \ |
+ * +--------------+--|- \ |
+ * | | | >--+----> Netlist Node
+ * / +---------|+ /
+ * |/ | | /
+ * Trig0 >--| NPN Z |/
+ * |\ Z r3
+ * > Z
+ * | |
+ * gnd gnd
+ *
+ *
+ * EXAMPLES: see Tank8
+ *
+ * --------------------------------------------------
+ *
+ * DISC_INTEGRATE_OP_AMP_1 | DISC_OP_AMP_IS_NORTON
+ *
+ * c
+ * .---||----.
+ * | |
+ * | |\ |
+ * r1 | | \ |
+ * v1 >----ZZZZ--------+--|- \ |
+ * | >--+----> Netlist Node
+ * r2 .--|+ /
+ * Trig0 >----ZZZZ--------' | /
+ * |/
+ *
+ * Note: Trig0 is voltage level, not logic.
+ * No functions are used so set them to 0, or DISC_OP_AMP_TRIGGER_FUNCTION_NONE.
+ * You can also use DISCRETE_OP_AMP with type DISC_OP_AMP_IS_NORTON to emulate this.
+ *
+ * EXAMPLES: see Double Play
+ *
+ * --------------------------------------------------
+ *
+ * DISC_INTEGRATE_OP_AMP_2 | DISC_OP_AMP_IS_NORTON
+ *
+ * c
+ * .---||----.
+ * r1a | |
+ * v1 >----ZZZZ---. | |\ |
+ * .----. | r1b Diode | | \ |
+ * | F0 |--+--ZZZZ----|>|--+--|- \ |
+ * '----' | >--+----> Netlist Node
+ * r2a r2b .--|+ /
+ * v1 >----ZZZZ---+--ZZZZ---------+ | /
+ * .----. | | |/
+ * | F1 |--' |
+ * '----' |
+ * r3a r3b Diode |
+ * v1 >----ZZZZ---+--ZZZZ----|>|--'
+ * .----. |
+ * | F2 |--'
+ * '----'
+ *
+ * Note: For an explanation of the functions and trigger inputs,
+ * see DISCRETE_OP_AMP_TRIG_VCA below.
+ *
+ * EXAMPLES: see Polaris
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_MIXER - Mixes multiple input signals.
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_MIXERx(name of node,
+ * (x = 2 to 8) enable node or static value,
+ * input 0 node,
+ * input 1 node,
+ * input 2 node, (if used)
+ * input 3 node, (if used)
+ * input 4 node, (if used)
+ * input 5 node, (if used)
+ * input 6 node, (if used)
+ * input 7 node, (if used)
+ * address of discrete_mixer_info structure)
+ *
+ * discrete_mixer_desc = {type, r{}, rNode{}, c{}, rI, rF, cF, cAmp, vRef, gain}
+ *
+ * Note: Set all unused components to 0.
+ * If an rNode is not used it should also be set to 0.
+ *
+ * Types:
+ *
+ * DISC_MIXER_IS_RESISTOR
+ *
+ * rNode[0] r[0] c[0]
+ * IN0 >--zzzz-----zzzz----||---.
+ * |
+ * rNode[1] r[1] c[1] |
+ * IN1 >--zzzz-----zzzz----||---+--------.
+ * . . . . | | cAmp
+ * . . . . | Z<------||---------> Netlist Node
+ * . . . . | Z
+ * . rNode[7] r[7] c[7] | Z rF
+ * IN7 >--zzzz-----zzzz----||---+ |
+ * | |
+ * --- |
+ * cF --- |
+ * | |
+ * gnd gnd
+ *
+ * Note: The variable resistor is used in it's full volume position.
+ * MAME's built in volume is used for adjustment.
+ *
+ * EXAMPLES: see Polaris, Super Bug
+ *
+ * --------------------------------------------------
+ *
+ * DISC_MIXER_IS_OP_AMP
+ *
+ * cF
+ * .----||---.
+ * | |
+ * rNode[0] r[0] c[0] | rF |
+ * IN0 >--zzzz------zzzz----||---. +---ZZZZ--+
+ * | | |
+ * rNode[1] r[1] c[1] | rI | |\ |
+ * IN1 >--zzzz------zzzz----||---+--zzzz--+ | \ |
+ * . . . . | '--|- \ | cAmp
+ * . . . . | | >--+---||-----> Netlist Node
+ * . . . . | .--|+ /
+ * . rNode[7] r[7] c[7] | | | /
+ * IN7 >--zzzz------zzzz----||---' | |/
+ * |
+ * vRef >----------------------------------'
+ *
+ * Note: rI is not always used and should then be 0.
+ *
+ * EXAMPLES: see Fire Truck, Monte Carlo
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_OP_AMP - Various op-amp circuits
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_OP_AMP(name of node,
+ * enable node or static value,
+ * input 0 node or static value,
+ * input 1 node or static value,
+ * address of discrete_op_amp_info structure)
+ *
+ * discrete_op_amp_info = {type, r1, r2, r3, r4, c, vN, vP}
+ *
+ * Note: Set all unused components to 0.
+ *
+ * Types:
+ *
+ * DISC_OP_AMP_IS_NORTON
+ *
+ * c
+ * .----||---.
+ * | |
+ * r3 | r4 | vP = B+
+ * vP >---ZZZZ------+---ZZZZ--+ vN = B-
+ * | |
+ * r1 | |\ | Note: r2 must always be used
+ * IN0 >---ZZZZ------+ | \ |
+ * '--|- \ |
+ * r2 | >--+-----> Netlist Node
+ * IN1 >---ZZZZ---------|+ /
+ * | /
+ * |/
+ *
+ * EXAMPLES: see Space Encounter
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_OP_AMP_ONESHOT - Various op-amp one shot circuits
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_OP_AMP_ONESHOT(name of node,
+ * trigger node (voltage level),
+ * address of discrete_op_amp_1sht_info structure)
+ *
+ * discrete_op_amp_1sht_info = {type, r1, r2, r3, r4, r5, c1, c2, vN, vP}
+ *
+ * Types:
+ *
+ * DISC_OP_AMP_1SHT_1 | DISC_OP_AMP_IS_NORTON
+ *
+ * c1 .---|>|---.
+ * gnd >----||---+---+ |
+ * | | r4 | vP = B+
+ * Z '---ZZZZ--+ vN = B-
+ * Z r3 |
+ * Z |\ | Note: all components must be used
+ * r1 | | \ | The oneshot is cancelled when TRIG goes low
+ * vP >---ZZZZ--+------|- \ |
+ * | >--+-----> Netlist Node
+ * c2 r2 .--|+ / |
+ * TRIG >--||---ZZZZ--+ | / |
+ * | |/ |
+ * | r5 |
+ * '---ZZZZ--'
+ *
+ *
+ * EXAMPLES: see Space Encounter
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_OP_AMP_TRIG_VCA - Triggered Norton op amp voltage controlled amplifier.
+ * This means the cap is rapidly charged thru r5 when F2=1.
+ * Then it discharges thru r6+r7 when F2=0.
+ * This voltage controls the amplitude.
+ * While the diagram looks complex, usually only parts of it are used.
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_OP_AMP_TRIG_VCA(name of node,
+ * trigger 0 node or static value,
+ * trigger 1 node or static value,
+ * trigger 2 node or static value,
+ * input 0 node or static value,
+ * input 1 node or static value,
+ * address of discrete_op_amp_tvca_info structure)
+ *
+ * discrete_op_amp_tvca_info = { r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, c1, c2, c3, v1, v2, v3, vP, f0, f1, f2, f3, f4, f5}
+ *
+ * Note: Set all unused components to 0.
+ * Set all unused functions to DISC_OP_AMP_TRIGGER_FUNCTION_NONE
+ * Set all unused nodes to NODE_NC.
+ * If function F3 is not used then set r6=0 and use only r7.
+ * r2 = r2a + r2b. r3 = r3a + r3b.
+ * vP is the op-amp B+.
+ *
+ * r2a
+ * IN0 >----ZZZZ-----. r1
+ * .----. | vP >------ZZZZ---.
+ * | F0 |----+ |
+ * '----' | r2b | r4
+ * r3a '---------------ZZZZ---+---ZZZZ--.
+ * IN1 >----ZZZZ---. | |
+ * .----. | r3b | |\ |
+ * | F1 |--+-----------------ZZZZ---+ | \ |
+ * '----' '--|- \ |
+ * .----. diode r6 r7 | >--+----> Netlist Node
+ * | F2 |--+--|>|--+--ZZZZ---+--ZZZZ-+-|+ /
+ * '----' | | | | | /
+ * | --- .----. | |/
+ * r5 | --- c1 | F3 | |
+ * v1 >----ZZZZ---' | '----' |
+ * gnd |
+ * |
+ * .----. diode r9 |
+ * | F4 |--+--|>|-----------+---ZZZZ-+
+ * '----' | c2 | |
+ * r8 | gnd >---||---' |
+ * v2 >----ZZZZ---' |
+ * .----. diode r11 |
+ * | F5 |--+--|>|-----------+---ZZZZ-'
+ * '----' | c3 |
+ * r10 | gnd >---||---'
+ * v3 >----ZZZZ---'
+ *
+ * Function types:
+ *
+ * Trigger 0, 1 and 2 are used for the functions F0 - F5.
+ * When the output of the function is 0, then the connection is held at 0V or gnd.
+ * When the output of the function is 1, then the function is an open circuit.
+ *
+ * DISC_OP_AMP_TRIGGER_FUNCTION_NONE - Not used, cicuit open.
+ * DISC_OP_AMP_TRIGGER_FUNCTION_TRG0 - Gnd when trigger 0 is 0.
+ * DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV - Gnd when trigger 0 is 1.
+ * DISC_OP_AMP_TRIGGER_FUNCTION_TRG1 - Gnd when trigger 1 is 0.
+ * DISC_OP_AMP_TRIGGER_FUNCTION_TRG1_INV - Gnd when trigger 1 is 1.
+ * DISC_OP_AMP_TRIGGER_FUNCTION_TRG2 - Gnd when trigger 2 is 0.
+ * DISC_OP_AMP_TRIGGER_FUNCTION_TRG2_INV - Gnd when trigger 2 is 1.
+ * DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_AND - Gnd when trigger 0 or 1 are 0.
+ * DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_NAND - Gnd when trigger 0 and 1 are 1.
+ *
+ * EXAMPLES: see Polaris
+ *
+ ***********************************************************************
+ =======================================================================
+ * from from disc_flt.c
+ * Generic modules
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_FILTER1
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_FILTER1(name of node,
+ * enable node or static value,
+ * input node,
+ * filter center frequency static value,
+ * filter type static value)
+ *
+ * Filter types: DISC_FILTER_LOWPASS,
+ * DISC_FILTER_HIGHPASS
+ * DISC_FILTER_BANDPASS
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_FILTER2
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_FILTER2(name of node,
+ * enable node or static value,
+ * input node,
+ * filter center frequency static value,
+ * damp static value,
+ * filter type static value)
+ *
+ * Filter types: DISC_FILTER_LOWPASS,
+ * DISC_FILTER_HIGHPASS
+ * DISC_FILTER_BANDPASS
+ *
+ * Note: Damp = 1/Q
+ *
+ ***********************************************************************
+ =======================================================================
+ * from from disc_flt.c
+ * Component specific modules
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_CRFILTER - Simple single pole CR filter network (vRef = 0)
+ * DISCRETE_CRFILTER_VREF - Same but refrenced to vRef not 0V
+ *
+ * .------------.
+ * | |
+ * ENAB -0------}| CR FILTER |
+ * | |
+ * INPUT1 -1------}| --| |-+-- |
+ * | C | |----} Netlist node
+ * RVAL -2------}| Z |
+ * | Z R |
+ * CVAL -3------}| | |
+ * | vRef |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_CRFILTER(name of node,
+ * enable
+ * input node (or value)
+ * resistor value in OHMS
+ * capacitor value in FARADS)
+ *
+ * DISCRETE_CRFILTER_VREF(name of node,
+ * enable
+ * input node (or value)
+ * resistor value in OHMS
+ * capacitor value in FARADS,
+ * vRef static value)
+ *
+ * Example config line
+ *
+ * DISCRETE_CRFILTER(NODE_11,1,NODE_10,100,CAP_U(1))
+ *
+ * Defines an always enabled CR filter with a 100R & 1uF network
+ * the input is fed from NODE_10.
+ *
+ * This can be also thought of as a high pass filter with a 3dB cutoff
+ * at:
+ * 1
+ * Fcuttoff = --------------
+ * 2*Pi*RVAL*CVAL
+ *
+ * (3dB cutoff is where the output power has dropped by 3dB ie Half)
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_OP_AMP_FILTER - Various Op Amp Filters.
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_OP_AMP_FILTER(name of node,
+ * enable node or static value,
+ * input 1 node or static value,
+ * input 2 node or static value,
+ * type static value,
+ * address of discrete_op_amp_filt_info)
+ *
+ * discrete_op_amp_filt_info = {r1, r2, r3, r4, rF, c1, c2, c3, vRef, vP, vN}
+ *
+ * Note: Set all unused components to 0.
+ * vP and vN are the +/- op-amp power supplies.
+ * vRef is 0 if Gnd.
+ *
+ * Types:
+ *
+ * DISC_OP_AMP_FILTER_IS_LOW_PASS_1
+ * First Order Low Pass Filter
+ *
+ * c1
+ * .-------||---------.
+ * | |
+ * r1 | rF |
+ * IN0 >--ZZZZ--. +------ZZZZ--------+
+ * | | |
+ * r2 | | |\ |
+ * IN1 >--ZZZZ--+------+--------+ | \ |
+ * | '--|- \ |
+ * r3 | | >--+----------> Netlist Node
+ * vRef >--ZZZZ--' .--|+ /
+ * | | /
+ * vRef >-----------------------' |/
+ *
+ * --------------------------------------------------
+ *
+ * DISC_OP_AMP_FILTER_IS_HIGH_PASS_1
+ * First Order High Pass Filter
+ *
+ * r1 rF
+ * IN0 >--ZZZZ--. .------ZZZZ--------.
+ * | | |
+ * r2 | c1 | |\ |
+ * IN1 >--ZZZZ--+--||--+--------+ | \ |
+ * | '--|- \ |
+ * r3 | | >--+----------> Netlist Node
+ * vRef >--ZZZZ--' .--|+ /
+ * | | /
+ * vRef >-----------------------' |/
+ *
+ * --------------------------------------------------
+ *
+ * DISC_OP_AMP_FILTER_IS_BAND_PASS_1
+ * First Order Band Pass Filter
+ *
+ * c1
+ * .-------||---------.
+ * | |
+ * r1 | rF |
+ * IN0 >--ZZZZ--. +------ZZZZ--------+
+ * | | |
+ * r2 | c2 | |\ |
+ * IN1 >--ZZZZ--+--||--+--------+ | \ |
+ * | '--|- \ |
+ * r3 | | >--+----------> Netlist Node
+ * vRef >--ZZZZ--' .--|+ /
+ * | | /
+ * vRef >-----------------------' |/
+ *
+ * --------------------------------------------------
+ *
+ * DISC_OP_AMP_FILTER_IS_BAND_PASS_1M
+ * Single Pole Multiple Feedback Band Pass Filter
+ *
+ * c1
+ * .--||----+---------.
+ * | | |
+ * r1 | Z |
+ * IN0 >--ZZZZ--. | Z rF |
+ * | | Z |
+ * r2 | | c2 | |\ |
+ * IN1 >--ZZZZ--+------+--||----+ | \ |
+ * | '--|- \ |
+ * r3 | | >--+----------> Netlist Node
+ * vRef >--ZZZZ--' .--|+ /
+ * | | /
+ * vRef >-----------------------' |/
+ *
+ * EXAMPLES: see Tank 8, Atari Baseball, Monte Carlo
+ *
+ * --------------------------------------------------
+ *
+ * DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON
+ * Single Pole Multiple Feedback Band Pass Filter
+ *
+ * c1
+ * .--||----+---------.
+ * | | |
+ * | Z |
+ * | Z rF |
+ * | Z |
+ * r1 | c2 | |\ |
+ * IN0 >--ZZZZ--+------+--||----+ | \ |
+ * | '--|- \ |
+ * r2 | | >--+----------> Netlist Node
+ * vRef >--ZZZZ--' .--|+ /
+ * r3 | | /
+ * vP >-----------ZZZZ--------' |/
+ *
+ * EXAMPLES: see Space Encounter
+ *
+ * --------------------------------------------------
+ *
+ * DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON
+ * Basic Norton High Pass Filter
+ *
+ * rF
+ * r1 = r1a + r1b .--ZZZZ---.
+ * | |
+ * r1a c1 r1b | |\ |
+ * IN1 >--ZZZZ---||---ZZZZ------+ | \ |
+ * '--|- \ |
+ * | >--+----------> Netlist Node
+ * .--|+ /
+ * r4 | | /
+ * vRef >------------ZZZZ-------' |/
+ *
+ * EXAMPLES: see Polaris
+*
+ * --------------------------------------------------
+ *
+ * DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON
+ * Basic Norton Band Pass Filter
+ *
+ * rF
+ * r3 = r3a + r3b .--ZZZZ---.
+ * | |
+ * r1 r2 r3a c3 r3b | |\ |
+ * IN1 >---ZZZZ--+--ZZZZ--+--ZZZZ---||----ZZZZ---+ | \ |
+ * | | '--|- \ |
+ * --- --- | >--+---> Netlist Node
+ * --- c1 --- c2 .--|+ /
+ * | | | | /
+ * gnd gnd | |/
+ * r4 |
+ * vRef >--------------------------------ZZZZ----'
+ *
+ * EXAMPLES: see Polaris
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_RCDISC - Simple single pole RC discharge network
+ *
+ * .------------.
+ * | |
+ * ENAB -0------>| RC |
+ * | |
+ * INPUT1 -1------>| -ZZZZ-+-- |
+ * | R | |----> Netlist node
+ * RVAL -2------>| --- |
+ * | ---C |
+ * CVAL -3------>| | |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_RCFILTER(name of node,
+ * enable,
+ * input node (or value),
+ * resistor value in OHMS,
+ * capacitor value in FARADS)
+ *
+ * Example config line
+ *
+ * DISCRETE_RCDISC(NODE_11,NODE_10,10,100,CAP_U(1))
+ *
+ * When enabled by NODE_10, C discharges from 10v as indicated by RC
+ * of 100R & 1uF.
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_RCDISC2 - Switched input RC discharge network
+ *
+ * .------------.
+ * | |
+ * SWITCH -0------>| IP0 | IP1 |
+ * | |
+ * INPUT0 -1------>| -ZZZZ-. |
+ * | R0 | |
+ * RVAL0 -2------>| | |
+ * | | |
+ * INPUT1 -3------>| -ZZZZ-+-- |
+ * | R1 | |----> Netlist node
+ * RVAL1 -4------>| --- |
+ * | ---C |
+ * CVAL -5------>| | |
+ * | |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_RCDISC2(name of node,
+ * switch,
+ * input0 node (or value),
+ * resistor0 value in OHMS,
+ * input1 node (or value),
+ * resistor1 value in OHMS,
+ * capacitor value in FARADS)
+ *
+ * Example config line
+ *
+ * DISCRETE_RCDISC2(NODE_9,NODE_10,10.0,100,0.0,100,CAP_U(1))
+ *
+ * When switched by NODE_10, C charges/discharges from 10v/0v
+ * as dictated by R0/C & R1/C combos respectively
+ * of 100R & 1uF.
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_RCDISC3 - RC discharge network
+ *
+ * .-----------------.
+ * | |
+ * ENAB -0------>| |
+ * | diode R2 |
+ * INPUT1 -1------>| -+-|<|--ZZZZ-+- |----> Netlist node
+ * | | | |
+ * RVAL1 -2------>| '-ZZZZ-+----' |
+ * | R1 | |
+ * RVAL2 -3------>| --- |
+ * | ---C |
+ * CVAL -4------>| | |
+ * | gnd |
+ * '-----------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_RCDISC3(name of node,
+ * enable,
+ * input node (or value),
+ * R1 resistor value in OHMS,
+ * R2 resistor value in OHMS,
+ * capacitor value in FARADS)
+ *
+ * Example config line
+ *
+ * DISCRETE_RCDISC3(NODE_11,NODE_10,10,100,220,CAP_U(1))
+ *
+ * When enabled by NODE_10, C charges from 10v as indicated by RC
+ * of 100R & 1uF.
+ *
+ * EXAMPLES: see Tank8
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_RCDISC4 - RC discharge networks triggered by logic levels
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_RCDISC4(name of node,
+ * enable,
+ * logic input node,
+ * R1 resistor static value in OHMS,
+ * R2 resistor static value in OHMS,
+ * R3 resistor static value in OHMS,
+ * C1 capacitor static value in FARADS,
+ * vP static value in VOLTS,
+ * circuit type static value)
+ *
+ * Type: 1
+ *
+ * vP >---.
+ * | .------.
+ * Z | |
+ * Z R2 | |\ |
+ * O.C. Z '-|-\ |
+ * |\ Diode R1 | | >-+---> node
+ * Input >---| o----|<|------ZZZZ---+--------+-------|+/
+ * |/ | | |/
+ * --- -----
+ * C1 --- \ / Diode
+ * | V
+ * gnd ---
+ * |
+ * Z
+ * Z R3
+ * Z
+ * |
+ * gnd
+ *
+ * EXAMPLES: see Phoenix
+ *
+ * --------------------------------------------------
+ *
+ * Type: 2
+ *
+ * 5V >---. .------.
+ * Z | |
+ * Z 1k | |\ |
+ * Z '-|-\ |
+ * | R1 C1 Diode | >-+---> node
+ * Input >---+--ZZZZ----||----+-----|>|----+--------|+/
+ * | | |/
+ * ----- Z
+ * ^ Z R2
+ * / \ Diode Z
+ * ----- |
+ * | gnd
+ * gnd
+ *
+ * EXAMPLES: see
+ *
+ * --------------------------------------------------
+ *
+ * Type: 3
+ *
+ * 5V >---. .------.
+ * Z | |
+ * Z 1k | |\ |
+ * Z '-|-\ |
+ * | R1 Diode | >-+---> node
+ * Input >---+--ZZZZ-----|>|------+---------+--------|+/
+ * | | |/
+ * --- C1 Z
+ * --- Z R2
+ * | Z
+ * gnd |
+ * gnd
+ *
+ *
+ * EXAMPLES: see
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_RCDISC5 - Diode in series with R//C
+ *
+ * .---------------.
+ * | |
+ * ENAB -0------>| |
+ * | |
+ * INPUT1 -1------>| -|>|--+---+- |
+ * | | | |----> Netlist node
+ * RVAL -2------>| --- Z |
+ * | C--- Z R |
+ * CVAL -3------>| | Z |
+ * | --+-- |
+ * | |gnd |
+ * '---------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_RCDISC5(name of node,
+ * enable,
+ * input node (or value),
+ * resistor value in OHMS,
+ * capacitor value in FARADS)
+ *
+ * Example config line
+ *
+ * DISCRETE_RCDISC5(NODE_11,NODE_10,10,100,CAP_U(1))
+ *
+ * When enabled by NODE_10, C discharges from 10v as indicated by RC
+ * of 100R & 1uF.
+ *
+ * EXAMPLES: see Spiders
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_RCDISC_MODULATED - RC triggered by logic and modulated
+ *
+ * vP >---.
+ * |
+ * Z
+ * Z R1
+ * O.C. Z
+ * |\ | R2 C1 R3
+ * INPUT1 >---| o---+--ZZZ---||------+----+---ZZZ------+---> node
+ * |/ | | /
+ * / \ Z |/
+ * Diode ----- Z R4 .---| NPN
+ * | Z | |\
+ * | | | >
+ * gnd gnd | |
+ * | gnd
+ * INPUT2 >----------ZZZ------------------------.
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_RCDISC_MODULATED(name of node,
+ * enable,
+ * INPUT1 node (or value),
+ * INPUT2 node (or value),
+ * R1 value in OHMS,
+ * R2 value in OHMS,
+ * R3 value in OHMS,
+ * R4 value in OHMS,
+ * C1 value in FARADS,
+ * vP value in VOLTS)
+ *
+ * EXAMPLES: dkong
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_RCINTEGRATE - RC integration circuit/amplifier
+ *
+ *
+ * vP >-------------------+
+ * |
+ * Z
+ * Z R3
+ * Z
+ * |
+ * +-----------------> node (Type 3)
+ * /
+ * |/
+ * INPUT >---------------| NPN
+ * \ .--------------> node (Type 2)
+ * > | R1
+ * +--+--ZZZ-+-------> node (Type 1)
+ * | |
+ * Z ---
+ * Z R2 C---
+ * Z |
+ * | |
+ * gnd gnd
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_RCINTEGRATE(name of node,
+ * enable,
+ * INPUT node (or value),
+ * R1 value in OHMS,
+ * R2 value in OHMS,
+ * R3 value in OHMS,
+ * C value in FARADS,
+ * vP node (or value in VOLTS)
+ * TYPE)
+ *
+ * TYPE: RC_INTEGRATE_TYPE1, RC_INTEGRATE_TYPE2, RC_INTEGRATE_TYPE3
+ *
+ * Actually an amplifier as well. Primary reason for implementation was integration.
+ * The integration configuration (TYPE3, R3=0) works quite well, the amplifying
+ * configuration is missing a good, yet simple ( :-) ) transistor model. Around the
+ * defined working point the amplifier delivers results.
+ *
+ * EXAMPLES: dkong
+ *
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_RCFILTER - Simple single pole RC filter network (vRef = 0)
+ * DISCRETE_RCFILTER_VREF - Same but refrenced to vRef not 0V
+ *
+ * .------------.
+ * | |
+ * ENAB -0------}| RC FILTER |
+ * | |
+ * INPUT1 -1------}| -ZZZZ-+-- |
+ * | R | |----} Netlist node
+ * RVAL -2------}| --- |
+ * | ---C |
+ * CVAL -3------}| | |
+ * | vRef |
+ * '------------'
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_RCFILTER(name of node,
+ * enable
+ * input node (or value)
+ * resistor value in OHMS
+ * capacitor value in FARADS)
+ *
+ * DISCRETE_RCFILTER_VREF(name of node,
+ * enable
+ * input node (or value)
+ * resistor value in OHMS
+ * capacitor value in FARADS,
+ * vRef static value)
+ *
+ * Example config line
+ *
+ * DISCRETE_RCFILTER(NODE_11,1,NODE_10,100,CAP_U(1))
+ *
+ * Defines an always enabled RC filter with a 100R & 1uF network
+ * the input is fed from NODE_10.
+ *
+ * This can be also thought of as a low pass filter with a 3dB cutoff
+ * at:
+ * 1
+ * Fcuttoff = --------------
+ * 2*Pi*RVAL*CVAL
+ *
+ * (3dB cutoff is where the output power has dropped by 3dB ie Half)
+ *
+ * EXAMPLES: see Polaris
+ *
+ ***********************************************************************
+ =======================================================================
+ * from from disc_flt.c
+ * Component specific modules
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_555_ASTABLE - NE555 Chip simulation (astable mode).
+ * DISCRETE_555_ASTABLE_CV - NE555 Chip simulation (astable mode) with CV control.
+ *
+ * v555
+ * |
+ * .---------+
+ * | |
+ * Z |8
+ * R1 Z .---------.
+ * | 7| Vcc |
+ * +-----|Discharge|
+ * | | |
+ * Z | 555 |3
+ * R2 Z | Out|---> Netlist Node
+ * | 6| |
+ * +-----|Threshold|
+ * | | |
+ * +-----|Trigger |
+ * | 2| |---< Control Voltage
+ * | | Reset |5
+ * | '---------'
+ * --- 4|
+ * C --- |
+ * | ^
+ * gnd Reset
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_555_ASTABLE(name of node,
+ * reset node (or value),
+ * R1 node (or value) in ohms,
+ * R2 node (or value) in ohms,
+ * C node (or value) in farads,
+ * address of discrete_555_desc structure)
+ *
+ * DISCRETE_555_ASTABLE_CV(name of node,
+ * reset node (or value),
+ * R1 node (or value) in ohms,
+ * R2 node (or value) in ohms,
+ * C node (or value) in farads,
+ * Control Voltage node (or value),
+ * address of discrete_555_desc structure)
+ *
+ * discrete_555_desc =
+ * {
+ * options, // bit mapped options
+ * v555, // B+ voltage of 555
+ * v555high, // High output voltage of 555 (Usually v555 - 1.2V)
+ * threshold555, // normally 2/3 of v555
+ * trigger555 // normally 1/3 of v555
+ * }
+ *
+ * The last 3 options of discrete_555_desc can use the following defaults
+ * unless otherwise needed.
+ * DEFAULT_555_HIGH, DEFAULT_555_THRESHOLD, DEFAULT_555_TRIGGER
+ * or all 3 combined as:
+ * DEFAULT_555_VALUES
+ *
+ * eg. {DISC_555_OUT_DC | DISC_555_OUT_SQW, 12, DEFAULT_555_VALUES}
+ *
+ * Output Types:
+ * DISC_555_OUT_DC - Output is actual DC. (DEFAULT)
+ * DISC_555_OUT_AC - A cheat to make the waveform AC.
+ *
+ * Waveform Types: (ORed with output types)
+ * DISC_555_OUT_SQW - Output is Squarewave. 0 or v555high. (DEFAULT)
+ * When the state changes from low to high (or high to low)
+ * during a sample, the output will high (or low) for that
+ * sample. This can cause alaising effects.
+ * DISC_555_OUT_CAP - Output is Timing Capacitor 'C' voltage.
+ * DISC_555_OUT_COUNT_F - If the 555 frequency is greater then half the sample
+ * rate, then the output may change state more then once
+ * during the sample. Using this flag will cause
+ * the output to be the number of falling edges that
+ * happened during the sample. This is usefull to feed
+ * to counter circuits. The Output Type flag is ingnored
+ * when this flag is used.
+ * DISC_555_OUT_COUNT_R - Same as DISC_555_OUT_COUNT_F but with rising edges.
+ * DISC_555_OUT_ENERGY - Same SQW, but will help reduce aliasing effects.
+ * This should be used when the 555 squarewave output is used
+ * as a final output and not as a clock source.
+ * If the state changes from low to high 1/4 of the way
+ * through the sample, then the output will be 75% of the
+ * normal high value.
+ * DISC_555_OUT_LOGIC_X - This will output the 0/1 level of the flip-flop with
+ * some eXtra info. This X info is in decimal remainder.
+ * It lets you know the percent of sample time where the
+ * flip-flop changed state. If 0, the change did not happen
+ * during the sample. 1.75 means the flip-flop is 1 and
+ * switched over 1/4 of the way through the sample.
+ * 0.2 means the flip-flop is 0 and switched over 4/5 of
+ * the way through the sample.
+ * X modules can be used with counters to reduce alaising.
+ * DISC_555_OUT_COUNT_F_X - Same as DISC_555_OUT_COUNT_F but with X info.
+ * DISC_555_OUT_COUNT_R_X - Same as DISC_555_OUT_COUNT_R but with X info.
+ *
+ * other options - DISCRETE_555_ASTABLE only:
+ * DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE - diode used to bypass rDischarge
+ * when charging for quicker charge.
+ *
+ * EXAMPLES: see Hit Me, Canyon Bomber, Sky Diver
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_555_MSTABLE - NE555 Chip simulation (monostable mode)
+ * - Triggered on falling edge.
+ *
+ * v555
+ * |
+ * .---------+
+ * | |
+ * Z |
+ * R Z .---------.
+ * | | Vcc |
+ * +-----|Discharge|
+ * | | |
+ * | | 555 |
+ * | | Out|---> Netlist Node
+ * | | |
+ * +-----|Threshold|
+ * | | |
+ * | | Trigger|--------< Trigger
+ * | | CV|---.
+ * | | Reset | |
+ * | '---------' --- not
+ * --- | --- needed
+ * C --- | |
+ * | ^ gnd
+ * gnd Reset
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_555_MSTABLE(name of node,
+ * reset node (or value),
+ * Trigger node,
+ * R node (or value) in ohms,
+ * C node (or value) in farads,
+ * address of discrete_555_desc structure)
+ *
+ * Trigger Types
+ * DISC_555_TRIGGER_IS_LOGIC - Input is (0 or !0) logic (DEFAULT)
+ * DISC_555_TRIGGER_IS_VOLTAGE - Input is actual voltage.
+ * Voltage must drop below
+ * trigger555 to activate.
+ * DISC_555_TRIGGER_DISCHARGES_CAP - some circuits connect an external
+ * device (transistor) to the cap to
+ * discharge it when the trigger is
+ * enabled. Thereby allowing the one-shot
+ * to retrigger.
+ *
+ * Output Types: (ORed with trigger types)
+ * DISC_555_OUT_DC - Output is actual DC. (DEFAULT)
+ * DISC_555_OUT_AC - A cheat to make the waveform AC.
+ *
+ * Waveform Types: (ORed with trigger types)
+ * DISC_555_OUT_SQW - Output is Squarewave. 0 or v555high. (DEFAULT)
+ * DISC_555_OUT_CAP - Output is Timing Capacitor 'C' voltage.
+ *
+ * EXAMPLES: see Frogs
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_555_CC - Constant Current Controlled 555 Oscillator
+ * Which works out to a VCO when R is fixed.
+ *
+ * vCCsource v555
+ * V V
+ * | .----------------------+
+ * | | |
+ * | | .---------.
+ * | | rDischarge | Vcc |
+ * Z Z .---+-----|Discharge|
+ * Z R Z rBias | | | |
+ * | | | Z | 555 |
+ * | | | Z | Out|---> Netlist Node
+ * .----. | >-' | | |
+ * Vin >--| CC |--+--> option +-----|Threshold|
+ * '----' >-----+ | |
+ * +-----|Trigger |
+ * | | |
+ * .------+-----' | Reset |
+ * | | '---------'
+ * --- Z |
+ * --- C Z rGnd |
+ * | | ^
+ * gnd gnd Reset
+ *
+ * Notes: R sets the current and should NEVER be 0 (short).
+ * The current follows the voltage I=Vin/R and charges C.
+ * rBias, rDischarge and rGnd should be 0 if not used.
+ * Reset is active low for the module.
+ *
+ * Note that the CC source can be connected two different ways.
+ * See the option flags below for more info.
+ *
+ * DISC_555_OUT_SQW mode only:
+ * When there is no rDischarge there is a very short discharge
+ * cycle (almost 0s), so the module triggers the output for 1
+ * sample. This does not effect the timing, just the duty cycle.
+ * But frequencies more the half the sample frequency will be
+ * limited to a max of half the sample frequency.
+ * This mode should be used to drive a counter for any real use.
+ * Just like the real thing.
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_555_CC(name of node,
+ * reset node or static value,
+ * Vin node or static value,
+ * R node or static value,
+ * C node or static value,
+ * rBias node or static value,
+ * rGnd node or static value,
+ * rDischarge node or static value,
+ * address of discrete_555_cc_desc structure)
+ *
+ * discrete_555_cc_desc =
+ * {
+ * options, // bit mapped options
+ * v555, // B+ voltage of 555
+ * v555high, // High output voltage of 555 (Usually v555 - 1.2V)
+ * threshold555, // normally 2/3 of v555
+ * trigger555, // normally 1/3 of v555
+ * vCCsource, // B+ voltage of the Constant Current source
+ * vCCjunction // The voltage drop of the Constant Current source transitor (0 if Op Amp)
+ * }
+ *
+ * Output Types:
+ * See DISCRETE_555_ASTABLE for description.
+ *
+ * Waveform Types: (ORed with output types)
+ * See DISCRETE_555_ASTABLE for description.
+ *
+ * Other Flags:
+ * DISCRETE_555_CC_TO_DISCHARGE_PIN - The CC source connects to the
+ * discharge pin. (Default)
+ * DISCRETE_555_CC_TO_CAP - The CC source connects to the
+ * threshold pin. This is not fully
+ * implemented yet. It only works properly
+ * when only rDischarge is defined.
+ *
+ * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_555_VCO1 - Op-Amp based 555 VCO circuit.
+ * DISCRETE_555_VCO1_CV - Op-Amp based 555 VCO circuit with CV control.
+ *
+ * c
+ * .------------------------+---||----+---------------------------> DISC_555_OUT_CAP
+ * | | |
+ * | | |\ |
+ * | r1 | | \ | .------------.
+ * | vIn1 >--+--ZZZZ-------+---|- \ | | |
+ * | | | >-+---+--|Threshold |
+ * | | r2 |+ / | | Out|------> DISC_555_OUT_xx
+ * Z '--ZZZZ--+--------| / '--|Trigger |
+ * Z r4 | |/ | |
+ * Z Z | Reset|------< Reset
+ * | Z r3 vIn2 >--|CV |
+ * .----. Z | |
+ * | En|<--------. | .---|Discharge |
+ * '----' | gnd | '------------'
+ * | | |
+ * gnd '-----------------------+---ZZZZ------> 5V
+ * rX
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_555_VCO1(name of node,
+ * reset node or static value,
+ * Vin1 node or static value,
+ * address of discrete_555_vco1_desc structure)
+ *
+ * DISCRETE_555_VCO1_CV(name of node,
+ * reset node or static value,
+ * Vin1 node or static value,
+ * Vin2 (CV) node or static value,
+ * address of discrete_555_vco1_desc structure)
+ *
+ * discrete_555_vco1_desc = {options, // bit mapped options
+ * r1, r2, r3, r4, c,
+ * v555, // B+ voltage of 555
+ * v555high, // High output voltage of 555 (Usually v555 - 1.2V)
+ * threshold555, // normally 2/3 of v555
+ * trigger555} // normally 1/3 of v555
+ *
+ * Notes: The value of resistor rX is not needed. It is just a pull-up
+ * for the discharge output.
+ * The 'En' block can be a transistor or 4066 switch. It connects
+ * r4 to ground when En is high.
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_566 - NE566 VCO simulation.
+ *
+ * vPlus
+ * V
+ * .-------------+
+ * | |
+ * | R .-------.
+ * '---/\/\--|6 8 |
+ * | |
+ * vMod >------------|5 3/4|---------> Netlist Node
+ * | |
+ * .---|7 1 |
+ * | '-------'
+ * --- |
+ * --- C |
+ * | |
+ * vNeg vNeg
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_566(name of node,
+ * enable node or static value,
+ * R node or static value in ohms,
+ * C node or static value in Farads,
+ * vMod node or static value,
+ * address of discrete_566_desc structure)
+ *
+ * discrete_566_desc = {options, vPlus, vNeg}
+ *
+ * Output Types:
+ * DISC_566_OUT_DC - Output is actual DC. (DEFAULT)
+ * DISC_566_OUT_AC - A cheat to make the waveform AC.
+ *
+ * Waveform Types:
+ * DISC_566_OUT_SQUARE - Pin 3 Square Wave Output (DEFAULT)
+ * DISC_566_OUT_TRIANGLE - Pin 4 Triangle Wave Output
+ * DISC_566_OUT_LOGIC - Internal Flip/Flop Output
+ *
+ ***********************************************************************
+ *
+ * DISCRETE_CUSTOMx - Link to custom code
+ * where x = 1 to 5
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_CUSTOMx(name of node,
+ * enable node or static value,
+ * input 0 node or static value, ...)
+ *
+ * discrete_custom_info = {reset, step, contextsize, custom}
+ * reset = address called to reset a node after creation or system reset
+ * step = address called to execute one time delta of output update
+ * contextsize = size of context to create
+ * custom = address of specific initialisation data
+ *
+ ***********************************************************************
+ =======================================================================
+ * Debugging modules.
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_CSVLOGx - Dump n nodes into a csv (comma separated value) file
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_CSVLOGx(node 1, ...)
+ * where x = 1 to 5
+ *
+ * WARNING: This can rapidally use up a lot of hard drive space.
+ * 48kHz sampling of 5 nodes used 217M after 80 seconds.
+ *
+ * Use this to monitor nodes while debugging the driver. You should
+ * remove these nodes from the final driver. You can use up to a maximum
+ * DISCRETE_MAX_CSVLOGS. Each file will be called discreteX_Y.csv,
+ * where X is the sndindex. Y is 0-9, in the order the file is
+ * created in the driver.
+ *
+ * This can be used to monitor how multiple nodes relate to each other.
+ * The resulting file can be imported to a spreadsheet.
+ *
+ ************************************************************************
+ *
+ * DISCRETE_WAVELOG - Dump nodes into a wav file
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_WAVELOG1(node,
+ * static gain for node)
+ *
+ * DISCRETE_WAVELOG2(left node,
+ * static gain for left node,
+ * right node,
+ * static gain for right node)
+ *
+ * Use this to monitor nodes while debugging the driver. You should
+ * remove these nodes from the final driver. You can use up to a maximum
+ * of DISCRETE_MAX_WAVELOGS. Each file will be called discreteX_Y.wav,
+ * where X is the sndindex. Y is 0-9, in the order the file is
+ * created in the driver.
+ *
+ * This can be used to monitor how a node's input affects it's output.
+ * Monitor the input trigger against the final effect, etc. The resulting
+ * file can be played/viewed etc. by music player/editor software.
+ *
+ * When logging nodes that are voltage levels, you may want to use a
+ * gain of 1000. This will make the wav sample level reflect milli-volts.
+ *
+ ************************************************************************
+ =======================================================================
+ * Must be last module.
+ =======================================================================
+ ***********************************************************************
+ *
+ * DISCRETE_OUTPUT - Single output node to Mame mixer and output
+ *
+ * .----------. .
+ * | | .-/|
+ * Netlist node -------->| OUTPUT |----| | Sound Output
+ * | | '-\|
+ * '----------' '
+ *
+ * Declaration syntax
+ *
+ * DISCRETE_OUTPUT(name of output node, gain)
+ *
+ * Example config line
+ *
+ * DISCRETE_OUTPUT(NODE_02, 1000)
+ *
+ * Output stream will be generated from the NODE_02 output stream * 1000.
+ *
+ * Multiple outputs can be used up to DISCRETE_MAX_OUTPUTS.
+ *
+ ************************************************************************/
+
+
+/*************************************
+ *
+ * Core constants
+ *
+ *************************************/
+
+#define DISCRETE_MAX_NODES 300
+#define DISCRETE_MAX_INPUTS 10
+#define DISCRETE_MAX_OUTPUTS 16
+#define DISCRETE_MAX_WAVELOGS 10
+#define DISCRETE_MAX_CSVLOGS 10
+
+
+
+/*************************************
+ *
+ * Node-specific constants
+ *
+ *************************************/
+
+#define DEFAULT_TTL_V_LOGIC_1 3.4
+
+#define DISC_LOGADJ 1.0
+#define DISC_LINADJ 0.0
+
+/* DISCRETE_COMP_ADDER types */
+#define DISC_COMP_P_CAPACITOR 0x00
+#define DISC_COMP_P_RESISTOR 0x01
+
+/* clk types */
+#define DISC_CLK_MASK 0x03
+#define DISC_CLK_ON_F_EDGE 0x00
+#define DISC_CLK_ON_R_EDGE 0x01
+#define DISC_CLK_BY_COUNT 0x02
+#define DISC_CLK_IS_FREQ 0x03
+
+#define DISC_COUNT_DOWN 0
+#define DISC_COUNT_UP 1
+
+#define DISC_COUNTER_IS_7492 0x08
+
+#define DISC_OUT_MASK 0x30
+#define DISC_OUT_DEFAULT 0x00
+#define DISC_OUT_IS_ENERGY 0x10
+#define DISC_OUT_HAS_XTIME 0x20
+
+/* Function possibilities for the LFSR feedback nodes */
+/* 2 inputs, one output */
+#define DISC_LFSR_XOR 0
+#define DISC_LFSR_OR 1
+#define DISC_LFSR_AND 2
+#define DISC_LFSR_XNOR 3
+#define DISC_LFSR_NOR 4
+#define DISC_LFSR_NAND 5
+#define DISC_LFSR_IN0 6
+#define DISC_LFSR_IN1 7
+#define DISC_LFSR_NOT_IN0 8
+#define DISC_LFSR_NOT_IN1 9
+#define DISC_LFSR_REPLACE 10
+#define DISC_LFSR_XOR_INV_IN0 11
+#define DISC_LFSR_XOR_INV_IN1 12
+
+/* LFSR Flag Bits */
+#define DISC_LFSR_FLAG_OUT_INVERT 0x01
+#define DISC_LFSR_FLAG_RESET_TYPE_L 0x00
+#define DISC_LFSR_FLAG_RESET_TYPE_H 0x02
+#define DISC_LFSR_FLAG_OUTPUT_F0 0x04
+
+/* Sample & Hold supported clock types */
+#define DISC_SAMPHOLD_REDGE 0
+#define DISC_SAMPHOLD_FEDGE 1
+#define DISC_SAMPHOLD_HLATCH 2
+#define DISC_SAMPHOLD_LLATCH 3
+
+/* Maximum number of resistors in ladder chain */
+#define DISC_LADDER_MAXRES 8
+
+/* Filter types */
+#define DISC_FILTER_LOWPASS 0
+#define DISC_FILTER_HIGHPASS 1
+#define DISC_FILTER_BANDPASS 2
+
+/* Mixer types */
+#define DISC_MIXER_IS_RESISTOR 0
+#define DISC_MIXER_IS_OP_AMP 1
+
+#define DISC_MIXER_IS_OP_AMP_WITH_RI 2 // Used only internally. Use DISC_MIXER_IS_OP_AMP
+#define DISC_MIXER_TYPE_MASK 3 // Used only internally.
+#define DISC_MIXER_HAS_R_NODE 4 // Used only internally.
+
+/* Triggered Op Amp Functions */
+enum
+{
+ DISC_OP_AMP_TRIGGER_FUNCTION_NONE,
+ DISC_OP_AMP_TRIGGER_FUNCTION_TRG0,
+ DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV,
+ DISC_OP_AMP_TRIGGER_FUNCTION_TRG1,
+ DISC_OP_AMP_TRIGGER_FUNCTION_TRG1_INV,
+ DISC_OP_AMP_TRIGGER_FUNCTION_TRG2,
+ DISC_OP_AMP_TRIGGER_FUNCTION_TRG2_INV,
+ DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_AND,
+ DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_NAND
+};
+
+
+/* Common Op Amp Flags and values */
+#define DISC_OP_AMP_IS_NORTON 0x01
+#define OP_AMP_NORTON_VBE 0.5 // This is the norton junction voltage. Used only internally.
+#define OP_AMP_VP_RAIL_OFFSET 1.5 // This is how close an op-amp can get to the vP rail. Used only internally.
+
+/* Integrate options */
+#define DISC_INTEGRATE_OP_AMP_1 0x00
+#define DISC_INTEGRATE_OP_AMP_2 0x10
+
+/* op amp 1 shot types */
+#define DISC_OP_AMP_1SHT_1 0x00
+
+/* Op Amp Filter Options */
+#define DISC_OP_AMP_FILTER_IS_LOW_PASS_1 0x00
+#define DISC_OP_AMP_FILTER_IS_HIGH_PASS_1 0x10
+#define DISC_OP_AMP_FILTER_IS_BAND_PASS_1 0x20
+#define DISC_OP_AMP_FILTER_IS_BAND_PASS_1M 0x30
+#define DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 0x40
+#define DISC_OP_AMP_FILTER_IS_BAND_PASS_0 0x50
+
+#define DISC_OP_AMP_FILTER_TYPE_MASK (0xf0 | DISC_OP_AMP_IS_NORTON) // Used only internally.
+
+/* Op Amp Oscillator Flags */
+#define DISC_OP_AMP_OSCILLATOR_1 0x00
+#define DISC_OP_AMP_OSCILLATOR_VCO_1 0x80
+#define DISC_OP_AMP_OSCILLATOR_VCO_2 0x90
+#define DISC_OP_AMP_OSCILLATOR_VCO_3 0xa0
+#define DISC_OP_AMP_OSCILLATOR_OUT_CAP 0x00
+#define DISC_OP_AMP_OSCILLATOR_OUT_SQW 0x02
+
+#define DISC_OP_AMP_OSCILLATOR_TYPE_MASK (0xf0 | DISC_OP_AMP_IS_NORTON) // Used only internally.
+
+/* Schmitt Oscillator Options */
+#define DISC_SCHMITT_OSC_IN_IS_LOGIC 0x00
+#define DISC_SCHMITT_OSC_IN_IS_VOLTAGE 0x01
+
+#define DISC_SCHMITT_OSC_ENAB_IS_AND 0x00
+#define DISC_SCHMITT_OSC_ENAB_IS_NAND 0x02
+#define DISC_SCHMITT_OSC_ENAB_IS_OR 0x04
+#define DISC_SCHMITT_OSC_ENAB_IS_NOR 0x06
+
+#define DISC_SCHMITT_OSC_ENAB_MASK 0x06 /* Bits that define output enable type.
+ * Used only internally in module. */
+
+/* 555 Common output flags */
+#define DISC_555_OUT_DC 0x00
+#define DISC_555_OUT_AC 0x10
+
+#define DISC_555_TRIGGER_IS_LOGIC 0x00
+#define DISC_555_TRIGGER_IS_VOLTAGE 0x40
+#define DISC_555_TRIGGER_DISCHARGES_CAP 0x80
+
+#define DISC_555_OUT_SQW 0x00 /* Squarewave */
+#define DISC_555_OUT_CAP 0x01 /* Cap charge waveform */
+#define DISC_555_OUT_COUNT_F 0x02 /* Falling count */
+#define DISC_555_OUT_COUNT_R 0x03 /* Rising count */
+#define DISC_555_OUT_ENERGY 0x04
+#define DISC_555_OUT_LOGIC_X 0x05
+#define DISC_555_OUT_COUNT_F_X 0x06
+#define DISC_555_OUT_COUNT_R_X 0x07
+
+#define DISC_555_OUT_MASK 0x07 /* Bits that define output type.
+ * Used only internally in module. */
+
+#define DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE 0x80
+#define DISCRETE_555_CC_TO_DISCHARGE_PIN 0x00
+#define DISCRETE_555_CC_TO_CAP 0x80
+
+/* 566 output flags */
+#define DISC_566_OUT_DC 0x00
+#define DISC_566_OUT_AC 0x01
+
+#define DISC_566_OUT_SQUARE 0x00 /* Squarewave */
+#define DISC_566_OUT_TRIANGLE 0x10 /* Triangle waveform */
+#define DISC_566_OUT_LOGIC 0x20 /* 0/1 logic output */
+
+#define DISC_566_OUT_MASK 0x30 /* Bits that define output type.
+ * Used only internally in module. */
+
+/* Oneshot types */
+#define DISC_ONESHOT_FEDGE 0x00
+#define DISC_ONESHOT_REDGE 0x01
+
+#define DISC_ONESHOT_NORETRIG 0x00
+#define DISC_ONESHOT_RETRIG 0x02
+
+#define DISC_OUT_ACTIVE_LOW 0x04
+#define DISC_OUT_ACTIVE_HIGH 0x00
+
+#define DISC_CD4066_THRESHOLD 2.75
+
+/* Integrate */
+
+#define DISC_RC_INTEGRATE_TYPE1 0x00
+#define DISC_RC_INTEGRATE_TYPE2 0x01
+#define DISC_RC_INTEGRATE_TYPE3 0x02
+
+/*************************************
+ *
+ * The discrete sound blocks as
+ * defined in the drivers
+ *
+ *************************************/
+
+struct _discrete_sound_block
+{
+ int node; /* Output node number */
+ int type; /* see defines below */
+ int active_inputs; /* Number of active inputs on this node type */
+ int input_node[DISCRETE_MAX_INPUTS];/* input/control nodes */
+ double initial[DISCRETE_MAX_INPUTS]; /* Initial values */
+ const void * custom; /* Custom function specific initialisation data */
+ const char * name; /* Node Name */
+};
+typedef struct _discrete_sound_block discrete_sound_block;
+
+/*************************************
+ *
+ * Discrete module definition
+ *
+ *************************************/
+
+typedef struct _node_description node_description;
+
+struct _discrete_module
+{
+ int type;
+ const char * name;
+ size_t contextsize;
+ void (*reset)(node_description *node); /* Called to reset a node after creation or system reset */
+ void (*step)(node_description *node); /* Called to execute one time delta of output update */
+};
+typedef struct _discrete_module discrete_module;
+
+
+/*************************************
+ *
+ * Internal structure of a node
+ *
+ *************************************/
+
+struct _node_description
+{
+ int node; /* The node's index number in the node list */
+ double output; /* The node's last output value */
+
+ int active_inputs; /* Number of active inputs on this node type */
+ int input_is_node; /* Bit Flags. 1 in bit location means input_is_node */
+ const double * input[DISCRETE_MAX_INPUTS]; /* Addresses of Input values */
+
+ discrete_module module; /* Copy of the node's module info */
+ const discrete_sound_block *block; /* Points to the node's setup block. */
+ void * context; /* Contextual information specific to this node type */
+ const char * name; /* Text name string for identification/debug */
+ const void * custom; /* Custom function specific initialisation data */
+};
+
+
+
+/*************************************
+ *
+ * Node-specific struct types
+ *
+ *************************************/
+
+struct _discrete_lfsr_desc
+{
+ int clock_type;
+ int bitlength;
+ int reset_value;
+
+ int feedback_bitsel0;
+ int feedback_bitsel1;
+ int feedback_function0; /* Combines bitsel0 & bitsel1 */
+
+ int feedback_function1; /* Combines funct0 & infeed bit */
+
+ int feedback_function2; /* Combines funct1 & shifted register */
+ int feedback_function2_mask; /* Which bits are affected by function 2 */
+
+ int flags;
+
+ int output_bit;
+};
+typedef struct _discrete_lfsr_desc discrete_lfsr_desc;
+
+
+struct _discrete_op_amp_osc_info
+{
+ int type;
+ double r1;
+ double r2;
+ double r3;
+ double r4;
+ double r5;
+ double r6;
+ double r7;
+ double r8;
+ double c;
+ double vP; // Op amp B+
+};
+typedef struct _discrete_op_amp_osc_info discrete_op_amp_osc_info;
+
+
+#define DEFAULT_7414_VALUES 1.7, 0.9, 3.4
+
+#define DEFAULT_74LS14_VALUES 1.6, 0.8, 3.4
+
+struct _discrete_schmitt_osc_desc
+{
+ double rIn;
+ double rFeedback;
+ double c;
+ double trshRise; // voltage that triggers the gate input to go high (vGate) on rise
+ double trshFall; // voltage that triggers the gate input to go low (0V) on fall
+ double vGate; // the output high voltage of the gate that gets fedback through rFeedback
+ int options; // bitmaped options
+};
+typedef struct _discrete_schmitt_osc_desc discrete_schmitt_osc_desc;
+
+
+struct _discrete_comp_adder_table
+{
+ int type;
+ double cDefault; // Default componet. 0 if not used.
+ int length;
+ double c[DISC_LADDER_MAXRES]; // Componet table
+};
+typedef struct _discrete_comp_adder_table discrete_comp_adder_table;
+
+
+struct _discrete_dac_r1_ladder
+{
+ int ladderLength; // 2 to DISC_LADDER_MAXRES. 1 would be useless.
+ double r[DISC_LADDER_MAXRES]; // Don't use 0 for valid resistors. That is a short.
+ double vBias; // Voltage Bias resistor is tied to (0 = not used)
+ double rBias; // Additional resistor tied to vBias (0 = not used)
+ double rGnd; // Resistor tied to ground (0 = not used)
+ double cFilter; // Filtering cap (0 = not used)
+};
+typedef struct _discrete_dac_r1_ladder discrete_dac_r1_ladder;
+
+
+struct _discrete_integrate_info
+{
+ int type;
+ double r1; // r1a + r1b
+ double r2; // r2a + r2b
+ double r3; // r3a + r3b
+ double c;
+ double v1;
+ double vP;
+ double f0;
+ double f1;
+ double f2;
+};
+typedef struct _discrete_integrate_info discrete_integrate_info;
+
+
+#define DISC_MAX_MIXER_INPUTS 8
+struct _discrete_mixer_desc
+{
+ int type;
+ double r[DISC_MAX_MIXER_INPUTS]; // static input resistance values. These are in series with rNode, if used.
+ int rNode[DISC_MAX_MIXER_INPUTS]; // variable resistance nodes, if needed. 0 if not used.
+ double c[DISC_MAX_MIXER_INPUTS];
+ double rI;
+ double rF;
+ double cF;
+ double cAmp;
+ double vRef;
+ double gain; // Scale value to get output close to +/- 32767
+};
+typedef struct _discrete_mixer_desc discrete_mixer_desc;
+
+
+struct _discrete_op_amp_info
+{
+ int type;
+ double r1;
+ double r2;
+ double r3;
+ double r4;
+ double c;
+ double vN; // Op amp B-
+ double vP; // Op amp B+
+};
+typedef struct _discrete_op_amp_info discrete_op_amp_info;
+
+
+struct _discrete_op_amp_1sht_info
+{
+ int type;
+ double r1;
+ double r2;
+ double r3;
+ double r4;
+ double r5;
+ double c1;
+ double c2;
+ double vN; // Op amp B-
+ double vP; // Op amp B+
+};
+typedef struct _discrete_op_amp_1sht_info discrete_op_amp_1sht_info;
+
+
+struct _discrete_op_amp_tvca_info
+{
+ double r1;
+ double r2; // r2a + r2b
+ double r3; // r3a + r3b
+ double r4;
+ double r5;
+ double r6;
+ double r7;
+ double r8;
+ double r9;
+ double r10;
+ double r11;
+ double c1;
+ double c2;
+ double c3;
+ double v1;
+ double v2;
+ double v3;
+ double vP;
+ int f0;
+ int f1;
+ int f2;
+ int f3;
+ int f4;
+ int f5;
+};
+typedef struct _discrete_op_amp_tvca_info discrete_op_amp_tvca_info;
+
+
+struct _discrete_op_amp_filt_info
+{
+ double r1;
+ double r2;
+ double r3;
+ double r4;
+ double rF;
+ double c1;
+ double c2;
+ double c3;
+ double vRef;
+ double vP;
+ double vN;
+};
+typedef struct _discrete_op_amp_filt_info discrete_op_amp_filt_info;
+
+
+#define DEFAULT_555_HIGH -1
+#define DEFAULT_555_THRESHOLD -1
+#define DEFAULT_555_TRIGGER -1
+#define DEFAULT_555_VALUES DEFAULT_555_HIGH, DEFAULT_555_THRESHOLD, DEFAULT_555_TRIGGER
+
+struct _discrete_555_desc
+{
+ int options; // bit mapped options
+ double v555; // B+ voltage of 555
+ double v555high; // High output voltage of 555 (Usually v555 - 1.2V)
+ double threshold555; // normally 2/3 of v555
+ double trigger555; // normally 1/3 of v555
+};
+typedef struct _discrete_555_desc discrete_555_desc;
+
+
+struct _discrete_555_cc_desc
+{
+ int options; // bit mapped options
+ double v555; // B+ voltage of 555
+ double v555high; // High output voltage of 555 (Usually v555 - 1.2V)
+ double threshold555; // normally 2/3 of v555
+ double trigger555; // normally 1/3 of v555
+ double vCCsource; // B+ voltage of the Constant Current source
+ double vCCjunction; // The voltage drop of the Constant Current source transitor (0 if Op Amp)
+};
+typedef struct _discrete_555_cc_desc discrete_555_cc_desc;
+
+
+struct _discrete_555_vco1_desc
+{
+ int options; // bit mapped options
+ double r1, r2, r3, r4, c;
+ double v555; // B+ voltage of 555
+ double v555high; // High output voltage of 555 (Usually v555 - 1.2V)
+ double threshold555; // normally 2/3 of v555
+ double trigger555; // normally 1/3 of v555
+};
+typedef struct _discrete_555_vco1_desc discrete_555_vco1_desc;
+
+
+struct _discrete_566_desc
+{
+ int options; // bit mapped options
+ double vPlus; // B+ voltage of 566
+ double vNeg; // B- voltage of 566
+};
+typedef struct _discrete_566_desc discrete_566_desc;
+
+
+struct _discrete_adsr
+{
+ double attack_time; /* All times are in seconds */
+ double attack_value;
+ double decay_time;
+ double decay_value;
+ double sustain_time;
+ double sustain_value;
+ double release_time;
+ double release_value;
+};
+typedef struct _discrete_adsr discrete_adsr;
+
+
+struct _discrete_custom_info
+{
+ void (*reset)(node_description *node); /* Called to reset a node after creation or system reset */
+ void (*step)(node_description *node); /* Called to execute one time delta of output update */
+ size_t contextsize;
+ const void *custom; /* Custom function specific initialisation data */
+};
+typedef struct _discrete_custom_info discrete_custom_info;
+
+
+// Taken from the transfer characteristerics diagram in CD4049UB datasheet (TI)
+// There is no default trigger point and vI-vO is a continuous function
+
+#define DEFAULT_CD40XX_VALUES(_vB) (_vB),(_vB)*0.02,(_vB)*0.98,(_vB)/5.0*1.5,(_vB)/5.0*3.5, 0.1
+
+#define DISC_OSC_INVERTER_IS_TYPE1 0x00
+#define DISC_OSC_INVERTER_IS_TYPE2 0x01
+#define DISC_OSC_INVERTER_IS_TYPE3 0x02
+#define DISC_OSC_INVERTER_IS_TYPE4 0x03
+#define DISC_OSC_INVERTER_IS_TYPE5 0x04
+#define DISC_OSC_INVERTER_TYPE_MASK 0x0F
+
+#define DISC_OSC_INVERTER_OUT_IS_LOGIC 0x10
+
+struct _discrete_inverter_osc_desc
+{
+ double vB;
+ double vOutLow;
+ double vOutHigh;
+ double vInFall; // voltage that triggers the gate input to go low (0V) on fall
+ double vInRise; // voltage that triggers the gate input to go high (vGate) on rise
+ double clamp; // voltage is clamped to -clamp ... vb+clamp if clamp>= 0;
+ int options; // bitmaped options
+};
+typedef struct _discrete_inverter_osc_desc discrete_inverter_osc_desc;
+
+
+/*************************************
+ *
+ * The node numbers themselves
+ *
+ *************************************/
+
+enum { NODE_00=0x40000000
+ , NODE_01, NODE_02, NODE_03, NODE_04, NODE_05, NODE_06, NODE_07, NODE_08, NODE_09,
+ NODE_10, NODE_11, NODE_12, NODE_13, NODE_14, NODE_15, NODE_16, NODE_17, NODE_18, NODE_19,
+ NODE_20, NODE_21, NODE_22, NODE_23, NODE_24, NODE_25, NODE_26, NODE_27, NODE_28, NODE_29,
+ NODE_30, NODE_31, NODE_32, NODE_33, NODE_34, NODE_35, NODE_36, NODE_37, NODE_38, NODE_39,
+ NODE_40, NODE_41, NODE_42, NODE_43, NODE_44, NODE_45, NODE_46, NODE_47, NODE_48, NODE_49,
+ NODE_50, NODE_51, NODE_52, NODE_53, NODE_54, NODE_55, NODE_56, NODE_57, NODE_58, NODE_59,
+ NODE_60, NODE_61, NODE_62, NODE_63, NODE_64, NODE_65, NODE_66, NODE_67, NODE_68, NODE_69,
+ NODE_70, NODE_71, NODE_72, NODE_73, NODE_74, NODE_75, NODE_76, NODE_77, NODE_78, NODE_79,
+ NODE_80, NODE_81, NODE_82, NODE_83, NODE_84, NODE_85, NODE_86, NODE_87, NODE_88, NODE_89,
+ NODE_90, NODE_91, NODE_92, NODE_93, NODE_94, NODE_95, NODE_96, NODE_97, NODE_98, NODE_99,
+ NODE_100,NODE_101,NODE_102,NODE_103,NODE_104,NODE_105,NODE_106,NODE_107,NODE_108,NODE_109,
+ NODE_110,NODE_111,NODE_112,NODE_113,NODE_114,NODE_115,NODE_116,NODE_117,NODE_118,NODE_119,
+ NODE_120,NODE_121,NODE_122,NODE_123,NODE_124,NODE_125,NODE_126,NODE_127,NODE_128,NODE_129,
+ NODE_130,NODE_131,NODE_132,NODE_133,NODE_134,NODE_135,NODE_136,NODE_137,NODE_138,NODE_139,
+ NODE_140,NODE_141,NODE_142,NODE_143,NODE_144,NODE_145,NODE_146,NODE_147,NODE_148,NODE_149,
+ NODE_150,NODE_151,NODE_152,NODE_153,NODE_154,NODE_155,NODE_156,NODE_157,NODE_158,NODE_159,
+ NODE_160,NODE_161,NODE_162,NODE_163,NODE_164,NODE_165,NODE_166,NODE_167,NODE_168,NODE_169,
+ NODE_170,NODE_171,NODE_172,NODE_173,NODE_174,NODE_175,NODE_176,NODE_177,NODE_178,NODE_179,
+ NODE_180,NODE_181,NODE_182,NODE_183,NODE_184,NODE_185,NODE_186,NODE_187,NODE_188,NODE_189,
+ NODE_190,NODE_191,NODE_192,NODE_193,NODE_194,NODE_195,NODE_196,NODE_197,NODE_198,NODE_199,
+ NODE_200,NODE_201,NODE_202,NODE_203,NODE_204,NODE_205,NODE_206,NODE_207,NODE_208,NODE_209,
+ NODE_210,NODE_211,NODE_212,NODE_213,NODE_214,NODE_215,NODE_216,NODE_217,NODE_218,NODE_219,
+ NODE_220,NODE_221,NODE_222,NODE_223,NODE_224,NODE_225,NODE_226,NODE_227,NODE_228,NODE_229,
+ NODE_230,NODE_231,NODE_232,NODE_233,NODE_234,NODE_235,NODE_236,NODE_237,NODE_238,NODE_239,
+ NODE_240,NODE_241,NODE_242,NODE_243,NODE_244,NODE_245,NODE_246,NODE_247,NODE_248,NODE_249,
+ NODE_250,NODE_251,NODE_252,NODE_253,NODE_254,NODE_255,NODE_256,NODE_257,NODE_258,NODE_259,
+ NODE_260,NODE_261,NODE_262,NODE_263,NODE_264,NODE_265,NODE_266,NODE_267,NODE_268,NODE_269,
+ NODE_270,NODE_271,NODE_272,NODE_273,NODE_274,NODE_275,NODE_276,NODE_277,NODE_278,NODE_279,
+ NODE_280,NODE_281,NODE_282,NODE_283,NODE_284,NODE_285,NODE_286,NODE_287,NODE_288,NODE_289,
+ NODE_290,NODE_291,NODE_292,NODE_293,NODE_294,NODE_295,NODE_296,NODE_297,NODE_298,NODE_299 };
+
+/* Some Pre-defined nodes for convenience */
+#define NODE_NC NODE_00
+#define NODE_SPECIAL (NODE_00+(DISCRETE_MAX_NODES))
+
+#define NODE_START NODE_00
+#define NODE_END NODE_SPECIAL
+
+
+
+/*************************************
+ *
+ * Enumerated values for Node types
+ * in the simulation
+ *
+ * DSS - Discrete Sound Source
+ * DST - Discrete Sound Transform
+ * DSD - Discrete Sound Device
+ * DSO - Discrete Sound Output
+ *
+ *************************************/
+
+enum
+{
+ DSS_NULL, /* Nothing, nill, zippo, only to be used as terminating node */
+
+ /* from disc_inp.c */
+ DSS_ADJUSTMENT, /* Adjustment node */
+ DSS_CONSTANT, /* Constant node */
+ /* Do not change or add to the next 4 without also modifying disc_inp.c */
+ DSS_INPUT_DATA, /* Input node */
+ DSS_INPUT_LOGIC, /* Input node */
+ DSS_INPUT_NOT, /* Input node */
+ DSS_INPUT_PULSE, /* Input node, single pulsed version */
+ DSS_INPUT_STREAM, /* Stream Input */
+
+ /* from disc_wav.c */
+ /* generic modules */
+ DSS_COUNTER, /* External clock Binary Counter */
+ DSS_COUNTER_FIX, /* Fixed frequency Binary Counter */
+ DSS_LFSR_NOISE, /* Cyclic/Resetable LFSR based Noise generator */
+ DSS_NOTE, /* Note Generator */
+ DSS_NOISE, /* Random Noise generator */
+ DSS_SAWTOOTHWAVE, /* Sawtooth wave generator */
+ DSS_SINEWAVE, /* Sine Wave generator */
+ DSS_SQUAREWAVE, /* Square Wave generator, adjustable frequency based */
+ DSS_SQUAREWFIX, /* Square Wave generator, fixed frequency based (faster) */
+ DSS_SQUAREWAVE2, /* Square Wave generator, time based */
+ DSS_INVERTER_OSC, /* Oscillator based on inverter circuits */
+ DSS_TRIANGLEWAVE, /* Triangle wave generator, frequency based */
+ /* Component specific */
+ DSS_OP_AMP_OSC, /* Op Amp Oscillator */
+ DSS_SCHMITT_OSC, /* Schmitt Feedback Oscillator */
+ /* Not yet implemented */
+ DSS_ADSR, /* ADSR Envelope generator */
+
+ /* from disc_mth.c */
+ /* generic modules */
+ DST_ADDER, /* C = A+B */
+ DST_CLAMP, /* Signal Clamp */
+ DST_DIVIDE, /* Gain Block, C = A/B */
+ DST_GAIN, /* Gain Block, D = (A*B) + C*/
+ DST_LOGIC_INV,
+ DST_LOGIC_AND,
+ DST_LOGIC_NAND,
+ DST_LOGIC_OR,
+ DST_LOGIC_NOR,
+ DST_LOGIC_XOR,
+ DST_LOGIC_NXOR,
+ DST_LOGIC_DFF,
+ DST_LOGIC_JKFF,
+ DST_LOOKUP_TABLE, /* return value from lookup table */
+ DST_MULTIPLEX, /* 1 of x multiplexer */
+ DST_ONESHOT, /* One-shot pulse generator */
+ DST_RAMP, /* Ramp up/down simulation */
+ DST_SAMPHOLD, /* Sample & hold transform */
+ DST_SWITCH, /* C = A or B */
+ DST_ASWITCH, /* Analog switch */
+ DST_TRANSFORM, /* Muliply math functions based on string */
+ /* Component specific */
+ DST_COMP_ADDER, /* Selectable Parallel Component Adder */
+ DST_DAC_R1, /* R1 Ladder DAC with cap smoothing */
+ DST_DIODE_MIX, /* Diode mixer */
+ DST_INTEGRATE, /* Various Integration circuits */
+ DST_MIXER, /* Final Mixing Stage */
+ DST_OP_AMP, /* Op Amp circuits */
+ DST_OP_AMP_1SHT, /* Op Amp One Shot */
+ DST_TVCA_OP_AMP, /* Triggered Op Amp Voltage controlled amplifier circuits */
+ DST_VCA, /* IC Voltage controlled amplifiers */
+// DST_DELAY, /* Phase shift/Delay line */
+
+ /* from disc_flt.c */
+ /* generic modules */
+ DST_FILTER1, /* 1st Order Filter, Low or High Pass */
+ DST_FILTER2, /* 2nd Order Filter, Low, High, or Band Pass */
+ /* Component specific */
+ DST_CRFILTER, /* RC Bypass Filter (High Pass) */
+ DST_OP_AMP_FILT, /* Op Amp filters */
+ DST_RCDISC, /* Simple RC discharge */
+ DST_RCDISC2, /* Switched 2 Input RC discharge */
+ DST_RCDISC3, /* Charge/discharge with diode */
+ DST_RCDISC4, /* various Charge/discharge circuits */
+ DST_RCDISC5, /* Diode in series with R//C */
+ DST_RCINTEGRATE, /* NPN RC charge/discharge network */
+ DST_RCDISC_MOD, /* Two diode mixer with Transistor and charge/discharge network */
+ DST_RCFILTER, /* Simple RC Filter network */
+ /* For testing - seem to be buggered. Use versions not ending in N. */
+ DST_RCFILTERN, /* Simple RC Filter network */
+ DST_RCDISCN, /* Simple RC discharge */
+ DST_RCDISC2N, /* Switched 2 Input RC discharge */
+
+ /* from disc_dev.c */
+ /* Component specific */
+ DSD_555_ASTBL, /* NE555 Astable Emulation */
+ DSD_555_MSTBL, /* NE555 Monostable Emulation */
+ DSD_555_CC, /* Constant Current 555 circuit (VCO)*/
+ DSD_555_VCO1, /* Op-Amp linear ramp based 555 VCO */
+ DSD_566, /* NE566 Emulation */
+
+ /* Custom */
+ DST_CUSTOM, /* whatever you want */
+
+ /* Debugging */
+ DSO_CSVLOG, /* Dump nodes as csv file */
+ DSO_WAVELOG, /* Dump nodes as wav file */
+
+ /* Output Node -- this must be the last entry in this enum! */
+ DSO_OUTPUT /* The final output node */
+};
+
+
+
+/*************************************
+ *
+ * Encapsulation macros for defining
+ * your simulation
+ *
+ *************************************/
+
+#define MDRV_SOUND_CONFIG_DISCRETE(name) MDRV_SOUND_CONFIG(name##_discrete_interface)
+
+#define DISCRETE_SOUND_EXTERN(name) extern const discrete_sound_block name##_discrete_interface[]
+#define DISCRETE_SOUND_START(name) const discrete_sound_block name##_discrete_interface[] = {
+#define DISCRETE_SOUND_END { NODE_00, DSS_NULL , 0, { NODE_NC }, { 0 } ,NULL ,"End Marker" } };
+
+/* from disc_inp.c */
+#define DISCRETE_ADJUSTMENT(NODE,ENAB,MIN,MAX,LOGLIN,PORT) { NODE, DSS_ADJUSTMENT , 7, { ENAB,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC }, { ENAB,MIN,MAX,LOGLIN,PORT,0 ,100 }, NULL , "DISCRETE_ADJUSTMENT" },
+#define DISCRETE_ADJUSTMENT_TAG(NODE,ENAB,MIN,MAX,LOGLIN,TAG) { NODE, DSS_ADJUSTMENT , 7, { ENAB,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC }, { ENAB,MIN,MAX,LOGLIN,0 ,0 ,100 }, TAG , "DISCRETE_ADJUSTMENT_TAG" },
+#define DISCRETE_ADJUSTMENTX(NODE,ENAB,MIN,MAX,LOGLIN,PORT,PMIN,PMAX) { NODE, DSS_ADJUSTMENT , 7, { ENAB,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC }, { ENAB,MIN,MAX,LOGLIN,PORT,PMIN,PMAX }, NULL , "DISCRETE_ADJUSTMENTX" },
+#define DISCRETE_CONSTANT(NODE,CONST) { NODE, DSS_CONSTANT , 1, { NODE_NC }, { CONST } ,NULL ,"Constant" },
+#define DISCRETE_INPUT_DATA(NODE) { NODE, DSS_INPUT_DATA , 3, { NODE_NC,NODE_NC,NODE_NC }, { 1,0,0 }, NULL, "Input Data" },
+#define DISCRETE_INPUTX_DATA(NODE,GAIN,OFFSET,INIT) { NODE, DSS_INPUT_DATA , 3, { NODE_NC,NODE_NC,NODE_NC }, { GAIN,OFFSET,INIT }, NULL, "InputX Data" },
+#define DISCRETE_INPUT_LOGIC(NODE) { NODE, DSS_INPUT_LOGIC , 3, { NODE_NC,NODE_NC,NODE_NC }, { 1,0,0 }, NULL, "Input Logic" },
+#define DISCRETE_INPUTX_LOGIC(NODE,GAIN,OFFSET,INIT) { NODE, DSS_INPUT_LOGIC , 3, { NODE_NC,NODE_NC,NODE_NC }, { GAIN,OFFSET,INIT }, NULL, "InputX Logic" },
+#define DISCRETE_INPUT_NOT(NODE) { NODE, DSS_INPUT_NOT , 3, { NODE_NC,NODE_NC,NODE_NC }, { 1,0,0 }, NULL, "Input Not" },
+#define DISCRETE_INPUTX_NOT(NODE,GAIN,OFFSET,INIT) { NODE, DSS_INPUT_NOT , 3, { NODE_NC,NODE_NC,NODE_NC }, { GAIN,OFFSET,INIT }, NULL, "InputX Not" },
+#define DISCRETE_INPUT_PULSE(NODE,INIT) { NODE, DSS_INPUT_PULSE , 3, { NODE_NC,NODE_NC,NODE_NC }, { 1,0,INIT }, NULL, "Input Pulse" },
+#define DISCRETE_INPUT_STREAM(NODE) { NODE, DSS_INPUT_STREAM, 2, { NODE_NC,NODE_NC }, { 1,0 }, NULL, "Input Stream" },
+#define DISCRETE_INPUTX_STREAM(NODE,GAIN,OFFSET) { NODE, DSS_INPUT_STREAM, 2, { NODE_NC,NODE_NC }, { GAIN,OFFSET }, NULL, "InputX Stream" },
+
+/* from disc_wav.c */
+/* generic modules */
+#define DISCRETE_COUNTER(NODE,ENAB,RESET,CLK,MAX,DIR,INIT0,CLKTYPE) { NODE, DSS_COUNTER , 7, { ENAB,RESET,CLK,NODE_NC,DIR,INIT0,NODE_NC }, { ENAB,RESET,CLK,MAX,DIR,INIT0,CLKTYPE }, NULL, "DISCRETE_COUNTER" },
+#define DISCRETE_COUNTER_7492(NODE,ENAB,RESET,CLK) { NODE, DSS_COUNTER , 7, { ENAB,RESET,CLK,NODE_NC,NODE_NC,NODE_NC,NODE_NC }, { ENAB,RESET,CLK,5,1,0,DISC_COUNTER_IS_7492 }, NULL, "DISCRETE_COUNTER_7492" },
+#define DISCRETE_LFSR_NOISE(NODE,ENAB,RESET,CLK,AMPL,FEED,BIAS,LFSRTB) { NODE, DSS_LFSR_NOISE , 6, { ENAB,RESET,CLK,AMPL,FEED,BIAS }, { ENAB,RESET,CLK,AMPL,FEED,BIAS }, LFSRTB, "LFSR Noise Source" },
+#define DISCRETE_NOISE(NODE,ENAB,FREQ,AMPL,BIAS) { NODE, DSS_NOISE , 4, { ENAB,FREQ,AMPL,BIAS }, { ENAB,FREQ,AMPL,BIAS }, NULL, "Noise Source" },
+#define DISCRETE_NOTE(NODE,ENAB,CLK,DATA,MAX1,MAX2,CLKTYPE) { NODE, DSS_NOTE , 6, { ENAB,CLK,DATA,NODE_NC,NODE_NC,NODE_NC }, { ENAB,CLK,DATA,MAX1,MAX2,CLKTYPE }, NULL, "Note Generator" },
+#define DISCRETE_SAWTOOTHWAVE(NODE,ENAB,FREQ,AMPL,BIAS,GRAD,PHASE) { NODE, DSS_SAWTOOTHWAVE, 6, { ENAB,FREQ,AMPL,BIAS,NODE_NC,NODE_NC }, { ENAB,FREQ,AMPL,BIAS,GRAD,PHASE }, NULL, "Saw Tooth Wave" },
+#define DISCRETE_SINEWAVE(NODE,ENAB,FREQ,AMPL,BIAS,PHASE) { NODE, DSS_SINEWAVE , 5, { ENAB,FREQ,AMPL,BIAS,NODE_NC }, { ENAB,FREQ,AMPL,BIAS,PHASE }, NULL, "Sine Wave" },
+#define DISCRETE_SQUAREWAVE(NODE,ENAB,FREQ,AMPL,DUTY,BIAS,PHASE) { NODE, DSS_SQUAREWAVE , 6, { ENAB,FREQ,AMPL,DUTY,BIAS,NODE_NC }, { ENAB,FREQ,AMPL,DUTY,BIAS,PHASE }, NULL, "Square Wave" },
+#define DISCRETE_SQUAREWFIX(NODE,ENAB,FREQ,AMPL,DUTY,BIAS,PHASE) { NODE, DSS_SQUAREWFIX , 6, { ENAB,FREQ,AMPL,DUTY,BIAS,NODE_NC }, { ENAB,FREQ,AMPL,DUTY,BIAS,PHASE }, NULL, "Square Wave Fixed" },
+#define DISCRETE_SQUAREWAVE2(NODE,ENAB,AMPL,T_OFF,T_ON,BIAS,TSHIFT) { NODE, DSS_SQUAREWAVE2 , 6, { ENAB,AMPL,T_OFF,T_ON,BIAS,NODE_NC }, { ENAB,AMPL,T_OFF,T_ON,BIAS,TSHIFT }, NULL, "Square Wave 2" },
+#define DISCRETE_TRIANGLEWAVE(NODE,ENAB,FREQ,AMPL,BIAS,PHASE) { NODE, DSS_TRIANGLEWAVE, 5, { ENAB,FREQ,AMPL,BIAS,NODE_NC }, { ENAB,FREQ,AMPL,BIAS,PHASE }, NULL, "Triangle Wave" },
+/* Component specific */
+#define DISCRETE_INVERTER_OSC(NODE,ENAB,MOD,RCHARGE,RP,C,R2,INFO) { NODE, DSS_INVERTER_OSC, 6, { ENAB,MOD,NODE_NC,NODE_NC,NODE_NC }, { ENAB,MOD,RCHARGE,RP,C,R2 }, INFO, "Inverter Oscillator" },
+#define DISCRETE_OP_AMP_OSCILLATOR(NODE,ENAB,INFO) { NODE, DSS_OP_AMP_OSC , 1, { ENAB }, { ENAB }, INFO, "Op Amp Oscillator" },
+#define DISCRETE_OP_AMP_VCO1(NODE,ENAB,VMOD1,INFO) { NODE, DSS_OP_AMP_OSC , 2, { ENAB,VMOD1 }, { ENAB,VMOD1 }, INFO, "Op Amp VCO 1-vMod" },
+#define DISCRETE_OP_AMP_VCO2(NODE,ENAB,VMOD1,VMOD2,INFO) { NODE, DSS_OP_AMP_OSC , 3, { ENAB,VMOD1,VMOD2 }, { ENAB,VMOD1,VMOD2 }, INFO, "Op Amp VCO 2-vMod" },
+#define DISCRETE_SCHMITT_OSCILLATOR(NODE,ENAB,INP0,AMPL,TABLE) { NODE, DSS_SCHMITT_OSC , 3, { ENAB,INP0,AMPL }, { ENAB,INP0,AMPL }, TABLE, "Schmitt Feedback Oscillator" },
+/* Not yet implemented */
+#define DISCRETE_ADSR_ENV(NODE,ENAB,TRIGGER,GAIN,ADSRTB) { NODE, DSS_ADSR , 3, { ENAB,TRIGGER,GAIN }, { ENAB,TRIGGER,GAIN }, ADSRTB, "ADSR Env Generator" },
+
+/* from disc_mth.c */
+/* generic modules */
+#define DISCRETE_ADDER2(NODE,ENAB,INP0,INP1) { NODE, DST_ADDER , 3, { ENAB,INP0,INP1 }, { ENAB,INP0,INP1 }, NULL, "Adder 2 Node" },
+#define DISCRETE_ADDER3(NODE,ENAB,INP0,INP1,INP2) { NODE, DST_ADDER , 4, { ENAB,INP0,INP1,INP2 }, { ENAB,INP0,INP1,INP2 }, NULL, "Adder 3 Node" },
+#define DISCRETE_ADDER4(NODE,ENAB,INP0,INP1,INP2,INP3) { NODE, DST_ADDER , 5, { ENAB,INP0,INP1,INP2,INP3 }, { ENAB,INP0,INP1,INP2,INP3 }, NULL, "Adder 4 Node" },
+#define DISCRETE_CLAMP(NODE,ENAB,INP0,MIN,MAX,CLAMP) { NODE, DST_CLAMP , 5, { ENAB,INP0,MIN,MAX,CLAMP }, { ENAB,INP0,MIN,MAX,CLAMP }, NULL, "Signal Clamp" },
+#define DISCRETE_DIVIDE(NODE,ENAB,INP0,INP1) { NODE, DST_DIVIDE , 3, { ENAB,INP0,INP1 }, { ENAB,INP0,INP1 }, NULL, "Divider" },
+#define DISCRETE_GAIN(NODE,INP0,GAIN) { NODE, DST_GAIN , 4, { NODE_NC,INP0,NODE_NC,NODE_NC }, { 1,INP0,GAIN,0 }, NULL, "Gain" },
+#define DISCRETE_INVERT(NODE,INP0) { NODE, DST_GAIN , 4, { NODE_NC,INP0,NODE_NC,NODE_NC }, { 1,INP0,-1,0 }, NULL, "Inverter" },
+#define DISCRETE_LOGIC_INVERT(NODE,ENAB,INP0) { NODE, DST_LOGIC_INV , 2, { ENAB,INP0 }, { ENAB,INP0 }, NULL, "Logic Invertor" },
+#define DISCRETE_LOGIC_AND(NODE,ENAB,INP0,INP1) { NODE, DST_LOGIC_AND , 5, { ENAB,INP0,INP1,NODE_NC,NODE_NC }, { ENAB,INP0,INP1,1.0,1.0 }, NULL, "Logic AND (2inp)" },
+#define DISCRETE_LOGIC_AND3(NODE,ENAB,INP0,INP1,INP2) { NODE, DST_LOGIC_AND , 5, { ENAB,INP0,INP1,INP2,NODE_NC }, { ENAB,INP0,INP1,INP2,1.0 }, NULL, "Logic AND (3inp)" },
+#define DISCRETE_LOGIC_AND4(NODE,ENAB,INP0,INP1,INP2,INP3) { NODE, DST_LOGIC_AND , 5, { ENAB,INP0,INP1,INP2,INP3 }, { ENAB,INP0,INP1,INP2,INP3 } ,NULL, "Logic AND (4inp)" },
+#define DISCRETE_LOGIC_NAND(NODE,ENAB,INP0,INP1) { NODE, DST_LOGIC_NAND , 5, { ENAB,INP0,INP1,NODE_NC,NODE_NC }, { ENAB,INP0,INP1,1.0,1.0 }, NULL, "Logic NAND (2inp)" },
+#define DISCRETE_LOGIC_NAND3(NODE,ENAB,INP0,INP1,INP2) { NODE, DST_LOGIC_NAND , 5, { ENAB,INP0,INP1,INP2,NODE_NC }, { ENAB,INP0,INP1,INP2,1.0 }, NULL, "Logic NAND (3inp)" },
+#define DISCRETE_LOGIC_NAND4(NODE,ENAB,INP0,INP1,INP2,INP3) { NODE, DST_LOGIC_NAND , 5, { ENAB,INP0,INP1,INP2,INP3 }, { ENAB,INP0,INP1,INP2,INP3 }, NULL, "Logic NAND (4inp)" },
+#define DISCRETE_LOGIC_OR(NODE,ENAB,INP0,INP1) { NODE, DST_LOGIC_OR , 5, { ENAB,INP0,INP1,NODE_NC,NODE_NC }, { ENAB,INP0,INP1,0.0,0.0 }, NULL, "Logic OR (2inp)" },
+#define DISCRETE_LOGIC_OR3(NODE,ENAB,INP0,INP1,INP2) { NODE, DST_LOGIC_OR , 5, { ENAB,INP0,INP1,INP2,NODE_NC }, { ENAB,INP0,INP1,INP2,0.0 }, NULL, "Logic OR (3inp)" },
+#define DISCRETE_LOGIC_OR4(NODE,ENAB,INP0,INP1,INP2,INP3) { NODE, DST_LOGIC_OR , 5, { ENAB,INP0,INP1,INP2,INP3 }, { ENAB,INP0,INP1,INP2,INP3 }, NULL, "Logic OR (4inp)" },
+#define DISCRETE_LOGIC_NOR(NODE,ENAB,INP0,INP1) { NODE, DST_LOGIC_NOR , 5, { ENAB,INP0,INP1,NODE_NC,NODE_NC }, { ENAB,INP0,INP1,0.0,0.0 }, NULL, "Logic NOR (2inp)" },
+#define DISCRETE_LOGIC_NOR3(NODE,ENAB,INP0,INP1,INP2) { NODE, DST_LOGIC_NOR , 5, { ENAB,INP0,INP1,INP2,NODE_NC }, { ENAB,INP0,INP1,INP2,0.0 }, NULL, "Logic NOR (3inp)" },
+#define DISCRETE_LOGIC_NOR4(NODE,ENAB,INP0,INP1,INP2,INP3) { NODE, DST_LOGIC_NOR , 5, { ENAB,INP0,INP1,INP2,INP3 }, { ENAB,INP0,INP1,INP2,INP3 }, NULL, "Logic NOR (4inp)" },
+#define DISCRETE_LOGIC_XOR(NODE,ENAB,INP0,INP1) { NODE, DST_LOGIC_XOR , 3, { ENAB,INP0,INP1 }, { ENAB,INP0,INP1 }, NULL, "Logic XOR (2inp)" },
+#define DISCRETE_LOGIC_NXOR(NODE,ENAB,INP0,INP1) { NODE, DST_LOGIC_NXOR , 3, { ENAB,INP0,INP1 }, { ENAB,INP0,INP1 }, NULL, "Logic NXOR (2inp)" },
+#define DISCRETE_LOGIC_DFLIPFLOP(NODE,ENAB,RESET,SET,CLK,INP) { NODE, DST_LOGIC_DFF , 5, { ENAB,RESET,SET,CLK,INP }, { ENAB,RESET,SET,CLK,INP }, NULL, "Logic DFlipFlop" },
+#define DISCRETE_LOGIC_JKFLIPFLOP(NODE,ENAB,RESET,SET,CLK,J,K) { NODE, DST_LOGIC_JKFF , 6, { ENAB,RESET,SET,CLK,J,K }, { ENAB,RESET,SET,CLK,J,K }, NULL, "Logic JKFlipFlop" },
+#define DISCRETE_LOOKUP_TABLE(NODE,ENAB,ADDR,SIZE,TABLE) { NODE, DST_LOOKUP_TABLE, 3, { ENAB,ADDR,NODE_NC }, { ENAB,ADDR,SIZE }, TABLE, "Lookup Table" },
+#define DISCRETE_MULTIPLEX2(NODE,ENAB,ADDR,INP0,INP1) { NODE, DST_MULTIPLEX , 4, { ENAB,ADDR,INP0,INP1 }, { ENAB,ADDR,INP0,INP1 }, NULL, "1 of 2 Multiplexer" },
+#define DISCRETE_MULTIPLEX4(NODE,ENAB,ADDR,INP0,INP1,INP2,INP3) { NODE, DST_MULTIPLEX , 6, { ENAB,ADDR,INP0,INP1,INP2,INP3 }, { ENAB,ADDR,INP0,INP1,INP2,INP3 }, NULL, "1 of 4 Multiplexer" },
+#define DISCRETE_MULTIPLEX8(NODE,ENAB,ADDR,INP0,INP1,INP2,INP3,INP4,INP5,INP6,INP7) { NODE, DST_MULTIPLEX, 10, { ENAB,ADDR,INP0,INP1,INP2,INP3,INP4,INP5,INP6,INP7 }, { ENAB,ADDR,INP0,INP1,INP2,INP3,INP4,INP5,INP6,INP7 }, NULL, "1 of 8 Multiplexer" },
+#define DISCRETE_MULTIPLY(NODE,ENAB,INP0,INP1) { NODE, DST_GAIN , 4, { ENAB,INP0,INP1,NODE_NC }, { ENAB,INP0,INP1,0 }, NULL, "Multiplier" },
+#define DISCRETE_MULTADD(NODE,ENAB,INP0,INP1,INP2) { NODE, DST_GAIN , 4, { ENAB,INP0,INP1,INP2 }, { ENAB,INP0,INP1,INP2 }, NULL, "Multiply/Add" },
+#define DISCRETE_ONESHOT(NODE,TRIG,AMPL,WIDTH,TYPE) { NODE, DST_ONESHOT , 5, { NODE_NC,TRIG,AMPL,WIDTH,NODE_NC }, { 0,TRIG,AMPL,WIDTH,TYPE }, NULL, "One Shot" },
+#define DISCRETE_ONESHOTR(NODE,RESET,TRIG,AMPL,WIDTH,TYPE) { NODE, DST_ONESHOT , 5, { RESET,TRIG,AMPL,WIDTH,NODE_NC }, { RESET,TRIG,AMPL,WIDTH,TYPE }, NULL, "One Shot Resetable" },
+#define DISCRETE_ONOFF(NODE,ENAB,INP0) { NODE, DST_GAIN , 4, { ENAB,INP0,NODE_NC,NODE_NC }, { ENAB,0,1,0 }, NULL, "OnOff Switch" },
+#define DISCRETE_RAMP(NODE,ENAB,RAMP,GRAD,START,END,CLAMP) { NODE, DST_RAMP , 6, { ENAB,RAMP,GRAD,START,END,CLAMP }, { ENAB,RAMP,GRAD,START,END,CLAMP }, NULL, "Ramp Up/Down" },
+#define DISCRETE_SAMPLHOLD(NODE,ENAB,INP0,CLOCK,CLKTYPE) { NODE, DST_SAMPHOLD , 4, { ENAB,INP0,CLOCK,NODE_NC }, { ENAB,INP0,CLOCK,CLKTYPE }, NULL, "Sample & Hold" },
+#define DISCRETE_SWITCH(NODE,ENAB,SWITCH,INP0,INP1) { NODE, DST_SWITCH , 4, { ENAB,SWITCH,INP0,INP1 }, { ENAB,SWITCH,INP0,INP1 }, NULL, "2 Pole Switch" },
+#define DISCRETE_ASWITCH(NODE,ENAB,CTRL,INP,THRESHOLD) { NODE, DST_ASWITCH , 3, { ENAB,CTRL,INP,THRESHOLD }, { ENAB,CTRL,INP, THRESHOLD}, NULL, "Analog Switch" },
+#define DISCRETE_TRANSFORM2(NODE,ENAB,INP0,INP1,FUNCT) { NODE, DST_TRANSFORM , 3, { ENAB,INP0,INP1 }, { ENAB,INP0,INP1 }, FUNCT, "Transform 2 Nodes" },
+#define DISCRETE_TRANSFORM3(NODE,ENAB,INP0,INP1,INP2,FUNCT) { NODE, DST_TRANSFORM , 4, { ENAB,INP0,INP1,INP2 }, { ENAB,INP0,INP1,INP2 }, FUNCT, "Transform 3 Nodes" },
+#define DISCRETE_TRANSFORM4(NODE,ENAB,INP0,INP1,INP2,INP3,FUNCT) { NODE, DST_TRANSFORM , 5, { ENAB,INP0,INP1,INP2,INP3 }, { ENAB,INP0,INP1,INP2,INP3 }, FUNCT, "Transform 4 Nodes" },
+#define DISCRETE_TRANSFORM5(NODE,ENAB,INP0,INP1,INP2,INP3,INP4,FUNCT) { NODE, DST_TRANSFORM , 6, { ENAB,INP0,INP1,INP2,INP3,INP4 }, { ENAB,INP0,INP1,INP2,INP3,INP4 }, FUNCT, "Transform 5 Nodes" },
+/* Component specific */
+#define DISCRETE_COMP_ADDER(NODE,ENAB,DATA,TABLE) { NODE, DST_COMP_ADDER , 2, { ENAB,DATA }, { ENAB,DATA }, TABLE, "Selectable R or C component Adder" },
+#define DISCRETE_DAC_R1(NODE,ENAB,DATA,VDATA,LADDER) { NODE, DST_DAC_R1 , 3, { ENAB,DATA,VDATA }, { ENAB,DATA,VDATA }, LADDER, "DAC with R1 Ladder" },
+#define DISCRETE_DIODE_MIXER2(NODE,ENAB,VJUNC,IN0,IN1) { NODE, DST_DIODE_MIX , 4, { ENAB,NODE_NC,IN0,IN1 }, { ENAB,VJUNC,IN0,IN1 }, NULL, "Diode Mixer 2 Stage" },
+#define DISCRETE_DIODE_MIXER3(NODE,ENAB,VJUNC,IN0,IN1,IN2) { NODE, DST_DIODE_MIX , 5, { ENAB,NODE_NC,IN0,IN1,IN2 }, { ENAB,VJUNC,IN0,IN1,IN2 }, INFO, "Diode Mixer 3 Stage" },
+#define DISCRETE_DIODE_MIXER4(NODE,ENAB,VJUNC,IN0,IN1,IN2,IN3) { NODE, DST_DIODE_MIX , 6, { ENAB,NODE_NC,IN0,IN1,IN2,IN3 }, { ENAB,VJUNC,IN0,IN1,IN2,IN3 }, INFO, "Diode Mixer 4 Stage" },
+#define DISCRETE_INTEGRATE(NODE,TRG0,TRG1,INFO) { NODE, DST_INTEGRATE , 2, { TRG0,TRG1 }, { TRG0,TRG1 }, INFO, "Various Integraton Circuit" },
+#define DISCRETE_MIXER2(NODE,ENAB,IN0,IN1,INFO) { NODE, DST_MIXER , 3, { ENAB,IN0,IN1 }, { ENAB,IN0,IN1 }, INFO, "Final Mixer 2 Stage" },
+#define DISCRETE_MIXER3(NODE,ENAB,IN0,IN1,IN2,INFO) { NODE, DST_MIXER , 4, { ENAB,IN0,IN1,IN2 }, { ENAB,IN0,IN1,IN2 }, INFO, "Final Mixer 3 Stage" },
+#define DISCRETE_MIXER4(NODE,ENAB,IN0,IN1,IN2,IN3,INFO) { NODE, DST_MIXER , 5, { ENAB,IN0,IN1,IN2,IN3 }, { ENAB,IN0,IN1,IN2,IN3 }, INFO, "Final Mixer 4 Stage" },
+#define DISCRETE_MIXER5(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,INFO) { NODE, DST_MIXER , 6, { ENAB,IN0,IN1,IN2,IN3,IN4 }, { ENAB,IN0,IN1,IN2,IN3,IN4 }, INFO, "Final Mixer 5 Stage" },
+#define DISCRETE_MIXER6(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,INFO) { NODE, DST_MIXER , 7, { ENAB,IN0,IN1,IN2,IN3,IN4,IN5 }, { ENAB,IN0,IN1,IN2,IN3,IN4,IN5 }, INFO, "Final Mixer 6 Stage" },
+#define DISCRETE_MIXER7(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,INFO) { NODE, DST_MIXER , 8, { ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6 }, { ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6 }, INFO, "Final Mixer 7 Stage" },
+#define DISCRETE_MIXER8(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,INFO) { NODE, DST_MIXER , 9, { ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7 }, { ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7 }, INFO, "Final Mixer 8 Stage" },
+#define DISCRETE_OP_AMP(NODE,ENAB,IN0,IN1,INFO) { NODE, DST_OP_AMP , 3, { ENAB,IN0,IN1 }, { ENAB,IN0,IN1 }, INFO, "Op Amp Circuit" },
+#define DISCRETE_OP_AMP_ONESHOT(NODE,TRIG,INFO) { NODE, DST_OP_AMP_1SHT , 1, { TRIG }, { TRIG }, INFO, "Op Amp One Shot" },
+#define DISCRETE_OP_AMP_TRIG_VCA(NODE,TRG0,TRG1,TRG2,IN0,IN1,INFO) { NODE, DST_TVCA_OP_AMP , 5, { TRG0,TRG1,TRG2,IN0,IN1 }, { TRG0,TRG1,TRG2,IN0,IN1 }, INFO, "Triggered VCA Op Amp Circuit" },
+#define DISCRETE_VCA(NODE,ENAB,IN0,CTRL,TYPE) { NODE, DST_VCA , 4, { ENAB,IN0,CTRL,NODE_NC }, { ENAB,IN0,CTRL,TYPE }, NULL, "VCA IC" },
+
+/* from disc_flt.c */
+/* generic modules */
+#define DISCRETE_FILTER1(NODE,ENAB,INP0,FREQ,TYPE) { NODE, DST_FILTER1 , 4, { ENAB,INP0,NODE_NC,NODE_NC }, { ENAB,INP0,FREQ,TYPE }, NULL, "1st Order Filter" },
+#define DISCRETE_FILTER2(NODE,ENAB,INP0,FREQ,DAMP,TYPE) { NODE, DST_FILTER2 , 5, { ENAB,INP0,NODE_NC,NODE_NC,NODE_NC }, { ENAB,INP0,FREQ,DAMP,TYPE }, NULL, "2nd Order Filter" },
+/* Component specific */
+#define DISCRETE_CRFILTER(NODE,ENAB,INP0,RVAL,CVAL) { NODE, DST_CRFILTER , 4, { ENAB,INP0,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL,CVAL }, NULL, "CR Filter" },
+#define DISCRETE_CRFILTER_VREF(NODE,ENAB,INP0,RVAL,CVAL,VREF) { NODE, DST_CRFILTER , 5, { ENAB,INP0,NODE_NC,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL,CVAL,VREF }, NULL, "CR Filter to VREF" },
+#define DISCRETE_OP_AMP_FILTER(NODE,ENAB,INP0,INP1,TYPE,INFO) { NODE, DST_OP_AMP_FILT , 4, { ENAB,INP0,INP1,NODE_NC }, { ENAB,INP0,INP1,TYPE }, INFO, "Op Amp Filter" },
+#define DISCRETE_RCDISC(NODE,ENAB,INP0,RVAL,CVAL) { NODE, DST_RCDISC , 4, { ENAB,INP0,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL,CVAL }, NULL, "RC Discharge" },
+#define DISCRETE_RCDISC2(NODE,SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL) { NODE, DST_RCDISC2 , 6, { SWITCH,INP0,NODE_NC,INP1,NODE_NC,NODE_NC }, { SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL }, NULL, "RC Discharge 2" },
+#define DISCRETE_RCDISC3(NODE,ENAB,INP0,RVAL0,RVAL1,CVAL) { NODE, DST_RCDISC3 , 5, { ENAB,INP0,NODE_NC,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL0,RVAL1,CVAL }, NULL, "RC Discharge 3" },
+#define DISCRETE_RCDISC4(NODE,ENAB,INP0,RVAL0,RVAL1,RVAL2,CVAL,VP,TYPE) { NODE, DST_RCDISC4 , 8, { ENAB,INP0,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL0,RVAL1,RVAL2,CVAL,VP,TYPE }, NULL, "RC Discharge 4" },
+#define DISCRETE_RCDISC5(NODE,ENAB,INP0,RVAL,CVAL) { NODE, DST_RCDISC5 , 4, { ENAB,INP0,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL,CVAL }, NULL, "RC Discharge 5" },
+#define DISCRETE_RCINTEGRATE(NODE,ENAB,INP0,RVAL0,RVAL1,RVAL2,CVAL,vP,TYPE) { NODE, DST_RCINTEGRATE , 8, { ENAB,INP0,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL0,RVAL1,RVAL2,CVAL,vP,TYPE }, NULL, "RC Discharge 6" },
+#define DISCRETE_RCDISC_MODULATED(NODE,ENAB,INP0,INP1,RVAL0,RVAL1,RVAL2,RVAL3,CVAL,VP) { NODE, DST_RCDISC_MOD , 9, { ENAB,INP0,INP1,RVAL0,RVAL1,RVAL2,RVAL3,CVAL,VP }, { ENAB,INP0,INP1,RVAL0,RVAL1,RVAL2,RVAL3,CVAL,VP }, NULL, "Modulated RC Discharge" },
+#define DISCRETE_RCFILTER(NODE,ENAB,INP0,RVAL,CVAL) { NODE, DST_RCFILTER , 4, { ENAB,INP0,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL,CVAL }, NULL, "RC Filter" },
+#define DISCRETE_RCFILTER_VREF(NODE,ENAB,INP0,RVAL,CVAL,VREF) { NODE, DST_RCFILTER , 5, { ENAB,INP0,NODE_NC,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL,CVAL,VREF }, NULL, "RC Filter to VREF" },
+/* For testing - seem to be buggered. Use versions not ending in N. */
+#define DISCRETE_RCDISCN(NODE,ENAB,INP0,RVAL,CVAL) { NODE, DST_RCDISCN , 4, { ENAB,INP0,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL,CVAL }, NULL, "RC Discharge (New Type)" },
+#define DISCRETE_RCDISC2N(NODE,SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL) { NODE, DST_RCDISC2N , 6, { SWITCH,INP0,NODE_NC,INP1,NODE_NC,NODE_NC }, { SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL }, NULL, "RC Discharge 2 (New Type)" },
+#define DISCRETE_RCFILTERN(NODE,ENAB,INP0,RVAL,CVAL) { NODE, DST_RCFILTERN , 4, { ENAB,INP0,NODE_NC,NODE_NC }, { ENAB,INP0,RVAL,CVAL }, NULL, "RC Filter (New Type)" },
+
+/* from disc_dev.c */
+/* generic modules */
+#define DISCRETE_CUSTOM1(NODE,ENAB,IN0,INFO) { NODE, DST_CUSTOM , 2, { ENAB,IN0 }, { ENAB,IN0 }, INFO, "1 input custom module" },
+#define DISCRETE_CUSTOM2(NODE,ENAB,IN0,IN1,INFO) { NODE, DST_CUSTOM , 3, { ENAB,IN0,IN1 }, { ENAB,IN0,IN1 }, INFO, "2 input custom module" },
+#define DISCRETE_CUSTOM3(NODE,ENAB,IN0,IN1,IN2,INFO) { NODE, DST_CUSTOM , 4, { ENAB,IN0,IN1,IN2 }, { ENAB,IN0,IN1,IN2 }, INFO, "3 input custom module" },
+#define DISCRETE_CUSTOM4(NODE,ENAB,IN0,IN1,IN2,IN3,INFO) { NODE, DST_CUSTOM , 5, { ENAB,IN0,IN1,IN2,IN3 }, { ENAB,IN0,IN1,IN2,IN3 }, INFO, "4 input custom module" },
+#define DISCRETE_CUSTOM5(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,INFO) { NODE, DST_CUSTOM , 6, { ENAB,IN0,IN1,IN2,IN3,IN4 }, { ENAB,IN0,IN1,IN2,IN3,IN4 }, INFO, "4 input custom module" },
+/* Component specific */
+#define DISCRETE_555_ASTABLE(NODE,RESET,R1,R2,C,OPTIONS) { NODE, DSD_555_ASTBL , 5, { RESET,R1,R2,C,NODE_NC }, { RESET,R1,R2,C,-1 }, OPTIONS, "555 Astable" },
+#define DISCRETE_555_ASTABLE_CV(NODE,RESET,R1,R2,C,CTRLV,OPTIONS) { NODE, DSD_555_ASTBL , 5, { RESET,R1,R2,C,CTRLV }, { RESET,R1,R2,C,CTRLV }, OPTIONS, "555 Astable with CV" },
+#define DISCRETE_555_MSTABLE(NODE,RESET,TRIG,R,C,OPTIONS) { NODE, DSD_555_MSTBL , 4, { RESET,TRIG,R,C }, { RESET,TRIG,R,C }, OPTIONS, "555 Monostable" },
+#define DISCRETE_555_CC(NODE,RESET,VIN,R,C,RBIAS,RGND,RDIS,OPTIONS) { NODE, DSD_555_CC , 7, { RESET,VIN,R,C,RBIAS,RGND,RDIS }, { RESET,VIN,R,C,RBIAS,RGND,RDIS }, OPTIONS, "555 Constant Current VCO" },
+#define DISCRETE_555_VCO1(NODE,RESET,VIN,OPTIONS) { NODE, DSD_555_VCO1 , 3, { RESET,VIN,NODE_NC }, { RESET,VIN,-1 }, OPTIONS, "555 VCO1 - Op-Amp type" },
+#define DISCRETE_555_VCO1_CV(NODE,RESET,VIN,CTRLV,OPTIONS) { NODE, DSD_555_VCO1 , 3, { RESET,VIN,CTRLV }, { RESET,VIN,CTRLV }, OPTIONS, "555 VCO1 with CV - Op-Amp type" },
+#define DISCRETE_566(NODE,ENAB,VMOD,R,C,OPTIONS) { NODE, DSD_566 , 4, { ENAB,VMOD,R,C }, { ENAB,VMOD,R,C }, OPTIONS, "566" },
+
+#define DISCRETE_CSVLOG1(NODE1) { NODE_SPECIAL, DSO_CSVLOG , 1, { NODE1 }, { NODE1 }, NULL, "CSV Log 1 Node" },
+#define DISCRETE_CSVLOG2(NODE1,NODE2) { NODE_SPECIAL, DSO_CSVLOG , 2, { NODE1,NODE2 }, { NODE1,NODE2 }, NULL, "CSV Log 2 Nodes" },
+#define DISCRETE_CSVLOG3(NODE1,NODE2,NODE3) { NODE_SPECIAL, DSO_CSVLOG , 3, { NODE1,NODE2,NODE3 }, { NODE1,NODE2,NODE3 }, NULL, "CSV Log 3 Nodes" },
+#define DISCRETE_CSVLOG4(NODE1,NODE2,NODE3,NODE4) { NODE_SPECIAL, DSO_CSVLOG , 4, { NODE1,NODE2,NODE3,NODE4 }, { NODE1,NODE2,NODE3,NODE4 }, NULL, "CSV Log 4 Nodes" },
+#define DISCRETE_CSVLOG5(NODE1,NODE2,NODE3,NODE4,NODE5) { NODE_SPECIAL, DSO_CSVLOG , 5, { NODE1,NODE2,NODE3,NODE4,NODE5 }, { NODE1,NODE2,NODE3,NODE4,NODE5 }, NULL, "CSV Log 5 Nodes" },
+#define DISCRETE_WAVELOG1(NODE1,GAIN1) { NODE_SPECIAL, DSO_WAVELOG , 2, { NODE1,NODE_NC }, { NODE1,GAIN1 }, NULL, "Wave Log 1 Node" },
+#define DISCRETE_WAVELOG2(NODE1,GAIN1,NODE2,GAIN2) { NODE_SPECIAL, DSO_WAVELOG , 4, { NODE1,NODE_NC,NODE2,NODE_NC }, { NODE1,GAIN1,NODE2,GAIN2 }, NULL, "Wave Log 2 Nodes" },
+#define DISCRETE_OUTPUT(OPNODE,GAIN) { NODE_SPECIAL, DSO_OUTPUT , 2, { OPNODE,NODE_NC }, { 0,GAIN }, NULL, "Output Node" },
+
+
+
+#define IS_VALUE_A_NODE(val) (((val) > NODE_START) && ((val) <= NODE_END))
+
+/*************************************
+ *
+ * Interface to the external world
+ *
+ *************************************/
+
+node_description *discrete_find_node(void *chip, int node);
+
+WRITE8_HANDLER(discrete_sound_w);
+READ8_HANDLER(discrete_sound_r);
+
+#endif
diff --git a/src/emu/sound/dmadac.c b/src/emu/sound/dmadac.c
new file mode 100644
index 00000000000..0fcf8a9ef50
--- /dev/null
+++ b/src/emu/sound/dmadac.c
@@ -0,0 +1,272 @@
+/***************************************************************************
+
+ DMA-driven DAC driver
+ by Aaron Giles
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "dmadac.h"
+
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define DEFAULT_SAMPLE_RATE (44100)
+
+#define BUFFER_SIZE 32768
+
+
+
+/*************************************
+ *
+ * Types
+ *
+ *************************************/
+
+struct dmadac_channel_data
+{
+ /* sound stream and buffers */
+ sound_stream * channel;
+ INT16 * buffer;
+ UINT32 bufin;
+ UINT32 bufout;
+
+ /* per-channel parameters */
+ INT16 volume;
+ UINT8 enabled;
+ double frequency;
+};
+
+
+
+/*************************************
+ *
+ * Stream callback
+ *
+ *************************************/
+
+static void dmadac_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct dmadac_channel_data *ch = param;
+ stream_sample_t *output = _buffer[0];
+ INT16 *source = ch->buffer;
+ UINT32 curout = ch->bufout;
+ UINT32 curin = ch->bufin;
+ int volume = ch->volume;
+
+ /* feed as much as we can */
+ while (curout != curin && length-- > 0)
+ *output++ = (source[curout++ % BUFFER_SIZE] * volume) >> 8;
+
+ /* fill the rest with silence */
+ while (length-- > 0)
+ *output++ = 0;
+
+ /* save the new output pointer */
+ ch->bufout = curout % BUFFER_SIZE;
+}
+
+
+
+/*************************************
+ *
+ * Sound hardware init
+ *
+ *************************************/
+
+static void *dmadac_start(int sndindex, int clock, const void *config)
+{
+ struct dmadac_channel_data *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ /* allocate a clear a buffer */
+ info->buffer = auto_malloc(sizeof(info->buffer[0]) * BUFFER_SIZE);
+ memset(info->buffer, 0, sizeof(info->buffer[0]) * BUFFER_SIZE);
+
+ /* reset the state */
+ info->volume = 0x100;
+
+ /* allocate a stream channel */
+ info->channel = stream_create(0, 1, DEFAULT_SAMPLE_RATE, info, dmadac_update);
+
+ /* register with the save state system */
+ state_save_register_item("dmadac", sndindex, info->bufin);
+ state_save_register_item("dmadac", sndindex, info->bufout);
+ state_save_register_item("dmadac", sndindex, info->volume);
+ state_save_register_item("dmadac", sndindex, info->enabled);
+ state_save_register_item("dmadac", sndindex, info->frequency);
+ state_save_register_item_pointer("dmadac", sndindex, info->buffer, BUFFER_SIZE);
+
+ return info;
+}
+
+
+
+/*************************************
+ *
+ * Primary transfer routine
+ *
+ *************************************/
+
+void dmadac_transfer(UINT8 first_channel, UINT8 num_channels, offs_t channel_spacing, offs_t frame_spacing, offs_t total_frames, INT16 *data)
+{
+ int i, j;
+
+ /* flush out as much data as we can */
+ for (i = 0; i < num_channels; i++)
+ {
+ struct dmadac_channel_data *info = sndti_token(SOUND_DMADAC, first_channel + i);
+ stream_update(info->channel);
+ }
+
+ /* loop over all channels and accumulate the data */
+ for (i = 0; i < num_channels; i++)
+ {
+ struct dmadac_channel_data *ch = sndti_token(SOUND_DMADAC, first_channel + i);
+ if (ch->enabled)
+ {
+ int maxin = (ch->bufout + BUFFER_SIZE - 1) % BUFFER_SIZE;
+ INT16 *src = data + i * channel_spacing;
+ int curin = ch->bufin;
+
+ /* copy the data */
+ for (j = 0; j < total_frames && curin != maxin; j++)
+ {
+ ch->buffer[curin++ % BUFFER_SIZE] = *src;
+ src += frame_spacing;
+ }
+ ch->bufin = curin;
+
+ /* log overruns */
+ if (j != total_frames)
+ logerror("dmadac_transfer: buffer overrun (short %d frames)\n", total_frames - j);
+ }
+ }
+
+ LOG(("dmadac_transfer - %d samples, %d effective, %d in buffer\n", total_frames, (int)(total_frames * (double)DEFAULT_SAMPLE_RATE / dmadac[first_channel].frequency), dmadac[first_channel].curinpos - dmadac[first_channel].curoutpos));
+}
+
+
+
+/*************************************
+ *
+ * Enable/disable DMA channel(s)
+ *
+ *************************************/
+
+void dmadac_enable(UINT8 first_channel, UINT8 num_channels, UINT8 enable)
+{
+ int i;
+
+ /* flush out as much data as we can */
+ for (i = 0; i < num_channels; i++)
+ {
+ struct dmadac_channel_data *info = sndti_token(SOUND_DMADAC, first_channel + i);
+ stream_update(info->channel);
+ info->enabled = enable;
+ if (!enable)
+ info->bufin = info->bufout = 0;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Set the frequency on DMA channel(s)
+ *
+ *************************************/
+
+void dmadac_set_frequency(UINT8 first_channel, UINT8 num_channels, double frequency)
+{
+ int i;
+
+ /* set the sample rate on each channel */
+ for (i = 0; i < num_channels; i++)
+ {
+ struct dmadac_channel_data *info = sndti_token(SOUND_DMADAC, first_channel + i);
+ stream_set_sample_rate(info->channel, frequency);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Set the volume on DMA channel(s)
+ *
+ *************************************/
+
+void dmadac_set_volume(UINT8 first_channel, UINT8 num_channels, UINT16 volume)
+{
+ int i;
+
+ /* flush out as much data as we can */
+ for (i = 0; i < num_channels; i++)
+ {
+ struct dmadac_channel_data *info = sndti_token(SOUND_DMADAC, first_channel + i);
+ stream_update(info->channel);
+ info->volume = volume;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void dmadac_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void dmadac_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = dmadac_set_info; break;
+ case SNDINFO_PTR_START: info->start = dmadac_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "DMA-driven DAC"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "DAC"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/dmadac.h b/src/emu/sound/dmadac.h
new file mode 100644
index 00000000000..37694d4273b
--- /dev/null
+++ b/src/emu/sound/dmadac.h
@@ -0,0 +1,16 @@
+/**********************************************************************************************
+ *
+ * DMA-driven DAC driver
+ * by Aaron Giles
+ *
+ **********************************************************************************************/
+
+#ifndef DMADAC_H
+#define DMADAC_H
+
+void dmadac_transfer(UINT8 first_channel, UINT8 num_channels, offs_t channel_spacing, offs_t frame_spacing, offs_t total_frames, INT16 *data);
+void dmadac_enable(UINT8 first_channel, UINT8 num_channels, UINT8 enable);
+void dmadac_set_frequency(UINT8 first_channel, UINT8 num_channels, double frequency);
+void dmadac_set_volume(UINT8 first_channel, UINT8 num_channels, UINT16 volume);
+
+#endif
diff --git a/src/emu/sound/es5503.c b/src/emu/sound/es5503.c
new file mode 100644
index 00000000000..8ba61b254c5
--- /dev/null
+++ b/src/emu/sound/es5503.c
@@ -0,0 +1,551 @@
+/*
+
+ ES5503 - Ensoniq ES5503 "DOC" emulator v1.0
+ By R. Belmont.
+
+ Copyright (c) 2005-2007 R. Belmont.
+
+ This software is dual-licensed: it may be used in MAME and properly licensed
+ MAME derivatives under the terms of the MAME license. For use outside of
+ MAME and properly licensed derivatives, it is available under the
+ terms of the GNU Lesser General Public License (LGPL), version 2.1.
+ You may read the LGPL at http://www.gnu.org/licenses/lgpl.html
+
+ History: the ES5503 was the next design after the famous C64 "SID" by Bob Yannes.
+ It powered the legendary Mirage sampler (the first affordable pro sampler) as well
+ as the ESQ-1 synth/sequencer. The ES5505 (used in Taito's F3 System) and 5506
+ (used in the "Soundscape" series of ISA PC sound cards) followed on a fundamentally
+ similar architecture.
+
+ Bugs: On the real silicon, oscillators 30 and 31 have random volume fluctuations and are
+ unusable for playback. We don't attempt to emulate that. :-)
+
+ Additionally, in "swap" mode, there's one cycle when the switch takes place where the
+ oscillator's output is 0x80 (centerline) regardless of the sample data. This can
+ cause audible clicks and a general degradation of audio quality if the correct sample
+ data at that point isn't 0x80 or very near it.
+
+ Changes:
+ 0.2 (RB) - improved behavior for volumes > 127, fixes missing notes in Nucleus & missing voices in Thexder
+ 0.3 (RB) - fixed extraneous clicking, improved timing behavior for e.g. Music Construction Set & Music Studio
+ 0.4 (RB) - major fixes to IRQ semantics and end-of-sample handling.
+ 0.5 (RB) - more flexible wave memory hookup (incl. banking) and save state support.
+ 1.0 (RB) - properly respects the input clock
+*/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "cpuintrf.h"
+#include "es5503.h"
+#include "streams.h"
+#include "state.h"
+
+typedef struct
+{
+ void *chip;
+
+ UINT16 freq;
+ UINT16 wtsize;
+ UINT8 control;
+ UINT8 vol;
+ UINT8 data;
+ UINT32 wavetblpointer;
+ UINT8 wavetblsize;
+ UINT8 resolution;
+
+ UINT32 accumulator;
+ UINT8 irqpend;
+ emu_timer *timer;
+} ES5503Osc;
+
+typedef struct
+{
+ ES5503Osc oscillators[32];
+
+ UINT8 *docram;
+
+ int index;
+ sound_stream * stream;
+
+ void (*irq_callback)(int); // IRQ callback
+
+ read8_handler adc_read; // callback for the 5503's built-in analog to digital converter
+
+ INT8 oscsenabled; // # of oscillators enabled
+
+ int rege0; // contents of register 0xe0
+
+ UINT32 clock;
+ UINT32 output_rate;
+} ES5503Chip;
+
+static UINT16 wavesizes[8] = { 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 };
+static UINT32 wavemasks[8] = { 0x1ff00, 0x1fe00, 0x1fc00, 0x1f800, 0x1f000, 0x1e000, 0x1c000, 0x18000 };
+static UINT32 accmasks[8] = { 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff };
+static int resshifts[8] = { 9, 10, 11, 12, 13, 14, 15, 16 };
+
+enum
+{
+ MODE_FREE = 0,
+ MODE_ONESHOT = 1,
+ MODE_SYNCAM = 2,
+ MODE_SWAP = 3
+};
+
+// halt_osc: handle halting an oscillator
+// chip = chip ptr
+// onum = oscillator #
+// type = 1 for 0 found in sample data, 0 for hit end of table size
+static void es5503_halt_osc(ES5503Chip *chip, int onum, int type, UINT32 *accumulator)
+{
+ ES5503Osc *pOsc = &chip->oscillators[onum];
+ ES5503Osc *pPartner = &chip->oscillators[onum^1];
+ int mode = (pOsc->control>>1) & 3;
+
+ // if 0 found in sample data or mode is not free-run, halt this oscillator
+ if ((type != MODE_FREE) || (mode > 0))
+ {
+ pOsc->control |= 1;
+ }
+ else
+ {
+ // reset the accumulator if not halting
+ *accumulator = 0;
+ }
+
+ // if swap mode, start the partner
+ if (mode == MODE_SWAP)
+ {
+ pPartner->control &= ~1; // clear the halt bit
+ pPartner->accumulator = 0; // and make sure it starts from the top
+ }
+
+ // IRQ enabled for this voice?
+ if (pOsc->control & 0x08)
+ {
+ pOsc->irqpend = 1;
+
+ if (chip->irq_callback)
+ {
+ chip->irq_callback(1);
+ }
+ }
+}
+
+static TIMER_CALLBACK_PTR( es5503_timer_cb )
+{
+ ES5503Osc *osc = param;
+ ES5503Chip *chip = (ES5503Chip *)osc->chip;
+
+ stream_update(chip->stream);
+}
+
+static void es5503_pcm_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length)
+{
+ INT32 mix[48000*2];
+ INT32 *mixp;
+ int osc, snum, i;
+ UINT32 ramptr;
+ ES5503Chip *chip = param;
+
+ memset(mix, 0, sizeof(mix));
+
+ for (osc = 0; osc < (chip->oscsenabled+1); osc++)
+ {
+ ES5503Osc *pOsc = &chip->oscillators[osc];
+
+ mixp = &mix[0];
+
+ if (!(pOsc->control & 1))
+ {
+ UINT32 wtptr = pOsc->wavetblpointer & wavemasks[pOsc->wavetblsize], altram;
+ UINT32 acc = pOsc->accumulator;
+ UINT16 wtsize = pOsc->wtsize - 1;
+ UINT8 ctrl = pOsc->control;
+ UINT16 freq = pOsc->freq;
+ INT16 vol = pOsc->vol;
+ INT8 data = -128;
+ int resshift = resshifts[pOsc->resolution] - pOsc->wavetblsize;
+ UINT32 sizemask = accmasks[pOsc->wavetblsize];
+
+ for (snum = 0; snum < length; snum++)
+ {
+ ramptr = (acc >> resshift) & sizemask;
+ altram = acc >> resshift;
+
+ acc += freq;
+
+ data = (INT32)chip->docram[ramptr + wtptr] ^ 0x80;
+
+ if (chip->docram[ramptr + wtptr] == 0x00)
+ {
+ es5503_halt_osc(chip, osc, 1, &acc);
+ }
+ else
+ {
+ if (pOsc->control & 0x10)
+ {
+ *mixp++ += (data * vol);
+ mixp++;
+ }
+ else
+ {
+ mixp++;
+ *mixp++ += (data * vol);
+ }
+
+ if (altram >= wtsize)
+ {
+ es5503_halt_osc(chip, osc, 0, &acc);
+ }
+ }
+
+ // if oscillator halted, we've got no more samples to generate
+ if (pOsc->control & 1)
+ {
+ ctrl |= 1;
+ break;
+ }
+ }
+
+ pOsc->control = ctrl;
+ pOsc->accumulator = acc;
+ pOsc->data = data ^ 0x80;
+ }
+ }
+
+ mixp = &mix[0];
+ for (i = 0; i < length; i++)
+ {
+ outputs[0][i] = (*mixp++)>>1;
+ outputs[1][i] = (*mixp++)>>1;
+ }
+}
+
+
+static void *es5503_start(int sndindex, int clock, const void *config)
+{
+ const struct ES5503interface *intf;
+ int osc;
+ ES5503Chip *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+ chip->index = sndindex;
+
+ intf = config;
+
+ chip->irq_callback = intf->irq_callback;
+ chip->adc_read = intf->adc_read;
+ chip->docram = intf->wave_memory;
+ chip->clock = clock;
+
+ chip->rege0 = 0x80;
+
+ for (osc = 0; osc < 32; osc++)
+ {
+ char sname[32];
+ sprintf(sname, "ES5503 %d osc %d", sndindex, osc);
+
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].freq);
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].wtsize);
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].control);
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].vol);
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].data);
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].wavetblpointer);
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].wavetblsize);
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].resolution);
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].accumulator);
+ state_save_register_item(sname, sndindex, chip->oscillators[osc].irqpend);
+
+ chip->oscillators[osc].data = 0x80;
+ chip->oscillators[osc].irqpend = 0;
+ chip->oscillators[osc].accumulator = 0;
+
+ chip->oscillators[osc].timer = timer_alloc_ptr(es5503_timer_cb, &chip->oscillators[osc]);
+ chip->oscillators[osc].chip = (void *)chip;
+ }
+
+ chip->oscsenabled = 1;
+
+ chip->output_rate = (clock/8)/34; // (input clock / 8) / # of oscs. enabled + 2
+ chip->stream = stream_create(0, 2, chip->output_rate, chip, es5503_pcm_update);
+
+ return chip;
+}
+
+READ8_HANDLER(ES5503_reg_0_r)
+{
+ UINT8 retval;
+ int i;
+ ES5503Chip *chip = sndti_token(SOUND_ES5503, 0);
+
+ stream_update(chip->stream);
+
+ if (offset < 0xe0)
+ {
+ int osc = offset & 0x1f;
+
+ switch(offset & 0xe0)
+ {
+ case 0: // freq lo
+ return (chip->oscillators[osc].freq & 0xff);
+ break;
+
+ case 0x20: // freq hi
+ return (chip->oscillators[osc].freq >> 8);
+ break;
+
+ case 0x40: // volume
+ return chip->oscillators[osc].vol;
+ break;
+
+ case 0x60: // data
+ return chip->oscillators[osc].data;
+ break;
+
+ case 0x80: // wavetable pointer
+ return (chip->oscillators[osc].wavetblpointer>>8) & 0xff;
+ break;
+
+ case 0xa0: // oscillator control
+ return chip->oscillators[osc].control;
+ break;
+
+ case 0xc0: // bank select / wavetable size / resolution
+ retval = 0;
+ if (chip->oscillators[osc].wavetblpointer & 0x10000)
+ {
+ retval |= 0x40;
+ }
+
+ retval |= (chip->oscillators[osc].wavetblsize<<3);
+ retval |= chip->oscillators[osc].resolution;
+ return retval;
+ break;
+ }
+ }
+ else // global registers
+ {
+ switch (offset)
+ {
+ case 0xe0: // interrupt status
+ retval = chip->rege0;
+
+ // scan all oscillators
+ for (i = 0; i < chip->oscsenabled+1; i++)
+ {
+ if (chip->oscillators[i].irqpend)
+ {
+ // signal this oscillator has an interrupt
+ retval = i<<1;
+
+ chip->rege0 = retval | 0x80;
+
+ // and clear its flag
+ chip->oscillators[i].irqpend--;
+
+ if (chip->irq_callback)
+ {
+ chip->irq_callback(0);
+ }
+ break;
+ }
+ }
+
+ // if any oscillators still need to be serviced, assert IRQ again immediately
+ for (i = 0; i < chip->oscsenabled+1; i++)
+ {
+ if (chip->oscillators[i].irqpend)
+ {
+ if (chip->irq_callback)
+ {
+ chip->irq_callback(1);
+ }
+ break;
+ }
+ }
+
+ return retval;
+ break;
+
+ case 0xe1: // oscillator enable
+ return chip->oscsenabled<<1;
+ break;
+
+ case 0xe2: // A/D converter
+ if (chip->adc_read)
+ {
+ return chip->adc_read(0);
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+WRITE8_HANDLER(ES5503_reg_0_w)
+{
+ ES5503Chip *chip = sndti_token(SOUND_ES5503, 0);
+
+ stream_update(chip->stream);
+
+ if (offset < 0xe0)
+ {
+ int osc = offset & 0x1f;
+
+ switch(offset & 0xe0)
+ {
+ case 0: // freq lo
+ chip->oscillators[osc].freq &= 0xff00;
+ chip->oscillators[osc].freq |= data;
+ break;
+
+ case 0x20: // freq hi
+ chip->oscillators[osc].freq &= 0x00ff;
+ chip->oscillators[osc].freq |= (data<<8);
+ break;
+
+ case 0x40: // volume
+ chip->oscillators[osc].vol = data;
+ break;
+
+ case 0x60: // data - ignore writes
+ break;
+
+ case 0x80: // wavetable pointer
+ chip->oscillators[osc].wavetblpointer = (data<<8);
+ break;
+
+ case 0xa0: // oscillator control
+ // if a fresh key-on, reset the ccumulator
+ if ((chip->oscillators[osc].control & 1) && (!(data&1)))
+ {
+ chip->oscillators[osc].accumulator = 0;
+
+ // if this voice generates interrupts, set a timer to make sure we service it on time
+ if (((data & 0x09) == 0x08) && (chip->oscillators[osc].freq > 0))
+ {
+ UINT32 length, run;
+ UINT32 wtptr = chip->oscillators[osc].wavetblpointer & wavemasks[chip->oscillators[osc].wavetblsize];
+ UINT32 acc = 0;
+ UINT16 wtsize = chip->oscillators[osc].wtsize-1;
+ UINT16 freq = chip->oscillators[osc].freq;
+ INT8 data = -128;
+ int resshift = resshifts[chip->oscillators[osc].resolution] - chip->oscillators[osc].wavetblsize;
+ UINT32 sizemask = accmasks[chip->oscillators[osc].wavetblsize];
+ UINT32 ramptr, altram;
+ attotime period;
+
+ run = 1;
+ length = 0;
+ while (run)
+ {
+ ramptr = (acc >> resshift) & sizemask;
+ altram = (acc >> resshift);
+ acc += freq;
+ data = (INT32)chip->docram[ramptr + wtptr];
+
+ if ((data == 0) || (altram >= wtsize))
+ {
+ run = 0;
+ }
+ else
+ {
+ length++;
+ }
+ }
+
+ // ok, we run for this long
+ period = attotime_mul(ATTOTIME_IN_HZ(chip->output_rate), length);
+
+ timer_adjust_ptr(chip->oscillators[osc].timer, period, period);
+ }
+ }
+ else if (!(chip->oscillators[osc].control & 1) && (data&1))
+ {
+ // key off
+ timer_adjust_ptr(chip->oscillators[osc].timer, attotime_never, attotime_never);
+ }
+
+ chip->oscillators[osc].control = data;
+ break;
+
+ case 0xc0: // bank select / wavetable size / resolution
+ if (data & 0x40) // bank select - not used on the Apple IIgs
+ {
+ chip->oscillators[osc].wavetblpointer |= 0x10000;
+ }
+ else
+ {
+ chip->oscillators[osc].wavetblpointer &= 0xffff;
+ }
+
+ chip->oscillators[osc].wavetblsize = ((data>>3) & 7);
+ chip->oscillators[osc].wtsize = wavesizes[chip->oscillators[osc].wavetblsize];
+ chip->oscillators[osc].resolution = (data & 7);
+ break;
+ }
+ }
+ else // global registers
+ {
+ switch (offset)
+ {
+ case 0xe0: // interrupt status
+ break;
+
+ case 0xe1: // oscillator enable
+ chip->oscsenabled = (data>>1);
+
+ chip->output_rate = (chip->clock/8)/(2+chip->oscsenabled);
+ stream_set_sample_rate(chip->stream, chip->output_rate);
+ break;
+
+ case 0xe2: // A/D converter
+ break;
+ }
+ }
+}
+
+void ES5503_set_base_0(UINT8 *wavemem)
+{
+ ES5503Chip *chip = sndti_token(SOUND_ES5503, 0);
+
+ chip->docram = wavemem;
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void es5503_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void es5503_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = es5503_set_info; break;
+ case SNDINFO_PTR_START: info->start = es5503_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "ES5503"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Ensoniq ES550x"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2005-2007 R. Belmont"; break;
+ }
+}
+
diff --git a/src/emu/sound/es5503.h b/src/emu/sound/es5503.h
new file mode 100644
index 00000000000..262cc35200e
--- /dev/null
+++ b/src/emu/sound/es5503.h
@@ -0,0 +1,15 @@
+#ifndef _ES5503_H_
+#define _ES5503_H_
+
+struct ES5503interface
+{
+ void (*irq_callback)(int state);
+ read8_handler adc_read;
+ UINT8 *wave_memory;
+};
+
+READ8_HANDLER(ES5503_reg_0_r);
+WRITE8_HANDLER(ES5503_reg_0_w);
+void ES5503_set_base_0(UINT8 *wavemem);
+
+#endif
diff --git a/src/emu/sound/es5506.c b/src/emu/sound/es5506.c
new file mode 100644
index 00000000000..0f4209faa24
--- /dev/null
+++ b/src/emu/sound/es5506.c
@@ -0,0 +1,2205 @@
+/**********************************************************************************************
+ *
+ * Ensoniq ES5505/6 driver
+ * by Aaron Giles
+ *
+ **********************************************************************************************/
+
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "es5506.h"
+
+
+
+/**********************************************************************************************
+
+ CONSTANTS
+
+***********************************************************************************************/
+
+#define LOG_COMMANDS 0
+#define RAINE_CHECK 0
+#define MAKE_WAVS 0
+
+#if MAKE_WAVS
+#include "wavwrite.h"
+#endif
+
+
+#define MAX_SAMPLE_CHUNK 10000
+#define ULAW_MAXBITS 8
+
+#define CONTROL_BS1 0x8000
+#define CONTROL_BS0 0x4000
+#define CONTROL_CMPD 0x2000
+#define CONTROL_CA2 0x1000
+#define CONTROL_CA1 0x0800
+#define CONTROL_CA0 0x0400
+#define CONTROL_LP4 0x0200
+#define CONTROL_LP3 0x0100
+#define CONTROL_IRQ 0x0080
+#define CONTROL_DIR 0x0040
+#define CONTROL_IRQE 0x0020
+#define CONTROL_BLE 0x0010
+#define CONTROL_LPE 0x0008
+#define CONTROL_LEI 0x0004
+#define CONTROL_STOP1 0x0002
+#define CONTROL_STOP0 0x0001
+
+#define CONTROL_BSMASK (CONTROL_BS1 | CONTROL_BS0)
+#define CONTROL_CAMASK (CONTROL_CA2 | CONTROL_CA1 | CONTROL_CA0)
+#define CONTROL_LPMASK (CONTROL_LP4 | CONTROL_LP3)
+#define CONTROL_LOOPMASK (CONTROL_BLE | CONTROL_LPE)
+#define CONTROL_STOPMASK (CONTROL_STOP1 | CONTROL_STOP0)
+
+
+
+/**********************************************************************************************
+
+ INTERNAL DATA STRUCTURES
+
+***********************************************************************************************/
+
+/* struct describing a single playing voice */
+struct ES5506Voice
+{
+ /* external state */
+ UINT32 control; /* control register */
+ UINT32 freqcount; /* frequency count register */
+ UINT32 start; /* start register */
+ UINT32 lvol; /* left volume register */
+ UINT32 end; /* end register */
+ UINT32 lvramp; /* left volume ramp register */
+ UINT32 accum; /* accumulator register */
+ UINT32 rvol; /* right volume register */
+ UINT32 rvramp; /* right volume ramp register */
+ UINT32 ecount; /* envelope count register */
+ UINT32 k2; /* k2 register */
+ UINT32 k2ramp; /* k2 ramp register */
+ UINT32 k1; /* k1 register */
+ UINT32 k1ramp; /* k1 ramp register */
+ INT32 o4n1; /* filter storage O4(n-1) */
+ INT32 o3n1; /* filter storage O3(n-1) */
+ INT32 o3n2; /* filter storage O3(n-2) */
+ INT32 o2n1; /* filter storage O2(n-1) */
+ INT32 o2n2; /* filter storage O2(n-2) */
+ INT32 o1n1; /* filter storage O1(n-1) */
+ UINT32 exbank; /* external address bank */
+
+ /* internal state */
+ UINT8 index; /* index of this voice */
+ UINT8 filtcount; /* filter count */
+ UINT32 accum_mask;
+};
+
+struct ES5506Chip
+{
+ sound_stream *stream; /* which stream are we using */
+ int sample_rate; /* current sample rate */
+ UINT16 * region_base[4]; /* pointer to the base of the region */
+ UINT32 write_latch; /* currently accumulated data for write */
+ UINT32 read_latch; /* currently accumulated data for read */
+ UINT32 master_clock; /* master clock frequency */
+ void (*irq_callback)(int); /* IRQ callback */
+ UINT16 (*port_read)(void); /* input port read */
+
+ UINT8 current_page; /* current register page */
+ UINT8 active_voices; /* number of active voices */
+ UINT8 mode; /* MODE register */
+ UINT8 wst; /* W_ST register */
+ UINT8 wend; /* W_END register */
+ UINT8 lrend; /* LR_END register */
+ UINT8 irqv; /* IRQV register */
+
+ struct ES5506Voice voice[32]; /* the 32 voices */
+
+ INT32 * scratch;
+
+ INT16 * ulaw_lookup;
+ UINT16 * volume_lookup;
+
+#if MAKE_WAVS
+ void * wavraw; /* raw waveform */
+#endif
+};
+
+
+
+/**********************************************************************************************
+
+ GLOBAL VARIABLES
+
+***********************************************************************************************/
+
+static FILE *eslog;
+
+
+
+/**********************************************************************************************
+
+ update_irq_state -- update the IRQ state
+
+***********************************************************************************************/
+
+static void update_irq_state(struct ES5506Chip *chip)
+{
+ /* ES5505/6 irq line has been set high - inform the host */
+ if (chip->irq_callback)
+ (*chip->irq_callback)(1); /* IRQB set high */
+}
+
+static void update_internal_irq_state(struct ES5506Chip *chip)
+{
+ /* Host (cpu) has just read the voice interrupt vector (voice IRQ ack).
+
+ Reset the voice vector to show the IRQB line is low (top bit set).
+ If we have any stacked interrupts (other voices waiting to be
+ processed - with their IRQ bit set) then they will be moved into
+ the vector next time the voice is processed. In emulation
+ terms they get updated next time generate_samples() is called.
+ */
+
+ chip->irqv=0x80;
+
+ if (chip->irq_callback)
+ (*chip->irq_callback)(0); /* IRQB set low */
+}
+
+/**********************************************************************************************
+
+ compute_tables -- compute static tables
+
+***********************************************************************************************/
+
+static int compute_tables(struct ES5506Chip *chip)
+{
+ int i;
+
+ /* allocate ulaw lookup table */
+ chip->ulaw_lookup = auto_malloc(sizeof(chip->ulaw_lookup[0]) << ULAW_MAXBITS);
+
+ /* generate ulaw lookup table */
+ for (i = 0; i < (1 << ULAW_MAXBITS); i++)
+ {
+ UINT16 rawval = (i << (16 - ULAW_MAXBITS)) | (1 << (15 - ULAW_MAXBITS));
+ UINT8 exponent = rawval >> 13;
+ UINT32 mantissa = (rawval << 3) & 0xffff;
+
+ if (exponent == 0)
+ chip->ulaw_lookup[i] = (INT16)mantissa >> 7;
+ else
+ {
+ mantissa = (mantissa >> 1) | (~mantissa & 0x8000);
+ chip->ulaw_lookup[i] = (INT16)mantissa >> (7 - exponent);
+ }
+ }
+
+ /* allocate volume lookup table */
+ chip->volume_lookup = auto_malloc(sizeof(chip->volume_lookup[0]) * 4096);
+
+ /* generate ulaw lookup table */
+ for (i = 0; i < 4096; i++)
+ {
+ UINT8 exponent = i >> 8;
+ UINT32 mantissa = (i & 0xff) | 0x100;
+
+ chip->volume_lookup[i] = (mantissa << 11) >> (20 - exponent);
+ }
+
+ return 1;
+}
+
+
+
+/**********************************************************************************************
+
+ interpolate -- interpolate between two samples
+
+***********************************************************************************************/
+
+#define interpolate(sample1, sample2, accum) \
+ (sample1 * (INT32)(0x800 - (accum & 0x7ff)) + \
+ sample2 * (INT32)(accum & 0x7ff)) >> 11;
+
+
+
+/**********************************************************************************************
+
+ apply_filters -- apply the 4-pole digital filter to the sample
+
+***********************************************************************************************/
+
+#define apply_filters(voice, sample) \
+do \
+{ \
+ /* pole 1 is always low-pass using K1 */ \
+ sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o1n1) / 16384) + voice->o1n1; \
+ voice->o1n1 = sample; \
+ \
+ /* pole 2 is always low-pass using K1 */ \
+ sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o2n1) / 16384) + voice->o2n1; \
+ voice->o2n2 = voice->o2n1; \
+ voice->o2n1 = sample; \
+ \
+ /* remaining poles depend on the current filter setting */ \
+ switch (voice->control & CONTROL_LPMASK) \
+ { \
+ case 0: \
+ /* pole 3 is high-pass using K2 */ \
+ sample = sample - voice->o2n2 + ((INT32)(voice->k2 >> 2) * voice->o3n1) / 32768 + voice->o3n1 / 2; \
+ voice->o3n2 = voice->o3n1; \
+ voice->o3n1 = sample; \
+ \
+ /* pole 4 is high-pass using K2 */ \
+ sample = sample - voice->o3n2 + ((INT32)(voice->k2 >> 2) * voice->o4n1) / 32768 + voice->o4n1 / 2; \
+ voice->o4n1 = sample; \
+ break; \
+ \
+ case CONTROL_LP3: \
+ /* pole 3 is low-pass using K1 */ \
+ sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1; \
+ voice->o3n2 = voice->o3n1; \
+ voice->o3n1 = sample; \
+ \
+ /* pole 4 is high-pass using K2 */ \
+ sample = sample - voice->o3n2 + ((INT32)(voice->k2 >> 2) * voice->o4n1) / 32768 + voice->o4n1 / 2; \
+ voice->o4n1 = sample; \
+ break; \
+ \
+ case CONTROL_LP4: \
+ /* pole 3 is low-pass using K2 */ \
+ sample = ((INT32)(voice->k2 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1; \
+ voice->o3n2 = voice->o3n1; \
+ voice->o3n1 = sample; \
+ \
+ /* pole 4 is low-pass using K2 */ \
+ sample = ((INT32)(voice->k2 >> 2) * (sample - voice->o4n1) / 16384) + voice->o4n1; \
+ voice->o4n1 = sample; \
+ break; \
+ \
+ case CONTROL_LP4 | CONTROL_LP3: \
+ /* pole 3 is low-pass using K1 */ \
+ sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1; \
+ voice->o3n2 = voice->o3n1; \
+ voice->o3n1 = sample; \
+ \
+ /* pole 4 is low-pass using K2 */ \
+ sample = ((INT32)(voice->k2 >> 2) * (sample - voice->o4n1) / 16384) + voice->o4n1; \
+ voice->o4n1 = sample; \
+ break; \
+ } \
+} while (0)
+
+
+
+/**********************************************************************************************
+
+ update_envelopes -- update the envelopes
+
+***********************************************************************************************/
+
+#define update_envelopes(voice, samples) \
+do \
+{ \
+ int count = (samples > 1 && samples > voice->ecount) ? voice->ecount : samples; \
+ \
+ /* decrement the envelope counter */ \
+ voice->ecount -= count; \
+ \
+ /* ramp left volume */ \
+ if (voice->lvramp) \
+ { \
+ voice->lvol += (INT8)voice->lvramp * count; \
+ if ((INT32)voice->lvol < 0) voice->lvol = 0; \
+ else if (voice->lvol > 0xffff) voice->lvol = 0xffff; \
+ } \
+ \
+ /* ramp right volume */ \
+ if (voice->rvramp) \
+ { \
+ voice->rvol += (INT8)voice->rvramp * count; \
+ if ((INT32)voice->rvol < 0) voice->rvol = 0; \
+ else if (voice->rvol > 0xffff) voice->rvol = 0xffff; \
+ } \
+ \
+ /* ramp k1 filter constant */ \
+ if (voice->k1ramp && ((INT32)voice->k1ramp >= 0 || !(voice->filtcount & 7))) \
+ { \
+ voice->k1 += (INT8)voice->k1ramp * count; \
+ if ((INT32)voice->k1 < 0) voice->k1 = 0; \
+ else if (voice->k1 > 0xffff) voice->k1 = 0xffff; \
+ } \
+ \
+ /* ramp k2 filter constant */ \
+ if (voice->k2ramp && ((INT32)voice->k2ramp >= 0 || !(voice->filtcount & 7))) \
+ { \
+ voice->k2 += (INT8)voice->k2ramp * count; \
+ if ((INT32)voice->k2 < 0) voice->k2 = 0; \
+ else if (voice->k2 > 0xffff) voice->k2 = 0xffff; \
+ } \
+ \
+ /* update the filter constant counter */ \
+ voice->filtcount += count; \
+ \
+} while (0)
+
+
+
+/**********************************************************************************************
+
+ check_for_end_forward
+ check_for_end_reverse -- check for loop end and loop appropriately
+
+***********************************************************************************************/
+
+#define check_for_end_forward(voice, accum) \
+do \
+{ \
+ /* are we past the end? */ \
+ if (accum > voice->end && !(voice->control & CONTROL_LEI)) \
+ { \
+ /* generate interrupt if required */ \
+ if (voice->control&CONTROL_IRQE) \
+ voice->control |= CONTROL_IRQ; \
+ \
+ /* handle the different types of looping */ \
+ switch (voice->control & CONTROL_LOOPMASK) \
+ { \
+ /* non-looping */ \
+ case 0: \
+ voice->control |= CONTROL_STOP0; \
+ goto alldone; \
+ \
+ /* uni-directional looping */ \
+ case CONTROL_LPE: \
+ accum = (voice->start + (accum - voice->end)) & voice->accum_mask; \
+ break; \
+ \
+ /* trans-wave looping */ \
+ case CONTROL_BLE: \
+ accum = (voice->start + (accum - voice->end)) & voice->accum_mask; \
+ voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;\
+ break; \
+ \
+ /* bi-directional looping */ \
+ case CONTROL_LPE | CONTROL_BLE: \
+ accum = (voice->end - (accum - voice->end)) & voice->accum_mask; \
+ voice->control ^= CONTROL_DIR; \
+ goto reverse; \
+ } \
+ } \
+} while (0)
+
+
+#define check_for_end_reverse(voice, accum) \
+do \
+{ \
+ /* are we past the end? */ \
+ if (accum < voice->start && !(voice->control & CONTROL_LEI)) \
+ { \
+ /* generate interrupt if required */ \
+ if (voice->control&CONTROL_IRQE) \
+ voice->control |= CONTROL_IRQ; \
+ \
+ /* handle the different types of looping */ \
+ switch (voice->control & CONTROL_LOOPMASK) \
+ { \
+ /* non-looping */ \
+ case 0: \
+ voice->control |= CONTROL_STOP0; \
+ goto alldone; \
+ \
+ /* uni-directional looping */ \
+ case CONTROL_LPE: \
+ accum = (voice->end - (voice->start - accum)) & voice->accum_mask; \
+ break; \
+ \
+ /* trans-wave looping */ \
+ case CONTROL_BLE: \
+ accum = (voice->end - (voice->start - accum)) & voice->accum_mask; \
+ voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;\
+ break; \
+ \
+ /* bi-directional looping */ \
+ case CONTROL_LPE | CONTROL_BLE: \
+ accum = (voice->start + (voice->start - accum)) & voice->accum_mask;\
+ voice->control ^= CONTROL_DIR; \
+ goto reverse; \
+ } \
+ } \
+} while (0)
+
+
+
+/**********************************************************************************************
+
+ generate_dummy -- generate nothing, just apply envelopes
+
+***********************************************************************************************/
+
+static void generate_dummy(struct ES5506Chip *chip, struct ES5506Voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples)
+{
+ UINT32 freqcount = voice->freqcount;
+ UINT32 accum = voice->accum & voice->accum_mask;
+
+ /* outer loop, in case we switch directions */
+ while (samples > 0 && !(voice->control & CONTROL_STOPMASK))
+ {
+reverse:
+ /* two cases: first case is forward direction */
+ if (!(voice->control & CONTROL_DIR))
+ {
+ /* loop while we still have samples to generate */
+ while (samples--)
+ {
+ /* fetch two samples */
+ accum = (accum + freqcount) & voice->accum_mask;
+
+ /* update filters/volumes */
+ if (voice->ecount != 0)
+ update_envelopes(voice, 1);
+
+ /* check for loop end */
+ check_for_end_forward(voice, accum);
+ }
+ }
+
+ /* two cases: second case is backward direction */
+ else
+ {
+ /* loop while we still have samples to generate */
+ while (samples--)
+ {
+ /* fetch two samples */
+ accum = (accum - freqcount) & voice->accum_mask;
+
+ /* update filters/volumes */
+ if (voice->ecount != 0)
+ update_envelopes(voice, 1);
+
+ /* check for loop end */
+ check_for_end_reverse(voice, accum);
+ }
+ }
+ }
+
+ /* if we stopped, process any additional envelope */
+alldone:
+ voice->accum = accum;
+ if (samples > 0)
+ update_envelopes(voice, samples);
+}
+
+
+
+/**********************************************************************************************
+
+ generate_ulaw -- general u-law decoding routine
+
+***********************************************************************************************/
+
+static void generate_ulaw(struct ES5506Chip *chip, struct ES5506Voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples)
+{
+ UINT32 freqcount = voice->freqcount;
+ UINT32 accum = voice->accum & voice->accum_mask;
+ INT32 lvol = chip->volume_lookup[voice->lvol >> 4];
+ INT32 rvol = chip->volume_lookup[voice->rvol >> 4];
+
+ /* pre-add the bank offset */
+ base += voice->exbank;
+
+ /* outer loop, in case we switch directions */
+ while (samples > 0 && !(voice->control & CONTROL_STOPMASK))
+ {
+reverse:
+ /* two cases: first case is forward direction */
+ if (!(voice->control & CONTROL_DIR))
+ {
+ /* loop while we still have samples to generate */
+ while (samples--)
+ {
+ /* fetch two samples */
+ INT32 val1 = base[accum >> 11];
+ INT32 val2 = base[((accum + (1 << 11)) & voice->accum_mask) >> 11];
+
+ /* decompress u-law */
+ val1 = chip->ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)];
+ val2 = chip->ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)];
+
+ /* interpolate */
+ val1 = interpolate(val1, val2, accum);
+ accum = (accum + freqcount) & voice->accum_mask;
+
+ /* apply filters */
+ apply_filters(voice, val1);
+
+ /* update filters/volumes */
+ if (voice->ecount != 0)
+ {
+ update_envelopes(voice, 1);
+ lvol = chip->volume_lookup[voice->lvol >> 4];
+ rvol = chip->volume_lookup[voice->rvol >> 4];
+ }
+
+ /* apply volumes and add */
+ *lbuffer++ += (val1 * lvol) >> 11;
+ *rbuffer++ += (val1 * rvol) >> 11;
+
+ /* check for loop end */
+ check_for_end_forward(voice, accum);
+ }
+ }
+
+ /* two cases: second case is backward direction */
+ else
+ {
+ /* loop while we still have samples to generate */
+ while (samples--)
+ {
+ /* fetch two samples */
+ INT32 val1 = base[accum >> 11];
+ INT32 val2 = base[((accum + (1 << 11)) & voice->accum_mask) >> 11];
+
+ /* decompress u-law */
+ val1 = chip->ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)];
+ val2 = chip->ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)];
+
+ /* interpolate */
+ val1 = interpolate(val1, val2, accum);
+ accum = (accum - freqcount) & voice->accum_mask;
+
+ /* apply filters */
+ apply_filters(voice, val1);
+
+ /* update filters/volumes */
+ if (voice->ecount != 0)
+ {
+ update_envelopes(voice, 1);
+ lvol = chip->volume_lookup[voice->lvol >> 4];
+ rvol = chip->volume_lookup[voice->rvol >> 4];
+ }
+
+ /* apply volumes and add */
+ *lbuffer++ += (val1 * lvol) >> 11;
+ *rbuffer++ += (val1 * rvol) >> 11;
+
+ /* check for loop end */
+ check_for_end_reverse(voice, accum);
+ }
+ }
+ }
+
+ /* if we stopped, process any additional envelope */
+alldone:
+ voice->accum = accum;
+ if (samples > 0)
+ update_envelopes(voice, samples);
+}
+
+
+
+/**********************************************************************************************
+
+ generate_pcm -- general PCM decoding routine
+
+***********************************************************************************************/
+
+static void generate_pcm(struct ES5506Chip *chip, struct ES5506Voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples)
+{
+ UINT32 freqcount = voice->freqcount;
+ UINT32 accum = voice->accum & voice->accum_mask;
+ INT32 lvol = chip->volume_lookup[voice->lvol >> 4];
+ INT32 rvol = chip->volume_lookup[voice->rvol >> 4];
+
+ /* pre-add the bank offset */
+ base += voice->exbank;
+
+ /* outer loop, in case we switch directions */
+ while (samples > 0 && !(voice->control & CONTROL_STOPMASK))
+ {
+reverse:
+ /* two cases: first case is forward direction */
+ if (!(voice->control & CONTROL_DIR))
+ {
+ /* loop while we still have samples to generate */
+ while (samples--)
+ {
+ /* fetch two samples */
+ INT32 val1 = (INT16)base[accum >> 11];
+ INT32 val2 = (INT16)base[((accum + (1 << 11)) & voice->accum_mask) >> 11];
+
+ /* interpolate */
+ val1 = interpolate(val1, val2, accum);
+ accum = (accum + freqcount) & voice->accum_mask;
+
+ /* apply filters */
+ apply_filters(voice, val1);
+
+ /* update filters/volumes */
+ if (voice->ecount != 0)
+ {
+ update_envelopes(voice, 1);
+ lvol = chip->volume_lookup[voice->lvol >> 4];
+ rvol = chip->volume_lookup[voice->rvol >> 4];
+ }
+
+ /* apply volumes and add */
+ *lbuffer++ += (val1 * lvol) >> 11;
+ *rbuffer++ += (val1 * rvol) >> 11;
+
+ /* check for loop end */
+ check_for_end_forward(voice, accum);
+ }
+ }
+
+ /* two cases: second case is backward direction */
+ else
+ {
+ /* loop while we still have samples to generate */
+ while (samples--)
+ {
+ /* fetch two samples */
+ INT32 val1 = (INT16)base[accum >> 11];
+ INT32 val2 = (INT16)base[((accum + (1 << 11)) & voice->accum_mask) >> 11];
+
+ /* interpolate */
+ val1 = interpolate(val1, val2, accum);
+ accum = (accum - freqcount) & voice->accum_mask;
+
+ /* apply filters */
+ apply_filters(voice, val1);
+
+ /* update filters/volumes */
+ if (voice->ecount != 0)
+ {
+ update_envelopes(voice, 1);
+ lvol = chip->volume_lookup[voice->lvol >> 4];
+ rvol = chip->volume_lookup[voice->rvol >> 4];
+ }
+
+ /* apply volumes and add */
+ *lbuffer++ += (val1 * lvol) >> 11;
+ *rbuffer++ += (val1 * rvol) >> 11;
+
+ /* check for loop end */
+ check_for_end_reverse(voice, accum);
+ }
+ }
+ }
+
+ /* if we stopped, process any additional envelope */
+alldone:
+ voice->accum = accum;
+ if (samples > 0)
+ update_envelopes(voice, samples);
+}
+
+
+
+/**********************************************************************************************
+
+ generate_samples -- tell each voice to generate samples
+
+***********************************************************************************************/
+
+static void generate_samples(struct ES5506Chip *chip, INT32 *left, INT32 *right, int samples)
+{
+ int v;
+
+ /* skip if nothing to do */
+ if (!samples)
+ return;
+
+ /* clear out the accumulator */
+ memset(left, 0, samples * sizeof(left[0]));
+ memset(right, 0, samples * sizeof(right[0]));
+
+ /* loop over voices */
+ for (v = 0; v <= chip->active_voices; v++)
+ {
+ struct ES5506Voice *voice = &chip->voice[v];
+ UINT16 *base = chip->region_base[voice->control >> 14];
+
+ /* special case: if end == start, stop the voice */
+ if (voice->start == voice->end)
+ voice->control |= CONTROL_STOP0;
+
+ /* generate from the appropriate source */
+ if (!base)
+ {
+ logerror("NULL region base %d\n",voice->control >> 14);
+ generate_dummy(chip, voice, base, left, right, samples);
+ }
+ else if (voice->control & 0x2000)
+ generate_ulaw(chip, voice, base, left, right, samples);
+ else
+ generate_pcm(chip, voice, base, left, right, samples);
+
+ /* does this voice have it's IRQ bit raised? */
+ if (voice->control&CONTROL_IRQ)
+ {
+logerror("IRQ raised on voice %d!!\n",v);
+ /* only update voice vector if existing IRQ is acked by host */
+ if (chip->irqv&0x80)
+ {
+ /* latch voice number into vector, and set high bit low */
+ chip->irqv=v&0x7f;
+
+ /* take down IRQ bit on voice */
+ voice->control&=~CONTROL_IRQ;
+
+ /* inform host of irq */
+ update_irq_state(chip);
+ }
+ }
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ es5506_update -- update the sound chip so that it is in sync with CPU execution
+
+***********************************************************************************************/
+
+static void es5506_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct ES5506Chip *chip = param;
+ INT32 *lsrc = chip->scratch, *rsrc = chip->scratch;
+ stream_sample_t *ldest = buffer[0];
+ stream_sample_t *rdest = buffer[1];
+
+#if MAKE_WAVS
+ /* start the logging once we have a sample rate */
+ if (chip->sample_rate)
+ {
+ if (!chip->wavraw)
+ chip->wavraw = wav_open("raw.wav", chip->sample_rate, 2);
+ }
+#endif
+
+ /* loop until all samples are output */
+ while (length)
+ {
+ int samples = (length > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : length;
+ int samp;
+
+ /* determine left/right source data */
+ lsrc = chip->scratch;
+ rsrc = chip->scratch + samples;
+ generate_samples(chip, lsrc, rsrc, samples);
+
+ /* copy the data */
+ for (samp = 0; samp < samples; samp++)
+ {
+ *ldest++ = lsrc[samp] >> 4;
+ *rdest++ = rsrc[samp] >> 4;
+ }
+
+#if MAKE_WAVS
+ /* log the raw data */
+ if (chip->wavraw)
+ wav_add_data_32lr(chip->wavraw, lsrc, rsrc, samples, 4);
+#endif
+
+ /* account for these samples */
+ length -= samples;
+ }
+}
+
+
+/**********************************************************************************************
+
+ ES5506_sh_start -- start emulation of the ES5506
+
+***********************************************************************************************/
+
+static void *es5506_start_common(sound_type sndtype, int sndindex, int clock, const void *config)
+{
+ const struct ES5506interface *intf = config;
+ struct ES5506Chip *chip;
+ int j;
+ UINT32 accum_mask;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ /* debugging */
+ if (LOG_COMMANDS && !eslog)
+ eslog = fopen("es.log", "w");
+
+ /* compute the tables */
+ if (!compute_tables(chip))
+ return NULL;
+
+ /* create the stream */
+ chip->stream = stream_create(0, 2, clock / (16*32), chip, es5506_update);
+
+ /* initialize the regions */
+ chip->region_base[0] = intf->region0 ? (UINT16 *)memory_region(intf->region0) : NULL;
+ chip->region_base[1] = intf->region1 ? (UINT16 *)memory_region(intf->region1) : NULL;
+ chip->region_base[2] = intf->region2 ? (UINT16 *)memory_region(intf->region2) : NULL;
+ chip->region_base[3] = intf->region3 ? (UINT16 *)memory_region(intf->region3) : NULL;
+
+ /* initialize the rest of the structure */
+ chip->master_clock = clock;
+ chip->irq_callback = intf->irq_callback;
+ chip->irqv = 0x80;
+
+ /* init the voices */
+ accum_mask = (sndtype == SOUND_ES5506) ? 0xffffffff : 0x7fffffff;
+ for (j = 0; j < 32; j++)
+ {
+ chip->voice[j].index = j;
+ chip->voice[j].control = CONTROL_STOPMASK;
+ chip->voice[j].lvol = 0xffff;
+ chip->voice[j].rvol = 0xffff;
+ chip->voice[j].exbank = 0;
+ chip->voice[j].accum_mask = accum_mask;
+ }
+
+ /* allocate memory */
+ chip->scratch = auto_malloc(sizeof(chip->scratch[0]) * 2 * MAX_SAMPLE_CHUNK);
+
+ /* success */
+ return chip;
+}
+
+
+static void *es5506_start(int sndindex, int clock, const void *config)
+{
+ return es5506_start_common(SOUND_ES5506, sndindex, clock, config);
+}
+
+
+
+/**********************************************************************************************
+
+ ES5506_stop -- stop emulation of the ES5506
+
+***********************************************************************************************/
+
+static void es5506_stop(void *chip)
+{
+ /* debugging */
+ if (LOG_COMMANDS && eslog)
+ {
+ fclose(eslog);
+ eslog = NULL;
+ }
+
+#if MAKE_WAVS
+{
+ int i;
+
+ for (i = 0; i < MAX_ES5506; i++)
+ {
+ if (es5506[i].wavraw)
+ wav_close(es5506[i].wavraw);
+ }
+}
+#endif
+}
+
+
+static void es5506_reset(void *chip)
+{
+}
+
+
+
+/**********************************************************************************************
+
+ es5506_reg_write -- handle a write to the selected ES5506 register
+
+***********************************************************************************************/
+
+INLINE void es5506_reg_write_low(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset, UINT32 data)
+{
+ switch (offset)
+ {
+ case 0x00/8: /* CR */
+ voice->control = data & 0xffff;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, control=%04x\n", chip->current_page & 0x1f, voice->control);
+ break;
+
+ case 0x08/8: /* FC */
+ voice->freqcount = data & 0x1ffff;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, freq count=%08x\n", chip->current_page & 0x1f, voice->freqcount);
+ break;
+
+ case 0x10/8: /* LVOL */
+ voice->lvol = data & 0xffff;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, left vol=%04x\n", chip->current_page & 0x1f, voice->lvol);
+ break;
+
+ case 0x18/8: /* LVRAMP */
+ voice->lvramp = (data & 0xff00) >> 8;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, left vol ramp=%04x\n", chip->current_page & 0x1f, voice->lvramp);
+ break;
+
+ case 0x20/8: /* RVOL */
+ voice->rvol = data & 0xffff;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, right vol=%04x\n", chip->current_page & 0x1f, voice->rvol);
+ break;
+
+ case 0x28/8: /* RVRAMP */
+ voice->rvramp = (data & 0xff00) >> 8;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, right vol ramp=%04x\n", chip->current_page & 0x1f, voice->rvramp);
+ break;
+
+ case 0x30/8: /* ECOUNT */
+ voice->ecount = data & 0x1ff;
+ voice->filtcount = 0;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, envelope count=%04x\n", chip->current_page & 0x1f, voice->ecount);
+ break;
+
+ case 0x38/8: /* K2 */
+ voice->k2 = data & 0xffff;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, K2=%04x\n", chip->current_page & 0x1f, voice->k2);
+ break;
+
+ case 0x40/8: /* K2RAMP */
+ voice->k2ramp = ((data & 0xff00) >> 8) | ((data & 0x0001) << 31);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, K2 ramp=%04x\n", chip->current_page & 0x1f, voice->k2ramp);
+ break;
+
+ case 0x48/8: /* K1 */
+ voice->k1 = data & 0xffff;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, K1=%04x\n", chip->current_page & 0x1f, voice->k1);
+ break;
+
+ case 0x50/8: /* K1RAMP */
+ voice->k1ramp = ((data & 0xff00) >> 8) | ((data & 0x0001) << 31);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, K1 ramp=%04x\n", chip->current_page & 0x1f, voice->k1ramp);
+ break;
+
+ case 0x58/8: /* ACTV */
+ {
+ chip->active_voices = data & 0x1f;
+ chip->sample_rate = chip->master_clock / (16 * (chip->active_voices + 1));
+ stream_set_sample_rate(chip->stream, chip->sample_rate);
+
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "active voices=%d, sample_rate=%d\n", chip->active_voices, chip->sample_rate);
+ break;
+ }
+
+ case 0x60/8: /* MODE */
+ chip->mode = data & 0x1f;
+ break;
+
+ case 0x68/8: /* PAR - read only */
+ case 0x70/8: /* IRQV - read only */
+ break;
+
+ case 0x78/8: /* PAGE */
+ chip->current_page = data & 0x7f;
+ break;
+ }
+}
+
+
+INLINE void es5506_reg_write_high(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset, UINT32 data)
+{
+ switch (offset)
+ {
+ case 0x00/8: /* CR */
+ voice->control = data & 0xffff;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, control=%04x\n", chip->current_page & 0x1f, voice->control);
+ break;
+
+ case 0x08/8: /* START */
+ voice->start = data & 0xfffff800;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, loop start=%08x\n", chip->current_page & 0x1f, voice->start);
+ break;
+
+ case 0x10/8: /* END */
+ voice->end = data & 0xffffff80;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, loop end=%08x\n", chip->current_page & 0x1f, voice->end);
+ break;
+
+ case 0x18/8: /* ACCUM */
+ voice->accum = data;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, accum=%08x\n", chip->current_page & 0x1f, voice->accum);
+ break;
+
+ case 0x20/8: /* O4(n-1) */
+ voice->o4n1 = (INT32)(data << 14) >> 14;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, O4(n-1)=%05x\n", chip->current_page & 0x1f, voice->o4n1 & 0x3ffff);
+ break;
+
+ case 0x28/8: /* O3(n-1) */
+ voice->o3n1 = (INT32)(data << 14) >> 14;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, O3(n-1)=%05x\n", chip->current_page & 0x1f, voice->o3n1 & 0x3ffff);
+ break;
+
+ case 0x30/8: /* O3(n-2) */
+ voice->o3n2 = (INT32)(data << 14) >> 14;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, O3(n-2)=%05x\n", chip->current_page & 0x1f, voice->o3n2 & 0x3ffff);
+ break;
+
+ case 0x38/8: /* O2(n-1) */
+ voice->o2n1 = (INT32)(data << 14) >> 14;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, O2(n-1)=%05x\n", chip->current_page & 0x1f, voice->o2n1 & 0x3ffff);
+ break;
+
+ case 0x40/8: /* O2(n-2) */
+ voice->o2n2 = (INT32)(data << 14) >> 14;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, O2(n-2)=%05x\n", chip->current_page & 0x1f, voice->o2n2 & 0x3ffff);
+ break;
+
+ case 0x48/8: /* O1(n-1) */
+ voice->o1n1 = (INT32)(data << 14) >> 14;
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "voice %d, O1(n-1)=%05x\n", chip->current_page & 0x1f, voice->o1n1 & 0x3ffff);
+ break;
+
+ case 0x50/8: /* W_ST */
+ chip->wst = data & 0x7f;
+ break;
+
+ case 0x58/8: /* W_END */
+ chip->wend = data & 0x7f;
+ break;
+
+ case 0x60/8: /* LR_END */
+ chip->lrend = data & 0x7f;
+ break;
+
+ case 0x68/8: /* PAR - read only */
+ case 0x70/8: /* IRQV - read only */
+ break;
+
+ case 0x78/8: /* PAGE */
+ chip->current_page = data & 0x7f;
+ break;
+ }
+}
+
+INLINE void es5506_reg_write_test(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset, UINT32 data)
+{
+ switch (offset)
+ {
+ case 0x00/8: /* CHANNEL 0 LEFT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 0 left test write %08x\n", data);
+ break;
+
+ case 0x08/8: /* CHANNEL 0 RIGHT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 0 right test write %08x\n", data);
+ break;
+
+ case 0x10/8: /* CHANNEL 1 LEFT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 1 left test write %08x\n", data);
+ break;
+
+ case 0x18/8: /* CHANNEL 1 RIGHT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 1 right test write %08x\n", data);
+ break;
+
+ case 0x20/8: /* CHANNEL 2 LEFT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 2 left test write %08x\n", data);
+ break;
+
+ case 0x28/8: /* CHANNEL 2 RIGHT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 2 right test write %08x\n", data);
+ break;
+
+ case 0x30/8: /* CHANNEL 3 LEFT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 3 left test write %08x\n", data);
+ break;
+
+ case 0x38/8: /* CHANNEL 3 RIGHT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 3 right test write %08x\n", data);
+ break;
+
+ case 0x40/8: /* CHANNEL 4 LEFT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 4 left test write %08x\n", data);
+ break;
+
+ case 0x48/8: /* CHANNEL 4 RIGHT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 4 right test write %08x\n", data);
+ break;
+
+ case 0x50/8: /* CHANNEL 5 LEFT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 5 left test write %08x\n", data);
+ break;
+
+ case 0x58/8: /* CHANNEL 6 RIGHT */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Channel 5 right test write %08x\n", data);
+ break;
+
+ case 0x60/8: /* EMPTY */
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "Test write EMPTY %08x\n", data);
+ break;
+
+ case 0x68/8: /* PAR - read only */
+ case 0x70/8: /* IRQV - read only */
+ break;
+
+ case 0x78/8: /* PAGE */
+ chip->current_page = data & 0x7f;
+ break;
+ }
+}
+
+static void es5506_reg_write(struct ES5506Chip *chip, offs_t offset, UINT8 data)
+{
+ struct ES5506Voice *voice = &chip->voice[chip->current_page & 0x1f];
+ int shift = 8 * (offset & 3);
+
+ /* accumulate the data */
+ chip->write_latch = (chip->write_latch & ~(0xff000000 >> shift)) | (data << (24 - shift));
+
+ /* wait for a write to complete */
+ if (shift != 24)
+ return;
+
+ /* force an update */
+ stream_update(chip->stream);
+
+ /* switch off the page and register */
+ if (chip->current_page < 0x20)
+ es5506_reg_write_low(chip, voice, offset / 4, chip->write_latch);
+ else if (chip->current_page < 0x40)
+ es5506_reg_write_high(chip, voice, offset / 4, chip->write_latch);
+ else
+ es5506_reg_write_test(chip, voice, offset / 4, chip->write_latch);
+
+ /* clear the write latch when done */
+ chip->write_latch = 0;
+}
+
+
+
+/**********************************************************************************************
+
+ es5506_reg_read -- read from the specified ES5506 register
+
+***********************************************************************************************/
+
+INLINE UINT32 es5506_reg_read_low(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset)
+{
+ UINT32 result = 0;
+
+ switch (offset)
+ {
+ case 0x00/8: /* CR */
+ result = voice->control;
+ break;
+
+ case 0x08/8: /* FC */
+ result = voice->freqcount;
+ break;
+
+ case 0x10/8: /* LVOL */
+ result = voice->lvol;
+ break;
+
+ case 0x18/8: /* LVRAMP */
+ result = voice->lvramp << 8;
+ break;
+
+ case 0x20/8: /* RVOL */
+ result = voice->rvol;
+ break;
+
+ case 0x28/8: /* RVRAMP */
+ result = voice->rvramp << 8;
+ break;
+
+ case 0x30/8: /* ECOUNT */
+ result = voice->ecount;
+ break;
+
+ case 0x38/8: /* K2 */
+ result = voice->k2;
+ break;
+
+ case 0x40/8: /* K2RAMP */
+ result = (voice->k2ramp << 8) | (voice->k2ramp >> 31);
+ break;
+
+ case 0x48/8: /* K1 */
+ result = voice->k1;
+ break;
+
+ case 0x50/8: /* K1RAMP */
+ result = (voice->k1ramp << 8) | (voice->k1ramp >> 31);
+ break;
+
+ case 0x58/8: /* ACTV */
+ result = chip->active_voices;
+ break;
+
+ case 0x60/8: /* MODE */
+ result = chip->mode;
+ break;
+
+ case 0x68/8: /* PAR */
+ if (chip->port_read)
+ result = (*chip->port_read)();
+ break;
+
+ case 0x70/8: /* IRQV */
+ result = chip->irqv;
+ update_internal_irq_state(chip);
+ break;
+
+ case 0x78/8: /* PAGE */
+ result = chip->current_page;
+ break;
+ }
+ return result;
+}
+
+
+INLINE UINT32 es5506_reg_read_high(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset)
+{
+ UINT32 result = 0;
+
+ switch (offset)
+ {
+ case 0x00/8: /* CR */
+ result = voice->control;
+ break;
+
+ case 0x08/8: /* START */
+ result = voice->start;
+ break;
+
+ case 0x10/8: /* END */
+ result = voice->end;
+ break;
+
+ case 0x18/8: /* ACCUM */
+ result = voice->accum;
+ break;
+
+ case 0x20/8: /* O4(n-1) */
+ result = voice->o4n1 & 0x3ffff;
+ break;
+
+ case 0x28/8: /* O3(n-1) */
+ result = voice->o3n1 & 0x3ffff;
+ break;
+
+ case 0x30/8: /* O3(n-2) */
+ result = voice->o3n2 & 0x3ffff;
+ break;
+
+ case 0x38/8: /* O2(n-1) */
+ result = voice->o2n1 & 0x3ffff;
+ break;
+
+ case 0x40/8: /* O2(n-2) */
+ result = voice->o2n2 & 0x3ffff;
+ break;
+
+ case 0x48/8: /* O1(n-1) */
+ result = voice->o1n1 & 0x3ffff;
+ break;
+
+ case 0x50/8: /* W_ST */
+ result = chip->wst;
+ break;
+
+ case 0x58/8: /* W_END */
+ result = chip->wend;
+ break;
+
+ case 0x60/8: /* LR_END */
+ result = chip->lrend;
+ break;
+
+ case 0x68/8: /* PAR */
+ if (chip->port_read)
+ result = (*chip->port_read)();
+ break;
+
+ case 0x70/8: /* IRQV */
+ result = chip->irqv;
+ update_internal_irq_state(chip);
+ break;
+
+ case 0x78/8: /* PAGE */
+ result = chip->current_page;
+ break;
+ }
+ return result;
+}
+
+INLINE UINT32 es5506_reg_read_test(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset)
+{
+ UINT32 result = 0;
+
+ switch (offset)
+ {
+ case 0x68/8: /* PAR */
+ if (chip->port_read)
+ result = (*chip->port_read)();
+ break;
+
+ case 0x70/8: /* IRQV */
+ result = chip->irqv;
+ break;
+
+ case 0x78/8: /* PAGE */
+ result = chip->current_page;
+ break;
+ }
+ return result;
+}
+
+static UINT8 es5506_reg_read(struct ES5506Chip *chip, offs_t offset)
+{
+ struct ES5506Voice *voice = &chip->voice[chip->current_page & 0x1f];
+ int shift = 8 * (offset & 3);
+
+ /* only read on offset 0 */
+ if (shift != 0)
+ return chip->read_latch >> (24 - shift);
+
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "read from %02x/%02x -> ", chip->current_page, offset / 4 * 8);
+
+ /* force an update */
+ stream_update(chip->stream);
+
+ /* switch off the page and register */
+ if (chip->current_page < 0x20)
+ chip->read_latch = es5506_reg_read_low(chip, voice, offset / 4);
+ else if (chip->current_page < 0x40)
+ chip->read_latch = es5506_reg_read_high(chip, voice, offset / 4);
+ else
+ chip->read_latch = es5506_reg_read_test(chip, voice, offset / 4);
+
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%08x\n", chip->read_latch);
+
+ /* return the high byte */
+ return chip->read_latch >> 24;
+}
+
+
+
+/**********************************************************************************************
+
+ ES5506_data_0_r/ES5506_data_1_r -- handle a read from the status register
+
+**********************************************************************************************/
+
+READ8_HANDLER( ES5506_data_0_r )
+{
+ return es5506_reg_read(sndti_token(SOUND_ES5506, 0), offset);
+}
+
+READ8_HANDLER( ES5506_data_1_r )
+{
+ return es5506_reg_read(sndti_token(SOUND_ES5506, 1), offset);
+}
+
+READ16_HANDLER( ES5506_data_0_word_r )
+{
+ return es5506_reg_read(sndti_token(SOUND_ES5506, 0), offset);
+}
+
+READ16_HANDLER( ES5506_data_1_word_r )
+{
+ return es5506_reg_read(sndti_token(SOUND_ES5506, 1), offset);
+}
+
+
+
+/**********************************************************************************************
+
+ ES5506_data_0_w/ES5506_data_1_w -- handle a write to the current register
+
+***********************************************************************************************/
+
+WRITE8_HANDLER( ES5506_data_0_w )
+{
+ es5506_reg_write(sndti_token(SOUND_ES5506, 0), offset, data);
+}
+
+WRITE8_HANDLER( ES5506_data_1_w )
+{
+ es5506_reg_write(sndti_token(SOUND_ES5506, 1), offset, data);
+}
+
+WRITE16_HANDLER( ES5506_data_0_word_w )
+{
+ if (ACCESSING_LSB)
+ es5506_reg_write(sndti_token(SOUND_ES5506, 0), offset, data);
+}
+
+WRITE16_HANDLER( ES5506_data_1_word_w )
+{
+ if (ACCESSING_LSB)
+ es5506_reg_write(sndti_token(SOUND_ES5506, 1), offset, data);
+}
+
+
+
+void ES5506_voice_bank_0_w(int voice, int bank)
+{
+ struct ES5506Chip *chip = sndti_token(SOUND_ES5506, 0);
+ chip->voice[voice].exbank=bank;
+}
+
+void ES5506_voice_bank_1_w(int voice, int bank)
+{
+ struct ES5506Chip *chip = sndti_token(SOUND_ES5506, 1);
+ chip->voice[voice].exbank=bank;
+}
+
+
+/**********************************************************************************************
+
+ ES5505_start -- start emulation of the ES5505
+
+***********************************************************************************************/
+
+static void *es5505_start(int sndindex, int clock, const void *config)
+{
+ const struct ES5505interface *intf = config;
+ struct ES5506interface es5506intf;
+
+ memset(&es5506intf, 0, sizeof(es5506intf));
+
+ es5506intf.region0 = intf->region0;
+ es5506intf.region1 = intf->region1;
+ es5506intf.irq_callback = intf->irq_callback;
+ es5506intf.read_port = intf->read_port;
+
+ return es5506_start_common(SOUND_ES5505, sndindex, clock, &es5506intf);
+}
+
+
+
+/**********************************************************************************************
+
+ ES5505_stop -- stop emulation of the ES5506
+
+***********************************************************************************************/
+
+static void es5505_stop(void *chip)
+{
+ es5506_stop(chip);
+}
+
+
+static void es5505_reset(void *chip)
+{
+ es5506_reset(chip);
+}
+
+
+
+/**********************************************************************************************
+
+ es5505_reg_write -- handle a write to the selected ES5505 register
+
+***********************************************************************************************/
+
+INLINE void es5505_reg_write_low(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset, UINT16 data, UINT16 mem_mask)
+{
+ switch (offset)
+ {
+ case 0x00: /* CR */
+ if (ACCESSING_LSB)
+ {
+#if RAINE_CHECK
+ voice->control &= ~(CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_DIR);
+#else
+ voice->control &= ~(CONTROL_STOPMASK | CONTROL_BS0 | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ);
+#endif
+ voice->control |= (data & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) |
+ ((data << 12) & CONTROL_BS0);
+ }
+ if (ACCESSING_MSB)
+ {
+ voice->control &= ~(CONTROL_CA0 | CONTROL_CA1 | CONTROL_LPMASK);
+ voice->control |= ((data >> 2) & CONTROL_LPMASK) |
+ ((data << 2) & (CONTROL_CA0 | CONTROL_CA1));
+ }
+
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, control=%04x (raw=%04x & %04x)\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->control, data, mem_mask ^ 0xffff);
+ break;
+
+ case 0x01: /* FC */
+ if (ACCESSING_LSB)
+ voice->freqcount = (voice->freqcount & ~0x001fe) | ((data & 0x00ff) << 1);
+ if (ACCESSING_MSB)
+ voice->freqcount = (voice->freqcount & ~0x1fe00) | ((data & 0xff00) << 1);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, freq count=%08x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->freqcount);
+ break;
+
+ case 0x02: /* STRT (hi) */
+ if (ACCESSING_LSB)
+ voice->start = (voice->start & ~0x03fc0000) | ((data & 0x00ff) << 18);
+ if (ACCESSING_MSB)
+ voice->start = (voice->start & ~0x7c000000) | ((data & 0x1f00) << 18);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, loop start=%08x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->start);
+ break;
+
+ case 0x03: /* STRT (lo) */
+ if (ACCESSING_LSB)
+ voice->start = (voice->start & ~0x00000380) | ((data & 0x00e0) << 2);
+ if (ACCESSING_MSB)
+ voice->start = (voice->start & ~0x0003fc00) | ((data & 0xff00) << 2);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, loop start=%08x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->start);
+ break;
+
+ case 0x04: /* END (hi) */
+ if (ACCESSING_LSB)
+ voice->end = (voice->end & ~0x03fc0000) | ((data & 0x00ff) << 18);
+ if (ACCESSING_MSB)
+ voice->end = (voice->end & ~0x7c000000) | ((data & 0x1f00) << 18);
+#if RAINE_CHECK
+ voice->control |= CONTROL_STOP0;
+#endif
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, loop end=%08x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->end);
+ break;
+
+ case 0x05: /* END (lo) */
+ if (ACCESSING_LSB)
+ voice->end = (voice->end & ~0x00000380) | ((data & 0x00e0) << 2);
+ if (ACCESSING_MSB)
+ voice->end = (voice->end & ~0x0003fc00) | ((data & 0xff00) << 2);
+#if RAINE_CHECK
+ voice->control |= CONTROL_STOP0;
+#endif
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, loop end=%08x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->end);
+ break;
+
+ case 0x06: /* K2 */
+ if (ACCESSING_LSB)
+ voice->k2 = (voice->k2 & ~0x00f0) | (data & 0x00f0);
+ if (ACCESSING_MSB)
+ voice->k2 = (voice->k2 & ~0xff00) | (data & 0xff00);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, K2=%04x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->k2);
+ break;
+
+ case 0x07: /* K1 */
+ if (ACCESSING_LSB)
+ voice->k1 = (voice->k1 & ~0x00f0) | (data & 0x00f0);
+ if (ACCESSING_MSB)
+ voice->k1 = (voice->k1 & ~0xff00) | (data & 0xff00);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, K1=%04x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->k1);
+ break;
+
+ case 0x08: /* LVOL */
+ if (ACCESSING_MSB)
+ voice->lvol = (voice->lvol & ~0xff00) | (data & 0xff00);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, left vol=%04x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->lvol);
+ break;
+
+ case 0x09: /* RVOL */
+ if (ACCESSING_MSB)
+ voice->rvol = (voice->rvol & ~0xff00) | (data & 0xff00);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, right vol=%04x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->rvol);
+ break;
+
+ case 0x0a: /* ACC (hi) */
+ if (ACCESSING_LSB)
+ voice->accum = (voice->accum & ~0x03fc0000) | ((data & 0x00ff) << 18);
+ if (ACCESSING_MSB)
+ voice->accum = (voice->accum & ~0x7c000000) | ((data & 0x1f00) << 18);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, accum=%08x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->accum);
+ break;
+
+ case 0x0b: /* ACC (lo) */
+ if (ACCESSING_LSB)
+ voice->accum = (voice->accum & ~0x000003fc) | ((data & 0x00ff) << 2);
+ if (ACCESSING_MSB)
+ voice->accum = (voice->accum & ~0x0003fc00) | ((data & 0xff00) << 2);
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, accum=%08x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->accum);
+ break;
+
+ case 0x0c: /* unused */
+ break;
+
+ case 0x0d: /* ACT */
+ if (ACCESSING_LSB)
+ {
+ chip->active_voices = data & 0x1f;
+ chip->sample_rate = chip->master_clock / (16 * (chip->active_voices + 1));
+ stream_set_sample_rate(chip->stream, chip->sample_rate);
+
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "active voices=%d, sample_rate=%d\n", chip->active_voices, chip->sample_rate);
+ }
+ break;
+
+ case 0x0e: /* IRQV - read only */
+ break;
+
+ case 0x0f: /* PAGE */
+ if (ACCESSING_LSB)
+ chip->current_page = data & 0x7f;
+ break;
+ }
+}
+
+
+INLINE void es5505_reg_write_high(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset, UINT16 data, UINT16 mem_mask)
+{
+ switch (offset)
+ {
+ case 0x00: /* CR */
+ if (ACCESSING_LSB)
+ {
+ voice->control &= ~(CONTROL_STOPMASK | CONTROL_BS0 | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ);
+ voice->control |= (data & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) |
+ ((data << 12) & CONTROL_BS0);
+ }
+ if (ACCESSING_MSB)
+ {
+ voice->control &= ~(CONTROL_CA0 | CONTROL_CA1 | CONTROL_LPMASK);
+ voice->control |= ((data >> 2) & CONTROL_LPMASK) |
+ ((data << 2) & (CONTROL_CA0 | CONTROL_CA1));
+ }
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, control=%04x (raw=%04x & %04x)\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->control, data, mem_mask ^ 0xffff);
+ break;
+
+ case 0x01: /* O4(n-1) */
+ if (ACCESSING_LSB)
+ voice->o4n1 = (voice->o4n1 & ~0x00ff) | (data & 0x00ff);
+ if (ACCESSING_MSB)
+ voice->o4n1 = (INT16)((voice->o4n1 & ~0xff00) | (data & 0xff00));
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, O4(n-1)=%05x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->o4n1 & 0x3ffff);
+ break;
+
+ case 0x02: /* O3(n-1) */
+ if (ACCESSING_LSB)
+ voice->o3n1 = (voice->o3n1 & ~0x00ff) | (data & 0x00ff);
+ if (ACCESSING_MSB)
+ voice->o3n1 = (INT16)((voice->o3n1 & ~0xff00) | (data & 0xff00));
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, O3(n-1)=%05x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->o3n1 & 0x3ffff);
+ break;
+
+ case 0x03: /* O3(n-2) */
+ if (ACCESSING_LSB)
+ voice->o3n2 = (voice->o3n2 & ~0x00ff) | (data & 0x00ff);
+ if (ACCESSING_MSB)
+ voice->o3n2 = (INT16)((voice->o3n2 & ~0xff00) | (data & 0xff00));
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, O3(n-2)=%05x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->o3n2 & 0x3ffff);
+ break;
+
+ case 0x04: /* O2(n-1) */
+ if (ACCESSING_LSB)
+ voice->o2n1 = (voice->o2n1 & ~0x00ff) | (data & 0x00ff);
+ if (ACCESSING_MSB)
+ voice->o2n1 = (INT16)((voice->o2n1 & ~0xff00) | (data & 0xff00));
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, O2(n-1)=%05x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->o2n1 & 0x3ffff);
+ break;
+
+ case 0x05: /* O2(n-2) */
+ if (ACCESSING_LSB)
+ voice->o2n2 = (voice->o2n2 & ~0x00ff) | (data & 0x00ff);
+ if (ACCESSING_MSB)
+ voice->o2n2 = (INT16)((voice->o2n2 & ~0xff00) | (data & 0xff00));
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, O2(n-2)=%05x\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->o2n2 & 0x3ffff);
+ break;
+
+ case 0x06: /* O1(n-1) */
+ if (ACCESSING_LSB)
+ voice->o1n1 = (voice->o1n1 & ~0x00ff) | (data & 0x00ff);
+ if (ACCESSING_MSB)
+ voice->o1n1 = (INT16)((voice->o1n1 & ~0xff00) | (data & 0xff00));
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%06x:voice %d, O1(n-1)=%05x (accum=%08x)\n", activecpu_get_previouspc(), chip->current_page & 0x1f, voice->o2n1 & 0x3ffff, voice->accum);
+ break;
+
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c: /* unused */
+ break;
+
+ case 0x0d: /* ACT */
+ if (ACCESSING_LSB)
+ {
+ chip->active_voices = data & 0x1f;
+ chip->sample_rate = chip->master_clock / (16 * (chip->active_voices + 1));
+ stream_set_sample_rate(chip->stream, chip->sample_rate);
+
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "active voices=%d, sample_rate=%d\n", chip->active_voices, chip->sample_rate);
+ }
+ break;
+
+ case 0x0e: /* IRQV - read only */
+ break;
+
+ case 0x0f: /* PAGE */
+ if (ACCESSING_LSB)
+ chip->current_page = data & 0x7f;
+ break;
+ }
+}
+
+
+INLINE void es5505_reg_write_test(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset, UINT16 data, UINT16 mem_mask)
+{
+ switch (offset)
+ {
+ case 0x00: /* CH0L */
+ case 0x01: /* CH0R */
+ case 0x02: /* CH1L */
+ case 0x03: /* CH1R */
+ case 0x04: /* CH2L */
+ case 0x05: /* CH2R */
+ case 0x06: /* CH3L */
+ case 0x07: /* CH3R */
+ break;
+
+ case 0x08: /* SERMODE */
+ chip->mode = data & 0x0007;
+ break;
+
+ case 0x09: /* PAR */
+ break;
+
+ case 0x0d: /* ACT */
+ if (ACCESSING_LSB)
+ {
+ chip->active_voices = data & 0x1f;
+ chip->sample_rate = chip->master_clock / (16 * (chip->active_voices + 1));
+ stream_set_sample_rate(chip->stream, chip->sample_rate);
+
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "active voices=%d, sample_rate=%d\n", chip->active_voices, chip->sample_rate);
+ }
+ break;
+
+ case 0x0e: /* IRQV - read only */
+ break;
+
+ case 0x0f: /* PAGE */
+ if (ACCESSING_LSB)
+ chip->current_page = data & 0x7f;
+ break;
+ }
+}
+
+
+static void es5505_reg_write(struct ES5506Chip *chip, offs_t offset, UINT16 data, UINT16 mem_mask)
+{
+ struct ES5506Voice *voice = &chip->voice[chip->current_page & 0x1f];
+
+// logerror("%04x:ES5505 write %02x/%02x = %04x & %04x\n", activecpu_get_previouspc(), chip->current_page, offset, data, mem_mask ^ 0xffff);
+
+ /* force an update */
+ stream_update(chip->stream);
+
+ /* switch off the page and register */
+ if (chip->current_page < 0x20)
+ es5505_reg_write_low(chip, voice, offset, data, mem_mask);
+ else if (chip->current_page < 0x40)
+ es5505_reg_write_high(chip, voice, offset, data, mem_mask);
+ else
+ es5505_reg_write_test(chip, voice, offset, data, mem_mask);
+}
+
+
+
+/**********************************************************************************************
+
+ es5505_reg_read -- read from the specified ES5505 register
+
+***********************************************************************************************/
+
+INLINE UINT16 es5505_reg_read_low(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset)
+{
+ UINT16 result = 0;
+
+ switch (offset)
+ {
+ case 0x00: /* CR */
+ result = (voice->control & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) |
+ ((voice->control & CONTROL_BS0) >> 12) |
+ ((voice->control & CONTROL_LPMASK) << 2) |
+ ((voice->control & (CONTROL_CA0 | CONTROL_CA1)) >> 2) |
+ 0xf000;
+ break;
+
+ case 0x01: /* FC */
+ result = voice->freqcount >> 1;
+ break;
+
+ case 0x02: /* STRT (hi) */
+ result = voice->start >> 18;
+ break;
+
+ case 0x03: /* STRT (lo) */
+ result = voice->start >> 2;
+ break;
+
+ case 0x04: /* END (hi) */
+ result = voice->end >> 18;
+ break;
+
+ case 0x05: /* END (lo) */
+ result = voice->end >> 2;
+ break;
+
+ case 0x06: /* K2 */
+ result = voice->k2;
+ break;
+
+ case 0x07: /* K1 */
+ result = voice->k1;
+ break;
+
+ case 0x08: /* LVOL */
+ result = voice->lvol;
+ break;
+
+ case 0x09: /* RVOL */
+ result = voice->rvol;
+ break;
+
+ case 0x0a: /* ACC (hi) */
+ result = voice->accum >> 18;
+ break;
+
+ case 0x0b: /* ACC (lo) */
+ result = voice->accum >> 2;
+ break;
+
+ case 0x0c: /* unused */
+ break;
+
+ case 0x0d: /* ACT */
+ result = chip->active_voices;
+ break;
+
+ case 0x0e: /* IRQV */
+ result = chip->irqv;
+ update_internal_irq_state(chip);
+ break;
+
+ case 0x0f: /* PAGE */
+ result = chip->current_page;
+ break;
+ }
+ return result;
+}
+
+
+INLINE UINT16 es5505_reg_read_high(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset)
+{
+ UINT16 result = 0;
+
+ switch (offset)
+ {
+ case 0x00: /* CR */
+ result = (voice->control & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) |
+ ((voice->control & CONTROL_BS0) >> 12) |
+ ((voice->control & CONTROL_LPMASK) << 2) |
+ ((voice->control & (CONTROL_CA0 | CONTROL_CA1)) >> 2) |
+ 0xf000;
+ break;
+
+ case 0x01: /* O4(n-1) */
+ result = voice->o4n1;
+ break;
+
+ case 0x02: /* O3(n-1) */
+ result = voice->o3n1;
+ break;
+
+ case 0x03: /* O3(n-2) */
+ result = voice->o3n2;
+ break;
+
+ case 0x04: /* O2(n-1) */
+ result = voice->o2n1;
+ break;
+
+ case 0x05: /* O2(n-2) */
+ result = voice->o2n2;
+ break;
+
+ case 0x06: /* O1(n-1) */
+ /* special case for the Taito F3 games: they set the accumulator on a stopped */
+ /* voice and assume the filters continue to process the data. They then read */
+ /* the O1(n-1) in order to extract raw data from the sound ROMs. Since we don't */
+ /* want to waste time filtering stopped channels, we just look for a read from */
+ /* this register on a stopped voice, and return the raw sample data at the */
+ /* accumulator */
+ if ((voice->control & CONTROL_STOPMASK) && chip->region_base[voice->control >> 14]) {
+ voice->o1n1 = chip->region_base[voice->control >> 14][voice->exbank + (voice->accum >> 11)];
+ logerror("%02x %08x ==> %08x\n",voice->o1n1,voice->control >> 14,voice->exbank + (voice->accum >> 11));
+ }
+ result = voice->o1n1;
+ break;
+
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c: /* unused */
+ break;
+
+ case 0x0d: /* ACT */
+ result = chip->active_voices;
+ break;
+
+ case 0x0e: /* IRQV */
+ result = chip->irqv;
+ update_internal_irq_state(chip);
+ break;
+
+ case 0x0f: /* PAGE */
+ result = chip->current_page;
+ break;
+ }
+ return result;
+}
+
+
+INLINE UINT16 es5505_reg_read_test(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset)
+{
+ UINT16 result = 0;
+
+ switch (offset)
+ {
+ case 0x00: /* CH0L */
+ case 0x01: /* CH0R */
+ case 0x02: /* CH1L */
+ case 0x03: /* CH1R */
+ case 0x04: /* CH2L */
+ case 0x05: /* CH2R */
+ case 0x06: /* CH3L */
+ case 0x07: /* CH3R */
+ break;
+
+ case 0x08: /* SERMODE */
+ result = chip->mode;
+ break;
+
+ case 0x09: /* PAR */
+ if (chip->port_read)
+ result = (*chip->port_read)();
+ break;
+
+ case 0x0f: /* PAGE */
+ result = chip->current_page;
+ break;
+ }
+ return result;
+}
+
+
+static UINT16 es5505_reg_read(struct ES5506Chip *chip, offs_t offset)
+{
+ struct ES5506Voice *voice = &chip->voice[chip->current_page & 0x1f];
+ UINT16 result = 0;
+
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "read from %02x/%02x -> ", chip->current_page, offset);
+
+ /* force an update */
+ stream_update(chip->stream);
+
+ /* switch off the page and register */
+ if (chip->current_page < 0x20)
+ result = es5505_reg_read_low(chip, voice, offset);
+ else if (chip->current_page < 0x40)
+ result = es5505_reg_read_high(chip, voice, offset);
+ else
+ result = es5505_reg_read_test(chip, voice, offset);
+
+ if (LOG_COMMANDS && eslog)
+ fprintf(eslog, "%04x (accum=%08x)\n", result, voice->accum);
+
+ /* return the high byte */
+ return result;
+}
+
+
+
+/**********************************************************************************************
+
+ ES5505_data_0_r/ES5505_data_1_r -- handle a read from the status register
+
+***********************************************************************************************/
+
+READ16_HANDLER( ES5505_data_0_r )
+{
+ return es5505_reg_read(sndti_token(SOUND_ES5505, 0), offset);
+}
+
+READ16_HANDLER( ES5505_data_1_r )
+{
+ return es5505_reg_read(sndti_token(SOUND_ES5505, 1), offset);
+}
+
+/**********************************************************************************************
+
+ ES5505_data_0_w/ES5505_data_1_w -- handle a write to the current register
+
+***********************************************************************************************/
+
+WRITE16_HANDLER( ES5505_data_0_w )
+{
+ es5505_reg_write(sndti_token(SOUND_ES5505, 0), offset, data, mem_mask);
+}
+
+WRITE16_HANDLER( ES5505_data_1_w )
+{
+ es5505_reg_write(sndti_token(SOUND_ES5505, 1), offset, data, mem_mask);
+}
+
+void ES5505_voice_bank_0_w(int voice, int bank)
+{
+ struct ES5506Chip *chip = sndti_token(SOUND_ES5505, 0);
+#if RAINE_CHECK
+ chip->voice[voice].control = CONTROL_STOPMASK;
+#endif
+ chip->voice[voice].exbank=bank;
+}
+
+void ES5505_voice_bank_1_w(int voice, int bank)
+{
+ struct ES5506Chip *chip = sndti_token(SOUND_ES5505, 1);
+#if RAINE_CHECK
+ chip->voice[voice].control = CONTROL_STOPMASK;
+#endif
+ chip->voice[voice].exbank=bank;
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void es5505_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void es5505_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = es5505_set_info; break;
+ case SNDINFO_PTR_START: info->start = es5505_start; break;
+ case SNDINFO_PTR_STOP: info->stop = es5505_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = es5505_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "ES5505"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Ensoniq Wavetable"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void es5506_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void es5506_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = es5506_set_info; break;
+ case SNDINFO_PTR_START: info->start = es5506_start; break;
+ case SNDINFO_PTR_STOP: info->stop = es5506_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = es5506_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "ES5506"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Ensoniq Wavetable"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/es5506.h b/src/emu/sound/es5506.h
new file mode 100644
index 00000000000..7d8e247e49f
--- /dev/null
+++ b/src/emu/sound/es5506.h
@@ -0,0 +1,53 @@
+/**********************************************************************************************
+ *
+ * Ensoniq ES5505/6 driver
+ * by Aaron Giles
+ *
+ **********************************************************************************************/
+
+#ifndef ES5506_H
+#define ES5506_H
+
+struct ES5505interface
+{
+ int region0; /* memory region where the sample ROM lives */
+ int region1; /* memory region where the sample ROM lives */
+ void (*irq_callback)(int state); /* irq callback */
+ UINT16 (*read_port)(void); /* input port read */
+};
+
+READ16_HANDLER( ES5505_data_0_r );
+READ16_HANDLER( ES5505_data_1_r );
+WRITE16_HANDLER( ES5505_data_0_w );
+WRITE16_HANDLER( ES5505_data_1_w );
+
+void ES5505_voice_bank_0_w(int voice, int bank);
+void ES5505_voice_bank_1_w(int voice, int bank);
+
+
+
+
+struct ES5506interface
+{
+ int region0; /* memory region where the sample ROM lives */
+ int region1; /* memory region where the sample ROM lives */
+ int region2; /* memory region where the sample ROM lives */
+ int region3; /* memory region where the sample ROM lives */
+ void (*irq_callback)(int state); /* irq callback */
+ UINT16 (*read_port)(void); /* input port read */
+};
+
+READ8_HANDLER( ES5506_data_0_r );
+READ8_HANDLER( ES5506_data_1_r );
+WRITE8_HANDLER( ES5506_data_0_w );
+WRITE8_HANDLER( ES5506_data_1_w );
+
+READ16_HANDLER( ES5506_data_0_word_r );
+READ16_HANDLER( ES5506_data_1_word_r );
+WRITE16_HANDLER( ES5506_data_0_word_w );
+WRITE16_HANDLER( ES5506_data_1_word_w );
+
+void ES5506_voice_bank_0_w(int voice, int bank);
+void ES5506_voice_bank_1_w(int voice, int bank);
+
+#endif
diff --git a/src/emu/sound/es8712.c b/src/emu/sound/es8712.c
new file mode 100644
index 00000000000..d808222cb0f
--- /dev/null
+++ b/src/emu/sound/es8712.c
@@ -0,0 +1,479 @@
+/**********************************************************************************************
+ *
+ * Streaming singe channel ADPCM core for the ES8712 chip
+ * Chip is branded by Excellent Systems, probably OEM'd.
+ *
+ * Samples are currently looped, but whether they should and how, is unknown.
+ * Interface to the chip is also not 100% clear.
+ * Should there be any status signals signifying busy, end of sample - etc?
+ *
+ * Heavily borrowed from the OKI M6295 source
+ *
+ **********************************************************************************************/
+
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "es8712.h"
+
+#define MAX_SAMPLE_CHUNK 10000
+
+
+/* struct describing a playing ADPCM chip */
+struct es8712
+{
+ UINT8 playing; /* 1 if we're actively playing */
+
+ UINT32 base_offset; /* pointer to the base memory location */
+ UINT32 sample; /* current sample number */
+ UINT32 count; /* total samples to play */
+
+ UINT32 signal; /* current ADPCM signal */
+ UINT32 step; /* current ADPCM step */
+
+ UINT32 start; /* starting address for the next loop */
+ UINT32 end; /* ending address for the next loop */
+ UINT8 repeat; /* Repeat current sample when 1 */
+
+ INT32 bank_offset;
+ UINT8 *region_base; /* pointer to the base of the region */
+ sound_stream *stream; /* which stream are we playing on? */
+};
+
+/* step size index shift table */
+static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
+
+/* lookup table for the precomputed difference */
+static int diff_lookup[49*16];
+
+/* useful interfaces */
+const struct ES8712interface es8712_interface_region_1 = { REGION_SOUND1 };
+const struct ES8712interface es8712_interface_region_2 = { REGION_SOUND2 };
+const struct ES8712interface es8712_interface_region_3 = { REGION_SOUND3 };
+const struct ES8712interface es8712_interface_region_4 = { REGION_SOUND4 };
+
+
+/**********************************************************************************************
+
+ compute_tables -- compute the difference tables
+
+***********************************************************************************************/
+
+static void compute_tables(void)
+{
+ /* nibble to bit map */
+ static const int nbl2bit[16][4] =
+ {
+ { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
+ { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
+ {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
+ {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
+ };
+
+ int step, nib;
+
+ /* loop over all possible steps */
+ for (step = 0; step <= 48; step++)
+ {
+ /* compute the step value */
+ int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step));
+
+ /* loop over all nibbles and compute the difference */
+ for (nib = 0; nib < 16; nib++)
+ {
+ diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
+ (stepval * nbl2bit[nib][1] +
+ stepval/2 * nbl2bit[nib][2] +
+ stepval/4 * nbl2bit[nib][3] +
+ stepval/8);
+ }
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ generate_adpcm -- general ADPCM decoding routine
+
+***********************************************************************************************/
+
+static void generate_adpcm(struct es8712 *chip, stream_sample_t *buffer, int samples)
+{
+ /* if this chip is active */
+ if (chip->playing)
+ {
+ UINT8 *base = chip->region_base + chip->bank_offset + chip->base_offset;
+ int sample = chip->sample;
+ int signal = chip->signal;
+ int count = chip->count;
+ int step = chip->step;
+ int val;
+
+ /* loop while we still have samples to generate */
+ while (samples)
+ {
+ /* compute the new amplitude and update the current step */
+ val = base[sample / 2] >> (((sample & 1) << 2) ^ 4);
+ signal += diff_lookup[step * 16 + (val & 15)];
+
+ /* clamp to the maximum */
+ if (signal > 2047)
+ signal = 2047;
+ else if (signal < -2048)
+ signal = -2048;
+
+ /* adjust the step size and clamp */
+ step += index_shift[val & 7];
+ if (step > 48)
+ step = 48;
+ else if (step < 0)
+ step = 0;
+
+ /* output to the buffer */
+ *buffer++ = signal * 16;
+ samples--;
+
+ /* next! */
+ if (++sample >= count)
+ {
+ if (chip->repeat)
+ {
+ sample = 0;
+ signal = -2;
+ step = 0;
+ }
+ else
+ {
+ chip->playing = 0;
+ break;
+ }
+ }
+ }
+
+ /* update the parameters */
+ chip->sample = sample;
+ chip->signal = signal;
+ chip->step = step;
+ }
+
+ /* fill the rest with silence */
+ while (samples--)
+ *buffer++ = 0;
+}
+
+
+/**********************************************************************************************
+
+ es8712_update -- update the sound chip so that it is in sync with CPU execution
+
+***********************************************************************************************/
+
+static void es8712_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ stream_sample_t *buffer = outputs[0];
+ struct es8712 *chip = param;
+
+ /* generate them into our buffer */
+ generate_adpcm(chip, buffer, samples);
+}
+
+
+
+/**********************************************************************************************
+
+ state save support for MAME
+
+***********************************************************************************************/
+
+static void es8712_state_save_register(struct es8712 *chip, int sndindex)
+{
+ char buf[20];
+
+ sprintf(buf,"ES8712");
+
+ state_save_register_item(buf, sndindex, chip->bank_offset);
+
+ state_save_register_item(buf, sndindex, chip->playing);
+ state_save_register_item(buf, sndindex, chip->sample);
+ state_save_register_item(buf, sndindex, chip->count);
+ state_save_register_item(buf, sndindex, chip->signal);
+ state_save_register_item(buf, sndindex, chip->step);
+
+ state_save_register_item(buf, sndindex, chip->base_offset);
+
+ state_save_register_item(buf, sndindex, chip->start);
+ state_save_register_item(buf, sndindex, chip->end);
+ state_save_register_item(buf, sndindex, chip->repeat);
+}
+
+
+
+/**********************************************************************************************
+
+ ES8712_start -- start emulation of an ES8712 chip
+
+***********************************************************************************************/
+
+static void *es8712_start(int sndindex, int clock, const void *config)
+{
+ const struct ES8712interface *intf = config;
+ struct es8712 *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ compute_tables();
+
+ chip->start = 0;
+ chip->end = 0;
+ chip->repeat = 0;
+
+ chip->bank_offset = 0;
+ chip->region_base = memory_region(intf->region);
+
+ /* generate the name and create the stream */
+ chip->stream = stream_create(0, 1, clock, chip, es8712_update);
+
+ /* initialize the rest of the structure */
+ chip->signal = -2;
+
+ es8712_state_save_register(chip, sndindex);
+
+ /* success */
+ return chip;
+}
+
+
+
+/*************************************************************************************
+
+ ES8712_reset -- stop emulation of an ES8712-compatible chip
+
+**************************************************************************************/
+
+static void es8712_reset(void *chip_src)
+{
+ struct es8712 *chip = chip_src;
+
+ if (chip->playing)
+ {
+ /* update the stream, then turn it off */
+ stream_update(chip->stream);
+ chip->playing = 0;
+ chip->repeat = 0;
+ }
+}
+
+
+/****************************************************************************
+
+ ES8712_set_bank_base -- set the base of the bank on a given chip
+
+*****************************************************************************/
+
+void ES8712_set_bank_base(int which, int base)
+{
+ struct es8712 *chip = sndti_token(SOUND_ES8712, which);
+ stream_update(chip->stream);
+ chip->bank_offset = base;
+}
+
+
+/****************************************************************************
+
+ ES8712_set_frequency -- dynamically adjusts the frequency of a given ADPCM chip
+
+*****************************************************************************/
+
+void ES8712_set_frequency(int which, int frequency)
+{
+ struct es8712 *chip = sndti_token(SOUND_ES8712, which);
+
+ /* update the stream and set the new base */
+ stream_update(chip->stream);
+ stream_set_sample_rate(chip->stream, frequency);
+}
+
+
+
+/**********************************************************************************************
+
+ ES8712_play -- Begin playing the addressed sample
+
+***********************************************************************************************/
+
+void ES8712_play(int which)
+{
+ struct es8712 *chip = sndti_token(SOUND_ES8712, which);
+
+
+ if (chip->start < chip->end)
+ {
+ if (!chip->playing)
+ {
+ chip->playing = 1;
+ chip->base_offset = chip->start;
+ chip->sample = 0;
+ chip->count = 2 * (chip->end - chip->start + 1);
+ chip->repeat = 0;//1;
+
+ /* also reset the ADPCM parameters */
+ chip->signal = -2;
+ chip->step = 0;
+ }
+ }
+ /* invalid samples go here */
+ else
+ {
+ logerror("ES871295:%d requested to play invalid sample range %06x-%06x\n",which,chip->start,chip->end);
+
+ if (chip->playing)
+ {
+ /* update the stream */
+ stream_update(chip->stream);
+ chip->playing = 0;
+ }
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ ES8712_data_0_w -- generic data write functions
+ ES8712_data_1_w
+
+***********************************************************************************************/
+
+/**********************************************************************************************
+ *
+ * offset Start End
+ * 0hmmll - 0HMMLL
+ * 00 ----ll
+ * 01 --mm--
+ * 02 0h----
+ * 03 ----LL
+ * 04 --MM--
+ * 05 0H----
+ * 06 Go!
+ *
+ * Offsets are written in the order -> 00, 02, 01, 03, 05, 04, 06
+ * Offset 06 is written with the same value as offset 04.
+ *
+***********************************************************************************************/
+
+static void ES8712_data_w(int which, int offset, UINT32 data)
+{
+ struct es8712 *chip = sndti_token(SOUND_ES8712, which);
+ switch (offset)
+ {
+ case 00: chip->start &= 0x000fff00;
+ chip->start |= ((data & 0xff) << 0); break;
+ case 01: chip->start &= 0x000f00ff;
+ chip->start |= ((data & 0xff) << 8); break;
+ case 02: chip->start &= 0x0000ffff;
+ chip->start |= ((data & 0x0f) << 16); break;
+ case 03: chip->end &= 0x000fff00;
+ chip->end |= ((data & 0xff) << 0); break;
+ case 04: chip->end &= 0x000f00ff;
+ chip->end |= ((data & 0xff) << 8); break;
+ case 05: chip->end &= 0x0000ffff;
+ chip->end |= ((data & 0x0f) << 16); break;
+ case 06:
+ ES8712_play(which);
+ break;
+ default: break;
+ }
+ chip->start &= 0xfffff; chip->end &= 0xfffff;
+}
+
+WRITE8_HANDLER( ES8712_data_0_w )
+{
+ ES8712_data_w(0, offset, data);
+}
+
+WRITE8_HANDLER( ES8712_data_1_w )
+{
+ ES8712_data_w(1, offset, data);
+}
+
+WRITE8_HANDLER( ES8712_data_2_w )
+{
+ ES8712_data_w(2, offset, data);
+}
+
+WRITE16_HANDLER( ES8712_data_0_lsb_w )
+{
+ if (ACCESSING_LSB)
+ ES8712_data_w(0, offset, data & 0xff);
+}
+
+WRITE16_HANDLER( ES8712_data_1_lsb_w )
+{
+ if (ACCESSING_LSB)
+ ES8712_data_w(1, offset, data & 0xff);
+}
+
+WRITE16_HANDLER( ES8712_data_2_lsb_w )
+{
+ if (ACCESSING_LSB)
+ ES8712_data_w(2, offset, data & 0xff);
+}
+
+WRITE16_HANDLER( ES8712_data_0_msb_w )
+{
+ if (ACCESSING_MSB)
+ ES8712_data_w(0, offset, data >> 8);
+}
+
+WRITE16_HANDLER( ES8712_data_1_msb_w )
+{
+ if (ACCESSING_MSB)
+ ES8712_data_w(1, offset, data >> 8);
+}
+
+WRITE16_HANDLER( ES8712_data_2_msb_w )
+{
+ if (ACCESSING_MSB)
+ ES8712_data_w(2, offset, data >> 8);
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void es8712_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void es8712_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = es8712_set_info; break;
+ case SNDINFO_PTR_START: info->start = es8712_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = es8712_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "ES8712"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Excellent Systems ADPCM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2005, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/es8712.h b/src/emu/sound/es8712.h
new file mode 100644
index 00000000000..6efb6cfb86c
--- /dev/null
+++ b/src/emu/sound/es8712.h
@@ -0,0 +1,30 @@
+#ifndef ES8712_H
+#define ES8712_H
+
+/* An interface for the ES8712 ADPCM chip */
+
+struct ES8712interface
+{
+ int region; /* Memory region where the sample ROM lives */
+};
+
+extern const struct ES8712interface es8712_interface_region_1;
+extern const struct ES8712interface es8712_interface_region_2;
+extern const struct ES8712interface es8712_interface_region_3;
+extern const struct ES8712interface es8712_interface_region_4;
+
+void ES8712_play(int which);
+void ES8712_set_bank_base(int which, int base);
+void ES8712_set_frequency(int which, int frequency);
+
+WRITE8_HANDLER( ES8712_data_0_w );
+WRITE8_HANDLER( ES8712_data_1_w );
+WRITE8_HANDLER( ES8712_data_2_w );
+WRITE16_HANDLER( ES8712_data_0_lsb_w );
+WRITE16_HANDLER( ES8712_data_1_lsb_w );
+WRITE16_HANDLER( ES8712_data_2_lsb_w );
+WRITE16_HANDLER( ES8712_data_0_msb_w );
+WRITE16_HANDLER( ES8712_data_1_msb_w );
+WRITE16_HANDLER( ES8712_data_2_msb_w );
+
+#endif
diff --git a/src/emu/sound/filter.c b/src/emu/sound/filter.c
new file mode 100644
index 00000000000..e6c249538e2
--- /dev/null
+++ b/src/emu/sound/filter.c
@@ -0,0 +1,233 @@
+#include "filter.h"
+#include "sndintrf.h"
+
+#include <math.h>
+
+static filter* filter_alloc(void) {
+ filter* f = malloc_or_die(sizeof(filter));
+ return f;
+}
+
+void filter_free(filter* f) {
+ free(f);
+}
+
+void filter_state_reset(filter* f, filter_state* s) {
+ int i;
+ s->prev_mac = 0;
+ for(i=0;i<f->order;++i) {
+ s->xprev[i] = 0;
+ }
+}
+
+filter_state* filter_state_alloc(void) {
+ int i;
+ filter_state* s = malloc_or_die(sizeof(filter_state));
+ s->prev_mac = 0;
+ for(i=0;i<FILTER_ORDER_MAX;++i)
+ s->xprev[i] = 0;
+ return s;
+}
+
+void filter_state_free(filter_state* s) {
+ free(s);
+}
+
+/****************************************************************************/
+/* FIR */
+
+filter_real filter_compute(filter* f, filter_state* s) {
+ unsigned order = f->order;
+ unsigned midorder = f->order / 2;
+ filter_real y = 0;
+ unsigned i,j,k;
+
+ /* i == [0] */
+ /* j == [-2*midorder] */
+ i = s->prev_mac;
+ j = i + 1;
+ if (j == order)
+ j = 0;
+
+ /* x */
+ for(k=0;k<midorder;++k) {
+ y += f->xcoeffs[midorder-k] * (s->xprev[i] + s->xprev[j]);
+ ++j;
+ if (j == order)
+ j = 0;
+ if (i == 0)
+ i = order - 1;
+ else
+ --i;
+ }
+ y += f->xcoeffs[0] * s->xprev[i];
+
+#ifdef FILTER_USE_INT
+ return y >> FILTER_INT_FRACT;
+#else
+ return y;
+#endif
+}
+
+filter* filter_lp_fir_alloc(double freq, int order) {
+ filter* f = filter_alloc();
+ unsigned midorder = (order - 1) / 2;
+ unsigned i;
+ double gain;
+
+ assert( order <= FILTER_ORDER_MAX );
+ assert( order % 2 == 1 );
+ assert( 0 < freq && freq <= 0.5 );
+
+ /* Compute the antitrasform of the perfect low pass filter */
+ gain = 2*freq;
+#ifdef FILTER_USE_INT
+ f->xcoeffs[0] = gain * (1 << FILTER_INT_FRACT);
+#else
+ f->xcoeffs[0] = gain;
+#endif
+ for(i=1;i<=midorder;++i) {
+ /* number of the sample starting from 0 to (order-1) included */
+ unsigned n = i + midorder;
+
+ /* sample value */
+ double c = sin(2*M_PI*freq*i) / (M_PI*i);
+
+ /* apply only one window or none */
+ /* double w = 2 - 2*n/(order-1); */ /* Bartlett (triangular) */
+ /* double w = 0.5 * (1 - cos(2*M_PI*n/(order-1))); */ /* Hanning */
+ double w = 0.54 - 0.46 * cos(2*M_PI*n/(order-1)); /* Hamming */
+ /* double w = 0.42 - 0.5 * cos(2*M_PI*n/(order-1)) + 0.08 * cos(4*M_PI*n/(order-1)); */ /* Blackman */
+
+ /* apply the window */
+ c *= w;
+
+ /* update the gain */
+ gain += 2*c;
+
+ /* insert the coeff */
+#ifdef FILTER_USE_INT
+ f->xcoeffs[i] = c * (1 << FILTER_INT_FRACT);
+#else
+ f->xcoeffs[i] = c;
+#endif
+ }
+
+ /* adjust the gain to be exact 1.0 */
+ for(i=0;i<=midorder;++i) {
+#ifdef FILTER_USE_INT
+ f->xcoeffs[i] /= gain;
+#else
+ f->xcoeffs[i] = f->xcoeffs[i] * (double)(1 << FILTER_INT_FRAC) / gain;
+#endif
+ }
+
+ /* decrease the order if the last coeffs are 0 */
+ i = midorder;
+ while (i > 0 && f->xcoeffs[i] == 0.0)
+ --i;
+
+ f->order = i * 2 + 1;
+
+ return f;
+}
+
+
+void filter2_setup(int type, double fc, double d, double gain,
+ filter2_context *filter2)
+{
+ double w; /* cutoff freq, in radians/sec */
+ double w_squared;
+ double den; /* temp variable */
+ double two_over_T = 2*Machine->sample_rate;
+ double two_over_T_squared = two_over_T * two_over_T;
+
+ /* calculate digital filter coefficents */
+ /*w = 2.0*M_PI*fc; no pre-warping */
+ w = Machine->sample_rate*2.0*tan(M_PI*fc/Machine->sample_rate); /* pre-warping */
+ w_squared = w*w;
+
+ den = two_over_T_squared + d*w*two_over_T + w_squared;
+
+ filter2->a1 = 2.0*(-two_over_T_squared + w_squared)/den;
+ filter2->a2 = (two_over_T_squared - d*w*two_over_T + w_squared)/den;
+
+ switch (type)
+ {
+ case FILTER_LOWPASS:
+ filter2->b0 = filter2->b2 = w_squared/den;
+ filter2->b1 = 2.0*(filter2->b0);
+ break;
+ case FILTER_BANDPASS:
+ filter2->b0 = d*w*two_over_T/den;
+ filter2->b1 = 0.0;
+ filter2->b2 = -(filter2->b0);
+ break;
+ case FILTER_HIGHPASS:
+ filter2->b0 = filter2->b2 = two_over_T_squared/den;
+ filter2->b1 = -2.0*(filter2->b0);
+ break;
+ default:
+ logerror("filter2_setup() - Invalid filter type for 2nd order filter.");
+ break;
+ }
+
+ filter2->b0 *= gain;
+ filter2->b1 *= gain;
+ filter2->b2 *= gain;
+}
+
+
+/* Reset the input/output voltages to 0. */
+void filter2_reset(filter2_context *filter2)
+{
+ filter2->x0 = 0;
+ filter2->x1 = 0;
+ filter2->x2 = 0;
+ filter2->y0 = 0;
+ filter2->y1 = 0;
+ filter2->y2 = 0;
+}
+
+
+/* Step the filter. */
+void filter2_step(filter2_context *filter2)
+{
+ filter2->y0 = -filter2->a1 * filter2->y1 - filter2->a2 * filter2->y2 +
+ filter2->b0 * filter2->x0 + filter2->b1 * filter2->x1 + filter2->b2 * filter2->x2;
+ filter2->x2 = filter2->x1;
+ filter2->x1 = filter2->x0;
+ filter2->y2 = filter2->y1;
+ filter2->y1 = filter2->y0;
+}
+
+
+/* Setup a filter2 structure based on an op-amp multipole bandpass circuit. */
+void filter_opamp_m_bandpass_setup(double r1, double r2, double r3, double c1, double c2,
+ filter2_context *filter2)
+{
+ double r_in, fc, d, gain;
+
+ if (r1 == 0)
+ {
+ logerror("filter_opamp_m_bandpass_setup() - r1 can not be 0");
+ return; /* Filter can not be setup. Undefined results. */
+ }
+
+ if (r2 == 0)
+ {
+ gain = 1;
+ r_in = r1;
+ }
+ else
+ {
+ gain = r2 / (r1 + r2);
+ r_in = 1.0 / (1.0/r1 + 1.0/r2);
+ }
+
+ fc = 1.0 / (2 * M_PI * sqrt(r_in * r3 * c1 * c2));
+ d = (c1 + c2) / sqrt(r3 / r_in * c1 * c2);
+ gain *= -r3 / r_in * c2 / (c1 + c2);
+
+ filter2_setup(FILTER_BANDPASS, fc, d, gain, filter2);
+}
diff --git a/src/emu/sound/filter.h b/src/emu/sound/filter.h
new file mode 100644
index 00000000000..036813f1569
--- /dev/null
+++ b/src/emu/sound/filter.h
@@ -0,0 +1,112 @@
+#ifndef __FILTER_H
+#define __FILTER_H
+
+/* Max filter order */
+#define FILTER_ORDER_MAX 51
+
+/* Define to use interger calculation */
+#define FILTER_USE_INT
+
+#ifdef FILTER_USE_INT
+typedef int filter_real;
+#define FILTER_INT_FRACT 15 /* fractional bits */
+#else
+typedef double filter_real;
+#endif
+
+typedef struct filter_struct {
+ filter_real xcoeffs[(FILTER_ORDER_MAX+1)/2];
+ unsigned order;
+} filter;
+
+typedef struct filter_state_struct {
+ unsigned prev_mac;
+ filter_real xprev[FILTER_ORDER_MAX];
+} filter_state;
+
+/* Allocate a FIR Low Pass filter */
+filter* filter_lp_fir_alloc(double freq, int order);
+void filter_free(filter* f);
+
+/* Allocate a filter state */
+filter_state* filter_state_alloc(void);
+
+/* Free the filter state */
+void filter_state_free(filter_state* s);
+
+/* Clear the filter state */
+void filter_state_reset(filter* f, filter_state* s);
+
+/* Insert a value in the filter state */
+INLINE void filter_insert(filter* f, filter_state* s, filter_real x) {
+ /* next state */
+ ++s->prev_mac;
+ if (s->prev_mac >= f->order)
+ s->prev_mac = 0;
+
+ /* set x[0] */
+ s->xprev[s->prev_mac] = x;
+}
+
+/* Compute the filter output */
+filter_real filter_compute(filter* f, filter_state* s);
+
+
+/* Filter types */
+#define FILTER_LOWPASS 0
+#define FILTER_HIGHPASS 1
+#define FILTER_BANDPASS 2
+
+#define Q_TO_DAMP(q) (1.0/q)
+
+typedef struct filter2_context_struct {
+ double x0, x1, x2; /* x[k], x[k-1], x[k-2], current and previous 2 input values */
+ double y0, y1, y2; /* y[k], y[k-1], y[k-2], current and previous 2 output values */
+ double a1, a2; /* digital filter coefficients, denominator */
+ double b0, b1, b2; /* digital filter coefficients, numerator */
+} filter2_context;
+
+
+/* Setup the filter context based on the passed filter type info.
+ * type - 1 of the 3 defined filter types
+ * fc - center frequency
+ * d - damp = 1/Q
+ * gain - overall filter gain. Set to 1 if not needed.
+ */
+void filter2_setup(int type, double fc, double d, double gain,
+ filter2_context *filter2);
+
+
+/* Reset the input/output voltages to 0. */
+void filter2_reset(filter2_context *filter2);
+
+
+/* Step the filter.
+ * x0 is the new input, which needs to be set before stepping.
+ * y0 is the new filter output.
+ */
+void filter2_step(filter2_context *filter2);
+
+
+/* Setup a filter2 structure based on an op-amp multipole bandpass circuit.
+ * NOTE: If r2 is not used then set to 0.
+ * vRef is not needed to setup filter.
+ *
+ * .--------+---------.
+ * | | |
+ * --- c1 Z |
+ * --- Z r3 |
+ * | Z |
+ * r1 | c2 | |\ |
+ * In >----ZZZZ----+---------+--||----+ | \ |
+ * Z '--|- \ |
+ * Z r2 | >--+------> out
+ * Z .--|+ /
+ * | | | /
+ * gnd vRef >---' |/
+ *
+ */
+void filter_opamp_m_bandpass_setup(double r1, double r2, double r3, double c1, double c2,
+ filter2_context *filter2);
+
+#endif
diff --git a/src/emu/sound/flt_rc.c b/src/emu/sound/flt_rc.c
new file mode 100644
index 00000000000..0a6c864a746
--- /dev/null
+++ b/src/emu/sound/flt_rc.c
@@ -0,0 +1,147 @@
+#include "sndintrf.h"
+#include "streams.h"
+#include "flt_rc.h"
+#include <math.h>
+
+struct filter_rc_info
+{
+ sound_stream * stream;
+ int k;
+ int memory;
+ int type;
+};
+
+flt_rc_config flt_rc_ac_default = {FLT_RC_AC, 10000, 0, 0, CAP_U(1)};
+
+
+static void filter_rc_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ stream_sample_t *src = inputs[0];
+ stream_sample_t *dst = outputs[0];
+ struct filter_rc_info *info = param;
+ int memory = info->memory;
+
+ switch (info->type)
+ {
+ case FLT_RC_LOWPASS:
+ while (samples--)
+ {
+ memory += ((*src++ - memory) * info->k) / 0x10000;
+ *dst++ = memory;
+ }
+ break;
+ case FLT_RC_HIGHPASS:
+ case FLT_RC_AC:
+ while (samples--)
+ {
+ *dst++ = *src - memory;
+ memory += ((*src++ - memory) * info->k) / 0x10000;
+ }
+ break;
+ }
+ info->memory = memory;
+}
+
+static void set_RC_info(struct filter_rc_info *info, int type, double R1, double R2, double R3, double C)
+{
+ double Req;
+
+ info->type = type;
+
+ switch (info->type)
+ {
+ case FLT_RC_LOWPASS:
+ if (C == 0.0)
+ {
+ /* filter disabled */
+ info->k = 0x10000;
+ return;
+ }
+ Req = (R1 * (R2 + R3)) / (R1 + R2 + R3);
+ break;
+ case FLT_RC_HIGHPASS:
+ case FLT_RC_AC:
+ if (C == 0.0)
+ {
+ /* filter disabled */
+ info->k = 0x0;
+ info->memory = 0x0;
+ return;
+ }
+ Req = R1;
+ break;
+ default:
+ fatalerror("filter_rc_setRC: Wrong filter type %d\n", info->type);
+ }
+
+ /* Cut Frequency = 1/(2*Pi*Req*C) */
+ /* k = (1-(EXP(-TIMEDELTA/RC))) */
+ info->k = 0x10000 - 0x10000 * (exp(-1 / (Req * C) / Machine->sample_rate));
+}
+
+
+static void *filter_rc_start(int sndindex, int clock, const void *config)
+{
+ struct filter_rc_info *info;
+ const flt_rc_config *conf = config;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->stream = stream_create(1, 1, Machine->sample_rate, info, filter_rc_update);
+ if (conf)
+ set_RC_info(info, conf->type, conf->R1, conf->R2, conf->R3, conf->C);
+ else
+ set_RC_info(info, FLT_RC_LOWPASS, 1, 1, 1, 0);
+
+ return info;
+}
+
+
+void filter_rc_set_RC(int num, int type, double R1, double R2, double R3, double C)
+{
+ struct filter_rc_info *info = sndti_token(SOUND_FILTER_RC, num);
+
+ if(!info)
+ return;
+
+ stream_update(info->stream);
+
+ set_RC_info(info, type, R1, R2, R3, C);
+
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void filter_rc_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void filter_rc_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = filter_rc_set_info; break;
+ case SNDINFO_PTR_START: info->start = filter_rc_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "RC Filter"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Filters"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/flt_rc.h b/src/emu/sound/flt_rc.h
new file mode 100644
index 00000000000..189d98c3651
--- /dev/null
+++ b/src/emu/sound/flt_rc.h
@@ -0,0 +1,59 @@
+#ifndef FLT_RC_H
+#define FLT_RC_H
+
+#include "rescap.h"
+
+#define FLT_RC_LOWPASS 0
+#define FLT_RC_HIGHPASS 1
+#define FLT_RC_AC 2
+
+/*
+ * FLT_RC_LOWPASS:
+ *
+ * signal >--R1--+--R2--+
+ * | |
+ * C R3---> amp
+ * | |
+ * GND GND
+ *
+ * Set C=0 to disable filter
+ *
+ * FLT_RC_HIGHPASS:
+ *
+ * signal >--C---+----> amp
+ * |
+ * R1
+ * |
+ * GND
+ *
+ * Set C = 0 to disable filter
+ *
+ * FLT_RC_AC:
+ *
+ * Same as FLT_RC_HIGHPASS, but with standard frequency of 16 HZ
+ * This filter may be setup just with
+ *
+ * MDRV_SOUND_ADD(FILTER_RC, 0)
+ * MDRV_SOUND_CONFIG(&flt_rc_ac_default)
+ *
+ * Default behaviour:
+ *
+ * Without MDRV_SOUND_CONFIG, a disabled FLT_RC_LOWPASS is created
+ *
+ */
+
+typedef struct _flt_rc_config flt_rc_config;
+struct _flt_rc_config
+{
+ int type;
+ double R1;
+ double R2;
+ double R3;
+ double C;
+};
+
+extern flt_rc_config flt_rc_ac_default;
+
+void filter_rc_set_RC(int num, int type, double R1, double R2, double R3, double C);
+
+#endif
diff --git a/src/emu/sound/flt_vol.c b/src/emu/sound/flt_vol.c
new file mode 100644
index 00000000000..008db9cc471
--- /dev/null
+++ b/src/emu/sound/flt_vol.c
@@ -0,0 +1,80 @@
+#include "sndintrf.h"
+#include "streams.h"
+#include "flt_vol.h"
+
+
+struct filter_volume_info
+{
+ sound_stream * stream;
+ int gain;
+};
+
+
+
+static void filter_volume_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ stream_sample_t *src = inputs[0];
+ stream_sample_t *dst = outputs[0];
+ struct filter_volume_info *info = param;
+
+ while (samples--)
+ *dst++ = (*src++ * info->gain) >> 8;
+}
+
+
+static void *filter_volume_start(int sndindex, int clock, const void *config)
+{
+ struct filter_volume_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->gain = 0x100;
+ info->stream = stream_create(1, 1, Machine->sample_rate, info, filter_volume_update);
+
+ return info;
+}
+
+
+void flt_volume_set_volume(int num, float volume)
+{
+ struct filter_volume_info *info = sndti_token(SOUND_FILTER_VOLUME, num);
+ info->gain = (int)(volume * 256);
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void filter_volume_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void filter_volume_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = filter_volume_set_info;break;
+ case SNDINFO_PTR_START: info->start = filter_volume_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Volume Filter"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Filters"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/flt_vol.h b/src/emu/sound/flt_vol.h
new file mode 100644
index 00000000000..a0db7bea16f
--- /dev/null
+++ b/src/emu/sound/flt_vol.h
@@ -0,0 +1,6 @@
+#ifndef FLT_VOL_H
+#define FLT_VOL_H
+
+void flt_volume_set_volume(int num, float volume);
+
+#endif
diff --git a/src/emu/sound/fm.c b/src/emu/sound/fm.c
new file mode 100644
index 00000000000..aca7d18584e
--- /dev/null
+++ b/src/emu/sound/fm.c
@@ -0,0 +1,4744 @@
+#define YM2610B_WARNING
+
+/*
+**
+** File: fm.c -- software implementation of Yamaha FM sound generator
+**
+** Copyright (C) 2001, 2002, 2003 Jarek Burczynski (bujar at mame dot net)
+** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development
+**
+** Version 1.4 (final beta)
+**
+*/
+
+/*
+** History:
+**
+** 06-23-2007 Zsolt Vasvari:
+** - changed the timing not to require the use of floating point calculations
+**
+** 03-08-2003 Jarek Burczynski:
+** - fixed YM2608 initial values (after the reset)
+** - fixed flag and irqmask handling (YM2608)
+** - fixed BUFRDY flag handling (YM2608)
+**
+** 14-06-2003 Jarek Burczynski:
+** - implemented all of the YM2608 status register flags
+** - implemented support for external memory read/write via YM2608
+** - implemented support for deltat memory limit register in YM2608 emulation
+**
+** 22-05-2003 Jarek Burczynski:
+** - fixed LFO PM calculations (copy&paste bugfix)
+**
+** 08-05-2003 Jarek Burczynski:
+** - fixed SSG support
+**
+** 22-04-2003 Jarek Burczynski:
+** - implemented 100% correct LFO generator (verified on real YM2610 and YM2608)
+**
+** 15-04-2003 Jarek Burczynski:
+** - added support for YM2608's register 0x110 - status mask
+**
+** 01-12-2002 Jarek Burczynski:
+** - fixed register addressing in YM2608, YM2610, YM2610B chips. (verified on real YM2608)
+** The addressing patch used for early Neo-Geo games can be removed now.
+**
+** 26-11-2002 Jarek Burczynski, Nicola Salmoria:
+** - recreated YM2608 ADPCM ROM using data from real YM2608's output which leads to:
+** - added emulation of YM2608 drums.
+** - output of YM2608 is two times lower now - same as YM2610 (verified on real YM2608)
+**
+** 16-08-2002 Jarek Burczynski:
+** - binary exact Envelope Generator (verified on real YM2203);
+** identical to YM2151
+** - corrected 'off by one' error in feedback calculations (when feedback is off)
+** - corrected connection (algorithm) calculation (verified on real YM2203 and YM2610)
+**
+** 18-12-2001 Jarek Burczynski:
+** - added SSG-EG support (verified on real YM2203)
+**
+** 12-08-2001 Jarek Burczynski:
+** - corrected sin_tab and tl_tab data (verified on real chip)
+** - corrected feedback calculations (verified on real chip)
+** - corrected phase generator calculations (verified on real chip)
+** - corrected envelope generator calculations (verified on real chip)
+** - corrected FM volume level (YM2610 and YM2610B).
+** - changed YMxxxUpdateOne() functions (YM2203, YM2608, YM2610, YM2610B, YM2612) :
+** this was needed to calculate YM2610 FM channels output correctly.
+** (Each FM channel is calculated as in other chips, but the output of the channel
+** gets shifted right by one *before* sending to accumulator. That was impossible to do
+** with previous implementation).
+**
+** 23-07-2001 Jarek Burczynski, Nicola Salmoria:
+** - corrected YM2610 ADPCM type A algorithm and tables (verified on real chip)
+**
+** 11-06-2001 Jarek Burczynski:
+** - corrected end of sample bug in ADPCMA_calc_cha().
+** Real YM2610 checks for equality between current and end addresses (only 20 LSB bits).
+**
+** 08-12-98 hiro-shi:
+** rename ADPCMA -> ADPCMB, ADPCMB -> ADPCMA
+** move ROM limit check.(CALC_CH? -> 2610Write1/2)
+** test program (ADPCMB_TEST)
+** move ADPCM A/B end check.
+** ADPCMB repeat flag(no check)
+** change ADPCM volume rate (8->16) (32->48).
+**
+** 09-12-98 hiro-shi:
+** change ADPCM volume. (8->16, 48->64)
+** replace ym2610 ch0/3 (YM-2610B)
+** change ADPCM_SHIFT (10->8) missing bank change 0x4000-0xffff.
+** add ADPCM_SHIFT_MASK
+** change ADPCMA_DECODE_MIN/MAX.
+*/
+
+
+
+
+/************************************************************************/
+/* comment of hiro-shi(Hiromitsu Shioya) */
+/* YM2610(B) = OPN-B */
+/* YM2610 : PSG:3ch FM:4ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */
+/* YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */
+/************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+
+#ifndef __RAINE__
+#include "sndintrf.h" /* use M.A.M.E. */
+#else
+#include "deftypes.h" /* use RAINE */
+#include "support.h" /* use RAINE */
+#endif
+
+#include "ay8910.h"
+#include "fm.h"
+
+
+/* include external DELTA-T unit (when needed) */
+#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B)
+ #include "ymdeltat.h"
+#endif
+
+/* shared function building option */
+#define BUILD_OPN (BUILD_YM2203||BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B||BUILD_YM2612||BUILD_YM3438)
+#define BUILD_OPN_PRESCALER (BUILD_YM2203||BUILD_YM2608)
+
+
+/* globals */
+#define TYPE_SSG 0x01 /* SSG support */
+#define TYPE_LFOPAN 0x02 /* OPN type LFO and PAN */
+#define TYPE_6CH 0x04 /* FM 6CH / 3CH */
+#define TYPE_DAC 0x08 /* YM2612's DAC device */
+#define TYPE_ADPCM 0x10 /* two ADPCM units */
+
+
+#define TYPE_YM2203 (TYPE_SSG)
+#define TYPE_YM2608 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM)
+#define TYPE_YM2610 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM)
+#define TYPE_YM2612 (TYPE_DAC |TYPE_LFOPAN |TYPE_6CH)
+
+
+
+#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
+#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */
+#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
+#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */
+
+#define FREQ_MASK ((1<<FREQ_SH)-1)
+
+#define ENV_BITS 10
+#define ENV_LEN (1<<ENV_BITS)
+#define ENV_STEP (128.0/ENV_LEN)
+
+#define MAX_ATT_INDEX (ENV_LEN-1) /* 1023 */
+#define MIN_ATT_INDEX (0) /* 0 */
+
+#define EG_ATT 4
+#define EG_DEC 3
+#define EG_SUS 2
+#define EG_REL 1
+#define EG_OFF 0
+
+#define SIN_BITS 10
+#define SIN_LEN (1<<SIN_BITS)
+#define SIN_MASK (SIN_LEN-1)
+
+#define TL_RES_LEN (256) /* 8 bits addressing (real chip) */
+
+
+#if (FM_SAMPLE_BITS==16)
+ #define FINAL_SH (0)
+ #define MAXOUT (+32767)
+ #define MINOUT (-32768)
+#else
+ #define FINAL_SH (8)
+ #define MAXOUT (+127)
+ #define MINOUT (-128)
+#endif
+
+
+/* TL_TAB_LEN is calculated as:
+* 13 - sinus amplitude bits (Y axis)
+* 2 - sinus sign bit (Y axis)
+* TL_RES_LEN - sinus resolution (X axis)
+*/
+#define TL_TAB_LEN (13*2*TL_RES_LEN)
+static signed int tl_tab[TL_TAB_LEN];
+
+#define ENV_QUIET (TL_TAB_LEN>>3)
+
+/* sin waveform table in 'decibel' scale */
+static unsigned int sin_tab[SIN_LEN];
+
+/* sustain level table (3dB per step) */
+/* bit0, bit1, bit2, bit3, bit4, bit5, bit6 */
+/* 1, 2, 4, 8, 16, 32, 64 (value)*/
+/* 0.75, 1.5, 3, 6, 12, 24, 48 (dB)*/
+
+/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
+#define SC(db) (UINT32) ( db * (4.0/ENV_STEP) )
+static const UINT32 sl_table[16]={
+ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
+ SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
+};
+#undef SC
+
+
+#define RATE_STEPS (8)
+static const UINT8 eg_inc[19*RATE_STEPS]={
+
+/*cycle:0 1 2 3 4 5 6 7*/
+
+/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */
+/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */
+/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */
+/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */
+
+/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */
+/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */
+/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */
+/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */
+
+/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */
+/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */
+/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */
+/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */
+
+/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */
+/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */
+/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */
+/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */
+
+/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */
+/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */
+/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */
+};
+
+
+#define O(a) (a*RATE_STEPS)
+
+/*note that there is no O(17) in this table - it's directly in the code */
+static const UINT8 eg_rate_select[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */
+/* 32 infinite time rates */
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
+
+/* rates 00-11 */
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+
+/* rate 12 */
+O( 4),O( 5),O( 6),O( 7),
+
+/* rate 13 */
+O( 8),O( 9),O(10),O(11),
+
+/* rate 14 */
+O(12),O(13),O(14),O(15),
+
+/* rate 15 */
+O(16),O(16),O(16),O(16),
+
+/* 32 dummy rates (same as 15 3) */
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16)
+
+};
+#undef O
+
+/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/
+/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */
+/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */
+
+#define O(a) (a*1)
+static const UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */
+/* 32 infinite time rates */
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+
+/* rates 00-11 */
+O(11),O(11),O(11),O(11),
+O(10),O(10),O(10),O(10),
+O( 9),O( 9),O( 9),O( 9),
+O( 8),O( 8),O( 8),O( 8),
+O( 7),O( 7),O( 7),O( 7),
+O( 6),O( 6),O( 6),O( 6),
+O( 5),O( 5),O( 5),O( 5),
+O( 4),O( 4),O( 4),O( 4),
+O( 3),O( 3),O( 3),O( 3),
+O( 2),O( 2),O( 2),O( 2),
+O( 1),O( 1),O( 1),O( 1),
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 12 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 13 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 14 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 15 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* 32 dummy rates (same as 15 3) */
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0)
+
+};
+#undef O
+
+static const UINT8 dt_tab[4 * 32]={
+/* this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format)*/
+/* FD=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,
+/* FD=1 */
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
+/* FD=2 */
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
+ 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16,
+/* FD=3 */
+ 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
+ 8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22
+};
+
+
+/* OPN key frequency number -> key code follow table */
+/* fnum higher 4bit -> keycode lower 2bit */
+static const UINT8 opn_fktable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3};
+
+
+/* 8 LFO speed parameters */
+/* each value represents number of samples that one LFO level will last for */
+static const UINT32 lfo_samples_per_step[8] = {108, 77, 71, 67, 62, 44, 8, 5};
+
+
+
+/*There are 4 different LFO AM depths available, they are:
+ 0 dB, 1.4 dB, 5.9 dB, 11.8 dB
+ Here is how it is generated (in EG steps):
+
+ 11.8 dB = 0, 2, 4, 6, 8, 10,12,14,16...126,126,124,122,120,118,....4,2,0
+ 5.9 dB = 0, 1, 2, 3, 4, 5, 6, 7, 8....63, 63, 62, 61, 60, 59,.....2,1,0
+ 1.4 dB = 0, 0, 0, 0, 1, 1, 1, 1, 2,...15, 15, 15, 15, 14, 14,.....0,0,0
+
+ (1.4 dB is loosing precision as you can see)
+
+ It's implemented as generator from 0..126 with step 2 then a shift
+ right N times, where N is:
+ 8 for 0 dB
+ 3 for 1.4 dB
+ 1 for 5.9 dB
+ 0 for 11.8 dB
+*/
+static const UINT8 lfo_ams_depth_shift[4] = {8, 3, 1, 0};
+
+
+
+/*There are 8 different LFO PM depths available, they are:
+ 0, 3.4, 6.7, 10, 14, 20, 40, 80 (cents)
+
+ Modulation level at each depth depends on F-NUMBER bits: 4,5,6,7,8,9,10
+ (bits 8,9,10 = FNUM MSB from OCT/FNUM register)
+
+ Here we store only first quarter (positive one) of full waveform.
+ Full table (lfo_pm_table) containing all 128 waveforms is build
+ at run (init) time.
+
+ One value in table below represents 4 (four) basic LFO steps
+ (1 PM step = 4 AM steps).
+
+ For example:
+ at LFO SPEED=0 (which is 108 samples per basic LFO step)
+ one value from "lfo_pm_output" table lasts for 432 consecutive
+ samples (4*108=432) and one full LFO waveform cycle lasts for 13824
+ samples (32*432=13824; 32 because we store only a quarter of whole
+ waveform in the table below)
+*/
+static const UINT8 lfo_pm_output[7*8][8]={ /* 7 bits meaningful (of F-NUMBER), 8 LFO output levels per one depth (out of 32), 8 LFO depths */
+/* FNUM BIT 4: 000 0001xxxx */
+/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 6 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 7 */ {0, 0, 0, 0, 1, 1, 1, 1},
+
+/* FNUM BIT 5: 000 0010xxxx */
+/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 6 */ {0, 0, 0, 0, 1, 1, 1, 1},
+/* DEPTH 7 */ {0, 0, 1, 1, 2, 2, 2, 3},
+
+/* FNUM BIT 6: 000 0100xxxx */
+/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 1},
+/* DEPTH 5 */ {0, 0, 0, 0, 1, 1, 1, 1},
+/* DEPTH 6 */ {0, 0, 1, 1, 2, 2, 2, 3},
+/* DEPTH 7 */ {0, 0, 2, 3, 4, 4, 5, 6},
+
+/* FNUM BIT 7: 000 1000xxxx */
+/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 1, 1},
+/* DEPTH 3 */ {0, 0, 0, 0, 1, 1, 1, 1},
+/* DEPTH 4 */ {0, 0, 0, 1, 1, 1, 1, 2},
+/* DEPTH 5 */ {0, 0, 1, 1, 2, 2, 2, 3},
+/* DEPTH 6 */ {0, 0, 2, 3, 4, 4, 5, 6},
+/* DEPTH 7 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc},
+
+/* FNUM BIT 8: 001 0000xxxx */
+/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 1 */ {0, 0, 0, 0, 1, 1, 1, 1},
+/* DEPTH 2 */ {0, 0, 0, 1, 1, 1, 2, 2},
+/* DEPTH 3 */ {0, 0, 1, 1, 2, 2, 3, 3},
+/* DEPTH 4 */ {0, 0, 1, 2, 2, 2, 3, 4},
+/* DEPTH 5 */ {0, 0, 2, 3, 4, 4, 5, 6},
+/* DEPTH 6 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc},
+/* DEPTH 7 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18},
+
+/* FNUM BIT 9: 010 0000xxxx */
+/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 1 */ {0, 0, 0, 0, 2, 2, 2, 2},
+/* DEPTH 2 */ {0, 0, 0, 2, 2, 2, 4, 4},
+/* DEPTH 3 */ {0, 0, 2, 2, 4, 4, 6, 6},
+/* DEPTH 4 */ {0, 0, 2, 4, 4, 4, 6, 8},
+/* DEPTH 5 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc},
+/* DEPTH 6 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18},
+/* DEPTH 7 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30},
+
+/* FNUM BIT10: 100 0000xxxx */
+/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
+/* DEPTH 1 */ {0, 0, 0, 0, 4, 4, 4, 4},
+/* DEPTH 2 */ {0, 0, 0, 4, 4, 4, 8, 8},
+/* DEPTH 3 */ {0, 0, 4, 4, 8, 8, 0xc, 0xc},
+/* DEPTH 4 */ {0, 0, 4, 8, 8, 8, 0xc,0x10},
+/* DEPTH 5 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18},
+/* DEPTH 6 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30},
+/* DEPTH 7 */ {0, 0,0x20,0x30,0x40,0x40,0x50,0x60},
+
+};
+
+/* all 128 LFO PM waveforms */
+static INT32 lfo_pm_table[128*8*32]; /* 128 combinations of 7 bits meaningful (of F-NUMBER), 8 LFO depths, 32 LFO output levels per one depth */
+
+
+
+
+
+/* register number to channel number , slot offset */
+#define OPN_CHAN(N) (N&3)
+#define OPN_SLOT(N) ((N>>2)&3)
+
+/* slot number */
+#define SLOT1 0
+#define SLOT2 2
+#define SLOT3 1
+#define SLOT4 3
+
+/* bit0 = Right enable , bit1 = Left enable */
+#define OUTD_RIGHT 1
+#define OUTD_LEFT 2
+#define OUTD_CENTER 3
+
+
+/* save output as raw 16-bit sample */
+/* #define SAVE_SAMPLE */
+
+#ifdef SAVE_SAMPLE
+static FILE *sample[1];
+ #if 1 /*save to MONO file */
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = lt; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ }
+ #else /*save to STEREO file */
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = lt; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ pom = rt; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ }
+ #endif
+#endif
+
+
+/* struct describing a single operator (SLOT) */
+typedef struct
+{
+ INT32 *DT; /* detune :dt_tab[DT] */
+ UINT8 KSR; /* key scale rate :3-KSR */
+ UINT32 ar; /* attack rate */
+ UINT32 d1r; /* decay rate */
+ UINT32 d2r; /* sustain rate */
+ UINT32 rr; /* release rate */
+ UINT8 ksr; /* key scale rate :kcode>>(3-KSR) */
+ UINT32 mul; /* multiple :ML_TABLE[ML] */
+
+ /* Phase Generator */
+ UINT32 phase; /* phase counter */
+ UINT32 Incr; /* phase step */
+
+ /* Envelope Generator */
+ UINT8 state; /* phase type */
+ UINT32 tl; /* total level: TL << 3 */
+ INT32 volume; /* envelope counter */
+ UINT32 sl; /* sustain level:sl_table[SL] */
+ UINT32 vol_out; /* current output from EG circuit (without AM from LFO) */
+
+ UINT8 eg_sh_ar; /* (attack state) */
+ UINT8 eg_sel_ar; /* (attack state) */
+ UINT8 eg_sh_d1r; /* (decay state) */
+ UINT8 eg_sel_d1r; /* (decay state) */
+ UINT8 eg_sh_d2r; /* (sustain state) */
+ UINT8 eg_sel_d2r; /* (sustain state) */
+ UINT8 eg_sh_rr; /* (release state) */
+ UINT8 eg_sel_rr; /* (release state) */
+
+ UINT8 ssg; /* SSG-EG waveform */
+ UINT8 ssgn; /* SSG-EG negated output */
+
+ UINT32 key; /* 0=last key was KEY OFF, 1=KEY ON */
+
+ /* LFO */
+ UINT32 AMmask; /* AM enable flag */
+
+} FM_SLOT;
+
+typedef struct
+{
+ FM_SLOT SLOT[4]; /* four SLOTs (operators) */
+
+ UINT8 ALGO; /* algorithm */
+ UINT8 FB; /* feedback shift */
+ INT32 op1_out[2]; /* op1 output for feedback */
+
+ INT32 *connect1; /* SLOT1 output pointer */
+ INT32 *connect3; /* SLOT3 output pointer */
+ INT32 *connect2; /* SLOT2 output pointer */
+ INT32 *connect4; /* SLOT4 output pointer */
+
+ INT32 *mem_connect;/* where to put the delayed sample (MEM) */
+ INT32 mem_value; /* delayed sample (MEM) value */
+
+ INT32 pms; /* channel PMS */
+ UINT8 ams; /* channel AMS */
+
+ UINT32 fc; /* fnum,blk:adjusted to sample rate */
+ UINT8 kcode; /* key code: */
+ UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
+} FM_CH;
+
+
+typedef struct
+{
+ void * param; /* this chip parameter */
+ int clock; /* master clock (Hz) */
+ int rate; /* sampling rate (Hz) */
+ double freqbase; /* frequency base */
+ int timer_prescaler; /* timer prescaler */
+#if FM_BUSY_FLAG_SUPPORT
+ TIME_TYPE busy_expiry_time; /* expiry time of the busy status */
+#endif
+ UINT8 address; /* address register */
+ UINT8 irq; /* interrupt level */
+ UINT8 irqmask; /* irq mask */
+ UINT8 status; /* status flag */
+ UINT32 mode; /* mode CSM / 3SLOT */
+ UINT8 prescaler_sel; /* prescaler selector */
+ UINT8 fn_h; /* freq latch */
+ INT32 TA; /* timer a */
+ INT32 TAC; /* timer a counter */
+ UINT8 TB; /* timer b */
+ INT32 TBC; /* timer b counter */
+ /* local time tables */
+ INT32 dt_tab[8][32]; /* DeTune table */
+ /* Extention Timer and IRQ handler */
+ FM_TIMERHANDLER timer_handler;
+ FM_IRQHANDLER IRQ_Handler;
+ const struct ssg_callbacks *SSG;
+} FM_ST;
+
+
+
+/***********************************************************/
+/* OPN unit */
+/***********************************************************/
+
+/* OPN 3slot struct */
+typedef struct
+{
+ UINT32 fc[3]; /* fnum3,blk3: calculated */
+ UINT8 fn_h; /* freq3 latch */
+ UINT8 kcode[3]; /* key code */
+ UINT32 block_fnum[3]; /* current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
+} FM_3SLOT;
+
+/* OPN/A/B common state */
+typedef struct
+{
+ UINT8 type; /* chip type */
+ FM_ST ST; /* general state */
+ FM_3SLOT SL3; /* 3 slot mode state */
+ FM_CH *P_CH; /* pointer of CH */
+ unsigned int pan[6*2]; /* fm channels output masks (0xffffffff = enable) */
+
+ UINT32 eg_cnt; /* global envelope generator counter */
+ UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/64/3 */
+ UINT32 eg_timer_add; /* step of eg_timer */
+ UINT32 eg_timer_overflow;/* envelope generator timer overlfows every 3 samples (on real chip) */
+
+
+ /* there are 2048 FNUMs that can be generated using FNUM/BLK registers
+ but LFO works with one more bit of a precision so we really need 4096 elements */
+
+ UINT32 fn_table[4096]; /* fnumber->increment counter */
+
+
+ /* LFO */
+ UINT32 lfo_cnt;
+ UINT32 lfo_inc;
+
+ UINT32 lfo_freq[8]; /* LFO FREQ table */
+} FM_OPN;
+
+
+
+/* current chip state */
+static INT32 m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */
+static INT32 mem; /* one sample delay memory */
+
+static INT32 out_fm[8]; /* outputs of working channels */
+
+#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B)
+static INT32 out_adpcm[4]; /* channel output NONE,LEFT,RIGHT or CENTER for YM2608/YM2610 ADPCM */
+static INT32 out_delta[4]; /* channel output NONE,LEFT,RIGHT or CENTER for YM2608/YM2610 DELTAT*/
+#endif
+
+static UINT32 LFO_AM; /* runtime LFO calculations helper */
+static INT32 LFO_PM; /* runtime LFO calculations helper */
+
+
+/* log output level */
+#define LOG_ERR 3 /* ERROR */
+#define LOG_WAR 2 /* WARNING */
+#define LOG_INF 1 /* INFORMATION */
+#define LOG_LEVEL LOG_INF
+
+#ifndef __RAINE__
+#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x
+#endif
+
+/* limitter */
+#define Limit(val, max,min) { \
+ if ( val > max ) val = max; \
+ else if ( val < min ) val = min; \
+}
+
+
+/* status set and IRQ handling */
+INLINE void FM_STATUS_SET(FM_ST *ST,int flag)
+{
+ /* set status flag */
+ ST->status |= flag;
+ if ( !(ST->irq) && (ST->status & ST->irqmask) )
+ {
+ ST->irq = 1;
+ /* callback user interrupt handler (IRQ is OFF to ON) */
+ if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->param,1);
+ }
+}
+
+/* status reset and IRQ handling */
+INLINE void FM_STATUS_RESET(FM_ST *ST,int flag)
+{
+ /* reset status flag */
+ ST->status &=~flag;
+ if ( (ST->irq) && !(ST->status & ST->irqmask) )
+ {
+ ST->irq = 0;
+ /* callback user interrupt handler (IRQ is ON to OFF) */
+ if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->param,0);
+ }
+}
+
+/* IRQ mask set */
+INLINE void FM_IRQMASK_SET(FM_ST *ST,int flag)
+{
+ ST->irqmask = flag;
+ /* IRQ handling check */
+ FM_STATUS_SET(ST,0);
+ FM_STATUS_RESET(ST,0);
+}
+
+/* OPN Mode Register Write */
+INLINE void set_timers( FM_ST *ST, void *n, int v )
+{
+ /* b7 = CSM MODE */
+ /* b6 = 3 slot mode */
+ /* b5 = reset b */
+ /* b4 = reset a */
+ /* b3 = timer enable b */
+ /* b2 = timer enable a */
+ /* b1 = load b */
+ /* b0 = load a */
+ ST->mode = v;
+
+ /* reset Timer b flag */
+ if( v & 0x20 )
+ FM_STATUS_RESET(ST,0x02);
+ /* reset Timer a flag */
+ if( v & 0x10 )
+ FM_STATUS_RESET(ST,0x01);
+ /* load b */
+ if( v & 0x02 )
+ {
+ if( ST->TBC == 0 )
+ {
+ ST->TBC = ( 256-ST->TB)<<4;
+ /* External timer handler */
+ if (ST->timer_handler) (ST->timer_handler)(n,1,ST->TBC * ST->timer_prescaler,ST->clock);
+ }
+ }
+ else
+ { /* stop timer b */
+ if( ST->TBC != 0 )
+ {
+ ST->TBC = 0;
+ if (ST->timer_handler) (ST->timer_handler)(n,1,0,ST->clock);
+ }
+ }
+ /* load a */
+ if( v & 0x01 )
+ {
+ if( ST->TAC == 0 )
+ {
+ ST->TAC = (1024-ST->TA);
+ /* External timer handler */
+ if (ST->timer_handler) (ST->timer_handler)(n,0,ST->TAC * ST->timer_prescaler,ST->clock);
+ }
+ }
+ else
+ { /* stop timer a */
+ if( ST->TAC != 0 )
+ {
+ ST->TAC = 0;
+ if (ST->timer_handler) (ST->timer_handler)(n,0,0,ST->clock);
+ }
+ }
+}
+
+
+/* Timer A Overflow */
+INLINE void TimerAOver(FM_ST *ST)
+{
+ /* set status (if enabled) */
+ if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01);
+ /* clear or reload the counter */
+ ST->TAC = (1024-ST->TA);
+ if (ST->timer_handler) (ST->timer_handler)(ST->param,0,ST->TAC * ST->timer_prescaler,ST->clock);
+}
+/* Timer B Overflow */
+INLINE void TimerBOver(FM_ST *ST)
+{
+ /* set status (if enabled) */
+ if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02);
+ /* clear or reload the counter */
+ ST->TBC = ( 256-ST->TB)<<4;
+ if (ST->timer_handler) (ST->timer_handler)(ST->param,1,ST->TBC * ST->timer_prescaler,ST->clock);
+}
+
+
+#if FM_INTERNAL_TIMER
+/* ----- internal timer mode , update timer */
+
+/* ---------- calculate timer A ---------- */
+ #define INTERNAL_TIMER_A(ST,CSM_CH) \
+ { \
+ if( ST->TAC && (ST->timer_handler==0) ) \
+ if( (ST->TAC -= (int)(ST->freqbase*4096)) <= 0 ) \
+ { \
+ TimerAOver( ST ); \
+ /* CSM mode total level latch and auto key on */ \
+ if( ST->mode & 0x80 ) \
+ CSMKeyControll( CSM_CH ); \
+ } \
+ }
+/* ---------- calculate timer B ---------- */
+ #define INTERNAL_TIMER_B(ST,step) \
+ { \
+ if( ST->TBC && (ST->timer_handler==0) ) \
+ if( (ST->TBC -= (int)(ST->freqbase*4096*step)) <= 0 ) \
+ TimerBOver( ST ); \
+ }
+#else /* FM_INTERNAL_TIMER */
+/* external timer mode */
+#define INTERNAL_TIMER_A(ST,CSM_CH)
+#define INTERNAL_TIMER_B(ST,step)
+#endif /* FM_INTERNAL_TIMER */
+
+
+
+#if FM_BUSY_FLAG_SUPPORT
+#define FM_BUSY_CLEAR(ST) ((ST)->busy_expiry_time = UNDEFINED_TIME)
+INLINE UINT8 FM_STATUS_FLAG(FM_ST *ST)
+{
+ if( COMPARE_TIMES(ST->busy_expiry_time, UNDEFINED_TIME) != 0 )
+ {
+ if (COMPARE_TIMES(ST->busy_expiry_time, FM_GET_TIME_NOW()) > 0)
+ return ST->status | 0x80; /* with busy */
+ /* expire */
+ FM_BUSY_CLEAR(ST);
+ }
+ return ST->status;
+}
+INLINE void FM_BUSY_SET(FM_ST *ST,int busyclock )
+{
+ TIME_TYPE expiry_period = MULTIPLY_TIME_BY_INT(ATTOTIME_IN_HZ(ST->clock), busyclock * ST->timer_prescaler);
+ ST->busy_expiry_time = ADD_TIMES(FM_GET_TIME_NOW(), expiry_period);
+}
+#else
+#define FM_STATUS_FLAG(ST) ((ST)->status)
+#define FM_BUSY_SET(ST,bclock) {}
+#define FM_BUSY_CLEAR(ST) {}
+#endif
+
+
+
+
+INLINE void FM_KEYON(FM_CH *CH , int s )
+{
+ FM_SLOT *SLOT = &CH->SLOT[s];
+ if( !SLOT->key )
+ {
+ SLOT->key = 1;
+ SLOT->phase = 0; /* restart Phase Generator */
+ SLOT->state = EG_ATT; /* phase -> Attack */
+ }
+}
+
+INLINE void FM_KEYOFF(FM_CH *CH , int s )
+{
+ FM_SLOT *SLOT = &CH->SLOT[s];
+ if( SLOT->key )
+ {
+ SLOT->key = 0;
+ if (SLOT->state>EG_REL)
+ SLOT->state = EG_REL;/* phase -> Release */
+ }
+}
+
+/* set algorithm connection */
+static void setup_connection( FM_CH *CH, int ch )
+{
+ INT32 *carrier = &out_fm[ch];
+
+ INT32 **om1 = &CH->connect1;
+ INT32 **om2 = &CH->connect3;
+ INT32 **oc1 = &CH->connect2;
+
+ INT32 **memc = &CH->mem_connect;
+
+ switch( CH->ALGO ){
+ case 0:
+ /* M1---C1---MEM---M2---C2---OUT */
+ *om1 = &c1;
+ *oc1 = &mem;
+ *om2 = &c2;
+ *memc= &m2;
+ break;
+ case 1:
+ /* M1------+-MEM---M2---C2---OUT */
+ /* C1-+ */
+ *om1 = &mem;
+ *oc1 = &mem;
+ *om2 = &c2;
+ *memc= &m2;
+ break;
+ case 2:
+ /* M1-----------------+-C2---OUT */
+ /* C1---MEM---M2-+ */
+ *om1 = &c2;
+ *oc1 = &mem;
+ *om2 = &c2;
+ *memc= &m2;
+ break;
+ case 3:
+ /* M1---C1---MEM------+-C2---OUT */
+ /* M2-+ */
+ *om1 = &c1;
+ *oc1 = &mem;
+ *om2 = &c2;
+ *memc= &c2;
+ break;
+ case 4:
+ /* M1---C1-+-OUT */
+ /* M2---C2-+ */
+ /* MEM: not used */
+ *om1 = &c1;
+ *oc1 = carrier;
+ *om2 = &c2;
+ *memc= &mem; /* store it anywhere where it will not be used */
+ break;
+ case 5:
+ /* +----C1----+ */
+ /* M1-+-MEM---M2-+-OUT */
+ /* +----C2----+ */
+ *om1 = 0; /* special mark */
+ *oc1 = carrier;
+ *om2 = carrier;
+ *memc= &m2;
+ break;
+ case 6:
+ /* M1---C1-+ */
+ /* M2-+-OUT */
+ /* C2-+ */
+ /* MEM: not used */
+ *om1 = &c1;
+ *oc1 = carrier;
+ *om2 = carrier;
+ *memc= &mem; /* store it anywhere where it will not be used */
+ break;
+ case 7:
+ /* M1-+ */
+ /* C1-+-OUT */
+ /* M2-+ */
+ /* C2-+ */
+ /* MEM: not used*/
+ *om1 = carrier;
+ *oc1 = carrier;
+ *om2 = carrier;
+ *memc= &mem; /* store it anywhere where it will not be used */
+ break;
+ }
+
+ CH->connect4 = carrier;
+}
+
+/* set detune & multiple */
+INLINE void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v)
+{
+ SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1;
+ SLOT->DT = ST->dt_tab[(v>>4)&7];
+ CH->SLOT[SLOT1].Incr=-1;
+}
+
+/* set total level */
+INLINE void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v)
+{
+ SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */
+}
+
+/* set attack rate & key scale */
+INLINE void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v)
+{
+ UINT8 old_KSR = SLOT->KSR;
+
+ SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
+
+ SLOT->KSR = 3-(v>>6);
+ if (SLOT->KSR != old_KSR)
+ {
+ CH->SLOT[SLOT1].Incr=-1;
+ }
+ else
+ {
+ /* refresh Attack rate */
+ if ((SLOT->ar + SLOT->ksr) < 32+62)
+ {
+ SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
+ SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
+ }
+ else
+ {
+ SLOT->eg_sh_ar = 0;
+ SLOT->eg_sel_ar = 17*RATE_STEPS;
+ }
+ }
+}
+
+/* set decay rate */
+INLINE void set_dr(FM_SLOT *SLOT,int v)
+{
+ SLOT->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
+
+ SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr];
+ SLOT->eg_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr];
+
+}
+
+/* set sustain rate */
+INLINE void set_sr(FM_SLOT *SLOT,int v)
+{
+ SLOT->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
+
+ SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr];
+ SLOT->eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr];
+}
+
+/* set release rate */
+INLINE void set_sl_rr(FM_SLOT *SLOT,int v)
+{
+ SLOT->sl = sl_table[ v>>4 ];
+
+ SLOT->rr = 34 + ((v&0x0f)<<2);
+
+ SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr];
+ SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr];
+}
+
+
+
+INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm)
+{
+ UINT32 p;
+
+ p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ];
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+ return tl_tab[p];
+}
+
+INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm)
+{
+ UINT32 p;
+
+ p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK ];
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+ return tl_tab[p];
+}
+
+/* advance LFO to next sample */
+INLINE void advance_lfo(FM_OPN *OPN)
+{
+ UINT8 pos;
+ UINT8 prev_pos;
+
+ if (OPN->lfo_inc) /* LFO enabled ? */
+ {
+ prev_pos = OPN->lfo_cnt>>LFO_SH & 127;
+
+ OPN->lfo_cnt += OPN->lfo_inc;
+
+ pos = (OPN->lfo_cnt >> LFO_SH) & 127;
+
+
+ /* update AM when LFO output changes */
+
+ /*if (prev_pos != pos)*/
+ /* actually I can't optimize is this way without rewritting chan_calc()
+ to use chip->lfo_am instead of global lfo_am */
+ {
+
+ /* triangle */
+ /* AM: 0 to 126 step +2, 126 to 0 step -2 */
+ if (pos<64)
+ LFO_AM = (pos&63) * 2;
+ else
+ LFO_AM = 126 - ((pos&63) * 2);
+ }
+
+ /* PM works with 4 times slower clock */
+ prev_pos >>= 2;
+ pos >>= 2;
+ /* update PM when LFO output changes */
+ /*if (prev_pos != pos)*/ /* can't use global lfo_pm for this optimization, must be chip->lfo_pm instead*/
+ {
+ LFO_PM = pos;
+ }
+
+ }
+ else
+ {
+ LFO_AM = 0;
+ LFO_PM = 0;
+ }
+}
+
+/* changed from INLINE to static here to work around gcc 4.2.1 codegen bug */
+static void advance_eg_channel(FM_OPN *OPN, FM_SLOT *SLOT)
+{
+ unsigned int out;
+ unsigned int swap_flag = 0;
+ unsigned int i;
+
+
+ i = 4; /* four operators per channel */
+ do
+ {
+ switch(SLOT->state)
+ {
+ case EG_ATT: /* attack phase */
+ if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_ar)-1) ) )
+ {
+ SLOT->volume += (~SLOT->volume *
+ (eg_inc[SLOT->eg_sel_ar + ((OPN->eg_cnt>>SLOT->eg_sh_ar)&7)])
+ ) >>4;
+
+ if (SLOT->volume <= MIN_ATT_INDEX)
+ {
+ SLOT->volume = MIN_ATT_INDEX;
+ SLOT->state = EG_DEC;
+ }
+ }
+ break;
+
+ case EG_DEC: /* decay phase */
+ if (SLOT->ssg&0x08) /* SSG EG type envelope selected */
+ {
+ if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_d1r)-1) ) )
+ {
+ SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)];
+
+ if ( SLOT->volume >= SLOT->sl )
+ SLOT->state = EG_SUS;
+ }
+ }
+ else
+ {
+ if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_d1r)-1) ) )
+ {
+ SLOT->volume += eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)];
+
+ if ( SLOT->volume >= SLOT->sl )
+ SLOT->state = EG_SUS;
+ }
+ }
+ break;
+
+ case EG_SUS: /* sustain phase */
+ if (SLOT->ssg&0x08) /* SSG EG type envelope selected */
+ {
+ if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_d2r)-1) ) )
+ {
+ SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)];
+
+ if ( SLOT->volume >= MAX_ATT_INDEX )
+ {
+ SLOT->volume = MAX_ATT_INDEX;
+
+ if (SLOT->ssg&0x01) /* bit 0 = hold */
+ {
+ if (SLOT->ssgn&1) /* have we swapped once ??? */
+ {
+ /* yes, so do nothing, just hold current level */
+ }
+ else
+ swap_flag = (SLOT->ssg&0x02) | 1 ; /* bit 1 = alternate */
+
+ }
+ else
+ {
+ /* same as KEY-ON operation */
+
+ /* restart of the Phase Generator should be here,
+ only if AR is not maximum ??? */
+ /*SLOT->phase = 0;*/
+
+ /* phase -> Attack */
+ SLOT->state = EG_ATT;
+
+ swap_flag = (SLOT->ssg&0x02); /* bit 1 = alternate */
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_d2r)-1) ) )
+ {
+ SLOT->volume += eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)];
+
+ if ( SLOT->volume >= MAX_ATT_INDEX )
+ {
+ SLOT->volume = MAX_ATT_INDEX;
+ /* do not change SLOT->state (verified on real chip) */
+ }
+ }
+
+ }
+ break;
+
+ case EG_REL: /* release phase */
+ if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_rr)-1) ) )
+ {
+ SLOT->volume += eg_inc[SLOT->eg_sel_rr + ((OPN->eg_cnt>>SLOT->eg_sh_rr)&7)];
+
+ if ( SLOT->volume >= MAX_ATT_INDEX )
+ {
+ SLOT->volume = MAX_ATT_INDEX;
+ SLOT->state = EG_OFF;
+ }
+ }
+ break;
+
+ }
+
+ out = SLOT->tl + ((UINT32)SLOT->volume);
+
+ if ((SLOT->ssg&0x08) && (SLOT->ssgn&2)) /* negate output (changes come from alternate bit, init comes from attack bit) */
+ out ^= ((1<<ENV_BITS)-1); /* 1023 */
+
+ /* we need to store the result here because we are going to change ssgn
+ in next instruction */
+ SLOT->vol_out = out;
+
+ SLOT->ssgn ^= swap_flag;
+
+ SLOT++;
+ i--;
+ }while (i);
+
+}
+
+
+
+#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask))
+
+INLINE void chan_calc(FM_OPN *OPN, FM_CH *CH)
+{
+ unsigned int eg_out;
+
+ UINT32 AM = LFO_AM >> CH->ams;
+
+
+ m2 = c1 = c2 = mem = 0;
+
+ *CH->mem_connect = CH->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
+
+ eg_out = volume_calc(&CH->SLOT[SLOT1]);
+ {
+ INT32 out = CH->op1_out[0] + CH->op1_out[1];
+ CH->op1_out[0] = CH->op1_out[1];
+
+ if( !CH->connect1 ){
+ /* algorithm 5 */
+ mem = c1 = c2 = CH->op1_out[0];
+ }else{
+ /* other algorithms */
+ *CH->connect1 += CH->op1_out[0];
+ }
+
+ CH->op1_out[1] = 0;
+ if( eg_out < ENV_QUIET ) /* SLOT 1 */
+ {
+ if (!CH->FB)
+ out=0;
+
+ CH->op1_out[1] = op_calc1(CH->SLOT[SLOT1].phase, eg_out, (out<<CH->FB) );
+ }
+ }
+
+ eg_out = volume_calc(&CH->SLOT[SLOT3]);
+ if( eg_out < ENV_QUIET ) /* SLOT 3 */
+ *CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, m2);
+
+ eg_out = volume_calc(&CH->SLOT[SLOT2]);
+ if( eg_out < ENV_QUIET ) /* SLOT 2 */
+ *CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, c1);
+
+ eg_out = volume_calc(&CH->SLOT[SLOT4]);
+ if( eg_out < ENV_QUIET ) /* SLOT 4 */
+ *CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, c2);
+
+
+ /* store current MEM */
+ CH->mem_value = mem;
+
+ /* update phase counters AFTER output calculations */
+ if(CH->pms)
+ {
+
+
+ /* add support for 3 slot mode */
+
+
+ UINT32 block_fnum = CH->block_fnum;
+
+ UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8;
+ INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + CH->pms + LFO_PM ];
+
+ if (lfo_fn_table_index_offset) /* LFO phase modulation active */
+ {
+ UINT8 blk;
+ UINT32 fn;
+ int kc,fc;
+
+ block_fnum = block_fnum*2 + lfo_fn_table_index_offset;
+
+ blk = (block_fnum&0x7000) >> 12;
+ fn = block_fnum & 0xfff;
+
+ /* keyscale code */
+ kc = (blk<<2) | opn_fktable[fn >> 8];
+ /* phase increment counter */
+ fc = OPN->fn_table[fn]>>(7-blk);
+
+ CH->SLOT[SLOT1].phase += ((fc+CH->SLOT[SLOT1].DT[kc])*CH->SLOT[SLOT1].mul) >> 1;
+ CH->SLOT[SLOT2].phase += ((fc+CH->SLOT[SLOT2].DT[kc])*CH->SLOT[SLOT2].mul) >> 1;
+ CH->SLOT[SLOT3].phase += ((fc+CH->SLOT[SLOT3].DT[kc])*CH->SLOT[SLOT3].mul) >> 1;
+ CH->SLOT[SLOT4].phase += ((fc+CH->SLOT[SLOT4].DT[kc])*CH->SLOT[SLOT4].mul) >> 1;
+ }
+ else /* LFO phase modulation = zero */
+ {
+ CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr;
+ CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr;
+ CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr;
+ CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr;
+ }
+ }
+ else /* no LFO phase modulation */
+ {
+ CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr;
+ CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr;
+ CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr;
+ CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr;
+ }
+}
+
+/* update phase increment and envelope generator */
+INLINE void refresh_fc_eg_slot(FM_SLOT *SLOT , int fc , int kc )
+{
+ int ksr;
+
+ /* (frequency) phase increment counter */
+ SLOT->Incr = ((fc+SLOT->DT[kc])*SLOT->mul) >> 1;
+
+ ksr = kc >> SLOT->KSR;
+ if( SLOT->ksr != ksr )
+ {
+ SLOT->ksr = ksr;
+
+ /* calculate envelope generator rates */
+ if ((SLOT->ar + SLOT->ksr) < 32+62)
+ {
+ SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
+ SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
+ }
+ else
+ {
+ SLOT->eg_sh_ar = 0;
+ SLOT->eg_sel_ar = 17*RATE_STEPS;
+ }
+
+ SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr];
+ SLOT->eg_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr];
+
+ SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr];
+ SLOT->eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr];
+
+ SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr];
+ SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr];
+ }
+}
+
+/* update phase increment counters */
+INLINE void refresh_fc_eg_chan(FM_CH *CH )
+{
+ if( CH->SLOT[SLOT1].Incr==-1){
+ int fc = CH->fc;
+ int kc = CH->kcode;
+ refresh_fc_eg_slot(&CH->SLOT[SLOT1] , fc , kc );
+ refresh_fc_eg_slot(&CH->SLOT[SLOT2] , fc , kc );
+ refresh_fc_eg_slot(&CH->SLOT[SLOT3] , fc , kc );
+ refresh_fc_eg_slot(&CH->SLOT[SLOT4] , fc , kc );
+ }
+}
+
+/* initialize time tables */
+static void init_timetables( FM_ST *ST , const UINT8 *dttable )
+{
+ int i,d;
+ double rate;
+
+#if 0
+ logerror("FM.C: samplerate=%8i chip clock=%8i freqbase=%f \n",
+ ST->rate, ST->clock, ST->freqbase );
+#endif
+
+ /* DeTune table */
+ for (d = 0;d <= 3;d++){
+ for (i = 0;i <= 31;i++){
+ rate = ((double)dttable[d*32 + i]) * SIN_LEN * ST->freqbase * (1<<FREQ_SH) / ((double)(1<<20));
+ ST->dt_tab[d][i] = (INT32) rate;
+ ST->dt_tab[d+4][i] = -ST->dt_tab[d][i];
+#if 0
+ logerror("FM.C: DT [%2i %2i] = %8x \n", d, i, ST->dt_tab[d][i] );
+#endif
+ }
+ }
+
+}
+
+
+static void reset_channels( FM_ST *ST , FM_CH *CH , int num )
+{
+ int c,s;
+
+ ST->mode = 0; /* normal mode */
+ ST->TA = 0;
+ ST->TAC = 0;
+ ST->TB = 0;
+ ST->TBC = 0;
+
+ for( c = 0 ; c < num ; c++ )
+ {
+ CH[c].fc = 0;
+ for(s = 0 ; s < 4 ; s++ )
+ {
+ CH[c].SLOT[s].ssg = 0;
+ CH[c].SLOT[s].ssgn = 0;
+ CH[c].SLOT[s].state= EG_OFF;
+ CH[c].SLOT[s].volume = MAX_ATT_INDEX;
+ CH[c].SLOT[s].vol_out= MAX_ATT_INDEX;
+ }
+ }
+}
+
+/* initialize generic tables */
+static int init_tables(void)
+{
+ signed int i,x;
+ signed int n;
+ double o,m;
+
+ for (x=0; x<TL_RES_LEN; x++)
+ {
+ m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0);
+ m = floor(m);
+
+ /* we never reach (1<<16) here due to the (x+1) */
+ /* result fits within 16 bits at maximum */
+
+ n = (int)m; /* 16 bits here */
+ n >>= 4; /* 12 bits here */
+ if (n&1) /* round to nearest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+ /* 11 bits here (rounded) */
+ n <<= 2; /* 13 bits here (as in real chip) */
+ tl_tab[ x*2 + 0 ] = n;
+ tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ];
+
+ for (i=1; i<13; i++)
+ {
+ tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i;
+ tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ];
+ }
+ #if 0
+ logerror("tl %04i", x);
+ for (i=0; i<13; i++)
+ logerror(", [%02i] %4x", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ]);
+ logerror("\n");
+ }
+ #endif
+ }
+ /*logerror("FM.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/
+
+
+ for (i=0; i<SIN_LEN; i++)
+ {
+ /* non-standard sinus */
+ m = sin( ((i*2)+1) * M_PI / SIN_LEN ); /* checked against the real chip */
+
+ /* we never reach zero here due to ((i*2)+1) */
+
+ if (m>0.0)
+ o = 8*log(1.0/m)/log(2); /* convert to 'decibels' */
+ else
+ o = 8*log(-1.0/m)/log(2); /* convert to 'decibels' */
+
+ o = o / (ENV_STEP/4);
+
+ n = (int)(2.0*o);
+ if (n&1) /* round to nearest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+
+ sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 );
+ /*logerror("FM.C: sin [%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[i],tl_tab[sin_tab[i]]);*/
+ }
+
+ /*logerror("FM.C: ENV_QUIET= %08x\n",ENV_QUIET );*/
+
+
+ /* build LFO PM modulation table */
+ for(i = 0; i < 8; i++) /* 8 PM depths */
+ {
+ UINT8 fnum;
+ for (fnum=0; fnum<128; fnum++) /* 7 bits meaningful of F-NUMBER */
+ {
+ UINT8 value;
+ UINT8 step;
+ UINT32 offset_depth = i;
+ UINT32 offset_fnum_bit;
+ UINT32 bit_tmp;
+
+ for (step=0; step<8; step++)
+ {
+ value = 0;
+ for (bit_tmp=0; bit_tmp<7; bit_tmp++) /* 7 bits */
+ {
+ if (fnum & (1<<bit_tmp)) /* only if bit "bit_tmp" is set */
+ {
+ offset_fnum_bit = bit_tmp * 8;
+ value += lfo_pm_output[offset_fnum_bit + offset_depth][step];
+ }
+ }
+ lfo_pm_table[(fnum*32*8) + (i*32) + step + 0] = value;
+ lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+ 8] = value;
+ lfo_pm_table[(fnum*32*8) + (i*32) + step +16] = -value;
+ lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+24] = -value;
+ }
+#if 0
+ logerror("LFO depth=%1x FNUM=%04x (<<4=%4x): ", i, fnum, fnum<<4);
+ for (step=0; step<16; step++) /* dump only positive part of waveforms */
+ logerror("%02x ", lfo_pm_table[(fnum*32*8) + (i*32) + step] );
+ logerror("\n");
+#endif
+
+ }
+ }
+
+
+
+#ifdef SAVE_SAMPLE
+ sample[0]=fopen("sampsum.pcm","wb");
+#endif
+
+ return 1;
+
+}
+
+
+
+static void FMCloseTable( void )
+{
+#ifdef SAVE_SAMPLE
+ fclose(sample[0]);
+#endif
+ return;
+}
+
+
+/* CSM Key Controll */
+INLINE void CSMKeyControll(FM_CH *CH)
+{
+ /* this is wrong, atm */
+
+ /* all key on */
+ FM_KEYON(CH,SLOT1);
+ FM_KEYON(CH,SLOT2);
+ FM_KEYON(CH,SLOT3);
+ FM_KEYON(CH,SLOT4);
+}
+
+#ifdef __STATE_H__
+/* FM channel save , internal state only */
+static void FMsave_state_channel(const char *name,int num,FM_CH *CH,int num_ch)
+{
+ int slot , ch;
+ char state_name[20];
+ static const char slot_array[4] = { 1 , 3 , 2 , 4 };
+
+ for(ch=0;ch<num_ch;ch++,CH++)
+ {
+ /* channel */
+ sprintf(state_name,"%s.CH%d",name,ch);
+ state_save_register_item_array(state_name, num, CH->op1_out);
+ state_save_register_item(state_name, num, CH->fc);
+ /* slots */
+ for(slot=0;slot<4;slot++)
+ {
+ FM_SLOT *SLOT = &CH->SLOT[slot];
+
+ sprintf(state_name,"%s.CH%d.SLOT%d",name,ch,slot_array[slot]);
+ state_save_register_item(state_name, num, SLOT->phase);
+ state_save_register_item(state_name, num, SLOT->state);
+ state_save_register_item(state_name, num, SLOT->volume);
+ }
+ }
+}
+
+static void FMsave_state_st(const char *state_name,int num,FM_ST *ST)
+{
+#if FM_BUSY_FLAG_SUPPORT
+ state_save_register_item(state_name, num, ST->busy_expiry_time.seconds );
+ state_save_register_item(state_name, num, ST->busy_expiry_time.attoseconds );
+#endif
+ state_save_register_item(state_name, num, ST->address );
+ state_save_register_item(state_name, num, ST->irq );
+ state_save_register_item(state_name, num, ST->irqmask );
+ state_save_register_item(state_name, num, ST->status );
+ state_save_register_item(state_name, num, ST->mode );
+ state_save_register_item(state_name, num, ST->prescaler_sel );
+ state_save_register_item(state_name, num, ST->fn_h );
+ state_save_register_item(state_name, num, ST->TA );
+ state_save_register_item(state_name, num, ST->TAC );
+ state_save_register_item(state_name, num, ST->TB );
+ state_save_register_item(state_name, num, ST->TBC );
+}
+#endif /* _STATE_H */
+
+#if BUILD_OPN
+
+
+
+/* prescaler set (and make time tables) */
+static void OPNSetPres(FM_OPN *OPN, int pres, int timer_prescaler, int SSGpres)
+{
+ int i;
+
+ /* frequency base */
+ OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pres : 0;
+
+#if 0
+ OPN->ST.rate = (double)OPN->ST.clock / pres;
+ OPN->ST.freqbase = 1.0;
+#endif
+
+ OPN->eg_timer_add = (1<<EG_SH) * OPN->ST.freqbase;
+ OPN->eg_timer_overflow = ( 3 ) * (1<<EG_SH);
+
+
+ /* Timer base time */
+ OPN->ST.timer_prescaler = timer_prescaler;
+
+ /* SSG part prescaler set */
+ if( SSGpres ) (*OPN->ST.SSG->set_clock)( OPN->ST.param, OPN->ST.clock * 2 / SSGpres );
+
+ /* make time tables */
+ init_timetables( &OPN->ST, dt_tab );
+
+ /* there are 2048 FNUMs that can be generated using FNUM/BLK registers
+ but LFO works with one more bit of a precision so we really need 4096 elements */
+ /* calculate fnumber -> increment counter table */
+ for(i = 0; i < 4096; i++)
+ {
+ /* freq table for octave 7 */
+ /* OPN phase increment counter = 20bit */
+ OPN->fn_table[i] = (UINT32)( (double)i * 32 * OPN->ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
+#if 0
+ logerror("FM.C: fn_table[%4i] = %08x (dec=%8i)\n",
+ i, OPN->fn_table[i]>>6,OPN->fn_table[i]>>6 );
+#endif
+ }
+
+ /* LFO freq. table */
+ for(i = 0; i < 8; i++)
+ {
+ /* Amplitude modulation: 64 output levels (triangle waveform); 1 level lasts for one of "lfo_samples_per_step" samples */
+ /* Phase modulation: one entry from lfo_pm_output lasts for one of 4 * "lfo_samples_per_step" samples */
+ OPN->lfo_freq[i] = (1.0 / lfo_samples_per_step[i]) * (1<<LFO_SH) * OPN->ST.freqbase;
+#if 0
+ logerror("FM.C: lfo_freq[%i] = %08x (dec=%8i)\n",
+ i, OPN->lfo_freq[i],OPN->lfo_freq[i] );
+#endif
+ }
+}
+
+
+
+/* write a OPN mode register 0x20-0x2f */
+static void OPNWriteMode(FM_OPN *OPN, int r, int v)
+{
+ UINT8 c;
+ FM_CH *CH;
+
+ switch(r){
+ case 0x21: /* Test */
+ break;
+ case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/YM2612) */
+ if( OPN->type & TYPE_LFOPAN )
+ {
+ if (v&0x08) /* LFO enabled ? */
+ {
+ OPN->lfo_inc = OPN->lfo_freq[v&7];
+ }
+ else
+ {
+ OPN->lfo_inc = 0;
+ }
+ }
+ break;
+ case 0x24: /* timer A High 8*/
+ OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2);
+ break;
+ case 0x25: /* timer A Low 2*/
+ OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3);
+ break;
+ case 0x26: /* timer B */
+ OPN->ST.TB = v;
+ break;
+ case 0x27: /* mode, timer control */
+ set_timers( &(OPN->ST),OPN->ST.param,v );
+ break;
+ case 0x28: /* key on / off */
+ c = v & 0x03;
+ if( c == 3 ) break;
+ if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3;
+ CH = OPN->P_CH;
+ CH = &CH[c];
+ if(v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1);
+ if(v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2);
+ if(v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3);
+ if(v&0x80) FM_KEYON(CH,SLOT4); else FM_KEYOFF(CH,SLOT4);
+ break;
+ }
+}
+
+/* write a OPN register (0x30-0xff) */
+static void OPNWriteReg(FM_OPN *OPN, int r, int v)
+{
+ FM_CH *CH;
+ FM_SLOT *SLOT;
+
+ UINT8 c = OPN_CHAN(r);
+
+ if (c == 3) return; /* 0xX3,0xX7,0xXB,0xXF */
+
+ if (r >= 0x100) c+=3;
+
+ CH = OPN->P_CH;
+ CH = &CH[c];
+
+ SLOT = &(CH->SLOT[OPN_SLOT(r)]);
+
+ switch( r & 0xf0 ) {
+ case 0x30: /* DET , MUL */
+ set_det_mul(&OPN->ST,CH,SLOT,v);
+ break;
+
+ case 0x40: /* TL */
+ set_tl(CH,SLOT,v);
+ break;
+
+ case 0x50: /* KS, AR */
+ set_ar_ksr(CH,SLOT,v);
+ break;
+
+ case 0x60: /* bit7 = AM ENABLE, DR */
+ set_dr(SLOT,v);
+
+ if(OPN->type & TYPE_LFOPAN) /* YM2608/2610/2610B/2612 */
+ {
+ SLOT->AMmask = (v&0x80) ? ~0 : 0;
+ }
+ break;
+
+ case 0x70: /* SR */
+ set_sr(SLOT,v);
+ break;
+
+ case 0x80: /* SL, RR */
+ set_sl_rr(SLOT,v);
+ break;
+
+ case 0x90: /* SSG-EG */
+
+ SLOT->ssg = v&0x0f;
+ SLOT->ssgn = (v&0x04)>>1; /* bit 1 in ssgn = attack */
+
+ /* SSG-EG envelope shapes :
+
+ E AtAlH
+ 1 0 0 0 \\\\
+
+ 1 0 0 1 \___
+
+ 1 0 1 0 \/\/
+ ___
+ 1 0 1 1 \
+
+ 1 1 0 0 ////
+ ___
+ 1 1 0 1 /
+
+ 1 1 1 0 /\/\
+
+ 1 1 1 1 /___
+
+
+ E = SSG-EG enable
+
+
+ The shapes are generated using Attack, Decay and Sustain phases.
+
+ Each single character in the diagrams above represents this whole
+ sequence:
+
+ - when KEY-ON = 1, normal Attack phase is generated (*without* any
+ difference when compared to normal mode),
+
+ - later, when envelope level reaches minimum level (max volume),
+ the EG switches to Decay phase (which works with bigger steps
+ when compared to normal mode - see below),
+
+ - later when envelope level passes the SL level,
+ the EG swithes to Sustain phase (which works with bigger steps
+ when compared to normal mode - see below),
+
+ - finally when envelope level reaches maximum level (min volume),
+ the EG switches to Attack phase again (depends on actual waveform).
+
+ Important is that when switch to Attack phase occurs, the phase counter
+ of that operator will be zeroed-out (as in normal KEY-ON) but not always.
+ (I havent found the rule for that - perhaps only when the output level is low)
+
+ The difference (when compared to normal Envelope Generator mode) is
+ that the resolution in Decay and Sustain phases is 4 times lower;
+ this results in only 256 steps instead of normal 1024.
+ In other words:
+ when SSG-EG is disabled, the step inside of the EG is one,
+ when SSG-EG is enabled, the step is four (in Decay and Sustain phases).
+
+ Times between the level changes are the same in both modes.
+
+
+ Important:
+ Decay 1 Level (so called SL) is compared to actual SSG-EG output, so
+ it is the same in both SSG and no-SSG modes, with this exception:
+
+ when the SSG-EG is enabled and is generating raising levels
+ (when the EG output is inverted) the SL will be found at wrong level !!!
+ For example, when SL=02:
+ 0 -6 = -6dB in non-inverted EG output
+ 96-6 = -90dB in inverted EG output
+ Which means that EG compares its level to SL as usual, and that the
+ output is simply inverted afterall.
+
+
+ The Yamaha's manuals say that AR should be set to 0x1f (max speed).
+ That is not necessary, but then EG will be generating Attack phase.
+
+ */
+
+
+ break;
+
+ case 0xa0:
+ switch( OPN_SLOT(r) ){
+ case 0: /* 0xa0-0xa2 : FNUM1 */
+ {
+ UINT32 fn = (((UINT32)( (OPN->ST.fn_h)&7))<<8) + v;
+ UINT8 blk = OPN->ST.fn_h>>3;
+ /* keyscale code */
+ CH->kcode = (blk<<2) | opn_fktable[fn >> 7];
+ /* phase increment counter */
+ CH->fc = OPN->fn_table[fn*2]>>(7-blk);
+
+ /* store fnum in clear form for LFO PM calculations */
+ CH->block_fnum = (blk<<11) | fn;
+
+ CH->SLOT[SLOT1].Incr=-1;
+ }
+ break;
+ case 1: /* 0xa4-0xa6 : FNUM2,BLK */
+ OPN->ST.fn_h = v&0x3f;
+ break;
+ case 2: /* 0xa8-0xaa : 3CH FNUM1 */
+ if(r < 0x100)
+ {
+ UINT32 fn = (((UINT32)(OPN->SL3.fn_h&7))<<8) + v;
+ UINT8 blk = OPN->SL3.fn_h>>3;
+ /* keyscale code */
+ OPN->SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7];
+ /* phase increment counter */
+ OPN->SL3.fc[c] = OPN->fn_table[fn*2]>>(7-blk);
+ OPN->SL3.block_fnum[c] = fn;
+ (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1;
+ }
+ break;
+ case 3: /* 0xac-0xae : 3CH FNUM2,BLK */
+ if(r < 0x100)
+ OPN->SL3.fn_h = v&0x3f;
+ break;
+ }
+ break;
+
+ case 0xb0:
+ switch( OPN_SLOT(r) ){
+ case 0: /* 0xb0-0xb2 : FB,ALGO */
+ {
+ int feedback = (v>>3)&7;
+ CH->ALGO = v&7;
+ CH->FB = feedback ? feedback+6 : 0;
+ setup_connection( CH, c );
+ }
+ break;
+ case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2610B/YM2610/YM2608) */
+ if( OPN->type & TYPE_LFOPAN)
+ {
+ /* b0-2 PMS */
+ CH->pms = (v & 7) * 32; /* CH->pms = PM depth * 32 (index in lfo_pm_table) */
+
+ /* b4-5 AMS */
+ CH->ams = lfo_ams_depth_shift[(v>>4) & 0x03];
+
+ /* PAN : b7 = L, b6 = R */
+ OPN->pan[ c*2 ] = (v & 0x80) ? ~0 : 0;
+ OPN->pan[ c*2+1 ] = (v & 0x40) ? ~0 : 0;
+
+ }
+ break;
+ }
+ break;
+ }
+}
+
+#endif /* BUILD_OPN */
+
+#if BUILD_OPN_PRESCALER
+/*
+ prescaler circuit (best guess to verified chip behaviour)
+
+ +--------------+ +-sel2-+
+ | +--|in20 |
+ +---+ | +-sel1-+ | |
+M-CLK -+-|1/2|-+--|in10 | +---+ | out|--INT_CLOCK
+ | +---+ | out|-|1/3|-|in21 |
+ +----------|in11 | +---+ +------+
+ +------+
+
+reg.2d : sel2 = in21 (select sel2)
+reg.2e : sel1 = in11 (select sel1)
+reg.2f : sel1 = in10 , sel2 = in20 (clear selector)
+reset : sel1 = in11 , sel2 = in21 (clear both)
+
+*/
+static void OPNPrescaler_w(FM_OPN *OPN , int addr, int pre_divider)
+{
+ static const int opn_pres[4] = { 2*12 , 2*12 , 6*12 , 3*12 };
+ static const int ssg_pres[4] = { 1 , 1 , 4 , 2 };
+ int sel;
+
+ switch(addr)
+ {
+ case 0: /* when reset */
+ OPN->ST.prescaler_sel = 2;
+ break;
+ case 1: /* when postload */
+ break;
+ case 0x2d: /* divider sel : select 1/1 for 1/3line */
+ OPN->ST.prescaler_sel |= 0x02;
+ break;
+ case 0x2e: /* divider sel , select 1/3line for output */
+ OPN->ST.prescaler_sel |= 0x01;
+ break;
+ case 0x2f: /* divider sel , clear both selector to 1/2,1/2 */
+ OPN->ST.prescaler_sel = 0;
+ break;
+ }
+ sel = OPN->ST.prescaler_sel & 3;
+ /* update prescaler */
+ OPNSetPres( OPN, opn_pres[sel]*pre_divider,
+ opn_pres[sel]*pre_divider,
+ ssg_pres[sel]*pre_divider );
+}
+#endif /* BUILD_OPN_PRESCALER */
+
+#if BUILD_YM2203
+/*****************************************************************************/
+/* YM2203 local section */
+/*****************************************************************************/
+
+/* here's the virtual YM2203(OPN) */
+typedef struct
+{
+ UINT8 REGS[256]; /* registers */
+ FM_OPN OPN; /* OPN state */
+ FM_CH CH[3]; /* channel state */
+} YM2203;
+
+/* Generate samples for one of the YM2203s */
+void YM2203UpdateOne(void *chip, FMSAMPLE *buffer, int length)
+{
+ YM2203 *F2203 = chip;
+ FM_OPN *OPN = &F2203->OPN;
+ int i;
+ FMSAMPLE *buf = buffer;
+ FM_CH *cch[3];
+
+ cch[0] = &F2203->CH[0];
+ cch[1] = &F2203->CH[1];
+ cch[2] = &F2203->CH[2];
+
+
+ /* refresh PG and EG */
+ refresh_fc_eg_chan( cch[0] );
+ refresh_fc_eg_chan( cch[1] );
+ if( (F2203->OPN.ST.mode & 0xc0) )
+ {
+ /* 3SLOT MODE */
+ if( cch[2]->SLOT[SLOT1].Incr==-1)
+ {
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
+ }
+ }else refresh_fc_eg_chan( cch[2] );
+
+
+ /* YM2203 doesn't have LFO so we must keep these globals at 0 level */
+ LFO_AM = 0;
+ LFO_PM = 0;
+
+ /* buffering */
+ for (i=0; i < length ; i++)
+ {
+ /* clear outputs */
+ out_fm[0] = 0;
+ out_fm[1] = 0;
+ out_fm[2] = 0;
+
+ /* advance envelope generator */
+ OPN->eg_timer += OPN->eg_timer_add;
+ while (OPN->eg_timer >= OPN->eg_timer_overflow)
+ {
+ OPN->eg_timer -= OPN->eg_timer_overflow;
+ OPN->eg_cnt++;
+
+ advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]);
+ }
+
+ /* calculate FM */
+ chan_calc(OPN, cch[0] );
+ chan_calc(OPN, cch[1] );
+ chan_calc(OPN, cch[2] );
+
+ /* buffering */
+ {
+ int lt;
+
+ lt = out_fm[0] + out_fm[1] + out_fm[2];
+
+ lt >>= FINAL_SH;
+
+ Limit( lt , MAXOUT, MINOUT );
+
+ #ifdef SAVE_SAMPLE
+ SAVE_ALL_CHANNELS
+ #endif
+
+ /* buffering */
+ buf[i] = lt;
+ }
+
+ /* timer A control */
+ INTERNAL_TIMER_A( &F2203->OPN.ST , cch[2] )
+ }
+ INTERNAL_TIMER_B(&F2203->OPN.ST,length)
+}
+
+/* ---------- reset one of chip ---------- */
+void YM2203ResetChip(void *chip)
+{
+ int i;
+ YM2203 *F2203 = chip;
+ FM_OPN *OPN = &F2203->OPN;
+
+ /* Reset Prescaler */
+ OPNPrescaler_w(OPN, 0 , 1 );
+ /* reset SSG section */
+ (*OPN->ST.SSG->reset)(OPN->ST.param);
+ /* status clear */
+ FM_IRQMASK_SET(&OPN->ST,0x03);
+ FM_BUSY_CLEAR(&OPN->ST);
+ OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */
+
+ OPN->eg_timer = 0;
+ OPN->eg_cnt = 0;
+
+ FM_STATUS_RESET(&OPN->ST, 0xff);
+
+ reset_channels( &OPN->ST , F2203->CH , 3 );
+ /* reset OPerator paramater */
+ for(i = 0xb2 ; i >= 0x30 ; i-- ) OPNWriteReg(OPN,i,0);
+ for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
+}
+
+#ifdef __STATE_H__
+void YM2203Postload(void *chip)
+{
+ if (chip)
+ {
+ YM2203 *F2203 = (YM2203 *)chip;
+ int r;
+
+ /* prescaler */
+ OPNPrescaler_w(&F2203->OPN,1,1);
+
+ /* SSG registers */
+ for(r=0;r<16;r++)
+ {
+ (*F2203->OPN.ST.SSG->write)(F2203->OPN.ST.param,0,r);
+ (*F2203->OPN.ST.SSG->write)(F2203->OPN.ST.param,1,F2203->REGS[r]);
+ }
+
+ /* OPN registers */
+ /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */
+ for(r=0x30;r<0x9e;r++)
+ if((r&3) != 3)
+ OPNWriteReg(&F2203->OPN,r,F2203->REGS[r]);
+ /* FB / CONNECT , L / R / AMS / PMS */
+ for(r=0xb0;r<0xb6;r++)
+ if((r&3) != 3)
+ OPNWriteReg(&F2203->OPN,r,F2203->REGS[r]);
+
+ /* channels */
+ /*FM_channel_postload(F2203->CH,3);*/
+ }
+}
+
+static void YM2203_save_state(YM2203 *F2203, int index)
+{
+ static const char statename[] = "YM2203";
+
+ state_save_register_item_array(statename, index, F2203->REGS);
+ FMsave_state_st(statename,index,&F2203->OPN.ST);
+ FMsave_state_channel(statename,index,F2203->CH,3);
+ /* 3slots */
+ state_save_register_item_array (statename, index, F2203->OPN.SL3.fc);
+ state_save_register_item (statename, index, F2203->OPN.SL3.fn_h);
+ state_save_register_item_array (statename, index, F2203->OPN.SL3.kcode);
+}
+#endif /* _STATE_H */
+
+/* ---------- Initialize YM2203 emulator(s) ----------
+ 'num' is the number of virtual YM2203s to allocate
+ 'clock' is the chip clock in Hz
+ 'rate' is sampling rate
+*/
+void * YM2203Init(void *param, int index, int clock, int rate,
+ FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler, const struct ssg_callbacks *ssg)
+{
+ YM2203 *F2203;
+
+ /* allocate ym2203 state space */
+ if( (F2203 = (YM2203 *)malloc(sizeof(YM2203)))==NULL)
+ return NULL;
+ /* clear */
+ memset(F2203,0,sizeof(YM2203));
+
+ if( !init_tables() )
+ {
+ free( F2203 );
+ return NULL;
+ }
+
+ F2203->OPN.ST.param = param;
+ F2203->OPN.type = TYPE_YM2203;
+ F2203->OPN.P_CH = F2203->CH;
+ F2203->OPN.ST.clock = clock;
+ F2203->OPN.ST.rate = rate;
+
+ F2203->OPN.ST.timer_handler = timer_handler;
+ F2203->OPN.ST.IRQ_Handler = IRQHandler;
+ F2203->OPN.ST.SSG = ssg;
+ YM2203ResetChip(F2203);
+
+#ifdef __STATE_H__
+ YM2203_save_state(F2203, index);
+#endif
+ return F2203;
+}
+
+/* shut down emulator */
+void YM2203Shutdown(void *chip)
+{
+ YM2203 *FM2203 = chip;
+
+ FMCloseTable();
+ free(FM2203);
+}
+
+/* YM2203 I/O interface */
+int YM2203Write(void *chip,int a,UINT8 v)
+{
+ YM2203 *F2203 = chip;
+ FM_OPN *OPN = &F2203->OPN;
+
+ if( !(a&1) )
+ { /* address port */
+ OPN->ST.address = (v &= 0xff);
+
+ /* Write register to SSG emulator */
+ if( v < 16 ) (*OPN->ST.SSG->write)(OPN->ST.param,0,v);
+
+ /* prescaler select : 2d,2e,2f */
+ if( v >= 0x2d && v <= 0x2f )
+ OPNPrescaler_w(OPN , v , 1);
+ }
+ else
+ { /* data port */
+ int addr = OPN->ST.address;
+ F2203->REGS[addr] = v;
+ switch( addr & 0xf0 )
+ {
+ case 0x00: /* 0x00-0x0f : SSG section */
+ /* Write data to SSG emulator */
+ (*OPN->ST.SSG->write)(OPN->ST.param,a,v);
+ break;
+ case 0x20: /* 0x20-0x2f : Mode section */
+ YM2203UpdateReq(OPN->ST.param);
+ /* write register */
+ OPNWriteMode(OPN,addr,v);
+ break;
+ default: /* 0x30-0xff : OPN section */
+ YM2203UpdateReq(OPN->ST.param);
+ /* write register */
+ OPNWriteReg(OPN,addr,v);
+ }
+ FM_BUSY_SET(&OPN->ST,1);
+ }
+ return OPN->ST.irq;
+}
+
+UINT8 YM2203Read(void *chip,int a)
+{
+ YM2203 *F2203 = chip;
+ int addr = F2203->OPN.ST.address;
+ UINT8 ret = 0;
+
+ if( !(a&1) )
+ { /* status port */
+ ret = FM_STATUS_FLAG(&F2203->OPN.ST);
+ }
+ else
+ { /* data port (only SSG) */
+ if( addr < 16 ) ret = (*F2203->OPN.ST.SSG->read)(F2203->OPN.ST.param);
+ }
+ return ret;
+}
+
+int YM2203TimerOver(void *chip,int c)
+{
+ YM2203 *F2203 = chip;
+
+ if( c )
+ { /* Timer B */
+ TimerBOver( &(F2203->OPN.ST) );
+ }
+ else
+ { /* Timer A */
+ YM2203UpdateReq(F2203->OPN.ST.param);
+ /* timer update */
+ TimerAOver( &(F2203->OPN.ST) );
+ /* CSM mode key,TL control */
+ if( F2203->OPN.ST.mode & 0x80 )
+ { /* CSM mode auto key on */
+ CSMKeyControll( &(F2203->CH[2]) );
+ }
+ }
+ return F2203->OPN.ST.irq;
+}
+#endif /* BUILD_YM2203 */
+
+
+
+#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B)
+
+/* ADPCM type A channel struct */
+typedef struct
+{
+ UINT8 flag; /* port state */
+ UINT8 flagMask; /* arrived flag mask */
+ UINT8 now_data; /* current ROM data */
+ UINT32 now_addr; /* current ROM address */
+ UINT32 now_step;
+ UINT32 step;
+ UINT32 start; /* sample data start address*/
+ UINT32 end; /* sample data end address */
+ UINT8 IL; /* Instrument Level */
+ INT32 adpcm_acc; /* accumulator */
+ INT32 adpcm_step; /* step */
+ INT32 adpcm_out; /* (speedup) hiro-shi!! */
+ INT8 vol_mul; /* volume in "0.75dB" steps */
+ UINT8 vol_shift; /* volume in "-6dB" steps */
+ INT32 *pan; /* &out_adpcm[OPN_xxxx] */
+} ADPCM_CH;
+
+/* here's the virtual YM2610 */
+typedef struct
+{
+ UINT8 REGS[512]; /* registers */
+ FM_OPN OPN; /* OPN state */
+ FM_CH CH[6]; /* channel state */
+ UINT8 addr_A1; /* address line A1 */
+
+ /* ADPCM-A unit */
+ UINT8 *pcmbuf; /* pcm rom buffer */
+ UINT32 pcm_size; /* size of pcm rom */
+ UINT8 adpcmTL; /* adpcmA total level */
+ ADPCM_CH adpcm[6]; /* adpcm channels */
+ UINT32 adpcmreg[0x30]; /* registers */
+ UINT8 adpcm_arrivedEndAddress;
+ YM_DELTAT deltaT; /* Delta-T ADPCM unit */
+
+ UINT8 flagmask; /* YM2608 only */
+ UINT8 irqmask; /* YM2608 only */
+} YM2610;
+
+/* here is the virtual YM2608 */
+typedef YM2610 YM2608;
+
+
+/**** YM2610 ADPCM defines ****/
+#define ADPCM_SHIFT (16) /* frequency step rate */
+#define ADPCMA_ADDRESS_SHIFT 8 /* adpcm A address shift */
+
+static UINT8 *pcmbufA;
+static UINT32 pcmsizeA;
+
+
+/* Algorithm and tables verified on real YM2608 and YM2610 */
+
+/* usual ADPCM table (16 * 1.1^N) */
+static int steps[49] =
+{
+ 16, 17, 19, 21, 23, 25, 28,
+ 31, 34, 37, 41, 45, 50, 55,
+ 60, 66, 73, 80, 88, 97, 107,
+ 118, 130, 143, 157, 173, 190, 209,
+ 230, 253, 279, 307, 337, 371, 408,
+ 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552
+};
+
+/* different from the usual ADPCM table */
+static int step_inc[8] = { -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16 };
+
+/* speedup purposes only */
+static int jedi_table[ 49*16 ];
+
+
+static void Init_ADPCMATable(void){
+
+ int step, nib;
+
+ for (step = 0; step < 49; step++)
+ {
+ /* loop over all nibbles and compute the difference */
+ for (nib = 0; nib < 16; nib++)
+ {
+ int value = (2*(nib & 0x07) + 1) * steps[step] / 8;
+ jedi_table[step*16 + nib] = (nib&0x08) ? -value : value;
+ }
+ }
+}
+
+/* ADPCM A (Non control type) : calculate one channel output */
+INLINE void ADPCMA_calc_chan( YM2610 *F2610, ADPCM_CH *ch )
+{
+ UINT32 step;
+ UINT8 data;
+
+
+ ch->now_step += ch->step;
+ if ( ch->now_step >= (1<<ADPCM_SHIFT) )
+ {
+ step = ch->now_step >> ADPCM_SHIFT;
+ ch->now_step &= (1<<ADPCM_SHIFT)-1;
+ do{
+ /* end check */
+ /* 11-06-2001 JB: corrected comparison. Was > instead of == */
+ /* YM2610 checks lower 20 bits only, the 4 MSB bits are sample bank */
+ /* Here we use 1<<21 to compensate for nibble calculations */
+
+ if ( (ch->now_addr & ((1<<21)-1)) == ((ch->end<<1) & ((1<<21)-1)) )
+ {
+ ch->flag = 0;
+ F2610->adpcm_arrivedEndAddress |= ch->flagMask;
+ return;
+ }
+#if 0
+ if ( ch->now_addr > (pcmsizeA<<1) ) {
+ LOG(LOG_WAR,("YM2610: Attempting to play past adpcm rom size!\n" ));
+ return;
+ }
+#endif
+ if ( ch->now_addr&1 )
+ data = ch->now_data & 0x0f;
+ else
+ {
+ ch->now_data = *(pcmbufA+(ch->now_addr>>1));
+ data = (ch->now_data >> 4) & 0x0f;
+ }
+
+ ch->now_addr++;
+
+ ch->adpcm_acc += jedi_table[ch->adpcm_step + data];
+
+ /* extend 12-bit signed int */
+ if (ch->adpcm_acc & ~0x7ff)
+ ch->adpcm_acc |= ~0xfff;
+ else
+ ch->adpcm_acc &= 0xfff;
+
+ ch->adpcm_step += step_inc[data & 7];
+ Limit( ch->adpcm_step, 48*16, 0*16 );
+
+ }while(--step);
+
+ /* calc pcm * volume data */
+ ch->adpcm_out = ((ch->adpcm_acc * ch->vol_mul) >> ch->vol_shift) & ~3; /* multiply, shift and mask out 2 LSB bits */
+ }
+
+ /* output for work of output channels (out_adpcm[OPNxxxx])*/
+ *(ch->pan) += ch->adpcm_out;
+}
+
+/* ADPCM type A Write */
+static void FM_ADPCMAWrite(YM2610 *F2610,int r,int v)
+{
+ ADPCM_CH *adpcm = F2610->adpcm;
+ UINT8 c = r&0x07;
+
+ F2610->adpcmreg[r] = v&0xff; /* stock data */
+ switch( r ){
+ case 0x00: /* DM,--,C5,C4,C3,C2,C1,C0 */
+ if( !(v&0x80) )
+ {
+ /* KEY ON */
+ for( c = 0; c < 6; c++ )
+ {
+ if( (v>>c)&1 )
+ {
+ /**** start adpcm ****/
+ adpcm[c].step = (UINT32)((float)(1<<ADPCM_SHIFT)*((float)F2610->OPN.ST.freqbase)/3.0);
+ adpcm[c].now_addr = adpcm[c].start<<1;
+ adpcm[c].now_step = 0;
+ adpcm[c].adpcm_acc = 0;
+ adpcm[c].adpcm_step= 0;
+ adpcm[c].adpcm_out = 0;
+ adpcm[c].flag = 1;
+
+ if(F2610->pcmbuf==NULL){ /* Check ROM Mapped */
+ logerror("YM2608-YM2610: ADPCM-A rom not mapped\n");
+ adpcm[c].flag = 0;
+ } else{
+ if(adpcm[c].end >= F2610->pcm_size){ /* Check End in Range */
+ logerror("YM2610: ADPCM-A end out of range: $%08x\n",adpcm[c].end);
+ /*adpcm[c].end = F2610->pcm_size-1;*/ /* JB: DO NOT uncomment this, otherwise you will break the comparison in the ADPCM_CALC_CHA() */
+ }
+ if(adpcm[c].start >= F2610->pcm_size) /* Check Start in Range */
+ {
+ logerror("YM2608-YM2610: ADPCM-A start out of range: $%08x\n",adpcm[c].start);
+ adpcm[c].flag = 0;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* KEY OFF */
+ for( c = 0; c < 6; c++ )
+ if( (v>>c)&1 )
+ adpcm[c].flag = 0;
+ }
+ break;
+ case 0x01: /* B0-5 = TL */
+ F2610->adpcmTL = (v & 0x3f) ^ 0x3f;
+ for( c = 0; c < 6; c++ )
+ {
+ int volume = F2610->adpcmTL + adpcm[c].IL;
+
+ if ( volume >= 63 ) /* This is correct, 63 = quiet */
+ {
+ adpcm[c].vol_mul = 0;
+ adpcm[c].vol_shift = 0;
+ }
+ else
+ {
+ adpcm[c].vol_mul = 15 - (volume & 7); /* so called 0.75 dB */
+ adpcm[c].vol_shift = 1 + (volume >> 3); /* Yamaha engineers used the approximation: each -6 dB is close to divide by two (shift right) */
+ }
+
+ /* calc pcm * volume data */
+ adpcm[c].adpcm_out = ((adpcm[c].adpcm_acc * adpcm[c].vol_mul) >> adpcm[c].vol_shift) & ~3; /* multiply, shift and mask out low 2 bits */
+ }
+ break;
+ default:
+ c = r&0x07;
+ if( c >= 0x06 ) return;
+ switch( r&0x38 ){
+ case 0x08: /* B7=L,B6=R, B4-0=IL */
+ {
+ int volume;
+
+ adpcm[c].IL = (v & 0x1f) ^ 0x1f;
+
+ volume = F2610->adpcmTL + adpcm[c].IL;
+
+ if ( volume >= 63 ) /* This is correct, 63 = quiet */
+ {
+ adpcm[c].vol_mul = 0;
+ adpcm[c].vol_shift = 0;
+ }
+ else
+ {
+ adpcm[c].vol_mul = 15 - (volume & 7); /* so called 0.75 dB */
+ adpcm[c].vol_shift = 1 + (volume >> 3); /* Yamaha engineers used the approximation: each -6 dB is close to divide by two (shift right) */
+ }
+
+ adpcm[c].pan = &out_adpcm[(v>>6)&0x03];
+
+ /* calc pcm * volume data */
+ adpcm[c].adpcm_out = ((adpcm[c].adpcm_acc * adpcm[c].vol_mul) >> adpcm[c].vol_shift) & ~3; /* multiply, shift and mask out low 2 bits */
+ }
+ break;
+ case 0x10:
+ case 0x18:
+ adpcm[c].start = ( (F2610->adpcmreg[0x18 + c]*0x0100 | F2610->adpcmreg[0x10 + c]) << ADPCMA_ADDRESS_SHIFT);
+ break;
+ case 0x20:
+ case 0x28:
+ adpcm[c].end = ( (F2610->adpcmreg[0x28 + c]*0x0100 | F2610->adpcmreg[0x20 + c]) << ADPCMA_ADDRESS_SHIFT);
+ adpcm[c].end += (1<<ADPCMA_ADDRESS_SHIFT) - 1;
+ break;
+ }
+ }
+}
+
+#ifdef __STATE_H__
+/* FM channel save , internal state only */
+static void FMsave_state_adpcma(const char *name,int num,ADPCM_CH *adpcm)
+{
+ int ch;
+ char state_name[20];
+
+ for(ch=0;ch<6;ch++,adpcm++)
+ {
+ sprintf(state_name,"%s.CH%d",name,ch);
+
+ state_save_register_item(state_name, num, adpcm->flag);
+ state_save_register_item(state_name, num, adpcm->now_data);
+ state_save_register_item(state_name, num, adpcm->now_addr);
+ state_save_register_item(state_name, num, adpcm->now_step);
+ state_save_register_item(state_name, num, adpcm->adpcm_acc);
+ state_save_register_item(state_name, num, adpcm->adpcm_step);
+ state_save_register_item(state_name, num, adpcm->adpcm_out);
+ }
+}
+#endif /* _STATE_H */
+
+#endif /* (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) */
+
+
+#if BUILD_YM2608
+/*****************************************************************************/
+/* YM2608 local section */
+/*****************************************************************************/
+
+
+
+static unsigned int YM2608_ADPCM_ROM_addr[2*6] = {
+0x0000, 0x01bf, /* bass drum */
+0x01c0, 0x043f, /* snare drum */
+0x0440, 0x1b7f, /* top cymbal */
+0x1b80, 0x1cff, /* high hat */
+0x1d00, 0x1f7f, /* tom tom */
+0x1f80, 0x1fff /* rim shot */
+};
+
+
+/*
+ This data is derived from the chip's output - internal ROM can't be read.
+ It was verified, using real YM2608, that this ADPCM stream produces 100% correct output signal.
+*/
+
+static unsigned char YM2608_ADPCM_ROM[0x2000] = {
+
+/* Source: 01BD.ROM */
+/* Length: 448 / 0x000001C0 */
+
+0x88,0x08,0x08,0x08,0x00,0x88,0x16,0x76,0x99,0xB8,0x22,0x3A,0x84,0x3C,0xB1,0x54,
+0x10,0xA9,0x98,0x32,0x80,0x33,0x9A,0xA7,0x4A,0xB4,0x58,0xBC,0x15,0x29,0x8A,0x97,
+0x9B,0x44,0xAC,0x80,0x12,0xDE,0x13,0x1B,0xC0,0x58,0xC8,0x11,0x0A,0xA2,0x1A,0xA0,
+0x00,0x98,0x0B,0x93,0x9E,0x92,0x0A,0x88,0xBE,0x14,0x1B,0x98,0x08,0xA1,0x4A,0xC1,
+0x30,0xD9,0x33,0x98,0x10,0x89,0x17,0x1A,0x82,0x29,0x37,0x0C,0x83,0x50,0x9A,0x24,
+0x1A,0x83,0x10,0x23,0x19,0xB3,0x72,0x8A,0x16,0x10,0x0A,0x93,0x70,0x99,0x23,0x99,
+0x02,0x20,0x91,0x18,0x02,0x41,0xAB,0x24,0x18,0x81,0x99,0x4A,0xE8,0x28,0x9A,0x99,
+0xA1,0x2F,0xA8,0x9D,0x90,0x08,0xCC,0xA3,0x1D,0xCA,0x82,0x0B,0xD8,0x08,0xB9,0x09,
+0xBC,0xB8,0x00,0xBE,0x90,0x1B,0xCA,0x00,0x9B,0x8A,0xA8,0x91,0x0F,0xB3,0x3D,0xB8,
+0x31,0x0B,0xA5,0x0A,0x11,0xA1,0x48,0x92,0x10,0x50,0x91,0x30,0x23,0x09,0x37,0x39,
+0xA2,0x72,0x89,0x92,0x30,0x83,0x1C,0x96,0x28,0xB9,0x24,0x8C,0xA1,0x31,0xAD,0xA9,
+0x13,0x9C,0xBA,0xA8,0x0B,0xBF,0xB8,0x9B,0xCA,0x88,0xDB,0xB8,0x19,0xFC,0x92,0x0A,
+0xBA,0x89,0xAB,0xB8,0xAB,0xD8,0x08,0xAD,0xBA,0x33,0x9D,0xAA,0x83,0x3A,0xC0,0x40,
+0xB9,0x15,0x39,0xA2,0x52,0x89,0x02,0x63,0x88,0x13,0x23,0x03,0x52,0x02,0x54,0x00,
+0x11,0x23,0x23,0x35,0x20,0x01,0x44,0x41,0x80,0x24,0x40,0xA9,0x45,0x19,0x81,0x12,
+0x81,0x02,0x11,0x21,0x19,0x02,0x61,0x8A,0x13,0x3A,0x10,0x12,0x23,0x8B,0x37,0x18,
+0x91,0x24,0x10,0x81,0x34,0x20,0x05,0x32,0x82,0x53,0x20,0x14,0x33,0x31,0x34,0x52,
+0x00,0x43,0x32,0x13,0x52,0x22,0x13,0x52,0x11,0x43,0x11,0x32,0x32,0x32,0x22,0x02,
+0x13,0x12,0x89,0x22,0x19,0x81,0x81,0x08,0xA8,0x08,0x8B,0x90,0x1B,0xBA,0x8A,0x9B,
+0xB9,0x89,0xCA,0xB9,0xAB,0xCA,0x9B,0xCA,0xB9,0xAB,0xDA,0x99,0xAC,0xBB,0x9B,0xAC,
+0xAA,0xBA,0xAC,0xAB,0x9A,0xAA,0xAA,0xBA,0xB8,0xA9,0xBA,0x99,0xA9,0x9A,0xA0,0x8A,
+0xA9,0x08,0x8A,0xA9,0x00,0x99,0x89,0x88,0x98,0x08,0x99,0x00,0x89,0x80,0x08,0x98,
+0x00,0x88,0x88,0x80,0x90,0x80,0x90,0x80,0x81,0x99,0x08,0x88,0x99,0x09,0x00,0x1A,
+0xA8,0x10,0x9A,0x88,0x08,0x0A,0x8A,0x89,0x99,0xA8,0x98,0xA9,0x99,0x99,0xA9,0x99,
+0xAA,0x8A,0xAA,0x9B,0x8A,0x9A,0xA9,0x9A,0xBA,0x99,0x9A,0xAA,0x99,0x89,0xA9,0x99,
+0x98,0x9A,0x98,0x88,0x09,0x89,0x09,0x08,0x08,0x09,0x18,0x18,0x00,0x12,0x00,0x11,
+0x11,0x11,0x12,0x12,0x21,0x21,0x22,0x22,0x22,0x22,0x22,0x22,0x32,0x31,0x32,0x31,
+0x32,0x32,0x21,0x31,0x21,0x32,0x21,0x12,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+
+/* Source: 02SD.ROM */
+/* Length: 640 / 0x00000280 */
+
+0x0A,0xDC,0x14,0x0B,0xBA,0xBC,0x01,0x0F,0xF5,0x2F,0x87,0x19,0xC9,0x24,0x1B,0xA1,
+0x31,0x99,0x90,0x32,0x32,0xFE,0x83,0x48,0xA8,0xA9,0x23,0x19,0xBC,0x91,0x02,0x41,
+0xDE,0x81,0x28,0xA8,0x0A,0xB1,0x72,0xDA,0x23,0xBC,0x04,0x19,0xB8,0x21,0x8A,0x03,
+0x29,0xBA,0x14,0x21,0x0B,0xC0,0x43,0x08,0x91,0x50,0x93,0x0F,0x86,0x1A,0x91,0x18,
+0x21,0xCB,0x27,0x0A,0xA1,0x42,0x8C,0xA9,0x21,0x10,0x08,0xAB,0x94,0x2A,0xDA,0x02,
+0x8B,0x91,0x09,0x98,0xAE,0x80,0xA9,0x02,0x0A,0xE9,0x21,0xBB,0x15,0x20,0xBE,0x92,
+0x42,0x09,0xA9,0x11,0x34,0x08,0x12,0x0A,0x27,0x29,0xA1,0x52,0x12,0x8E,0x92,0x28,
+0x92,0x2B,0xD1,0x23,0xBF,0x81,0x10,0x99,0xA8,0x0A,0xC4,0x3B,0xB9,0xB0,0x00,0x62,
+0xCF,0x92,0x29,0x92,0x2B,0xB1,0x1C,0xB2,0x72,0xAA,0x88,0x11,0x18,0x80,0x13,0x9E,
+0x03,0x18,0xB0,0x60,0xA1,0x28,0x88,0x08,0x04,0x10,0x8F,0x96,0x19,0x90,0x01,0x09,
+0xC8,0x50,0x91,0x8A,0x01,0xAB,0x03,0x50,0xBA,0x9D,0x93,0x68,0xBA,0x80,0x22,0xCB,
+0x41,0xBC,0x92,0x60,0xB9,0x1A,0x95,0x4A,0xC8,0x20,0x88,0x33,0xAC,0x92,0x38,0x83,
+0x09,0x80,0x16,0x09,0x29,0xD0,0x54,0x8C,0xA2,0x28,0x91,0x89,0x93,0x60,0xCD,0x85,
+0x1B,0xA1,0x49,0x90,0x8A,0x80,0x34,0x0C,0xC9,0x14,0x19,0x98,0xA0,0x40,0xA9,0x21,
+0xD9,0x34,0x0A,0xA9,0x10,0x23,0xCB,0x25,0xAA,0x25,0x9B,0x13,0xCD,0x16,0x09,0xA0,
+0x80,0x01,0x19,0x90,0x88,0x21,0xAC,0x33,0x8B,0xD8,0x27,0x3B,0xB8,0x81,0x31,0x80,
+0xAF,0x97,0x0A,0x82,0x0A,0xA0,0x21,0x89,0x8A,0xA2,0x32,0x8D,0xBB,0x87,0x19,0x21,
+0xC9,0xBC,0x45,0x09,0x90,0x09,0xA1,0x24,0x1A,0xD0,0x10,0x08,0x11,0xA9,0x21,0xE8,
+0x60,0xA9,0x14,0x0C,0xD1,0x32,0xAB,0x04,0x0C,0x81,0x90,0x29,0x83,0x9B,0x01,0x8F,
+0x97,0x0B,0x82,0x18,0x88,0xBA,0x06,0x39,0xC8,0x23,0xBC,0x04,0x09,0x92,0x08,0x1A,
+0xBB,0x74,0x8C,0x81,0x18,0x81,0x9D,0x83,0x41,0xCD,0x81,0x40,0x9A,0x90,0x10,0x12,
+0x9C,0xA1,0x68,0xD8,0x33,0x9C,0x91,0x01,0x12,0xBE,0x02,0x09,0x12,0x99,0x9A,0x36,
+0x0A,0xB0,0x30,0x88,0xA3,0x2D,0x12,0xBC,0x03,0x3A,0x11,0xBD,0x08,0xC8,0x62,0x80,
+0x8B,0xD8,0x23,0x38,0xF9,0x12,0x08,0x99,0x91,0x21,0x99,0x85,0x2F,0xB2,0x30,0x90,
+0x88,0xD9,0x53,0xAC,0x82,0x19,0x91,0x20,0xCC,0x96,0x29,0xC9,0x24,0x89,0x80,0x99,
+0x12,0x08,0x18,0x88,0x99,0x23,0xAB,0x73,0xCB,0x33,0x9F,0x04,0x2B,0xB1,0x08,0x03,
+0x1B,0xC9,0x21,0x32,0xFA,0x33,0xDB,0x02,0x33,0xAE,0xB9,0x54,0x8B,0xA1,0x20,0x89,
+0x90,0x11,0x88,0x09,0x98,0x23,0xBE,0x37,0x8D,0x81,0x20,0xAA,0x34,0xBB,0x13,0x18,
+0xB9,0x40,0xB1,0x18,0x83,0x8E,0xB2,0x72,0xBC,0x82,0x30,0xA9,0x9A,0x24,0x8B,0x27,
+0x0E,0x91,0x20,0x90,0x08,0xB0,0x32,0xB9,0x21,0xB0,0xAC,0x45,0x9A,0xA1,0x50,0xA9,
+0x80,0x0A,0x26,0x9B,0x11,0xBB,0x23,0x71,0xCB,0x12,0x10,0xB8,0x40,0xA9,0xA5,0x39,
+0xC0,0x30,0xB2,0x20,0xAA,0xBA,0x76,0x1C,0xC1,0x48,0x98,0x80,0x18,0x81,0xAA,0x23,
+0x9C,0xA2,0x32,0xAC,0x9A,0x43,0x9C,0x12,0xAD,0x82,0x72,0xBC,0x00,0x82,0x39,0xD1,
+0x3A,0xB8,0x35,0x9B,0x10,0x40,0xF9,0x22,0x0A,0xC0,0x51,0xB9,0x82,0x18,0x98,0xA3,
+0x79,0xD0,0x20,0x88,0x09,0x01,0x99,0x82,0x11,0x38,0xFC,0x33,0x09,0xC8,0x40,0xA9,
+0x11,0x29,0xAA,0x94,0x3A,0xC2,0x4A,0xC0,0x89,0x52,0xBC,0x11,0x08,0x09,0xB8,0x71,
+0xA9,0x08,0xA8,0x62,0x8D,0x92,0x10,0x00,0x9E,0x94,0x38,0xBA,0x13,0x88,0x90,0x4A,
+0xE2,0x30,0xBA,0x02,0x00,0x19,0xD9,0x62,0xBB,0x04,0x0B,0xA3,0x68,0xB9,0x21,0x88,
+0x9D,0x04,0x10,0x8C,0xC8,0x62,0x99,0xAA,0x24,0x1A,0x80,0x9A,0x14,0x9B,0x26,0x8C,
+0x92,0x30,0xB9,0x09,0xA3,0x71,0xBB,0x10,0x19,0x82,0x39,0xDB,0x02,0x44,0x9F,0x10,
+
+/* Source: 04TOP.ROM */
+/* Length: 5952 / 0x00001740 */
+
+0x07,0xFF,0x7C,0x3C,0x31,0xC6,0xC4,0xBB,0x7F,0x7F,0x7B,0x82,0x8A,0x4D,0x5F,0x7C,
+0x3E,0x44,0xD2,0xB3,0xA0,0x19,0x1B,0x6C,0x81,0x28,0xC4,0xA1,0x1C,0x4B,0x18,0x00,
+0x2A,0xA2,0x0A,0x7C,0x2A,0x00,0x01,0x89,0x98,0x48,0x8A,0x3C,0x28,0x2A,0x5B,0x3E,
+0x3A,0x1A,0x3B,0x3D,0x4B,0x3B,0x4A,0x08,0x2A,0x1A,0x2C,0x4A,0x3B,0x82,0x99,0x3C,
+0x5D,0x29,0x2B,0x39,0x0B,0x23,0xAB,0x1A,0x4C,0x79,0xA3,0x01,0xC1,0x2A,0x0A,0x38,
+0xA7,0xB9,0x12,0x1F,0x29,0x08,0x82,0xA1,0x08,0xA9,0x42,0xAA,0x95,0xB3,0x90,0x81,
+0x09,0xD4,0x1A,0x80,0x1B,0x07,0xB8,0x12,0x8E,0x49,0x81,0x92,0xD3,0x90,0xA1,0x2A,
+0x02,0xE1,0xA3,0x99,0x02,0xB3,0x94,0xB3,0xB0,0xF4,0x98,0x93,0x90,0x13,0xE1,0x81,
+0x99,0x38,0x91,0xA6,0xD3,0x99,0x94,0xC1,0x83,0xB1,0x92,0x98,0x49,0xC4,0xB2,0xA4,
+0xA3,0xD0,0x1A,0x30,0xBA,0x59,0x02,0xD4,0xA0,0xA4,0xA2,0x8A,0x01,0x00,0xB7,0xA8,
+0x18,0x2A,0x2B,0x1E,0x23,0xC8,0x1A,0x00,0x39,0xA0,0x18,0x92,0x4F,0x2D,0x5A,0x10,
+0x89,0x81,0x2A,0x8B,0x6A,0x02,0x09,0xB3,0x8D,0x48,0x1B,0x80,0x19,0x34,0xF8,0x29,
+0x0A,0x7B,0x2A,0x28,0x81,0x0C,0x02,0x1E,0x29,0x09,0x12,0xC2,0x94,0xE1,0x18,0x98,
+0x02,0xC4,0x89,0x91,0x1A,0x20,0xA9,0x02,0x1B,0x48,0x8E,0x20,0x88,0x2D,0x08,0x59,
+0x1B,0x02,0xA3,0xB1,0x8A,0x1E,0x58,0x80,0xC2,0xB6,0x88,0x91,0x88,0x11,0xA1,0xA3,
+0xE2,0x01,0xB0,0x19,0x11,0x09,0xF4,0x88,0x09,0x88,0x19,0x89,0x12,0xF1,0x2A,0x28,
+0x8C,0x25,0x99,0xA4,0x98,0x39,0xA1,0x00,0xD0,0x58,0xAA,0x59,0x01,0x0C,0x00,0x2B,
+0x00,0x08,0x89,0x6B,0x69,0x90,0x01,0x90,0x98,0x12,0xB3,0xF3,0xA0,0x89,0x02,0x3B,
+0x0C,0x50,0xA9,0x4E,0x6B,0x19,0x28,0x09,0xA2,0x08,0x2F,0x20,0x88,0x92,0x8A,0x11,
+0xC4,0x93,0xF1,0x18,0x88,0x11,0xF2,0x80,0x92,0xA8,0x02,0xA8,0xB7,0xB3,0xA3,0xA0,
+0x88,0x1A,0x40,0xE2,0x91,0x19,0x88,0x18,0x91,0x83,0xC1,0xB5,0x92,0xA9,0xC6,0x90,
+0x01,0xC2,0x81,0x98,0x03,0xF0,0x00,0x2C,0x2A,0x92,0x2C,0x83,0x1F,0x3A,0x29,0x00,
+0xB8,0x70,0xAB,0x69,0x18,0x89,0x10,0x0D,0x12,0x0B,0x88,0x4A,0x3A,0x9B,0x70,0xA8,
+0x28,0x2F,0x2A,0x3A,0x1B,0x85,0x88,0x8B,0x6A,0x29,0x00,0x91,0x91,0x1B,0x7C,0x29,
+0x01,0x88,0x90,0x19,0x2B,0x2B,0x00,0x39,0xA8,0x5E,0x21,0x89,0x91,0x09,0x3A,0x6F,
+0x2A,0x18,0x18,0x8B,0x50,0x89,0x2B,0x19,0x49,0x88,0x29,0xF5,0x89,0x08,0x09,0x12,
+0xAA,0x15,0xB0,0x82,0xAC,0x38,0x00,0x3F,0x81,0x10,0xB0,0x49,0xA2,0x81,0x3A,0xC8,
+0x87,0x90,0xC4,0xA3,0x99,0x19,0x83,0xE1,0x84,0xE2,0xA2,0x90,0x80,0x93,0xB5,0xC4,
+0xB3,0xA1,0x0A,0x18,0x92,0xC4,0xA0,0x93,0x0C,0x3A,0x18,0x01,0x1E,0x20,0xB1,0x82,
+0x8C,0x03,0xB5,0x2E,0x82,0x19,0xB2,0x1B,0x1B,0x6B,0x4C,0x19,0x12,0x8B,0x5A,0x11,
+0x0C,0x3A,0x2C,0x18,0x3D,0x08,0x2A,0x5C,0x18,0x00,0x88,0x3D,0x29,0x80,0x2A,0x09,
+0x00,0x7A,0x0A,0x10,0x0B,0x69,0x98,0x10,0x81,0x3F,0x00,0x18,0x19,0x91,0xB7,0x9A,
+0x28,0x8A,0x48,0x92,0xF3,0xA2,0x88,0x98,0x87,0xA1,0x88,0x80,0x81,0x95,0xD1,0xA3,
+0x1B,0x1C,0x39,0x10,0xA1,0x2A,0x0B,0x7A,0x4B,0x80,0x13,0xC1,0xD1,0x2B,0x2A,0x85,
+0xB2,0xA2,0x93,0xB2,0xD3,0x80,0xD1,0x18,0x08,0x08,0xB7,0x98,0x81,0x3F,0x01,0x88,
+0x01,0xE2,0x00,0x9A,0x59,0x08,0x10,0xC3,0x99,0x84,0xA9,0xA5,0x91,0x91,0x91,0x80,
+0xB5,0x94,0xC0,0x01,0x98,0x09,0x84,0xB0,0x80,0x7A,0x08,0x18,0x90,0xA8,0x6A,0x1C,
+0x39,0x2A,0xB7,0x98,0x19,0x10,0x2A,0xA1,0x10,0xBD,0x39,0x18,0x2D,0x39,0x3F,0x10,
+0x3F,0x01,0x09,0x19,0x0A,0x38,0x8C,0x40,0xB3,0xB4,0x93,0xAD,0x20,0x2B,0xD4,0x81,
+0xC3,0xB0,0x39,0xA0,0x23,0xD8,0x04,0xB1,0x9B,0xA7,0x1A,0x92,0x08,0xA5,0x88,0x81,
+0xE2,0x01,0xB8,0x01,0x81,0xC1,0xC7,0x90,0x92,0x80,0xA1,0x97,0xA0,0xA2,0x82,0xB8,
+0x18,0x00,0x9C,0x78,0x98,0x83,0x0B,0x0B,0x32,0x7D,0x19,0x10,0xA1,0x19,0x09,0x0A,
+0x78,0xA8,0x10,0x1B,0x29,0x29,0x1A,0x14,0x2F,0x88,0x4A,0x1B,0x10,0x10,0xAB,0x79,
+0x0D,0x49,0x18,0xA0,0x02,0x1F,0x19,0x3A,0x2B,0x11,0x8A,0x88,0x79,0x8A,0x20,0x49,
+0x9B,0x58,0x0B,0x28,0x18,0xA9,0x3A,0x7D,0x00,0x29,0x88,0x82,0x3D,0x1A,0x38,0xBA,
+0x15,0x09,0xAA,0x51,0x8B,0x83,0x3C,0x8A,0x58,0x1B,0xB5,0x01,0xBB,0x50,0x19,0x99,
+0x24,0xCA,0x21,0x1B,0xA2,0x87,0xA8,0xB1,0x68,0xA1,0xA6,0xA2,0xA8,0x29,0x8B,0x24,
+0xB4,0xE2,0x92,0x8A,0x00,0x19,0x93,0xB5,0xB4,0xB1,0x81,0xB1,0x03,0x9A,0x82,0xA7,
+0x90,0xD6,0xA0,0x80,0x1B,0x29,0x01,0xA4,0xE1,0x18,0x0A,0x2A,0x29,0x92,0xC7,0xA8,
+0x81,0x19,0x89,0x30,0x10,0xE0,0x30,0xB8,0x10,0x0C,0x1A,0x79,0x1B,0xA7,0x80,0xA0,
+0x00,0x0B,0x28,0x18,0xB1,0x85,0x1E,0x00,0x20,0xA9,0x18,0x18,0x1C,0x13,0xBC,0x15,
+0x99,0x2E,0x12,0x00,0xE1,0x00,0x0B,0x3B,0x21,0x90,0x06,0xC9,0x2A,0x49,0x0A,0x18,
+0x20,0xD1,0x3C,0x08,0x00,0x83,0xC9,0x41,0x8E,0x18,0x08,0x02,0xA0,0x09,0xA4,0x7B,
+0x90,0x19,0x2A,0x10,0x2A,0xA8,0x71,0xBA,0x10,0x4A,0x0E,0x22,0xB2,0xB2,0x1B,0x8C,
+0x78,0x1A,0xB5,0x93,0xA9,0x1B,0x49,0x19,0x29,0xA3,0xC6,0x88,0xAA,0x32,0x0D,0x1B,
+0x22,0x08,0xC2,0x18,0xB9,0x79,0x3F,0x01,0x10,0xA9,0x84,0x1C,0x09,0x21,0xB0,0xA7,
+0x0A,0x99,0x50,0x0C,0x81,0x28,0x8B,0x48,0x2E,0x00,0x08,0x99,0x38,0x5B,0x88,0x14,
+0xA9,0x08,0x11,0xAA,0x72,0xC1,0xB3,0x09,0x8A,0x05,0x91,0xF2,0x81,0xA1,0x09,0x02,
+0xF2,0x92,0x99,0x1A,0x49,0x80,0xC5,0x90,0x90,0x18,0x09,0x12,0xA1,0xF2,0x81,0x98,
+0xC6,0x91,0xA0,0x11,0xA0,0x94,0xB4,0xF2,0x81,0x8B,0x03,0x80,0xD2,0x93,0xA8,0x88,
+0x69,0xA0,0x03,0xB8,0x88,0x32,0xBC,0x97,0x80,0xB1,0x3B,0x1A,0xA6,0x00,0xD1,0x01,
+0x0B,0x3B,0x30,0x9B,0x31,0x3E,0x92,0x19,0x8A,0xD3,0x5C,0x1B,0x41,0xA0,0x93,0xA2,
+0xAF,0x39,0x4C,0x01,0x92,0xA8,0x81,0x3C,0x0D,0x78,0x98,0x00,0x19,0x0A,0x20,0x2D,
+0x29,0x3C,0x1B,0x48,0x88,0x99,0x7A,0x2D,0x29,0x2A,0x82,0x80,0xA8,0x49,0x3E,0x19,
+0x11,0x98,0x82,0x9A,0x3B,0x28,0x2F,0x20,0x4C,0x90,0x29,0x19,0x9A,0x7A,0x29,0x28,
+0x98,0x88,0x33,0xCD,0x11,0x3A,0xC1,0xA4,0xA0,0xC4,0x82,0xC8,0x50,0x98,0xB2,0x21,
+0xC0,0xB6,0x98,0x82,0x80,0x9C,0x23,0x00,0xF8,0x30,0xA8,0x1A,0x68,0xA8,0x86,0x9A,
+0x01,0x2A,0x0A,0x97,0x91,0xC1,0x18,0x89,0x02,0x83,0xE0,0x01,0x8B,0x29,0x30,0xE2,
+0x91,0x0B,0x18,0x3B,0x1C,0x11,0x28,0xAC,0x78,0x80,0x93,0x91,0xA9,0x49,0x8B,0x87,
+0x90,0x99,0x3D,0x5A,0x81,0x08,0xA1,0x11,0x2F,0x1A,0x21,0x9B,0x15,0xA2,0xB0,0x11,
+0xC0,0x91,0x5B,0x98,0x24,0xA2,0xF2,0x92,0x8B,0x6A,0x18,0x81,0xB5,0xB1,0x88,0x4C,
+0x00,0x00,0xA4,0xC1,0x2B,0x1A,0x59,0x0A,0x02,0x80,0x1E,0x02,0x08,0xB3,0x80,0x9A,
+0x23,0xB8,0xF2,0x84,0xAB,0x01,0x48,0x90,0xA7,0x90,0x0A,0x29,0x09,0x95,0x99,0xA0,
+0x59,0x2B,0x00,0x97,0xB0,0x29,0x89,0x2A,0x03,0xD0,0xB7,0x1B,0x81,0x00,0xA6,0xB1,
+0x90,0x09,0x48,0xC0,0x11,0x00,0x8A,0x00,0x5B,0x83,0x9A,0x18,0x2F,0x3C,0x18,0x11,
+0xA9,0x04,0x1A,0x4F,0x01,0x98,0x81,0x09,0x09,0x4A,0x18,0xB4,0xA2,0x0B,0x59,0x90,
+0x3B,0x49,0xBC,0x40,0x6A,0x88,0x3A,0x08,0x3E,0x3A,0x80,0x93,0xB0,0xE1,0x5A,0x00,
+0xA4,0xB3,0xE3,0x90,0x0D,0x38,0x09,0x82,0xC4,0xA1,0xB1,0x4C,0x18,0x10,0x91,0xB2,
+0x13,0xEA,0x34,0x99,0x88,0xA6,0x89,0x92,0x91,0xC1,0x20,0xB2,0xC2,0x86,0xD2,0xB3,
+0x80,0xB2,0x08,0x09,0x87,0x91,0xC0,0x11,0x89,0x90,0x28,0xB9,0x79,0x19,0xA4,0x82,
+0xD0,0x03,0x0C,0xA3,0xA5,0xB2,0xB2,0x1B,0x29,0x13,0xF1,0xB4,0x81,0x9D,0x38,0x00,
+0xC4,0xA1,0x89,0x59,0x1A,0x81,0xA4,0xA9,0x1C,0x6A,0x19,0x02,0xB1,0x1A,0x4A,0x0B,
+0x78,0x89,0x81,0x1C,0x2A,0x29,0x4A,0xA3,0x3E,0x1C,0x49,0x1A,0x08,0x21,0xAE,0x28,
+0x4B,0x19,0x20,0x8C,0x10,0x3A,0xAB,0x26,0x8B,0x18,0x59,0x99,0x13,0xA2,0xAB,0x79,
+0x2F,0x18,0x10,0xB2,0x80,0x1B,0x4D,0x5A,0x80,0x82,0x98,0x81,0x80,0x09,0xA5,0x90,
+0x91,0x03,0xC2,0xE2,0x81,0xA8,0x82,0x09,0xC6,0xA3,0xB1,0x08,0x5B,0x08,0x05,0xD1,
+0xA2,0x89,0x2A,0x28,0x91,0xA6,0x88,0xB0,0x49,0x80,0x09,0x08,0x88,0x07,0xB8,0x05,
+0x99,0x81,0x88,0x18,0xE2,0x00,0xC3,0x18,0x0D,0x10,0x30,0xD0,0x93,0x8A,0x09,0x10,
+0x2F,0x11,0x90,0xA1,0x20,0x9B,0xB1,0x73,0xC8,0x94,0x98,0x3B,0x01,0x0C,0x30,0x19,
+0xF8,0x12,0x90,0xBA,0x78,0x0A,0x11,0x98,0xA0,0x79,0x8A,0x30,0x2B,0xC2,0x11,0x0D,
+0x09,0x7A,0x00,0x82,0xB9,0x01,0x7A,0x89,0x21,0x09,0xA1,0x0A,0x7C,0x10,0x88,0xB5,
+0x88,0x0A,0x2B,0x69,0x1A,0x10,0xA0,0x5B,0x19,0x1A,0x10,0x19,0x1A,0x6C,0x20,0x90,
+0xA5,0x98,0x1B,0x0A,0x69,0x82,0xD1,0x18,0x09,0x19,0x2A,0x93,0xD4,0x9A,0x01,0x49,
+0xA2,0xA2,0x82,0xD8,0x22,0xAA,0x97,0xA9,0x2D,0x38,0x2A,0xB6,0x80,0x90,0x0A,0x3C,
+0x82,0x94,0xB8,0x21,0x0E,0x2A,0x22,0xB8,0x00,0x4F,0x2B,0x3A,0x81,0xA1,0x29,0x2C,
+0x6A,0x13,0xD1,0xA2,0x98,0x28,0x0C,0x01,0xD5,0x08,0xA9,0x31,0xB3,0xB0,0xA7,0xB0,
+0x29,0x1B,0x87,0xA2,0xA1,0xB2,0x4A,0x89,0x11,0xC3,0xF3,0x98,0x08,0x03,0xA0,0xA3,
+0xC5,0x90,0xB3,0xB5,0xB4,0xB8,0x02,0x91,0x91,0xD3,0xA4,0xC1,0x1B,0x82,0x28,0xA4,
+0xD1,0x94,0x8A,0x28,0x08,0x03,0xE0,0x80,0xD4,0x90,0x91,0xA1,0x3B,0x3D,0x02,0xE4,
+0xA1,0x92,0x89,0x1A,0x4B,0x95,0xB3,0x90,0x99,0x6A,0x0A,0x30,0xA1,0x93,0xA6,0xA9,
+0x85,0x8B,0x82,0x10,0xB1,0xA3,0x94,0xF8,0x38,0x9A,0x30,0x1A,0x8B,0xA7,0x89,0x01,
+0x5B,0x19,0x18,0x11,0xF0,0x18,0x1C,0x39,0x19,0x0C,0x12,0x1C,0x2A,0x7B,0x3A,0x88,
+0x2B,0x18,0x2B,0x5C,0x20,0x92,0x8D,0x38,0x8A,0x3A,0x5B,0x2E,0x3A,0x2B,0x10,0x12,
+0xBB,0x6A,0x4D,0x18,0x10,0xB1,0x81,0x2A,0x8B,0x79,0x80,0x01,0x0A,0x09,0x5B,0x2D,
+0x84,0x8A,0x08,0x02,0xA2,0x91,0x82,0xE8,0x50,0x9B,0x85,0xA3,0xB0,0xA3,0x1B,0x02,
+0x18,0xF3,0xA2,0x88,0xAB,0x53,0xD1,0xB4,0xA3,0x09,0x09,0x18,0xD4,0x08,0xB0,0x09,
+0x58,0xD1,0x82,0x89,0x81,0x1A,0x18,0x05,0xB9,0xC3,0x30,0xC0,0x95,0x80,0xC3,0x89,
+0x89,0x13,0x88,0xF2,0x93,0x0E,0x18,0x01,0x92,0xA5,0xB8,0x2A,0x39,0xAA,0x33,0x9A,
+0xB1,0x11,0xF5,0xA1,0xA1,0x0A,0x50,0xB8,0x03,0xC4,0xA0,0x4E,0x29,0x10,0x88,0xC2,
+0x1A,0x39,0x1D,0x28,0x98,0x94,0x0E,0x10,0x2A,0x3C,0x02,0x2D,0x1B,0x4B,0x3B,0x49,
+0x19,0xA9,0x48,0x2F,0x29,0x10,0x89,0x02,0x0C,0x10,0x09,0xB9,0x70,0x1B,0x8A,0x50,
+0xA8,0x2B,0x49,0x89,0x69,0x88,0x95,0x89,0x90,0x92,0x4C,0x19,0x82,0xC1,0x01,0x80,
+0xA0,0x2B,0x7A,0x81,0x10,0xC2,0xB7,0x98,0x88,0x19,0x2C,0x03,0xB1,0xA4,0xA1,0x0C,
+0x3B,0x78,0x88,0x85,0xB1,0xA0,0x1B,0x3A,0x4A,0x08,0x94,0x81,0xF1,0x80,0x00,0x0C,
+0x59,0x09,0x18,0x90,0xA6,0x92,0x8C,0x1A,0x79,0x92,0xA8,0x00,0x81,0x2E,0x2A,0x13,
+0xA2,0xB0,0xA5,0x88,0x88,0x89,0x11,0x19,0xA0,0xF3,0x82,0xB0,0x83,0x5F,0x2A,0x01,
+0xA1,0x94,0xB0,0x09,0x78,0x98,0xA3,0xA6,0xA0,0x91,0x80,0x93,0x98,0xC1,0x12,0x18,
+0xC9,0x17,0xA0,0xA0,0x1A,0x21,0x80,0x99,0xD4,0x30,0x9D,0x00,0x10,0x2F,0x08,0x1C,
+0x21,0x08,0xB4,0xC3,0x2B,0xA9,0x52,0xD2,0xA3,0xD1,0x09,0x10,0x8B,0x24,0x92,0xD1,
+0x80,0x19,0xA0,0x2C,0x12,0x49,0xAA,0xB6,0x95,0xB8,0x08,0x3A,0x2B,0x01,0xF3,0xB3,
+0x0B,0x09,0x79,0x18,0xA2,0xA4,0xA0,0x18,0x0C,0x20,0x08,0xA9,0x16,0x0C,0x00,0x1B,
+0x08,0x2B,0x7B,0x01,0x01,0xB9,0x59,0x19,0x8B,0x45,0xA8,0x80,0x0C,0x1A,0x41,0x1E,
+0x00,0x28,0xA8,0x5A,0x00,0xC1,0x49,0x99,0x21,0x1D,0x08,0x85,0x99,0x95,0x89,0x90,
+0x11,0x90,0xD1,0x28,0xB2,0xA7,0x99,0x81,0x02,0xAC,0x13,0x81,0xB2,0xA6,0xA9,0x28,
+0x1C,0xB1,0x33,0xD1,0xC1,0x58,0xA8,0x14,0xB0,0xB7,0x91,0xA0,0x82,0x89,0xC2,0x28,
+0xA1,0xB2,0x49,0xD2,0x94,0xC8,0x12,0x80,0x99,0x85,0x08,0xD3,0x09,0xA2,0xB3,0x1E,
+0x08,0x21,0xB9,0x23,0xB4,0xAB,0x41,0xAC,0x87,0x09,0xA2,0xC5,0x0B,0x2A,0x5A,0x91,
+0x20,0x9A,0x89,0x78,0x9B,0x31,0x89,0x80,0x29,0x0A,0xB7,0x3C,0x98,0x48,0x1D,0x00,
+0x01,0xB0,0x20,0x2F,0x29,0x4A,0x89,0x94,0x1C,0x88,0x28,0x2B,0x10,0x88,0x9A,0x71,
+0x9A,0x08,0x4A,0x2F,0x18,0x2B,0x18,0x02,0xA8,0x4B,0x7A,0x99,0x48,0x80,0xA8,0x20,
+0x1D,0x40,0xA8,0x10,0x08,0xA8,0xC5,0x88,0xC2,0x18,0x88,0x2A,0x12,0xF3,0x82,0xD8,
+0x20,0x0A,0x09,0xA6,0x98,0x04,0xB9,0x11,0x18,0xC3,0xE1,0x29,0xA1,0x11,0xC1,0x03,
+0xE2,0x9A,0x33,0xA9,0xB5,0x98,0x92,0xA1,0x02,0xF8,0x21,0xA8,0x10,0x02,0xC1,0xB7,
+0x1B,0x90,0x5B,0x3C,0x83,0x93,0xE0,0x19,0x1A,0x11,0x11,0xF1,0x92,0x89,0x19,0x2C,
+0x2C,0x41,0x99,0x92,0x90,0x3F,0x18,0x4B,0x00,0x08,0xD2,0x01,0xB2,0xAA,0x78,0x09,
+0x01,0x91,0xA2,0x98,0x2F,0x3A,0x2C,0x01,0x00,0x93,0xE0,0x28,0x2C,0x2B,0x01,0x12,
+0xE1,0x80,0xB3,0x3D,0x3A,0x0A,0x50,0x98,0xC2,0xA0,0x11,0xAA,0x30,0x87,0x90,0xC2,
+0x29,0x88,0x38,0xC8,0xB5,0x90,0xBA,0x70,0x1A,0x02,0x94,0xD0,0x80,0x1A,0x82,0xA6,
+0xB0,0x91,0x18,0xB3,0x00,0x13,0xF1,0xA2,0xC1,0x82,0xB0,0x00,0x15,0x0B,0xD3,0x02,
+0xA8,0x91,0x2B,0x1F,0x49,0x88,0xA6,0x80,0x88,0x08,0x1B,0xA5,0x80,0xB9,0x06,0x0B,
+0x90,0x21,0x9D,0x48,0x18,0xA0,0x15,0xC9,0x82,0x2B,0x1A,0x42,0x9A,0xC4,0x39,0xBC,
+0x69,0x00,0xA0,0x29,0x8C,0x39,0x59,0x08,0x09,0x49,0xA9,0x6B,0x81,0x00,0x98,0xB0,
+0x68,0x3D,0x81,0x88,0x18,0x19,0x1D,0x12,0x80,0xB2,0x3A,0x3F,0x85,0x92,0xD0,0x00,
+0x0A,0x19,0x12,0xF1,0x02,0x9B,0x19,0x40,0xB9,0x11,0x02,0xF2,0x1A,0x08,0x94,0x0A,
+0xC2,0x83,0x0B,0xB4,0xA4,0xC0,0x32,0xD8,0x86,0x98,0x90,0x95,0x89,0xA3,0x83,0xC2,
+0x92,0xE1,0x92,0x82,0xD9,0x03,0x08,0xA9,0x85,0x92,0xA2,0x80,0xE0,0x30,0x8B,0xB3,
+0x87,0x89,0x90,0x83,0xA0,0x08,0x92,0x93,0x3E,0xAB,0x43,0x89,0xE3,0x80,0x83,0x2F,
+0x00,0xA3,0x80,0xC9,0x22,0x3F,0x08,0x81,0x0B,0x33,0x9A,0xA3,0x7B,0x0C,0x29,0x4A,
+0x1B,0x21,0xAA,0x70,0x1B,0x0D,0x48,0x1A,0x81,0x88,0xB1,0x39,0x3F,0x08,0x58,0xA0,
+0x81,0x1A,0x1A,0x2B,0x6D,0x11,0x0A,0x91,0x01,0x1A,0x98,0x5A,0x0C,0x03,0xB1,0x84,
+0xA3,0xAD,0x58,0x2A,0xA1,0x84,0xB1,0xA0,0x5C,0x2B,0x13,0xA8,0x95,0x83,0xE8,0x10,
+0x81,0xB0,0x00,0xC2,0x96,0xA0,0x91,0x00,0x2C,0x90,0x30,0xF2,0x80,0xA8,0x39,0x21,
+0xC1,0x03,0xAC,0x39,0x7C,0x29,0x91,0x1A,0x00,0x19,0x2C,0x3A,0x93,0xB0,0x29,0x8F,
+0x28,0x02,0x93,0xF3,0xA9,0x01,0x03,0xE0,0x08,0x09,0x1D,0x58,0xA1,0x83,0xA9,0x6B,
+0x2A,0x3C,0x21,0x89,0xC2,0x2C,0x4B,0x8A,0x50,0x81,0x98,0xA8,0x32,0x0C,0x8E,0x24,
+0x0B,0x1A,0x81,0x92,0xA1,0x4F,0x18,0x3A,0x0A,0xB4,0x18,0x2E,0x39,0x82,0x19,0xD3,
+0xD0,0x28,0x1B,0x11,0x98,0x07,0xAA,0x28,0x00,0x88,0xB4,0x89,0x1B,0x1F,0x22,0x00,
+0xB3,0xC9,0x33,0xAB,0x2B,0xB5,0x48,0x98,0x98,0xA7,0x10,0xD2,0xC1,0x23,0xCA,0x93,
+0xC6,0x80,0xA1,0x88,0x02,0x89,0xE2,0x09,0x38,0xBA,0x40,0x89,0x21,0xD8,0x49,0x10,
+0x8D,0x02,0x90,0xC3,0x9A,0x24,0x89,0x08,0x84,0xA5,0x9C,0x10,0x11,0x9C,0x88,0x30,
+0x3C,0xA1,0x94,0x58,0x8C,0x0B,0x69,0x29,0x9A,0x81,0x12,0x2B,0x8B,0x79,0x94,0xB0,
+0xC1,0x84,0xC2,0x99,0x25,0x99,0x11,0xA2,0x93,0xE4,0x99,0x80,0x0A,0x00,0x10,0xB7,
+0xB0,0x31,0xBA,0x3C,0x21,0xB3,0xF1,0x18,0xA0,0x2A,0x20,0xA3,0x06,0xE8,0x28,0xA1,
+0xB4,0x08,0x0B,0x11,0x4B,0xB7,0x90,0xA5,0x98,0x3D,0x19,0x02,0xA1,0xC4,0xB2,0x19,
+0x28,0xC0,0xA5,0x92,0xB1,0xA3,0x0A,0x0A,0x08,0x2B,0x70,0xC4,0xB3,0x00,0xBC,0x4B,
+0x39,0x12,0xE3,0xA0,0x00,0x3F,0x18,0x29,0x94,0xD1,0x19,0x09,0x00,0xA1,0x83,0x99,
+0x9B,0x35,0x80,0xC4,0xB1,0x6A,0x1A,0x1C,0x29,0x38,0x0E,0x19,0x5A,0x1A,0x82,0x8A,
+0x59,0x2A,0x2E,0x20,0x88,0xA8,0x3A,0x38,0x3D,0x00,0xB3,0x29,0xAD,0x49,0x10,0x0C,
+0x01,0x01,0xA3,0x8F,0x85,0x09,0x1B,0x88,0x10,0xA3,0xD2,0x90,0x3C,0x5C,0x39,0x03,
+0xD1,0xA0,0x00,0x2A,0x0B,0x04,0xA7,0x90,0xA0,0x11,0x90,0x99,0x83,0xB4,0xB1,0xF1,
+0x84,0x88,0x90,0x18,0x18,0xD3,0xD2,0xB3,0xA0,0x1A,0x21,0xA7,0xB2,0xB3,0x92,0x9A,
+0x22,0xB9,0x28,0x38,0xBD,0x87,0x2A,0xB1,0x13,0x0D,0x0A,0x38,0xC9,0x24,0xC0,0x19,
+0x23,0x0F,0x01,0x88,0xC0,0x2A,0x82,0x18,0x28,0xF0,0x18,0x2A,0x29,0x4B,0x35,0xB8,
+0xA3,0x9D,0x18,0x1B,0x40,0x00,0x9A,0x5C,0x3A,0x09,0x2F,0x38,0x8A,0x3B,0x3B,0x11,
+0x5C,0x19,0x2B,0x4A,0x08,0x0A,0x3D,0x20,0x4F,0x3A,0x19,0x2A,0x18,0x4D,0x1B,0x3A,
+0x11,0x0D,0x3A,0x3C,0x4B,0x93,0x81,0xAA,0x6B,0x4A,0x18,0x00,0xC3,0xC3,0x9A,0x59,
+0x2A,0x1B,0xA7,0xA1,0x81,0x88,0x88,0x58,0xB2,0xB1,0x2B,0x83,0xD4,0x81,0x08,0x0F,
+0x00,0x20,0xC2,0xE2,0x80,0x08,0x1C,0x29,0x04,0xB1,0xA2,0x01,0x1C,0x91,0x00,0x0C,
+0x49,0xB0,0x43,0xF2,0x99,0x39,0x3F,0x00,0x81,0x94,0xC1,0x09,0x1A,0x69,0x90,0x80,
+0x94,0xAA,0x20,0x2A,0x91,0xB1,0x39,0x7A,0x38,0xD1,0x10,0x8A,0x8C,0x5A,0x01,0xB5,
+0x98,0x80,0x2A,0x0B,0x32,0x92,0xF1,0x81,0x9A,0x23,0x8A,0xA3,0xB7,0x09,0x03,0x08,
+0xD0,0x94,0x9A,0x09,0x01,0x93,0xB7,0xC2,0x8C,0x3A,0x83,0x99,0x05,0xA0,0x0B,0x29,
+0x93,0xE5,0x80,0x89,0x38,0x90,0x8A,0xD7,0xA1,0x19,0x1B,0x48,0x98,0x92,0xC3,0xA1,
+0x09,0x3F,0x02,0x0C,0x22,0xC3,0xB2,0xA1,0x01,0x9F,0x4A,0x01,0xA3,0xD3,0xB0,0x28,
+0x3F,0x29,0x20,0xA2,0xC2,0xB1,0x08,0x5A,0x98,0x13,0xD2,0xC1,0x01,0xB2,0x80,0x3D,
+0x03,0xC1,0x89,0x96,0x90,0x90,0x3A,0x1A,0x9A,0x32,0xB6,0xA2,0x8E,0x4A,0x28,0x8A,
+0x84,0xA2,0x8A,0x2D,0x49,0x09,0x88,0x18,0x30,0x9D,0x2C,0x23,0xB1,0x0C,0x92,0x2D,
+0x39,0x82,0xC4,0x2E,0x10,0x1A,0x10,0xB9,0x48,0x19,0x39,0xBA,0x34,0xDA,0x2D,0x48,
+0x1A,0xA6,0x98,0x83,0x9A,0x1D,0x38,0x04,0xD0,0x18,0x90,0x2C,0x11,0x93,0xD3,0x9A,
+0x11,0x08,0x82,0xF1,0x01,0xA0,0x2A,0x93,0xD3,0xB4,0xB8,0x82,0x2F,0x11,0xA3,0xB3,
+0xA8,0x3B,0x09,0x23,0x96,0xC8,0x3B,0x3F,0x93,0x82,0xA1,0x90,0x3F,0x28,0x81,0xD1,
+0x93,0x08,0x2D,0x18,0x91,0xB3,0xB5,0x98,0x2A,0x2B,0x84,0xB1,0x5B,0x8A,0x31,0x18,
+0x80,0x8B,0x7E,0x39,0x2B,0x02,0xC1,0x8B,0x6C,0x49,0x09,0x10,0xA1,0x08,0x01,0x0C,
+0x20,0xA1,0x09,0x4F,0x18,0x00,0x01,0xA0,0x5C,0x1B,0x5B,0x10,0x92,0x90,0x2B,0x5A,
+0x3D,0x18,0x91,0x19,0x98,0x2D,0x39,0x89,0x2D,0x3A,0x48,0x2C,0x11,0xB5,0x9A,0x19,
+0x5B,0x28,0x90,0x95,0x98,0x89,0x2B,0x40,0x08,0x90,0xF3,0x0A,0x08,0xA6,0x80,0x91,
+0xB2,0xA0,0x02,0xF2,0xA1,0xB7,0x89,0x81,0x82,0x91,0xB1,0x21,0xAB,0x32,0xE9,0x04,
+0xA2,0x8D,0x12,0x91,0xA3,0xA3,0xD2,0x8B,0x39,0xD1,0x84,0xE2,0x90,0x00,0x2B,0x29,
+0xA3,0xD4,0xA1,0x91,0x1D,0x5A,0x08,0x19,0x11,0x99,0x08,0x18,0x49,0x0F,0x18,0x10,
+0x82,0xF1,0x00,0x89,0x2F,0x3A,0x01,0xB3,0xC2,0x81,0x3F,0x29,0x08,0x10,0xA1,0xA1,
+0x3B,0x5D,0x19,0x28,0x0B,0x38,0x82,0x91,0x19,0xBD,0x3B,0x7A,0x80,0x12,0xB3,0xE0,
+0x0B,0x6A,0x01,0x88,0xA4,0x08,0x0B,0x08,0x59,0x80,0x80,0x1D,0x49,0x89,0x00,0x84,
+0x99,0x1A,0x2B,0x32,0xE3,0xB4,0xA9,0x3A,0x99,0x31,0xE3,0xAA,0x58,0x3B,0x88,0x95,
+0xC0,0x18,0x4A,0x09,0x30,0xF2,0xA3,0x1C,0x1B,0x49,0x00,0xD3,0xB2,0xA0,0x18,0x11,
+0x92,0xD3,0xB2,0x91,0x80,0xE7,0xA1,0x91,0x98,0x19,0x22,0xC2,0xD2,0x18,0x8D,0x3B,
+0x10,0xA5,0x91,0x98,0x02,0x3E,0x80,0x01,0x90,0xAA,0x13,0xF1,0x02,0xD1,0x08,0x19,
+0x49,0xB4,0x91,0xB4,0x99,0x2A,0x0C,0x32,0xC0,0x05,0x88,0x0B,0x80,0x2C,0x81,0x10,
+0x0B,0x51,0xA9,0x19,0x05,0xBF,0x28,0x20,0xE1,0x90,0x80,0x28,0x19,0x08,0x26,0xB1,
+0xA1,0x18,0x88,0x2A,0xF0,0x12,0x8A,0xB3,0x14,0x1B,0xD4,0xD8,0x10,0x08,0x8A,0x17,
+0xA0,0x98,0x2B,0x3A,0x29,0x48,0xA4,0x99,0x0E,0x4A,0x12,0x8B,0x31,0x8B,0x4E,0x1A,
+0x11,0xB5,0x89,0x91,0x29,0x89,0xC2,0x97,0x90,0x0A,0x19,0x11,0x91,0xC1,0xD5,0x08,
+0x89,0x20,0x91,0xB1,0x1A,0x2D,0x18,0x29,0xD2,0x3B,0x3E,0x3A,0x2A,0x90,0x82,0x1C,
+0x49,0x3B,0x93,0xB6,0xC8,0x4C,0x02,0x91,0x93,0xF2,0x88,0x2D,0x28,0x81,0x82,0xC1,
+0x89,0x2D,0x6B,0x19,0x82,0x80,0x18,0x8B,0x39,0x39,0xC8,0x3A,0x6A,0x0A,0x22,0xD2,
+0x09,0x2C,0x1A,0x68,0x92,0xE2,0x89,0x2A,0x2A,0x30,0xC2,0xA3,0xB4,0x1D,0x2A,0x09,
+0x93,0x18,0xF2,0x89,0x28,0xB3,0x01,0x8F,0x18,0x11,0xA1,0x93,0x90,0xD1,0x7A,0x20,
+0xC3,0xA2,0xA8,0x88,0x1D,0x28,0xA5,0xA2,0xA2,0x0B,0x29,0x2B,0x87,0xC1,0x80,0x0A,
+0x19,0x01,0x12,0xF1,0x10,0x80,0x0A,0x18,0x08,0x2F,0x4A,0x02,0x89,0x1B,0x29,0x5D,
+0x4C,0x08,0x82,0xA1,0x0A,0x3A,0x4B,0x29,0xC6,0xC3,0x09,0x09,0x88,0x39,0x98,0x82,
+0xA5,0x1A,0x30,0x11,0xBD,0x3F,0x12,0x8B,0x28,0xC3,0x88,0x3F,0x2B,0x3B,0x48,0xA1,
+0x80,0x8A,0x4D,0x39,0x01,0x93,0xA2,0xF1,0x19,0x19,0x0A,0x02,0xB2,0x8B,0x24,0xD2,
+0x4B,0x12,0xC8,0x2E,0x10,0xB5,0x89,0x01,0x09,0x1C,0x2A,0x03,0xD4,0x91,0x98,0x99,
+0x11,0x2B,0xE4,0x00,0x00,0x01,0xE0,0xA5,0x89,0x99,0x31,0x18,0xD0,0xB7,0x98,0x18,
+0x0A,0x10,0x94,0xC2,0x90,0x18,0x00,0x99,0x87,0xA0,0x90,0x2A,0x3C,0x02,0xB8,0xC1,
+0x79,0x1A,0x20,0x08,0xA1,0xD2,0x1C,0x29,0x03,0xD1,0x29,0x99,0x2C,0x50,0xB3,0xD1,
+0x08,0x09,0x3C,0x10,0x04,0xB2,0x0D,0x2B,0x59,0x80,0x90,0x01,0x0F,0x3A,0x18,0x01,
+0xA2,0x9B,0x5B,0x3D,0x81,0x03,0xD2,0x98,0x59,0x90,0x81,0x92,0xB4,0x8B,0x1B,0x40,
+0xB2,0xB5,0x08,0x4B,0x01,0x09,0xD1,0x91,0x8B,0x7A,0x10,0xB3,0xC3,0x99,0x49,0x1A,
+0x29,0xB5,0xA2,0xAB,0x40,0x81,0x19,0xB7,0xB0,0x20,0x2B,0xD4,0x88,0xA1,0x91,0x3C,
+0x82,0x37,0xD3,0xB1,0x8A,0x1B,0x30,0xB3,0xF4,0xA1,0x91,0x09,0x10,0x03,0xD0,0x83,
+0xA9,0x8F,0x10,0x01,0x90,0x18,0x80,0x20,0x2B,0xF1,0x28,0x99,0x2A,0x41,0xF0,0x12,
+0xAA,0x83,0x82,0xD1,0xC1,0x08,0x89,0x59,0x09,0x83,0x87,0xB0,0x2A,0x4D,0x18,0x09,
+0x19,0xB3,0x4B,0x3F,0x39,0x19,0x09,0x01,0x89,0x03,0x1F,0x00,0x1A,0x0B,0x10,0x68,
+0xA0,0x18,0x8C,0x6A,0x09,0x08,0x97,0xA1,0x81,0x1B,0x2B,0x4C,0x03,0xB4,0xA8,0x92,
+0x4B,0x3C,0xA1,0x81,0x95,0xA8,0x81,0x12,0xBB,0x92,0x45,0xB9,0x93,0xF4,0x88,0x0A,
+0x2D,0x28,0x00,0xA3,0xA3,0x8A,0x3F,0x48,0xB1,0x92,0xB4,0xA8,0x30,0x80,0xD3,0x80,
+0xD1,0x19,0x3B,0xC4,0x81,0xC1,0x29,0x0D,0x20,0x13,0xC8,0xB4,0x4C,0x09,0x00,0x82,
+0xC2,0x3B,0x0D,0x30,0x0B,0x12,0xF0,0x1B,0x20,0x0A,0xA6,0x80,0x0A,0x4A,0x4A,0x80,
+0x94,0xB1,0x2E,0x3B,0x1A,0x10,0x93,0x10,0x4C,0x3D,0x08,0x82,0xC9,0x19,0x6A,0x2B,
+0x38,0xD1,0x08,0x19,0x2A,0x5A,0x82,0xB1,0x8D,0x29,0x78,0x09,0x82,0x0A,0x2C,0x1B,
+0x19,0x41,0xB8,0x8C,0x79,0x2B,0x11,0x88,0x82,0x91,0xDC,0x28,0x11,0xB0,0x11,0x18,
+0xC9,0x62,0xA1,0x91,0x98,0x3B,0x3A,0xB0,0xF4,0x01,0xC0,0x29,0x39,0xF8,0x95,0x91,
+0x88,0x88,0x91,0x03,0xA1,0xE2,0x18,0x82,0xD1,0xA2,0xD1,0x80,0x19,0x20,0x83,0xB1,
+0xE3,0x80,0x91,0x4D,0x1A,0x03,0xB2,0x09,0x18,0xD1,0x19,0x09,0x92,0xA6,0xA0,0xB6,
+0xB2,0x8B,0x38,0x10,0x42,0xD3,0xD0,0xA8,0x20,0x2C,0x10,0x01,0xB1,0xB4,0xAB,0x5B,
+0x79,0x80,0x10,0x1A,0xA8,0x3D,0x18,0x20,0xB3,0x8F,0x18,0x01,0x00,0x09,0xF3,0x89,
+0x69,0x88,0x81,0x91,0x08,0xE1,0x1A,0x08,0x11,0x81,0x1E,0x29,0xA0,0x01,0x00,0x90,
+0x3E,0x7B,0x18,0x82,0xC3,0xA1,0x2A,0x2C,0x5B,0x81,0xA5,0x90,0x81,0x00,0x0B,0x1A,
+0x1C,0x2C,0x32,0xC0,0xF3,0x80,0x2D,0x2A,0x10,0x02,0xE4,0xC1,0x89,0x4A,0x09,0x01,
+0x03,0xD2,0x98,0x2A,0x39,0x8A,0x89,0x26,0xB1,0xB2,0x12,0xC0,0x0A,0x5A,0x18,0x98,
+0xF3,0x92,0x99,0x99,0x79,0x01,0xB5,0xA1,0x80,0x80,0x90,0x83,0xA0,0xE2,0x81,0x29,
+0x93,0x8A,0x0A,0x6A,0x1F,0x18,0x02,0xC8,0x01,0x19,0x3B,0x4A,0x98,0x17,0xA8,0x0D,
+0x38,0xA1,0x91,0x10,0xA2,0x2B,0x4C,0xA6,0x81,0xBA,0x21,0x4C,0x80,0x21,0xD1,0x92,
+0x2C,0x08,0x30,0x9F,0x93,0x2A,0x89,0x03,0x8B,0x87,0x0A,0x0D,0x12,0x98,0xA4,0x93,
+0xBB,0x59,0x18,0xA1,0x32,0xE9,0x84,0x08,0x8A,0x02,0xA1,0x91,0x4B,0xB4,0x20,0x88,
+0xF0,0x3A,0x1A,0x88,0x87,0xB1,0x92,0x0A,0x08,0x6B,0x83,0xC3,0x91,0xC0,0x2B,0x79,
+0x08,0x8A,0x84,0xA0,0x89,0x40,0x1B,0xA1,0x39,0x98,0x17,0xC2,0xA2,0x12,0xCD,0x20,
+0x89,0x92,0x25,0xB0,0x2D,0x3A,0x8B,0x58,0x2A,0xA0,0x4C,0x08,0x30,0xAE,0x82,0x59,
+0x89,0x1A,0x10,0xC2,0x18,0x2C,0x40,0x1E,0x01,0xA3,0x8A,0x81,0x2C,0x29,0x29,0xA9,
+0x13,0x51,0xAD,0x12,0x89,0x8F,0x18,0x2C,0x39,0x00,0xC1,0x10,0x3C,0x2A,0x41,0xC8,
+0xA2,0x91,0x0A,0x6C,0x10,0x12,0x88,0xE8,0x30,0x91,0x81,0xD8,0x01,0x1B,0x0D,0x07,
+0x00,0xA8,0x92,0x0A,0x28,0xD2,0xC3,0x02,0xAA,0x94,0x81,0xB4,0xB3,0x1A,0x0B,0x13,
+0xF9,0x16,0xA1,0x8A,0x59,0x19,0x02,0xC1,0x91,0x8B,0x3D,0x18,0x3B,0xA4,0x94,0x80,
+0x99,0x88,0x1C,0x79,0x0A,0x02,0x03,0xF8,0x90,0x39,0x5B,0x19,0x02,0xC3,0x90,0xBB,
+0x58,0x6A,0x09,0x02,0x89,0x91,0x88,0x1A,0x69,0x8A,0x19,0x15,0xA0,0xA2,0x00,0x9A,
+0x6B,0x49,0x88,0xA3,0x92,0xBB,0x6B,0x3D,0x38,0x01,0x98,0x91,0x3F,0x09,0x18,0x20,
+0x90,0x80,0xAC,0x70,0x91,0x9B,0x51,0x09,0x88,0x99,0x14,0x8B,0x98,0x83,0x79,0xA0,
+0x99,0x13,0x01,0x19,0xE0,0x83,0x0B,0xB0,0x0C,0x31,0x95,0xB5,0xC2,0x8A,0x39,0x20,
+0x80,0x39,0xF3,0xB1,0x10,0x88,0x5E,0x18,0x94,0xA1,0x88,0xA1,0x98,0x15,0xAA,0x39,
+0xD4,0x84,0xC0,0xA2,0xA2,0x0C,0x81,0x86,0xB5,0xA1,0xB1,0x14,0x1B,0xB1,0x02,0x92,
+0xC3,0xE0,0x88,0x11,0xAA,0x69,0x18,0x81,0xA3,0xB0,0x01,0xBF,0x2A,0x31,0x93,0xF1,
+0x00,0x89,0x18,0x19,0x11,0xD3,0xE0,0x10,0x18,0xB1,0x18,0x24,0x9A,0x2B,0xA4,0xC0,
+0xB0,0x31,0x6C,0x19,0xB4,0x12,0xA8,0xEA,0x58,0x10,0x8B,0x93,0x82,0x88,0x9A,0x41,
+0x10,0xC3,0xEA,0x41,0xA9,0x9C,0x34,0xA1,0x2A,0x79,0xA2,0x01,0xA8,0xB3,0x28,0xCC,
+0x41,0x9A,0xB3,0x4B,0xB3,0x27,0x8B,0x83,0x2B,0x2F,0x08,0x28,0xB2,0x80,0x2C,0x30,
+0x5E,0x09,0x12,0x9B,0x09,0x22,0x5B,0x19,0x8A,0x11,0x59,0x99,0xA4,0x32,0xCD,0x18,
+0x08,0x10,0x85,0xB3,0xB4,0x1E,0x88,0x28,0x8A,0x11,0x09,0xC0,0x79,0x80,0x91,0x3B,
+0x80,0x10,0x0F,0x01,0x80,0x91,0x19,0x3D,0x92,0x28,0xA8,0x37,0x9A,0x0A,0x3A,0x8A,
+0x45,0xA9,0xA4,0x00,0xAA,0x09,0x3D,0x59,0x20,0xE1,0x08,0x98,0x90,0x59,0x10,0x09,
+0xA3,0xC3,0x93,0x99,0x2B,0x69,0x11,0xD1,0xB1,0xA4,0x91,0x3C,0x89,0x83,0xF0,0x10,
+0x91,0xA1,0x89,0x59,0x05,0x99,0x93,0x94,0xC8,0x08,0x0A,0x09,0x17,0xB1,0x83,0xC1,
+0x91,0x40,0xA2,0xC2,0x98,0xC3,0xBA,0x28,0x23,0x0F,0x80,0x50,0xB8,0x19,0x10,0x96,
+0x98,0x8C,0x05,0x98,0x19,0x29,0x2B,0x3B,0x0A,0xE2,0x01,0x0F,0x3C,0x38,0x08,0x09,
+0x81,0x4A,0x6C,0x08,0x00,0x88,0x98,0x38,0x2C,0x5A,0x1B,0x20,0x1A,0x39,0xB0,0x09,
+0xCB,0x5B,0x49,0x09,0x71,0x00,0xC1,0x0E,0x08,0x38,0x0C,0x02,0x10,0x0E,0x10,0x8A,
+0x48,0x19,0x90,0x92,0x0D,0xA3,0x98,0x3B,0x79,0x19,0x01,0x10,0xE1,0x80,0x19,0x2B,
+0x10,0xF2,0x02,0xAB,0x84,0x9A,0x29,0xB4,0x80,0x92,0x03,0x88,0x95,0xD0,0x03,0x90,
+0xA0,0xC7,0xA1,0xB0,0xA2,0x02,0x18,0xB5,0xD4,0x01,0xC0,0x08,0xA2,0x93,0xA8,0xA0,
+0xC3,0x20,0xF3,0x90,0x00,0xD5,0x08,0x89,0xA5,0x80,0xA0,0x81,0x82,0xC2,0x09,0xD1,
+0x13,0xCB,0x03,0x84,0x91,0xE1,0x1B,0x12,0x08,0xAB,0x87,0x18,0xAB,0x58,0x89,0x28,
+0x81,0xC9,0x33,0xA9,0x80,0x2E,0x20,0x83,0xB9,0x20,0x3B,0x9E,0x7A,0x08,0x81,0x18,
+0x0B,0x88,0x79,0x80,0x8B,0x00,0x12,0x0E,0x89,0x51,0x1B,0x81,0xA0,0x3A,0x01,0xAF,
+0x11,0x28,0xBA,0x35,0x98,0x88,0x52,0xC0,0x83,0x2F,0xA9,0x11,0x0A,0x19,0x25,0xD0,
+0x30,0x9C,0x08,0x21,0x98,0x81,0x2A,0xF3,0x2A,0x80,0xB6,0x2B,0x08,0x93,0xE9,0x02,
+0x81,0x8C,0x21,0x00,0xA6,0xA9,0x94,0x01,0x8F,0x80,0x94,0x98,0x93,0xB4,0x00,0x08,
+0xC0,0x14,0x98,0xB3,0xB4,0xC1,0x09,0x18,0xA7,0x00,0xA3,0xC8,0x0A,0x3C,0x19,0x96,
+0x83,0xC1,0x99,0x19,0x4A,0x85,0x80,0xC1,0x91,0x99,0x90,0x2A,0x17,0x95,0x99,0x88,
+0x12,0xAE,0x39,0x08,0x92,0x84,0xB0,0xA8,0x79,0x09,0x19,0x01,0xB2,0xA3,0x8F,0x28,
+0x2B,0xA2,0x40,0x82,0xA0,0x4C,0xA9,0x39,0x8D,0x81,0x70,0x88,0xA0,0x1A,0x49,0x2D,
+0x1A,0x26,0xA8,0x98,0x08,0x29,0x0B,0x12,0x96,0xB1,0xB2,0x3A,0x13,0x9B,0x60,0xA0,
+0x88,0xB2,0x34,0xEA,0x1A,0x2A,0x79,0x98,0x10,0x04,0x8C,0x1C,0x81,0x04,0x8C,0x83,
+0x19,0x2F,0x81,0x93,0x98,0x10,0x08,0x30,0x2A,0xFA,0x05,0x08,0x2A,0x89,0x91,0xA3,
+0xFA,0x11,0x11,0x00,0x8C,0x04,0x8A,0x2A,0xB5,0x10,0xA9,0xC2,0x3D,0x1B,0x32,0x04,
+0x0A,0x1A,0x09,0x40,0x1F,0x92,0x1D,0x2A,0x91,0x10,0x30,0x2F,0x0B,0x68,0x99,0xA2,
+0x92,0x88,0x78,0xA9,0x20,0x28,0xE2,0x92,0x1A,0x99,0x4B,0x19,0x22,0xA1,0xE2,0x21,
+0x2F,0x98,0x29,0x18,0x91,0x08,0xB0,0x79,0x1A,0x82,0x3B,0xB1,0xA7,0x8A,0xB3,0x98,
+0x5B,0x23,0xCA,0x42,0x83,0xF0,0x90,0x18,0x98,0x08,0xB4,0x20,0xA3,0xC0,0x43,0xD8,
+0x80,0x81,0xA3,0x99,0xD9,0xA7,0x19,0x90,0x10,0x05,0xB1,0x8B,0x02,0xA4,0xBD,0x23,
+0x93,0x8A,0x99,0x4B,0x03,0xC1,0xF8,0x38,0x09,0x2B,0x14,0xD0,0x03,0x8A,0x2A,0x39,
+0xB9,0x97,0x90,0xAA,0x50,0x01,0x99,0x51,0xD1,0x09,0x1A,0xB5,0x00,0x8B,0x93,0x08,
+0x98,0x11,0xF9,0x85,0x2B,0x08,0x96,0x89,0x90,0x2A,0x12,0x4A,0xD8,0x85,0x2B,0x0E,
+0x10,0x00,0x01,0xB1,0x9B,0x69,0x1A,0x90,0x40,0xB8,0x01,0x08,0x0A,0x2C,0x09,0x14,
+0x4B,0xE2,0x82,0x88,0xB1,0x78,0x0A,0x01,0xC2,0x93,0x19,0xCE,0x20,0x3C,0x82,0xB4,
+0x1B,0x20,0x8C,0x3B,0x29,0xAB,0x86,0x23,0xD8,0x81,0x9A,0x5A,0x49,0xB0,0x16,0xA0,
+0xB0,0x28,0x1B,0x13,0x93,0xE4,0xA2,0xA9,0x08,0x5A,0xB3,0x12,0xC1,0xE1,0x10,0x88,
+0x01,0x0C,0x92,0x08,0x89,0xB7,0x88,0x81,0x10,0x9A,0x17,0xA0,0xB0,0x13,0x99,0xE0,
+0x39,0x31,0xD2,0xB2,0x80,0x0B,0x2D,0x49,0x80,0x01,0xB0,0x06,0x09,0x0C,0x3A,0x69,
+0xA0,0x08,0xB2,0xA1,0x69,0x2B,0x5A,0x81,0x92,0xBA,0x21,0xB1,0x7D,0x10,0x80,0x08,
+0x88,0x82,0x32,0x0D,0xB0,0x1A,0x1C,0x21,0x94,0xA9,0x58,0xB9,0x5A,0x4A,0xA0,0x13,
+0xA9,0x80,0x7C,0x00,0x20,0x8A,0x04,0x0C,0x00,0x82,0x2A,0xB2,0xAC,0x4B,0x69,0xA0,
+0xA6,0x81,0x9B,0x19,0x38,0x8B,0x17,0xB2,0x81,0x2A,0xBB,0x94,0x29,0xA2,0x15,0xBA,
+0x97,0xA3,0xB9,0x79,0x01,0xB2,0x02,0xF1,0x90,0x0A,0x29,0x11,0x88,0xE5,0xA0,0x81,
+0x19,0x91,0x90,0x28,0xB3,0x14,0xD0,0xB5,0x91,0x9A,0x29,0x0B,0x07,0xA2,0xB3,0x01,
+0x9D,0x28,0x41,0xD0,0x91,0x90,0x82,0x1A,0xA8,0x44,0x9A,0xA9,0x21,0xE3,0xA9,0x4B,
+0x19,0x78,0x89,0x83,0xA3,0xB9,0x5A,0x3D,0x80,0x82,0xA2,0xA0,0x6C,0x10,0x20,0x8B,
+0x93,0x8B,0x0E,0x33,0xA9,0xB1,0x68,0x8A,0x31,0xAC,0x94,0xB4,0x8B,0x32,0x0B,0xB4,
+0x81,0x91,0x1D,0x33,0xD9,0x31,0xE1,0x8B,0x3B,0x30,0x12,0x49,0xD2,0x8E,0x29,0x18,
+0x8A,0x92,0x02,0xAA,0x59,0x1C,0x32,0x88,0x01,0x23,0xFB,0x83,0x29,0xDA,0x59,0x01,
+0x81,0x92,0xE1,0x18,0x8A,0x1D,0x30,0x93,0xF1,0x00,0x01,0x0B,0x39,0x92,0x89,0xA0,
+0x11,0x5B,0xE0,0x82,0x09,0x13,0xAA,0xB4,0x16,0xD8,0x91,0x2A,0x29,0x84,0x1B,0xC5,
+0x98,0x98,0x31,0x98,0x99,0x17,0xA9,0x20,0x92,0xC3,0x18,0x9D,0x20,0x3D,0x89,0x94,
+0xA2,0x1C,0x5C,0x29,0x39,0xA0,0xB3,0x00,0x0C,0x4C,0x48,0x92,0x0A,0x91,0x85,0x9A,
+0x01,0x82,0x1F,0x10,0x99,0x15,0xC1,0xA0,0x39,0x1A,0x1D,0x85,0xB4,0x90,0x1A,0x2A,
+0x4B,0x01,0xB2,0x93,0xBE,0x12,0x83,0xC9,0x18,0x09,0x20,0x78,0xF1,0x08,0x19,0x88,
+0x3A,0x83,0xB3,0xA9,0x93,0x7A,0x0A,0x96,0x98,0x00,0xA8,0x3A,0x30,0x92,0xF2,0x9B,
+0x3D,0x38,0x92,0x92,0xC3,0xB8,0x6B,0x29,0x01,0x01,0xB2,0x2F,0x09,0x19,0x18,0x01,
+0x3B,0x7B,0x10,0xA1,0x90,0x39,0x0F,0x38,0x0A,0xB5,0xA4,0x89,0x8B,0x6A,0x2B,0x12,
+0xC8,0x90,0x40,0x2A,0x9E,0x22,0x88,0x18,0x09,0x3A,0xC3,0xE8,0x09,0x59,0x08,0x12,
+0x94,0xD0,0x1A,0x2C,0x38,0x00,0xA1,0x83,0xE8,0x08,0x3A,0x08,0x10,0x9E,0x83,0x1D,
+0x92,0x19,0x2C,0x39,0x3B,0x59,0x04,0xE1,0x80,0x08,0x8D,0x21,0x81,0xB2,0xB2,0x02,
+0x99,0x91,0xA4,0xD6,0x98,0x99,0x03,0x80,0x98,0xA7,0x91,0x09,0xA1,0xB2,0xB3,0xE1,
+0x12,0x92,0xB1,0x81,0x06,0x99,0x0A,0x23,0xC4,0xB1,0xF2,0x89,0x19,0x3A,0x94,0x82,
+0xE0,0x89,0x38,0x0B,0xA4,0xA5,0x80,0x80,0x8C,0x34,0xB9,0xA9,0x23,0x13,0xB9,0xC1,
+0xC7,0x1B,0x89,0x10,0x20,0x11,0xE3,0xA8,0x4B,0x0B,0x40,0x91,0x90,0x1B,0x5F,0x2A,
+0x18,0x82,0x91,0x0B,0x4A,0x28,0xCA,0x40,0x80,0x5B,0x2C,0x13,0xB0,0x8A,0xA9,0x5A,
+0x58,0x89,0x82,0x88,0x2E,0x3B,0x31,0xA1,0x9B,0x01,0x7A,0x2C,0x01,0x91,0x93,0x3F,
+0x88,0x39,0x10,0xF1,0x91,0x8B,0x48,0x0A,0x12,0xE3,0xA8,0x18,0x28,0x92,0x97,0x98,
+0x99,0x19,0xA1,0x11,0xB6,0x88,0x3B,0x10,0xD3,0xC3,0xA1,0x2A,0x8A,0x49,0x04,0xF1,
+0x91,0x02,0x8A,0x89,0x04,0xF1,0x98,0x80,0x18,0x12,0xE3,0x81,0x98,0x80,0x01,0xB3,
+0xF2,0x99,0x12,0x2A,0xB5,0xB3,0x92,0xAA,0x19,0x50,0xB2,0xC3,0x92,0xD0,0x2B,0x68,
+0x93,0x99,0xC0,0x2C,0x3E,0x80,0x20,0x08,0x93,0x0D,0x2A,0x31,0x8D,0x02,0x2B,0x91,
+0x08,0x0A,0x03,0x2C,0x3C,0x52,0xB9,0xA0,0x12,0xBF,0x3A,0x29,0x01,0x88,0xC0,0x6A,
+0x3C,0x0A,0x49,0x18,0x0B,0x39,0x2B,0x69,0x0A,0x84,0x2A,0x2A,0x1C,0x2A,0xC3,0x8C,
+0x19,0x50,0x09,0x91,0xA7,0x8D,0x18,0x1A,0x28,0x00,0xA0,0x94,0x10,0x1F,0x20,0x90,
+0x8A,0x12,0xD0,0x1A,0x5A,0x81,0x04,0xBC,0x23,0x10,0xE0,0x90,0x90,0x18,0x1A,0xA6,
+0x12,0xB1,0xD0,0x4A,0x08,0x82,0x92,0xB6,0x9A,0x0A,0x12,0x88,0xC3,0xC5,0x8A,0x89,
+0x20,0xB5,0x93,0x0B,0x18,0x00,0x09,0xF2,0x88,0x2A,0x4A,0x08,0x05,0xB2,0xA9,0x3B,
+0x5D,0x28,0xA4,0xB1,0x00,0x19,0x19,0x7A,0xA3,0xB3,0x0A,0x90,0xA1,0xC4,0x80,0xBA,
+0x50,0x13,0xC1,0xC2,0x9A,0x2A,0x7B,0x28,0x84,0xC1,0x09,0x3B,0x4E,0x20,0x91,0xA1,
+0x18,0xAB,0x79,0x10,0xB4,0x08,0x9A,0x11,0x2B,0xF0,0x93,0xAA,0x01,0x6A,0x01,0x93,
+0x80,0xB8,0x2A,0x5B,0x10,0x80,0x89,0x4A,0x5B,0x92,0x15,0xB2,0xA0,0x2F,0x19,0x93,
+0xB8,0x95,0x80,0x1C,0x21,0xA9,0x02,0x0B,0xA0,0x5A,0x18,0x98,0x39,0x1B,0x68,0x00,
+0x91,0x91,0x9C,0x39,0x3E,0x18,0x84,0xB3,0x9B,0x7A,0x08,0x18,0x0A,0xB5,0x91,0x0B,
+0x28,0x39,0x19,0x90,0x0A,0x50,0xAC,0x11,0x01,0xAB,0x88,0x52,0x1B,0x83,0xC4,0xA2,
+0x9A,0xAB,0x03,0x90,0x19,0x93,0x81,0x08,0x92,0x9A,0x68,0x98,0x19,0x39,0xC1,0x92,
+0x8A,0x38,0x4E,0x02,0xB1,0x90,0xC3,0x18,0x2B,0x04,0xC3,0xD2,0x91,0x90,0x81,0x89,
+0x13,0xF1,0x88,0x93,0xA2,0x00,0x91,0xC0,0x5B,0x21,0x99,0x93,0x06,0x9A,0x1B,0x48,
+0x99,0xB7,0x90,0x89,0x18,0x1B,0x11,0xA4,0xB2,0x81,0x9A,0x08,0x97,0x98,0x91,0x10,
+0xB8,0x06,0xA2,0xA0,0x29,0x2B,0x21,0xC2,0xD1,0x10,0x1A,0x4A,0x29,0xF1,0x98,0x29,
+0x1B,0x31,0x10,0xA0,0xA1,0x1D,0x5A,0x29,0xB2,0x82,0xA8,0x0F,0x28,0x21,0x09,0x91,
+0x82,0x4D,0x10,0xA3,0xB0,0x89,0x4C,0x39,0xA0,0xA4,0xA1,0x89,0x1E,0x28,0x29,0xA3,
+0xC3,0x2D,0x19,0x01,0x49,0x01,0x9B,0x0C,0x21,0xC2,0xA2,0x93,0x7C,0x2A,0x10,0x90,
+
+/* Source: 08HH.ROM */
+/* Length: 384 / 0x00000180 */
+
+0x75,0xF2,0xAB,0x7D,0x7E,0x5C,0x3B,0x4B,0x3C,0x4D,0x4A,0x02,0xB3,0xC5,0xE7,0xE3,
+0x92,0xB3,0xC4,0xB3,0xC3,0x8A,0x3B,0x5D,0x5C,0x3A,0x84,0xC2,0x91,0xA4,0xE7,0xF7,
+0xF7,0xF4,0xA1,0x1B,0x49,0xA5,0xB1,0x1E,0x7F,0x5A,0x00,0x89,0x39,0xB7,0xA8,0x3D,
+0x4A,0x84,0xE7,0xF7,0xE2,0x2D,0x4C,0x3A,0x4E,0x7D,0x04,0xB0,0x2D,0x4B,0x10,0x80,
+0xA3,0x99,0x10,0x0E,0x59,0x93,0xC4,0xB1,0x81,0xC4,0xA2,0xB2,0x88,0x08,0x3F,0x3B,
+0x28,0xA6,0xC3,0xA2,0xA2,0xC5,0xC1,0x3F,0x7E,0x39,0x81,0x93,0xC2,0xA3,0xE5,0xD2,
+0x80,0x93,0xB8,0x6D,0x49,0x82,0xD4,0xA1,0x90,0x01,0xA0,0x09,0x04,0xE3,0xB2,0x91,
+0xB7,0xB3,0xA8,0x2A,0x03,0xF3,0xA1,0x92,0xC5,0xC3,0xB2,0x0B,0x30,0xB3,0x8E,0x6D,
+0x4A,0x01,0xB4,0xB4,0xC4,0xC3,0x99,0x3B,0x12,0xE3,0xA1,0x88,0x82,0xB4,0x9A,0x5C,
+0x3A,0x18,0x93,0xC3,0xB3,0xB4,0xA8,0x19,0x04,0xF3,0xA8,0x3B,0x10,0xA2,0x88,0xA5,
+0xB2,0x0B,0x6D,0x4B,0x10,0x91,0x89,0x3C,0x18,0x18,0xA6,0xC4,0xC3,0x98,0x19,0x2B,
+0x20,0x91,0xA0,0x4E,0x28,0x93,0xB3,0xC2,0x92,0xA9,0x5A,0x96,0xC4,0xC2,0x09,0x01,
+0xC4,0xA1,0x92,0xC4,0xA1,0x89,0x10,0xA3,0xA1,0x90,0x1C,0x5A,0x01,0xC5,0xA1,0x92,
+0xD4,0xB3,0xC4,0xC4,0xC3,0xA1,0x88,0x1A,0x28,0x89,0x3C,0x3A,0x3D,0x29,0x00,0x93,
+0xB0,0x3D,0x28,0x80,0x91,0x82,0xE3,0x99,0x2A,0x11,0xD6,0xC3,0x99,0x29,0x82,0xC4,
+0xC3,0xA1,0x0A,0x3B,0x3D,0x3A,0x02,0xC3,0xA2,0x99,0x3B,0x2C,0x7C,0x28,0x81,0xA3,
+0xB2,0xA3,0xB1,0x08,0x1A,0x3C,0x18,0x2E,0x4C,0x39,0xA5,0xB3,0xB4,0xC2,0x88,0x08,
+0x19,0x0A,0x49,0xB7,0xB3,0xA2,0xA1,0x92,0xA1,0x93,0xB1,0x0C,0x7D,0x39,0x93,0xB3,
+0xB1,0x1A,0x19,0x5D,0x28,0xA6,0xC4,0xB2,0x90,0x09,0x2A,0x18,0x1B,0x5B,0x28,0x88,
+0x2C,0x29,0x82,0xA0,0x18,0x91,0x2D,0x29,0x2B,0x5C,0x4C,0x3B,0x4C,0x28,0x80,0x92,
+0x90,0x09,0x2B,0x28,0x1D,0x6B,0x11,0xC5,0xB2,0x0B,0x39,0x09,0x4D,0x28,0x88,0x00,
+0x1B,0x28,0x94,0xE3,0xA0,0x1A,0x28,0xB5,0xB4,0xB3,0xB2,0x93,0xE2,0x91,0x92,0xD4,
+0xA0,0x1B,0x4A,0x01,0xA1,0x88,0x2D,0x5C,0x3B,0x28,0x08,0x93,0xD4,0xB2,0x91,0xB4,
+0xA0,0x3E,0x3B,0x4B,0x3B,0x29,0x08,0x93,0x9B,0x7B,0x3A,0x19,0x00,0x80,0x80,0xA0,
+
+/* Source: 10TOM.ROM */
+/* Length: 640 / 0x00000280 */
+
+0x77,0x27,0x87,0x01,0x2D,0x4F,0xC3,0xC1,0x92,0x91,0x89,0x59,0x83,0x1A,0x32,0xC2,
+0x95,0xB1,0x81,0x88,0x81,0x4A,0x3D,0x11,0x9E,0x0B,0x88,0x0C,0x18,0x3B,0x11,0x11,
+0x91,0x00,0xA0,0xE2,0x0A,0x48,0x13,0x24,0x81,0x48,0x1B,0x39,0x1C,0x83,0x84,0xA1,
+0xD1,0x8E,0x8A,0x0B,0xC0,0x98,0x92,0xB8,0x39,0x90,0x10,0x92,0xF0,0xB5,0x88,0x32,
+0x49,0x51,0x21,0x03,0x82,0x10,0x8A,0x7A,0x09,0x00,0xA2,0xCA,0x1B,0xCC,0x1C,0xB9,
+0x8E,0x89,0x89,0xA1,0x89,0x92,0x29,0x11,0x60,0x40,0x14,0x22,0x32,0x78,0x40,0x01,
+0x02,0x90,0x81,0xAB,0x0B,0x00,0xAF,0x99,0xCC,0xAB,0xDA,0xA9,0x99,0x1B,0x30,0x14,
+0x92,0x22,0x19,0x68,0x32,0x14,0x26,0x13,0x23,0x23,0x20,0x12,0x9A,0xA8,0xB9,0xFA,
+0xAA,0xCA,0xCC,0x0C,0xA8,0xAE,0x88,0xB9,0x88,0xA0,0x02,0x21,0x50,0x43,0x03,0x81,
+0x2A,0x11,0x34,0x63,0x24,0x33,0x22,0x38,0x8B,0xEA,0xAE,0x99,0xA0,0x90,0x82,0x00,
+0x89,0xBF,0x8A,0xE8,0xA9,0x90,0x01,0x12,0x13,0x12,0x08,0xA9,0xAA,0xC9,0x22,0x63,
+0x63,0x12,0x44,0x00,0x10,0x88,0x9C,0x98,0xA1,0x85,0x03,0x32,0x36,0x80,0x89,0xDB,
+0xDB,0xBB,0xB9,0xBA,0x01,0x81,0x28,0x19,0xCB,0xFA,0xBC,0x09,0x13,0x37,0x34,0x34,
+0x23,0x31,0x20,0x10,0x00,0x00,0x28,0x38,0x10,0x88,0xEC,0x8D,0xCB,0xBC,0xCC,0xBB,
+0xBB,0xC9,0x99,0x00,0x00,0x33,0x11,0x22,0x81,0x07,0x41,0x54,0x34,0x34,0x22,0x31,
+0x00,0x88,0x9A,0x9B,0x98,0xAB,0x8E,0x9B,0xBD,0x9C,0xBC,0xBB,0xDA,0xAA,0xA9,0x99,
+0x18,0x38,0x60,0x20,0x31,0x13,0x13,0x51,0x14,0x31,0x53,0x33,0x35,0x22,0x01,0x8A,
+0x9C,0xA9,0xCA,0xC9,0xA8,0x00,0x10,0x81,0x9C,0x9E,0xAB,0xCC,0xAB,0xBA,0x98,0x30,
+0x52,0x03,0x81,0x08,0x9C,0xAC,0xAC,0x18,0x11,0x03,0x51,0x61,0x41,0x31,0x31,0x02,
+0x01,0x20,0x24,0x43,0x44,0x40,0x30,0x10,0xBC,0xBE,0xCB,0xDB,0xAB,0xBA,0x99,0x98,
+0x99,0xAA,0xBD,0xAA,0xC8,0x90,0x11,0x53,0x37,0x23,0x43,0x34,0x33,0x33,0x33,0x11,
+0x28,0x00,0x19,0xA9,0x9A,0xCB,0xCE,0xBB,0xEB,0xBC,0xBB,0xCA,0xBA,0xA8,0x88,0x11,
+0x12,0x21,0x20,0x22,0x26,0x26,0x23,0x23,0x43,0x24,0x22,0x32,0x20,0x31,0x81,0x9A,
+0xBC,0xBC,0xCB,0xBD,0x9A,0xA9,0x90,0x98,0xBA,0xCC,0xCB,0xBC,0x8B,0x88,0x22,0x35,
+0x23,0x12,0x99,0x8B,0xAA,0xAA,0x89,0x82,0x93,0x31,0x42,0x23,0x23,0x21,0x32,0x11,
+0x20,0x13,0x13,0x24,0x24,0x24,0x22,0x11,0x8A,0x9E,0xAC,0xAC,0xAA,0xBA,0xAA,0xAB,
+0xBD,0xBC,0xCB,0xCB,0xA9,0xA8,0x91,0x12,0x44,0x43,0x44,0x34,0x34,0x42,0x33,0x42,
+0x21,0x11,0x11,0x88,0x80,0xAA,0x0B,0xAC,0xCB,0xEC,0xAC,0xBA,0xCA,0xAB,0x9A,0x99,
+0x80,0x91,0x09,0x08,0x10,0x22,0x44,0x43,0x44,0x33,0x43,0x22,0x13,0x21,0x22,0x20,
+0x09,0x88,0xB9,0xC8,0xBB,0xAB,0xAB,0xA9,0xA9,0x9B,0x9B,0x99,0x90,0x90,0x00,0x81,
+0x00,0x08,0x09,0x8A,0x9A,0xAA,0xA9,0xA9,0x99,0x90,0x80,0x01,0x80,0x00,0x09,0x31,
+0x32,0x44,0x33,0x43,0x34,0x33,0x24,0x22,0x23,0x12,0x10,0x09,0x9B,0xAB,0xCA,0xCC,
+0xBB,0xCB,0xDA,0xCA,0xAB,0xCA,0xAB,0xA9,0xA8,0x92,0x12,0x43,0x53,0x35,0x23,0x33,
+0x43,0x43,0x52,0x22,0x22,0x21,0x01,0x09,0x89,0xA9,0xBB,0xBD,0xBC,0xCB,0xDA,0xAB,
+0xAB,0xAB,0xAA,0xA9,0x99,0xA8,0x09,0x01,0x11,0x34,0x25,0x23,0x33,0x51,0x22,0x31,
+0x12,0x20,0x21,0x12,0x10,0x80,0x99,0x9A,0x99,0x99,0x88,0x08,0x00,0x88,0xA9,0x99,
+0x99,0x80,0x80,0x10,0x01,0x00,0x9A,0xAA,0xBB,0xBA,0xBA,0xA9,0x99,0x99,0x89,0x99,
+0x99,0x00,0x01,0x33,0x35,0x24,0x23,0x34,0x23,0x33,0x34,0x33,0x43,0x32,0x21,0x88,
+0xAB,0xBD,0xBB,0xDB,0xAB,0xBA,0xBB,0xDA,0xBB,0xCB,0xBB,0xBC,0xA8,0x90,0x01,0x12,
+0x23,0x43,0x53,0x34,0x34,0x39,0x80,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,
+
+/* Source: 20RIM.ROM */
+/* Length: 128 / 0x00000080 */
+
+0x0F,0xFF,0x73,0x8E,0x71,0xCD,0x00,0x49,0x10,0x90,0x21,0x49,0xA0,0xDB,0x02,0x3A,
+0xE3,0x0A,0x50,0x98,0xC0,0x59,0xA2,0x99,0x09,0x22,0xA2,0x80,0x10,0xA8,0x5B,0xD2,
+0x88,0x21,0x09,0x96,0xA8,0x10,0x0A,0xE0,0x08,0x48,0x19,0xAB,0x52,0xA8,0x92,0x0C,
+0x03,0x19,0xE2,0x0A,0x12,0xC2,0x81,0x1E,0x01,0xD0,0x48,0x88,0x98,0x01,0x49,0x91,
+0xAA,0x2C,0x25,0x89,0x88,0xB5,0x81,0xA2,0x9A,0x12,0x9E,0x38,0x3B,0x81,0x9B,0x59,
+0x01,0x93,0xCA,0x4A,0x21,0xA0,0x3D,0x0A,0x39,0x3D,0x12,0xA8,0x3F,0x18,0x01,0x92,
+0x1C,0x00,0xB2,0x48,0xB9,0x94,0xA3,0x19,0x4F,0x19,0xB2,0x32,0x90,0xBA,0x01,0xE6,
+0x91,0x80,0xC1,0xA4,0x2A,0x08,0xA1,0xB1,0x25,0xD2,0x88,0x99,0x21,0x80,0x88,0x80,
+};
+
+
+
+/* flag enable control 0x110 */
+INLINE void YM2608IRQFlagWrite(FM_OPN *OPN, YM2608 *F2608, int v)
+{
+ if( v & 0x80 )
+ { /* Reset IRQ flag */
+ FM_STATUS_RESET(&OPN->ST, 0xf7); /* don't touch BUFRDY flag otherwise we'd have to call ymdeltat module to set the flag back */
+ }
+ else
+ { /* Set status flag mask */
+ F2608->flagmask = (~(v&0x1f));
+ FM_IRQMASK_SET(&OPN->ST, (F2608->irqmask & F2608->flagmask) );
+ }
+}
+
+/* compatible mode & IRQ enable control 0x29 */
+INLINE void YM2608IRQMaskWrite(FM_OPN *OPN, YM2608 *F2608, int v)
+{
+ /* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */
+
+ /* extend 3ch. enable/disable */
+ if(v&0x80)
+ OPN->type |= TYPE_6CH; /* OPNA mode - 6 FM channels */
+ else
+ OPN->type &= ~TYPE_6CH; /* OPN mode - 3 FM channels */
+
+ /* IRQ MASK store and set */
+ F2608->irqmask = v&0x1f;
+ FM_IRQMASK_SET(&OPN->ST, (F2608->irqmask & F2608->flagmask) );
+}
+
+/* Generate samples for one of the YM2608s */
+void YM2608UpdateOne(void *chip, FMSAMPLE **buffer, int length)
+{
+ YM2608 *F2608 = chip;
+ FM_OPN *OPN = &F2608->OPN;
+ YM_DELTAT *DELTAT = &F2608->deltaT;
+ int i,j;
+ FMSAMPLE *bufL,*bufR;
+ FM_CH *cch[6];
+
+ /* set bufer */
+ bufL = buffer[0];
+ bufR = buffer[1];
+
+ cch[0] = &F2608->CH[0];
+ cch[1] = &F2608->CH[1];
+ cch[2] = &F2608->CH[2];
+ cch[3] = &F2608->CH[3];
+ cch[4] = &F2608->CH[4];
+ cch[5] = &F2608->CH[5];
+ /* setup adpcm rom address */
+ pcmbufA = F2608->pcmbuf;
+ pcmsizeA = F2608->pcm_size;
+
+ /* refresh PG and EG */
+ refresh_fc_eg_chan( cch[0] );
+ refresh_fc_eg_chan( cch[1] );
+ if( (OPN->ST.mode & 0xc0) )
+ {
+ /* 3SLOT MODE */
+ if( cch[2]->SLOT[SLOT1].Incr==-1)
+ {
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
+ }
+ }else refresh_fc_eg_chan( cch[2] );
+ refresh_fc_eg_chan( cch[3] );
+ refresh_fc_eg_chan( cch[4] );
+ refresh_fc_eg_chan( cch[5] );
+
+
+ /* buffering */
+ for(i=0; i < length ; i++)
+ {
+
+ advance_lfo(OPN);
+
+ /* clear output acc. */
+ out_adpcm[OUTD_LEFT] = out_adpcm[OUTD_RIGHT]= out_adpcm[OUTD_CENTER] = 0;
+ out_delta[OUTD_LEFT] = out_delta[OUTD_RIGHT]= out_delta[OUTD_CENTER] = 0;
+ /* clear outputs */
+ out_fm[0] = 0;
+ out_fm[1] = 0;
+ out_fm[2] = 0;
+ out_fm[3] = 0;
+ out_fm[4] = 0;
+ out_fm[5] = 0;
+
+ /* advance envelope generator */
+ OPN->eg_timer += OPN->eg_timer_add;
+ while (OPN->eg_timer >= OPN->eg_timer_overflow)
+ {
+ OPN->eg_timer -= OPN->eg_timer_overflow;
+ OPN->eg_cnt++;
+
+ advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[4]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[5]->SLOT[SLOT1]);
+ }
+
+ /* calculate FM */
+ chan_calc(OPN, cch[0] );
+ chan_calc(OPN, cch[1] );
+ chan_calc(OPN, cch[2] );
+ chan_calc(OPN, cch[3] );
+ chan_calc(OPN, cch[4] );
+ chan_calc(OPN, cch[5] );
+
+ /* deltaT ADPCM */
+ if( DELTAT->portstate&0x80 )
+ YM_DELTAT_ADPCM_CALC(DELTAT);
+
+ /* ADPCMA */
+ for( j = 0; j < 6; j++ )
+ {
+ if( F2608->adpcm[j].flag )
+ ADPCMA_calc_chan( F2608, &F2608->adpcm[j]);
+ }
+
+ /* buffering */
+ {
+ int lt,rt;
+
+ lt = out_adpcm[OUTD_LEFT] + out_adpcm[OUTD_CENTER];
+ rt = out_adpcm[OUTD_RIGHT] + out_adpcm[OUTD_CENTER];
+ lt += (out_delta[OUTD_LEFT] + out_delta[OUTD_CENTER])>>9;
+ rt += (out_delta[OUTD_RIGHT] + out_delta[OUTD_CENTER])>>9;
+ lt += ((out_fm[0]>>1) & OPN->pan[0]); /* shift right verified on real YM2608 */
+ rt += ((out_fm[0]>>1) & OPN->pan[1]);
+ lt += ((out_fm[1]>>1) & OPN->pan[2]);
+ rt += ((out_fm[1]>>1) & OPN->pan[3]);
+ lt += ((out_fm[2]>>1) & OPN->pan[4]);
+ rt += ((out_fm[2]>>1) & OPN->pan[5]);
+ lt += ((out_fm[3]>>1) & OPN->pan[6]);
+ rt += ((out_fm[3]>>1) & OPN->pan[7]);
+ lt += ((out_fm[4]>>1) & OPN->pan[8]);
+ rt += ((out_fm[4]>>1) & OPN->pan[9]);
+ lt += ((out_fm[5]>>1) & OPN->pan[10]);
+ rt += ((out_fm[5]>>1) & OPN->pan[11]);
+
+ lt >>= FINAL_SH;
+ rt >>= FINAL_SH;
+
+ Limit( lt, MAXOUT, MINOUT );
+ Limit( rt, MAXOUT, MINOUT );
+ /* buffering */
+ bufL[i] = lt;
+ bufR[i] = rt;
+
+ #ifdef SAVE_SAMPLE
+ SAVE_ALL_CHANNELS
+ #endif
+
+ }
+
+ /* timer A control */
+ INTERNAL_TIMER_A( &OPN->ST , cch[2] )
+ }
+ INTERNAL_TIMER_B(&OPN->ST,length)
+
+
+ /* check IRQ for DELTA-T EOS */
+ FM_STATUS_SET(&OPN->ST, 0);
+
+}
+#ifdef __STATE_H__
+void YM2608Postload(void *chip)
+{
+ if (chip)
+ {
+ YM2608 *F2608 = (YM2608 *)chip;
+ int r;
+
+ /* prescaler */
+ OPNPrescaler_w(&F2608->OPN,1,2);
+ F2608->deltaT.freqbase = F2608->OPN.ST.freqbase;
+ /* IRQ mask / mode */
+ YM2608IRQMaskWrite(&F2608->OPN, F2608, F2608->REGS[0x29]);
+ /* SSG registers */
+ for(r=0;r<16;r++)
+ {
+ (*F2608->OPN.ST.SSG->write)(F2608->OPN.ST.param,0,r);
+ (*F2608->OPN.ST.SSG->write)(F2608->OPN.ST.param,1,F2608->REGS[r]);
+ }
+
+ /* OPN registers */
+ /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */
+ for(r=0x30;r<0x9e;r++)
+ if((r&3) != 3)
+ {
+ OPNWriteReg(&F2608->OPN,r,F2608->REGS[r]);
+ OPNWriteReg(&F2608->OPN,r|0x100,F2608->REGS[r|0x100]);
+ }
+ /* FB / CONNECT , L / R / AMS / PMS */
+ for(r=0xb0;r<0xb6;r++)
+ if((r&3) != 3)
+ {
+ OPNWriteReg(&F2608->OPN,r,F2608->REGS[r]);
+ OPNWriteReg(&F2608->OPN,r|0x100,F2608->REGS[r|0x100]);
+ }
+ /* FM channels */
+ /*FM_channel_postload(F2608->CH,6);*/
+ /* rhythm(ADPCMA) */
+ FM_ADPCMAWrite(F2608,1,F2608->REGS[0x111]);
+ for( r=0x08 ; r<0x0c ; r++)
+ FM_ADPCMAWrite(F2608,r,F2608->REGS[r+0x110]);
+ /* Delta-T ADPCM unit */
+ YM_DELTAT_postload(&F2608->deltaT , &F2608->REGS[0x100] );
+ }
+}
+
+static void YM2608_save_state(YM2608 *F2608, int index)
+{
+ static const char statename[] = "YM2608";
+
+ state_save_register_item_array(statename, index, F2608->REGS);
+ FMsave_state_st(statename,index,&F2608->OPN.ST);
+ FMsave_state_channel(statename,index,F2608->CH,6);
+ /* 3slots */
+ state_save_register_item_array(statename, index, F2608->OPN.SL3.fc);
+ state_save_register_item(statename, index, F2608->OPN.SL3.fn_h);
+ state_save_register_item_array(statename, index, F2608->OPN.SL3.kcode);
+ /* address register1 */
+ state_save_register_item(statename, index, F2608->addr_A1);
+ /* rythm(ADPCMA) */
+ FMsave_state_adpcma(statename,index,F2608->adpcm);
+ /* Delta-T ADPCM unit */
+ YM_DELTAT_savestate(statename,index,&F2608->deltaT);
+}
+#endif /* _STATE_H */
+
+static void YM2608_deltat_status_set(void *chip, UINT8 changebits)
+{
+ YM2608 *F2608 = chip;
+ FM_STATUS_SET(&(F2608->OPN.ST), changebits);
+}
+static void YM2608_deltat_status_reset(void *chip, UINT8 changebits)
+{
+ YM2608 *F2608 = chip;
+ FM_STATUS_RESET(&(F2608->OPN.ST), changebits);
+}
+/* YM2608(OPNA) */
+void * YM2608Init(void *param, int index, int clock, int rate,
+ void *pcmrom,int pcmsize,
+ FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler, const struct ssg_callbacks *ssg)
+{
+ YM2608 *F2608;
+
+ /* allocate extend state space */
+ if( (F2608 = (YM2608 *)malloc(sizeof(YM2608)))==NULL)
+ return NULL;
+ /* clear */
+ memset(F2608,0,sizeof(YM2608));
+ /* allocate total level table (128kb space) */
+ if( !init_tables() )
+ {
+ free( F2608 );
+ return NULL;
+ }
+
+ F2608->OPN.ST.param = param;
+ F2608->OPN.type = TYPE_YM2608;
+ F2608->OPN.P_CH = F2608->CH;
+ F2608->OPN.ST.clock = clock;
+ F2608->OPN.ST.rate = rate;
+
+ /* External handlers */
+ F2608->OPN.ST.timer_handler = timer_handler;
+ F2608->OPN.ST.IRQ_Handler = IRQHandler;
+ F2608->OPN.ST.SSG = ssg;
+
+ /* DELTA-T */
+ F2608->deltaT.memory = (UINT8 *)pcmrom;
+ F2608->deltaT.memory_size = pcmsize;
+
+ /*F2608->deltaT.write_time = 20.0 / clock;*/ /* a single byte write takes 20 cycles of main clock */
+ /*F2608->deltaT.read_time = 18.0 / clock;*/ /* a single byte read takes 18 cycles of main clock */
+
+ F2608->deltaT.status_set_handler = YM2608_deltat_status_set;
+ F2608->deltaT.status_reset_handler = YM2608_deltat_status_reset;
+ F2608->deltaT.status_change_which_chip = F2608;
+ F2608->deltaT.status_change_EOS_bit = 0x04; /* status flag: set bit2 on End Of Sample */
+ F2608->deltaT.status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY */
+ F2608->deltaT.status_change_ZERO_bit = 0x10; /* status flag: set bit4 if silence continues for more than 290 miliseconds while recording the ADPCM */
+
+ /* ADPCM Rhythm */
+ F2608->pcmbuf = YM2608_ADPCM_ROM;
+ F2608->pcm_size = 0x2000;
+
+ YM2608ResetChip(F2608);
+
+ Init_ADPCMATable();
+
+#ifdef __STATE_H__
+ YM2608_save_state(F2608, index);
+#endif
+ return F2608;
+}
+
+/* shut down emulator */
+void YM2608Shutdown(void *chip)
+{
+ YM2608 *F2608 = chip;
+
+ FMCloseTable();
+ free(F2608);
+}
+
+/* reset one of chips */
+void YM2608ResetChip(void *chip)
+{
+ int i;
+ YM2608 *F2608 = chip;
+ FM_OPN *OPN = &F2608->OPN;
+ YM_DELTAT *DELTAT = &F2608->deltaT;
+
+ /* Reset Prescaler */
+ OPNPrescaler_w(OPN , 0 , 2);
+ F2608->deltaT.freqbase = OPN->ST.freqbase;
+ /* reset SSG section */
+ (*OPN->ST.SSG->reset)(OPN->ST.param);
+
+ /* status clear */
+ FM_BUSY_CLEAR(&OPN->ST);
+
+ /* register 0x29 - default value after reset is:
+ enable only 3 FM channels and enable all the status flags */
+ YM2608IRQMaskWrite(OPN, F2608, 0x1f ); /* default value for D4-D0 is 1 */
+
+ /* register 0x10, A1=1 - default value is 1 for D4, D3, D2, 0 for the rest */
+ YM2608IRQFlagWrite(OPN, F2608, 0x1c ); /* default: enable timer A and B, disable EOS, BRDY and ZERO */
+
+ OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */
+
+ OPN->eg_timer = 0;
+ OPN->eg_cnt = 0;
+
+ FM_STATUS_RESET(&OPN->ST, 0xff);
+
+ reset_channels( &OPN->ST , F2608->CH , 6 );
+ /* reset OPerator paramater */
+ for(i = 0xb6 ; i >= 0xb4 ; i-- )
+ {
+ OPNWriteReg(OPN,i ,0xc0);
+ OPNWriteReg(OPN,i|0x100,0xc0);
+ }
+ for(i = 0xb2 ; i >= 0x30 ; i-- )
+ {
+ OPNWriteReg(OPN,i ,0);
+ OPNWriteReg(OPN,i|0x100,0);
+ }
+ for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
+
+ /* ADPCM - percussion sounds */
+ for( i = 0; i < 6; i++ )
+ {
+ if (i<=3) /* channels 0,1,2,3 */
+ F2608->adpcm[i].step = (UINT32)((float)(1<<ADPCM_SHIFT)*((float)F2608->OPN.ST.freqbase)/3.0);
+ else /* channels 4 and 5 work with slower clock */
+ F2608->adpcm[i].step = (UINT32)((float)(1<<ADPCM_SHIFT)*((float)F2608->OPN.ST.freqbase)/6.0);
+
+ F2608->adpcm[i].start = YM2608_ADPCM_ROM_addr[i*2];
+ F2608->adpcm[i].end = YM2608_ADPCM_ROM_addr[i*2+1];
+
+ F2608->adpcm[i].now_addr = 0;
+ F2608->adpcm[i].now_step = 0;
+ /* F2608->adpcm[i].delta = 21866; */
+ F2608->adpcm[i].vol_mul = 0;
+ F2608->adpcm[i].pan = &out_adpcm[OUTD_CENTER]; /* default center */
+ F2608->adpcm[i].flagMask = 0;
+ F2608->adpcm[i].flag = 0;
+ F2608->adpcm[i].adpcm_acc = 0;
+ F2608->adpcm[i].adpcm_step= 0;
+ F2608->adpcm[i].adpcm_out = 0;
+ }
+ F2608->adpcmTL = 0x3f;
+
+ F2608->adpcm_arrivedEndAddress = 0; /* not used */
+
+ /* DELTA-T unit */
+ DELTAT->freqbase = OPN->ST.freqbase;
+ DELTAT->output_pointer = out_delta;
+ DELTAT->portshift = 5; /* always 5bits shift */ /* ASG */
+ DELTAT->output_range = 1<<23;
+ YM_DELTAT_ADPCM_Reset(DELTAT,OUTD_CENTER,YM_DELTAT_EMULATION_MODE_NORMAL);
+}
+
+/* YM2608 write */
+/* n = number */
+/* a = address */
+/* v = value */
+int YM2608Write(void *chip, int a,UINT8 v)
+{
+ YM2608 *F2608 = chip;
+ FM_OPN *OPN = &F2608->OPN;
+ int addr;
+
+ v &= 0xff; /*adjust to 8 bit bus */
+
+
+ switch(a&3)
+ {
+ case 0: /* address port 0 */
+ OPN->ST.address = v;
+ F2608->addr_A1 = 0;
+
+ /* Write register to SSG emulator */
+ if( v < 16 ) (*OPN->ST.SSG->write)(OPN->ST.param,0,v);
+ /* prescaler selecter : 2d,2e,2f */
+ if( v >= 0x2d && v <= 0x2f )
+ {
+ OPNPrescaler_w(OPN , v , 2);
+ F2608->deltaT.freqbase = OPN->ST.freqbase;
+ }
+ break;
+
+ case 1: /* data port 0 */
+ if (F2608->addr_A1 != 0)
+ break; /* verified on real YM2608 */
+
+ addr = OPN->ST.address;
+ F2608->REGS[addr] = v;
+ switch(addr & 0xf0)
+ {
+ case 0x00: /* SSG section */
+ /* Write data to SSG emulator */
+ (*OPN->ST.SSG->write)(OPN->ST.param,a,v);
+ break;
+ case 0x10: /* 0x10-0x1f : Rhythm section */
+ YM2608UpdateReq(OPN->ST.param);
+ FM_ADPCMAWrite(F2608,addr-0x10,v);
+ break;
+ case 0x20: /* Mode Register */
+ switch(addr)
+ {
+ case 0x29: /* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */
+ YM2608IRQMaskWrite(OPN, F2608, v);
+ break;
+ default:
+ YM2608UpdateReq(OPN->ST.param);
+ OPNWriteMode(OPN,addr,v);
+ }
+ break;
+ default: /* OPN section */
+ YM2608UpdateReq(OPN->ST.param);
+ OPNWriteReg(OPN,addr,v);
+ }
+ break;
+
+ case 2: /* address port 1 */
+ OPN->ST.address = v;
+ F2608->addr_A1 = 1;
+ break;
+
+ case 3: /* data port 1 */
+ if (F2608->addr_A1 != 1)
+ break; /* verified on real YM2608 */
+
+ addr = OPN->ST.address;
+ F2608->REGS[addr | 0x100] = v;
+ YM2608UpdateReq(OPN->ST.param);
+ switch( addr & 0xf0 )
+ {
+ case 0x00: /* DELTAT PORT */
+ switch( addr )
+ {
+ case 0x0e: /* DAC data */
+ logerror("YM2608: write to DAC data (unimplemented) value=%02x\n",v);
+ break;
+ default:
+ /* 0x00-0x0d */
+ YM_DELTAT_ADPCM_Write(&F2608->deltaT,addr,v);
+ }
+ break;
+ case 0x10: /* IRQ Flag control */
+ if( addr == 0x10 )
+ {
+ YM2608IRQFlagWrite(OPN, F2608, v);
+ }
+ break;
+ default:
+ OPNWriteReg(OPN,addr | 0x100,v);
+ }
+ }
+ return OPN->ST.irq;
+}
+
+UINT8 YM2608Read(void *chip,int a)
+{
+ YM2608 *F2608 = chip;
+ int addr = F2608->OPN.ST.address;
+ UINT8 ret = 0;
+
+ switch( a&3 ){
+ case 0: /* status 0 : YM2203 compatible */
+ /* BUSY:x:x:x:x:x:FLAGB:FLAGA */
+ ret = FM_STATUS_FLAG(&F2608->OPN.ST) & 0x83;
+ break;
+
+ case 1: /* status 0, ID */
+ if( addr < 16 ) ret = (*F2608->OPN.ST.SSG->read)(F2608->OPN.ST.param);
+ else if(addr == 0xff) ret = 0x01; /* ID code */
+ break;
+
+ case 2: /* status 1 : status 0 + ADPCM status */
+ /* BUSY : x : PCMBUSY : ZERO : BRDY : EOS : FLAGB : FLAGA */
+ ret = (FM_STATUS_FLAG(&F2608->OPN.ST) & (F2608->flagmask|0x80)) | ((F2608->deltaT.PCM_BSY & 1)<<5) ;
+ break;
+
+ case 3:
+ if(addr == 0x08)
+ {
+ ret = YM_DELTAT_ADPCM_Read(&F2608->deltaT);
+ }
+ else
+ {
+ if(addr == 0x0f)
+ {
+ logerror("YM2608 A/D convertion is accessed but not implemented !\n");
+ ret = 0x80; /* 2's complement PCM data - result from A/D convertion */
+ }
+ }
+ break;
+ }
+ return ret;
+}
+
+int YM2608TimerOver(void *chip,int c)
+{
+ YM2608 *F2608 = chip;
+
+ switch(c)
+ {
+#if 0
+ case 2:
+ { /* BUFRDY flag */
+ YM_DELTAT_BRDY_callback( &F2608->deltaT );
+ }
+ break;
+#endif
+ case 1:
+ { /* Timer B */
+ TimerBOver( &(F2608->OPN.ST) );
+ }
+ break;
+ case 0:
+ { /* Timer A */
+ YM2608UpdateReq(F2608->OPN.ST.param);
+ /* timer update */
+ TimerAOver( &(F2608->OPN.ST) );
+ /* CSM mode key,TL controll */
+ if( F2608->OPN.ST.mode & 0x80 )
+ { /* CSM mode total level latch and auto key on */
+ CSMKeyControll( &(F2608->CH[2]) );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return F2608->OPN.ST.irq;
+}
+
+#endif /* BUILD_YM2608 */
+
+
+
+#if (BUILD_YM2610||BUILD_YM2610B)
+/* YM2610(OPNB) */
+
+/* Generate samples for one of the YM2610s */
+void YM2610UpdateOne(void *chip, FMSAMPLE **buffer, int length)
+{
+ YM2610 *F2610 = chip;
+ FM_OPN *OPN = &F2610->OPN;
+ YM_DELTAT *DELTAT = &F2610->deltaT;
+ int i,j;
+ FMSAMPLE *bufL,*bufR;
+ FM_CH *cch[4];
+
+ /* buffer setup */
+ bufL = buffer[0];
+ bufR = buffer[1];
+
+ cch[0] = &F2610->CH[1];
+ cch[1] = &F2610->CH[2];
+ cch[2] = &F2610->CH[4];
+ cch[3] = &F2610->CH[5];
+ /* setup adpcm rom address */
+ pcmbufA = F2610->pcmbuf;
+ pcmsizeA = F2610->pcm_size;
+
+#ifdef YM2610B_WARNING
+#define FM_KEY_IS(SLOT) ((SLOT)->key)
+#define FM_MSG_YM2610B "YM2610-%p.CH%d is playing,Check whether the type of the chip is YM2610B\n"
+ /* Check YM2610B warning message */
+ if( FM_KEY_IS(&F2610->CH[0].SLOT[3]) )
+ LOG(LOG_WAR,(FM_MSG_YM2610B,F2610->OPN.ST.param,0));
+ if( FM_KEY_IS(&F2610->CH[3].SLOT[3]) )
+ LOG(LOG_WAR,(FM_MSG_YM2610B,F2610->OPN.ST.param,3));
+#endif
+
+ /* refresh PG and EG */
+ refresh_fc_eg_chan( cch[0] );
+ if( (OPN->ST.mode & 0xc0) )
+ {
+ /* 3SLOT MODE */
+ if( cch[1]->SLOT[SLOT1].Incr==-1)
+ {
+ refresh_fc_eg_slot(&cch[1]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
+ refresh_fc_eg_slot(&cch[1]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
+ refresh_fc_eg_slot(&cch[1]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
+ refresh_fc_eg_slot(&cch[1]->SLOT[SLOT4] , cch[1]->fc , cch[1]->kcode );
+ }
+ }else refresh_fc_eg_chan( cch[1] );
+ refresh_fc_eg_chan( cch[2] );
+ refresh_fc_eg_chan( cch[3] );
+
+ /* buffering */
+ for(i=0; i < length ; i++)
+ {
+
+ advance_lfo(OPN);
+
+ /* clear output acc. */
+ out_adpcm[OUTD_LEFT] = out_adpcm[OUTD_RIGHT]= out_adpcm[OUTD_CENTER] = 0;
+ out_delta[OUTD_LEFT] = out_delta[OUTD_RIGHT]= out_delta[OUTD_CENTER] = 0;
+ /* clear outputs */
+ out_fm[1] = 0;
+ out_fm[2] = 0;
+ out_fm[4] = 0;
+ out_fm[5] = 0;
+
+ /* advance envelope generator */
+ OPN->eg_timer += OPN->eg_timer_add;
+ while (OPN->eg_timer >= OPN->eg_timer_overflow)
+ {
+ OPN->eg_timer -= OPN->eg_timer_overflow;
+ OPN->eg_cnt++;
+
+ advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]);
+ }
+
+ /* calculate FM */
+ chan_calc(OPN, cch[0] ); /*remapped to 1*/
+ chan_calc(OPN, cch[1] ); /*remapped to 2*/
+ chan_calc(OPN, cch[2] ); /*remapped to 4*/
+ chan_calc(OPN, cch[3] ); /*remapped to 5*/
+
+ /* deltaT ADPCM */
+ if( DELTAT->portstate&0x80 )
+ YM_DELTAT_ADPCM_CALC(DELTAT);
+
+ /* ADPCMA */
+ for( j = 0; j < 6; j++ )
+ {
+ if( F2610->adpcm[j].flag )
+ ADPCMA_calc_chan( F2610, &F2610->adpcm[j]);
+ }
+
+ /* buffering */
+ {
+ int lt,rt;
+
+ lt = out_adpcm[OUTD_LEFT] + out_adpcm[OUTD_CENTER];
+ rt = out_adpcm[OUTD_RIGHT] + out_adpcm[OUTD_CENTER];
+ lt += (out_delta[OUTD_LEFT] + out_delta[OUTD_CENTER])>>9;
+ rt += (out_delta[OUTD_RIGHT] + out_delta[OUTD_CENTER])>>9;
+
+
+ lt += ((out_fm[1]>>1) & OPN->pan[2]); /* the shift right was verified on real chip */
+ rt += ((out_fm[1]>>1) & OPN->pan[3]);
+ lt += ((out_fm[2]>>1) & OPN->pan[4]);
+ rt += ((out_fm[2]>>1) & OPN->pan[5]);
+
+ lt += ((out_fm[4]>>1) & OPN->pan[8]);
+ rt += ((out_fm[4]>>1) & OPN->pan[9]);
+ lt += ((out_fm[5]>>1) & OPN->pan[10]);
+ rt += ((out_fm[5]>>1) & OPN->pan[11]);
+
+
+ lt >>= FINAL_SH;
+ rt >>= FINAL_SH;
+
+ Limit( lt, MAXOUT, MINOUT );
+ Limit( rt, MAXOUT, MINOUT );
+
+ #ifdef SAVE_SAMPLE
+ SAVE_ALL_CHANNELS
+ #endif
+
+ /* buffering */
+ bufL[i] = lt;
+ bufR[i] = rt;
+ }
+
+ /* timer A control */
+ INTERNAL_TIMER_A( &OPN->ST , cch[1] )
+ }
+ INTERNAL_TIMER_B(&OPN->ST,length)
+
+}
+
+#if BUILD_YM2610B
+/* Generate samples for one of the YM2610Bs */
+void YM2610BUpdateOne(void *chip, FMSAMPLE **buffer, int length)
+{
+ YM2610 *F2610 = chip;
+ FM_OPN *OPN = &F2610->OPN;
+ YM_DELTAT *DELTAT = &F2610->deltaT;
+ int i,j;
+ FMSAMPLE *bufL,*bufR;
+ FM_CH *cch[6];
+
+ /* buffer setup */
+ bufL = buffer[0];
+ bufR = buffer[1];
+
+ cch[0] = &F2610->CH[0];
+ cch[1] = &F2610->CH[1];
+ cch[2] = &F2610->CH[2];
+ cch[3] = &F2610->CH[3];
+ cch[4] = &F2610->CH[4];
+ cch[5] = &F2610->CH[5];
+ /* setup adpcm rom address */
+ pcmbufA = F2610->pcmbuf;
+ pcmsizeA = F2610->pcm_size;
+
+ /* refresh PG and EG */
+ refresh_fc_eg_chan( cch[0] );
+ refresh_fc_eg_chan( cch[1] );
+ if( (OPN->ST.mode & 0xc0) )
+ {
+ /* 3SLOT MODE */
+ if( cch[2]->SLOT[SLOT1].Incr==-1)
+ {
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
+ }
+ }else refresh_fc_eg_chan( cch[2] );
+ refresh_fc_eg_chan( cch[3] );
+ refresh_fc_eg_chan( cch[4] );
+ refresh_fc_eg_chan( cch[5] );
+
+ /* buffering */
+ for(i=0; i < length ; i++)
+ {
+
+ advance_lfo(OPN);
+
+ /* clear output acc. */
+ out_adpcm[OUTD_LEFT] = out_adpcm[OUTD_RIGHT]= out_adpcm[OUTD_CENTER] = 0;
+ out_delta[OUTD_LEFT] = out_delta[OUTD_RIGHT]= out_delta[OUTD_CENTER] = 0;
+ /* clear outputs */
+ out_fm[0] = 0;
+ out_fm[1] = 0;
+ out_fm[2] = 0;
+ out_fm[3] = 0;
+ out_fm[4] = 0;
+ out_fm[5] = 0;
+
+ /* advance envelope generator */
+ OPN->eg_timer += OPN->eg_timer_add;
+ while (OPN->eg_timer >= OPN->eg_timer_overflow)
+ {
+ OPN->eg_timer -= OPN->eg_timer_overflow;
+ OPN->eg_cnt++;
+
+ advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[4]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[5]->SLOT[SLOT1]);
+ }
+
+ /* calculate FM */
+ chan_calc(OPN, cch[0] );
+ chan_calc(OPN, cch[1] );
+ chan_calc(OPN, cch[2] );
+ chan_calc(OPN, cch[3] );
+ chan_calc(OPN, cch[4] );
+ chan_calc(OPN, cch[5] );
+
+ /* deltaT ADPCM */
+ if( DELTAT->portstate&0x80 )
+ YM_DELTAT_ADPCM_CALC(DELTAT);
+
+ /* ADPCMA */
+ for( j = 0; j < 6; j++ )
+ {
+ if( F2610->adpcm[j].flag )
+ ADPCMA_calc_chan( F2610, &F2610->adpcm[j]);
+ }
+
+ /* buffering */
+ {
+ int lt,rt;
+
+ lt = out_adpcm[OUTD_LEFT] + out_adpcm[OUTD_CENTER];
+ rt = out_adpcm[OUTD_RIGHT] + out_adpcm[OUTD_CENTER];
+ lt += (out_delta[OUTD_LEFT] + out_delta[OUTD_CENTER])>>9;
+ rt += (out_delta[OUTD_RIGHT] + out_delta[OUTD_CENTER])>>9;
+
+ lt += ((out_fm[0]>>1) & OPN->pan[0]); /* the shift right is verified on YM2610 */
+ rt += ((out_fm[0]>>1) & OPN->pan[1]);
+ lt += ((out_fm[1]>>1) & OPN->pan[2]);
+ rt += ((out_fm[1]>>1) & OPN->pan[3]);
+ lt += ((out_fm[2]>>1) & OPN->pan[4]);
+ rt += ((out_fm[2]>>1) & OPN->pan[5]);
+ lt += ((out_fm[3]>>1) & OPN->pan[6]);
+ rt += ((out_fm[3]>>1) & OPN->pan[7]);
+ lt += ((out_fm[4]>>1) & OPN->pan[8]);
+ rt += ((out_fm[4]>>1) & OPN->pan[9]);
+ lt += ((out_fm[5]>>1) & OPN->pan[10]);
+ rt += ((out_fm[5]>>1) & OPN->pan[11]);
+
+
+ lt >>= FINAL_SH;
+ rt >>= FINAL_SH;
+
+ Limit( lt, MAXOUT, MINOUT );
+ Limit( rt, MAXOUT, MINOUT );
+
+ #ifdef SAVE_SAMPLE
+ SAVE_ALL_CHANNELS
+ #endif
+
+ /* buffering */
+ bufL[i] = lt;
+ bufR[i] = rt;
+ }
+
+ /* timer A control */
+ INTERNAL_TIMER_A( &OPN->ST , cch[2] )
+ }
+ INTERNAL_TIMER_B(&OPN->ST,length)
+
+}
+#endif /* BUILD_YM2610B */
+
+
+#ifdef __STATE_H__
+void YM2610Postload(void *chip)
+{
+ if (chip)
+ {
+ YM2610 *F2610 = (YM2610 *)chip;
+ int r;
+
+ /* SSG registers */
+ for(r=0;r<16;r++)
+ {
+ (*F2610->OPN.ST.SSG->write)(F2610->OPN.ST.param,0,r);
+ (*F2610->OPN.ST.SSG->write)(F2610->OPN.ST.param,1,F2610->REGS[r]);
+ }
+
+ /* OPN registers */
+ /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */
+ for(r=0x30;r<0x9e;r++)
+ if((r&3) != 3)
+ {
+ OPNWriteReg(&F2610->OPN,r,F2610->REGS[r]);
+ OPNWriteReg(&F2610->OPN,r|0x100,F2610->REGS[r|0x100]);
+ }
+ /* FB / CONNECT , L / R / AMS / PMS */
+ for(r=0xb0;r<0xb6;r++)
+ if((r&3) != 3)
+ {
+ OPNWriteReg(&F2610->OPN,r,F2610->REGS[r]);
+ OPNWriteReg(&F2610->OPN,r|0x100,F2610->REGS[r|0x100]);
+ }
+ /* FM channels */
+ /*FM_channel_postload(F2610->CH,6);*/
+
+ /* rhythm(ADPCMA) */
+ FM_ADPCMAWrite(F2610,1,F2610->REGS[0x101]);
+ for( r=0 ; r<6 ; r++)
+ {
+ FM_ADPCMAWrite(F2610,r+0x08,F2610->REGS[r+0x108]);
+ FM_ADPCMAWrite(F2610,r+0x10,F2610->REGS[r+0x110]);
+ FM_ADPCMAWrite(F2610,r+0x18,F2610->REGS[r+0x118]);
+ FM_ADPCMAWrite(F2610,r+0x20,F2610->REGS[r+0x120]);
+ FM_ADPCMAWrite(F2610,r+0x28,F2610->REGS[r+0x128]);
+ }
+ /* Delta-T ADPCM unit */
+ YM_DELTAT_postload(&F2610->deltaT , &F2610->REGS[0x010] );
+ }
+}
+
+static void YM2610_save_state(YM2610 *F2610, int index)
+{
+ static const char statename[] = "YM2610";
+
+ state_save_register_item_array(statename, index, F2610->REGS);
+ FMsave_state_st(statename,index,&F2610->OPN.ST);
+ FMsave_state_channel(statename,index,F2610->CH,6);
+ /* 3slots */
+ state_save_register_item_array(statename, index, F2610->OPN.SL3.fc);
+ state_save_register_item(statename, index, F2610->OPN.SL3.fn_h);
+ state_save_register_item_array(statename, index, F2610->OPN.SL3.kcode);
+ /* address register1 */
+ state_save_register_item(statename, index, F2610->addr_A1);
+
+ state_save_register_item(statename, index, F2610->adpcm_arrivedEndAddress);
+ /* rythm(ADPCMA) */
+ FMsave_state_adpcma(statename,index,F2610->adpcm);
+ /* Delta-T ADPCM unit */
+ YM_DELTAT_savestate(statename,index,&F2610->deltaT);
+}
+#endif /* _STATE_H */
+
+static void YM2610_deltat_status_set(void *chip, UINT8 changebits)
+{
+ YM2610 *F2610 = chip;
+ F2610->adpcm_arrivedEndAddress |= changebits;
+}
+static void YM2610_deltat_status_reset(void *chip, UINT8 changebits)
+{
+ YM2610 *F2610 = chip;
+ F2610->adpcm_arrivedEndAddress &= (~changebits);
+}
+
+void *YM2610Init(void *param, int index, int clock, int rate,
+ void *pcmroma,int pcmsizea,void *pcmromb,int pcmsizeb,
+ FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler, const struct ssg_callbacks *ssg)
+
+{
+ YM2610 *F2610;
+
+ /* allocate extend state space */
+ if( (F2610 = (YM2610 *)malloc(sizeof(YM2610)))==NULL)
+ return NULL;
+ /* clear */
+ memset(F2610,0,sizeof(YM2610));
+ /* allocate total level table (128kb space) */
+ if( !init_tables() )
+ {
+ free( F2610 );
+ return NULL;
+ }
+
+ /* FM */
+ F2610->OPN.ST.param = param;
+ F2610->OPN.type = TYPE_YM2610;
+ F2610->OPN.P_CH = F2610->CH;
+ F2610->OPN.ST.clock = clock;
+ F2610->OPN.ST.rate = rate;
+ /* Extend handler */
+ F2610->OPN.ST.timer_handler = timer_handler;
+ F2610->OPN.ST.IRQ_Handler = IRQHandler;
+ F2610->OPN.ST.SSG = ssg;
+ /* ADPCM */
+ F2610->pcmbuf = (UINT8 *)pcmroma;
+ F2610->pcm_size = pcmsizea;
+ /* DELTA-T */
+ F2610->deltaT.memory = (UINT8 *)pcmromb;
+ F2610->deltaT.memory_size = pcmsizeb;
+
+ F2610->deltaT.status_set_handler = YM2610_deltat_status_set;
+ F2610->deltaT.status_reset_handler = YM2610_deltat_status_reset;
+ F2610->deltaT.status_change_which_chip = F2610;
+ F2610->deltaT.status_change_EOS_bit = 0x80; /* status flag: set bit7 on End Of Sample */
+
+ YM2610ResetChip(F2610);
+
+ Init_ADPCMATable();
+#ifdef __STATE_H__
+ YM2610_save_state(F2610, index);
+#endif
+ return F2610;
+}
+
+/* shut down emulator */
+void YM2610Shutdown(void *chip)
+{
+ YM2610 *F2610 = chip;
+
+ FMCloseTable();
+ free(F2610);
+}
+
+/* reset one of chip */
+void YM2610ResetChip(void *chip)
+{
+ int i;
+ YM2610 *F2610 = chip;
+ FM_OPN *OPN = &F2610->OPN;
+ YM_DELTAT *DELTAT = &F2610->deltaT;
+
+ /* Reset Prescaler */
+ OPNSetPres( OPN, 6*24, 6*24, 4*2); /* OPN 1/6 , SSG 1/4 */
+ /* reset SSG section */
+ (*OPN->ST.SSG->reset)(OPN->ST.param);
+ /* status clear */
+ FM_IRQMASK_SET(&OPN->ST,0x03);
+ FM_BUSY_CLEAR(&OPN->ST);
+ OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */
+
+ OPN->eg_timer = 0;
+ OPN->eg_cnt = 0;
+
+ FM_STATUS_RESET(&OPN->ST, 0xff);
+
+ reset_channels( &OPN->ST , F2610->CH , 6 );
+ /* reset OPerator paramater */
+ for(i = 0xb6 ; i >= 0xb4 ; i-- )
+ {
+ OPNWriteReg(OPN,i ,0xc0);
+ OPNWriteReg(OPN,i|0x100,0xc0);
+ }
+ for(i = 0xb2 ; i >= 0x30 ; i-- )
+ {
+ OPNWriteReg(OPN,i ,0);
+ OPNWriteReg(OPN,i|0x100,0);
+ }
+ for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
+ /**** ADPCM work initial ****/
+ for( i = 0; i < 6 ; i++ ){
+ F2610->adpcm[i].step = (UINT32)((float)(1<<ADPCM_SHIFT)*((float)F2610->OPN.ST.freqbase)/3.0);
+ F2610->adpcm[i].now_addr = 0;
+ F2610->adpcm[i].now_step = 0;
+ F2610->adpcm[i].start = 0;
+ F2610->adpcm[i].end = 0;
+ /* F2610->adpcm[i].delta = 21866; */
+ F2610->adpcm[i].vol_mul = 0;
+ F2610->adpcm[i].pan = &out_adpcm[OUTD_CENTER]; /* default center */
+ F2610->adpcm[i].flagMask = 1<<i;
+ F2610->adpcm[i].flag = 0;
+ F2610->adpcm[i].adpcm_acc = 0;
+ F2610->adpcm[i].adpcm_step= 0;
+ F2610->adpcm[i].adpcm_out = 0;
+ }
+ F2610->adpcmTL = 0x3f;
+
+ F2610->adpcm_arrivedEndAddress = 0;
+
+ /* DELTA-T unit */
+ DELTAT->freqbase = OPN->ST.freqbase;
+ DELTAT->output_pointer = out_delta;
+ DELTAT->portshift = 8; /* allways 8bits shift */
+ DELTAT->output_range = 1<<23;
+ YM_DELTAT_ADPCM_Reset(DELTAT,OUTD_CENTER,YM_DELTAT_EMULATION_MODE_YM2610);
+}
+
+/* YM2610 write */
+/* n = number */
+/* a = address */
+/* v = value */
+int YM2610Write(void *chip, int a, UINT8 v)
+{
+ YM2610 *F2610 = chip;
+ FM_OPN *OPN = &F2610->OPN;
+ int addr;
+ int ch;
+
+ v &= 0xff; /* adjust to 8 bit bus */
+
+ switch( a&3 ){
+ case 0: /* address port 0 */
+ OPN->ST.address = v;
+ F2610->addr_A1 = 0;
+
+ /* Write register to SSG emulator */
+ if( v < 16 ) (*OPN->ST.SSG->write)(OPN->ST.param,0,v);
+ break;
+
+ case 1: /* data port 0 */
+ if (F2610->addr_A1 != 0)
+ break; /* verified on real YM2608 */
+
+ addr = OPN->ST.address;
+ F2610->REGS[addr] = v;
+ switch(addr & 0xf0)
+ {
+ case 0x00: /* SSG section */
+ /* Write data to SSG emulator */
+ (*OPN->ST.SSG->write)(OPN->ST.param,a,v);
+ break;
+ case 0x10: /* DeltaT ADPCM */
+ YM2610UpdateReq(OPN->ST.param);
+
+ switch(addr)
+ {
+ case 0x10: /* control 1 */
+ case 0x11: /* control 2 */
+ case 0x12: /* start address L */
+ case 0x13: /* start address H */
+ case 0x14: /* stop address L */
+ case 0x15: /* stop address H */
+
+ case 0x19: /* delta-n L */
+ case 0x1a: /* delta-n H */
+ case 0x1b: /* volume */
+ {
+ YM_DELTAT_ADPCM_Write(&F2610->deltaT,addr-0x10,v);
+ }
+ break;
+
+ case 0x1c: /* FLAG CONTROL : Extend Status Clear/Mask */
+ {
+ UINT8 statusmask = ~v;
+ /* set arrived flag mask */
+ for(ch=0;ch<6;ch++)
+ F2610->adpcm[ch].flagMask = statusmask&(1<<ch);
+
+ F2610->deltaT.status_change_EOS_bit = statusmask & 0x80; /* status flag: set bit7 on End Of Sample */
+
+ /* clear arrived flag */
+ F2610->adpcm_arrivedEndAddress &= statusmask;
+ }
+ break;
+
+ default:
+ logerror("YM2610: write to unknown deltat register %02x val=%02x\n",addr,v);
+ break;
+ }
+
+ break;
+ case 0x20: /* Mode Register */
+ YM2610UpdateReq(OPN->ST.param);
+ OPNWriteMode(OPN,addr,v);
+ break;
+ default: /* OPN section */
+ YM2610UpdateReq(OPN->ST.param);
+ /* write register */
+ OPNWriteReg(OPN,addr,v);
+ }
+ break;
+
+ case 2: /* address port 1 */
+ OPN->ST.address = v;
+ F2610->addr_A1 = 1;
+ break;
+
+ case 3: /* data port 1 */
+ if (F2610->addr_A1 != 1)
+ break; /* verified on real YM2608 */
+
+ YM2610UpdateReq(OPN->ST.param);
+ addr = OPN->ST.address;
+ F2610->REGS[addr | 0x100] = v;
+ if( addr < 0x30 )
+ /* 100-12f : ADPCM A section */
+ FM_ADPCMAWrite(F2610,addr,v);
+ else
+ OPNWriteReg(OPN,addr | 0x100,v);
+ }
+ return OPN->ST.irq;
+}
+
+UINT8 YM2610Read(void *chip,int a)
+{
+ YM2610 *F2610 = chip;
+ int addr = F2610->OPN.ST.address;
+ UINT8 ret = 0;
+
+ switch( a&3){
+ case 0: /* status 0 : YM2203 compatible */
+ ret = FM_STATUS_FLAG(&F2610->OPN.ST) & 0x83;
+ break;
+ case 1: /* data 0 */
+ if( addr < 16 ) ret = (*F2610->OPN.ST.SSG->read)(F2610->OPN.ST.param);
+ if( addr == 0xff ) ret = 0x01;
+ break;
+ case 2: /* status 1 : ADPCM status */
+ /* ADPCM STATUS (arrived End Address) */
+ /* B,--,A5,A4,A3,A2,A1,A0 */
+ /* B = ADPCM-B(DELTA-T) arrived end address */
+ /* A0-A5 = ADPCM-A arrived end address */
+ ret = F2610->adpcm_arrivedEndAddress;
+ break;
+ case 3:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+int YM2610TimerOver(void *chip,int c)
+{
+ YM2610 *F2610 = chip;
+
+ if( c )
+ { /* Timer B */
+ TimerBOver( &(F2610->OPN.ST) );
+ }
+ else
+ { /* Timer A */
+ YM2610UpdateReq(F2610->OPN.ST.param);
+ /* timer update */
+ TimerAOver( &(F2610->OPN.ST) );
+ /* CSM mode key,TL controll */
+ if( F2610->OPN.ST.mode & 0x80 )
+ { /* CSM mode total level latch and auto key on */
+ CSMKeyControll( &(F2610->CH[2]) );
+ }
+ }
+ return F2610->OPN.ST.irq;
+}
+
+#endif /* (BUILD_YM2610||BUILD_YM2610B) */
+
+
+
+#if (BUILD_YM2612||BUILD_YM3438)
+/*******************************************************************************/
+/* YM2612 local section */
+/*******************************************************************************/
+/* here's the virtual YM2612 */
+typedef struct
+{
+ UINT8 REGS[512]; /* registers */
+ FM_OPN OPN; /* OPN state */
+ FM_CH CH[6]; /* channel state */
+ UINT8 addr_A1; /* address line A1 */
+
+ /* dac output (YM2612) */
+ int dacen;
+ INT32 dacout;
+} YM2612;
+
+static int dacen;
+
+/* Generate samples for one of the YM2612s */
+void YM2612UpdateOne(void *chip, FMSAMPLE **buffer, int length)
+{
+ YM2612 *F2612 = chip;
+ FM_OPN *OPN = &F2612->OPN;
+ int i;
+ FMSAMPLE *bufL,*bufR;
+ INT32 dacout = F2612->dacout;
+ FM_CH *cch[6];
+
+ /* set bufer */
+ bufL = buffer[0];
+ bufR = buffer[1];
+
+ cch[0] = &F2612->CH[0];
+ cch[1] = &F2612->CH[1];
+ cch[2] = &F2612->CH[2];
+ cch[3] = &F2612->CH[3];
+ cch[4] = &F2612->CH[4];
+ cch[5] = &F2612->CH[5];
+ /* DAC mode */
+ dacen = F2612->dacen;
+
+ /* refresh PG and EG */
+ refresh_fc_eg_chan( cch[0] );
+ refresh_fc_eg_chan( cch[1] );
+ if( (OPN->ST.mode & 0xc0) )
+ {
+ /* 3SLOT MODE */
+ if( cch[2]->SLOT[SLOT1].Incr==-1)
+ {
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
+ refresh_fc_eg_slot(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
+ }
+ }else refresh_fc_eg_chan( cch[2] );
+ refresh_fc_eg_chan( cch[3] );
+ refresh_fc_eg_chan( cch[4] );
+ refresh_fc_eg_chan( cch[5] );
+
+ /* buffering */
+ for(i=0; i < length ; i++)
+ {
+
+ advance_lfo(OPN);
+
+ /* clear outputs */
+ out_fm[0] = 0;
+ out_fm[1] = 0;
+ out_fm[2] = 0;
+ out_fm[3] = 0;
+ out_fm[4] = 0;
+ out_fm[5] = 0;
+
+ /* advance envelope generator */
+ OPN->eg_timer += OPN->eg_timer_add;
+ while (OPN->eg_timer >= OPN->eg_timer_overflow)
+ {
+ OPN->eg_timer -= OPN->eg_timer_overflow;
+ OPN->eg_cnt++;
+
+ advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[4]->SLOT[SLOT1]);
+ advance_eg_channel(OPN, &cch[5]->SLOT[SLOT1]);
+ }
+
+ /* calculate FM */
+ chan_calc(OPN, cch[0] );
+ chan_calc(OPN, cch[1] );
+ chan_calc(OPN, cch[2] );
+ chan_calc(OPN, cch[3] );
+ chan_calc(OPN, cch[4] );
+ if( dacen )
+ *cch[5]->connect4 += dacout;
+ else
+ chan_calc(OPN, cch[5] );
+
+ {
+ int lt,rt;
+
+ lt = ((out_fm[0]>>0) & OPN->pan[0]);
+ rt = ((out_fm[0]>>0) & OPN->pan[1]);
+ lt += ((out_fm[1]>>0) & OPN->pan[2]);
+ rt += ((out_fm[1]>>0) & OPN->pan[3]);
+ lt += ((out_fm[2]>>0) & OPN->pan[4]);
+ rt += ((out_fm[2]>>0) & OPN->pan[5]);
+ lt += ((out_fm[3]>>0) & OPN->pan[6]);
+ rt += ((out_fm[3]>>0) & OPN->pan[7]);
+ lt += ((out_fm[4]>>0) & OPN->pan[8]);
+ rt += ((out_fm[4]>>0) & OPN->pan[9]);
+ lt += ((out_fm[5]>>0) & OPN->pan[10]);
+ rt += ((out_fm[5]>>0) & OPN->pan[11]);
+
+
+ lt >>= FINAL_SH;
+ rt >>= FINAL_SH;
+
+ Limit( lt, MAXOUT, MINOUT );
+ Limit( rt, MAXOUT, MINOUT );
+
+ #ifdef SAVE_SAMPLE
+ SAVE_ALL_CHANNELS
+ #endif
+
+ /* buffering */
+ bufL[i] = lt;
+ bufR[i] = rt;
+ }
+
+ /* timer A control */
+ INTERNAL_TIMER_A( &OPN->ST , cch[2] )
+ }
+ INTERNAL_TIMER_B(&OPN->ST,length)
+
+}
+
+#ifdef __STATE_H__
+void YM2612Postload(void *chip)
+{
+ if (chip)
+ {
+ YM2612 *F2612 = (YM2612 *)chip;
+ int r;
+
+ /* DAC data & port */
+ F2612->dacout = ((int)F2612->REGS[0x2a] - 0x80) << 0; /* level unknown */
+ F2612->dacen = F2612->REGS[0x2d] & 0x80;
+ /* OPN registers */
+ /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */
+ for(r=0x30;r<0x9e;r++)
+ if((r&3) != 3)
+ {
+ OPNWriteReg(&F2612->OPN,r,F2612->REGS[r]);
+ OPNWriteReg(&F2612->OPN,r|0x100,F2612->REGS[r|0x100]);
+ }
+ /* FB / CONNECT , L / R / AMS / PMS */
+ for(r=0xb0;r<0xb6;r++)
+ if((r&3) != 3)
+ {
+ OPNWriteReg(&F2612->OPN,r,F2612->REGS[r]);
+ OPNWriteReg(&F2612->OPN,r|0x100,F2612->REGS[r|0x100]);
+ }
+ /* channels */
+ /*FM_channel_postload(F2612->CH,6);*/
+ }
+}
+
+static void YM2612_save_state(YM2612 *F2612, int index)
+{
+ static const char statename[] = "YM2612";
+
+ state_save_register_item_array(statename, index, F2612->REGS);
+ FMsave_state_st(statename,index,&F2612->OPN.ST);
+ FMsave_state_channel(statename,index,F2612->CH,6);
+ /* 3slots */
+ state_save_register_item_array(statename, index, F2612->OPN.SL3.fc);
+ state_save_register_item(statename, index, F2612->OPN.SL3.fn_h);
+ state_save_register_item_array(statename, index, F2612->OPN.SL3.kcode);
+ /* address register1 */
+ state_save_register_item(statename, index, F2612->addr_A1);
+}
+#endif /* _STATE_H */
+
+/* initialize YM2612 emulator(s) */
+void * YM2612Init(void *param, int index, int clock, int rate,
+ FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler)
+{
+ YM2612 *F2612;
+
+ /* allocate extend state space */
+ if( (F2612 = (YM2612 *)malloc(sizeof(YM2612)))==NULL)
+ return NULL;
+ /* clear */
+ memset(F2612,0,sizeof(YM2612));
+ /* allocate total level table (128kb space) */
+ if( !init_tables() )
+ {
+ free( F2612 );
+ return NULL;
+ }
+
+ F2612->OPN.ST.param = param;
+ F2612->OPN.type = TYPE_YM2612;
+ F2612->OPN.P_CH = F2612->CH;
+ F2612->OPN.ST.clock = clock;
+ F2612->OPN.ST.rate = rate;
+ /* F2612->OPN.ST.irq = 0; */
+ /* F2612->OPN.ST.status = 0; */
+ /* Extend handler */
+ F2612->OPN.ST.timer_handler = timer_handler;
+ F2612->OPN.ST.IRQ_Handler = IRQHandler;
+ YM2612ResetChip(F2612);
+
+#ifdef __STATE_H__
+ YM2612_save_state(F2612, index);
+#endif
+ return F2612;
+}
+
+/* shut down emulator */
+void YM2612Shutdown(void *chip)
+{
+ YM2612 *F2612 = chip;
+
+ FMCloseTable();
+ free(F2612);
+}
+
+/* reset one of chip */
+void YM2612ResetChip(void *chip)
+{
+ int i;
+ YM2612 *F2612 = chip;
+ FM_OPN *OPN = &F2612->OPN;
+
+ OPNSetPres( OPN, 6*24, 6*24, 0);
+ /* status clear */
+ FM_IRQMASK_SET(&OPN->ST,0x03);
+ FM_BUSY_CLEAR(&OPN->ST);
+ OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */
+
+ OPN->eg_timer = 0;
+ OPN->eg_cnt = 0;
+
+ FM_STATUS_RESET(&OPN->ST, 0xff);
+
+ reset_channels( &OPN->ST , &F2612->CH[0] , 6 );
+ for(i = 0xb6 ; i >= 0xb4 ; i-- )
+ {
+ OPNWriteReg(OPN,i ,0xc0);
+ OPNWriteReg(OPN,i|0x100,0xc0);
+ }
+ for(i = 0xb2 ; i >= 0x30 ; i-- )
+ {
+ OPNWriteReg(OPN,i ,0);
+ OPNWriteReg(OPN,i|0x100,0);
+ }
+ for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
+ /* DAC mode clear */
+ F2612->dacen = 0;
+}
+
+/* YM2612 write */
+/* n = number */
+/* a = address */
+/* v = value */
+int YM2612Write(void *chip, int a, UINT8 v)
+{
+ YM2612 *F2612 = chip;
+ int addr;
+
+ v &= 0xff; /* adjust to 8 bit bus */
+
+ switch( a&3){
+ case 0: /* address port 0 */
+ F2612->OPN.ST.address = v;
+ F2612->addr_A1 = 0;
+ break;
+
+ case 1: /* data port 0 */
+ if (F2612->addr_A1 != 0)
+ break; /* verified on real YM2608 */
+
+ addr = F2612->OPN.ST.address;
+ F2612->REGS[addr] = v;
+ switch( addr & 0xf0 )
+ {
+ case 0x20: /* 0x20-0x2f Mode */
+ switch( addr )
+ {
+ case 0x2a: /* DAC data (YM2612) */
+ YM2612UpdateReq(F2612->OPN.ST.param);
+ F2612->dacout = ((int)v - 0x80) << 7; /* level unknown */
+ break;
+ case 0x2b: /* DAC Sel (YM2612) */
+ /* b7 = dac enable */
+ F2612->dacen = v & 0x80;
+ break;
+ default: /* OPN section */
+ YM2612UpdateReq(F2612->OPN.ST.param);
+ /* write register */
+ OPNWriteMode(&(F2612->OPN),addr,v);
+ }
+ break;
+ default: /* 0x30-0xff OPN section */
+ YM2612UpdateReq(F2612->OPN.ST.param);
+ /* write register */
+ OPNWriteReg(&(F2612->OPN),addr,v);
+ }
+ break;
+
+ case 2: /* address port 1 */
+ F2612->OPN.ST.address = v;
+ F2612->addr_A1 = 1;
+ break;
+
+ case 3: /* data port 1 */
+ if (F2612->addr_A1 != 1)
+ break; /* verified on real YM2608 */
+
+ addr = F2612->OPN.ST.address;
+ F2612->REGS[addr | 0x100] = v;
+ YM2612UpdateReq(F2612->OPN.ST.param);
+ OPNWriteReg(&(F2612->OPN),addr | 0x100,v);
+ break;
+ }
+ return F2612->OPN.ST.irq;
+}
+
+UINT8 YM2612Read(void *chip,int a)
+{
+ YM2612 *F2612 = chip;
+
+ switch( a&3){
+ case 0: /* status 0 */
+ return FM_STATUS_FLAG(&F2612->OPN.ST);
+ case 1:
+ case 2:
+ case 3:
+ LOG(LOG_WAR,("YM2612 #%p:A=%d read unmapped area\n",F2612->OPN.ST.param,a));
+ return FM_STATUS_FLAG(&F2612->OPN.ST);
+ }
+ return 0;
+}
+
+int YM2612TimerOver(void *chip,int c)
+{
+ YM2612 *F2612 = chip;
+
+ if( c )
+ { /* Timer B */
+ TimerBOver( &(F2612->OPN.ST) );
+ }
+ else
+ { /* Timer A */
+ YM2612UpdateReq(F2612->OPN.ST.param);
+ /* timer update */
+ TimerAOver( &(F2612->OPN.ST) );
+ /* CSM mode key,TL controll */
+ if( F2612->OPN.ST.mode & 0x80 )
+ { /* CSM mode total level latch and auto key on */
+ CSMKeyControll( &(F2612->CH[2]) );
+ }
+ }
+ return F2612->OPN.ST.irq;
+}
+
+#endif /* (BUILD_YM2612||BUILD_YM3238) */
diff --git a/src/emu/sound/fm.h b/src/emu/sound/fm.h
new file mode 100644
index 00000000000..10d860be8cc
--- /dev/null
+++ b/src/emu/sound/fm.h
@@ -0,0 +1,211 @@
+/*
+ File: fm.h -- header file for software emulation for FM sound generator
+
+*/
+#ifndef _H_FM_FM_
+#define _H_FM_FM_
+
+/* --- select emulation chips --- */
+#define BUILD_YM2203 (HAS_YM2203) /* build YM2203(OPN) emulator */
+#define BUILD_YM2608 (HAS_YM2608) /* build YM2608(OPNA) emulator */
+#define BUILD_YM2610 (HAS_YM2610) /* build YM2610(OPNB) emulator */
+#define BUILD_YM2610B (HAS_YM2610B) /* build YM2610B(OPNB?)emulator */
+#define BUILD_YM2612 (HAS_YM2612) /* build YM2612(OPN2) emulator */
+#define BUILD_YM3438 (HAS_YM3438) /* build YM3438(OPN) emulator */
+
+/* select bit size of output : 8 or 16 */
+#define FM_SAMPLE_BITS 16
+
+/* select timer system internal or external */
+#define FM_INTERNAL_TIMER 0
+
+/* --- speedup optimize --- */
+/* busy flag enulation , The definition of FM_GET_TIME_NOW() is necessary. */
+#define FM_BUSY_FLAG_SUPPORT 1
+
+/* --- external SSG(YM2149/AY-3-8910)emulator interface port */
+/* used by YM2203,YM2608,and YM2610 */
+struct ssg_callbacks
+{
+ void (*set_clock)(void *param, int clock);
+ void (*write)(void *param, int address, int data);
+ int (*read)(void *param);
+ void (*reset)(void *param);
+};
+
+/* --- external callback funstions for realtime update --- */
+
+#if FM_BUSY_FLAG_SUPPORT
+#define TIME_TYPE attotime
+#define UNDEFINED_TIME attotime_zero
+#define FM_GET_TIME_NOW() timer_get_time()
+#define ADD_TIMES(t1, t2) attotime_add((t1), (t2))
+#define COMPARE_TIMES(t1, t2) attotime_compare((t1), (t2))
+#define MULTIPLY_TIME_BY_INT(t,i) attotime_mul(t, i)
+#endif
+
+#if BUILD_YM2203
+ /* in 2203intf.c */
+ void YM2203UpdateRequest(void *param);
+ #define YM2203UpdateReq(chip) YM2203UpdateRequest(chip)
+#endif
+#if BUILD_YM2608
+ /* in 2608intf.c */
+ void YM2608UpdateRequest(void *param);
+ #define YM2608UpdateReq(chip) YM2608UpdateRequest(chip);
+#endif
+#if (BUILD_YM2610||BUILD_YM2610B)
+ /* in 2610intf.c */
+ void YM2610UpdateRequest(void *param);
+ #define YM2610UpdateReq(chip) YM2610UpdateRequest(chip);
+#endif
+#if (BUILD_YM2612||BUILD_YM3438)
+ /* in 2612intf.c */
+ void YM2612UpdateRequest(void *param);
+ #define YM2612UpdateReq(chip) YM2612UpdateRequest(chip);
+#endif
+
+/* compiler dependence */
+#if 0
+#ifndef OSD_CPU_H
+#define OSD_CPU_H
+typedef unsigned char UINT8; /* unsigned 8bit */
+typedef unsigned short UINT16; /* unsigned 16bit */
+typedef unsigned int UINT32; /* unsigned 32bit */
+typedef signed char INT8; /* signed 8bit */
+typedef signed short INT16; /* signed 16bit */
+typedef signed int INT32; /* signed 32bit */
+#endif
+#endif
+
+#ifndef INLINE
+#define INLINE static __inline__
+#endif
+
+
+
+
+typedef stream_sample_t FMSAMPLE;
+/*
+#if (FM_SAMPLE_BITS==16)
+typedef INT16 FMSAMPLE;
+#endif
+#if (FM_SAMPLE_BITS==8)
+typedef unsigned char FMSAMPLE;
+#endif
+*/
+
+typedef void (*FM_TIMERHANDLER)(void *param,int c,int cnt,int clock);
+typedef void (*FM_IRQHANDLER)(void *param,int irq);
+/* FM_TIMERHANDLER : Stop or Start timer */
+/* int n = chip number */
+/* int c = Channel 0=TimerA,1=TimerB */
+/* int count = timer count (0=stop) */
+/* doube stepTime = step time of one count (sec.)*/
+
+/* FM_IRQHHANDLER : IRQ level changing sense */
+/* int n = chip number */
+/* int irq = IRQ level 0=OFF,1=ON */
+
+#if BUILD_YM2203
+/* -------------------- YM2203(OPN) Interface -------------------- */
+
+/*
+** Initialize YM2203 emulator(s).
+**
+** 'num' is the number of virtual YM2203's to allocate
+** 'baseclock'
+** 'rate' is sampling rate
+** 'TimerHandler' timer callback handler when timer start and clear
+** 'IRQHandler' IRQ callback handler when changed IRQ level
+** return 0 = success
+*/
+void * YM2203Init(void *param, int index, int baseclock, int rate,
+ FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, const struct ssg_callbacks *ssg);
+
+/*
+** shutdown the YM2203 emulators
+*/
+void YM2203Shutdown(void *chip);
+
+/*
+** reset all chip registers for YM2203 number 'num'
+*/
+void YM2203ResetChip(void *chip);
+
+/*
+** update one of chip
+*/
+void YM2203UpdateOne(void *chip, FMSAMPLE *buffer, int length);
+
+/*
+** Write
+** return : InterruptLevel
+*/
+int YM2203Write(void *chip,int a,unsigned char v);
+
+/*
+** Read
+** return : InterruptLevel
+*/
+unsigned char YM2203Read(void *chip,int a);
+
+/*
+** Timer OverFlow
+*/
+int YM2203TimerOver(void *chip, int c);
+
+/*
+** State Save
+*/
+void YM2203Postload(void *chip);
+#endif /* BUILD_YM2203 */
+
+#if BUILD_YM2608
+/* -------------------- YM2608(OPNA) Interface -------------------- */
+void * YM2608Init(void *param, int index, int baseclock, int rate,
+ void *pcmroma,int pcmsizea,
+ FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, const struct ssg_callbacks *ssg);
+void YM2608Shutdown(void *chip);
+void YM2608ResetChip(void *chip);
+void YM2608UpdateOne(void *chip, FMSAMPLE **buffer, int length);
+
+int YM2608Write(void *chip, int a,unsigned char v);
+unsigned char YM2608Read(void *chip,int a);
+int YM2608TimerOver(void *chip, int c );
+void YM2608Postload(void *chip);
+#endif /* BUILD_YM2608 */
+
+#if (BUILD_YM2610||BUILD_YM2610B)
+/* -------------------- YM2610(OPNB) Interface -------------------- */
+void * YM2610Init(void *param, int index, int baseclock, int rate,
+ void *pcmroma,int pcmasize,void *pcmromb,int pcmbsize,
+ FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, const struct ssg_callbacks *ssg);
+void YM2610Shutdown(void *chip);
+void YM2610ResetChip(void *chip);
+void YM2610UpdateOne(void *chip, FMSAMPLE **buffer, int length);
+#if BUILD_YM2610B
+void YM2610BUpdateOne(void *chip, FMSAMPLE **buffer, int length);
+#endif
+
+int YM2610Write(void *chip, int a,unsigned char v);
+unsigned char YM2610Read(void *chip,int a);
+int YM2610TimerOver(void *chip, int c );
+void YM2610Postload(void *chip);
+#endif /* (BUILD_YM2610||BUILD_YM2610B) */
+
+#if (BUILD_YM2612||BUILD_YM3438)
+void * YM2612Init(void *param, int index, int baseclock, int rate,
+ FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler);
+void YM2612Shutdown(void *chip);
+void YM2612ResetChip(void *chip);
+void YM2612UpdateOne(void *chip, FMSAMPLE **buffer, int length);
+
+int YM2612Write(void *chip, int a,unsigned char v);
+unsigned char YM2612Read(void *chip,int a);
+int YM2612TimerOver(void *chip, int c );
+void YM2612Postload(void *chip);
+#endif /* (BUILD_YM2612||BUILD_YM3438) */
+
+
+#endif /* _H_FM_FM_ */
diff --git a/src/emu/sound/fmopl.c b/src/emu/sound/fmopl.c
new file mode 100644
index 00000000000..358e44c675a
--- /dev/null
+++ b/src/emu/sound/fmopl.c
@@ -0,0 +1,2625 @@
+/*
+**
+** File: fmopl.c - software implementation of FM sound generator
+** types OPL and OPL2
+**
+** Copyright (C) 2002,2003 Jarek Burczynski (bujar at mame dot net)
+** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmulator development
+**
+** Version 0.72
+**
+
+Revision History:
+
+04-08-2003 Jarek Burczynski:
+ - removed BFRDY hack. BFRDY is busy flag, and it should be 0 only when the chip
+ handles memory read/write or during the adpcm synthesis when the chip
+ requests another byte of ADPCM data.
+
+24-07-2003 Jarek Burczynski:
+ - added a small hack for Y8950 status BFRDY flag (bit 3 should be set after
+ some (unknown) delay). Right now it's always set.
+
+14-06-2003 Jarek Burczynski:
+ - implemented all of the status register flags in Y8950 emulation
+ - renamed Y8950SetDeltaTMemory() parameters from _rom_ to _mem_ since
+ they can be either RAM or ROM
+
+08-10-2002 Jarek Burczynski (thanks to Dox for the YM3526 chip)
+ - corrected YM3526Read() to always set bit 2 and bit 1
+ to HIGH state - identical to YM3812Read (verified on real YM3526)
+
+04-28-2002 Jarek Burczynski:
+ - binary exact Envelope Generator (verified on real YM3812);
+ compared to YM2151: the EG clock is equal to internal_clock,
+ rates are 2 times slower and volume resolution is one bit less
+ - modified interface functions (they no longer return pointer -
+ that's internal to the emulator now):
+ - new wrapper functions for OPLCreate: YM3526Init(), YM3812Init() and Y8950Init()
+ - corrected 'off by one' error in feedback calculations (when feedback is off)
+ - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22)
+ - speeded up noise generator calculations (Nicola Salmoria)
+
+03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip)
+ Complete rewrite (all verified on real YM3812):
+ - corrected sin_tab and tl_tab data
+ - corrected operator output calculations
+ - corrected waveform_select_enable register;
+ simply: ignore all writes to waveform_select register when
+ waveform_select_enable == 0 and do not change the waveform previously selected.
+ - corrected KSR handling
+ - corrected Envelope Generator: attack shape, Sustain mode and
+ Percussive/Non-percussive modes handling
+ - Envelope Generator rates are two times slower now
+ - LFO amplitude (tremolo) and phase modulation (vibrato)
+ - rhythm sounds phase generation
+ - white noise generator (big thanks to Olivier Galibert for mentioning Berlekamp-Massey algorithm)
+ - corrected key on/off handling (the 'key' signal is ORed from three sources: FM, rhythm and CSM)
+ - funky details (like ignoring output of operator 1 in BD rhythm sound when connect == 1)
+
+12-28-2001 Acho A. Tang
+ - reflected Delta-T EOS status on Y8950 status port.
+ - fixed subscription range of attack/decay tables
+
+
+ To do:
+ add delay before key off in CSM mode (see CSMKeyControll)
+ verify volume of the FM part on the Y8950
+*/
+
+#include <math.h>
+
+#include "sndintrf.h" /* use M.A.M.E. */
+
+#include "ymdeltat.h"
+
+#include "fmopl.h"
+
+
+
+/* output final shift */
+#if (OPL_SAMPLE_BITS==16)
+ #define FINAL_SH (0)
+ #define MAXOUT (+32767)
+ #define MINOUT (-32768)
+#else
+ #define FINAL_SH (8)
+ #define MAXOUT (+127)
+ #define MINOUT (-128)
+#endif
+
+
+#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
+#define EG_SH 16 /* 16.16 fixed point (EG timing) */
+#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
+#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */
+
+#define FREQ_MASK ((1<<FREQ_SH)-1)
+
+/* envelope output entries */
+#define ENV_BITS 10
+#define ENV_LEN (1<<ENV_BITS)
+#define ENV_STEP (128.0/ENV_LEN)
+
+#define MAX_ATT_INDEX ((1<<(ENV_BITS-1))-1) /*511*/
+#define MIN_ATT_INDEX (0)
+
+/* sinwave entries */
+#define SIN_BITS 10
+#define SIN_LEN (1<<SIN_BITS)
+#define SIN_MASK (SIN_LEN-1)
+
+#define TL_RES_LEN (256) /* 8 bits addressing (real chip) */
+
+
+
+/* register number to channel number , slot offset */
+#define SLOT1 0
+#define SLOT2 1
+
+/* Envelope Generator phases */
+
+#define EG_ATT 4
+#define EG_DEC 3
+#define EG_SUS 2
+#define EG_REL 1
+#define EG_OFF 0
+
+
+/* save output as raw 16-bit sample */
+
+/*#define SAVE_SAMPLE*/
+
+#ifdef SAVE_SAMPLE
+INLINE signed int acc_calc(signed int value)
+{
+ if (value>=0)
+ {
+ if (value < 0x0200)
+ return (value & ~0);
+ if (value < 0x0400)
+ return (value & ~1);
+ if (value < 0x0800)
+ return (value & ~3);
+ if (value < 0x1000)
+ return (value & ~7);
+ if (value < 0x2000)
+ return (value & ~15);
+ if (value < 0x4000)
+ return (value & ~31);
+ return (value & ~63);
+ }
+ /*else value < 0*/
+ if (value > -0x0200)
+ return (~abs(value) & ~0);
+ if (value > -0x0400)
+ return (~abs(value) & ~1);
+ if (value > -0x0800)
+ return (~abs(value) & ~3);
+ if (value > -0x1000)
+ return (~abs(value) & ~7);
+ if (value > -0x2000)
+ return (~abs(value) & ~15);
+ if (value > -0x4000)
+ return (~abs(value) & ~31);
+ return (~abs(value) & ~63);
+}
+
+
+static FILE *sample[1];
+ #if 1 /*save to MONO file */
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = acc_calc(lt); \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ }
+ #else /*save to STEREO file */
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = lt; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ pom = rt; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ }
+ #endif
+#endif
+
+/* #define LOG_CYM_FILE */
+#ifdef LOG_CYM_FILE
+ FILE * cymfile = NULL;
+#endif
+
+
+
+#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
+#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
+#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
+#define OPL_TYPE_IO 0x08 /* I/O port */
+
+/* ---------- Generic interface section ---------- */
+#define OPL_TYPE_YM3526 (0)
+#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
+#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
+
+
+
+typedef struct{
+ UINT32 ar; /* attack rate: AR<<2 */
+ UINT32 dr; /* decay rate: DR<<2 */
+ UINT32 rr; /* release rate:RR<<2 */
+ UINT8 KSR; /* key scale rate */
+ UINT8 ksl; /* keyscale level */
+ UINT8 ksr; /* key scale rate: kcode>>KSR */
+ UINT8 mul; /* multiple: mul_tab[ML] */
+
+ /* Phase Generator */
+ UINT32 Cnt; /* frequency counter */
+ UINT32 Incr; /* frequency counter step */
+ UINT8 FB; /* feedback shift value */
+ INT32 *connect1; /* slot1 output pointer */
+ INT32 op1_out[2]; /* slot1 output for feedback */
+ UINT8 CON; /* connection (algorithm) type */
+
+ /* Envelope Generator */
+ UINT8 eg_type; /* percussive/non-percussive mode */
+ UINT8 state; /* phase type */
+ UINT32 TL; /* total level: TL << 2 */
+ INT32 TLL; /* adjusted now TL */
+ INT32 volume; /* envelope counter */
+ UINT32 sl; /* sustain level: sl_tab[SL] */
+ UINT8 eg_sh_ar; /* (attack state) */
+ UINT8 eg_sel_ar; /* (attack state) */
+ UINT8 eg_sh_dr; /* (decay state) */
+ UINT8 eg_sel_dr; /* (decay state) */
+ UINT8 eg_sh_rr; /* (release state) */
+ UINT8 eg_sel_rr; /* (release state) */
+ UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
+
+ /* LFO */
+ UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
+ UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/
+
+ /* waveform select */
+ UINT16 wavetable;
+} OPL_SLOT;
+
+typedef struct{
+ OPL_SLOT SLOT[2];
+ /* phase generator state */
+ UINT32 block_fnum; /* block+fnum */
+ UINT32 fc; /* Freq. Increment base */
+ UINT32 ksl_base; /* KeyScaleLevel Base step */
+ UINT8 kcode; /* key code (for key scaling) */
+} OPL_CH;
+
+/* OPL state */
+typedef struct fm_opl_f {
+ /* FM channel slots */
+ OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/
+
+ UINT32 eg_cnt; /* global envelope generator counter */
+ UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */
+ UINT32 eg_timer_add; /* step of eg_timer */
+ UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */
+
+ UINT8 rhythm; /* Rhythm mode */
+
+ UINT32 fn_tab[1024]; /* fnumber->increment counter */
+
+ /* LFO */
+ UINT8 lfo_am_depth;
+ UINT8 lfo_pm_depth_range;
+ UINT32 lfo_am_cnt;
+ UINT32 lfo_am_inc;
+ UINT32 lfo_pm_cnt;
+ UINT32 lfo_pm_inc;
+
+ UINT32 noise_rng; /* 23 bit noise shift register */
+ UINT32 noise_p; /* current noise 'phase' */
+ UINT32 noise_f; /* current noise period */
+
+ UINT8 wavesel; /* waveform select enable flag */
+
+ UINT32 T[2]; /* timer counters */
+ UINT8 st[2]; /* timer enable */
+
+#if BUILD_Y8950
+ /* Delta-T ADPCM unit (Y8950) */
+
+ YM_DELTAT *deltat;
+
+ /* Keyboard and I/O ports interface */
+ UINT8 portDirection;
+ UINT8 portLatch;
+ OPL_PORTHANDLER_R porthandler_r;
+ OPL_PORTHANDLER_W porthandler_w;
+ void * port_param;
+ OPL_PORTHANDLER_R keyboardhandler_r;
+ OPL_PORTHANDLER_W keyboardhandler_w;
+ void * keyboard_param;
+#endif
+
+ /* external event callback handlers */
+ OPL_TIMERHANDLER timer_handler; /* TIMER handler */
+ void *TimerParam; /* TIMER parameter */
+ OPL_IRQHANDLER IRQHandler; /* IRQ handler */
+ void *IRQParam; /* IRQ parameter */
+ OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */
+ void *UpdateParam; /* stream update parameter */
+
+ UINT8 type; /* chip type */
+ UINT8 address; /* address register */
+ UINT8 status; /* status flag */
+ UINT8 statusmask; /* status mask */
+ UINT8 mode; /* Reg.08 : CSM,notesel,etc. */
+
+ UINT32 clock; /* master clock (Hz) */
+ UINT32 rate; /* sampling rate (Hz) */
+ double freqbase; /* frequency base */
+ attotime TimerBase; /* Timer base time (==sampling time)*/
+} FM_OPL;
+
+
+
+/* mapping of register number (offset) to slot number used by the emulator */
+static const int slot_array[32]=
+{
+ 0, 2, 4, 1, 3, 5,-1,-1,
+ 6, 8,10, 7, 9,11,-1,-1,
+ 12,14,16,13,15,17,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1
+};
+
+/* key scale level */
+/* table is 3dB/octave , DV converts this into 6dB/octave */
+/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */
+#define DV (0.1875/2.0)
+static const UINT32 ksl_tab[8*16]=
+{
+ /* OCT 0 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ /* OCT 1 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV,
+ 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV,
+ /* OCT 2 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV,
+ 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV,
+ 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV,
+ /* OCT 3 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV,
+ 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV,
+ 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV,
+ 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV,
+ /* OCT 4 */
+ 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV,
+ 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV,
+ 9.000/DV, 9.750/DV,10.125/DV,10.500/DV,
+ 10.875/DV,11.250/DV,11.625/DV,12.000/DV,
+ /* OCT 5 */
+ 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV,
+ 9.000/DV,10.125/DV,10.875/DV,11.625/DV,
+ 12.000/DV,12.750/DV,13.125/DV,13.500/DV,
+ 13.875/DV,14.250/DV,14.625/DV,15.000/DV,
+ /* OCT 6 */
+ 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV,
+ 12.000/DV,13.125/DV,13.875/DV,14.625/DV,
+ 15.000/DV,15.750/DV,16.125/DV,16.500/DV,
+ 16.875/DV,17.250/DV,17.625/DV,18.000/DV,
+ /* OCT 7 */
+ 0.000/DV, 9.000/DV,12.000/DV,13.875/DV,
+ 15.000/DV,16.125/DV,16.875/DV,17.625/DV,
+ 18.000/DV,18.750/DV,19.125/DV,19.500/DV,
+ 19.875/DV,20.250/DV,20.625/DV,21.000/DV
+};
+#undef DV
+
+/* sustain level table (3dB per step) */
+/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
+#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) )
+static const UINT32 sl_tab[16]={
+ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
+ SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
+};
+#undef SC
+
+
+#define RATE_STEPS (8)
+static const unsigned char eg_inc[15*RATE_STEPS]={
+
+/*cycle:0 1 2 3 4 5 6 7*/
+
+/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */
+/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */
+/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */
+/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */
+
+/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */
+/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */
+/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */
+/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */
+
+/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */
+/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */
+/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */
+/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */
+
+/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */
+/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */
+/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */
+};
+
+
+#define O(a) (a*RATE_STEPS)
+
+/*note that there is no O(13) in this table - it's directly in the code */
+static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */
+/* 16 infinite time rates */
+O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
+O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
+
+/* rates 00-12 */
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+
+/* rate 13 */
+O( 4),O( 5),O( 6),O( 7),
+
+/* rate 14 */
+O( 8),O( 9),O(10),O(11),
+
+/* rate 15 */
+O(12),O(12),O(12),O(12),
+
+/* 16 dummy rates (same as 15 3) */
+O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
+O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
+
+};
+#undef O
+
+/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */
+/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */
+/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */
+
+#define O(a) (a*1)
+static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */
+/* 16 infinite time rates */
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+
+/* rates 00-12 */
+O(12),O(12),O(12),O(12),
+O(11),O(11),O(11),O(11),
+O(10),O(10),O(10),O(10),
+O( 9),O( 9),O( 9),O( 9),
+O( 8),O( 8),O( 8),O( 8),
+O( 7),O( 7),O( 7),O( 7),
+O( 6),O( 6),O( 6),O( 6),
+O( 5),O( 5),O( 5),O( 5),
+O( 4),O( 4),O( 4),O( 4),
+O( 3),O( 3),O( 3),O( 3),
+O( 2),O( 2),O( 2),O( 2),
+O( 1),O( 1),O( 1),O( 1),
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 13 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 14 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 15 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* 16 dummy rates (same as 15 3) */
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+
+};
+#undef O
+
+
+/* multiple table */
+#define ML 2
+static const UINT8 mul_tab[16]= {
+/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */
+ 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
+ 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
+};
+#undef ML
+
+/* TL_TAB_LEN is calculated as:
+* 12 - sinus amplitude bits (Y axis)
+* 2 - sinus sign bit (Y axis)
+* TL_RES_LEN - sinus resolution (X axis)
+*/
+#define TL_TAB_LEN (12*2*TL_RES_LEN)
+static signed int tl_tab[TL_TAB_LEN];
+
+#define ENV_QUIET (TL_TAB_LEN>>4)
+
+/* sin waveform table in 'decibel' scale */
+/* four waveforms on OPL2 type chips */
+static unsigned int sin_tab[SIN_LEN * 4];
+
+
+/* LFO Amplitude Modulation table (verified on real YM3812)
+ 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples
+
+ Length: 210 elements.
+
+ Each of the elements has to be repeated
+ exactly 64 times (on 64 consecutive samples).
+ The whole table takes: 64 * 210 = 13440 samples.
+
+ When AM = 1 data is used directly
+ When AM = 0 data is divided by 4 before being used (loosing precision is important)
+*/
+
+#define LFO_AM_TAB_ELEMENTS 210
+
+static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = {
+0,0,0,0,0,0,0,
+1,1,1,1,
+2,2,2,2,
+3,3,3,3,
+4,4,4,4,
+5,5,5,5,
+6,6,6,6,
+7,7,7,7,
+8,8,8,8,
+9,9,9,9,
+10,10,10,10,
+11,11,11,11,
+12,12,12,12,
+13,13,13,13,
+14,14,14,14,
+15,15,15,15,
+16,16,16,16,
+17,17,17,17,
+18,18,18,18,
+19,19,19,19,
+20,20,20,20,
+21,21,21,21,
+22,22,22,22,
+23,23,23,23,
+24,24,24,24,
+25,25,25,25,
+26,26,26,
+25,25,25,25,
+24,24,24,24,
+23,23,23,23,
+22,22,22,22,
+21,21,21,21,
+20,20,20,20,
+19,19,19,19,
+18,18,18,18,
+17,17,17,17,
+16,16,16,16,
+15,15,15,15,
+14,14,14,14,
+13,13,13,13,
+12,12,12,12,
+11,11,11,11,
+10,10,10,10,
+9,9,9,9,
+8,8,8,8,
+7,7,7,7,
+6,6,6,6,
+5,5,5,5,
+4,4,4,4,
+3,3,3,3,
+2,2,2,2,
+1,1,1,1
+};
+
+/* LFO Phase Modulation table (verified on real YM3812) */
+static const INT8 lfo_pm_table[8*8*2] = {
+
+/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */
+0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/
+0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */
+0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/
+1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */
+1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/
+2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */
+1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/
+3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */
+2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/
+4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */
+2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/
+5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */
+3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/
+6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */
+3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/
+7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/
+};
+
+
+/* lock level of common table */
+static int num_lock = 0;
+
+
+static void *cur_chip = NULL; /* current chip pointer */
+static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2;
+
+static signed int phase_modulation; /* phase modulation input (SLOT 2) */
+static signed int output[1];
+
+#if BUILD_Y8950
+static INT32 output_deltat[4]; /* for Y8950 DELTA-T, chip is mono, that 4 here is just for safety */
+#endif
+
+static UINT32 LFO_AM;
+static INT32 LFO_PM;
+
+
+
+INLINE int limit( int val, int max, int min ) {
+ if ( val > max )
+ val = max;
+ else if ( val < min )
+ val = min;
+
+ return val;
+}
+
+
+/* status set and IRQ handling */
+INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag)
+{
+ /* set status flag */
+ OPL->status |= flag;
+ if(!(OPL->status & 0x80))
+ {
+ if(OPL->status & OPL->statusmask)
+ { /* IRQ on */
+ OPL->status |= 0x80;
+ /* callback user interrupt handler (IRQ is OFF to ON) */
+ if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
+ }
+ }
+}
+
+/* status reset and IRQ handling */
+INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
+{
+ /* reset status flag */
+ OPL->status &=~flag;
+ if((OPL->status & 0x80))
+ {
+ if (!(OPL->status & OPL->statusmask) )
+ {
+ OPL->status &= 0x7f;
+ /* callback user interrupt handler (IRQ is ON to OFF) */
+ if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
+ }
+ }
+}
+
+/* IRQ mask set */
+INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
+{
+ OPL->statusmask = flag;
+ /* IRQ handling check */
+ OPL_STATUS_SET(OPL,0);
+ OPL_STATUS_RESET(OPL,0);
+}
+
+
+/* advance LFO to next sample */
+INLINE void advance_lfo(FM_OPL *OPL)
+{
+ UINT8 tmp;
+
+ /* LFO */
+ OPL->lfo_am_cnt += OPL->lfo_am_inc;
+ if (OPL->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<<LFO_SH) ) /* lfo_am_table is 210 elements long */
+ OPL->lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<<LFO_SH);
+
+ tmp = lfo_am_table[ OPL->lfo_am_cnt >> LFO_SH ];
+
+ if (OPL->lfo_am_depth)
+ LFO_AM = tmp;
+ else
+ LFO_AM = tmp>>2;
+
+ OPL->lfo_pm_cnt += OPL->lfo_pm_inc;
+ LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range;
+}
+
+/* advance to next sample */
+INLINE void advance(FM_OPL *OPL)
+{
+ OPL_CH *CH;
+ OPL_SLOT *op;
+ int i;
+
+ OPL->eg_timer += OPL->eg_timer_add;
+
+ while (OPL->eg_timer >= OPL->eg_timer_overflow)
+ {
+ OPL->eg_timer -= OPL->eg_timer_overflow;
+
+ OPL->eg_cnt++;
+
+ for (i=0; i<9*2; i++)
+ {
+ CH = &OPL->P_CH[i/2];
+ op = &CH->SLOT[i&1];
+
+ /* Envelope Generator */
+ switch(op->state)
+ {
+ case EG_ATT: /* attack phase */
+ if ( !(OPL->eg_cnt & ((1<<op->eg_sh_ar)-1) ) )
+ {
+ op->volume += (~op->volume *
+ (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)])
+ ) >>3;
+
+ if (op->volume <= MIN_ATT_INDEX)
+ {
+ op->volume = MIN_ATT_INDEX;
+ op->state = EG_DEC;
+ }
+
+ }
+ break;
+
+ case EG_DEC: /* decay phase */
+ if ( !(OPL->eg_cnt & ((1<<op->eg_sh_dr)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)];
+
+ if ( op->volume >= op->sl )
+ op->state = EG_SUS;
+
+ }
+ break;
+
+ case EG_SUS: /* sustain phase */
+
+ /* this is important behaviour:
+ one can change percusive/non-percussive modes on the fly and
+ the chip will remain in sustain phase - verified on real YM3812 */
+
+ if(op->eg_type) /* non-percussive mode */
+ {
+ /* do nothing */
+ }
+ else /* percussive mode */
+ {
+ /* during sustain phase chip adds Release Rate (in percussive mode) */
+ if ( !(OPL->eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)];
+
+ if ( op->volume >= MAX_ATT_INDEX )
+ op->volume = MAX_ATT_INDEX;
+ }
+ /* else do nothing in sustain phase */
+ }
+ break;
+
+ case EG_REL: /* release phase */
+ if ( !(OPL->eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)];
+
+ if ( op->volume >= MAX_ATT_INDEX )
+ {
+ op->volume = MAX_ATT_INDEX;
+ op->state = EG_OFF;
+ }
+
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ for (i=0; i<9*2; i++)
+ {
+ CH = &OPL->P_CH[i/2];
+ op = &CH->SLOT[i&1];
+
+ /* Phase Generator */
+ if(op->vib)
+ {
+ UINT8 block;
+ unsigned int block_fnum = CH->block_fnum;
+
+ unsigned int fnum_lfo = (block_fnum&0x0380) >> 7;
+
+ signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + 16*fnum_lfo ];
+
+ if (lfo_fn_table_index_offset) /* LFO phase modulation active */
+ {
+ block_fnum += lfo_fn_table_index_offset;
+ block = (block_fnum&0x1c00) >> 10;
+ op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul;
+ }
+ else /* LFO phase modulation = zero */
+ {
+ op->Cnt += op->Incr;
+ }
+ }
+ else /* LFO phase modulation disabled for this operator */
+ {
+ op->Cnt += op->Incr;
+ }
+ }
+
+ /* The Noise Generator of the YM3812 is 23-bit shift register.
+ * Period is equal to 2^23-2 samples.
+ * Register works at sampling frequency of the chip, so output
+ * can change on every sample.
+ *
+ * Output of the register and input to the bit 22 is:
+ * bit0 XOR bit14 XOR bit15 XOR bit22
+ *
+ * Simply use bit 22 as the noise output.
+ */
+
+ OPL->noise_p += OPL->noise_f;
+ i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */
+ OPL->noise_p &= FREQ_MASK;
+ while (i)
+ {
+ /*
+ UINT32 j;
+ j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1;
+ OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1);
+ */
+
+ /*
+ Instead of doing all the logic operations above, we
+ use a trick here (and use bit 0 as the noise output).
+ The difference is only that the noise bit changes one
+ step ahead. This doesn't matter since we don't know
+ what is real state of the noise_rng after the reset.
+ */
+
+ if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302;
+ OPL->noise_rng >>= 1;
+
+ i--;
+ }
+}
+
+
+INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab)
+{
+ UINT32 p;
+
+ p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ];
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+ return tl_tab[p];
+}
+
+INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab)
+{
+ UINT32 p;
+
+ p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ];
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+ return tl_tab[p];
+}
+
+
+#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask))
+
+/* calculate output */
+INLINE void OPL_CALC_CH( OPL_CH *CH )
+{
+ OPL_SLOT *SLOT;
+ unsigned int env;
+ signed int out;
+
+ phase_modulation = 0;
+
+ /* SLOT 1 */
+ SLOT = &CH->SLOT[SLOT1];
+ env = volume_calc(SLOT);
+ out = SLOT->op1_out[0] + SLOT->op1_out[1];
+ SLOT->op1_out[0] = SLOT->op1_out[1];
+ *SLOT->connect1 += SLOT->op1_out[0];
+ SLOT->op1_out[1] = 0;
+ if( env < ENV_QUIET )
+ {
+ if (!SLOT->FB)
+ out = 0;
+ SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<<SLOT->FB), SLOT->wavetable );
+ }
+
+ /* SLOT 2 */
+ SLOT++;
+ env = volume_calc(SLOT);
+ if( env < ENV_QUIET )
+ output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable);
+}
+
+/*
+ operators used in the rhythm sounds generation process:
+
+ Envelope Generator:
+
+channel operator register number Bass High Snare Tom Top
+/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal
+ 6 / 0 12 50 70 90 f0 +
+ 6 / 1 15 53 73 93 f3 +
+ 7 / 0 13 51 71 91 f1 +
+ 7 / 1 16 54 74 94 f4 +
+ 8 / 0 14 52 72 92 f2 +
+ 8 / 1 17 55 75 95 f5 +
+
+ Phase Generator:
+
+channel operator register number Bass High Snare Tom Top
+/ slot number MULTIPLE Drum Hat Drum Tom Cymbal
+ 6 / 0 12 30 +
+ 6 / 1 15 33 +
+ 7 / 0 13 31 + + +
+ 7 / 1 16 34 ----- n o t u s e d -----
+ 8 / 0 14 32 +
+ 8 / 1 17 35 + +
+
+channel operator register number Bass High Snare Tom Top
+number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal
+ 6 12,15 B6 A6 +
+
+ 7 13,16 B7 A7 + + +
+
+ 8 14,17 B8 A8 + + +
+
+*/
+
+/* calculate rhythm */
+
+INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
+{
+ OPL_SLOT *SLOT;
+ signed int out;
+ unsigned int env;
+
+
+ /* Bass Drum (verified on real YM3812):
+ - depends on the channel 6 'connect' register:
+ when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out)
+ when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored
+ - output sample always is multiplied by 2
+ */
+
+ phase_modulation = 0;
+ /* SLOT 1 */
+ SLOT = &CH[6].SLOT[SLOT1];
+ env = volume_calc(SLOT);
+
+ out = SLOT->op1_out[0] + SLOT->op1_out[1];
+ SLOT->op1_out[0] = SLOT->op1_out[1];
+
+ if (!SLOT->CON)
+ phase_modulation = SLOT->op1_out[0];
+ /* else ignore output of operator 1 */
+
+ SLOT->op1_out[1] = 0;
+ if( env < ENV_QUIET )
+ {
+ if (!SLOT->FB)
+ out = 0;
+ SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<<SLOT->FB), SLOT->wavetable );
+ }
+
+ /* SLOT 2 */
+ SLOT++;
+ env = volume_calc(SLOT);
+ if( env < ENV_QUIET )
+ output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2;
+
+
+ /* Phase generation is based on: */
+ /* HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) */
+ /* SD (16) channel 7->slot 1 */
+ /* TOM (14) channel 8->slot 1 */
+ /* TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */
+
+ /* Envelope generation based on: */
+ /* HH channel 7->slot1 */
+ /* SD channel 7->slot2 */
+ /* TOM channel 8->slot1 */
+ /* TOP channel 8->slot2 */
+
+
+ /* The following formulas can be well optimized.
+ I leave them in direct form for now (in case I've missed something).
+ */
+
+ /* High Hat (verified on real YM3812) */
+ env = volume_calc(SLOT7_1);
+ if( env < ENV_QUIET )
+ {
+
+ /* high hat phase generation:
+ phase = d0 or 234 (based on frequency only)
+ phase = 34 or 2d0 (based on noise)
+ */
+
+ /* base frequency derived from operator 1 in channel 7 */
+ unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1;
+ unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1;
+ unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1;
+
+ unsigned char res1 = (bit2 ^ bit7) | bit3;
+
+ /* when res1 = 0 phase = 0x000 | 0xd0; */
+ /* when res1 = 1 phase = 0x200 | (0xd0>>2); */
+ UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0;
+
+ /* enable gate based on frequency of operator 2 in channel 8 */
+ unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1;
+ unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1;
+
+ unsigned char res2 = (bit3e ^ bit5e);
+
+ /* when res2 = 0 pass the phase from calculation above (res1); */
+ /* when res2 = 1 phase = 0x200 | (0xd0>>2); */
+ if (res2)
+ phase = (0x200|(0xd0>>2));
+
+
+ /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */
+ /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */
+ if (phase&0x200)
+ {
+ if (noise)
+ phase = 0x200|0xd0;
+ }
+ else
+ /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */
+ /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */
+ {
+ if (noise)
+ phase = 0xd0>>2;
+ }
+
+ output[0] += op_calc(phase<<FREQ_SH, env, 0, SLOT7_1->wavetable) * 2;
+ }
+
+ /* Snare Drum (verified on real YM3812) */
+ env = volume_calc(SLOT7_2);
+ if( env < ENV_QUIET )
+ {
+ /* base frequency derived from operator 1 in channel 7 */
+ unsigned char bit8 = ((SLOT7_1->Cnt>>FREQ_SH)>>8)&1;
+
+ /* when bit8 = 0 phase = 0x100; */
+ /* when bit8 = 1 phase = 0x200; */
+ UINT32 phase = bit8 ? 0x200 : 0x100;
+
+ /* Noise bit XOR'es phase by 0x100 */
+ /* when noisebit = 0 pass the phase from calculation above */
+ /* when noisebit = 1 phase ^= 0x100; */
+ /* in other words: phase ^= (noisebit<<8); */
+ if (noise)
+ phase ^= 0x100;
+
+ output[0] += op_calc(phase<<FREQ_SH, env, 0, SLOT7_2->wavetable) * 2;
+ }
+
+ /* Tom Tom (verified on real YM3812) */
+ env = volume_calc(SLOT8_1);
+ if( env < ENV_QUIET )
+ output[0] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2;
+
+ /* Top Cymbal (verified on real YM3812) */
+ env = volume_calc(SLOT8_2);
+ if( env < ENV_QUIET )
+ {
+ /* base frequency derived from operator 1 in channel 7 */
+ unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1;
+ unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1;
+ unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1;
+
+ unsigned char res1 = (bit2 ^ bit7) | bit3;
+
+ /* when res1 = 0 phase = 0x000 | 0x100; */
+ /* when res1 = 1 phase = 0x200 | 0x100; */
+ UINT32 phase = res1 ? 0x300 : 0x100;
+
+ /* enable gate based on frequency of operator 2 in channel 8 */
+ unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1;
+ unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1;
+
+ unsigned char res2 = (bit3e ^ bit5e);
+ /* when res2 = 0 pass the phase from calculation above (res1); */
+ /* when res2 = 1 phase = 0x200 | 0x100; */
+ if (res2)
+ phase = 0x300;
+
+ output[0] += op_calc(phase<<FREQ_SH, env, 0, SLOT8_2->wavetable) * 2;
+ }
+
+}
+
+
+/* generic table initialize */
+static int init_tables(void)
+{
+ signed int i,x;
+ signed int n;
+ double o,m;
+
+
+ for (x=0; x<TL_RES_LEN; x++)
+ {
+ m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0);
+ m = floor(m);
+
+ /* we never reach (1<<16) here due to the (x+1) */
+ /* result fits within 16 bits at maximum */
+
+ n = (int)m; /* 16 bits here */
+ n >>= 4; /* 12 bits here */
+ if (n&1) /* round to nearest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+ /* 11 bits here (rounded) */
+ n <<= 1; /* 12 bits here (as in real chip) */
+ tl_tab[ x*2 + 0 ] = n;
+ tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ];
+
+ for (i=1; i<12; i++)
+ {
+ tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i;
+ tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ];
+ }
+ #if 0
+ logerror("tl %04i", x*2);
+ for (i=0; i<12; i++)
+ logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] );
+ logerror("\n");
+ #endif
+ }
+ /*logerror("FMOPL.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/
+
+
+ for (i=0; i<SIN_LEN; i++)
+ {
+ /* non-standard sinus */
+ m = sin( ((i*2)+1) * M_PI / SIN_LEN ); /* checked against the real chip */
+
+ /* we never reach zero here due to ((i*2)+1) */
+
+ if (m>0.0)
+ o = 8*log(1.0/m)/log(2); /* convert to 'decibels' */
+ else
+ o = 8*log(-1.0/m)/log(2); /* convert to 'decibels' */
+
+ o = o / (ENV_STEP/4);
+
+ n = (int)(2.0*o);
+ if (n&1) /* round to nearest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+
+ sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 );
+
+ /*logerror("FMOPL.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/
+ }
+
+ for (i=0; i<SIN_LEN; i++)
+ {
+ /* waveform 1: __ __ */
+ /* / \____/ \____*/
+ /* output only first half of the sinus waveform (positive one) */
+
+ if (i & (1<<(SIN_BITS-1)) )
+ sin_tab[1*SIN_LEN+i] = TL_TAB_LEN;
+ else
+ sin_tab[1*SIN_LEN+i] = sin_tab[i];
+
+ /* waveform 2: __ __ __ __ */
+ /* / \/ \/ \/ \*/
+ /* abs(sin) */
+
+ sin_tab[2*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>1) ];
+
+ /* waveform 3: _ _ _ _ */
+ /* / |_/ |_/ |_/ |_*/
+ /* abs(output only first quarter of the sinus waveform) */
+
+ if (i & (1<<(SIN_BITS-2)) )
+ sin_tab[3*SIN_LEN+i] = TL_TAB_LEN;
+ else
+ sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)];
+
+ /*logerror("FMOPL.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] );
+ logerror("FMOPL.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] );
+ logerror("FMOPL.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] );*/
+ }
+ /*logerror("FMOPL.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/
+
+
+#ifdef SAVE_SAMPLE
+ sample[0]=fopen("sampsum.pcm","wb");
+#endif
+
+ return 1;
+}
+
+static void OPLCloseTable( void )
+{
+#ifdef SAVE_SAMPLE
+ fclose(sample[0]);
+#endif
+}
+
+
+
+static void OPL_initalize(FM_OPL *OPL)
+{
+ int i;
+
+ /* frequency base */
+ OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / 72.0) / OPL->rate : 0;
+#if 0
+ OPL->rate = (double)OPL->clock / 72.0;
+ OPL->freqbase = 1.0;
+#endif
+
+ /*logerror("freqbase=%f\n", OPL->freqbase);*/
+
+ /* Timer base time */
+ OPL->TimerBase = attotime_mul(ATTOTIME_IN_HZ(OPL->clock), 72);
+
+ /* make fnumber -> increment counter table */
+ for( i=0 ; i < 1024 ; i++ )
+ {
+ /* opn phase increment counter = 20bit */
+ OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
+#if 0
+ logerror("FMOPL.C: fn_tab[%4i] = %08x (dec=%8i)\n",
+ i, OPL->fn_tab[i]>>6, OPL->fn_tab[i]>>6 );
+#endif
+ }
+
+#if 0
+ for( i=0 ; i < 16 ; i++ )
+ {
+ logerror("FMOPL.C: sl_tab[%i] = %08x\n",
+ i, sl_tab[i] );
+ }
+ for( i=0 ; i < 8 ; i++ )
+ {
+ int j;
+ logerror("FMOPL.C: ksl_tab[oct=%2i] =",i);
+ for (j=0; j<16; j++)
+ {
+ logerror("%08x ", ksl_tab[i*16+j] );
+ }
+ logerror("\n");
+ }
+#endif
+
+
+ /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */
+ /* One entry from LFO_AM_TABLE lasts for 64 samples */
+ OPL->lfo_am_inc = (1.0 / 64.0 ) * (1<<LFO_SH) * OPL->freqbase;
+
+ /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */
+ OPL->lfo_pm_inc = (1.0 / 1024.0) * (1<<LFO_SH) * OPL->freqbase;
+
+ /*logerror ("OPL->lfo_am_inc = %8x ; OPL->lfo_pm_inc = %8x\n", OPL->lfo_am_inc, OPL->lfo_pm_inc);*/
+
+ /* Noise generator: a step takes 1 sample */
+ OPL->noise_f = (1.0 / 1.0) * (1<<FREQ_SH) * OPL->freqbase;
+
+ OPL->eg_timer_add = (1<<EG_SH) * OPL->freqbase;
+ OPL->eg_timer_overflow = ( 1 ) * (1<<EG_SH);
+ /*logerror("OPLinit eg_timer_add=%8x eg_timer_overflow=%8x\n", OPL->eg_timer_add, OPL->eg_timer_overflow);*/
+
+}
+
+INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set)
+{
+ if( !SLOT->key )
+ {
+ /* restart Phase Generator */
+ SLOT->Cnt = 0;
+ /* phase -> Attack */
+ SLOT->state = EG_ATT;
+ }
+ SLOT->key |= key_set;
+}
+
+INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr)
+{
+ if( SLOT->key )
+ {
+ SLOT->key &= key_clr;
+
+ if( !SLOT->key )
+ {
+ /* phase -> Release */
+ if (SLOT->state>EG_REL)
+ SLOT->state = EG_REL;
+ }
+ }
+}
+
+/* update phase increment counter of operator (also update the EG rates if necessary) */
+INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
+{
+ int ksr;
+
+ /* (frequency) phase increment counter */
+ SLOT->Incr = CH->fc * SLOT->mul;
+ ksr = CH->kcode >> SLOT->KSR;
+
+ if( SLOT->ksr != ksr )
+ {
+ SLOT->ksr = ksr;
+
+ /* calculate envelope generator rates */
+ if ((SLOT->ar + SLOT->ksr) < 16+62)
+ {
+ SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
+ SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
+ }
+ else
+ {
+ SLOT->eg_sh_ar = 0;
+ SLOT->eg_sel_ar = 13*RATE_STEPS;
+ }
+ SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ];
+ SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ];
+ SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ];
+ SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ];
+ }
+}
+
+/* set multi,am,vib,EG-TYP,KSR,mul */
+INLINE void set_mul(FM_OPL *OPL,int slot,int v)
+{
+ OPL_CH *CH = &OPL->P_CH[slot/2];
+ OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ SLOT->mul = mul_tab[v&0x0f];
+ SLOT->KSR = (v&0x10) ? 0 : 2;
+ SLOT->eg_type = (v&0x20);
+ SLOT->vib = (v&0x40);
+ SLOT->AMmask = (v&0x80) ? ~0 : 0;
+ CALC_FCSLOT(CH,SLOT);
+}
+
+/* set ksl & tl */
+INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v)
+{
+ OPL_CH *CH = &OPL->P_CH[slot/2];
+ OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+ int ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */
+
+ SLOT->ksl = ksl ? 3-ksl : 31;
+ SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */
+
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+}
+
+/* set attack rate & decay rate */
+INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
+{
+ OPL_CH *CH = &OPL->P_CH[slot/2];
+ OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0;
+
+ if ((SLOT->ar + SLOT->ksr) < 16+62)
+ {
+ SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
+ SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
+ }
+ else
+ {
+ SLOT->eg_sh_ar = 0;
+ SLOT->eg_sel_ar = 13*RATE_STEPS;
+ }
+
+ SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0;
+ SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ];
+ SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ];
+}
+
+/* set sustain level & release rate */
+INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v)
+{
+ OPL_CH *CH = &OPL->P_CH[slot/2];
+ OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ SLOT->sl = sl_tab[ v>>4 ];
+
+ SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0;
+ SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ];
+ SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ];
+}
+
+
+/* write a value v to register r on OPL chip */
+static void OPLWriteReg(FM_OPL *OPL, int r, int v)
+{
+ OPL_CH *CH;
+ int slot;
+ int block_fnum;
+
+
+ /* adjust bus to 8 bits */
+ r &= 0xff;
+ v &= 0xff;
+
+#ifdef LOG_CYM_FILE
+ if ((cymfile) && (r!=0) )
+ {
+ fputc( (unsigned char)r, cymfile );
+ fputc( (unsigned char)v, cymfile );
+ }
+#endif
+
+
+ switch(r&0xe0)
+ {
+ case 0x00: /* 00-1f:control */
+ switch(r&0x1f)
+ {
+ case 0x01: /* waveform select enable */
+ if(OPL->type&OPL_TYPE_WAVESEL)
+ {
+ OPL->wavesel = v&0x20;
+ /* do not change the waveform previously selected */
+ }
+ break;
+ case 0x02: /* Timer 1 */
+ OPL->T[0] = (256-v)*4;
+ break;
+ case 0x03: /* Timer 2 */
+ OPL->T[1] = (256-v)*16;
+ break;
+ case 0x04: /* IRQ clear / mask and Timer enable */
+ if(v&0x80)
+ { /* IRQ flag clear */
+ OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */
+ }
+ else
+ { /* set IRQ mask ,timer enable*/
+ UINT8 st1 = v&1;
+ UINT8 st2 = (v>>1)&1;
+
+ /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
+ OPL_STATUS_RESET(OPL, v & (0x78-0x08) );
+ OPL_STATUSMASK_SET(OPL, (~v) & 0x78 );
+
+ /* timer 2 */
+ if(OPL->st[1] != st2)
+ {
+ attotime period = st2 ? attotime_mul(OPL->TimerBase, OPL->T[1]) : attotime_zero;
+ OPL->st[1] = st2;
+ if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,1,period);
+ }
+ /* timer 1 */
+ if(OPL->st[0] != st1)
+ {
+ attotime period = st1 ? attotime_mul(OPL->TimerBase, OPL->T[0]) : attotime_zero;
+ OPL->st[0] = st1;
+ if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,0,period);
+ }
+ }
+ break;
+#if BUILD_Y8950
+ case 0x06: /* Key Board OUT */
+ if(OPL->type&OPL_TYPE_KEYBOARD)
+ {
+ if(OPL->keyboardhandler_w)
+ OPL->keyboardhandler_w(OPL->keyboard_param,v);
+ else
+ logerror("Y8950: write unmapped KEYBOARD port\n");
+ }
+ break;
+ case 0x07: /* DELTA-T control 1 : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
+ if(OPL->type&OPL_TYPE_ADPCM)
+ YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
+ break;
+#endif
+ case 0x08: /* MODE,DELTA-T control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
+ OPL->mode = v;
+#if BUILD_Y8950
+ if(OPL->type&OPL_TYPE_ADPCM)
+ YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v&0x0f); /* mask 4 LSBs in register 08 for DELTA-T unit */
+#endif
+ break;
+
+#if BUILD_Y8950
+ case 0x09: /* START ADD */
+ case 0x0a:
+ case 0x0b: /* STOP ADD */
+ case 0x0c:
+ case 0x0d: /* PRESCALE */
+ case 0x0e:
+ case 0x0f: /* ADPCM data write */
+ case 0x10: /* DELTA-N */
+ case 0x11: /* DELTA-N */
+ case 0x12: /* ADPCM volume */
+ if(OPL->type&OPL_TYPE_ADPCM)
+ YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
+ break;
+
+ case 0x15: /* DAC data high 8 bits (F7,F6...F2) */
+ case 0x16: /* DAC data low 2 bits (F1, F0 in bits 7,6) */
+ case 0x17: /* DAC data shift (S2,S1,S0 in bits 2,1,0) */
+ logerror("FMOPL.C: DAC data register written, but not implemented reg=%02x val=%02x\n",r,v);
+ break;
+
+ case 0x18: /* I/O CTRL (Direction) */
+ if(OPL->type&OPL_TYPE_IO)
+ OPL->portDirection = v&0x0f;
+ break;
+ case 0x19: /* I/O DATA */
+ if(OPL->type&OPL_TYPE_IO)
+ {
+ OPL->portLatch = v;
+ if(OPL->porthandler_w)
+ OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
+ }
+ break;
+#endif
+ default:
+ logerror("FMOPL.C: write to unknown register: %02x\n",r);
+ break;
+ }
+ break;
+ case 0x20: /* am ON, vib ON, ksr, eg_type, mul */
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+ set_mul(OPL,slot,v);
+ break;
+ case 0x40:
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+ set_ksl_tl(OPL,slot,v);
+ break;
+ case 0x60:
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+ set_ar_dr(OPL,slot,v);
+ break;
+ case 0x80:
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+ set_sl_rr(OPL,slot,v);
+ break;
+ case 0xa0:
+ if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */
+ {
+ OPL->lfo_am_depth = v & 0x80;
+ OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0;
+
+ OPL->rhythm = v&0x3f;
+
+ if(OPL->rhythm&0x20)
+ {
+ /* BD key on/off */
+ if(v&0x10)
+ {
+ FM_KEYON (&OPL->P_CH[6].SLOT[SLOT1], 2);
+ FM_KEYON (&OPL->P_CH[6].SLOT[SLOT2], 2);
+ }
+ else
+ {
+ FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2);
+ FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2);
+ }
+ /* HH key on/off */
+ if(v&0x01) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT1], 2);
+ else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2);
+ /* SD key on/off */
+ if(v&0x08) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT2], 2);
+ else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2);
+ /* TOM key on/off */
+ if(v&0x04) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT1], 2);
+ else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2);
+ /* TOP-CY key on/off */
+ if(v&0x02) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT2], 2);
+ else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2);
+ }
+ else
+ {
+ /* BD key off */
+ FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2);
+ FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2);
+ /* HH key off */
+ FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2);
+ /* SD key off */
+ FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2);
+ /* TOM key off */
+ FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2);
+ /* TOP-CY off */
+ FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2);
+ }
+ return;
+ }
+ /* keyon,block,fnum */
+ if( (r&0x0f) > 8) return;
+ CH = &OPL->P_CH[r&0x0f];
+ if(!(r&0x10))
+ { /* a0-a8 */
+ block_fnum = (CH->block_fnum&0x1f00) | v;
+ }
+ else
+ { /* b0-b8 */
+ block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
+
+ if(v&0x20)
+ {
+ FM_KEYON (&CH->SLOT[SLOT1], 1);
+ FM_KEYON (&CH->SLOT[SLOT2], 1);
+ }
+ else
+ {
+ FM_KEYOFF(&CH->SLOT[SLOT1],~1);
+ FM_KEYOFF(&CH->SLOT[SLOT2],~1);
+ }
+ }
+ /* update */
+ if(CH->block_fnum != block_fnum)
+ {
+ UINT8 block = block_fnum >> 10;
+
+ CH->block_fnum = block_fnum;
+
+ CH->ksl_base = ksl_tab[block_fnum>>6];
+ CH->fc = OPL->fn_tab[block_fnum&0x03ff] >> (7-block);
+
+ /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */
+ CH->kcode = (CH->block_fnum&0x1c00)>>9;
+
+ /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */
+ /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */
+ /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */
+ if (OPL->mode&0x40)
+ CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */
+ else
+ CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */
+
+ /* refresh Total Level in both SLOTs of this channel */
+ CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl);
+ CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl);
+
+ /* refresh frequency counter in both SLOTs of this channel */
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+ }
+ break;
+ case 0xc0:
+ /* FB,C */
+ if( (r&0x0f) > 8) return;
+ CH = &OPL->P_CH[r&0x0f];
+ CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0;
+ CH->SLOT[SLOT1].CON = v&1;
+ CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &output[0] : &phase_modulation;
+ break;
+ case 0xe0: /* waveform select */
+ /* simply ignore write to the waveform select register if selecting not enabled in test register */
+ if(OPL->wavesel)
+ {
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+ CH = &OPL->P_CH[slot/2];
+
+ CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN;
+ }
+ break;
+ }
+}
+
+#ifdef LOG_CYM_FILE
+static TIMER_CALLBACK( cymfile_callback )
+{
+ if (cymfile)
+ {
+ fputc( (unsigned char)0, cymfile );
+ }
+}
+#endif
+
+/* lock/unlock for common table */
+static int OPL_LockTable(void)
+{
+ num_lock++;
+ if(num_lock>1) return 0;
+
+ /* first time */
+
+ cur_chip = NULL;
+ /* allocate total level table (128kb space) */
+ if( !init_tables() )
+ {
+ num_lock--;
+ return -1;
+ }
+
+#ifdef LOG_CYM_FILE
+ cymfile = fopen("3812_.cym","wb");
+ if (cymfile)
+ timer_pulse ( ATTOTIME_IN_HZ(110), 0, cymfile_callback); /*110 Hz pulse timer*/
+ else
+ logerror("Could not create file 3812_.cym\n");
+#endif
+
+ return 0;
+}
+
+static void OPL_UnLockTable(void)
+{
+ if(num_lock) num_lock--;
+ if(num_lock) return;
+
+ /* last time */
+
+ cur_chip = NULL;
+ OPLCloseTable();
+
+#ifdef LOG_CYM_FILE
+ fclose (cymfile);
+ cymfile = NULL;
+#endif
+
+}
+
+static void OPLResetChip(FM_OPL *OPL)
+{
+ int c,s;
+ int i;
+
+ OPL->eg_timer = 0;
+ OPL->eg_cnt = 0;
+
+ OPL->noise_rng = 1; /* noise shift register */
+ OPL->mode = 0; /* normal mode */
+ OPL_STATUS_RESET(OPL,0x7f);
+
+ /* reset with register write */
+ OPLWriteReg(OPL,0x01,0); /* wavesel disable */
+ OPLWriteReg(OPL,0x02,0); /* Timer1 */
+ OPLWriteReg(OPL,0x03,0); /* Timer2 */
+ OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */
+ for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
+
+ /* reset operator parameters */
+ for( c = 0 ; c < 9 ; c++ )
+ {
+ OPL_CH *CH = &OPL->P_CH[c];
+ for(s = 0 ; s < 2 ; s++ )
+ {
+ /* wave table */
+ CH->SLOT[s].wavetable = 0;
+ CH->SLOT[s].state = EG_OFF;
+ CH->SLOT[s].volume = MAX_ATT_INDEX;
+ }
+ }
+#if BUILD_Y8950
+ if(OPL->type&OPL_TYPE_ADPCM)
+ {
+ YM_DELTAT *DELTAT = OPL->deltat;
+
+ DELTAT->freqbase = OPL->freqbase;
+ DELTAT->output_pointer = &output_deltat[0];
+ DELTAT->portshift = 5;
+ DELTAT->output_range = 1<<23;
+ YM_DELTAT_ADPCM_Reset(DELTAT,0,YM_DELTAT_EMULATION_MODE_NORMAL);
+ }
+#endif
+}
+
+
+static void OPL_postload(void *param)
+{
+ FM_OPL *OPL = (FM_OPL *)param;
+ int slot, ch;
+
+ for( ch=0 ; ch < 9 ; ch++ )
+ {
+ OPL_CH *CH = &OPL->P_CH[ch];
+
+ /* Look up key scale level */
+ UINT32 block_fnum = CH->block_fnum;
+ CH->ksl_base = ksl_tab[block_fnum >> 6];
+ CH->fc = OPL->fn_tab[block_fnum & 0x03ff] >> (7 - (block_fnum >> 10));
+
+ for( slot=0 ; slot < 2 ; slot++ )
+ {
+ OPL_SLOT *SLOT = &CH->SLOT[slot];
+
+ /* Calculate key scale rate */
+ SLOT->ksr = CH->kcode >> SLOT->KSR;
+
+ /* Calculate attack, decay and release rates */
+ if ((SLOT->ar + SLOT->ksr) < 16+62)
+ {
+ SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
+ SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
+ }
+ else
+ {
+ SLOT->eg_sh_ar = 0;
+ SLOT->eg_sel_ar = 13*RATE_STEPS;
+ }
+ SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ];
+ SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ];
+ SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ];
+ SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ];
+
+ /* Calculate phase increment */
+ SLOT->Incr = CH->fc * SLOT->mul;
+
+ /* Total level */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl);
+
+ /* Connect output */
+ SLOT->connect1 = SLOT->CON ? &output[0] : &phase_modulation;
+ }
+ }
+#if BUILD_Y8950
+ if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) )
+ {
+ // We really should call the postlod function for the YM_DELTAT, but it's hard without registers
+ // (see the way the YM2610 does it)
+ //YM_DELTAT_postload(OPL->deltat, REGS);
+ }
+#endif
+}
+
+
+static void OPLsave_state_channel(const char *name, int num, OPL_CH *CH)
+{
+ int slot, ch;
+ char state_name[20];
+ static const char slot_array[2] = { 1, 2 };
+
+ for( ch=0 ; ch < 9 ; ch++, CH++ )
+ {
+ /* channel */
+ sprintf(state_name, "%s.CH%d", name,ch);
+ state_save_register_item(state_name, num, CH->block_fnum);
+ state_save_register_item(state_name, num, CH->kcode);
+ /* slots */
+ for( slot=0 ; slot < 2 ; slot++ )
+ {
+ OPL_SLOT *SLOT = &CH->SLOT[slot];
+
+ sprintf(state_name, "%s.CH%d.SLOT%d", name, ch, slot_array[slot]);
+
+ state_save_register_item(state_name, num, SLOT->ar);
+ state_save_register_item(state_name, num, SLOT->dr);
+ state_save_register_item(state_name, num, SLOT->rr);
+ state_save_register_item(state_name, num, SLOT->KSR);
+ state_save_register_item(state_name, num, SLOT->ksl);
+ state_save_register_item(state_name, num, SLOT->mul);
+
+ state_save_register_item(state_name, num, SLOT->Cnt);
+ state_save_register_item(state_name, num, SLOT->FB);
+ state_save_register_item_array(state_name, num, SLOT->op1_out);
+ state_save_register_item(state_name, num, SLOT->CON);
+
+ state_save_register_item(state_name, num, SLOT->eg_type);
+ state_save_register_item(state_name, num, SLOT->state);
+ state_save_register_item(state_name, num, SLOT->TL);
+ state_save_register_item(state_name, num, SLOT->volume);
+ state_save_register_item(state_name, num, SLOT->sl);
+ state_save_register_item(state_name, num, SLOT->key);
+
+ state_save_register_item(state_name, num, SLOT->AMmask);
+ state_save_register_item(state_name, num, SLOT->vib);
+
+ state_save_register_item(state_name, num, SLOT->wavetable);
+ }
+ }
+}
+
+
+/* Register savestate for a virtual YM3812/YM3526Y8950 */
+
+static void OPL_save_state(FM_OPL *OPL, const char *statename, int index)
+{
+ OPLsave_state_channel(statename, index, OPL->P_CH);
+
+ state_save_register_item(statename, index, OPL->eg_cnt);
+ state_save_register_item(statename, index, OPL->eg_timer);
+
+ state_save_register_item(statename, index, OPL->rhythm);
+
+ state_save_register_item(statename, index, OPL->lfo_am_depth);
+ state_save_register_item(statename, index, OPL->lfo_pm_depth_range);
+ state_save_register_item(statename, index, OPL->lfo_am_cnt);
+ state_save_register_item(statename, index, OPL->lfo_pm_cnt);
+
+ state_save_register_item(statename, index, OPL->noise_rng);
+ state_save_register_item(statename, index, OPL->noise_p);
+
+ if( OPL->type & OPL_TYPE_WAVESEL )
+ {
+ state_save_register_item(statename, index, OPL->wavesel);
+ }
+
+ state_save_register_item_array(statename, index, OPL->T);
+ state_save_register_item_array(statename, index, OPL->st);
+
+#if BUILD_Y8950
+ if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) )
+ {
+ YM_DELTAT_savestate(statename, index, OPL->deltat);
+ }
+
+ if ( OPL->type & OPL_TYPE_IO )
+ {
+ state_save_register_item(statename, index, OPL->portDirection);
+ state_save_register_item(statename, index, OPL->portLatch);
+ }
+#endif
+
+ state_save_register_item(statename, index, OPL->address);
+ state_save_register_item(statename, index, OPL->status);
+ state_save_register_item(statename, index, OPL->statusmask);
+ state_save_register_item(statename, index, OPL->mode);
+
+ state_save_register_func_postload_ptr(OPL_postload, OPL);
+}
+
+
+/* Create one of virtual YM3812/YM3526/Y8950 */
+/* 'clock' is chip clock in Hz */
+/* 'rate' is sampling rate */
+static FM_OPL *OPLCreate(int type, UINT32 clock, UINT32 rate)
+{
+ char *ptr;
+ FM_OPL *OPL;
+ int state_size;
+
+ if (OPL_LockTable() ==-1) return NULL;
+
+ /* calculate OPL state size */
+ state_size = sizeof(FM_OPL);
+
+#if BUILD_Y8950
+ if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
+#endif
+
+ /* allocate memory block */
+ ptr = malloc(state_size);
+
+ if (ptr==NULL)
+ return NULL;
+
+ /* clear */
+ memset(ptr,0,state_size);
+
+ OPL = (FM_OPL *)ptr;
+
+ ptr += sizeof(FM_OPL);
+
+#if BUILD_Y8950
+ if (type&OPL_TYPE_ADPCM)
+ {
+ OPL->deltat = (YM_DELTAT *)ptr;
+ }
+ ptr += sizeof(YM_DELTAT);
+#endif
+
+ OPL->type = type;
+ OPL->clock = clock;
+ OPL->rate = rate;
+
+ /* init global tables */
+ OPL_initalize(OPL);
+
+ return OPL;
+}
+
+/* Destroy one of virtual YM3812 */
+static void OPLDestroy(FM_OPL *OPL)
+{
+ OPL_UnLockTable();
+ free(OPL);
+}
+
+/* Optional handlers */
+
+static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER timer_handler,void *param)
+{
+ OPL->timer_handler = timer_handler;
+ OPL->TimerParam = param;
+}
+static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,void *param)
+{
+ OPL->IRQHandler = IRQHandler;
+ OPL->IRQParam = param;
+}
+static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,void *param)
+{
+ OPL->UpdateHandler = UpdateHandler;
+ OPL->UpdateParam = param;
+}
+
+static int OPLWrite(FM_OPL *OPL,int a,int v)
+{
+ if( !(a&1) )
+ { /* address port */
+ OPL->address = v & 0xff;
+ }
+ else
+ { /* data port */
+ if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
+ OPLWriteReg(OPL,OPL->address,v);
+ }
+ return OPL->status>>7;
+}
+
+static unsigned char OPLRead(FM_OPL *OPL,int a)
+{
+ if( !(a&1) )
+ {
+ /* status port */
+
+ #if BUILD_Y8950
+
+ if(OPL->type&OPL_TYPE_ADPCM) /* Y8950 */
+ {
+ return (OPL->status & (OPL->statusmask|0x80)) | (OPL->deltat->PCM_BSY&1);
+ }
+
+ #endif
+
+ /* OPL and OPL2 */
+ return OPL->status & (OPL->statusmask|0x80);
+ }
+
+#if BUILD_Y8950
+ /* data port */
+ switch(OPL->address)
+ {
+ case 0x05: /* KeyBoard IN */
+ if(OPL->type&OPL_TYPE_KEYBOARD)
+ {
+ if(OPL->keyboardhandler_r)
+ return OPL->keyboardhandler_r(OPL->keyboard_param);
+ else
+ logerror("Y8950: read unmapped KEYBOARD port\n");
+ }
+ return 0;
+
+ case 0x0f: /* ADPCM-DATA */
+ if(OPL->type&OPL_TYPE_ADPCM)
+ {
+ UINT8 val;
+
+ val = YM_DELTAT_ADPCM_Read(OPL->deltat);
+ /*logerror("Y8950: read ADPCM value read=%02x\n",val);*/
+ return val;
+ }
+ return 0;
+
+ case 0x19: /* I/O DATA */
+ if(OPL->type&OPL_TYPE_IO)
+ {
+ if(OPL->porthandler_r)
+ return OPL->porthandler_r(OPL->port_param);
+ else
+ logerror("Y8950:read unmapped I/O port\n");
+ }
+ return 0;
+ case 0x1a: /* PCM-DATA */
+ if(OPL->type&OPL_TYPE_ADPCM)
+ {
+ logerror("Y8950 A/D convertion is accessed but not implemented !\n");
+ return 0x80; /* 2's complement PCM data - result from A/D convertion */
+ }
+ return 0;
+ }
+#endif
+
+ return 0xff;
+}
+
+/* CSM Key Controll */
+INLINE void CSMKeyControll(OPL_CH *CH)
+{
+ FM_KEYON (&CH->SLOT[SLOT1], 4);
+ FM_KEYON (&CH->SLOT[SLOT2], 4);
+
+ /* The key off should happen exactly one sample later - not implemented correctly yet */
+
+ FM_KEYOFF(&CH->SLOT[SLOT1], ~4);
+ FM_KEYOFF(&CH->SLOT[SLOT2], ~4);
+}
+
+
+static int OPLTimerOver(FM_OPL *OPL,int c)
+{
+ if( c )
+ { /* Timer B */
+ OPL_STATUS_SET(OPL,0x20);
+ }
+ else
+ { /* Timer A */
+ OPL_STATUS_SET(OPL,0x40);
+ /* CSM mode key,TL controll */
+ if( OPL->mode & 0x80 )
+ { /* CSM mode total level latch and auto key on */
+ int ch;
+ if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
+ for(ch=0; ch<9; ch++)
+ CSMKeyControll( &OPL->P_CH[ch] );
+ }
+ }
+ /* reload timer */
+ if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,c,attotime_mul(OPL->TimerBase, OPL->T[c]));
+ return OPL->status>>7;
+}
+
+
+#define MAX_OPL_CHIPS 2
+
+
+#if (BUILD_YM3812)
+
+void * YM3812Init(int sndindex, UINT32 clock, UINT32 rate)
+{
+ /* emulator create */
+ FM_OPL *YM3812 = OPLCreate(OPL_TYPE_YM3812,clock,rate);
+ if (YM3812)
+ {
+ OPL_save_state(YM3812, "YM3812", sndindex);
+ YM3812ResetChip(YM3812);
+ }
+ return YM3812;
+}
+
+void YM3812Shutdown(void *chip)
+{
+ FM_OPL *YM3812 = chip;
+
+ /* emulator shutdown */
+ OPLDestroy(YM3812);
+}
+void YM3812ResetChip(void *chip)
+{
+ FM_OPL *YM3812 = chip;
+ OPLResetChip(YM3812);
+}
+
+int YM3812Write(void *chip, int a, int v)
+{
+ FM_OPL *YM3812 = chip;
+ return OPLWrite(YM3812, a, v);
+}
+
+unsigned char YM3812Read(void *chip, int a)
+{
+ FM_OPL *YM3812 = chip;
+ /* YM3812 always returns bit2 and bit1 in HIGH state */
+ return OPLRead(YM3812, a) | 0x06 ;
+}
+int YM3812TimerOver(void *chip, int c)
+{
+ FM_OPL *YM3812 = chip;
+ return OPLTimerOver(YM3812, c);
+}
+
+void YM3812SetTimerHandler(void *chip, OPL_TIMERHANDLER timer_handler, void *param)
+{
+ FM_OPL *YM3812 = chip;
+ OPLSetTimerHandler(YM3812, timer_handler, param);
+}
+void YM3812SetIRQHandler(void *chip,OPL_IRQHANDLER IRQHandler,void *param)
+{
+ FM_OPL *YM3812 = chip;
+ OPLSetIRQHandler(YM3812, IRQHandler, param);
+}
+void YM3812SetUpdateHandler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param)
+{
+ FM_OPL *YM3812 = chip;
+ OPLSetUpdateHandler(YM3812, UpdateHandler, param);
+}
+
+
+/*
+** Generate samples for one of the YM3812's
+**
+** 'which' is the virtual YM3812 number
+** '*buffer' is the output buffer pointer
+** 'length' is the number of samples that should be generated
+*/
+void YM3812UpdateOne(void *chip, OPLSAMPLE *buffer, int length)
+{
+ FM_OPL *OPL = chip;
+ UINT8 rhythm = OPL->rhythm&0x20;
+ OPLSAMPLE *buf = buffer;
+ int i;
+
+ if( (void *)OPL != cur_chip ){
+ cur_chip = (void *)OPL;
+ /* rhythm slots */
+ SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1];
+ SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2];
+ SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1];
+ SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2];
+ }
+ for( i=0; i < length ; i++ )
+ {
+ int lt;
+
+ output[0] = 0;
+
+ advance_lfo(OPL);
+
+ /* FM part */
+ OPL_CALC_CH(&OPL->P_CH[0]);
+ OPL_CALC_CH(&OPL->P_CH[1]);
+ OPL_CALC_CH(&OPL->P_CH[2]);
+ OPL_CALC_CH(&OPL->P_CH[3]);
+ OPL_CALC_CH(&OPL->P_CH[4]);
+ OPL_CALC_CH(&OPL->P_CH[5]);
+
+ if(!rhythm)
+ {
+ OPL_CALC_CH(&OPL->P_CH[6]);
+ OPL_CALC_CH(&OPL->P_CH[7]);
+ OPL_CALC_CH(&OPL->P_CH[8]);
+ }
+ else /* Rhythm part */
+ {
+ OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 );
+ }
+
+ lt = output[0];
+
+ lt >>= FINAL_SH;
+
+ /* limit check */
+ lt = limit( lt , MAXOUT, MINOUT );
+
+ #ifdef SAVE_SAMPLE
+ if (which==0)
+ {
+ SAVE_ALL_CHANNELS
+ }
+ #endif
+
+ /* store to sound buffer */
+ buf[i] = lt;
+
+ advance(OPL);
+ }
+
+}
+#endif /* BUILD_YM3812 */
+
+
+
+#if (BUILD_YM3526)
+
+void *YM3526Init(int sndindex, UINT32 clock, UINT32 rate)
+{
+ /* emulator create */
+ FM_OPL *YM3526 = OPLCreate(OPL_TYPE_YM3526,clock,rate);
+ if (YM3526)
+ {
+ OPL_save_state(YM3526, "YM3526", sndindex);
+ YM3526ResetChip(YM3526);
+ }
+ return YM3526;
+}
+
+void YM3526Shutdown(void *chip)
+{
+ FM_OPL *YM3526 = chip;
+ /* emulator shutdown */
+ OPLDestroy(YM3526);
+}
+void YM3526ResetChip(void *chip)
+{
+ FM_OPL *YM3526 = chip;
+ OPLResetChip(YM3526);
+}
+
+int YM3526Write(void *chip, int a, int v)
+{
+ FM_OPL *YM3526 = chip;
+ return OPLWrite(YM3526, a, v);
+}
+
+unsigned char YM3526Read(void *chip, int a)
+{
+ FM_OPL *YM3526 = chip;
+ /* YM3526 always returns bit2 and bit1 in HIGH state */
+ return OPLRead(YM3526, a) | 0x06 ;
+}
+int YM3526TimerOver(void *chip, int c)
+{
+ FM_OPL *YM3526 = chip;
+ return OPLTimerOver(YM3526, c);
+}
+
+void YM3526SetTimerHandler(void *chip, OPL_TIMERHANDLER timer_handler, void *param)
+{
+ FM_OPL *YM3526 = chip;
+ OPLSetTimerHandler(YM3526, timer_handler, param);
+}
+void YM3526SetIRQHandler(void *chip,OPL_IRQHANDLER IRQHandler,void *param)
+{
+ FM_OPL *YM3526 = chip;
+ OPLSetIRQHandler(YM3526, IRQHandler, param);
+}
+void YM3526SetUpdateHandler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param)
+{
+ FM_OPL *YM3526 = chip;
+ OPLSetUpdateHandler(YM3526, UpdateHandler, param);
+}
+
+
+/*
+** Generate samples for one of the YM3526's
+**
+** 'which' is the virtual YM3526 number
+** '*buffer' is the output buffer pointer
+** 'length' is the number of samples that should be generated
+*/
+void YM3526UpdateOne(void *chip, OPLSAMPLE *buffer, int length)
+{
+ FM_OPL *OPL = chip;
+ UINT8 rhythm = OPL->rhythm&0x20;
+ OPLSAMPLE *buf = buffer;
+ int i;
+
+ if( (void *)OPL != cur_chip ){
+ cur_chip = (void *)OPL;
+ /* rhythm slots */
+ SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1];
+ SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2];
+ SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1];
+ SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2];
+ }
+ for( i=0; i < length ; i++ )
+ {
+ int lt;
+
+ output[0] = 0;
+
+ advance_lfo(OPL);
+
+ /* FM part */
+ OPL_CALC_CH(&OPL->P_CH[0]);
+ OPL_CALC_CH(&OPL->P_CH[1]);
+ OPL_CALC_CH(&OPL->P_CH[2]);
+ OPL_CALC_CH(&OPL->P_CH[3]);
+ OPL_CALC_CH(&OPL->P_CH[4]);
+ OPL_CALC_CH(&OPL->P_CH[5]);
+
+ if(!rhythm)
+ {
+ OPL_CALC_CH(&OPL->P_CH[6]);
+ OPL_CALC_CH(&OPL->P_CH[7]);
+ OPL_CALC_CH(&OPL->P_CH[8]);
+ }
+ else /* Rhythm part */
+ {
+ OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 );
+ }
+
+ lt = output[0];
+
+ lt >>= FINAL_SH;
+
+ /* limit check */
+ lt = limit( lt , MAXOUT, MINOUT );
+
+ #ifdef SAVE_SAMPLE
+ if (which==0)
+ {
+ SAVE_ALL_CHANNELS
+ }
+ #endif
+
+ /* store to sound buffer */
+ buf[i] = lt;
+
+ advance(OPL);
+ }
+
+}
+#endif /* BUILD_YM3526 */
+
+
+
+
+#if BUILD_Y8950
+
+static void Y8950_deltat_status_set(void *chip, UINT8 changebits)
+{
+ FM_OPL *Y8950 = chip;
+ OPL_STATUS_SET(Y8950, changebits);
+}
+static void Y8950_deltat_status_reset(void *chip, UINT8 changebits)
+{
+ FM_OPL *Y8950 = chip;
+ OPL_STATUS_RESET(Y8950, changebits);
+}
+
+void *Y8950Init(int sndindex, UINT32 clock, UINT32 rate)
+{
+ /* emulator create */
+ FM_OPL *Y8950 = OPLCreate(OPL_TYPE_Y8950,clock,rate);
+ if (Y8950)
+ {
+ Y8950->deltat->status_set_handler = Y8950_deltat_status_set;
+ Y8950->deltat->status_reset_handler = Y8950_deltat_status_reset;
+ Y8950->deltat->status_change_which_chip = Y8950;
+ Y8950->deltat->status_change_EOS_bit = 0x10; /* status flag: set bit4 on End Of Sample */
+ Y8950->deltat->status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY (End Of: ADPCM analysis/synthesis, memory reading/writing) */
+
+ /*Y8950->deltat->write_time = 10.0 / clock;*/ /* a single byte write takes 10 cycles of main clock */
+ /*Y8950->deltat->read_time = 8.0 / clock;*/ /* a single byte read takes 8 cycles of main clock */
+ /* reset */
+ OPL_save_state(Y8950, "Y8950", sndindex);
+ Y8950ResetChip(Y8950);
+ }
+
+ return Y8950;
+}
+
+void Y8950Shutdown(void *chip)
+{
+ FM_OPL *Y8950 = chip;
+ /* emulator shutdown */
+ OPLDestroy(Y8950);
+}
+void Y8950ResetChip(void *chip)
+{
+ FM_OPL *Y8950 = chip;
+ OPLResetChip(Y8950);
+}
+
+int Y8950Write(void *chip, int a, int v)
+{
+ FM_OPL *Y8950 = chip;
+ return OPLWrite(Y8950, a, v);
+}
+
+unsigned char Y8950Read(void *chip, int a)
+{
+ FM_OPL *Y8950 = chip;
+ return OPLRead(Y8950, a);
+}
+int Y8950TimerOver(void *chip, int c)
+{
+ FM_OPL *Y8950 = chip;
+ return OPLTimerOver(Y8950, c);
+}
+
+void Y8950SetTimerHandler(void *chip, OPL_TIMERHANDLER timer_handler, void *param)
+{
+ FM_OPL *Y8950 = chip;
+ OPLSetTimerHandler(Y8950, timer_handler, param);
+}
+void Y8950SetIRQHandler(void *chip,OPL_IRQHANDLER IRQHandler,void *param)
+{
+ FM_OPL *Y8950 = chip;
+ OPLSetIRQHandler(Y8950, IRQHandler, param);
+}
+void Y8950SetUpdateHandler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param)
+{
+ FM_OPL *Y8950 = chip;
+ OPLSetUpdateHandler(Y8950, UpdateHandler, param);
+}
+
+void Y8950SetDeltaTMemory(void *chip, void * deltat_mem_ptr, int deltat_mem_size )
+{
+ FM_OPL *OPL = chip;
+ OPL->deltat->memory = (UINT8 *)(deltat_mem_ptr);
+ OPL->deltat->memory_size = deltat_mem_size;
+}
+
+/*
+** Generate samples for one of the Y8950's
+**
+** 'which' is the virtual Y8950 number
+** '*buffer' is the output buffer pointer
+** 'length' is the number of samples that should be generated
+*/
+void Y8950UpdateOne(void *chip, OPLSAMPLE *buffer, int length)
+{
+ int i;
+ FM_OPL *OPL = chip;
+ UINT8 rhythm = OPL->rhythm&0x20;
+ YM_DELTAT *DELTAT = OPL->deltat;
+ OPLSAMPLE *buf = buffer;
+
+ if( (void *)OPL != cur_chip ){
+ cur_chip = (void *)OPL;
+ /* rhythm slots */
+ SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1];
+ SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2];
+ SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1];
+ SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2];
+
+ }
+ for( i=0; i < length ; i++ )
+ {
+ int lt;
+
+ output[0] = 0;
+ output_deltat[0] = 0;
+
+ advance_lfo(OPL);
+
+ /* deltaT ADPCM */
+ if( DELTAT->portstate&0x80 )
+ YM_DELTAT_ADPCM_CALC(DELTAT);
+
+ /* FM part */
+ OPL_CALC_CH(&OPL->P_CH[0]);
+ OPL_CALC_CH(&OPL->P_CH[1]);
+ OPL_CALC_CH(&OPL->P_CH[2]);
+ OPL_CALC_CH(&OPL->P_CH[3]);
+ OPL_CALC_CH(&OPL->P_CH[4]);
+ OPL_CALC_CH(&OPL->P_CH[5]);
+
+ if(!rhythm)
+ {
+ OPL_CALC_CH(&OPL->P_CH[6]);
+ OPL_CALC_CH(&OPL->P_CH[7]);
+ OPL_CALC_CH(&OPL->P_CH[8]);
+ }
+ else /* Rhythm part */
+ {
+ OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 );
+ }
+
+ lt = output[0] + (output_deltat[0]>>11);
+
+ lt >>= FINAL_SH;
+
+ /* limit check */
+ lt = limit( lt , MAXOUT, MINOUT );
+
+ #ifdef SAVE_SAMPLE
+ if (which==0)
+ {
+ SAVE_ALL_CHANNELS
+ }
+ #endif
+
+ /* store to sound buffer */
+ buf[i] = lt;
+
+ advance(OPL);
+ }
+
+}
+
+void Y8950SetPortHandler(void *chip,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,void * param)
+{
+ FM_OPL *OPL = chip;
+ OPL->porthandler_w = PortHandler_w;
+ OPL->porthandler_r = PortHandler_r;
+ OPL->port_param = param;
+}
+
+void Y8950SetKeyboardHandler(void *chip,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,void * param)
+{
+ FM_OPL *OPL = chip;
+ OPL->keyboardhandler_w = KeyboardHandler_w;
+ OPL->keyboardhandler_r = KeyboardHandler_r;
+ OPL->keyboard_param = param;
+}
+
+#endif
+
diff --git a/src/emu/sound/fmopl.h b/src/emu/sound/fmopl.h
new file mode 100644
index 00000000000..f9521144c22
--- /dev/null
+++ b/src/emu/sound/fmopl.h
@@ -0,0 +1,111 @@
+#ifndef __FMOPL_H_
+#define __FMOPL_H_
+
+/* --- select emulation chips --- */
+#define BUILD_YM3812 (HAS_YM3812)
+#define BUILD_YM3526 (HAS_YM3526)
+#define BUILD_Y8950 (HAS_Y8950)
+
+/* select output bits size of output : 8 or 16 */
+#define OPL_SAMPLE_BITS 16
+
+/* compiler dependence */
+#ifndef __OSDCOMM_H__
+#define __OSDCOMM_H__
+typedef unsigned char UINT8; /* unsigned 8bit */
+typedef unsigned short UINT16; /* unsigned 16bit */
+typedef unsigned int UINT32; /* unsigned 32bit */
+typedef signed char INT8; /* signed 8bit */
+typedef signed short INT16; /* signed 16bit */
+typedef signed int INT32; /* signed 32bit */
+#endif
+
+typedef stream_sample_t OPLSAMPLE;
+/*
+#if (OPL_SAMPLE_BITS==16)
+typedef INT16 OPLSAMPLE;
+#endif
+#if (OPL_SAMPLE_BITS==8)
+typedef INT8 OPLSAMPLE;
+#endif
+*/
+
+typedef void (*OPL_TIMERHANDLER)(void *param,int timer,attotime period);
+typedef void (*OPL_IRQHANDLER)(void *param,int irq);
+typedef void (*OPL_UPDATEHANDLER)(void *param,int min_interval_us);
+typedef void (*OPL_PORTHANDLER_W)(void *param,unsigned char data);
+typedef unsigned char (*OPL_PORTHANDLER_R)(void *param);
+
+
+#if BUILD_YM3812
+
+void *YM3812Init(int sndindex, UINT32 clock, UINT32 rate);
+void YM3812Shutdown(void *chip);
+void YM3812ResetChip(void *chip);
+int YM3812Write(void *chip, int a, int v);
+unsigned char YM3812Read(void *chip, int a);
+int YM3812TimerOver(void *chip, int c);
+void YM3812UpdateOne(void *chip, OPLSAMPLE *buffer, int length);
+
+void YM3812SetTimerHandler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
+void YM3812SetIRQHandler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
+void YM3812SetUpdateHandler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
+
+#endif
+
+
+#if BUILD_YM3526
+
+/*
+** Initialize YM3526 emulator(s).
+**
+** 'num' is the number of virtual YM3526's to allocate
+** 'clock' is the chip clock in Hz
+** 'rate' is sampling rate
+*/
+void *YM3526Init(int sndindex, UINT32 clock, UINT32 rate);
+/* shutdown the YM3526 emulators*/
+void YM3526Shutdown(void *chip);
+void YM3526ResetChip(void *chip);
+int YM3526Write(void *chip, int a, int v);
+unsigned char YM3526Read(void *chip, int a);
+int YM3526TimerOver(void *chip, int c);
+/*
+** Generate samples for one of the YM3526's
+**
+** 'which' is the virtual YM3526 number
+** '*buffer' is the output buffer pointer
+** 'length' is the number of samples that should be generated
+*/
+void YM3526UpdateOne(void *chip, OPLSAMPLE *buffer, int length);
+
+void YM3526SetTimerHandler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
+void YM3526SetIRQHandler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
+void YM3526SetUpdateHandler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
+
+#endif
+
+
+#if BUILD_Y8950
+
+/* Y8950 port handlers */
+void Y8950SetPortHandler(void *chip, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, void *param);
+void Y8950SetKeyboardHandler(void *chip, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, void *param);
+void Y8950SetDeltaTMemory(void *chip, void * deltat_mem_ptr, int deltat_mem_size );
+
+void * Y8950Init (int sndindex, UINT32 clock, UINT32 rate);
+void Y8950Shutdown (void *chip);
+void Y8950ResetChip (void *chip);
+int Y8950Write (void *chip, int a, int v);
+unsigned char Y8950Read (void *chip, int a);
+int Y8950TimerOver (void *chip, int c);
+void Y8950UpdateOne (void *chip, OPLSAMPLE *buffer, int length);
+
+void Y8950SetTimerHandler (void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
+void Y8950SetIRQHandler (void *chip, OPL_IRQHANDLER IRQHandler, void *param);
+void Y8950SetUpdateHandler (void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
+
+#endif
+
+
+#endif /* __FMOPL_H_ */
diff --git a/src/emu/sound/gaelco.c b/src/emu/sound/gaelco.c
new file mode 100644
index 00000000000..5077dc52d90
--- /dev/null
+++ b/src/emu/sound/gaelco.c
@@ -0,0 +1,377 @@
+/***************************************************************************
+ Gaelco Sound Hardware
+
+ By Manuel Abadia <manu@teleline.es>
+
+CG-1V/GAE1 (Gaelco custom GFX & Sound chip):
+ The CG-1V/GAE1 can handle up to 7 stereo channels.
+ The chip output is connected to a TDA1543 (16 bit DAC).
+
+Registers per channel:
+======================
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | xxxxxxxx xxxxxxxx | not used?
+ 1 | xxxx---- -------- | left channel volume (0x00..0x0f)
+ 1 | ----xxxx -------- | right channel volume (0x00..0x0f)
+ 1 | -------- xxxx---- | sample type (0x0c = PCM 8 bits mono, 0x08 = PCM 8 bits stereo)
+ 1 | -------- ----xxxx | ROM Bank
+ 2 | xxxxxxxx xxxxxxxx | sample end position
+ 3 | xxxxxxxx xxxxxxxx | remaining bytes to play
+
+ the following are used only when looping (usually used for music)
+
+ 4 | xxxxxxxx xxxxxxxx | not used?
+ 5 | xxxx---- -------- | left channel volume (0x00..0x0f)
+ 5 | ----xxxx -------- | right channel volume (0x00..0x0f)
+ 5 | -------- xxxx---- | sample type (0x0c = PCM 8 bits mono, 0x08 = PCM 8 bits stereo)
+ 5 | -------- ----xxxx | ROM Bank
+ 6 | xxxxxxxx xxxxxxxx | sample end position
+ 7 | xxxxxxxx xxxxxxxx | remaining bytes to play
+
+ The samples are played from (end position + length) to (end position)!
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "gaelco.h"
+#include "wavwrite.h"
+
+
+//#define LOG_SOUND 1
+//#define LOG_READ_WRITES 1
+//#define LOG_WAVE 1
+//#define ALT_MIX
+
+#define GAELCO_NUM_CHANNELS 0x07
+#define VOLUME_LEVELS 0x10
+
+UINT16 *gaelco_sndregs;
+
+/* fix me -- asumes that only one type can be active at a time */
+static sound_type chip_type;
+
+/* this structure defines a channel */
+struct gaelcosnd_channel
+{
+ int active; /* is it playing? */
+ int loop; /* = 0 no looping, = 1 looping */
+ int chunkNum; /* current chunk if looping */
+};
+
+/* this structure defines the Gaelco custom sound chip */
+struct GAELCOSND
+{
+ sound_stream *stream; /* our stream */
+ UINT8 *snd_data; /* PCM data */
+ int banks[4]; /* start of each ROM bank */
+ struct gaelcosnd_channel channel[GAELCO_NUM_CHANNELS]; /* 7 stereo channels */
+
+ /* table for converting from 8 to 16 bits with volume control */
+ INT16 volume_table[VOLUME_LEVELS][256];
+};
+
+#ifdef LOG_WAVE
+void * wavraw; /* raw waveform */
+#endif
+
+/*============================================================================
+ CG-1V/GAE1 Sound Update
+
+ Writes length bytes to the sound buffer
+ ============================================================================*/
+
+static void gaelco_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct GAELCOSND *info = param;
+ int j, ch;
+
+ /* fill all data needed */
+ for(j = 0; j < length; j++){
+ int output_l = 0, output_r = 0;
+
+ /* for each channel */
+ for (ch = 0; ch < GAELCO_NUM_CHANNELS; ch ++){
+ int ch_data_l = 0, ch_data_r = 0;
+ struct gaelcosnd_channel *channel = &info->channel[ch];
+
+ /* if the channel is playing */
+ if (channel->active == 1){
+ int data, chunkNum = 0;
+ int base_offset, type, bank, vol_r, vol_l, end_pos;
+
+ /* if the channel is looping, get current chunk to play */
+ if (channel->loop == 1){
+ chunkNum = channel->chunkNum;
+ }
+
+ base_offset = ch*8 + chunkNum*4;
+
+ /* get channel parameters */
+ type = ((gaelco_sndregs[base_offset + 1] >> 4) & 0x0f);
+ bank = info->banks[((gaelco_sndregs[base_offset + 1] >> 0) & 0x03)];
+ vol_l = ((gaelco_sndregs[base_offset + 1] >> 12) & 0x0f);
+ vol_r = ((gaelco_sndregs[base_offset + 1] >> 8) & 0x0f);
+ end_pos = gaelco_sndregs[base_offset + 2] << 8;
+
+ /* generates output data (range 0x00000..0xffff) */
+ if (type == 0x08){
+ /* PCM, 8 bits mono */
+ data = info->snd_data[bank + end_pos + gaelco_sndregs[base_offset + 3]];
+ ch_data_l = info->volume_table[vol_l][data];
+ ch_data_r = info->volume_table[vol_r][data];
+
+ gaelco_sndregs[base_offset + 3]--;
+ } else if (type == 0x0c){
+ /* PCM, 8 bits stereo */
+ data = info->snd_data[bank + end_pos + gaelco_sndregs[base_offset + 3]];
+ ch_data_l = info->volume_table[vol_l][data];
+
+ gaelco_sndregs[base_offset + 3]--;
+
+ if (gaelco_sndregs[base_offset + 3] > 0){
+ data = info->snd_data[bank + end_pos + gaelco_sndregs[base_offset + 3]];
+ ch_data_r = info->volume_table[vol_r][data];
+
+ gaelco_sndregs[base_offset + 3]--;
+ }
+ } else {
+#ifdef LOG_SOUND
+ logerror("(GAE1) Playing unknown sample format in channel: %02d, type: %02x, bank: %02x, end: %08x, Length: %04x\n", ch, type, bank, end_pos, gaelco_sndregs[base_offset + 3]);
+#endif
+ channel->active = 0;
+ }
+
+ /* check if the current sample has finished playing */
+ if (gaelco_sndregs[base_offset + 3] == 0){
+ if (channel->loop == 0){ /* if no looping, we're done */
+ channel->active = 0;
+ } else { /* if we're looping, swap chunks */
+ channel->chunkNum = (channel->chunkNum + 1) & 0x01;
+
+ /* if the length of the next chunk is 0, we're done */
+ if (gaelco_sndregs[ch*8 + channel->chunkNum*4 + 3] == 0){
+ channel->active = 0;
+ }
+ }
+ }
+ }
+
+ /* add the contribution of this channel to the current data output */
+ output_l += ch_data_l;
+ output_r += ch_data_r;
+ }
+
+#ifndef ALT_MIX
+ /* clip to max or min value */
+ if (output_l > 32767) output_l = 32767;
+ if (output_r > 32767) output_r = 32767;
+ if (output_l < -32768) output_l = -32768;
+ if (output_r < -32768) output_r = -32768;
+#else
+ /* ponderate channels */
+ output_l /= GAELCO_NUM_CHANNELS;
+ output_r /= GAELCO_NUM_CHANNELS;
+#endif
+
+ /* now that we have computed all channels, save current data to the output buffer */
+ buffer[0][j] = output_l;
+ buffer[1][j] = output_r;
+ }
+
+#ifdef LOG_WAVE
+ wav_add_data_16lr(wavraw, buffer[0], buffer[1], length);
+#endif
+}
+
+/*============================================================================
+ CG-1V/GAE1 Read Handler
+ ============================================================================*/
+
+READ16_HANDLER( gaelcosnd_r )
+{
+#ifdef LOG_READ_WRITES
+ logerror("%06x: (GAE1): read from %04x\n", activecpu_get_pc(), offset);
+#endif
+
+ return gaelco_sndregs[offset];
+}
+
+/*============================================================================
+ CG-1V/GAE1 Write Handler
+ ============================================================================*/
+
+WRITE16_HANDLER( gaelcosnd_w )
+{
+ struct GAELCOSND *info = sndti_token(chip_type, 0);
+ struct gaelcosnd_channel *channel = &info->channel[offset >> 3];
+
+#ifdef LOG_READ_WRITES
+ logerror("%06x: (GAE1): write %04x to %04x\n", activecpu_get_pc(), data, offset);
+#endif
+
+ /* first update the stream to this point in time */
+ stream_update(info->stream);
+
+ COMBINE_DATA(&gaelco_sndregs[offset]);
+
+ switch(offset & 0x07){
+ case 0x03:
+ /* trigger sound */
+ if ((gaelco_sndregs[offset - 1] != 0) && (data != 0)){
+ if (!channel->active){
+ channel->active = 1;
+ channel->chunkNum = 0;
+ channel->loop = 0;
+#ifdef LOG_SOUND
+ logerror("(GAE1) Playing sample channel: %02d, type: %02x, bank: %02x, end: %08x, Length: %04x\n", offset >> 3, (gaelco_sndregs[offset - 2] >> 4) & 0x0f, gaelco_sndregs[offset - 2] & 0x03, gaelco_sndregs[offset - 1] << 8, data);
+#endif
+ }
+ } else {
+ channel->active = 0;
+ }
+
+ break;
+
+ case 0x07: /* enable/disable looping */
+ if ((gaelco_sndregs[offset - 1] != 0) && (data != 0)){
+#ifdef LOG_SOUND
+ logerror("(GAE1) Looping in channel: %02d, type: %02x, bank: %02x, end: %08x, Length: %04x\n", offset >> 3, (gaelco_sndregs[offset - 2] >> 4) & 0x0f, gaelco_sndregs[offset - 2] & 0x03, gaelco_sndregs[offset - 1] << 8, data);
+#endif
+ channel->loop = 1;
+ } else {
+ channel->loop = 0;
+ }
+
+ break;
+ }
+}
+
+/*============================================================================
+ CG-1V/GAE1 Init
+ ============================================================================*/
+
+static void *gaelcosnd_start(sound_type sndtype, int sndindex, int clock, const void *config)
+{
+ int j, vol;
+ const struct gaelcosnd_interface *intf = config;
+
+ struct GAELCOSND *info;
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ chip_type = sndtype;
+
+ /* copy rom banks */
+ for (j = 0; j < 4; j++){
+ info->banks[j] = intf->banks[j];
+ }
+ info->stream = stream_create(0, 2, 8000, info, gaelco_update);
+ info->snd_data = (UINT8 *)memory_region(intf->region);
+
+ /* init volume table */
+ for (vol = 0; vol < VOLUME_LEVELS; vol++){
+ for (j = -128; j <= 127; j++){
+ info->volume_table[vol][(j ^ 0x80) & 0xff] = (vol*j*256)/(VOLUME_LEVELS - 1);
+ }
+ }
+
+#ifdef LOG_WAVE
+ wavraw = wav_open("gae1_snd.wav", 8000, 2);
+#endif
+
+ return info;
+}
+
+static void *gaelco_gae1_start(int sndindex, int clock, const void *config)
+{
+ return gaelcosnd_start(SOUND_GAELCO_GAE1, sndindex, clock, config);
+}
+
+static void *gaelco_cg1v_start(int sndindex, int clock, const void *config)
+{
+ return gaelcosnd_start(SOUND_GAELCO_CG1V, sndindex, clock, config);
+}
+
+
+static void gaelco_stop(void *chip)
+{
+#ifdef LOG_WAVE
+ wav_close(wavraw);
+#endif
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void gaelco_gae1_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void gaelco_gae1_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = gaelco_gae1_set_info; break;
+ case SNDINFO_PTR_START: info->start = gaelco_gae1_start; break;
+ case SNDINFO_PTR_STOP: info->stop = gaelco_stop; break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Gaelco GAE1"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Gaelco custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void gaelco_cg1v_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void gaelco_cg1v_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = gaelco_cg1v_set_info; break;
+ case SNDINFO_PTR_START: info->start = gaelco_cg1v_start; break;
+ case SNDINFO_PTR_STOP: info->stop = gaelco_stop; break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Gaelco CG1V"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Gaelco custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/gaelco.h b/src/emu/sound/gaelco.h
new file mode 100644
index 00000000000..04f4e16d405
--- /dev/null
+++ b/src/emu/sound/gaelco.h
@@ -0,0 +1,13 @@
+#ifndef gaelco_snd_h
+#define gaelco_snd_h
+
+struct gaelcosnd_interface
+{
+ int region; /* memory region */
+ int banks[4]; /* start of each ROM bank */
+};
+
+WRITE16_HANDLER( gaelcosnd_w );
+READ16_HANDLER( gaelcosnd_r );
+
+#endif
diff --git a/src/emu/sound/hc55516.c b/src/emu/sound/hc55516.c
new file mode 100644
index 00000000000..c1e609fc201
--- /dev/null
+++ b/src/emu/sound/hc55516.c
@@ -0,0 +1,246 @@
+#include "sndintrf.h"
+#include "streams.h"
+#include "hc55516.h"
+#include <math.h>
+
+
+/* default to 4x oversampling */
+#define DEFAULT_SAMPLE_RATE (48000 * 4)
+
+
+#define INTEGRATOR_LEAK_TC 0.001
+#define FILTER_DECAY_TC 0.004
+#define FILTER_CHARGE_TC 0.004
+#define FILTER_MIN 0.0416
+#define FILTER_MAX 1.0954
+#define SAMPLE_GAIN 10000.0
+
+
+struct hc55516_data
+{
+ sound_stream *channel;
+ int sample_rate;
+
+ UINT8 last_clock;
+ UINT8 databit;
+ UINT8 shiftreg;
+
+ INT16 curr_value;
+ INT16 next_value;
+
+ UINT32 update_count;
+
+ double filter;
+ double integrator;
+};
+
+
+static double charge, decay, leak;
+
+
+static void hc55516_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length);
+
+
+
+static void *hc55516_start(int sndindex, int clock, const void *config)
+{
+ struct hc55516_data *chip;
+
+ /* allocate the chip */
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ /* compute the fixed charge, decay, and leak time constants */
+ charge = pow(exp(-1), 1.0 / (FILTER_CHARGE_TC * 16000.0));
+ decay = pow(exp(-1), 1.0 / (FILTER_DECAY_TC * 16000.0));
+ leak = pow(exp(-1), 1.0 / (INTEGRATOR_LEAK_TC * 16000.0));
+
+ /* create the stream */
+ chip->sample_rate = clock ? clock : DEFAULT_SAMPLE_RATE;
+ chip->channel = stream_create(0, 1, chip->sample_rate, chip, hc55516_update);
+
+ state_save_register_item("hc55516", sndindex, chip->last_clock);
+ state_save_register_item("hc55516", sndindex, chip->databit);
+ state_save_register_item("hc55516", sndindex, chip->shiftreg);
+ state_save_register_item("hc55516", sndindex, chip->curr_value);
+ state_save_register_item("hc55516", sndindex, chip->next_value);
+ state_save_register_item("hc55516", sndindex, chip->update_count);
+ state_save_register_item("hc55516", sndindex, chip->filter);
+ state_save_register_item("hc55516", sndindex, chip->integrator);
+
+ /* success */
+ return chip;
+}
+
+
+static void hc55516_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct hc55516_data *chip = param;
+ stream_sample_t *buffer = _buffer[0];
+ INT32 data, slope;
+ int i;
+
+ /* zero-length? bail */
+ if (length == 0)
+ return;
+
+ /* track how many samples we've updated without a clock */
+ chip->update_count += length;
+ if (chip->update_count > chip->sample_rate / 32)
+ {
+ chip->update_count = chip->sample_rate;
+ chip->next_value = 0;
+ }
+
+ /* compute the interpolation slope */
+ data = chip->curr_value;
+ slope = ((INT32)chip->next_value - data) / length;
+ chip->curr_value = chip->next_value;
+
+ /* reset the sample count */
+ for (i = 0; i < length; i++, data += slope)
+ *buffer++ = data;
+}
+
+
+void hc55516_clock_w(int num, int state)
+{
+ struct hc55516_data *chip = sndti_token(SOUND_HC55516, num);
+ int clock = state & 1, diffclock;
+
+ /* update the clock */
+ diffclock = clock ^ chip->last_clock;
+ chip->last_clock = clock;
+
+ /* speech clock changing (active on rising edge) */
+ if (diffclock && clock)
+ {
+ double integrator = chip->integrator, temp;
+
+ /* clear the update count */
+ chip->update_count = 0;
+
+ /* move the estimator up or down a step based on the bit */
+ if (chip->databit)
+ {
+ chip->shiftreg = ((chip->shiftreg << 1) | 1) & 7;
+ integrator += chip->filter;
+ }
+ else
+ {
+ chip->shiftreg = (chip->shiftreg << 1) & 7;
+ integrator -= chip->filter;
+ }
+
+ /* simulate leakage */
+ integrator *= leak;
+
+ /* if we got all 0's or all 1's in the last n bits, bump the step up */
+ if (chip->shiftreg == 0 || chip->shiftreg == 7)
+ {
+ chip->filter = FILTER_MAX - ((FILTER_MAX - chip->filter) * charge);
+ if (chip->filter > FILTER_MAX)
+ chip->filter = FILTER_MAX;
+ }
+
+ /* simulate decay */
+ else
+ {
+ chip->filter *= decay;
+ if (chip->filter < FILTER_MIN)
+ chip->filter = FILTER_MIN;
+ }
+
+ /* compute the sample as a 32-bit word */
+ temp = integrator * SAMPLE_GAIN;
+ chip->integrator = integrator;
+
+ /* compress the sample range to fit better in a 16-bit word */
+ if (temp < 0)
+ chip->next_value = (int)(temp / (-temp * (1.0 / 32768.0) + 1.0));
+ else
+ chip->next_value = (int)(temp / (temp * (1.0 / 32768.0) + 1.0));
+
+ /* update the output buffer before changing the registers */
+ stream_update(chip->channel);
+ }
+}
+
+
+void hc55516_digit_w(int num, int data)
+{
+ struct hc55516_data *chip = sndti_token(SOUND_HC55516, num);
+ chip->databit = data & 1;
+}
+
+
+void hc55516_clock_clear_w(int num, int data)
+{
+ hc55516_clock_w(num, 0);
+}
+
+
+void hc55516_clock_set_w(int num, int data)
+{
+ hc55516_clock_w(num, 1);
+}
+
+
+void hc55516_digit_clock_clear_w(int num, int data)
+{
+ struct hc55516_data *chip = sndti_token(SOUND_HC55516, num);
+ chip->databit = data & 1;
+ hc55516_clock_w(num, 0);
+}
+
+
+WRITE8_HANDLER( hc55516_0_digit_w ) { hc55516_digit_w(0,data); }
+WRITE8_HANDLER( hc55516_0_clock_w ) { hc55516_clock_w(0,data); }
+WRITE8_HANDLER( hc55516_0_clock_clear_w ) { hc55516_clock_clear_w(0,data); }
+WRITE8_HANDLER( hc55516_0_clock_set_w ) { hc55516_clock_set_w(0,data); }
+WRITE8_HANDLER( hc55516_0_digit_clock_clear_w ) { hc55516_digit_clock_clear_w(0,data); }
+
+WRITE8_HANDLER( hc55516_1_digit_w ) { hc55516_digit_w(1,data); }
+WRITE8_HANDLER( hc55516_1_clock_w ) { hc55516_clock_w(1,data); }
+WRITE8_HANDLER( hc55516_1_clock_clear_w ) { hc55516_clock_clear_w(1,data); }
+WRITE8_HANDLER( hc55516_1_clock_set_w ) { hc55516_clock_set_w(1,data); }
+WRITE8_HANDLER( hc55516_1_digit_clock_clear_w ) { hc55516_digit_clock_clear_w(1,data); }
+
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void hc55516_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void hc55516_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = hc55516_set_info; break;
+ case SNDINFO_PTR_START: info->start = hc55516_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "HC55516"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Gaelco custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/hc55516.h b/src/emu/sound/hc55516.h
new file mode 100644
index 00000000000..e9a719e6b20
--- /dev/null
+++ b/src/emu/sound/hc55516.h
@@ -0,0 +1,31 @@
+#ifndef HC55516_H
+#define HC55516_H
+
+
+/* sets the databit (0 or 1) */
+void hc55516_digit_w(int num, int data);
+
+/* sets the clock state (0 or 1, clocked on the rising edge) */
+void hc55516_clock_w(int num, int state);
+
+/* clears or sets the clock state */
+void hc55516_clock_clear_w(int num, int data);
+void hc55516_clock_set_w(int num, int data);
+
+/* clears the clock state and sets the databit */
+void hc55516_digit_clock_clear_w(int num, int data);
+
+WRITE8_HANDLER( hc55516_0_digit_w );
+WRITE8_HANDLER( hc55516_0_clock_w );
+WRITE8_HANDLER( hc55516_0_clock_clear_w );
+WRITE8_HANDLER( hc55516_0_clock_set_w );
+WRITE8_HANDLER( hc55516_0_digit_clock_clear_w );
+
+WRITE8_HANDLER( hc55516_1_digit_w );
+WRITE8_HANDLER( hc55516_1_clock_w );
+WRITE8_HANDLER( hc55516_1_clock_clear_w );
+WRITE8_HANDLER( hc55516_1_clock_set_w );
+WRITE8_HANDLER( hc55516_1_digit_clock_clear_w );
+
+
+#endif
diff --git a/src/emu/sound/ics2115.c b/src/emu/sound/ics2115.c
new file mode 100644
index 00000000000..d81cb4994b9
--- /dev/null
+++ b/src/emu/sound/ics2115.c
@@ -0,0 +1,578 @@
+/*
+ ICS 2115 sound synthesizer.
+
+ By O. Galibert, with a lot of help from the nebula
+ ics emulation by Elsemi.
+*/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "ics2115.h"
+
+#define ICS2115LOGERROR 0
+
+// a:401ae90.000 l:1c23c.0 e:1e1d8.0 09 tone
+// a:4023c40.000 l:25d60.0 e:266cb.0 08 tone
+// a:4028fc0.000 l:28fc0.0 e:2b6ef.0 01 violon, noisy
+// a:4034020.000 l:34560.0 e:36001.0 19 percussion
+// a:4034218.1e8 l:34560.0 e:36001.0 19 percussion
+// a:4037f10.000 l:37f3e.0 e:39cb7.0 08 tone
+// a:4044f10.000 l:463ea.0 e:46476.0 09 tone
+// a:40490d0.000 l:760e9.0 e:910d8.0 19 percussion moche
+// a:4051bd0.000 l:51bd0.0 e:528df.0 01 percussion
+// a:40621f0.000 l:621f0.0 e:62aef.0 01 percussion faible
+// a:4063430.000 l:63c78.0 e:63d25.0 08 tone
+// a:40668a0.000 l:668a0.0 e:670ec.0 01 percussion
+// a:4067940.000 l:67940.0 e:68140.0 01 percussion
+// a:40aff36.000 l:aff36.0 e:b194d.0 20 Selection menu
+// a:40b5f26.000 l:b5f26.0 e:b63a5.0 20 Move up/down
+// a:4102772.000 l:02772.0 e:03a31.0 20 Voice test (screwed up?)
+
+// conf:
+// 10b6: 00
+// 11ee: 20
+// 1867: a0
+// 188b: 00
+// 20ba: 01 08 09
+// 2299: 01 09 19
+
+enum { V_ON = 1, V_DONE = 2 };
+
+struct ics2115{
+ const struct ics2115_interface *intf;
+ int index;
+ UINT8 *rom;
+ INT16 *ulaw;
+
+ struct {
+ UINT16 fc, addrh, addrl, strth, endh, volacc;
+ UINT8 strtl, endl, saddr, pan, conf, ctl;
+ UINT8 vstart, vend, vctl;
+ UINT8 state;
+ } voice[32];
+
+ struct {
+ UINT8 scale, preset;
+ emu_timer *timer;
+ UINT64 period; /* in nsec */
+ } timer[2];
+
+ UINT8 reg, osc;
+ UINT8 irq_en, irq_pend;
+ int irq_on;
+ sound_stream * stream;
+};
+
+static int caller_get_pc(void)
+{
+ int pc = activecpu_get_pc();
+#if 0
+ if(pc == 0x14b || pc == 0x26e || pc == 0x284 || pc == 0x28d ||
+ pc == 0x290 || pc == 0x299 || pc == 0x2a2 || pc == 0x2b3) {
+ int sp = z80_get_reg(Z80_SP);
+ pc = cpu_readmem16(sp)|(cpu_readmem16((UINT16)(sp+1)) << 8);
+ }
+#endif
+
+ return pc;
+}
+
+static void recalc_irq(struct ics2115 *chip)
+{
+ int i;
+ int irq = 0;
+ if(chip->irq_en & chip->irq_pend)
+ irq = 1;
+ for(i=0; !irq && i<32; i++)
+ if(chip->voice[i].state & V_DONE)
+ irq = 1;
+ if(irq != chip->irq_on) {
+ chip->irq_on = irq;
+ if(chip->intf->irq_cb)
+ chip->intf->irq_cb(irq ? ASSERT_LINE : CLEAR_LINE);
+ }
+}
+
+
+static void update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct ics2115 *chip = param;
+ int osc, i;
+ int rec_irq = 0;
+
+ memset(buffer[0], 0, length*sizeof(*buffer[0]));
+ memset(buffer[1], 0, length*sizeof(*buffer[0]));
+
+ for(osc = 0; osc < 32; osc++)
+ if(chip->voice[osc].state & V_ON) {
+ UINT32 adr = (chip->voice[osc].addrh << 16) | chip->voice[osc].addrl;
+ UINT32 end = (chip->voice[osc].endh << 16) | (chip->voice[osc].endl << 8);
+ UINT32 loop = (chip->voice[osc].strth << 16) | (chip->voice[osc].strtl << 8);
+ UINT32 badr = (chip->voice[osc].saddr << 20) & 0xffffff;
+ UINT32 delta = chip->voice[osc].fc << 2;
+ UINT8 conf = chip->voice[osc].conf;
+ INT32 vol = chip->voice[osc].volacc;
+ vol = (((vol & 0xff0)|0x1000)<<(vol>>12))>>12;
+
+ if (ICS2115LOGERROR) logerror("ICS2115: KEYRUN %02d adr=%08x end=%08x delta=%08x\n",
+ osc, adr, end, delta);
+
+ for(i=0; i<length; i++) {
+ INT32 v = chip->rom[badr|(adr >> 12)];
+ if(conf & 1)
+ v = chip->ulaw[v];
+ else
+ v = ((INT8)v) << 6;
+
+ v = (v*vol)>>(16+5);
+ buffer[0][i] += v;
+ buffer[1][i] += v;
+ adr += delta;
+ if(adr >= end) {
+ if (ICS2115LOGERROR) logerror("ICS2115: KEYDONE %2d\n", osc);
+ adr -= (end-loop);
+ chip->voice[osc].state &= ~V_ON;
+ chip->voice[osc].state |= V_DONE;
+ rec_irq = 1;
+ break;
+ }
+ }
+ chip->voice[osc].addrh = adr >> 16;
+ chip->voice[osc].addrl = adr;
+ }
+ if(rec_irq)
+ recalc_irq(chip);
+}
+
+static void keyon(struct ics2115 *chip, int osc)
+{
+ if (ICS2115LOGERROR) logerror("ICS2115: KEYON %2d conf:%02x vctl:%02x a:%07x.%03x l:%05x.%x e:%05x.%x v:%03x f:%d\n",
+ osc,
+ chip->voice[chip->osc].conf,
+ chip->voice[chip->osc].vctl,
+ (chip->voice[osc].saddr << 20)|(chip->voice[osc].addrh << 4)|(chip->voice[osc].addrl >> 12),
+ (chip->voice[osc].addrl >> 3) & 0x1ff,
+ (chip->voice[osc].strth << 4)|(chip->voice[osc].strtl >> 4),
+ chip->voice[osc].strtl & 0xf,
+ (chip->voice[osc].endh << 4)|(chip->voice[osc].endl >> 4),
+ chip->voice[osc].endl & 0xf,
+ chip->voice[osc].volacc>>4,
+ (chip->voice[chip->osc].fc*33075+512)/1024);
+ chip->voice[osc].state |= V_ON;
+}
+
+
+static TIMER_CALLBACK_PTR( timer_cb_0 )
+{
+ struct ics2115 *chip = param;
+ chip->irq_pend |= 1<<0;
+ recalc_irq(chip);
+}
+
+static TIMER_CALLBACK_PTR( timer_cb_1 )
+{
+ struct ics2115 *chip = param;
+ chip->irq_pend |= 1<<1;
+ recalc_irq(chip);
+}
+
+static void recalc_timer(struct ics2115 *chip, int timer)
+{
+ UINT64 period = 1000000000 * chip->timer[timer].scale*chip->timer[timer].preset / 33868800;
+ if(period)
+ period = 1000000000/62.8206;
+ if(period)
+ {
+ if (ICS2115LOGERROR) logerror("ICS2115: timer %d freq=%fHz\n", timer, 1.0/(period / 1000000000.0));
+ }
+ else
+ {
+ if (ICS2115LOGERROR) logerror("ICS2115: timer %d off\n", timer);
+ }
+
+ if(chip->timer[timer].period != period) {
+ chip->timer[timer].period = period;
+ if(period)
+ timer_adjust_ptr(chip->timer[timer].timer, ATTOTIME_IN_NSEC(period), ATTOTIME_IN_NSEC(period));
+ else
+ timer_adjust_ptr(chip->timer[timer].timer, attotime_never, attotime_zero);
+ }
+}
+
+
+static void ics2115_reg_w(struct ics2115 *chip, UINT8 reg, UINT8 data, int msb)
+{
+ switch(reg) {
+ case 0x00: // [osc] Oscillator Configuration
+ if(msb) {
+ chip->voice[chip->osc].conf = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: conf = %02x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].conf, caller_get_pc());
+ }
+ break;
+
+ case 0x01: // [osc] Wavesample frequency
+ // freq = fc*33075/1024 in 32 voices mode, fc*44100/1024 in 24 voices mode
+ if(msb)
+ chip->voice[chip->osc].fc = (chip->voice[chip->osc].fc & 0xff)|(data << 8);
+ else
+ chip->voice[chip->osc].fc = (chip->voice[chip->osc].fc & 0xff00)|data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: fc = %04x (%dHz) (%04x)\n", chip->osc,
+ chip->voice[chip->osc].fc, chip->voice[chip->osc].fc*33075/1024, caller_get_pc());
+ break;
+
+ case 0x02: // [osc] Wavesample loop start address 19-4
+ if(msb)
+ chip->voice[chip->osc].strth = (chip->voice[chip->osc].strth & 0xff)|(data << 8);
+ else
+ chip->voice[chip->osc].strth = (chip->voice[chip->osc].strth & 0xff00)|data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: strth = %04x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].strth, caller_get_pc());
+ break;
+
+ case 0x03: // [osc] Wavesample loop start address 3-0.3-0
+ if(msb) {
+ chip->voice[chip->osc].strtl = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: strtl = %02x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].strtl, caller_get_pc());
+ }
+ break;
+
+ case 0x04: // [osc] Wavesample loop end address 19-4
+ if(msb)
+ chip->voice[chip->osc].endh = (chip->voice[chip->osc].endh & 0xff)|(data << 8);
+ else
+ chip->voice[chip->osc].endh = (chip->voice[chip->osc].endh & 0xff00)|data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: endh = %04x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].endh, caller_get_pc());
+ break;
+
+ case 0x05: // [osc] Wavesample loop end address 3-0.3-0
+ if(msb) {
+ chip->voice[chip->osc].endl = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: endl = %02x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].endl, caller_get_pc());
+ }
+ break;
+
+ case 0x07: // [osc] Volume Start
+ if(msb) {
+ chip->voice[chip->osc].vstart = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: vstart = %02x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].vstart, caller_get_pc());
+ }
+ break;
+
+ case 0x08: // [osc] Volume End
+ if(msb) {
+ chip->voice[chip->osc].vend = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: vend = %02x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].vend, caller_get_pc());
+ }
+ break;
+
+ case 0x09: // [osc] Volume accumulator
+ if(msb)
+ chip->voice[chip->osc].volacc = (chip->voice[chip->osc].volacc & 0xff)|(data << 8);
+ else
+ chip->voice[chip->osc].volacc = (chip->voice[chip->osc].volacc & 0xff00)|data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: volacc = %04x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].volacc, caller_get_pc());
+ break;
+
+ case 0x0a: // [osc] Wavesample address 19-4
+ if(msb)
+ chip->voice[chip->osc].addrh = (chip->voice[chip->osc].addrh & 0xff)|(data << 8);
+ else
+ chip->voice[chip->osc].addrh = (chip->voice[chip->osc].addrh & 0xff00)|data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: addrh = %04x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].addrh, caller_get_pc());
+ break;
+
+ case 0x0b: // [osc] Wavesample address 3-0.8-0
+ if(msb)
+ chip->voice[chip->osc].addrl = (chip->voice[chip->osc].addrl & 0xff)|(data << 8);
+ else
+ chip->voice[chip->osc].addrl = (chip->voice[chip->osc].addrl & 0xff00)|data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: addrl = %04x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].addrl, caller_get_pc());
+ break;
+
+
+ case 0x0c: // [osc] Pan
+ if(msb) {
+ chip->voice[chip->osc].pan = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: pan = %02x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].pan, caller_get_pc());
+ }
+ break;
+
+ case 0x0d: // [osc] Volume Enveloppe Control
+ if(msb) {
+ chip->voice[chip->osc].vctl = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: vctl = %02x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].vctl, caller_get_pc());
+ }
+ break;
+
+ case 0x10: // [osc] Oscillator Control
+ if(msb) {
+ chip->voice[chip->osc].ctl = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: ctl = %02x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].ctl, caller_get_pc());
+ if(data == 0)
+ keyon(chip, chip->osc);
+ }
+ break;
+
+ case 0x11: // [osc] Wavesample static address 27-20
+ if(msb) {
+ chip->voice[chip->osc].saddr = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: saddr = %02x (%04x)\n", chip->osc,
+ chip->voice[chip->osc].saddr, caller_get_pc());
+ }
+ break;
+
+ case 0x40: // Timer 1 Preset
+ if(!msb) {
+ chip->timer[0].preset = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: t1preset = %d (%04x)\n", chip->timer[0].preset, caller_get_pc());
+ recalc_timer(chip, 0);
+ }
+ break;
+
+ case 0x41: // Timer 2 Preset
+ if(!msb) {
+ chip->timer[1].preset = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: t2preset = %d (%04x)\n", chip->timer[1].preset, caller_get_pc());
+ recalc_timer(chip, 1);
+ }
+ break;
+
+ case 0x42: // Timer 1 Prescaler
+ if(!msb) {
+ chip->timer[0].scale = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: t1scale = %d (%04x)\n", chip->timer[0].scale, caller_get_pc());
+ recalc_timer(chip, 0);
+ }
+ break;
+
+ case 0x43: // Timer 2 Prescaler
+ if(!msb) {
+ chip->timer[1].scale = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: t2scale = %d (%04x)\n", chip->timer[1].scale, caller_get_pc());
+ recalc_timer(chip, 1);
+ }
+ break;
+
+ case 0x4a: // IRQ Enable
+ if(!msb) {
+ chip->irq_en = data;
+ if (ICS2115LOGERROR) logerror("ICS2115: irq_en = %02x (%04x)\n", chip->irq_en, caller_get_pc());
+ recalc_irq(chip);
+ }
+ break;
+
+ case 0x4f: // Oscillator Address being Programmed
+ if(!msb) {
+ chip->osc = data & 31;
+ if (ICS2115LOGERROR) logerror("ICS2115: oscnumber = %d (%04x)\n", chip->osc, caller_get_pc());
+ }
+ break;
+
+ default:
+ if (ICS2115LOGERROR) logerror("ICS2115: write %02x, %02x:%d (%04x)\n", reg, data, msb, caller_get_pc());
+ }
+}
+
+static UINT16 ics2115_reg_r(struct ics2115 *chip, UINT8 reg)
+{
+ switch(reg) {
+ case 0x0d: // [osc] Volume Enveloppe Control
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: read vctl (%04x)\n", chip->osc, caller_get_pc());
+ // res = chip->voice[chip->osc].vctl << 8;
+ // may expect |8 on voice irq with &40 == 0
+ // may expect |8 on reg 0 on voice irq with &80 == 0
+ return 0x100;
+
+ case 0x0f:{// [osc] Interrupt source/oscillator
+ int osc;
+ UINT8 res = 0xff;
+ for(osc = 0; osc < 32; osc++)
+ if(chip->voice[osc].state & V_DONE) {
+ chip->voice[osc].state &= ~V_DONE;
+ if (ICS2115LOGERROR) logerror("ICS2115: KEYOFF %2d\n", osc);
+ recalc_irq(chip);
+ res = 0x40 | osc; // 0x40 ? 0x80 ?
+ break;
+ }
+ if (ICS2115LOGERROR) logerror("ICS2115: read irqv %02x (%04x)\n", res, caller_get_pc());
+ return res << 8;
+ }
+
+ case 0x40: // Timer 0 clear irq
+ // if (ICS2115LOGERROR) logerror("ICS2115: clear timer 0 (%04x)\n", caller_get_pc());
+ chip->irq_pend &= ~(1<<0);
+ recalc_irq(chip);
+ return chip->timer[0].preset;
+
+ case 0x41: // Timer 1 clear irq
+ if (ICS2115LOGERROR) logerror("ICS2115: clear timer 1 (%04x)\n", caller_get_pc());
+ chip->irq_pend &= ~(1<<1);
+ recalc_irq(chip);
+ return chip->timer[1].preset;
+
+ case 0x43: // Timer status
+ // if (ICS2115LOGERROR) logerror("ICS2115: read timer status %02x (%04x)\n", chip->irq_pend & 3, caller_get_pc());
+ return chip->irq_pend & 3;
+
+ case 0x4a: // IRQ Pending
+ if (ICS2115LOGERROR) logerror("ICS2115: read irq_pend %02x (%04x)\n", chip->irq_pend, caller_get_pc());
+ return chip->irq_pend;
+
+ case 0x4b: // Address of Interrupting Oscillator
+ if (ICS2115LOGERROR) logerror("ICS2115: %2d: read intoscaddr (%04x)\n", chip->osc, caller_get_pc());
+ return 0x80;
+
+ case 0x4c: // Chip revision
+ if (ICS2115LOGERROR) logerror("ICS2115: read revision (%04x)\n", caller_get_pc());
+ return 0x01;
+
+ default:
+ if (ICS2115LOGERROR) logerror("ICS2115: read %02x unmapped (%04x)\n", reg, caller_get_pc());
+ return 0;
+ }
+}
+
+
+static void *ics2115_start(int sndindex, int clock, const void *config)
+{
+ struct ics2115 *chip;
+ int i;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ chip->intf = config;
+ chip->index = sndindex;
+ chip->rom = memory_region(chip->intf->region);
+ chip->timer[0].timer = timer_alloc_ptr(timer_cb_0, chip);
+ chip->timer[1].timer = timer_alloc_ptr(timer_cb_1, chip);
+ chip->ulaw = auto_malloc(256*sizeof(INT16));
+ chip->stream = stream_create(0, 2, 33075, chip, update);
+
+ for(i=0; i<256; i++) {
+ UINT8 c = ~i;
+ int v;
+ v = ((c & 15) << 1) + 33;
+ v <<= ((c & 0x70) >> 4);
+ if(c & 0x80)
+ v = 33-v;
+ else
+ v = v-33;
+ chip->ulaw[i] = v;
+ }
+
+ return chip;
+}
+
+READ8_HANDLER( ics2115_r )
+{
+ struct ics2115 *chip = sndti_token(SOUND_ICS2115, 0);
+ switch(offset) {
+ case 0: {
+ UINT8 res = 0;
+ if(chip->irq_on) {
+ int i;
+ res |= 0x80;
+ if(chip->irq_en & chip->irq_pend & 3)
+ res |= 1; // Timer irq
+ for(i=0; i<32; i++)
+ if(chip->voice[i].state & V_DONE) {
+ res |= 2;
+ break;
+ }
+ }
+ // if (ICS2115LOGERROR) logerror("ICS2115: read status %02x (%04x)\n", res, caller_get_pc());
+
+ return res;
+ }
+ case 1:
+ return chip->reg;
+ case 2:
+ return ics2115_reg_r(chip, chip->reg);
+ case 3:
+ default:
+ return ics2115_reg_r(chip, chip->reg) >> 8;
+ }
+}
+
+WRITE8_HANDLER( ics2115_w )
+{
+ struct ics2115 *chip = sndti_token(SOUND_ICS2115, 0);
+ switch(offset) {
+ case 1:
+ chip->reg = data;
+ break;
+ case 2:
+ ics2115_reg_w(chip, chip->reg, data, 0);
+ break;
+ case 3:
+ ics2115_reg_w(chip, chip->reg, data, 1);
+ break;
+ }
+ // if (ICS2115LOGERROR) logerror("ICS2115: wi %d, %02x (%04x)\n", offset, data, caller_get_pc());
+}
+
+void ics2115_reset(void *_chip)
+{
+ struct ics2115 *chip = _chip;
+ chip->irq_en = 0;
+ chip->irq_pend = 0;
+ memset(chip->voice, 0, sizeof(chip->voice));
+ timer_adjust_ptr(chip->timer[0].timer, attotime_never, attotime_zero);
+ timer_adjust_ptr(chip->timer[1].timer, attotime_never, attotime_zero);
+ chip->timer[0].period = 0;
+ chip->timer[1].period = 0;
+ recalc_irq(chip);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ics2115_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ics2115_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ics2115_set_info; break;
+ case SNDINFO_PTR_START: info->start = ics2115_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = ics2115_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "ICS2115"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "ICS"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.01"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004-2007, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/ics2115.h b/src/emu/sound/ics2115.h
new file mode 100644
index 00000000000..e97407e359a
--- /dev/null
+++ b/src/emu/sound/ics2115.h
@@ -0,0 +1,12 @@
+#ifndef __ICS2115_H__
+#define __ICS2115_H__
+
+struct ics2115_interface {
+ int region;
+ void (*irq_cb)(int);
+};
+
+READ8_HANDLER( ics2115_r );
+WRITE8_HANDLER( ics2115_w );
+
+#endif
diff --git a/src/emu/sound/iremga20.c b/src/emu/sound/iremga20.c
new file mode 100644
index 00000000000..981e0668b8f
--- /dev/null
+++ b/src/emu/sound/iremga20.c
@@ -0,0 +1,304 @@
+/*********************************************************
+
+Irem GA20 PCM Sound Chip
+
+It's not currently known whether this chip is stereo.
+
+
+Revisions:
+
+04-15-2002 Acho A. Tang
+- rewrote channel mixing
+- added prelimenary volume and sample rate emulation
+
+05-30-2002 Acho A. Tang
+- applied hyperbolic gain control to volume and used
+ a musical-note style progression in sample rate
+ calculation(still very inaccurate)
+
+02-18-2004 R. Belmont
+- sample rate calculation reverse-engineered.
+ Thanks to Fujix, Yasuhiro Ogawa, the Guru, and Tormod
+ for real PCB samples that made this possible.
+
+02-03-2007 R. Belmont
+- Cleaned up faux x86 assembly.
+
+*********************************************************/
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "iremga20.h"
+
+#define MAX_VOL 256
+
+struct IremGA20_channel_def
+{
+ UINT32 rate;
+ UINT32 size;
+ UINT32 start;
+ UINT32 pos;
+ UINT32 frac;
+ UINT32 end;
+ UINT32 volume;
+ UINT32 pan;
+ UINT32 effect;
+ UINT32 play;
+};
+
+struct IremGA20_chip_def
+{
+ const struct IremGA20_interface *intf;
+ UINT8 *rom;
+ INT32 rom_size;
+ sound_stream * stream;
+ UINT16 regs[0x40];
+ struct IremGA20_channel_def channel[4];
+};
+
+void IremGA20_update( void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length )
+{
+ struct IremGA20_chip_def *chip = param;
+ UINT32 rate[4], pos[4], frac[4], end[4], vol[4], play[4];
+ UINT8 *pSamples;
+ stream_sample_t *outL, *outR;
+ int i, sampleout;
+
+ /* precache some values */
+ for (i=0; i < 4; i++)
+ {
+ rate[i] = chip->channel[i].rate;
+ pos[i] = chip->channel[i].pos;
+ frac[i] = chip->channel[i].frac;
+ end[i] = chip->channel[i].end - 0x20;
+ vol[i] = chip->channel[i].volume;
+ play[i] = chip->channel[i].play;
+ }
+
+ i = length;
+ pSamples = chip->rom;
+ outL = buffer[0];
+ outR = buffer[1];
+
+ for (i = 0; i < length; i++)
+ {
+ sampleout = 0;
+
+ // update the 4 channels inline
+ if (play[0])
+ {
+ sampleout += (pSamples[pos[0]] - 0x80) * vol[0];
+ frac[0] += rate[0];
+ pos[0] += frac[0] >> 24;
+ frac[0] &= 0xffffff;
+ play[0] = (pos[0] < end[0]);
+ }
+ if (play[1])
+ {
+ sampleout += (pSamples[pos[1]] - 0x80) * vol[1];
+ frac[1] += rate[1];
+ pos[1] += frac[1] >> 24;
+ frac[1] &= 0xffffff;
+ play[1] = (pos[1] < end[1]);
+ }
+ if (play[2])
+ {
+ sampleout += (pSamples[pos[2]] - 0x80) * vol[2];
+ frac[2] += rate[2];
+ pos[2] += frac[2] >> 24;
+ frac[2] &= 0xffffff;
+ play[2] = (pos[2] < end[2]);
+ }
+ if (play[3])
+ {
+ sampleout += (pSamples[pos[3]] - 0x80) * vol[3];
+ frac[3] += rate[3];
+ pos[3] += frac[3] >> 24;
+ frac[3] &= 0xffffff;
+ play[3] = (pos[3] < end[3]);
+ }
+
+ sampleout >>= 2;
+ outL[i] = sampleout;
+ outR[i] = sampleout;
+ }
+
+ /* update the regs now */
+ for (i=0; i < 4; i++)
+ {
+ chip->channel[i].pos = pos[i];
+ chip->channel[i].frac = frac[i];
+ chip->channel[i].play = play[i];
+ }
+}
+
+WRITE16_HANDLER( IremGA20_w )
+{
+ struct IremGA20_chip_def *chip = sndti_token(SOUND_IREMGA20, 0);
+ int channel;
+
+ /* only low byte hooked up? */
+ if (!ACCESSING_LSB)
+ return;
+
+ //logerror("GA20: Offset %02x, data %04x\n",offset,data);
+
+ stream_update(chip->stream);
+
+ channel = offset >> 3;
+
+ chip->regs[offset] = data;
+
+ switch (offset & 0x7)
+ {
+ case 0: /* start address low */
+ chip->channel[channel].start = ((chip->channel[channel].start)&0xff000) | (data<<4);
+ break;
+
+ case 1: /* start address high */
+ chip->channel[channel].start = ((chip->channel[channel].start)&0x00ff0) | (data<<12);
+ break;
+
+ case 2: /* end address low */
+ chip->channel[channel].end = ((chip->channel[channel].end)&0xff000) | (data<<4);
+ break;
+
+ case 3: /* end address high */
+ chip->channel[channel].end = ((chip->channel[channel].end)&0x00ff0) | (data<<12);
+ break;
+
+ case 4:
+ chip->channel[channel].rate = 0x1000000 / (256 - data);
+ break;
+
+ case 5: //AT: gain control
+ chip->channel[channel].volume = (data * MAX_VOL) / (data + 10);
+ break;
+
+ case 6: //AT: this is always written 2(enabling both channels?)
+ chip->channel[channel].play = data;
+ chip->channel[channel].pos = chip->channel[channel].start;
+ chip->channel[channel].frac = 0;
+ break;
+ }
+}
+
+READ16_HANDLER( IremGA20_r )
+{
+ struct IremGA20_chip_def *chip = sndti_token(SOUND_IREMGA20, 0);
+ int channel;
+
+ stream_update(chip->stream);
+
+ channel = offset >> 3;
+
+ switch (offset & 0x7)
+ {
+ case 7: // voice status. bit 0 is 1 if active. (routine around 0xccc in rtypeleo)
+ return chip->channel[channel].play ? 1 : 0;
+ break;
+
+ default:
+ logerror("GA20: read unk. register %d, channel %d\n", offset & 0xf, channel);
+ break;
+ }
+
+ return 0;
+}
+
+static void iremga20_reset( void *_chip )
+{
+ struct IremGA20_chip_def *chip = _chip;
+ int i;
+
+ for( i = 0; i < 4; i++ ) {
+ chip->channel[i].rate = 0;
+ chip->channel[i].size = 0;
+ chip->channel[i].start = 0;
+ chip->channel[i].pos = 0;
+ chip->channel[i].frac = 0;
+ chip->channel[i].end = 0;
+ chip->channel[i].volume = 0;
+ chip->channel[i].pan = 0;
+ chip->channel[i].effect = 0;
+ chip->channel[i].play = 0;
+ }
+}
+
+
+static void *iremga20_start(int sndindex, int clock, const void *config)
+{
+ struct IremGA20_chip_def *chip;
+ int i;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ /* Initialize our chip structure */
+ chip->intf = config;
+ chip->rom = memory_region(chip->intf->region);
+ chip->rom_size = memory_region_length(chip->intf->region);
+
+ iremga20_reset(chip);
+
+ for ( i = 0; i < 0x40; i++ )
+ chip->regs[i] = 0;
+
+ chip->stream = stream_create( 0, 2, clock/4, chip, IremGA20_update );
+
+ state_save_register_item_array("irem_ga20", sndindex, chip->regs);
+ for (i = 0; i < 4; i++)
+ {
+ char buf[20];
+ sprintf(buf, "irem_ga20.ch%d", i);
+ state_save_register_item(buf, sndindex, chip->channel[i].rate);
+ state_save_register_item(buf, sndindex, chip->channel[i].size);
+ state_save_register_item(buf, sndindex, chip->channel[i].start);
+ state_save_register_item(buf, sndindex, chip->channel[i].pos);
+ state_save_register_item(buf, sndindex, chip->channel[i].end);
+ state_save_register_item(buf, sndindex, chip->channel[i].volume);
+ state_save_register_item(buf, sndindex, chip->channel[i].pan);
+ state_save_register_item(buf, sndindex, chip->channel[i].effect);
+ state_save_register_item(buf, sndindex, chip->channel[i].play);
+ }
+
+ return chip;
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void iremga20_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void iremga20_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = iremga20_set_info; break;
+ case SNDINFO_PTR_START: info->start = iremga20_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = iremga20_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Irem GA20"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Irem custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/iremga20.h b/src/emu/sound/iremga20.h
new file mode 100644
index 00000000000..015c7b86704
--- /dev/null
+++ b/src/emu/sound/iremga20.h
@@ -0,0 +1,16 @@
+/*********************************************************
+
+ Irem GA20 PCM Sound Chip
+
+*********************************************************/
+#ifndef __IREMGA20_H__
+#define __IREMGA20_H__
+
+struct IremGA20_interface {
+ int region; /* memory region of sample ROM(s) */
+};
+
+WRITE16_HANDLER( IremGA20_w );
+READ16_HANDLER( IremGA20_r );
+
+#endif /* __IREMGA20_H__ */
diff --git a/src/emu/sound/k005289.c b/src/emu/sound/k005289.c
new file mode 100644
index 00000000000..9424e985599
--- /dev/null
+++ b/src/emu/sound/k005289.c
@@ -0,0 +1,285 @@
+/***************************************************************************
+
+ Konami 005289 - SCC sound as used in Bubblesystem
+
+ This file is pieced together by Bryan McPhail from a combination of
+ Namco Sound, Amuse by Cab, Nemesis schematics and whoever first
+ figured out SCC!
+
+ The 005289 is a 2 channel sound generator, each channel gets it's
+ waveform from a prom (4 bits wide).
+
+ (From Nemesis schematics)
+
+ Address lines A0-A4 of the prom run to the 005289, giving 32 bytes
+ per waveform. Address lines A5-A7 of the prom run to PA5-PA7 of
+ the AY8910 control port A, giving 8 different waveforms. PA0-PA3
+ of the AY8910 control volume.
+
+ The second channel is the same as above except port B is used.
+
+ The 005289 has no data bus, so data values written don't matter.
+
+ There are 4 unknown pins, LD1, LD2, TG1, TG2. Two of them look to be
+ the selector for changing frequency. The other two seem unused.
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "k005289.h"
+
+#define FREQBASEBITS 16
+
+/* this structure defines the parameters for a channel */
+typedef struct
+{
+ int frequency;
+ int counter;
+ int volume;
+ const unsigned char *wave;
+} k005289_sound_channel;
+
+struct k005289_info
+{
+ k005289_sound_channel channel_list[2];
+
+ /* global sound parameters */
+ const unsigned char *sound_prom;
+ sound_stream * stream;
+ int mclock,rate;
+
+ /* mixer tables and internal buffers */
+ INT16 *mixer_table;
+ INT16 *mixer_lookup;
+ short *mixer_buffer;
+
+ int k005289_A_frequency,k005289_B_frequency;
+ int k005289_A_volume,k005289_B_volume;
+ int k005289_A_waveform,k005289_B_waveform;
+ int k005289_A_latch,k005289_B_latch;
+};
+
+/* build a table to divide by the number of voices */
+static int make_mixer_table(struct k005289_info *info, int voices)
+{
+ int count = voices * 128;
+ int i;
+ int gain = 16;
+
+ /* allocate memory */
+ info->mixer_table = auto_malloc(256 * voices * sizeof(INT16));
+
+ /* find the middle of the table */
+ info->mixer_lookup = info->mixer_table + (128 * voices);
+
+ /* fill in the table - 16 bit case */
+ for (i = 0; i < count; i++)
+ {
+ int val = i * gain * 16 / voices;
+ if (val > 32767) val = 32767;
+ info->mixer_lookup[ i] = val;
+ info->mixer_lookup[-i] = -val;
+ }
+
+ return 0;
+}
+
+
+/* generate sound to the mix buffer */
+static void K005289_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct k005289_info *info = param;
+ k005289_sound_channel *voice=info->channel_list;
+ stream_sample_t *buffer = _buffer[0];
+ short *mix;
+ int i,v,f;
+
+ /* zap the contents of the mixer buffer */
+ memset(info->mixer_buffer, 0, length * sizeof(INT16));
+
+ v=voice[0].volume;
+ f=voice[0].frequency;
+ if (v && f)
+ {
+ const unsigned char *w = voice[0].wave;
+ int c = voice[0].counter;
+
+ mix = info->mixer_buffer;
+
+ /* add our contribution */
+ for (i = 0; i < length; i++)
+ {
+ int offs;
+
+ c+=(long)((((float)info->mclock / (float)(f * 16))*(float)(1<<FREQBASEBITS)) / (float)(info->rate / 32));
+ offs = (c >> 16) & 0x1f;
+ *mix++ += ((w[offs] & 0x0f) - 8) * v;
+ }
+
+ /* update the counter for this voice */
+ voice[0].counter = c;
+ }
+
+ v=voice[1].volume;
+ f=voice[1].frequency;
+ if (v && f)
+ {
+ const unsigned char *w = voice[1].wave;
+ int c = voice[1].counter;
+
+ mix = info->mixer_buffer;
+
+ /* add our contribution */
+ for (i = 0; i < length; i++)
+ {
+ int offs;
+
+ c+=(long)((((float)info->mclock / (float)(f * 16))*(float)(1<<FREQBASEBITS)) / (float)(info->rate / 32));
+ offs = (c >> 16) & 0x1f;
+ *mix++ += ((w[offs] & 0x0f) - 8) * v;
+ }
+
+ /* update the counter for this voice */
+ voice[1].counter = c;
+ }
+
+ /* mix it down */
+ mix = info->mixer_buffer;
+ for (i = 0; i < length; i++)
+ *buffer++ = info->mixer_lookup[*mix++];
+}
+
+static void *k005289_start(int sndindex, int clock, const void *config)
+{
+ k005289_sound_channel *voice;
+ const struct k005289_interface *intf = config;
+ struct k005289_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+ voice = info->channel_list;
+
+ /* get stream channels */
+ info->rate = clock/16;
+ info->stream = stream_create(0, 1, info->rate, info, K005289_update);
+ info->mclock = clock;
+
+ /* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */
+ info->mixer_buffer = auto_malloc(2 * sizeof(short) * info->rate);
+
+ /* build the mixer table */
+ if (make_mixer_table(info, 2))
+ return NULL;
+
+ info->sound_prom = memory_region(intf->region);
+
+ /* reset all the voices */
+ voice[0].frequency = 0;
+ voice[0].volume = 0;
+ voice[0].wave = &info->sound_prom[0];
+ voice[0].counter = 0;
+ voice[1].frequency = 0;
+ voice[1].volume = 0;
+ voice[1].wave = &info->sound_prom[0x100];
+ voice[1].counter = 0;
+
+ return info;
+}
+
+
+/********************************************************************************/
+
+static void k005289_recompute(struct k005289_info *info)
+{
+ k005289_sound_channel *voice = info->channel_list;
+
+ stream_update(info->stream); /* update the streams */
+
+ voice[0].frequency = info->k005289_A_frequency;
+ voice[1].frequency = info->k005289_B_frequency;
+ voice[0].volume = info->k005289_A_volume;
+ voice[1].volume = info->k005289_B_volume;
+ voice[0].wave = &info->sound_prom[32 * info->k005289_A_waveform];
+ voice[1].wave = &info->sound_prom[32 * info->k005289_B_waveform + 0x100];
+}
+
+WRITE8_HANDLER( k005289_control_A_w )
+{
+ struct k005289_info *info = sndti_token(SOUND_K005289, 0);
+ info->k005289_A_volume=data&0xf;
+ info->k005289_A_waveform=data>>5;
+ k005289_recompute(info);
+}
+
+WRITE8_HANDLER( k005289_control_B_w )
+{
+ struct k005289_info *info = sndti_token(SOUND_K005289, 0);
+ info->k005289_B_volume=data&0xf;
+ info->k005289_B_waveform=data>>5;
+ k005289_recompute(info);
+}
+
+WRITE8_HANDLER( k005289_pitch_A_w )
+{
+ struct k005289_info *info = sndti_token(SOUND_K005289, 0);
+ info->k005289_A_latch = 0x1000 - offset;
+}
+
+WRITE8_HANDLER( k005289_pitch_B_w )
+{
+ struct k005289_info *info = sndti_token(SOUND_K005289, 0);
+ info->k005289_B_latch = 0x1000 - offset;
+}
+
+WRITE8_HANDLER( k005289_keylatch_A_w )
+{
+ struct k005289_info *info = sndti_token(SOUND_K005289, 0);
+ info->k005289_A_frequency = info->k005289_A_latch;
+ k005289_recompute(info);
+}
+
+WRITE8_HANDLER( k005289_keylatch_B_w )
+{
+ struct k005289_info *info = sndti_token(SOUND_K005289, 0);
+ info->k005289_B_frequency = info->k005289_B_latch;
+ k005289_recompute(info);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void k005289_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void k005289_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = k005289_set_info; break;
+ case SNDINFO_PTR_START: info->start = k005289_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "K005289"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Konami custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/k005289.h b/src/emu/sound/k005289.h
new file mode 100644
index 00000000000..71563b4e463
--- /dev/null
+++ b/src/emu/sound/k005289.h
@@ -0,0 +1,16 @@
+#ifndef k005289_h
+#define k005289_h
+
+struct k005289_interface
+{
+ int region; /* memory region */
+};
+
+WRITE8_HANDLER( k005289_control_A_w );
+WRITE8_HANDLER( k005289_control_B_w );
+WRITE8_HANDLER( k005289_pitch_A_w );
+WRITE8_HANDLER( k005289_pitch_B_w );
+WRITE8_HANDLER( k005289_keylatch_A_w );
+WRITE8_HANDLER( k005289_keylatch_B_w );
+
+#endif
diff --git a/src/emu/sound/k007232.c b/src/emu/sound/k007232.c
new file mode 100644
index 00000000000..53c33c346e7
--- /dev/null
+++ b/src/emu/sound/k007232.c
@@ -0,0 +1,509 @@
+/*********************************************************/
+/* Konami PCM controller */
+/*********************************************************/
+
+/*
+ Changelog, Hiromitsu Shioya 02/05/2002
+ fix start address decode timing. (sample loop bug.)
+
+ Changelog, Mish, August 1999:
+ Removed interface support for different memory regions per channel.
+ Removed interface support for differing channel volume.
+
+ Added bankswitching.
+ Added support for multiple chips.
+
+ (Nb: Should different memory regions per channel be needed
+ the bankswitching function can set this up).
+
+NS990821
+support for the K007232_VOL() macro.
+added external port callback, and functions to set the volume of the channels
+
+*/
+
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "k007232.h"
+#include <math.h>
+
+
+#define KDAC_A_PCM_MAX (2) /* Channels per chip */
+
+
+typedef struct kdacApcm
+{
+ UINT8 vol[KDAC_A_PCM_MAX][2]; /* volume for the left and right channel */
+ UINT32 addr[KDAC_A_PCM_MAX];
+ UINT32 start[KDAC_A_PCM_MAX];
+ UINT32 step[KDAC_A_PCM_MAX];
+ UINT32 bank[KDAC_A_PCM_MAX];
+ int play[KDAC_A_PCM_MAX];
+
+ UINT8 wreg[0x10]; /* write data */
+ UINT8 * pcmbuf[2]; /* Channel A & B pointers */
+
+ UINT32 clock; /* chip clock */
+ UINT32 pcmlimit;
+
+ sound_stream * stream;
+ const struct K007232_interface *intf;
+ UINT32 fncode[0x200];
+} KDAC_A_PCM;
+
+
+#define BASE_SHIFT (12)
+
+
+
+#if 0
+static int kdac_note[] = {
+ 261.63/8, 277.18/8,
+ 293.67/8, 311.13/8,
+ 329.63/8,
+ 349.23/8, 369.99/8,
+ 392.00/8, 415.31/8,
+ 440.00/8, 466.16/8,
+ 493.88/8,
+
+ 523.25/8,
+};
+
+static float kdaca_fn[][2] = {
+ /* B */
+ { 0x03f, 493.88/8 }, /* ?? */
+ { 0x11f, 493.88/4 }, /* ?? */
+ { 0x18f, 493.88/2 }, /* ?? */
+ { 0x1c7, 493.88 },
+ { 0x1e3, 493.88*2 },
+ { 0x1f1, 493.88*4 }, /* ?? */
+ { 0x1f8, 493.88*8 }, /* ?? */
+ /* A+ */
+ { 0x020, 466.16/8 }, /* ?? */
+ { 0x110, 466.16/4 }, /* ?? */
+ { 0x188, 466.16/2 },
+ { 0x1c4, 466.16 },
+ { 0x1e2, 466.16*2 },
+ { 0x1f1, 466.16*4 }, /* ?? */
+ { 0x1f8, 466.16*8 }, /* ?? */
+ /* A */
+ { 0x000, 440.00/8 }, /* ?? */
+ { 0x100, 440.00/4 }, /* ?? */
+ { 0x180, 440.00/2 },
+ { 0x1c0, 440.00 },
+ { 0x1e0, 440.00*2 },
+ { 0x1f0, 440.00*4 }, /* ?? */
+ { 0x1f8, 440.00*8 }, /* ?? */
+ { 0x1fc, 440.00*16}, /* ?? */
+ { 0x1fe, 440.00*32}, /* ?? */
+ { 0x1ff, 440.00*64}, /* ?? */
+ /* G+ */
+ { 0x0f2, 415.31/4 },
+ { 0x179, 415.31/2 },
+ { 0x1bc, 415.31 },
+ { 0x1de, 415.31*2 },
+ { 0x1ef, 415.31*4 }, /* ?? */
+ { 0x1f7, 415.31*8 }, /* ?? */
+ /* G */
+ { 0x0e2, 392.00/4 },
+ { 0x171, 392.00/2 },
+ { 0x1b8, 392.00 },
+ { 0x1dc, 392.00*2 },
+ { 0x1ee, 392.00*4 }, /* ?? */
+ { 0x1f7, 392.00*8 }, /* ?? */
+ /* F+ */
+ { 0x0d0, 369.99/4 }, /* ?? */
+ { 0x168, 369.99/2 },
+ { 0x1b4, 369.99 },
+ { 0x1da, 369.99*2 },
+ { 0x1ed, 369.99*4 }, /* ?? */
+ { 0x1f6, 369.99*8 }, /* ?? */
+ /* F */
+ { 0x0bf, 349.23/4 }, /* ?? */
+ { 0x15f, 349.23/2 },
+ { 0x1af, 349.23 },
+ { 0x1d7, 349.23*2 },
+ { 0x1eb, 349.23*4 }, /* ?? */
+ { 0x1f5, 349.23*8 }, /* ?? */
+ /* E */
+ { 0x0ac, 329.63/4 },
+ { 0x155, 329.63/2 }, /* ?? */
+ { 0x1ab, 329.63 },
+ { 0x1d5, 329.63*2 },
+ { 0x1ea, 329.63*4 }, /* ?? */
+ { 0x1f4, 329.63*8 }, /* ?? */
+ /* D+ */
+ { 0x098, 311.13/4 }, /* ?? */
+ { 0x14c, 311.13/2 },
+ { 0x1a6, 311.13 },
+ { 0x1d3, 311.13*2 },
+ { 0x1e9, 311.13*4 }, /* ?? */
+ { 0x1f4, 311.13*8 }, /* ?? */
+ /* D */
+ { 0x080, 293.67/4 }, /* ?? */
+ { 0x140, 293.67/2 }, /* ?? */
+ { 0x1a0, 293.67 },
+ { 0x1d0, 293.67*2 },
+ { 0x1e8, 293.67*4 }, /* ?? */
+ { 0x1f4, 293.67*8 }, /* ?? */
+ { 0x1fa, 293.67*16}, /* ?? */
+ { 0x1fd, 293.67*32}, /* ?? */
+ /* C+ */
+ { 0x06d, 277.18/4 }, /* ?? */
+ { 0x135, 277.18/2 }, /* ?? */
+ { 0x19b, 277.18 },
+ { 0x1cd, 277.18*2 },
+ { 0x1e6, 277.18*4 }, /* ?? */
+ { 0x1f2, 277.18*8 }, /* ?? */
+ /* C */
+ { 0x054, 261.63/4 },
+ { 0x12a, 261.63/2 },
+ { 0x195, 261.63 },
+ { 0x1ca, 261.63*2 },
+ { 0x1e5, 261.63*4 },
+ { 0x1f2, 261.63*8 }, /* ?? */
+
+ { -1, -1 },
+};
+#endif
+
+/*************************************************************/
+static void KDAC_A_make_fncode( struct kdacApcm *info ){
+ int i;
+#if 0
+ int i, j, k;
+ float fn;
+ for( i = 0; i < 0x200; i++ ) fncode[i] = 0;
+
+ i = 0;
+ while( (int)kdaca_fn[i][0] != -1 ){
+ fncode[(int)kdaca_fn[i][0]] = kdaca_fn[i][1];
+ i++;
+ }
+
+ i = j = 0;
+ while( i < 0x200 ){
+ if( fncode[i] != 0 ){
+ if( i != j ){
+ fn = (fncode[i] - fncode[j]) / (i - j);
+ for( k = 1; k < (i-j); k++ )
+ fncode[k+j] = fncode[j] + fn*k;
+ j = i;
+ }
+ }
+ i++;
+ }
+#if 0
+ for( i = 0; i < 0x200; i++ )
+ logerror("fncode[%04x] = %.2f\n", i, fncode[i] );
+#endif
+
+#else
+ for( i = 0; i < 0x200; i++ ){
+ //fncode[i] = (0x200 * 55) / (0x200 - i);
+ info->fncode[i] = (32 << BASE_SHIFT) / (0x200 - i);
+// info->fncode[i] = ((0x200 * 55.2 / 880) / (0x200 - i));
+ // = 512 * 55.2 / 220 / (512 - i) = 128 / (512 - i)
+ // logerror("2 : fncode[%04x] = %.2f\n", i, fncode[i] );
+ }
+
+#endif
+}
+
+
+/************************************************/
+/* Konami PCM update */
+/************************************************/
+
+static void KDAC_A_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int buffer_len)
+{
+ struct kdacApcm *info = param;
+ int i;
+
+ memset(buffer[0],0,buffer_len * sizeof(*buffer[0]));
+ memset(buffer[1],0,buffer_len * sizeof(*buffer[1]));
+
+ for( i = 0; i < KDAC_A_PCM_MAX; i++ )
+ {
+ if (info->play[i])
+ {
+ int volA,volB,j,out;
+ unsigned int addr, old_addr;
+ //int cen;
+
+ /**** PCM setup ****/
+ addr = info->start[i] + ((info->addr[i]>>BASE_SHIFT)&0x000fffff);
+ volA = info->vol[i][0] * 2;
+ volB = info->vol[i][1] * 2;
+#if 0
+ cen = (volA + volB) / 2;
+ volA = (volA + cen) < 0x1fe ? (volA + cen) : 0x1fe;
+ volB = (volB + cen) < 0x1fe ? (volB + cen) : 0x1fe;
+#endif
+
+ for( j = 0; j < buffer_len; j++ )
+ {
+ old_addr = addr;
+ addr = info->start[i] + ((info->addr[i]>>BASE_SHIFT)&0x000fffff);
+ while (old_addr <= addr)
+ {
+ if( (info->pcmbuf[i][old_addr] & 0x80) || old_addr >= info->pcmlimit )
+ {
+ /* end of sample */
+
+ if( info->wreg[0x0d]&(1<<i) )
+ {
+ /* loop to the beginning */
+ info->start[i] =
+ ((((unsigned int)info->wreg[i*0x06 + 0x04]<<16)&0x00010000) |
+ (((unsigned int)info->wreg[i*0x06 + 0x03]<< 8)&0x0000ff00) |
+ (((unsigned int)info->wreg[i*0x06 + 0x02] )&0x000000ff) |
+ info->bank[i]);
+ addr = info->start[i];
+ info->addr[i] = 0;
+ old_addr = addr; /* skip loop */
+ }
+ else
+ {
+ /* stop sample */
+ info->play[i] = 0;
+ }
+ break;
+ }
+
+ old_addr++;
+ }
+
+ if (info->play[i] == 0)
+ break;
+
+ info->addr[i] += info->step[i];
+
+ out = (info->pcmbuf[i][addr] & 0x7f) - 0x40;
+
+ buffer[0][j] += out * volA;
+ buffer[1][j] += out * volB;
+ }
+ }
+ }
+}
+
+
+/************************************************/
+/* Konami PCM start */
+/************************************************/
+static void *k007232_start(int sndindex, int clock, const void *config)
+{
+ int i;
+ struct kdacApcm *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = config;
+
+ /* Set up the chips */
+
+ info->pcmbuf[0] = (unsigned char *)memory_region(info->intf->bank);
+ info->pcmbuf[1] = (unsigned char *)memory_region(info->intf->bank);
+ info->pcmlimit = (unsigned int)memory_region_length(info->intf->bank);
+
+ info->clock = clock;
+
+ for( i = 0; i < KDAC_A_PCM_MAX; i++ )
+ {
+ info->start[i] = 0;
+ info->step[i] = 0;
+ info->play[i] = 0;
+ info->bank[i] = 0;
+ }
+ info->vol[0][0] = 255; /* channel A output to output A */
+ info->vol[0][1] = 0;
+ info->vol[1][0] = 0;
+ info->vol[1][1] = 255; /* channel B output to output B */
+
+ for( i = 0; i < 0x10; i++ ) info->wreg[i] = 0;
+
+ info->stream = stream_create(0,2,clock/128,info,KDAC_A_update);
+
+ KDAC_A_make_fncode(info);
+
+ return info;
+}
+
+/************************************************/
+/* Konami PCM write register */
+/************************************************/
+static void K007232_WriteReg( int r, int v, int chip )
+{
+ struct kdacApcm *info = sndti_token(SOUND_K007232, chip);
+ int data;
+
+ stream_update(info->stream);
+
+ info->wreg[r] = v; /* stock write data */
+
+ if (r == 0x0c){
+ /* external port, usually volume control */
+ if (info->intf->portwritehandler) (*info->intf->portwritehandler)(v);
+ return;
+ }
+ else if( r == 0x0d ){
+ /* loopflag. */
+ return;
+ }
+ else{
+ int reg_port;
+
+ reg_port = 0;
+ if (r >= 0x06){
+ reg_port = 1;
+ r -= 0x06;
+ }
+
+ switch (r){
+ case 0x00:
+ case 0x01:
+ /**** address step ****/
+ data = (((((unsigned int)info->wreg[reg_port*0x06 + 0x01])<<8)&0x0100) | (((unsigned int)info->wreg[reg_port*0x06 + 0x00])&0x00ff));
+#if 0
+ if( !reg_port && r == 1 )
+ logerror("%04x\n" ,data );
+#endif
+
+ info->step[reg_port] = info->fncode[data];
+ break;
+
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ break;
+ case 0x05:
+ /**** start address ****/
+ info->start[reg_port] =
+ ((((unsigned int)info->wreg[reg_port*0x06 + 0x04]<<16)&0x00010000) |
+ (((unsigned int)info->wreg[reg_port*0x06 + 0x03]<< 8)&0x0000ff00) |
+ (((unsigned int)info->wreg[reg_port*0x06 + 0x02] )&0x000000ff) |
+ info->bank[reg_port]);
+ if (info->start[reg_port] < info->pcmlimit ){
+ info->play[reg_port] = 1;
+ info->addr[reg_port] = 0;
+ }
+ break;
+ }
+ }
+}
+
+/************************************************/
+/* Konami PCM read register */
+/************************************************/
+static int K007232_ReadReg( int r, int chip )
+{
+ struct kdacApcm *info = sndti_token(SOUND_K007232, chip);
+ int ch = 0;
+
+ if( r == 0x0005 || r == 0x000b ){
+ ch = r/0x0006;
+ r = ch * 0x0006;
+
+ info->start[ch] =
+ ((((unsigned int)info->wreg[r + 0x04]<<16)&0x00010000) |
+ (((unsigned int)info->wreg[r + 0x03]<< 8)&0x0000ff00) |
+ (((unsigned int)info->wreg[r + 0x02] )&0x000000ff) |
+ info->bank[ch]);
+
+ if (info->start[ch] < info->pcmlimit ){
+ info->play[ch] = 1;
+ info->addr[ch] = 0;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+
+WRITE8_HANDLER( K007232_write_port_0_w )
+{
+ K007232_WriteReg(offset,data,0);
+}
+
+READ8_HANDLER( K007232_read_port_0_r )
+{
+ return K007232_ReadReg(offset,0);
+}
+
+WRITE8_HANDLER( K007232_write_port_1_w )
+{
+ K007232_WriteReg(offset,data,1);
+}
+
+READ8_HANDLER( K007232_read_port_1_r )
+{
+ return K007232_ReadReg(offset,1);
+}
+
+WRITE8_HANDLER( K007232_write_port_2_w )
+{
+ K007232_WriteReg(offset,data,2);
+}
+
+READ8_HANDLER( K007232_read_port_2_r )
+{
+ return K007232_ReadReg(offset,2);
+}
+
+void K007232_set_volume(int chip,int channel,int volumeA,int volumeB)
+{
+ struct kdacApcm *info = sndti_token(SOUND_K007232, chip);
+ info->vol[channel][0] = volumeA;
+ info->vol[channel][1] = volumeB;
+}
+
+void K007232_set_bank( int chip, int chABank, int chBBank )
+{
+ struct kdacApcm *info = sndti_token(SOUND_K007232, chip);
+ info->bank[0] = chABank<<17;
+ info->bank[1] = chBBank<<17;
+}
+
+/*****************************************************************************/
+
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void k007232_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void k007232_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = k007232_set_info; break;
+ case SNDINFO_PTR_START: info->start = k007232_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "K007232"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Konami custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/k007232.h b/src/emu/sound/k007232.h
new file mode 100644
index 00000000000..f1736e96a9c
--- /dev/null
+++ b/src/emu/sound/k007232.h
@@ -0,0 +1,32 @@
+/*********************************************************/
+/* Konami PCM controller */
+/*********************************************************/
+#ifndef __KDAC_A_H__
+#define __KDAC_A_H__
+
+struct K007232_interface
+{
+ int bank; /* memory regions */
+ void (*portwritehandler)(int);
+};
+
+WRITE8_HANDLER( K007232_write_port_0_w );
+WRITE8_HANDLER( K007232_write_port_1_w );
+WRITE8_HANDLER( K007232_write_port_2_w );
+READ8_HANDLER( K007232_read_port_0_r );
+READ8_HANDLER( K007232_read_port_1_r );
+READ8_HANDLER( K007232_read_port_2_r );
+
+void K007232_set_bank( int chip, int chABank, int chBBank );
+
+/*
+ The 007232 has two channels and produces two outputs. The volume control
+ is external, however to make it easier to use we handle that inside the
+ emulation. You can control volume and panning: for each of the two channels
+ you can set the volume of the two outputs. If panning is not required,
+ then volumeB will be 0 for channel 0, and volumeA will be 0 for channel 1.
+ Volume is in the range 0-255.
+*/
+void K007232_set_volume(int chip,int channel,int volumeA,int volumeB);
+
+#endif
diff --git a/src/emu/sound/k051649.c b/src/emu/sound/k051649.c
new file mode 100644
index 00000000000..8a66c55e594
--- /dev/null
+++ b/src/emu/sound/k051649.c
@@ -0,0 +1,255 @@
+/***************************************************************************
+
+ Konami 051649 - SCC1 sound as used in Haunted Castle, City Bomber
+
+ This file is pieced together by Bryan McPhail from a combination of
+ Namco Sound, Amuse by Cab, Haunted Castle schematics and whoever first
+ figured out SCC!
+
+ The 051649 is a 5 channel sound generator, each channel gets it's
+ waveform from RAM (32 bytes per waveform, 8 bit signed data).
+
+ This sound chip is the same as the sound chip in some Konami
+ megaROM cartridges for the MSX. It is actually well researched
+ and documented:
+
+ http://www.msxnet.org/tech/scc
+
+ Thanks to Sean Young (sean@mess.org) for some bugfixes.
+
+ K052539 is equivalent to this chip except channel 5 does not share
+ waveforms with channel 4.
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "k051649.h"
+
+#define FREQBASEBITS 16
+
+/* this structure defines the parameters for a channel */
+typedef struct
+{
+ unsigned long counter;
+ int frequency;
+ int volume;
+ int key;
+ signed char waveform[32]; /* 19991207.CAB */
+} k051649_sound_channel;
+
+struct k051649_info
+{
+ k051649_sound_channel channel_list[5];
+
+ /* global sound parameters */
+ sound_stream * stream;
+ int mclock,rate;
+
+ /* mixer tables and internal buffers */
+ INT16 *mixer_table;
+ INT16 *mixer_lookup;
+ short *mixer_buffer;
+
+ int f[10];
+};
+
+/* build a table to divide by the number of voices */
+static int make_mixer_table(struct k051649_info *info, int voices)
+{
+ int count = voices * 256;
+ int i;
+ int gain = 8;
+
+ /* allocate memory */
+ info->mixer_table = auto_malloc(512 * voices * sizeof(INT16));
+
+ /* find the middle of the table */
+ info->mixer_lookup = info->mixer_table + (256 * voices);
+
+ /* fill in the table - 16 bit case */
+ for (i = 0; i < count; i++)
+ {
+ int val = i * gain * 16 / voices;
+ if (val > 32767) val = 32767;
+ info->mixer_lookup[ i] = val;
+ info->mixer_lookup[-i] = -val;
+ }
+
+ return 0;
+}
+
+
+/* generate sound to the mix buffer */
+static void K051649_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct k051649_info *info = param;
+ k051649_sound_channel *voice=info->channel_list;
+ stream_sample_t *buffer = _buffer[0];
+ short *mix;
+ int i,v,f,j,k;
+
+ /* zap the contents of the mixer buffer */
+ memset(info->mixer_buffer, 0, length * sizeof(short));
+
+ for (j=0; j<5; j++) {
+ v=voice[j].volume;
+ f=voice[j].frequency;
+ k=voice[j].key;
+ /* SY 20040109: the SCC produces no sound for freq < 9 */
+ if (v && f > 8 && k)
+ {
+ const signed char *w = voice[j].waveform; /* 19991207.CAB */
+ int c=voice[j].counter;
+
+ mix = info->mixer_buffer;
+
+ /* add our contribution */
+ for (i = 0; i < length; i++)
+ {
+ int offs;
+
+ /* Amuse source: Cab suggests this method gives greater resolution */
+ /* Sean Young 20010417: the formula is really: f = clock/(16*(f+1))*/
+ c+=(long)((((float)info->mclock / (float)((f+1) * 16))*(float)(1<<FREQBASEBITS)) / (float)(info->rate / 32));
+ offs = (c >> 16) & 0x1f;
+ *mix++ += (w[offs] * v)>>3;
+ }
+
+ /* update the counter for this voice */
+ voice[j].counter = c;
+ }
+ }
+
+ /* mix it down */
+ mix = info->mixer_buffer;
+ for (i = 0; i < length; i++)
+ *buffer++ = info->mixer_lookup[*mix++];
+}
+
+static void *k051649_start(int sndindex, int clock, const void *config)
+{
+ struct k051649_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ /* get stream channels */
+ info->rate = clock/16;
+ info->stream = stream_create(0, 1, info->rate, info, K051649_update);
+ info->mclock = clock;
+
+ /* allocate a buffer to mix into - 1 second's worth should be more than enough */
+ info->mixer_buffer = auto_malloc(2 * sizeof(short) * info->rate);
+
+ /* build the mixer table */
+ if (make_mixer_table(info, 5))
+ return NULL;
+
+ return info;
+}
+
+static void k051649_reset(void *chip)
+{
+ struct k051649_info *info = chip;
+ k051649_sound_channel *voice = info->channel_list;
+ int i;
+
+ /* reset all the voices */
+ for (i=0; i>5; i++) {
+ voice[i].frequency = 0;
+ voice[i].volume = 0;
+ voice[i].counter = 0;
+ }
+}
+
+/********************************************************************************/
+
+WRITE8_HANDLER( K051649_waveform_w )
+{
+ struct k051649_info *info = sndti_token(SOUND_K051649, 0);
+ stream_update(info->stream);
+ info->channel_list[offset>>5].waveform[offset&0x1f]=data;
+ /* SY 20001114: Channel 5 shares the waveform with channel 4 */
+ if (offset >= 0x60)
+ info->channel_list[4].waveform[offset&0x1f]=data;
+}
+
+READ8_HANDLER ( K051649_waveform_r )
+{
+ struct k051649_info *info = sndti_token(SOUND_K051649, 0);
+ return info->channel_list[offset>>5].waveform[offset&0x1f];
+}
+
+/* SY 20001114: Channel 5 doesn't share the waveform with channel 4 on this chip */
+WRITE8_HANDLER( K052539_waveform_w )
+{
+ struct k051649_info *info = sndti_token(SOUND_K051649, 0);
+ stream_update(info->stream);
+ info->channel_list[offset>>5].waveform[offset&0x1f]=data;
+}
+
+WRITE8_HANDLER( K051649_volume_w )
+{
+ struct k051649_info *info = sndti_token(SOUND_K051649, 0);
+ stream_update(info->stream);
+ info->channel_list[offset&0x7].volume=data&0xf;
+}
+
+WRITE8_HANDLER( K051649_frequency_w )
+{
+ struct k051649_info *info = sndti_token(SOUND_K051649, 0);
+ info->f[offset]=data;
+
+ stream_update(info->stream);
+ info->channel_list[offset>>1].frequency=(info->f[offset&0xe] + (info->f[offset|1]<<8))&0xfff;
+}
+
+WRITE8_HANDLER( K051649_keyonoff_w )
+{
+ struct k051649_info *info = sndti_token(SOUND_K051649, 0);
+ stream_update(info->stream);
+ info->channel_list[0].key=data&1;
+ info->channel_list[1].key=data&2;
+ info->channel_list[2].key=data&4;
+ info->channel_list[3].key=data&8;
+ info->channel_list[4].key=data&16;
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void k051649_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void k051649_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = k051649_set_info; break;
+ case SNDINFO_PTR_START: info->start = k051649_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = k051649_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "K051649"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Konami custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/k051649.h b/src/emu/sound/k051649.h
new file mode 100644
index 00000000000..4b4dd9799e6
--- /dev/null
+++ b/src/emu/sound/k051649.h
@@ -0,0 +1,11 @@
+#ifndef k051649_h
+#define k051649_h
+
+WRITE8_HANDLER( K051649_waveform_w );
+READ8_HANDLER( K051649_waveform_r );
+WRITE8_HANDLER( K051649_volume_w );
+WRITE8_HANDLER( K051649_frequency_w );
+WRITE8_HANDLER( K051649_keyonoff_w );
+WRITE8_HANDLER( K052539_waveform_w );
+
+#endif
diff --git a/src/emu/sound/k053260.c b/src/emu/sound/k053260.c
new file mode 100644
index 00000000000..82179687dcb
--- /dev/null
+++ b/src/emu/sound/k053260.c
@@ -0,0 +1,487 @@
+/*********************************************************
+
+ Konami 053260 PCM Sound Chip
+
+*********************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "k053260.h"
+
+/* 2004-02-28: Fixed ppcm decoding. Games sound much better now.*/
+
+#define LOG 0
+
+#define BASE_SHIFT 16
+
+struct K053260_channel_def {
+ unsigned long rate;
+ unsigned long size;
+ unsigned long start;
+ unsigned long bank;
+ unsigned long volume;
+ int play;
+ unsigned long pan;
+ unsigned long pos;
+ int loop;
+ int ppcm; /* packed PCM ( 4 bit signed ) */
+ int ppcm_data;
+};
+struct K053260_chip_def {
+ sound_stream * channel;
+ int mode;
+ int regs[0x30];
+ unsigned char *rom;
+ int rom_size;
+ unsigned long *delta_table;
+ struct K053260_channel_def channels[4];
+ const struct K053260_interface *intf;
+};
+
+
+static void InitDeltaTable( struct K053260_chip_def *ic, int rate, int clock ) {
+ int i;
+ double base = ( double )rate;
+ double max = (double)(clock); /* Hz */
+ unsigned long val;
+
+ for( i = 0; i < 0x1000; i++ ) {
+ double v = ( double )( 0x1000 - i );
+ double target = (max) / v;
+ double fixed = ( double )( 1 << BASE_SHIFT );
+
+ if ( target && base ) {
+ target = fixed / ( base / target );
+ val = ( unsigned long )target;
+ if ( val == 0 )
+ val = 1;
+ } else
+ val = 1;
+
+ ic->delta_table[i] = val;
+ }
+}
+
+static void K053260_reset( void *chip ) {
+ struct K053260_chip_def *ic = chip;
+ int i;
+
+ for( i = 0; i < 4; i++ ) {
+ ic->channels[i].rate = 0;
+ ic->channels[i].size = 0;
+ ic->channels[i].start = 0;
+ ic->channels[i].bank = 0;
+ ic->channels[i].volume = 0;
+ ic->channels[i].play = 0;
+ ic->channels[i].pan = 0;
+ ic->channels[i].pos = 0;
+ ic->channels[i].loop = 0;
+ ic->channels[i].ppcm = 0;
+ ic->channels[i].ppcm_data = 0;
+ }
+}
+
+INLINE int limit( int val, int max, int min ) {
+ if ( val > max )
+ val = max;
+ else if ( val < min )
+ val = min;
+
+ return val;
+}
+
+#define MAXOUT 0x7fff
+#define MINOUT -0x8000
+
+void K053260_update( void * param, stream_sample_t **inputs, stream_sample_t **buffer, int length ) {
+ static long dpcmcnv[] = { 0,1,2,4,8,16,32,64, -128, -64, -32, -16, -8, -4, -2, -1};
+
+ int i, j, lvol[4], rvol[4], play[4], loop[4], ppcm_data[4], ppcm[4];
+ unsigned char *rom[4];
+ unsigned long delta[4], end[4], pos[4];
+ int dataL, dataR;
+ signed char d;
+ struct K053260_chip_def *ic = param;
+
+ /* precache some values */
+ for ( i = 0; i < 4; i++ ) {
+ rom[i]= &ic->rom[ic->channels[i].start + ( ic->channels[i].bank << 16 )];
+ delta[i] = ic->delta_table[ic->channels[i].rate];
+ lvol[i] = ic->channels[i].volume * ic->channels[i].pan;
+ rvol[i] = ic->channels[i].volume * ( 8 - ic->channels[i].pan );
+ end[i] = ic->channels[i].size;
+ pos[i] = ic->channels[i].pos;
+ play[i] = ic->channels[i].play;
+ loop[i] = ic->channels[i].loop;
+ ppcm[i] = ic->channels[i].ppcm;
+ ppcm_data[i] = ic->channels[i].ppcm_data;
+ if ( ppcm[i] )
+ delta[i] /= 2;
+ }
+
+ for ( j = 0; j < length; j++ ) {
+
+ dataL = dataR = 0;
+
+ for ( i = 0; i < 4; i++ ) {
+ /* see if the voice is on */
+ if ( play[i] ) {
+ /* see if we're done */
+ if ( ( pos[i] >> BASE_SHIFT ) >= end[i] ) {
+
+ ppcm_data[i] = 0;
+ if ( loop[i] )
+ pos[i] = 0;
+ else {
+ play[i] = 0;
+ continue;
+ }
+ }
+
+ if ( ppcm[i] ) { /* Packed PCM */
+ /* we only update the signal if we're starting or a real sound sample has gone by */
+ /* this is all due to the dynamic sample rate convertion */
+ if ( pos[i] == 0 || ( ( pos[i] ^ ( pos[i] - delta[i] ) ) & 0x8000 ) == 0x8000 )
+
+ {
+ int newdata;
+ if ( pos[i] & 0x8000 ){
+
+ newdata = ((rom[i][pos[i] >> BASE_SHIFT]) >> 4) & 0x0f; /*high nybble*/
+ }
+ else{
+ newdata = ( ( rom[i][pos[i] >> BASE_SHIFT] ) ) & 0x0f; /*low nybble*/
+ }
+
+ ppcm_data[i] = (( ( ppcm_data[i] * 62 ) >> 6 ) + dpcmcnv[newdata]);
+
+ if ( ppcm_data[i] > 127 )
+ ppcm_data[i] = 127;
+ else
+ if ( ppcm_data[i] < -128 )
+ ppcm_data[i] = -128;
+ }
+
+
+
+ d = ppcm_data[i];
+
+ pos[i] += delta[i];
+ } else { /* PCM */
+ d = rom[i][pos[i] >> BASE_SHIFT];
+
+ pos[i] += delta[i];
+ }
+
+ if ( ic->mode & 2 ) {
+ dataL += ( d * lvol[i] ) >> 2;
+ dataR += ( d * rvol[i] ) >> 2;
+ }
+ }
+ }
+
+ buffer[1][j] = limit( dataL, MAXOUT, MINOUT );
+ buffer[0][j] = limit( dataR, MAXOUT, MINOUT );
+ }
+
+ /* update the regs now */
+ for ( i = 0; i < 4; i++ ) {
+ ic->channels[i].pos = pos[i];
+ ic->channels[i].play = play[i];
+ ic->channels[i].ppcm_data = ppcm_data[i];
+ }
+}
+
+static void *k053260_start(int sndindex, int clock, const void *config)
+{
+ struct K053260_chip_def *ic;
+ int rate = clock / 32;
+ int i;
+
+ ic = auto_malloc(sizeof(*ic));
+ memset(ic, 0, sizeof(*ic));
+
+ /* Initialize our chip structure */
+ ic->intf = config;
+
+ ic->mode = 0;
+ ic->rom = memory_region(ic->intf->region);
+ ic->rom_size = memory_region_length(ic->intf->region) - 1;
+
+ K053260_reset( ic );
+
+ for ( i = 0; i < 0x30; i++ )
+ ic->regs[i] = 0;
+
+ ic->delta_table = ( unsigned long * )auto_malloc( 0x1000 * sizeof( unsigned long ) );
+
+ ic->channel = stream_create( 0, 2, rate, ic, K053260_update );
+
+ InitDeltaTable( ic, rate, clock );
+
+ /* setup SH1 timer if necessary */
+ if ( ic->intf->irq )
+ timer_pulse( attotime_mul(ATTOTIME_IN_HZ(clock), 32), 0, ic->intf->irq );
+
+ return ic;
+}
+
+INLINE void check_bounds( struct K053260_chip_def *ic, int channel ) {
+
+ int channel_start = ( ic->channels[channel].bank << 16 ) + ic->channels[channel].start;
+ int channel_end = channel_start + ic->channels[channel].size - 1;
+
+ if ( channel_start > ic->rom_size ) {
+ logerror("K53260: Attempting to start playing past the end of the rom ( start = %06x, end = %06x ).\n", channel_start, channel_end );
+
+ ic->channels[channel].play = 0;
+
+ return;
+ }
+
+ if ( channel_end > ic->rom_size ) {
+ logerror("K53260: Attempting to play past the end of the rom ( start = %06x, end = %06x ).\n", channel_start, channel_end );
+
+ ic->channels[channel].size = ic->rom_size - channel_start;
+ }
+#if LOG
+ logerror("K053260: Sample Start = %06x, Sample End = %06x, Sample rate = %04lx, PPCM = %s\n", channel_start, channel_end, ic->channels[channel].rate, ic->channels[channel].ppcm ? "yes" : "no" );
+#endif
+}
+
+void K053260_write( int chip, offs_t offset, UINT8 data )
+{
+ int i, t;
+ int r = offset;
+ int v = data;
+
+ struct K053260_chip_def *ic = sndti_token(SOUND_K053260, chip);
+
+ if ( r > 0x2f ) {
+ logerror("K053260: Writing past registers\n" );
+ return;
+ }
+
+ stream_update( ic->channel);
+
+ /* before we update the regs, we need to check for a latched reg */
+ if ( r == 0x28 ) {
+ t = ic->regs[r] ^ v;
+
+ for ( i = 0; i < 4; i++ ) {
+ if ( t & ( 1 << i ) ) {
+ if ( v & ( 1 << i ) ) {
+ ic->channels[i].play = 1;
+ ic->channels[i].pos = 0;
+ ic->channels[i].ppcm_data = 0;
+ check_bounds( ic, i );
+ } else
+ ic->channels[i].play = 0;
+ }
+ }
+
+ ic->regs[r] = v;
+ return;
+ }
+
+ /* update regs */
+ ic->regs[r] = v;
+
+ /* communication registers */
+ if ( r < 8 )
+ return;
+
+ /* channel setup */
+ if ( r < 0x28 ) {
+ int channel = ( r - 8 ) / 8;
+
+ switch ( ( r - 8 ) & 0x07 ) {
+ case 0: /* sample rate low */
+ ic->channels[channel].rate &= 0x0f00;
+ ic->channels[channel].rate |= v;
+ break;
+
+ case 1: /* sample rate high */
+ ic->channels[channel].rate &= 0x00ff;
+ ic->channels[channel].rate |= ( v & 0x0f ) << 8;
+ break;
+
+ case 2: /* size low */
+ ic->channels[channel].size &= 0xff00;
+ ic->channels[channel].size |= v;
+ break;
+
+ case 3: /* size high */
+ ic->channels[channel].size &= 0x00ff;
+ ic->channels[channel].size |= v << 8;
+ break;
+
+ case 4: /* start low */
+ ic->channels[channel].start &= 0xff00;
+ ic->channels[channel].start |= v;
+ break;
+
+ case 5: /* start high */
+ ic->channels[channel].start &= 0x00ff;
+ ic->channels[channel].start |= v << 8;
+ break;
+
+ case 6: /* bank */
+ ic->channels[channel].bank = v & 0xff;
+ break;
+
+ case 7: /* volume is 7 bits. Convert to 8 bits now. */
+ ic->channels[channel].volume = ( ( v & 0x7f ) << 1 ) | ( v & 1 );
+ break;
+ }
+
+ return;
+ }
+
+ switch( r ) {
+ case 0x2a: /* loop, ppcm */
+ for ( i = 0; i < 4; i++ )
+ ic->channels[i].loop = ( v & ( 1 << i ) ) != 0;
+
+ for ( i = 4; i < 8; i++ )
+ ic->channels[i-4].ppcm = ( v & ( 1 << i ) ) != 0;
+ break;
+
+ case 0x2c: /* pan */
+ ic->channels[0].pan = v & 7;
+ ic->channels[1].pan = ( v >> 3 ) & 7;
+ break;
+
+ case 0x2d: /* more pan */
+ ic->channels[2].pan = v & 7;
+ ic->channels[3].pan = ( v >> 3 ) & 7;
+ break;
+
+ case 0x2f: /* control */
+ ic->mode = v & 7;
+ /* bit 0 = read ROM */
+ /* bit 1 = enable sound output */
+ /* bit 2 = unknown */
+ break;
+ }
+}
+
+UINT8 K053260_read( int chip, offs_t offset )
+{
+ struct K053260_chip_def *ic = sndti_token(SOUND_K053260, chip);
+
+ switch ( offset ) {
+ case 0x29: /* channel status */
+ {
+ int i, status = 0;
+
+ for ( i = 0; i < 4; i++ )
+ status |= ic->channels[i].play << i;
+
+ return status;
+ }
+ break;
+
+ case 0x2e: /* read rom */
+ if ( ic->mode & 1 ) {
+ unsigned int offs = ic->channels[0].start + ( ic->channels[0].pos >> BASE_SHIFT ) + ( ic->channels[0].bank << 16 );
+
+ ic->channels[0].pos += ( 1 << 16 );
+
+ if ( offs > ic->rom_size ) {
+ logerror("%06x: K53260: Attempting to read past rom size in rom Read Mode (offs = %06x, size = %06x).\n",activecpu_get_pc(),offs,ic->rom_size );
+
+ return 0;
+ }
+
+ return ic->rom[offs];
+ }
+ break;
+ }
+
+ return ic->regs[offset];
+}
+
+/**************************************************************************************************/
+/* Accesors */
+
+READ8_HANDLER( K053260_0_r )
+{
+ return K053260_read( 0, offset );
+}
+
+WRITE8_HANDLER( K053260_0_w )
+{
+ K053260_write( 0, offset, data );
+}
+
+READ8_HANDLER( K053260_1_r )
+{
+ return K053260_read( 1, offset );
+}
+
+WRITE8_HANDLER( K053260_1_w )
+{
+ K053260_write( 1, offset, data );
+}
+
+WRITE16_HANDLER( K053260_0_lsb_w )
+{
+ if (ACCESSING_LSB)
+ K053260_0_w (offset, data & 0xff);
+}
+
+READ16_HANDLER( K053260_0_lsb_r )
+{
+ return K053260_0_r(offset);
+}
+
+WRITE16_HANDLER( K053260_1_lsb_w )
+{
+ if (ACCESSING_LSB)
+ K053260_1_w (offset, data & 0xff);
+}
+
+READ16_HANDLER( K053260_1_lsb_r )
+{
+ return K053260_1_r(offset);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void k053260_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void k053260_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = k053260_set_info; break;
+ case SNDINFO_PTR_START: info->start = k053260_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "K053260"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Konami custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/k053260.h b/src/emu/sound/k053260.h
new file mode 100644
index 00000000000..e4f53e5e1fb
--- /dev/null
+++ b/src/emu/sound/k053260.h
@@ -0,0 +1,24 @@
+/*********************************************************
+
+ Konami 053260 PCM/ADPCM Sound Chip
+
+*********************************************************/
+#ifndef __K053260_H__
+#define __K053260_H__
+
+struct K053260_interface {
+ int region; /* memory region of sample ROM(s) */
+ void (*irq)(running_machine *machine, int param ); /* called on SH1 complete cycle ( clock / 32 ) */
+};
+
+
+WRITE8_HANDLER( K053260_0_w );
+WRITE8_HANDLER( K053260_1_w );
+READ8_HANDLER( K053260_0_r );
+READ8_HANDLER( K053260_1_r );
+WRITE16_HANDLER( K053260_0_lsb_w );
+READ16_HANDLER( K053260_0_lsb_r );
+WRITE16_HANDLER( K053260_1_lsb_w );
+READ16_HANDLER( K053260_1_lsb_r );
+
+#endif /* __K053260_H__ */
diff --git a/src/emu/sound/k054539.c b/src/emu/sound/k054539.c
new file mode 100644
index 00000000000..1944272112f
--- /dev/null
+++ b/src/emu/sound/k054539.c
@@ -0,0 +1,741 @@
+#define CHANNEL_DEBUG 0
+#define VERBOSE 0
+
+/*********************************************************
+
+ Konami 054539 PCM Sound Chip
+
+ A lot of information comes from Amuse.
+ Big thanks to them.
+
+
+
+CHANNEL_DEBUG enables the following keys:
+
+ PAD. : toggle debug mode
+ PAD0 : toggle chip (0 / 1)
+ PAD4,6 : select channel (0 - 7)
+ PAD8,2 : adjust gain (00=0.0 10=1.0, 20=2.0, etc.)
+ PAD5 : reset gain factor to 1.0
+
+*********************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "k054539.h"
+#include <math.h>
+
+/* Registers:
+ 00..ff: 20 bytes/channel, 8 channels
+ 00..02: pitch (lsb, mid, msb)
+ 03: volume (0=max, 0x40=-36dB)
+ 04: reverb volume (idem)
+ 05: pan (1-f right, 10 middle, 11-1f left)
+ 06..07: reverb delay (0=max, current computation non-trusted)
+ 08..0a: loop (lsb, mid, msb)
+ 0c..0e: start (lsb, mid, msb) (and current position ?)
+
+ 100.1ff: effects?
+ 13f: pan of the analog input (1-1f)
+
+ 200..20f: 2 bytes/channel, 8 channels
+ 00: type (b2-3), reverse (b5)
+ 01: loop (b0)
+
+ 214: keyon (b0-7 = channel 0-7)
+ 215: keyoff ""
+ 22c: channel active? ""
+ 22d: data read/write port
+ 22e: rom/ram select (00..7f == rom banks, 80 = ram)
+ 22f: enable pcm (b0), disable register ram updating (b7)
+
+ The chip has a 0x4000 bytes reverb buffer (the ram from 0x22e).
+ The reverb delay is actually an offset in this buffer. This driver
+ uses some tricks (doubling the buffer size so that the longest
+ reverbs don't fold over the sound to output, and adding a space at
+ the end to fold back overflows in) to be able to do frame-based
+ rendering instead of sample-based.
+*/
+
+struct k054539_info {
+ const struct K054539interface *intf;
+ double voltab[256];
+ double pantab[0xf];
+
+ double K054539_gain[8];
+ UINT8 K054539_posreg_latch[8][3];
+ int K054539_flags;
+
+ unsigned char regs[0x230];
+ unsigned char *ram;
+ int reverb_pos;
+
+ INT32 cur_ptr;
+ int cur_limit;
+ unsigned char *cur_zone;
+ unsigned char *rom;
+ UINT32 rom_size;
+ UINT32 rom_mask;
+ sound_stream * stream;
+
+ struct K054539_channel {
+ UINT32 pos;
+ UINT32 pfrac;
+ INT32 val;
+ INT32 pval;
+ } channels[8];
+};
+
+//*
+
+void K054539_init_flags(int chip, int flags)
+{
+ struct k054539_info *info = sndti_token(SOUND_K054539, chip);
+ info->K054539_flags = flags;
+}
+
+void K054539_set_gain(int chip, int channel, double gain)
+{
+ struct k054539_info *info = sndti_token(SOUND_K054539, chip);
+ if (gain >= 0) info->K054539_gain[channel] = gain;
+}
+//*
+
+static int K054539_regupdate(struct k054539_info *info)
+{
+ return !(info->regs[0x22f] & 0x80);
+}
+
+static void K054539_keyon(struct k054539_info *info, int channel)
+{
+ if(K054539_regupdate(info))
+ info->regs[0x22c] |= 1 << channel;
+}
+
+static void K054539_keyoff(struct k054539_info *info, int channel)
+{
+ if(K054539_regupdate(info))
+ info->regs[0x22c] &= ~(1 << channel);
+}
+
+static void K054539_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct k054539_info *info = param;
+#define VOL_CAP 1.80
+
+ static INT16 dpcm[16] = {
+ 0<<8, 1<<8, 4<<8, 9<<8, 16<<8, 25<<8, 36<<8, 49<<8,
+ -64<<8, -49<<8, -36<<8, -25<<8, -16<<8, -9<<8, -4<<8, -1<<8
+ };
+
+ int ch, reverb_pos;
+ short *rev_max;
+ short *rbase, *rbuffer, *rev_top;
+ unsigned char *samples;
+ UINT32 rom_mask;
+
+ unsigned char *base1, *base2;
+ struct K054539_channel *chan;
+ stream_sample_t *bufl, *bufr;
+ short *revb;
+ int cur_pos, cur_pfrac, cur_val, cur_pval;
+ int delta, rdelta, fdelta, pdelta;
+ int vol, bval, pan, i;
+
+ double gain, lvol, rvol, rbvol;
+
+ reverb_pos = info->reverb_pos;
+ rbase = (short *)(info->ram);
+ rbuffer = rbase + reverb_pos;
+ rev_max = rev_top = rbase + 0x4000;
+
+ memset(buffer[0], 0, length*sizeof(*buffer[0]));
+ memset(buffer[1], 0, length*sizeof(*buffer[1]));
+
+ samples = info->rom;
+ rom_mask = info->rom_mask;
+
+ if(!(info->regs[0x22f] & 1)) return;
+
+ info->reverb_pos = (reverb_pos + length) & 0x3fff;
+
+
+ for(ch=0; ch<8; ch++)
+ if(info->regs[0x22c] & (1<<ch)) {
+ base1 = info->regs + 0x20*ch;
+ base2 = info->regs + 0x200 + 0x2*ch;
+ chan = info->channels + ch;
+//*
+ delta = base1[0x00] | (base1[0x01] << 8) | (base1[0x02] << 16);
+
+ vol = base1[0x03];
+
+ bval = vol + base1[0x04];
+ if (bval > 255) bval = 255;
+
+ pan = base1[0x05];
+// DJ Main: 81-87 right, 88 middle, 89-8f left
+if (pan >= 0x81 && pan <= 0x8f)
+pan -= 0x81;
+else
+ if (pan >= 0x11 && pan <= 0x1f) pan -= 0x11; else pan = 0x18 - 0x11;
+
+ gain = info->K054539_gain[ch];
+
+ lvol = info->voltab[vol] * info->pantab[pan] * gain;
+ if (lvol > VOL_CAP) lvol = VOL_CAP;
+
+ rvol = info->voltab[vol] * info->pantab[0xe - pan] * gain;
+ if (rvol > VOL_CAP) rvol = VOL_CAP;
+
+ rbvol= info->voltab[bval] * gain / 2;
+ if (rbvol > VOL_CAP) rbvol = VOL_CAP;
+
+/*
+ INT x FLOAT could be interpreted as INT x (int)FLOAT instead of (float)INT x FLOAT on some compilers
+ causing precision loss. (rdelta - 0x2000) wraps around on zero reverb and the scale factor should
+ actually be 1/freq_ratio because the target is an offset to the reverb buffer not sample source.
+*/
+ rdelta = (base1[6] | (base1[7] << 8)) >> 3;
+// rdelta = (reverb_pos + (int)((rdelta - 0x2000) * info->freq_ratio)) & 0x3fff;
+ rdelta = (int)(rdelta + reverb_pos) & 0x3fff;
+ revb = rbase + rdelta;
+
+ cur_pos = (base1[0x0c] | (base1[0x0d] << 8) | (base1[0x0e] << 16)) & rom_mask;
+
+ bufl = buffer[0];
+ bufr = buffer[1];
+//*
+
+ if(base2[0] & 0x20) {
+ delta = -delta;
+ fdelta = +0x10000;
+ pdelta = -1;
+ } else {
+ fdelta = -0x10000;
+ pdelta = +1;
+ }
+
+ if(cur_pos != chan->pos) {
+ chan->pos = cur_pos;
+ cur_pfrac = 0;
+ cur_val = 0;
+ cur_pval = 0;
+ } else {
+ cur_pfrac = chan->pfrac;
+ cur_val = chan->val;
+ cur_pval = chan->pval;
+ }
+
+#define UPDATE_CHANNELS \
+ do { \
+ *bufl++ += (INT16)(cur_val*lvol); \
+ *bufr++ += (INT16)(cur_val*rvol); \
+ *revb++ += (INT16)(cur_val*rbvol); \
+ } while(0)
+
+ switch(base2[0] & 0xc) {
+ case 0x0: { // 8bit pcm
+ for(i=0; i<length; i++) {
+ cur_pfrac += delta;
+ while(cur_pfrac & ~0xffff) {
+ cur_pfrac += fdelta;
+ cur_pos += pdelta;
+
+ cur_pval = cur_val;
+ cur_val = (INT16)(samples[cur_pos] << 8);
+ if(cur_val == (INT16)0x8000) {
+ if(base2[1] & 1) {
+ cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask;
+ cur_val = (INT16)(samples[cur_pos] << 8);
+ if(cur_val != (INT16)0x8000)
+ continue;
+ }
+ K054539_keyoff(info, ch);
+ goto end_channel_0;
+ }
+ }
+
+ UPDATE_CHANNELS;
+ }
+ end_channel_0:
+ break;
+ }
+ case 0x4: { // 16bit pcm lsb first
+ pdelta <<= 1;
+
+ for(i=0; i<length; i++) {
+ cur_pfrac += delta;
+ while(cur_pfrac & ~0xffff) {
+ cur_pfrac += fdelta;
+ cur_pos += pdelta;
+
+ cur_pval = cur_val;
+ cur_val = (INT16)(samples[cur_pos] | samples[cur_pos+1]<<8);
+ if(cur_val == (INT16)0x8000) {
+ if(base2[1] & 1) {
+ cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask;
+ cur_val = (INT16)(samples[cur_pos] | samples[cur_pos+1]<<8);
+ if(cur_val != (INT16)0x8000)
+ continue;
+ }
+ K054539_keyoff(info, ch);
+ goto end_channel_4;
+ }
+ }
+
+ UPDATE_CHANNELS;
+ }
+ end_channel_4:
+ break;
+ }
+ case 0x8: { // 4bit dpcm
+ cur_pos <<= 1;
+ cur_pfrac <<= 1;
+ if(cur_pfrac & 0x10000) {
+ cur_pfrac &= 0xffff;
+ cur_pos |= 1;
+ }
+
+ for(i=0; i<length; i++) {
+ cur_pfrac += delta;
+ while(cur_pfrac & ~0xffff) {
+ cur_pfrac += fdelta;
+ cur_pos += pdelta;
+
+ cur_pval = cur_val;
+ cur_val = samples[cur_pos>>1];
+ if(cur_val == 0x88) {
+ if(base2[1] & 1) {
+ cur_pos = ((base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask) << 1;
+ cur_val = samples[cur_pos>>1];
+ if(cur_val != 0x88)
+ goto next_iter;
+ }
+ K054539_keyoff(info, ch);
+ goto end_channel_8;
+ }
+ next_iter:
+ if(cur_pos & 1)
+ cur_val >>= 4;
+ else
+ cur_val &= 15;
+ cur_val = cur_pval + dpcm[cur_val];
+ if(cur_val < -32768)
+ cur_val = -32768;
+ else if(cur_val > 32767)
+ cur_val = 32767;
+ }
+
+ UPDATE_CHANNELS;
+ }
+ end_channel_8:
+ cur_pfrac >>= 1;
+ if(cur_pos & 1)
+ cur_pfrac |= 0x8000;
+ cur_pos >>= 1;
+ break;
+ }
+ default:
+#if VERBOSE
+ logerror("Unknown sample type %x for channel %d\n", base2[0] & 0xc, ch);
+#endif
+ break;
+ }
+ chan->pos = cur_pos;
+ chan->pfrac = cur_pfrac;
+ chan->pval = cur_pval;
+ chan->val = cur_val;
+ if(K054539_regupdate(info)) {
+ base1[0x0c] = cur_pos & 0xff;
+ base1[0x0d] = cur_pos>> 8 & 0xff;
+ base1[0x0e] = cur_pos>>16 & 0xff;
+ }
+
+ if(revb > rev_max)
+ rev_max = revb;
+ }
+
+ while(rev_max >= rev_top) {
+ rev_max[-0x4000] += rev_max[0];
+ rev_max[0] = 0;
+ rev_max--;
+ }
+
+ //* drivers should be given the option to disable reverb when things go terribly wrong
+ if(!(info->K054539_flags & K054539_DISABLE_REVERB))
+ {
+ for(i=0; i<length; i++) {
+ short val = rbase[(i+reverb_pos) & 0x3fff];
+ buffer[0][i] += val;
+ buffer[1][i] += val;
+ }
+ }
+
+ if(rbuffer+length > rev_top) {
+ i = rev_top-rbuffer; // delta
+ memset(rbuffer, 0, i*2);
+ memset(rbase, 0, (length-i)*2);
+ } else
+ memset(rbuffer, 0, length*2);
+
+ #if CHANNEL_DEBUG
+ {
+ static char gc_msg[32] = "chip : ";
+ static int gc_active=0, gc_chip=0, gc_pos[2]={0,0};
+ double *gc_fptr;
+ char *gc_cptr;
+ double gc_f0;
+ int gc_i, gc_j, gc_k, gc_l;
+
+ if (input_code_pressed_once(KEYCODE_DEL_PAD))
+ {
+ gc_active ^= 1;
+ if (!gc_active) ui_popup_time(0, " ");
+ }
+
+ if (gc_active)
+ {
+ if (input_code_pressed_once(KEYCODE_0_PAD)) gc_chip ^= 1;
+
+ gc_i = gc_pos[gc_chip];
+ gc_j = 0;
+ if (input_code_pressed_once(KEYCODE_4_PAD)) { gc_i--; gc_j = 1; }
+ if (input_code_pressed_once(KEYCODE_6_PAD)) { gc_i++; gc_j = 1; }
+ if (gc_j) { gc_i &= 7; gc_pos[gc_chip] = gc_i; }
+
+ if (input_code_pressed_once(KEYCODE_5_PAD))
+ info->K054539_gain[gc_i] = 1.0;
+ else
+ {
+ gc_fptr = &info->K054539_gain[gc_i];
+ gc_f0 = *gc_fptr;
+ gc_j = 0;
+ if (input_code_pressed_once(KEYCODE_2_PAD)) { gc_f0 -= 0.1; gc_j = 1; }
+ if (input_code_pressed_once(KEYCODE_8_PAD)) { gc_f0 += 0.1; gc_j = 1; }
+ if (gc_j) { if (gc_f0 < 0) gc_f0 = 0; *gc_fptr = gc_f0; }
+ }
+
+ gc_fptr = &info->K054539_gain[0] + 8;
+ gc_cptr = gc_msg + 7;
+ for (gc_j=-8; gc_j; gc_j++)
+ {
+ gc_k = (int)(gc_fptr[gc_j] * 10);
+ gc_l = gc_k / 10;
+ gc_k = gc_k % 10;
+ gc_cptr[0] = gc_l + '0';
+ gc_cptr[1] = gc_k + '0';
+ gc_cptr += 3;
+ }
+ gc_i = (gc_i + gc_i*2 + 6);
+ gc_msg[4] = gc_chip + '0';
+ gc_msg[gc_i ] = '[';
+ gc_msg[gc_i+3] = ']';
+ popmessage("%s", gc_msg);
+ gc_msg[gc_i+3] = gc_msg[gc_i] = ' ';
+ }
+ }
+ #endif
+}
+
+
+static TIMER_CALLBACK_PTR( K054539_irq )
+{
+ struct k054539_info *info = param;
+ if(info->regs[0x22f] & 0x20)
+ info->intf->irq ();
+}
+
+static void K054539_init_chip(struct k054539_info *info, int clock, int sndindex)
+{
+ int i;
+
+ memset(info->regs, 0, sizeof(info->regs));
+ memset(info->K054539_posreg_latch, 0, sizeof(info->K054539_posreg_latch)); //*
+ info->K054539_flags |= K054539_UPDATE_AT_KEYON; //* make it default until proven otherwise
+
+ // Real size of 0x4000, the addon is to simplify the reverb buffer computations
+ info->ram = auto_malloc(0x4000*2+clock/50*2);
+ info->reverb_pos = 0;
+ info->cur_ptr = 0;
+ memset(info->ram, 0, 0x4000*2+clock/50*2);
+
+ info->rom = memory_region(info->intf->region);
+ info->rom_size = memory_region_length(info->intf->region);
+ info->rom_mask = 0xffffffffU;
+ for(i=0; i<32; i++)
+ if((1U<<i) >= info->rom_size) {
+ info->rom_mask = (1U<<i) - 1;
+ break;
+ }
+
+ if(info->intf->irq)
+ // One or more of the registers must be the timer period
+ // And anyway, this particular frequency is probably wrong
+ // 480 hz is TRUSTED by gokuparo disco stage - the looping sample doesn't line up otherwise
+ timer_pulse_ptr(ATTOTIME_IN_HZ(480), info, K054539_irq);
+
+ info->stream = stream_create(0, 2, clock, info, K054539_update);
+
+ state_save_register_item_array("K054539", sndindex, info->regs);
+ state_save_register_item_pointer("K054539", sndindex, info->ram, 0x4000);
+ state_save_register_item("K054539", sndindex, info->cur_ptr);
+}
+
+static void K054539_w(int chip, offs_t offset, UINT8 data) //*
+{
+ struct k054539_info *info = sndti_token(SOUND_K054539, chip);
+#if 0
+ int voice, reg;
+
+ /* The K054539 has behavior like many other wavetable chips including
+ the Ensoniq 550x and Gravis GF-1: if a voice is active, writing
+ to it's current position is silently ignored.
+
+ Dadandaan depends on this or the vocals go wrong.
+ */
+ if (offset < 8*0x20)
+ {
+ voice = offset / 0x20;
+ reg = offset & ~0x20;
+
+ if(info->regs[0x22c] & (1<<voice))
+ {
+ if (reg >= 0xc && reg <= 0xe)
+ {
+ return;
+ }
+ }
+ }
+#endif
+
+ int latch, offs, ch, pan;
+ UINT8 *regbase, *regptr, *posptr;
+
+ regbase = info->regs;
+ latch = (info->K054539_flags & K054539_UPDATE_AT_KEYON) && (regbase[0x22f] & 1);
+
+ if (latch && offset < 0x100)
+ {
+ offs = (offset & 0x1f) - 0xc;
+ ch = offset >> 5;
+
+ if (offs >= 0 && offs <= 2)
+ {
+ // latch writes to the position index registers
+ info->K054539_posreg_latch[ch][offs] = data;
+ return;
+ }
+ }
+
+ else switch(offset)
+ {
+ case 0x13f:
+ pan = data >= 0x11 && data <= 0x1f ? data - 0x11 : 0x18 - 0x11;
+ if(info->intf->apan)
+ info->intf->apan(info->pantab[pan], info->pantab[0xe - pan]);
+ break;
+
+ case 0x214:
+ if (latch)
+ {
+ for(ch=0; ch<8; ch++)
+ {
+ if(data & (1<<ch))
+ {
+ posptr = &info->K054539_posreg_latch[ch][0];
+ regptr = regbase + (ch<<5) + 0xc;
+
+ // update the chip at key-on
+ regptr[0] = posptr[0];
+ regptr[1] = posptr[1];
+ regptr[2] = posptr[2];
+
+ K054539_keyon(info, ch);
+ }
+ }
+ }
+ else
+ {
+ for(ch=0; ch<8; ch++)
+ if(data & (1<<ch))
+ K054539_keyon(info, ch);
+ }
+ break;
+
+ case 0x215:
+ for(ch=0; ch<8; ch++)
+ if(data & (1<<ch))
+ K054539_keyoff(info, ch);
+ break;
+
+ case 0x22d:
+ if(regbase[0x22e] == 0x80)
+ info->cur_zone[info->cur_ptr] = data;
+ info->cur_ptr++;
+ if(info->cur_ptr == info->cur_limit)
+ info->cur_ptr = 0;
+ break;
+
+ case 0x22e:
+ info->cur_zone =
+ data == 0x80 ? info->ram :
+ info->rom + 0x20000*data;
+ info->cur_limit = data == 0x80 ? 0x4000 : 0x20000;
+ info->cur_ptr = 0;
+ break;
+
+ default:
+#if VERBOSE
+ if(regbase[offset] != data) {
+ if((offset & 0xff00) == 0) {
+ chanoff = offset & 0x1f;
+ if(chanoff < 4 || chanoff == 5 ||
+ (chanoff >=8 && chanoff <= 0xa) ||
+ (chanoff >= 0xc && chanoff <= 0xe))
+ break;
+ }
+ if(1 || ((offset >= 0x200) && (offset <= 0x210)))
+ break;
+ logerror("K054539 %03x = %02x\n", offset, data);
+ }
+#endif
+ break;
+ }
+
+ regbase[offset] = data;
+}
+
+static void reset_zones(void *param)
+{
+ struct k054539_info *info = param;
+ int data = info->regs[0x22e];
+ info->cur_zone =
+ data == 0x80 ? info->ram :
+ info->rom + 0x20000*data;
+ info->cur_limit = data == 0x80 ? 0x4000 : 0x20000;
+}
+
+static UINT8 K054539_r(int chip, offs_t offset)
+{
+ struct k054539_info *info = sndti_token(SOUND_K054539, chip);
+ switch(offset) {
+ case 0x22d:
+ if(info->regs[0x22f] & 0x10) {
+ UINT8 res = info->cur_zone[info->cur_ptr];
+ info->cur_ptr++;
+ if(info->cur_ptr == info->cur_limit)
+ info->cur_ptr = 0;
+ return res;
+ } else
+ return 0;
+ case 0x22c:
+ break;
+ default:
+#if VERBOSE
+ logerror("K054539 read %03x\n", offset);
+#endif
+ break;
+ }
+ return info->regs[offset];
+}
+
+static void *k054539_start(int sndindex, int clock, const void *config)
+{
+ int i;
+ struct k054539_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ for (i = 0; i < 8; i++)
+ info->K054539_gain[i] = 1.0;
+ info->K054539_flags = K054539_RESET_FLAGS;
+
+ info->intf = config;
+
+ /*
+ I've tried various equations on volume control but none worked consistently.
+ The upper four channels in most MW/GX games simply need a significant boost
+ to sound right. For example, the bass and smash sound volumes in Violent Storm
+ have roughly the same values and the voices in Tokimeki Puzzledama are given
+ values smaller than those of the hihats. Needless to say the two K054539 chips
+ in Mystic Warriors are completely out of balance. Rather than forcing a
+ "one size fits all" function to the voltab the current invert exponential
+ appraoch seems most appropriate.
+ */
+ // Factor the 1/4 for the number of channels in the volume (1/8 is too harsh, 1/2 gives clipping)
+ // vol=0 -> no attenuation, vol=0x40 -> -36dB
+ for(i=0; i<256; i++)
+ info->voltab[i] = pow(10.0, (-36.0 * (double)i / (double)0x40) / 20.0) / 4.0;
+
+ // Pan table for the left channel
+ // Right channel is identical with inverted index
+ // Formula is such that pan[i]**2+pan[0xe-i]**2 = 1 (constant output power)
+ // and pan[0xe] = 1 (full panning)
+ for(i=0; i<0xf; i++)
+ info->pantab[i] = sqrt(i) / sqrt(0xe);
+
+ K054539_init_chip(info, clock, sndindex);
+
+ state_save_register_func_postload_ptr(reset_zones, info);
+ return info;
+}
+
+WRITE8_HANDLER( K054539_0_w )
+{
+ K054539_w(0, offset, data);
+}
+
+READ8_HANDLER( K054539_0_r )
+{
+ return K054539_r(0, offset);
+}
+
+WRITE8_HANDLER( K054539_1_w )
+{
+ K054539_w(1, offset, data);
+}
+
+READ8_HANDLER( K054539_1_r )
+{
+ return K054539_r(1, offset);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void k054539_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void k054539_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = k054539_set_info; break;
+ case SNDINFO_PTR_START: info->start = k054539_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "K054539"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Konami custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/k054539.h b/src/emu/sound/k054539.h
new file mode 100644
index 00000000000..61caf8f9d50
--- /dev/null
+++ b/src/emu/sound/k054539.h
@@ -0,0 +1,43 @@
+/*********************************************************
+
+ Konami 054539 PCM Sound Chip
+
+*********************************************************/
+#ifndef __K054539_H__
+#define __K054539_H__
+
+struct K054539interface {
+ int region; /* memory regions of sample ROM(s) */
+ void (*apan)(double, double); /* Callback for analog output mixing levels (0..1 for each channel) */
+ void (*irq)( void );
+};
+
+
+WRITE8_HANDLER( K054539_0_w );
+READ8_HANDLER( K054539_0_r );
+WRITE8_HANDLER( K054539_1_w );
+READ8_HANDLER( K054539_1_r );
+
+//* control flags, may be set at DRIVER_INIT().
+#define K054539_RESET_FLAGS 0
+#define K054539_REVERSE_STEREO 1
+#define K054539_DISABLE_REVERB 2
+#define K054539_UPDATE_AT_KEYON 4
+
+void K054539_init_flags(int chip, int flags);
+
+/*
+ Note that the eight PCM channels of a K054539 do not have seperate
+ volume controls. Considering the global attenuation equation may not
+ be entirely accurate, K054539_set_gain() provides means to control
+ channel gain. It can be called anywhere but preferrably from
+ DRIVER_INIT().
+
+ Parameters:
+ chip : 0 / 1
+ channel : 0 - 7
+ gain : 0.0=silent, 1.0=no gain, 2.0=twice as loud, etc.
+*/
+void K054539_set_gain(int chip, int channel, double gain);
+
+#endif /* __K054539_H__ */
diff --git a/src/emu/sound/msm5205.c b/src/emu/sound/msm5205.c
new file mode 100644
index 00000000000..678ca78b919
--- /dev/null
+++ b/src/emu/sound/msm5205.c
@@ -0,0 +1,330 @@
+/*
+ * streaming ADPCM driver
+ * by Aaron Giles
+ *
+ * Library to transcode from an ADPCM source to raw PCM.
+ * Written by Buffoni Mirko in 08/06/97
+ * References: various sources and documents.
+ *
+ * HJB 08/31/98
+ * modified to use an automatically selected oversampling factor
+ * for the current sample rate
+ *
+ * 01/06/99
+ * separate MSM5205 emulator form adpcm.c and some fix
+ */
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "msm5205.h"
+
+/*
+ *
+ * MSM 5205 ADPCM chip:
+ *
+ * Data is streamed from a CPU by means of a clock generated on the chip.
+ *
+ * A reset signal is set high or low to determine whether playback (and interrupts) are occuring
+ *
+ */
+
+struct MSM5205Voice
+{
+ const struct MSM5205interface *intf;
+ sound_stream * stream; /* number of stream system */
+ INT32 index;
+ INT32 clock; /* clock rate */
+ emu_timer *timer; /* VCLK callback timer */
+ INT32 data; /* next adpcm data */
+ INT32 vclk; /* vclk signal (external mode) */
+ INT32 reset; /* reset pin signal */
+ INT32 prescaler; /* prescaler selector S1 and S2 */
+ INT32 bitwidth; /* bit width selector -3B/4B */
+ INT32 signal; /* current ADPCM signal */
+ INT32 step; /* current ADPCM step */
+ int diff_lookup[49*16];
+};
+
+
+/*
+ * ADPCM lockup tabe
+ */
+
+/* step size index shift table */
+static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
+
+/*
+ * Compute the difference table
+ */
+
+static void ComputeTables (struct MSM5205Voice *voice)
+{
+ /* nibble to bit map */
+ static const int nbl2bit[16][4] =
+ {
+ { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
+ { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
+ {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
+ {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
+ };
+
+ int step, nib;
+
+ /* loop over all possible steps */
+ for (step = 0; step <= 48; step++)
+ {
+ /* compute the step value */
+ int stepval = floor (16.0 * pow (11.0 / 10.0, (double)step));
+
+ /* loop over all nibbles and compute the difference */
+ for (nib = 0; nib < 16; nib++)
+ {
+ voice->diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
+ (stepval * nbl2bit[nib][1] +
+ stepval/2 * nbl2bit[nib][2] +
+ stepval/4 * nbl2bit[nib][3] +
+ stepval/8);
+ }
+ }
+}
+
+/* stream update callbacks */
+static void MSM5205_update(void *param,stream_sample_t **inputs, stream_sample_t **_buffer,int length)
+{
+ struct MSM5205Voice *voice = param;
+ stream_sample_t *buffer = _buffer[0];
+
+ /* if this voice is active */
+ if(voice->signal)
+ {
+ short val = voice->signal * 16;
+ while (length)
+ {
+ *buffer++ = val;
+ length--;
+ }
+ }
+ else
+ memset (buffer,0,length*sizeof(*buffer));
+}
+
+/* timer callback at VCLK low eddge */
+static TIMER_CALLBACK_PTR( MSM5205_vclk_callback )
+{
+ struct MSM5205Voice *voice = param;
+ int val;
+ int new_signal;
+ /* callback user handler and latch next data */
+ if(voice->intf->vclk_callback) (*voice->intf->vclk_callback)(voice->index);
+
+ /* reset check at last hieddge of VCLK */
+ if(voice->reset)
+ {
+ new_signal = 0;
+ voice->step = 0;
+ }
+ else
+ {
+ /* update signal */
+ /* !! MSM5205 has internal 12bit decoding, signal width is 0 to 8191 !! */
+ val = voice->data;
+ new_signal = voice->signal + voice->diff_lookup[voice->step * 16 + (val & 15)];
+ if (new_signal > 2047) new_signal = 2047;
+ else if (new_signal < -2048) new_signal = -2048;
+ voice->step += index_shift[val & 7];
+ if (voice->step > 48) voice->step = 48;
+ else if (voice->step < 0) voice->step = 0;
+ }
+ /* update when signal changed */
+ if( voice->signal != new_signal)
+ {
+ stream_update(voice->stream);
+ voice->signal = new_signal;
+ }
+}
+
+/*
+ * Reset emulation of an MSM5205-compatible chip
+ */
+static void msm5205_reset(void *chip)
+{
+ struct MSM5205Voice *voice = chip;
+
+ /* initialize work */
+ voice->data = 0;
+ voice->vclk = 0;
+ voice->reset = 0;
+ voice->signal = 0;
+ voice->step = 0;
+ /* timer and bitwidth set */
+ MSM5205_playmode_w(voice->index,voice->intf->select);
+}
+
+/*
+ * Start emulation of an MSM5205-compatible chip
+ */
+
+static void *msm5205_start(int sndindex, int clock, const void *config)
+{
+ struct MSM5205Voice *voice;
+
+ voice = auto_malloc(sizeof(*voice));
+ memset(voice, 0, sizeof(*voice));
+ sndintrf_register_token(voice);
+
+ /* save a global pointer to our interface */
+ voice->intf = config;
+ voice->index = sndindex;
+ voice->clock = clock;
+
+ /* compute the difference tables */
+ ComputeTables (voice);
+
+ /* stream system initialize */
+ voice->stream = stream_create(0,1,clock,voice,MSM5205_update);
+ voice->timer = timer_alloc_ptr(MSM5205_vclk_callback, voice);
+
+ /* initialize */
+ msm5205_reset(voice);
+
+ /* register for save states */
+ state_save_register_item("msm5205", sndindex, voice->clock);
+ state_save_register_item("msm5205", sndindex, voice->data);
+ state_save_register_item("msm5205", sndindex, voice->vclk);
+ state_save_register_item("msm5205", sndindex, voice->reset);
+ state_save_register_item("msm5205", sndindex, voice->prescaler);
+ state_save_register_item("msm5205", sndindex, voice->bitwidth);
+ state_save_register_item("msm5205", sndindex, voice->signal);
+ state_save_register_item("msm5205", sndindex, voice->step);
+
+ /* success */
+ return voice;
+}
+
+/*
+ * Handle an update of the vclk status of a chip (1 is reset ON, 0 is reset OFF)
+ * This function can use selector = MSM5205_SEX only
+ */
+void MSM5205_vclk_w (int num, int vclk)
+{
+ struct MSM5205Voice *voice = sndti_token(SOUND_MSM5205, num);
+
+ if( voice->prescaler != 0 )
+ {
+ logerror("error: MSM5205_vclk_w() called with chip = %d, but VCLK selected master mode\n", num);
+ }
+ else
+ {
+ if( voice->vclk != vclk)
+ {
+ voice->vclk = vclk;
+ if( !vclk ) MSM5205_vclk_callback(Machine, voice);
+ }
+ }
+}
+
+/*
+ * Handle an update of the reset status of a chip (1 is reset ON, 0 is reset OFF)
+ */
+
+void MSM5205_reset_w (int num, int reset)
+{
+ struct MSM5205Voice *voice = sndti_token(SOUND_MSM5205, num);
+ voice->reset = reset;
+}
+
+/*
+ * Handle an update of the data to the chip
+ */
+
+void MSM5205_data_w (int num, int data)
+{
+ struct MSM5205Voice *voice = sndti_token(SOUND_MSM5205, num);
+ if( voice->bitwidth == 4)
+ voice->data = data & 0x0f;
+ else
+ voice->data = (data & 0x07)<<1; /* unknown */
+}
+
+/*
+ * Handle an change of the selector
+ */
+
+void MSM5205_playmode_w(int num,int select)
+{
+ struct MSM5205Voice *voice = sndti_token(SOUND_MSM5205, num);
+ static const int prescaler_table[4] = {96,48,64,0};
+ int prescaler = prescaler_table[select & 3];
+ int bitwidth = (select & 4) ? 4 : 3;
+
+
+ if( voice->prescaler != prescaler )
+ {
+ stream_update(voice->stream);
+
+ voice->prescaler = prescaler;
+ /* timer set */
+ if( prescaler )
+ {
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(voice->clock), prescaler);
+ timer_adjust_ptr(voice->timer, period, period);
+ }
+ else
+ timer_adjust_ptr(voice->timer, attotime_never, attotime_zero);
+ }
+
+ if( voice->bitwidth != bitwidth )
+ {
+ stream_update(voice->stream);
+
+ voice->bitwidth = bitwidth;
+ }
+}
+
+
+void MSM5205_set_volume(int num,int volume)
+{
+ struct MSM5205Voice *voice = sndti_token(SOUND_MSM5205, num);
+
+ stream_set_output_gain(voice->stream,0,volume / 100.0);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void msm5205_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void msm5205_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = msm5205_set_info; break;
+ case SNDINFO_PTR_START: info->start = msm5205_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "MSM5205"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "ADPCM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/msm5205.h b/src/emu/sound/msm5205.h
new file mode 100644
index 00000000000..cb0657fbf18
--- /dev/null
+++ b/src/emu/sound/msm5205.h
@@ -0,0 +1,36 @@
+#ifndef MSM5205_H
+#define MSM5205_H
+
+/* an interface for the MSM5205 and similar chips */
+
+/* priscaler selector defines */
+/* default master clock is 384KHz */
+#define MSM5205_S96_3B 0 /* prsicaler 1/96(4KHz) , data 3bit */
+#define MSM5205_S48_3B 1 /* prsicaler 1/48(8KHz) , data 3bit */
+#define MSM5205_S64_3B 2 /* prsicaler 1/64(6KHz) , data 3bit */
+#define MSM5205_SEX_3B 3 /* VCLK slave mode , data 3bit */
+#define MSM5205_S96_4B 4 /* prsicaler 1/96(4KHz) , data 4bit */
+#define MSM5205_S48_4B 5 /* prsicaler 1/48(8KHz) , data 4bit */
+#define MSM5205_S64_4B 6 /* prsicaler 1/64(6KHz) , data 4bit */
+#define MSM5205_SEX_4B 7 /* VCLK slave mode , data 4bit */
+
+struct MSM5205interface
+{
+ void (*vclk_callback)(int); /* VCLK callback */
+ int select; /* prescaler / bit width selector */
+};
+
+/* reset signal should keep for 2cycle of VCLK */
+void MSM5205_reset_w (int num, int reset);
+/* adpcmata is latched after vclk_interrupt callback */
+void MSM5205_data_w (int num, int data);
+/* VCLK slave mode option */
+/* if VCLK and reset or data is changed at the same time, */
+/* Call MSM5205_vclk_w after MSM5205_data_w and MSM5205_reset_w. */
+void MSM5205_vclk_w (int num, int reset);
+/* option , selected pin seletor */
+void MSM5205_playmode_w(int num,int _select);
+
+void MSM5205_set_volume(int num,int volume);
+
+#endif
diff --git a/src/emu/sound/msm5232.c b/src/emu/sound/msm5232.c
new file mode 100644
index 00000000000..b51947e14b0
--- /dev/null
+++ b/src/emu/sound/msm5232.c
@@ -0,0 +1,803 @@
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+
+#include "msm5232.h"
+
+/*
+ OKI MSM5232RS
+ 8 channel tone generator
+*/
+
+typedef struct {
+ UINT8 mode;
+
+ int TG_count_period;
+ int TG_count;
+
+ UINT8 TG_cnt; /* 7 bits binary counter (frequency output) */
+ UINT8 TG_out16; /* bit number (of TG_cnt) for 16' output */
+ UINT8 TG_out8; /* bit number (of TG_cnt) for 8' output */
+ UINT8 TG_out4; /* bit number (of TG_cnt) for 4' output */
+ UINT8 TG_out2; /* bit number (of TG_cnt) for 2' output */
+
+ int egvol;
+ int eg_sect;
+ int counter;
+ int eg;
+
+ UINT8 eg_arm; /* attack/release mode */
+
+ double ar_rate;
+ double dr_rate;
+ double rr_rate;
+
+ int pitch; /* current pitch data */
+} VOICE;
+
+
+typedef struct {
+ sound_stream *stream;
+
+ VOICE voi[8];
+
+ UINT32 EN_out16[2]; /* enable 16' output masks for both groups (0-disabled ; ~0 -enabled) */
+ UINT32 EN_out8[2]; /* enable 8' output masks */
+ UINT32 EN_out4[2]; /* enable 4' output masks */
+ UINT32 EN_out2[2]; /* enable 2' output masks */
+
+ int noise_cnt;
+ int noise_step;
+ int noise_rng;
+ int noise_clocks; /* number of the noise_rng (output) level changes */
+
+ unsigned int UpdateStep;
+
+ /* rate tables */
+ double ar_tbl[8];
+ double dr_tbl[16];
+
+ UINT8 control1;
+ UINT8 control2;
+
+ int clock; /* chip clock in Hz */
+ int rate; /* sample rate in Hz */
+
+ double external_capacity[8]; /* in Farads, eg 0.39e-6 = 0.36 uF (microFarads) */
+
+} MSM5232;
+
+
+/* Default chip clock is 2119040 Hz */
+/* At this clock chip generates exactly 440.0 Hz signal on 8' output when pitch data=0x21 */
+
+
+/* ROM table to convert from pitch data into data for programmable counter and binary counter */
+/* Chip has 88x12bits ROM (addressing (in hex) from 0x00 to 0x57) */
+#define ROM(counter,bindiv) (counter|(bindiv<<9))
+
+static const UINT16 MSM5232_ROM[88]={
+/* higher values are Programmable Counter data (9 bits) */
+/* lesser values are Binary Counter shift data (3 bits) */
+
+/* 0 */ ROM (506, 7),
+
+/* 1 */ ROM (478, 7),/* 2 */ ROM (451, 7),/* 3 */ ROM (426, 7),/* 4 */ ROM (402, 7),
+/* 5 */ ROM (379, 7),/* 6 */ ROM (358, 7),/* 7 */ ROM (338, 7),/* 8 */ ROM (319, 7),
+/* 9 */ ROM (301, 7),/* A */ ROM (284, 7),/* B */ ROM (268, 7),/* C */ ROM (253, 7),
+
+/* D */ ROM (478, 6),/* E */ ROM (451, 6),/* F */ ROM (426, 6),/*10 */ ROM (402, 6),
+/*11 */ ROM (379, 6),/*12 */ ROM (358, 6),/*13 */ ROM (338, 6),/*14 */ ROM (319, 6),
+/*15 */ ROM (301, 6),/*16 */ ROM (284, 6),/*17 */ ROM (268, 6),/*18 */ ROM (253, 6),
+
+/*19 */ ROM (478, 5),/*1A */ ROM (451, 5),/*1B */ ROM (426, 5),/*1C */ ROM (402, 5),
+/*1D */ ROM (379, 5),/*1E */ ROM (358, 5),/*1F */ ROM (338, 5),/*20 */ ROM (319, 5),
+/*21 */ ROM (301, 5),/*22 */ ROM (284, 5),/*23 */ ROM (268, 5),/*24 */ ROM (253, 5),
+
+/*25 */ ROM (478, 4),/*26 */ ROM (451, 4),/*27 */ ROM (426, 4),/*28 */ ROM (402, 4),
+/*29 */ ROM (379, 4),/*2A */ ROM (358, 4),/*2B */ ROM (338, 4),/*2C */ ROM (319, 4),
+/*2D */ ROM (301, 4),/*2E */ ROM (284, 4),/*2F */ ROM (268, 4),/*30 */ ROM (253, 4),
+
+/*31 */ ROM (478, 3),/*32 */ ROM (451, 3),/*33 */ ROM (426, 3),/*34 */ ROM (402, 3),
+/*35 */ ROM (379, 3),/*36 */ ROM (358, 3),/*37 */ ROM (338, 3),/*38 */ ROM (319, 3),
+/*39 */ ROM (301, 3),/*3A */ ROM (284, 3),/*3B */ ROM (268, 3),/*3C */ ROM (253, 3),
+
+/*3D */ ROM (478, 2),/*3E */ ROM (451, 2),/*3F */ ROM (426, 2),/*40 */ ROM (402, 2),
+/*41 */ ROM (379, 2),/*42 */ ROM (358, 2),/*43 */ ROM (338, 2),/*44 */ ROM (319, 2),
+/*45 */ ROM (301, 2),/*46 */ ROM (284, 2),/*47 */ ROM (268, 2),/*48 */ ROM (253, 2),
+
+/*49 */ ROM (478, 1),/*4A */ ROM (451, 1),/*4B */ ROM (426, 1),/*4C */ ROM (402, 1),
+/*4D */ ROM (379, 1),/*4E */ ROM (358, 1),/*4F */ ROM (338, 1),/*50 */ ROM (319, 1),
+/*51 */ ROM (301, 1),/*52 */ ROM (284, 1),/*53 */ ROM (268, 1),/*54 */ ROM (253, 1),
+
+/*55 */ ROM (253, 1),/*56 */ ROM (253, 1),
+
+/*57 */ ROM (13, 7)
+};
+#undef ROM
+
+
+#define STEP_SH (16) /* step calculations accuracy */
+
+
+/* save output as raw 16-bit sample */
+/* #define SAVE_SAMPLE */
+/* #define SAVE_SEPARATE_CHANNELS */
+#if defined SAVE_SAMPLE || defined SAVE_SEPARATE_CHANNELS
+static FILE *sample[9];
+#endif
+
+
+
+/*
+ * resistance values are guesswork, default capacity is mentioned in the datasheets
+ *
+ * charges external capacitor (default is 0.39uF) via R51
+ * in approx. 5*1400 * 0.39e-6
+ *
+ * external capacitor is discharged through R52
+ * in approx. 5*28750 * 0.39e-6
+ */
+
+
+#define R51 1400 /* charge resistance */
+#define R52 28750 /* discharge resistance */
+
+#if 0
+/*
+ C24 = external capacity
+
+ mame_printf_debug("Time constant T=R*C =%f sec.\n",R51*C24);
+ mame_printf_debug("Cap fully charged after 5T=%f sec (sample=%f). Level=%f\n",(R51*C24)*5,(R51*C24)*5*sample_rate , VMAX*0.99326 );
+ mame_printf_debug("Cap charged after 5T=%f sec (sample=%f). Level=%20.16f\n",(R51*C24)*5,(R51*C24)*5*sample_rate ,
+ VMAX*(1.0-pow(2.718,-0.0748/(R51*C24))) );
+*/
+#endif
+
+
+
+
+static void msm5232_init_tables( MSM5232 *chip )
+{
+ int i;
+ double scale;
+
+ /* sample rate = chip clock !!! But : */
+ /* highest possible frequency is chipclock/13/16 (pitch data=0x57) */
+ /* at 2MHz : 2000000/13/16 = 9615 Hz */
+
+ i = ((double)(1<<STEP_SH) * (double)chip->rate) / (double)chip->clock;
+ chip->UpdateStep = i;
+ /* logerror("clock=%i Hz rate=%i Hz, UpdateStep=%i\n",
+ chip->clock, chip->rate, chip->UpdateStep); */
+
+ scale = ((double)chip->clock) / (double)chip->rate;
+ chip->noise_step = ((1<<STEP_SH)/128.0) * scale; /* step of the rng reg in 16.16 format */
+ /* logerror("noise step=%8x\n", chip->noise_step); */
+
+#if 0
+{
+ /* rate tables (in miliseconds) */
+ static int ATBL[8] = { 2,4,8,16, 32,64, 32,64};
+ static int DTBL[16]= { 40,80,160,320, 640,1280, 640,1280,
+ 333,500,1000,2000, 4000,8000, 4000,8000};
+ for (i=0; i<8; i++)
+ {
+ double clockscale = (double)chip->clock / 2119040.0;
+ double time = (ATBL[i] / 1000.0) / clockscale; /* attack time in seconds */
+ chip->ar_tbl[i] = (float)0.50 * ( (1.0/time) / (double)chip->rate );
+ /* logerror("ATBL[%i] = %20.16f time = %f s\n",i, chip->ar_tbl[i], time); */
+ }
+
+ for (i=0; i<16; i++)
+ {
+ double clockscale = (double)chip->clock / 2119040.0;
+ double time = (DTBL[i] / 1000.0) / clockscale; /* decay time in seconds */
+ chip->dr_tbl[i] = (float)0.50 * ( (1.0/time) / (double)chip->rate );
+ /* logerror("DTBL[%i] = %20.16f time = %f s\n",i, chip->dr_tbl[i], time); */
+ }
+}
+#endif
+
+
+ for (i=0; i<8; i++)
+ {
+ double clockscale = (double)chip->clock / 2119040.0;
+ chip->ar_tbl[i] = ((1<<i) / clockscale) * (double)R51;
+ }
+
+ for (i=0; i<8; i++)
+ {
+ double clockscale = (double)chip->clock / 2119040.0;
+ chip->dr_tbl[i] = ( (1<<i) / clockscale) * (double)R52;
+ chip->dr_tbl[i+8] = (6.25*(1<<i) / clockscale) * (double)R52;
+ }
+
+
+#ifdef SAVE_SAMPLE
+ sample[8]=fopen("sampsum.pcm","wb");
+#endif
+#ifdef SAVE_SEPARATE_CHANNELS
+ sample[0]=fopen("samp0.pcm","wb");
+ sample[1]=fopen("samp1.pcm","wb");
+ sample[2]=fopen("samp2.pcm","wb");
+ sample[3]=fopen("samp3.pcm","wb");
+ sample[4]=fopen("samp4.pcm","wb");
+ sample[5]=fopen("samp5.pcm","wb");
+ sample[6]=fopen("samp6.pcm","wb");
+ sample[7]=fopen("samp7.pcm","wb");
+#endif
+}
+
+
+static void msm5232_init_voice(MSM5232 *chip, int i)
+{
+ chip->voi[i].ar_rate= chip->ar_tbl[0] * chip->external_capacity[i];
+ chip->voi[i].dr_rate= chip->dr_tbl[0] * chip->external_capacity[i];
+ chip->voi[i].rr_rate= chip->dr_tbl[0] * chip->external_capacity[i]; /* this is constant value */
+ chip->voi[i].eg_sect= -1;
+ chip->voi[i].eg = 0.0;
+ chip->voi[i].eg_arm = 0;
+ chip->voi[i].pitch = -1.0;
+}
+
+
+static void msm5232_write(MSM5232 *chip, int ofst, int data);
+
+
+static void msm5232_reset(void *_chip)
+{
+ MSM5232 *chip = _chip;
+ int i;
+
+ for (i=0; i<8; i++)
+ {
+ msm5232_write(chip,i,0x80);
+ msm5232_write(chip,i,0x00);
+ }
+ chip->noise_cnt = 0;
+ chip->noise_rng = 1;
+ chip->noise_clocks = 0;
+
+ chip->control1 = 0;
+ chip->EN_out16[0] = 0;
+ chip->EN_out8[0] = 0;
+ chip->EN_out4[0] = 0;
+ chip->EN_out2[0] = 0;
+
+ chip->control2 = 0;
+ chip->EN_out16[1] = 0;
+ chip->EN_out8[1] = 0;
+ chip->EN_out4[1] = 0;
+ chip->EN_out2[1] = 0;
+
+}
+
+static void msm5232_init(MSM5232 *chip, const struct MSM5232interface *intf, int clock, int rate)
+{
+ int j;
+
+ chip->clock = clock;
+ chip->rate = rate ? rate : 44100; /* avoid division by 0 */
+
+ for (j=0; j<8; j++)
+ {
+ chip->external_capacity[j] = intf->capacity[j];
+ }
+
+ msm5232_init_tables( chip );
+
+ for (j=0; j<8; j++)
+ {
+ memset(&chip->voi[j],0,sizeof(VOICE));
+ msm5232_init_voice(chip,j);
+ }
+ msm5232_reset( chip );
+}
+
+static void msm5232_shutdown(void *chip)
+{
+#ifdef SAVE_SAMPLE
+ fclose(sample[8]);
+#endif
+#ifdef SAVE_SEPARATE_CHANNELS
+ fclose(sample[0]);
+ fclose(sample[1]);
+ fclose(sample[2]);
+ fclose(sample[3]);
+ fclose(sample[4]);
+ fclose(sample[5]);
+ fclose(sample[6]);
+ fclose(sample[7]);
+#endif
+}
+
+static void msm5232_write(MSM5232 *chip, int ofst, int data)
+{
+ if (ofst > 0x0d)
+ return;
+
+ if (ofst < 0x08) /* pitch */
+ {
+ int ch = ofst&7;
+ if(data&0x80)
+ {
+ if(data >= 0xd8)
+ {
+ /*if ((data&0x7f) != 0x5f) logerror("MSM5232: WRONG PITCH CODE = %2x\n",data&0x7f);*/
+ chip->voi[ch].mode = 1; /* noise mode */
+ chip->voi[ch].eg_sect = 0; /* Key On */
+ }
+ else
+ {
+ if ( chip->voi[ch].pitch != (data&0x7f) )
+ {
+ int n;
+ UINT16 pg;
+
+ chip->voi[ch].pitch = data&0x7f;
+
+ pg = MSM5232_ROM[ data&0x7f ];
+
+ chip->voi[ch].TG_count_period = (pg & 0x1ff) * chip->UpdateStep / 2;
+
+ n = (pg>>9) & 7; /* n = bit number for 16' output */
+ chip->voi[ch].TG_out16 = 1<<n;
+ /* for 8' it is bit n-1 (bit 0 if n-1<0) */
+ /* for 4' it is bit n-2 (bit 0 if n-2<0) */
+ /* for 2' it is bit n-3 (bit 0 if n-3<0) */
+ n = (n>0)? n-1: 0;
+ chip->voi[ch].TG_out8 = 1<<n;
+
+ n = (n>0)? n-1: 0;
+ chip->voi[ch].TG_out4 = 1<<n;
+
+ n = (n>0)? n-1: 0;
+ chip->voi[ch].TG_out2 = 1<<n;
+
+ }
+ chip->voi[ch].mode = 0; /* tone mode */
+ chip->voi[ch].eg_sect = 0; /* Key On */
+ }
+ }
+ else
+ {
+ if ( !chip->voi[ch].eg_arm ) /* arm = 0 */
+ chip->voi[ch].eg_sect = 2; /* Key Off -> go to release */
+ else /* arm = 1 */
+ chip->voi[ch].eg_sect = 1; /* Key Off -> go to decay */
+ }
+ }
+ else
+ {
+ int i;
+ switch(ofst)
+ {
+ case 0x08: /* group1 attack */
+ for (i=0; i<4; i++)
+ chip->voi[i].ar_rate = chip->ar_tbl[data&0x7] * chip->external_capacity[i];
+ break;
+
+ case 0x09: /* group2 attack */
+ for (i=0; i<4; i++)
+ chip->voi[i+4].ar_rate = chip->ar_tbl[data&0x7] * chip->external_capacity[i+4];
+ break;
+
+ case 0x0a: /* group1 decay */
+ for (i=0; i<4; i++)
+ chip->voi[i].dr_rate = chip->dr_tbl[data&0xf] * chip->external_capacity[i];
+ break;
+
+ case 0x0b: /* group2 decay */
+ for (i=0; i<4; i++)
+ chip->voi[i+4].dr_rate = chip->dr_tbl[data&0xf] * chip->external_capacity[i+4];
+ break;
+
+ case 0x0c: /* group1 control */
+
+ /*if (chip->control1 != data)
+ logerror("msm5232: control1 ctrl=%x OE=%x\n", data&0xf0, data&0x0f);*/
+
+ /*if (data & 0x10)
+ popmessage("msm5232: control1 ctrl=%2x\n", data);*/
+
+ chip->control1 = data;
+
+ for (i=0; i<4; i++)
+ chip->voi[i].eg_arm = data&0x10;
+
+ chip->EN_out16[0] = (data&1) ? ~0:0;
+ chip->EN_out8[0] = (data&2) ? ~0:0;
+ chip->EN_out4[0] = (data&4) ? ~0:0;
+ chip->EN_out2[0] = (data&8) ? ~0:0;
+
+ break;
+
+ case 0x0d: /* group2 control */
+
+ /*if (chip->control2 != data)
+ logerror("msm5232: control2 ctrl=%x OE=%x\n", data&0xf0, data&0x0f);*/
+
+ /*if (data & 0x10)
+ popmessage("msm5232: control2 ctrl=%2x\n", data);*/
+
+ chip->control2 = data;
+
+ for (i=0; i<4; i++)
+ chip->voi[i+4].eg_arm = data&0x10;
+
+ chip->EN_out16[1] = (data&1) ? ~0:0;
+ chip->EN_out8[1] = (data&2) ? ~0:0;
+ chip->EN_out4[1] = (data&4) ? ~0:0;
+ chip->EN_out2[1] = (data&8) ? ~0:0;
+
+ break;
+ }
+ }
+}
+
+
+
+#define VMIN 0
+#define VMAX 32768
+
+
+INLINE void EG_voices_advance(MSM5232 *chip)
+{
+ VOICE *voi = &chip->voi[0];
+ int samplerate = chip->rate;
+ int i;
+
+ i = 8;
+ do
+ {
+ switch(voi->eg_sect)
+ {
+ case 0: /* attack */
+
+ /* capacitor charge */
+ if (voi->eg < VMAX)
+ {
+ voi->counter -= (int)((VMAX - voi->eg) / voi->ar_rate);
+ if ( voi->counter <= 0 )
+ {
+ int n = -voi->counter / samplerate + 1;
+ voi->counter += n * samplerate;
+ if ( (voi->eg += n) > VMAX )
+ voi->eg = VMAX;
+ }
+ }
+
+ /* when ARM=0, EG switches to decay as soon as cap is charged to VT (EG inversion voltage; about 80% of MAX) */
+ if (!voi->eg_arm)
+ {
+ if(voi->eg >= VMAX * 80/100 )
+ {
+ voi->eg_sect = 1;
+ }
+ }
+ else
+ /* ARM=1 */
+ {
+ /* when ARM=1, EG stays at maximum until key off */
+ }
+
+ voi->egvol = voi->eg / 16; /*32768/16 = 2048 max*/
+
+ break;
+
+ case 1: /* decay */
+
+ /* capacitor discharge */
+ if (voi->eg > VMIN)
+ {
+ voi->counter -= (int)((voi->eg - VMIN) / voi->dr_rate);
+ if ( voi->counter <= 0 )
+ {
+ int n = -voi->counter / samplerate + 1;
+ voi->counter += n * samplerate;
+ if ( (voi->eg -= n) < VMIN )
+ voi->eg = VMIN;
+ }
+ }
+ else /* voi->eg <= VMIN */
+ {
+ voi->eg_sect =-1;
+ }
+
+ voi->egvol = voi->eg / 16; /*32768/16 = 2048 max*/
+
+ break;
+
+ case 2: /* release */
+
+ /* capacitor discharge */
+ if (voi->eg > VMIN)
+ {
+ voi->counter -= (int)((voi->eg - VMIN) / voi->rr_rate);
+ if ( voi->counter <= 0 )
+ {
+ int n = -voi->counter / samplerate + 1;
+ voi->counter += n * samplerate;
+ if ( (voi->eg -= n) < VMIN )
+ voi->eg = VMIN;
+ }
+ }
+ else /* voi->eg <= VMIN */
+ {
+ voi->eg_sect =-1;
+ }
+
+ voi->egvol = voi->eg / 16; /*32768/16 = 2048 max*/
+
+ break;
+
+ default:
+ break;
+ }
+
+ voi++;
+ i--;
+ } while (i>0);
+
+}
+
+static int o2,o4,o8,o16;
+
+INLINE void TG_group_advance(MSM5232 *chip, int groupidx)
+{
+ VOICE *voi = &chip->voi[groupidx*4];
+ int i;
+
+ o2 = o4 = o8 = o16 = 0;
+
+ i=4;
+ do
+ {
+ int out2, out4, out8, out16;
+
+ out2 = out4 = out8 = out16 = 0;
+
+ if (voi->mode==0) /* generate square tone */
+ {
+ int left = 1<<STEP_SH;
+ do
+ {
+ int nextevent = left;
+
+ if (voi->TG_cnt&voi->TG_out16) out16+=voi->TG_count;
+ if (voi->TG_cnt&voi->TG_out8) out8 +=voi->TG_count;
+ if (voi->TG_cnt&voi->TG_out4) out4 +=voi->TG_count;
+ if (voi->TG_cnt&voi->TG_out2) out2 +=voi->TG_count;
+
+ voi->TG_count -= nextevent;
+
+ while (voi->TG_count <= 0)
+ {
+ voi->TG_count += voi->TG_count_period;
+ voi->TG_cnt++;
+ if (voi->TG_cnt&voi->TG_out16) out16+=voi->TG_count_period;
+ if (voi->TG_cnt&voi->TG_out8 ) out8 +=voi->TG_count_period;
+ if (voi->TG_cnt&voi->TG_out4 ) out4 +=voi->TG_count_period;
+ if (voi->TG_cnt&voi->TG_out2 ) out2 +=voi->TG_count_period;
+
+ if (voi->TG_count > 0)
+ break;
+
+ voi->TG_count += voi->TG_count_period;
+ voi->TG_cnt++;
+ if (voi->TG_cnt&voi->TG_out16) out16+=voi->TG_count_period;
+ if (voi->TG_cnt&voi->TG_out8 ) out8 +=voi->TG_count_period;
+ if (voi->TG_cnt&voi->TG_out4 ) out4 +=voi->TG_count_period;
+ if (voi->TG_cnt&voi->TG_out2 ) out2 +=voi->TG_count_period;
+ }
+ if (voi->TG_cnt&voi->TG_out16) out16-=voi->TG_count;
+ if (voi->TG_cnt&voi->TG_out8 ) out8 -=voi->TG_count;
+ if (voi->TG_cnt&voi->TG_out4 ) out4 -=voi->TG_count;
+ if (voi->TG_cnt&voi->TG_out2 ) out2 -=voi->TG_count;
+
+ left -=nextevent;
+
+ }while (left>0);
+ }
+ else /* generate noise */
+ {
+ if (chip->noise_clocks&8) out16+=(1<<STEP_SH);
+ if (chip->noise_clocks&4) out8 +=(1<<STEP_SH);
+ if (chip->noise_clocks&2) out4 +=(1<<STEP_SH);
+ if (chip->noise_clocks&1) out2 +=(1<<STEP_SH);
+ }
+
+ /* calculate signed output */
+ o16 += ( (out16-(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH;
+ o8 += ( (out8 -(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH;
+ o4 += ( (out4 -(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH;
+ o2 += ( (out2 -(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH;
+ voi++;
+ i--;
+ }while (i>0);
+
+ /* cut off disabled output lines */
+ o16 &= chip->EN_out16[groupidx];
+ o8 &= chip->EN_out8 [groupidx];
+ o4 &= chip->EN_out4 [groupidx];
+ o2 &= chip->EN_out2 [groupidx];
+}
+
+
+/* macro saves feet data to mono file */
+#ifdef SAVE_SEPARATE_CHANNELS
+ #define SAVE_SINGLE_CHANNEL(j,val) \
+ { signed int pom= val; \
+ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \
+ fputc((unsigned short)pom&0xff,sample[j]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[j]); }
+#else
+ #define SAVE_SINGLE_CHANNEL(j,val)
+#endif
+
+/* first macro saves all 8 feet outputs to mixed (mono) file */
+/* second macro saves one group into left and the other in right channel */
+#if 1 /*MONO*/
+ #ifdef SAVE_SAMPLE
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = buf1[i] + buf2[i]; \
+ fputc((unsigned short)pom&0xff,sample[8]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[8]); \
+ }
+ #else
+ #define SAVE_ALL_CHANNELS
+ #endif
+#else /*STEREO*/
+ #ifdef SAVE_SAMPLE
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = buf1[i]; \
+ fputc((unsigned short)pom&0xff,sample[8]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[8]); \
+ pom = buf2[i]; \
+ fputc((unsigned short)pom&0xff,sample[8]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[8]); \
+ }
+ #else
+ #define SAVE_ALL_CHANNELS
+ #endif
+#endif
+
+
+void MSM5232_update_one(void *param, stream_sample_t **inputs, stream_sample_t** buffer, int samples)
+{
+ MSM5232 * chip = param;
+ stream_sample_t *buf1 = buffer[0];
+ stream_sample_t *buf2 = buffer[1];
+ int i;
+
+ for (i=0; i<samples; i++)
+ {
+ int out;
+
+ /* calculate all voices' envelopes */
+ EG_voices_advance(chip);
+
+ TG_group_advance(chip,0); /* calculate tones group 1 */
+ out = (o2+o4+o8+o16);
+ if (out>32767)
+ out = 32767;
+ else if (out<-32768)
+ out = -32768;
+ buf1[i] = out; /* should be 4 separate outputs */
+ SAVE_SINGLE_CHANNEL(0,o2)
+ SAVE_SINGLE_CHANNEL(1,o4)
+ SAVE_SINGLE_CHANNEL(2,o8)
+ SAVE_SINGLE_CHANNEL(3,o16)
+
+ TG_group_advance(chip,1); /* calculate tones group 2 */
+ out = (o2+o4+o8+o16);
+ if (out>32767)
+ out = 32767;
+ else if (out<-32768)
+ out = -32768;
+ buf2[i] = out; /* should be 4 separate outputs */
+ SAVE_SINGLE_CHANNEL(4,o2)
+ SAVE_SINGLE_CHANNEL(5,o4)
+ SAVE_SINGLE_CHANNEL(6,o8)
+ SAVE_SINGLE_CHANNEL(7,o16)
+
+ SAVE_ALL_CHANNELS
+
+ /* update noise generator */
+ {
+ int cnt = (chip->noise_cnt+=chip->noise_step) >> STEP_SH;
+ chip->noise_cnt &= ((1<<STEP_SH)-1);
+ while (cnt > 0)
+ {
+ int tmp = chip->noise_rng & (1<<16); /* store current level */
+
+ if (chip->noise_rng&1)
+ chip->noise_rng ^= 0x28000;
+ chip->noise_rng>>=1;
+
+ if ( (chip->noise_rng & (1<<16)) != tmp ) /* level change detect */
+ chip->noise_clocks++;
+
+ cnt--;
+ }
+ }
+ }
+}
+
+
+
+/* MAME Interface */
+
+static void *msm5232_start(int sndindex, int clock, const void *config)
+{
+ const struct MSM5232interface *intf = config;
+ int rate = clock/16;
+ MSM5232 *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ msm5232_init(chip, intf, clock, rate);
+
+ chip->stream = stream_create(0,2,rate,chip,MSM5232_update_one);
+ return chip;
+}
+
+static void msm5232_stop (void *chip)
+{
+ msm5232_shutdown(chip);
+}
+
+WRITE8_HANDLER ( MSM5232_0_w )
+{
+ MSM5232 *chip = sndti_token(SOUND_MSM5232, 0);
+ stream_update (chip->stream);
+ msm5232_write(chip, offset, data);
+}
+
+WRITE8_HANDLER ( MSM5232_1_w )
+{
+ MSM5232 *chip = sndti_token(SOUND_MSM5232, 1);
+ stream_update (chip->stream);
+ msm5232_write(chip, offset, data);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void msm5232_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void msm5232_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = msm5232_set_info; break;
+ case SNDINFO_PTR_START: info->start = msm5232_start; break;
+ case SNDINFO_PTR_STOP: info->stop = msm5232_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = msm5232_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "MSM5232"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "ADPCM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/msm5232.h b/src/emu/sound/msm5232.h
new file mode 100644
index 00000000000..a6a180d1642
--- /dev/null
+++ b/src/emu/sound/msm5232.h
@@ -0,0 +1,12 @@
+#ifndef _H_MSM5232_
+#define _H_MSM5232_
+
+struct MSM5232interface
+{
+ double capacity[8]; /* in Farads, capacitors connected to pins: 24,25,26,27 and 37,38,39,40 */
+};
+
+WRITE8_HANDLER( MSM5232_0_w );
+WRITE8_HANDLER( MSM5232_1_w );
+
+#endif
diff --git a/src/emu/sound/multipcm.c b/src/emu/sound/multipcm.c
new file mode 100644
index 00000000000..414d7681a0f
--- /dev/null
+++ b/src/emu/sound/multipcm.c
@@ -0,0 +1,551 @@
+/*
+ * Sega System 32 Multi/Model 1 custom PCM chip (315-5560) emulation.
+ *
+ * by R. Belmont. Info from AMUSE, Hoot, and the YMF278B (OPL4).
+ * This chip is sort of a dry run for the PCM section of the YMF278B,
+ * and it has many obvious similarities to that chip.
+ *
+ * voice registers:
+ * 0: pan
+ * 1: sample to play (PCM chip uses table to figure out)
+ * 2: LSB of pitch
+ * 3: MSB of pitch
+ * 4: voice control: top bit = 1 for key on, 0 for key off
+ * 5: bit 0: loop, bits 1-7 = volume attenuate (0=max, 7f=min)
+ * 6: LFO (OutRunners engine, singing man in Daytona)
+ * 7: LFO
+ *
+ * The first sample ROM contains a variable length table with 12
+ * bytes per instrument/sample. The end of the table is marked
+ * by 12 bytes of 0xFF. This is very similar to the YMF278B.
+ *
+ * The first 3 bytes are the offset into the file (big endian).
+ * The next 2 are the loop start offset into the file (big endian)
+ * The next 2 are the 2's complement of the total sample size (big endian)
+ * The next byte is unknown.
+ * The next 3 are envelope attack / decay / release parameters (not yet emulated)
+ *
+ */
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "multipcm.h"
+
+#define MULTIPCM_CLOCKDIV (360.0)
+#define MULTIPCM_ONE (18)
+
+static int ctbl[] =
+{
+ 0, 1, 2, 3, 4, 5, 6 , -1, // voice number mapping
+ 7, 8, 9, 10,11,12,13, -1,
+ 14,15,16,17,18,19,20, -1,
+ 21,22,23,24,25,26,27, -1,
+};
+
+static int decaytbl[16] = // decay times
+{
+ 0, 300, 800, 1400,
+ 2100, 3000, 4000, 5200,
+ 6600, 8200, 10000, 12000,
+ 14500, 17500, 21000, 25000
+};
+
+
+// sample info struct
+typedef struct PCM_t
+{
+ INT32 st;
+ INT32 size;
+ INT32 loop;
+ UINT8 env[4];
+} PCMInfoT;
+
+// voice structure
+typedef struct Voice_t
+{
+ INT8 active; // active flag
+ INT8 loop; // loop flag
+ INT32 end; // length of sample
+ INT32 loopst; // loop start offset
+ INT32 pan; // panning
+ INT32 vol; // volume
+ INT8 *pSamp; // pointer to start of sample data
+
+ INT32 ptdelta; // pitch step
+ INT32 ptoffset; // fixed point offset
+ INT32 ptsum; // fixed point sum
+ INT32 relamt; // release amount
+ INT32 relcount; // release counter
+ INT8 relstage; // release stage
+} VoiceT;
+
+// chip structure
+typedef struct MultiPCM_t
+{
+ sound_stream * stream;
+
+ UINT8 registers[28][8]; // 8 registers per voice?
+ UINT32 bankL, bankR;
+
+ VoiceT Voices[28];
+ int curreg, curvoice;
+ INT8 *romptr;
+
+ long dlttbl[0x1001]; // pre-calculated pitch table
+ long voltbl[128]; // pre-calculated volume table
+ long pantbl[16]; // pre-calculated panning table
+
+ PCMInfoT samples[512];
+
+} MultiPCMT;
+
+static void MultiPCM_postload(void *param)
+{
+ MultiPCMT *mpcm = param;
+ int j;
+ for (j = 0; j < 28; j++)
+ {
+ int inum = mpcm->registers[j][1] | ((mpcm->registers[j][2]&0x1)<<8);
+ mpcm->Voices[j].pSamp = &mpcm->romptr[mpcm->samples[inum].st];
+ }
+}
+
+static void MultiPCM_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length )
+{
+ MultiPCMT *mpcm = param;
+ stream_sample_t *datap[2];
+ int i, j;
+ signed long lvol, rvol, mlvol, mrvol;
+ INT8 *pSamp;
+ long cnt, ptsum, ptoffset, ptdelta, end;
+ VoiceT *vptr;
+ float decTemp;
+ char relstage;
+ int relcount, relamt;
+ float invrelamt;
+
+ datap[0] = buffer[0];
+ datap[1] = buffer[1];
+
+ memset(datap[0], 0, sizeof(*datap[0])*length);
+ memset(datap[1], 0, sizeof(*datap[1])*length);
+
+ for (j = 0; j < 28; j++)
+ {
+ vptr = &mpcm->Voices[j];
+
+ // is voice playing?
+ if ((vptr->active) || (vptr->relstage))
+ { // only calculate volume once per voice per update cycle
+ rvol = mpcm->pantbl[vptr->pan];
+ lvol = mpcm->pantbl[15-vptr->pan];
+
+ mrvol = rvol = (rvol * vptr->vol)>>8;
+ mlvol = lvol = (lvol * vptr->vol)>>8;
+
+ decTemp = 1.0f;
+
+ // copy our "working set" into locals
+ ptsum = vptr->ptsum;
+ ptoffset = vptr->ptoffset;
+ ptdelta = vptr->ptdelta;
+ end = vptr->end;
+ pSamp = vptr->pSamp;
+ relstage = vptr->relstage;
+ relcount = vptr->relcount;
+ relamt = vptr->relamt;
+ invrelamt = 1.f / (float)relamt;
+
+ for (i = 0; i < length; i++)
+ {
+ cnt = ptsum >> MULTIPCM_ONE;
+ ptsum &= ((1<<MULTIPCM_ONE)-1);
+ ptoffset += cnt;
+
+ if (ptoffset >= end)
+ {
+ if (vptr->loop)
+ {
+ ptoffset = vptr->loopst;
+ }
+ else
+ {
+ vptr->active = 0;
+ break;
+ }
+ }
+
+ if (relstage)
+ {
+ relcount++;
+ if (relcount > relamt)
+ {
+ relstage = 0;
+ vptr->relstage = 0;
+ break;
+ }
+
+ decTemp = 1.0f - (relcount * invrelamt);
+
+ lvol = mlvol * decTemp;
+ rvol = mrvol * decTemp;
+ }
+
+ ptsum += ptdelta;
+
+ datap[0][i] += ((pSamp[ptoffset] * lvol)>>2);
+ datap[1][i] += ((pSamp[ptoffset] * rvol)>>2);
+ }
+
+ // copy back the working values we need to keep
+ vptr->ptsum = ptsum;
+ vptr->ptoffset = ptoffset;
+ vptr->relcount = relcount;
+ }
+ }
+}
+
+static void *multipcm_start(int sndindex, int clock, const void *config)
+{
+ int i;
+ double unity = (double)(1<<MULTIPCM_ONE);
+ UINT8* phdr;
+ long nowadrs;
+ long idx;
+ const struct MultiPCM_interface *intf = config;
+ MultiPCMT *mpcm;
+
+ // make volume table
+ double max=255.0;
+ double db=(48.0/128);
+
+ mpcm = auto_malloc(sizeof(*mpcm));
+ memset(mpcm, 0, sizeof(*mpcm));
+
+ for (i = 0; i < 128; i++)
+ {
+ mpcm->voltbl[i]=max;
+ max /= pow(10.0,db/20.0);
+ }
+ mpcm->voltbl[127]=0;
+
+ // make pan table
+ for(i=0; i<16; i++)
+ {
+ mpcm->pantbl[i]=(long)( (255/sqrt(15)) * sqrt(i));
+ }
+
+ mpcm->curreg = mpcm->curvoice = 0;
+
+ mpcm->romptr = (INT8 *)memory_region(intf->region);
+
+ for (i = 0; i < 28; i++)
+ {
+ mpcm->Voices[i].active = 0;
+ mpcm->Voices[i].ptsum = 0;
+ mpcm->Voices[i].ptoffset = 0;
+ mpcm->Voices[i].loop = 0;
+ mpcm->Voices[i].loopst = 0;
+ mpcm->Voices[i].end = 0;
+ mpcm->Voices[i].pan = 0;
+ mpcm->Voices[i].vol = 0;
+ mpcm->Voices[i].relamt = 0;
+ mpcm->Voices[i].relcount = 0;
+ mpcm->Voices[i].relstage = 0;
+ }
+
+ mpcm->stream = stream_create(0, 2, clock / MULTIPCM_CLOCKDIV, mpcm, MultiPCM_update);
+
+ // make pitch delta table (1 octave)
+ for(i=0; i<0x1001; i++)
+ {
+ mpcm->dlttbl[i] = (long)(unity * (1.0 + ((double)i / 4096.0)));
+ }
+
+ // precalculate the PCM data for a small speedup
+ phdr = (UINT8 *)mpcm->romptr;
+ for(i = 0; i < 511; i++)
+ {
+ idx = i*12;
+ nowadrs = (phdr[idx + 0]<<16) + (phdr[idx + 1]<<8) + (phdr[idx + 2]);
+
+ if((nowadrs == 0)||(nowadrs==0xffffff))
+ { // invalid entry
+ mpcm->samples[i].st=0;
+ mpcm->samples[i].size=0;
+ }
+ else
+ {
+ mpcm->samples[i].st = nowadrs;
+ mpcm->samples[i].loop = (phdr[idx + 3]<<8) + (phdr[idx + 4]);
+ mpcm->samples[i].size = 0xffff - ((phdr[idx + 5]<<8) + (phdr[idx + 6]));
+ mpcm->samples[i].env[0] = phdr[idx + 8];
+ mpcm->samples[i].env[1] = phdr[idx + 9];
+ mpcm->samples[i].env[2] = phdr[idx + 10];
+ }
+ }
+
+ /* set up the save state info */
+ {
+ int v;
+ char mname[20];
+
+ sprintf(mname, "MultiPCM %d", sndindex);
+
+ state_save_register_item(mname, sndindex, mpcm->bankL);
+ state_save_register_item(mname, sndindex, mpcm->bankR);
+
+ state_save_register_item_2d_array(mname, sndindex, mpcm->registers);
+
+ for (v = 0; v < 28; v++)
+ {
+ char mname2[32];
+
+ sprintf(mname2, "MultiPCM %d v %d", sndindex, v);
+
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].active);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].loop);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].end);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].loopst);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].pan);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].vol);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].ptdelta);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].ptoffset);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].ptsum);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].relamt);
+ state_save_register_item(mname2, sndindex, mpcm->Voices[v].relstage);
+ }
+
+ state_save_register_item(mname, sndindex, mpcm->curreg);
+ state_save_register_item(mname, sndindex, mpcm->curvoice);
+ }
+
+ state_save_register_func_postload_ptr(MultiPCM_postload, mpcm);
+
+ return mpcm;
+}
+
+/* write register */
+static void MultiPCM_reg_w(int chip, int offset, UINT8 data)
+{
+ int ppp, inum;
+ signed short pitch;
+ long pt_abs, pt_oct, st;
+ int vnum;
+ MultiPCMT *cptr = sndti_token(SOUND_MULTIPCM, chip);
+ VoiceT *vptr;
+
+ stream_update(cptr->stream);
+
+ switch (offset)
+ {
+ case 0: // data / status
+ if ((cptr->curvoice > 27) || (cptr->curvoice < 0))
+ {
+ //logerror("MPCM: unknown write to voice > 28\n");
+ return;
+ }
+
+ vnum = cptr->curvoice;
+ cptr->registers[vnum][cptr->curreg] = data;
+
+ vptr = &cptr->Voices[vnum];
+
+ switch (cptr->curreg)
+ {
+ case 0: // panning
+ ppp = (cptr->registers[vnum][0]>>4)&0xf;
+ if (ppp >= 8)
+ {
+ ppp = -(16-ppp);
+ }
+ vptr->pan = ppp + 8;
+ break;
+
+ case 1: // sample
+ break;
+
+ case 2: // pitch LSB
+ // MUST fall through to update pitch also!
+ case 3: // pitch MSB
+ // compute frequency divisor
+ pitch = (cptr->registers[vnum][3]<<8) + cptr->registers[vnum][2];
+ pt_abs = (double)abs(pitch);
+ pt_oct = pt_abs>>12;
+ if(pitch < 0)
+ {
+ vptr->ptdelta = cptr->dlttbl[0x1000 - (pt_abs&0xfff)];
+ vptr->ptdelta >>= (pt_oct+1);
+ }
+ else
+ {
+ vptr->ptdelta = cptr->dlttbl[pt_abs&0xfff];
+ vptr->ptdelta <<= pt_oct;
+ }
+ break;
+
+ case 4: // key on/off
+ if (data & 0x80)
+ {
+ inum = cptr->registers[vnum][1];
+
+ // calc decay amount
+ vptr->relamt = decaytbl[(0x0f - cptr->samples[inum].env[2])];
+
+ // compute start and end pointers
+ st = cptr->samples[inum].st;
+
+ // perform banking
+ if (st >= 0x100000)
+ {
+/* logerror("MPCM: key on chip %d voice %d\n", chip, vnum);
+ logerror("regs %02x %02x %02x %02x %02x %02x %02x %02x\n", cptr->registers[vnum][0],
+ cptr->registers[vnum][1],cptr->registers[vnum][2],cptr->registers[vnum][3],
+ cptr->registers[vnum][4],cptr->registers[vnum][5],
+ cptr->registers[vnum][6],cptr->registers[vnum][7]);*/
+
+ if (vptr->pan < 8)
+ {
+ st = (st & 0xfffff) + cptr->bankL;
+ }
+ else
+ {
+ st = (st & 0xfffff) + cptr->bankR;
+ }
+ }
+
+ vptr->pSamp = &cptr->romptr[st];
+ vptr->end = cptr->samples[inum].size;
+ vptr->loopst = cptr->samples[inum].loop;
+
+ vptr->ptoffset = 0;
+ vptr->ptsum = 0;
+ vptr->active = 1;
+ vptr->relstage = 0;
+ }
+ else
+ {
+// logerror("MPCM: key off chip %d voice %d\n", chip, vnum);
+ vptr->active = 0;
+ vptr->relcount = 0;
+ if ((vptr->loop) && (vptr->pSamp))
+ {
+ vptr->relstage = 1;
+ }
+ }
+ break;
+
+ case 5: // volume/loop
+ vptr->vol = cptr->voltbl[(cptr->registers[vnum][5]>>1)&0x7f];
+ vptr->loop = (cptr->registers[vnum][5]&0x1) || !vptr->loopst;
+ break;
+
+ case 6: // ??? LFO? reverb?
+ case 7:
+// logerror("write %x to reg %d, voice %d\n", data, cptr->curreg, vnum);
+ break;
+
+ default:
+// logerror("write %x to reg %d, voice %d\n", data, cptr->curreg, vnum);
+ break;
+ }
+ break;
+
+ case 1: // voice select
+ cptr->curvoice = ctbl[data&0x1f];
+ break;
+
+ case 2: // register select
+ cptr->curreg = data;
+ if (cptr->curreg > 7)
+ cptr->curreg = 7;
+ break;
+ }
+}
+
+/* read register */
+
+static UINT8 MultiPCM_reg_r(int chip, int offset)
+{
+ UINT8 retval = 0;
+
+ switch (offset)
+ {
+ case 0:
+ retval = 0; // always return READY
+ break;
+
+ default:
+ //logerror("read from unknown MPCM register %ld\n", offset);
+ break;
+ }
+
+ return retval;
+}
+
+/* MAME/M1 access functions */
+
+READ8_HANDLER( MultiPCM_reg_0_r )
+{
+ return MultiPCM_reg_r(0, offset);
+}
+
+WRITE8_HANDLER( MultiPCM_reg_0_w )
+{
+ MultiPCM_reg_w(0, offset, data);
+}
+
+READ8_HANDLER( MultiPCM_reg_1_r )
+{
+ return MultiPCM_reg_r(1, offset);
+}
+
+WRITE8_HANDLER( MultiPCM_reg_1_w )
+{
+ MultiPCM_reg_w(1, offset, data);
+}
+
+void multipcm_set_bank(int which, UINT32 leftoffs, UINT32 rightoffs)
+{
+ struct MultiPCM_t *mpcm = sndti_token(SOUND_MULTIPCM, which);
+ mpcm->bankL = leftoffs;
+ mpcm->bankR = rightoffs;
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void multipcm_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void multipcm_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = multipcm_set_info; break;
+ case SNDINFO_PTR_START: info->start = multipcm_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "MultiPCM"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Sega custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/multipcm.h b/src/emu/sound/multipcm.h
new file mode 100644
index 00000000000..6431406686e
--- /dev/null
+++ b/src/emu/sound/multipcm.h
@@ -0,0 +1,17 @@
+#ifndef __MultiPCM_H__
+#define __MultiPCM_H__
+
+struct MultiPCM_interface
+{
+ int region;
+};
+
+
+WRITE8_HANDLER( MultiPCM_reg_0_w );
+READ8_HANDLER( MultiPCM_reg_0_r);
+WRITE8_HANDLER( MultiPCM_reg_1_w );
+READ8_HANDLER( MultiPCM_reg_1_r);
+
+void multipcm_set_bank(int which, UINT32 leftoffs, UINT32 rightoffs);
+
+#endif
diff --git a/src/emu/sound/n63701x.c b/src/emu/sound/n63701x.c
new file mode 100644
index 00000000000..e3932effc8d
--- /dev/null
+++ b/src/emu/sound/n63701x.c
@@ -0,0 +1,193 @@
+/***************************************************************************
+
+An Hitachi HD637A01X0 MCU programmed to act as a sample player.
+Used by some Namco System 86 games.
+
+The MCU has internal ROM which hasn't been dumped, so here we simulate its
+simple functions.
+
+The chip can address ROM space up to 8 block of 0x10000 bytes. At the beginning
+of each block there's a table listing the start offset of each sample.
+Samples are 8 bit unsigned, 0xff marks the end of the sample. 0x00 is used for
+silence compression: '00 nn' must be replaced by nn+1 times '80'.
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "n63701x.h"
+
+
+typedef struct
+{
+ int select;
+ int playing;
+ int base_addr;
+ int position;
+ int volume;
+ int silence_counter;
+} voice;
+
+struct namco_63701x
+{
+ voice voices[2];
+ sound_stream * stream; /* channel assigned by the mixer */
+ const struct namco_63701x_interface *intf; /* pointer to our config data */
+ UINT8 *rom; /* pointer to sample ROM */
+};
+
+
+/* volume control has three resistors: 22000, 10000 and 3300 Ohm.
+ 22000 is always enabled, the other two can be turned off.
+ Since 0x00 and 0xff samples have special meaning, the available range is
+ 0x01 to 0xfe, therefore 258 * (0x01 - 0x80) = 0x8002 just keeps us
+ inside 16 bits without overflowing.
+ */
+static const int vol_table[4] = { 26, 84, 200, 258 };
+
+
+static void namco_63701x_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct namco_63701x *chip = param;
+ int ch;
+
+ for (ch = 0;ch < 2;ch++)
+ {
+ stream_sample_t *buf = buffer[ch];
+ voice *v = &chip->voices[ch];
+
+ if (v->playing)
+ {
+ UINT8 *base = chip->rom + v->base_addr;
+ int pos = v->position;
+ int vol = vol_table[v->volume];
+ int p;
+
+ for (p = 0;p < length;p++)
+ {
+ if (v->silence_counter)
+ {
+ v->silence_counter--;
+ *(buf++) = 0;
+ }
+ else
+ {
+ int data = base[(pos++) & 0xffff];
+
+ if (data == 0xff) /* end of sample */
+ {
+ v->playing = 0;
+ break;
+ }
+ else if (data == 0x00) /* silence compression */
+ {
+ data = base[(pos++) & 0xffff];
+ v->silence_counter = data;
+ *(buf++) = 0;
+ }
+ else
+ {
+ *(buf++) = vol * (data - 0x80);
+ }
+ }
+ }
+
+ v->position = pos;
+ }
+ else
+ memset(buf, 0, length * sizeof(*buf));
+ }
+}
+
+
+static void *namco_63701x_start(int sndindex, int clock, const void *config)
+{
+ struct namco_63701x *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ chip->intf = config;
+ chip->rom = memory_region(chip->intf->region);
+
+ chip->stream = stream_create(0, 2, clock/1000, chip, namco_63701x_update);
+
+ return chip;
+}
+
+
+
+void namco_63701x_write(int offset, int data)
+{
+ struct namco_63701x *chip = sndti_token(SOUND_NAMCO_63701X, 0);
+ int ch = offset / 2;
+
+ if (offset & 1)
+ chip->voices[ch].select = data;
+ else
+ {
+ /*
+ should we stop the playing sample if voice_select[ch] == 0 ?
+ originally we were, but this makes us lose a sample in genpeitd,
+ after the continue counter reaches 0. Either we shouldn't stop
+ the sample, or genpeitd is returning to the title screen too soon.
+ */
+ if (chip->voices[ch].select & 0x1f)
+ {
+ int rom_offs;
+
+ /* update the streams */
+ stream_update(chip->stream);
+
+ chip->voices[ch].playing = 1;
+ chip->voices[ch].base_addr = 0x10000 * ((chip->voices[ch].select & 0xe0) >> 5);
+ rom_offs = chip->voices[ch].base_addr + 2 * ((chip->voices[ch].select & 0x1f) - 1);
+ chip->voices[ch].position = (chip->rom[rom_offs] << 8) + chip->rom[rom_offs+1];
+ /* bits 6-7 = volume */
+ chip->voices[ch].volume = data >> 6;
+ /* bits 0-5 = counter to indicate new sample start? we don't use them */
+
+ chip->voices[ch].silence_counter = 0;
+ }
+ }
+}
+
+
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void namco_63701x_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void namco_63701x_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = namco_63701x_set_info; break;
+ case SNDINFO_PTR_START: info->start = namco_63701x_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Namco 63701X"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Namco custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/n63701x.h b/src/emu/sound/n63701x.h
new file mode 100644
index 00000000000..9fe1a9e8c65
--- /dev/null
+++ b/src/emu/sound/n63701x.h
@@ -0,0 +1,12 @@
+#ifndef namco_63701x_h
+#define namco_63701x_h
+
+struct namco_63701x_interface
+{
+ int region; /* memory region; region MUST be 0x80000 bytes long */
+};
+
+void namco_63701x_write(int offset,int data);
+
+#endif
+
diff --git a/src/emu/sound/namco.c b/src/emu/sound/namco.c
new file mode 100644
index 00000000000..e7c5c3c6abb
--- /dev/null
+++ b/src/emu/sound/namco.c
@@ -0,0 +1,927 @@
+/***************************************************************************
+
+ NAMCO sound driver.
+
+ This driver handles the four known types of NAMCO wavetable sounds:
+
+ - 3-voice mono (PROM-based design: Pac-Man, Pengo, Dig Dug, etc)
+ - 8-voice quadrophonic (Pole Position 1, Pole Position 2)
+ - 8-voice mono (custom 15XX: Mappy, Dig Dug 2, etc)
+ - 8-voice stereo (System 1)
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "namco.h"
+
+
+/* 8 voices max */
+#define MAX_VOICES 8
+
+#define MAX_VOLUME 16
+
+/* quality parameter: internal sample rate is 192 KHz, output is 48 KHz */
+#define INTERNAL_RATE 192000
+
+/* 16 bits: sample bits of the stream buffer */
+/* 4 bits: volume */
+/* 4 bits: prom sample bits */
+#define MIXLEVEL (1 << (16 - 4 - 4))
+
+/* stream output level */
+#define OUTPUT_LEVEL(n) ((n) * MIXLEVEL / chip->num_voices)
+
+/* a position of waveform sample */
+#define WAVEFORM_POSITION(n) (((n) >> chip->f_fracbits) & 0x1f)
+
+
+/* this structure defines the parameters for a channel */
+typedef struct
+{
+ UINT32 frequency;
+ UINT32 counter;
+ INT32 volume[2];
+ INT32 noise_sw;
+ INT32 noise_state;
+ INT32 noise_seed;
+ UINT32 noise_counter;
+ INT32 noise_hold;
+ INT32 waveform_select;
+} sound_channel;
+
+
+/* globals available to everyone */
+UINT8 *namco_soundregs;
+UINT8 *namco_wavedata;
+
+struct namco_sound
+{
+ /* data about the sound system */
+ sound_channel channel_list[MAX_VOICES];
+ sound_channel *last_channel;
+
+ /* global sound parameters */
+ int wave_size;
+ INT32 num_voices;
+ INT32 sound_enable;
+ sound_stream * stream;
+ int namco_clock;
+ int sample_rate;
+ int f_fracbits;
+ int stereo;
+
+ /* decoded waveform table */
+ INT16 *waveform[MAX_VOLUME];
+};
+
+
+/* update the decoded waveform data */
+static void update_namco_waveform(struct namco_sound *chip, int offset, UINT8 data)
+{
+ if (chip->wave_size == 1)
+ {
+ INT16 wdata;
+ int v;
+
+ /* use full byte, first 4 high bits, then low 4 bits */
+ for (v = 0; v < MAX_VOLUME; v++)
+ {
+ wdata = ((data >> 4) & 0x0f) - 8;
+ chip->waveform[v][offset * 2] = OUTPUT_LEVEL(wdata * v);
+ wdata = (data & 0x0f) - 8;
+ chip->waveform[v][offset * 2 + 1] = OUTPUT_LEVEL(wdata * v);
+ }
+ }
+ else
+ {
+ int v;
+
+ /* use only low 4 bits */
+ for (v = 0; v < MAX_VOLUME; v++)
+ chip->waveform[v][offset] = OUTPUT_LEVEL(((data & 0x0f) - 8) * v);
+ }
+}
+
+
+/* build the decoded waveform table */
+static int build_decoded_waveform(struct namco_sound *chip, int region)
+{
+ INT16 *p;
+ int size;
+ int offset;
+ int v;
+
+ /* 20pacgal has waves in RAM but old sound system */
+ if (region == -1 && chip->num_voices != 3)
+ {
+ chip->wave_size = 1;
+ size = 32 * 16; /* 32 samples, 16 waveforms */
+ }
+ else
+ {
+ chip->wave_size = 0;
+ size = 32 * 8; /* 32 samples, 8 waveforms */
+ }
+
+ p = auto_malloc(size * MAX_VOLUME * sizeof (INT16));
+
+ for (v = 0; v < MAX_VOLUME; v++)
+ {
+ chip->waveform[v] = p;
+ p += size;
+ }
+
+ if (region != -1)
+ namco_wavedata = memory_region(region);
+
+ /* We need waveform data. It fails if region is not specified. */
+ if (namco_wavedata)
+ {
+ for (offset = 0; offset < 256; offset++)
+ update_namco_waveform(chip, offset, namco_wavedata[offset]);
+ }
+
+ return 0;
+}
+
+
+/* generate sound by oversampling */
+INLINE UINT32 namco_update_one(struct namco_sound *chip, stream_sample_t *buffer, int length, const INT16 *wave, UINT32 counter, UINT32 freq)
+{
+ while (length-- > 0)
+ {
+ *buffer++ += wave[WAVEFORM_POSITION(counter)];
+ counter += freq;
+ }
+
+ return counter;
+}
+
+
+/* generate sound to the mix buffer in mono */
+static void namco_update_mono(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct namco_sound *chip = param;
+ stream_sample_t *buffer = _buffer[0];
+ sound_channel *voice;
+
+ /* zap the contents of the buffer */
+ memset(buffer, 0, length * sizeof(*buffer));
+
+ /* if no sound, we're done */
+ if (chip->sound_enable == 0)
+ return;
+
+ /* loop over each voice and add its contribution */
+ for (voice = chip->channel_list; voice < chip->last_channel; voice++)
+ {
+ stream_sample_t *mix = buffer;
+ int v = voice->volume[0];
+
+ if (voice->noise_sw)
+ {
+ int f = voice->frequency & 0xff;
+
+ /* only update if we have non-zero volume and frequency */
+ if (v && f)
+ {
+ int hold_time = 1 << (chip->f_fracbits - 16);
+ int hold = voice->noise_hold;
+ UINT32 delta = f << 4;
+ UINT32 c = voice->noise_counter;
+ INT16 noise_data = OUTPUT_LEVEL(0x07 * (v >> 1));
+ int i;
+
+ /* add our contribution */
+ for (i = 0; i < length; i++)
+ {
+ int cnt;
+
+ if (voice->noise_state)
+ *mix++ += noise_data;
+ else
+ *mix++ -= noise_data;
+
+ if (hold)
+ {
+ hold--;
+ continue;
+ }
+
+ hold = hold_time;
+
+ c += delta;
+ cnt = (c >> 12);
+ c &= (1 << 12) - 1;
+ for( ;cnt > 0; cnt--)
+ {
+ if ((voice->noise_seed + 1) & 2) voice->noise_state ^= 1;
+ if (voice->noise_seed & 1) voice->noise_seed ^= 0x28000;
+ voice->noise_seed >>= 1;
+ }
+ }
+
+ /* update the counter and hold time for this voice */
+ voice->noise_counter = c;
+ voice->noise_hold = hold;
+ }
+ }
+ else
+ {
+ /* only update if we have non-zero volume and frequency */
+ if (v && voice->frequency)
+ {
+ const INT16 *w = &chip->waveform[v][voice->waveform_select * 32];
+
+ /* generate sound into buffer and update the counter for this voice */
+ voice->counter = namco_update_one(chip, mix, length, w, voice->counter, voice->frequency);
+ }
+ }
+ }
+}
+
+
+/* generate sound to the mix buffer in stereo */
+static void namco_update_stereo(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct namco_sound *chip = param;
+ sound_channel *voice;
+
+ /* zap the contents of the buffers */
+ memset(buffer[0], 0, length * sizeof(*buffer[0]));
+ memset(buffer[1], 0, length * sizeof(*buffer[1]));
+
+ /* if no sound, we're done */
+ if (chip->sound_enable == 0)
+ return;
+
+ /* loop over each voice and add its contribution */
+ for (voice = chip->channel_list; voice < chip->last_channel; voice++)
+ {
+ stream_sample_t *lmix = buffer[0];
+ stream_sample_t *rmix = buffer[1];
+ int lv = voice->volume[0];
+ int rv = voice->volume[1];
+
+ if (voice->noise_sw)
+ {
+ int f = voice->frequency & 0xff;
+
+ /* only update if we have non-zero volume and frequency */
+ if ((lv || rv) && f)
+ {
+ int hold_time = 1 << (chip->f_fracbits - 16);
+ int hold = voice->noise_hold;
+ UINT32 delta = f << 4;
+ UINT32 c = voice->noise_counter;
+ INT16 l_noise_data = OUTPUT_LEVEL(0x07 * (lv >> 1));
+ INT16 r_noise_data = OUTPUT_LEVEL(0x07 * (rv >> 1));
+ int i;
+
+ /* add our contribution */
+ for (i = 0; i < length; i++)
+ {
+ int cnt;
+
+ if (voice->noise_state)
+ {
+ *lmix++ += l_noise_data;
+ *rmix++ += r_noise_data;
+ }
+ else
+ {
+ *lmix++ -= l_noise_data;
+ *rmix++ -= r_noise_data;
+ }
+
+ if (hold)
+ {
+ hold--;
+ continue;
+ }
+
+ hold = hold_time;
+
+ c += delta;
+ cnt = (c >> 12);
+ c &= (1 << 12) - 1;
+ for( ;cnt > 0; cnt--)
+ {
+ if ((voice->noise_seed + 1) & 2) voice->noise_state ^= 1;
+ if (voice->noise_seed & 1) voice->noise_seed ^= 0x28000;
+ voice->noise_seed >>= 1;
+ }
+ }
+
+ /* update the counter and hold time for this voice */
+ voice->noise_counter = c;
+ voice->noise_hold = hold;
+ }
+ }
+ else
+ {
+ /* only update if we have non-zero frequency */
+ if (voice->frequency)
+ {
+ /* save the counter for this voice */
+ UINT32 c = voice->counter;
+
+ /* only update if we have non-zero left volume */
+ if (lv)
+ {
+ const INT16 *lw = &chip->waveform[lv][voice->waveform_select * 32];
+
+ /* generate sound into the buffer */
+ c = namco_update_one(chip, lmix, length, lw, voice->counter, voice->frequency);
+ }
+
+ /* only update if we have non-zero right volume */
+ if (rv)
+ {
+ const INT16 *rw = &chip->waveform[rv][voice->waveform_select * 32];
+
+ /* generate sound into the buffer */
+ c = namco_update_one(chip, rmix, length, rw, voice->counter, voice->frequency);
+ }
+
+ /* update the counter for this voice */
+ voice->counter = c;
+ }
+ }
+ }
+}
+
+
+static void *namco_start(int sndindex, int clock, const void *config)
+{
+ sound_channel *voice;
+ const struct namco_interface *intf = config;
+ int clock_multiple;
+ struct namco_sound *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ /* extract globals from the interface */
+ chip->num_voices = intf->voices;
+ chip->last_channel = chip->channel_list + chip->num_voices;
+ chip->stereo = intf->stereo;
+
+ /* adjust internal clock */
+ chip->namco_clock = clock;
+ for (clock_multiple = 0; chip->namco_clock < INTERNAL_RATE; clock_multiple++)
+ chip->namco_clock *= 2;
+
+ chip->f_fracbits = clock_multiple + 15;
+
+ /* adjust output clock */
+ chip->sample_rate = chip->namco_clock;
+
+ logerror("Namco: freq fractional bits = %d: internal freq = %d, output freq = %d\n", chip->f_fracbits, chip->namco_clock, chip->sample_rate);
+
+ /* build the waveform table */
+ if (build_decoded_waveform(chip, intf->region))
+ return NULL;
+
+ /* get stream channels */
+ if (intf->stereo)
+ chip->stream = stream_create(0, 2, chip->sample_rate, chip, namco_update_stereo);
+ else
+ chip->stream = stream_create(0, 1, chip->sample_rate, chip, namco_update_mono);
+
+ /* start with sound enabled, many games don't have a sound enable register */
+ chip->sound_enable = 1;
+
+ /* register with the save state system */
+ state_save_register_item("namco", sndindex, chip->num_voices);
+ state_save_register_item("namco", sndindex, chip->sound_enable);
+ state_save_register_item_pointer("namco", sndindex, chip->waveform[0],
+ MAX_VOLUME * 32 * 8 * (1+chip->wave_size));
+
+ /* reset all the voices */
+ for (voice = chip->channel_list; voice < chip->last_channel; voice++)
+ {
+ int state_index = sndindex * MAX_VOICES + (voice - chip->channel_list);
+
+ voice->frequency = 0;
+ voice->volume[0] = voice->volume[1] = 0;
+ voice->waveform_select = 0;
+ voice->counter = 0;
+ voice->noise_sw = 0;
+ voice->noise_state = 0;
+ voice->noise_seed = 1;
+ voice->noise_counter = 0;
+ voice->noise_hold = 0;
+
+ /* register with the save state system */
+ state_save_register_item("namco", state_index, voice->frequency);
+ state_save_register_item("namco", state_index, voice->counter);
+ state_save_register_item_array("namco", state_index, voice->volume);
+ state_save_register_item("namco", state_index, voice->noise_sw);
+ state_save_register_item("namco", state_index, voice->noise_state);
+ state_save_register_item("namco", state_index, voice->noise_seed);
+ state_save_register_item("namco", state_index, voice->noise_hold);
+ state_save_register_item("namco", state_index, voice->noise_counter);
+ state_save_register_item("namco", state_index, voice->waveform_select);
+ }
+
+ return chip;
+}
+
+
+/********************************************************************************/
+
+/* pacman register map
+ 0x05: ch 0 waveform select
+ 0x0a: ch 1 waveform select
+ 0x0f: ch 2 waveform select
+
+ 0x10: ch 0 the first voice has extra frequency bits
+ 0x11-0x14: ch 0 frequency
+ 0x15: ch 0 volume
+
+ 0x16-0x19: ch 1 frequency
+ 0x1a: ch 1 volume
+
+ 0x1b-0x1e: ch 2 frequency
+ 0x1f: ch 2 volume
+*/
+
+WRITE8_HANDLER( pacman_sound_enable_w )
+{
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO, 0);
+ chip->sound_enable = data;
+}
+
+WRITE8_HANDLER( pacman_sound_w )
+{
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO, 0);
+ sound_channel *voice;
+ int ch;
+
+ data &= 0x0f;
+ if (namco_soundregs[offset] == data)
+ return;
+
+ /* update the streams */
+ stream_update(chip->stream);
+
+ /* set the register */
+ namco_soundregs[offset] = data;
+
+ if (offset < 0x10)
+ ch = (offset - 5) / 5;
+ else if (offset == 0x10)
+ ch = 0;
+ else
+ ch = (offset - 0x11) / 5;
+
+ if (ch >= chip->num_voices)
+ return;
+
+ /* recompute the voice parameters */
+ voice = chip->channel_list + ch;
+ switch (offset - ch * 5)
+ {
+ case 0x05:
+ voice->waveform_select = data & 7;
+ break;
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ /* the frequency has 20 bits */
+ /* the first voice has extra frequency bits */
+ voice->frequency = (ch == 0) ? namco_soundregs[0x10] : 0;
+ voice->frequency += (namco_soundregs[ch * 5 + 0x11] << 4);
+ voice->frequency += (namco_soundregs[ch * 5 + 0x12] << 8);
+ voice->frequency += (namco_soundregs[ch * 5 + 0x13] << 12);
+ voice->frequency += (namco_soundregs[ch * 5 + 0x14] << 16); /* always 0 */
+ break;
+
+ case 0x15:
+ voice->volume[0] = data;
+ break;
+ }
+}
+
+
+/********************************************************************************/
+
+/* polepos register map
+Note: even if there are 8 voices, the game doesn't use the first 2 because
+it select the 54XX/52XX outputs on those channels
+
+ 0x00-0x01 ch 0 frequency
+ 0x02 ch 0 xxxx---- GAIN 2 volume
+ 0x03 ch 0 xxxx---- GAIN 3 volume
+ ----xxxx GAIN 4 volume
+
+ 0x04-0x07 ch 1
+
+ .
+ .
+ .
+
+ 0x1c-0x1f ch 7
+
+ 0x23 ch 0 xxxx---- GAIN 1 volume
+ -----xxx waveform select
+ ----x-xx channel output select
+ 0-7 (all the same, shared with waveform select) = wave
+ 8 = CHANL1 (54XX pins 17-20)
+ 9 = CHANL2 (54XX pins 8-11)
+ A = CHANL3 (54XX pins 4-7)
+ B = CHANL4 (52XX)
+ 0x27 ch 1
+ 0x2b ch 2
+ 0x2f ch 3
+ 0x33 ch 4
+ 0x37 ch 5
+ 0x3b ch 6
+ 0x3f ch 7
+*/
+
+void polepos_sound_enable(int enable)
+{
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO, 0);
+ chip->sound_enable = enable;
+}
+
+WRITE8_HANDLER( polepos_sound_w )
+{
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO, 0);
+ sound_channel *voice;
+ int ch;
+
+ if (namco_soundregs[offset] == data)
+ return;
+
+ /* update the streams */
+ stream_update(chip->stream);
+
+ /* set the register */
+ namco_soundregs[offset] = data;
+
+ ch = (offset & 0x1f) / 4;
+
+ /* recompute the voice parameters */
+ voice = chip->channel_list + ch;
+ switch (offset & 0x23)
+ {
+ case 0x00:
+ case 0x01:
+ /* the frequency has 16 bits */
+ voice->frequency = namco_soundregs[ch * 4 + 0x00];
+ voice->frequency += namco_soundregs[ch * 4 + 0x01] << 8;
+ break;
+
+ case 0x23:
+ voice->waveform_select = data & 7;
+ /* fall through */
+ case 0x02:
+ case 0x03:
+ voice->volume[0] = voice->volume[1] = 0;
+ // front speakers ?
+ voice->volume[0] += namco_soundregs[ch * 4 + 0x03] >> 4;
+ voice->volume[1] += namco_soundregs[ch * 4 + 0x03] & 0x0f;
+ // rear speakers ?
+ voice->volume[0] += namco_soundregs[ch * 4 + 0x23] >> 4;
+ voice->volume[1] += namco_soundregs[ch * 4 + 0x02] >> 4;
+
+ voice->volume[0] /= 2;
+ voice->volume[1] /= 2;
+
+ /* if 54XX or 52XX selected, silence this voice */
+ if (namco_soundregs[ch * 4 + 0x23] & 8)
+ voice->volume[0] = voice->volume[1] = 0;
+ break;
+ }
+}
+
+
+/********************************************************************************/
+
+/* 15XX register map
+ 0x03 ch 0 volume
+ 0x04-0x05 ch 0 frequency
+ 0x06 ch 0 waveform select & frequency
+
+ 0x0b ch 1 volume
+ 0x0c-0x0d ch 1 frequency
+ 0x0e ch 1 waveform select & frequency
+
+ .
+ .
+ .
+
+ 0x3b ch 7 volume
+ 0x3c-0x3d ch 7 frequency
+ 0x3e ch 7 waveform select & frequency
+*/
+
+void mappy_sound_enable(int enable)
+{
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO_15XX, 0);
+ chip->sound_enable = enable;
+}
+
+WRITE8_HANDLER( namco_15xx_w )
+{
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO_15XX, 0);
+ sound_channel *voice;
+ int ch;
+
+ if (namco_soundregs[offset] == data)
+ return;
+
+ /* update the streams */
+ stream_update(chip->stream);
+
+ /* set the register */
+ namco_soundregs[offset] = data;
+
+ ch = offset / 8;
+ if (ch >= chip->num_voices)
+ return;
+
+ /* recompute the voice parameters */
+ voice = chip->channel_list + ch;
+ switch (offset - ch * 8)
+ {
+ case 0x03:
+ voice->volume[0] = data & 0x0f;
+ break;
+
+ case 0x06:
+ voice->waveform_select = (data >> 4) & 7;
+ case 0x04:
+ case 0x05:
+ /* the frequency has 20 bits */
+ voice->frequency = namco_soundregs[ch * 8 + 0x04];
+ voice->frequency += namco_soundregs[ch * 8 + 0x05] << 8;
+ voice->frequency += (namco_soundregs[ch * 8 + 0x06] & 15) << 16; /* high bits are from here */
+ break;
+ }
+}
+
+
+/********************************************************************************/
+
+/* namcos1 register map
+ 0x00 ch 0 left volume
+ 0x01 ch 0 waveform select & frequency
+ 0x02-0x03 ch 0 frequency
+ 0x04 ch 0 right volume AND
+ 0x04 ch 1 noise sw
+
+ 0x08 ch 1 left volume
+ 0x09 ch 1 waveform select & frequency
+ 0x0a-0x0b ch 1 frequency
+ 0x0c ch 1 right volume AND
+ 0x0c ch 2 noise sw
+
+ .
+ .
+ .
+
+ 0x38 ch 7 left volume
+ 0x39 ch 7 waveform select & frequency
+ 0x3a-0x3b ch 7 frequency
+ 0x3c ch 7 right volume AND
+ 0x3c ch 0 noise sw
+*/
+
+static WRITE8_HANDLER( namcos1_sound_w )
+{
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO_CUS30, 0);
+ sound_channel *voice;
+ int ch;
+ int nssw;
+
+
+ /* verify the offset */
+ if (offset > 63)
+ {
+ logerror("NAMCOS1 sound: Attempting to write past the 64 registers segment\n");
+ return;
+ }
+
+ namco_soundregs = namco_wavedata + 0x100;
+
+ if (namco_soundregs[offset] == data)
+ return;
+
+ /* update the streams */
+ stream_update(chip->stream);
+
+ /* set the register */
+ namco_soundregs[offset] = data;
+
+ ch = offset / 8;
+ if (ch >= chip->num_voices)
+ return;
+
+ /* recompute the voice parameters */
+ voice = chip->channel_list + ch;
+ switch (offset - ch * 8)
+ {
+ case 0x00:
+ voice->volume[0] = data & 0x0f;
+ break;
+
+ case 0x01:
+ voice->waveform_select = (data >> 4) & 15;
+ case 0x02:
+ case 0x03:
+ /* the frequency has 20 bits */
+ voice->frequency = (namco_soundregs[ch * 8 + 0x01] & 15) << 16; /* high bits are from here */
+ voice->frequency += namco_soundregs[ch * 8 + 0x02] << 8;
+ voice->frequency += namco_soundregs[ch * 8 + 0x03];
+ break;
+
+ case 0x04:
+ voice->volume[1] = data & 0x0f;
+
+ nssw = ((data & 0x80) >> 7);
+ if (++voice == chip->last_channel)
+ voice = chip->channel_list;
+ voice->noise_sw = nssw;
+ break;
+ }
+}
+
+WRITE8_HANDLER( namcos1_cus30_w )
+{
+ if (offset < 0x100)
+ {
+ if (namco_wavedata[offset] != data)
+ {
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO_CUS30, 0);
+ /* update the streams */
+ stream_update(chip->stream);
+
+ namco_wavedata[offset] = data;
+
+ /* update the decoded waveform table */
+ update_namco_waveform(chip, offset, data);
+ }
+ }
+ else if (offset < 0x140)
+ namcos1_sound_w(offset - 0x100,data);
+ else
+ namco_wavedata[offset] = data;
+}
+
+READ8_HANDLER( namcos1_cus30_r )
+{
+ return namco_wavedata[offset];
+}
+
+WRITE8_HANDLER( _20pacgal_wavedata_w )
+{
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO, 0);
+
+ if (namco_wavedata[offset] != data)
+ {
+ /* update the streams */
+ stream_update(chip->stream);
+
+ namco_wavedata[offset] = data;
+
+ /* update the decoded waveform table */
+ update_namco_waveform(chip, offset, data);
+ }
+}
+
+/********************************************************************************/
+
+WRITE8_HANDLER( snkwave_w )
+{
+ struct namco_sound *chip = sndti_token(SOUND_NAMCO, 0);
+ static int freq0 = 0xff;
+ sound_channel *voice = chip->channel_list;
+ if( offset==0 ) freq0 = data;
+ if( offset==1 )
+ {
+ stream_update(chip->stream);
+ if( data==0xff || freq0==0 )
+ {
+ voice->volume[0] = 0x0;
+ }
+ else
+ {
+ voice->volume[0] = 0x8;
+ voice->frequency = (data<<16)/freq0;
+ }
+ }
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void namco_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void namco_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = namco_set_info; break;
+ case SNDINFO_PTR_START: info->start = namco_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Namco"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Namco custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void namco_15xx_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void namco_15xx_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = namco_15xx_set_info; break;
+ case SNDINFO_PTR_START: info->start = namco_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Namco 15XX"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Namco custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void namco_cus30_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void namco_cus30_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = namco_cus30_set_info; break;
+ case SNDINFO_PTR_START: info->start = namco_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Namco CUS30"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Namco custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/namco.h b/src/emu/sound/namco.h
new file mode 100644
index 00000000000..f8eecf7a013
--- /dev/null
+++ b/src/emu/sound/namco.h
@@ -0,0 +1,32 @@
+#ifndef namco_h
+#define namco_h
+
+struct namco_interface
+{
+ int voices; /* number of voices */
+ int region; /* memory region; -1 to use RAM (pointed to by namco_wavedata) */
+ int stereo; /* set to 1 to indicate stereo (e.g., System 1) */
+};
+
+WRITE8_HANDLER( pacman_sound_enable_w );
+WRITE8_HANDLER( pacman_sound_w );
+
+void polepos_sound_enable(int enable);
+WRITE8_HANDLER( polepos_sound_w );
+
+void mappy_sound_enable(int enable);
+WRITE8_HANDLER( namco_15xx_w );
+
+WRITE8_HANDLER( namcos1_cus30_w ); /* wavedata + sound registers + RAM */
+READ8_HANDLER( namcos1_cus30_r );
+
+WRITE8_HANDLER( _20pacgal_wavedata_w );
+
+extern UINT8 *namco_soundregs;
+extern UINT8 *namco_wavedata;
+
+#define pacman_soundregs namco_soundregs
+#define polepos_soundregs namco_soundregs
+
+#endif
+
diff --git a/src/emu/sound/namco52.c b/src/emu/sound/namco52.c
new file mode 100644
index 00000000000..9d0013753ee
--- /dev/null
+++ b/src/emu/sound/namco52.c
@@ -0,0 +1,228 @@
+/***************************************************************************
+
+Namco 52XX
+
+This instance of the Fujitsu MB8852 MCU is programmed to act as a sample player.
+It is used by just two games: Bosconian and Pole Position.
+
+A0-A15 = address to read from sample ROMs
+D0-D7 = data freom sample ROMs
+CMD = command from CPU (sample to play, 0 = none)
+OUT = sound output
+
+ +------+
+ EXTAL|1 42|Vcc
+ XTAL|2 41|CMD3
+/RESET|3 40|CMD2
+ /IRQ|4 39|CMD1
+ n.c.|5 38|CMD0
+ [2] |6 37|A7
+ n.c.|7 36|A6
+ [1] |8 35|A5
+ OUT0|9 34|A4
+ OUT1|10 33|A3
+ OUT2|11 32|A2
+ OUT3|12 31|A1
+ A8|13 30|A0
+ A9|14 29|D7
+ A10|15 28|D6
+ A11|16 27|D5
+[3]A12|17 26|D4
+[3]A13|18 25|D3
+[3]A14|19 24|D2
+[3]A15|20 23|D1
+ GND|21 22|D0
+ +------+
+
+[1] in polepos, GND; in bosco, 4kHz output from a 555 timer
+[2] in polepos, +5V; in bosco, GND
+[3] in polepos, these are true address lines, in bosco they are chip select lines
+ (each one select one of the four ROM chips). Behaviour related to [2]?
+
+TODO:
+- the purpose of the 555 timer in bosco is unknown; maybe modulate the output?
+Jan 12, 2005. The 555 is probably an external playback frequency.
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "filter.h"
+#include "namco52.h"
+
+
+struct namco_52xx
+{
+ const struct namco_52xx_interface *intf; /* pointer to our config data */
+ UINT8 *rom; /* pointer to sample ROM */
+ UINT32 rom_len;
+ sound_stream * stream; /* the output stream */
+ double n52_pb_cycle; /* playback clock time based on machine sample rate */
+ double n52_step; /* playback clock step based on machine sample rate */
+ /* n52_pb_cycle is incremented by n52_step every machine-sample.
+ * At every integer value of n52_pb_cycle the next 4bit value is used. */
+ INT32 n52_start; /* current effect start position in the ROM */
+ INT32 n52_end; /* current effect end position in the ROM */
+ INT32 n52_length; /* # of 4bit samples in current effect */
+ INT32 n52_pos; /* current 4bit sample of effect */
+ filter2_context n52_hp_filter;
+ filter2_context n52_lp_filter;
+};
+
+static void namco_52xx_reset(void *_chip);
+
+
+static void namco_52xx_stream_update_one(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct namco_52xx *chip = param;
+ int i, rom_pos, whole_pb_cycles, buf;
+ stream_sample_t *buffer = _buffer[0];
+
+ if (chip->n52_start >= chip->n52_end)
+ {
+ memset(buffer, 0, length * sizeof(*buffer));
+ return;
+ }
+
+ for (i = 0; i < length; i++)
+ {
+ chip->n52_pb_cycle += chip->n52_step;
+ if (chip->n52_pb_cycle >= 1)
+ {
+ whole_pb_cycles = (int)chip->n52_pb_cycle;
+ chip->n52_pos += whole_pb_cycles;
+ chip->n52_pb_cycle -= whole_pb_cycles;
+ }
+
+ if (chip->n52_pos > chip->n52_length)
+ {
+ /* sample done */
+ memset(&buffer[i], 0, (length - i) * sizeof(INT16));
+ i = length;
+ namco_52xx_reset(chip);
+ }
+ else
+ {
+ /* filter and fill the buffer */
+ rom_pos = chip->n52_start + (chip->n52_pos >> 1);
+ /* get the 4bit sample from rom and shift to +7/-8 value */
+ chip->n52_hp_filter.x0 = (((chip->n52_pos & 1) ? chip->rom[rom_pos] >> 4 : chip->rom[rom_pos]) & 0x0f) - 0x08;
+ filter2_step(&chip->n52_hp_filter);
+ chip->n52_lp_filter.x0 = chip->n52_hp_filter.y0;
+ filter2_step(&chip->n52_lp_filter);
+ /* convert 4bit filtered to 16bit allowing room for filter gain */
+ buf = (int)(chip->n52_lp_filter.y0 * 0x0fff);
+ if (buf > 32767) buf = 32767;
+ if (buf < -32768) buf = -32768;
+ buffer[i] = buf;
+ }
+ }
+}
+
+
+static void namco_52xx_reset(void *_chip)
+{
+ struct namco_52xx *chip = _chip;
+ chip->n52_pb_cycle = chip->n52_start = chip->n52_end = chip->n52_length = chip->n52_pos = 0;
+
+ filter2_reset(&chip->n52_hp_filter);
+ filter2_reset(&chip->n52_lp_filter);
+}
+
+static void *namco_52xx_start(int sndindex, int clock, const void *config)
+{
+ struct namco_52xx *chip;
+ int rate = clock/32;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ chip->intf = config;
+ chip->rom = memory_region(chip->intf->region);
+ chip->rom_len = memory_region_length(chip->intf->region);
+
+ if (chip->intf->play_rate == 0)
+ {
+ /* If play clock is 0 (grounded) then default to internal clock */
+ chip->n52_step = (double)clock / 384 / rate;
+ }
+ else
+ {
+ chip->n52_step = chip->intf->play_rate / rate;
+ }
+ filter2_setup(FILTER_HIGHPASS, chip->intf->hp_filt_fc, Q_TO_DAMP(chip->intf->hp_filt_q), 1, &chip->n52_hp_filter);
+ filter2_setup(FILTER_LOWPASS, chip->intf->lp_filt_fc, Q_TO_DAMP(chip->intf->lp_filt_q), chip->intf->filt_gain, &chip->n52_lp_filter);
+
+
+ chip->stream = stream_create(0, 1, rate, chip, namco_52xx_stream_update_one);
+
+ namco_52xx_reset(chip);
+
+ state_save_register_item("namco52xx", sndindex, chip->n52_pb_cycle);
+ state_save_register_item("namco52xx", sndindex, chip->n52_step);
+ state_save_register_item("namco52xx", sndindex, chip->n52_start);
+ state_save_register_item("namco52xx", sndindex, chip->n52_end);
+ state_save_register_item("namco52xx", sndindex, chip->n52_length);
+ state_save_register_item("namco52xx", sndindex, chip->n52_pos);
+
+ return chip;
+}
+
+
+void namcoio_52XX_write(int data)
+{
+ struct namco_52xx *chip = sndti_token(SOUND_NAMCO_52XX, 0);
+ data &= 0x0f;
+
+ if (data != 0)
+ {
+ stream_update(chip->stream);
+
+ chip->n52_start = chip->rom[data-1] + (chip->rom[data-1+0x10] << 8);
+ chip->n52_end = chip->rom[data] + (chip->rom[data+0x10] << 8);
+
+ if (chip->n52_end >= chip->rom_len)
+ chip->n52_end = chip->rom_len;
+
+ chip->n52_length = (chip->n52_end - chip->n52_start) * 2;
+ chip->n52_pos = 0;
+ chip->n52_pb_cycle= 0;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void namco_52xx_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void namco_52xx_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = namco_52xx_set_info; break;
+ case SNDINFO_PTR_START: info->start = namco_52xx_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = namco_52xx_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Namco 52XX"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Namco custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/namco52.h b/src/emu/sound/namco52.h
new file mode 100644
index 00000000000..312312dedbc
--- /dev/null
+++ b/src/emu/sound/namco52.h
@@ -0,0 +1,32 @@
+#ifndef namco52_h
+#define namco52_h
+
+/* While a little confusing, this interface uses 2 gains.
+ *
+ * "mixing_level" is the relative level of the signal
+ * compared to other effects before entering the filter.
+ *
+ * "filt_gain" is the combined gain of the filters.
+ *
+ * If I did not do it this way, then the filters could
+ * cause the signal to go beyond the 16bit range.
+ *
+ * If "play_rate" is 0 (ground) then the sample clock rate
+ * defaults to the 52xx internal sample clock. (baseclock/384)
+ */
+
+struct namco_52xx_interface
+{
+ int region; /* memory region */
+ double play_rate; /* Playback frequency */
+ double hp_filt_fc;
+ double hp_filt_q;
+ double lp_filt_fc;
+ double lp_filt_q;
+ double filt_gain;
+};
+
+void namcoio_52XX_write(int data);
+
+#endif
+
diff --git a/src/emu/sound/namcona.c b/src/emu/sound/namcona.c
new file mode 100644
index 00000000000..3b1faec64d7
--- /dev/null
+++ b/src/emu/sound/namcona.c
@@ -0,0 +1,1329 @@
+/*
+ Namco NA1/2 Sound Hardware
+
+ PCM samples and sound sequencing metadata are written by the main CPU to
+ shared RAM.
+
+ The sound CPU's type is unknown, though it appears to be little endian.
+ It has an internal BIOS.
+
+ RAM[0x820]: song select
+ RAM[0x822]: song control (fade?)
+ RAM[0x824..0x89e]:
+ Even addresses are used to select the sound effect.
+ 0x40 is written to odd addresses as a signal to play the requested sound.
+
+ Metadata vectors:
+ addr sample
+ 0000: 0012 // table of addresses for each VOX sequence
+ 0002: 07e4 // table of wave records (5 words each record)
+ 0004: 0794 // unknown table (5 words each record)
+ 0006: 0000 // unknown (always zero?)
+ 0008: 0102 // unknown address table
+ 000a: 0384 // unknown address table
+ 000c: 0690 // unknown chunk
+ 000e: 07bc // unknown table (5 words each record)
+ 0010: 7700 // unknown
+ 0012: addresses for each song sequence start here
+
+ Known issues:
+ - many opcodes are ignored or implemented imperfectly
+ - the metadata contains several mystery tables
+*/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "namcona.h"
+
+#define kTwelfthRootTwo 1.059463094
+#define FIXED_POINT_SHIFT (10) /* for mixing */
+#define MAX_VOICE 16
+#define MAX_SEQUENCE_VOICE 32
+#define MAX_SEQUENCE 0x40
+#define MAX_SEQUENCE_RECURSION 4 /* ? */
+#define SAMPLE_RATE_BASE (42667*2)
+
+struct voice
+{
+ INT32 bActive;
+
+ INT32 flags;
+ INT32 start; /* fixed point */
+ INT32 end; /* fixed point */
+ INT32 loop; /* fixed point */
+ INT32 baseFreq;
+ INT32 bank;
+
+ INT32 delta; /* fixed point */
+ INT32 pos;
+ INT32 note;
+ INT32 preNote;
+ INT32 volume;
+ INT32 pan;
+ INT32 leftVolume;
+ INT32 rightVolume;
+ INT32 dnote;
+ INT32 detune;
+ INT32 ignoreCount;
+ INT32 delay;
+ INT32 delayCount;
+ INT32 freqCtrlTableNo;
+ INT32 freqCtrlTable;
+ INT32 freqCtrlSpeed;
+ INT32 freqCtrlAmp;
+ INT32 freqCtrlPointer;
+ INT32 freqCtrlCounter;
+ INT32 freqCtrlFreq;
+ INT32 volCtrlTable;
+ INT32 volCtrlCount;
+ INT32 volCtrlPointer;
+ INT32 volCtrlCounter;
+ INT32 volCtrlSpeed;
+ INT32 volCtrlVol;
+ INT32 volCtrlVolEnd;
+ INT32 panCtrlTable;
+ INT32 panCtrlSpeed;
+ INT32 panCtrlCounter;
+ INT32 panCtrlEnable;
+ INT32 portament;
+ INT32 portamentSpeed;
+ INT32 portamentNote;
+};
+
+struct sequence
+{
+ UINT8 volume;
+ UINT8 reg2; /* master freq? */
+ UINT8 tempo;
+ int addr;
+ int pause;
+ int channel[8];
+ int stackData[MAX_SEQUENCE_RECURSION]; /* used for sub-sequences */
+ int stackSize;
+ int count; /* used for "repeat" opcode */
+ int count2;
+ int count3;
+};
+
+struct namcona
+{
+ int mSampleRate;
+ sound_stream * mStream;
+ INT16 *mpMixerBuffer;
+ INT32 *mpPitchTable;
+ UINT16 *mpROM;
+ UINT16 *mpMetaData;
+ struct sequence mSequence[MAX_SEQUENCE];
+ struct voice mVoice[MAX_SEQUENCE_VOICE];
+};
+
+static const UINT16 VolCtrlSpeedTable[0x80] =
+{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009,
+ 0x000b, 0x000d, 0x000f, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019,
+ 0x001b, 0x001d, 0x001f, 0x0022, 0x0024, 0x0027, 0x002a, 0x002d,
+ 0x0030, 0x0033, 0x0037, 0x003b, 0x0040, 0x0044, 0x0049, 0x004f,
+ 0x0054, 0x005a, 0x0061, 0x0068, 0x0070, 0x0078, 0x0081, 0x008a,
+ 0x0094, 0x009f, 0x00aa, 0x00b7, 0x00c4, 0x00d2, 0x00e1, 0x00f2,
+ 0x0103, 0x0116, 0x012a, 0x0140, 0x0157, 0x0170, 0x018b, 0x01ab,
+ 0x01c7, 0x01e8, 0x020b, 0x0231, 0x025a, 0x0285, 0x02b4, 0x02e6,
+ 0x031c, 0x0356, 0x0394, 0x03d6, 0x041d, 0x046a, 0x04bc, 0x0514,
+ 0x0572, 0x05d7, 0x0644, 0x06b8, 0x0735, 0x07ba, 0x084a, 0x08e4,
+ 0x0989, 0x0a3a, 0x0af8, 0x0bc3, 0x0c9e, 0x0d88, 0x0e83, 0x0f91,
+ 0x10b2, 0x11e8, 0x1334, 0x1498, 0x1617, 0x17b1, 0x1969, 0x1b40,
+ 0x1d3a, 0x1f59, 0x219f, 0x240f, 0x26ac, 0x297a, 0x2c7c, 0x2fb6,
+ 0x332b, 0x36e1, 0x3adc, 0x3f20, 0x43b4, 0x489d, 0x4de1, 0x5386,
+ 0x5995, 0x6014, 0x670b, 0x6e84, 0x7687, 0x7f1f, 0x8857, 0x923a,
+ 0x9cd4, 0xa833, 0xb465, 0xc17a, 0xcf81, 0xde8d, 0xeeb0, 0xffff
+};
+
+
+/**
+ * Given a sequence, return a pointer to the associated 16 bit word in shared RAM.
+ * The 16 bits are interpretted as follows:
+ * xxxxxxxx-------- index into sequence table (selects song/sample)
+ * --------x------- 1 if sequence is active/playing
+ * ---------x------ 1 if the main CPU has written a new sound command
+ * ----------xxxxxx unknown/unused
+ */
+static UINT16 *
+GetSequenceStatusAddr( struct namcona *chip, struct sequence *pSeq )
+{
+ int offs = pSeq - chip->mSequence;
+ return &chip->mpROM[0x820/2+offs];
+}
+
+static void
+Silence( struct namcona *chip )
+{
+ int i;
+ for( i=0; i<MAX_SEQUENCE_VOICE; i++ )
+ {
+ chip->mVoice[i].bActive = 0;
+ }
+ for( i=0; i<MAX_SEQUENCE; i++ )
+ {
+ UINT16 *pStatus = GetSequenceStatusAddr(chip, &chip->mSequence[i]);
+ *pStatus &= 0xff7f; /* wipe "sequence-is-playing" flag */
+ }
+}
+
+static UINT8
+ReadMetaDataByte( struct namcona *chip, int addr )
+{
+ UINT16 data = chip->mpMetaData[addr/2];
+ return (addr&1)?(data&0xff):(data>>8);
+} /* ReadMetaDataByte */
+
+static UINT16
+ReadMetaDataWord( struct namcona *chip, int addr )
+{
+ return ReadMetaDataByte(chip, addr)+ReadMetaDataByte(chip, addr+1)*256;
+} /* ReadMetaDataWord */
+
+static signed char
+ReadPCMSample(struct namcona *chip, int addr, int flag )
+{
+ UINT16 data16 = chip->mpROM[addr/2];
+ int dat = (addr&1)?(data16&0xff):(data16>>8);
+
+ if( flag&0x100 )
+ {
+ if( dat&0x80 )
+ {
+ dat = -(dat&0x7f) - 1;
+ }
+ }
+
+ return dat;
+} /* ReadPCMSample */
+
+static void
+RenderSamples(struct namcona *chip, stream_sample_t **buffer, INT16 *pSource, int length )
+{
+ int i;
+ stream_sample_t * pDest1 = buffer[0];
+ stream_sample_t * pDest2 = buffer[1];
+ for (i = 0; i < length; i++)
+ {
+ INT32 dataL = /* 100 * */ (*pSource++);
+ INT32 dataR = /* 100 * */ (*pSource++);
+ if( dataL > 0x7fff )
+ {
+ dataL = 0x7fff; /* clip */
+ }
+ else if( dataL < -0x8000 )
+ {
+ dataL = -0x8000; /* clip */
+ }
+ if( dataR > 0x7fff )
+ {
+ dataR = 0x7fff; /* clip */
+ }
+ else if( dataR < -0x8000 )
+ {
+ dataR = -0x8000; /* clip */
+ }
+ *pDest1++ = (INT16)dataL; /* stereo left */
+ *pDest2++ = (INT16)dataR; /* stereo right */
+ }
+} /* RenderSamples */
+
+static void
+PushSequenceAddr(struct namcona *chip, struct sequence *pSequence, int addr )
+{
+ if( pSequence->stackSize<MAX_SEQUENCE_RECURSION )
+ {
+ pSequence->stackData[pSequence->stackSize++] = addr;
+ }
+ else
+ {
+ logerror( "sound/namcona.c stack overflow!\n" );
+ }
+} /* PushSequenceAddr */
+
+static void
+PopSequenceAddr(struct namcona *chip, struct sequence *pSequence )
+{
+ if( pSequence->stackSize )
+ {
+ pSequence->addr = pSequence->stackData[--pSequence->stackSize];
+ }
+ else
+ {
+ UINT16 *pStatus = GetSequenceStatusAddr(chip,pSequence);
+ *pStatus &= 0xff7f; /* wipe "sequence-is-playing" flag */
+ }
+} /* PopSequenceAddr */
+
+static void
+HandleSubroutine(struct namcona *chip, struct sequence *pSequence )
+{
+ int addr = ReadMetaDataWord(chip, pSequence->addr );
+ PushSequenceAddr(chip, pSequence, pSequence->addr+2 );
+ pSequence->addr = addr;
+} /* HandleSubroutine */
+
+static void
+HandleRepeat(struct namcona *chip, struct sequence *pSequence )
+{
+ int count = ReadMetaDataByte( chip, pSequence->addr++ );
+ int addr = ReadMetaDataWord(chip, pSequence->addr );
+ if( pSequence->count < count )
+ {
+ pSequence->count++;
+ pSequence->addr = addr;
+ }
+ else
+ {
+ pSequence->count = 0;
+ pSequence->addr += 2;
+ }
+} /* HandleRepeat */
+
+static void
+HandleRepeatOut(struct namcona *chip, struct sequence *pSequence )
+{
+ int count = ReadMetaDataByte( chip, pSequence->addr++ );
+ int addr = ReadMetaDataWord(chip, pSequence->addr );
+ if( pSequence->count2 < count )
+ {
+ pSequence->count2++;
+ pSequence->addr += 2;
+ }
+ else
+ {
+ pSequence->count2 = 0;
+ pSequence->addr = addr;
+ }
+} /* HandleRepeatOut */
+
+static void
+MapArgs(struct namcona *chip, struct sequence *pSequence,
+ int bCommon,
+ void (*callback)( struct namcona *chip, struct sequence *, int chan, UINT8 data ) )
+{
+ UINT8 set = ReadMetaDataByte(chip,pSequence->addr++);
+ UINT8 data = 0;
+ int i;
+ if( bCommon )
+ {
+ data = ReadMetaDataByte( chip, pSequence->addr++ );
+ }
+ for( i=0; i<8; i++ )
+ {
+ if( set&(1<<(7-i)) )
+ {
+ if( !bCommon )
+ {
+ data = ReadMetaDataByte( chip,pSequence->addr++ );
+ }
+ callback( chip, pSequence, i, data );
+ }
+ }
+} /* MapArgs */
+
+static void
+AssignChannel(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ if( (pSequence - chip->mSequence) > 1 )
+ data += 16; /* sound effect */
+
+ if( data<MAX_SEQUENCE_VOICE )
+ {
+ struct voice *pVoice = &chip->mVoice[data];
+ pSequence->channel[chan] = data;
+ pVoice->bActive = 0;
+ pVoice->bank = 0;
+ pVoice->volume = 0x80;
+ pVoice->pan = 0x80;
+ pVoice->dnote = 0;
+ pVoice->detune = 0;
+ pVoice->freqCtrlTableNo = 0;
+ pVoice->freqCtrlSpeed = 0;
+ pVoice->freqCtrlAmp = 0;
+ pVoice->volCtrlTable = 0;
+ pVoice->volCtrlCount = 0;
+ pVoice->panCtrlTable = 0;
+ pVoice->ignoreCount = 0;
+ pVoice->delay = 0;
+ pVoice->portament = 0;
+ }
+} /* AssignChannel */
+
+static void
+IgnoreUnknownOp(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+} /* IgnoreUnknownOp */
+
+static void
+SelectWave(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ int bank = 0x20000 + pVoice->bank*0x20000;
+ int addr = ReadMetaDataWord(chip,2)+10*data;
+
+ pVoice->flags = ReadMetaDataWord(chip,addr+0*2);
+ pVoice->start = ReadMetaDataWord(chip,addr+1*2)*2+bank;
+ pVoice->end = ReadMetaDataWord(chip,addr+2*2)*2+bank;
+ pVoice->loop = ReadMetaDataWord(chip,addr+3*2)*2+bank;
+ pVoice->baseFreq = ReadMetaDataWord(chip,addr+4*2); /* unsure what this is; not currently used */
+
+ pVoice->start <<= FIXED_POINT_SHIFT;
+ pVoice->end <<= FIXED_POINT_SHIFT;
+ pVoice->loop <<= FIXED_POINT_SHIFT;
+
+ pVoice->bActive = 0;
+ pVoice->dnote = 0;
+ pVoice->detune = 0;
+} /* SelectWave */
+
+static void
+PlayNote(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ if( data == 0xff )
+ {
+ pVoice->volCtrlCounter = 1;
+ }
+ else
+ {
+ if (pVoice->ignoreCount > 0)
+ pVoice->ignoreCount--;
+ else
+ {
+ pVoice->delayCount = pVoice->delay;
+ pVoice->preNote = pVoice->note;
+ pVoice->note = data<<8;
+ pVoice->bActive |= 4;
+ }
+ }
+} /* PlayNote */
+
+static void
+SelectWaveAndPlayNote(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ int bank = 0x20000 + pVoice->bank*0x20000;
+ int addr = ReadMetaDataWord(chip,4)+10*data;
+ float pbase = (float)SAMPLE_RATE_BASE / (float)chip->mSampleRate;
+ INT32 frequency;
+
+ pVoice->flags = ReadMetaDataWord(chip,addr+0*2);
+ pVoice->start = ReadMetaDataWord(chip,addr+3*2)*2+bank;
+ pVoice->end = ReadMetaDataWord(chip,addr+4*2)*2+bank;
+ pVoice->loop = pVoice->start;
+
+ pVoice->start <<= FIXED_POINT_SHIFT;
+ pVoice->end <<= FIXED_POINT_SHIFT;
+ pVoice->loop <<= FIXED_POINT_SHIFT;
+
+ pVoice->leftVolume = ReadMetaDataByte(chip,addr+1*2);
+ pVoice->rightVolume = ReadMetaDataByte(chip,addr+1*2+1);
+
+ frequency = ReadMetaDataWord(chip,addr+2*2);
+ pVoice->delta = (long)((float)frequency * pbase);
+ pVoice->delta >>= 16-FIXED_POINT_SHIFT;
+
+ pVoice->bActive = 2;
+ pVoice->pos = pVoice->start;
+} /* SelectWaveAndPlayNote */
+
+static void
+Detune(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->detune = data;
+} /* Detune */
+
+
+static void
+DNote(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->dnote = data;
+} /* DNote */
+
+static void
+Pan(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->pan = data;
+ pVoice->panCtrlSpeed = 0;
+} /* Pan */
+
+static void
+Volume(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->volume = pSequence->volume * data / 256;
+} /* Volume */
+
+static void
+FreqCtrlTable(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->freqCtrlTableNo = data;
+} /* FreqCtrlTable */
+
+static void
+FreqCtrlSpeed(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->freqCtrlSpeed = data;
+} /* FreqCtrlSpeed */
+
+static void
+FreqCtrlAmp(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->freqCtrlAmp = data;
+} /* FreqCtrlAmp */
+
+static void
+VolCtrlTable(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ int addr = ReadMetaDataWord(chip,10);
+ addr = ReadMetaDataWord(chip,addr+data*2);
+ pVoice->volCtrlTable = addr;
+} /* VolCtrlTable */
+
+static void
+VolCtrlCount(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->volCtrlCount = data;
+} /* VolCtrlCount */
+
+static void
+PanCtrlTable(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ int addr = ReadMetaDataWord(chip,12) + data*4;
+ pVoice->panCtrlTable = addr;
+ pVoice->panCtrlSpeed = ReadMetaDataByte(chip,addr+3);
+ if( pVoice->panCtrlSpeed & 0x80)
+ pVoice->panCtrlSpeed = -(0x100 - pVoice->panCtrlSpeed);
+} /* PanCtrlTable */
+
+static void
+IgnoreCount(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->ignoreCount = data;
+} /* IgnoreCount */
+
+static void
+Delay(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->delay = data;
+} /* Delay */
+
+static void
+Portament(struct namcona *chip, struct sequence *pSequence, int chan, UINT8 data )
+{
+ struct voice *pVoice = &chip->mVoice[pSequence->channel[chan]];
+ pVoice->portament = (0x100 - data) & 0xff;
+} /* Portament */
+
+static void
+UpdateSequence(struct namcona *chip, struct sequence *pSequence )
+{
+ UINT16 *pStatus = GetSequenceStatusAddr(chip,pSequence);
+ UINT16 data = *pStatus;
+
+ if( data&0x0040 )
+ { /* bit 0x0040 indicates that a sound request was written by the main CPU */
+ int offs = ReadMetaDataWord(chip,0)+(data>>8)*2;
+ memset( pSequence, 0x00, sizeof(struct sequence) );
+ if( pSequence == &chip->mSequence[0] ) Silence(chip); /* hack! */
+ pSequence->addr = ReadMetaDataWord(chip,offs);
+ *pStatus = (data&0xffbf)|0x0080; /* set "sequence-is-playing" flag */
+ }
+ if( data&0x0080 )
+ {
+ if( pSequence == &chip->mSequence[1] )
+ {
+ if( !(*(pStatus-1) & 0x0080) )
+ *pStatus = data&0xff7f;
+ }
+ }
+
+ while( (*pStatus)&0x0080 )
+ {
+ if( pSequence->pause )
+ {
+ pSequence->pause--;
+ return;
+ }
+ else
+ {
+ int code = ReadMetaDataByte(chip,pSequence->addr++);
+ if( code&0x80 )
+ {
+ pSequence->pause = pSequence->tempo*((code&0x7f)+1);
+ }
+ else
+ {
+ int bCommon = (code&0x40);
+ switch( code&0x3f )
+ {
+ case 0x01: /* master volume */
+ pSequence->volume = ReadMetaDataByte(chip,pSequence->addr++);
+ break;
+
+ case 0x02: /* master tempo */
+ pSequence->reg2 = ReadMetaDataByte(chip,pSequence->addr++);
+ break;
+
+ case 0x03: /* tempo */
+ pSequence->tempo = ReadMetaDataByte(chip,pSequence->addr++) * pSequence->reg2;
+ if (pSequence->tempo == 0) pSequence->tempo = 1;
+ break;
+
+ case 0x04:
+ HandleSubroutine(chip, pSequence );
+ break;
+
+ case 0x05: /* end-of-sequence */
+ PopSequenceAddr(chip, pSequence );
+ break;
+
+ case 0x06: /* operand is note index */
+ MapArgs(chip, pSequence, bCommon, PlayNote );
+ pSequence->pause = pSequence->tempo;
+ break;
+
+ case 0x07:
+ MapArgs(chip, pSequence, bCommon, SelectWave );
+ break;
+
+ case 0x08:
+ MapArgs(chip, pSequence, bCommon, Volume );
+ break;
+
+ case 0x09:
+ pSequence->addr = ReadMetaDataWord(chip,pSequence->addr);
+ break;
+
+ case 0x0a:
+ HandleRepeat(chip, pSequence );
+ break;
+
+ case 0x0b:
+ HandleRepeatOut(chip, pSequence );
+ break;
+
+ case 0x0c:
+ MapArgs(chip, pSequence, bCommon, DNote );
+ break;
+
+ case 0x0d:
+ MapArgs(chip, pSequence, bCommon, Detune );
+ break;
+
+ case 0x0e:
+ MapArgs(chip, pSequence, bCommon, FreqCtrlTable );
+ break;
+
+ case 0x0f:
+ MapArgs(chip, pSequence, bCommon, FreqCtrlSpeed );
+ break;
+
+ case 0x12:
+ MapArgs(chip, pSequence, bCommon, FreqCtrlAmp );
+ break;
+
+ case 0x13:
+ MapArgs(chip, pSequence, bCommon, VolCtrlTable );
+ break;
+
+ case 0x11:
+ MapArgs(chip, pSequence, bCommon, VolCtrlCount );
+ break;
+
+ case 0x10:
+ MapArgs(chip, pSequence, bCommon, IgnoreCount );
+ break;
+
+ case 0x14:
+ MapArgs(chip, pSequence, bCommon, Delay );
+ break;
+
+ case 0x16:
+ MapArgs(chip, pSequence, bCommon, Pan );
+ break;
+
+ case 0x17:
+ MapArgs(chip, pSequence, bCommon, PanCtrlTable );
+ break;
+
+ case 0x19: // one loop?
+ if (pSequence->count3 == 0)
+ {
+ pSequence->addr = ReadMetaDataWord(chip,pSequence->addr);
+ pSequence->count3++;
+ }
+ else
+ {
+ pSequence->addr += 2;
+ pSequence->count3 = 0;
+ }
+ break;
+
+ case 0x1b:
+ MapArgs(chip, pSequence, bCommon, SelectWaveAndPlayNote );
+ pSequence->pause = pSequence->tempo;
+ break;
+
+ case 0x1c: // request sound effect ?
+ pSequence->addr += 2;
+ break;
+
+ case 0x1e:
+ {
+ int no = ReadMetaDataByte(chip,pSequence->addr++); /* Sequence No */
+ int cod = ReadMetaDataByte(chip,pSequence->addr++);
+ if (no < MAX_SEQUENCE)
+ {
+ struct sequence *pSequence2 = &chip->mSequence[no];
+ UINT16 *pStatus2 = GetSequenceStatusAddr(chip,pSequence2);
+ int offs = 0x12+cod*2;
+ *pStatus2 = (cod<<8)|0x0080;
+ memset( pSequence2, 0x00, sizeof(struct sequence) );
+ pSequence2->addr = ReadMetaDataWord(chip,offs);
+ }
+ }
+ break;
+
+ case 0x20:
+ MapArgs(chip, pSequence, bCommon, AssignChannel );
+ break;
+
+ case 0x22:
+ MapArgs(chip, pSequence, bCommon, Portament );
+ break;
+
+ case 0x23:
+ {
+ UINT8 reg23_0 = ReadMetaDataByte(chip,pSequence->addr++); /* Channel select */
+ UINT8 reg23_1 = ReadMetaDataByte(chip,pSequence->addr++); /* PCM bank select */
+ /* reg23_0: 0 = Ch. 0- 3 PCM Bank select
+ 1 = Ch. 4- 7 PCM Bank select
+ 2 = Ch. 8-11 PCM Bank select
+ 3 = Ch.12-15 PCM Bank select
+ */
+ if( reg23_0 == 5 ) reg23_0 = 3; /* xday2,bkrtmaq */
+ if( reg23_0 < 4 )
+ {
+ if( (pSequence - chip->mSequence) > 1 )
+ reg23_0 += 4; /* sound effect */
+ chip->mVoice[reg23_0*4 + 0].bank = reg23_1;
+ chip->mVoice[reg23_0*4 + 1].bank = reg23_1;
+ chip->mVoice[reg23_0*4 + 2].bank = reg23_1;
+ chip->mVoice[reg23_0*4 + 3].bank = reg23_1;
+ }
+ }
+ break;
+
+ case 0x24: // priority ?
+ MapArgs(chip, pSequence, bCommon, IgnoreUnknownOp );
+ break;
+
+ default:
+ //mame_printf_debug( "? 0x%x\n", code&0x3f );
+ *pStatus &= 0xff7f; /* clear "sequence-is-playing" flag */
+ break;
+ }
+ }
+ }
+ }
+} /* UpdateSequence */
+
+static void
+InitFreqCtrl( struct namcona *chip, struct voice *pVoice )
+{
+ if( pVoice->freqCtrlTableNo == 0 )
+ {
+ pVoice->freqCtrlPointer = 0;
+ }
+ else
+ {
+ int addr = ReadMetaDataWord(chip,8);
+ addr = ReadMetaDataWord(chip,addr+pVoice->freqCtrlTableNo*2);
+ pVoice->freqCtrlTable = pVoice->freqCtrlTableNo;
+ pVoice->freqCtrlPointer = addr;
+ }
+ pVoice->freqCtrlCounter = 0;
+ pVoice->freqCtrlFreq = 0;
+}
+
+static void
+UpdateFreqCtrl( struct namcona *chip, struct voice *pVoice )
+{
+ int addr,freq;
+
+ if( !pVoice->freqCtrlPointer ) return;
+
+ pVoice->freqCtrlCounter += pVoice->freqCtrlSpeed;
+ if( pVoice->freqCtrlCounter > 0xff )
+ {
+ pVoice->freqCtrlPointer += pVoice->freqCtrlCounter>>8;
+ pVoice->freqCtrlCounter &= 0xff;
+ }
+
+ switch( ReadMetaDataByte(chip,pVoice->freqCtrlPointer+1) )
+ {
+ case 0xfd:
+ pVoice->freqCtrlTable++;
+ case 0xfe:
+ addr = ReadMetaDataWord(chip,8);
+ addr = ReadMetaDataWord(chip,addr+pVoice->freqCtrlTable*2);
+ pVoice->freqCtrlPointer = addr;
+ break;
+ case 0xff:
+ freq = ReadMetaDataByte(chip,pVoice->freqCtrlPointer+0) * 0x100;
+ freq -= 100 * 0x100;
+ freq *= pVoice->freqCtrlAmp;
+ freq /= 0x100 * 2;
+ pVoice->freqCtrlFreq = freq;
+ pVoice->freqCtrlPointer = 0;
+ break;
+ default:
+ freq = ReadMetaDataByte(chip,pVoice->freqCtrlPointer+0) * (0x100 - pVoice->freqCtrlCounter);
+ freq += ReadMetaDataByte(chip,pVoice->freqCtrlPointer+1) * pVoice->freqCtrlCounter;
+ freq -= 100 * 0x100;
+ freq *= pVoice->freqCtrlAmp;
+ freq /= 0x100 * 2;
+ pVoice->freqCtrlFreq = freq;
+ break;
+ }
+}
+
+static void
+InitVolCtrl( struct namcona *chip, struct voice *pVoice )
+{
+ pVoice->volCtrlPointer = pVoice->volCtrlTable;
+ pVoice->volCtrlCounter = pVoice->volCtrlCount;
+ if( pVoice->volCtrlCounter > 0 ) pVoice->volCtrlCounter++;
+ if( pVoice->volCtrlPointer )
+ {
+ pVoice->volCtrlSpeed = VolCtrlSpeedTable[ReadMetaDataByte(chip,pVoice->volCtrlPointer) & 0x7f];
+ pVoice->volCtrlVolEnd = ReadMetaDataByte(chip,pVoice->volCtrlPointer+1)<<8;
+ pVoice->volCtrlPointer += 2;
+ pVoice->volCtrlVol = 0;
+ }
+ else
+ {
+ pVoice->volCtrlVol = 0xffff;
+ }
+}
+
+static void
+UpdateVolCtrl( struct namcona *chip, struct voice *pVoice )
+{
+ if( !pVoice->volCtrlPointer ) return;
+
+ if( pVoice->volCtrlCounter == 1 )
+ {
+ pVoice->volCtrlCounter = 0;
+
+ while( pVoice->volCtrlPointer )
+ {
+ if( ReadMetaDataByte(chip,pVoice->volCtrlPointer) == 0x00 )
+ {
+ if( ReadMetaDataByte(chip,pVoice->volCtrlPointer+1) == 0xff )
+ {
+ pVoice->volCtrlPointer = 0;
+ pVoice->bActive &= ~1;
+ }
+ else
+ {
+ pVoice->volCtrlPointer += 2;
+ pVoice->volCtrlSpeed = VolCtrlSpeedTable[ReadMetaDataByte(chip,pVoice->volCtrlPointer) & 0x7f];
+ pVoice->volCtrlVolEnd = ReadMetaDataByte(chip,pVoice->volCtrlPointer+1)<<8;
+ pVoice->volCtrlPointer += 2;
+ }
+ break;
+ }
+ pVoice->volCtrlPointer += 2;
+ }
+ }
+ else
+ {
+ int next = 0;
+
+ if( pVoice->volCtrlCounter > 0 )
+ pVoice->volCtrlCounter--;
+
+ if( pVoice->volCtrlVol < pVoice->volCtrlVolEnd )
+ {
+ pVoice->volCtrlVol += pVoice->volCtrlSpeed;
+ if( pVoice->volCtrlVol >= pVoice->volCtrlVolEnd )
+ {
+ pVoice->volCtrlVol = pVoice->volCtrlVolEnd;
+ next = 1;
+ }
+ }
+ else
+ {
+ pVoice->volCtrlVol -= pVoice->volCtrlSpeed;
+ if( pVoice->volCtrlVol <= pVoice->volCtrlVolEnd )
+ {
+ pVoice->volCtrlVol = pVoice->volCtrlVolEnd;
+ next = 1;
+ }
+ }
+
+ if( next )
+ {
+ UINT8 val1, val2;
+
+ val1 = ReadMetaDataByte(chip,pVoice->volCtrlPointer+0);
+ val2 = ReadMetaDataByte(chip,pVoice->volCtrlPointer+1);
+
+ if( val1 == 0x00 && val2 > 0x80 )
+ {
+ pVoice->volCtrlPointer = 0;
+ pVoice->bActive &= ~1;
+ }
+ else if( val1 != 0x00 || val2 != 0x80 )
+ {
+ if( val1 == 0x00 )
+ pVoice->volCtrlPointer = pVoice->volCtrlTable + val2;
+ pVoice->volCtrlSpeed = VolCtrlSpeedTable[ReadMetaDataByte(chip,pVoice->volCtrlPointer) & 0x7f];
+ pVoice->volCtrlVolEnd = ReadMetaDataByte(chip,pVoice->volCtrlPointer+1)<<8;
+ pVoice->volCtrlPointer += 2;
+ }
+ }
+ }
+}
+
+
+static void
+InitPanCtrl( struct namcona *chip, struct voice *pVoice )
+{
+ if( pVoice->panCtrlTable != 0 && pVoice->panCtrlSpeed != 0)
+ {
+ pVoice->panCtrlEnable = 1;
+ pVoice->panCtrlCounter = ReadMetaDataByte(chip,pVoice->panCtrlTable);
+ if( pVoice->panCtrlCounter != 0xFE )
+ pVoice->pan = ReadMetaDataByte(chip,pVoice->panCtrlTable+1);
+ }
+ else
+ {
+ pVoice->panCtrlEnable = 0;
+ }
+}
+
+static void
+UpdatePanCtrl( struct namcona *chip, struct voice *pVoice )
+{
+ if( pVoice->panCtrlEnable )
+ {
+ if( pVoice->panCtrlCounter == 0 )
+ {
+ UINT8 pan_2 = ReadMetaDataByte(chip,pVoice->panCtrlTable+2);
+ UINT8 pan_3 = ReadMetaDataByte(chip,pVoice->panCtrlTable+3);
+ if( !(pan_3&0x80) )
+ {
+ pVoice->pan += pan_3;
+ if( pVoice->pan > 0xff || pVoice->pan >= pan_2)
+ {
+ pVoice->pan = pan_2;
+ pVoice->panCtrlEnable = 0;
+ }
+ }
+ else
+ {
+ pVoice->pan -= 0x100 - pan_3;
+ if( pVoice->pan < 0 || pVoice->pan <= pan_2)
+ {
+ pVoice->pan = pan_2;
+ pVoice->panCtrlEnable = 0;
+ }
+ }
+ }
+ else if( pVoice->panCtrlCounter < 0xFE )
+ {
+ pVoice->panCtrlCounter--;
+ }
+ else
+ {
+ if( pVoice->panCtrlSpeed >= 0 )
+ {
+ pVoice->pan += pVoice->panCtrlSpeed;
+ if( pVoice->pan > 0xff )
+ {
+ pVoice->pan = 0xff;
+ pVoice->panCtrlSpeed = -pVoice->panCtrlSpeed;
+ }
+ }
+ else
+ {
+ pVoice->pan += pVoice->panCtrlSpeed;
+ if( pVoice->pan < 0 )
+ {
+ pVoice->pan = 0;
+ pVoice->panCtrlSpeed = -pVoice->panCtrlSpeed;
+ }
+ }
+ }
+ }
+}
+
+static void
+InitPortament( struct namcona *chip, struct voice *pVoice )
+{
+ pVoice->portamentSpeed = pVoice->portament;
+}
+
+static void
+UpdatePortament( struct namcona *chip, struct voice *pVoice )
+{
+ if( !pVoice->portamentSpeed )
+ {
+ pVoice->portamentNote = pVoice->note;
+ }
+ else
+ {
+ int note;
+ note = pVoice->note - pVoice->preNote;
+ if( note >= 0 )
+ {
+ note = (note/256+1) * pVoice->portamentSpeed / 2;
+ pVoice->portamentNote += note;
+ if( pVoice->portamentNote > pVoice->note )
+ {
+ pVoice->portamentNote = pVoice->note;
+ pVoice->portamentSpeed = 0;
+ }
+ }
+ else
+ {
+ note = (-note/256+1) * pVoice->portamentSpeed / 2;
+ pVoice->portamentNote -= note;
+ if( pVoice->portamentNote < pVoice->note )
+ {
+ pVoice->portamentNote = pVoice->note;
+ pVoice->portamentSpeed = 0;
+ }
+ }
+ }
+}
+
+static void
+StartPlayNote( struct namcona *chip, struct voice *pVoice )
+{
+ if( pVoice->bActive & 4 )
+ {
+ if( pVoice->delayCount == 0)
+ {
+ pVoice->bActive &= ~4;
+ pVoice->bActive |= 1;
+ pVoice->pos = pVoice->start;
+ InitFreqCtrl( chip, pVoice );
+ InitVolCtrl( chip, pVoice );
+ InitPanCtrl( chip, pVoice );
+ InitPortament( chip, pVoice );
+ }
+ else
+ pVoice->delayCount--;
+ }
+}
+
+static void
+UpdatePlayNote( struct namcona *chip, struct voice *pVoice )
+{
+ int vol;
+ UINT16 Note = pVoice->portamentNote + (pVoice->dnote<<8) + pVoice->detune + pVoice->baseFreq;
+ Note += pVoice->freqCtrlFreq;
+ Note &= 0x7fff;
+ pVoice->delta = chip->mpPitchTable[Note>>8];
+ pVoice->delta += (chip->mpPitchTable[(Note>>8)+1]-pVoice->delta) * (Note&0xff) / 256;
+
+ vol = (pVoice->volCtrlVol>>8) * pVoice->volume / 256;
+ pVoice->leftVolume = (0x100-pVoice->pan) * vol / 256;
+ pVoice->rightVolume = pVoice->pan * vol / 256;
+}
+
+static void
+UpdateStatus( struct namcona *chip, struct voice *pVoice )
+{
+ StartPlayNote( chip, pVoice );
+ if( pVoice->bActive & 1 )
+ {
+ UpdateFreqCtrl( chip, pVoice );
+ UpdateVolCtrl( chip, pVoice );
+ UpdatePanCtrl( chip, pVoice );
+ UpdatePortament( chip, pVoice );
+ UpdatePlayNote( chip, pVoice );
+ }
+}
+
+static void
+UpdateSound( void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length )
+{
+ struct namcona *chip = param;
+ int i;
+
+ for( i=0; i<MAX_SEQUENCE; i++ )
+ UpdateSequence(chip, &chip->mSequence[i] );
+ for( i=0; i<MAX_SEQUENCE_VOICE; i++ )
+ UpdateStatus(chip, &chip->mVoice[i] );
+ for( i=0; i<MAX_SEQUENCE; i++ )
+ UpdateSequence(chip, &chip->mSequence[i] );
+ for( i=0; i<MAX_SEQUENCE_VOICE; i++ )
+ UpdateStatus(chip, &chip->mVoice[i] );
+
+ if( length>chip->mSampleRate ) length = chip->mSampleRate;
+ memset(chip->mpMixerBuffer, 0, length * sizeof(INT16) * 2);
+ for( i=0;i<MAX_VOICE;i++ )
+ {
+ struct voice *pVoice;
+ if( chip->mVoice[i+16].bActive & 3 )
+ pVoice = &chip->mVoice[i+16]; //sound effect is high priority
+ else
+ pVoice = &chip->mVoice[i];
+
+ if( (pVoice->bActive & 3) && pVoice->delta )
+ {
+ INT32 delta = pVoice->delta;
+ INT32 end = pVoice->end;
+ INT32 pos = pVoice->pos;
+ INT32 lvol = pVoice->leftVolume;
+ INT32 rvol = pVoice->rightVolume;
+ INT16 *pDest = chip->mpMixerBuffer;
+ INT16 dat;
+ int j;
+ for( j=0; j<length; j++ )
+ {
+ if( pos >= end )
+ {
+ if( pVoice->flags&0x1000 )
+ {
+ pos = pos - end + pVoice->loop;
+ }
+ else
+ {
+ pVoice->bActive &= ~3;
+ break;
+ }
+ }
+ dat = ReadPCMSample(chip,pos>>FIXED_POINT_SHIFT, pVoice->flags)*32;
+ *pDest++ += dat*lvol/256;
+ *pDest++ += dat*rvol/256;
+ pos += delta;
+ }
+ pVoice->pos = pos;
+ }
+ }
+ RenderSamples(chip, buffer, chip->mpMixerBuffer, length );
+} /* UpdateSound */
+
+static void *namcona_start(int sndindex, int clock, const void *config)
+{
+ const struct NAMCONAinterface *intf = config;
+ struct namcona *chip;
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+ chip->mSampleRate = clock;
+ chip->mStream = stream_create(0, 2, chip->mSampleRate, chip, UpdateSound);
+ chip->mpROM = (UINT16 *)intf->memory_base;
+ chip->mpMetaData = chip->mpROM+intf->metadata_offset;
+
+ memset( chip->mVoice, 0x00, sizeof(chip->mVoice) );
+ memset( chip->mSequence, 0x00, sizeof(chip->mSequence) );
+
+ chip->mpMixerBuffer = auto_malloc( sizeof(INT16)*chip->mSampleRate*2 );
+ chip->mpPitchTable = auto_malloc( sizeof(INT32)*0xff );
+ {
+ int i;
+ for( i=0; i<0xff; i++ )
+ {
+ int data = i;
+ double freq = freq = (1<<FIXED_POINT_SHIFT)/4;
+ while( data>0x3a )
+ {
+ data--;
+ freq *= kTwelfthRootTwo;
+ }
+ while( data<0x3a )
+ {
+ data++;
+ freq /= kTwelfthRootTwo;
+ }
+ chip->mpPitchTable[i] = (INT32)freq;
+ }
+ }
+ return chip;
+} /* NAMCONA_sh_start */
+
+#if 0
+static void
+DumpSampleTable( FILE *f, struct namcona *chip, int table, unsigned char *special )
+{
+ int iStart = ReadMetaDataWord(chip,table);
+ int i=iStart;
+ fprintf( f, "\nsample table:\n" );
+ while( i<0x10000 )
+ {
+ fprintf( f, "%04x(%02x): %04x %04x %04x %04x %04x (len=%d)\n",
+ i, (i-iStart)/10,
+ ReadMetaDataWord(chip,i+0*2), // flags
+ ReadMetaDataWord(chip,i+1*2), // start
+ ReadMetaDataWord(chip,i+2*2), // end
+ ReadMetaDataWord(chip,i+3*2), // loop
+ ReadMetaDataWord(chip,i+4*2), // freq
+ ReadMetaDataWord(chip,i+2*2)-ReadMetaDataWord(chip,i+1*2) );
+ i+=5*2;
+ if( special[i] || special[i+1] ) break;
+ }
+ fprintf( f, "\n" );
+}
+
+static void
+DumpBytes( FILE *f, struct namcona *chip, int addr, unsigned char *special )
+{
+ fprintf( f, "%04x:", addr );
+ while( addr<0x10000 )
+ {
+ fprintf( f, " %02x", ReadMetaDataByte(chip,addr) );
+ addr++;
+ if( (addr&0xf)==0 ) fprintf( f, "\n%04x;", addr );
+ if( special[addr] ) break;
+ }
+ fprintf( f, "\n" );
+}
+
+static void
+DumpUnkTable( FILE *f, struct namcona *chip, int table, unsigned char *special )
+{
+ int iStart = ReadMetaDataWord(chip,table);
+ int iFinish = ReadMetaDataWord(chip,iStart);
+ int i,addr;
+
+ if( iFinish<iStart )
+ { /* hack for CosmoGang */
+ iFinish = ReadMetaDataWord(chip,iStart+2);
+ }
+
+ fprintf( f, "\nunk table; %d entries:\n", (iFinish-iStart)/2 );
+ fprintf( f, "%04x:", iStart );
+
+
+ for( i=iStart; i<iFinish; i+=2 )
+ {
+ addr = ReadMetaDataWord(chip,i);
+ fprintf( f, " %04x", addr );
+ special[addr] = 1;
+ }
+ fprintf( f,"\n" );
+ for( i=iStart; i<iFinish; i+=2 )
+ {
+ addr = ReadMetaDataWord(chip,i);
+ fprintf( f, "%04x:", addr );
+ for(;;)
+ {
+ fprintf( f, " %02x", ReadMetaDataByte(chip,addr) );
+ addr++;
+ if( addr>=0x10000 || special[addr] ) break;
+ }
+ fprintf( f, "\n" );
+ }
+ fprintf( f, "\n" );
+}
+#endif
+
+static void
+namcona_stop( void *chip )
+{
+ #if 0
+ FILE *f = fopen("snd.txt","w");
+ if( f )
+ {
+ unsigned char *special = malloc(0x10000);
+ if( special )
+ {
+ int i,addr, table;
+ memset( special, 0x00, 0x10000 );
+ for( i=0; i<0x12; i+=2 )
+ {
+ addr = ReadMetaDataWord(chip,i);
+ if( i ) special[addr] = 1;
+ fprintf( f, "%04x: %04x\n", i, addr );
+ }
+ table = 0x12;
+ i = table;
+ while( i<0x10000 )
+ {
+ addr = ReadMetaDataWord(chip,i);
+ special[addr] = 1;
+ i+=2;
+ if( special[i] ) break;
+ }
+ DumpSampleTable( f, chip, 0x0002, special );
+ DumpSampleTable( f, chip, 0x0004, special );
+ /* 0x0006 is unused */
+ DumpUnkTable( f, chip, 0x0008, special );
+ DumpUnkTable( f, chip, 0x000a, special );
+ fprintf( f, "\nunknown chunk:\n" );
+ DumpBytes(f, chip, ReadMetaDataWord(chip,0x0c), special );
+ DumpSampleTable( f, chip, 0x000e, special );
+ fprintf( f, "\nSong Table:\n" );
+ i = 0x12;
+ while( i<0x10000 )
+ {
+ addr = ReadMetaDataWord(chip,i);
+ fprintf( f, "[%02x] ", (i-0x12)/2 );
+ DumpBytes( f,chip,addr,special );
+ i+=2;
+ if( special[i] ) break;
+ }
+ free( special );
+ }
+ fclose( f );
+ }
+ #endif
+} /* NAMCONA_sh_stop */
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void namcona_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void namcona_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = namcona_set_info; break;
+ case SNDINFO_PTR_START: info->start = namcona_start; break;
+ case SNDINFO_PTR_STOP: info->stop = namcona_stop; break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Namco NA"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Namco custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/namcona.h b/src/emu/sound/namcona.h
new file mode 100644
index 00000000000..9ee364379f4
--- /dev/null
+++ b/src/emu/sound/namcona.h
@@ -0,0 +1,10 @@
+/* namcona1.h */
+#ifndef _NAMCONA_
+#define _NAMCONA_
+
+struct NAMCONAinterface {
+ void *memory_base;
+ int metadata_offset;
+};
+
+#endif
diff --git a/src/emu/sound/nes_apu.c b/src/emu/sound/nes_apu.c
new file mode 100644
index 00000000000..21c5768abe5
--- /dev/null
+++ b/src/emu/sound/nes_apu.c
@@ -0,0 +1,789 @@
+/*****************************************************************************
+
+ MAME/MESS NES APU CORE
+
+ Based on the Nofrendo/Nosefart NES N2A03 sound emulation core written by
+ Matthew Conte (matt@conte.com) and redesigned for use in MAME/MESS by
+ Who Wants to Know? (wwtk@mail.com)
+
+ This core is written with the advise and consent of Matthew Conte and is
+ released under the GNU Public License. This core is freely avaiable for
+ use in any freeware project, subject to the following terms:
+
+ Any modifications to this code must be duly noted in the source and
+ approved by Matthew Conte and myself prior to public submission.
+
+ timing notes:
+ master = 21477270
+ 2A03 clock = master/12
+ sequencer = master/89490 or CPU/7457
+
+ *****************************************************************************
+
+ NES_APU.C
+
+ Actual NES APU interface.
+
+ LAST MODIFIED 02/29/2004
+
+ - Based on Matthew Conte's Nofrendo/Nosefart core and redesigned to
+ use MAME system calls and to enable multiple APUs. Sound at this
+ point should be just about 100% accurate, though I cannot tell for
+ certain as yet.
+
+ A queue interface is also available for additional speed. However,
+ the implementation is not yet 100% (DPCM sounds are inaccurate),
+ so it is disabled by default.
+
+ *****************************************************************************
+
+ BUGFIXES:
+
+ - Various bugs concerning the DPCM channel fixed. (Oliver Achten)
+ - Fixed $4015 read behaviour. (Oliver Achten)
+
+ *****************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "nes_apu.h"
+#include "cpu/m6502/m6502.h"
+
+#include "nes_defs.h"
+
+/* GLOBAL CONSTANTS */
+#define SYNCS_MAX1 0x20
+#define SYNCS_MAX2 0x80
+
+/* GLOBAL VARIABLES */
+struct nesapu_info
+{
+ apu_t APU; /* Actual APUs */
+ float apu_incsize; /* Adjustment increment */
+ uint32 samps_per_sync; /* Number of samples per vsync */
+ uint32 buffer_size; /* Actual buffer size in bytes */
+ uint32 real_rate; /* Actual playback rate */
+ uint8 noise_lut[NOISE_LONG]; /* Noise sample lookup table */
+ uint32 vbl_times[0x20]; /* VBL durations in samples */
+ uint32 sync_times1[SYNCS_MAX1]; /* Samples per sync table */
+ uint32 sync_times2[SYNCS_MAX2]; /* Samples per sync table */
+ sound_stream *stream;
+};
+
+
+/* INTERNAL FUNCTIONS */
+
+/* INITIALIZE WAVE TIMES RELATIVE TO SAMPLE RATE */
+static void create_vbltimes(uint32 * table,const uint8 *vbl,unsigned int rate)
+{
+ int i;
+
+ for (i=0;i<0x20;i++)
+ table[i]=vbl[i]*rate;
+}
+
+/* INITIALIZE SAMPLE TIMES IN TERMS OF VSYNCS */
+static void create_syncs(struct nesapu_info *info, unsigned long sps)
+{
+ int i;
+ unsigned long val=sps;
+
+ for (i=0;i<SYNCS_MAX1;i++)
+ {
+ info->sync_times1[i]=val;
+ val+=sps;
+ }
+
+ val=0;
+ for (i=0;i<SYNCS_MAX2;i++)
+ {
+ info->sync_times2[i]=val;
+ info->sync_times2[i]>>=2;
+ val+=sps;
+ }
+}
+
+/* INITIALIZE NOISE LOOKUP TABLE */
+static void create_noise(uint8 *buf, const int bits, int size)
+{
+ static int m = 0x0011;
+ int xor_val, i;
+
+ for (i = 0; i < size; i++)
+ {
+ xor_val = m & 1;
+ m >>= 1;
+ xor_val ^= (m & 1);
+ m |= xor_val << (bits - 1);
+
+ buf[i] = m;
+ }
+}
+
+/* TODO: sound channels should *ALL* have DC volume decay */
+
+/* OUTPUT SQUARE WAVE SAMPLE (VALUES FROM -16 to +15) */
+static int8 apu_square(struct nesapu_info *info, square_t *chan)
+{
+ int env_delay;
+ int sweep_delay;
+ int8 output;
+
+ /* reg0: 0-3=volume, 4=envelope, 5=hold, 6-7=duty cycle
+ ** reg1: 0-2=sweep shifts, 3=sweep inc/dec, 4-6=sweep length, 7=sweep on
+ ** reg2: 8 bits of freq
+ ** reg3: 0-2=high freq, 7-4=vbl length counter
+ */
+
+ if (FALSE == chan->enabled)
+ return 0;
+
+ /* enveloping */
+ env_delay = info->sync_times1[chan->regs[0] & 0x0F];
+
+ /* decay is at a rate of (env_regs + 1) / 240 secs */
+ chan->env_phase -= 4;
+ while (chan->env_phase < 0)
+ {
+ chan->env_phase += env_delay;
+ if (chan->regs[0] & 0x20)
+ chan->env_vol = (chan->env_vol + 1) & 15;
+ else if (chan->env_vol < 15)
+ chan->env_vol++;
+ }
+
+ /* vbl length counter */
+ if (chan->vbl_length > 0 && 0 == (chan->regs [0] & 0x20))
+ chan->vbl_length--;
+
+ if (0 == chan->vbl_length)
+ return 0;
+
+ /* freqsweeps */
+ if ((chan->regs[1] & 0x80) && (chan->regs[1] & 7))
+ {
+ sweep_delay = info->sync_times1[(chan->regs[1] >> 4) & 7];
+ chan->sweep_phase -= 2;
+ while (chan->sweep_phase < 0)
+ {
+ chan->sweep_phase += sweep_delay;
+ if (chan->regs[1] & 8)
+ chan->freq -= chan->freq >> (chan->regs[1] & 7);
+ else
+ chan->freq += chan->freq >> (chan->regs[1] & 7);
+ }
+ }
+
+ if ((0 == (chan->regs[1] & 8) && (chan->freq >> 16) > freq_limit[chan->regs[1] & 7])
+ || (chan->freq >> 16) < 4)
+ return 0;
+
+ chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */
+
+ while (chan->phaseacc < 0)
+ {
+ chan->phaseacc += (chan->freq >> 16);
+ chan->adder = (chan->adder + 1) & 0x0F;
+ }
+
+ if (chan->regs[0] & 0x10) /* fixed volume */
+ output = chan->regs[0] & 0x0F;
+ else
+ output = 0x0F - chan->env_vol;
+
+ if (chan->adder < (duty_lut[chan->regs[0] >> 6]))
+ output = -output;
+
+ return (int8) output;
+}
+
+/* OUTPUT TRIANGLE WAVE SAMPLE (VALUES FROM -16 to +15) */
+static int8 apu_triangle(struct nesapu_info *info, triangle_t *chan)
+{
+ int freq;
+ int8 output;
+ /* reg0: 7=holdnote, 6-0=linear length counter
+ ** reg2: low 8 bits of frequency
+ ** reg3: 7-3=length counter, 2-0=high 3 bits of frequency
+ */
+
+ if (FALSE == chan->enabled)
+ return 0;
+
+ if (FALSE == chan->counter_started && 0 == (chan->regs[0] & 0x80))
+ {
+ if (chan->write_latency)
+ chan->write_latency--;
+ if (0 == chan->write_latency)
+ chan->counter_started = TRUE;
+ }
+
+ if (chan->counter_started)
+ {
+ if (chan->linear_length > 0)
+ chan->linear_length--;
+ if (chan->vbl_length && 0 == (chan->regs[0] & 0x80))
+ chan->vbl_length--;
+
+ if (0 == chan->vbl_length)
+ return 0;
+ }
+
+ if (0 == chan->linear_length)
+ return 0;
+
+ freq = (((chan->regs[3] & 7) << 8) + chan->regs[2]) + 1;
+
+ if (freq < 4) /* inaudible */
+ return 0;
+
+ chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */
+ while (chan->phaseacc < 0)
+ {
+ chan->phaseacc += freq;
+ chan->adder = (chan->adder + 1) & 0x1F;
+
+ output = (chan->adder & 7) << 1;
+ if (chan->adder & 8)
+ output = 0x10 - output;
+ if (chan->adder & 0x10)
+ output = -output;
+
+ chan->output_vol = output;
+ }
+
+ return (int8) chan->output_vol;
+}
+
+/* OUTPUT NOISE WAVE SAMPLE (VALUES FROM -16 to +15) */
+static int8 apu_noise(struct nesapu_info *info, noise_t *chan)
+{
+ int freq, env_delay;
+ uint8 outvol;
+ uint8 output;
+
+ /* reg0: 0-3=volume, 4=envelope, 5=hold
+ ** reg2: 7=small(93 byte) sample,3-0=freq lookup
+ ** reg3: 7-4=vbl length counter
+ */
+
+ if (FALSE == chan->enabled)
+ return 0;
+
+ /* enveloping */
+ env_delay = info->sync_times1[chan->regs[0] & 0x0F];
+
+ /* decay is at a rate of (env_regs + 1) / 240 secs */
+ chan->env_phase -= 4;
+ while (chan->env_phase < 0)
+ {
+ chan->env_phase += env_delay;
+ if (chan->regs[0] & 0x20)
+ chan->env_vol = (chan->env_vol + 1) & 15;
+ else if (chan->env_vol < 15)
+ chan->env_vol++;
+ }
+
+ /* length counter */
+ if (0 == (chan->regs[0] & 0x20))
+ {
+ if (chan->vbl_length > 0)
+ chan->vbl_length--;
+ }
+
+ if (0 == chan->vbl_length)
+ return 0;
+
+ freq = noise_freq[chan->regs[2] & 0x0F];
+ chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */
+ while (chan->phaseacc < 0)
+ {
+ chan->phaseacc += freq;
+
+ chan->cur_pos++;
+ if (NOISE_SHORT == chan->cur_pos && (chan->regs[2] & 0x80))
+ chan->cur_pos = 0;
+ else if (NOISE_LONG == chan->cur_pos)
+ chan->cur_pos = 0;
+ }
+
+ if (chan->regs[0] & 0x10) /* fixed volume */
+ outvol = chan->regs[0] & 0x0F;
+ else
+ outvol = 0x0F - chan->env_vol;
+
+ output = info->noise_lut[chan->cur_pos];
+ if (output > outvol)
+ output = outvol;
+
+ if (info->noise_lut[chan->cur_pos] & 0x80) /* make it negative */
+ output = -output;
+
+ return (int8) output;
+}
+
+/* RESET DPCM PARAMETERS */
+INLINE void apu_dpcmreset(dpcm_t *chan)
+{
+ chan->address = 0xC000 + (uint16) (chan->regs[2] << 6);
+ chan->length = (uint16) (chan->regs[3] << 4) + 1;
+ chan->bits_left = chan->length << 3;
+ chan->irq_occurred = FALSE;
+ chan->enabled = TRUE; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/
+ chan->vol = 0; /* Fixed * DPCM DAC resets itself when restarted */
+}
+
+/* OUTPUT DPCM WAVE SAMPLE (VALUES FROM -64 to +63) */
+/* TODO: centerline naughtiness */
+static int8 apu_dpcm(struct nesapu_info *info, dpcm_t *chan)
+{
+ int freq, bit_pos;
+
+ /* reg0: 7=irq gen, 6=looping, 3-0=pointer to clock table
+ ** reg1: output dc level, 7 bits unsigned
+ ** reg2: 8 bits of 64-byte aligned address offset : $C000 + (value * 64)
+ ** reg3: length, (value * 16) + 1
+ */
+
+ if (chan->enabled)
+ {
+ freq = dpcm_clocks[chan->regs[0] & 0x0F];
+ chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */
+
+ while (chan->phaseacc < 0)
+ {
+ chan->phaseacc += freq;
+
+ if (0 == chan->length)
+ {
+ chan->enabled = FALSE; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/
+ chan->vol=0; /* Fixed * DPCM DAC resets itself when restarted */
+ if (chan->regs[0] & 0x40)
+ apu_dpcmreset(chan);
+ else
+ {
+ if (chan->regs[0] & 0x80) /* IRQ Generator */
+ {
+ chan->irq_occurred = TRUE;
+ n2a03_irq();
+ }
+ break;
+ }
+ }
+
+
+ chan->bits_left--;
+ bit_pos = 7 - (chan->bits_left & 7);
+ if (7 == bit_pos)
+ {
+ chan->cur_byte = chan->cpu_mem[chan->address];
+ chan->address++;
+ chan->length--;
+ }
+
+ if (chan->cur_byte & (1 << bit_pos))
+// chan->regs[1]++;
+ chan->vol+=2; /* FIXED * DPCM channel only uses the upper 6 bits of the DAC */
+ else
+// chan->regs[1]--;
+ chan->vol-=2;
+ }
+ }
+
+ if (chan->vol > 63)
+ chan->vol = 63;
+ else if (chan->vol < -64)
+ chan->vol = -64;
+
+ return (int8) (chan->vol);
+}
+
+/* WRITE REGISTER VALUE */
+INLINE void apu_regwrite(struct nesapu_info *info,int address, uint8 value)
+{
+ int chan = (address & 4) ? 1 : 0;
+
+ switch (address)
+ {
+ /* squares */
+ case APU_WRA0:
+ case APU_WRB0:
+ info->APU.squ[chan].regs[0] = value;
+ break;
+
+ case APU_WRA1:
+ case APU_WRB1:
+ info->APU.squ[chan].regs[1] = value;
+ break;
+
+ case APU_WRA2:
+ case APU_WRB2:
+ info->APU.squ[chan].regs[2] = value;
+ if (info->APU.squ[chan].enabled)
+ info->APU.squ[chan].freq = ((((info->APU.squ[chan].regs[3] & 7) << 8) + value) + 1) << 16;
+ break;
+
+ case APU_WRA3:
+ case APU_WRB3:
+ info->APU.squ[chan].regs[3] = value;
+
+ if (info->APU.squ[chan].enabled)
+ {
+ info->APU.squ[chan].vbl_length = info->vbl_times[value >> 3];
+ info->APU.squ[chan].env_vol = 0;
+ info->APU.squ[chan].freq = ((((value & 7) << 8) + info->APU.squ[chan].regs[2]) + 1) << 16;
+ }
+
+ break;
+
+ /* triangle */
+ case APU_WRC0:
+ info->APU.tri.regs[0] = value;
+
+ if (info->APU.tri.enabled)
+ { /* ??? */
+ if (FALSE == info->APU.tri.counter_started)
+ info->APU.tri.linear_length = info->sync_times2[value & 0x7F];
+ }
+
+ break;
+
+ case 0x4009:
+ /* unused */
+ info->APU.tri.regs[1] = value;
+ break;
+
+ case APU_WRC2:
+ info->APU.tri.regs[2] = value;
+ break;
+
+ case APU_WRC3:
+ info->APU.tri.regs[3] = value;
+
+ /* this is somewhat of a hack. there is some latency on the Real
+ ** Thing between when trireg0 is written to and when the linear
+ ** length counter actually begins its countdown. we want to prevent
+ ** the case where the program writes to the freq regs first, then
+ ** to reg 0, and the counter accidentally starts running because of
+ ** the sound queue's timestamp processing.
+ **
+ ** set to a few NES sample -- should be sufficient
+ **
+ ** 3 * (1789772.727 / 44100) = ~122 cycles, just around one scanline
+ **
+ ** should be plenty of time for the 6502 code to do a couple of table
+ ** dereferences and load up the other triregs
+ */
+
+ info->APU.tri.write_latency = 3;
+
+ if (info->APU.tri.enabled)
+ {
+ info->APU.tri.counter_started = FALSE;
+ info->APU.tri.vbl_length = info->vbl_times[value >> 3];
+ info->APU.tri.linear_length = info->sync_times2[info->APU.tri.regs[0] & 0x7F];
+ }
+
+ break;
+
+ /* noise */
+ case APU_WRD0:
+ info->APU.noi.regs[0] = value;
+ break;
+
+ case 0x400D:
+ /* unused */
+ info->APU.noi.regs[1] = value;
+ break;
+
+ case APU_WRD2:
+ info->APU.noi.regs[2] = value;
+ break;
+
+ case APU_WRD3:
+ info->APU.noi.regs[3] = value;
+
+ if (info->APU.noi.enabled)
+ {
+ info->APU.noi.vbl_length = info->vbl_times[value >> 3];
+ info->APU.noi.env_vol = 0; /* reset envelope */
+ }
+ break;
+
+ /* DMC */
+ case APU_WRE0:
+ info->APU.dpcm.regs[0] = value;
+ if (0 == (value & 0x80))
+ info->APU.dpcm.irq_occurred = FALSE;
+ break;
+
+ case APU_WRE1: /* 7-bit DAC */
+ //info->APU.dpcm.regs[1] = value - 0x40;
+ info->APU.dpcm.regs[1] = value & 0x7F;
+ info->APU.dpcm.vol = (info->APU.dpcm.regs[1]-64);
+ break;
+
+ case APU_WRE2:
+ info->APU.dpcm.regs[2] = value;
+ //apu_dpcmreset(info->APU.dpcm);
+ break;
+
+ case APU_WRE3:
+ info->APU.dpcm.regs[3] = value;
+ break;
+
+ case APU_IRQCTRL:
+ break;
+
+ case APU_SMASK:
+ if (value & 0x01)
+ info->APU.squ[0].enabled = TRUE;
+ else
+ {
+ info->APU.squ[0].enabled = FALSE;
+ info->APU.squ[0].vbl_length = 0;
+ }
+
+ if (value & 0x02)
+ info->APU.squ[1].enabled = TRUE;
+ else
+ {
+ info->APU.squ[1].enabled = FALSE;
+ info->APU.squ[1].vbl_length = 0;
+ }
+
+ if (value & 0x04)
+ info->APU.tri.enabled = TRUE;
+ else
+ {
+ info->APU.tri.enabled = FALSE;
+ info->APU.tri.vbl_length = 0;
+ info->APU.tri.linear_length = 0;
+ info->APU.tri.counter_started = FALSE;
+ info->APU.tri.write_latency = 0;
+ }
+
+ if (value & 0x08)
+ info->APU.noi.enabled = TRUE;
+ else
+ {
+ info->APU.noi.enabled = FALSE;
+ info->APU.noi.vbl_length = 0;
+ }
+
+ if (value & 0x10)
+ {
+ /* only reset dpcm values if DMA is finished */
+ if (FALSE == info->APU.dpcm.enabled)
+ {
+ info->APU.dpcm.enabled = TRUE;
+ apu_dpcmreset(&info->APU.dpcm);
+ }
+ }
+ else
+ info->APU.dpcm.enabled = FALSE;
+
+ info->APU.dpcm.irq_occurred = FALSE;
+
+ break;
+ default:
+#ifdef MAME_DEBUG
+logerror("invalid apu write: $%02X at $%04X\n", value, address);
+#endif
+ break;
+ }
+}
+
+/* UPDATE SOUND BUFFER USING CURRENT DATA */
+INLINE void apu_update(struct nesapu_info *info, stream_sample_t *buffer16, int samples)
+{
+ int accum;
+
+ while (samples--)
+ {
+ accum = apu_square(info, &info->APU.squ[0]);
+ accum += apu_square(info, &info->APU.squ[1]);
+ accum += apu_triangle(info, &info->APU.tri);
+ accum += apu_noise(info, &info->APU.noi);
+ accum += apu_dpcm(info, &info->APU.dpcm);
+
+ /* 8-bit clamps */
+ if (accum > 127)
+ accum = 127;
+ else if (accum < -128)
+ accum = -128;
+
+ *(buffer16++)=accum<<8;
+ }
+}
+
+/* READ VALUES FROM REGISTERS */
+INLINE uint8 apu_read(int chip,int address)
+{
+ struct nesapu_info *info = sndti_token(SOUND_NES, chip);
+ if (address == 0x0f) /*FIXED* Address $4015 has different behaviour*/
+ {
+ int readval = 0;
+ if ( info->APU.dpcm.enabled == TRUE )
+ {
+ readval |= 0x10;
+ }
+
+ if ( info->APU.dpcm.irq_occurred == TRUE )
+ {
+ readval |= 0x80;
+ }
+ return readval;
+ }
+ else
+ return info->APU.regs[address];
+}
+
+/* WRITE VALUE TO TEMP REGISTRY AND QUEUE EVENT */
+INLINE void apu_write(int chip,int address, uint8 value)
+{
+ struct nesapu_info *info = sndti_token(SOUND_NES, chip);
+ info->APU.regs[address]=value;
+ stream_update(info->stream);
+ apu_regwrite(info,address,value);
+}
+
+/* EXTERNAL INTERFACE FUNCTIONS */
+
+/* REGISTER READ/WRITE FUNCTIONS */
+READ8_HANDLER( NESPSG_0_r ) {return apu_read(0,offset);}
+READ8_HANDLER( NESPSG_1_r ) {return apu_read(1,offset);}
+WRITE8_HANDLER( NESPSG_0_w ) {apu_write(0,offset,data);}
+WRITE8_HANDLER( NESPSG_1_w ) {apu_write(1,offset,data);}
+
+/* UPDATE APU SYSTEM */
+void NESPSG_update_sound(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct nesapu_info *info = param;
+ apu_update(info, buffer[0], length);
+}
+
+
+/* INITIALIZE APU SYSTEM */
+static void *nesapu_start(int sndindex, int clock, const void *config)
+{
+ const struct NESinterface *intf = config;
+ struct nesapu_info *info;
+ int rate = clock / 4;
+ int i;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ /* Initialize global variables */
+ info->samps_per_sync = rate / ATTOSECONDS_TO_HZ(Machine->screen[0].refresh);
+ info->buffer_size = info->samps_per_sync;
+ info->real_rate = info->samps_per_sync * ATTOSECONDS_TO_HZ(Machine->screen[0].refresh);
+ info->apu_incsize = (float) (clock / (float) info->real_rate);
+
+ /* Use initializer calls */
+ create_noise(info->noise_lut, 13, NOISE_LONG);
+ create_vbltimes(info->vbl_times,vbl_length,info->samps_per_sync);
+ create_syncs(info, info->samps_per_sync);
+
+ /* Adjust buffer size if 16 bits */
+ info->buffer_size+=info->samps_per_sync;
+
+ /* Initialize individual chips */
+ (info->APU.dpcm).cpu_mem=memory_region(intf->region);
+
+ info->stream = stream_create(0, 1, rate, info, NESPSG_update_sound);
+
+ /* register for save */
+ for (i = 0; i < 2; i++)
+ {
+ state_save_register_item_array("apu", sndindex + i * 100, info->APU.squ[i].regs);
+ state_save_register_item("apu", sndindex + i * 100, info->APU.squ[i].vbl_length);
+ state_save_register_item("apu", sndindex + i * 100, info->APU.squ[i].freq);
+ state_save_register_item("apu", sndindex + i * 100, info->APU.squ[i].phaseacc);
+ state_save_register_item("apu", sndindex + i * 100, info->APU.squ[i].output_vol);
+ state_save_register_item("apu", sndindex + i * 100, info->APU.squ[i].env_phase);
+ state_save_register_item("apu", sndindex + i * 100, info->APU.squ[i].sweep_phase);
+ state_save_register_item("apu", sndindex + i * 100, info->APU.squ[i].adder);
+ state_save_register_item("apu", sndindex + i * 100, info->APU.squ[i].env_vol);
+ state_save_register_item("apu", sndindex + i * 100, info->APU.squ[i].enabled);
+ }
+
+ state_save_register_item_array("apu", sndindex, info->APU.tri.regs);
+ state_save_register_item("apu", sndindex, info->APU.tri.linear_length);
+ state_save_register_item("apu", sndindex, info->APU.tri.vbl_length);
+ state_save_register_item("apu", sndindex, info->APU.tri.write_latency);
+ state_save_register_item("apu", sndindex, info->APU.tri.phaseacc);
+ state_save_register_item("apu", sndindex, info->APU.tri.output_vol);
+ state_save_register_item("apu", sndindex, info->APU.tri.adder);
+ state_save_register_item("apu", sndindex, info->APU.tri.counter_started);
+ state_save_register_item("apu", sndindex, info->APU.tri.enabled);
+
+ state_save_register_item_array("apu", sndindex, info->APU.noi.regs);
+ state_save_register_item("apu", sndindex, info->APU.noi.cur_pos);
+ state_save_register_item("apu", sndindex, info->APU.noi.vbl_length);
+ state_save_register_item("apu", sndindex, info->APU.noi.phaseacc);
+ state_save_register_item("apu", sndindex, info->APU.noi.output_vol);
+ state_save_register_item("apu", sndindex, info->APU.noi.env_phase);
+ state_save_register_item("apu", sndindex, info->APU.noi.env_vol);
+ state_save_register_item("apu", sndindex, info->APU.noi.enabled);
+
+ state_save_register_item_array("apu", sndindex, info->APU.dpcm.regs);
+ state_save_register_item("apu", sndindex, info->APU.dpcm.address);
+ state_save_register_item("apu", sndindex, info->APU.dpcm.length);
+ state_save_register_item("apu", sndindex, info->APU.dpcm.bits_left);
+ state_save_register_item("apu", sndindex, info->APU.dpcm.phaseacc);
+ state_save_register_item("apu", sndindex, info->APU.dpcm.output_vol);
+ state_save_register_item("apu", sndindex, info->APU.dpcm.cur_byte);
+ state_save_register_item("apu", sndindex, info->APU.dpcm.enabled);
+ state_save_register_item("apu", sndindex, info->APU.dpcm.irq_occurred);
+ state_save_register_item("apu", sndindex, info->APU.dpcm.vol);
+
+ state_save_register_item_array("apu", sndindex, info->APU.regs);
+
+#ifdef USE_QUEUE
+ state_save_register_item_array("apu", sndindex, info->APU.queue);
+ state_save_register_item("apu", sndindex, info->APU.head);
+ state_save_register_item("apu", sndindex, info->APU.tail);
+#else
+ state_save_register_item("apu", sndindex, info->APU.buf_pos);
+#endif
+
+ return info;
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void nesapu_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void nesapu_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = nesapu_set_info; break;
+ case SNDINFO_PTR_START: info->start = nesapu_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "N2A03"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Nintendo custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2005, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/nes_apu.h b/src/emu/sound/nes_apu.h
new file mode 100644
index 00000000000..6f44c23cdf5
--- /dev/null
+++ b/src/emu/sound/nes_apu.h
@@ -0,0 +1,46 @@
+/*****************************************************************************
+
+ MAME/MESS NES APU CORE
+
+ Based on the Nofrendo/Nosefart NES N2A03 sound emulation core written by
+ Matthew Conte (matt@conte.com) and redesigned for use in MAME/MESS by
+ Who Wants to Know? (wwtk@mail.com)
+
+ This core is written with the advise and consent of Matthew Conte and is
+ released under the GNU Public License. This core is freely avaiable for
+ use in any freeware project, subject to the following terms:
+
+ Any modifications to this code must be duly noted in the source and
+ approved by Matthew Conte and myself prior to public submission.
+
+ *****************************************************************************
+
+ NES_APU.H
+
+ NES APU external interface.
+
+ *****************************************************************************/
+
+#ifndef NES_APU_H
+#define NES_APU_H
+
+#include "sndintrf.h"
+
+/* AN EXPLANATION
+ *
+ * The NES APU is actually integrated into the Nintendo processor.
+ * You must supply the same number of APUs as you do processors.
+ * Also make sure to correspond the memory regions to those used in the
+ * processor, as each is shared.
+ */
+struct NESinterface
+{
+ int region; /* DMC regions */
+};
+
+READ8_HANDLER( NESPSG_0_r );
+READ8_HANDLER( NESPSG_1_r );
+WRITE8_HANDLER( NESPSG_0_w );
+WRITE8_HANDLER( NESPSG_1_w );
+
+#endif
diff --git a/src/emu/sound/nes_defs.h b/src/emu/sound/nes_defs.h
new file mode 100644
index 00000000000..f22f7e2b6a6
--- /dev/null
+++ b/src/emu/sound/nes_defs.h
@@ -0,0 +1,205 @@
+/*****************************************************************************
+
+ MAME/MESS NES APU CORE
+
+ Based on the Nofrendo/Nosefart NES N2A03 sound emulation core written by
+ Matthew Conte (matt@conte.com) and redesigned for use in MAME/MESS by
+ Who Wants to Know? (wwtk@mail.com)
+
+ This core is written with the advise and consent of Matthew Conte and is
+ released under the GNU Public License. This core is freely avaiable for
+ use in any freeware project, subject to the following terms:
+
+ Any modifications to this code must be duly noted in the source and
+ approved by Matthew Conte and myself prior to public submission.
+
+ *****************************************************************************
+
+ NES_DEFS.H
+
+ NES APU internal type definitions and constants.
+
+ *****************************************************************************/
+
+#ifndef NESTYPES_H
+#define NESTYPES_H
+
+/* BOOLEAN CONSTANTS */
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/* REGULAR TYPE DEFINITIONS */
+typedef INT8 int8;
+typedef INT16 int16;
+typedef INT32 int32;
+typedef UINT8 uint8;
+typedef UINT16 uint16;
+typedef UINT32 uint32;
+typedef UINT8 boolean;
+
+
+/* QUEUE TYPES */
+#ifdef USE_QUEUE
+
+#define QUEUE_SIZE 0x2000
+#define QUEUE_MAX (QUEUE_SIZE-1)
+
+typedef struct queue_s
+{
+ int pos;
+ unsigned char reg,val;
+} queue_t;
+
+#endif
+
+/* REGISTER DEFINITIONS */
+#define APU_WRA0 0x00
+#define APU_WRA1 0x01
+#define APU_WRA2 0x02
+#define APU_WRA3 0x03
+#define APU_WRB0 0x04
+#define APU_WRB1 0x05
+#define APU_WRB2 0x06
+#define APU_WRB3 0x07
+#define APU_WRC0 0x08
+#define APU_WRC2 0x0A
+#define APU_WRC3 0x0B
+#define APU_WRD0 0x0C
+#define APU_WRD2 0x0E
+#define APU_WRD3 0x0F
+#define APU_WRE0 0x10
+#define APU_WRE1 0x11
+#define APU_WRE2 0x12
+#define APU_WRE3 0x13
+#define APU_SMASK 0x15
+#define APU_IRQCTRL 0x17
+
+#define NOISE_LONG 0x4000
+#define NOISE_SHORT 93
+
+/* CHANNEL TYPE DEFINITIONS */
+
+/* Square Wave */
+typedef struct square_s
+{
+ uint8 regs[4];
+ int vbl_length;
+ int freq;
+ float phaseacc;
+ float output_vol;
+ float env_phase;
+ float sweep_phase;
+ uint8 adder;
+ uint8 env_vol;
+ boolean enabled;
+} square_t;
+
+/* Triangle Wave */
+typedef struct triangle_s
+{
+ uint8 regs[4]; /* regs[1] unused */
+ int linear_length;
+ int vbl_length;
+ int write_latency;
+ float phaseacc;
+ float output_vol;
+ uint8 adder;
+ boolean counter_started;
+ boolean enabled;
+} triangle_t;
+
+/* Noise Wave */
+typedef struct noise_s
+{
+ uint8 regs[4]; /* regs[1] unused */
+ int cur_pos;
+ int vbl_length;
+ float phaseacc;
+ float output_vol;
+ float env_phase;
+ uint8 env_vol;
+ boolean enabled;
+} noise_t;
+
+/* DPCM Wave */
+typedef struct dpcm_s
+{
+ uint8 regs[4];
+ uint32 address;
+ uint32 length;
+ int bits_left;
+ float phaseacc;
+ float output_vol;
+ uint8 cur_byte;
+ boolean enabled;
+ boolean irq_occurred;
+ uint8 *cpu_mem;
+ signed char vol;
+} dpcm_t;
+
+/* APU type */
+typedef struct apu
+{
+ /* Sound channels */
+ square_t squ[2];
+ triangle_t tri;
+ noise_t noi;
+ dpcm_t dpcm;
+
+ /* APU registers */
+ unsigned char regs[0x17];
+
+ /* Sound pointers */
+ void *buffer;
+
+#ifdef USE_QUEUE
+
+ /* Event queue */
+ queue_t queue[QUEUE_SIZE];
+ int head,tail;
+
+#else
+
+ int buf_pos;
+
+#endif
+
+} apu_t;
+
+/* CONSTANTS */
+
+/* vblank length table used for squares, triangle, noise */
+static const uint8 vbl_length[32] =
+{
+ 5, 127, 10, 1, 19, 2, 40, 3, 80, 4, 30, 5, 7, 6, 13, 7,
+ 6, 8, 12, 9, 24, 10, 48, 11, 96, 12, 36, 13, 8, 14, 16, 15
+};
+
+/* frequency limit of square channels */
+static const int freq_limit[8] =
+{
+ 0x3FF, 0x555, 0x666, 0x71C, 0x787, 0x7C1, 0x7E0, 0x7F0,
+};
+
+/* table of noise frequencies */
+static const int noise_freq[16] =
+{
+ 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 2046
+};
+
+/* dpcm transfer freqs */
+static const int dpcm_clocks[16] =
+{
+ 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 85, 72, 54
+};
+
+/* ratios of pos/neg pulse for square waves */
+/* 2/16 = 12.5%, 4/16 = 25%, 8/16 = 50%, 12/16 = 75% */
+static const int duty_lut[4] =
+{
+ 2, 4, 8, 12
+};
+
+#endif
diff --git a/src/emu/sound/okim6295.c b/src/emu/sound/okim6295.c
new file mode 100644
index 00000000000..6b42a68e020
--- /dev/null
+++ b/src/emu/sound/okim6295.c
@@ -0,0 +1,676 @@
+/**********************************************************************************************
+ *
+ * streaming ADPCM driver
+ * by Aaron Giles
+ *
+ * Library to transcode from an ADPCM source to raw PCM.
+ * Written by Buffoni Mirko in 08/06/97
+ * References: various sources and documents.
+ *
+ * HJB 08/31/98
+ * modified to use an automatically selected oversampling factor
+ * for the current sample rate
+ *
+ * Mish 21/7/99
+ * Updated to allow multiple OKI chips with different sample rates
+ *
+ * R. Belmont 31/10/2003
+ * Updated to allow a driver to use both MSM6295s and "raw" ADPCM voices (gcpinbal)
+ * Also added some error trapping for MAME_DEBUG builds
+ *
+ **********************************************************************************************/
+
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "okim6295.h"
+
+#define MAX_SAMPLE_CHUNK 10000
+
+
+/* struct describing a single playing ADPCM voice */
+struct ADPCMVoice
+{
+ UINT8 playing; /* 1 if we are actively playing */
+
+ UINT32 base_offset; /* pointer to the base memory location */
+ UINT32 sample; /* current sample number */
+ UINT32 count; /* total samples to play */
+
+ struct adpcm_state adpcm;/* current ADPCM state */
+ UINT32 volume; /* output volume */
+};
+
+struct okim6295
+{
+ #define OKIM6295_VOICES 4
+ struct ADPCMVoice voice[OKIM6295_VOICES];
+ INT32 command;
+ INT32 bank_offset;
+ UINT8 *region_base; /* pointer to the base of the region */
+ sound_stream *stream; /* which stream are we playing on? */
+ UINT32 master_clock; /* master clock frequency */
+};
+
+/* step size index shift table */
+static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
+
+/* lookup table for the precomputed difference */
+static int diff_lookup[49*16];
+
+/* volume lookup table */
+static UINT32 volume_table[16];
+
+/* tables computed? */
+static int tables_computed = 0;
+
+/* useful interfaces */
+const struct OKIM6295interface okim6295_interface_region_1_pin7high = { REGION_SOUND1, 1 };
+const struct OKIM6295interface okim6295_interface_region_2_pin7high = { REGION_SOUND2, 1 };
+const struct OKIM6295interface okim6295_interface_region_3_pin7high = { REGION_SOUND3, 1 };
+const struct OKIM6295interface okim6295_interface_region_4_pin7high = { REGION_SOUND4, 1 };
+
+const struct OKIM6295interface okim6295_interface_region_1_pin7low = { REGION_SOUND1, 0 };
+const struct OKIM6295interface okim6295_interface_region_2_pin7low = { REGION_SOUND2, 0 };
+const struct OKIM6295interface okim6295_interface_region_3_pin7low = { REGION_SOUND3, 0 };
+const struct OKIM6295interface okim6295_interface_region_4_pin7low = { REGION_SOUND4, 0 };
+
+/**********************************************************************************************
+
+ compute_tables -- compute the difference tables
+
+***********************************************************************************************/
+
+static void compute_tables(void)
+{
+ /* nibble to bit map */
+ static int nbl2bit[16][4] =
+ {
+ { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
+ { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
+ {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
+ {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
+ };
+
+ int step, nib;
+
+ /* loop over all possible steps */
+ for (step = 0; step <= 48; step++)
+ {
+ /* compute the step value */
+ int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step));
+
+ /* loop over all nibbles and compute the difference */
+ for (nib = 0; nib < 16; nib++)
+ {
+ diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
+ (stepval * nbl2bit[nib][1] +
+ stepval/2 * nbl2bit[nib][2] +
+ stepval/4 * nbl2bit[nib][3] +
+ stepval/8);
+ }
+ }
+
+ /* generate the OKI6295 volume table */
+ for (step = 0; step < 16; step++)
+ {
+ double out = 256.0;
+ int vol = step;
+
+ /* 3dB per step */
+ while (vol-- > 0)
+ out /= 1.412537545; /* = 10 ^ (3/20) = 3dB */
+ volume_table[step] = (UINT32)out;
+ }
+
+ tables_computed = 1;
+}
+
+
+
+/**********************************************************************************************
+
+ reset_adpcm -- reset the ADPCM stream
+
+***********************************************************************************************/
+
+void reset_adpcm(struct adpcm_state *state)
+{
+ /* make sure we have our tables */
+ if (!tables_computed)
+ compute_tables();
+
+ /* reset the signal/step */
+ state->signal = -2;
+ state->step = 0;
+}
+
+
+
+/**********************************************************************************************
+
+ clock_adpcm -- clock the next ADPCM byte
+
+***********************************************************************************************/
+
+INT16 clock_adpcm(struct adpcm_state *state, UINT8 nibble)
+{
+ state->signal += diff_lookup[state->step * 16 + (nibble & 15)];
+
+ /* clamp to the maximum */
+ if (state->signal > 2047)
+ state->signal = 2047;
+ else if (state->signal < -2048)
+ state->signal = -2048;
+
+ /* adjust the step size and clamp */
+ state->step += index_shift[nibble & 7];
+ if (state->step > 48)
+ state->step = 48;
+ else if (state->step < 0)
+ state->step = 0;
+
+ /* return the signal scaled up to 32767 */
+ return state->signal << 4;
+}
+
+
+
+/**********************************************************************************************
+
+ generate_adpcm -- general ADPCM decoding routine
+
+***********************************************************************************************/
+
+static void generate_adpcm(struct okim6295 *chip, struct ADPCMVoice *voice, INT16 *buffer, int samples)
+{
+ /* if this voice is active */
+ if (voice->playing)
+ {
+ UINT8 *base = chip->region_base + chip->bank_offset + voice->base_offset;
+ int sample = voice->sample;
+ int count = voice->count;
+
+ /* loop while we still have samples to generate */
+ while (samples)
+ {
+ /* compute the new amplitude and update the current step */
+ int nibble = base[sample / 2] >> (((sample & 1) << 2) ^ 4);
+
+ /* output to the buffer, scaling by the volume */
+ *buffer++ = clock_adpcm(&voice->adpcm, nibble) * voice->volume / 256;
+ samples--;
+
+ /* next! */
+ if (++sample >= count)
+ {
+ voice->playing = 0;
+ break;
+ }
+ }
+
+ /* update the parameters */
+ voice->sample = sample;
+ }
+
+ /* fill the rest with silence */
+ while (samples--)
+ *buffer++ = 0;
+}
+
+
+
+/**********************************************************************************************
+ *
+ * OKIM 6295 ADPCM chip:
+ *
+ * Command bytes are sent:
+ *
+ * 1xxx xxxx = start of 2-byte command sequence, xxxxxxx is the sample number to trigger
+ * abcd vvvv = second half of command; one of the abcd bits is set to indicate which voice
+ * the v bits seem to be volumed
+ *
+ * 0abc d000 = stop playing; one or more of the abcd bits is set to indicate which voice(s)
+ *
+ * Status is read:
+ *
+ * ???? abcd = one bit per voice, set to 0 if nothing is playing, or 1 if it is active
+ *
+***********************************************************************************************/
+
+
+/**********************************************************************************************
+
+ okim6295_update -- update the sound chip so that it is in sync with CPU execution
+
+***********************************************************************************************/
+
+static void okim6295_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ struct okim6295 *chip = param;
+ int i;
+
+ memset(outputs[0], 0, samples * sizeof(*outputs[0]));
+
+ for (i = 0; i < OKIM6295_VOICES; i++)
+ {
+ struct ADPCMVoice *voice = &chip->voice[i];
+ stream_sample_t *buffer = outputs[0];
+ INT16 sample_data[MAX_SAMPLE_CHUNK];
+ int remaining = samples;
+
+ /* loop while we have samples remaining */
+ while (remaining)
+ {
+ int samples = (remaining > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : remaining;
+ int samp;
+
+ generate_adpcm(chip, voice, sample_data, samples);
+ for (samp = 0; samp < samples; samp++)
+ *buffer++ += sample_data[samp];
+
+ remaining -= samples;
+ }
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ state save support for MAME
+
+***********************************************************************************************/
+
+static void adpcm_state_save_register(struct ADPCMVoice *voice, int i)
+{
+ char buf[20];
+
+ sprintf(buf,"ADPCM");
+
+ state_save_register_item(buf, i, voice->playing);
+ state_save_register_item(buf, i, voice->sample);
+ state_save_register_item(buf, i, voice->count);
+ state_save_register_item(buf, i, voice->adpcm.signal);
+ state_save_register_item(buf, i, voice->adpcm.step);
+ state_save_register_item(buf, i, voice->volume);
+ state_save_register_item(buf, i, voice->base_offset);
+}
+
+static void okim6295_state_save_register(struct okim6295 *info, int sndindex)
+{
+ int j;
+ char buf[20];
+
+ sprintf(buf,"OKIM6295");
+
+ state_save_register_item(buf, sndindex, info->command);
+ state_save_register_item(buf, sndindex, info->bank_offset);
+ for (j = 0; j < OKIM6295_VOICES; j++)
+ adpcm_state_save_register(&info->voice[j], sndindex * 4 + j);
+}
+
+
+
+/**********************************************************************************************
+
+ OKIM6295_start -- start emulation of an OKIM6295-compatible chip
+
+***********************************************************************************************/
+
+static void *okim6295_start(int sndindex, int clock, const void *config)
+{
+ const struct OKIM6295interface *intf = config;
+ struct okim6295 *info;
+ int voice;
+ int divisor = intf->pin7 ? 132 : 165;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ compute_tables();
+
+ info->command = -1;
+ info->bank_offset = 0;
+ info->region_base = memory_region(intf->region);
+
+ info->master_clock = clock;
+
+ /* generate the name and create the stream */
+ info->stream = stream_create(0, 1, clock/divisor, info, okim6295_update);
+
+ /* initialize the voices */
+ for (voice = 0; voice < OKIM6295_VOICES; voice++)
+ {
+ /* initialize the rest of the structure */
+ info->voice[voice].volume = 255;
+ reset_adpcm(&info->voice[voice].adpcm);
+ }
+
+ okim6295_state_save_register(info, sndindex);
+
+ /* success */
+ return info;
+}
+
+
+
+/**********************************************************************************************
+
+ OKIM6295_stop -- stop emulation of an OKIM6295-compatible chip
+
+***********************************************************************************************/
+
+static void okim6295_reset(void *chip)
+{
+ struct okim6295 *info = chip;
+ int i;
+
+ stream_update(info->stream);
+ for (i = 0; i < OKIM6295_VOICES; i++)
+ info->voice[i].playing = 0;
+}
+
+
+
+/**********************************************************************************************
+
+ OKIM6295_set_bank_base -- set the base of the bank for a given voice on a given chip
+
+***********************************************************************************************/
+
+void OKIM6295_set_bank_base(int which, int base)
+{
+ struct okim6295 *info = sndti_token(SOUND_OKIM6295, which);
+ stream_update(info->stream);
+ info->bank_offset = base;
+}
+
+
+
+/**********************************************************************************************
+
+ OKIM6295_set_pin7 -- adjust pin 7, which controls the internal clock division
+
+***********************************************************************************************/
+
+void OKIM6295_set_pin7(int which, int pin7)
+{
+ struct okim6295 *info = sndti_token(SOUND_OKIM6295, which);
+ int divisor = pin7 ? 132 : 165;
+
+ stream_set_sample_rate(info->stream, info->master_clock/divisor);
+}
+
+
+/**********************************************************************************************
+
+ OKIM6295_status_r -- read the status port of an OKIM6295-compatible chip
+
+***********************************************************************************************/
+
+static int OKIM6295_status_r(int num)
+{
+ struct okim6295 *info = sndti_token(SOUND_OKIM6295, num);
+ int i, result;
+
+ result = 0xf0; /* naname expects bits 4-7 to be 1 */
+
+ /* set the bit to 1 if something is playing on a given channel */
+ stream_update(info->stream);
+ for (i = 0; i < OKIM6295_VOICES; i++)
+ {
+ struct ADPCMVoice *voice = &info->voice[i];
+
+ /* set the bit if it's playing */
+ if (voice->playing)
+ result |= 1 << i;
+ }
+
+ return result;
+}
+
+
+
+/**********************************************************************************************
+
+ OKIM6295_data_w -- write to the data port of an OKIM6295-compatible chip
+
+***********************************************************************************************/
+
+static void OKIM6295_data_w(int num, int data)
+{
+ struct okim6295 *info = sndti_token(SOUND_OKIM6295, num);
+
+ /* if a command is pending, process the second half */
+ if (info->command != -1)
+ {
+ int temp = data >> 4, i, start, stop;
+ unsigned char *base;
+
+ /* update the stream */
+ stream_update(info->stream);
+
+ /* determine which voice(s) (voice is set by a 1 bit in the upper 4 bits of the second byte) */
+ for (i = 0; i < OKIM6295_VOICES; i++, temp >>= 1)
+ {
+ if (temp & 1)
+ {
+ struct ADPCMVoice *voice = &info->voice[i];
+
+ /* determine the start/stop positions */
+ base = &info->region_base[info->bank_offset + info->command * 8];
+ start = ((base[0] << 16) + (base[1] << 8) + base[2]) & 0x3ffff;
+ stop = ((base[3] << 16) + (base[4] << 8) + base[5]) & 0x3ffff;
+
+ /* set up the voice to play this sample */
+ if (start < stop)
+ {
+ if (!voice->playing) /* fixes Got-cha and Steel Force */
+ {
+ voice->playing = 1;
+ voice->base_offset = start;
+ voice->sample = 0;
+ voice->count = 2 * (stop - start + 1);
+
+ /* also reset the ADPCM parameters */
+ reset_adpcm(&voice->adpcm);
+ voice->volume = volume_table[data & 0x0f];
+ }
+ else
+ {
+ logerror("OKIM6295:%d requested to play sample %02x on non-stopped voice\n",num,info->command);
+ }
+ }
+ /* invalid samples go here */
+ else
+ {
+ logerror("OKIM6295:%d requested to play invalid sample %02x\n",num,info->command);
+ voice->playing = 0;
+ }
+ }
+ }
+
+ /* reset the command */
+ info->command = -1;
+ }
+
+ /* if this is the start of a command, remember the sample number for next time */
+ else if (data & 0x80)
+ {
+ info->command = data & 0x7f;
+ }
+
+ /* otherwise, see if this is a silence command */
+ else
+ {
+ int temp = data >> 3, i;
+
+ /* update the stream, then turn it off */
+ stream_update(info->stream);
+
+ /* determine which voice(s) (voice is set by a 1 bit in bits 3-6 of the command */
+ for (i = 0; i < 4; i++, temp >>= 1)
+ {
+ if (temp & 1)
+ {
+ struct ADPCMVoice *voice = &info->voice[i];
+
+ voice->playing = 0;
+ }
+ }
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ OKIM6295_status_0_r -- generic status read functions
+ OKIM6295_status_1_r
+
+***********************************************************************************************/
+
+READ8_HANDLER( OKIM6295_status_0_r )
+{
+ return OKIM6295_status_r(0);
+}
+
+READ8_HANDLER( OKIM6295_status_1_r )
+{
+ return OKIM6295_status_r(1);
+}
+
+READ8_HANDLER( OKIM6295_status_2_r )
+{
+ return OKIM6295_status_r(2);
+}
+
+READ16_HANDLER( OKIM6295_status_0_lsb_r )
+{
+ return OKIM6295_status_r(0);
+}
+
+READ16_HANDLER( OKIM6295_status_1_lsb_r )
+{
+ return OKIM6295_status_r(1);
+}
+
+READ16_HANDLER( OKIM6295_status_2_lsb_r )
+{
+ return OKIM6295_status_r(2);
+}
+
+READ16_HANDLER( OKIM6295_status_0_msb_r )
+{
+ return OKIM6295_status_r(0) << 8;
+}
+
+READ16_HANDLER( OKIM6295_status_1_msb_r )
+{
+ return OKIM6295_status_r(1) << 8;
+}
+
+READ16_HANDLER( OKIM6295_status_2_msb_r )
+{
+ return OKIM6295_status_r(2) << 8;
+}
+
+
+
+/**********************************************************************************************
+
+ OKIM6295_data_0_w -- generic data write functions
+ OKIM6295_data_1_w
+
+***********************************************************************************************/
+
+WRITE8_HANDLER( OKIM6295_data_0_w )
+{
+ OKIM6295_data_w(0, data);
+}
+
+WRITE8_HANDLER( OKIM6295_data_1_w )
+{
+ OKIM6295_data_w(1, data);
+}
+
+WRITE8_HANDLER( OKIM6295_data_2_w )
+{
+ OKIM6295_data_w(2, data);
+}
+
+WRITE16_HANDLER( OKIM6295_data_0_lsb_w )
+{
+ if (ACCESSING_LSB)
+ OKIM6295_data_w(0, data & 0xff);
+}
+
+WRITE16_HANDLER( OKIM6295_data_1_lsb_w )
+{
+ if (ACCESSING_LSB)
+ OKIM6295_data_w(1, data & 0xff);
+}
+
+WRITE16_HANDLER( OKIM6295_data_2_lsb_w )
+{
+ if (ACCESSING_LSB)
+ OKIM6295_data_w(2, data & 0xff);
+}
+
+WRITE16_HANDLER( OKIM6295_data_0_msb_w )
+{
+ if (ACCESSING_MSB)
+ OKIM6295_data_w(0, data >> 8);
+}
+
+WRITE16_HANDLER( OKIM6295_data_1_msb_w )
+{
+ if (ACCESSING_MSB)
+ OKIM6295_data_w(1, data >> 8);
+}
+
+WRITE16_HANDLER( OKIM6295_data_2_msb_w )
+{
+ if (ACCESSING_MSB)
+ OKIM6295_data_w(2, data >> 8);
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void okim6295_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void okim6295_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = okim6295_set_info; break;
+ case SNDINFO_PTR_START: info->start = okim6295_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = okim6295_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "OKI6295"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "OKI ADPCM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/okim6295.h b/src/emu/sound/okim6295.h
new file mode 100644
index 00000000000..b11a171e44b
--- /dev/null
+++ b/src/emu/sound/okim6295.h
@@ -0,0 +1,65 @@
+#ifndef OKIM6295_H
+#define OKIM6295_H
+
+/* an interface for the OKIM6295 and similar chips */
+
+/*
+ Note about the playback frequency: the external clock is internally divided,
+ depending on pin 7, by 132 (high) or 165 (low).
+*/
+struct OKIM6295interface
+{
+ int region; /* memory region where the sample ROM lives */
+ int pin7;
+};
+
+extern const struct OKIM6295interface okim6295_interface_region_1_pin7high;
+extern const struct OKIM6295interface okim6295_interface_region_2_pin7high;
+extern const struct OKIM6295interface okim6295_interface_region_3_pin7high;
+extern const struct OKIM6295interface okim6295_interface_region_4_pin7high;
+
+extern const struct OKIM6295interface okim6295_interface_region_1_pin7low;
+extern const struct OKIM6295interface okim6295_interface_region_2_pin7low;
+extern const struct OKIM6295interface okim6295_interface_region_3_pin7low;
+extern const struct OKIM6295interface okim6295_interface_region_4_pin7low;
+
+
+
+
+
+void OKIM6295_set_bank_base(int which, int base);
+void OKIM6295_set_pin7(int which, int pin7);
+
+READ8_HANDLER( OKIM6295_status_0_r );
+READ8_HANDLER( OKIM6295_status_1_r );
+READ8_HANDLER( OKIM6295_status_2_r );
+READ16_HANDLER( OKIM6295_status_0_lsb_r );
+READ16_HANDLER( OKIM6295_status_1_lsb_r );
+READ16_HANDLER( OKIM6295_status_2_lsb_r );
+READ16_HANDLER( OKIM6295_status_0_msb_r );
+READ16_HANDLER( OKIM6295_status_1_msb_r );
+READ16_HANDLER( OKIM6295_status_2_msb_r );
+WRITE8_HANDLER( OKIM6295_data_0_w );
+WRITE8_HANDLER( OKIM6295_data_1_w );
+WRITE8_HANDLER( OKIM6295_data_2_w );
+WRITE16_HANDLER( OKIM6295_data_0_lsb_w );
+WRITE16_HANDLER( OKIM6295_data_1_lsb_w );
+WRITE16_HANDLER( OKIM6295_data_2_lsb_w );
+WRITE16_HANDLER( OKIM6295_data_0_msb_w );
+WRITE16_HANDLER( OKIM6295_data_1_msb_w );
+WRITE16_HANDLER( OKIM6295_data_2_msb_w );
+
+/*
+ To help the various custom ADPCM generators out there,
+ the following routines may be used.
+*/
+struct adpcm_state
+{
+ INT32 signal;
+ INT32 step;
+};
+void reset_adpcm(struct adpcm_state *state);
+INT16 clock_adpcm(struct adpcm_state *state, UINT8 nibble);
+
+
+#endif
diff --git a/src/emu/sound/pokey.c b/src/emu/sound/pokey.c
new file mode 100644
index 00000000000..fcb1b097aaf
--- /dev/null
+++ b/src/emu/sound/pokey.c
@@ -0,0 +1,1599 @@
+/*****************************************************************************
+ *
+ * POKEY chip emulator 4.51
+ * Copyright (c) 2000-2007 by The MAME Team
+ *
+ * Based on original info found in Ron Fries' Pokey emulator,
+ * with additions by Brad Oliver, Eric Smith and Juergen Buchmueller,
+ * paddle (a/d conversion) details from the Atari 400/800 Hardware Manual.
+ * Polynome algorithms according to info supplied by Perry McFarlane.
+ *
+ * This code is subject to the MAME license, which besides other
+ * things means it is distributed as is, no warranties whatsoever.
+ * For more details read mame.txt that comes with MAME.
+ *
+ * 4.51:
+ * - changed to use the attotime datatype
+ * 4.5:
+ * - changed the 9/17 bit polynomial formulas such that the values
+ * required for the Tempest Pokey protection will be found.
+ * Tempest expects the upper 4 bits of the RNG to appear in the
+ * lower 4 bits after four cycles, so there has to be a shift
+ * of 1 per cycle (which was not the case before). Bits #6-#13 of the
+ * new RNG give this expected result now, bits #0-7 of the 9 bit poly.
+ * - reading the RNG returns the shift register contents ^ 0xff.
+ * That way resetting the Pokey with SKCTL (which resets the
+ * polynome shifters to 0) returns the expected 0xff value.
+ * 4.4:
+ * - reversed sample values to make OFF channels produce a zero signal.
+ * actually de-reversed them; don't remember that I reversed them ;-/
+ * 4.3:
+ * - for POT inputs returning zero, immediately assert the ALLPOT
+ * bit after POTGO is written, otherwise start trigger timer
+ * depending on SK_PADDLE mode, either 1-228 scanlines or 1-2
+ * scanlines, depending on the SK_PADDLE bit of SKCTL.
+ * 4.2:
+ * - half volume for channels which are inaudible (this should be
+ * close to the real thing).
+ * 4.1:
+ * - default gain increased to closely match the old code.
+ * - random numbers repeat rate depends on POLY9 flag too!
+ * - verified sound output with many, many Atari 800 games,
+ * including the SUPPRESS_INAUDIBLE optimizations.
+ * 4.0:
+ * - rewritten from scratch.
+ * - 16bit stream interface.
+ * - serout ready/complete delayed interrupts.
+ * - reworked pot analog/digital conversion timing.
+ * - optional non-indexing pokey update functions.
+ *
+ *****************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "pokey.h"
+
+/*
+ * Defining this produces much more (about twice as much)
+ * but also more efficient code. Ideally this should be set
+ * for processors with big code cache and for healthy compilers :)
+ */
+#ifndef BIG_SWITCH
+#ifndef HEAVY_MACRO_USAGE
+#define HEAVY_MACRO_USAGE 1
+#endif
+#else
+#define HEAVY_MACRO_USAGE BIG_SWITCH
+#endif
+
+#define SUPPRESS_INAUDIBLE 1
+
+/* Four channels with a range of 0..32767 and volume 0..15 */
+//#define POKEY_DEFAULT_GAIN (32767/15/4)
+
+/*
+ * But we raise the gain and risk clipping, the old Pokey did
+ * this too. It defined POKEY_DEFAULT_GAIN 6 and this was
+ * 6 * 15 * 4 = 360, 360/256 = 1.40625
+ * I use 15/11 = 1.3636, so this is a little lower.
+ */
+#define POKEY_DEFAULT_GAIN (32767/11/4)
+
+#define VERBOSE 0
+#define VERBOSE_SOUND 0
+#define VERBOSE_TIMER 0
+#define VERBOSE_POLY 0
+#define VERBOSE_RAND 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+#if VERBOSE_SOUND
+#define LOG_SOUND(x) logerror x
+#else
+#define LOG_SOUND(x)
+#endif
+
+#if VERBOSE_TIMER
+#define LOG_TIMER(x) logerror x
+#else
+#define LOG_TIMER(x)
+#endif
+
+#if VERBOSE_POLY
+#define LOG_POLY(x) logerror x
+#else
+#define LOG_POLY(x)
+#endif
+
+#if VERBOSE_RAND
+#define LOG_RAND(x) logerror x
+#else
+#define LOG_RAND(x)
+#endif
+
+#define CHAN1 0
+#define CHAN2 1
+#define CHAN3 2
+#define CHAN4 3
+
+#define TIMER1 0
+#define TIMER2 1
+#define TIMER4 2
+
+/* values to add to the divisors for the different modes */
+#define DIVADD_LOCLK 1
+#define DIVADD_HICLK 4
+#define DIVADD_HICLK_JOINED 7
+
+/* AUDCx */
+#define NOTPOLY5 0x80 /* selects POLY5 or direct CLOCK */
+#define POLY4 0x40 /* selects POLY4 or POLY17 */
+#define PURE 0x20 /* selects POLY4/17 or PURE tone */
+#define VOLUME_ONLY 0x10 /* selects VOLUME OUTPUT ONLY */
+#define VOLUME_MASK 0x0f /* volume mask */
+
+/* AUDCTL */
+#define POLY9 0x80 /* selects POLY9 or POLY17 */
+#define CH1_HICLK 0x40 /* selects 1.78979 MHz for Ch 1 */
+#define CH3_HICLK 0x20 /* selects 1.78979 MHz for Ch 3 */
+#define CH12_JOINED 0x10 /* clocks channel 1 w/channel 2 */
+#define CH34_JOINED 0x08 /* clocks channel 3 w/channel 4 */
+#define CH1_FILTER 0x04 /* selects channel 1 high pass filter */
+#define CH2_FILTER 0x02 /* selects channel 2 high pass filter */
+#define CLK_15KHZ 0x01 /* selects 15.6999 kHz or 63.9211 kHz */
+
+/* IRQEN (D20E) */
+#define IRQ_BREAK 0x80 /* BREAK key pressed interrupt */
+#define IRQ_KEYBD 0x40 /* keyboard data ready interrupt */
+#define IRQ_SERIN 0x20 /* serial input data ready interrupt */
+#define IRQ_SEROR 0x10 /* serial output register ready interrupt */
+#define IRQ_SEROC 0x08 /* serial output complete interrupt */
+#define IRQ_TIMR4 0x04 /* timer channel #4 interrupt */
+#define IRQ_TIMR2 0x02 /* timer channel #2 interrupt */
+#define IRQ_TIMR1 0x01 /* timer channel #1 interrupt */
+
+/* SKSTAT (R/D20F) */
+#define SK_FRAME 0x80 /* serial framing error */
+#define SK_OVERRUN 0x40 /* serial overrun error */
+#define SK_KBERR 0x20 /* keyboard overrun error */
+#define SK_SERIN 0x10 /* serial input high */
+#define SK_SHIFT 0x08 /* shift key pressed */
+#define SK_KEYBD 0x04 /* keyboard key pressed */
+#define SK_SEROUT 0x02 /* serial output active */
+
+/* SKCTL (W/D20F) */
+#define SK_BREAK 0x80 /* serial out break signal */
+#define SK_BPS 0x70 /* bits per second */
+#define SK_FM 0x08 /* FM mode */
+#define SK_PADDLE 0x04 /* fast paddle a/d conversion */
+#define SK_RESET 0x03 /* reset serial/keyboard interface */
+
+#define DIV_64 28 /* divisor for 1.78979 MHz clock to 63.9211 kHz */
+#define DIV_15 114 /* divisor for 1.78979 MHz clock to 15.6999 kHz */
+
+struct POKEYregisters
+{
+ INT32 counter[4]; /* channel counter */
+ INT32 divisor[4]; /* channel divisor (modulo value) */
+ UINT32 volume[4]; /* channel volume - derived */
+ UINT8 output[4]; /* channel output signal (1 active, 0 inactive) */
+ UINT8 audible[4]; /* channel plays an audible tone/effect */
+ UINT32 samplerate_24_8; /* sample rate in 24.8 format */
+ UINT32 samplepos_fract; /* sample position fractional part */
+ UINT32 samplepos_whole; /* sample position whole part */
+ UINT32 polyadjust; /* polynome adjustment */
+ UINT32 p4; /* poly4 index */
+ UINT32 p5; /* poly5 index */
+ UINT32 p9; /* poly9 index */
+ UINT32 p17; /* poly17 index */
+ UINT32 r9; /* rand9 index */
+ UINT32 r17; /* rand17 index */
+ UINT32 clockmult; /* clock multiplier */
+ sound_stream * channel; /* streams channel */
+ emu_timer *timer[3]; /* timers for channel 1,2 and 4 events */
+ attotime timer_period[3]; /* computed periods for these timers */
+ int timer_param[3]; /* computed parameters for these timers */
+ emu_timer *rtimer; /* timer for calculating the random offset */
+ emu_timer *ptimer[8]; /* pot timers */
+ read8_handler pot_r[8];
+ read8_handler allpot_r;
+ read8_handler serin_r;
+ write8_handler serout_w;
+ void (*interrupt_cb)(int mask);
+ UINT8 AUDF[4]; /* AUDFx (D200, D202, D204, D206) */
+ UINT8 AUDC[4]; /* AUDCx (D201, D203, D205, D207) */
+ UINT8 POTx[8]; /* POTx (R/D200-D207) */
+ UINT8 AUDCTL; /* AUDCTL (W/D208) */
+ UINT8 ALLPOT; /* ALLPOT (R/D208) */
+ UINT8 KBCODE; /* KBCODE (R/D209) */
+ UINT8 RANDOM; /* RANDOM (R/D20A) */
+ UINT8 SERIN; /* SERIN (R/D20D) */
+ UINT8 SEROUT; /* SEROUT (W/D20D) */
+ UINT8 IRQST; /* IRQST (R/D20E) */
+ UINT8 IRQEN; /* IRQEN (W/D20E) */
+ UINT8 SKSTAT; /* SKSTAT (R/D20F) */
+ UINT8 SKCTL; /* SKCTL (W/D20F) */
+ struct POKEYinterface intf;
+ attotime clock_period;
+ attotime ad_time_fast;
+ attotime ad_time_slow;
+ int index;
+
+ UINT8 poly4[0x0f];
+ UINT8 poly5[0x1f];
+ UINT8 poly9[0x1ff];
+ UINT8 poly17[0x1ffff];
+
+ UINT8 rand9[0x1ff];
+ UINT8 rand17[0x1ffff];
+};
+
+
+#define P4(chip) chip->poly4[chip->p4]
+#define P5(chip) chip->poly5[chip->p5]
+#define P9(chip) chip->poly9[chip->p9]
+#define P17(chip) chip->poly17[chip->p17]
+
+static TIMER_CALLBACK_PTR( pokey_timer_expire_1 );
+static TIMER_CALLBACK_PTR( pokey_timer_expire_2 );
+static TIMER_CALLBACK_PTR( pokey_timer_expire_4 );
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_0 );
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_1 );
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_2 );
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_3 );
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_4 );
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_5 );
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_6 );
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_7 );
+
+
+#define SAMPLE -1
+
+#define ADJUST_EVENT(chip) \
+ chip->counter[CHAN1] -= event; \
+ chip->counter[CHAN2] -= event; \
+ chip->counter[CHAN3] -= event; \
+ chip->counter[CHAN4] -= event; \
+ chip->samplepos_whole -= event; \
+ chip->polyadjust += event
+
+#if SUPPRESS_INAUDIBLE
+
+#define PROCESS_CHANNEL(chip,ch) \
+ int toggle = 0; \
+ ADJUST_EVENT(chip); \
+ /* reset the channel counter */ \
+ if( chip->audible[ch] ) \
+ chip->counter[ch] = chip->divisor[ch]; \
+ else \
+ chip->counter[ch] = 0x7fffffff; \
+ chip->p4 = (chip->p4+chip->polyadjust)%0x0000f; \
+ chip->p5 = (chip->p5+chip->polyadjust)%0x0001f; \
+ chip->p9 = (chip->p9+chip->polyadjust)%0x001ff; \
+ chip->p17 = (chip->p17+chip->polyadjust)%0x1ffff; \
+ chip->polyadjust = 0; \
+ if( (chip->AUDC[ch] & NOTPOLY5) || P5(chip) ) \
+ { \
+ if( chip->AUDC[ch] & PURE ) \
+ toggle = 1; \
+ else \
+ if( chip->AUDC[ch] & POLY4 ) \
+ toggle = chip->output[ch] == !P4(chip); \
+ else \
+ if( chip->AUDCTL & POLY9 ) \
+ toggle = chip->output[ch] == !P9(chip); \
+ else \
+ toggle = chip->output[ch] == !P17(chip); \
+ } \
+ if( toggle ) \
+ { \
+ if( chip->audible[ch] ) \
+ { \
+ if( chip->output[ch] ) \
+ sum -= chip->volume[ch]; \
+ else \
+ sum += chip->volume[ch]; \
+ } \
+ chip->output[ch] ^= 1; \
+ } \
+ /* is this a filtering channel (3/4) and is the filter active? */ \
+ if( chip->AUDCTL & ((CH1_FILTER|CH2_FILTER) & (0x10 >> ch)) ) \
+ { \
+ if( chip->output[ch-2] ) \
+ { \
+ chip->output[ch-2] = 0; \
+ if( chip->audible[ch] ) \
+ sum -= chip->volume[ch-2]; \
+ } \
+ } \
+
+#else
+
+#define PROCESS_CHANNEL(chip,ch) \
+ int toggle = 0; \
+ ADJUST_EVENT(chip); \
+ /* reset the channel counter */ \
+ chip->counter[ch] = p[chip].divisor[ch]; \
+ chip->p4 = (chip->p4+chip->polyadjust)%0x0000f; \
+ chip->p5 = (chip->p5+chip->polyadjust)%0x0001f; \
+ chip->p9 = (chip->p9+chip->polyadjust)%0x001ff; \
+ chip->p17 = (chip->p17+chip->polyadjust)%0x1ffff; \
+ chip->polyadjust = 0; \
+ if( (chip->AUDC[ch] & NOTPOLY5) || P5(chip) ) \
+ { \
+ if( chip->AUDC[ch] & PURE ) \
+ toggle = 1; \
+ else \
+ if( chip->AUDC[ch] & POLY4 ) \
+ toggle = chip->output[ch] == !P4(chip); \
+ else \
+ if( chip->AUDCTL & POLY9 ) \
+ toggle = chip->output[ch] == !P9(chip); \
+ else \
+ toggle = chip->output[ch] == !P17(chip); \
+ } \
+ if( toggle ) \
+ { \
+ if( chip->output[ch] ) \
+ sum -= chip->volume[ch]; \
+ else \
+ sum += chip->volume[ch]; \
+ chip->output[ch] ^= 1; \
+ } \
+ /* is this a filtering channel (3/4) and is the filter active? */ \
+ if( chip->AUDCTL & ((CH1_FILTER|CH2_FILTER) & (0x10 >> ch)) ) \
+ { \
+ if( chip->output[ch-2] ) \
+ { \
+ chip->output[ch-2] = 0; \
+ sum -= chip->volume[ch-2]; \
+ } \
+ } \
+
+#endif
+
+#define PROCESS_SAMPLE(chip) \
+ ADJUST_EVENT(chip); \
+ /* adjust the sample position */ \
+ chip->samplepos_whole++; \
+ /* store sum of output signals into the buffer */ \
+ *buffer++ = (sum > 0x7fff) ? 0x7fff : sum; \
+ length--
+
+#if HEAVY_MACRO_USAGE
+
+/*
+ * This version of PROCESS_POKEY repeats the search for the minimum
+ * event value without using an index to the channel. That way the
+ * PROCESS_CHANNEL macros can be called with fixed values and expand
+ * to much more efficient code
+ */
+
+#define PROCESS_POKEY(chip) \
+ UINT32 sum = 0; \
+ if( chip->output[CHAN1] ) \
+ sum += chip->volume[CHAN1]; \
+ if( chip->output[CHAN2] ) \
+ sum += chip->volume[CHAN2]; \
+ if( chip->output[CHAN3] ) \
+ sum += chip->volume[CHAN3]; \
+ if( chip->output[CHAN4] ) \
+ sum += chip->volume[CHAN4]; \
+ while( length > 0 ) \
+ { \
+ if( chip->counter[CHAN1] < chip->samplepos_whole ) \
+ { \
+ if( chip->counter[CHAN2] < chip->counter[CHAN1] ) \
+ { \
+ if( chip->counter[CHAN3] < chip->counter[CHAN2] ) \
+ { \
+ if( chip->counter[CHAN4] < chip->counter[CHAN3] ) \
+ { \
+ UINT32 event = chip->counter[CHAN4]; \
+ PROCESS_CHANNEL(chip,CHAN4); \
+ } \
+ else \
+ { \
+ UINT32 event = chip->counter[CHAN3]; \
+ PROCESS_CHANNEL(chip,CHAN3); \
+ } \
+ } \
+ else \
+ if( chip->counter[CHAN4] < chip->counter[CHAN2] ) \
+ { \
+ UINT32 event = chip->counter[CHAN4]; \
+ PROCESS_CHANNEL(chip,CHAN4); \
+ } \
+ else \
+ { \
+ UINT32 event = chip->counter[CHAN2]; \
+ PROCESS_CHANNEL(chip,CHAN2); \
+ } \
+ } \
+ else \
+ if( chip->counter[CHAN3] < chip->counter[CHAN1] ) \
+ { \
+ if( chip->counter[CHAN4] < chip->counter[CHAN3] ) \
+ { \
+ UINT32 event = chip->counter[CHAN4]; \
+ PROCESS_CHANNEL(chip,CHAN4); \
+ } \
+ else \
+ { \
+ UINT32 event = chip->counter[CHAN3]; \
+ PROCESS_CHANNEL(chip,CHAN3); \
+ } \
+ } \
+ else \
+ if( chip->counter[CHAN4] < chip->counter[CHAN1] ) \
+ { \
+ UINT32 event = chip->counter[CHAN4]; \
+ PROCESS_CHANNEL(chip,CHAN4); \
+ } \
+ else \
+ { \
+ UINT32 event = chip->counter[CHAN1]; \
+ PROCESS_CHANNEL(chip,CHAN1); \
+ } \
+ } \
+ else \
+ if( chip->counter[CHAN2] < chip->samplepos_whole ) \
+ { \
+ if( chip->counter[CHAN3] < chip->counter[CHAN2] ) \
+ { \
+ if( chip->counter[CHAN4] < chip->counter[CHAN3] ) \
+ { \
+ UINT32 event = chip->counter[CHAN4]; \
+ PROCESS_CHANNEL(chip,CHAN4); \
+ } \
+ else \
+ { \
+ UINT32 event = chip->counter[CHAN3]; \
+ PROCESS_CHANNEL(chip,CHAN3); \
+ } \
+ } \
+ else \
+ if( chip->counter[CHAN4] < chip->counter[CHAN2] ) \
+ { \
+ UINT32 event = chip->counter[CHAN4]; \
+ PROCESS_CHANNEL(chip,CHAN4); \
+ } \
+ else \
+ { \
+ UINT32 event = chip->counter[CHAN2]; \
+ PROCESS_CHANNEL(chip,CHAN2); \
+ } \
+ } \
+ else \
+ if( chip->counter[CHAN3] < chip->samplepos_whole ) \
+ { \
+ if( chip->counter[CHAN4] < chip->counter[CHAN3] ) \
+ { \
+ UINT32 event = chip->counter[CHAN4]; \
+ PROCESS_CHANNEL(chip,CHAN4); \
+ } \
+ else \
+ { \
+ UINT32 event = chip->counter[CHAN3]; \
+ PROCESS_CHANNEL(chip,CHAN3); \
+ } \
+ } \
+ else \
+ if( chip->counter[CHAN4] < chip->samplepos_whole ) \
+ { \
+ UINT32 event = chip->counter[CHAN4]; \
+ PROCESS_CHANNEL(chip,CHAN4); \
+ } \
+ else \
+ { \
+ UINT32 event = chip->samplepos_whole; \
+ PROCESS_SAMPLE(chip); \
+ } \
+ } \
+ timer_adjust(chip->rtimer, attotime_never, 0, attotime_zero)
+
+#else /* no HEAVY_MACRO_USAGE */
+/*
+ * And this version of PROCESS_POKEY uses event and channel variables
+ * so that the PROCESS_CHANNEL macro needs to index memory at runtime.
+ */
+
+#define PROCESS_POKEY(chip) \
+ UINT32 sum = 0; \
+ if( chip->output[CHAN1] ) \
+ sum += chip->volume[CHAN1]; \
+ if( chip->output[CHAN2] ) \
+ sum += chip->volume[CHAN2]; \
+ if( chip->output[CHAN3] ) \
+ sum += chip->volume[CHAN3]; \
+ if( chip->output[CHAN4] ) \
+ sum += chip->volume[CHAN4]; \
+ while( length > 0 ) \
+ { \
+ UINT32 event = chip->samplepos_whole; \
+ UINT32 channel = SAMPLE; \
+ if( chip->counter[CHAN1] < event ) \
+ { \
+ event = chip->counter[CHAN1]; \
+ channel = CHAN1; \
+ } \
+ if( chip->counter[CHAN2] < event ) \
+ { \
+ event = chip->counter[CHAN2]; \
+ channel = CHAN2; \
+ } \
+ if( chip->counter[CHAN3] < event ) \
+ { \
+ event = chip->counter[CHAN3]; \
+ channel = CHAN3; \
+ } \
+ if( chip->counter[CHAN4] < event ) \
+ { \
+ event = chip->counter[CHAN4]; \
+ channel = CHAN4; \
+ } \
+ if( channel == SAMPLE ) \
+ { \
+ PROCESS_SAMPLE(chip); \
+ } \
+ else \
+ { \
+ PROCESS_CHANNEL(chip,channel); \
+ } \
+ } \
+ timer_adjust(chip->rtimer, attotime_never, 0, attotime_zero)
+
+#endif
+
+
+void pokey_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct POKEYregisters *chip = param;
+ stream_sample_t *buffer = _buffer[0];
+ PROCESS_POKEY(chip);
+}
+
+
+static void poly_init(UINT8 *poly, int size, int left, int right, int add)
+{
+ int mask = (1 << size) - 1;
+ int i, x = 0;
+
+ LOG_POLY(("poly %d\n", size));
+ for( i = 0; i < mask; i++ )
+ {
+ *poly++ = x & 1;
+ LOG_POLY(("%05x: %d\n", x, x&1));
+ /* calculate next bit */
+ x = ((x << left) + (x >> right) + add) & mask;
+ }
+}
+
+static void rand_init(UINT8 *rng, int size, int left, int right, int add)
+{
+ int mask = (1 << size) - 1;
+ int i, x = 0;
+
+ LOG_RAND(("rand %d\n", size));
+ for( i = 0; i < mask; i++ )
+ {
+ if (size == 17)
+ *rng = x >> 6; /* use bits 6..13 */
+ else
+ *rng = x; /* use bits 0..7 */
+ LOG_RAND(("%05x: %02x\n", x, *rng));
+ rng++;
+ /* calculate next bit */
+ x = ((x << left) + (x >> right) + add) & mask;
+ }
+}
+
+
+static void register_for_save(struct POKEYregisters *chip, int index)
+{
+ state_save_register_item_array("pokey", index, chip->counter);
+ state_save_register_item_array("pokey", index, chip->divisor);
+ state_save_register_item_array("pokey", index, chip->volume);
+ state_save_register_item_array("pokey", index, chip->output);
+ state_save_register_item_array("pokey", index, chip->audible);
+ state_save_register_item("pokey", index, chip->samplepos_fract);
+ state_save_register_item("pokey", index, chip->samplepos_whole);
+ state_save_register_item("pokey", index, chip->polyadjust);
+ state_save_register_item("pokey", index, chip->p4);
+ state_save_register_item("pokey", index, chip->p5);
+ state_save_register_item("pokey", index, chip->p9);
+ state_save_register_item("pokey", index, chip->p17);
+ state_save_register_item("pokey", index, chip->r9);
+ state_save_register_item("pokey", index, chip->r17);
+ state_save_register_item("pokey", index, chip->clockmult);
+ state_save_register_item("pokey", index, chip->timer_period[0].seconds);
+ state_save_register_item("pokey", index, chip->timer_period[0].attoseconds);
+ state_save_register_item("pokey", index, chip->timer_period[1].seconds);
+ state_save_register_item("pokey", index, chip->timer_period[1].attoseconds);
+ state_save_register_item("pokey", index, chip->timer_period[2].seconds);
+ state_save_register_item("pokey", index, chip->timer_period[2].attoseconds);
+ state_save_register_item_array("pokey", index, chip->timer_param);
+ state_save_register_item_array("pokey", index, chip->AUDF);
+ state_save_register_item_array("pokey", index, chip->AUDC);
+ state_save_register_item_array("pokey", index, chip->POTx);
+ state_save_register_item("pokey", index, chip->AUDCTL);
+ state_save_register_item("pokey", index, chip->ALLPOT);
+ state_save_register_item("pokey", index, chip->KBCODE);
+ state_save_register_item("pokey", index, chip->RANDOM);
+ state_save_register_item("pokey", index, chip->SERIN);
+ state_save_register_item("pokey", index, chip->SEROUT);
+ state_save_register_item("pokey", index, chip->IRQST);
+ state_save_register_item("pokey", index, chip->IRQEN);
+ state_save_register_item("pokey", index, chip->SKSTAT);
+ state_save_register_item("pokey", index, chip->SKCTL);
+}
+
+
+static void *pokey_start(int sndindex, int clock, const void *config)
+{
+ struct POKEYregisters *chip;
+ int sample_rate = clock;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ if (config)
+ memcpy(&chip->intf, config, sizeof(struct POKEYinterface));
+ chip->clock_period = ATTOTIME_IN_HZ(clock);
+ chip->index = sndindex;
+
+ /* calculate the A/D times
+ * In normal, slow mode (SKCTL bit SK_PADDLE is clear) the conversion
+ * takes N scanlines, where N is the paddle value. A single scanline
+ * takes approximately 64us to finish (1.78979MHz clock).
+ * In quick mode (SK_PADDLE set) the conversion is done very fast
+ * (takes two scanlines) but the result is not as accurate.
+ */
+ chip->ad_time_fast = attotime_div(attotime_mul(ATTOTIME_IN_NSEC(64000*2/228), FREQ_17_EXACT), clock);
+ chip->ad_time_slow = attotime_div(attotime_mul(ATTOTIME_IN_NSEC(64000 ), FREQ_17_EXACT), clock);
+
+ /* initialize the poly counters */
+ poly_init(chip->poly4, 4, 3, 1, 0x00004);
+ poly_init(chip->poly5, 5, 3, 2, 0x00008);
+ poly_init(chip->poly9, 9, 8, 1, 0x00180);
+ poly_init(chip->poly17, 17,16, 1, 0x1c000);
+
+ /* initialize the random arrays */
+ rand_init(chip->rand9, 9, 8, 1, 0x00180);
+ rand_init(chip->rand17, 17,16, 1, 0x1c000);
+
+ chip->samplerate_24_8 = (clock << 8) / sample_rate;
+ chip->divisor[CHAN1] = 4;
+ chip->divisor[CHAN2] = 4;
+ chip->divisor[CHAN3] = 4;
+ chip->divisor[CHAN4] = 4;
+ chip->clockmult = DIV_64;
+ chip->KBCODE = 0x09; /* Atari 800 'no key' */
+ chip->SKCTL = SK_RESET; /* let the RNG run after reset */
+ chip->rtimer = timer_alloc(NULL);
+
+ chip->timer[0] = timer_alloc_ptr(pokey_timer_expire_1, chip);
+ chip->timer[1] = timer_alloc_ptr(pokey_timer_expire_2, chip);
+ chip->timer[2] = timer_alloc_ptr(pokey_timer_expire_4, chip);
+
+ chip->ptimer[0] = timer_alloc_ptr(pokey_pot_trigger_0, chip);
+ chip->ptimer[1] = timer_alloc_ptr(pokey_pot_trigger_1, chip);
+ chip->ptimer[2] = timer_alloc_ptr(pokey_pot_trigger_2, chip);
+ chip->ptimer[3] = timer_alloc_ptr(pokey_pot_trigger_3, chip);
+ chip->ptimer[4] = timer_alloc_ptr(pokey_pot_trigger_4, chip);
+ chip->ptimer[5] = timer_alloc_ptr(pokey_pot_trigger_5, chip);
+ chip->ptimer[6] = timer_alloc_ptr(pokey_pot_trigger_6, chip);
+ chip->ptimer[7] = timer_alloc_ptr(pokey_pot_trigger_7, chip);
+
+ chip->pot_r[0] = chip->intf.pot_r[0];
+ chip->pot_r[1] = chip->intf.pot_r[1];
+ chip->pot_r[2] = chip->intf.pot_r[2];
+ chip->pot_r[3] = chip->intf.pot_r[3];
+ chip->pot_r[4] = chip->intf.pot_r[4];
+ chip->pot_r[5] = chip->intf.pot_r[5];
+ chip->pot_r[6] = chip->intf.pot_r[6];
+ chip->pot_r[7] = chip->intf.pot_r[7];
+ chip->allpot_r = chip->intf.allpot_r;
+ chip->serin_r = chip->intf.serin_r;
+ chip->serout_w = chip->intf.serout_w;
+ chip->interrupt_cb = chip->intf.interrupt_cb;
+
+ chip->channel = stream_create(0, 1, sample_rate, chip, pokey_update);
+
+ register_for_save(chip, sndindex);
+
+ return chip;
+}
+
+static void pokey_timer_expire_common(struct POKEYregisters *p, int timers)
+{
+ LOG_TIMER(("POKEY #%p timer %d with IRQEN $%02x\n", p, timers, p->IRQEN));
+
+ /* check if some of the requested timer interrupts are enabled */
+ timers &= p->IRQEN;
+
+ if( timers )
+ {
+ /* set the enabled timer irq status bits */
+ p->IRQST |= timers;
+ /* call back an application supplied function to handle the interrupt */
+ if( p->interrupt_cb )
+ (*p->interrupt_cb)(timers);
+ }
+}
+
+static TIMER_CALLBACK_PTR( pokey_timer_expire_1 )
+{
+ struct POKEYregisters *chip = param;
+ pokey_timer_expire_common(chip, chip->timer_param[TIMER1]);
+}
+static TIMER_CALLBACK_PTR( pokey_timer_expire_2 )
+{
+ struct POKEYregisters *chip = param;
+ pokey_timer_expire_common(chip, chip->timer_param[TIMER2]);
+}
+static TIMER_CALLBACK_PTR( pokey_timer_expire_4 )
+{
+ struct POKEYregisters *chip = param;
+ pokey_timer_expire_common(chip, chip->timer_param[TIMER4]);
+}
+
+#if VERBOSE_SOUND
+static char *audc2str(int val)
+{
+ static char buff[80];
+ if( val & NOTPOLY5 )
+ {
+ if( val & PURE )
+ strcpy(buff,"pure");
+ else
+ if( val & POLY4 )
+ strcpy(buff,"poly4");
+ else
+ strcpy(buff,"poly9/17");
+ }
+ else
+ {
+ if( val & PURE )
+ strcpy(buff,"poly5");
+ else
+ if( val & POLY4 )
+ strcpy(buff,"poly4+poly5");
+ else
+ strcpy(buff,"poly9/17+poly5");
+ }
+ return buff;
+}
+
+static char *audctl2str(int val)
+{
+ static char buff[80];
+ if( val & POLY9 )
+ strcpy(buff,"poly9");
+ else
+ strcpy(buff,"poly17");
+ if( val & CH1_HICLK )
+ strcat(buff,"+ch1hi");
+ if( val & CH3_HICLK )
+ strcat(buff,"+ch3hi");
+ if( val & CH12_JOINED )
+ strcat(buff,"+ch1/2");
+ if( val & CH34_JOINED )
+ strcat(buff,"+ch3/4");
+ if( val & CH1_FILTER )
+ strcat(buff,"+ch1filter");
+ if( val & CH2_FILTER )
+ strcat(buff,"+ch2filter");
+ if( val & CLK_15KHZ )
+ strcat(buff,"+clk15");
+ return buff;
+}
+#endif
+
+static TIMER_CALLBACK_PTR( pokey_serin_ready )
+{
+ struct POKEYregisters *p = param;
+ if( p->IRQEN & IRQ_SERIN )
+ {
+ /* set the enabled timer irq status bits */
+ p->IRQST |= IRQ_SERIN;
+ /* call back an application supplied function to handle the interrupt */
+ if( p->interrupt_cb )
+ (*p->interrupt_cb)(IRQ_SERIN);
+ }
+}
+
+static TIMER_CALLBACK_PTR( pokey_serout_ready )
+{
+ struct POKEYregisters *p = param;
+ if( p->IRQEN & IRQ_SEROR )
+ {
+ p->IRQST |= IRQ_SEROR;
+ if( p->interrupt_cb )
+ (*p->interrupt_cb)(IRQ_SEROR);
+ }
+}
+
+static TIMER_CALLBACK_PTR( pokey_serout_complete )
+{
+ struct POKEYregisters *p = param;
+ if( p->IRQEN & IRQ_SEROC )
+ {
+ p->IRQST |= IRQ_SEROC;
+ if( p->interrupt_cb )
+ (*p->interrupt_cb)(IRQ_SEROC);
+ }
+}
+
+static void pokey_pot_trigger_common(struct POKEYregisters *p, int pot)
+{
+ LOG(("POKEY #%p POT%d triggers after %dus\n", p, pot, (int)(1000000 * attotime_to_double(timer_timeelapsed(p->ptimer[pot])))));
+ p->ALLPOT &= ~(1 << pot); /* set the enabled timer irq status bits */
+}
+
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_0 ) { pokey_pot_trigger_common(param, 0); }
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_1 ) { pokey_pot_trigger_common(param, 1); }
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_2 ) { pokey_pot_trigger_common(param, 2); }
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_3 ) { pokey_pot_trigger_common(param, 3); }
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_4 ) { pokey_pot_trigger_common(param, 4); }
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_5 ) { pokey_pot_trigger_common(param, 5); }
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_6 ) { pokey_pot_trigger_common(param, 6); }
+static TIMER_CALLBACK_PTR( pokey_pot_trigger_7 ) { pokey_pot_trigger_common(param, 7); }
+
+#define AD_TIME ((p->SKCTL & SK_PADDLE) ? p->ad_time_fast : p->ad_time_slow)
+
+static void pokey_potgo(struct POKEYregisters *p)
+{
+ int pot;
+
+ LOG(("POKEY #%p pokey_potgo\n", p));
+
+ p->ALLPOT = 0xff;
+
+ for( pot = 0; pot < 8; pot++ )
+ {
+ p->POTx[pot] = 0xff;
+ if( p->pot_r[pot] )
+ {
+ int r = (*p->pot_r[pot])(pot);
+
+ LOG(("POKEY #%d pot_r(%d) returned $%02x\n", p->index, pot, r));
+ if( r != -1 )
+ {
+ if (r > 228)
+ r = 228;
+
+ /* final value */
+ p->POTx[pot] = r;
+ timer_adjust_ptr(p->ptimer[pot], attotime_mul(AD_TIME, r), attotime_zero);
+ }
+ }
+ }
+}
+
+static int pokey_register_r(int chip, int offs)
+{
+ struct POKEYregisters *p = sndti_token(SOUND_POKEY, chip);
+ int data = 0, pot;
+ UINT32 adjust = 0;
+
+#ifdef MAME_DEBUG
+ if( !p )
+ {
+ logerror("POKEY #%d is >= number of Pokeys!\n", chip);
+ return data;
+ }
+#endif
+
+ switch (offs & 15)
+ {
+ case POT0_C: case POT1_C: case POT2_C: case POT3_C:
+ case POT4_C: case POT5_C: case POT6_C: case POT7_C:
+ pot = offs & 7;
+ if( p->pot_r[pot] )
+ {
+ /*
+ * If the conversion is not yet finished (ptimer running),
+ * get the current value by the linear interpolation of
+ * the final value using the elapsed time.
+ */
+ if( p->ALLPOT & (1 << pot) )
+ {
+ data = timer_timeelapsed(p->ptimer[pot]).attoseconds / AD_TIME.attoseconds;
+ LOG(("POKEY #%d read POT%d (interpolated) $%02x\n", chip, pot, data));
+ }
+ else
+ {
+ data = p->POTx[pot];
+ LOG(("POKEY #%d read POT%d (final value) $%02x\n", chip, pot, data));
+ }
+ }
+ else
+ logerror("PC %04x: warning - read p[chip] #%d POT%d\n", activecpu_get_pc(), chip, pot);
+ break;
+
+ case ALLPOT_C:
+ /****************************************************************
+ * If the 2 least significant bits of SKCTL are 0, the ALLPOTs
+ * are disabled (SKRESET). Thanks to MikeJ for pointing this out.
+ ****************************************************************/
+ if( (p->SKCTL & SK_RESET) == 0)
+ {
+ data = 0;
+ LOG(("POKEY #%d ALLPOT internal $%02x (reset)\n", chip, data));
+ }
+ else if( p->allpot_r )
+ {
+ data = (*p->allpot_r)(offs);
+ LOG(("POKEY #%d ALLPOT callback $%02x\n", chip, data));
+ }
+ else
+ {
+ data = p->ALLPOT;
+ LOG(("POKEY #%d ALLPOT internal $%02x\n", chip, data));
+ }
+ break;
+
+ case KBCODE_C:
+ data = p->KBCODE;
+ break;
+
+ case RANDOM_C:
+ /****************************************************************
+ * If the 2 least significant bits of SKCTL are 0, the random
+ * number generator is disabled (SKRESET). Thanks to Eric Smith
+ * for pointing out this critical bit of info! If the random
+ * number generator is enabled, get a new random number. Take
+ * the time gone since the last read into account and read the
+ * new value from an appropriate offset in the rand17 table.
+ ****************************************************************/
+ if( p->SKCTL & SK_RESET )
+ {
+ adjust = attotime_to_double(timer_timeelapsed(p->rtimer)) / attotime_to_double(p->clock_period);
+ p->r9 = (p->r9 + adjust) % 0x001ff;
+ p->r17 = (p->r17 + adjust) % 0x1ffff;
+ }
+ else
+ {
+ adjust = 1;
+ p->r9 = 0;
+ p->r17 = 0;
+ LOG_RAND(("POKEY #%d rand17 frozen (SKCTL): $%02x\n", chip, p->RANDOM));
+ }
+ if( p->AUDCTL & POLY9 )
+ {
+ p->RANDOM = p->rand9[p->r9];
+ LOG_RAND(("POKEY #%d adjust %u rand9[$%05x]: $%02x\n", chip, adjust, p->r9, p->RANDOM));
+ }
+ else
+ {
+ p->RANDOM = p->rand17[p->r17];
+ LOG_RAND(("POKEY #%d adjust %u rand17[$%05x]: $%02x\n", chip, adjust, p->r17, p->RANDOM));
+ }
+ if (adjust > 0)
+ timer_adjust(p->rtimer, attotime_never, 0, attotime_zero);
+ data = p->RANDOM ^ 0xff;
+ break;
+
+ case SERIN_C:
+ if( p->serin_r )
+ p->SERIN = (*p->serin_r)(offs);
+ data = p->SERIN;
+ LOG(("POKEY #%d SERIN $%02x\n", chip, data));
+ break;
+
+ case IRQST_C:
+ /* IRQST is an active low input port; we keep it active high */
+ /* internally to ease the (un-)masking of bits */
+ data = p->IRQST ^ 0xff;
+ LOG(("POKEY #%d IRQST $%02x\n", chip, data));
+ break;
+
+ case SKSTAT_C:
+ /* SKSTAT is also an active low input port */
+ data = p->SKSTAT ^ 0xff;
+ LOG(("POKEY #%d SKSTAT $%02x\n", chip, data));
+ break;
+
+ default:
+ LOG(("POKEY #%d register $%02x\n", chip, offs));
+ break;
+ }
+ return data;
+}
+
+READ8_HANDLER( pokey1_r )
+{
+ return pokey_register_r(0, offset);
+}
+
+READ8_HANDLER( pokey2_r )
+{
+ return pokey_register_r(1, offset);
+}
+
+READ8_HANDLER( pokey3_r )
+{
+ return pokey_register_r(2, offset);
+}
+
+READ8_HANDLER( pokey4_r )
+{
+ return pokey_register_r(3, offset);
+}
+
+READ8_HANDLER( quad_pokey_r )
+{
+ int pokey_num = (offset >> 3) & ~0x04;
+ int control = (offset & 0x20) >> 2;
+ int pokey_reg = (offset % 8) | control;
+
+ return pokey_register_r(pokey_num, pokey_reg);
+}
+
+
+void pokey_register_w(int chip, int offs, int data)
+{
+ struct POKEYregisters *p = sndti_token(SOUND_POKEY, chip);
+ int ch_mask = 0, new_val;
+
+#ifdef MAME_DEBUG
+ if( !p )
+ {
+ logerror("POKEY #%d is >= number of Pokeys!\n", chip);
+ return;
+ }
+#endif
+ stream_update(p->channel);
+
+ /* determine which address was changed */
+ switch (offs & 15)
+ {
+ case AUDF1_C:
+ if( data == p->AUDF[CHAN1] )
+ return;
+ LOG_SOUND(("POKEY #%d AUDF1 $%02x\n", chip, data));
+ p->AUDF[CHAN1] = data;
+ ch_mask = 1 << CHAN1;
+ if( p->AUDCTL & CH12_JOINED ) /* if ch 1&2 tied together */
+ ch_mask |= 1 << CHAN2; /* then also change on ch2 */
+ break;
+
+ case AUDC1_C:
+ if( data == p->AUDC[CHAN1] )
+ return;
+ LOG_SOUND(("POKEY #%d AUDC1 $%02x (%s)\n", chip, data, audc2str(data)));
+ p->AUDC[CHAN1] = data;
+ ch_mask = 1 << CHAN1;
+ break;
+
+ case AUDF2_C:
+ if( data == p->AUDF[CHAN2] )
+ return;
+ LOG_SOUND(("POKEY #%d AUDF2 $%02x\n", chip, data));
+ p->AUDF[CHAN2] = data;
+ ch_mask = 1 << CHAN2;
+ break;
+
+ case AUDC2_C:
+ if( data == p->AUDC[CHAN2] )
+ return;
+ LOG_SOUND(("POKEY #%d AUDC2 $%02x (%s)\n", chip, data, audc2str(data)));
+ p->AUDC[CHAN2] = data;
+ ch_mask = 1 << CHAN2;
+ break;
+
+ case AUDF3_C:
+ if( data == p->AUDF[CHAN3] )
+ return;
+ LOG_SOUND(("POKEY #%d AUDF3 $%02x\n", chip, data));
+ p->AUDF[CHAN3] = data;
+ ch_mask = 1 << CHAN3;
+
+ if( p->AUDCTL & CH34_JOINED ) /* if ch 3&4 tied together */
+ ch_mask |= 1 << CHAN4; /* then also change on ch4 */
+ break;
+
+ case AUDC3_C:
+ if( data == p->AUDC[CHAN3] )
+ return;
+ LOG_SOUND(("POKEY #%d AUDC3 $%02x (%s)\n", chip, data, audc2str(data)));
+ p->AUDC[CHAN3] = data;
+ ch_mask = 1 << CHAN3;
+ break;
+
+ case AUDF4_C:
+ if( data == p->AUDF[CHAN4] )
+ return;
+ LOG_SOUND(("POKEY #%d AUDF4 $%02x\n", chip, data));
+ p->AUDF[CHAN4] = data;
+ ch_mask = 1 << CHAN4;
+ break;
+
+ case AUDC4_C:
+ if( data == p->AUDC[CHAN4] )
+ return;
+ LOG_SOUND(("POKEY #%d AUDC4 $%02x (%s)\n", chip, data, audc2str(data)));
+ p->AUDC[CHAN4] = data;
+ ch_mask = 1 << CHAN4;
+ break;
+
+ case AUDCTL_C:
+ if( data == p->AUDCTL )
+ return;
+ LOG_SOUND(("POKEY #%d AUDCTL $%02x (%s)\n", chip, data, audctl2str(data)));
+ p->AUDCTL = data;
+ ch_mask = 15; /* all channels */
+ /* determine the base multiplier for the 'div by n' calculations */
+ p->clockmult = (p->AUDCTL & CLK_15KHZ) ? DIV_15 : DIV_64;
+ break;
+
+ case STIMER_C:
+ /* first remove any existing timers */
+ LOG_TIMER(("POKEY #%d STIMER $%02x\n", chip, data));
+
+ timer_adjust_ptr(p->timer[TIMER1], attotime_never, attotime_zero);
+ timer_adjust_ptr(p->timer[TIMER2], attotime_never, attotime_zero);
+ timer_adjust_ptr(p->timer[TIMER4], attotime_never, attotime_zero);
+
+ /* reset all counters to zero (side effect) */
+ p->polyadjust = 0;
+ p->counter[CHAN1] = 0;
+ p->counter[CHAN2] = 0;
+ p->counter[CHAN3] = 0;
+ p->counter[CHAN4] = 0;
+
+ /* joined chan#1 and chan#2 ? */
+ if( p->AUDCTL & CH12_JOINED )
+ {
+ if( p->divisor[CHAN2] > 4 )
+ {
+ LOG_TIMER(("POKEY #%d timer1+2 after %d clocks\n", chip, p->divisor[CHAN2]));
+ /* set timer #1 _and_ #2 event after timer_div clocks of joined CHAN1+CHAN2 */
+ p->timer_period[TIMER2] = attotime_mul(p->clock_period, p->divisor[CHAN2]);
+ p->timer_param[TIMER2] = (chip<<3)|IRQ_TIMR2|IRQ_TIMR1;
+ timer_adjust_ptr(p->timer[TIMER2], p->timer_period[TIMER2], p->timer_period[TIMER2]);
+ }
+ }
+ else
+ {
+ if( p->divisor[CHAN1] > 4 )
+ {
+ LOG_TIMER(("POKEY #%d timer1 after %d clocks\n", chip, p->divisor[CHAN1]));
+ /* set timer #1 event after timer_div clocks of CHAN1 */
+ p->timer_period[TIMER1] = attotime_mul(p->clock_period, p->divisor[CHAN1]);
+ p->timer_param[TIMER1] = (chip<<3)|IRQ_TIMR1;
+ timer_adjust_ptr(p->timer[TIMER1], p->timer_period[TIMER1], p->timer_period[TIMER1]);
+ }
+
+ if( p->divisor[CHAN2] > 4 )
+ {
+ LOG_TIMER(("POKEY #%d timer2 after %d clocks\n", chip, p->divisor[CHAN2]));
+ /* set timer #2 event after timer_div clocks of CHAN2 */
+ p->timer_period[TIMER2] = attotime_mul(p->clock_period, p->divisor[CHAN2]);
+ p->timer_param[TIMER2] = (chip<<3)|IRQ_TIMR2;
+ timer_adjust_ptr(p->timer[TIMER2], p->timer_period[TIMER2], p->timer_period[TIMER2]);
+ }
+ }
+
+ /* Note: p[chip] does not have a timer #3 */
+
+ if( p->AUDCTL & CH34_JOINED )
+ {
+ /* not sure about this: if audc4 == 0000xxxx don't start timer 4 ? */
+ if( p->AUDC[CHAN4] & 0xf0 )
+ {
+ if( p->divisor[CHAN4] > 4 )
+ {
+ LOG_TIMER(("POKEY #%d timer4 after %d clocks\n", chip, p->divisor[CHAN4]));
+ /* set timer #4 event after timer_div clocks of CHAN4 */
+ p->timer_period[TIMER4] = attotime_mul(p->clock_period, p->divisor[CHAN4]);
+ p->timer_param[TIMER4] = (chip<<3)|IRQ_TIMR4;
+ timer_adjust_ptr(p->timer[TIMER4], p->timer_period[TIMER4], p->timer_period[TIMER4]);
+ }
+ }
+ }
+ else
+ {
+ if( p->divisor[CHAN4] > 4 )
+ {
+ LOG_TIMER(("POKEY #%d timer4 after %d clocks\n", chip, p->divisor[CHAN4]));
+ /* set timer #4 event after timer_div clocks of CHAN4 */
+ p->timer_period[TIMER4] = attotime_mul(p->clock_period, p->divisor[CHAN4]);
+ p->timer_param[TIMER4] = (chip<<3)|IRQ_TIMR4;
+ timer_adjust_ptr(p->timer[TIMER4], p->timer_period[TIMER4], p->timer_period[TIMER4]);
+ }
+ }
+
+ timer_enable(p->timer[TIMER1], p->IRQEN & IRQ_TIMR1);
+ timer_enable(p->timer[TIMER2], p->IRQEN & IRQ_TIMR2);
+ timer_enable(p->timer[TIMER4], p->IRQEN & IRQ_TIMR4);
+ break;
+
+ case SKREST_C:
+ /* reset SKSTAT */
+ LOG(("POKEY #%d SKREST $%02x\n", chip, data));
+ p->SKSTAT &= ~(SK_FRAME|SK_OVERRUN|SK_KBERR);
+ break;
+
+ case POTGO_C:
+ LOG(("POKEY #%d POTGO $%02x\n", chip, data));
+ pokey_potgo(p);
+ break;
+
+ case SEROUT_C:
+ LOG(("POKEY #%d SEROUT $%02x\n", chip, data));
+ if (p->serout_w)
+ (*p->serout_w)(offs, data);
+ p->SKSTAT |= SK_SEROUT;
+ /*
+ * These are arbitrary values, tested with some custom boot
+ * loaders from Ballblazer and Escape from Fractalus
+ * The real times are unknown
+ */
+ timer_set_ptr(ATTOTIME_IN_USEC(200), p, pokey_serout_ready);
+ /* 10 bits (assumption 1 start, 8 data and 1 stop bit) take how long? */
+ timer_set_ptr(ATTOTIME_IN_USEC(2000), p, pokey_serout_complete);
+ break;
+
+ case IRQEN_C:
+ LOG(("POKEY #%d IRQEN $%02x\n", chip, data));
+
+ /* acknowledge one or more IRQST bits ? */
+ if( p->IRQST & ~data )
+ {
+ /* reset IRQST bits that are masked now */
+ p->IRQST &= data;
+ }
+ else
+ {
+ /* enable/disable timers now to avoid unneeded
+ breaking of the CPU cores for masked timers */
+ if( p->timer[TIMER1] && ((p->IRQEN^data) & IRQ_TIMR1) )
+ timer_enable(p->timer[TIMER1], data & IRQ_TIMR1);
+ if( p->timer[TIMER2] && ((p->IRQEN^data) & IRQ_TIMR2) )
+ timer_enable(p->timer[TIMER2], data & IRQ_TIMR2);
+ if( p->timer[TIMER4] && ((p->IRQEN^data) & IRQ_TIMR4) )
+ timer_enable(p->timer[TIMER4], data & IRQ_TIMR4);
+ }
+ /* store irq enable */
+ p->IRQEN = data;
+ break;
+
+ case SKCTL_C:
+ if( data == p->SKCTL )
+ return;
+ LOG(("POKEY #%d SKCTL $%02x\n", chip, data));
+ p->SKCTL = data;
+ if( !(data & SK_RESET) )
+ {
+ pokey_register_w(chip, IRQEN_C, 0);
+ pokey_register_w(chip, SKREST_C, 0);
+ }
+ break;
+ }
+
+ /************************************************************
+ * As defined in the manual, the exact counter values are
+ * different depending on the frequency and resolution:
+ * 64 kHz or 15 kHz - AUDF + 1
+ * 1.79 MHz, 8-bit - AUDF + 4
+ * 1.79 MHz, 16-bit - AUDF[CHAN1]+256*AUDF[CHAN2] + 7
+ ************************************************************/
+
+ /* only reset the channels that have changed */
+
+ if( ch_mask & (1 << CHAN1) )
+ {
+ /* process channel 1 frequency */
+ if( p->AUDCTL & CH1_HICLK )
+ new_val = p->AUDF[CHAN1] + DIVADD_HICLK;
+ else
+ new_val = (p->AUDF[CHAN1] + DIVADD_LOCLK) * p->clockmult;
+
+ LOG_SOUND(("POKEY #%d chan1 %d\n", chip, new_val));
+
+ p->volume[CHAN1] = (p->AUDC[CHAN1] & VOLUME_MASK) * POKEY_DEFAULT_GAIN;
+ p->divisor[CHAN1] = new_val;
+ if( new_val < p->counter[CHAN1] )
+ p->counter[CHAN1] = new_val;
+ if( p->interrupt_cb && p->timer[TIMER1] )
+ timer_adjust_ptr(p->timer[TIMER1], attotime_mul(p->clock_period, new_val), p->timer_period[TIMER1]);
+ p->audible[CHAN1] = !(
+ (p->AUDC[CHAN1] & VOLUME_ONLY) ||
+ (p->AUDC[CHAN1] & VOLUME_MASK) == 0 ||
+ ((p->AUDC[CHAN1] & PURE) && new_val < (p->samplerate_24_8 >> 8)));
+ if( !p->audible[CHAN1] )
+ {
+ p->output[CHAN1] = 1;
+ p->counter[CHAN1] = 0x7fffffff;
+ /* 50% duty cycle should result in half volume */
+ p->volume[CHAN1] >>= 1;
+ }
+ }
+
+ if( ch_mask & (1 << CHAN2) )
+ {
+ /* process channel 2 frequency */
+ if( p->AUDCTL & CH12_JOINED )
+ {
+ if( p->AUDCTL & CH1_HICLK )
+ new_val = p->AUDF[CHAN2] * 256 + p->AUDF[CHAN1] + DIVADD_HICLK_JOINED;
+ else
+ new_val = (p->AUDF[CHAN2] * 256 + p->AUDF[CHAN1] + DIVADD_LOCLK) * p->clockmult;
+ LOG_SOUND(("POKEY #%d chan1+2 %d\n", chip, new_val));
+ }
+ else
+ {
+ new_val = (p->AUDF[CHAN2] + DIVADD_LOCLK) * p->clockmult;
+ LOG_SOUND(("POKEY #%d chan2 %d\n", chip, new_val));
+ }
+
+ p->volume[CHAN2] = (p->AUDC[CHAN2] & VOLUME_MASK) * POKEY_DEFAULT_GAIN;
+ p->divisor[CHAN2] = new_val;
+ if( new_val < p->counter[CHAN2] )
+ p->counter[CHAN2] = new_val;
+ if( p->interrupt_cb && p->timer[TIMER2] )
+ timer_adjust_ptr(p->timer[TIMER2], attotime_mul(p->clock_period, new_val), p->timer_period[TIMER2]);
+ p->audible[CHAN2] = !(
+ (p->AUDC[CHAN2] & VOLUME_ONLY) ||
+ (p->AUDC[CHAN2] & VOLUME_MASK) == 0 ||
+ ((p->AUDC[CHAN2] & PURE) && new_val < (p->samplerate_24_8 >> 8)));
+ if( !p->audible[CHAN2] )
+ {
+ p->output[CHAN2] = 1;
+ p->counter[CHAN2] = 0x7fffffff;
+ /* 50% duty cycle should result in half volume */
+ p->volume[CHAN2] >>= 1;
+ }
+ }
+
+ if( ch_mask & (1 << CHAN3) )
+ {
+ /* process channel 3 frequency */
+ if( p->AUDCTL & CH3_HICLK )
+ new_val = p->AUDF[CHAN3] + DIVADD_HICLK;
+ else
+ new_val = (p->AUDF[CHAN3] + DIVADD_LOCLK) * p->clockmult;
+
+ LOG_SOUND(("POKEY #%d chan3 %d\n", chip, new_val));
+
+ p->volume[CHAN3] = (p->AUDC[CHAN3] & VOLUME_MASK) * POKEY_DEFAULT_GAIN;
+ p->divisor[CHAN3] = new_val;
+ if( new_val < p->counter[CHAN3] )
+ p->counter[CHAN3] = new_val;
+ /* channel 3 does not have a timer associated */
+ p->audible[CHAN3] = !(
+ (p->AUDC[CHAN3] & VOLUME_ONLY) ||
+ (p->AUDC[CHAN3] & VOLUME_MASK) == 0 ||
+ ((p->AUDC[CHAN3] & PURE) && new_val < (p->samplerate_24_8 >> 8))) ||
+ (p->AUDCTL & CH1_FILTER);
+ if( !p->audible[CHAN3] )
+ {
+ p->output[CHAN3] = 1;
+ p->counter[CHAN3] = 0x7fffffff;
+ /* 50% duty cycle should result in half volume */
+ p->volume[CHAN3] >>= 1;
+ }
+ }
+
+ if( ch_mask & (1 << CHAN4) )
+ {
+ /* process channel 4 frequency */
+ if( p->AUDCTL & CH34_JOINED )
+ {
+ if( p->AUDCTL & CH3_HICLK )
+ new_val = p->AUDF[CHAN4] * 256 + p->AUDF[CHAN3] + DIVADD_HICLK_JOINED;
+ else
+ new_val = (p->AUDF[CHAN4] * 256 + p->AUDF[CHAN3] + DIVADD_LOCLK) * p->clockmult;
+ LOG_SOUND(("POKEY #%d chan3+4 %d\n", chip, new_val));
+ }
+ else
+ {
+ new_val = (p->AUDF[CHAN4] + DIVADD_LOCLK) * p->clockmult;
+ LOG_SOUND(("POKEY #%d chan4 %d\n", chip, new_val));
+ }
+
+ p->volume[CHAN4] = (p->AUDC[CHAN4] & VOLUME_MASK) * POKEY_DEFAULT_GAIN;
+ p->divisor[CHAN4] = new_val;
+ if( new_val < p->counter[CHAN4] )
+ p->counter[CHAN4] = new_val;
+ if( p->interrupt_cb && p->timer[TIMER4] )
+ timer_adjust_ptr(p->timer[TIMER4], attotime_mul(p->clock_period, new_val), p->timer_period[TIMER4]);
+ p->audible[CHAN4] = !(
+ (p->AUDC[CHAN4] & VOLUME_ONLY) ||
+ (p->AUDC[CHAN4] & VOLUME_MASK) == 0 ||
+ ((p->AUDC[CHAN4] & PURE) && new_val < (p->samplerate_24_8 >> 8))) ||
+ (p->AUDCTL & CH2_FILTER);
+ if( !p->audible[CHAN4] )
+ {
+ p->output[CHAN4] = 1;
+ p->counter[CHAN4] = 0x7fffffff;
+ /* 50% duty cycle should result in half volume */
+ p->volume[CHAN4] >>= 1;
+ }
+ }
+}
+
+WRITE8_HANDLER( pokey1_w )
+{
+ pokey_register_w(0,offset,data);
+}
+
+WRITE8_HANDLER( pokey2_w )
+{
+ pokey_register_w(1,offset,data);
+}
+
+WRITE8_HANDLER( pokey3_w )
+{
+ pokey_register_w(2,offset,data);
+}
+
+WRITE8_HANDLER( pokey4_w )
+{
+ pokey_register_w(3,offset,data);
+}
+
+WRITE8_HANDLER( quad_pokey_w )
+{
+ int pokey_num = (offset >> 3) & ~0x04;
+ int control = (offset & 0x20) >> 2;
+ int pokey_reg = (offset % 8) | control;
+
+ pokey_register_w(pokey_num, pokey_reg, data);
+}
+
+void pokey1_serin_ready(int after)
+{
+ struct POKEYregisters *p = sndti_token(SOUND_POKEY, 0);
+ timer_set_ptr(attotime_mul(p->clock_period, after), p, pokey_serin_ready);
+}
+
+void pokey2_serin_ready(int after)
+{
+ struct POKEYregisters *p = sndti_token(SOUND_POKEY, 1);
+ timer_set_ptr(attotime_mul(p->clock_period, after), p, pokey_serin_ready);
+}
+
+void pokey3_serin_ready(int after)
+{
+ struct POKEYregisters *p = sndti_token(SOUND_POKEY, 2);
+ timer_set_ptr(attotime_mul(p->clock_period, after), p, pokey_serin_ready);
+}
+
+void pokey4_serin_ready(int after)
+{
+ struct POKEYregisters *p = sndti_token(SOUND_POKEY, 3);
+ timer_set_ptr(attotime_mul(p->clock_period, after), p, pokey_serin_ready);
+}
+
+void pokey_break_w(int chip, int shift)
+{
+ struct POKEYregisters *p = sndti_token(SOUND_POKEY, chip);
+ if( shift ) /* shift code ? */
+ p->SKSTAT |= SK_SHIFT;
+ else
+ p->SKSTAT &= ~SK_SHIFT;
+ /* check if the break IRQ is enabled */
+ if( p->IRQEN & IRQ_BREAK )
+ {
+ /* set break IRQ status and call back the interrupt handler */
+ p->IRQST |= IRQ_BREAK;
+ if( p->interrupt_cb )
+ (*p->interrupt_cb)(IRQ_BREAK);
+ }
+}
+
+void pokey1_break_w(int shift)
+{
+ pokey_break_w(0, shift);
+}
+
+void pokey2_break_w(int shift)
+{
+ pokey_break_w(1, shift);
+}
+
+void pokey3_break_w(int shift)
+{
+ pokey_break_w(2, shift);
+}
+
+void pokey4_break_w(int shift)
+{
+ pokey_break_w(3, shift);
+}
+
+void pokey_kbcode_w(int chip, int kbcode, int make)
+{
+ struct POKEYregisters *p = sndti_token(SOUND_POKEY, chip);
+ /* make code ? */
+ if( make )
+ {
+ p->KBCODE = kbcode;
+ p->SKSTAT |= SK_KEYBD;
+ if( kbcode & 0x40 ) /* shift code ? */
+ p->SKSTAT |= SK_SHIFT;
+ else
+ p->SKSTAT &= ~SK_SHIFT;
+
+ if( p->IRQEN & IRQ_KEYBD )
+ {
+ /* last interrupt not acknowledged ? */
+ if( p->IRQST & IRQ_KEYBD )
+ p->SKSTAT |= SK_KBERR;
+ p->IRQST |= IRQ_KEYBD;
+ if( p->interrupt_cb )
+ (*p->interrupt_cb)(IRQ_KEYBD);
+ }
+ }
+ else
+ {
+ p->KBCODE = kbcode;
+ p->SKSTAT &= ~SK_KEYBD;
+ }
+}
+
+void pokey1_kbcode_w(int kbcode, int make)
+{
+ pokey_kbcode_w(0, kbcode, make);
+}
+
+void pokey2_kbcode_w(int kbcode, int make)
+{
+ pokey_kbcode_w(1, kbcode, make);
+}
+
+void pokey3_kbcode_w(int kbcode, int make)
+{
+ pokey_kbcode_w(2, kbcode, make);
+}
+
+void pokey4_kbcode_w(int kbcode, int make)
+{
+ pokey_kbcode_w(3, kbcode, make);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void pokey_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void pokey_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = pokey_set_info; break;
+ case SNDINFO_PTR_START: info->start = pokey_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "POKEY"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Atari custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "4.51"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2000-2007, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/pokey.h b/src/emu/sound/pokey.h
new file mode 100644
index 00000000000..21d3675d58f
--- /dev/null
+++ b/src/emu/sound/pokey.h
@@ -0,0 +1,105 @@
+/*****************************************************************************
+ *
+ * POKEY chip emulator 4.3
+ * Copyright (c) 2000 by The MAME Team
+ *
+ * Based on original info found in Ron Fries' Pokey emulator,
+ * with additions by Brad Oliver, Eric Smith and Juergen Buchmueller.
+ * paddle (a/d conversion) details from the Atari 400/800 Hardware Manual.
+ * Polynome algorithms according to info supplied by Perry McFarlane.
+ *
+ * This code is subject to the MAME license, which besides other
+ * things means it is distributed as is, no warranties whatsoever.
+ * For more details read mame.txt that comes with MAME.
+ *
+ *****************************************************************************/
+
+#ifndef _POKEYSOUND_H
+#define _POKEYSOUND_H
+
+#include "sndintrf.h"
+
+/* CONSTANT DEFINITIONS */
+
+/* POKEY WRITE LOGICALS */
+#define AUDF1_C 0x00
+#define AUDC1_C 0x01
+#define AUDF2_C 0x02
+#define AUDC2_C 0x03
+#define AUDF3_C 0x04
+#define AUDC3_C 0x05
+#define AUDF4_C 0x06
+#define AUDC4_C 0x07
+#define AUDCTL_C 0x08
+#define STIMER_C 0x09
+#define SKREST_C 0x0A
+#define POTGO_C 0x0B
+#define SEROUT_C 0x0D
+#define IRQEN_C 0x0E
+#define SKCTL_C 0x0F
+
+/* POKEY READ LOGICALS */
+#define POT0_C 0x00
+#define POT1_C 0x01
+#define POT2_C 0x02
+#define POT3_C 0x03
+#define POT4_C 0x04
+#define POT5_C 0x05
+#define POT6_C 0x06
+#define POT7_C 0x07
+#define ALLPOT_C 0x08
+#define KBCODE_C 0x09
+#define RANDOM_C 0x0A
+#define SERIN_C 0x0D
+#define IRQST_C 0x0E
+#define SKSTAT_C 0x0F
+
+/* exact 1.79 MHz clock freq (of the Atari 800 that is) */
+#define FREQ_17_EXACT 1789790
+
+
+/*****************************************************************************
+ * pot0_r to pot7_r:
+ * Handlers for reading the pot values. Some Atari games use
+ * ALLPOT to return dipswitch settings and other things.
+ * serin_r, serout_w, interrupt_cb:
+ * New function pointers for serial input/output and a interrupt callback.
+ *****************************************************************************/
+
+struct POKEYinterface {
+ read8_handler pot_r[8];
+ read8_handler allpot_r;
+ read8_handler serin_r;
+ write8_handler serout_w;
+ void (*interrupt_cb)(int mask);
+};
+
+
+READ8_HANDLER( pokey1_r );
+READ8_HANDLER( pokey2_r );
+READ8_HANDLER( pokey3_r );
+READ8_HANDLER( pokey4_r );
+READ8_HANDLER( quad_pokey_r );
+
+WRITE8_HANDLER( pokey1_w );
+WRITE8_HANDLER( pokey2_w );
+WRITE8_HANDLER( pokey3_w );
+WRITE8_HANDLER( pokey4_w );
+WRITE8_HANDLER( quad_pokey_w );
+
+void pokey1_serin_ready (int after);
+void pokey2_serin_ready (int after);
+void pokey3_serin_ready (int after);
+void pokey4_serin_ready (int after);
+
+void pokey1_break_w (int shift);
+void pokey2_break_w (int shift);
+void pokey3_break_w (int shift);
+void pokey4_break_w (int shift);
+
+void pokey1_kbcode_w (int kbcode, int make);
+void pokey2_kbcode_w (int kbcode, int make);
+void pokey3_kbcode_w (int kbcode, int make);
+void pokey4_kbcode_w (int kbcode, int make);
+
+#endif /* POKEYSOUND_H */
diff --git a/src/emu/sound/pokey.txt b/src/emu/sound/pokey.txt
new file mode 100644
index 00000000000..04a12ec48da
--- /dev/null
+++ b/src/emu/sound/pokey.txt
@@ -0,0 +1,319 @@
+ Atari POKEY Chip Emulator V2.0
+ ==============================
+ by Ron Fries
+ 31 Jan 97
+
+The PokeySound Chip Emulator is designed to emulate the functionality of the
+Atari POKEY Chip Hardware through 'C' Sourcecode. The emulator is able to
+produce sounds which are essentially identical to the original POKEY chip,
+including the exact distortions and pitches.
+
+The emulator is designed to run in a 32-bit environment. Though it can be
+compiled and run in a 16-bit environment, it is slow.
+
+I would like to give special thanks to Neil Bradley. He provided excellent
+testing support and was also the driving force behind the multiple POKEY
+emulation.
+
+New Features:
+-------------
+
+Version 2.0 of the 'PokeySound' adds the following features:
+
+1) Support for multiple POKEY chips. The maximum supported is configured
+ at compile time.
+
+2) An adjustable gain. The previous releases had a built-in gain of 64.
+
+3) A clipping option. Depending on the number of chips emulated and the
+ configured gain, it is possible for the output to exceed 8-bits.
+ Clipping can be enabled to prevent this, though it does increase the
+ processing time.
+
+
+Standard Features:
+------------------
+
+The 'PokeySound' emulator supports the following functions:
+
+1) All polynomial sound generators:
+ a) 4-bit poly - actual bit pattern determined from sampled sound
+ b) 5-bit poly - actual bit pattern determined from sampled sound
+ c) 17-bit poly - simulated random bit pattern
+ d) 9-bit poly - derived from simulated 17-bit poly
+
+2) Full support of all 'Divide by N' counter clocks:
+ a) 1.79 MHz (high limited to playback sample rate)
+ b) 64 KHz (high limited to playback sample rate)
+ c) 15 KHz
+
+3) Full support of all 'Divide by N' resolutions:
+ a) 8-bit - single channel
+ b) 16-bit - double channel
+
+4) Full support of all distortions
+ a) 5-bit poly, then 17-bit poly
+ b) 5-bit poly only
+ c) 5-bit poly, then 4-bit poly
+ d) 17-bit poly only
+ e) no poly counters (pure tone)
+ f) 5-bit poly only
+
+5) Full support of volume control
+
+6) Full support of all pitches - distortions will vary exactly as the
+ original Atari based on different pitches
+
+7) Accurate pitch generation
+
+8) Support of any playback sample rate (e.g. 22050)
+
+
+The 'PokeySound' emulator does not currently support the following functions:
+
+1) High pass filters
+
+
+Though I don't believe adding support for the High-Pass filters is very
+complicated, I decided not to add support right now because I don't
+believe this feature is used much. I'm also not sure how much impact it
+would have on performance. Let me know if you find an application that
+uses it.
+
+In the 2.0 release, I've removed the non-optimized vrersion. It was only
+left in for reference. If you would still like to see the non-optimized
+version, it's available in the 1.2 release.
+
+One of the unique features of the emulator is that the processing time varies
+based on the frequency. Since the routine only calculates new output values
+when a change is sensed, the lower frequencies (which change less frequently)
+will require less processing time.
+
+
+Differences Between the Emulator and the Actual POKEY Chip:
+-----------------------------------------------------------
+
+The biggest difference between the emulator and the original hardware is
+that the emulator emulates an 'ideal' POKEY chip. All output from the
+emulator is a based on a precise square wave, whereas the output from the
+original chip has decay. Though the output is slightly different, I
+don't believe this difference is easily discernible.
+
+Another slight difference is the 17-bit/9-bit poly. Since the polynomial
+is large (2^17 bits), I choose to create the sample using a random number
+generator rather than a table. I don't believe this difference is
+significant.
+
+There are also a few differences which are introduced by aliasing. This is
+a direct result of using an output sampling rate which is not identical to
+the original sound rate. It is most evident with high frequencies.
+
+A final difference is the lack of support for the High-Pass Filter
+functionality. I plan to add this in a future release if necessary.
+
+
+Sample/Test Application:
+------------------------
+
+The test program I've distributed is a 16-bit DOS application created with
+the Borland 'C' compiler. The only reason I used 16-bit was because I
+already had a set of working SB drivers in 16-bit. Since the test system
+is dedicated to generating sounds, the performance in 16-bit is more than
+adequate.
+
+
+POKEY.C
+=======
+
+The POKEY.C file is the heart of the PokeySound Emulation program.
+Although the routines in the file must work together, no other files are
+modules are required for operation. A header file, 'POKEY.H', has
+been included for use in other modules, and provides the necessary
+function prototypes. I've attempted to make the routines as portable as
+possible, so the file should compile on almost any compiler with little
+or no modification.
+
+I have made some attempts at optimizing the routines, though I am sure
+more optimization can be done. They are currently only available in 'C'.
+I'll be happy to convert them to assembly language if desired. Please feel
+free to send me e-mail at rfries@tcmail.frco.com.
+
+The routines are easy to use. Detailed descriptions on the function calls
+are listed below.
+
+The POKEY.C module can be compiled in a 32-bit or 16-bit environment.
+Since these routines are optimized for 32-bit use, the code will default
+to 32-bit. To compile in 16-bits, use a command line option to define
+the variable COMP16.
+
+
+GENERAL OVERVIEW
+----------------
+
+On start-up of the system, a single call should be made to Pokey_sound_init.
+This routine will prepare the structures for sound output. This routine
+can be called again if necessary during warm-start or other reset.
+
+Once in the main loop, there are two other functions that will be used.
+Whenever the system needs to write to either the AUDC or AUDF values,
+a call should be made to the Update_pokey_sound routine. This routine will
+take care of updating the internal registers. It will pre-calculate several
+values to help with optimization.
+
+The only other routine that is called is the Pokey_process function. This
+function will fill a audio buffer with a specified number of bytes. This
+function should be called whenever a new audio buffer is required.
+
+For best results, I recommend using at least two output buffers. Using this
+scheme, the sound card can be playing one buffer while the system is filling
+the other.
+
+
+DETAILED FUNCTION DESCRIPTIONS
+------------------------------
+
+Pokey_sound_init(uint32 freq17, uint16 playback_freq, uint8 num_pokeys)
+-----------------------------------------------------------------------
+
+This function initializes the structures used by the PokeySound routines.
+This function takes three parameters: the main clock frequency, the
+playback frequency and the number of POKEY chips to emulate.
+
+The maximum number of POKEY chips emulated is configured at compile time.
+Though the maximum number of chips can be configured as one, the PokeySound
+1.2 routines are recommended if only a single chip is to be emulated since
+they have will provide better performance.
+
+The main clock frequency is the frequency of the 1.79MHz source clock.
+To provide exact results, freq17 should be set equal to 1789790 Hz. As an
+alternative, freq17 can be set to an approximate frequency of 1787520 Hz.
+Using this approximate frequency will reduce aliasing and thus produce a
+clearer output signal.
+
+A constant has been defined for both of these values for your convenience.
+The names are FREQ_17_EXACT and FREQ_17_APPROX.
+
+The playback frequency is the frequency of the sound playback (the frequency
+used by the sound card). For best results, the playback frequency should
+be an even division of the main clock frequency. Since most of the sounds
+will be generated using the 64kHz clock, I also recommend making the
+playback frequency an even division of the 64kHz clock.
+
+The 64kHz clock is exactly equal to the main clock divided by 28. For
+the playback frequency, I recommend one of the following values:
+
+1) FREQ_17_APPROX / (28*1), which is equal to 63840. Of course, most sound
+ cards can't reproduce this frequency.
+
+2) FREQ_17_APPROX / (28*2), which is equal to 31920. All of the newer cards
+ will support this frequency.
+
+3) FREQ_17_APPROX / (28*3), which is equal to 21280. All of the SB
+ compatibles should support this frequency.
+
+4) FREQ_17_APPROX / (28*4), which is equal to 15960. This may be the
+ best choice, as it offers good sound reproduction with good performance.
+
+Of course, these options also assume you are using the approximate
+frequency for the main clock as well. Any of these choices will offer the
+best results when the main 64kHz clock is used, reasonable results when the
+15kHz clock is selected, and marginal results when the 1.79MHz clock is
+selected (the only way to produce good results in all cases is to set the
+playback frequency to 1.79MHz!)
+
+Feel free to experiment to find other alternatives as well.
+
+This function has no return value (void).
+
+
+Update_pokey_sound (uint16 addr, uint8 val, uint8 chip, uint8 gain)
+-------------------------------------------------------------------
+
+This function should be called each time an AUDC, AUDF or AUDCTL value
+changes. This function takes four parameters: the address to change,
+the new value, the chip to be updated, and the gain to be used.
+The lower four bits of the address should be one of the following values:
+
+ Addr Description
+ ------ -----------
+ 0x00 AUDF1
+ 0x01 AUDC1
+ 0x02 AUDF2
+ 0x03 AUDC2
+ 0x04 AUDF3
+ 0x05 AUDC3
+ 0x06 AUDF4
+ 0x07 AUDC4
+ 0x08 AUDCTL
+
+In order to support multiple POKEY chips, only the lower four bits of
+the address are used. Note that this routine can no longer be called with
+any address as it will affect the operation of the specified chip.
+
+The routine pre-calculates several values that are needed by the
+processing function. This is done to optimize performance.
+
+The output will be amplified (multiplied) by gain/16 (previous releases had
+a built in multiplier of 4, which calculates to a gain value of 64). If the
+output exceeds the maximum value after then gain and clipping is enabled,
+the output will be limited to reduce distortion.
+
+The best value for the gain depends on the number of POKEYs emulated and
+the maximum volume used. The maximum possible output for each channel is 15,
+making the maximum possible output for a single chip to be 60. Assuming all
+four channels on the chip are used at full volume, a gain of 64 can be used
+without distortion. If 4 POKEY chips are emulated and all 16 channels are
+used at full volume, the gain must be no more than 16 to prevent distortion.
+Of course, if only a few of the 16 channels are used or not all channels are
+used at full volume, a larger gain can be used.
+
+To enable clipping, define the logical CLIP before compiling. This is the
+default mode of operation as it has already been included in the POKEY.H file.
+Note that this is only recommended if clipping is necessary since it will
+impact the performance.
+
+This function has no return value (void).
+
+
+Pokey_process (uint8 *buffer, uint16 n)
+---------------------------------------
+
+This function calculates and fills a buffer with unsigned 8-bit mono audio.
+This function takes two parameters: a pointer to the buffer to fill and
+the size of the buffer (limited to 65535). This function fills the
+buffer based on the requested size and returns. It automatically
+updates the pointers for the next call, so subsequent calls to this function
+will provide a continuous stream of data.
+
+The size of the buffer that is needed depends on the playback frequency.
+It is best to keep the buffer as small as possible to maximize response time
+to changes in the sound. Of course, the minimum size is dependent on
+system and emulator performance.
+
+Selecting the correct buffer size is a careful balance. Selecting a buffer
+size that is too small will produce noticeable clicks in the output, though
+selecting a size that is too large will cause a poor response time and
+possible delays in the system when the new buffer is filled.
+
+This function has no return value (void).
+
+
+License Information and Copyright Notice
+========================================
+
+PokeySound is Copyright(c) 1996-1997 by Ron Fries
+
+This library is free software; you can redistribute it and/or modify it under
+the terms of version 2 of the GNU Library General Public License as published
+by the Free Software Foundation.
+
+This library is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
+details.
+
+To obtain a copy of the GNU Library General Public License, write to the Free
+Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Any permitted reproduction of these routines, in whole or in part, must bear
+this legend.
diff --git a/src/emu/sound/psx.c b/src/emu/sound/psx.c
new file mode 100644
index 00000000000..aa887e2278e
--- /dev/null
+++ b/src/emu/sound/psx.c
@@ -0,0 +1,695 @@
+/***************************************************************************
+
+ PSX SPU
+
+ CXD2922BQ/CXD2925Q
+
+ preliminary version by smf.
+
+***************************************************************************/
+
+#include <stdarg.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "psx.h"
+
+#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 );
+ logerror( "%08x: %s", activecpu_get_pc(), buf );
+ }
+}
+
+#define MAX_CHANNEL ( 24 )
+#define SPU_RAM_SIZE ( 512 * 1024 )
+#define SAMPLES_PER_BLOCK ( 28 )
+#define PITCH_SHIFT ( 12 )
+
+struct psxinfo
+{
+ const struct PSXSPUinterface *intf;
+
+ UINT32 *g_p_n_psxram;
+ UINT16 m_n_mainvolumeleft;
+ UINT16 m_n_mainvolumeright;
+ UINT16 m_n_reverberationdepthleft;
+ UINT16 m_n_reverberationdepthright;
+ UINT32 m_n_voiceon;
+ UINT32 m_n_voiceoff;
+ UINT32 m_n_modulationmode;
+ UINT32 m_n_noisemode;
+ UINT32 m_n_reverbmode;
+ UINT32 m_n_channelonoff;
+ UINT16 m_n_reverbworkareastart;
+ UINT16 m_n_irqaddress;
+ UINT32 m_n_spuoffset;
+ UINT16 m_n_spudata;
+ UINT16 m_n_spucontrol;
+ UINT32 m_n_spustatus;
+ UINT16 m_n_cdvolumeleft;
+ UINT16 m_n_cdvolumeright;
+ UINT16 m_n_externalvolumeleft;
+ UINT16 m_n_externalvolumeright;
+ UINT16 m_p_n_volumeleft[ MAX_CHANNEL ];
+ UINT16 m_p_n_volumeright[ MAX_CHANNEL ];
+ UINT16 m_p_n_pitch[ MAX_CHANNEL ];
+ UINT16 m_p_n_address[ MAX_CHANNEL ];
+ UINT16 m_p_n_attackdecaysustain[ MAX_CHANNEL ];
+ UINT16 m_p_n_sustainrelease[ MAX_CHANNEL ];
+ UINT16 m_p_n_adsrvolume[ MAX_CHANNEL ];
+ UINT16 m_p_n_repeataddress[ MAX_CHANNEL ];
+ UINT32 m_p_n_effect[ 16 ];
+ UINT16 *m_p_n_spuram;
+ UINT32 m_p_n_blockaddress[ MAX_CHANNEL ];
+ UINT32 m_p_n_blockoffset[ MAX_CHANNEL ];
+ UINT32 m_p_n_blockstatus[ MAX_CHANNEL ];
+ INT16 m_p_n_blockbuffer[ MAX_CHANNEL * SAMPLES_PER_BLOCK ];
+ INT16 m_p_n_s1[ MAX_CHANNEL ];
+ INT16 m_p_n_s2[ MAX_CHANNEL ];
+ UINT32 m_n_loop[ MAX_CHANNEL ];
+
+ sound_stream *stream;
+};
+
+#define SPU_REG( a ) ( ( a - 0xc00 ) / 4 )
+#define SPU_CHANNEL_REG( a ) ( a / 4 )
+
+INLINE int volume( UINT16 n_volume )
+{
+ if( ( n_volume & 0x8000 ) != 0 )
+ {
+ n_volume = ( n_volume & 0x7f ) * 0x80;
+ }
+ else if( ( n_volume & 0x4000 ) != 0 )
+ {
+ n_volume = -( n_volume & 0x3fff );
+ }
+ return n_volume;
+}
+
+INLINE int limit( int v )
+{
+ if( v < -32768 )
+ {
+ return -32768;
+ }
+ else if( v > 32767 )
+ {
+ return 32767;
+ }
+ return v;
+}
+
+static void PSXSPU_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct psxinfo *chip = param;
+ int v;
+ int voll;
+ int volr;
+ int n_channel;
+ int n_sample;
+ int n_word;
+ int n_shift;
+ int n_predict;
+ int n_flags;
+ int n_nibble;
+ int n_packed;
+ int n_unpacked;
+
+ static const int f[ 5 ][ 2 ] =
+ {
+ { 0, 0 },
+ { 60, 0 },
+ { 115, -52 },
+ { 98, -55 },
+ { 122, -60 }
+ };
+
+ memset( buffer[ 0 ], 0, length * sizeof( *buffer[ 0 ] ));
+ memset( buffer[ 1 ], 0, length * sizeof( *buffer[ 1 ] ));
+
+ for( n_channel = 0; n_channel < MAX_CHANNEL; n_channel++ )
+ {
+ voll = volume( chip->m_p_n_volumeleft[ n_channel ] );
+ volr = volume( chip->m_p_n_volumeright[ n_channel ] );
+
+ for( n_sample = 0; n_sample < length; n_sample++ )
+ {
+ if( chip->m_p_n_blockoffset[ n_channel ] >= ( SAMPLES_PER_BLOCK << PITCH_SHIFT ) )
+ {
+ if( !chip->m_p_n_blockstatus[ n_channel ] )
+ {
+ break;
+ }
+ if( ( chip->m_n_spucontrol & 0x40 ) != 0 &&
+ ( chip->m_n_irqaddress * 4 ) >= chip->m_p_n_blockaddress[ n_channel ] &&
+ ( chip->m_n_irqaddress * 4 ) <= chip->m_p_n_blockaddress[ n_channel ] + 7 )
+ {
+ chip->intf->irq_set( 0x0200 );
+ }
+
+ n_shift = ( chip->m_p_n_spuram[ chip->m_p_n_blockaddress[ n_channel ] ] >> 0 ) & 0x0f;
+ n_predict = ( chip->m_p_n_spuram[ chip->m_p_n_blockaddress[ n_channel ] ] >> 4 ) & 0x0f;
+ n_flags = ( chip->m_p_n_spuram[ chip->m_p_n_blockaddress[ n_channel ] ] >> 8 ) & 0xff;
+ if( ( n_flags & 4 ) != 0 )
+ {
+ chip->m_n_loop[ n_channel ] = chip->m_p_n_blockaddress[ n_channel ];
+ }
+ chip->m_p_n_blockaddress[ n_channel ]++;
+ chip->m_p_n_blockaddress[ n_channel ] %= ( SPU_RAM_SIZE / 2 );
+
+ for( n_word = 0; n_word < 7; n_word++ )
+ {
+ n_packed = chip->m_p_n_spuram[ chip->m_p_n_blockaddress[ n_channel ] ];
+ chip->m_p_n_blockaddress[ n_channel ]++;
+ chip->m_p_n_blockaddress[ n_channel ] %= ( SPU_RAM_SIZE / 2 );
+
+ for( n_nibble = 0; n_nibble < 4; n_nibble++ )
+ {
+ n_unpacked = ( ( n_packed & 0xf ) << 12 );
+ if( ( n_unpacked & 0x8000 ) != 0 )
+ {
+ n_unpacked |= 0xffff0000;
+ }
+ n_unpacked = ( n_unpacked >> n_shift ) +
+ ( ( chip->m_p_n_s1[ n_channel ] * f[ n_predict ][ 0 ] ) >> 6 ) +
+ ( ( chip->m_p_n_s2[ n_channel ] * f[ n_predict ][ 1 ] ) >> 6 );
+ chip->m_p_n_s2[ n_channel ] = chip->m_p_n_s1[ n_channel ];
+ chip->m_p_n_s1[ n_channel ] = n_unpacked;
+
+ chip->m_p_n_blockbuffer[ ( n_channel * SAMPLES_PER_BLOCK ) + ( n_word * 4 ) + n_nibble ] = n_unpacked;
+ n_packed >>= 4;
+ }
+ }
+ if( ( n_flags & 1 ) != 0 )
+ {
+ if( n_flags != 3 )
+ {
+ chip->m_p_n_blockstatus[ n_channel ] = 0;
+ }
+ else
+ {
+ chip->m_p_n_blockaddress[ n_channel ] = chip->m_n_loop[ n_channel ];
+ }
+ }
+ chip->m_p_n_blockoffset[ n_channel ] %= ( SAMPLES_PER_BLOCK << PITCH_SHIFT );
+ }
+ v = chip->m_p_n_blockbuffer[ ( n_channel * SAMPLES_PER_BLOCK ) + ( chip->m_p_n_blockoffset[ n_channel ] >> PITCH_SHIFT ) ];
+ chip->m_p_n_blockoffset[ n_channel ] += chip->m_p_n_pitch[ n_channel ];
+ buffer[ 0 ][ n_sample ] = limit( buffer[ 0 ][ n_sample ] + ( ( v * voll ) / 0x4000 ) );
+ buffer[ 1 ][ n_sample ] = limit( buffer[ 1 ][ n_sample ] + ( ( v * volr ) / 0x4000 ) );
+ }
+ }
+}
+
+static void spu_read( UINT32 n_address, INT32 n_size )
+{
+ struct psxinfo *chip = sndti_token(SOUND_PSXSPU, 0);
+ verboselog( 1, "spu_read( %08x, %08x )\n", n_address, n_size );
+
+ while( n_size > 0 )
+ {
+ chip->g_p_n_psxram[ n_address / 4 ] =
+ ( chip->m_p_n_spuram[ chip->m_n_spuoffset + 0 ] << 0 ) |
+ ( chip->m_p_n_spuram[ chip->m_n_spuoffset + 1 ] << 16 );
+ verboselog( 2, "%08x > %04x\n", chip->m_n_spuoffset + 0, chip->m_p_n_spuram[ chip->m_n_spuoffset + 0 ] );
+ verboselog( 2, "%08x > %04x\n", chip->m_n_spuoffset + 1, chip->m_p_n_spuram[ chip->m_n_spuoffset + 1 ] );
+ chip->m_n_spuoffset += 2;
+ chip->m_n_spuoffset %= ( SPU_RAM_SIZE / 2 );
+ n_address += 4;
+ n_size--;
+ }
+}
+
+static void spu_write( UINT32 n_address, INT32 n_size )
+{
+ struct psxinfo *chip = sndti_token(SOUND_PSXSPU, 0);
+ verboselog( 1, "spu_write( %08x, %08x )\n", n_address, n_size );
+
+ while( n_size > 0 )
+ {
+ chip->m_p_n_spuram[ chip->m_n_spuoffset + 0 ] = ( chip->g_p_n_psxram[ n_address / 4 ] >> 0 );
+ chip->m_p_n_spuram[ chip->m_n_spuoffset + 1 ] = ( chip->g_p_n_psxram[ n_address / 4 ] >> 16 );
+ verboselog( 2, "%08x < %04x\n", chip->m_n_spuoffset + 0, chip->m_p_n_spuram[ chip->m_n_spuoffset + 0 ] );
+ verboselog( 2, "%08x < %04x\n", chip->m_n_spuoffset + 1, chip->m_p_n_spuram[ chip->m_n_spuoffset + 1 ] );
+ chip->m_n_spuoffset += 2;
+ chip->m_n_spuoffset %= ( SPU_RAM_SIZE / 2 );
+ n_address += 4;
+ n_size--;
+ }
+}
+
+static void *psxspu_start(int sndindex, int clock, const void *config)
+{
+ struct psxinfo *chip;
+ int n_effect;
+ int n_channel;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ chip->intf = config;
+ chip->g_p_n_psxram = *(chip->intf->p_psxram);
+
+ chip->m_n_mainvolumeleft = 0;
+ chip->m_n_mainvolumeright = 0;
+ chip->m_n_reverberationdepthleft = 0;
+ chip->m_n_reverberationdepthright = 0;
+ chip->m_n_voiceon = 0;
+ chip->m_n_voiceoff = 0;
+ chip->m_n_modulationmode = 0;
+ chip->m_n_noisemode = 0;
+ chip->m_n_reverbmode = 0;
+ chip->m_n_channelonoff = 0;
+ chip->m_n_reverbworkareastart = 0;
+ chip->m_n_irqaddress = 0;
+ chip->m_n_spuoffset = 0;
+ chip->m_n_spudata = 0;
+ chip->m_n_spucontrol = 0;
+ chip->m_n_spustatus = 0;
+ chip->m_n_cdvolumeleft = 0;
+ chip->m_n_cdvolumeright = 0;
+ chip->m_n_externalvolumeleft = 0;
+ chip->m_n_externalvolumeright = 0;
+
+ for( n_channel = 0; n_channel < MAX_CHANNEL; n_channel++ )
+ {
+ chip->m_p_n_volumeleft[ n_channel ] = 0;
+ chip->m_p_n_volumeright[ n_channel ] = 0;
+ chip->m_p_n_pitch[ n_channel ] = 0;
+ chip->m_p_n_address[ n_channel ] = 0;
+ chip->m_p_n_attackdecaysustain[ n_channel ] = 0;
+ chip->m_p_n_sustainrelease[ n_channel ] = 0;
+ chip->m_p_n_adsrvolume[ n_channel ] = 0;
+ chip->m_p_n_repeataddress[ n_channel ] = 0;
+ chip->m_p_n_blockaddress[ n_channel ] = 0;
+ chip->m_p_n_blockoffset[ n_channel ] = 0;
+ chip->m_p_n_blockstatus[ n_channel ] = 0;
+ {
+ char s[ 1024 ];
+ sprintf( s, "SPU%d", n_channel );
+ }
+ }
+
+ for( n_effect = 0; n_effect < 16; n_effect++ )
+ {
+ chip->m_p_n_effect[ n_effect ] = 0;
+ }
+
+ chip->m_p_n_spuram = auto_malloc( SPU_RAM_SIZE );
+
+ state_save_register_item( "psx", sndindex, chip->m_n_mainvolumeleft );
+ state_save_register_item( "psx", sndindex, chip->m_n_mainvolumeright );
+ state_save_register_item( "psx", sndindex, chip->m_n_reverberationdepthleft );
+ state_save_register_item( "psx", sndindex, chip->m_n_reverberationdepthright );
+ state_save_register_item( "psx", sndindex, chip->m_n_voiceon );
+ state_save_register_item( "psx", sndindex, chip->m_n_voiceoff );
+ state_save_register_item( "psx", sndindex, chip->m_n_modulationmode );
+ state_save_register_item( "psx", sndindex, chip->m_n_noisemode );
+ state_save_register_item( "psx", sndindex, chip->m_n_reverbmode );
+ state_save_register_item( "psx", sndindex, chip->m_n_channelonoff );
+ state_save_register_item( "psx", sndindex, chip->m_n_reverbworkareastart );
+ state_save_register_item( "psx", sndindex, chip->m_n_irqaddress );
+ state_save_register_item( "psx", sndindex, chip->m_n_spuoffset );
+ state_save_register_item( "psx", sndindex, chip->m_n_spudata );
+ state_save_register_item( "psx", sndindex, chip->m_n_spucontrol );
+ state_save_register_item( "psx", sndindex, chip->m_n_spustatus );
+ state_save_register_item( "psx", sndindex, chip->m_n_cdvolumeleft );
+ state_save_register_item( "psx", sndindex, chip->m_n_cdvolumeright );
+ state_save_register_item( "psx", sndindex, chip->m_n_externalvolumeleft );
+ state_save_register_item( "psx", sndindex, chip->m_n_externalvolumeright );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_volumeleft );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_volumeright );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_pitch );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_address );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_attackdecaysustain );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_sustainrelease );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_adsrvolume );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_repeataddress );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_effect );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_spuram );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_blockaddress );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_blockoffset );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_blockstatus );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_blockbuffer );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_s1 );
+ state_save_register_item_array( "psx", sndindex, chip->m_p_n_s2 );
+ state_save_register_item_array( "psx", sndindex, chip->m_n_loop );
+
+ chip->intf->spu_install_read_handler( 4, spu_read );
+ chip->intf->spu_install_write_handler( 4, spu_write );
+
+ chip->stream = stream_create( 0, 2, 44100, chip, PSXSPU_update );
+ return chip;
+}
+
+
+static UINT32 psx_spu_delay = 0;
+
+WRITE32_HANDLER( psx_spu_delay_w )
+{
+ COMBINE_DATA( &psx_spu_delay );
+ verboselog( 1, "psx_spu_delay_w( %08x %08x )\n", data, mem_mask );
+}
+
+READ32_HANDLER( psx_spu_delay_r )
+{
+ verboselog( 1, "psx_spu_delay_r( %08x )\n", mem_mask );
+ return psx_spu_delay;
+}
+
+READ32_HANDLER( psx_spu_r )
+{
+ struct psxinfo *chip = sndti_token(SOUND_PSXSPU, 0);
+ int n_channel;
+ n_channel = offset / 4;
+ if( n_channel < MAX_CHANNEL )
+ {
+ switch( offset % 4 )
+ {
+ case SPU_CHANNEL_REG( 0x8 ):
+ if( ACCESSING_LSW32 )
+ {
+ verboselog( 1, "psx_spu_r() channel %d attack/decay/sustain = %04x\n", n_channel, chip->m_p_n_attackdecaysustain[ n_channel ] );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ verboselog( 1, "psx_spu_r() channel %d sustain/release = %04x\n", n_channel, chip->m_p_n_sustainrelease[ n_channel ] );
+ }
+ return ( chip->m_p_n_sustainrelease[ n_channel ] << 16 ) | chip->m_p_n_attackdecaysustain[ n_channel ];
+ case SPU_CHANNEL_REG( 0xc ):
+ if( ACCESSING_LSW32 )
+ {
+ verboselog( 1, "psx_spu_r() channel %d adsr volume = %04x\n", n_channel, chip->m_p_n_adsrvolume[ n_channel ] );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ verboselog( 1, "psx_spu_r() channel %d repeat address = %04x\n", n_channel, chip->m_p_n_repeataddress[ n_channel ] );
+ }
+ return ( chip->m_p_n_repeataddress[ n_channel ] << 16 ) | chip->m_p_n_adsrvolume[ n_channel ];
+ default:
+ verboselog( 0, "psx_spu_r( %08x, %08x ) channel %d reg %d\n", offset, mem_mask, n_channel, offset % 4 );
+ return 0;
+ }
+ }
+ else
+ {
+ switch( offset )
+ {
+ case SPU_REG( 0xd88 ):
+ verboselog( 1, "psx_spu_r( %08x ) voice on = %08x\n", mem_mask, chip->m_n_voiceon );
+ return chip->m_n_voiceon;
+ case SPU_REG( 0xd8c ):
+ verboselog( 1, "psx_spu_r( %08x ) voice off = %08x\n", mem_mask, chip->m_n_voiceoff );
+ return chip->m_n_voiceoff;
+ case SPU_REG( 0xd90 ):
+ verboselog( 1, "psx_spu_r( %08x ) modulation mode = %08x\n", mem_mask, chip->m_n_modulationmode );
+ return chip->m_n_modulationmode;
+ case SPU_REG( 0xd94 ):
+ verboselog( 1, "psx_spu_r( %08x ) noise mode = %08x\n", mem_mask, chip->m_n_noisemode );
+ return chip->m_n_noisemode;
+ case SPU_REG( 0xd98 ):
+ verboselog( 1, "psx_spu_r( %08x ) reverb mode = %08x\n", mem_mask, chip->m_n_reverbmode );
+ return chip->m_n_reverbmode;
+ case SPU_REG( 0xda4 ):
+ verboselog( 1, "psx_spu_r( %08x ) dma/irq address = %08x\n", mem_mask, ( ( chip->m_n_spuoffset / 4 ) << 16 ) | chip->m_n_irqaddress );
+ return ( ( chip->m_n_spuoffset / 4 ) << 16 ) | chip->m_n_irqaddress;
+ case SPU_REG( 0xda8 ):
+ verboselog( 1, "psx_spu_r( %08x ) spu control/data = %08x\n", mem_mask, ( chip->m_n_spucontrol << 16 ) | chip->m_n_spudata );
+ return chip->m_n_spudata | ( chip->m_n_spucontrol << 16 );
+ case SPU_REG( 0xdac ):
+ verboselog( 1, "psx_spu_r( %08x ) spu status = %08x\n", mem_mask, chip->m_n_spustatus );
+ return chip->m_n_spustatus;
+ default:
+ verboselog( 0, "psx_spu_r( %08x, %08x ) %08x\n", offset, mem_mask, 0xc00 + ( offset * 4 ) );
+ return 0;
+ }
+ }
+}
+
+WRITE32_HANDLER( psx_spu_w )
+{
+ struct psxinfo *chip = sndti_token(SOUND_PSXSPU, 0);
+ int n_channel;
+ n_channel = offset / 4;
+ if( n_channel < MAX_CHANNEL )
+ {
+ switch( offset % 4 )
+ {
+ case SPU_CHANNEL_REG( 0x0 ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_p_n_volumeleft[ n_channel ] = data & 0xffff;
+ verboselog( 1, "psx_spu_w() channel %d volume left = %04x\n", n_channel, chip->m_p_n_volumeleft[ n_channel ] );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_p_n_volumeright[ n_channel ] = data >> 16;
+ verboselog( 1, "psx_spu_w() channel %d volume right = %04x\n", n_channel, chip->m_p_n_volumeright[ n_channel ] );
+ }
+ break;
+ case SPU_CHANNEL_REG( 0x4 ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_p_n_pitch[ n_channel ] = data & 0xffff;
+ verboselog( 1, "psx_spu_w() channel %d pitch = %04x\n", n_channel, chip->m_p_n_pitch[ n_channel ] );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_p_n_address[ n_channel ] = data >> 16;
+ verboselog( 1, "psx_spu_w() channel %d address = %04x\n", n_channel, chip->m_p_n_address[ n_channel ] );
+ }
+ break;
+ case SPU_CHANNEL_REG( 0x8 ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_p_n_attackdecaysustain[ n_channel ] = data & 0xffff;
+ verboselog( 1, "psx_spu_w() channel %d attack/decay/sustain = %04x\n", n_channel, chip->m_p_n_attackdecaysustain[ n_channel ] );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_p_n_sustainrelease[ n_channel ] = data >> 16;
+ verboselog( 1, "psx_spu_w() channel %d sustain/release = %04x\n", n_channel, chip->m_p_n_sustainrelease[ n_channel ] );
+ }
+ break;
+ case SPU_CHANNEL_REG( 0xc ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_p_n_adsrvolume[ n_channel ] = data & 0xffff;
+ verboselog( 1, "psx_spu_w() channel %d adsr volume = %04x\n", n_channel, chip->m_p_n_adsrvolume[ n_channel ] );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_p_n_repeataddress[ n_channel ] = data >> 16;
+ verboselog( 1, "psx_spu_w() channel %d repeat address = %04x\n", n_channel, chip->m_p_n_repeataddress[ n_channel ] );
+ }
+ break;
+ default:
+ verboselog( 0, "psx_spu_w( %08x, %08x, %08x ) channel %d reg %d\n", offset, mem_mask, data, n_channel, offset % 4 );
+ break;
+ }
+ }
+ else
+ {
+ switch( offset )
+ {
+ case SPU_REG( 0xd80 ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_n_mainvolumeleft = data & 0xffff;
+ verboselog( 1, "psx_spu_w() main volume left = %04x\n", chip->m_n_mainvolumeleft );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_n_mainvolumeright = data >> 16;
+ verboselog( 1, "psx_spu_w() main volume right = %04x\n", chip->m_n_mainvolumeright );
+ }
+ break;
+ case SPU_REG( 0xd84 ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_n_reverberationdepthleft = data & 0xffff;
+ verboselog( 1, "psx_spu_w() reverberation depth left = %04x\n", chip->m_n_reverberationdepthleft );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_n_reverberationdepthright = data >> 16;
+ verboselog( 1, "psx_spu_w() reverberation depth right = %04x\n", chip->m_n_reverberationdepthright );
+ }
+ break;
+ case SPU_REG( 0xd88 ):
+ chip->m_n_voiceon = 0;
+ COMBINE_DATA( &chip->m_n_voiceon );
+ verboselog( 1, "psx_spu_w() voice on = %08x\n", chip->m_n_voiceon );
+ for( n_channel = 0; n_channel < 32; n_channel++ )
+ {
+ if( ( chip->m_n_voiceon & ( 1 << n_channel ) ) != 0 )
+ {
+ chip->m_p_n_blockaddress[ n_channel ] = ( chip->m_p_n_address[ n_channel ] * 4 ) % ( SPU_RAM_SIZE / 2 );
+ chip->m_p_n_blockoffset[ n_channel ] = ( SAMPLES_PER_BLOCK << PITCH_SHIFT );
+ chip->m_p_n_s1[ n_channel ] = 0;
+ chip->m_p_n_s2[ n_channel ] = 0;
+ chip->m_p_n_blockstatus[ n_channel ] = 1;
+ }
+ }
+ break;
+ case SPU_REG( 0xd8c ):
+ chip->m_n_voiceoff = 0;
+ COMBINE_DATA( &chip->m_n_voiceoff );
+ verboselog( 1, "psx_spu_w() voice off = %08x\n", chip->m_n_voiceoff );
+ break;
+ case SPU_REG( 0xd90 ):
+ COMBINE_DATA( &chip->m_n_modulationmode );
+ verboselog( 1, "psx_spu_w() modulation mode = %08x\n", chip->m_n_modulationmode );
+ break;
+ case SPU_REG( 0xd94 ):
+ COMBINE_DATA( &chip->m_n_noisemode );
+ verboselog( 1, "psx_spu_w() noise mode = %08x\n", chip->m_n_noisemode );
+ break;
+ case SPU_REG( 0xd98 ):
+ COMBINE_DATA( &chip->m_n_reverbmode );
+ verboselog( 1, "psx_spu_w() reverb mode = %08x\n", chip->m_n_reverbmode );
+ break;
+ case SPU_REG( 0xd9c ):
+ COMBINE_DATA( &chip->m_n_channelonoff );
+ verboselog( 1, "psx_spu_w() channel on/off = %08x\n", chip->m_n_channelonoff );
+ break;
+ case SPU_REG( 0xda0 ):
+ if( ACCESSING_LSW32 )
+ {
+ verboselog( 0, "psx_spu_w( %08x, %08x, %08x ) %08x\n", offset, mem_mask, data, 0xc00 + ( offset * 4 ) );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_n_reverbworkareastart = data >> 16;
+ verboselog( 1, "psx_spu_w() reverb work area start = %04x\n", chip->m_n_reverbworkareastart );
+ }
+ break;
+ case SPU_REG( 0xda4 ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_n_irqaddress = data & 0xffff;
+ verboselog( 1, "psx_spu_w() irq address = %04x\n", chip->m_n_irqaddress );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_n_spuoffset = ( data >> 16 ) * 4;
+ chip->m_n_spuoffset %= ( SPU_RAM_SIZE / 2 );
+ verboselog( 1, "psx_spu_w() spu offset = %04x\n", chip->m_n_spuoffset );
+ }
+ break;
+ case SPU_REG( 0xda8 ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_n_spudata = data & 0xffff;
+ chip->m_p_n_spuram[ chip->m_n_spuoffset++ ] = chip->m_n_spudata;
+ chip->m_n_spuoffset %= ( SPU_RAM_SIZE / 2 );
+ verboselog( 1, "psx_spu_w() spu data = %04x\n", chip->m_n_spudata );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_n_spucontrol = data >> 16;
+ verboselog( 1, "psx_spu_w() spu control = %04x\n", chip->m_n_spucontrol );
+ }
+ break;
+ case SPU_REG( 0xdac ):
+ COMBINE_DATA( &chip->m_n_spustatus );
+ chip->m_n_spustatus &= 0xf800ffff;
+ verboselog( 1, "psx_spu_w() spu status = %08x\n", chip->m_n_spustatus );
+ break;
+ case SPU_REG( 0xdb0 ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_n_cdvolumeleft = data & 0xffff;
+ verboselog( 1, "psx_spu_w() cd volume left = %04x\n", chip->m_n_cdvolumeleft );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_n_cdvolumeright = data >> 16;
+ verboselog( 1, "psx_spu_w() cd volume right = %04x\n", chip->m_n_cdvolumeright );
+ }
+ break;
+ case SPU_REG( 0xdb4 ):
+ if( ACCESSING_LSW32 )
+ {
+ chip->m_n_externalvolumeleft = data & 0xffff;
+ verboselog( 1, "psx_spu_w() external volume left = %04x\n", chip->m_n_externalvolumeleft );
+ }
+ if( ACCESSING_MSW32 )
+ {
+ chip->m_n_externalvolumeright = data >> 16;
+ verboselog( 1, "psx_spu_w() external volume right = %04x\n", chip->m_n_externalvolumeright );
+ }
+ break;
+ case SPU_REG( 0xdc0 ):
+ case SPU_REG( 0xdc4 ):
+ case SPU_REG( 0xdc8 ):
+ case SPU_REG( 0xdcc ):
+ case SPU_REG( 0xdd0 ):
+ case SPU_REG( 0xdd4 ):
+ case SPU_REG( 0xdd8 ):
+ case SPU_REG( 0xddc ):
+ case SPU_REG( 0xde0 ):
+ case SPU_REG( 0xde4 ):
+ case SPU_REG( 0xde8 ):
+ case SPU_REG( 0xdec ):
+ case SPU_REG( 0xdf0 ):
+ case SPU_REG( 0xdf4 ):
+ case SPU_REG( 0xdf8 ):
+ case SPU_REG( 0xdfc ):
+ COMBINE_DATA( &chip->m_p_n_effect[ offset & 0x0f ] );
+ verboselog( 1, "psx_spu_w() effect %d = %04x\n", offset & 0x0f, chip->m_p_n_effect[ offset & 0x0f ] );
+ break;
+ default:
+ verboselog( 0, "psx_spu_w( %08x, %08x, %08x ) %08x\n", offset, mem_mask, data, 0xc00 + ( offset * 4 ) );
+ break;
+ }
+ }
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void psxspu_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void psxspu_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = psxspu_set_info; break;
+ case SNDINFO_PTR_START: info->start = psxspu_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "SPU"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Sony custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/psx.h b/src/emu/sound/psx.h
new file mode 100644
index 00000000000..4379dfdde83
--- /dev/null
+++ b/src/emu/sound/psx.h
@@ -0,0 +1,27 @@
+/***************************************************************************
+
+ PSX SPU
+
+ preliminary version by smf.
+
+***************************************************************************/
+
+#if !defined( PSX_SPU_H )
+
+WRITE32_HANDLER( psx_spu_w );
+READ32_HANDLER( psx_spu_r );
+WRITE32_HANDLER( psx_spu_delay_w );
+READ32_HANDLER( psx_spu_delay_r );
+
+typedef void ( *spu_handler )( UINT32, INT32 );
+
+struct PSXSPUinterface
+{
+ UINT32 **p_psxram;
+ void (*irq_set)(UINT32);
+ void (*spu_install_read_handler)(int,spu_handler);
+ void (*spu_install_write_handler)(int,spu_handler);
+};
+
+#define PSX_SPU_H ( 1 )
+#endif
diff --git a/src/emu/sound/qsound.c b/src/emu/sound/qsound.c
new file mode 100644
index 00000000000..1eabe0759b0
--- /dev/null
+++ b/src/emu/sound/qsound.c
@@ -0,0 +1,411 @@
+/***************************************************************************
+
+ Capcom System QSound(tm)
+ ========================
+
+ Driver by Paul Leaman (paul@vortexcomputing.demon.co.uk)
+ and Miguel Angel Horna (mahorna@teleline.es)
+
+ A 16 channel stereo sample player.
+
+ QSpace position is simulated by panning the sound in the stereo space.
+
+ Register
+ 0 xxbb xx = unknown bb = start high address
+ 1 ssss ssss = sample start address
+ 2 pitch
+ 3 unknown (always 0x8000)
+ 4 loop offset from end address
+ 5 end
+ 6 master channel volume
+ 7 not used
+ 8 Balance (left=0x0110 centre=0x0120 right=0x0130)
+ 9 unknown (most fixed samples use 0 for this register)
+
+ Many thanks to CAB (the author of Amuse), without whom this probably would
+ never have been finished.
+
+ If anybody has some information about this hardware, please send it to me
+ to mahorna@teleline.es or 432937@cepsz.unizar.es.
+ http://teleline.terra.es/personal/mahorna
+
+***************************************************************************/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "qsound.h"
+
+/*
+Debug defines
+*/
+#define LOG_WAVE 0
+#define LOG_QSOUND 0
+
+/* 8 bit source ROM samples */
+typedef INT8 QSOUND_SRC_SAMPLE;
+
+
+#define QSOUND_CLOCKDIV 166 /* Clock divider */
+#define QSOUND_CHANNELS 16
+typedef stream_sample_t QSOUND_SAMPLE;
+
+struct QSOUND_CHANNEL
+{
+ INT32 bank; /* bank (x16) */
+ INT32 address; /* start address */
+ INT32 pitch; /* pitch */
+ INT32 reg3; /* unknown (always 0x8000) */
+ INT32 loop; /* loop address */
+ INT32 end; /* end address */
+ INT32 vol; /* master volume */
+ INT32 pan; /* Pan value */
+ INT32 reg9; /* unknown */
+
+ /* Work variables */
+ INT32 key; /* Key on / key off */
+
+ INT32 lvol; /* left volume */
+ INT32 rvol; /* right volume */
+ INT32 lastdt; /* last sample value */
+ INT32 offset; /* current offset counter */
+};
+
+struct qsound_info
+{
+ /* Private variables */
+ const struct QSound_interface *intf; /* Interface */
+ sound_stream * stream; /* Audio stream */
+ struct QSOUND_CHANNEL channel[QSOUND_CHANNELS];
+ int data; /* register latch data */
+ QSOUND_SRC_SAMPLE *sample_rom; /* Q sound sample ROM */
+ UINT32 sample_rom_length;
+
+ int pan_table[33]; /* Pan volume table */
+ float frq_ratio; /* Frequency ratio */
+
+ #if LOG_WAVE
+ FILE *fpRawDataL;
+ FILE *fpRawDataR;
+ #endif
+};
+
+/* Function prototypes */
+void qsound_update( void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length );
+void qsound_set_command(struct qsound_info *chip, int data, int value);
+
+static void *qsound_start(int sndindex, int clock, const void *config)
+{
+ struct qsound_info *chip;
+ int i;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(chip));
+
+ chip->intf = config;
+
+ chip->sample_rom = (QSOUND_SRC_SAMPLE *)memory_region(chip->intf->region);
+ chip->sample_rom_length = memory_region_length(chip->intf->region);
+
+ memset(chip->channel, 0, sizeof(chip->channel));
+
+ chip->frq_ratio = 16.0;
+
+ /* Create pan table */
+ for (i=0; i<33; i++)
+ {
+ chip->pan_table[i]=(int)((256/sqrt(32)) * sqrt(i));
+ }
+
+#if LOG_QSOUND
+ logerror("Pan table\n");
+ for (i=0; i<33; i++)
+ logerror("%02x ", chip->pan_table[i]);
+#endif
+ {
+ /* Allocate stream */
+ chip->stream = stream_create(
+ 0, 2,
+ clock / QSOUND_CLOCKDIV,
+ chip,
+ qsound_update );
+ }
+
+#if LOG_WAVE
+ chip->fpRawDataR=fopen("qsoundr.raw", "w+b");
+ chip->fpRawDataL=fopen("qsoundl.raw", "w+b");
+ if (!chip->fpRawDataR || !chip->fpRawDataL)
+ {
+ return NULL;
+ }
+#endif
+
+ /* state save */
+ for (i=0; i<QSOUND_CHANNELS; i++)
+ {
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].bank);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].address);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].pitch);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].loop);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].end);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].vol);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].pan);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].key);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].lvol);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].rvol);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].lastdt);
+ state_save_register_item("QSound", sndindex*QSOUND_CHANNELS+i, chip->channel[i].offset);
+ }
+
+ return chip;
+}
+
+static void qsound_stop (void *_chip)
+{
+#if LOG_WAVE
+ if (chip->fpRawDataR)
+ {
+ fclose(chip->fpRawDataR);
+ }
+ if (chip->fpRawDataL)
+ {
+ fclose(chip->fpRawDataL);
+ }
+#endif
+}
+
+WRITE8_HANDLER( qsound_data_h_w )
+{
+ struct qsound_info *chip = sndti_token(SOUND_QSOUND, 0);
+ chip->data=(chip->data&0xff)|(data<<8);
+}
+
+WRITE8_HANDLER( qsound_data_l_w )
+{
+ struct qsound_info *chip = sndti_token(SOUND_QSOUND, 0);
+ chip->data=(chip->data&0xff00)|data;
+}
+
+WRITE8_HANDLER( qsound_cmd_w )
+{
+ struct qsound_info *chip = sndti_token(SOUND_QSOUND, 0);
+ qsound_set_command(chip, data, chip->data);
+}
+
+READ8_HANDLER( qsound_status_r )
+{
+ /* Port ready bit (0x80 if ready) */
+ return 0x80;
+}
+
+void qsound_set_command(struct qsound_info *chip, int data, int value)
+{
+ int ch=0,reg=0;
+ if (data < 0x80)
+ {
+ ch=data>>3;
+ reg=data & 0x07;
+ }
+ else
+ {
+ if (data < 0x90)
+ {
+ ch=data-0x80;
+ reg=8;
+ }
+ else
+ {
+ if (data >= 0xba && data < 0xca)
+ {
+ ch=data-0xba;
+ reg=9;
+ }
+ else
+ {
+ /* Unknown registers */
+ ch=99;
+ reg=99;
+ }
+ }
+ }
+
+ switch (reg)
+ {
+ case 0: /* Bank */
+ ch=(ch+1)&0x0f; /* strange ... */
+ chip->channel[ch].bank=(value&0x7f)<<16;
+#ifdef MAME_DEBUG
+ if (!value & 0x8000)
+ popmessage("Register3=%04x",value);
+#endif
+
+ break;
+ case 1: /* start */
+ chip->channel[ch].address=value;
+ break;
+ case 2: /* pitch */
+ chip->channel[ch].pitch=value * 16;
+ if (!value)
+ {
+ /* Key off */
+ chip->channel[ch].key=0;
+ }
+ break;
+ case 3: /* unknown */
+ chip->channel[ch].reg3=value;
+#ifdef MAME_DEBUG
+ if (value != 0x8000)
+ popmessage("Register3=%04x",value);
+#endif
+ break;
+ case 4: /* loop offset */
+ chip->channel[ch].loop=value;
+ break;
+ case 5: /* end */
+ chip->channel[ch].end=value;
+ break;
+ case 6: /* master volume */
+ if (value==0)
+ {
+ /* Key off */
+ chip->channel[ch].key=0;
+ }
+ else if (chip->channel[ch].key==0)
+ {
+ /* Key on */
+ chip->channel[ch].key=1;
+ chip->channel[ch].offset=0;
+ chip->channel[ch].lastdt=0;
+ }
+ chip->channel[ch].vol=value;
+ break;
+
+ case 7: /* unused */
+#ifdef MAME_DEBUG
+ popmessage("UNUSED QSOUND REG 7=%04x",value);
+#endif
+
+ break;
+ case 8:
+ {
+ int pandata=(value-0x10)&0x3f;
+ if (pandata > 32)
+ {
+ pandata=32;
+ }
+ chip->channel[ch].rvol=chip->pan_table[pandata];
+ chip->channel[ch].lvol=chip->pan_table[32-pandata];
+ chip->channel[ch].pan = value;
+ }
+ break;
+ case 9:
+ chip->channel[ch].reg9=value;
+/*
+#ifdef MAME_DEBUG
+ popmessage("QSOUND REG 9=%04x",value);
+#endif
+*/
+ break;
+ }
+#if LOG_QSOUND
+ logerror("QSOUND WRITE %02x CH%02d-R%02d =%04x\n", data, ch, reg, value);
+#endif
+}
+
+
+void qsound_update( void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length )
+{
+ struct qsound_info *chip = param;
+ int i,j;
+ int rvol, lvol, count;
+ struct QSOUND_CHANNEL *pC=&chip->channel[0];
+ stream_sample_t *datap[2];
+
+ datap[0] = buffer[0];
+ datap[1] = buffer[1];
+ memset( datap[0], 0x00, length * sizeof(*datap[0]) );
+ memset( datap[1], 0x00, length * sizeof(*datap[1]) );
+
+ for (i=0; i<QSOUND_CHANNELS; i++)
+ {
+ if (pC->key)
+ {
+ QSOUND_SAMPLE *pOutL=datap[0];
+ QSOUND_SAMPLE *pOutR=datap[1];
+ rvol=(pC->rvol*pC->vol)>>8;
+ lvol=(pC->lvol*pC->vol)>>8;
+
+ for (j=length-1; j>=0; j--)
+ {
+ count=(pC->offset)>>16;
+ pC->offset &= 0xffff;
+ if (count)
+ {
+ pC->address += count;
+ if (pC->address >= pC->end)
+ {
+ if (!pC->loop)
+ {
+ /* Reached the end of a non-looped sample */
+ pC->key=0;
+ break;
+ }
+ /* Reached the end, restart the loop */
+ pC->address = (pC->end - pC->loop) & 0xffff;
+ }
+ pC->lastdt=chip->sample_rom[(pC->bank+pC->address)%(chip->sample_rom_length)];
+ }
+
+ (*pOutL) += ((pC->lastdt * lvol) >> 6);
+ (*pOutR) += ((pC->lastdt * rvol) >> 6);
+ pOutL++;
+ pOutR++;
+ pC->offset += pC->pitch;
+ }
+ }
+ pC++;
+ }
+
+#if LOG_WAVE
+ fwrite(datap[0], length*sizeof(QSOUND_SAMPLE), 1, chip->fpRawDataL);
+ fwrite(datap[1], length*sizeof(QSOUND_SAMPLE), 1, chip->fpRawDataR);
+#endif
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void qsound_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void qsound_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = qsound_set_info; break;
+ case SNDINFO_PTR_START: info->start = qsound_start; break;
+ case SNDINFO_PTR_STOP: info->stop = qsound_stop; break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Q-Sound"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Capcom custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+/**************** end of file ****************/
diff --git a/src/emu/sound/qsound.h b/src/emu/sound/qsound.h
new file mode 100644
index 00000000000..00191c5a189
--- /dev/null
+++ b/src/emu/sound/qsound.h
@@ -0,0 +1,21 @@
+/*********************************************************
+
+ Capcom Q-Sound system
+
+*********************************************************/
+
+#ifndef __QSOUND_H__
+#define __QSOUND_H__
+
+#define QSOUND_CLOCK 4000000 /* default 4MHz clock */
+
+struct QSound_interface {
+ int region; /* memory region of sample ROM(s) */
+};
+
+WRITE8_HANDLER( qsound_data_h_w );
+WRITE8_HANDLER( qsound_data_l_w );
+WRITE8_HANDLER( qsound_cmd_w );
+READ8_HANDLER( qsound_status_r );
+
+#endif /* __QSOUND_H__ */
diff --git a/src/emu/sound/rf5c400.c b/src/emu/sound/rf5c400.c
new file mode 100644
index 00000000000..ead2d954754
--- /dev/null
+++ b/src/emu/sound/rf5c400.c
@@ -0,0 +1,581 @@
+/*
+ Ricoh RF5C400 emulator
+
+ Written by Ville Linde
+ Improvements by the hoot development team
+
+ history -
+ 2007-02-08 hoot development team
+ looping
+ stereo panning
+ 8-bit sample support
+
+ 2007-02-16 hoot development team
+ envelope
+ fixed volume table
+*/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "rf5c400.h"
+#include <math.h>
+
+struct rf5c400_info
+{
+ const struct RF5C400interface *intf;
+
+ INT16 *rom;
+ UINT32 rom_length;
+
+ sound_stream *stream;
+
+ int current_channel;
+ int keyon_channel;
+
+ double env_ar_table[0x9f];
+ double env_dr_table[0x9f];
+ double env_rr_table[0x9f];
+
+ struct RF5C400_CHANNEL
+ {
+ UINT16 startH;
+ UINT16 startL;
+ UINT16 freq;
+ UINT16 endL;
+ UINT16 endHloopH;
+ UINT16 loopL;
+ UINT16 pan;
+ UINT16 effect;
+ UINT16 volume;
+
+ UINT16 attack;
+ UINT16 decay;
+ UINT16 release;
+
+ UINT16 cutoff;
+
+ UINT64 pos;
+ UINT64 step;
+ UINT16 keyon;
+
+ UINT8 env_phase;
+ double env_level;
+ double env_step;
+ double env_scale;
+ } channels[32];
+};
+
+static int volume_table[256];
+static double pan_table[0x64];
+
+/* envelope parameter (experimental) */
+#define ENV_AR_SPEED 0.1
+#define ENV_MIN_AR 0x02
+#define ENV_MAX_AR 0x80
+#define ENV_DR_SPEED 2.0
+#define ENV_MIN_DR 0x20
+#define ENV_MAX_DR 0x73
+#define ENV_RR_SPEED 0.7
+#define ENV_MIN_RR 0x20
+#define ENV_MAX_RR 0x54
+
+/* PCM type */
+enum {
+ TYPE_MASK = 0x00C0,
+ TYPE_16 = 0x0000,
+ TYPE_8LOW = 0x0040,
+ TYPE_8HIGH = 0x0080,
+};
+
+/* envelope phase */
+enum {
+ PHASE_NONE = 0,
+ PHASE_ATTACK,
+ PHASE_DECAY,
+ PHASE_RELEASE,
+};
+
+
+/*****************************************************************************/
+
+static UINT8 decode80(UINT8 val)
+{
+ if (val & 0x80)
+ {
+ val = (val & 0x7f) + 0x1f;
+ }
+
+ return val;
+}
+
+static void rf5c400_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ int i, ch;
+ struct rf5c400_info *info = param;
+ INT16 *rom = info->rom;
+ UINT32 start, end, loop;
+ UINT64 pos;
+ UINT8 vol, lvol, rvol, type;
+ UINT8 env_phase;
+ double env_level, env_step, env_rstep;
+
+ memset(buffer[0], 0, length * sizeof(*buffer[0]));
+ memset(buffer[1], 0, length * sizeof(*buffer[1]));
+
+ for (ch=0; ch < 32; ch++)
+ {
+ struct RF5C400_CHANNEL *channel = &info->channels[ch];
+ stream_sample_t *buf0 = buffer[0];
+ stream_sample_t *buf1 = buffer[1];
+
+ start = ((channel->startH & 0xFF00) << 8) | channel->startL;
+ end = ((channel->endHloopH & 0xFF) << 16) | channel->endL;
+ loop = ((channel->endHloopH & 0xFF00) << 8) | channel->loopL;
+ pos = channel->pos;
+ vol = channel->volume & 0xFF;
+ lvol = channel->pan & 0xFF;
+ rvol = channel->pan >> 8;
+ type = (channel->volume >> 8) & TYPE_MASK;
+
+ env_phase = channel->env_phase;
+ env_level = channel->env_level;
+ env_step = channel->env_step;
+ env_rstep = env_step * channel->env_scale;
+
+ for (i=0; i < length; i++)
+ {
+ INT16 tmp;
+ INT32 sample;
+
+ if (env_phase == PHASE_NONE) break;
+
+ tmp = rom[pos>>16];
+ switch ( type )
+ {
+ case TYPE_16:
+ sample = tmp;
+ break;
+ case TYPE_8LOW:
+ sample = (INT16)(tmp << 8);
+ break;
+ case TYPE_8HIGH:
+ sample = (INT16)(tmp & 0xFF00);
+ break;
+ default:
+ sample = 0;
+ break;
+ }
+
+ if ( sample & 0x8000 )
+ {
+ sample ^= 0x7FFF;
+ }
+
+ env_level += env_rstep;
+ switch (env_phase)
+ {
+ case PHASE_ATTACK:
+ if (env_level >= 1.0)
+ {
+ env_phase = PHASE_DECAY;
+ env_level = 1.0;
+ if (channel->decay & 0x0080)
+ {
+ env_step = 0.0;
+ }
+ else
+ {
+ env_step =
+ info->env_dr_table[decode80(channel->decay >> 8)];
+ }
+ env_rstep = env_step * channel->env_scale;
+ }
+ break;
+ case PHASE_DECAY:
+ if (env_level <= 0.0)
+ {
+ env_phase = PHASE_NONE;
+ env_level = 0.0;
+ env_step = 0.0;
+ env_rstep = 0.0;
+ }
+ break;
+ case PHASE_RELEASE:
+ if (env_level <= 0.0)
+ {
+ env_phase = PHASE_NONE;
+ env_level = 0.0;
+ env_step = 0.0;
+ env_rstep = 0.0;
+ }
+ break;
+ }
+
+ sample *= volume_table[vol];
+ sample = (sample >> 9) * env_level;
+ *buf0++ += sample * pan_table[lvol];
+ *buf1++ += sample * pan_table[rvol];
+
+ pos += channel->step;
+ if ( (pos>>16) > info->rom_length || (pos>>16) > end)
+ {
+ pos -= loop<<16;
+ pos &= U64(0xFFFFFF0000);
+ }
+
+ }
+ channel->pos = pos;
+
+ channel->env_phase = env_phase;
+ channel->env_level = env_level;
+ channel->env_step = env_step;
+ }
+}
+
+static void rf5c400_init_chip(struct rf5c400_info *info, int sndindex, int clock)
+{
+ int i;
+
+ info->rom = (INT16*)memory_region(info->intf->region);
+ info->rom_length = memory_region_length(info->intf->region) / 2;
+
+ // init volume table
+ {
+ double max=255.0;
+ for (i = 0; i < 256; i++) {
+ volume_table[i]=(UINT16)max;
+ max /= pow(10.0,(double)((4.5/(256.0/16.0))/20));
+ }
+ for(i = 0; i < 0x48; i++) {
+ pan_table[i] = sqrt( (double)(0x47 - i) ) / sqrt( (double)0x47 );
+ }
+ for(i = 0x48; i < 0x64; i++) {
+ pan_table[i] = 0.0;
+ }
+ }
+
+ // init envelope table
+ {
+ double r;
+
+ // attack
+ r = 1.0 / (ENV_AR_SPEED * Machine->sample_rate);
+ for (i = 0; i < ENV_MIN_AR; i++)
+ {
+ info->env_ar_table[i] = 1.0;
+ }
+ for (i = ENV_MIN_AR; i < ENV_MAX_AR; i++)
+ {
+ info->env_ar_table[i] =
+ r * (ENV_MAX_AR - i) / (ENV_MAX_AR - ENV_MIN_AR);
+ }
+ for (i = ENV_MAX_AR; i < 0x9f; i++)
+ {
+ info->env_ar_table[i] = 0.0;
+ }
+
+ // decay
+ r = -1.0 / (ENV_DR_SPEED * Machine->sample_rate);
+ for (i = 0; i < ENV_MIN_DR; i++)
+ {
+ info->env_dr_table[i] = r;
+ }
+ for (i = ENV_MIN_DR; i < ENV_MAX_DR; i++)
+ {
+ info->env_dr_table[i] =
+ r * (ENV_MAX_DR - i) / (ENV_MAX_DR - ENV_MIN_DR);
+ }
+ for (i = ENV_MAX_DR; i < 0x9f; i++)
+ {
+ info->env_dr_table[i] = 0.0;
+ }
+
+ // release
+ r = -1.0 / (ENV_RR_SPEED * Machine->sample_rate);
+ for (i = 0; i < ENV_MIN_RR; i++)
+ {
+ info->env_rr_table[i] = r;
+ }
+ for (i = ENV_MIN_RR; i < ENV_MAX_RR; i++)
+ {
+ info->env_rr_table[i] =
+ r * (ENV_MAX_RR - i) / (ENV_MAX_RR - ENV_MIN_RR);
+ }
+ for (i = ENV_MAX_RR; i < 0x9f; i++)
+ {
+ info->env_rr_table[i] = 0.0;
+ }
+ }
+
+ // init channel info
+ for (i = 0; i < 32; i++)
+ {
+ info->channels[i].env_phase = PHASE_NONE;
+ info->channels[i].env_level = 0.0;
+ info->channels[i].env_step = 0.0;
+ info->channels[i].env_scale = 1.0;
+ }
+
+ info->stream = stream_create(0, 2, clock/384, info, rf5c400_update);
+}
+
+
+static void *rf5c400_start(int sndindex, int clock, const void *config)
+{
+ struct rf5c400_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->intf = config;
+
+ rf5c400_init_chip(info, sndindex, clock);
+
+ return info;
+}
+
+/*****************************************************************************/
+
+static UINT16 rf5c400_status = 0;
+static UINT16 rf5c400_r(int chipnum, int offset)
+{
+ switch(offset)
+ {
+ case 0x00:
+ {
+ return rf5c400_status;
+ }
+
+ case 0x04:
+ {
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static void rf5c400_w(int chipnum, int offset, UINT16 data)
+{
+ struct rf5c400_info *info = sndti_token(SOUND_RF5C400, chipnum);
+
+ if (offset < 0x400)
+ {
+ switch(offset)
+ {
+ case 0x00:
+ {
+ rf5c400_status = data;
+ break;
+ }
+
+ case 0x01: // channel control
+ {
+ int ch = data & 0x1f;
+ switch ( data & 0x60 )
+ {
+ case 0x60:
+ info->channels[ch].pos =
+ ((info->channels[ch].startH & 0xFF00) << 8) | info->channels[ch].startL;
+ info->channels[ch].pos <<= 16;
+
+ info->channels[ch].env_phase = PHASE_ATTACK;
+ info->channels[ch].env_level = 0.0;
+ info->channels[ch].env_step =
+ info->env_ar_table[decode80(info->channels[ch].attack >> 8)];
+ break;
+ case 0x40:
+ if (info->channels[ch].env_phase != PHASE_NONE)
+ {
+ info->channels[ch].env_phase = PHASE_RELEASE;
+ if (info->channels[ch].release & 0x0080)
+ {
+ info->channels[ch].env_step = 0.0;
+ }
+ else
+ {
+ info->channels[ch].env_step =
+ info->env_rr_table[decode80(info->channels[ch].release >> 8)];
+ }
+ }
+ break;
+ default:
+ info->channels[ch].env_phase = PHASE_NONE;
+ info->channels[ch].env_level = 0.0;
+ info->channels[ch].env_step = 0.0;
+ break;
+ }
+ break;
+ }
+
+ case 0x08: // relative to env attack (channel no)
+ case 0x09: // relative to env attack (0x0c00/ 0x1c00)
+
+ case 0x21: // reverb(character).w
+ case 0x32: // reverb(pre-lpf).w
+ case 0x2B: // reverb(level).w
+ case 0x20: // ???.b : reverb(time).b
+
+ case 0x2C: // chorus(level).w
+ case 0x30: // chorus(rate).w
+ case 0x22: // chorus(macro).w
+ case 0x23: // chorus(depth).w
+ case 0x24: // chorus(macro).w
+ case 0x2F: // chorus(depth).w
+ case 0x27: // chorus(send level to reverb).w
+
+ default:
+ {
+ //mame_printf_debug("rf5c400_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc());
+ break;
+ }
+ }
+ //mame_printf_debug("rf5c400_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc());
+ }
+ else
+ {
+ // channel registers
+ int ch = (offset >> 5) & 0x1f;
+ int reg = (offset & 0x1f);
+
+ struct RF5C400_CHANNEL *channel = &info->channels[ch];
+
+ switch (reg)
+ {
+ case 0x00: // sample start address, bits 23 - 16
+ {
+ channel->startH = data;
+ break;
+ }
+ case 0x01: // sample start address, bits 15 - 0
+ {
+ channel->startL = data;
+ break;
+ }
+ case 0x02: // sample playing frequency
+ {
+ channel->step = ((data & 0x1fff) << (data >> 13)) * 4;
+ channel->freq = data;
+ break;
+ }
+ case 0x03: // sample end address, bits 15 - 0
+ {
+ channel->endL = data;
+ break;
+ }
+ case 0x04: // sample end address, bits 23 - 16 , sample loop 23 - 16
+ {
+ channel->endHloopH = data;
+ break;
+ }
+ case 0x05: // sample loop offset, bits 15 - 0
+ {
+ channel->loopL = data;
+ break;
+ }
+ case 0x06: // channel volume
+ {
+ channel->pan = data;
+ break;
+ }
+ case 0x07: // effect depth
+ {
+ // 0xCCRR: CC = chorus send depth, RR = reverb send depth
+ channel->effect = data;
+ break;
+ }
+ case 0x08: // volume, flag
+ {
+ channel->volume = data;
+ break;
+ }
+ case 0x09: // env attack
+ {
+ // 0x0100: max speed (in case of attack <= 0x40)
+ // 0xXX40: XX = attack-0x3f (encoded) (in case of attack > 0x40)
+ //
+ channel->attack = data;
+ break;
+ }
+ case 0x0A: // relative to env attack ?
+ {
+ // always 0x0100
+ break;
+ }
+ case 0x0B: // relative to env decay ?
+ {
+ // always 0x0100
+ break;
+ }
+ case 0x0C: // env decay
+ {
+ // 0xXX70: XX = decay (encoded) (in case of decay > 0x71)
+ // 0xXX80: XX = decay (encoded) (in case of decay <= 0x71)
+ channel->decay = data;
+ break;
+ }
+ case 0x0D: // relative to env release ?
+ {
+ // always 0x0100
+ break;
+ }
+ case 0x0E: // env release
+ {
+ // 0xXX70: XX = release-0x1f (encoded) (0x01 if release <= 0x20)
+ channel->release = data;
+ break;
+ }
+ case 0x10: // resonance, cutoff freq.
+ {
+ // bit 15-12: resonance
+ // bit 11-0 : cutoff frequency
+ channel->cutoff = data;
+ break;
+ }
+ }
+ }
+}
+
+READ16_HANDLER( RF5C400_0_r )
+{
+ return rf5c400_r(0, offset);
+}
+
+WRITE16_HANDLER( RF5C400_0_w )
+{
+ rf5c400_w(0, offset, data);
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void rf5c400_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void rf5c400_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = rf5c400_set_info; break;
+ case SNDINFO_PTR_START: info->start = rf5c400_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "RF5C400"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Ricoh PCM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.1"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004-2007, The MAME Team & hoot development team"; break;
+ }
+}
diff --git a/src/emu/sound/rf5c400.h b/src/emu/sound/rf5c400.h
new file mode 100644
index 00000000000..93123dc573b
--- /dev/null
+++ b/src/emu/sound/rf5c400.h
@@ -0,0 +1,13 @@
+/* Ricoh RF5C400 emulator */
+
+#ifndef __RF5C400_H__
+#define __RF5C400_H__
+
+struct RF5C400interface {
+ int region; /* memory regions of sample ROM(s) */
+};
+
+READ16_HANDLER( RF5C400_0_r );
+WRITE16_HANDLER( RF5C400_0_w );
+
+#endif
diff --git a/src/emu/sound/rf5c68.c b/src/emu/sound/rf5c68.c
new file mode 100644
index 00000000000..ad1c642734a
--- /dev/null
+++ b/src/emu/sound/rf5c68.c
@@ -0,0 +1,260 @@
+/*********************************************************/
+/* ricoh RF5C68(or clone) PCM controller */
+/*********************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "rf5c68.h"
+#include <math.h>
+
+
+#define NUM_CHANNELS (8)
+
+
+struct pcm_channel
+{
+ UINT8 enable;
+ UINT8 env;
+ UINT8 pan;
+ UINT8 start;
+ UINT32 addr;
+ UINT16 step;
+ UINT16 loopst;
+};
+
+
+struct rf5c68pcm
+{
+ sound_stream * stream;
+ struct pcm_channel chan[NUM_CHANNELS];
+ UINT8 cbank;
+ UINT8 wbank;
+ UINT8 enable;
+ UINT8 data[0x10000];
+};
+
+
+
+/************************************************/
+/* RF5C68 stream update */
+/************************************************/
+
+static void rf5c68_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct rf5c68pcm *chip = param;
+ stream_sample_t *left = buffer[0];
+ stream_sample_t *right = buffer[1];
+ int i, j;
+
+ /* start with clean buffers */
+ memset(left, 0, length * sizeof(*left));
+ memset(right, 0, length * sizeof(*right));
+
+ /* bail if not enabled */
+ if (!chip->enable)
+ return;
+
+ /* loop over channels */
+ for (i = 0; i < NUM_CHANNELS; i++)
+ {
+ struct pcm_channel *chan = &chip->chan[i];
+
+ /* if this channel is active, accumulate samples */
+ if (chan->enable)
+ {
+ int lv = (chan->pan & 0x0f) * chan->env;
+ int rv = ((chan->pan >> 4) & 0x0f) * chan->env;
+
+ /* loop over the sample buffer */
+ for (j = 0; j < length; j++)
+ {
+ int sample;
+
+ /* fetch the sample and handle looping */
+ sample = chip->data[(chan->addr >> 11) & 0xffff];
+ if (sample == 0xff)
+ {
+ chan->addr = chan->loopst << 11;
+ sample = chip->data[(chan->addr >> 11) & 0xffff];
+
+ /* if we loop to a loop point, we're effectively dead */
+ if (sample == 0xff)
+ break;
+ }
+ chan->addr += chan->step;
+
+ /* add to the buffer */
+ if (sample & 0x80)
+ {
+ sample &= 0x7f;
+ left[j] += (sample * lv) >> 5;
+ right[j] += (sample * rv) >> 5;
+ }
+ else
+ {
+ left[j] -= (sample * lv) >> 5;
+ right[j] -= (sample * rv) >> 5;
+ }
+ }
+ }
+ }
+
+ /* now clamp and shift the result (output is only 10 bits) */
+ for (j = 0; j < length; j++)
+ {
+ stream_sample_t temp;
+
+ temp = left[j];
+ if (temp > 32767) temp = 32767;
+ else if (temp < -32768) temp = -32768;
+ left[j] = temp & ~0x3f;
+
+ temp = right[j];
+ if (temp > 32767) temp = 32767;
+ else if (temp < -32768) temp = -32768;
+ right[j] = temp & ~0x3f;
+ }
+}
+
+
+/************************************************/
+/* RF5C68 start */
+/************************************************/
+
+static void *rf5c68_start(int sndindex, int clock, const void *config)
+{
+ /* allocate memory for the chip */
+ struct rf5c68pcm *chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+ memset(chip->data, 0xff, sizeof(chip->data));
+
+ /* allocate the stream */
+ chip->stream = stream_create(0, 2, clock / 384, chip, rf5c68_update);
+ return chip;
+}
+
+
+/************************************************/
+/* RF5C68 write register */
+/************************************************/
+
+WRITE8_HANDLER( RF5C68_reg_w )
+{
+ struct rf5c68pcm *chip = sndti_token(SOUND_RF5C68, 0);
+ struct pcm_channel *chan = &chip->chan[chip->cbank];
+ int i;
+
+ /* force the stream to update first */
+ stream_update(chip->stream);
+
+ /* switch off the address */
+ switch (offset)
+ {
+ case 0x00: /* envelope */
+ chan->env = data;
+ break;
+
+ case 0x01: /* pan */
+ chan->pan = data;
+ break;
+
+ case 0x02: /* FDL */
+ chan->step = (chan->step & 0xff00) | (data & 0x00ff);
+ break;
+
+ case 0x03: /* FDH */
+ chan->step = (chan->step & 0x00ff) | ((data << 8) & 0xff00);
+ break;
+
+ case 0x04: /* LSL */
+ chan->loopst = (chan->loopst & 0xff00) | (data & 0x00ff);
+ break;
+
+ case 0x05: /* LSH */
+ chan->loopst = (chan->loopst & 0x00ff) | ((data << 8) & 0xff00);
+ break;
+
+ case 0x06: /* ST */
+ chan->start = data;
+ if (!chan->enable)
+ chan->addr = chan->start << (8 + 11);
+ break;
+
+ case 0x07: /* control reg */
+ chip->enable = (data >> 7) & 1;
+ if (data & 0x40)
+ chip->cbank = data & 7;
+ else
+ chip->wbank = data & 15;
+ break;
+
+ case 0x08: /* channel on/off reg */
+ for (i = 0; i < 8; i++)
+ {
+ chip->chan[i].enable = (~data >> i) & 1;
+ if (!chip->chan[i].enable)
+ chip->chan[i].addr = chip->chan[i].start << (8 + 11);
+ }
+ break;
+ }
+}
+
+
+/************************************************/
+/* RF5C68 read memory */
+/************************************************/
+
+READ8_HANDLER( RF5C68_r )
+{
+ struct rf5c68pcm *chip = sndti_token(SOUND_RF5C68, 0);
+ return chip->data[chip->wbank * 0x1000 + offset];
+}
+
+
+/************************************************/
+/* RF5C68 write memory */
+/************************************************/
+
+WRITE8_HANDLER( RF5C68_w )
+{
+ struct rf5c68pcm *chip = sndti_token(SOUND_RF5C68, 0);
+ chip->data[chip->wbank * 0x1000 + offset] = data;
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void rf5c68_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void rf5c68_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = rf5c68_set_info; break;
+ case SNDINFO_PTR_START: info->start = rf5c68_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "RF5C68"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Ricoh PCM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
+/**************** end of file ****************/
diff --git a/src/emu/sound/rf5c68.h b/src/emu/sound/rf5c68.h
new file mode 100644
index 00000000000..a33443d7090
--- /dev/null
+++ b/src/emu/sound/rf5c68.h
@@ -0,0 +1,15 @@
+/*********************************************************/
+/* ricoh RF5C68(or clone) PCM controller */
+/*********************************************************/
+#ifndef __RF5C68_H__
+#define __RF5C68_H__
+
+/******************************************/
+WRITE8_HANDLER( RF5C68_reg_w );
+
+READ8_HANDLER( RF5C68_r );
+WRITE8_HANDLER( RF5C68_w );
+
+
+#endif
+/**************** end of file ****************/
diff --git a/src/emu/sound/s14001a.c b/src/emu/sound/s14001a.c
new file mode 100644
index 00000000000..051b12489aa
--- /dev/null
+++ b/src/emu/sound/s14001a.c
@@ -0,0 +1,548 @@
+/*
+
+ TSI S14001A emulator v1.11
+ By Jonathan Gevaryahu ("Lord Nightmare") with help from Kevin Horton ("kevtris")
+ MAME conversion and integration by R. Belmont
+
+ Copyright (c) 2007 Jonathan Gevaryahu.
+
+ Version history:
+ 0.8 initial version - LN
+ 0.9 MAME conversion, glue code added - R. Belmont
+ 1.0 partly fixed stream update - LN (0.111u4)
+ 1.01 fixed clipping problem - LN (0.111u5)
+ 1.1 add VSU-1000 features, fully fixed stream update by fixing word latching - LN (0.111u6)
+ 1.11 fix signedness of output, pre-multiply, fixes clicking on VSU-1000 volume change - LN (0.111u7)
+
+ TODO:
+ * increase accuracy of internal S14001A 'filter' for both driven and undriven cycles (its not terribly inaccurate for undriven cycles, but the dc sliding of driven cycles is not emulated)
+ * add option for and attach Frank P.'s emulation of the Analog external filter from the vsu-1000 using the discrete core.
+*/
+
+/* state map:
+
+ * state machine 1: odd/even clock state
+ * on even clocks, audio output is floating, /romen is low so rom data bus is driven, input is latched?
+ * on odd clocks, audio output is driven, /romen is high, state machine 2 is clocked
+ * *****
+ * state machine 2: decoder state
+ * NOTE: holding the start line high forces the state machine 2 state to go to or remain in state 1!
+ * state 0(Idle): Idle (no sample rom bus activity, output at 0), next state is 0(Idle)
+
+ * state 1(GetHiWord):
+ * grab byte at (wordinput<<1) -> register_WH
+ * reset output DAC accumulator to 0x8 <- ???
+ * reset OldValHi to 1
+ * reset OldValLo to 0
+ * next state is 2(GetLoWord) UNLESS the PLAY line is still high, in which case the state remains at 1
+
+ * state 2(GetLoWord):
+ * grab byte at (wordinput<<1)+1 -> register_WL
+ * next state is 3(GetHiPhon)
+
+ * state 3(GetHiPhon):
+ * grab byte at ((register_WH<<8) + (register_WL))>>4 -> phoneaddress
+ * next state is 4(GetLoPhon)
+
+ * state 4(GetLoPhon):
+ * grab byte at (((register_WH<<8) + (register_WL))>>4)+1 -> playparams
+ * set phonepos register to 0
+ * set oddphone register to 0
+ * next state is 5(PlayForward1)
+ * playparams:
+ * 7 6 5 4 3 2 1 0
+ * G G = LastPhone
+ * B B = PlayMode
+ * Y Y = Silenceflag
+ * S S S S = Length count load value
+ * R R R = Repeat count reload value (upon carry/overflow of 3 bits)
+ * load the repeat counter with the bits 'R R 0'
+ * load the length counter with the bits 'S S S 0'
+ * NOTE: though only three bits of the length counter load value are controllable, there is a fourth lower bit which is assumed 0 on start and controls the direction of playback, i.e. forwards or backwards within a phone.
+ * NOTE: though only two bits of the repeat counter reload value are controllable, there is a third bit which is loaded to 0 on phoneme start, and this hidden low-order bit of the counter itself is what controls whether the output is forced to silence in mirrored mode. the 'carry' from the highest bit of the 3 bit counter is what increments the address pointer for pointing to the next phoneme in mirrored mode
+
+
+ * shift register diagram:
+ * F E D C B A 9 8 7 6 5 4 3 2 1 0
+ * <new byte here>
+ * C C C = Current delta sample read point
+ * O O O = Old delta sample read point
+ * I *OPTIMIZED OUT* the shift register by making use of the fact that the device reads each rom byte 4 times
+
+ * state 5(PlayForward1):
+ * grab byte at (((phoneaddress<<8)+(oddphone*8))+(phonepos>>2)) -> PlayRegister high end, bits F to 8
+ * if Playmode is mirrored, set OldValHi and OldValLo to 1 and 0 respectively, otherwise leave them with whatever was in them before.
+ * Put OldValHi in bit 7 of PlayRegister
+ * Put OldValLo in bit 6 of PlayRegister
+ * Get new OldValHi from bit 9
+ * Get new OldValLo from bit 8
+ * feed current delta (bits 9 and 8) and olddelta (bits 7 and 6) to delta demodulator table, delta demodulator table applies a delta to the accumulator, accumulator goes to enable/disable latch which Silenceflag enables or disables (forces output to 0x8 on disable), then to DAC to output.
+ * next state: state 6(PlayForward2)
+
+ * state 6(PlayForward2):
+ * grab byte at (((phoneaddress<<8)+oddphone)+(phonepos>>2)) -> PlayRegister bits D to 6.
+ * Put OldValHi in bit 7 of PlayRegister\____already done by above operation
+ * Put OldValLo in bit 6 of PlayRegister/
+ * Get new OldValHi from bit 9
+ * Get new OldValLo from bit 8
+ * feed current delta (bits 9 and 8) and olddelta (bits 7 and 6) to delta demodulator table, delta demodulator table applies a delta to the accumulator, accumulator goes to enable/disable latch which Silenceflag enables or disables (forces output to 0x8 on disable), then to DAC to output.
+ * next state: state 7(PlayForward3)
+
+ * state 7(PlayForward3):
+ * grab byte at (((phoneaddress<<8)+oddphone)+(phonepos>>2)) -> PlayRegister bits B to 4.
+ * Put OldValHi in bit 7 of PlayRegister\____already done by above operation
+ * Put OldValLo in bit 6 of PlayRegister/
+ * Get new OldValHi from bit 9
+ * Get new OldValLo from bit 8
+ * feed current delta (bits 9 and 8) and olddelta (bits 7 and 6) to delta demodulator table, delta demodulator table applies a delta to the accumulator, accumulator goes to enable/disable latch which Silenceflag enables or disables (forces output to 0x8 on disable), then to DAC to output.
+ * next state: state 8(PlayForward4)
+
+ * state 8(PlayForward4):
+ * grab byte at (((phoneaddress<<8)+oddphone)+(phonepos>>2)) -> PlayRegister bits 9 to 2.
+ * Put OldValHi in bit 7 of PlayRegister\____already done by above operation
+ * Put OldValLo in bit 6 of PlayRegister/
+ * Get new OldValHi from bit 9
+ * Get new OldValLo from bit 8
+ * feed current delta (bits 9 and 8) and olddelta (bits 7 and 6) to delta demodulator table, delta demodulator table applies a delta to the accumulator, accumulator goes to enable/disable latch which Silenceflag enables or disables (forces output to 0x8 on disable), then to DAC to output.
+ * Call function: increment address
+
+ * next state: depends on playparams:
+ * if we're in mirrored mode, next will be LoadAndPlayBackward1
+
+ * state 9(LoadAndPlayBackward1)
+ * state 10(PlayBackward2)
+ * state 11(PlayBackward3)
+ * state 12(PlayBackward4)
+*/
+
+/* increment address function:
+ * increment repeat counter
+ if repeat counter produces a carry, do two things:
+ 1. if mirrored mode is ON, increment oddphone. if oddphone carries out (i.e. if it was 1), increment phoneaddress and zero oddphone
+ 2. increment lengthcounter. if lengthcounter carries out, we're done this phone.
+ * increment output counter
+ * if mirrored mode is on, output direction is
+ * if mirrored mode is OFF, increment oddphone. if not, don't touch it here. if oddphone was 1 before the increment, increment phoneaddress and set oddphone to 0
+ *
+ */
+
+#include <math.h>
+#include "sndintrf.h"
+#include "s14001a.h"
+#include "streams.h"
+
+typedef struct
+{
+ int index;
+ sound_stream * stream;
+
+ UINT8 WordInput; // value on word input bus
+ UINT8 LatchedWord; // value latched from input bus
+ UINT16 SyllableAddress; // address read from word table
+ UINT16 PhoneAddress; // starting/current phone address from syllable table
+ UINT8 PlayParams; // playback parameters from syllable table
+ UINT8 PhoneOffset; // offset within phone
+ UINT8 LengthCounter; // 4-bit counter which holds the inverted length of the word in phones, leftshifted by 1
+ UINT8 RepeatCounter; // 3-bit counter which holds the inverted number of repeats per phone, leftshifted by 1
+ UINT8 OutputCounter; // 2-bit counter to determine forward/backward and output/silence state.
+ UINT8 machineState; // chip state machine state
+ UINT8 nextstate; // chip state machine's new state
+ UINT8 laststate; // chip state machine's previous state, needed for mirror increment masking
+ UINT8 resetState; // reset line state
+ UINT8 oddeven; // odd versus even cycle toggle
+ UINT8 GlobalSilenceState; // same as above but for silent syllables instead of silent portions of mirrored syllables
+ UINT8 OldDelta; // 2-bit old delta value
+ UINT8 DACOutput; // 4-bit DAC Accumulator/output
+ UINT8 audioout; // filtered audio output
+ UINT8 *SpeechRom; // array to hold rom contents, mame will not need this, will use a pointer
+ UINT8 filtervals[8];
+ UINT8 VSU1000_amp; // amplitude setting on VSU-1000 board
+ UINT16 VSU1000_freq; // frequency setting on VSU-1000 board
+ UINT16 VSU1000_counter; // counter for freq divider
+} S14001AChip;
+
+//#define DEBUGSTATE
+
+#define SILENCE 0x77 // value output when silent
+
+#define LASTSYLLABLE ((chip->PlayParams & 0x80)>>7)
+#define MIRRORMODE ((chip->PlayParams & 0x40)>>6)
+#define SILENCEFLAG ((chip->PlayParams & 0x20)>>5)
+#define LENGTHCOUNT ((chip->PlayParams & 0x1C)>>1) // remember: its 4 bits and the bottom bit is always zero!
+#define REPEATCOUNT ((chip->PlayParams<<1)&0x6) // remember: its 3 bits and the bottom bit is always zero!
+#define LOCALSILENCESTATE ((chip->OutputCounter & 0x2) && (MIRRORMODE)) // 1 when silent output, 0 when DAC output.
+
+static INT8 DeltaTable[4][4] =
+{
+ { 0xCD, 0xCD, 0xEF, 0xEF, },
+ { 0xEF, 0xEF, 0x00, 0x00, },
+ { 0x00, 0x00, 0x11, 0x11, },
+ { 0x11, 0x11, 0x33, 0x33 },
+};
+
+static UINT8 audiofilter(S14001AChip *chip) /* rewrite me to better match the real filter! */
+{
+ UINT16 temp1, temp2 = 0;
+ /* crappy averaging filter! */
+ for (temp1 = 0; temp1 < 8; temp1++) { temp2 += chip->filtervals[temp1]; }
+ temp2 >>= 3;
+ return temp2;
+}
+
+static void shiftIntoFilter(S14001AChip *chip, UINT8 inputvalue)
+{
+ UINT8 temp1;
+ for (temp1 = 7; temp1 > 0; temp1--)
+ {
+ chip->filtervals[temp1] = chip->filtervals[(temp1 - 1)];
+ }
+ chip->filtervals[0] = inputvalue;
+
+}
+
+static void PostPhoneme(S14001AChip *chip) /* figure out what the heck to do after playing a phoneme */
+{
+#ifdef DEBUGSTATE
+ fprintf(stderr,"0: entered PostPhoneme\n");
+#endif
+ chip->RepeatCounter++; // increment the repeat counter
+ chip->OutputCounter++; // increment the output counter
+ if (MIRRORMODE) // if mirroring is enabled
+ {
+#ifdef DEBUGSTATE
+ fprintf(stderr,"1: MIRRORMODE was on\n");
+#endif
+ if (chip->RepeatCounter == 0x8) // exceeded 3 bits?
+ {
+#ifdef DEBUGSTATE
+ fprintf(stderr,"2: RepeatCounter was == 8\n");
+#endif
+ // reset repeat counter, increment length counter
+ // but first check if lowest bit is set
+ chip->RepeatCounter = REPEATCOUNT; // reload repeat counter with reload value
+ if (chip->LengthCounter & 0x1) // if low bit is 1 (will carry after increment)
+ {
+#ifdef DEBUGSTATE
+ fprintf(stderr,"3: LengthCounter's low bit was 1\n");
+#endif
+ chip->PhoneAddress+=8; // go to next phone in this syllable
+ }
+ chip->LengthCounter++;
+ if (chip->LengthCounter == 0x10) // if Length counter carried out of 4 bits
+ {
+#ifdef DEBUGSTATE
+ fprintf(stderr,"3: LengthCounter overflowed\n");
+#endif
+ chip->SyllableAddress += 2; // go to next syllable
+ chip->nextstate = LASTSYLLABLE ? 13 : 3; // if we're on the last syllable, go to end state, otherwise go and load the next syllable.
+ }
+ else
+ {
+#ifdef DEBUGSTATE
+ fprintf(stderr,"3: LengthCounter's low bit wasn't 1 and it didn't overflow\n");
+#endif
+ chip->PhoneOffset = (chip->OutputCounter&1) ? 7 : 0;
+ chip->nextstate = (chip->OutputCounter&1) ? 9 : 5;
+ }
+ }
+ else // repeatcounter did NOT carry out of 3 bits so leave length counter alone
+ {
+#ifdef DEBUGSTATE
+ fprintf(stderr,"2: RepeatCounter is less than 8 (its actually %d)\n", chip->RepeatCounter);
+#endif
+ chip->PhoneOffset = (chip->OutputCounter&1) ? 7 : 0;
+ chip->nextstate = (chip->OutputCounter&1) ? 9 : 5;
+ }
+ }
+ else // if mirroring is NOT enabled
+ {
+#ifdef DEBUGSTATE
+ fprintf(stderr,"1: MIRRORMODE was off\n");
+#endif
+ if (chip->RepeatCounter == 0x8) // exceeded 3 bits?
+ {
+#ifdef DEBUGSTATE
+ fprintf(stderr,"2: RepeatCounter was == 8\n");
+#endif
+ // reset repeat counter, increment length counter
+ chip->RepeatCounter = REPEATCOUNT; // reload repeat counter with reload value
+ chip->LengthCounter++;
+ if (chip->LengthCounter == 0x10) // if Length counter carried out of 4 bits
+ {
+#ifdef DEBUGSTATE
+ fprintf(stderr,"3: LengthCounter overflowed\n");
+#endif
+ chip->SyllableAddress += 2; // go to next syllable
+ chip->nextstate = LASTSYLLABLE ? 13 : 3; // if we're on the last syllable, go to end state, otherwise go and load the next syllable.
+#ifdef DEBUGSTATE
+ fprintf(stderr,"nextstate is now %d\n", chip->nextstate); // see line below, same reason.
+#endif
+ return; // need a return here so we don't hit the 'nextstate = 5' line below
+ }
+ }
+ chip->PhoneAddress += 8; // regardless of counters, the phone address always increments in non-mirrored mode
+ chip->PhoneOffset = 0;
+ chip->nextstate = 5;
+ }
+#ifdef DEBUGSTATE
+ fprintf(stderr,"nextstate is now %d\n", chip->nextstate);
+#endif
+}
+
+void s14001a_clock(S14001AChip *chip) /* called once per clock */
+{
+ UINT8 CurDelta; // Current delta
+
+ /* on even clocks, audio output is floating, /romen is low so rom data bus is driven, input is latched?
+ * on odd clocks, audio output is driven, /romen is high, state machine 2 is clocked*/
+ chip->oddeven = !(chip->oddeven); // invert the clock
+ if (chip->oddeven == 0) // even clock
+ {
+ chip->audioout = audiofilter(chip); // function to handle output filtering by internal capacitance based on clock speed and such
+ shiftIntoFilter(chip, chip->audioout); // shift over all the filter outputs and stick in audioout
+ }
+ else // odd clock
+ {
+ // fix dac output between samples. theoretically this might be unnecessary but it would require some messy logic in state 5 on the first sample load.
+ if (chip->GlobalSilenceState || LOCALSILENCESTATE)
+ {
+ chip->DACOutput = SILENCE;
+ chip->OldDelta = 2;
+ }
+ chip->audioout = (chip->GlobalSilenceState || LOCALSILENCESTATE) ? SILENCE : chip->DACOutput; // when either silence state is 1, output silence.
+ shiftIntoFilter(chip, chip->audioout); // shift over all the filter outputs and stick in audioout
+ switch(chip->machineState) // HUUUUUGE switch statement
+ {
+ case 0: // idle state
+ chip->nextstate = 0;
+ break;
+ case 1: // read starting syllable high byte from word table
+ chip->SyllableAddress = 0; // clear syllable address
+ chip->SyllableAddress |= chip->SpeechRom[(chip->LatchedWord<<1)]<<4;
+ chip->nextstate = chip->resetState ? 1 : 2;
+ break;
+ case 2: // read starting syllable low byte from word table
+ chip->SyllableAddress |= chip->SpeechRom[(chip->LatchedWord<<1)+1]>>4;
+ chip->nextstate = 3;
+ break;
+ case 3: // read starting phone address
+ chip->PhoneAddress = chip->SpeechRom[chip->SyllableAddress]<<4;
+ chip->nextstate = 4;
+ break;
+ case 4: // read playback parameters and prepare for play
+ chip->PlayParams = chip->SpeechRom[chip->SyllableAddress+1];
+ chip->GlobalSilenceState = SILENCEFLAG; // load phone silence flag
+ chip->LengthCounter = LENGTHCOUNT; // load length counter
+ chip->RepeatCounter = REPEATCOUNT; // load repeat counter
+ chip->OutputCounter = 0; // clear output counter and disable mirrored phoneme silence indirectly via LOCALSILENCESTATE
+ chip->PhoneOffset = 0; // set offset within phone to zero
+ chip->OldDelta = 0x2; // set old delta to 2 <- is this right?
+ chip->DACOutput = 0x88; // set DAC output to center/silence position (0x88)
+ chip->nextstate = 5;
+ break;
+ case 5: // Play phone forward, shift = 0 (also load)
+ CurDelta = (chip->SpeechRom[(chip->PhoneAddress)+chip->PhoneOffset]&0xc0)>>6; // grab current delta from high 2 bits of high nybble
+ chip->DACOutput += DeltaTable[CurDelta][chip->OldDelta]; // send data to forward delta table and add result to accumulator
+ chip->OldDelta = CurDelta; // Move current delta to old
+ chip->nextstate = 6;
+ break;
+ case 6: // Play phone forward, shift = 2
+ CurDelta = (chip->SpeechRom[(chip->PhoneAddress)+chip->PhoneOffset]&0x30)>>4; // grab current delta from low 2 bits of high nybble
+ chip->DACOutput += DeltaTable[CurDelta][chip->OldDelta]; // send data to forward delta table and add result to accumulator
+ chip->OldDelta = CurDelta; // Move current delta to old
+ chip->nextstate = 7;
+ break;
+ case 7: // Play phone forward, shift = 4
+ CurDelta = (chip->SpeechRom[(chip->PhoneAddress)+chip->PhoneOffset]&0xc)>>2; // grab current delta from high 2 bits of low nybble
+ chip->DACOutput += DeltaTable[CurDelta][chip->OldDelta]; // send data to forward delta table and add result to accumulator
+ chip->OldDelta = CurDelta; // Move current delta to old
+ chip->nextstate = 8;
+ break;
+ case 8: // Play phone forward, shift = 6 (increment address if needed)
+ CurDelta = chip->SpeechRom[(chip->PhoneAddress)+chip->PhoneOffset]&0x3; // grab current delta from low 2 bits of low nybble
+ chip->DACOutput += DeltaTable[CurDelta][chip->OldDelta]; // send data to forward delta table and add result to accumulator
+ chip->OldDelta = CurDelta; // Move current delta to old
+ chip->PhoneOffset++; // increment phone offset
+ if (chip->PhoneOffset == 0x8) // if we're now done this phone
+ {
+ /* call the PostPhoneme Function */
+ PostPhoneme(chip);
+ }
+ else
+ {
+ chip->nextstate = 5;
+ }
+ break;
+ case 9: // Play phone backward, shift = 6 (also load)
+ CurDelta = (chip->SpeechRom[(chip->PhoneAddress)+chip->PhoneOffset]&0x3); // grab current delta from low 2 bits of low nybble
+ if (chip->laststate != 8) // ignore first (bogus) dac change in mirrored backwards mode. observations and the patent show this.
+ {
+ chip->DACOutput -= DeltaTable[chip->OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator
+ }
+ chip->OldDelta = CurDelta; // Move current delta to old
+ chip->nextstate = 10;
+ break;
+ case 10: // Play phone backward, shift = 4
+ CurDelta = (chip->SpeechRom[(chip->PhoneAddress)+chip->PhoneOffset]&0xc)>>2; // grab current delta from high 2 bits of low nybble
+ chip->DACOutput -= DeltaTable[chip->OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator
+ chip->OldDelta = CurDelta; // Move current delta to old
+ chip->nextstate = 11;
+ break;
+ case 11: // Play phone backward, shift = 2
+ CurDelta = (chip->SpeechRom[(chip->PhoneAddress)+chip->PhoneOffset]&0x30)>>4; // grab current delta from low 2 bits of high nybble
+ chip->DACOutput -= DeltaTable[chip->OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator
+ chip->OldDelta = CurDelta; // Move current delta to old
+ chip->nextstate = 12;
+ break;
+ case 12: // Play phone backward, shift = 0 (increment address if needed)
+ CurDelta = (chip->SpeechRom[(chip->PhoneAddress)+chip->PhoneOffset]&0xc0)>>6; // grab current delta from high 2 bits of high nybble
+ chip->DACOutput -= DeltaTable[chip->OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator
+ chip->OldDelta = CurDelta; // Move current delta to old
+ chip->PhoneOffset--; // decrement phone offset
+ if (chip->PhoneOffset == 0xFF) // if we're now done this phone
+ {
+ /* call the PostPhoneme() function */
+ PostPhoneme(chip);
+ }
+ else
+ {
+ chip->nextstate = 9;
+ }
+ break;
+ case 13: // For those pedantic among us, consume an extra two clocks like the real chip does.
+ chip->nextstate = 0;
+ break;
+ }
+#ifdef DEBUGSTATE
+ fprintf(stderr, "Machine state is now %d, was %d, PhoneOffset is %d\n", chip->nextstate, chip->machineState, chip->PhoneOffset);
+#endif
+ chip->laststate = chip->machineState;
+ chip->machineState = chip->nextstate;
+ }
+}
+
+/**************************************************************************
+ MAME glue code
+ **************************************************************************/
+
+static void s14001a_pcm_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length)
+{
+ INT32 mix[48000];
+ INT32 *mixp;
+ S14001AChip *chip = param;
+ int i;
+
+ memset(mix, 0, sizeof(mix));
+
+ mixp = &mix[0];
+ for (i = 0; i < length; i++)
+ {
+ if (--chip->VSU1000_counter==0)
+ {
+ s14001a_clock(chip);
+ chip->VSU1000_counter = chip->VSU1000_freq;
+ }
+ outputs[0][i] = ((((INT16)chip->audioout)-128)<<6)*chip->VSU1000_amp;
+ }
+}
+
+static void *s14001a_start(int sndindex, int clock, const void *config)
+{
+ const struct S14001A_interface *intf;
+ S14001AChip *chip;
+ int i;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+ chip->index = sndindex;
+
+ chip->GlobalSilenceState = 1;
+ chip->OldDelta = 0x02;
+ chip->DACOutput = SILENCE;
+ chip->VSU1000_amp = 0; /* reset by /reset line */
+ chip->VSU1000_freq = 1; /* base-1; reset by /reset line */
+ chip->VSU1000_counter = 1; /* base-1; not reset by /reset line but this is the best place to reset it */
+
+ for (i = 0; i < 8; i++)
+ {
+ chip->filtervals[i] = SILENCE;
+ }
+
+ intf = config;
+
+ chip->SpeechRom = memory_region(intf->region);
+
+ chip->stream = stream_create(0, 1, clock, chip, s14001a_pcm_update);
+
+ return chip;
+}
+
+static void s14001a_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+int S14001A_bsy_0_r(void)
+{
+ S14001AChip *chip = sndti_token(SOUND_S14001A, 0);
+ stream_update(chip->stream);
+#ifdef DEBUGSTATE
+ fprintf(stderr,"busy state checked: %d\n",(chip->machineState != 0) );
+#endif
+ return (chip->machineState != 0);
+}
+
+void S14001A_reg_0_w(int data)
+{
+ S14001AChip *chip = sndti_token(SOUND_S14001A, 0);
+ stream_update(chip->stream);
+ chip->WordInput = data;
+}
+
+void S14001A_rst_0_w(int data)
+{
+ S14001AChip *chip = sndti_token(SOUND_S14001A, 0);
+ stream_update(chip->stream);
+ chip->LatchedWord = chip->WordInput;
+ chip->resetState = (data==1);
+ chip->machineState = chip->resetState ? 1 : chip->machineState;
+}
+
+void S14001A_set_rate(int newrate)
+{
+ S14001AChip *chip = sndti_token(SOUND_S14001A, 0);
+ stream_update(chip->stream);
+ chip->VSU1000_freq = newrate;
+}
+
+void S14001A_set_volume(int volume)
+{
+ S14001AChip *chip = sndti_token(SOUND_S14001A, 0);
+ stream_update(chip->stream);
+ chip->VSU1000_amp = volume;
+}
+
+void s14001a_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = s14001a_set_info; break;
+ case SNDINFO_PTR_START: info->start = s14001a_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "S14001A"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "TSI S14001A"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.11"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2007 Jonathan Gevaryahu"; break;
+ }
+}
+
diff --git a/src/emu/sound/s14001a.h b/src/emu/sound/s14001a.h
new file mode 100644
index 00000000000..19e7149434a
--- /dev/null
+++ b/src/emu/sound/s14001a.h
@@ -0,0 +1,16 @@
+#ifndef _S14001A_H_
+#define _S14001A_H_
+
+struct S14001A_interface
+{
+ int region; /* memory region where the sample ROM lives */
+};
+
+int S14001A_bsy_0_r(void); /* read BUSY pin */
+void S14001A_reg_0_w(int data); /* write to input latch */
+void S14001A_rst_0_w(int data); /* write to RESET pin */
+void S14001A_set_rate(int newrate); /* set VSU-1000 clock divider */
+void S14001A_set_volume(int volume); /* set VSU-1000 volume control */
+
+#endif
+
diff --git a/src/emu/sound/saa1099.c b/src/emu/sound/saa1099.c
new file mode 100644
index 00000000000..776277e2449
--- /dev/null
+++ b/src/emu/sound/saa1099.c
@@ -0,0 +1,519 @@
+/***************************************************************************
+
+ Philips SAA1099 Sound driver
+
+ By Juergen Buchmueller and Manuel Abadia
+
+ SAA1099 register layout:
+ ========================
+
+ offs | 7654 3210 | description
+ -----+-----------+---------------------------
+ 0x00 | ---- xxxx | Amplitude channel 0 (left)
+ 0x00 | xxxx ---- | Amplitude channel 0 (right)
+ 0x01 | ---- xxxx | Amplitude channel 1 (left)
+ 0x01 | xxxx ---- | Amplitude channel 1 (right)
+ 0x02 | ---- xxxx | Amplitude channel 2 (left)
+ 0x02 | xxxx ---- | Amplitude channel 2 (right)
+ 0x03 | ---- xxxx | Amplitude channel 3 (left)
+ 0x03 | xxxx ---- | Amplitude channel 3 (right)
+ 0x04 | ---- xxxx | Amplitude channel 4 (left)
+ 0x04 | xxxx ---- | Amplitude channel 4 (right)
+ 0x05 | ---- xxxx | Amplitude channel 5 (left)
+ 0x05 | xxxx ---- | Amplitude channel 5 (right)
+ | |
+ 0x08 | xxxx xxxx | Frequency channel 0
+ 0x09 | xxxx xxxx | Frequency channel 1
+ 0x0a | xxxx xxxx | Frequency channel 2
+ 0x0b | xxxx xxxx | Frequency channel 3
+ 0x0c | xxxx xxxx | Frequency channel 4
+ 0x0d | xxxx xxxx | Frequency channel 5
+ | |
+ 0x10 | ---- -xxx | Channel 0 octave select
+ 0x10 | -xxx ---- | Channel 1 octave select
+ 0x11 | ---- -xxx | Channel 2 octave select
+ 0x11 | -xxx ---- | Channel 3 octave select
+ 0x12 | ---- -xxx | Channel 4 octave select
+ 0x12 | -xxx ---- | Channel 5 octave select
+ | |
+ 0x14 | ---- ---x | Channel 0 frequency enable (0 = off, 1 = on)
+ 0x14 | ---- --x- | Channel 1 frequency enable (0 = off, 1 = on)
+ 0x14 | ---- -x-- | Channel 2 frequency enable (0 = off, 1 = on)
+ 0x14 | ---- x--- | Channel 3 frequency enable (0 = off, 1 = on)
+ 0x14 | ---x ---- | Channel 4 frequency enable (0 = off, 1 = on)
+ 0x14 | --x- ---- | Channel 5 frequency enable (0 = off, 1 = on)
+ | |
+ 0x15 | ---- ---x | Channel 0 noise enable (0 = off, 1 = on)
+ 0x15 | ---- --x- | Channel 1 noise enable (0 = off, 1 = on)
+ 0x15 | ---- -x-- | Channel 2 noise enable (0 = off, 1 = on)
+ 0x15 | ---- x--- | Channel 3 noise enable (0 = off, 1 = on)
+ 0x15 | ---x ---- | Channel 4 noise enable (0 = off, 1 = on)
+ 0x15 | --x- ---- | Channel 5 noise enable (0 = off, 1 = on)
+ | |
+ 0x16 | ---- --xx | Noise generator parameters 0
+ 0x16 | --xx ---- | Noise generator parameters 1
+ | |
+ 0x18 | --xx xxxx | Envelope generator 0 parameters
+ 0x18 | x--- ---- | Envelope generator 0 control enable (0 = off, 1 = on)
+ 0x19 | --xx xxxx | Envelope generator 1 parameters
+ 0x19 | x--- ---- | Envelope generator 1 control enable (0 = off, 1 = on)
+ | |
+ 0x1c | ---- ---x | All channels enable (0 = off, 1 = on)
+ 0x1c | ---- --x- | Synch & Reset generators
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "saa1099.h"
+#include <math.h>
+
+
+#define LEFT 0x00
+#define RIGHT 0x01
+
+/* this structure defines a channel */
+struct saa1099_channel
+{
+ int frequency; /* frequency (0x00..0xff) */
+ int freq_enable; /* frequency enable */
+ int noise_enable; /* noise enable */
+ int octave; /* octave (0x00..0x07) */
+ int amplitude[2]; /* amplitude (0x00..0x0f) */
+ int envelope[2]; /* envelope (0x00..0x0f or 0x10 == off) */
+
+ /* vars to simulate the square wave */
+ double counter;
+ double freq;
+ int level;
+};
+
+/* this structure defines a noise channel */
+struct saa1099_noise
+{
+ /* vars to simulate the noise generator output */
+ double counter;
+ double freq;
+ int level; /* noise polynomal shifter */
+};
+
+/* this structure defines a SAA1099 chip */
+struct SAA1099
+{
+ sound_stream * stream; /* our stream */
+ int noise_params[2]; /* noise generators parameters */
+ int env_enable[2]; /* envelope generators enable */
+ int env_reverse_right[2]; /* envelope reversed for right channel */
+ int env_mode[2]; /* envelope generators mode */
+ int env_bits[2]; /* non zero = 3 bits resolution */
+ int env_clock[2]; /* envelope clock mode (non-zero external) */
+ int env_step[2]; /* current envelope step */
+ int all_ch_enable; /* all channels enable */
+ int sync_state; /* sync all channels */
+ int selected_reg; /* selected register */
+ struct saa1099_channel channels[6]; /* channels */
+ struct saa1099_noise noise[2]; /* noise generators */
+ double sample_rate;
+};
+
+static const int amplitude_lookup[16] = {
+ 0*32767/16, 1*32767/16, 2*32767/16, 3*32767/16,
+ 4*32767/16, 5*32767/16, 6*32767/16, 7*32767/16,
+ 8*32767/16, 9*32767/16, 10*32767/16, 11*32767/16,
+ 12*32767/16, 13*32767/16, 14*32767/16, 15*32767/16
+};
+
+static const UINT8 envelope[8][64] = {
+ /* zero amplitude */
+ { 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 },
+ /* maximum amplitude */
+ {15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, },
+ /* single decay */
+ {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 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 },
+ /* repetitive decay */
+ {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
+ /* single triangular */
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 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 },
+ /* repetitive triangular */
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
+ /* single attack */
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,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 },
+ /* repetitive attack */
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 }
+};
+
+static void saa1099_envelope(struct SAA1099 *saa, int ch)
+{
+ if (saa->env_enable[ch])
+ {
+ int step, mode, mask;
+ mode = saa->env_mode[ch];
+ /* step from 0..63 and then loop in steps 32..63 */
+ step = saa->env_step[ch] =
+ ((saa->env_step[ch] + 1) & 0x3f) | (saa->env_step[ch] & 0x20);
+
+ mask = 15;
+ if (saa->env_bits[ch])
+ mask &= ~1; /* 3 bit resolution, mask LSB */
+
+ saa->channels[ch*3+0].envelope[ LEFT] =
+ saa->channels[ch*3+1].envelope[ LEFT] =
+ saa->channels[ch*3+2].envelope[ LEFT] = envelope[mode][step] & mask;
+ if (saa->env_reverse_right[ch] & 0x01)
+ {
+ saa->channels[ch*3+0].envelope[RIGHT] =
+ saa->channels[ch*3+1].envelope[RIGHT] =
+ saa->channels[ch*3+2].envelope[RIGHT] = (15 - envelope[mode][step]) & mask;
+ }
+ else
+ {
+ saa->channels[ch*3+0].envelope[RIGHT] =
+ saa->channels[ch*3+1].envelope[RIGHT] =
+ saa->channels[ch*3+2].envelope[RIGHT] = envelope[mode][step] & mask;
+ }
+ }
+ else
+ {
+ /* envelope mode off, set all envelope factors to 16 */
+ saa->channels[ch*3+0].envelope[ LEFT] =
+ saa->channels[ch*3+1].envelope[ LEFT] =
+ saa->channels[ch*3+2].envelope[ LEFT] =
+ saa->channels[ch*3+0].envelope[RIGHT] =
+ saa->channels[ch*3+1].envelope[RIGHT] =
+ saa->channels[ch*3+2].envelope[RIGHT] = 16;
+ }
+}
+
+
+static void saa1099_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct SAA1099 *saa = param;
+ int j, ch;
+
+ /* if the channels are disabled we're done */
+ if (!saa->all_ch_enable)
+ {
+ /* init output data */
+ memset(buffer[LEFT],0,length*sizeof(*buffer[LEFT]));
+ memset(buffer[RIGHT],0,length*sizeof(*buffer[RIGHT]));
+ return;
+ }
+
+ for (ch = 0; ch < 2; ch++)
+ {
+ switch (saa->noise_params[ch])
+ {
+ case 0: saa->noise[ch].freq = 31250.0 * 2; break;
+ case 1: saa->noise[ch].freq = 15625.0 * 2; break;
+ case 2: saa->noise[ch].freq = 7812.5 * 2; break;
+ case 3: saa->noise[ch].freq = saa->channels[ch * 3].freq; break;
+ }
+ }
+
+ /* fill all data needed */
+ for( j = 0; j < length; j++ )
+ {
+ int output_l = 0, output_r = 0;
+
+ /* for each channel */
+ for (ch = 0; ch < 6; ch++)
+ {
+ if (saa->channels[ch].freq == 0.0)
+ saa->channels[ch].freq = (double)((2 * 15625) << saa->channels[ch].octave) /
+ (511.0 - (double)saa->channels[ch].frequency);
+
+ /* check the actual position in the square wave */
+ saa->channels[ch].counter -= saa->channels[ch].freq;
+ while (saa->channels[ch].counter < 0)
+ {
+ /* calculate new frequency now after the half wave is updated */
+ saa->channels[ch].freq = (double)((2 * 15625) << saa->channels[ch].octave) /
+ (511.0 - (double)saa->channels[ch].frequency);
+
+ saa->channels[ch].counter += saa->sample_rate;
+ saa->channels[ch].level ^= 1;
+
+ /* eventually clock the envelope counters */
+ if (ch == 1 && saa->env_clock[0] == 0)
+ saa1099_envelope(saa, 0);
+ if (ch == 4 && saa->env_clock[1] == 0)
+ saa1099_envelope(saa, 1);
+ }
+
+ /* if the noise is enabled */
+ if (saa->channels[ch].noise_enable)
+ {
+ /* if the noise level is high (noise 0: chan 0-2, noise 1: chan 3-5) */
+ if (saa->noise[ch/3].level & 1)
+ {
+ /* subtract to avoid overflows, also use only half amplitude */
+ output_l -= saa->channels[ch].amplitude[ LEFT] * saa->channels[ch].envelope[ LEFT] / 16 / 2;
+ output_r -= saa->channels[ch].amplitude[RIGHT] * saa->channels[ch].envelope[RIGHT] / 16 / 2;
+ }
+ }
+
+ /* if the square wave is enabled */
+ if (saa->channels[ch].freq_enable)
+ {
+ /* if the channel level is high */
+ if (saa->channels[ch].level & 1)
+ {
+ output_l += saa->channels[ch].amplitude[ LEFT] * saa->channels[ch].envelope[ LEFT] / 16;
+ output_r += saa->channels[ch].amplitude[RIGHT] * saa->channels[ch].envelope[RIGHT] / 16;
+ }
+ }
+ }
+
+ for (ch = 0; ch < 2; ch++)
+ {
+ /* check the actual position in noise generator */
+ saa->noise[ch].counter -= saa->noise[ch].freq;
+ while (saa->noise[ch].counter < 0)
+ {
+ saa->noise[ch].counter += saa->sample_rate;
+ if( ((saa->noise[ch].level & 0x4000) == 0) == ((saa->noise[ch].level & 0x0040) == 0) )
+ saa->noise[ch].level = (saa->noise[ch].level << 1) | 1;
+ else
+ saa->noise[ch].level <<= 1;
+ }
+ }
+ /* write sound data to the buffer */
+ buffer[LEFT][j] = output_l / 6;
+ buffer[RIGHT][j] = output_r / 6;
+ }
+}
+
+
+
+static void *saa1099_start(int sndindex, int clock, const void *config)
+{
+ struct SAA1099 *saa;
+
+ saa = auto_malloc(sizeof(*saa));
+ memset(saa, 0, sizeof(*saa));
+
+ /* copy global parameters */
+ saa->sample_rate = clock / 256;
+
+ /* for each chip allocate one stream */
+ saa->stream = stream_create(0, 2, saa->sample_rate, saa, saa1099_update);
+
+ return saa;
+}
+
+static void saa1099_control_port_w( int chip, int reg, int data )
+{
+ struct SAA1099 *saa = sndti_token(SOUND_SAA1099, chip);
+
+ if ((data & 0xff) > 0x1c)
+ {
+ /* Error! */
+ logerror("%04x: (SAA1099 #%d) Unknown register selected\n",activecpu_get_pc(), chip);
+ }
+
+ saa->selected_reg = data & 0x1f;
+ if (saa->selected_reg == 0x18 || saa->selected_reg == 0x19)
+ {
+ /* clock the envelope channels */
+ if (saa->env_clock[0])
+ saa1099_envelope(saa,0);
+ if (saa->env_clock[1])
+ saa1099_envelope(saa,1);
+ }
+}
+
+
+static void saa1099_write_port_w( int chip, int offset, int data )
+{
+ struct SAA1099 *saa = sndti_token(SOUND_SAA1099, chip);
+ int reg = saa->selected_reg;
+ int ch;
+
+ /* first update the stream to this point in time */
+ stream_update(saa->stream);
+
+ switch (reg)
+ {
+ /* channel i amplitude */
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+ ch = reg & 7;
+ saa->channels[ch].amplitude[LEFT] = amplitude_lookup[data & 0x0f];
+ saa->channels[ch].amplitude[RIGHT] = amplitude_lookup[(data >> 4) & 0x0f];
+ break;
+ /* channel i frequency */
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d:
+ ch = reg & 7;
+ saa->channels[ch].frequency = data & 0xff;
+ break;
+ /* channel i octave */
+ case 0x10: case 0x11: case 0x12:
+ ch = (reg - 0x10) << 1;
+ saa->channels[ch + 0].octave = data & 0x07;
+ saa->channels[ch + 1].octave = (data >> 4) & 0x07;
+ break;
+ /* channel i frequency enable */
+ case 0x14:
+ saa->channels[0].freq_enable = data & 0x01;
+ saa->channels[1].freq_enable = data & 0x02;
+ saa->channels[2].freq_enable = data & 0x04;
+ saa->channels[3].freq_enable = data & 0x08;
+ saa->channels[4].freq_enable = data & 0x10;
+ saa->channels[5].freq_enable = data & 0x20;
+ break;
+ /* channel i noise enable */
+ case 0x15:
+ saa->channels[0].noise_enable = data & 0x01;
+ saa->channels[1].noise_enable = data & 0x02;
+ saa->channels[2].noise_enable = data & 0x04;
+ saa->channels[3].noise_enable = data & 0x08;
+ saa->channels[4].noise_enable = data & 0x10;
+ saa->channels[5].noise_enable = data & 0x20;
+ break;
+ /* noise generators parameters */
+ case 0x16:
+ saa->noise_params[0] = data & 0x03;
+ saa->noise_params[1] = (data >> 4) & 0x03;
+ break;
+ /* envelope generators parameters */
+ case 0x18: case 0x19:
+ ch = reg - 0x18;
+ saa->env_reverse_right[ch] = data & 0x01;
+ saa->env_mode[ch] = (data >> 1) & 0x07;
+ saa->env_bits[ch] = data & 0x10;
+ saa->env_clock[ch] = data & 0x20;
+ saa->env_enable[ch] = data & 0x80;
+ /* reset the envelope */
+ saa->env_step[ch] = 0;
+ break;
+ /* channels enable & reset generators */
+ case 0x1c:
+ saa->all_ch_enable = data & 0x01;
+ saa->sync_state = data & 0x02;
+ if (data & 0x02)
+ {
+ int i;
+
+ /* Synch & Reset generators */
+ logerror("%04x: (SAA1099 #%d) -reg 0x1c- Chip reset\n",activecpu_get_pc(), chip);
+ for (i = 0; i < 6; i++)
+ {
+ saa->channels[i].level = 0;
+ saa->channels[i].counter = 0.0;
+ }
+ }
+ break;
+ default: /* Error! */
+ logerror("%04x: (SAA1099 #%d) Unknown operation (reg:%02x, data:%02x)\n",activecpu_get_pc(), chip, reg, data);
+ }
+}
+
+
+/*******************************************
+ SAA1099 interface functions
+*******************************************/
+
+WRITE8_HANDLER( saa1099_control_port_0_w )
+{
+ saa1099_control_port_w(0, offset, data);
+}
+
+WRITE8_HANDLER( saa1099_write_port_0_w )
+{
+ saa1099_write_port_w(0, offset, data);
+}
+
+WRITE8_HANDLER( saa1099_control_port_1_w )
+{
+ saa1099_control_port_w(1, offset, data);
+}
+
+WRITE8_HANDLER( saa1099_write_port_1_w )
+{
+ saa1099_write_port_w(1, offset, data);
+}
+
+WRITE16_HANDLER( saa1099_control_port_0_lsb_w )
+{
+ if (ACCESSING_LSB)
+ saa1099_control_port_w(0, offset, data & 0xff);
+}
+
+WRITE16_HANDLER( saa1099_write_port_0_lsb_w )
+{
+ if (ACCESSING_LSB)
+ saa1099_write_port_w(0, offset, data & 0xff);
+}
+
+WRITE16_HANDLER( saa1099_control_port_1_lsb_w )
+{
+ if (ACCESSING_LSB)
+ saa1099_control_port_w(1, offset, data & 0xff);
+}
+
+WRITE16_HANDLER( saa1099_write_port_1_lsb_w )
+{
+ if (ACCESSING_LSB)
+ saa1099_write_port_w(1, offset, data & 0xff);
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void saa1099_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void saa1099_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = saa1099_set_info; break;
+ case SNDINFO_PTR_START: info->start = saa1099_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "SAA1099"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Philips"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/saa1099.h b/src/emu/sound/saa1099.h
new file mode 100644
index 00000000000..b8fe520cb91
--- /dev/null
+++ b/src/emu/sound/saa1099.h
@@ -0,0 +1,18 @@
+#ifndef saa1099_h
+#define saa1099_h
+
+/**********************************************
+ Philips SAA1099 Sound driver
+**********************************************/
+
+WRITE8_HANDLER( saa1099_control_port_0_w );
+WRITE8_HANDLER( saa1099_write_port_0_w );
+WRITE8_HANDLER( saa1099_control_port_1_w );
+WRITE8_HANDLER( saa1099_write_port_1_w );
+
+WRITE16_HANDLER( saa1099_control_port_0_lsb_w );
+WRITE16_HANDLER( saa1099_write_port_0_lsb_w );
+WRITE16_HANDLER( saa1099_control_port_1_lsb_w );
+WRITE16_HANDLER( saa1099_write_port_1_lsb_w );
+
+#endif
diff --git a/src/emu/sound/samples.c b/src/emu/sound/samples.c
new file mode 100644
index 00000000000..8d773916e10
--- /dev/null
+++ b/src/emu/sound/samples.c
@@ -0,0 +1,612 @@
+#include "driver.h"
+#include "streams.h"
+#include "samples.h"
+
+
+struct sample_channel
+{
+ sound_stream *stream;
+ INT16 * source;
+ INT32 source_length;
+ INT32 source_num;
+ UINT32 pos;
+ UINT32 frac;
+ UINT32 step;
+ UINT32 basefreq;
+ UINT8 loop;
+ UINT8 paused;
+};
+
+struct samples_info
+{
+ int numchannels; /* how many channels */
+ struct sample_channel *channel;/* array of channels */
+ struct loaded_samples *samples;/* array of samples */
+};
+
+
+
+#define FRAC_BITS 24
+#define FRAC_ONE (1 << FRAC_BITS)
+#define FRAC_MASK (FRAC_ONE - 1)
+#define MAX_CHANNELS 100
+
+
+/*-------------------------------------------------
+ read_wav_sample - read a WAV file as a sample
+-------------------------------------------------*/
+
+#ifdef LSB_FIRST
+#define intelLong(x) (x)
+#else
+#define intelLong(x) (((x << 24) | (((unsigned long) x) >> 24) | (( x & 0x0000ff00) << 8) | (( x & 0x00ff0000) >> 8)))
+#endif
+
+static int read_wav_sample(mame_file *f, struct loaded_sample *sample)
+{
+ unsigned long offset = 0;
+ UINT32 length, rate, filesize;
+ UINT16 bits, temp16;
+ char buf[32];
+ #ifndef LSB_FIRST
+ UINT32 sindex;
+ #endif
+
+ /* read the core header and make sure it's a WAVE file */
+ offset += mame_fread(f, buf, 4);
+ if (offset < 4)
+ return 0;
+ if (memcmp(&buf[0], "RIFF", 4) != 0)
+ return 0;
+
+ /* get the total size */
+ offset += mame_fread(f, &filesize, 4);
+ if (offset < 8)
+ return 0;
+ filesize = intelLong(filesize);
+
+ /* read the RIFF file type and make sure it's a WAVE file */
+ offset += mame_fread(f, buf, 4);
+ if (offset < 12)
+ return 0;
+ if (memcmp(&buf[0], "WAVE", 4) != 0)
+ return 0;
+
+ /* seek until we find a format tag */
+ while (1)
+ {
+ offset += mame_fread(f, buf, 4);
+ offset += mame_fread(f, &length, 4);
+ length = intelLong(length);
+ if (memcmp(&buf[0], "fmt ", 4) == 0)
+ break;
+
+ /* seek to the next block */
+ mame_fseek(f, length, SEEK_CUR);
+ offset += length;
+ if (offset >= filesize)
+ return 0;
+ }
+
+ /* read the format -- make sure it is PCM */
+ offset += mame_fread(f, &temp16, 2);
+ temp16 = LITTLE_ENDIANIZE_INT16(temp16);
+ if (temp16 != 1)
+ return 0;
+
+ /* number of channels -- only mono is supported */
+ offset += mame_fread(f, &temp16, 2);
+ temp16 = LITTLE_ENDIANIZE_INT16(temp16);
+ if (temp16 != 1)
+ return 0;
+
+ /* sample rate */
+ offset += mame_fread(f, &rate, 4);
+ rate = intelLong(rate);
+
+ /* bytes/second and block alignment are ignored */
+ offset += mame_fread(f, buf, 6);
+
+ /* bits/sample */
+ offset += mame_fread(f, &bits, 2);
+ bits = LITTLE_ENDIANIZE_INT16(bits);
+ if (bits != 8 && bits != 16)
+ return 0;
+
+ /* seek past any extra data */
+ mame_fseek(f, length - 16, SEEK_CUR);
+ offset += length - 16;
+
+ /* seek until we find a data tag */
+ while (1)
+ {
+ offset += mame_fread(f, buf, 4);
+ offset += mame_fread(f, &length, 4);
+ length = intelLong(length);
+ if (memcmp(&buf[0], "data", 4) == 0)
+ break;
+
+ /* seek to the next block */
+ mame_fseek(f, length, SEEK_CUR);
+ offset += length;
+ if (offset >= filesize)
+ return 0;
+ }
+
+ /* if there was a 0 length data block, we're done */
+ if (length == 0)
+ return 0;
+
+ /* fill in the sample data */
+ sample->length = length;
+ sample->frequency = rate;
+
+ /* read the data in */
+ if (bits == 8)
+ {
+ unsigned char *tempptr;
+ int sindex;
+
+ sample->data = auto_malloc(sizeof(*sample->data) * length);
+ mame_fread(f, sample->data, length);
+
+ /* convert 8-bit data to signed samples */
+ tempptr = (unsigned char *)sample->data;
+ for (sindex = length - 1; sindex >= 0; sindex--)
+ sample->data[sindex] = (INT8)(tempptr[sindex] ^ 0x80) * 256;
+ }
+ else
+ {
+ /* 16-bit data is fine as-is */
+ sample->data = auto_malloc(sizeof(*sample->data) * (length/2));
+ mame_fread(f, sample->data, length);
+ sample->length /= 2;
+#ifndef LSB_FIRST
+ for (sindex = 0; sindex < sample->length; sindex++)
+ sample->data[sindex] = LITTLE_ENDIANIZE_INT16(sample->data[sindex]);
+#endif
+ }
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ readsamples - load all samples
+-------------------------------------------------*/
+
+struct loaded_samples *readsamples(const char **samplenames, const char *basename)
+{
+ struct loaded_samples *samples;
+ int skipfirst = 0;
+ int i;
+
+ /* if the user doesn't want to use samples, bail */
+ if (!options_get_bool(mame_options(), OPTION_SAMPLES))
+ return NULL;
+ if (samplenames == 0 || samplenames[0] == 0)
+ return NULL;
+
+ /* if a name begins with '*', we will also look under that as an alternate basename */
+ if (samplenames[0][0] == '*')
+ skipfirst = 1;
+
+ /* count the samples */
+ for (i = 0; samplenames[i+skipfirst] != 0; i++) ;
+ if (i == 0)
+ return NULL;
+
+ /* allocate the array */
+ samples = auto_malloc(sizeof(struct loaded_samples) + (i-1) * sizeof(struct loaded_sample));
+ memset(samples, 0, sizeof(struct loaded_samples) + (i-1) * sizeof(struct loaded_sample));
+ samples->total = i;
+
+ /* load the samples */
+ for (i = 0; i < samples->total; i++)
+ if (samplenames[i+skipfirst][0])
+ {
+ file_error filerr;
+ mame_file *f;
+ astring *fname;
+
+ fname = astring_assemble_3(astring_alloc(), basename, PATH_SEPARATOR, samplenames[i+skipfirst]);
+ filerr = mame_fopen(SEARCHPATH_SAMPLE, astring_c(fname), OPEN_FLAG_READ, &f);
+
+ if (filerr != FILERR_NONE && skipfirst)
+ {
+ astring_assemble_3(fname, samplenames[0] + 1, PATH_SEPARATOR, samplenames[i+skipfirst]);
+ filerr = mame_fopen(SEARCHPATH_SAMPLE, astring_c(fname), OPEN_FLAG_READ, &f);
+ }
+ if (filerr == FILERR_NONE)
+ {
+ read_wav_sample(f, &samples->sample[i]);
+ mame_fclose(f);
+ }
+
+ astring_free(fname);
+ }
+
+ return samples;
+}
+
+
+
+
+/* Start one of the samples loaded from disk. Note: channel must be in the range */
+/* 0 .. Samplesinterface->channels-1. It is NOT the discrete channel to pass to */
+/* mixer_play_sample() */
+void sample_start_n(int num,int channel,int samplenum,int loop)
+{
+ struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
+ struct sample_channel *chan;
+ struct loaded_sample *sample;
+
+ /* if samples are disabled, just return quietly */
+ if (info->samples == NULL)
+ return;
+
+ assert( samplenum < info->samples->total );
+ assert( channel < info->numchannels );
+
+ chan = &info->channel[channel];
+
+ /* force an update before we start */
+ stream_update(chan->stream);
+
+ /* update the parameters */
+ sample = &info->samples->sample[samplenum];
+ chan->source = sample->data;
+ chan->source_length = sample->length;
+ chan->source_num = sample->data ? samplenum : -1;
+ chan->pos = 0;
+ chan->frac = 0;
+ chan->basefreq = sample->frequency;
+ chan->step = ((INT64)chan->basefreq << FRAC_BITS) / Machine->sample_rate;
+ chan->loop = loop;
+}
+
+void sample_start(int channel,int samplenum,int loop)
+{
+ sample_start_n(0,channel,samplenum,loop);
+}
+
+
+void sample_start_raw_n(int num,int channel,INT16 *sampledata,int samples,int frequency,int loop)
+{
+ struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
+ struct sample_channel *chan;
+
+ assert( channel < info->numchannels );
+
+ chan = &info->channel[channel];
+
+ /* force an update before we start */
+ stream_update(chan->stream);
+
+ /* update the parameters */
+ chan->source = sampledata;
+ chan->source_length = samples;
+ chan->source_num = -1;
+ chan->pos = 0;
+ chan->frac = 0;
+ chan->basefreq = frequency;
+ chan->step = ((INT64)chan->basefreq << FRAC_BITS) / Machine->sample_rate;
+ chan->loop = loop;
+}
+
+void sample_start_raw(int channel,INT16 *sampledata,int samples,int frequency,int loop)
+{
+ sample_start_raw_n(0,channel,sampledata,samples,frequency,loop);
+}
+
+
+void sample_set_freq_n(int num,int channel,int freq)
+{
+ struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
+ struct sample_channel *chan;
+
+ assert( channel < info->numchannels );
+
+ chan = &info->channel[channel];
+
+ /* force an update before we start */
+ stream_update(chan->stream);
+
+ chan->step = ((INT64)freq << FRAC_BITS) / Machine->sample_rate;
+}
+
+void sample_set_freq(int channel,int freq)
+{
+ sample_set_freq_n(0,channel,freq);
+}
+
+
+void sample_set_volume_n(int num,int channel,float volume)
+{
+ struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
+ struct sample_channel *chan;
+
+ assert( channel < info->numchannels );
+
+ chan = &info->channel[channel];
+
+ stream_set_output_gain(chan->stream, 0, volume);
+}
+
+void sample_set_volume(int channel,float volume)
+{
+ sample_set_volume_n(0,channel,volume);
+}
+
+
+void sample_set_pause_n(int num,int channel,int pause)
+{
+ struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
+ struct sample_channel *chan;
+
+ assert( channel < info->numchannels );
+
+ chan = &info->channel[channel];
+
+ /* force an update before we start */
+ stream_update(chan->stream);
+
+ chan->paused = pause;
+}
+
+void sample_set_pause(int channel,int pause)
+{
+ sample_set_pause_n(0,channel,pause);
+}
+
+
+void sample_stop_n(int num,int channel)
+{
+ struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
+ struct sample_channel *chan;
+
+ assert( channel < info->numchannels );
+
+ chan = &info->channel[channel];
+
+ /* force an update before we start */
+ stream_update(chan->stream);
+ chan->source = NULL;
+ chan->source_num = -1;
+}
+
+void sample_stop(int channel)
+{
+ sample_stop_n(0,channel);
+}
+
+
+int sample_get_base_freq_n(int num,int channel)
+{
+ struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
+ struct sample_channel *chan;
+
+ assert( channel < info->numchannels );
+
+ chan = &info->channel[channel];
+
+ /* force an update before we start */
+ stream_update(chan->stream);
+ return chan->basefreq;
+}
+
+int sample_get_base_freq(int channel)
+{
+ return sample_get_base_freq_n(0,channel);
+}
+
+
+int sample_playing_n(int num,int channel)
+{
+ struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
+ struct sample_channel *chan;
+
+ assert( channel < info->numchannels );
+
+ chan = &info->channel[channel];
+
+ /* force an update before we start */
+ stream_update(chan->stream);
+ return (chan->source != NULL);
+}
+
+int sample_playing(int channel)
+{
+ return sample_playing_n(0,channel);
+}
+
+
+int sample_loaded_n(int num,int samplenum)
+{
+ int ret = 0;
+ struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
+
+ if (info->samples != NULL)
+ {
+ assert( samplenum < info->samples->total );
+
+ ret = (info->samples->sample[samplenum].data != NULL);
+ }
+
+ return ret;
+}
+
+int sample_loaded(int samplenum)
+{
+ return sample_loaded_n(0,samplenum);
+}
+
+
+static void sample_update_sound(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct sample_channel *chan = param;
+ stream_sample_t *buffer = _buffer[0];
+
+ if (chan->source && !chan->paused)
+ {
+ /* load some info locally */
+ UINT32 pos = chan->pos;
+ UINT32 frac = chan->frac;
+ UINT32 step = chan->step;
+ INT16 *sample = chan->source;
+ UINT32 sample_length = chan->source_length;
+
+ while (length--)
+ {
+ /* do a linear interp on the sample */
+ INT32 sample1 = sample[pos];
+ INT32 sample2 = sample[(pos + 1) % sample_length];
+ INT32 fracmult = frac >> (FRAC_BITS - 14);
+ *buffer++ = ((0x4000 - fracmult) * sample1 + fracmult * sample2) >> 14;
+
+ /* advance */
+ frac += step;
+ pos += frac >> FRAC_BITS;
+ frac = frac & ((1 << FRAC_BITS) - 1);
+
+ /* handle looping/ending */
+ if (pos >= sample_length)
+ {
+ if (chan->loop)
+ pos %= sample_length;
+ else
+ {
+ chan->source = NULL;
+ chan->source_num = -1;
+ if (length > 0)
+ memset(buffer, 0, length * sizeof(*buffer));
+ break;
+ }
+ }
+ }
+
+ /* push position back out */
+ chan->pos = pos;
+ chan->frac = frac;
+ }
+ else
+ memset(buffer, 0, length * sizeof(*buffer));
+}
+
+
+static void samples_postload(void *param)
+{
+ struct samples_info *info = param;
+ int i;
+
+ /* loop over channels */
+ for (i = 0; i < info->numchannels; i++)
+ {
+ struct sample_channel *chan = &info->channel[i];
+
+ /* attach any samples that were loaded and playing */
+ if (chan->source_num >= 0 && chan->source_num < info->samples->total)
+ {
+ struct loaded_sample *sample = &info->samples->sample[chan->source_num];
+ chan->source = sample->data;
+ chan->source_length = sample->length;
+ if (!sample->data)
+ chan->source_num = -1;
+ }
+
+ /* validate the position against the length in case the sample is smaller */
+ if (chan->source && chan->pos >= chan->source_length)
+ {
+ if (chan->loop)
+ chan->pos %= chan->source_length;
+ else
+ {
+ chan->source = NULL;
+ chan->source_num = -1;
+ }
+ }
+ }
+}
+
+
+static void *samples_start(int sndindex, int clock, const void *config)
+{
+ int i;
+ const struct Samplesinterface *intf = config;
+ struct samples_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+ sndintrf_register_token(info);
+
+ /* read audio samples */
+ if (intf->samplenames)
+ info->samples = readsamples(intf->samplenames,Machine->gamedrv->name);
+
+ /* allocate channels */
+ info->numchannels = intf->channels;
+ assert(info->numchannels < MAX_CHANNELS);
+ info->channel = auto_malloc(sizeof(*info->channel) * info->numchannels);
+ for (i = 0; i < info->numchannels; i++)
+ {
+ info->channel[i].stream = stream_create(0, 1, Machine->sample_rate, &info->channel[i], sample_update_sound);
+
+ info->channel[i].source = NULL;
+ info->channel[i].source_num = -1;
+ info->channel[i].step = 0;
+ info->channel[i].loop = 0;
+ info->channel[i].paused = 0;
+
+ /* register with the save state system */
+ state_save_register_item("samples", sndindex * MAX_CHANNELS + i, info->channel[i].source_length);
+ state_save_register_item("samples", sndindex * MAX_CHANNELS + i, info->channel[i].source_num);
+ state_save_register_item("samples", sndindex * MAX_CHANNELS + i, info->channel[i].pos);
+ state_save_register_item("samples", sndindex * MAX_CHANNELS + i, info->channel[i].frac);
+ state_save_register_item("samples", sndindex * MAX_CHANNELS + i, info->channel[i].step);
+ state_save_register_item("samples", sndindex * MAX_CHANNELS + i, info->channel[i].loop);
+ state_save_register_item("samples", sndindex * MAX_CHANNELS + i, info->channel[i].paused);
+ }
+ state_save_register_func_postload_ptr(samples_postload, info);
+
+ /* initialize any custom handlers */
+ if (intf->start)
+ (*intf->start)();
+
+ return info;
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void samples_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void samples_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = samples_set_info; break;
+ case SNDINFO_PTR_START: info->start = samples_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Samples"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Big Hack"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.1"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2007, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/samples.h b/src/emu/sound/samples.h
new file mode 100644
index 00000000000..334899d09ce
--- /dev/null
+++ b/src/emu/sound/samples.h
@@ -0,0 +1,50 @@
+#ifndef SAMPLES_H
+#define SAMPLES_H
+
+struct loaded_sample
+{
+ int length; /* length in samples */
+ int frequency; /* frequency of the sample */
+ INT16 * data; /* 16-bit signed data */
+};
+
+struct loaded_samples
+{
+ int total; /* number of samples */
+ struct loaded_sample sample[1]; /* array of samples */
+};
+
+struct Samplesinterface
+{
+ int channels; /* number of discrete audio channels needed */
+ const char **samplenames;
+ void (*start)(void);
+};
+
+
+void sample_start_n(int num,int channel,int samplenum,int loop);
+void sample_start_raw_n(int num,int channel,INT16 *sampledata,int samples,int frequency,int loop);
+void sample_set_freq_n(int num,int channel,int freq);
+void sample_set_volume_n(int num,int channel,float volume);
+void sample_set_pause_n(int num,int channel,int pause);
+void sample_stop_n(int num,int channel);
+int sample_get_base_freq_n(int num,int channel);
+int sample_playing_n(int num,int channel);
+int sample_loaded_n(int num,int samplenum);
+
+/* shortcuts for backwards compatibilty */
+void sample_start(int channel,int samplenum,int loop);
+void sample_start_raw(int channel,INT16 *sampledata,int samples,int frequency,int loop);
+void sample_set_freq(int channel,int freq);
+void sample_set_volume(int channel,float volume);
+void sample_set_pause(int channel,int pause);
+void sample_stop(int channel);
+int sample_get_base_freq(int channel);
+int sample_playing(int channel);
+int sample_loaded(int samplenum);
+
+/* helper function that reads samples from disk - this can be used by other */
+/* drivers as well (e.g. a sound chip emulator needing drum samples) */
+struct loaded_samples *readsamples(const char **samplenames, const char *name);
+
+#endif
diff --git a/src/emu/sound/scsp.c b/src/emu/sound/scsp.c
new file mode 100644
index 00000000000..357d7c3bb84
--- /dev/null
+++ b/src/emu/sound/scsp.c
@@ -0,0 +1,1567 @@
+/*
+ Sega/Yamaha YMF292-F (SCSP = Saturn Custom Sound Processor) emulation
+ By ElSemi
+ MAME/M1 conversion and cleanup by R. Belmont
+
+ This chip has 32 voices. Each voice can play a sample or be part of
+ an FM construct. Unlike traditional Yamaha FM chips, the base waveform
+ for the FM still comes from the wavetable RAM.
+
+ Unsupported:
+ - FM mode (VF3 uses it, Hanagumi might late in the title song...)
+
+ ChangeLog:
+ * November 25, 2003 (ES) Fixed buggy timers and envelope overflows.
+ (RB) Improved sample rates other than 44100, multiple
+ chips now works properly.
+ * December 02, 2003 (ES) Added DISDL register support, improves mix.
+ * April 28, 2004 (ES) Corrected envelope rates, added key-rate scaling,
+ added ringbuffer support.
+ * January 8, 2005 (RB) Added ability to specify region offset for RAM.
+ * January 26, 2007 (ES) Added on-board DSP capability
+ * September 24, 2007 (RB+ES) Removed fake reverb. Rewrote timers and IRQ handling.
+ Fixed case where voice frequency is updated while looping.
+ Enabled DSP again.
+*/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "scsp.h"
+#include "scspdsp.h"
+
+
+#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x)
+
+#define SHIFT 12
+#define FIX(v) ((UINT32) ((float) (1<<SHIFT)*(v)))
+
+
+#define EG_SHIFT 8
+
+// include the LFO handling code
+#include "scsplfo.c"
+
+/*
+ SCSP features 32 programmable slots
+ that can generate FM and PCM (from ROM/RAM) sound
+*/
+
+//SLOT PARAMETERS
+#define KEYONEX(slot) ((slot->udata.data[0x0]>>0x0)&0x1000)
+#define KEYONB(slot) ((slot->udata.data[0x0]>>0x0)&0x0800)
+#define SBCTL(slot) ((slot->udata.data[0x0]>>0x9)&0x0003)
+#define SSCTL(slot) ((slot->udata.data[0x0]>>0x7)&0x0003)
+#define LPCTL(slot) ((slot->udata.data[0x0]>>0x5)&0x0003)
+#define PCM8B(slot) ((slot->udata.data[0x0]>>0x0)&0x0010)
+
+#define SA(slot) (((slot->udata.data[0x0]&0xF)<<16)|(slot->udata.data[0x1]))
+
+#define LSA(slot) (slot->udata.data[0x2])
+
+#define LEA(slot) (slot->udata.data[0x3])
+
+#define D2R(slot) ((slot->udata.data[0x4]>>0xB)&0x001F)
+#define D1R(slot) ((slot->udata.data[0x4]>>0x6)&0x001F)
+#define EGHOLD(slot) ((slot->udata.data[0x4]>>0x0)&0x0020)
+#define AR(slot) ((slot->udata.data[0x4]>>0x0)&0x001F)
+
+#define LPSLNK(slot) ((slot->udata.data[0x5]>>0x0)&0x4000)
+#define KRS(slot) ((slot->udata.data[0x5]>>0xA)&0x000F)
+#define DL(slot) ((slot->udata.data[0x5]>>0x5)&0x001F)
+#define RR(slot) ((slot->udata.data[0x5]>>0x0)&0x001F)
+
+#define STWINH(slot) ((slot->udata.data[0x6]>>0x0)&0x0200)
+#define SDIR(slot) ((slot->udata.data[0x6]>>0x0)&0x0100)
+#define TL(slot) ((slot->udata.data[0x6]>>0x0)&0x00FF)
+
+#define MDL(slot) ((slot->udata.data[0x7]>>0xB)&0x0007)
+#define MDXSL(slot) ((slot->udata.data[0x7]>>0x6)&0x003F)
+#define MDYSL(slot) ((slot->udata.data[0x7]>>0x0)&0x003F)
+
+#define OCT(slot) ((slot->udata.data[0x8]>>0xB)&0x000F)
+#define FNS(slot) ((slot->udata.data[0x8]>>0x0)&0x03FF)
+
+#define LFORE(slot) ((slot->udata.data[0x9]>>0x0)&0x8000)
+#define LFOF(slot) ((slot->udata.data[0x9]>>0xA)&0x001F)
+#define PLFOWS(slot) ((slot->udata.data[0x9]>>0x8)&0x0003)
+#define PLFOS(slot) ((slot->udata.data[0x9]>>0x5)&0x0007)
+#define ALFOWS(slot) ((slot->udata.data[0x9]>>0x3)&0x0003)
+#define ALFOS(slot) ((slot->udata.data[0x9]>>0x0)&0x0007)
+
+#define ISEL(slot) ((slot->udata.data[0xA]>>0x3)&0x000F)
+#define IMXL(slot) ((slot->udata.data[0xA]>>0x0)&0x0007)
+
+#define DISDL(slot) ((slot->udata.data[0xB]>>0xD)&0x0007)
+#define DIPAN(slot) ((slot->udata.data[0xB]>>0x8)&0x001F)
+#define EFSDL(slot) ((slot->udata.data[0xB]>>0x5)&0x0007)
+#define EFPAN(slot) ((slot->udata.data[0xB]>>0x0)&0x001F)
+
+//Envelope times in ms
+static const double ARTimes[64]={100000/*infinity*/,100000/*infinity*/,8100.0,6900.0,6000.0,4800.0,4000.0,3400.0,3000.0,2400.0,2000.0,1700.0,1500.0,
+ 1200.0,1000.0,860.0,760.0,600.0,500.0,430.0,380.0,300.0,250.0,220.0,190.0,150.0,130.0,110.0,95.0,
+ 76.0,63.0,55.0,47.0,38.0,31.0,27.0,24.0,19.0,15.0,13.0,12.0,9.4,7.9,6.8,6.0,4.7,3.8,3.4,3.0,2.4,
+ 2.0,1.8,1.6,1.3,1.1,0.93,0.85,0.65,0.53,0.44,0.40,0.35,0.0,0.0};
+static const double DRTimes[64]={100000/*infinity*/,100000/*infinity*/,118200.0,101300.0,88600.0,70900.0,59100.0,50700.0,44300.0,35500.0,29600.0,25300.0,22200.0,17700.0,
+ 14800.0,12700.0,11100.0,8900.0,7400.0,6300.0,5500.0,4400.0,3700.0,3200.0,2800.0,2200.0,1800.0,1600.0,1400.0,1100.0,
+ 920.0,790.0,690.0,550.0,460.0,390.0,340.0,270.0,230.0,200.0,170.0,140.0,110.0,98.0,85.0,68.0,57.0,49.0,43.0,34.0,
+ 28.0,25.0,22.0,18.0,14.0,12.0,11.0,8.5,7.1,6.1,5.4,4.3,3.6,3.1};
+static UINT32 FNS_Table[0x400];
+
+typedef enum {ATTACK,DECAY1,DECAY2,RELEASE} _STATE;
+struct _EG
+{
+ int volume; //
+ _STATE state;
+ int step;
+ //step vals
+ int AR; //Attack
+ int D1R; //Decay1
+ int D2R; //Decay2
+ int RR; //Release
+
+ int DL; //Decay level
+ UINT8 EGHOLD;
+ UINT8 LPLINK;
+};
+
+struct _SLOT
+{
+ union
+ {
+ UINT16 data[0x10]; //only 0x1a bytes used
+ UINT8 datab[0x20];
+ } udata;
+ UINT8 Backwards; //the wave is playing backwards
+ UINT8 active; //this slot is currently playing
+ UINT8 *base; //samples base address
+ UINT32 cur_addr; //current play address (24.8)
+ UINT32 step; //pitch step (24.8)
+ struct _EG EG; //Envelope
+ struct _LFO PLFO; //Phase LFO
+ struct _LFO ALFO; //Amplitude LFO
+ int slot;
+ signed short Prev; //Previous sample (for interpolation)
+};
+
+
+#define MEM4B(scsp) ((scsp->udata.data[0]>>0x0)&0x0200)
+#define DAC18B(scsp) ((scsp->udata.data[0]>>0x0)&0x0100)
+#define MVOL(scsp) ((scsp->udata.data[0]>>0x0)&0x000F)
+#define RBL(scsp) ((scsp->udata.data[1]>>0x7)&0x0003)
+#define RBP(scsp) ((scsp->udata.data[1]>>0x0)&0x003F)
+#define MOFULL(scsp) ((scsp->udata.data[2]>>0x0)&0x1000)
+#define MOEMPTY(scsp) ((scsp->udata.data[2]>>0x0)&0x0800)
+#define MIOVF(scsp) ((scsp->udata.data[2]>>0x0)&0x0400)
+#define MIFULL(scsp) ((scsp->udata.data[2]>>0x0)&0x0200)
+#define MIEMPTY(scsp) ((scsp->udata.data[2]>>0x0)&0x0100)
+
+#define SCILV0(scsp) ((scsp->udata.data[0x24/2]>>0x0)&0xff)
+#define SCILV1(scsp) ((scsp->udata.data[0x26/2]>>0x0)&0xff)
+#define SCILV2(scsp) ((scsp->udata.data[0x28/2]>>0x0)&0xff)
+
+#define SCIEX0 0
+#define SCIEX1 1
+#define SCIEX2 2
+#define SCIMID 3
+#define SCIDMA 4
+#define SCIIRQ 5
+#define SCITMA 6
+#define SCITMB 7
+
+#define USEDSP
+
+struct _SCSP
+{
+ union
+ {
+ UINT16 data[0x30/2];
+ UINT8 datab[0x30];
+ } udata;
+ struct _SLOT Slots[32];
+ signed short RINGBUF[64];
+ unsigned char BUFPTR;
+ unsigned char *SCSPRAM;
+ UINT32 SCSPRAM_LENGTH;
+ char Master;
+ void (*Int68kCB)(int irq);
+ sound_stream * stream;
+
+ INT32 *buffertmpl,*buffertmpr;
+
+ UINT32 IrqTimA;
+ UINT32 IrqTimBC;
+ UINT32 IrqMidi;
+
+ UINT8 MidiOutW,MidiOutR;
+ UINT8 MidiStack[32];
+ UINT8 MidiW,MidiR;
+
+ int LPANTABLE[0x10000];
+ int RPANTABLE[0x10000];
+
+ int TimPris[3];
+ int TimCnt[3];
+
+ // timers
+ emu_timer *timerA, *timerB, *timerC;
+
+ // DMA stuff
+ UINT32 scsp_dmea;
+ UINT16 scsp_drga;
+ UINT16 scsp_dtlg;
+
+ int ARTABLE[64], DRTABLE[64];
+
+#ifdef USEDSP
+ struct _SCSPDSP DSP;
+#endif
+};
+
+static void dma_scsp(struct _SCSP *SCSP); /*SCSP DMA transfer function*/
+#define scsp_dgate scsp_regs[0x16/2] & 0x4000
+#define scsp_ddir scsp_regs[0x16/2] & 0x2000
+#define scsp_dexe scsp_regs[0x16/2] & 0x1000
+#define dma_transfer_end ((scsp_regs[0x24/2] & 0x10)>>4)|(((scsp_regs[0x26/2] & 0x10)>>4)<<1)|(((scsp_regs[0x28/2] & 0x10)>>4)<<2)
+
+static const float SDLT[8]={-1000000.0,-36.0,-30.0,-24.0,-18.0,-12.0,-6.0,0.0};
+
+static stream_sample_t *bufferl;
+static stream_sample_t *bufferr;
+
+static int length;
+
+
+static signed short *RBUFDST; //this points to where the sample will be stored in the RingBuf
+
+static unsigned char DecodeSCI(struct _SCSP *SCSP,unsigned char irq)
+{
+ unsigned char SCI=0;
+ unsigned char v;
+ v=(SCILV0((SCSP))&(1<<irq))?1:0;
+ SCI|=v;
+ v=(SCILV1((SCSP))&(1<<irq))?1:0;
+ SCI|=v<<1;
+ v=(SCILV2((SCSP))&(1<<irq))?1:0;
+ SCI|=v<<2;
+ return SCI;
+}
+
+static void CheckPendingIRQ(struct _SCSP *SCSP)
+{
+ UINT32 pend=SCSP->udata.data[0x20/2];
+ UINT32 en=SCSP->udata.data[0x1e/2];
+ if(SCSP->MidiW!=SCSP->MidiR)
+ {
+ SCSP->udata.data[0x20/2] |= 8;
+ pend |= 8;
+ }
+ if(!pend)
+ return;
+ if(pend&0x40)
+ if(en&0x40)
+ {
+ SCSP->Int68kCB(SCSP->IrqTimA);
+ return;
+ }
+ if(pend&0x80)
+ if(en&0x80)
+ {
+ SCSP->Int68kCB(SCSP->IrqTimBC);
+ return;
+ }
+ if(pend&0x100)
+ if(en&0x100)
+ {
+ SCSP->Int68kCB(SCSP->IrqTimBC);
+ return;
+ }
+ if(pend&8)
+ if (en&8)
+ {
+ SCSP->Int68kCB(SCSP->IrqMidi);
+ SCSP->udata.data[0x20/2] &= ~8;
+ return;
+ }
+
+ SCSP->Int68kCB(0);
+}
+
+static void ResetInterrupts(struct _SCSP *SCSP)
+{
+ UINT32 reset = SCSP->udata.data[0x22/2];
+
+ if (reset & 0x40)
+ {
+ SCSP->Int68kCB(-SCSP->IrqTimA);
+ }
+ if (reset & 0x180)
+ {
+ SCSP->Int68kCB(-SCSP->IrqTimBC);
+ }
+ if (reset & 0x8)
+ {
+ SCSP->Int68kCB(-SCSP->IrqMidi);
+ }
+
+ CheckPendingIRQ(SCSP);
+}
+
+static TIMER_CALLBACK_PTR( timerA_cb )
+{
+ struct _SCSP *SCSP = (struct _SCSP *)param;
+
+ SCSP->TimCnt[0] = 0xFFFF;
+ SCSP->udata.data[0x20/2]|=0x40;
+ SCSP->udata.data[0x18/2]&=0xff00;
+ SCSP->udata.data[0x18/2]|=SCSP->TimCnt[0]>>8;
+
+ CheckPendingIRQ(SCSP);
+}
+
+static TIMER_CALLBACK_PTR( timerB_cb )
+{
+ struct _SCSP *SCSP = (struct _SCSP *)param;
+
+ SCSP->TimCnt[1] = 0xFFFF;
+ SCSP->udata.data[0x20/2]|=0x80;
+ SCSP->udata.data[0x1a/2]&=0xff00;
+ SCSP->udata.data[0x1a/2]|=SCSP->TimCnt[0]>>8;
+
+ CheckPendingIRQ(SCSP);
+}
+
+static TIMER_CALLBACK_PTR( timerC_cb )
+{
+ struct _SCSP *SCSP = (struct _SCSP *)param;
+
+ SCSP->TimCnt[2] = 0xFFFF;
+ SCSP->udata.data[0x20/2]|=0x100;
+ SCSP->udata.data[0x1c/2]&=0xff00;
+ SCSP->udata.data[0x1c/2]|=SCSP->TimCnt[0]>>8;
+
+ CheckPendingIRQ(SCSP);
+}
+
+static int Get_AR(struct _SCSP *SCSP,int base,int R)
+{
+ int Rate=base+(R<<1);
+ if(Rate>63) Rate=63;
+ if(Rate<0) Rate=0;
+ return SCSP->ARTABLE[Rate];
+}
+
+static int Get_DR(struct _SCSP *SCSP,int base,int R)
+{
+ int Rate=base+(R<<1);
+ if(Rate>63) Rate=63;
+ if(Rate<0) Rate=0;
+ return SCSP->DRTABLE[Rate];
+}
+
+static int Get_RR(struct _SCSP *SCSP,int base,int R)
+{
+ int Rate=base+(R<<1);
+ if(Rate>63) Rate=63;
+ if(Rate<0) Rate=0;
+ return SCSP->ARTABLE[63-Rate];
+}
+
+static void Compute_EG(struct _SCSP *SCSP,struct _SLOT *slot)
+{
+ int octave=OCT(slot);
+ int rate;
+ if(octave&8) octave=octave-16;
+ if(KRS(slot)!=0xf)
+ rate=2*(octave+KRS(slot))+((FNS(slot)>>9)&1);
+ else
+ rate=0; //rate=((FNS(slot)>>9)&1);
+
+ slot->EG.volume=0;
+ slot->EG.AR=Get_AR(SCSP,rate,AR(slot));
+ slot->EG.D1R=Get_DR(SCSP,rate,D1R(slot));
+ slot->EG.D2R=Get_DR(SCSP,rate,D2R(slot));
+ slot->EG.RR=Get_RR(SCSP,rate,RR(slot));
+ slot->EG.DL=0x1f-DL(slot);
+ slot->EG.EGHOLD=EGHOLD(slot);
+}
+
+static void SCSP_StopSlot(struct _SLOT *slot,int keyoff);
+
+static int EG_Update(struct _SLOT *slot)
+{
+ switch(slot->EG.state)
+ {
+ case ATTACK:
+ slot->EG.volume+=slot->EG.AR;
+ if(slot->EG.volume>=(0x3ff<<EG_SHIFT))
+ {
+ if (!LPSLNK(slot))
+ {
+ slot->EG.state=DECAY1;
+ if(slot->EG.D1R>=(1024<<EG_SHIFT)) //Skip DECAY1, go directly to DECAY2
+ slot->EG.state=DECAY2;
+ }
+ slot->EG.volume=0x3ff<<EG_SHIFT;
+ }
+ if(slot->EG.EGHOLD)
+ return 0x3ff<<(SHIFT-10);
+ break;
+ case DECAY1:
+ slot->EG.volume-=slot->EG.D1R;
+ if(slot->EG.volume>>(EG_SHIFT+5)<=slot->EG.DL)
+ slot->EG.state=DECAY2;
+ break;
+ case DECAY2:
+ if(D2R(slot)==0)
+ return (slot->EG.volume>>EG_SHIFT)<<(SHIFT-10);
+ slot->EG.volume-=slot->EG.D2R;
+ if(slot->EG.volume<=0)
+ slot->EG.volume=0;
+
+ break;
+ case RELEASE:
+ slot->EG.volume-=slot->EG.RR;
+ if(slot->EG.volume<=0)
+ {
+ SCSP_StopSlot(slot,0);
+ slot->EG.volume=0;
+ slot->EG.state=ATTACK;
+ }
+ break;
+ default:
+ return 1<<SHIFT;
+ }
+ return (slot->EG.volume>>EG_SHIFT)<<(SHIFT-10);
+}
+
+static UINT32 SCSP_Step(struct _SLOT *slot)
+{
+ int octave=OCT(slot);
+ int Fn;
+
+ Fn=(FNS_Table[FNS(slot)]); //24.8
+ if(octave&8)
+ Fn>>=(16-octave);
+ else
+ Fn<<=octave;
+
+ return Fn/(44100);
+}
+
+
+static void Compute_LFO(struct _SLOT *slot)
+{
+ if(PLFOS(slot)!=0)
+ LFO_ComputeStep(&(slot->PLFO),LFOF(slot),PLFOWS(slot),PLFOS(slot),0);
+ if(ALFOS(slot)!=0)
+ LFO_ComputeStep(&(slot->ALFO),LFOF(slot),ALFOWS(slot),ALFOS(slot),1);
+}
+
+static void SCSP_StartSlot(struct _SCSP *SCSP, struct _SLOT *slot)
+{
+ slot->active=1;
+ slot->base=SCSP->SCSPRAM+SA(slot);
+ slot->cur_addr=0;
+ slot->step=SCSP_Step(slot);
+ Compute_EG(SCSP,slot);
+ slot->EG.state=ATTACK;
+ slot->EG.volume=0;
+ slot->Prev=0;
+ slot->Backwards=0;
+ Compute_LFO(slot);
+
+// printf("StartSlot[%p]: SA %x PCM8B %x LPCTL %x ALFOS %x STWINH %x TL %x EFSDL %x\n", slot, SA(slot), PCM8B(slot), LPCTL(slot), ALFOS(slot), STWINH(slot), TL(slot), EFSDL(slot));
+}
+
+static void SCSP_StopSlot(struct _SLOT *slot,int keyoff)
+{
+ if(keyoff && slot->EG.state!=RELEASE)
+ {
+ slot->EG.state=RELEASE;
+ }
+ else
+ {
+ slot->active=0;
+ }
+
+ slot->udata.data[0]&=~0x800;
+}
+
+#define log_base_2(n) (log((float) n)/log((float) 2))
+
+static void SCSP_Init(struct _SCSP *SCSP, const struct SCSPinterface *intf, int sndindex)
+{
+ int i;
+
+ SCSP->IrqTimA = SCSP->IrqTimBC = SCSP->IrqMidi = 0;
+ SCSP->MidiR=SCSP->MidiW=0;
+ SCSP->MidiOutR=SCSP->MidiOutW=0;
+
+ // get SCSP RAM
+ {
+ memset(SCSP,0,sizeof(*SCSP));
+
+ if (sndindex == 0)
+ {
+ SCSP->Master=1;
+ }
+ else
+ {
+ SCSP->Master=0;
+ }
+
+ if (intf->region)
+ {
+ SCSP->SCSPRAM = memory_region(intf->region);
+ SCSP->SCSPRAM_LENGTH = memory_region_length(intf->region);
+#ifdef USEDSP
+ SCSP->DSP.SCSPRAM = (UINT16 *)SCSP->SCSPRAM;
+ SCSP->DSP.SCSPRAM_LENGTH = memory_region_length(intf->region)/2;
+#endif
+ SCSP->SCSPRAM += intf->roffset;
+ }
+ }
+
+ SCSP->timerA = timer_alloc_ptr(timerA_cb, SCSP);
+ SCSP->timerB = timer_alloc_ptr(timerB_cb, SCSP);
+ SCSP->timerC = timer_alloc_ptr(timerC_cb, SCSP);
+
+ for(i=0;i<0x400;++i)
+ {
+ //float fcent=(double) 1200.0*log_base_2((double)(((double) 1024.0+(double)i)/(double)1024.0));
+ //fcent=(double) 44100.0*pow(2.0,fcent/1200.0);
+ float fcent=44100.0*(1024.0+(double) i)/1024.0;
+ FNS_Table[i]=(float) (1<<SHIFT) *fcent;
+ }
+
+ for(i=0;i<0x10000;++i)
+ {
+ int iTL =(i>>0x0)&0xff;
+ int iPAN=(i>>0x8)&0x1f;
+ int iSDL=(i>>0xD)&0x07;
+ float TL=1.0;
+ float SegaDB=0;
+ float fSDL=1.0;
+ float PAN=1.0;
+ float LPAN,RPAN;
+
+ if(iTL&0x01) SegaDB-=0.4;
+ if(iTL&0x02) SegaDB-=0.8;
+ if(iTL&0x04) SegaDB-=1.5;
+ if(iTL&0x08) SegaDB-=3;
+ if(iTL&0x10) SegaDB-=6;
+ if(iTL&0x20) SegaDB-=12;
+ if(iTL&0x40) SegaDB-=24;
+ if(iTL&0x80) SegaDB-=48;
+
+ TL=pow(10.0,SegaDB/20.0);
+
+ SegaDB=0;
+ if(iPAN&0x1) SegaDB-=3;
+ if(iPAN&0x2) SegaDB-=6;
+ if(iPAN&0x4) SegaDB-=12;
+ if(iPAN&0x8) SegaDB-=24;
+
+ if((iPAN&0xf)==0xf) PAN=0.0;
+ else PAN=pow(10.0,SegaDB/20.0);
+
+ if(iPAN<0x10)
+ {
+ LPAN=PAN;
+ RPAN=1.0;
+ }
+ else
+ {
+ RPAN=PAN;
+ LPAN=1.0;
+ }
+
+ if(iSDL)
+ fSDL=pow(10.0,(SDLT[iSDL])/20.0);
+ else
+ fSDL=0.0;
+
+ SCSP->LPANTABLE[i]=FIX((4.0*LPAN*TL*fSDL));
+ SCSP->RPANTABLE[i]=FIX((4.0*RPAN*TL*fSDL));
+ }
+
+ SCSP->ARTABLE[0]=SCSP->DRTABLE[0]=0; //Infinite time
+ SCSP->ARTABLE[1]=SCSP->DRTABLE[1]=0; //Infinite time
+ for(i=2;i<64;++i)
+ {
+ double t,step,scale;
+ t=ARTimes[i]; //In ms
+ if(t!=0.0)
+ {
+ step=(1023*1000.0)/((float) 44100.0f*t);
+ scale=(double) (1<<EG_SHIFT);
+ SCSP->ARTABLE[i]=(int) (step*scale);
+ }
+ else
+ SCSP->ARTABLE[i]=1024<<EG_SHIFT;
+
+ t=DRTimes[i]; //In ms
+ step=(1023*1000.0)/((float) 44100.0f*t);
+ scale=(double) (1<<EG_SHIFT);
+ SCSP->DRTABLE[i]=(int) (step*scale);
+ }
+
+ // make sure all the slots are off
+ for(i=0;i<32;++i)
+ {
+ SCSP->Slots[i].slot=i;
+ SCSP->Slots[i].active=0;
+ SCSP->Slots[i].active=0;
+ SCSP->Slots[i].base=NULL;
+ }
+
+ LFO_Init();
+ SCSP->buffertmpl=(signed int*) auto_malloc(44100*sizeof(signed int));
+ SCSP->buffertmpr=(signed int*) auto_malloc(44100*sizeof(signed int));
+ memset(SCSP->buffertmpl,0,44100*sizeof(signed int));
+ memset(SCSP->buffertmpr,0,44100*sizeof(signed int));
+
+ // no "pend"
+ SCSP[0].udata.data[0x20/2] = 0;
+ //SCSP[1].udata.data[0x20/2] = 0;
+ SCSP->TimCnt[0] = 0xffff;
+ SCSP->TimCnt[1] = 0xffff;
+ SCSP->TimCnt[2] = 0xffff;
+}
+
+static void SCSP_UpdateSlotReg(struct _SCSP *SCSP,int s,int r)
+{
+ struct _SLOT *slot=SCSP->Slots+s;
+ int sl;
+ switch(r&0x3f)
+ {
+ case 0:
+ case 1:
+ if(KEYONEX(slot))
+ {
+ for(sl=0;sl<32;++sl)
+ {
+ struct _SLOT *s2=SCSP->Slots+sl;
+ {
+ if(KEYONB(s2) && !s2->active)
+ {
+ SCSP_StartSlot(SCSP, s2);
+ }
+ if(!KEYONB(s2) && s2->active)
+ {
+ SCSP_StopSlot(s2,1);
+ }
+ }
+ }
+ slot->udata.data[0]&=~0x1000;
+ }
+ break;
+ case 0x10:
+ case 0x11:
+ slot->step=SCSP_Step(slot);
+ break;
+ case 0xA:
+ case 0xB:
+ slot->EG.RR=Get_RR(SCSP,0,RR(slot));
+ slot->EG.DL=0x1f-DL(slot);
+ break;
+ case 0x12:
+ case 0x13:
+ Compute_LFO(slot);
+ break;
+ }
+}
+
+static void SCSP_UpdateReg(struct _SCSP *SCSP, int reg)
+{
+ switch(reg&0x3f)
+ {
+ case 0x2:
+ case 0x3:
+ {
+#ifdef USEDSP
+ unsigned int v=RBL(SCSP);
+ SCSP->DSP.RBP=RBP(SCSP);
+ if(v==0)
+ SCSP->DSP.RBL=8*1024;
+ else if(v==1)
+ SCSP->DSP.RBL=16*1024;
+ if(v==2)
+ SCSP->DSP.RBL=32*1024;
+ if(v==3)
+ SCSP->DSP.RBL=64*1024;
+#endif
+ }
+ break;
+ case 0x6:
+ case 0x7:
+ SCSP_MidiIn(0, SCSP->udata.data[0x6/2]&0xff, 0);
+ break;
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ break;
+ case 0x18:
+ case 0x19:
+ if(SCSP->Master)
+ {
+ UINT32 time;
+
+ SCSP->TimPris[0]=1<<((SCSP->udata.data[0x18/2]>>8)&0x7);
+ SCSP->TimCnt[0]=(SCSP->udata.data[0x18/2]&0xff)<<8;
+
+ if ((SCSP->udata.data[0x18/2]&0xff) != 255)
+ {
+ time = (44100 / SCSP->TimPris[0]) / (255-(SCSP->udata.data[0x18/2]&0xff));
+ if (time)
+ {
+ timer_adjust_ptr(SCSP->timerA, ATTOTIME_IN_HZ(time), attotime_never);
+ }
+ }
+ }
+ break;
+ case 0x1a:
+ case 0x1b:
+ if(SCSP->Master)
+ {
+ UINT32 time;
+
+ SCSP->TimPris[1]=1<<((SCSP->udata.data[0x1A/2]>>8)&0x7);
+ SCSP->TimCnt[1]=(SCSP->udata.data[0x1A/2]&0xff)<<8;
+
+ if ((SCSP->udata.data[0x1A/2]&0xff) != 255)
+ {
+ time = (44100 / SCSP->TimPris[1]) / (255-(SCSP->udata.data[0x1A/2]&0xff));
+ if (time)
+ {
+ timer_adjust_ptr(SCSP->timerB, ATTOTIME_IN_HZ(time), attotime_never);
+ }
+ }
+ }
+ break;
+ case 0x1C:
+ case 0x1D:
+ if(SCSP->Master)
+ {
+ UINT32 time;
+
+ SCSP->TimPris[2]=1<<((SCSP->udata.data[0x1C/2]>>8)&0x7);
+ SCSP->TimCnt[2]=(SCSP->udata.data[0x1C/2]&0xff)<<8;
+
+ if ((SCSP->udata.data[0x1C/2]&0xff) != 255)
+ {
+ time = (44100 / SCSP->TimPris[2]) / (255-(SCSP->udata.data[0x1C/2]&0xff));
+ if (time)
+ {
+ timer_adjust_ptr(SCSP->timerC, ATTOTIME_IN_HZ(time), attotime_never);
+ }
+ }
+ }
+ break;
+ case 0x22: //SCIRE
+ case 0x23:
+
+ if(SCSP->Master)
+ {
+ SCSP->udata.data[0x20/2]&=~SCSP->udata.data[0x22/2];
+ ResetInterrupts(SCSP);
+
+ // behavior from real hardware: if you SCIRE a timer that's expired,
+ // it'll immediately pop up again in SCIPD. ask Sakura Taisen on the Saturn...
+ if (SCSP->TimCnt[0] == 0xffff)
+ {
+ SCSP->udata.data[0x20/2] |= 0x40;
+ }
+ if (SCSP->TimCnt[1] == 0xffff)
+ {
+ SCSP->udata.data[0x20/2] |= 0x80;
+ }
+ if (SCSP->TimCnt[2] == 0xffff)
+ {
+ SCSP->udata.data[0x20/2] |= 0x100;
+ }
+ }
+ break;
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ if(SCSP->Master)
+ {
+ SCSP->IrqTimA=DecodeSCI(SCSP,SCITMA);
+ SCSP->IrqTimBC=DecodeSCI(SCSP,SCITMB);
+ SCSP->IrqMidi=DecodeSCI(SCSP,SCIMID);
+ }
+ break;
+ }
+}
+
+static void SCSP_UpdateSlotRegR(struct _SCSP *SCSP, int slot,int reg)
+{
+
+}
+
+static void SCSP_UpdateRegR(struct _SCSP *SCSP, int reg)
+{
+ switch(reg&0x3f)
+ {
+ case 4:
+ case 5:
+ {
+ unsigned short v=SCSP->udata.data[0x5/2];
+ v&=0xff00;
+ v|=SCSP->MidiStack[SCSP->MidiR];
+ SCSP[0].Int68kCB(-SCSP->IrqMidi); // cancel the IRQ
+ if(SCSP->MidiR!=SCSP->MidiW)
+ {
+ ++SCSP->MidiR;
+ SCSP->MidiR&=31;
+ }
+ SCSP->udata.data[0x5/2]=v;
+ }
+ break;
+ case 8:
+ case 9:
+ {
+ unsigned char slot=SCSP->udata.data[0x8/2]>>11;
+ unsigned int CA=SCSP->Slots[slot&0x1f].cur_addr>>(SHIFT+12);
+ SCSP->udata.data[0x8/2]&=~(0x780);
+ SCSP->udata.data[0x8/2]|=CA<<7;
+ }
+ break;
+
+ case 0x18:
+ case 0x19:
+ break;
+
+ case 0x1a:
+ case 0x1b:
+ break;
+
+ case 0x1c:
+ case 0x1d:
+ break;
+ }
+}
+
+static void SCSP_w16(struct _SCSP *SCSP,unsigned int addr,unsigned short val)
+{
+ addr&=0xffff;
+ if(addr<0x400)
+ {
+ int slot=addr/0x20;
+ addr&=0x1f;
+ *((unsigned short *) (SCSP->Slots[slot].udata.datab+(addr))) = val;
+ SCSP_UpdateSlotReg(SCSP,slot,addr&0x1f);
+ }
+ else if(addr<0x600)
+ {
+ if (addr < 0x430)
+ {
+ *((unsigned short *) (SCSP->udata.datab+((addr&0x3f)))) = val;
+ SCSP_UpdateReg(SCSP, addr&0x3f);
+ }
+ }
+ else if(addr<0x700)
+ SCSP->RINGBUF[(addr-0x600)/2]=val;
+ else
+ {
+#ifdef USEDSP
+ //DSP
+ if(addr<0x780) //COEF
+ *((unsigned short *) (SCSP->DSP.COEF+(addr-0x700)/2))=val;
+ else if(addr<0x800)
+ *((unsigned short *) (SCSP->DSP.MADRS+(addr-0x780)/2))=val;
+ else if(addr<0xC00)
+ *((unsigned short *) (SCSP->DSP.MPRO+(addr-0x800)/2))=val;
+
+ if(addr==0xBF0)
+ {
+ SCSPDSP_Start(&SCSP->DSP);
+ }
+#endif
+ }
+}
+
+static unsigned short SCSP_r16(struct _SCSP *SCSP, unsigned int addr)
+{
+ unsigned short v=0;
+ addr&=0xffff;
+ if(addr<0x400)
+ {
+ int slot=addr/0x20;
+ addr&=0x1f;
+ SCSP_UpdateSlotRegR(SCSP, slot,addr&0x1f);
+ v=*((unsigned short *) (SCSP->Slots[slot].udata.datab+(addr)));
+ }
+ else if(addr<0x600)
+ {
+ if (addr < 0x430)
+ {
+ SCSP_UpdateRegR(SCSP, addr&0x3f);
+ v= *((unsigned short *) (SCSP->udata.datab+((addr&0x3f))));
+ }
+ }
+ else if(addr<0x700)
+ v=SCSP->RINGBUF[(addr-0x600)/2];
+ return v;
+}
+
+
+#define REVSIGN(v) ((~v)+1)
+
+
+#ifndef USEDSP
+static signed int *bufl1,*bufr1;
+#define SCSPNAME(_8bit,lfo,alfo,loop) \
+static void SCSP_Update##_8bit##lfo##alfo##loop(struct _SCSP *SCSP, struct _SLOT *slot,unsigned int Enc,unsigned int nsamples)
+
+#define SCSPTMPL(_8bit,lfo,alfo,loop) \
+SCSPNAME(_8bit,lfo,alfo,loop)\
+{\
+ signed int sample;\
+ UINT32 addr;\
+ unsigned int s;\
+ for(s=0;s<nsamples;++s)\
+ {\
+ int step=slot->step;\
+ if(!slot->active)\
+ return;\
+ if(lfo) \
+ {\
+ step=step*PLFO_Step(&(slot->PLFO));\
+ step>>=SHIFT; \
+ }\
+ if(_8bit)\
+ {\
+ signed char *p=(signed char *) (slot->base+BYTE_XOR_BE((slot->cur_addr>>SHIFT)));\
+ int s;\
+ signed int fpart=slot->cur_addr&((1<<SHIFT)-1);\
+ s=(int) (p[0]<<8)*((1<<SHIFT)-fpart)+(int) slot->Prev*fpart;\
+ sample=(s>>SHIFT);\
+ slot->Prev=p[0]<<8;\
+ }\
+ else\
+ {\
+ signed short *p=(signed short *) (slot->base+((slot->cur_addr>>(SHIFT-1))&(~1)));\
+ int s;\
+ signed int fpart=slot->cur_addr&((1<<SHIFT)-1);\
+ s=(int) (p[0])*((1<<SHIFT)-fpart)+(int) slot->Prev*fpart;\
+ sample=(s>>SHIFT);\
+ slot->Prev=p[0];\
+ }\
+ if(slot->Backwards)\
+ slot->cur_addr-=step;\
+ else\
+ slot->cur_addr+=step;\
+ addr=slot->cur_addr>>SHIFT;\
+ if(loop==0)\
+ {\
+ if(addr>LEA(slot))\
+ {\
+ SCSP_StopSlot(slot,0);\
+ }\
+ }\
+ if(loop==1)\
+ {\
+ if(addr>=LEA(slot))\
+ slot->cur_addr=LSA(slot)<<SHIFT;\
+ }\
+ if(loop==2)\
+ {\
+ if(addr>=LEA(slot))\
+ {\
+ slot->cur_addr=LEA(slot)<<SHIFT;\
+ slot->step=REVSIGN(slot->step);\
+ }\
+ if(addr<LSA(slot) || (addr&0x80000000))\
+ slot->cur_addr=LEA(slot)<<SHIFT;\
+ }\
+ if(loop==3)\
+ {\
+ if(addr>=LEA(slot)) /*reached end, reverse till start*/ \
+ {\
+ slot->cur_addr=LEA(slot)<<SHIFT;\
+ slot->Backwards=1;\
+ }\
+ if((addr<=LSA(slot) || (addr&0x80000000)) && (slot->Backwards))/*reached start or negative*/\
+ {\
+ slot->cur_addr=LSA(slot)<<SHIFT;\
+ slot->Backwards=0;\
+ }\
+ }\
+ if(alfo)\
+ {\
+ sample=sample*ALFO_Step(&(slot->ALFO));\
+ sample>>=SHIFT;\
+ }\
+ *RBUFDST=sample;\
+ \
+ sample=(sample*EG_Update(slot))>>SHIFT;\
+ \
+ *bufl1=*bufl1 + ((sample*SCSP->LPANTABLE[Enc])>>SHIFT);\
+ *bufr1=*bufr1 + ((sample*SCSP->RPANTABLE[Enc])>>SHIFT);\
+ ++bufl1;\
+ ++bufr1;\
+ }\
+}
+
+SCSPTMPL(0,0,0,0)
+SCSPTMPL(0,0,0,1)
+SCSPTMPL(0,0,0,2)
+SCSPTMPL(0,0,0,3)
+SCSPTMPL(0,0,1,0)
+SCSPTMPL(0,0,1,1)
+SCSPTMPL(0,0,1,2)
+SCSPTMPL(0,0,1,3)
+SCSPTMPL(0,1,0,0)
+SCSPTMPL(0,1,0,1)
+SCSPTMPL(0,1,0,2)
+SCSPTMPL(0,1,0,3)
+SCSPTMPL(0,1,1,0)
+SCSPTMPL(0,1,1,1)
+SCSPTMPL(0,1,1,2)
+SCSPTMPL(0,1,1,3)
+SCSPTMPL(1,0,0,0)
+SCSPTMPL(1,0,0,1)
+SCSPTMPL(1,0,0,2)
+SCSPTMPL(1,0,0,3)
+SCSPTMPL(1,0,1,0)
+SCSPTMPL(1,0,1,1)
+SCSPTMPL(1,0,1,2)
+SCSPTMPL(1,0,1,3)
+SCSPTMPL(1,1,0,0)
+SCSPTMPL(1,1,0,1)
+SCSPTMPL(1,1,0,2)
+SCSPTMPL(1,1,0,3)
+SCSPTMPL(1,1,1,0)
+SCSPTMPL(1,1,1,1)
+SCSPTMPL(1,1,1,2)
+SCSPTMPL(1,1,1,3)
+
+#undef SCSPTMPL
+#define SCSPTMPL(_8bit,lfo,alfo,loop) \
+ SCSP_Update##_8bit##lfo##alfo##loop ,
+
+
+typedef void (*_SCSPUpdateModes)(struct _SCSP *,struct _SLOT *,unsigned int,unsigned int);
+
+static _SCSPUpdateModes SCSPUpdateModes[]=
+{
+ SCSPTMPL(0,0,0,0)
+ SCSPTMPL(0,0,0,1)
+ SCSPTMPL(0,0,0,2)
+ SCSPTMPL(0,0,0,3)
+ SCSPTMPL(0,0,1,0)
+ SCSPTMPL(0,0,1,1)
+ SCSPTMPL(0,0,1,2)
+ SCSPTMPL(0,0,1,3)
+ SCSPTMPL(0,1,0,0)
+ SCSPTMPL(0,1,0,1)
+ SCSPTMPL(0,1,0,2)
+ SCSPTMPL(0,1,0,3)
+ SCSPTMPL(0,1,1,0)
+ SCSPTMPL(0,1,1,1)
+ SCSPTMPL(0,1,1,2)
+ SCSPTMPL(0,1,1,3)
+ SCSPTMPL(1,0,0,0)
+ SCSPTMPL(1,0,0,1)
+ SCSPTMPL(1,0,0,2)
+ SCSPTMPL(1,0,0,3)
+ SCSPTMPL(1,0,1,0)
+ SCSPTMPL(1,0,1,1)
+ SCSPTMPL(1,0,1,2)
+ SCSPTMPL(1,0,1,3)
+ SCSPTMPL(1,1,0,0)
+ SCSPTMPL(1,1,0,1)
+ SCSPTMPL(1,1,0,2)
+ SCSPTMPL(1,1,0,3)
+ SCSPTMPL(1,1,1,0)
+ SCSPTMPL(1,1,1,1)
+ SCSPTMPL(1,1,1,2)
+ SCSPTMPL(1,1,1,3)
+};
+
+
+static void SCSP_DoMasterSamples(struct _SCSP *SCSP, int nsamples)
+{
+ stream_sample_t *bufr,*bufl;
+ int sl, s;
+
+ for(sl=0;sl<32;++sl)
+ {
+ bufr1=SCSP->buffertmpr;
+ bufl1=SCSP->buffertmpl;
+
+ if(SCSP->Slots[sl].active)
+ {
+ struct _SLOT *slot=SCSP->Slots+sl;
+ unsigned short Enc=((TL(slot))<<0x0)|((DIPAN(slot))<<0x8)|((DISDL(slot))<<0xd);
+ unsigned int mode=LPCTL(slot);
+
+ RBUFDST=SCSP->RINGBUF+SCSP->BUFPTR;
+ if(PLFOS(slot))
+ mode|=8;
+ if(ALFOS(slot))
+ mode|=4;
+ if(PCM8B(slot))
+ mode|=0x10;
+
+ SCSPUpdateModes[mode](SCSP,slot,Enc,nsamples);
+
+ ++SCSP->BUFPTR;
+ SCSP->BUFPTR&=63;
+ }
+ }
+
+ bufr=bufferr;
+ bufl=bufferl;
+ bufr1=SCSP->buffertmpr;
+ bufl1=SCSP->buffertmpl;
+ for(s=0;s<nsamples;++s)
+ {
+ signed int smpl=*bufl1>>2;
+ signed int smpr=*bufr1>>2;
+
+ *bufl=ICLIP16(smpl);
+ *bufr=ICLIP16(smpr);
+ *bufl1=0;
+ *bufr1=0;
+ ++bufl;
+ ++bufr;
+ ++bufl1;
+ ++bufr1;
+
+ }
+}
+#else
+INLINE INT32 SCSP_UpdateSlot(struct _SCSP *SCSP, struct _SLOT *slot)
+{
+ INT32 sample;
+ int step=slot->step;
+ UINT32 addr;
+
+ if(SSCTL(slot)!=0) //no FM or noise yet
+ return 0;
+
+ if(PLFOS(slot)!=0)
+ {
+ step=step*PLFO_Step(&(slot->PLFO));
+ step>>=SHIFT;
+ }
+
+ if(PCM8B(slot))
+ addr=slot->cur_addr>>SHIFT;
+ else
+ addr=(slot->cur_addr>>(SHIFT-1)) & 0x7fffe;
+/*
+ if(MDL(slot)!=0 || MDXSL(slot)!=0 || MDYSL(slot)!=0)
+ {
+ INT32 smp;
+ smp=(SCSP->RINGBUF[(SCSP->BUFPTR+MDXSL(slot))&63]+SCSP->RINGBUF[(SCSP->BUFPTR+MDYSL(slot))&63])/2;
+
+ smp>>=11;
+ addr+=smp;
+ if(!PCM8B(slot))
+ addr&=0x7fffe;
+ else
+ addr&=0x7ffff;
+ }
+*/
+ if(addr==LSA(slot))
+ {
+ if(LPSLNK(slot) && slot->EG.state==ATTACK)
+ slot->EG.state = DECAY1;
+ }
+
+ if(PCM8B(slot)) //8 bit signed
+ {
+ INT8 *p=(INT8 *) (slot->base+BYTE_XOR_BE((slot->cur_addr>>SHIFT)));
+ INT32 s;
+ INT32 fpart=slot->cur_addr&((1<<SHIFT)-1);
+ s=(int) (p[0]<<8)*((1<<SHIFT)-fpart)+(int) slot->Prev*fpart;
+ sample=(s>>SHIFT);
+ slot->Prev=p[0]<<8;
+
+ }
+ else //16 bit signed
+ {
+ INT16 *p=(INT16 *) (slot->base+addr);
+ INT32 s;
+ INT32 fpart=slot->cur_addr&((1<<SHIFT)-1);
+ s=(int) (p[0])*((1<<SHIFT)-fpart)+(int) slot->Prev*fpart;
+ sample=(s>>SHIFT);
+ slot->Prev=p[0];
+
+ }
+
+ if(SBCTL(slot)&0x1)
+ sample ^= 0x7FFF;
+ if(SBCTL(slot)&0x2)
+ sample = (INT16)(sample^0x8000);
+
+ if(slot->Backwards)
+ slot->cur_addr-=step;
+ else
+ slot->cur_addr+=step;
+ addr=slot->cur_addr>>SHIFT;
+ switch(LPCTL(slot))
+ {
+ case 0: //no loop
+ if(addr>LEA(slot))
+ {
+ //slot->active=0;
+ SCSP_StopSlot(slot,0);
+ }
+ break;
+ case 1: //normal loop
+ if(addr>LEA(slot))
+ slot->cur_addr=LSA(slot)<<SHIFT;
+ break;
+ case 2: //reverse loop
+ if(addr>LEA(slot))
+ {
+ slot->cur_addr=LEA(slot)<<SHIFT;
+ slot->Backwards=1;
+ }
+ if(addr<LSA(slot) || (addr&0x80000000))
+ slot->cur_addr=LEA(slot)<<SHIFT;
+ break;
+ case 3: //ping-pong
+ if(addr>LEA(slot)) //reached end, reverse till start
+ {
+ slot->cur_addr=LEA(slot)<<SHIFT;
+ slot->Backwards=1;
+ }
+ if((addr<LSA(slot) || (addr&0x80000000)) && (slot->Backwards))//reached start or negative
+ {
+ slot->cur_addr=LSA(slot)<<SHIFT;
+ slot->Backwards=0;
+ }
+ break;
+ }
+
+ if(ALFOS(slot)!=0)
+ {
+ sample=sample*ALFO_Step(&(slot->ALFO));
+ sample>>=SHIFT;
+ }
+
+ if(!STWINH(slot))
+ *RBUFDST=sample;
+
+ sample=(sample*EG_Update(slot))>>SHIFT;
+
+ return sample;
+}
+
+static void SCSP_DoMasterSamples(struct _SCSP *SCSP, int nsamples)
+{
+ stream_sample_t *bufr,*bufl;
+ int sl, s, i;
+
+ bufr=bufferr;
+ bufl=bufferl;
+
+ for(s=0;s<nsamples;++s)
+ {
+ INT32 smpl, smpr;
+
+ smpl = smpr = 0;
+
+ for(sl=0;sl<32;++sl)
+ {
+ if(SCSP->Slots[sl].active)
+ {
+ struct _SLOT *slot=SCSP->Slots+sl;
+ unsigned short Enc;
+ signed int sample;
+
+ RBUFDST=SCSP->RINGBUF+SCSP->BUFPTR;
+ sample=SCSP_UpdateSlot(SCSP, slot);
+ ++SCSP->BUFPTR;
+ SCSP->BUFPTR&=63;
+#ifdef USEDSP
+ SCSPDSP_SetSample(&SCSP->DSP,sample>>SHIFT,ISEL(slot),IMXL(slot));
+#endif
+ Enc=((TL(slot))<<0x0)|((DIPAN(slot))<<0x8)|((DISDL(slot))<<0xd);
+ {
+ smpl+=(sample*SCSP->LPANTABLE[Enc])>>SHIFT;
+ smpr+=(sample*SCSP->RPANTABLE[Enc])>>SHIFT;
+ }
+ }
+
+ }
+
+ SCSPDSP_Step(&SCSP->DSP);
+
+ for(i=0;i<16;++i)
+ {
+ struct _SLOT *slot=SCSP->Slots+i;
+ if(EFSDL(slot))
+ {
+ unsigned short Enc=(TL(slot))|((EFPAN(slot))<<0x8)|((EFSDL(slot))<<0xd);
+ smpl+=(SCSP->DSP.EFREG[i]*SCSP->LPANTABLE[Enc])>>(SHIFT-5);
+ smpr+=(SCSP->DSP.EFREG[i]*SCSP->RPANTABLE[Enc])>>(SHIFT-5);
+ }
+ }
+
+ *bufl++ = ICLIP16(smpl>>4);
+ *bufr++ = ICLIP16(smpr>>4);
+ }
+}
+#endif
+
+static void dma_scsp(struct _SCSP *SCSP)
+{
+ static UINT16 tmp_dma[3], *scsp_regs;
+
+ scsp_regs = (UINT16 *)SCSP->udata.datab;
+
+ logerror("SCSP: DMA transfer START\n"
+ "DMEA: %04x DRGA: %04x DTLG: %04x\n"
+ "DGATE: %d DDIR: %d\n",SCSP->scsp_dmea,SCSP->scsp_drga,SCSP->scsp_dtlg,scsp_dgate ? 1 : 0,scsp_ddir ? 1 : 0);
+
+ /* Copy the dma values in a temp storage for resuming later */
+ /* (DMA *can't* overwrite his parameters). */
+ if(!(scsp_ddir))
+ {
+ tmp_dma[0] = scsp_regs[0x12/2];
+ tmp_dma[1] = scsp_regs[0x14/2];
+ tmp_dma[2] = scsp_regs[0x16/2];
+ }
+
+ if(scsp_ddir)
+ {
+ for(;SCSP->scsp_dtlg > 0;SCSP->scsp_dtlg-=2)
+ {
+ program_write_word(SCSP->scsp_dmea, program_read_word(0x100000|SCSP->scsp_drga));
+ SCSP->scsp_dmea+=2;
+ SCSP->scsp_drga+=2;
+ }
+ }
+ else
+ {
+ for(;SCSP->scsp_dtlg > 0;SCSP->scsp_dtlg-=2)
+ {
+ program_write_word(0x100000|SCSP->scsp_drga,program_read_word(SCSP->scsp_dmea));
+ SCSP->scsp_dmea+=2;
+ SCSP->scsp_drga+=2;
+ }
+ }
+
+ /*Resume the values*/
+ if(!(scsp_ddir))
+ {
+ scsp_regs[0x12/2] = tmp_dma[0];
+ scsp_regs[0x14/2] = tmp_dma[1];
+ scsp_regs[0x16/2] = tmp_dma[2];
+ }
+
+ /*Job done,request a dma end irq*/
+ if(scsp_regs[0x1e/2] & 0x10)
+ cpunum_set_input_line(2,dma_transfer_end,HOLD_LINE);
+}
+
+int SCSP_IRQCB(void *param)
+{
+ CheckPendingIRQ(param);
+ return -1;
+}
+
+static void SCSP_Update(void *param, stream_sample_t **inputs, stream_sample_t **buf, int samples)
+{
+ struct _SCSP *SCSP = param;
+ bufferl = buf[0];
+ bufferr = buf[1];
+ length = samples;
+ SCSP_DoMasterSamples(SCSP, samples);
+}
+
+static void *scsp_start(int sndindex, int clock, const void *config)
+{
+ const struct SCSPinterface *intf;
+
+ struct _SCSP *SCSP;
+
+ SCSP = auto_malloc(sizeof(*SCSP));
+ memset(SCSP, 0, sizeof(*SCSP));
+
+ intf = config;
+
+ // init the emulation
+ SCSP_Init(SCSP, intf, sndindex);
+
+ // set up the IRQ callbacks
+ {
+ SCSP->Int68kCB = intf->irq_callback;
+
+ SCSP->stream = stream_create(0, 2, 44100, SCSP, SCSP_Update);
+ }
+
+ return SCSP;
+}
+
+
+void SCSP_set_ram_base(int which, void *base)
+{
+ struct _SCSP *SCSP = sndti_token(SOUND_SCSP, which);
+ if (SCSP)
+ {
+ SCSP->SCSPRAM = base;
+#ifdef USEDSP
+ SCSP->DSP.SCSPRAM = base;
+#endif
+ }
+}
+
+
+READ16_HANDLER( SCSP_0_r )
+{
+ struct _SCSP *SCSP = sndti_token(SOUND_SCSP, 0);
+
+ stream_update(SCSP->stream);
+
+ return SCSP_r16(SCSP, offset*2);
+}
+
+UINT32* stv_scu;
+
+WRITE16_HANDLER( SCSP_0_w )
+{
+ struct _SCSP *SCSP = sndti_token(SOUND_SCSP, 0);
+ UINT16 tmp, *scsp_regs;
+
+ stream_update(SCSP->stream);
+
+ tmp = SCSP_r16(SCSP, offset*2);
+ COMBINE_DATA(&tmp);
+ SCSP_w16(SCSP,offset*2, tmp);
+
+ scsp_regs = (UINT16 *)SCSP->udata.datab;
+
+ switch(offset*2)
+ {
+ // check DMA
+ case 0x412:
+ /*DMEA [15:1]*/
+ /*Sound memory address*/
+ SCSP->scsp_dmea = (((scsp_regs[0x414/2] & 0xf000)>>12)*0x10000) | (scsp_regs[0x412/2] & 0xfffe);
+ break;
+ case 0x414:
+ /*DMEA [19:16]*/
+ SCSP->scsp_dmea = (((scsp_regs[0x414/2] & 0xf000)>>12)*0x10000) | (scsp_regs[0x412/2] & 0xfffe);
+ /*DRGA [11:1]*/
+ /*Register memory address*/
+ SCSP->scsp_drga = scsp_regs[0x414/2] & 0x0ffe;
+ break;
+ case 0x416:
+ /*DGATE[14]*/
+ /*DDIR[13]*/
+ /*if 0 sound_mem -> reg*/
+ /*if 1 sound_mem <- reg*/
+ /*DEXE[12]*/
+ /*starting bit*/
+ /*DTLG[11:1]*/
+ /*size of transfer*/
+ SCSP->scsp_dtlg = scsp_regs[0x416/2] & 0x0ffe;
+ if(scsp_dexe)
+ {
+ dma_scsp(SCSP);
+ scsp_regs[0x416/2]^=0x1000;//disable starting bit
+ }
+ break;
+ //check main cpu IRQ
+ case 0x42a:
+ if(stv_scu && !(stv_scu[40] & 0x40) /*&& scsp_regs[0x42c/2] & 0x20*/)/*Main CPU allow sound irq*/
+ {
+ cpunum_set_input_line_and_vector(0, 9, HOLD_LINE , 0x46);
+ logerror("SCSP: Main CPU interrupt\n");
+ }
+ break;
+ case 0x42c:
+ break;
+ case 0x42e:
+ break;
+ }
+}
+
+READ16_HANDLER( SCSP_1_r )
+{
+ struct _SCSP *SCSP = sndti_token(SOUND_SCSP, 1);
+ return SCSP_r16(SCSP, offset*2);
+}
+
+WRITE16_HANDLER( SCSP_1_w )
+{
+ struct _SCSP *SCSP = sndti_token(SOUND_SCSP, 1);
+ unsigned short tmp;
+
+ tmp = SCSP_r16(SCSP, offset*2);
+ COMBINE_DATA(&tmp);
+ SCSP_w16(SCSP, offset*2, tmp);
+}
+
+WRITE16_HANDLER( SCSP_MidiIn )
+{
+ struct _SCSP *SCSP = sndti_token(SOUND_SCSP, 0);
+
+ SCSP->MidiStack[SCSP->MidiW++]=data;
+ SCSP->MidiW &= 31;
+
+ CheckPendingIRQ(SCSP);
+}
+
+READ16_HANDLER( SCSP_MidiOutR )
+{
+ struct _SCSP *SCSP = sndti_token(SOUND_SCSP, 0);
+ unsigned char val;
+
+ val=SCSP->MidiStack[SCSP->MidiR++];
+ SCSP->MidiR&=31;
+ return val;
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void scsp_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void scsp_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = scsp_set_info; break;
+ case SNDINFO_PTR_START: info->start = scsp_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "SCSP"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Sega/Yamaha custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "2.1.1"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004-2007, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/scsp.h b/src/emu/sound/scsp.h
new file mode 100644
index 00000000000..c53ca5df369
--- /dev/null
+++ b/src/emu/sound/scsp.h
@@ -0,0 +1,28 @@
+/*
+
+ SCSP (YMF292-F) header
+*/
+
+#ifndef _SCSP_H_
+#define _SCSP_H_
+
+struct SCSPinterface
+{
+ int region; /* region of 512k RAM */
+ int roffset; /* offset in the region */
+ void (*irq_callback)(int state); /* irq callback */
+};
+
+void SCSP_set_ram_base(int which, void *base);
+
+// SCSP register access
+READ16_HANDLER( SCSP_0_r );
+WRITE16_HANDLER( SCSP_0_w );
+READ16_HANDLER( SCSP_1_r );
+WRITE16_HANDLER( SCSP_1_w );
+
+// MIDI I/O access (used for comms on Model 2/3)
+WRITE16_HANDLER( SCSP_MidiIn );
+READ16_HANDLER( SCSP_MidiOutR );
+
+#endif
diff --git a/src/emu/sound/scspdsp.c b/src/emu/sound/scspdsp.c
new file mode 100644
index 00000000000..9a417c47443
--- /dev/null
+++ b/src/emu/sound/scspdsp.c
@@ -0,0 +1,319 @@
+#include <math.h>
+#include "sndintrf.h"
+#include "cpuintrf.h"
+#include "scsp.h"
+#include "scspdsp.h"
+
+static UINT16 PACK(INT32 val)
+{
+ //cut to 16 bits
+ INT32 f=((UINT32 ) val)>>8;
+ return f;
+}
+
+static INT32 UNPACK(UINT16 val)
+{
+ INT32 r=val<<8;
+ r<<=8;
+ r>>=8;
+ //if(r&0x00800000)
+ // r|=0xFF000000;
+ return r;
+}
+
+void SCSPDSP_Init(struct _SCSPDSP *DSP)
+{
+ memset(DSP,0,sizeof(struct _SCSPDSP));
+ DSP->RBL=0x8000;
+ DSP->Stopped=1;
+}
+
+void SCSPDSP_Step(struct _SCSPDSP *DSP)
+{
+ INT32 ACC=0; //26 bit
+ INT32 SHIFTED=0; //24 bit
+ INT32 X=0; //24 bit
+ INT32 Y=0; //13 bit
+ INT32 B=0; //26 bit
+ INT32 INPUTS=0; //24 bit
+ INT32 MEMVAL=0;
+ INT32 FRC_REG=0; //13 bit
+ INT32 Y_REG=0; //24 bit
+ UINT32 ADDR=0;
+ UINT32 ADRS_REG=0; //13 bit
+ int step;
+
+ if(DSP->Stopped)
+ return;
+
+ memset(DSP->EFREG,0,2*16);
+#if 0
+ int dump=0;
+ FILE *f=NULL;
+ if(dump)
+ f=fopen("dsp.txt","wt");
+#endif
+ for(step=0;step</*128*/DSP->LastStep;++step)
+ {
+ UINT16 *IPtr=DSP->MPRO+step*4;
+
+// if(IPtr[0]==0 && IPtr[1]==0 && IPtr[2]==0 && IPtr[3]==0)
+// break;
+
+ UINT32 TRA=(IPtr[0]>>8)&0x7F;
+ UINT32 TWT=(IPtr[0]>>7)&0x01;
+ UINT32 TWA=(IPtr[0]>>0)&0x7F;
+
+ UINT32 XSEL=(IPtr[1]>>15)&0x01;
+ UINT32 YSEL=(IPtr[1]>>13)&0x03;
+ UINT32 IRA=(IPtr[1]>>6)&0x3F;
+ UINT32 IWT=(IPtr[1]>>5)&0x01;
+ UINT32 IWA=(IPtr[1]>>0)&0x1F;
+
+ UINT32 TABLE=(IPtr[2]>>15)&0x01;
+ UINT32 MWT=(IPtr[2]>>14)&0x01;
+ UINT32 MRD=(IPtr[2]>>13)&0x01;
+ UINT32 EWT=(IPtr[2]>>12)&0x01;
+ UINT32 EWA=(IPtr[2]>>8)&0x0F;
+ UINT32 ADRL=(IPtr[2]>>7)&0x01;
+ UINT32 FRCL=(IPtr[2]>>6)&0x01;
+ UINT32 SHIFT=(IPtr[2]>>4)&0x03;
+ UINT32 YRL=(IPtr[2]>>3)&0x01;
+ UINT32 NEGB=(IPtr[2]>>2)&0x01;
+ UINT32 ZERO=(IPtr[2]>>1)&0x01;
+ UINT32 BSEL=(IPtr[2]>>0)&0x01;
+
+ UINT32 NOFL=(IPtr[3]>>15)&1; //????
+ UINT32 COEF=(IPtr[3]>>9)&0x3f;
+
+ UINT32 MASA=(IPtr[3]>>2)&0x1f; //???
+ UINT32 ADREB=(IPtr[3]>>1)&0x1;
+ UINT32 NXADR=(IPtr[3]>>0)&0x1;
+
+ INT64 v;
+
+ //operations are done at 24 bit precision
+#if 0
+ if(MASA)
+ int a=1;
+ if(NOFL)
+ int a=1;
+
+// int dump=0;
+
+ if(f)
+ {
+#define DUMP(v) fprintf(f," " #v ": %04X",v);
+
+ fprintf(f,"%d: ",step);
+ DUMP(ACC);
+ DUMP(SHIFTED);
+ DUMP(X);
+ DUMP(Y);
+ DUMP(B);
+ DUMP(INPUTS);
+ DUMP(MEMVAL);
+ DUMP(FRC_REG);
+ DUMP(Y_REG);
+ DUMP(ADDR);
+ DUMP(ADRS_REG);
+ fprintf(f,"\n");
+ }
+#endif
+ //INPUTS RW
+ assert(IRA<0x32);
+ if(IRA<=0x1f)
+ INPUTS=DSP->MEMS[IRA];
+ else if(IRA<=0x2F)
+ INPUTS=DSP->MIXS[IRA-0x20]<<8; //MIXS is 16 bit
+ else if(IRA<=0x31)
+ INPUTS=0;
+
+ INPUTS<<=8;
+ INPUTS>>=8;
+ //if(INPUTS&0x00800000)
+ // INPUTS|=0xFF000000;
+
+ if(IWT)
+ {
+ DSP->MEMS[IWA]=MEMVAL; //MEMVAL was selected in previous MRD
+ if(IRA==IWA)
+ INPUTS=MEMVAL;
+ }
+
+ //Operand sel
+ //B
+ if(!ZERO)
+ {
+ if(BSEL)
+ B=ACC;
+ else
+ {
+ B=DSP->TEMP[(TRA+DSP->DEC)&0x7F];
+ B<<=8;
+ B>>=8;
+ //if(B&0x00800000)
+ // B|=0xFF000000; //Sign extend
+ }
+ if(NEGB)
+ B=0-B;
+ }
+ else
+ B=0;
+
+ //X
+ if(XSEL)
+ X=INPUTS;
+ else
+ {
+ X=DSP->TEMP[(TRA+DSP->DEC)&0x7F];
+ X<<=8;
+ X>>=8;
+ //if(X&0x00800000)
+ // X|=0xFF000000;
+ }
+
+ //Y
+ if(YSEL==0)
+ Y=FRC_REG;
+ else if(YSEL==1)
+ Y=DSP->COEF[COEF]>>3; //COEF is 16 bits
+ else if(YSEL==2)
+ Y=(Y_REG>>11)&0x1FFF;
+ else if(YSEL==3)
+ Y=(Y_REG>>4)&0x0FFF;
+
+ if(YRL)
+ Y_REG=INPUTS;
+
+ //Shifter
+ if(SHIFT==0)
+ {
+ SHIFTED=ACC;
+ if(SHIFTED>0x007FFFFF)
+ SHIFTED=0x007FFFFF;
+ if(SHIFTED<(-0x00800000))
+ SHIFTED=-0x00800000;
+ }
+ else if(SHIFT==1)
+ {
+ SHIFTED=ACC*2;
+ if(SHIFTED>0x007FFFFF)
+ SHIFTED=0x007FFFFF;
+ if(SHIFTED<(-0x00800000))
+ SHIFTED=-0x00800000;
+ }
+ else if(SHIFT==2)
+ {
+ SHIFTED=ACC*2;
+ SHIFTED<<=8;
+ SHIFTED>>=8;
+ //SHIFTED&=0x00FFFFFF;
+ //if(SHIFTED&0x00800000)
+ // SHIFTED|=0xFF000000;
+ }
+ else if(SHIFT==3)
+ {
+ SHIFTED=ACC;
+ SHIFTED<<=8;
+ SHIFTED>>=8;
+ //SHIFTED&=0x00FFFFFF;
+ //if(SHIFTED&0x00800000)
+ // SHIFTED|=0xFF000000;
+ }
+
+ //ACCUM
+ Y<<=19;
+ Y>>=19;
+ //if(Y&0x1000)
+ // Y|=0xFFFFF000;
+
+ v=(((INT64) X*(INT64) Y)>>12);
+ ACC=(int) v+B;
+
+ if(TWT)
+ DSP->TEMP[(TWA+DSP->DEC)&0x7F]=SHIFTED;
+
+ if(FRCL)
+ {
+ if(SHIFT==3)
+ FRC_REG=SHIFTED&0x0FFF;
+ else
+ FRC_REG=(SHIFTED>>11)&0x1FFF;
+ }
+
+ if(MRD || MWT)
+ //if(0)
+ {
+ ADDR=DSP->MADRS[MASA];
+ if(!TABLE)
+ ADDR+=DSP->DEC;
+ if(ADREB)
+ ADDR+=ADRS_REG&0x0FFF;
+ if(NXADR)
+ ADDR++;
+ if(!TABLE)
+ ADDR&=DSP->RBL-1;
+ else
+ ADDR&=0xFFFF;
+ //ADDR<<=1;
+ //ADDR+=DSP->RBP<<13;
+ //MEMVAL=DSP->SCSPRAM[ADDR>>1];
+ ADDR+=DSP->RBP<<12;
+ if (ADDR > 0x7ffff) ADDR = 0;
+ if(MRD && (step&1)) //memory only allowed on odd? DoA inserts NOPs on even
+ {
+ if(NOFL)
+ MEMVAL=DSP->SCSPRAM[ADDR]<<8;
+ else
+ MEMVAL=UNPACK(DSP->SCSPRAM[ADDR]);
+ }
+ if(MWT && (step&1))
+ {
+ if(NOFL)
+ DSP->SCSPRAM[ADDR]=SHIFTED>>8;
+ else
+ DSP->SCSPRAM[ADDR]=PACK(SHIFTED);
+ }
+ }
+
+ if(ADRL)
+ {
+ if(SHIFT==3)
+ ADRS_REG=(SHIFTED>>12)&0xFFF;
+ else
+ ADRS_REG=(INPUTS>>16);
+ }
+
+ if(EWT)
+ DSP->EFREG[EWA]+=SHIFTED>>8;
+
+ }
+ --DSP->DEC;
+ memset(DSP->MIXS,0,4*16);
+// if(f)
+// fclose(f);
+}
+
+void SCSPDSP_SetSample(struct _SCSPDSP *DSP,INT32 sample,int SEL,int MXL)
+{
+ //DSP->MIXS[SEL]+=sample<<(MXL+1)/*7*/;
+ DSP->MIXS[SEL]+=sample<<7;
+// if(MXL)
+// int a=1;
+}
+
+void SCSPDSP_Start(struct _SCSPDSP *DSP)
+{
+ int i;
+ DSP->Stopped=0;
+ for(i=127;i>=0;--i)
+ {
+ UINT16 *IPtr=DSP->MPRO+i*4;
+
+ if(IPtr[0]!=0 || IPtr[1]!=0 || IPtr[2]!=0 || IPtr[3]!=0)
+ break;
+ }
+ DSP->LastStep=i+1;
+
+}
diff --git a/src/emu/sound/scspdsp.h b/src/emu/sound/scspdsp.h
new file mode 100644
index 00000000000..481f93af0bd
--- /dev/null
+++ b/src/emu/sound/scspdsp.h
@@ -0,0 +1,37 @@
+#ifndef SCSPDSP_H
+#define SCSPDSP_H
+
+//the DSP Context
+struct _SCSPDSP
+{
+//Config
+ UINT16 *SCSPRAM;
+ UINT32 SCSPRAM_LENGTH;
+ UINT32 RBP; //Ring buf pointer
+ UINT32 RBL; //Delay ram (Ring buffer) size in words
+
+//context
+
+ INT16 COEF[64]; //16 bit signed
+ UINT16 MADRS[32]; //offsets (in words), 16 bit
+ UINT16 MPRO[128*4]; //128 steps 64 bit
+ INT32 TEMP[128]; //TEMP regs,24 bit signed
+ INT32 MEMS[32]; //MEMS regs,24 bit signed
+ UINT32 DEC;
+
+//input
+ INT32 MIXS[16]; //MIXS, 24 bit signed
+ INT16 EXTS[2]; //External inputs (CDDA) 16 bit signed
+
+//output
+ INT16 EFREG[16]; //EFREG, 16 bit signed
+
+ int Stopped;
+ int LastStep;
+};
+
+void SCSPDSP_Init(struct _SCSPDSP *DSP);
+void SCSPDSP_SetSample(struct _SCSPDSP *DSP, INT32 sample, INT32 SEL, INT32 MXL);
+void SCSPDSP_Step(struct _SCSPDSP *DSP);
+void SCSPDSP_Start(struct _SCSPDSP *DSP);
+#endif
diff --git a/src/emu/sound/scsplfo.c b/src/emu/sound/scsplfo.c
new file mode 100644
index 00000000000..dc9dcca674c
--- /dev/null
+++ b/src/emu/sound/scsplfo.c
@@ -0,0 +1,157 @@
+/*
+ SCSP LFO handling
+
+ Part of the SCSP (YMF292-F) emulator package.
+ (not compiled directly, #included from scsp.c)
+
+ By ElSemi
+ MAME/M1 conversion and cleanup by R. Belmont
+*/
+
+#define LFO_SHIFT 8
+
+struct _LFO
+{
+ unsigned short phase;
+ UINT32 phase_step;
+ int *table;
+ int *scale;
+};
+
+#define LFIX(v) ((unsigned int) ((float) (1<<LFO_SHIFT)*(v)))
+
+//Convert DB to multiply amplitude
+#define DB(v) LFIX(pow(10.0,v/20.0))
+
+//Convert cents to step increment
+#define CENTS(v) LFIX(pow(2.0,v/1200.0))
+
+static int PLFO_TRI[256],PLFO_SQR[256],PLFO_SAW[256],PLFO_NOI[256];
+static int ALFO_TRI[256],ALFO_SQR[256],ALFO_SAW[256],ALFO_NOI[256];
+static float LFOFreq[32]={0.17,0.19,0.23,0.27,0.34,0.39,0.45,0.55,0.68,0.78,0.92,1.10,1.39,1.60,1.87,2.27,
+ 2.87,3.31,3.92,4.79,6.15,7.18,8.60,10.8,14.4,17.2,21.5,28.7,43.1,57.4,86.1,172.3};
+static float ASCALE[8]={0.0,0.4,0.8,1.5,3.0,6.0,12.0,24.0};
+static float PSCALE[8]={0.0,7.0,13.5,27.0,55.0,112.0,230.0,494};
+static int PSCALES[8][256];
+static int ASCALES[8][256];
+
+static void LFO_Init(void)
+{
+ int i,s;
+ for(i=0;i<256;++i)
+ {
+ int a,p;
+// float TL;
+ //Saw
+ a=255-i;
+ if(i<128)
+ p=i;
+ else
+ p=255-i;
+ ALFO_SAW[i]=a;
+ PLFO_SAW[i]=p;
+
+ //Square
+ if(i<128)
+ {
+ a=255;
+ p=127;
+ }
+ else
+ {
+ a=0;
+ p=-128;
+ }
+ ALFO_SQR[i]=a;
+ PLFO_SQR[i]=p;
+
+ //Tri
+ if(i<128)
+ a=255-(i*2);
+ else
+ a=(i*2)-256;
+ if(i<64)
+ p=i*2;
+ else if(i<128)
+ p=255-i*2;
+ else if(i<192)
+ p=256-i*2;
+ else
+ p=i*2-511;
+ ALFO_TRI[i]=a;
+ PLFO_TRI[i]=p;
+
+ //noise
+ //a=lfo_noise[i];
+ a=mame_rand(Machine)&0xff;
+ p=128-a;
+ ALFO_NOI[i]=a;
+ PLFO_NOI[i]=p;
+ }
+
+ for(s=0;s<8;++s)
+ {
+ float limit=PSCALE[s];
+ for(i=-128;i<128;++i)
+ {
+ PSCALES[s][i+128]=CENTS(((limit*(float) i)/128.0));
+ }
+ limit=-ASCALE[s];
+ for(i=0;i<256;++i)
+ {
+ ASCALES[s][i]=DB(((limit*(float) i)/256.0));
+ }
+ }
+}
+
+INLINE signed int PLFO_Step(struct _LFO *LFO)
+{
+ int p;
+ LFO->phase+=LFO->phase_step;
+#if LFO_SHIFT!=8
+ LFO->phase&=(1<<(LFO_SHIFT+8))-1;
+#endif
+ p=LFO->table[LFO->phase>>LFO_SHIFT];
+ p=LFO->scale[p+128];
+ return p<<(SHIFT-LFO_SHIFT);
+}
+
+INLINE signed int ALFO_Step(struct _LFO *LFO)
+{
+ int p;
+ LFO->phase+=LFO->phase_step;
+#if LFO_SHIFT!=8
+ LFO->phase&=(1<<(LFO_SHIFT+8))-1;
+#endif
+ p=LFO->table[LFO->phase>>LFO_SHIFT];
+ p=LFO->scale[p];
+ return p<<(SHIFT-LFO_SHIFT);
+}
+
+static void LFO_ComputeStep(struct _LFO *LFO,UINT32 LFOF,UINT32 LFOWS,UINT32 LFOS,int ALFO)
+{
+ float step=(float) LFOFreq[LFOF]*256.0/(float)44100;
+ LFO->phase_step=(unsigned int) ((float) (1<<LFO_SHIFT)*step);
+ if(ALFO)
+ {
+ switch(LFOWS)
+ {
+ case 0: LFO->table=ALFO_SAW; break;
+ case 1: LFO->table=ALFO_SQR; break;
+ case 2: LFO->table=ALFO_TRI; break;
+ case 3: LFO->table=ALFO_NOI; break;
+ }
+ LFO->scale=ASCALES[LFOS];
+ }
+ else
+ {
+ switch(LFOWS)
+ {
+ case 0: LFO->table=PLFO_SAW; break;
+ case 1: LFO->table=PLFO_SQR; break;
+ case 2: LFO->table=PLFO_TRI; break;
+ case 3: LFO->table=PLFO_NOI; break;
+ }
+ LFO->scale=PSCALES[LFOS];
+ }
+}
diff --git a/src/emu/sound/segapcm.c b/src/emu/sound/segapcm.c
new file mode 100644
index 00000000000..7fa6a215fa7
--- /dev/null
+++ b/src/emu/sound/segapcm.c
@@ -0,0 +1,160 @@
+/*********************************************************/
+/* SEGA 16ch 8bit PCM */
+/*********************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "segapcm.h"
+
+struct segapcm
+{
+ UINT8 *ram;
+ UINT8 low[16];
+ const UINT8 *rom;
+ int bankshift;
+ int bankmask;
+ sound_stream * stream;
+};
+
+static void SEGAPCM_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct segapcm *spcm = param;
+ int ch;
+
+ /* clear the buffers */
+ memset(buffer[0], 0, length*sizeof(*buffer[0]));
+ memset(buffer[1], 0, length*sizeof(*buffer[1]));
+
+ /* loop over channels */
+ for (ch = 0; ch < 16; ch++)
+
+ /* only process active channels */
+ if (!(spcm->ram[0x86+8*ch] & 1))
+ {
+ UINT8 *base = spcm->ram+8*ch;
+ UINT8 flags = base[0x86];
+ const UINT8 *rom = spcm->rom + ((flags & spcm->bankmask) << spcm->bankshift);
+ UINT32 addr = (base[5] << 16) | (base[4] << 8) | spcm->low[ch];
+ UINT16 loop = (base[0x85] << 8) | base[0x84];
+ UINT8 end = base[6] + 1;
+ UINT8 delta = base[7];
+ UINT8 voll = base[2];
+ UINT8 volr = base[3];
+ int i;
+
+ /* loop over samples on this channel */
+ for (i = 0; i < length; i++)
+ {
+ INT8 v = 0;
+
+ /* handle looping if we've hit the end */
+ if ((addr >> 16) == end)
+ {
+ if (!(flags & 2))
+ addr = loop << 8;
+ else
+ {
+ flags |= 1;
+ break;
+ }
+ }
+
+ /* fetch the sample */
+ v = rom[addr >> 8] - 0x80;
+
+ /* apply panning and advance */
+ buffer[0][i] += v * voll;
+ buffer[1][i] += v * volr;
+ addr += delta;
+ }
+
+ /* store back the updated address and info */
+ base[0x86] = flags;
+ base[4] = addr >> 8;
+ base[5] = addr >> 16;
+ spcm->low[ch] = flags & 1 ? 0 : addr;
+ }
+}
+
+static void *segapcm_start(int sndindex, int clock, const void *config)
+{
+ const struct SEGAPCMinterface *intf = config;
+ int mask, rom_mask;
+ struct segapcm *spcm;
+
+ spcm = auto_malloc(sizeof(*spcm));
+ memset(spcm, 0, sizeof(*spcm));
+
+ spcm->rom = (const UINT8 *)memory_region(intf->region);
+ spcm->ram = auto_malloc(0x800);
+
+ memset(spcm->ram, 0xff, 0x800);
+
+ spcm->bankshift = (UINT8)(intf->bank);
+ mask = intf->bank >> 16;
+ if(!mask)
+ mask = BANK_MASK7>>16;
+
+ for(rom_mask = 1; rom_mask < memory_region_length(intf->region); rom_mask *= 2);
+ rom_mask--;
+
+ spcm->bankmask = mask & (rom_mask >> spcm->bankshift);
+
+ spcm->stream = stream_create(0, 2, clock / 128, spcm, SEGAPCM_update);
+
+ state_save_register_item_array("segapcm", sndindex, spcm->low);
+ state_save_register_item_pointer("segapcm", sndindex, spcm->ram, 0x800);
+
+ return spcm;
+}
+
+
+WRITE8_HANDLER( SegaPCM_w )
+{
+ struct segapcm *spcm = sndti_token(SOUND_SEGAPCM, 0);
+ stream_update(spcm->stream);
+ spcm->ram[offset & 0x07ff] = data;
+}
+
+READ8_HANDLER( SegaPCM_r )
+{
+ struct segapcm *spcm = sndti_token(SOUND_SEGAPCM, 0);
+ stream_update(spcm->stream);
+ return spcm->ram[offset & 0x07ff];
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void segapcm_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void segapcm_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = segapcm_set_info; break;
+ case SNDINFO_PTR_START: info->start = segapcm_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Sega PCM"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Sega custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/segapcm.h b/src/emu/sound/segapcm.h
new file mode 100644
index 00000000000..c2ceac372c0
--- /dev/null
+++ b/src/emu/sound/segapcm.h
@@ -0,0 +1,24 @@
+/*********************************************************/
+/* SEGA 8bit PCM */
+/*********************************************************/
+
+#ifndef __SEGAPCM_H__
+#define __SEGAPCM_H__
+
+#define BANK_256 (11)
+#define BANK_512 (12)
+#define BANK_12M (13)
+#define BANK_MASK7 (0x70<<16)
+#define BANK_MASKF (0xf0<<16)
+#define BANK_MASKF8 (0xf8<<16)
+
+struct SEGAPCMinterface
+{
+ int bank;
+ int region;
+};
+
+WRITE8_HANDLER( SegaPCM_w );
+READ8_HANDLER( SegaPCM_r );
+
+#endif
diff --git a/src/emu/sound/sid.c b/src/emu/sound/sid.c
new file mode 100644
index 00000000000..b6825add8a4
--- /dev/null
+++ b/src/emu/sound/sid.c
@@ -0,0 +1,364 @@
+/*
+ copyright peter trauner 2000
+
+ based on michael schwend's sid play
+
+ Noise generation algorithm is used courtesy of Asger Alstrup Nielsen.
+ His original publication can be found on the SID home page.
+
+ Noise table optimization proposed by Phillip Wooller. The output of
+ each table does not differ.
+
+ MOS-8580 R5 combined waveforms recorded by Dennis "Deadman" Lindroos.
+*/
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "sidvoice.h"
+#include "sidenvel.h"
+#include "sid.h"
+
+static float *filterTable;
+static float *bandPassParam;
+#define lowPassParam filterTable
+float filterResTable[16];
+
+#define maxLogicalVoices 4
+
+static const int mix16monoMiddleIndex = 256*maxLogicalVoices/2;
+static UINT16 mix16mono[256*maxLogicalVoices];
+
+static UINT16 zero16bit=0; /* either signed or unsigned */
+UINT32 splitBufferLen;
+
+void MixerInit(int threeVoiceAmplify)
+{
+ long si;
+ UINT16 ui;
+ long ampDiv = maxLogicalVoices;
+
+ if (threeVoiceAmplify)
+ {
+ ampDiv = (maxLogicalVoices-1);
+ }
+
+ /* Mixing formulas are optimized by sample input value. */
+
+ si = (-128*maxLogicalVoices) * 256;
+ for (ui = 0; ui < sizeof(mix16mono)/sizeof(UINT16); ui++ )
+ {
+ mix16mono[ui] = (UINT16)(si/ampDiv) + zero16bit;
+ si+=256;
+ }
+
+}
+
+
+INLINE void syncEm(SID6581 *This)
+{
+ int sync1 = (This->optr1.modulator->cycleLenCount <= 0);
+ int sync2 = (This->optr2.modulator->cycleLenCount <= 0);
+ int sync3 = (This->optr3.modulator->cycleLenCount <= 0);
+
+ This->optr1.cycleLenCount--;
+ This->optr2.cycleLenCount--;
+ This->optr3.cycleLenCount--;
+
+ if (This->optr1.sync && sync1)
+ {
+ This->optr1.cycleLenCount = 0;
+ This->optr1.outProc = &sidWaveCalcNormal;
+#if defined(DIRECT_FIXPOINT)
+ optr1.waveStep.l = 0;
+#else
+ This->optr1.waveStep = (This->optr1.waveStepPnt = 0);
+#endif
+ }
+ if (This->optr2.sync && sync2)
+ {
+ This->optr2.cycleLenCount = 0;
+ This->optr2.outProc = &sidWaveCalcNormal;
+#if defined(DIRECT_FIXPOINT)
+ This->optr2.waveStep.l = 0;
+#else
+ This->optr2.waveStep = (This->optr2.waveStepPnt = 0);
+#endif
+ }
+ if (This->optr3.sync && sync3)
+ {
+ This->optr3.cycleLenCount = 0;
+ This->optr3.outProc = &sidWaveCalcNormal;
+#if defined(DIRECT_FIXPOINT)
+ optr3.waveStep.l = 0;
+#else
+ This->optr3.waveStep = (This->optr3.waveStepPnt = 0);
+#endif
+ }
+}
+
+
+void sidEmuFillBuffer(SID6581 *This, stream_sample_t *buffer, UINT32 bufferLen )
+{
+//void* fill16bitMono( SID6581 *This, void* buffer, UINT32 numberOfSamples )
+
+ for ( ; bufferLen > 0; bufferLen-- )
+ {
+ *buffer++ = (INT16) mix16mono[(unsigned)(mix16monoMiddleIndex
+ +(*This->optr1.outProc)(&This->optr1)
+ +(*This->optr2.outProc)(&This->optr2)
+ +(This->optr3.outProc(&This->optr3)&This->optr3_outputmask)
+/* hack for digi sounds
+ does n't seam to come from a tone operator
+ ghostbusters and goldrunner everything except volume zeroed */
+ +(This->masterVolume<<2)
+// +(*sampleEmuRout)()
+ )];
+ syncEm(This);
+ }
+}
+
+/* --------------------------------------------------------------------- Init */
+
+
+/* Reset. */
+
+int sidEmuReset(SID6581 *This)
+{
+ sidClearOperator( &This->optr1 );
+ enveEmuResetOperator( &This->optr1 );
+ sidClearOperator( &This->optr2 );
+ enveEmuResetOperator( &This->optr2 );
+ sidClearOperator( &This->optr3 );
+ enveEmuResetOperator( &This->optr3 );
+ This->optr3_outputmask = ~0; /* on */
+
+// sampleEmuReset();
+
+ This->filter.Type = (This->filter.CurType = 0);
+ This->filter.Value = 0;
+ This->filter.Dy = (This->filter.ResDy = 0);
+
+ sidEmuSet( &This->optr1 );
+ sidEmuSet( &This->optr2 );
+ sidEmuSet( &This->optr3 );
+
+ sidEmuSet2( &This->optr1 );
+ sidEmuSet2( &This->optr2 );
+ sidEmuSet2( &This->optr3 );
+
+ return TRUE;
+}
+
+
+void filterTableInit(void)
+{
+ UINT16 uk;
+ /* Parameter calculation has not been moved to a separate function */
+ /* by purpose. */
+ const float filterRefFreq = 44100.0;
+
+ float yMax = 1.0;
+ float yMin = 0.01;
+ float yAdd;
+ float yTmp, rk, rk2;
+
+ float resDyMax;
+ float resDyMin;
+ float resDy;
+
+ filterTable = auto_malloc(sizeof(*filterTable) * 0x800);
+ bandPassParam = auto_malloc(sizeof(*bandPassParam) * 0x800);
+
+ uk = 0;
+ for ( rk = 0; rk < 0x800; rk++ )
+ {
+ filterTable[uk] = (((exp(rk/0x800*log(400.0))/60.0)+0.05)
+ *filterRefFreq) / Machine->sample_rate;
+ if ( filterTable[uk] < yMin )
+ filterTable[uk] = yMin;
+ if ( filterTable[uk] > yMax )
+ filterTable[uk] = yMax;
+ uk++;
+ }
+
+ /*extern float bandPassParam[0x800]; */
+ yMax = 0.22;
+ yMin = 0.05; /* less for some R1/R4 chips */
+ yAdd = (yMax-yMin)/2048.0;
+ yTmp = yMin;
+ uk = 0;
+ /* Some C++ compilers still have non-local scope! */
+ for ( rk2 = 0; rk2 < 0x800; rk2++ )
+ {
+ bandPassParam[uk] = (yTmp*filterRefFreq) / Machine->sample_rate;
+ yTmp += yAdd;
+ uk++;
+ }
+
+ /*extern float filterResTable[16]; */
+ resDyMax = 1.0;
+ resDyMin = 2.0;
+ resDy = resDyMin;
+ for ( uk = 0; uk < 16; uk++ )
+ {
+ filterResTable[uk] = resDy;
+ resDy -= (( resDyMin - resDyMax ) / 15 );
+ }
+ filterResTable[0] = resDyMin;
+ filterResTable[15] = resDyMax;
+}
+
+void sid6581_init (SID6581 *This)
+{
+ This->optr1.sid=This;
+ This->optr2.sid=This;
+ This->optr3.sid=This;
+
+ This->optr1.modulator = &This->optr3;
+ This->optr3.carrier = &This->optr1;
+ This->optr1.filtVoiceMask = 1;
+
+ This->optr2.modulator = &This->optr1;
+ This->optr1.carrier = &This->optr2;
+ This->optr2.filtVoiceMask = 2;
+
+ This->optr3.modulator = &This->optr2;
+ This->optr2.carrier = &This->optr3;
+ This->optr3.filtVoiceMask = 4;
+
+
+
+ This->PCMsid = (UINT32)(This->PCMfreq * (16777216.0 / This->clock));
+ This->PCMsidNoise = (UINT32)((This->clock*256.0)/This->PCMfreq);
+
+ This->filter.Enabled = TRUE;
+
+ sidInitMixerEngine();
+ filterTableInit();
+
+ sidInitWaveformTables(This->type);
+
+ enveEmuInit(This->PCMfreq, TRUE);
+
+ MixerInit(0);
+
+ sidEmuReset(This);
+}
+
+void sid6581_port_w (SID6581 *This, int offset, int data)
+{
+ offset &= 0x1f;
+
+ switch (offset)
+ {
+ case 0x19: case 0x1a: case 0x1b: case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ break;
+ case 0x15: case 0x16: case 0x17:
+ case 0x18:
+ stream_update(This->mixer_channel);
+ This->reg[offset] = data;
+ This->masterVolume = ( This->reg[0x18] & 15 );
+ This->masterVolumeAmplIndex = This->masterVolume << 8;
+
+ if ((This->reg[0x18]&0x80) &&
+ ((This->reg[0x17]&This->optr3.filtVoiceMask)==0))
+ This->optr3_outputmask = 0; /* off */
+ else
+ This->optr3_outputmask = ~0; /* on */
+
+ This->filter.Type = This->reg[0x18] & 0x70;
+ if (This->filter.Type != This->filter.CurType)
+ {
+ This->filter.CurType = This->filter.Type;
+ This->optr1.filtLow = (This->optr1.filtRef = 0);
+ This->optr2.filtLow = (This->optr2.filtRef = 0);
+ This->optr3.filtLow = (This->optr3.filtRef = 0);
+ }
+ if ( This->filter.Enabled )
+ {
+ This->filter.Value = 0x7ff & ( (This->reg[0x15]&7) | ( (UINT16)This->reg[0x16] << 3 ));
+ if (This->filter.Type == 0x20)
+ This->filter.Dy = bandPassParam ? bandPassParam[This->filter.Value] : 0.0;
+ else
+ This->filter.Dy = lowPassParam ? lowPassParam[This->filter.Value] : 0.0;
+ This->filter.ResDy = filterResTable[This->reg[0x17] >> 4] - This->filter.Dy;
+ if ( This->filter.ResDy < 1.0 )
+ This->filter.ResDy = 1.0;
+ }
+
+ sidEmuSet( &This->optr1 );
+ sidEmuSet( &This->optr3 );
+ sidEmuSet( &This->optr2 );
+
+ // relies on sidEmuSet also for other channels!
+ sidEmuSet2( &This->optr1 );
+ sidEmuSet2( &This->optr2 );
+ sidEmuSet2( &This->optr3 );
+ break;
+
+ default:
+ stream_update(This->mixer_channel);
+ This->reg[offset] = data;
+
+ if (offset<7) {
+ This->optr1.reg[offset] = data;
+ } else if (offset<14) {
+ This->optr2.reg[offset-7] = data;
+ } else if (offset<21) {
+ This->optr3.reg[offset-14] = data;
+ }
+
+ sidEmuSet( &This->optr1 );
+ sidEmuSet( &This->optr3 );
+ sidEmuSet( &This->optr2 );
+
+ // relies on sidEmuSet also for other channels!
+ sidEmuSet2( &This->optr1 );
+ sidEmuSet2( &This->optr2 );
+ sidEmuSet2( &This->optr3 );
+ break;
+ }
+}
+
+int sid6581_port_r (SID6581 *This, int offset)
+{
+ int data;
+/* SIDPLAY reads last written at a sid address value */
+ offset &= 0x1f;
+ switch (offset)
+ {
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ data=0xff;
+ break;
+ case 0x19: /* paddle 1 */
+ if (This->ad_read != NULL)
+ data=This->ad_read (0);
+ else
+ data=0;
+ break;
+ case 0x1a: /* paddle 2 */
+ if (This->ad_read != NULL)
+ data=This->ad_read (1);
+ else
+ data=0;
+ break;
+ case 0x1b:
+ stream_update(This->mixer_channel);
+ data = This->optr3.output;
+ break;
+ case 0x1c:
+ stream_update(This->mixer_channel);
+ data = This->optr3.enveVol;
+ break;
+ default:
+ data=This->reg[offset];
+ }
+ return data;
+}
+
diff --git a/src/emu/sound/sid.h b/src/emu/sound/sid.h
new file mode 100644
index 00000000000..55c54011f47
--- /dev/null
+++ b/src/emu/sound/sid.h
@@ -0,0 +1,74 @@
+#ifndef __SID_H_
+#define __SID_H_
+
+/*
+ approximation of the sid6581 chip
+ this part is for one chip,
+*/
+
+#include "sound/sid6581.h"
+#include "sidvoice.h"
+#include "streams.h"
+
+/* private area */
+typedef struct _SID6581
+{
+ sound_stream *mixer_channel; // mame stream/ mixer channel
+
+ int (*ad_read) (int which);
+ SIDTYPE type;
+ UINT32 clock;
+
+ UINT16 PCMfreq; // samplerate of the current systems soundcard/DAC
+ UINT32 PCMsid, PCMsidNoise;
+
+#if 0
+ /* following depends on type */
+ ptr2sidVoidFunc ModeNormalTable[16];
+ ptr2sidVoidFunc ModeRingTable[16];
+ // for speed reason it could be better to make them global!
+ UINT8* waveform30;
+ UINT8* waveform50;
+ UINT8* waveform60;
+ UINT8* waveform70;
+#endif
+ int reg[0x20];
+
+// bool sidKeysOn[0x20], sidKeysOff[0x20];
+
+ UINT8 masterVolume;
+ UINT16 masterVolumeAmplIndex;
+
+
+ struct
+ {
+ int Enabled;
+ UINT8 Type, CurType;
+ float Dy, ResDy;
+ UINT16 Value;
+ } filter;
+
+ sidOperator optr1, optr2, optr3;
+ int optr3_outputmask;
+} SID6581;
+
+void sid6581_init (SID6581 *This);
+
+int sidEmuReset(SID6581 *This);
+
+int sid6581_port_r (SID6581 *This, int offset);
+void sid6581_port_w (SID6581 *This, int offset, int data);
+
+void sid_set_type(SID6581 *This, SIDTYPE type);
+
+void initMixerEngine(void);
+void filterTableInit(void);
+extern void MixerInit(int threeVoiceAmplify);
+
+void sidEmuFillBuffer(SID6581 *This, stream_sample_t *buffer, UINT32 bufferLen );
+
+#if 0
+void sidFilterTableInit(void);
+#endif
+
+#endif
diff --git a/src/emu/sound/sid6581.c b/src/emu/sound/sid6581.c
new file mode 100644
index 00000000000..0b5b4b67287
--- /dev/null
+++ b/src/emu/sound/sid6581.c
@@ -0,0 +1,144 @@
+/***************************************************************************
+
+ sid6581.c
+
+ MAME/MESS interface for SID6581 and SID8580 chips
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "sid6581.h"
+#include "sid.h"
+
+
+
+static SID6581 *get_sid(int indx)
+{
+ sound_type type = sndnum_to_sndti(indx, NULL);
+ assert((type == SOUND_SID6581) || (type == SOUND_SID8580));
+ return (SID6581 *) sndti_token(type, indx);
+}
+
+
+
+static void sid_update(void *token,stream_sample_t **inputs, stream_sample_t **_buffer,int length)
+{
+ SID6581 *sid = (SID6581 *) token;
+ sidEmuFillBuffer(sid, _buffer[0], length);
+}
+
+
+
+static void *sid_start(int sndindex, int clock, const void *config, SIDTYPE sidtype)
+{
+ SID6581 *sid;
+ const SID6581_interface *iface = (const SID6581_interface*) config;
+
+ sid = (SID6581 *) auto_malloc(sizeof(*sid));
+ memset(sid, 0, sizeof(*sid));
+
+ sid->mixer_channel = stream_create (0, 1, Machine->sample_rate, (void *) sid, sid_update);
+ sid->PCMfreq = Machine->sample_rate;
+ sid->clock = clock;
+ sid->ad_read = iface ? iface->ad_read : NULL;
+ sid->type = sidtype;
+
+ sid6581_init(sid);
+ sidInitWaveformTables(sidtype);
+ return sid;
+}
+
+
+
+static void sid_reset(void *token)
+{
+ SID6581 *sid = (SID6581 *) token;
+ sidEmuReset(sid);
+}
+
+
+
+static void *sid6581_start(int sndindex, int clock, const void *config)
+{
+ return sid_start(sndindex, clock, config, MOS6581);
+}
+
+
+
+static void *sid8580_start(int sndindex, int clock, const void *config)
+{
+ return sid_start(sndindex, clock, config, MOS8580);
+}
+
+
+
+READ8_HANDLER ( sid6581_0_port_r )
+{
+ return sid6581_port_r(get_sid(0), offset);
+}
+
+READ8_HANDLER ( sid6581_1_port_r )
+{
+ return sid6581_port_r(get_sid(1), offset);
+}
+
+WRITE8_HANDLER ( sid6581_0_port_w )
+{
+ sid6581_port_w(get_sid(0), offset, data);
+}
+
+WRITE8_HANDLER ( sid6581_1_port_w )
+{
+ sid6581_port_w(get_sid(1), offset, data);
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void sid6581_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void sid6581_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = sid6581_set_info; break;
+ case SNDINFO_PTR_START: info->start = sid6581_start; break;
+ case SNDINFO_PTR_STOP: info->stop = NULL; break;
+ case SNDINFO_PTR_RESET: info->reset = sid_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "SID6581"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "SID"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2005, The MESS Team"; break;
+ }
+}
+
+
+void sid8580_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_START: info->start = sid8580_start; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "SID8580"; break;
+ default: sid6581_get_info(token, state, info); break;
+ }
+}
+
diff --git a/src/emu/sound/sid6581.h b/src/emu/sound/sid6581.h
new file mode 100644
index 00000000000..888e9ac027c
--- /dev/null
+++ b/src/emu/sound/sid6581.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+
+ sid6581.h
+
+ MAME/MESS interface for SID6581 and SID8580 chips
+
+***************************************************************************/
+
+#ifndef SID6581_H
+#define SID6581_H
+
+#include "sndintrf.h"
+
+typedef enum
+{
+ MOS6581,
+ MOS8580
+} SIDTYPE;
+
+
+typedef struct
+{
+ int (*ad_read)(int channel);
+} SID6581_interface;
+
+
+READ8_HANDLER ( sid6581_0_port_r );
+READ8_HANDLER ( sid6581_1_port_r );
+WRITE8_HANDLER ( sid6581_0_port_w );
+WRITE8_HANDLER ( sid6581_1_port_w );
+
+#endif /* SID6581_H */
diff --git a/src/emu/sound/side6581.h b/src/emu/sound/side6581.h
new file mode 100644
index 00000000000..8e2a5b8e829
--- /dev/null
+++ b/src/emu/sound/side6581.h
@@ -0,0 +1,124 @@
+//
+// /home/ms/source/sidplay/libsidplay/emu/RCS/enve_dl.h,v
+//
+
+#ifndef ENVE_DL_H
+#define ENVE_DL_H
+
+
+//
+// Hardware:
+// C64 C PAL, MOS 6581R4 1686 S
+//
+
+static UINT8 releaseTab[] =
+{
+ 255, 255, 254, 254, 253, 253, 252, 252, 251, 251, 250, 250, 249, 249, 248,
+ 248, 247, 247, 246, 246, 245, 245, 244, 244, 243, 243, 242, 242, 241, 241,
+ 240, 240, 239, 239, 238, 238, 237, 237, 236, 236, 235, 235, 234, 234, 233,
+ 233, 232, 232, 231, 231, 230, 230, 229, 229, 228, 228, 227, 227, 226, 226,
+ 225, 225, 224, 224, 223, 223, 222, 222, 221, 221, 220, 220, 219, 219, 218,
+ 218, 217, 217, 216, 216, 215, 215, 214, 214, 213, 213, 212, 212, 211, 211,
+ 210, 210, 209, 209, 208, 208, 207, 207, 206, 206, 205, 205, 204, 204, 203,
+ 203, 202, 202, 201, 201, 200, 200, 199, 199, 198, 198, 197, 197, 196, 196,
+ 195, 195, 194, 194, 193, 193, 192, 192, 191, 191, 190, 190, 189, 189, 188,
+ 188, 187, 187, 186, 186, 185, 185, 184, 184, 183, 183, 182, 182, 181, 181,
+ 180, 180, 179, 179, 178, 178, 177, 177, 176, 176, 175, 175, 174, 174, 173,
+ 173, 172, 172, 171, 171, 170, 170, 169, 169, 168, 168, 167, 167, 166, 166,
+ 165, 165, 164, 164, 163, 163, 162, 162, 161, 161, 160, 160, 159, 159, 158,
+ 158, 157, 157, 156, 156, 155, 155, 154, 154, 153, 153, 152, 152, 151, 151,
+ 150, 150, 149, 149, 148, 148, 147, 147, 146, 146, 145, 145, 144, 144, 143,
+ 143, 142, 142, 141, 141, 140, 140, 139, 139, 138, 138, 137, 137, 136, 136,
+ 135, 135, 134, 134, 133, 133, 132, 132, 131, 131, 130, 130, 129, 129, 128,
+ 128, 127, 127, 126, 126, 125, 125, 124, 124, 123, 123, 122, 122, 121, 121,
+ 120, 120, 119, 119, 118, 118, 117, 117, 116, 116, 115, 115, 114, 114, 113,
+ 113, 112, 112, 111, 111, 110, 110, 109, 109, 108, 108, 107, 107, 106, 106,
+ 105, 105, 104, 104, 103, 103, 102, 102, 101, 101, 100, 100, 99, 99, 98,
+ 98, 97, 97, 96, 96, 95, 95, 94, 94, 94, 94, 93, 93, 93, 93,
+ 92, 92, 92, 92, 91, 91, 91, 91, 90, 90, 90, 90, 89, 89, 89,
+ 89, 88, 88, 88, 88, 87, 87, 87, 87, 86, 86, 86, 86, 85, 85,
+ 85, 85, 84, 84, 84, 84, 83, 83, 83, 83, 82, 82, 82, 82, 81,
+ 81, 81, 81, 80, 80, 80, 80, 79, 79, 79, 79, 78, 78, 78, 78,
+ 77, 77, 77, 77, 76, 76, 76, 76, 75, 75, 75, 75, 74, 74, 74,
+ 74, 73, 73, 73, 73, 72, 72, 72, 72, 71, 71, 71, 71, 70, 70,
+ 70, 70, 69, 69, 69, 69, 68, 68, 68, 68, 67, 67, 67, 67, 66,
+ 66, 66, 66, 65, 65, 65, 65, 64, 64, 64, 64, 63, 63, 63, 63,
+ 62, 62, 62, 62, 61, 61, 61, 61, 60, 60, 60, 60, 59, 59, 59,
+ 59, 58, 58, 58, 58, 57, 57, 57, 57, 56, 56, 56, 56, 55, 55,
+ 55, 55, 55, 55, 55, 55, 54, 54, 54, 54, 54, 54, 54, 54, 53,
+ 53, 53, 53, 53, 53, 53, 53, 52, 52, 52, 52, 52, 52, 52, 52,
+ 51, 51, 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50,
+ 50, 49, 49, 49, 49, 49, 49, 49, 49, 48, 48, 48, 48, 48, 48,
+ 48, 48, 47, 47, 47, 47, 47, 47, 47, 47, 46, 46, 46, 46, 46,
+ 46, 46, 46, 45, 45, 45, 45, 45, 45, 45, 45, 44, 44, 44, 44,
+ 44, 44, 44, 44, 43, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42,
+ 42, 42, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 40, 40,
+ 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39, 38,
+ 38, 38, 38, 38, 38, 38, 38, 37, 37, 37, 37, 37, 37, 37, 37,
+ 36, 36, 36, 36, 36, 36, 36, 36, 35, 35, 35, 35, 35, 35, 35,
+ 35, 34, 34, 34, 34, 34, 34, 34, 34, 33, 33, 33, 33, 33, 33,
+ 33, 33, 32, 32, 32, 32, 32, 32, 32, 32, 31, 31, 31, 31, 31,
+ 31, 31, 31, 30, 30, 30, 30, 30, 30, 30, 30, 29, 29, 29, 29,
+ 29, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 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, 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, 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, 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, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
+};
+
+
+#endif
diff --git a/src/emu/sound/sidenvel.c b/src/emu/sound/sidenvel.c
new file mode 100644
index 00000000000..2958b8a9b24
--- /dev/null
+++ b/src/emu/sound/sidenvel.c
@@ -0,0 +1,590 @@
+/*========================================================================= */
+/* This source implements the ADSR volume envelope of the SID-chip. */
+/* Two different envelope shapes are implemented, an exponential */
+/* approximation and the linear shape, which can easily be determined */
+/* by reading the registers of the third SID operator. */
+/* */
+/* Accurate volume envelope times as of November 1994 are used */
+/* courtesy of George W. Taylor <aa601@cfn.cs.dal.ca>, <yurik@io.org> */
+/* They are slightly modified. */
+/* */
+/* To use the rounded envelope times from the C64 Programmers Reference */
+/* Book define SID_REFTIMES at the Makefile level. */
+/* */
+/* To perform realtime calculations with floating point precision define */
+/* SID_FPUENVE at the Makefile level. On high-end FPUs (not Pentium !), */
+/* this can result in speed improvement. Default is integer fixpoint. */
+/* */
+/* Global Makefile definables: */
+/* */
+/* DIRECT_FIXPOINT - use a union to access integer fixpoint operands */
+/* in memory. This makes an assumption about the */
+/* hardware and software architecture and therefore */
+/* is considered a hack ! */
+/* */
+/* Local (or Makefile) definables: */
+/* */
+/* SID_REFTIMES - use rounded envelope times */
+/* SID_FPUENVE - use floating point precision for calculations */
+/* (will override the global DIRECT_FIXPOINT setting !) */
+/* */
+/*========================================================================= */
+
+#include <math.h>
+
+#include "sidvoice.h"
+#include "sid.h"
+
+#include "side6581.h"
+#include "sidenvel.h"
+
+const UINT8 masterVolumeLevels[16] =
+{
+ 0, 17, 34, 51, 68, 85, 102, 119,
+ 136, 153, 170, 187, 204, 221, 238, 255
+};
+
+static UINT16 masterAmplModTable[16*256];
+
+static float attackTimes[16] =
+{
+ /* milliseconds */
+#if defined(SID_REFTIMES)
+ 2,8,16,24,38,56,68,80,
+ 100,250,500,800,1000,3000,5000,8000
+#else
+ 2.2528606, 8.0099577, 15.7696042, 23.7795619, 37.2963655, 55.0684591,
+ 66.8330845, 78.3473987,
+ 98.1219818, 244.554021, 489.108042, 782.472742, 977.715461, 2933.64701,
+ 4889.07793, 7822.72493
+#endif
+};
+
+static float decayReleaseTimes[16] =
+{
+ /* milliseconds */
+#if defined(SID_REFTIMES)
+ 8,24,48,72,114,168,204,240,
+ 300,750,1500,2400,3000,9000,15000,24000
+#else
+ 8.91777693, 24.594051, 48.4185907, 73.0116639, 114.512475, 169.078356,
+ 205.199432, 240.551975,
+ 301.266125, 750.858245, 1501.71551, 2402.43682, 3001.89298, 9007.21405,
+ 15010.998, 24018.2111
+#endif
+};
+
+#ifdef SID_FPUENVE
+ static float attackRates[16];
+ static float decayReleaseRates[16];
+#elif defined(DIRECT_FIXPOINT)
+ static UINT32 attackRates[16];
+ static UINT32 decayReleaseRates[16];
+#else
+ static UINT32 attackRates[16];
+ static UINT32 attackRatesP[16];
+ static UINT32 decayReleaseRates[16];
+ static UINT32 decayReleaseRatesP[16];
+#endif
+
+const UINT32 attackTabLen = 255;
+static UINT32 releaseTabLen;
+static UINT32 releasePos[256];
+
+
+void enveEmuInit( UINT32 updateFreq, int measuredValues )
+{
+ UINT32 i, j, k;
+
+ releaseTabLen = sizeof(releaseTab);
+ for ( i = 0; i < 256; i++ )
+ {
+ j = 0;
+ while (( j < releaseTabLen ) && (releaseTab[j] > i) )
+ {
+ j++;
+ }
+ if ( j < releaseTabLen )
+ {
+ releasePos[i] = j;
+ }
+ else
+ {
+ releasePos[i] = releaseTabLen -1;
+ }
+ }
+
+ k = 0;
+ for ( i = 0; i < 16; i++ )
+ {
+ for ( j = 0; j < 256; j++ )
+ {
+ UINT16 tmpVol = j;
+ if (measuredValues)
+ {
+ tmpVol = (UINT16) ((293.0*(1-exp(j/-130.0)))+4.0);
+ if (j == 0)
+ tmpVol = 0;
+ if (tmpVol > 255)
+ tmpVol = 255;
+ }
+ /* Want the modulated volume value in the high byte. */
+ masterAmplModTable[k++] = ((tmpVol * masterVolumeLevels[i]) / 255) << 8;
+ }
+ }
+
+ for ( i = 0; i < 16; i++ )
+ {
+#ifdef SID_FPUENVE
+ double scaledenvelen = floor(( attackTimes[i] * updateFreq ) / 1000UL );
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ attackRates[i] = attackTabLen / scaledenvelen;
+
+ scaledenvelen = floor(( decayReleaseTimes[i] * updateFreq ) / 1000UL );
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ decayReleaseRates[i] = releaseTabLen / scaledenvelen;
+#elif defined(DIRECT_FIXPOINT)
+ UINT32 scaledenvelen = (UINT32)floor(( attackTimes[i] * updateFreq ) / 1000UL );
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ attackRates[i] = (attackTabLen << 16) / scaledenvelen;
+
+ scaledenvelen = (UINT32)floor(( decayReleaseTimes[i] * updateFreq ) / 1000UL );
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ decayReleaseRates[i] = (releaseTabLen << 16) / scaledenvelen;
+#else
+ UINT32 scaledenvelen = (UINT32)(/*floor*/(( attackTimes[i] * updateFreq ) / 1000UL ));
+
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ attackRates[i] = attackTabLen / scaledenvelen;
+ attackRatesP[i] = (( attackTabLen % scaledenvelen ) * 65536UL ) / scaledenvelen;
+
+ scaledenvelen = (UINT32)(/*floor*/(( decayReleaseTimes[i] * updateFreq ) / 1000UL ));
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ decayReleaseRates[i] = releaseTabLen / scaledenvelen;
+ decayReleaseRatesP[i] = (( releaseTabLen % scaledenvelen ) * 65536UL ) / scaledenvelen;
+#endif
+ }
+}
+
+/* Reset op. */
+
+void enveEmuResetOperator(sidOperator* pVoice)
+{
+ /* mute, end of R-phase */
+ pVoice->ADSRctrl = ENVE_MUTE;
+// pVoice->gateOnCtrl = (pVoice->gateOffCtrl = false);
+
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = (pVoice->fenveStepAdd = 0);
+ pVoice->enveStep = 0;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.l = (pVoice->enveStepAdd.l = 0);
+#else
+ pVoice->enveStep = (pVoice->enveStepPnt = 0);
+ pVoice->enveStepAdd = (pVoice->enveStepAddPnt = 0);
+#endif
+ pVoice->enveSusVol = 0;
+ pVoice->enveVol = 0;
+ pVoice->enveShortAttackCount = 0;
+}
+
+INLINE UINT16 enveEmuStartAttack(sidOperator*);
+INLINE UINT16 enveEmuStartDecay(sidOperator*);
+INLINE UINT16 enveEmuStartRelease(sidOperator*);
+INLINE UINT16 enveEmuAlterAttack(sidOperator*);
+INLINE UINT16 enveEmuAlterDecay(sidOperator*);
+INLINE UINT16 enveEmuAlterSustain(sidOperator*);
+INLINE UINT16 enveEmuAlterSustainDecay(sidOperator*);
+INLINE UINT16 enveEmuAlterRelease(sidOperator*);
+INLINE UINT16 enveEmuAttack(sidOperator*);
+INLINE UINT16 enveEmuDecay(sidOperator*);
+INLINE UINT16 enveEmuSustain(sidOperator*);
+INLINE UINT16 enveEmuSustainDecay(sidOperator*);
+INLINE UINT16 enveEmuRelease(sidOperator*);
+INLINE UINT16 enveEmuMute(sidOperator*);
+
+INLINE UINT16 enveEmuStartShortAttack(sidOperator*);
+INLINE UINT16 enveEmuAlterShortAttack(sidOperator*);
+INLINE UINT16 enveEmuShortAttack(sidOperator*);
+
+
+ptr2sidUwordFunc enveModeTable[] =
+{
+ /* 0 */
+ &enveEmuStartAttack, &enveEmuStartRelease,
+ &enveEmuAttack, &enveEmuDecay, &enveEmuSustain, &enveEmuRelease,
+ &enveEmuSustainDecay, &enveEmuMute,
+ /* 16 */
+ &enveEmuStartShortAttack,
+ &enveEmuMute, &enveEmuMute, &enveEmuMute,
+ &enveEmuMute, &enveEmuMute, &enveEmuMute, &enveEmuMute,
+ /* 32 */
+ &enveEmuStartAttack, &enveEmuStartRelease,
+ &enveEmuAlterAttack, &enveEmuAlterDecay, &enveEmuAlterSustain, &enveEmuAlterRelease,
+ &enveEmuAlterSustainDecay, &enveEmuMute,
+ /* 48 */
+ &enveEmuStartShortAttack,
+ &enveEmuMute, &enveEmuMute, &enveEmuMute,
+ &enveEmuMute, &enveEmuMute, &enveEmuMute, &enveEmuMute
+};
+
+/* Real-time functions. */
+/* Order is important because of inline optimizations. */
+/* */
+/* ADSRctrl is (index*2) to enveModeTable[], because of KEY-bit. */
+
+INLINE void enveEmuEnveAdvance(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->fenveStep += pVoice->fenveStepAdd;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.l += pVoice->enveStepAdd.l;
+#else
+ pVoice->enveStepPnt += pVoice->enveStepAddPnt;
+ pVoice->enveStep += pVoice->enveStepAdd + ( pVoice->enveStepPnt > 65535 );
+ pVoice->enveStepPnt &= 0xFFFF;
+#endif
+}
+
+/* */
+/* Mute/Idle. */
+/* */
+
+/* Only used in the beginning. */
+INLINE UINT16 enveEmuMute(sidOperator* pVoice)
+{
+ return 0;
+}
+
+/* */
+/* Release */
+/* */
+
+INLINE UINT16 enveEmuRelease(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ( pVoice->enveStep.w[HI] >= releaseTabLen )
+#else
+ if ( pVoice->enveStep >= releaseTabLen )
+#endif
+ {
+ pVoice->enveVol = releaseTab[releaseTabLen -1];
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+ else
+ {
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = releaseTab[pVoice->enveStep.w[HI]];
+#else
+ pVoice->enveVol = releaseTab[pVoice->enveStep];
+#endif
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+}
+
+INLINE UINT16 enveEmuAlterRelease(sidOperator* pVoice)
+{
+ UINT8 release = pVoice->SIDSR & 0x0F;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = decayReleaseRates[release];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = decayReleaseRates[release];
+#else
+ pVoice->enveStepAdd = decayReleaseRates[release];
+ pVoice->enveStepAddPnt = decayReleaseRatesP[release];
+#endif
+ pVoice->ADSRproc = &enveEmuRelease;
+ return enveEmuRelease(pVoice);
+}
+
+INLINE UINT16 enveEmuStartRelease(sidOperator* pVoice)
+{
+ pVoice->ADSRctrl = ENVE_RELEASE;
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = releasePos[pVoice->enveVol];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.w[HI] = releasePos[pVoice->enveVol];
+ pVoice->enveStep.w[LO] = 0;
+#else
+ pVoice->enveStep = releasePos[pVoice->enveVol];
+ pVoice->enveStepPnt = 0;
+#endif
+ return enveEmuAlterRelease(pVoice);
+}
+
+/* */
+/* Sustain */
+/* */
+
+INLINE UINT16 enveEmuSustain(sidOperator* pVoice)
+{
+ return masterAmplModTable[pVoice->sid->masterVolumeAmplIndex+pVoice->enveVol];
+}
+
+INLINE UINT16 enveEmuSustainDecay(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ( pVoice->enveStep.w[HI] >= releaseTabLen )
+#else
+ if ( pVoice->enveStep >= releaseTabLen )
+#endif
+ {
+ pVoice->enveVol = releaseTab[releaseTabLen-1];
+ return enveEmuAlterSustain(pVoice);
+ }
+ else
+ {
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = releaseTab[pVoice->enveStep.w[HI]];
+#else
+ pVoice->enveVol = releaseTab[pVoice->enveStep];
+#endif
+ /* Will be controlled from sidEmuSet2(). */
+ if ( pVoice->enveVol <= pVoice->enveSusVol )
+ {
+ pVoice->enveVol = pVoice->enveSusVol;
+ return enveEmuAlterSustain(pVoice);
+ }
+ else
+ {
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+ }
+}
+
+/* This is the same as enveEmuStartSustainDecay(). */
+INLINE UINT16 enveEmuAlterSustainDecay(sidOperator* pVoice)
+{
+ UINT8 decay = pVoice->SIDAD & 0x0F ;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = decayReleaseRates[decay];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = decayReleaseRates[decay];
+#else
+ pVoice->enveStepAdd = decayReleaseRates[decay];
+ pVoice->enveStepAddPnt = decayReleaseRatesP[decay];
+#endif
+ pVoice->ADSRproc = &enveEmuSustainDecay;
+ return enveEmuSustainDecay(pVoice);
+}
+
+/* This is the same as enveEmuStartSustain(). */
+INLINE UINT16 enveEmuAlterSustain(sidOperator* pVoice)
+{
+ if ( pVoice->enveVol > pVoice->enveSusVol )
+ {
+ pVoice->ADSRctrl = ENVE_SUSTAINDECAY;
+ pVoice->ADSRproc = &enveEmuSustainDecay;
+ return enveEmuAlterSustainDecay(pVoice);
+ }
+ else
+ {
+ pVoice->ADSRctrl = ENVE_SUSTAIN;
+ pVoice->ADSRproc = &enveEmuSustain;
+ return enveEmuSustain(pVoice);
+ }
+}
+
+/* */
+/* Decay */
+/* */
+
+INLINE UINT16 enveEmuDecay(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ( pVoice->enveStep.w[HI] >= releaseTabLen )
+#else
+ if ( pVoice->enveStep >= releaseTabLen )
+#endif
+ {
+ pVoice->enveVol = pVoice->enveSusVol;
+ return enveEmuAlterSustain(pVoice); /* start sustain */
+ }
+ else
+ {
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = releaseTab[pVoice->enveStep.w[HI]];
+#else
+ pVoice->enveVol = releaseTab[pVoice->enveStep];
+#endif
+ /* Will be controlled from sidEmuSet2(). */
+ if ( pVoice->enveVol <= pVoice->enveSusVol )
+ {
+ pVoice->enveVol = pVoice->enveSusVol;
+ return enveEmuAlterSustain(pVoice); /* start sustain */
+ }
+ else
+ {
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+ }
+}
+
+INLINE UINT16 enveEmuAlterDecay(sidOperator* pVoice)
+{
+ UINT8 decay = pVoice->SIDAD & 0x0F ;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = decayReleaseRates[decay];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = decayReleaseRates[decay];
+#else
+ pVoice->enveStepAdd = decayReleaseRates[decay];
+ pVoice->enveStepAddPnt = decayReleaseRatesP[decay];
+#endif
+ pVoice->ADSRproc = &enveEmuDecay;
+ return enveEmuDecay(pVoice);
+}
+
+INLINE UINT16 enveEmuStartDecay(sidOperator* pVoice)
+{
+ pVoice->ADSRctrl = ENVE_DECAY;
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = 0;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.l = 0;
+#else
+ pVoice->enveStep = (pVoice->enveStepPnt = 0);
+#endif
+ return enveEmuAlterDecay(pVoice);
+}
+
+/* */
+/* Attack */
+/* */
+
+INLINE UINT16 enveEmuAttack(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ( pVoice->enveStep.w[HI] > attackTabLen )
+#else
+ if ( pVoice->enveStep >= attackTabLen )
+#endif
+ return enveEmuStartDecay(pVoice);
+ else
+ {
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = pVoice->enveStep.w[HI];
+#else
+ pVoice->enveVol = pVoice->enveStep;
+#endif
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+}
+
+INLINE UINT16 enveEmuAlterAttack(sidOperator* pVoice)
+{
+ UINT8 attack = pVoice->SIDAD >> 4;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = attackRates[attack];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = attackRates[attack];
+#else
+ pVoice->enveStepAdd = attackRates[attack];
+ pVoice->enveStepAddPnt = attackRatesP[attack];
+#endif
+ pVoice->ADSRproc = &enveEmuAttack;
+ return enveEmuAttack(pVoice);
+}
+
+INLINE UINT16 enveEmuStartAttack(sidOperator* pVoice)
+{
+ pVoice->ADSRctrl = ENVE_ATTACK;
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = (float)pVoice->enveVol;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.w[HI] = pVoice->enveVol;
+ pVoice->enveStep.w[LO] = 0;
+#else
+ pVoice->enveStep = pVoice->enveVol;
+ pVoice->enveStepPnt = 0;
+#endif
+ return enveEmuAlterAttack(pVoice);
+}
+
+/* */
+/* Experimental. */
+/* */
+
+/*#include <iostream.h> */
+/*#include <iomanip.h> */
+
+INLINE UINT16 enveEmuShortAttack(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ((pVoice->enveStep.w[HI] > attackTabLen) ||
+ (pVoice->enveShortAttackCount == 0))
+#else
+ if ((pVoice->enveStep >= attackTabLen) ||
+ (pVoice->enveShortAttackCount == 0))
+#endif
+/* return enveEmuStartRelease(pVoice); */
+ return enveEmuStartDecay(pVoice);
+ else
+ {
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = pVoice->enveStep.w[HI];
+#else
+ pVoice->enveVol = pVoice->enveStep;
+#endif
+ pVoice->enveShortAttackCount--;
+/* cout << hex << pVoice->enveShortAttackCount << " / " << pVoice->enveVol << endl; */
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+}
+
+INLINE UINT16 enveEmuAlterShortAttack(sidOperator* pVoice)
+{
+ UINT8 attack = pVoice->SIDAD >> 4;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = attackRates[attack];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = attackRates[attack];
+#else
+ pVoice->enveStepAdd = attackRates[attack];
+ pVoice->enveStepAddPnt = attackRatesP[attack];
+#endif
+ pVoice->ADSRproc = &enveEmuShortAttack;
+ return enveEmuShortAttack(pVoice);
+}
+
+INLINE UINT16 enveEmuStartShortAttack(sidOperator* pVoice)
+{
+ pVoice->ADSRctrl = ENVE_SHORTATTACK;
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = (float)pVoice->enveVol;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.w[HI] = pVoice->enveVol;
+ pVoice->enveStep.w[LO] = 0;
+#else
+ pVoice->enveStep = pVoice->enveVol;
+ pVoice->enveStepPnt = 0;
+#endif
+ pVoice->enveShortAttackCount = 65535; /* unused */
+ return enveEmuAlterShortAttack(pVoice);
+}
diff --git a/src/emu/sound/sidenvel.h b/src/emu/sound/sidenvel.h
new file mode 100644
index 00000000000..8f0c83a1465
--- /dev/null
+++ b/src/emu/sound/sidenvel.h
@@ -0,0 +1,32 @@
+//
+// /home/ms/source/sidplay/libsidplay/emu/RCS/envelope.h,v
+//
+
+#ifndef ENVELOPE_H
+#define ENVELOPE_H
+
+
+extern void enveEmuInit(UINT32 updateFreq, int measuredValues);
+void enveEmuResetOperator(sidOperator* pVoice);
+
+
+extern ptr2sidUwordFunc enveModeTable[]; // -> envelope.cpp
+extern const UINT8 masterVolumeLevels[16]; // -> envelope.cpp
+
+static const UINT8 ENVE_STARTATTACK = 0;
+static const UINT8 ENVE_STARTRELEASE = 2;
+
+static const UINT8 ENVE_ATTACK = 4;
+static const UINT8 ENVE_DECAY = 6;
+static const UINT8 ENVE_SUSTAIN = 8;
+static const UINT8 ENVE_RELEASE = 10;
+static const UINT8 ENVE_SUSTAINDECAY = 12;
+static const UINT8 ENVE_MUTE = 14;
+
+static const UINT8 ENVE_STARTSHORTATTACK = 16;
+static const UINT8 ENVE_SHORTATTACK = 16;
+
+static const UINT8 ENVE_ALTER = 32;
+
+
+#endif
diff --git a/src/emu/sound/sidvoice.c b/src/emu/sound/sidvoice.c
new file mode 100644
index 00000000000..79568753758
--- /dev/null
+++ b/src/emu/sound/sidvoice.c
@@ -0,0 +1,819 @@
+#include <math.h>
+
+#include "sidvoice.h"
+#include "sid.h"
+#include "sidenvel.h"
+#include "sidw6581.h"
+#include "sidw8580.h"
+
+static UINT8 triangleTable[4096];
+static UINT8 sawtoothTable[4096];
+static UINT8 squareTable[2*4096];
+static UINT8* waveform30;
+static UINT8* waveform50;
+static UINT8* waveform60;
+static UINT8* waveform70;
+#if defined(LARGE_NOISE_TABLE)
+ static UINT8 noiseTableMSB[1<<8];
+ static UINT8 noiseTableLSB[1L<<16];
+#else
+ static UINT8 noiseTableMSB[1<<8];
+ static UINT8 noiseTableMID[1<<8];
+ static UINT8 noiseTableLSB[1<<8];
+#endif
+
+static INT8* ampMod1x8;
+
+static const UINT32 noiseSeed = 0x7ffff8;
+
+void sidInitMixerEngine(void)
+{
+ UINT16 uk;
+ INT32 si, sj ;
+
+ /* 8-bit volume modulation tables. */
+ float filterAmpl = 1.0;
+
+ filterAmpl = 0.7;
+
+ ampMod1x8=(INT8*) auto_malloc(256*256);
+
+ uk = 0;
+ for ( si = 0; si < 256; si++ )
+ {
+ for ( sj = -128; sj < 128; sj++, uk++ )
+ {
+ ampMod1x8[uk] = (INT8)(((si*sj)/255)*filterAmpl);
+ }
+ }
+
+}
+
+INLINE void waveAdvance(sidOperator* pVoice)
+{
+#if defined(DIRECT_FIXPOINT)
+ pVoice->waveStep.l += pVoice->waveStepAdd.l;
+ pVoice->waveStep.w[HI] &= 4095;
+#else
+ pVoice->waveStepPnt += pVoice->waveStepAddPnt;
+ pVoice->waveStep += pVoice->waveStepAdd;
+ if (pVoice->waveStepPnt > 65535 ) pVoice->waveStep++;
+ pVoice->waveStepPnt &= 0xFFFF;
+ pVoice->waveStep &= 4095;
+#endif
+}
+
+INLINE void noiseAdvance(sidOperator* pVoice)
+{
+ pVoice->noiseStep += pVoice->noiseStepAdd;
+ if (pVoice->noiseStep >= (1L<<20))
+ {
+ pVoice->noiseStep -= (1L<<20);
+#if defined(DIRECT_FIXPOINT)
+ pVoice->noiseReg.l = (pVoice->noiseReg.l << 1) |
+ (((pVoice->noiseReg.l >> 22) ^ (pVoice->noiseReg.l >> 17)) & 1);
+#else
+ pVoice->noiseReg = (pVoice->noiseReg << 1) |
+ (((pVoice->noiseReg >> 22) ^ (pVoice->noiseReg >> 17)) & 1);
+#endif
+#if defined(DIRECT_FIXPOINT) && defined(LARGE_NOISE_TABLE)
+ pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg.w[LO]]
+ |noiseTableMSB[pVoice->noiseReg.w[HI]&0xff]);
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg.b[LOLO]]
+ |noiseTableMID[pVoice->noiseReg.b[LOHI]]
+ |noiseTableMSB[pVoice->noiseReg.b[HILO]]);
+#else
+ pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg&0xff]
+ |noiseTableMID[pVoice->noiseReg>>8&0xff]
+ |noiseTableMSB[pVoice->noiseReg>>16&0xff]);
+#endif
+ }
+}
+
+INLINE void noiseAdvanceHp(sidOperator* pVoice)
+{
+ UINT32 tmp = pVoice->noiseStepAdd;
+ while (tmp >= (1L<<20))
+ {
+ tmp -= (1L<<20);
+#if defined(DIRECT_FIXPOINT)
+ pVoice->noiseReg.l = (pVoice->noiseReg.l << 1) |
+ (((pVoice->noiseReg.l >> 22) ^ (pVoice->noiseReg.l >> 17)) & 1);
+#else
+ pVoice->noiseReg = (pVoice->noiseReg << 1) |
+ (((pVoice->noiseReg >> 22) ^ (pVoice->noiseReg >> 17)) & 1);
+#endif
+ }
+ pVoice->noiseStep += tmp;
+ if (pVoice->noiseStep >= (1L<<20))
+ {
+ pVoice->noiseStep -= (1L<<20);
+#if defined(DIRECT_FIXPOINT)
+ pVoice->noiseReg.l = (pVoice->noiseReg.l << 1) |
+ (((pVoice->noiseReg.l >> 22) ^ (pVoice->noiseReg.l >> 17)) & 1);
+#else
+ pVoice->noiseReg = (pVoice->noiseReg << 1) |
+ (((pVoice->noiseReg >> 22) ^ (pVoice->noiseReg >> 17)) & 1);
+#endif
+ }
+#if defined(DIRECT_FIXPOINT) && defined(LARGE_NOISE_TABLE)
+ pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg.w[LO]]
+ |noiseTableMSB[pVoice->noiseReg.w[HI]&0xff]);
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg.b[LOLO]]
+ |noiseTableMID[pVoice->noiseReg.b[LOHI]]
+ |noiseTableMSB[pVoice->noiseReg.b[HILO]]);
+#else
+ pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg&0xff]
+ |noiseTableMID[pVoice->noiseReg>>8&0xff]
+ |noiseTableMSB[pVoice->noiseReg>>16&0xff]);
+#endif
+}
+
+
+#if defined(DIRECT_FIXPOINT)
+ #define triangle triangleTable[pVoice->waveStep.w[HI]]
+ #define sawtooth sawtoothTable[pVoice->waveStep.w[HI]]
+ #define square squareTable[pVoice->waveStep.w[HI] + pVoice->pulseIndex]
+ #define triSaw waveform30[pVoice->waveStep.w[HI]]
+ #define triSquare waveform50[pVoice->waveStep.w[HI] + pVoice->SIDpulseWidth]
+ #define sawSquare waveform60[pVoice->waveStep.w[HI] + pVoice->SIDpulseWidth]
+ #define triSawSquare waveform70[pVoice->waveStep.w[HI] + pVoice->SIDpulseWidth]
+#else
+ #define triangle triangleTable[pVoice->waveStep]
+ #define sawtooth sawtoothTable[pVoice->waveStep]
+ #define square squareTable[pVoice->waveStep + pVoice->pulseIndex]
+ #define triSaw waveform30[pVoice->waveStep]
+ #define triSquare waveform50[pVoice->waveStep + pVoice->SIDpulseWidth]
+ #define sawSquare waveform60[pVoice->waveStep + pVoice->SIDpulseWidth]
+ #define triSawSquare waveform70[pVoice->waveStep + pVoice->SIDpulseWidth]
+#endif
+
+
+static void sidMode00(sidOperator* pVoice) {
+ pVoice->output = (pVoice->filtIO-0x80);
+ waveAdvance(pVoice);
+}
+
+#if 0
+/* not used */
+static void sidModeReal00(sidOperator* pVoice) {
+ pVoice->output = 0;
+ waveAdvance(pVoice);
+}
+#endif
+
+static void sidMode10(sidOperator* pVoice) {
+ pVoice->output = triangle;
+ waveAdvance(pVoice);
+}
+
+static void sidMode20(sidOperator* pVoice) {
+ pVoice->output = sawtooth;
+ waveAdvance(pVoice);
+}
+
+static void sidMode30(sidOperator* pVoice) {
+ pVoice->output = triSaw;
+ waveAdvance(pVoice);
+}
+
+static void sidMode40(sidOperator* pVoice) {
+ pVoice->output = square;
+ waveAdvance(pVoice);
+}
+
+static void sidMode50(sidOperator* pVoice) {
+ pVoice->output = triSquare;
+ waveAdvance(pVoice);
+}
+
+static void sidMode60(sidOperator* pVoice) {
+ pVoice->output = sawSquare;
+ waveAdvance(pVoice);
+}
+
+static void sidMode70(sidOperator* pVoice) {
+ pVoice->output = triSawSquare;
+ waveAdvance(pVoice);
+}
+
+static void sidMode80(sidOperator* pVoice) {
+ pVoice->output = pVoice->noiseOutput;
+ waveAdvance(pVoice);
+ noiseAdvance(pVoice);
+}
+
+static void sidMode80hp(sidOperator* pVoice) {
+ pVoice->output = pVoice->noiseOutput;
+ waveAdvance(pVoice);
+ noiseAdvanceHp(pVoice);
+}
+
+static void sidModeLock(sidOperator* pVoice)
+{
+ pVoice->noiseIsLocked = TRUE;
+ pVoice->output = (pVoice->filtIO-0x80);
+ waveAdvance(pVoice);
+}
+
+/* */
+/* */
+/* */
+
+static void sidMode14(sidOperator* pVoice)
+{
+#if defined(DIRECT_FIXPOINT)
+ if ( pVoice->modulator->waveStep.w[HI] < 2048 )
+#else
+ if ( pVoice->modulator->waveStep < 2048 )
+#endif
+ pVoice->output = triangle;
+ else
+ pVoice->output = 0xFF ^ triangle;
+ waveAdvance(pVoice);
+}
+
+static void sidMode34(sidOperator* pVoice) {
+#if defined(DIRECT_FIXPOINT)
+ if ( pVoice->modulator->waveStep.w[HI] < 2048 )
+#else
+ if ( pVoice->modulator->waveStep < 2048 )
+#endif
+ pVoice->output = triSaw;
+ else
+ pVoice->output = 0xFF ^ triSaw;
+ waveAdvance(pVoice);
+}
+
+static void sidMode54(sidOperator* pVoice) {
+#if defined(DIRECT_FIXPOINT)
+ if ( pVoice->modulator->waveStep.w[HI] < 2048 )
+#else
+ if ( pVoice->modulator->waveStep < 2048 )
+#endif
+ pVoice->output = triSquare;
+ else
+ pVoice->output = 0xFF ^ triSquare;
+ waveAdvance(pVoice);
+}
+
+static void sidMode74(sidOperator* pVoice) {
+#if defined(DIRECT_FIXPOINT)
+ if ( pVoice->modulator->waveStep.w[HI] < 2048 )
+#else
+ if ( pVoice->modulator->waveStep < 2048 )
+#endif
+ pVoice->output = triSawSquare;
+ else
+ pVoice->output = 0xFF ^ triSawSquare;
+ waveAdvance(pVoice);
+}
+
+/* */
+/* */
+/* */
+
+INLINE void waveCalcCycleLen(sidOperator* pVoice)
+{
+#if defined(DIRECT_FIXPOINT)
+ pVoice->cycleAddLen.w[HI] = 0;
+ pVoice->cycleAddLen.l += pVoice->cycleLen.l;
+ pVoice->cycleLenCount = pVoice->cycleAddLen.w[HI];
+#else
+ pVoice->cycleAddLenPnt += pVoice->cycleLenPnt;
+ pVoice->cycleLenCount = pVoice->cycleLen;
+ if ( pVoice->cycleAddLenPnt > 65535 ) pVoice->cycleLenCount++;
+ pVoice->cycleAddLenPnt &= 0xFFFF;
+#endif
+ /* If we keep the value cycleLen between 1 <= x <= 65535, */
+ /* the following check is not required. */
+/* if ( pVoice->cycleLenCount == 0 ) */
+/* { */
+/*#if defined(DIRECT_FIXPOINT) */
+/* pVoice->waveStep.l = 0; */
+/*#else */
+/* pVoice->waveStep = (pVoice->waveStepPnt = 0); */
+/*#endif */
+/* pVoice->cycleLenCount = 0; */
+/* } */
+/* else */
+ {
+#if defined(DIRECT_FIXPOINT)
+ register UINT16 diff = pVoice->cycleLenCount - pVoice->cycleLen.w[HI];
+#else
+ register UINT16 diff = pVoice->cycleLenCount - pVoice->cycleLen;
+#endif
+ if ( pVoice->wavePre[diff].len != pVoice->cycleLenCount )
+ {
+ pVoice->wavePre[diff].len = pVoice->cycleLenCount;
+#if defined(DIRECT_FIXPOINT)
+ pVoice->wavePre[diff].stp = (pVoice->waveStepAdd.l = (4096UL*65536UL) / pVoice->cycleLenCount);
+#else
+ pVoice->wavePre[diff].stp = (pVoice->waveStepAdd = 4096UL / pVoice->cycleLenCount);
+ pVoice->wavePre[diff].pnt = (pVoice->waveStepAddPnt = ((4096UL % pVoice->cycleLenCount) * 65536UL) / pVoice->cycleLenCount);
+#endif
+ }
+ else
+ {
+#if defined(DIRECT_FIXPOINT)
+ pVoice->waveStepAdd.l = pVoice->wavePre[diff].stp;
+#else
+ pVoice->waveStepAdd = pVoice->wavePre[diff].stp;
+ pVoice->waveStepAddPnt = pVoice->wavePre[diff].pnt;
+#endif
+ }
+ } /* see above (opening bracket) */
+}
+
+INLINE void waveCalcFilter(sidOperator* pVoice)
+{
+ if ( pVoice->filtEnabled )
+ {
+ if ( pVoice->sid->filter.Type != 0 )
+ {
+ if ( pVoice->sid->filter.Type == 0x20 )
+ {
+ float tmp;
+ pVoice->filtLow += ( pVoice->filtRef * pVoice->sid->filter.Dy );
+ tmp = (float)pVoice->filtIO - pVoice->filtLow;
+ tmp -= pVoice->filtRef * pVoice->sid->filter.ResDy;
+ pVoice->filtRef += ( tmp * (pVoice->sid->filter.Dy) );
+ pVoice->filtIO = (INT8)(pVoice->filtRef-pVoice->filtLow/4);
+ }
+ else if (pVoice->sid->filter.Type == 0x40)
+ {
+ float tmp, tmp2;
+ pVoice->filtLow += ( pVoice->filtRef * pVoice->sid->filter.Dy * 0.1 );
+ tmp = (float)pVoice->filtIO - pVoice->filtLow;
+ tmp -= pVoice->filtRef * pVoice->sid->filter.ResDy;
+ pVoice->filtRef += ( tmp * (pVoice->sid->filter.Dy) );
+ tmp2 = pVoice->filtRef - pVoice->filtIO/8;
+ if (tmp2 < -128)
+ tmp2 = -128;
+ if (tmp2 > 127)
+ tmp2 = 127;
+ pVoice->filtIO = (INT8)tmp2;
+ }
+ else
+ {
+ float sample, sample2;
+ int tmp;
+ pVoice->filtLow += ( pVoice->filtRef * pVoice->sid->filter.Dy );
+ sample = pVoice->filtIO;
+ sample2 = sample - pVoice->filtLow;
+ tmp = (int)sample2;
+ sample2 -= pVoice->filtRef * pVoice->sid->filter.ResDy;
+ pVoice->filtRef += ( sample2 * pVoice->sid->filter.Dy );
+
+ if ( pVoice->sid->filter.Type == 0x10 )
+ {
+ pVoice->filtIO = (INT8)pVoice->filtLow;
+ }
+ else if ( pVoice->sid->filter.Type == 0x30 )
+ {
+ pVoice->filtIO = (INT8)pVoice->filtLow;
+ }
+ else if ( pVoice->sid->filter.Type == 0x50 )
+ {
+ pVoice->filtIO = (INT8)(sample - (tmp >> 1));
+ }
+ else if ( pVoice->sid->filter.Type == 0x60 )
+ {
+ pVoice->filtIO = (INT8)tmp;
+ }
+ else if ( pVoice->sid->filter.Type == 0x70 )
+ {
+ pVoice->filtIO = (INT8)(sample - (tmp >> 1));
+ }
+ }
+ }
+ else /* pVoice->sid->filter.Type == 0x00 */
+ {
+ pVoice->filtIO = 0;
+ }
+ }
+}
+
+static INT8 waveCalcMute(sidOperator* pVoice)
+{
+ (*pVoice->ADSRproc)(pVoice); /* just process envelope */
+ return pVoice->filtIO;//&pVoice->outputMask;
+}
+
+
+INT8 sidWaveCalcNormal(sidOperator* pVoice)
+{
+ if ( pVoice->cycleLenCount <= 0 )
+ {
+ waveCalcCycleLen(pVoice);
+ if (( pVoice->SIDctrl & 0x40 ) == 0x40 )
+ {
+ pVoice->pulseIndex = pVoice->newPulseIndex;
+ if ( pVoice->pulseIndex > 2048 )
+ {
+#if defined(DIRECT_FIXPOINT)
+ pVoice->waveStep.w[HI] = 0;
+#else
+ pVoice->waveStep = 0;
+#endif
+ }
+ }
+ }
+ (*pVoice->waveProc)(pVoice);
+ pVoice->filtIO = ampMod1x8[(*pVoice->ADSRproc)(pVoice)|pVoice->output];
+// pVoice->filtIO = pVoice->sid->masterVolume; // test for digi sound
+ waveCalcFilter(pVoice);
+ return pVoice->filtIO;//&pVoice->outputMask;
+}
+
+
+static INT8 waveCalcRangeCheck(sidOperator* pVoice)
+{
+#if defined(DIRECT_FIXPOINT)
+ pVoice->waveStepOld = pVoice->waveStep.w[HI];
+ (*pVoice->waveProc)(pVoice);
+ if (pVoice->waveStep.w[HI] < pVoice->waveStepOld)
+#else
+ pVoice->waveStepOld = pVoice->waveStep;
+ (*pVoice->waveProc)(pVoice);
+ if (pVoice->waveStep < pVoice->waveStepOld)
+#endif
+ {
+ /* Next step switch back to normal calculation. */
+ pVoice->cycleLenCount = 0;
+ pVoice->outProc = &sidWaveCalcNormal;
+#if defined(DIRECT_FIXPOINT)
+ pVoice->waveStep.w[HI] = 4095;
+#else
+ pVoice->waveStep = 4095;
+#endif
+ }
+ pVoice->filtIO = ampMod1x8[(*pVoice->ADSRproc)(pVoice)|pVoice->output];
+ waveCalcFilter(pVoice);
+ return pVoice->filtIO;//&pVoice->outputMask;
+}
+
+/* -------------------------------------------------- Operator frame set-up 1 */
+
+void sidEmuSet(sidOperator* pVoice)
+{
+ UINT8 enveTemp, newWave, oldWave;
+ UINT8 ADtemp;
+ UINT8 SRtemp;
+ UINT8 tmpSusVol;
+
+ pVoice->SIDfreq = pVoice->reg[0]|(pVoice->reg[1]<<8);
+
+ pVoice->SIDpulseWidth = (pVoice->reg[2]|(pVoice->reg[3]<<8)) & 0x0FFF;
+ pVoice->newPulseIndex = 4096 - pVoice->SIDpulseWidth;
+#if defined(DIRECT_FIXPOINT)
+ if ( ((pVoice->waveStep.w[HI] + pVoice->pulseIndex) >= 0x1000)
+ && ((pVoice->waveStep.w[HI] + pVoice->newPulseIndex) >= 0x1000) )
+ {
+ pVoice->pulseIndex = pVoice->newPulseIndex;
+ }
+ else if ( ((pVoice->waveStep.w[HI] + pVoice->pulseIndex) < 0x1000)
+ && ((pVoice->waveStep.w[HI] + pVoice->newPulseIndex) < 0x1000) )
+ {
+ pVoice->pulseIndex = pVoice->newPulseIndex;
+ }
+#else
+ if ( ((pVoice->waveStep + pVoice->pulseIndex) >= 0x1000)
+ && ((pVoice->waveStep + pVoice->newPulseIndex) >= 0x1000) )
+ {
+ pVoice->pulseIndex = pVoice->newPulseIndex;
+ }
+ else if ( ((pVoice->waveStep + pVoice->pulseIndex) < 0x1000)
+ && ((pVoice->waveStep + pVoice->newPulseIndex) < 0x1000) )
+ {
+ pVoice->pulseIndex = pVoice->newPulseIndex;
+ }
+#endif
+
+
+ oldWave = pVoice->SIDctrl;
+ enveTemp = pVoice->ADSRctrl;
+ pVoice->SIDctrl = (newWave = pVoice->reg[4]|(pVoice->reg[5]<<8));
+
+ if (( newWave & 1 ) ==0 )
+ {
+ if (( oldWave & 1 ) !=0 )
+ enveTemp = ENVE_STARTRELEASE;
+/* else if ( pVoice->gateOnCtrl ) */
+/* { */
+/* enveTemp = ENVE_STARTSHORTATTACK; */
+/* } */
+ }
+ else if ( /*pVoice->gateOffCtrl || */((oldWave&1)==0) )
+ {
+ enveTemp = ENVE_STARTATTACK;
+ }
+
+ if ((( oldWave ^ newWave ) & 0xF0 ) != 0 )
+ {
+ pVoice->cycleLenCount = 0;
+ }
+
+ ADtemp = pVoice->reg[5];
+ SRtemp = pVoice->reg[6];
+ if ( pVoice->SIDAD != ADtemp )
+ {
+ enveTemp |= ENVE_ALTER;
+ }
+ else if ( pVoice->SIDSR != SRtemp )
+ {
+ enveTemp |= ENVE_ALTER;
+ }
+ pVoice->SIDAD = ADtemp;
+ pVoice->SIDSR = SRtemp;
+ tmpSusVol = masterVolumeLevels[SRtemp >> 4];
+ if (pVoice->ADSRctrl != ENVE_SUSTAIN) /* !!! */
+ {
+ pVoice->enveSusVol = tmpSusVol;
+ }
+ else
+ {
+ if ( pVoice->enveSusVol > pVoice->enveVol )
+ pVoice->enveSusVol = 0;
+ else
+ pVoice->enveSusVol = tmpSusVol;
+ }
+
+ pVoice->ADSRproc = enveModeTable[enveTemp>>1]; /* shifting out the KEY-bit */
+ pVoice->ADSRctrl = enveTemp & (255-ENVE_ALTER-1);
+
+ pVoice->filtEnabled = pVoice->sid->filter.Enabled &&
+ ((pVoice->sid->reg[0x17] & pVoice->filtVoiceMask)!=0);
+}
+
+/* -------------------------------------------------- Operator frame set-up 2 */
+
+/* MOS-8580, MOS-6581 (no 70) */
+static ptr2sidVoidFunc sidModeNormalTable[16] =
+{
+ sidMode00, sidMode10, sidMode20, sidMode30, sidMode40, sidMode50, sidMode60, sidMode70,
+ sidMode80, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock
+};
+
+/* MOS-8580, MOS-6581 (no 74) */
+static ptr2sidVoidFunc sidModeRingTable[16] =
+{
+ sidMode00, sidMode14, sidMode00, sidMode34, sidMode00, sidMode54, sidMode00, sidMode74,
+ sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock
+};
+
+void sidClearOperator( sidOperator* pVoice )
+{
+ pVoice->SIDfreq = 0;
+ pVoice->SIDctrl = 0;
+ pVoice->SIDAD = 0;
+ pVoice->SIDSR = 0;
+
+ pVoice->sync = FALSE;
+
+ pVoice->pulseIndex = (pVoice->newPulseIndex = (pVoice->SIDpulseWidth = 0));
+ pVoice->curSIDfreq = (pVoice->curNoiseFreq = 0);
+
+ pVoice->output = (pVoice->noiseOutput = 0);
+ pVoice->filtIO = 0;
+
+ pVoice->filtEnabled = FALSE;
+ pVoice->filtLow = (pVoice->filtRef = 0);
+
+ pVoice->cycleLenCount = 0;
+#if defined(DIRECT_FIXPOINT)
+ pVoice->cycleLen.l = (pVoice->cycleAddLen.l = 0);
+#else
+ pVoice->cycleLen = (pVoice->cycleLenPnt = 0);
+ pVoice->cycleAddLenPnt = 0;
+#endif
+
+ pVoice->outProc = waveCalcMute;
+
+#if defined(DIRECT_FIXPOINT)
+ pVoice->waveStepAdd.l = (pVoice->waveStep.l = 0);
+ pVoice->wavePre[0].len = (pVoice->wavePre[0].stp = 0);
+ pVoice->wavePre[1].len = (pVoice->wavePre[1].stp = 0);
+#else
+ pVoice->waveStepAdd = (pVoice->waveStepAddPnt = 0);
+ pVoice->waveStep = (pVoice->waveStepPnt = 0);
+ pVoice->wavePre[0].len = 0;
+ pVoice->wavePre[0].stp = (pVoice->wavePre[0].pnt = 0);
+ pVoice->wavePre[1].len = 0;
+ pVoice->wavePre[1].stp = (pVoice->wavePre[1].pnt = 0);
+#endif
+ pVoice->waveStepOld = 0;
+
+#if defined(DIRECT_FIXPOINT)
+ pVoice->noiseReg.l = noiseSeed;
+#else
+ pVoice->noiseReg = noiseSeed;
+#endif
+ pVoice->noiseStepAdd = (pVoice->noiseStep = 0);
+ pVoice->noiseIsLocked = FALSE;
+}
+
+void sidEmuSet2(sidOperator* pVoice)
+{
+ pVoice->outProc = &sidWaveCalcNormal;
+ pVoice->sync = FALSE;
+
+ if ( (pVoice->SIDfreq < 16) || ((pVoice->SIDctrl & 8) != 0) )
+// if ( /*(pVoice->SIDfreq < 16) || */((pVoice->SIDctrl & 8) != 0) )
+ {
+ pVoice->outProc = waveCalcMute;
+ if (pVoice->SIDfreq == 0)
+ {
+#if defined(DIRECT_FIXPOINT)
+ pVoice->cycleLen.l = (pVoice->cycleAddLen.l = 0);
+ pVoice->waveStep.l = 0;
+#else
+ pVoice->cycleLen = (pVoice->cycleLenPnt = 0);
+ pVoice->cycleAddLenPnt = 0;
+ pVoice->waveStep = 0;
+ pVoice->waveStepPnt = 0;
+#endif
+ pVoice->curSIDfreq = (pVoice->curNoiseFreq = 0);
+ pVoice->noiseStepAdd = 0;
+ pVoice->cycleLenCount = 0;
+ }
+ if ((pVoice->SIDctrl & 8) != 0)
+ {
+ if (pVoice->noiseIsLocked)
+ {
+ pVoice->noiseIsLocked = FALSE;
+#if defined(DIRECT_FIXPOINT)
+ pVoice->noiseReg.l = noiseSeed;
+#else
+ pVoice->noiseReg = noiseSeed;
+#endif
+ }
+ }
+ }
+ else
+ {
+ if ( pVoice->curSIDfreq != pVoice->SIDfreq )
+ {
+ pVoice->curSIDfreq = pVoice->SIDfreq;
+ /* We keep the value cycleLen between 1 <= x <= 65535. */
+ /* This makes a range-check in waveCalcCycleLen() unrequired. */
+#if defined(DIRECT_FIXPOINT)
+ pVoice->cycleLen.l = ((pVoice->sid->PCMsid << 12) / pVoice->SIDfreq) << 4;
+ if (pVoice->cycleLenCount > 0)
+ {
+ waveCalcCycleLen(pVoice);
+ pVoice->outProc = &waveCalcRangeCheck;
+ }
+#else
+ pVoice->cycleLen = pVoice->sid->PCMsid / pVoice->SIDfreq;
+ pVoice->cycleLenPnt = (( pVoice->sid->PCMsid % pVoice->SIDfreq ) * 65536UL ) / pVoice->SIDfreq;
+ if (pVoice->cycleLenCount > 0)
+ {
+ waveCalcCycleLen(pVoice);
+ pVoice->outProc = &waveCalcRangeCheck;
+ }
+#endif
+ }
+
+ if ((( pVoice->SIDctrl & 0x80 ) == 0x80 ) && ( pVoice->curNoiseFreq != pVoice->SIDfreq ))
+ {
+ pVoice->curNoiseFreq = pVoice->SIDfreq;
+ pVoice->noiseStepAdd = (pVoice->sid->PCMsidNoise * pVoice->SIDfreq) >> 8;
+ if (pVoice->noiseStepAdd >= (1L<<21))
+ sidModeNormalTable[8] = sidMode80hp;
+ else
+ sidModeNormalTable[8] = sidMode80;
+ }
+
+ if (( pVoice->SIDctrl & 2 ) != 0 )
+ {
+ if ( ( pVoice->modulator->SIDfreq == 0 ) || (( pVoice->modulator->SIDctrl & 8 ) != 0 ) )
+ {
+ ;
+ }
+ else if ( (( pVoice->carrier->SIDctrl & 2 ) != 0 ) &&
+ ( pVoice->modulator->SIDfreq >= ( pVoice->SIDfreq << 1 )) )
+ {
+ ;
+ }
+ else
+ {
+ pVoice->sync = TRUE;
+ }
+ }
+
+ if ((( pVoice->SIDctrl & 0x14 ) == 0x14 ) && ( pVoice->modulator->SIDfreq != 0 ))
+ pVoice->waveProc = sidModeRingTable[pVoice->SIDctrl >> 4];
+ else
+ pVoice->waveProc = sidModeNormalTable[pVoice->SIDctrl >> 4];
+ }
+}
+
+void sidInitWaveformTables(SIDTYPE type)
+{
+ int i,j;
+ UINT16 k;
+
+ k = 0;
+ for ( i = 0; i < 256; i++ )
+ for ( j = 0; j < 8; j++ )
+ triangleTable[k++] = i;
+ for ( i = 255; i >= 0; i-- )
+ for ( j = 0; j < 8; j++ )
+ triangleTable[k++] = i;
+
+ k = 0;
+ for ( i = 0; i < 256; i++ )
+ for ( j = 0; j < 16; j++ )
+ sawtoothTable[k++] = i;
+
+ k = 0;
+ for ( i = 0; i < 4096; i++ )
+ squareTable[k++] = 255; //0; my estimation; especial for digi sound
+ for ( i = 0; i < 4096; i++ )
+ squareTable[k++] = 0; //255;
+
+ if ( type==MOS8580 )
+ {
+ waveform30 = waveform30_8580;
+ waveform50 = waveform50_8580;
+ waveform60 = waveform60_8580;
+ waveform70 = waveform70_8580;
+ }
+ else
+ {
+ waveform30 = waveform30_6581;
+ waveform50 = waveform50_6581;
+ waveform60 = waveform60_6581;
+ waveform70 = waveform70_6581; /* really audible? */
+ }
+
+ for ( i = 4096; i < 8192; i++ )
+ {
+ waveform50[i] = 0;
+ waveform60[i] = 0;
+ waveform70[i] = 0;
+ }
+
+ if ( type==MOS8580 )
+ {
+ sidModeNormalTable[3] = sidMode30;
+ sidModeNormalTable[6] = sidMode60;
+ sidModeNormalTable[7] = sidMode70;
+ sidModeRingTable[7] = sidMode74;
+ }
+ else
+ {
+ sidModeNormalTable[3] = sidMode30;
+ sidModeNormalTable[6] = sidMode60;
+ sidModeNormalTable[7] = sidMode00; /* really audible? */
+ sidModeRingTable[7] = sidMode00; /* */
+ }
+
+ {
+#if defined(LARGE_NOISE_TABLE)
+ UINT32 ni;
+ for (ni = 0; ni < sizeof(noiseTableLSB); ni++)
+ {
+ noiseTableLSB[ni] = (UINT8)
+ (((ni >> (13-4)) & 0x10) |
+ ((ni >> (11-3)) & 0x08) |
+ ((ni >> (7-2)) & 0x04) |
+ ((ni >> (4-1)) & 0x02) |
+ ((ni >> (2-0)) & 0x01));
+ }
+ for (ni = 0; ni < sizeof(noiseTableMSB); ni++)
+ {
+ noiseTableMSB[ni] = (UINT8)
+ (((ni << (7-(22-16))) & 0x80) |
+ ((ni << (6-(20-16))) & 0x40) |
+ ((ni << (5-(16-16))) & 0x20));
+ }
+#else
+ UINT32 ni;
+ for (ni = 0; ni < sizeof(noiseTableLSB); ni++)
+ {
+ noiseTableLSB[ni] = (UINT8)
+ (((ni >> (7-2)) & 0x04) |
+ ((ni >> (4-1)) & 0x02) |
+ ((ni >> (2-0)) & 0x01));
+ }
+ for (ni = 0; ni < sizeof(noiseTableMID); ni++)
+ {
+ noiseTableMID[ni] = (UINT8)
+ (((ni >> (13-8-4)) & 0x10) |
+ ((ni << (3-(11-8))) & 0x08));
+ }
+ for (ni = 0; ni < sizeof(noiseTableMSB); ni++)
+ {
+ noiseTableMSB[ni] = (UINT8)
+ (((ni << (7-(22-16))) & 0x80) |
+ ((ni << (6-(20-16))) & 0x40) |
+ ((ni << (5-(16-16))) & 0x20));
+ }
+#endif
+ }
+}
+
diff --git a/src/emu/sound/sidvoice.h b/src/emu/sound/sidvoice.h
new file mode 100644
index 00000000000..682502cd15f
--- /dev/null
+++ b/src/emu/sound/sidvoice.h
@@ -0,0 +1,117 @@
+#ifndef __SIDVOICE_H_
+#define __SIDVOICE_H_
+
+#include "sndintrf.h"
+
+/*
+ approximation of the sid6581 chip
+ this part is for 1 (of the 3) voices of a chip
+*/
+#include "sound/sid6581.h"
+
+struct sw_storage
+{
+ UINT16 len;
+#if defined(DIRECT_FIXPOINT)
+ UINT32 stp;
+#else
+ UINT32 pnt;
+ INT16 stp;
+#endif
+};
+
+struct _SID6581;
+
+typedef struct _sidOperator
+{
+ struct _SID6581 *sid;
+ UINT8 reg[7];
+ UINT32 SIDfreq;
+ UINT16 SIDpulseWidth;
+ UINT8 SIDctrl;
+ UINT8 SIDAD, SIDSR;
+
+ struct _sidOperator* carrier;
+ struct _sidOperator* modulator;
+ int sync;
+
+ UINT16 pulseIndex, newPulseIndex;
+ UINT16 curSIDfreq;
+ UINT16 curNoiseFreq;
+
+ UINT8 output;//, outputMask;
+
+ char filtVoiceMask;
+ int filtEnabled;
+ float filtLow, filtRef;
+ INT8 filtIO;
+
+ INT32 cycleLenCount;
+#if defined(DIRECT_FIXPOINT)
+ cpuLword cycleLen, cycleAddLen;
+#else
+ UINT32 cycleAddLenPnt;
+ UINT16 cycleLen, cycleLenPnt;
+#endif
+
+ INT8(*outProc)(struct _sidOperator *);
+ void(*waveProc)(struct _sidOperator *);
+
+#if defined(DIRECT_FIXPOINT)
+ cpuLword waveStep, waveStepAdd;
+#else
+ UINT16 waveStep, waveStepAdd;
+ UINT32 waveStepPnt, waveStepAddPnt;
+#endif
+ UINT16 waveStepOld;
+ struct sw_storage wavePre[2];
+
+#if defined(DIRECT_FIXPOINT) && defined(LARGE_NOISE_TABLE)
+ cpuLword noiseReg;
+#elif defined(DIRECT_FIXPOINT)
+ cpuLBword noiseReg;
+#else
+ UINT32 noiseReg;
+#endif
+ UINT32 noiseStep, noiseStepAdd;
+ UINT8 noiseOutput;
+ int noiseIsLocked;
+
+ UINT8 ADSRctrl;
+// int gateOnCtrl, gateOffCtrl;
+ UINT16 (*ADSRproc)(struct _sidOperator *);
+
+#ifdef SID_FPUENVE
+ float fenveStep, fenveStepAdd;
+ UINT32 enveStep;
+#elif defined(DIRECT_FIXPOINT)
+ cpuLword enveStep, enveStepAdd;
+#else
+ UINT16 enveStep, enveStepAdd;
+ UINT32 enveStepPnt, enveStepAddPnt;
+#endif
+ UINT8 enveVol, enveSusVol;
+ UINT16 enveShortAttackCount;
+} sidOperator;
+
+typedef INT8 (*ptr2sidFunc)(sidOperator *);
+typedef UINT16 (*ptr2sidUwordFunc)(sidOperator *);
+typedef void (*ptr2sidVoidFunc)(sidOperator *);
+
+void sidClearOperator( sidOperator* pVoice );
+
+void sidEmuSet(sidOperator* pVoice);
+void sidEmuSet2(sidOperator* pVoice);
+INT8 sidWaveCalcNormal(sidOperator* pVoice);
+
+void sidInitWaveformTables(SIDTYPE type);
+void sidInitMixerEngine(void);
+
+#if 0
+extern ptr2sidVoidFunc sid6581ModeNormalTable[16];
+extern ptr2sidVoidFunc sid6581ModeRingTable[16];
+extern ptr2sidVoidFunc sid8580ModeNormalTable[16];
+extern ptr2sidVoidFunc sid8580ModeRingTable[16];
+#endif
+
+#endif
diff --git a/src/emu/sound/sidw6581.h b/src/emu/sound/sidw6581.h
new file mode 100644
index 00000000000..c18445a3f10
--- /dev/null
+++ b/src/emu/sound/sidw6581.h
@@ -0,0 +1,1051 @@
+#ifndef WAVE6581_h
+#define WAVE6581_h
+
+/*
+ * MOS-6581 R1, R3, R4
+ *
+ * Read-out combined waveforms taken from reSID 0.5.
+ * Copyright (C) 1998 Dag Lem <resid@nimrod.no>
+ */
+
+static UINT8 waveform30_6581[4096] =
+{
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xf,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x1e,0x1f,0x1f,0x3f,0x3f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf,0x1f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,
+ 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3e,0x3e,0x3f,0x3f,0x7f,0x7f,0x7f,0x7f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xf,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x1e,0x1f,0x1f,0x3f,0x3f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf,0x1f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,
+ 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3e,0x3e,0x3f,0x3f,0x7f,0x7f,0x7f,0x7f
+};
+
+static UINT8 waveform50_6581[4096+4096] =
+{
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x20,0x38,0x3f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x40,0x5f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x6f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x70,0x77,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x70,0x40,0x70,0x70,0x7b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x70, 0x0,0x40,0x40,0x70,0x60,0x70,0x78,0x7d,
+ 0x0,0x40,0x60,0x78,0x60,0x78,0x78,0x7e,0x70,0x7c,0x7c,0x7f,0x7e,0x7f,0x7f,0x7f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80,0x80,0x80,0x80,0x9f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0x80,0x80,0xa0,0xa0,0xaf,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,0x80,0x80,
+ 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xa0, 0x0,0x80,0x80,0xa0,0x80,0xa0,0xb0,0xb7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xa0,
+ 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xa0, 0x0,0x80,0x80,0xa0,0x80,0xb0,0xb0,0xbb,
+ 0x0, 0x0, 0x0,0x80,0x80,0x80,0x80,0xb0,0x80,0x80,0x80,0xb0,0x80,0xb0,0xb8,0xbd,
+ 0x80,0x80,0x80,0xb8,0xa0,0xb8,0xb8,0xbe,0xa0,0xb8,0xbc,0xbf,0xbe,0xbf,0xbf,0xbf,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0xc0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,0x80,0xc0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0,
+ 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0, 0x0,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xcf,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0,
+ 0x0, 0x0, 0x0,0x80, 0x0,0x80,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xd7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80,0x80,0x80,0xc0,0xc0,
+ 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xd0,0xd0,0xdb,
+ 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xd0,0x80,0xc0,0xc0,0xd0,0xc0,0xd0,0xd8,0xdd,
+ 0xc0,0xc0,0xc0,0xd0,0xc0,0xd8,0xd8,0xde,0xc0,0xd8,0xdc,0xdf,0xdc,0xdf,0xdf,0xdf,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80,0x80,0xc0,0xc0,0xe0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xe0,
+ 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xe0,0x80,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe7,
+ 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0, 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xe0,
+ 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xeb,
+ 0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xed,
+ 0xc0,0xe0,0xe0,0xe0,0xe0,0xe8,0xe8,0xee,0xe0,0xe8,0xec,0xef,0xec,0xef,0xef,0xef,
+ 0x0, 0x0, 0x0,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xf0,
+ 0x80,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xf0,0xc0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf3,
+ 0x80,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xf0,0xc0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf5,
+ 0xe0,0xe0,0xe0,0xf0,0xf0,0xf0,0xf0,0xf6,0xf0,0xf0,0xf4,0xf7,0xf4,0xf7,0xf7,0xf7,
+ 0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xf0,0xe0,0xe0,0xe0,0xf8,0xf0,0xf8,0xf8,0xf9,
+ 0xe0,0xf0,0xf0,0xf8,0xf0,0xf8,0xf8,0xfa,0xf0,0xf8,0xf8,0xfb,0xf8,0xfb,0xfb,0xfb,
+ 0xe0,0xf0,0xf0,0xf8,0xf0,0xf8,0xfc,0xfc,0xf8,0xfc,0xfc,0xfd,0xfc,0xfd,0xfd,0xfd,
+ 0xf8,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfc,0xf8,
+ 0xfd,0xfd,0xfd,0xfc,0xfd,0xfc,0xfc,0xf8,0xfc,0xfc,0xfc,0xf0,0xf8,0xf0,0xf0,0xe0,
+ 0xfb,0xfb,0xfb,0xf8,0xfb,0xf8,0xf8,0xf0,0xfa,0xf8,0xf8,0xf0,0xf8,0xf0,0xf0,0xe0,
+ 0xf9,0xf8,0xf8,0xf0,0xf8,0xf0,0xe0,0xe0,0xf0,0xe0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,
+ 0xf7,0xf7,0xf7,0xf4,0xf7,0xf4,0xf0,0xf0,0xf6,0xf0,0xf0,0xf0,0xf0,0xe0,0xe0,0xe0,
+ 0xf5,0xf0,0xf0,0xe0,0xf0,0xe0,0xe0,0xc0,0xf0,0xe0,0xe0,0xc0,0xe0,0xc0,0xc0,0x80,
+ 0xf3,0xf0,0xf0,0xe0,0xf0,0xe0,0xe0,0xc0,0xf0,0xe0,0xe0,0xc0,0xc0,0xc0,0xc0,0x80,
+ 0xf0,0xe0,0xc0,0xc0,0xc0,0xc0,0x80,0x80,0xc0,0x80,0x80,0x80,0x80, 0x0, 0x0, 0x0,
+ 0xef,0xef,0xef,0xec,0xef,0xec,0xe8,0xe0,0xee,0xe8,0xe8,0xe0,0xe0,0xe0,0xe0,0xc0,
+ 0xed,0xe8,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0,0xe0,0xe0,0xc0,0xc0,0xc0,0xc0,0x80,0x80,
+ 0xeb,0xe0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0,
+ 0xe0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0,0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,
+ 0xe7,0xe0,0xe0,0xc0,0xe0,0xc0,0xc0,0x80,0xe0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0,
+ 0xe0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0,0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xe0,0xc0,0xc0,0x80,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xdf,0xdf,0xdf,0xdc,0xdf,0xdc,0xd8,0xc0,0xde,0xd8,0xd8,0xc0,0xd8,0xc0,0xc0,0xc0,
+ 0xdd,0xd8,0xd0,0xc0,0xd0,0xc0,0xc0,0x80,0xd0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0,
+ 0xdb,0xd0,0xd0,0xc0,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0,
+ 0xc0,0xc0,0x80,0x80,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xd7,0xd0,0xc0,0xc0,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0x80, 0x0,0x80, 0x0, 0x0, 0x0,
+ 0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xcf,0xc0,0xc0,0xc0,0xc0,0x80,0x80, 0x0,0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,
+ 0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xc0,0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xc0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xbf,0xbf,0xbf,0xbe,0xbf,0xbc,0xbc,0xa0,0xbe,0xbc,0xb8,0xa0,0xb8,0xa0,0x80,0x80,
+ 0xbd,0xb8,0xb0,0x80,0xb0,0x80,0x80,0x80,0xb0,0x80,0x80,0x80,0x80, 0x0, 0x0, 0x0,
+ 0xbb,0xb0,0xb0,0x80,0xa0,0x80,0x80, 0x0,0xa0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,
+ 0xa0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xb7,0xb0,0xa0,0x80,0xa0,0x80,0x80, 0x0,0xa0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,
+ 0x80,0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xaf,0xa0,0xa0,0x80,0x80,0x80,0x80, 0x0,0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x9f,0x90,0x80,0x80,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x7f,0x7f,0x7f,0x7e,0x7f,0x7c,0x7c,0x70,0x7e,0x7c,0x78,0x60,0x78,0x60,0x60, 0x0,
+ 0x7d,0x78,0x78,0x60,0x70,0x40,0x40, 0x0,0x70,0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x7b,0x78,0x70,0x40,0x70,0x40, 0x0, 0x0,0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x77,0x70,0x70, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x6f,0x60,0x60, 0x0,0x60, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x5f,0x58,0x40, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x3f,0x3c,0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+};
+
+static UINT8 waveform60_6581[4096+4096] =
+{
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,0x1f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x2f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x37,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3d,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3e,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x30,0x3f, 0x0,0x30,0x38,0x3f,0x3e,0x3f,0x3f,0x3f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x4f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x57,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5d,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5e,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x5f, 0x0,0x40,0x40,0x5f,0x5c,0x5f,0x5f,0x5f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x67,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x6b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x40,0x6d,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x40,0x6e,
+ 0x0, 0x0, 0x0,0x40, 0x0,0x60,0x60,0x6f, 0x0,0x60,0x60,0x6f,0x60,0x6f,0x6f,0x6f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x60,0x73,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x60,0x60,0x75,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x76,
+ 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x77, 0x0,0x70,0x70,0x77,0x70,0x77,0x77,0x77,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x79,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x70,0x70,0x7a,
+ 0x0, 0x0, 0x0,0x70, 0x0,0x70,0x70,0x7b,0x40,0x70,0x70,0x7b,0x78,0x7b,0x7b,0x7b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x70, 0x0, 0x0, 0x0,0x70, 0x0,0x70,0x70,0x7c,
+ 0x0, 0x0, 0x0,0x70,0x40,0x70,0x70,0x7d,0x40,0x70,0x78,0x7d,0x78,0x7d,0x7d,0x7d,
+ 0x0,0x40,0x40,0x78,0x60,0x78,0x78,0x7e,0x60,0x78,0x78,0x7e,0x7c,0x7e,0x7e,0x7e,
+ 0x70,0x7c,0x7c,0x7f,0x7e,0x7f,0x7f,0x7f,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,0x1f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x2f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x37,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3d,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3e,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x30,0x3f, 0x0,0x30,0x38,0x3f,0x3e,0x3f,0x3f,0x3f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x4f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x57,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5d,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5e,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x5f, 0x0,0x40,0x40,0x5f,0x5c,0x5f,0x5f,0x5f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x67,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x6b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x6d,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x40,0x6e,
+ 0x0, 0x0, 0x0,0x40, 0x0,0x60,0x60,0x6f, 0x0,0x60,0x60,0x6f,0x60,0x6f,0x6f,0x6f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x60,0x73,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x60,0x60,0x75,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x76,
+ 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x77, 0x0,0x70,0x70,0x77,0x70,0x77,0x77,0x77,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x79,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x70,0x70,0x7a,
+ 0x0, 0x0, 0x0,0x70, 0x0,0x70,0x70,0x7b,0x40,0x70,0x70,0x7b,0x78,0x7b,0x7b,0x7b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x70, 0x0, 0x0, 0x0,0x70, 0x0,0x70,0x70,0x7c,
+ 0x0, 0x0, 0x0,0x70,0x40,0x70,0x70,0x7d,0x40,0x70,0x78,0x7d,0x78,0x7d,0x7d,0x7d,
+ 0x0,0x40,0x40,0x78,0x60,0x78,0x78,0x7e,0x60,0x78,0x78,0x7e,0x7c,0x7e,0x7e,0x7e,
+ 0x70,0x7c,0x7c,0x7f,0x7c,0x7f,0x7f,0x7f,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f
+};
+
+static UINT8 waveform70_6581[4096+4096] =
+{
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x20,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x30, 0x0, 0x0, 0x0,0x78,0x78,0x7e,0x7f,0x7f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3f,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x20,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x30, 0x0, 0x0, 0x0,0x78,0x78,0x7e,0x7f,0x7f
+};
+
+#endif // WAVE6581_h
diff --git a/src/emu/sound/sidw8580.h b/src/emu/sound/sidw8580.h
new file mode 100644
index 00000000000..226d2e18b34
--- /dev/null
+++ b/src/emu/sound/sidw8580.h
@@ -0,0 +1,1395 @@
+#ifndef WAVE8580_H
+#define WAVE8580_H
+
+
+/* MOS-8580 R5 waveforms $30,$50,$60,$70
+ *
+ * Created with Deadman's Raw Data to C Header converter
+ */
+
+static UINT8 waveform30_8580[4096] =
+{
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x0e,0x0e,0x0e,0x0e,0x0f,0x0f,0x0f,0x0f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x1e,
+ 0x1f,0x1f,0x1f,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x0e,0x0e,0x0e,0x0e,0x0f,0x0f,0x0f,0x0f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,
+ 0x38,0x38,0x38,0x38,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
+ 0x3e,0x3e,0x3f,0x3f,0x7f,0x7f,0x7f,0x7f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x0e,0x0e,0x0e,
+ 0x0f,0x0f,0x0f,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x1c,0x1c,0x1c,
+ 0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x1e,0x1f,0x1f,0x1f,0x1f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x0e,0x0e,0x0e,0x0e,0x0f,0x0f,0x1f,0x1f,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x81,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x87,0x87,0x87,0x8f,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe3,0xe3,0xe0,0xf0,0xf0,0xf0,
+ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0,0xe0,0xf0,0xf0,
+ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
+ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
+ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
+ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf1,
+ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf8,0xf0,0xf0,
+ 0xf0,0xf0,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,
+ 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xfc,0xfc,0xfc,
+ 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,
+ 0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff
+};
+
+static UINT8 waveform50_8580[4096+4096] =
+{
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x3f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x6f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x40,0x60,0x60,0x77,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x60,
+ 0x00,0x40,0x40,0x60,0x40,0x70,0x70,0x7b,0x00,0x00,0x40,0x40,
+ 0x40,0x40,0x40,0x70,0x40,0x60,0x60,0x70,0x60,0x70,0x78,0x7c,
+ 0x60,0x70,0x70,0x78,0x70,0x78,0x7c,0x7e,0x78,0x7c,0x7c,0x7f,
+ 0x7e,0x7f,0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,
+ 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x9f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,
+ 0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb7,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xa0,
+ 0x80,0xa0,0xb0,0xbb,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xa0,
+ 0x80,0x80,0x80,0xb0,0xa0,0xb0,0xb0,0xbc,0x80,0xa0,0xa0,0xb0,
+ 0xb0,0xb8,0xb8,0xbe,0xb8,0xbc,0xbc,0xbf,0xbc,0xbf,0xbf,0xbf,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,
+ 0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xcf,0x00,0x00,0x80,0x80,
+ 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0x80,0x80,0x80,0xc0,
+ 0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd7,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xd8,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xd0,0xdc,
+ 0xc0,0xc0,0xc0,0xd0,0xd0,0xd8,0xd8,0xde,0xd0,0xd8,0xdc,0xdf,
+ 0xdc,0xdf,0xdf,0xdf,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,
+ 0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,
+ 0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe7,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xc0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe8,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xec,0xe0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe8,0xee,0xe0,0xe8,0xec,0xee,0xec,0xef,0xef,0xef,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,
+ 0xe0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf0,0xe0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf4,
+ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf4,0xf0,0xf0,0xf0,0xf6,
+ 0xf4,0xf7,0xf7,0xf7,0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
+ 0xf0,0xf0,0xf0,0xf8,0xf0,0xf8,0xf8,0xf8,0xf0,0xf0,0xf0,0xf8,
+ 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfa,0xf8,0xfb,0xfb,0xfb,
+ 0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xfc,0xfc,0xf8,0xfc,0xfc,0xfc,
+ 0xfc,0xfd,0xfd,0xfd,0xfc,0xfc,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,
+ 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfc,0xfc,0xfc,
+ 0xfd,0xfd,0xfc,0xfc,0xfc,0xfc,0xfc,0xf8,0xfc,0xfc,0xfc,0xf8,
+ 0xf8,0xf8,0xf8,0xf8,0xfb,0xfb,0xfb,0xf8,0xfa,0xf8,0xf8,0xf8,
+ 0xf8,0xf8,0xf8,0xf8,0xf8,0xf0,0xf0,0xf0,0xf8,0xf8,0xf8,0xf0,
+ 0xf8,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0,
+ 0xf7,0xf7,0xf7,0xf4,0xf6,0xf0,0xf0,0xf0,0xf4,0xf0,0xf0,0xf0,
+ 0xf0,0xf0,0xf0,0xf0,0xf4,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0,
+ 0xf0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xf0,0xf0,0xe0,
+ 0xf0,0xe0,0xe0,0xe0,0xf0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xef,0xef,0xef,0xec,0xee,0xec,0xe8,0xe0,
+ 0xee,0xe8,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xec,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,
+ 0xe8,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0,0xe0,0xe0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe7,0xe0,0xe0,0xc0,
+ 0xe0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x80,
+ 0xc0,0x80,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x80,
+ 0xc0,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0xdf,0xdf,0xdf,0xdc,0xdf,0xdc,0xdc,0xd0,0xde,0xd8,0xd8,0xd0,
+ 0xd0,0xc0,0xc0,0xc0,0xdc,0xd0,0xd0,0xc0,0xd0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd8,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x80,0xc0,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0xd7,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0x80,0xc0,0x80,0x80,0x80,0xc0,0xc0,0xc0,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0xcf,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xbf,0xbf,0xbf,0xbc,0xbf,0xbc,0xbc,0xb8,
+ 0xbe,0xb8,0xb8,0xb0,0xb8,0xa0,0xa0,0x80,0xbc,0xb0,0xb0,0xa0,
+ 0xb0,0x80,0x80,0x80,0xa0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0xbb,0xb0,0xa0,0x80,0xa0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb7,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xaf,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x80,0x00,0x00,0x00,
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9f,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x7f,0x7f,0x7f,0x7e,0x7f,0x7c,0x7c,0x78,0x7e,0x7c,0x78,0x70,
+ 0x78,0x70,0x70,0x60,0x7c,0x78,0x70,0x60,0x70,0x60,0x60,0x40,
+ 0x70,0x60,0x40,0x40,0x40,0x40,0x00,0x00,0x7b,0x70,0x70,0x40,
+ 0x60,0x40,0x40,0x00,0x60,0x40,0x40,0x00,0x00,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x77,0x60,0x40,0x40,0x40,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0x40,0x40,0x00,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x1c,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00
+};
+
+static UINT8 waveform60_8580[4096+4096] =
+{
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3b,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,
+ 0x00,0x3f,0x3f,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5e,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x5f,0x00,0x00,0x00,0x5f,0x00,0x5f,0x5f,0x5f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6b,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6e,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0x00,0x00,0x00,0x6f,
+ 0x40,0x6f,0x6f,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x00,0x00,0x00,0x00,
+ 0x00,0x40,0x40,0x77,0x00,0x40,0x40,0x77,0x40,0x77,0x77,0x77,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,
+ 0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x79,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x78,
+ 0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x78,0x40,0x60,0x60,0x78,
+ 0x60,0x7b,0x7b,0x7b,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x60,
+ 0x00,0x40,0x40,0x60,0x40,0x60,0x60,0x7c,0x40,0x40,0x40,0x60,
+ 0x40,0x70,0x70,0x7c,0x60,0x70,0x70,0x7c,0x70,0x7c,0x7d,0x7d,
+ 0x40,0x60,0x60,0x70,0x60,0x70,0x78,0x7e,0x70,0x78,0x78,0x7e,
+ 0x78,0x7e,0x7e,0x7e,0x78,0x7c,0x7c,0x7f,0x7c,0x7f,0x7f,0x7f,
+ 0x7c,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8b,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x9d,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x9e,
+ 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x9f,0x80,0x80,0x80,0x9f,
+ 0x80,0x9f,0x9f,0x9f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x87,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,
+ 0x00,0x80,0x80,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x85,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,
+ 0x80,0x80,0x80,0xae,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xaf,
+ 0x80,0x80,0x80,0xaf,0x80,0xaf,0xaf,0xaf,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0xa3,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,
+ 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xa1,0x00,0x00,0x80,0x80,
+ 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb0,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb0,0x80,0x80,0x80,0xb5,
+ 0x80,0xb7,0xb7,0xb7,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,
+ 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb1,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0xb8,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb8,
+ 0x80,0x80,0x80,0xb8,0x80,0xb8,0xbb,0xbb,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbc,
+ 0x80,0x80,0x80,0xa0,0x80,0xa0,0xa0,0xbc,0x80,0xa0,0xa0,0xbc,
+ 0xb0,0xbc,0xbc,0xbd,0x80,0x80,0x80,0xb0,0x80,0xb0,0xb0,0xbc,
+ 0xa0,0xb0,0xb0,0xbc,0xb8,0xbc,0xbe,0xbe,0xb0,0xb8,0xb8,0xbe,
+ 0xbc,0xbe,0xbf,0xbf,0xbc,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,
+ 0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,
+ 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xc7,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,
+ 0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc3,
+ 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc5,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xce,
+ 0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xcf,0x80,0xc0,0xc0,0xcf,
+ 0xc0,0xcf,0xcf,0xcf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0xc3,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0xc0,
+ 0x80,0xc0,0xc0,0xc1,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,
+ 0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0,0x80,0x80,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xc0,0xd5,0xd7,0xd7,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,
+ 0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd1,0x80,0x80,0x80,0xc0,
+ 0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xc0,0xc0,0xc0,0xd8,
+ 0xc0,0xd8,0xd9,0xdb,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd8,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xdc,0xc0,0xc0,0xc0,0xdc,0xd0,0xdc,0xdc,0xdd,
+ 0xc0,0xc0,0xc0,0xd0,0xc0,0xd0,0xd0,0xdc,0xc0,0xd0,0xd0,0xdc,
+ 0xd0,0xdc,0xde,0xde,0xd0,0xd8,0xd8,0xde,0xd8,0xde,0xde,0xdf,
+ 0xdc,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0xc0,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,
+ 0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0,0x80,0x80,0x80,0xc0,
+ 0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe3,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0xc0,
+ 0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe1,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe0,
+ 0xe0,0xe1,0xe7,0xe7,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe1,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xe0,
+ 0xc0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe8,0xe8,0xeb,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe8,
+ 0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe8,0xe0,0xe0,0xe0,0xec,
+ 0xe0,0xec,0xec,0xed,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xec,
+ 0xe0,0xe0,0xe0,0xec,0xe0,0xec,0xec,0xee,0xe0,0xe8,0xe8,0xee,
+ 0xe8,0xee,0xee,0xef,0xec,0xef,0xef,0xef,0xef,0xef,0xef,0xef,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,
+ 0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xc0,0xc0,0xc0,0xe0,
+ 0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xe0,0xe0,0xf0,0xf0,
+ 0xf0,0xf0,0xf0,0xf3,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,
+ 0xe0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf0,0xe0,0xe0,0xe0,0xf0,
+ 0xe0,0xf0,0xf0,0xf0,0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf4,0xf5,
+ 0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf4,0xf0,0xf0,0xf0,0xf4,
+ 0xf0,0xf4,0xf4,0xf6,0xf0,0xf0,0xf0,0xf4,0xf0,0xf4,0xf6,0xf7,
+ 0xf4,0xf6,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xe0,0xe0,0xe0,0xf0,
+ 0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf8,
+ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf8,0xf0,0xf0,0xf8,0xf8,
+ 0xf8,0xf8,0xf8,0xf9,0xf0,0xf0,0xf0,0xf8,0xf0,0xf8,0xf8,0xf8,
+ 0xf0,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfa,0xf8,0xf8,0xf8,0xf8,
+ 0xf8,0xf8,0xfa,0xfb,0xf8,0xfa,0xfa,0xfb,0xfb,0xfb,0xfb,0xfb,
+ 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xf8,0xf8,0xf8,0xfc,
+ 0xfc,0xfc,0xfc,0xfc,0xf8,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfd,
+ 0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfd,0xfc,0xfc,0xfc,0xfe,
+ 0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
+ 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff
+};
+
+static UINT8 waveform70_8580[4096+4096] =
+{
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,
+ 0x20,0x70,0x70,0x7c,0x7c,0x7e,0x7f,0x7f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x3f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x9f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xcf,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0xc0,0xc0,0xc0,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe3,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
+ 0xc0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,
+ 0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xf0,0xf0,
+ 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xe0,0xe0,0xe0,0xf0,
+ 0xf0,0xf0,0xf0,0xf0,0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
+ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf8,0xf8,0xf0,0xf0,0xf0,0xf8,
+ 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xfc,
+ 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfe,0xfe,0xfe,0xfe,0xff,
+ 0xff,0xff,0xff,0xff
+};
+
+
+#endif
diff --git a/src/emu/sound/sn76477.c b/src/emu/sound/sn76477.c
new file mode 100644
index 00000000000..f477eee4f7a
--- /dev/null
+++ b/src/emu/sound/sn76477.c
@@ -0,0 +1,2512 @@
+/*****************************************************************************
+
+ Texas Instruments SN76477 emulator
+
+ authors: Derrick Renaud - info
+ Zsolt Vasvari - software
+
+ (see sn76477.h for details)
+
+ Notes:
+ * All formulas were derived by taking measurements of a real device,
+ then running the data sets through the numerical analysis
+ application at http://zunzun.com to come up with the functions.
+
+ Known issues/to-do's:
+ * VCO
+ * confirm value of VCO_MAX_EXT_VOLTAGE, VCO_TO_SLF_VOLTAGE_DIFF
+ VCO_CAP_VOLTAGE_MIN and VCO_CAP_VOLTAGE_MAX
+ * confirm value of VCO_MIN_DUTY_CYCLE
+ * get real formulas for VCO cap charging and discharging
+ * get real formula for VCO duty cycle
+ * what happens if no vco_res
+ * what happens if no vco_cap
+
+ * Attack/Decay
+ * get real formulas for a/d cap charging and discharging
+
+ *****************************************************************************/
+
+#include <math.h> /* for pow() */
+#include "sndintrf.h"
+#include "streams.h"
+#include "sn76477.h"
+
+
+
+/*****************************************************************************
+ *
+ * Debugging
+ *
+ *****************************************************************************/
+
+#define VERBOSE 1
+
+/* if 1, create a .wav file of the sound produced */
+#define LOG_WAV 0
+
+/* if 1 and LOG_WAV is 1, only logs to .wav file in chip is enabled */
+#define LOG_WAV_ENABLED_ONLY 0
+
+/* determines what value will be logged in the left channel of the .wav file */
+#define LOG_WAV_VALUE_L 0 /* 0 = OUT voltage */
+ /* 1 = enable line */
+ /* 2 = one-shot cap voltage */
+ /* 3 = a/d cap voltage */
+ /* 4 = slf cap voltage */
+ /* 5 = vco cap voltage */
+ /* 6 = noise filter cap voltage */
+
+/* determines what value will be logged in the right channel of the .wav file
+ same values as for the left channel above */
+#define LOG_WAV_VALUE_R 3
+
+#define LOG_WAV_GAIN_FACTOR 1000
+
+#define LOG_WAV_FILE_NAME "sn76477_%d.wav"
+
+
+#if VERBOSE
+#define LOG(n,x) if (VERBOSE >= (n)) logerror x
+#else
+#define LOG(n,x)
+#endif
+
+#define CHECK_CHIP_NUM assert(sn != NULL)
+#define CHECK_CHIP_NUM_AND_BOOLEAN CHECK_CHIP_NUM; assert((data & 0x01) == data)
+#define CHECK_CHIP_NUM_AND_POSITIVE CHECK_CHIP_NUM; assert(data >= 0.0)
+#define CHECK_CHIP_NUM_AND_VOLTAGE CHECK_CHIP_NUM; assert((data >= 0.0) && (data <= 5.0))
+#define CHECK_CHIP_NUM_AND_CAP_VOLTAGE CHECK_CHIP_NUM; assert(((data >= 0.0) && (data <= 5.0)) || (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT))
+
+
+
+/*****************************************************************************
+ *
+ * Test Mode
+ *
+ * in test mode, the interface structure
+ * passed in by the driver is not used.
+ * Instead, the values for all the inputs
+ * can be specified by modifing the structure
+ * below. Calls by the driver to the input
+ * setter functions are ignored. Use the
+ * space bar to enable/disable the chip.
+ *
+ *****************************************************************************/
+
+#define TEST_MODE 0
+
+
+#if TEST_MODE
+#include "input.h"
+
+static struct SN76477interface empty_interface =
+{
+ 0, /* 4 noise_clock_res */
+ 0, /* 5 filter_res */
+ 0, /* 6 filter_cap */
+ 0, /* 7 decay_res */
+ 0, /* 8 attack_decay_cap */
+ 0, /* 10 attack_res */
+ 0, /* 11 amplitude_res */
+ 0, /* 12 feedback_res */
+ 0, /* 16 vco_voltage */
+ 0, /* 17 vco_cap */
+ 0, /* 18 vco_res */
+ 0, /* 19 pitch_voltage */
+ 0, /* 20 slf_res */
+ 0, /* 21 slf_cap */
+ 0, /* 23 oneshot_cap */
+ 0, /* 24 oneshot_res */
+ 0, /* 22 vco */
+ 0, /* 26 mixer A */
+ 0, /* 25 mixer B */
+ 0, /* 27 mixer C */
+ 0, /* 1 envelope 1 */
+ 0, /* 28 envelope 2 */
+ 0 /* 9 enable */
+};
+
+#define test_interface empty_empty_interface
+
+#endif
+
+
+
+/*****************************************************************************
+ *
+ * Constants
+ *
+ *****************************************************************************/
+
+#define ONE_SHOT_CAP_VOLTAGE_MIN (0) /* the voltage at which the one-shot starts from (measured) */
+#define ONE_SHOT_CAP_VOLTAGE_MAX (2.5) /* the voltage at which the one-shot finishes (measured) */
+#define ONE_SHOT_CAP_VOLTAGE_RANGE (ONE_SHOT_CAP_VOLTAGE_MAX - ONE_SHOT_CAP_VOLTAGE_MIN)
+
+#define SLF_CAP_VOLTAGE_MIN (0.33) /* the voltage at the bottom peak of the SLF triangle wave (measured) */
+#define SLF_CAP_VOLTAGE_MAX (2.37) /* the voltage at the top peak of the SLF triangle wave (measured) */
+#define SLF_CAP_VOLTAGE_RANGE (SLF_CAP_VOLTAGE_MAX - SLF_CAP_VOLTAGE_MIN)
+
+#define VCO_MAX_EXT_VOLTAGE (2.35) /* the external voltage at which the VCO saturates and produces no output,
+ also used as the voltage threshold for the SLF */
+#define VCO_TO_SLF_VOLTAGE_DIFF (0.35)
+#define VCO_CAP_VOLTAGE_MIN (SLF_CAP_VOLTAGE_MIN) /* the voltage at the bottom peak of the VCO triangle wave */
+#define VCO_CAP_VOLTAGE_MAX (SLF_CAP_VOLTAGE_MAX + VCO_TO_SLF_VOLTAGE_DIFF) /* the voltage at the bottom peak of the VCO triangle wave */
+#define VCO_CAP_VOLTAGE_RANGE (VCO_CAP_VOLTAGE_MAX - VCO_CAP_VOLTAGE_MIN)
+#define VCO_DUTY_CYCLE_50 (5.0) /* the high voltage that produces a 50% duty cycle */
+#define VCO_MIN_DUTY_CYCLE (18) /* the smallest possible duty cycle, in % */
+
+#define NOISE_MIN_CLOCK_RES RES_K(10) /* the maximum resistor value that still produces a noise (measured) */
+#define NOISE_MAX_CLOCK_RES RES_M(3.3) /* the minimum resistor value that still produces a noise (measured) */
+#define NOISE_CAP_VOLTAGE_MIN (0) /* the minimum voltage that the noise filter cap can hold (measured) */
+#define NOISE_CAP_VOLTAGE_MAX (5.0) /* the maximum voltage that the noise filter cap can hold (measured) */
+#define NOISE_CAP_VOLTAGE_RANGE (NOISE_CAP_VOLTAGE_MAX - NOISE_CAP_VOLTAGE_MIN)
+#define NOISE_CAP_HIGH_THRESHOLD (3.35) /* the voltage at which the filtered noise bit goes to 0 (measured) */
+#define NOISE_CAP_LOW_THRESHOLD (0.74) /* the voltage at which the filtered noise bit goes to 1 (measured) */
+
+#define AD_CAP_VOLTAGE_MIN (0) /* the minimum voltage the attack/decay cap can hold (measured) */
+#define AD_CAP_VOLTAGE_MAX (4.44) /* the minimum voltage the attack/decay cap can hold (measured) */
+#define AD_CAP_VOLTAGE_RANGE (AD_CAP_VOLTAGE_MAX - AD_CAP_VOLTAGE_MIN)
+
+#define OUT_CENTER_LEVEL_VOLTAGE (2.57) /* the voltage that gets outputted when the volumne is 0 (measured) */
+#define OUT_HIGH_CLIP_THRESHOLD (3.51) /* the maximum voltage that can be put out (measured) */
+#define OUT_LOW_CLIP_THRESHOLD (0.715) /* the minimum voltage that can be put out (measured) */
+
+/* gain factors for OUT voltage in 0.1V increments (measured) */
+static const double out_pos_gain[] =
+{
+ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.01, /* 0.0 - 0.9V */
+ 0.03, 0.11, 0.15, 0.19, 0.21, 0.23, 0.26, 0.29, 0.31, 0.33, /* 1.0 - 1.9V */
+ 0.36, 0.38, 0.41, 0.43, 0.46, 0.49, 0.52, 0.54, 0.57, 0.60, /* 2.0 - 2.9V */
+ 0.62, 0.65, 0.68, 0.70, 0.73, 0.76, 0.80, 0.82, 0.84, 0.87, /* 3.0 - 3.9V */
+ 0.90, 0.93, 0.96, 0.98, 1.00 /* 4.0 - 4.4V */
+};
+
+static const double out_neg_gain[] =
+{
+ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, -0.01, /* 0.0 - 0.9V */
+ -0.02, -0.09, -0.13, -0.15, -0.17, -0.19, -0.22, -0.24, -0.26, -0.28, /* 1.0 - 1.9V */
+ -0.30, -0.32, -0.34, -0.37, -0.39, -0.41, -0.44, -0.46, -0.48, -0.51, /* 2.0 - 2.9V */
+ -0.53, -0.56, -0.58, -0.60, -0.62, -0.65, -0.67, -0.69, -0.72, -0.74, /* 3.0 - 3.9V */
+ -0.76, -0.78, -0.81, -0.84, -0.85 /* 4.0 - 4.4V */
+};
+
+
+
+/*****************************************************************************
+ *
+ * State structure
+ *
+ *****************************************************************************/
+
+struct SN76477
+{
+ /* chip's external interface */
+ UINT32 enable;
+ UINT32 envelope_mode;
+ UINT32 vco_mode;
+ UINT32 mixer_mode;
+
+ double one_shot_res;
+ double one_shot_cap;
+ UINT32 one_shot_cap_voltage_ext;
+
+ double slf_res;
+ double slf_cap;
+ UINT32 slf_cap_voltage_ext;
+
+ double vco_voltage;
+ double vco_res;
+ double vco_cap;
+ UINT32 vco_cap_voltage_ext;
+
+ double noise_clock_res;
+ UINT32 noise_clock_ext;
+ UINT32 noise_clock;
+ double noise_filter_res;
+ double noise_filter_cap;
+ UINT32 noise_filter_cap_voltage_ext;
+
+ double attack_res;
+ double decay_res;
+ double attack_decay_cap;
+ UINT32 attack_decay_cap_voltage_ext;
+
+ double amplitude_res;
+ double feedback_res;
+ double pitch_voltage;
+
+ /* chip's internal state */
+ double one_shot_cap_voltage; /* voltage on the one-shot cap */
+ UINT32 one_shot_running_ff; /* 1 = one-shot running, 0 = stopped */
+
+ double slf_cap_voltage; /* voltage on the SLF cap */
+ UINT32 slf_out_ff; /* output of the SLF */
+
+ double vco_cap_voltage; /* voltage on the VCO cap */
+ UINT32 vco_out_ff; /* output of the VCO */
+ UINT32 vco_alt_pos_edge_ff; /* keeps track of the # of positive edges for VCO Alt envelope */
+
+ double noise_filter_cap_voltage; /* voltage on the noise filter cap */
+ UINT32 real_noise_bit_ff; /* the current noise bit before filtering */
+ UINT32 filtered_noise_bit_ff; /* the noise bit after filtering */
+ UINT32 noise_gen_count; /* noise freq emulation */
+
+ double attack_decay_cap_voltage; /* voltage on the attack/decay cap */
+
+ UINT32 rng; /* current value of the random number generator */
+
+ /* others */
+ sound_stream *channel; /* returned by stream_create() */
+ UINT32 index;
+ int sample_rate; /* from Machine->sample_rate */
+
+#if LOG_WAV
+ wav_file *file; /* handle of the wave file to produce */
+#endif
+};
+
+
+
+/*****************************************************************************
+ *
+ * Max/min
+ *
+ *****************************************************************************/
+
+#undef max
+#undef min
+
+INLINE double max(double a, double b)
+{
+ return (a > b) ? a : b;
+}
+
+
+INLINE double min(double a, double b)
+{
+ return (a < b) ? a : b;
+}
+
+
+
+/*****************************************************************************
+ *
+ * Functions for computing frequencies, voltages and similar values based
+ * on the hardware itself. Do NOT put anything emulation specific here,
+ * such as calculations based on sample_rate.
+ *
+ *****************************************************************************/
+
+static double compute_one_shot_cap_charging_rate(struct SN76477 *sn) /* in V/sec */
+{
+ /* this formula was derived using the data points below
+
+ Res (kohms) Cap (uF) Time (millisec)
+ 47 0.33 11.84
+ 47 1.0 36.2
+ 47 1.5 52.1
+ 47 2.0 76.4
+ 100 0.33 24.4
+ 100 1.0 75.2
+ 100 1.5 108.5
+ 100 2.0 158.4
+ */
+
+ double ret = 0;
+
+ if ((sn->one_shot_res > 0) && (sn->one_shot_cap > 0))
+ {
+ ret = ONE_SHOT_CAP_VOLTAGE_RANGE / (0.8024 * sn->one_shot_res * sn->one_shot_cap + 0.002079);
+ }
+ else if (sn->one_shot_cap > 0)
+ {
+ /* if no resistor, there is no current to charge the cap,
+ effectively making the one-shot time effectively infinite */
+ ret = +1e-30;
+ }
+ else if (sn->one_shot_res > 0)
+ {
+ /* if no cap, the voltage changes extremely fast,
+ effectively making the one-shot time 0 */
+ ret = +1e+30;
+ }
+
+ return ret;
+}
+
+
+static double compute_one_shot_cap_discharging_rate(struct SN76477 *sn) /* in V/sec */
+{
+ /* this formula was derived using the data points below
+
+ Cap (uF) Time (microsec)
+ 0.33 300
+ 1.0 850
+ 1.5 1300
+ 2.0 1900
+ */
+
+ double ret = 0;
+
+ if ((sn->one_shot_res > 0) && (sn->one_shot_cap > 0))
+ {
+ ret = ONE_SHOT_CAP_VOLTAGE_RANGE / (854.7 * sn->one_shot_cap + 0.00001795);
+ }
+ else if (sn->one_shot_res > 0)
+ {
+ /* if no cap, the voltage changes extremely fast,
+ effectively making the one-shot time 0 */
+ ret = +1e+30;
+ }
+
+ return ret;
+}
+
+
+static double compute_slf_cap_charging_rate(struct SN76477 *sn) /* in V/sec */
+{
+ /* this formula was derived using the data points below
+
+ Res (kohms) Cap (uF) Time (millisec)
+ 47 0.47 14.3
+ 120 0.47 35.6
+ 200 0.47 59.2
+ 47 1.00 28.6
+ 120 1.00 71.6
+ 200 1.00 119.0
+ */
+ double ret = 0;
+
+ if ((sn->slf_res > 0) && (sn->slf_cap > 0))
+ {
+ ret = SLF_CAP_VOLTAGE_RANGE / (0.5885 * sn->slf_res * sn->slf_cap + 0.001300);
+ }
+
+ return ret;
+}
+
+
+static double compute_slf_cap_discharging_rate(struct SN76477 *sn) /* in V/sec */
+{
+ /* this formula was derived using the data points below
+
+ Res (kohms) Cap (uF) Time (millisec)
+ 47 0.47 13.32
+ 120 0.47 32.92
+ 200 0.47 54.4
+ 47 1.00 26.68
+ 120 1.00 66.2
+ 200 1.00 109.6
+ */
+ double ret = 0;
+
+ if ((sn->slf_res > 0) && (sn->slf_cap > 0))
+ {
+ ret = SLF_CAP_VOLTAGE_RANGE / (0.5413 * sn->slf_res * sn->slf_cap + 0.001343);
+ }
+
+ return ret;
+}
+
+
+static double compute_vco_cap_charging_discharging_rate(struct SN76477 *sn) /* in V/sec */
+{
+ double ret = 0;
+
+ if ((sn->vco_res > 0) && (sn->vco_cap > 0))
+ {
+ ret = 0.64 * 2 * VCO_CAP_VOLTAGE_RANGE / (sn->vco_res * sn->vco_cap);
+ }
+
+ return ret;
+}
+
+
+static double compute_vco_duty_cycle(struct SN76477 *sn) /* no measure, just a number */
+{
+ double ret = 0.5; /* 50% */
+
+ if ((sn->vco_voltage > 0) && (sn->pitch_voltage != VCO_DUTY_CYCLE_50))
+ {
+ ret = max(0.5 * (sn->pitch_voltage / sn->vco_voltage), (VCO_MIN_DUTY_CYCLE / 100.0));
+
+ ret = min(ret, 1);
+ }
+
+ return ret;
+}
+
+
+static UINT32 compute_noise_gen_freq(struct SN76477 *sn) /* in Hz */
+{
+ /* this formula was derived using the data points below
+
+ Res (ohms) Freq (Hz)
+ 10k 97493
+ 12k 83333
+ 15k 68493
+ 22k 49164
+ 27k 41166
+ 33k 34449
+ 36k 31969
+ 47k 25126
+ 56k 21322
+ 68k 17721.5
+ 82k 15089.2
+ 100k 12712.0
+ 150k 8746.4
+ 220k 6122.4
+ 270k 5101.5
+ 330k 4217.2
+ 390k 3614.5
+ 470k 3081.7
+ 680k 2132.7
+ 820k 1801.8
+ 1M 1459.9
+ 2.2M 705.13
+ 3.3M 487.59
+ */
+
+ UINT32 ret = 0;
+
+ if ((sn->noise_clock_res >= NOISE_MIN_CLOCK_RES) &&
+ (sn->noise_clock_res <= NOISE_MAX_CLOCK_RES))
+ {
+ ret = 339100000 * pow(sn->noise_clock_res, -0.8849);
+ }
+
+ return ret;
+}
+
+
+static double compute_noise_filter_cap_charging_rate(struct SN76477 *sn) /* in V/sec */
+{
+ /* this formula was derived using the data points below
+
+ R*C Time (sec)
+ .000068 .0000184
+ .0001496 .0000378
+ .0002244 .0000548
+ .0003196 .000077
+ .0015 .000248
+ .0033 .000540
+ .00495 .000792
+ .00705 .001096
+ */
+
+ double ret = 0;
+
+ if ((sn->noise_filter_res > 0) && (sn->noise_filter_cap > 0))
+ {
+ ret = NOISE_CAP_VOLTAGE_RANGE / (0.1571 * sn->noise_filter_res * sn->noise_filter_cap + 0.00001430);
+ }
+ else if (sn->noise_filter_cap > 0)
+ {
+ /* if no resistor, there is no current to charge the cap,
+ effectively making the filter's output constants */
+ ret = +1e-30;
+ }
+ else if (sn->noise_filter_res > 0)
+ {
+ /* if no cap, the voltage changes extremely fast,
+ effectively disabling the filter */
+ ret = +1e+30;
+ }
+
+ return ret;
+}
+
+
+static double compute_noise_filter_cap_discharging_rate(struct SN76477 *sn) /* in V/sec */
+{
+ /* this formula was derived using the data points below
+
+ R*C Time (sec)
+ .000068 .000016
+ .0001496 .0000322
+ .0002244 .0000472
+ .0003196 .0000654
+ .0015 .000219
+ .0033 .000468
+ .00495 .000676
+ .00705 .000948
+ */
+
+ double ret = 0;
+
+ if ((sn->noise_filter_res > 0) && (sn->noise_filter_cap > 0))
+ {
+ ret = NOISE_CAP_VOLTAGE_RANGE / (0.1331 * sn->noise_filter_res * sn->noise_filter_cap + 0.00001734);
+ }
+ else if (sn->noise_filter_cap > 0)
+ {
+ /* if no resistor, there is no current to charge the cap,
+ effectively making the filter's output constants */
+ ret = +1e-30;
+ }
+ else if (sn->noise_filter_res > 0)
+ {
+ /* if no cap, the voltage changes extremely fast,
+ effectively disabling the filter */
+ ret = +1e+30;
+ }
+
+ return ret;
+}
+
+
+static double compute_attack_decay_cap_charging_rate(struct SN76477 *sn) /* in V/sec */
+{
+ double ret = 0;
+
+ if ((sn->attack_res > 0) && (sn->attack_decay_cap > 0))
+ {
+ ret = AD_CAP_VOLTAGE_RANGE / (sn->attack_res * sn->attack_decay_cap);
+ }
+ else if (sn->attack_decay_cap > 0)
+ {
+ /* if no resistor, there is no current to charge the cap,
+ effectively making the attack time infinite */
+ ret = +1e-30;
+ }
+ else if (sn->attack_res > 0)
+ {
+ /* if no cap, the voltage changes extremely fast,
+ effectively making the attack time 0 */
+ ret = +1e+30;
+ }
+
+ return ret;
+}
+
+
+static double compute_attack_decay_cap_discharging_rate(struct SN76477 *sn) /* in V/sec */
+{
+ double ret = 0;
+
+ if ((sn->decay_res > 0) && (sn->attack_decay_cap > 0))
+ {
+ ret = AD_CAP_VOLTAGE_RANGE / (sn->decay_res * sn->attack_decay_cap);
+ }
+ else if (sn->attack_decay_cap > 0)
+ {
+ /* if no resistor, there is no current to charge the cap,
+ effectively making the decay time infinite */
+ ret = +1e-30;
+ }
+ else if (sn->attack_res > 0)
+ {
+ /* if no cap, the voltage changes extremely fast,
+ effectively making the decay time 0 */
+ ret = +1e+30;
+ }
+
+ return ret;
+}
+
+
+static double compute_center_to_peak_voltage_out(struct SN76477 *sn)
+{
+ /* this formula was derived using the data points below
+
+ Ra (kohms) Rf (kohms) Voltage
+ 150 47 1.28
+ 200 47 0.96
+ 47 22 1.8
+ 100 22 0.87
+ 150 22 0.6
+ 200 22 0.45
+ 47 10 0.81
+ 100 10 0.4
+ 150 10 0.27
+ */
+
+ double ret = 0;
+
+ if (sn->amplitude_res > 0)
+ {
+ ret = 3.818 * (sn->feedback_res / sn->amplitude_res) + 0.03;
+ }
+
+ return ret;
+}
+
+
+
+/*****************************************************************************
+ *
+ * Logging functions
+ *
+ *****************************************************************************/
+
+static void log_enable_line(struct SN76477 *sn)
+{
+#if VERBOSE
+ static const char *desc[] =
+ {
+ "Enabled", "Inhibited"
+ };
+#endif
+
+ LOG(1, ("SN76477 #%d: Enable line (9): %d [%s]\n", sn->index, sn->enable, desc[sn->enable]));
+}
+
+
+static void log_mixer_mode(struct SN76477 *sn)
+{
+#if VERBOSE
+ const char *desc[] =
+ {
+ "VCO", "SLF", "Noise", "VCO/Noise",
+ "SLF/Noise", "SLF/VCO/Noise", "SLF/VCO", "Inhibit"
+ };
+#endif
+
+ LOG(1, ("SN76477 #%d: Mixer mode (25-27): %d [%s]\n", sn->index, sn->mixer_mode, desc[sn->mixer_mode]));
+}
+
+
+static void log_envelope_mode(struct SN76477 *sn)
+{
+#if VERBOSE
+ const char *desc[] =
+ {
+ "VCO", "One-Shot", "Mixer Only", "VCO with Alternating Polarity"
+ };
+#endif
+
+ LOG(1, ("SN76477 #%d: Envelope mode (1,28): %d [%s]\n", sn->index, sn->envelope_mode, desc[sn->envelope_mode]));
+}
+
+
+static void log_vco_mode(struct SN76477 *sn)
+{
+#if VERBOSE
+ const char *desc[] =
+ {
+ "External (Pin 16)", "Internal (SLF)"
+ };
+#endif
+
+ LOG(1, ("SN76477 #%d: VCO mode (22): %d [%s]\n", sn->index, sn->vco_mode, desc[sn->vco_mode]));
+}
+
+
+static void log_one_shot_time(struct SN76477 *sn)
+{
+ if (!sn->one_shot_cap_voltage_ext)
+ {
+ if (compute_one_shot_cap_charging_rate(sn) > 0)
+ {
+ LOG(1, ("SN76477 #%d: One-shot time (23,24): %.4f sec\n", sn->index, ONE_SHOT_CAP_VOLTAGE_RANGE * (1 / compute_one_shot_cap_charging_rate(sn))));
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: One-shot time (23,24): N/A\n", sn->index));
+ }
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: One-shot time (23,24): External (cap = %.2fV)\n", sn->index, sn->one_shot_cap_voltage));
+ }
+}
+
+
+static void log_slf_freq(struct SN76477 *sn)
+{
+ if (!sn->slf_cap_voltage_ext)
+ {
+ if (compute_slf_cap_charging_rate(sn) > 0)
+ {
+ double charging_time = (1 / compute_slf_cap_charging_rate(sn)) * SLF_CAP_VOLTAGE_RANGE;
+ double discharging_time = (1 / compute_slf_cap_discharging_rate(sn)) * SLF_CAP_VOLTAGE_RANGE;
+
+ LOG(1, ("SN76477 #%d: SLF frequency (20,21): %.2f Hz\n", sn->index, 1 / (charging_time + discharging_time)));
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: SLF frequency (20,21): N/A\n", sn->index));
+ }
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: SLF frequency (20,21): External (cap = %.2fV)\n", sn->index, sn->slf_cap_voltage));
+ }
+}
+
+
+static void log_vco_pitch_voltage(struct SN76477 *sn)
+{
+ LOG(1, ("SN76477 #%d: VCO pitch voltage (19): %.2fV\n", sn->index, sn->pitch_voltage));
+}
+
+
+static void log_vco_duty_cycle(struct SN76477 *sn)
+{
+ LOG(1, ("SN76477 #%d: VCO duty cycle (16,19): %.0f%%\n", sn->index, compute_vco_duty_cycle(sn) * 100.0));
+}
+
+
+static void log_vco_freq(struct SN76477 *sn)
+{
+ if (!sn->vco_cap_voltage_ext)
+ {
+ if (compute_vco_cap_charging_discharging_rate(sn) > 0)
+ {
+ double min_freq = compute_vco_cap_charging_discharging_rate(sn) / (2 * VCO_CAP_VOLTAGE_RANGE);
+ double max_freq = compute_vco_cap_charging_discharging_rate(sn) / (2 * VCO_TO_SLF_VOLTAGE_DIFF);
+
+ LOG(1, ("SN76477 #%d: VCO frequency (17,18): %.2f Hz - %.1f Hz\n", sn->index, min_freq, max_freq));
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: VCO frequency (17,18): N/A\n", sn->index));
+ }
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: VCO frequency (17,18): External (cap = %.2fV)\n", sn->index, sn->vco_cap_voltage));
+ }
+}
+
+
+static void log_vco_ext_voltage(struct SN76477 *sn)
+{
+ if (sn->vco_voltage <= VCO_MAX_EXT_VOLTAGE)
+ {
+ double min_freq = compute_vco_cap_charging_discharging_rate(sn) / (2 * VCO_CAP_VOLTAGE_RANGE);
+ double max_freq = compute_vco_cap_charging_discharging_rate(sn) / (2 * VCO_TO_SLF_VOLTAGE_DIFF);
+
+ LOG(1, ("SN76477 #%d: VCO ext. voltage (16): %.2fV (%.2f Hz)\n", sn->index,
+ sn->vco_voltage,
+ min_freq + ((max_freq - min_freq) * sn->vco_voltage / VCO_MAX_EXT_VOLTAGE)));
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: VCO ext. voltage (16): %.2fV (saturated, no output)\n", sn->index, sn->vco_voltage));
+ }
+}
+
+
+static void log_noise_gen_freq(struct SN76477 *sn)
+{
+ if (sn->noise_clock_ext)
+ {
+ LOG(1, ("SN76477 #%d: Noise gen frequency (4): External\n", sn->index));
+ }
+ else
+ {
+ if (compute_noise_gen_freq(sn) > 0)
+ {
+ LOG(1, ("SN76477 #%d: Noise gen frequency (4): %d Hz\n", sn->index, compute_noise_gen_freq(sn)));
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: Noise gen frequency (4): N/A\n", sn->index));
+ }
+ }
+}
+
+
+static void log_noise_filter_freq(struct SN76477 *sn)
+{
+ if (!sn->noise_filter_cap_voltage_ext)
+ {
+ double charging_rate = compute_noise_filter_cap_charging_rate(sn);
+
+ if (charging_rate > 0)
+ {
+ if (charging_rate < 1000000.0)
+ {
+ double charging_time = (1 / charging_rate) * NOISE_CAP_VOLTAGE_RANGE;
+ double discharging_time = (1 / charging_rate) * NOISE_CAP_VOLTAGE_RANGE;
+
+ LOG(1, ("SN76477 #%d: Noise filter frequency (5,6): %.0f Hz\n", sn->index, 1 / (charging_time + discharging_time)));
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: Noise filter frequency (5,6): Very Large (Filtering Disabled)\n", sn->index));
+ }
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: Noise filter frequency (5,6): N/A\n", sn->index));
+ }
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: Noise filter frequency (5,6): External (cap = %.2fV)\n", sn->index, sn->noise_filter_cap));
+ }
+}
+
+
+static void log_attack_time(struct SN76477 *sn)
+{
+ if (!sn->attack_decay_cap_voltage_ext)
+ {
+ if (compute_attack_decay_cap_charging_rate(sn) > 0)
+ {
+ LOG(1, ("SN76477 #%d: Attack time (8,10): %.4f sec\n", sn->index, AD_CAP_VOLTAGE_RANGE * (1 / compute_attack_decay_cap_charging_rate(sn))));
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: Attack time (8,10): N/A\n", sn->index));
+ }
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: Attack time (8,10): External (cap = %.2fV)\n", sn->index, sn->attack_decay_cap_voltage));
+ }
+}
+
+
+static void log_decay_time(struct SN76477 *sn)
+{
+ if (!sn->attack_decay_cap_voltage_ext)
+ {
+ if (compute_attack_decay_cap_discharging_rate(sn) > 0)
+ {
+ LOG(1, ("SN76477 #%d: Decay time (7,8): %.4f sec\n", sn->index, AD_CAP_VOLTAGE_RANGE * (1 / compute_attack_decay_cap_discharging_rate(sn))));
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: Decay time (8,10): N/A\n", sn->index));
+ }
+ }
+ else
+ {
+ LOG(1, ("SN76477 #%d: Decay time (7, 8): External (cap = %.2fV)\n", sn->index, sn->attack_decay_cap_voltage));
+ }
+}
+
+
+static void log_voltage_out(struct SN76477 *sn)
+{
+ LOG(1, ("SN76477 #%d: Voltage OUT range (11,12): %.2fV - %.2fV (clips above %.2fV)\n",
+ sn->index,
+ OUT_CENTER_LEVEL_VOLTAGE + compute_center_to_peak_voltage_out(sn) * out_neg_gain[(int)(AD_CAP_VOLTAGE_MAX * 10)],
+ OUT_CENTER_LEVEL_VOLTAGE + compute_center_to_peak_voltage_out(sn) * out_pos_gain[(int)(AD_CAP_VOLTAGE_MAX * 10)],
+ OUT_HIGH_CLIP_THRESHOLD));
+}
+
+
+static void log_complete_state(struct SN76477 *sn)
+{
+ log_enable_line(sn);
+ log_mixer_mode(sn);
+ log_envelope_mode(sn);
+ log_vco_mode(sn);
+ log_one_shot_time(sn);
+ log_slf_freq(sn);
+ log_vco_freq(sn);
+ log_vco_ext_voltage(sn);
+ log_vco_pitch_voltage(sn);
+ log_vco_duty_cycle(sn);
+ log_noise_filter_freq(sn);
+ log_noise_gen_freq(sn);
+ log_attack_time(sn);
+ log_decay_time(sn);
+ log_voltage_out(sn);
+}
+
+
+
+/*****************************************************************************
+ *
+ * .WAV file functions
+ *
+ *****************************************************************************/
+
+#if LOG_WAV
+
+#include "wavwrite.h"
+
+
+static void open_wav_file(struct SN76477 *sn)
+{
+ char wav_file_name[30];
+
+ sprintf(wav_file_name, LOG_WAV_FILE_NAME, sn->index);
+ sn->file = wav_open(wav_file_name, sn->sample_rate, 2);
+
+ LOG(1, ("SN76477 #%d: Logging output: %s\n", sn->index, wav_file_name));
+}
+
+
+static void close_wav_file(struct SN76477 *sn)
+{
+ wav_close(sn->file);
+}
+
+
+static void add_wav_data(struct SN76477 *sn, INT16 data_l, INT16 data_r)
+{
+ wav_add_data_16lr(sn->file, &data_l, &data_r, 1);
+}
+
+#endif
+
+
+
+/*****************************************************************************
+ *
+ * Noise generator
+ *
+ *****************************************************************************/
+
+static void intialize_noise(struct SN76477 *sn)
+{
+ sn->rng = 0;
+}
+
+
+INLINE UINT32 generate_next_real_noise_bit(struct SN76477 *sn)
+{
+ UINT32 out = ((sn->rng >> 28) & 1) ^ ((sn->rng >> 0) & 1);
+
+ /* if bits 0-4 and 28 are all zero then force the output to 1 */
+ if ((sn->rng & 0x1000001f) == 0)
+ {
+ out = 1;
+ }
+
+ sn->rng = (sn->rng >> 1) | (out << 30);
+
+ return out;
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set enable input
+ *
+ *****************************************************************************/
+
+static void _SN76477_enable_w(struct SN76477 *sn, UINT32 data)
+{
+ sn->enable = data;
+
+ /* if falling edge */
+ if (!sn->enable)
+ {
+ /* start the attack phase */
+ sn->attack_decay_cap_voltage = AD_CAP_VOLTAGE_MIN;
+
+ /* one-shot runs regardless of envelope mode */
+ sn->one_shot_running_ff = 1;
+ }
+}
+
+
+static void SN76477_test_enable_w(struct SN76477 *sn, UINT32 data)
+{
+ if (data != sn->enable)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_enable_w(sn, data);
+
+ log_enable_line(sn);
+ }
+}
+
+
+void SN76477_enable_w(int chip, UINT32 data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_BOOLEAN;
+
+ SN76477_test_enable_w(sn, data);
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set mixer select inputs
+ *
+ *****************************************************************************/
+
+static void _SN76477_mixer_a_w(struct SN76477 *sn, UINT32 data)
+{
+ sn->mixer_mode = (sn->mixer_mode & ~0x01) | (data << 0);
+}
+
+
+void SN76477_mixer_a_w(int chip, UINT32 data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_BOOLEAN;
+
+ if (data != ((sn->mixer_mode >> 0) & 0x01))
+ {
+ stream_update(sn->channel);
+
+ _SN76477_mixer_a_w(sn, data);
+
+ log_mixer_mode(sn);
+ }
+#endif
+}
+
+
+static void _SN76477_mixer_b_w(struct SN76477 *sn, UINT32 data)
+{
+ sn->mixer_mode = (sn->mixer_mode & ~0x02) | (data << 1);
+}
+
+
+void SN76477_mixer_b_w(int chip, UINT32 data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_BOOLEAN;
+
+ if (data != ((sn->mixer_mode >> 1) & 0x01))
+ {
+ stream_update(sn->channel);
+
+ _SN76477_mixer_b_w(sn, data);
+
+ log_mixer_mode(sn);
+ }
+#endif
+}
+
+
+static void _SN76477_mixer_c_w(struct SN76477 *sn, UINT32 data)
+{
+ sn->mixer_mode = (sn->mixer_mode & ~0x04) | (data << 2);
+}
+
+
+void SN76477_mixer_c_w(int chip, UINT32 data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_BOOLEAN;
+
+ if (data != ((sn->mixer_mode >> 2) & 0x01))
+ {
+ stream_update(sn->channel);
+
+ _SN76477_mixer_c_w(sn, data);
+
+ log_mixer_mode(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set envelope select inputs
+ *
+ *****************************************************************************/
+
+static void _SN76477_envelope_1_w(struct SN76477 *sn, UINT32 data)
+{
+ sn->envelope_mode = (sn->envelope_mode & ~0x01) | (data << 0);
+}
+
+
+void SN76477_envelope_1_w(int chip, UINT32 data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_BOOLEAN;
+
+ if (data != ((sn->envelope_mode >> 0) & 0x01))
+ {
+ stream_update(sn->channel);
+
+ _SN76477_envelope_1_w(sn, data);
+
+ log_envelope_mode(sn);
+ }
+#endif
+}
+
+
+static void _SN76477_envelope_2_w(struct SN76477 *sn, UINT32 data)
+{
+ sn->envelope_mode = (sn->envelope_mode & ~0x02) | (data << 1);
+}
+
+
+void SN76477_envelope_2_w(int chip, UINT32 data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_BOOLEAN;
+
+ if (data != ((sn->envelope_mode >> 1) & 0x01))
+ {
+ stream_update(sn->channel);
+
+ _SN76477_envelope_2_w(sn, data);
+
+ log_envelope_mode(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set VCO select input
+ *
+ *****************************************************************************/
+
+static void _SN76477_vco_w(struct SN76477 *sn, UINT32 data)
+{
+ sn->vco_mode = data;
+}
+
+
+void SN76477_vco_w(int chip, UINT32 data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_BOOLEAN;
+
+ if (data != sn->vco_mode)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_vco_w(sn, data);
+
+ log_vco_mode(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set one-shot resistor
+ *
+ *****************************************************************************/
+
+static void _SN76477_one_shot_res_w(struct SN76477 *sn, double data)
+{
+ sn->one_shot_res = data;
+}
+
+
+void SN76477_one_shot_res_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->one_shot_res)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_one_shot_res_w(sn, data);
+
+ log_one_shot_time(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set one-shot capacitor
+ *
+ *****************************************************************************/
+
+static void _SN76477_one_shot_cap_w(struct SN76477 *sn, double data)
+{
+ sn->one_shot_cap = data;
+}
+
+
+void SN76477_one_shot_cap_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->one_shot_cap)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_one_shot_cap_w(sn, data);
+
+ log_one_shot_time(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set the voltage on the one-shot capacitor
+ *
+ *****************************************************************************/
+
+void SN76477_one_shot_cap_voltage_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_CAP_VOLTAGE;
+
+ if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT)
+ {
+ /* switch to internal, if not already */
+ if (sn->one_shot_cap_voltage_ext)
+ {
+ stream_update(sn->channel);
+
+ sn->one_shot_cap_voltage_ext = 0;
+
+ log_one_shot_time(sn);
+ }
+ }
+ else
+ {
+ /* set the voltage on the cap */
+ if (!sn->one_shot_cap_voltage_ext || (data != sn->one_shot_cap_voltage))
+ {
+ stream_update(sn->channel);
+
+ sn->one_shot_cap_voltage_ext = 1;
+ sn->one_shot_cap_voltage = data;
+
+ log_one_shot_time(sn);
+ }
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set SLF resistor
+ *
+ *****************************************************************************/
+
+static void _SN76477_slf_res_w(struct SN76477 *sn, double data)
+{
+ sn->slf_res = data;
+}
+
+
+void SN76477_slf_res_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->slf_res)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_slf_res_w(sn, data);
+
+ log_slf_freq(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set SLF capacitor
+ *
+ *****************************************************************************/
+
+static void _SN76477_slf_cap_w(struct SN76477 *sn, double data)
+{
+ sn->slf_cap = data;
+}
+
+
+void SN76477_slf_cap_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->slf_cap)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_slf_cap_w(sn, data);
+
+ log_slf_freq(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set the voltage on the SLF capacitor
+ *
+ * This is an alternate way of controlling the VCO as described in the book
+ *
+ *****************************************************************************/
+
+void SN76477_slf_cap_voltage_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_CAP_VOLTAGE;
+
+ if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT)
+ {
+ /* switch to internal, if not already */
+ if (sn->slf_cap_voltage_ext)
+ {
+ stream_update(sn->channel);
+
+ sn->slf_cap_voltage_ext = 0;
+
+ log_slf_freq(sn);
+ }
+ }
+ else
+ {
+ /* set the voltage on the cap */
+ if (!sn->slf_cap_voltage_ext || (data != sn->slf_cap_voltage))
+ {
+ stream_update(sn->channel);
+
+ sn->slf_cap_voltage_ext = 1;
+ sn->slf_cap_voltage = data;
+
+ log_slf_freq(sn);
+ }
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set VCO resistor
+ *
+ *****************************************************************************/
+
+static void _SN76477_vco_res_w(struct SN76477 *sn, double data)
+{
+ sn->vco_res = data;
+}
+
+
+void SN76477_vco_res_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->vco_res)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_vco_res_w(sn, data);
+
+ log_vco_freq(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set VCO capacitor
+ *
+ *****************************************************************************/
+
+static void _SN76477_vco_cap_w(struct SN76477 *sn, double data)
+{
+ sn->vco_cap = data;
+}
+
+
+void SN76477_vco_cap_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->vco_cap)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_vco_cap_w(sn, data);
+
+ log_vco_freq(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set the voltage on the VCO capacitor
+ *
+ *****************************************************************************/
+
+void SN76477_vco_cap_voltage_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_CAP_VOLTAGE;
+
+ if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT)
+ {
+ /* switch to internal, if not already */
+ if (sn->vco_cap_voltage_ext)
+ {
+ stream_update(sn->channel);
+
+ sn->vco_cap_voltage_ext = 0;
+
+ log_vco_freq(sn);
+ }
+ }
+ else
+ {
+ /* set the voltage on the cap */
+ if (!sn->vco_cap_voltage_ext || (data != sn->vco_cap_voltage))
+ {
+ stream_update(sn->channel);
+
+ sn->vco_cap_voltage_ext = 1;
+ sn->vco_cap_voltage = data;
+
+ log_vco_freq(sn);
+ }
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set VCO voltage
+ *
+ *****************************************************************************/
+
+static void _SN76477_vco_voltage_w(struct SN76477 *sn, double data)
+{
+ sn->vco_voltage = data;
+}
+
+
+void SN76477_vco_voltage_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_VOLTAGE;
+
+ if (data != sn->vco_voltage)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_vco_voltage_w(sn, data);
+
+ log_vco_ext_voltage(sn);
+ log_vco_duty_cycle(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set pitch voltage
+ *
+ *****************************************************************************/
+
+static void _SN76477_pitch_voltage_w(struct SN76477 *sn, double data)
+{
+ sn->pitch_voltage = data;
+}
+
+
+void SN76477_pitch_voltage_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_VOLTAGE;
+
+ if (data != sn->pitch_voltage)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_pitch_voltage_w(sn, data);
+
+ log_vco_pitch_voltage(sn);
+ log_vco_duty_cycle(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set noise external clock
+ *
+ *****************************************************************************/
+
+void SN76477_noise_clock_w(int chip, UINT32 data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_BOOLEAN;
+
+ if (data != sn->noise_clock)
+ {
+ sn->noise_clock = data;
+
+ /* on the rising edge shift generate next value,
+ if external control is enabled */
+ if (sn->noise_clock && sn->noise_clock_ext)
+ {
+ stream_update(sn->channel);
+
+ sn->real_noise_bit_ff = generate_next_real_noise_bit(sn);
+ }
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set noise clock resistor
+ *
+ *****************************************************************************/
+
+static void _SN76477_noise_clock_res_w(struct SN76477 *sn, double data)
+{
+ if (data == 0)
+ {
+ sn->noise_clock_ext = 1;
+ }
+ else
+ {
+ sn->noise_clock_ext = 0;
+
+ sn->noise_clock_res = data;
+ }
+}
+
+
+void SN76477_noise_clock_res_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (((data == 0) && !sn->noise_clock_ext) ||
+ ((data != 0) && (data != sn->noise_clock_res)))
+ {
+ stream_update(sn->channel);
+
+ _SN76477_noise_clock_res_w(sn, data);
+
+ log_noise_gen_freq(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set noise filter resistor
+ *
+ *****************************************************************************/
+
+static void _SN76477_noise_filter_res_w(struct SN76477 *sn, double data)
+{
+ sn->noise_filter_res = data;
+}
+
+
+void SN76477_noise_filter_res_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->noise_filter_res)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_noise_filter_res_w(sn, data);
+
+ log_noise_filter_freq(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set noise filter capacitor
+ *
+ *****************************************************************************/
+
+static void _SN76477_noise_filter_cap_w(struct SN76477 *sn, double data)
+{
+ sn->noise_filter_cap = data;
+}
+
+
+void SN76477_noise_filter_cap_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->noise_filter_cap)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_noise_filter_cap_w(sn, data);
+
+ log_noise_filter_freq(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set the voltage on the noise filter capacitor
+ *
+ *****************************************************************************/
+
+void SN76477_noise_filter_cap_voltage_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_CAP_VOLTAGE;
+
+ if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT)
+ {
+ /* switch to internal, if not already */
+ if (sn->noise_filter_cap_voltage_ext)
+ {
+ stream_update(sn->channel);
+
+ sn->noise_filter_cap_voltage_ext = 0;
+
+ log_noise_filter_freq(sn);
+ }
+ }
+ else
+ {
+ /* set the voltage on the cap */
+ if (!sn->noise_filter_cap_voltage_ext || (data != sn->noise_filter_cap_voltage))
+ {
+ stream_update(sn->channel);
+
+ sn->noise_filter_cap_voltage_ext = 1;
+ sn->noise_filter_cap_voltage = data;
+
+ log_noise_filter_freq(sn);
+ }
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set attack resistor
+ *
+ *****************************************************************************/
+
+static void _SN76477_attack_res_w(struct SN76477 *sn, double data)
+{
+ sn->attack_res = data;
+}
+
+
+void SN76477_attack_res_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->attack_res)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_attack_res_w(sn, data);
+
+ log_attack_time(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set decay resistor
+ *
+ *****************************************************************************/
+
+static void _SN76477_decay_res_w(struct SN76477 *sn, double data)
+{
+ sn->decay_res = data;
+}
+
+
+void SN76477_decay_res_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->decay_res)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_decay_res_w(sn, data);
+
+ log_decay_time(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set attack/decay capacitor
+ *
+ *****************************************************************************/
+
+static void _SN76477_attack_decay_cap_w(struct SN76477 *sn, double data)
+{
+ sn->attack_decay_cap = data;
+}
+
+
+void SN76477_attack_decay_cap_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->attack_decay_cap)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_attack_decay_cap_w(sn, data);
+
+ log_attack_time(sn);
+ log_decay_time(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set the voltage on the attack/decay capacitor
+ *
+ *****************************************************************************/
+
+void SN76477_attack_decay_cap_voltage_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_CAP_VOLTAGE;
+
+ if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT)
+ {
+ /* switch to internal, if not already */
+ if (sn->attack_decay_cap_voltage_ext)
+ {
+ stream_update(sn->channel);
+
+ sn->attack_decay_cap_voltage_ext = 0;
+
+ log_attack_time(sn);
+ log_decay_time(sn);
+ }
+ }
+ else
+ {
+ /* set the voltage on the cap */
+ if (!sn->attack_decay_cap_voltage_ext || (data != sn->attack_decay_cap_voltage))
+ {
+ stream_update(sn->channel);
+
+ sn->attack_decay_cap_voltage_ext = 1;
+ sn->attack_decay_cap_voltage = data;
+
+ log_attack_time(sn);
+ log_decay_time(sn);
+ }
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set amplitude resistor
+ *
+ *****************************************************************************/
+
+static void _SN76477_amplitude_res_w(struct SN76477 *sn, double data)
+{
+ sn->amplitude_res = data;
+}
+
+
+void SN76477_amplitude_res_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->amplitude_res)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_amplitude_res_w(sn, data);
+
+ log_voltage_out(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Set feedback resistor
+ *
+ *****************************************************************************/
+
+static void _SN76477_feedback_res_w(struct SN76477 *sn, double data)
+{
+ sn->feedback_res = data;
+}
+
+
+void SN76477_feedback_res_w(int chip, double data)
+{
+#if TEST_MODE == 0
+ struct SN76477 *sn = sndti_token(SOUND_SN76477, chip);
+
+ CHECK_CHIP_NUM_AND_POSITIVE;
+
+ if (data != sn->feedback_res)
+ {
+ stream_update(sn->channel);
+
+ _SN76477_feedback_res_w(sn, data);
+
+ log_voltage_out(sn);
+ }
+#endif
+}
+
+
+
+/*****************************************************************************
+ *
+ * Sample generation
+ *
+ *****************************************************************************/
+
+static void SN76477_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ double one_shot_cap_charging_step;
+ double one_shot_cap_discharging_step;
+ double slf_cap_charging_step;
+ double slf_cap_discharging_step;
+ double vco_duty_cycle_multiplier;
+ double vco_cap_charging_step;
+ double vco_cap_discharging_step;
+ double vco_cap_voltage_max;
+ UINT32 noise_gen_freq;
+ double noise_filter_cap_charging_step;
+ double noise_filter_cap_discharging_step;
+ double attack_decay_cap_charging_step;
+ double attack_decay_cap_discharging_step;
+ int attack_decay_cap_charging;
+ double voltage_out;
+ double center_to_peak_voltage_out;
+
+ struct SN76477 *sn = param;
+ stream_sample_t *buffer = _buffer[0];
+
+
+#if TEST_MODE
+ static int recursing = 0; /* we need to prevent recursion since enable_w calls stream_update */
+
+ if (input_code_pressed_once(KEYCODE_SPACE) && !recursing)
+ {
+ recursing = 1;
+
+ sound_global_enable(1);
+ SN76477_test_enable_w(sn, !sn->enable);
+ }
+
+ recursing = 0;
+#endif
+
+ /* compute charging values, doing it here ensures that we always use the latest values */
+ one_shot_cap_charging_step = compute_one_shot_cap_charging_rate(sn) / sn->sample_rate;
+ one_shot_cap_discharging_step = compute_one_shot_cap_discharging_rate(sn) / sn->sample_rate;
+
+ slf_cap_charging_step = compute_slf_cap_charging_rate(sn) / sn->sample_rate;
+ slf_cap_discharging_step = compute_slf_cap_discharging_rate(sn) / sn->sample_rate;
+
+ vco_duty_cycle_multiplier = (1 - compute_vco_duty_cycle(sn)) * 2;
+ vco_cap_charging_step = compute_vco_cap_charging_discharging_rate(sn) / vco_duty_cycle_multiplier / sn->sample_rate;
+ vco_cap_discharging_step = compute_vco_cap_charging_discharging_rate(sn) * vco_duty_cycle_multiplier / sn->sample_rate;
+
+ noise_filter_cap_charging_step = compute_noise_filter_cap_charging_rate(sn) / sn->sample_rate;
+ noise_filter_cap_discharging_step = compute_noise_filter_cap_discharging_rate(sn) / sn->sample_rate;
+ noise_gen_freq = compute_noise_gen_freq(sn);
+
+ attack_decay_cap_charging_step = compute_attack_decay_cap_charging_rate(sn) / sn->sample_rate;
+ attack_decay_cap_discharging_step = compute_attack_decay_cap_discharging_rate(sn) / sn->sample_rate;
+
+ center_to_peak_voltage_out = compute_center_to_peak_voltage_out(sn);
+
+
+ /* process 'length' number of samples */
+ while (length--)
+ {
+ /* update the one-shot cap voltage */
+ if (!sn->one_shot_cap_voltage_ext)
+ {
+ if (sn->one_shot_running_ff)
+ {
+ /* charging */
+ sn->one_shot_cap_voltage = min(sn->one_shot_cap_voltage + one_shot_cap_charging_step, ONE_SHOT_CAP_VOLTAGE_MAX);
+ }
+ else
+ {
+ /* discharging */
+ sn->one_shot_cap_voltage = max(sn->one_shot_cap_voltage - one_shot_cap_discharging_step, ONE_SHOT_CAP_VOLTAGE_MIN);
+ }
+ }
+
+ if (sn->one_shot_cap_voltage >= ONE_SHOT_CAP_VOLTAGE_MAX)
+ {
+ sn->one_shot_running_ff = 0;
+ }
+
+
+ /* update the SLF (super low frequency oscillator) */
+ if (!sn->slf_cap_voltage_ext)
+ {
+ /* internal */
+ if (!sn->slf_out_ff)
+ {
+ /* charging */
+ sn->slf_cap_voltage = min(sn->slf_cap_voltage + slf_cap_charging_step, SLF_CAP_VOLTAGE_MAX);
+ }
+ else
+ {
+ /* discharging */
+ sn->slf_cap_voltage = max(sn->slf_cap_voltage - slf_cap_discharging_step, SLF_CAP_VOLTAGE_MIN);
+ }
+ }
+
+ if (sn->slf_cap_voltage >= SLF_CAP_VOLTAGE_MAX)
+ {
+ sn->slf_out_ff = 1;
+ }
+ else if (sn->slf_cap_voltage <= SLF_CAP_VOLTAGE_MIN)
+ {
+ sn->slf_out_ff = 0;
+ }
+
+
+ /* update the VCO (voltage controlled oscillator) */
+ if (sn->vco_mode)
+ {
+ /* VCO is controlled by SLF */
+ vco_cap_voltage_max = sn->slf_cap_voltage + VCO_TO_SLF_VOLTAGE_DIFF;
+ }
+ else
+ {
+ /* VCO is controlled by external voltage */
+ vco_cap_voltage_max = sn->vco_voltage + VCO_TO_SLF_VOLTAGE_DIFF;
+ }
+
+ if (!sn->vco_cap_voltage_ext)
+ {
+ if (!sn->vco_out_ff)
+ {
+ /* charging */
+ sn->vco_cap_voltage = min(sn->vco_cap_voltage + vco_cap_charging_step, vco_cap_voltage_max);
+ }
+ else
+ {
+ /* discharging */
+ sn->vco_cap_voltage = max(sn->vco_cap_voltage - vco_cap_discharging_step, VCO_CAP_VOLTAGE_MIN);
+ }
+ }
+
+ if (sn->vco_cap_voltage >= vco_cap_voltage_max)
+ {
+ if (!sn->vco_out_ff)
+ {
+ /* positive edge */
+ sn->vco_alt_pos_edge_ff = !sn->vco_alt_pos_edge_ff;
+ }
+
+ sn->vco_out_ff = 1;
+ }
+ else if (sn->vco_cap_voltage <= VCO_CAP_VOLTAGE_MIN)
+ {
+ sn->vco_out_ff = 0;
+ }
+
+
+ /* update the noise generator */
+ while (!sn->noise_clock_ext && (sn->noise_gen_count <= noise_gen_freq))
+ {
+ sn->noise_gen_count = sn->noise_gen_count + sn->sample_rate;
+
+ sn->real_noise_bit_ff = generate_next_real_noise_bit(sn);
+ }
+
+ sn->noise_gen_count = sn->noise_gen_count - noise_gen_freq;
+
+
+ /* update the noise filter */
+ if (!sn->noise_filter_cap_voltage_ext)
+ {
+ /* internal */
+ if (sn->real_noise_bit_ff)
+ {
+ /* charging */
+ sn->noise_filter_cap_voltage = min(sn->noise_filter_cap_voltage + noise_filter_cap_charging_step, NOISE_CAP_VOLTAGE_MAX);
+ }
+ else
+ {
+ /* discharging */
+ sn->noise_filter_cap_voltage = max(sn->noise_filter_cap_voltage - noise_filter_cap_discharging_step, NOISE_CAP_VOLTAGE_MIN);
+ }
+ }
+
+ /* check the thresholds */
+ if (sn->noise_filter_cap_voltage >= NOISE_CAP_HIGH_THRESHOLD)
+ {
+ sn->filtered_noise_bit_ff = 0;
+ }
+ else if (sn->noise_filter_cap_voltage <= NOISE_CAP_LOW_THRESHOLD)
+ {
+ sn->filtered_noise_bit_ff = 1;
+ }
+
+
+ /* based on the envelope mode figure out the attack/decay phase we are in */
+ switch (sn->envelope_mode)
+ {
+ case 0: /* VCO */
+ attack_decay_cap_charging = sn->vco_out_ff;
+ break;
+
+ case 1: /* one-shot */
+ attack_decay_cap_charging = sn->one_shot_running_ff;
+ break;
+
+ case 2:
+ default: /* mixer only */
+ attack_decay_cap_charging = 1; /* never a decay phase */
+ break;
+
+ case 3: /* VCO with alternating polarity */
+ attack_decay_cap_charging = sn->vco_out_ff && sn->vco_alt_pos_edge_ff;
+ break;
+ }
+
+
+ /* update a/d cap voltage */
+ if (!sn->attack_decay_cap_voltage_ext)
+ {
+ if (attack_decay_cap_charging)
+ {
+ if (attack_decay_cap_charging_step > 0)
+ {
+ sn->attack_decay_cap_voltage = min(sn->attack_decay_cap_voltage + attack_decay_cap_charging_step, AD_CAP_VOLTAGE_MAX);
+ }
+ else
+ {
+ /* no attack, voltage to max instantly */
+ sn->attack_decay_cap_voltage = AD_CAP_VOLTAGE_MAX;
+ }
+ }
+ else
+ {
+ /* discharging */
+ if (attack_decay_cap_discharging_step > 0)
+ {
+ sn->attack_decay_cap_voltage = max(sn->attack_decay_cap_voltage - attack_decay_cap_discharging_step, AD_CAP_VOLTAGE_MIN);
+ }
+ else
+ {
+ /* no decay, voltage to min instantly */
+ sn->attack_decay_cap_voltage = AD_CAP_VOLTAGE_MIN;
+ }
+ }
+ }
+
+
+ /* mix the output, if enabled, or not saturated by the VCO */
+ if (!sn->enable && (sn->vco_cap_voltage <= VCO_CAP_VOLTAGE_MAX))
+ {
+ UINT32 out;
+
+ /* enabled */
+ switch (sn->mixer_mode)
+ {
+ case 0: /* VCO */
+ out = sn->vco_out_ff;
+ break;
+
+ case 1: /* SLF */
+ out = sn->slf_out_ff;
+ break;
+
+ case 2: /* noise */
+ out = sn->filtered_noise_bit_ff;
+ break;
+
+ case 3: /* VCO and noise */
+ out = sn->vco_out_ff & sn->filtered_noise_bit_ff;
+ break;
+
+ case 4: /* SLF and noise */
+ out = sn->slf_out_ff & sn->filtered_noise_bit_ff;
+ break;
+
+ case 5: /* VCO, SLF and noise */
+ out = sn->vco_out_ff & sn->slf_out_ff & sn->filtered_noise_bit_ff;
+ break;
+
+ case 6: /* VCO and SLF */
+ out = sn->vco_out_ff & sn->slf_out_ff;
+ break;
+
+ case 7: /* inhibit */
+ default:
+ out = 0;
+ break;
+ }
+
+ /* determine the OUT voltage from the attack/delay cap voltage and clip it */
+ if (out)
+ {
+ voltage_out = OUT_CENTER_LEVEL_VOLTAGE + center_to_peak_voltage_out * out_pos_gain[(int)(sn->attack_decay_cap_voltage * 10)],
+ voltage_out = min(voltage_out, OUT_HIGH_CLIP_THRESHOLD);
+ }
+ else
+ {
+ voltage_out = OUT_CENTER_LEVEL_VOLTAGE + center_to_peak_voltage_out * out_neg_gain[(int)(sn->attack_decay_cap_voltage * 10)],
+ voltage_out = max(voltage_out, OUT_LOW_CLIP_THRESHOLD);
+ }
+ }
+ else
+ {
+ /* disabled */
+ voltage_out = OUT_CENTER_LEVEL_VOLTAGE;
+ }
+
+
+ /* convert it to a signed 16-bit sample,
+ -32767 = OUT_LOW_CLIP_THRESHOLD
+ 0 = OUT_CENTER_LEVEL_VOLTAGE
+ 32767 = 2 * OUT_CENTER_LEVEL_VOLTAGE + OUT_LOW_CLIP_THRESHOLD
+
+ / Vout - Vmin \
+ sample = | ----------- - 1 | * 32767
+ \ Vcen - Vmin /
+ */
+ *buffer++ = (((voltage_out - OUT_LOW_CLIP_THRESHOLD) / (OUT_CENTER_LEVEL_VOLTAGE - OUT_LOW_CLIP_THRESHOLD)) - 1) * 32767;
+
+#if LOG_WAV
+#if LOG_WAV_ENABLED_ONLY
+ if (!sn->enable)
+#endif
+ {
+ INT16 log_data_l;
+ INT16 log_data_r;
+
+#if LOG_WAV_VALUE_L == 0
+ log_data_l = LOG_WAV_GAIN_FACTOR * voltage_out;
+#elif LOG_WAV_VALUE_L == 1
+ log_data_l = LOG_WAV_GAIN_FACTOR * sn->enable;
+#elif LOG_WAV_VALUE_L == 2
+ log_data_l = LOG_WAV_GAIN_FACTOR * sn->one_shot_cap_voltage;
+#elif LOG_WAV_VALUE_L == 3
+ log_data_l = LOG_WAV_GAIN_FACTOR * sn->attack_decay_cap_voltage;
+#elif LOG_WAV_VALUE_L == 4
+ log_data_l = LOG_WAV_GAIN_FACTOR * sn->slf_cap_voltage;
+#elif LOG_WAV_VALUE_L == 5
+ log_data_l = LOG_WAV_GAIN_FACTOR * sn->vco_cap_voltage;
+#elif LOG_WAV_VALUE_L == 6
+ log_data_l = LOG_WAV_GAIN_FACTOR * sn->noise_filter_cap_voltage;
+#endif
+
+#if LOG_WAV_VALUE_R == 0
+ log_data_r = LOG_WAV_GAIN_FACTOR * voltage_out;
+#elif LOG_WAV_VALUE_R == 1
+ log_data_r = LOG_WAV_GAIN_FACTOR * sn->enable;
+#elif LOG_WAV_VALUE_R == 2
+ log_data_r = LOG_WAV_GAIN_FACTOR * sn->one_shot_cap_voltage;
+#elif LOG_WAV_VALUE_R == 3
+ log_data_r = LOG_WAV_GAIN_FACTOR * sn->attack_decay_cap_voltage;
+#elif LOG_WAV_VALUE_R == 4
+ log_data_r = LOG_WAV_GAIN_FACTOR * sn->slf_cap_voltage;
+#elif LOG_WAV_VALUE_R == 5
+ log_data_r = LOG_WAV_GAIN_FACTOR * sn->vco_cap_voltage;
+#elif LOG_WAV_VALUE_R == 6
+ log_data_r = LOG_WAV_GAIN_FACTOR * sn->noise_filter_cap_voltage;
+#endif
+ add_wav_data(sn, log_data_l, log_data_r);
+ }
+#endif
+ }
+}
+
+
+
+/*****************************************************************************
+ *
+ * State saving
+ *
+ *****************************************************************************/
+
+static void state_save_register(struct SN76477 *sn)
+{
+ state_save_register_item("sn76744", sn->index, sn->enable);
+ state_save_register_item("sn76744", sn->index, sn->envelope_mode);
+ state_save_register_item("sn76744", sn->index, sn->vco_mode);
+ state_save_register_item("sn76744", sn->index, sn->mixer_mode);
+
+ state_save_register_item("sn76744", sn->index, sn->one_shot_res);
+ state_save_register_item("sn76744", sn->index, sn->one_shot_cap);
+ state_save_register_item("sn76744", sn->index, sn->one_shot_cap_voltage_ext);
+
+ state_save_register_item("sn76744", sn->index, sn->slf_res);
+ state_save_register_item("sn76744", sn->index, sn->slf_cap);
+ state_save_register_item("sn76744", sn->index, sn->slf_cap_voltage_ext);
+
+ state_save_register_item("sn76744", sn->index, sn->vco_voltage);
+ state_save_register_item("sn76744", sn->index, sn->vco_res);
+ state_save_register_item("sn76744", sn->index, sn->vco_cap);
+ state_save_register_item("sn76744", sn->index, sn->vco_cap_voltage_ext);
+
+ state_save_register_item("sn76744", sn->index, sn->noise_clock_res);
+ state_save_register_item("sn76744", sn->index, sn->noise_clock_ext);
+ state_save_register_item("sn76744", sn->index, sn->noise_clock);
+ state_save_register_item("sn76744", sn->index, sn->noise_filter_res);
+ state_save_register_item("sn76744", sn->index, sn->noise_filter_cap);
+ state_save_register_item("sn76744", sn->index, sn->noise_filter_cap_voltage_ext);
+
+ state_save_register_item("sn76744", sn->index, sn->attack_res);
+ state_save_register_item("sn76744", sn->index, sn->decay_res);
+ state_save_register_item("sn76744", sn->index, sn->attack_decay_cap);
+ state_save_register_item("sn76744", sn->index, sn->attack_decay_cap_voltage_ext);
+
+ state_save_register_item("sn76744", sn->index, sn->amplitude_res);
+ state_save_register_item("sn76744", sn->index, sn->feedback_res);
+ state_save_register_item("sn76744", sn->index, sn->pitch_voltage);
+
+ state_save_register_item("sn76744", sn->index, sn->one_shot_cap_voltage);
+ state_save_register_item("sn76744", sn->index, sn->one_shot_running_ff);
+
+ state_save_register_item("sn76744", sn->index, sn->slf_cap_voltage);
+ state_save_register_item("sn76744", sn->index, sn->slf_out_ff);
+
+ state_save_register_item("sn76744", sn->index, sn->vco_cap_voltage);
+ state_save_register_item("sn76744", sn->index, sn->vco_out_ff);
+ state_save_register_item("sn76744", sn->index, sn->vco_alt_pos_edge_ff);
+
+ state_save_register_item("sn76744", sn->index, sn->noise_filter_cap_voltage);
+ state_save_register_item("sn76744", sn->index, sn->real_noise_bit_ff);
+ state_save_register_item("sn76744", sn->index, sn->filtered_noise_bit_ff);
+ state_save_register_item("sn76744", sn->index, sn->noise_gen_count);
+
+ state_save_register_item("sn76744", sn->index, sn->attack_decay_cap_voltage);
+
+ state_save_register_item("sn76744", sn->index, sn->rng);
+}
+
+
+
+/*****************************************************************************
+ *
+ * Sound interface glue functions
+ *
+ *****************************************************************************/
+
+static void *sn76477_start(int sndindex, int clock, const void *config)
+{
+ struct SN76477 *sn;
+ struct SN76477interface *intf;
+
+
+#if TEST_MODE == 0
+ intf = (struct SN76477interface *)config;
+#else
+ intf = &test_interface;
+#endif
+
+
+ sn = auto_malloc(sizeof(*sn));
+ memset(sn, 0, sizeof(*sn));
+
+ sn->index = sndindex;
+
+ sn->channel = stream_create(0, 1, Machine->sample_rate, sn, SN76477_update);
+
+ if (clock > 0)
+ {
+ sn->sample_rate = clock;
+ }
+ else
+ {
+ sn->sample_rate = Machine->sample_rate;
+ }
+
+ intialize_noise(sn);
+
+ sndintrf_register_token(sn);
+
+ /* set up interface values */
+ _SN76477_enable_w(sn, intf->enable);
+ _SN76477_vco_w(sn, intf->vco);
+ _SN76477_mixer_a_w(sn, intf->mixer_a);
+ _SN76477_mixer_b_w(sn, intf->mixer_b);
+ _SN76477_mixer_c_w(sn, intf->mixer_c);
+ _SN76477_envelope_1_w(sn, intf->envelope_1);
+ _SN76477_envelope_2_w(sn, intf->envelope_2);
+ _SN76477_one_shot_res_w(sn, intf->one_shot_res);
+ _SN76477_one_shot_cap_w(sn, intf->one_shot_cap);
+ _SN76477_slf_res_w(sn, intf->slf_res);
+ _SN76477_slf_cap_w(sn, intf->slf_cap);
+ _SN76477_vco_res_w(sn, intf->vco_res);
+ _SN76477_vco_cap_w(sn, intf->vco_cap);
+ _SN76477_vco_voltage_w(sn, intf->vco_voltage);
+ _SN76477_noise_clock_res_w(sn, intf->noise_clock_res);
+ _SN76477_noise_filter_res_w(sn, intf->noise_filter_res);
+ _SN76477_noise_filter_cap_w(sn, intf->noise_filter_cap);
+ _SN76477_decay_res_w(sn, intf->decay_res);
+ _SN76477_attack_res_w(sn, intf->attack_res);
+ _SN76477_attack_decay_cap_w(sn, intf->attack_decay_cap);
+ _SN76477_amplitude_res_w(sn, intf->amplitude_res);
+ _SN76477_feedback_res_w(sn, intf->feedback_res);
+ _SN76477_pitch_voltage_w(sn, intf->pitch_voltage);
+
+ sn->one_shot_cap_voltage = ONE_SHOT_CAP_VOLTAGE_MIN;
+ sn->slf_cap_voltage = SLF_CAP_VOLTAGE_MIN;
+ sn->vco_cap_voltage = VCO_CAP_VOLTAGE_MIN;
+ sn->noise_filter_cap_voltage = NOISE_CAP_VOLTAGE_MIN;
+ sn->attack_decay_cap_voltage = AD_CAP_VOLTAGE_MIN;
+
+ state_save_register(sn);
+
+ log_complete_state(sn);
+
+#if LOG_WAV
+ open_wav_file(sn);
+#endif
+
+ return sn;
+}
+
+
+#if LOG_WAV
+static void sn76477_stop(void *token)
+{
+ struct SN76477 *sn = (struct SN76477 *)token;
+
+ close_wav_file(sn);
+}
+#endif
+
+
+void sn76477_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = sn76477_start; break;
+#if LOG_WAV
+ case SNDINFO_PTR_STOP: info->stop = sn76477_stop; break;
+#endif
+ case SNDINFO_STR_NAME: info->s = "SN76477"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Analog"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "2.1"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2007, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/sn76477.h b/src/emu/sound/sn76477.h
new file mode 100644
index 00000000000..d224cbe2ca8
--- /dev/null
+++ b/src/emu/sound/sn76477.h
@@ -0,0 +1,124 @@
+/*****************************************************************************
+
+ Texas Instruments SN76477 emulator
+
+ SN76477 pin layout. There is a corresponding interface variable with the
+ same name. The only exception is noise_clock which must be programmatically
+ set. The other pins have programmatic equivalents as well.
+ The name of the function is SN76477_<pinname>_w.
+ All capacitor functions can also specify a fixed voltage on the cap.
+ The name of this function is SN76477_<pinname>_voltage_w
+
+ +-------------------+
+ envelope_1 | 1 | | 28| envelope_2
+ | 2 GND - 27| mixer_c
+ noise_clock | 3 26| mixer_a
+ noise_clock_res | 4 25| mixer_b
+ noise_filter_res | 5 24| one_shot_res
+ noise_filter_cap | 6 23| one_shot_cap
+ decay_res | 7 22| vco
+ attack_decay_cap | 8 21| slf_cap
+ enable o| 9 20| slf_res
+ attack_res |10 19| pitch_voltage
+ amplitude_res |11 18| vco_res
+ feedback_res |12 17| vco_cap
+ |13 OUTPUT 16| vco_voltage
+ |14 Vcc +5V OUT 15|
+ +-------------------+
+
+ All resistor values in Ohms
+ All capacitor values in Farads
+ Use RES_K, RES_M and CAP_U, CAP_N, CAP_P macros in rescap.h to convert
+ magnitudes, eg. 220k = RES_K(220), 47nF = CAP_N(47)
+
+ *****************************************************************************/
+
+#ifndef SN76477_SOUND_H
+#define SN76477_SOUND_H
+
+#include "rescap.h"
+
+
+
+/*****************************************************************************
+ *
+ * Interface definition
+ *
+ *****************************************************************************/
+
+struct SN76477interface
+{
+ double noise_clock_res;
+ double noise_filter_res;
+ double noise_filter_cap;
+ double decay_res;
+ double attack_decay_cap;
+ double attack_res;
+ double amplitude_res;
+ double feedback_res;
+ double vco_voltage;
+ double vco_cap;
+ double vco_res;
+ double pitch_voltage;
+ double slf_res;
+ double slf_cap;
+ double one_shot_cap;
+ double one_shot_res;
+ UINT32 vco;
+ UINT32 mixer_a;
+ UINT32 mixer_b;
+ UINT32 mixer_c;
+ UINT32 envelope_1;
+ UINT32 envelope_2;
+ UINT32 enable;
+};
+
+
+
+/*****************************************************************************
+ *
+ * Functions to set a pin's value
+ *
+ *****************************************************************************/
+
+/* these functions take 0 or 1 as a logic input */
+void SN76477_enable_w(int chip, UINT32 data); /* active LO, 0 = enabled, 1 = disabled */
+void SN76477_mixer_a_w(int chip, UINT32 data);
+void SN76477_mixer_b_w(int chip, UINT32 data);
+void SN76477_mixer_c_w(int chip, UINT32 data);
+void SN76477_envelope_1_w(int chip, UINT32 data);
+void SN76477_envelope_2_w(int chip, UINT32 data);
+void SN76477_vco_w(int chip, UINT32 data); /* 0 = external, 1 = controlled by SLF */
+void SN76477_noise_clock_w(int chip, UINT32 data); /* noise clock write, iff noise_clock_res = 0 */
+
+/* these functions take a resistor value in Ohms */
+void SN76477_one_shot_res_w(int chip, double data);
+void SN76477_slf_res_w(int chip, double data);
+void SN76477_vco_res_w(int chip, double data);
+void SN76477_noise_clock_res_w(int chip, double data); /* = 0 if the noise gen is clocked via noise_clock */
+void SN76477_noise_filter_res_w(int chip, double data);
+void SN76477_decay_res_w(int chip, double data);
+void SN76477_attack_res_w(int chip, double data);
+void SN76477_amplitude_res_w(int chip, double data);
+void SN76477_feedback_res_w(int chip, double data);
+
+/* these functions take a capacitor value in Farads or the voltage on it in Volts */
+#define SN76477_EXTERNAL_VOLTAGE_DISCONNECT (-1.0) /* indicates that the voltage in internally computed,
+ can be used in all the functions that take a
+ voltage on a capacitor */
+void SN76477_one_shot_cap_w(int chip, double data);
+void SN76477_one_shot_cap_voltage_w(int chip, double data);
+void SN76477_slf_cap_w(int chip, double data);
+void SN76477_slf_cap_voltage_w(int chip, double data);
+void SN76477_vco_cap_w(int chip, double data);
+void SN76477_vco_cap_voltage_w(int chip, double data);
+void SN76477_noise_filter_cap_w(int chip, double data);
+void SN76477_noise_filter_cap_voltage_w(int chip, double data);
+void SN76477_attack_decay_cap_w(int chip, double data);
+void SN76477_attack_decay_cap_voltage_w(int chip, double data);
+
+/* these functions take a voltage value in Volts */
+void SN76477_vco_voltage_w(int chip, double data);
+void SN76477_pitch_voltage_w(int chip, double data);
+
+#endif
diff --git a/src/emu/sound/sn76496.c b/src/emu/sound/sn76496.c
new file mode 100644
index 00000000000..d03e226798b
--- /dev/null
+++ b/src/emu/sound/sn76496.c
@@ -0,0 +1,456 @@
+/***************************************************************************
+
+ sn76496.c
+ by Nicola Salmoria
+
+ Routines to emulate the:
+ Texas Instruments SN76489, SN76489A, SN76494/SN76496
+ ( Also known as, or at least compatible with, the TMS9919.)
+ and the Sega 'PSG' used on the Master System, Game Gear, and Megadrive/Genesis
+ This chip is known as the Programmable Sound Generator, or PSG, and is a 4
+ channel sound generator, with three squarewave channels and a noise/arbitrary
+ duty cycle channel.
+
+ Noise emulation for all chips should be accurate:
+ SN76489 uses a 15-bit shift register with taps on bits D and E, output on /E
+ * It uses a 15-bit ring buffer for periodic noise/arbitrary duty cycle.
+ SN76489A uses a 16-bit shift register with taps on bits D and F, output on F
+ * It uses a 16-bit ring buffer for periodic noise/arbitrary duty cycle.
+ SN76494 and SN76496 are PROBABLY identical in operation to the SN76489A
+ * They have an audio input line which is mixed with the 4 channels of output.
+ Sega Master System III/MD/Genesis PSG uses a 16-bit shift register with taps
+ on bits C and F, output on F
+ * It uses a 16-bit ring buffer for periodic noise/arbitrary duty cycle.
+ Sega Game Gear PSG is identical to the SMS3/MD/Genesis one except it has an
+ extra register for mapping which channels go to which speaker.
+
+ 28/03/2005 : Sebastien Chevalier
+ Update th SN76496Write func, according to SN76489 doc found on SMSPower.
+ - On write with 0x80 set to 0, when LastRegister is other then TONE,
+ the function is similar than update with 0x80 set to 1
+
+ 23/04/2007 : Lord Nightmare
+ Major update, implement all three different noise generation algorithms plus
+ the game gear stereo output, and a set_variant call to discern among them.
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "sn76496.h"
+
+
+#define MAX_OUTPUT 0x7fff
+
+#define STEP 0x10000
+
+struct SN76496
+{
+ sound_stream * Channel;
+ int SampleRate;
+ int VolTable[16]; /* volume table */
+ INT32 Register[8]; /* registers */
+ INT32 LastRegister; /* last register written */
+ INT32 Volume[4]; /* volume of voice 0-2 and noise */
+ UINT32 RNG; /* noise generator */
+ INT32 NoiseMode; /* active noise mode */
+ INT32 FeedbackMask; /* mask for feedback */
+ INT32 WhitenoiseTaps; /* mask for white noise taps */
+ INT32 WhitenoiseInvert; /* white noise invert flag */
+ INT32 Period[4];
+ INT32 Count[4];
+ INT32 Output[4];
+};
+
+
+
+static void SN76496Write(int chip,int data)
+{
+ struct SN76496 *R = sndti_token(SOUND_SN76496, chip);
+ int n, r, c;
+
+
+ /* update the output buffer before changing the registers */
+ stream_update(R->Channel);
+
+ if (data & 0x80)
+ {
+ r = (data & 0x70) >> 4;
+ R->LastRegister = r;
+ R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
+ }
+ else
+ {
+ r = R->LastRegister;
+ }
+ c = r/2;
+ switch (r)
+ {
+ case 0: /* tone 0 : frequency */
+ case 2: /* tone 1 : frequency */
+ case 4: /* tone 2 : frequency */
+ if ((data & 0x80) == 0) R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
+ R->Period[c] = STEP * R->Register[r];
+ if (R->Period[c] == 0) R->Period[c] = STEP;
+ if (r == 4)
+ {
+ /* update noise shift frequency */
+ if ((R->Register[6] & 0x03) == 0x03)
+ R->Period[3] = 2 * R->Period[2];
+ }
+ break;
+ case 1: /* tone 0 : volume */
+ case 3: /* tone 1 : volume */
+ case 5: /* tone 2 : volume */
+ case 7: /* noise : volume */
+ R->Volume[c] = R->VolTable[data & 0x0f];
+ if ((data & 0x80) == 0) R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
+ break;
+ case 6: /* noise : frequency, mode */
+ {
+ if ((data & 0x80) == 0) R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
+ n = R->Register[6];
+ R->NoiseMode = (n & 4) ? 1 : 0;
+ /* N/512,N/1024,N/2048,Tone #3 output */
+ R->Period[3] = ((n&3) == 3) ? 2 * R->Period[2] : (STEP << (5+(n&3)));
+ /* Reset noise shifter */
+ R->RNG = R->FeedbackMask; /* this is correct according to the smspower document */
+ //R->RNG = 0xF35; /* this is not, but sounds better in do run run */
+ R->Output[3] = R->RNG & 1;
+ }
+ break;
+ }
+}
+
+
+
+WRITE8_HANDLER( SN76496_0_w ) { SN76496Write(0,data); }
+WRITE8_HANDLER( SN76496_1_w ) { SN76496Write(1,data); }
+WRITE8_HANDLER( SN76496_2_w ) { SN76496Write(2,data); }
+WRITE8_HANDLER( SN76496_3_w ) { SN76496Write(3,data); }
+WRITE8_HANDLER( SN76496_4_w ) { SN76496Write(4,data); }
+
+
+static void SN76496Update(void *param,stream_sample_t **inputs, stream_sample_t **_buffer,int length)
+{
+ int i;
+ struct SN76496 *R = param;
+ stream_sample_t *buffer = _buffer[0];
+
+
+ /* If the volume is 0, increase the counter */
+ for (i = 0;i < 4;i++)
+ {
+ if (R->Volume[i] == 0)
+ {
+ /* note that I do count += length, NOT count = length + 1. You might think */
+ /* it's the same since the volume is 0, but doing the latter could cause */
+ /* interferencies when the program is rapidly modulating the volume. */
+ if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP;
+ }
+ }
+
+ while (length > 0)
+ {
+ int vol[4];
+ unsigned int out;
+ int left;
+
+
+ /* vol[] keeps track of how long each square wave stays */
+ /* in the 1 position during the sample period. */
+ vol[0] = vol[1] = vol[2] = vol[3] = 0;
+
+ for (i = 0;i < 3;i++)
+ {
+ if (R->Output[i]) vol[i] += R->Count[i];
+ R->Count[i] -= STEP;
+ /* Period[i] is the half period of the square wave. Here, in each */
+ /* loop I add Period[i] twice, so that at the end of the loop the */
+ /* square wave is in the same status (0 or 1) it was at the start. */
+ /* vol[i] is also incremented by Period[i], since the wave has been 1 */
+ /* exactly half of the time, regardless of the initial position. */
+ /* If we exit the loop in the middle, Output[i] has to be inverted */
+ /* and vol[i] incremented only if the exit status of the square */
+ /* wave is 1. */
+ while (R->Count[i] <= 0)
+ {
+ R->Count[i] += R->Period[i];
+ if (R->Count[i] > 0)
+ {
+ R->Output[i] ^= 1;
+ if (R->Output[i]) vol[i] += R->Period[i];
+ break;
+ }
+ R->Count[i] += R->Period[i];
+ vol[i] += R->Period[i];
+ }
+ if (R->Output[i]) vol[i] -= R->Count[i];
+ }
+
+ left = STEP;
+ do
+ {
+ int nextevent;
+
+
+ if (R->Count[3] < left) nextevent = R->Count[3];
+ else nextevent = left;
+
+ if (R->Output[3]) vol[3] += R->Count[3];
+ R->Count[3] -= nextevent;
+ if (R->Count[3] <= 0)
+ {
+ if (R->NoiseMode == 1) /* White Noise Mode */
+ {
+ if (((R->RNG & R->WhitenoiseTaps) != R->WhitenoiseTaps) && ((R->RNG & R->WhitenoiseTaps) != 0)) /* crappy xor! */
+ {
+ R->RNG >>= 1;
+ R->RNG |= R->FeedbackMask;
+ }
+ else
+ {
+ R->RNG >>= 1;
+ }
+ R->Output[3] = R->WhitenoiseInvert ? !(R->RNG & 1) : R->RNG & 1;
+ }
+ else /* Periodic noise mode */
+ {
+ if (R->RNG & 1)
+ {
+ R->RNG >>= 1;
+ R->RNG |= R->FeedbackMask;
+ }
+ else
+ {
+ R->RNG >>= 1;
+ }
+ R->Output[3] = R->RNG & 1;
+ }
+ R->Count[3] += R->Period[3];
+ if (R->Output[3]) vol[3] += R->Period[3];
+ }
+ if (R->Output[3]) vol[3] -= R->Count[3];
+
+ left -= nextevent;
+ } while (left > 0);
+
+ out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +
+ vol[2] * R->Volume[2] + vol[3] * R->Volume[3];
+
+ if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP;
+
+ *(buffer++) = out / STEP;
+
+ length--;
+ }
+}
+
+
+
+static void SN76496_set_gain(struct SN76496 *R,int gain)
+{
+ int i;
+ double out;
+
+
+ gain &= 0xff;
+
+ /* increase max output basing on gain (0.2 dB per step) */
+ out = MAX_OUTPUT / 3;
+ while (gain-- > 0)
+ out *= 1.023292992; /* = (10 ^ (0.2/20)) */
+
+ /* build volume table (2dB per step) */
+ for (i = 0;i < 15;i++)
+ {
+ /* limit volume to avoid clipping */
+ if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3;
+ else R->VolTable[i] = out;
+
+ out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */
+ }
+ R->VolTable[15] = 0;
+}
+
+
+
+static int SN76496_init(struct SN76496 *R,int sndindex,int clock)
+{
+ int sample_rate = clock/16;
+ int i;
+
+ R->Channel = stream_create(0,1, sample_rate,R,SN76496Update);
+
+ R->SampleRate = sample_rate;
+
+ for (i = 0;i < 4;i++) R->Volume[i] = 0;
+
+ R->LastRegister = 0;
+ for (i = 0;i < 8;i+=2)
+ {
+ R->Register[i] = 0;
+ R->Register[i + 1] = 0x0f; /* volume = 0 */
+ }
+
+ for (i = 0;i < 4;i++)
+ {
+ R->Output[i] = 0;
+ R->Period[i] = R->Count[i] = STEP;
+ }
+
+ /* Default is SN76489 non-A */
+ R->FeedbackMask = 0x4000; /* mask for feedback */
+ R->WhitenoiseTaps = 0x03; /* mask for white noise taps */
+ R->WhitenoiseInvert = 1; /* white noise invert flag */
+
+ R->RNG = R->FeedbackMask;
+ R->Output[3] = R->RNG & 1;
+
+ return 0;
+}
+
+
+static void *generic_start(int sndindex, int clock, int feedbackmask, int noisetaps, int noiseinvert)
+{
+ struct SN76496 *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ if (SN76496_init(chip,sndindex,clock) != 0)
+ return NULL;
+ SN76496_set_gain(chip, 0);
+
+ chip->FeedbackMask = feedbackmask;
+ chip->WhitenoiseTaps = noisetaps;
+ chip->WhitenoiseInvert = noiseinvert;
+
+ state_save_register_item_array("sn76496", sndindex, chip->Register);
+ state_save_register_item("sn76496", sndindex, chip->LastRegister);
+ state_save_register_item_array("sn76496", sndindex, chip->Volume);
+ state_save_register_item("sn76496", sndindex, chip->RNG);
+ state_save_register_item("sn76496", sndindex, chip->NoiseMode);
+ state_save_register_item_array("sn76496", sndindex, chip->Period);
+ state_save_register_item_array("sn76496", sndindex, chip->Count);
+ state_save_register_item_array("sn76496", sndindex, chip->Output);
+
+ return chip;
+
+}
+
+
+static void *sn76489_start(int sndindex, int clock, const void *config)
+{
+ return generic_start(sndindex, clock, 0x4000, 0x03, TRUE);
+}
+
+static void *sn76489a_start(int sndindex, int clock, const void *config)
+{
+ return generic_start(sndindex, clock, 0x8000, 0x06, FALSE);
+}
+
+static void *sn76494_start(int sndindex, int clock, const void *config)
+{
+ return generic_start(sndindex, clock, 0x8000, 0x06, FALSE);
+}
+
+static void *sn76496_start(int sndindex, int clock, const void *config)
+{
+ return generic_start(sndindex, clock, 0x8000, 0x06, FALSE);
+}
+
+static void *gamegear_start(int sndindex, int clock, const void *config)
+{
+ return generic_start(sndindex, clock, 0x8000, 0x09, FALSE);
+}
+
+static void *smsiii_start(int sndindex, int clock, const void *config)
+{
+ return generic_start(sndindex, clock, 0x8000, 0x09, FALSE);
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void sn76496_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void sn76496_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case SNDINFO_INT_ALIAS: info->i = SOUND_SN76496; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = sn76496_set_info; break;
+ case SNDINFO_PTR_START: info->start = sn76496_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "SN76496"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "TI PSG"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.1"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, 2007 The MAME Team"; break;
+ }
+}
+
+void sn76489_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = sn76489_start; break;
+ case SNDINFO_STR_NAME: info->s = "SN76489"; break;
+ default: sn76496_get_info(token, state, info); break;
+ }
+}
+
+void sn76489a_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = sn76489a_start; break;
+ case SNDINFO_STR_NAME: info->s = "SN76489A"; break;
+ default: sn76496_get_info(token, state, info); break;
+ }
+}
+
+void sn76494_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = sn76494_start; break;
+ case SNDINFO_STR_NAME: info->s = "SN76494"; break;
+ default: sn76496_get_info(token, state, info); break;
+ }
+}
+
+void gamegear_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = gamegear_start; break;
+ case SNDINFO_STR_NAME: info->s = "Game Gear PSG"; break;
+ default: sn76496_get_info(token, state, info); break;
+ }
+}
+
+void smsiii_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ case SNDINFO_PTR_START: info->start = smsiii_start; break;
+ case SNDINFO_STR_NAME: info->s = "SMSIII PSG"; break;
+ default: sn76496_get_info(token, state, info); break;
+ }
+}
diff --git a/src/emu/sound/sn76496.h b/src/emu/sound/sn76496.h
new file mode 100644
index 00000000000..cf51b48ce7c
--- /dev/null
+++ b/src/emu/sound/sn76496.h
@@ -0,0 +1,10 @@
+#ifndef SN76496_H
+#define SN76496_H
+
+WRITE8_HANDLER( SN76496_0_w );
+WRITE8_HANDLER( SN76496_1_w );
+WRITE8_HANDLER( SN76496_2_w );
+WRITE8_HANDLER( SN76496_3_w );
+WRITE8_HANDLER( SN76496_4_w );
+
+#endif
diff --git a/src/emu/sound/sound.mak b/src/emu/sound/sound.mak
new file mode 100644
index 00000000000..34b8a47b642
--- /dev/null
+++ b/src/emu/sound/sound.mak
@@ -0,0 +1,717 @@
+###########################################################################
+#
+# sound.mak
+#
+# Rules for building sound cores
+#
+# Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+# Visit http://mamedev.org for licensing and usage restrictions.
+#
+###########################################################################
+
+
+SOUNDSRC = $(EMUSRC)/sound
+SOUNDOBJ = $(EMUOBJ)/sound
+
+
+#-------------------------------------------------
+# Core sound types
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_CUSTOM=$(if $(filter CUSTOM,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_SAMPLES=$(if $(filter SAMPLES,$(SOUNDS)),1,0)
+
+ifneq ($(filter CUSTOM,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/custom.o
+endif
+
+ifneq ($(filter SAMPLES,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/samples.o
+endif
+
+
+
+#-------------------------------------------------
+# DACs
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_DAC=$(if $(filter DAC,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_DMADAC=$(if $(filter DMADAC,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_SPEAKER=$(if $(filter SPEAKER,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_BEEP=$(if $(filter BEEP,$(SOUNDS)),1,0)
+
+ifneq ($(filter DAC,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/dac.o
+endif
+
+ifneq ($(filter DMADAC,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/dmadac.o
+endif
+
+ifneq ($(filter SPEAKER,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/speaker.o
+endif
+
+ifneq ($(filter BEEP,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/beep.o
+endif
+
+
+
+#-------------------------------------------------
+# CD audio
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_CDDA=$(if $(filter CDDA,$(SOUNDS)),1,0)
+
+ifneq ($(filter CDDA,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/cdda.o
+endif
+
+
+
+#-------------------------------------------------
+# Discrete component audio
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_DISCRETE=$(if $(filter DISCRETE,$(SOUNDS)),1,0)
+
+ifneq ($(filter DISCRETE,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/discrete.o
+endif
+
+$(SOUNDOBJ)/discrete.o: $(SOUNDSRC)/discrete.c \
+ $(SOUNDSRC)/discrete.h \
+ $(SOUNDSRC)/disc_dev.c \
+ $(SOUNDSRC)/disc_flt.c \
+ $(SOUNDSRC)/disc_inp.c \
+ $(SOUNDSRC)/disc_mth.c \
+ $(SOUNDSRC)/disc_wav.c
+
+
+
+#-------------------------------------------------
+# Atari custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_POKEY=$(if $(filter POKEY,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_TIA=$(if $(filter TIA,$(SOUNDS)),1,0)
+
+ifneq ($(filter POKEY,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/pokey.o
+endif
+
+ifneq ($(filter TIA,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/tiasound.o $(SOUNDOBJ)/tiaintf.o
+endif
+
+
+
+#-------------------------------------------------
+# Bally Astrocade sound system
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_ASTROCADE=$(if $(filter ASTROCADE,$(SOUNDS)),1,0)
+
+ifneq ($(filter ASTROCADE,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/astrocde.o
+endif
+
+
+
+#-------------------------------------------------
+# CEM 3394 analog synthesizer chip
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_CEM3394=$(if $(filter CEM3394,$(SOUNDS)),1,0)
+
+ifneq ($(filter CEM3394,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/cem3394.o
+endif
+
+
+
+#-------------------------------------------------
+# Data East custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_BSMT2000=$(if $(filter BSMT2000,$(SOUNDS)),1,0)
+
+ifneq ($(filter BSMT2000,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/bsmt2000.o
+endif
+
+
+
+#-------------------------------------------------
+# Ensoniq 5503 (Apple IIgs)
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_ES5503=$(if $(filter ES5503,$(SOUNDS)),1,0)
+
+ifneq ($(filter ES5503,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/es5503.o
+endif
+
+
+
+#-------------------------------------------------
+# Ensoniq 5505/5506
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_ES5505=$(if $(filter ES5505,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_ES5506=$(if $(filter ES5506,$(SOUNDS)),1,0)
+
+ifneq ($(filter ES5505 ES5506,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/es5506.o
+endif
+
+
+
+#-------------------------------------------------
+# Excellent Systems ADPCM sound chip
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_ES8712=$(if $(filter ES8712,$(SOUNDS)),1,0)
+
+ifneq ($(filter ES8712,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/es8712.o
+endif
+
+
+
+#-------------------------------------------------
+# Gaelco custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_GAELCO_CG1V=$(if $(filter GAELCO_CG1V,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_GAELCO_GAE1=$(if $(filter GAELCO_GAE1,$(SOUNDS)),1,0)
+
+ifneq ($(filter GAELCO_CG1V,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/gaelco.o
+endif
+
+ifneq ($(filter GAELCO_GAE1,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/gaelco.o
+endif
+
+
+
+#-------------------------------------------------
+# RCA CDP1869
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_CDP1869=$(if $(filter CDP1869,$(SOUNDS)),1,0)
+
+ifneq ($(filter CDP1869,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/cdp1869.o
+endif
+
+
+
+#-------------------------------------------------
+# GI AY-8910
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_AY8910=$(if $(filter AY8910,$(SOUNDS)),1,0)
+
+ifneq ($(filter AY8910,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/ay8910.o
+endif
+
+
+
+#-------------------------------------------------
+# Harris HC55516 CVSD
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_HC55516=$(if $(filter HC55516,$(SOUNDS)),1,0)
+
+ifneq ($(filter HC55516,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/hc55516.o
+endif
+
+
+
+#-------------------------------------------------
+# Hudsonsoft C6280 sound chip
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_C6280=$(if $(filter C6280,$(SOUNDS)),1,0)
+
+ifneq ($(filter C6280,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/c6280.o
+endif
+
+
+
+#-------------------------------------------------
+# ICS2115 sound chip
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_ICS2115=$(if $(filter ICS2115,$(SOUNDS)),1,0)
+
+ifneq ($(filter ICS2115,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/ics2115.o
+endif
+
+
+
+#-------------------------------------------------
+# Irem custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_IREMGA20=$(if $(filter IREMGA20,$(SOUNDS)),1,0)
+
+ifneq ($(filter IREMGA20,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/iremga20.o
+endif
+
+
+
+#-------------------------------------------------
+# Konami custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_K005289=$(if $(filter K005289,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_K007232=$(if $(filter K007232,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_K051649=$(if $(filter K051649,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_K053260=$(if $(filter K053260,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_K054539=$(if $(filter K054539,$(SOUNDS)),1,0)
+
+ifneq ($(filter K005289,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/k005289.o
+endif
+
+ifneq ($(filter K007232,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/k007232.o
+endif
+
+ifneq ($(filter K051649,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/k051649.o
+endif
+
+ifneq ($(filter K053260,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/k053260.o
+endif
+
+ifneq ($(filter K054539,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/k054539.o
+endif
+
+
+
+#-------------------------------------------------
+# Namco custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_NAMCO=$(if $(filter NAMCO,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_NAMCO_15XX=$(if $(filter NAMCO_15XX,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_NAMCO_CUS30=$(if $(filter NAMCO_CUS30,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_NAMCO_52XX=$(if $(filter NAMCO_52XX,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_NAMCO_63701X=$(if $(filter NAMCO_63701X,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_NAMCONA=$(if $(filter NAMCONA,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_C140=$(if $(filter C140,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_C352=$(if $(filter C352,$(SOUNDS)),1,0)
+
+ifneq ($(filter NAMCO NAMCO_15XX NAMCO_CUS30,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/namco.o
+endif
+
+ifneq ($(filter NAMCO_52XX,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/namco52.o
+endif
+
+ifneq ($(filter NAMCO_63701X,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/n63701x.o
+endif
+
+ifneq ($(filter NAMCONA,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/namcona.o
+endif
+
+ifneq ($(filter C140,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/c140.o
+endif
+
+ifneq ($(filter C352,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/c352.o
+endif
+
+
+
+#-------------------------------------------------
+# Nintendo custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_NES=$(if $(filter NES,$(SOUNDS)),1,0)
+
+ifneq ($(filter NES,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/nes_apu.o
+endif
+
+
+
+#-------------------------------------------------
+# NEC uPD7759 ADPCM sample player
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_UPD7759=$(if $(filter UPD7759,$(SOUNDS)),1,0)
+
+ifneq ($(filter UPD7759,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/upd7759.o
+endif
+
+
+
+#-------------------------------------------------
+# OKI ADPCM sample players
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_MSM5205=$(if $(filter MSM5205,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_MSM5232=$(if $(filter MSM5232,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_OKIM6295=$(if $(filter OKIM6295,$(SOUNDS)),1,0)
+
+ifneq ($(filter MSM5205,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/msm5205.o
+endif
+
+ifneq ($(filter MSM5232,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/msm5232.o
+endif
+
+ifneq ($(filter OKIM6295,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/okim6295.o
+endif
+
+
+
+#-------------------------------------------------
+# Philips SAA1099
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_SAA1099=$(if $(filter SAA1099,$(SOUNDS)),1,0)
+
+ifneq ($(filter SAA1099,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/saa1099.o
+endif
+
+
+
+#-------------------------------------------------
+# QSound sample player
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_QSOUND=$(if $(filter QSOUND,$(SOUNDS)),1,0)
+
+ifneq ($(filter QSOUND,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/qsound.o
+endif
+
+
+
+#-------------------------------------------------
+# Ricoh sample players
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_RF5C68=$(if $(filter RF5C68,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_RF5C400=$(if $(filter RF5C400,$(SOUNDS)),1,0)
+
+ifneq ($(filter RF5C68,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/rf5c68.o
+endif
+
+ifneq ($(filter RF5C400,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/rf5c400.o
+endif
+
+
+
+#-------------------------------------------------
+# Sega custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_SEGAPCM=$(if $(filter SEGAPCM,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_MULTIPCM=$(if $(filter MULTIPCM,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_SCSP=$(if $(filter SCSP,$(SOUNDS)),1,0)
+
+ifneq ($(filter SEGAPCM,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/segapcm.o
+endif
+
+ifneq ($(filter MULTIPCM,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/multipcm.o
+endif
+
+ifneq ($(filter SCSP,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/scsp.o $(SOUNDOBJ)/scspdsp.o
+endif
+
+
+
+#-------------------------------------------------
+# Seta custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_ST0016=$(if $(filter ST0016,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_X1_010=$(if $(filter X1_010,$(SOUNDS)),1,0)
+
+ifneq ($(filter ST0016,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/st0016.o
+endif
+
+ifneq ($(filter X1_010,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/x1_010.o
+endif
+
+
+
+#-------------------------------------------------
+# SID custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_SID6581=$(if $(filter SID6581,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_SID8580=$(if $(filter SID8580,$(SOUNDS)),1,0)
+
+ifneq ($(filter SID6581,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/sid6581.o $(SOUNDOBJ)/sid.o $(SOUNDOBJ)/sidenvel.o $(SOUNDOBJ)/sidvoice.o
+endif
+
+ifneq ($(filter SID8580,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/sid6581.o $(SOUNDOBJ)/sid.o $(SOUNDOBJ)/sidenvel.o $(SOUNDOBJ)/sidvoice.o
+endif
+
+
+
+#-------------------------------------------------
+# Sony custom sound chips
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_PSXSPU=$(if $(filter PSXSPU,$(SOUNDS)),1,0)
+
+ifneq ($(filter PSXSPU,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/psx.o
+endif
+
+
+
+#-------------------------------------------------
+# SP0256 speech synthesizer
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_SP0256=$(if $(filter SP0256,$(SOUNDS)),1,0)
+
+ifneq ($(filter SP0256,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/sp0256.o
+endif
+
+
+
+#-------------------------------------------------
+# SP0250 speech synthesizer
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_SP0250=$(if $(filter SP0250,$(SOUNDS)),1,0)
+
+ifneq ($(filter SP0250,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/sp0250.o
+endif
+
+
+#-------------------------------------------------
+# S14001A speech synthesizer
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_S14001A=$(if $(filter S14001A,$(SOUNDS)),1,0)
+
+ifneq ($(filter S14001A,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/s14001a.o
+endif
+
+#-------------------------------------------------
+# Texas Instruments SN76477 analog chip
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_SN76477=$(if $(filter SN76477,$(SOUNDS)),1,0)
+
+ifneq ($(filter SN76477,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/sn76477.o
+endif
+
+
+
+#-------------------------------------------------
+# Texas Instruments SN76496
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_SN76496=$(if $(filter SN76496,$(SOUNDS)),1,0)
+
+ifneq ($(filter SN76496,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/sn76496.o
+endif
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS36xx doorbell chime
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_TMS36XX=$(if $(filter TMS36XX,$(SOUNDS)),1,0)
+
+ifneq ($(filter TMS36XX,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/tms36xx.o
+endif
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS3615 Octave Multiple Tone Synthesizer
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_TMS3615=$(if $(filter TMS3615,$(SOUNDS)),1,0)
+
+ifneq ($(filter TMS3615,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/tms3615.o
+endif
+
+
+
+#-------------------------------------------------
+# Texas Instruments TMS5110 speech synthesizers
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_TMS5110=$(if $(filter TMS5110,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_TMS5220=$(if $(filter TMS5220,$(SOUNDS)),1,0)
+
+ifneq ($(filter TMS5110,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/tms5110.o $(SOUNDOBJ)/5110intf.o
+endif
+
+ifneq ($(filter TMS5220,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/tms5220.o $(SOUNDOBJ)/5220intf.o
+endif
+
+
+
+#-------------------------------------------------
+# VLM5030 speech synthesizer
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_VLM5030=$(if $(filter VLM5030,$(SOUNDS)),1,0)
+
+ifneq ($(filter VLM5030,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/vlm5030.o
+endif
+
+
+
+#-------------------------------------------------
+# Votrax speech synthesizer
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_VOTRAX=$(if $(filter VOTRAX,$(SOUNDS)),1,0)
+
+ifneq ($(filter VOTRAX,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/votrax.o $(SOUNDOBJ)/samples.o
+endif
+
+
+
+#-------------------------------------------------
+# VRender0 custom sound chip
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_VRENDER0=$(if $(filter VRENDER0,$(SOUNDS)),1,0)
+
+ifneq ($(filter VRENDER0,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/vrender0.o
+endif
+
+
+
+#-------------------------------------------------
+# WAVE file (used for MESS cassette)
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_WAVE=$(if $(filter WAVE,$(SOUNDS)),1,0)
+
+ifneq ($(filter WAVE,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/wave.o
+endif
+
+
+
+#-------------------------------------------------
+# Yamaha FM synthesizers
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_YM2151=$(if $(filter YM2151,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YM2203=$(if $(filter YM2203,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YM2413=$(if $(filter YM2413,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YM2608=$(if $(filter YM2608,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YM2610=$(if $(filter YM2610,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YM2610B=$(if $(filter YM2610B,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YM2612=$(if $(filter YM2612,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YM3438=$(if $(filter YM3438,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YM3812=$(if $(filter YM3812,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YM3526=$(if $(filter YM3526,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_Y8950=$(if $(filter Y8950,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YMF262=$(if $(filter YMF262,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YMF271=$(if $(filter YMF271,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_YMF278B=$(if $(filter YMF278B,$(SOUNDS)),1,0)
+
+ifneq ($(filter YM2151,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/2151intf.o $(SOUNDOBJ)/ym2151.o
+endif
+
+ifneq ($(filter YM2203,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/2203intf.o $(SOUNDOBJ)/ay8910.o $(SOUNDOBJ)/fm.o
+endif
+
+ifneq ($(filter YM2413,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/2413intf.o $(SOUNDOBJ)/ym2413.o
+endif
+
+ifneq ($(filter YM2608,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/2608intf.o $(SOUNDOBJ)/ay8910.o $(SOUNDOBJ)/fm.o $(SOUNDOBJ)/ymdeltat.o
+endif
+
+ifneq ($(filter YM2610 YM2610B,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/2610intf.o $(SOUNDOBJ)/ay8910.o $(SOUNDOBJ)/fm.o $(SOUNDOBJ)/ymdeltat.o
+endif
+
+ifneq ($(filter YM2612 YM3438,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/2612intf.o $(SOUNDOBJ)/ay8910.o $(SOUNDOBJ)/fm.o
+endif
+
+ifneq ($(filter YM3812 YM3526,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/3812intf.o $(SOUNDOBJ)/fmopl.o
+endif
+
+ifneq ($(filter Y8950,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/3812intf.o $(SOUNDOBJ)/fmopl.o $(SOUNDOBJ)/ymdeltat.o
+endif
+
+ifneq ($(filter YMF262,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/ymf262.o $(SOUNDOBJ)/262intf.o
+endif
+
+ifneq ($(filter YMF271,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/ymf271.o
+endif
+
+ifneq ($(filter YMF278B,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/ymf278b.o
+endif
+
+
+
+#-------------------------------------------------
+# Yamaha YMZ280B ADPCM
+#-------------------------------------------------
+
+SOUNDDEFS += -DHAS_YMZ280B=$(if $(filter YMZ280B,$(SOUNDS)),1,0)
+
+ifneq ($(filter YMZ280B,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/ymz280b.o
+endif
diff --git a/src/emu/sound/sp0250.c b/src/emu/sound/sp0250.c
new file mode 100644
index 00000000000..fc6e00bec00
--- /dev/null
+++ b/src/emu/sound/sp0250.c
@@ -0,0 +1,257 @@
+/*
+ GI SP0250 digital LPC sound synthesizer
+
+ By O. Galibert.
+
+ Unknown:
+ - Exact clock divider
+ - Exact noise algorithm
+ - Exact noise pitch (probably ok)
+ - 7 bits output mapping
+ - Whether the pitch starts counting from 0 or 1
+
+ Unimplemented:
+ - Direct Data test mode (pin 7)
+
+ Sound quite reasonably already though.
+*/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "sp0250.h"
+
+/*
+standard external clock is 3.12MHz
+the chip provides a 445.7kHz output clock, which is = 3.12MHz / 7
+therefore I expect the clock divider to be a multiple of 7
+Also there are 6 cascading filter stages so I expect the divider to be a multiple of 6.
+
+The SP0250 manual states that the original speech is sampled at 10kHz, so the divider
+should be 312, but 312 = 39*8 so it doesn't look right because a divider by 39 is unlikely.
+
+7*6*8 = 336 gives a 9.286kHz sample rate and matches the samples from the Sega boards.
+*/
+#define CLOCK_DIVIDER (7*6*8)
+
+struct sp0250
+{
+ INT16 amp;
+ UINT8 pitch;
+ UINT8 repeat;
+ int pcount, rcount;
+ int playing;
+ UINT32 RNG;
+ sound_stream * stream;
+ int voiced;
+ UINT8 fifo[15];
+ int fifo_pos;
+
+ void (*drq)(int state);
+
+ struct
+ {
+ INT16 F, B;
+ INT16 z1, z2;
+ } filter[6];
+};
+
+
+static UINT16 sp0250_ga(UINT8 v)
+{
+ return (v & 0x1f) << (v>>5);
+}
+
+static INT16 sp0250_gc(UINT8 v)
+{
+ // Internal ROM to the chip, cf. manual
+ static const UINT16 coefs[128] =
+ {
+ 0, 9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 113, 121,
+ 129, 137, 145, 153, 161, 169, 177, 185, 193, 201, 203, 217, 225, 233, 241, 249,
+ 257, 265, 273, 281, 289, 297, 301, 305, 309, 313, 317, 321, 325, 329, 333, 337,
+ 341, 345, 349, 353, 357, 361, 365, 369, 373, 377, 381, 385, 389, 393, 397, 401,
+ 405, 409, 413, 417, 421, 425, 427, 429, 431, 433, 435, 437, 439, 441, 443, 445,
+ 447, 449, 451, 453, 455, 457, 459, 461, 463, 465, 467, 469, 471, 473, 475, 477,
+ 479, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495,
+ 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511
+ };
+ INT16 res = coefs[v & 0x7f];
+
+ if (!(v & 0x80))
+ res = -res;
+ return res;
+}
+
+static void sp0250_load_values(struct sp0250 *sp)
+{
+ int f;
+
+
+ sp->filter[0].B = sp0250_gc(sp->fifo[ 0]);
+ sp->filter[0].F = sp0250_gc(sp->fifo[ 1]);
+ sp->amp = sp0250_ga(sp->fifo[ 2]);
+ sp->filter[1].B = sp0250_gc(sp->fifo[ 3]);
+ sp->filter[1].F = sp0250_gc(sp->fifo[ 4]);
+ sp->pitch = sp->fifo[ 5];
+ sp->filter[2].B = sp0250_gc(sp->fifo[ 6]);
+ sp->filter[2].F = sp0250_gc(sp->fifo[ 7]);
+ sp->repeat = sp->fifo[ 8] & 0x3f;
+ sp->voiced = sp->fifo[ 8] & 0x40;
+ sp->filter[3].B = sp0250_gc(sp->fifo[ 9]);
+ sp->filter[3].F = sp0250_gc(sp->fifo[10]);
+ sp->filter[4].B = sp0250_gc(sp->fifo[11]);
+ sp->filter[4].F = sp0250_gc(sp->fifo[12]);
+ sp->filter[5].B = sp0250_gc(sp->fifo[13]);
+ sp->filter[5].F = sp0250_gc(sp->fifo[14]);
+ sp->fifo_pos = 0;
+ sp->drq(ASSERT_LINE);
+
+ sp->pcount = 0;
+ sp->rcount = 0;
+
+ for (f = 0; f < 6; f++)
+ sp->filter[f].z1 = sp->filter[f].z2 = 0;
+
+ sp->playing = 1;
+}
+
+static TIMER_CALLBACK_PTR( sp0250_timer_tick )
+{
+ struct sp0250 *sp = param;
+ stream_update(sp->stream);
+}
+
+static void sp0250_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct sp0250 *sp = param;
+ stream_sample_t *output = buffer[0];
+ int i;
+ for (i = 0; i < length; i++)
+ {
+ if (sp->playing)
+ {
+ INT16 z0;
+ int f;
+
+ if (sp->voiced)
+ {
+ if(!sp->pcount)
+ z0 = sp->amp;
+ else
+ z0 = 0;
+ }
+ else
+ {
+ // Borrowing the ay noise generation LFSR
+ if(sp->RNG & 1)
+ {
+ z0 = sp->amp;
+ sp->RNG ^= 0x24000;
+ }
+ else
+ z0 = -sp->amp;
+
+ sp->RNG >>= 1;
+ }
+
+ for (f = 0; f < 6; f++)
+ {
+ z0 += ((sp->filter[f].z1 * sp->filter[f].F) >> 8)
+ + ((sp->filter[f].z2 * sp->filter[f].B) >> 9);
+ sp->filter[f].z2 = sp->filter[f].z1;
+ sp->filter[f].z1 = z0;
+ }
+
+ // Physical resolution is only 7 bits, but heh
+
+ // max amplitude is 0x0f80 so we have margin to push up the output
+ output[i] = z0 << 3;
+
+ sp->pcount++;
+ if (sp->pcount >= sp->pitch)
+ {
+ sp->pcount = 0;
+ sp->rcount++;
+ if (sp->rcount >= sp->repeat)
+ sp->playing = 0;
+ }
+ }
+ else
+ output[i] = 0;
+
+ if (!sp->playing)
+ {
+ if(sp->fifo_pos == 15)
+ sp0250_load_values(sp);
+ }
+ }
+}
+
+
+static void *sp0250_start(int sndindex, int clock, const void *config)
+{
+ const struct sp0250_interface *intf = config;
+ struct sp0250 *sp;
+
+ sp = auto_malloc(sizeof(*sp));
+ memset(sp, 0, sizeof(*sp));
+ sp->RNG = 1;
+ sp->drq = intf->drq_callback;
+ sp->drq(ASSERT_LINE);
+ timer_pulse_ptr(attotime_mul(ATTOTIME_IN_HZ(clock), CLOCK_DIVIDER), sp, sp0250_timer_tick);
+
+ sp->stream = stream_create(0, 1, clock / CLOCK_DIVIDER, sp, sp0250_update);
+
+ return sp;
+}
+
+
+WRITE8_HANDLER( sp0250_w )
+{
+ struct sp0250 *sp = sndti_token(SOUND_SP0250, 0);
+ if (sp->fifo_pos != 15)
+ {
+ sp->fifo[sp->fifo_pos++] = data;
+ if (sp->fifo_pos == 15)
+ sp->drq(CLEAR_LINE);
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void sp0250_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void sp0250_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = sp0250_set_info; break;
+ case SNDINFO_PTR_START: info->start = sp0250_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "SP0250"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "GI speech"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.1"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, 2005 The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/sp0250.h b/src/emu/sound/sp0250.h
new file mode 100644
index 00000000000..1aeca96f066
--- /dev/null
+++ b/src/emu/sound/sp0250.h
@@ -0,0 +1,10 @@
+#ifndef __SP0250_H__
+#define __SP0250_H__
+
+struct sp0250_interface {
+ void (*drq_callback)(int state);
+};
+
+WRITE8_HANDLER( sp0250_w );
+
+#endif
diff --git a/src/emu/sound/sp0256.c b/src/emu/sound/sp0256.c
new file mode 100644
index 00000000000..67b34e621f7
--- /dev/null
+++ b/src/emu/sound/sp0256.c
@@ -0,0 +1,1383 @@
+/*
+ GI SP0256 Narrator Speech Processor
+ GI SPB640 Speech Buffer
+
+ By Joe Zbiciak. Ported to MESS by tim lindner.
+
+ Unimplemented:
+ - Microsequencer repeat count of zero
+ - Support for non bit-flipped ROMs
+ - SPB-640 perpherial/RAM bus
+
+ Copyright (c) 1998-2000, Joseph Zbiciak, all rights reserved.
+ Copyright (c) 2006, tim lindner, all rights reserved.
+
+ - This source code is released as freeware for non-commercial purposes.
+ - You are free to use and redistribute this code in modified or
+ unmodified form, provided you list us in the credits.
+ - If you modify this source code, you must add a notice to each
+ modified source file that it has been changed. If you're a nice
+ person, you will clearly mark each change too. :)
+ - If you wish to use this for commercial purposes, please contact us at
+ intvnut@gmail.com (Joseph Zbiciak), tlindner@macmess.org (tim lindner)
+ - This entire notice must remain in the source code.
+
+ Note: Bit flipping.
+ This emulation flips the bits on every byte of the memory map during
+ the sp0256_start() call.
+
+ If the memory map contents is modified during execution (becuase of ROM
+ bank switching) the sp0256_bitrevbuff() call must be called after the
+ section of ROM is modified.
+*/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "sp0256.h"
+
+#define CLOCK_DIVIDER (7*6*8)
+#define HIGH_QUALITY
+
+#define SCBUF_SIZE (4096) /* Must be power of 2 */
+#define SCBUF_MASK (SCBUF_SIZE - 1)
+#define PER_PAUSE (64) /* Equiv timing period for pauses. */
+#define PER_NOISE (64) /* Equiv timing period for noise. */
+
+#define FIFO_ADDR (0x1800 << 3) /* SP0256 address of SPB260 speech FIFO. */
+
+#define VERBOSE 0
+#define DEBUG_FIFO 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+#ifdef DEBUG_FIFO
+#define LOG_FIFO(x) logerror x
+#else
+#define LOG_FIFO(x)
+#endif
+
+#define SET_SBY(line_state) { \
+ if( sp->sby_line != line_state ) \
+ { \
+ sp->sby_line = line_state; \
+ if( sp->sby ) sp->sby(sp->sby_line); \
+ } \
+}
+
+struct lpc12_t
+{
+ int rpt, cnt; /* Repeat counter, Period down-counter. */
+ UINT32 per, rng; /* Period, Amplitude, Random Number Generator */
+ int amp;
+ INT16 f_coef[6]; /* F0 through F5. */
+ INT16 b_coef[6]; /* B0 through B5. */
+ INT16 z_data[6][2]; /* Time-delay data for the filter stages. */
+ UINT8 r[16]; /* The encoded register set. */
+ int interp;
+};
+
+
+struct sp0256
+{
+ sound_stream *stream; /* MAME core sound stream */
+ void (*drq)(int state); /* Data request callback */
+ void (*sby)(int state); /* Standby callback */
+ int sby_line; /* Standby line state */
+ INT16 *cur_buf; /* Current sound buffer. */
+ int cur_len; /* Fullness of current sound buffer. */
+
+ int silent; /* Flag: SP0256 is silent. */
+
+ INT16 *scratch; /* Scratch buffer for audio. */
+ UINT32 sc_head; /* Head pointer into scratch circular buf */
+ UINT32 sc_tail; /* Tail pointer into scratch circular buf */
+
+ struct lpc12_t filt; /* 12-pole filter */
+ int lrq; /* Load ReQuest. == 0 if we can accept a load */
+ int ald; /* Address LoaD. < 0 if no command pending. */
+ int pc; /* Microcontroller's PC value. */
+ int stack; /* Microcontroller's PC stack. */
+ int fifo_sel; /* True when executing from FIFO. */
+ int halted; /* True when CPU is halted. */
+ UINT32 mode; /* Mode register. */
+ UINT32 page; /* Page set by SETPAGE */
+
+ UINT32 fifo_head; /* FIFO head pointer (where new data goes). */
+ UINT32 fifo_tail; /* FIFO tail pointer (where data comes from). */
+ UINT32 fifo_bitp; /* FIFO bit-pointer (for partial decles). */
+ UINT16 fifo[64]; /* The 64-decle FIFO. */
+
+ UINT8 *rom; /* 64K ROM. */
+};
+
+/* ======================================================================== */
+/* qtbl -- Coefficient Quantization Table. This comes from a */
+/* SP0250 data sheet, and should be correct for SP0256. */
+/* ======================================================================== */
+static const INT16 qtbl[128] =
+{
+ 0, 9, 17, 25, 33, 41, 49, 57,
+ 65, 73, 81, 89, 97, 105, 113, 121,
+ 129, 137, 145, 153, 161, 169, 177, 185,
+ 193, 201, 209, 217, 225, 233, 241, 249,
+ 257, 265, 273, 281, 289, 297, 301, 305,
+ 309, 313, 317, 321, 325, 329, 333, 337,
+ 341, 345, 349, 353, 357, 361, 365, 369,
+ 373, 377, 381, 385, 389, 393, 397, 401,
+ 405, 409, 413, 417, 421, 425, 427, 429,
+ 431, 433, 435, 437, 439, 441, 443, 445,
+ 447, 449, 451, 453, 455, 457, 459, 461,
+ 463, 465, 467, 469, 471, 473, 475, 477,
+ 479, 481, 482, 483, 484, 485, 486, 487,
+ 488, 489, 490, 491, 492, 493, 494, 495,
+ 496, 497, 498, 499, 500, 501, 502, 503,
+ 504, 505, 506, 507, 508, 509, 510, 511
+};
+
+/* ======================================================================== */
+/* LIMIT -- Limiter function for digital sample output. */
+/* ======================================================================== */
+static INT16 limit(INT16 s)
+{
+#ifdef HIGH_QUALITY /* Higher quality than the original, but who cares? */
+ if (s > 8191) return 8191;
+ if (s < -8192) return -8192;
+#else
+ if (s > 127) return 127;
+ if (s < -128) return -128;
+#endif
+ return s;
+}
+
+/* ======================================================================== */
+/* LPC12_UPDATE -- Update the 12-pole filter, outputting samples. */
+/* ======================================================================== */
+static int lpc12_update(struct lpc12_t *f, int num_samp, INT16 *out, UINT32 *optr)
+{
+ int i, j;
+ INT16 samp;
+ int do_int;
+ int oidx = *optr;
+
+ /* -------------------------------------------------------------------- */
+ /* Iterate up to the desired number of samples. We actually may */
+ /* break out early if our repeat count expires. */
+ /* -------------------------------------------------------------------- */
+ for (i = 0; i < num_samp; i++)
+ {
+ /* ---------------------------------------------------------------- */
+ /* Generate a series of periodic impulses, or random noise. */
+ /* ---------------------------------------------------------------- */
+ do_int = 0;
+ samp = 0;
+ if (f->per)
+ {
+ if (f->cnt <= 0)
+ {
+ f->cnt += f->per;
+ samp = f->amp;
+ f->rpt--;
+ do_int = f->interp;
+
+ for (j = 0; j < 6; j++)
+ f->z_data[j][1] = f->z_data[j][0] = 0;
+
+ } else
+ {
+ samp = 0;
+ f->cnt--;
+ }
+
+ } else
+ {
+ int bit;
+
+ if (--f->cnt <= 0)
+ {
+ do_int = f->interp;
+ f->cnt = PER_NOISE;
+ f->rpt--;
+ for (j = 0; j < 6; j++)
+ f->z_data[j][0] = f->z_data[j][1] = 0;
+ }
+
+ bit = f->rng & 1;
+ f->rng = (f->rng >> 1) ^ (bit ? 0x4001 : 0);
+
+ if (bit) { samp = f->amp; }
+ else { samp = -f->amp; }
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* If we need to, process the interpolation registers. */
+ /* ---------------------------------------------------------------- */
+ if (do_int)
+ {
+ f->r[0] += f->r[14];
+ f->r[1] += f->r[15];
+
+ f->amp = (f->r[0] & 0x1F) << (((f->r[0] & 0xE0) >> 5) + 0);
+ f->per = f->r[1];
+
+ do_int = 0;
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* Stop if we expire our repeat counter and return the actual */
+ /* number of samples we did. */
+ /* ---------------------------------------------------------------- */
+ if (f->rpt <= 0) break;
+
+ /* ---------------------------------------------------------------- */
+ /* Each 2nd order stage looks like one of these. The App. Manual */
+ /* gives the first form, the patent gives the second form. */
+ /* They're equivalent except for time delay. I implement the */
+ /* first form. (Note: 1/Z == 1 unit of time delay.) */
+ /* */
+ /* ---->(+)-------->(+)----------+-------> */
+ /* ^ ^ | */
+ /* | | | */
+ /* | | | */
+ /* [B] [2*F] | */
+ /* ^ ^ | */
+ /* | | | */
+ /* | | | */
+ /* +---[1/Z]<--+---[1/Z]<--+ */
+ /* */
+ /* */
+ /* +---[2*F]<---+ */
+ /* | | */
+ /* | | */
+ /* v | */
+ /* ---->(+)-->[1/Z]-->+-->[1/Z]---+------> */
+ /* ^ | */
+ /* | | */
+ /* | | */
+ /* +-----------[B]<---------+ */
+ /* */
+ /* ---------------------------------------------------------------- */
+ for (j = 0; j < 6; j++)
+ {
+ samp += (((int)f->b_coef[j] * (int)f->z_data[j][1]) >> 9);
+ samp += (((int)f->f_coef[j] * (int)f->z_data[j][0]) >> 8);
+
+ f->z_data[j][1] = f->z_data[j][0];
+ f->z_data[j][0] = samp;
+ }
+
+#ifdef HIGH_QUALITY /* Higher quality than the original, but who cares? */
+ out[oidx++ & SCBUF_MASK] = limit(samp) << 2;
+#else
+ out[oidx++ & SCBUF_MASK] = (limit(samp >> 4) << 8);
+#endif
+ }
+
+ *optr = oidx;
+
+ return i;
+}
+
+static int stage_map[6] = { 0, 1, 2, 3, 4, 5 };
+
+/* ======================================================================== */
+/* LPC12_REGDEC -- Decode the register set in the filter bank. */
+/* ======================================================================== */
+static void lpc12_regdec(struct lpc12_t *f)
+{
+ int i;
+
+ /* -------------------------------------------------------------------- */
+ /* Decode the Amplitude and Period registers. Force the 'cnt' to 0 */
+ /* to get an initial impulse. We compensate elsewhere by setting */
+ /* the repeat count to "repeat + 1". */
+ /* -------------------------------------------------------------------- */
+ f->amp = (f->r[0] & 0x1F) << (((f->r[0] & 0xE0) >> 5) + 0);
+ f->cnt = 0;
+ f->per = f->r[1];
+
+ /* -------------------------------------------------------------------- */
+ /* Decode the filter coefficients from the quant table. */
+ /* -------------------------------------------------------------------- */
+ for (i = 0; i < 6; i++)
+ {
+ #define IQ(x) (((x) & 0x80) ? qtbl[0x7F & -(x)] : -qtbl[(x)])
+
+ f->b_coef[stage_map[i]] = IQ(f->r[2 + 2*i]);
+ f->f_coef[stage_map[i]] = IQ(f->r[3 + 2*i]);
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Set the Interp flag based on whether we have interpolation parms */
+ /* -------------------------------------------------------------------- */
+ f->interp = f->r[14] || f->r[15];
+
+ return;
+}
+
+/* ======================================================================== */
+/* SP0256_DATAFMT -- Data format table for the SP0256's microsequencer */
+/* */
+/* len 4 bits Length of field to extract */
+/* lshift 4 bits Left-shift amount on field */
+/* param 4 bits Parameter number being updated */
+/* delta 1 bit This is a delta-update. (Implies sign-extend) */
+/* field 1 bit This is a field replace. */
+/* clr5 1 bit Clear F5, B5. */
+/* clrall 1 bit Clear all before doing this update */
+/* ======================================================================== */
+
+#define CR(l,s,p,d,f,c5,ca) \
+ ( \
+ (((l) & 15) << 0) | \
+ (((s) & 15) << 4) | \
+ (((p) & 15) << 8) | \
+ (((d) & 1) << 12) | \
+ (((f) & 1) << 13) | \
+ (((c5) & 1) << 14) | \
+ (((ca) & 1) << 15) \
+ )
+
+#define CR_DELTA CR(0,0,0,1,0,0,0)
+#define CR_FIELD CR(0,0,0,0,1,0,0)
+#define CR_CLR5 CR(0,0,0,0,0,1,0)
+#define CR_CLRA CR(0,0,0,0,0,0,1)
+#define CR_LEN(x) ((x) & 15)
+#define CR_SHF(x) (((x) >> 4) & 15)
+#define CR_PRM(x) (((x) >> 8) & 15)
+
+enum { AM = 0, PR, B0, F0, B1, F1, B2, F2, B3, F3, B4, F4, B5, F5, IA, IP };
+
+static const UINT16 sp0256_datafmt[] =
+{
+ /* -------------------------------------------------------------------- */
+ /* OPCODE 1111: PAUSE */
+ /* -------------------------------------------------------------------- */
+ /* 0 */ CR( 0, 0, 0, 0, 0, 0, 1), /* Clear all */
+
+ /* -------------------------------------------------------------------- */
+ /* Opcode 0001: LOADALL */
+ /* -------------------------------------------------------------------- */
+ /* All modes */
+ /* 1 */ CR( 8, 0, AM, 0, 0, 0, 1), /* Amplitude */
+ /* 2 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+ /* 3 */ CR( 8, 0, B0, 0, 0, 0, 0), /* B0 */
+ /* 4 */ CR( 8, 0, F0, 0, 0, 0, 0), /* F0 */
+ /* 5 */ CR( 8, 0, B1, 0, 0, 0, 0), /* B1 */
+ /* 6 */ CR( 8, 0, F1, 0, 0, 0, 0), /* F1 */
+ /* 7 */ CR( 8, 0, B2, 0, 0, 0, 0), /* B2 */
+ /* 8 */ CR( 8, 0, F2, 0, 0, 0, 0), /* F2 */
+ /* 9 */ CR( 8, 0, B3, 0, 0, 0, 0), /* B3 */
+ /* 10 */ CR( 8, 0, F3, 0, 0, 0, 0), /* F3 */
+ /* 11 */ CR( 8, 0, B4, 0, 0, 0, 0), /* B4 */
+ /* 12 */ CR( 8, 0, F4, 0, 0, 0, 0), /* F4 */
+ /* 13 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */
+ /* 14 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */
+ /* Mode 01 and 11 only */
+ /* 15 */ CR( 8, 0, IA, 0, 0, 0, 0), /* Amp Interp */
+ /* 16 */ CR( 8, 0, IP, 0, 0, 0, 0), /* Pit Interp */
+
+ /* -------------------------------------------------------------------- */
+ /* Opcode 0100: LOAD_4 */
+ /* -------------------------------------------------------------------- */
+ /* Mode 00 and 01 */
+ /* 17 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */
+ /* 18 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+ /* 19 */ CR( 4, 3, B3, 0, 0, 0, 0), /* B3 (S=0) */
+ /* 20 */ CR( 6, 2, F3, 0, 0, 0, 0), /* F3 */
+ /* 21 */ CR( 7, 1, B4, 0, 0, 0, 0), /* B4 */
+ /* 22 */ CR( 6, 2, F4, 0, 0, 0, 0), /* F4 */
+ /* Mode 01 only */
+ /* 23 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */
+ /* 24 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */
+
+ /* Mode 10 and 11 */
+ /* 25 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */
+ /* 26 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+ /* 27 */ CR( 6, 1, B3, 0, 0, 0, 0), /* B3 (S=0) */
+ /* 28 */ CR( 7, 1, F3, 0, 0, 0, 0), /* F3 */
+ /* 29 */ CR( 8, 0, B4, 0, 0, 0, 0), /* B4 */
+ /* 30 */ CR( 8, 0, F4, 0, 0, 0, 0), /* F4 */
+ /* Mode 11 only */
+ /* 31 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */
+ /* 32 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */
+
+ /* -------------------------------------------------------------------- */
+ /* Opcode 0110: SETMSB_6 */
+ /* -------------------------------------------------------------------- */
+ /* Mode 00 only */
+ /* 33 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */
+ /* Mode 00 and 01 */
+ /* 34 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */
+ /* 35 */ CR( 6, 2, F3, 0, 1, 0, 0), /* F3 (5 MSBs) */
+ /* 36 */ CR( 6, 2, F4, 0, 1, 0, 0), /* F4 (5 MSBs) */
+ /* Mode 01 only */
+ /* 37 */ CR( 8, 0, F5, 0, 1, 0, 0), /* F5 (5 MSBs) */
+
+ /* Mode 10 only */
+ /* 38 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */
+ /* Mode 10 and 11 */
+ /* 39 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */
+ /* 40 */ CR( 7, 1, F3, 0, 1, 0, 0), /* F3 (6 MSBs) */
+ /* 41 */ CR( 8, 0, F4, 0, 1, 0, 0), /* F4 (6 MSBs) */
+ /* Mode 11 only */
+ /* 42 */ CR( 8, 0, F5, 0, 1, 0, 0), /* F5 (6 MSBs) */
+
+ /* 43 */ 0, /* unused */
+ /* 44 */ 0, /* unused */
+
+ /* -------------------------------------------------------------------- */
+ /* Opcode 1001: DELTA_9 */
+ /* -------------------------------------------------------------------- */
+ /* Mode 00 and 01 */
+ /* 45 */ CR( 4, 2, AM, 1, 0, 0, 0), /* Amplitude */
+ /* 46 */ CR( 5, 0, PR, 1, 0, 0, 0), /* Period */
+ /* 47 */ CR( 3, 4, B0, 1, 0, 0, 0), /* B0 4 MSBs */
+ /* 48 */ CR( 3, 3, F0, 1, 0, 0, 0), /* F0 5 MSBs */
+ /* 49 */ CR( 3, 4, B1, 1, 0, 0, 0), /* B1 4 MSBs */
+ /* 50 */ CR( 3, 3, F1, 1, 0, 0, 0), /* F1 5 MSBs */
+ /* 51 */ CR( 3, 4, B2, 1, 0, 0, 0), /* B2 4 MSBs */
+ /* 52 */ CR( 3, 3, F2, 1, 0, 0, 0), /* F2 5 MSBs */
+ /* 53 */ CR( 3, 3, B3, 1, 0, 0, 0), /* B3 5 MSBs */
+ /* 54 */ CR( 4, 2, F3, 1, 0, 0, 0), /* F3 6 MSBs */
+ /* 55 */ CR( 4, 1, B4, 1, 0, 0, 0), /* B4 7 MSBs */
+ /* 56 */ CR( 4, 2, F4, 1, 0, 0, 0), /* F4 6 MSBs */
+ /* Mode 01 only */
+ /* 57 */ CR( 5, 0, B5, 1, 0, 0, 0), /* B5 8 MSBs */
+ /* 58 */ CR( 5, 0, F5, 1, 0, 0, 0), /* F5 8 MSBs */
+
+ /* Mode 10 and 11 */
+ /* 59 */ CR( 4, 2, AM, 1, 0, 0, 0), /* Amplitude */
+ /* 60 */ CR( 5, 0, PR, 1, 0, 0, 0), /* Period */
+ /* 61 */ CR( 4, 1, B0, 1, 0, 0, 0), /* B0 7 MSBs */
+ /* 62 */ CR( 4, 2, F0, 1, 0, 0, 0), /* F0 6 MSBs */
+ /* 63 */ CR( 4, 1, B1, 1, 0, 0, 0), /* B1 7 MSBs */
+ /* 64 */ CR( 4, 2, F1, 1, 0, 0, 0), /* F1 6 MSBs */
+ /* 65 */ CR( 4, 1, B2, 1, 0, 0, 0), /* B2 7 MSBs */
+ /* 66 */ CR( 4, 2, F2, 1, 0, 0, 0), /* F2 6 MSBs */
+ /* 67 */ CR( 4, 1, B3, 1, 0, 0, 0), /* B3 7 MSBs */
+ /* 68 */ CR( 5, 1, F3, 1, 0, 0, 0), /* F3 7 MSBs */
+ /* 69 */ CR( 5, 0, B4, 1, 0, 0, 0), /* B4 8 MSBs */
+ /* 70 */ CR( 5, 0, F4, 1, 0, 0, 0), /* F4 8 MSBs */
+ /* Mode 11 only */
+ /* 71 */ CR( 5, 0, B5, 1, 0, 0, 0), /* B5 8 MSBs */
+ /* 72 */ CR( 5, 0, F5, 1, 0, 0, 0), /* F5 8 MSBs */
+
+ /* -------------------------------------------------------------------- */
+ /* Opcode 1010: SETMSB_A */
+ /* -------------------------------------------------------------------- */
+ /* Mode 00 only */
+ /* 73 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */
+ /* Mode 00 and 01 */
+ /* 74 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */
+ /* 75 */ CR( 5, 3, F0, 0, 1, 0, 0), /* F0 (5 MSBs) */
+ /* 76 */ CR( 5, 3, F1, 0, 1, 0, 0), /* F1 (5 MSBs) */
+ /* 77 */ CR( 5, 3, F2, 0, 1, 0, 0), /* F2 (5 MSBs) */
+
+ /* Mode 10 only */
+ /* 78 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */
+ /* Mode 10 and 11 */
+ /* 79 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */
+ /* 80 */ CR( 6, 2, F0, 0, 1, 0, 0), /* F0 (6 MSBs) */
+ /* 81 */ CR( 6, 2, F1, 0, 1, 0, 0), /* F1 (6 MSBs) */
+ /* 82 */ CR( 6, 2, F2, 0, 1, 0, 0), /* F2 (6 MSBs) */
+
+ /* -------------------------------------------------------------------- */
+ /* Opcode 0010: LOAD_2 Mode 00 and 10 */
+ /* Opcode 1100: LOAD_C Mode 00 and 10 */
+ /* -------------------------------------------------------------------- */
+ /* LOAD_2, LOAD_C Mode 00 */
+ /* 83 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */
+ /* 84 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+ /* 85 */ CR( 3, 4, B0, 0, 0, 0, 0), /* B0 (S=0) */
+ /* 86 */ CR( 5, 3, F0, 0, 0, 0, 0), /* F0 */
+ /* 87 */ CR( 3, 4, B1, 0, 0, 0, 0), /* B1 (S=0) */
+ /* 88 */ CR( 5, 3, F1, 0, 0, 0, 0), /* F1 */
+ /* 89 */ CR( 3, 4, B2, 0, 0, 0, 0), /* B2 (S=0) */
+ /* 90 */ CR( 5, 3, F2, 0, 0, 0, 0), /* F2 */
+ /* 91 */ CR( 4, 3, B3, 0, 0, 0, 0), /* B3 (S=0) */
+ /* 92 */ CR( 6, 2, F3, 0, 0, 0, 0), /* F3 */
+ /* 93 */ CR( 7, 1, B4, 0, 0, 0, 0), /* B4 */
+ /* 94 */ CR( 6, 2, F4, 0, 0, 0, 0), /* F4 */
+ /* LOAD_2 only */
+ /* 95 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */
+ /* 96 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */
+
+ /* LOAD_2, LOAD_C Mode 10 */
+ /* 97 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */
+ /* 98 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+ /* 99 */ CR( 6, 1, B0, 0, 0, 0, 0), /* B0 (S=0) */
+ /* 100 */ CR( 6, 2, F0, 0, 0, 0, 0), /* F0 */
+ /* 101 */ CR( 6, 1, B1, 0, 0, 0, 0), /* B1 (S=0) */
+ /* 102 */ CR( 6, 2, F1, 0, 0, 0, 0), /* F1 */
+ /* 103 */ CR( 6, 1, B2, 0, 0, 0, 0), /* B2 (S=0) */
+ /* 104 */ CR( 6, 2, F2, 0, 0, 0, 0), /* F2 */
+ /* 105 */ CR( 6, 1, B3, 0, 0, 0, 0), /* B3 (S=0) */
+ /* 106 */ CR( 7, 1, F3, 0, 0, 0, 0), /* F3 */
+ /* 107 */ CR( 8, 0, B4, 0, 0, 0, 0), /* B4 */
+ /* 108 */ CR( 8, 0, F4, 0, 0, 0, 0), /* F4 */
+ /* LOAD_2 only */
+ /* 109 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */
+ /* 110 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */
+
+ /* -------------------------------------------------------------------- */
+ /* OPCODE 1101: DELTA_D */
+ /* -------------------------------------------------------------------- */
+ /* Mode 00 and 01 */
+ /* 111 */ CR( 4, 2, AM, 1, 0, 0, 0), /* Amplitude */
+ /* 112 */ CR( 5, 0, PR, 1, 0, 0, 0), /* Period */
+ /* 113 */ CR( 3, 3, B3, 1, 0, 0, 0), /* B3 5 MSBs */
+ /* 114 */ CR( 4, 2, F3, 1, 0, 0, 0), /* F3 6 MSBs */
+ /* 115 */ CR( 4, 1, B4, 1, 0, 0, 0), /* B4 7 MSBs */
+ /* 116 */ CR( 4, 2, F4, 1, 0, 0, 0), /* F4 6 MSBs */
+ /* Mode 01 only */
+ /* 117 */ CR( 5, 0, B5, 1, 0, 0, 0), /* B5 8 MSBs */
+ /* 118 */ CR( 5, 0, F5, 1, 0, 0, 0), /* F5 8 MSBs */
+
+ /* Mode 10 and 11 */
+ /* 119 */ CR( 4, 2, AM, 1, 0, 0, 0), /* Amplitude */
+ /* 120 */ CR( 5, 0, PR, 1, 0, 0, 0), /* Period */
+ /* 121 */ CR( 4, 1, B3, 1, 0, 0, 0), /* B3 7 MSBs */
+ /* 122 */ CR( 5, 1, F3, 1, 0, 0, 0), /* F3 7 MSBs */
+ /* 123 */ CR( 5, 0, B4, 1, 0, 0, 0), /* B4 8 MSBs */
+ /* 124 */ CR( 5, 0, F4, 1, 0, 0, 0), /* F4 8 MSBs */
+ /* Mode 11 only */
+ /* 125 */ CR( 5, 0, B5, 1, 0, 0, 0), /* B5 8 MSBs */
+ /* 126 */ CR( 5, 0, F5, 1, 0, 0, 0), /* F5 8 MSBs */
+
+ /* -------------------------------------------------------------------- */
+ /* OPCODE 1110: LOAD_E */
+ /* -------------------------------------------------------------------- */
+ /* 127 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */
+ /* 128 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+
+ /* -------------------------------------------------------------------- */
+ /* Opcode 0010: LOAD_2 Mode 01 and 11 */
+ /* Opcode 1100: LOAD_C Mode 01 and 11 */
+ /* -------------------------------------------------------------------- */
+ /* LOAD_2, LOAD_C Mode 01 */
+ /* 129 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */
+ /* 130 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+ /* 131 */ CR( 3, 4, B0, 0, 0, 0, 0), /* B0 (S=0) */
+ /* 132 */ CR( 5, 3, F0, 0, 0, 0, 0), /* F0 */
+ /* 133 */ CR( 3, 4, B1, 0, 0, 0, 0), /* B1 (S=0) */
+ /* 134 */ CR( 5, 3, F1, 0, 0, 0, 0), /* F1 */
+ /* 135 */ CR( 3, 4, B2, 0, 0, 0, 0), /* B2 (S=0) */
+ /* 136 */ CR( 5, 3, F2, 0, 0, 0, 0), /* F2 */
+ /* 137 */ CR( 4, 3, B3, 0, 0, 0, 0), /* B3 (S=0) */
+ /* 138 */ CR( 6, 2, F3, 0, 0, 0, 0), /* F3 */
+ /* 139 */ CR( 7, 1, B4, 0, 0, 0, 0), /* B4 */
+ /* 140 */ CR( 6, 2, F4, 0, 0, 0, 0), /* F4 */
+ /* 141 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */
+ /* 142 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */
+ /* LOAD_2 only */
+ /* 143 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */
+ /* 144 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */
+
+ /* LOAD_2, LOAD_C Mode 11 */
+ /* 145 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */
+ /* 146 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+ /* 147 */ CR( 6, 1, B0, 0, 0, 0, 0), /* B0 (S=0) */
+ /* 148 */ CR( 6, 2, F0, 0, 0, 0, 0), /* F0 */
+ /* 149 */ CR( 6, 1, B1, 0, 0, 0, 0), /* B1 (S=0) */
+ /* 150 */ CR( 6, 2, F1, 0, 0, 0, 0), /* F1 */
+ /* 151 */ CR( 6, 1, B2, 0, 0, 0, 0), /* B2 (S=0) */
+ /* 152 */ CR( 6, 2, F2, 0, 0, 0, 0), /* F2 */
+ /* 153 */ CR( 6, 1, B3, 0, 0, 0, 0), /* B3 (S=0) */
+ /* 154 */ CR( 7, 1, F3, 0, 0, 0, 0), /* F3 */
+ /* 155 */ CR( 8, 0, B4, 0, 0, 0, 0), /* B4 */
+ /* 156 */ CR( 8, 0, F4, 0, 0, 0, 0), /* F4 */
+ /* 157 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */
+ /* 158 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */
+ /* LOAD_2 only */
+ /* 159 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */
+ /* 160 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */
+
+ /* -------------------------------------------------------------------- */
+ /* Opcode 0011: SETMSB_3 */
+ /* Opcode 0101: SETMSB_5 */
+ /* -------------------------------------------------------------------- */
+ /* Mode 00 only */
+ /* 161 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */
+ /* Mode 00 and 01 */
+ /* 162 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */
+ /* 163 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+ /* 164 */ CR( 5, 3, F0, 0, 1, 0, 0), /* F0 (5 MSBs) */
+ /* 165 */ CR( 5, 3, F1, 0, 1, 0, 0), /* F1 (5 MSBs) */
+ /* 166 */ CR( 5, 3, F2, 0, 1, 0, 0), /* F2 (5 MSBs) */
+ /* SETMSB_3 only */
+ /* 167 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */
+ /* 168 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */
+
+ /* Mode 10 only */
+ /* 169 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */
+ /* Mode 10 and 11 */
+ /* 170 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */
+ /* 171 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */
+ /* 172 */ CR( 6, 2, F0, 0, 1, 0, 0), /* F0 (6 MSBs) */
+ /* 173 */ CR( 6, 2, F1, 0, 1, 0, 0), /* F1 (6 MSBs) */
+ /* 174 */ CR( 6, 2, F2, 0, 1, 0, 0), /* F2 (6 MSBs) */
+ /* SETMSB_3 only */
+ /* 175 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */
+ /* 176 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */
+};
+
+static const INT16 sp0256_df_idx[16 * 8] =
+{
+ /* OPCODE 0000 */ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* OPCODE 1000 */ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* OPCODE 0100 */ 17, 22, 17, 24, 25, 30, 25, 32,
+ /* OPCODE 1100 */ 83, 94, 129,142, 97, 108, 145,158,
+ /* OPCODE 0010 */ 83, 96, 129,144, 97, 110, 145,160,
+ /* OPCODE 1010 */ 73, 77, 74, 77, 78, 82, 79, 82,
+ /* OPCODE 0110 */ 33, 36, 34, 37, 38, 41, 39, 42,
+ /* OPCODE 1110 */ 127,128, 127,128, 127,128, 127,128,
+ /* OPCODE 0001 */ 1, 14, 1, 16, 1, 14, 1, 16,
+ /* OPCODE 1001 */ 45, 56, 45, 58, 59, 70, 59, 72,
+ /* OPCODE 0101 */ 161,166, 162,166, 169,174, 170,174,
+ /* OPCODE 1101 */ 111,116, 111,118, 119,124, 119,126,
+ /* OPCODE 0011 */ 161,168, 162,168, 169,176, 170,176,
+ /* OPCODE 1011 */ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* OPCODE 0111 */ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* OPCODE 1111 */ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* ======================================================================== */
+/* BITREV32 -- Bit-reverse a 32-bit number. */
+/* ======================================================================== */
+static UINT32 bitrev32(UINT32 val)
+{
+ val = ((val & 0xFFFF0000) >> 16) | ((val & 0x0000FFFF) << 16);
+ val = ((val & 0xFF00FF00) >> 8) | ((val & 0x00FF00FF) << 8);
+ val = ((val & 0xF0F0F0F0) >> 4) | ((val & 0x0F0F0F0F) << 4);
+ val = ((val & 0xCCCCCCCC) >> 2) | ((val & 0x33333333) << 2);
+ val = ((val & 0xAAAAAAAA) >> 1) | ((val & 0x55555555) << 1);
+
+ return val;
+}
+
+/* ======================================================================== */
+/* BITREV8 -- Bit-reverse a 8-bit number. */
+/* ======================================================================== */
+static UINT8 bitrev8(UINT8 val)
+{
+ val = ((val & 0xF0) >> 4) | ((val & 0x0F) << 4);
+ val = ((val & 0xCC) >> 2) | ((val & 0x33) << 2);
+ val = ((val & 0xAA) >> 1) | ((val & 0x55) << 1);
+
+ return val;
+}
+
+/* ======================================================================== */
+/* BITREVBUFF -- Bit-reverse a buffer. */
+/* ======================================================================== */
+void sp0256_bitrevbuff(UINT8 *buffer, unsigned int start, unsigned int length)
+{
+ unsigned int i;
+
+ for( i=start; i<length; i++ )
+ buffer[i] = bitrev8( buffer[i] );
+}
+
+/* ======================================================================== */
+/* SP0256_GETB -- Get up to 8 bits at the current PC. */
+/* ======================================================================== */
+static UINT32 sp0256_getb(struct sp0256 *sp, int len)
+{
+ UINT32 data = 0;
+ UINT32 d0, d1;
+
+ /* -------------------------------------------------------------------- */
+ /* Fetch data from the FIFO or from the MASK */
+ /* -------------------------------------------------------------------- */
+ if (sp->fifo_sel)
+ {
+ d0 = sp->fifo[(sp->fifo_tail ) & 63];
+ d1 = sp->fifo[(sp->fifo_tail + 1) & 63];
+
+ data = ((d1 << 10) | d0) >> sp->fifo_bitp;
+
+ LOG_FIFO( ("sp0256: RD_FIFO %.3X %d.%d %d\n", data & ((1 << len) - 1),
+ sp->fifo_tail, sp->fifo_bitp, sp->fifo_head));
+
+ /* ---------------------------------------------------------------- */
+ /* Note the PC doesn't advance when we execute from FIFO. */
+ /* Just the FIFO's bit-pointer advances. (That's not REALLY */
+ /* what happens, but that's roughly how it behaves.) */
+ /* ---------------------------------------------------------------- */
+ sp->fifo_bitp += len;
+ if (sp->fifo_bitp >= 10)
+ {
+ sp->fifo_tail++;
+ sp->fifo_bitp -= 10;
+ }
+ } else
+ {
+ /* ---------------------------------------------------------------- */
+ /* Figure out which ROMs are being fetched into, and grab two */
+ /* adjacent bytes. The byte we're interested in is extracted */
+ /* from the appropriate bit-boundary between them. */
+ /* ---------------------------------------------------------------- */
+ int idx0 = (sp->pc ) >> 3, d0;
+ int idx1 = (sp->pc + 8) >> 3, d1;
+
+ d0 = sp->rom[idx0 & 0xffff];
+ d1 = sp->rom[idx1 & 0xffff];
+
+ data = ((d1 << 8) | d0) >> (sp->pc & 7);
+
+ sp->pc += len;
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Mask data to the requested length. */
+ /* -------------------------------------------------------------------- */
+ data &= ((1 << len) - 1);
+
+ return data;
+}
+
+/* ======================================================================== */
+/* SP0256_MICRO -- Emulate the microsequencer in the SP0256. Executes */
+/* instructions either until the repeat count != 0 or */
+/* the sequencer gets halted by a RTS to 0. */
+/* ======================================================================== */
+static void sp0256_micro(struct sp0256 *sp)
+{
+ UINT8 immed4;
+ UINT8 opcode;
+ UINT16 cr;
+ int ctrl_xfer = 0;
+ int repeat = 0;
+ int i, idx0, idx1;
+
+ /* -------------------------------------------------------------------- */
+ /* Only execute instructions while the filter is not busy. */
+ /* -------------------------------------------------------------------- */
+ while (sp->filt.rpt <= 0)
+ {
+ /* ---------------------------------------------------------------- */
+ /* If the CPU is halted, see if we have a new command pending */
+ /* in the Address LoaD buffer. */
+ /* ---------------------------------------------------------------- */
+ if (sp->halted && !sp->lrq)
+ {
+ sp->pc = sp->ald | (0x1000 << 3);
+ sp->fifo_sel = 0;
+ sp->halted = 0;
+ sp->lrq = 0x8000;
+ sp->ald = 0;
+ for (i = 0; i < 16; i++)
+ sp->filt.r[i] = 0;
+ if( sp->drq) sp->drq(ASSERT_LINE);
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* If we're still halted, do nothing. */
+ /* ---------------------------------------------------------------- */
+ if (sp->halted)
+ {
+ sp->filt.rpt = 1;
+ sp->lrq = 0x8000;
+ sp->ald = 0;
+ for (i = 0; i < 16; i++)
+ sp->filt.r[i] = 0;
+
+ SET_SBY(ASSERT_LINE)
+
+ return;
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* Fetch the first 8 bits of the opcode, which are always in the */
+ /* same approximate format -- immed4 followed by opcode. */
+ /* ---------------------------------------------------------------- */
+ immed4 = sp0256_getb(sp, 4);
+ opcode = sp0256_getb(sp, 4);
+ repeat = 0;
+ ctrl_xfer = 0;
+
+ LOG(("$%.4X.%.1X: OPCODE %d%d%d%d.%d%d\n",
+ (sp->pc >> 3) - 1, sp->pc & 7,
+ !!(opcode & 1), !!(opcode & 2),
+ !!(opcode & 4), !!(opcode & 8),
+ !!(sp->mode&4), !!(sp->mode&2)));
+
+ /* ---------------------------------------------------------------- */
+ /* Handle the special cases for specific opcodes. */
+ /* ---------------------------------------------------------------- */
+ switch (opcode)
+ {
+ /* ------------------------------------------------------------ */
+ /* OPCODE 0000: RTS / SETPAGE */
+ /* ------------------------------------------------------------ */
+ case 0x0:
+ {
+ /* -------------------------------------------------------- */
+ /* If immed4 != 0, then this is a SETPAGE instruction. */
+ /* -------------------------------------------------------- */
+ if (immed4) /* SETPAGE */
+ {
+ sp->page = bitrev32(immed4) >> 13;
+ } else
+ /* -------------------------------------------------------- */
+ /* Otherwise, this is an RTS / HLT. */
+ /* -------------------------------------------------------- */
+ {
+ UINT32 btrg;
+
+ /* ---------------------------------------------------- */
+ /* Figure out our branch target. */
+ /* ---------------------------------------------------- */
+ btrg = sp->stack;
+
+ sp->stack = 0;
+
+ /* ---------------------------------------------------- */
+ /* If the branch target is zero, this is a HLT. */
+ /* Otherwise, it's an RTS, so set the PC. */
+ /* ---------------------------------------------------- */
+ if (!btrg)
+ {
+ sp->halted = 1;
+ sp->pc = 0;
+ ctrl_xfer = 1;
+ } else
+ {
+ sp->pc = btrg;
+ ctrl_xfer = 1;
+ }
+ }
+
+ break;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* OPCODE 0111: JMP Jump to 12-bit/16-bit Abs Addr */
+ /* OPCODE 1011: JSR Jump to Subroutine */
+ /* ------------------------------------------------------------ */
+ case 0xE:
+ case 0xD:
+ {
+ int btrg;
+
+ /* -------------------------------------------------------- */
+ /* Figure out our branch target. */
+ /* -------------------------------------------------------- */
+ btrg = sp->page |
+ (bitrev32(immed4) >> 17) |
+ (bitrev32(sp0256_getb(sp, 8)) >> 21);
+ ctrl_xfer = 1;
+
+ /* -------------------------------------------------------- */
+ /* If this is a JSR, push our return address on the */
+ /* stack. Make sure it's byte aligned. */
+ /* -------------------------------------------------------- */
+ if (opcode == 0xD)
+ sp->stack = (sp->pc + 7) & ~7;
+
+ /* -------------------------------------------------------- */
+ /* Jump to the new location! */
+ /* -------------------------------------------------------- */
+ sp->pc = btrg;
+ break;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* OPCODE 1000: SETMODE Set the Mode and Repeat MSBs */
+ /* ------------------------------------------------------------ */
+ case 0x1:
+ {
+ sp->mode = ((immed4 & 8) >> 2) | (immed4 & 4) |
+ ((immed4 & 3) << 4);
+ break;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* OPCODE 0001: LOADALL Load All Parameters */
+ /* OPCODE 0010: LOAD_2 Load Per, Ampl, Coefs, Interp. */
+ /* OPCODE 0011: SETMSB_3 Load Pitch, Ampl, MSBs, & Intrp */
+ /* OPCODE 0100: LOAD_4 Load Pitch, Ampl, Coeffs */
+ /* OPCODE 0101: SETMSB_5 Load Pitch, Ampl, and Coeff MSBs */
+ /* OPCODE 0110: SETMSB_6 Load Ampl, and Coeff MSBs. */
+ /* OPCODE 1001: DELTA_9 Delta update Ampl, Pitch, Coeffs */
+ /* OPCODE 1010: SETMSB_A Load Ampl and MSBs of 3 Coeffs */
+ /* OPCODE 1100: LOAD_C Load Pitch, Ampl, Coeffs */
+ /* OPCODE 1101: DELTA_D Delta update Ampl, Pitch, Coeffs */
+ /* OPCODE 1110: LOAD_E Load Pitch, Amplitude */
+ /* OPCODE 1111: PAUSE Silent pause */
+ /* ------------------------------------------------------------ */
+ default:
+ {
+ repeat = immed4 | (sp->mode & 0x30);
+ break;
+ }
+ }
+ if (opcode != 1) sp->mode &= 0xF;
+
+ /* ---------------------------------------------------------------- */
+ /* If this was a control transfer, handle setting "fifo_sel" */
+ /* and all that ugliness. */
+ /* ---------------------------------------------------------------- */
+ if (ctrl_xfer)
+ {
+ LOG(("jumping to $%.4X.%.1X: ", sp->pc >> 3, sp->pc & 7));
+
+ /* ------------------------------------------------------------ */
+ /* Set our "FIFO Selected" flag based on whether we're going */
+ /* to the FIFO's address. */
+ /* ------------------------------------------------------------ */
+ sp->fifo_sel = sp->pc == FIFO_ADDR;
+
+ LOG(("%s ", sp->fifo_sel ? "FIFO" : "ROM"));
+
+ /* ------------------------------------------------------------ */
+ /* Control transfers to the FIFO cause it to discard the */
+ /* partial decle that's at the front of the FIFO. */
+ /* ------------------------------------------------------------ */
+ if (sp->fifo_sel && sp->fifo_bitp)
+ {
+ LOG(("bitp = %d -> Flush", sp->fifo_bitp));
+
+ /* Discard partially-read decle. */
+ if (sp->fifo_tail < sp->fifo_head) sp->fifo_tail++;
+ sp->fifo_bitp = 0;
+ }
+
+ LOG(("\n"));
+
+ continue;
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* Otherwise, if we have a repeat count, then go grab the data */
+ /* block and feed it to the filter. */
+ /* ---------------------------------------------------------------- */
+ if (!repeat) continue;
+
+ sp->filt.rpt = repeat + 1;
+ LOG(("repeat = %d\n", repeat));
+
+ i = (opcode << 3) | (sp->mode & 6);
+ idx0 = sp0256_df_idx[i++];
+ idx1 = sp0256_df_idx[i ];
+
+ assert(idx0 >= 0 && idx1 >= 0 && idx1 >= idx0);
+
+ /* ---------------------------------------------------------------- */
+ /* Step through control words in the description for data block. */
+ /* ---------------------------------------------------------------- */
+ for (i = idx0; i <= idx1; i++)
+ {
+ int len, shf, delta, field, prm, clra, clr5;
+ INT8 value;
+
+ /* ------------------------------------------------------------ */
+ /* Get the control word and pull out some important fields. */
+ /* ------------------------------------------------------------ */
+ cr = sp0256_datafmt[i];
+
+ len = CR_LEN(cr);
+ shf = CR_SHF(cr);
+ prm = CR_PRM(cr);
+ clra = cr & CR_CLRA;
+ clr5 = cr & CR_CLR5;
+ delta = cr & CR_DELTA;
+ field = cr & CR_FIELD;
+ value = 0;
+
+ LOG(("$%.4X.%.1X: len=%2d shf=%2d prm=%2d d=%d f=%d ",
+ sp->pc >> 3, sp->pc & 7, len, shf, prm, !!delta, !!field));
+ /* ------------------------------------------------------------ */
+ /* Clear any registers that were requested to be cleared. */
+ /* ------------------------------------------------------------ */
+ if (clra)
+ {
+ int j;
+
+ for (j = 0; j < 16; j++)
+ sp->filt.r[j] = 0;
+
+ sp->silent = 1;
+ }
+
+ if (clr5)
+ sp->filt.r[B5] = sp->filt.r[F5] = 0;
+
+ /* ------------------------------------------------------------ */
+ /* If this entry has a bitfield with it, grab the bitfield. */
+ /* ------------------------------------------------------------ */
+ if (len)
+ {
+ value = sp0256_getb(sp, len);
+ }
+ else
+ {
+ LOG((" (no update)\n"));
+ continue;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* Sign extend if this is a delta update. */
+ /* ------------------------------------------------------------ */
+ if (delta) /* Sign extend */
+ {
+ if (value & (1 << (len - 1))) value |= -1 << len;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* Shift the value to the appropriate precision. */
+ /* ------------------------------------------------------------ */
+ if (shf)
+ value <<= shf;
+
+ LOG(("v=%.2X (%c%.2X) ", value & 0xFF,
+ value & 0x80 ? '-' : '+',
+ 0xFF & (value & 0x80 ? -value : value)));
+
+ sp->silent = 0;
+
+ /* ------------------------------------------------------------ */
+ /* If this is a field-replace, insert the field. */
+ /* ------------------------------------------------------------ */
+ if (field)
+ {
+ LOG(("--field-> r[%2d] = %.2X -> ", prm, sp->filt.r[prm]));
+
+ sp->filt.r[prm] &= ~(~0 << shf); /* Clear the old bits. */
+ sp->filt.r[prm] |= value; /* Merge in the new bits. */
+
+ LOG(("%.2X\n", sp->filt.r[prm]));
+
+ continue;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* If this is a delta update, add to the appropriate field. */
+ /* ------------------------------------------------------------ */
+ if (delta)
+ {
+ LOG(("--delta-> r[%2d] = %.2X -> ", prm, sp->filt.r[prm]));
+
+ sp->filt.r[prm] += value;
+
+ LOG(("%.2X\n", sp->filt.r[prm]));
+
+ continue;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* Otherwise, just write the new value. */
+ /* ------------------------------------------------------------ */
+ sp->filt.r[prm] = value;
+ LOG(("--value-> r[%2d] = %.2X\n", prm, sp->filt.r[prm]));
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* Special case: Set PAUSE's equivalent period. */
+ /* ---------------------------------------------------------------- */
+ if (opcode == 0xF)
+ {
+ sp->silent = 1;
+ sp->filt.r[1] = PER_PAUSE;
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* Now that we've updated the registers, go decode them. */
+ /* ---------------------------------------------------------------- */
+ lpc12_regdec(&sp->filt);
+
+ /* ---------------------------------------------------------------- */
+ /* Break out since we now have a repeat count. */
+ /* ---------------------------------------------------------------- */
+ break;
+ }
+}
+
+static void sp0256_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct sp0256 *sp = param;
+ stream_sample_t *output = buffer[0];
+ int output_index = 0;
+ int samples, did_samp, old_idx;
+
+ while( output_index < length )
+ {
+ /* ---------------------------------------------------------------- */
+ /* First, drain as much of our scratch buffer as we can into the */
+ /* sound buffer. */
+ /* ---------------------------------------------------------------- */
+
+ while( sp->sc_tail != sp->sc_head )
+ {
+ output[output_index++] = sp->scratch[sp->sc_tail++ & SCBUF_MASK];
+ sp->sc_tail &= SCBUF_MASK;
+
+ if( output_index > length )
+ break;
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* If output buffer is full, then we're done. */
+ /* ---------------------------------------------------------------- */
+ if( output_index > length )
+ break;
+
+ samples = length - output_index;
+
+ /* ---------------------------------------------------------------- */
+ /* Process the current set of filter coefficients as long as the */
+ /* repeat count holds up and we have room in our scratch buffer. */
+ /* ---------------------------------------------------------------- */
+ did_samp = 0;
+ old_idx = sp->sc_head;
+ if (samples > 0) do
+ {
+ int do_samp;
+
+ /* ------------------------------------------------------------ */
+ /* If our repeat count expired, emulate the microsequencer. */
+ /* ------------------------------------------------------------ */
+ if (sp->filt.rpt <= 0)
+ sp0256_micro(sp);
+
+ /* ------------------------------------------------------------ */
+ /* Do as many samples as we can. */
+ /* ------------------------------------------------------------ */
+ do_samp = samples - did_samp;
+ if (sp->sc_head + do_samp - sp->sc_tail > SCBUF_SIZE)
+ do_samp = sp->sc_tail + SCBUF_SIZE - sp->sc_head;
+
+ if (do_samp == 0) break;
+
+ if (sp->silent && sp->filt.rpt <= 0)
+ {
+ int x, y = sp->sc_head;
+
+ for (x = 0; x < do_samp; x++)
+ sp->scratch[y++ & SCBUF_MASK] = 0;
+ sp->sc_head += do_samp;
+ did_samp += do_samp;
+ }
+ else
+ {
+ did_samp += lpc12_update(&sp->filt, do_samp,
+ sp->scratch, &sp->sc_head);
+ }
+
+ sp->sc_head &= SCBUF_MASK;
+
+ } while (sp->filt.rpt >= 0 && samples > did_samp);
+ }
+}
+
+static void *sp0256_start(int sndindex, int clock, const void *config)
+{
+ const struct sp0256_interface *intf = config;
+ struct sp0256 *sp;
+
+ sp = auto_malloc(sizeof(*sp));
+ memset(sp, 0, sizeof(*sp));
+ sp->drq = intf->lrq_callback;
+ sp->sby = intf->sby_callback;
+ if( sp->drq ) sp->drq(ASSERT_LINE);
+ if( sp->sby ) sp->sby(sp->sby_line = ASSERT_LINE);
+
+ sp->stream = stream_create(0, 1, clock / CLOCK_DIVIDER, sp, sp0256_update);
+
+ /* -------------------------------------------------------------------- */
+ /* Configure our internal variables. */
+ /* -------------------------------------------------------------------- */
+ sp->filt.rng = 1;
+
+ /* -------------------------------------------------------------------- */
+ /* Allocate a scratch buffer for generating ~10kHz samples. */
+ /* -------------------------------------------------------------------- */
+ sp->scratch = malloc_or_die(SCBUF_SIZE * sizeof(INT16));
+ sp->sc_head = sp->sc_tail = 0;
+
+ /* -------------------------------------------------------------------- */
+ /* Set up the microsequencer's initial state. */
+ /* -------------------------------------------------------------------- */
+ sp->halted = 1;
+ sp->filt.rpt = -1;
+ sp->lrq = 0x8000;
+ sp->page = 0x1000 << 3;
+ sp->silent = 1;
+
+ /* -------------------------------------------------------------------- */
+ /* Setup the ROM. */
+ /* -------------------------------------------------------------------- */
+ sp->rom = memory_region(intf->memory_region);
+ sp0256_bitrevbuff(sp->rom, 0, 0xffff);
+
+ return sp;
+}
+
+static void sp0256_stop(void *token)
+{
+ struct sp0256 *sp = token;
+ free( sp->scratch );
+}
+
+void sp0256_reset(void *token)
+{
+ struct sp0256 *sp = token;
+
+ /* ---------------------------------------------------------------- */
+ /* Reset the FIFO and SP0256. */
+ /* ---------------------------------------------------------------- */
+ sp->fifo_head = sp->fifo_tail = sp->fifo_bitp = 0;
+
+ memset(&sp->filt, 0, sizeof(sp->filt));
+ sp->halted = 1;
+ sp->filt.rpt = -1;
+ sp->filt.rng = 1;
+ sp->lrq = 0x8000;
+ sp->ald = 0x0000;
+ sp->pc = 0x0000;
+ sp->stack = 0x0000;
+ sp->fifo_sel = 0;
+ sp->mode = 0;
+ sp->page = 0x1000 << 3;
+ sp->silent = 1;
+ if( sp->drq ) sp->drq(ASSERT_LINE);
+ SET_SBY(ASSERT_LINE)
+}
+
+WRITE8_HANDLER( sp0256_ALD_w )
+{
+ struct sp0256 *sp = sndti_token(SOUND_SP0256, 0);
+
+ /* ---------------------------------------------------------------- */
+ /* Drop writes to the ALD register if we're busy. */
+ /* ---------------------------------------------------------------- */
+ if (!sp->lrq)
+ {
+ LOG(( "sp0256: Droped ALD write\n" ));
+ return;
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* Set LRQ to "busy" and load the 8 LSBs of the data into the ALD */
+ /* reg. We take the command address, and multiply by 2 bytes to */
+ /* get the new PC address. */
+ /* ---------------------------------------------------------------- */
+ sp->lrq = 0;
+ sp->ald = (0xFF & data) << 4;
+ if( sp->drq ) sp->drq(CLEAR_LINE);
+ SET_SBY(CLEAR_LINE)
+
+ return;
+}
+
+READ16_HANDLER( spb640_r )
+{
+ struct sp0256 *sp = sndti_token(SOUND_SP0256, 0);
+
+ /* -------------------------------------------------------------------- */
+ /* Offset 0 returns the SP0256 LRQ status on bit 15. */
+ /* -------------------------------------------------------------------- */
+ if (offset == 0)
+ {
+ return sp->lrq;
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Offset 1 returns the SPB640 FIFO full status on bit 15. */
+ /* -------------------------------------------------------------------- */
+ if (offset == 1)
+ {
+ return (sp->fifo_head - sp->fifo_tail) >= 64 ? 0x8000 : 0;
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Just return 255 for all other addresses in our range. */
+ /* -------------------------------------------------------------------- */
+ return 0x00FF;
+}
+
+WRITE16_HANDLER( spb640_w )
+{
+ struct sp0256 *sp = sndti_token(SOUND_SP0256, 0);
+
+ if( offset == 0 )
+ {
+ sp0256_ALD_w( 0, data & 0xff );
+ return;
+ }
+
+ if( offset == 1 )
+ {
+ /* ---------------------------------------------------------------- */
+ /* If Bit 10 is set, reset the FIFO, and SP0256. */
+ /* ---------------------------------------------------------------- */
+
+ if (data & 0x400)
+ {
+ sp->fifo_head = sp->fifo_tail = sp->fifo_bitp = 0;
+ sp0256_reset(sp);
+ return;
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* If the FIFO is full, drop the data. */
+ /* ---------------------------------------------------------------- */
+ if ((sp->fifo_head - sp->fifo_tail) >= 64)
+ {
+ LOG(("spb640: Dropped FIFO write\n"));
+ return;
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* FIFO up the lower 10 bits of the data. */
+ /* ---------------------------------------------------------------- */
+
+ LOG(("spb640: WR_FIFO %.3X %d.%d %d\n", data & 0x3FF,
+ sp->fifo_tail, sp->fifo_bitp, sp->fifo_head));
+
+ sp->fifo[sp->fifo_head++ & 63] = data & 0x3FF;
+
+ return;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void sp0256_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void sp0256_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = sp0256_set_info; break;
+ case SNDINFO_PTR_START: info->start = sp0256_start; break;
+ case SNDINFO_PTR_STOP: info->stop = sp0256_stop; break;
+ case SNDINFO_PTR_RESET: info->reset = sp0256_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "SP0256"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "GI"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2006, Joseph Zbiciak, tim lindner"; break;
+ }
+}
+
diff --git a/src/emu/sound/sp0256.h b/src/emu/sound/sp0256.h
new file mode 100644
index 00000000000..fd9d0dba893
--- /dev/null
+++ b/src/emu/sound/sp0256.h
@@ -0,0 +1,37 @@
+#ifndef __SP0256_H__
+#define __SP0256_H__
+
+/*
+ GI SP0256 Narrator Speech Processor
+
+ By Joe Zbiciak. Ported to MESS by tim lindner.
+
+ Copyright (c) 1998-2000, Joseph Zbiciak, all rights reserved.
+ Copyright (c) 2006, tim lindner, all rights reserved.
+
+ - This source code is released as freeware for non-commercial purposes.
+ - You are free to use and redistribute this code in modified or
+ unmodified form, provided you list us in the credits.
+ - If you modify this source code, you must add a notice to each
+ modified source file that it has been changed. If you're a nice
+ person, you will clearly mark each change too. :)
+ - If you wish to use this for commercial purposes, please contact us at
+ intvnut@gmail.com (Joe Zbiciak), tlindner@macmess.org (tim lindner)
+ - This entire notice must remain in the source code.
+
+*/
+
+struct sp0256_interface {
+ void (*lrq_callback)(int state);
+ void (*sby_callback)(int state);
+ int memory_region;
+};
+
+void sp0256_bitrevbuff(UINT8 *buffer, unsigned int start, unsigned int length);
+
+WRITE8_HANDLER( sp0256_ALD_w );
+
+READ16_HANDLER( spb640_r );
+WRITE16_HANDLER( spb640_w );
+
+#endif
diff --git a/src/emu/sound/speaker.c b/src/emu/sound/speaker.c
new file mode 100644
index 00000000000..4fba85bb5e3
--- /dev/null
+++ b/src/emu/sound/speaker.c
@@ -0,0 +1,104 @@
+/***************************************************************************
+
+ speaker.c
+
+ Sound driver to emulate a simple speaker,
+ driven by one or more output bits
+
+****************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "speaker.h"
+
+static INT16 default_levels[2] = {0,32767};
+
+struct speaker
+{
+ sound_stream *channel;
+ INT16 *levels;
+ int num_levels;
+ int level;
+};
+
+
+
+static void speaker_sound_update(void *param,stream_sample_t **inputs, stream_sample_t **_buffer,int length)
+{
+ struct speaker *sp = (struct speaker *) param;
+ stream_sample_t *buffer = _buffer[0];
+ int volume = sp->levels[sp->level];
+
+ while( length-- > 0 )
+ *buffer++ = volume;
+}
+
+
+
+static void *speaker_start(int sndindex, int clock, const void *config)
+{
+ struct speaker *sp = auto_malloc(sizeof(*sp));
+
+ sp->channel = stream_create(0, 1, Machine->sample_rate, sp, speaker_sound_update);
+ sp->num_levels = 2;
+ sp->levels = default_levels;
+ sp->level = 0;
+ return sp;
+}
+
+
+
+void speaker_level_w(int which, int new_level)
+{
+ struct speaker *sp = sndti_token(SOUND_SPEAKER, which);
+
+ if( new_level < 0 )
+ new_level = 0;
+ else
+ if( new_level >= sp->num_levels )
+ new_level = sp->num_levels - 1;
+
+ if( new_level == sp->level )
+ return;
+
+ /* force streams.c to update sound until this point in time now */
+ stream_update(sp->channel);
+
+ sp->level = new_level;
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void speaker_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void speaker_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = speaker_set_info; break;
+ case SNDINFO_PTR_START: info->start = speaker_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Speaker"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Speaker"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2005, The MESS Team"; break;
+ }
+}
diff --git a/src/emu/sound/speaker.h b/src/emu/sound/speaker.h
new file mode 100644
index 00000000000..ae89881bb80
--- /dev/null
+++ b/src/emu/sound/speaker.h
@@ -0,0 +1,29 @@
+/**********************************************************************
+
+ speaker.h
+ Sound driver to emulate a simple speaker,
+ driven by one or more output bits
+
+**********************************************************************/
+#ifndef SPEAKER_H
+#define SPEAKER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Speaker_interface
+{
+ int num_level; /* optional: number of levels (if not two) */
+ INT16 *levels; /* optional: pointer to level lookup table */
+};
+
+void speaker_level_w (int which, int new_level);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/src/emu/sound/st0016.c b/src/emu/sound/st0016.c
new file mode 100644
index 00000000000..c1c121fa5f3
--- /dev/null
+++ b/src/emu/sound/st0016.c
@@ -0,0 +1,180 @@
+/************************************
+ Seta custom ST-0016 chip
+ sound emulation by R. Belmont, Tomasz Slanina, and David Haywood
+************************************/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "st0016.h"
+
+#define VERBOSE (0)
+
+UINT8 *st0016_sound_regs;
+
+struct st0016_info
+{
+ sound_stream * stream;
+ UINT8 **sound_ram;
+ int vpos[8], frac[8], lponce[8];
+};
+
+WRITE8_HANDLER(st0016_snd_w)
+{
+ struct st0016_info *info = sndti_token(SOUND_ST0016, 0);
+ int voice = offset/32;
+ int reg = offset & 0x1f;
+ int oldreg = st0016_sound_regs[offset];
+#if VERBOSE
+ int vbase = offset & ~0x1f;
+#endif
+
+ st0016_sound_regs[offset] = data;
+
+ if ((voice < 8) && (data != oldreg))
+ {
+ if ((reg == 0x16) && (data != 0))
+ {
+ info->vpos[voice] = info->frac[voice] = info->lponce[voice] = 0;
+
+#if VERBOSE
+ logerror("Key on V%02d: st %06x-%06x lp %06x-%06x frq %x flg %x\n", voice,
+ st0016_sound_regs[vbase+2]<<16 | st0016_sound_regs[vbase+1]<<8 | st0016_sound_regs[vbase+2],
+ st0016_sound_regs[vbase+0xe]<<16 | st0016_sound_regs[vbase+0xd]<<8 | st0016_sound_regs[vbase+0xc],
+ st0016_sound_regs[vbase+6]<<16 | st0016_sound_regs[vbase+5]<<8 | st0016_sound_regs[vbase+4],
+ st0016_sound_regs[vbase+0xa]<<16 | st0016_sound_regs[vbase+0x9]<<8 | st0016_sound_regs[vbase+0x8],
+ st0016_sound_regs[vbase+0x11]<<8 | st0016_sound_regs[vbase+0x10],
+ st0016_sound_regs[vbase+0x16]);
+#endif
+ }
+ }
+}
+
+static void st0016_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length)
+{
+ struct st0016_info *info = param;
+ UINT8 *sound_ram = *info->sound_ram;
+ int v, i, snum;
+ unsigned char *slot;
+ INT32 mix[48000*2];
+ INT32 *mixp;
+ INT16 sample;
+ int sptr, eptr, freq, lsptr, leptr;
+
+ memset(mix, 0, sizeof(mix[0])*length*2);
+
+ for (v = 0; v < 8; v++)
+ {
+ slot = (unsigned char *)&st0016_sound_regs[v * 32];
+
+ if (slot[0x16] & 0x06)
+ {
+ mixp = &mix[0];
+
+ sptr = slot[0x02]<<16 | slot[0x01]<<8 | slot[0x00];
+ eptr = slot[0x0e]<<16 | slot[0x0d]<<8 | slot[0x0c];
+ freq = slot[0x11]<<8 | slot[0x10];
+ lsptr = slot[0x06]<<16 | slot[0x05]<<8 | slot[0x04];
+ leptr = slot[0x0a]<<16 | slot[0x09]<<8 | slot[0x08];
+
+ for (snum = 0; snum < length; snum++)
+ {
+ sample = sound_ram[(sptr + info->vpos[v])&0x1fffff]<<8;
+
+ *mixp++ += (sample * (char)slot[0x14]) >> 8;
+ *mixp++ += (sample * (char)slot[0x15]) >> 8;
+
+ info->frac[v] += freq;
+ info->vpos[v] += (info->frac[v]>>16);
+ info->frac[v] &= 0xffff;
+
+ // stop if we're at the end
+ if (info->lponce[v])
+ {
+ // we've looped once, check loop end rather than sample end
+ if ((info->vpos[v] + sptr) >= leptr)
+ {
+ info->vpos[v] = (lsptr - sptr);
+ }
+ }
+ else
+ {
+ // not looped yet, check sample end
+ if ((info->vpos[v] + sptr) >= eptr)
+ {
+ if (slot[0x16] & 0x01) // loop?
+ {
+ info->vpos[v] = (lsptr - sptr);
+ info->lponce[v] = 1;
+ }
+ else
+ {
+ slot[0x16] = 0;
+ info->vpos[v] = info->frac[v] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ mixp = &mix[0];
+ for (i = 0; i < length; i++)
+ {
+ outputs[0][i] = (*mixp++)>>4;
+ outputs[1][i] = (*mixp++)>>4;
+ }
+}
+
+static void *st0016_start(int sndindex, int clock, const void *config)
+{
+ const struct ST0016interface *intf = config;
+ struct st0016_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->sound_ram = intf->p_soundram;
+
+ info->stream = stream_create(0, 2, 44100, info, st0016_update);
+
+ return info;
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void st0016_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void st0016_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = st0016_set_info; break;
+ case SNDINFO_PTR_START: info->start = st0016_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "ST0016"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Seta custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/st0016.h b/src/emu/sound/st0016.h
new file mode 100644
index 00000000000..c6e5c0ba0cd
--- /dev/null
+++ b/src/emu/sound/st0016.h
@@ -0,0 +1,14 @@
+#ifndef _ST0016_H_
+#define _ST0016_H_
+
+struct ST0016interface
+{
+ UINT8 **p_soundram;
+};
+
+extern UINT8 *st0016_sound_regs;
+
+WRITE8_HANDLER(st0016_snd_w);
+
+#endif
+
diff --git a/src/emu/sound/tiaintf.c b/src/emu/sound/tiaintf.c
new file mode 100644
index 00000000000..b931829115d
--- /dev/null
+++ b/src/emu/sound/tiaintf.c
@@ -0,0 +1,85 @@
+#include "sndintrf.h"
+#include "streams.h"
+#include "tiaintf.h"
+#include "tiasound.h"
+
+struct tia_info
+{
+ sound_stream * channel;
+ void *chip;
+};
+
+
+static void tia_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct tia_info *info = param;
+ tia_process(info->chip, buffer[0], length);
+}
+
+
+static void *tia_start(int sndindex, int clock, const void *config)
+{
+ struct tia_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->channel = stream_create(0, 1, clock, info, tia_update);
+
+ info->chip = tia_sound_init(clock, clock, 16);
+ if (!info->chip)
+ return NULL;
+
+ return info;
+}
+
+static void tia_stop(void *token)
+{
+ struct tia_info *info = (struct tia_info*)token;
+ tia_sound_free(info->chip);
+}
+
+WRITE8_HANDLER( tia_sound_w )
+{
+ struct tia_info *info = sndti_token(SOUND_TIA, 0);
+ stream_update(info->channel);
+ tia_write(info->chip, offset, data);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void tia_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void tia_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = tia_set_info; break;
+ case SNDINFO_PTR_START: info->start = tia_start; break;
+ case SNDINFO_PTR_STOP: info->stop = tia_stop; break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "TIA"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Atari custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/tiaintf.h b/src/emu/sound/tiaintf.h
new file mode 100644
index 00000000000..e7d404faedc
--- /dev/null
+++ b/src/emu/sound/tiaintf.h
@@ -0,0 +1,8 @@
+#ifndef TIA_H
+#define TIA_H
+
+WRITE8_HANDLER( tia_sound_w );
+
+#endif
+
+
diff --git a/src/emu/sound/tiasound.c b/src/emu/sound/tiasound.c
new file mode 100644
index 00000000000..8f40737260e
--- /dev/null
+++ b/src/emu/sound/tiasound.c
@@ -0,0 +1,596 @@
+/*****************************************************************************/
+/* */
+/* Module: TIA Chip Sound Simulator */
+/* Purpose: To emulate the sound generation hardware of the Atari TIA chip. */
+/* Author: Ron Fries */
+/* */
+/* Revision History: */
+/* 10-Sep-96 - V1.0 - Initial Release */
+/* 14-Jan-97 - V1.1 - Cleaned up sound output by eliminating counter */
+/* reset. */
+/* 30-Oct-98 - Modified for use in MESS by Dan Boris */
+/* 28-Jul-01 - Added support for sample rates > TIA clock rate, */
+/* through oversampling */
+/* 30-Jun-07 - Updated the poly generation. Improved handling of the */
+/* POLY5_DIV3 mode. (Wilbert Pol) */
+/* */
+/* */
+/* */
+/*****************************************************************************/
+/* */
+/* License Information and Copyright Notice */
+/* ======================================== */
+/* */
+/* TiaSound is Copyright(c) 1996 by Ron Fries */
+/* */
+/* This library is free software; you can redistribute it and/or modify it */
+/* under the terms of version 2 of the GNU Library General Public License */
+/* as published by the Free Software Foundation. */
+/* */
+/* This library is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library */
+/* General Public License for more details. */
+/* To obtain a copy of the GNU Library General Public License, write to the */
+/* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* */
+/* Any permitted reproduction of these routines, in whole or in part, must */
+/* bear this legend. */
+/* */
+/*****************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "tiaintf.h"
+#include "tiasound.h"
+
+/* number of bits to shift left AUDV0/AUDV1 registers for 16 bit volume */
+#define AUDV_SHIFT 10
+
+/* CONSTANT DEFINITIONS */
+
+/* definitions for AUDCx (15, 16) */
+#define SET_TO_1 0x00 /* 0000 */
+#define POLY4 0x01 /* 0001 */
+#define DIV31_POLY4 0x02 /* 0010 */
+#define POLY5_POLY4 0x03 /* 0011 */
+#define PURE 0x04 /* 0100 */
+#define PURE2 0x05 /* 0101 */
+#define DIV31_PURE 0x06 /* 0110 */
+#define POLY5_2 0x07 /* 0111 */
+#define POLY9 0x08 /* 1000 */
+#define POLY5 0x09 /* 1001 */
+#define DIV31_POLY5 0x0a /* 1010 */
+#define POLY5_POLY5 0x0b /* 1011 */
+#define DIV3_PURE 0x0c /* 1100 */
+#define DIV3_PURE2 0x0d /* 1101 */
+#define DIV93_PURE 0x0e /* 1110 */
+#define POLY5_DIV3 0x0f /* 1111 */
+
+#define DIV3_MASK 0x0c
+
+#define AUDC0 0x15
+#define AUDC1 0x16
+#define AUDF0 0x17
+#define AUDF1 0x18
+#define AUDV0 0x19
+#define AUDV1 0x1a
+
+/* the size (in entries) of the 4 polynomial tables */
+#define POLY4_SIZE 0x000f
+#define POLY5_SIZE 0x001f
+#define POLY9_SIZE 0x01ff
+
+/* channel definitions */
+#define CHAN1 0
+#define CHAN2 1
+
+/* LOCAL GLOBAL VARIABLE DEFINITIONS */
+
+struct tia
+{
+ /* structures to hold the 6 tia sound control bytes */
+ UINT8 AUDC[2]; /* AUDCx (15, 16) */
+ UINT8 AUDF[2]; /* AUDFx (17, 18) */
+ INT16 AUDV[2]; /* AUDVx (19, 1A) */
+
+ INT16 Outvol[2]; /* last output volume for each channel */
+
+ int tia_gain; /* initialized in tia_sound_init() */
+
+ /* Initialze the bit patterns for the polynomials. */
+
+ /* The 4bit and 5bit patterns are the identical ones used in the tia chip. */
+ /* Though the patterns could be packed with 8 bits per byte, using only a */
+ /* single bit per byte keeps the math simple, which is important for */
+ /* efficient processing. */
+
+ /* HJB: poly bits are initialized at runtime */
+
+ UINT8 Bit4[POLY4_SIZE];
+ UINT8 Bit5[POLY5_SIZE];
+ UINT8 Bit9[POLY9_SIZE];
+
+
+ UINT8 P4[2]; /* Position pointer for the 4-bit POLY array */
+ UINT8 P5[2]; /* Position pointer for the 5-bit POLY array */
+ UINT16 P9[2]; /* Position pointer for the 9-bit POLY array */
+
+ UINT8 Div_n_cnt[2]; /* Divide by n counter. one for each channel */
+ UINT8 Div_n_max[2]; /* Divide by n maximum, one for each channel */
+ UINT8 Div_3_cnt[2]; /* Div 3 counter, used for POLY5_DIV3 mode */
+
+
+ /* In my routines, I treat the sample output as another divide by N counter. */
+ /* For better accuracy, the Samp_n_cnt has a fixed binary decimal point */
+ /* which has 8 binary digits to the right of the decimal point. */
+
+ UINT16 Samp_n_max; /* Sample max, multiplied by 256 */
+ UINT16 Samp_n_cnt; /* Sample cnt. */
+
+ int oversampling; /* Added oversampling for sample_rate > clock_rate */
+};
+
+
+/* I've treated the 'Div by 31' counter as another polynomial because of */
+/* the way it operates. It does not have a 50% duty cycle, but instead */
+/* has a 13:18 ratio (of course, 13+18 = 31). This could also be */
+/* implemented by using counters. */
+
+static const UINT8 Div31[POLY5_SIZE] =
+ {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+
+/*****************************************************************************/
+/* Module: tia_sound_w() */
+/* Purpose: To process the latest control values stored in the AUDF, AUDC, */
+/* and AUDV registers. It pre-calculates as much information as */
+/* possible for better performance. This routine has not been */
+/* optimized. */
+/* */
+/* Author: Ron Fries */
+/* Date: January 14, 1997 */
+/* */
+/* Inputs: addr - the address of the parameter to be changed */
+/* val - the new value to be placed in the specified address */
+/* */
+/* Outputs: Adjusts local globals - no return value */
+/* */
+/*****************************************************************************/
+
+void tia_write(void *_chip, offs_t offset, UINT8 data)
+{
+ struct tia *chip = _chip;
+ UINT16 new_val = 0;
+ UINT8 chan;
+
+ /* determine which address was changed */
+ switch (offset)
+ {
+ case AUDC0:
+ chip->AUDC[0] = data & 0x0f;
+ chan = 0;
+ break;
+
+ case AUDC1:
+ chip->AUDC[1] = data & 0x0f;
+ chan = 1;
+ break;
+
+ case AUDF0:
+ chip->AUDF[0] = data & 0x1f;
+ chan = 0;
+ break;
+
+ case AUDF1:
+ chip->AUDF[1] = data & 0x1f;
+ chan = 1;
+ break;
+
+ case AUDV0:
+ chip->AUDV[0] = ((data & 0x0f) << AUDV_SHIFT);
+ chan = 0;
+ break;
+
+ case AUDV1:
+ chip->AUDV[1] = ((data & 0x0f) << AUDV_SHIFT);
+ chan = 1;
+ break;
+
+ default:
+ chan = 255;
+ break;
+ }
+
+ /* if the output value changed */
+ if (chan != 255)
+ {
+ /* an AUDC value of 0 is a special case */
+ if (chip->AUDC[chan] == SET_TO_1 || chip->AUDC[chan] == POLY5_POLY5)
+ {
+ /* indicate the clock is zero so no processing will occur */
+ new_val = 0;
+
+ /* and set the output to the selected volume */
+ chip->Outvol[chan] = chip->AUDV[chan];
+ }
+ else
+ {
+ /* otherwise calculate the 'divide by N' value */
+ new_val = chip->AUDF[chan] + 1;
+
+ /* if bits 2 & 3 are set, then multiply the 'div by n' count by 3 */
+ if ((chip->AUDC[chan] & DIV3_MASK) == DIV3_MASK && chip->AUDC[chan] != POLY5_DIV3)
+ {
+ new_val *= 3;
+ }
+ }
+
+ /* only reset those channels that have changed */
+ if (new_val != chip->Div_n_max[chan])
+ {
+ /* reset the divide by n counters */
+ chip->Div_n_max[chan] = new_val;
+
+ /* if the channel is now volume only or was volume only */
+ if ((chip->Div_n_cnt[chan] == 0) || (new_val == 0))
+ {
+ /* reset the counter (otherwise let it complete the previous) */
+ chip->Div_n_cnt[chan] = new_val;
+ }
+ }
+ }
+}
+
+
+/*****************************************************************************/
+/* Module: tia_process() */
+/* Purpose: To fill the output buffer with the sound output based on the */
+/* tia chip parameters. This routine has been optimized. */
+/* */
+/* Author: Ron Fries */
+/* Date: September 10, 1996 */
+/* */
+/* Inputs: *buffer - pointer to the buffer where the audio output will */
+/* be placed */
+/* n - size of the playback buffer */
+/* */
+/* Outputs: the buffer will be filled with n bytes of audio - no return val */
+/* */
+/*****************************************************************************/
+
+void tia_process(void *_chip, stream_sample_t *buffer, int length)
+{
+ struct tia *chip = _chip;
+ UINT8 audc0, audc1;
+ UINT8 div_n_cnt0, div_n_cnt1;
+ UINT8 p5_0, p5_1;
+ INT16 audv0, audv1, outvol_0, outvol_1;
+
+ audc0 = chip->AUDC[0];
+ audc1 = chip->AUDC[1];
+ audv0 = chip->AUDV[0];
+ audv1 = chip->AUDV[1];
+
+ /* make temporary local copy */
+ p5_0 = chip->P5[0];
+ p5_1 = chip->P5[1];
+ outvol_0 = chip->Outvol[0];
+ outvol_1 = chip->Outvol[1];
+ div_n_cnt0 = chip->Div_n_cnt[0];
+ div_n_cnt1 = chip->Div_n_cnt[1];
+
+ /* loop until the buffer is filled */
+ while (length > 0)
+ {
+ /* Process channel 0 */
+ if (div_n_cnt0 > 1)
+ {
+ div_n_cnt0--;
+ }
+ else if (div_n_cnt0 == 1)
+ {
+ int prev_bit5 = chip->Bit5[p5_0];
+
+ div_n_cnt0 = chip->Div_n_max[0];
+
+ /* the chip->P5 counter has multiple uses, so we inc it here */
+ p5_0++;
+ if (p5_0 == POLY5_SIZE)
+ p5_0 = 0;
+
+ /* check clock modifier for clock tick */
+ if ((audc0 & 0x02) == 0 ||
+ ((audc0 & 0x01) == 0 && Div31[p5_0]) ||
+ ((audc0 & 0x01) == 1 && chip->Bit5[p5_0]) ||
+ ((audc0 & 0x0f) == POLY5_DIV3 && chip->Bit5[p5_0] != prev_bit5))
+ {
+ if (audc0 & 0x04) /* pure modified clock selected */
+ {
+ if ((audc0 & 0x0f) == POLY5_DIV3) /* POLY5 -> DIV3 mode */
+ {
+ if ( chip->Bit5[p5_0] != prev_bit5 )
+ {
+ chip->Div_3_cnt[0]--;
+ if ( ! chip->Div_3_cnt[0] )
+ {
+ chip->Div_3_cnt[0] = 3;
+ if (outvol_0)
+ outvol_0 = 0;
+ else
+ outvol_0 = audv0;
+ }
+ }
+ }
+ else if (outvol_0) /* if the output was set */
+ outvol_0 = 0; /* turn it off */
+ else
+ outvol_0 = audv0; /* else turn it on */
+ }
+ else if (audc0 & 0x08) /* check for p5/p9 */
+ {
+ if (audc0 == POLY9) /* check for poly9 */
+ {
+ /* inc the poly9 counter */
+ chip->P9[0]++;
+ if (chip->P9[0] == POLY9_SIZE)
+ chip->P9[0] = 0;
+
+ if (chip->Bit9[chip->P9[0]])
+ outvol_0 = audv0;
+ else
+ outvol_0 = 0;
+ }
+ else if ( audc0 & 0x02 )
+ {
+ if (outvol_0 || audc0 & 0x01 )
+ outvol_0 = 0;
+ else
+ outvol_0 = audv0;
+ }
+ else
+ /* must be poly5 */
+ {
+ if (chip->Bit5[p5_0])
+ outvol_0 = audv0;
+ else
+ outvol_0 = 0;
+ }
+ }
+ else
+ /* poly4 is the only remaining option */
+ {
+ /* inc the poly4 counter */
+ chip->P4[0]++;
+ if (chip->P4[0] == POLY4_SIZE)
+ chip->P4[0] = 0;
+
+ if (chip->Bit4[chip->P4[0]])
+ outvol_0 = audv0;
+ else
+ outvol_0 = 0;
+ }
+ }
+ }
+
+
+ /* Process channel 1 */
+ if (div_n_cnt1 > 1)
+ {
+ div_n_cnt1--;
+ }
+ else if (div_n_cnt1 == 1)
+ {
+ int prev_bit5 = chip->Bit5[p5_1];
+
+ div_n_cnt1 = chip->Div_n_max[1];
+
+ /* the chip->P5 counter has multiple uses, so we inc it here */
+ p5_1++;
+ if (p5_1 == POLY5_SIZE)
+ p5_1 = 0;
+
+ /* check clock modifier for clock tick */
+ if ((audc1 & 0x02) == 0 ||
+ ((audc1 & 0x01) == 0 && Div31[p5_1]) ||
+ ((audc1 & 0x01) == 1 && chip->Bit5[p5_1]) ||
+ ((audc1 & 0x0f) == POLY5_DIV3 && chip->Bit5[p5_1] != prev_bit5))
+ {
+ if (audc1 & 0x04) /* pure modified clock selected */
+ {
+ if ((audc1 & 0x0f) == POLY5_DIV3) /* POLY5 -> DIV3 mode */
+ {
+ if ( chip->Bit5[p5_1] != prev_bit5 )
+ {
+ chip->Div_3_cnt[1]--;
+ if ( ! chip->Div_3_cnt[1] )
+ {
+ chip->Div_3_cnt[1] = 3;
+ if (outvol_1)
+ outvol_1 = 0;
+ else
+ outvol_1 = audv1;
+ }
+ }
+ }
+ else if (outvol_1) /* if the output was set */
+ outvol_1 = 0; /* turn it off */
+ else
+ outvol_1 = audv1; /* else turn it on */
+ }
+ else if (audc1 & 0x08) /* check for p5/p9 */
+ {
+ if (audc1 == POLY9) /* check for poly9 */
+ {
+ /* inc the poly9 counter */
+ chip->P9[1]++;
+ if (chip->P9[1] == POLY9_SIZE)
+ chip->P9[1] = 0;
+
+ if (chip->Bit9[chip->P9[1]])
+ outvol_1 = audv1;
+ else
+ outvol_1 = 0;
+ }
+ else if ( audc1 & 0x02 )
+ {
+ if (outvol_1 || audc1 & 0x01 )
+ outvol_1 = 0;
+ else
+ outvol_1 = audv1;
+ }
+ else
+ /* must be poly5 */
+ {
+ if (chip->Bit5[p5_1])
+ outvol_1 = audv1;
+ else
+ outvol_1 = 0;
+ }
+ }
+ else
+ /* poly4 is the only remaining option */
+ {
+ /* inc the poly4 counter */
+ chip->P4[1]++;
+ if (chip->P4[1] == POLY4_SIZE)
+ chip->P4[1] = 0;
+
+ if (chip->Bit4[chip->P4[1]])
+ outvol_1 = audv1;
+ else
+ outvol_1 = 0;
+ }
+ }
+ }
+
+ if (!chip->oversampling)
+ {
+ /* decrement the sample counter - value is 256 since the lower
+ * byte contains the fractional part */
+ chip->Samp_n_cnt -= 256;
+
+ /* if the count down has reached zero */
+ if (chip->Samp_n_cnt < 256)
+ {
+ /* adjust the sample counter */
+ chip->Samp_n_cnt += chip->Samp_n_max;
+
+ /* calculate the latest output value and place in buffer */
+ *buffer++ = outvol_0 + outvol_1;
+
+ /* and indicate one less byte to process */
+ length--;
+ }
+ }
+ else
+ {
+ do
+ {
+ /* decrement the sample counter - value is 256 since the lower
+ * byte contains the fractional part */
+ chip->Samp_n_cnt -= 256;
+ /* calculate the latest output value and place in buffer */
+ *buffer++ = outvol_0 + outvol_1;
+ length--;
+ }
+ while ((chip->Samp_n_cnt >= 256) && (length > 0));
+
+ /* adjust the sample counter if necessary */
+ if (chip->Samp_n_cnt < 256)
+ chip->Samp_n_cnt += chip->Samp_n_max;
+ }
+ }
+
+ /* save for next round */
+ chip->P5[0] = p5_0;
+ chip->P5[1] = p5_1;
+ chip->Outvol[0] = outvol_0;
+ chip->Outvol[1] = outvol_1;
+ chip->Div_n_cnt[0] = div_n_cnt0;
+ chip->Div_n_cnt[1] = div_n_cnt1;
+
+}
+
+static void poly_init(UINT8 *poly, int size, int f0, int f1)
+{
+ int mask = (1 << size) - 1;
+ int i, x = mask;
+
+ for (i = 0; i < mask; i++)
+ {
+ int bit0 = ( ( size - f0 ) ? ( x >> ( size - f0 ) ) : x ) & 0x01;
+ int bit1 = ( ( size - f1 ) ? ( x >> ( size - f1 ) ) : x ) & 0x01;
+ poly[i] = x & 1;
+ /* calculate next bit */
+ x = ( x >> 1 ) | ( ( bit0 ^ bit1 ) << ( size - 1) );
+ }
+}
+
+/*****************************************************************************/
+/* Module: tia_sh_start() */
+/* Purpose: to handle the power-up initialization functions */
+/* these functions should only be executed on a cold-restart */
+/* */
+/* Author: Ron Fries */
+/* Date: September 10, 1996 */
+/* */
+/* Inputs: sound_config *msound */
+/* is a pointer to the struct TIAInterface parameters */
+/* */
+/* Outputs: returns zero on success */
+/* */
+/*****************************************************************************/
+
+void *tia_sound_init(int clock, int sample_rate, int gain)
+{
+ struct tia *chip;
+ int chan;
+
+ chip = malloc(sizeof(*chip));
+ if (!chip)
+ return NULL;
+ memset(chip, 0, sizeof(*chip));
+
+ /* set the gain factor (normally use TIA_DEFAULT_GAIN) */
+ chip->tia_gain = gain;
+
+ /* fill the polynomials */
+ poly_init(chip->Bit4, 4, 4, 3);
+ poly_init(chip->Bit5, 5, 5, 3);
+ poly_init(chip->Bit9, 9, 9, 5);
+
+ /* calculate the sample 'divide by N' value based on the playback freq. */
+ chip->Samp_n_max = ((UINT16)(UINT32)clock << 8) / sample_rate;
+ chip->Samp_n_cnt = chip->Samp_n_max; /* initialize all bits of the sample counter */
+
+ if (chip->Samp_n_max < 256) /* we need to use oversampling for sample_rate > clock_rate */
+ {
+ chip->Samp_n_max = ((UINT16)(UINT32)sample_rate << 8) / clock;
+ chip->Samp_n_cnt = chip->Samp_n_max;
+ chip->oversampling = 1;
+ }
+
+ /* initialize the local globals */
+ for (chan = CHAN1; chan <= CHAN2; chan++)
+ {
+ chip->Outvol[chan] = 0;
+ chip->Div_n_cnt[chan] = 0;
+ chip->Div_n_max[chan] = 0;
+ chip->Div_3_cnt[chan] = 3;
+ chip->AUDC[chan] = 0;
+ chip->AUDF[chan] = 0;
+ chip->AUDV[chan] = 0;
+ chip->P4[chan] = 0;
+ chip->P5[chan] = 0;
+ chip->P9[chan] = 0;
+ }
+
+ return chip;
+}
+
+
+void tia_sound_free(void *chip)
+{
+ free(chip);
+}
diff --git a/src/emu/sound/tiasound.h b/src/emu/sound/tiasound.h
new file mode 100644
index 00000000000..d53e2dfa543
--- /dev/null
+++ b/src/emu/sound/tiasound.h
@@ -0,0 +1,44 @@
+/*****************************************************************************/
+/* */
+/* Module: TIA Chip Sound Simulator Includes, V1.1 */
+/* Purpose: Define global function prototypes and structures for the TIA */
+/* Chip Sound Simulator. */
+/* Author: Ron Fries */
+/* */
+/* Revision History: */
+/* 10-Sep-96 - V1.0 - Initial Release */
+/* 14-Jan-97 - V1.1 - Added compiler directives to facilitate compilation */
+/* on a C++ compiler. */
+/* */
+/*****************************************************************************/
+/* */
+/* License Information and Copyright Notice */
+/* ======================================== */
+/* */
+/* TiaSound is Copyright(c) 1997 by Ron Fries */
+/* */
+/* This library is free software; you can redistribute it and/or modify it */
+/* under the terms of version 2 of the GNU Library General Public License */
+/* as published by the Free Software Foundation. */
+/* */
+/* This library is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library */
+/* General Public License for more details. */
+/* To obtain a copy of the GNU Library General Public License, write to the */
+/* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* */
+/* Any permitted reproduction of these routines, in whole or in part, must */
+/* bear this legend. */
+/* */
+/*****************************************************************************/
+#ifndef TIASOUND_H
+#define TIASOUND_H
+
+void *tia_sound_init(int clock, int sample_rate, int gain);
+void tia_sound_free(void *chip);
+void tia_process (void *chip, stream_sample_t *buffer, int length);
+void tia_write(void *chip, offs_t offset, UINT8 data);
+
+#endif /* TIASOUND_H */
+
diff --git a/src/emu/sound/tms3615.c b/src/emu/sound/tms3615.c
new file mode 100644
index 00000000000..46225348ccd
--- /dev/null
+++ b/src/emu/sound/tms3615.c
@@ -0,0 +1,125 @@
+#include "sndintrf.h"
+#include "streams.h"
+#include "tms3615.h"
+
+#define VMIN 0x0000
+#define VMAX 0x7fff
+
+#define TONES 13
+
+static int divisor[TONES] = { 478, 451, 426, 402, 379, 358, 338, 319, 301, 284, 268, 253, 239 };
+
+struct TMS3615 {
+ sound_stream *channel; /* returned by stream_create() */
+ int samplerate; /* output sample rate */
+ int basefreq; /* chip's base frequency */
+ int counter8[TONES]; /* tone frequency counter for 8' */
+ int counter16[TONES]; /* tone frequency counter for 16'*/
+ int output8; /* output signal bits for 8' */
+ int output16; /* output signal bits for 16' */
+ int enable; /* mask which tones to play */
+};
+
+static void tms3615_sound_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct TMS3615 *tms = param;
+ int samplerate = tms->samplerate;
+ stream_sample_t *buffer8 = _buffer[TMS3615_FOOTAGE_8];
+ stream_sample_t *buffer16 = _buffer[TMS3615_FOOTAGE_16];
+
+ while( length-- > 0 )
+ {
+ int sum8 = 0, sum16 = 0, tone = 0;
+
+ for (tone = 0; tone < TONES; tone++)
+ {
+ // 8'
+
+ tms->counter8[tone] -= (tms->basefreq / divisor[tone]);
+
+ while( tms->counter8[tone] <= 0 )
+ {
+ tms->counter8[tone] += samplerate;
+ tms->output8 ^= 1 << tone;
+ }
+
+ if (tms->output8 & tms->enable & (1 << tone))
+ {
+ sum8 += VMAX;
+ }
+
+ // 16'
+
+ tms->counter16[tone] -= (tms->basefreq / divisor[tone] / 2);
+
+ while( tms->counter16[tone] <= 0 )
+ {
+ tms->counter16[tone] += samplerate;
+ tms->output16 ^= 1 << tone;
+ }
+
+ if (tms->output16 & tms->enable & (1 << tone))
+ {
+ sum16 += VMAX;
+ }
+ }
+
+ *buffer8++ = sum8 / TONES;
+ *buffer16++ = sum16 / TONES;
+ }
+
+ tms->enable = 0;
+}
+
+void tms3615_enable_w(int chip, int enable)
+{
+ struct TMS3615 *tms = sndti_token(SOUND_TMS3615, chip);
+ tms->enable = enable;
+}
+
+static void *tms3615_start(int sndindex, int clock, const void *config)
+{
+ struct TMS3615 *tms;
+
+ tms = auto_malloc(sizeof(*tms));
+ memset(tms, 0, sizeof(*tms));
+
+ tms->channel = stream_create(0, 2, clock/8, tms, tms3615_sound_update);
+ tms->samplerate = clock/8;
+ tms->basefreq = clock;
+
+ return tms;
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void tms3615_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+void tms3615_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = tms3615_set_info; break;
+ case SNDINFO_PTR_START: info->start = tms3615_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "TMS3615"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "TI PSG"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2006, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/tms3615.h b/src/emu/sound/tms3615.h
new file mode 100644
index 00000000000..49062f1997c
--- /dev/null
+++ b/src/emu/sound/tms3615.h
@@ -0,0 +1,9 @@
+#ifndef TMS3615_SOUND_H
+#define TMS3615_SOUND_H
+
+extern void tms3615_enable_w(int chip, int enable);
+
+#define TMS3615_FOOTAGE_8 0
+#define TMS3615_FOOTAGE_16 1
+
+#endif
diff --git a/src/emu/sound/tms36xx.c b/src/emu/sound/tms36xx.c
new file mode 100644
index 00000000000..bd0d1d68bf6
--- /dev/null
+++ b/src/emu/sound/tms36xx.c
@@ -0,0 +1,565 @@
+#include "sndintrf.h"
+#include "streams.h"
+#include "tms36xx.h"
+
+#define VERBOSE 1
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+#define VMIN 0x0000
+#define VMAX 0x7fff
+
+/* the frequencies are later adjusted by "* clock / FSCALE" */
+#define FSCALE 1024
+
+struct TMS36XX {
+ char *subtype; /* subtype name MM6221AA, TMS3615 or TMS3617 */
+ sound_stream * channel; /* returned by stream_create() */
+
+ int samplerate; /* output sample rate */
+
+ int basefreq; /* chip's base frequency */
+ int octave; /* octave select of the TMS3615 */
+
+ int speed; /* speed of the tune */
+ int tune_counter; /* tune counter */
+ int note_counter; /* note counter */
+
+ int voices; /* active voices */
+ int shift; /* shift toggles between 0 and 6 to allow decaying voices */
+ int vol[12]; /* (decaying) volume of harmonics notes */
+ int vol_counter[12];/* volume adjustment counter */
+ int decay[12]; /* volume adjustment rate - dervied from decay */
+
+ int counter[12]; /* tone frequency counter */
+ int frequency[12]; /* tone frequency */
+ int output; /* output signal bits */
+ int enable; /* mask which harmoics */
+
+ int tune_num; /* tune currently playing */
+ int tune_ofs; /* note currently playing */
+ int tune_max; /* end of tune */
+
+ const struct TMS36XXinterface *intf;
+};
+
+#define C(n) (int)((FSCALE<<(n-1))*1.18921) /* 2^(3/12) */
+#define Cx(n) (int)((FSCALE<<(n-1))*1.25992) /* 2^(4/12) */
+#define D(n) (int)((FSCALE<<(n-1))*1.33484) /* 2^(5/12) */
+#define Dx(n) (int)((FSCALE<<(n-1))*1.41421) /* 2^(6/12) */
+#define E(n) (int)((FSCALE<<(n-1))*1.49831) /* 2^(7/12) */
+#define F(n) (int)((FSCALE<<(n-1))*1.58740) /* 2^(8/12) */
+#define Fx(n) (int)((FSCALE<<(n-1))*1.68179) /* 2^(9/12) */
+#define G(n) (int)((FSCALE<<(n-1))*1.78180) /* 2^(10/12) */
+#define Gx(n) (int)((FSCALE<<(n-1))*1.88775) /* 2^(11/12) */
+#define A(n) (int)((FSCALE<<n)) /* A */
+#define Ax(n) (int)((FSCALE<<n)*1.05946) /* 2^(1/12) */
+#define B(n) (int)((FSCALE<<n)*1.12246) /* 2^(2/12) */
+
+/*
+ * Alarm sound?
+ * It is unknown what this sound is like. Until somebody manages
+ * trigger sound #1 of the Phoenix PCB sound chip I put just something
+ * 'alarming' in here.
+ */
+static const int tune1[96*6] = {
+ C(3), 0, 0, C(2), 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, C(4), 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, C(2), 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, C(4), 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+ C(3), 0, 0, 0, 0, 0,
+ G(3), 0, 0, 0, 0, 0,
+};
+
+/*
+ * Fuer Elise, Beethoven
+ * (Excuse my non-existent musical skill, Mr. B ;-)
+ */
+static const int tune2[96*6] = {
+ D(3), D(4), D(5), 0, 0, 0,
+ Cx(3), Cx(4), Cx(5), 0, 0, 0,
+ D(3), D(4), D(5), 0, 0, 0,
+ Cx(3), Cx(4), Cx(5), 0, 0, 0,
+ D(3), D(4), D(5), 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ C(3), C(4), C(5), 0, 0, 0,
+ Ax(2), Ax(3), Ax(4), 0, 0, 0,
+ G(2), G(3), G(4), 0, 0, 0,
+ D(1), D(2), D(3), 0, 0, 0,
+ G(1), G(2), G(3), 0, 0, 0,
+ Ax(1), Ax(2), Ax(3), 0, 0, 0,
+
+ D(2), D(3), D(4), 0, 0, 0,
+ G(2), G(3), G(4), 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ D(1), D(2), D(3), 0, 0, 0,
+ A(1), A(2), A(3), 0, 0, 0,
+ D(2), D(3), D(4), 0, 0, 0,
+ Fx(2), Fx(3), Fx(4), 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ Ax(2), Ax(3), Ax(4), 0, 0, 0,
+ D(1), D(2), D(3), 0, 0, 0,
+ G(1), G(2), G(3), 0, 0, 0,
+ Ax(1), Ax(2), Ax(3), 0, 0, 0,
+
+ D(3), D(4), D(5), 0, 0, 0,
+ Cx(3), Cx(4), Cx(5), 0, 0, 0,
+ D(3), D(4), D(5), 0, 0, 0,
+ Cx(3), Cx(4), Cx(5), 0, 0, 0,
+ D(3), D(4), D(5), 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ C(3), C(4), C(5), 0, 0, 0,
+ Ax(2), Ax(3), Ax(4), 0, 0, 0,
+ G(2), G(3), G(4), 0, 0, 0,
+ D(1), D(2), D(3), 0, 0, 0,
+ G(1), G(2), G(3), 0, 0, 0,
+ Ax(1), Ax(2), Ax(3), 0, 0, 0,
+
+ D(2), D(3), D(4), 0, 0, 0,
+ G(2), G(3), G(4), 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ D(1), D(2), D(3), 0, 0, 0,
+ A(1), A(2), A(3), 0, 0, 0,
+ D(2), D(3), D(4), 0, 0, 0,
+ Ax(2), Ax(3), Ax(4), 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ 0, 0, 0, G(2), G(3), G(4),
+ D(1), D(2), D(3), 0, 0, 0,
+ G(1), G(2), G(3), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * The theme from Phoenix, a sad little tune.
+ * Gerald Coy:
+ * The starting song from Phoenix is coming from a old french movie and
+ * it's called : "Jeux interdits" which means "unallowed games" ;-)
+ * Mirko Buffoni:
+ * It's called "Sogni proibiti" in italian, by Anonymous.
+ * Magic*:
+ * This song is a classical piece called "ESTUDIO" from M.A.Robira.
+ */
+static const int tune3[96*6] = {
+ A(2), A(3), A(4), D(1), D(2), D(3),
+ 0, 0, 0, 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ A(2), A(3), A(4), A(1), A(2), A(3),
+ 0, 0, 0, 0, 0, 0,
+ G(2), G(3), G(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ F(2), F(3), F(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ F(2), F(3), F(4), F(1), F(2), F(3),
+ 0, 0, 0, 0, 0, 0,
+ E(2), E(3), E(4), F(1), F(2), F(3),
+ 0, 0, 0, 0, 0, 0,
+ D(2), D(3), D(4), F(1), F(2), F(3),
+ 0, 0, 0, 0, 0, 0,
+
+ D(2), D(3), D(4), A(1), A(2), A(3),
+ 0, 0, 0, 0, 0, 0,
+ F(2), F(3), F(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ D(3), D(4), D(5), D(1), D(2), D(3),
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, D(1), D(2), D(3),
+ 0, 0, 0, F(1), F(2), F(3),
+ 0, 0, 0, A(1), A(2), A(3),
+ 0, 0, 0, D(2), D(2), D(2),
+
+ D(3), D(4), D(5), D(1), D(2), D(3),
+ 0, 0, 0, 0, 0, 0,
+ C(3), C(4), C(5), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ Ax(2), Ax(3), Ax(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ Ax(2), Ax(3), Ax(4), Ax(1), Ax(2), Ax(3),
+ 0, 0, 0, 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ G(2), G(3), G(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ G(2), G(3), G(4), G(1), G(2), G(3),
+ 0, 0, 0, 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ Ax(2), Ax(3), Ax(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ A(2), A(3), A(4), A(1), A(2), A(3),
+ 0, 0, 0, 0, 0, 0,
+ Ax(2), Ax(3), Ax(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ Cx(3), Cx(4), Cx(5), A(1), A(2), A(3),
+ 0, 0, 0, 0, 0, 0,
+ Ax(2), Ax(3), Ax(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ A(2), A(3), A(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ A(2), A(3), A(4), F(1), F(2), F(3),
+ 0, 0, 0, 0, 0, 0,
+ G(2), G(3), G(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ F(2), F(3), F(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ F(2), F(3), F(4), D(1), D(2), D(3),
+ 0, 0, 0, 0, 0, 0,
+ E(2), E(3), E(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ D(2), D(3), D(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ E(2), E(3), E(4), E(1), E(2), E(3),
+ 0, 0, 0, 0, 0, 0,
+ E(2), E(3), E(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ E(2), E(3), E(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ E(2), E(3), E(4), Ax(1), Ax(2), Ax(3),
+ 0, 0, 0, 0, 0, 0,
+ F(2), F(3), F(4), 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ E(2), E(3), E(4), F(1), F(2), F(3),
+ 0, 0, 0, 0, 0, 0,
+
+ D(2), D(3), D(4), D(1), D(2), D(3),
+ 0, 0, 0, 0, 0, 0,
+ F(2), F(3), F(4), A(1), A(2), A(3),
+ 0, 0, 0, 0, 0, 0,
+ A(2), A(3), A(4), F(1), F(2), F(3),
+ 0, 0, 0, 0, 0, 0,
+
+ D(3), D(4), D(5), D(1), D(2), D(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
+};
+
+/* This is used to play single notes for the TMS3615/TMS3617 */
+static const int tune4[13*6] = {
+/* 16' 8' 5 1/3' 4' 2 2/3' 2' */
+ B(0), B(1), Dx(2), B(2), Dx(3), B(3),
+ C(1), C(2), E(2), C(3), E(3), C(4),
+ Cx(1), Cx(2), F(2), Cx(3), F(3), Cx(4),
+ D(1), D(2), Fx(2), D(3), Fx(3), D(4),
+ Dx(1), Dx(2), G(2), Dx(3), G(3), Dx(4),
+ E(1), E(2), Gx(2), E(3), Gx(3), E(4),
+ F(1), F(2), A(2), F(3), A(3), F(4),
+ Fx(1), Fx(2), Ax(2), Fx(3), Ax(3), Fx(4),
+ G(1), G(2), B(2), G(3), B(3), G(4),
+ Gx(1), Gx(2), C(3), Gx(3), C(4), Gx(4),
+ A(1), A(2), Cx(3), A(3), Cx(4), A(4),
+ Ax(1), Ax(2), D(3), Ax(3), D(4), Ax(4),
+ B(1), B(2), Dx(3), B(3), Dx(4), B(4)
+};
+
+static const int *tunes[] = {NULL,tune1,tune2,tune3,tune4};
+
+#define DECAY(voice) \
+ if( tms->vol[voice] > VMIN ) \
+ { \
+ /* decay of first voice */ \
+ tms->vol_counter[voice] -= tms->decay[voice]; \
+ while( tms->vol_counter[voice] <= 0 ) \
+ { \
+ tms->vol_counter[voice] += samplerate; \
+ if( tms->vol[voice]-- <= VMIN ) \
+ { \
+ tms->frequency[voice] = 0; \
+ tms->vol[voice] = VMIN; \
+ break; \
+ } \
+ } \
+ }
+
+#define RESTART(voice) \
+ if( tunes[tms->tune_num][tms->tune_ofs*6+voice] ) \
+ { \
+ tms->frequency[tms->shift+voice] = \
+ tunes[tms->tune_num][tms->tune_ofs*6+voice] * \
+ (tms->basefreq << tms->octave) / FSCALE; \
+ tms->vol[tms->shift+voice] = VMAX; \
+ }
+
+#define TONE(voice) \
+ if( (tms->enable & (1<<voice)) && tms->frequency[voice] ) \
+ { \
+ /* first note */ \
+ tms->counter[voice] -= tms->frequency[voice]; \
+ while( tms->counter[voice] <= 0 ) \
+ { \
+ tms->counter[voice] += samplerate; \
+ tms->output ^= 1 << voice; \
+ } \
+ if (tms->output & tms->enable & (1 << voice)) \
+ sum += tms->vol[voice]; \
+ }
+
+
+
+static void tms36xx_sound_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct TMS36XX *tms = param;
+ int samplerate = tms->samplerate;
+ stream_sample_t *buffer = _buffer[0];
+
+ /* no tune played? */
+ if( !tunes[tms->tune_num] || tms->voices == 0 )
+ {
+ while (--length >= 0)
+ buffer[length] = 0;
+ return;
+ }
+
+ while( length-- > 0 )
+ {
+ int sum = 0;
+
+ /* decay the twelve voices */
+ DECAY( 0) DECAY( 1) DECAY( 2) DECAY( 3) DECAY( 4) DECAY( 5)
+ DECAY( 6) DECAY( 7) DECAY( 8) DECAY( 9) DECAY(10) DECAY(11)
+
+ /* musical note timing */
+ tms->tune_counter -= tms->speed;
+ if( tms->tune_counter <= 0 )
+ {
+ int n = (-tms->tune_counter / samplerate) + 1;
+ tms->tune_counter += n * samplerate;
+
+ if( (tms->note_counter -= n) <= 0 )
+ {
+ tms->note_counter += VMAX;
+ if (tms->tune_ofs < tms->tune_max)
+ {
+ /* shift to the other 'bank' of voices */
+ tms->shift ^= 6;
+ /* restart one 'bank' of voices */
+ RESTART(0) RESTART(1) RESTART(2)
+ RESTART(3) RESTART(4) RESTART(5)
+ tms->tune_ofs++;
+ }
+ }
+ }
+
+ /* update the twelve voices */
+ TONE( 0) TONE( 1) TONE( 2) TONE( 3) TONE( 4) TONE( 5)
+ TONE( 6) TONE( 7) TONE( 8) TONE( 9) TONE(10) TONE(11)
+
+ *buffer++ = sum / tms->voices;
+ }
+}
+
+static void tms36xx_reset_counters(struct TMS36XX *tms)
+{
+ tms->tune_counter = 0;
+ tms->note_counter = 0;
+ memset(tms->vol_counter, 0, sizeof(tms->vol_counter));
+ memset(tms->counter, 0, sizeof(tms->counter));
+}
+
+void mm6221aa_tune_w(int chip, int tune)
+{
+ struct TMS36XX *tms = sndti_token(SOUND_TMS36XX, chip);
+
+ /* which tune? */
+ tune &= 3;
+ if( tune == tms->tune_num )
+ return;
+
+ LOG(("%s tune:%X\n", tms->subtype, tune));
+
+ /* update the stream before changing the tune */
+ stream_update(tms->channel);
+
+ tms->tune_num = tune;
+ tms->tune_ofs = 0;
+ tms->tune_max = 96; /* fixed for now */
+}
+
+void tms36xx_note_w(int chip, int octave, int note)
+{
+ struct TMS36XX *tms = sndti_token(SOUND_TMS36XX, chip);
+
+ octave &= 3;
+ note &= 15;
+
+ if (note > 12)
+ return;
+
+ LOG(("%s octave:%X note:%X\n", tms->subtype, octave, note));
+
+ /* update the stream before changing the tune */
+ stream_update(tms->channel);
+
+ /* play a single note from 'tune 4', a list of the 13 tones */
+ tms36xx_reset_counters(tms);
+ tms->octave = octave;
+ tms->tune_num = 4;
+ tms->tune_ofs = note;
+ tms->tune_max = note + 1;
+}
+
+void tms3617_enable(struct TMS36XX *tms, int enable)
+{
+ int i, bits = 0;
+
+ /* duplicate the 6 voice enable bits */
+ enable = (enable & 0x3f) | ((enable & 0x3f) << 6);
+ if (enable == tms->enable)
+ return;
+
+ /* update the stream before changing the tune */
+ stream_update(tms->channel);
+
+ LOG(("%s enable voices", tms->subtype));
+ for (i = 0; i < 6; i++)
+ {
+ if (enable & (1 << i))
+ {
+ bits += 2; /* each voice has two instances */
+#if VERBOSE
+ switch (i)
+ {
+ case 0: LOG((" 16'")); break;
+ case 1: LOG((" 8'")); break;
+ case 2: LOG((" 5 1/3'")); break;
+ case 3: LOG((" 4'")); break;
+ case 4: LOG((" 2 2/3'")); break;
+ case 5: LOG((" 2'")); break;
+ }
+#endif
+ }
+ }
+ /* set the enable mask and number of active voices */
+ tms->enable = enable;
+ tms->voices = bits;
+ LOG(("%s\n", bits ? "" : " none"));
+}
+
+void tms3617_enable_w(int chip, int enable)
+{
+ struct TMS36XX *tms = sndti_token(SOUND_TMS36XX, chip);
+ tms3617_enable(tms, enable);
+}
+
+static void *tms36xx_start(int sndindex, int clock, const void *config)
+{
+ int j;
+ struct TMS36XX *tms;
+ int enable;
+
+ tms = auto_malloc(sizeof(*tms));
+ memset(tms, 0, sizeof(*tms));
+
+ tms->intf = config;
+
+ tms->channel = stream_create(0, 1, clock * 64, tms, tms36xx_sound_update);
+ tms->samplerate = clock * 64;
+ tms->basefreq = clock;
+ enable = 0;
+ for (j = 0; j < 6; j++)
+ {
+ if( tms->intf->decay[j] > 0 )
+ {
+ tms->decay[j+0] = tms->decay[j+6] = VMAX / tms->intf->decay[j];
+ enable |= 0x41 << j;
+ }
+ }
+ tms->speed = (tms->intf->speed > 0) ? VMAX / tms->intf->speed : VMAX;
+ tms3617_enable(tms,enable);
+
+ LOG(("TMS36xx samplerate %d\n", tms->samplerate));
+ LOG(("TMS36xx basefreq %d\n", tms->basefreq));
+ LOG(("TMS36xx decay %d,%d,%d,%d,%d,%d\n",
+ tms->decay[0], tms->decay[1], tms->decay[2],
+ tms->decay[3], tms->decay[4], tms->decay[5]));
+ LOG(("TMS36xx speed %d\n", tms->speed));
+
+ return tms;
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void tms36xx_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void tms36xx_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = tms36xx_set_info; break;
+ case SNDINFO_PTR_START: info->start = tms36xx_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "TMS36XX"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "TI PSG"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/tms36xx.h b/src/emu/sound/tms36xx.h
new file mode 100644
index 00000000000..45a4fa887d9
--- /dev/null
+++ b/src/emu/sound/tms36xx.h
@@ -0,0 +1,25 @@
+#ifndef TMS36XX_SOUND_H
+#define TMS36XX_SOUND_H
+
+/* subtypes */
+#define MM6221AA 21 /* Phoenix (fixed melodies) */
+#define TMS3615 15 /* Naughty Boy, Pleiads (13 notes, one output) */
+#define TMS3617 17 /* Monster Bash (13 notes, six outputs) */
+
+/* The interface structure */
+struct TMS36XXinterface {
+ int subtype;
+ double decay[6]; /* decay times for the six harmonic notes */
+ double speed; /* tune speed (meaningful for the TMS3615 only) */
+};
+
+/* MM6221AA interface functions */
+extern void mm6221aa_tune_w(int chip, int tune);
+
+/* TMS3615/17 interface functions */
+extern void tms36xx_note_w(int chip, int octave, int note);
+
+/* TMS3617 interface functions */
+extern void tms3617_enable_w(int chip, int enable);
+
+#endif
diff --git a/src/emu/sound/tms5110.c b/src/emu/sound/tms5110.c
new file mode 100644
index 00000000000..a1e3ee5131c
--- /dev/null
+++ b/src/emu/sound/tms5110.c
@@ -0,0 +1,731 @@
+/**********************************************************************************************
+
+ TMS5110 simulator (modified from TMS5220 by Jarek Burczynski)
+
+ Written for MAME by Frank Palazzolo
+ With help from Neill Corlett
+ Additional tweaking by Aaron Giles
+ Various fixes by Lord Nightmare
+
+***********************************************************************************************/
+
+#include "sndintrf.h"
+#include "tms5110.h"
+
+
+/* Pull in the ROM tables */
+#include "tms5110r.c"
+
+
+struct tms5110
+{
+ /* these contain data that describes the 64 bits FIFO */
+ #define FIFO_SIZE 64
+ UINT8 fifo[FIFO_SIZE];
+ UINT8 fifo_head;
+ UINT8 fifo_tail;
+ UINT8 fifo_count;
+
+ /* these contain global status bits */
+ UINT8 PDC;
+ UINT8 CTL_pins;
+ UINT8 speaking_now;
+ UINT8 speak_delay_frames;
+ UINT8 talk_status;
+
+
+ int (*M0_callback)(void);
+
+ /* these contain data describing the current and previous voice frames */
+ UINT16 old_energy;
+ UINT16 old_pitch;
+ INT32 old_k[10];
+
+ UINT16 new_energy;
+ UINT16 new_pitch;
+ INT32 new_k[10];
+
+
+ /* these are all used to contain the current state of the sound generation */
+ UINT16 current_energy;
+ UINT16 current_pitch;
+ INT32 current_k[10];
+
+ UINT16 target_energy;
+ UINT16 target_pitch;
+ INT32 target_k[10];
+
+ UINT8 interp_count; /* number of interp periods (0-7) */
+ UINT8 sample_count; /* sample number within interp (0-24) */
+ INT32 pitch_count;
+
+ INT32 u[11];
+ INT32 x[10];
+
+ INT32 RNG; /* the random noise generator configuration is: 1 + x + x^3 + x^4 + x^13 */
+};
+
+
+/* Static function prototypes */
+static void parse_frame(struct tms5110 *tms);
+
+
+#define DEBUG_5110 0
+
+
+void *tms5110_create(int index)
+{
+ struct tms5110 *tms;
+
+ tms = malloc_or_die(sizeof(*tms));
+ memset(tms, 0, sizeof(*tms));
+
+ state_save_register_item_array("tms5110", index, tms->fifo);
+ state_save_register_item("tms5110", index, tms->fifo_head);
+ state_save_register_item("tms5110", index, tms->fifo_tail);
+ state_save_register_item("tms5110", index, tms->fifo_count);
+
+ state_save_register_item("tms5110", index, tms->PDC);
+ state_save_register_item("tms5110", index, tms->CTL_pins);
+ state_save_register_item("tms5110", index, tms->speaking_now);
+ state_save_register_item("tms5110", index, tms->speak_delay_frames);
+ state_save_register_item("tms5110", index, tms->talk_status);
+
+ state_save_register_item("tms5110", index, tms->old_energy);
+ state_save_register_item("tms5110", index, tms->old_pitch);
+ state_save_register_item_array("tms5110", index, tms->old_k);
+
+ state_save_register_item("tms5110", index, tms->new_energy);
+ state_save_register_item("tms5110", index, tms->new_pitch);
+ state_save_register_item_array("tms5110", index, tms->new_k);
+
+ state_save_register_item("tms5110", index, tms->current_energy);
+ state_save_register_item("tms5110", index, tms->current_pitch);
+ state_save_register_item_array("tms5110", index, tms->current_k);
+
+ state_save_register_item("tms5110", index, tms->target_energy);
+ state_save_register_item("tms5110", index, tms->target_pitch);
+ state_save_register_item_array("tms5110", index, tms->target_k);
+
+ state_save_register_item("tms5110", index, tms->interp_count);
+ state_save_register_item("tms5110", index, tms->sample_count);
+ state_save_register_item("tms5110", index, tms->pitch_count);
+
+ state_save_register_item_array("tms5110", index, tms->u);
+ state_save_register_item_array("tms5110", index, tms->x);
+
+ state_save_register_item("tms5110", index, tms->RNG);
+
+ return tms;
+}
+
+
+void tms5110_destroy(void *chip)
+{
+ free(chip);
+}
+
+
+
+
+/**********************************************************************************************
+
+ tms5110_reset -- resets the TMS5110
+
+***********************************************************************************************/
+
+void tms5110_reset_chip(void *chip)
+{
+ struct tms5110 *tms = chip;
+
+ /* initialize the FIFO */
+ memset(tms->fifo, 0, sizeof(tms->fifo));
+ tms->fifo_head = tms->fifo_tail = tms->fifo_count = 0;
+
+ /* initialize the chip state */
+ tms->speaking_now = tms->speak_delay_frames = tms->talk_status = 0;
+ tms->CTL_pins = 0;
+ tms->RNG = 0x1fff;
+
+ /* initialize the energy/pitch/k states */
+ tms->old_energy = tms->new_energy = tms->current_energy = tms->target_energy = 0;
+ tms->old_pitch = tms->new_pitch = tms->current_pitch = tms->target_pitch = 0;
+ memset(tms->old_k, 0, sizeof(tms->old_k));
+ memset(tms->new_k, 0, sizeof(tms->new_k));
+ memset(tms->current_k, 0, sizeof(tms->current_k));
+ memset(tms->target_k, 0, sizeof(tms->target_k));
+
+ /* initialize the sample generators */
+ tms->interp_count = tms->sample_count = tms->pitch_count = 0;
+ memset(tms->u, 0, sizeof(tms->u));
+ memset(tms->x, 0, sizeof(tms->x));
+}
+
+
+
+/******************************************************************************************
+
+ tms5110_set_M0_callback -- set M0 callback for the TMS5110
+
+******************************************************************************************/
+
+void tms5110_set_M0_callback(void *chip, int (*func)(void))
+{
+ struct tms5110 *tms = chip;
+ tms->M0_callback = func;
+}
+
+
+/******************************************************************************************
+
+ FIFO_data_write -- handle bit data write to the TMS5110 (as a result of toggling M0 pin)
+
+******************************************************************************************/
+static void FIFO_data_write(struct tms5110 *tms, int data)
+{
+ /* add this bit to the FIFO */
+ if (tms->fifo_count < FIFO_SIZE)
+ {
+ tms->fifo[tms->fifo_tail] = (data&1); /* set bit to 1 or 0 */
+
+ tms->fifo_tail = (tms->fifo_tail + 1) % FIFO_SIZE;
+ tms->fifo_count++;
+
+ if (DEBUG_5110) logerror("Added bit to FIFO (size=%2d)\n", tms->fifo_count);
+ }
+ else
+ {
+ if (DEBUG_5110) logerror("Ran out of room in the FIFO!\n");
+ }
+}
+
+/******************************************************************************************
+
+ extract_bits -- extract a specific number of bits from the FIFO
+
+******************************************************************************************/
+
+static int extract_bits(struct tms5110 *tms, int count)
+{
+ int val = 0;
+
+ while (count--)
+ {
+ val = (val << 1) | (tms->fifo[tms->fifo_head] & 1);
+ tms->fifo_count--;
+ tms->fifo_head = (tms->fifo_head + 1) % FIFO_SIZE;
+ }
+ return val;
+}
+
+static void request_bits(struct tms5110 *tms, int no)
+{
+int i;
+ for (i=0; i<no; i++)
+ {
+ if (tms->M0_callback)
+ {
+ int data = (*tms->M0_callback)();
+ FIFO_data_write(tms, data);
+ }
+ else
+ if (DEBUG_5110) logerror("-->ERROR: TMS5110 missing M0 callback function\n");
+ }
+}
+
+static void perform_dummy_read(struct tms5110 *tms)
+{
+ if (tms->M0_callback)
+ {
+ int data = (*tms->M0_callback)();
+ if (DEBUG_5110) logerror("TMS5110 performing dummy read; value read = %1i\n", data&1);
+ }
+ else
+ if (DEBUG_5110) logerror("-->ERROR: TMS5110 missing M0 callback function\n");
+}
+
+/**********************************************************************************************
+
+ tms5110_status_read -- read status from the TMS5110
+
+ bit 0 = TS - Talk Status is active (high) when the VSP is processing speech data.
+ Talk Status goes active at the initiation of a SPEAK command.
+ It goes inactive (low) when the stop code (Energy=1111) is processed, or
+ immediately(?????? not TMS5110) by a RESET command.
+ TMS5110 datasheets mention this is only available as a result of executing
+ TEST TALK command.
+
+
+***********************************************************************************************/
+
+int tms5110_status_read(void *chip)
+{
+ struct tms5110 *tms = chip;
+ if (DEBUG_5110) logerror("Status read: TS=%d\n", tms->talk_status);
+
+ return (tms->talk_status << 0); /*CTL1 = still talking ? */
+}
+
+
+
+/**********************************************************************************************
+
+ tms5110_ready_read -- returns the ready state of the TMS5110
+
+***********************************************************************************************/
+
+int tms5110_ready_read(void *chip)
+{
+ struct tms5110 *tms = chip;
+ return (tms->fifo_count < FIFO_SIZE-1);
+}
+
+
+
+/**********************************************************************************************
+
+ tms5110_process -- fill the buffer with a specific number of samples
+
+***********************************************************************************************/
+
+void tms5110_process(void *chip, INT16 *buffer, unsigned int size)
+{
+ struct tms5110 *tms = chip;
+ int buf_count=0;
+ int i, interp_period, cliptemp;
+
+ /* if we're not speaking, fill with nothingness */
+ if (!tms->speaking_now)
+ goto empty;
+
+ /* if we're to speak, but haven't started */
+ if (!tms->talk_status)
+ {
+
+ /* a "dummy read" is mentioned in the tms5200 datasheet */
+ /* The Bagman speech roms data are organized in such a way that
+ ** the bit at address 0 is NOT a speech data. The bit at address 1
+ ** is the speech data. It seems that the tms5110 performs a dummy read
+ ** just before it executes a SPEAK command.
+ */
+ perform_dummy_read(tms);
+
+ /* clear out the new frame parameters (it will become old frame just before the first call to parse_frame() ) */
+ tms->new_energy = 0;
+ tms->new_pitch = 0;
+ for (i = 0; i < 10; i++)
+ tms->new_k[i] = 0;
+
+ tms->talk_status = 1;
+ }
+
+
+ /* loop until the buffer is full or we've stopped speaking */
+ while ((size > 0) && tms->speaking_now)
+ {
+ int current_val;
+
+ /* if we're ready for a new frame */
+ if ((tms->interp_count == 0) && (tms->sample_count == 0))
+ {
+
+ /* remember previous frame */
+ tms->old_energy = tms->new_energy;
+ tms->old_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->old_k[i] = tms->new_k[i];
+
+
+ /* if the old frame was a stop frame, exit and do not process any more frames */
+ if (tms->old_energy == energytable[15])
+ {
+ /*if (DEBUG_5110) logerror("processing frame: stop frame\n");*/
+ tms->target_energy = tms->current_energy = 0;
+ tms->speaking_now = tms->talk_status = 0;
+ tms->interp_count = tms->sample_count = tms->pitch_count = 0;
+ goto empty;
+ }
+
+
+ /* Parse a new frame into the new_energy, new_pitch and new_k[] */
+ parse_frame(tms);
+
+
+ /* Set old target as new start of frame */
+ tms->current_energy = tms->old_energy;
+ tms->current_pitch = tms->old_pitch;
+ for (i = 0; i < 10; i++)
+ tms->current_k[i] = tms->old_k[i];
+
+
+ /* is this the stop (ramp down) frame? */
+ if (tms->new_energy == energytable[15])
+ {
+ /*logerror("processing frame: ramp down\n");*/
+ tms->target_energy = 0;
+ tms->target_pitch = tms->old_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->old_k[i];
+ }
+ else if ((tms->old_energy == 0) && (tms->new_energy != 0)) /* was the old frame a zero-energy frame? */
+ {
+ /* if so, and if the new frame is non-zero energy frame then the new parameters
+ should become our current and target parameters immediately,
+ i.e. we should NOT interpolate them slowly in.
+ */
+
+ /*logerror("processing non-zero energy frame after zero-energy frame\n");*/
+ tms->target_energy = tms->new_energy;
+ tms->target_pitch = tms->current_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->current_k[i] = tms->new_k[i];
+ }
+ else if ((tms->old_pitch == 0) && (tms->new_pitch != 0)) /* is this a change from unvoiced to voiced frame ? */
+ {
+ /* if so, then the new parameters should become our current and target parameters immediately,
+ i.e. we should NOT interpolate them slowly in.
+ */
+ /*if (DEBUG_5110) logerror("processing frame: UNVOICED->VOICED frame change\n");*/
+ tms->target_energy = tms->new_energy;
+ tms->target_pitch = tms->current_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->current_k[i] = tms->new_k[i];
+ }
+ else if ((tms->old_pitch != 0) && (tms->new_pitch == 0)) /* is this a change from voiced to unvoiced frame ? */
+ {
+ /* if so, then the new parameters should become our current and target parameters immediately,
+ i.e. we should NOT interpolate them slowly in.
+ */
+ /*if (DEBUG_5110) logerror("processing frame: VOICED->UNVOICED frame change\n");*/
+ tms->target_energy = tms->new_energy;
+ tms->target_pitch = tms->current_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->current_k[i] = tms->new_k[i];
+ }
+ else
+ {
+ /*logerror("processing frame: Normal\n");*/
+ /*logerror("*** Energy = %d\n",current_energy);*/
+ /*logerror("proc: %d %d\n",last_fbuf_head,fbuf_head);*/
+
+ tms->target_energy = tms->new_energy;
+ tms->target_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->new_k[i];
+ }
+ }
+ else if (tms->interp_count == 0)
+ {
+ /* interpolate (update) values based on step values */
+ /*logerror("\n");*/
+
+ interp_period = tms->sample_count / 25;
+ tms->current_energy += (tms->target_energy - tms->current_energy) / interp_coeff[interp_period];
+ tms->current_pitch += (tms->target_pitch - tms->current_pitch) / interp_coeff[interp_period];
+
+ /*logerror("*** Energy = %d\n",current_energy);*/
+
+ for (i = 0; i < 10; i++)
+ {
+ tms->current_k[i] += (tms->target_k[i] - tms->current_k[i]) / interp_coeff[interp_period];
+ }
+ }
+
+
+
+
+
+ /* calculate the output */
+
+ if (tms->current_energy == 0)
+ {
+ /* generate silent samples here */
+ current_val = 0x00;
+ }
+ else if (tms->old_pitch == 0)
+ {
+ int bitout, randbit;
+
+ /* generate unvoiced samples here */
+ if (tms->RNG&1)
+ randbit = -64; /* according to the patent it is (either + or -) half of the maximum value in the chirp table */
+ else
+ randbit = 64;
+
+ bitout = ((tms->RNG>>12)&1) ^
+ ((tms->RNG>>10)&1) ^
+ ((tms->RNG>> 9)&1) ^
+ ((tms->RNG>> 0)&1);
+ tms->RNG >>= 1;
+ tms->RNG |= (bitout<<12);
+
+ current_val = (randbit * tms->current_energy) / 256;
+ }
+ else
+ {
+ /* generate voiced samples here */
+ current_val = (chirptable[tms->pitch_count%sizeof(chirptable)] * tms->current_energy) / 256;
+ }
+
+
+ /* Lattice filter here */
+
+ tms->u[10] = current_val;
+
+ for (i = 9; i >= 0; i--)
+ {
+ tms->u[i] = tms->u[i+1] - ((tms->current_k[i] * tms->x[i]) / 32768);
+ }
+ for (i = 9; i >= 1; i--)
+ {
+ tms->x[i] = tms->x[i-1] + ((tms->current_k[i-1] * tms->u[i-1]) / 32768);
+ }
+
+ tms->x[0] = tms->u[0];
+
+
+ /* clipping & wrapping, just like the patent */
+
+ cliptemp = tms->u[0];
+ if (cliptemp > 2047) cliptemp = -2048 + (cliptemp-2047);
+ else if (cliptemp < -2048) cliptemp = 2047 - (cliptemp+2048);
+
+ if (cliptemp > 511)
+ buffer[buf_count] = 127<<8;
+ else if (cliptemp < -512)
+ buffer[buf_count] = -128<<8;
+ else
+ buffer[buf_count] = cliptemp << 6;
+
+ /* Update all counts */
+
+ tms->sample_count = (tms->sample_count + 1) % 200;
+
+ if (tms->current_pitch != 0)
+ tms->pitch_count = (tms->pitch_count + 1) % tms->current_pitch;
+ else
+ tms->pitch_count = 0;
+
+ tms->interp_count = (tms->interp_count + 1) % 25;
+
+ buf_count++;
+ size--;
+ }
+
+empty:
+
+ while (size > 0)
+ {
+ tms->sample_count = (tms->sample_count + 1) % 200;
+ tms->interp_count = (tms->interp_count + 1) % 25;
+
+ buffer[buf_count] = 0x00;
+ buf_count++;
+ size--;
+ }
+}
+
+
+
+
+/******************************************************************************************
+
+ CTL_set -- set CTL pins named CTL1, CTL2, CTL4 and CTL8
+
+******************************************************************************************/
+
+void tms5110_CTL_set(void *chip, int data)
+{
+ struct tms5110 *tms = chip;
+ tms->CTL_pins = data & 0xf;
+}
+
+
+/******************************************************************************************
+
+ PDC_set -- set Processor Data Clock. Execute CTL_pins command on hi-lo transition.
+
+******************************************************************************************/
+
+void tms5110_PDC_set(void *chip, int data)
+{
+ struct tms5110 *tms = chip;
+ if (tms->PDC != (data & 0x1) )
+ {
+ tms->PDC = data & 0x1;
+ if (tms->PDC == 0) /* toggling 1->0 processes command on CTL_pins */
+ {
+ /* the only real commands we handle now are SPEAK and RESET */
+
+ switch (tms->CTL_pins & 0xe) /*CTL1 - don't care*/
+ {
+ case TMS5110_CMD_SPEAK:
+ tms->speaking_now = 1;
+
+ //should FIFO be cleared now ?????
+
+ break;
+
+ case TMS5110_CMD_RESET:
+ tms->speaking_now = 0;
+ tms->talk_status = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+
+
+/******************************************************************************************
+
+ parse_frame -- parse a new frame's worth of data; returns 0 if not enough bits in buffer
+
+******************************************************************************************/
+
+static void parse_frame(struct tms5110 *tms)
+{
+ int bits, indx, i, rep_flag;
+
+
+ /* count the total number of bits available */
+ bits = tms->fifo_count;
+
+
+ /* attempt to extract the energy index */
+ bits -= 4;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ indx = extract_bits(tms,4);
+ tms->new_energy = energytable[indx];
+
+
+ /* if the energy index is 0 or 15, we're done */
+
+ if ((indx == 0) || (indx == 15))
+ {
+ if (DEBUG_5110) logerror(" (4-bit energy=%d frame)\n",tms->new_energy);
+
+ /* clear the k's */
+ if (indx == 0)
+ {
+ for (i = 0; i < 10; i++)
+ tms->new_k[i] = 0;
+ }
+
+ /* clear fifo if stop frame encountered */
+ if (indx == 15)
+ {
+ if (DEBUG_5110) logerror(" (4-bit energy=%d STOP frame)\n",tms->new_energy);
+ tms->fifo_head = tms->fifo_tail = tms->fifo_count = 0;
+ //speaking_now = talk_status = 0;
+ }
+ return;
+ }
+
+
+ /* attempt to extract the repeat flag */
+ bits -= 1;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ rep_flag = extract_bits(tms,1);
+
+ /* attempt to extract the pitch */
+ bits -= 5;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ indx = extract_bits(tms,5);
+ tms->new_pitch = pitchtable[indx];
+
+
+ /* if this is a repeat frame, just copy the k's */
+ if (rep_flag)
+ {
+ //actually, we do nothing because the k's were already loaded (on parsing the previous frame)
+
+ if (DEBUG_5110) logerror(" (10-bit energy=%d pitch=%d rep=%d frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+ return;
+ }
+
+
+ /* if the pitch index was zero, we need 4 k's */
+ if (indx == 0)
+ {
+ /* attempt to extract 4 K's */
+ bits -= 18;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ tms->new_k[0] = k1table[extract_bits(tms,5)];
+ tms->new_k[1] = k2table[extract_bits(tms,5)];
+ tms->new_k[2] = k3table[extract_bits(tms,4)];
+ tms->new_k[3] = k4table[extract_bits(tms,4)];
+
+ /* and clear the rest of the new_k[] */
+ for (i = 4; i < 10; i++)
+ tms->new_k[i] = 0;
+
+ if (DEBUG_5110) logerror(" (28-bit energy=%d pitch=%d rep=%d 4K frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+ return;
+ }
+
+ /* else we need 10 K's */
+ bits -= 39;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ tms->new_k[0] = k1table[extract_bits(tms,5)];
+ tms->new_k[1] = k2table[extract_bits(tms,5)];
+ tms->new_k[2] = k3table[extract_bits(tms,4)];
+ tms->new_k[3] = k4table[extract_bits(tms,4)];
+ tms->new_k[4] = k5table[extract_bits(tms,4)];
+ tms->new_k[5] = k6table[extract_bits(tms,4)];
+ tms->new_k[6] = k7table[extract_bits(tms,4)];
+ tms->new_k[7] = k8table[extract_bits(tms,3)];
+ tms->new_k[8] = k9table[extract_bits(tms,3)];
+ tms->new_k[9] = k10table[extract_bits(tms,3)];
+
+ if (DEBUG_5110) logerror(" (49-bit energy=%d pitch=%d rep=%d 10K frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+
+}
+
+
+
+#if 0
+/*This is an example word TEN taken from the TMS5110A datasheet*/
+static unsigned int example_word_TEN[619]={
+/* 1*/1,0,0,0, 0, 0,0,0,0,0, 1,1,0,0,0, 0,0,0,1,0, 0,1,1,1, 0,1,0,1,
+/* 2*/1,0,0,0, 0, 0,0,0,0,0, 1,0,0,1,0, 0,0,1,1,0, 0,0,1,1, 0,1,0,1,
+/* 3*/1,1,0,0, 0, 1,0,0,0,0, 1,0,1,0,0, 0,1,0,1,0, 0,1,0,0, 1,0,1,0, 1,0,0,0, 1,0,0,1, 0,1,0,1, 0,0,1, 0,1,0, 0,1,1,
+/* 4*/1,1,1,0, 0, 0,1,1,1,1, 1,0,1,0,1, 0,1,1,1,0, 0,1,0,1, 0,1,1,1, 0,1,1,1, 1,0,1,1, 1,0,1,0, 0,1,1, 0,1,0, 0,1,1,
+/* 5*/1,1,1,0, 0, 1,0,0,0,0, 1,0,1,0,0, 0,1,1,1,0, 0,1,0,1, 1,0,1,0, 1,0,0,0, 1,1,0,0, 1,0,1,1, 1,0,0, 0,1,0, 0,1,1,
+/* 6*/1,1,1,0, 0, 1,0,0,0,1, 1,0,1,0,1, 0,1,1,0,1, 0,1,1,0, 0,1,1,1, 0,1,1,1, 1,0,1,0, 1,0,1,0, 1,1,0, 0,0,1, 1,0,0,
+/* 7*/1,1,1,0, 0, 1,0,0,1,0, 1,0,1,1,1, 0,1,1,1,0, 0,1,1,1, 0,1,1,1, 0,1,0,1, 0,1,1,0, 1,0,0,1, 1,1,0, 0,1,0, 0,1,1,
+/* 8*/1,1,1,0, 1, 1,0,1,0,1,
+/* 9*/1,1,1,0, 0, 1,1,0,0,1, 1,0,1,1,1, 0,1,0,1,1, 1,0,1,1, 0,1,1,1, 0,1,0,0, 1,0,0,0, 1,0,0,0, 1,1,0, 0,1,1, 0,1,1,
+/*10*/1,1,0,1, 0, 1,1,0,1,0, 1,0,1,0,1, 0,1,1,0,1, 1,0,1,1, 0,1,0,1, 0,1,0,0, 1,0,0,0, 1,0,1,0, 1,1,0, 0,1,0, 1,0,0,
+/*11*/1,0,1,1, 0, 1,1,0,1,1, 1,0,0,1,1, 1,0,0,1,0, 0,1,1,0, 0,0,1,1, 0,1,0,1, 1,0,0,1, 1,0,1,0, 1,0,0, 0,1,1, 0,1,1,
+/*12*/1,0,0,0, 0, 1,1,1,0,0, 1,0,0,1,1, 0,0,1,1,0, 0,1,0,0, 0,1,1,0, 1,1,0,0, 0,1,0,1, 1,0,0,0, 1,0,0, 0,1,0, 1,0,1,
+/*13*/0,1,1,1, 1, 1,1,1,0,1,
+/*14*/0,1,1,1, 0, 1,1,1,1,0, 1,0,0,1,1, 0,0,1,1,1, 0,1,0,1, 0,1,0,1, 1,1,0,0, 0,1,1,1, 1,0,0,0, 1,0,0, 0,1,0, 1,0,1,
+/*15*/0,1,1,0, 0, 1,1,1,1,0, 1,0,1,0,1, 0,0,1,1,0, 0,1,0,0, 0,0,1,1, 1,1,0,0, 1,0,0,1, 0,1,1,1, 1,0,1, 0,1,0, 1,0,1,
+/*16*/1,1,1,1
+};
+#endif
+
diff --git a/src/emu/sound/tms5110.h b/src/emu/sound/tms5110.h
new file mode 100644
index 00000000000..faaba5375a2
--- /dev/null
+++ b/src/emu/sound/tms5110.h
@@ -0,0 +1,32 @@
+#ifndef tms5110_h
+#define tms5110_h
+
+
+/* TMS5110 commands */
+ /* CTL8 CTL4 CTL2 CTL1 | PDC's */
+ /* (MSB) (LSB) | required */
+#define TMS5110_CMD_RESET (0) /* 0 0 0 x | 1 */
+#define TMS5110_CMD_LOAD_ADDRESS (2) /* 0 0 1 x | 2 */
+#define TMS5110_CMD_OUTPUT (4) /* 0 1 0 x | 3 */
+#define TMS5110_CMD_READ_BIT (8) /* 1 0 0 x | 1 */
+#define TMS5110_CMD_SPEAK (10) /* 1 0 1 x | 1 */
+#define TMS5110_CMD_READ_BRANCH (12) /* 1 1 0 x | 1 */
+#define TMS5110_CMD_TEST_TALK (14) /* 1 1 1 x | 3 */
+
+
+void *tms5110_create(int index);
+void tms5110_destroy(void *chip);
+
+void tms5110_reset_chip(void *chip);
+void tms5110_set_M0_callback(void *chip, int (*func)(void));
+
+void tms5110_CTL_set(void *chip, int data);
+void tms5110_PDC_set(void *chip, int data);
+
+int tms5110_status_read(void *chip);
+int tms5110_ready_read(void *chip);
+
+void tms5110_process(void *chip, INT16 *buffer, unsigned int size);
+
+#endif
+
diff --git a/src/emu/sound/tms5110r.c b/src/emu/sound/tms5110r.c
new file mode 100644
index 00000000000..7e0040cf839
--- /dev/null
+++ b/src/emu/sound/tms5110r.c
@@ -0,0 +1,136 @@
+/* TMS5110 ROM Tables */
+
+/* Note: all the tables in this file were read from the real TMS5110A chip, except
+ for the chirptable and the interp_coeff
+*/
+
+
+/* This is the energy lookup table (4-bits -> 10-bits) */
+const static unsigned short energytable[0x10] = {
+0*2, 1*2, 2*2, 3*2,
+4*2, 6*2, 8*2, 11*2,
+16*2, 23*2, 33*2, 47*2,
+63*2, 85*2, 114*2, 511 }; /*note: the last value (511) is not a true energy value, it's just a stop-sentinel */
+
+
+/* This is the tms5110 pitchtable */
+const static unsigned short pitchtable [0x20]={
+0, 15, 16, 17,
+19, 21, 22, 25,
+26, 29, 32, 36,
+40, 42, 46, 50,
+55, 60, 64, 68,
+72, 76, 80, 84,
+86, 93, 101, 110,
+120, 132, 144, 159 };
+
+
+/* These are the reflection coefficient lookup tables */
+
+/* K1 is (5-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k1table[0x20] = {
+-501*64, -498*64, -497*64, -495*64,
+-493*64, -491*64, -488*64, -482*64,
+-478*64, -474*64, -469*64, -464*64,
+-459*64, -452*64, -445*64, -437*64,
+-412*64, -380*64, -339*64, -288*64,
+-227*64, -158*64, -81*64, -1*64,
+ 80*64, 157*64, 226*64, 287*64,
+ 337*64, 379*64, 411*64, 436*64 };
+
+/* K2 is (5-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k2table[0x20] = {
+-328*64, -303*64, -274*64, -244*64,
+-211*64, -175*64, -138*64, -99*64,
+ -59*64, -18*64, 24*64, 64*64,
+ 105*64, 143*64, 180*64, 215*64,
+ 248*64, 278*64, 306*64, 331*64,
+ 354*64, 374*64, 392*64, 408*64,
+ 422*64, 435*64, 445*64, 455*64,
+ 463*64, 470*64, 476*64, 506*64 };
+
+/* K3 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k3table[0x10] = {
+-441*64, -387*64, -333*64, -279*64,
+-225*64, -171*64, -117*64, -63*64,
+ -9*64, 45*64, 98*64, 152*64,
+ 206*64, 260*64, 314*64, 368*64 };
+
+/* K4 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k4table[0x10] = {
+-328*64, -273*64, -217*64, -161*64,
+-106*64, -50*64, 5*64, 61*64,
+ 116*64, 172*64, 228*64, 283*64,
+ 339*64, 394*64, 450*64, 506*64 };
+
+/* K5 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k5table[0x10] = {
+-328*64, -282*64, -235*64, -189*64,
+-142*64, -96*64, -50*64, -3*64,
+ 43*64, 90*64, 136*64, 182*64,
+ 229*64, 275*64, 322*64, 368*64 };
+
+/* K6 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k6table[0x10] = {
+-256*64, -212*64, -168*64, -123*64,
+ -79*64, -35*64, 10*64, 54*64,
+ 98*64, 143*64, 187*64, 232*64,
+ 276*64, 320*64, 365*64, 409*64 };
+
+/* K7 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k7table[0x10] = {
+-308*64, -260*64, -212*64, -164*64,
+-117*64, -69*64, -21*64, 27*64,
+ 75*64, 122*64, 170*64, 218*64,
+ 266*64, 314*64, 361*64, 409*64 };
+
+/* K8 is (3-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k8table[0x08] = {
+-256*64, -161*64, -66*64, 29*64,
+ 124*64, 219*64, 314*64, 409*64 };
+
+/* K9 is (3-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k9table[0x08] = {
+-256*64, -176*64, -96*64, -15*64,
+ 65*64, 146*64, 226*64, 307*64 };
+
+/* K10 is (3-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static int k10table[0x08] = {
+-205*64, -132*64, -59*64, 14*64,
+ 87*64, 160*64, 234*64, 307*64 };
+
+
+/* chirp table */
+
+const static signed char chirptable[51] = {
+0x00, 0x2a, (char)0xd4, 0x32,
+(char)0xb2, 0x12, 0x25, 0x14,
+0x02, (char)0xe1, (char)0xc5, 0x02,
+0x5f, 0x5a, 0x05, 0x0f,
+0x26, (char)0xfc, (char)0xa5, (char)0xa5,
+(char)0xd6, (char)0xdd, (char)0xdc, (char)0xfc,
+0x25, 0x2b, 0x22, 0x21,
+0x0f, (char)0xff, (char)0xf8, (char)0xee,
+(char)0xed, (char)0xef, (char)0xf7, (char)0xf6,
+(char)0xfa, 0x00, 0x03, 0x02,
+0x01, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00
+};
+
+/* interpolation coefficients */
+
+const static char interp_coeff[8] = {
+8, 8, 8, 4, 4, 2, 2, 1
+};
+
diff --git a/src/emu/sound/tms5220.c b/src/emu/sound/tms5220.c
new file mode 100644
index 00000000000..c6907163d40
--- /dev/null
+++ b/src/emu/sound/tms5220.c
@@ -0,0 +1,1140 @@
+/**********************************************************************************************
+
+ TMS5220 simulator
+
+ Written for MAME by Frank Palazzolo
+ With help from Neill Corlett
+ Additional tweaking by Aaron Giles
+ TMS6100 Speech Rom support added by Raphael Nabet
+ PRNG code by Jarek Burczynski backported from tms5110.c by Lord Nightmare
+ Chirp/excitation table fixes by Lord Nightmare
+ Various fixes by Lord Nightmare
+ Modularization by Lord Nightmare
+
+***********************************************************************************************/
+
+#include "sndintrf.h"
+#include "tms5220.h"
+
+
+/* Pull in the ROM tables */
+#include "tms5220r.c"
+
+/*
+ Changes by R. Nabet
+ * added Speech ROM support
+ * modified code so that the beast only start speaking at the start of next frame, like the data
+ sheet says
+*/
+#define USE_OBSOLETE_HACK 0
+
+
+#ifndef TRUE
+ #define TRUE 1
+#endif
+#ifndef FALSE
+ #define FALSE 0
+#endif
+
+
+struct tms5220
+{
+ /* these contain data that describes the 128-bit data FIFO */
+ #define FIFO_SIZE 16
+ UINT8 fifo[FIFO_SIZE];
+ UINT8 fifo_head;
+ UINT8 fifo_tail;
+ UINT8 fifo_count;
+ UINT8 fifo_bits_taken;
+
+
+ /* these contain global status bits */
+ /*
+ R Nabet : speak_external is only set when a speak external command is going on.
+ tms5220_speaking is set whenever a speak or speak external command is going on.
+ Note that we really need to do anything in tms5220_process and play samples only when
+ tms5220_speaking is true. Else, we can play nothing as well, which is a
+ speed-up...
+ */
+ UINT8 tms5220_speaking; /* Speak or Speak External command in progress */
+ UINT8 speak_external; /* Speak External command in progress */
+ #if USE_OBSOLETE_HACK
+ UINT8 speak_delay_frames;
+ #endif
+ UINT8 talk_status; /* tms5220 is really currently speaking */
+ UINT8 first_frame; /* we have just started speaking, and we are to parse the first frame */
+ UINT8 last_frame; /* we are doing the frame of sound */
+ UINT8 buffer_low; /* FIFO has less than 8 bytes in it */
+ UINT8 buffer_empty; /* FIFO is empty*/
+ UINT8 irq_pin; /* state of the IRQ pin (output) */
+
+ void (*irq_func)(int state); /* called when the state of the IRQ pin changes */
+
+
+ /* these contain data describing the current and previous voice frames */
+ UINT16 old_energy;
+ UINT16 old_pitch;
+ INT32 old_k[10];
+
+ UINT16 new_energy;
+ UINT16 new_pitch;
+ INT32 new_k[10];
+
+
+ /* these are all used to contain the current state of the sound generation */
+ UINT16 current_energy;
+ UINT16 current_pitch;
+ INT32 current_k[10];
+
+ UINT16 target_energy;
+ UINT16 target_pitch;
+ INT32 target_k[10];
+
+ UINT16 previous_energy; /* needed for lattice filter to match patent */
+
+ UINT8 interp_count; /* number of interp periods (0-7) */
+ UINT8 sample_count; /* sample number within interp (0-24) */
+ UINT16 pitch_count;
+
+ INT32 u[11];
+ INT32 x[10];
+
+ INT32 RNG; /* the random noise generator configuration is: 1 + x + x^3 + x^4 + x^13 */
+ INT8 excitation_data;
+
+ /* R Nabet : These have been added to emulate speech Roms */
+ int (*read_callback)(int count);
+ void (*load_address_callback)(int data);
+ void (*read_and_branch_callback)(void);
+ UINT8 schedule_dummy_read; /* set after each load address, so that next read operation
+ is preceded by a dummy read */
+
+ UINT8 data_register; /* data register, used by read command */
+ UINT8 RDB_flag; /* whether we should read data register or status register */
+
+ /* flag for variant tms0285/tms5200 emulation */
+ /* The TMC0285 AKA TMS5200 is an early variant of the TMS5220 used in
+ the early releases of the Speech Module for the TI-99/4(a) computer,
+ in Zaccaria's 'Money Money', and in a few other places.
+ The TMS5200 has a bug in its state machine PLA which causes it to
+ incorrectly use the LPC K3 parameter table for both K3 and K4.
+ (the chip has the unused K4 parameter in its internal ROM, but it is
+ never accessed due to the PLA bug)
+ The bug was fixed in the quickly-released TMS5220.
+ TI may have sold the remaining stocks of TMS5200s at a discount, and
+ apparently provided a special encoder to work around the bug.
+ Other than the bug, the two chips are identical.
+ Another variant of the TMS5220 is the TMS5220C/TSP5220C, which adds
+ an additional opcode (to select the data rate).
+ */
+ tms5220_variant variant;
+ /* The TMS52xx has two different ways of providing output data: the
+ analog speaker pin (which was usually used) and the Digital I/O pin.
+ The internal DAC used to feed the analog pin is only 8 bits, while the
+ digital pin gives full 12? bit resolution to the output data.
+ */
+ UINT8 digital_select;
+};
+
+
+/* Static function prototypes */
+static void process_command(struct tms5220 *tms);
+static int extract_bits(struct tms5220 *tms, int count);
+static int parse_frame(struct tms5220 *tms, int the_first_frame);
+static void check_buffer_low(struct tms5220 *tms);
+static void set_interrupt_state(struct tms5220 *tms, int state);
+static INT16 lattice_filter(void *chip);
+static INT16 clip_and_wrap(INT16 cliptemp);
+
+
+#define DEBUG_5220 0
+
+
+void *tms5220_create(int index)
+{
+ struct tms5220 *tms;
+
+ tms = malloc_or_die(sizeof(*tms));
+ memset(tms, 0, sizeof(*tms));
+
+ state_save_register_item_array("tms5220", index, tms->fifo);
+ state_save_register_item("tms5220", index, tms->fifo_head);
+ state_save_register_item("tms5220", index, tms->fifo_tail);
+ state_save_register_item("tms5220", index, tms->fifo_count);
+ state_save_register_item("tms5220", index, tms->fifo_bits_taken);
+
+ state_save_register_item("tms5220", index, tms->tms5220_speaking);
+ state_save_register_item("tms5220", index, tms->speak_external);
+ state_save_register_item("tms5220", index, tms->talk_status);
+ state_save_register_item("tms5220", index, tms->first_frame);
+ state_save_register_item("tms5220", index, tms->last_frame);
+ state_save_register_item("tms5220", index, tms->buffer_low);
+ state_save_register_item("tms5220", index, tms->buffer_empty);
+ state_save_register_item("tms5220", index, tms->irq_pin);
+
+ state_save_register_item("tms5220", index, tms->old_energy);
+ state_save_register_item("tms5220", index, tms->old_pitch);
+ state_save_register_item_array("tms5220", index, tms->old_k);
+
+ state_save_register_item("tms5220", index, tms->new_energy);
+ state_save_register_item("tms5220", index, tms->new_pitch);
+ state_save_register_item_array("tms5220", index, tms->new_k);
+
+ state_save_register_item("tms5220", index, tms->current_energy);
+ state_save_register_item("tms5220", index, tms->current_pitch);
+ state_save_register_item_array("tms5220", index, tms->current_k);
+
+ state_save_register_item("tms5220", index, tms->target_energy);
+ state_save_register_item("tms5220", index, tms->target_pitch);
+ state_save_register_item_array("tms5220", index, tms->target_k);
+
+ state_save_register_item("tms5220", index, tms->previous_energy);
+
+ state_save_register_item("tms5220", index, tms->interp_count);
+ state_save_register_item("tms5220", index, tms->sample_count);
+ state_save_register_item("tms5220", index, tms->pitch_count);
+
+ state_save_register_item_array("tms5220", index, tms->u);
+ state_save_register_item_array("tms5220", index, tms->x);
+
+ state_save_register_item("tms5220", index, tms->RNG);
+ state_save_register_item("tms5220", index, tms->excitation_data);
+
+ state_save_register_item("tms5220", index, tms->schedule_dummy_read);
+ state_save_register_item("tms5220", index, tms->data_register);
+ state_save_register_item("tms5220", index, tms->RDB_flag);
+ state_save_register_item("tms5220", index, tms->digital_select);
+
+ return tms;
+}
+
+
+void tms5220_destroy(void *chip)
+{
+ free(chip);
+}
+
+/**********************************************************************************************
+
+ tms5220_reset -- resets the TMS5220
+
+***********************************************************************************************/
+
+void tms5220_reset_chip(void *chip)
+{
+ struct tms5220 *tms = chip;
+
+ /* initialize the FIFO */
+ /*memset(tms->fifo, 0, sizeof(tms->fifo));*/
+ tms->fifo_head = tms->fifo_tail = tms->fifo_count = tms->fifo_bits_taken = 0;
+
+ /* initialize the chip state */
+ /* Note that we do not actually clear IRQ on start-up : IRQ is even raised if tms->buffer_empty or tms->buffer_low are 0 */
+ tms->tms5220_speaking = tms->speak_external = tms->talk_status = tms->first_frame = tms->last_frame = tms->irq_pin = 0;
+#if USE_OBSOLETE_HACK
+ tms->speak_delay_frames = 0;
+#endif
+ if (tms->irq_func) tms->irq_func(0);
+ tms->buffer_empty = tms->buffer_low = 1;
+
+ tms->RDB_flag = FALSE;
+
+ /* initialize the energy/pitch/k states */
+ tms->old_energy = tms->new_energy = tms->current_energy = tms->target_energy = 0;
+ tms->old_pitch = tms->new_pitch = tms->current_pitch = tms->target_pitch = 0;
+ memset(tms->old_k, 0, sizeof(tms->old_k));
+ memset(tms->new_k, 0, sizeof(tms->new_k));
+ memset(tms->current_k, 0, sizeof(tms->current_k));
+ memset(tms->target_k, 0, sizeof(tms->target_k));
+
+ /* initialize the sample generators */
+ tms->interp_count = tms->sample_count = tms->pitch_count = 0;
+ tms->RNG = 0x1FFF;
+ memset(tms->u, 0, sizeof(tms->u));
+ memset(tms->x, 0, sizeof(tms->x));
+
+ if (tms->load_address_callback)
+ (*tms->load_address_callback)(0);
+
+ tms->schedule_dummy_read = TRUE;
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_set_irq -- sets the interrupt handler
+
+***********************************************************************************************/
+
+void tms5220_set_irq(void *chip, void (*func)(int))
+{
+ struct tms5220 *tms = chip;
+ tms->irq_func = func;
+}
+
+
+/**********************************************************************************************
+
+ tms5220_set_read -- sets the speech ROM read handler
+
+***********************************************************************************************/
+
+void tms5220_set_read(void *chip, int (*func)(int))
+{
+ struct tms5220 *tms = chip;
+ tms->read_callback = func;
+}
+
+
+/**********************************************************************************************
+
+ tms5220_set_load_address -- sets the speech ROM load address handler
+
+***********************************************************************************************/
+
+void tms5220_set_load_address(void *chip, void (*func)(int))
+{
+ struct tms5220 *tms = chip;
+ tms->load_address_callback = func;
+}
+
+
+/**********************************************************************************************
+
+ tms5220_set_read_and_branch -- sets the speech ROM read and branch handler
+
+***********************************************************************************************/
+
+void tms5220_set_read_and_branch(void *chip, void (*func)(void))
+{
+ struct tms5220 *tms = chip;
+ tms->read_and_branch_callback = func;
+}
+
+
+/**********************************************************************************************
+
+ tms5220_set_variant -- sets the tms5220 core to emulate its buggy forerunner, the tms0285
+
+***********************************************************************************************/
+
+void tms5220_set_variant(void *chip, tms5220_variant new_variant)
+{
+ struct tms5220 *tms = chip;
+ tms->variant = new_variant;
+}
+
+
+/**********************************************************************************************
+
+ tms5220_data_write -- handle a write to the TMS5220
+
+***********************************************************************************************/
+
+void tms5220_data_write(void *chip, int data)
+{
+ struct tms5220 *tms = chip;
+
+ /* add this byte to the FIFO */
+ if (tms->fifo_count < FIFO_SIZE)
+ {
+ tms->fifo[tms->fifo_tail] = data;
+ tms->fifo_tail = (tms->fifo_tail + 1) % FIFO_SIZE;
+ tms->fifo_count++;
+
+ /* if we were speaking, then we're no longer empty */
+ if (tms->speak_external)
+ tms->buffer_empty = 0;
+
+ if (DEBUG_5220) logerror("Added byte to FIFO (size=%2d)\n", tms->fifo_count);
+ }
+ else
+ {
+ if (DEBUG_5220) logerror("Ran out of room in the FIFO!\n");
+ }
+
+ /* update the buffer low state */
+ check_buffer_low(tms);
+
+ if (! tms->speak_external)
+ /* R Nabet : we parse commands at once. It is necessary for such commands as read. */
+ process_command (tms/*data*/);
+}
+
+
+/**********************************************************************************************
+
+ tms5220_status_read -- read status or data from the TMS5220
+
+ From the data sheet:
+ bit 0 = TS - Talk Status is active (high) when the VSP is processing speech data.
+ Talk Status goes active at the initiation of a Speak command or after nine
+ bytes of data are loaded into the FIFO following a Speak External command. It
+ goes inactive (low) when the stop code (Energy=1111) is processed, or
+ immediately by a buffer empty condition or a reset command.
+ bit 1 = BL - Buffer Low is active (high) when the FIFO buffer is more than half empty.
+ Buffer Low is set when the "Last-In" byte is shifted down past the half-full
+ boundary of the stack. Buffer Low is cleared when data is loaded to the stack
+ so that the "Last-In" byte lies above the half-full boundary and becomes the
+ ninth data byte of the stack.
+ bit 2 = BE - Buffer Empty is active (high) when the FIFO buffer has run out of data
+ while executing a Speak External command. Buffer Empty is set when the last bit
+ of the "Last-In" byte is shifted out to the Synthesis Section. This causes
+ Talk Status to be cleared. Speed is terminated at some abnormal point and the
+ Speak External command execution is terminated.
+
+***********************************************************************************************/
+
+int tms5220_status_read(void *chip)
+{
+ struct tms5220 *tms = chip;
+
+ if (tms->RDB_flag)
+ { /* if last command was read, return data register */
+ tms->RDB_flag = FALSE;
+ return(tms->data_register);
+ }
+ else
+ { /* read status */
+
+ /* clear the interrupt pin */
+ set_interrupt_state(tms, 0);
+
+ if (DEBUG_5220) logerror("Status read: TS=%d BL=%d BE=%d\n", tms->talk_status, tms->buffer_low, tms->buffer_empty);
+
+ return (tms->talk_status << 7) | (tms->buffer_low << 6) | (tms->buffer_empty << 5);
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_ready_read -- returns the ready state of the TMS5220
+
+***********************************************************************************************/
+
+int tms5220_ready_read(void *chip)
+{
+ struct tms5220 *tms = chip;
+ return (tms->fifo_count < FIFO_SIZE-1);
+}
+
+
+/**********************************************************************************************
+
+ tms5220_ready_read -- returns the number of cycles until ready is asserted
+
+***********************************************************************************************/
+
+int tms5220_cycles_to_ready(void *chip)
+{
+ struct tms5220 *tms = chip;
+ int answer;
+
+
+ if (tms5220_ready_read(tms))
+ answer = 0;
+ else
+ {
+ int val;
+
+ answer = 200-tms->sample_count+8;
+
+ /* total number of bits available in current byte is (8 - tms->fifo_bits_taken) */
+ /* if more than 4 are available, we need to check the energy */
+ if (tms->fifo_bits_taken < 4)
+ {
+ /* read energy */
+ val = (tms->fifo[tms->fifo_head] >> tms->fifo_bits_taken) & 0xf;
+ if (val == 0)
+ /* 0 -> silence frame: we will only read 4 bits, and we will
+ therefore need to read another frame before the FIFO is not
+ full any more */
+ answer += 200;
+ /* 15 -> stop frame, we will only read 4 bits, but the FIFO will
+ we cleared */
+ /* otherwise, we need to parse the repeat flag (1 bit) and the
+ pitch (6 bits), so everything will be OK. */
+ }
+ }
+
+ return answer;
+}
+
+
+/**********************************************************************************************
+
+ tms5220_int_read -- returns the interrupt state of the TMS5220
+
+***********************************************************************************************/
+
+int tms5220_int_read(void *chip)
+{
+ struct tms5220 *tms = chip;
+ return tms->irq_pin;
+}
+
+
+
+/**********************************************************************************************
+
+ tms5220_process -- fill the buffer with a specific number of samples
+
+***********************************************************************************************/
+
+void tms5220_process(void *chip, INT16 *buffer, unsigned int size)
+{
+ struct tms5220 *tms = chip;
+ int buf_count=0;
+ int i, interp_period, bitout;
+
+tryagain:
+
+ /* if we're not speaking, parse commands */
+ /*while (!tms->speak_external && tms->fifo_count > 0)
+ process_command(tms);*/
+
+ /* if we're empty and still not speaking, fill with nothingness */
+ if ((!tms->tms5220_speaking) && (!tms->last_frame))
+ goto empty;
+
+ /* if we're to speak, but haven't started, wait for the 9th byte */
+ if (!tms->talk_status && tms->speak_external)
+ {
+ if (tms->fifo_count < 9)
+ goto empty;
+
+ tms->talk_status = 1;
+ tms->first_frame = 1; /* will cause the first frame to be parsed */
+ tms->buffer_empty = 0;
+ }
+
+#if 0
+ /* we are to speak, yet we fill with 0s until start of next frame */
+ if (tms->first_frame)
+ {
+ while ((size > 0) && ((tms->sample_count != 0) || (tms->interp_count != 0)))
+ {
+ tms->sample_count = (tms->sample_count + 1) % 200;
+ tms->interp_count = (tms->interp_count + 1) % 25;
+ buffer[buf_count] = 0x00; /* should be (-1 << 8) ??? (cf note in data sheet, p 10, table 4) */
+ buf_count++;
+ size--;
+ }
+ }
+#endif
+
+#if USE_OBSOLETE_HACK
+ /* apply some delay before we actually consume data; Victory requires this */
+ if (tms->speak_delay_frames)
+ {
+ if (size <= tms->speak_delay_frames)
+ {
+ tms->speak_delay_frames -= size;
+ size = 0;
+ }
+ else
+ {
+ size -= tms->speak_delay_frames;
+ tms->speak_delay_frames = 0;
+ }
+ }
+#endif
+
+ /* loop until the buffer is full or we've stopped speaking */
+ while ((size > 0) && tms->talk_status)
+ {
+
+ /* if we're ready for a new frame */
+ if ((tms->interp_count == 0) && (tms->sample_count == 0))
+ {
+ /* Parse a new frame */
+ if (!parse_frame(tms, tms->first_frame))
+ break;
+ tms->first_frame = 0;
+
+ /* Set old target as new start of frame */
+ tms->current_energy = tms->old_energy;
+ tms->current_pitch = tms->old_pitch;
+ for (i = 0; i < 10; i++)
+ tms->current_k[i] = tms->old_k[i];
+
+ /* is this a zero energy frame? */
+ if (tms->current_energy == 0)
+ {
+ /*mame_printf_debug("processing frame: zero energy\n");*/
+ tms->target_energy = 0;
+ tms->target_pitch = tms->current_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->current_k[i];
+ }
+
+ /* is this a stop frame? */
+ else if (tms->current_energy == (energytable[15] >> 6))
+ {
+ /*mame_printf_debug("processing frame: stop frame\n");*/
+ tms->current_energy = energytable[0] >> 6;
+ tms->target_energy = tms->current_energy;
+ /*tms->interp_count = tms->sample_count =*/ tms->pitch_count = 0;
+ tms->last_frame = 0;
+ if (tms->tms5220_speaking)
+ /* new speech command in progress */
+ tms->first_frame = 1;
+ else
+ {
+ /* really stop speaking */
+ tms->talk_status = 0;
+
+ /* generate an interrupt if necessary */
+ set_interrupt_state(tms, 1);
+ }
+
+ /* try to fetch commands again */
+ goto tryagain;
+ }
+ else
+ {
+ /* is this the ramp down frame? */
+ if (tms->new_energy == (energytable[15] >> 6))
+ {
+ /*mame_printf_debug("processing frame: ramp down\n");*/
+ tms->target_energy = 0;
+ tms->target_pitch = tms->current_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->current_k[i];
+ }
+ /* Reset the step size */
+ else
+ {
+ /*mame_printf_debug("processing frame: Normal\n");*/
+ /*mame_printf_debug("*** Energy = %d\n",tms->current_energy);*/
+ /*mame_printf_debug("proc: %d %d\n",last_fbuf_head,fbuf_head);*/
+
+ tms->target_energy = tms->new_energy;
+ tms->target_pitch = tms->new_pitch;
+
+ for (i = 0; i < 4; i++)
+ tms->target_k[i] = tms->new_k[i];
+ if (tms->current_pitch == 0)
+ for (i = 4; i < 10; i++)
+ {
+ tms->target_k[i] = tms->current_k[i] = 0;
+ }
+ else
+ for (i = 4; i < 10; i++)
+ tms->target_k[i] = tms->new_k[i];
+ }
+ }
+ }
+ else if (tms->interp_count == 0)
+ {
+ /* Update values based on step values */
+ /*mame_printf_debug("\n");*/
+
+ interp_period = tms->sample_count / 25;
+ tms->current_energy += ((tms->target_energy - tms->current_energy) >> interp_coeff[interp_period]);
+ if (tms->old_pitch != 0)
+ tms->current_pitch += ((tms->target_pitch - tms->current_pitch) >> interp_coeff[interp_period]);
+
+ /*mame_printf_debug("*** Energy = %d\n",tms->current_energy);*/
+
+ for (i = 0; i < 10; i++)
+ {
+ tms->current_k[i] += ((tms->target_k[i] - tms->current_k[i]) >> interp_coeff[interp_period]);
+ }
+ }
+
+ if (tms->old_energy == 0)
+ {
+ /* generate silent samples here */
+ tms->excitation_data = 0x00; /* I'm not sure if this is actually RIGHT, the current_energy may be forced to zero when we've just passed a zero energy frame. However, this does work too. May be removed later. */
+ }
+ else if (tms->old_pitch == 0)
+ {
+ /* generate unvoiced samples here */
+ if (tms->RNG & 1)
+ tms->excitation_data = -0x40; /* according to the patent it is (either + or -) half of the maximum value in the chirp table, so +-64 */
+ else
+ tms->excitation_data = 0x40;
+ }
+ else
+ {
+ /* generate voiced samples here */
+ tms->excitation_data = chirptable[tms->pitch_count%sizeof(chirptable)];
+ }
+
+ /* Update LFSR every clock, like patent shows */
+ bitout = ((tms->RNG >> 12) & 1) ^
+ ((tms->RNG >> 10) & 1) ^
+ ((tms->RNG >> 9) & 1) ^
+ ((tms->RNG >> 0) & 1);
+ tms->RNG >>= 1;
+ tms->RNG |= bitout << 12;
+
+ buffer[buf_count] = clip_and_wrap(lattice_filter(tms)); /* execute lattice filter and clipping/wrapping */
+
+ if (tms->digital_select == 0) /* if digital is NOT selected... */
+ buffer[buf_count] &= 0xff00; /* mask out all but the 8 dac bits */
+
+ /* Update all counts */
+
+ size--;
+ tms->sample_count = (tms->sample_count + 1) % 200;
+
+ if (tms->current_pitch != 0)
+ tms->pitch_count = (tms->pitch_count + 1) % tms->current_pitch;
+ else
+ tms->pitch_count = 0;
+
+ tms->interp_count = (tms->interp_count + 1) % 25;
+ buf_count++;
+ }
+
+empty:
+
+ while (size > 0)
+ {
+ tms->sample_count = (tms->sample_count + 1) % 200;
+ tms->interp_count = (tms->interp_count + 1) % 25;
+ buffer[buf_count] = 0x00; /* should be (-1 << 8) ??? (cf note in data sheet, p 10, table 4) */
+ buf_count++;
+ size--;
+ }
+}
+
+/**********************************************************************************************
+
+ clip_and_wrap -- clips and wraps the 14 bit return value from the lattice filter to its final 10 bit value (-512 to 511), and upshifts this to 16 bits
+
+***********************************************************************************************/
+
+static INT16 clip_and_wrap(INT16 cliptemp)
+{
+ /* clipping & wrapping, just like the patent shows */
+
+ if (cliptemp > 2047) cliptemp = -2048 + (cliptemp-2047);
+ else if (cliptemp < -2048) cliptemp = 2047 - (cliptemp+2048);
+
+ if (cliptemp > 511) { mame_printf_debug ("cliptemp > 511\n");
+ return 127<<8; }
+ else if (cliptemp < -512) { mame_printf_debug ("cliptemp < -512\n");
+ return -128<<8; }
+ else
+ return cliptemp << 6;
+}
+
+
+/**********************************************************************************************
+
+ lattice_filter -- executes one 'full run' of the lattice filter on a specific byte of
+ excitation data, and specific values of all the current k constants, and returns the
+ resulting sample.
+ Note: the current_k processing here by dividing the result by 32768 is necessary, as the stored
+ parameters in the lookup table are the 10 bit coefficients but are pre-multiplied by 512 for
+ ease of storage. This is undone on the real chip by a shifter here, after the multiply.
+
+***********************************************************************************************/
+
+static INT16 lattice_filter(void *chip)
+{
+ struct tms5220 *tms = chip;
+ /* Lattice filter here */
+ /* Aug/05/07: redone as unrolled loop, for clarity - LN*/
+ /* Copied verbatim from table I in US patent 4,209,804:
+ notation equivalencies from table:
+ Yn(i) == tms->u[n-1]
+ Kn = tms->current_k[n-1]
+ bn = tms->x[n-1]
+ */
+ tms->u[10] = (tms->excitation_data * tms->previous_energy) >> 8; /* Y(11) */
+ tms->u[9] = tms->u[10] - ((tms->current_k[9] * tms->x[9]) / 32768);
+ tms->u[8] = tms->u[9] - ((tms->current_k[8] * tms->x[8]) / 32768);
+ tms->x[9] = tms->x[8] + ((tms->current_k[8] * tms->u[8]) / 32768);
+ tms->u[7] = tms->u[8] - ((tms->current_k[7] * tms->x[7]) / 32768);
+ tms->x[8] = tms->x[7] + ((tms->current_k[7] * tms->u[7]) / 32768);
+ tms->u[6] = tms->u[7] - ((tms->current_k[6] * tms->x[6]) / 32768);
+ tms->x[7] = tms->x[6] + ((tms->current_k[6] * tms->u[6]) / 32768);
+ tms->u[5] = tms->u[6] - ((tms->current_k[5] * tms->x[5]) / 32768);
+ tms->x[6] = tms->x[5] + ((tms->current_k[5] * tms->u[5]) / 32768);
+ tms->u[4] = tms->u[5] - ((tms->current_k[4] * tms->x[4]) / 32768);
+ tms->x[5] = tms->x[4] + ((tms->current_k[4] * tms->u[4]) / 32768);
+ tms->u[3] = tms->u[4] - ((tms->current_k[3] * tms->x[3]) / 32768);
+ tms->x[4] = tms->x[3] + ((tms->current_k[3] * tms->u[3]) / 32768);
+ tms->u[2] = tms->u[3] - ((tms->current_k[2] * tms->x[2]) / 32768);
+ tms->x[3] = tms->x[2] + ((tms->current_k[2] * tms->u[2]) / 32768);
+ tms->u[1] = tms->u[2] - ((tms->current_k[1] * tms->x[1]) / 32768);
+ tms->x[2] = tms->x[1] + ((tms->current_k[1] * tms->u[1]) / 32768);
+ tms->u[0] = tms->u[1] - ((tms->current_k[0] * tms->x[0]) / 32768);
+ tms->x[1] = tms->x[0] + ((tms->current_k[0] * tms->u[0]) / 32768);
+ tms->x[0] = tms->u[0];
+ tms->previous_energy = tms->current_energy;
+ return tms->u[0];
+}
+
+
+/**********************************************************************************************
+
+ process_command -- extract a byte from the FIFO and interpret it as a command
+
+***********************************************************************************************/
+
+static void process_command(struct tms5220 *tms)
+{
+ unsigned char cmd;
+
+ /* if there are stray bits, ignore them */
+ if (tms->fifo_bits_taken)
+ {
+ tms->fifo_bits_taken = 0;
+ tms->fifo_count--;
+ tms->fifo_head = (tms->fifo_head + 1) % FIFO_SIZE;
+ }
+
+ /* grab a full byte from the FIFO */
+ if (tms->fifo_count > 0)
+ {
+ cmd = tms->fifo[tms->fifo_head];
+ tms->fifo_count--;
+ tms->fifo_head = (tms->fifo_head + 1) % FIFO_SIZE;
+
+ /* parse the command */
+ switch (cmd & 0x70)
+ {
+ case 0x10 : /* read byte */
+ if (tms->schedule_dummy_read)
+ {
+ tms->schedule_dummy_read = FALSE;
+ if (tms->read_callback)
+ (*tms->read_callback)(1);
+ }
+ if (tms->read_callback)
+ tms->data_register = (*tms->read_callback)(8); /* read one byte from speech ROM... */
+ tms->RDB_flag = TRUE;
+ break;
+
+ case 0x30 : /* read and branch */
+ if (DEBUG_5220) logerror("read and branch command received\n");
+ tms->RDB_flag = FALSE;
+ if (tms->read_and_branch_callback)
+ (*tms->read_and_branch_callback)();
+ break;
+
+ case 0x40 : /* load address */
+ /* tms5220 data sheet says that if we load only one 4-bit nibble, it won't work.
+ This code does not care about this. */
+ if (tms->load_address_callback)
+ (*tms->load_address_callback)(cmd & 0x0f);
+ tms->schedule_dummy_read = TRUE;
+ break;
+
+ case 0x50 : /* speak */
+ if (tms->schedule_dummy_read)
+ {
+ tms->schedule_dummy_read = FALSE;
+ if (tms->read_callback)
+ (*tms->read_callback)(1);
+ }
+ tms->tms5220_speaking = 1;
+ tms->speak_external = 0;
+ if (! tms->last_frame)
+ {
+ tms->first_frame = 1;
+ }
+ tms->talk_status = 1; /* start immediately */
+ break;
+
+ case 0x60 : /* speak external */
+ tms->tms5220_speaking = tms->speak_external = 1;
+#if USE_OBSOLETE_HACK
+ tms->speak_delay_frames = 10;
+#endif
+
+ tms->RDB_flag = FALSE;
+
+ /* according to the datasheet, this will cause an interrupt due to a BE condition */
+ if (!tms->buffer_empty)
+ {
+ tms->buffer_empty = 1;
+ set_interrupt_state(tms, 1);
+ }
+
+ tms->talk_status = 0; /* wait to have 8 bytes in buffer before starting */
+ break;
+
+ case 0x70 : /* reset */
+ if (tms->schedule_dummy_read)
+ {
+ tms->schedule_dummy_read = FALSE;
+ if (tms->read_callback)
+ (*tms->read_callback)(1);
+ }
+ tms5220_reset_chip(tms);
+ break;
+ }
+ }
+
+ /* update the buffer low state */
+ check_buffer_low(tms);
+}
+
+
+
+/**********************************************************************************************
+
+ extract_bits -- extract a specific number of bits from the FIFO
+
+***********************************************************************************************/
+
+static int extract_bits(struct tms5220 *tms, int count)
+{
+ int val = 0;
+
+ if (tms->speak_external)
+ {
+ /* extract from FIFO */
+ while (count--)
+ {
+ val = (val << 1) | ((tms->fifo[tms->fifo_head] >> tms->fifo_bits_taken) & 1);
+ tms->fifo_bits_taken++;
+ if (tms->fifo_bits_taken >= 8)
+ {
+ tms->fifo_count--;
+ tms->fifo_head = (tms->fifo_head + 1) % FIFO_SIZE;
+ tms->fifo_bits_taken = 0;
+ }
+ }
+ }
+ else
+ {
+ /* extract from speech ROM */
+ if (tms->read_callback)
+ val = (* tms->read_callback)(count);
+ }
+
+ return val;
+}
+
+
+
+/**********************************************************************************************
+
+ parse_frame -- parse a new frame's worth of data; returns 0 if not enough bits in buffer
+
+***********************************************************************************************/
+
+static int parse_frame(struct tms5220 *tms, int the_first_frame)
+{
+ int bits = 0; /* number of bits in FIFO (speak external only) */
+ int indx, i, rep_flag;
+
+ if (! the_first_frame)
+ {
+ /* remember previous frame */
+ tms->old_energy = tms->new_energy;
+ tms->old_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->old_k[i] = tms->new_k[i];
+ }
+
+ /* clear out the new frame */
+ tms->new_energy = 0;
+ tms->new_pitch = 0;
+ for (i = 0; i < 10; i++)
+ tms->new_k[i] = 0;
+
+ /* if the previous frame was a stop frame, don't do anything */
+ if ((! the_first_frame) && (tms->old_energy == (energytable[15] >> 6)))
+ /*return 1;*/
+ {
+ tms->buffer_empty = 1;
+ return 1;
+ }
+
+ if (tms->speak_external)
+ /* count the total number of bits available */
+ bits = tms->fifo_count * 8 - tms->fifo_bits_taken;
+
+ /* attempt to extract the energy index */
+ if (tms->speak_external)
+ {
+ bits -= 4;
+ if (bits < 0)
+ goto ranout;
+ }
+ indx = extract_bits(tms, 4);
+ tms->new_energy = energytable[indx] >> 6;
+
+ /* if the index is 0 or 15, we're done */
+ if (indx == 0 || indx == 15)
+ {
+ if (DEBUG_5220) logerror(" (4-bit energy=%d frame)\n",tms->new_energy);
+
+ /* clear tms->fifo if stop frame encountered */
+ if (indx == 15)
+ {
+ tms->fifo_head = tms->fifo_tail = tms->fifo_count = tms->fifo_bits_taken = 0;
+ tms->speak_external = tms->tms5220_speaking = 0;
+ tms->last_frame = 1;
+ }
+ goto done;
+ }
+
+ /* attempt to extract the repeat flag */
+ if (tms->speak_external)
+ {
+ bits -= 1;
+ if (bits < 0)
+ goto ranout;
+ }
+ rep_flag = extract_bits(tms, 1);
+
+ /* attempt to extract the pitch */
+ if (tms->speak_external)
+ {
+ bits -= 6;
+ if (bits < 0)
+ goto ranout;
+ }
+ indx = extract_bits(tms, 6);
+ tms->new_pitch = pitchtable[indx] / 256;
+
+ /* if this is a repeat frame, just copy the k's */
+ if (rep_flag)
+ {
+ for (i = 0; i < 10; i++)
+ tms->new_k[i] = tms->old_k[i];
+
+ if (DEBUG_5220) logerror(" (11-bit energy=%d pitch=%d rep=%d frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+ goto done;
+ }
+
+ /* if the pitch index was zero, we need 4 k's */
+ if (indx == 0)
+ {
+ /* attempt to extract 4 K's */
+ if (tms->speak_external)
+ {
+ bits -= 18;
+ if (bits < 0)
+ goto ranout;
+ }
+ tms->new_k[0] = k1table[extract_bits(tms, 5)];
+ tms->new_k[1] = k2table[extract_bits(tms, 5)];
+ tms->new_k[2] = k3table[extract_bits(tms, 4)];
+ if (tms->variant == variant_tms0285)
+ tms->new_k[3] = k3table[extract_bits(tms, 4)]; /* ??? */
+ else
+ tms->new_k[3] = k4table[extract_bits(tms, 4)];
+
+ if (DEBUG_5220) logerror(" (29-bit energy=%d pitch=%d rep=%d 4K frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+ goto done;
+ }
+
+ /* else we need 10 K's */
+ if (tms->speak_external)
+ {
+ bits -= 39;
+ if (bits < 0)
+ goto ranout;
+ }
+
+ tms->new_k[0] = k1table[extract_bits(tms, 5)];
+ tms->new_k[1] = k2table[extract_bits(tms, 5)];
+ tms->new_k[2] = k3table[extract_bits(tms, 4)];
+ if (tms->variant == variant_tms0285)
+ tms->new_k[3] = k3table[extract_bits(tms, 4)]; /* ??? */
+ else
+ tms->new_k[3] = k4table[extract_bits(tms, 4)];
+ tms->new_k[4] = k5table[extract_bits(tms, 4)];
+ tms->new_k[5] = k6table[extract_bits(tms, 4)];
+ tms->new_k[6] = k7table[extract_bits(tms, 4)];
+ tms->new_k[7] = k8table[extract_bits(tms, 3)];
+ tms->new_k[8] = k9table[extract_bits(tms, 3)];
+ tms->new_k[9] = k10table[extract_bits(tms, 3)];
+
+ if (DEBUG_5220) logerror(" (50-bit energy=%d pitch=%d rep=%d 10K frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+
+done:
+ if (DEBUG_5220)
+ {
+ if (tms->speak_external)
+ logerror("Parsed a frame successfully in FIFO - %d bits remaining\n", bits);
+ else
+ logerror("Parsed a frame successfully in ROM\n");
+ }
+
+ if (the_first_frame)
+ {
+ /* if this is the first frame, no previous frame to take as a starting point */
+ tms->old_energy = tms->new_energy;
+ tms->old_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->old_k[i] = tms->new_k[i];
+ }
+
+ /* update the tms->buffer_low status */
+ check_buffer_low(tms);
+ return 1;
+
+ranout:
+
+ if (DEBUG_5220) logerror("Ran out of bits on a parse!\n");
+
+ /* this is an error condition; mark the buffer empty and turn off speaking */
+ tms->buffer_empty = 1;
+ tms->talk_status = tms->speak_external = tms->tms5220_speaking = the_first_frame = tms->last_frame = 0;
+ tms->fifo_count = tms->fifo_head = tms->fifo_tail = 0;
+
+ tms->RDB_flag = FALSE;
+
+ /* generate an interrupt if necessary */
+ set_interrupt_state(tms, 1);
+ return 0;
+}
+
+
+
+/**********************************************************************************************
+
+ check_buffer_low -- check to see if the buffer low flag should be on or off
+
+***********************************************************************************************/
+
+static void check_buffer_low(struct tms5220 *tms)
+{
+ /* did we just become low? */
+ if (tms->fifo_count <= 8)
+ {
+ /* generate an interrupt if necessary */
+ if (!tms->buffer_low)
+ set_interrupt_state(tms, 1);
+ tms->buffer_low = 1;
+
+ if (DEBUG_5220) logerror("Buffer low set\n");
+ }
+
+ /* did we just become full? */
+ else
+ {
+ tms->buffer_low = 0;
+
+ if (DEBUG_5220) logerror("Buffer low cleared\n");
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ set_interrupt_state -- generate an interrupt
+
+***********************************************************************************************/
+
+static void set_interrupt_state(struct tms5220 *tms, int state)
+{
+ if (tms->irq_func && state != tms->irq_pin)
+ tms->irq_func(state);
+ tms->irq_pin = state;
+}
diff --git a/src/emu/sound/tms5220.h b/src/emu/sound/tms5220.h
new file mode 100644
index 00000000000..29e8609e567
--- /dev/null
+++ b/src/emu/sound/tms5220.h
@@ -0,0 +1,32 @@
+#ifndef tms5220_h
+#define tms5220_h
+
+void *tms5220_create(int index);
+void tms5220_destroy(void *chip);
+
+void tms5220_reset_chip(void *chip);
+void tms5220_set_irq(void *chip, void (*func)(int));
+
+void tms5220_data_write(void *chip, int data);
+int tms5220_status_read(void *chip);
+int tms5220_ready_read(void *chip);
+int tms5220_cycles_to_ready(void *chip);
+int tms5220_int_read(void *chip);
+
+void tms5220_process(void *chip, INT16 *buffer, unsigned int size);
+
+/* three variables added by R Nabet */
+void tms5220_set_read(void *chip, int (*func)(int));
+void tms5220_set_load_address(void *chip, void (*func)(int));
+void tms5220_set_read_and_branch(void *chip, void (*func)(void));
+
+typedef enum
+{
+ variant_tms5220,
+ variant_tms0285
+} tms5220_variant;
+
+void tms5220_set_variant(void *chip, tms5220_variant new_variant);
+
+#endif
+
diff --git a/src/emu/sound/tms5220.txt b/src/emu/sound/tms5220.txt
new file mode 100644
index 00000000000..d7a8b1a178c
--- /dev/null
+++ b/src/emu/sound/tms5220.txt
@@ -0,0 +1,86 @@
+*****************************
+
+ TI TMS5220 Emulator
+ (c) Frank Palazzolo
+ Updated by Raphael Nabet
+
+*****************************
+
+The TI TMS5220 Speech chip uses Linear-Predictive decoding scheme to produce
+speech from very compact data. This scheme is very similar to the U.S.
+Federal Standard LPC-10e coding system, which was developed soon after
+this chip.
+
+It is virtually identical to the chip used in the landmark "Speak 'N Spell"
+toy produced in the '70s.
+
+Acknowledgements:
+-----------------
+
+I would like to thank Larry Brantingham, the original designer of the chip,
+for his technical help.
+
+I would also like to thank Neill Cortlett, who first showed that this chip
+could be emulated in real-time in his Multi-Gauntlet Emulator.
+
+Theory of operation:
+--------------------
+
+The TI speech chip contains a 128-bit parallel-in, serial-out FIFO, a
+10-pole digital lattice filter which models the vocal tract, and a D/A
+converter. It was originally design to operate either with a microcomputer
+interface, or with a serial speech ROM. The Speech ROM functionality is
+now emulated, although no arcade games require it currently.
+
+The input data is writen a byte at a time into the chip, and it is
+decoded bitwise into variable length frames.
+
+Possible Frame Types are as follows:
+
+ Energy RF Pitch K1 K2 K3 K4 K5 K6 K7 K8 K9 K10
+ -----------------------------------------------------------------
+
+Silent 0000
+Stop 1111
+Repeat XXXX 1 XXXXXX
+Unvoiced XXXX 0 000000 XXXXX XXXXX XXXX XXXX
+Voiced XXXX 0 XXXXXX XXXXX XXXXX XXXX XXXX XXXX XXXX XXXX XXX XXX XXX
+
+Stop Frame: Stops the current speech
+Repeat Frame: Uses the digital filter coefficients from the previous frame,
+ with new Energy and Pitch values
+Unvoiced Frame: Uses Noise generator to feed 4 pole digital filter
+ (All other coefficients are set to zero)
+Voiced Frame: Uses Pulse Generator to feed 10 pole digital filter
+
+All parameters (Energy, Pitch, K1-K10) are indexes into a lookup table for
+actual values (see TMS5220R.c)
+
+K1-K10 are reflection coefficients for the lattice filter.
+
+Each frame is used to generate 200 samples, and 8 times during each frame,
+(every 25 samples), these values are linearly interpolated to smooth out
+frame transitions.
+
+The Noise generator is based on a shift-register type random-bit generator.
+The Pulse generator is based on a lookup table.
+
+API:
+----
+
+TBD
+
+More:
+-----
+
+For further technical info, the data sheet is floating around on the net.
+(I believe the name is TMS.PDF) If you can't find a copy, email me and
+I'll point you towards it. Feel free to contact me if you have a question.
+
+Frank Palazzolo
+
+palazzol@home.com
+
+
+
+
diff --git a/src/emu/sound/tms5220r.c b/src/emu/sound/tms5220r.c
new file mode 100644
index 00000000000..e373dd045ec
--- /dev/null
+++ b/src/emu/sound/tms5220r.c
@@ -0,0 +1,107 @@
+/* TMS5220 ROM Tables */
+
+/* This is the energy lookup table (4-bits -> 10-bits) */
+
+const static unsigned short energytable[0x10]={
+0x0000,0x00C0,0x0140,0x01C0,0x0280,0x0380,0x0500,0x0740,
+0x0A00,0x0E40,0x1440,0x1C80,0x2840,0x38C0,0x5040,0x7FC0};
+
+/* This is the pitch lookup table (6-bits -> 8-bits) */
+
+const static unsigned short pitchtable [0x40]={
+0x0000,0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,
+0x1700,0x1800,0x1900,0x1A00,0x1B00,0x1C00,0x1D00,0x1E00,
+0x1F00,0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,
+0x2700,0x2800,0x2900,0x2A00,0x2B00,0x2D00,0x2F00,0x3100,
+0x3300,0x3500,0x3600,0x3900,0x3B00,0x3D00,0x3F00,0x4200,
+0x4500,0x4700,0x4900,0x4D00,0x4F00,0x5100,0x5500,0x5700,
+0x5C00,0x5F00,0x6300,0x6600,0x6A00,0x6E00,0x7300,0x7700,
+0x7B00,0x8000,0x8500,0x8A00,0x8F00,0x9500,0x9A00,0xA000};
+
+/* These are the reflection coefficient lookup tables */
+
+/* K1 is (5-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k1table [0x20]={
+(short)0x82C0,(short)0x8380,(short)0x83C0,(short)0x8440,(short)0x84C0,(short)0x8540,(short)0x8600,(short)0x8780,
+(short)0x8880,(short)0x8980,(short)0x8AC0,(short)0x8C00,(short)0x8D40,(short)0x8F00,(short)0x90C0,(short)0x92C0,
+(short)0x9900,(short)0xA140,(short)0xAB80,(short)0xB840,(short)0xC740,(short)0xD8C0,(short)0xEBC0,0x0000,
+0x1440,0x2740,0x38C0,0x47C0,0x5480,0x5EC0,0x6700,0x6D40};
+
+/* K2 is (5-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k2table [0x20]={
+(short)0xAE00,(short)0xB480,(short)0xBB80,(short)0xC340,(short)0xCB80,(short)0xD440,(short)0xDDC0,(short)0xE780,
+(short)0xF180,(short)0xFBC0,0x0600,0x1040,0x1A40,0x2400,0x2D40,0x3600,
+0x3E40,0x45C0,0x4CC0,0x5300,0x5880,0x5DC0,0x6240,0x6640,
+0x69C0,0x6CC0,0x6F80,0x71C0,0x73C0,0x7580,0x7700,0x7E80};
+
+/* K3 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k3table [0x10]={
+(short)0x9200,(short)0x9F00,(short)0xAD00,(short)0xBA00,(short)0xC800,(short)0xD500,(short)0xE300,(short)0xF000,
+(short)0xFE00,0x0B00,0x1900,0x2600,0x3400,0x4100,0x4F00,0x5C00};
+
+/* K4 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k4table [0x10]={
+(short)0xAE00,(short)0xBC00,(short)0xCA00,(short)0xD800,(short)0xE600,(short)0xF400,0x0100,0x0F00,
+0x1D00,0x2B00,0x3900,0x4700,0x5500,0x6300,0x7100,0x7E00};
+
+/* K5 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k5table [0x10]={
+(short)0xAE00,(short)0xBA00,(short)0xC500,(short)0xD100,(short)0xDD00,(short)0xE800,(short)0xF400,(short)0xFF00,
+0x0B00,0x1700,0x2200,0x2E00,0x3900,0x4500,0x5100,0x5C00};
+
+/* K6 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k6table [0x10]={
+(short)0xC000,(short)0xCB00,(short)0xD600,(short)0xE100,(short)0xEC00,(short)0xF700,0x0300,0x0E00,
+0x1900,0x2400,0x2F00,0x3A00,0x4500,0x5000,0x5B00,0x6600};
+
+/* K7 is (4-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k7table [0x10]={
+(short)0xB300,(short)0xBF00,(short)0xCB00,(short)0xD700,(short)0xE300,(short)0xEF00,(short)0xFB00,0x0700,
+0x1300,0x1F00,0x2B00,0x3700,0x4300,0x4F00,0x5A00,0x6600};
+
+/* K8 is (3-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k8table [0x08]={
+(short)0xC000,(short)0xD800,(short)0xF000,0x0700,0x1F00,0x3700,0x4F00,0x6600};
+
+/* K9 is (3-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k9table [0x08]={
+(short)0xC000,(short)0xD400,(short)0xE800,(short)0xFC00,0x1000,0x2500,0x3900,0x4D00};
+
+/* K10 is (3-bits -> 9 bits+sign, 2's comp. fractional (-1 < x < 1) */
+
+const static short k10table [0x08]={
+(short)0xCD00,(short)0xDF00,(short)0xF100,0x0400,0x1600,0x2000,0x3B00,0x4D00};
+
+/* chirp table */
+
+static char chirptable[51]={
+0x00, 0x2a, (char)0xd4, 0x32,
+(char)0xb2, 0x12, 0x25, 0x14,
+0x02, (char)0xe1, (char)0xc5, 0x02,
+0x5f, 0x5a, 0x05, 0x0f,
+0x26, (char)0xfc, (char)0xa5, (char)0xa5,
+(char)0xd6, (char)0xdd, (char)0xdc, (char)0xfc,
+0x25, 0x2b, 0x22, 0x21,
+0x0f, (char)0xff, (char)0xf8, (char)0xee,
+(char)0xed, (char)0xef, (char)0xf7, (char)0xf6,
+(char)0xfa, 0x00, 0x03, 0x02,
+0x01, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00
+};
+
+/* interpolation coefficients (in rightshifts, as in actual chip) */
+
+static char interp_coeff[8] = {
+3, 3, 3, 2, 2, 1, 1, 0
+};
+
diff --git a/src/emu/sound/upd7759.c b/src/emu/sound/upd7759.c
new file mode 100644
index 00000000000..2748c647dfa
--- /dev/null
+++ b/src/emu/sound/upd7759.c
@@ -0,0 +1,801 @@
+/************************************************************
+
+ NEC UPD7759 ADPCM Speech Processor
+ by: Juergen Buchmueller, Mike Balfour, Howie Cohen,
+ Olivier Galibert, and Aaron Giles
+
+*************************************************************
+
+ Description:
+
+ The UPD7759 is a speech processing LSI that utilizes ADPCM to produce
+ speech or other sampled sounds. It can directly address up to 1Mbit
+ (128k) of external data ROM, or the host CPU can control the speech
+ data transfer. The UPD7759 is usually hooked up to a 640 kHz clock and
+ has one 8-bit input port, a start pin, a busy pin, and a clock output.
+
+ The chip is composed of 3 parts:
+ - a clock divider
+ - a rom-reading engine
+ - an adpcm engine
+ - a 4-to-9 bit adpcm converter
+
+ The clock divider takes the base 640KHz clock and divides it first
+ by a fixed divisor of 4 and then by a value between 9 and 32. The
+ result gives a clock between 5KHz and 17.78KHz. It's probably
+ possible, but not recommended and certainly out-of-spec, to push the
+ chip harder by reducing the divider.
+
+ The rom-reading engine reads one byte every two divided clock cycles.
+ The factor two comes from the fact that a byte has two nibbles, i.e.
+ two samples.
+
+ The apdcm engine takes bytes and interprets them as commands:
+
+ 00000000 sample end
+ 00dddddd silence
+ 01ffffff send the 256 following nibbles to the converter
+ 10ffffff nnnnnnnn send the n+1 following nibbles to the converter
+ 11---rrr --ffffff nnnnnnnn send the n+1 following nibbles to the converter, and repeat r+1 times
+
+ "ffffff" is sent to the clock divider to be the base clock for the
+ adpcm converter, i.e., it's the sampling rate. If the number of
+ nibbles to send is odd the last nibble is ignored. The commands
+ are always 8-bit aligned.
+
+ "dddddd" is the duration of the silence. The base speed is unknown,
+ 1ms sounds reasonably. It does not seem linked to the adpcm clock
+ speed because there often is a silence before any 01 or 10 command.
+
+ The adpcm converter converts nibbles into 9-bit DAC values. It has
+ an internal state of 4 bits that's used in conjunction with the
+ nibble to lookup which of the 256 possible steps is used. Then
+ the state is changed according to the nibble value. Essentially, the
+ higher the state, the bigger the steps are, and using big steps
+ increase the state. Conversely, using small steps reduces the state.
+ This allows the engine to be a little more adaptative than a
+ classical ADPCM algorithm.
+
+ The UPD7759 can run in two modes, master (also known as standalone)
+ and slave. The mode is selected through the "md" pin. No known
+ game changes modes on the fly, and it's unsure if that's even
+ possible to do.
+
+
+ Master mode:
+
+ The output of the rom reader is directly connected to the adpcm
+ converter. The controlling cpu only sends a sample number and the
+ 7759 plays it.
+
+ The sample rom has a header at the beginning of the form
+
+ nn 5a a5 69 55
+
+ where nn is the number of the last sample. This is then followed by
+ a vector of 2-bytes msb-first values, one per sample. Multiplying
+ them by two gives the sample start offset in the rom. A 0x00 marks
+ the end of each sample.
+
+ It seems that the UPD7759 reads at least part of the rom header at
+ startup. Games doing rom banking are careful to reset the chip after
+ each change.
+
+
+ Slave mode:
+
+ The rom reader is completely disconnected. The input port is
+ connected directly to the adpcm engine. The first write to the input
+ port activates the engine (the value itself is ignored). The engine
+ activates the clock output and waits for commands. The clock speed
+ is unknown, but its probably a divider of 640KHz. We use 40KHz here
+ because 80KHz crashes altbeast. The chip probably has an internal
+ fifo to the converter and suspends the clock when the fifo is full.
+ The first command is always 0xFF. A second 0xFF marks the end of the
+ sample and the engine stops. OTOH, there is a 0x00 at the end too.
+ Go figure.
+
+*************************************************************/
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "upd7759.h"
+
+
+#define DEBUG_STATES (0)
+#define DEBUG_METHOD mame_printf_debug
+
+
+
+/************************************************************
+
+ Constants
+
+*************************************************************/
+
+/* step value fractional bits */
+#define FRAC_BITS 20
+#define FRAC_ONE (1 << FRAC_BITS)
+#define FRAC_MASK (FRAC_ONE - 1)
+
+/* chip states */
+enum
+{
+ STATE_IDLE,
+ STATE_DROP_DRQ,
+ STATE_START,
+ STATE_FIRST_REQ,
+ STATE_LAST_SAMPLE,
+ STATE_DUMMY1,
+ STATE_ADDR_MSB,
+ STATE_ADDR_LSB,
+ STATE_DUMMY2,
+ STATE_BLOCK_HEADER,
+ STATE_NIBBLE_COUNT,
+ STATE_NIBBLE_MSN,
+ STATE_NIBBLE_LSN
+};
+
+
+
+/************************************************************
+
+ Type definitions
+
+*************************************************************/
+
+struct upd7759_chip
+{
+ sound_stream *channel; /* stream channel for playback */
+
+ /* internal clock to output sample rate mapping */
+ UINT32 pos; /* current output sample position */
+ UINT32 step; /* step value per output sample */
+ attotime clock_period; /* clock period */
+ emu_timer *timer; /* timer */
+
+ /* I/O lines */
+ UINT8 fifo_in; /* last data written to the sound chip */
+ UINT8 reset; /* current state of the RESET line */
+ UINT8 start; /* current state of the START line */
+ UINT8 drq; /* current state of the DRQ line */
+ void (*drqcallback)(int param); /* drq callback */
+
+ /* internal state machine */
+ INT8 state; /* current overall chip state */
+ INT32 clocks_left; /* number of clocks left in this state */
+ UINT16 nibbles_left; /* number of ADPCM nibbles left to process */
+ UINT8 repeat_count; /* number of repeats remaining in current repeat block */
+ INT8 post_drq_state; /* state we will be in after the DRQ line is dropped */
+ INT32 post_drq_clocks; /* clocks that will be left after the DRQ line is dropped */
+ UINT8 req_sample; /* requested sample number */
+ UINT8 last_sample; /* last sample number available */
+ UINT8 block_header; /* header byte */
+ UINT8 sample_rate; /* number of UPD clocks per ADPCM nibble */
+ UINT8 first_valid_header; /* did we get our first valid header yet? */
+ UINT32 offset; /* current ROM offset */
+ UINT32 repeat_offset; /* current ROM repeat offset */
+
+ /* ADPCM processing */
+ INT8 adpcm_state; /* ADPCM state index */
+ UINT8 adpcm_data; /* current byte of ADPCM data */
+ INT16 sample; /* current sample value */
+
+ /* ROM access */
+ UINT8 * rom; /* pointer to ROM data or NULL for slave mode */
+ UINT8 * rombase; /* pointer to ROM data or NULL for slave mode */
+ UINT32 romoffset; /* ROM offset to make save/restore easier */
+};
+
+
+
+/************************************************************
+
+ Local variables
+
+*************************************************************/
+
+const static int upd7759_step[16][16] =
+{
+ { 0, 0, 1, 2, 3, 5, 7, 10, 0, 0, -1, -2, -3, -5, -7, -10 },
+ { 0, 1, 2, 3, 4, 6, 8, 13, 0, -1, -2, -3, -4, -6, -8, -13 },
+ { 0, 1, 2, 4, 5, 7, 10, 15, 0, -1, -2, -4, -5, -7, -10, -15 },
+ { 0, 1, 3, 4, 6, 9, 13, 19, 0, -1, -3, -4, -6, -9, -13, -19 },
+ { 0, 2, 3, 5, 8, 11, 15, 23, 0, -2, -3, -5, -8, -11, -15, -23 },
+ { 0, 2, 4, 7, 10, 14, 19, 29, 0, -2, -4, -7, -10, -14, -19, -29 },
+ { 0, 3, 5, 8, 12, 16, 22, 33, 0, -3, -5, -8, -12, -16, -22, -33 },
+ { 1, 4, 7, 10, 15, 20, 29, 43, -1, -4, -7, -10, -15, -20, -29, -43 },
+ { 1, 4, 8, 13, 18, 25, 35, 53, -1, -4, -8, -13, -18, -25, -35, -53 },
+ { 1, 6, 10, 16, 22, 31, 43, 64, -1, -6, -10, -16, -22, -31, -43, -64 },
+ { 2, 7, 12, 19, 27, 37, 51, 76, -2, -7, -12, -19, -27, -37, -51, -76 },
+ { 2, 9, 16, 24, 34, 46, 64, 96, -2, -9, -16, -24, -34, -46, -64, -96 },
+ { 3, 11, 19, 29, 41, 57, 79, 117, -3, -11, -19, -29, -41, -57, -79, -117 },
+ { 4, 13, 24, 36, 50, 69, 96, 143, -4, -13, -24, -36, -50, -69, -96, -143 },
+ { 4, 16, 29, 44, 62, 85, 118, 175, -4, -16, -29, -44, -62, -85, -118, -175 },
+ { 6, 20, 36, 54, 76, 104, 144, 214, -6, -20, -36, -54, -76, -104, -144, -214 },
+};
+
+const static int upd7759_state[16] = { -1, -1, 0, 0, 1, 2, 2, 3, -1, -1, 0, 0, 1, 2, 2, 3 };
+
+
+
+/************************************************************
+
+ ADPCM sample updater
+
+*************************************************************/
+
+INLINE void update_adpcm(struct upd7759_chip *chip, int data)
+{
+ /* update the sample and the state */
+ chip->sample += upd7759_step[chip->adpcm_state][data];
+ chip->adpcm_state += upd7759_state[data];
+
+ /* clamp the state to 0..15 */
+ if (chip->adpcm_state < 0)
+ chip->adpcm_state = 0;
+ else if (chip->adpcm_state > 15)
+ chip->adpcm_state = 15;
+}
+
+
+
+/************************************************************
+
+ Master chip state machine
+
+*************************************************************/
+
+static void advance_state(struct upd7759_chip *chip)
+{
+ switch (chip->state)
+ {
+ /* Idle state: we stick around here while there's nothing to do */
+ case STATE_IDLE:
+ chip->clocks_left = 4;
+ break;
+
+ /* drop DRQ state: update to the intended state */
+ case STATE_DROP_DRQ:
+ chip->drq = 0;
+
+ chip->clocks_left = chip->post_drq_clocks;
+ chip->state = chip->post_drq_state;
+ break;
+
+ /* Start state: we begin here as soon as a sample is triggered */
+ case STATE_START:
+ chip->req_sample = chip->rom ? chip->fifo_in : 0x10;
+ if (DEBUG_STATES) DEBUG_METHOD("UPD7759: req_sample = %02X\n", chip->req_sample);
+
+ /* 35+ cycles after we get here, the /DRQ goes low
+ * (first byte (number of samples in ROM) should be sent in response)
+ *
+ * (35 is the minimum number of cycles I found during heavy tests.
+ * Depending on the state the chip was in just before the /MD was set to 0 (reset, standby
+ * or just-finished-playing-previous-sample) this number can range from 35 up to ~24000).
+ * It also varies slightly from test to test, but not much - a few cycles at most.) */
+ chip->clocks_left = 70; /* 35 - breaks cotton */
+ chip->state = STATE_FIRST_REQ;
+ break;
+
+ /* First request state: issue a request for the first byte */
+ /* The expected response will be the index of the last sample */
+ case STATE_FIRST_REQ:
+ if (DEBUG_STATES) DEBUG_METHOD("UPD7759: first data request\n");
+ chip->drq = 1;
+
+ /* 44 cycles later, we will latch this value and request another byte */
+ chip->clocks_left = 44;
+ chip->state = STATE_LAST_SAMPLE;
+ break;
+
+ /* Last sample state: latch the last sample value and issue a request for the second byte */
+ /* The second byte read will be just a dummy */
+ case STATE_LAST_SAMPLE:
+ chip->last_sample = chip->rom ? chip->rom[0] : chip->fifo_in;
+ if (DEBUG_STATES) DEBUG_METHOD("UPD7759: last_sample = %02X, requesting dummy 1\n", chip->last_sample);
+ chip->drq = 1;
+
+ /* 28 cycles later, we will latch this value and request another byte */
+ chip->clocks_left = 28; /* 28 - breaks cotton */
+ chip->state = (chip->req_sample > chip->last_sample) ? STATE_IDLE : STATE_DUMMY1;
+ break;
+
+ /* First dummy state: ignore any data here and issue a request for the third byte */
+ /* The expected response will be the MSB of the sample address */
+ case STATE_DUMMY1:
+ if (DEBUG_STATES) DEBUG_METHOD("UPD7759: dummy1, requesting offset_hi\n");
+ chip->drq = 1;
+
+ /* 32 cycles later, we will latch this value and request another byte */
+ chip->clocks_left = 32;
+ chip->state = STATE_ADDR_MSB;
+ break;
+
+ /* Address MSB state: latch the MSB of the sample address and issue a request for the fourth byte */
+ /* The expected response will be the LSB of the sample address */
+ case STATE_ADDR_MSB:
+ chip->offset = (chip->rom ? chip->rom[chip->req_sample * 2 + 5] : chip->fifo_in) << 9;
+ if (DEBUG_STATES) DEBUG_METHOD("UPD7759: offset_hi = %02X, requesting offset_lo\n", chip->offset >> 9);
+ chip->drq = 1;
+
+ /* 44 cycles later, we will latch this value and request another byte */
+ chip->clocks_left = 44;
+ chip->state = STATE_ADDR_LSB;
+ break;
+
+ /* Address LSB state: latch the LSB of the sample address and issue a request for the fifth byte */
+ /* The expected response will be just a dummy */
+ case STATE_ADDR_LSB:
+ chip->offset |= (chip->rom ? chip->rom[chip->req_sample * 2 + 6] : chip->fifo_in) << 1;
+ if (DEBUG_STATES) DEBUG_METHOD("UPD7759: offset_lo = %02X, requesting dummy 2\n", (chip->offset >> 1) & 0xff);
+ chip->drq = 1;
+
+ /* 36 cycles later, we will latch this value and request another byte */
+ chip->clocks_left = 36;
+ chip->state = STATE_DUMMY2;
+ break;
+
+ /* Second dummy state: ignore any data here and issue a request for the the sixth byte */
+ /* The expected response will be the first block header */
+ case STATE_DUMMY2:
+ chip->offset++;
+ chip->first_valid_header = 0;
+ if (DEBUG_STATES) DEBUG_METHOD("UPD7759: dummy2, requesting block header\n");
+ chip->drq = 1;
+
+ /* 36?? cycles later, we will latch this value and request another byte */
+ chip->clocks_left = 36;
+ chip->state = STATE_BLOCK_HEADER;
+ break;
+
+ /* Block header state: latch the header and issue a request for the first byte afterwards */
+ case STATE_BLOCK_HEADER:
+
+ /* if we're in a repeat loop, reset the offset to the repeat point and decrement the count */
+ if (chip->repeat_count)
+ {
+ chip->repeat_count--;
+ chip->offset = chip->repeat_offset;
+ }
+ chip->block_header = chip->rom ? chip->rom[chip->offset++ & 0x1ffff] : chip->fifo_in;
+ if (DEBUG_STATES) DEBUG_METHOD("UPD7759: header (@%05X) = %02X, requesting next byte\n", chip->offset, chip->block_header);
+ chip->drq = 1;
+
+ /* our next step depends on the top two bits */
+ switch (chip->block_header & 0xc0)
+ {
+ case 0x00: /* silence */
+ chip->clocks_left = 1024 * ((chip->block_header & 0x3f) + 1);
+ chip->state = (chip->block_header == 0 && chip->first_valid_header) ? STATE_IDLE : STATE_BLOCK_HEADER;
+ chip->sample = 0;
+ chip->adpcm_state = 0;
+ break;
+
+ case 0x40: /* 256 nibbles */
+ chip->sample_rate = (chip->block_header & 0x3f) + 1;
+ chip->nibbles_left = 256;
+ chip->clocks_left = 36; /* just a guess */
+ chip->state = STATE_NIBBLE_MSN;
+ break;
+
+ case 0x80: /* n nibbles */
+ chip->sample_rate = (chip->block_header & 0x3f) + 1;
+ chip->clocks_left = 36; /* just a guess */
+ chip->state = STATE_NIBBLE_COUNT;
+ break;
+
+ case 0xc0: /* repeat loop */
+ chip->repeat_count = (chip->block_header & 7) + 1;
+ chip->repeat_offset = chip->offset;
+ chip->clocks_left = 36; /* just a guess */
+ chip->state = STATE_BLOCK_HEADER;
+ break;
+ }
+
+ /* set a flag when we get the first non-zero header */
+ if (chip->block_header != 0)
+ chip->first_valid_header = 1;
+ break;
+
+ /* Nibble count state: latch the number of nibbles to play and request another byte */
+ /* The expected response will be the first data byte */
+ case STATE_NIBBLE_COUNT:
+ chip->nibbles_left = (chip->rom ? chip->rom[chip->offset++ & 0x1ffff] : chip->fifo_in) + 1;
+ if (DEBUG_STATES) DEBUG_METHOD("UPD7759: nibble_count = %u, requesting next byte\n", (unsigned)chip->nibbles_left);
+ chip->drq = 1;
+
+ /* 36?? cycles later, we will latch this value and request another byte */
+ chip->clocks_left = 36; /* just a guess */
+ chip->state = STATE_NIBBLE_MSN;
+ break;
+
+ /* MSN state: latch the data for this pair of samples and request another byte */
+ /* The expected response will be the next sample data or another header */
+ case STATE_NIBBLE_MSN:
+ chip->adpcm_data = chip->rom ? chip->rom[chip->offset++ & 0x1ffff] : chip->fifo_in;
+ update_adpcm(chip, chip->adpcm_data >> 4);
+ chip->drq = 1;
+
+ /* we stay in this state until the time for this sample is complete */
+ chip->clocks_left = chip->sample_rate * 4;
+ if (--chip->nibbles_left == 0)
+ chip->state = STATE_BLOCK_HEADER;
+ else
+ chip->state = STATE_NIBBLE_LSN;
+ break;
+
+ /* LSN state: process the lower nibble */
+ case STATE_NIBBLE_LSN:
+ update_adpcm(chip, chip->adpcm_data & 15);
+
+ /* we stay in this state until the time for this sample is complete */
+ chip->clocks_left = chip->sample_rate * 4;
+ if (--chip->nibbles_left == 0)
+ chip->state = STATE_BLOCK_HEADER;
+ else
+ chip->state = STATE_NIBBLE_MSN;
+ break;
+ }
+
+ /* if there's a DRQ, fudge the state */
+ if (chip->drq)
+ {
+ chip->post_drq_state = chip->state;
+ chip->post_drq_clocks = chip->clocks_left - 21;
+ chip->state = STATE_DROP_DRQ;
+ chip->clocks_left = 21;
+ }
+}
+
+
+
+/************************************************************
+
+ Stream callback
+
+*************************************************************/
+
+static void upd7759_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int samples)
+{
+ struct upd7759_chip *chip = param;
+ INT32 clocks_left = chip->clocks_left;
+ INT16 sample = chip->sample;
+ UINT32 step = chip->step;
+ UINT32 pos = chip->pos;
+ stream_sample_t *buffer = _buffer[0];
+
+ /* loop until done */
+ if (chip->state != STATE_IDLE)
+ while (samples != 0)
+ {
+ /* store the current sample */
+ *buffer++ = sample << 7;
+ samples--;
+
+ /* advance by the number of clocks/output sample */
+ pos += step;
+
+ /* handle clocks, but only in standalone mode */
+ while (chip->rom && pos >= FRAC_ONE)
+ {
+ int clocks_this_time = pos >> FRAC_BITS;
+ if (clocks_this_time > clocks_left)
+ clocks_this_time = clocks_left;
+
+ /* clock once */
+ pos -= clocks_this_time * FRAC_ONE;
+ clocks_left -= clocks_this_time;
+
+ /* if we're out of clocks, time to handle the next state */
+ if (clocks_left == 0)
+ {
+ /* advance one state; if we hit idle, bail */
+ advance_state(chip);
+ if (chip->state == STATE_IDLE)
+ break;
+
+ /* reimport the variables that we cached */
+ clocks_left = chip->clocks_left;
+ sample = chip->sample;
+ }
+ }
+ }
+
+ /* if we got out early, just zap the rest of the buffer */
+ if (samples != 0)
+ memset(buffer, 0, samples * sizeof(*buffer));
+
+ /* flush the state back */
+ chip->clocks_left = clocks_left;
+ chip->pos = pos;
+}
+
+
+
+/************************************************************
+
+ DRQ callback
+
+*************************************************************/
+
+static TIMER_CALLBACK_PTR( upd7759_slave_update )
+{
+ struct upd7759_chip *chip = param;
+ UINT8 olddrq = chip->drq;
+
+ /* update the stream */
+ stream_update(chip->channel);
+
+ /* advance the state */
+ advance_state(chip);
+
+ /* if the DRQ changed, update it */
+ logerror("slave_update: DRQ %d->%d\n", olddrq, chip->drq);
+ if (olddrq != chip->drq && chip->drqcallback)
+ (*chip->drqcallback)(chip->drq);
+
+ /* set a timer to go off when that is done */
+ if (chip->state != STATE_IDLE)
+ timer_adjust_ptr(chip->timer, attotime_mul(chip->clock_period, chip->clocks_left), attotime_zero);
+}
+
+
+
+/************************************************************
+
+ Sound startup
+
+*************************************************************/
+
+static void upd7759_reset(struct upd7759_chip *chip)
+{
+ chip->pos = 0;
+ chip->fifo_in = 0;
+ chip->drq = 0;
+ chip->state = STATE_IDLE;
+ chip->clocks_left = 0;
+ chip->nibbles_left = 0;
+ chip->repeat_count = 0;
+ chip->post_drq_state = STATE_IDLE;
+ chip->post_drq_clocks = 0;
+ chip->req_sample = 0;
+ chip->last_sample = 0;
+ chip->block_header = 0;
+ chip->sample_rate = 0;
+ chip->first_valid_header = 0;
+ chip->offset = 0;
+ chip->repeat_offset = 0;
+ chip->adpcm_state = 0;
+ chip->adpcm_data = 0;
+ chip->sample = 0;
+
+ /* turn off any timer */
+ if (chip->timer)
+ timer_adjust_ptr(chip->timer, attotime_never, attotime_zero);
+}
+
+
+static void upd7759_postload(void *param)
+{
+ struct upd7759_chip *chip = (struct upd7759_chip *)param;
+ chip->rom = chip->rombase + chip->romoffset;
+}
+
+
+static void register_for_save(struct upd7759_chip *chip, int index)
+{
+ state_save_register_item("upd7759", index, chip->pos);
+ state_save_register_item("upd7759", index, chip->step);
+
+ state_save_register_item("upd7759", index, chip->fifo_in);
+ state_save_register_item("upd7759", index, chip->reset);
+ state_save_register_item("upd7759", index, chip->start);
+ state_save_register_item("upd7759", index, chip->drq);
+
+ state_save_register_item("upd7759", index, chip->state);
+ state_save_register_item("upd7759", index, chip->clocks_left);
+ state_save_register_item("upd7759", index, chip->nibbles_left);
+ state_save_register_item("upd7759", index, chip->repeat_count);
+ state_save_register_item("upd7759", index, chip->post_drq_state);
+ state_save_register_item("upd7759", index, chip->post_drq_clocks);
+ state_save_register_item("upd7759", index, chip->req_sample);
+ state_save_register_item("upd7759", index, chip->last_sample);
+ state_save_register_item("upd7759", index, chip->block_header);
+ state_save_register_item("upd7759", index, chip->sample_rate);
+ state_save_register_item("upd7759", index, chip->first_valid_header);
+ state_save_register_item("upd7759", index, chip->offset);
+ state_save_register_item("upd7759", index, chip->repeat_offset);
+
+ state_save_register_item("upd7759", index, chip->adpcm_state);
+ state_save_register_item("upd7759", index, chip->adpcm_data);
+ state_save_register_item("upd7759", index, chip->sample);
+
+ state_save_register_item("upd7759", index, chip->romoffset);
+ state_save_register_func_postload_ptr(upd7759_postload, chip);
+}
+
+
+static void *upd7759_start(int sndindex, int clock, const void *config)
+{
+ const struct upd7759_interface *intf = config;
+ struct upd7759_chip *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ /* allocate a stream channel */
+ chip->channel = stream_create(0, 1, clock/4, chip, upd7759_update);
+
+ /* compute the stepping rate based on the chip's clock speed */
+ chip->step = 4 * FRAC_ONE;
+
+ /* compute the clock period */
+ chip->clock_period = ATTOTIME_IN_HZ(clock);
+
+ /* set the intial state */
+ chip->state = STATE_IDLE;
+
+ /* compute the ROM base or allocate a timer */
+ if (intf->region != 0)
+ chip->rom = chip->rombase = memory_region(intf->region);
+ else
+ chip->timer = timer_alloc_ptr(upd7759_slave_update, chip);
+
+ /* set the DRQ callback */
+ chip->drqcallback = intf->drqcallback;
+
+ /* assume /RESET and /START are both high */
+ chip->reset = 1;
+ chip->start = 1;
+
+ /* toggle the reset line to finish the reset */
+ upd7759_reset(chip);
+
+ register_for_save(chip, sndindex);
+
+ return chip;
+}
+
+
+
+/************************************************************
+
+ I/O handlers
+
+*************************************************************/
+
+void upd7759_reset_w(int which, UINT8 data)
+{
+ /* update the reset value */
+ struct upd7759_chip *chip = sndti_token(SOUND_UPD7759, which);
+ UINT8 oldreset = chip->reset;
+ chip->reset = (data != 0);
+
+ /* update the stream first */
+ stream_update(chip->channel);
+
+ /* on the falling edge, reset everything */
+ if (oldreset && !chip->reset)
+ upd7759_reset(chip);
+}
+
+void upd7759_start_w(int which, UINT8 data)
+{
+ /* update the start value */
+ struct upd7759_chip *chip = sndti_token(SOUND_UPD7759, which);
+ UINT8 oldstart = chip->start;
+ chip->start = (data != 0);
+
+ logerror("upd7759_start_w: %d->%d\n", oldstart, chip->start);
+
+ /* update the stream first */
+ stream_update(chip->channel);
+
+ /* on the rising edge, if we're idle, start going, but not if we're held in reset */
+ if (chip->state == STATE_IDLE && !oldstart && chip->start && chip->reset)
+ {
+ chip->state = STATE_START;
+
+ /* for slave mode, start the timer going */
+ if (chip->timer)
+ timer_adjust_ptr(chip->timer, attotime_zero, attotime_zero);
+ }
+}
+
+
+void upd7759_port_w(int which, UINT8 data)
+{
+ /* update the FIFO value */
+ struct upd7759_chip *chip = sndti_token(SOUND_UPD7759, which);
+ chip->fifo_in = data;
+}
+
+
+int upd7759_busy_r(int which)
+{
+ /* return /BUSY */
+ struct upd7759_chip *chip = sndti_token(SOUND_UPD7759, which);
+ return (chip->state == STATE_IDLE);
+}
+
+
+void upd7759_set_bank_base(int which, UINT32 base)
+{
+ struct upd7759_chip *chip = sndti_token(SOUND_UPD7759, which);
+ chip->rom = chip->rombase + base;
+ chip->romoffset = base;
+}
+
+
+
+/************************************************************
+
+ Convenience handlers
+
+*************************************************************/
+
+WRITE8_HANDLER(upd7759_0_start_w)
+{
+ upd7759_start_w(0,data);
+}
+
+
+WRITE8_HANDLER(upd7759_0_reset_w)
+{
+ upd7759_reset_w(0,data);
+}
+
+
+WRITE8_HANDLER(upd7759_0_port_w)
+{
+ upd7759_port_w(0,data);
+}
+
+
+READ8_HANDLER(upd7759_0_busy_r)
+{
+ return upd7759_busy_r(0);
+}
+
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void upd7759_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void upd7759_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = upd7759_set_info; break;
+ case SNDINFO_PTR_START: info->start = upd7759_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "UPD7759"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "NEC ADPCM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/upd7759.h b/src/emu/sound/upd7759.h
new file mode 100644
index 00000000000..1471f6c2681
--- /dev/null
+++ b/src/emu/sound/upd7759.h
@@ -0,0 +1,31 @@
+#ifndef UPD7759S_H
+#define UPD7759S_H
+
+/* There are two modes for the uPD7759, selected through the !MD pin.
+ This is the mode select input. High is stand alone, low is slave.
+ We're making the assumption that nobody switches modes through
+ software. */
+
+#define UPD7759_STANDARD_CLOCK 640000
+
+struct upd7759_interface
+{
+ int region; /* memory region (per chip, standalone mode only) */
+ void (*drqcallback)(int param); /* drq callback (per chip, slave mode only) */
+};
+
+void upd7759_set_bank_base(int which, offs_t base);
+
+void upd7759_reset_w(int num, UINT8 data);
+
+void upd7759_port_w(int num, UINT8 data);
+void upd7759_start_w(int num, UINT8 data);
+int upd7759_busy_r(int num);
+
+WRITE8_HANDLER( upd7759_0_reset_w );
+WRITE8_HANDLER( upd7759_0_port_w );
+WRITE8_HANDLER( upd7759_0_start_w );
+READ8_HANDLER( upd7759_0_busy_r );
+
+#endif
+
diff --git a/src/emu/sound/vlm5030.c b/src/emu/sound/vlm5030.c
new file mode 100644
index 00000000000..9d1ea3eef1e
--- /dev/null
+++ b/src/emu/sound/vlm5030.c
@@ -0,0 +1,721 @@
+/*
+ vlm5030.c
+
+ VLM5030 emulator
+
+ Written by Tatsuyuki Satoh
+ Based on TMS5220 simulator (tms5220.c)
+
+ note:
+ memory read cycle(==sampling rate) = 122.9u(440clock)
+ interpolator (LC8109 = 2.5ms) = 20 * samples(125us)
+ frame time (20ms) = 4 * interpolator
+ 9bit DAC is composed of 5bit Physical and 3bitPWM.
+
+ todo:
+ Noise Generator circuit without 'mame_rand()' function.
+
+----------- command format (Analytical result) ----------
+
+1)end of speech (8bit)
+:00000011:
+
+2)silent some frame (8bit)
+:????SS01:
+
+SS : number of silent frames
+ 00 = 2 frame
+ 01 = 4 frame
+ 10 = 6 frame
+ 11 = 8 frame
+
+3)-speech frame (48bit)
+function: 6th : 5th : 4th : 3rd : 2nd : 1st :
+end : --- : --- : --- : --- : --- :00000011:
+silent : --- : --- : --- : --- : --- :0000SS01:
+speech :11111122:22233334:44455566:67778889:99AAAEEE:EEPPPPP0:
+
+EEEEE : energy : volume 0=off,0x1f=max
+PPPPP : pitch : 0=noize , 1=fast,0x1f=slow
+111111 : K1 : 48=off
+22222 : K2 : 0=off,1=+min,0x0f=+max,0x10=off,0x11=+max,0x1f=-min
+ : 16 == special function??
+3333 : K3 : 0=off,1=+min,0x07=+max,0x08=-max,0x0f=-min
+4444 : K4 :
+555 : K5 : 0=off,1=+min,0x03=+max,0x04=-max,0x07=-min
+666 : K6 :
+777 : K7 :
+888 : K8 :
+999 : K9 :
+AAA : K10 :
+
+ ---------- chirp table information ----------
+
+DAC PWM cycle == 88system clock , (11clock x 8 pattern) = 40.6KHz
+one chirp == 5 x PWM cycle == 440systemclock(8,136Hz)
+
+chirp 0 : volume 10- 8 : with filter
+chirp 1 : volume 8- 6 : with filter
+chirp 2 : volume 6- 4 : with filter
+chirp 3 : volume 4 : no filter ??
+chirp 4- 5: volume 4- 2 : with filter
+chirp 6-11: volume 2- 0 : with filter
+chirp 12-..: vokume 0 : silent
+
+ ---------- digial output information ----------
+ when ME pin = high , some status output to A0..15 pins
+
+ A0..8 : DAC output value (abs)
+ A9 : DAC sign flag , L=minus,H=Plus
+ A10 : energy reload flag (pitch pulse)
+ A11..15 : unknown
+
+ [DAC output value(signed 6bit)] = A9 ? A0..8 : -(A0..8)
+
+*/
+#include "sndintrf.h"
+#include "streams.h"
+#include "vlm5030.h"
+
+/* interpolator per frame */
+#define FR_SIZE 4
+/* samples per interpolator */
+#define IP_SIZE_SLOWER (240/FR_SIZE)
+#define IP_SIZE_SLOW (200/FR_SIZE)
+#define IP_SIZE_NORMAL (160/FR_SIZE)
+#define IP_SIZE_FAST (120/FR_SIZE)
+#define IP_SIZE_FASTER ( 80/FR_SIZE)
+
+struct vlm5030_info
+{
+ const struct VLM5030interface *intf;
+
+ sound_stream * channel;
+
+ /* need to save state */
+
+ UINT8 *rom;
+ int address_mask;
+ UINT16 address;
+ UINT8 pin_BSY;
+ UINT8 pin_ST;
+ UINT8 pin_VCU;
+ UINT8 pin_RST;
+ UINT8 latch_data;
+ UINT16 vcu_addr_h;
+ UINT8 parameter;
+ UINT8 phase;
+
+ /* state of option paramter */
+ int frame_size;
+ int pitch_offset;
+ UINT8 interp_step;
+
+ UINT8 interp_count; /* number of interp periods */
+ UINT8 sample_count; /* sample number within interp */
+ UINT8 pitch_count;
+
+ /* these contain data describing the current and previous voice frames */
+ UINT16 old_energy;
+ UINT8 old_pitch;
+ INT16 old_k[10];
+ UINT16 target_energy;
+ UINT8 target_pitch;
+ INT16 target_k[10];
+
+ UINT16 new_energy;
+ UINT8 new_pitch;
+ INT16 new_k[10];
+
+ /* these are all used to contain the current state of the sound generation */
+ unsigned int current_energy;
+ unsigned int current_pitch;
+ int current_k[10];
+
+ INT32 x[10];
+};
+
+/* phase value */
+enum {
+ PH_RESET,
+ PH_IDLE,
+ PH_SETUP,
+ PH_WAIT,
+ PH_RUN,
+ PH_STOP,
+ PH_END
+};
+
+/*
+ speed parameter
+SPC SPB SPA
+ 1 0 1 more slow (05h) : 42ms (150%) : 60sample
+ 1 1 x slow (06h,07h) : 34ms (125%) : 50sample
+ x 0 0 normal (00h,04h) : 25.6ms (100%) : 40samplme
+ 0 0 1 fast (01h) : 20.2ms (75%) : 30sample
+ 0 1 x more fast (02h,03h) : 12.2ms (50%) : 20sample
+*/
+static const int VLM5030_speed_table[8] =
+{
+ IP_SIZE_NORMAL,
+ IP_SIZE_FAST,
+ IP_SIZE_FASTER,
+ IP_SIZE_FASTER,
+ IP_SIZE_NORMAL,
+ IP_SIZE_SLOWER,
+ IP_SIZE_SLOW,
+ IP_SIZE_SLOW
+};
+
+static const char VLM_NAME[] = "VLM5030";
+
+/* ROM Tables */
+
+/* This is the energy lookup table */
+
+/* sampled from real chip */
+static unsigned short energytable[0x20] =
+{
+ 0, 2, 4, 6, 10, 12, 14, 18, /* 0-7 */
+ 22, 26, 30, 34, 38, 44, 48, 54, /* 8-15 */
+ 62, 68, 76, 84, 94,102,114,124, /* 16-23 */
+ 136,150,164,178,196,214,232,254 /* 24-31 */
+};
+
+/* This is the pitch lookup table */
+static const unsigned char pitchtable [0x20]=
+{
+ 1, /* 0 : random mode */
+ 22, /* 1 : start=22 */
+ 23, 24, 25, 26, 27, 28, 29, 30, /* 2- 9 : 1step */
+ 32, 34, 36, 38, 40, 42, 44, 46, /* 10-17 : 2step */
+ 50, 54, 58, 62, 66, 70, 74, 78, /* 18-25 : 4step */
+ 86, 94, 102,110,118,126 /* 26-31 : 8step */
+};
+
+static const INT16 K1_table[] = {
+ -24898, -25672, -26446, -27091, -27736, -28252, -28768, -29155,
+ -29542, -29929, -30316, -30574, -30832, -30961, -31219, -31348,
+ -31606, -31735, -31864, -31864, -31993, -32122, -32122, -32251,
+ -32251, -32380, -32380, -32380, -32509, -32509, -32509, -32509,
+ 24898, 23995, 22963, 21931, 20770, 19480, 18061, 16642,
+ 15093, 13416, 11610, 9804, 7998, 6063, 3999, 1935,
+ 0, -1935, -3999, -6063, -7998, -9804, -11610, -13416,
+ -15093, -16642, -18061, -19480, -20770, -21931, -22963, -23995
+};
+static const INT16 K2_table[] = {
+ 0, -3096, -6321, -9417, -12513, -15351, -18061, -20770,
+ -23092, -25285, -27220, -28897, -30187, -31348, -32122, -32638,
+ 0, 32638, 32122, 31348, 30187, 28897, 27220, 25285,
+ 23092, 20770, 18061, 15351, 12513, 9417, 6321, 3096
+};
+static const INT16 K3_table[] = {
+ 0, -3999, -8127, -12255, -16384, -20383, -24511, -28639,
+ 32638, 28639, 24511, 20383, 16254, 12255, 8127, 3999
+};
+static const INT16 K5_table[] = {
+ 0, -8127, -16384, -24511, 32638, 24511, 16254, 8127
+};
+
+static int get_bits(struct vlm5030_info *chip, int sbit,int bits)
+{
+ int offset = chip->address + (sbit>>3);
+ int data;
+
+ data = chip->rom[offset&chip->address_mask] +
+ (((int)chip->rom[(offset+1)&chip->address_mask])*256);
+ data >>= (sbit&7);
+ data &= (0xff>>(8-bits));
+
+ return data;
+}
+
+/* get next frame */
+static int parse_frame (struct vlm5030_info *chip)
+{
+ unsigned char cmd;
+ int i;
+
+ /* remember previous frame */
+ chip->old_energy = chip->new_energy;
+ chip->old_pitch = chip->new_pitch;
+ for(i=0;i<=9;i++)
+ chip->old_k[i] = chip->new_k[i];
+
+ /* command byte check */
+ cmd = chip->rom[chip->address&chip->address_mask];
+ if( cmd & 0x01 )
+ { /* extend frame */
+ chip->new_energy = chip->new_pitch = 0;
+ for(i=0;i<=9;i++)
+ chip->new_k[i] = 0;
+ chip->address++;
+ if( cmd & 0x02 )
+ { /* end of speech */
+
+ /* logerror("VLM5030 %04X end \n",chip->address ); */
+ return 0;
+ }
+ else
+ { /* silent frame */
+ int nums = ( (cmd>>2)+1 )*2;
+ /* logerror("VLM5030 %04X silent %d frame\n",chip->address,nums ); */
+ return nums * FR_SIZE;
+ }
+ }
+ /* pitch */
+ chip->new_pitch = ( pitchtable[get_bits(chip, 1,5)] + chip->pitch_offset )&0xff;
+ /* energy */
+ chip->new_energy = energytable[get_bits(chip, 6,5)];
+
+ /* 10 K's */
+ chip->new_k[9] = K5_table[get_bits(chip,11,3)];
+ chip->new_k[8] = K5_table[get_bits(chip,14,3)];
+ chip->new_k[7] = K5_table[get_bits(chip,17,3)];
+ chip->new_k[6] = K5_table[get_bits(chip,20,3)];
+ chip->new_k[5] = K5_table[get_bits(chip,23,3)];
+ chip->new_k[4] = K5_table[get_bits(chip,26,3)];
+ chip->new_k[3] = K3_table[get_bits(chip,29,4)];
+ chip->new_k[2] = K3_table[get_bits(chip,33,4)];
+ chip->new_k[1] = K2_table[get_bits(chip,37,5)];
+ chip->new_k[0] = K1_table[get_bits(chip,42,6)];
+
+ chip->address+=6;
+ logerror("VLM5030 %04X voice \n",chip->address );
+ return FR_SIZE;
+}
+
+/* decode and buffering data */
+static void vlm5030_update_callback(void *param,stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct vlm5030_info *chip = param;
+ int buf_count=0;
+ int interp_effect;
+ int i;
+ int u[11];
+ stream_sample_t *buffer = _buffer[0];
+
+ /* running */
+ if( chip->phase == PH_RUN || chip->phase == PH_STOP )
+ {
+ /* playing speech */
+ while (length > 0)
+ {
+ int current_val;
+
+ /* check new interpolator or new frame */
+ if( chip->sample_count == 0 )
+ {
+ if( chip->phase == PH_STOP )
+ {
+ chip->phase = PH_END;
+ chip->sample_count = 1;
+ goto phase_stop; /* continue to end phase */
+ }
+ chip->sample_count = chip->frame_size;
+ /* interpolator changes */
+ if ( chip->interp_count == 0 )
+ {
+ /* change to new frame */
+ chip->interp_count = parse_frame(chip); /* with change phase */
+ if ( chip->interp_count == 0 )
+ { /* end mark found */
+ chip->interp_count = FR_SIZE;
+ chip->sample_count = chip->frame_size; /* end -> stop time */
+ chip->phase = PH_STOP;
+ }
+ /* Set old target as new start of frame */
+ chip->current_energy = chip->old_energy;
+ chip->current_pitch = chip->old_pitch;
+ for(i=0;i<=9;i++)
+ chip->current_k[i] = chip->old_k[i];
+ /* is this a zero energy frame? */
+ if (chip->current_energy == 0)
+ {
+ /*mame_printf_debug("processing frame: zero energy\n");*/
+ chip->target_energy = 0;
+ chip->target_pitch = chip->current_pitch;
+ for(i=0;i<=9;i++)
+ chip->target_k[i] = chip->current_k[i];
+ }
+ else
+ {
+ /*mame_printf_debug("processing frame: Normal\n");*/
+ /*mame_printf_debug("*** Energy = %d\n",chip->current_energy);*/
+ /*mame_printf_debug("proc: %d %d\n",last_fbuf_head,fbuf_head);*/
+ chip->target_energy = chip->new_energy;
+ chip->target_pitch = chip->new_pitch;
+ for(i=0;i<=9;i++)
+ chip->target_k[i] = chip->new_k[i];
+ }
+ }
+ /* next interpolator */
+ /* Update values based on step values 25% , 50% , 75% , 100% */
+ chip->interp_count -= chip->interp_step;
+ /* 3,2,1,0 -> 1,2,3,4 */
+ interp_effect = FR_SIZE - (chip->interp_count%FR_SIZE);
+ chip->current_energy = chip->old_energy + (chip->target_energy - chip->old_energy) * interp_effect / FR_SIZE;
+ if (chip->old_pitch > 1)
+ chip->current_pitch = chip->old_pitch + (chip->target_pitch - chip->old_pitch) * interp_effect / FR_SIZE;
+ for (i = 0; i <= 9 ; i++)
+ chip->current_k[i] = chip->old_k[i] + (chip->target_k[i] - chip->old_k[i]) * interp_effect / FR_SIZE;
+ }
+ /* calcrate digital filter */
+ if (chip->old_energy == 0)
+ {
+ /* generate silent samples here */
+ current_val = 0x00;
+ }
+ else if (chip->old_pitch <= 1)
+ { /* generate unvoiced samples here */
+ current_val = (mame_rand(Machine)&1) ? chip->current_energy : -chip->current_energy;
+ }
+ else
+ {
+ /* generate voiced samples here */
+ current_val = ( chip->pitch_count == 0) ? chip->current_energy : 0;
+ }
+
+ /* Lattice filter here */
+ u[10] = current_val;
+ for (i = 9; i >= 0; i--)
+ u[i] = u[i+1] - ((chip->current_k[i] * chip->x[i]) / 32768);
+ for (i = 9; i >= 1; i--)
+ chip->x[i] = chip->x[i-1] + ((chip->current_k[i-1] * u[i-1]) / 32768);
+ chip->x[0] = u[0];
+
+ /* clipping, buffering */
+ if (u[0] > 511)
+ buffer[buf_count] = 511<<6;
+ else if (u[0] < -511)
+ buffer[buf_count] = -511<<6;
+ else
+ buffer[buf_count] = (u[0] << 6);
+ buf_count++;
+
+ /* sample count */
+ chip->sample_count--;
+ /* pitch */
+ chip->pitch_count++;
+ if (chip->pitch_count >= chip->current_pitch )
+ chip->pitch_count = 0;
+ /* size */
+ length--;
+ }
+/* return;*/
+ }
+ /* stop phase */
+phase_stop:
+ switch( chip->phase )
+ {
+ case PH_SETUP:
+ if( chip->sample_count <= length)
+ {
+ chip->sample_count = 0;
+ /* logerror("VLM5030 BSY=H\n" ); */
+ /* pin_BSY = 1; */
+ chip->phase = PH_WAIT;
+ }
+ else
+ {
+ chip->sample_count -= length;
+ }
+ break;
+ case PH_END:
+ if( chip->sample_count <= length)
+ {
+ chip->sample_count = 0;
+ /* logerror("VLM5030 BSY=L\n" ); */
+ chip->pin_BSY = 0;
+ chip->phase = PH_IDLE;
+ }
+ else
+ {
+ chip->sample_count -= length;
+ }
+ }
+ /* silent buffering */
+ while (length > 0)
+ {
+ buffer[buf_count++] = 0x00;
+ length--;
+ }
+}
+
+/* realtime update */
+static void VLM5030_update(struct vlm5030_info *chip)
+{
+ stream_update(chip->channel);
+}
+
+/* setup parameteroption when RST=H */
+static void VLM5030_setup_parameter(struct vlm5030_info *chip, UINT8 param)
+{
+ /* latch parameter value */
+ chip->parameter = param;
+
+ /* bit 0,1 : 4800bps / 9600bps , interporator step */
+ if(param&2) /* bit 1 = 1 , 9600bps */
+ chip->interp_step = 4; /* 9600bps : no interporator */
+ else if(param&1) /* bit1 = 0 & bit0 = 1 , 4800bps */
+ chip->interp_step = 2; /* 4800bps : 2 interporator */
+ else /* bit1 = bit0 = 0 : 2400bps */
+ chip->interp_step = 1; /* 2400bps : 4 interporator */
+
+ /* bit 3,4,5 : speed (frame size) */
+ chip->frame_size = VLM5030_speed_table[(param>>3) &7];
+
+ /* bit 6,7 : low / high pitch */
+ if(param&0x80) /* bit7=1 , high pitch */
+ chip->pitch_offset = -8;
+ else if(param&0x40) /* bit6=1 , low pitch */
+ chip->pitch_offset = 8;
+ else
+ chip->pitch_offset = 0;
+}
+
+
+static void VLM5030_restore_state(void *param)
+{
+ struct vlm5030_info *chip = param;
+ int i;
+
+ int interp_effect = FR_SIZE - (chip->interp_count%FR_SIZE);
+ /* restore parameter data */
+ VLM5030_setup_parameter(chip, chip->parameter);
+
+ /* restore current energy,pitch & filter */
+ chip->current_energy = chip->old_energy + (chip->target_energy - chip->old_energy) * interp_effect / FR_SIZE;
+ if (chip->old_pitch > 1)
+ chip->current_pitch = chip->old_pitch + (chip->target_pitch - chip->old_pitch) * interp_effect / FR_SIZE;
+ for (i = 0; i <= 9 ; i++)
+ chip->current_k[i] = chip->old_k[i] + (chip->target_k[i] - chip->old_k[i]) * interp_effect / FR_SIZE;
+}
+
+
+static void VLM5030_reset(struct vlm5030_info *chip)
+{
+ chip->phase = PH_RESET;
+ chip->address = 0;
+ chip->vcu_addr_h = 0;
+ chip->pin_BSY = 0;
+
+ chip->old_energy = chip->old_pitch = 0;
+ chip->new_energy = chip->new_pitch = 0;
+ chip->current_energy = chip->current_pitch = 0;
+ chip->target_energy = chip->target_pitch = 0;
+ memset(chip->old_k, 0, sizeof(chip->old_k));
+ memset(chip->new_k, 0, sizeof(chip->new_k));
+ memset(chip->current_k, 0, sizeof(chip->current_k));
+ memset(chip->target_k, 0, sizeof(chip->target_k));
+ chip->interp_count = chip->sample_count = chip->pitch_count = 0;
+ memset(chip->x, 0, sizeof(chip->x));
+ /* reset parameters */
+ VLM5030_setup_parameter(chip, 0x00);
+}
+
+/* set speech rom address */
+void VLM5030_set_rom(void *speech_rom)
+{
+ struct vlm5030_info *chip = sndti_token(SOUND_VLM5030, 0);
+ chip->rom = (UINT8 *)speech_rom;
+}
+
+/* get BSY pin level */
+int VLM5030_BSY(void)
+{
+ struct vlm5030_info *chip = sndti_token(SOUND_VLM5030, 0);
+ VLM5030_update(chip);
+ return chip->pin_BSY;
+}
+
+/* latch contoll data */
+WRITE8_HANDLER( VLM5030_data_w )
+{
+ struct vlm5030_info *chip = sndti_token(SOUND_VLM5030, 0);
+ chip->latch_data = (UINT8)data;
+}
+
+/* set RST pin level : reset / set table address A8-A15 */
+void VLM5030_RST (int pin )
+{
+ struct vlm5030_info *chip = sndti_token(SOUND_VLM5030, 0);
+ if( chip->pin_RST )
+ {
+ if( !pin )
+ { /* H -> L : latch parameters */
+ chip->pin_RST = 0;
+ VLM5030_setup_parameter(chip, chip->latch_data);
+ }
+ }
+ else
+ {
+ if( pin )
+ { /* L -> H : reset chip */
+ chip->pin_RST = 1;
+ if( chip->pin_BSY )
+ {
+ VLM5030_reset(chip);
+ }
+ }
+ }
+}
+
+/* set VCU pin level : ?? unknown */
+void VLM5030_VCU(int pin)
+{
+ struct vlm5030_info *chip = sndti_token(SOUND_VLM5030, 0);
+ /* direct mode / indirect mode */
+ chip->pin_VCU = pin;
+ return;
+}
+
+/* set ST pin level : set table address A0-A7 / start speech */
+void VLM5030_ST(int pin )
+{
+ struct vlm5030_info *chip = sndti_token(SOUND_VLM5030, 0);
+ int table;
+
+ if( chip->pin_ST != pin )
+ {
+ /* pin level is change */
+ if( !pin )
+ { /* H -> L */
+ chip->pin_ST = 0;
+
+ if( chip->pin_VCU )
+ { /* direct access mode & address High */
+ chip->vcu_addr_h = ((int)chip->latch_data<<8) + 0x01;
+ }
+ else
+ {
+ /* start speech */
+ /* check access mode */
+ if( chip->vcu_addr_h )
+ { /* direct access mode */
+ chip->address = (chip->vcu_addr_h&0xff00) + chip->latch_data;
+ chip->vcu_addr_h = 0;
+ }
+ else
+ { /* indirect accedd mode */
+ table = (chip->latch_data&0xfe) + (((int)chip->latch_data&1)<<8);
+ chip->address = (((int)chip->rom[table&chip->address_mask])<<8)
+ | chip->rom[(table+1)&chip->address_mask];
+#if 0
+/* show unsupported parameter message */
+if( chip->interp_step != 1)
+ popmessage("No %d %dBPS parameter",table/2,chip->interp_step*2400);
+#endif
+ }
+ VLM5030_update(chip);
+ /* logerror("VLM5030 %02X start adr=%04X\n",table/2,chip->address ); */
+ /* reset process status */
+ chip->sample_count = chip->frame_size;
+ chip->interp_count = FR_SIZE;
+ /* clear filter */
+ /* start after 3 sampling cycle */
+ chip->phase = PH_RUN;
+ }
+ }
+ else
+ { /* L -> H */
+ chip->pin_ST = 1;
+ /* setup speech , BSY on after 30ms? */
+ chip->phase = PH_SETUP;
+ chip->sample_count = 1; /* wait time for busy on */
+ chip->pin_BSY = 1; /* */
+ }
+ }
+}
+
+/* start VLM5030 with sound rom */
+/* speech_rom == 0 -> use sampling data mode */
+static void *vlm5030_start(int sndindex, int clock, const void *config)
+{
+ int emulation_rate;
+ struct vlm5030_info *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ chip->intf = config;
+
+ emulation_rate = clock / 440;
+
+ /* reset input pins */
+ chip->pin_RST = chip->pin_ST = chip->pin_VCU= 0;
+ chip->latch_data = 0;
+
+ VLM5030_reset(chip);
+ chip->phase = PH_IDLE;
+
+ chip->rom = memory_region(chip->intf->memory_region);
+ /* memory size */
+ if( chip->intf->memory_size == 0)
+ chip->address_mask = memory_region_length(chip->intf->memory_region)-1;
+ else
+ chip->address_mask = chip->intf->memory_size-1;
+
+ chip->channel = stream_create(0, 1, emulation_rate,chip,vlm5030_update_callback);
+
+ /* don't restore "UINT8 *chip->rom" when use VLM5030_set_rom() */
+
+ state_save_register_item(VLM_NAME,sndindex,chip->address);
+ state_save_register_item(VLM_NAME,sndindex,chip->pin_BSY);
+ state_save_register_item(VLM_NAME,sndindex,chip->pin_ST);
+ state_save_register_item(VLM_NAME,sndindex,chip->pin_VCU);
+ state_save_register_item(VLM_NAME,sndindex,chip->pin_RST);
+ state_save_register_item(VLM_NAME,sndindex,chip->latch_data);
+ state_save_register_item(VLM_NAME,sndindex,chip->vcu_addr_h);
+ state_save_register_item(VLM_NAME,sndindex,chip->parameter);
+ state_save_register_item(VLM_NAME,sndindex,chip->phase);
+ state_save_register_item(VLM_NAME,sndindex,chip->interp_count);
+ state_save_register_item(VLM_NAME,sndindex,chip->sample_count);
+ state_save_register_item(VLM_NAME,sndindex,chip->pitch_count);
+ state_save_register_item(VLM_NAME,sndindex,chip->old_energy);
+ state_save_register_item(VLM_NAME,sndindex,chip->old_pitch);
+ state_save_register_item_array(VLM_NAME,sndindex,chip->old_k);
+ state_save_register_item(VLM_NAME,sndindex,chip->target_energy);
+ state_save_register_item(VLM_NAME,sndindex,chip->target_pitch);
+ state_save_register_item_array(VLM_NAME,sndindex,chip->target_k);
+ state_save_register_item_array(VLM_NAME,sndindex,chip->x);
+ state_save_register_func_postload_ptr(VLM5030_restore_state, chip);
+
+ return chip;
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void vlm5030_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void vlm5030_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = vlm5030_set_info; break;
+ case SNDINFO_PTR_START: info->start = vlm5030_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "VLM5030"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "VLM speech"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/vlm5030.h b/src/emu/sound/vlm5030.h
new file mode 100644
index 00000000000..24368193945
--- /dev/null
+++ b/src/emu/sound/vlm5030.h
@@ -0,0 +1,25 @@
+#ifndef VLM5030_h
+#define VLM5030_h
+
+struct VLM5030interface
+{
+ int memory_region; /* memory region of speech rom */
+ int memory_size; /* memory size of speech rom (0=memory region length) */
+};
+
+/* set speech rom address */
+void VLM5030_set_rom(void *speech_rom);
+
+/* get BSY pin level */
+int VLM5030_BSY(void);
+/* latch contoll data */
+WRITE8_HANDLER( VLM5030_data_w );
+/* set RST pin level : reset / set table address A8-A15 */
+void VLM5030_RST (int pin );
+/* set VCU pin level : ?? unknown */
+void VLM5030_VCU(int pin );
+/* set ST pin level : set table address A0-A7 / start speech */
+void VLM5030_ST(int pin );
+
+#endif
+
diff --git a/src/emu/sound/votrax.c b/src/emu/sound/votrax.c
new file mode 100644
index 00000000000..f856e68b9ed
--- /dev/null
+++ b/src/emu/sound/votrax.c
@@ -0,0 +1,190 @@
+/**************************************************************************
+
+ Votrax SC-01 Emulator
+
+ Mike@Dissfulfils.co.uk
+
+**************************************************************************
+
+sh_votrax_start - Start emulation, load samples from Votrax subdirectory
+sh_votrax_stop - End emulation, free memory used for samples
+votrax_w - Write data to votrax port
+votrax_status - Return busy status (-1 = busy)
+
+If you need to alter the base frequency (i.e. Qbert) then just alter
+the variable VotraxBaseFrequency, this is defaulted to 8000
+
+**************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "samples.h"
+
+
+struct votrax_info
+{
+ int stream;
+ int frequency; /* Some games (Qbert) change this */
+ int volume;
+ sound_stream * channel;
+
+ struct loaded_sample *sample;
+ UINT32 pos;
+ UINT32 frac;
+ UINT32 step;
+
+ struct loaded_samples *samples;
+};
+
+#define FRAC_BITS 24
+#define FRAC_ONE (1 << FRAC_BITS)
+#define FRAC_MASK (FRAC_ONE - 1)
+
+
+/****************************************************************************
+ * 64 Phonemes - currently 1 sample per phoneme, will be combined sometime!
+ ****************************************************************************/
+
+static const char *VotraxTable[65] =
+{
+ "EH3","EH2","EH1","PA0","DT" ,"A1" ,"A2" ,"ZH",
+ "AH2","I3" ,"I2" ,"I1" ,"M" ,"N" ,"B" ,"V",
+ "CH" ,"SH" ,"Z" ,"AW1","NG" ,"AH1","OO1","OO",
+ "L" ,"K" ,"J" ,"H" ,"G" ,"F" ,"D" ,"S",
+ "A" ,"AY" ,"Y1" ,"UH3","AH" ,"P" ,"O" ,"I",
+ "U" ,"Y" ,"T" ,"R" ,"E" ,"W" ,"AE" ,"AE1",
+ "AW2","UH2","UH1","UH" ,"O2" ,"O1" ,"IU" ,"U1",
+ "THV","TH" ,"ER" ,"EH" ,"E1" ,"AW" ,"PA1","STOP",
+ 0
+};
+
+static void votrax_update_sound(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct votrax_info *info = param;
+ stream_sample_t *buffer = _buffer[0];
+
+ if (info->sample)
+ {
+ /* load some info locally */
+ UINT32 pos = info->pos;
+ UINT32 frac = info->frac;
+ UINT32 step = info->step;
+ UINT32 length = info->sample->length;
+ INT16 *sample = info->sample->data;
+
+ while (length--)
+ {
+ /* do a linear interp on the sample */
+ INT32 sample1 = sample[pos];
+ INT32 sample2 = sample[(pos + 1) % length];
+ INT32 fracmult = frac >> (FRAC_BITS - 14);
+ *buffer++ = ((0x4000 - fracmult) * sample1 + fracmult * sample2) >> 14;
+
+ /* advance */
+ frac += step;
+ pos += frac >> FRAC_BITS;
+ frac = frac & ((1 << FRAC_BITS) - 1);
+
+ /* handle looping/ending */
+ if (pos >= length)
+ {
+ info->sample = NULL;
+ break;
+ }
+ }
+
+ /* push position back out */
+ info->pos = pos;
+ info->frac = frac;
+ }
+}
+
+
+static void *votrax_start(int sndindex, int clock, const void *config)
+{
+ struct votrax_info *votrax;
+
+ votrax = auto_malloc(sizeof(*votrax));
+ memset(votrax, 0, sizeof(*votrax));
+
+ votrax->samples = readsamples(VotraxTable,"votrax");
+ votrax->frequency = 8000;
+ votrax->volume = 230;
+
+ votrax->channel = stream_create(0, 1, Machine->sample_rate, votrax, votrax_update_sound);
+
+ votrax->sample = NULL;
+ votrax->step = 0;
+
+ return votrax;
+}
+
+
+void votrax_w(int data)
+{
+ struct votrax_info *info = sndti_token(SOUND_VOTRAX, 0);
+ int Phoneme,Intonation;
+
+ stream_update(info->channel);
+
+ Phoneme = data & 0x3F;
+ Intonation = data >> 6;
+
+ logerror("Speech : %s at intonation %d\n",VotraxTable[Phoneme],Intonation);
+
+ if(Phoneme==63)
+ info->sample = NULL;
+
+ if(info->samples->sample[Phoneme].data)
+ {
+ info->sample = &info->samples->sample[Phoneme];
+ info->pos = 0;
+ info->frac = 0;
+ info->step = ((INT64)(info->sample->frequency + (256*Intonation)) << FRAC_BITS) / Machine->sample_rate;
+ stream_set_output_gain(info->channel, 0, (info->volume + (8*Intonation)*100/255) / 100.0);
+ }
+}
+
+int votrax_status_r(void)
+{
+ struct votrax_info *info = sndti_token(SOUND_VOTRAX, 0);
+ stream_update(info->channel);
+ return (info->sample != NULL);
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void votrax_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void votrax_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = votrax_set_info; break;
+ case SNDINFO_PTR_START: info->start = votrax_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Votrax SC-01"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Votrax speech"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/vrender0.c b/src/emu/sound/vrender0.c
new file mode 100644
index 00000000000..fc7df4c9a12
--- /dev/null
+++ b/src/emu/sound/vrender0.c
@@ -0,0 +1,274 @@
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "vrender0.h"
+
+/***********************************
+ VRENDER ZERO
+ AUDIO EMULATION
+************************************/
+/************
+MISSING:
+envelopes
+reverb
+interrupts
+*************/
+
+struct _VR0Chip
+{
+ UINT32 *TexBase;
+ UINT32 *FBBase;
+ UINT32 SOUNDREGS[0x10000/4];
+ struct VR0Interface Intf;
+ sound_stream * stream;
+};
+
+static void VR0_RenderAudio(struct _VR0Chip *VR0, int nsamples,stream_sample_t *l,stream_sample_t *r);
+
+static void VR0_Update(void *param, stream_sample_t **inputs, stream_sample_t **buf, int samples)
+{
+ struct _VR0Chip *VR0 = param;
+ VR0_RenderAudio(VR0, samples,buf[0],buf[1]);
+}
+
+//Correct table thanks to Evoga
+//they left a ulaw<->linear conversion tool inside the roms
+static const unsigned short ULawTo16[]=
+{
+ 0x8000,0x8400,0x8800,0x8C00,0x9000,0x9400,0x9800,0x9C00,
+ 0xA000,0xA400,0xA800,0xAC00,0xB000,0xB400,0xB800,0xBC00,
+ 0x4000,0x4400,0x4800,0x4C00,0x5000,0x5400,0x5800,0x5C00,
+ 0x6000,0x6400,0x6800,0x6C00,0x7000,0x7400,0x7800,0x7C00,
+ 0xC000,0xC200,0xC400,0xC600,0xC800,0xCA00,0xCC00,0xCE00,
+ 0xD000,0xD200,0xD400,0xD600,0xD800,0xDA00,0xDC00,0xDE00,
+ 0x2000,0x2200,0x2400,0x2600,0x2800,0x2A00,0x2C00,0x2E00,
+ 0x3000,0x3200,0x3400,0x3600,0x3800,0x3A00,0x3C00,0x3E00,
+ 0xE000,0xE100,0xE200,0xE300,0xE400,0xE500,0xE600,0xE700,
+ 0xE800,0xE900,0xEA00,0xEB00,0xEC00,0xED00,0xEE00,0xEF00,
+ 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700,
+ 0x1800,0x1900,0x1A00,0x1B00,0x1C00,0x1D00,0x1E00,0x1F00,
+ 0xF000,0xF080,0xF100,0xF180,0xF200,0xF280,0xF300,0xF380,
+ 0xF400,0xF480,0xF500,0xF580,0xF600,0xF680,0xF700,0xF780,
+ 0x0800,0x0880,0x0900,0x0980,0x0A00,0x0A80,0x0B00,0x0B80,
+ 0x0C00,0x0C80,0x0D00,0x0D80,0x0E00,0x0E80,0x0F00,0x0F80,
+ 0xF800,0xF840,0xF880,0xF8C0,0xF900,0xF940,0xF980,0xF9C0,
+ 0xFA00,0xFA40,0xFA80,0xFAC0,0xFB00,0xFB40,0xFB80,0xFBC0,
+ 0x0400,0x0440,0x0480,0x04C0,0x0500,0x0540,0x0580,0x05C0,
+ 0x0600,0x0640,0x0680,0x06C0,0x0700,0x0740,0x0780,0x07C0,
+ 0xFC00,0xFC20,0xFC40,0xFC60,0xFC80,0xFCA0,0xFCC0,0xFCE0,
+ 0xFD00,0xFD20,0xFD40,0xFD60,0xFD80,0xFDA0,0xFDC0,0xFDE0,
+ 0x0200,0x0220,0x0240,0x0260,0x0280,0x02A0,0x02C0,0x02E0,
+ 0x0300,0x0320,0x0340,0x0360,0x0380,0x03A0,0x03C0,0x03E0,
+ 0xFE00,0xFE10,0xFE20,0xFE30,0xFE40,0xFE50,0xFE60,0xFE70,
+ 0xFE80,0xFE90,0xFEA0,0xFEB0,0xFEC0,0xFED0,0xFEE0,0xFEF0,
+ 0x0100,0x0110,0x0120,0x0130,0x0140,0x0150,0x0160,0x0170,
+ 0x0180,0x0190,0x01A0,0x01B0,0x01C0,0x01D0,0x01E0,0x01F0,
+ 0x0000,0x0008,0x0010,0x0018,0x0020,0x0028,0x0030,0x0038,
+ 0x0040,0x0048,0x0050,0x0058,0x0060,0x0068,0x0070,0x0078,
+ 0xFF80,0xFF88,0xFF90,0xFF98,0xFFA0,0xFFA8,0xFFB0,0xFFB8,
+ 0xFFC0,0xFFC8,0xFFD0,0xFFD8,0xFFE0,0xFFE8,0xFFF0,0xFFF8,
+};
+
+
+#define STATUS VR0->SOUNDREGS[0x404/4]
+#define CURSADDR(chan) (VR0->SOUNDREGS[(0x20/4)*chan+0x00])
+#define DSADDR(chan) ((VR0->SOUNDREGS[(0x20/4)*chan+0x08/4]>>0)&0xffff)
+#define LOOPBEGIN(chan) (VR0->SOUNDREGS[(0x20/4)*chan+0x0c/4]&0x3fffff)
+#define LOOPEND(chan) (VR0->SOUNDREGS[(0x20/4)*chan+0x10/4]&0x3fffff)
+#define ENVVOL(chan) (VR0->SOUNDREGS[(0x20/4)*chan+0x04/4]&0xffffff)
+
+/*
+#define GETSOUNDREG16(Chan,Offs) program_read_word_32le(VR0->Intf.RegBase+0x20*Chan+Offs)
+#define GETSOUNDREG32(Chan,Offs) program_read_dword_32le(VR0->Intf.RegBase+0x20*Chan+Offs)
+
+#define CURSADDR(chan) GETSOUNDREG32(chan,0x00)
+#define DSADDR(chan) GETSOUNDREG16(chan,0x08)
+#define LOOPBEGIN(chan) (GETSOUNDREG32(chan,0x0c)&0x3fffff)
+#define LOOPEND(chan) (GETSOUNDREG32(chan,0x10)&0x3fffff)
+#define ENVVOL(chan) (GETSOUNDREG32(chan,0x04)&0xffffff)
+*/
+void VR0_Snd_Set_Areas(UINT32 *Texture,UINT32 *Frame)
+{
+ struct _VR0Chip *VR0 = sndti_token(SOUND_VRENDER0, 0);
+ VR0->TexBase=Texture;
+ VR0->FBBase=Frame;
+}
+
+static void *vrender0_start(int sndindex, int clock, const void *config)
+{
+ const struct VR0Interface *intf;
+ struct _VR0Chip *VR0;
+
+ VR0 = auto_malloc(sizeof(*VR0));
+ memset(VR0, 0, sizeof(*VR0));
+
+ intf=config;
+
+ memcpy(&(VR0->Intf),intf,sizeof(struct VR0Interface));
+ memset(VR0->SOUNDREGS,0,0x10000);
+
+ VR0->stream = stream_create(0, 2, 44100, VR0, VR0_Update);
+
+ return VR0;
+}
+
+WRITE32_HANDLER(VR0_Snd_Write)
+{
+ struct _VR0Chip *VR0 = sndti_token(SOUND_VRENDER0, 0);
+ if(offset==0x404/4)
+ {
+ data&=0xffff;
+ if(data&0x8000)
+ {
+ UINT32 c=data&0x1f;
+ STATUS|=1<<c;
+ CURSADDR(c)=0;
+ }
+ else
+ {
+ STATUS&=~(1<<(data&0x1f));
+ }
+ return;
+ }
+ else
+ {
+ COMBINE_DATA(&VR0->SOUNDREGS[offset]);
+ }
+}
+
+
+READ32_HANDLER(VR0_Snd_Read)
+{
+ struct _VR0Chip *VR0 = sndti_token(SOUND_VRENDER0, 0);
+ return VR0->SOUNDREGS[offset];
+}
+
+static void VR0_RenderAudio(struct _VR0Chip *VR0, int nsamples,stream_sample_t *l,stream_sample_t *r)
+{
+ INT16 *SAMPLES;
+ UINT32 st=STATUS;
+ signed int lsample=0,rsample=0;
+ UINT32 CLK=(VR0->SOUNDREGS[0x600/4]>>0)&0xff;
+ UINT32 NCH=(VR0->SOUNDREGS[0x600/4]>>8)&0xff;
+ UINT32 CT1=(VR0->SOUNDREGS[0x600/4]>>16)&0xff;
+ UINT32 CT2=(VR0->SOUNDREGS[0x600/4]>>24)&0xff;
+ int div;
+ int s;
+
+
+ if(CT1&0x20)
+ SAMPLES=(INT16 *)VR0->TexBase;
+ else
+ SAMPLES=(INT16 *)VR0->FBBase;
+
+ if(CLK)
+ div=((30<<16)|0x8000)/(CLK+1);
+ else
+ div=1<<16;
+
+ for(s=0;s<nsamples;++s)
+ {
+ int i;
+ lsample=rsample=0;
+ for(i=0;i<=NCH;++i)
+ {
+ signed int sample;
+ UINT32 cur=CURSADDR(i);
+ UINT32 a=LOOPBEGIN(i)+(cur>>10);
+ UINT8 Mode=VR0->SOUNDREGS[(0x20/4)*i+0x8/4]>>24;
+ signed int LVOL=VR0->SOUNDREGS[(0x20/4)*i+0xc/4]>>24;
+ signed int RVOL=VR0->SOUNDREGS[(0x20/4)*i+0x10/4]>>24;
+
+ INT32 DSADD=(DSADDR(i)*div)>>16;
+
+ if(!(st&(1<<i)) || !(CT2&0x80))
+ continue;
+
+ if(Mode&0x10) //u-law
+ {
+ UINT16 s=SAMPLES[a];
+ if((cur&0x200))
+ s>>=8;
+ sample=(signed short)ULawTo16[s&0xff];
+ }
+ else
+ {
+ if(Mode&0x20) //8bit
+ {
+ UINT16 s=SAMPLES[a];
+ if((cur&0x200))
+ s>>=8;
+ sample=(signed short) (((signed char) (s&0xff))<<8);
+ }
+ else //16bit
+ {
+ sample=SAMPLES[a];
+ }
+ }
+
+ CURSADDR(i)+=DSADD;
+ if(a>=LOOPEND(i))
+ {
+ if(Mode&1) //Loop
+ CURSADDR(i)=0;//LOOPBEGIN(i)<<10;
+ else
+ {
+ STATUS&=~(1<<(i&0x1f));
+ break;
+ }
+ }
+// UINT32 v=(ENVVOL(i))>>8;
+// sample=(sample*v)>>16;
+ lsample+=(sample*LVOL)>>8;
+ rsample+=(sample*RVOL)>>8;
+ }
+ if(lsample>32767)
+ lsample=32767;
+ if(lsample<-32768)
+ lsample=-32768;
+ l[s]=lsample;
+ if(rsample>32767)
+ rsample=32767;
+ if(rsample<-32768)
+ rsample=-32768;
+ r[s]=rsample;
+ }
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void vrender0_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void vrender0_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = vrender0_set_info; break;
+ case SNDINFO_PTR_START: info->start = vrender0_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "VRender0"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "???"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/vrender0.h b/src/emu/sound/vrender0.h
new file mode 100644
index 00000000000..7f0e8ed1317
--- /dev/null
+++ b/src/emu/sound/vrender0.h
@@ -0,0 +1,9 @@
+struct VR0Interface
+{
+ UINT32 RegBase;
+};
+
+void VR0_Snd_Set_Areas(UINT32 *Texture,UINT32 *Frame);
+
+READ32_HANDLER(VR0_Snd_Read);
+WRITE32_HANDLER(VR0_Snd_Write);
diff --git a/src/emu/sound/wave.c b/src/emu/sound/wave.c
new file mode 100644
index 00000000000..0f33ba51343
--- /dev/null
+++ b/src/emu/sound/wave.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+
+ wave.c
+
+ Code that interfaces
+ Functions to handle loading, creation, recording and playback
+ of wave samples for IO_CASSETTE
+
+****************************************************************************/
+
+#include "driver.h"
+#include "streams.h"
+#ifdef MESS
+#include "messdrv.h"
+#include "utils.h"
+#include "devices/cassette.h"
+#endif
+
+#define ALWAYS_PLAY_SOUND 0
+#define WAVE_TOKEN_MASK 0xFFFF0000
+
+
+
+static void wave_sound_update(void *param,stream_sample_t **inputs, stream_sample_t **_buffer,int length)
+{
+#ifdef MESS
+ mess_image *image;
+ cassette_image *cassette;
+ cassette_state state;
+ double time_index;
+ double duration;
+ int num = ((FPTR)param) & ~WAVE_TOKEN_MASK;
+ stream_sample_t *buffer = _buffer[0];
+ int i;
+
+ image = image_from_devtype_and_index(IO_CASSETTE, num);
+ state = cassette_get_state(image);
+
+ state &= CASSETTE_MASK_UISTATE | CASSETTE_MASK_MOTOR | CASSETTE_MASK_SPEAKER;
+ if (image_exists(image) && (ALWAYS_PLAY_SOUND || (state == (CASSETTE_PLAY | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED))))
+ {
+ cassette = cassette_get_image(image);
+ time_index = cassette_get_position(image);
+ duration = ((double) length) / Machine->sample_rate;
+
+ cassette_get_samples(cassette, 0, time_index, duration, length, 2, buffer, CASSETTE_WAVEFORM_16BIT);
+
+ for (i = length-1; i >= 0; i--)
+ buffer[i] = ((INT16 *) buffer)[i];
+ }
+ else
+ {
+ memset(buffer, 0, sizeof(*buffer) * length);
+ }
+#endif
+}
+
+
+
+static void *wave_start(int sndindex, int clock, const void *config)
+{
+ stream_create(0, 1, Machine->sample_rate, (void *) (FPTR)sndindex, wave_sound_update);
+ return (void *) (FPTR)(sndindex | WAVE_TOKEN_MASK);
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void wave_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void wave_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = wave_set_info; break;
+ case SNDINFO_PTR_START: info->start = wave_start; break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "Cassette"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Cassette"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2005, The MESS Team"; break;
+ }
+}
diff --git a/src/emu/sound/wave.h b/src/emu/sound/wave.h
new file mode 100644
index 00000000000..36ff3baa0da
--- /dev/null
+++ b/src/emu/sound/wave.h
@@ -0,0 +1,14 @@
+#ifndef WAVE_H
+#define WAVE_H
+
+/*****************************************************************************
+ * CassetteWave interface
+ *****************************************************************************/
+
+#include "messdrv.h"
+
+
+
+#endif /* WAVE_H */
+
+
diff --git a/src/emu/sound/wavwrite.c b/src/emu/sound/wavwrite.c
new file mode 100644
index 00000000000..47fa9a8a02b
--- /dev/null
+++ b/src/emu/sound/wavwrite.c
@@ -0,0 +1,207 @@
+#include "mamecore.h"
+#include "sound/wavwrite.h"
+
+struct _wav_file
+{
+ FILE *file;
+ UINT32 total_offs;
+ UINT32 data_offs;
+};
+
+#ifdef LSB_FIRST
+#define intel_long(x) (x)
+#define intel_short(x) (x)
+#else
+#define intel_long(x) (((x << 24) | (((unsigned long) x) >> 24) | (( x & 0x0000ff00) << 8) | (( x & 0x00ff0000) >> 8)))
+#define intel_short(x) (((x) << 8) | ((x) >> 8))
+#endif
+
+wav_file *wav_open(const char *filename, int sample_rate, int channels)
+{
+ wav_file *wav;
+ UINT32 bps, temp32;
+ UINT16 align, temp16;
+
+ /* allocate memory for the wav struct */
+ wav = (wav_file *) malloc(sizeof(struct _wav_file));
+ if (!wav)
+ return NULL;
+
+ /* create the file */
+ wav->file = fopen(filename, "wb");
+ if (!wav->file)
+ {
+ free(wav);
+ return NULL;
+ }
+
+ /* write the 'RIFF' header */
+ fwrite("RIFF", 1, 4, wav->file);
+
+ /* write the total size */
+ temp32 = 0;
+ wav->total_offs = ftell(wav->file);
+ fwrite(&temp32, 1, 4, wav->file);
+
+ /* write the 'WAVE' type */
+ fwrite("WAVE", 1, 4, wav->file);
+
+ /* write the 'fmt ' tag */
+ fwrite("fmt ", 1, 4, wav->file);
+
+ /* write the format length */
+ temp32 = intel_long(16);
+ fwrite(&temp32, 1, 4, wav->file);
+
+ /* write the format (PCM) */
+ temp16 = intel_short(1);
+ fwrite(&temp16, 1, 2, wav->file);
+
+ /* write the channels */
+ temp16 = intel_short(channels);
+ fwrite(&temp16, 1, 2, wav->file);
+
+ /* write the sample rate */
+ temp32 = intel_long(sample_rate);
+ fwrite(&temp32, 1, 4, wav->file);
+
+ /* write the bytes/second */
+ bps = sample_rate * 2 * channels;
+ temp32 = intel_long(bps);
+ fwrite(&temp32, 1, 4, wav->file);
+
+ /* write the block align */
+ align = 2 * channels;
+ temp16 = intel_short(align);
+ fwrite(&temp16, 1, 2, wav->file);
+
+ /* write the bits/sample */
+ temp16 = intel_short(16);
+ fwrite(&temp16, 1, 2, wav->file);
+
+ /* write the 'data' tag */
+ fwrite("data", 1, 4, wav->file);
+
+ /* write the data length */
+ temp32 = 0;
+ wav->data_offs = ftell(wav->file);
+ fwrite(&temp32, 1, 4, wav->file);
+
+ return wav;
+}
+
+
+void wav_close(wav_file *wav)
+{
+ UINT32 total = ftell(wav->file);
+ UINT32 temp32;
+
+ if (!wav) return;
+
+ /* update the total file size */
+ fseek(wav->file, wav->total_offs, SEEK_SET);
+ temp32 = total - (wav->total_offs + 4);
+ temp32 = intel_long(temp32);
+ fwrite(&temp32, 1, 4, wav->file);
+
+ /* update the data size */
+ fseek(wav->file, wav->data_offs, SEEK_SET);
+ temp32 = total - (wav->data_offs + 4);
+ temp32 = intel_long(temp32);
+ fwrite(&temp32, 1, 4, wav->file);
+
+ fclose(wav->file);
+ free(wav);
+}
+
+
+void wav_add_data_16(wav_file *wav, INT16 *data, int samples)
+{
+ if (!wav) return;
+
+ /* just write and flush the data */
+ fwrite(data, 2, samples, wav->file);
+ fflush(wav->file);
+}
+
+
+void wav_add_data_32(wav_file *wav, INT32 *data, int samples, int shift)
+{
+ INT16 *temp;
+ int i;
+
+ if (!wav) return;
+
+ /* allocate temp memory */
+ temp = malloc(samples * sizeof(temp[0]));
+ if (!temp)
+ return;
+
+ /* clamp */
+ for (i = 0; i < samples; i++)
+ {
+ int val = data[i] >> shift;
+ temp[i] = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val;
+ }
+
+ /* write and flush */
+ fwrite(temp, 2, samples, wav->file);
+ fflush(wav->file);
+
+ /* free memory */
+ free(temp);
+}
+
+
+void wav_add_data_16lr(wav_file *wav, INT16 *left, INT16 *right, int samples)
+{
+ INT16 *temp;
+ int i;
+
+ if (!wav) return;
+
+ /* allocate temp memory */
+ temp = malloc(samples * 2 * sizeof(temp[0]));
+ if (!temp)
+ return;
+
+ /* interleave */
+ for (i = 0; i < samples * 2; i++)
+ temp[i] = (i & 1) ? right[i / 2] : left[i / 2];
+
+ /* write and flush */
+ fwrite(temp, 4, samples, wav->file);
+ fflush(wav->file);
+
+ /* free memory */
+ free(temp);
+}
+
+
+void wav_add_data_32lr(wav_file *wav, INT32 *left, INT32 *right, int samples, int shift)
+{
+ INT16 *temp;
+ int i;
+
+ if (!wav) return;
+
+ /* allocate temp memory */
+ temp = malloc(samples * 2 * sizeof(temp[0]));
+ if (!temp)
+ return;
+
+ /* interleave */
+ for (i = 0; i < samples * 2; i++)
+ {
+ int val = (i & 1) ? right[i / 2] : left[i / 2];
+ val >>= shift;
+ temp[i] = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val;
+ }
+
+ /* write and flush */
+ fwrite(temp, 4, samples, wav->file);
+ fflush(wav->file);
+
+ /* free memory */
+ free(temp);
+}
diff --git a/src/emu/sound/wavwrite.h b/src/emu/sound/wavwrite.h
new file mode 100644
index 00000000000..6a41fd9924b
--- /dev/null
+++ b/src/emu/sound/wavwrite.h
@@ -0,0 +1,14 @@
+#ifndef WAVWRITE_H
+#define WAVWRITE_H
+
+typedef struct _wav_file wav_file;
+
+wav_file *wav_open(const char *filename, int sample_rate, int channels);
+void wav_close(wav_file*wavptr);
+
+void wav_add_data_16(wav_file *wavptr, INT16 *data, int samples);
+void wav_add_data_32(wav_file *wavptr, INT32 *data, int samples, int shift);
+void wav_add_data_16lr(wav_file *wavptr, INT16 *left, INT16 *right, int samples);
+void wav_add_data_32lr(wav_file *wavptr, INT32 *left, INT32 *right, int samples, int shift);
+
+#endif /* WAVWRITE_H */
diff --git a/src/emu/sound/x1_010.c b/src/emu/sound/x1_010.c
new file mode 100644
index 00000000000..b9df5e5884c
--- /dev/null
+++ b/src/emu/sound/x1_010.c
@@ -0,0 +1,330 @@
+/***************************************************************************
+
+ -= Seta Hardware =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+ rewrite by Manbow-J(manbowj@hamal.freemail.ne.jp)
+
+ X1-010 Seta Custom Sound Chip (80 Pin PQFP)
+
+ Custom programmed Mitsubishi M60016 Gate Array, 3608 gates, 148 Max I/O ports
+
+ The X1-010 is 16 Voices sound generator, each channel gets it's
+ waveform from RAM (128 bytes per waveform, 8 bit unsigned data)
+ or sampling PCM(8bit unsigned data).
+
+Registers:
+ 8 registers per channel (mapped to the lower bytes of 16 words on the 68K)
+
+ Reg: Bits: Meaning:
+
+ 0 7654 3---
+ ---- -2-- PCM/Waveform repeat flag (0:Ones 1:Repeat) (*1)
+ ---- --1- Sound out select (0:PCM 1:Waveform)
+ ---- ---0 Key on / off
+
+ 1 7654 ---- PCM Volume 1 (L?)
+ ---- 3210 PCM Volume 2 (R?)
+ Waveform No.
+
+ 2 PCM Frequency
+ Waveform Pitch Lo
+
+ 3 Waveform Pitch Hi
+
+ 4 PCM Sample Start / 0x1000 [Start/End in bytes]
+ Waveform Envelope Time
+
+ 5 PCM Sample End 0x100 - (Sample End / 0x1000) [PCM ROM is Max 1MB?]
+ Waveform Envelope No.
+ 6 Reserved
+ 7 Reserved
+
+ offset 0x0000 - 0x0fff Wave form data
+ offset 0x1000 - 0x1fff Envelope data
+
+ *1 : when 0 is specified, hardware interrupt is caused(allways return soon)
+
+Hardcoded Values:
+
+ PCM ROM region: REGION_SOUND1
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "x1_010.h"
+
+
+
+#define LOG_SOUND 0
+
+#define SETA_NUM_CHANNELS 16
+
+
+#define LOG_REGISTER_WRITE 0
+#define LOG_REGISTER_READ 0
+
+#define FREQ_BASE_BITS 8 // Frequency fixed decimal shift bits
+#define ENV_BASE_BITS 16 // wave form envelope fixed decimal shift bits
+#define VOL_BASE (2*32*256/30) // Volume base
+
+/* this structure defines the parameters for a channel */
+typedef struct {
+ unsigned char status;
+ unsigned char volume; // volume / wave form no.
+ unsigned char frequency; // frequency / pitch lo
+ unsigned char pitch_hi; // reserved / pitch hi
+ unsigned char start; // start address / envelope time
+ unsigned char end; // end address / envelope no.
+ unsigned char reserve[2];
+} X1_010_CHANNEL;
+
+struct x1_010_info
+{
+ /* Variables only used here */
+ int rate; // Output sampling rate (Hz)
+ sound_stream * stream; // Stream handle
+ int address; // address eor data
+ int sound_enable; // sound output enable/disable
+ UINT8 reg[0x2000]; // X1-010 Register & wave form area
+ UINT8 HI_WORD_BUF[0x2000]; // X1-010 16bit access ram check avoidance work
+ UINT32 smp_offset[SETA_NUM_CHANNELS];
+ UINT32 env_offset[SETA_NUM_CHANNELS];
+
+ UINT32 base_clock;
+};
+
+/* mixer tables and internal buffers */
+//static short *mixer_buffer = NULL;
+
+
+/*--------------------------------------------------------------
+ generate sound to the mix buffer
+--------------------------------------------------------------*/
+static void seta_update( void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length )
+{
+ struct x1_010_info *info = param;
+ X1_010_CHANNEL *reg;
+ int ch, i, volL, volR, freq;
+ register INT8 *start, *end, data;
+ register UINT8 *env;
+ register UINT32 smp_offs, smp_step, env_offs, env_step, delta;
+
+ // mixer buffer zero clear
+ memset( buffer[0], 0, length*sizeof(*buffer[0]) );
+ memset( buffer[1], 0, length*sizeof(*buffer[1]) );
+
+// if( info->sound_enable == 0 ) return;
+
+ for( ch = 0; ch < SETA_NUM_CHANNELS; ch++ ) {
+ reg = (X1_010_CHANNEL *)&(info->reg[ch*sizeof(X1_010_CHANNEL)]);
+ if( (reg->status&1) != 0 ) { // Key On
+ stream_sample_t *bufL = buffer[0];
+ stream_sample_t *bufR = buffer[1];
+ if( (reg->status&2) == 0 ) { // PCM sampling
+ start = (INT8 *)(reg->start *0x1000+memory_region(REGION_SOUND1));
+ end = (INT8 *)((0x100-reg->end)*0x1000+memory_region(REGION_SOUND1));
+ volL = ((reg->volume>>4)&0xf)*VOL_BASE;
+ volR = ((reg->volume>>0)&0xf)*VOL_BASE;
+ smp_offs = info->smp_offset[ch];
+ freq = reg->frequency&0x1f;
+ // Meta Fox does not write the frequency register. Ever
+ if( freq == 0 ) freq = 4;
+ smp_step = (UINT32)((float)info->base_clock/8192.0
+ *freq*(1<<FREQ_BASE_BITS)/(float)info->rate);
+#if LOG_SOUND
+ if( smp_offs == 0 ) {
+ logerror( "Play sample %06X - %06X, channel %X volume %d freq %X step %X offset %X\n",
+ start, end, ch, vol, freq, smp_step, smp_offs );
+ }
+#endif
+ for( i = 0; i < length; i++ ) {
+ delta = smp_offs>>FREQ_BASE_BITS;
+ // sample ended?
+ if( start+delta >= end ) {
+ reg->status &= 0xfe; // Key off
+ break;
+ }
+ data = *(start+delta);
+ *bufL++ += (data*volL/256);
+ *bufR++ += (data*volR/256);
+ smp_offs += smp_step;
+ }
+ info->smp_offset[ch] = smp_offs;
+ } else { // Wave form
+ start = (INT8 *)&(info->reg[reg->volume*128+0x1000]);
+ smp_offs = info->smp_offset[ch];
+ freq = (reg->pitch_hi<<8)+reg->frequency;
+ smp_step = (UINT32)((float)info->base_clock/128.0/1024.0/4.0*freq*(1<<FREQ_BASE_BITS)/(float)info->rate);
+
+ env = (UINT8 *)&(info->reg[reg->end*128]);
+ env_offs = info->env_offset[ch];
+ env_step = (UINT32)((float)info->base_clock/128.0/1024.0/4.0*reg->start*(1<<ENV_BASE_BITS)/(float)info->rate);
+#if LOG_SOUND
+/* Print some more debug info */
+ if( smp_offs == 0 ) {
+ logerror( "Play waveform %X, channel %X volume %X freq %4X step %X offset %X\n",
+ reg->volume, ch, reg->end, freq, smp_step, smp_offs );
+ }
+#endif
+ for( i = 0; i < length; i++ ) {
+ int vol;
+ delta = env_offs>>ENV_BASE_BITS;
+ // Envelope one shot mode
+ if( (reg->status&4) != 0 && delta >= 0x80 ) {
+ reg->status &= 0xfe; // Key off
+ break;
+ }
+ vol = *(env+(delta&0x7f));
+ volL = ((vol>>4)&0xf)*VOL_BASE;
+ volR = ((vol>>0)&0xf)*VOL_BASE;
+ data = *(start+((smp_offs>>FREQ_BASE_BITS)&0x7f));
+ *bufL++ += (data*volL/256);
+ *bufR++ += (data*volR/256);
+ smp_offs += smp_step;
+ env_offs += env_step;
+ }
+ info->smp_offset[ch] = smp_offs;
+ info->env_offset[ch] = env_offs;
+ }
+ }
+ }
+}
+
+
+
+static void *x1_010_start(int sndindex, int clock, const void *config)
+{
+ int i;
+ const struct x1_010_interface *intf = config;
+ struct x1_010_info *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ info->base_clock = clock;
+ info->rate = clock / 1024;
+ info->address = intf->adr;
+
+ for( i = 0; i < SETA_NUM_CHANNELS; i++ ) {
+ info->smp_offset[i] = 0;
+ info->env_offset[i] = 0;
+ }
+#if LOG_SOUND
+ /* Print some more debug info */
+ logerror("masterclock = %d rate = %d\n", master_clock, info->rate );
+#endif
+ /* get stream channels */
+ info->stream = stream_create(0,2,info->rate,info,seta_update);
+
+ return info;
+}
+
+
+void seta_sound_enable_w(int data)
+{
+ struct x1_010_info *info = sndti_token(SOUND_X1_010, 0);
+ info->sound_enable = data;
+}
+
+
+
+/* Use these for 8 bit CPUs */
+
+
+READ8_HANDLER( seta_sound_r )
+{
+ struct x1_010_info *info = sndti_token(SOUND_X1_010, 0);
+ offset ^= info->address;
+ return info->reg[offset];
+}
+
+
+
+
+WRITE8_HANDLER( seta_sound_w )
+{
+ struct x1_010_info *info = sndti_token(SOUND_X1_010, 0);
+ int channel, reg;
+ offset ^= info->address;
+
+ channel = offset/sizeof(X1_010_CHANNEL);
+ reg = offset%sizeof(X1_010_CHANNEL);
+
+ if( channel < SETA_NUM_CHANNELS && reg == 0
+ && (info->reg[offset]&1) == 0 && (data&1) != 0 ) {
+ info->smp_offset[channel] = 0;
+ info->env_offset[channel] = 0;
+ }
+#if LOG_REGISTER_WRITE
+ logerror("PC: %06X : offset %6X : data %2X\n", activecpu_get_pc(), offset, data );
+#endif
+ info->reg[offset] = data;
+}
+
+
+
+
+/* Use these for 16 bit CPUs */
+
+READ16_HANDLER( seta_sound_word_r )
+{
+ struct x1_010_info *info = sndti_token(SOUND_X1_010, 0);
+ UINT16 ret;
+
+ ret = info->HI_WORD_BUF[offset]<<8;
+ ret += (seta_sound_r( offset )&0xff);
+#if LOG_REGISTER_READ
+ logerror( "Read X1-010 PC:%06X Offset:%04X Data:%04X\n", activecpu_get_pc(), offset, ret );
+#endif
+ return ret;
+}
+
+WRITE16_HANDLER( seta_sound_word_w )
+{
+ struct x1_010_info *info = sndti_token(SOUND_X1_010, 0);
+ info->HI_WORD_BUF[offset] = (data>>8)&0xff;
+ seta_sound_w( offset, data&0xff );
+#if LOG_REGISTER_WRITE
+ logerror( "Write X1-010 PC:%06X Offset:%04X Data:%04X\n", activecpu_get_pc(), offset, data );
+#endif
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void x1_010_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void x1_010_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = x1_010_set_info; break;
+ case SNDINFO_PTR_START: info->start = x1_010_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "X1-010"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Seta custom"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/x1_010.h b/src/emu/sound/x1_010.h
new file mode 100644
index 00000000000..d54d22cc3f8
--- /dev/null
+++ b/src/emu/sound/x1_010.h
@@ -0,0 +1,13 @@
+struct x1_010_interface
+{
+ int adr; /* address */
+};
+
+
+READ8_HANDLER ( seta_sound_r );
+WRITE8_HANDLER( seta_sound_w );
+
+READ16_HANDLER ( seta_sound_word_r );
+WRITE16_HANDLER( seta_sound_word_w );
+
+void seta_sound_enable_w(int);
diff --git a/src/emu/sound/ym2151.c b/src/emu/sound/ym2151.c
new file mode 100644
index 00000000000..dd3b0e45b5f
--- /dev/null
+++ b/src/emu/sound/ym2151.c
@@ -0,0 +1,2505 @@
+/*****************************************************************************
+*
+* Yamaha YM2151 driver (version 2.150 final beta)
+*
+******************************************************************************/
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "ym2151.h"
+
+
+/* undef this to not use MAME timer system */
+#define USE_MAME_TIMERS
+
+/*#define FM_EMU*/
+#ifdef FM_EMU
+ #define INLINE static __inline__
+ #ifdef USE_MAME_TIMERS
+ #undef USE_MAME_TIMERS
+ #endif
+#endif
+#ifdef USE_MAME_TIMERS
+ /*#define LOG_CYM_FILE*/
+ #ifdef LOG_CYM_FILE
+ FILE * cymfile = NULL;
+ #endif
+#endif
+
+
+/* struct describing a single operator */
+typedef struct{
+ UINT32 phase; /* accumulated operator phase */
+ UINT32 freq; /* operator frequency count */
+ INT32 dt1; /* current DT1 (detune 1 phase inc/decrement) value */
+ UINT32 mul; /* frequency count multiply */
+ UINT32 dt1_i; /* DT1 index * 32 */
+ UINT32 dt2; /* current DT2 (detune 2) value */
+
+ signed int *connect; /* operator output 'direction' */
+
+ /* only M1 (operator 0) is filled with this data: */
+ signed int *mem_connect; /* where to put the delayed sample (MEM) */
+ INT32 mem_value; /* delayed sample (MEM) value */
+
+ /* channel specific data; note: each operator number 0 contains channel specific data */
+ UINT32 fb_shift; /* feedback shift value for operators 0 in each channel */
+ INT32 fb_out_curr; /* operator feedback value (used only by operators 0) */
+ INT32 fb_out_prev; /* previous feedback value (used only by operators 0) */
+ UINT32 kc; /* channel KC (copied to all operators) */
+ UINT32 kc_i; /* just for speedup */
+ UINT32 pms; /* channel PMS */
+ UINT32 ams; /* channel AMS */
+ /* end of channel specific data */
+
+ UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
+ UINT32 state; /* Envelope state: 4-attack(AR) 3-decay(D1R) 2-sustain(D2R) 1-release(RR) 0-off */
+ UINT8 eg_sh_ar; /* (attack state) */
+ UINT8 eg_sel_ar; /* (attack state) */
+ UINT32 tl; /* Total attenuation Level */
+ INT32 volume; /* current envelope attenuation level */
+ UINT8 eg_sh_d1r; /* (decay state) */
+ UINT8 eg_sel_d1r; /* (decay state) */
+ UINT32 d1l; /* envelope switches to sustain state after reaching this level */
+ UINT8 eg_sh_d2r; /* (sustain state) */
+ UINT8 eg_sel_d2r; /* (sustain state) */
+ UINT8 eg_sh_rr; /* (release state) */
+ UINT8 eg_sel_rr; /* (release state) */
+
+ UINT32 key; /* 0=last key was KEY OFF, 1=last key was KEY ON */
+
+ UINT32 ks; /* key scale */
+ UINT32 ar; /* attack rate */
+ UINT32 d1r; /* decay rate */
+ UINT32 d2r; /* sustain rate */
+ UINT32 rr; /* release rate */
+
+ UINT32 reserved0; /**/
+ UINT32 reserved1; /**/
+
+} YM2151Operator;
+
+
+typedef struct
+{
+ YM2151Operator oper[32]; /* the 32 operators */
+
+ UINT32 pan[16]; /* channels output masks (0xffffffff = enable) */
+
+ UINT32 eg_cnt; /* global envelope generator counter */
+ UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/64/3 */
+ UINT32 eg_timer_add; /* step of eg_timer */
+ UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 3 samples (on real chip) */
+
+ UINT32 lfo_phase; /* accumulated LFO phase (0 to 255) */
+ UINT32 lfo_timer; /* LFO timer */
+ UINT32 lfo_timer_add; /* step of lfo_timer */
+ UINT32 lfo_overflow; /* LFO generates new output when lfo_timer reaches this value */
+ UINT32 lfo_counter; /* LFO phase increment counter */
+ UINT32 lfo_counter_add; /* step of lfo_counter */
+ UINT8 lfo_wsel; /* LFO waveform (0-saw, 1-square, 2-triangle, 3-random noise) */
+ UINT8 amd; /* LFO Amplitude Modulation Depth */
+ INT8 pmd; /* LFO Phase Modulation Depth */
+ UINT32 lfa; /* LFO current AM output */
+ INT32 lfp; /* LFO current PM output */
+
+ UINT8 test; /* TEST register */
+ UINT8 ct; /* output control pins (bit1-CT2, bit0-CT1) */
+
+ UINT32 noise; /* noise enable/period register (bit 7 - noise enable, bits 4-0 - noise period */
+ UINT32 noise_rng; /* 17 bit noise shift register */
+ UINT32 noise_p; /* current noise 'phase'*/
+ UINT32 noise_f; /* current noise period */
+
+ UINT32 csm_req; /* CSM KEY ON / KEY OFF sequence request */
+
+ UINT32 irq_enable; /* IRQ enable for timer B (bit 3) and timer A (bit 2); bit 7 - CSM mode (keyon to all slots, everytime timer A overflows) */
+ UINT32 status; /* chip status (BUSY, IRQ Flags) */
+ UINT8 connect[8]; /* channels connections */
+
+#ifdef USE_MAME_TIMERS
+/* ASG 980324 -- added for tracking timers */
+ emu_timer *timer_A;
+ emu_timer *timer_B;
+ attotime timer_A_time[1024]; /* timer A times for MAME */
+ attotime timer_B_time[256]; /* timer B times for MAME */
+ int irqlinestate;
+#else
+ UINT8 tim_A; /* timer A enable (0-disabled) */
+ UINT8 tim_B; /* timer B enable (0-disabled) */
+ INT32 tim_A_val; /* current value of timer A */
+ INT32 tim_B_val; /* current value of timer B */
+ UINT32 tim_A_tab[1024]; /* timer A deltas */
+ UINT32 tim_B_tab[256]; /* timer B deltas */
+#endif
+ UINT32 timer_A_index; /* timer A index */
+ UINT32 timer_B_index; /* timer B index */
+ UINT32 timer_A_index_old; /* timer A previous index */
+ UINT32 timer_B_index_old; /* timer B previous index */
+
+ /* Frequency-deltas to get the closest frequency possible.
+ * There are 11 octaves because of DT2 (max 950 cents over base frequency)
+ * and LFO phase modulation (max 800 cents below AND over base frequency)
+ * Summary: octave explanation
+ * 0 note code - LFO PM
+ * 1 note code
+ * 2 note code
+ * 3 note code
+ * 4 note code
+ * 5 note code
+ * 6 note code
+ * 7 note code
+ * 8 note code
+ * 9 note code + DT2 + LFO PM
+ * 10 note code + DT2 + LFO PM
+ */
+ UINT32 freq[11*768]; /* 11 octaves, 768 'cents' per octave */
+
+ /* Frequency deltas for DT1. These deltas alter operator frequency
+ * after it has been taken from frequency-deltas table.
+ */
+ INT32 dt1_freq[8*32]; /* 8 DT1 levels, 32 KC values */
+
+ UINT32 noise_tab[32]; /* 17bit Noise Generator periods */
+
+ void (*irqhandler)(int irq); /* IRQ function handler */
+ write8_handler porthandler; /* port write function handler */
+
+ unsigned int clock; /* chip clock in Hz (passed from 2151intf.c) */
+ unsigned int sampfreq; /* sampling frequency in Hz (passed from 2151intf.c) */
+} YM2151;
+
+
+#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
+#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */
+#define LFO_SH 10 /* 22.10 fixed point (LFO calculations) */
+#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */
+
+#define FREQ_MASK ((1<<FREQ_SH)-1)
+
+#define ENV_BITS 10
+#define ENV_LEN (1<<ENV_BITS)
+#define ENV_STEP (128.0/ENV_LEN)
+
+#define MAX_ATT_INDEX (ENV_LEN-1) /* 1023 */
+#define MIN_ATT_INDEX (0) /* 0 */
+
+#define EG_ATT 4
+#define EG_DEC 3
+#define EG_SUS 2
+#define EG_REL 1
+#define EG_OFF 0
+
+#define SIN_BITS 10
+#define SIN_LEN (1<<SIN_BITS)
+#define SIN_MASK (SIN_LEN-1)
+
+#define TL_RES_LEN (256) /* 8 bits addressing (real chip) */
+
+
+#if (SAMPLE_BITS==16)
+ #define FINAL_SH (0)
+ #define MAXOUT (+32767)
+ #define MINOUT (-32768)
+#else
+ #define FINAL_SH (8)
+ #define MAXOUT (+127)
+ #define MINOUT (-128)
+#endif
+
+
+/* TL_TAB_LEN is calculated as:
+* 13 - sinus amplitude bits (Y axis)
+* 2 - sinus sign bit (Y axis)
+* TL_RES_LEN - sinus resolution (X axis)
+*/
+#define TL_TAB_LEN (13*2*TL_RES_LEN)
+static signed int tl_tab[TL_TAB_LEN];
+
+#define ENV_QUIET (TL_TAB_LEN>>3)
+
+/* sin waveform table in 'decibel' scale */
+static unsigned int sin_tab[SIN_LEN];
+
+
+/* translate from D1L to volume index (16 D1L levels) */
+static UINT32 d1l_tab[16];
+
+
+#define RATE_STEPS (8)
+static UINT8 eg_inc[19*RATE_STEPS]={
+
+/*cycle:0 1 2 3 4 5 6 7*/
+
+/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */
+/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */
+/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */
+/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */
+
+/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */
+/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */
+/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */
+/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */
+
+/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */
+/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */
+/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */
+/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */
+
+/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */
+/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */
+/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */
+/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */
+
+/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */
+/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */
+/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */
+};
+
+
+#define O(a) (a*RATE_STEPS)
+
+/*note that there is no O(17) in this table - it's directly in the code */
+static UINT8 eg_rate_select[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */
+/* 32 dummy (infinite time) rates */
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
+
+/* rates 00-11 */
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+
+/* rate 12 */
+O( 4),O( 5),O( 6),O( 7),
+
+/* rate 13 */
+O( 8),O( 9),O(10),O(11),
+
+/* rate 14 */
+O(12),O(13),O(14),O(15),
+
+/* rate 15 */
+O(16),O(16),O(16),O(16),
+
+/* 32 dummy rates (same as 15 3) */
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16)
+
+};
+#undef O
+
+/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/
+/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */
+/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */
+
+#define O(a) (a*1)
+static UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */
+/* 32 infinite time rates */
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+
+
+/* rates 00-11 */
+O(11),O(11),O(11),O(11),
+O(10),O(10),O(10),O(10),
+O( 9),O( 9),O( 9),O( 9),
+O( 8),O( 8),O( 8),O( 8),
+O( 7),O( 7),O( 7),O( 7),
+O( 6),O( 6),O( 6),O( 6),
+O( 5),O( 5),O( 5),O( 5),
+O( 4),O( 4),O( 4),O( 4),
+O( 3),O( 3),O( 3),O( 3),
+O( 2),O( 2),O( 2),O( 2),
+O( 1),O( 1),O( 1),O( 1),
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 12 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 13 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 14 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 15 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* 32 dummy rates (same as 15 3) */
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0)
+
+};
+#undef O
+
+/* DT2 defines offset in cents from base note
+*
+* This table defines offset in frequency-deltas table.
+* User's Manual page 22
+*
+* Values below were calculated using formula: value = orig.val / 1.5625
+*
+* DT2=0 DT2=1 DT2=2 DT2=3
+* 0 600 781 950
+*/
+static UINT32 dt2_tab[4] = { 0, 384, 500, 608 };
+
+/* DT1 defines offset in Hertz from base note
+* This table is converted while initialization...
+* Detune table shown in YM2151 User's Manual is wrong (verified on the real chip)
+*/
+
+static UINT8 dt1_tab[4*32] = { /* 4*32 DT1 values */
+/* DT1=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,
+
+/* DT1=1 */
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
+
+/* DT1=2 */
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
+ 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16,
+
+/* DT1=3 */
+ 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
+ 8, 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22
+};
+
+static UINT16 phaseinc_rom[768]={
+1299,1300,1301,1302,1303,1304,1305,1306,1308,1309,1310,1311,1313,1314,1315,1316,
+1318,1319,1320,1321,1322,1323,1324,1325,1327,1328,1329,1330,1332,1333,1334,1335,
+1337,1338,1339,1340,1341,1342,1343,1344,1346,1347,1348,1349,1351,1352,1353,1354,
+1356,1357,1358,1359,1361,1362,1363,1364,1366,1367,1368,1369,1371,1372,1373,1374,
+1376,1377,1378,1379,1381,1382,1383,1384,1386,1387,1388,1389,1391,1392,1393,1394,
+1396,1397,1398,1399,1401,1402,1403,1404,1406,1407,1408,1409,1411,1412,1413,1414,
+1416,1417,1418,1419,1421,1422,1423,1424,1426,1427,1429,1430,1431,1432,1434,1435,
+1437,1438,1439,1440,1442,1443,1444,1445,1447,1448,1449,1450,1452,1453,1454,1455,
+1458,1459,1460,1461,1463,1464,1465,1466,1468,1469,1471,1472,1473,1474,1476,1477,
+1479,1480,1481,1482,1484,1485,1486,1487,1489,1490,1492,1493,1494,1495,1497,1498,
+1501,1502,1503,1504,1506,1507,1509,1510,1512,1513,1514,1515,1517,1518,1520,1521,
+1523,1524,1525,1526,1528,1529,1531,1532,1534,1535,1536,1537,1539,1540,1542,1543,
+1545,1546,1547,1548,1550,1551,1553,1554,1556,1557,1558,1559,1561,1562,1564,1565,
+1567,1568,1569,1570,1572,1573,1575,1576,1578,1579,1580,1581,1583,1584,1586,1587,
+1590,1591,1592,1593,1595,1596,1598,1599,1601,1602,1604,1605,1607,1608,1609,1610,
+1613,1614,1615,1616,1618,1619,1621,1622,1624,1625,1627,1628,1630,1631,1632,1633,
+1637,1638,1639,1640,1642,1643,1645,1646,1648,1649,1651,1652,1654,1655,1656,1657,
+1660,1661,1663,1664,1666,1667,1669,1670,1672,1673,1675,1676,1678,1679,1681,1682,
+1685,1686,1688,1689,1691,1692,1694,1695,1697,1698,1700,1701,1703,1704,1706,1707,
+1709,1710,1712,1713,1715,1716,1718,1719,1721,1722,1724,1725,1727,1728,1730,1731,
+1734,1735,1737,1738,1740,1741,1743,1744,1746,1748,1749,1751,1752,1754,1755,1757,
+1759,1760,1762,1763,1765,1766,1768,1769,1771,1773,1774,1776,1777,1779,1780,1782,
+1785,1786,1788,1789,1791,1793,1794,1796,1798,1799,1801,1802,1804,1806,1807,1809,
+1811,1812,1814,1815,1817,1819,1820,1822,1824,1825,1827,1828,1830,1832,1833,1835,
+1837,1838,1840,1841,1843,1845,1846,1848,1850,1851,1853,1854,1856,1858,1859,1861,
+1864,1865,1867,1868,1870,1872,1873,1875,1877,1879,1880,1882,1884,1885,1887,1888,
+1891,1892,1894,1895,1897,1899,1900,1902,1904,1906,1907,1909,1911,1912,1914,1915,
+1918,1919,1921,1923,1925,1926,1928,1930,1932,1933,1935,1937,1939,1940,1942,1944,
+1946,1947,1949,1951,1953,1954,1956,1958,1960,1961,1963,1965,1967,1968,1970,1972,
+1975,1976,1978,1980,1982,1983,1985,1987,1989,1990,1992,1994,1996,1997,1999,2001,
+2003,2004,2006,2008,2010,2011,2013,2015,2017,2019,2021,2022,2024,2026,2028,2029,
+2032,2033,2035,2037,2039,2041,2043,2044,2047,2048,2050,2052,2054,2056,2058,2059,
+2062,2063,2065,2067,2069,2071,2073,2074,2077,2078,2080,2082,2084,2086,2088,2089,
+2092,2093,2095,2097,2099,2101,2103,2104,2107,2108,2110,2112,2114,2116,2118,2119,
+2122,2123,2125,2127,2129,2131,2133,2134,2137,2139,2141,2142,2145,2146,2148,2150,
+2153,2154,2156,2158,2160,2162,2164,2165,2168,2170,2172,2173,2176,2177,2179,2181,
+2185,2186,2188,2190,2192,2194,2196,2197,2200,2202,2204,2205,2208,2209,2211,2213,
+2216,2218,2220,2222,2223,2226,2227,2230,2232,2234,2236,2238,2239,2242,2243,2246,
+2249,2251,2253,2255,2256,2259,2260,2263,2265,2267,2269,2271,2272,2275,2276,2279,
+2281,2283,2285,2287,2288,2291,2292,2295,2297,2299,2301,2303,2304,2307,2308,2311,
+2315,2317,2319,2321,2322,2325,2326,2329,2331,2333,2335,2337,2338,2341,2342,2345,
+2348,2350,2352,2354,2355,2358,2359,2362,2364,2366,2368,2370,2371,2374,2375,2378,
+2382,2384,2386,2388,2389,2392,2393,2396,2398,2400,2402,2404,2407,2410,2411,2414,
+2417,2419,2421,2423,2424,2427,2428,2431,2433,2435,2437,2439,2442,2445,2446,2449,
+2452,2454,2456,2458,2459,2462,2463,2466,2468,2470,2472,2474,2477,2480,2481,2484,
+2488,2490,2492,2494,2495,2498,2499,2502,2504,2506,2508,2510,2513,2516,2517,2520,
+2524,2526,2528,2530,2531,2534,2535,2538,2540,2542,2544,2546,2549,2552,2553,2556,
+2561,2563,2565,2567,2568,2571,2572,2575,2577,2579,2581,2583,2586,2589,2590,2593
+};
+
+
+/*
+ Noise LFO waveform.
+
+ Here are just 256 samples out of much longer data.
+
+ It does NOT repeat every 256 samples on real chip and I wasnt able to find
+ the point where it repeats (even in strings as long as 131072 samples).
+
+ I only put it here because its better than nothing and perhaps
+ someone might be able to figure out the real algorithm.
+
+
+ Note that (due to the way the LFO output is calculated) it is quite
+ possible that two values: 0x80 and 0x00 might be wrong in this table.
+ To be exact:
+ some 0x80 could be 0x81 as well as some 0x00 could be 0x01.
+*/
+
+static UINT8 lfo_noise_waveform[256] = {
+0xFF,0xEE,0xD3,0x80,0x58,0xDA,0x7F,0x94,0x9E,0xE3,0xFA,0x00,0x4D,0xFA,0xFF,0x6A,
+0x7A,0xDE,0x49,0xF6,0x00,0x33,0xBB,0x63,0x91,0x60,0x51,0xFF,0x00,0xD8,0x7F,0xDE,
+0xDC,0x73,0x21,0x85,0xB2,0x9C,0x5D,0x24,0xCD,0x91,0x9E,0x76,0x7F,0x20,0xFB,0xF3,
+0x00,0xA6,0x3E,0x42,0x27,0x69,0xAE,0x33,0x45,0x44,0x11,0x41,0x72,0x73,0xDF,0xA2,
+
+0x32,0xBD,0x7E,0xA8,0x13,0xEB,0xD3,0x15,0xDD,0xFB,0xC9,0x9D,0x61,0x2F,0xBE,0x9D,
+0x23,0x65,0x51,0x6A,0x84,0xF9,0xC9,0xD7,0x23,0xBF,0x65,0x19,0xDC,0x03,0xF3,0x24,
+0x33,0xB6,0x1E,0x57,0x5C,0xAC,0x25,0x89,0x4D,0xC5,0x9C,0x99,0x15,0x07,0xCF,0xBA,
+0xC5,0x9B,0x15,0x4D,0x8D,0x2A,0x1E,0x1F,0xEA,0x2B,0x2F,0x64,0xA9,0x50,0x3D,0xAB,
+
+0x50,0x77,0xE9,0xC0,0xAC,0x6D,0x3F,0xCA,0xCF,0x71,0x7D,0x80,0xA6,0xFD,0xFF,0xB5,
+0xBD,0x6F,0x24,0x7B,0x00,0x99,0x5D,0xB1,0x48,0xB0,0x28,0x7F,0x80,0xEC,0xBF,0x6F,
+0x6E,0x39,0x90,0x42,0xD9,0x4E,0x2E,0x12,0x66,0xC8,0xCF,0x3B,0x3F,0x10,0x7D,0x79,
+0x00,0xD3,0x1F,0x21,0x93,0x34,0xD7,0x19,0x22,0xA2,0x08,0x20,0xB9,0xB9,0xEF,0x51,
+
+0x99,0xDE,0xBF,0xD4,0x09,0x75,0xE9,0x8A,0xEE,0xFD,0xE4,0x4E,0x30,0x17,0xDF,0xCE,
+0x11,0xB2,0x28,0x35,0xC2,0x7C,0x64,0xEB,0x91,0x5F,0x32,0x0C,0x6E,0x00,0xF9,0x92,
+0x19,0xDB,0x8F,0xAB,0xAE,0xD6,0x12,0xC4,0x26,0x62,0xCE,0xCC,0x0A,0x03,0xE7,0xDD,
+0xE2,0x4D,0x8A,0xA6,0x46,0x95,0x0F,0x8F,0xF5,0x15,0x97,0x32,0xD4,0x28,0x1E,0x55
+};
+
+
+
+/* these variables stay here for speedup purposes only */
+static YM2151 * PSG;
+static signed int chanout[8];
+static signed int m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */
+static signed int mem; /* one sample delay memory */
+
+
+/* save output as raw 16-bit sample */
+/* #define SAVE_SAMPLE */
+/* #define SAVE_SEPARATE_CHANNELS */
+#if defined SAVE_SAMPLE || defined SAVE_SEPARATE_CHANNELS
+static FILE *sample[9];
+#endif
+
+
+
+
+static void init_tables(void)
+{
+ signed int i,x,n;
+ double o,m;
+
+ for (x=0; x<TL_RES_LEN; x++)
+ {
+ m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0);
+ m = floor(m);
+
+ /* we never reach (1<<16) here due to the (x+1) */
+ /* result fits within 16 bits at maximum */
+
+ n = (int)m; /* 16 bits here */
+ n >>= 4; /* 12 bits here */
+ if (n&1) /* round to closest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+ /* 11 bits here (rounded) */
+ n <<= 2; /* 13 bits here (as in real chip) */
+ tl_tab[ x*2 + 0 ] = n;
+ tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ];
+
+ for (i=1; i<13; i++)
+ {
+ tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i;
+ tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ];
+ }
+ #if 0
+ logerror("tl %04i", x*2);
+ for (i=0; i<13; i++)
+ logerror(", [%02i] %4i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ]);
+ logerror("\n");
+ #endif
+ }
+ /*logerror("TL_TAB_LEN = %i (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/
+ /*logerror("ENV_QUIET= %i\n",ENV_QUIET );*/
+
+
+ for (i=0; i<SIN_LEN; i++)
+ {
+ /* non-standard sinus */
+ m = sin( ((i*2)+1) * M_PI / SIN_LEN ); /* verified on the real chip */
+
+ /* we never reach zero here due to ((i*2)+1) */
+
+ if (m>0.0)
+ o = 8*log(1.0/m)/log(2); /* convert to 'decibels' */
+ else
+ o = 8*log(-1.0/m)/log(2); /* convert to 'decibels' */
+
+ o = o / (ENV_STEP/4);
+
+ n = (int)(2.0*o);
+ if (n&1) /* round to closest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+
+ sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 );
+ /*logerror("sin [0x%4x]= %4i (tl_tab value=%8x)\n", i, sin_tab[i],tl_tab[sin_tab[i]]);*/
+ }
+
+
+ /* calculate d1l_tab table */
+ for (i=0; i<16; i++)
+ {
+ m = (i!=15 ? i : i+16) * (4.0/ENV_STEP); /* every 3 'dB' except for all bits = 1 = 45+48 'dB' */
+ d1l_tab[i] = m;
+ /*logerror("d1l_tab[%02x]=%08x\n",i,d1l_tab[i] );*/
+ }
+
+#ifdef SAVE_SAMPLE
+ sample[8]=fopen("sampsum.pcm","wb");
+#endif
+#ifdef SAVE_SEPARATE_CHANNELS
+ sample[0]=fopen("samp0.pcm","wb");
+ sample[1]=fopen("samp1.pcm","wb");
+ sample[2]=fopen("samp2.pcm","wb");
+ sample[3]=fopen("samp3.pcm","wb");
+ sample[4]=fopen("samp4.pcm","wb");
+ sample[5]=fopen("samp5.pcm","wb");
+ sample[6]=fopen("samp6.pcm","wb");
+ sample[7]=fopen("samp7.pcm","wb");
+#endif
+}
+
+
+static void init_chip_tables(YM2151 *chip)
+{
+ int i,j;
+ double mult,phaseinc,Hz;
+ double scaler;
+ attotime pom;
+
+ scaler = ( (double)chip->clock / 64.0 ) / ( (double)chip->sampfreq );
+ /*logerror("scaler = %20.15f\n", scaler);*/
+
+
+ /* this loop calculates Hertz values for notes from c-0 to b-7 */
+ /* including 64 'cents' (100/64 that is 1.5625 of real cent) per note */
+ /* i*100/64/1200 is equal to i/768 */
+
+ /* real chip works with 10 bits fixed point values (10.10) */
+ mult = (1<<(FREQ_SH-10)); /* -10 because phaseinc_rom table values are already in 10.10 format */
+
+ for (i=0; i<768; i++)
+ {
+ /* 3.4375 Hz is note A; C# is 4 semitones higher */
+ Hz = 1000;
+#if 0
+/* Hz is close, but not perfect */
+ //Hz = scaler * 3.4375 * pow (2, (i + 4 * 64 ) / 768.0 );
+ /* calculate phase increment */
+ phaseinc = (Hz*SIN_LEN) / (double)chip->sampfreq;
+#endif
+
+ phaseinc = phaseinc_rom[i]; /* real chip phase increment */
+ phaseinc *= scaler; /* adjust */
+
+
+ /* octave 2 - reference octave */
+ chip->freq[ 768+2*768+i ] = ((int)(phaseinc*mult)) & 0xffffffc0; /* adjust to X.10 fixed point */
+ /* octave 0 and octave 1 */
+ for (j=0; j<2; j++)
+ {
+ chip->freq[768 + j*768 + i] = (chip->freq[ 768+2*768+i ] >> (2-j) ) & 0xffffffc0; /* adjust to X.10 fixed point */
+ }
+ /* octave 3 to 7 */
+ for (j=3; j<8; j++)
+ {
+ chip->freq[768 + j*768 + i] = chip->freq[ 768+2*768+i ] << (j-2);
+ }
+
+ #if 0
+ pom = (double)chip->freq[ 768+2*768+i ] / ((double)(1<<FREQ_SH));
+ pom = pom * (double)chip->sampfreq / (double)SIN_LEN;
+ logerror("1freq[%4i][%08x]= real %20.15f Hz emul %20.15f Hz\n", i, chip->freq[ 768+2*768+i ], Hz, pom);
+ #endif
+ }
+
+ /* octave -1 (all equal to: oct 0, _KC_00_, _KF_00_) */
+ for (i=0; i<768; i++)
+ {
+ chip->freq[ 0*768 + i ] = chip->freq[1*768+0];
+ }
+
+ /* octave 8 and 9 (all equal to: oct 7, _KC_14_, _KF_63_) */
+ for (j=8; j<10; j++)
+ {
+ for (i=0; i<768; i++)
+ {
+ chip->freq[768+ j*768 + i ] = chip->freq[768 + 8*768 -1];
+ }
+ }
+
+#if 0
+ for (i=0; i<11*768; i++)
+ {
+ pom = (double)chip->freq[i] / ((double)(1<<FREQ_SH));
+ pom = pom * (double)chip->sampfreq / (double)SIN_LEN;
+ logerror("freq[%4i][%08x]= emul %20.15f Hz\n", i, chip->freq[i], pom);
+ }
+#endif
+
+ mult = (1<<FREQ_SH);
+ for (j=0; j<4; j++)
+ {
+ for (i=0; i<32; i++)
+ {
+ Hz = ( (double)dt1_tab[j*32+i] * ((double)chip->clock/64.0) ) / (double)(1<<20);
+
+ /*calculate phase increment*/
+ phaseinc = (Hz*SIN_LEN) / (double)chip->sampfreq;
+
+ /*positive and negative values*/
+ chip->dt1_freq[ (j+0)*32 + i ] = phaseinc * mult;
+ chip->dt1_freq[ (j+4)*32 + i ] = -chip->dt1_freq[ (j+0)*32 + i ];
+
+#if 0
+ {
+ int x = j*32 + i;
+ pom = (double)chip->dt1_freq[x] / mult;
+ pom = pom * (double)chip->sampfreq / (double)SIN_LEN;
+ logerror("DT1(%03i)[%02i %02i][%08x]= real %19.15f Hz emul %19.15f Hz\n",
+ x, j, i, chip->dt1_freq[x], Hz, pom);
+ }
+#endif
+ }
+ }
+
+
+ /* calculate timers' deltas */
+ /* User's Manual pages 15,16 */
+ mult = (1<<TIMER_SH);
+ for (i=0; i<1024; i++)
+ {
+ /* ASG 980324: changed to compute both tim_A_tab and timer_A_time */
+ pom= attotime_mul(ATTOTIME_IN_HZ(chip->clock), 64 * (1024 - i));
+ #ifdef USE_MAME_TIMERS
+ chip->timer_A_time[i] = pom;
+ #else
+ chip->tim_A_tab[i] = attotime_to_double(pom) * (double)chip->sampfreq * mult; /* number of samples that timer period takes (fixed point) */
+ #endif
+ }
+ for (i=0; i<256; i++)
+ {
+ /* ASG 980324: changed to compute both tim_B_tab and timer_B_time */
+ pom= attotime_mul(ATTOTIME_IN_HZ(chip->clock), 1024 * (256 - i));
+ #ifdef USE_MAME_TIMERS
+ chip->timer_B_time[i] = pom;
+ #else
+ chip->tim_B_tab[i] = attotime_to_double(pom) * (double)chip->sampfreq * mult; /* number of samples that timer period takes (fixed point) */
+ #endif
+ }
+
+ /* calculate noise periods table */
+ scaler = ( (double)chip->clock / 64.0 ) / ( (double)chip->sampfreq );
+ for (i=0; i<32; i++)
+ {
+ j = (i!=31 ? i : 30); /* rate 30 and 31 are the same */
+ j = 32-j;
+ j = (65536.0 / (double)(j*32.0)); /* number of samples per one shift of the shift register */
+ /*chip->noise_tab[i] = j * 64;*/ /* number of chip clock cycles per one shift */
+ chip->noise_tab[i] = j * 64 * scaler;
+ /*logerror("noise_tab[%02x]=%08x\n", i, chip->noise_tab[i]);*/
+ }
+}
+
+#define KEY_ON(op, key_set){ \
+ if (!(op)->key) \
+ { \
+ (op)->phase = 0; /* clear phase */ \
+ (op)->state = EG_ATT; /* KEY ON = attack */ \
+ (op)->volume += (~(op)->volume * \
+ (eg_inc[(op)->eg_sel_ar + ((PSG->eg_cnt>>(op)->eg_sh_ar)&7)]) \
+ ) >>4; \
+ if ((op)->volume <= MIN_ATT_INDEX) \
+ { \
+ (op)->volume = MIN_ATT_INDEX; \
+ (op)->state = EG_DEC; \
+ } \
+ } \
+ (op)->key |= key_set; \
+}
+
+#define KEY_OFF(op, key_clr){ \
+ if ((op)->key) \
+ { \
+ (op)->key &= key_clr; \
+ if (!(op)->key) \
+ { \
+ if ((op)->state>EG_REL) \
+ (op)->state = EG_REL;/* KEY OFF = release */\
+ } \
+ } \
+}
+
+INLINE void envelope_KONKOFF(YM2151Operator * op, int v)
+{
+ if (v&0x08) /* M1 */
+ KEY_ON (op+0, 1)
+ else
+ KEY_OFF(op+0,~1)
+
+ if (v&0x20) /* M2 */
+ KEY_ON (op+1, 1)
+ else
+ KEY_OFF(op+1,~1)
+
+ if (v&0x10) /* C1 */
+ KEY_ON (op+2, 1)
+ else
+ KEY_OFF(op+2,~1)
+
+ if (v&0x40) /* C2 */
+ KEY_ON (op+3, 1)
+ else
+ KEY_OFF(op+3,~1)
+}
+
+
+#ifdef USE_MAME_TIMERS
+
+static TIMER_CALLBACK_PTR( irqAon_callback )
+{
+ YM2151 *chip = param;
+ int oldstate = chip->irqlinestate;
+
+ chip->irqlinestate |= 1;
+
+ if (oldstate == 0 && chip->irqhandler) (*chip->irqhandler)(1);
+}
+
+static TIMER_CALLBACK_PTR( irqBon_callback )
+{
+ YM2151 *chip = param;
+ int oldstate = chip->irqlinestate;
+
+ chip->irqlinestate |= 2;
+
+ if (oldstate == 0 && chip->irqhandler) (*chip->irqhandler)(1);
+}
+
+static TIMER_CALLBACK_PTR( irqAoff_callback )
+{
+ YM2151 *chip = param;
+ int oldstate = chip->irqlinestate;
+
+ chip->irqlinestate &= ~1;
+
+ if (oldstate == 1 && chip->irqhandler) (*chip->irqhandler)(0);
+}
+
+static TIMER_CALLBACK_PTR( irqBoff_callback )
+{
+ YM2151 *chip = param;
+ int oldstate = chip->irqlinestate;
+
+ chip->irqlinestate &= ~2;
+
+ if (oldstate == 2 && chip->irqhandler) (*chip->irqhandler)(0);
+}
+
+static TIMER_CALLBACK_PTR( timer_callback_a )
+{
+ YM2151 *chip = param;
+ timer_adjust_ptr(chip->timer_A, chip->timer_A_time[ chip->timer_A_index ], attotime_zero);
+ chip->timer_A_index_old = chip->timer_A_index;
+ if (chip->irq_enable & 0x04)
+ {
+ chip->status |= 1;
+ timer_set_ptr(attotime_zero,chip,irqAon_callback);
+ }
+ if (chip->irq_enable & 0x80)
+ chip->csm_req = 2; /* request KEY ON / KEY OFF sequence */
+}
+static TIMER_CALLBACK_PTR( timer_callback_b )
+{
+ YM2151 *chip = param;
+ timer_adjust_ptr(chip->timer_B, chip->timer_B_time[ chip->timer_B_index ], attotime_zero);
+ chip->timer_B_index_old = chip->timer_B_index;
+ if (chip->irq_enable & 0x08)
+ {
+ chip->status |= 2;
+ timer_set_ptr(attotime_zero,chip,irqBon_callback);
+ }
+}
+#if 0
+static TIMER_CALLBACK_PTR( timer_callback_chip_busy )
+{
+ YM2151 *chip = param;
+ chip->status &= 0x7f; /* reset busy flag */
+}
+#endif
+#endif
+
+
+
+
+
+
+INLINE void set_connect( YM2151Operator *om1, int cha, int v)
+{
+ YM2151Operator *om2 = om1+1;
+ YM2151Operator *oc1 = om1+2;
+
+ /* set connect algorithm */
+
+ /* MEM is simply one sample delay */
+
+ switch( v&7 )
+ {
+ case 0:
+ /* M1---C1---MEM---M2---C2---OUT */
+ om1->connect = &c1;
+ oc1->connect = &mem;
+ om2->connect = &c2;
+ om1->mem_connect = &m2;
+ break;
+
+ case 1:
+ /* M1------+-MEM---M2---C2---OUT */
+ /* C1-+ */
+ om1->connect = &mem;
+ oc1->connect = &mem;
+ om2->connect = &c2;
+ om1->mem_connect = &m2;
+ break;
+
+ case 2:
+ /* M1-----------------+-C2---OUT */
+ /* C1---MEM---M2-+ */
+ om1->connect = &c2;
+ oc1->connect = &mem;
+ om2->connect = &c2;
+ om1->mem_connect = &m2;
+ break;
+
+ case 3:
+ /* M1---C1---MEM------+-C2---OUT */
+ /* M2-+ */
+ om1->connect = &c1;
+ oc1->connect = &mem;
+ om2->connect = &c2;
+ om1->mem_connect = &c2;
+ break;
+
+ case 4:
+ /* M1---C1-+-OUT */
+ /* M2---C2-+ */
+ /* MEM: not used */
+ om1->connect = &c1;
+ oc1->connect = &chanout[cha];
+ om2->connect = &c2;
+ om1->mem_connect = &mem; /* store it anywhere where it will not be used */
+ break;
+
+ case 5:
+ /* +----C1----+ */
+ /* M1-+-MEM---M2-+-OUT */
+ /* +----C2----+ */
+ om1->connect = 0; /* special mark */
+ oc1->connect = &chanout[cha];
+ om2->connect = &chanout[cha];
+ om1->mem_connect = &m2;
+ break;
+
+ case 6:
+ /* M1---C1-+ */
+ /* M2-+-OUT */
+ /* C2-+ */
+ /* MEM: not used */
+ om1->connect = &c1;
+ oc1->connect = &chanout[cha];
+ om2->connect = &chanout[cha];
+ om1->mem_connect = &mem; /* store it anywhere where it will not be used */
+ break;
+
+ case 7:
+ /* M1-+ */
+ /* C1-+-OUT */
+ /* M2-+ */
+ /* C2-+ */
+ /* MEM: not used*/
+ om1->connect = &chanout[cha];
+ oc1->connect = &chanout[cha];
+ om2->connect = &chanout[cha];
+ om1->mem_connect = &mem; /* store it anywhere where it will not be used */
+ break;
+ }
+}
+
+
+INLINE void refresh_EG(YM2151Operator * op)
+{
+ UINT32 kc;
+ UINT32 v;
+
+ kc = op->kc;
+
+ /* v = 32 + 2*RATE + RKS = max 126 */
+
+ v = kc >> op->ks;
+ if ((op->ar+v) < 32+62)
+ {
+ op->eg_sh_ar = eg_rate_shift [op->ar + v ];
+ op->eg_sel_ar = eg_rate_select[op->ar + v ];
+ }
+ else
+ {
+ op->eg_sh_ar = 0;
+ op->eg_sel_ar = 17*RATE_STEPS;
+ }
+ op->eg_sh_d1r = eg_rate_shift [op->d1r + v];
+ op->eg_sel_d1r= eg_rate_select[op->d1r + v];
+ op->eg_sh_d2r = eg_rate_shift [op->d2r + v];
+ op->eg_sel_d2r= eg_rate_select[op->d2r + v];
+ op->eg_sh_rr = eg_rate_shift [op->rr + v];
+ op->eg_sel_rr = eg_rate_select[op->rr + v];
+
+
+ op+=1;
+
+ v = kc >> op->ks;
+ if ((op->ar+v) < 32+62)
+ {
+ op->eg_sh_ar = eg_rate_shift [op->ar + v ];
+ op->eg_sel_ar = eg_rate_select[op->ar + v ];
+ }
+ else
+ {
+ op->eg_sh_ar = 0;
+ op->eg_sel_ar = 17*RATE_STEPS;
+ }
+ op->eg_sh_d1r = eg_rate_shift [op->d1r + v];
+ op->eg_sel_d1r= eg_rate_select[op->d1r + v];
+ op->eg_sh_d2r = eg_rate_shift [op->d2r + v];
+ op->eg_sel_d2r= eg_rate_select[op->d2r + v];
+ op->eg_sh_rr = eg_rate_shift [op->rr + v];
+ op->eg_sel_rr = eg_rate_select[op->rr + v];
+
+ op+=1;
+
+ v = kc >> op->ks;
+ if ((op->ar+v) < 32+62)
+ {
+ op->eg_sh_ar = eg_rate_shift [op->ar + v ];
+ op->eg_sel_ar = eg_rate_select[op->ar + v ];
+ }
+ else
+ {
+ op->eg_sh_ar = 0;
+ op->eg_sel_ar = 17*RATE_STEPS;
+ }
+ op->eg_sh_d1r = eg_rate_shift [op->d1r + v];
+ op->eg_sel_d1r= eg_rate_select[op->d1r + v];
+ op->eg_sh_d2r = eg_rate_shift [op->d2r + v];
+ op->eg_sel_d2r= eg_rate_select[op->d2r + v];
+ op->eg_sh_rr = eg_rate_shift [op->rr + v];
+ op->eg_sel_rr = eg_rate_select[op->rr + v];
+
+ op+=1;
+
+ v = kc >> op->ks;
+ if ((op->ar+v) < 32+62)
+ {
+ op->eg_sh_ar = eg_rate_shift [op->ar + v ];
+ op->eg_sel_ar = eg_rate_select[op->ar + v ];
+ }
+ else
+ {
+ op->eg_sh_ar = 0;
+ op->eg_sel_ar = 17*RATE_STEPS;
+ }
+ op->eg_sh_d1r = eg_rate_shift [op->d1r + v];
+ op->eg_sel_d1r= eg_rate_select[op->d1r + v];
+ op->eg_sh_d2r = eg_rate_shift [op->d2r + v];
+ op->eg_sel_d2r= eg_rate_select[op->d2r + v];
+ op->eg_sh_rr = eg_rate_shift [op->rr + v];
+ op->eg_sel_rr = eg_rate_select[op->rr + v];
+}
+
+
+/* write a register on YM2151 chip number 'n' */
+void YM2151WriteReg(void *_chip, int r, int v)
+{
+ YM2151 *chip = _chip;
+ YM2151Operator *op = &chip->oper[ (r&0x07)*4+((r&0x18)>>3) ];
+
+ /* adjust bus to 8 bits */
+ r &= 0xff;
+ v &= 0xff;
+
+#if 0
+ /* There is no info on what YM2151 really does when busy flag is set */
+ if ( chip->status & 0x80 ) return;
+ timer_set_ptr ( attotime_mul(ATTOTIME_IN_HZ(chip->clock), 64), chip, timer_callback_chip_busy);
+ chip->status |= 0x80; /* set busy flag for 64 chip clock cycles */
+#endif
+
+#ifdef LOG_CYM_FILE
+ if ((cymfile) && (r!=0) )
+ {
+ fputc( (unsigned char)r, cymfile );
+ fputc( (unsigned char)v, cymfile );
+ }
+#endif
+
+
+ switch(r & 0xe0){
+ case 0x00:
+ switch(r){
+ case 0x01: /* LFO reset(bit 1), Test Register (other bits) */
+ chip->test = v;
+ if (v&2) chip->lfo_phase = 0;
+ break;
+
+ case 0x08:
+ PSG = chip; /* PSG is used in KEY_ON macro */
+ envelope_KONKOFF(&chip->oper[ (v&7)*4 ], v );
+ break;
+
+ case 0x0f: /* noise mode enable, noise period */
+ chip->noise = v;
+ chip->noise_f = chip->noise_tab[ v & 0x1f ];
+ break;
+
+ case 0x10: /* timer A hi */
+ chip->timer_A_index = (chip->timer_A_index & 0x003) | (v<<2);
+ break;
+
+ case 0x11: /* timer A low */
+ chip->timer_A_index = (chip->timer_A_index & 0x3fc) | (v & 3);
+ break;
+
+ case 0x12: /* timer B */
+ chip->timer_B_index = v;
+ break;
+
+ case 0x14: /* CSM, irq flag reset, irq enable, timer start/stop */
+
+ chip->irq_enable = v; /* bit 3-timer B, bit 2-timer A, bit 7 - CSM */
+
+ if (v&0x10) /* reset timer A irq flag */
+ {
+#ifdef USE_MAME_TIMERS
+ chip->status &= ~1;
+ timer_set_ptr(attotime_zero,chip,irqAoff_callback);
+#else
+ int oldstate = chip->status & 3;
+ chip->status &= ~1;
+ if ((oldstate==1) && (chip->irqhandler)) (*chip->irqhandler)(0);
+#endif
+ }
+
+ if (v&0x20) /* reset timer B irq flag */
+ {
+#ifdef USE_MAME_TIMERS
+ chip->status &= ~2;
+ timer_set_ptr(attotime_zero,chip,irqBoff_callback);
+#else
+ int oldstate = chip->status & 3;
+ chip->status &= ~2;
+ if ((oldstate==2) && (chip->irqhandler)) (*chip->irqhandler)(0);
+#endif
+ }
+
+ if (v&0x02){ /* load and start timer B */
+ #ifdef USE_MAME_TIMERS
+ /* ASG 980324: added a real timer */
+ /* start timer _only_ if it wasn't already started (it will reload time value next round) */
+ if (!timer_enable(chip->timer_B, 1))
+ {
+ timer_adjust_ptr(chip->timer_B, chip->timer_B_time[ chip->timer_B_index ], attotime_zero);
+ chip->timer_B_index_old = chip->timer_B_index;
+ }
+ #else
+ if (!chip->tim_B)
+ {
+ chip->tim_B = 1;
+ chip->tim_B_val = chip->tim_B_tab[ chip->timer_B_index ];
+ }
+ #endif
+ }else{ /* stop timer B */
+ #ifdef USE_MAME_TIMERS
+ /* ASG 980324: added a real timer */
+ timer_enable(chip->timer_B, 0);
+ #else
+ chip->tim_B = 0;
+ #endif
+ }
+
+ if (v&0x01){ /* load and start timer A */
+ #ifdef USE_MAME_TIMERS
+ /* ASG 980324: added a real timer */
+ /* start timer _only_ if it wasn't already started (it will reload time value next round) */
+ if (!timer_enable(chip->timer_A, 1))
+ {
+ timer_adjust_ptr(chip->timer_A, chip->timer_A_time[ chip->timer_A_index ], attotime_zero);
+ chip->timer_A_index_old = chip->timer_A_index;
+ }
+ #else
+ if (!chip->tim_A)
+ {
+ chip->tim_A = 1;
+ chip->tim_A_val = chip->tim_A_tab[ chip->timer_A_index ];
+ }
+ #endif
+ }else{ /* stop timer A */
+ #ifdef USE_MAME_TIMERS
+ /* ASG 980324: added a real timer */
+ timer_enable(chip->timer_A, 0);
+ #else
+ chip->tim_A = 0;
+ #endif
+ }
+ break;
+
+ case 0x18: /* LFO frequency */
+ {
+ chip->lfo_overflow = ( 1 << ((15-(v>>4))+3) ) * (1<<LFO_SH);
+ chip->lfo_counter_add = 0x10 + (v & 0x0f);
+ }
+ break;
+
+ case 0x19: /* PMD (bit 7==1) or AMD (bit 7==0) */
+ if (v&0x80)
+ chip->pmd = v & 0x7f;
+ else
+ chip->amd = v & 0x7f;
+ break;
+
+ case 0x1b: /* CT2, CT1, LFO waveform */
+ chip->ct = v >> 6;
+ chip->lfo_wsel = v & 3;
+ if (chip->porthandler) (*chip->porthandler)(0 , chip->ct );
+ break;
+
+ default:
+ logerror("YM2151 Write %02x to undocumented register #%02x\n",v,r);
+ break;
+ }
+ break;
+
+ case 0x20:
+ op = &chip->oper[ (r&7) * 4 ];
+ switch(r & 0x18){
+ case 0x00: /* RL enable, Feedback, Connection */
+ op->fb_shift = ((v>>3)&7) ? ((v>>3)&7)+6:0;
+ chip->pan[ (r&7)*2 ] = (v & 0x40) ? ~0 : 0;
+ chip->pan[ (r&7)*2 +1 ] = (v & 0x80) ? ~0 : 0;
+ chip->connect[r&7] = v&7;
+ set_connect(op, r&7, v&7);
+ break;
+
+ case 0x08: /* Key Code */
+ v &= 0x7f;
+ if (v != op->kc)
+ {
+ UINT32 kc, kc_channel;
+
+ kc_channel = (v - (v>>2))*64;
+ kc_channel += 768;
+ kc_channel |= (op->kc_i & 63);
+
+ (op+0)->kc = v;
+ (op+0)->kc_i = kc_channel;
+ (op+1)->kc = v;
+ (op+1)->kc_i = kc_channel;
+ (op+2)->kc = v;
+ (op+2)->kc_i = kc_channel;
+ (op+3)->kc = v;
+ (op+3)->kc_i = kc_channel;
+
+ kc = v>>2;
+
+ (op+0)->dt1 = chip->dt1_freq[ (op+0)->dt1_i + kc ];
+ (op+0)->freq = ( (chip->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1;
+
+ (op+1)->dt1 = chip->dt1_freq[ (op+1)->dt1_i + kc ];
+ (op+1)->freq = ( (chip->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1;
+
+ (op+2)->dt1 = chip->dt1_freq[ (op+2)->dt1_i + kc ];
+ (op+2)->freq = ( (chip->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1;
+
+ (op+3)->dt1 = chip->dt1_freq[ (op+3)->dt1_i + kc ];
+ (op+3)->freq = ( (chip->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1;
+
+ refresh_EG( op );
+ }
+ break;
+
+ case 0x10: /* Key Fraction */
+ v >>= 2;
+ if (v != (op->kc_i & 63))
+ {
+ UINT32 kc_channel;
+
+ kc_channel = v;
+ kc_channel |= (op->kc_i & ~63);
+
+ (op+0)->kc_i = kc_channel;
+ (op+1)->kc_i = kc_channel;
+ (op+2)->kc_i = kc_channel;
+ (op+3)->kc_i = kc_channel;
+
+ (op+0)->freq = ( (chip->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1;
+ (op+1)->freq = ( (chip->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1;
+ (op+2)->freq = ( (chip->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1;
+ (op+3)->freq = ( (chip->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1;
+ }
+ break;
+
+ case 0x18: /* PMS, AMS */
+ op->pms = (v>>4) & 7;
+ op->ams = (v & 3);
+ break;
+ }
+ break;
+
+ case 0x40: /* DT1, MUL */
+ {
+ UINT32 olddt1_i = op->dt1_i;
+ UINT32 oldmul = op->mul;
+
+ op->dt1_i = (v&0x70)<<1;
+ op->mul = (v&0x0f) ? (v&0x0f)<<1: 1;
+
+ if (olddt1_i != op->dt1_i)
+ op->dt1 = chip->dt1_freq[ op->dt1_i + (op->kc>>2) ];
+
+ if ( (olddt1_i != op->dt1_i) || (oldmul != op->mul) )
+ op->freq = ( (chip->freq[ op->kc_i + op->dt2 ] + op->dt1) * op->mul ) >> 1;
+ }
+ break;
+
+ case 0x60: /* TL */
+ op->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */
+ break;
+
+ case 0x80: /* KS, AR */
+ {
+ UINT32 oldks = op->ks;
+ UINT32 oldar = op->ar;
+
+ op->ks = 5-(v>>6);
+ op->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
+
+ if ( (op->ar != oldar) || (op->ks != oldks) )
+ {
+ if ((op->ar + (op->kc>>op->ks)) < 32+62)
+ {
+ op->eg_sh_ar = eg_rate_shift [op->ar + (op->kc>>op->ks) ];
+ op->eg_sel_ar = eg_rate_select[op->ar + (op->kc>>op->ks) ];
+ }
+ else
+ {
+ op->eg_sh_ar = 0;
+ op->eg_sel_ar = 17*RATE_STEPS;
+ }
+ }
+
+ if (op->ks != oldks)
+ {
+ op->eg_sh_d1r = eg_rate_shift [op->d1r + (op->kc>>op->ks) ];
+ op->eg_sel_d1r= eg_rate_select[op->d1r + (op->kc>>op->ks) ];
+ op->eg_sh_d2r = eg_rate_shift [op->d2r + (op->kc>>op->ks) ];
+ op->eg_sel_d2r= eg_rate_select[op->d2r + (op->kc>>op->ks) ];
+ op->eg_sh_rr = eg_rate_shift [op->rr + (op->kc>>op->ks) ];
+ op->eg_sel_rr = eg_rate_select[op->rr + (op->kc>>op->ks) ];
+ }
+ }
+ break;
+
+ case 0xa0: /* LFO AM enable, D1R */
+ op->AMmask = (v&0x80) ? ~0 : 0;
+ op->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
+ op->eg_sh_d1r = eg_rate_shift [op->d1r + (op->kc>>op->ks) ];
+ op->eg_sel_d1r= eg_rate_select[op->d1r + (op->kc>>op->ks) ];
+ break;
+
+ case 0xc0: /* DT2, D2R */
+ {
+ UINT32 olddt2 = op->dt2;
+ op->dt2 = dt2_tab[ v>>6 ];
+ if (op->dt2 != olddt2)
+ op->freq = ( (chip->freq[ op->kc_i + op->dt2 ] + op->dt1) * op->mul ) >> 1;
+ }
+ op->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
+ op->eg_sh_d2r = eg_rate_shift [op->d2r + (op->kc>>op->ks) ];
+ op->eg_sel_d2r= eg_rate_select[op->d2r + (op->kc>>op->ks) ];
+ break;
+
+ case 0xe0: /* D1L, RR */
+ op->d1l = d1l_tab[ v>>4 ];
+ op->rr = 34 + ((v&0x0f)<<2);
+ op->eg_sh_rr = eg_rate_shift [op->rr + (op->kc>>op->ks) ];
+ op->eg_sel_rr = eg_rate_select[op->rr + (op->kc>>op->ks) ];
+ break;
+ }
+}
+
+
+#ifdef LOG_CYM_FILE
+static TIMER_CALLBACK( cymfile_callback )
+{
+ if (cymfile)
+ fputc( (unsigned char)0, cymfile );
+}
+#endif
+
+
+int YM2151ReadStatus( void *_chip )
+{
+ YM2151 *chip = _chip;
+ return chip->status;
+}
+
+
+
+//#ifdef USE_MAME_TIMERS
+#if 1 // disabled for now due to crashing with winalloc.c (ERROR_NOT_ENOUGH_MEMORY)
+/*
+* state save support for MAME
+*/
+void YM2151Postload(void *chip)
+{
+ YM2151 *YM2151_chip = (YM2151 *)chip;
+ int j;
+
+ for (j=0; j<8; j++)
+ set_connect(&YM2151_chip->oper[j*4], j, YM2151_chip->connect[j]);
+}
+
+static void ym2151_state_save_register( YM2151 *chip, int sndindex )
+{
+ int j;
+ char buf1[20];
+
+ /* save all 32 operators of chip #i */
+ for (j=0; j<32; j++)
+ {
+ YM2151Operator *op;
+
+ sprintf(buf1,"YM2151.op%02i",j);
+ op = &chip->oper[(j&7)*4+(j>>3)];
+
+ state_save_register_item(buf1, sndindex, op->phase);
+ state_save_register_item(buf1, sndindex, op->freq);
+ state_save_register_item(buf1, sndindex, op->dt1);
+ state_save_register_item(buf1, sndindex, op->mul);
+ state_save_register_item(buf1, sndindex, op->dt1_i);
+ state_save_register_item(buf1, sndindex, op->dt2);
+ /* operators connection is saved in chip data block */
+ state_save_register_item(buf1, sndindex, op->mem_value);
+
+ state_save_register_item(buf1, sndindex, op->fb_shift);
+ state_save_register_item(buf1, sndindex, op->fb_out_curr);
+ state_save_register_item(buf1, sndindex, op->fb_out_prev);
+ state_save_register_item(buf1, sndindex, op->kc);
+ state_save_register_item(buf1, sndindex, op->kc_i);
+ state_save_register_item(buf1, sndindex, op->pms);
+ state_save_register_item(buf1, sndindex, op->ams);
+ state_save_register_item(buf1, sndindex, op->AMmask);
+
+ state_save_register_item(buf1, sndindex, op->state);
+ state_save_register_item(buf1, sndindex, op->eg_sh_ar);
+ state_save_register_item(buf1, sndindex, op->eg_sel_ar);
+ state_save_register_item(buf1, sndindex, op->tl);
+ state_save_register_item(buf1, sndindex, op->volume);
+ state_save_register_item(buf1, sndindex, op->eg_sh_d1r);
+ state_save_register_item(buf1, sndindex, op->eg_sel_d1r);
+ state_save_register_item(buf1, sndindex, op->d1l);
+ state_save_register_item(buf1, sndindex, op->eg_sh_d2r);
+ state_save_register_item(buf1, sndindex, op->eg_sel_d2r);
+ state_save_register_item(buf1, sndindex, op->eg_sh_rr);
+ state_save_register_item(buf1, sndindex, op->eg_sel_rr);
+
+ state_save_register_item(buf1, sndindex, op->key);
+ state_save_register_item(buf1, sndindex, op->ks);
+ state_save_register_item(buf1, sndindex, op->ar);
+ state_save_register_item(buf1, sndindex, op->d1r);
+ state_save_register_item(buf1, sndindex, op->d2r);
+ state_save_register_item(buf1, sndindex, op->rr);
+
+ state_save_register_item(buf1, sndindex, op->reserved0);
+ state_save_register_item(buf1, sndindex, op->reserved1);
+ }
+
+ sprintf(buf1,"YM2151.registers");
+
+ state_save_register_item_array(buf1, sndindex, chip->pan);
+
+ state_save_register_item(buf1, sndindex, chip->eg_cnt);
+ state_save_register_item(buf1, sndindex, chip->eg_timer);
+ state_save_register_item(buf1, sndindex, chip->eg_timer_add);
+ state_save_register_item(buf1, sndindex, chip->eg_timer_overflow);
+
+ state_save_register_item(buf1, sndindex, chip->lfo_phase);
+ state_save_register_item(buf1, sndindex, chip->lfo_timer);
+ state_save_register_item(buf1, sndindex, chip->lfo_timer_add);
+ state_save_register_item(buf1, sndindex, chip->lfo_overflow);
+ state_save_register_item(buf1, sndindex, chip->lfo_counter);
+ state_save_register_item(buf1, sndindex, chip->lfo_counter_add);
+ state_save_register_item(buf1, sndindex, chip->lfo_wsel);
+ state_save_register_item(buf1, sndindex, chip->amd);
+ state_save_register_item(buf1, sndindex, chip->pmd);
+ state_save_register_item(buf1, sndindex, chip->lfa);
+ state_save_register_item(buf1, sndindex, chip->lfp);
+
+ state_save_register_item(buf1, sndindex, chip->test);
+ state_save_register_item(buf1, sndindex, chip->ct);
+
+ state_save_register_item(buf1, sndindex, chip->noise);
+ state_save_register_item(buf1, sndindex, chip->noise_rng);
+ state_save_register_item(buf1, sndindex, chip->noise_p);
+ state_save_register_item(buf1, sndindex, chip->noise_f);
+
+ state_save_register_item(buf1, sndindex, chip->csm_req);
+ state_save_register_item(buf1, sndindex, chip->irq_enable);
+ state_save_register_item(buf1, sndindex, chip->status);
+
+ state_save_register_item(buf1, sndindex, chip->timer_A_index);
+ state_save_register_item(buf1, sndindex, chip->timer_B_index);
+ state_save_register_item(buf1, sndindex, chip->timer_A_index_old);
+ state_save_register_item(buf1, sndindex, chip->timer_B_index_old);
+
+#ifdef USE_MAME_TIMERS
+ state_save_register_item(buf1, sndindex, chip->irqlinestate);
+#endif
+
+ state_save_register_item_array(buf1, sndindex, chip->connect);
+
+ state_save_register_func_postload_ptr(YM2151Postload, chip);
+}
+#else
+void YM2151Postload(void *chip)
+{
+}
+
+static void ym2151_state_save_register( YM2151 *chip, int sndindex )
+{
+}
+#endif
+
+
+/*
+* Initialize YM2151 emulator(s).
+*
+* 'num' is the number of virtual YM2151's to allocate
+* 'clock' is the chip clock in Hz
+* 'rate' is sampling rate
+*/
+void * YM2151Init(int index, int clock, int rate)
+{
+ YM2151 *PSG;
+
+ PSG = (YM2151 *)malloc(sizeof(YM2151));
+ if (PSG == NULL)
+ return NULL;
+
+ memset(PSG, 0, sizeof(YM2151));
+
+ ym2151_state_save_register( PSG, index );
+
+ init_tables();
+
+ PSG->clock = clock;
+ /*rate = clock/64;*/
+ PSG->sampfreq = rate ? rate : 44100; /* avoid division by 0 in init_chip_tables() */
+ PSG->irqhandler = NULL; /* interrupt handler */
+ PSG->porthandler = NULL; /* port write handler */
+ init_chip_tables( PSG );
+
+ PSG->lfo_timer_add = (1<<LFO_SH) * (clock/64.0) / PSG->sampfreq;
+
+ PSG->eg_timer_add = (1<<EG_SH) * (clock/64.0) / PSG->sampfreq;
+ PSG->eg_timer_overflow = ( 3 ) * (1<<EG_SH);
+ /*logerror("YM2151[init] eg_timer_add=%8x eg_timer_overflow=%8x\n", PSG->eg_timer_add, PSG->eg_timer_overflow);*/
+
+#ifdef USE_MAME_TIMERS
+/* this must be done _before_ a call to YM2151ResetChip() */
+ PSG->timer_A = timer_alloc_ptr(timer_callback_a, PSG);
+ PSG->timer_B = timer_alloc_ptr(timer_callback_b, PSG);
+#else
+ PSG->tim_A = 0;
+ PSG->tim_B = 0;
+#endif
+ YM2151ResetChip(PSG);
+ /*logerror("YM2151[init] clock=%i sampfreq=%i\n", PSG->clock, PSG->sampfreq);*/
+
+#ifdef LOG_CYM_FILE
+ cymfile = fopen("2151_.cym","wb");
+ if (cymfile)
+ timer_pulse ( ATTOTIME_IN_HZ(110), 0, cymfile_callback); /*110 Hz pulse timer*/
+ else
+ logerror("Could not create file 2151_.cym\n");
+#endif
+
+ return PSG;
+}
+
+
+
+void YM2151Shutdown(void *_chip)
+{
+ YM2151 *chip = _chip;
+
+ free (chip);
+
+#ifdef LOG_CYM_FILE
+ fclose (cymfile);
+ cymfile = NULL;
+#endif
+
+#ifdef SAVE_SAMPLE
+ fclose(sample[8]);
+#endif
+#ifdef SAVE_SEPARATE_CHANNELS
+ fclose(sample[0]);
+ fclose(sample[1]);
+ fclose(sample[2]);
+ fclose(sample[3]);
+ fclose(sample[4]);
+ fclose(sample[5]);
+ fclose(sample[6]);
+ fclose(sample[7]);
+#endif
+}
+
+
+
+/*
+* Reset chip number 'n'.
+*/
+void YM2151ResetChip(void *_chip)
+{
+ int i;
+ YM2151 *chip = _chip;
+
+
+ /* initialize hardware registers */
+ for (i=0; i<32; i++)
+ {
+ memset(&chip->oper[i],'\0',sizeof(YM2151Operator));
+ chip->oper[i].volume = MAX_ATT_INDEX;
+ chip->oper[i].kc_i = 768; /* min kc_i value */
+ }
+
+ chip->eg_timer = 0;
+ chip->eg_cnt = 0;
+
+ chip->lfo_timer = 0;
+ chip->lfo_counter= 0;
+ chip->lfo_phase = 0;
+ chip->lfo_wsel = 0;
+ chip->pmd = 0;
+ chip->amd = 0;
+ chip->lfa = 0;
+ chip->lfp = 0;
+
+ chip->test= 0;
+
+ chip->irq_enable = 0;
+#ifdef USE_MAME_TIMERS
+ /* ASG 980324 -- reset the timers before writing to the registers */
+ timer_enable(chip->timer_A, 0);
+ timer_enable(chip->timer_B, 0);
+#else
+ chip->tim_A = 0;
+ chip->tim_B = 0;
+ chip->tim_A_val = 0;
+ chip->tim_B_val = 0;
+#endif
+ chip->timer_A_index = 0;
+ chip->timer_B_index = 0;
+ chip->timer_A_index_old = 0;
+ chip->timer_B_index_old = 0;
+
+ chip->noise = 0;
+ chip->noise_rng = 0;
+ chip->noise_p = 0;
+ chip->noise_f = chip->noise_tab[0];
+
+ chip->csm_req = 0;
+ chip->status = 0;
+
+ YM2151WriteReg(chip, 0x1b, 0); /* only because of CT1, CT2 output pins */
+ YM2151WriteReg(chip, 0x18, 0); /* set LFO frequency */
+ for (i=0x20; i<0x100; i++) /* set the operators */
+ {
+ YM2151WriteReg(chip, i, 0);
+ }
+}
+
+
+
+INLINE signed int op_calc(YM2151Operator * OP, unsigned int env, signed int pm)
+{
+ UINT32 p;
+
+
+ p = (env<<3) + sin_tab[ ( ((signed int)((OP->phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ];
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+
+ return tl_tab[p];
+}
+
+INLINE signed int op_calc1(YM2151Operator * OP, unsigned int env, signed int pm)
+{
+ UINT32 p;
+ INT32 i;
+
+
+ i = (OP->phase & ~FREQ_MASK) + pm;
+
+/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, OP->phase>>FREQ_SH, pm);*/
+
+ p = (env<<3) + sin_tab[ (i>>FREQ_SH) & SIN_MASK];
+
+/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+
+ return tl_tab[p];
+}
+
+
+
+#define volume_calc(OP) ((OP)->tl + ((UINT32)(OP)->volume) + (AM & (OP)->AMmask))
+
+INLINE void chan_calc(unsigned int chan)
+{
+ YM2151Operator *op;
+ unsigned int env;
+ UINT32 AM = 0;
+
+ m2 = c1 = c2 = mem = 0;
+ op = &PSG->oper[chan*4]; /* M1 */
+
+ *op->mem_connect = op->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
+
+ if (op->ams)
+ AM = PSG->lfa << (op->ams-1);
+ env = volume_calc(op);
+ {
+ INT32 out = op->fb_out_prev + op->fb_out_curr;
+ op->fb_out_prev = op->fb_out_curr;
+
+ if (!op->connect)
+ /* algorithm 5 */
+ mem = c1 = c2 = op->fb_out_prev;
+ else
+ /* other algorithms */
+ *op->connect = op->fb_out_prev;
+
+ op->fb_out_curr = 0;
+ if (env < ENV_QUIET)
+ {
+ if (!op->fb_shift)
+ out=0;
+ op->fb_out_curr = op_calc1(op, env, (out<<op->fb_shift) );
+ }
+ }
+
+ env = volume_calc(op+1); /* M2 */
+ if (env < ENV_QUIET)
+ *(op+1)->connect += op_calc(op+1, env, m2);
+
+ env = volume_calc(op+2); /* C1 */
+ if (env < ENV_QUIET)
+ *(op+2)->connect += op_calc(op+2, env, c1);
+
+ env = volume_calc(op+3); /* C2 */
+ if (env < ENV_QUIET)
+ chanout[chan] += op_calc(op+3, env, c2);
+
+ /* M1 */
+ op->mem_value = mem;
+}
+INLINE void chan7_calc(void)
+{
+ YM2151Operator *op;
+ unsigned int env;
+ UINT32 AM = 0;
+
+ m2 = c1 = c2 = mem = 0;
+ op = &PSG->oper[7*4]; /* M1 */
+
+ *op->mem_connect = op->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
+
+ if (op->ams)
+ AM = PSG->lfa << (op->ams-1);
+ env = volume_calc(op);
+ {
+ INT32 out = op->fb_out_prev + op->fb_out_curr;
+ op->fb_out_prev = op->fb_out_curr;
+
+ if (!op->connect)
+ /* algorithm 5 */
+ mem = c1 = c2 = op->fb_out_prev;
+ else
+ /* other algorithms */
+ *op->connect = op->fb_out_prev;
+
+ op->fb_out_curr = 0;
+ if (env < ENV_QUIET)
+ {
+ if (!op->fb_shift)
+ out=0;
+ op->fb_out_curr = op_calc1(op, env, (out<<op->fb_shift) );
+ }
+ }
+
+ env = volume_calc(op+1); /* M2 */
+ if (env < ENV_QUIET)
+ *(op+1)->connect += op_calc(op+1, env, m2);
+
+ env = volume_calc(op+2); /* C1 */
+ if (env < ENV_QUIET)
+ *(op+2)->connect += op_calc(op+2, env, c1);
+
+ env = volume_calc(op+3); /* C2 */
+ if (PSG->noise & 0x80)
+ {
+ UINT32 noiseout;
+
+ noiseout = 0;
+ if (env < 0x3ff)
+ noiseout = (env ^ 0x3ff) * 2; /* range of the YM2151 noise output is -2044 to 2040 */
+ chanout[7] += ((PSG->noise_rng&0x10000) ? noiseout: -noiseout); /* bit 16 -> output */
+ }
+ else
+ {
+ if (env < ENV_QUIET)
+ chanout[7] += op_calc(op+3, env, c2);
+ }
+ /* M1 */
+ op->mem_value = mem;
+}
+
+
+
+
+
+
+/*
+The 'rate' is calculated from following formula (example on decay rate):
+ rks = notecode after key scaling (a value from 0 to 31)
+ DR = value written to the chip register
+ rate = 2*DR + rks; (max rate = 2*31+31 = 93)
+Four MSBs of the 'rate' above are the 'main' rate (from 00 to 15)
+Two LSBs of the 'rate' above are the value 'x' (the shape type).
+(eg. '11 2' means that 'rate' is 11*4+2=46)
+
+NOTE: A 'sample' in the description below is actually 3 output samples,
+thats because the Envelope Generator clock is equal to internal_clock/3.
+
+Single '-' (minus) character in the diagrams below represents one sample
+on the output; this is for rates 11 x (11 0, 11 1, 11 2 and 11 3)
+
+these 'main' rates:
+00 x: single '-' = 2048 samples; (ie. level can change every 2048 samples)
+01 x: single '-' = 1024 samples;
+02 x: single '-' = 512 samples;
+03 x: single '-' = 256 samples;
+04 x: single '-' = 128 samples;
+05 x: single '-' = 64 samples;
+06 x: single '-' = 32 samples;
+07 x: single '-' = 16 samples;
+08 x: single '-' = 8 samples;
+09 x: single '-' = 4 samples;
+10 x: single '-' = 2 samples;
+11 x: single '-' = 1 sample; (ie. level can change every 1 sample)
+
+Shapes for rates 11 x look like this:
+rate: step:
+11 0 01234567
+
+level:
+0 --
+1 --
+2 --
+3 --
+
+rate: step:
+11 1 01234567
+
+level:
+0 --
+1 --
+2 -
+3 -
+4 --
+
+rate: step:
+11 2 01234567
+
+level:
+0 --
+1 -
+2 -
+3 --
+4 -
+5 -
+
+rate: step:
+11 3 01234567
+
+level:
+0 --
+1 -
+2 -
+3 -
+4 -
+5 -
+6 -
+
+
+For rates 12 x, 13 x, 14 x and 15 x output level changes on every
+sample - this means that the waveform looks like this: (but the level
+changes by different values on different steps)
+12 3 01234567
+
+0 -
+2 -
+4 -
+8 -
+10 -
+12 -
+14 -
+18 -
+20 -
+
+Notes about the timing:
+----------------------
+
+1. Synchronism
+
+Output level of each two (or more) voices running at the same 'main' rate
+(eg 11 0 and 11 1 in the diagram below) will always be changing in sync,
+even if there're started with some delay.
+
+Note that, in the diagram below, the decay phase in channel 0 starts at
+sample #2, while in channel 1 it starts at sample #6. Anyway, both channels
+will always change their levels at exactly the same (following) samples.
+
+(S - start point of this channel, A-attack phase, D-decay phase):
+
+step:
+01234567012345670123456
+
+channel 0:
+ --
+ | --
+ | -
+ | -
+ | --
+ | --
+| --
+| -
+| -
+| --
+AADDDDDDDDDDDDDDDD
+S
+
+01234567012345670123456
+channel 1:
+ -
+ | -
+ | --
+ | --
+ | --
+ | -
+ | -
+ | --
+ | --
+ | --
+ AADDDDDDDDDDDDDDDD
+ S
+01234567012345670123456
+
+
+2. Shifted (delayed) synchronism
+
+Output of each two (or more) voices running at different 'main' rate
+(9 1, 10 1 and 11 1 in the diagrams below) will always be changing
+in 'delayed-sync' (even if there're started with some delay as in "1.")
+
+Note that the shapes are delayed by exactly one sample per one 'main' rate
+increment. (Normally one would expect them to start at the same samples.)
+
+See diagram below (* - start point of the shape).
+
+cycle:
+0123456701234567012345670123456701234567012345670123456701234567
+
+rate 09 1
+*-------
+ --------
+ ----
+ ----
+ --------
+ *-------
+ | --------
+ | ----
+ | ----
+ | --------
+rate 10 1 |
+-- |
+ *--- |
+ ---- |
+ -- |
+ -- |
+ ---- |
+ *--- |
+ | ---- |
+ | -- | | <- one step (two samples) delay between 9 1 and 10 1
+ | -- | |
+ | ----|
+ | *---
+ | ----
+ | --
+ | --
+ | ----
+rate 11 1 |
+- |
+ -- |
+ *- |
+ -- |
+ - |
+ - |
+ -- |
+ *- |
+ -- |
+ - || <- one step (one sample) delay between 10 1 and 11 1
+ - ||
+ --|
+ *-
+ --
+ -
+ -
+ --
+ *-
+ --
+ -
+ -
+ --
+*/
+
+INLINE void advance_eg(void)
+{
+ YM2151Operator *op;
+ unsigned int i;
+
+
+
+ PSG->eg_timer += PSG->eg_timer_add;
+
+ while (PSG->eg_timer >= PSG->eg_timer_overflow)
+ {
+ PSG->eg_timer -= PSG->eg_timer_overflow;
+
+ PSG->eg_cnt++;
+
+ /* envelope generator */
+ op = &PSG->oper[0]; /* CH 0 M1 */
+ i = 32;
+ do
+ {
+ switch(op->state)
+ {
+ case EG_ATT: /* attack phase */
+ if ( !(PSG->eg_cnt & ((1<<op->eg_sh_ar)-1) ) )
+ {
+ op->volume += (~op->volume *
+ (eg_inc[op->eg_sel_ar + ((PSG->eg_cnt>>op->eg_sh_ar)&7)])
+ ) >>4;
+
+ if (op->volume <= MIN_ATT_INDEX)
+ {
+ op->volume = MIN_ATT_INDEX;
+ op->state = EG_DEC;
+ }
+
+ }
+ break;
+
+ case EG_DEC: /* decay phase */
+ if ( !(PSG->eg_cnt & ((1<<op->eg_sh_d1r)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_d1r + ((PSG->eg_cnt>>op->eg_sh_d1r)&7)];
+
+ if ( op->volume >= op->d1l )
+ op->state = EG_SUS;
+
+ }
+ break;
+
+ case EG_SUS: /* sustain phase */
+ if ( !(PSG->eg_cnt & ((1<<op->eg_sh_d2r)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_d2r + ((PSG->eg_cnt>>op->eg_sh_d2r)&7)];
+
+ if ( op->volume >= MAX_ATT_INDEX )
+ {
+ op->volume = MAX_ATT_INDEX;
+ op->state = EG_OFF;
+ }
+
+ }
+ break;
+
+ case EG_REL: /* release phase */
+ if ( !(PSG->eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_rr + ((PSG->eg_cnt>>op->eg_sh_rr)&7)];
+
+ if ( op->volume >= MAX_ATT_INDEX )
+ {
+ op->volume = MAX_ATT_INDEX;
+ op->state = EG_OFF;
+ }
+
+ }
+ break;
+ }
+ op++;
+ i--;
+ }while (i);
+ }
+}
+
+
+INLINE void advance(void)
+{
+ YM2151Operator *op;
+ unsigned int i;
+ int a,p;
+
+ /* LFO */
+ if (PSG->test&2)
+ PSG->lfo_phase = 0;
+ else
+ {
+ PSG->lfo_timer += PSG->lfo_timer_add;
+ if (PSG->lfo_timer >= PSG->lfo_overflow)
+ {
+ PSG->lfo_timer -= PSG->lfo_overflow;
+ PSG->lfo_counter += PSG->lfo_counter_add;
+ PSG->lfo_phase += (PSG->lfo_counter>>4);
+ PSG->lfo_phase &= 255;
+ PSG->lfo_counter &= 15;
+ }
+ }
+
+ i = PSG->lfo_phase;
+ /* calculate LFO AM and PM waveform value (all verified on real chip, except for noise algorithm which is impossible to analyse)*/
+ switch (PSG->lfo_wsel)
+ {
+ case 0:
+ /* saw */
+ /* AM: 255 down to 0 */
+ /* PM: 0 to 127, -127 to 0 (at PMD=127: LFP = 0 to 126, -126 to 0) */
+ a = 255 - i;
+ if (i<128)
+ p = i;
+ else
+ p = i - 255;
+ break;
+ case 1:
+ /* square */
+ /* AM: 255, 0 */
+ /* PM: 128,-128 (LFP = exactly +PMD, -PMD) */
+ if (i<128){
+ a = 255;
+ p = 128;
+ }else{
+ a = 0;
+ p = -128;
+ }
+ break;
+ case 2:
+ /* triangle */
+ /* AM: 255 down to 1 step -2; 0 up to 254 step +2 */
+ /* PM: 0 to 126 step +2, 127 to 1 step -2, 0 to -126 step -2, -127 to -1 step +2*/
+ if (i<128)
+ a = 255 - (i*2);
+ else
+ a = (i*2) - 256;
+
+ if (i<64) /* i = 0..63 */
+ p = i*2; /* 0 to 126 step +2 */
+ else if (i<128) /* i = 64..127 */
+ p = 255 - i*2; /* 127 to 1 step -2 */
+ else if (i<192) /* i = 128..191 */
+ p = 256 - i*2; /* 0 to -126 step -2*/
+ else /* i = 192..255 */
+ p = i*2 - 511; /*-127 to -1 step +2*/
+ break;
+ case 3:
+ default: /*keep the compiler happy*/
+ /* random */
+ /* the real algorithm is unknown !!!
+ We just use a snapshot of data from real chip */
+
+ /* AM: range 0 to 255 */
+ /* PM: range -128 to 127 */
+
+ a = lfo_noise_waveform[i];
+ p = a-128;
+ break;
+ }
+ PSG->lfa = a * PSG->amd / 128;
+ PSG->lfp = p * PSG->pmd / 128;
+
+
+ /* The Noise Generator of the YM2151 is 17-bit shift register.
+ * Input to the bit16 is negated (bit0 XOR bit3) (EXNOR).
+ * Output of the register is negated (bit0 XOR bit3).
+ * Simply use bit16 as the noise output.
+ */
+ PSG->noise_p += PSG->noise_f;
+ i = (PSG->noise_p>>16); /* number of events (shifts of the shift register) */
+ PSG->noise_p &= 0xffff;
+ while (i)
+ {
+ UINT32 j;
+ j = ( (PSG->noise_rng ^ (PSG->noise_rng>>3) ) & 1) ^ 1;
+ PSG->noise_rng = (j<<16) | (PSG->noise_rng>>1);
+ i--;
+ }
+
+
+ /* phase generator */
+ op = &PSG->oper[0]; /* CH 0 M1 */
+ i = 8;
+ do
+ {
+ if (op->pms) /* only when phase modulation from LFO is enabled for this channel */
+ {
+ INT32 mod_ind = PSG->lfp; /* -128..+127 (8bits signed) */
+ if (op->pms < 6)
+ mod_ind >>= (6 - op->pms);
+ else
+ mod_ind <<= (op->pms - 5);
+
+ if (mod_ind)
+ {
+ UINT32 kc_channel = op->kc_i + mod_ind;
+ (op+0)->phase += ( (PSG->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1;
+ (op+1)->phase += ( (PSG->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1;
+ (op+2)->phase += ( (PSG->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1;
+ (op+3)->phase += ( (PSG->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1;
+ }
+ else /* phase modulation from LFO is equal to zero */
+ {
+ (op+0)->phase += (op+0)->freq;
+ (op+1)->phase += (op+1)->freq;
+ (op+2)->phase += (op+2)->freq;
+ (op+3)->phase += (op+3)->freq;
+ }
+ }
+ else /* phase modulation from LFO is disabled */
+ {
+ (op+0)->phase += (op+0)->freq;
+ (op+1)->phase += (op+1)->freq;
+ (op+2)->phase += (op+2)->freq;
+ (op+3)->phase += (op+3)->freq;
+ }
+
+ op+=4;
+ i--;
+ }while (i);
+
+
+ /* CSM is calculated *after* the phase generator calculations (verified on real chip)
+ * CSM keyon line seems to be ORed with the KO line inside of the chip.
+ * The result is that it only works when KO (register 0x08) is off, ie. 0
+ *
+ * Interesting effect is that when timer A is set to 1023, the KEY ON happens
+ * on every sample, so there is no KEY OFF at all - the result is that
+ * the sound played is the same as after normal KEY ON.
+ */
+
+ if (PSG->csm_req) /* CSM KEYON/KEYOFF seqeunce request */
+ {
+ if (PSG->csm_req==2) /* KEY ON */
+ {
+ op = &PSG->oper[0]; /* CH 0 M1 */
+ i = 32;
+ do
+ {
+ KEY_ON(op, 2);
+ op++;
+ i--;
+ }while (i);
+ PSG->csm_req = 1;
+ }
+ else /* KEY OFF */
+ {
+ op = &PSG->oper[0]; /* CH 0 M1 */
+ i = 32;
+ do
+ {
+ KEY_OFF(op,~2);
+ op++;
+ i--;
+ }while (i);
+ PSG->csm_req = 0;
+ }
+ }
+}
+
+#if 0
+INLINE signed int acc_calc(signed int value)
+{
+ if (value>=0)
+ {
+ if (value < 0x0200)
+ return (value & ~0);
+ if (value < 0x0400)
+ return (value & ~1);
+ if (value < 0x0800)
+ return (value & ~3);
+ if (value < 0x1000)
+ return (value & ~7);
+ if (value < 0x2000)
+ return (value & ~15);
+ if (value < 0x4000)
+ return (value & ~31);
+ return (value & ~63);
+ }
+ /*else value < 0*/
+ if (value > -0x0200)
+ return (~abs(value) & ~0);
+ if (value > -0x0400)
+ return (~abs(value) & ~1);
+ if (value > -0x0800)
+ return (~abs(value) & ~3);
+ if (value > -0x1000)
+ return (~abs(value) & ~7);
+ if (value > -0x2000)
+ return (~abs(value) & ~15);
+ if (value > -0x4000)
+ return (~abs(value) & ~31);
+ return (~abs(value) & ~63);
+}
+#endif
+
+/* first macro saves left and right channels to mono file */
+/* second macro saves left and right channels to stereo file */
+#if 0 /*MONO*/
+ #ifdef SAVE_SEPARATE_CHANNELS
+ #define SAVE_SINGLE_CHANNEL(j) \
+ { signed int pom= -(chanout[j] & PSG->pan[j*2]); \
+ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \
+ fputc((unsigned short)pom&0xff,sample[j]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[j]); }
+ #else
+ #define SAVE_SINGLE_CHANNEL(j)
+ #endif
+#else /*STEREO*/
+ #ifdef SAVE_SEPARATE_CHANNELS
+ #define SAVE_SINGLE_CHANNEL(j) \
+ { signed int pom = -(chanout[j] & PSG->pan[j*2]); \
+ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \
+ fputc((unsigned short)pom&0xff,sample[j]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[j]); \
+ pom = -(chanout[j] & PSG->pan[j*2+1]); \
+ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \
+ fputc((unsigned short)pom&0xff,sample[j]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[j]); \
+ }
+ #else
+ #define SAVE_SINGLE_CHANNEL(j)
+ #endif
+#endif
+
+/* first macro saves left and right channels to mono file */
+/* second macro saves left and right channels to stereo file */
+#if 1 /*MONO*/
+ #ifdef SAVE_SAMPLE
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = outl; \
+ /*pom = acc_calc(pom);*/ \
+ /*fprintf(sample[8]," %i\n",pom);*/ \
+ fputc((unsigned short)pom&0xff,sample[8]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[8]); \
+ }
+ #else
+ #define SAVE_ALL_CHANNELS
+ #endif
+#else /*STEREO*/
+ #ifdef SAVE_SAMPLE
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = outl; \
+ fputc((unsigned short)pom&0xff,sample[8]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[8]); \
+ pom = outr; \
+ fputc((unsigned short)pom&0xff,sample[8]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[8]); \
+ }
+ #else
+ #define SAVE_ALL_CHANNELS
+ #endif
+#endif
+
+
+/* Generate samples for one of the YM2151's
+*
+* 'num' is the number of virtual YM2151
+* '**buffers' is table of pointers to the buffers: left and right
+* 'length' is the number of samples that should be generated
+*/
+void YM2151UpdateOne(void *chip, SAMP **buffers, int length)
+{
+ int i;
+ signed int outl,outr;
+ SAMP *bufL, *bufR;
+
+ bufL = buffers[0];
+ bufR = buffers[1];
+
+ PSG = chip;
+
+#ifdef USE_MAME_TIMERS
+ /* ASG 980324 - handled by real timers now */
+#else
+ if (PSG->tim_B)
+ {
+ PSG->tim_B_val -= ( length << TIMER_SH );
+ if (PSG->tim_B_val<=0)
+ {
+ PSG->tim_B_val += PSG->tim_B_tab[ PSG->timer_B_index ];
+ if ( PSG->irq_enable & 0x08 )
+ {
+ int oldstate = PSG->status & 3;
+ PSG->status |= 2;
+ if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(1);
+ }
+ }
+ }
+#endif
+
+ for (i=0; i<length; i++)
+ {
+ advance_eg();
+
+ chanout[0] = 0;
+ chanout[1] = 0;
+ chanout[2] = 0;
+ chanout[3] = 0;
+ chanout[4] = 0;
+ chanout[5] = 0;
+ chanout[6] = 0;
+ chanout[7] = 0;
+
+ chan_calc(0);
+ SAVE_SINGLE_CHANNEL(0)
+ chan_calc(1);
+ SAVE_SINGLE_CHANNEL(1)
+ chan_calc(2);
+ SAVE_SINGLE_CHANNEL(2)
+ chan_calc(3);
+ SAVE_SINGLE_CHANNEL(3)
+ chan_calc(4);
+ SAVE_SINGLE_CHANNEL(4)
+ chan_calc(5);
+ SAVE_SINGLE_CHANNEL(5)
+ chan_calc(6);
+ SAVE_SINGLE_CHANNEL(6)
+ chan7_calc();
+ SAVE_SINGLE_CHANNEL(7)
+
+ outl = chanout[0] & PSG->pan[0];
+ outr = chanout[0] & PSG->pan[1];
+ outl += (chanout[1] & PSG->pan[2]);
+ outr += (chanout[1] & PSG->pan[3]);
+ outl += (chanout[2] & PSG->pan[4]);
+ outr += (chanout[2] & PSG->pan[5]);
+ outl += (chanout[3] & PSG->pan[6]);
+ outr += (chanout[3] & PSG->pan[7]);
+ outl += (chanout[4] & PSG->pan[8]);
+ outr += (chanout[4] & PSG->pan[9]);
+ outl += (chanout[5] & PSG->pan[10]);
+ outr += (chanout[5] & PSG->pan[11]);
+ outl += (chanout[6] & PSG->pan[12]);
+ outr += (chanout[6] & PSG->pan[13]);
+ outl += (chanout[7] & PSG->pan[14]);
+ outr += (chanout[7] & PSG->pan[15]);
+
+ outl >>= FINAL_SH;
+ outr >>= FINAL_SH;
+ if (outl > MAXOUT) outl = MAXOUT;
+ else if (outl < MINOUT) outl = MINOUT;
+ if (outr > MAXOUT) outr = MAXOUT;
+ else if (outr < MINOUT) outr = MINOUT;
+ ((SAMP*)bufL)[i] = (SAMP)outl;
+ ((SAMP*)bufR)[i] = (SAMP)outr;
+
+ SAVE_ALL_CHANNELS
+
+#ifdef USE_MAME_TIMERS
+ /* ASG 980324 - handled by real timers now */
+#else
+ /* calculate timer A */
+ if (PSG->tim_A)
+ {
+ PSG->tim_A_val -= ( 1 << TIMER_SH );
+ if (PSG->tim_A_val <= 0)
+ {
+ PSG->tim_A_val += PSG->tim_A_tab[ PSG->timer_A_index ];
+ if (PSG->irq_enable & 0x04)
+ {
+ int oldstate = PSG->status & 3;
+ PSG->status |= 1;
+ if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(1);
+ }
+ if (PSG->irq_enable & 0x80)
+ PSG->csm_req = 2; /* request KEY ON / KEY OFF sequence */
+ }
+ }
+#endif
+ advance();
+ }
+}
+
+void YM2151SetIrqHandler(void *chip, void(*handler)(int irq))
+{
+ YM2151 *PSG = chip;
+ PSG->irqhandler = handler;
+}
+
+void YM2151SetPortWriteHandler(void *chip, write8_handler handler)
+{
+ YM2151 *PSG = chip;
+ PSG->porthandler = handler;
+}
+
diff --git a/src/emu/sound/ym2151.h b/src/emu/sound/ym2151.h
new file mode 100644
index 00000000000..a3dd23b6a0e
--- /dev/null
+++ b/src/emu/sound/ym2151.h
@@ -0,0 +1,86 @@
+/*
+**
+** File: ym2151.h - header file for software implementation of YM2151
+** FM Operator Type-M(OPM)
+**
+** (c) 1997-2002 Jarek Burczynski (s0246@poczta.onet.pl, bujar@mame.net)
+** Some of the optimizing ideas by Tatsuyuki Satoh
+**
+** Version 2.150 final beta May, 11th 2002
+**
+**
+** I would like to thank following people for making this project possible:
+**
+** Beauty Planets - for making a lot of real YM2151 samples and providing
+** additional informations about the chip. Also for the time spent making
+** the samples and the speed of replying to my endless requests.
+**
+** Shigeharu Isoda - for general help, for taking time to scan his YM2151
+** Japanese Manual first of all, and answering MANY of my questions.
+**
+** Nao - for giving me some info about YM2151 and pointing me to Shigeharu.
+** Also for creating fmemu (which I still use to test the emulator).
+**
+** Aaron Giles and Chris Hardy - they made some samples of one of my favourite
+** arcade games so I could compare it to my emulator.
+**
+** Bryan McPhail and Tim (powerjaw) - for making some samples.
+**
+** Ishmair - for the datasheet and motivation.
+*/
+
+#ifndef _H_YM2151_
+#define _H_YM2151_
+
+/* 16- and 8-bit samples (signed) are supported*/
+#define SAMPLE_BITS 16
+
+typedef stream_sample_t SAMP;
+/*
+#if (SAMPLE_BITS==16)
+ typedef INT16 SAMP;
+#endif
+#if (SAMPLE_BITS==8)
+ typedef signed char SAMP;
+#endif
+*/
+
+/*
+** Initialize YM2151 emulator(s).
+**
+** 'num' is the number of virtual YM2151's to allocate
+** 'clock' is the chip clock in Hz
+** 'rate' is sampling rate
+*/
+void *YM2151Init(int index, int clock, int rate);
+
+/* shutdown the YM2151 emulators*/
+void YM2151Shutdown(void *chip);
+
+/* reset all chip registers for YM2151 number 'num'*/
+void YM2151ResetChip(void *chip);
+
+/*
+** Generate samples for one of the YM2151's
+**
+** 'num' is the number of virtual YM2151
+** '**buffers' is table of pointers to the buffers: left and right
+** 'length' is the number of samples that should be generated
+*/
+void YM2151UpdateOne(void *chip, SAMP **buffers, int length);
+
+/* write 'v' to register 'r' on YM2151 chip number 'n'*/
+void YM2151WriteReg(void *chip, int r, int v);
+
+/* read status register on YM2151 chip number 'n'*/
+int YM2151ReadStatus(void *chip);
+
+/* set interrupt handler on YM2151 chip number 'n'*/
+void YM2151SetIrqHandler(void *chip, void (*handler)(int irq));
+
+/* set port write handler on YM2151 chip number 'n'*/
+void YM2151SetPortWriteHandler(void *chip, write8_handler handler);
+
+/* refresh chip when load state */
+void YM2151Postload(void *chip);
+#endif /*_H_YM2151_*/
diff --git a/src/emu/sound/ym2151.txt b/src/emu/sound/ym2151.txt
new file mode 100644
index 00000000000..a28893ae3ff
--- /dev/null
+++ b/src/emu/sound/ym2151.txt
@@ -0,0 +1,162 @@
+
+This is some very technical info I found during my experiments with real chip.
+I hope someone will find it interesting.
+
+
+ YM2151 TIMING DIAGRAM
+ +-------------------------------------------------------------------------------------------------------------------------------|---------
+Cycle no. | 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 | 0 | 1 |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+-
+ | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _
+D/A clock |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_
+ | |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+-
+ | _______________________________ |
+SH1 signal |_______________________________| |_______________________________________________________________|_________
+ | |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+-
+ | _______________________________|
+SH2 signal |_______________________________________________________________________________________________| |_________
+ | |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+-
+ | | |
+SO | x | x | x | D0| D1| D2| D3| D4| D5| D6| D7| D8| D9| S0| S1| S2| x | x | x | D0| D1| D2| D3| D4| D5| D6| D7| D8| D9| S0| S1| S2| x | x |
+(D/A data) | | |
+ | R I G H T C H A N N E L | L E F T C H A N N E L |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+-
+READ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+INTERNAL CH| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 |
+DATA OP| C2| C2| C2| C2| C2| C2| C2| C2| M1| M1| M1| M1| M1| M1| M1| M1| M2| M2| M2| M2| M2| M2| M2| M2| C1| C1| C1| C1| C1| C1| C1| C1| C2| C2|
+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+ operator #| 24| 25| 26| 27| 28| 29| 30| 31| 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|
+ +---------------------------------------------------------------|---------------------------------------------------------------|---------
+
+
+ Note:
+ -----
+ The SO (D/A data) is sequentially output to the YM3012 (stereo) or YM3014 (mono).
+ Formula to calculate sample from SO data is:
+ N = S2(2^2) + S1(2^1) + S0
+ where S2 = S1 = S0 = 0 - not allowed
+ SAMPLE = (-1+D9 + D8(2^-1) + D7(2^-2) + D6(2^-3) + ... + D0(2^-9) + 2^-10) * 2^-N
+
+ Anyway, important is that SO data is delayed by one sample compared to READ INTERNAL DATA.
+ This is logical since chip has to sum all channels' outputs before it will send SO data
+ (this is what the ACC (accumulator) does).
+
+
+
+YM2151 Test register (0x01):
+
+ +----------+-----+------+-----+-----+------+------+------+-------+
+ | bit no. | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ +----------+-----+------+-----+-----+------+------+------+-------+
+ | hex val. | 80 | 40 | 20 | 10 | 08 | 04 | 02 | 01 |
+ +----------+-----+------+-----+-----+------+------+------+-------+
+ | |LS/MS| RIen | HEG | NEG | HPGL | ILFO | HLFO | u_clk |
+ +----------+-----+------+-----+-----+------+------+------+-------+
+
+
+bit 6 - RIen (Read Internal data Enable)
+
+ When set to 1, chip's internal data can be read via status register.
+
+ Simply set this bit and read data that will come out sequentially via the 8-bit
+ bus. Format of this data and the timing will be described later (diagram is above).
+
+
+
+bit 7 - LS/MS (Least Significant or Most Significant 8 bits of internal data)
+
+ When 0 - chip's internal data read via status register is lower 8 bits (LSB),
+ When 1 - chip's internal data is upper 8 bits (MSB) (plus something I haven't figured out).
+
+ In other words: in order to read 8 LSB bits set this bit to 0, in order to read
+ 8 MSB bits set this bit to 1.
+
+
+
+bit 5 - HEG (Halt Envelope Generator)
+
+ When 1 - Envelope Generator gets halted.
+
+ This means that *Phase* Generator data can be read out when:
+ HEG bit is set to 1 (EG gets halted), and data coming out via the status register
+ will be pure sinus wave at the _CURRENT_ EG output.
+ This means you need to know _EXACTLY_ when to set this bit.
+
+ Simple workaround is to do the following:
+ - TL (Total Level) of the operator to minimum dB value (0x00) - it is max volume,
+ - AR (Attack Rate) of the operator to maximum speed (shortest time) (0x1f),
+ - D1L (Decay Level) of the operator to max (93 dB) (0xf0),
+ - D1R (Decay Rate) of the operator to zero (infinite time) speed (0x00),
+ - set KEYON of that operator,
+ - wait a while (long enough so Attack phase of the EG can be done),
+ - set HEG bit in the test register to 1,
+ and its done, since EG will be halted generating 0 (zero) dB level for
+ that operator (exactly speaking EG will stay in D1R phase) and, since 0 dB from EG
+ means no change on the sinus data stored inside of the chip's internal ROM,
+ you can read this ROM data.
+
+ Careful reader will notice that it may not be needed to use HEG bit to read the data
+ (bacause EG will be at 0dB anyway), but using this bit, one can make samples
+ of pure PHASE generator innerworking - that is how I obtained phaseinc_rom[].
+
+
+
+bit 4 - NEG (Negate output data)
+
+ When 1 - output data sign will be simply inverted.
+
+ Worth noticing is that when this bit is 1 - also chip output data will be negated,
+ causing bad sound coming out of the speakers since the YM3012 (the D/A converter)
+ does not expect the negated data !!!
+
+
+
+bit 3 - HPGL (Halt Phase Generator AND LFO amplitude modulation)
+
+ When 1 - Phase Generator is halted. Also amplitude modulation
+ (from LFO to Envelope Generator) is halted.
+
+ You can use this bit to analyse Envelope Generator work.
+ As it was in the case of HEG bit you need to know _EXACTLY_ when to set this bit.
+ Unfortunately, there is no _simple_ way. You will need to synchronise on the chip
+ output signals to know when to set it.
+
+
+
+bit 2 - ILFO (Internal LFO related)
+
+ When 1 - LFO output (depends on selected waveform)
+
+ LFO outputs some internal signals...what are they ?
+ I did not test if this bit alters Phase Modulation in any way.
+
+ Also alters timer A somehow. At least it sounds like a restart.
+
+
+
+bit 1 - HLFO (Halt LFO)
+
+ When 1 - LFO gets HALTED (at maximum amplitude in case of AM).
+
+ On the 1 to 0 transition LFO will be RESET to startup of the waveform
+ (phase of the LFO _only_).
+
+
+
+bit 0 - u_clk (unknown, but probably internal clock related)
+
+ When 1 - Envelope Generator times are much shorter (faster envelopes).
+
+ I do not know if it alters Attacks parts of the envelope. I'm sure it
+ alters Decays times. Also timers are much (twice ?) faster than normally.
+ Perhaps this bit is disabling some internal clock divider.
+ FWIW, frequencies of the operators are NOT altered by setting this bit.
+
+
+Jarek Burczynski
+
+s0246@poczta.onet.pl
+bujar at mame dot net
diff --git a/src/emu/sound/ym2413.c b/src/emu/sound/ym2413.c
new file mode 100644
index 00000000000..f4d65b2263a
--- /dev/null
+++ b/src/emu/sound/ym2413.c
@@ -0,0 +1,2122 @@
+/*
+**
+** File: ym2413.c - software implementation of YM2413
+** FM sound generator type OPLL
+**
+** Copyright (C) 2002 Jarek Burczynski
+**
+** Version 1.0
+**
+
+
+to do:
+
+- make sure of the sinus amplitude bits
+
+- make sure of the EG resolution bits (looks like the biggest
+ modulation index generated by the modulator is 123, 124 = no modulation)
+- find proper algorithm for attack phase of EG
+
+- tune up instruments ROM
+
+- support sample replay in test mode (it is NOT as simple as setting bit 0
+ in register 0x0f and using register 0x10 for sample data).
+ Which games use this feature ?
+
+
+*/
+
+#include <math.h>
+
+#include "sndintrf.h" /* use M.A.M.E. */
+#include "ym2413.h"
+
+
+
+/* output final shift */
+#if (SAMPLE_BITS==16)
+ #define FINAL_SH (0)
+ #define MAXOUT (+32767)
+ #define MINOUT (-32768)
+#else
+ #define FINAL_SH (8)
+ #define MAXOUT (+127)
+ #define MINOUT (-128)
+#endif
+
+
+#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
+#define EG_SH 16 /* 16.16 fixed point (EG timing) */
+#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
+
+#define FREQ_MASK ((1<<FREQ_SH)-1)
+
+/* envelope output entries */
+#define ENV_BITS 10
+#define ENV_LEN (1<<ENV_BITS)
+#define ENV_STEP (128.0/ENV_LEN)
+
+#define MAX_ATT_INDEX ((1<<(ENV_BITS-2))-1) /*255*/
+#define MIN_ATT_INDEX (0)
+
+/* sinwave entries */
+#define SIN_BITS 10
+#define SIN_LEN (1<<SIN_BITS)
+#define SIN_MASK (SIN_LEN-1)
+
+#define TL_RES_LEN (256) /* 8 bits addressing (real chip) */
+
+
+
+/* register number to channel number , slot offset */
+#define SLOT1 0
+#define SLOT2 1
+
+/* Envelope Generator phases */
+
+#define EG_DMP 5
+#define EG_ATT 4
+#define EG_DEC 3
+#define EG_SUS 2
+#define EG_REL 1
+#define EG_OFF 0
+
+
+/* save output as raw 16-bit sample */
+
+//#define SAVE_SAMPLE
+
+#ifdef SAVE_SAMPLE
+INLINE signed int acc_calc(signed int value)
+{
+ if (value>=0)
+ {
+ if (value < 0x0200)
+ return (value & ~0);
+ if (value < 0x0400)
+ return (value & ~1);
+ if (value < 0x0800)
+ return (value & ~3);
+ if (value < 0x1000)
+ return (value & ~7);
+ if (value < 0x2000)
+ return (value & ~15);
+ if (value < 0x4000)
+ return (value & ~31);
+ return (value & ~63);
+ }
+ /*else value < 0*/
+ if (value > -0x0200)
+ return (~abs(value) & ~0);
+ if (value > -0x0400)
+ return (~abs(value) & ~1);
+ if (value > -0x0800)
+ return (~abs(value) & ~3);
+ if (value > -0x1000)
+ return (~abs(value) & ~7);
+ if (value > -0x2000)
+ return (~abs(value) & ~15);
+ if (value > -0x4000)
+ return (~abs(value) & ~31);
+ return (~abs(value) & ~63);
+}
+
+
+static FILE *sample[1];
+ #if 0 /*save to MONO file */
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = acc_calc(mo); \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ }
+ #else /*save to STEREO file */
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = mo; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ pom = ro; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ }
+ #define SAVE_SEPARATE_CHANNEL(j) \
+ { signed int pom = outchan; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ pom = chip->instvol_r[j]>>4; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ }
+ #endif
+#endif
+
+/*#define LOG_CYM_FILE*/
+#ifdef LOG_CYM_FILE
+ FILE * cymfile = NULL;
+#endif
+
+
+
+
+typedef struct{
+ UINT32 ar; /* attack rate: AR<<2 */
+ UINT32 dr; /* decay rate: DR<<2 */
+ UINT32 rr; /* release rate:RR<<2 */
+ UINT8 KSR; /* key scale rate */
+ UINT8 ksl; /* keyscale level */
+ UINT8 ksr; /* key scale rate: kcode>>KSR */
+ UINT8 mul; /* multiple: mul_tab[ML] */
+
+ /* Phase Generator */
+ UINT32 phase; /* frequency counter */
+ UINT32 freq; /* frequency counter step */
+ UINT8 fb_shift; /* feedback shift value */
+ INT32 op1_out[2]; /* slot1 output for feedback */
+
+ /* Envelope Generator */
+ UINT8 eg_type; /* percussive/nonpercussive mode*/
+ UINT8 state; /* phase type */
+ UINT32 TL; /* total level: TL << 2 */
+ INT32 TLL; /* adjusted now TL */
+ INT32 volume; /* envelope counter */
+ UINT32 sl; /* sustain level: sl_tab[SL] */
+
+ UINT8 eg_sh_dp; /* (dump state) */
+ UINT8 eg_sel_dp; /* (dump state) */
+ UINT8 eg_sh_ar; /* (attack state) */
+ UINT8 eg_sel_ar; /* (attack state) */
+ UINT8 eg_sh_dr; /* (decay state) */
+ UINT8 eg_sel_dr; /* (decay state) */
+ UINT8 eg_sh_rr; /* (release state for non-perc.)*/
+ UINT8 eg_sel_rr; /* (release state for non-perc.)*/
+ UINT8 eg_sh_rs; /* (release state for perc.mode)*/
+ UINT8 eg_sel_rs; /* (release state for perc.mode)*/
+
+ UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
+
+ /* LFO */
+ UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
+ UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/
+
+ /* waveform select */
+ unsigned int wavetable;
+} OPLL_SLOT;
+
+typedef struct{
+ OPLL_SLOT SLOT[2];
+ /* phase generator state */
+ UINT32 block_fnum; /* block+fnum */
+ UINT32 fc; /* Freq. freqement base */
+ UINT32 ksl_base; /* KeyScaleLevel Base step */
+ UINT8 kcode; /* key code (for key scaling) */
+ UINT8 sus; /* sus on/off (release speed in percussive mode)*/
+} OPLL_CH;
+
+/* chip state */
+typedef struct {
+ OPLL_CH P_CH[9]; /* OPLL chips have 9 channels*/
+ UINT8 instvol_r[9]; /* instrument/volume (or volume/volume in percussive mode)*/
+
+ UINT32 eg_cnt; /* global envelope generator counter */
+ UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */
+ UINT32 eg_timer_add; /* step of eg_timer */
+ UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */
+
+ UINT8 rhythm; /* Rhythm mode */
+
+ /* LFO */
+ UINT32 lfo_am_cnt;
+ UINT32 lfo_am_inc;
+ UINT32 lfo_pm_cnt;
+ UINT32 lfo_pm_inc;
+
+ UINT32 noise_rng; /* 23 bit noise shift register */
+ UINT32 noise_p; /* current noise 'phase' */
+ UINT32 noise_f; /* current noise period */
+
+
+/* instrument settings */
+/*
+ 0-user instrument
+ 1-15 - fixed instruments
+ 16 -bass drum settings
+ 17,18 - other percussion instruments
+*/
+ UINT8 inst_tab[19][8];
+
+ /* external event callback handlers */
+ OPLL_UPDATEHANDLER UpdateHandler; /* stream update handler */
+ void * UpdateParam; /* stream update parameter */
+
+ UINT32 fn_tab[1024]; /* fnumber->increment counter */
+
+ UINT8 address; /* address register */
+ UINT8 status; /* status flag */
+
+ int clock; /* master clock (Hz) */
+ int rate; /* sampling rate (Hz) */
+ double freqbase; /* frequency base */
+} YM2413;
+
+/* key scale level */
+/* table is 3dB/octave, DV converts this into 6dB/octave */
+/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */
+#define DV (0.1875/1.0)
+static const UINT32 ksl_tab[8*16]=
+{
+ /* OCT 0 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ /* OCT 1 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV,
+ 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV,
+ /* OCT 2 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV,
+ 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV,
+ 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV,
+ /* OCT 3 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV,
+ 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV,
+ 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV,
+ 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV,
+ /* OCT 4 */
+ 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV,
+ 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV,
+ 9.000/DV, 9.750/DV,10.125/DV,10.500/DV,
+ 10.875/DV,11.250/DV,11.625/DV,12.000/DV,
+ /* OCT 5 */
+ 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV,
+ 9.000/DV,10.125/DV,10.875/DV,11.625/DV,
+ 12.000/DV,12.750/DV,13.125/DV,13.500/DV,
+ 13.875/DV,14.250/DV,14.625/DV,15.000/DV,
+ /* OCT 6 */
+ 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV,
+ 12.000/DV,13.125/DV,13.875/DV,14.625/DV,
+ 15.000/DV,15.750/DV,16.125/DV,16.500/DV,
+ 16.875/DV,17.250/DV,17.625/DV,18.000/DV,
+ /* OCT 7 */
+ 0.000/DV, 9.000/DV,12.000/DV,13.875/DV,
+ 15.000/DV,16.125/DV,16.875/DV,17.625/DV,
+ 18.000/DV,18.750/DV,19.125/DV,19.500/DV,
+ 19.875/DV,20.250/DV,20.625/DV,21.000/DV
+};
+#undef DV
+
+/* sustain level table (3dB per step) */
+/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,45 (dB)*/
+#define SC(db) (UINT32) ( db * (1.0/ENV_STEP) )
+static const UINT32 sl_tab[16]={
+ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
+ SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(15)
+};
+#undef SC
+
+
+#define RATE_STEPS (8)
+static const unsigned char eg_inc[15*RATE_STEPS]={
+
+/*cycle:0 1 2 3 4 5 6 7*/
+
+/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */
+/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */
+/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */
+/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */
+
+/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */
+/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */
+/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */
+/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */
+
+/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */
+/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */
+/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */
+/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */
+
+/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */
+/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */
+/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */
+};
+
+
+#define O(a) (a*RATE_STEPS)
+
+/*note that there is no O(13) in this table - it's directly in the code */
+static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */
+/* 16 infinite time rates */
+O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
+O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
+
+/* rates 00-12 */
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+
+/* rate 13 */
+O( 4),O( 5),O( 6),O( 7),
+
+/* rate 14 */
+O( 8),O( 9),O(10),O(11),
+
+/* rate 15 */
+O(12),O(12),O(12),O(12),
+
+/* 16 dummy rates (same as 15 3) */
+O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
+O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
+
+};
+#undef O
+
+/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */
+/*shift 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0 */
+/*mask 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0 */
+
+#define O(a) (a*1)
+static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */
+/* 16 infinite time rates */
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+
+/* rates 00-12 */
+O(13),O(13),O(13),O(13),
+O(12),O(12),O(12),O(12),
+O(11),O(11),O(11),O(11),
+O(10),O(10),O(10),O(10),
+O( 9),O( 9),O( 9),O( 9),
+O( 8),O( 8),O( 8),O( 8),
+O( 7),O( 7),O( 7),O( 7),
+O( 6),O( 6),O( 6),O( 6),
+O( 5),O( 5),O( 5),O( 5),
+O( 4),O( 4),O( 4),O( 4),
+O( 3),O( 3),O( 3),O( 3),
+O( 2),O( 2),O( 2),O( 2),
+O( 1),O( 1),O( 1),O( 1),
+
+/* rate 13 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 14 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 15 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* 16 dummy rates (same as 15 3) */
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+
+};
+#undef O
+
+
+/* multiple table */
+#define ML 2
+static const UINT8 mul_tab[16]= {
+/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */
+ 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
+ 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
+};
+#undef ML
+
+/* TL_TAB_LEN is calculated as:
+* 11 - sinus amplitude bits (Y axis)
+* 2 - sinus sign bit (Y axis)
+* TL_RES_LEN - sinus resolution (X axis)
+*/
+#define TL_TAB_LEN (11*2*TL_RES_LEN)
+static signed int tl_tab[TL_TAB_LEN];
+
+#define ENV_QUIET (TL_TAB_LEN>>5)
+
+/* sin waveform table in 'decibel' scale */
+/* two waveforms on OPLL type chips */
+static unsigned int sin_tab[SIN_LEN * 2];
+
+
+/* LFO Amplitude Modulation table (verified on real YM3812)
+ 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples
+
+ Length: 210 elements.
+
+ Each of the elements has to be repeated
+ exactly 64 times (on 64 consecutive samples).
+ The whole table takes: 64 * 210 = 13440 samples.
+
+We use data>>1, until we find what it really is on real chip...
+
+*/
+
+#define LFO_AM_TAB_ELEMENTS 210
+
+static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = {
+0,0,0,0,0,0,0,
+1,1,1,1,
+2,2,2,2,
+3,3,3,3,
+4,4,4,4,
+5,5,5,5,
+6,6,6,6,
+7,7,7,7,
+8,8,8,8,
+9,9,9,9,
+10,10,10,10,
+11,11,11,11,
+12,12,12,12,
+13,13,13,13,
+14,14,14,14,
+15,15,15,15,
+16,16,16,16,
+17,17,17,17,
+18,18,18,18,
+19,19,19,19,
+20,20,20,20,
+21,21,21,21,
+22,22,22,22,
+23,23,23,23,
+24,24,24,24,
+25,25,25,25,
+26,26,26,
+25,25,25,25,
+24,24,24,24,
+23,23,23,23,
+22,22,22,22,
+21,21,21,21,
+20,20,20,20,
+19,19,19,19,
+18,18,18,18,
+17,17,17,17,
+16,16,16,16,
+15,15,15,15,
+14,14,14,14,
+13,13,13,13,
+12,12,12,12,
+11,11,11,11,
+10,10,10,10,
+9,9,9,9,
+8,8,8,8,
+7,7,7,7,
+6,6,6,6,
+5,5,5,5,
+4,4,4,4,
+3,3,3,3,
+2,2,2,2,
+1,1,1,1
+};
+
+/* LFO Phase Modulation table (verified on real YM2413) */
+static const INT8 lfo_pm_table[8*8] = {
+
+/* FNUM2/FNUM = 0 00xxxxxx (0x0000) */
+0, 0, 0, 0, 0, 0, 0, 0,
+
+/* FNUM2/FNUM = 0 01xxxxxx (0x0040) */
+1, 0, 0, 0,-1, 0, 0, 0,
+
+/* FNUM2/FNUM = 0 10xxxxxx (0x0080) */
+2, 1, 0,-1,-2,-1, 0, 1,
+
+/* FNUM2/FNUM = 0 11xxxxxx (0x00C0) */
+3, 1, 0,-1,-3,-1, 0, 1,
+
+/* FNUM2/FNUM = 1 00xxxxxx (0x0100) */
+4, 2, 0,-2,-4,-2, 0, 2,
+
+/* FNUM2/FNUM = 1 01xxxxxx (0x0140) */
+5, 2, 0,-2,-5,-2, 0, 2,
+
+/* FNUM2/FNUM = 1 10xxxxxx (0x0180) */
+6, 3, 0,-3,-6,-3, 0, 3,
+
+/* FNUM2/FNUM = 1 11xxxxxx (0x01C0) */
+7, 3, 0,-3,-7,-3, 0, 3,
+};
+
+
+
+
+
+
+/* This is not 100% perfect yet but very close */
+/*
+ - multi parameters are 100% correct (instruments and drums)
+ - LFO PM and AM enable are 100% correct
+ - waveform DC and DM select are 100% correct
+*/
+
+static unsigned char table[19][8] = {
+/* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */
+/* 0 1 2 3 4 5 6 7 */
+ {0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, //0
+
+ {0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, //1
+ {0x13, 0x41, 0x1e, 0x0d, 0xd7, 0xf7, 0x13, 0x13 }, //2
+ {0x13, 0x01, 0x99, 0x04, 0xf2, 0xf4, 0x11, 0x23 }, //3
+ {0x21, 0x61, 0x1b, 0x07, 0xaf, 0x64, 0x40, 0x27 }, //4
+
+//{0x22, 0x21, 0x1e, 0x09, 0xf0, 0x76, 0x08, 0x28 }, //5
+ {0x22, 0x21, 0x1e, 0x06, 0xf0, 0x75, 0x08, 0x18 }, //5
+
+//{0x31, 0x22, 0x16, 0x09, 0x90, 0x7f, 0x00, 0x08 }, //6
+ {0x31, 0x22, 0x16, 0x05, 0x90, 0x71, 0x00, 0x13 }, //6
+
+ {0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x10, 0x17 }, //7
+ {0x23, 0x21, 0x2d, 0x16, 0xc0, 0x70, 0x07, 0x07 }, //8
+ {0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 }, //9
+
+//{0x61, 0x61, 0x0c, 0x08, 0x85, 0xa0, 0x79, 0x07 }, //A
+ {0x61, 0x61, 0x0c, 0x18, 0x85, 0xf0, 0x70, 0x07 }, //A
+
+ {0x23, 0x01, 0x07, 0x11, 0xf0, 0xa4, 0x00, 0x22 }, //B
+ {0x97, 0xc1, 0x24, 0x07, 0xff, 0xf8, 0x22, 0x12 }, //C
+
+//{0x61, 0x10, 0x0c, 0x08, 0xf2, 0xc4, 0x40, 0xc8 }, //D
+ {0x61, 0x10, 0x0c, 0x05, 0xf2, 0xf4, 0x40, 0x44 }, //D
+
+ {0x01, 0x01, 0x55, 0x03, 0xf3, 0x92, 0xf3, 0xf3 }, //E
+ {0x61, 0x41, 0x89, 0x03, 0xf1, 0xf4, 0xf0, 0x13 }, //F
+
+/* drum instruments definitions */
+/* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */
+/* 0 1 2 3 4 5 6 7 */
+ {0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */
+ {0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */
+ {0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */
+};
+
+/* lock level of common table */
+static int num_lock = 0;
+
+/* work table */
+static void *cur_chip = NULL; /* current chip pointer */
+static OPLL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2;
+
+static signed int output[2];
+static signed int outchan;
+
+static UINT32 LFO_AM;
+static INT32 LFO_PM;
+
+
+INLINE int limit( int val, int max, int min ) {
+ if ( val > max )
+ val = max;
+ else if ( val < min )
+ val = min;
+
+ return val;
+}
+
+
+/* advance LFO to next sample */
+INLINE void advance_lfo(YM2413 *chip)
+{
+ /* LFO */
+ chip->lfo_am_cnt += chip->lfo_am_inc;
+ if (chip->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<<LFO_SH) ) /* lfo_am_table is 210 elements long */
+ chip->lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<<LFO_SH);
+
+ LFO_AM = lfo_am_table[ chip->lfo_am_cnt >> LFO_SH ] >> 1;
+
+ chip->lfo_pm_cnt += chip->lfo_pm_inc;
+ LFO_PM = (chip->lfo_pm_cnt>>LFO_SH) & 7;
+}
+
+/* advance to next sample */
+INLINE void advance(YM2413 *chip)
+{
+ OPLL_CH *CH;
+ OPLL_SLOT *op;
+ unsigned int i;
+
+ /* Envelope Generator */
+ chip->eg_timer += chip->eg_timer_add;
+
+ while (chip->eg_timer >= chip->eg_timer_overflow)
+ {
+ chip->eg_timer -= chip->eg_timer_overflow;
+
+ chip->eg_cnt++;
+
+ for (i=0; i<9*2; i++)
+ {
+ CH = &chip->P_CH[i/2];
+
+ op = &CH->SLOT[i&1];
+
+ switch(op->state)
+ {
+
+ case EG_DMP: /* dump phase */
+ /*dump phase is performed by both operators in each channel*/
+ /*when CARRIER envelope gets down to zero level,
+ ** phases in BOTH opearators are reset (at the same time ?)
+ */
+ if ( !(chip->eg_cnt & ((1<<op->eg_sh_dp)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_dp + ((chip->eg_cnt>>op->eg_sh_dp)&7)];
+
+ if ( op->volume >= MAX_ATT_INDEX )
+ {
+ op->volume = MAX_ATT_INDEX;
+ op->state = EG_ATT;
+ /* restart Phase Generator */
+ op->phase = 0;
+ }
+ }
+ break;
+
+ case EG_ATT: /* attack phase */
+ if ( !(chip->eg_cnt & ((1<<op->eg_sh_ar)-1) ) )
+ {
+ op->volume += (~op->volume *
+ (eg_inc[op->eg_sel_ar + ((chip->eg_cnt>>op->eg_sh_ar)&7)])
+ ) >>2;
+
+ if (op->volume <= MIN_ATT_INDEX)
+ {
+ op->volume = MIN_ATT_INDEX;
+ op->state = EG_DEC;
+ }
+ }
+ break;
+
+ case EG_DEC: /* decay phase */
+ if ( !(chip->eg_cnt & ((1<<op->eg_sh_dr)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_dr + ((chip->eg_cnt>>op->eg_sh_dr)&7)];
+
+ if ( op->volume >= op->sl )
+ op->state = EG_SUS;
+ }
+ break;
+
+ case EG_SUS: /* sustain phase */
+ /* this is important behaviour:
+ one can change percusive/non-percussive modes on the fly and
+ the chip will remain in sustain phase - verified on real YM3812 */
+
+ if(op->eg_type) /* non-percussive mode (sustained tone) */
+ {
+ /* do nothing */
+ }
+ else /* percussive mode */
+ {
+ /* during sustain phase chip adds Release Rate (in percussive mode) */
+ if ( !(chip->eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)];
+
+ if ( op->volume >= MAX_ATT_INDEX )
+ op->volume = MAX_ATT_INDEX;
+ }
+ /* else do nothing in sustain phase */
+ }
+ break;
+
+ case EG_REL: /* release phase */
+ /* exclude modulators in melody channels from performing anything in this mode*/
+ /* allowed are only carriers in melody mode and rhythm slots in rhythm mode */
+
+ /*This table shows which operators and on what conditions are allowed to perform EG_REL:
+ (a) - always perform EG_REL
+ (n) - never perform EG_REL
+ (r) - perform EG_REL in Rhythm mode ONLY
+ 0: 0 (n), 1 (a)
+ 1: 2 (n), 3 (a)
+ 2: 4 (n), 5 (a)
+ 3: 6 (n), 7 (a)
+ 4: 8 (n), 9 (a)
+ 5: 10(n), 11(a)
+ 6: 12(r), 13(a)
+ 7: 14(r), 15(a)
+ 8: 16(r), 17(a)
+ */
+ if ( (i&1) || ((chip->rhythm&0x20) && (i>=12)) )/* exclude modulators */
+ {
+ if(op->eg_type) /* non-percussive mode (sustained tone) */
+ /*this is correct: use RR when SUS = OFF*/
+ /*and use RS when SUS = ON*/
+ {
+ if (CH->sus)
+ {
+ if ( !(chip->eg_cnt & ((1<<op->eg_sh_rs)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_rs + ((chip->eg_cnt>>op->eg_sh_rs)&7)];
+ if ( op->volume >= MAX_ATT_INDEX )
+ {
+ op->volume = MAX_ATT_INDEX;
+ op->state = EG_OFF;
+ }
+ }
+ }
+ else
+ {
+ if ( !(chip->eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)];
+ if ( op->volume >= MAX_ATT_INDEX )
+ {
+ op->volume = MAX_ATT_INDEX;
+ op->state = EG_OFF;
+ }
+ }
+ }
+ }
+ else /* percussive mode */
+ {
+ if ( !(chip->eg_cnt & ((1<<op->eg_sh_rs)-1) ) )
+ {
+ op->volume += eg_inc[op->eg_sel_rs + ((chip->eg_cnt>>op->eg_sh_rs)&7)];
+ if ( op->volume >= MAX_ATT_INDEX )
+ {
+ op->volume = MAX_ATT_INDEX;
+ op->state = EG_OFF;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ for (i=0; i<9*2; i++)
+ {
+ CH = &chip->P_CH[i/2];
+ op = &CH->SLOT[i&1];
+
+ /* Phase Generator */
+ if(op->vib)
+ {
+ UINT8 block;
+
+ unsigned int fnum_lfo = 8*((CH->block_fnum&0x01c0) >> 6);
+ unsigned int block_fnum = CH->block_fnum * 2;
+ signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + fnum_lfo ];
+
+ if (lfo_fn_table_index_offset) /* LFO phase modulation active */
+ {
+ block_fnum += lfo_fn_table_index_offset;
+ block = (block_fnum&0x1c00) >> 10;
+ op->phase += (chip->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul;
+ }
+ else /* LFO phase modulation = zero */
+ {
+ op->phase += op->freq;
+ }
+ }
+ else /* LFO phase modulation disabled for this operator */
+ {
+ op->phase += op->freq;
+ }
+ }
+
+ /* The Noise Generator of the YM3812 is 23-bit shift register.
+ * Period is equal to 2^23-2 samples.
+ * Register works at sampling frequency of the chip, so output
+ * can change on every sample.
+ *
+ * Output of the register and input to the bit 22 is:
+ * bit0 XOR bit14 XOR bit15 XOR bit22
+ *
+ * Simply use bit 22 as the noise output.
+ */
+
+ chip->noise_p += chip->noise_f;
+ i = chip->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */
+ chip->noise_p &= FREQ_MASK;
+ while (i)
+ {
+ /*
+ UINT32 j;
+ j = ( (chip->noise_rng) ^ (chip->noise_rng>>14) ^ (chip->noise_rng>>15) ^ (chip->noise_rng>>22) ) & 1;
+ chip->noise_rng = (j<<22) | (chip->noise_rng>>1);
+ */
+
+ /*
+ Instead of doing all the logic operations above, we
+ use a trick here (and use bit 0 as the noise output).
+ The difference is only that the noise bit changes one
+ step ahead. This doesn't matter since we don't know
+ what is real state of the noise_rng after the reset.
+ */
+
+ if (chip->noise_rng & 1) chip->noise_rng ^= 0x800302;
+ chip->noise_rng >>= 1;
+
+ i--;
+ }
+}
+
+
+INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab)
+{
+ UINT32 p;
+
+ p = (env<<5) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<17))) >> FREQ_SH ) & SIN_MASK) ];
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+ return tl_tab[p];
+}
+
+INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab)
+{
+ UINT32 p;
+ INT32 i;
+
+ i = (phase & ~FREQ_MASK) + pm;
+
+/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, phase>>FREQ_SH, pm);*/
+
+ p = (env<<5) + sin_tab[ wave_tab + ((i>>FREQ_SH) & SIN_MASK)];
+
+/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+ return tl_tab[p];
+}
+
+
+#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask))
+
+/* calculate output */
+INLINE void chan_calc( OPLL_CH *CH )
+{
+ OPLL_SLOT *SLOT;
+ unsigned int env;
+ signed int out;
+ signed int phase_modulation; /* phase modulation input (SLOT 2) */
+
+
+ /* SLOT 1 */
+ SLOT = &CH->SLOT[SLOT1];
+ env = volume_calc(SLOT);
+ out = SLOT->op1_out[0] + SLOT->op1_out[1];
+
+ SLOT->op1_out[0] = SLOT->op1_out[1];
+ phase_modulation = SLOT->op1_out[0];
+
+ SLOT->op1_out[1] = 0;
+
+ if( env < ENV_QUIET )
+ {
+ if (!SLOT->fb_shift)
+ out = 0;
+ SLOT->op1_out[1] = op_calc1(SLOT->phase, env, (out<<SLOT->fb_shift), SLOT->wavetable );
+ }
+
+ /* SLOT 2 */
+
+outchan=0;
+
+ SLOT++;
+ env = volume_calc(SLOT);
+ if( env < ENV_QUIET )
+ {
+ signed int outp = op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable);
+ output[0] += outp;
+ outchan = outp;
+ //output[0] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable);
+ }
+}
+
+/*
+ operators used in the rhythm sounds generation process:
+
+ Envelope Generator:
+
+channel operator register number Bass High Snare Tom Top
+/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal
+ 6 / 0 12 50 70 90 f0 +
+ 6 / 1 15 53 73 93 f3 +
+ 7 / 0 13 51 71 91 f1 +
+ 7 / 1 16 54 74 94 f4 +
+ 8 / 0 14 52 72 92 f2 +
+ 8 / 1 17 55 75 95 f5 +
+
+ Phase Generator:
+
+channel operator register number Bass High Snare Tom Top
+/ slot number MULTIPLE Drum Hat Drum Tom Cymbal
+ 6 / 0 12 30 +
+ 6 / 1 15 33 +
+ 7 / 0 13 31 + + +
+ 7 / 1 16 34 ----- n o t u s e d -----
+ 8 / 0 14 32 +
+ 8 / 1 17 35 + +
+
+channel operator register number Bass High Snare Tom Top
+number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal
+ 6 12,15 B6 A6 +
+
+ 7 13,16 B7 A7 + + +
+
+ 8 14,17 B8 A8 + + +
+
+*/
+
+/* calculate rhythm */
+
+INLINE void rhythm_calc( OPLL_CH *CH, unsigned int noise )
+{
+ OPLL_SLOT *SLOT;
+ signed int out;
+ unsigned int env;
+ signed int phase_modulation; /* phase modulation input (SLOT 2) */
+
+
+ /* Bass Drum (verified on real YM3812):
+ - depends on the channel 6 'connect' register:
+ when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out)
+ when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored
+ - output sample always is multiplied by 2
+ */
+
+
+ /* SLOT 1 */
+ SLOT = &CH[6].SLOT[SLOT1];
+ env = volume_calc(SLOT);
+
+ out = SLOT->op1_out[0] + SLOT->op1_out[1];
+ SLOT->op1_out[0] = SLOT->op1_out[1];
+
+ phase_modulation = SLOT->op1_out[0];
+
+ SLOT->op1_out[1] = 0;
+ if( env < ENV_QUIET )
+ {
+ if (!SLOT->fb_shift)
+ out = 0;
+ SLOT->op1_out[1] = op_calc1(SLOT->phase, env, (out<<SLOT->fb_shift), SLOT->wavetable );
+ }
+
+ /* SLOT 2 */
+ SLOT++;
+ env = volume_calc(SLOT);
+ if( env < ENV_QUIET )
+ output[1] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable) * 2;
+
+
+ /* Phase generation is based on: */
+ // HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases)
+ // SD (16) channel 7->slot 1
+ // TOM (14) channel 8->slot 1
+ // TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases)
+
+ /* Envelope generation based on: */
+ // HH channel 7->slot1
+ // SD channel 7->slot2
+ // TOM channel 8->slot1
+ // TOP channel 8->slot2
+
+
+ /* The following formulas can be well optimized.
+ I leave them in direct form for now (in case I've missed something).
+ */
+
+ /* High Hat (verified on real YM3812) */
+ env = volume_calc(SLOT7_1);
+ if( env < ENV_QUIET )
+ {
+
+ /* high hat phase generation:
+ phase = d0 or 234 (based on frequency only)
+ phase = 34 or 2d0 (based on noise)
+ */
+
+ /* base frequency derived from operator 1 in channel 7 */
+ unsigned char bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1;
+ unsigned char bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1;
+ unsigned char bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1;
+
+ unsigned char res1 = (bit2 ^ bit7) | bit3;
+
+ /* when res1 = 0 phase = 0x000 | 0xd0; */
+ /* when res1 = 1 phase = 0x200 | (0xd0>>2); */
+ UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0;
+
+ /* enable gate based on frequency of operator 2 in channel 8 */
+ unsigned char bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1;
+ unsigned char bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1;
+
+ unsigned char res2 = (bit3e | bit5e);
+
+ /* when res2 = 0 pass the phase from calculation above (res1); */
+ /* when res2 = 1 phase = 0x200 | (0xd0>>2); */
+ if (res2)
+ phase = (0x200|(0xd0>>2));
+
+
+ /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */
+ /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */
+ if (phase&0x200)
+ {
+ if (noise)
+ phase = 0x200|0xd0;
+ }
+ else
+ /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */
+ /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */
+ {
+ if (noise)
+ phase = 0xd0>>2;
+ }
+
+ output[1] += op_calc(phase<<FREQ_SH, env, 0, SLOT7_1->wavetable) * 2;
+ }
+
+ /* Snare Drum (verified on real YM3812) */
+ env = volume_calc(SLOT7_2);
+ if( env < ENV_QUIET )
+ {
+ /* base frequency derived from operator 1 in channel 7 */
+ unsigned char bit8 = ((SLOT7_1->phase>>FREQ_SH)>>8)&1;
+
+ /* when bit8 = 0 phase = 0x100; */
+ /* when bit8 = 1 phase = 0x200; */
+ UINT32 phase = bit8 ? 0x200 : 0x100;
+
+ /* Noise bit XOR'es phase by 0x100 */
+ /* when noisebit = 0 pass the phase from calculation above */
+ /* when noisebit = 1 phase ^= 0x100; */
+ /* in other words: phase ^= (noisebit<<8); */
+ if (noise)
+ phase ^= 0x100;
+
+ output[1] += op_calc(phase<<FREQ_SH, env, 0, SLOT7_2->wavetable) * 2;
+ }
+
+ /* Tom Tom (verified on real YM3812) */
+ env = volume_calc(SLOT8_1);
+ if( env < ENV_QUIET )
+ output[1] += op_calc(SLOT8_1->phase, env, 0, SLOT8_1->wavetable) * 2;
+
+ /* Top Cymbal (verified on real YM2413) */
+ env = volume_calc(SLOT8_2);
+ if( env < ENV_QUIET )
+ {
+ /* base frequency derived from operator 1 in channel 7 */
+ unsigned char bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1;
+ unsigned char bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1;
+ unsigned char bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1;
+
+ unsigned char res1 = (bit2 ^ bit7) | bit3;
+
+ /* when res1 = 0 phase = 0x000 | 0x100; */
+ /* when res1 = 1 phase = 0x200 | 0x100; */
+ UINT32 phase = res1 ? 0x300 : 0x100;
+
+ /* enable gate based on frequency of operator 2 in channel 8 */
+ unsigned char bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1;
+ unsigned char bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1;
+
+ unsigned char res2 = (bit3e | bit5e);
+ /* when res2 = 0 pass the phase from calculation above (res1); */
+ /* when res2 = 1 phase = 0x200 | 0x100; */
+ if (res2)
+ phase = 0x300;
+
+ output[1] += op_calc(phase<<FREQ_SH, env, 0, SLOT8_2->wavetable) * 2;
+ }
+
+}
+
+
+/* generic table initialize */
+static int init_tables(void)
+{
+ signed int i,x;
+ signed int n;
+ double o,m;
+
+
+ for (x=0; x<TL_RES_LEN; x++)
+ {
+ m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0);
+ m = floor(m);
+
+ /* we never reach (1<<16) here due to the (x+1) */
+ /* result fits within 16 bits at maximum */
+
+ n = (int)m; /* 16 bits here */
+ n >>= 4; /* 12 bits here */
+ if (n&1) /* round to nearest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+ /* 11 bits here (rounded) */
+ tl_tab[ x*2 + 0 ] = n;
+ tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ];
+
+ for (i=1; i<11; i++)
+ {
+ tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i;
+ tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ];
+ }
+ #if 0
+ logerror("tl %04i", x*2);
+ for (i=0; i<11; i++)
+ logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] );
+ logerror("\n");
+ #endif
+ }
+ /*logerror("ym2413.c: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/
+
+
+ for (i=0; i<SIN_LEN; i++)
+ {
+ /* non-standard sinus */
+ m = sin( ((i*2)+1) * M_PI / SIN_LEN ); /* checked against the real chip */
+
+ /* we never reach zero here due to ((i*2)+1) */
+
+ if (m>0.0)
+ o = 8*log(1.0/m)/log(2); /* convert to 'decibels' */
+ else
+ o = 8*log(-1.0/m)/log(2); /* convert to 'decibels' */
+
+ o = o / (ENV_STEP/4);
+
+ n = (int)(2.0*o);
+ if (n&1) /* round to nearest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+
+ /* waveform 0: standard sinus */
+ sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 );
+
+ /*logerror("ym2413.c: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/
+
+
+ /* waveform 1: __ __ */
+ /* / \____/ \____*/
+ /* output only first half of the sinus waveform (positive one) */
+ if (i & (1<<(SIN_BITS-1)) )
+ sin_tab[1*SIN_LEN+i] = TL_TAB_LEN;
+ else
+ sin_tab[1*SIN_LEN+i] = sin_tab[i];
+
+ /*logerror("ym2413.c: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] );*/
+ }
+#if 0
+ logerror("YM2413.C: ENV_QUIET= %08x (*32=%08x)\n", ENV_QUIET, ENV_QUIET*32 );
+ for (i=0; i<ENV_QUIET; i++)
+ {
+ logerror("tl_tb[%4x(%4i)]=%8x\n", i<<5, i, tl_tab[i<<5] );
+ }
+#endif
+#ifdef SAVE_SAMPLE
+ sample[0]=fopen("sampsum.pcm","wb");
+#endif
+
+ return 1;
+}
+
+static void OPLCloseTable( void )
+{
+#ifdef SAVE_SAMPLE
+ fclose(sample[0]);
+#endif
+}
+
+
+
+static void OPLL_initalize(YM2413 *chip)
+{
+ int i;
+
+ /* frequency base */
+ chip->freqbase = (chip->rate) ? ((double)chip->clock / 72.0) / chip->rate : 0;
+#if 0
+ chip->rate = (double)chip->clock / 72.0;
+ chip->freqbase = 1.0;
+ logerror("freqbase=%f\n", chip->freqbase);
+#endif
+
+
+
+ /* make fnumber -> increment counter table */
+ for( i = 0 ; i < 1024; i++ )
+ {
+ /* OPLL (YM2413) phase increment counter = 18bit */
+
+ chip->fn_tab[i] = (UINT32)( (double)i * 64 * chip->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
+#if 0
+ logerror("ym2413.c: fn_tab[%4i] = %08x (dec=%8i)\n",
+ i, chip->fn_tab[i]>>6, chip->fn_tab[i]>>6 );
+#endif
+ }
+
+#if 0
+ for( i=0 ; i < 16 ; i++ )
+ {
+ logerror("ym2413.c: sl_tab[%i] = %08x\n", i, sl_tab[i] );
+ }
+ for( i=0 ; i < 8 ; i++ )
+ {
+ int j;
+ logerror("ym2413.c: ksl_tab[oct=%2i] =",i);
+ for (j=0; j<16; j++)
+ {
+ logerror("%08x ", ksl_tab[i*16+j] );
+ }
+ logerror("\n");
+ }
+#endif
+
+
+ /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */
+ /* One entry from LFO_AM_TABLE lasts for 64 samples */
+ chip->lfo_am_inc = (1.0 / 64.0 ) * (1<<LFO_SH) * chip->freqbase;
+
+ /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */
+ chip->lfo_pm_inc = (1.0 / 1024.0) * (1<<LFO_SH) * chip->freqbase;
+
+ /*logerror ("chip->lfo_am_inc = %8x ; chip->lfo_pm_inc = %8x\n", chip->lfo_am_inc, chip->lfo_pm_inc);*/
+
+ /* Noise generator: a step takes 1 sample */
+ chip->noise_f = (1.0 / 1.0) * (1<<FREQ_SH) * chip->freqbase;
+ /*logerror("YM2413init noise_f=%8x\n", chip->noise_f);*/
+
+ chip->eg_timer_add = (1<<EG_SH) * chip->freqbase;
+ chip->eg_timer_overflow = ( 1 ) * (1<<EG_SH);
+ /*logerror("YM2413init eg_timer_add=%8x eg_timer_overflow=%8x\n", chip->eg_timer_add, chip->eg_timer_overflow);*/
+
+}
+
+INLINE void KEY_ON(OPLL_SLOT *SLOT, UINT32 key_set)
+{
+ if( !SLOT->key )
+ {
+ /* do NOT restart Phase Generator (verified on real YM2413)*/
+ /* phase -> Dump */
+ SLOT->state = EG_DMP;
+ }
+ SLOT->key |= key_set;
+}
+
+INLINE void KEY_OFF(OPLL_SLOT *SLOT, UINT32 key_clr)
+{
+ if( SLOT->key )
+ {
+ SLOT->key &= key_clr;
+
+ if( !SLOT->key )
+ {
+ /* phase -> Release */
+ if (SLOT->state>EG_REL)
+ SLOT->state = EG_REL;
+ }
+ }
+}
+
+/* update phase increment counter of operator (also update the EG rates if necessary) */
+INLINE void CALC_FCSLOT(OPLL_CH *CH,OPLL_SLOT *SLOT)
+{
+ int ksr;
+ UINT32 SLOT_rs;
+ UINT32 SLOT_dp;
+
+ /* (frequency) phase increment counter */
+ SLOT->freq = CH->fc * SLOT->mul;
+ ksr = CH->kcode >> SLOT->KSR;
+
+ if( SLOT->ksr != ksr )
+ {
+ SLOT->ksr = ksr;
+
+ /* calculate envelope generator rates */
+ if ((SLOT->ar + SLOT->ksr) < 16+62)
+ {
+ SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
+ SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
+ }
+ else
+ {
+ SLOT->eg_sh_ar = 0;
+ SLOT->eg_sel_ar = 13*RATE_STEPS;
+ }
+ SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ];
+ SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ];
+ SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ];
+ SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ];
+
+ }
+
+ if (CH->sus)
+ SLOT_rs = 16 + (5<<2);
+ else
+ SLOT_rs = 16 + (7<<2);
+
+ SLOT->eg_sh_rs = eg_rate_shift [SLOT_rs + SLOT->ksr ];
+ SLOT->eg_sel_rs = eg_rate_select[SLOT_rs + SLOT->ksr ];
+
+ SLOT_dp = 16 + (13<<2);
+ SLOT->eg_sh_dp = eg_rate_shift [SLOT_dp + SLOT->ksr ];
+ SLOT->eg_sel_dp = eg_rate_select[SLOT_dp + SLOT->ksr ];
+}
+
+/* set multi,am,vib,EG-TYP,KSR,mul */
+INLINE void set_mul(YM2413 *chip,int slot,int v)
+{
+ OPLL_CH *CH = &chip->P_CH[slot/2];
+ OPLL_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ SLOT->mul = mul_tab[v&0x0f];
+ SLOT->KSR = (v&0x10) ? 0 : 2;
+ SLOT->eg_type = (v&0x20);
+ SLOT->vib = (v&0x40);
+ SLOT->AMmask = (v&0x80) ? ~0 : 0;
+ CALC_FCSLOT(CH,SLOT);
+}
+
+/* set ksl, tl */
+INLINE void set_ksl_tl(YM2413 *chip,int chan,int v)
+{
+ int ksl;
+ OPLL_CH *CH = &chip->P_CH[chan];
+/* modulator */
+ OPLL_SLOT *SLOT = &CH->SLOT[SLOT1];
+
+ ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */
+
+ SLOT->ksl = ksl ? 3-ksl : 31;
+ SLOT->TL = (v&0x3f)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+}
+
+/* set ksl , waveforms, feedback */
+INLINE void set_ksl_wave_fb(YM2413 *chip,int chan,int v)
+{
+ int ksl;
+ OPLL_CH *CH = &chip->P_CH[chan];
+/* modulator */
+ OPLL_SLOT *SLOT = &CH->SLOT[SLOT1];
+ SLOT->wavetable = ((v&0x08)>>3)*SIN_LEN;
+ SLOT->fb_shift = (v&7) ? (v&7) + 8 : 0;
+
+/*carrier*/
+ SLOT = &CH->SLOT[SLOT2];
+ ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */
+
+ SLOT->ksl = ksl ? 3-ksl : 31;
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+
+ SLOT->wavetable = ((v&0x10)>>4)*SIN_LEN;
+}
+
+/* set attack rate & decay rate */
+INLINE void set_ar_dr(YM2413 *chip,int slot,int v)
+{
+ OPLL_CH *CH = &chip->P_CH[slot/2];
+ OPLL_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0;
+
+ if ((SLOT->ar + SLOT->ksr) < 16+62)
+ {
+ SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
+ SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
+ }
+ else
+ {
+ SLOT->eg_sh_ar = 0;
+ SLOT->eg_sel_ar = 13*RATE_STEPS;
+ }
+
+ SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0;
+ SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ];
+ SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ];
+}
+
+/* set sustain level & release rate */
+INLINE void set_sl_rr(YM2413 *chip,int slot,int v)
+{
+ OPLL_CH *CH = &chip->P_CH[slot/2];
+ OPLL_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ SLOT->sl = sl_tab[ v>>4 ];
+
+ SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0;
+ SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ];
+ SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ];
+}
+
+static void load_instrument(YM2413 *chip, UINT32 chan, UINT32 slot, UINT8* inst )
+{
+ set_mul (chip, slot, inst[0]);
+ set_mul (chip, slot+1, inst[1]);
+ set_ksl_tl (chip, chan, inst[2]);
+ set_ksl_wave_fb (chip, chan, inst[3]);
+ set_ar_dr (chip, slot, inst[4]);
+ set_ar_dr (chip, slot+1, inst[5]);
+ set_sl_rr (chip, slot, inst[6]);
+ set_sl_rr (chip, slot+1, inst[7]);
+}
+static void update_instrument_zero(YM2413 *chip, UINT8 r )
+{
+ UINT8* inst = &chip->inst_tab[0][0]; /* point to user instrument */
+ UINT32 chan;
+ UINT32 chan_max;
+
+ chan_max = 9;
+ if (chip->rhythm & 0x20)
+ chan_max=6;
+
+ switch(r)
+ {
+ case 0:
+ for (chan=0; chan<chan_max; chan++)
+ {
+ if ((chip->instvol_r[chan]&0xf0)==0)
+ {
+ set_mul (chip, chan*2, inst[0]);
+ }
+ }
+ break;
+ case 1:
+ for (chan=0; chan<chan_max; chan++)
+ {
+ if ((chip->instvol_r[chan]&0xf0)==0)
+ {
+ set_mul (chip, chan*2+1,inst[1]);
+ }
+ }
+ break;
+ case 2:
+ for (chan=0; chan<chan_max; chan++)
+ {
+ if ((chip->instvol_r[chan]&0xf0)==0)
+ {
+ set_ksl_tl (chip, chan, inst[2]);
+ }
+ }
+ break;
+ case 3:
+ for (chan=0; chan<chan_max; chan++)
+ {
+ if ((chip->instvol_r[chan]&0xf0)==0)
+ {
+ set_ksl_wave_fb (chip, chan, inst[3]);
+ }
+ }
+ break;
+ case 4:
+ for (chan=0; chan<chan_max; chan++)
+ {
+ if ((chip->instvol_r[chan]&0xf0)==0)
+ {
+ set_ar_dr (chip, chan*2, inst[4]);
+ }
+ }
+ break;
+ case 5:
+ for (chan=0; chan<chan_max; chan++)
+ {
+ if ((chip->instvol_r[chan]&0xf0)==0)
+ {
+ set_ar_dr (chip, chan*2+1,inst[5]);
+ }
+ }
+ break;
+ case 6:
+ for (chan=0; chan<chan_max; chan++)
+ {
+ if ((chip->instvol_r[chan]&0xf0)==0)
+ {
+ set_sl_rr (chip, chan*2, inst[6]);
+ }
+ }
+ break;
+ case 7:
+ for (chan=0; chan<chan_max; chan++)
+ {
+ if ((chip->instvol_r[chan]&0xf0)==0)
+ {
+ set_sl_rr (chip, chan*2+1,inst[7]);
+ }
+ }
+ break;
+ }
+}
+
+/* write a value v to register r on chip chip */
+static void OPLLWriteReg(YM2413 *chip, int r, int v)
+{
+ OPLL_CH *CH;
+ OPLL_SLOT *SLOT;
+ UINT8 *inst;
+ int chan;
+ int slot;
+
+ /* adjust bus to 8 bits */
+ r &= 0xff;
+ v &= 0xff;
+
+
+#ifdef LOG_CYM_FILE
+ if ((cymfile) && (r!=8) )
+ {
+ fputc( (unsigned char)r, cymfile );
+ fputc( (unsigned char)v, cymfile );
+ }
+#endif
+
+
+ switch(r&0xf0)
+ {
+ case 0x00: /* 00-0f:control */
+ {
+ switch(r&0x0f)
+ {
+ case 0x00: /* AM/VIB/EGTYP/KSR/MULTI (modulator) */
+ case 0x01: /* AM/VIB/EGTYP/KSR/MULTI (carrier) */
+ case 0x02: /* Key Scale Level, Total Level (modulator) */
+ case 0x03: /* Key Scale Level, carrier waveform, modulator waveform, Feedback */
+ case 0x04: /* Attack, Decay (modulator) */
+ case 0x05: /* Attack, Decay (carrier) */
+ case 0x06: /* Sustain, Release (modulator) */
+ case 0x07: /* Sustain, Release (carrier) */
+ chip->inst_tab[0][r & 0x07] = v;
+ update_instrument_zero(chip,r&7);
+ break;
+
+ case 0x0e: /* x, x, r,bd,sd,tom,tc,hh */
+ {
+ if(v&0x20)
+ {
+ if ((chip->rhythm&0x20)==0)
+ /*rhythm off to on*/
+ {
+ logerror("YM2413: Rhythm mode enable\n");
+
+ /* Load instrument settings for channel seven(chan=6 since we're zero based). (Bass drum) */
+ chan = 6;
+ inst = &chip->inst_tab[16][0];
+ slot = chan*2;
+
+ load_instrument(chip, chan, slot, inst);
+
+ /* Load instrument settings for channel eight. (High hat and snare drum) */
+ chan = 7;
+ inst = &chip->inst_tab[17][0];
+ slot = chan*2;
+
+ load_instrument(chip, chan, slot, inst);
+
+ CH = &chip->P_CH[chan];
+ SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is HH */
+ SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+
+ /* Load instrument settings for channel nine. (Tom-tom and top cymbal) */
+ chan = 8;
+ inst = &chip->inst_tab[18][0];
+ slot = chan*2;
+
+ load_instrument(chip, chan, slot, inst);
+
+ CH = &chip->P_CH[chan];
+ SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is TOM */
+ SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+ }
+ /* BD key on/off */
+ if(v&0x10)
+ {
+ KEY_ON (&chip->P_CH[6].SLOT[SLOT1], 2);
+ KEY_ON (&chip->P_CH[6].SLOT[SLOT2], 2);
+ }
+ else
+ {
+ KEY_OFF(&chip->P_CH[6].SLOT[SLOT1],~2);
+ KEY_OFF(&chip->P_CH[6].SLOT[SLOT2],~2);
+ }
+ /* HH key on/off */
+ if(v&0x01) KEY_ON (&chip->P_CH[7].SLOT[SLOT1], 2);
+ else KEY_OFF(&chip->P_CH[7].SLOT[SLOT1],~2);
+ /* SD key on/off */
+ if(v&0x08) KEY_ON (&chip->P_CH[7].SLOT[SLOT2], 2);
+ else KEY_OFF(&chip->P_CH[7].SLOT[SLOT2],~2);
+ /* TOM key on/off */
+ if(v&0x04) KEY_ON (&chip->P_CH[8].SLOT[SLOT1], 2);
+ else KEY_OFF(&chip->P_CH[8].SLOT[SLOT1],~2);
+ /* TOP-CY key on/off */
+ if(v&0x02) KEY_ON (&chip->P_CH[8].SLOT[SLOT2], 2);
+ else KEY_OFF(&chip->P_CH[8].SLOT[SLOT2],~2);
+ }
+ else
+ {
+ if ((chip->rhythm&0x20)==1)
+ /*rhythm on to off*/
+ {
+ logerror("YM2413: Rhythm mode disable\n");
+ /* Load instrument settings for channel seven(chan=6 since we're zero based).*/
+ chan = 6;
+ inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0];
+ slot = chan*2;
+
+ load_instrument(chip, chan, slot, inst);
+
+ /* Load instrument settings for channel eight.*/
+ chan = 7;
+ inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0];
+ slot = chan*2;
+
+ load_instrument(chip, chan, slot, inst);
+
+ /* Load instrument settings for channel nine.*/
+ chan = 8;
+ inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0];
+ slot = chan*2;
+
+ load_instrument(chip, chan, slot, inst);
+ }
+ /* BD key off */
+ KEY_OFF(&chip->P_CH[6].SLOT[SLOT1],~2);
+ KEY_OFF(&chip->P_CH[6].SLOT[SLOT2],~2);
+ /* HH key off */
+ KEY_OFF(&chip->P_CH[7].SLOT[SLOT1],~2);
+ /* SD key off */
+ KEY_OFF(&chip->P_CH[7].SLOT[SLOT2],~2);
+ /* TOM key off */
+ KEY_OFF(&chip->P_CH[8].SLOT[SLOT1],~2);
+ /* TOP-CY off */
+ KEY_OFF(&chip->P_CH[8].SLOT[SLOT2],~2);
+ }
+ chip->rhythm = v&0x3f;
+ }
+ break;
+ }
+ }
+ break;
+
+ case 0x10:
+ case 0x20:
+ {
+ int block_fnum;
+
+ chan = r&0x0f;
+
+ if (chan >= 9)
+ chan -= 9; /* verified on real YM2413 */
+
+ CH = &chip->P_CH[chan];
+
+ if(r&0x10)
+ { /* 10-18: FNUM 0-7 */
+ block_fnum = (CH->block_fnum&0x0f00) | v;
+ }
+ else
+ { /* 20-28: suson, keyon, block, FNUM 8 */
+ block_fnum = ((v&0x0f)<<8) | (CH->block_fnum&0xff);
+
+ if(v&0x10)
+ {
+ KEY_ON (&CH->SLOT[SLOT1], 1);
+ KEY_ON (&CH->SLOT[SLOT2], 1);
+ }
+ else
+ {
+ KEY_OFF(&CH->SLOT[SLOT1],~1);
+ KEY_OFF(&CH->SLOT[SLOT2],~1);
+ }
+
+
+ if (CH->sus!=(v&0x20))
+ logerror("chan=%i sus=%2x\n",chan,v&0x20);
+
+ CH->sus = v & 0x20;
+ }
+ /* update */
+ if(CH->block_fnum != block_fnum)
+ {
+ UINT8 block;
+
+ CH->block_fnum = block_fnum;
+
+ /* BLK 2,1,0 bits -> bits 3,2,1 of kcode, FNUM MSB -> kcode LSB */
+ CH->kcode = (block_fnum&0x0f00)>>8;
+
+ CH->ksl_base = ksl_tab[block_fnum>>5];
+
+ block_fnum = block_fnum * 2;
+ block = (block_fnum&0x1c00) >> 10;
+ CH->fc = chip->fn_tab[block_fnum&0x03ff] >> (7-block);
+
+ /* refresh Total Level in both SLOTs of this channel */
+ CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl);
+ CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl);
+
+ /* refresh frequency counter in both SLOTs of this channel */
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+ }
+ }
+ break;
+
+ case 0x30: /* inst 4 MSBs, VOL 4 LSBs */
+ {
+ UINT8 old_instvol;
+
+ chan = r&0x0f;
+
+ if (chan >= 9)
+ chan -= 9; /* verified on real YM2413 */
+
+ old_instvol = chip->instvol_r[chan];
+ chip->instvol_r[chan] = v; /* store for later use */
+
+ CH = &chip->P_CH[chan];
+ SLOT = &CH->SLOT[SLOT2]; /* carrier */
+ SLOT->TL = ((v&0x0f)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+
+
+ /*check wether we are in rhythm mode and handle instrument/volume register accordingly*/
+ if ((chan>=6) && (chip->rhythm&0x20))
+ {
+ /* we're in rhythm mode*/
+
+ if (chan>=7) /* only for channel 7 and 8 (channel 6 is handled in usual way)*/
+ {
+ SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is HH(chan=7) or TOM(chan=8) */
+ SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+ }
+ }
+ else
+ {
+ if ( (old_instvol&0xf0) == (v&0xf0) )
+ return;
+
+ inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0];
+ slot = chan*2;
+
+ load_instrument(chip, chan, slot, inst);
+
+ #if 0
+ logerror("YM2413: chan#%02i inst=%02i: (r=%2x, v=%2x)\n",chan,v>>4,r,v);
+ logerror(" 0:%2x 1:%2x\n",inst[0],inst[1]); logerror(" 2:%2x 3:%2x\n",inst[2],inst[3]);
+ logerror(" 4:%2x 5:%2x\n",inst[4],inst[5]); logerror(" 6:%2x 7:%2x\n",inst[6],inst[7]);
+ #endif
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+#ifdef LOG_CYM_FILE
+static TIMER_CALLBACK( cymfile_callback )
+{
+ if (cymfile)
+ {
+ fputc( (unsigned char)8, cymfile );
+ }
+}
+#endif
+
+/* lock/unlock for common table */
+static int OPLL_LockTable(void)
+{
+ num_lock++;
+ if(num_lock>1) return 0;
+
+ /* first time */
+
+ cur_chip = NULL;
+ /* allocate total level table (128kb space) */
+ if( !init_tables() )
+ {
+ num_lock--;
+ return -1;
+ }
+
+#ifdef LOG_CYM_FILE
+ cymfile = fopen("2413_.cym","wb");
+ if (cymfile)
+ timer_pulse ( ATTOTIME_IN_HZ(110), 0, cymfile_callback); /*110 Hz pulse timer*/
+ else
+ logerror("Could not create file 2413_.cym\n");
+#endif
+
+ return 0;
+}
+
+static void OPLL_UnLockTable(void)
+{
+ if(num_lock) num_lock--;
+ if(num_lock) return;
+
+ /* last time */
+
+ cur_chip = NULL;
+ OPLCloseTable();
+
+#ifdef LOG_CYM_FILE
+ fclose (cymfile);
+ cymfile = NULL;
+#endif
+
+}
+
+static void OPLLResetChip(YM2413 *chip)
+{
+ int c,s;
+ int i;
+
+ chip->eg_timer = 0;
+ chip->eg_cnt = 0;
+
+ chip->noise_rng = 1; /* noise shift register */
+
+
+ /* setup instruments table */
+ for (i=0; i<19; i++)
+ {
+ for (c=0; c<8; c++)
+ {
+ chip->inst_tab[i][c] = table[i][c];
+ }
+ }
+
+
+ /* reset with register write */
+ OPLLWriteReg(chip,0x0f,0); /*test reg*/
+ for(i = 0x3f ; i >= 0x10 ; i-- ) OPLLWriteReg(chip,i,0x00);
+
+ /* reset operator parameters */
+ for( c = 0 ; c < 9 ; c++ )
+ {
+ OPLL_CH *CH = &chip->P_CH[c];
+ for(s = 0 ; s < 2 ; s++ )
+ {
+ /* wave table */
+ CH->SLOT[s].wavetable = 0;
+ CH->SLOT[s].state = EG_OFF;
+ CH->SLOT[s].volume = MAX_ATT_INDEX;
+ }
+ }
+}
+
+/* Create one of virtual YM2413 */
+/* 'clock' is chip clock in Hz */
+/* 'rate' is sampling rate */
+static YM2413 *OPLLCreate(int clock, int rate)
+{
+ char *ptr;
+ YM2413 *chip;
+ int state_size;
+
+ if (OPLL_LockTable() ==-1) return NULL;
+
+ /* calculate chip state size */
+ state_size = sizeof(YM2413);
+
+ /* allocate memory block */
+ ptr = malloc(state_size);
+
+ if (ptr==NULL)
+ return NULL;
+
+ /* clear */
+ memset(ptr,0,state_size);
+
+ chip = (YM2413 *)ptr;
+
+ chip->clock = clock;
+ chip->rate = rate;
+
+ /* init global tables */
+ OPLL_initalize(chip);
+
+ /* reset chip */
+ OPLLResetChip(chip);
+ return chip;
+}
+
+/* Destroy one of virtual YM3812 */
+static void OPLLDestroy(YM2413 *chip)
+{
+ OPLL_UnLockTable();
+ free(chip);
+}
+
+/* Option handlers */
+
+static void OPLLSetUpdateHandler(YM2413 *chip,OPLL_UPDATEHANDLER UpdateHandler,void * param)
+{
+ chip->UpdateHandler = UpdateHandler;
+ chip->UpdateParam = param;
+}
+
+/* YM3812 I/O interface */
+static void OPLLWrite(YM2413 *chip,int a,int v)
+{
+ if( !(a&1) )
+ { /* address port */
+ chip->address = v & 0xff;
+ }
+ else
+ { /* data port */
+ if(chip->UpdateHandler) chip->UpdateHandler(chip->UpdateParam,0);
+ OPLLWriteReg(chip,chip->address,v);
+ }
+}
+
+static unsigned char OPLLRead(YM2413 *chip,int a)
+{
+ if( !(a&1) )
+ {
+ /* status port */
+ return chip->status;
+ }
+ return 0xff;
+}
+
+
+
+
+
+void * YM2413Init(int clock, int rate)
+{
+ /* emulator create */
+ return OPLLCreate(clock, rate);
+}
+
+void YM2413Shutdown(void *chip)
+{
+ YM2413 *OPLL = chip;
+
+ /* emulator shutdown */
+ OPLLDestroy(OPLL);
+}
+
+void YM2413ResetChip(void *chip)
+{
+ YM2413 *OPLL = chip;
+ OPLLResetChip(OPLL);
+}
+
+void YM2413Write(void *chip, int a, int v)
+{
+ YM2413 *OPLL = chip;
+ OPLLWrite(OPLL, a, v);
+}
+
+unsigned char YM2413Read(void *chip, int a)
+{
+ YM2413 *OPLL = chip;
+ return OPLLRead(OPLL, a) & 0x03 ;
+}
+
+void YM2413SetUpdateHandler(void *chip,OPLL_UPDATEHANDLER UpdateHandler,void *param)
+{
+ YM2413 *OPLL = chip;
+ OPLLSetUpdateHandler(OPLL, UpdateHandler, param);
+}
+
+
+/*
+** Generate samples for one of the YM2413's
+**
+** 'which' is the virtual YM2413 number
+** '*buffer' is the output buffer pointer
+** 'length' is the number of samples that should be generated
+*/
+void YM2413UpdateOne(void *_chip, SAMP **buffers, int length)
+{
+ YM2413 *chip = _chip;
+ UINT8 rhythm = chip->rhythm&0x20;
+ SAMP *bufMO = buffers[0];
+ SAMP *bufRO = buffers[1];
+
+ int i;
+
+ if( (void *)chip != cur_chip ){
+ cur_chip = (void *)chip;
+ /* rhythm slots */
+ SLOT7_1 = &chip->P_CH[7].SLOT[SLOT1];
+ SLOT7_2 = &chip->P_CH[7].SLOT[SLOT2];
+ SLOT8_1 = &chip->P_CH[8].SLOT[SLOT1];
+ SLOT8_2 = &chip->P_CH[8].SLOT[SLOT2];
+ }
+
+
+ for( i=0; i < length ; i++ )
+ {
+ int mo,ro;
+
+ output[0] = 0;
+ output[1] = 0;
+
+ advance_lfo(chip);
+
+ /* FM part */
+ chan_calc(&chip->P_CH[0]);
+//SAVE_SEPARATE_CHANNEL(0);
+ chan_calc(&chip->P_CH[1]);
+ chan_calc(&chip->P_CH[2]);
+ chan_calc(&chip->P_CH[3]);
+ chan_calc(&chip->P_CH[4]);
+ chan_calc(&chip->P_CH[5]);
+
+ if(!rhythm)
+ {
+ chan_calc(&chip->P_CH[6]);
+ chan_calc(&chip->P_CH[7]);
+ chan_calc(&chip->P_CH[8]);
+ }
+ else /* Rhythm part */
+ {
+ rhythm_calc(&chip->P_CH[0], (chip->noise_rng>>0)&1 );
+ }
+
+ mo = output[0];
+ ro = output[1];
+
+ mo >>= FINAL_SH;
+ ro >>= FINAL_SH;
+
+ /* limit check */
+ mo = limit( mo , MAXOUT, MINOUT );
+ ro = limit( ro , MAXOUT, MINOUT );
+
+ #ifdef SAVE_SAMPLE
+ if (which==0)
+ {
+ SAVE_ALL_CHANNELS
+ }
+ #endif
+
+ /* store to sound buffer */
+ bufMO[i] = mo;
+ bufRO[i] = ro;
+
+ advance(chip);
+ }
+
+}
diff --git a/src/emu/sound/ym2413.h b/src/emu/sound/ym2413.h
new file mode 100644
index 00000000000..faedce5451d
--- /dev/null
+++ b/src/emu/sound/ym2413.h
@@ -0,0 +1,42 @@
+#ifndef _H_YM2413_
+#define _H_YM2413_
+
+/* select output bits size of output : 8 or 16 */
+#define SAMPLE_BITS 16
+
+/* compiler dependence */
+#ifndef __OSDCOMM_H__
+#define __OSDCOMM_H__
+typedef unsigned char UINT8; /* unsigned 8bit */
+typedef unsigned short UINT16; /* unsigned 16bit */
+typedef unsigned int UINT32; /* unsigned 32bit */
+typedef signed char INT8; /* signed 8bit */
+typedef signed short INT16; /* signed 16bit */
+typedef signed int INT32; /* signed 32bit */
+#endif
+
+typedef stream_sample_t SAMP;
+/*
+#if (SAMPLE_BITS==16)
+typedef INT16 SAMP;
+#endif
+#if (SAMPLE_BITS==8)
+typedef INT8 SAMP;
+#endif
+*/
+
+
+
+void *YM2413Init(int clock, int rate);
+void YM2413Shutdown(void *chip);
+void YM2413ResetChip(void *chip);
+void YM2413Write(void *chip, int a, int v);
+unsigned char YM2413Read(void *chip, int a);
+void YM2413UpdateOne(void *chip, SAMP **buffers, int length);
+
+typedef void (*OPLL_UPDATEHANDLER)(void *param,int min_interval_us);
+
+void YM2413SetUpdateHandler(void *chip, OPLL_UPDATEHANDLER UpdateHandler, void *param);
+
+
+#endif /*_H_YM2413_*/
diff --git a/src/emu/sound/ymdeltat.c b/src/emu/sound/ymdeltat.c
new file mode 100644
index 00000000000..2c91a0ca066
--- /dev/null
+++ b/src/emu/sound/ymdeltat.c
@@ -0,0 +1,652 @@
+/*
+**
+** File: ymdeltat.c
+**
+** YAMAHA DELTA-T adpcm sound emulation subroutine
+** used by fmopl.c (Y8950) and fm.c (YM2608 and YM2610/B)
+**
+** Base program is YM2610 emulator by Hiromitsu Shioya.
+** Written by Tatsuyuki Satoh
+** Improvements by Jarek Burczynski (bujar at mame dot net)
+**
+**
+** History:
+**
+** 03-08-2003 Jarek Burczynski:
+** - fixed BRDY flag implementation.
+**
+** 24-07-2003 Jarek Burczynski, Frits Hilderink:
+** - fixed delault value for control2 in YM_DELTAT_ADPCM_Reset
+**
+** 22-07-2003 Jarek Burczynski, Frits Hilderink:
+** - fixed external memory support
+**
+** 15-06-2003 Jarek Burczynski:
+** - implemented CPU -> AUDIO ADPCM synthesis (via writes to the ADPCM data reg $08)
+** - implemented support for the Limit address register
+** - supported two bits from the control register 2 ($01): RAM TYPE (x1 bit/x8 bit), ROM/RAM
+** - implemented external memory access (read/write) via the ADPCM data reg reads/writes
+** Thanks go to Frits Hilderink for the example code.
+**
+** 14-06-2003 Jarek Burczynski:
+** - various fixes to enable proper support for status register flags: BSRDY, PCM BSY, ZERO
+** - modified EOS handling
+**
+** 05-04-2003 Jarek Burczynski:
+** - implemented partial support for external/processor memory on sample replay
+**
+** 01-12-2002 Jarek Burczynski:
+** - fixed first missing sound in gigandes thanks to previous fix (interpolator) by ElSemi
+** - renamed/removed some YM_DELTAT struct fields
+**
+** 28-12-2001 Acho A. Tang
+** - added EOS status report on ADPCM playback.
+**
+** 05-08-2001 Jarek Burczynski:
+** - now_step is initialized with 0 at the start of play.
+**
+** 12-06-2001 Jarek Burczynski:
+** - corrected end of sample bug in YM_DELTAT_ADPCM_CALC.
+** Checked on real YM2610 chip - address register is 24 bits wide.
+** Thanks go to Stefan Jokisch (stefan.jokisch@gmx.de) for tracking down the problem.
+**
+** TO DO:
+** Check size of the address register on the other chips....
+**
+** Version 0.72
+**
+** sound chips that have this unit:
+** YM2608 OPNA
+** YM2610/B OPNB
+** Y8950 MSX AUDIO
+**
+*/
+
+#include "sndintrf.h"
+#include "ymdeltat.h"
+
+#define YM_DELTAT_DELTA_MAX (24576)
+#define YM_DELTAT_DELTA_MIN (127)
+#define YM_DELTAT_DELTA_DEF (127)
+
+#define YM_DELTAT_DECODE_RANGE 32768
+#define YM_DELTAT_DECODE_MIN (-(YM_DELTAT_DECODE_RANGE))
+#define YM_DELTAT_DECODE_MAX ((YM_DELTAT_DECODE_RANGE)-1)
+
+
+/* Forecast to next Forecast (rate = *8) */
+/* 1/8 , 3/8 , 5/8 , 7/8 , 9/8 , 11/8 , 13/8 , 15/8 */
+static const INT32 ym_deltat_decode_tableB1[16] = {
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ -1, -3, -5, -7, -9, -11, -13, -15,
+};
+/* delta to next delta (rate= *64) */
+/* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */
+static const INT32 ym_deltat_decode_tableB2[16] = {
+ 57, 57, 57, 57, 77, 102, 128, 153,
+ 57, 57, 57, 57, 77, 102, 128, 153
+};
+
+#if 0
+void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT)
+{
+ logerror("BRDY_callback reached (flag set) !\n");
+
+ /* set BRDY bit in status register */
+ if(DELTAT->status_set_handler)
+ if(DELTAT->status_change_BRDY_bit)
+ (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
+}
+#endif
+
+UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT)
+{
+ UINT8 v = 0;
+
+ /* external memory read */
+ if ( (DELTAT->portstate & 0xe0)==0x20 )
+ {
+ /* two dummy reads */
+ if (DELTAT->memread)
+ {
+ DELTAT->now_addr = DELTAT->start << 1;
+ DELTAT->memread--;
+ return 0;
+ }
+
+
+ if ( DELTAT->now_addr != (DELTAT->end<<1) )
+ {
+ v = DELTAT->memory[DELTAT->now_addr>>1];
+
+ /*logerror("YM Delta-T memory read $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/
+
+ DELTAT->now_addr+=2; /* two nibbles at a time */
+
+ /* reset BRDY bit in status register, which means we are reading the memory now */
+ if(DELTAT->status_reset_handler)
+ if(DELTAT->status_change_BRDY_bit)
+ (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
+
+ /* setup a timer that will callback us in 10 master clock cycles for Y8950
+ * in the callback set the BRDY flag to 1 , which means we have another data ready.
+ * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work.
+ */
+ /* set BRDY bit in status register */
+ if(DELTAT->status_set_handler)
+ if(DELTAT->status_change_BRDY_bit)
+ (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
+ }
+ else
+ {
+ /* set EOS bit in status register */
+ if(DELTAT->status_set_handler)
+ if(DELTAT->status_change_EOS_bit)
+ (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit);
+ }
+ }
+
+ return v;
+}
+
+
+/* 0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */
+static UINT8 dram_rightshift[4]={3,0,0,0};
+
+/* DELTA-T ADPCM write register */
+void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v)
+{
+ if(r>=0x10) return;
+ DELTAT->reg[r] = v; /* stock data */
+
+ switch( r )
+ {
+ case 0x00:
+/*
+START:
+ Accessing *external* memory is started when START bit (D7) is set to "1", so
+ you must set all conditions needed for recording/playback before starting.
+ If you access *CPU-managed* memory, recording/playback starts after
+ read/write of ADPCM data register $08.
+
+REC:
+ 0 = ADPCM synthesis (playback)
+ 1 = ADPCM analysis (record)
+
+MEMDATA:
+ 0 = processor (*CPU-managed*) memory (means: using register $08)
+ 1 = external memory (using start/end/limit registers to access memory: RAM or ROM)
+
+
+SPOFF:
+ controls output pin that should disable the speaker while ADPCM analysis
+
+RESET and REPEAT only work with external memory.
+
+
+some examples:
+value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning:
+ C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register
+ E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register
+ 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register
+ a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register
+
+ 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08
+ 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08
+
+*/
+ /* handle emulation mode */
+ if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610)
+ {
+ v |= 0x20; /* YM2610 always uses external memory and doesn't even have memory flag bit. */
+ }
+
+ DELTAT->portstate = v & (0x80|0x40|0x20|0x10|0x01); /* start, rec, memory mode, repeat flag copy, reset(bit0) */
+
+ if( DELTAT->portstate&0x80 )/* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */
+ {
+ /* set PCM BUSY bit */
+ DELTAT->PCM_BSY = 1;
+
+ /* start ADPCM */
+ DELTAT->now_step = 0;
+ DELTAT->acc = 0;
+ DELTAT->prev_acc = 0;
+ DELTAT->adpcml = 0;
+ DELTAT->adpcmd = YM_DELTAT_DELTA_DEF;
+ DELTAT->now_data = 0;
+
+ }
+
+ if( DELTAT->portstate&0x20 ) /* do we access external memory? */
+ {
+ DELTAT->now_addr = DELTAT->start << 1;
+ DELTAT->memread = 2; /* two dummy reads needed before accesing external memory via register $08*/
+
+ /* if yes, then let's check if ADPCM memory is mapped and big enough */
+ if(DELTAT->memory == 0)
+ {
+ logerror("YM Delta-T ADPCM rom not mapped\n");
+ DELTAT->portstate = 0x00;
+ DELTAT->PCM_BSY = 0;
+ }
+ else
+ {
+ if( DELTAT->end >= DELTAT->memory_size ) /* Check End in Range */
+ {
+ logerror("YM Delta-T ADPCM end out of range: $%08x\n", DELTAT->end);
+ DELTAT->end = DELTAT->memory_size - 1;
+ }
+ if( DELTAT->start >= DELTAT->memory_size ) /* Check Start in Range */
+ {
+ logerror("YM Delta-T ADPCM start out of range: $%08x\n", DELTAT->start);
+ DELTAT->portstate = 0x00;
+ DELTAT->PCM_BSY = 0;
+ }
+ }
+ }
+ else /* we access CPU memory (ADPCM data register $08) so we only reset now_addr here */
+ {
+ DELTAT->now_addr = 0;
+ }
+
+ if( DELTAT->portstate&0x01 )
+ {
+ DELTAT->portstate = 0x00;
+
+ /* clear PCM BUSY bit (in status register) */
+ DELTAT->PCM_BSY = 0;
+
+ /* set BRDY flag */
+ if(DELTAT->status_set_handler)
+ if(DELTAT->status_change_BRDY_bit)
+ (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
+ }
+ break;
+ case 0x01: /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */
+ /* handle emulation mode */
+ if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610)
+ {
+ v |= 0x01; /* YM2610 always uses ROM as an external memory and doesn't tave ROM/RAM memory flag bit. */
+ }
+
+ DELTAT->pan = &DELTAT->output_pointer[(v>>6)&0x03];
+ if ((DELTAT->control2 & 3) != (v & 3))
+ {
+ /*0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */
+ if (DELTAT->DRAMportshift != dram_rightshift[v&3])
+ {
+ DELTAT->DRAMportshift = dram_rightshift[v&3];
+
+ /* final shift value depends on chip type and memory type selected:
+ 8 for YM2610 (ROM only),
+ 5 for ROM for Y8950 and YM2608,
+ 5 for x8bit DRAMs for Y8950 and YM2608,
+ 2 for x1bit DRAMs for Y8950 and YM2608.
+ */
+
+ /* refresh addresses */
+ DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift);
+ DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift);
+ DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1;
+ DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift);
+ }
+ }
+ DELTAT->control2 = v;
+ break;
+ case 0x02: /* Start Address L */
+ case 0x03: /* Start Address H */
+ DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift);
+ /*logerror("DELTAT start: 02=%2x 03=%2x addr=%8x\n",DELTAT->reg[0x2], DELTAT->reg[0x3],DELTAT->start );*/
+ break;
+ case 0x04: /* Stop Address L */
+ case 0x05: /* Stop Address H */
+ DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift);
+ DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1;
+ /*logerror("DELTAT end : 04=%2x 05=%2x addr=%8x\n",DELTAT->reg[0x4], DELTAT->reg[0x5],DELTAT->end );*/
+ break;
+ case 0x06: /* Prescale L (ADPCM and Record frq) */
+ case 0x07: /* Prescale H */
+ break;
+ case 0x08: /* ADPCM data */
+
+/*
+some examples:
+value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning:
+ C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register
+ E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register
+ 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register
+ a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register
+
+ 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08
+ 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08
+
+*/
+
+ /* external memory write */
+ if ( (DELTAT->portstate & 0xe0)==0x60 )
+ {
+ if (DELTAT->memread)
+ {
+ DELTAT->now_addr = DELTAT->start << 1;
+ DELTAT->memread = 0;
+ }
+
+ /*logerror("YM Delta-T memory write $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/
+
+ if ( DELTAT->now_addr != (DELTAT->end<<1) )
+ {
+ DELTAT->memory[DELTAT->now_addr>>1] = v;
+ DELTAT->now_addr+=2; /* two nibbles at a time */
+
+ /* reset BRDY bit in status register, which means we are processing the write */
+ if(DELTAT->status_reset_handler)
+ if(DELTAT->status_change_BRDY_bit)
+ (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
+
+ /* setup a timer that will callback us in 10 master clock cycles for Y8950
+ * in the callback set the BRDY flag to 1 , which means we have written the data.
+ * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work.
+ */
+ /* set BRDY bit in status register */
+ if(DELTAT->status_set_handler)
+ if(DELTAT->status_change_BRDY_bit)
+ (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
+
+ }
+ else
+ {
+ /* set EOS bit in status register */
+ if(DELTAT->status_set_handler)
+ if(DELTAT->status_change_EOS_bit)
+ (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit);
+ }
+
+ return;
+ }
+
+ /* ADPCM synthesis from CPU */
+ if ( (DELTAT->portstate & 0xe0)==0x80 )
+ {
+ DELTAT->CPU_data = v;
+
+ /* Reset BRDY bit in status register, which means we are full of data */
+ if(DELTAT->status_reset_handler)
+ if(DELTAT->status_change_BRDY_bit)
+ (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
+ return;
+ }
+
+ break;
+ case 0x09: /* DELTA-N L (ADPCM Playback Prescaler) */
+ case 0x0a: /* DELTA-N H */
+ DELTAT->delta = (DELTAT->reg[0xa]*0x0100 | DELTAT->reg[0x9]);
+ DELTAT->step = (UINT32)( (double)(DELTAT->delta /* *(1<<(YM_DELTAT_SHIFT-16)) */ ) * (DELTAT->freqbase) );
+ /*logerror("DELTAT deltan:09=%2x 0a=%2x\n",DELTAT->reg[0x9], DELTAT->reg[0xa]);*/
+ break;
+ case 0x0b: /* Output level control (volume, linear) */
+ {
+ INT32 oldvol = DELTAT->volume;
+ DELTAT->volume = (v&0xff) * (DELTAT->output_range/256) / YM_DELTAT_DECODE_RANGE;
+/* v * ((1<<16)>>8) >> 15;
+* thus: v * (1<<8) >> 15;
+* thus: output_range must be (1 << (15+8)) at least
+* v * ((1<<23)>>8) >> 15;
+* v * (1<<15) >> 15;
+*/
+ /*logerror("DELTAT vol = %2x\n",v&0xff);*/
+ if( oldvol != 0 )
+ {
+ DELTAT->adpcml = (int)((double)DELTAT->adpcml / (double)oldvol * (double)DELTAT->volume);
+ }
+ }
+ break;
+ case 0x0c: /* Limit Address L */
+ case 0x0d: /* Limit Address H */
+ DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift);
+ /*logerror("DELTAT limit: 0c=%2x 0d=%2x addr=%8x\n",DELTAT->reg[0xc], DELTAT->reg[0xd],DELTAT->limit );*/
+ break;
+ }
+}
+
+void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode)
+{
+ DELTAT->now_addr = 0;
+ DELTAT->now_step = 0;
+ DELTAT->step = 0;
+ DELTAT->start = 0;
+ DELTAT->end = 0;
+ DELTAT->limit = ~0; /* this way YM2610 and Y8950 (both of which don't have limit address reg) will still work */
+ DELTAT->volume = 0;
+ DELTAT->pan = &DELTAT->output_pointer[pan];
+ DELTAT->acc = 0;
+ DELTAT->prev_acc = 0;
+ DELTAT->adpcmd = 127;
+ DELTAT->adpcml = 0;
+ DELTAT->emulation_mode = (UINT8)emulation_mode;
+ DELTAT->portstate = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x20 : 0;
+ DELTAT->control2 = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x01 : 0; /* default setting depends on the emulation mode. MSX demo called "facdemo_4" doesn't setup control2 register at all and still works */
+ DELTAT->DRAMportshift = dram_rightshift[DELTAT->control2 & 3];
+
+ /* The flag mask register disables the BRDY after the reset, however
+ ** as soon as the mask is enabled the flag needs to be set. */
+
+ /* set BRDY bit in status register */
+ if(DELTAT->status_set_handler)
+ if(DELTAT->status_change_BRDY_bit)
+ (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
+}
+
+void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs)
+{
+ int r;
+
+ /* to keep adpcml */
+ DELTAT->volume = 0;
+ /* update */
+ for(r=1;r<16;r++)
+ YM_DELTAT_ADPCM_Write(DELTAT,r,regs[r]);
+ DELTAT->reg[0] = regs[0];
+
+ /* current rom data */
+ if (DELTAT->memory)
+ DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1) );
+
+}
+void YM_DELTAT_savestate(const char *statename,int num,YM_DELTAT *DELTAT)
+{
+#ifdef __STATE_H__
+ state_save_register_item(statename, num, DELTAT->portstate);
+ state_save_register_item(statename, num, DELTAT->now_addr);
+ state_save_register_item(statename, num, DELTAT->now_step);
+ state_save_register_item(statename, num, DELTAT->acc);
+ state_save_register_item(statename, num, DELTAT->prev_acc);
+ state_save_register_item(statename, num, DELTAT->adpcmd);
+ state_save_register_item(statename, num, DELTAT->adpcml);
+#endif
+}
+
+
+#define YM_DELTAT_Limit(val,max,min) \
+{ \
+ if ( val > max ) val = max; \
+ else if ( val < min ) val = min; \
+}
+
+INLINE void YM_DELTAT_synthesis_from_external_memory(YM_DELTAT *DELTAT)
+{
+ UINT32 step;
+ int data;
+
+ DELTAT->now_step += DELTAT->step;
+ if ( DELTAT->now_step >= (1<<YM_DELTAT_SHIFT) )
+ {
+ step = DELTAT->now_step >> YM_DELTAT_SHIFT;
+ DELTAT->now_step &= (1<<YM_DELTAT_SHIFT)-1;
+ do{
+
+ if ( DELTAT->now_addr == (DELTAT->limit<<1) )
+ DELTAT->now_addr = 0;
+
+ if ( DELTAT->now_addr == (DELTAT->end<<1) ) { /* 12-06-2001 JB: corrected comparison. Was > instead of == */
+ if( DELTAT->portstate&0x10 ){
+ /* repeat start */
+ DELTAT->now_addr = DELTAT->start<<1;
+ DELTAT->acc = 0;
+ DELTAT->adpcmd = YM_DELTAT_DELTA_DEF;
+ DELTAT->prev_acc = 0;
+ }else{
+ /* set EOS bit in status register */
+ if(DELTAT->status_set_handler)
+ if(DELTAT->status_change_EOS_bit)
+ (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit);
+
+ /* clear PCM BUSY bit (reflected in status register) */
+ DELTAT->PCM_BSY = 0;
+
+ DELTAT->portstate = 0;
+ DELTAT->adpcml = 0;
+ DELTAT->prev_acc = 0;
+ return;
+ }
+ }
+
+ if( DELTAT->now_addr&1 ) data = DELTAT->now_data & 0x0f;
+ else
+ {
+ DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1));
+ data = DELTAT->now_data >> 4;
+ }
+
+ DELTAT->now_addr++;
+ /* 12-06-2001 JB: */
+ /* YM2610 address register is 24 bits wide.*/
+ /* The "+1" is there because we use 1 bit more for nibble calculations.*/
+ /* WARNING: */
+ /* Side effect: we should take the size of the mapped ROM into account */
+ DELTAT->now_addr &= ( (1<<(24+1))-1);
+
+ /* store accumulator value */
+ DELTAT->prev_acc = DELTAT->acc;
+
+ /* Forecast to next Forecast */
+ DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8);
+ YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN);
+
+ /* delta to next delta */
+ DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64;
+ YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN );
+
+ /* ElSemi: Fix interpolator. */
+ /*DELTAT->prev_acc = prev_acc + ((DELTAT->acc - prev_acc) / 2 );*/
+
+ }while(--step);
+
+ }
+
+ /* ElSemi: Fix interpolator. */
+ DELTAT->adpcml = DELTAT->prev_acc * (int)((1<<YM_DELTAT_SHIFT)-DELTAT->now_step);
+ DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step);
+ DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume;
+
+ /* output for work of output channels (outd[OPNxxxx])*/
+ *(DELTAT->pan) += DELTAT->adpcml;
+}
+
+
+
+INLINE void YM_DELTAT_synthesis_from_CPU_memory(YM_DELTAT *DELTAT)
+{
+ UINT32 step;
+ int data;
+
+ DELTAT->now_step += DELTAT->step;
+ if ( DELTAT->now_step >= (1<<YM_DELTAT_SHIFT) )
+ {
+ step = DELTAT->now_step >> YM_DELTAT_SHIFT;
+ DELTAT->now_step &= (1<<YM_DELTAT_SHIFT)-1;
+ do{
+
+ if( DELTAT->now_addr&1 )
+ {
+ data = DELTAT->now_data & 0x0f;
+
+ DELTAT->now_data = DELTAT->CPU_data;
+
+ /* after we used CPU_data, we set BRDY bit in status register,
+ * which means we are ready to accept another byte of data */
+ if(DELTAT->status_set_handler)
+ if(DELTAT->status_change_BRDY_bit)
+ (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit);
+ }
+ else
+ {
+ data = DELTAT->now_data >> 4;
+ }
+
+ DELTAT->now_addr++;
+
+ /* store accumulator value */
+ DELTAT->prev_acc = DELTAT->acc;
+
+ /* Forecast to next Forecast */
+ DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8);
+ YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN);
+
+ /* delta to next delta */
+ DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64;
+ YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN );
+
+
+ }while(--step);
+
+ }
+
+ /* ElSemi: Fix interpolator. */
+ DELTAT->adpcml = DELTAT->prev_acc * (int)((1<<YM_DELTAT_SHIFT)-DELTAT->now_step);
+ DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step);
+ DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume;
+
+ /* output for work of output channels (outd[OPNxxxx])*/
+ *(DELTAT->pan) += DELTAT->adpcml;
+}
+
+
+
+/* ADPCM B (Delta-T control type) */
+void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT)
+{
+
+/*
+some examples:
+value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning:
+ 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register
+ a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register
+ C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register
+ E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register
+
+ 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08
+ 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08
+
+*/
+
+ if ( (DELTAT->portstate & 0xe0)==0xa0 )
+ {
+ YM_DELTAT_synthesis_from_external_memory(DELTAT);
+ return;
+ }
+
+ if ( (DELTAT->portstate & 0xe0)==0x80 )
+ {
+ /* ADPCM synthesis from CPU-managed memory (from reg $08) */
+ YM_DELTAT_synthesis_from_CPU_memory(DELTAT); /* change output based on data in ADPCM data reg ($08) */
+ return;
+ }
+
+//todo: ADPCM analysis
+// if ( (DELTAT->portstate & 0xe0)==0xc0 )
+// if ( (DELTAT->portstate & 0xe0)==0xe0 )
+
+ return;
+}
+
diff --git a/src/emu/sound/ymdeltat.h b/src/emu/sound/ymdeltat.h
new file mode 100644
index 00000000000..15c626e3e13
--- /dev/null
+++ b/src/emu/sound/ymdeltat.h
@@ -0,0 +1,82 @@
+#ifndef __YMDELTAT_H_
+#define __YMDELTAT_H_
+
+#define YM_DELTAT_SHIFT (16)
+
+#define YM_DELTAT_EMULATION_MODE_NORMAL 0
+#define YM_DELTAT_EMULATION_MODE_YM2610 1
+
+
+typedef void (*STATUS_CHANGE_HANDLER)(void *chip, UINT8 status_bits);
+
+
+/* DELTA-T (adpcm type B) struct */
+typedef struct deltat_adpcm_state { /* AT: rearranged and tigntened structure */
+ UINT8 *memory;
+ INT32 *output_pointer;/* pointer of output pointers */
+ INT32 *pan; /* pan : &output_pointer[pan] */
+ double freqbase;
+#if 0
+ double write_time; /* Y8950: 10 cycles of main clock; YM2608: 20 cycles of main clock */
+ double read_time; /* Y8950: 8 cycles of main clock; YM2608: 18 cycles of main clock */
+#endif
+ UINT32 memory_size;
+ int output_range;
+ UINT32 now_addr; /* current address */
+ UINT32 now_step; /* currect step */
+ UINT32 step; /* step */
+ UINT32 start; /* start address */
+ UINT32 limit; /* limit address */
+ UINT32 end; /* end address */
+ UINT32 delta; /* delta scale */
+ INT32 volume; /* current volume */
+ INT32 acc; /* shift Measurement value*/
+ INT32 adpcmd; /* next Forecast */
+ INT32 adpcml; /* current value */
+ INT32 prev_acc; /* leveling value */
+ UINT8 now_data; /* current rom data */
+ UINT8 CPU_data; /* current data from reg 08 */
+ UINT8 portstate; /* port status */
+ UINT8 control2; /* control reg: SAMPLE, DA/AD, RAM TYPE (x8bit / x1bit), ROM/RAM */
+ UINT8 portshift; /* address bits shift-left:
+ ** 8 for YM2610,
+ ** 5 for Y8950 and YM2608 */
+
+ UINT8 DRAMportshift; /* address bits shift-right:
+ ** 0 for ROM and x8bit DRAMs,
+ ** 3 for x1 DRAMs */
+
+ UINT8 memread; /* needed for reading/writing external memory */
+
+ /* handlers and parameters for the status flags support */
+ STATUS_CHANGE_HANDLER status_set_handler;
+ STATUS_CHANGE_HANDLER status_reset_handler;
+
+ /* note that different chips have these flags on different
+ ** bits of the status register
+ */
+ void * status_change_which_chip; /* this chip id */
+ UINT8 status_change_EOS_bit; /* 1 on End Of Sample (record/playback/cycle time of AD/DA converting has passed)*/
+ UINT8 status_change_BRDY_bit; /* 1 after recording 2 datas (2x4bits) or after reading/writing 1 data */
+ UINT8 status_change_ZERO_bit; /* 1 if silence lasts for more than 290 miliseconds on ADPCM recording */
+
+ /* neither Y8950 nor YM2608 can generate IRQ when PCMBSY bit changes, so instead of above,
+ ** the statusflag gets ORed with PCM_BSY (below) (on each read of statusflag of Y8950 and YM2608)
+ */
+ UINT8 PCM_BSY; /* 1 when ADPCM is playing; Y8950/YM2608 only */
+
+ UINT8 reg[16]; /* adpcm registers */
+ UINT8 emulation_mode; /* which chip we're emulating */
+}YM_DELTAT;
+
+/*void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT);*/
+
+UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT);
+void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v);
+void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode);
+void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT);
+
+void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs);
+void YM_DELTAT_savestate(const char *statename,int num,YM_DELTAT *DELTAT);
+
+#endif
diff --git a/src/emu/sound/ymf262.c b/src/emu/sound/ymf262.c
new file mode 100644
index 00000000000..0c201e5a0bc
--- /dev/null
+++ b/src/emu/sound/ymf262.c
@@ -0,0 +1,2719 @@
+/*
+**
+** File: ymf262.c - software implementation of YMF262
+** FM sound generator type OPL3
+**
+** Copyright (C) 2003 Jarek Burczynski
+**
+** Version 0.2
+**
+
+Revision History:
+
+03-03-2003: initial release
+ - thanks to Olivier Galibert and Chris Hardy for YMF262 and YAC512 chips
+ - thanks to Stiletto for the datasheets
+
+
+
+differences between OPL2 and OPL3 not documented in Yamaha datahasheets:
+- sinus table is a little different: the negative part is off by one...
+
+- in order to enable selection of four different waveforms on OPL2
+ one must set bit 5 in register 0x01(test).
+ on OPL3 this bit is ignored and 4-waveform select works *always*.
+ (Don't confuse this with OPL3's 8-waveform select.)
+
+- Envelope Generator: all 15 x rates take zero time on OPL3
+ (on OPL2 15 0 and 15 1 rates take some time while 15 2 and 15 3 rates
+ take zero time)
+
+- channel calculations: output of operator 1 is in perfect sync with
+ output of operator 2 on OPL3; on OPL and OPL2 output of operator 1
+ is always delayed by one sample compared to output of operator 2
+
+
+differences between OPL2 and OPL3 shown in datasheets:
+- YMF262 does not support CSM mode
+
+
+*/
+
+#include <math.h>
+
+#include "sndintrf.h" /* use M.A.M.E. */
+#include "ymf262.h"
+
+
+
+/* output final shift */
+#if (OPL3_SAMPLE_BITS==16)
+ #define FINAL_SH (0)
+ #define MAXOUT (+32767)
+ #define MINOUT (-32768)
+#else
+ #define FINAL_SH (8)
+ #define MAXOUT (+127)
+ #define MINOUT (-128)
+#endif
+
+
+#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
+#define EG_SH 16 /* 16.16 fixed point (EG timing) */
+#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
+#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */
+
+#define FREQ_MASK ((1<<FREQ_SH)-1)
+
+/* envelope output entries */
+#define ENV_BITS 10
+#define ENV_LEN (1<<ENV_BITS)
+#define ENV_STEP (128.0/ENV_LEN)
+
+#define MAX_ATT_INDEX ((1<<(ENV_BITS-1))-1) /*511*/
+#define MIN_ATT_INDEX (0)
+
+/* sinwave entries */
+#define SIN_BITS 10
+#define SIN_LEN (1<<SIN_BITS)
+#define SIN_MASK (SIN_LEN-1)
+
+#define TL_RES_LEN (256) /* 8 bits addressing (real chip) */
+
+
+
+/* register number to channel number , slot offset */
+#define SLOT1 0
+#define SLOT2 1
+
+/* Envelope Generator phases */
+
+#define EG_ATT 4
+#define EG_DEC 3
+#define EG_SUS 2
+#define EG_REL 1
+#define EG_OFF 0
+
+
+/* save output as raw 16-bit sample */
+
+/*#define SAVE_SAMPLE*/
+
+#ifdef SAVE_SAMPLE
+static FILE *sample[1];
+ #if 1 /*save to MONO file */
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = a; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ }
+ #else /*save to STEREO file */
+ #define SAVE_ALL_CHANNELS \
+ { signed int pom = a; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ pom = b; \
+ fputc((unsigned short)pom&0xff,sample[0]); \
+ fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+ }
+ #endif
+#endif
+
+/*#define LOG_CYM_FILE*/
+#ifdef LOG_CYM_FILE
+ FILE * cymfile = NULL;
+#endif
+
+
+
+
+
+#define OPL3_TYPE_YMF262 (0) /* 36 operators, 8 waveforms */
+
+
+typedef struct{
+ UINT32 ar; /* attack rate: AR<<2 */
+ UINT32 dr; /* decay rate: DR<<2 */
+ UINT32 rr; /* release rate:RR<<2 */
+ UINT8 KSR; /* key scale rate */
+ UINT8 ksl; /* keyscale level */
+ UINT8 ksr; /* key scale rate: kcode>>KSR */
+ UINT8 mul; /* multiple: mul_tab[ML] */
+
+ /* Phase Generator */
+ UINT32 Cnt; /* frequency counter */
+ UINT32 Incr; /* frequency counter step */
+ UINT8 FB; /* feedback shift value */
+ INT32 *connect; /* slot output pointer */
+ INT32 op1_out[2]; /* slot1 output for feedback */
+ UINT8 CON; /* connection (algorithm) type */
+
+ /* Envelope Generator */
+ UINT8 eg_type; /* percussive/non-percussive mode */
+ UINT8 state; /* phase type */
+ UINT32 TL; /* total level: TL << 2 */
+ INT32 TLL; /* adjusted now TL */
+ INT32 volume; /* envelope counter */
+ UINT32 sl; /* sustain level: sl_tab[SL] */
+
+ UINT32 eg_m_ar; /* (attack state) */
+ UINT8 eg_sh_ar; /* (attack state) */
+ UINT8 eg_sel_ar; /* (attack state) */
+ UINT32 eg_m_dr; /* (decay state) */
+ UINT8 eg_sh_dr; /* (decay state) */
+ UINT8 eg_sel_dr; /* (decay state) */
+ UINT32 eg_m_rr; /* (release state) */
+ UINT8 eg_sh_rr; /* (release state) */
+ UINT8 eg_sel_rr; /* (release state) */
+
+ UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
+
+ /* LFO */
+ UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
+ UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/
+
+ /* waveform select */
+ UINT8 waveform_number;
+ unsigned int wavetable;
+
+//unsigned char reserved[128-84];//speedup: pump up the struct size to power of 2
+unsigned char reserved[128-100];//speedup: pump up the struct size to power of 2
+
+} OPL3_SLOT;
+
+typedef struct{
+ OPL3_SLOT SLOT[2];
+
+ UINT32 block_fnum; /* block+fnum */
+ UINT32 fc; /* Freq. Increment base */
+ UINT32 ksl_base; /* KeyScaleLevel Base step */
+ UINT8 kcode; /* key code (for key scaling) */
+
+ /*
+ there are 12 2-operator channels which can be combined in pairs
+ to form six 4-operator channel, they are:
+ 0 and 3,
+ 1 and 4,
+ 2 and 5,
+ 9 and 12,
+ 10 and 13,
+ 11 and 14
+ */
+ UINT8 extended; /* set to 1 if this channel forms up a 4op channel with another channel(only used by first of pair of channels, ie 0,1,2 and 9,10,11) */
+
+unsigned char reserved[512-272];//speedup:pump up the struct size to power of 2
+
+} OPL3_CH;
+
+/* OPL3 state */
+typedef struct {
+ OPL3_CH P_CH[18]; /* OPL3 chips have 18 channels */
+
+ UINT32 pan[18*4]; /* channels output masks (0xffffffff = enable); 4 masks per one channel */
+ UINT32 pan_ctrl_value[18]; /* output control values 1 per one channel (1 value contains 4 masks) */
+
+ UINT32 eg_cnt; /* global envelope generator counter */
+ UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/288 (288=8*36) */
+ UINT32 eg_timer_add; /* step of eg_timer */
+ UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */
+
+ UINT32 fn_tab[1024]; /* fnumber->increment counter */
+
+ /* LFO */
+ UINT8 lfo_am_depth;
+ UINT8 lfo_pm_depth_range;
+ UINT32 lfo_am_cnt;
+ UINT32 lfo_am_inc;
+ UINT32 lfo_pm_cnt;
+ UINT32 lfo_pm_inc;
+
+ UINT32 noise_rng; /* 23 bit noise shift register */
+ UINT32 noise_p; /* current noise 'phase' */
+ UINT32 noise_f; /* current noise period */
+
+ UINT8 OPL3_mode; /* OPL3 extension enable flag */
+
+ UINT8 rhythm; /* Rhythm mode */
+
+ int T[2]; /* timer counters */
+ UINT8 st[2]; /* timer enable */
+
+ UINT32 address; /* address register */
+ UINT8 status; /* status flag */
+ UINT8 statusmask; /* status mask */
+
+ UINT8 nts; /* NTS (note select) */
+
+ /* external event callback handlers */
+ OPL3_TIMERHANDLER timer_handler;/* TIMER handler */
+ void *TimerParam; /* TIMER parameter */
+ OPL3_IRQHANDLER IRQHandler; /* IRQ handler */
+ void *IRQParam; /* IRQ parameter */
+ OPL3_UPDATEHANDLER UpdateHandler;/* stream update handler */
+ void *UpdateParam; /* stream update parameter */
+
+ UINT8 type; /* chip type */
+ int clock; /* master clock (Hz) */
+ int rate; /* sampling rate (Hz) */
+ double freqbase; /* frequency base */
+ attotime TimerBase; /* Timer base time (==sampling time)*/
+} OPL3;
+
+
+
+/* mapping of register number (offset) to slot number used by the emulator */
+static const int slot_array[32]=
+{
+ 0, 2, 4, 1, 3, 5,-1,-1,
+ 6, 8,10, 7, 9,11,-1,-1,
+ 12,14,16,13,15,17,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1
+};
+
+/* key scale level */
+/* table is 3dB/octave , DV converts this into 6dB/octave */
+/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */
+#define DV (0.1875/2.0)
+static const UINT32 ksl_tab[8*16]=
+{
+ /* OCT 0 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ /* OCT 1 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV,
+ 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV,
+ /* OCT 2 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+ 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV,
+ 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV,
+ 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV,
+ /* OCT 3 */
+ 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV,
+ 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV,
+ 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV,
+ 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV,
+ /* OCT 4 */
+ 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV,
+ 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV,
+ 9.000/DV, 9.750/DV,10.125/DV,10.500/DV,
+ 10.875/DV,11.250/DV,11.625/DV,12.000/DV,
+ /* OCT 5 */
+ 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV,
+ 9.000/DV,10.125/DV,10.875/DV,11.625/DV,
+ 12.000/DV,12.750/DV,13.125/DV,13.500/DV,
+ 13.875/DV,14.250/DV,14.625/DV,15.000/DV,
+ /* OCT 6 */
+ 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV,
+ 12.000/DV,13.125/DV,13.875/DV,14.625/DV,
+ 15.000/DV,15.750/DV,16.125/DV,16.500/DV,
+ 16.875/DV,17.250/DV,17.625/DV,18.000/DV,
+ /* OCT 7 */
+ 0.000/DV, 9.000/DV,12.000/DV,13.875/DV,
+ 15.000/DV,16.125/DV,16.875/DV,17.625/DV,
+ 18.000/DV,18.750/DV,19.125/DV,19.500/DV,
+ 19.875/DV,20.250/DV,20.625/DV,21.000/DV
+};
+#undef DV
+
+/* sustain level table (3dB per step) */
+/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
+#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) )
+static const UINT32 sl_tab[16]={
+ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
+ SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
+};
+#undef SC
+
+
+#define RATE_STEPS (8)
+static const unsigned char eg_inc[15*RATE_STEPS]={
+
+/*cycle:0 1 2 3 4 5 6 7*/
+
+/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */
+/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */
+/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */
+/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */
+
+/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */
+/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */
+/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */
+/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */
+
+/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */
+/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */
+/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */
+/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */
+
+/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 for decay */
+/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 for attack (zero time) */
+/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */
+};
+
+
+#define O(a) (a*RATE_STEPS)
+
+/* note that there is no O(13) in this table - it's directly in the code */
+static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */
+/* 16 infinite time rates */
+O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
+O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
+
+/* rates 00-12 */
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+O( 0),O( 1),O( 2),O( 3),
+
+/* rate 13 */
+O( 4),O( 5),O( 6),O( 7),
+
+/* rate 14 */
+O( 8),O( 9),O(10),O(11),
+
+/* rate 15 */
+O(12),O(12),O(12),O(12),
+
+/* 16 dummy rates (same as 15 3) */
+O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
+O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
+
+};
+#undef O
+
+/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */
+/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */
+/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */
+
+#define O(a) (a*1)
+static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */
+/* 16 infinite time rates */
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
+
+/* rates 00-12 */
+O(12),O(12),O(12),O(12),
+O(11),O(11),O(11),O(11),
+O(10),O(10),O(10),O(10),
+O( 9),O( 9),O( 9),O( 9),
+O( 8),O( 8),O( 8),O( 8),
+O( 7),O( 7),O( 7),O( 7),
+O( 6),O( 6),O( 6),O( 6),
+O( 5),O( 5),O( 5),O( 5),
+O( 4),O( 4),O( 4),O( 4),
+O( 3),O( 3),O( 3),O( 3),
+O( 2),O( 2),O( 2),O( 2),
+O( 1),O( 1),O( 1),O( 1),
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 13 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 14 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* rate 15 */
+O( 0),O( 0),O( 0),O( 0),
+
+/* 16 dummy rates (same as 15 3) */
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
+
+};
+#undef O
+
+
+/* multiple table */
+#define ML 2
+static const UINT8 mul_tab[16]= {
+/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */
+ 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
+ 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
+};
+#undef ML
+
+/* TL_TAB_LEN is calculated as:
+
+* (12+1)=13 - sinus amplitude bits (Y axis)
+* additional 1: to compensate for calculations of negative part of waveform
+* (if we don't add it then the greatest possible _negative_ value would be -2
+* and we really need -1 for waveform #7)
+* 2 - sinus sign bit (Y axis)
+* TL_RES_LEN - sinus resolution (X axis)
+*/
+#define TL_TAB_LEN (13*2*TL_RES_LEN)
+static signed int tl_tab[TL_TAB_LEN];
+
+#define ENV_QUIET (TL_TAB_LEN>>4)
+
+/* sin waveform table in 'decibel' scale */
+/* there are eight waveforms on OPL3 chips */
+static unsigned int sin_tab[SIN_LEN * 8];
+
+
+/* LFO Amplitude Modulation table (verified on real YM3812)
+ 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples
+
+ Length: 210 elements.
+
+ Each of the elements has to be repeated
+ exactly 64 times (on 64 consecutive samples).
+ The whole table takes: 64 * 210 = 13440 samples.
+
+ When AM = 1 data is used directly
+ When AM = 0 data is divided by 4 before being used (loosing precision is important)
+*/
+
+#define LFO_AM_TAB_ELEMENTS 210
+
+static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = {
+0,0,0,0,0,0,0,
+1,1,1,1,
+2,2,2,2,
+3,3,3,3,
+4,4,4,4,
+5,5,5,5,
+6,6,6,6,
+7,7,7,7,
+8,8,8,8,
+9,9,9,9,
+10,10,10,10,
+11,11,11,11,
+12,12,12,12,
+13,13,13,13,
+14,14,14,14,
+15,15,15,15,
+16,16,16,16,
+17,17,17,17,
+18,18,18,18,
+19,19,19,19,
+20,20,20,20,
+21,21,21,21,
+22,22,22,22,
+23,23,23,23,
+24,24,24,24,
+25,25,25,25,
+26,26,26,
+25,25,25,25,
+24,24,24,24,
+23,23,23,23,
+22,22,22,22,
+21,21,21,21,
+20,20,20,20,
+19,19,19,19,
+18,18,18,18,
+17,17,17,17,
+16,16,16,16,
+15,15,15,15,
+14,14,14,14,
+13,13,13,13,
+12,12,12,12,
+11,11,11,11,
+10,10,10,10,
+9,9,9,9,
+8,8,8,8,
+7,7,7,7,
+6,6,6,6,
+5,5,5,5,
+4,4,4,4,
+3,3,3,3,
+2,2,2,2,
+1,1,1,1
+};
+
+/* LFO Phase Modulation table (verified on real YM3812) */
+static const INT8 lfo_pm_table[8*8*2] = {
+
+/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */
+0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/
+0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */
+0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/
+1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */
+1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/
+2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */
+1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/
+3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */
+2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/
+4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */
+2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/
+5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */
+3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/
+6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/
+
+/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */
+3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/
+7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/
+};
+
+
+/* lock level of common table */
+static int num_lock = 0;
+
+/* work table */
+static void *cur_chip = NULL; /* current chip point */
+static OPL3_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2;
+
+static signed int phase_modulation; /* phase modulation input (SLOT 2) */
+static signed int phase_modulation2; /* phase modulation input (SLOT 3 in 4 operator channels) */
+static signed int chanout[18]; /* 18 channels */
+
+
+static UINT32 LFO_AM;
+static INT32 LFO_PM;
+
+
+
+INLINE int limit( int val, int max, int min ) {
+ if ( val > max )
+ val = max;
+ else if ( val < min )
+ val = min;
+
+ return val;
+}
+
+
+/* status set and IRQ handling */
+INLINE void OPL3_STATUS_SET(OPL3 *chip,int flag)
+{
+ /* set status flag masking out disabled IRQs */
+ chip->status |= (flag & chip->statusmask);
+ if(!(chip->status & 0x80))
+ {
+ if(chip->status & 0x7f)
+ { /* IRQ on */
+ chip->status |= 0x80;
+ /* callback user interrupt handler (IRQ is OFF to ON) */
+ if(chip->IRQHandler) (chip->IRQHandler)(chip->IRQParam,1);
+ }
+ }
+}
+
+/* status reset and IRQ handling */
+INLINE void OPL3_STATUS_RESET(OPL3 *chip,int flag)
+{
+ /* reset status flag */
+ chip->status &= ~flag;
+ if(chip->status & 0x80)
+ {
+ if (!(chip->status & 0x7f))
+ {
+ chip->status &= 0x7f;
+ /* callback user interrupt handler (IRQ is ON to OFF) */
+ if(chip->IRQHandler) (chip->IRQHandler)(chip->IRQParam,0);
+ }
+ }
+}
+
+/* IRQ mask set */
+INLINE void OPL3_STATUSMASK_SET(OPL3 *chip,int flag)
+{
+ chip->statusmask = flag;
+ /* IRQ handling check */
+ OPL3_STATUS_SET(chip,0);
+ OPL3_STATUS_RESET(chip,0);
+}
+
+
+/* advance LFO to next sample */
+INLINE void advance_lfo(OPL3 *chip)
+{
+ UINT8 tmp;
+
+ /* LFO */
+ chip->lfo_am_cnt += chip->lfo_am_inc;
+ if (chip->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<<LFO_SH) ) /* lfo_am_table is 210 elements long */
+ chip->lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<<LFO_SH);
+
+ tmp = lfo_am_table[ chip->lfo_am_cnt >> LFO_SH ];
+
+ if (chip->lfo_am_depth)
+ LFO_AM = tmp;
+ else
+ LFO_AM = tmp>>2;
+
+ chip->lfo_pm_cnt += chip->lfo_pm_inc;
+ LFO_PM = ((chip->lfo_pm_cnt>>LFO_SH) & 7) | chip->lfo_pm_depth_range;
+}
+
+/* advance to next sample */
+INLINE void advance(OPL3 *chip)
+{
+ OPL3_CH *CH;
+ OPL3_SLOT *op;
+ int i;
+
+ chip->eg_timer += chip->eg_timer_add;
+
+ while (chip->eg_timer >= chip->eg_timer_overflow)
+ {
+ chip->eg_timer -= chip->eg_timer_overflow;
+
+ chip->eg_cnt++;
+
+ for (i=0; i<9*2*2; i++)
+ {
+ CH = &chip->P_CH[i/2];
+ op = &CH->SLOT[i&1];
+#if 1
+ /* Envelope Generator */
+ switch(op->state)
+ {
+ case EG_ATT: /* attack phase */
+// if ( !(chip->eg_cnt & ((1<<op->eg_sh_ar)-1) ) )
+ if ( !(chip->eg_cnt & op->eg_m_ar) )
+ {
+ op->volume += (~op->volume *
+ (eg_inc[op->eg_sel_ar + ((chip->eg_cnt>>op->eg_sh_ar)&7)])
+ ) >>3;
+
+ if (op->volume <= MIN_ATT_INDEX)
+ {
+ op->volume = MIN_ATT_INDEX;
+ op->state = EG_DEC;
+ }
+
+ }
+ break;
+
+ case EG_DEC: /* decay phase */
+// if ( !(chip->eg_cnt & ((1<<op->eg_sh_dr)-1) ) )
+ if ( !(chip->eg_cnt & op->eg_m_dr) )
+ {
+ op->volume += eg_inc[op->eg_sel_dr + ((chip->eg_cnt>>op->eg_sh_dr)&7)];
+
+ if ( op->volume >= op->sl )
+ op->state = EG_SUS;
+
+ }
+ break;
+
+ case EG_SUS: /* sustain phase */
+
+ /* this is important behaviour:
+ one can change percusive/non-percussive modes on the fly and
+ the chip will remain in sustain phase - verified on real YM3812 */
+
+ if(op->eg_type) /* non-percussive mode */
+ {
+ /* do nothing */
+ }
+ else /* percussive mode */
+ {
+ /* during sustain phase chip adds Release Rate (in percussive mode) */
+// if ( !(chip->eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
+ if ( !(chip->eg_cnt & op->eg_m_rr) )
+ {
+ op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)];
+
+ if ( op->volume >= MAX_ATT_INDEX )
+ op->volume = MAX_ATT_INDEX;
+ }
+ /* else do nothing in sustain phase */
+ }
+ break;
+
+ case EG_REL: /* release phase */
+// if ( !(chip->eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
+ if ( !(chip->eg_cnt & op->eg_m_rr) )
+ {
+ op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)];
+
+ if ( op->volume >= MAX_ATT_INDEX )
+ {
+ op->volume = MAX_ATT_INDEX;
+ op->state = EG_OFF;
+ }
+
+ }
+ break;
+
+ default:
+ break;
+ }
+#endif
+ }
+ }
+
+ for (i=0; i<9*2*2; i++)
+ {
+ CH = &chip->P_CH[i/2];
+ op = &CH->SLOT[i&1];
+
+ /* Phase Generator */
+ if(op->vib)
+ {
+ UINT8 block;
+ unsigned int block_fnum = CH->block_fnum;
+
+ unsigned int fnum_lfo = (block_fnum&0x0380) >> 7;
+
+ signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + 16*fnum_lfo ];
+
+ if (lfo_fn_table_index_offset) /* LFO phase modulation active */
+ {
+ block_fnum += lfo_fn_table_index_offset;
+ block = (block_fnum&0x1c00) >> 10;
+ op->Cnt += (chip->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul;
+ }
+ else /* LFO phase modulation = zero */
+ {
+ op->Cnt += op->Incr;
+ }
+ }
+ else /* LFO phase modulation disabled for this operator */
+ {
+ op->Cnt += op->Incr;
+ }
+ }
+
+ /* The Noise Generator of the YM3812 is 23-bit shift register.
+ * Period is equal to 2^23-2 samples.
+ * Register works at sampling frequency of the chip, so output
+ * can change on every sample.
+ *
+ * Output of the register and input to the bit 22 is:
+ * bit0 XOR bit14 XOR bit15 XOR bit22
+ *
+ * Simply use bit 22 as the noise output.
+ */
+
+ chip->noise_p += chip->noise_f;
+ i = chip->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */
+ chip->noise_p &= FREQ_MASK;
+ while (i)
+ {
+ /*
+ UINT32 j;
+ j = ( (chip->noise_rng) ^ (chip->noise_rng>>14) ^ (chip->noise_rng>>15) ^ (chip->noise_rng>>22) ) & 1;
+ chip->noise_rng = (j<<22) | (chip->noise_rng>>1);
+ */
+
+ /*
+ Instead of doing all the logic operations above, we
+ use a trick here (and use bit 0 as the noise output).
+ The difference is only that the noise bit changes one
+ step ahead. This doesn't matter since we don't know
+ what is real state of the noise_rng after the reset.
+ */
+
+ if (chip->noise_rng & 1) chip->noise_rng ^= 0x800302;
+ chip->noise_rng >>= 1;
+
+ i--;
+ }
+}
+
+
+INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab)
+{
+ UINT32 p;
+
+ p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ];
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+ return tl_tab[p];
+}
+
+INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab)
+{
+ UINT32 p;
+
+ p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm))>>FREQ_SH) & SIN_MASK)];
+
+ if (p >= TL_TAB_LEN)
+ return 0;
+ return tl_tab[p];
+}
+
+
+#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask))
+
+/* calculate output of a standard 2 operator channel
+ (or 1st part of a 4-op channel) */
+INLINE void chan_calc( OPL3_CH *CH )
+{
+ OPL3_SLOT *SLOT;
+ unsigned int env;
+ signed int out;
+
+ phase_modulation = 0;
+ phase_modulation2= 0;
+
+ /* SLOT 1 */
+ SLOT = &CH->SLOT[SLOT1];
+ env = volume_calc(SLOT);
+ out = SLOT->op1_out[0] + SLOT->op1_out[1];
+ SLOT->op1_out[0] = SLOT->op1_out[1];
+ SLOT->op1_out[1] = 0;
+ if( env < ENV_QUIET )
+ {
+ if (!SLOT->FB)
+ out = 0;
+ SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<<SLOT->FB), SLOT->wavetable );
+ }
+ *SLOT->connect += SLOT->op1_out[1];
+//logerror("out0=%5i vol0=%4i ", SLOT->op1_out[1], env );
+
+ /* SLOT 2 */
+ SLOT++;
+ env = volume_calc(SLOT);
+ if( env < ENV_QUIET )
+ *SLOT->connect += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable);
+
+//logerror("out1=%5i vol1=%4i\n", op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable), env );
+
+}
+
+/* calculate output of a 2nd part of 4-op channel */
+INLINE void chan_calc_ext( OPL3_CH *CH )
+{
+ OPL3_SLOT *SLOT;
+ unsigned int env;
+
+ phase_modulation = 0;
+
+ /* SLOT 1 */
+ SLOT = &CH->SLOT[SLOT1];
+ env = volume_calc(SLOT);
+ if( env < ENV_QUIET )
+ *SLOT->connect += op_calc(SLOT->Cnt, env, phase_modulation2, SLOT->wavetable );
+
+ /* SLOT 2 */
+ SLOT++;
+ env = volume_calc(SLOT);
+ if( env < ENV_QUIET )
+ *SLOT->connect += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable);
+
+}
+
+/*
+ operators used in the rhythm sounds generation process:
+
+ Envelope Generator:
+
+channel operator register number Bass High Snare Tom Top
+/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal
+ 6 / 0 12 50 70 90 f0 +
+ 6 / 1 15 53 73 93 f3 +
+ 7 / 0 13 51 71 91 f1 +
+ 7 / 1 16 54 74 94 f4 +
+ 8 / 0 14 52 72 92 f2 +
+ 8 / 1 17 55 75 95 f5 +
+
+ Phase Generator:
+
+channel operator register number Bass High Snare Tom Top
+/ slot number MULTIPLE Drum Hat Drum Tom Cymbal
+ 6 / 0 12 30 +
+ 6 / 1 15 33 +
+ 7 / 0 13 31 + + +
+ 7 / 1 16 34 ----- n o t u s e d -----
+ 8 / 0 14 32 +
+ 8 / 1 17 35 + +
+
+channel operator register number Bass High Snare Tom Top
+number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal
+ 6 12,15 B6 A6 +
+
+ 7 13,16 B7 A7 + + +
+
+ 8 14,17 B8 A8 + + +
+
+*/
+
+/* calculate rhythm */
+
+INLINE void chan_calc_rhythm( OPL3_CH *CH, unsigned int noise )
+{
+ OPL3_SLOT *SLOT;
+ signed int out;
+ unsigned int env;
+
+
+ /* Bass Drum (verified on real YM3812):
+ - depends on the channel 6 'connect' register:
+ when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out)
+ when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored
+ - output sample always is multiplied by 2
+ */
+
+ phase_modulation = 0;
+
+ /* SLOT 1 */
+ SLOT = &CH[6].SLOT[SLOT1];
+ env = volume_calc(SLOT);
+
+ out = SLOT->op1_out[0] + SLOT->op1_out[1];
+ SLOT->op1_out[0] = SLOT->op1_out[1];
+
+ if (!SLOT->CON)
+ phase_modulation = SLOT->op1_out[0];
+ //else ignore output of operator 1
+
+ SLOT->op1_out[1] = 0;
+ if( env < ENV_QUIET )
+ {
+ if (!SLOT->FB)
+ out = 0;
+ SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<<SLOT->FB), SLOT->wavetable );
+ }
+
+ /* SLOT 2 */
+ SLOT++;
+ env = volume_calc(SLOT);
+ if( env < ENV_QUIET )
+ chanout[6] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2;
+
+
+ /* Phase generation is based on: */
+ // HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases)
+ // SD (16) channel 7->slot 1
+ // TOM (14) channel 8->slot 1
+ // TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases)
+
+ /* Envelope generation based on: */
+ // HH channel 7->slot1
+ // SD channel 7->slot2
+ // TOM channel 8->slot1
+ // TOP channel 8->slot2
+
+
+ /* The following formulas can be well optimized.
+ I leave them in direct form for now (in case I've missed something).
+ */
+
+ /* High Hat (verified on real YM3812) */
+ env = volume_calc(SLOT7_1);
+ if( env < ENV_QUIET )
+ {
+
+ /* high hat phase generation:
+ phase = d0 or 234 (based on frequency only)
+ phase = 34 or 2d0 (based on noise)
+ */
+
+ /* base frequency derived from operator 1 in channel 7 */
+ unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1;
+ unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1;
+ unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1;
+
+ unsigned char res1 = (bit2 ^ bit7) | bit3;
+
+ /* when res1 = 0 phase = 0x000 | 0xd0; */
+ /* when res1 = 1 phase = 0x200 | (0xd0>>2); */
+ UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0;
+
+ /* enable gate based on frequency of operator 2 in channel 8 */
+ unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1;
+ unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1;
+
+ unsigned char res2 = (bit3e ^ bit5e);
+
+ /* when res2 = 0 pass the phase from calculation above (res1); */
+ /* when res2 = 1 phase = 0x200 | (0xd0>>2); */
+ if (res2)
+ phase = (0x200|(0xd0>>2));
+
+
+ /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */
+ /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */
+ if (phase&0x200)
+ {
+ if (noise)
+ phase = 0x200|0xd0;
+ }
+ else
+ /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */
+ /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */
+ {
+ if (noise)
+ phase = 0xd0>>2;
+ }
+
+ chanout[7] += op_calc(phase<<FREQ_SH, env, 0, SLOT7_1->wavetable) * 2;
+ }
+
+ /* Snare Drum (verified on real YM3812) */
+ env = volume_calc(SLOT7_2);
+ if( env < ENV_QUIET )
+ {
+ /* base frequency derived from operator 1 in channel 7 */
+ unsigned char bit8 = ((SLOT7_1->Cnt>>FREQ_SH)>>8)&1;
+
+ /* when bit8 = 0 phase = 0x100; */
+ /* when bit8 = 1 phase = 0x200; */
+ UINT32 phase = bit8 ? 0x200 : 0x100;
+
+ /* Noise bit XOR'es phase by 0x100 */
+ /* when noisebit = 0 pass the phase from calculation above */
+ /* when noisebit = 1 phase ^= 0x100; */
+ /* in other words: phase ^= (noisebit<<8); */
+ if (noise)
+ phase ^= 0x100;
+
+ chanout[7] += op_calc(phase<<FREQ_SH, env, 0, SLOT7_2->wavetable) * 2;
+ }
+
+ /* Tom Tom (verified on real YM3812) */
+ env = volume_calc(SLOT8_1);
+ if( env < ENV_QUIET )
+ chanout[8] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2;
+
+ /* Top Cymbal (verified on real YM3812) */
+ env = volume_calc(SLOT8_2);
+ if( env < ENV_QUIET )
+ {
+ /* base frequency derived from operator 1 in channel 7 */
+ unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1;
+ unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1;
+ unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1;
+
+ unsigned char res1 = (bit2 ^ bit7) | bit3;
+
+ /* when res1 = 0 phase = 0x000 | 0x100; */
+ /* when res1 = 1 phase = 0x200 | 0x100; */
+ UINT32 phase = res1 ? 0x300 : 0x100;
+
+ /* enable gate based on frequency of operator 2 in channel 8 */
+ unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1;
+ unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1;
+
+ unsigned char res2 = (bit3e ^ bit5e);
+ /* when res2 = 0 pass the phase from calculation above (res1); */
+ /* when res2 = 1 phase = 0x200 | 0x100; */
+ if (res2)
+ phase = 0x300;
+
+ chanout[8] += op_calc(phase<<FREQ_SH, env, 0, SLOT8_2->wavetable) * 2;
+ }
+
+}
+
+
+/* generic table initialize */
+static int init_tables(void)
+{
+ signed int i,x;
+ signed int n;
+ double o,m;
+
+
+ for (x=0; x<TL_RES_LEN; x++)
+ {
+ m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0);
+ m = floor(m);
+
+ /* we never reach (1<<16) here due to the (x+1) */
+ /* result fits within 16 bits at maximum */
+
+ n = (int)m; /* 16 bits here */
+ n >>= 4; /* 12 bits here */
+ if (n&1) /* round to nearest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+ /* 11 bits here (rounded) */
+ n <<= 1; /* 12 bits here (as in real chip) */
+ tl_tab[ x*2 + 0 ] = n;
+ tl_tab[ x*2 + 1 ] = ~tl_tab[ x*2 + 0 ]; /* this *is* different from OPL2 (verified on real YMF262) */
+
+ for (i=1; i<13; i++)
+ {
+ tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i;
+ tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = ~tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; /* this *is* different from OPL2 (verified on real YMF262) */
+ }
+ #if 0
+ logerror("tl %04i", x*2);
+ for (i=0; i<13; i++)
+ logerror(", [%02i] %5i", i*2, tl_tab[ x*2 +0 + i*2*TL_RES_LEN ] ); /* positive */
+ logerror("\n");
+
+ logerror("tl %04i", x*2);
+ for (i=0; i<13; i++)
+ logerror(", [%02i] %5i", i*2, tl_tab[ x*2 +1 + i*2*TL_RES_LEN ] ); /* negative */
+ logerror("\n");
+ #endif
+ }
+
+ for (i=0; i<SIN_LEN; i++)
+ {
+ /* non-standard sinus */
+ m = sin( ((i*2)+1) * M_PI / SIN_LEN ); /* checked against the real chip */
+
+ /* we never reach zero here due to ((i*2)+1) */
+
+ if (m>0.0)
+ o = 8*log(1.0/m)/log(2); /* convert to 'decibels' */
+ else
+ o = 8*log(-1.0/m)/log(2); /* convert to 'decibels' */
+
+ o = o / (ENV_STEP/4);
+
+ n = (int)(2.0*o);
+ if (n&1) /* round to nearest */
+ n = (n>>1)+1;
+ else
+ n = n>>1;
+
+ sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 );
+
+ /*logerror("YMF262.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/
+ }
+
+ for (i=0; i<SIN_LEN; i++)
+ {
+ /* these 'pictures' represent _two_ cycles */
+ /* waveform 1: __ __ */
+ /* / \____/ \____*/
+ /* output only first half of the sinus waveform (positive one) */
+
+ if (i & (1<<(SIN_BITS-1)) )
+ sin_tab[1*SIN_LEN+i] = TL_TAB_LEN;
+ else
+ sin_tab[1*SIN_LEN+i] = sin_tab[i];
+
+ /* waveform 2: __ __ __ __ */
+ /* / \/ \/ \/ \*/
+ /* abs(sin) */
+
+ sin_tab[2*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>1) ];
+
+ /* waveform 3: _ _ _ _ */
+ /* / |_/ |_/ |_/ |_*/
+ /* abs(output only first quarter of the sinus waveform) */
+
+ if (i & (1<<(SIN_BITS-2)) )
+ sin_tab[3*SIN_LEN+i] = TL_TAB_LEN;
+ else
+ sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)];
+
+ /* waveform 4: */
+ /* /\ ____/\ ____*/
+ /* \/ \/ */
+ /* output whole sinus waveform in half the cycle(step=2) and output 0 on the other half of cycle */
+
+ if (i & (1<<(SIN_BITS-1)) )
+ sin_tab[4*SIN_LEN+i] = TL_TAB_LEN;
+ else
+ sin_tab[4*SIN_LEN+i] = sin_tab[i*2];
+
+ /* waveform 5: */
+ /* /\/\____/\/\____*/
+ /* */
+ /* output abs(whole sinus) waveform in half the cycle(step=2) and output 0 on the other half of cycle */
+
+ if (i & (1<<(SIN_BITS-1)) )
+ sin_tab[5*SIN_LEN+i] = TL_TAB_LEN;
+ else
+ sin_tab[5*SIN_LEN+i] = sin_tab[(i*2) & (SIN_MASK>>1) ];
+
+ /* waveform 6: ____ ____ */
+ /* */
+ /* ____ ____*/
+ /* output maximum in half the cycle and output minimum on the other half of cycle */
+
+ if (i & (1<<(SIN_BITS-1)) )
+ sin_tab[6*SIN_LEN+i] = 1; /* negative */
+ else
+ sin_tab[6*SIN_LEN+i] = 0; /* positive */
+
+ /* waveform 7: */
+ /* |\____ |\____ */
+ /* \| \|*/
+ /* output sawtooth waveform */
+
+ if (i & (1<<(SIN_BITS-1)) )
+ x = ((SIN_LEN-1)-i)*16 + 1; /* negative: from 8177 to 1 */
+ else
+ x = i*16; /*positive: from 0 to 8176 */
+
+ if (x > TL_TAB_LEN)
+ x = TL_TAB_LEN; /* clip to the allowed range */
+
+ sin_tab[7*SIN_LEN+i] = x;
+
+ //logerror("YMF262.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] );
+ //logerror("YMF262.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] );
+ //logerror("YMF262.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] );
+ //logerror("YMF262.C: sin4[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[4*SIN_LEN+i], tl_tab[sin_tab[4*SIN_LEN+i]] );
+ //logerror("YMF262.C: sin5[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[5*SIN_LEN+i], tl_tab[sin_tab[5*SIN_LEN+i]] );
+ //logerror("YMF262.C: sin6[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[6*SIN_LEN+i], tl_tab[sin_tab[6*SIN_LEN+i]] );
+ //logerror("YMF262.C: sin7[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[7*SIN_LEN+i], tl_tab[sin_tab[7*SIN_LEN+i]] );
+ }
+ /*logerror("YMF262.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/
+
+#ifdef SAVE_SAMPLE
+ sample[0]=fopen("sampsum.pcm","wb");
+#endif
+
+ return 1;
+}
+
+static void OPLCloseTable( void )
+{
+#ifdef SAVE_SAMPLE
+ fclose(sample[0]);
+#endif
+}
+
+
+
+static void OPL3_initalize(OPL3 *chip)
+{
+ int i;
+
+ /* frequency base */
+ chip->freqbase = (chip->rate) ? ((double)chip->clock / (8.0*36)) / chip->rate : 0;
+#if 0
+ chip->rate = (double)chip->clock / (8.0*36);
+ chip->freqbase = 1.0;
+#endif
+
+ /* logerror("YMF262: freqbase=%f\n", chip->freqbase); */
+
+ /* Timer base time */
+ chip->TimerBase = attotime_mul(ATTOTIME_IN_HZ(chip->clock), 8*36);
+
+ /* make fnumber -> increment counter table */
+ for( i=0 ; i < 1024 ; i++ )
+ {
+ /* opn phase increment counter = 20bit */
+ chip->fn_tab[i] = (UINT32)( (double)i * 64 * chip->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
+#if 0
+ logerror("YMF262.C: fn_tab[%4i] = %08x (dec=%8i)\n",
+ i, chip->fn_tab[i]>>6, chip->fn_tab[i]>>6 );
+#endif
+ }
+
+#if 0
+ for( i=0 ; i < 16 ; i++ )
+ {
+ logerror("YMF262.C: sl_tab[%i] = %08x\n",
+ i, sl_tab[i] );
+ }
+ for( i=0 ; i < 8 ; i++ )
+ {
+ int j;
+ logerror("YMF262.C: ksl_tab[oct=%2i] =",i);
+ for (j=0; j<16; j++)
+ {
+ logerror("%08x ", ksl_tab[i*16+j] );
+ }
+ logerror("\n");
+ }
+#endif
+
+
+ /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */
+ /* One entry from LFO_AM_TABLE lasts for 64 samples */
+ chip->lfo_am_inc = (1.0 / 64.0 ) * (1<<LFO_SH) * chip->freqbase;
+
+ /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */
+ chip->lfo_pm_inc = (1.0 / 1024.0) * (1<<LFO_SH) * chip->freqbase;
+
+ /*logerror ("chip->lfo_am_inc = %8x ; chip->lfo_pm_inc = %8x\n", chip->lfo_am_inc, chip->lfo_pm_inc);*/
+
+ /* Noise generator: a step takes 1 sample */
+ chip->noise_f = (1.0 / 1.0) * (1<<FREQ_SH) * chip->freqbase;
+
+ chip->eg_timer_add = (1<<EG_SH) * chip->freqbase;
+ chip->eg_timer_overflow = ( 1 ) * (1<<EG_SH);
+ /*logerror("YMF262init eg_timer_add=%8x eg_timer_overflow=%8x\n", chip->eg_timer_add, chip->eg_timer_overflow);*/
+
+}
+
+INLINE void FM_KEYON(OPL3_SLOT *SLOT, UINT32 key_set)
+{
+ if( !SLOT->key )
+ {
+ /* restart Phase Generator */
+ SLOT->Cnt = 0;
+ /* phase -> Attack */
+ SLOT->state = EG_ATT;
+ }
+ SLOT->key |= key_set;
+}
+
+INLINE void FM_KEYOFF(OPL3_SLOT *SLOT, UINT32 key_clr)
+{
+ if( SLOT->key )
+ {
+ SLOT->key &= key_clr;
+
+ if( !SLOT->key )
+ {
+ /* phase -> Release */
+ if (SLOT->state>EG_REL)
+ SLOT->state = EG_REL;
+ }
+ }
+}
+
+/* update phase increment counter of operator (also update the EG rates if necessary) */
+INLINE void CALC_FCSLOT(OPL3_CH *CH,OPL3_SLOT *SLOT)
+{
+ int ksr;
+
+ /* (frequency) phase increment counter */
+ SLOT->Incr = CH->fc * SLOT->mul;
+ ksr = CH->kcode >> SLOT->KSR;
+
+ if( SLOT->ksr != ksr )
+ {
+ SLOT->ksr = ksr;
+
+ /* calculate envelope generator rates */
+ if ((SLOT->ar + SLOT->ksr) < 16+60)
+ {
+ SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
+ SLOT->eg_m_ar = (1<<SLOT->eg_sh_ar)-1;
+ SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
+ }
+ else
+ {
+ SLOT->eg_sh_ar = 0;
+ SLOT->eg_m_ar = (1<<SLOT->eg_sh_ar)-1;
+ SLOT->eg_sel_ar = 13*RATE_STEPS;
+ }
+ SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ];
+ SLOT->eg_m_dr = (1<<SLOT->eg_sh_dr)-1;
+ SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ];
+ SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ];
+ SLOT->eg_m_rr = (1<<SLOT->eg_sh_rr)-1;
+ SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ];
+ }
+}
+
+/* set multi,am,vib,EG-TYP,KSR,mul */
+INLINE void set_mul(OPL3 *chip,int slot,int v)
+{
+ OPL3_CH *CH = &chip->P_CH[slot/2];
+ OPL3_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ SLOT->mul = mul_tab[v&0x0f];
+ SLOT->KSR = (v&0x10) ? 0 : 2;
+ SLOT->eg_type = (v&0x20);
+ SLOT->vib = (v&0x40);
+ SLOT->AMmask = (v&0x80) ? ~0 : 0;
+
+ if (chip->OPL3_mode & 1)
+ {
+ int chan_no = slot/2;
+
+ /* in OPL3 mode */
+ //DO THIS:
+ //if this is one of the slots of 1st channel forming up a 4-op channel
+ //do normal operation
+ //else normal 2 operator function
+ //OR THIS:
+ //if this is one of the slots of 2nd channel forming up a 4-op channel
+ //update it using channel data of 1st channel of a pair
+ //else normal 2 operator function
+ switch(chan_no)
+ {
+ case 0: case 1: case 2:
+ case 9: case 10: case 11:
+ if (CH->extended)
+ {
+ /* normal */
+ CALC_FCSLOT(CH,SLOT);
+ }
+ else
+ {
+ /* normal */
+ CALC_FCSLOT(CH,SLOT);
+ }
+ break;
+ case 3: case 4: case 5:
+ case 12: case 13: case 14:
+ if ((CH-3)->extended)
+ {
+ /* update this SLOT using frequency data for 1st channel of a pair */
+ CALC_FCSLOT(CH-3,SLOT);
+ }
+ else
+ {
+ /* normal */
+ CALC_FCSLOT(CH,SLOT);
+ }
+ break;
+ default:
+ /* normal */
+ CALC_FCSLOT(CH,SLOT);
+ break;
+ }
+ }
+ else
+ {
+ /* in OPL2 mode */
+ CALC_FCSLOT(CH,SLOT);
+ }
+}
+
+/* set ksl & tl */
+INLINE void set_ksl_tl(OPL3 *chip,int slot,int v)
+{
+ OPL3_CH *CH = &chip->P_CH[slot/2];
+ OPL3_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ int ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */
+
+ SLOT->ksl = ksl ? 3-ksl : 31;
+ SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */
+
+ if (chip->OPL3_mode & 1)
+ {
+ int chan_no = slot/2;
+
+ /* in OPL3 mode */
+ //DO THIS:
+ //if this is one of the slots of 1st channel forming up a 4-op channel
+ //do normal operation
+ //else normal 2 operator function
+ //OR THIS:
+ //if this is one of the slots of 2nd channel forming up a 4-op channel
+ //update it using channel data of 1st channel of a pair
+ //else normal 2 operator function
+ switch(chan_no)
+ {
+ case 0: case 1: case 2:
+ case 9: case 10: case 11:
+ if (CH->extended)
+ {
+ /* normal */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+ }
+ else
+ {
+ /* normal */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+ }
+ break;
+ case 3: case 4: case 5:
+ case 12: case 13: case 14:
+ if ((CH-3)->extended)
+ {
+ /* update this SLOT using frequency data for 1st channel of a pair */
+ SLOT->TLL = SLOT->TL + ((CH-3)->ksl_base>>SLOT->ksl);
+ }
+ else
+ {
+ /* normal */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+ }
+ break;
+ default:
+ /* normal */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+ break;
+ }
+ }
+ else
+ {
+ /* in OPL2 mode */
+ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+ }
+
+}
+
+/* set attack rate & decay rate */
+INLINE void set_ar_dr(OPL3 *chip,int slot,int v)
+{
+ OPL3_CH *CH = &chip->P_CH[slot/2];
+ OPL3_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0;
+
+ if ((SLOT->ar + SLOT->ksr) < 16+60) /* verified on real YMF262 - all 15 x rates take "zero" time */
+ {
+ SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
+ SLOT->eg_m_ar = (1<<SLOT->eg_sh_ar)-1;
+ SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
+ }
+ else
+ {
+ SLOT->eg_sh_ar = 0;
+ SLOT->eg_m_ar = (1<<SLOT->eg_sh_ar)-1;
+ SLOT->eg_sel_ar = 13*RATE_STEPS;
+ }
+
+ SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0;
+ SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ];
+ SLOT->eg_m_dr = (1<<SLOT->eg_sh_dr)-1;
+ SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ];
+}
+
+/* set sustain level & release rate */
+INLINE void set_sl_rr(OPL3 *chip,int slot,int v)
+{
+ OPL3_CH *CH = &chip->P_CH[slot/2];
+ OPL3_SLOT *SLOT = &CH->SLOT[slot&1];
+
+ SLOT->sl = sl_tab[ v>>4 ];
+
+ SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0;
+ SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ];
+ SLOT->eg_m_rr = (1<<SLOT->eg_sh_rr)-1;
+ SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ];
+}
+
+
+static void update_channels(OPL3 *chip, OPL3_CH *CH)
+{
+ /* update channel passed as a parameter and a channel at CH+=3; */
+ if (CH->extended)
+ { /* we've just switched to combined 4 operator mode */
+
+ }
+ else
+ { /* we've just switched to normal 2 operator mode */
+
+ }
+
+}
+
+/* write a value v to register r on OPL chip */
+static void OPL3WriteReg(OPL3 *chip, int r, int v)
+{
+ OPL3_CH *CH;
+ unsigned int ch_offset = 0;
+ int slot;
+ int block_fnum;
+
+
+
+#ifdef LOG_CYM_FILE
+ if ((cymfile) && ((r&255)!=0) && (r!=255) )
+ {
+ if (r>0xff)
+ fputc( (unsigned char)0xff, cymfile );/*mark writes to second register set*/
+
+ fputc( (unsigned char)r&0xff, cymfile );
+ fputc( (unsigned char)v, cymfile );
+ }
+#endif
+
+ if(r&0x100)
+ {
+ switch(r)
+ {
+ case 0x101: /* test register */
+ return;
+ break;
+ case 0x104: /* 6 channels enable */
+ {
+ UINT8 prev;
+
+ CH = &chip->P_CH[0]; /* channel 0 */
+ prev = CH->extended;
+ CH->extended = (v>>0) & 1;
+ if(prev != CH->extended)
+ update_channels(chip, CH);
+ CH++; /* channel 1 */
+ prev = CH->extended;
+ CH->extended = (v>>1) & 1;
+ if(prev != CH->extended)
+ update_channels(chip, CH);
+ CH++; /* channel 2 */
+ prev = CH->extended;
+ CH->extended = (v>>2) & 1;
+ if(prev != CH->extended)
+ update_channels(chip, CH);
+
+
+ CH = &chip->P_CH[9]; /* channel 9 */
+ prev = CH->extended;
+ CH->extended = (v>>3) & 1;
+ if(prev != CH->extended)
+ update_channels(chip, CH);
+ CH++; /* channel 10 */
+ prev = CH->extended;
+ CH->extended = (v>>4) & 1;
+ if(prev != CH->extended)
+ update_channels(chip, CH);
+ CH++; /* channel 11 */
+ prev = CH->extended;
+ CH->extended = (v>>5) & 1;
+ if(prev != CH->extended)
+ update_channels(chip, CH);
+
+ }
+ return;
+ break;
+ case 0x105: /* OPL3 extensions enable register */
+
+ chip->OPL3_mode = v&0x01; /* OPL3 mode when bit0=1 otherwise it is OPL2 mode */
+
+ /* following behaviour was tested on real YMF262,
+ switching OPL3/OPL2 modes on the fly:
+ - does not change the waveform previously selected (unless when ....)
+ - does not update CH.A, CH.B, CH.C and CH.D output selectors (registers c0-c8) (unless when ....)
+ - does not disable channels 9-17 on OPL3->OPL2 switch
+ - does not switch 4 operator channels back to 2 operator channels
+ */
+
+ return;
+ break;
+
+ default:
+ if (r < 0x120)
+ logerror("YMF262: write to unknown register (set#2): %03x value=%02x\n",r,v);
+ break;
+ }
+
+ ch_offset = 9; /* register page #2 starts from channel 9 (counting from 0) */
+ }
+
+ /* adjust bus to 8 bits */
+ r &= 0xff;
+ v &= 0xff;
+
+
+ switch(r&0xe0)
+ {
+ case 0x00: /* 00-1f:control */
+ switch(r&0x1f)
+ {
+ case 0x01: /* test register */
+ break;
+ case 0x02: /* Timer 1 */
+ chip->T[0] = (256-v)*4;
+ break;
+ case 0x03: /* Timer 2 */
+ chip->T[1] = (256-v)*16;
+ break;
+ case 0x04: /* IRQ clear / mask and Timer enable */
+ if(v&0x80)
+ { /* IRQ flags clear */
+ OPL3_STATUS_RESET(chip,0x60);
+ }
+ else
+ { /* set IRQ mask ,timer enable */
+ UINT8 st1 = v & 1;
+ UINT8 st2 = (v>>1) & 1;
+
+ /* IRQRST,T1MSK,t2MSK,x,x,x,ST2,ST1 */
+ OPL3_STATUS_RESET(chip, v & 0x60);
+ OPL3_STATUSMASK_SET(chip, (~v) & 0x60 );
+
+ /* timer 2 */
+ if(chip->st[1] != st2)
+ {
+ attotime period = st2 ? attotime_mul(chip->TimerBase, chip->T[1]) : attotime_zero;
+ chip->st[1] = st2;
+ if (chip->timer_handler) (chip->timer_handler)(chip->TimerParam,1,period);
+ }
+ /* timer 1 */
+ if(chip->st[0] != st1)
+ {
+ attotime period = st1 ? attotime_mul(chip->TimerBase, chip->T[0]) : attotime_zero;
+ chip->st[0] = st1;
+ if (chip->timer_handler) (chip->timer_handler)(chip->TimerParam,0,period);
+ }
+ }
+ break;
+ case 0x08: /* x,NTS,x,x, x,x,x,x */
+ chip->nts = v;
+ break;
+
+ default:
+ logerror("YMF262: write to unknown register: %02x value=%02x\n",r,v);
+ break;
+ }
+ break;
+ case 0x20: /* am ON, vib ON, ksr, eg_type, mul */
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+ set_mul(chip, slot + ch_offset*2, v);
+ break;
+ case 0x40:
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+ set_ksl_tl(chip, slot + ch_offset*2, v);
+ break;
+ case 0x60:
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+ set_ar_dr(chip, slot + ch_offset*2, v);
+ break;
+ case 0x80:
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+ set_sl_rr(chip, slot + ch_offset*2, v);
+ break;
+ case 0xa0:
+ if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */
+ {
+ if (ch_offset != 0) /* 0xbd register is present in set #1 only */
+ return;
+
+ chip->lfo_am_depth = v & 0x80;
+ chip->lfo_pm_depth_range = (v&0x40) ? 8 : 0;
+
+ chip->rhythm = v&0x3f;
+
+ if(chip->rhythm&0x20)
+ {
+ /* BD key on/off */
+ if(v&0x10)
+ {
+ FM_KEYON (&chip->P_CH[6].SLOT[SLOT1], 2);
+ FM_KEYON (&chip->P_CH[6].SLOT[SLOT2], 2);
+ }
+ else
+ {
+ FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT1],~2);
+ FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT2],~2);
+ }
+ /* HH key on/off */
+ if(v&0x01) FM_KEYON (&chip->P_CH[7].SLOT[SLOT1], 2);
+ else FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT1],~2);
+ /* SD key on/off */
+ if(v&0x08) FM_KEYON (&chip->P_CH[7].SLOT[SLOT2], 2);
+ else FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT2],~2);
+ /* TOM key on/off */
+ if(v&0x04) FM_KEYON (&chip->P_CH[8].SLOT[SLOT1], 2);
+ else FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT1],~2);
+ /* TOP-CY key on/off */
+ if(v&0x02) FM_KEYON (&chip->P_CH[8].SLOT[SLOT2], 2);
+ else FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT2],~2);
+ }
+ else
+ {
+ /* BD key off */
+ FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT1],~2);
+ FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT2],~2);
+ /* HH key off */
+ FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT1],~2);
+ /* SD key off */
+ FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT2],~2);
+ /* TOM key off */
+ FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT1],~2);
+ /* TOP-CY off */
+ FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT2],~2);
+ }
+ return;
+ }
+
+ /* keyon,block,fnum */
+ if( (r&0x0f) > 8) return;
+ CH = &chip->P_CH[(r&0x0f) + ch_offset];
+
+ if(!(r&0x10))
+ { /* a0-a8 */
+ block_fnum = (CH->block_fnum&0x1f00) | v;
+ }
+ else
+ { /* b0-b8 */
+ block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
+
+ if (chip->OPL3_mode & 1)
+ {
+ int chan_no = (r&0x0f) + ch_offset;
+
+ /* in OPL3 mode */
+ //DO THIS:
+ //if this is 1st channel forming up a 4-op channel
+ //ALSO keyon/off slots of 2nd channel forming up 4-op channel
+ //else normal 2 operator function keyon/off
+ //OR THIS:
+ //if this is 2nd channel forming up 4-op channel just do nothing
+ //else normal 2 operator function keyon/off
+ switch(chan_no)
+ {
+ case 0: case 1: case 2:
+ case 9: case 10: case 11:
+ if (CH->extended)
+ {
+ //if this is 1st channel forming up a 4-op channel
+ //ALSO keyon/off slots of 2nd channel forming up 4-op channel
+ if(v&0x20)
+ {
+ FM_KEYON (&CH->SLOT[SLOT1], 1);
+ FM_KEYON (&CH->SLOT[SLOT2], 1);
+ FM_KEYON (&(CH+3)->SLOT[SLOT1], 1);
+ FM_KEYON (&(CH+3)->SLOT[SLOT2], 1);
+ }
+ else
+ {
+ FM_KEYOFF(&CH->SLOT[SLOT1],~1);
+ FM_KEYOFF(&CH->SLOT[SLOT2],~1);
+ FM_KEYOFF(&(CH+3)->SLOT[SLOT1],~1);
+ FM_KEYOFF(&(CH+3)->SLOT[SLOT2],~1);
+ }
+ }
+ else
+ {
+ //else normal 2 operator function keyon/off
+ if(v&0x20)
+ {
+ FM_KEYON (&CH->SLOT[SLOT1], 1);
+ FM_KEYON (&CH->SLOT[SLOT2], 1);
+ }
+ else
+ {
+ FM_KEYOFF(&CH->SLOT[SLOT1],~1);
+ FM_KEYOFF(&CH->SLOT[SLOT2],~1);
+ }
+ }
+ break;
+
+ case 3: case 4: case 5:
+ case 12: case 13: case 14:
+ if ((CH-3)->extended)
+ {
+ //if this is 2nd channel forming up 4-op channel just do nothing
+ }
+ else
+ {
+ //else normal 2 operator function keyon/off
+ if(v&0x20)
+ {
+ FM_KEYON (&CH->SLOT[SLOT1], 1);
+ FM_KEYON (&CH->SLOT[SLOT2], 1);
+ }
+ else
+ {
+ FM_KEYOFF(&CH->SLOT[SLOT1],~1);
+ FM_KEYOFF(&CH->SLOT[SLOT2],~1);
+ }
+ }
+ break;
+
+ default:
+ if(v&0x20)
+ {
+ FM_KEYON (&CH->SLOT[SLOT1], 1);
+ FM_KEYON (&CH->SLOT[SLOT2], 1);
+ }
+ else
+ {
+ FM_KEYOFF(&CH->SLOT[SLOT1],~1);
+ FM_KEYOFF(&CH->SLOT[SLOT2],~1);
+ }
+ break;
+ }
+ }
+ else
+ {
+ if(v&0x20)
+ {
+ FM_KEYON (&CH->SLOT[SLOT1], 1);
+ FM_KEYON (&CH->SLOT[SLOT2], 1);
+ }
+ else
+ {
+ FM_KEYOFF(&CH->SLOT[SLOT1],~1);
+ FM_KEYOFF(&CH->SLOT[SLOT2],~1);
+ }
+ }
+ }
+ /* update */
+ if(CH->block_fnum != block_fnum)
+ {
+ UINT8 block = block_fnum >> 10;
+
+ CH->block_fnum = block_fnum;
+
+ CH->ksl_base = ksl_tab[block_fnum>>6];
+ CH->fc = chip->fn_tab[block_fnum&0x03ff] >> (7-block);
+
+ /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */
+ CH->kcode = (CH->block_fnum&0x1c00)>>9;
+
+ /* the info below is actually opposite to what is stated in the Manuals (verifed on real YMF262) */
+ /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */
+ /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */
+ if (chip->nts&0x40)
+ CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */
+ else
+ CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */
+
+ if (chip->OPL3_mode & 1)
+ {
+ int chan_no = (r&0x0f) + ch_offset;
+ /* in OPL3 mode */
+ //DO THIS:
+ //if this is 1st channel forming up a 4-op channel
+ //ALSO update slots of 2nd channel forming up 4-op channel
+ //else normal 2 operator function keyon/off
+ //OR THIS:
+ //if this is 2nd channel forming up 4-op channel just do nothing
+ //else normal 2 operator function keyon/off
+ switch(chan_no)
+ {
+ case 0: case 1: case 2:
+ case 9: case 10: case 11:
+ if (CH->extended)
+ {
+ //if this is 1st channel forming up a 4-op channel
+ //ALSO update slots of 2nd channel forming up 4-op channel
+
+ /* refresh Total Level in FOUR SLOTs of this channel and channel+3 using data from THIS channel */
+ CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl);
+ CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl);
+ (CH+3)->SLOT[SLOT1].TLL = (CH+3)->SLOT[SLOT1].TL + (CH->ksl_base>>(CH+3)->SLOT[SLOT1].ksl);
+ (CH+3)->SLOT[SLOT2].TLL = (CH+3)->SLOT[SLOT2].TL + (CH->ksl_base>>(CH+3)->SLOT[SLOT2].ksl);
+
+ /* refresh frequency counter in FOUR SLOTs of this channel and channel+3 using data from THIS channel */
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+ CALC_FCSLOT(CH,&(CH+3)->SLOT[SLOT1]);
+ CALC_FCSLOT(CH,&(CH+3)->SLOT[SLOT2]);
+ }
+ else
+ {
+ //else normal 2 operator function
+ /* refresh Total Level in both SLOTs of this channel */
+ CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl);
+ CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl);
+
+ /* refresh frequency counter in both SLOTs of this channel */
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+ }
+ break;
+
+ case 3: case 4: case 5:
+ case 12: case 13: case 14:
+ if ((CH-3)->extended)
+ {
+ //if this is 2nd channel forming up 4-op channel just do nothing
+ }
+ else
+ {
+ //else normal 2 operator function
+ /* refresh Total Level in both SLOTs of this channel */
+ CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl);
+ CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl);
+
+ /* refresh frequency counter in both SLOTs of this channel */
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+ }
+ break;
+
+ default:
+ /* refresh Total Level in both SLOTs of this channel */
+ CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl);
+ CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl);
+
+ /* refresh frequency counter in both SLOTs of this channel */
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+ break;
+ }
+ }
+ else
+ {
+ /* in OPL2 mode */
+
+ /* refresh Total Level in both SLOTs of this channel */
+ CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl);
+ CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl);
+
+ /* refresh frequency counter in both SLOTs of this channel */
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+ CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+ }
+ }
+ break;
+
+ case 0xc0:
+ /* CH.D, CH.C, CH.B, CH.A, FB(3bits), C */
+ if( (r&0xf) > 8) return;
+
+ CH = &chip->P_CH[(r&0xf) + ch_offset];
+
+ if( chip->OPL3_mode & 1 )
+ {
+ int base = ((r&0xf) + ch_offset) * 4;
+
+ /* OPL3 mode */
+ chip->pan[ base ] = (v & 0x10) ? ~0 : 0; /* ch.A */
+ chip->pan[ base +1 ] = (v & 0x20) ? ~0 : 0; /* ch.B */
+ chip->pan[ base +2 ] = (v & 0x40) ? ~0 : 0; /* ch.C */
+ chip->pan[ base +3 ] = (v & 0x80) ? ~0 : 0; /* ch.D */
+ }
+ else
+ {
+ int base = ((r&0xf) + ch_offset) * 4;
+
+ /* OPL2 mode - always enabled */
+ chip->pan[ base ] = ~0; /* ch.A */
+ chip->pan[ base +1 ] = ~0; /* ch.B */
+ chip->pan[ base +2 ] = ~0; /* ch.C */
+ chip->pan[ base +3 ] = ~0; /* ch.D */
+ }
+
+ chip->pan_ctrl_value[ (r&0xf) + ch_offset ] = v; /* store control value for OPL3/OPL2 mode switching on the fly */
+
+ CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0;
+ CH->SLOT[SLOT1].CON = v&1;
+
+ if( chip->OPL3_mode & 1 )
+ {
+ int chan_no = (r&0x0f) + ch_offset;
+
+ switch(chan_no)
+ {
+ case 0: case 1: case 2:
+ case 9: case 10: case 11:
+ if (CH->extended)
+ {
+ UINT8 conn = (CH->SLOT[SLOT1].CON<<1) || ((CH+3)->SLOT[SLOT1].CON<<0);
+ switch(conn)
+ {
+ case 0:
+ /* 1 -> 2 -> 3 -> 4 - out */
+
+ CH->SLOT[SLOT1].connect = &phase_modulation;
+ CH->SLOT[SLOT2].connect = &phase_modulation2;
+ (CH+3)->SLOT[SLOT1].connect = &phase_modulation;
+ (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ];
+ break;
+ case 1:
+ /* 1 -> 2 -\
+ 3 -> 4 -+- out */
+
+ CH->SLOT[SLOT1].connect = &phase_modulation;
+ CH->SLOT[SLOT2].connect = &chanout[ chan_no ];
+ (CH+3)->SLOT[SLOT1].connect = &phase_modulation;
+ (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ];
+ break;
+ case 2:
+ /* 1 -----------\
+ 2 -> 3 -> 4 -+- out */
+
+ CH->SLOT[SLOT1].connect = &chanout[ chan_no ];
+ CH->SLOT[SLOT2].connect = &phase_modulation2;
+ (CH+3)->SLOT[SLOT1].connect = &phase_modulation;
+ (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ];
+ break;
+ case 3:
+ /* 1 ------\
+ 2 -> 3 -+- out
+ 4 ------/ */
+ CH->SLOT[SLOT1].connect = &chanout[ chan_no ];
+ CH->SLOT[SLOT2].connect = &phase_modulation2;
+ (CH+3)->SLOT[SLOT1].connect = &chanout[ chan_no + 3 ];
+ (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ];
+ break;
+ }
+ }
+ else
+ {
+ /* 2 operators mode */
+ CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &phase_modulation;
+ CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset];
+ }
+ break;
+
+ case 3: case 4: case 5:
+ case 12: case 13: case 14:
+ if ((CH-3)->extended)
+ {
+ UINT8 conn = ((CH-3)->SLOT[SLOT1].CON<<1) || (CH->SLOT[SLOT1].CON<<0);
+ switch(conn)
+ {
+ case 0:
+ /* 1 -> 2 -> 3 -> 4 - out */
+
+ (CH-3)->SLOT[SLOT1].connect = &phase_modulation;
+ (CH-3)->SLOT[SLOT2].connect = &phase_modulation2;
+ CH->SLOT[SLOT1].connect = &phase_modulation;
+ CH->SLOT[SLOT2].connect = &chanout[ chan_no ];
+ break;
+ case 1:
+ /* 1 -> 2 -\
+ 3 -> 4 -+- out */
+
+ (CH-3)->SLOT[SLOT1].connect = &phase_modulation;
+ (CH-3)->SLOT[SLOT2].connect = &chanout[ chan_no - 3 ];
+ CH->SLOT[SLOT1].connect = &phase_modulation;
+ CH->SLOT[SLOT2].connect = &chanout[ chan_no ];
+ break;
+ case 2:
+ /* 1 -----------\
+ 2 -> 3 -> 4 -+- out */
+
+ (CH-3)->SLOT[SLOT1].connect = &chanout[ chan_no - 3 ];
+ (CH-3)->SLOT[SLOT2].connect = &phase_modulation2;
+ CH->SLOT[SLOT1].connect = &phase_modulation;
+ CH->SLOT[SLOT2].connect = &chanout[ chan_no ];
+ break;
+ case 3:
+ /* 1 ------\
+ 2 -> 3 -+- out
+ 4 ------/ */
+ (CH-3)->SLOT[SLOT1].connect = &chanout[ chan_no - 3 ];
+ (CH-3)->SLOT[SLOT2].connect = &phase_modulation2;
+ CH->SLOT[SLOT1].connect = &chanout[ chan_no ];
+ CH->SLOT[SLOT2].connect = &chanout[ chan_no ];
+ break;
+ }
+ }
+ else
+ {
+ /* 2 operators mode */
+ CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &phase_modulation;
+ CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset];
+ }
+ break;
+
+ default:
+ /* 2 operators mode */
+ CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &phase_modulation;
+ CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset];
+ break;
+ }
+ }
+ else
+ {
+ /* OPL2 mode - always 2 operators mode */
+ CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &phase_modulation;
+ CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset];
+ }
+ break;
+
+ case 0xe0: /* waveform select */
+ slot = slot_array[r&0x1f];
+ if(slot < 0) return;
+
+ slot += ch_offset*2;
+
+ CH = &chip->P_CH[slot/2];
+
+
+ /* store 3-bit value written regardless of current OPL2 or OPL3 mode... (verified on real YMF262) */
+ v &= 7;
+ CH->SLOT[slot&1].waveform_number = v;
+
+ /* ... but select only waveforms 0-3 in OPL2 mode */
+ if( !(chip->OPL3_mode & 1) )
+ {
+ v &= 3; /* we're in OPL2 mode */
+ }
+ CH->SLOT[slot&1].wavetable = v * SIN_LEN;
+ break;
+ }
+}
+
+#ifdef LOG_CYM_FILE
+static TIMER_CALLBACK( cymfile_callback )
+{
+ if (cymfile)
+ {
+ fputc( (unsigned char)0, cymfile );
+ }
+}
+#endif
+
+/* lock/unlock for common table */
+static int OPL3_LockTable(void)
+{
+ num_lock++;
+ if(num_lock>1) return 0;
+
+ /* first time */
+
+ cur_chip = NULL;
+
+ if( !init_tables() )
+ {
+ num_lock--;
+ return -1;
+ }
+
+#ifdef LOG_CYM_FILE
+ cymfile = fopen("ymf262_.cym","wb");
+ if (cymfile)
+ timer_pulse ( ATTOTIME_IN_HZ(110), 0, cymfile_callback); /*110 Hz pulse timer*/
+ else
+ logerror("Could not create ymf262_.cym file\n");
+#endif
+
+ return 0;
+}
+
+static void OPL3_UnLockTable(void)
+{
+ if(num_lock) num_lock--;
+ if(num_lock) return;
+
+ /* last time */
+
+ cur_chip = NULL;
+ OPLCloseTable();
+
+#ifdef LOG_CYM_FILE
+ fclose (cymfile);
+ cymfile = NULL;
+#endif
+
+}
+
+static void OPL3ResetChip(OPL3 *chip)
+{
+ int c,s;
+
+ chip->eg_timer = 0;
+ chip->eg_cnt = 0;
+
+ chip->noise_rng = 1; /* noise shift register */
+ chip->nts = 0; /* note split */
+ OPL3_STATUS_RESET(chip,0x60);
+
+ /* reset with register write */
+ OPL3WriteReg(chip,0x01,0); /* test register */
+ OPL3WriteReg(chip,0x02,0); /* Timer1 */
+ OPL3WriteReg(chip,0x03,0); /* Timer2 */
+ OPL3WriteReg(chip,0x04,0); /* IRQ mask clear */
+
+
+//FIX IT registers 101, 104 and 105
+
+
+//FIX IT (dont change CH.D, CH.C, CH.B and CH.A in C0-C8 registers)
+ for(c = 0xff ; c >= 0x20 ; c-- )
+ OPL3WriteReg(chip,c,0);
+//FIX IT (dont change CH.D, CH.C, CH.B and CH.A in C0-C8 registers)
+ for(c = 0x1ff ; c >= 0x120 ; c-- )
+ OPL3WriteReg(chip,c,0);
+
+
+
+ /* reset operator parameters */
+ for( c = 0 ; c < 9*2 ; c++ )
+ {
+ OPL3_CH *CH = &chip->P_CH[c];
+ for(s = 0 ; s < 2 ; s++ )
+ {
+ CH->SLOT[s].state = EG_OFF;
+ CH->SLOT[s].volume = MAX_ATT_INDEX;
+ }
+ }
+}
+
+/* Create one of virtual YMF262 */
+/* 'clock' is chip clock in Hz */
+/* 'rate' is sampling rate */
+static OPL3 *OPL3Create(int type, int clock, int rate)
+{
+ OPL3 *chip;
+
+ if (OPL3_LockTable() ==-1) return NULL;
+
+ /* allocate memory block */
+ chip = (OPL3 *)malloc(sizeof(OPL3));
+
+ if (chip==NULL)
+ return NULL;
+
+ /* clear */
+ memset(chip, 0, sizeof(OPL3));
+
+ chip->type = type;
+ chip->clock = clock;
+ chip->rate = rate;
+
+ /* init global tables */
+ OPL3_initalize(chip);
+
+ /* reset chip */
+ OPL3ResetChip(chip);
+ return chip;
+}
+
+/* Destroy one of virtual YMF262 */
+static void OPL3Destroy(OPL3 *chip)
+{
+ OPL3_UnLockTable();
+ free(chip);
+}
+
+
+/* Optional handlers */
+
+static void OPL3SetTimerHandler(OPL3 *chip,OPL3_TIMERHANDLER timer_handler,void *param)
+{
+ chip->timer_handler = timer_handler;
+ chip->TimerParam = param;
+}
+static void OPL3SetIRQHandler(OPL3 *chip,OPL3_IRQHANDLER IRQHandler,void *param)
+{
+ chip->IRQHandler = IRQHandler;
+ chip->IRQParam = param;
+}
+static void OPL3SetUpdateHandler(OPL3 *chip,OPL3_UPDATEHANDLER UpdateHandler,void *param)
+{
+ chip->UpdateHandler = UpdateHandler;
+ chip->UpdateParam = param;
+}
+
+/* YMF262 I/O interface */
+static int OPL3Write(OPL3 *chip, int a, int v)
+{
+ /* data bus is 8 bits */
+ v &= 0xff;
+
+ switch(a&3)
+ {
+ case 0: /* address port 0 (register set #1) */
+ chip->address = v;
+ break;
+
+ case 1: /* data port - ignore A1 */
+ case 3: /* data port - ignore A1 */
+ if(chip->UpdateHandler) chip->UpdateHandler(chip->UpdateParam,0);
+ OPL3WriteReg(chip,chip->address,v);
+ break;
+
+ case 2: /* address port 1 (register set #2) */
+
+ /* verified on real YMF262:
+ in OPL3 mode:
+ address line A1 is stored during *address* write and ignored during *data* write.
+
+ in OPL2 mode:
+ register set#2 writes go to register set#1 (ignoring A1)
+ verified on registers from set#2: 0x01, 0x04, 0x20-0xef
+ The only exception is register 0x05.
+ */
+ if( chip->OPL3_mode & 1 )
+ {
+ /* OPL3 mode */
+ chip->address = v | 0x100;
+ }
+ else
+ {
+ /* in OPL2 mode the only accessible in set #2 is register 0x05 */
+ if( v==5 )
+ chip->address = v | 0x100;
+ else
+ chip->address = v; /* verified range: 0x01, 0x04, 0x20-0xef(set #2 becomes set #1 in opl2 mode) */
+ }
+ break;
+ }
+
+ return chip->status>>7;
+}
+
+static unsigned char OPL3Read(OPL3 *chip,int a)
+{
+ if( a==0 )
+ {
+ /* status port */
+ return chip->status;
+ }
+
+ return 0x00; /* verified on real YMF262 */
+}
+
+
+
+static int OPL3TimerOver(OPL3 *chip,int c)
+{
+ if( c )
+ { /* Timer B */
+ OPL3_STATUS_SET(chip,0x20);
+ }
+ else
+ { /* Timer A */
+ OPL3_STATUS_SET(chip,0x40);
+ }
+ /* reload timer */
+ if (chip->timer_handler) (chip->timer_handler)(chip->TimerParam,c,attotime_mul(chip->TimerBase, chip->T[c]));
+ return chip->status>>7;
+}
+
+
+
+
+void * YMF262Init(int clock, int rate)
+{
+ return OPL3Create(OPL3_TYPE_YMF262,clock,rate);
+}
+
+void YMF262Shutdown(void *chip)
+{
+ OPL3Destroy(chip);
+}
+void YMF262ResetChip(void *chip)
+{
+ OPL3ResetChip(chip);
+}
+
+int YMF262Write(void *chip, int a, int v)
+{
+ return OPL3Write(chip, a, v);
+}
+
+unsigned char YMF262Read(void *chip, int a)
+{
+ /* Note on status register: */
+
+ /* YM3526(OPL) and YM3812(OPL2) return bit2 and bit1 in HIGH state */
+
+ /* YMF262(OPL3) always returns bit2 and bit1 in LOW state */
+ /* which can be used to identify the chip */
+
+ /* YMF278(OPL4) returns bit2 in LOW and bit1 in HIGH state ??? info from manual - not verified */
+
+ return OPL3Read(chip, a);
+}
+int YMF262TimerOver(void *chip, int c)
+{
+ return OPL3TimerOver(chip, c);
+}
+
+void YMF262SetTimerHandler(void *chip, OPL3_TIMERHANDLER timer_handler, void *param)
+{
+ OPL3SetTimerHandler(chip, timer_handler, param);
+}
+void YMF262SetIRQHandler(void *chip,OPL3_IRQHANDLER IRQHandler,void *param)
+{
+ OPL3SetIRQHandler(chip, IRQHandler, param);
+}
+void YMF262SetUpdateHandler(void *chip,OPL3_UPDATEHANDLER UpdateHandler,void *param)
+{
+ OPL3SetUpdateHandler(chip, UpdateHandler, param);
+}
+
+
+/*
+** Generate samples for one of the YMF262's
+**
+** 'which' is the virtual YMF262 number
+** '**buffers' is table of 4 pointers to the buffers: CH.A, CH.B, CH.C and CH.D
+** 'length' is the number of samples that should be generated
+*/
+void YMF262UpdateOne(void *_chip, OPL3SAMPLE **buffers, int length)
+{
+ OPL3 *chip = _chip;
+ UINT8 rhythm = chip->rhythm&0x20;
+
+ OPL3SAMPLE *ch_a = buffers[0];
+ OPL3SAMPLE *ch_b = buffers[1];
+ OPL3SAMPLE *ch_c = buffers[2];
+ OPL3SAMPLE *ch_d = buffers[3];
+
+ int i;
+
+ if( (void *)chip != cur_chip ){
+ cur_chip = (void *)chip;
+ /* rhythm slots */
+ SLOT7_1 = &chip->P_CH[7].SLOT[SLOT1];
+ SLOT7_2 = &chip->P_CH[7].SLOT[SLOT2];
+ SLOT8_1 = &chip->P_CH[8].SLOT[SLOT1];
+ SLOT8_2 = &chip->P_CH[8].SLOT[SLOT2];
+ }
+ for( i=0; i < length ; i++ )
+ {
+ int a,b,c,d;
+
+
+ advance_lfo(chip);
+
+ /* clear channel outputs */
+ memset(chanout, 0, sizeof(signed int) * 18);
+
+#if 1
+ /* register set #1 */
+ chan_calc(&chip->P_CH[0]); /* extended 4op ch#0 part 1 or 2op ch#0 */
+ if (chip->P_CH[0].extended)
+ chan_calc_ext(&chip->P_CH[3]); /* extended 4op ch#0 part 2 */
+ else
+ chan_calc(&chip->P_CH[3]); /* standard 2op ch#3 */
+
+
+ chan_calc(&chip->P_CH[1]); /* extended 4op ch#1 part 1 or 2op ch#1 */
+ if (chip->P_CH[1].extended)
+ chan_calc_ext(&chip->P_CH[4]); /* extended 4op ch#1 part 2 */
+ else
+ chan_calc(&chip->P_CH[4]); /* standard 2op ch#4 */
+
+
+ chan_calc(&chip->P_CH[2]); /* extended 4op ch#2 part 1 or 2op ch#2 */
+ if (chip->P_CH[2].extended)
+ chan_calc_ext(&chip->P_CH[5]); /* extended 4op ch#2 part 2 */
+ else
+ chan_calc(&chip->P_CH[5]); /* standard 2op ch#5 */
+
+
+ if(!rhythm)
+ {
+ chan_calc(&chip->P_CH[6]);
+ chan_calc(&chip->P_CH[7]);
+ chan_calc(&chip->P_CH[8]);
+ }
+ else /* Rhythm part */
+ {
+ chan_calc_rhythm(&chip->P_CH[0], (chip->noise_rng>>0)&1 );
+ }
+
+ /* register set #2 */
+ chan_calc(&chip->P_CH[ 9]);
+ if (chip->P_CH[9].extended)
+ chan_calc_ext(&chip->P_CH[12]);
+ else
+ chan_calc(&chip->P_CH[12]);
+
+
+ chan_calc(&chip->P_CH[10]);
+ if (chip->P_CH[10].extended)
+ chan_calc_ext(&chip->P_CH[13]);
+ else
+ chan_calc(&chip->P_CH[13]);
+
+
+ chan_calc(&chip->P_CH[11]);
+ if (chip->P_CH[11].extended)
+ chan_calc_ext(&chip->P_CH[14]);
+ else
+ chan_calc(&chip->P_CH[14]);
+
+
+ /* channels 15,16,17 are fixed 2-operator channels only */
+ chan_calc(&chip->P_CH[15]);
+ chan_calc(&chip->P_CH[16]);
+ chan_calc(&chip->P_CH[17]);
+#endif
+
+ /* accumulator register set #1 */
+ a = chanout[0] & chip->pan[0];
+ b = chanout[0] & chip->pan[1];
+ c = chanout[0] & chip->pan[2];
+ d = chanout[0] & chip->pan[3];
+#if 1
+ a += chanout[1] & chip->pan[4];
+ b += chanout[1] & chip->pan[5];
+ c += chanout[1] & chip->pan[6];
+ d += chanout[1] & chip->pan[7];
+ a += chanout[2] & chip->pan[8];
+ b += chanout[2] & chip->pan[9];
+ c += chanout[2] & chip->pan[10];
+ d += chanout[2] & chip->pan[11];
+
+ a += chanout[3] & chip->pan[12];
+ b += chanout[3] & chip->pan[13];
+ c += chanout[3] & chip->pan[14];
+ d += chanout[3] & chip->pan[15];
+ a += chanout[4] & chip->pan[16];
+ b += chanout[4] & chip->pan[17];
+ c += chanout[4] & chip->pan[18];
+ d += chanout[4] & chip->pan[19];
+ a += chanout[5] & chip->pan[20];
+ b += chanout[5] & chip->pan[21];
+ c += chanout[5] & chip->pan[22];
+ d += chanout[5] & chip->pan[23];
+
+ a += chanout[6] & chip->pan[24];
+ b += chanout[6] & chip->pan[25];
+ c += chanout[6] & chip->pan[26];
+ d += chanout[6] & chip->pan[27];
+ a += chanout[7] & chip->pan[28];
+ b += chanout[7] & chip->pan[29];
+ c += chanout[7] & chip->pan[30];
+ d += chanout[7] & chip->pan[31];
+ a += chanout[8] & chip->pan[32];
+ b += chanout[8] & chip->pan[33];
+ c += chanout[8] & chip->pan[34];
+ d += chanout[8] & chip->pan[35];
+
+ /* accumulator register set #2 */
+ a += chanout[9] & chip->pan[36];
+ b += chanout[9] & chip->pan[37];
+ c += chanout[9] & chip->pan[38];
+ d += chanout[9] & chip->pan[39];
+ a += chanout[10] & chip->pan[40];
+ b += chanout[10] & chip->pan[41];
+ c += chanout[10] & chip->pan[42];
+ d += chanout[10] & chip->pan[43];
+ a += chanout[11] & chip->pan[44];
+ b += chanout[11] & chip->pan[45];
+ c += chanout[11] & chip->pan[46];
+ d += chanout[11] & chip->pan[47];
+
+ a += chanout[12] & chip->pan[48];
+ b += chanout[12] & chip->pan[49];
+ c += chanout[12] & chip->pan[50];
+ d += chanout[12] & chip->pan[51];
+ a += chanout[13] & chip->pan[52];
+ b += chanout[13] & chip->pan[53];
+ c += chanout[13] & chip->pan[54];
+ d += chanout[13] & chip->pan[55];
+ a += chanout[14] & chip->pan[56];
+ b += chanout[14] & chip->pan[57];
+ c += chanout[14] & chip->pan[58];
+ d += chanout[14] & chip->pan[59];
+
+ a += chanout[15] & chip->pan[60];
+ b += chanout[15] & chip->pan[61];
+ c += chanout[15] & chip->pan[62];
+ d += chanout[15] & chip->pan[63];
+ a += chanout[16] & chip->pan[64];
+ b += chanout[16] & chip->pan[65];
+ c += chanout[16] & chip->pan[66];
+ d += chanout[16] & chip->pan[67];
+ a += chanout[17] & chip->pan[68];
+ b += chanout[17] & chip->pan[69];
+ c += chanout[17] & chip->pan[70];
+ d += chanout[17] & chip->pan[71];
+#endif
+ a >>= FINAL_SH;
+ b >>= FINAL_SH;
+ c >>= FINAL_SH;
+ d >>= FINAL_SH;
+
+ /* limit check */
+ a = limit( a , MAXOUT, MINOUT );
+ b = limit( b , MAXOUT, MINOUT );
+ c = limit( c , MAXOUT, MINOUT );
+ d = limit( d , MAXOUT, MINOUT );
+
+ #ifdef SAVE_SAMPLE
+ if (which==0)
+ {
+ SAVE_ALL_CHANNELS
+ }
+ #endif
+
+ /* store to sound buffer */
+ ch_a[i] = a;
+ ch_b[i] = b;
+ ch_c[i] = c;
+ ch_d[i] = d;
+
+ advance(chip);
+ }
+
+}
+
diff --git a/src/emu/sound/ymf262.h b/src/emu/sound/ymf262.h
new file mode 100644
index 00000000000..63ef5bba561
--- /dev/null
+++ b/src/emu/sound/ymf262.h
@@ -0,0 +1,46 @@
+#ifndef YMF262_H
+#define YMF262_H
+
+/* select number of output bits: 8 or 16 */
+#define OPL3_SAMPLE_BITS 16
+
+/* compiler dependence */
+#ifndef __OSDCOMM_H__
+#define __OSDCOMM_H__
+typedef unsigned char UINT8; /* unsigned 8bit */
+typedef unsigned short UINT16; /* unsigned 16bit */
+typedef unsigned int UINT32; /* unsigned 32bit */
+typedef signed char INT8; /* signed 8bit */
+typedef signed short INT16; /* signed 16bit */
+typedef signed int INT32; /* signed 32bit */
+#endif
+
+typedef stream_sample_t OPL3SAMPLE;
+/*
+#if (OPL3_SAMPLE_BITS==16)
+typedef INT16 OPL3SAMPLE;
+#endif
+#if (OPL3_SAMPLE_BITS==8)
+typedef INT8 OPL3SAMPLE;
+#endif
+*/
+
+typedef void (*OPL3_TIMERHANDLER)(void *param,int timer,attotime period);
+typedef void (*OPL3_IRQHANDLER)(void *param,int irq);
+typedef void (*OPL3_UPDATEHANDLER)(void *param,int min_interval_us);
+
+
+void *YMF262Init(int clock, int rate);
+void YMF262Shutdown(void *chip);
+void YMF262ResetChip(void *chip);
+int YMF262Write(void *chip, int a, int v);
+unsigned char YMF262Read(void *chip, int a);
+int YMF262TimerOver(void *chip, int c);
+void YMF262UpdateOne(void *chip, OPL3SAMPLE **buffers, int length);
+
+void YMF262SetTimerHandler(void *chip, OPL3_TIMERHANDLER TimerHandler, void *param);
+void YMF262SetIRQHandler(void *chip, OPL3_IRQHANDLER IRQHandler, void *param);
+void YMF262SetUpdateHandler(void *chip, OPL3_UPDATEHANDLER UpdateHandler, void *param);
+
+
+#endif /* YMF262_H */
diff --git a/src/emu/sound/ymf271.c b/src/emu/sound/ymf271.c
new file mode 100644
index 00000000000..710fdc3b9d6
--- /dev/null
+++ b/src/emu/sound/ymf271.c
@@ -0,0 +1,1833 @@
+/*
+ Yamaha YMF271-F "OPX" emulator v0.1
+ By R. Belmont.
+ Based in part on YMF278B emulator by R. Belmont and O. Galibert.
+ 12June04 update by Toshiaki Nijiura
+ Copyright (c) 2003 R. Belmont.
+
+ This software is dual-licensed: it may be used in MAME and properly licensed
+ MAME derivatives under the terms of the MAME license. For use outside of
+ MAME and properly licensed derivatives, it is available under the
+ terms of the GNU Lesser General Public License (LGPL), version 2.1.
+ You may read the LGPL at http://www.gnu.org/licenses/lgpl.html
+*/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "ymf271.h"
+
+#define VERBOSE (1)
+
+#define MAXOUT (+32767)
+#define MINOUT (-32768)
+
+#define SIN_BITS 10
+#define SIN_LEN (1<<SIN_BITS)
+#define SIN_MASK (SIN_LEN-1)
+
+#define LFO_LENGTH 256
+#define LFO_SHIFT 8
+#define PLFO_MAX (+1.0)
+#define PLFO_MIN (-1.0)
+#define ALFO_MAX (+65536)
+#define ALFO_MIN (0)
+
+#define log2(n) (log((float) n)/log((float) 2))
+
+typedef struct
+{
+ INT8 extout;
+ UINT8 lfoFreq;
+ INT8 lfowave;
+ INT8 pms, ams;
+ INT8 detune;
+ INT8 multiple;
+ INT8 tl;
+ INT8 keyscale;
+ INT8 ar;
+ INT8 decay1rate, decay2rate;
+ INT8 decay1lvl;
+ INT8 relrate;
+ INT32 fns;
+ INT8 block;
+ INT8 feedback;
+ INT8 waveform;
+ INT8 accon;
+ INT8 algorithm;
+ INT8 ch0_level, ch1_level, ch2_level, ch3_level;
+
+ UINT32 startaddr;
+ UINT32 loopaddr;
+ UINT32 endaddr;
+ INT8 fs, srcnote, srcb;
+
+ INT64 step;
+ INT64 stepptr;
+
+ INT8 active;
+ INT8 bits;
+
+ // envelope generator
+ INT32 volume;
+ INT32 env_state;
+ INT32 env_attack_step; // volume increase step in attack state
+ INT32 env_decay1_step;
+ INT32 env_decay2_step;
+ INT32 env_release_step;
+
+ INT64 feedback_modulation0;
+ INT64 feedback_modulation1;
+
+ INT32 lfo_phase, lfo_step;
+ INT32 lfo_amplitude;
+ double lfo_phasemod;
+} YMF271Slot;
+
+typedef struct
+{
+ INT8 sync, pfm;
+} YMF271Group;
+
+typedef struct
+{
+ YMF271Slot slots[48];
+ YMF271Group groups[12];
+
+ INT32 timerA, timerB;
+ INT32 timerAVal, timerBVal;
+ INT32 irqstate;
+ INT8 status;
+ INT8 enable;
+
+ emu_timer *timA, *timB;
+
+ INT8 reg0, reg1, reg2, reg3, pcmreg, timerreg;
+ UINT32 ext_address;
+ UINT8 ext_read;
+
+ const UINT8 *rom;
+ read8_handler ext_mem_read;
+ write8_handler ext_mem_write;
+ void (*irq_callback)(int);
+
+ int index;
+ UINT32 clock;
+ sound_stream * stream;
+} YMF271Chip;
+
+// slot mapping assists
+static const int fm_tab[] = { 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1 };
+static const int pcm_tab[] = { 0, 4, 8, -1, 12, 16, 20, -1, 24, 28, 32, -1, 36, 40, 44, -1 };
+
+static INT16 *wavetable[8];
+static double plfo_table[4][8][LFO_LENGTH];
+static int alfo_table[4][LFO_LENGTH];
+static INT32 *mix;
+
+#define ENV_ATTACK 0
+#define ENV_DECAY1 1
+#define ENV_DECAY2 2
+#define ENV_RELEASE 3
+
+#define ENV_VOLUME_SHIFT 16
+
+#define INF 100000000.0
+
+static const double ARTime[] =
+{
+ INF, INF, INF, INF, 6188.12, 4980.68, 4144.76, 3541.04,
+ 3094.06, 2490.34, 2072.38, 1770.52, 1547.03, 1245.17, 1036.19, 885.26,
+ 773.51, 622.59, 518.10, 441.63, 386.76, 311.29, 259.05, 221.32,
+ 193.38, 155.65, 129.52, 110.66, 96.69, 77.82, 64.76, 55.33,
+ 48.34, 38.91, 32.38, 27.66, 24.17, 19.46, 16.19, 13.83,
+ 12.09, 9.73, 8.10, 6.92, 6.04, 4.86, 4.05, 3.46,
+ 3.02, 2.47, 2.14, 1.88, 1.70, 1.38, 1.16, 1.02,
+ 0.88, 0.70, 0.57, 0.48, 0.43, 0.43, 0.43, 0.07
+};
+
+static const double DCTime[] =
+{
+ INF, INF, INF, INF, 93599.64, 74837.91, 62392.02, 53475.56,
+ 46799.82, 37418.96, 31196.01, 26737.78, 23399.91, 18709.48, 15598.00, 13368.89,
+ 11699.95, 9354.74, 7799.00, 6684.44, 5849.98, 4677.37, 3899.50, 3342.22,
+ 2924.99, 2338.68, 1949.75, 1671.11, 1462.49, 1169.34, 974.88, 835.56,
+ 731.25, 584.67, 487.44, 417.78, 365.62, 292.34, 243.72, 208.89,
+ 182.81, 146.17, 121.86, 104.44, 91.41, 73.08, 60.93, 52.22,
+ 45.69, 36.55, 33.85, 26.09, 22.83, 18.28, 15.22, 13.03,
+ 11.41, 9.12, 7.60, 6.51, 5.69, 5.69, 5.69, 5.69
+};
+
+static const double LFO_frequency_table[256] =
+{
+ 0.00066, 0.00068, 0.00070, 0.00073, 0.00075, 0.00078, 0.00081, 0.00084,
+ 0.00088, 0.00091, 0.00096, 0.00100, 0.00105, 0.00111, 0.00117, 0.00124,
+ 0.00131, 0.00136, 0.00140, 0.00145, 0.00150, 0.00156, 0.00162, 0.00168,
+ 0.00175, 0.00183, 0.00191, 0.00200, 0.00210, 0.00221, 0.00234, 0.00247,
+ 0.00263, 0.00271, 0.00280, 0.00290, 0.00300, 0.00312, 0.00324, 0.00336,
+ 0.00350, 0.00366, 0.00382, 0.00401, 0.00421, 0.00443, 0.00467, 0.00495,
+ 0.00526, 0.00543, 0.00561, 0.00580, 0.00601, 0.00623, 0.00647, 0.00673,
+ 0.00701, 0.00731, 0.00765, 0.00801, 0.00841, 0.00885, 0.00935, 0.00990,
+ 0.01051, 0.01085, 0.01122, 0.01160, 0.01202, 0.01246, 0.01294, 0.01346,
+ 0.01402, 0.01463, 0.01529, 0.01602, 0.01682, 0.01771, 0.01869, 0.01979,
+ 0.02103, 0.02171, 0.02243, 0.02320, 0.02403, 0.02492, 0.02588, 0.02692,
+ 0.02804, 0.02926, 0.03059, 0.03204, 0.03365, 0.03542, 0.03738, 0.03958,
+ 0.04206, 0.04341, 0.04486, 0.04641, 0.04807, 0.04985, 0.05176, 0.05383,
+ 0.05608, 0.05851, 0.06117, 0.06409, 0.06729, 0.07083, 0.07477, 0.07917,
+ 0.08411, 0.08683, 0.08972, 0.09282, 0.09613, 0.09969, 0.10353, 0.10767,
+ 0.11215, 0.11703, 0.12235, 0.12817, 0.13458, 0.14167, 0.14954, 0.15833,
+ 0.16823, 0.17365, 0.17944, 0.18563, 0.19226, 0.19938, 0.20705, 0.21533,
+ 0.22430, 0.23406, 0.24470, 0.25635, 0.26917, 0.28333, 0.29907, 0.31666,
+ 0.33646, 0.34731, 0.35889, 0.37126, 0.38452, 0.39876, 0.41410, 0.43066,
+ 0.44861, 0.46811, 0.48939, 0.51270, 0.53833, 0.56666, 0.59814, 0.63333,
+ 0.67291, 0.69462, 0.71777, 0.74252, 0.76904, 0.79753, 0.82820, 0.86133,
+ 0.89722, 0.93623, 0.97878, 1.02539, 1.07666, 1.13333, 1.19629, 1.26666,
+ 1.34583, 1.38924, 1.43555, 1.48505, 1.53809, 1.59509, 1.65640, 1.72266,
+ 1.79443, 1.87245, 1.95756, 2.05078, 2.15332, 2.26665, 2.39258, 2.53332,
+ 2.69165, 2.77848, 2.87109, 2.97010, 3.07617, 3.19010, 3.31280, 3.44531,
+ 3.58887, 3.74490, 3.92000, 4.10156, 4.30664, 4.53331, 4.78516, 5.06664,
+ 5.38330, 5.55696, 5.74219, 5.94019, 6.15234, 6.38021, 6.62560, 6.89062,
+ 7.17773, 7.48981, 7.83026, 8.20312, 8.61328, 9.06661, 9.57031, 10.13327,
+ 10.76660, 11.11391, 11.48438, 11.88039, 12.30469, 12.76042, 13.25120, 13.78125,
+ 13.35547, 14.97962, 15.66051, 16.40625, 17.22656, 18.13322, 19.14062, 20.26654,
+ 21.53320, 22.96875, 24.60938, 26.50240, 28.71094, 31.32102, 34.45312, 38.28125,
+ 43.06641, 49.21875, 57.42188, 68.90625, 86.13281, 114.84375, 172.26562, 344.53125
+};
+
+static const int RKS_Table[32][8] =
+{
+ { 0, 0, 0, 0, 0, 2, 4, 8 },
+ { 0, 0, 0, 0, 1, 3, 5, 9 },
+ { 0, 0, 0, 1, 2, 4, 6, 10 },
+ { 0, 0, 0, 1, 3, 5, 7, 11 },
+ { 0, 0, 1, 2, 4, 6, 8, 12 },
+ { 0, 0, 1, 2, 5, 7, 9, 13 },
+ { 0, 0, 1, 3, 6, 8, 10, 14 },
+ { 0, 0, 1, 3, 7, 9, 11, 15 },
+ { 0, 1, 2, 4, 8, 10, 12, 16 },
+ { 0, 1, 2, 4, 9, 11, 13, 17 },
+ { 0, 1, 2, 5, 10, 12, 14, 18 },
+ { 0, 1, 2, 5, 11, 13, 15, 19 },
+ { 0, 1, 3, 6, 12, 14, 16, 20 },
+ { 0, 1, 3, 6, 13, 15, 17, 21 },
+ { 0, 1, 3, 7, 14, 16, 18, 22 },
+ { 0, 1, 3, 7, 15, 17, 19, 23 },
+ { 0, 2, 4, 8, 16, 18, 20, 24 },
+ { 0, 2, 4, 8, 17, 19, 21, 25 },
+ { 0, 2, 4, 9, 18, 20, 22, 26 },
+ { 0, 2, 4, 9, 19, 21, 23, 27 },
+ { 0, 2, 5, 10, 20, 22, 24, 28 },
+ { 0, 2, 5, 10, 21, 23, 25, 29 },
+ { 0, 2, 5, 11, 22, 24, 26, 30 },
+ { 0, 2, 5, 11, 23, 25, 27, 31 },
+ { 0, 3, 6, 12, 24, 26, 28, 31 },
+ { 0, 3, 6, 12, 25, 27, 29, 31 },
+ { 0, 3, 6, 13, 26, 28, 30, 31 },
+ { 0, 3, 6, 13, 27, 29, 31, 31 },
+ { 0, 3, 7, 14, 28, 30, 31, 31 },
+ { 0, 3, 7, 14, 29, 31, 31, 31 },
+ { 0, 3, 7, 15, 30, 31, 31, 31 },
+ { 0, 3, 7, 15, 31, 31, 31, 31 },
+};
+
+static const double channel_attenuation_table[16] =
+{
+ 0.0, 2.5, 6.0, 8.5, 12.0, 14.5, 18.1, 20.6, 24.1, 26.6, 30.1, 32.6, 36.1, 96.1, 96.1, 96.1
+};
+
+static const int modulation_level[8] = { 16, 8, 4, 2, 1, 32, 64, 128 };
+
+// feedback_level * 16
+static const int feedback_level[8] = { 0, 1, 2, 4, 8, 16, 32, 64 };
+
+static int channel_attenuation[16];
+static int total_level[128];
+static int env_volume_table[256];
+
+INLINE int GET_KEYSCALED_RATE(int rate, int keycode, int keyscale)
+{
+ int newrate = rate + RKS_Table[keycode][keyscale];
+
+ if (newrate > 63)
+ {
+ newrate = 63;
+ }
+ if (newrate < 0)
+ {
+ newrate = 0;
+ }
+ return newrate;
+}
+
+INLINE int GET_INTERNAL_KEYCODE(int block, int fns)
+{
+ int n43;
+ if (fns < 0x780)
+ {
+ n43 = 0;
+ }
+ else if (fns < 0x900)
+ {
+ n43 = 1;
+ }
+ else if (fns < 0xa80)
+ {
+ n43 = 2;
+ }
+ else
+ {
+ n43 = 3;
+ }
+
+ return ((block & 7) * 4) + n43;
+}
+
+INLINE int GET_EXTERNAL_KEYCODE(int block, int fns)
+{
+ /* TODO: SrcB and SrcNote !? */
+ int n43;
+ if (fns < 0x100)
+ {
+ n43 = 0;
+ }
+ else if (fns < 0x300)
+ {
+ n43 = 1;
+ }
+ else if (fns < 0x500)
+ {
+ n43 = 2;
+ }
+ else
+ {
+ n43 = 3;
+ }
+
+ return ((block & 7) * 4) + n43;
+}
+
+static const double multiple_table[16] = { 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+
+static const double pow_table[16] = { 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0.5, 1, 2, 4, 8, 16, 32, 64 };
+
+static const double fs_frequency[4] = { 1.0/1.0, 1.0/2.0, 1.0/4.0, 1.0/8.0 };
+
+INLINE void calculate_step(YMF271Slot *slot)
+{
+ double st;
+
+ if (slot->waveform == 7) // external waveform (PCM)
+ {
+ st = (double)(2 * (slot->fns | 2048)) * pow_table[slot->block] * fs_frequency[slot->fs];
+ st = st * multiple_table[slot->multiple];
+
+ // LFO phase modulation
+ st *= slot->lfo_phasemod;
+
+ st /= (double)(524288/65536); // pre-multiply with 65536
+
+ slot->step = (UINT64)st;
+ }
+ else // internal waveform (FM)
+ {
+ st = (double)(2 * slot->fns) * pow_table[slot->block];
+ st = st * multiple_table[slot->multiple] * (double)(SIN_LEN);
+
+ // LFO phase modulation
+ st *= slot->lfo_phasemod;
+
+ st /= (double)(536870912/65536); // pre-multiply with 65536
+
+ slot->step = (UINT64)st;
+ }
+}
+
+static void update_envelope(YMF271Slot *slot)
+{
+ switch (slot->env_state)
+ {
+ case ENV_ATTACK:
+ {
+ slot->volume += slot->env_attack_step;
+
+ if (slot->volume >= (255 << ENV_VOLUME_SHIFT))
+ {
+ slot->volume = (255 << ENV_VOLUME_SHIFT);
+ slot->env_state = ENV_DECAY1;
+ }
+ break;
+ }
+
+ case ENV_DECAY1:
+ {
+ int decay_level = 255 - (slot->decay1lvl << 4);
+ slot->volume -= slot->env_decay1_step;
+
+ if ((slot->volume >> (ENV_VOLUME_SHIFT)) <= decay_level)
+ {
+ slot->env_state = ENV_DECAY2;
+ }
+ break;
+ }
+
+ case ENV_DECAY2:
+ {
+ slot->volume -= slot->env_decay2_step;
+
+ if (slot->volume < 0)
+ {
+ slot->volume = 0;
+ }
+ break;
+ }
+
+ case ENV_RELEASE:
+ {
+ slot->volume -= slot->env_release_step;
+
+ if (slot->volume <= (0 << ENV_VOLUME_SHIFT))
+ {
+ slot->active = 0;
+ slot->volume = 0;
+ }
+ break;
+ }
+ }
+}
+
+static void init_envelope(YMF271Slot *slot)
+{
+ int keycode, rate;
+ int attack_length, decay1_length, decay2_length, release_length;
+ int decay_level = 255 - (slot->decay1lvl << 4);
+
+ double time;
+
+ if (slot->waveform != 7)
+ {
+ keycode = GET_INTERNAL_KEYCODE(slot->block, slot->fns);
+ }
+ else
+ {
+ keycode = GET_EXTERNAL_KEYCODE(slot->block, slot->fns);
+ }
+
+ // init attack state
+ rate = GET_KEYSCALED_RATE(slot->ar * 2, keycode, slot->keyscale);
+ time = ARTime[rate];
+
+ attack_length = (UINT32)((time * 44100.0) / 1000.0); // attack end time in samples
+ slot->env_attack_step = (int)(((double)(160-0) / (double)(attack_length)) * 65536.0);
+
+ // init decay1 state
+ rate = GET_KEYSCALED_RATE(slot->decay1rate * 2, keycode, slot->keyscale);
+ time = DCTime[rate];
+
+ decay1_length = (UINT32)((time * 44100.0) / 1000.0);
+ slot->env_decay1_step = (int)(((double)(255-decay_level) / (double)(decay1_length)) * 65536.0);
+
+ // init decay2 state
+ rate = GET_KEYSCALED_RATE(slot->decay2rate * 2, keycode, slot->keyscale);
+ time = DCTime[rate];
+
+ decay2_length = (UINT32)((time * 44100.0) / 1000.0);
+ slot->env_decay2_step = (int)(((double)(255-0) / (double)(decay2_length)) * 65536.0);
+
+ // init release state
+ rate = GET_KEYSCALED_RATE(slot->relrate * 4, keycode, slot->keyscale);
+ time = ARTime[rate];
+
+ release_length = (UINT32)((time * 44100.0) / 1000.0);
+ slot->env_release_step = (int)(((double)(255-0) / (double)(release_length)) * 65536.0);
+
+ slot->volume = (255-160) << ENV_VOLUME_SHIFT; // -60db
+ slot->env_state = ENV_ATTACK;
+}
+
+static void init_lfo(YMF271Slot *slot)
+{
+ slot->lfo_phase = 0;
+ slot->lfo_amplitude = 0;
+ slot->lfo_phasemod = 0;
+
+ slot->lfo_step = (int)((((double)LFO_LENGTH * LFO_frequency_table[slot->lfoFreq]) / 44100.0) * 256.0);
+}
+
+INLINE void update_lfo(YMF271Slot *slot)
+{
+ slot->lfo_phase += slot->lfo_step;
+
+ slot->lfo_amplitude = alfo_table[slot->lfowave][(slot->lfo_phase >> LFO_SHIFT) & (LFO_LENGTH-1)];
+ slot->lfo_phasemod = plfo_table[slot->lfowave][slot->pms][(slot->lfo_phase >> LFO_SHIFT) & (LFO_LENGTH-1)];
+
+ calculate_step(slot);
+}
+
+INLINE int calculate_slot_volume(YMF271Slot *slot)
+{
+ UINT64 volume;
+ UINT64 env_volume;
+ UINT64 lfo_volume = 65536;
+
+ switch (slot->ams)
+ {
+ case 0: lfo_volume = 65536; break; // 0dB
+ case 1: lfo_volume = 65536 - (((UINT64)slot->lfo_amplitude * 33124) >> 16); break; // 5.90625dB
+ case 2: lfo_volume = 65536 - (((UINT64)slot->lfo_amplitude * 16742) >> 16); break; // 11.8125dB
+ case 3: lfo_volume = 65536 - (((UINT64)slot->lfo_amplitude * 4277) >> 16); break; // 23.625dB
+ }
+
+ env_volume = ((UINT64)env_volume_table[255 - (slot->volume >> ENV_VOLUME_SHIFT)] * (UINT64)lfo_volume) >> 16;
+
+ volume = ((UINT64)env_volume * (UINT64)total_level[slot->tl]) >> 16;
+
+ return volume;
+}
+
+static void update_pcm(YMF271Chip *chip, int slotnum, INT32 *mixp, int length)
+{
+ int i;
+ int final_volume;
+ INT16 sample;
+ INT64 ch0_vol, ch1_vol, ch2_vol, ch3_vol;
+ const UINT8 *rombase;
+
+ YMF271Slot *slot = &chip->slots[slotnum];
+ rombase = chip->rom;
+
+ if (!slot->active)
+ {
+ return;
+ }
+
+ if (slot->waveform != 7)
+ {
+ fatalerror("Waveform %d in update_pcm !!!", slot->waveform);
+ }
+
+ for (i = 0; i < length; i++)
+ {
+ if (slot->bits == 8)
+ {
+ sample = rombase[slot->startaddr + (slot->stepptr>>16)]<<8;
+ }
+ else
+ {
+ if (slot->stepptr & 1)
+ sample = rombase[slot->startaddr + (slot->stepptr>>17)*3 + 2]<<8 | ((rombase[slot->startaddr + (slot->stepptr>>17)*3 + 1] << 4) & 0xf0);
+ else
+ sample = rombase[slot->startaddr + (slot->stepptr>>17)*3]<<8 | (rombase[slot->startaddr + (slot->stepptr>>17)*3 + 1] & 0xf0);
+ }
+
+ update_envelope(slot);
+ update_lfo(slot);
+
+ final_volume = calculate_slot_volume(slot);
+
+ ch0_vol = ((UINT64)final_volume * (UINT64)channel_attenuation[slot->ch0_level]) >> 16;
+ ch1_vol = ((UINT64)final_volume * (UINT64)channel_attenuation[slot->ch1_level]) >> 16;
+ ch2_vol = ((UINT64)final_volume * (UINT64)channel_attenuation[slot->ch2_level]) >> 16;
+ ch3_vol = ((UINT64)final_volume * (UINT64)channel_attenuation[slot->ch3_level]) >> 16;
+
+ if (ch0_vol > 65536) ch0_vol = 65536;
+ if (ch1_vol > 65536) ch1_vol = 65536;
+
+ *mixp++ += (sample * ch0_vol) >> 16;
+ *mixp++ += (sample * ch1_vol) >> 16;
+
+ slot->stepptr += slot->step;
+ if ((slot->stepptr>>16) > slot->endaddr)
+ {
+ // kill non-frac
+ slot->stepptr &= 0xffff;
+ slot->stepptr |= (slot->loopaddr<<16);
+ }
+ }
+}
+
+// calculates 2 operator FM using algorithm 0
+// <--------|
+// +--[S1]--+--[S3]-->
+INLINE INT32 calculate_2op_fm_0(YMF271Chip *chip, int slotnum1, int slotnum2)
+{
+ YMF271Slot *slot1 = &chip->slots[slotnum1];
+ YMF271Slot *slot2 = &chip->slots[slotnum2];
+ INT64 env1, env2;
+ INT64 slot1_output, slot2_output;
+ INT64 phase_mod;
+ INT64 feedback;
+
+ update_envelope(slot1);
+ update_lfo(slot1);
+ env1 = calculate_slot_volume(slot1);
+ update_envelope(slot2);
+ update_lfo(slot2);
+ env2 = calculate_slot_volume(slot2);
+
+ feedback = (slot1->feedback_modulation0 + slot1->feedback_modulation1) / 2;
+ slot1->feedback_modulation0 = slot1->feedback_modulation1;
+
+ slot1_output = wavetable[slot1->waveform][((slot1->stepptr + feedback) >> 16) & SIN_MASK];
+ slot1_output = (slot1_output * env1) >> 16;
+
+ phase_mod = ((slot1_output << (SIN_BITS-2)) * modulation_level[slot2->feedback]);
+ slot2_output = wavetable[slot2->waveform][((slot2->stepptr + phase_mod) >> 16) & SIN_MASK];
+ slot2_output = (slot2_output * env2) >> 16;
+
+ slot1->feedback_modulation1 = (((slot1_output << (SIN_BITS-2)) * feedback_level[slot1->feedback]) / 16);
+
+ slot1->stepptr += slot1->step;
+ slot2->stepptr += slot2->step;
+
+ return slot2_output;
+}
+
+// calculates 2 operator FM using algorithm 1
+// <-----------------|
+// +--[S1]--+--[S3]--|-->
+INLINE INT32 calculate_2op_fm_1(YMF271Chip *chip, int slotnum1, int slotnum2)
+{
+ YMF271Slot *slot1 = &chip->slots[slotnum1];
+ YMF271Slot *slot2 = &chip->slots[slotnum2];
+ INT64 env1, env2;
+ INT64 slot1_output, slot2_output;
+ INT64 phase_mod;
+ INT64 feedback;
+
+ update_envelope(slot1);
+ update_lfo(slot1);
+ env1 = calculate_slot_volume(slot1);
+ update_envelope(slot2);
+ update_lfo(slot2);
+ env2 = calculate_slot_volume(slot2);
+
+ feedback = (slot1->feedback_modulation0 + slot1->feedback_modulation1) / 2;
+ slot1->feedback_modulation0 = slot1->feedback_modulation1;
+
+ slot1_output = wavetable[slot1->waveform][((slot1->stepptr + feedback) >> 16) & SIN_MASK];
+ slot1_output = (slot1_output * env1) >> 16;
+
+ phase_mod = ((slot1_output << (SIN_BITS-2)) * modulation_level[slot2->feedback]);
+ slot2_output = wavetable[slot2->waveform][((slot2->stepptr + phase_mod) >> 16) & SIN_MASK];
+ slot2_output = (slot2_output * env2) >> 16;
+
+ slot1->feedback_modulation1 = (((slot2_output << (SIN_BITS-2)) * feedback_level[slot1->feedback]) / 16);
+
+ slot1->stepptr += slot1->step;
+ slot2->stepptr += slot2->step;
+
+ return slot2_output;
+}
+
+// calculates the output of one FM operator
+INLINE INT32 calculate_1op_fm_0(YMF271Chip *chip, int slotnum, int phase_modulation)
+{
+ YMF271Slot *slot = &chip->slots[slotnum];
+ INT64 env;
+ INT64 slot_output;
+ INT64 phase_mod = phase_modulation;
+
+ update_envelope(slot);
+ update_lfo(slot);
+ env = calculate_slot_volume(slot);
+
+ phase_mod = ((phase_mod << (SIN_BITS-2)) * modulation_level[slot->feedback]);
+
+ slot_output = wavetable[slot->waveform][((slot->stepptr + phase_mod) >> 16) & SIN_MASK];
+ slot->stepptr += slot->step;
+
+ slot_output = (slot_output * env) >> 16;
+
+ return slot_output;
+}
+
+// calculates the output of one FM operator with feedback modulation
+// <--------|
+// +--[S1]--|
+INLINE INT32 calculate_1op_fm_1(YMF271Chip *chip, int slotnum)
+{
+ YMF271Slot *slot = &chip->slots[slotnum];
+ INT64 env;
+ INT64 slot_output;
+ INT64 feedback;
+
+ update_envelope(slot);
+ update_lfo(slot);
+ env = calculate_slot_volume(slot);
+
+ feedback = slot->feedback_modulation0 + slot->feedback_modulation1;
+ slot->feedback_modulation0 = slot->feedback_modulation1;
+
+ slot_output = wavetable[slot->waveform][((slot->stepptr + feedback) >> 16) & SIN_MASK];
+ slot_output = (slot_output * env) >> 16;
+
+ slot->feedback_modulation1 = (((slot_output << (SIN_BITS-2)) * feedback_level[slot->feedback]) / 16);
+ slot->stepptr += slot->step;
+
+ return slot_output;
+}
+
+static void ymf271_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length)
+{
+ int i, j;
+ int op;
+ INT32 *mixp;
+ YMF271Chip *chip = param;
+
+ memset(mix, 0, sizeof(mix[0])*length*2);
+
+ for (j = 0; j < 12; j++)
+ {
+ YMF271Group *slot_group = &chip->groups[j];
+ mixp = &mix[0];
+
+ if (slot_group->pfm && slot_group->sync != 3)
+ {
+ mame_printf_debug("Group %d: PFM, Sync = %d, Waveform Slot1 = %d, Slot2 = %d, Slot3 = %d, Slot4 = %d\n",
+ j, slot_group->sync, chip->slots[j+0].waveform, chip->slots[j+12].waveform, chip->slots[j+24].waveform, chip->slots[j+36].waveform);
+ }
+
+ switch (slot_group->sync)
+ {
+ case 0: // 4 operator FM
+ {
+ int slot1 = j + (0*12);
+ int slot2 = j + (1*12);
+ int slot3 = j + (2*12);
+ int slot4 = j + (3*12);
+ mixp = &mix[0];
+
+ if (chip->slots[slot1].active)
+ {
+ for (i = 0; i < length; i++)
+ {
+ INT64 output1 = 0, output2 = 0, output3 = 0, output4 = 0, phase_mod1 = 0, phase_mod2 = 0;
+ switch (chip->slots[slot1].algorithm)
+ {
+ // <--------|
+ // +--[S1]--+--[S3]--+--[S2]--+--[S4]-->
+ case 0:
+ phase_mod1 = calculate_2op_fm_0(chip, slot1, slot3);
+ phase_mod2 = calculate_1op_fm_0(chip, slot2, phase_mod1);
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod2);
+ break;
+
+ // <-----------------|
+ // +--[S1]--+--[S3]--+--[S2]--+--[S4]-->
+ case 1:
+ phase_mod1 = calculate_2op_fm_1(chip, slot1, slot3);
+ phase_mod2 = calculate_1op_fm_0(chip, slot2, phase_mod1);
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod2);
+ break;
+
+ // <--------|
+ // +--[S1]--|
+ // ---[S3]--+--[S2]--+--[S4]-->
+ case 2:
+ phase_mod1 = (calculate_1op_fm_1(chip, slot1) + calculate_1op_fm_0(chip, slot3, 0)) / 2;
+ phase_mod2 = calculate_1op_fm_0(chip, slot2, phase_mod1);
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod2);
+ break;
+
+ // <--------|
+ // +--[S1]--|
+ // ---[S3]--+--[S2]--+--[S4]-->
+ case 3:
+ phase_mod1 = calculate_1op_fm_0(chip, slot3, 0);
+ phase_mod2 = (calculate_1op_fm_0(chip, slot2, phase_mod1) + calculate_1op_fm_1(chip, slot1)) / 2;
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod2);
+ break;
+
+ // <--------| --[S2]--|
+ // ---[S1]--|-+--[S3]--+--[S4]-->
+ case 4:
+ phase_mod1 = (calculate_2op_fm_0(chip, slot1, slot3) + calculate_1op_fm_0(chip, slot2, 0)) / 2;
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod1);
+ break;
+
+ // --[S2]-----|
+ // <-----------------| |
+ // ---[S1]--+--[S3]--|--+--[S4]-->
+ case 5:
+ phase_mod1 = (calculate_2op_fm_1(chip, slot1, slot3) + calculate_1op_fm_0(chip, slot2, 0)) / 2;
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod1);
+ break;
+
+ // ---[S2]-----+--[S4]--|
+ // |
+ // <--------| |
+ // +--[S1]--|--+--[S3]--+-->
+ case 6:
+ output3 = calculate_2op_fm_0(chip, slot1, slot3);
+ phase_mod1 = calculate_1op_fm_0(chip, slot2, 0);
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod1);
+ break;
+
+ // ---[S2]--+--[S4]-----|
+ // |
+ // <-----------------| |
+ // +--[S1]--+--[S3]--|--+-->
+ case 7:
+ output3 = calculate_2op_fm_1(chip, slot1, slot3);
+ phase_mod1 = calculate_1op_fm_0(chip, slot2, 0);
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod1);
+ break;
+
+ // ---[S3]--+--[S2]--+--[S4]--|
+ // |
+ // <--------| |
+ // +--[S1]--|-----------------+-->
+ case 8:
+ output1 = calculate_1op_fm_1(chip, slot1);
+ phase_mod1 = calculate_1op_fm_0(chip, slot3, 0);
+ phase_mod2 = calculate_1op_fm_0(chip, slot2, phase_mod1);
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod2);
+ break;
+
+ // <--------|
+ // -----------[S1]--|
+ // |
+ // --[S3]--| |
+ // --[S2]--+--[S4]--+-->
+ case 9:
+ phase_mod1 = (calculate_1op_fm_0(chip, slot2, 0) + calculate_1op_fm_0(chip, slot3, 0)) / 2;
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod1);
+ output1 = calculate_1op_fm_1(chip, slot1);
+ break;
+
+ // --[S4]--|
+ // --[S2]--+
+ // <--------| |
+ // +--[S1]--+--[S3]--+-->
+ case 10:
+ output3 = calculate_2op_fm_0(chip, slot1, slot3);
+ output2 = calculate_1op_fm_0(chip, slot2, 0);
+ output4 = calculate_1op_fm_0(chip, slot4, 0);
+ break;
+
+ // --[S4]-----|
+ // --[S2]-----+
+ // <-----------------| |
+ // +--[S1]--+--[S3]--|--+-->
+ case 11:
+ output3 = calculate_2op_fm_1(chip, slot1, slot3);
+ output2 = calculate_1op_fm_0(chip, slot2, 0);
+ output4 = calculate_1op_fm_0(chip, slot4, 0);
+ break;
+
+ // |--+--[S4]--+
+ // <--------| |--+--[S3]--+
+ // +--[S1]--+-|--+--[S2]--+-->
+ case 12:
+ phase_mod1 = calculate_1op_fm_1(chip, slot1);
+ output2 = calculate_1op_fm_0(chip, slot2, phase_mod1);
+ output3 = calculate_1op_fm_0(chip, slot3, phase_mod1);
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod1);
+ break;
+
+ // ---[S3]--+--[S2]--+
+ // |
+ // ---[S4]-----------+
+ // <--------| |
+ // +--[S1]--|--------+-->
+ case 13:
+ output1 = calculate_1op_fm_1(chip, slot1);
+ phase_mod1 = calculate_1op_fm_0(chip, slot3, 0);
+ output2 = calculate_1op_fm_0(chip, slot2, phase_mod1);
+ output4 = calculate_1op_fm_0(chip, slot4, 0);
+ break;
+
+ // ---[S2]----+--[S4]--+
+ // |
+ // <--------| +--[S3]--|
+ // +--[S1]--+-|--------+-->
+ case 14:
+ output1 = calculate_1op_fm_1(chip, slot1);
+ phase_mod1 = output1;
+ output3 = calculate_1op_fm_0(chip, slot3, phase_mod1);
+ phase_mod2 = calculate_1op_fm_0(chip, slot2, 0);
+ output4 = calculate_1op_fm_0(chip, slot4, phase_mod2);
+ break;
+
+ // --[S4]-----+
+ // --[S2]-----+
+ // --[S3]-----+
+ // <--------| |
+ // +--[S1]--|--+-->
+ case 15:
+ output1 = calculate_1op_fm_1(chip, slot1);
+ output2 = calculate_1op_fm_0(chip, slot2, 0);
+ output3 = calculate_1op_fm_0(chip, slot3, 0);
+ output4 = calculate_1op_fm_0(chip, slot4, 0);
+ break;
+ }
+
+ *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch0_level]) +
+ (output2 * channel_attenuation[chip->slots[slot2].ch0_level]) +
+ (output3 * channel_attenuation[chip->slots[slot3].ch0_level]) +
+ (output4 * channel_attenuation[chip->slots[slot4].ch0_level])) >> 16;
+ *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch1_level]) +
+ (output2 * channel_attenuation[chip->slots[slot2].ch1_level]) +
+ (output3 * channel_attenuation[chip->slots[slot3].ch1_level]) +
+ (output4 * channel_attenuation[chip->slots[slot4].ch1_level])) >> 16;
+ }
+ }
+ break;
+ }
+
+ case 1: // 2x 2 operator FM
+ {
+ for (op = 0; op < 2; op++)
+ {
+ int slot1 = j + ((op + 0) * 12);
+ int slot2 = j + ((op + 2) * 12);
+
+ mixp = &mix[0];
+ if (chip->slots[slot1].active)
+ {
+ for (i = 0; i < length; i++)
+ {
+ INT64 output1 = 0, output2 = 0, phase_mod = 0;
+ switch (chip->slots[slot1].algorithm & 3)
+ {
+ // <--------|
+ // +--[S1]--+--[S3]-->
+ case 0:
+ output2 = calculate_2op_fm_0(chip, slot1, slot2);
+ break;
+
+ // <-----------------|
+ // +--[S1]--+--[S3]--|-->
+ case 1:
+ output2 = calculate_2op_fm_1(chip, slot1, slot2);
+ break;
+
+ // ---[S3]-----|
+ // <--------| |
+ // +--[S1]--|--+-->
+ case 2:
+ output1 = calculate_1op_fm_1(chip, slot1);
+ output2 = calculate_1op_fm_0(chip, slot2, 0);
+ break;
+ //
+ // <--------| +--[S3]--|
+ // +--[S1]--|-|--------+-->
+ case 3:
+ output1 = calculate_1op_fm_1(chip, slot1);
+ phase_mod = output1;
+ output2 = calculate_1op_fm_0(chip, slot2, phase_mod);
+ break;
+ }
+
+ *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch0_level]) +
+ (output2 * channel_attenuation[chip->slots[slot2].ch0_level])) >> 16;
+ *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch1_level]) +
+ (output2 * channel_attenuation[chip->slots[slot2].ch1_level])) >> 16;
+ }
+ }
+ }
+ break;
+ }
+
+ case 2: // 3 operator FM + PCM
+ {
+ int slot1 = j + (0*12);
+ int slot2 = j + (1*12);
+ int slot3 = j + (2*12);
+ mixp = &mix[0];
+
+ if (chip->slots[slot1].active)
+ {
+ for (i = 0; i < length; i++)
+ {
+ INT64 output1 = 0, output2 = 0, output3 = 0, phase_mod = 0;
+ switch (chip->slots[slot1].algorithm & 7)
+ {
+ // <--------|
+ // +--[S1]--+--[S3]--+--[S2]-->
+ case 0:
+ phase_mod = calculate_2op_fm_0(chip, slot1, slot3);
+ output2 = calculate_1op_fm_0(chip, slot2, phase_mod);
+ break;
+
+ // <-----------------|
+ // +--[S1]--+--[S3]--+--[S2]-->
+ case 1:
+ phase_mod = calculate_2op_fm_1(chip, slot1, slot3);
+ output2 = calculate_1op_fm_0(chip, slot2, phase_mod);
+ break;
+
+ // ---[S3]-----|
+ // <--------| |
+ // +--[S1]--+--+--[S2]-->
+ case 2:
+ phase_mod = (calculate_1op_fm_1(chip, slot1) + calculate_1op_fm_0(chip, slot3, 0)) / 2;
+ output2 = calculate_1op_fm_0(chip, slot2, phase_mod);
+ break;
+
+ // ---[S3]--+--[S2]--|
+ // <--------| |
+ // +--[S1]--|--------+-->
+ case 3:
+ phase_mod = calculate_1op_fm_0(chip, slot3, 0);
+ output2 = calculate_1op_fm_0(chip, slot2, phase_mod);
+ output1 = calculate_1op_fm_1(chip, slot1);
+ break;
+
+ // ------------[S2]--|
+ // <--------| |
+ // +--[S1]--+--[S3]--+-->
+ case 4:
+ output3 = calculate_2op_fm_0(chip, slot1, slot3);
+ output2 = calculate_1op_fm_0(chip, slot2, 0);
+ break;
+
+ // ------------[S2]--|
+ // <-----------------|
+ // +--[S1]--+--[S3]--+-->
+ case 5:
+ output3 = calculate_2op_fm_1(chip, slot1, slot3);
+ output2 = calculate_1op_fm_0(chip, slot2, 0);
+ break;
+
+ // ---[S2]-----|
+ // ---[S3]-----+
+ // <--------| |
+ // +--[S1]--+--+-->
+ case 6:
+ output1 = calculate_1op_fm_1(chip, slot1);
+ output3 = calculate_1op_fm_0(chip, slot3, 0);
+ output2 = calculate_1op_fm_0(chip, slot2, 0);
+ break;
+
+ // --------------[S2]--+
+ // <--------| +--[S3]--|
+ // +--[S1]--+-|--------+-->
+ case 7:
+ output1 = calculate_1op_fm_1(chip, slot1);
+ phase_mod = output1;
+ output3 = calculate_1op_fm_0(chip, slot3, phase_mod);
+ output2 = calculate_1op_fm_0(chip, slot2, 0);
+ break;
+ }
+
+ *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch0_level]) +
+ (output2 * channel_attenuation[chip->slots[slot2].ch0_level]) +
+ (output3 * channel_attenuation[chip->slots[slot3].ch0_level])) >> 16;
+ *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch1_level]) +
+ (output2 * channel_attenuation[chip->slots[slot2].ch1_level]) +
+ (output3 * channel_attenuation[chip->slots[slot3].ch1_level])) >> 16;
+ }
+ }
+
+ update_pcm(chip, j + (3*12), mixp, length);
+ break;
+ }
+
+ case 3: // PCM
+ {
+ update_pcm(chip, j + (0*12), mixp, length);
+ update_pcm(chip, j + (1*12), mixp, length);
+ update_pcm(chip, j + (2*12), mixp, length);
+ update_pcm(chip, j + (3*12), mixp, length);
+ break;
+ }
+
+ default: break;
+ }
+ }
+
+ mixp = &mix[0];
+ for (i = 0; i < length; i++)
+ {
+ outputs[0][i] = (*mixp++)>>2;
+ outputs[1][i] = (*mixp++)>>2;
+ }
+}
+
+static void write_register(YMF271Chip *chip, int slotnum, int reg, int data)
+{
+ YMF271Slot *slot = &chip->slots[slotnum];
+
+ switch (reg)
+ {
+ case 0:
+ {
+ slot->extout = (data>>3)&0xf;
+
+ if (data & 1)
+ {
+ // key on
+ slot->step = 0;
+ slot->stepptr = 0;
+
+ slot->active = 1;
+
+ calculate_step(slot);
+ init_envelope(slot);
+ init_lfo(slot);
+ slot->feedback_modulation0 = 0;
+ slot->feedback_modulation1 = 0;
+ }
+ else
+ {
+ if (slot->active)
+ {
+ //slot->active = 0;
+ slot->env_state = ENV_RELEASE;
+ }
+ }
+ break;
+ }
+
+ case 1:
+ {
+ slot->lfoFreq = data;
+ break;
+ }
+
+ case 2:
+ {
+ slot->lfowave = data & 3;
+ slot->pms = (data >> 3) & 0x7;
+ slot->ams = (data >> 6) & 0x3;
+ break;
+ }
+
+ case 3:
+ {
+ slot->multiple = data & 0xf;
+ slot->detune = (data >> 4) & 0x7;
+ break;
+ }
+
+ case 4:
+ {
+ slot->tl = data & 0x7f;
+ break;
+ }
+
+ case 5:
+ {
+ slot->ar = data & 0x1f;
+ slot->keyscale = (data>>5)&0x7;
+ break;
+ }
+
+ case 6:
+ {
+ slot->decay1rate = data & 0x1f;
+ break;
+ }
+
+ case 7:
+ {
+ slot->decay2rate = data & 0x1f;
+ break;
+ }
+
+ case 8:
+ {
+ slot->relrate = data & 0xf;
+ slot->decay1lvl = (data >> 4) & 0xf;
+ break;
+ }
+
+ case 9:
+ {
+ slot->fns &= ~0xff;
+ slot->fns |= data;
+
+ calculate_step(slot);
+ break;
+ }
+
+ case 10:
+ {
+ slot->fns &= ~0xff00;
+ slot->fns |= (data & 0xf)<<8;
+ slot->block = (data>>4)&0xf;
+ break;
+ }
+
+ case 11:
+ {
+ slot->waveform = data & 0x7;
+ slot->feedback = (data >> 4) & 0x7;
+ slot->accon = (data & 0x80) ? 1 : 0;
+ break;
+ }
+
+ case 12:
+ {
+ slot->algorithm = data & 0xf;
+ break;
+ }
+
+ case 13:
+ {
+ slot->ch0_level = data >> 4;
+ slot->ch1_level = data & 0xf;
+ break;
+ }
+
+ case 14:
+ {
+ slot->ch2_level = data >> 4;
+ slot->ch3_level = data & 0xf;
+ break;
+ }
+ }
+}
+
+static void ymf271_write_fm(YMF271Chip *chip, int grp, int adr, int data)
+{
+ int reg;
+ int slotnum;
+ int slot_group;
+ int sync_mode, sync_reg;
+ YMF271Slot *slot;
+
+ slotnum = 12*grp;
+ slotnum += fm_tab[adr & 0xf];
+ slot = &chip->slots[slotnum];
+ slot_group = fm_tab[adr & 0xf];
+
+ reg = (adr >> 4) & 0xf;
+
+ // check if the register is a synchronized register
+ sync_reg = 0;
+ switch (reg)
+ {
+ case 0:
+ case 9:
+ case 10:
+ case 12:
+ case 13:
+ case 14:
+ sync_reg = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ // check if the slot is key on slot for synchronizing
+ sync_mode = 0;
+ switch (chip->groups[slot_group].sync)
+ {
+ case 0: // 4 slot mode
+ {
+ if (grp == 0)
+ sync_mode = 1;
+ break;
+ }
+ case 1: // 2x 2 slot mode
+ {
+ if (grp == 0 || grp == 1)
+ sync_mode = 1;
+ break;
+ }
+ case 2: // 3 slot + 1 slot mode
+ {
+ if (grp == 0)
+ sync_mode = 1;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (sync_mode && sync_reg) // key-on slot & synced register
+ {
+ switch (chip->groups[slot_group].sync)
+ {
+ case 0: // 4 slot mode
+ {
+ write_register(chip, (12 * 0) + slot_group, reg, data);
+ write_register(chip, (12 * 1) + slot_group, reg, data);
+ write_register(chip, (12 * 2) + slot_group, reg, data);
+ write_register(chip, (12 * 3) + slot_group, reg, data);
+ break;
+ }
+ case 1: // 2x 2 slot mode
+ {
+ if (grp == 0) // Slot 1 - Slot 3
+ {
+ write_register(chip, (12 * 0) + slot_group, reg, data);
+ write_register(chip, (12 * 2) + slot_group, reg, data);
+ }
+ else // Slot 2 - Slot 4
+ {
+ write_register(chip, (12 * 1) + slot_group, reg, data);
+ write_register(chip, (12 * 3) + slot_group, reg, data);
+ }
+ break;
+ }
+ case 2: // 3 slot + 1 slot mode
+ {
+ // 1 slot is handled normally
+ write_register(chip, (12 * 0) + slot_group, reg, data);
+ write_register(chip, (12 * 1) + slot_group, reg, data);
+ write_register(chip, (12 * 2) + slot_group, reg, data);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else // write register normally
+ {
+ write_register(chip, (12 * grp) + slot_group, reg, data);
+ }
+}
+
+static void ymf271_write_pcm(YMF271Chip *chip, int data)
+{
+ int slotnum;
+ YMF271Slot *slot;
+
+ slotnum = pcm_tab[chip->pcmreg&0xf];
+ slot = &chip->slots[slotnum];
+
+ switch ((chip->pcmreg>>4)&0xf)
+ {
+ case 0:
+ slot->startaddr &= ~0xff;
+ slot->startaddr |= data;
+ break;
+ case 1:
+ slot->startaddr &= ~0xff00;
+ slot->startaddr |= data<<8;
+ break;
+ case 2:
+ slot->startaddr &= ~0xff0000;
+ slot->startaddr |= data<<16;
+ break;
+ case 3:
+ slot->endaddr &= ~0xff;
+ slot->endaddr |= data;
+ break;
+ case 4:
+ slot->endaddr &= ~0xff00;
+ slot->endaddr |= data<<8;
+ break;
+ case 5:
+ slot->endaddr &= ~0xff0000;
+ slot->endaddr |= data<<16;
+ break;
+ case 6:
+ slot->loopaddr &= ~0xff;
+ slot->loopaddr |= data;
+ break;
+ case 7:
+ slot->loopaddr &= ~0xff00;
+ slot->loopaddr |= data<<8;
+ break;
+ case 8:
+ slot->loopaddr &= ~0xff0000;
+ slot->loopaddr |= data<<16;
+ break;
+ case 9:
+ slot->fs = data & 0x3;
+ slot->bits = (data & 0x4) ? 12 : 8;
+ slot->srcnote = (data >> 3) & 0x3;
+ slot->srcb = (data >> 5) & 0x7;
+ break;
+ }
+}
+
+static TIMER_CALLBACK_PTR( ymf271_timer_a_tick )
+{
+ YMF271Chip *chip = param;
+
+ chip->status |= 1;
+
+ if (chip->enable & 4)
+ {
+ chip->irqstate |= 1;
+ if (chip->irq_callback) chip->irq_callback(1);
+ }
+}
+
+static TIMER_CALLBACK_PTR( ymf271_timer_b_tick )
+{
+ YMF271Chip *chip = param;
+
+ chip->status |= 2;
+
+ if (chip->enable & 8)
+ {
+ chip->irqstate |= 2;
+ if (chip->irq_callback) chip->irq_callback(1);
+ }
+}
+
+static UINT8 ymf271_read_ext_memory(YMF271Chip *chip, UINT32 address)
+{
+ if( chip->ext_mem_read ) {
+ return chip->ext_mem_read(address);
+ } else {
+ if( address < 0x800000)
+ return chip->rom[address];
+ }
+ return 0xff;
+}
+
+static void ymf271_write_ext_memory(YMF271Chip *chip, UINT32 address, UINT8 data)
+{
+ if( chip->ext_mem_write ) {
+ chip->ext_mem_write(address, data);
+ }
+}
+
+static void ymf271_write_timer(YMF271Chip *chip, int data)
+{
+ int slotnum;
+ YMF271Group *group;
+ attotime period;
+
+ slotnum = fm_tab[chip->timerreg & 0xf];
+ group = &chip->groups[slotnum];
+
+ if ((chip->timerreg & 0xf0) == 0)
+ {
+ group->sync = data & 0x3;
+ group->pfm = data >> 7;
+ }
+ else
+ {
+ switch (chip->timerreg)
+ {
+ case 0x10:
+ chip->timerA &= ~0xff;
+ chip->timerA |= data;
+ break;
+
+ case 0x11:
+ if (!(data & 0xfc))
+ {
+ chip->timerA &= 0x00ff;
+ if ((data & 0x3) != 0x3)
+ {
+ chip->timerA |= (data & 0xff)<<8;
+ }
+ }
+ break;
+
+ case 0x12:
+ chip->timerB = data;
+ break;
+
+ case 0x13:
+ if (data & 1)
+ { // timer A load
+ chip->timerAVal = chip->timerA;
+ }
+ if (data & 2)
+ { // timer B load
+ chip->timerBVal = chip->timerB;
+ }
+ if (data & 4)
+ {
+ // timer A IRQ enable
+ chip->enable |= 4;
+ }
+ if (data & 8)
+ {
+ // timer B IRQ enable
+ chip->enable |= 8;
+ }
+ if (data & 0x10)
+ { // timer A reset
+ chip->irqstate &= ~1;
+ chip->status &= ~1;
+
+ if (chip->irq_callback) chip->irq_callback(0);
+
+ //period = (double)(256.0 - chip->timerAVal ) * ( 384.0 * 4.0 / (double)CLOCK);
+ period = attotime_mul(ATTOTIME_IN_HZ(chip->clock), 384 * (1024 - chip->timerAVal));
+
+ timer_adjust_ptr(chip->timA, period, period);
+ }
+ if (data & 0x20)
+ { // timer B reset
+ chip->irqstate &= ~2;
+ chip->status &= ~2;
+
+ if (chip->irq_callback) chip->irq_callback(0);
+
+ period = attotime_mul(ATTOTIME_IN_HZ(chip->clock), 384 * 16 * (256 - chip->timerBVal));
+
+ timer_adjust_ptr(chip->timB, period, period);
+ }
+
+ break;
+
+ case 0x14:
+ chip->ext_address &= ~0xff;
+ chip->ext_address |= data;
+ break;
+ case 0x15:
+ chip->ext_address &= ~0xff00;
+ chip->ext_address |= data << 8;
+ break;
+ case 0x16:
+ chip->ext_address &= ~0xff0000;
+ chip->ext_address |= (data & 0x7f) << 16;
+ chip->ext_read = (data & 0x80) ? 1 : 0;
+ if( !chip->ext_read )
+ chip->ext_address = (chip->ext_address + 1) & 0x7fffff;
+ break;
+ case 0x17:
+ ymf271_write_ext_memory( chip, chip->ext_address, data );
+ chip->ext_address = (chip->ext_address + 1) & 0x7fffff;
+ break;
+ }
+ }
+}
+
+static void ymf271_w(int chipnum, int offset, int data)
+{
+ YMF271Chip *chip = sndti_token(SOUND_YMF271, chipnum);
+
+ switch (offset)
+ {
+ case 0:
+ chip->reg0 = data;
+ break;
+ case 1:
+ ymf271_write_fm(chip, 0, chip->reg0, data);
+ break;
+ case 2:
+ chip->reg1 = data;
+ break;
+ case 3:
+ ymf271_write_fm(chip, 1, chip->reg1, data);
+ break;
+ case 4:
+ chip->reg2 = data;
+ break;
+ case 5:
+ ymf271_write_fm(chip, 2, chip->reg2, data);
+ break;
+ case 6:
+ chip->reg3 = data;
+ break;
+ case 7:
+ ymf271_write_fm(chip, 3, chip->reg3, data);
+ break;
+ case 8:
+ chip->pcmreg = data;
+ break;
+ case 9:
+ ymf271_write_pcm(chip, data);
+ break;
+ case 0xc:
+ chip->timerreg = data;
+ break;
+ case 0xd:
+ ymf271_write_timer(chip, data);
+ break;
+ }
+}
+
+static int ymf271_r(int chipnum, int offset)
+{
+ UINT8 value;
+ YMF271Chip *chip = sndti_token(SOUND_YMF271, chipnum);
+
+ switch(offset)
+ {
+ case 0:
+ return chip->status;
+
+ case 2:
+ value = ymf271_read_ext_memory( chip, chip->ext_address );
+ chip->ext_address = (chip->ext_address + 1) & 0x7fffff;
+ return value;
+ }
+
+ return 0;
+}
+
+static void init_tables(void)
+{
+ int i,j;
+
+ for (i=0; i < ARRAY_LENGTH(wavetable); i++)
+ {
+ wavetable[i] = auto_malloc(SIN_LEN * sizeof(INT16));
+ }
+
+ for (i=0; i < SIN_LEN; i++)
+ {
+ double m = sin( ((i*2)+1) * M_PI / SIN_LEN );
+ double m2 = sin( ((i*4)+1) * M_PI / SIN_LEN );
+
+ // Waveform 0: sin(wt) (0 <= wt <= 2PI)
+ wavetable[0][i] = (INT16)(m * MAXOUT);
+
+ // Waveform 1: sin?(wt) (0 <= wt <= PI) -sin?(wt) (PI <= wt <= 2PI)
+ wavetable[1][i] = (i < (SIN_LEN/2)) ? (INT16)((m * m) * MAXOUT) : (INT16)((m * m) * MINOUT);
+
+ // Waveform 2: sin(wt) (0 <= wt <= PI) -sin(wt) (PI <= wt <= 2PI)
+ wavetable[2][i] = (i < (SIN_LEN/2)) ? (INT16)(m * MAXOUT) : (INT16)(-m * MAXOUT);
+
+ // Waveform 3: sin(wt) (0 <= wt <= PI) 0
+ wavetable[3][i] = (i < (SIN_LEN/2)) ? (INT16)(m * MAXOUT) : 0;
+
+ // Waveform 4: sin(2wt) (0 <= wt <= PI) 0
+ wavetable[4][i] = (i < (SIN_LEN/2)) ? (INT16)(m2 * MAXOUT) : 0;
+
+ // Waveform 5: |sin(2wt)| (0 <= wt <= PI) 0
+ wavetable[5][i] = (i < (SIN_LEN/2)) ? (INT16)(fabs(m2) * MAXOUT) : 0;
+
+ // Waveform 6: 1 (0 <= wt <= 2PI)
+ wavetable[6][i] = (INT16)(1 * MAXOUT);
+
+ wavetable[7][i] = 0;
+ }
+
+ for (i=0; i < LFO_LENGTH; i++)
+ {
+ int tri_wave;
+ double ftri_wave, fsaw_wave;
+ double plfo[4];
+
+ // LFO phase modulation
+ plfo[0] = 0;
+
+ fsaw_wave = ((i % (LFO_LENGTH/2)) * PLFO_MAX) / (double)((LFO_LENGTH/2)-1);
+ plfo[1] = (i < (LFO_LENGTH/2)) ? fsaw_wave : fsaw_wave - PLFO_MAX;
+
+ plfo[2] = (i < (LFO_LENGTH/2)) ? PLFO_MAX : PLFO_MIN;
+
+ ftri_wave = ((i % (LFO_LENGTH/4)) * PLFO_MAX) / (double)(LFO_LENGTH/4);
+ switch (i / (LFO_LENGTH/4))
+ {
+ case 0: plfo[3] = ftri_wave; break;
+ case 1: plfo[3] = PLFO_MAX - ftri_wave; break;
+ case 2: plfo[3] = 0 - ftri_wave; break;
+ case 3: plfo[3] = 0 - (PLFO_MAX - ftri_wave); break;
+ }
+
+ for (j=0; j < 4; j++)
+ {
+ plfo_table[j][0][i] = pow(2.0, 0.0);
+ plfo_table[j][1][i] = pow(2.0, (3.378 * plfo[j]) / 1200.0);
+ plfo_table[j][2][i] = pow(2.0, (5.0646 * plfo[j]) / 1200.0);
+ plfo_table[j][3][i] = pow(2.0, (6.7495 * plfo[j]) / 1200.0);
+ plfo_table[j][4][i] = pow(2.0, (10.1143 * plfo[j]) / 1200.0);
+ plfo_table[j][5][i] = pow(2.0, (20.1699 * plfo[j]) / 1200.0);
+ plfo_table[j][6][i] = pow(2.0, (40.1076 * plfo[j]) / 1200.0);
+ plfo_table[j][7][i] = pow(2.0, (79.307 * plfo[j]) / 1200.0);
+ }
+
+ // LFO amplitude modulation
+ alfo_table[0][i] = 0;
+
+ alfo_table[1][i] = ALFO_MAX - ((i * ALFO_MAX) / LFO_LENGTH);
+
+ alfo_table[2][i] = (i < (LFO_LENGTH/2)) ? ALFO_MAX : ALFO_MIN;
+
+ tri_wave = ((i % (LFO_LENGTH/2)) * ALFO_MAX) / (LFO_LENGTH/2);
+ alfo_table[3][i] = (i < (LFO_LENGTH/2)) ? ALFO_MAX-tri_wave : tri_wave;
+ }
+
+ mix = auto_malloc(48000*2*sizeof(*mix));
+}
+
+static void init_state(YMF271Chip *chip)
+{
+ int i, instance;
+
+ for (i = 0; i < sizeof(chip->slots) / sizeof(chip->slots[0]); i++)
+ {
+ instance = chip->index * (sizeof(chip->slots) / sizeof(chip->slots[0])) + i;
+
+ state_save_register_item("ymf271", instance, chip->slots[i].extout);
+ state_save_register_item("ymf271", instance, chip->slots[i].lfoFreq);
+ state_save_register_item("ymf271", instance, chip->slots[i].pms);
+ state_save_register_item("ymf271", instance, chip->slots[i].ams);
+ state_save_register_item("ymf271", instance, chip->slots[i].detune);
+ state_save_register_item("ymf271", instance, chip->slots[i].multiple);
+ state_save_register_item("ymf271", instance, chip->slots[i].tl);
+ state_save_register_item("ymf271", instance, chip->slots[i].keyscale);
+ state_save_register_item("ymf271", instance, chip->slots[i].ar);
+ state_save_register_item("ymf271", instance, chip->slots[i].decay1rate);
+ state_save_register_item("ymf271", instance, chip->slots[i].decay2rate);
+ state_save_register_item("ymf271", instance, chip->slots[i].decay1lvl);
+ state_save_register_item("ymf271", instance, chip->slots[i].relrate);
+ state_save_register_item("ymf271", instance, chip->slots[i].fns);
+ state_save_register_item("ymf271", instance, chip->slots[i].block);
+ state_save_register_item("ymf271", instance, chip->slots[i].feedback);
+ state_save_register_item("ymf271", instance, chip->slots[i].waveform);
+ state_save_register_item("ymf271", instance, chip->slots[i].accon);
+ state_save_register_item("ymf271", instance, chip->slots[i].algorithm);
+ state_save_register_item("ymf271", instance, chip->slots[i].ch0_level);
+ state_save_register_item("ymf271", instance, chip->slots[i].ch1_level);
+ state_save_register_item("ymf271", instance, chip->slots[i].ch2_level);
+ state_save_register_item("ymf271", instance, chip->slots[i].ch3_level);
+ state_save_register_item("ymf271", instance, chip->slots[i].startaddr);
+ state_save_register_item("ymf271", instance, chip->slots[i].loopaddr);
+ state_save_register_item("ymf271", instance, chip->slots[i].endaddr);
+ state_save_register_item("ymf271", instance, chip->slots[i].fs);
+ state_save_register_item("ymf271", instance, chip->slots[i].srcnote);
+ state_save_register_item("ymf271", instance, chip->slots[i].srcb);
+ state_save_register_item("ymf271", instance, chip->slots[i].step);
+ state_save_register_item("ymf271", instance, chip->slots[i].stepptr);
+ state_save_register_item("ymf271", instance, chip->slots[i].active);
+ state_save_register_item("ymf271", instance, chip->slots[i].bits);
+ state_save_register_item("ymf271", instance, chip->slots[i].volume);
+ state_save_register_item("ymf271", instance, chip->slots[i].env_state);
+ state_save_register_item("ymf271", instance, chip->slots[i].env_attack_step);
+ state_save_register_item("ymf271", instance, chip->slots[i].env_decay1_step);
+ state_save_register_item("ymf271", instance, chip->slots[i].env_decay2_step);
+ state_save_register_item("ymf271", instance, chip->slots[i].env_release_step);
+ state_save_register_item("ymf271", instance, chip->slots[i].feedback_modulation0);
+ state_save_register_item("ymf271", instance, chip->slots[i].feedback_modulation1);
+ state_save_register_item("ymf271", instance, chip->slots[i].lfo_phase);
+ state_save_register_item("ymf271", instance, chip->slots[i].lfo_step);
+ state_save_register_item("ymf271", instance, chip->slots[i].lfo_amplitude);
+ }
+
+ for (i = 0; i < sizeof(chip->groups) / sizeof(chip->groups[0]); i++)
+ {
+ instance = chip->index * (sizeof(chip->groups) / sizeof(chip->groups[0])) + i;
+ state_save_register_item("ymf271", instance, chip->groups[i].sync);
+ state_save_register_item("ymf271", instance, chip->groups[i].pfm);
+ }
+
+ state_save_register_item("ymf271", chip->index, chip->timerA);
+ state_save_register_item("ymf271", chip->index, chip->timerB);
+ state_save_register_item("ymf271", chip->index, chip->timerAVal);
+ state_save_register_item("ymf271", chip->index, chip->timerBVal);
+ state_save_register_item("ymf271", chip->index, chip->irqstate);
+ state_save_register_item("ymf271", chip->index, chip->status);
+ state_save_register_item("ymf271", chip->index, chip->enable);
+ state_save_register_item("ymf271", chip->index, chip->reg0);
+ state_save_register_item("ymf271", chip->index, chip->reg1);
+ state_save_register_item("ymf271", chip->index, chip->reg2);
+ state_save_register_item("ymf271", chip->index, chip->reg3);
+ state_save_register_item("ymf271", chip->index, chip->pcmreg);
+ state_save_register_item("ymf271", chip->index, chip->timerreg);
+ state_save_register_item("ymf271", chip->index, chip->ext_address);
+ state_save_register_item("ymf271", chip->index, chip->ext_read);
+}
+
+static void ymf271_init(YMF271Chip *chip, UINT8 *rom, void (*cb)(int), read8_handler ext_read, write8_handler ext_write)
+{
+ chip->timA = timer_alloc_ptr(ymf271_timer_a_tick, chip);
+ chip->timB = timer_alloc_ptr(ymf271_timer_b_tick, chip);
+
+ chip->rom = rom;
+ chip->irq_callback = cb;
+
+ chip->ext_mem_read = ext_read;
+ chip->ext_mem_write = ext_write;
+
+ init_tables();
+ init_state(chip);
+}
+
+static void *ymf271_start(int sndindex, int clock, const void *config)
+{
+ const struct YMF271interface *intf;
+ int i;
+ YMF271Chip *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+ chip->index = sndindex;
+ chip->clock = clock;
+
+ intf = config;
+
+ ymf271_init(chip, memory_region(intf->region), intf->irq_callback, intf->ext_read, intf->ext_write);
+ chip->stream = stream_create(0, 2, clock/384, chip, ymf271_update);
+
+ for (i = 0; i < 256; i++)
+ {
+ env_volume_table[i] = (int)(65536.0 / pow(10.0, ((double)i / (256.0 / 96.0)) / 20.0));
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ channel_attenuation[i] = (int)(65536.0 / pow(10.0, channel_attenuation_table[i] / 20.0));
+ }
+ for (i = 0; i < 128; i++)
+ {
+ double db = 0.75 * (double)i;
+ total_level[i] = (int)(65536.0 / pow(10.0, db / 20.0));
+ }
+
+ return chip;
+}
+
+READ8_HANDLER( YMF271_0_r )
+{
+ return ymf271_r(0, offset);
+}
+
+WRITE8_HANDLER( YMF271_0_w )
+{
+ ymf271_w(0, offset, data);
+}
+
+READ8_HANDLER( YMF271_1_r )
+{
+ return ymf271_r(1, offset);
+}
+
+WRITE8_HANDLER( YMF271_1_w )
+{
+ ymf271_w(1, offset, data);
+}
+
+static void ymf271_reset(void *token)
+{
+ int i;
+ YMF271Chip *chip = (YMF271Chip*)token;
+
+ for (i = 0; i < 48; i++)
+ {
+ chip->slots[i].active = 0;
+ chip->slots[i].volume = 0;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ymf271_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ymf271_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ymf271_set_info; break;
+ case SNDINFO_PTR_START: info->start = ymf271_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = ymf271_reset; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YMF271"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
diff --git a/src/emu/sound/ymf271.h b/src/emu/sound/ymf271.h
new file mode 100644
index 00000000000..c9375573dc6
--- /dev/null
+++ b/src/emu/sound/ymf271.h
@@ -0,0 +1,17 @@
+#ifndef _YMF271_H_
+#define _YMF271_H_
+
+struct YMF271interface
+{
+ int region; /* memory region of sample ROMs */
+ read8_handler ext_read; /* external memory read */
+ write8_handler ext_write; /* external memory write */
+ void (*irq_callback)(int state); /* irq callback */
+};
+
+READ8_HANDLER( YMF271_0_r );
+WRITE8_HANDLER( YMF271_0_w );
+READ8_HANDLER( YMF271_1_r );
+WRITE8_HANDLER( YMF271_1_w );
+
+#endif
diff --git a/src/emu/sound/ymf278b.c b/src/emu/sound/ymf278b.c
new file mode 100644
index 00000000000..a8ef72015f4
--- /dev/null
+++ b/src/emu/sound/ymf278b.c
@@ -0,0 +1,835 @@
+/*
+
+ YMF278B FM + Wave table Synthesizer (OPL4)
+
+ Timer and PCM YMF278B. The FM will be shared with the ymf262, eventually.
+
+ This chip roughly splits the difference between the Sega 315-5560 MultiPCM
+ (Multi32, Model 1/2) and YMF 292-F SCSP (later Model 2, STV, Saturn, Model 3).
+
+ Features as listed in LSI-4MF2782 data sheet:
+ FM Synthesis (same as YMF262)
+ 1. Sound generation mode
+ Two-operater mode
+ Generates eighteen voices or fifteen voices plus five rhythm sounds simultaneously
+ Four-operator mode
+ Generates six voices in four-operator mode plus six voices in two-operator mode simultaneously,
+ or generates six voices in four-operator mode plus three voices in two-operator mode plus five
+ rhythm sounds simultaneously
+ 2. Eight selectable waveforms
+ 3. Stereo output
+ Wave Table Synthesis
+ 1. Generates twenty-four voices simultaneously
+ 2. 44.1kHz sampling rate for output sound data
+ 3. Selectable from 8-bit, 12-bit and 16-bit word lengths for wave data
+ 4. Stereo output (16-stage panpot for each voice)
+ Wave Data
+ 1. Accepts 32M bit external memory at maximum
+ 2. Up to 512 wave tables
+ 3. External ROM or SRAM can be connected. With SRAM connected, the CPU can download wave data
+ 4. Outputs chip select signals for 1Mbit, 4Mbit, 8Mbit or 16Mbit memory
+ 5. Can be directly connected to the Yamaha YRW801 (Wave data ROM)
+ Features of YRW801 as listed in LSI 4RW801A2
+ Built-in wave data of tones which comply with GM system Level 1
+ Melody tone ....... 128 tones
+ Percussion tone ... 47 tones
+ 16Mbit capacity (2,097,152word x 8)
+
+ By R. Belmont and O. Galibert.
+
+ Copyright (c) 2002-2003 R. Belmont and O. Galibert.
+
+ This software is dual-licensed: it may be used in MAME and properly licensed
+ MAME derivatives under the terms of the MAME license. For use outside of
+ MAME and properly licensed derivatives, it is available under the
+ terms of the GNU Lesser General Public License (LGPL), version 2.1.
+ You may read the LGPL at http://www.gnu.org/licenses/lgpl.html
+
+ Changelog:
+ Sep. 8, 2002 - fixed ymf278b_compute_rate when OCT is negative (RB)
+ Dec. 11, 2002 - added ability to set non-standard clock rates (RB)
+ fixed envelope target for release (fixes missing
+ instruments in hotdebut).
+ Thanks to Team Japump! for MP3s from a real PCB.
+ fixed crash if MAME is run with no sound.
+ June 4, 2003 - Changed to dual-license with LGPL for use in OpenMSX.
+ OpenMSX contributed a bugfix where looped samples were
+ not being addressed properly, causing pitch fluctuation.
+*/
+
+#include <math.h>
+#include "sndintrf.h"
+#include "streams.h"
+#include "cpuintrf.h"
+#include "ymf278b.h"
+
+#undef VERBOSE
+
+typedef struct
+{
+ INT16 wave; /* wavetable number */
+ INT16 FN; /* f-number */
+ INT8 OCT; /* octave */
+ INT8 PRVB; /* pseudo-reverb */
+ INT8 LD; /* level direct */
+ INT8 TL; /* total level */
+ INT8 pan; /* panpot */
+ INT8 lfo; /* LFO */
+ INT8 vib; /* vibrato */
+ INT8 AM; /* AM level */
+
+ INT8 AR;
+ INT8 D1R;
+ INT8 DL;
+ INT8 D2R;
+ INT8 RC; /* rate correction */
+ INT8 RR;
+
+ UINT32 step; /* fixed-point frequency step */
+ UINT32 stepptr; /* fixed-point pointer into the sample */
+
+ INT8 active; /* slot keyed on */
+ INT8 bits; /* width of the samples */
+ UINT32 startaddr;
+ UINT32 loopaddr;
+ UINT32 endaddr;
+
+ int env_step;
+ UINT32 env_vol;
+ UINT32 env_vol_step;
+ UINT32 env_vol_lim;
+} YMF278BSlot;
+
+typedef struct
+{
+ YMF278BSlot slots[24];
+ INT8 lsitest0;
+ INT8 lsitest1;
+ INT8 wavetblhdr;
+ INT8 memmode;
+ INT32 memadr;
+
+ INT32 fm_l, fm_r;
+ INT32 pcm_l, pcm_r;
+
+ UINT8 timer_a_count, timer_b_count, enable, current_irq;
+ emu_timer *timer_a, *timer_b;
+ int irq_line;
+
+ UINT8 port_A, port_B, port_C;
+ void (*irq_callback)(int);
+
+ const UINT8 *rom;
+ int clock;
+
+ INT32 volume[256*4]; // precalculated attenuation values with some marging for enveloppe and pan levels
+ int pan_left[16], pan_right[16]; // pan volume offsets
+ INT32 mix_level[8];
+
+ sound_stream * stream;
+ int index;
+} YMF278BChip;
+
+static INT32 *mix;
+
+static int ymf278b_compute_rate(YMF278BSlot *slot, int val)
+{
+ int res, oct;
+
+ if(val == 0)
+ return 0;
+ if(val == 15)
+ return 63;
+ if(slot->RC != 15)
+ {
+ oct = slot->OCT;
+ if (oct & 8) oct |= -8;
+
+ res = (oct+slot->RC)*2 + (slot->FN & 0x200 ? 1 : 0) + val*4;
+ }
+ else
+ res = val * 4;
+ if(res < 0)
+ res = 0;
+ else if(res > 63)
+ res = 63;
+ return res;
+}
+
+static UINT32 ymf278_compute_decay_rate(int num)
+{
+ int samples;
+
+ if (num <= 3)
+ samples = 0;
+ else if (num >= 60)
+ samples = 15 << 4;
+ else
+ {
+ samples = (15 << (21 - num / 4)) / (4 + num % 4);
+ if (num % 4 && num / 4 <= 11)
+ samples += 2;
+ else if (num == 51)
+ samples += 2;
+ }
+
+ return samples;
+}
+
+static void ymf278b_envelope_next(YMF278BSlot *slot)
+{
+ if(slot->env_step == 0)
+ {
+ // Attack
+ slot->env_vol = (256U << 23) - 1;
+ slot->env_vol_lim = 256U<<23;
+#ifdef VERBOSE
+ logerror("YMF278B: Skipping attack (rate = %d)\n", slot->AR);
+#endif
+ slot->env_step++;
+ }
+ if(slot->env_step == 1)
+ {
+ // Decay 1
+ slot->env_vol = 0;
+ slot->env_step++;
+ if(slot->DL)
+ {
+ int rate = ymf278b_compute_rate(slot, slot->D1R);
+#ifdef VERBOSE
+ logerror("YMF278B: Decay step 1, dl=%d, val = %d rate = %d, delay = %g\n", slot->DL, slot->D1R, rate, ymf278_compute_decay_rate(rate)*1000.0);
+#endif
+ if(rate<4)
+ slot->env_vol_step = 0;
+ else
+ slot->env_vol_step = ((slot->DL*8)<<23) / ymf278_compute_decay_rate(rate);
+ slot->env_vol_lim = (slot->DL*8)<<23;
+ return;
+ }
+ }
+ if(slot->env_step == 2)
+ {
+ // Decay 2
+ int rate = ymf278b_compute_rate(slot, slot->D2R);
+#ifdef VERBOSE
+ logerror("YMF278B: Decay step 2, val = %d, rate = %d, delay = %g, current vol = %d\n", slot->D2R, rate, ymf278_compute_decay_rate(rate)*1000.0, slot->env_vol >> 23);
+#endif
+ if(rate<4)
+ slot->env_vol_step = 0;
+ else
+ slot->env_vol_step = ((256U-slot->DL*8)<<23) / ymf278_compute_decay_rate(rate);
+ slot->env_vol_lim = 256U<<23;
+ slot->env_step++;
+ return;
+ }
+ if(slot->env_step == 3)
+ {
+ // Decay 2 reached -96dB
+#ifdef VERBOSE
+ logerror("YMF278B: Voice cleared because of decay 2\n");
+#endif
+ slot->env_vol = 256U<<23;
+ slot->env_vol_step = 0;
+ slot->env_vol_lim = 0;
+ slot->active = 0;
+ return;
+ }
+ if(slot->env_step == 4)
+ {
+ // Release
+ int rate = ymf278b_compute_rate(slot, slot->RR);
+#ifdef VERBOSE
+ logerror("YMF278B: Release, val = %d, rate = %d, delay = %g\n", slot->RR, rate, ymf278_compute_decay_rate(rate)*1000.0);
+#endif
+ if(rate<4)
+ slot->env_vol_step = 0;
+ else
+ slot->env_vol_step = ((256U<<23)-slot->env_vol) / ymf278_compute_decay_rate(rate);
+ slot->env_vol_lim = 256U<<23;
+ slot->env_step++;
+ return;
+ }
+ if(slot->env_step == 5)
+ {
+ // Release reached -96dB
+#ifdef VERBOSE
+ logerror("YMF278B: Release ends\n");
+#endif
+ slot->env_vol = 256U<<23;
+ slot->env_vol_step = 0;
+ slot->env_vol_lim = 0;
+ slot->active = 0;
+ return;
+ }
+}
+
+static void ymf278b_pcm_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length)
+{
+ YMF278BChip *chip = param;
+ int i, j;
+ YMF278BSlot *slot = NULL;
+ INT16 sample = 0;
+ const UINT8 *rombase;
+ INT32 *mixp;
+ INT32 vl, vr;
+
+ memset(mix, 0, sizeof(mix[0])*length*2);
+
+ rombase = chip->rom;
+
+ for (i = 0; i < 24; i++)
+ {
+ slot = &chip->slots[i];
+
+ if (slot->active)
+ {
+ mixp = mix;
+
+ for (j = 0; j < length; j++)
+ {
+ switch (slot->bits)
+ {
+ case 8: // 8 bit
+ sample = rombase[slot->startaddr + (slot->stepptr>>16)]<<8;
+ break;
+
+ case 12: // 12 bit
+ if (slot->stepptr & 1)
+ sample = rombase[slot->startaddr + (slot->stepptr>>17)*3 + 2]<<8 | ((rombase[slot->startaddr + (slot->stepptr>>17)*3 + 1] << 4) & 0xf0);
+ else
+ sample = rombase[slot->startaddr + (slot->stepptr>>17)*3]<<8 | (rombase[slot->startaddr + (slot->stepptr>>17)*3 + 1] & 0xf0);
+ break;
+
+ case 16: // 16 bit
+ sample = rombase[slot->startaddr + ((slot->stepptr>>16)*2)]<<8;
+ sample |= rombase[slot->startaddr + ((slot->stepptr>>16)*2) + 1];
+ break;
+ }
+
+ *mixp++ += (sample * chip->volume[slot->TL+chip->pan_left [slot->pan]+(slot->env_vol>>23)])>>17;
+ *mixp++ += (sample * chip->volume[slot->TL+chip->pan_right[slot->pan]+(slot->env_vol>>23)])>>17;
+
+ // update frequency
+ slot->stepptr += slot->step;
+ if(slot->stepptr >= slot->endaddr)
+ {
+ slot->stepptr = slot->stepptr - slot->endaddr + slot->loopaddr;
+ // If the step is bigger than the loop, finish the sample forcibly
+ if(slot->stepptr >= slot->endaddr)
+ {
+ slot->env_vol = 256U<<23;
+ slot->env_vol_step = 0;
+ slot->env_vol_lim = 0;
+ slot->active = 0;
+ slot->stepptr = 0;
+ slot->step = 0;
+ }
+ }
+
+ // update envelope
+ slot->env_vol += slot->env_vol_step;
+ if(((INT32)(slot->env_vol - slot->env_vol_lim)) >= 0)
+ ymf278b_envelope_next(slot);
+ }
+ }
+ }
+
+ mixp = mix;
+ vl = chip->mix_level[chip->pcm_l];
+ vr = chip->mix_level[chip->pcm_r];
+ for (i = 0; i < length; i++)
+ {
+ outputs[0][i] = (*mixp++ * vl) >> 16;
+ outputs[1][i] = (*mixp++ * vr) >> 16;
+ }
+}
+
+static void ymf278b_irq_check(YMF278BChip *chip)
+{
+ int prev_line = chip->irq_line;
+ chip->irq_line = chip->current_irq ? ASSERT_LINE : CLEAR_LINE;
+ if(chip->irq_line != prev_line && chip->irq_callback)
+ chip->irq_callback(chip->irq_line);
+}
+
+static TIMER_CALLBACK_PTR( ymf278b_timer_a_tick )
+{
+ YMF278BChip *chip = param;
+ if(!(chip->enable & 0x40))
+ {
+ chip->current_irq |= 0x40;
+ ymf278b_irq_check(chip);
+ }
+}
+
+static TIMER_CALLBACK_PTR( ymf278b_timer_b_tick )
+{
+ YMF278BChip *chip = param;
+ if(!(chip->enable & 0x20))
+ {
+ chip->current_irq |= 0x20;
+ ymf278b_irq_check(chip);
+ }
+}
+
+static void ymf278b_timer_a_reset(YMF278BChip *chip)
+{
+ if(chip->enable & 1)
+ {
+ attotime period = ATTOTIME_IN_NSEC((256-chip->timer_a_count) * 80800);
+
+ if (chip->clock != YMF278B_STD_CLOCK)
+ period = attotime_div(attotime_mul(period, chip->clock), YMF278B_STD_CLOCK);
+
+ timer_adjust_ptr(chip->timer_a, period, period);
+ }
+ else
+ timer_adjust_ptr(chip->timer_a, attotime_never, attotime_zero);
+}
+
+static void ymf278b_timer_b_reset(YMF278BChip *chip)
+{
+ if(chip->enable & 2)
+ {
+ attotime period = ATTOTIME_IN_NSEC((256-chip->timer_b_count) * 323100);
+
+ if (chip->clock != YMF278B_STD_CLOCK)
+ period = attotime_div(attotime_mul(period, chip->clock), YMF278B_STD_CLOCK);
+
+ timer_adjust_ptr(chip->timer_a, period, period);
+ }
+ else
+ timer_adjust_ptr(chip->timer_b, attotime_never, attotime_zero);
+}
+
+static void ymf278b_A_w(YMF278BChip *chip, UINT8 reg, UINT8 data)
+{
+ switch(reg)
+ {
+ case 0x02:
+ chip->timer_a_count = data;
+ ymf278b_timer_a_reset(chip);
+ break;
+ case 0x03:
+ chip->timer_b_count = data;
+ ymf278b_timer_b_reset(chip);
+ break;
+ case 0x04:
+ if(data & 0x80)
+ chip->current_irq = 0;
+ else
+ {
+ UINT8 old_enable = chip->enable;
+ chip->enable = data;
+ chip->current_irq &= ~data;
+ if((old_enable ^ data) & 1)
+ ymf278b_timer_a_reset(chip);
+ if((old_enable ^ data) & 2)
+ ymf278b_timer_b_reset(chip);
+ }
+ ymf278b_irq_check(chip);
+ break;
+ default:
+ logerror("YMF278B: Port A write %02x, %02x\n", reg, data);
+ }
+}
+
+static void ymf278b_B_w(YMF278BChip *chip, UINT8 reg, UINT8 data)
+{
+ logerror("YMF278B: Port B write %02x, %02x\n", reg, data);
+}
+
+static void ymf278b_C_w(YMF278BChip *chip, UINT8 reg, UINT8 data)
+{
+ // Handle slot registers specifically
+ if (reg >= 0x08 && reg <= 0xf7)
+ {
+ YMF278BSlot *slot = NULL;
+ int snum;
+ snum = (reg-8) % 24;
+ slot = &chip->slots[snum];
+ switch((reg-8) / 24)
+ {
+ case 0:
+ {
+ const UINT8 *p;
+
+ slot->wave &= 0x100;
+ slot->wave |= data;
+
+ if(slot->wave < 384 || !chip->wavetblhdr)
+ p = chip->rom + (slot->wave * 12);
+ else
+ p = chip->rom + chip->wavetblhdr*0x80000 + ((slot->wave - 384) * 12);
+
+ switch (p[0]&0xc0)
+ {
+ case 0:
+ slot->bits = 8;
+ break;
+ case 0x40:
+ slot->bits = 12;
+ break;
+ case 0x80:
+ slot->bits = 16;
+ break;
+ }
+
+ slot->lfo = (p[7] >> 2) & 7;
+ slot->vib = p[7] & 7;
+ slot->AR = p[8] >> 4;
+ slot->D1R = p[8] & 0xf;
+ slot->DL = p[9] >> 4;
+ slot->D2R = p[9] & 0xf;
+ slot->RC = p[10] >> 4;
+ slot->RR = p[10] & 0xf;
+ slot->AM = p[11] & 7;
+
+ slot->startaddr = (p[2] | (p[1]<<8) | ((p[0]&0x3f)<<16));
+ slot->loopaddr = (p[4]<<16) | (p[3]<<24);
+ slot->endaddr = (p[6]<<16) | (p[5]<<24);
+ slot->endaddr -= 0x00010000U;
+ slot->endaddr ^= 0xffff0000U;
+ break;
+ }
+ case 1:
+ slot->wave &= 0xff;
+ slot->wave |= ((data&0x1)<<8);
+ slot->FN &= 0x380;
+ slot->FN |= (data>>1);
+ break;
+ case 2:
+ slot->FN &= 0x07f;
+ slot->FN |= ((data&0x07)<<7);
+ slot->PRVB = ((data&0x4)>>3);
+ slot->OCT = ((data&0xf0)>>4);
+ break;
+ case 3:
+ slot->TL = (data>>1);
+ slot->LD = data&0x1;
+ break;
+ case 4:
+ slot->pan = data&0xf;
+ if (data & 0x80)
+ {
+ unsigned int step;
+ int oct;
+
+ slot->active = 1;
+
+ oct = slot->OCT;
+ if(oct & 8)
+ oct |= -8;
+
+ slot->env_step = 0;
+ slot->env_vol = 256U<<23;
+ slot->env_vol_step = 0;
+ slot->env_vol_lim = 256U<<23;
+ slot->stepptr = 0;
+ slot->step = 0;
+
+ step = (slot->FN | 1024) << (oct + 7);
+ slot->step = step / 4;
+
+ ymf278b_envelope_next(slot);
+
+#ifdef VERBOSE
+ logerror("YMF278B: slot %2d wave %3d lfo=%d vib=%d ar=%d d1r=%d dl=%d d2r=%d rc=%d rr=%d am=%d\n", snum, slot->wave,
+ slot->lfo, slot->vib, slot->AR, slot->D1R, slot->DL, slot->D2R, slot->RC, slot->RR, slot->AM);
+ logerror(" b=%d, start=%x, loop=%x, end=%x, oct=%d, fn=%d, step=%x\n", slot->bits, slot->startaddr, slot->loopaddr>>16, slot->endaddr>>16, oct, slot->FN, slot->step);
+#endif
+ }
+ else
+ {
+#ifdef VERBOSE
+ logerror("YMF278B: slot %2d off\n", snum);
+#endif
+ if(slot->active)
+ {
+ slot->env_step = 4;
+ ymf278b_envelope_next(slot);
+ }
+ }
+ break;
+ case 5:
+ slot->vib = data&0x7;
+ slot->lfo = (data>>3)&0x7;
+ break;
+ case 6:
+ slot->AR = data>>4;
+ slot->D1R = data&0xf;
+ break;
+ case 7:
+ slot->DL = data>>4;
+ slot->D2R = data&0xf;
+ break;
+ case 8:
+ slot->RC = data>>4;
+ slot->RR = data&0xf;
+ break;
+ case 9:
+ slot->AM = data & 0x7;
+ break;
+ }
+ }
+ else
+ {
+ // All non-slot registers
+ switch (reg)
+ {
+ case 0x00: // TEST
+ case 0x01:
+ break;
+
+ case 0x02:
+ chip->wavetblhdr = (data>>2)&0x7;
+ chip->memmode = data&1;
+ break;
+
+ case 0x03:
+ chip->memadr &= 0xffff;
+ chip->memadr |= (data<<16);
+ break;
+
+ case 0x04:
+ chip->memadr &= 0xff00ff;
+ chip->memadr |= (data<<8);
+ break;
+
+ case 0x05:
+ chip->memadr &= 0xffff00;
+ chip->memadr |= data;
+ break;
+
+ case 0x06: // memory data (ignored, we don't support RAM)
+ case 0x07: // unused
+ break;
+
+ case 0xf8:
+ chip->fm_l = data & 0x7;
+ chip->fm_r = (data>>3)&0x7;
+ break;
+
+ case 0xf9:
+ chip->pcm_l = data & 0x7;
+ chip->pcm_r = (data>>3)&0x7;
+ break;
+ }
+ }
+}
+
+static UINT8 ymf278b_status_port_r(int num)
+{
+ YMF278BChip *chip = sndti_token(SOUND_YMF278B, num);
+ return chip->current_irq | (chip->irq_line == ASSERT_LINE ? 0x80 : 0x00);
+}
+
+// Not implemented yet
+static UINT8 ymf278b_data_port_r(int num)
+{
+ return 0;
+}
+
+static void ymf278b_control_port_A_w(int num, UINT8 data)
+{
+ YMF278BChip *chip = sndti_token(SOUND_YMF278B, num);
+ chip->port_A = data;
+}
+
+static void ymf278b_data_port_A_w(int num, UINT8 data)
+{
+ YMF278BChip *chip = sndti_token(SOUND_YMF278B, num);
+ ymf278b_A_w(chip, chip->port_A, data);
+}
+
+static void ymf278b_control_port_B_w(int num, UINT8 data)
+{
+ YMF278BChip *chip = sndti_token(SOUND_YMF278B, num);
+ chip->port_B = data;
+}
+
+static void ymf278b_data_port_B_w(int num, UINT8 data)
+{
+ YMF278BChip *chip = sndti_token(SOUND_YMF278B, num);
+ ymf278b_B_w(chip, chip->port_B, data);
+}
+
+static void ymf278b_control_port_C_w(int num, UINT8 data)
+{
+ YMF278BChip *chip = sndti_token(SOUND_YMF278B, num);
+ chip->port_C = data;
+}
+
+static void ymf278b_data_port_C_w(int num, UINT8 data)
+{
+ YMF278BChip *chip = sndti_token(SOUND_YMF278B, num);
+ ymf278b_C_w(chip, chip->port_C, data);
+}
+
+static void ymf278b_init(YMF278BChip *chip, UINT8 *rom, void (*cb)(int), int clock)
+{
+ chip->rom = rom;
+ chip->irq_callback = cb;
+ chip->timer_a = timer_alloc_ptr(ymf278b_timer_a_tick, chip);
+ chip->timer_b = timer_alloc_ptr(ymf278b_timer_b_tick, chip);
+ chip->irq_line = CLEAR_LINE;
+ chip->clock = clock;
+
+ mix = auto_malloc(44100*2*sizeof(*mix));
+}
+
+static void *ymf278b_start(int sndindex, int clock, const void *config)
+{
+ const struct YMF278B_interface *intf;
+ int i;
+ YMF278BChip *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+ chip->index = sndindex;
+
+ intf = config;
+
+ ymf278b_init(chip, memory_region(intf->region), intf->irq_callback, clock);
+ chip->stream = stream_create(0, 2, clock/768, chip, ymf278b_pcm_update);
+
+ // Volume table, 1 = -0.375dB, 8 = -3dB, 256 = -96dB
+ for(i = 0; i < 256; i++)
+ chip->volume[i] = 65536*pow(2.0, (-0.375/6)*i);
+ for(i = 256; i < 256*4; i++)
+ chip->volume[i] = 0;
+
+ // Pan values, units are -3dB, i.e. 8.
+ for(i = 0; i < 16; i++)
+ {
+ chip->pan_left[i] = i < 7 ? i*8 : i < 9 ? 256 : 0;
+ chip->pan_right[i] = i < 8 ? 0 : i < 10 ? 256 : (16-i)*8;
+ }
+
+ // Mixing levels, units are -3dB, and add some marging to avoid clipping
+ for(i=0; i<7; i++)
+ chip->mix_level[i] = chip->volume[8*i+8];
+ chip->mix_level[7] = 0;
+
+ return chip;
+}
+
+
+READ8_HANDLER( YMF278B_status_port_0_r )
+{
+ return ymf278b_status_port_r(0);
+}
+
+READ8_HANDLER( YMF278B_data_port_0_r )
+{
+ return ymf278b_data_port_r(0);
+}
+
+WRITE8_HANDLER( YMF278B_control_port_0_A_w )
+{
+ ymf278b_control_port_A_w(0, data);
+}
+
+WRITE8_HANDLER( YMF278B_data_port_0_A_w )
+{
+ ymf278b_data_port_A_w(0, data);
+}
+
+WRITE8_HANDLER( YMF278B_control_port_0_B_w )
+{
+ ymf278b_control_port_B_w(0, data);
+}
+
+WRITE8_HANDLER( YMF278B_data_port_0_B_w )
+{
+ ymf278b_data_port_B_w(0, data);
+}
+
+WRITE8_HANDLER( YMF278B_control_port_0_C_w )
+{
+ ymf278b_control_port_C_w(0, data);
+}
+
+WRITE8_HANDLER( YMF278B_data_port_0_C_w )
+{
+ ymf278b_data_port_C_w(0, data);
+}
+
+
+READ8_HANDLER( YMF278B_status_port_1_r )
+{
+ return ymf278b_status_port_r(1);
+}
+
+READ8_HANDLER( YMF278B_data_port_1_r )
+{
+ return ymf278b_data_port_r(1);
+}
+
+WRITE8_HANDLER( YMF278B_control_port_1_A_w )
+{
+ ymf278b_control_port_A_w(1, data);
+}
+
+WRITE8_HANDLER( YMF278B_data_port_1_A_w )
+{
+ ymf278b_data_port_A_w(1, data);
+}
+
+WRITE8_HANDLER( YMF278B_control_port_1_B_w )
+{
+ ymf278b_control_port_B_w(1, data);
+}
+
+WRITE8_HANDLER( YMF278B_data_port_1_B_w )
+{
+ ymf278b_data_port_B_w(1, data);
+}
+
+WRITE8_HANDLER( YMF278B_control_port_1_C_w )
+{
+ ymf278b_control_port_C_w(1, data);
+}
+
+WRITE8_HANDLER( YMF278B_data_port_1_C_w )
+{
+ ymf278b_data_port_C_w(1, data);
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ymf278b_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ymf278b_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ymf278b_set_info; break;
+ case SNDINFO_PTR_START: info->start = ymf278b_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YMF278B"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/ymf278b.h b/src/emu/sound/ymf278b.h
new file mode 100644
index 00000000000..f89c2fbfb06
--- /dev/null
+++ b/src/emu/sound/ymf278b.h
@@ -0,0 +1,29 @@
+#ifndef __YMF278B_H__
+#define __YMF278B_H__
+
+#define YMF278B_STD_CLOCK (33868800) /* standard clock for OPL4 */
+
+struct YMF278B_interface {
+ int region; /* memory region of sample ROMs */
+ void (*irq_callback)(int state); /* irq callback */
+};
+
+READ8_HANDLER( YMF278B_status_port_0_r );
+READ8_HANDLER( YMF278B_data_port_0_r );
+WRITE8_HANDLER( YMF278B_control_port_0_A_w );
+WRITE8_HANDLER( YMF278B_data_port_0_A_w );
+WRITE8_HANDLER( YMF278B_control_port_0_B_w );
+WRITE8_HANDLER( YMF278B_data_port_0_B_w );
+WRITE8_HANDLER( YMF278B_control_port_0_C_w );
+WRITE8_HANDLER( YMF278B_data_port_0_C_w );
+
+READ8_HANDLER( YMF278B_status_port_1_r );
+READ8_HANDLER( YMF278B_data_port_1_r );
+WRITE8_HANDLER( YMF278B_control_port_1_A_w );
+WRITE8_HANDLER( YMF278B_data_port_1_A_w );
+WRITE8_HANDLER( YMF278B_control_port_1_B_w );
+WRITE8_HANDLER( YMF278B_data_port_1_B_w );
+WRITE8_HANDLER( YMF278B_control_port_1_C_w );
+WRITE8_HANDLER( YMF278B_data_port_1_C_w );
+
+#endif
diff --git a/src/emu/sound/ymz280b.c b/src/emu/sound/ymz280b.c
new file mode 100644
index 00000000000..e9df9742413
--- /dev/null
+++ b/src/emu/sound/ymz280b.c
@@ -0,0 +1,1125 @@
+/*
+
+ Yamaha YMZ280B driver
+ by Aaron Giles
+
+ YMZ280B 8-Channel PCMD8 PCM/ADPCM Decoder
+
+ Features as listed in LSI-4MZ280B3 data sheet:
+ Voice data stored in external memory can be played back simultaneously for up to eight voices
+ Voice data format can be selected from 4-bit ADPCM, 8-bit PCM and 16-bit PCM
+ Control of voice data external memory
+ Up to 16M bytes of ROM or SRAM (x 8 bits, access time 150ms max) can be connected
+ Continuous access is possible
+ Loop playback between selective addresses is possible
+ Voice data playback frequency control
+ 4-bit ADPCM ................ 0.172 to 44.1kHz in 256 steps
+ 8-bit PCM, 16-bit PCM ...... 0.172 to 88.2kHz in 512 steps
+ 256 steps total level and 16 steps panpot can be set
+ Voice signal is output in stereo 16-bit 2's complement MSB-first format
+
+*/
+
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "ymz280b.h"
+
+
+#define MAX_SAMPLE_CHUNK 10000
+#define MAKE_WAVS 0
+
+#define FRAC_BITS 14
+#define FRAC_ONE (1 << FRAC_BITS)
+#define FRAC_MASK (FRAC_ONE - 1)
+
+#define INTERNAL_BUFFER_SIZE (1 << 15)
+#define INTERNAL_SAMPLE_RATE (chip->master_clock * 2.0)
+
+#if MAKE_WAVS
+#include "wavwrite.h"
+#endif
+
+
+/* struct describing a single playing ADPCM voice */
+struct YMZ280BVoice
+{
+ UINT8 playing; /* 1 if we are actively playing */
+
+ UINT8 keyon; /* 1 if the key is on */
+ UINT8 looping; /* 1 if looping is enabled */
+ UINT8 mode; /* current playback mode */
+ UINT16 fnum; /* frequency */
+ UINT8 level; /* output level */
+ UINT8 pan; /* panning */
+
+ UINT32 start; /* start address, in nibbles */
+ UINT32 stop; /* stop address, in nibbles */
+ UINT32 loop_start; /* loop start address, in nibbles */
+ UINT32 loop_end; /* loop end address, in nibbles */
+ UINT32 position; /* current position, in nibbles */
+
+ INT32 signal; /* current ADPCM signal */
+ INT32 step; /* current ADPCM step */
+
+ INT32 loop_signal; /* signal at loop start */
+ INT32 loop_step; /* step at loop start */
+ UINT32 loop_count; /* number of loops so far */
+
+ INT32 output_left; /* output volume (left) */
+ INT32 output_right; /* output volume (right) */
+ INT32 output_step; /* step value for frequency conversion */
+ INT32 output_pos; /* current fractional position */
+ INT16 last_sample; /* last sample output */
+ INT16 curr_sample; /* current sample target */
+ UINT8 irq_schedule; /* 1 if the IRQ state is updated by timer */
+};
+
+struct YMZ280BChip
+{
+ sound_stream * stream; /* which stream are we using */
+ UINT8 *region_base; /* pointer to the base of the region */
+ UINT8 current_register; /* currently accessible register */
+ UINT8 status_register; /* current status register */
+ UINT8 irq_state; /* current IRQ state */
+ UINT8 irq_mask; /* current IRQ mask */
+ UINT8 irq_enable; /* current IRQ enable */
+ UINT8 keyon_enable; /* key on enable */
+ double master_clock; /* master clock frequency */
+ void (*irq_callback)(int); /* IRQ callback */
+ struct YMZ280BVoice voice[8]; /* the 8 voices */
+ UINT32 rom_readback_addr; /* where the CPU can read the ROM */
+ read8_handler ext_ram_read; /* external RAM read handler */
+ write8_handler ext_ram_write; /* external RAM write handler */
+
+#if MAKE_WAVS
+ void * wavresample; /* resampled waveform */
+#endif
+
+ INT16 *scratch;
+};
+
+/* step size index shift table */
+static const int index_scale[8] = { 0x0e6, 0x0e6, 0x0e6, 0x0e6, 0x133, 0x199, 0x200, 0x266 };
+
+/* lookup table for the precomputed difference */
+static int diff_lookup[16];
+
+/* timer callback */
+static TIMER_CALLBACK_PTR( update_irq_state_timer_0 );
+static TIMER_CALLBACK_PTR( update_irq_state_timer_1 );
+static TIMER_CALLBACK_PTR( update_irq_state_timer_2 );
+static TIMER_CALLBACK_PTR( update_irq_state_timer_3 );
+static TIMER_CALLBACK_PTR( update_irq_state_timer_4 );
+static TIMER_CALLBACK_PTR( update_irq_state_timer_5 );
+static TIMER_CALLBACK_PTR( update_irq_state_timer_6 );
+static TIMER_CALLBACK_PTR( update_irq_state_timer_7 );
+
+static void (*update_irq_state_cb[])(running_machine *, void *) =
+{
+ update_irq_state_timer_0,
+ update_irq_state_timer_1,
+ update_irq_state_timer_2,
+ update_irq_state_timer_3,
+ update_irq_state_timer_4,
+ update_irq_state_timer_5,
+ update_irq_state_timer_6,
+ update_irq_state_timer_7
+};
+
+
+
+INLINE void update_irq_state(struct YMZ280BChip *chip)
+{
+ int irq_bits = chip->status_register & chip->irq_mask;
+
+ /* always off if the enable is off */
+ if (!chip->irq_enable)
+ irq_bits = 0;
+
+ /* update the state if changed */
+ if (irq_bits && !chip->irq_state)
+ {
+ chip->irq_state = 1;
+ if (chip->irq_callback)
+ (*chip->irq_callback)(1);
+ else logerror("YMZ280B: IRQ generated, but no callback specified!");
+ }
+ else if (!irq_bits && chip->irq_state)
+ {
+ chip->irq_state = 0;
+ if (chip->irq_callback)
+ (*chip->irq_callback)(0);
+ else logerror("YMZ280B: IRQ generated, but no callback specified!");
+ }
+}
+
+
+INLINE void update_step(struct YMZ280BChip *chip, struct YMZ280BVoice *voice)
+{
+ double frequency;
+
+ /* compute the frequency */
+ if (voice->mode == 1)
+ frequency = chip->master_clock * (double)((voice->fnum & 0x0ff) + 1) * (1.0 / 256.0);
+ else
+ frequency = chip->master_clock * (double)((voice->fnum & 0x1ff) + 1) * (1.0 / 256.0);
+ voice->output_step = (UINT32)(frequency * (double)FRAC_ONE / INTERNAL_SAMPLE_RATE);
+}
+
+
+INLINE void update_volumes(struct YMZ280BVoice *voice)
+{
+ if (voice->pan == 8)
+ {
+ voice->output_left = voice->level;
+ voice->output_right = voice->level;
+ }
+ else if (voice->pan < 8)
+ {
+ voice->output_left = voice->level;
+ voice->output_right = voice->level * voice->pan / 8;
+ }
+ else
+ {
+ voice->output_left = voice->level * (15 - voice->pan) / 8;
+ voice->output_right = voice->level;
+ }
+}
+
+
+static void YMZ280B_state_save_update_step(void *param)
+{
+ struct YMZ280BChip *chip = param;
+ int j;
+ for (j = 0; j < 8; j++)
+ {
+ struct YMZ280BVoice *voice = &chip->voice[j];
+ update_step(chip, voice);
+ if(voice->irq_schedule)
+ timer_set_ptr(attotime_zero, chip, update_irq_state_cb[j]);
+ }
+}
+
+
+static void update_irq_state_timer_common(void *param, int voicenum)
+{
+ struct YMZ280BChip *chip = param;
+ struct YMZ280BVoice *voice = &chip->voice[voicenum];
+
+ if(!voice->irq_schedule) return;
+
+ voice->playing = 0;
+ chip->status_register |= 1 << voicenum;
+ update_irq_state(chip);
+ voice->irq_schedule = 0;
+}
+
+static TIMER_CALLBACK_PTR( update_irq_state_timer_0 ) { update_irq_state_timer_common(param, 0); }
+static TIMER_CALLBACK_PTR( update_irq_state_timer_1 ) { update_irq_state_timer_common(param, 1); }
+static TIMER_CALLBACK_PTR( update_irq_state_timer_2 ) { update_irq_state_timer_common(param, 2); }
+static TIMER_CALLBACK_PTR( update_irq_state_timer_3 ) { update_irq_state_timer_common(param, 3); }
+static TIMER_CALLBACK_PTR( update_irq_state_timer_4 ) { update_irq_state_timer_common(param, 4); }
+static TIMER_CALLBACK_PTR( update_irq_state_timer_5 ) { update_irq_state_timer_common(param, 5); }
+static TIMER_CALLBACK_PTR( update_irq_state_timer_6 ) { update_irq_state_timer_common(param, 6); }
+static TIMER_CALLBACK_PTR( update_irq_state_timer_7 ) { update_irq_state_timer_common(param, 7); }
+
+
+/**********************************************************************************************
+
+ compute_tables -- compute the difference tables
+
+***********************************************************************************************/
+
+static void compute_tables(void)
+{
+ int nib;
+
+ /* loop over all nibbles and compute the difference */
+ for (nib = 0; nib < 16; nib++)
+ {
+ int value = (nib & 0x07) * 2 + 1;
+ diff_lookup[nib] = (nib & 0x08) ? -value : value;
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ generate_adpcm -- general ADPCM decoding routine
+
+***********************************************************************************************/
+
+static int generate_adpcm(struct YMZ280BVoice *voice, UINT8 *base, INT16 *buffer, int samples)
+{
+ int position = voice->position;
+ int signal = voice->signal;
+ int step = voice->step;
+ int val;
+
+ /* two cases: first cases is non-looping */
+ if (!voice->looping)
+ {
+ /* loop while we still have samples to generate */
+ while (samples)
+ {
+ /* compute the new amplitude and update the current step */
+ val = base[position / 2] >> ((~position & 1) << 2);
+ signal += (step * diff_lookup[val & 15]) / 8;
+
+ /* clamp to the maximum */
+ if (signal > 32767)
+ signal = 32767;
+ else if (signal < -32768)
+ signal = -32768;
+
+ /* adjust the step size and clamp */
+ step = (step * index_scale[val & 7]) >> 8;
+ if (step > 0x6000)
+ step = 0x6000;
+ else if (step < 0x7f)
+ step = 0x7f;
+
+ /* output to the buffer, scaling by the volume */
+ *buffer++ = signal;
+ samples--;
+
+ /* next! */
+ position++;
+ if (position >= voice->stop)
+ break;
+ }
+ }
+
+ /* second case: looping */
+ else
+ {
+ /* loop while we still have samples to generate */
+ while (samples)
+ {
+ /* compute the new amplitude and update the current step */
+ val = base[position / 2] >> ((~position & 1) << 2);
+ signal += (step * diff_lookup[val & 15]) / 8;
+
+ /* clamp to the maximum */
+ if (signal > 32767)
+ signal = 32767;
+ else if (signal < -32768)
+ signal = -32768;
+
+ /* adjust the step size and clamp */
+ step = (step * index_scale[val & 7]) >> 8;
+ if (step > 0x6000)
+ step = 0x6000;
+ else if (step < 0x7f)
+ step = 0x7f;
+
+ /* output to the buffer, scaling by the volume */
+ *buffer++ = signal;
+ samples--;
+
+ /* next! */
+ position++;
+ if (position == voice->loop_start && voice->loop_count == 0)
+ {
+ voice->loop_signal = signal;
+ voice->loop_step = step;
+ }
+ if (position >= voice->loop_end)
+ {
+ if (voice->keyon)
+ {
+ position = voice->loop_start;
+ signal = voice->loop_signal;
+ step = voice->loop_step;
+ voice->loop_count++;
+ }
+ }
+ if (position >= voice->stop)
+ break;
+ }
+ }
+
+ /* update the parameters */
+ voice->position = position;
+ voice->signal = signal;
+ voice->step = step;
+
+ return samples;
+}
+
+
+
+/**********************************************************************************************
+
+ generate_pcm8 -- general 8-bit PCM decoding routine
+
+***********************************************************************************************/
+
+static int generate_pcm8(struct YMZ280BVoice *voice, UINT8 *base, INT16 *buffer, int samples)
+{
+ int position = voice->position;
+ int val;
+
+ /* two cases: first cases is non-looping */
+ if (!voice->looping)
+ {
+ /* loop while we still have samples to generate */
+ while (samples)
+ {
+ /* fetch the current value */
+ val = base[position / 2];
+
+ /* output to the buffer, scaling by the volume */
+ *buffer++ = (INT8)val * 256;
+ samples--;
+
+ /* next! */
+ position += 2;
+ if (position >= voice->stop)
+ break;
+ }
+ }
+
+ /* second case: looping */
+ else
+ {
+ /* loop while we still have samples to generate */
+ while (samples)
+ {
+ /* fetch the current value */
+ val = base[position / 2];
+
+ /* output to the buffer, scaling by the volume */
+ *buffer++ = (INT8)val * 256;
+ samples--;
+
+ /* next! */
+ position += 2;
+ if (position >= voice->loop_end)
+ {
+ if (voice->keyon)
+ position = voice->loop_start;
+ }
+ if (position >= voice->stop)
+ break;
+ }
+ }
+
+ /* update the parameters */
+ voice->position = position;
+
+ return samples;
+}
+
+
+
+/**********************************************************************************************
+
+ generate_pcm16 -- general 16-bit PCM decoding routine
+
+***********************************************************************************************/
+
+static int generate_pcm16(struct YMZ280BVoice *voice, UINT8 *base, INT16 *buffer, int samples)
+{
+ int position = voice->position;
+ int val;
+
+ /* two cases: first cases is non-looping */
+ if (!voice->looping)
+ {
+ /* loop while we still have samples to generate */
+ while (samples)
+ {
+ /* fetch the current value */
+ val = (INT16)((base[position / 2 + 1] << 8) + base[position / 2]);
+
+ /* output to the buffer, scaling by the volume */
+ *buffer++ = val;
+ samples--;
+
+ /* next! */
+ position += 4;
+ if (position >= voice->stop)
+ break;
+ }
+ }
+
+ /* second case: looping */
+ else
+ {
+ /* loop while we still have samples to generate */
+ while (samples)
+ {
+ /* fetch the current value */
+ val = (INT16)((base[position / 2 + 1] << 8) + base[position / 2]);
+
+ /* output to the buffer, scaling by the volume */
+ *buffer++ = val;
+ samples--;
+
+ /* next! */
+ position += 4;
+ if (position >= voice->loop_end)
+ {
+ if (voice->keyon)
+ position = voice->loop_start;
+ }
+ if (position >= voice->stop)
+ break;
+ }
+ }
+
+ /* update the parameters */
+ voice->position = position;
+
+ return samples;
+}
+
+
+
+/**********************************************************************************************
+
+ ymz280b_update -- update the sound chip so that it is in sync with CPU execution
+
+***********************************************************************************************/
+
+static void ymz280b_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
+{
+ struct YMZ280BChip *chip = param;
+ stream_sample_t *lacc = buffer[0];
+ stream_sample_t *racc = buffer[1];
+ int v;
+
+ /* clear out the accumulator */
+ memset(lacc, 0, length * sizeof(lacc[0]));
+ memset(racc, 0, length * sizeof(racc[0]));
+
+ /* loop over voices */
+ for (v = 0; v < 8; v++)
+ {
+ struct YMZ280BVoice *voice = &chip->voice[v];
+ INT16 prev = voice->last_sample;
+ INT16 curr = voice->curr_sample;
+ INT16 *curr_data = chip->scratch;
+ INT32 *ldest = lacc;
+ INT32 *rdest = racc;
+ UINT32 new_samples, samples_left;
+ UINT32 final_pos;
+ int remaining = length;
+ int lvol = voice->output_left;
+ int rvol = voice->output_right;
+
+ /* quick out if we're not playing and we're at 0 */
+ if (!voice->playing && curr == 0)
+ continue;
+
+ /* finish off the current sample */
+// if (voice->output_pos > 0)
+ {
+ /* interpolate */
+ while (remaining > 0 && voice->output_pos < FRAC_ONE)
+ {
+ int interp_sample = (((INT32)prev * (FRAC_ONE - voice->output_pos)) + ((INT32)curr * voice->output_pos)) >> FRAC_BITS;
+ *ldest++ += interp_sample * lvol;
+ *rdest++ += interp_sample * rvol;
+ voice->output_pos += voice->output_step;
+ remaining--;
+ }
+
+ /* if we're over, continue; otherwise, we're done */
+ if (voice->output_pos >= FRAC_ONE)
+ voice->output_pos -= FRAC_ONE;
+ else
+ continue;
+ }
+
+ /* compute how many new samples we need */
+ final_pos = voice->output_pos + remaining * voice->output_step;
+ new_samples = (final_pos + FRAC_ONE) >> FRAC_BITS;
+ if (new_samples > MAX_SAMPLE_CHUNK)
+ new_samples = MAX_SAMPLE_CHUNK;
+ samples_left = new_samples;
+
+ /* generate them into our buffer */
+ if (voice->playing)
+ {
+ switch (voice->mode)
+ {
+ case 1: samples_left = generate_adpcm(voice, chip->region_base, chip->scratch, new_samples); break;
+ case 2: samples_left = generate_pcm8(voice, chip->region_base, chip->scratch, new_samples); break;
+ case 3: samples_left = generate_pcm16(voice, chip->region_base, chip->scratch, new_samples); break;
+ default:
+ case 0: samples_left = 0; memset(chip->scratch, 0, new_samples * sizeof(chip->scratch[0])); break;
+ }
+ }
+
+ /* if there are leftovers, ramp back to 0 */
+ if (samples_left)
+ {
+ int base = new_samples - samples_left;
+ int i, t = (base == 0) ? curr : chip->scratch[base - 1];
+ for (i = 0; i < samples_left; i++)
+ {
+ if (t < 0) t = -((-t * 15) >> 4);
+ else if (t > 0) t = (t * 15) >> 4;
+ chip->scratch[base + i] = t;
+ }
+
+ /* if we hit the end and IRQs are enabled, signal it */
+ if (base != 0)
+ {
+ voice->playing = 0;
+
+ /* set update_irq_state_timer. IRQ is signaled on next CPU execution. */
+ timer_set_ptr(attotime_zero, chip, update_irq_state_cb[v]);
+ voice->irq_schedule = 1;
+ }
+ }
+
+ /* advance forward one sample */
+ prev = curr;
+ curr = *curr_data++;
+
+ /* then sample-rate convert with linear interpolation */
+ while (remaining > 0)
+ {
+ /* interpolate */
+ while (remaining > 0 && voice->output_pos < FRAC_ONE)
+ {
+ int interp_sample = (((INT32)prev * (FRAC_ONE - voice->output_pos)) + ((INT32)curr * voice->output_pos)) >> FRAC_BITS;
+ *ldest++ += interp_sample * lvol;
+ *rdest++ += interp_sample * rvol;
+ voice->output_pos += voice->output_step;
+ remaining--;
+ }
+
+ /* if we're over, grab the next samples */
+ if (voice->output_pos >= FRAC_ONE)
+ {
+ voice->output_pos -= FRAC_ONE;
+ prev = curr;
+ curr = *curr_data++;
+ }
+ }
+
+ /* remember the last samples */
+ voice->last_sample = prev;
+ voice->curr_sample = curr;
+ }
+
+ for (v = 0; v < length; v++)
+ {
+ buffer[0][v] /= 256;
+ buffer[1][v] /= 256;
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ YMZ280B_sh_start -- start emulation of the YMZ280B
+
+***********************************************************************************************/
+
+static void *ymz280b_start(int sndindex, int clock, const void *config)
+{
+ const struct YMZ280Binterface *intf = config;
+ struct YMZ280BChip *chip;
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ chip->ext_ram_read = intf->ext_read;
+ chip->ext_ram_write = intf->ext_write;
+
+ /* compute ADPCM tables */
+ compute_tables();
+
+ /* initialize the rest of the structure */
+ chip->master_clock = (double)clock / 384.0;
+ chip->region_base = memory_region(intf->region);
+ chip->irq_callback = intf->irq_callback;
+
+ /* create the stream */
+ chip->stream = stream_create(0, 2, INTERNAL_SAMPLE_RATE, chip, ymz280b_update);
+
+ /* allocate memory */
+ chip->scratch = auto_malloc(sizeof(chip->scratch[0]) * MAX_SAMPLE_CHUNK);
+
+ /* state save */
+ {
+ int j;
+ state_save_register_item("YMZ280B", sndindex, chip->current_register);
+ state_save_register_item("YMZ280B", sndindex, chip->status_register);
+ state_save_register_item("YMZ280B", sndindex, chip->irq_state);
+ state_save_register_item("YMZ280B", sndindex, chip->irq_mask);
+ state_save_register_item("YMZ280B", sndindex, chip->irq_enable);
+ state_save_register_item("YMZ280B", sndindex, chip->keyon_enable);
+ state_save_register_item("YMZ280B", sndindex, chip->rom_readback_addr);
+ for (j = 0; j < 8; j++)
+ {
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].playing);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].keyon);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].looping);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].mode);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].fnum);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].level);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].pan);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].start);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].stop);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].loop_start);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].loop_end);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].position);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].signal);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].step);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].loop_signal);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].loop_step);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].loop_count);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].output_left);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].output_right);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].output_pos);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].last_sample);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].curr_sample);
+ state_save_register_item("YMZ280B.voice", sndindex*8+j, chip->voice[j].irq_schedule);
+ }
+ }
+
+ state_save_register_func_postload_ptr(YMZ280B_state_save_update_step, chip);
+
+#if MAKE_WAVS
+ chip->wavresample = wav_open("resamp.wav", INTERNAL_SAMPLE_RATE, 2);
+#endif
+
+ /* success */
+ return chip;
+}
+
+
+
+/**********************************************************************************************
+
+ YMZ280B_sh_stop -- stop emulation of the YMZ280B
+
+***********************************************************************************************/
+
+void YMZ280B_sh_stop(void)
+{
+#if MAKE_WAVS
+{
+ int i;
+
+ for (i = 0; i < MAX_BSMT2000; i++)
+ {
+ if (ymz280b[i].wavresample)
+ wav_close(ymz280b[i].wavresample);
+ }
+}
+#endif
+}
+
+
+
+/**********************************************************************************************
+
+ write_to_register -- handle a write to the current register
+
+***********************************************************************************************/
+
+static void write_to_register(struct YMZ280BChip *chip, int data)
+{
+ struct YMZ280BVoice *voice;
+ int i;
+
+ /* force an update */
+ stream_update(chip->stream);
+
+ /* lower registers follow a pattern */
+ if (chip->current_register < 0x80)
+ {
+ voice = &chip->voice[(chip->current_register >> 2) & 7];
+
+ switch (chip->current_register & 0xe3)
+ {
+ case 0x00: /* pitch low 8 bits */
+ voice->fnum = (voice->fnum & 0x100) | (data & 0xff);
+ update_step(chip, voice);
+ break;
+
+ case 0x01: /* pitch upper 1 bit, loop, key on, mode */
+ voice->fnum = (voice->fnum & 0xff) | ((data & 0x01) << 8);
+ voice->looping = (data & 0x10) >> 4;
+ voice->mode = (data & 0x60) >> 5;
+ if (!voice->keyon && (data & 0x80) && chip->keyon_enable)
+ {
+ voice->playing = 1;
+ voice->position = voice->start;
+ voice->signal = voice->loop_signal = 0;
+ voice->step = voice->loop_step = 0x7f;
+ voice->loop_count = 0;
+
+ /* if update_irq_state_timer is set, cancel it. */
+ voice->irq_schedule = 0;
+ }
+ if (voice->keyon && !(data & 0x80) && !voice->looping)
+ {
+ voice->playing = 0;
+
+ /* if update_irq_state_timer is set, cancel it. */
+ voice->irq_schedule = 0;
+ }
+ voice->keyon = (data & 0x80) >> 7;
+ update_step(chip, voice);
+ break;
+
+ case 0x02: /* total level */
+ voice->level = data;
+ update_volumes(voice);
+ break;
+
+ case 0x03: /* pan */
+ voice->pan = data & 0x0f;
+ update_volumes(voice);
+ break;
+
+ case 0x20: /* start address high */
+ voice->start = (voice->start & (0x00ffff << 1)) | (data << 17);
+ break;
+
+ case 0x21: /* loop start address high */
+ voice->loop_start = (voice->loop_start & (0x00ffff << 1)) | (data << 17);
+ break;
+
+ case 0x22: /* loop end address high */
+ voice->loop_end = (voice->loop_end & (0x00ffff << 1)) | (data << 17);
+ break;
+
+ case 0x23: /* stop address high */
+ voice->stop = (voice->stop & (0x00ffff << 1)) | (data << 17);
+ break;
+
+ case 0x40: /* start address middle */
+ voice->start = (voice->start & (0xff00ff << 1)) | (data << 9);
+ break;
+
+ case 0x41: /* loop start address middle */
+ voice->loop_start = (voice->loop_start & (0xff00ff << 1)) | (data << 9);
+ break;
+
+ case 0x42: /* loop end address middle */
+ voice->loop_end = (voice->loop_end & (0xff00ff << 1)) | (data << 9);
+ break;
+
+ case 0x43: /* stop address middle */
+ voice->stop = (voice->stop & (0xff00ff << 1)) | (data << 9);
+ break;
+
+ case 0x60: /* start address low */
+ voice->start = (voice->start & (0xffff00 << 1)) | (data << 1);
+ break;
+
+ case 0x61: /* loop start address low */
+ voice->loop_start = (voice->loop_start & (0xffff00 << 1)) | (data << 1);
+ break;
+
+ case 0x62: /* loop end address low */
+ voice->loop_end = (voice->loop_end & (0xffff00 << 1)) | (data << 1);
+ break;
+
+ case 0x63: /* stop address low */
+ voice->stop = (voice->stop & (0xffff00 << 1)) | (data << 1);
+ break;
+
+ default:
+ logerror("YMZ280B: unknown register write %02X = %02X\n", chip->current_register, data);
+ break;
+ }
+ }
+
+ /* upper registers are special */
+ else
+ {
+ switch (chip->current_register)
+ {
+ case 0x84: /* ROM readback / RAM write (high) */
+ chip->rom_readback_addr &= 0xffff;
+ chip->rom_readback_addr |= (data<<16);
+ break;
+
+ case 0x85: /* ROM readback / RAM write (med) */
+ chip->rom_readback_addr &= 0xff00ff;
+ chip->rom_readback_addr |= (data<<8);
+ break;
+
+ case 0x86: /* ROM readback / RAM write (low) */
+ chip->rom_readback_addr &= 0xffff00;
+ chip->rom_readback_addr |= data;
+ break;
+
+ case 0x87: /* RAM write */
+ if (chip->ext_ram_write)
+ chip->ext_ram_write(chip->rom_readback_addr, data);
+ else
+ logerror("YMZ280B attempted RAM write to %X\n", chip->rom_readback_addr);
+ break;
+
+ case 0xfe: /* IRQ mask */
+ chip->irq_mask = data;
+ update_irq_state(chip);
+ break;
+
+ case 0xff: /* IRQ enable, test, etc */
+ chip->irq_enable = (data & 0x10) >> 4;
+ update_irq_state(chip);
+
+ if (chip->keyon_enable && !(data & 0x80))
+ {
+ for (i = 0; i < 8; i++)
+ {
+ chip->voice[i].playing = 0;
+
+ /* if update_irq_state_timer is set, cancel it. */
+ chip->voice[i].irq_schedule = 0;
+ }
+ }
+ else if (!chip->keyon_enable && (data & 0x80))
+ {
+ for (i = 0; i < 8; i++)
+ {
+ if (chip->voice[i].keyon && chip->voice[i].looping)
+ chip->voice[i].playing = 1;
+ }
+ }
+ chip->keyon_enable = (data & 0x80) >> 7;
+ break;
+
+ default:
+ logerror("YMZ280B: unknown register write %02X = %02X\n", chip->current_register, data);
+ break;
+ }
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ compute_status -- determine the status bits
+
+***********************************************************************************************/
+
+static int compute_status(struct YMZ280BChip *chip)
+{
+ UINT8 result;
+
+ /* ROM/RAM readback? */
+ if (chip->current_register == 0x86)
+ {
+ return chip->region_base[chip->rom_readback_addr];
+ }
+
+ /* force an update */
+ stream_update(chip->stream);
+
+ result = chip->status_register;
+
+ /* clear the IRQ state */
+ chip->status_register = 0;
+ update_irq_state(chip);
+
+ return result;
+}
+
+
+
+/**********************************************************************************************
+
+ YMZ280B_status_0_r/YMZ280B_status_1_r -- handle a read from the status register
+
+***********************************************************************************************/
+
+READ8_HANDLER( YMZ280B_status_0_r )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ return compute_status(chip);
+}
+
+READ8_HANDLER( YMZ280B_status_1_r )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ return compute_status(chip);
+}
+
+READ16_HANDLER( YMZ280B_status_0_lsb_r )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ return compute_status(chip);
+}
+
+READ16_HANDLER( YMZ280B_status_0_msb_r )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ return compute_status(chip) << 8;
+}
+
+READ16_HANDLER( YMZ280B_status_1_lsb_r )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ return compute_status(chip);
+}
+
+READ16_HANDLER( YMZ280B_status_1_msb_r )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ return compute_status(chip) << 8;
+}
+
+/**********************************************************************************************
+
+ YMZ280B_register_0_w/YMZ280B_register_1_w -- handle a write to the register select
+
+***********************************************************************************************/
+
+WRITE8_HANDLER( YMZ280B_register_0_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ chip->current_register = data;
+}
+
+WRITE8_HANDLER( YMZ280B_register_1_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ chip->current_register = data;
+}
+
+WRITE16_HANDLER( YMZ280B_register_0_lsb_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ if (ACCESSING_LSB) chip->current_register = data & 0xff;
+}
+
+WRITE16_HANDLER( YMZ280B_register_0_msb_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ if (ACCESSING_MSB) chip->current_register = (data >> 8) & 0xff;
+}
+
+WRITE16_HANDLER( YMZ280B_register_1_lsb_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ if (ACCESSING_LSB) chip->current_register = data & 0xff;
+}
+
+WRITE16_HANDLER( YMZ280B_register_1_msb_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ if (ACCESSING_MSB) chip->current_register = (data >> 8) & 0xff;
+}
+
+/**********************************************************************************************
+
+ YMZ280B_data_0_w/YMZ280B_data_1_w -- handle a write to the current register
+
+***********************************************************************************************/
+
+WRITE8_HANDLER( YMZ280B_data_0_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ write_to_register(chip, data);
+}
+
+WRITE8_HANDLER( YMZ280B_data_1_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ write_to_register(chip, data);
+}
+
+WRITE16_HANDLER( YMZ280B_data_0_lsb_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ if (ACCESSING_LSB) write_to_register(chip, data & 0xff);
+}
+
+WRITE16_HANDLER( YMZ280B_data_0_msb_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ if (ACCESSING_MSB) write_to_register(chip, (data >> 8) & 0xff);
+}
+
+WRITE16_HANDLER( YMZ280B_data_1_lsb_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ if (ACCESSING_LSB) write_to_register(chip, data & 0xff);
+}
+
+WRITE16_HANDLER( YMZ280B_data_1_msb_w )
+{
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ if (ACCESSING_MSB) write_to_register(chip, (data >> 8) & 0xff);
+}
+
+/**********************************************************************************************
+
+ YMZ280B_data_0_r/YMZ280B_data_1_r -- handle an external RAM read
+
+***********************************************************************************************/
+
+READ8_HANDLER( YMZ280B_data_0_r )
+{
+ UINT8 data;
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 0);
+ data = chip->ext_ram_read(chip->rom_readback_addr - 1);
+ chip->rom_readback_addr++;
+ return data;
+}
+
+READ8_HANDLER( YMZ280B_data_1_r )
+{
+ UINT8 data;
+ struct YMZ280BChip *chip = sndti_token(SOUND_YMZ280B, 1);
+ data = chip->ext_ram_read(chip->rom_readback_addr - 1);
+ chip->rom_readback_addr++;
+ return data;
+}
+
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static void ymz280b_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void ymz280b_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = ymz280b_set_info; break;
+ case SNDINFO_PTR_START: info->start = ymz280b_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "YMZ280B"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha Wavetable"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
+ }
+}
+
diff --git a/src/emu/sound/ymz280b.h b/src/emu/sound/ymz280b.h
new file mode 100644
index 00000000000..b32a908cad0
--- /dev/null
+++ b/src/emu/sound/ymz280b.h
@@ -0,0 +1,43 @@
+/**********************************************************************************************
+ *
+ * Yamaha YMZ280B driver
+ * by Aaron Giles
+ *
+ **********************************************************************************************/
+
+#ifndef YMZ280B_H
+#define YMZ280B_H
+
+struct YMZ280Binterface
+{
+ int region; /* memory region where the sample ROM lives */
+ void (*irq_callback)(int state); /* irq callback */
+ read8_handler ext_read; /* external RAM read */
+ write8_handler ext_write; /* external RAM write */
+};
+
+READ8_HANDLER ( YMZ280B_status_0_r );
+WRITE8_HANDLER( YMZ280B_register_0_w );
+READ8_HANDLER( YMZ280B_data_0_r );
+WRITE8_HANDLER( YMZ280B_data_0_w );
+
+READ16_HANDLER ( YMZ280B_status_0_lsb_r );
+READ16_HANDLER ( YMZ280B_status_0_msb_r );
+WRITE16_HANDLER( YMZ280B_register_0_lsb_w );
+WRITE16_HANDLER( YMZ280B_register_0_msb_w );
+WRITE16_HANDLER( YMZ280B_data_0_lsb_w );
+WRITE16_HANDLER( YMZ280B_data_0_msb_w );
+
+READ8_HANDLER ( YMZ280B_status_1_r );
+WRITE8_HANDLER( YMZ280B_register_1_w );
+READ8_HANDLER( YMZ280B_data_1_r );
+WRITE8_HANDLER( YMZ280B_data_1_w );
+
+READ16_HANDLER ( YMZ280B_status_1_lsb_r );
+READ16_HANDLER ( YMZ280B_status_1_msb_r );
+WRITE16_HANDLER( YMZ280B_register_1_lsb_w );
+WRITE16_HANDLER( YMZ280B_register_1_msb_w );
+WRITE16_HANDLER( YMZ280B_data_1_lsb_w );
+WRITE16_HANDLER( YMZ280B_data_1_msb_w );
+
+#endif
diff --git a/src/emu/state.c b/src/emu/state.c
new file mode 100644
index 00000000000..9b4159f82a5
--- /dev/null
+++ b/src/emu/state.c
@@ -0,0 +1,966 @@
+/***************************************************************************
+
+ state.c
+
+ Save state management functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Save state file format:
+
+ 0.. 7 'MAMESAVE"
+ 8 Format version (this is format 1)
+ 9 Flags
+ a..13 Game name padded with \0
+ 14..17 Signature
+ 18..end Save game data
+
+***************************************************************************/
+
+#include "driver.h"
+#include "astring.h"
+#include <zlib.h>
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE
+
+#ifdef VERBOSE
+#define TRACE(x) do {x;} while (0)
+#else
+#define TRACE(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define SAVE_VERSION 1
+
+#define TAG_STACK_SIZE 4
+
+/* Available flags */
+enum
+{
+ SS_MSB_FIRST = 0x02
+};
+
+enum
+{
+ FUNC_NOPARAM,
+ FUNC_INTPARAM,
+ FUNC_PTRPARAM
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _ss_entry ss_entry;
+struct _ss_entry
+{
+ ss_entry * next; /* pointer to next entry */
+ void * data; /* pointer to the memory to save/restore */
+ astring * name; /* full name */
+ UINT8 typesize; /* size of the raw data type */
+ UINT32 typecount; /* number of items */
+ int tag; /* saving tag */
+ UINT32 offset; /* offset within the final structure */
+};
+
+
+typedef struct _ss_func ss_func;
+struct _ss_func
+{
+ ss_func * next; /* pointer to next entry */
+ int type; /* type of callback */
+ union
+ {
+ void (*voidf)(void);
+ void (*intf)(int param);
+ void (*ptrf)(void *param);
+ } func; /* function pointers */
+ union
+ {
+ int intp;
+ void *ptrp;
+ } param; /* parameters */
+ int tag; /* saving tag */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static int ss_illegal_regs;
+static ss_entry *ss_registry;
+static ss_func *ss_prefunc_reg;
+static ss_func *ss_postfunc_reg;
+
+static int ss_tag_stack[TAG_STACK_SIZE];
+static int ss_tag_stack_index;
+static int ss_current_tag;
+static UINT8 ss_registration_allowed;
+
+static UINT8 *ss_dump_array;
+static mame_file *ss_dump_file;
+static UINT32 ss_dump_size;
+
+#ifdef MESS
+static const char ss_magic_num[8] = { 'M', 'E', 'S', 'S', 'S', 'A', 'V', 'E' };
+#else
+static const char ss_magic_num[8] = { 'M', 'A', 'M', 'E', 'S', 'A', 'V', 'E' };
+#endif
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void ss_c2(UINT8 *, UINT32);
+static void ss_c4(UINT8 *, UINT32);
+static void ss_c8(UINT8 *, UINT32);
+
+static void (*ss_conv[])(UINT8 *, UINT32) = { 0, 0, ss_c2, 0, ss_c4, 0, 0, 0, ss_c8 };
+
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ state_init - initialize the system and reset
+ all registrations
+-------------------------------------------------*/
+
+void state_init(running_machine *machine)
+{
+ ss_illegal_regs = 0;
+ ss_current_tag = 0;
+ ss_tag_stack_index = 0;
+ ss_registration_allowed = FALSE;
+}
+
+
+
+/***************************************************************************
+ TAGGING
+***************************************************************************/
+
+/*-------------------------------------------------
+ state_save_push_tag - push the current tag
+ onto the stack and set a new tag
+-------------------------------------------------*/
+
+void state_save_push_tag(int tag)
+{
+ if (ss_tag_stack_index == TAG_STACK_SIZE - 1)
+ fatalerror("state_save tag stack overflow");
+ ss_tag_stack[ss_tag_stack_index++] = ss_current_tag;
+ ss_current_tag = tag;
+}
+
+
+/*-------------------------------------------------
+ state_save_pop_tag - pop the tag from the top
+ of the stack
+-------------------------------------------------*/
+
+void state_save_pop_tag(void)
+{
+ if (ss_tag_stack_index == 0)
+ fatalerror("state_save tag stack underflow");
+ ss_current_tag = ss_tag_stack[--ss_tag_stack_index];
+}
+
+
+/*-------------------------------------------------
+ state_save_get_reg_count - count the number of
+ registered entries on the current tag
+-------------------------------------------------*/
+
+int state_save_get_reg_count(void)
+{
+ ss_entry *entry;
+ int count = 0;
+
+ /* iterate over entries with matching tags */
+ for (entry = ss_registry; entry; entry = entry->next)
+ if (entry->tag == ss_current_tag)
+ count++;
+
+ return count;
+}
+
+
+
+/***************************************************************************
+ REGISTRATION HANDLING
+***************************************************************************/
+
+/*-------------------------------------------------
+ state_save_allow_registration - allow/disallow
+ registrations to happen
+-------------------------------------------------*/
+
+void state_save_allow_registration(int allowed)
+{
+ /* allow/deny registration */
+ ss_registration_allowed = allowed;
+}
+
+
+/*-------------------------------------------------
+ state_save_registration_allowed - query
+ whether or not registrations are allowed
+-------------------------------------------------*/
+
+int state_save_registration_allowed(void)
+{
+ return ss_registration_allowed;
+}
+
+
+/*-------------------------------------------------
+ state_save_register_memory - register an
+ array of data in memory
+-------------------------------------------------*/
+
+void state_save_register_memory(const char *module, UINT32 instance, const char *name, void *val, UINT32 valsize, UINT32 valcount)
+{
+ ss_entry **entry, *next;
+ astring *totalname;
+
+ assert(valsize == 1 || valsize == 2 || valsize == 4 || valsize == 8);
+
+ /* check for invalid timing */
+ if (!ss_registration_allowed)
+ {
+ logerror("Attempt to register save state entry after state registration is closed! module %s name %s\n",module,name);
+ ss_illegal_regs++;
+ return;
+ }
+
+ /* create the full name */
+ totalname = astring_alloc();
+ astring_printf(totalname, "%X/%s/%X/%s", ss_current_tag, module, instance, name);
+
+ /* look for duplicates and an entry to insert in front of */
+ for (entry = &ss_registry; *entry; entry = &(*entry)->next)
+ {
+ /* stop if the next guy's string is greater than ours */
+ int cmpval = astring_cmp((*entry)->name, totalname);
+ if (cmpval > 0)
+ break;
+
+ /* error if we are equal */
+ if ((*entry)->tag == ss_current_tag && cmpval == 0)
+ fatalerror("Duplicate save state registration entry (%d, %s)", ss_current_tag, astring_c(totalname));
+ }
+
+ /* didn't find one; allocate a new one */
+ next = *entry;
+ *entry = malloc_or_die(sizeof(**entry));
+ memset(*entry, 0, sizeof(**entry));
+
+ /* fill in the rest */
+ (*entry)->next = next;
+ (*entry)->data = val;
+ (*entry)->name = totalname;
+ (*entry)->typesize = valsize;
+ (*entry)->typecount = valcount;
+ (*entry)->tag = ss_current_tag;
+ restrack_register_object(OBJTYPE_STATEREG, *entry, 0, __FILE__, __LINE__);
+}
+
+
+/*-------------------------------------------------
+ state_save_register_bitmap - register a
+ bitmap to be saved
+-------------------------------------------------*/
+
+void state_save_register_bitmap(const char *module, UINT32 instance, const char *name, mame_bitmap *val)
+{
+ state_save_register_memory(module, instance, name, val->base, val->bpp / 8, val->rowpixels * val->height);
+}
+
+
+
+/***************************************************************************
+ CALLBACK FUNCTION REGISTRATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ register_func_void - register a function
+ callback that takes no parameters
+-------------------------------------------------*/
+
+static void register_func_void(ss_func **root, void (*func)(void))
+{
+ ss_func **cur;
+
+ /* check for invalid timing */
+ if (!ss_registration_allowed)
+ {
+ logerror("Attempt to register callback function after state registration is closed!");
+ ss_illegal_regs++;
+ return;
+ }
+
+ /* scan for duplicates and push through to the end */
+ for (cur = root; *cur; cur = &(*cur)->next)
+ if ((*cur)->func.voidf == func && (*cur)->tag == ss_current_tag)
+ fatalerror("Duplicate save state function (%d, 0x%p)", ss_current_tag, func);
+
+ /* allocate a new entry */
+ *cur = malloc_or_die(sizeof(ss_func));
+
+ /* fill it in */
+ (*cur)->next = NULL;
+ (*cur)->type = FUNC_NOPARAM;
+ (*cur)->func.voidf = func;
+ (*cur)->tag = ss_current_tag;
+ restrack_register_object(OBJTYPE_STATEREG, *cur, (root == &ss_prefunc_reg) ? 1 : 2, __FILE__, __LINE__);
+}
+
+void state_save_register_func_presave(void (*func)(void))
+{
+ register_func_void(&ss_prefunc_reg, func);
+}
+
+void state_save_register_func_postload(void (*func)(void))
+{
+ register_func_void(&ss_postfunc_reg, func);
+}
+
+
+/*-------------------------------------------------
+ register_func_int - register a function
+ callback that takes an integer parameter
+-------------------------------------------------*/
+
+static void register_func_int(ss_func **root, void (*func)(int), int param)
+{
+ ss_func **cur;
+
+ /* check for invalid timing */
+ if (!ss_registration_allowed)
+ fatalerror("Attempt to register callback function after state registration is closed!");
+
+ /* scan for duplicates and push through to the end */
+ for (cur = root; *cur; cur = &(*cur)->next)
+ if ((*cur)->func.intf == func && (*cur)->param.intp == param && (*cur)->tag == ss_current_tag)
+ fatalerror("Duplicate save state function (%d, %d, %p)", ss_current_tag, param, func);
+
+ /* allocate a new entry */
+ *cur = malloc_or_die(sizeof(ss_func));
+
+ /* fill it in */
+ (*cur)->next = NULL;
+ (*cur)->type = FUNC_INTPARAM;
+ (*cur)->func.intf = func;
+ (*cur)->param.intp = param;
+ (*cur)->tag = ss_current_tag;
+ restrack_register_object(OBJTYPE_STATEREG, *cur, (root == &ss_prefunc_reg) ? 1 : 2, __FILE__, __LINE__);
+}
+
+void state_save_register_func_presave_int(void (*func)(int), int param)
+{
+ register_func_int(&ss_prefunc_reg, func, param);
+}
+
+void state_save_register_func_postload_int(void (*func)(int), int param)
+{
+ register_func_int(&ss_postfunc_reg, func, param);
+}
+
+
+/*-------------------------------------------------
+ register_func_ptr - register a function
+ callback that takes a void * parameter
+-------------------------------------------------*/
+
+static void register_func_ptr(ss_func **root, void (*func)(void *), void *param)
+{
+ ss_func **cur;
+
+ /* check for invalid timing */
+ if (!ss_registration_allowed)
+ fatalerror("Attempt to register callback function after state registration is closed!");
+
+ /* scan for duplicates and push through to the end */
+ for (cur = root; *cur; cur = &(*cur)->next)
+ if ((*cur)->func.ptrf == func && (*cur)->param.ptrp == param && (*cur)->tag == ss_current_tag)
+ fatalerror("Duplicate save state function (%d, %p, %p)", ss_current_tag, param, func);
+
+ /* allocate a new entry */
+ *cur = malloc_or_die(sizeof(ss_func));
+
+ /* fill it in */
+ (*cur)->next = NULL;
+ (*cur)->type = FUNC_PTRPARAM;
+ (*cur)->func.ptrf = func;
+ (*cur)->param.ptrp = param;
+ (*cur)->tag = ss_current_tag;
+ restrack_register_object(OBJTYPE_STATEREG, *cur, (root == &ss_prefunc_reg) ? 1 : 2, __FILE__, __LINE__);
+}
+
+void state_save_register_func_presave_ptr(void (*func)(void *), void * param)
+{
+ register_func_ptr(&ss_prefunc_reg, func, param);
+}
+
+void state_save_register_func_postload_ptr(void (*func)(void *), void * param)
+{
+ register_func_ptr(&ss_postfunc_reg, func, param);
+}
+
+
+
+/***************************************************************************
+ REGISTRATION FREEING
+***************************************************************************/
+
+/*-------------------------------------------------
+ func_free - free registered functions attached
+ to the current resource tag
+-------------------------------------------------*/
+
+static void func_free(ss_func **root, void *ptr)
+{
+ ss_func **func;
+
+ /* iterate over the function list */
+ for (func = root; *func; )
+ {
+ /* if this entry matches, free it */
+ if (*func == ptr)
+ {
+ ss_func *func_to_free = *func;
+
+ /* de-link us from the list and free our memory */
+ *func = (*func)->next;
+ free(func_to_free);
+ break;
+ }
+
+ /* otherwise, advance */
+ else
+ func = &(*func)->next;
+ }
+}
+
+
+/*-------------------------------------------------
+ state_save_free - free all registrations that
+ have been tagged with the current resource
+ tag
+-------------------------------------------------*/
+
+void state_destructor(void *ptr, size_t size)
+{
+ /* size of 0 means an entry */
+ if (size == 0)
+ {
+ ss_entry **entry;
+
+ /* iterate over entries */
+ for (entry = &ss_registry; *entry; )
+ {
+ /* if this entry matches, free it */
+ if (*entry == ptr)
+ {
+ ss_entry *entry_to_free = *entry;
+
+ /* de-link us from the list and free our memory */
+ *entry = (*entry)->next;
+ astring_free(entry_to_free->name);
+ free(entry_to_free);
+ break;
+ }
+
+ /* if not a match, move on */
+ else
+ entry = &(*entry)->next;
+ }
+ }
+
+ /* size of 1 means a pre function */
+ else if (size == 1)
+ func_free(&ss_prefunc_reg, ptr);
+
+ /* size of 2 means a post function */
+ else if (size == 2)
+ func_free(&ss_postfunc_reg, ptr);
+
+ /* if we're clear of all registrations, reset the invalid counter */
+ if (ss_registry == NULL && ss_prefunc_reg == NULL && ss_postfunc_reg == NULL)
+ ss_illegal_regs = 0;
+}
+
+
+
+/***************************************************************************
+ ENDIAN CONVERSION
+***************************************************************************/
+
+/*-------------------------------------------------
+ ss_c2 - byte swap an array of 16-bit data
+-------------------------------------------------*/
+
+static void ss_c2(UINT8 *data, UINT32 size)
+{
+ UINT16 *convert = (UINT16 *)data;
+ unsigned i;
+
+ for (i = 0; i < size; i++)
+ convert[i] = FLIPENDIAN_INT16(convert[i]);
+}
+
+
+/*-------------------------------------------------
+ ss_c4 - byte swap an array of 32-bit data
+-------------------------------------------------*/
+
+static void ss_c4(UINT8 *data, UINT32 size)
+{
+ UINT32 *convert = (UINT32 *)data;
+ unsigned i;
+
+ for (i = 0; i < size; i++)
+ convert[i] = FLIPENDIAN_INT32(convert[i]);
+}
+
+
+/*-------------------------------------------------
+ ss_c8 - byte swap an array of 64-bit data
+-------------------------------------------------*/
+
+static void ss_c8(UINT8 *data, UINT32 size)
+{
+ UINT64 *convert = (UINT64 *)data;
+ unsigned i;
+
+ for (i = 0; i < size; i++)
+ convert[i] = FLIPENDIAN_INT64(convert[i]);
+}
+
+
+
+/***************************************************************************
+ PROCESSING HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ compute_size_and_offsets - compute the total
+ size and offsets of each individual item
+-------------------------------------------------*/
+
+static int compute_size_and_offsets(void)
+{
+ ss_entry *entry;
+ int total_size;
+
+ /* start with the header size */
+ total_size = 0x18;
+
+ /* iterate over entries */
+ for (entry = ss_registry; entry; entry = entry->next)
+ {
+ /* note the offset and accumulate a total size */
+ entry->offset = total_size;
+ total_size += entry->typesize * entry->typecount;
+ }
+
+ /* return the total size */
+ return total_size;
+}
+
+
+/*-------------------------------------------------
+ call_hook_functions - loop through all the
+ hook functions and call them
+-------------------------------------------------*/
+
+static int call_hook_functions(ss_func *funclist)
+{
+ ss_func *func;
+ int count = 0;
+
+ /* iterate over the list of functions */
+ for (func = funclist; func; func = func->next)
+ if (func->tag == ss_current_tag)
+ {
+ count++;
+
+ /* call with the appropriate parameters */
+ switch (func->type)
+ {
+ case FUNC_NOPARAM: (func->func.voidf)(); break;
+ case FUNC_INTPARAM: (func->func.intf)(func->param.intp); break;
+ case FUNC_PTRPARAM: (func->func.ptrf)(func->param.ptrp); break;
+ }
+ }
+
+ return count;
+}
+
+
+/*-------------------------------------------------
+ get_signature - compute the signature, which
+ is a CRC over the structure of the data
+-------------------------------------------------*/
+
+static UINT32 get_signature(void)
+{
+ ss_entry *entry;
+ UINT32 crc = 0;
+
+ /* iterate over entries */
+ for (entry = ss_registry; entry; entry = entry->next)
+ {
+ UINT32 temp[2];
+
+ /* add the entry name to the CRC */
+ crc = crc32(crc, (UINT8 *)astring_c(entry->name), astring_len(entry->name));
+
+ /* add the type and size to the CRC */
+ temp[0] = LITTLE_ENDIANIZE_INT32(entry->typecount);
+ temp[1] = LITTLE_ENDIANIZE_INT32(entry->typesize);
+ crc = crc32(crc, (UINT8 *)&temp[0], 8);
+ }
+
+ return crc;
+}
+
+
+
+/***************************************************************************
+ STATE FILE VALIDATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ validate_header - validate the data in the
+ header
+-------------------------------------------------*/
+
+static int validate_header(const UINT8 *header, const char *gamename, UINT32 signature,
+ void (CLIB_DECL *errormsg)(const char *fmt, ...), const char *error_prefix)
+{
+ /* check magic number */
+ if (memcmp(header, ss_magic_num, 8))
+ {
+ if (errormsg)
+ errormsg("%sThis is not a " APPNAME " save file", error_prefix);
+ return -1;
+ }
+
+ /* check save state version */
+ if (header[8] != SAVE_VERSION)
+ {
+ if (errormsg)
+ errormsg("%sWrong version in save file (%d, 1 expected)", error_prefix, header[8]);
+ return -1;
+ }
+
+ /* check gamename, if we were asked to */
+ if (gamename && strcmp(gamename, (const char *)&header[10]))
+ {
+ if (errormsg)
+ errormsg("%s'%s' is not a valid savestate file for game '%s'.", error_prefix, gamename);
+ return -1;
+ }
+
+ /* check signature, if we were asked to */
+ if (signature)
+ {
+ UINT32 rawsig = *(UINT32 *)&header[0x14];
+ UINT32 filesig = LITTLE_ENDIANIZE_INT32(rawsig);
+ if (signature != filesig)
+ {
+ if (errormsg)
+ errormsg("%sIncompatible save file (signature %08x, expected %08x)", error_prefix, filesig, signature);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ state_save_check_file - check if a file is
+ a valid save state
+-------------------------------------------------*/
+
+int state_save_check_file(mame_file *file, const char *gamename, int validate_signature, void (CLIB_DECL *errormsg)(const char *fmt, ...))
+{
+ UINT32 signature = 0;
+ UINT8 header[0x18];
+
+ /* if we want to validate the signature, compute it */
+ if (validate_signature)
+ signature = get_signature();
+
+ /* seek to the beginning and read the header */
+ mame_fseek(file, 0, SEEK_SET);
+ if (mame_fread(file, header, sizeof(header)) != sizeof(header))
+ {
+ if (errormsg)
+ errormsg("Could not read " APPNAME " save file header");
+ return -1;
+ }
+
+ /* let the generic header check work out the rest */
+ return validate_header(header, gamename, signature, errormsg, "");
+}
+
+
+
+/***************************************************************************
+ SAVE STATE PROCESSING
+***************************************************************************/
+
+/*-------------------------------------------------
+ state_save_save_begin - begin the process of
+ saving
+-------------------------------------------------*/
+
+int state_save_save_begin(mame_file *file)
+{
+ /* if we have illegal registrations, return an error */
+ if (ss_illegal_regs > 0)
+ return 1;
+
+ TRACE(logerror("Beginning save\n"));
+ ss_dump_file = file;
+
+ /* compute the total dump size and the offsets of each element */
+ ss_dump_size = compute_size_and_offsets();
+ TRACE(logerror(" total size %u\n", ss_dump_size));
+
+ /* allocate memory for the array */
+ ss_dump_array = malloc_or_die(ss_dump_size);
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ state_save_save_continue - save within the
+ current tag
+-------------------------------------------------*/
+
+void state_save_save_continue(void)
+{
+ ss_entry *entry;
+ int count;
+
+ TRACE(logerror("Saving tag %d\n", ss_current_tag));
+
+ /* call the pre-save functions */
+ TRACE(logerror(" calling pre-save functions\n"));
+ count = call_hook_functions(ss_prefunc_reg);
+ TRACE(logerror(" %d functions called\n", count));
+
+ /* then copy in all the data */
+ TRACE(logerror(" copying data\n"));
+
+ /* iterate over entries with matching tags */
+ for (entry = ss_registry; entry; entry = entry->next)
+ if (entry->tag == ss_current_tag)
+ {
+ memcpy(ss_dump_array + entry->offset, entry->data, entry->typesize * entry->typecount);
+ TRACE(logerror(" %s: %x..%x\n", astring_c(entry->name), entry->offset, entry->offset + entry->typesize * entry->typecount - 1));
+ }
+}
+
+
+/*-------------------------------------------------
+ state_save_save_finish - finish saving the
+ file by writing the header and closing
+-------------------------------------------------*/
+
+void state_save_save_finish(void)
+{
+ UINT32 signature;
+ UINT8 flags = 0;
+
+ TRACE(logerror("Finishing save\n"));
+
+ /* compute the flags */
+#ifndef LSB_FIRST
+ flags |= SS_MSB_FIRST;
+#endif
+
+ /* build up the header */
+ memcpy(ss_dump_array, ss_magic_num, 8);
+ ss_dump_array[8] = SAVE_VERSION;
+ ss_dump_array[9] = flags;
+ memset(ss_dump_array+0xa, 0, 10);
+ strcpy((char *)ss_dump_array+0xa, Machine->gamedrv->name);
+
+ /* copy in the signature */
+ signature = get_signature();
+ *(UINT32 *)&ss_dump_array[0x14] = LITTLE_ENDIANIZE_INT32(signature);
+
+ /* write the file */
+ mame_fwrite(ss_dump_file, ss_dump_array, ss_dump_size);
+
+ /* free memory and reset the global states */
+ free(ss_dump_array);
+ ss_dump_array = NULL;
+ ss_dump_size = 0;
+ ss_dump_file = NULL;
+}
+
+
+
+/***************************************************************************
+ LOAD STATE PROCESSING
+***************************************************************************/
+
+/*-------------------------------------------------
+ state_save_load_begin - begin the process
+ of loading the state
+-------------------------------------------------*/
+
+int state_save_load_begin(mame_file *file)
+{
+ TRACE(logerror("Beginning load\n"));
+
+ /* read the file into memory */
+ ss_dump_size = mame_fsize(file);
+ ss_dump_array = malloc_or_die(ss_dump_size);
+ ss_dump_file = file;
+ mame_fread(ss_dump_file, ss_dump_array, ss_dump_size);
+
+ /* verify the header and report an error if it doesn't match */
+ if (validate_header(ss_dump_array, NULL, get_signature(), popmessage, "Error: "))
+ {
+ free(ss_dump_array);
+ ss_dump_array = NULL;
+ ss_dump_size = 0;
+ ss_dump_file = NULL;
+ return 1;
+ }
+
+ /* compute the total size and offset of all the entries */
+ compute_size_and_offsets();
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ state_save_load_continue - load all state in
+ the current tag
+-------------------------------------------------*/
+
+void state_save_load_continue(void)
+{
+ ss_entry *entry;
+ int need_convert;
+ int count;
+
+ /* first determine whether or not we need to convert the endianness of the data */
+#ifdef LSB_FIRST
+ need_convert = (ss_dump_array[9] & SS_MSB_FIRST) != 0;
+#else
+ need_convert = (ss_dump_array[9] & SS_MSB_FIRST) == 0;
+#endif
+
+ TRACE(logerror("Loading tag %d\n", ss_current_tag));
+ TRACE(logerror(" copying data\n"));
+
+ /* iterate over entries with matching tags */
+ for (entry = ss_registry; entry; entry = entry->next)
+ if (entry->tag == ss_current_tag)
+ {
+ memcpy(entry->data, ss_dump_array + entry->offset, entry->typesize * entry->typecount);
+ if (need_convert && ss_conv[entry->typesize])
+ (*ss_conv[entry->typesize])(entry->data, entry->typecount);
+ TRACE(logerror(" %s: %x..%x\n", astring_c(entry->name), entry->offset, entry->offset + entry->typesize * entry->typecount - 1));
+ }
+
+ /* call the post-load functions */
+ TRACE(logerror(" calling post-load functions\n"));
+ count = call_hook_functions(ss_postfunc_reg);
+ TRACE(logerror(" %d functions called\n", count));
+}
+
+
+/*-------------------------------------------------
+ state_save_load_finish - complete the process
+ of loading the state
+-------------------------------------------------*/
+
+void state_save_load_finish(void)
+{
+ TRACE(logerror("Finishing load\n"));
+
+ /* free memory and reset the global states */
+ free(ss_dump_array);
+ ss_dump_array = NULL;
+ ss_dump_size = 0;
+ ss_dump_file = NULL;
+}
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+/*-------------------------------------------------
+ state_save_get_indexed_item - return an item
+ with the given index
+-------------------------------------------------*/
+
+const char *state_save_get_indexed_item(int index, void **base, UINT32 *valsize, UINT32 *valcount)
+{
+ ss_entry *ss;
+
+ for (ss = ss_registry; ss != NULL; ss = ss->next)
+ if (index-- == 0)
+ {
+ if (base != NULL)
+ *base = ss->data;
+ if (valsize != NULL)
+ *valsize = ss->typesize;
+ if (valcount != NULL)
+ *valcount = ss->typecount;
+ return astring_c(ss->name);
+ }
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ state_save_dump_registry - dump the registry
+ to the logfile
+-------------------------------------------------*/
+
+void state_save_dump_registry(void)
+{
+#ifdef VERBOSE
+ ss_entry *entry;
+
+ for (entry = ss_registry; entry; entry=entry->next)
+ logerror("%s: %d x %d\n", astring_c(entry->name), entry->typesize, entry->typecount);
+#endif
+}
+
diff --git a/src/emu/state.h b/src/emu/state.h
new file mode 100644
index 00000000000..0f4b3b5f7cb
--- /dev/null
+++ b/src/emu/state.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+
+ state.h
+
+ Save state management functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __STATE_H__
+#define __STATE_H__
+
+#include "mamecore.h"
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define IS_COMPATIBLE_TYPE(_valtype, _checktype) \
+ (sizeof(_valtype) == sizeof(_checktype) && TYPES_COMPATIBLE(typeof(_valtype), _checktype))
+
+#define IS_VALID_SAVE_TYPE(_valtype) \
+ (IS_COMPATIBLE_TYPE(_valtype, double) || IS_COMPATIBLE_TYPE(_valtype, float) || \
+ IS_COMPATIBLE_TYPE(_valtype, INT64) || IS_COMPATIBLE_TYPE(_valtype, UINT64) || \
+ IS_COMPATIBLE_TYPE(_valtype, INT32) || IS_COMPATIBLE_TYPE(_valtype, UINT32) || \
+ IS_COMPATIBLE_TYPE(_valtype, INT16) || IS_COMPATIBLE_TYPE(_valtype, UINT16) || \
+ IS_COMPATIBLE_TYPE(_valtype, INT8) || IS_COMPATIBLE_TYPE(_valtype, UINT8) || \
+ IS_COMPATIBLE_TYPE(_valtype, PAIR) || IS_COMPATIBLE_TYPE(_valtype, PAIR64))
+
+#define state_save_register_generic(_mod, _inst, _name, _val, _valsize, _count) \
+do { \
+ assert_always(IS_VALID_SAVE_TYPE(_valsize), "Invalid data type supplied for state saving.");\
+ state_save_register_memory(_mod, _inst, _name, _val, sizeof(_valsize), _count); \
+} while (0)
+
+#define state_save_register_item(_mod, _inst, _val) \
+ state_save_register_generic(_mod, _inst, #_val, &_val, _val, 1)
+
+#define state_save_register_item_pointer(_mod, _inst, _val, _count) \
+ state_save_register_generic(_mod, _inst, #_val, &_val[0], _val[0], _count)
+
+#define state_save_register_item_array(_mod, _inst, _val) \
+ state_save_register_item_pointer(_mod, _inst, _val, sizeof(_val)/sizeof(_val[0]))
+
+#define state_save_register_item_2d_array(_mod, _inst, _val) \
+ state_save_register_item_pointer(_mod, _inst, _val[0], sizeof(_val)/sizeof(_val[0][0]))
+
+#define state_save_register_global(_val) \
+ state_save_register_item("globals", 0, _val)
+
+#define state_save_register_global_pointer(_val, _count) \
+ state_save_register_item_pointer("globals", 0, _val, _count)
+
+#define state_save_register_global_array(_val) \
+ state_save_register_item_array("globals", 0, _val)
+
+#define state_save_register_global_2d_array(_val) \
+ state_save_register_item_2d_array("globals", 0, _val)
+
+#define state_save_register_global_bitmap(_val) \
+ state_save_register_bitmap("globals", 0, #_val, _val)
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void state_init(running_machine *machine);
+
+/* Initializes the save state registrations */
+void state_destructor(void *ptr, size_t size);
+void state_save_allow_registration(int allowed);
+int state_save_registration_allowed(void);
+
+/* Registering functions */
+int state_save_get_reg_count(void);
+
+void state_save_register_memory(const char *module, UINT32 instance, const char *name, void *val, UINT32 valsize, UINT32 valcount);
+void state_save_register_bitmap(const char *module, UINT32 instance, const char *name, mame_bitmap *val);
+
+void state_save_register_func_presave(void (*func)(void));
+void state_save_register_func_postload(void (*func)(void));
+
+void state_save_register_func_presave_int(void (*func)(int), int param);
+void state_save_register_func_postload_int(void (*func)(int), int param);
+
+void state_save_register_func_presave_ptr(void (*func)(void *), void *param);
+void state_save_register_func_postload_ptr(void (*func)(void *), void *param);
+
+/* Save and load functions */
+/* The tags are a hack around the current cpu structures */
+int state_save_save_begin(mame_file *file);
+int state_save_load_begin(mame_file *file);
+
+void state_save_push_tag(int tag);
+void state_save_pop_tag(void);
+
+void state_save_save_continue(void);
+void state_save_load_continue(void);
+
+void state_save_save_finish(void);
+void state_save_load_finish(void);
+
+/* Display function */
+void state_save_dump_registry(void);
+
+const char *state_save_get_indexed_item(int index, void **base, UINT32 *valsize, UINT32 *valcount);
+
+/* Verification function; can be called from front ends */
+int state_save_check_file(mame_file *file, const char *gamename, int validate_signature, void (CLIB_DECL *errormsg)(const char *fmt, ...));
+
+#endif /* __STATE_H__ */
diff --git a/src/emu/streams.c b/src/emu/streams.c
new file mode 100644
index 00000000000..e8b5d753f7f
--- /dev/null
+++ b/src/emu/streams.c
@@ -0,0 +1,881 @@
+/***************************************************************************
+
+ streams.c
+
+ Handle general purpose audio streams
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Streaming works as follows:
+
+ Each stream can have 'n' inputs and 'm' outputs. The inputs for a
+ stream are the outputs from another stream. Note that for tracking
+ purposes, each stream tracks its input streams directly, but does
+ not explicitly track its output streams. Instead, each output simply
+ tracks the number of dependent input streams.
+
+ Each stream has a sample rate. This rate controls the sample rate
+ of the outputs. All outputs on a stream output at the same sample
+ rate.
+
+ Each stream also has a callback function. This function is called
+ with an array of input sample streams, and an array out output
+ sample streams. The input sample streams are automatically resampled
+ by the streaming engine to match the stream's current sample rate.
+ The output sample streams are expected to be generated at the
+ stream's current sample rate.
+
+ Before the callback can be invoked, all the inputs that flow into it
+ must be updated as well. However, each stream can have an independent
+ sample rate, so this isn't as easy as it sounds.
+
+ To update a stream, the engine must iterate over all the inputs. For
+ each input, it requests that input to update to the current time.
+ Then it resamples the input data into a local resample buffer at the
+ stream's sample rate. Once all inputs are up-to-date, it calls the
+ callback with the array of resampled input sample buffers. The
+ callback is expected to fill in the array of output sample buffers.
+ These sample buffers can then be further resampled and passed to
+ other streams, or output as desired.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "streams.h"
+#include <math.h>
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE (0)
+
+#if VERBOSE
+#define VPRINTF(x) mame_printf_debug x
+#else
+#define VPRINTF(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define OUTPUT_BUFFER_UPDATES (5)
+
+#define FRAC_BITS 22
+#define FRAC_ONE (1 << FRAC_BITS)
+#define FRAC_MASK (FRAC_ONE - 1)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _stream_input stream_input;
+typedef struct _stream_output stream_output;
+
+struct _stream_input
+{
+ /* linking information */
+ sound_stream * owner; /* pointer to the owning stream */
+ stream_output * source; /* pointer to the sound_output for this source */
+
+ /* resample buffer */
+ stream_sample_t * resample; /* buffer for resampling to the stream's sample rate */
+ UINT32 bufsize; /* size of output buffer, in samples */
+ UINT32 bufalloc; /* allocated size of output buffer, in samples */
+
+ /* resampling information */
+ attoseconds_t latency_attoseconds; /* latency between this stream and the input stream */
+ INT16 gain; /* gain to apply to this input */
+};
+
+
+struct _stream_output
+{
+ /* linking information */
+ sound_stream * owner; /* pointer to the owning stream */
+
+ /* output buffer */
+ stream_sample_t * buffer; /* output buffer */
+
+ /* output buffer position */
+ int dependents; /* number of dependents */
+ INT16 gain; /* gain to apply to the output */
+};
+
+
+struct _sound_stream
+{
+ /* linking information */
+ sound_stream * next; /* next stream in the chain */
+ void * tag; /* tag (used for identification) */
+ int index; /* index for save states */
+
+ /* general information */
+ UINT32 sample_rate; /* sample rate of this stream */
+ UINT32 new_sample_rate; /* newly-set sample rate for the stream */
+
+ /* timing information */
+ attoseconds_t attoseconds_per_sample; /* number of attoseconds per sample */
+ INT32 max_samples_per_update; /* maximum samples per update */
+
+ /* input information */
+ int inputs; /* number of inputs */
+ stream_input * input; /* list of streams we directly depend upon */
+ stream_sample_t ** input_array; /* array of inputs for passing to the callback */
+
+ /* resample buffer information */
+ UINT32 resample_bufalloc; /* allocated size of each resample buffer */
+
+ /* output information */
+ int outputs; /* number of outputs */
+ stream_output * output; /* list of streams which directly depend upon us */
+ stream_sample_t ** output_array; /* array of outputs for passing to the callback */
+
+ /* output buffer information */
+ UINT32 output_bufalloc; /* allocated size of each output buffer */
+ INT32 output_sampindex; /* current position within each output buffer */
+ INT32 output_update_sampindex;/* position at time of last global update */
+ INT32 output_base_sampindex; /* sample at base of buffer, relative to the current emulated second */
+
+ /* callback information */
+ stream_callback callback; /* callback function */
+ void * param; /* callback function parameter */
+};
+
+
+struct _streams_private
+{
+ sound_stream * stream_head; /* pointer to first stream */
+ sound_stream ** stream_tailptr; /* pointer to pointer to last stream */
+ void * current_tag; /* current tag to assign to new streams */
+ int stream_index; /* index of the current stream */
+ attoseconds_t update_attoseconds; /* attoseconds between global updates */
+ attotime last_update; /* last update time */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void stream_postload(void *param);
+static void allocate_resample_buffers(streams_private *strdata, sound_stream *stream);
+static void allocate_output_buffers(streams_private *strdata, sound_stream *stream);
+static void recompute_sample_rate_data(streams_private *strdata, sound_stream *stream);
+static void generate_samples(sound_stream *stream, int samples);
+static stream_sample_t *generate_resampled_data(stream_input *input, UINT32 numsamples);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ time_to_sampindex - convert an absolute
+ time to a sample index in a given stream
+-------------------------------------------------*/
+
+INLINE INT32 time_to_sampindex(const streams_private *strdata, const sound_stream *stream, attotime time)
+{
+ /* determine the number of samples since the start of this second */
+ INT32 sample = (INT32)(time.attoseconds / stream->attoseconds_per_sample);
+
+ /* if we're ahead of the last update, then adjust upwards */
+ if (time.seconds > strdata->last_update.seconds)
+ {
+ assert(time.seconds == strdata->last_update.seconds + 1);
+ sample += stream->sample_rate;
+ }
+
+ /* if we're behind the last update, then adjust downwards */
+ if (time.seconds < strdata->last_update.seconds)
+ {
+ assert(time.seconds == strdata->last_update.seconds - 1);
+ sample -= stream->sample_rate;
+ }
+ return sample;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ streams_init - initialize the streams engine
+-------------------------------------------------*/
+
+void streams_init(running_machine *machine, attoseconds_t update_attoseconds)
+{
+ streams_private *strdata;
+
+ /* allocate memory for our private data */
+ strdata = auto_malloc(sizeof(*strdata));
+ memset(strdata, 0, sizeof(*strdata));
+
+ /* reset globals */
+ strdata->stream_tailptr = &strdata->stream_head;
+ strdata->update_attoseconds = update_attoseconds;
+
+ /* set the global pointer */
+ machine->streams_data = strdata;
+
+ /* register global states */
+ state_save_register_global(strdata->last_update.seconds);
+ state_save_register_global(strdata->last_update.attoseconds);
+}
+
+
+/*-------------------------------------------------
+ streams_update - update all the streams
+ periodically
+-------------------------------------------------*/
+
+void streams_update(running_machine *machine)
+{
+ streams_private *strdata = machine->streams_data;
+ attotime curtime = timer_get_time();
+ int second_tick = FALSE;
+ sound_stream *stream;
+
+ VPRINTF(("streams_update\n"));
+
+ /* see if we ticked over to the next second */
+ if (curtime.seconds != strdata->last_update.seconds)
+ {
+ assert(curtime.seconds == strdata->last_update.seconds + 1);
+ second_tick = TRUE;
+ }
+
+ /* iterate over all the streams */
+ for (stream = strdata->stream_head; stream != NULL; stream = stream->next)
+ {
+ INT32 output_bufindex = stream->output_sampindex - stream->output_base_sampindex;
+ int outputnum;
+
+ /* make sure this stream is up-to-date */
+ stream_update(stream);
+
+ /* if we've ticked over another second, adjust all the counters that are relative to
+ the current second */
+ if (second_tick)
+ {
+ stream->output_sampindex -= stream->sample_rate;
+ stream->output_base_sampindex -= stream->sample_rate;
+ }
+
+ /* note our current output sample */
+ stream->output_update_sampindex = stream->output_sampindex;
+
+ /* if we don't have enough output buffer space to hold two updates' worth of samples,
+ we need to shuffle things down */
+ if (stream->output_bufalloc - output_bufindex < 2 * stream->max_samples_per_update)
+ {
+ INT32 samples_to_lose = output_bufindex - stream->max_samples_per_update;
+ if (samples_to_lose > 0)
+ {
+ /* if we have samples to move, do so for each output */
+ if (output_bufindex > 0)
+ for (outputnum = 0; outputnum < stream->outputs; outputnum++)
+ {
+ stream_output *output = &stream->output[outputnum];
+ memmove(&output->buffer[0], &output->buffer[samples_to_lose], sizeof(output->buffer[0]) * (output_bufindex - samples_to_lose));
+ }
+
+ /* update the base position */
+ stream->output_base_sampindex += samples_to_lose;
+ }
+ }
+ }
+
+ /* remember the update time */
+ strdata->last_update = curtime;
+
+ /* update sample rates if they have changed */
+ for (stream = strdata->stream_head; stream != NULL; stream = stream->next)
+ if (stream->new_sample_rate != 0)
+ {
+ UINT32 old_rate = stream->sample_rate;
+ int outputnum;
+
+ /* update to the new rate and remember the old rate */
+ stream->sample_rate = stream->new_sample_rate;
+ stream->new_sample_rate = 0;
+
+ /* recompute all the data */
+ recompute_sample_rate_data(strdata, stream);
+
+ /* reset our sample indexes to the current time */
+ stream->output_sampindex = (INT64)stream->output_sampindex * (INT64)stream->sample_rate / old_rate;
+ stream->output_update_sampindex = (INT64)stream->output_update_sampindex * (INT64)stream->sample_rate / old_rate;
+ stream->output_base_sampindex = stream->output_sampindex - stream->max_samples_per_update;
+
+ /* clear out the buffer */
+ for (outputnum = 0; outputnum < stream->outputs; outputnum++)
+ memset(stream->output[outputnum].buffer, 0, stream->max_samples_per_update * sizeof(stream->output[outputnum].buffer[0]));
+ }
+}
+
+
+/*-------------------------------------------------
+ streams_set_tag - set the tag to be associated
+ with all streams allocated from now on
+-------------------------------------------------*/
+
+void streams_set_tag(running_machine *machine, void *streamtag)
+{
+ streams_private *strdata = machine->streams_data;
+ strdata->current_tag = streamtag;
+}
+
+
+/*-------------------------------------------------
+ stream_create - create a new stream
+-------------------------------------------------*/
+
+sound_stream *stream_create(int inputs, int outputs, int sample_rate, void *param, stream_callback callback)
+{
+ streams_private *strdata = Machine->streams_data;
+ int inputnum, outputnum;
+ sound_stream *stream;
+ char statetag[30];
+
+ /* allocate memory */
+ stream = auto_malloc(sizeof(*stream));
+ memset(stream, 0, sizeof(*stream));
+
+ VPRINTF(("stream_create(%d, %d, %d) => %p\n", inputs, outputs, sample_rate, stream));
+
+ /* fill in the data */
+ stream->tag = strdata->current_tag;
+ stream->index = strdata->stream_index++;
+ stream->sample_rate = sample_rate;
+ stream->inputs = inputs;
+ stream->outputs = outputs;
+ stream->callback = callback;
+ stream->param = param;
+
+ /* create a unique tag for saving */
+ sprintf(statetag, "stream.%d", stream->index);
+ state_save_register_item(statetag, 0, stream->sample_rate);
+ state_save_register_func_postload_ptr(stream_postload, stream);
+
+ /* allocate space for the inputs */
+ if (inputs > 0)
+ {
+ stream->input = auto_malloc(inputs * sizeof(*stream->input));
+ memset(stream->input, 0, inputs * sizeof(*stream->input));
+ stream->input_array = auto_malloc(inputs * sizeof(*stream->input_array));
+ memset(stream->input_array, 0, inputs * sizeof(*stream->input_array));
+ }
+
+ /* initialize the state of each input */
+ for (inputnum = 0; inputnum < inputs; inputnum++)
+ {
+ stream->input[inputnum].owner = stream;
+ stream->input[inputnum].gain = 0x100;
+ state_save_register_item(statetag, inputnum, stream->input[inputnum].gain);
+ }
+
+ /* allocate space for the outputs */
+ if (outputs > 0)
+ {
+ stream->output = auto_malloc(outputs * sizeof(*stream->output));
+ memset(stream->output, 0, outputs * sizeof(*stream->output));
+ stream->output_array = auto_malloc(outputs * sizeof(*stream->output_array));
+ memset(stream->output_array, 0, outputs * sizeof(*stream->output_array));
+ }
+
+ /* initialize the state of each output */
+ for (outputnum = 0; outputnum < outputs; outputnum++)
+ {
+ stream->output[outputnum].owner = stream;
+ stream->output[outputnum].gain = 0x100;
+ state_save_register_item(statetag, outputnum, stream->output[outputnum].gain);
+ }
+
+ /* hook us into the master stream list */
+ *strdata->stream_tailptr = stream;
+ strdata->stream_tailptr = &stream->next;
+
+ /* force an update to the sample rates; this will cause everything to be recomputed
+ and will generate the initial resample buffers for our inputs */
+ recompute_sample_rate_data(strdata, stream);
+
+ /* set up the initial output buffer positions now that we have data */
+ stream->output_base_sampindex = -stream->max_samples_per_update;
+
+ return stream;
+}
+
+
+/*-------------------------------------------------
+ stream_set_input - configure a stream's input
+-------------------------------------------------*/
+
+void stream_set_input(sound_stream *stream, int index, sound_stream *input_stream, int output_index, float gain)
+{
+ stream_input *input;
+
+ VPRINTF(("stream_set_input(%p, %d, %p, %d, %f)\n", stream, index, input_stream, output_index, gain));
+
+ /* make sure it's a valid input */
+ if (index >= stream->inputs)
+ fatalerror("Fatal error: stream_set_input attempted to configure non-existant input %d (%d max)", index, stream->inputs);
+
+ /* make sure it's a valid output */
+ if (input_stream != NULL && output_index >= input_stream->outputs)
+ fatalerror("Fatal error: stream_set_input attempted to use a non-existant output %d (%d max)", output_index, input_stream->outputs);
+
+ /* if this input is already wired, update the dependent info */
+ input = &stream->input[index];
+ if (input->source != NULL)
+ input->source->dependents--;
+
+ /* wire it up */
+ input->source = (input_stream != NULL) ? &input_stream->output[output_index] : NULL;
+ input->gain = (int)(0x100 * gain);
+
+ /* update the dependent info */
+ if (input->source != NULL)
+ input->source->dependents++;
+
+ /* update sample rates now that we know the input */
+ recompute_sample_rate_data(Machine->streams_data, stream);
+}
+
+
+/*-------------------------------------------------
+ stream_update - force a stream to update to
+ the current emulated time
+-------------------------------------------------*/
+
+void stream_update(sound_stream *stream)
+{
+ streams_private *strdata = Machine->streams_data;
+ INT32 update_sampindex = time_to_sampindex(strdata, stream, timer_get_time());
+
+ /* generate samples to get us up to the appropriate time */
+ assert(stream->output_sampindex - stream->output_base_sampindex >= 0);
+ assert(update_sampindex - stream->output_base_sampindex <= stream->output_bufalloc);
+ generate_samples(stream, update_sampindex - stream->output_sampindex);
+
+ /* remember this info for next time */
+ stream->output_sampindex = update_sampindex;
+}
+
+
+/*-------------------------------------------------
+ stream_find_by_tag - find a stream using a
+ tag and index
+-------------------------------------------------*/
+
+sound_stream *stream_find_by_tag(void *streamtag, int streamindex)
+{
+ streams_private *strdata = Machine->streams_data;
+ sound_stream *stream;
+
+ /* scan the list looking for the nth stream that matches the tag */
+ for (stream = strdata->stream_head; stream; stream = stream->next)
+ if (stream->tag == streamtag && streamindex-- == 0)
+ return stream;
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ stream_get_inputs - return the number of
+ inputs for a given stream
+-------------------------------------------------*/
+
+int stream_get_inputs(sound_stream *stream)
+{
+ return stream->inputs;
+}
+
+
+/*-------------------------------------------------
+ stream_get_outputs - return the number of
+ outputs for a given stream
+-------------------------------------------------*/
+
+int stream_get_outputs(sound_stream *stream)
+{
+ return stream->outputs;
+}
+
+
+/*-------------------------------------------------
+ stream_set_input_gain - set the input gain on
+ a given stream
+-------------------------------------------------*/
+
+void stream_set_input_gain(sound_stream *stream, int input, float gain)
+{
+ stream_update(stream);
+ stream->input[input].gain = (int)(0x100 * gain);
+}
+
+
+/*-------------------------------------------------
+ stream_set_output_gain - set the output gain on
+ a given stream
+-------------------------------------------------*/
+
+void stream_set_output_gain(sound_stream *stream, int output, float gain)
+{
+ stream_update(stream);
+ stream->output[output].gain = (int)(0x100 * gain);
+}
+
+
+/*-------------------------------------------------
+ stream_set_sample_rate - set the sample rate
+ on a given stream
+-------------------------------------------------*/
+
+void stream_set_sample_rate(sound_stream *stream, int sample_rate)
+{
+ /* we will update this on the next global update */
+ if ((stream->new_sample_rate == 0 && sample_rate != stream->sample_rate) || (stream->new_sample_rate != 0 && sample_rate != stream->new_sample_rate))
+ stream->new_sample_rate = sample_rate;
+}
+
+
+/*-------------------------------------------------
+ stream_get_output_since_last_update - return a
+ pointer to the output buffer and the number of
+ samples since the last global update
+-------------------------------------------------*/
+
+const stream_sample_t *stream_get_output_since_last_update(sound_stream *stream, int outputnum, int *numsamples)
+{
+ stream_output *output = &stream->output[outputnum];
+
+ /* force an update on the stream */
+ stream_update(stream);
+
+ /* compute the number of samples and a pointer to the output buffer */
+ *numsamples = stream->output_sampindex - stream->output_update_sampindex;
+ return output->buffer + (stream->output_update_sampindex - stream->output_base_sampindex);
+}
+
+
+
+/***************************************************************************
+ STREAM BUFFER MAINTENANCE
+***************************************************************************/
+
+/*-------------------------------------------------
+ stream_postload - save/restore callback
+-------------------------------------------------*/
+
+static void stream_postload(void *param)
+{
+ streams_private *strdata = Machine->streams_data;
+ sound_stream *stream = param;
+ int outputnum;
+
+ /* recompute the same rate information */
+ recompute_sample_rate_data(strdata, stream);
+
+ /* make sure our output buffers are fully cleared */
+ for (outputnum = 0; outputnum < stream->outputs; outputnum++)
+ memset(stream->output[outputnum].buffer, 0, stream->output_bufalloc * sizeof(stream->output[outputnum].buffer[0]));
+
+ /* recompute the sample indexes to make sense */
+ stream->output_sampindex = strdata->last_update.attoseconds / stream->attoseconds_per_sample;
+ stream->output_update_sampindex = stream->output_sampindex;
+ stream->output_base_sampindex = stream->output_sampindex - stream->max_samples_per_update;
+}
+
+
+/*-------------------------------------------------
+ allocate_resample_buffers - recompute the
+ resample buffer sizes and expand if necessary
+-------------------------------------------------*/
+
+static void allocate_resample_buffers(streams_private *strdata, sound_stream *stream)
+{
+ /* compute the target number of samples */
+ INT32 bufsize = 2 * stream->max_samples_per_update;
+
+ /* if we don't have enough room, allocate more */
+ if (stream->resample_bufalloc < bufsize)
+ {
+ int inputnum;
+
+ /* this becomes the new allocation size */
+ stream->resample_bufalloc = bufsize;
+
+ /* iterate over outputs and realloc their buffers */
+ for (inputnum = 0; inputnum < stream->inputs; inputnum++)
+ {
+ stream_input *input = &stream->input[inputnum];
+ input->resample = auto_realloc(input->resample, stream->resample_bufalloc * sizeof(input->resample[0]));
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ allocate_output_buffers - recompute the
+ output buffer sizes and expand if necessary
+-------------------------------------------------*/
+
+static void allocate_output_buffers(streams_private *strdata, sound_stream *stream)
+{
+ /* compute the target number of samples */
+ INT32 bufsize = OUTPUT_BUFFER_UPDATES * stream->max_samples_per_update;
+
+ /* if we don't have enough room, allocate more */
+ if (stream->output_bufalloc < bufsize)
+ {
+ int outputnum;
+ int oldsize;
+
+ /* this becomes the new allocation size */
+ oldsize = stream->output_bufalloc;
+ stream->output_bufalloc = bufsize;
+
+ /* iterate over outputs and realloc their buffers */
+ for (outputnum = 0; outputnum < stream->outputs; outputnum++)
+ {
+ stream_output *output = &stream->output[outputnum];
+ output->buffer = auto_realloc(output->buffer, stream->output_bufalloc * sizeof(output->buffer[0]));
+ memset(&output->buffer[oldsize], 0, (stream->output_bufalloc - oldsize) * sizeof(output->buffer[0]));
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ recompute_sample_rate_data - recompute sample
+ rate data, and all streams that are affected
+ by this stream
+-------------------------------------------------*/
+
+static void recompute_sample_rate_data(streams_private *strdata, sound_stream *stream)
+{
+ int inputnum;
+
+ /* recompute the timing parameters */
+ stream->attoseconds_per_sample = ATTOSECONDS_PER_SECOND / stream->sample_rate;
+ stream->max_samples_per_update = (strdata->update_attoseconds + stream->attoseconds_per_sample - 1) / stream->attoseconds_per_sample;
+
+ /* update resample and output buffer sizes */
+ allocate_resample_buffers(strdata, stream);
+ allocate_output_buffers(strdata, stream);
+
+ /* iterate over each input */
+ for (inputnum = 0; inputnum < stream->inputs; inputnum++)
+ {
+ stream_input *input = &stream->input[inputnum];
+
+ /* if we have a source, see if its sample rate changed */
+ if (input->source != NULL)
+ {
+ sound_stream *input_stream = input->source->owner;
+ attoseconds_t new_attosecs_per_sample = ATTOSECONDS_PER_SECOND / input_stream->sample_rate;
+ attoseconds_t latency;
+
+ /* okay, we have a new sample rate; recompute the latency to be the maximum
+ sample period between us and our input */
+ latency = MAX(new_attosecs_per_sample, stream->attoseconds_per_sample);
+
+ /* if the input stream's sample rate is lower, we will use linear interpolation */
+ /* this requires an extra sample from the source */
+ if (input_stream->sample_rate < stream->sample_rate)
+ latency += new_attosecs_per_sample;
+
+ /* if our sample rates match exactly, we don't need any latency */
+ else if (input_stream->sample_rate == stream->sample_rate)
+ latency = 0;
+
+ /* we generally don't want to tweak the latency, so we just keep the greatest
+ one we've computed thus far */
+ input->latency_attoseconds = MAX(input->latency_attoseconds, latency);
+ assert(input->latency_attoseconds < strdata->update_attoseconds);
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ SOUND GENERATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ generate_samples - generate the requested
+ number of samples for a stream, making sure
+ all inputs have the appropriate number of
+ samples generated
+-------------------------------------------------*/
+
+static void generate_samples(sound_stream *stream, int samples)
+{
+ int inputnum, outputnum;
+
+ /* if we're already there, skip it */
+ if (samples <= 0)
+ return;
+
+ VPRINTF(("generate_samples(%p, %d)\n", stream, samples));
+
+ /* ensure all inputs are up to date and generate resampled data */
+ for (inputnum = 0; inputnum < stream->inputs; inputnum++)
+ {
+ stream_input *input = &stream->input[inputnum];
+
+ /* update the stream to the current time */
+ if (input->source != NULL)
+ stream_update(input->source->owner);
+
+ /* generate the resampled data */
+ stream->input_array[inputnum] = generate_resampled_data(input, samples);
+ }
+
+ /* loop over all outputs and compute the output pointer */
+ for (outputnum = 0; outputnum < stream->outputs; outputnum++)
+ {
+ stream_output *output = &stream->output[outputnum];
+ stream->output_array[outputnum] = output->buffer + (stream->output_sampindex - stream->output_base_sampindex);
+ }
+
+ /* run the callback */
+ VPRINTF((" callback(%p, %d)\n", stream, samples));
+ (*stream->callback)(stream->param, stream->input_array, stream->output_array, samples);
+ VPRINTF((" callback done\n"));
+}
+
+
+/*-------------------------------------------------
+ generate_resampled_data - generate the
+ resample buffer for a given input
+-------------------------------------------------*/
+
+static stream_sample_t *generate_resampled_data(stream_input *input, UINT32 numsamples)
+{
+ stream_sample_t *dest = input->resample;
+ stream_output *output = input->source;
+ sound_stream *stream = input->owner;
+ sound_stream *input_stream;
+ stream_sample_t *source;
+ stream_sample_t sample;
+ attoseconds_t basetime;
+ INT32 basesample;
+ UINT32 basefrac;
+ UINT32 step;
+ int gain;
+
+ /* if we don't have an output to pull data from, generate silence */
+ if (output == NULL)
+ {
+ memset(dest, 0, numsamples * sizeof(*dest));
+ return input->resample;
+ }
+
+ /* grab data from the output */
+ input_stream = output->owner;
+ gain = (input->gain * output->gain) >> 8;
+
+ /* determine the time at which the current sample begins, accounting for the
+ latency we calculated between the input and output streams */
+ basetime = stream->output_sampindex * stream->attoseconds_per_sample - input->latency_attoseconds;
+
+ /* now convert that time into a sample in the input stream */
+ if (basetime >= 0)
+ basesample = basetime / input_stream->attoseconds_per_sample;
+ else
+ basesample = -(-basetime / input_stream->attoseconds_per_sample) - 1;
+
+ /* compute a source pointer to the first sample */
+ assert(basesample >= input_stream->output_base_sampindex);
+ source = output->buffer + (basesample - input_stream->output_base_sampindex);
+
+ /* determine the current fraction of a sample */
+ basefrac = (basetime - basesample * input_stream->attoseconds_per_sample) / (ATTOSECONDS_PER_SECOND >> FRAC_BITS);
+ assert(basefrac >= 0);
+ assert(basefrac < FRAC_ONE);
+
+ /* compute the stepping fraction */
+ step = ((UINT64)input_stream->sample_rate << FRAC_BITS) / stream->sample_rate;
+
+ /* if we have equal sample rates, we just need to copy */
+ if (step == FRAC_ONE)
+ {
+ while (numsamples--)
+ {
+ /* compute the sample */
+ sample = *source++;
+ *dest++ = (sample * gain) >> 8;
+ }
+ }
+
+ /* input is undersampled: use linear interpolation */
+ else if (step < FRAC_ONE)
+ {
+ while (numsamples--)
+ {
+ int interp_frac = basefrac >> (FRAC_BITS - 12);
+
+ /* compute the sample */
+ sample = (source[0] * (0x1000 - interp_frac) + source[1] * interp_frac) >> 12;
+ *dest++ = (sample * gain) >> 8;
+
+ /* advance */
+ basefrac += step;
+ source += basefrac >> FRAC_BITS;
+ basefrac &= FRAC_MASK;
+ }
+ }
+
+ /* input is oversampled: sum the energy */
+ else
+ {
+ /* use 8 bits to allow some extra headroom */
+ int smallstep = step >> (FRAC_BITS - 8);
+
+ while (numsamples--)
+ {
+ int remainder = smallstep;
+ int tpos = 0;
+ int scale;
+
+ /* compute the sample */
+ scale = (FRAC_ONE - basefrac) >> (FRAC_BITS - 8);
+ sample = source[tpos++] * scale;
+ remainder -= scale;
+ while (remainder > 0x100)
+ {
+ sample += source[tpos++] * 0x100;
+ remainder -= 0x100;
+ }
+ sample += source[tpos] * remainder;
+ sample /= smallstep;
+
+ *dest++ = (sample * gain) >> 8;
+
+ /* advance */
+ basefrac += step;
+ source += basefrac >> FRAC_BITS;
+ basefrac &= FRAC_MASK;
+ }
+ }
+
+ return input->resample;
+}
diff --git a/src/emu/streams.h b/src/emu/streams.h
new file mode 100644
index 00000000000..130fc256c55
--- /dev/null
+++ b/src/emu/streams.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+
+ streams.h
+
+ Handle general purpose audio streams
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef STREAMS_H
+#define STREAMS_H
+
+#include "mamecore.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _sound_stream sound_stream;
+
+typedef void (*stream_callback)(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void streams_init(running_machine *machine, attoseconds_t update_subseconds);
+void streams_set_tag(running_machine *machine, void *streamtag);
+void streams_update(running_machine *machine);
+
+/* core stream configuration and operation */
+sound_stream *stream_create(int inputs, int outputs, int sample_rate, void *param, stream_callback callback);
+void stream_set_input(sound_stream *stream, int index, sound_stream *input_stream, int output_index, float gain);
+void stream_update(sound_stream *stream);
+const stream_sample_t *stream_get_output_since_last_update(sound_stream *stream, int outputnum, int *numsamples);
+
+/* utilities for accessing a particular stream */
+sound_stream *stream_find_by_tag(void *streamtag, int streamindex);
+int stream_get_inputs(sound_stream *stream);
+int stream_get_outputs(sound_stream *stream);
+void stream_set_input_gain(sound_stream *stream, int input, float gain);
+void stream_set_output_gain(sound_stream *stream, int output, float gain);
+void stream_set_sample_rate(sound_stream *stream, int sample_rate);
+
+#endif
diff --git a/src/emu/tilemap.c b/src/emu/tilemap.c
new file mode 100644
index 00000000000..d2d0f9cbe83
--- /dev/null
+++ b/src/emu/tilemap.c
@@ -0,0 +1,2402 @@
+/***************************************************************************
+
+ tilemap.c
+
+ Generic tilemap management system.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "tilemap.h"
+#include "profiler.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* internal usage to mark tiles dirty */
+#define TILE_FLAG_DIRTY 0xff
+
+/* invalid logical index */
+#define INVALID_LOGICAL_INDEX ((tilemap_logical_index)~0)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* logical index */
+typedef UINT32 tilemap_logical_index;
+
+
+/* internal set of transparency states for rendering */
+typedef enum
+{
+ WHOLLY_TRANSPARENT,
+ WHOLLY_OPAQUE,
+ MASKED
+} trans_t;
+
+
+/* internal blitting callbacks */
+typedef void (*blitmask_t)(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode);
+typedef void (*blitopaque_t)(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode);
+
+
+/* blitting parameters for rendering */
+typedef struct _blit_parameters blit_parameters;
+struct _blit_parameters
+{
+ mame_bitmap * bitmap;
+ rectangle cliprect;
+ blitmask_t draw_masked;
+ blitopaque_t draw_opaque;
+ UINT32 tilemap_priority_code;
+ UINT8 mask;
+ UINT8 value;
+};
+
+
+/* core tilemap structure */
+struct _tilemap
+{
+ tilemap * next; /* pointer to next tilemap */
+
+ /* basic tilemap metrics */
+ tilemap_type type; /* type of tilemap */
+ UINT32 rows; /* number of tile rows */
+ UINT32 cols; /* number of tile columns */
+ UINT32 tilewidth; /* width of a single tile in pixels */
+ UINT32 tileheight; /* height of a single tile in pixels */
+ UINT32 width; /* width of the full tilemap in pixels */
+ UINT32 height; /* height of the full tilemap in pixels */
+
+ /* logical <-> memory mappings */
+ tilemap_mapper_callback mapper; /* callback to map a row/column to a memory index */
+ tilemap_logical_index * memory_to_logical; /* map from memory index to logical index */
+ tilemap_logical_index max_logical_index; /* maximum valid logical index */
+ tilemap_memory_index * logical_to_memory; /* map from logical index to memory index */
+ tilemap_memory_index max_memory_index; /* maximum valid memory index */
+
+ /* callback to interpret video RAM for the tilemap */
+ tile_get_info_callback tile_get_info; /* callback to get information about a tile */
+ tile_data tileinfo; /* structure to hold the data for a tile */
+ void * user_data; /* user data value passed to the callback */
+
+ /* global tilemap states */
+ UINT8 enable; /* true if we are enabled */
+ UINT8 attributes; /* global attributes (flipx/y) */
+ UINT8 all_tiles_dirty; /* true if all tiles are dirty */
+ UINT8 all_tiles_clean; /* true if all tiles are clean */
+ UINT32 palette_offset; /* palette offset */
+
+ /* scroll information */
+ UINT32 scrollrows; /* number of independently scrolled rows */
+ UINT32 scrollcols; /* number of independently scrolled colums */
+ INT32 * rowscroll; /* array of rowscroll values */
+ INT32 * colscroll; /* array of colscroll values */
+ INT32 dx; /* global horizontal scroll offset */
+ INT32 dx_flipped; /* global horizontal scroll offset when flipped */
+ INT32 dy; /* global vertical scroll offset */
+ INT32 dy_flipped; /* global vertical scroll offset when flipped */
+
+ /* pixel data */
+ mame_bitmap * pixmap; /* cached pixel data */
+
+ /* transparency mapping */
+ mame_bitmap * flagsmap; /* per-pixel flags */
+ UINT8 * tileflags; /* per-tile flags */
+ UINT8 * pen_to_flags; /* mapping of pens to flags */
+ UINT32 max_pen_to_flags; /* maximum index in each array */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+mame_bitmap * priority_bitmap;
+
+static tilemap * tilemap_list;
+static tilemap ** tilemap_tailptr;
+static int tilemap_instance;
+
+static UINT32 screen_width, screen_height;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* system management helpers */
+static void tilemap_exit(running_machine *machine);
+static void tilemap_postload(void *param);
+static void tilemap_dispose(tilemap *tmap);
+
+/* logical <-> memory index mapping */
+static void mappings_create(tilemap *tmap);
+static void mappings_update(tilemap *tmap);
+
+/* tile rendering */
+static void pixmap_update(tilemap *tmap, const rectangle *cliprect);
+static void tile_update(tilemap *tmap, tilemap_logical_index logindex, UINT32 cached_col, UINT32 cached_row);
+static UINT8 tile_draw(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags);
+static UINT8 tile_draw_colortable(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags);
+static UINT8 tile_draw_colortrans(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags);
+static UINT8 tile_apply_bitmask(tilemap *tmap, const UINT8 *maskdata, UINT32 x0, UINT32 y0, UINT8 category, UINT8 flags);
+
+/* drawing helpers */
+static void configure_blit_parameters(blit_parameters *blit, tilemap *tmap, mame_bitmap *dest, const rectangle *cliprect, UINT32 flags, UINT8 priority, UINT8 priority_mask);
+static void tilemap_draw_instance(tilemap *tmap, const blit_parameters *blit, int xpos, int ypos);
+static void tilemap_draw_roz_core(tilemap *tmap, const blit_parameters *blit,
+ UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, int wraparound);
+
+/* scanline rasterizers for drawing to the pixmap */
+static void scanline_draw_opaque_null(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_masked_null(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_opaque_ind16(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_masked_ind16(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_opaque_rgb16(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_masked_rgb16(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_opaque_rgb16_alpha(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_masked_rgb16_alpha(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_opaque_rgb32(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_masked_rgb32(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_opaque_rgb32_alpha(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode);
+static void scanline_draw_masked_rgb32_alpha(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ effective_rowscroll - return the effective
+ rowscroll value for a given index, taking into
+ account tilemap flip states
+-------------------------------------------------*/
+
+INLINE INT32 effective_rowscroll(tilemap *tmap, int index)
+{
+ INT32 value;
+
+ /* if we're flipping vertically, adjust the row number */
+ if (tmap->attributes & TILEMAP_FLIPY)
+ index = tmap->scrollrows - 1 - index;
+
+ /* adjust final result based on the horizontal flip and dx values */
+ if (!(tmap->attributes & TILEMAP_FLIPX))
+ value = tmap->dx - tmap->rowscroll[index];
+ else
+ value = screen_width - tmap->width - (tmap->dx_flipped - tmap->rowscroll[index]);
+
+ /* clamp to 0..width */
+ if (value < 0)
+ value = tmap->width - (-value) % tmap->width;
+ else
+ value %= tmap->width;
+ return value;
+}
+
+
+/*-------------------------------------------------
+ effective_colscroll - return the effective
+ colscroll value for a given index, taking into
+ account tilemap flip states
+-------------------------------------------------*/
+
+INLINE INT32 effective_colscroll(tilemap *tmap, int index)
+{
+ INT32 value;
+
+ /* if we're flipping horizontally, adjust the column number */
+ if (tmap->attributes & TILEMAP_FLIPX)
+ index = tmap->scrollcols - 1 - index;
+
+ /* adjust final result based on the vertical flip and dx values */
+ if (!(tmap->attributes & TILEMAP_FLIPY))
+ value = tmap->dy - tmap->colscroll[index];
+ else
+ value = screen_height - tmap->height - (tmap->dy_flipped - tmap->colscroll[index]);
+
+ /* clamp to 0..height */
+ if (value < 0)
+ value = tmap->height - (-value) % tmap->height;
+ else
+ value %= tmap->height;
+ return value;
+}
+
+
+/*-------------------------------------------------
+ indexed_tilemap - return a tilemap by index
+-------------------------------------------------*/
+
+INLINE tilemap *indexed_tilemap(int index)
+{
+ tilemap *tmap;
+
+ /* find by the tilemap index */
+ for (tmap = tilemap_list; tmap != NULL; tmap = tmap->next)
+ if (index-- == 0)
+ return tmap;
+
+ return NULL;
+}
+
+
+
+/***************************************************************************
+ SYSTEM-WIDE MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_init - initialize the tilemap system
+-------------------------------------------------*/
+
+void tilemap_init(running_machine *machine)
+{
+ screen_width = Machine->screen[0].width;
+ screen_height = Machine->screen[0].height;
+
+ tilemap_list = NULL;
+ tilemap_tailptr = &tilemap_list;
+ tilemap_instance = 0;
+
+ priority_bitmap = auto_bitmap_alloc(screen_width, screen_height, BITMAP_FORMAT_INDEXED8);
+ add_exit_callback(machine, tilemap_exit);
+}
+
+
+
+/***************************************************************************
+ TILEMAP CREATION AND CONFIGURATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_create - allocate a new tilemap
+-------------------------------------------------*/
+
+tilemap *tilemap_create(tile_get_info_callback tile_get_info, tilemap_mapper_callback mapper, tilemap_type type, int tilewidth, int tileheight, int cols, int rows)
+{
+ tilemap *tmap;
+ int group;
+
+ /* allocate the tilemap itself */
+ tmap = malloc_or_die(sizeof(tilemap));
+ memset(tmap, 0, sizeof(tilemap));
+
+ /* fill in the basic metrics */
+ tmap->type = type;
+ tmap->rows = rows;
+ tmap->cols = cols;
+ tmap->tilewidth = tilewidth;
+ tmap->tileheight = tileheight;
+ tmap->width = cols * tilewidth;
+ tmap->height = rows * tileheight;
+
+ /* set up the logical <-> memory mappings */
+ tmap->mapper = mapper;
+ mappings_create(tmap);
+
+ /* set up the tile map callbacks */
+ tmap->tile_get_info = tile_get_info;
+
+ /* initialize global states */
+ tmap->enable = TRUE;
+ tmap->all_tiles_dirty = TRUE;
+
+ /* initialize scroll information */
+ tmap->scrollrows = 1;
+ tmap->scrollcols = 1;
+ tmap->rowscroll = malloc_or_die(tmap->height * sizeof(*tmap->rowscroll));
+ memset(tmap->rowscroll, 0, tmap->height * sizeof(*tmap->rowscroll));
+ tmap->colscroll = malloc_or_die(tmap->width * sizeof(*tmap->colscroll));
+ memset(tmap->colscroll, 0, tmap->width * sizeof(*tmap->colscroll));
+
+ /* allocate the pixel data cache */
+ tmap->pixmap = bitmap_alloc(tmap->width, tmap->height, BITMAP_FORMAT_INDEXED16);
+
+ /* allocate transparency mapping data */
+ tmap->tileflags = malloc_or_die(tmap->max_logical_index);
+ tmap->flagsmap = bitmap_alloc(tmap->width, tmap->height, BITMAP_FORMAT_INDEXED8);
+ tmap->max_pen_to_flags = (tmap->type != TILEMAP_TYPE_COLORTABLE) ? 256 : Machine->drv->color_table_len;
+ tmap->pen_to_flags = malloc_or_die(sizeof(tmap->pen_to_flags[0]) * tmap->max_pen_to_flags * TILEMAP_NUM_GROUPS);
+ for (group = 0; group < TILEMAP_NUM_GROUPS; group++)
+ tilemap_map_pens_to_layer(tmap, group, 0, 0, TILEMAP_PIXEL_LAYER0);
+
+ /* add us to the end of the list of tilemaps */
+ *tilemap_tailptr = tmap;
+ tilemap_tailptr = &tmap->next;
+
+ /* save relevant state */
+ state_save_register_item("tilemap", tilemap_instance, tmap->enable);
+ state_save_register_item("tilemap", tilemap_instance, tmap->attributes);
+ state_save_register_item("tilemap", tilemap_instance, tmap->palette_offset);
+ state_save_register_item("tilemap", tilemap_instance, tmap->scrollrows);
+ state_save_register_item("tilemap", tilemap_instance, tmap->scrollcols);
+ state_save_register_item_pointer("tilemap", tilemap_instance, tmap->rowscroll, rows * tileheight);
+ state_save_register_item_pointer("tilemap", tilemap_instance, tmap->colscroll, cols * tilewidth);
+ state_save_register_item("tilemap", tilemap_instance, tmap->dx);
+ state_save_register_item("tilemap", tilemap_instance, tmap->dx_flipped);
+ state_save_register_item("tilemap", tilemap_instance, tmap->dy);
+ state_save_register_item("tilemap", tilemap_instance, tmap->dy_flipped);
+ tilemap_instance++;
+
+ /* reset everything after a load */
+ state_save_register_func_postload_ptr(tilemap_postload, tmap);
+ return tmap;
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_user_data - specify a parameter
+ to be passed into the tile_get_info callback
+-------------------------------------------------*/
+
+void tilemap_set_user_data(tilemap *tmap, void *user_data)
+{
+ tmap->user_data = user_data;
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_palette_offset - specify an offset
+ to be added to each pixel before looking up
+ the palette
+-------------------------------------------------*/
+
+void tilemap_set_palette_offset(tilemap *tmap, UINT32 offset)
+{
+ if (tmap->palette_offset != offset)
+ {
+ tmap->palette_offset = offset;
+ tilemap_mark_all_tiles_dirty(tmap);
+ }
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_enable - set an enable flag for
+ the tilemap; if 0, requests to draw the
+ tilemap are ignored
+-------------------------------------------------*/
+
+void tilemap_set_enable(tilemap *tmap, int enable)
+{
+ tmap->enable = (enable != 0);
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_flip - set a global flip for the
+ tilemap; ALL_TILEMAPS can be passed here as
+ well
+-------------------------------------------------*/
+
+void tilemap_set_flip(tilemap *tmap, UINT32 attributes)
+{
+ /* handle ALL_TILEMAPS */
+ if (tmap == ALL_TILEMAPS)
+ {
+ for (tmap = tilemap_list; tmap != NULL; tmap = tmap->next)
+ tilemap_set_flip(tmap, attributes);
+ }
+
+ /* if we're changing things, force a refresh of the mappings and mark it all dirty */
+ else if (tmap->attributes != attributes)
+ {
+ tmap->attributes = attributes;
+ mappings_update(tmap);
+ }
+}
+
+
+
+/***************************************************************************
+ DIRTY TILE MARKING
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_mark_tile_dirty - mark a single tile
+ dirty based on its memory index
+-------------------------------------------------*/
+
+void tilemap_mark_tile_dirty(tilemap *tmap, tilemap_memory_index memindex)
+{
+ /* only mark if within range */
+ if (memindex < tmap->max_memory_index)
+ {
+ tilemap_logical_index logindex = tmap->memory_to_logical[memindex];
+
+ /* there may be no logical index for a given memory index */
+ if (logindex != INVALID_LOGICAL_INDEX)
+ {
+ tmap->tileflags[logindex] = TILE_FLAG_DIRTY;
+ tmap->all_tiles_clean = FALSE;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ tilemap_mark_all_tiles_dirty - mark all the
+ tiles in a tilemap dirty
+-------------------------------------------------*/
+
+void tilemap_mark_all_tiles_dirty(tilemap *tmap)
+{
+ /* handle ALL_TILEMAPS */
+ if (tmap == ALL_TILEMAPS)
+ {
+ for (tmap = tilemap_list; tmap != NULL; tmap = tmap->next)
+ tilemap_mark_all_tiles_dirty(tmap);
+ }
+
+ /* mark all tiles dirty and clear the clean flag */
+ else
+ {
+ tmap->all_tiles_dirty = TRUE;
+ tmap->all_tiles_clean = FALSE;
+ }
+}
+
+
+
+/***************************************************************************
+ PEN-TO-LAYER MAPPING
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_map_pens_to_layer - specify the
+ mapping of one or more pens (where
+ (<pen> & mask) == pen) to a layer
+-------------------------------------------------*/
+
+void tilemap_map_pens_to_layer(tilemap *tmap, int group, pen_t pen, pen_t mask, UINT8 layermask)
+{
+ UINT8 *array = tmap->pen_to_flags + group * tmap->max_pen_to_flags;
+ pen_t start, stop, cur;
+ UINT8 changed = FALSE;
+
+ assert(group < TILEMAP_NUM_GROUPS);
+ assert((layermask & TILEMAP_PIXEL_CATEGORY_MASK) == 0);
+
+ /* we start at the index where (pen & mask) == pen, and all other bits are 0 */
+ start = pen & mask;
+
+ /* we stop at the index where (pen & mask) == pen, and all other bits are 1 */
+ stop = start | ~mask;
+
+ /* clamp to the number of entries actually there */
+ stop = MIN(stop, tmap->max_pen_to_flags - 1);
+
+ /* iterate and set */
+ for (cur = start; cur <= stop; cur++)
+ if ((cur & mask) == pen && array[cur] != layermask)
+ {
+ changed = TRUE;
+ array[cur] = layermask;
+ }
+
+ /* everything gets dirty if anything changed */
+ if (changed)
+ tilemap_mark_all_tiles_dirty(tmap);
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_transparent_pen - set a single
+ transparent pen into the tilemap, mapping
+ all other pens to layer 0
+-------------------------------------------------*/
+
+void tilemap_set_transparent_pen(tilemap *tmap, pen_t pen)
+{
+ /* reset the whole pen map to opaque */
+ tilemap_map_pens_to_layer(tmap, 0, 0, 0, TILEMAP_PIXEL_LAYER0);
+
+ /* set the single pen to transparent */
+ tilemap_map_pen_to_layer(tmap, 0, pen, TILEMAP_PIXEL_TRANSPARENT);
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_transmask - set up the first 32
+ pens using a foreground mask (mapping to
+ layer 0) and a background mask (mapping to
+ layer 1)
+-------------------------------------------------*/
+
+void tilemap_set_transmask(tilemap *tmap, int group, UINT32 fgmask, UINT32 bgmask)
+{
+ pen_t pen;
+
+ /* iterate over all 32 pens specified */
+ for (pen = 0; pen < 32; pen++)
+ {
+ UINT8 fgbits = ((fgmask >> pen) & 1) ? TILEMAP_PIXEL_TRANSPARENT : TILEMAP_PIXEL_LAYER0;
+ UINT8 bgbits = ((bgmask >> pen) & 1) ? TILEMAP_PIXEL_TRANSPARENT : TILEMAP_PIXEL_LAYER1;
+ tilemap_map_pen_to_layer(tmap, group, pen, fgbits | bgbits);
+ }
+}
+
+
+
+/***************************************************************************
+ TILEMAP SCROLLING
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_set_scroll_rows - specify the number of
+ independently scrollable row units; each unit
+ covers height/scroll_rows pixels
+-------------------------------------------------*/
+
+void tilemap_set_scroll_rows(tilemap *tmap, UINT32 scroll_rows)
+{
+ assert(scroll_rows <= tmap->height);
+ tmap->scrollrows = scroll_rows;
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_scroll_cols - specify the number of
+ independently scrollable column units; each
+ unit covers width/scroll_cols pixels
+-------------------------------------------------*/
+
+void tilemap_set_scroll_cols(tilemap *tmap, UINT32 scroll_cols)
+{
+ assert(scroll_cols <= tmap->width);
+ tmap->scrollcols = scroll_cols;
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_scrolldx - specify global
+ horizontal scroll offset, for non-flipped and
+ flipped cases
+-------------------------------------------------*/
+
+void tilemap_set_scrolldx(tilemap *tmap, int dx, int dx_flipped)
+{
+ tmap->dx = dx;
+ tmap->dx_flipped = dx_flipped;
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_scrolldy - specify global
+ vertical scroll offset, for non-flipped and
+ flipped cases
+-------------------------------------------------*/
+
+void tilemap_set_scrolldy(tilemap *tmap, int dy, int dy_flipped)
+{
+ tmap->dy = dy;
+ tmap->dy_flipped = dy_flipped;
+}
+
+
+/*-------------------------------------------------
+ tilemap_get_scrolldx - return the global
+ horizontal scroll offset, based on current
+ flip state
+-------------------------------------------------*/
+
+int tilemap_get_scrolldx(tilemap *tmap)
+{
+ return (tmap->attributes & TILEMAP_FLIPX) ? tmap->dx_flipped : tmap->dx;
+}
+
+
+/*-------------------------------------------------
+ tilemap_get_scrolldy - return the global
+ vertical scroll offset, based on current
+ flip state
+-------------------------------------------------*/
+
+int tilemap_get_scrolldy(tilemap *tmap)
+{
+ return (tmap->attributes & TILEMAP_FLIPY) ? tmap->dy_flipped : tmap->dy;
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_scrollx - specify the scroll value
+ for a row unit
+-------------------------------------------------*/
+
+void tilemap_set_scrollx(tilemap *tmap, int which, int value)
+{
+ if (which < tmap->scrollrows)
+ tmap->rowscroll[which] = value;
+}
+
+
+/*-------------------------------------------------
+ tilemap_set_scrolly - specify the scroll value
+ for a column unit
+-------------------------------------------------*/
+
+void tilemap_set_scrolly(tilemap *tmap, int which, int value)
+{
+ if (which < tmap->scrollcols)
+ tmap->colscroll[which] = value;
+}
+
+
+
+/***************************************************************************
+ INTERNAL MAP ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_get_pixmap - return a pointer to the
+ (updated) internal pixmap for a tilemap
+-------------------------------------------------*/
+
+mame_bitmap *tilemap_get_pixmap(tilemap *tmap)
+{
+ /* ensure all the tiles are up-to-date and then return the pixmap */
+ pixmap_update(tmap, NULL);
+ return tmap->pixmap;
+}
+
+
+/*-------------------------------------------------
+ tilemap_get_flagsmap - return a pointer to the
+ (updated) internal flagsmap for a tilemap
+-------------------------------------------------*/
+
+mame_bitmap *tilemap_get_flagsmap(tilemap *tmap)
+{
+ /* ensure all the tiles are up-to-date and then return the pixmap */
+ pixmap_update(tmap, NULL);
+ return tmap->flagsmap;
+}
+
+
+/*-------------------------------------------------
+ tilemap_get_pixmap - return a pointer to the
+ (updated) internal per-tile flags for a tilemap
+-------------------------------------------------*/
+
+UINT8 *tilemap_get_tile_flags(tilemap *tmap)
+{
+ /* ensure all the tiles are up-to-date and then return the pixmap */
+ pixmap_update(tmap, NULL);
+ return tmap->tileflags;
+}
+
+
+
+/***************************************************************************
+ TILEMAP RENDERING
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_draw_primask - draw a tilemap to the
+ destination with clipping; pixels apply
+ priority/priority_mask to the priority bitmap
+-------------------------------------------------*/
+
+void tilemap_draw_primask(mame_bitmap *dest, const rectangle *cliprect, tilemap *tmap, UINT32 flags, UINT8 priority, UINT8 priority_mask)
+{
+ rectangle original_cliprect;
+ blit_parameters blit;
+ int xpos, ypos;
+
+ /* skip if disabled */
+ if (!tmap->enable)
+ return;
+
+profiler_mark(PROFILER_TILEMAP_DRAW);
+ /* configure the blit parameters based on the input parameters */
+ configure_blit_parameters(&blit, tmap, dest, cliprect, flags, priority, priority_mask);
+ original_cliprect = blit.cliprect;
+
+ /* if the whole map is dirty, mark it as such */
+ if (tmap->all_tiles_dirty)
+ {
+ memset(tmap->tileflags, TILE_FLAG_DIRTY, tmap->max_logical_index);
+ tmap->all_tiles_dirty = FALSE;
+ }
+
+ /* XY scrolling playfield */
+ if (tmap->scrollrows == 1 && tmap->scrollcols == 1)
+ {
+ int scrollx = effective_rowscroll(tmap, 0);
+ int scrolly = effective_colscroll(tmap, 0);
+
+ /* iterate to handle wraparound */
+ for (ypos = scrolly - tmap->height; ypos <= blit.cliprect.max_y; ypos += tmap->height)
+ for (xpos = scrollx - tmap->width; xpos <= blit.cliprect.max_x; xpos += tmap->width)
+ tilemap_draw_instance(tmap, &blit, xpos, ypos);
+ }
+
+ /* scrolling rows + vertical scroll */
+ else if (tmap->scrollcols == 1)
+ {
+ const rectangle original_cliprect = blit.cliprect;
+ int rowheight = tmap->height / tmap->scrollrows;
+ int scrolly = effective_colscroll(tmap, 0);
+ int currow, nextrow;
+
+ /* iterate over rows in the tilemap */
+ for (currow = 0; currow < tmap->scrollrows; currow = nextrow)
+ {
+ int scrollx = effective_rowscroll(tmap, currow);
+
+ /* scan forward until we find a non-matching row */
+ for (nextrow = currow + 1; nextrow < tmap->scrollrows; nextrow++)
+ if (effective_rowscroll(tmap, nextrow) != scrollx)
+ break;
+
+ /* skip if disabled */
+ if (scrollx == TILE_LINE_DISABLED)
+ continue;
+
+ /* iterate over Y to handle wraparound */
+ for (ypos = scrolly - tmap->height; ypos <= original_cliprect.max_y; ypos += tmap->height)
+ {
+ /* update the cliprect just for this set of rows */
+ blit.cliprect.min_y = currow * rowheight + ypos;
+ blit.cliprect.max_y = nextrow * rowheight - 1 + ypos;
+ sect_rect(&blit.cliprect, &original_cliprect);
+
+ /* iterate over X to handle wraparound */
+ for (xpos = scrollx - tmap->width; xpos <= original_cliprect.max_x; xpos += tmap->width)
+ tilemap_draw_instance(tmap, &blit, xpos, ypos);
+ }
+ }
+ }
+
+ /* scrolling columns + horizontal scroll */
+ else if (tmap->scrollrows == 1)
+ {
+ const rectangle original_cliprect = blit.cliprect;
+ int colwidth = tmap->width / tmap->scrollcols;
+ int scrollx = effective_rowscroll(tmap, 0);
+ int curcol, nextcol;
+
+ /* iterate over columns in the tilemap */
+ for (curcol = 0; curcol < tmap->scrollcols; curcol = nextcol)
+ {
+ int scrolly = effective_colscroll(tmap, curcol);
+
+ /* scan forward until we find a non-matching column */
+ for (nextcol = curcol + 1; nextcol < tmap->scrollcols; nextcol++)
+ if (effective_colscroll(tmap, nextcol) != scrolly)
+ break;
+
+ /* skip if disabled */
+ if (scrolly == TILE_LINE_DISABLED)
+ continue;
+
+ /* iterate over X to handle wraparound */
+ for (xpos = scrollx - tmap->width; xpos <= original_cliprect.max_x; xpos += tmap->width)
+ {
+ /* update the cliprect just for this set of columns */
+ blit.cliprect.min_x = curcol * colwidth + xpos;
+ blit.cliprect.max_x = nextcol * colwidth - 1 + xpos;
+ sect_rect(&blit.cliprect, &original_cliprect);
+
+ /* iterate over Y to handle wraparound */
+ for (ypos = scrolly - tmap->height; ypos <= original_cliprect.max_y; ypos += tmap->height)
+ tilemap_draw_instance(tmap, &blit, xpos, ypos);
+ }
+ }
+ }
+profiler_mark(PROFILER_END);
+}
+
+
+/*-------------------------------------------------
+ tilemap_draw_primask - draw a tilemap to the
+ destination with clipping and arbitrary
+ rotate/zoom; pixels apply priority/
+ priority_mask to the priority bitmap
+-------------------------------------------------*/
+
+void tilemap_draw_roz_primask(mame_bitmap *dest, const rectangle *cliprect, tilemap *tmap,
+ UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy,
+ int wraparound, UINT32 flags, UINT8 priority, UINT8 priority_mask)
+{
+ blit_parameters blit;
+
+/* notes:
+ - startx and starty MUST be UINT32 for calculations to work correctly
+ - srcbitmap->width and height are assumed to be a power of 2 to speed up wraparound
+ */
+
+ /* skip if disabled */
+ if (!tmap->enable)
+ return;
+
+ /* see if this is just a regular render and if so, do a regular render */
+ if (incxx == (1 << 16) && incxy == 0 && incyx == 0 && incyy == (1 << 16) && wraparound)
+ {
+ tilemap_set_scrollx(tmap, 0, startx >> 16);
+ tilemap_set_scrolly(tmap, 0, starty >> 16);
+ tilemap_draw(dest, cliprect, tmap, flags, priority);
+ return;
+ }
+
+profiler_mark(PROFILER_TILEMAP_DRAW_ROZ);
+ /* configure the blit parameters */
+ configure_blit_parameters(&blit, tmap, dest, cliprect, flags, priority, priority_mask);
+
+ /* get the full pixmap for the tilemap */
+ tilemap_get_pixmap(tmap);
+
+ /* then do the roz copy */
+ tilemap_draw_roz_core(tmap, &blit, startx, starty, incxx, incxy, incyx, incyy, wraparound);
+profiler_mark(PROFILER_END);
+}
+
+
+
+/***************************************************************************
+ INDEXED TILEMAP HANDLING
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_count - return the number of tilemaps
+-------------------------------------------------*/
+
+int tilemap_count(void)
+{
+ tilemap *tmap;
+ int count = 0;
+
+ /* find by the tilemap index */
+ for (tmap = tilemap_list; tmap != NULL; tmap = tmap->next)
+ count++;
+ return count;
+}
+
+
+/*-------------------------------------------------
+ tilemap_size_by_index - return the size of an
+ indexed tilemap
+-------------------------------------------------*/
+
+void tilemap_size_by_index(int number, UINT32 *width, UINT32 *height)
+{
+ tilemap *tmap = indexed_tilemap(number);
+ *width = tmap->width;
+ *height = tmap->height;
+}
+
+
+/*-------------------------------------------------
+ tilemap_draw_by_index - render an indexed
+ tilemap with fixed characteristics (no
+ priority)
+-------------------------------------------------*/
+
+void tilemap_draw_by_index(mame_bitmap *dest, int number, UINT32 scrollx, UINT32 scrolly)
+{
+ tilemap *tmap = indexed_tilemap(number);
+ blit_parameters blit;
+ int xpos,ypos;
+
+ /* set up for the blit, using hard-coded parameters (no priority, etc) */
+ configure_blit_parameters(&blit, tmap, dest, NULL, TILEMAP_DRAW_OPAQUE, 0, 0xff);
+
+ /* compute the effective scroll positions */
+ scrollx = tmap->width - scrollx % tmap->width;
+ scrolly = tmap->height - scrolly % tmap->height;
+
+ /* if the whole map is dirty, mark it as such */
+ if (tmap->all_tiles_dirty)
+ {
+ memset(tmap->tileflags, TILE_FLAG_DIRTY, tmap->max_logical_index);
+ tmap->all_tiles_dirty = FALSE;
+ }
+
+ /* iterate to handle wraparound */
+ for (ypos = scrolly - tmap->height; ypos <= blit.cliprect.max_y; ypos += tmap->height)
+ for (xpos = scrollx - tmap->width; xpos <= blit.cliprect.max_x; xpos += tmap->width)
+ tilemap_draw_instance(tmap, &blit, xpos, ypos);
+}
+
+
+
+/***************************************************************************
+ COMMON LOGICAL-TO-MEMORY MAPPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_scan_rows
+ tilemap_scan_rows_flip_x
+ tilemap_scan_rows_flip_y
+ tilemap_scan_rows_flip_xy - scan in row-major
+ order with optional flipping
+-------------------------------------------------*/
+
+TILEMAP_MAPPER( tilemap_scan_rows )
+{
+ return row * num_cols + col;
+}
+
+TILEMAP_MAPPER( tilemap_scan_rows_flip_x )
+{
+ return row * num_cols + (num_cols - 1 - col);
+}
+
+TILEMAP_MAPPER( tilemap_scan_rows_flip_y )
+{
+ return (num_rows - 1 - row) * num_cols + col;
+}
+
+TILEMAP_MAPPER( tilemap_scan_rows_flip_xy )
+{
+ return (num_rows - 1 - row) * num_cols + (num_cols - 1 - col);
+}
+
+
+/*-------------------------------------------------
+ tilemap_scan_cols
+ tilemap_scan_cols_flip_x
+ tilemap_scan_cols_flip_y
+ tilemap_scan_cols_flip_xy - scan in column-
+ major order with optional flipping
+-------------------------------------------------*/
+
+TILEMAP_MAPPER( tilemap_scan_cols )
+{
+ return col * num_rows + row;
+}
+
+TILEMAP_MAPPER( tilemap_scan_cols_flip_x )
+{
+ return (num_cols - 1 - col) * num_rows + row;
+}
+
+TILEMAP_MAPPER( tilemap_scan_cols_flip_y )
+{
+ return col * num_rows + (num_rows - 1 - row);
+}
+
+TILEMAP_MAPPER( tilemap_scan_cols_flip_xy )
+{
+ return (num_cols - 1 - col) * num_rows + (num_rows - 1 - row);
+}
+
+
+
+/***************************************************************************
+ SYSTEM MANAGEMENT HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_exit - free memory allocated by the
+ tilemap system
+-------------------------------------------------*/
+
+static void tilemap_exit(running_machine *machine)
+{
+ /* free all the tilemaps in the list */
+ while (tilemap_list != NULL)
+ {
+ tilemap *next = tilemap_list->next;
+ tilemap_dispose(tilemap_list);
+ tilemap_list = next;
+ }
+ tilemap_tailptr = NULL;
+}
+
+
+/*-------------------------------------------------
+ tilemap_postload - after loading a save state
+ invalidate everything
+-------------------------------------------------*/
+
+static void tilemap_postload(void *param)
+{
+ /* recompute the mappings for this tilemap */
+ tilemap *tmap = param;
+ mappings_update(tmap);
+}
+
+
+/*-------------------------------------------------
+ tilemap_dispose - dispose of a tilemap
+-------------------------------------------------*/
+
+static void tilemap_dispose(tilemap *tmap)
+{
+ tilemap **tmapptr;
+
+ /* walk the list of tilemaps; when we find ourself, remove it */
+ for (tmapptr = &tilemap_list; *tmapptr != NULL; tmapptr = &(*tmapptr)->next)
+ if (*tmapptr == tmap)
+ {
+ *tmapptr = tmap->next;
+ break;
+ }
+
+ /* free allocated memory */
+ free(tmap->pen_to_flags);
+ free(tmap->tileflags);
+ bitmap_free(tmap->flagsmap);
+ bitmap_free(tmap->pixmap);
+ free(tmap->colscroll);
+ free(tmap->rowscroll);
+ free(tmap->logical_to_memory);
+ free(tmap->memory_to_logical);
+ free(tmap);
+}
+
+
+
+/***************************************************************************
+ LOGICAL <-> MEMORY INDEX MAPPING
+***************************************************************************/
+
+/*-------------------------------------------------
+ mappings_create - allocate memory for the
+ mapping tables and compute their extents
+-------------------------------------------------*/
+
+static void mappings_create(tilemap *tmap)
+{
+ UINT32 col, row;
+
+ /* compute the maximum logical index */
+ tmap->max_logical_index = tmap->rows * tmap->cols;
+
+ /* compute the maximum memory index */
+ tmap->max_memory_index = 0;
+ for (row = 0; row < tmap->rows; row++)
+ for (col = 0; col < tmap->cols; col++)
+ {
+ tilemap_memory_index memindex = (*tmap->mapper)(col, row, tmap->cols, tmap->rows);
+ tmap->max_memory_index = MAX(tmap->max_memory_index, memindex);
+ }
+ tmap->max_memory_index++;
+
+ /* allocate the necessary mappings */
+ tmap->memory_to_logical = malloc_or_die(tmap->max_memory_index * sizeof(*tmap->memory_to_logical));
+ tmap->logical_to_memory = malloc_or_die(tmap->max_logical_index * sizeof(*tmap->logical_to_memory));
+
+ /* update the mappings */
+ mappings_update(tmap);
+}
+
+
+/*-------------------------------------------------
+ mappings_update - update the mappings after
+ a major change (flip x/y changes)
+-------------------------------------------------*/
+
+static void mappings_update(tilemap *tmap)
+{
+ tilemap_logical_index logindex;
+ tilemap_memory_index memindex;
+
+ /* initialize all the mappings to invalid values */
+ for (memindex = 0; memindex < tmap->max_memory_index; memindex++)
+ tmap->memory_to_logical[memindex] = -1;
+
+ /* now iterate over all logical indexes and populate the memory index */
+ for (logindex = 0; logindex < tmap->max_logical_index; logindex++)
+ {
+ UINT32 logical_col = logindex % tmap->cols;
+ UINT32 logical_row = logindex / tmap->cols;
+ tilemap_memory_index memindex = (*tmap->mapper)(logical_col, logical_row, tmap->cols, tmap->rows);
+ UINT32 flipped_logindex;
+
+ /* apply tilemap flip to get the final location to store */
+ if (tmap->attributes & TILEMAP_FLIPX)
+ logical_col = (tmap->cols - 1) - logical_col;
+ if (tmap->attributes & TILEMAP_FLIPY)
+ logical_row = (tmap->rows - 1) - logical_row;
+ flipped_logindex = logical_row * tmap->cols + logical_col;
+
+ /* fill in entries in both arrays */
+ tmap->memory_to_logical[memindex] = flipped_logindex;
+ tmap->logical_to_memory[flipped_logindex] = memindex;
+ }
+
+ /* mark the whole tilemap dirty */
+ tilemap_mark_all_tiles_dirty(tmap);
+}
+
+
+
+/***************************************************************************
+ TILE RENDERING
+***************************************************************************/
+
+/*-------------------------------------------------
+ pixmap_update - update the portion of the
+ pixmap described by the cliprect
+-------------------------------------------------*/
+
+static void pixmap_update(tilemap *tmap, const rectangle *cliprect)
+{
+ int mincol, maxcol, minrow, maxrow;
+ int row, col;
+
+ /* if everything is clean, do nothing */
+ if (tmap->all_tiles_clean)
+ return;
+
+profiler_mark(PROFILER_TILEMAP_DRAW);
+
+ /* compute which columns and rows to update */
+ if (cliprect != NULL)
+ {
+ mincol = cliprect->min_x / tmap->tilewidth;
+ maxcol = cliprect->max_x / tmap->tilewidth;
+ minrow = cliprect->min_y / tmap->tileheight;
+ maxrow = cliprect->max_y / tmap->tileheight;
+ }
+ else
+ {
+ mincol = minrow = 0;
+ maxcol = tmap->cols - 1;
+ maxrow = tmap->rows - 1;
+ }
+
+ /* if the whole map is dirty, mark it as such */
+ if (tmap->all_tiles_dirty)
+ {
+ memset(tmap->tileflags, TILE_FLAG_DIRTY, tmap->max_logical_index);
+ tmap->all_tiles_dirty = FALSE;
+ }
+
+ /* iterate over rows */
+ for (row = minrow; row <= maxrow; row++)
+ {
+ tilemap_logical_index logindex = row * tmap->cols;
+
+ /* iterate over colums */
+ for (col = mincol; col <= maxcol; col++)
+ if (tmap->tileflags[logindex + col] == TILE_FLAG_DIRTY)
+ tile_update(tmap, logindex + col, col, row);
+ }
+
+ /* mark it all clean */
+ if (mincol == 0 && minrow == 0 && maxcol == tmap->cols - 1 && maxcol == tmap->rows - 1)
+ tmap->all_tiles_clean = TRUE;
+
+profiler_mark(PROFILER_END);
+}
+
+
+/*-------------------------------------------------
+ tile_update - update a single dirty tile
+-------------------------------------------------*/
+
+static void tile_update(tilemap *tmap, tilemap_logical_index logindex, UINT32 col, UINT32 row)
+{
+ UINT32 x0 = tmap->tilewidth * col;
+ UINT32 y0 = tmap->tileheight * row;
+ tilemap_memory_index memindex;
+ UINT32 flags;
+
+profiler_mark(PROFILER_TILEMAP_UPDATE);
+
+ /* call the get info callback for the associated memory index */
+ memindex = tmap->logical_to_memory[logindex];
+ (*tmap->tile_get_info)(Machine, &tmap->tileinfo, memindex, tmap->user_data);
+
+ /* apply the global tilemap flip to the returned flip flags */
+ flags = tmap->tileinfo.flags ^ (tmap->attributes & 0x03);
+
+ /* draw the tile, using either direct or transparent */
+ if (Machine->game_colortable != NULL)
+ {
+ if (tmap->type != TILEMAP_TYPE_COLORTABLE)
+ tmap->tileflags[logindex] = tile_draw_colortable(tmap, tmap->tileinfo.pen_data, x0, y0, tmap->tileinfo.palette_base, tmap->tileinfo.category, tmap->tileinfo.group, flags);
+ else
+ tmap->tileflags[logindex] = tile_draw_colortrans(tmap, tmap->tileinfo.pen_data, x0, y0, tmap->tileinfo.palette_base, tmap->tileinfo.category, tmap->tileinfo.group, flags);
+ }
+ else
+ tmap->tileflags[logindex] = tile_draw(tmap, tmap->tileinfo.pen_data, x0, y0, tmap->tileinfo.palette_base, tmap->tileinfo.category, tmap->tileinfo.group, flags);
+
+ /* if mask data is specified, apply it */
+ if ((flags & (TILE_FORCE_LAYER0 | TILE_FORCE_LAYER1 | TILE_FORCE_LAYER2)) == 0 && tmap->tileinfo.mask_data != NULL)
+ tmap->tileflags[logindex] = tile_apply_bitmask(tmap, tmap->tileinfo.mask_data, x0, y0, tmap->tileinfo.category, flags);
+
+profiler_mark(PROFILER_END);
+}
+
+
+/*-------------------------------------------------
+ tile_draw - draw a single tile to the
+ tilemap's internal pixmap, using the pen as
+ the pen_to_flags lookup value, and adding
+ the palette_base
+-------------------------------------------------*/
+
+static UINT8 tile_draw(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags)
+{
+ const UINT8 *penmap = tmap->pen_to_flags + group * tmap->max_pen_to_flags;
+ mame_bitmap *flagsmap = tmap->flagsmap;
+ mame_bitmap *pixmap = tmap->pixmap;
+ int height = tmap->tileheight;
+ int width = tmap->tilewidth;
+ UINT8 andmask = ~0, ormask = 0;
+ int dx0 = 1, dy0 = 1;
+ int tx, ty;
+
+ /* OR in the force layer flags */
+ category |= flags & (TILE_FORCE_LAYER0 | TILE_FORCE_LAYER1 | TILE_FORCE_LAYER2);
+
+ /* if we're vertically flipped, point to the bottom row and work backwards */
+ if (flags & TILE_FLIPY)
+ {
+ y0 += height - 1;
+ dy0 = -1;
+ }
+
+ /* if we're horizontally flipped, point to the rightmost column and work backwards */
+ if (flags & TILE_FLIPX)
+ {
+ x0 += width - 1;
+ dx0 = -1;
+ }
+
+ /* in 4bpp mode, we draw in groups of 2 pixels, so halve the width now */
+ if (flags & TILE_4BPP)
+ {
+ assert(width % 2 == 0);
+ width /= 2;
+ }
+
+ /* iterate over rows */
+ for (ty = 0; ty < height; ty++)
+ {
+ UINT16 *pixptr = BITMAP_ADDR16(pixmap, y0, x0);
+ UINT8 *flagsptr = BITMAP_ADDR8(flagsmap, y0, x0);
+ int xoffs = 0;
+
+ /* pre-advance to the next row */
+ y0 += dy0;
+
+ /* 8bpp data */
+ if (!(flags & TILE_4BPP))
+ {
+ for (tx = 0; tx < width; tx++)
+ {
+ UINT8 pen = *pendata++;
+ UINT8 map = penmap[pen];
+ pixptr[xoffs] = palette_base + pen;
+ flagsptr[xoffs] = map | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+ }
+ }
+
+ /* 4bpp data */
+ else
+ {
+ for (tx = 0; tx < width; tx++)
+ {
+ UINT8 data = *pendata++;
+ UINT8 pen, map;
+
+ pen = data & 0x0f;
+ map = penmap[pen];
+ pixptr[xoffs] = palette_base + pen;
+ flagsptr[xoffs] = map | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+
+ pen = data >> 4;
+ map = penmap[pen];
+ pixptr[xoffs] = palette_base + pen;
+ flagsptr[xoffs] = map | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+ }
+ }
+ }
+ return andmask ^ ormask;
+}
+
+
+/*-------------------------------------------------
+ tile_draw_colortable - draw a single tile to
+ the tilemap's internal pixmap, using the pen
+ as the pen_to_flags lookup value, and using
+ the machine's remapped_colortable
+-------------------------------------------------*/
+
+static UINT8 tile_draw_colortable(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags)
+{
+ const UINT8 *penmap = tmap->pen_to_flags + group * tmap->max_pen_to_flags;
+ const pen_t *palette_lookup = Machine->remapped_colortable + palette_base;
+ mame_bitmap *flagsmap = tmap->flagsmap;
+ mame_bitmap *pixmap = tmap->pixmap;
+ int height = tmap->tileheight;
+ int width = tmap->tilewidth;
+ UINT8 andmask = ~0, ormask = 0;
+ int dx0 = 1, dy0 = 1;
+ int tx, ty;
+
+ /* OR in the force layer flags */
+ category |= flags & (TILE_FORCE_LAYER0 | TILE_FORCE_LAYER1 | TILE_FORCE_LAYER2);
+
+ /* if we're vertically flipped, point to the bottom row and work backwards */
+ if (flags & TILE_FLIPY)
+ {
+ y0 += height - 1;
+ dy0 = -1;
+ }
+
+ /* if we're horizontally flipped, point to the rightmost column and work backwards */
+ if (flags & TILE_FLIPX)
+ {
+ x0 += width - 1;
+ dx0 = -1;
+ }
+
+ /* in 4bpp mode, we draw in groups of 2 pixels, so halve the width now */
+ if (flags & TILE_4BPP)
+ {
+ assert(width % 2 == 0);
+ width /= 2;
+ }
+
+ /* iterate over rows */
+ for (ty = 0; ty < height; ty++)
+ {
+ UINT16 *pixptr = BITMAP_ADDR16(pixmap, y0, x0);
+ UINT8 *flagsptr = BITMAP_ADDR8(flagsmap, y0, x0);
+ int xoffs = 0;
+
+ /* pre-advance to the next row */
+ y0 += dy0;
+
+ /* 8bpp data */
+ if (!(flags & TILE_4BPP))
+ {
+ for (tx = 0; tx < width; tx++)
+ {
+ UINT8 pen = *pendata++;
+ UINT8 map = penmap[pen];
+ pixptr[xoffs] = palette_lookup[pen];
+ flagsptr[xoffs] = map | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+ }
+ }
+
+ /* 4bpp data */
+ else
+ {
+ for (tx = 0; tx < width; tx++)
+ {
+ UINT8 data = *pendata++;
+ pen_t pen;
+ UINT8 map;
+
+ pen = data & 0x0f;
+ map = penmap[pen];
+ pixptr[xoffs] = palette_lookup[pen];
+ flagsptr[xoffs] = map | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+
+ pen = data >> 4;
+ map = penmap[pen];
+ pixptr[xoffs] = palette_lookup[pen];
+ flagsptr[xoffs] = map | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+ }
+ }
+ }
+ return andmask ^ ormask;
+}
+
+
+/*-------------------------------------------------
+ tile_draw_colortrans - draw a single tile to
+ the tilemap's internal pixmap, using the
+ remapped pen as the pen_to_flags lookup value
+-------------------------------------------------*/
+
+static UINT8 tile_draw_colortrans(tilemap *tmap, const UINT8 *pendata, UINT32 x0, UINT32 y0, UINT32 palette_base, UINT8 category, UINT8 group, UINT8 flags)
+{
+ const UINT8 *penmap = tmap->pen_to_flags + group * tmap->max_pen_to_flags;
+ const pen_t *palette_lookup = Machine->remapped_colortable + palette_base;
+ mame_bitmap *flagsmap = tmap->flagsmap;
+ mame_bitmap *pixmap = tmap->pixmap;
+ int height = tmap->tileheight;
+ int width = tmap->tilewidth;
+ UINT8 andmask = ~0, ormask = 0;
+ int dx0 = 1, dy0 = 1;
+ int tx, ty;
+
+ /* OR in the force layer flags */
+ category |= flags & (TILE_FORCE_LAYER0 | TILE_FORCE_LAYER1 | TILE_FORCE_LAYER2);
+
+ /* if we're vertically flipped, point to the bottom row and work backwards */
+ if (flags & TILE_FLIPY)
+ {
+ y0 += height - 1;
+ dy0 = -1;
+ }
+
+ /* if we're horizontally flipped, point to the rightmost column and work backwards */
+ if (flags & TILE_FLIPX)
+ {
+ x0 += width - 1;
+ dx0 = -1;
+ }
+
+ /* in 4bpp mode, we draw in groups of 2 pixels, so halve the width now */
+ if (flags & TILE_4BPP)
+ {
+ assert(width % 2 == 0);
+ width /= 2;
+ }
+
+ /* iterate over rows */
+ for (ty = 0; ty < height; ty++)
+ {
+ UINT16 *pixptr = BITMAP_ADDR16(pixmap, y0, x0);
+ UINT8 *flagsptr = BITMAP_ADDR8(flagsmap, y0, x0);
+ int xoffs = 0;
+
+ /* pre-advance to the next row */
+ y0 += dy0;
+
+ /* 8bpp data */
+ if (!(flags & TILE_4BPP))
+ {
+ for (tx = 0; tx < width; tx++)
+ {
+ pen_t pen = palette_lookup[*pendata++];
+ UINT8 map = penmap[pen];
+ pixptr[xoffs] = pen;
+ flagsptr[xoffs] = map | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+ }
+ }
+
+ /* 4bpp data */
+ else
+ {
+ for (tx = 0; tx < width; tx++)
+ {
+ UINT8 data = *pendata++;
+ pen_t pen;
+ UINT8 map;
+
+ pen = palette_lookup[data & 0x0f];
+ map = penmap[pen];
+ pixptr[xoffs] = pen;
+ flagsptr[xoffs] = map | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+
+ pen = palette_lookup[data >> 4];
+ map = penmap[pen];
+ pixptr[xoffs] = pen;
+ flagsptr[xoffs] = map | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+ }
+ }
+ }
+ return andmask ^ ormask;
+}
+
+
+/*-------------------------------------------------
+ tile_apply_bitmask - apply a bitmask to an
+ already-rendered tile by modifying the
+ flagsmap appropriately
+-------------------------------------------------*/
+
+static UINT8 tile_apply_bitmask(tilemap *tmap, const UINT8 *maskdata, UINT32 x0, UINT32 y0, UINT8 category, UINT8 flags)
+{
+ mame_bitmap *flagsmap = tmap->flagsmap;
+ int height = tmap->tileheight;
+ int width = tmap->tilewidth;
+ UINT8 andmask = ~0, ormask = 0;
+ int dx0 = 1, dy0 = 1;
+ int bitoffs = 0;
+ int tx, ty;
+
+ /* if we're vertically flipped, point to the bottom row and work backwards */
+ if (flags & TILE_FLIPY)
+ {
+ y0 += height - 1;
+ dy0 = -1;
+ }
+
+ /* if we're horizontally flipped, point to the rightmost column and work backwards */
+ if (flags & TILE_FLIPX)
+ {
+ x0 += width - 1;
+ dx0 = -1;
+ }
+
+ /* iterate over rows */
+ for (ty = 0; ty < height; ty++)
+ {
+ UINT8 *flagsptr = BITMAP_ADDR8(flagsmap, y0, x0);
+ int xoffs = 0;
+
+ /* pre-advance to the next row */
+ y0 += dy0;
+
+ /* anywhere the bitmask is 0 should be transparent */
+ for (tx = 0; tx < width; tx++)
+ {
+ UINT8 map = flagsptr[xoffs];
+
+ if ((maskdata[bitoffs / 8] & (0x80 >> (bitoffs & 7))) == 0)
+ map = flagsptr[xoffs] = TILEMAP_PIXEL_TRANSPARENT | category;
+ andmask &= map;
+ ormask |= map;
+ xoffs += dx0;
+ bitoffs++;
+ }
+ }
+ return andmask ^ ormask;
+}
+
+
+
+/***************************************************************************
+ DRAWING HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ configure_blit_parameters - fill in the
+ standard blit parameters based on the input
+ data; this code is shared by normal, roz,
+ and indexed drawing code
+-------------------------------------------------*/
+
+static void configure_blit_parameters(blit_parameters *blit, tilemap *tmap, mame_bitmap *dest, const rectangle *cliprect, UINT32 flags, UINT8 priority, UINT8 priority_mask)
+{
+ /* start with nothing */
+ memset(blit, 0, sizeof(*blit));
+
+ /* set the target bitmap */
+ blit->bitmap = dest;
+
+ /* if we have a cliprect, copy */
+ if (cliprect != NULL)
+ blit->cliprect = *cliprect;
+
+ /* otherwise, make one up */
+ else
+ {
+ blit->cliprect.min_x = blit->cliprect.min_y = 0;
+ blit->cliprect.max_x = dest->width - 1;
+ blit->cliprect.max_y = dest->height - 1;
+ }
+
+ /* set the priority code */
+ blit->tilemap_priority_code = priority | (priority_mask << 8) | (tmap->palette_offset << 16);
+
+ /* if no destination, just render priority */
+ if (dest == NULL)
+ {
+ blit->draw_masked = scanline_draw_masked_null;
+ blit->draw_opaque = scanline_draw_opaque_null;
+ }
+
+ /* otherwise get the appropriate callbacks for the format and flags */
+ else
+ {
+ switch (dest->format)
+ {
+ case BITMAP_FORMAT_RGB32:
+ blit->draw_masked = (flags & TILEMAP_DRAW_ALPHA) ? scanline_draw_masked_rgb32_alpha : scanline_draw_masked_rgb32;
+ blit->draw_opaque = (flags & TILEMAP_DRAW_ALPHA) ? scanline_draw_opaque_rgb32_alpha : scanline_draw_opaque_rgb32;
+ break;
+
+ case BITMAP_FORMAT_RGB15:
+ blit->draw_masked = (flags & TILEMAP_DRAW_ALPHA) ? scanline_draw_masked_rgb16_alpha : scanline_draw_masked_rgb16;
+ blit->draw_opaque = (flags & TILEMAP_DRAW_ALPHA) ? scanline_draw_opaque_rgb16_alpha : scanline_draw_opaque_rgb16;
+ break;
+
+ case BITMAP_FORMAT_INDEXED16:
+ blit->draw_masked = scanline_draw_masked_ind16;
+ blit->draw_opaque = scanline_draw_opaque_ind16;
+ break;
+
+ default:
+ fatalerror("tilemap_draw_primask: Invalid bitmap format");
+ break;
+ }
+ }
+
+ /* tile priority; unless otherwise specified, draw anything in layer 0 */
+ blit->mask = TILEMAP_PIXEL_CATEGORY_MASK;
+ blit->value = flags & TILEMAP_PIXEL_CATEGORY_MASK;
+
+ /* if no layers specified, draw layer 0 */
+ if ((flags & (TILEMAP_DRAW_LAYER0 | TILEMAP_DRAW_LAYER1 | TILEMAP_DRAW_LAYER2)) == 0)
+ flags |= TILEMAP_DRAW_LAYER0;
+
+ /* OR in the bits from the draw masks */
+ blit->mask |= flags & (TILEMAP_DRAW_LAYER0 | TILEMAP_DRAW_LAYER1 | TILEMAP_DRAW_LAYER2);
+ blit->value |= flags & (TILEMAP_DRAW_LAYER0 | TILEMAP_DRAW_LAYER1 | TILEMAP_DRAW_LAYER2);
+
+ /* for all-opaque rendering, don't check any of the layer bits */
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ {
+ blit->mask &= ~(TILEMAP_PIXEL_LAYER0 | TILEMAP_PIXEL_LAYER1 | TILEMAP_PIXEL_LAYER2);
+ blit->value &= ~(TILEMAP_PIXEL_LAYER0 | TILEMAP_PIXEL_LAYER1 | TILEMAP_PIXEL_LAYER2);
+ }
+}
+
+
+/*-------------------------------------------------
+ tilemap_draw_instance - draw a single
+ instance of the tilemap to the internal
+ pixmap at the given xpos,ypos
+-------------------------------------------------*/
+
+static void tilemap_draw_instance(tilemap *tmap, const blit_parameters *blit, int xpos, int ypos)
+{
+ mame_bitmap *dest = blit->bitmap;
+ const UINT16 *source_baseaddr;
+ const UINT8 *mask_baseaddr;
+ void *dest_baseaddr = NULL;
+ UINT8 *priority_baseaddr;
+ int dest_line_pitch_bytes = 0;
+ int dest_bytespp = 0;
+ int mincol, maxcol;
+ int x1, y1, x2, y2;
+ int y, nexty;
+
+ /* clip destination coordinates to the tilemap */
+ /* note that x2/y2 are exclusive, not inclusive */
+ x1 = MAX(xpos, blit->cliprect.min_x);
+ x2 = MIN(xpos + (int)tmap->width, blit->cliprect.max_x + 1);
+ y1 = MAX(ypos, blit->cliprect.min_y);
+ y2 = MIN(ypos + (int)tmap->height, blit->cliprect.max_y + 1);
+
+ /* if totally clipped, stop here */
+ if (x1 >= x2 || y1 >= y2)
+ return;
+
+ /* look up priority and destination base addresses for y1 */
+ priority_baseaddr = BITMAP_ADDR8(priority_bitmap, y1, xpos);
+ if (dest != NULL)
+ {
+ dest_bytespp = dest->bpp / 8;
+ dest_line_pitch_bytes = dest->rowpixels * dest_bytespp;
+ dest_baseaddr = (UINT8 *)dest->base + (y1 * dest->rowpixels + xpos) * dest_bytespp;
+ }
+
+ /* convert screen coordinates to source tilemap coordinates */
+ x1 -= xpos;
+ y1 -= ypos;
+ x2 -= xpos;
+ y2 -= ypos;
+
+ /* get tilemap pixels */
+ source_baseaddr = BITMAP_ADDR16(tmap->pixmap, y1, 0);
+ mask_baseaddr = BITMAP_ADDR8(tmap->flagsmap, y1, 0);
+
+ /* get start/stop columns, rounding outward */
+ mincol = x1 / tmap->tilewidth;
+ maxcol = (x2 + tmap->tilewidth - 1) / tmap->tilewidth;
+
+ /* set up row counter */
+ y = y1;
+ nexty = tmap->tileheight * (y1 / tmap->tileheight) + tmap->tileheight;
+ nexty = MIN(nexty, y2);
+
+ /* loop over tilemap rows */
+ for (;;)
+ {
+ int row = y / tmap->tileheight;
+ trans_t prev_trans = WHOLLY_TRANSPARENT;
+ trans_t cur_trans;
+ int x_start = x1;
+ int column;
+
+ /* iterate across the applicable tilemap columns */
+ for (column = mincol; column <= maxcol; column++)
+ {
+ int x_end;
+
+ /* we don't actually render the last column; it is always just used for flushing */
+ if (column == maxcol)
+ cur_trans = WHOLLY_TRANSPARENT;
+
+ /* for other columns we look up the transparency information */
+ else
+ {
+ tilemap_logical_index logindex = row * tmap->cols + column;
+
+ /* if the current tile is dirty, fix it */
+ if (tmap->tileflags[logindex] == TILE_FLAG_DIRTY)
+ tile_update(tmap, logindex, column, row);
+
+ /* if the current summary data is non-zero, we must draw masked */
+ if ((tmap->tileflags[logindex] & blit->mask) != 0)
+ cur_trans = MASKED;
+
+ /* otherwise, our transparency state is constant across the tile; fetch it */
+ else
+ cur_trans = ((mask_baseaddr[column * tmap->tilewidth] & blit->mask) == blit->value) ? WHOLLY_OPAQUE : WHOLLY_TRANSPARENT;
+ }
+
+ /* if the transparency state is the same as last time, don't render yet */
+ if (cur_trans == prev_trans)
+ continue;
+
+ /* compute the end of this run, in pixels */
+ x_end = column * tmap->tilewidth;
+ x_end = MAX(x_end, x1);
+ x_end = MIN(x_end, x2);
+
+ /* if we're rendering something, compute the pointers */
+ if (prev_trans != WHOLLY_TRANSPARENT)
+ {
+ const UINT16 *source0 = source_baseaddr + x_start;
+ void *dest0 = (UINT8 *)dest_baseaddr + x_start * dest_bytespp;
+ UINT8 *pmap0 = priority_baseaddr + x_start;
+ int cury;
+
+ /* if we were opaque, use the opaque renderer */
+ if (prev_trans == WHOLLY_OPAQUE)
+ {
+ for (cury = y; cury < nexty; cury++)
+ {
+ (*blit->draw_opaque)(dest0, source0, x_end - x_start, pmap0, blit->tilemap_priority_code);
+
+ dest0 = (UINT8 *)dest0 + dest_line_pitch_bytes;
+ source0 += tmap->pixmap->rowpixels;
+ pmap0 += priority_bitmap->rowpixels;
+ }
+ }
+
+ /* otherwise use the masked renderer */
+ else
+ {
+ const UINT8 *mask0 = mask_baseaddr + x_start;
+ for (cury = y; cury < nexty; cury++)
+ {
+ (*blit->draw_masked)(dest0, source0, mask0, blit->mask, blit->value, x_end - x_start, pmap0, blit->tilemap_priority_code);
+
+ dest0 = (UINT8 *)dest0 + dest_line_pitch_bytes;
+ source0 += tmap->pixmap->rowpixels;
+ mask0 += tmap->flagsmap->rowpixels;
+ pmap0 += priority_bitmap->rowpixels;
+ }
+ }
+ }
+
+ /* the new start is the end */
+ x_start = x_end;
+ prev_trans = cur_trans;
+ }
+
+ /* if this was the last row, stop */
+ if (nexty == y2)
+ break;
+
+ /* advance to the next row on all our bitmaps */
+ priority_baseaddr += priority_bitmap->rowpixels * (nexty - y);
+ source_baseaddr += tmap->pixmap->rowpixels * (nexty - y);
+ mask_baseaddr += tmap->flagsmap->rowpixels * (nexty - y);
+ dest_baseaddr = (UINT8 *)dest_baseaddr + dest_line_pitch_bytes * (nexty - y);
+
+ /* increment the Y counter */
+ y = nexty;
+ nexty += tmap->tileheight;
+ nexty = MIN(nexty, y2);
+ }
+}
+
+
+/*-------------------------------------------------
+ tilemap_draw_roz_core - render the tilemap's
+ pixmap to the destination with rotation
+ and zoom
+-------------------------------------------------*/
+
+#define ROZ_PLOT_PIXEL(INPUT_VAL) \
+do { \
+ if (blit->draw_masked == scanline_draw_masked_ind16) \
+ *(UINT16 *)dest = (INPUT_VAL) + (priority >> 16); \
+ else if (blit->draw_masked == scanline_draw_masked_rgb32) \
+ *(UINT32 *)dest = clut[INPUT_VAL]; \
+ else if (blit->draw_masked == scanline_draw_masked_rgb16) \
+ *(UINT16 *)dest = clut[INPUT_VAL]; \
+ else if (blit->draw_masked == scanline_draw_masked_rgb32_alpha) \
+ *(UINT32 *)dest = alpha_blend32(*(UINT32 *)dest, clut[INPUT_VAL]); \
+ else if (blit->draw_masked == scanline_draw_masked_rgb16_alpha) \
+ *(UINT16 *)dest = alpha_blend16(*(UINT16 *)dest, clut[INPUT_VAL]); \
+} while (0)
+
+static void tilemap_draw_roz_core(tilemap *tmap, const blit_parameters *blit,
+ UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, int wraparound)
+{
+ const pen_t *clut = &Machine->remapped_colortable[blit->tilemap_priority_code >> 16];
+ mame_bitmap *destbitmap = blit->bitmap;
+ mame_bitmap *srcbitmap = tmap->pixmap;
+ mame_bitmap *flagsmap = tmap->flagsmap;
+ const int xmask = srcbitmap->width-1;
+ const int ymask = srcbitmap->height-1;
+ const int widthshifted = srcbitmap->width << 16;
+ const int heightshifted = srcbitmap->height << 16;
+ UINT32 priority = blit->tilemap_priority_code;
+ UINT8 mask = blit->mask;
+ UINT8 value = blit->value;
+ UINT32 cx;
+ UINT32 cy;
+ int x;
+ int sx;
+ int sy;
+ int ex;
+ int ey;
+ void *dest;
+ UINT8 *pri;
+ const UINT16 *src;
+ const UINT8 *maskptr;
+ int destadvance = destbitmap->bpp / 8;
+
+ /* pre-advance based on the cliprect */
+ startx += blit->cliprect.min_x * incxx + blit->cliprect.min_y * incyx;
+ starty += blit->cliprect.min_x * incxy + blit->cliprect.min_y * incyy;
+
+ /* extract start/end points */
+ sx = blit->cliprect.min_x;
+ sy = blit->cliprect.min_y;
+ ex = blit->cliprect.max_x;
+ ey = blit->cliprect.max_y;
+
+ /* optimized loop for the not rotated case */
+ if (incxy == 0 && incyx == 0 && !wraparound)
+ {
+ /* skip without drawing until we are within the bitmap */
+ while (startx >= widthshifted && sx <= ex)
+ {
+ startx += incxx;
+ sx++;
+ }
+
+ /* early exit if we're done already */
+ if (sx > ex)
+ return;
+
+ /* loop over rows */
+ while (sy <= ey)
+ {
+ /* only draw if Y is within range */
+ if (starty < heightshifted)
+ {
+ /* initialize X counters */
+ x = sx;
+ cx = startx;
+ cy = starty >> 16;
+
+ /* get source and priority pointers */
+ pri = BITMAP_ADDR8(priority_bitmap, sy, sx);
+ src = BITMAP_ADDR16(srcbitmap, cy, 0);
+ maskptr = BITMAP_ADDR8(flagsmap, cy, 0);
+ dest = (UINT8 *)destbitmap->base + (destbitmap->rowpixels * sy + sx) * destadvance;
+
+ /* loop over columns */
+ while (x <= ex && cx < widthshifted)
+ {
+ /* plot if we match the mask */
+ if ((maskptr[cx >> 16] & mask) == value)
+ {
+ ROZ_PLOT_PIXEL(src[cx >> 16]);
+ *pri = (*pri & (priority >> 8)) | priority;
+ }
+
+ /* advance in X */
+ cx += incxx;
+ x++;
+ dest = (UINT8 *)dest + destadvance;
+ pri++;
+ }
+ }
+
+ /* advance in Y */
+ starty += incyy;
+ sy++;
+ }
+ }
+
+ /* wraparound case */
+ else if (wraparound)
+ {
+ /* loop over rows */
+ while (sy <= ey)
+ {
+ /* initialize X counters */
+ x = sx;
+ cx = startx;
+ cy = starty;
+
+ /* get dest and priority pointers */
+ dest = (UINT8 *)destbitmap->base + (destbitmap->rowpixels * sy + sx) * destadvance;
+ pri = BITMAP_ADDR8(priority_bitmap, sy, sx);
+
+ /* loop over columns */
+ while (x <= ex)
+ {
+ /* plot if we match the mask */
+ if ((*BITMAP_ADDR8(flagsmap, (cy >> 16) & ymask, (cx >> 16) & xmask) & mask) == value)
+ {
+ ROZ_PLOT_PIXEL(*BITMAP_ADDR16(srcbitmap, (cy >> 16) & ymask, (cx >> 16) & xmask));
+ *pri = (*pri & (priority >> 8)) | priority;
+ }
+
+ /* advance in X */
+ cx += incxx;
+ cy += incxy;
+ x++;
+ dest = (UINT8 *)dest + destadvance;
+ pri++;
+ }
+
+ /* advance in Y */
+ startx += incyx;
+ starty += incyy;
+ sy++;
+ }
+ }
+
+ /* non-wraparound case */
+ else
+ {
+ /* loop over rows */
+ while (sy <= ey)
+ {
+ /* initialize X counters */
+ x = sx;
+ cx = startx;
+ cy = starty;
+
+ /* get dest and priority pointers */
+ dest = (UINT8 *)destbitmap->base + (destbitmap->rowpixels * sy + sx) * destadvance;
+ pri = BITMAP_ADDR8(priority_bitmap, sy, sx);
+
+ /* loop over columns */
+ while (x <= ex)
+ {
+ /* plot if we're within the bitmap and we match the mask */
+ if (cx < widthshifted && cy < heightshifted)
+ if ((*BITMAP_ADDR8(flagsmap, cy >> 16, cx >> 16) & mask) == value)
+ {
+ ROZ_PLOT_PIXEL(*BITMAP_ADDR16(srcbitmap, cy >> 16, cx >> 16));
+ *pri = (*pri & (priority >> 8)) | priority;
+ }
+
+ /* advance in X */
+ cx += incxx;
+ cy += incxy;
+ x++;
+ dest = (UINT8 *)dest + destadvance;
+ pri++;
+ }
+
+ /* advance in Y */
+ startx += incyx;
+ starty += incyy;
+ sy++;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ SCANLINE RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ scanline_draw_opaque_null - draw to a NULL
+ bitmap, setting priority only
+-------------------------------------------------*/
+
+static void scanline_draw_opaque_null(void *dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode)
+{
+ int i;
+
+ /* skip entirely if not changing priority */
+ if (pcode != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+}
+
+
+/*-------------------------------------------------
+ scanline_draw_masked_null - draw to a NULL
+ bitmap using a mask, setting priority only
+-------------------------------------------------*/
+
+static void scanline_draw_masked_null(void *dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode)
+{
+ int i;
+
+ /* skip entirely if not changing priority */
+ if (pcode != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ scanline_draw_opaque_ind16 - draw to a 16bpp
+ indexed bitmap
+-------------------------------------------------*/
+
+static void scanline_draw_opaque_ind16(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode)
+{
+ UINT16 *dest = _dest;
+ int pal = pcode >> 16;
+ int i;
+
+ /* special case for no palette offset */
+ if (pal == 0)
+ {
+ memcpy(dest, source, count * 2);
+
+ /* priority if necessary */
+ if (pcode != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* priority case */
+ else if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ {
+ dest[i] = source[i] + pal;
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ dest[i] = source[i] + pal;
+ }
+}
+
+
+/*-------------------------------------------------
+ scanline_draw_masked_ind16 - draw to a 16bpp
+ indexed bitmap using a mask
+-------------------------------------------------*/
+
+static void scanline_draw_masked_ind16(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode)
+{
+ UINT16 *dest = _dest;
+ int pal = pcode >> 16;
+ int i;
+
+ /* priority case */
+ if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ {
+ dest[i] = source[i] + pal;
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ dest[i] = source[i] + pal;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ scanline_draw_opaque_rgb16 - draw to a 16bpp
+ RGB bitmap
+-------------------------------------------------*/
+
+static void scanline_draw_opaque_rgb16(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode)
+{
+ const pen_t *clut = &Machine->remapped_colortable[pcode >> 16];
+ UINT16 *dest = _dest;
+ int i;
+
+ /* priority case */
+ if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ {
+ dest[i] = clut[source[i]];
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ dest[i] = clut[source[i]];
+ }
+}
+
+
+/*-------------------------------------------------
+ scanline_draw_masked_rgb16 - draw to a 16bpp
+ RGB bitmap using a mask
+-------------------------------------------------*/
+
+static void scanline_draw_masked_rgb16(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode)
+{
+ const pen_t *clut = &Machine->remapped_colortable[pcode >> 16];
+ UINT16 *dest = _dest;
+ int i;
+
+ /* priority case */
+ if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ {
+ dest[i] = clut[source[i]];
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ dest[i] = clut[source[i]];
+ }
+}
+
+
+/*-------------------------------------------------
+ scanline_draw_opaque_rgb16_alpha - draw to a
+ 16bpp RGB bitmap with alpha blending
+-------------------------------------------------*/
+
+static void scanline_draw_opaque_rgb16_alpha(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode)
+{
+ const pen_t *clut = &Machine->remapped_colortable[pcode >> 16];
+ UINT16 *dest = _dest;
+ int i;
+
+ /* priority case */
+ if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ {
+ dest[i] = alpha_blend16(dest[i], clut[source[i]]);
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ dest[i] = alpha_blend16(dest[i], clut[source[i]]);
+ }
+}
+
+
+/*-------------------------------------------------
+ scanline_draw_masked_rgb16_alpha - draw to a
+ 16bpp RGB bitmap using a mask and alpha
+ blending
+-------------------------------------------------*/
+
+static void scanline_draw_masked_rgb16_alpha(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode)
+{
+ const pen_t *clut = &Machine->remapped_colortable[pcode >> 16];
+ UINT16 *dest = _dest;
+ int i;
+
+ /* priority case */
+ if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ {
+ dest[i] = alpha_blend16(dest[i], clut[source[i]]);
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ dest[i] = alpha_blend16(dest[i], clut[source[i]]);
+ }
+}
+
+
+/*-------------------------------------------------
+ scanline_draw_opaque_rgb32 - draw to a 32bpp
+ RGB bitmap
+-------------------------------------------------*/
+
+static void scanline_draw_opaque_rgb32(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode)
+{
+ const pen_t *clut = &Machine->remapped_colortable[pcode >> 16];
+ UINT32 *dest = _dest;
+ int i;
+
+ /* priority case */
+ if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ {
+ dest[i] = clut[source[i]];
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ dest[i] = clut[source[i]];
+ }
+}
+
+
+/*-------------------------------------------------
+ scanline_draw_masked_rgb32 - draw to a 32bpp
+ RGB bitmap using a mask
+-------------------------------------------------*/
+
+static void scanline_draw_masked_rgb32(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode)
+{
+ const pen_t *clut = &Machine->remapped_colortable[pcode >> 16];
+ UINT32 *dest = _dest;
+ int i;
+
+ /* priority case */
+ if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ {
+ dest[i] = clut[source[i]];
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ dest[i] = clut[source[i]];
+ }
+}
+
+
+/*-------------------------------------------------
+ scanline_draw_opaque_rgb32_alpha - draw to a
+ 32bpp RGB bitmap with alpha blending
+-------------------------------------------------*/
+
+static void scanline_draw_opaque_rgb32_alpha(void *_dest, const UINT16 *source, int count, UINT8 *pri, UINT32 pcode)
+{
+ const pen_t *clut = &Machine->remapped_colortable[pcode >> 16];
+ UINT32 *dest = _dest;
+ int i;
+
+ /* priority case */
+ if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ {
+ dest[i] = alpha_blend32(dest[i], clut[source[i]]);
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ dest[i] = alpha_blend32(dest[i], clut[source[i]]);
+ }
+}
+
+
+/*-------------------------------------------------
+ scanline_draw_masked_rgb32_alpha - draw to a
+ 32bpp RGB bitmap using a mask and alpha
+ blending
+-------------------------------------------------*/
+
+static void scanline_draw_masked_rgb32_alpha(void *_dest, const UINT16 *source, const UINT8 *maskptr, int mask, int value, int count, UINT8 *pri, UINT32 pcode)
+{
+ const pen_t *clut = &Machine->remapped_colortable[pcode >> 16];
+ UINT32 *dest = _dest;
+ int i;
+
+ /* priority case */
+ if ((pcode & 0xffff) != 0xff00)
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ {
+ dest[i] = alpha_blend32(dest[i], clut[source[i]]);
+ pri[i] = (pri[i] & (pcode >> 8)) | pcode;
+ }
+ }
+
+ /* no priority case */
+ else
+ {
+ for (i = 0; i < count; i++)
+ if ((maskptr[i] & mask) == value)
+ dest[i] = alpha_blend32(dest[i], clut[source[i]]);
+ }
+}
diff --git a/src/emu/tilemap.h b/src/emu/tilemap.h
new file mode 100644
index 00000000000..ec4e288e5a9
--- /dev/null
+++ b/src/emu/tilemap.h
@@ -0,0 +1,635 @@
+/***************************************************************************
+
+ tilemap.h
+
+ Generic tilemap management system.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Core concepts:
+
+ Tilemap = a 2-dimensional array of tiles; each tile has its own
+ independent characteristics which describe how that tile is
+ rendered. A tilemap is described by the number of rows and
+ columns in the map. Each tile in the tilemap is a fixed size
+ specified as width and height in pixels.
+
+ Tile = a single rectangular element in a tilemap; tiles can be
+ any size, but all tiles in a tilemap are the same size. Each
+ tile is described by the following parameters:
+
+ pen_data (required): pointer to an array of 8bpp pen data
+ describing the raw pixels to be rendered for a tile;
+ for example, an 8x8 tile requires 64 bytes of pen_data
+
+ palette_base (required): the base index in the global palette;
+ each pixel fetched from pen_data will have this base added
+ to it before it is stored in the pixmap
+
+ mask_data (optional): pointer to an array of 1bpp mask data
+ which controls which pixels are to be considered visible
+ or transparent (part of no layer); data is packed MSB
+ first with no padding, so an 8x8 tile requires 64 bits or
+ 8 bytes data
+
+ category (optional): specifies one of 16 categories for the
+ pixels in the tile; the category controls which tiles are
+ rendered during a tilemap_draw() call
+
+ group (optional): specifies one of 256 groups for pen mapping;
+ each pen in the tile is looked up in a table to determine
+ which layer(s) it belongs to, and the group selects one of
+ 256 different tables to use for this mapping
+
+ flags (optional): specifies one or more of the following bits:
+
+ TILE_FLIPX means render the tile flipped horizontally
+
+ TILE_FLIPY means render the tile flipped vertically
+
+ TILE_4BPP means pen_data is actually packed 4bpp pixels
+ (low 4 bits first, then upper 4 bits)
+
+ TILE_FORCE_LAYERn means all pixels are forced to be in
+ layer n, where n = 0,1,2
+
+ Pen = another name for pixel value; tilemap graphics are either
+ 4 or 8 bits per pixel, meaning that pen values range from
+ 0-15 (4bpp) or 0-255 (8bpp).
+
+ Logical index = index of a tile in a tilemap, assuming perfect
+ packing in row-major order; this is always equal to
+ (rownum * tilemap_columns + colnum).
+
+ Memory index = index of a tile in memory; this often does not
+ map 1:1 to the logical index (though it can). A mapper
+ function is provided when creating a new tilemap that can
+ map from (column,row) to memory index.
+
+ Layer = one of 3 categories each pixel can belong to, based on
+ the pens in a tile; traditionally, layer 0 is the only
+ one used. If a pixel does not belong to any layers, it is
+ considered transparent.
+
+ Group = one of 256 per-tile selectable means of mapping from
+ pens to layers; traditionally only group 0 is used.
+
+ Category = a 4-bit value specified per-tile which allows for
+ separating tiles into categories which can be rendered
+ independently.
+
+ Pixmap = a 16bpp bitmap containing the full tilemap with
+ all tiles rendered.
+
+ Flagsmap = an 8bpp bitmap containing per-pixel flags,
+ specifically the category (specified in bits 0-3) and
+ the layer (specified in bits 4-6).
+
+****************************************************************************
+
+ How to use a tilemap:
+
+ 1. First create a new tilemap by calling tilemap_create(). The
+ parameters are as follows:
+
+ tile_get_info = pointer to a callback function which accepts a
+ memory index and in return fills in a tile_info structure
+ that describes the characteristics of a tile; this function
+ will be called whenever a dirty tile needs to be rendered
+
+ mapper = pointer to a callback function which maps the logical
+ column and row to a memory index; several standard mappers
+ are provided, with tilemap_scan_rows being the most common
+
+ type = the type of tilemap this is;
+
+ TILEMAP_TYPE_PEN - this is the most common type,
+ and means that transparency is determined by taking the
+ raw pen value and looking it up in a table to determine
+ which layer(s) each pixel belongs to
+
+ TILEMAP_TYPE_COLORTABLE - this is less common and
+ will eventually be deprecated; it means that transparency
+ is determined by taking the raw pen value, looking it up
+ in the machine's colortable, and then looking that value
+ up in a table to determine which layer(s) each pixel
+ belongs to
+
+ tilewidth = the width, in pixels, of each individual tile
+
+ tileheight = the height, in pixels, of each individual tile
+
+ cols = the number of columns in the tilemap
+
+ rows = the number of rows in the tilemap
+
+ 2. Once you have created your tilemap, you need to configure it.
+ Common configuration tasks include:
+
+ * marking one of the pens as transparent via
+ tilemap_set_transparent_pen()
+
+ * performing more complex pen-to-layer mapping via
+ tilemap_map_pen_to_layer() or
+ tilemap_map_pens_to_layer()
+
+ * configuring global scroll offsets via
+ tilemap_set_scrolldx() and tilemap_set_scrolldy()
+
+ * specifying a pointer that is passed to your tile_get_info
+ callback via tilemap_set_user_data()
+
+ * setting a global palette offset via
+ tilemap_set_palette_offset()
+
+ 3. In your memory write handlers for the tile memory, anytime tile
+ data is modified, you need to mark the tile dirty so that it is
+ re-rendered with the new data the next time the tilemap is drawn.
+ Use tilemap_mark_tile_dirty() and pass in the memory index.
+
+ 4. In your handlers for scrolling, update the scroll values for the
+ tilemap via tilemap_set_scrollx() and tilemap_set_scrolly().
+
+ 5. If any other major characteristics of the tilemap change (generally
+ any global state that is used by the tile_get_info callback but
+ which is not reported via other calls to the tilemap code), you
+ should invalidate the entire tilemap. You can do this by calling
+ tilemap_mark_all_tiles_dirty().
+
+ 6. In your VIDEO_UPDATE callback, render the tiles by calling
+ tilemap_draw() or tilemap_draw_roz(). If you need to do custom
+ rendering and want access to the raw pixels, call
+ tilemap_get_pixmap() to get a pointer to the updated mame_bitmap
+ containing the tilemap graphics.
+
+****************************************************************************
+
+ The following example shows how to use the tilemap system to create
+ a simple tilemap where pen 0 is transparent. Each tile is 8x8 pixels
+ in size, and there are 32 rows and 64 columns, stored in row-major
+ order. Based on bits in the tile memory, tiles can be drawn either
+ behind or in front of sprites.
+
+ tilemap *tmap;
+ UINT16 *my_tmap_memory;
+
+ TILE_GET_INFO( my_get_info )
+ {
+ UINT8 tiledata = my_tmap_memory[tile_index];
+ UINT8 code = tiledata & 0xff;
+ UINT8 color = (tiledata >> 8) & 0x1f;
+ UINT8 flipx = (tiledata >> 13) & 1;
+ UINT8 flipy = (tiledata >> 14) & 1;
+ UINT8 category = (tiledata >> 15) & 1;
+
+ // set the common info for the tile
+ SET_TILE_INFO(
+ 1, // use machine->gfx[1] for tile graphics
+ code, // the index of the graphics for this tile
+ color, // the color to use for this tile
+ (flipx ? TILE_FLIPX : 0) | // flags for this tile; also
+ (flipy ? TILE_FLIPY : 0); // see the FLIP_YX macro
+ );
+
+ // set the category of each tile based on the high bit; this
+ // allows us to draw each category independently
+ tileinfo->category = category;
+ }
+
+ VIDEO_START( mydriver )
+ {
+ // first create the tilemap
+ tmap = tilemap_create(
+ my_get_info, // pointer to your get_info
+ tilemap_scan_rows, // standard row-major mapper
+ TILEMAP_TYPE_PEN, // transparency from pens
+ 8,8, // 8x8 tiles
+ 64,32); // 64 columns, 32 rows
+
+ // then set the transparent pen; all other pens will default
+ // to being part of layer 0
+ tilemap_set_transparent_pen(tmap, 0);
+ }
+
+ VIDEO_UPDATE( mydriver )
+ {
+ // draw the tilemap first, fully opaque since it needs to
+ // erase all previous pixels
+ tilemap_draw(
+ bitmap, // destination bitmap
+ cliprect, // clipping rectangle
+ tmap, // tilemap to draw
+ TILEMAP_DRAW_OPAQUE, // flags
+ 0); // don't use priority_bitmap
+
+ // next draw the sprites
+ my_draw_sprites();
+
+ // then draw the tiles which have priority over sprites
+ tilemap_draw(
+ bitmap, // destination bitmap
+ cliprect, // clipping rectangle
+ tmap, // tilemap to draw
+ TILEMAP_DRAW_CATEGORY(1),// flags: draw category 1
+ 0); // don't use priority_bitmap
+
+ return 0;
+ }
+
+****************************************************************************
+
+ Tilemap techniques:
+
+ * The previous tilemap code specified a number of different tilemap
+ types that were fundamentally similar. This has been collapsed
+ into just two types now. Here is how to replicate that
+ functionality with the new system:
+
+ TILEMAP_OPAQUE: If you want a tilemap with no transparency,
+ you don't need to do anything; by default all pens map to
+ layer 0 and are thus non-transparent. Note that a lot of
+ code used to create OPAQUE tilemaps and then set the
+ transparent pen for them; this no longer works.
+
+ TILEMAP_TRANSPARENT: This described a tilemap with a single
+ transparent pen. To create the same effect, make a new tilemap
+ of type TILEMAP_TYPE_PEN, and then call
+ tilemap_set_transparent_pen() to specify which pen is
+ transparent; all other pens will map to layer 0.
+
+ TILEMAP_TRANSPARENT_COLOR: This works just like before and
+ even has the same type name. Create a tilemap of type
+ TILEMAP_TYPE_COLORTABLE and call
+ tilemap_set_transparent_pen() to specify which remapped pen
+ is transparent.
+
+ TILEMAP_BITMASK: This type is no longer special; with the new
+ code, any tile_get_info callback can specify a bitmask which
+ will be processed after rendering to make some pixels
+ transparent.
+
+ TILEMAP_SPLIT: This type used to let you map pens into two
+ layers (called "front" and "back") based on their pens. It
+ also allowed for you to choose one of 4 mappings on a per-tile
+ basis. All of this functionality is now expanded: you can
+ specify one of 3 layers and can choose from one of 256 mappings
+ on a per-tile basis. You just create a tilemap of type
+ TILEMAP_TYPE_PEN and call tilemap_set_transmask(),
+ which still exists but maps onto the new behavior. The "front"
+ layer is now "layer 0" and the "back" layer is now "layer 1".
+
+ TILEMAP_SPLIT_PENBIT: This type was only used in one driver
+ and is not worth describing in detail how the new mapping
+ works. :)
+
+ * By far the most common usage of layers is the simplest: layer 0 is
+ the only one used and rendered. If you want a particular tile to
+ render opaque, you can set the TILE_FORCE_LAYER0 file in your
+ tile_get_info callback.
+
+ * When drawing, you can specify in the flags which classes of pixels
+ to draw. In the low 4 bits, you specify the category; this must
+ match exactly the category specified for the tile in order to
+ render. In addition, the flags TILEMAP_DRAW_LAYERn allow you to
+ control which layer pattern to draw; note that combining these
+ flags may produce interesting results. Specifying both layer 0
+ and layer 1 will render only pixels that are in *both* layers.
+ If you want to render everything, regardless of layer, specify
+ the TILEMAP_DRAW_OPAQUE flag. If you don't specify any layers,
+ TILEMAP_DRAW_LAYER0 is assumed.
+
+ * If you want to render with alpha blending, you can call
+ tilemap_draw() with the TILEMAP_DRAW_ALPHA flag. To configure the
+ amount of alpha blending, call alpha_set_level() ahead of time.
+
+ * To configure more complex pen-to-layer mapping, use the
+ tilemap_map_pens_to_layer() call. This call takes a group number
+ so that you can configure 1 of the 256 groups independently.
+ It also takes a pen and a mask; the mapping is updated for all
+ pens where ((pennum & mask) == pen). To set all the pens in a
+ group to the same value, pass a mask of 0. To set a single pen in
+ a group, pass a mask of ~0. The helper function
+ tilemap_map_pen_to_layer() does this for you.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __TILEMAP_H__
+#define __TILEMAP_H__
+
+#include "mamecore.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* ALL_TILEMAPS may be used with: tilemap_set_flip, tilemap_mark_all_tiles_dirty */
+#define ALL_TILEMAPS NULL
+
+
+/* maximum number of groups */
+#define TILEMAP_NUM_GROUPS 256
+
+
+/* these flags control tilemap_draw() behavior */
+#define TILEMAP_DRAW_CATEGORY_MASK 0x0f /* specify the category to draw */
+#define TILEMAP_DRAW_CATEGORY(x) (x) /* specify category to draw */
+#define TILEMAP_DRAW_LAYER0 0x10 /* draw layer 0 */
+#define TILEMAP_DRAW_LAYER1 0x20 /* draw layer 1 */
+#define TILEMAP_DRAW_LAYER2 0x40 /* draw layer 2 */
+#define TILEMAP_DRAW_OPAQUE 0x80 /* draw everything, even transparent stuff */
+#define TILEMAP_DRAW_ALPHA 0x100 /* draw with alpha blending */
+
+
+/* per-pixel flags in the transparency_bitmap */
+#define TILEMAP_PIXEL_CATEGORY_MASK 0x0f /* category is stored in the low 4 bits */
+#define TILEMAP_PIXEL_TRANSPARENT 0x00 /* transparent if in none of the layers below */
+#define TILEMAP_PIXEL_LAYER0 0x10 /* pixel is opaque in layer 0 */
+#define TILEMAP_PIXEL_LAYER1 0x20 /* pixel is opaque in layer 1 */
+#define TILEMAP_PIXEL_LAYER2 0x40 /* pixel is opaque in layer 2 */
+
+
+/* per-tile flags, set by get_tile_info callback */
+#define TILE_FLIPX 0x01 /* draw this tile horizontally flipped */
+#define TILE_FLIPY 0x02 /* draw this tile vertically flipped */
+#define TILE_4BPP 0x04 /* tile data is packed 4bpp */
+#define TILE_FORCE_LAYER0 TILEMAP_PIXEL_LAYER0 /* force all pixels to be layer 0 (no transparency) */
+#define TILE_FORCE_LAYER1 TILEMAP_PIXEL_LAYER1 /* force all pixels to be layer 1 (no transparency) */
+#define TILE_FORCE_LAYER2 TILEMAP_PIXEL_LAYER2 /* force all pixels to be layer 2 (no transparency) */
+
+
+/* tilemap global flags, used by tilemap_set_flip() */
+#define TILEMAP_FLIPX TILE_FLIPX /* draw the tilemap horizontally flipped */
+#define TILEMAP_FLIPY TILE_FLIPY /* draw the tilemap vertically flipped */
+
+
+/* set this value for a scroll row/column to fully disable it */
+#define TILE_LINE_DISABLED 0x80000000
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* function definition for a get info callback */
+#define TILE_GET_INFO(_name) void _name(running_machine *machine, tile_data *tileinfo, tilemap_memory_index tile_index, void *param)
+
+/* function definition for a logical-to-memory mapper */
+#define TILEMAP_MAPPER(_name) tilemap_memory_index _name(UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows)
+
+/* useful macro inside of a TILE_GET_INFO callback to set tile information */
+#define SET_TILE_INFO(GFX,CODE,COLOR,FLAGS) tileinfo_set(machine, tileinfo, GFX, CODE, COLOR, FLAGS)
+
+/* Macros for setting tile attributes in the TILE_GET_INFO callback: */
+/* TILE_FLIP_YX assumes that flipy is in bit 1 and flipx is in bit 0 */
+/* TILE_FLIP_XY assumes that flipy is in bit 0 and flipx is in bit 1 */
+/* TILE_GROUP shifts a split group number appropriately to OR into the tile flags */
+#define TILE_FLIPYX(YX) ((YX) & 3)
+#define TILE_FLIPXY(XY) ((((XY) & 2) >> 1) | (((XY) & 1) << 1))
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* memory indexes are unsigned integers */
+typedef UINT32 tilemap_memory_index;
+
+/* opaque tilemap definition */
+typedef struct _tilemap tilemap;
+
+
+/* tilemap types */
+enum _tilemap_type
+{
+ TILEMAP_TYPE_PEN, /* pen-to-layer mapping is determined by pen lookup */
+ TILEMAP_TYPE_COLORTABLE /* pen-to-layer mapping is determined by colortable[pen] lookup */
+};
+typedef enum _tilemap_type tilemap_type;
+
+
+/* tile_data is filled in by the get_tile_info callback */
+typedef struct _tile_data tile_data;
+struct _tile_data
+{
+ const UINT8 * pen_data; /* required */
+ const UINT8 * mask_data; /* required for TILEMAP_TYPE_PEN */
+ pen_t palette_base; /* defaults to 0 */
+ UINT8 category; /* defaults to 0; range from 0..15 */
+ UINT8 group; /* defaults to 0; range from 0..TILEMAP_NUM_GROUPS */
+ UINT8 flags; /* defaults to 0; one or more of TILE_* flags above */
+};
+
+
+/* callback function to get info about a tile */
+typedef void (*tile_get_info_callback)(running_machine *machine, tile_data *tileinfo, tilemap_memory_index tile_index, void *param);
+
+/* callback function to map a column,row pair to a memory index */
+typedef tilemap_memory_index (*tilemap_mapper_callback)(UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows);
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+extern mame_bitmap *priority_bitmap;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- system-wide management ----- */
+
+/* initialize the tilemap system -- not for use by drivers */
+void tilemap_init(running_machine *machine);
+
+
+
+/* ----- tilemap creation and configuration ----- */
+
+/* create a new tilemap; note that tilemaps are tracked by the core so there is no dispose */
+tilemap *tilemap_create(tile_get_info_callback tile_get_info, tilemap_mapper_callback mapper, tilemap_type type, int tilewidth, int tileheight, int cols, int rows);
+
+/* specify a parameter to be passed into the tile_get_info callback */
+void tilemap_set_user_data(tilemap *tmap, void *user_data);
+
+/* specify an offset to be added to each pixel before looking up the palette */
+void tilemap_set_palette_offset(tilemap *tmap, UINT32 offset);
+
+/* set an enable flag for the tilemap; if 0, requests to draw the tilemap are ignored */
+void tilemap_set_enable(tilemap *tmap, int enable);
+
+/* set a global flip for the tilemap; ALL_TILEMAPS can be passed here as well */
+void tilemap_set_flip(tilemap *tmap, UINT32 attributes);
+
+
+
+/* ----- dirty tile marking ----- */
+
+/* mark a single tile dirty based on its memory index */
+void tilemap_mark_tile_dirty(tilemap *tmap, tilemap_memory_index memory_index);
+
+/* mark all the tiles in a tilemap dirty; ALL_TILEMAPS can be passed here as well */
+void tilemap_mark_all_tiles_dirty(tilemap *tmap);
+
+
+
+/* ----- pen-to-layer mapping ----- */
+
+/* specify the mapping of one or more pens (where (<pen> & mask == pen) to a layer */
+void tilemap_map_pens_to_layer(tilemap *tmap, int group, pen_t pen, pen_t mask, UINT8 layermask);
+
+/* set a single transparent pen into the tilemap, mapping all other pens to layer 0 */
+void tilemap_set_transparent_pen(tilemap *tmap, pen_t pen);
+
+/* set up the first 32 pens using a foreground (layer 0) mask and a background (layer 1) mask */
+void tilemap_set_transmask(tilemap *tmap, int group, UINT32 fgmask, UINT32 bgmask);
+
+
+
+/* ----- tilemap scrolling ----- */
+
+/* specify the number of independently scrollable row units; each unit covers height/scroll_rows pixels */
+void tilemap_set_scroll_rows(tilemap *tmap, UINT32 scroll_rows);
+
+/* specify the number of independently scrollable column units; each unit covers width/scroll_cols pixels */
+void tilemap_set_scroll_cols(tilemap *tmap, UINT32 scroll_cols);
+
+/* specify global horizontal and vertical scroll offsets, for non-flipped and flipped cases */
+void tilemap_set_scrolldx(tilemap *tmap, int dx, int dx_if_flipped);
+void tilemap_set_scrolldy(tilemap *tmap, int dy, int dy_if_flipped);
+
+/* return the global horizontal or vertical scroll offset, based on current flip state */
+int tilemap_get_scrolldx(tilemap *tmap);
+int tilemap_get_scrolldy(tilemap *tmap);
+
+/* specify the scroll value for a row/column unit */
+void tilemap_set_scrollx(tilemap *tmap, int row, int value);
+void tilemap_set_scrolly(tilemap *tmap, int col, int value);
+
+
+
+/* ----- internal map access ----- */
+
+/* return a pointer to the (updated) internal pixmap for a tilemap */
+mame_bitmap *tilemap_get_pixmap(tilemap *tmap);
+
+/* return a pointer to the (updated) internal flagsmap for a tilemap */
+mame_bitmap *tilemap_get_flagsmap(tilemap *tmap);
+
+/* return a pointer to the (updated) internal per-tile flags for a tilemap */
+UINT8 *tilemap_get_tile_flags(tilemap *tmap);
+
+
+
+/* ----- tilemap rendering ----- */
+
+/* draw a tilemap to the destination with clipping; pixels apply priority/priority_mask to the priority bitmap */
+void tilemap_draw_primask(mame_bitmap *dest, const rectangle *cliprect, tilemap *tmap, UINT32 flags, UINT8 priority, UINT8 priority_mask);
+
+/* draw a tilemap to the destination with clipping and arbitrary rotate/zoom; */
+/* pixels apply priority/priority_mask to the priority bitmap */
+void tilemap_draw_roz_primask(mame_bitmap *dest, const rectangle *cliprect, tilemap *tmap,
+ UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy,
+ int wraparound, UINT32 flags, UINT8 priority, UINT8 priority_mask);
+
+
+
+/* ----- indexed tilemap handling ----- */
+
+/* return the number of tilemaps */
+int tilemap_count(void);
+
+/* return the size of an indexed tilemap */
+void tilemap_size_by_index(int number, UINT32 *width, UINT32 *height);
+
+/* render an indexed tilemap with fixed characteristics (no priority) */
+void tilemap_draw_by_index(mame_bitmap *dest, int number, UINT32 scrollx, UINT32 scrolly);
+
+
+
+/* ----- common logical-to-memory mappers ----- */
+
+/* scan in row-major order with optional flipping */
+TILEMAP_MAPPER( tilemap_scan_rows );
+TILEMAP_MAPPER( tilemap_scan_rows_flip_x );
+TILEMAP_MAPPER( tilemap_scan_rows_flip_y );
+TILEMAP_MAPPER( tilemap_scan_rows_flip_xy );
+
+/* scan in column-major order with optional flipping */
+TILEMAP_MAPPER( tilemap_scan_cols );
+TILEMAP_MAPPER( tilemap_scan_cols_flip_x );
+TILEMAP_MAPPER( tilemap_scan_cols_flip_y );
+TILEMAP_MAPPER( tilemap_scan_cols_flip_xy );
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ tileinfo_set - set the values of a tileinfo
+ structure
+-------------------------------------------------*/
+
+INLINE void tileinfo_set(running_machine *machine, tile_data *tileinfo, int gfxnum, int rawcode, int rawcolor, int flags)
+{
+ const gfx_element * gfx = machine->gfx[gfxnum];
+ int code = rawcode % gfx->total_elements;
+ tileinfo->pen_data = gfx->gfxdata + code * gfx->char_modulo;
+ tileinfo->palette_base = gfx->color_base + gfx->color_granularity * rawcolor;
+ tileinfo->flags = flags;
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ tileinfo->flags |= TILE_4BPP;
+}
+
+
+/*-------------------------------------------------
+ tilemap_map_pen_to_layer - map a single pen
+ to a layer
+-------------------------------------------------*/
+
+INLINE void tilemap_map_pen_to_layer(tilemap *tmap, int group, pen_t pen, UINT8 layermask)
+{
+ tilemap_map_pens_to_layer(tmap, group, pen, ~0, layermask);
+}
+
+
+/*-------------------------------------------------
+ tilemap_draw - shortcut to
+ tilemap_draw_primask
+-------------------------------------------------*/
+
+INLINE void tilemap_draw(mame_bitmap *dest, const rectangle *cliprect, tilemap *tmap, UINT32 flags, UINT8 priority)
+{
+ tilemap_draw_primask(dest, cliprect, tmap, flags, priority, 0xff);
+}
+
+
+/*-------------------------------------------------
+ tilemap_draw_roz - shortcut to
+ tilemap_draw_roz_primask
+-------------------------------------------------*/
+
+INLINE void tilemap_draw_roz(mame_bitmap *dest, const rectangle *cliprect, tilemap *tmap,
+ UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy,
+ int wraparound, UINT32 flags, UINT8 priority)
+{
+ tilemap_draw_roz_primask(dest, cliprect, tmap, startx, starty, incxx, incxy, incyx, incyy, wraparound, flags, priority, 0xff);
+}
+
+
+
+#endif /* __TILEMAP_H__ */
diff --git a/src/emu/timer.c b/src/emu/timer.c
new file mode 100644
index 00000000000..cd1b4fe3eb1
--- /dev/null
+++ b/src/emu/timer.c
@@ -0,0 +1,810 @@
+/***************************************************************************
+
+ timer.c
+
+ Functions needed to generate timing and synchronization between several
+ CPUs.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+#include "pool.h"
+#include <math.h>
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) do { logerror x; } while (0)
+#else
+#define LOG(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_TIMERS 256
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* in timer.h: typedef struct _emu_timer emu_timer; */
+struct _emu_timer
+{
+ emu_timer * next;
+ emu_timer * prev;
+ void (*callback)(running_machine *, int);
+ void (*callback_ptr)(running_machine *, void *);
+ int callback_param;
+ void * callback_ptr_param;
+ const char * file;
+ int line;
+ const char * func;
+ UINT8 enabled;
+ UINT8 temporary;
+ UINT8 ptr;
+ attotime period;
+ attotime start;
+ attotime expire;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* conversion constants */
+attoseconds_t attoseconds_per_cycle[MAX_CPU];
+UINT32 cycles_per_second[MAX_CPU];
+
+/* list of active timers */
+static emu_timer timers[MAX_TIMERS];
+static emu_timer *timer_head;
+static emu_timer *timer_free_head;
+static emu_timer *timer_free_tail;
+
+/* other internal states */
+static attotime global_basetime;
+static emu_timer *callback_timer;
+static int callback_timer_modified;
+static attotime callback_timer_expire_time;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void timer_postload(void);
+static void timer_logtimers(void);
+static void timer_remove(emu_timer *which);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ get_current_time - return the current time
+-------------------------------------------------*/
+
+INLINE attotime get_current_time(void)
+{
+ int activecpu;
+
+ /* if we're currently in a callback, use the timer's expiration time as a base */
+ if (callback_timer != NULL)
+ return callback_timer_expire_time;
+
+ /* if we're executing as a particular CPU, use its local time as a base */
+ activecpu = cpu_getactivecpu();
+ if (activecpu >= 0)
+ return cpunum_get_localtime(activecpu);
+
+ /* otherwise, return the current global base time */
+ return global_basetime;
+}
+
+
+/*-------------------------------------------------
+ timer_new - allocate a new timer
+-------------------------------------------------*/
+
+INLINE emu_timer *timer_new(void)
+{
+ emu_timer *timer;
+
+ /* remove an empty entry */
+ if (!timer_free_head)
+ {
+ timer_logtimers();
+ fatalerror("Out of timers!");
+ }
+ timer = timer_free_head;
+ timer_free_head = timer->next;
+ if (!timer_free_head)
+ timer_free_tail = NULL;
+
+ return timer;
+}
+
+
+/*-------------------------------------------------
+ timer_list_insert - insert a new timer into
+ the list at the appropriate location
+-------------------------------------------------*/
+
+INLINE void timer_list_insert(emu_timer *timer)
+{
+ attotime expire = timer->enabled ? timer->expire : attotime_never;
+ emu_timer *t, *lt = NULL;
+
+ /* sanity checks for the debug build */
+ #ifdef MAME_DEBUG
+ {
+ int tnum = 0;
+
+ /* loop over the timer list */
+ for (t = timer_head; t; t = t->next, tnum++)
+ {
+ if (t == timer)
+ fatalerror("This timer is already inserted in the list!");
+ if (tnum == MAX_TIMERS-1)
+ fatalerror("Timer list is full!");
+ }
+ }
+ #endif
+
+ /* loop over the timer list */
+ for (t = timer_head; t; lt = t, t = t->next)
+ {
+ /* if the current list entry expires after us, we should be inserted before it */
+ if (attotime_compare(t->expire, expire) > 0)
+ {
+ /* link the new guy in before the current list entry */
+ timer->prev = t->prev;
+ timer->next = t;
+
+ if (t->prev)
+ t->prev->next = timer;
+ else
+ timer_head = timer;
+ t->prev = timer;
+ return;
+ }
+ }
+
+ /* need to insert after the last one */
+ if (lt)
+ lt->next = timer;
+ else
+ timer_head = timer;
+ timer->prev = lt;
+ timer->next = NULL;
+}
+
+
+/*-------------------------------------------------
+ timer_list_remove - remove a timer from the
+ linked list
+-------------------------------------------------*/
+
+INLINE void timer_list_remove(emu_timer *timer)
+{
+ /* sanity checks for the debug build */
+ #ifdef MAME_DEBUG
+ {
+ emu_timer *t;
+
+ /* loop over the timer list */
+ for (t = timer_head; t && t != timer; t = t->next) ;
+ if (t == NULL)
+ fatalerror("timer (%s from %s:%d) not found in list", timer->func, timer->file, timer->line);
+ }
+ #endif
+
+ /* remove it from the list */
+ if (timer->prev)
+ timer->prev->next = timer->next;
+ else
+ timer_head = timer->next;
+ if (timer->next)
+ timer->next->prev = timer->prev;
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_init - initialize the timer system
+-------------------------------------------------*/
+
+void timer_init(running_machine *machine)
+{
+ int i;
+
+ /* we need to wait until the first call to timer_cyclestorun before using real CPU times */
+ global_basetime = attotime_zero;
+ callback_timer = NULL;
+ callback_timer_modified = FALSE;
+
+ /* register with the save state system */
+ state_save_push_tag(0);
+ state_save_register_item("timer", 0, global_basetime.seconds);
+ state_save_register_item("timer", 0, global_basetime.attoseconds);
+ state_save_register_func_postload(timer_postload);
+ state_save_pop_tag();
+
+ /* reset the timers */
+ memset(timers, 0, sizeof(timers));
+
+ /* initialize the lists */
+ timer_head = NULL;
+ timer_free_head = &timers[0];
+ for (i = 0; i < MAX_TIMERS-1; i++)
+ timers[i].next = &timers[i+1];
+ timers[MAX_TIMERS-1].next = NULL;
+ timer_free_tail = &timers[MAX_TIMERS-1];
+}
+
+
+/*-------------------------------------------------
+ timer_destructor - destruct a timer from a
+ pool callback
+-------------------------------------------------*/
+
+void timer_destructor(void *ptr, size_t size)
+{
+ timer_remove(ptr);
+}
+
+
+
+/***************************************************************************
+ SCHEDULING HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_next_fire_time - return the
+ time when the next timer will fire
+-------------------------------------------------*/
+
+attotime timer_next_fire_time(void)
+{
+ return timer_head->expire;
+}
+
+
+/*-------------------------------------------------
+ timer_adjust_global_time - adjust the global
+ time; this is also where we fire the timers
+-------------------------------------------------*/
+
+void timer_set_global_time(attotime newbase)
+{
+ emu_timer *timer;
+
+ /* set the new global offset */
+ global_basetime = newbase;
+
+ LOG(("timer_set_global_time: new=%s head->expire=%s\n", attotime_string(newbase), attotime_string(timer_head->expire)));
+
+ /* now process any timers that are overdue */
+ while (attotime_compare(timer_head->expire, global_basetime) <= 0)
+ {
+ int was_enabled = timer_head->enabled;
+
+ /* if this is a one-shot timer, disable it now */
+ timer = timer_head;
+ if (attotime_compare(timer->period, attotime_zero) == 0 || attotime_compare(timer->period, attotime_never) == 0)
+ timer->enabled = FALSE;
+
+ /* set the global state of which callback we're in */
+ callback_timer_modified = FALSE;
+ callback_timer = timer;
+ callback_timer_expire_time = timer->expire;
+
+ /* call the callback */
+ if (was_enabled)
+ {
+ if (!timer->ptr && timer->callback)
+ {
+ LOG(("Timer %s:%d[%s] fired (expire=%s)\n", timer->file, timer->line, timer->func, attotime_string(timer->expire, 9)));
+ profiler_mark(PROFILER_TIMER_CALLBACK);
+ (*timer->callback)(Machine, timer->callback_param);
+ profiler_mark(PROFILER_END);
+ }
+ else if (timer->ptr && timer->callback_ptr)
+ {
+ LOG(("Timer %s:%d[%s] fired (expire=%s)\n", timer->file, timer->line, timer->func, attotime_string(timer->expire, 9)));
+ profiler_mark(PROFILER_TIMER_CALLBACK);
+ (*timer->callback_ptr)(Machine, timer->callback_ptr_param);
+ profiler_mark(PROFILER_END);
+ }
+ }
+
+ /* clear the callback timer global */
+ callback_timer = NULL;
+
+ /* reset or remove the timer, but only if it wasn't modified during the callback */
+ if (!callback_timer_modified)
+ {
+ /* if the timer is temporary, remove it now */
+ if (timer->temporary)
+ timer_remove(timer);
+
+ /* otherwise, reschedule it */
+ else
+ {
+ timer->start = timer->expire;
+ timer->expire = attotime_add(timer->expire, timer->period);
+
+ timer_list_remove(timer);
+ timer_list_insert(timer);
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ SAVE/RESTORE HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_register_save - register ourself with
+ the save state system
+-------------------------------------------------*/
+
+static void timer_register_save(emu_timer *timer)
+{
+ char buf[256];
+ int count = 0;
+ emu_timer *t;
+
+ /* find other timers that match our func name */
+ for (t = timer_head; t; t = t->next)
+ if (!strcmp(t->func, timer->func))
+ count++;
+
+ /* make up a name */
+ sprintf(buf, "timer.%s", timer->func);
+
+ /* use different instances to differentiate the bits */
+ state_save_push_tag(0);
+ state_save_register_item(buf, count, timer->callback_param);
+ state_save_register_item(buf, count, timer->enabled);
+ state_save_register_item(buf, count, timer->period.seconds);
+ state_save_register_item(buf, count, timer->period.attoseconds);
+ state_save_register_item(buf, count, timer->start.seconds);
+ state_save_register_item(buf, count, timer->start.attoseconds);
+ state_save_register_item(buf, count, timer->expire.seconds);
+ state_save_register_item(buf, count, timer->expire.attoseconds);
+ state_save_pop_tag();
+}
+
+
+/*-------------------------------------------------
+ timer_postload - after loading a save state
+-------------------------------------------------*/
+
+static void timer_postload(void)
+{
+ emu_timer *privlist = NULL;
+ emu_timer *t;
+
+ /* remove all timers and make a private list */
+ while (timer_head)
+ {
+ t = timer_head;
+
+ /* temporary timers go away entirely */
+ if (t->temporary)
+ timer_remove(t);
+
+ /* permanent ones get added to our private list */
+ else
+ {
+ timer_list_remove(t);
+ t->next = privlist;
+ privlist = t;
+ }
+ }
+
+ /* now add them all back in; this effectively re-sorts them by time */
+ while (privlist)
+ {
+ t = privlist;
+ privlist = t->next;
+ timer_list_insert(t);
+ }
+}
+
+
+/*-------------------------------------------------
+ timer_count_anonymous - count the number of
+ anonymous (non-saveable) timers
+-------------------------------------------------*/
+
+int timer_count_anonymous(void)
+{
+ emu_timer *t;
+ int count = 0;
+
+ logerror("timer_count_anonymous:\n");
+ for (t = timer_head; t; t = t->next)
+ if (t->temporary && t != callback_timer)
+ {
+ count++;
+ logerror(" Temp. timer %p, file %s:%d[%s]\n", (void *) t, t->file, t->line, t->func);
+ }
+ logerror("%d temporary timers found\n", count);
+
+ return count;
+}
+
+
+
+/***************************************************************************
+ CORE TIMER ALLOCATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_alloc - allocate a permament timer that
+ isn't primed yet
+-------------------------------------------------*/
+
+INLINE emu_timer *_timer_alloc_common(void (*callback)(running_machine *, int), void (*callback_ptr)(running_machine *, void *), void *param, const char *file, int line, const char *func, int temp)
+{
+ attotime time = get_current_time();
+ emu_timer *timer = timer_new();
+
+ /* fill in the record */
+ timer->callback = callback;
+ timer->callback_ptr = callback_ptr;
+ timer->callback_param = 0;
+ timer->callback_ptr_param = param;
+ timer->enabled = FALSE;
+ timer->temporary = temp;
+ timer->ptr = (callback_ptr != NULL);
+ timer->period = attotime_zero;
+ timer->file = file;
+ timer->line = line;
+ timer->func = func;
+
+ /* compute the time of the next firing and insert into the list */
+ timer->start = time;
+ timer->expire = attotime_never;
+ timer_list_insert(timer);
+
+ /* if we're not temporary, register ourselve with the save state system */
+ if (!temp)
+ {
+ timer_register_save(timer);
+ restrack_register_object(OBJTYPE_TIMER, timer, 0, file, line);
+ }
+
+ /* return a handle */
+ return timer;
+}
+
+emu_timer *_timer_alloc(void (*callback)(running_machine *, int), const char *file, int line, const char *func)
+{
+ return _timer_alloc_common(callback, NULL, NULL, file, line, func, FALSE);
+}
+
+emu_timer *_timer_alloc_ptr(void (*callback_ptr)(running_machine *, void *), void *param, const char *file, int line, const char *func)
+{
+ return _timer_alloc_common(NULL, callback_ptr, param, file, line, func, FALSE);
+}
+
+
+/*-------------------------------------------------
+ timer_remove - remove a timer from the
+ system
+-------------------------------------------------*/
+
+static void timer_remove(emu_timer *which)
+{
+ /* if this is a callback timer, note that */
+ if (which == callback_timer)
+ callback_timer_modified = TRUE;
+
+ /* remove it from the list */
+ timer_list_remove(which);
+
+ /* free it up by adding it back to the free list */
+ if (timer_free_tail)
+ timer_free_tail->next = which;
+ else
+ timer_free_head = which;
+ which->next = NULL;
+ timer_free_tail = which;
+}
+
+
+
+/***************************************************************************
+ CORE TIMER ADJUSTMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_adjust - adjust the time when this
+ timer will fire, and whether or not it will
+ fire periodically
+-------------------------------------------------*/
+
+INLINE void timer_adjust_common(emu_timer *which, attotime duration, INT32 param, attotime period)
+{
+ attotime time = get_current_time();
+
+ /* if this is the callback timer, mark it modified */
+ if (which == callback_timer)
+ callback_timer_modified = TRUE;
+
+ /* compute the time of the next firing and insert into the list */
+ which->callback_param = param;
+ which->enabled = TRUE;
+
+ /* clamp negative times to 0 */
+ if (duration.seconds < 0)
+ duration = attotime_zero;
+
+ /* set the start and expire times */
+ which->start = time;
+ which->expire = attotime_add(time, duration);
+ which->period = period;
+
+ /* remove and re-insert the timer in its new order */
+ timer_list_remove(which);
+ timer_list_insert(which);
+
+ /* if this was inserted as the head, abort the current timeslice and resync */
+ LOG(("timer_adjust %s.%s:%d to expire @ %s\n", which->file, which->func, which->line, attotime_string(which->expire, 9)));
+ if (which == timer_head && cpu_getexecutingcpu() >= 0)
+ activecpu_abort_timeslice();
+}
+
+void timer_adjust(emu_timer *which, attotime duration, INT32 param, attotime period)
+{
+ if (which->ptr)
+ fatalerror("timer_adjust called on a ptr timer!");
+ timer_adjust_common(which, duration, param, period);
+}
+
+void timer_adjust_ptr(emu_timer *which, attotime duration, attotime period)
+{
+ if (!which->ptr)
+ fatalerror("timer_adjust_ptr called on a non-ptr timer!");
+ timer_adjust_common(which, duration, 0, period);
+}
+
+
+
+/***************************************************************************
+ SIMPLIFIED ANONYMOUS TIMER MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_pulse - allocate a pulse timer, which
+ repeatedly calls the callback using the given
+ period
+-------------------------------------------------*/
+
+void _timer_pulse(attotime period, INT32 param, void (*callback)(running_machine *, int), const char *file, int line, const char *func)
+{
+ emu_timer *timer = _timer_alloc_common(callback, NULL, NULL, file, line, func, FALSE);
+
+ /* adjust to our liking */
+ timer_adjust(timer, period, param, period);
+}
+
+void _timer_pulse_ptr(attotime period, void *param, void (*callback)(running_machine *, void *), const char *file, int line, const char *func)
+{
+ emu_timer *timer = _timer_alloc_common(NULL, callback, param, file, line, func, FALSE);
+
+ /* adjust to our liking */
+ timer_adjust_ptr(timer, period, period);
+}
+
+
+/*-------------------------------------------------
+ timer_set - allocate a one-shot timer, which
+ calls the callback after the given duration
+-------------------------------------------------*/
+
+void _timer_set(attotime duration, INT32 param, void (*callback)(running_machine *, int), const char *file, int line, const char *func)
+{
+ emu_timer *timer = _timer_alloc_common(callback, NULL, NULL, file, line, func, TRUE);
+
+ /* adjust to our liking */
+ timer_adjust(timer, duration, param, attotime_zero);
+}
+
+void _timer_set_ptr(attotime duration, void *param, void (*callback)(running_machine *, void *), const char *file, int line, const char *func)
+{
+ emu_timer *timer = _timer_alloc_common(NULL, callback, param, file, line, func, TRUE);
+
+ /* adjust to our liking */
+ timer_adjust_ptr(timer, duration, attotime_zero);
+}
+
+
+
+/***************************************************************************
+ MISCELLANEOUS CONTROLS
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_reset - reset the timing on a timer
+-------------------------------------------------*/
+
+void timer_reset(emu_timer *which, attotime duration)
+{
+ /* adjust the timer */
+ if (!which->ptr)
+ timer_adjust(which, duration, which->callback_param, which->period);
+ else
+ timer_adjust_ptr(which, duration, which->period);
+}
+
+
+/*-------------------------------------------------
+ timer_enable - enable/disable a timer
+-------------------------------------------------*/
+
+int timer_enable(emu_timer *which, int enable)
+{
+ int old;
+
+ /* set the enable flag */
+ old = which->enabled;
+ which->enabled = enable;
+
+ /* remove the timer and insert back into the list */
+ timer_list_remove(which);
+ timer_list_insert(which);
+
+ return old;
+}
+
+
+/*-------------------------------------------------
+ timer_enabled - determine if a timer is
+ enabled
+-------------------------------------------------*/
+
+int timer_enabled(emu_timer *which)
+{
+ return which->enabled;
+}
+
+
+/*-------------------------------------------------
+ timer_get_param
+ timer_get_param_ptr - returns the callback
+ parameter of a timer
+-------------------------------------------------*/
+
+int timer_get_param(emu_timer *which)
+{
+ return which->callback_param;
+}
+
+
+void *timer_get_param_ptr(emu_timer *which)
+{
+ return which->callback_ptr_param;
+}
+
+
+
+/***************************************************************************
+ TIMING FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_timeelapsed - return the time since the
+ last trigger
+-------------------------------------------------*/
+
+attotime timer_timeelapsed(emu_timer *which)
+{
+ return attotime_sub(get_current_time(), which->start);
+}
+
+
+/*-------------------------------------------------
+ timer_timeleft - return the time until the
+ next trigger
+-------------------------------------------------*/
+
+attotime timer_timeleft(emu_timer *which)
+{
+ return attotime_sub(which->expire, get_current_time());
+}
+
+
+/*-------------------------------------------------
+ timer_get_time - return the current time
+-------------------------------------------------*/
+
+attotime timer_get_time(void)
+{
+ return get_current_time();
+}
+
+
+/*-------------------------------------------------
+ timer_starttime - return the time when this
+ timer started counting
+-------------------------------------------------*/
+
+attotime timer_starttime(emu_timer *which)
+{
+ return which->start;
+}
+
+
+/*-------------------------------------------------
+ timer_firetime - return the time when this
+ timer will fire next
+-------------------------------------------------*/
+
+attotime timer_firetime(emu_timer *which)
+{
+ return which->expire;
+}
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_logtimers - log all the timers
+-------------------------------------------------*/
+
+static void timer_logtimers(void)
+{
+ emu_timer *t;
+
+ logerror("===============\n");
+ logerror("TIMER LOG START\n");
+ logerror("===============\n");
+
+ logerror("Enqueued timers:\n");
+ for (t = timer_head; t; t = t->next)
+ logerror(" Start=%15.6f Exp=%15.6f Per=%15.6f Ena=%d Tmp=%d (%s:%d[%s])\n",
+ attotime_to_double(t->start), attotime_to_double(t->expire), attotime_to_double(t->period), t->enabled, t->temporary, t->file, t->line, t->func);
+
+ logerror("Free timers:\n");
+ for (t = timer_free_head; t; t = t->next)
+ logerror(" Start=%15.6f Exp=%15.6f Per=%15.6f Ena=%d Tmp=%d (%s:%d[%s])\n",
+ attotime_to_double(t->start), attotime_to_double(t->expire), attotime_to_double(t->period), t->enabled, t->temporary, t->file, t->line, t->func);
+
+ logerror("==============\n");
+ logerror("TIMER LOG STOP\n");
+ logerror("==============\n");
+}
diff --git a/src/emu/timer.h b/src/emu/timer.h
new file mode 100644
index 00000000000..e8193b4b170
--- /dev/null
+++ b/src/emu/timer.h
@@ -0,0 +1,185 @@
+/***************************************************************************
+
+ timer.h
+
+ Functions needed to generate timing and synchronization between several
+ CPUs.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __TIMER_H__
+#define __TIMER_H__
+
+#include "mamecore.h"
+#include "attotime.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* convert cycles on a given CPU to/from attotime */
+#define ATTOTIME_TO_CYCLES(cpu,t) ((t).seconds * cycles_per_second[cpu] + (t).attoseconds / attoseconds_per_cycle[cpu])
+#define ATTOTIME_IN_CYCLES(c,cpu) (attotime_make((c) / cycles_per_second[cpu], (c) * attoseconds_per_cycle[cpu]))
+
+/* macro for the RC time constant on a 74LS123 with C > 1000pF */
+/* R is in ohms, C is in farads */
+#define TIME_OF_74LS123(r,c) (0.45 * (double)(r) * (double)(c))
+
+/* macros for the RC time constant on a 555 timer IC */
+/* R is in ohms, C is in farads */
+#define PERIOD_OF_555_MONOSTABLE(r,c) ATTOTIME_IN_NSEC((attoseconds_t)(1100000000 * (double)(r) * (double)(c)))
+#define PERIOD_OF_555_ASTABLE(r1,r2,c) ATTOTIME_IN_NSEC((attoseconds_t)( 693000000 * ((double)(r1) + 2.0 * (double)(r2)) * (double)(c)))
+
+/* macros that map all allocations to provide file/line/functions to the callee */
+#define timer_alloc(c) _timer_alloc(c, __FILE__, __LINE__, #c)
+#define timer_alloc_ptr(c,p) _timer_alloc_ptr(c, p, __FILE__, __LINE__, #c)
+#define timer_pulse(e,p,c) _timer_pulse(e, p, c, __FILE__, __LINE__, #c)
+#define timer_pulse_ptr(e,p,c) _timer_pulse_ptr(e, p, c, __FILE__, __LINE__, #c)
+#define timer_set(d,p,c) _timer_set(d, p, c, __FILE__, __LINE__, #c)
+#define timer_set_ptr(d,p,c) _timer_set_ptr(d, p, c, __FILE__, __LINE__, #c)
+
+/* macros for a timer callback functions */
+#define TIMER_CALLBACK(name) void name(running_machine *machine, int param)
+#define TIMER_CALLBACK_PTR(name) void name(running_machine *machine, void *param)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* opaque type for representing a timer */
+typedef struct _emu_timer emu_timer;
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* arrays containing mappings between CPU cycle times and timer values */
+extern attoseconds_t attoseconds_per_cycle[];
+extern UINT32 cycles_per_second[];
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- initialization ----- */
+
+/* initialize the timer system */
+void timer_init(running_machine *machine);
+
+/* destruct a timer from a pool callback */
+void timer_destructor(void *ptr, size_t size);
+
+
+
+/* ----- scheduling helpers ----- */
+
+/* return the time when the next timer will fire */
+attotime timer_next_fire_time(void);
+
+/* adjust the global time; this is also where we fire the timers */
+void timer_set_global_time(attotime newbase);
+
+
+
+/* ----- save/restore helpers ----- */
+
+/* count the number of anonymous (non-saveable) timers */
+int timer_count_anonymous(void);
+
+
+
+/* ----- core timer management ----- */
+
+/* allocate a permament timer that isn't primed yet */
+emu_timer *_timer_alloc(void (*callback)(running_machine *, int), const char *file, int line, const char *func);
+emu_timer *_timer_alloc_ptr(void (*callback)(running_machine *, void *), void *param, const char *file, int line, const char *func);
+
+/* adjust the time when this timer will fire, and whether or not it will fire periodically */
+void timer_adjust(emu_timer *which, attotime duration, INT32 param, attotime period);
+void timer_adjust_ptr(emu_timer *which, attotime duration, attotime period);
+
+
+
+/* ----- anonymous timer management ----- */
+
+/* allocate a pulse timer, which repeatedly calls the callback using the given period */
+void _timer_pulse(attotime period, INT32 param, void (*callback)(running_machine *, int), const char *file, int line, const char *func);
+void _timer_pulse_ptr(attotime period, void *param, void (*callback)(running_machine *, void *), const char *file, int line, const char *func);
+
+/* allocate a one-shot timer, which calls the callback after the given duration */
+void _timer_set(attotime duration, INT32 param, void (*callback)(running_machine *, int), const char *file, int line, const char *func);
+void _timer_set_ptr(attotime duration, void *param, void (*callback)(running_machine *, void *), const char *file, int line, const char *func);
+
+
+
+/* ----- miscellaneous controls ----- */
+
+/* reset the timing on a timer */
+void timer_reset(emu_timer *which, attotime duration);
+
+/* enable/disable a timer */
+int timer_enable(emu_timer *which, int enable);
+
+/* determine if a timer is enabled */
+int timer_enabled(emu_timer *which);
+
+/* returns the callback parameter of a timer */
+int timer_get_param(emu_timer *which);
+void *timer_get_param_ptr(emu_timer *which);
+
+
+
+/* ----- timing functions ----- */
+
+/* return the time since the last trigger */
+attotime timer_timeelapsed(emu_timer *which);
+
+/* return the time until the next trigger */
+attotime timer_timeleft(emu_timer *which);
+
+/* return the current time */
+attotime timer_get_time(void);
+
+/* return the time when this timer started counting */
+attotime timer_starttime(emu_timer *which);
+
+/* return the time when this timer will fire next */
+attotime timer_firetime(emu_timer *which);
+
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_call_after_resynch - synchs the CPUs
+ and calls the callback immediately
+-------------------------------------------------*/
+
+INLINE void timer_call_after_resynch(INT32 param, void (*callback)(running_machine *, int))
+{
+ timer_set(attotime_zero, param, callback);
+}
+
+INLINE void timer_call_after_resynch_ptr(void *param, void (*callback)(running_machine *, void *))
+{
+ timer_set_ptr(attotime_zero, param, callback);
+}
+
+
+#endif /* __TIMER_H__ */
diff --git a/src/emu/ui.c b/src/emu/ui.c
new file mode 100644
index 00000000000..4267422f0f7
--- /dev/null
+++ b/src/emu/ui.c
@@ -0,0 +1,1961 @@
+/*********************************************************************
+
+ ui.c
+
+ Functions used to handle MAME's user interface.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "osdepend.h"
+#include "video/vector.h"
+#include "profiler.h"
+#include "cheat.h"
+#include "render.h"
+#include "rendfont.h"
+#include "ui.h"
+#include "uimenu.h"
+#include "uigfx.h"
+#include "uitext.h"
+
+#ifdef MESS
+#include "mess.h"
+#include "uimess.h"
+#include "inputx.h"
+#endif
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <math.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+enum
+{
+ INPUT_TYPE_DIGITAL = 0,
+ INPUT_TYPE_ANALOG = 1,
+ INPUT_TYPE_ANALOG_DEC = 2,
+ INPUT_TYPE_ANALOG_INC = 3
+};
+
+enum
+{
+ ANALOG_ITEM_KEYSPEED = 0,
+ ANALOG_ITEM_CENTERSPEED,
+ ANALOG_ITEM_REVERSE,
+ ANALOG_ITEM_SENSITIVITY,
+ ANALOG_ITEM_COUNT
+};
+
+enum
+{
+ LOADSAVE_NONE,
+ LOADSAVE_LOAD,
+ LOADSAVE_SAVE
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _slider_state slider_state;
+struct _slider_state
+{
+ INT32 minval; /* minimum value */
+ INT32 defval; /* default value */
+ INT32 maxval; /* maximum value */
+ INT32 incval; /* increment value */
+ INT32 (*update)(INT32 newval, char *buffer, int arg); /* callback */
+ int arg; /* argument */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* font for rendering */
+static render_font *ui_font;
+
+/* current UI handler */
+static UINT32 (*ui_handler_callback)(UINT32);
+static UINT32 ui_handler_param;
+
+/* flag to track single stepping */
+static int single_step;
+
+/* FPS counter display */
+static int showfps;
+static osd_ticks_t showfps_end;
+
+/* profiler display */
+static int show_profiler;
+
+/* popup text display */
+static osd_ticks_t popup_text_end;
+
+/* messagebox buffer */
+static char messagebox_text[4096];
+static rgb_t messagebox_backcolor;
+
+/* slider info */
+static slider_state slider_list[100];
+static int slider_count;
+static int slider_current;
+
+static int display_rescale_message;
+static int allow_rescale;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void ui_exit(running_machine *machine);
+static int rescale_notifier(running_machine *machine, int width, int height);
+
+/* text generators */
+static int sprintf_disclaimer(char *buffer);
+static int sprintf_warnings(char *buffer);
+
+/* UI handlers */
+static UINT32 handler_messagebox(UINT32 state);
+static UINT32 handler_messagebox_ok(UINT32 state);
+static UINT32 handler_messagebox_anykey(UINT32 state);
+static UINT32 handler_ingame(UINT32 state);
+static UINT32 handler_slider(UINT32 state);
+static UINT32 handler_load_save(UINT32 state);
+
+/* slider controls */
+static void slider_init(void);
+static void slider_display(const char *text, int minval, int maxval, int defval, int curval);
+static void slider_draw_bar(float leftx, float topy, float width, float height, float percentage, float default_percentage);
+static INT32 slider_volume(INT32 newval, char *buffer, int arg);
+static INT32 slider_mixervol(INT32 newval, char *buffer, int arg);
+static INT32 slider_adjuster(INT32 newval, char *buffer, int arg);
+static INT32 slider_overclock(INT32 newval, char *buffer, int arg);
+static INT32 slider_refresh(INT32 newval, char *buffer, int arg);
+static INT32 slider_brightness(INT32 newval, char *buffer, int arg);
+static INT32 slider_contrast(INT32 newval, char *buffer, int arg);
+static INT32 slider_gamma(INT32 newval, char *buffer, int arg);
+static INT32 slider_xscale(INT32 newval, char *buffer, int arg);
+static INT32 slider_yscale(INT32 newval, char *buffer, int arg);
+static INT32 slider_xoffset(INT32 newval, char *buffer, int arg);
+static INT32 slider_yoffset(INT32 newval, char *buffer, int arg);
+static INT32 slider_flicker(INT32 newval, char *buffer, int arg);
+static INT32 slider_beam(INT32 newval, char *buffer, int arg);
+#ifdef MAME_DEBUG
+static INT32 slider_crossscale(INT32 newval, char *buffer, int arg);
+static INT32 slider_crossoffset(INT32 newval, char *buffer, int arg);
+#endif
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ ui_set_handler - set a callback/parameter
+ pair for the current UI handler
+-------------------------------------------------*/
+
+INLINE UINT32 ui_set_handler(UINT32 (*callback)(UINT32), UINT32 param)
+{
+ ui_handler_callback = callback;
+ ui_handler_param = param;
+ return param;
+}
+
+
+/*-------------------------------------------------
+ slider_config - configure a slider entry
+-------------------------------------------------*/
+
+INLINE void slider_config(slider_state *state, INT32 minval, INT32 defval, INT32 maxval, INT32 incval, INT32 (*update)(INT32, char *, int), int arg)
+{
+ state->minval = minval;
+ state->defval = defval;
+ state->maxval = maxval;
+ state->incval = incval;
+ state->update = update;
+ state->arg = arg;
+}
+
+
+/*-------------------------------------------------
+ is_breakable_char - is a given unicode
+ character a possible line break?
+-------------------------------------------------*/
+
+INLINE int is_breakable_char(unicode_char ch)
+{
+ /* regular spaces and hyphens are breakable */
+ if (ch == ' ' || ch == '-')
+ return TRUE;
+
+ /* In the following character sets, any character is breakable:
+ Hiragana (3040-309F)
+ Katakana (30A0-30FF)
+ Bopomofo (3100-312F)
+ Hangul Compatibility Jamo (3130-318F)
+ Kanbun (3190-319F)
+ Bopomofo Extended (31A0-31BF)
+ CJK Strokes (31C0-31EF)
+ Katakana Phonetic Extensions (31F0-31FF)
+ Enclosed CJK Letters and Months (3200-32FF)
+ CJK Compatibility (3300-33FF)
+ CJK Unified Ideographs Extension A (3400-4DBF)
+ Yijing Hexagram Symbols (4DC0-4DFF)
+ CJK Unified Ideographs (4E00-9FFF) */
+ if (ch >= 0x3040 && ch <= 0x9fff)
+ return TRUE;
+
+ /* Hangul Syllables (AC00-D7AF) are breakable */
+ if (ch >= 0xac00 && ch <= 0xd7af)
+ return TRUE;
+
+ /* CJK Compatibility Ideographs (F900-FAFF) are breakable */
+ if (ch >= 0xf900 && ch <= 0xfaff)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ ui_init - set up the user interface
+-------------------------------------------------*/
+
+int ui_init(running_machine *machine)
+{
+ /* make sure we clean up after ourselves */
+ add_exit_callback(machine, ui_exit);
+
+ /* load the localization file */
+ /* fix me -- need to find a real way to do this */
+ uistring_init(NULL);
+
+ /* allocate the font */
+ ui_font = render_font_alloc("ui.bdf");
+
+ /* initialize the other UI bits */
+ ui_menu_init(machine);
+ ui_gfx_init(machine);
+
+ /* reset globals */
+ single_step = FALSE;
+ ui_set_handler(handler_messagebox, 0);
+
+ /* request callbacks when the renderer does resizing */
+ render_set_rescale_notify(machine, rescale_notifier);
+ allow_rescale = 0;
+ display_rescale_message = FALSE;
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ ui_exit - clean up ourselves on exit
+-------------------------------------------------*/
+
+static void ui_exit(running_machine *machine)
+{
+ /* free the font */
+ if (ui_font != NULL)
+ render_font_free(ui_font);
+ ui_font = NULL;
+}
+
+
+/*-------------------------------------------------
+ rescale_notifier - notifier to trigger a
+ rescale message during long operations
+-------------------------------------------------*/
+
+static int rescale_notifier(running_machine *machine, int width, int height)
+{
+ /* always allow "small" rescaling */
+ if (width < 500 || height < 500)
+ return TRUE;
+
+ /* if we've currently disallowed rescaling, turn on a message next frame */
+ if (allow_rescale == 0)
+ display_rescale_message = TRUE;
+
+ /* only allow rescaling once we're sure the message is visible */
+ return (allow_rescale == 1);
+}
+
+
+/*-------------------------------------------------
+ ui_display_startup_screens - display the
+ various startup screens
+-------------------------------------------------*/
+
+int ui_display_startup_screens(int first_time, int show_disclaimer)
+{
+#ifdef MESS
+ const int maxstate = 4;
+#else
+ const int maxstate = 3;
+#endif
+ int str = options_get_int(mame_options(), OPTION_SECONDS_TO_RUN);
+ int show_gameinfo = !options_get_bool(mame_options(), OPTION_SKIP_GAMEINFO);
+ int show_warnings = TRUE;
+ int state;
+
+ /* disable everything if we are using -str */
+ if (!first_time || (str > 0 && str < 60*5) || Machine->gamedrv == &driver_empty)
+ show_gameinfo = show_warnings = show_disclaimer = FALSE;
+
+ /* initialize the on-screen display system */
+ slider_init();
+
+ /* loop over states */
+ ui_set_handler(handler_ingame, 0);
+ for (state = 0; state < maxstate && !mame_is_scheduled_event_pending(Machine) && !ui_menu_is_force_game_select(); state++)
+ {
+ /* default to standard colors */
+ messagebox_backcolor = UI_FILLCOLOR;
+
+ /* pick the next state */
+ switch (state)
+ {
+ case 0:
+ if (show_disclaimer && sprintf_disclaimer(messagebox_text))
+ ui_set_handler(handler_messagebox_ok, 0);
+ break;
+
+ case 1:
+ if (show_warnings && sprintf_warnings(messagebox_text))
+ {
+ ui_set_handler(handler_messagebox_ok, 0);
+ if (Machine->gamedrv->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION))
+ messagebox_backcolor = UI_REDCOLOR;
+ }
+ break;
+
+ case 2:
+ if (show_gameinfo && sprintf_game_info(messagebox_text))
+ ui_set_handler(handler_messagebox_anykey, 0);
+ break;
+#ifdef MESS
+ case 3:
+ break;
+#endif
+ }
+
+ /* clear the input memory */
+ input_code_poll_switches(TRUE);
+ while (input_code_poll_switches(FALSE) != INPUT_CODE_INVALID) ;
+
+ /* loop while we have a handler */
+ while (ui_handler_callback != handler_ingame && !mame_is_scheduled_event_pending(Machine) && !ui_menu_is_force_game_select())
+ video_frame_update();
+
+ /* clear the handler and force an update */
+ ui_set_handler(handler_ingame, 0);
+ video_frame_update();
+ }
+
+ /* if we're the empty driver, force the menus on */
+ if (ui_menu_is_force_game_select())
+ ui_set_handler(ui_menu_ui_handler, 0);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ ui_set_startup_text - set the text to display
+ at startup
+-------------------------------------------------*/
+
+void ui_set_startup_text(const char *text, int force)
+{
+ static osd_ticks_t lastupdatetime = 0;
+ osd_ticks_t curtime = osd_ticks();
+
+ /* copy in the new text */
+ strncpy(messagebox_text, text, sizeof(messagebox_text));
+ messagebox_backcolor = UI_FILLCOLOR;
+
+ /* don't update more than 4 times/second */
+ if (force || (curtime - lastupdatetime) > osd_ticks_per_second() / 4)
+ {
+ lastupdatetime = curtime;
+ video_frame_update();
+ }
+}
+
+
+/*-------------------------------------------------
+ ui_update_and_render - update the UI and
+ render it; called by video.c
+-------------------------------------------------*/
+
+void ui_update_and_render(void)
+{
+ /* always start clean */
+ render_container_empty(render_container_get_ui());
+
+ /* if we're paused, dim the whole screen */
+ if (mame_get_phase(Machine) >= MAME_PHASE_RESET && (single_step || mame_is_paused(Machine)))
+ {
+ int alpha = (1.0f - options_get_float(mame_options(), OPTION_PAUSE_BRIGHTNESS)) * 255.0f;
+ if (ui_menu_is_force_game_select())
+ alpha = 255;
+ if (alpha > 255)
+ alpha = 255;
+ if (alpha >= 0)
+ render_ui_add_rect(0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(alpha,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+
+ /* call the current UI handler */
+ assert(ui_handler_callback != NULL);
+ ui_handler_param = (*ui_handler_callback)(ui_handler_param);
+
+ /* cancel takes us back to the ingame handler */
+ if (ui_handler_param == UI_HANDLER_CANCEL)
+ ui_set_handler(handler_ingame, 0);
+
+ /* add a message if we are rescaling */
+ if (display_rescale_message)
+ {
+ display_rescale_message = FALSE;
+ if (allow_rescale == 0)
+ allow_rescale = 2;
+ ui_draw_text_box("Updating Artwork...", JUSTIFY_CENTER, 0.5f, 0.5f, messagebox_backcolor);
+ }
+
+ /* decrement the frame counter if it is non-zero */
+ else if (allow_rescale != 0)
+ allow_rescale--;
+
+#ifdef MESS
+ /* let MESS display its stuff */
+ mess_ui_update();
+#endif
+}
+
+
+/*-------------------------------------------------
+ ui_get_font - return the UI font
+-------------------------------------------------*/
+
+render_font *ui_get_font(void)
+{
+ return ui_font;
+}
+
+
+/*-------------------------------------------------
+ ui_get_line_height - return the current height
+ of a line
+-------------------------------------------------*/
+
+float ui_get_line_height(void)
+{
+ INT32 raw_font_pixel_height = render_font_get_pixel_height(ui_font);
+ INT32 target_pixel_width, target_pixel_height;
+ float one_to_one_line_height;
+ float target_aspect;
+ float scale_factor;
+
+ /* get info about the UI target */
+ render_target_get_bounds(render_get_ui_target(), &target_pixel_width, &target_pixel_height, &target_aspect);
+
+ /* compute the font pixel height at the nominal size */
+ one_to_one_line_height = (float)raw_font_pixel_height / (float)target_pixel_height;
+
+ /* determine the scale factor */
+ scale_factor = UI_TARGET_FONT_HEIGHT / one_to_one_line_height;
+
+ /* if our font is small-ish, do integral scaling */
+ if (raw_font_pixel_height < 24)
+ {
+ /* do we want to scale smaller? only do so if we exceed the threshhold */
+ if (scale_factor <= 1.0f)
+ {
+ if (one_to_one_line_height < UI_MAX_FONT_HEIGHT || raw_font_pixel_height < 12)
+ scale_factor = 1.0f;
+ }
+
+ /* otherwise, just ensure an integral scale factor */
+ else
+ scale_factor = floor(scale_factor);
+ }
+
+ /* otherwise, just make sure we hit an even number of pixels */
+ else
+ {
+ INT32 height = scale_factor * one_to_one_line_height * (float)target_pixel_height;
+ scale_factor = (float)height / (one_to_one_line_height * (float)target_pixel_height);
+ }
+
+ return scale_factor * one_to_one_line_height;
+}
+
+
+/*-------------------------------------------------
+ ui_get_char_width - return the width of a
+ single character
+-------------------------------------------------*/
+
+float ui_get_char_width(unicode_char ch)
+{
+ return render_font_get_char_width(ui_font, ui_get_line_height(), render_get_ui_aspect(), ch);
+}
+
+
+/*-------------------------------------------------
+ ui_get_string_width - return the width of a
+ character string
+-------------------------------------------------*/
+
+float ui_get_string_width(const char *s)
+{
+ return render_font_get_utf8string_width(ui_font, ui_get_line_height(), render_get_ui_aspect(), s);
+}
+
+
+/*-------------------------------------------------
+ ui_draw_outlined_box - add primitives to draw
+ an outlined box with the given background
+ color
+-------------------------------------------------*/
+
+void ui_draw_outlined_box(float x0, float y0, float x1, float y1, rgb_t backcolor)
+{
+ float hw = UI_LINE_WIDTH * 0.5f;
+ render_ui_add_rect(x0, y0, x1, y1, backcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ render_ui_add_line(x0 + hw, y0 + hw, x1 - hw, y0 + hw, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ render_ui_add_line(x1 - hw, y0 + hw, x1 - hw, y1 - hw, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ render_ui_add_line(x1 - hw, y1 - hw, x0 + hw, y1 - hw, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ render_ui_add_line(x0 + hw, y1 - hw, x0 + hw, y0 + hw, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+}
+
+
+/*-------------------------------------------------
+ ui_draw_text - simple text renderer
+-------------------------------------------------*/
+
+void ui_draw_text(const char *buf, float x, float y)
+{
+ ui_draw_text_full(buf, x, y, 1.0f - x, JUSTIFY_LEFT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+}
+
+
+/*-------------------------------------------------
+ ui_draw_text_full - full featured text
+ renderer with word wrapping, justification,
+ and full size computation
+-------------------------------------------------*/
+
+void ui_draw_text_full(const char *origs, float x, float y, float wrapwidth, int justify, int wrap, int draw, rgb_t fgcolor, rgb_t bgcolor, float *totalwidth, float *totalheight)
+{
+ float lineheight = ui_get_line_height();
+ const char *ends = origs + strlen(origs);
+ const char *s = origs;
+ const char *linestart;
+ float cury = y;
+ float maxwidth = 0;
+
+ /* if we don't want wrapping, guarantee a huge wrapwidth */
+ if (wrap == WRAP_NEVER)
+ wrapwidth = 1000000.0f;
+ if (wrapwidth <= 0)
+ return;
+
+ /* loop over lines */
+ while (*s != 0)
+ {
+ const char *lastbreak = NULL;
+ int line_justify = justify;
+ unicode_char schar;
+ int scharcount;
+ float lastbreak_width = 0;
+ float curwidth = 0;
+ float curx = x;
+
+ /* get the current character */
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ /* if the line starts with a tab character, center it regardless */
+ if (schar == '\t')
+ {
+ s += scharcount;
+ line_justify = JUSTIFY_CENTER;
+ }
+
+ /* remember the starting position of the line */
+ linestart = s;
+
+ /* loop while we have characters and are less than the wrapwidth */
+ while (*s != 0 && curwidth <= wrapwidth)
+ {
+ float chwidth;
+
+ /* get the current chcaracter */
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ /* if we hit a newline, stop immediately */
+ if (schar == '\n')
+ break;
+
+ /* get the width of this character */
+ chwidth = ui_get_char_width(schar);
+
+ /* if we hit a space, remember the location and width *without* the space */
+ if (schar == ' ')
+ {
+ lastbreak = s;
+ lastbreak_width = curwidth;
+ }
+
+ /* add the width of this character and advance */
+ curwidth += chwidth;
+ s += scharcount;
+
+ /* if we hit any non-space breakable character, remember the location and width
+ *with* the breakable character */
+ if (schar != ' ' && is_breakable_char(schar) && curwidth <= wrapwidth)
+ {
+ lastbreak = s;
+ lastbreak_width = curwidth;
+ }
+ }
+
+ /* if we accumulated too much for the current width, we need to back off */
+ if (curwidth > wrapwidth)
+ {
+ /* if we're word wrapping, back up to the last break if we can */
+ if (wrap == WRAP_WORD)
+ {
+ /* if we hit a break, back up to there with the appropriate width */
+ if (lastbreak != NULL)
+ {
+ s = lastbreak;
+ curwidth = lastbreak_width;
+ }
+
+ /* if we didn't hit a break, back up one character */
+ else if (s > linestart)
+ {
+ /* get the previous character */
+ s = (const char *)utf8_previous_char(s);
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ curwidth -= ui_get_char_width(schar);
+ }
+ }
+
+ /* if we're truncating, make sure we have enough space for the ... */
+ else if (wrap == WRAP_TRUNCATE)
+ {
+ /* add in the width of the ... */
+ curwidth += 3.0f * ui_get_char_width('.');
+
+ /* while we are above the wrap width, back up one character */
+ while (curwidth > wrapwidth && s > linestart)
+ {
+ /* get the previous character */
+ s = (const char *)utf8_previous_char(s);
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ curwidth -= ui_get_char_width(schar);
+ }
+ }
+ }
+
+ /* align according to the justfication */
+ if (line_justify == JUSTIFY_CENTER)
+ curx += (wrapwidth - curwidth) * 0.5f;
+ else if (line_justify == JUSTIFY_RIGHT)
+ curx += wrapwidth - curwidth;
+
+ /* track the maximum width of any given line */
+ if (curwidth > maxwidth)
+ maxwidth = curwidth;
+
+ /* if opaque, add a black box */
+ if (draw == DRAW_OPAQUE)
+ render_ui_add_rect(curx, cury, curx + curwidth, cury + lineheight, bgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ /* loop from the line start and add the characters */
+ while (linestart < s)
+ {
+ /* get the current character */
+ unicode_char linechar;
+ int linecharcount = uchar_from_utf8(&linechar, linestart, ends - linestart);
+ if (linecharcount == -1)
+ break;
+
+ if (draw != DRAW_NONE)
+ {
+ render_ui_add_char(curx, cury, lineheight, render_get_ui_aspect(), fgcolor, ui_font, linechar);
+ curx += ui_get_char_width(linechar);
+ }
+ linestart += linecharcount;
+ }
+
+ /* append ellipses if needed */
+ if (wrap == WRAP_TRUNCATE && *s != 0 && draw != DRAW_NONE)
+ {
+ render_ui_add_char(curx, cury, lineheight, render_get_ui_aspect(), fgcolor, ui_font, '.');
+ curx += ui_get_char_width('.');
+ render_ui_add_char(curx, cury, lineheight, render_get_ui_aspect(), fgcolor, ui_font, '.');
+ curx += ui_get_char_width('.');
+ render_ui_add_char(curx, cury, lineheight, render_get_ui_aspect(), fgcolor, ui_font, '.');
+ curx += ui_get_char_width('.');
+ }
+
+ /* if we're not word-wrapping, we're done */
+ if (wrap != WRAP_WORD)
+ break;
+
+ /* advance by a row */
+ cury += lineheight;
+
+ /* skip past any spaces at the beginning of the next line */
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ if (schar == '\n')
+ s += scharcount;
+ else
+ while (*s && isspace(schar))
+ {
+ s += scharcount;
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+ }
+ }
+
+ /* report the width and height of the resulting space */
+ if (totalwidth)
+ *totalwidth = maxwidth;
+ if (totalheight)
+ *totalheight = cury - y;
+}
+
+
+/*-------------------------------------------------
+ ui_draw_text_box - draw a multiline text
+ message with a box around it
+-------------------------------------------------*/
+
+void ui_draw_text_box(const char *text, int justify, float xpos, float ypos, rgb_t backcolor)
+{
+ float target_width, target_height;
+ float target_x, target_y;
+
+ /* compute the multi-line target width/height */
+ ui_draw_text_full(text, 0, 0, 1.0f - 2.0f * UI_BOX_LR_BORDER,
+ justify, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &target_width, &target_height);
+ if (target_height > 1.0f - 2.0f * UI_BOX_TB_BORDER)
+ target_height = floor((1.0f - 2.0f * UI_BOX_TB_BORDER) / ui_get_line_height()) * ui_get_line_height();
+
+ /* determine the target location */
+ target_x = xpos - 0.5f * target_width;
+ target_y = ypos - 0.5f * target_height;
+
+ /* make sure we stay on-screen */
+ if (target_x < UI_BOX_LR_BORDER)
+ target_x = UI_BOX_LR_BORDER;
+ if (target_x + target_width + UI_BOX_LR_BORDER > 1.0f)
+ target_x = 1.0f - UI_BOX_LR_BORDER - target_width;
+ if (target_y < UI_BOX_TB_BORDER)
+ target_y = UI_BOX_TB_BORDER;
+ if (target_y + target_height + UI_BOX_TB_BORDER > 1.0f)
+ target_y = 1.0f - UI_BOX_TB_BORDER - target_height;
+
+ /* add a box around that */
+ ui_draw_outlined_box(target_x - UI_BOX_LR_BORDER,
+ target_y - UI_BOX_TB_BORDER,
+ target_x + target_width + UI_BOX_LR_BORDER,
+ target_y + target_height + UI_BOX_TB_BORDER, backcolor);
+ ui_draw_text_full(text, target_x, target_y, target_width,
+ justify, WRAP_WORD, DRAW_NORMAL, ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+}
+
+
+/*-------------------------------------------------
+ ui_popup - popup a message for a standard
+ amount of time
+-------------------------------------------------*/
+
+void CLIB_DECL ui_popup(const char *text, ...)
+{
+ int seconds;
+ va_list arg;
+
+ /* extract the text */
+ va_start(arg,text);
+ vsprintf(messagebox_text, text, arg);
+ messagebox_backcolor = UI_FILLCOLOR;
+ va_end(arg);
+
+ /* set a timer */
+ seconds = (int)strlen(messagebox_text) / 40 + 2;
+ popup_text_end = osd_ticks() + osd_ticks_per_second() * seconds;
+}
+
+
+/*-------------------------------------------------
+ ui_popup_time - popup a message for a specific
+ amount of time
+-------------------------------------------------*/
+
+void CLIB_DECL ui_popup_time(int seconds, const char *text, ...)
+{
+ va_list arg;
+
+ /* extract the text */
+ va_start(arg,text);
+ vsprintf(messagebox_text, text, arg);
+ messagebox_backcolor = UI_FILLCOLOR;
+ va_end(arg);
+
+ /* set a timer */
+ popup_text_end = osd_ticks() + osd_ticks_per_second() * seconds;
+}
+
+
+/*-------------------------------------------------
+ ui_show_fps_temp - show the FPS counter for
+ a specific period of time
+-------------------------------------------------*/
+
+void ui_show_fps_temp(double seconds)
+{
+ if (!showfps)
+ showfps_end = osd_ticks() + seconds * osd_ticks_per_second();
+}
+
+
+/*-------------------------------------------------
+ ui_set_show_fps - show/hide the FPS counter
+-------------------------------------------------*/
+
+void ui_set_show_fps(int show)
+{
+ showfps = show;
+ if (!show)
+ {
+ showfps = 0;
+ showfps_end = 0;
+ }
+}
+
+
+/*-------------------------------------------------
+ ui_get_show_fps - return the current FPS
+ counter visibility state
+-------------------------------------------------*/
+
+int ui_get_show_fps(void)
+{
+ return showfps || (showfps_end != 0);
+}
+
+
+/*-------------------------------------------------
+ ui_set_show_profiler - show/hide the profiler
+-------------------------------------------------*/
+
+void ui_set_show_profiler(int show)
+{
+ if (show)
+ {
+ show_profiler = TRUE;
+ profiler_start();
+ }
+ else
+ {
+ show_profiler = FALSE;
+ profiler_stop();
+ }
+}
+
+
+/*-------------------------------------------------
+ ui_get_show_profiler - return the current
+ profiler visibility state
+-------------------------------------------------*/
+
+int ui_get_show_profiler(void)
+{
+ return show_profiler;
+}
+
+
+/*-------------------------------------------------
+ ui_show_menu - show the menus
+-------------------------------------------------*/
+
+void ui_show_menu(void)
+{
+ ui_set_handler(ui_menu_ui_handler, 0);
+}
+
+
+/*-------------------------------------------------
+ ui_is_menu_active - return TRUE if the menu
+ UI handler is active
+-------------------------------------------------*/
+
+int ui_is_menu_active(void)
+{
+ return (ui_handler_callback == ui_menu_ui_handler);
+}
+
+
+/*-------------------------------------------------
+ ui_is_slider_active - return TRUE if the slider
+ UI handler is active
+-------------------------------------------------*/
+
+int ui_is_slider_active(void)
+{
+ return (ui_handler_callback == handler_slider);
+}
+
+
+
+/***************************************************************************
+ TEXT GENERATORS
+***************************************************************************/
+
+/*-------------------------------------------------
+ sprintf_disclaimer - print the disclaimer
+ text to the given buffer
+-------------------------------------------------*/
+
+static int sprintf_disclaimer(char *buffer)
+{
+ char *bufptr = buffer;
+ bufptr += sprintf(bufptr, "%s\n\n", ui_getstring(UI_copyright1));
+ bufptr += sprintf(bufptr, ui_getstring(UI_copyright2), Machine->gamedrv->description);
+ bufptr += sprintf(bufptr, "\n\n%s", ui_getstring(UI_copyright3));
+ return bufptr - buffer;
+}
+
+
+/*-------------------------------------------------
+ sprintf_warnings - print the warning flags
+ text to the given buffer
+-------------------------------------------------*/
+
+static int sprintf_warnings(char *buffer)
+{
+#define WARNING_FLAGS ( GAME_NOT_WORKING | \
+ GAME_UNEMULATED_PROTECTION | \
+ GAME_WRONG_COLORS | \
+ GAME_IMPERFECT_COLORS | \
+ GAME_NO_SOUND | \
+ GAME_IMPERFECT_SOUND | \
+ GAME_IMPERFECT_GRAPHICS | \
+ GAME_NO_COCKTAIL)
+ char *bufptr = buffer;
+ int i;
+
+ /* if no warnings, nothing to return */
+ if (rom_load_warnings() == 0 && !(Machine->gamedrv->flags & WARNING_FLAGS))
+ return 0;
+
+ /* add a warning if any ROMs were loaded with warnings */
+ if (rom_load_warnings() > 0)
+ {
+ bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_incorrectroms));
+ if (Machine->gamedrv->flags & WARNING_FLAGS)
+ *bufptr++ = '\n';
+ }
+
+ /* if we have at least one warning flag, print the general header */
+ if (Machine->gamedrv->flags & WARNING_FLAGS)
+ {
+ bufptr += sprintf(bufptr, "%s\n\n", ui_getstring(UI_knownproblems));
+
+ /* add one line per warning flag */
+#ifdef MESS
+ if (Machine->gamedrv->flags & GAME_COMPUTER)
+ bufptr += sprintf(bufptr, "%s\n\n%s\n", ui_getstring(UI_comp1), ui_getstring(UI_comp2));
+#endif
+ if (Machine->gamedrv->flags & GAME_IMPERFECT_COLORS)
+ bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_imperfectcolors));
+ if (Machine->gamedrv->flags & GAME_WRONG_COLORS)
+ bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_wrongcolors));
+ if (Machine->gamedrv->flags & GAME_IMPERFECT_GRAPHICS)
+ bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_imperfectgraphics));
+ if (Machine->gamedrv->flags & GAME_IMPERFECT_SOUND)
+ bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_imperfectsound));
+ if (Machine->gamedrv->flags & GAME_NO_SOUND)
+ bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_nosound));
+ if (Machine->gamedrv->flags & GAME_NO_COCKTAIL)
+ bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_nococktail));
+
+ /* if there's a NOT WORKING or UNEMULATED PROTECTION warning, make it stronger */
+ if (Machine->gamedrv->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION))
+ {
+ const game_driver *maindrv;
+ const game_driver *clone_of;
+ int foundworking;
+
+ /* add the strings for these warnings */
+ if (Machine->gamedrv->flags & GAME_NOT_WORKING)
+ bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_brokengame));
+ if (Machine->gamedrv->flags & GAME_UNEMULATED_PROTECTION)
+ bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_brokenprotection));
+
+ /* find the parent of this driver */
+ clone_of = driver_get_clone(Machine->gamedrv);
+ if (clone_of != NULL && !(clone_of->flags & GAME_IS_BIOS_ROOT))
+ maindrv = clone_of;
+ else
+ maindrv = Machine->gamedrv;
+
+ /* scan the driver list for any working clones and add them */
+ foundworking = 0;
+ for (i = 0; drivers[i] != NULL; i++)
+ if (drivers[i] == maindrv || driver_get_clone(drivers[i]) == maindrv)
+ if ((drivers[i]->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION)) == 0)
+ {
+ /* this one works, add a header and display the name of the clone */
+ if (foundworking == 0)
+ bufptr += sprintf(bufptr, "\n\n%s\n\n", ui_getstring(UI_workingclones));
+ bufptr += sprintf(bufptr, "%s\n", drivers[i]->name);
+ foundworking = 1;
+ }
+ }
+ }
+
+ /* add the 'press OK' string */
+ bufptr += sprintf(bufptr, "\n\n%s", ui_getstring(UI_typeok));
+ return bufptr - buffer;
+}
+
+
+/*-------------------------------------------------
+ sprintf_game_info - print the game info text
+ to the given buffer
+-------------------------------------------------*/
+
+int sprintf_game_info(char *buffer)
+{
+ char *bufptr = buffer;
+ int cpunum, sndnum;
+ int count;
+
+ /* print description, manufacturer, and CPU: */
+ bufptr += sprintf(bufptr, "%s\n%s %s\n\n%s:\n", Machine->gamedrv->description, Machine->gamedrv->year, Machine->gamedrv->manufacturer, ui_getstring(UI_cpu));
+
+ /* loop over all CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum += count)
+ {
+ cpu_type type = Machine->drv->cpu[cpunum].type;
+ int clock = Machine->drv->cpu[cpunum].clock;
+
+ /* count how many identical CPUs we have */
+ for (count = 1; cpunum + count < MAX_CPU; count++)
+ if (Machine->drv->cpu[cpunum + count].type != type ||
+ Machine->drv->cpu[cpunum + count].clock != clock)
+ break;
+
+ /* if more than one, prepend a #x in front of the CPU name */
+ if (count > 1)
+ bufptr += sprintf(bufptr, "%d" UTF8_MULTIPLY, count);
+ bufptr += sprintf(bufptr, "%s", cputype_name(type));
+
+ /* display clock in kHz or MHz */
+ if (clock >= 1000000)
+ bufptr += sprintf(bufptr, " %d.%06d" UTF8_NBSP "MHz\n", clock / 1000000, clock % 1000000);
+ else
+ bufptr += sprintf(bufptr, " %d.%03d" UTF8_NBSP "kHz\n", clock / 1000, clock % 1000);
+ }
+
+ /* append the Sound: string */
+ bufptr += sprintf(bufptr, "\n%s:\n", ui_getstring(UI_sound));
+
+ /* loop over all sound chips */
+ for (sndnum = 0; sndnum < MAX_SOUND && Machine->drv->sound[sndnum].type != SOUND_DUMMY; sndnum += count)
+ {
+ sound_type type = Machine->drv->sound[sndnum].type;
+ int clock = sndnum_clock(sndnum);
+
+ /* count how many identical sound chips we have */
+ for (count = 1; sndnum + count < MAX_SOUND; count++)
+ if (Machine->drv->sound[sndnum + count].type != type ||
+ sndnum_clock(sndnum + count) != clock)
+ break;
+
+ /* if more than one, prepend a #x in front of the CPU name */
+ if (count > 1)
+ bufptr += sprintf(bufptr, "%d" UTF8_MULTIPLY, count);
+ bufptr += sprintf(bufptr, "%s", sndnum_name(sndnum));
+
+ /* display clock in kHz or MHz */
+ if (clock >= 1000000)
+ bufptr += sprintf(bufptr, " %d.%06d" UTF8_NBSP "MHz\n", clock / 1000000, clock % 1000000);
+ else if (clock != 0)
+ bufptr += sprintf(bufptr, " %d.%03d" UTF8_NBSP "kHz\n", clock / 1000, clock % 1000);
+ else
+ *bufptr++ = '\n';
+ }
+
+ /* display vector information for vector games */
+ if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR)
+ bufptr += sprintf(bufptr, "\n%s\n", ui_getstring(UI_vectorgame));
+
+ /* display screen resolution and refresh rate info for raster games */
+ else
+ bufptr += sprintf(bufptr,"\n%s:\n%d " UTF8_MULTIPLY " %d (%s) %f" UTF8_NBSP "Hz\n",
+ ui_getstring(UI_screenres),
+ Machine->screen[0].visarea.max_x - Machine->screen[0].visarea.min_x + 1,
+ Machine->screen[0].visarea.max_y - Machine->screen[0].visarea.min_y + 1,
+ (Machine->gamedrv->flags & ORIENTATION_SWAP_XY) ? "V" : "H",
+ ATTOSECONDS_TO_HZ(Machine->screen[0].refresh));
+ return bufptr - buffer;
+}
+
+
+
+/***************************************************************************
+ UI HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ handler_messagebox - displays the current
+ messagebox_text string but handles no input
+-------------------------------------------------*/
+
+static UINT32 handler_messagebox(UINT32 state)
+{
+ ui_draw_text_box(messagebox_text, JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor);
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ handler_messagebox_ok - displays the current
+ messagebox_text string and waits for an OK
+-------------------------------------------------*/
+
+static UINT32 handler_messagebox_ok(UINT32 state)
+{
+ /* draw a standard message window */
+ ui_draw_text_box(messagebox_text, JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor);
+
+ /* an 'O' or left joystick kicks us to the next state */
+ if (state == 0 && (input_code_pressed_once(KEYCODE_O) || input_ui_pressed(IPT_UI_LEFT)))
+ state++;
+
+ /* a 'K' or right joystick exits the state */
+ else if (state == 1 && (input_code_pressed_once(KEYCODE_K) || input_ui_pressed(IPT_UI_RIGHT)))
+ state = UI_HANDLER_CANCEL;
+
+ /* if the user cancels, exit out completely */
+ else if (input_ui_pressed(IPT_UI_CANCEL))
+ {
+ mame_schedule_exit(Machine);
+ state = UI_HANDLER_CANCEL;
+ }
+
+ return state;
+}
+
+
+/*-------------------------------------------------
+ handler_messagebox_anykey - displays the
+ current messagebox_text string and waits for
+ any keypress
+-------------------------------------------------*/
+
+static UINT32 handler_messagebox_anykey(UINT32 state)
+{
+ /* draw a standard message window */
+ ui_draw_text_box(messagebox_text, JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor);
+
+ /* if the user cancels, exit out completely */
+ if (input_ui_pressed(IPT_UI_CANCEL))
+ {
+ mame_schedule_exit(Machine);
+ state = UI_HANDLER_CANCEL;
+ }
+
+ /* if any key is pressed, just exit */
+ else if (input_code_poll_switches(FALSE) != INPUT_CODE_INVALID)
+ state = UI_HANDLER_CANCEL;
+
+ return state;
+}
+
+
+/*-------------------------------------------------
+ handler_ingame - in-game handler takes care
+ of the standard keypresses
+-------------------------------------------------*/
+
+static UINT32 handler_ingame(UINT32 state)
+{
+ int is_paused = mame_is_paused(Machine);
+
+ /* first draw the FPS counter */
+ if (showfps || osd_ticks() < showfps_end)
+ {
+ ui_draw_text_full(video_get_speed_text(), 0.0f, 0.0f, 1.0f,
+ JUSTIFY_RIGHT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+ }
+ else
+ showfps_end = 0;
+
+ /* draw the profiler if visible */
+ if (show_profiler)
+ ui_draw_text_full(profiler_get_text(), 0.0f, 0.0f, 1.0f, JUSTIFY_LEFT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+
+ /* let the cheat engine display its stuff */
+ if (options_get_bool(mame_options(), OPTION_CHEAT))
+ cheat_display_watches();
+
+ /* display any popup messages */
+ if (osd_ticks() < popup_text_end)
+ ui_draw_text_box(messagebox_text, JUSTIFY_CENTER, 0.5f, 0.9f, messagebox_backcolor);
+ else
+ popup_text_end = 0;
+
+ /* if we're single-stepping, pause now */
+ if (single_step)
+ {
+ mame_pause(Machine, TRUE);
+ single_step = FALSE;
+ }
+
+#ifdef MESS
+ if (mess_disable_builtin_ui())
+ return 0;
+#endif
+
+ /* if the user pressed ESC, stop the emulation */
+ if (input_ui_pressed(IPT_UI_CANCEL))
+ mame_schedule_exit(Machine);
+
+ /* turn on menus if requested */
+ if (input_ui_pressed(IPT_UI_CONFIGURE))
+ return ui_set_handler(ui_menu_ui_handler, 0);
+
+ /* if the on-screen display isn't up and the user has toggled it, turn it on */
+#ifdef MAME_DEBUG
+ if (!Machine->debug_mode)
+#endif
+ if (input_ui_pressed(IPT_UI_ON_SCREEN_DISPLAY))
+ return ui_set_handler(handler_slider, 0);
+
+ /* handle a reset request */
+ if (input_ui_pressed(IPT_UI_RESET_MACHINE))
+ mame_schedule_hard_reset(Machine);
+ if (input_ui_pressed(IPT_UI_SOFT_RESET))
+ mame_schedule_soft_reset(Machine);
+
+ /* handle a request to display graphics/palette */
+ if (input_ui_pressed(IPT_UI_SHOW_GFX))
+ {
+ if (!is_paused)
+ mame_pause(Machine, TRUE);
+ return ui_set_handler(ui_gfx_ui_handler, is_paused);
+ }
+
+ /* handle a save state request */
+ if (input_ui_pressed(IPT_UI_SAVE_STATE))
+ {
+ mame_pause(Machine, TRUE);
+ return ui_set_handler(handler_load_save, LOADSAVE_SAVE);
+ }
+
+ /* handle a load state request */
+ if (input_ui_pressed(IPT_UI_LOAD_STATE))
+ {
+ mame_pause(Machine, TRUE);
+ return ui_set_handler(handler_load_save, LOADSAVE_LOAD);
+ }
+
+ /* handle a save snapshot request */
+ if (input_ui_pressed(IPT_UI_SNAPSHOT))
+ video_save_active_screen_snapshots(Machine);
+
+ /* toggle pause */
+ if (input_ui_pressed(IPT_UI_PAUSE))
+ {
+ /* with a shift key, it is single step */
+ if (is_paused && (input_code_pressed(KEYCODE_LSHIFT) || input_code_pressed(KEYCODE_RSHIFT)))
+ {
+ single_step = TRUE;
+ mame_pause(Machine, FALSE);
+ }
+ else
+ mame_pause(Machine, !mame_is_paused(Machine));
+ }
+
+ /* toggle movie recording */
+ if (input_ui_pressed(IPT_UI_RECORD_MOVIE))
+ {
+ if (!video_is_movie_active(Machine, 0))
+ {
+ video_movie_begin_recording(Machine, 0, NULL);
+ popmessage("REC START");
+ }
+ else
+ {
+ video_movie_end_recording(Machine, 0);
+ popmessage("REC STOP");
+ }
+ }
+
+ /* toggle profiler display */
+ if (input_ui_pressed(IPT_UI_SHOW_PROFILER))
+ ui_set_show_profiler(!ui_get_show_profiler());
+
+ /* toggle FPS display */
+ if (input_ui_pressed(IPT_UI_SHOW_FPS))
+ ui_set_show_fps(!ui_get_show_fps());
+
+ /* toggle crosshair display */
+ if (input_ui_pressed(IPT_UI_TOGGLE_CROSSHAIR))
+ video_crosshair_toggle();
+
+ /* increment frameskip? */
+ if (input_ui_pressed(IPT_UI_FRAMESKIP_INC))
+ {
+ /* get the current value and increment it */
+ int newframeskip = video_get_frameskip() + 1;
+ if (newframeskip > MAX_FRAMESKIP)
+ newframeskip = -1;
+ video_set_frameskip(newframeskip);
+
+ /* display the FPS counter for 2 seconds */
+ ui_show_fps_temp(2.0);
+ }
+
+ /* decrement frameskip? */
+ if (input_ui_pressed(IPT_UI_FRAMESKIP_DEC))
+ {
+ /* get the current value and decrement it */
+ int newframeskip = video_get_frameskip() - 1;
+ if (newframeskip < -1)
+ newframeskip = MAX_FRAMESKIP;
+ video_set_frameskip(newframeskip);
+
+ /* display the FPS counter for 2 seconds */
+ ui_show_fps_temp(2.0);
+ }
+
+ /* toggle throttle? */
+ if (input_ui_pressed(IPT_UI_THROTTLE))
+ video_set_throttle(!video_get_throttle());
+
+ /* check for fast forward */
+ if (input_port_type_pressed(IPT_UI_FAST_FORWARD, 0))
+ {
+ video_set_fastforward(TRUE);
+ ui_show_fps_temp(0.5);
+ }
+ else
+ video_set_fastforward(FALSE);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ handler_slider - displays the current slider
+ and calls the slider handler
+-------------------------------------------------*/
+
+static UINT32 handler_slider(UINT32 state)
+{
+ slider_state *cur = &slider_list[slider_current];
+ INT32 increment = 0, newval;
+ char textbuf[256];
+
+ /* left/right control the increment */
+ if (input_ui_pressed_repeat(IPT_UI_LEFT,6))
+ increment = -cur->incval;
+ if (input_ui_pressed_repeat(IPT_UI_RIGHT,6))
+ increment = cur->incval;
+
+ /* alt goes to 1, shift goes 10x smaller, control goes 10x larger */
+ if (increment != 0)
+ {
+ if (input_code_pressed(KEYCODE_LALT) || input_code_pressed(KEYCODE_RALT))
+ increment = (increment < 0) ? -1 : 1;
+ if (input_code_pressed(KEYCODE_LSHIFT) || input_code_pressed(KEYCODE_RSHIFT))
+ increment = (increment < -10 || increment > 10) ? (increment / 10) : ((increment < 0) ? -1 : 1);
+ if (input_code_pressed(KEYCODE_LCONTROL) || input_code_pressed(KEYCODE_RCONTROL))
+ increment *= 10;
+ }
+
+ /* determine the new value */
+ newval = (*cur->update)(0, NULL, cur->arg) + increment;
+
+ /* select resets to the default value */
+ if (input_ui_pressed(IPT_UI_SELECT))
+ newval = cur->defval;
+
+ /* clamp within bounds */
+ if (newval < cur->minval)
+ newval = cur->minval;
+ if (newval > cur->maxval)
+ newval = cur->maxval;
+
+ /* update the new data and get the text */
+ (*cur->update)(newval, textbuf, cur->arg);
+
+ /* display the UI */
+ slider_display(textbuf, cur->minval, cur->maxval, cur->defval, newval);
+
+ /* up/down select which slider to control */
+ if (input_ui_pressed_repeat(IPT_UI_DOWN,6))
+ slider_current = (slider_current + 1) % slider_count;
+ if (input_ui_pressed_repeat(IPT_UI_UP,6))
+ slider_current = (slider_current + slider_count - 1) % slider_count;
+
+ /* the slider toggle or ESC will cancel out of our display */
+ if (input_ui_pressed(IPT_UI_ON_SCREEN_DISPLAY) || input_ui_pressed(IPT_UI_CANCEL))
+ return UI_HANDLER_CANCEL;
+
+ /* the menu key will take us directly to the menu */
+ if (input_ui_pressed(IPT_UI_CONFIGURE))
+ return ui_set_handler(ui_menu_ui_handler, 0);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ handler_load_save - leads the user through
+ specifying a game to save or load
+-------------------------------------------------*/
+
+static UINT32 handler_load_save(UINT32 state)
+{
+ char filename[20];
+ input_code code;
+ char file = 0;
+
+ /* if we're not in the middle of anything, skip */
+ if (state == LOADSAVE_NONE)
+ return 0;
+
+ /* okay, we're waiting for a key to select a slot; display a message */
+ if (state == LOADSAVE_SAVE)
+ ui_draw_message_window("Select position to save to");
+ else
+ ui_draw_message_window("Select position to load from");
+
+ /* check for cancel key */
+ if (input_ui_pressed(IPT_UI_CANCEL))
+ {
+ /* display a popup indicating things were cancelled */
+ if (state == LOADSAVE_SAVE)
+ popmessage("Save cancelled");
+ else
+ popmessage("Load cancelled");
+
+ /* reset the state */
+ mame_pause(Machine, FALSE);
+ return UI_HANDLER_CANCEL;
+ }
+
+ /* check for A-Z or 0-9 */
+ for (code = KEYCODE_A; code <= (input_code)KEYCODE_Z; code++)
+ if (input_code_pressed_once(code))
+ file = code - KEYCODE_A + 'a';
+ if (file == 0)
+ for (code = KEYCODE_0; code <= (input_code)KEYCODE_9; code++)
+ if (input_code_pressed_once(code))
+ file = code - KEYCODE_0 + '0';
+ if (file == 0)
+ for (code = KEYCODE_0_PAD; code <= (input_code)KEYCODE_9_PAD; code++)
+ if (input_code_pressed_once(code))
+ file = code - KEYCODE_0_PAD + '0';
+ if (file == 0)
+ return state;
+
+ /* display a popup indicating that the save will proceed */
+ sprintf(filename, "%c", file);
+ if (state == LOADSAVE_SAVE)
+ {
+ popmessage("Save to position %c", file);
+ mame_schedule_save(Machine, filename);
+ }
+ else
+ {
+ popmessage("Load from position %c", file);
+ mame_schedule_load(Machine, filename);
+ }
+
+ /* remove the pause and reset the state */
+ mame_pause(Machine, FALSE);
+ return UI_HANDLER_CANCEL;
+}
+
+
+
+/***************************************************************************
+ SLIDER CONTROLS
+***************************************************************************/
+
+/*-------------------------------------------------
+ slider_init - initialize the list of slider
+ controls
+-------------------------------------------------*/
+
+static void slider_init(void)
+{
+ int numitems, item;
+ input_port_entry *in;
+
+ slider_count = 0;
+
+ /* add overall volume */
+ slider_config(&slider_list[slider_count++], -32, 0, 0, 1, slider_volume, 0);
+
+ /* add per-channel volume */
+ numitems = sound_get_user_gain_count();
+ for (item = 0; item < numitems; item++)
+ slider_config(&slider_list[slider_count++], 0, sound_get_default_gain(item) * 1000.0f + 0.5f, 2000, 20, slider_mixervol, item);
+
+ /* add analog adjusters */
+ for (in = Machine->input_ports; in && in->type != IPT_END; in++)
+ if ((in->type & 0xff) == IPT_ADJUSTER)
+ slider_config(&slider_list[slider_count++], 0, in->default_value >> 8, 100, 1, slider_adjuster, in - Machine->input_ports);
+
+ if (options_get_bool(mame_options(), OPTION_CHEAT))
+ {
+ /* add CPU overclocking */
+ numitems = cpu_gettotalcpu();
+ for (item = 0; item < numitems; item++)
+ slider_config(&slider_list[slider_count++], 10, 1000, 2000, 1, slider_overclock, item);
+
+ /* add refresh rate tweaker */
+ slider_config(&slider_list[slider_count++], -10000, 0, 10000, 1000, slider_refresh, 0);
+ }
+
+ for (item = 0; item < MAX_SCREENS; item++)
+ if (Machine->drv->screen[item].tag != NULL)
+ {
+ int defxscale = floor(Machine->drv->screen[item].xscale * 1000.0f + 0.5f);
+ int defyscale = floor(Machine->drv->screen[item].yscale * 1000.0f + 0.5f);
+ int defxoffset = floor(Machine->drv->screen[item].xoffset * 1000.0f + 0.5f);
+ int defyoffset = floor(Machine->drv->screen[item].yoffset * 1000.0f + 0.5f);
+
+ /* add standard brightness/contrast/gamma controls per-screen */
+ slider_config(&slider_list[slider_count++], 100, 1000, 2000, 10, slider_brightness, item);
+ slider_config(&slider_list[slider_count++], 100, 1000, 2000, 50, slider_contrast, item);
+ slider_config(&slider_list[slider_count++], 100, 1000, 3000, 50, slider_gamma, item);
+
+ /* add scale and offset controls per-screen */
+ slider_config(&slider_list[slider_count++], 500, (defxscale == 0) ? 1000 : defxscale, 1500, 2, slider_xscale, item);
+ slider_config(&slider_list[slider_count++], -500, defxoffset, 500, 2, slider_xoffset, item);
+ slider_config(&slider_list[slider_count++], 500, (defyscale == 0) ? 1000 : defyscale, 1500, 2, slider_yscale, item);
+ slider_config(&slider_list[slider_count++], -500, defyoffset, 500, 2, slider_yoffset, item);
+ }
+
+ if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR)
+ {
+ /* add flicker control */
+ slider_config(&slider_list[slider_count++], 0, 0, 1000, 10, slider_flicker, 0);
+ slider_config(&slider_list[slider_count++], 10, 100, 1000, 10, slider_beam, 0);
+ }
+
+#ifdef MAME_DEBUG
+ /* add crosshair adjusters */
+ for (in = Machine->input_ports; in && in->type != IPT_END; in++)
+ if (in->analog.crossaxis != CROSSHAIR_AXIS_NONE && in->player == 0)
+ {
+ slider_config(&slider_list[slider_count++], -3000, 1000, 3000, 100, slider_crossscale, in->analog.crossaxis);
+ slider_config(&slider_list[slider_count++], -3000, 0, 3000, 100, slider_crossoffset, in->analog.crossaxis);
+ }
+#endif
+}
+
+
+/*-------------------------------------------------
+ slider_display - display a slider box with
+ text
+-------------------------------------------------*/
+
+static void slider_display(const char *text, int minval, int maxval, int defval, int curval)
+{
+ float percentage = (float)(curval - minval) / (float)(maxval - minval);
+ float default_percentage = (float)(defval - minval) / (float)(maxval - minval);
+ float space_width = ui_get_char_width(' ');
+ float line_height = ui_get_line_height();
+ float ui_width, ui_height;
+ float text_height;
+
+ /* leave a spaces' worth of room along the left/right sides, and a lines' worth on the top/bottom */
+ ui_width = 1.0f - 2.0f * space_width;
+ ui_height = 1.0f - 2.0f * line_height;
+
+ /* determine the text height */
+ ui_draw_text_full(text, 0, 0, ui_width - 2 * UI_BOX_LR_BORDER,
+ JUSTIFY_CENTER, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, NULL, &text_height);
+
+ /* add a box around the whole area */
+ ui_draw_outlined_box(space_width,
+ line_height + ui_height - text_height - line_height - 2 * UI_BOX_TB_BORDER,
+ space_width + ui_width,
+ line_height + ui_height, UI_FILLCOLOR);
+
+ /* draw the thermometer */
+ slider_draw_bar(2.0f * space_width, line_height + ui_height - UI_BOX_TB_BORDER - text_height - line_height * 0.75f,
+ ui_width - 2.0f * space_width, line_height * 0.75f, percentage, default_percentage);
+
+ /* draw the actual text */
+ ui_draw_text_full(text, space_width + UI_BOX_LR_BORDER, line_height + ui_height - UI_BOX_TB_BORDER - text_height, ui_width - 2.0f * UI_BOX_LR_BORDER,
+ JUSTIFY_CENTER, WRAP_WORD, DRAW_NORMAL, ARGB_WHITE, ARGB_BLACK, NULL, &text_height);
+}
+
+
+/*-------------------------------------------------
+ slider_draw_bar - draw a slider thermometer
+-------------------------------------------------*/
+
+static void slider_draw_bar(float leftx, float topy, float width, float height, float percentage, float default_percentage)
+{
+ float current_x, default_x;
+ float bar_top, bar_bottom;
+
+ /* compute positions */
+ bar_top = topy + 0.125f * height;
+ bar_bottom = topy + 0.875f * height;
+ default_x = leftx + width * default_percentage;
+ current_x = leftx + width * percentage;
+
+ /* fill in the percentage */
+ render_ui_add_rect(leftx, bar_top, current_x, bar_bottom, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ /* draw the top and bottom lines */
+ render_ui_add_line(leftx, bar_top, leftx + width, bar_top, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ render_ui_add_line(leftx, bar_bottom, leftx + width, bar_bottom, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ /* draw default marker */
+ render_ui_add_line(default_x, topy, default_x, bar_top, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ render_ui_add_line(default_x, bar_bottom, default_x, topy + height, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+}
+
+
+/*-------------------------------------------------
+ slider_volume - global volume slider callback
+-------------------------------------------------*/
+
+static INT32 slider_volume(INT32 newval, char *buffer, int arg)
+{
+ if (buffer != NULL)
+ {
+ sound_set_attenuation(newval);
+ sprintf(buffer, "%s %3ddB", ui_getstring(UI_volume), sound_get_attenuation());
+ }
+ return sound_get_attenuation();
+}
+
+
+/*-------------------------------------------------
+ slider_mixervol - single channel volume
+ slider callback
+-------------------------------------------------*/
+
+static INT32 slider_mixervol(INT32 newval, char *buffer, int arg)
+{
+ if (buffer != NULL)
+ {
+ sound_set_user_gain(arg, (float)newval * 0.001f);
+ sprintf(buffer, "%s %s %4.2f", sound_get_user_gain_name(arg), ui_getstring(UI_volume), sound_get_user_gain(arg));
+ }
+ return floor(sound_get_user_gain(arg) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_adjuster - analog adjuster slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_adjuster(INT32 newval, char *buffer, int arg)
+{
+ input_port_entry *in = &Machine->input_ports[arg];
+ if (buffer != NULL)
+ {
+ in->default_value = (in->default_value & ~0xff) | (newval & 0xff);
+ sprintf(buffer, "%s %d%%", in->name, in->default_value & 0xff);
+ }
+ return in->default_value & 0xff;
+}
+
+
+/*-------------------------------------------------
+ slider_overclock - CPU overclocker slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_overclock(INT32 newval, char *buffer, int arg)
+{
+ if (buffer != NULL)
+ {
+ cpunum_set_clockscale(arg, (float)newval * 0.001f);
+ sprintf(buffer, "%s %s%d %3.0f%%", ui_getstring(UI_overclock), ui_getstring(UI_cpu), arg, floor(cpunum_get_clockscale(arg) * 100.0f + 0.5f));
+ }
+ return floor(cpunum_get_clockscale(arg) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_refresh - refresh rate slider callback
+-------------------------------------------------*/
+
+static INT32 slider_refresh(INT32 newval, char *buffer, int arg)
+{
+ double defrefresh = ATTOSECONDS_TO_HZ(Machine->drv->screen[arg].defstate.refresh);
+ double refresh;
+
+ if (buffer != NULL)
+ {
+ screen_state *state = &Machine->screen[arg];
+ video_screen_configure(arg, state->width, state->height, &state->visarea, HZ_TO_ATTOSECONDS(defrefresh + (double)newval * 0.001));
+ sprintf(buffer, "Screen %d %s %.3f", arg, ui_getstring(UI_refresh_rate), ATTOSECONDS_TO_HZ(Machine->screen[arg].refresh));
+ }
+ refresh = ATTOSECONDS_TO_HZ(Machine->screen[arg].refresh);
+ return floor((refresh - defrefresh) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_brightness - screen brightness slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_brightness(INT32 newval, char *buffer, int arg)
+{
+ render_container *container = render_container_get_screen(arg);
+ if (buffer != NULL)
+ {
+ render_container_set_brightness(container, (float)newval * 0.001f);
+ sprintf(buffer, "Screen %d %s %.3f", arg, ui_getstring(UI_brightness), render_container_get_brightness(container));
+ }
+ return floor(render_container_get_brightness(container) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_contrast - screen contrast slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_contrast(INT32 newval, char *buffer, int arg)
+{
+ render_container *container = render_container_get_screen(arg);
+ if (buffer != NULL)
+ {
+ render_container_set_contrast(container, (float)newval * 0.001f);
+ sprintf(buffer, "Screen %d %s %.3f", arg, ui_getstring(UI_contrast), render_container_get_contrast(container));
+ }
+ return floor(render_container_get_contrast(container) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_gamma - screen gamma slider callback
+-------------------------------------------------*/
+
+static INT32 slider_gamma(INT32 newval, char *buffer, int arg)
+{
+ render_container *container = render_container_get_screen(arg);
+ if (buffer != NULL)
+ {
+ render_container_set_gamma(container, (float)newval * 0.001f);
+ sprintf(buffer, "Screen %d %s %.3f", arg, ui_getstring(UI_gamma), render_container_get_gamma(container));
+ }
+ return floor(render_container_get_gamma(container) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_xscale - screen horizontal scale slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_xscale(INT32 newval, char *buffer, int arg)
+{
+ render_container *container = render_container_get_screen(arg);
+ if (buffer != NULL)
+ {
+ render_container_set_xscale(container, (float)newval * 0.001f);
+ sprintf(buffer, "Screen %d %s %.3f", arg, "Horiz stretch", render_container_get_xscale(container));
+ }
+ return floor(render_container_get_xscale(container) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_yscale - screen vertical scale slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_yscale(INT32 newval, char *buffer, int arg)
+{
+ render_container *container = render_container_get_screen(arg);
+ if (buffer != NULL)
+ {
+ render_container_set_yscale(container, (float)newval * 0.001f);
+ sprintf(buffer, "Screen %d %s %.3f", arg, "Vert stretch", render_container_get_yscale(container));
+ }
+ return floor(render_container_get_yscale(container) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_xoffset - screen horizontal position
+ slider callback
+-------------------------------------------------*/
+
+static INT32 slider_xoffset(INT32 newval, char *buffer, int arg)
+{
+ render_container *container = render_container_get_screen(arg);
+ if (buffer != NULL)
+ {
+ render_container_set_xoffset(container, (float)newval * 0.001f);
+ sprintf(buffer, "Screen %d %s %.3f", arg, "Horiz position", render_container_get_xoffset(container));
+ }
+ return floor(render_container_get_xoffset(container) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_yoffset - screen vertical position
+ slider callback
+-------------------------------------------------*/
+
+static INT32 slider_yoffset(INT32 newval, char *buffer, int arg)
+{
+ render_container *container = render_container_get_screen(arg);
+ if (buffer != NULL)
+ {
+ render_container_set_yoffset(container, (float)newval * 0.001f);
+ sprintf(buffer, "Screen %d %s %.3f", arg, "Vert position", render_container_get_yoffset(container));
+ }
+ return floor(render_container_get_yoffset(container) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_flicker - vector flicker slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_flicker(INT32 newval, char *buffer, int arg)
+{
+ if (buffer != NULL)
+ {
+ vector_set_flicker((float)newval * 0.1f);
+ sprintf(buffer, "%s %1.2f", ui_getstring(UI_vectorflicker), vector_get_flicker());
+ }
+ return floor(vector_get_flicker() * 10.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_beam - vector beam width slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_beam(INT32 newval, char *buffer, int arg)
+{
+ if (buffer != NULL)
+ {
+ vector_set_beam((float)newval * 0.01f);
+ sprintf(buffer, "%s %1.2f", "Beam Width", vector_get_beam());
+ }
+ return floor(vector_get_beam() * 100.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_crossscale - crosshair scale slider
+ callback
+-------------------------------------------------*/
+
+#ifdef MAME_DEBUG
+static INT32 slider_crossscale(INT32 newval, char *buffer, int arg)
+{
+ input_port_entry *in;
+
+ if (buffer != NULL)
+ {
+ for (in = Machine->input_ports; in && in->type != IPT_END; in++)
+ if (in->analog.crossaxis == arg)
+ {
+ in->analog.crossscale = (float)newval * 0.001f;
+ break;
+ }
+ sprintf(buffer, "%s %s %1.3f", "Crosshair Scale", (in->analog.crossaxis == CROSSHAIR_AXIS_X) ? "X" : "Y", (float)newval * 0.001f);
+ }
+ for (in = Machine->input_ports; in && in->type != IPT_END; in++)
+ if (in->analog.crossaxis == arg)
+ return floor(in->analog.crossscale * 1000.0f + 0.5f);
+ return 0;
+}
+#endif
+
+
+/*-------------------------------------------------
+ slider_crossoffset - crosshair scale slider
+ callback
+-------------------------------------------------*/
+
+#ifdef MAME_DEBUG
+static INT32 slider_crossoffset(INT32 newval, char *buffer, int arg)
+{
+ input_port_entry *in;
+
+ if (buffer != NULL)
+ {
+ for (in = Machine->input_ports; in && in->type != IPT_END; in++)
+ if (in->analog.crossaxis == arg)
+ {
+ in->analog.crossoffset = (float)newval * 0.001f;
+ break;
+ }
+ sprintf(buffer, "%s %s %1.3f", "Crosshair Offset", (in->analog.crossaxis == CROSSHAIR_AXIS_X) ? "X" : "Y", (float)newval * 0.001f);
+ }
+ for (in = Machine->input_ports; in && in->type != IPT_END; in++)
+ if (in->analog.crossaxis == arg)
+ return floor(in->analog.crossoffset * 1000.0f + 0.5f);
+ return 0;
+}
+#endif
diff --git a/src/emu/ui.h b/src/emu/ui.h
new file mode 100644
index 00000000000..d7b61be4905
--- /dev/null
+++ b/src/emu/ui.h
@@ -0,0 +1,141 @@
+/***************************************************************************
+
+ ui.h
+
+ Functions used to handle MAME's crude user interface.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __USRINTRF_H__
+#define __USRINTRF_H__
+
+#include "mamecore.h"
+#include "render.h"
+#include "unicode.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* preferred font height; use ui_get_line_height() to get actual height */
+#define UI_TARGET_FONT_HEIGHT (1.0f / 25.0f)
+#define UI_MAX_FONT_HEIGHT (1.0f / 15.0f)
+
+/* width of lines drawn in the UI */
+#define UI_LINE_WIDTH (1.0f / 500.0f)
+
+/* border between outlines and inner text on left/right and top/bottom sides */
+#define UI_BOX_LR_BORDER (UI_TARGET_FONT_HEIGHT * 0.25f)
+#define UI_BOX_TB_BORDER (UI_TARGET_FONT_HEIGHT * 0.25f)
+
+/* handy colors */
+#define ARGB_WHITE MAKE_ARGB(0xff,0xff,0xff,0xff)
+#define ARGB_BLACK MAKE_ARGB(0xff,0x00,0x00,0x00)
+#define UI_FILLCOLOR MAKE_ARGB(0xe0,0x10,0x10,0x30)
+#define UI_YELLOWCOLOR MAKE_ARGB(0xe0,0x60,0x60,0x10)
+#define UI_REDCOLOR MAKE_ARGB(0xf0,0x60,0x10,0x10)
+
+/* cancel return value for a UI handler */
+#define UI_HANDLER_CANCEL ((UINT32)~0)
+
+/* justification options for ui_draw_text_full */
+enum
+{
+ JUSTIFY_LEFT = 0,
+ JUSTIFY_CENTER,
+ JUSTIFY_RIGHT
+};
+
+/* word wrapping options for ui_draw_text_full */
+enum
+{
+ WRAP_NEVER,
+ WRAP_TRUNCATE,
+ WRAP_WORD
+};
+
+/* drawing options for ui_draw_text_full */
+enum
+{
+ DRAW_NONE,
+ DRAW_NORMAL,
+ DRAW_OPAQUE
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define ui_draw_message_window(text) ui_draw_text_box(text, JUSTIFY_LEFT, 0.5f, 0.5f, UI_FILLCOLOR)
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* main init/exit routines */
+int ui_init(running_machine *machine);
+
+/* display the startup screens */
+int ui_display_startup_screens(int first_time, int show_disclaimer);
+
+/* set the current text to display at startup */
+void ui_set_startup_text(const char *text, int force);
+
+/* once-per-frame update and render */
+void ui_update_and_render(void);
+
+/* returns the current UI font */
+render_font *ui_get_font(void);
+
+/* returns the line height of the font used by the UI system */
+float ui_get_line_height(void);
+
+/* returns the width of a character or string in the UI font */
+float ui_get_char_width(unicode_char ch);
+float ui_get_string_width(const char *s);
+
+/* draw an outlined box filled with a given color */
+void ui_draw_outlined_box(float x0, float y0, float x1, float y1, rgb_t backcolor);
+
+/* simple text draw at the given coordinates */
+void ui_draw_text(const char *buf, float x, float y);
+
+/* full-on text draw with all the options */
+void ui_draw_text_full(const char *origs, float x, float y, float wrapwidth, int justify, int wrap, int draw, rgb_t fgcolor, rgb_t bgcolor, float *totalwidth, float *totalheight);
+
+/* draw a multi-line message with a box around it */
+void ui_draw_text_box(const char *text, int justify, float xpos, float ypos, rgb_t backcolor);
+
+/* display a temporary message at the bottom of the screen */
+void CLIB_DECL ui_popup_time(int seconds, const char *text, ...) ATTR_PRINTF(2,3);
+
+/* get/set whether or not the FPS is displayed */
+void ui_show_fps_temp(double seconds);
+void ui_set_show_fps(int show);
+int ui_get_show_fps(void);
+
+/* get/set whether or not the profiler is displayed */
+void ui_set_show_profiler(int show);
+int ui_get_show_profiler(void);
+
+/* force the menus to display */
+void ui_show_menu(void);
+
+/* return true if a menu or the slider is displayed */
+int ui_is_menu_active(void);
+int ui_is_slider_active(void);
+
+/* print the game info string into a buffer */
+int sprintf_game_info(char *buffer);
+
+#endif /* __USRINTRF_H__ */
diff --git a/src/emu/uigfx.c b/src/emu/uigfx.c
new file mode 100644
index 00000000000..e45eb46d4d8
--- /dev/null
+++ b/src/emu/uigfx.c
@@ -0,0 +1,1085 @@
+/*********************************************************************
+
+ uigfx.c
+
+ Internal graphics viewer.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "ui.h"
+#include "render.h"
+#include "rendfont.h"
+#include "rendutil.h"
+#include "uigfx.h"
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _ui_gfx_state ui_gfx_state;
+struct _ui_gfx_state
+{
+ UINT8 mode; /* which mode are we in? */
+
+ /* intermediate bitmaps */
+ UINT8 bitmap_dirty; /* is the bitmap dirty? */
+ mame_bitmap * bitmap; /* bitmap for drawing gfx and tilemaps */
+ render_texture *texture; /* texture for rendering the above bitmap */
+
+ /* palette-specific data */
+ struct
+ {
+ int which; /* which subset (palette or colortable)? */
+ int offset; /* current offset of top,left item */
+ int count; /* number of items per row */
+ } palette;
+
+ /* graphics-viewer-specific data */
+ struct
+ {
+ int set; /* which set is visible */
+ int offset[MAX_GFX_ELEMENTS]; /* current offset of top,left item */
+ int color[MAX_GFX_ELEMENTS]; /* current color selected */
+ int count[MAX_GFX_ELEMENTS]; /* number of items per row */
+ UINT8 rotate[MAX_GFX_ELEMENTS]; /* current rotation (orientation) value */
+ } gfxset;
+
+ /* tilemap-viewer-specific data */
+ struct
+ {
+ int which; /* which tilemap are we viewing? */
+ int xoffs; /* current X offset */
+ int yoffs; /* current Y offset */
+ int zoom; /* zoom factor */
+ UINT8 rotate; /* current rotation (orientation) value */
+ } tilemap;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static ui_gfx_state ui_gfx;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void ui_gfx_exit(running_machine *machine);
+
+/* palette handling */
+static void palette_handle_keys(ui_gfx_state *state);
+static void palette_handler(ui_gfx_state *state);
+
+/* graphics set handling */
+static void gfxset_handle_keys(ui_gfx_state *state, int xcells, int ycells);
+static void gfxset_draw_item(const gfx_element *gfx, int index, mame_bitmap *bitmap, int dstx, int dsty, int color, int rotate);
+static void gfxset_update_bitmap(ui_gfx_state *state, int xcells, int ycells, gfx_element *gfx);
+static void gfxset_handler(ui_gfx_state *state);
+
+/* tilemap handling */
+static void tilemap_handle_keys(ui_gfx_state *state, int viswidth, int visheight);
+static void tilemap_update_bitmap(ui_gfx_state *state, int width, int height);
+static void tilemap_handler(ui_gfx_state *state);
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ ui_gfx_init - initialize the menu system
+-------------------------------------------------*/
+
+void ui_gfx_init(running_machine *machine)
+{
+ ui_gfx_state *state = &ui_gfx;
+ int gfx;
+
+ /* make sure we clean up after ourselves */
+ add_exit_callback(machine, ui_gfx_exit);
+
+ /* initialize our global state */
+ memset(state, 0, sizeof(*state));
+
+ /* set up the palette state */
+ state->palette.count = 16;
+
+ /* set up the graphics state */
+ for (gfx = 0; gfx < MAX_GFX_ELEMENTS; gfx++)
+ {
+ state->gfxset.rotate[gfx] = Machine->gamedrv->flags & ORIENTATION_MASK;
+ state->gfxset.count[gfx] = 16;
+ }
+
+ /* set up the tilemap state */
+ state->tilemap.rotate = Machine->gamedrv->flags & ORIENTATION_MASK;
+}
+
+
+/*-------------------------------------------------
+ ui_gfx_exit - clean up after ourselves
+-------------------------------------------------*/
+
+static void ui_gfx_exit(running_machine *machine)
+{
+ /* free the texture */
+ if (ui_gfx.texture != NULL)
+ render_texture_free(ui_gfx.texture);
+ ui_gfx.texture = NULL;
+
+ /* free the bitmap */
+ if (ui_gfx.bitmap != NULL)
+ bitmap_free(ui_gfx.bitmap);
+ ui_gfx.bitmap = NULL;
+}
+
+
+/*-------------------------------------------------
+ ui_gfx_ui_handler - primary UI handler
+-------------------------------------------------*/
+
+UINT32 ui_gfx_ui_handler(UINT32 uistate)
+{
+ ui_gfx_state *state = &ui_gfx;
+
+ /* if we have nothing, implicitly cancel */
+ if (Machine->drv->total_colors == 0 && Machine->drv->color_table_len == 0 && Machine->gfx[0] == NULL && tilemap_count() == 0)
+ goto cancel;
+
+ /* if we're not paused, mark the bitmap dirty */
+ if (!mame_is_paused(Machine))
+ state->bitmap_dirty = TRUE;
+
+ /* switch off the state to display something */
+again:
+ switch (state->mode)
+ {
+ case 0:
+ /* if we have a palette, display it */
+ if (Machine->drv->total_colors > 0)
+ {
+ palette_handler(state);
+ break;
+ }
+
+ /* fall through...*/
+ state->mode++;
+
+ case 1:
+ /* if we have graphics sets, display them */
+ if (Machine->gfx[0] != NULL)
+ {
+ gfxset_handler(state);
+ break;
+ }
+
+ /* fall through...*/
+ state->mode++;
+
+ case 2:
+ /* if we have tilemaps, display them */
+ if (tilemap_count() > 0)
+ {
+ tilemap_handler(state);
+ break;
+ }
+
+ state->mode = 0;
+ goto again;
+ }
+
+ /* handle keys */
+ if (input_ui_pressed(IPT_UI_SELECT))
+ {
+ state->mode = (state->mode + 1) % 3;
+ state->bitmap_dirty = TRUE;
+ }
+
+ if (input_ui_pressed(IPT_UI_PAUSE))
+ mame_pause(Machine, !mame_is_paused(Machine));
+
+ if (input_ui_pressed(IPT_UI_CANCEL) || input_ui_pressed(IPT_UI_SHOW_GFX))
+ goto cancel;
+
+ return uistate;
+
+cancel:
+ if (!uistate)
+ mame_pause(Machine, FALSE);
+ state->bitmap_dirty = TRUE;
+ return UI_HANDLER_CANCEL;
+}
+
+
+
+/***************************************************************************
+ PALETTE VIEWER
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_handler - handler for the palette
+ viewer
+-------------------------------------------------*/
+
+static void palette_handler(ui_gfx_state *state)
+{
+ int total = state->palette.which ? Machine->drv->color_table_len : Machine->drv->total_colors;
+ const UINT16 *pens = state->palette.which ? Machine->game_colortable : NULL;
+ const char *title = state->palette.which ? "COLORTABLE" : "PALETTE";
+ const rgb_t *raw_color = palette_entry_list_raw(Machine->palette);
+ render_font *ui_font = ui_get_font();
+ float cellwidth, cellheight;
+ float chwidth, chheight;
+ float titlewidth;
+ float x0, y0;
+ render_bounds cellboxbounds;
+ render_bounds boxbounds;
+ int x, y, skip;
+
+ /* add a half character padding for the box */
+ chheight = ui_get_line_height();
+ chwidth = render_font_get_char_width(ui_font, chheight, render_get_ui_aspect(), '0');
+ boxbounds.x0 = 0.0f + 0.5f * chwidth;
+ boxbounds.x1 = 1.0f - 0.5f * chwidth;
+ boxbounds.y0 = 0.0f + 0.5f * chheight;
+ boxbounds.y1 = 1.0f - 0.5f * chheight;
+
+ /* the character cell box bounds starts a half character in from the box */
+ cellboxbounds = boxbounds;
+ cellboxbounds.x0 += 0.5f * chwidth;
+ cellboxbounds.x1 -= 0.5f * chwidth;
+ cellboxbounds.y0 += 0.5f * chheight;
+ cellboxbounds.y1 -= 0.5f * chheight;
+
+ /* add space on the left for 5 characters of text, plus a half character of padding */
+ cellboxbounds.x0 += 5.5f * chwidth;
+
+ /* add space on the top for a title, a half line of padding, a header, and another half line */
+ cellboxbounds.y0 += 3.0f * chheight;
+
+ /* figure out the title and expand the outer box to fit */
+ titlewidth = render_font_get_string_width(ui_font, chheight, render_get_ui_aspect(), title);
+ x0 = 0.0f;
+ if (boxbounds.x1 - boxbounds.x0 < titlewidth + chwidth)
+ x0 = boxbounds.x0 - (0.5f - 0.5f * (titlewidth + chwidth));
+
+ /* go ahead and draw the outer box now */
+ ui_draw_outlined_box(boxbounds.x0 - x0, boxbounds.y0, boxbounds.x1 + x0, boxbounds.y1, UI_FILLCOLOR);
+
+ /* draw the title */
+ x0 = 0.5f - 0.5f * titlewidth;
+ y0 = boxbounds.y0 + 0.5f * chheight;
+ for (x = 0; title[x] != 0; x++)
+ {
+ render_ui_add_char(x0, y0, chheight, render_get_ui_aspect(), ARGB_WHITE, ui_font, title[x]);
+ x0 += render_font_get_char_width(ui_font, chheight, render_get_ui_aspect(), title[x]);
+ }
+
+ /* compute the cell size */
+ cellwidth = (cellboxbounds.x1 - cellboxbounds.x0) / (float)state->palette.count;
+ cellheight = (cellboxbounds.y1 - cellboxbounds.y0) / (float)state->palette.count;
+
+ /* draw the top column headers */
+ skip = (int)(chwidth / cellwidth);
+ for (x = 0; x < state->palette.count; x += 1 + skip)
+ {
+ x0 = boxbounds.x0 + 6.0f * chwidth + (float)x * cellwidth;
+ y0 = boxbounds.y0 + 2.0f * chheight;
+ render_ui_add_char(x0 + 0.5f * (cellwidth - chwidth), y0, chheight, render_get_ui_aspect(), ARGB_WHITE, ui_font, "0123456789ABCDEF"[x & 0xf]);
+
+ /* if we're skipping, draw a point between the character and the box to indicate which */
+ /* one it's referring to */
+ if (skip != 0)
+ render_ui_add_point(x0 + 0.5f * cellwidth, 0.5f * (y0 + chheight + cellboxbounds.y0), UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+
+ /* draw the side column headers */
+ skip = (int)(chheight / cellheight);
+ for (y = 0; y < state->palette.count; y += 1 + skip)
+
+ /* only display if there is data to show */
+ if (state->palette.offset + y * state->palette.count < total)
+ {
+ char buffer[10];
+
+ /* if we're skipping, draw a point between the character and the box to indicate which */
+ /* one it's referring to */
+ x0 = boxbounds.x0 + 5.5f * chwidth;
+ y0 = boxbounds.y0 + 3.5f * chheight + (float)y * cellheight;
+ if (skip != 0)
+ render_ui_add_point(0.5f * (x0 + cellboxbounds.x0), y0 + 0.5f * cellheight, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ /* draw the row header */
+ sprintf(buffer, "%5X", state->palette.offset + y * state->palette.count);
+ for (x = 4; x >= 0; x--)
+ {
+ x0 -= render_font_get_char_width(ui_font, chheight, render_get_ui_aspect(), buffer[x]);
+ render_ui_add_char(x0, y0 + 0.5f * (cellheight - chheight), chheight, render_get_ui_aspect(), ARGB_WHITE, ui_font, buffer[x]);
+ }
+ }
+
+ /* now add the rectangles for the colors */
+ for (y = 0; y < state->palette.count; y++)
+ for (x = 0; x < state->palette.count; x++)
+ {
+ int index = state->palette.offset + y * state->palette.count + x;
+ if (index < total)
+ {
+ pen_t pen = (pens != NULL) ? pens[index] : index;
+ render_ui_add_rect(cellboxbounds.x0 + x * cellwidth, cellboxbounds.y0 + y * cellheight,
+ cellboxbounds.x0 + (x + 1) * cellwidth, cellboxbounds.y0 + (y + 1) * cellheight,
+ 0xff000000 | raw_color[pen], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+ }
+
+ /* handle keys */
+ palette_handle_keys(state);
+}
+
+
+/*-------------------------------------------------
+ palette_handler - handle key inputs for the
+ palette viewer
+-------------------------------------------------*/
+
+static void palette_handle_keys(ui_gfx_state *state)
+{
+ int rowcount, screencount;
+ int total;
+
+ /* handle zoom (minus,plus) */
+ if (input_ui_pressed(IPT_UI_ZOOM_OUT))
+ state->palette.count /= 2;
+ if (input_ui_pressed(IPT_UI_ZOOM_IN))
+ state->palette.count *= 2;
+
+ /* clamp within range */
+ if (state->palette.count <= 4)
+ state->palette.count = 4;
+ if (state->palette.count > 64)
+ state->palette.count = 64;
+
+ /* handle colormap selection (open bracket,close bracket) */
+ if (input_ui_pressed(IPT_UI_PREV_GROUP))
+ state->palette.which--;
+ if (input_ui_pressed(IPT_UI_NEXT_GROUP))
+ state->palette.which++;
+
+ /* clamp within range */
+ if (state->palette.which < 0)
+ state->palette.which = 1;
+ if (state->palette.which > (Machine->drv->color_table_len != 0))
+ state->palette.which = (Machine->drv->color_table_len != 0);
+
+ /* cache some info in locals */
+ total = state->palette.which ? Machine->drv->color_table_len : Machine->drv->total_colors;
+
+ /* determine number of entries per row and total */
+ rowcount = state->palette.count;
+ screencount = rowcount * rowcount;
+
+ /* handle keyboard navigation */
+ if (input_ui_pressed_repeat(IPT_UI_UP, 4))
+ state->palette.offset -= rowcount;
+ if (input_ui_pressed_repeat(IPT_UI_DOWN, 4))
+ state->palette.offset += rowcount;
+ if (input_ui_pressed_repeat(IPT_UI_PAGE_UP, 6))
+ state->palette.offset -= screencount;
+ if (input_ui_pressed_repeat(IPT_UI_PAGE_DOWN, 6))
+ state->palette.offset += screencount;
+ if (input_ui_pressed_repeat(IPT_UI_HOME, 4))
+ state->palette.offset = 0;
+ if (input_ui_pressed_repeat(IPT_UI_END, 4))
+ state->palette.offset = total;
+
+ /* clamp within range */
+ if (state->palette.offset + screencount > ((total + rowcount - 1) / rowcount) * rowcount)
+ state->palette.offset = ((total + rowcount - 1) / rowcount) * rowcount - screencount;
+ if (state->palette.offset < 0)
+ state->palette.offset = 0;
+}
+
+
+
+/***************************************************************************
+ GRAPHICS VIEWER
+***************************************************************************/
+
+/*-------------------------------------------------
+ gfxset_handler - handler for the graphics
+ viewer
+-------------------------------------------------*/
+
+static void gfxset_handler(ui_gfx_state *state)
+{
+ render_font *ui_font = ui_get_font();
+ int set = state->gfxset.set;
+ gfx_element *gfx = Machine->gfx[set];
+ float fullwidth, fullheight;
+ float cellwidth, cellheight;
+ float chwidth, chheight;
+ float titlewidth;
+ float cellaspect;
+ float x0, y0;
+ render_bounds cellboxbounds;
+ render_bounds boxbounds;
+ int cellboxwidth, cellboxheight;
+ int targwidth, targheight;
+ int cellxpix, cellypix;
+ int xcells, ycells;
+ int pixelscale = 0;
+ int x, y, skip;
+ char title[100];
+
+ /* get the bounds of our target */
+ render_target_get_bounds(render_get_ui_target(), &targwidth, &targheight, NULL);
+
+ /* add a half character padding for the box */
+ chheight = ui_get_line_height();
+ chwidth = render_font_get_char_width(ui_font, chheight, render_get_ui_aspect(), '0');
+ boxbounds.x0 = 0.0f + 0.5f * chwidth;
+ boxbounds.x1 = 1.0f - 0.5f * chwidth;
+ boxbounds.y0 = 0.0f + 0.5f * chheight;
+ boxbounds.y1 = 1.0f - 0.5f * chheight;
+
+ /* the character cell box bounds starts a half character in from the box */
+ cellboxbounds = boxbounds;
+ cellboxbounds.x0 += 0.5f * chwidth;
+ cellboxbounds.x1 -= 0.5f * chwidth;
+ cellboxbounds.y0 += 0.5f * chheight;
+ cellboxbounds.y1 -= 0.5f * chheight;
+
+ /* add space on the left for 5 characters of text, plus a half character of padding */
+ cellboxbounds.x0 += 5.5f * chwidth;
+
+ /* add space on the top for a title, a half line of padding, a header, and another half line */
+ cellboxbounds.y0 += 3.0f * chheight;
+
+ /* convert back to pixels */
+ cellboxwidth = (cellboxbounds.x1 - cellboxbounds.x0) * (float)targwidth;
+ cellboxheight = (cellboxbounds.y1 - cellboxbounds.y0) * (float)targheight;
+
+ /* compute the number of source pixels in a cell */
+ cellxpix = 1 + ((state->gfxset.rotate[state->gfxset.set] & ORIENTATION_SWAP_XY) ? gfx->height : gfx->width);
+ cellypix = 1 + ((state->gfxset.rotate[state->gfxset.set] & ORIENTATION_SWAP_XY) ? gfx->width : gfx->height);
+
+ /* compute the largest pixel scale factor that still fits */
+ xcells = state->gfxset.count[set];
+ while (xcells > 1)
+ {
+ pixelscale = (cellboxwidth / xcells) / cellxpix;
+ if (pixelscale != 0)
+ break;
+ xcells--;
+ }
+
+ /* worst case, we need a pixel scale of 1 */
+ pixelscale = MAX(1, pixelscale);
+
+ /* in the Y direction, we just display as many as we can */
+ ycells = cellboxheight / (pixelscale * cellypix);
+
+ /* now determine the actual cellbox size */
+ cellboxwidth = MIN(cellboxwidth, xcells * pixelscale * cellxpix);
+ cellboxheight = MIN(cellboxheight, ycells * pixelscale * cellypix);
+
+ /* compute the size of a single cell at this pixel scale factor, as well as the aspect ratio */
+ cellwidth = (cellboxwidth / (float)xcells) / (float)targwidth;
+ cellheight = (cellboxheight / (float)ycells) / (float)targheight;
+ cellaspect = cellwidth / cellheight;
+
+ /* working from the new width/height, recompute the boxbounds */
+ fullwidth = (float)cellboxwidth / (float)targwidth + 6.5f * chwidth;
+ fullheight = (float)cellboxheight / (float)targheight + 4.0f * chheight;
+
+ /* recompute boxbounds from this */
+ boxbounds.x0 = (1.0f - fullwidth) * 0.5f;
+ boxbounds.x1 = boxbounds.x0 + fullwidth;
+ boxbounds.y0 = (1.0f - fullheight) * 0.5f;
+ boxbounds.y1 = boxbounds.y0 + fullheight;
+
+ /* figure out the title and expand the outer box to fit */
+ for (x = 0; x < MAX_GFX_ELEMENTS && Machine->gfx[x] != NULL; x++) ;
+ sprintf(title, "GFX %d/%d %dx%d COLOR %X", state->gfxset.set, x - 1, gfx->width, gfx->height, state->gfxset.color[set]);
+ titlewidth = render_font_get_string_width(ui_font, chheight, render_get_ui_aspect(), title);
+ x0 = 0.0f;
+ if (boxbounds.x1 - boxbounds.x0 < titlewidth + chwidth)
+ x0 = boxbounds.x0 - (0.5f - 0.5f * (titlewidth + chwidth));
+
+ /* go ahead and draw the outer box now */
+ ui_draw_outlined_box(boxbounds.x0 - x0, boxbounds.y0, boxbounds.x1 + x0, boxbounds.y1, UI_FILLCOLOR);
+
+ /* draw the title */
+ x0 = 0.5f - 0.5f * titlewidth;
+ y0 = boxbounds.y0 + 0.5f * chheight;
+ for (x = 0; title[x] != 0; x++)
+ {
+ render_ui_add_char(x0, y0, chheight, render_get_ui_aspect(), ARGB_WHITE, ui_font, title[x]);
+ x0 += render_font_get_char_width(ui_font, chheight, render_get_ui_aspect(), title[x]);
+ }
+
+ /* draw the top column headers */
+ skip = (int)(chwidth / cellwidth);
+ for (x = 0; x < xcells; x += 1 + skip)
+ {
+ x0 = boxbounds.x0 + 6.0f * chwidth + (float)x * cellwidth;
+ y0 = boxbounds.y0 + 2.0f * chheight;
+ render_ui_add_char(x0 + 0.5f * (cellwidth - chwidth), y0, chheight, render_get_ui_aspect(), ARGB_WHITE, ui_font, "0123456789ABCDEF"[x & 0xf]);
+
+ /* if we're skipping, draw a point between the character and the box to indicate which */
+ /* one it's referring to */
+ if (skip != 0)
+ render_ui_add_point(x0 + 0.5f * cellwidth, 0.5f * (y0 + chheight + boxbounds.y0 + 3.5f * chheight), UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+
+ /* draw the side column headers */
+ skip = (int)(chheight / cellheight);
+ for (y = 0; y < ycells; y += 1 + skip)
+
+ /* only display if there is data to show */
+ if (state->gfxset.offset[set] + y * xcells < gfx->total_elements)
+ {
+ char buffer[10];
+
+ /* if we're skipping, draw a point between the character and the box to indicate which */
+ /* one it's referring to */
+ x0 = boxbounds.x0 + 5.5f * chwidth;
+ y0 = boxbounds.y0 + 3.5f * chheight + (float)y * cellheight;
+ if (skip != 0)
+ render_ui_add_point(0.5f * (x0 + boxbounds.x0 + 6.0f * chwidth), y0 + 0.5f * cellheight, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ /* draw the row header */
+ sprintf(buffer, "%5X", state->gfxset.offset[set] + y * xcells);
+ for (x = 4; x >= 0; x--)
+ {
+ x0 -= render_font_get_char_width(ui_font, chheight, render_get_ui_aspect(), buffer[x]);
+ render_ui_add_char(x0, y0 + 0.5f * (cellheight - chheight), chheight, render_get_ui_aspect(), ARGB_WHITE, ui_font, buffer[x]);
+ }
+ }
+
+ /* update the bitmap */
+ gfxset_update_bitmap(state, xcells, ycells, gfx);
+
+ /* add the final quad */
+ render_ui_add_quad(boxbounds.x0 + 6.0f * chwidth, boxbounds.y0 + 3.5f * chheight,
+ boxbounds.x0 + 6.0f * chwidth + (float)cellboxwidth / (float)targwidth,
+ boxbounds.y0 + 3.5f * chheight + (float)cellboxheight / (float)targheight,
+ ARGB_WHITE, state->texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ /* handle keyboard navigation before drawing */
+ gfxset_handle_keys(state, xcells, ycells);
+}
+
+
+/*-------------------------------------------------
+ gfxset_handler - handle keys for the graphics
+ viewer
+-------------------------------------------------*/
+
+static void gfxset_handle_keys(ui_gfx_state *state, int xcells, int ycells)
+{
+ ui_gfx_state oldstate = *state;
+ gfx_element *gfx;
+ int temp, set;
+
+ /* handle gfxset selection (open bracket,close bracket) */
+ if (input_ui_pressed(IPT_UI_PREV_GROUP))
+ {
+ for (temp = state->gfxset.set - 1; temp >= 0; temp--)
+ if (Machine->gfx[temp] != NULL)
+ break;
+ if (temp >= 0)
+ state->gfxset.set = temp;
+ }
+ if (input_ui_pressed(IPT_UI_NEXT_GROUP))
+ {
+ for (temp = state->gfxset.set + 1; temp < MAX_GFX_ELEMENTS; temp++)
+ if (Machine->gfx[temp] != NULL)
+ break;
+ if (temp < MAX_GFX_ELEMENTS)
+ state->gfxset.set = temp;
+ }
+
+ /* cache some info in locals */
+ set = state->gfxset.set;
+ gfx = Machine->gfx[set];
+
+ /* handle cells per line (minus,plus) */
+ if (input_ui_pressed(IPT_UI_ZOOM_OUT))
+ state->gfxset.count[set] = xcells - 1;
+ if (input_ui_pressed(IPT_UI_ZOOM_IN))
+ state->gfxset.count[set] = xcells + 1;
+
+ /* clamp within range */
+ if (state->gfxset.count[set] < 2)
+ state->gfxset.count[set] = 2;
+ if (state->gfxset.count[set] > 32)
+ state->gfxset.count[set] = 32;
+
+ /* handle rotation (R) */
+ if (input_ui_pressed(IPT_UI_ROTATE))
+ state->gfxset.rotate[set] = orientation_add(ROT90, state->gfxset.rotate[set]);
+
+ /* handle navigation within the cells (up,down,pgup,pgdown) */
+ if (input_ui_pressed_repeat(IPT_UI_UP, 4))
+ state->gfxset.offset[set] -= xcells;
+ if (input_ui_pressed_repeat(IPT_UI_DOWN, 4))
+ state->gfxset.offset[set] += xcells;
+ if (input_ui_pressed_repeat(IPT_UI_PAGE_UP, 6))
+ state->gfxset.offset[set] -= xcells * ycells;
+ if (input_ui_pressed_repeat(IPT_UI_PAGE_DOWN, 6))
+ state->gfxset.offset[set] += xcells * ycells;
+ if (input_ui_pressed_repeat(IPT_UI_HOME, 4))
+ state->gfxset.offset[set] = 0;
+ if (input_ui_pressed_repeat(IPT_UI_END, 4))
+ state->gfxset.offset[set] = gfx->total_elements;
+
+ /* clamp within range */
+ if (state->gfxset.offset[set] + xcells * ycells > ((gfx->total_elements + xcells - 1) / xcells) * xcells)
+ state->gfxset.offset[set] = ((gfx->total_elements + xcells - 1) / xcells) * xcells - xcells * ycells;
+ if (state->gfxset.offset[set] < 0)
+ state->gfxset.offset[set] = 0;
+
+ /* handle color selection (left,right) */
+ if (input_ui_pressed_repeat(IPT_UI_LEFT, 4))
+ state->gfxset.color[set] -= 1;
+ if (input_ui_pressed_repeat(IPT_UI_RIGHT, 4))
+ state->gfxset.color[set] += 1;
+
+ /* clamp within range */
+ if (state->gfxset.color[set] >= (int)gfx->total_colors)
+ state->gfxset.color[set] = gfx->total_colors - 1;
+ if (state->gfxset.color[set] < 0)
+ state->gfxset.color[set] = 0;
+
+ /* if something changed, we need to force an update to the bitmap */
+ if (state->gfxset.set != oldstate.gfxset.set ||
+ state->gfxset.offset[set] != oldstate.gfxset.offset[set] ||
+ state->gfxset.rotate[set] != oldstate.gfxset.rotate[set] ||
+ state->gfxset.color[set] != oldstate.gfxset.color[set] ||
+ state->gfxset.count[set] != oldstate.gfxset.count[set])
+ {
+ state->bitmap_dirty = TRUE;
+ }
+}
+
+
+/*-------------------------------------------------
+ gfxset_update_bitmap - redraw the current
+ graphics view bitmap
+-------------------------------------------------*/
+
+static void gfxset_update_bitmap(ui_gfx_state *state, int xcells, int ycells, gfx_element *gfx)
+{
+ int set = state->gfxset.set;
+ int cellxpix, cellypix;
+ int x, y;
+
+ /* compute the number of source pixels in a cell */
+ cellxpix = 1 + ((state->gfxset.rotate[set] & ORIENTATION_SWAP_XY) ? gfx->height : gfx->width);
+ cellypix = 1 + ((state->gfxset.rotate[set] & ORIENTATION_SWAP_XY) ? gfx->width : gfx->height);
+
+ /* realloc the bitmap if it is too small */
+ if (state->bitmap == NULL || state->texture == NULL || state->bitmap->bpp != 32 || state->bitmap->width != cellxpix * xcells || state->bitmap->height != cellypix * ycells)
+ {
+ /* free the old stuff */
+ if (state->texture != NULL)
+ render_texture_free(state->texture);
+ if (state->bitmap != NULL)
+ bitmap_free(state->bitmap);
+
+ /* allocate new stuff */
+ state->bitmap = bitmap_alloc(cellxpix * xcells, cellypix * ycells, BITMAP_FORMAT_ARGB32);
+ state->texture = render_texture_alloc(NULL, NULL);
+ render_texture_set_bitmap(state->texture, state->bitmap, NULL, 0, TEXFORMAT_ARGB32);
+
+ /* force a redraw */
+ state->bitmap_dirty = TRUE;
+ }
+
+ /* handle the redraw */
+ if (state->bitmap_dirty)
+ {
+ /* loop over rows */
+ for (y = 0; y < ycells; y++)
+ {
+ rectangle cellbounds;
+
+ /* make a rect that covers this row */
+ cellbounds.min_x = 0;
+ cellbounds.max_x = state->bitmap->width - 1;
+ cellbounds.min_y = y * cellypix;
+ cellbounds.max_y = (y + 1) * cellypix - 1;
+
+ /* only display if there is data to show */
+ if (state->gfxset.offset[set] + y * xcells < gfx->total_elements)
+ {
+ /* draw the individual cells */
+ for (x = 0; x < xcells; x++)
+ {
+ int index = state->gfxset.offset[set] + y * xcells + x;
+
+ /* update the bounds for this cell */
+ cellbounds.min_x = x * cellxpix;
+ cellbounds.max_x = (x + 1) * cellxpix - 1;
+
+ /* only render if there is data */
+ if (index < gfx->total_elements)
+ gfxset_draw_item(gfx, index, state->bitmap, cellbounds.min_x, cellbounds.min_y, state->gfxset.color[set], state->gfxset.rotate[set]);
+
+ /* otherwise, fill with transparency */
+ else
+ fillbitmap(state->bitmap, 0, &cellbounds);
+ }
+ }
+
+ /* otherwise, fill with transparency */
+ else
+ fillbitmap(state->bitmap, 0, &cellbounds);
+ }
+
+ /* reset the texture to force an update */
+ render_texture_set_bitmap(state->texture, state->bitmap, NULL, 0, TEXFORMAT_ARGB32);
+ state->bitmap_dirty = FALSE;
+ }
+}
+
+
+/*-------------------------------------------------
+ gfxset_draw_item - draw a single item into
+ the view
+-------------------------------------------------*/
+
+static void gfxset_draw_item(const gfx_element *gfx, int index, mame_bitmap *bitmap, int dstx, int dsty, int color, int rotate)
+{
+ static const pen_t default_palette[] =
+ {
+ MAKE_RGB(0,0,0), MAKE_RGB(0,0,255), MAKE_RGB(0,255,0), MAKE_RGB(0,255,255),
+ MAKE_RGB(255,0,0), MAKE_RGB(255,0,255), MAKE_RGB(255,255,0), MAKE_RGB(255,255,255)
+ };
+ int width = (rotate & ORIENTATION_SWAP_XY) ? gfx->height : gfx->width;
+ int height = (rotate & ORIENTATION_SWAP_XY) ? gfx->width : gfx->height;
+ const pen_t *palette = (Machine->drv->total_colors != 0) ? palette_entry_list_raw(Machine->palette) : NULL;
+ UINT32 rowpixels = bitmap->rowpixels;
+ const UINT16 *colortable = NULL;
+ UINT32 palette_mask = ~0;
+ int x, y;
+
+ /* select either the raw palette or the colortable */
+ if (Machine->game_colortable != NULL)
+ colortable = &Machine->game_colortable[gfx->color_base + color * gfx->color_granularity];
+ else if (palette != NULL)
+ palette += gfx->color_base + color * gfx->color_granularity;
+ else
+ {
+ palette = default_palette;
+ palette_mask = 7;
+ }
+
+ /* loop over rows in the cell */
+ for (y = 0; y < height; y++)
+ {
+ UINT32 *dest = (UINT32 *)bitmap->base + (dsty + y) * rowpixels + dstx;
+ UINT8 *src = gfx->gfxdata + index * gfx->char_modulo;
+
+ /* loop over columns in the cell */
+ for (x = 0; x < width; x++)
+ {
+ int effx = x, effy = y;
+ rgb_t pixel;
+ UINT8 *s;
+
+ /* compute effective x,y values after rotation */
+ if (!(rotate & ORIENTATION_SWAP_XY))
+ {
+ if (rotate & ORIENTATION_FLIP_X)
+ effx = gfx->width - 1 - effx;
+ if (rotate & ORIENTATION_FLIP_Y)
+ effy = gfx->height - 1 - effy;
+ }
+ else
+ {
+ int temp;
+ if (rotate & ORIENTATION_FLIP_X)
+ effx = gfx->height - 1 - effx;
+ if (rotate & ORIENTATION_FLIP_Y)
+ effy = gfx->width - 1 - effy;
+ temp = effx; effx = effy; effy = temp;
+ }
+
+ /* get a pointer to the start of this source row */
+ s = src + effy * gfx->line_modulo;
+
+ /* extract the pixel */
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ pixel = (s[effx/2] >> ((effx & 1) * 4)) & 0xf;
+ else
+ pixel = s[effx];
+ if (colortable != NULL)
+ pixel = colortable[pixel];
+ *dest++ = 0xff000000 | palette[pixel & palette_mask];
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ TILEMAP VIEWER
+***************************************************************************/
+
+/*-------------------------------------------------
+ tilemap_handler - handler for the tilemap
+ viewer
+-------------------------------------------------*/
+
+static void tilemap_handler(ui_gfx_state *state)
+{
+ render_font *ui_font = ui_get_font();
+ float chwidth, chheight;
+ render_bounds mapboxbounds;
+ render_bounds boxbounds;
+ int targwidth, targheight;
+ float titlewidth;
+ float x0, y0;
+ int mapboxwidth, mapboxheight;
+ int maxxscale, maxyscale;
+ UINT32 mapwidth, mapheight;
+ int x, pixelscale;
+ char title[100];
+
+ /* get the bounds of our target */
+ render_target_get_bounds(render_get_ui_target(), &targwidth, &targheight, NULL);
+
+ /* get the size of the tilemap itself */
+ tilemap_size_by_index(state->tilemap.which, &mapwidth, &mapheight);
+ if (state->tilemap.rotate & ORIENTATION_SWAP_XY)
+ { UINT32 temp = mapwidth; mapwidth = mapheight; mapheight = temp; }
+
+ /* add a half character padding for the box */
+ chheight = ui_get_line_height();
+ chwidth = render_font_get_char_width(ui_font, chheight, render_get_ui_aspect(), '0');
+ boxbounds.x0 = 0.0f + 0.5f * chwidth;
+ boxbounds.x1 = 1.0f - 0.5f * chwidth;
+ boxbounds.y0 = 0.0f + 0.5f * chheight;
+ boxbounds.y1 = 1.0f - 0.5f * chheight;
+
+ /* the tilemap box bounds starts a half character in from the box */
+ mapboxbounds = boxbounds;
+ mapboxbounds.x0 += 0.5f * chwidth;
+ mapboxbounds.x1 -= 0.5f * chwidth;
+ mapboxbounds.y0 += 0.5f * chheight;
+ mapboxbounds.y1 -= 0.5f * chheight;
+
+ /* add space on the top for a title and a half line of padding */
+ mapboxbounds.y0 += 1.5f * chheight;
+
+ /* convert back to pixels */
+ mapboxwidth = (mapboxbounds.x1 - mapboxbounds.x0) * (float)targwidth;
+ mapboxheight = (mapboxbounds.y1 - mapboxbounds.y0) * (float)targheight;
+
+ /* determine the maximum integral scaling factor */
+ pixelscale = state->tilemap.zoom;
+ if (pixelscale == 0)
+ {
+ for (maxxscale = 1; mapwidth * (maxxscale + 1) < mapboxwidth; maxxscale++) ;
+ for (maxyscale = 1; mapheight * (maxyscale + 1) < mapboxheight; maxyscale++) ;
+ pixelscale = MIN(maxxscale, maxyscale);
+ }
+
+ /* recompute the final box size */
+ mapboxwidth = MIN(mapboxwidth, mapwidth * pixelscale);
+ mapboxheight = MIN(mapboxheight, mapheight * pixelscale);
+
+ /* recompute the bounds, centered within the existing bounds */
+ mapboxbounds.x0 += 0.5f * ((mapboxbounds.x1 - mapboxbounds.x0) - (float)mapboxwidth / (float)targwidth);
+ mapboxbounds.x1 = mapboxbounds.x0 + (float)mapboxwidth / (float)targwidth;
+ mapboxbounds.y0 += 0.5f * ((mapboxbounds.y1 - mapboxbounds.y0) - (float)mapboxheight / (float)targheight);
+ mapboxbounds.y1 = mapboxbounds.y0 + (float)mapboxheight / (float)targheight;
+
+ /* now recompute the outer box against this new info */
+ boxbounds.x0 = mapboxbounds.x0 - 0.5f * chwidth;
+ boxbounds.x1 = mapboxbounds.x1 + 0.5f * chwidth;
+ boxbounds.y0 = mapboxbounds.y0 - 2.0f * chheight;
+ boxbounds.y1 = mapboxbounds.y1 + 0.5f * chheight;
+
+ /* figure out the title and expand the outer box to fit */
+ sprintf(title, "TMAP %d/%d %dx%d OFFS %d,%d", state->tilemap.which, tilemap_count() - 1, mapwidth, mapheight, state->tilemap.xoffs, state->tilemap.yoffs);
+ titlewidth = render_font_get_string_width(ui_font, chheight, render_get_ui_aspect(), title);
+ if (boxbounds.x1 - boxbounds.x0 < titlewidth + chwidth)
+ {
+ boxbounds.x0 = 0.5f - 0.5f * (titlewidth + chwidth);
+ boxbounds.x1 = boxbounds.x0 + titlewidth + chwidth;
+ }
+
+ /* go ahead and draw the outer box now */
+ ui_draw_outlined_box(boxbounds.x0, boxbounds.y0, boxbounds.x1, boxbounds.y1, UI_FILLCOLOR);
+
+ /* draw the title */
+ x0 = 0.5f - 0.5f * titlewidth;
+ y0 = boxbounds.y0 + 0.5f * chheight;
+ for (x = 0; title[x] != 0; x++)
+ {
+ render_ui_add_char(x0, y0, chheight, render_get_ui_aspect(), ARGB_WHITE, ui_font, title[x]);
+ x0 += render_font_get_char_width(ui_font, chheight, render_get_ui_aspect(), title[x]);
+ }
+
+ /* update the bitmap */
+ tilemap_update_bitmap(state, mapboxwidth / pixelscale, mapboxheight / pixelscale);
+
+ /* add the final quad */
+ render_ui_add_quad(mapboxbounds.x0, mapboxbounds.y0,
+ mapboxbounds.x1, mapboxbounds.y1,
+ ARGB_WHITE, state->texture,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(state->tilemap.rotate));
+
+ /* handle keyboard input */
+ tilemap_handle_keys(state, mapboxwidth, mapboxheight);
+}
+
+
+/*-------------------------------------------------
+ tilemap_handle_keys - handle keys for the
+ tilemap view
+-------------------------------------------------*/
+
+static void tilemap_handle_keys(ui_gfx_state *state, int viswidth, int visheight)
+{
+ ui_gfx_state oldstate = *state;
+ UINT32 mapwidth, mapheight;
+ int step;
+
+ /* handle tilemap selection (open bracket,close bracket) */
+ if (input_ui_pressed(IPT_UI_PREV_GROUP))
+ state->tilemap.which--;
+ if (input_ui_pressed(IPT_UI_NEXT_GROUP))
+ state->tilemap.which++;
+
+ /* clamp within range */
+ if (state->tilemap.which < 0)
+ state->tilemap.which = 0;
+ if (state->tilemap.which >= tilemap_count())
+ state->tilemap.which = tilemap_count() - 1;
+
+ /* cache some info in locals */
+ tilemap_size_by_index(state->tilemap.which, &mapwidth, &mapheight);
+
+ /* handle zoom (minus,plus) */
+ if (input_ui_pressed(IPT_UI_ZOOM_OUT))
+ state->tilemap.zoom--;
+ if (input_ui_pressed(IPT_UI_ZOOM_IN))
+ state->tilemap.zoom++;
+
+ /* clamp within range */
+ if (state->tilemap.zoom < 0)
+ state->tilemap.zoom = 0;
+ if (state->tilemap.zoom > 8)
+ state->tilemap.zoom = 8;
+ if (state->tilemap.zoom != oldstate.tilemap.zoom)
+ {
+ if (state->tilemap.zoom != 0)
+ popmessage("Zoom = %d", state->tilemap.zoom);
+ else
+ popmessage("Zoom Auto");
+ }
+
+ /* handle rotation (R) */
+ if (input_ui_pressed(IPT_UI_ROTATE))
+ state->tilemap.rotate = orientation_add(ROT90, state->tilemap.rotate);
+
+ /* handle navigation (up,down,left,right) */
+ step = 8;
+ if (input_code_pressed(KEYCODE_LSHIFT)) step = 1;
+ if (input_code_pressed(KEYCODE_LCONTROL)) step = 64;
+ if (input_ui_pressed_repeat(IPT_UI_UP, 4))
+ state->tilemap.yoffs -= step;
+ if (input_ui_pressed_repeat(IPT_UI_DOWN, 4))
+ state->tilemap.yoffs += step;
+ if (input_ui_pressed_repeat(IPT_UI_LEFT, 6))
+ state->tilemap.xoffs -= step;
+ if (input_ui_pressed_repeat(IPT_UI_RIGHT, 6))
+ state->tilemap.xoffs += step;
+
+ /* clamp within range */
+ while (state->tilemap.xoffs < 0)
+ state->tilemap.xoffs += mapwidth;
+ while (state->tilemap.xoffs >= mapwidth)
+ state->tilemap.xoffs -= mapwidth;
+ while (state->tilemap.yoffs < 0)
+ state->tilemap.yoffs += mapheight;
+ while (state->tilemap.yoffs >= mapheight)
+ state->tilemap.yoffs -= mapheight;
+
+ /* if something changed, we need to force an update to the bitmap */
+ if (state->tilemap.which != oldstate.tilemap.which ||
+ state->tilemap.xoffs != oldstate.tilemap.xoffs ||
+ state->tilemap.yoffs != oldstate.tilemap.yoffs ||
+ state->tilemap.rotate != oldstate.tilemap.rotate)
+ {
+ state->bitmap_dirty = TRUE;
+ }
+}
+
+
+/*-------------------------------------------------
+ tilemap_update_bitmap - update the bitmap
+ for the tilemap view
+-------------------------------------------------*/
+
+static void tilemap_update_bitmap(ui_gfx_state *state, int width, int height)
+{
+ bitmap_format screen_format = Machine->screen[0].format;
+ int screen_texformat;
+
+ /* convert the screen format to a texture format */
+ switch (screen_format)
+ {
+ case BITMAP_FORMAT_INDEXED16: screen_texformat = TEXFORMAT_PALETTE16; break;
+ case BITMAP_FORMAT_RGB15: screen_texformat = TEXFORMAT_RGB15; break;
+ case BITMAP_FORMAT_RGB32: screen_texformat = TEXFORMAT_RGB32; break;
+ default: fatalerror("Invalid bitmap format!"); break;
+ }
+
+ /* swap the coordinates back if they were talking about a rotated surface */
+ if (state->tilemap.rotate & ORIENTATION_SWAP_XY)
+ { UINT32 temp = width; width = height; height = temp; }
+
+ /* realloc the bitmap if it is too small */
+ if (state->bitmap == NULL || state->texture == NULL || state->bitmap->format != screen_format || state->bitmap->width != width || state->bitmap->height != height)
+ {
+ /* free the old stuff */
+ if (state->texture != NULL)
+ render_texture_free(state->texture);
+ if (state->bitmap != NULL)
+ bitmap_free(state->bitmap);
+
+ /* allocate new stuff */
+ state->bitmap = bitmap_alloc(width, height, screen_format);
+ state->texture = render_texture_alloc(NULL, NULL);
+ render_texture_set_bitmap(state->texture, state->bitmap, NULL, 0, screen_texformat);
+
+ /* force a redraw */
+ state->bitmap_dirty = TRUE;
+ }
+
+ /* handle the redraw */
+ if (state->bitmap_dirty)
+ {
+ tilemap_draw_by_index(state->bitmap, state->tilemap.which, state->tilemap.xoffs, state->tilemap.yoffs);
+
+ /* reset the texture to force an update */
+ render_texture_set_bitmap(state->texture, state->bitmap, NULL, 0, screen_texformat);
+ state->bitmap_dirty = FALSE;
+ }
+}
diff --git a/src/emu/uigfx.h b/src/emu/uigfx.h
new file mode 100644
index 00000000000..375f3cd392e
--- /dev/null
+++ b/src/emu/uigfx.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+
+ uigfx.h
+
+ Internal graphics viewer.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __UIGFX_H__
+#define __UIGFX_H__
+
+#include "mamecore.h"
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* initialization */
+void ui_gfx_init(running_machine *machine);
+
+/* master handler */
+UINT32 ui_gfx_ui_handler(UINT32 state);
+
+
+#endif /* __UIGFX_H__ */
diff --git a/src/emu/uimenu.c b/src/emu/uimenu.c
new file mode 100644
index 00000000000..f058e6dda59
--- /dev/null
+++ b/src/emu/uimenu.c
@@ -0,0 +1,2612 @@
+/*********************************************************************
+
+ uimenu.c
+
+ Internal MAME menus for the user interface.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "ui.h"
+#include "rendutil.h"
+#include "cheat.h"
+#include "uimenu.h"
+#include "uitext.h"
+#include "audit.h"
+
+#ifdef MESS
+#include "uimess.h"
+#include "inputx.h"
+#endif /* MESS */
+
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MENU_STACK_DEPTH 8
+#define MENU_STRING_POOL_SIZE (64*1024)
+
+#define MENU_TEXTCOLOR ARGB_WHITE
+#define MENU_SELECTCOLOR MAKE_ARGB(0xff,0xff,0xff,0x00)
+#define MENU_UNAVAILABLECOLOR MAKE_ARGB(0xff,0x40,0x40,0x40)
+
+#define VISIBLE_GAMES_IN_LIST 15
+
+#define MAX_PHYSICAL_DIPS 10
+
+/* DIP switch rendering parameters */
+#define DIP_SWITCH_HEIGHT 0.05f
+#define DIP_SWITCH_SPACING 0.01
+#define SINGLE_TOGGLE_SWITCH_FIELD_WIDTH 0.02f
+#define SINGLE_TOGGLE_SWITCH_WIDTH 0.015f
+/* make the switch 80% of the width space and 1/2 of the switch height */
+#define PERCENTAGE_OF_HALF_FIELD_USED 0.80f
+#define SINGLE_TOGGLE_SWITCH_HEIGHT ((DIP_SWITCH_HEIGHT / 2) * PERCENTAGE_OF_HALF_FIELD_USED)
+
+
+enum
+{
+ INPUT_TYPE_DIGITAL = 0,
+ INPUT_TYPE_ANALOG = 1,
+ INPUT_TYPE_ANALOG_DEC = 2,
+ INPUT_TYPE_ANALOG_INC = 3
+};
+
+enum
+{
+ ANALOG_ITEM_KEYSPEED = 0,
+ ANALOG_ITEM_CENTERSPEED,
+ ANALOG_ITEM_REVERSE,
+ ANALOG_ITEM_SENSITIVITY,
+ ANALOG_ITEM_COUNT
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _menu_state menu_state;
+struct _menu_state
+{
+ ui_menu_handler handler; /* handler callback */
+ UINT32 state; /* state value */
+};
+
+
+typedef struct _input_item_data input_item_data;
+struct _input_item_data
+{
+ input_seq * seq; /* pointer to the sequence we are operating on */
+ const input_seq *defseq; /* pointer to the sequence we are operating on */
+ const char * name;
+ const char * seqname;
+ UINT16 sortorder; /* sorting information */
+ UINT8 type; /* type of port */
+ UINT8 invert; /* type of port */
+};
+
+
+typedef struct _dip_descriptor dip_descriptor;
+struct _dip_descriptor
+{
+ const char * dip_name;
+ UINT16 total_dip_mask;
+ UINT16 total_dip_settings;
+ UINT16 dip_invert_mask;
+ UINT16 selected_dip_feature_mask;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* menu states */
+static int menu_stack_index;
+static menu_state menu_stack[MENU_STACK_DEPTH];
+
+static UINT32 menu_string_pool_offset;
+static char menu_string_pool[MENU_STRING_POOL_SIZE];
+
+static input_seq starting_seq;
+
+static char select_game_buffer[40];
+static const game_driver *select_game_list[VISIBLE_GAMES_IN_LIST];
+static const game_driver **select_game_driver_list;
+
+static dip_descriptor dip_switch_model[MAX_PHYSICAL_DIPS];
+
+static mame_bitmap *hilight_bitmap;
+static render_texture *hilight_texture;
+
+static render_texture *arrow_texture;
+
+static const char *input_format[] =
+{
+ "%s",
+ "%s Analog",
+ "%s Dec",
+ "%s Inc"
+};
+
+static const rgb_t text_fgcolor = MAKE_ARGB(0xff,0xff,0xff,0xff);
+static const rgb_t text_bgcolor = MAKE_ARGB(0xe0,0x80,0x80,0x80);
+static const rgb_t sel_fgcolor = MAKE_ARGB(0xff,0xff,0xff,0x00);
+static const rgb_t sel_bgcolor = MAKE_ARGB(0xe0,0x80,0x80,0x00);
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void ui_menu_exit(running_machine *machine);
+
+/* menu handlers */
+static UINT32 menu_main(UINT32 state);
+static UINT32 menu_input_groups(UINT32 state);
+static UINT32 menu_input(UINT32 state);
+static UINT32 menu_switches(UINT32 state);
+static UINT32 menu_analog(UINT32 state);
+#ifndef MESS
+static UINT32 menu_bookkeeping(UINT32 state);
+#endif
+static UINT32 menu_game_info(UINT32 state);
+static UINT32 menu_cheat(UINT32 state);
+static UINT32 menu_memory_card(UINT32 state);
+static UINT32 menu_video(UINT32 state);
+static UINT32 menu_quit_game(UINT32 state);
+static UINT32 menu_select_game(UINT32 state);
+#ifdef MESS
+static UINT32 menu_file_manager(UINT32 state);
+#if HAS_WAVE
+static UINT32 menu_tape_control(UINT32 state);
+#endif /* HAS_WAVE */
+#endif /* MESS */
+
+/* menu helpers */
+static void menu_render_triangle(mame_bitmap *dest, const mame_bitmap *source, const rectangle *sbounds, void *param);
+
+static int input_menu_get_items(input_item_data *itemlist, int group);
+static int input_menu_get_game_items(input_item_data *itemlist);
+static void input_menu_toggle_none_default(input_seq *selected_seq, input_seq *original_seq, const input_seq *selected_defseq);
+static int input_menu_compare_items(const void *i1, const void *i2);
+static void switches_menu_add_item(ui_menu_item *item, const input_port_entry *in, int switch_entry, void *ref);
+static void switches_menu_select_previous(input_port_entry *in, int switch_entry);
+static void switches_menu_select_next(input_port_entry *in, int switch_entry);
+//static int switches_menu_compare_items(const void *i1, const void *i2);
+static void analog_menu_add_item(ui_menu_item *item, const input_port_entry *in, int append_string, int which_item);
+
+/* DIP switch helpers */
+static void dip_switch_build_model(input_port_entry *entry, int item_is_selected);
+static void dip_switch_draw_one(float dip_menu_x1, float dip_menu_y1, float dip_menu_x2, float dip_menu_y2, int model_index);
+static void dip_switch_render(const menu_extra *extra, float x1, float y1, float x2, float y2);
+
+static int CLIB_DECL select_game_driver_compare(const void *elem1, const void *elem2);
+static void select_game_build_driver_list(void);
+static void select_game_render(const menu_extra *extra, float x1, float y1, float x2, float y2);
+static int select_game_handle_key(input_code keycode, char value);
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ menu_string_pool_add - add a formatted string
+ to the string pool
+-------------------------------------------------*/
+
+INLINE const char *CLIB_DECL menu_string_pool_add(const char *format, ...)
+{
+ char *result = &menu_string_pool[menu_string_pool_offset];
+ va_list arg;
+
+ /* print to the string pool */
+ va_start(arg, format);
+ menu_string_pool_offset += vsprintf(result, format, arg) + 1;
+ va_end(arg);
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ get_num_dips - return the number of physical
+ DIP switches that are to be drawn
+-------------------------------------------------*/
+
+INLINE int get_num_dips(void)
+{
+ int num = 0;
+
+ while (dip_switch_model[num].dip_name != NULL && num++ < MAX_PHYSICAL_DIPS)
+ ;
+
+ return num;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ ui_menu_init - initialize the menu system
+-------------------------------------------------*/
+
+void ui_menu_init(running_machine *machine)
+{
+ int x;
+
+ /* initialize the menu stack */
+ ui_menu_stack_reset();
+ select_game_buffer[0] = 0;
+
+ /* create a texture for hilighting items */
+ hilight_bitmap = bitmap_alloc(256, 1, BITMAP_FORMAT_ARGB32);
+ for (x = 0; x < 256; x++)
+ {
+ int alpha = 0xff;
+ if (x < 25) alpha = 0xff * x / 25;
+ if (x > 256 - 25) alpha = 0xff * (255 - x) / 25;
+ *BITMAP_ADDR32(hilight_bitmap, 0, x) = MAKE_ARGB(alpha,0xff,0xff,0xff);
+ }
+ hilight_texture = render_texture_alloc(NULL, NULL);
+ render_texture_set_bitmap(hilight_texture, hilight_bitmap, NULL, 0, TEXFORMAT_ARGB32);
+
+ /* create a texture for arrow icons */
+ arrow_texture = render_texture_alloc(menu_render_triangle, NULL);
+
+ /* add an exit callback to free memory */
+ add_exit_callback(machine, ui_menu_exit);
+}
+
+
+/*-------------------------------------------------
+ ui_menu_exit - clean up after ourselves
+-------------------------------------------------*/
+
+static void ui_menu_exit(running_machine *machine)
+{
+ /* free textures */
+ render_texture_free(hilight_texture);
+ bitmap_free(hilight_bitmap);
+ render_texture_free(arrow_texture);
+
+ /* free the driver list */
+ if (select_game_driver_list != NULL)
+ free((void *)select_game_driver_list);
+ select_game_driver_list = NULL;
+}
+
+
+/*-------------------------------------------------
+ ui_menu_draw - draw a menu
+-------------------------------------------------*/
+
+int ui_menu_draw(const ui_menu_item *items, int numitems, int selected, const menu_extra *extra)
+{
+ float line_height = ui_get_line_height();
+ float lr_arrow_width = 0.4f * line_height * render_get_ui_aspect();
+ float ud_arrow_width = line_height * render_get_ui_aspect();
+ float gutter_width = lr_arrow_width * 1.3f;
+ float x1, y1, x2, y2;
+
+ float effective_width, effective_left;
+ float visible_width, visible_main_menu_height;
+ float visible_extra_menu_height = 0;
+ float visible_top, visible_left;
+ int selected_subitem_too_big = 0;
+ int visible_lines;
+ int top_line;
+ int itemnum, linenum;
+
+ /* compute the width and height of the full menu */
+ visible_width = 0;
+ visible_main_menu_height = 0;
+ for (itemnum = 0; itemnum < numitems; itemnum++)
+ {
+ const ui_menu_item *item = &items[itemnum];
+ float total_width;
+
+ /* compute width of left hand side */
+ total_width = gutter_width + ui_get_string_width(item->text) + gutter_width;
+
+ /* add in width of right hand side */
+ if (item->subtext)
+ total_width += 2.0f * gutter_width + ui_get_string_width(item->subtext);
+
+ /* track the maximum */
+ if (total_width > visible_width)
+ visible_width = total_width;
+
+ /* track the height as well */
+ visible_main_menu_height += line_height;
+ }
+
+ /* if agumenting the menu, find out how much extra space is needed */
+ if (extra != NULL)
+ visible_extra_menu_height = extra->top + extra->bottom;
+
+ /* add a little bit of slop for rounding */
+ visible_width += 0.01f;
+ visible_main_menu_height += 0.01f;
+
+ /* if we are too wide or too tall, clamp it down */
+ if (visible_width + 2.0f * UI_BOX_LR_BORDER > 1.0f)
+ visible_width = 1.0f - 2.0f * UI_BOX_LR_BORDER;
+
+ /* if the menu and extra menu won't fit, take away part of the regular menu, it will scroll */
+ if (visible_main_menu_height + visible_extra_menu_height + 2.0f * UI_BOX_TB_BORDER > 1.0f)
+ visible_main_menu_height = 1.0f - 2.0f * UI_BOX_TB_BORDER - visible_extra_menu_height;
+
+ visible_lines = floor(visible_main_menu_height / line_height);
+ visible_main_menu_height = (float)visible_lines * line_height;
+
+ /* compute top/left of inner menu area by centering */
+ visible_left = (1.0f - visible_width) * 0.5f;
+ visible_top = (1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f;
+
+ /* if the menu is at the bottom of the extra, adjust */
+ if (extra != NULL)
+ visible_top += extra->top;
+
+ /* first add us a box */
+ x1 = visible_left - UI_BOX_LR_BORDER;
+ y1 = visible_top - UI_BOX_TB_BORDER;
+ x2 = visible_left + visible_width + UI_BOX_LR_BORDER;
+ y2 = visible_top + visible_main_menu_height + UI_BOX_TB_BORDER;
+ ui_draw_outlined_box(x1, y1, x2, y2, UI_FILLCOLOR);
+
+ /* determine the first visible line based on the current selection */
+ top_line = selected - visible_lines / 2;
+ if (top_line < 0)
+ top_line = 0;
+ if (top_line + visible_lines >= numitems)
+ top_line = numitems - visible_lines;
+
+ /* determine effective positions taking into account the hilighting arrows */
+ effective_width = visible_width - 2.0f * gutter_width;
+ effective_left = visible_left + gutter_width;
+
+ /* loop over visible lines */
+ for (linenum = 0; linenum < visible_lines; linenum++)
+ {
+ float line_y = visible_top + (float)linenum * line_height;
+ int itemnum = top_line + linenum;
+ const ui_menu_item *item = &items[itemnum];
+ const char *itemtext = item->text;
+ rgb_t fgcolor = text_fgcolor;
+ rgb_t bgcolor = text_bgcolor;
+
+ /* if we're selected, draw with a different background */
+ if (itemnum == selected)
+ {
+ fgcolor = sel_fgcolor;
+ bgcolor = sel_bgcolor;
+ render_ui_add_quad( x1 + 0.5f * UI_LINE_WIDTH,
+ line_y,
+ x2 - 0.5f * UI_LINE_WIDTH,
+ line_y + line_height,
+ bgcolor,
+ hilight_texture,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
+ }
+
+ /* if we're on the top line, display the up arrow */
+ if (linenum == 0 && top_line != 0)
+ {
+ render_ui_add_quad( 0.5f * (x1 + x2) - 0.5f * ud_arrow_width,
+ line_y + 0.25f * line_height,
+ 0.5f * (x1 + x2) + 0.5f * ud_arrow_width,
+ line_y + 0.75f * line_height,
+ fgcolor,
+ arrow_texture,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT0));
+ }
+
+ /* if we're on the bottom line, display the down arrow */
+ else if (linenum == visible_lines - 1 && itemnum != numitems - 1)
+ {
+ render_ui_add_quad( 0.5f * (x1 + x2) - 0.5f * ud_arrow_width,
+ line_y + 0.25f * line_height,
+ 0.5f * (x1 + x2) + 0.5f * ud_arrow_width,
+ line_y + 0.75f * line_height,
+ fgcolor,
+ arrow_texture,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT0 ^ ORIENTATION_FLIP_Y));
+ }
+
+ /* if we're just a divider, draw a line */
+ else if (strcmp(itemtext, "-") == 0)
+ render_ui_add_line(visible_left, line_y + 0.5f * line_height, visible_left + visible_width, line_y + 0.5f * line_height, UI_LINE_WIDTH, bgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ /* if we don't have a subitem, just draw the string centered */
+ else if (item->subtext == NULL)
+ ui_draw_text_full(itemtext, effective_left, line_y, effective_width,
+ JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, fgcolor, bgcolor, NULL, NULL);
+
+ /* otherwise, draw the item on the left and the subitem text on the right */
+ else
+ {
+ int subitem_invert = item->flags & MENU_FLAG_INVERT;
+ const char *subitem_text = item->subtext;
+ float item_width, subitem_width;
+
+ /* draw the left-side text */
+ ui_draw_text_full(itemtext, effective_left, line_y, effective_width,
+ JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, fgcolor, bgcolor, &item_width, NULL);
+
+ /* give 2 spaces worth of padding */
+ item_width += 2.0f * gutter_width;
+
+ /* if the subitem doesn't fit here, display dots */
+ if (ui_get_string_width(subitem_text) > effective_width - item_width)
+ {
+ subitem_text = "...";
+ if (itemnum == selected)
+ selected_subitem_too_big = 1;
+ }
+
+ /* draw the subitem right-justified */
+ ui_draw_text_full(subitem_text, effective_left + item_width, line_y, effective_width - item_width,
+ JUSTIFY_RIGHT, WRAP_TRUNCATE, subitem_invert ? DRAW_OPAQUE : DRAW_NORMAL, fgcolor, bgcolor, &subitem_width, NULL);
+
+ /* apply arrows */
+ if (itemnum == selected && (item->flags & MENU_FLAG_LEFT_ARROW))
+ {
+ render_ui_add_quad( effective_left + effective_width - subitem_width - gutter_width,
+ line_y + 0.1f * line_height,
+ effective_left + effective_width - subitem_width - gutter_width + lr_arrow_width,
+ line_y + 0.9f * line_height,
+ fgcolor,
+ arrow_texture,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90 ^ ORIENTATION_FLIP_X));
+ }
+ if (itemnum == selected && (item->flags & MENU_FLAG_RIGHT_ARROW))
+ {
+ render_ui_add_quad( effective_left + effective_width + gutter_width - lr_arrow_width,
+ line_y + 0.1f * line_height,
+ effective_left + effective_width + gutter_width,
+ line_y + 0.9f * line_height,
+ fgcolor,
+ arrow_texture,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90));
+ }
+ }
+ }
+
+ /* if the selected subitem is too big, display it in a separate offset box */
+ if (selected_subitem_too_big)
+ {
+ const ui_menu_item *item = &items[selected];
+ int subitem_invert = item->flags & MENU_FLAG_INVERT;
+ int linenum = selected - top_line;
+ float line_y = visible_top + (float)linenum * line_height;
+ float target_width, target_height;
+ float target_x, target_y;
+
+ /* compute the multi-line target width/height */
+ ui_draw_text_full(item->subtext, 0, 0, visible_width * 0.75f,
+ JUSTIFY_RIGHT, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &target_width, &target_height);
+
+ /* determine the target location */
+ target_x = visible_left + visible_width - target_width - UI_BOX_LR_BORDER;
+ target_y = line_y + line_height + UI_BOX_TB_BORDER;
+ if (target_y + target_height + UI_BOX_TB_BORDER > visible_main_menu_height)
+ target_y = line_y - target_height - UI_BOX_TB_BORDER;
+
+ /* add a box around that */
+ ui_draw_outlined_box(target_x - UI_BOX_LR_BORDER,
+ target_y - UI_BOX_TB_BORDER,
+ target_x + target_width + UI_BOX_LR_BORDER,
+ target_y + target_height + UI_BOX_TB_BORDER, subitem_invert ? sel_bgcolor : UI_FILLCOLOR);
+ ui_draw_text_full(item->subtext, target_x, target_y, target_width,
+ JUSTIFY_RIGHT, WRAP_WORD, DRAW_NORMAL, sel_fgcolor, sel_bgcolor, NULL, NULL);
+ }
+
+ /* if there is somthing special to add, do it by calling the passed routine */
+ if (extra != NULL)
+ (*extra->render)(extra, x1, y1, x2, y2);
+
+ /* return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow */
+ return visible_lines - (top_line != 0) - (top_line + visible_lines != numitems);
+}
+
+
+/*-------------------------------------------------
+ ui_menu_draw_text_box - draw a multiline
+ word-wrapped text box with a menu item at the
+ bottom
+-------------------------------------------------*/
+
+void ui_menu_draw_text_box(const char *text)
+{
+ const char *priortext = ui_getstring(UI_returntoprior);
+ float line_height = ui_get_line_height();
+ float lr_arrow_width = 0.4f * line_height * render_get_ui_aspect();
+ float gutter_width = lr_arrow_width;
+ float target_width, target_height, prior_width;
+ float target_x, target_y;
+
+ /* compute the multi-line target width/height */
+ ui_draw_text_full(text, 0, 0, 1.0f - 2.0f * UI_BOX_LR_BORDER - 2.0f * gutter_width,
+ JUSTIFY_LEFT, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &target_width, &target_height);
+ target_height += 2.0f * line_height;
+ if (target_height > 1.0f - 2.0f * UI_BOX_TB_BORDER)
+ target_height = floor((1.0f - 2.0f * UI_BOX_TB_BORDER) / line_height) * line_height;
+
+ /* maximum against "return to prior menu" text */
+ prior_width = ui_get_string_width(priortext) + 2.0f * gutter_width;
+ target_width = MAX(target_width, prior_width);
+
+ /* determine the target location */
+ target_x = 0.5f - 0.5f * target_width;
+ target_y = 0.5f - 0.5f * target_height;
+
+ /* make sure we stay on-screen */
+ if (target_x < UI_BOX_LR_BORDER + gutter_width)
+ target_x = UI_BOX_LR_BORDER + gutter_width;
+ if (target_x + target_width + gutter_width + UI_BOX_LR_BORDER > 1.0f)
+ target_x = 1.0f - UI_BOX_LR_BORDER - gutter_width - target_width;
+ if (target_y < UI_BOX_TB_BORDER)
+ target_y = UI_BOX_TB_BORDER;
+ if (target_y + target_height + UI_BOX_TB_BORDER > 1.0f)
+ target_y = 1.0f - UI_BOX_TB_BORDER - target_height;
+
+ /* add a box around that */
+ ui_draw_outlined_box(target_x - UI_BOX_LR_BORDER - gutter_width,
+ target_y - UI_BOX_TB_BORDER,
+ target_x + target_width + gutter_width + UI_BOX_LR_BORDER,
+ target_y + target_height + UI_BOX_TB_BORDER, UI_FILLCOLOR);
+ ui_draw_text_full(text, target_x, target_y, target_width,
+ JUSTIFY_LEFT, WRAP_WORD, DRAW_NORMAL, ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+
+ /* draw the "return to prior menu" text with a hilight behind it */
+ render_ui_add_quad( target_x + 0.5f * UI_LINE_WIDTH,
+ target_y + target_height - line_height,
+ target_x + target_width - 0.5f * UI_LINE_WIDTH,
+ target_y + target_height,
+ sel_bgcolor,
+ hilight_texture,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
+ ui_draw_text_full(priortext, target_x, target_y + target_height - line_height, target_width,
+ JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, sel_fgcolor, sel_bgcolor, NULL, NULL);
+}
+
+
+/*-------------------------------------------------
+ ui_menu_generic_keys - generically handle
+ keys for a menu
+-------------------------------------------------*/
+
+int ui_menu_generic_keys(UINT32 *selected, int num_items, int visible_items)
+{
+ /* hitting cancel or selecting the last item returns to the previous menu */
+ if (input_ui_pressed(IPT_UI_CANCEL) || (*selected == num_items - 1 && input_ui_pressed(IPT_UI_SELECT)))
+ {
+ *selected = ui_menu_stack_pop();
+ return 1;
+ }
+
+ /* up backs up by one item */
+ if (input_ui_pressed_repeat(IPT_UI_UP, 6))
+ *selected = (*selected + num_items - 1) % num_items;
+
+ /* down advances by one item */
+ if (input_ui_pressed_repeat(IPT_UI_DOWN, 6))
+ *selected = (*selected + 1) % num_items;
+
+ /* page up backs up by visible_items */
+ if (input_ui_pressed_repeat(IPT_UI_PAGE_UP, 6))
+ {
+ if (*selected >= visible_items - 1)
+ *selected -= visible_items - 1;
+ else
+ *selected = 0;
+ }
+
+ /* page down advances by visible_items */
+ if (input_ui_pressed_repeat(IPT_UI_PAGE_DOWN, 6))
+ {
+ *selected += visible_items - 1;
+ if (*selected >= num_items)
+ *selected = num_items - 1;
+ }
+
+ /* home goes to the start */
+ if (input_ui_pressed(IPT_UI_HOME))
+ *selected = 0;
+
+ /* end goes to the last */
+ if (input_ui_pressed(IPT_UI_END))
+ *selected = num_items - 1;
+
+ /* pause enables/disables pause */
+ if (input_ui_pressed(IPT_UI_PAUSE))
+ mame_pause(Machine, !mame_is_paused(Machine));
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ ui_menu_stack_reset - reset the menu stack
+-------------------------------------------------*/
+
+void ui_menu_stack_reset(void)
+{
+ menu_state *state = &menu_stack[menu_stack_index = 0];
+ state->handler = NULL;
+ state->state = 0;
+}
+
+
+/*-------------------------------------------------
+ ui_menu_stack_push - push a new menu onto the
+ stack
+-------------------------------------------------*/
+
+UINT32 ui_menu_stack_push(ui_menu_handler new_handler, UINT32 new_state)
+{
+ menu_state *state = &menu_stack[++menu_stack_index];
+ assert(menu_stack_index < MENU_STACK_DEPTH);
+ state->handler = new_handler;
+ state->state = new_state;
+ return new_state;
+}
+
+
+/*-------------------------------------------------
+ ui_menu_stack_pop - pop a menu from the stack
+-------------------------------------------------*/
+
+UINT32 ui_menu_stack_pop(void)
+{
+ menu_state *state = &menu_stack[--menu_stack_index];
+ assert(menu_stack_index >= 0);
+ return state->state;
+}
+
+
+/*-------------------------------------------------
+ ui_menu_ui_handler - displays the current menu
+ and calls the menu handler
+-------------------------------------------------*/
+
+UINT32 ui_menu_ui_handler(UINT32 state)
+{
+ UINT32 newstate;
+
+ /* if we have no menus stacked up, start with the main menu */
+ if (menu_stack[menu_stack_index].handler == NULL)
+ ui_menu_stack_push(menu_main, 0);
+
+ /* update the menu state */
+ newstate = (*menu_stack[menu_stack_index].handler)(menu_stack[menu_stack_index].state);
+ menu_stack[menu_stack_index].state = newstate;
+
+ /* if the menus are to be hidden, return a cancel here */
+ if ((input_ui_pressed(IPT_UI_CONFIGURE) && !ui_menu_is_force_game_select()) || menu_stack[menu_stack_index].handler == NULL)
+ return UI_HANDLER_CANCEL;
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ ui_menu_force_game_select - force the game
+ select menu to be visible and inescapable
+-------------------------------------------------*/
+
+void ui_menu_force_game_select(void)
+{
+ /* reset the menu stack */
+ ui_menu_stack_reset();
+
+ /* add the quit entry followed by the game select entry */
+ ui_menu_stack_push(menu_quit_game, 0);
+ ui_menu_stack_push(menu_select_game, 1 << 16);
+
+ /* initialize the game name buffer */
+ select_game_buffer[0] = 0;
+ strcpy(select_game_buffer, options_get_string(mame_options(), OPTION_GAMENAME));
+
+ /* force the menus on */
+ ui_show_menu();
+
+ /* make sure MAME is paused */
+ mame_pause(Machine, TRUE);
+}
+
+
+/*-------------------------------------------------
+ ui_menu_is_force_game_select - return true
+ if we are currently in "force game select"
+ mode
+-------------------------------------------------*/
+
+int ui_menu_is_force_game_select(void)
+{
+ return (menu_stack_index >= 2 && menu_stack[1].handler == menu_quit_game);
+}
+
+
+
+/***************************************************************************
+ MENU HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ menu_main - main UI menu
+-------------------------------------------------*/
+
+static UINT32 menu_main(UINT32 state)
+{
+#define ADD_MENU(name, _handler, _param) \
+do { \
+ item_list[menu_items].text = ui_getstring(name); \
+ handler_list[menu_items].handler = _handler; \
+ handler_list[menu_items].state = _param; \
+ menu_items++; \
+} while (0)
+
+ menu_state handler_list[20];
+ ui_menu_item item_list[20];
+ int has_categories = FALSE;
+ int has_configs = FALSE;
+ int has_analog = FALSE;
+ int has_dips = FALSE;
+ input_port_entry *in;
+ int menu_items = 0;
+ int visible_items;
+
+ /* scan the input port array to see what options we need to enable */
+ for (in = Machine->input_ports; in->type != IPT_END; in++)
+ if (input_port_active(in))
+ {
+ if (in->type == IPT_DIPSWITCH_NAME)
+ has_dips = TRUE;
+ if (port_type_is_analog(in->type))
+ has_analog = TRUE;
+ if (in->type == IPT_CONFIG_NAME)
+ has_configs = TRUE;
+ if (in->category > 0)
+ has_categories = TRUE;
+ }
+
+ /* reset the menu */
+ memset(item_list, 0, sizeof(item_list));
+
+ /* add input menu items */
+ ADD_MENU(UI_inputgeneral, menu_input_groups, 0);
+ ADD_MENU(UI_inputspecific, menu_input, 1000 << 16);
+
+ /* add optional input-related menus */
+ if (has_dips)
+ ADD_MENU(UI_dipswitches, menu_switches, (IPT_DIPSWITCH_NAME << 16) | (IPT_DIPSWITCH_SETTING << 24));
+ if (has_configs)
+ ADD_MENU(UI_configuration, menu_switches, (IPT_CONFIG_NAME << 16) | (IPT_CONFIG_SETTING << 24));
+#ifdef MESS
+ if (has_categories)
+ ADD_MENU(UI_categories, menu_switches, (IPT_CATEGORY_NAME << 16) | (IPT_CATEGORY_SETTING << 24));
+#endif
+ if (has_analog)
+ ADD_MENU(UI_analogcontrols, menu_analog, 0);
+
+#ifndef MESS
+ /* add bookkeeping menu */
+ ADD_MENU(UI_bookkeeping, menu_bookkeeping, 0);
+#endif
+
+ /* add game info menu */
+ ADD_MENU(UI_gameinfo, menu_game_info, 0);
+
+#ifdef MESS
+ /* add image info menu */
+ ADD_MENU(UI_imageinfo, ui_menu_image_info, 0);
+
+ /* add image info menu */
+ ADD_MENU(UI_filemanager, menu_file_manager, 1);
+
+#if HAS_WAVE
+ /* add tape control menu */
+ if (device_find(Machine->devices, IO_CASSETTE))
+ ADD_MENU(UI_tapecontrol, menu_tape_control, 1);
+#endif /* HAS_WAVE */
+#endif /* MESS */
+
+ /* add video options menu */
+ ADD_MENU(UI_video, menu_video, 1000 << 16);
+
+ /* add cheat menu */
+ if (options_get_bool(mame_options(), OPTION_CHEAT))
+ ADD_MENU(UI_cheat, menu_cheat, 1);
+
+ /* add memory card menu */
+ if (Machine->drv->memcard_handler != NULL)
+ ADD_MENU(UI_memorycard, menu_memory_card, 0);
+
+ /* add reset and exit menus */
+ ADD_MENU(UI_selectgame, menu_select_game, 1 << 16);
+ ADD_MENU(UI_returntogame, NULL, 0);
+
+ /* draw the menu */
+ visible_items = ui_menu_draw(item_list, menu_items, state, NULL);
+
+ /* handle the keys */
+ if (ui_menu_generic_keys(&state, menu_items, visible_items))
+ return state;
+ if (input_ui_pressed(IPT_UI_SELECT))
+ return ui_menu_stack_push(handler_list[state].handler, handler_list[state].state);
+
+ return state;
+
+#undef ADD_MENU
+}
+
+
+/*-------------------------------------------------
+ menu_input_groups - menu displaying input
+ groups
+-------------------------------------------------*/
+
+static UINT32 menu_input_groups(UINT32 state)
+{
+ ui_menu_item item_list[IPG_TOTAL_GROUPS + 2];
+ int menu_items = 0;
+ int visible_items;
+
+ /* reset the menu */
+ memset(item_list, 0, sizeof(item_list));
+
+ /* build up the menu */
+ for (menu_items = 0; menu_items < IPG_TOTAL_GROUPS; menu_items++)
+ item_list[menu_items].text = ui_getstring(UI_uigroup + menu_items);
+
+ /* add an item for the return */
+ item_list[menu_items++].text = ui_getstring(UI_returntoprior);
+
+ /* draw the menu */
+ visible_items = ui_menu_draw(item_list, menu_items, state, NULL);
+
+ /* handle the keys */
+ if (ui_menu_generic_keys(&state, menu_items, visible_items))
+ return state;
+ if (input_ui_pressed(IPT_UI_SELECT))
+ return ui_menu_stack_push(menu_input, state << 16);
+
+ return state;
+}
+
+
+/*-------------------------------------------------
+ menu_input - display a menu for inputs
+-------------------------------------------------*/
+
+static UINT32 menu_input(UINT32 state)
+{
+ ui_menu_item item_list[MAX_INPUT_PORTS * MAX_BITS_PER_PORT / 2];
+ input_item_data item_data[MAX_INPUT_PORTS * MAX_BITS_PER_PORT / 2];
+ input_item_data *selected_item_data;
+ UINT32 selected = state & 0x3fff;
+ int record_next = (state >> 14) & 1;
+ int polling = (state >> 15) & 1;
+ int group = state >> 16;
+ int visible_items;
+ int menu_items;
+ int item;
+
+ /* get the list of items */
+ menu_string_pool_offset = 0;
+ menu_items = input_menu_get_items(item_data, group);
+
+ /* build the menu */
+ memset(item_list, 0, sizeof(item_list));
+ for (item = 0; item < menu_items; item++)
+ {
+ input_item_data *id = &item_data[item];
+
+ /* set the item text from the precomputed data */
+ item_list[item].text = id->name;
+ item_list[item].subtext = id->seqname;
+ if (id->invert)
+ item_list[item].flags |= MENU_FLAG_INVERT;
+
+ /* keep the sequence pointer as a ref */
+ item_list[item].ref = id;
+ }
+
+ /* sort the list canonically */
+ qsort(item_list, menu_items, sizeof(item_list[0]), input_menu_compare_items);
+
+ /* add an item to return */
+ item_list[menu_items++].text = ui_getstring(UI_returntoprior);
+
+ /* if we're polling, just put an empty entry and arrows for the subitem */
+ if (polling)
+ {
+ item_list[selected].subtext = " ";
+ item_list[selected].flags = MENU_FLAG_LEFT_ARROW | MENU_FLAG_RIGHT_ARROW;
+ }
+
+ /* draw the menu */
+ visible_items = ui_menu_draw(item_list, menu_items, selected, NULL);
+
+ /* if we're polling, read the sequence */
+ selected_item_data = item_list[selected].ref;
+ if (polling)
+ {
+ input_seq newseq;
+
+ /* if UI_CANCEL is pressed, abort */
+ if (input_ui_pressed(IPT_UI_CANCEL))
+ {
+ record_next = polling = FALSE;
+ input_menu_toggle_none_default(selected_item_data->seq, &starting_seq, selected_item_data->defseq);
+ }
+
+ /* poll again; if finished, update the sequence */
+ if (input_seq_poll(&newseq))
+ {
+ record_next = TRUE;
+ polling = FALSE;
+ *selected_item_data->seq = newseq;
+ }
+ }
+
+ /* otherwise, handle the keys */
+ else
+ {
+ int prevsel = selected;
+
+ /* handle generic menu keys */
+ if (ui_menu_generic_keys(&selected, menu_items, visible_items))
+ return selected;
+
+ /* if an item was selected, start polling on it */
+ if (input_ui_pressed(IPT_UI_SELECT))
+ {
+ input_seq_poll_start((selected_item_data->type == INPUT_TYPE_ANALOG) ? ITEM_CLASS_ABSOLUTE : ITEM_CLASS_SWITCH, record_next ? selected_item_data->seq : NULL);
+ starting_seq = *selected_item_data->seq;
+ polling = TRUE;
+ }
+
+ /* if the clear key was pressed, reset the selected item */
+ if (input_ui_pressed(IPT_UI_CLEAR))
+ {
+ input_menu_toggle_none_default(selected_item_data->seq, selected_item_data->seq, selected_item_data->defseq);
+ record_next = FALSE;
+ }
+
+ /* if the selection changed, update and reset the "record first" flag */
+ if (selected != prevsel)
+ record_next = FALSE;
+ }
+
+ return selected | (record_next << 14) | (polling << 15) | (group << 16);
+}
+
+
+/*-------------------------------------------------
+ menu_switches - display a menu for DIP
+ switches
+-------------------------------------------------*/
+
+static UINT32 menu_switches(UINT32 state)
+{
+ ui_menu_item item_list[MAX_INPUT_PORTS * MAX_BITS_PER_PORT / 2];
+ int switch_entry = (state >> 24) & 0xff;
+ int switch_name = (state >> 16) & 0xff;
+ UINT32 selected = state & 0xffff;
+ input_port_entry *selected_in = NULL;
+ input_port_entry *in;
+ int menu_items = 0;
+ int changed = FALSE;
+ int visible_items;
+ menu_extra extra;
+
+ /* reset the menu */
+ memset(item_list, 0, sizeof(item_list));
+ /* reset the dip switch model */
+ memset(dip_switch_model, 0, sizeof(dip_switch_model));
+
+ /* loop over input ports and set up the current values */
+ for (in = Machine->input_ports; in->type != IPT_END; in++)
+ if (in->type == switch_name && input_port_active(in) && input_port_condition(in))
+ {
+ switches_menu_add_item(&item_list[menu_items], in, switch_entry, in);
+ if (in->type == IPT_DIPSWITCH_NAME)
+ dip_switch_build_model(in, menu_items == selected);
+ menu_items++;
+ }
+
+ /* sort the list */
+// qsort(item_list, menu_items, sizeof(item_list[0]), switches_menu_compare_items);
+ selected_in = item_list[selected].ref;
+
+ /* add an item to return */
+ item_list[menu_items++].text = ui_getstring(UI_returntoprior);
+
+ /* configure the extra menu */
+ extra.top = 0;
+ extra.bottom = get_num_dips() * (DIP_SWITCH_HEIGHT + DIP_SWITCH_SPACING) + DIP_SWITCH_SPACING;
+ extra.render = dip_switch_render;
+
+ /* go through the port map and create masks that are easy to use when drawing DIP graphics. */
+ /* draw the menu, augment the regular menue drawing with an additional box for DIPs */
+ visible_items = ui_menu_draw(item_list, menu_items, selected, (dip_switch_model[0].dip_name) ? &extra : NULL);
+
+ /* handle generic menu keys */
+ if (ui_menu_generic_keys(&selected, menu_items, visible_items))
+ return selected;
+
+ /* handle left/right arrows */
+ if (input_ui_pressed(IPT_UI_LEFT) && (item_list[selected].flags & MENU_FLAG_LEFT_ARROW))
+ {
+ switches_menu_select_previous(selected_in, switch_entry);
+ changed = TRUE;
+ }
+ if (input_ui_pressed(IPT_UI_RIGHT) && (item_list[selected].flags & MENU_FLAG_RIGHT_ARROW))
+ {
+ switches_menu_select_next(selected_in, switch_entry);
+ changed = TRUE;
+ }
+
+ /* update the selection to match the existing entry in case things got shuffled */
+ /* due to conditional DIPs changing things */
+ if (changed)
+ {
+ int newsel = 0;
+ input_port_update_defaults();
+ for (in = Machine->input_ports; in->type != IPT_END; in++)
+ if (in->type == switch_name && input_port_active(in) && input_port_condition(in))
+ {
+ if (selected_in == in)
+ {
+ selected = newsel;
+ break;
+ }
+ newsel++;
+ }
+ }
+
+ return selected | (switch_name << 16) | (switch_entry << 24);
+}
+
+
+/*-------------------------------------------------
+ menu_analog - display a menu for analog
+ control settings
+-------------------------------------------------*/
+
+static UINT32 menu_analog(UINT32 state)
+{
+ ui_menu_item item_list[MAX_INPUT_PORTS * 4 * ANALOG_ITEM_COUNT];
+ input_port_entry *selected_in = NULL;
+ input_port_entry *in;
+ int menu_items = 0;
+ int selected_item = 0;
+ int visible_items;
+ int delta = 0;
+ int use_autocenter;
+
+ /* reset the menu and string pool */
+ memset(item_list, 0, sizeof(item_list));
+ menu_string_pool_offset = 0;
+
+ /* loop over input ports and add the items */
+ for (in = Machine->input_ports; in->type != IPT_END; in++)
+ if (port_type_is_analog(in->type))
+ {
+ use_autocenter = 0;
+ switch (in->type)
+ {
+ /* Autocenter Speed is only used for these devices */
+ case IPT_POSITIONAL:
+ case IPT_POSITIONAL_V:
+ if (in->analog.wraps) break;
+
+ case IPT_PEDAL:
+ case IPT_PEDAL2:
+ case IPT_PEDAL3:
+ case IPT_PADDLE:
+ case IPT_PADDLE_V:
+ case IPT_AD_STICK_X:
+ case IPT_AD_STICK_Y:
+ case IPT_AD_STICK_Z:
+ use_autocenter = 1;
+ break;
+ }
+
+ /* track the selected item */
+ if (state >= menu_items && state < menu_items + 3 + use_autocenter)
+ {
+ selected_in = in;
+ selected_item = state - menu_items;
+ // shift menu for missing Autocenter
+ if (selected_item && !use_autocenter) selected_item++;
+ }
+
+ /* add the needed items for each analog input */
+ analog_menu_add_item(&item_list[menu_items++], in, UI_keyjoyspeed, ANALOG_ITEM_KEYSPEED);
+ if (use_autocenter)
+ analog_menu_add_item(&item_list[menu_items++], in, UI_centerspeed, ANALOG_ITEM_CENTERSPEED);
+ analog_menu_add_item(&item_list[menu_items++], in, UI_reverse, ANALOG_ITEM_REVERSE);
+ analog_menu_add_item(&item_list[menu_items++], in, UI_sensitivity, ANALOG_ITEM_SENSITIVITY);
+ }
+
+ /* add an item to return */
+ item_list[menu_items++].text = ui_getstring(UI_returntoprior);
+
+ /* draw the menu */
+ visible_items = ui_menu_draw(item_list, menu_items, state, NULL);
+
+ /* handle generic menu keys */
+ if (ui_menu_generic_keys(&state, menu_items, visible_items))
+ return state;
+
+ /* handle left/right arrows */
+ if (input_ui_pressed_repeat(IPT_UI_LEFT,6) && (item_list[state].flags & MENU_FLAG_LEFT_ARROW))
+ delta = -1;
+ if (input_ui_pressed_repeat(IPT_UI_RIGHT,6) && (item_list[state].flags & MENU_FLAG_RIGHT_ARROW))
+ delta = 1;
+ if (input_code_pressed(KEYCODE_LSHIFT))
+ delta *= 10;
+
+ /* adjust the appropriate value */
+ if (delta != 0 && selected_in)
+ switch (selected_item)
+ {
+ case ANALOG_ITEM_KEYSPEED: selected_in->analog.delta += delta; break;
+ case ANALOG_ITEM_CENTERSPEED: selected_in->analog.centerdelta += delta; break;
+ case ANALOG_ITEM_REVERSE: selected_in->analog.reverse += delta; break;
+ case ANALOG_ITEM_SENSITIVITY: selected_in->analog.sensitivity += delta; break;
+ }
+
+ return state;
+}
+
+
+/*-------------------------------------------------
+ menu_bookkeeping - display a "menu" for
+ bookkeeping information
+-------------------------------------------------*/
+
+#ifndef MESS
+static UINT32 menu_bookkeeping(UINT32 state)
+{
+ char buf[2048];
+ char *bufptr = buf;
+ UINT32 selected = 0;
+ int ctrnum;
+ attotime total_time;
+
+ /* show total time first */
+ total_time = timer_get_time();
+ if (total_time.seconds >= 60 * 60)
+ bufptr += sprintf(bufptr, "%s: %d:%02d:%02d\n\n", ui_getstring(UI_totaltime), total_time.seconds / (60*60), (total_time.seconds / 60) % 60, total_time.seconds % 60);
+ else
+ bufptr += sprintf(bufptr, "%s: %d:%02d\n\n", ui_getstring(UI_totaltime), (total_time.seconds / 60) % 60, total_time.seconds % 60);
+
+ /* show tickets at the top */
+ if (dispensed_tickets)
+ bufptr += sprintf(bufptr, "%s: %d\n\n", ui_getstring(UI_tickets), dispensed_tickets);
+
+ /* loop over coin counters */
+ for (ctrnum = 0; ctrnum < COIN_COUNTERS; ctrnum++)
+ {
+ /* display the coin counter number */
+ bufptr += sprintf(bufptr, "%s %c: ", ui_getstring(UI_coin), ctrnum + 'A');
+
+ /* display how many coins */
+ if (!coin_count[ctrnum])
+ bufptr += sprintf(bufptr, "%s", ui_getstring(UI_NA));
+ else
+ bufptr += sprintf(bufptr, "%d", coin_count[ctrnum]);
+
+ /* display whether or not we are locked out */
+ if (coinlockedout[ctrnum])
+ bufptr += sprintf(bufptr, " %s", ui_getstring(UI_locked));
+ *bufptr++ = '\n';
+ }
+ *bufptr = 0;
+
+ /* draw the text */
+ ui_menu_draw_text_box(buf);
+
+ /* handle the keys */
+ ui_menu_generic_keys(&selected, 1, 0);
+ return selected;
+}
+#endif
+
+
+/*-------------------------------------------------
+ menu_game_info - display a "menu" for
+ game information
+-------------------------------------------------*/
+
+static UINT32 menu_game_info(UINT32 state)
+{
+ char buf[2048];
+ char *bufptr = buf;
+ UINT32 selected = 0;
+
+ /* add the game info */
+ bufptr += sprintf_game_info(bufptr);
+
+ /* draw the text */
+ ui_menu_draw_text_box(buf);
+
+ /* handle the keys */
+ ui_menu_generic_keys(&selected, 1, 0);
+ return selected;
+}
+
+
+/*-------------------------------------------------
+ menu_cheat - display a menu for cheat options
+-------------------------------------------------*/
+
+static UINT32 menu_cheat(UINT32 state)
+{
+ int result = cheat_menu(state);
+ if (result == 0)
+ return ui_menu_stack_pop();
+ return result;
+}
+
+
+/*-------------------------------------------------
+ menu_memory_card - display a menu for memory
+ card options
+-------------------------------------------------*/
+
+static UINT32 menu_memory_card(UINT32 state)
+{
+ ui_menu_item item_list[5];
+ int menu_items = 0;
+ int cardnum = state >> 16;
+ UINT32 selected = state & 0xffff;
+ int insertindex = -1, ejectindex = -1, createindex = -1;
+ int visible_items;
+
+ /* reset the menu and string pool */
+ memset(item_list, 0, sizeof(item_list));
+ menu_string_pool_offset = 0;
+
+ /* add the card select menu */
+ item_list[menu_items].text = ui_getstring(UI_selectcard);
+ item_list[menu_items].subtext = menu_string_pool_add("%d", cardnum);
+ if (cardnum > 0)
+ item_list[menu_items].flags |= MENU_FLAG_LEFT_ARROW;
+ if (cardnum < 1000)
+ item_list[menu_items].flags |= MENU_FLAG_RIGHT_ARROW;
+ menu_items++;
+
+ /* add the remaining items */
+ item_list[insertindex = menu_items++].text = ui_getstring(UI_loadcard);
+ if (memcard_present() != -1)
+ item_list[ejectindex = menu_items++].text = ui_getstring(UI_ejectcard);
+ item_list[createindex = menu_items++].text = ui_getstring(UI_createcard);
+
+ /* add an item for the return */
+ item_list[menu_items++].text = ui_getstring(UI_returntoprior);
+
+ /* draw the menu */
+ visible_items = ui_menu_draw(item_list, menu_items, selected, NULL);
+
+ /* handle the keys */
+ if (ui_menu_generic_keys(&selected, menu_items, visible_items))
+ return selected;
+ if (selected == 0 && input_ui_pressed(IPT_UI_LEFT) && cardnum > 0)
+ cardnum--;
+ if (selected == 0 && input_ui_pressed(IPT_UI_RIGHT) && cardnum < 1000)
+ cardnum++;
+
+ /* handle actions */
+ if (input_ui_pressed(IPT_UI_SELECT))
+ {
+ /* handle load */
+ if (selected == insertindex)
+ {
+ if (memcard_insert(cardnum) == 0)
+ {
+ popmessage("%s", ui_getstring(UI_loadok));
+ ui_menu_stack_reset();
+ return 0;
+ }
+ else
+ popmessage("%s", ui_getstring(UI_loadfailed));
+ }
+
+ /* handle eject */
+ else if (selected == ejectindex)
+ {
+ memcard_eject(Machine);
+ popmessage("%s", ui_getstring(UI_cardejected));
+ }
+
+ /* handle create */
+ else if (selected == createindex)
+ {
+ if (memcard_create(cardnum, FALSE) == 0)
+ popmessage("%s", ui_getstring(UI_cardcreated));
+ else
+ popmessage("%s\n%s", ui_getstring(UI_cardcreatedfailed), ui_getstring(UI_cardcreatedfailed2));
+ }
+ }
+
+ return selected | (cardnum << 16);
+}
+
+
+/*-------------------------------------------------
+ menu_video - display a menu for video options
+-------------------------------------------------*/
+
+static UINT32 menu_video(UINT32 state)
+{
+ ui_menu_item item_list[100];
+ render_target *targetlist[16];
+ int curtarget = state >> 16;
+ UINT32 selected = state & 0xffff;
+ int menu_items = 0;
+ int visible_items;
+ int targets;
+
+ /* reset the menu and string pool */
+ memset(item_list, 0, sizeof(item_list));
+ menu_string_pool_offset = 0;
+
+ /* find the targets */
+ for (targets = 0; targets < ARRAY_LENGTH(targetlist); targets++)
+ {
+ targetlist[targets] = render_target_get_indexed(targets);
+ if (targetlist[targets] == NULL)
+ break;
+ }
+
+ /* if we have a current target of 1000, we may need to select from multiple targets */
+ if (curtarget == 1000)
+ {
+ /* count up the targets, creating menu items for them */
+ for (; menu_items < targets; menu_items++)
+ item_list[menu_items].text = menu_string_pool_add("%s%d", ui_getstring(UI_screen), menu_items);
+
+ /* if we only ended up with one, auto-select it */
+ if (menu_items == 1)
+ return menu_video(0 << 16 | render_target_get_view(render_target_get_indexed(0)));
+
+ /* add an item for moving the UI */
+ item_list[menu_items++].text = "Move User Interface";
+
+ /* add an item to return */
+ item_list[menu_items++].text = ui_getstring(UI_returntoprior);
+
+ /* draw the menu */
+ visible_items = ui_menu_draw(item_list, menu_items, selected, NULL);
+
+ /* handle the keys */
+ if (ui_menu_generic_keys(&selected, menu_items, visible_items))
+ return selected;
+
+ /* handle actions */
+ if (input_ui_pressed(IPT_UI_SELECT))
+ {
+ if (selected == menu_items - 2)
+ {
+ render_target *uitarget = render_get_ui_target();
+ int targnum;
+
+ for (targnum = 0; targnum < targets; targnum++)
+ if (targetlist[targnum] == uitarget)
+ break;
+ targnum = (targnum + 1) % targets;
+ render_set_ui_target(targetlist[targnum]);
+ }
+ else
+ return ui_menu_stack_push(menu_video, (selected << 16) | render_target_get_view(render_target_get_indexed(selected)));
+ }
+ }
+
+ /* otherwise, draw the list of layouts */
+ else
+ {
+ render_target *target = targetlist[curtarget];
+ int layermask;
+ assert(target != NULL);
+
+ /* add all the views */
+ for ( ; menu_items < ARRAY_LENGTH(item_list); menu_items++)
+ {
+ const char *name = render_target_get_view_name(target, menu_items);
+ if (name == NULL)
+ break;
+
+ /* create a string for the item */
+ item_list[menu_items].text = name;
+ }
+
+ /* add an item to rotate */
+ item_list[menu_items++].text = "Rotate View";
+
+ /* add an item to enable/disable backdrops */
+ layermask = render_target_get_layer_config(target);
+ if (layermask & LAYER_CONFIG_ENABLE_BACKDROP)
+ item_list[menu_items++].text = "Hide Backdrops";
+ else
+ item_list[menu_items++].text = "Show Backdrops";
+
+ /* add an item to enable/disable overlays */
+ if (layermask & LAYER_CONFIG_ENABLE_OVERLAY)
+ item_list[menu_items++].text = "Hide Overlays";
+ else
+ item_list[menu_items++].text = "Show Overlays";
+
+ /* add an item to enable/disable bezels */
+ if (layermask & LAYER_CONFIG_ENABLE_BEZEL)
+ item_list[menu_items++].text = "Hide Bezels";
+ else
+ item_list[menu_items++].text = "Show Bezels";
+
+ /* add an item to enable/disable cropping */
+ if (layermask & LAYER_CONFIG_ZOOM_TO_SCREEN)
+ item_list[menu_items++].text = "Show Full Artwork";
+ else
+ item_list[menu_items++].text = "Crop to Screen";
+
+ /* add an item to return */
+ item_list[menu_items++].text = ui_getstring(UI_returntoprior);
+
+ /* draw the menu */
+ visible_items = ui_menu_draw(item_list, menu_items, selected, NULL);
+
+ /* handle the keys */
+ if (ui_menu_generic_keys(&selected, menu_items, visible_items))
+ return selected;
+
+ /* handle actions */
+ if (input_ui_pressed(IPT_UI_SELECT))
+ {
+ /* rotate */
+ if (selected == menu_items - 6)
+ {
+ render_target_set_orientation(target, orientation_add(ROT90, render_target_get_orientation(target)));
+ if (target == render_get_ui_target())
+ render_container_set_orientation(render_container_get_ui(), orientation_add(ROT270, render_container_get_orientation(render_container_get_ui())));
+ }
+
+ /* show/hide backdrops */
+ else if (selected == menu_items - 5)
+ {
+ layermask ^= LAYER_CONFIG_ENABLE_BACKDROP;
+ render_target_set_layer_config(target, layermask);
+ }
+
+ /* show/hide overlays */
+ else if (selected == menu_items - 4)
+ {
+ layermask ^= LAYER_CONFIG_ENABLE_OVERLAY;
+ render_target_set_layer_config(target, layermask);
+ }
+
+ /* show/hide bezels */
+ else if (selected == menu_items - 3)
+ {
+ layermask ^= LAYER_CONFIG_ENABLE_BEZEL;
+ render_target_set_layer_config(target, layermask);
+ }
+
+ /* crop/uncrop artwork */
+ else if (selected == menu_items - 2)
+ {
+ layermask ^= LAYER_CONFIG_ZOOM_TO_SCREEN;
+ render_target_set_layer_config(target, layermask);
+ }
+
+ /* else just set the selected view */
+ else
+ render_target_set_view(target, selected);
+ }
+ }
+
+ return selected | (curtarget << 16);
+}
+
+
+/*-------------------------------------------------
+ menu_quit_game - handle the "menu" for
+ quitting the game
+-------------------------------------------------*/
+
+static UINT32 menu_quit_game(UINT32 state)
+{
+ /* request a reset */
+ mame_schedule_exit(Machine);
+
+ /* reset the menu stack */
+ ui_menu_stack_reset();
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ menu_select_game - handle the game select
+ menu
+-------------------------------------------------*/
+
+static UINT32 menu_select_game(UINT32 state)
+{
+ ui_menu_item item_list[VISIBLE_GAMES_IN_LIST + 2];
+ int error = (state >> 17) & 1;
+ int recompute = (state >> 16) & 1;
+ UINT32 selected = state & 0xffff;
+ int visible_items;
+ int menu_items = 0;
+ int curitem, curkey;
+ menu_extra extra;
+ int matchcount;
+
+ /* update our driver list if necessary */
+ if (select_game_driver_list == NULL)
+ select_game_build_driver_list();
+ for (curitem = matchcount = 0; select_game_driver_list[curitem] != NULL && matchcount < VISIBLE_GAMES_IN_LIST; curitem++)
+ if (!(select_game_driver_list[curitem]->flags & GAME_NO_STANDALONE))
+ matchcount++;
+
+ /* if nothing there, just display an error message and exit */
+ if (matchcount == 0)
+ {
+ ui_draw_text_box("No games found. Please check the rompath specified in the mame.ini file.\n\n"
+ "If this is your first time using MAME, please see the config.txt file in "
+ "the docs directory for information on configuring MAME.\n\n"
+ "Press any key to exit",
+ JUSTIFY_CENTER, 0.5f, 0.5f, UI_REDCOLOR);
+ if (input_code_poll_switches(FALSE))
+ return ui_menu_stack_pop();
+ return 0;
+ }
+
+ /* reset the menu and string pool */
+ memset(item_list, 0, sizeof(item_list));
+ menu_string_pool_offset = 0;
+
+ /* reset the text and recompute if necessary */
+ if (recompute)
+ driver_list_get_approx_matches(select_game_driver_list, select_game_buffer, matchcount, select_game_list);
+ recompute = 0;
+
+ /* iterate over entries */
+ for (curitem = 0; curitem < matchcount; curitem++)
+ {
+ const game_driver *driver = select_game_list[curitem];
+ if (driver != NULL)
+ {
+ const game_driver *cloneof = driver_get_clone(driver);
+ item_list[menu_items].text = menu_string_pool_add("%s", driver->name);
+ item_list[menu_items].subtext = menu_string_pool_add("%s", driver->description);
+ item_list[menu_items++].flags = (cloneof == NULL || (cloneof->flags & GAME_IS_BIOS_ROOT)) ? 0 : MENU_FLAG_INVERT;
+ }
+ }
+
+ /* add an item to return, but only if we're not going to pop to the quit handler */
+ if (!ui_menu_is_force_game_select())
+ item_list[menu_items++].text = ui_getstring(UI_returntoprior);
+
+ /* otherwise, add a general input configuration and exit menus */
+ else
+ {
+ item_list[menu_items++].text = "Configure General Inputs";
+ item_list[menu_items++].text = ui_getstring(UI_exit);
+ }
+
+ /* configure the extra menu */
+ extra.top = ui_get_line_height() + 3.0f * UI_BOX_TB_BORDER;
+ extra.bottom = 4.0f * ui_get_line_height() + 3.0f * UI_BOX_TB_BORDER;
+ extra.render = select_game_render;
+ extra.param = (selected < matchcount) ? (void *)select_game_list[selected] : NULL;
+
+ /* draw the menu */
+ visible_items = ui_menu_draw(item_list, menu_items, selected, &extra);
+
+ /* if we have an error, overlay with the error message and look for a keypress */
+ if (error)
+ {
+ ui_draw_text_box("The selected game is missing one or more required ROM or CHD images. "
+ "Please select a different game.\n\nPress any key to continue.",
+ JUSTIFY_CENTER, 0.5f, 0.5f, UI_REDCOLOR);
+ if (input_code_poll_switches(FALSE))
+ error = FALSE;
+ }
+
+ /* non-error case process normally */
+ else
+ {
+ /* handle typeahead */
+ recompute |= select_game_handle_key(KEYCODE_BACKSPACE, 8);
+ recompute |= select_game_handle_key(KEYCODE_SPACE, ' ');
+ for (curkey = KEYCODE_A; curkey <= KEYCODE_Z; curkey++)
+ recompute |= select_game_handle_key(curkey, curkey - KEYCODE_A + 'a');
+ for (curkey = KEYCODE_0; curkey <= KEYCODE_9; curkey++)
+ recompute |= select_game_handle_key(curkey, curkey - KEYCODE_0 + '0');
+ for (curkey = KEYCODE_0_PAD; curkey <= KEYCODE_9_PAD; curkey++)
+ recompute |= select_game_handle_key(curkey, curkey - KEYCODE_0_PAD + '0');
+
+ /* escape pressed with non-empty text clears the text */
+ if (input_ui_pressed(IPT_UI_CANCEL))
+ {
+ if (select_game_buffer[0] == 0)
+ return ui_menu_stack_pop();
+ else
+ {
+ select_game_buffer[0] = 0;
+ recompute = TRUE;
+ }
+ }
+
+ /* if we're recomputing, reselect the first item */
+ if (recompute)
+ selected = 0;
+
+ /* ignore pause keys by swallowing them */
+ input_ui_pressed(IPT_UI_PAUSE);
+
+ /* handle the generic keys */
+ if (!recompute && ui_menu_generic_keys(&selected, menu_items, visible_items))
+ return selected;
+
+ /* handle actions */
+ if (input_ui_pressed(IPT_UI_SELECT))
+ {
+ /* control config */
+ if (ui_menu_is_force_game_select() && selected == menu_items - 2)
+ return ui_menu_stack_push(menu_input_groups, 0);
+
+ /* valid selected game */
+ if (selected < ARRAY_LENGTH(select_game_list) && select_game_list[selected] != NULL)
+ {
+ audit_record *audit;
+ int audit_records;
+ int audit_result;
+
+ /* audit the game first to see if we're going to work */
+ audit_records = audit_images(mame_options(), select_game_list[selected], AUDIT_VALIDATE_FAST, &audit);
+ audit_result = audit_summary(select_game_list[selected], audit_records, audit, FALSE);
+ if (audit_records > 0)
+ free(audit);
+
+ /* if everything looks good, schedule the new driver */
+ if (audit_result == CORRECT || audit_result == BEST_AVAILABLE)
+ {
+ mame_schedule_new_driver(Machine, select_game_list[selected]);
+ ui_menu_stack_reset();
+ return 0;
+ }
+
+ /* otherwise, display an error */
+ else
+ {
+ error = TRUE;
+ input_code_poll_switches(TRUE);
+ }
+ }
+ }
+ }
+
+ return selected | (recompute << 16) | (error << 17);
+}
+
+
+/*-------------------------------------------------
+ menu_file_manager - MESS-specific menu
+-------------------------------------------------*/
+
+#ifdef MESS
+static UINT32 menu_file_manager(UINT32 state)
+{
+ int result = filemanager(state);
+ if (result == 0)
+ return ui_menu_stack_pop();
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ menu_tape_control - MESS-specific menu
+-------------------------------------------------*/
+
+#ifdef MESS
+#if HAS_WAVE
+static UINT32 menu_tape_control(UINT32 state)
+{
+ int result = tapecontrol(state);
+ if (result == 0)
+ return ui_menu_stack_pop();
+ return result;
+}
+#endif /* HAS_WAVE */
+#endif /* MESS */
+
+
+
+/***************************************************************************
+ MENU HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ menu_render_triangle - render a triangle that
+ is used for up/down arrows and left/right
+ indicators
+-------------------------------------------------*/
+
+static void menu_render_triangle(mame_bitmap *dest, const mame_bitmap *source, const rectangle *sbounds, void *param)
+{
+ int halfwidth = dest->width / 2;
+ int height = dest->height;
+ int x, y;
+
+ /* start with all-transparent */
+ bitmap_fill(dest, NULL, MAKE_ARGB(0x00,0x00,0x00,0x00));
+
+ /* render from the tip to the bottom */
+ for (y = 0; y < height; y++)
+ {
+ int linewidth = (y * (halfwidth - 1) + (height / 2)) * 255 * 2 / height;
+ UINT32 *target = BITMAP_ADDR32(dest, y, halfwidth);
+
+ /* don't antialias if height < 12 */
+ if (dest->height < 12)
+ {
+ int pixels = (linewidth + 254) / 255;
+ if (pixels % 2 == 0) pixels++;
+ linewidth = pixels * 255;
+ }
+
+ /* loop while we still have data to generate */
+ for (x = 0; linewidth > 0; x++)
+ {
+ int dalpha;
+
+ /* first colum we only consume one pixel */
+ if (x == 0)
+ {
+ dalpha = MIN(0xff, linewidth);
+ target[x] = MAKE_ARGB(dalpha,0xff,0xff,0xff);
+ }
+
+ /* remaining columns consume two pixels, one on each side */
+ else
+ {
+ dalpha = MIN(0x1fe, linewidth);
+ target[x] = target[-x] = MAKE_ARGB(dalpha/2,0xff,0xff,0xff);
+ }
+
+ /* account for the weight we consumed */
+ linewidth -= dalpha;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ input_menu_get_items - build a list of items
+ for a given group of inputs
+-------------------------------------------------*/
+
+static int input_menu_get_items(input_item_data *itemlist, int group)
+{
+ input_item_data *item = itemlist;
+ const input_port_default_entry *indef;
+ input_port_default_entry *in;
+ astring *seqstring;
+
+ /* an out of range group is special; it just means the game-specific inputs */
+ if (group > IPG_TOTAL_GROUPS)
+ return input_menu_get_game_items(itemlist);
+
+ /* iterate over the input ports and add menu items */
+ seqstring = astring_alloc();
+ for (in = get_input_port_list(), indef = get_input_port_list_defaults(); in->type != IPT_END; in++, indef++)
+
+ /* add if we match the group and we have a valid name */
+ if (in->group == group && in->name && in->name[0] != 0)
+ {
+ /* build an entry for the standard sequence */
+ item->seq = &in->defaultseq;
+ item->defseq = &indef->defaultseq;
+ item->sortorder = item - itemlist;
+ item->type = port_type_is_analog(in->type) ? INPUT_TYPE_ANALOG : INPUT_TYPE_DIGITAL;
+ item->name = menu_string_pool_add(input_format[item->type], in->name);
+ item->seqname = menu_string_pool_add("%s", astring_c(input_seq_name(seqstring, item->seq)));
+ item->invert = input_seq_cmp(item->seq, item->defseq);
+ item++;
+
+ /* if we're analog, add more entries */
+ if (item[-1].type == INPUT_TYPE_ANALOG)
+ {
+ /* build an entry for the decrement sequence */
+ item->seq = &in->defaultdecseq;
+ item->defseq = &indef->defaultdecseq;
+ item->sortorder = item - itemlist;
+ item->type = INPUT_TYPE_ANALOG_DEC;
+ item->name = menu_string_pool_add(input_format[item->type], in->name);
+ item->seqname = menu_string_pool_add("%s", astring_c(input_seq_name(seqstring, item->seq)));
+ item->invert = input_seq_cmp(item->seq, item->defseq);
+ item++;
+
+ /* build an entry for the increment sequence */
+ item->seq = &in->defaultincseq;
+ item->defseq = &indef->defaultincseq;
+ item->sortorder = item - itemlist;
+ item->type = INPUT_TYPE_ANALOG_INC;
+ item->name = menu_string_pool_add(input_format[item->type], in->name);
+ item->seqname = menu_string_pool_add("%s", astring_c(input_seq_name(seqstring, item->seq)));
+ item->invert = input_seq_cmp(item->seq, item->defseq);
+ item++;
+ }
+ }
+
+ /* return the number of items */
+ astring_free(seqstring);
+ return item - itemlist;
+}
+
+
+/*-------------------------------------------------
+ input_menu_get_game_items - build a list of
+ items for the game-specific inputs
+-------------------------------------------------*/
+
+static int input_menu_get_game_items(input_item_data *itemlist)
+{
+ static const input_seq default_seq = SEQ_DEF_1(SEQCODE_DEFAULT);
+ astring *seqstring = astring_alloc();
+ input_item_data *item = itemlist;
+ input_port_entry *in;
+
+ /* iterate over the input ports and add menu items */
+ for (in = Machine->input_ports; in->type != IPT_END; in++)
+ {
+ const char *name = input_port_name(in);
+
+ /* add if we match the group and we have a valid name */
+ if (name != NULL &&
+#ifdef MESS
+ (in->category == 0 || input_category_active(in->category)) &&
+#endif /* MESS */
+ ((in->type == IPT_OTHER && in->name != IP_NAME_DEFAULT) || port_type_to_group(in->type, in->player) != IPG_INVALID))
+ {
+ UINT16 sortorder;
+ input_seq *curseq, *defseq;
+
+ /* determine the sorting order */
+ if (in->type >= IPT_START1 && in->type <= __ipt_analog_end)
+ sortorder = (in->type << 2) | (in->player << 12);
+ else
+ sortorder = in->type | 0xf000;
+
+ /* fetch data for the standard sequence */
+ curseq = input_port_seq(in, SEQ_TYPE_STANDARD);
+ defseq = input_port_default_seq(in->type, in->player, SEQ_TYPE_STANDARD);
+
+ /* build an entry for the standard sequence */
+ item->seq = &in->seq;
+ item->defseq = &default_seq;
+ item->sortorder = sortorder;
+ item->type = port_type_is_analog(in->type) ? INPUT_TYPE_ANALOG : INPUT_TYPE_DIGITAL;
+ item->name = menu_string_pool_add(input_format[item->type], name);
+ item->seqname = menu_string_pool_add("%s", astring_c(input_seq_name(seqstring, curseq)));
+ item->invert = input_seq_cmp(curseq, defseq);
+ item++;
+
+ /* if we're analog, add more entries */
+ if (item[-1].type == INPUT_TYPE_ANALOG)
+ {
+ /* fetch data for the decrement sequence */
+ curseq = input_port_seq(in, SEQ_TYPE_DECREMENT);
+ defseq = input_port_default_seq(in->type, in->player, SEQ_TYPE_DECREMENT);
+
+ /* build an entry for the decrement sequence */
+ item->seq = &in->analog.decseq;
+ item->defseq = &default_seq;
+ item->sortorder = sortorder;
+ item->type = INPUT_TYPE_ANALOG_DEC;
+ item->name = menu_string_pool_add(input_format[item->type], name);
+ item->seqname = menu_string_pool_add("%s", astring_c(input_seq_name(seqstring, curseq)));
+ item->invert = input_seq_cmp(curseq, defseq);
+ item++;
+
+ /* fetch data for the increment sequence */
+ curseq = input_port_seq(in, SEQ_TYPE_INCREMENT);
+ defseq = input_port_default_seq(in->type, in->player, SEQ_TYPE_INCREMENT);
+
+ /* build an entry for the increment sequence */
+ item->seq = &in->analog.incseq;
+ item->defseq = &default_seq;
+ item->sortorder = sortorder;
+ item->type = INPUT_TYPE_ANALOG_INC;
+ item->name = menu_string_pool_add(input_format[item->type], name);
+ item->seqname = menu_string_pool_add("%s", astring_c(input_seq_name(seqstring, curseq)));
+ item->invert = input_seq_cmp(curseq, defseq);
+ item++;
+ }
+ }
+ }
+
+ /* return the number of items */
+ astring_free(seqstring);
+ return item - itemlist;
+}
+
+
+/*-------------------------------------------------
+ input_menu_toggle_none_default - toggle
+ between "NONE" and the default item
+-------------------------------------------------*/
+
+static void input_menu_toggle_none_default(input_seq *selected_seq, input_seq *original_seq, const input_seq *selected_defseq)
+{
+ /* if we used to be "none", toggle to the default value */
+ if (input_seq_get_1(original_seq) == SEQCODE_END)
+ *selected_seq = *selected_defseq;
+
+ /* otherwise, toggle to "none" */
+ else
+ input_seq_set_1(selected_seq, SEQCODE_END);
+}
+
+
+/*-------------------------------------------------
+ input_menu_compare_items - compare two
+ items for quicksort
+-------------------------------------------------*/
+
+static int input_menu_compare_items(const void *i1, const void *i2)
+{
+ const ui_menu_item *item1 = i1;
+ const ui_menu_item *item2 = i2;
+ const input_item_data *data1 = item1->ref;
+ const input_item_data *data2 = item2->ref;
+ if (data1->sortorder < data2->sortorder)
+ return -1;
+ if (data1->sortorder > data2->sortorder)
+ return 1;
+ if (data1->type < data2->type)
+ return -1;
+ if (data1->type > data2->type)
+ return 1;
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ switches_menu_add_item - add an item to the
+ switches menu list
+-------------------------------------------------*/
+
+static void switches_menu_add_item(ui_menu_item *item, const input_port_entry *in, int switch_entry, void *ref)
+{
+ const input_port_entry *tin;
+
+ /* set the text to the name and the subitem text to invalid */
+ item->text = input_port_name(in);
+ item->subtext = NULL;
+
+ /* scan for the current selection in the list */
+ for (tin = in + 1; tin->type == switch_entry; tin++)
+ if (input_port_condition(tin))
+ {
+ /* if this is a match, set the subtext */
+ if (in->default_value == tin->default_value)
+ item->subtext = input_port_name(tin);
+
+ /* else if we haven't seen a match yet, show a left arrow */
+ else if (!item->subtext)
+ item->flags |= MENU_FLAG_LEFT_ARROW;
+
+ /* else if we have seen a match, show a right arrow */
+ else
+ item->flags |= MENU_FLAG_RIGHT_ARROW;
+ }
+
+ /* if no matches, we're invalid */
+ if (!item->subtext)
+ item->subtext = ui_getstring(UI_INVALID);
+
+ /* stash our reference */
+ item->ref = ref;
+}
+
+
+/*-------------------------------------------------
+ switches_menu_select_previous - select the
+ previous item in the switches list
+-------------------------------------------------*/
+
+static void switches_menu_select_previous(input_port_entry *in, int switch_entry)
+{
+ int last_value = in->default_value;
+ const input_port_entry *tin;
+
+ /* scan for the current selection in the list */
+ for (tin = in + 1; tin->type == switch_entry; tin++)
+ if (input_port_condition(tin))
+ {
+ /* if this is a match, we're done */
+ if (in->default_value == tin->default_value)
+ {
+ in->default_value = last_value;
+ return;
+ }
+
+ /* otherwise, keep track of last one found */
+ else
+ last_value = tin->default_value;
+ }
+}
+
+
+/*-------------------------------------------------
+ switches_menu_select_next - select the
+ next item in the switches list
+-------------------------------------------------*/
+
+static void switches_menu_select_next(input_port_entry *in, int switch_entry)
+{
+ const input_port_entry *tin;
+ int foundit = FALSE;
+
+ /* scan for the current selection in the list */
+ for (tin = in + 1; tin->type == switch_entry; tin++)
+ if (input_port_condition(tin))
+ {
+ /* if we found the current selection, we pick the next one */
+ if (foundit)
+ {
+ in->default_value = tin->default_value;
+ return;
+ }
+
+ /* if this is a match, note it */
+ if (in->default_value == tin->default_value)
+ foundit = TRUE;
+ }
+}
+
+
+/*-------------------------------------------------
+ switches_menu_compare_items - compare two
+ switches items for quicksort purposes
+-------------------------------------------------*/
+
+/*
+static int switches_menu_compare_items(const void *i1, const void *i2)
+{
+ const ui_menu_item *item1 = i1;
+ const ui_menu_item *item2 = i2;
+ const input_port_entry *data1 = item1->ref;
+ const input_port_entry *data2 = item2->ref;
+ return strcmp(input_port_name(data1), input_port_name(data2));
+}
+*/
+
+
+/*-------------------------------------------------
+ analog_menu_add_item - add an item to the
+ analog controls menu
+-------------------------------------------------*/
+
+static void analog_menu_add_item(ui_menu_item *item, const input_port_entry *in, int append_string, int which_item)
+{
+ int value, minval, maxval;
+
+ /* set the item text using the formatting string provided */
+ item->text = menu_string_pool_add("%s %s", input_port_name(in), ui_getstring(append_string));
+
+ /* set the subitem text */
+ switch (which_item)
+ {
+ default:
+ case ANALOG_ITEM_KEYSPEED:
+ value = in->analog.delta;
+ minval = 0;
+ maxval = 255;
+ item->subtext = menu_string_pool_add("%d", value);
+ break;
+
+ case ANALOG_ITEM_CENTERSPEED:
+ value = in->analog.centerdelta;
+ minval = 0;
+ maxval = 255;
+ item->subtext = menu_string_pool_add("%d", value);
+ break;
+
+ case ANALOG_ITEM_REVERSE:
+ value = in->analog.reverse;
+ minval = 0;
+ maxval = 1;
+ item->subtext = value ? ui_getstring(UI_on) : ui_getstring(UI_off);
+ break;
+
+ case ANALOG_ITEM_SENSITIVITY:
+ value = in->analog.sensitivity;
+ minval = 1;
+ maxval = 255;
+ item->subtext = menu_string_pool_add("%d%%", value);
+ break;
+ }
+
+ /* put on arrows */
+ if (value > minval)
+ item->flags |= MENU_FLAG_LEFT_ARROW;
+ if (value < maxval)
+ item->flags |= MENU_FLAG_RIGHT_ARROW;
+}
+
+
+/*-------------------------------------------------
+ dip_switch_build_model - build up the model
+ for DIP switches
+-------------------------------------------------*/
+
+static void dip_switch_build_model(input_port_entry *entry, int item_is_selected)
+{
+ int dip_declaration_index = 0;
+ int value_mask_temp = entry->mask;
+ int value_mask_bit = 0;
+ int toggle_switch_mask;
+ int model_index = 0;
+ int toggle_num;
+
+ if (entry->diploc[dip_declaration_index].swname == NULL)
+ return;
+
+ /* get the entry in the model to work with */
+ do
+ {
+ /* use this entry if it's not used */
+ if (dip_switch_model[model_index].dip_name == NULL)
+ {
+ dip_switch_model[model_index].dip_name = entry->diploc[dip_declaration_index].swname;
+ break;
+ }
+
+ /* reuse this entry if the switch name matches */
+ if (!strcmp(entry->diploc[dip_declaration_index].swname, dip_switch_model[model_index].dip_name))
+ break;
+
+ // todo: add a check here to see if we go over the max dips and throw an error.
+ } while (++model_index < MAX_PHYSICAL_DIPS);
+
+ /* Create a mask depicting the number of toggles on the physical switch */
+ while (entry->diploc[dip_declaration_index].swname)
+ {
+ /* get the Nth DIP toggle number */
+ toggle_num = entry->diploc[dip_declaration_index].swnum;
+
+ /* get the Nth mask bit -
+ * should probably put a check here to avoid bad driver definitions
+ * which could put us into an infinite loop. */
+ while (!(value_mask_temp & 1))
+ {
+ value_mask_temp >>= 1;
+ ++value_mask_bit;
+ }
+ /* clear out the lsb to keep it moving next iteration. */
+ value_mask_temp &= ~1;
+
+ toggle_switch_mask = 1 << (toggle_num - 1);
+
+ /* indicate the toggle exists in the switch */
+ dip_switch_model[model_index].total_dip_mask |= toggle_switch_mask;
+
+ /* if it's inverted, mark it as such */
+ if (entry->diploc[dip_declaration_index].invert)
+ dip_switch_model[model_index].dip_invert_mask |= toggle_switch_mask;
+
+ /* if isolated bit is on, set the toggle on */
+ if ((1 << value_mask_bit) & entry->default_value)
+ dip_switch_model[model_index].total_dip_settings |= toggle_switch_mask;
+
+ /* indicate if the toggle is selected */
+ if (item_is_selected)
+ dip_switch_model[model_index].selected_dip_feature_mask |= toggle_switch_mask;
+
+ ++dip_declaration_index;
+ }
+}
+
+
+/*-------------------------------------------------
+ dip_switch_draw_one - draw a single DIP
+ switch
+-------------------------------------------------*/
+
+static void dip_switch_draw_one(float dip_menu_x1, float dip_menu_y1, float dip_menu_x2, float dip_menu_y2, int model_index)
+{
+ int toggle_index;
+ int num_toggles = 0;
+ float segment_start_x;
+ float dip_field_y;
+ float y1_on, y2_on, y1_off, y2_off;
+ float switch_toggle_gap;
+ float name_width;
+
+ /* determine the number of toggles in the DIP */
+ for (toggle_index = 0; toggle_index < 16; toggle_index++)
+ if (dip_switch_model[model_index].total_dip_mask & (1 << toggle_index))
+ num_toggles = toggle_index + 1;
+
+ /* calculate the starting x coordinate so that the entire switch is centered */
+ dip_field_y = dip_menu_y1 + DIP_SWITCH_SPACING + (model_index * (DIP_SWITCH_SPACING + DIP_SWITCH_HEIGHT));
+
+ switch_toggle_gap = ((DIP_SWITCH_HEIGHT/2) - SINGLE_TOGGLE_SWITCH_HEIGHT)/2;
+
+ segment_start_x = dip_menu_x1 + (dip_menu_x2 - dip_menu_x1 - num_toggles * SINGLE_TOGGLE_SWITCH_FIELD_WIDTH) / 2;
+
+ y1_off = dip_field_y + UI_LINE_WIDTH + switch_toggle_gap;
+ y2_off = y1_off + SINGLE_TOGGLE_SWITCH_HEIGHT;
+
+ y1_on = dip_field_y + DIP_SWITCH_HEIGHT/2 + switch_toggle_gap;
+ y2_on = y1_on + SINGLE_TOGGLE_SWITCH_HEIGHT;
+
+ for (toggle_index = 0; toggle_index < num_toggles; toggle_index++)
+ {
+ int bit_mask, dip_on;
+ float dip_field_x1, x1, x2;
+
+ bit_mask = 1 << toggle_index;
+
+ /* draw the field for a single toggle on a DIP switch */
+ dip_field_x1 = segment_start_x + (SINGLE_TOGGLE_SWITCH_FIELD_WIDTH * toggle_index);
+
+ ui_draw_outlined_box(dip_field_x1,
+ dip_field_y,
+ dip_field_x1 + SINGLE_TOGGLE_SWITCH_FIELD_WIDTH,
+ dip_field_y + DIP_SWITCH_HEIGHT,
+ UI_FILLCOLOR);
+
+ x1 = dip_field_x1 + (SINGLE_TOGGLE_SWITCH_FIELD_WIDTH - SINGLE_TOGGLE_SWITCH_WIDTH) / 2;
+ x2 = x1 + SINGLE_TOGGLE_SWITCH_WIDTH;
+
+ /* see if the switch is actually used */
+ if (dip_switch_model[model_index].total_dip_mask & bit_mask)
+ {
+ /* yes, draw the switch position for a single toggle switch in a switch field */
+ int feature_field_selected = ((bit_mask & dip_switch_model[model_index].selected_dip_feature_mask) != 0);
+ dip_on = ((bit_mask & (dip_switch_model[model_index].total_dip_settings ^ dip_switch_model[model_index].dip_invert_mask)) != 0);
+
+ render_ui_add_rect(x1, dip_on ? y1_on : y1_off,
+ x2, dip_on ? y2_on : y2_off,
+ feature_field_selected ? MENU_SELECTCOLOR : ARGB_WHITE,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+ else
+ {
+ /* no, draw it grayed out */
+ render_ui_add_rect(x1, y1_off,
+ x2, y2_on,
+ MENU_UNAVAILABLECOLOR,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+ }
+
+ /* add the dip switch name */
+ name_width = ui_get_string_width(dip_switch_model[model_index].dip_name) + ui_get_string_width(" ") / 2;
+
+ ui_draw_text_full( dip_switch_model[model_index].dip_name,
+ segment_start_x - name_width,
+ dip_field_y + (DIP_SWITCH_HEIGHT - UI_TARGET_FONT_HEIGHT)/2,
+ name_width,
+ JUSTIFY_LEFT,
+ WRAP_NEVER,
+ DRAW_NORMAL,
+ ARGB_WHITE,
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA),
+ NULL ,
+ NULL);
+}
+
+
+/*-------------------------------------------------
+ dip_switch_render - perform our special
+ rendering
+-------------------------------------------------*/
+
+static void dip_switch_render(const menu_extra *extra, float x1, float y1, float x2, float y2)
+{
+ int num_dips;
+ int dip_model_index;
+ float dip_menu_y1, dip_menu_y2;
+
+ /* how many dips does this game have? */
+ num_dips = get_num_dips();
+
+ dip_menu_y1 = y2 + UI_BOX_TB_BORDER;
+ dip_menu_y2 = dip_menu_y1 + extra->bottom;
+
+ /* draw extra menu area */
+ ui_draw_outlined_box(x1, dip_menu_y1, x2, dip_menu_y2, UI_FILLCOLOR);
+
+ /* draw all the dip switches */
+ for (dip_model_index = 0; dip_model_index < num_dips; dip_model_index++)
+ dip_switch_draw_one(x1, dip_menu_y1, x2, dip_menu_y2, dip_model_index);
+}
+
+
+/*-------------------------------------------------
+ select_game_driver_compare - compare the
+ names of two drivers
+-------------------------------------------------*/
+
+static int CLIB_DECL select_game_driver_compare(const void *elem1, const void *elem2)
+{
+ const game_driver **driver1_ptr = (const game_driver **)elem1;
+ const game_driver **driver2_ptr = (const game_driver **)elem2;
+ const char *driver1 = (*driver1_ptr)->name;
+ const char *driver2 = (*driver2_ptr)->name;
+
+ while (*driver1 == *driver2 && *driver1 != 0)
+ driver1++, driver2++;
+ return *driver1 - *driver2;
+}
+
+
+/*-------------------------------------------------
+ select_game_build_driver_list - build a list
+ of available drivers
+-------------------------------------------------*/
+
+static void select_game_build_driver_list(void)
+{
+ int driver_count = driver_list_get_count(drivers);
+ int drivnum, listnum;
+ mame_path *path;
+ UINT8 *found;
+
+ /* first allocate a copy of the full driver list */
+ if (select_game_driver_list == NULL)
+ select_game_driver_list = malloc_or_die(driver_count * sizeof(*select_game_driver_list));
+ memcpy((void *)select_game_driver_list, drivers, driver_count * sizeof(*select_game_driver_list));
+
+ /* sort it */
+ qsort((void *)select_game_driver_list, driver_count, sizeof(*select_game_driver_list), select_game_driver_compare);
+
+ /* allocate a temporary array to track which ones we found */
+ found = malloc_or_die((driver_count + 1) * sizeof(*found));
+ memset(found, 0, (driver_count + 1) * sizeof(*found));
+
+ /* open a path to the ROMs and find them in the array */
+ path = mame_openpath(mame_options(), OPTION_ROMPATH);
+ if (path != NULL)
+ {
+ const osd_directory_entry *dir;
+
+ /* iterate while we get new objects */
+ while ((dir = mame_readpath(path)) != NULL)
+ {
+ game_driver tempdriver;
+ game_driver *tempdriver_ptr;
+ const game_driver **found_driver;
+ char drivername[50];
+ char *dst = drivername;
+ const char *src;
+
+ /* build a name for it */
+ for (src = dir->name; *src != 0 && *src != '.' && dst < &drivername[ARRAY_LENGTH(drivername) - 1]; src++)
+ *dst++ = tolower(*src);
+ *dst = 0;
+
+ /* find it in the array */
+ tempdriver.name = drivername;
+ tempdriver_ptr = &tempdriver;
+ found_driver = bsearch(&tempdriver_ptr, select_game_driver_list, driver_count, sizeof(*select_game_driver_list), select_game_driver_compare);
+
+ /* if found, mark the corresponding entry in the array */
+ if (found_driver != NULL)
+ found[found_driver - select_game_driver_list] = TRUE;
+ }
+ mame_closepath(path);
+ }
+
+ /* now build the final list */
+ for (drivnum = listnum = 0; drivnum < driver_count; drivnum++)
+ if (found[drivnum])
+ select_game_driver_list[listnum++] = select_game_driver_list[drivnum];
+
+ /* NULL-terminate */
+ select_game_driver_list[listnum] = NULL;
+ free(found);
+}
+
+
+/*-------------------------------------------------
+ select_game_render - perform our special
+ rendering
+-------------------------------------------------*/
+
+static void select_game_render(const menu_extra *extra, float origx1, float origy1, float origx2, float origy2)
+{
+ const game_driver *driver;
+ float width, maxwidth;
+ float x1, y1, x2, y2;
+ char tempbuf[4][256];
+ rgb_t color;
+ int line;
+
+ /* display the current typeahead */
+ if (select_game_buffer[0] != 0)
+ sprintf(&tempbuf[0][0], "Type name or select: %s_", select_game_buffer);
+ else
+ sprintf(&tempbuf[0][0], "Type name or select: (random)");
+
+ /* get the size of the text */
+ ui_draw_text_full(&tempbuf[0][0], 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, NULL);
+ width += 2 * UI_BOX_LR_BORDER;
+ maxwidth = MAX(width, origx2 - origx1);
+
+ /* compute our bounds */
+ x1 = 0.5f - 0.5f * maxwidth;
+ x2 = x1 + maxwidth;
+ y1 = origy1 - extra->top;
+ y2 = origy1 - UI_BOX_TB_BORDER;
+
+ /* draw a box */
+ ui_draw_outlined_box(x1, y1, x2, y2, UI_FILLCOLOR);
+
+ /* take off the borders */
+ x1 += UI_BOX_LR_BORDER;
+ x2 -= UI_BOX_LR_BORDER;
+ y1 += UI_BOX_TB_BORDER;
+ y2 -= UI_BOX_TB_BORDER;
+
+ /* draw the text within it */
+ ui_draw_text_full(&tempbuf[0][0], x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NORMAL, ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+
+ /* determine the text to render below */
+ driver = extra->param;
+ if (driver != NULL)
+ {
+ const char *gfxstat, *soundstat;
+
+ /* first line is game name */
+ sprintf(&tempbuf[0][0], "%-.100s", driver->description);
+
+ /* next line is year, manufacturer */
+ sprintf(&tempbuf[1][0], "%s, %-.100s", driver->year, driver->manufacturer);
+
+ /* next line is overall driver status */
+ if (driver->flags & GAME_NOT_WORKING)
+ strcpy(&tempbuf[2][0], "Overall: NOT WORKING");
+ else if (driver->flags & GAME_UNEMULATED_PROTECTION)
+ strcpy(&tempbuf[2][0], "Overall: Unemulated Protection");
+ else
+ strcpy(&tempbuf[2][0], "Overall: Working");
+
+ /* next line is graphics, sound status */
+ if (driver->flags & (GAME_IMPERFECT_GRAPHICS | GAME_WRONG_COLORS | GAME_IMPERFECT_COLORS))
+ gfxstat = "Imperfect";
+ else
+ gfxstat = "OK";
+
+ if (driver->flags & GAME_NO_SOUND)
+ soundstat = "Unimplemented";
+ else if (driver->flags & GAME_IMPERFECT_SOUND)
+ soundstat = "Imperfect";
+ else
+ soundstat = "OK";
+
+ sprintf(&tempbuf[3][0], "Gfx: %s, Sound: %s", gfxstat, soundstat);
+ }
+ else
+ {
+ int line = 0;
+ int col = 0;
+ const char *s = COPYRIGHT;
+
+ /* first line is version string */
+ sprintf(&tempbuf[line++][0], "%s %s", APPLONGNAME, build_version);
+
+ /* output message */
+ while(line < ARRAY_LENGTH(tempbuf))
+ {
+ if ((*s == '\0') || (*s == '\n'))
+ {
+ tempbuf[line++][col] = '\0';
+ col = 0;
+ }
+ else
+ {
+ tempbuf[line][col++] = *s;
+ }
+
+ if (*s != '\0')
+ s++;
+ }
+ }
+
+ /* get the size of the text */
+ maxwidth = origx2 - origx1;
+ for (line = 0; line < 4; line++)
+ {
+ ui_draw_text_full(&tempbuf[line][0], 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, NULL);
+ width += 2 * UI_BOX_LR_BORDER;
+ maxwidth = MAX(maxwidth, width);
+ }
+
+ /* compute our bounds */
+ x1 = 0.5f - 0.5f * maxwidth;
+ x2 = x1 + maxwidth;
+ y1 = origy2 + UI_BOX_TB_BORDER;
+ y2 = origy2 + extra->bottom;
+
+ /* draw a box */
+ color = UI_FILLCOLOR;
+ if (driver != NULL && (driver->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION)) != 0)
+ color = UI_REDCOLOR;
+ ui_draw_outlined_box(x1, y1, x2, y2, color);
+
+ /* take off the borders */
+ x1 += UI_BOX_LR_BORDER;
+ x2 -= UI_BOX_LR_BORDER;
+ y1 += UI_BOX_TB_BORDER;
+ y2 -= UI_BOX_TB_BORDER;
+
+ /* draw all lines */
+ for (line = 0; line < 4; line++)
+ {
+ ui_draw_text_full(&tempbuf[line][0], x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NORMAL, ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+ y1 += ui_get_line_height();
+ }
+}
+
+
+/*-------------------------------------------------
+ select_game_handle_key - handle a keypress
+-------------------------------------------------*/
+
+static int select_game_handle_key(input_code keycode, char value)
+{
+ /* is this key pressed? */
+ if (input_code_pressed_once(keycode))
+ {
+ int buflen = strlen(select_game_buffer);
+
+ /* if it's a backspace and we can handle it, do so */
+ if (value == 8)
+ {
+ if (buflen > 0)
+ {
+ select_game_buffer[buflen - 1] = 0;
+ return TRUE;
+ }
+ }
+
+ /* if it's any other key and we're not maxed out, update */
+ else if (buflen < ARRAY_LENGTH(select_game_buffer) - 1)
+ {
+ select_game_buffer[buflen] = value;
+ select_game_buffer[buflen + 1] = 0;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
diff --git a/src/emu/uimenu.h b/src/emu/uimenu.h
new file mode 100644
index 00000000000..3484ed42693
--- /dev/null
+++ b/src/emu/uimenu.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+
+ uimenu.h
+
+ Internal MAME menus for the user interface.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __UIMENU_H__
+#define __UIMENU_H__
+
+#include "mamecore.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* flags for menu items */
+#define MENU_FLAG_LEFT_ARROW (1 << 0)
+#define MENU_FLAG_RIGHT_ARROW (1 << 1)
+#define MENU_FLAG_INVERT (1 << 2)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef UINT32 (*ui_menu_handler)(UINT32 state);
+
+typedef struct _ui_menu_item ui_menu_item;
+struct _ui_menu_item
+{
+ const char *text;
+ const char *subtext;
+ UINT32 flags;
+ void *ref;
+};
+
+
+typedef struct _menu_extra menu_extra;
+struct _menu_extra
+{
+ float top; /* amount of extra height to add at the top */
+ float bottom; /* amount of extra height to add at the bottom*/
+ void (*render)(const menu_extra *extra, float x, float y, float x2, float y2);
+ void * param; /* parameter to pass through */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* initialization */
+void ui_menu_init(running_machine *machine);
+
+/* draw a menu, returning the number of visible items */
+int ui_menu_draw(const ui_menu_item *items, int numitems, int selected, const menu_extra *extra);
+
+/* master handler */
+UINT32 ui_menu_ui_handler(UINT32 state);
+
+/* menu keyboard handling */
+int ui_menu_generic_keys(UINT32 *selected, int num_items, int visible_items);
+
+/* menu stack management */
+void ui_menu_stack_reset(void);
+UINT32 ui_menu_stack_push(ui_menu_handler new_handler, UINT32 new_state);
+UINT32 ui_menu_stack_pop(void);
+
+/* force game select menu */
+void ui_menu_force_game_select(void);
+int ui_menu_is_force_game_select(void);
+
+
+#endif /* __UIMENU_H__ */
diff --git a/src/emu/uismall.png b/src/emu/uismall.png
new file mode 100644
index 00000000000..5d391640f62
--- /dev/null
+++ b/src/emu/uismall.png
Binary files differ
diff --git a/src/emu/uitext.c b/src/emu/uitext.c
new file mode 100644
index 00000000000..e3fa967cf69
--- /dev/null
+++ b/src/emu/uitext.c
@@ -0,0 +1,356 @@
+/*********************************************************************
+
+ uitext.c
+
+ Functions used to retrieve text used by MAME, to aid in
+ translation.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "uitext.h"
+
+#ifdef MESS
+extern const char *mess_default_text[];
+#endif /* MESS */
+
+
+lang_struct lang;
+
+/* All entries in this table must match the enum ordering in "uitext.h" */
+static const char *mame_default_text[] =
+{
+ APPNAME,
+ /* copyright stuff */
+ "Usage of emulators in conjunction with ROMs you don't own is forbidden by copyright law.",
+ "IF YOU ARE NOT LEGALLY ENTITLED TO PLAY \"%s\" ON THIS EMULATOR, PRESS ESC.",
+ "Otherwise, type OK or move the joystick left then right to continue",
+
+ /* misc stuff */
+ "Return to Main Menu",
+ "Return to Prior Menu",
+ "Press Any Key",
+ "On",
+ "Off",
+ "NA",
+ "OK",
+ "INVALID",
+ "(none)",
+ "CPU",
+ "Address",
+ "Value",
+ "Sound",
+ "sound",
+ "stereo",
+ "Vector Game",
+ "Screen Resolution",
+ "Text",
+ "Volume",
+ "Relative",
+ "ALL CHANNELS",
+ "Brightness",
+ "Contrast",
+ "Gamma",
+ "Vector Flicker",
+ "Overclock",
+ "ALL CPUS",
+ HISTORYNAME " not available",
+
+ /* special characters */
+ "\xc2\xab",
+ "\xc2\xbb",
+ "(more)",
+ "(more)",
+ "",
+ "",
+
+ /* known problems */
+ "There are known problems with this " GAMENOUN,
+ "The colors aren't 100% accurate.",
+ "The colors are completely wrong.",
+ "The video emulation isn't 100% accurate.",
+ "The sound emulation isn't 100% accurate.",
+ "The game lacks sound.",
+ "Screen flipping in cocktail mode is not supported.",
+ "THIS " CAPGAMENOUN " DOESN'T WORK. You won't be able to make it work correctly. Don't bother.",
+ "The game has protection which isn't fully emulated.",
+ "There are working clones of this game. They are:",
+ "One or more ROMs/CHDs for this game are incorrect. The " GAMENOUN " may not run correctly.",
+ "Type OK or move the joystick left then right to continue",
+
+ /* main menu */
+ "Input (general)",
+ "Dip Switches",
+ "Analog Controls",
+ "Calibrate Joysticks",
+ "Bookkeeping Info",
+
+ "Input (this " CAPSTARTGAMENOUN")",
+ CAPSTARTGAMENOUN " Information",
+ CAPSTARTGAMENOUN " History",
+ "Reset " CAPSTARTGAMENOUN,
+ "Select New " CAPSTARTGAMENOUN,
+ "Return to " CAPSTARTGAMENOUN,
+ "Exit",
+
+ "Cheat",
+ "Memory Card",
+
+ /* input */
+ "Digital Speed",
+ "Autocenter Speed",
+ "Reverse",
+ "Sensitivity",
+
+ /* input groups */
+ "User Interface",
+ "Player 1 Controls",
+ "Player 2 Controls",
+ "Player 3 Controls",
+ "Player 4 Controls",
+ "Player 5 Controls",
+ "Player 6 Controls",
+ "Player 7 Controls",
+ "Player 8 Controls",
+ "Other Controls",
+ "Return to Groups",
+
+ /* stats */
+ "Uptime",
+ "Tickets dispensed",
+ "Coin",
+ "(locked)",
+
+ /* memory card */
+ "Card Number:",
+ "Load Selected Card",
+ "Eject Current Card",
+ "Create New Card",
+ "Error loading memory card",
+ "Memory card loaded",
+ "Memory card ejected",
+ "Memory card created",
+ "Error creating memory card",
+ "(Card may already exist)",
+
+ /* cheats */
+ "Enable/Disable a Cheat",
+ "Add/Edit a Cheat",
+ "Start a New Cheat Search",
+ "Continue Search",
+ "View Last Results",
+ "Restore Previous Results",
+ "Configure Watchpoints",
+ "General Help",
+ "Options",
+ "Reload Database",
+ "Watchpoint",
+ "Disabled",
+ "Cheats",
+ "Watchpoints",
+ "More Info",
+ "More Info for",
+ "Name",
+ "Description",
+ "Activation Key",
+ "Code",
+ "Max",
+ "Set",
+ "Cheat conflict found: disabling",
+ "Help not available yet",
+
+ /* watchpoints */
+ "Number of bytes",
+ "Display Type",
+ "Label Type",
+ "Label",
+ "X Position",
+ "Y Position",
+ "Watch",
+
+ "Hex",
+ "Decimal",
+ "Binary",
+
+ /* searching */
+ "Lives (or another value)",
+ "Timers (+/- some value)",
+ "Energy (greater or less)",
+ "Status (bits or flags)",
+ "Slow But Sure (changed or not)",
+ "Default Search Speed",
+ "Fast",
+ "Medium",
+ "Slow",
+ "Very Slow",
+ "All Memory",
+ "Select Memory Areas",
+ "Matches found",
+ "Search not initialized",
+ "No previous values saved",
+ "Previous values already restored",
+ "Restoration successful",
+ "Select a value",
+ "All values saved",
+ "One match found - added to list",
+
+ /* refresh rate */
+ "Refresh rate",
+ "Decoding Graphics",
+
+ "Video Options",
+ "Screen #",
+ "Rotate Clockwise",
+ "Rotate Counter-clockwise",
+ "Flip X",
+ "Flip Y",
+
+ "Driver Configuration",
+
+ NULL
+};
+
+
+
+static const char **default_text[] =
+{
+ mame_default_text,
+#ifdef MESS
+ mess_default_text,
+#endif /* MESS */
+ NULL
+};
+
+
+
+static const char **trans_text;
+
+
+int uistring_init (mame_file *langfile)
+{
+ /*
+ TODO: This routine needs to do several things:
+ - load an external font if needed
+ - determine the number of characters in the font
+ - deal with multibyte languages
+
+ */
+
+ int i, j, str;
+ char curline[255];
+ char section[255] = "\0";
+ char *ptr;
+ int string_count;
+
+ /* count the total amount of strings */
+ string_count = 0;
+ for (i = 0; default_text[i]; i++)
+ {
+ for (j = 0; default_text[i][j]; j++)
+ string_count++;
+ }
+
+ /* allocate the translated text array, and set defaults */
+ trans_text = auto_malloc(sizeof(const char *) * string_count);
+
+ /* copy in references to all of the strings */
+ str = 0;
+ for (i = 0; default_text[i]; i++)
+ {
+ for (j = 0; default_text[i][j]; j++)
+ trans_text[str++] = default_text[i][j];
+ }
+
+ memset(&lang, 0, sizeof(lang));
+
+ /* if no language file, exit */
+ if (!langfile)
+ return 0;
+
+ while (mame_fgets (curline, sizeof(curline) / sizeof(curline[0]), langfile) != NULL)
+ {
+ /* Ignore commented and blank lines */
+ if (curline[0] == ';') continue;
+ if (curline[0] == '\n') continue;
+ if (curline[0] == '\r') continue;
+
+ if (curline[0] == '[')
+ {
+ ptr = strtok (&curline[1], "]");
+ /* Found a section, indicate as such */
+ strcpy (section, ptr);
+
+ /* Skip to the next line */
+ continue;
+ }
+
+ /* Parse the LangInfo section */
+ if (strcmp (section, "LangInfo") == 0)
+ {
+ ptr = strtok (curline, "=");
+ if (strcmp (ptr, "Version") == 0)
+ {
+ ptr = strtok (NULL, "\n\r");
+ sscanf (ptr, "%d", &lang.version);
+ }
+ else if (strcmp (ptr, "Language") == 0)
+ {
+ ptr = strtok (NULL, "\n\r");
+ strcpy (lang.langname, ptr);
+ }
+ else if (strcmp (ptr, "Author") == 0)
+ {
+ ptr = strtok (NULL, "\n\r");
+ strcpy (lang.author, ptr);
+ }
+ else if (strcmp (ptr, "Font") == 0)
+ {
+ ptr = strtok (NULL, "\n\r");
+ strcpy (lang.fontname, ptr);
+ }
+ }
+
+ /* Parse the Strings section */
+ if (strcmp (section, "Strings") == 0)
+ {
+ /* Get all text up to the first line ending */
+ ptr = strtok (curline, "\n\r");
+
+ /* Find a matching default string */
+ str = 0;
+ for (i = 0; default_text[i]; i++)
+ {
+ for (j = 0; default_text[i][j]; j++)
+ {
+ if (strcmp (curline, default_text[i][j]) == 0)
+ {
+ char transline[255];
+
+ /* Found a match, read next line as the translation */
+ mame_fgets (transline, 255, langfile);
+
+ /* Get all text up to the first line ending */
+ ptr = strtok (transline, "\n\r");
+
+ /* Allocate storage and copy the string */
+ trans_text[str] = auto_strdup(transline);
+ }
+ str++;
+ }
+ }
+ }
+ }
+
+ /* indicate success */
+ return 0;
+}
+
+
+
+const char * ui_getstring (int string_num)
+{
+ return trans_text[string_num];
+}
diff --git a/src/emu/uitext.h b/src/emu/uitext.h
new file mode 100644
index 00000000000..4d37c6d6427
--- /dev/null
+++ b/src/emu/uitext.h
@@ -0,0 +1,233 @@
+/***************************************************************************
+
+ uitext.h
+
+ Functions used to retrieve text used by MAME, to aid in
+ translation.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __uitext_H__
+#define __uitext_H__
+
+#include "mamecore.h"
+
+/* Important: this must match the default_text list in uitext.c! */
+enum
+{
+ UI_mame = 0,
+
+ /* copyright stuff */
+ UI_copyright1,
+ UI_copyright2,
+ UI_copyright3,
+
+ /* misc menu stuff */
+ UI_returntomain,
+ UI_returntoprior,
+ UI_anykey,
+ UI_on,
+ UI_off,
+ UI_NA,
+ UI_OK,
+ UI_INVALID,
+ UI_none,
+ UI_cpu,
+ UI_address,
+ UI_value,
+ UI_sound,
+ UI_sound_lc, /* lower-case version */
+ UI_stereo,
+ UI_vectorgame,
+ UI_screenres,
+ uitext,
+ UI_volume,
+ UI_relative,
+ UI_allchannels,
+ UI_brightness,
+ UI_contrast,
+ UI_gamma,
+ UI_vectorflicker,
+ UI_overclock,
+ UI_allcpus,
+ UI_historymissing,
+
+ /* special characters */
+ UI_leftarrow,
+ UI_rightarrow,
+ UI_uparrow,
+ UI_downarrow,
+ UI_lefthilight,
+ UI_righthilight,
+
+ /* warnings */
+ UI_knownproblems,
+ UI_imperfectcolors,
+ UI_wrongcolors,
+ UI_imperfectgraphics,
+ UI_imperfectsound,
+ UI_nosound,
+ UI_nococktail,
+ UI_brokengame,
+ UI_brokenprotection,
+ UI_workingclones,
+ UI_incorrectroms,
+ UI_typeok,
+
+ /* main menu */
+ UI_inputgeneral,
+ UI_dipswitches,
+ UI_analogcontrols,
+ UI_calibrate,
+ UI_bookkeeping,
+ UI_inputspecific,
+ UI_gameinfo,
+ UI_history,
+ UI_resetgame,
+ UI_selectgame,
+ UI_returntogame,
+ UI_exit,
+ UI_cheat,
+ UI_memorycard,
+
+ /* input stuff */
+ UI_keyjoyspeed,
+ UI_centerspeed,
+ UI_reverse,
+ UI_sensitivity,
+
+ /* input groups */
+ UI_uigroup,
+ UI_p1group,
+ UI_p2group,
+ UI_p3group,
+ UI_p4group,
+ UI_p5group,
+ UI_p6group,
+ UI_p7group,
+ UI_p8group,
+ UI_othergroup,
+ UI_returntogroup,
+
+ /* stats */
+ UI_totaltime,
+ UI_tickets,
+ UI_coin,
+ UI_locked,
+
+ /* memory card */
+ UI_selectcard,
+ UI_loadcard,
+ UI_ejectcard,
+ UI_createcard,
+ UI_loadfailed,
+ UI_loadok,
+ UI_cardejected,
+ UI_cardcreated,
+ UI_cardcreatedfailed,
+ UI_cardcreatedfailed2,
+
+ /* cheat stuff */
+ UI_enablecheat,
+ UI_addeditcheat,
+ UI_startcheat,
+ UI_continuesearch,
+ UI_viewresults,
+ UI_restoreresults,
+ UI_memorywatch,
+ UI_generalhelp,
+ UI_options,
+ UI_reloaddatabase,
+ UI_watchpoint,
+ UI_disabled,
+ UI_cheats,
+ UI_watchpoints,
+ UI_moreinfo,
+ UI_moreinfoheader,
+ UI_cheatname,
+ UI_cheatdescription,
+ UI_cheatactivationkey,
+ UI_code,
+ UI_max,
+ UI_set,
+ UI_conflict_found,
+ UI_no_help_available,
+
+ /* watchpoint stuff */
+ UI_watchlength,
+ UI_watchdisplaytype,
+ UI_watchlabeltype,
+ UI_watchlabel,
+ UI_watchx,
+ UI_watchy,
+ UI_watch,
+
+ UI_hex,
+ UI_decimal,
+ UI_binary,
+
+ /* search stuff */
+ UI_search_lives,
+ UI_search_timers,
+ UI_search_energy,
+ UI_search_status,
+ UI_search_slow,
+ UI_search_speed,
+ UI_search_speed_fast,
+ UI_search_speed_medium,
+ UI_search_speed_slow,
+ UI_search_speed_veryslow,
+ UI_search_speed_allmemory,
+ UI_search_select_memory_areas,
+ UI_search_matches_found,
+ UI_search_noinit,
+ UI_search_nosave,
+ UI_search_done,
+ UI_search_OK,
+ UI_search_select_value,
+ UI_search_all_values_saved,
+ UI_search_one_match_found_added,
+
+ /* refresh rate */
+ UI_refresh_rate,
+ UI_decoding_gfx,
+
+ UI_video,
+ UI_screen,
+ UI_rotate_clockwise,
+ UI_rotate_counterclockwise,
+ UI_flip_x,
+ UI_flip_y,
+
+ UI_configuration,
+
+ UI_last_mame_entry
+};
+
+#ifdef MESS
+#include "muitext.h"
+#endif
+
+struct _lang_struct
+{
+ int version;
+ int multibyte; /* UNUSED: 1 if this is a multibyte font/language */
+ UINT8 *fontdata; /* pointer to the raw font data to be decoded */
+ UINT16 fontglyphs; /* total number of glyps in the external font - 1 */
+ char langname[255];
+ char fontname[255];
+ char author[255];
+};
+typedef struct _lang_struct lang_struct;
+
+int uistring_init (mame_file *language_file);
+
+const char * ui_getstring (int string_num);
+
+#endif /* __uitext_H__ */
+
diff --git a/src/emu/validity.c b/src/emu/validity.c
new file mode 100644
index 00000000000..6bfaf303c31
--- /dev/null
+++ b/src/emu/validity.c
@@ -0,0 +1,1449 @@
+/***************************************************************************
+
+ validity.c
+
+ Validity checks on internal data structures.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "osdepend.h"
+#include "eminline.h"
+#include "driver.h"
+#include "hash.h"
+#include <ctype.h>
+#include <stdarg.h>
+#include "uitext.h"
+#include "unicode.h"
+#include <zlib.h>
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define REPORT_TIMES (0)
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define QUARK_HASH_SIZE 389
+
+
+
+/*************************************
+ *
+ * Type definitions
+ *
+ *************************************/
+
+typedef struct _quark_entry quark_entry;
+struct _quark_entry
+{
+ UINT32 crc;
+ struct _quark_entry *next;
+};
+
+
+typedef struct _quark_table quark_table;
+struct _quark_table
+{
+ UINT32 entries;
+ UINT32 hashsize;
+ quark_entry *entry;
+ quark_entry **hash;
+};
+
+
+
+/*************************************
+ *
+ * Local variables
+ *
+ *************************************/
+
+static quark_table *source_table;
+static quark_table *name_table;
+static quark_table *description_table;
+static quark_table *roms_table;
+static quark_table *inputs_table;
+static quark_table *defstr_table;
+
+
+
+/*************************************
+ *
+ * Allocate an array of quark
+ * entries and a hash table
+ *
+ *************************************/
+
+static quark_table *allocate_quark_table(UINT32 entries, UINT32 hashsize)
+{
+ quark_table *table;
+ UINT32 total_bytes;
+
+ /* determine how many total bytes we need */
+ total_bytes = sizeof(*table) + entries * sizeof(table->entry[0]) + hashsize * sizeof(table->hash[0]);
+ table = auto_malloc(total_bytes);
+
+ /* fill in the details */
+ table->entries = entries;
+ table->hashsize = hashsize;
+
+ /* compute the pointers */
+ table->entry = (quark_entry *)((UINT8 *)table + sizeof(*table));
+ table->hash = (quark_entry **)((UINT8 *)table->entry + entries * sizeof(table->entry[0]));
+
+ /* reset the hash table */
+ memset(table->hash, 0, hashsize * sizeof(table->hash[0]));
+ return table;
+}
+
+
+
+/*************************************
+ *
+ * Compute the CRC of a string
+ *
+ *************************************/
+
+INLINE UINT32 quark_string_crc(const char *string)
+{
+ return crc32(0, (UINT8 *)string, (UINT32)strlen(string));
+}
+
+
+
+/*************************************
+ *
+ * Add a quark to the table and
+ * connect it to the hash tables
+ *
+ *************************************/
+
+INLINE void add_quark(quark_table *table, int index, UINT32 crc)
+{
+ quark_entry *entry = &table->entry[index];
+ int hash = crc % table->hashsize;
+ entry->crc = crc;
+ entry->next = table->hash[hash];
+ table->hash[hash] = entry;
+}
+
+
+
+/*************************************
+ *
+ * Return a pointer to the first
+ * hash entry connected to a CRC
+ *
+ *************************************/
+
+INLINE quark_entry *first_hash_entry(quark_table *table, UINT32 crc)
+{
+ return table->hash[crc % table->hashsize];
+}
+
+
+
+/*************************************
+ *
+ * Build "quarks" for fast string
+ * operations
+ *
+ *************************************/
+
+static void build_quarks(void)
+{
+ int drivnum, strnum;
+
+ /* first count drivers */
+ for (drivnum = 0; drivers[drivnum]; drivnum++)
+ ;
+
+ /* allocate memory for the quark tables */
+ source_table = allocate_quark_table(drivnum, QUARK_HASH_SIZE);
+ name_table = allocate_quark_table(drivnum, QUARK_HASH_SIZE);
+ description_table = allocate_quark_table(drivnum, QUARK_HASH_SIZE);
+ roms_table = allocate_quark_table(drivnum, QUARK_HASH_SIZE);
+ inputs_table = allocate_quark_table(drivnum, QUARK_HASH_SIZE);
+
+ /* build the quarks and the hash tables */
+ for (drivnum = 0; drivers[drivnum]; drivnum++)
+ {
+ const game_driver *driver = drivers[drivnum];
+
+ /* fill in the quark with hashes of the strings */
+ add_quark(source_table, drivnum, quark_string_crc(driver->source_file));
+ add_quark(name_table, drivnum, quark_string_crc(driver->name));
+ add_quark(description_table, drivnum, quark_string_crc(driver->description));
+
+ /* only track actual driver ROM entries */
+ if (driver->rom && (driver->flags & GAME_NO_STANDALONE) == 0)
+ add_quark(roms_table, drivnum, (FPTR)driver->rom);
+ }
+
+ /* allocate memory for a quark table of strings */
+ defstr_table = allocate_quark_table(INPUT_STRING_COUNT, 97);
+
+ /* add all the default strings */
+ for (strnum = 1; strnum < INPUT_STRING_COUNT; strnum++)
+ {
+ const char *string = input_port_string_from_token(INPUT_PORT_UINT32(strnum));
+ if (string != NULL)
+ add_quark(defstr_table, strnum, quark_string_crc(string));
+ }
+}
+
+
+
+/*************************************
+ *
+ * Validate inline functions
+ *
+ *************************************/
+
+static int validate_inlines(void)
+{
+#undef rand
+ UINT64 testu64a = rand() + (rand() << 15) + ((UINT64)rand() << 30) + ((UINT64)rand() << 45) + 1;
+ INT64 testi64a = rand() + (rand() << 15) + ((INT64)rand() << 30) + ((INT64)rand() << 45) + 1;
+#ifdef PTR64
+ INT64 testi64b = rand() + (rand() << 15) + ((INT64)rand() << 30) + ((INT64)rand() << 45) + 1;
+#endif
+ UINT32 testu32a = rand() + (rand() << 15) + 1;
+ UINT32 testu32b = rand() + (rand() << 15) + 1;
+ INT32 testi32a = rand() + (rand() << 15) + 1;
+ INT32 testi32b = rand() + (rand() << 15) + 1;
+ INT32 resulti32, expectedi32;
+ UINT32 resultu32, expectedu32;
+ INT64 resulti64, expectedi64;
+ UINT64 resultu64, expectedu64;
+ INT32 remainder, expremainder;
+ UINT32 uremainder, expuremainder;
+ int error = FALSE;
+
+ resulti64 = mul_32x32(testi32a, testi32b);
+ expectedi64 = (INT64)testi32a * (INT64)testi32b;
+ if (resulti64 != expectedi64)
+ { mame_printf_error("Error testing mul_32x32 (%08X x %08X) = %08X%08X (expected %08X%08X)\n", testi32a, testi32b, (UINT32)(resulti64 >> 32), (UINT32)resulti64, (UINT32)(expectedi64 >> 32), (UINT32)expectedi64); error = TRUE; }
+
+ resultu64 = mulu_32x32(testu32a, testu32b);
+ expectedu64 = (UINT64)testu32a * (UINT64)testu32b;
+ if (resultu64 != expectedu64)
+ { mame_printf_error("Error testing mulu_32x32 (%08X x %08X) = %08X%08X (expected %08X%08X)\n", testu32a, testu32b, (UINT32)(resultu64 >> 32), (UINT32)resultu64, (UINT32)(expectedu64 >> 32), (UINT32)expectedu64); error = TRUE; }
+
+ resulti32 = mul_32x32_hi(testi32a, testi32b);
+ expectedi32 = ((INT64)testi32a * (INT64)testi32b) >> 32;
+ if (resulti32 != expectedi32)
+ { mame_printf_error("Error testing mul_32x32_hi (%08X x %08X) = %08X (expected %08X)\n", testi32a, testi32b, resulti32, expectedi32); error = TRUE; }
+
+ resultu32 = mulu_32x32_hi(testu32a, testu32b);
+ expectedu32 = ((INT64)testu32a * (INT64)testu32b) >> 32;
+ if (resultu32 != expectedu32)
+ { mame_printf_error("Error testing mulu_32x32_hi (%08X x %08X) = %08X (expected %08X)\n", testu32a, testu32b, resultu32, expectedu32); error = TRUE; }
+
+ resulti32 = mul_32x32_shift(testi32a, testi32b, 7);
+ expectedi32 = ((INT64)testi32a * (INT64)testi32b) >> 7;
+ if (resulti32 != expectedi32)
+ { mame_printf_error("Error testing mul_32x32_shift (%08X x %08X) >> 7 = %08X (expected %08X)\n", testi32a, testi32b, resulti32, expectedi32); error = TRUE; }
+
+ resultu32 = mulu_32x32_shift(testu32a, testu32b, 7);
+ expectedu32 = ((INT64)testu32a * (INT64)testu32b) >> 7;
+ if (resultu32 != expectedu32)
+ { mame_printf_error("Error testing mulu_32x32_shift (%08X x %08X) >> 7 = %08X (expected %08X)\n", testu32a, testu32b, resultu32, expectedu32); error = TRUE; }
+
+ while ((INT64)testi32a * (INT64)0x7fffffff < testi64a)
+ testi64a /= 2;
+ while ((UINT64)testu32a * (UINT64)0xffffffff < testu64a)
+ testu64a /= 2;
+
+ resulti32 = div_64x32(testi64a, testi32a);
+ expectedi32 = testi64a / (INT64)testi32a;
+ if (resulti32 != expectedi32)
+ { mame_printf_error("Error testing div_64x32 (%08X%08X / %08X) = %08X (expected %08X)\n", (UINT32)(testi64a >> 32), (UINT32)testi64a, testi32a, resulti32, expectedi32); error = TRUE; }
+
+ resultu32 = divu_64x32(testu64a, testu32a);
+ expectedu32 = testu64a / (UINT64)testu32a;
+ if (resultu32 != expectedu32)
+ { mame_printf_error("Error testing divu_64x32 (%08X%08X / %08X) = %08X (expected %08X)\n", (UINT32)(testu64a >> 32), (UINT32)testu64a, testu32a, resultu32, expectedu32); error = TRUE; }
+
+ resulti32 = div_64x32_rem(testi64a, testi32a, &remainder);
+ expectedi32 = testi64a / (INT64)testi32a;
+ expremainder = testi64a % (INT64)testi32a;
+ if (resulti32 != expectedi32 || remainder != expremainder)
+ { mame_printf_error("Error testing div_64x32_rem (%08X%08X / %08X) = %08X,%08X (expected %08X,%08X)\n", (UINT32)(testi64a >> 32), (UINT32)testi64a, testi32a, resulti32, remainder, expectedi32, expremainder); error = TRUE; }
+
+ resultu32 = divu_64x32_rem(testu64a, testu32a, &uremainder);
+ expectedu32 = testu64a / (UINT64)testu32a;
+ expuremainder = testu64a % (UINT64)testu32a;
+ if (resultu32 != expectedu32 || uremainder != expuremainder)
+ { mame_printf_error("Error testing divu_64x32_rem (%08X%08X / %08X) = %08X,%08X (expected %08X,%08X)\n", (UINT32)(testu64a >> 32), (UINT32)testu64a, testu32a, resultu32, uremainder, expectedu32, expuremainder); error = TRUE; }
+
+ resulti32 = mod_64x32(testi64a, testi32a);
+ expectedi32 = testi64a % (INT64)testi32a;
+ if (resulti32 != expectedi32)
+ { mame_printf_error("Error testing mod_64x32 (%08X%08X / %08X) = %08X (expected %08X)\n", (UINT32)(testi64a >> 32), (UINT32)testi64a, testi32a, resulti32, expectedi32); error = TRUE; }
+
+ resultu32 = modu_64x32(testu64a, testu32a);
+ expectedu32 = testu64a % (UINT64)testu32a;
+ if (resultu32 != expectedu32)
+ { mame_printf_error("Error testing modu_64x32 (%08X%08X / %08X) = %08X (expected %08X)\n", (UINT32)(testu64a >> 32), (UINT32)testu64a, testu32a, resultu32, expectedu32); error = TRUE; }
+
+ while ((INT64)testi32a * (INT64)0x7fffffff < ((INT32)testi64a << 3))
+ testi64a /= 2;
+ while ((UINT64)testu32a * (UINT64)0xffffffff < ((UINT32)testu64a << 3))
+ testu64a /= 2;
+
+ resulti32 = div_32x32_shift((INT32)testi64a, testi32a, 3);
+ expectedi32 = ((INT64)(INT32)testi64a << 3) / (INT64)testi32a;
+ if (resulti32 != expectedi32)
+ { mame_printf_error("Error testing div_32x32_shift (%08X << 3) / %08X = %08X (expected %08X)\n", (INT32)testi64a, testi32a, resulti32, expectedi32); error = TRUE; }
+
+ resultu32 = divu_32x32_shift((UINT32)testu64a, testu32a, 3);
+ expectedu32 = ((UINT64)(UINT32)testu64a << 3) / (UINT64)testu32a;
+ if (resultu32 != expectedu32)
+ { mame_printf_error("Error testing divu_32x32_shift (%08X << 3) / %08X = %08X (expected %08X)\n", (UINT32)testu64a, testu32a, resultu32, expectedu32); error = TRUE; }
+
+ if (fabs(recip_approx(100.0) - 0.01) > 0.0001)
+ { mame_printf_error("Error testing recip_approx\n"); error = TRUE; }
+
+ testi32a = (testi32a & 0x0000ffff) | 0x400000;
+ if (count_leading_zeros(testi32a) != 9)
+ { mame_printf_error("Error testing count_leading_zeros\n"); error = TRUE; }
+ testi32a = (testi32a | 0xffff0000) & ~0x400000;
+ if (count_leading_ones(testi32a) != 9)
+ { mame_printf_error("Error testing count_leading_ones\n"); error = TRUE; }
+
+ testi32b = testi32a;
+ if (compare_exchange32(&testi32a, testi32b, 1000) != testi32b || testi32a != 1000)
+ { mame_printf_error("Error testing compare_exchange32\n"); error = TRUE; }
+#ifdef PTR64
+ testi64b = testi64a;
+ if (compare_exchange64(&testi64a, testi64b, 1000) != testi64b || testi64a != 1000)
+ { mame_printf_error("Error testing compare_exchange64\n"); error = TRUE; }
+#endif
+ if (atomic_exchange32(&testi32a, testi32b) != 1000)
+ { mame_printf_error("Error testing atomic_exchange32\n"); error = TRUE; }
+ if (atomic_add32(&testi32a, 45) != testi32b + 45)
+ { mame_printf_error("Error testing atomic_add32\n"); error = TRUE; }
+ if (atomic_increment32(&testi32a) != testi32b + 46)
+ { mame_printf_error("Error testing atomic_increment32\n"); error = TRUE; }
+ if (atomic_decrement32(&testi32a) != testi32b + 45)
+ { mame_printf_error("Error testing atomic_decrement32\n"); error = TRUE; }
+
+ return error;
+}
+
+
+
+/*************************************
+ *
+ * Validate basic driver info
+ *
+ *************************************/
+
+static int validate_driver(int drivnum, const machine_config *drv)
+{
+ const game_driver *driver = drivers[drivnum];
+ const game_driver *clone_of;
+ quark_entry *entry;
+ int error = FALSE;
+ const char *s;
+ UINT32 crc;
+
+ /* determine the clone */
+ clone_of = driver_get_clone(driver);
+
+ /* if we have at least 100 drivers, validate the clone */
+ /* (100 is arbitrary, but tries to avoid tiny.mak dependencies) */
+ if (driver_list_get_count(drivers) > 100 && !clone_of && strcmp(driver->parent, "0"))
+ {
+ mame_printf_error("%s: %s is a non-existant clone\n", driver->source_file, driver->parent);
+ error = TRUE;
+ }
+
+ /* look for recursive cloning */
+ if (clone_of == driver)
+ {
+ mame_printf_error("%s: %s is set as a clone of itself\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* look for clones that are too deep */
+ if (clone_of != NULL && (clone_of = driver_get_clone(clone_of)) != NULL && (clone_of->flags & GAME_IS_BIOS_ROOT) == 0)
+ {
+ mame_printf_error("%s: %s is a clone of a clone\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* make sure the driver name is 8 chars or less */
+ if (strlen(driver->name) > 8)
+ {
+ mame_printf_error("%s: %s driver name must be 8 characters or less\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* make sure the year is only digits, '?' or '+' */
+ for (s = driver->year; *s; s++)
+ if (!isdigit(*s) && *s != '?' && *s != '+')
+ {
+ mame_printf_error("%s: %s has an invalid year '%s'\n", driver->source_file, driver->name, driver->year);
+ error = TRUE;
+ break;
+ }
+
+#ifndef MESS
+ /* make sure sound-less drivers are flagged */
+ if ((driver->flags & GAME_IS_BIOS_ROOT) == 0 && drv->sound[0].type == SOUND_DUMMY && (driver->flags & GAME_NO_SOUND) == 0 && strcmp(driver->name, "minivadr"))
+ {
+ mame_printf_error("%s: %s missing GAME_NO_SOUND flag\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+#endif
+
+ /* find duplicate driver names */
+ crc = quark_string_crc(driver->name);
+ for (entry = first_hash_entry(name_table, crc); entry; entry = entry->next)
+ if (entry->crc == crc && entry != &name_table->entry[drivnum])
+ {
+ const game_driver *match = drivers[entry - name_table->entry];
+ if (!strcmp(match->name, driver->name))
+ {
+ mame_printf_error("%s: %s is a duplicate name (%s, %s)\n", driver->source_file, driver->name, match->source_file, match->name);
+ error = TRUE;
+ }
+ }
+
+ /* find duplicate descriptions */
+ crc = quark_string_crc(driver->description);
+ for (entry = first_hash_entry(description_table, crc); entry; entry = entry->next)
+ if (entry->crc == crc && entry != &description_table->entry[drivnum])
+ {
+ const game_driver *match = drivers[entry - description_table->entry];
+ if (!strcmp(match->description, driver->description))
+ {
+ mame_printf_error("%s: %s is a duplicate description (%s, %s)\n", driver->source_file, driver->description, match->source_file, match->name);
+ error = TRUE;
+ }
+ }
+
+ /* find shared ROM entries */
+#ifndef MESS
+ if (driver->rom && (driver->flags & GAME_IS_BIOS_ROOT) == 0)
+ {
+ crc = (FPTR)driver->rom;
+ for (entry = first_hash_entry(roms_table, crc); entry; entry = entry->next)
+ if (entry->crc == crc && entry != &roms_table->entry[drivnum])
+ {
+ const game_driver *match = drivers[entry - roms_table->entry];
+ if (match->rom == driver->rom)
+ {
+ mame_printf_error("%s: %s uses the same ROM set as (%s, %s)\n", driver->source_file, driver->description, match->source_file, match->name);
+ error = TRUE;
+ }
+ }
+ }
+#endif /* MESS */
+
+ return error;
+}
+
+
+
+/*************************************
+ *
+ * Validate ROM definitions
+ *
+ *************************************/
+
+static int validate_roms(int drivnum, const machine_config *drv, UINT32 *region_length)
+{
+ const game_driver *driver = drivers[drivnum];
+ const rom_entry *romp;
+ const char *last_name = "???";
+ int cur_region = -1;
+ int error = FALSE;
+ int items_since_region = 1;
+ int bios_flags = 0, last_bios = 0;
+
+ /* reset region info */
+ memset(region_length, 0, REGION_MAX * sizeof(*region_length));
+
+ /* scan the ROM entries */
+ for (romp = driver->rom; romp && !ROMENTRY_ISEND(romp); romp++)
+ {
+ /* if this is a region, make sure it's valid, and record the length */
+ if (ROMENTRY_ISREGION(romp))
+ {
+ int type = ROMREGION_GETTYPE(romp);
+
+ /* if we haven't seen any items since the last region, print a warning */
+ if (items_since_region == 0)
+ mame_printf_warning("%s: %s has empty ROM region (warning)\n", driver->source_file, driver->name);
+ items_since_region = (ROMREGION_ISERASE(romp) || ROMREGION_ISDISPOSE(romp)) ? 1 : 0;
+
+ /* check for an invalid region */
+ if (type >= REGION_MAX || type <= REGION_INVALID)
+ {
+ mame_printf_error("%s: %s has invalid ROM_REGION type %x\n", driver->source_file, driver->name, type);
+ error = TRUE;
+ cur_region = -1;
+ }
+
+ /* check for a duplicate */
+ else if (region_length[type] != 0)
+ {
+ mame_printf_error("%s: %s has duplicate ROM_REGION type %x\n", driver->source_file, driver->name, type);
+ error = TRUE;
+ cur_region = -1;
+ }
+
+ /* if all looks good, remember the length and note the region */
+ else
+ {
+ cur_region = type;
+ region_length[type] = ROMREGION_GETLENGTH(romp);
+ }
+ }
+
+ /* If this is a system bios, make sure it is using the next available bios number */
+ else if (ROMENTRY_ISSYSTEM_BIOS(romp))
+ {
+ bios_flags = ROM_GETBIOSFLAGS(romp);
+ if (last_bios+1 != bios_flags)
+ {
+ const char *name = ROM_GETHASHDATA(romp);
+ mame_printf_error("%s: %s has non-sequential bios %s\n", driver->source_file, driver->name, name);
+ error = TRUE;
+ }
+ last_bios = bios_flags;
+ }
+
+ /* if this is a file, make sure it is properly formatted */
+ else if (ROMENTRY_ISFILE(romp))
+ {
+ const char *hash;
+ const char *s;
+
+ items_since_region++;
+
+ /* track the last filename we found */
+ last_name = ROM_GETNAME(romp);
+
+ /* make sure it's all lowercase */
+ for (s = last_name; *s; s++)
+ if (tolower(*s) != *s)
+ {
+ mame_printf_error("%s: %s has upper case ROM name %s\n", driver->source_file, driver->name, last_name);
+ error = TRUE;
+ break;
+ }
+
+ /* if this is a bios rom, make sure it has the same flags as the last system bios entry */
+ bios_flags = ROM_GETBIOSFLAGS(romp);
+ if (bios_flags != 0)
+ {
+ if (bios_flags != last_bios)
+ {
+ mame_printf_error("%s: %s has bios rom name %s without preceding matching system bios definition\n", driver->source_file, driver->name, last_name);
+ error = TRUE;
+ }
+ }
+
+ /* make sure the has is valid */
+ hash = ROM_GETHASHDATA(romp);
+ if (!hash_verify_string(hash))
+ {
+ mame_printf_error("%s: rom '%s' has an invalid hash string '%s'\n", driver->name, last_name, hash);
+ error = TRUE;
+ }
+ }
+
+ /* for any non-region ending entries, make sure they don't extend past the end */
+ if (!ROMENTRY_ISREGIONEND(romp) && cur_region != -1)
+ {
+ items_since_region++;
+
+ if (ROM_GETOFFSET(romp) + ROM_GETLENGTH(romp) > region_length[cur_region])
+ {
+ mame_printf_error("%s: %s has ROM %s extending past the defined memory region\n", driver->source_file, driver->name, last_name);
+ error = TRUE;
+ }
+ }
+ }
+
+ /* final check for empty regions */
+ if (items_since_region == 0)
+ mame_printf_warning("%s: %s has empty ROM region (warning)\n", driver->source_file, driver->name);
+
+ return error;
+}
+
+
+
+/*************************************
+ *
+ * Validate CPUs and memory maps
+ *
+ *************************************/
+
+static int validate_cpu(int drivnum, const machine_config *drv, const UINT32 *region_length)
+{
+ const game_driver *driver = drivers[drivnum];
+ int error = FALSE;
+ int cpunum;
+
+ /* loop over all the CPUs */
+ for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
+ {
+ extern void dummy_get_info(UINT32 state, cpuinfo *info);
+ const cpu_config *cpu = &drv->cpu[cpunum];
+ int spacenum;
+
+ /* skip empty entries */
+ if (cpu->type == CPU_DUMMY)
+ continue;
+
+ /* checks to see if this driver is using a dummy CPU */
+ if (cputype_get_interface(cpu->type)->get_info == dummy_get_info)
+ {
+ mame_printf_error("%s: %s uses non-present CPU\n", driver->source_file, driver->name);
+ error = TRUE;
+ continue;
+ }
+
+ /* check the CPU for incompleteness */
+ if (!cputype_get_info_fct(cpu->type, CPUINFO_PTR_GET_CONTEXT)
+ || !cputype_get_info_fct(cpu->type, CPUINFO_PTR_SET_CONTEXT)
+ || !cputype_get_info_fct(cpu->type, CPUINFO_PTR_RESET)
+ || !cputype_get_info_fct(cpu->type, CPUINFO_PTR_EXECUTE))
+ {
+ mame_printf_error("%s: %s uses an incomplete CPU\n", driver->source_file, driver->name);
+ error = TRUE;
+ continue;
+ }
+
+ /* loop over all address spaces */
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ {
+#define SPACE_SHIFT(a) ((addr_shift < 0) ? ((a) << -addr_shift) : ((a) >> addr_shift))
+#define SPACE_SHIFT_END(a) ((addr_shift < 0) ? (((a) << -addr_shift) | ((1 << -addr_shift) - 1)) : ((a) >> addr_shift))
+ static const char *spacename[] = { "program", "data", "I/O" };
+ int databus_width = cputype_databus_width(cpu->type, spacenum);
+ int addr_shift = cputype_addrbus_shift(cpu->type, spacenum);
+ int alignunit = databus_width/8;
+ address_map addrmap[MAX_ADDRESS_MAP_SIZE*2];
+ address_map *map;
+ UINT32 flags;
+
+ /* check to see that the same map is not used twice */
+ if (cpu->construct_map[spacenum][0] && cpu->construct_map[spacenum][0] == cpu->construct_map[spacenum][1])
+ {
+ mame_printf_error("%s: %s uses identical memory maps for CPU #%d spacenum %d\n", driver->source_file, driver->name, cpunum, spacenum);
+ error = TRUE;
+ }
+
+ /* reset the address map, resetting the base address to a non-NULL value */
+ /* because the AM_REGION macro will query non-existant memory regions and */
+ /* product valid NULL results */
+ memset(addrmap, 0, sizeof(addrmap));
+
+ /* construct the maps */
+ map = addrmap;
+ construct_address_map(map, drv, cpunum, spacenum);
+
+ /* if this is an empty map, just skip it */
+ if (IS_AMENTRY_END(map))
+ continue;
+
+ /* make sure we start with a proper entry */
+ if (!IS_AMENTRY_EXTENDED(map))
+ {
+ mame_printf_error("%s: %s wrong MEMORY_READ_START for %s space\n", driver->source_file, driver->name, spacename[spacenum]);
+ error = TRUE;
+ }
+
+ /* loop over entries and look for errors */
+ for ( ; !IS_AMENTRY_END(map); map++)
+ if (!IS_AMENTRY_EXTENDED(map))
+ {
+ int ismatchmask = ((map->flags & AM_FLAGS_MATCH_MASK) != 0);
+ UINT32 start = SPACE_SHIFT(map->start);
+ UINT32 end = ismatchmask ? SPACE_SHIFT(map->end) : SPACE_SHIFT_END(map->end);
+
+ {
+ /* look for inverted start/end pairs */
+ if (end < start)
+ {
+ mame_printf_error("%s: %s wrong %s memory read handler start = %08x > end = %08x\n", driver->source_file, driver->name, spacename[spacenum], map->start, map->end);
+ error = TRUE;
+ }
+
+ /* look for misaligned entries */
+ if ((start & (alignunit-1)) != 0 || (end & (alignunit-1)) != (alignunit-1))
+ {
+ mame_printf_error("%s: %s wrong %s memory read handler start = %08x, end = %08x ALIGN = %d\n", driver->source_file, driver->name, spacename[spacenum], map->start, map->end, alignunit);
+ error = TRUE;
+ }
+
+ /* if this is a program space, auto-assign implicit ROM entries */
+ if ((FPTR)map->read.handler == STATIC_ROM && !map->region)
+ {
+ map->region = REGION_CPU1 + cpunum;
+ map->region_offs = map->start;
+ }
+
+ /* if this entry references a memory region, validate it */
+ if (map->region && map->share == 0)
+ {
+ offs_t length = region_length[map->region];
+
+ if (length == 0)
+ {
+ mame_printf_error("%s: %s CPU %d space %d memory map entry %X-%X references non-existant region %d\n", driver->source_file, driver->name, cpunum, spacenum, map->start, map->end, map->region);
+ error = TRUE;
+ }
+ else if (map->region_offs + (end - start + 1) > length)
+ {
+ mame_printf_error("%s: %s CPU %d space %d memory map entry %X-%X extends beyond region %d size (%X)\n", driver->source_file, driver->name, cpunum, spacenum, map->start, map->end, map->region, length);
+ error = TRUE;
+ }
+ }
+
+ /* If this is a match/mask, make sure the match bits are present in the mask */
+ if (ismatchmask && (start & end) != start)
+ {
+ mame_printf_error("%s: %s CPU %d space %d memory map entry match %X contains bits not in mask %X for region %d\n", driver->source_file, driver->name, cpunum, spacenum, map->start, map->end, map->region);
+ error = TRUE;
+ }
+ }
+ }
+ else
+ {
+ flags = AM_EXTENDED_FLAGS(map);
+ if (flags & AMEF_SPECIFIES_SPACE)
+ {
+ int val = (flags & AMEF_SPACE_MASK) >> AMEF_SPACE_SHIFT;
+ if (val != spacenum)
+ {
+ mame_printf_error("%s: %s CPU #%d space %d has address space %d handlers!", driver->source_file, driver->name, cpunum, spacenum, val);
+ error = TRUE;
+ }
+ }
+
+ /* verify the type of memory handlers */
+ if (flags & AMEF_SPECIFIES_DBITS)
+ {
+ int val = (flags & AMEF_DBITS_MASK) >> AMEF_DBITS_SHIFT;
+ val = (val + 1) * 8;
+ if (val != databus_width)
+ {
+ mame_printf_error("%s: %s cpu #%d uses wrong memory handlers for %s space! (width = %d, memory = %08x)\n", driver->source_file, driver->name, cpunum, spacename[spacenum], databus_width, val);
+ error = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
+
+
+/*************************************
+ *
+ * Validate display
+ *
+ *************************************/
+
+static int validate_display(int drivnum, const machine_config *drv)
+{
+ const game_driver *driver = drivers[drivnum];
+ int palette_modes = FALSE;
+ int error = FALSE;
+ int scrnum;
+
+ /* loop over screens */
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ if (drv->screen[scrnum].tag != NULL)
+ {
+ /* sanity check dimensions */
+ if ((drv->screen[scrnum].defstate.width <= 0) || (drv->screen[scrnum].defstate.height <= 0))
+ {
+ mame_printf_error("%s: %s screen %d has invalid display dimensions\n", driver->source_file, driver->name, scrnum);
+ error = TRUE;
+ }
+
+ /* sanity check screen formats */
+ if (drv->screen[scrnum].defstate.format != BITMAP_FORMAT_INDEXED16 &&
+ drv->screen[scrnum].defstate.format != BITMAP_FORMAT_RGB15 &&
+ drv->screen[scrnum].defstate.format != BITMAP_FORMAT_RGB32)
+ {
+ mame_printf_error("%s: %s screen %d has unsupported format\n", driver->source_file, driver->name, scrnum);
+ error = TRUE;
+ }
+ if (drv->screen[scrnum].defstate.format == BITMAP_FORMAT_INDEXED16)
+ palette_modes = TRUE;
+
+ /* sanity check display area */
+ if (!(drv->video_attributes & VIDEO_TYPE_VECTOR))
+ {
+ if ((drv->screen[scrnum].defstate.visarea.max_x < drv->screen[scrnum].defstate.visarea.min_x)
+ || (drv->screen[scrnum].defstate.visarea.max_y < drv->screen[scrnum].defstate.visarea.min_y)
+ || (drv->screen[scrnum].defstate.visarea.max_x >= drv->screen[scrnum].defstate.width)
+ || (drv->screen[scrnum].defstate.visarea.max_y >= drv->screen[scrnum].defstate.height))
+ {
+ mame_printf_error("%s: %s screen %d has an invalid display area\n", driver->source_file, driver->name, scrnum);
+ error = TRUE;
+ }
+ }
+
+ /* check for zero frame rate */
+ if (drv->screen[scrnum].defstate.refresh == 0)
+ {
+ mame_printf_error("%s: %s screen %d has a zero refresh rate\n", driver->source_file, driver->name, scrnum);
+ error = TRUE;
+ }
+ }
+
+ /* check for empty palette */
+ if (palette_modes && drv->total_colors == 0)
+ {
+ mame_printf_error("%s: %s has zero palette entries\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ return error;
+}
+
+
+
+/*************************************
+ *
+ * Validate graphics
+ *
+ *************************************/
+
+static int validate_gfx(int drivnum, const machine_config *drv, const UINT32 *region_length)
+{
+ const game_driver *driver = drivers[drivnum];
+ int error = FALSE;
+ int gfxnum;
+
+ /* bail if no gfx */
+ if (!drv->gfxdecodeinfo)
+ return FALSE;
+
+ /* iterate over graphics decoding entries */
+ for (gfxnum = 0; gfxnum < MAX_GFX_ELEMENTS && drv->gfxdecodeinfo[gfxnum].memory_region != -1; gfxnum++)
+ {
+ const gfx_decode_entry *gfx = &drv->gfxdecodeinfo[gfxnum];
+ int region = gfx->memory_region;
+
+ /* if we have a valid region, and we're not using auto-sizing, check the decode against the region length */
+ if (region && !IS_FRAC(gfx->gfxlayout->total))
+ {
+ int len, avail, plane, start;
+
+ /* determine which plane is the largest */
+ start = 0;
+ for (plane = 0; plane < MAX_GFX_PLANES; plane++)
+ if (gfx->gfxlayout->planeoffset[plane] > start)
+ start = gfx->gfxlayout->planeoffset[plane];
+ start &= ~(gfx->gfxlayout->charincrement - 1);
+
+ /* determine the total length based on this info */
+ len = gfx->gfxlayout->total * gfx->gfxlayout->charincrement;
+
+ /* do we have enough space in the region to cover the whole decode? */
+ avail = region_length[region] - (gfx->start & ~(gfx->gfxlayout->charincrement/8-1));
+
+ /* if not, this is an error */
+ if ((start + len) / 8 > avail)
+ {
+ mame_printf_error("%s: %s has gfx[%d] extending past allocated memory\n", driver->source_file, driver->name, gfxnum);
+ error = TRUE;
+ }
+ }
+ }
+
+ return error;
+}
+
+
+/*************************************
+ *
+ * Display valid coin order
+ *
+ *************************************/
+
+static void display_valid_coin_order(int drivnum, const input_port_entry *memory)
+{
+ const game_driver *driver = drivers[drivnum];
+ const input_port_entry *inp;
+ int coin_list[1024];
+ int coin_len = 0;
+ int i, j;
+ quark_entry *entry;
+
+ for (inp = memory; inp->type != IPT_END; inp++)
+ {
+ int strindex = 0;
+ UINT32 crc;
+
+ if ( !inp->name || inp->name == IP_NAME_DEFAULT )
+ continue;
+
+ /* hash the string and look it up in the string table */
+ crc = quark_string_crc(inp->name);
+ for (entry = first_hash_entry(defstr_table, crc); entry; entry = entry->next)
+ if (entry->crc == crc && !strcmp(inp->name, input_port_string_from_token(INPUT_PORT_UINT32(entry - defstr_table->entry))))
+ {
+ strindex = entry - defstr_table->entry;
+ break;
+ }
+
+ /* if its a coin entry, add it to our list, avoiding repetitions */
+ if ( strindex >= INPUT_STRING_9C_1C && strindex <= INPUT_STRING_1C_9C )
+ {
+ j = 1;
+
+ for( i = 0; i < coin_len; i++ )
+ {
+ if ( coin_list[i] == strindex )
+ {
+ j = 0;
+ break;
+ }
+ }
+
+ if ( j )
+ coin_list[coin_len++] = strindex;
+ }
+ }
+
+ /* now display the proper coin entry list */
+ mame_printf_error( "%s: %s proper coin sort order should be:\n", driver->source_file, driver->name );
+ for (i = INPUT_STRING_9C_1C; i <= INPUT_STRING_1C_9C; i++)
+ for (j = 0; j < coin_len; j++)
+ /* if it's on our list, display it */
+ if (coin_list[j] == i)
+ mame_printf_error("%s\n", input_port_string_from_token(INPUT_PORT_UINT32(i)));
+}
+
+
+/*************************************
+ *
+ * Validate input ports
+ *
+ *************************************/
+
+static int validate_inputs(int drivnum, const machine_config *drv, input_port_entry **memory)
+{
+ const char *demo_sounds = input_port_string_from_token(INPUT_PORT_UINT32(INPUT_STRING_Demo_Sounds));
+ const char *flipscreen = input_port_string_from_token(INPUT_PORT_UINT32(INPUT_STRING_Flip_Screen));
+ const input_port_entry *inp, *last_dipname_entry = NULL;
+ const game_driver *driver = drivers[drivnum];
+ int empty_string_found = FALSE;
+ int last_strindex = 0;
+ quark_entry *entry;
+ int error = FALSE;
+ int coin_error = FALSE;
+ UINT32 crc;
+
+ /* skip if no ports */
+ if (!driver->ipt)
+ return FALSE;
+
+ /* skip if we already validated these ports */
+ crc = (FPTR)driver->ipt;
+ for (entry = first_hash_entry(inputs_table, crc); entry; entry = entry->next)
+ if (entry->crc == crc && driver->ipt == drivers[entry - inputs_table->entry]->ipt)
+ return FALSE;
+
+ /* otherwise, add ourself to the list */
+ add_quark(inputs_table, drivnum, crc);
+
+ /* allocate the input ports */
+ *memory = input_port_allocate(driver->ipt, *memory);
+
+ /* iterate over the results */
+ for (inp = *memory; inp->type != IPT_END; inp++)
+ {
+ int strindex = 0;
+
+ if (port_type_is_analog(inp->type))
+ {
+ INT32 analog_max = inp->analog.max;
+ INT32 analog_min = inp->analog.min;
+ int shift;
+
+ if (inp->type == IPT_POSITIONAL || inp->type == IPT_POSITIONAL_V)
+ {
+ for (shift = 0; (shift <= 31) && (~inp->mask & (1 << shift)); shift++);
+ /* convert the positional max value to be in the bitmask for testing */
+ analog_max = (analog_max - 1) << shift;
+
+ /* positional port size must fit in bits used */
+ if (((inp->mask >> shift) + 1) < inp->analog.max)
+ {
+ mame_printf_error("%s: %s has an analog port with a positional port size bigger then the mask size\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+ }
+ else
+ {
+ /* only positional controls use PORT_WRAPS */
+ if (inp->analog.wraps)
+ {
+ mame_printf_error("%s: %s only positional analog ports use PORT_WRAPS\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+ }
+
+
+ /* analog ports must have a valid sensitivity */
+ if (inp->analog.sensitivity == 0)
+ {
+ mame_printf_error("%s: %s has an analog port with zero sensitivity\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* check that the default falls in the bitmask range */
+ if (inp->default_value & ~inp->mask)
+ {
+ mame_printf_error("%s: %s has an analog port with a default value out of the bitmask range\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* tests for absolute devices */
+ if (port_type_is_analog_absolute(inp->type))
+ {
+ INT32 default_value = inp->default_value;
+
+ /* adjust for signed values */
+ if (analog_min > analog_max)
+ {
+ analog_min = -analog_min;
+ if (default_value > analog_max)
+ default_value = -default_value;
+ }
+
+ /* check that the default falls in the MINMAX range */
+ if (default_value < analog_min || default_value > analog_max)
+ {
+ mame_printf_error("%s: %s has an analog port with a default value out PORT_MINMAX range\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* check that the MINMAX falls in the bitmask range */
+ /* we use the unadjusted min for testing */
+ if (inp->analog.min & ~inp->mask || analog_max & ~inp->mask)
+ {
+ mame_printf_error("%s: %s has an analog port with a PORT_MINMAX value out of the bitmask range\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* absolute analog ports do not use PORT_RESET */
+ if (inp->analog.reset)
+ {
+ mame_printf_error("%s: %s - absolute analog ports do not use PORT_RESET\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+ }
+ else
+ /* tests for relative devices */
+ {
+ /* tests for non IPT_POSITIONAL relative devices */
+ if (inp->type != IPT_POSITIONAL && inp->type != IPT_POSITIONAL_V)
+ {
+ /* relative devices do not use PORT_MINMAX */
+ if (inp->analog.min || inp->analog.max != inp->mask)
+ {
+ mame_printf_error("%s: %s - relative ports do not use PORT_MINMAX\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* relative devices do not use a default value */
+ /* the counter is at 0 on power up */
+ if (inp->default_value)
+ {
+ mame_printf_error("%s: %s - relative ports do not use a default value other then 0\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+ }
+ }
+ }
+
+ /* clear the DIP switch tracking when we hit the first non-DIP entry */
+ if (last_dipname_entry && inp->type != IPT_DIPSWITCH_SETTING)
+ last_dipname_entry = NULL;
+
+ /* look for invalid (0) types which should be mapped to IPT_OTHER */
+ if (inp->type == IPT_INVALID)
+ {
+ mame_printf_error("%s: %s has an input port with an invalid type (0); use IPT_OTHER instead\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* if this entry doesn't have a name, we don't care about the rest of this stuff */
+ if (!inp->name || inp->name == IP_NAME_DEFAULT)
+ {
+ /* not allowed for dipswitches */
+ if (inp->type == IPT_DIPSWITCH_NAME || inp->type == IPT_DIPSWITCH_SETTING)
+ {
+ mame_printf_error("%s: %s has a DIP switch name or setting with no name\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+ last_strindex = 0;
+ continue;
+ }
+
+ /* check for empty string */
+ if (!inp->name[0] && !empty_string_found)
+ {
+ mame_printf_error("%s: %s has an input with an empty string\n", driver->source_file, driver->name);
+ error = TRUE;
+ empty_string_found = TRUE;
+ }
+
+ /* check for trailing spaces */
+ if (inp->name[0] && inp->name[strlen(inp->name) - 1] == ' ')
+ {
+ mame_printf_error("%s: %s input '%s' has trailing spaces\n", driver->source_file, driver->name, inp->name);
+ error = TRUE;
+ }
+
+ /* check for invalid UTF-8 */
+ if (!utf8_is_valid_string(inp->name))
+ {
+ mame_printf_error("%s: %s input '%s' has invalid characters\n", driver->source_file, driver->name, inp->name);
+ error = TRUE;
+ }
+
+ /* hash the string and look it up in the string table */
+ crc = quark_string_crc(inp->name);
+ for (entry = first_hash_entry(defstr_table, crc); entry; entry = entry->next)
+ if (entry->crc == crc && !strcmp(inp->name, input_port_string_from_token(INPUT_PORT_UINT32(entry - defstr_table->entry))))
+ {
+ strindex = entry - defstr_table->entry;
+ break;
+ }
+
+ /* check for strings that should be DEF_STR */
+ if (strindex != 0 && inp->name != input_port_string_from_token(INPUT_PORT_UINT32(strindex)))
+ {
+ mame_printf_error("%s: %s must use DEF_STR( %s )\n", driver->source_file, driver->name, inp->name);
+ error = TRUE;
+ }
+
+ /* track the last dipswitch we encountered */
+ if (inp->type == IPT_DIPSWITCH_NAME)
+ last_dipname_entry = inp;
+
+ /* check for dipswitch ordering against the last entry */
+ if (inp[0].type == IPT_DIPSWITCH_SETTING && inp[-1].type == IPT_DIPSWITCH_SETTING && last_strindex != 0 && strindex != 0)
+ {
+ /* check for inverted off/on dispswitch order */
+ if (last_strindex == INPUT_STRING_On && strindex == INPUT_STRING_Off)
+ {
+ mame_printf_error("%s: %s has inverted Off/On dipswitch order\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* check for inverted yes/no dispswitch order */
+ else if (last_strindex == INPUT_STRING_Yes && strindex == INPUT_STRING_No)
+ {
+ mame_printf_error("%s: %s has inverted No/Yes dipswitch order\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* check for inverted upright/cocktail dispswitch order */
+ else if (last_strindex == INPUT_STRING_Cocktail && strindex == INPUT_STRING_Upright)
+ {
+ mame_printf_error("%s: %s has inverted Upright/Cocktail dipswitch order\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* check for proper coin ordering */
+ else if (last_strindex >= INPUT_STRING_9C_1C && last_strindex <= INPUT_STRING_1C_9C && strindex >= INPUT_STRING_9C_1C && strindex <= INPUT_STRING_1C_9C &&
+ last_strindex >= strindex && !memcmp(&inp[-1].condition, &inp[0].condition, sizeof(inp[-1].condition)))
+ {
+ mame_printf_error("%s: %s has unsorted coinage %s > %s\n", driver->source_file, driver->name, inp[-1].name, inp[0].name);
+ error = TRUE;
+ coin_error = TRUE;
+ }
+ }
+
+ /* check for invalid DIP switch entries */
+ if (last_dipname_entry && inp->type == IPT_DIPSWITCH_SETTING)
+ {
+ /* make sure demo sounds default to on */
+ if (last_dipname_entry->name == demo_sounds && strindex == INPUT_STRING_On &&
+ last_dipname_entry->default_value != inp->default_value)
+ {
+ mame_printf_error("%s: %s Demo Sounds must default to On\n", driver->source_file, driver->name);
+ error = TRUE;
+ }
+
+ /* check for bad flip screen options */
+ if (last_dipname_entry->name == flipscreen && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No))
+ {
+ mame_printf_error("%s: %s has wrong Flip Screen option %s (must be Off/On)\n", driver->source_file, driver->name, inp->name);
+ error = TRUE;
+ }
+
+ /* check for bad demo sounds options */
+ if (last_dipname_entry->name == demo_sounds && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No))
+ {
+ mame_printf_error("%s: %s has wrong Demo Sounds option %s (must be Off/On)\n", driver->source_file, driver->name, inp->name);
+ error = TRUE;
+ }
+ }
+
+ /* remember the last string index */
+ last_strindex = strindex;
+ }
+
+ if ( coin_error )
+ display_valid_coin_order(drivnum, *memory);
+
+ return error;
+}
+
+
+
+/*************************************
+ *
+ * Validate sound and speakers
+ *
+ *************************************/
+
+static int validate_sound(int drivnum, const machine_config *drv)
+{
+ const game_driver *driver = drivers[drivnum];
+ int speaknum, sndnum;
+ int error = FALSE;
+
+ /* make sure the speaker layout makes sense */
+ for (speaknum = 0; speaknum < MAX_SPEAKER && drv->speaker[speaknum].tag; speaknum++)
+ {
+ int check;
+
+ /* check for duplicate tags */
+ for (check = 0; check < MAX_SPEAKER && drv->speaker[check].tag; check++)
+ if (speaknum != check && drv->speaker[check].tag && !strcmp(drv->speaker[speaknum].tag, drv->speaker[check].tag))
+ {
+ mame_printf_error("%s: %s has multiple speakers tagged as '%s'\n", driver->source_file, driver->name, drv->speaker[speaknum].tag);
+ error = TRUE;
+ }
+
+ /* make sure there are no sound chips with the same tag */
+ for (check = 0; check < MAX_SOUND && drv->sound[check].type != SOUND_DUMMY; check++)
+ if (drv->sound[check].tag && !strcmp(drv->speaker[speaknum].tag, drv->sound[check].tag))
+ {
+ mame_printf_error("%s: %s has both a speaker and a sound chip tagged as '%s'\n", driver->source_file, driver->name, drv->speaker[speaknum].tag);
+ error = TRUE;
+ }
+ }
+
+ /* make sure the sounds are wired to the speakers correctly */
+ for (sndnum = 0; sndnum < MAX_SOUND && drv->sound[sndnum].type != SOUND_DUMMY; sndnum++)
+ {
+ int routenum;
+
+ /* loop over all the routes */
+ for (routenum = 0; routenum < drv->sound[sndnum].routes; routenum++)
+ {
+ /* find a speaker with the requested tag */
+ for (speaknum = 0; speaknum < MAX_SPEAKER && drv->speaker[speaknum].tag; speaknum++)
+ if (!strcmp(drv->sound[sndnum].route[routenum].target, drv->speaker[speaknum].tag))
+ break;
+
+ /* if we didn't find one, look for another sound chip with the tag */
+ if (speaknum >= MAX_SPEAKER || !drv->speaker[speaknum].tag)
+ {
+ int check;
+
+ for (check = 0; check < MAX_SOUND && drv->sound[check].type != SOUND_DUMMY; check++)
+ if (check != sndnum && drv->sound[check].tag && !strcmp(drv->sound[check].tag, drv->sound[sndnum].route[routenum].target))
+ break;
+
+ /* if we didn't find one, it's an error */
+ if (check >= MAX_SOUND || drv->sound[check].type == SOUND_DUMMY)
+ {
+ mame_printf_error("%s: %s attempting to route sound to non-existant speaker '%s'\n", driver->source_file, driver->name, drv->sound[sndnum].route[routenum].target);
+ error = TRUE;
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
+
+
+/*************************************
+ *
+ * Master validity checker
+ *
+ *************************************/
+
+int mame_validitychecks(const game_driver *curdriver)
+{
+ osd_ticks_t prep = 0;
+ osd_ticks_t expansion = 0;
+ osd_ticks_t driver_checks = 0;
+ osd_ticks_t rom_checks = 0;
+ osd_ticks_t cpu_checks = 0;
+ osd_ticks_t gfx_checks = 0;
+ osd_ticks_t display_checks = 0;
+ osd_ticks_t input_checks = 0;
+ osd_ticks_t sound_checks = 0;
+#ifdef MESS
+ osd_ticks_t mess_checks = 0;
+#endif
+
+ input_port_entry *inputports = NULL;
+ int drivnum;
+ int error = FALSE;
+ UINT16 lsbtest;
+ UINT8 a, b;
+
+ /* basic system checks */
+ a = 0xff;
+ b = a + 1;
+ if (b > a) { mame_printf_error("UINT8 must be 8 bits\n"); error = TRUE; }
+
+ if (sizeof(INT8) != 1) { mame_printf_error("INT8 must be 8 bits\n"); error = TRUE; }
+ if (sizeof(UINT8) != 1) { mame_printf_error("UINT8 must be 8 bits\n"); error = TRUE; }
+ if (sizeof(INT16) != 2) { mame_printf_error("INT16 must be 16 bits\n"); error = TRUE; }
+ if (sizeof(UINT16) != 2) { mame_printf_error("UINT16 must be 16 bits\n"); error = TRUE; }
+ if (sizeof(INT32) != 4) { mame_printf_error("INT32 must be 32 bits\n"); error = TRUE; }
+ if (sizeof(UINT32) != 4) { mame_printf_error("UINT32 must be 32 bits\n"); error = TRUE; }
+ if (sizeof(INT64) != 8) { mame_printf_error("INT64 must be 64 bits\n"); error = TRUE; }
+ if (sizeof(UINT64) != 8) { mame_printf_error("UINT64 must be 64 bits\n"); error = TRUE; }
+#ifdef PTR64
+ if (sizeof(void *) != 8) { mame_printf_error("PTR64 flag enabled, but was compiled for 32-bit target\n"); error = TRUE; }
+#else
+ if (sizeof(void *) != 4) { mame_printf_error("PTR64 flag not enabled, but was compiled for 64-bit target\n"); error = TRUE; }
+#endif
+ lsbtest = 0;
+ *(UINT8 *)&lsbtest = 0xff;
+#ifdef LSB_FIRST
+ if (lsbtest == 0xff00) { mame_printf_error("LSB_FIRST specified, but running on a big-endian machine\n"); error = TRUE; }
+#else
+ if (lsbtest == 0x00ff) { mame_printf_error("LSB_FIRST not specified, but running on a little-endian machine\n"); error = TRUE; }
+#endif
+
+ /* validate inline function behavior */
+ error = validate_inlines() || error;
+
+ /* make sure the CPU and sound interfaces are up and running */
+ cpuintrf_init(NULL);
+ sndintrf_init(NULL);
+
+ init_resource_tracking();
+ begin_resource_tracking();
+ osd_profiling_ticks();
+
+ /* prepare by pre-scanning all the drivers and adding their info to hash tables */
+ prep -= osd_profiling_ticks();
+ build_quarks();
+ prep += osd_profiling_ticks();
+
+ /* iterate over all drivers */
+ for (drivnum = 0; drivers[drivnum]; drivnum++)
+ {
+ const game_driver *driver = drivers[drivnum];
+ UINT32 region_length[REGION_MAX];
+ machine_config drv;
+
+/* ASG -- trying this for a while to see if submission failures increase */
+#if 1
+ /* non-debug builds only care about games in the same driver */
+ if (curdriver != NULL && strcmp(curdriver->source_file, driver->source_file) != 0)
+ continue;
+#endif
+
+ /* expand the machine driver */
+ expansion -= osd_profiling_ticks();
+ expand_machine_driver(driver->drv, &drv);
+ expansion += osd_profiling_ticks();
+
+ /* validate the driver entry */
+ driver_checks -= osd_profiling_ticks();
+ error = validate_driver(drivnum, &drv) || error;
+ driver_checks += osd_profiling_ticks();
+
+ /* validate the ROM information */
+ rom_checks -= osd_profiling_ticks();
+ error = validate_roms(drivnum, &drv, region_length) || error;
+ rom_checks += osd_profiling_ticks();
+
+ /* validate the CPU information */
+ cpu_checks -= osd_profiling_ticks();
+ error = validate_cpu(drivnum, &drv, region_length) || error;
+ cpu_checks += osd_profiling_ticks();
+
+ /* validate the display */
+ display_checks -= osd_profiling_ticks();
+ error = validate_display(drivnum, &drv) || error;
+ display_checks += osd_profiling_ticks();
+
+ /* validate the graphics decoding */
+ gfx_checks -= osd_profiling_ticks();
+ error = validate_gfx(drivnum, &drv, region_length) || error;
+ gfx_checks += osd_profiling_ticks();
+
+ /* validate input ports */
+ input_checks -= osd_profiling_ticks();
+ error = validate_inputs(drivnum, &drv, &inputports) || error;
+ input_checks += osd_profiling_ticks();
+
+ /* validate sounds and speakers */
+ sound_checks -= osd_profiling_ticks();
+ error = validate_sound(drivnum, &drv) || error;
+ sound_checks += osd_profiling_ticks();
+ }
+
+#ifdef MESS
+ mess_checks -= osd_profiling_ticks();
+ if (mess_validitychecks())
+ error = TRUE;
+ mess_checks += osd_profiling_ticks();
+#endif /* MESS */
+
+#if (REPORT_TIMES)
+ mame_printf_info("Prep: %8dm\n", (int)(prep / 1000000));
+ mame_printf_info("Expansion: %8dm\n", (int)(expansion / 1000000));
+ mame_printf_info("Driver: %8dm\n", (int)(driver_checks / 1000000));
+ mame_printf_info("ROM: %8dm\n", (int)(rom_checks / 1000000));
+ mame_printf_info("CPU: %8dm\n", (int)(cpu_checks / 1000000));
+ mame_printf_info("Display: %8dm\n", (int)(display_checks / 1000000));
+ mame_printf_info("Graphics: %8dm\n", (int)(gfx_checks / 1000000));
+ mame_printf_info("Input: %8dm\n", (int)(input_checks / 1000000));
+ mame_printf_info("Sound: %8dm\n", (int)(sound_checks / 1000000));
+#ifdef MESS
+ mame_printf_info("MESS: %8dm\n", (int)(mess_checks / 1000000));
+#endif
+#endif
+
+ end_resource_tracking();
+ exit_resource_tracking();
+
+ return error;
+}
diff --git a/src/emu/video.c b/src/emu/video.c
new file mode 100644
index 00000000000..d7c98cda799
--- /dev/null
+++ b/src/emu/video.c
@@ -0,0 +1,2211 @@
+/***************************************************************************
+
+ video.c
+
+ Core MAME video routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "osdepend.h"
+#include "driver.h"
+#include "profiler.h"
+#include "png.h"
+#include "debugger.h"
+#include "video/vector.h"
+#include "render.h"
+#include "rendutil.h"
+#include "ui.h"
+
+#include "snap.lh"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define LOG_THROTTLE (0)
+#define LOG_PARTIAL_UPDATES(x) /* logerror x */
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define SUBSECONDS_PER_SPEED_UPDATE (ATTOSECONDS_PER_SECOND / 4)
+#define PAUSED_REFRESH_RATE 30
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _internal_screen_info internal_screen_info;
+struct _internal_screen_info
+{
+ /* pointers to screen configuration and state */
+ const screen_config * config; /* pointer to the configuration in the Machine->drv */
+ screen_state * state; /* pointer to visible state in Machine structure */
+
+ /* textures and bitmaps */
+ render_texture * texture[2]; /* 2x textures for the screen bitmap */
+ mame_bitmap * bitmap[2]; /* 2x bitmaps for rendering */
+ UINT8 curbitmap; /* current bitmap index */
+ UINT8 curtexture; /* current texture index */
+ bitmap_format format; /* format of bitmap for this screen */
+ UINT8 changed; /* has this bitmap changed? */
+ INT32 last_partial_scan; /* scanline of last partial update */
+
+ /* screen timing */
+ attoseconds_t scantime; /* attoseconds per scanline */
+ attoseconds_t pixeltime; /* attoseconds per pixel */
+ attotime vblank_time; /* time of last VBLANK start */
+ emu_timer * scanline0_timer; /* scanline 0 timer */
+
+ /* movie recording */
+ mame_file * movie_file; /* handle to the open movie file */
+ UINT32 movie_frame; /* current movie frame number */
+};
+
+
+struct _video_private
+{
+ /* per-screen information */
+ internal_screen_info scrinfo[MAX_SCREENS]; /* per-screen infomration */
+
+ /* snapshot stuff */
+ render_target * snap_target; /* screen shapshot target */
+ mame_bitmap * snap_bitmap; /* screen snapshot bitmap */
+
+ /* crosshair bits */
+ mame_bitmap * crosshair_bitmap[MAX_PLAYERS]; /* crosshair bitmap per player */
+ render_texture * crosshair_texture[MAX_PLAYERS]; /* crosshair texture per player */
+ UINT8 crosshair_animate; /* animation frame index */
+ UINT8 crosshair_visible; /* crosshair visible mask */
+ UINT8 crosshair_needed; /* crosshair needed mask */
+};
+
+
+typedef struct _video_global video_global;
+struct _video_global
+{
+ /* throttling calculations */
+ osd_ticks_t throttle_last_ticks;/* osd_ticks the last call to throttle */
+ attotime throttle_realtime; /* real time the last call to throttle */
+ attotime throttle_emutime; /* emulated time the last call to throttle */
+ UINT32 throttle_history; /* history of frames where we were fast enough */
+
+ /* dynamic speed computation */
+ osd_ticks_t speed_last_realtime;/* real time at the last speed calculation */
+ attotime speed_last_emutime; /* emulated time at the last speed calculation */
+ double speed_percent; /* most recent speed percentage */
+ UINT32 partial_updates_this_frame;/* partial update counter this frame */
+
+ /* overall speed computation */
+ UINT32 overall_real_seconds;/* accumulated real seconds at normal speed */
+ osd_ticks_t overall_real_ticks; /* accumulated real ticks at normal speed */
+ attotime overall_emutime; /* accumulated emulated time at normal speed */
+ UINT32 overall_valid_counter;/* number of consecutive valid time periods */
+
+ /* configuration */
+ UINT8 sleep; /* flag: TRUE if we're allowed to sleep */
+ UINT8 throttle; /* flag: TRUE if we're currently throttled */
+ UINT8 fastforward; /* flag: TRUE if we're currently fast-forwarding */
+ UINT32 seconds_to_run; /* number of seconds to run before quitting */
+ UINT8 auto_frameskip; /* flag: TRUE if we're automatically frameskipping */
+ UINT32 speed; /* overall speed (*100) */
+ UINT32 original_speed; /* originally-specified speed */
+ UINT8 refresh_speed; /* flag: TRUE if we max out our speed according to the refresh */
+
+ /* frameskipping */
+ UINT8 empty_skip_count; /* number of empty frames we have skipped */
+ UINT8 frameskip_level; /* current frameskip level */
+ UINT8 frameskip_counter; /* counter that counts through the frameskip steps */
+ INT8 frameskip_adjust;
+ UINT8 skipping_this_frame;/* flag: TRUE if we are skipping the current frame */
+ osd_ticks_t average_oversleep; /* average number of ticks the OSD oversleeps */
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* global video state */
+static video_global global;
+
+/* frameskipping tables */
+static const UINT8 skiptable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS] =
+{
+ { 0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,1 },
+ { 0,0,0,0,0,1,0,0,0,0,0,1 },
+ { 0,0,0,1,0,0,0,1,0,0,0,1 },
+ { 0,0,1,0,0,1,0,0,1,0,0,1 },
+ { 0,1,0,0,1,0,1,0,0,1,0,1 },
+ { 0,1,0,1,0,1,0,1,0,1,0,1 },
+ { 0,1,0,1,1,0,1,0,1,1,0,1 },
+ { 0,1,1,0,1,1,0,1,1,0,1,1 },
+ { 0,1,1,1,0,1,1,1,0,1,1,1 },
+ { 0,1,1,1,1,1,0,1,1,1,1,1 },
+ { 0,1,1,1,1,1,1,1,1,1,1,1 }
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* core implementation */
+static void video_exit(running_machine *machine);
+static void init_buffered_spriteram(void);
+
+/* graphics decoding */
+static void allocate_graphics(running_machine *machine, const gfx_decode_entry *gfxdecodeinfo);
+static void decode_graphics(running_machine *machine, const gfx_decode_entry *gfxdecodeinfo);
+
+/* global rendering */
+static TIMER_CALLBACK( scanline0_callback );
+static int finish_screen_updates(running_machine *machine);
+
+/* throttling/frameskipping/performance */
+static void update_throttle(attotime emutime);
+static osd_ticks_t throttle_until_ticks(osd_ticks_t target_ticks);
+static void update_frameskip(void);
+static void recompute_speed(attotime emutime);
+
+/* screen snapshots */
+static mame_bitmap *get_snapshot_bitmap(running_machine *machine, int scrnum);
+static file_error mame_fopen_next(const char *pathoption, const char *extension, mame_file **file);
+
+/* movie recording */
+static void movie_record_frame(running_machine *machine, int scrnum);
+
+/* crosshair rendering */
+static void crosshair_init(video_private *viddata);
+static void crosshair_render(video_private *viddata);
+static void crosshair_free(video_private *viddata);
+
+/* software rendering */
+static void rgb888_draw_primitives(const render_primitive *primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ effective_autoframeskip - return the effective
+ autoframeskip value, accounting for fast
+ forward
+-------------------------------------------------*/
+
+INLINE int effective_autoframeskip(void)
+{
+ /* if we're fast forwarding or paused, autoframeskip is disabled */
+ if (global.fastforward || mame_is_paused(Machine))
+ return FALSE;
+
+ /* otherwise, it's up to the user */
+ return global.auto_frameskip;
+}
+
+
+/*-------------------------------------------------
+ effective_frameskip - return the effective
+ frameskip value, accounting for fast
+ forward
+-------------------------------------------------*/
+
+INLINE int effective_frameskip(void)
+{
+ /* if we're fast forwarding, use the maximum frameskip */
+ if (global.fastforward)
+ return FRAMESKIP_LEVELS - 1;
+
+ /* otherwise, it's up to the user */
+ return global.frameskip_level;
+}
+
+
+/*-------------------------------------------------
+ effective_throttle - return the effective
+ throttle value, accounting for fast
+ forward and user interface
+-------------------------------------------------*/
+
+INLINE int effective_throttle(void)
+{
+ /* if we're paused, or if the UI is active, we always throttle */
+ if (mame_is_paused(Machine) || ui_is_menu_active() || ui_is_slider_active())
+ return TRUE;
+
+ /* if we're fast forwarding, we don't throttle */
+ if (global.fastforward)
+ return FALSE;
+
+ /* otherwise, it's up to the user */
+ return global.throttle;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ video_init - start up the video system
+-------------------------------------------------*/
+
+void video_init(running_machine *machine)
+{
+ video_private *viddata;
+ const char *filename;
+ int scrnum;
+
+ /* reset our global state */
+ memset(&global, 0, sizeof(global));
+ global.speed_percent = 1.0;
+
+ /* extract global configuration settings */
+ global.sleep = options_get_bool(mame_options(), OPTION_SLEEP);
+ global.throttle = options_get_bool(mame_options(), OPTION_THROTTLE);
+ global.auto_frameskip = options_get_bool(mame_options(), OPTION_AUTOFRAMESKIP);
+ global.frameskip_level = options_get_int(mame_options(), OPTION_FRAMESKIP);
+ global.seconds_to_run = options_get_int(mame_options(), OPTION_SECONDS_TO_RUN);
+ global.original_speed = global.speed = (options_get_float(mame_options(), OPTION_SPEED) * 100.0 + 0.5);
+ global.refresh_speed = options_get_bool(mame_options(), OPTION_REFRESHSPEED);
+
+ /* allocate memory for our private data */
+ viddata = machine->video_data = auto_malloc(sizeof(*viddata));
+ memset(viddata, 0, sizeof(*viddata));
+
+ /* request a callback upon exiting */
+ add_exit_callback(machine, video_exit);
+
+ /* configure all of the screens */
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ if (machine->drv->screen[scrnum].tag != NULL)
+ {
+ render_container *container = render_container_get_screen(scrnum);
+ internal_screen_info *info = &viddata->scrinfo[scrnum];
+
+ /* allocate a timer to reset partial updates */
+ info->scanline0_timer = timer_alloc(scanline0_callback);
+
+ /* make pointers back to the config and state */
+ info->config = &machine->drv->screen[scrnum];
+ info->state = &machine->screen[scrnum];
+
+ /* configure the screen with the default parameters */
+ video_screen_configure(scrnum, info->state->width, info->state->height, &info->state->visarea, info->state->refresh);
+
+ /* configure the default cliparea */
+ if (info->config->xoffset != 0)
+ render_container_set_xoffset(container, info->config->xoffset);
+ if (info->config->yoffset != 0)
+ render_container_set_yoffset(container, info->config->yoffset);
+ if (info->config->xscale != 0)
+ render_container_set_xscale(container, info->config->xscale);
+ if (info->config->yscale != 0)
+ render_container_set_yscale(container, info->config->yscale);
+
+ /* reset VBLANK timing */
+ info->vblank_time = attotime_sub_attoseconds(attotime_zero, machine->screen[0].vblank);
+
+ /* register for save states */
+ state_save_register_item("video", scrnum, info->vblank_time.seconds);
+ state_save_register_item("video", scrnum, info->vblank_time.attoseconds);
+ }
+
+ /* create spriteram buffers if necessary */
+ if (machine->drv->video_attributes & VIDEO_BUFFERS_SPRITERAM)
+ init_buffered_spriteram();
+
+ /* convert the gfx ROMs into character sets. This is done BEFORE calling the driver's */
+ /* palette_init() routine because it might need to check the machine->gfx[] data */
+ if (machine->drv->gfxdecodeinfo != NULL)
+ allocate_graphics(machine, machine->drv->gfxdecodeinfo);
+
+ /* configure the palette */
+ palette_config(machine);
+
+ /* actually decode the graphics */
+ if (machine->drv->gfxdecodeinfo != NULL)
+ decode_graphics(machine, machine->drv->gfxdecodeinfo);
+
+ /* reset video statics and get out of here */
+ pdrawgfx_shadow_lowpri = 0;
+
+ /* initialize tilemaps */
+ tilemap_init(machine);
+
+ /* create a render target for snapshots */
+ if (viddata->scrinfo[0].state != NULL)
+ {
+ viddata->snap_target = render_target_alloc(layout_snap, RENDER_CREATE_SINGLE_FILE | RENDER_CREATE_HIDDEN);
+ assert(viddata->snap_target != NULL);
+ if (viddata->snap_target == NULL)
+ fatalerror("Unable to allocate snapshot render target\n");
+ render_target_set_layer_config(viddata->snap_target, 0);
+ }
+
+ /* create crosshairs */
+ crosshair_init(viddata);
+
+ /* start recording movie if specified */
+ filename = options_get_string(mame_options(), OPTION_MNGWRITE);
+ if (filename[0] != 0)
+ video_movie_begin_recording(machine, 0, filename);
+}
+
+
+/*-------------------------------------------------
+ video_exit - close down the video system
+-------------------------------------------------*/
+
+static void video_exit(running_machine *machine)
+{
+ video_private *viddata = machine->video_data;
+ int scrnum;
+ int i;
+
+ /* free crosshairs */
+ crosshair_free(viddata);
+
+ /* stop recording any movie */
+ video_movie_end_recording(machine, 0);
+
+ /* free all the graphics elements */
+ for (i = 0; i < MAX_GFX_ELEMENTS; i++)
+ freegfx(machine->gfx[i]);
+
+ /* free all the textures and bitmaps */
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ {
+ internal_screen_info *info = &viddata->scrinfo[scrnum];
+ if (info->texture[0] != NULL)
+ render_texture_free(info->texture[0]);
+ if (info->texture[1] != NULL)
+ render_texture_free(info->texture[1]);
+ if (info->bitmap[0] != NULL)
+ bitmap_free(info->bitmap[0]);
+ if (info->bitmap[1] != NULL)
+ bitmap_free(info->bitmap[1]);
+ }
+
+ /* free the snapshot target */
+ if (viddata->snap_target != NULL)
+ render_target_free(viddata->snap_target);
+ if (viddata->snap_bitmap != NULL)
+ bitmap_free(viddata->snap_bitmap);
+
+ /* print a final result if we have at least 5 seconds' worth of data */
+ if (global.overall_emutime.seconds >= 5)
+ {
+ osd_ticks_t tps = osd_ticks_per_second();
+ double final_real_time = (double)global.overall_real_seconds + (double)global.overall_real_ticks / (double)tps;
+ double final_emu_time = attotime_to_double(global.overall_emutime);
+ mame_printf_info("Average speed: %.2f%% (%d seconds)\n", 100 * final_emu_time / final_real_time, attotime_add_attoseconds(global.overall_emutime, ATTOSECONDS_PER_SECOND / 2).seconds);
+ }
+}
+
+
+/*-------------------------------------------------
+ video_vblank_start - called at the start of
+ VBLANK, which is driven by the CPU scheduler
+-------------------------------------------------*/
+
+void video_vblank_start(running_machine *machine)
+{
+ video_private *viddata = machine->video_data;
+ attotime curtime = timer_get_time();
+ int scrnum;
+
+ /* kludge: we get called at time 0 to reset, but at that point,
+ the time of last VBLANK is actually -vblank_duration */
+ if (curtime.seconds == 0 && curtime.attoseconds == 0)
+ curtime = attotime_sub_attoseconds(attotime_zero, machine->screen[0].vblank);
+
+ /* reset VBLANK timers for each screen -- fix me */
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ viddata->scrinfo[scrnum].vblank_time = curtime;
+}
+
+
+/*-------------------------------------------------
+ init_buffered_spriteram - initialize the
+ double-buffered spriteram
+-------------------------------------------------*/
+
+static void init_buffered_spriteram(void)
+{
+ assert_always(spriteram_size != 0, "Video buffers spriteram but spriteram_size is 0");
+
+ /* allocate memory for the back buffer */
+ buffered_spriteram = auto_malloc(spriteram_size);
+
+ /* register for saving it */
+ state_save_register_global_pointer(buffered_spriteram, spriteram_size);
+
+ /* do the same for the secon back buffer, if present */
+ if (spriteram_2_size)
+ {
+ /* allocate memory */
+ buffered_spriteram_2 = auto_malloc(spriteram_2_size);
+
+ /* register for saving it */
+ state_save_register_global_pointer(buffered_spriteram_2, spriteram_2_size);
+ }
+
+ /* make 16-bit and 32-bit pointer variants */
+ buffered_spriteram16 = (UINT16 *)buffered_spriteram;
+ buffered_spriteram32 = (UINT32 *)buffered_spriteram;
+ buffered_spriteram16_2 = (UINT16 *)buffered_spriteram_2;
+ buffered_spriteram32_2 = (UINT32 *)buffered_spriteram_2;
+}
+
+
+
+/***************************************************************************
+ GRAPHICS DECODING
+***************************************************************************/
+
+/*-------------------------------------------------
+ allocate_graphics - allocate memory for the
+ graphics
+-------------------------------------------------*/
+
+static void allocate_graphics(running_machine *machine, const gfx_decode_entry *gfxdecodeinfo)
+{
+ int i;
+
+ /* loop over all elements */
+ for (i = 0; i < MAX_GFX_ELEMENTS && gfxdecodeinfo[i].memory_region != -1; i++)
+ {
+ int region_length = 8 * memory_region_length(gfxdecodeinfo[i].memory_region);
+ int xscale = (gfxdecodeinfo[i].xscale == 0) ? 1 : gfxdecodeinfo[i].xscale;
+ int yscale = (gfxdecodeinfo[i].yscale == 0) ? 1 : gfxdecodeinfo[i].yscale;
+ UINT32 extxoffs[MAX_ABS_GFX_SIZE], extyoffs[MAX_ABS_GFX_SIZE];
+ gfx_layout glcopy;
+ int j;
+
+ /* make a copy of the layout */
+ glcopy = *gfxdecodeinfo[i].gfxlayout;
+
+ /* copy the X and Y offsets into temporary arrays */
+ memcpy(extxoffs, glcopy.xoffset, sizeof(glcopy.xoffset));
+ memcpy(extyoffs, glcopy.yoffset, sizeof(glcopy.yoffset));
+
+ /* if there are extended offsets, copy them over top */
+ if (glcopy.extxoffs != NULL)
+ memcpy(extxoffs, glcopy.extxoffs, glcopy.width * sizeof(extxoffs[0]));
+ if (glcopy.extyoffs != NULL)
+ memcpy(extyoffs, glcopy.extyoffs, glcopy.height * sizeof(extyoffs[0]));
+
+ /* always use the extended offsets here */
+ glcopy.extxoffs = extxoffs;
+ glcopy.extyoffs = extyoffs;
+
+ /* expand X and Y by the scale factors */
+ if (xscale > 1)
+ {
+ glcopy.width *= xscale;
+ for (j = glcopy.width - 1; j >= 0; j--)
+ extxoffs[j] = extxoffs[j / xscale];
+ }
+ if (yscale > 1)
+ {
+ glcopy.height *= yscale;
+ for (j = glcopy.height - 1; j >= 0; j--)
+ extyoffs[j] = extyoffs[j / yscale];
+ }
+
+ /* if the character count is a region fraction, compute the effective total */
+ if (IS_FRAC(glcopy.total))
+ {
+ if (region_length == 0)
+ continue;
+ glcopy.total = region_length / glcopy.charincrement * FRAC_NUM(glcopy.total) / FRAC_DEN(glcopy.total);
+ }
+
+ /* for non-raw graphics, decode the X and Y offsets */
+ if (glcopy.planeoffset[0] != GFX_RAW)
+ {
+ /* loop over all the planes, converting fractions */
+ for (j = 0; j < glcopy.planes; j++)
+ {
+ UINT32 value = glcopy.planeoffset[j];
+ if (IS_FRAC(value))
+ glcopy.planeoffset[j] = FRAC_OFFSET(value) + region_length * FRAC_NUM(value) / FRAC_DEN(value);
+ }
+
+ /* loop over all the X/Y offsets, converting fractions */
+ for (j = 0; j < glcopy.width; j++)
+ {
+ UINT32 value = extxoffs[j];
+ if (IS_FRAC(value))
+ extxoffs[j] = FRAC_OFFSET(value) + region_length * FRAC_NUM(value) / FRAC_DEN(value);
+ }
+
+ for (j = 0; j < glcopy.height; j++)
+ {
+ UINT32 value = extyoffs[j];
+ if (IS_FRAC(value))
+ extyoffs[j] = FRAC_OFFSET(value) + region_length * FRAC_NUM(value) / FRAC_DEN(value);
+ }
+ }
+
+ /* otherwise, just use yoffset[0] as the line modulo */
+ else
+ {
+ int base = gfxdecodeinfo[i].start;
+ int end = region_length/8;
+ while (glcopy.total > 0)
+ {
+ int elementbase = base + (glcopy.total - 1) * glcopy.charincrement / 8;
+ int lastpixelbase = elementbase + glcopy.height * glcopy.yoffset[0] / 8 - 1;
+ if (lastpixelbase < end)
+ break;
+ glcopy.total--;
+ }
+ }
+
+ /* allocate the graphics */
+ machine->gfx[i] = allocgfx(&glcopy);
+
+ /* if we have a remapped colortable, point our local colortable to it */
+ machine->gfx[i]->total_colors = gfxdecodeinfo[i].total_color_codes;
+ machine->gfx[i]->color_base = machine->drv->gfxdecodeinfo[i].color_codes_start;
+ }
+}
+
+
+/*-------------------------------------------------
+ decode_graphics - decode the graphics
+-------------------------------------------------*/
+
+static void decode_graphics(running_machine *machine, const gfx_decode_entry *gfxdecodeinfo)
+{
+ int totalgfx = 0, curgfx = 0;
+ char buffer[200];
+ int i;
+
+ /* count total graphics elements */
+ for (i = 0; i < MAX_GFX_ELEMENTS; i++)
+ if (machine->gfx[i])
+ totalgfx += machine->gfx[i]->total_elements;
+
+ /* loop over all elements */
+ for (i = 0; i < MAX_GFX_ELEMENTS; i++)
+ if (machine->gfx[i] != NULL)
+ {
+ /* if we have a valid region, decode it now */
+ if (gfxdecodeinfo[i].memory_region > REGION_INVALID)
+ {
+ UINT8 *region_base = memory_region(gfxdecodeinfo[i].memory_region);
+ gfx_element *gfx = machine->gfx[i];
+ int j;
+
+ /* now decode the actual graphics */
+ for (j = 0; j < gfx->total_elements; j += 1024)
+ {
+ int num_to_decode = (j + 1024 < gfx->total_elements) ? 1024 : (gfx->total_elements - j);
+ decodegfx(gfx, region_base + gfxdecodeinfo[i].start, j, num_to_decode);
+ curgfx += num_to_decode;
+
+ /* display some startup text */
+ sprintf(buffer, "Decoding (%d%%)", curgfx * 100 / totalgfx);
+ ui_set_startup_text(buffer, FALSE);
+ }
+ }
+
+ /* otherwise, clear the target region */
+ else
+ memset(machine->gfx[i]->gfxdata, 0, machine->gfx[i]->char_modulo * machine->gfx[i]->total_elements);
+ }
+}
+
+
+
+/***************************************************************************
+ SCREEN MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ video_screen_configure - configure the parameters
+ of a screen
+-------------------------------------------------*/
+
+void video_screen_configure(int scrnum, int width, int height, const rectangle *visarea, attoseconds_t refresh)
+{
+ video_private *viddata = Machine->video_data;
+ internal_screen_info *info = &viddata->scrinfo[scrnum];
+
+ /* reallocate bitmap if necessary */
+ if (!(Machine->drv->video_attributes & VIDEO_TYPE_VECTOR))
+ {
+ int curwidth = 0, curheight = 0;
+
+ /* reality checks */
+ if (visarea->min_x < 0 || visarea->min_y < 0 || visarea->max_x >= width || visarea->max_y >= height)
+ fatalerror("video_screen_configure(): visible area must be contained within the width/height!");
+
+ /* extract the current width/height from the bitmap */
+ if (info->bitmap[0] != NULL)
+ {
+ curwidth = info->bitmap[0]->width;
+ curheight = info->bitmap[0]->height;
+ }
+
+ /* if we're too small to contain this width/height, reallocate our bitmaps and textures */
+ if (width > curwidth || height > curheight)
+ {
+ bitmap_format screen_format = info->state->format;
+
+ /* free what we have currently */
+ if (info->texture[0] != NULL)
+ render_texture_free(info->texture[0]);
+ if (info->texture[1] != NULL)
+ render_texture_free(info->texture[1]);
+ if (info->bitmap[0] != NULL)
+ bitmap_free(info->bitmap[0]);
+ if (info->bitmap[1] != NULL)
+ bitmap_free(info->bitmap[1]);
+
+ /* compute new width/height */
+ curwidth = MAX(width, curwidth);
+ curheight = MAX(height, curheight);
+
+ /* choose the texture format */
+ /* convert the screen format to a texture format */
+ switch (screen_format)
+ {
+ case BITMAP_FORMAT_INDEXED16: info->format = TEXFORMAT_PALETTE16; break;
+ case BITMAP_FORMAT_RGB15: info->format = TEXFORMAT_RGB15; break;
+ case BITMAP_FORMAT_RGB32: info->format = TEXFORMAT_RGB32; break;
+ default: fatalerror("Invalid bitmap format!"); break;
+ }
+
+ /* allocate bitmaps */
+ info->bitmap[0] = bitmap_alloc(curwidth, curheight, screen_format);
+ bitmap_set_palette(info->bitmap[0], Machine->palette);
+ info->bitmap[1] = bitmap_alloc(curwidth, curheight, screen_format);
+ bitmap_set_palette(info->bitmap[1], Machine->palette);
+
+ /* allocate textures */
+ info->texture[0] = render_texture_alloc(NULL, NULL);
+ render_texture_set_bitmap(info->texture[0], info->bitmap[0], visarea, info->config->palette_base, info->format);
+ info->texture[1] = render_texture_alloc(NULL, NULL);
+ render_texture_set_bitmap(info->texture[1], info->bitmap[1], visarea, info->config->palette_base, info->format);
+ }
+ }
+
+ /* now fill in the new parameters */
+ info->state->width = width;
+ info->state->height = height;
+ info->state->visarea = *visarea;
+ info->state->refresh = refresh;
+
+ /* compute timing parameters */
+ info->scantime = refresh / height;
+ info->pixeltime = refresh / (height * width);
+
+ /* adjust speed if necessary */
+ if (global.refresh_speed)
+ {
+ float minrefresh = render_get_max_update_rate();
+ if (minrefresh != 0)
+ {
+ UINT32 target_speed = floor(minrefresh * 100.0 / ATTOSECONDS_TO_HZ(refresh));
+ target_speed = MIN(target_speed, global.original_speed);
+ if (target_speed != global.speed)
+ {
+ mame_printf_verbose("Adjusting target speed to %d%%\n", target_speed);
+ global.speed = target_speed;
+ }
+ }
+ }
+
+ /* recompute the VBLANK timing */
+ cpu_compute_vblank_timing();
+
+ /* if we are on scanline 0 already, reset the update timer immediately */
+ /* otherwise, defer until the next scanline 0 */
+ if (video_screen_get_vpos(scrnum) == 0)
+ timer_adjust(info->scanline0_timer, attotime_zero, scrnum, attotime_zero);
+ else
+ timer_adjust(info->scanline0_timer, video_screen_get_time_until_pos(scrnum, 0, 0), scrnum, attotime_zero);
+}
+
+
+/*-------------------------------------------------
+ video_screen_set_visarea - just set the visible area
+ of a screen
+-------------------------------------------------*/
+
+void video_screen_set_visarea(int scrnum, int min_x, int max_x, int min_y, int max_y)
+{
+ screen_state *state = &Machine->screen[scrnum];
+ rectangle visarea;
+
+ visarea.min_x = min_x;
+ visarea.max_x = max_x;
+ visarea.min_y = min_y;
+ visarea.max_y = max_y;
+
+ video_screen_configure(scrnum, state->width, state->height, &visarea, state->refresh);
+}
+
+
+/*-------------------------------------------------
+ video_screen_exists - returns whether a given
+ screen exists
+-------------------------------------------------*/
+
+int video_screen_exists(int scrnum)
+{
+ return (scrnum >= 0 && scrnum < MAX_SCREENS && Machine->drv->screen[scrnum].tag != NULL);
+}
+
+
+/*-------------------------------------------------
+ get_screen_info - accessor function to get
+ private data for a screen
+-------------------------------------------------*/
+
+static internal_screen_info *get_screen_info(running_machine *machine, int scrnum)
+{
+ video_private *viddata = machine->video_data;
+ assert_always(video_screen_exists(scrnum), "Invalid screen");
+ return &viddata->scrinfo[scrnum];
+}
+
+
+/*-------------------------------------------------
+ video_screen_update_partial - perform a partial
+ update from the last scanline up to and
+ including the specified scanline
+-------------------------------------------------*/
+
+void video_screen_update_partial(int scrnum, int scanline)
+{
+ internal_screen_info *info = get_screen_info(Machine, scrnum);
+ rectangle clip = info->state->visarea;
+
+ LOG_PARTIAL_UPDATES(("Partial: video_screen_update_partial(%d,%d): ", scrnum, scanline));
+
+ /* these two checks only apply if we're allowed to skip frames */
+ if (!(Machine->drv->video_attributes & VIDEO_ALWAYS_UPDATE))
+ {
+ /* if skipping this frame, bail */
+ if (global.skipping_this_frame)
+ {
+ LOG_PARTIAL_UPDATES(("skipped due to frameskipping\n"));
+ return;
+ }
+
+ /* skip if this screen is not visible anywhere */
+ if (!(render_get_live_screens_mask() & (1 << scrnum)))
+ {
+ LOG_PARTIAL_UPDATES(("skipped because screen not live\n"));
+ return;
+ }
+ }
+
+ /* skip if less than the lowest so far */
+ if (scanline < info->last_partial_scan)
+ {
+ LOG_PARTIAL_UPDATES(("skipped because less than previous\n"));
+ return;
+ }
+
+ /* set the start/end scanlines */
+ if (info->last_partial_scan > clip.min_y)
+ clip.min_y = info->last_partial_scan;
+ if (scanline < clip.max_y)
+ clip.max_y = scanline;
+
+ /* render if necessary */
+ if (clip.min_y <= clip.max_y)
+ {
+ UINT32 flags = UPDATE_HAS_NOT_CHANGED;
+
+ profiler_mark(PROFILER_VIDEO);
+ LOG_PARTIAL_UPDATES(("updating %d-%d\n", clip.min_y, clip.max_y));
+
+ if (Machine->drv->video_update != NULL)
+ flags = (*Machine->drv->video_update)(Machine, scrnum, info->bitmap[info->curbitmap], &clip);
+ global.partial_updates_this_frame++;
+ profiler_mark(PROFILER_END);
+
+ /* if we modified the bitmap, we have to commit */
+ info->changed |= ~flags & UPDATE_HAS_NOT_CHANGED;
+ }
+
+ /* remember where we left off */
+ info->last_partial_scan = scanline + 1;
+}
+
+
+/*-------------------------------------------------
+ video_screen_get_vpos - returns the current
+ vertical position of the beam for a given
+ screen
+-------------------------------------------------*/
+
+int video_screen_get_vpos(int scrnum)
+{
+ internal_screen_info *info = get_screen_info(Machine, scrnum);
+ attoseconds_t delta = attotime_to_attoseconds(attotime_sub(timer_get_time(), info->vblank_time));
+ int vpos;
+
+ /* round to the nearest pixel */
+ delta += info->pixeltime / 2;
+
+ /* compute the v position relative to the start of VBLANK */
+ vpos = delta / info->scantime;
+
+ /* adjust for the fact that VBLANK starts at the bottom of the visible area */
+ return (info->state->visarea.max_y + 1 + vpos) % info->state->height;
+}
+
+
+/*-------------------------------------------------
+ video_screen_get_hpos - returns the current
+ horizontal position of the beam for a given
+ screen
+-------------------------------------------------*/
+
+int video_screen_get_hpos(int scrnum)
+{
+ internal_screen_info *info = get_screen_info(Machine, scrnum);
+ attoseconds_t delta = attotime_to_attoseconds(attotime_sub(timer_get_time(), info->vblank_time));
+ int vpos;
+
+ /* round to the nearest pixel */
+ delta += info->pixeltime / 2;
+
+ /* compute the v position relative to the start of VBLANK */
+ vpos = delta / info->scantime;
+
+ /* subtract that from the total time */
+ delta -= vpos * info->scantime;
+
+ /* return the pixel offset from the start of this scanline */
+ return delta / info->pixeltime;
+}
+
+
+/*-------------------------------------------------
+ video_screen_get_vblank - returns the VBLANK
+ state of a given screen
+-------------------------------------------------*/
+
+int video_screen_get_vblank(int scrnum)
+{
+ internal_screen_info *info = get_screen_info(Machine, scrnum);
+ int vpos = video_screen_get_vpos(scrnum);
+ return (vpos < info->state->visarea.min_y || vpos > info->state->visarea.max_y);
+}
+
+
+/*-------------------------------------------------
+ video_screen_get_hblank - returns the HBLANK
+ state of a given screen
+-------------------------------------------------*/
+
+int video_screen_get_hblank(int scrnum)
+{
+ internal_screen_info *info = get_screen_info(Machine, scrnum);
+ int hpos = video_screen_get_hpos(scrnum);
+ return (hpos < info->state->visarea.min_x || hpos > info->state->visarea.max_x);
+}
+
+
+/*-------------------------------------------------
+ video_screen_get_time_until_pos - returns the
+ amount of time remaining until the beam is
+ at the given hpos,vpos
+-------------------------------------------------*/
+
+attotime video_screen_get_time_until_pos(int scrnum, int vpos, int hpos)
+{
+ internal_screen_info *info = get_screen_info(Machine, scrnum);
+ attoseconds_t curdelta = attotime_to_attoseconds(attotime_sub(timer_get_time(), info->vblank_time));
+ attoseconds_t targetdelta;
+
+ /* since we measure time relative to VBLANK, compute the scanline offset from VBLANK */
+ vpos += info->state->height - (info->state->visarea.max_y + 1);
+ vpos %= info->state->height;
+
+ /* compute the delta for the given X,Y position */
+ targetdelta = (attoseconds_t)vpos * info->scantime + (attoseconds_t)hpos * info->pixeltime;
+
+ /* if we're past that time (within 1/2 of a pixel), head to the next frame */
+ if (targetdelta <= curdelta + info->pixeltime / 2)
+ targetdelta += info->state->refresh;
+ while (targetdelta <= curdelta)
+ targetdelta += info->state->refresh;
+
+ /* return the difference */
+ return attotime_make(0, targetdelta - curdelta);
+}
+
+
+/*-------------------------------------------------
+ video_screen_get_scan_period - return the
+ amount of time the beam takes to draw one
+ scanline
+-------------------------------------------------*/
+
+attotime video_screen_get_scan_period(int scrnum)
+{
+ internal_screen_info *info = get_screen_info(Machine, scrnum);
+ return attotime_make(0, info->scantime);
+}
+
+
+/*-------------------------------------------------
+ video_screen_get_frame_period - return the
+ amount of time the beam takes to draw one
+ complete frame
+-------------------------------------------------*/
+
+attotime video_screen_get_frame_period(int scrnum)
+{
+ return attotime_make(0, Machine->screen[scrnum].refresh);
+}
+
+
+
+/***************************************************************************
+ GLOBAL RENDERING
+***************************************************************************/
+
+/*-------------------------------------------------
+ scanline0_callback - reset partial updates
+ for a screen
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( scanline0_callback )
+{
+ video_private *viddata = machine->video_data;
+ int scrnum = param;
+
+ /* reset partial updates */
+ viddata->scrinfo[scrnum].last_partial_scan = 0;
+ global.partial_updates_this_frame = 0;
+
+ timer_adjust(viddata->scrinfo[scrnum].scanline0_timer, video_screen_get_time_until_pos(scrnum, 0, 0), scrnum, attotime_zero);
+}
+
+
+/*-------------------------------------------------
+ video_frame_update - handle frameskipping and
+ UI, plus updating the screen during normal
+ operations
+-------------------------------------------------*/
+
+void video_frame_update(void)
+{
+ attotime current_time = timer_get_time();
+ int skipped_it = global.skipping_this_frame;
+ int phase = mame_get_phase(Machine);
+
+ /* only render sound and video if we're in the running phase */
+#ifdef MAME_DEBUG
+ if (phase == MAME_PHASE_RUNNING)
+#else
+ if (phase == MAME_PHASE_RUNNING && !mame_is_paused(Machine))
+#endif
+ {
+ int anything_changed = finish_screen_updates(Machine);
+
+ /* if none of the screens changed and we haven't skipped too many frames in a row,
+ mark this frame as skipped to prevent throttling; this helps for games that
+ don't update their screen at the monitor refresh rate */
+ if (!anything_changed && !global.auto_frameskip && global.frameskip_level == 0 && global.empty_skip_count++ < 3)
+ skipped_it = TRUE;
+ else
+ global.empty_skip_count = 0;
+ }
+
+ /* draw the user interface */
+ ui_update_and_render();
+
+ /* if we're throttling, synchronize before rendering */
+ if (!skipped_it && effective_throttle())
+ update_throttle(current_time);
+
+ /* ask the OSD to update */
+ profiler_mark(PROFILER_BLIT);
+ osd_update(skipped_it);
+ profiler_mark(PROFILER_END);
+
+ /* perform tasks for this frame */
+ mame_frame_update(Machine);
+
+ /* update frameskipping */
+ update_frameskip();
+
+ /* update speed computations */
+ if (!skipped_it)
+ recompute_speed(current_time);
+
+ /* call the end-of-frame callback */
+ if (phase == MAME_PHASE_RUNNING)
+ {
+ /* reset partial updates if we're paused or if the debugger is active */
+ if (video_screen_exists(0) && (mame_is_paused(Machine) || mame_debug_is_active()))
+ scanline0_callback(Machine, 0);
+
+ /* otherwise, call the video EOF callback */
+ else if (Machine->drv->video_eof != NULL)
+ {
+ profiler_mark(PROFILER_VIDEO);
+ (*Machine->drv->video_eof)(Machine);
+ profiler_mark(PROFILER_END);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ finish_screen_updates - finish updating all
+ the screens
+-------------------------------------------------*/
+
+static int finish_screen_updates(running_machine *machine)
+{
+ video_private *viddata = machine->video_data;
+ int anything_changed = FALSE;
+ int livemask;
+ int scrnum;
+
+ /* finish updating the screens */
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ if (machine->drv->screen[scrnum].tag != NULL)
+ video_screen_update_partial(scrnum, machine->screen[scrnum].visarea.max_y);
+
+ /* now add the quads for all the screens */
+ livemask = render_get_live_screens_mask();
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ {
+ internal_screen_info *screen = &viddata->scrinfo[scrnum];
+
+ /* only update if live */
+ if (livemask & (1 << scrnum))
+ {
+ /* only update if empty and not a vector game; otherwise assume the driver did it directly */
+ if ((machine->drv->video_attributes & (VIDEO_TYPE_VECTOR | VIDEO_SELF_RENDER)) == 0)
+ {
+ /* if we're not skipping the frame and if the screen actually changed, then update the texture */
+ if (!global.skipping_this_frame && screen->changed)
+ {
+ mame_bitmap *bitmap = screen->bitmap[screen->curbitmap];
+ rectangle fixedvis = machine->screen[scrnum].visarea;
+ fixedvis.max_x++;
+ fixedvis.max_y++;
+ render_texture_set_bitmap(screen->texture[screen->curbitmap], bitmap, &fixedvis, machine->drv->screen[scrnum].palette_base, screen->format);
+ screen->curtexture = screen->curbitmap;
+ screen->curbitmap = 1 - screen->curbitmap;
+ }
+
+ /* create an empty container with a single quad */
+ render_container_empty(render_container_get_screen(scrnum));
+ render_screen_add_quad(scrnum, 0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0xff,0xff,0xff), screen->texture[screen->curtexture], PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1));
+ }
+
+ /* update our movie recording state */
+ if (!mame_is_paused(machine))
+ movie_record_frame(machine, scrnum);
+ }
+
+ /* reset the screen changed flags */
+ if (screen->changed)
+ anything_changed = TRUE;
+ screen->changed = FALSE;
+ }
+
+ /* draw any crosshairs */
+ crosshair_render(viddata);
+ return anything_changed;
+}
+
+
+
+/***************************************************************************
+ THROTTLING/FRAMESKIPPING/PERFORMANCE
+***************************************************************************/
+
+/*-------------------------------------------------
+ video_skip_this_frame - accessor to determine
+ if this frame is being skipped
+-------------------------------------------------*/
+
+int video_skip_this_frame(void)
+{
+ return global.skipping_this_frame;
+}
+
+
+/*-------------------------------------------------
+ video_get_speed_factor - return the speed
+ factor as an integer * 100
+-------------------------------------------------*/
+
+int video_get_speed_factor(void)
+{
+ return global.speed;
+}
+
+
+/*-------------------------------------------------
+ video_set_speed_factor - sets the speed
+ factor as an integer * 100
+-------------------------------------------------*/
+
+void video_set_speed_factor(int speed)
+{
+ global.speed = speed;
+}
+
+
+/*-------------------------------------------------
+ video_get_speed_text - print the text to
+ be displayed in the upper-right corner
+-------------------------------------------------*/
+
+const char *video_get_speed_text(void)
+{
+ int paused = mame_is_paused(Machine);
+ static char buffer[1024];
+ char *dest = buffer;
+
+ /* if we're paused, just display Paused */
+ if (paused)
+ dest += sprintf(dest, "paused");
+
+ /* if we're fast forwarding, just display Fast-forward */
+ else if (global.fastforward)
+ dest += sprintf(dest, "fast ");
+
+ /* if we're auto frameskipping, display that plus the level */
+ else if (effective_autoframeskip())
+ dest += sprintf(dest, "auto%2d/%d", effective_frameskip(), MAX_FRAMESKIP);
+
+ /* otherwise, just display the frameskip plus the level */
+ else
+ dest += sprintf(dest, "skip %d/%d", effective_frameskip(), MAX_FRAMESKIP);
+
+ /* append the speed for all cases except paused */
+ if (!paused)
+ dest += sprintf(dest, "%4d%%", (int)(100 * global.speed_percent + 0.5));
+
+ /* display the number of partial updates as well */
+ if (global.partial_updates_this_frame > 1)
+ dest += sprintf(dest, "\n%d partial updates", global.partial_updates_this_frame);
+
+ /* return a pointer to the static buffer */
+ return buffer;
+}
+
+
+/*-------------------------------------------------
+ video_get_frameskip - return the current
+ actual frameskip (-1 means autoframeskip)
+-------------------------------------------------*/
+
+int video_get_frameskip(void)
+{
+ /* if autoframeskip is on, return -1 */
+ if (global.auto_frameskip)
+ return -1;
+
+ /* otherwise, return the direct level */
+ else
+ return global.frameskip_level;
+}
+
+
+/*-------------------------------------------------
+ video_set_frameskip - set the current
+ actual frameskip (-1 means autoframeskip)
+-------------------------------------------------*/
+
+void video_set_frameskip(int frameskip)
+{
+ /* -1 means autoframeskip */
+ if (frameskip == -1)
+ {
+ global.auto_frameskip = TRUE;
+ global.frameskip_level = 0;
+ }
+
+ /* any other level is a direct control */
+ else if (frameskip >= 0 && frameskip <= MAX_FRAMESKIP)
+ {
+ global.auto_frameskip = FALSE;
+ global.frameskip_level = frameskip;
+ }
+}
+
+
+/*-------------------------------------------------
+ video_get_throttle - return the current
+ actual throttle
+-------------------------------------------------*/
+
+int video_get_throttle(void)
+{
+ return global.throttle;
+}
+
+
+/*-------------------------------------------------
+ video_set_throttle - set the current
+ actual throttle
+-------------------------------------------------*/
+
+void video_set_throttle(int throttle)
+{
+ global.throttle = throttle;
+}
+
+
+/*-------------------------------------------------
+ video_get_fastforward - return the current
+ fastforward value
+-------------------------------------------------*/
+
+int video_get_fastforward(void)
+{
+ return global.fastforward;
+}
+
+
+/*-------------------------------------------------
+ video_set_fastforward - set the current
+ fastforward value
+-------------------------------------------------*/
+
+void video_set_fastforward(int _fastforward)
+{
+ global.fastforward = _fastforward;
+}
+
+
+/*-------------------------------------------------
+ update_throttle - throttle to the game's
+ natural speed
+-------------------------------------------------*/
+
+static void update_throttle(attotime emutime)
+{
+/*
+
+ Throttling theory:
+
+ This routine is called periodically with an up-to-date emulated time.
+ The idea is to synchronize real time with emulated time. We do this
+ by "throttling", or waiting for real time to catch up with emulated
+ time.
+
+ In an ideal world, it will take less real time to emulate and render
+ each frame than the emulated time, so we need to slow things down to
+ get both times in sync.
+
+ There are many complications to this model:
+
+ * some games run too slow, so each frame we get further and
+ further behind real time; our only choice here is to not
+ throttle
+
+ * some games have very uneven frame rates; one frame will take
+ a long time to emulate, and the next frame may be very fast
+
+ * we run on top of multitasking OSes; sometimes execution time
+ is taken away from us, and this means we may not get enough
+ time to emulate one frame
+
+ * we may be paused, and emulated time may not be marching
+ forward
+
+ * emulated time could jump due to resetting the machine or
+ restoring from a saved state
+
+*/
+ static const UINT8 popcount[256] =
+ {
+ 0,1,1,2,1,2,2,3, 1,2,2,3,2,3,3,4, 1,2,2,3,2,3,3,4, 2,3,3,4,3,4,4,5,
+ 1,2,2,3,2,3,3,4, 2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6,
+ 1,2,2,3,2,3,3,4, 2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6,
+ 2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7,
+ 1,2,2,3,2,3,3,4, 2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6,
+ 2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7,
+ 2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7,
+ 3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7, 4,5,5,6,5,6,6,7, 5,6,6,7,6,7,7,8
+ };
+ attoseconds_t real_delta_attoseconds;
+ attoseconds_t emu_delta_attoseconds;
+ attoseconds_t real_is_ahead_attoseconds;
+ attoseconds_t attoseconds_per_tick;
+ osd_ticks_t ticks_per_second;
+ osd_ticks_t target_ticks;
+ osd_ticks_t diff_ticks;
+
+ /* apply speed factor to emu time */
+ if (global.speed != 0 && global.speed != 100)
+ {
+ /* multiply emutime by 100 */
+ emutime = attotime_mul(emutime, 100);
+
+ /* divide emutime by the global speed factor */
+ emutime.attoseconds /= global.speed;
+ emutime.attoseconds += (emutime.seconds % global.speed) * (ATTOSECONDS_PER_SECOND / global.speed);
+ emutime.seconds /= global.speed;
+ }
+
+ /* compute conversion factors up front */
+ ticks_per_second = osd_ticks_per_second();
+ attoseconds_per_tick = ATTOSECONDS_PER_SECOND / ticks_per_second;
+
+ /* if we're paused, emutime will not advance; instead, we subtract a fixed
+ amount of time (1/60th of a second) from the emulated time that was passed in,
+ and explicitly reset our tracked real and emulated timers to that value ...
+ this means we pretend that the last update was exactly 1/60th of a second
+ ago, and was in sync in both real and emulated time */
+ if (mame_is_paused(Machine))
+ {
+ global.throttle_emutime = attotime_sub_attoseconds(emutime, ATTOSECONDS_PER_SECOND / PAUSED_REFRESH_RATE);
+ global.throttle_realtime = global.throttle_emutime;
+ }
+
+ /* attempt to detect anomalies in the emulated time by subtracting the previously
+ reported value from our current value; this should be a small value somewhere
+ between 0 and 1/10th of a second ... anything outside of this range is obviously
+ wrong and requires a resync */
+ emu_delta_attoseconds = attotime_to_attoseconds(attotime_sub(emutime, global.throttle_emutime));
+ if (emu_delta_attoseconds < 0 || emu_delta_attoseconds > ATTOSECONDS_PER_SECOND / 10)
+ {
+ if (LOG_THROTTLE)
+ logerror("Resync due to weird emutime delta: %s\n", attotime_string(attotime_make(0, emu_delta_attoseconds), 18));
+ goto resync;
+ }
+
+ /* now determine the current real time in OSD-specified ticks; we have to be careful
+ here because counters can wrap, so we only use the difference between the last
+ read value and the current value in our computations */
+ diff_ticks = osd_ticks() - global.throttle_last_ticks;
+ global.throttle_last_ticks += diff_ticks;
+
+ /* if it has been more than a full second of real time since the last call to this
+ function, we just need to resynchronize */
+ if (diff_ticks >= ticks_per_second)
+ {
+ if (LOG_THROTTLE)
+ logerror("Resync due to real time advancing by more than 1 second\n");
+ goto resync;
+ }
+
+ /* convert this value into attoseconds for easier comparison */
+ real_delta_attoseconds = diff_ticks * attoseconds_per_tick;
+
+ /* now update our real and emulated timers with the current values */
+ global.throttle_emutime = emutime;
+ global.throttle_realtime = attotime_add_attoseconds(global.throttle_realtime, real_delta_attoseconds);
+
+ /* keep a history of whether or not emulated time beat real time over the last few
+ updates; this can be used for future heuristics */
+ global.throttle_history = (global.throttle_history << 1) | (emu_delta_attoseconds > real_delta_attoseconds);
+
+ /* determine how far ahead real time is versus emulated time; note that we use the
+ accumulated times for this instead of the deltas for the current update because
+ we want to track time over a longer duration than a single update */
+ real_is_ahead_attoseconds = attotime_to_attoseconds(attotime_sub(global.throttle_emutime, global.throttle_realtime));
+
+ /* if we're more than 1/10th of a second out, or if we are behind at all and emulation
+ is taking longer than the real frame, we just need to resync */
+ if (real_is_ahead_attoseconds < -ATTOSECONDS_PER_SECOND / 10 ||
+ (real_is_ahead_attoseconds < 0 && popcount[global.throttle_history & 0xff] < 6))
+ {
+ if (LOG_THROTTLE)
+ logerror("Resync due to being behind: %s (history=%08X)\n", attotime_string(attotime_make(0, -real_is_ahead_attoseconds), 18), global.throttle_history);
+ goto resync;
+ }
+
+ /* if we're behind, it's time to just get out */
+ if (real_is_ahead_attoseconds < 0)
+ return;
+
+ /* compute the target real time, in ticks, where we want to be */
+ target_ticks = global.throttle_last_ticks + real_is_ahead_attoseconds / attoseconds_per_tick;
+
+ /* throttle until we read the target, and update real time to match the final time */
+ diff_ticks = throttle_until_ticks(target_ticks) - global.throttle_last_ticks;
+ global.throttle_last_ticks += diff_ticks;
+ global.throttle_realtime = attotime_add_attoseconds(global.throttle_realtime, diff_ticks * attoseconds_per_tick);
+ return;
+
+resync:
+ /* reset realtime and emutime to the same value */
+ global.throttle_realtime = global.throttle_emutime = emutime;
+}
+
+
+/*-------------------------------------------------
+ throttle_until_ticks - spin until the
+ specified target time, calling the OSD code
+ to sleep if possible
+-------------------------------------------------*/
+
+static osd_ticks_t throttle_until_ticks(osd_ticks_t target_ticks)
+{
+ osd_ticks_t minimum_sleep = osd_ticks_per_second() / 1000;
+ osd_ticks_t current_ticks = osd_ticks();
+ osd_ticks_t new_ticks;
+ int allowed_to_sleep;
+
+ /* we're allowed to sleep via the OSD code only if we're configured to do so
+ and we're not frameskipping due to autoframeskip, or if we're paused */
+ allowed_to_sleep = mame_is_paused(Machine) ||
+ (global.sleep && (!effective_autoframeskip() || effective_frameskip() == 0));
+
+ /* loop until we reach our target */
+ profiler_mark(PROFILER_IDLE);
+ while (current_ticks < target_ticks)
+ {
+ osd_ticks_t delta;
+ int slept = FALSE;
+
+ /* compute how much time to sleep for, taking into account the average oversleep */
+ delta = (target_ticks - current_ticks) * 1000 / (1000 + global.average_oversleep);
+
+ /* see if we can sleep */
+ if (allowed_to_sleep && delta >= minimum_sleep)
+ {
+ osd_sleep(delta);
+ slept = TRUE;
+ }
+
+ /* read the new value */
+ new_ticks = osd_ticks();
+
+ /* keep some metrics on the sleeping patterns of the OSD layer */
+ if (slept)
+ {
+ osd_ticks_t actual_ticks = new_ticks - current_ticks;
+
+ /* if we overslept, keep an average of the amount */
+ if (actual_ticks > delta)
+ {
+ osd_ticks_t oversleep_milliticks = 1000 * (actual_ticks - delta) / delta;
+
+ /* take 90% of the previous average plus 10% of the new value */
+ global.average_oversleep = (global.average_oversleep * 99 + oversleep_milliticks) / 100;
+
+ if (LOG_THROTTLE)
+ logerror("Slept for %d ticks, got %d ticks, avgover = %d\n", (int)delta, (int)actual_ticks, (int)global.average_oversleep);
+ }
+ }
+ current_ticks = new_ticks;
+ }
+
+ return current_ticks;
+}
+
+
+/*-------------------------------------------------
+ update_frameskip - update frameskipping
+ counters and periodically update autoframeskip
+-------------------------------------------------*/
+
+static void update_frameskip(void)
+{
+ /* if we're throttling and autoframeskip is on, adjust */
+ if (effective_throttle() && effective_autoframeskip() && global.frameskip_counter == 0)
+ {
+ float speed = global.speed * 0.01;
+
+ /* if we're too fast, attempt to increase the frameskip */
+ if (global.speed_percent >= 0.995 * speed)
+ {
+ /* but only after 3 consecutive frames where we are too fast */
+ if (++global.frameskip_adjust >= 3)
+ {
+ global.frameskip_adjust = 0;
+ if (global.frameskip_level > 0)
+ global.frameskip_level--;
+ }
+ }
+
+ /* if we're too slow, attempt to increase the frameskip */
+ else
+ {
+ /* if below 80% speed, be more aggressive */
+ if (global.speed_percent < 0.80 * speed)
+ global.frameskip_adjust -= (0.90 * speed - global.speed_percent) / 0.05;
+
+ /* if we're close, only force it up to frameskip 8 */
+ else if (global.frameskip_level < 8)
+ global.frameskip_adjust--;
+
+ /* perform the adjustment */
+ while (global.frameskip_adjust <= -2)
+ {
+ global.frameskip_adjust += 2;
+ if (global.frameskip_level < MAX_FRAMESKIP)
+ global.frameskip_level++;
+ }
+ }
+ }
+
+ /* increment the frameskip counter and determine if we will skip the next frame */
+ global.frameskip_counter = (global.frameskip_counter + 1) % FRAMESKIP_LEVELS;
+ global.skipping_this_frame = skiptable[effective_frameskip()][global.frameskip_counter];
+}
+
+
+/*-------------------------------------------------
+ recompute_speed - recompute the current
+ overall speed; we assume this is called only
+ if we did not skip a frame
+-------------------------------------------------*/
+
+static void recompute_speed(attotime emutime)
+{
+ attoseconds_t delta_emutime;
+
+ /* if we don't have a starting time yet, or if we're paused, reset our starting point */
+ if (global.speed_last_realtime == 0 || mame_is_paused(Machine))
+ {
+ global.speed_last_realtime = osd_ticks();
+ global.speed_last_emutime = emutime;
+ }
+
+ /* if it has been more than the update interval, update the time */
+ delta_emutime = attotime_to_attoseconds(attotime_sub(emutime, global.speed_last_emutime));
+ if (delta_emutime > SUBSECONDS_PER_SPEED_UPDATE)
+ {
+ osd_ticks_t realtime = osd_ticks();
+ osd_ticks_t delta_realtime = realtime - global.speed_last_realtime;
+ osd_ticks_t tps = osd_ticks_per_second();
+
+ /* convert from ticks to attoseconds */
+ global.speed_percent = (double)delta_emutime * (double)tps / ((double)delta_realtime * (double)ATTOSECONDS_PER_SECOND);
+
+ /* remember the last times */
+ global.speed_last_realtime = realtime;
+ global.speed_last_emutime = emutime;
+
+ /* if we're throttled, this time period counts for overall speed; otherwise, we reset the counter */
+ if (!global.fastforward)
+ global.overall_valid_counter++;
+ else
+ global.overall_valid_counter = 0;
+
+ /* if we've had at least 4 consecutive valid periods, accumulate stats */
+ if (global.overall_valid_counter >= 4)
+ {
+ global.overall_real_ticks += delta_realtime;
+ while (global.overall_real_ticks >= tps)
+ {
+ global.overall_real_ticks -= tps;
+ global.overall_real_seconds++;
+ }
+ global.overall_emutime = attotime_add_attoseconds(global.overall_emutime, delta_emutime);
+ }
+ }
+
+ /* if we're past the "time-to-execute" requested, signal an exit */
+ if (global.seconds_to_run != 0 && emutime.seconds >= global.seconds_to_run)
+ {
+ astring *fname = astring_assemble_2(astring_alloc(), Machine->basename, PATH_SEPARATOR "final.png");
+ file_error filerr;
+ mame_file *file;
+
+ /* create a final screenshot */
+ filerr = mame_fopen(SEARCHPATH_SCREENSHOT, astring_c(fname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
+ if (filerr == FILERR_NONE)
+ {
+ video_screen_save_snapshot(Machine, file, 0);
+ mame_fclose(file);
+ }
+ astring_free(fname);
+
+ /* schedule our demise */
+ mame_schedule_exit(Machine);
+ }
+}
+
+
+
+/***************************************************************************
+ SCREEN SNAPSHOTS
+***************************************************************************/
+
+/*-------------------------------------------------
+ video_screen_save_snapshot - save a snapshot
+ to the given file handle
+-------------------------------------------------*/
+
+void video_screen_save_snapshot(running_machine *machine, mame_file *fp, int scrnum)
+{
+ const rgb_t *palette = (machine->palette != NULL) ? palette_entry_list_adjusted(machine->palette) : NULL;
+ png_info pnginfo = { 0 };
+ mame_bitmap *bitmap;
+ png_error error;
+ char text[256];
+
+ /* generate the bitmap to pass in */
+ bitmap = get_snapshot_bitmap(machine, scrnum);
+ if (bitmap == NULL)
+ return;
+
+ /* add two text entries describing the image */
+ sprintf(text, APPNAME " %s", build_version);
+ png_add_text(&pnginfo, "Software", text);
+ sprintf(text, "%s %s", machine->gamedrv->manufacturer, machine->gamedrv->description);
+ png_add_text(&pnginfo, "System", text);
+
+ /* now do the actual work */
+ error = png_write_bitmap(mame_core_file(fp), &pnginfo, machine->video_data->snap_bitmap, machine->drv->total_colors, palette);
+
+ /* free any data allocated */
+ png_free(&pnginfo);
+}
+
+
+/*-------------------------------------------------
+ video_save_active_screen_snapshots - save a
+ snapshot of all active screens
+-------------------------------------------------*/
+
+void video_save_active_screen_snapshots(running_machine *machine)
+{
+ UINT32 screenmask = render_get_live_screens_mask();
+ mame_file *fp;
+ int scrnum;
+
+ /* write one snapshot per visible screen */
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ if (screenmask & (1 << scrnum))
+ {
+ file_error filerr = mame_fopen_next(SEARCHPATH_SCREENSHOT, "png", &fp);
+ if (filerr == FILERR_NONE)
+ {
+ video_screen_save_snapshot(machine, fp, scrnum);
+ mame_fclose(fp);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ get_snapshot_bitmap - return a pointer to the
+ bitmap containing the screenshot for the
+ given screen number
+-------------------------------------------------*/
+
+static mame_bitmap *get_snapshot_bitmap(running_machine *machine, int scrnum)
+{
+ video_private *viddata = machine->video_data;
+ const render_primitive_list *primlist;
+ INT32 width, height;
+
+ assert(scrnum >= 0 && scrnum < MAX_SCREENS);
+
+ /* if no screens, do nothing */
+ if (viddata->snap_target == NULL)
+ return NULL;
+
+ /* select the appropriate view in our dummy target */
+ render_target_set_view(viddata->snap_target, scrnum);
+
+ /* get the minimum width/height and set it on the target */
+ render_target_get_minimum_size(viddata->snap_target, &width, &height);
+ render_target_set_bounds(viddata->snap_target, width, height, 0);
+
+ /* if we don't have a bitmap, or if it's not the right size, allocate a new one */
+ if (viddata->snap_bitmap == NULL || width != viddata->snap_bitmap->width || height != viddata->snap_bitmap->height)
+ {
+ if (viddata->snap_bitmap != NULL)
+ bitmap_free(viddata->snap_bitmap);
+ viddata->snap_bitmap = bitmap_alloc(width, height, BITMAP_FORMAT_RGB32);
+ assert(viddata->snap_bitmap != NULL);
+ }
+
+ /* render the screen there */
+ primlist = render_target_get_primitives(viddata->snap_target);
+ osd_lock_acquire(primlist->lock);
+ rgb888_draw_primitives(primlist->head, viddata->snap_bitmap->base, width, height, viddata->snap_bitmap->rowpixels);
+ osd_lock_release(primlist->lock);
+
+ /* now do the actual work */
+ return viddata->snap_bitmap;
+}
+
+
+/*-------------------------------------------------
+ mame_fopen_next - open the next non-existing
+ file of type filetype according to our
+ numbering scheme
+-------------------------------------------------*/
+
+static file_error mame_fopen_next(const char *pathoption, const char *extension, mame_file **file)
+{
+ file_error filerr;
+ char *fname;
+ int seq;
+
+ /* allocate temp space for the name */
+ fname = malloc_or_die(strlen(Machine->basename) + 1 + 10 + strlen(extension) + 1);
+
+ /* try until we succeed */
+ for (seq = 0; ; seq++)
+ {
+ sprintf(fname, "%s" PATH_SEPARATOR "%04d.%s", Machine->basename, seq, extension);
+ filerr = mame_fopen(pathoption, fname, OPEN_FLAG_READ, file);
+ if (filerr != FILERR_NONE)
+ break;
+ mame_fclose(*file);
+ }
+
+ /* create the final file */
+ filerr = mame_fopen(pathoption, fname, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, file);
+
+ /* free the name and get out */
+ free(fname);
+ return filerr;
+}
+
+
+
+/***************************************************************************
+ MNG MOVIE RECORDING
+***************************************************************************/
+
+/*-------------------------------------------------
+ video_is_movie_active - return true if a movie
+ is currently being recorded
+-------------------------------------------------*/
+
+int video_is_movie_active(running_machine *machine, int scrnum)
+{
+ video_private *viddata = machine->video_data;
+ internal_screen_info *info = &viddata->scrinfo[scrnum];
+ return (info->movie_file != NULL);
+}
+
+
+/*-------------------------------------------------
+ video_movie_begin_recording - begin recording
+ of a MNG movie
+-------------------------------------------------*/
+
+void video_movie_begin_recording(running_machine *machine, int scrnum, const char *name)
+{
+ video_private *viddata = machine->video_data;
+ internal_screen_info *info = &viddata->scrinfo[scrnum];
+ file_error filerr;
+
+ /* close any existing movie file */
+ if (info->movie_file != NULL)
+ video_movie_end_recording(machine, scrnum);
+
+ /* create a new movie file and start recording */
+ if (name != NULL)
+ filerr = mame_fopen(SEARCHPATH_MOVIE, name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &info->movie_file);
+ else
+ filerr = mame_fopen_next(SEARCHPATH_MOVIE, "mng", &info->movie_file);
+ info->movie_frame = 0;
+}
+
+
+/*-------------------------------------------------
+ video_movie_end_recording - stop recording of
+ a MNG movie
+-------------------------------------------------*/
+
+void video_movie_end_recording(running_machine *machine, int scrnum)
+{
+ video_private *viddata = machine->video_data;
+ internal_screen_info *info = &viddata->scrinfo[scrnum];
+
+ /* close the file if it exists */
+ if (info->movie_file != NULL)
+ {
+ mng_capture_stop(mame_core_file(info->movie_file));
+ mame_fclose(info->movie_file);
+ info->movie_file = NULL;
+ info->movie_frame = 0;
+ }
+}
+
+
+/*-------------------------------------------------
+ movie_record_frame - record a frame of a
+ movie
+-------------------------------------------------*/
+
+static void movie_record_frame(running_machine *machine, int scrnum)
+{
+ video_private *viddata = machine->video_data;
+ internal_screen_info *info = &viddata->scrinfo[scrnum];
+
+ /* only record if we have a file */
+ if (info->movie_file != NULL)
+ {
+ png_info pnginfo = { 0 };
+ mame_bitmap *bitmap;
+ png_error error;
+
+ profiler_mark(PROFILER_MOVIE_REC);
+
+ /* get the bitmap */
+ bitmap = get_snapshot_bitmap(machine, scrnum);
+ if (bitmap == NULL)
+ return;
+
+ /* track frames */
+ if (info->movie_frame++ == 0)
+ {
+ char text[256];
+
+ /* set up the text fields in the movie info */
+ sprintf(text, APPNAME " %s", build_version);
+ png_add_text(&pnginfo, "Software", text);
+ sprintf(text, "%s %s", machine->gamedrv->manufacturer, machine->gamedrv->description);
+ png_add_text(&pnginfo, "System", text);
+
+ /* start the capture */
+ error = mng_capture_start(mame_core_file(info->movie_file), bitmap, ATTOSECONDS_TO_HZ(viddata->scrinfo[scrnum].state->refresh));
+ if (error != PNGERR_NONE)
+ {
+ png_free(&pnginfo);
+ video_movie_end_recording(machine, scrnum);
+ return;
+ }
+ }
+
+ /* write the next frame */
+ error = mng_capture_frame(mame_core_file(info->movie_file), &pnginfo, bitmap, machine->drv->total_colors, palette_entry_list_adjusted(machine->palette));
+ png_free(&pnginfo);
+ if (error != PNGERR_NONE)
+ {
+ video_movie_end_recording(machine, scrnum);
+ return;
+ }
+
+ profiler_mark(PROFILER_END);
+ }
+}
+
+
+
+/***************************************************************************
+ CROSSHAIR RENDERING
+***************************************************************************/
+
+/* decripton of the bitmap data */
+#define CROSSHAIR_RAW_SIZE 100
+#define CROSSHAIR_RAW_ROWBYTES ((CROSSHAIR_RAW_SIZE + 7) / 8)
+
+/* raw bitmap */
+static const UINT8 crosshair_raw_top[] =
+{
+ 0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,
+ 0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,
+ 0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF0,0x00,
+ 0x01,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,0x00,
+ 0x03,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFC,0x00,
+ 0x07,0xFE,0x00,0x00,0x00,0x0F,0xFE,0x00,0x00,0x00,0x07,0xFE,0x00,
+ 0x0F,0xFF,0x00,0x00,0x01,0xFF,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0x00,
+ 0x1F,0xFF,0x80,0x00,0x1F,0xFF,0xFF,0xFF,0x00,0x00,0x1F,0xFF,0x80,
+ 0x3F,0xFF,0x80,0x00,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x1F,0xFF,0xC0,
+ 0x7F,0xFF,0xC0,0x03,0xFF,0xFF,0xFF,0xFF,0xF8,0x00,0x3F,0xFF,0xE0,
+ 0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xFF,0xFF,0xFC,0x00,0x7F,0xFF,0xF0,
+ 0x7F,0xFF,0xF0,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xE0,
+ 0x3F,0xFF,0xF8,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC1,0xFF,0xFF,0xC0,
+ 0x0F,0xFF,0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1,0xFF,0xFF,0x00,
+ 0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFE,0x00,
+ 0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0x00,
+ 0x01,0xFF,0xFF,0xFF,0xFF,0xF0,0x01,0xFF,0xFF,0xFF,0xFF,0xF8,0x00,
+ 0x00,0x7F,0xFF,0xFF,0xFF,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xE0,0x00,
+ 0x00,0x3F,0xFF,0xFF,0xF8,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xC0,0x00,
+ 0x00,0x1F,0xFF,0xFF,0xE0,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x80,0x00,
+ 0x00,0x0F,0xFF,0xFF,0x80,0x00,0x00,0x00,0x3F,0xFF,0xFF,0x00,0x00,
+ 0x00,0x03,0xFF,0xFE,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFC,0x00,0x00,
+ 0x00,0x01,0xFF,0xFC,0x00,0x00,0x00,0x00,0x07,0xFF,0xF8,0x00,0x00,
+ 0x00,0x03,0xFF,0xF8,0x00,0x00,0x00,0x00,0x01,0xFF,0xF8,0x00,0x00,
+ 0x00,0x07,0xFF,0xFC,0x00,0x00,0x00,0x00,0x03,0xFF,0xFC,0x00,0x00,
+ 0x00,0x0F,0xFF,0xFE,0x00,0x00,0x00,0x00,0x07,0xFF,0xFE,0x00,0x00,
+ 0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFE,0x00,0x00,
+ 0x00,0x1F,0xFF,0xFF,0x80,0x00,0x00,0x00,0x1F,0xFF,0xFF,0x00,0x00,
+ 0x00,0x1F,0xFF,0xFF,0x80,0x00,0x00,0x00,0x1F,0xFF,0xFF,0x00,0x00,
+ 0x00,0x3F,0xFE,0xFF,0xC0,0x00,0x00,0x00,0x3F,0xFF,0xFF,0x80,0x00,
+ 0x00,0x7F,0xFC,0x7F,0xE0,0x00,0x00,0x00,0x7F,0xE7,0xFF,0xC0,0x00,
+ 0x00,0x7F,0xF8,0x3F,0xF0,0x00,0x00,0x00,0xFF,0xC3,0xFF,0xC0,0x00,
+ 0x00,0xFF,0xF8,0x1F,0xF8,0x00,0x00,0x01,0xFF,0x83,0xFF,0xE0,0x00,
+ 0x00,0xFF,0xF0,0x07,0xF8,0x00,0x00,0x01,0xFE,0x01,0xFF,0xE0,0x00,
+ 0x00,0xFF,0xF0,0x03,0xFC,0x00,0x00,0x03,0xFC,0x01,0xFF,0xE0,0x00,
+ 0x01,0xFF,0xE0,0x01,0xFE,0x00,0x00,0x07,0xF8,0x00,0xFF,0xF0,0x00,
+ 0x01,0xFF,0xE0,0x00,0xFF,0x00,0x00,0x0F,0xF0,0x00,0xFF,0xF0,0x00,
+ 0x01,0xFF,0xC0,0x00,0x3F,0x80,0x00,0x1F,0xC0,0x00,0x7F,0xF0,0x00,
+ 0x01,0xFF,0xC0,0x00,0x1F,0x80,0x00,0x1F,0x80,0x00,0x7F,0xF0,0x00,
+ 0x03,0xFF,0xC0,0x00,0x0F,0xC0,0x00,0x3F,0x00,0x00,0x7F,0xF8,0x00,
+ 0x03,0xFF,0x80,0x00,0x07,0xE0,0x00,0x7E,0x00,0x00,0x3F,0xF8,0x00,
+ 0x03,0xFF,0x80,0x00,0x01,0xF0,0x00,0xF8,0x00,0x00,0x3F,0xF8,0x00,
+ 0x03,0xFF,0x80,0x00,0x00,0xF8,0x01,0xF0,0x00,0x00,0x3F,0xF8,0x00,
+ 0x03,0xFF,0x80,0x00,0x00,0x78,0x01,0xE0,0x00,0x00,0x3F,0xF8,0x00,
+ 0x07,0xFF,0x00,0x00,0x00,0x3C,0x03,0xC0,0x00,0x00,0x3F,0xFC,0x00,
+ 0x07,0xFF,0x00,0x00,0x00,0x0E,0x07,0x00,0x00,0x00,0x1F,0xFC,0x00,
+ 0x07,0xFF,0x00,0x00,0x00,0x07,0x0E,0x00,0x00,0x00,0x1F,0xFC,0x00,
+ 0x07,0xFF,0x00,0x00,0x00,0x03,0x9C,0x00,0x00,0x00,0x1F,0xFC,0x00,
+ 0x07,0xFF,0x00,0x00,0x00,0x01,0x98,0x00,0x00,0x00,0x1F,0xFC,0x00,
+ 0x07,0xFF,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x1F,0xFC,0x00
+};
+
+/* per-player colors */
+static const rgb_t crosshair_colors[] =
+{
+ MAKE_RGB(0x40,0x40,0xff),
+ MAKE_RGB(0xff,0x40,0x40),
+ MAKE_RGB(0x40,0xff,0x40),
+ MAKE_RGB(0xff,0xff,0x40),
+ MAKE_RGB(0xff,0x40,0xff),
+ MAKE_RGB(0x40,0xff,0xff),
+ MAKE_RGB(0xff,0xff,0xff)
+};
+
+
+/*-------------------------------------------------
+ crosshair_init - initialize the crosshair
+ bitmaps and such
+-------------------------------------------------*/
+
+static void crosshair_init(video_private *viddata)
+{
+ input_port_entry *ipt;
+ int player;
+
+ /* determine who needs crosshairs */
+ viddata->crosshair_needed = 0x00;
+ for (ipt = Machine->input_ports; ipt->type != IPT_END; ipt++)
+ if (ipt->analog.crossaxis != CROSSHAIR_AXIS_NONE)
+ viddata->crosshair_needed |= 1 << ipt->player;
+
+ /* all visible by default */
+ viddata->crosshair_visible = viddata->crosshair_needed;
+
+ /* loop over each player and load or create a bitmap */
+ for (player = 0; player < MAX_PLAYERS; player++)
+ if (viddata->crosshair_needed & (1 << player))
+ {
+ char filename[20];
+
+ /* first try to load a bitmap for the crosshair */
+ sprintf(filename, "cross%d.png", player);
+ viddata->crosshair_bitmap[player] = render_load_png(NULL, filename, NULL, NULL);
+
+ /* if that didn't work, make one up */
+ if (viddata->crosshair_bitmap[player] == NULL)
+ {
+ rgb_t color = crosshair_colors[player];
+ int x, y;
+
+ /* allocate a blank bitmap to start with */
+ viddata->crosshair_bitmap[player] = bitmap_alloc(CROSSHAIR_RAW_SIZE, CROSSHAIR_RAW_SIZE, BITMAP_FORMAT_ARGB32);
+ fillbitmap(viddata->crosshair_bitmap[player], MAKE_ARGB(0x00,0xff,0xff,0xff), NULL);
+
+ /* extract the raw source data to it */
+ for (y = 0; y < CROSSHAIR_RAW_SIZE / 2; y++)
+ {
+ /* assume it is mirrored vertically */
+ UINT32 *dest0 = BITMAP_ADDR32(viddata->crosshair_bitmap[player], y, 0);
+ UINT32 *dest1 = BITMAP_ADDR32(viddata->crosshair_bitmap[player], CROSSHAIR_RAW_SIZE - 1 - y, 0);
+
+ /* extract to two rows simultaneously */
+ for (x = 0; x < CROSSHAIR_RAW_SIZE; x++)
+ if ((crosshair_raw_top[y * CROSSHAIR_RAW_ROWBYTES + x / 8] << (x % 8)) & 0x80)
+ dest0[x] = dest1[x] = MAKE_ARGB(0xff,0x00,0x00,0x00) | color;
+ }
+ }
+
+ /* create a texture to reference the bitmap */
+ viddata->crosshair_texture[player] = render_texture_alloc(render_texture_hq_scale, NULL);
+ render_texture_set_bitmap(viddata->crosshair_texture[player], viddata->crosshair_bitmap[player], NULL, 0, TEXFORMAT_ARGB32);
+ }
+}
+
+
+/*-------------------------------------------------
+ video_crosshair_toggle - toggle crosshair
+ visibility
+-------------------------------------------------*/
+
+void video_crosshair_toggle(void)
+{
+ video_private *viddata = Machine->video_data;
+ int player;
+
+ /* if we're all visible, turn all off */
+ if (viddata->crosshair_visible == viddata->crosshair_needed)
+ viddata->crosshair_visible = 0;
+
+ /* otherwise, turn on the first bit that isn't currently on and stop there */
+ else
+ for (player = 0; player < MAX_PLAYERS; player++)
+ if ((viddata->crosshair_needed & (1 << player)) && !(viddata->crosshair_visible & (1 << player)))
+ {
+ viddata->crosshair_visible |= 1 << player;
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ get_crosshair_screen_mask - returns a bitmask
+ indicating on which screens the crosshair for
+ a player's should be displayed
+-------------------------------------------------*/
+
+static UINT32 get_crosshair_screen_mask(video_private *viddata, int player)
+{
+ return (viddata->crosshair_visible & (1 << player)) ? 1 : 0;
+}
+
+
+/*-------------------------------------------------
+ crosshair_render - render the crosshairs
+-------------------------------------------------*/
+
+static void crosshair_render(video_private *viddata)
+{
+ float x[MAX_PLAYERS], y[MAX_PLAYERS];
+ input_port_entry *ipt;
+ int portnum = -1;
+ int player;
+ UINT8 tscale;
+
+ /* skip if not needed */
+ if (viddata->crosshair_visible == 0)
+ return;
+
+ /* animate via crosshair_animate */
+ viddata->crosshair_animate += 0x04;
+
+ /* compute a color scaling factor from the current animation value */
+ if (viddata->crosshair_animate < 0x80)
+ tscale = 0xa0 + (0x60 * ( viddata->crosshair_animate & 0x7f) / 0x80);
+ else
+ tscale = 0xa0 + (0x60 * (~viddata->crosshair_animate & 0x7f) / 0x80);
+
+ /* read all the lightgun values */
+ for (ipt = Machine->input_ports; ipt->type != IPT_END; ipt++)
+ {
+ /* keep track of the port number */
+ if (ipt->type == IPT_PORT)
+ portnum++;
+
+ /* compute the values */
+ if (ipt->analog.crossaxis != CROSSHAIR_AXIS_NONE)
+ {
+ float value = (float)(get_crosshair_pos(portnum, ipt->player, ipt->analog.crossaxis) - ipt->analog.min) / (float)(ipt->analog.max - ipt->analog.min);
+ if (ipt->analog.crossscale < 0)
+ value = -(1.0 - value) * ipt->analog.crossscale;
+ else
+ value *= ipt->analog.crossscale;
+ value += ipt->analog.crossoffset;
+
+ /* switch off the axis */
+ switch (ipt->analog.crossaxis)
+ {
+ case CROSSHAIR_AXIS_X:
+ x[ipt->player] = value;
+ if (ipt->analog.crossaltaxis != 0)
+ y[ipt->player] = ipt->analog.crossaltaxis;
+ break;
+
+ case CROSSHAIR_AXIS_Y:
+ y[ipt->player] = value;
+ if (ipt->analog.crossaltaxis != 0)
+ x[ipt->player] = ipt->analog.crossaltaxis;
+ break;
+ }
+ }
+ }
+
+ /* draw all crosshairs */
+ for (player = 0; player < MAX_PLAYERS; player++)
+ {
+ UINT32 scrmask = get_crosshair_screen_mask(viddata, player);
+ if (scrmask != 0)
+ {
+ int scrnum;
+
+ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
+ {
+ if (scrmask & (1 << scrnum))
+ {
+ /* add a quad assuming a 4:3 screen (this is not perfect) */
+ render_screen_add_quad(scrnum,
+ x[player] - 0.03f, y[player] - 0.04f,
+ x[player] + 0.03f, y[player] + 0.04f,
+ MAKE_ARGB(0xc0, tscale, tscale, tscale),
+ viddata->crosshair_texture[player], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ crosshair_free - free memory allocated for
+ the crosshairs
+-------------------------------------------------*/
+
+static void crosshair_free(video_private *viddata)
+{
+ int player;
+
+ /* free bitmaps and textures for each player */
+ for (player = 0; player < MAX_PLAYERS; player++)
+ {
+ if (viddata->crosshair_texture[player] != NULL)
+ render_texture_free(viddata->crosshair_texture[player]);
+ viddata->crosshair_texture[player] = NULL;
+
+ if (viddata->crosshair_bitmap[player] != NULL)
+ bitmap_free(viddata->crosshair_bitmap[player]);
+ viddata->crosshair_bitmap[player] = NULL;
+ }
+}
+
+
+
+/***************************************************************************
+ SOFTWARE RENDERING
+***************************************************************************/
+
+#define FUNC_PREFIX(x) rgb888_##x
+#define PIXEL_TYPE UINT32
+#define SRCSHIFT_R 0
+#define SRCSHIFT_G 0
+#define SRCSHIFT_B 0
+#define DSTSHIFT_R 16
+#define DSTSHIFT_G 8
+#define DSTSHIFT_B 0
+
+#include "rendersw.c"
diff --git a/src/emu/video.h b/src/emu/video.h
new file mode 100644
index 00000000000..da602318588
--- /dev/null
+++ b/src/emu/video.h
@@ -0,0 +1,169 @@
+/***************************************************************************
+
+ video.h
+
+ Core MAME video routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __VIDEO_H__
+#define __VIDEO_H__
+
+#include "mamecore.h"
+#include "timer.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* maximum number of screens for one game */
+#define MAX_SCREENS 8
+
+/* number of levels of frameskipping supported */
+#define FRAMESKIP_LEVELS 12
+#define MAX_FRAMESKIP (FRAMESKIP_LEVELS - 2)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ screen_state - current live state of a screen
+-------------------------------------------------*/
+
+typedef struct _screen_state screen_state;
+struct _screen_state
+{
+ int width, height; /* total width/height (HTOTAL, VTOTAL) */
+ rectangle visarea; /* visible area (HBLANK end/start, VBLANK end/start) */
+ UINT8 oldstyle_vblank_supplied; /* MDRV_SCREEN_VBLANK_TIME macro used */
+ attoseconds_t refresh; /* refresh period */
+ attoseconds_t vblank; /* duration of a VBLANK */
+ bitmap_format format; /* bitmap format */
+};
+
+
+/*-------------------------------------------------
+ screen_config - configuration of a single
+ screen
+-------------------------------------------------*/
+
+typedef struct _screen_config screen_config;
+struct _screen_config
+{
+ const char * tag; /* nametag for the screen */
+ UINT32 palette_base; /* base palette entry for this screen */
+ screen_state defstate; /* default state */
+ float xoffset, yoffset; /* default X/Y offsets */
+ float xscale, yscale; /* default X/Y scale factor */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* ----- core implementation ----- */
+
+/* core initialization */
+void video_init(running_machine *machine);
+
+/* core VBLANK callback */
+void video_vblank_start(running_machine *machine);
+
+
+/* ----- screen management ----- */
+
+/* set the resolution of a screen */
+void video_screen_configure(int scrnum, int width, int height, const rectangle *visarea, attoseconds_t refresh);
+
+/* set the visible area of a screen; this is a subset of video_screen_configure */
+void video_screen_set_visarea(int scrnum, int min_x, int max_x, int min_y, int max_y);
+
+/* force a partial update of the screen up to and including the requested scanline */
+void video_screen_update_partial(int scrnum, int scanline);
+
+/* return the current vertical or horizontal position of the beam for a screen */
+int video_screen_get_vpos(int scrnum);
+int video_screen_get_hpos(int scrnum);
+
+/* return the current vertical or horizontal blanking state for a screen */
+int video_screen_get_vblank(int scrnum);
+int video_screen_get_hblank(int scrnum);
+
+/* return the time when the beam will reach a particular H,V position */
+attotime video_screen_get_time_until_pos(int scrnum, int vpos, int hpos);
+
+/* return the amount of time the beam takes to draw one scan line */
+attotime video_screen_get_scan_period(int scrnum);
+
+/* return the amount of time the beam takes to draw one complete frame */
+attotime video_screen_get_frame_period(int scrnum);
+
+/* returns whether a given screen exists */
+int video_screen_exists(int scrnum);
+
+
+
+/* ----- global rendering ----- */
+
+/* update the screen, handling frame skipping and rendering */
+void video_frame_update(void);
+
+
+/* ----- throttling/frameskipping/performance ----- */
+
+/* are we skipping the current frame? */
+int video_skip_this_frame(void);
+
+/* get/set the speed factor as an integer * 100 */
+int video_get_speed_factor(void);
+void video_set_speed_factor(int speed);
+
+/* return text to display about the current speed */
+const char *video_get_speed_text(void);
+
+/* get/set the current frameskip (-1 means auto) */
+int video_get_frameskip(void);
+void video_set_frameskip(int frameskip);
+
+/* get/set the current throttle */
+int video_get_throttle(void);
+void video_set_throttle(int throttle);
+
+/* get/set the current fastforward state */
+int video_get_fastforward(void);
+void video_set_fastforward(int fastforward);
+
+
+/* ----- snapshots ----- */
+
+/* save a snapshot of a given screen */
+void video_screen_save_snapshot(running_machine *machine, mame_file *fp, int scrnum);
+
+/* save a snapshot of all the active screens */
+void video_save_active_screen_snapshots(running_machine *machine);
+
+
+/* ----- movie recording ----- */
+
+/* Movie recording */
+int video_is_movie_active(running_machine *machine, int scrnum);
+void video_movie_begin_recording(running_machine *machine, int scrnum, const char *name);
+void video_movie_end_recording(running_machine *machine, int scrnum);
+
+
+/* ----- crosshair rendering ----- */
+
+void video_crosshair_toggle(void);
+
+#endif /* __VIDEO_H__ */
diff --git a/src/emu/video/cdp1869.c b/src/emu/video/cdp1869.c
new file mode 100644
index 00000000000..2c32b4834d5
--- /dev/null
+++ b/src/emu/video/cdp1869.c
@@ -0,0 +1,569 @@
+#include "driver.h"
+#include "cpu/cdp1802/cdp1802.h"
+#include "video/cdp1869.h"
+#include "sound/cdp1869.h"
+
+typedef struct
+{
+ int ntsc_pal;
+ int dispoff;
+ int fresvert, freshorz;
+ int dblpage, line16, line9, cmem, cfc;
+ UINT8 col, bkg;
+ UINT16 pma, hma;
+ UINT8 cram[CDP1869_CHARRAM_SIZE];
+ UINT8 pram[CDP1869_PAGERAM_SIZE];
+ int cramsize, pramsize;
+ UINT8 (*color_callback)(UINT8 cramdata, UINT16 cramaddr, UINT16 pramaddr);
+} CDP1869_VIDEO_CONFIG;
+
+static CDP1869_VIDEO_CONFIG cdp1869;
+
+static UINT16 cdp1802_get_r_x(void)
+{
+ return activecpu_get_reg(CDP1802_R0 + activecpu_get_reg(CDP1802_X));
+}
+
+WRITE8_HANDLER ( cdp1869_out3_w )
+{
+ /*
+ bit description
+
+ 0 bkg green
+ 1 bkg blue
+ 2 bkg red
+ 3 cfc
+ 4 disp off
+ 5 colb0
+ 6 colb1
+ 7 fres horz
+ */
+
+ cdp1869.bkg = (data & 0x07);
+ cdp1869.cfc = (data & 0x08) >> 3;
+ cdp1869.dispoff = (data & 0x10) >> 4;
+ cdp1869.col = (data & 0x60) >> 5;
+ cdp1869.freshorz = (data & 0x80) >> 7;
+}
+
+WRITE8_HANDLER ( cdp1869_out4_w )
+{
+ UINT16 word = cdp1802_get_r_x();
+
+ /*
+ bit description
+
+ 0 tone amp 2^0
+ 1 tone amp 2^1
+ 2 tone amp 2^2
+ 3 tone amp 2^3
+ 4 tone freq sel0
+ 5 tone freq sel1
+ 6 tone freq sel2
+ 7 tone off
+ 8 tone / 2^0
+ 9 tone / 2^1
+ 10 tone / 2^2
+ 11 tone / 2^3
+ 12 tone / 2^4
+ 13 tone / 2^5
+ 14 tone / 2^6
+ 15 always 0
+ */
+
+ cdp1869_set_toneamp(0, word & 0x0f);
+ cdp1869_set_tonefreq(0, (word & 0x70) >> 4);
+ cdp1869_set_toneoff(0, (word & 0x80) >> 7);
+ cdp1869_set_tonediv(0, (word & 0x7f00) >> 8);
+}
+
+WRITE8_HANDLER ( cdp1869_out5_w )
+{
+ UINT16 word = cdp1802_get_r_x();
+
+ /*
+ bit description
+
+ 0 cmem access mode
+ 1 x
+ 2 x
+ 3 9-line
+ 4 x
+ 5 16 line hi-res
+ 6 double page
+ 7 fres vert
+ 8 wn amp 2^0
+ 9 wn amp 2^1
+ 10 wn amp 2^2
+ 11 wn amp 2^3
+ 12 wn freq sel0
+ 13 wn freq sel1
+ 14 wn freq sel2
+ 15 wn off
+ */
+
+ cdp1869.cmem = (word & 0x01);
+ cdp1869.line9 = (word & 0x08) >> 3;
+ cdp1869.line16 = (word & 0x20) >> 5;
+ cdp1869.dblpage = (word & 0x40) >> 6;
+ cdp1869.fresvert = (word & 0x80) >> 7;
+
+ cdp1869_set_wnamp(0, (word & 0x0f00) >> 8);
+ cdp1869_set_wnfreq(0, (word & 0x7000) >> 12);
+ cdp1869_set_wnoff(0, (word & 0x8000) >> 15);
+}
+
+WRITE8_HANDLER ( cdp1869_out6_w )
+{
+ UINT16 word = cdp1802_get_r_x();
+
+ /*
+ bit description
+
+ 0 pma0 reg
+ 1 pma1 reg
+ 2 pma2 reg
+ 3 pma3 reg
+ 4 pma4 reg
+ 5 pma5 reg
+ 6 pma6 reg
+ 7 pma7 reg
+ 8 pma8 reg
+ 9 pma9 reg
+ 10 pma10 reg
+ 11 x
+ 12 x
+ 13 x
+ 14 x
+ 15 x
+ */
+
+ cdp1869.pma = word & 0x7ff;
+}
+
+WRITE8_HANDLER ( cdp1869_out7_w )
+{
+ UINT16 word = cdp1802_get_r_x();
+
+ /*
+ bit description
+
+ 0 x
+ 1 x
+ 2 hma2 reg
+ 3 hma3 reg
+ 4 hma4 reg
+ 5 hma5 reg
+ 6 hma6 reg
+ 7 hma7 reg
+ 8 hma8 reg
+ 9 hma9 reg
+ 10 hma10 reg
+ 11 x
+ 12 x
+ 13 x
+ 14 x
+ 15 x
+ */
+
+ cdp1869.hma = word & 0x7fc;
+}
+
+static void cdp1869_set_color(int i, int c, int l)
+{
+ int luma = 0, r, g, b;
+
+ luma += (l & 4) ? CDP1869_WEIGHT_RED : 0;
+ luma += (l & 1) ? CDP1869_WEIGHT_GREEN : 0;
+ luma += (l & 2) ? CDP1869_WEIGHT_BLUE : 0;
+
+ luma = (luma * 0xff) / 100;
+
+ r = (c & 4) ? luma : 0;
+ g = (c & 1) ? luma : 0;
+ b = (c & 2) ? luma : 0;
+
+ palette_set_color( Machine, i, MAKE_RGB(r, g, b) );
+}
+
+PALETTE_INIT( cdp1869 )
+{
+ int i, c, l;
+
+ // color-on-color display (CFC=0)
+
+ for (i = 0; i < 8; i++)
+ {
+ cdp1869_set_color(i, i, 15);
+ }
+
+ // tone-on-tone display (CFC=1)
+
+ for (c = 0; c < 8; c++)
+ {
+ for (l = 0; l < 8; l++)
+ {
+ cdp1869_set_color(i, c, l);
+ i++;
+ }
+ }
+}
+
+static int cdp1869_get_lines(void)
+{
+ if (cdp1869.line16 && !cdp1869.dblpage)
+ {
+ return 16;
+ }
+ else if (!cdp1869.line9)
+ {
+ return 9;
+ }
+ else
+ {
+ return 8;
+ }
+}
+
+static UINT16 cdp1869_get_pmemsize(int cols, int rows)
+{
+ int pmemsize = cols * rows;
+
+ if (cdp1869.dblpage) pmemsize *= 2;
+ if (cdp1869.line16) pmemsize *= 2;
+
+ return pmemsize;
+}
+
+static UINT16 cdp1869_get_pma(void)
+{
+ if (cdp1869.dblpage)
+ {
+ return cdp1869.pma;
+ }
+ else
+ {
+ return cdp1869.pma & 0x3ff;
+ }
+}
+
+UINT16 cdp1869_get_cma(UINT16 offset)
+{
+ int column = cdp1869.pram[cdp1869_get_pma()];
+ int row = offset & 0x07;
+
+ int addr = (column << 3) + row;
+
+ if ((offset & 0x08) && (cdp1869_get_lines() > 8))
+ {
+ addr += (CDP1869_CHARRAM_SIZE / 2);
+ }
+
+ return addr;
+}
+
+static UINT8 cdp1869_read_pageram(UINT16 addr)
+{
+ if (addr >= cdp1869.pramsize)
+ {
+ return 0xff;
+ }
+ else
+ {
+ return cdp1869.pram[addr];
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+UINT8 cdp1869_read_charram(UINT16 addr)
+{
+ if (addr >= cdp1869.cramsize)
+ {
+ return 0xff;
+ }
+ else
+ {
+ return cdp1869.cram[addr];
+ }
+}
+#endif
+
+WRITE8_HANDLER ( cdp1869_charram_w )
+{
+ if (cdp1869.cmem)
+ {
+ UINT16 addr = cdp1869_get_cma(offset);
+ cdp1869.cram[addr] = data;
+ }
+}
+
+READ8_HANDLER ( cdp1869_charram_r )
+{
+ if (cdp1869.cmem)
+ {
+ UINT16 addr = cdp1869_get_cma(offset);
+ return cdp1869.cram[addr];
+ }
+ else
+ {
+ return 0xff;
+ }
+}
+
+WRITE8_HANDLER ( cdp1869_pageram_w )
+{
+ UINT16 addr;
+
+ if (cdp1869.cmem)
+ {
+ addr = cdp1869_get_pma();
+ }
+ else
+ {
+ addr = offset;
+ }
+
+ cdp1869.pram[addr] = data;
+}
+
+READ8_HANDLER ( cdp1869_pageram_r )
+{
+ UINT16 addr;
+
+ if (cdp1869.cmem)
+ {
+ addr = cdp1869_get_pma();
+ }
+ else
+ {
+ addr = offset;
+ }
+
+ return cdp1869.pram[addr];
+}
+
+static int cdp1869_get_color(int ccb0, int ccb1, int pcb)
+{
+ int r = 0, g = 0, b = 0, color;
+
+ switch (cdp1869.col)
+ {
+ case 0:
+ r = ccb0;
+ g = pcb;
+ b = ccb1;
+ break;
+
+ case 1:
+ r = ccb0;
+ g = ccb1;
+ b = pcb;
+ break;
+
+ case 2:
+ case 3:
+ r = pcb;
+ g = ccb1;
+ b = ccb0;
+ break;
+ }
+
+ color = (r << 2) + (b << 1) + g;
+
+ if (cdp1869.cfc)
+ {
+ return color + ((cdp1869.bkg + 1) * 8);
+ }
+ else
+ {
+ return color;
+ }
+}
+
+static void cdp1869_draw_line(running_machine *machine, mame_bitmap *bitmap, int x, int y, int data, int color)
+{
+ int i;
+
+ data <<= 2;
+
+ for (i = 0; i < CDP1869_CHAR_WIDTH; i++)
+ {
+ if (data & 0x80)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[color];
+
+ if (!cdp1869.fresvert)
+ {
+ *BITMAP_ADDR16(bitmap, y + 1, x) = machine->pens[color];
+ }
+
+ if (!cdp1869.freshorz)
+ {
+ *BITMAP_ADDR16(bitmap, y, x + 1) = machine->pens[color];
+
+ if (!cdp1869.fresvert)
+ {
+ *BITMAP_ADDR16(bitmap, y + 1, x + 1) = machine->pens[color];
+ }
+ }
+ }
+
+ if (!cdp1869.freshorz)
+ {
+ x++;
+ }
+
+ x++;
+
+ data <<= 1;
+ }
+}
+
+static void cdp1869_draw_char(running_machine *machine, mame_bitmap *bitmap, int x, int y, UINT16 pramaddr, const rectangle *screenrect)
+{
+ int i;
+ UINT8 code = cdp1869_read_pageram(pramaddr);
+ UINT16 addr = code * 8;
+ UINT16 addr2 = addr + (CDP1869_CHARRAM_SIZE / 2);
+
+ for (i = 0; i < cdp1869_get_lines(); i++)
+ {
+ UINT8 data = cdp1869.cram[addr];
+
+ UINT8 colorbits = cdp1869.color_callback(data, addr, pramaddr);
+
+ int pcb = colorbits & 0x01;
+ int ccb1 = (colorbits & 0x02) >> 1;
+ int ccb0 = (colorbits & 0x04) >> 2;
+
+ int color = cdp1869_get_color(ccb0, ccb1, pcb);
+
+ cdp1869_draw_line(machine, bitmap, screenrect->min_x + x, screenrect->min_y + y, data, color);
+
+ addr++;
+ y++;
+
+ if (!cdp1869.fresvert)
+ {
+ y++;
+ }
+
+ if (i == 7)
+ {
+ addr = addr2;
+ }
+ }
+}
+
+VIDEO_START( cdp1869 )
+{
+ state_save_register_item("cdp1869", 0, cdp1869.ntsc_pal);
+ state_save_register_item("cdp1869", 0, cdp1869.dispoff);
+ state_save_register_item("cdp1869", 0, cdp1869.fresvert);
+ state_save_register_item("cdp1869", 0, cdp1869.freshorz);
+ state_save_register_item("cdp1869", 0, cdp1869.dblpage);
+ state_save_register_item("cdp1869", 0, cdp1869.line16);
+ state_save_register_item("cdp1869", 0, cdp1869.line9);
+ state_save_register_item("cdp1869", 0, cdp1869.cmem);
+ state_save_register_item("cdp1869", 0, cdp1869.cfc);
+ state_save_register_item("cdp1869", 0, cdp1869.col);
+ state_save_register_item("cdp1869", 0, cdp1869.bkg);
+ state_save_register_item("cdp1869", 0, cdp1869.pma);
+ state_save_register_item("cdp1869", 0, cdp1869.hma);
+ state_save_register_item_array("cdp1869", 0, cdp1869.cram);
+ state_save_register_item_array("cdp1869", 0, cdp1869.pram);
+ state_save_register_item("cdp1869", 0, cdp1869.cramsize);
+ state_save_register_item("cdp1869", 0, cdp1869.pramsize);
+}
+
+VIDEO_UPDATE( cdp1869 )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ if (!cdp1869.dispoff)
+ {
+ int sx, sy, rows, cols, width, height;
+ UINT16 addr, pmemsize;
+ rectangle screen, outer;
+
+ switch (cdp1869.ntsc_pal)
+ {
+ case CDP1869_NTSC:
+ outer.min_x = CDP1869_HBLANK_END;
+ outer.max_x = CDP1869_HBLANK_START - 1;
+ outer.min_y = CDP1869_SCANLINE_VBLANK_END_NTSC;
+ outer.max_y = CDP1869_SCANLINE_VBLANK_START_NTSC - 1;
+ screen.min_x = CDP1869_SCREEN_START_NTSC;
+ screen.max_x = CDP1869_SCREEN_END - 1;
+ screen.min_y = CDP1869_SCANLINE_DISPLAY_START_NTSC;
+ screen.max_y = CDP1869_SCANLINE_DISPLAY_END_NTSC - 1;
+ break;
+
+ default:
+ case CDP1869_PAL:
+ outer.min_x = CDP1869_HBLANK_END;
+ outer.max_x = CDP1869_HBLANK_START - 1;
+ outer.min_y = CDP1869_SCANLINE_VBLANK_END_PAL;
+ outer.max_y = CDP1869_SCANLINE_VBLANK_START_PAL - 1;
+ screen.min_x = CDP1869_SCREEN_START_PAL;
+ screen.max_x = CDP1869_SCREEN_END - 1;
+ screen.min_y = CDP1869_SCANLINE_DISPLAY_START_PAL;
+ screen.max_y = CDP1869_SCANLINE_DISPLAY_END_PAL - 1;
+ break;
+ }
+
+ sect_rect(&outer, cliprect);
+ fillbitmap(bitmap, machine->pens[cdp1869.bkg], &outer);
+
+ width = CDP1869_CHAR_WIDTH;
+ height = cdp1869_get_lines();
+
+ if (!cdp1869.freshorz)
+ {
+ width *= 2;
+ }
+
+ if (!cdp1869.fresvert)
+ {
+ height *= 2;
+ }
+
+ cols = cdp1869.freshorz ? CDP1869_COLUMNS_FULL : CDP1869_COLUMNS_HALF;
+ rows = (screen.max_y - screen.min_y + 1) / height;
+
+ pmemsize = cdp1869_get_pmemsize(cols, rows);
+
+ addr = cdp1869.hma;
+
+ for (sy = 0; sy < rows; sy++)
+ {
+ for (sx = 0; sx < cols; sx++)
+ {
+ int x = sx * width;
+ int y = sy * height;
+
+ cdp1869_draw_char(machine, bitmap, x, y, addr, &screen);
+
+ addr++;
+
+ if (addr == pmemsize) addr = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void cdp1869_configure(const CDP1869_interface *intf)
+{
+ if (intf->charrom_region != REGION_INVALID)
+ {
+ UINT8 *memory = memory_region(intf->charrom_region);
+ memcpy(cdp1869.cram, memory, intf->charram_size);
+ }
+
+ cdp1869.ntsc_pal = intf->ntsc_pal;
+ cdp1869.cramsize = intf->charram_size;
+ cdp1869.pramsize = intf->pageram_size;
+ cdp1869.color_callback = intf->get_color_bits;
+}
diff --git a/src/emu/video/cdp1869.h b/src/emu/video/cdp1869.h
new file mode 100644
index 00000000000..6a0146073d3
--- /dev/null
+++ b/src/emu/video/cdp1869.h
@@ -0,0 +1,128 @@
+/*
+
+ RCA CDP1869/70/76 Video Interface System (VIS)
+
+ http://homepage.mac.com/ruske/cosmacelf/cdp1869.pdf
+
+ ________________ ________________
+ TPA 1 ---| \/ |--- 40 Vdd PREDISPLAY_ 1 ---| \/ |--- 40 Vdd
+ TPB 2 ---| |--- 39 PMSEL *DISPLAY_ 2 ---| |--- 39 PAL/NTSC_
+ MRD_ 3 ---| |--- 38 PMWR_ PCB 3 ---| |--- 38 CPUCLK
+ MWR_ 4 ---| |--- 37 *CMSEL CCB1 4 ---| |--- 37 XTAL (DOT)
+ MA0/8 5 ---| |--- 36 CMWR_ BUS7 5 ---| |--- 36 XTAL (DOT)_
+ MA1/9 6 ---| |--- 35 PMA0 CCB0 6 ---| |--- 35 *ADDRSTB_
+ MA2/10 7 ---| |--- 34 PMA1 BUS6 7 ---| |--- 34 MRD_
+ MA3/11 8 ---| |--- 33 PMA2 CDB5 8 ---| |--- 33 TPB
+ MA4/12 9 ---| |--- 32 PMA3 BUS5 9 ---| |--- 32 *CMSEL
+ MA5/13 10 ---| CDP1869C |--- 31 PMA4 CDB4 10 ---| CDP1870/76C |--- 31 BURST
+ MA6/14 11 ---| top view |--- 30 PMA5 BUS4 11 ---| top view |--- 30 *H SYNC_
+ MA7/15 12 ---| |--- 29 PMA6 CDB3 12 ---| |--- 29 COMPSYNC_
+ N0 13 ---| |--- 28 PMA7 BUS3 13 ---| |--- 28 LUM / (RED)^
+ N1 14 ---| |--- 27 PMA8 CDB2 14 ---| |--- 27 PAL CHROM / (BLUE)^
+ N2 15 ---| |--- 26 PMA9 BUS2 15 ---| |--- 26 NTSC CHROM / (GREEN)^
+ *H SYNC_ 16 ---| |--- 25 CMA3/PMA10 CDB1 16 ---| |--- 25 XTAL_ (CHROM)
+ *DISPLAY_ 17 ---| |--- 24 CMA2 BUS1 17 ---| |--- 24 XTAL (CHROM)
+ *ADDRSTB_ 18 ---| |--- 23 CMA1 CDB0 18 ---| |--- 23 EMS_
+ SOUND 19 ---| |--- 22 CMA0 BUS0 19 ---| |--- 22 EVS_
+ VSS 20 ---|________________|--- 21 *N=3_ Vss 20 ---|________________|--- 21 *N=3_
+
+
+ * = INTERCHIP CONNECTIONS ^ = FOR THE RGB BOND-OUT OPTION (CDP1876C) _ = ACTIVE LOW
+
+*/
+
+#ifndef __CDP1869_VIDEO__
+#define __CDP1869_VIDEO__
+
+enum {
+ CDP1869_NTSC,
+ CDP1869_PAL
+};
+
+#define CDP1869_DOT_CLK_PAL 5626000.0
+#define CDP1869_DOT_CLK_NTSC 5670000.0
+#define CDP1869_COLOR_CLK_PAL 8867236.0
+#define CDP1869_COLOR_CLK_NTSC 7159090.0
+
+#define CDP1869_CPU_CLK_PAL (CDP1869_DOT_CLK_PAL / 2)
+#define CDP1869_CPU_CLK_NTSC (CDP1869_DOT_CLK_NTSC / 2)
+
+#define CDP1869_CHAR_WIDTH 6
+
+#define CDP1869_HSYNC_START (56 * CDP1869_CHAR_WIDTH)
+#define CDP1869_HSYNC_END (60 * CDP1869_CHAR_WIDTH)
+#define CDP1869_HBLANK_START (54 * CDP1869_CHAR_WIDTH)
+#define CDP1869_HBLANK_END (5 * CDP1869_CHAR_WIDTH)
+#define CDP1869_SCREEN_START_PAL (9 * CDP1869_CHAR_WIDTH)
+#define CDP1869_SCREEN_START_NTSC (10 * CDP1869_CHAR_WIDTH)
+#define CDP1869_SCREEN_START (10 * CDP1869_CHAR_WIDTH)
+#define CDP1869_SCREEN_END (50 * CDP1869_CHAR_WIDTH)
+#define CDP1869_SCREEN_WIDTH (60 * CDP1869_CHAR_WIDTH)
+
+#define CDP1869_TOTAL_SCANLINES_PAL 312
+#define CDP1869_SCANLINE_VBLANK_START_PAL 304
+#define CDP1869_SCANLINE_VBLANK_END_PAL 10
+#define CDP1869_SCANLINE_VSYNC_START_PAL 308
+#define CDP1869_SCANLINE_VSYNC_END_PAL 312
+#define CDP1869_SCANLINE_DISPLAY_START_PAL 44
+#define CDP1869_SCANLINE_DISPLAY_END_PAL 260
+#define CDP1869_SCANLINE_PREDISPLAY_START_PAL 43
+#define CDP1869_SCANLINE_PREDISPLAY_END_PAL 260
+#define CDP1869_VISIBLE_SCANLINES_PAL (CDP1869_SCANLINE_DISPLAY_END_PAL - CDP1869_SCANLINE_DISPLAY_START_PAL)
+
+#define CDP1869_TOTAL_SCANLINES_NTSC 262
+#define CDP1869_SCANLINE_VBLANK_START_NTSC 252
+#define CDP1869_SCANLINE_VBLANK_END_NTSC 10
+#define CDP1869_SCANLINE_VSYNC_START_NTSC 258
+#define CDP1869_SCANLINE_VSYNC_END_NTSC 262
+#define CDP1869_SCANLINE_DISPLAY_START_NTSC 36
+#define CDP1869_SCANLINE_DISPLAY_END_NTSC 228
+#define CDP1869_SCANLINE_PREDISPLAY_START_NTSC 35
+#define CDP1869_SCANLINE_PREDISPLAY_END_NTSC 228
+#define CDP1869_VISIBLE_SCANLINES_NTSC (CDP1869_SCANLINE_DISPLAY_END_NTSC - CDP1869_SCANLINE_DISPLAY_START_NTSC)
+
+#define CDP1869_FPS_PAL CDP1869_DOT_CLK_PAL / CDP1869_SCREEN_WIDTH / CDP1869_TOTAL_SCANLINES_PAL
+#define CDP1869_FPS_NTSC CDP1869_DOT_CLK_NTSC / CDP1869_SCREEN_WIDTH / CDP1869_TOTAL_SCANLINES_NTSC
+
+#define CDP1869_WEIGHT_RED 30 // % of max luminance
+#define CDP1869_WEIGHT_GREEN 59
+#define CDP1869_WEIGHT_BLUE 11
+
+#define CDP1869_CHARRAM_SIZE 0x1000
+#define CDP1869_PAGERAM_SIZE 0x800
+
+#define CDP1869_COLUMNS_HALF 20
+#define CDP1869_COLUMNS_FULL 40
+#define CDP1869_ROWS_HALF 12
+#define CDP1869_ROWS_FULL_PAL 25
+#define CDP1869_ROWS_FULL_NTSC 24
+
+typedef struct CDP1869_interface
+{
+ int ntsc_pal; // display format (NTSC/PAL)
+ int charrom_region; // memory region to load CHARRAM from
+ UINT16 charram_size; // CHARRAM size
+ UINT16 pageram_size; // PAGERAM size
+ UINT8 (*get_color_bits)(UINT8 cramdata, UINT16 cramaddr, UINT16 pramaddr); // 0x01 = PCB, 0x02 = CCB0, 0x04 = CCB1
+} CDP1869_interface;
+
+WRITE8_HANDLER ( cdp1869_out3_w );
+WRITE8_HANDLER ( cdp1869_out4_w );
+WRITE8_HANDLER ( cdp1869_out5_w );
+WRITE8_HANDLER ( cdp1869_out6_w );
+WRITE8_HANDLER ( cdp1869_out7_w );
+
+PALETTE_INIT( cdp1869 );
+VIDEO_START( cdp1869 );
+VIDEO_UPDATE( cdp1869 );
+
+READ8_HANDLER ( cdp1869_charram_r );
+READ8_HANDLER ( cdp1869_pageram_r );
+WRITE8_HANDLER ( cdp1869_charram_w );
+WRITE8_HANDLER ( cdp1869_pageram_w );
+
+void cdp1869_configure(const CDP1869_interface *intf);
+
+UINT16 cdp1869_get_cma(UINT16 offset);
+
+#endif
diff --git a/src/emu/video/crtc6845.c b/src/emu/video/crtc6845.c
new file mode 100644
index 00000000000..69040b0b892
--- /dev/null
+++ b/src/emu/video/crtc6845.c
@@ -0,0 +1,444 @@
+/**********************************************************************
+
+ Motorola 6845 CRT controller emulation
+
+**********************************************************************/
+
+#include "driver.h"
+#include "crtc6845.h"
+
+
+#define LOG (0)
+
+
+typedef struct _crtc6845_state crtc6845_state;
+
+struct _crtc6845_state
+{
+ const crtc6845_interface *intf;
+
+ /* internal registers */
+ UINT8 address_latch;
+ UINT8 horiz_total;
+ UINT8 horiz_disp;
+ UINT8 horiz_sync_pos;
+ UINT8 sync_width;
+ UINT8 vert_total;
+ UINT8 vert_total_adj;
+ UINT8 vert_disp;
+ UINT8 vert_sync_pos;
+ UINT8 intl_skew;
+ UINT8 max_ras_addr;
+ UINT8 cursor_start_ras;
+ UINT8 cursor_end_ras;
+ UINT16 start_addr;
+ UINT16 cursor;
+ UINT16 light_pen;
+
+ emu_timer *display_enable_changed_timer;
+
+ /* saved screen parameters so we don't call
+ video_screen_configure() unneccessarily.
+ Do NOT state save these! */
+ UINT16 last_horiz_total;
+ UINT16 last_vert_total;
+ UINT16 last_max_x;
+ UINT16 last_max_y;
+ UINT16 current_ma; /* the MA address currently drawn */
+ int has_valid_parameters;
+};
+
+static crtc6845_state crtc6845;
+
+
+static void crtc6845_state_save_postload(void *param);
+static void configure_screen(crtc6845_state *chip, int postload);
+static void update_timer(crtc6845_state *chip);
+static TIMER_CALLBACK_PTR( display_enable_changed_timer_cb );
+
+
+void crtc6845_init(void)
+{
+ crtc6845_state *chip = &crtc6845;
+ int which = 0;
+
+ state_save_register_func_postload_ptr(crtc6845_state_save_postload, chip);
+
+ state_save_register_item("crtc6845", which, chip->address_latch);
+ state_save_register_item("crtc6845", which, chip->horiz_total);
+ state_save_register_item("crtc6845", which, chip->horiz_disp);
+ state_save_register_item("crtc6845", which, chip->horiz_sync_pos);
+ state_save_register_item("crtc6845", which, chip->sync_width);
+ state_save_register_item("crtc6845", which, chip->vert_total);
+ state_save_register_item("crtc6845", which, chip->vert_total_adj);
+ state_save_register_item("crtc6845", which, chip->vert_disp);
+ state_save_register_item("crtc6845", which, chip->vert_sync_pos);
+ state_save_register_item("crtc6845", which, chip->intl_skew);
+ state_save_register_item("crtc6845", which, chip->max_ras_addr);
+ state_save_register_item("crtc6845", which, chip->cursor_start_ras);
+ state_save_register_item("crtc6845", which, chip->cursor_end_ras);
+ state_save_register_item("crtc6845", which, chip->start_addr);
+ state_save_register_item("crtc6845", which, chip->cursor);
+ state_save_register_item("crtc6845", which, chip->light_pen);
+
+ /* do not configure the screen */
+ chip->intf = 0;
+ chip->has_valid_parameters = FALSE;
+}
+
+
+void crtc6845_config(int which, const crtc6845_interface *intf)
+{
+ crtc6845_state *chip = &crtc6845;
+
+ crtc6845_init();
+
+ chip->intf = intf;
+
+ /* create the timer if the user is interested in getting display enable
+ notifications */
+ if (intf->display_enable_changed)
+ chip->display_enable_changed_timer = timer_alloc_ptr(display_enable_changed_timer_cb, chip);
+}
+
+
+static void crtc6845_state_save_postload(void *param)
+{
+ crtc6845_state *chip = (crtc6845_state *)param;
+
+ configure_screen(chip, TRUE);
+}
+
+
+READ8_HANDLER( crtc6845_register_r )
+{
+ crtc6845_state *chip = &crtc6845;
+
+ UINT8 ret = 0xff;
+
+ switch (chip->address_latch)
+ {
+ case 14:
+ ret = chip->cursor >> 8;
+ break;
+ case 15:
+ ret = chip->cursor;
+ break;
+ case 16:
+ ret = chip->light_pen >> 8;
+ break;
+ case 17:
+ ret = chip->light_pen;
+ break;
+ default:
+ /* all other registers are write only */
+ break;
+ }
+ return ret;
+}
+
+
+WRITE8_HANDLER( crtc6845_address_w )
+{
+ crtc6845_state *chip = &crtc6845;
+
+ chip->address_latch = data & 0x1f;
+}
+
+
+WRITE8_HANDLER( crtc6845_register_w )
+{
+ crtc6845_state *chip = &crtc6845;
+
+ int call_configure_screen = FALSE;
+ if (LOG) logerror("CRT #0 PC %04x: CRTC6845 reg 0x%02x = 0x%02x\n", activecpu_get_pc(), chip->address_latch, data);
+
+ switch (chip->address_latch)
+ {
+ case 0:
+ chip->horiz_total = data;
+ call_configure_screen = TRUE;
+ break;
+ case 1:
+ chip->horiz_disp = data;
+ call_configure_screen = TRUE;
+ break;
+ case 2:
+ chip->horiz_sync_pos = data;
+ break;
+ case 3:
+ chip->sync_width = data & 0x0f;
+ break;
+ case 4:
+ chip->vert_total = data & 0x7f;
+ call_configure_screen = TRUE;
+ break;
+ case 5:
+ chip->vert_total_adj = data & 0x1f;
+ call_configure_screen = TRUE;
+ break;
+ case 6:
+ chip->vert_disp = data & 0x7f;
+ call_configure_screen = TRUE;
+ break;
+ case 7:
+ chip->vert_sync_pos = data & 0x7f;
+ break;
+ case 8:
+ chip->intl_skew = data & 0x03;
+ break;
+ case 9:
+ chip->max_ras_addr = data & 0x1f;
+ call_configure_screen = TRUE;
+ break;
+ case 10:
+ chip->cursor_start_ras = data & 0x7f;
+ break;
+ case 11:
+ chip->cursor_end_ras = data & 0x1f;
+ break;
+ case 12:
+ chip->start_addr &= 0x00ff;
+ chip->start_addr |= (data & 0x3f) << 8;
+ call_configure_screen = TRUE;
+ break;
+ case 13:
+ chip->start_addr &= 0xff00;
+ chip->start_addr |= data;
+ call_configure_screen = TRUE;
+ break;
+ case 14:
+ chip->cursor &= 0x00ff;
+ chip->cursor |= (data & 0x3f) << 8;
+ break;
+ case 15:
+ chip->cursor &= 0xff00;
+ chip->cursor |= data;
+ break;
+ case 16: /* read-only */
+ break;
+ case 17: /* read-only */
+ break;
+ default:
+ break;
+ }
+
+ if (call_configure_screen)
+ configure_screen(chip, FALSE);
+}
+
+
+static void configure_screen(crtc6845_state *chip, int postload)
+{
+ if (chip->intf)
+ {
+ /* compute the screen sizes */
+ UINT16 horiz_total = (chip->horiz_total + 1) * chip->intf->hpixels_per_column;
+ UINT16 vert_total = (chip->vert_total + 1) * (chip->max_ras_addr + 1) + chip->vert_total_adj;
+
+ /* determine the visible area, avoid division by 0 */
+ UINT16 max_x = chip->horiz_disp * chip->intf->hpixels_per_column - 1;
+ UINT16 max_y = chip->vert_disp * (chip->max_ras_addr + 1) - 1;
+
+ /* update only if screen parameters changed, unless we are coming here after loading the saved state */
+ if (postload ||
+ (horiz_total != chip->last_horiz_total) || (vert_total != chip->last_vert_total) ||
+ (max_x != chip->last_max_x) || (max_y != chip->last_max_y))
+ {
+ /* update the screen only if we have valid data */
+ if ((chip->horiz_total > 0) && (max_x < horiz_total) && (chip->vert_total > 0) && (max_y < vert_total))
+ {
+ rectangle visarea;
+
+ attoseconds_t refresh = HZ_TO_ATTOSECONDS(chip->intf->clock) * (chip->horiz_total + 1) * vert_total;
+
+ visarea.min_x = 0;
+ visarea.min_y = 0;
+ visarea.max_x = max_x;
+ visarea.max_y = max_y;
+
+ if (LOG) logerror("CRTC6845 config screen: HTOTAL: %x VTOTAL: %x MAX_X: %x MAX_Y: %x FPS: %f\n",
+ horiz_total, vert_total, max_x, max_y, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
+
+ video_screen_configure(chip->intf->scrnum, horiz_total, vert_total, &visarea, refresh);
+
+ chip->has_valid_parameters = TRUE;
+ }
+ else
+ chip->has_valid_parameters = FALSE;
+
+ chip->last_horiz_total = horiz_total;
+ chip->last_vert_total = vert_total;
+ chip->last_max_x = max_x;
+ chip->last_max_y = max_y;
+
+ update_timer(chip);
+ }
+ }
+}
+
+
+static int is_display_enabled(crtc6845_state *chip)
+{
+ UINT16 y = video_screen_get_vpos(chip->intf->scrnum);
+ UINT16 x = video_screen_get_hpos(chip->intf->scrnum);
+
+ return (y <= chip->last_max_y) && (x <= chip->last_max_x);
+}
+
+
+static void update_timer(crtc6845_state *chip)
+{
+ INT16 next_y;
+ UINT16 next_x;
+ attotime duration;
+
+ if (chip->has_valid_parameters && (chip->display_enable_changed_timer != 0))
+ {
+ if (is_display_enabled(chip))
+ {
+ /* we are in a display region,
+ get the location of the next blanking start */
+
+ /* normally, it's at end the current raster line */
+ next_y = video_screen_get_vpos(chip->intf->scrnum);
+ next_x = chip->last_max_x + 1;
+
+ /* but if visible width = horiz_total, then we need
+ to go to the beginning of VBLANK */
+ if (next_x == chip->last_horiz_total)
+ {
+ next_y = chip->last_max_y + 1;
+ next_x = 0;
+
+ /* abnormal case, no vertical blanking, either */
+ if (next_y == chip->last_vert_total)
+ next_y = -1;
+ }
+ }
+ else
+ {
+ /* we are in a blanking region,
+ get the location of the next display start */
+ next_x = 0;
+ next_y = (video_screen_get_vpos(chip->intf->scrnum) + 1) % chip->last_vert_total;
+
+ /* if we would now fall in the vertical blanking, we need
+ to go to the top of the screen */
+ if (next_y > chip->last_max_y)
+ next_y = 0;
+ }
+
+ if (next_y != -1)
+ duration = video_screen_get_time_until_pos(chip->intf->scrnum, next_y, next_x);
+ else
+ duration = attotime_never;
+
+ timer_adjust_ptr(chip->display_enable_changed_timer, duration, attotime_never);
+ }
+}
+
+
+static TIMER_CALLBACK_PTR( display_enable_changed_timer_cb )
+{
+ crtc6845_state *chip = param;
+
+ /* call the callback function -- we know it exists */
+ chip->intf->display_enable_changed(is_display_enabled(chip));
+
+ update_timer(chip);
+}
+
+
+UINT16 crtc6845_get_ma(int which)
+{
+ crtc6845_state *chip = &crtc6845;
+
+ UINT16 ret;
+
+ if (chip->has_valid_parameters)
+ {
+ /* get the current raster positions and clamp them to the visible region */
+ int y = video_screen_get_vpos(0);
+ int x = video_screen_get_hpos(0);
+
+ /* since the MA counter stops in the blanking regions, if we are in a
+ VBLANK, both X and Y are at their max */
+ if ((y > chip->last_max_y) || (x > chip->last_max_x))
+ x = chip->last_max_x;
+
+ if (y > chip->last_max_y)
+ y = chip->last_max_y;
+
+ ret = (chip->start_addr +
+ (y / (chip->max_ras_addr + 1)) * chip->horiz_disp +
+ (x / chip->intf->hpixels_per_column)) & 0x3fff;
+ }
+ else
+ ret = 0;
+
+ return ret;
+}
+
+
+UINT8 crtc6845_get_ra(int which)
+{
+ crtc6845_state *chip = &crtc6845;
+
+ UINT8 ret;
+
+ if (chip->has_valid_parameters)
+ {
+ /* get the current vertical raster position and clamp it to the visible region */
+ int y = video_screen_get_vpos(0);
+
+ if (y > chip->last_max_y)
+ y = chip->last_max_y;
+
+ ret = y % (chip->max_ras_addr + 1);
+ }
+ else
+ ret = 0;
+
+ return ret;
+}
+
+
+VIDEO_UPDATE( crtc6845 )
+{
+ crtc6845_state *chip = &crtc6845;
+
+ if (chip->has_valid_parameters)
+ {
+ UINT16 y;
+
+ /* call the set up function if any */
+ void *param = 0;
+
+ if (chip->intf->begin_update)
+ param = chip->intf->begin_update(machine, screen, bitmap, cliprect);
+
+ /* read the start address at the beginning of the frame */
+ if (cliprect->min_y == 0)
+ chip->current_ma = chip->start_addr;
+
+ /* for each row in the visible region */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT8 ra = y % (chip->max_ras_addr + 1);
+
+ /* call the external system to draw it */
+ chip->intf->update_row(bitmap, cliprect, chip->current_ma, ra, y, chip->horiz_disp, param);
+
+ /* update MA if the last raster address */
+ if (ra == chip->max_ras_addr)
+ chip->current_ma = (chip->current_ma + chip->horiz_disp) & 0x3fff;
+ }
+
+ /* call the tear down function if any */
+ if (chip->intf->end_update)
+ chip->intf->end_update(bitmap, cliprect, param);
+ }
+
+ return 0;
+}
diff --git a/src/emu/video/crtc6845.h b/src/emu/video/crtc6845.h
new file mode 100644
index 00000000000..92f6a0bc412
--- /dev/null
+++ b/src/emu/video/crtc6845.h
@@ -0,0 +1,62 @@
+/**********************************************************************
+
+ Motorola 6845 CRT controller emulation
+
+**********************************************************************/
+
+
+typedef struct _crtc6845_interface crtc6845_interface;
+struct _crtc6845_interface
+{
+ int scrnum; /* screen we are acting on */
+ int clock; /* the clock (pin 21) of the chip */
+ int hpixels_per_column; /* number of pixels per video memory address */
+
+ /* if specified, this gets called before any pixel update,
+ optionally return a pointer that will be passed to the
+ update and tear down callbacks */
+ void * (*begin_update)(running_machine *machine, int screen,
+ mame_bitmap *bitmap, const rectangle *cliprect);
+
+ /* this gets called for every row, the driver must output
+ x_count * hpixels_per_column pixels */
+ void (*update_row)(mame_bitmap *bitmap, const rectangle *cliprect,
+ UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, void *param);
+
+ /* if specified, this gets called after all row updating is complete */
+ void (*end_update)(mame_bitmap *bitmap, const rectangle *cliprect, void *param);
+
+ /* if specified, this gets called for every change of the disply enable (DT pin 18) */
+ void (*display_enable_changed)(int display_enabled);
+};
+
+
+/* Deprectated - use crtc6845_init to set up for save states only, but not to configure the screen */
+void crtc6845_init(void);
+
+/* use crtc6845_init to set up for save states AND to configure the screen
+ the 'which' argument is currently a dummy as only one instance is supported */
+void crtc6845_config(int which, const crtc6845_interface *intf);
+
+/* selects one of the registers for reading or writing */
+WRITE8_HANDLER( crtc6845_address_w );
+#define crtc6845_0_address_w crtc6845_address_w
+
+/* reads the currently selected register */
+READ8_HANDLER( crtc6845_register_r );
+#define crtc6845_0_register_r crtc6845_register_r
+
+/* writes the currently selected register */
+WRITE8_HANDLER( crtc6845_register_w );
+#define crtc6845_0_register_w crtc6845_register_w
+
+/* return the current value on the MA0-MA13 pins */
+UINT16 crtc6845_get_ma(int which);
+
+/* return the current value on the RA0-RA4 pins */
+UINT8 crtc6845_get_ra(int which);
+
+/* updates the screen -- this will call begin_update(),
+ followed by update_row() reapeatedly and after all row
+ updating is complete, end_update() */
+VIDEO_UPDATE( crtc6845 );
diff --git a/src/emu/video/generic.c b/src/emu/video/generic.c
new file mode 100644
index 00000000000..955d6958cd5
--- /dev/null
+++ b/src/emu/video/generic.c
@@ -0,0 +1,1102 @@
+/*********************************************************************
+
+ generic.c
+
+ Generic simple video functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "generic.h"
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+UINT8 *videoram;
+UINT16 *videoram16;
+UINT32 *videoram32;
+size_t videoram_size;
+
+UINT8 *colorram;
+UINT16 *colorram16;
+UINT32 *colorram32;
+
+UINT8 *spriteram; /* not used in this module... */
+UINT16 *spriteram16; /* ... */
+UINT32 *spriteram32; /* ... */
+
+UINT8 *spriteram_2;
+UINT16 *spriteram16_2;
+UINT32 *spriteram32_2;
+
+UINT8 *spriteram_3;
+UINT16 *spriteram16_3;
+UINT32 *spriteram32_3;
+
+UINT8 *buffered_spriteram;
+UINT16 *buffered_spriteram16;
+UINT32 *buffered_spriteram32;
+
+UINT8 *buffered_spriteram_2;
+UINT16 *buffered_spriteram16_2;
+UINT32 *buffered_spriteram32_2;
+
+size_t spriteram_size; /* ... here just for convenience */
+size_t spriteram_2_size;
+size_t spriteram_3_size;
+
+UINT8 *dirtybuffer;
+UINT16 *dirtybuffer16;
+UINT32 *dirtybuffer32;
+
+UINT8 *paletteram;
+UINT16 *paletteram16;
+UINT32 *paletteram32;
+
+UINT8 *paletteram_2; /* use when palette RAM is split in two parts */
+UINT16 *paletteram16_2;
+
+mame_bitmap *tmpbitmap;
+int flip_screen_x, flip_screen_y;
+
+
+
+/***************************************************************************
+ COMMON GRAPHICS LAYOUTS
+***************************************************************************/
+
+const gfx_layout gfx_8x8x1 =
+{
+ 8,8,
+ RGN_FRAC(1,1),
+ 1,
+ { RGN_FRAC(0,1) },
+ { STEP8(0,1) },
+ { STEP8(0,8) },
+ 8*8
+};
+
+const gfx_layout gfx_8x8x2_planar =
+{
+ 8,8,
+ RGN_FRAC(1,2),
+ 2,
+ { RGN_FRAC(1,2), RGN_FRAC(0,2) },
+ { STEP8(0,1) },
+ { STEP8(0,8) },
+ 8*8
+};
+
+const gfx_layout gfx_8x8x3_planar =
+{
+ 8,8,
+ RGN_FRAC(1,3),
+ 3,
+ { RGN_FRAC(2,3), RGN_FRAC(1,3), RGN_FRAC(0,3) },
+ { STEP8(0,1) },
+ { STEP8(0,8) },
+ 8*8
+};
+
+const gfx_layout gfx_8x8x4_planar =
+{
+ 8,8,
+ RGN_FRAC(1,4),
+ 4,
+ { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) },
+ { STEP8(0,1) },
+ { STEP8(0,8) },
+ 8*8
+};
+
+const gfx_layout gfx_8x8x5_planar =
+{
+ 8,8,
+ RGN_FRAC(1,5),
+ 5,
+ { RGN_FRAC(4,5), RGN_FRAC(3,5), RGN_FRAC(2,5), RGN_FRAC(1,5), RGN_FRAC(0,5) },
+ { STEP8(0,1) },
+ { STEP8(0,8) },
+ 8*8
+};
+
+const gfx_layout gfx_8x8x6_planar =
+{
+ 8,8,
+ RGN_FRAC(1,6),
+ 6,
+ { RGN_FRAC(5,6), RGN_FRAC(4,6), RGN_FRAC(3,6), RGN_FRAC(2,6), RGN_FRAC(1,6), RGN_FRAC(0,6) },
+ { STEP8(0,1) },
+ { STEP8(0,8) },
+ 8*8
+};
+
+const gfx_layout gfx_16x16x4_planar =
+{
+ 16,16,
+ RGN_FRAC(1,4),
+ 4,
+ { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) },
+ { STEP16(0,1) },
+ { STEP16(0,16) },
+ 16*16
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ paletteram16_le - return a 16-bit value
+ assembled from the two bytes of little-endian
+ palette RAM referenced by offset
+-------------------------------------------------*/
+
+INLINE UINT16 paletteram16_le(offs_t offset)
+{
+ return paletteram[offset & ~1] | (paletteram[offset | 1] << 8);
+}
+
+
+/*-------------------------------------------------
+ paletteram16_be - return a 16-bit value
+ assembled from the two bytes of big-endian
+ palette RAM referenced by offset
+-------------------------------------------------*/
+
+INLINE UINT16 paletteram16_be(offs_t offset)
+{
+ return paletteram[offset | 1] | (paletteram[offset & ~1] << 8);
+}
+
+
+/*-------------------------------------------------
+ paletteram16_split - return a 16-bit value
+ assembled from the two bytes of split palette
+ RAM referenced by offset
+-------------------------------------------------*/
+
+INLINE UINT16 paletteram16_split(offs_t offset)
+{
+ return paletteram[offset] | (paletteram_2[offset] << 8);
+}
+
+
+/*-------------------------------------------------
+ paletteram32_be - return a 32-bit value
+ assembled from the two words of big-endian
+ palette RAM referenced by offset
+-------------------------------------------------*/
+
+INLINE UINT32 paletteram32_be(offs_t offset)
+{
+ return paletteram16[offset | 1] | (paletteram16[offset & ~1] << 16);
+}
+
+
+/*-------------------------------------------------
+ set_color_444 - set a 4-4-4 RGB color using
+ the 16-bit data provided and the specified
+ shift values
+-------------------------------------------------*/
+
+INLINE void set_color_444(pen_t color, int rshift, int gshift, int bshift, UINT16 data)
+{
+ palette_set_color_rgb(Machine, color, pal4bit(data >> rshift), pal4bit(data >> gshift), pal4bit(data >> bshift));
+}
+
+
+/*-------------------------------------------------
+ set_color_4444 - set a 4-4-4-4 IRGB color using
+ the 16-bit data provided and the specified
+ shift values
+-------------------------------------------------*/
+
+INLINE void set_color_4444(pen_t color, int ishift, int rshift, int gshift, int bshift, UINT16 data)
+{
+ static const UINT8 ztable[16] =
+ { 0x0, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11 };
+ int i, r, g, b;
+
+ i = ztable[(data >> ishift) & 15];
+ r = ((data >> rshift) & 15) * i;
+ g = ((data >> gshift) & 15) * i;
+ b = ((data >> bshift) & 15) * i;
+
+ palette_set_color_rgb(Machine, color, r, g, b);
+}
+
+
+/*-------------------------------------------------
+ set_color_555 - set a 5-5-5 RGB color using
+ the 16-bit data provided and the specified
+ shift values
+-------------------------------------------------*/
+
+INLINE void set_color_555(pen_t color, int rshift, int gshift, int bshift, UINT16 data)
+{
+ palette_set_color_rgb(Machine, color, pal5bit(data >> rshift), pal5bit(data >> gshift), pal5bit(data >> bshift));
+}
+
+
+/*-------------------------------------------------
+ set_color_8888 - set a 8-8-8 RGB color using
+ the 32-bit data provided and the specified
+ shift values
+-------------------------------------------------*/
+
+INLINE void set_color_888(pen_t color, int rshift, int gshift, int bshift, UINT32 data)
+{
+ palette_set_color_rgb(Machine, color, (data >> rshift) & 0xff, (data >> gshift) & 0xff, (data >> bshift) & 0xff);
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ generic_video_init - initialize globals and
+ register for save states
+-------------------------------------------------*/
+
+void generic_video_init(running_machine *machine)
+{
+ videoram = NULL;
+ videoram16 = NULL;
+ videoram32 = NULL;
+ videoram_size = 0;
+ colorram = NULL;
+ colorram16 = NULL;
+ colorram32 = NULL;
+ spriteram = NULL;
+ spriteram16 = NULL;
+ spriteram32 = NULL;
+ spriteram_2 = NULL;
+ spriteram16_2 = NULL;
+ spriteram32_2 = NULL;
+ spriteram_3 = NULL;
+ spriteram16_3 = NULL;
+ spriteram32_3 = NULL;
+ buffered_spriteram = NULL;
+ buffered_spriteram16 = NULL;
+ buffered_spriteram32 = NULL;
+ buffered_spriteram_2 = NULL;
+ buffered_spriteram16_2 = NULL;
+ buffered_spriteram32_2 = NULL;
+ spriteram_size = 0; /* ... here just for convenience */
+ spriteram_2_size = 0;
+ spriteram_3_size = 0;
+ dirtybuffer = NULL;
+ dirtybuffer16 = NULL;
+ dirtybuffer32 = NULL;
+ tmpbitmap = NULL;
+ flip_screen_x = flip_screen_y = 0;
+}
+
+
+
+/***************************************************************************
+ GENERIC VIDEO START/UPDATE
+***************************************************************************/
+
+/*-------------------------------------------------
+ video_generic_postload - post-load callback
+ that marks all videoram as dirty
+-------------------------------------------------*/
+
+static void video_generic_postload(void)
+{
+ memset(dirtybuffer, 1, videoram_size);
+}
+
+
+/*-------------------------------------------------
+ video_start_generic - general video system
+ with dirty buffer support
+-------------------------------------------------*/
+
+VIDEO_START( generic )
+{
+ assert_always(videoram_size != 0, "VIDEO_START(generic) requires non-zero videoram_size");
+
+ /* allocate memory for the dirty buffer */
+ dirtybuffer = auto_malloc(videoram_size);
+ memset(dirtybuffer, 1, videoram_size);
+
+ /* allocate the temporary bitmap */
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ /* on a restore, we automatically zap the dirty buffer */
+ state_save_register_func_postload(video_generic_postload);
+}
+
+
+/*-------------------------------------------------
+ video_start_generic_bitmapped - general video
+ system with a bitmap
+-------------------------------------------------*/
+
+VIDEO_START( generic_bitmapped )
+{
+ /* allocate the temporary bitmap */
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ /* ensure the contents of the bitmap are saved */
+ state_save_register_bitmap("video", 0, "tmpbitmap", tmpbitmap);
+}
+
+
+/*-------------------------------------------------
+ video_update_generic_bitmapped - blast the
+ generic bitmap to the screen
+-------------------------------------------------*/
+
+VIDEO_UPDATE( generic_bitmapped )
+{
+ copybitmap(bitmap, tmpbitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ return 0;
+}
+
+
+
+/***************************************************************************
+ GENERIC READ/WRITE HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ videoram_r/w - 8-bit access to videoram with
+ dirty buffer marking
+-------------------------------------------------*/
+
+READ8_HANDLER( videoram_r )
+{
+ return videoram[offset];
+}
+
+WRITE8_HANDLER( videoram_w )
+{
+ dirtybuffer[offset] = 1;
+ videoram[offset] = data;
+}
+
+
+/*-------------------------------------------------
+ colorram_r/w - 8-bit access to colorram with
+ dirty buffer marking
+-------------------------------------------------*/
+
+READ8_HANDLER( colorram_r )
+{
+ return colorram[offset];
+}
+
+WRITE8_HANDLER( colorram_w )
+{
+ dirtybuffer[offset] = 1;
+ colorram[offset] = data;
+}
+
+
+/*-------------------------------------------------
+ spriteram_r/w - 8-bit access to spriteram
+-------------------------------------------------*/
+
+READ8_HANDLER( spriteram_r )
+{
+ return spriteram[offset];
+}
+
+WRITE8_HANDLER( spriteram_w )
+{
+ spriteram[offset] = data;
+}
+
+
+/*-------------------------------------------------
+ spriteram16_r/w - 16-bit access to spriteram16
+-------------------------------------------------*/
+
+READ16_HANDLER( spriteram16_r )
+{
+ return spriteram16[offset];
+}
+
+WRITE16_HANDLER( spriteram16_w )
+{
+ COMBINE_DATA(spriteram16+offset);
+}
+
+
+/*-------------------------------------------------
+ spriteram_r/w - 8-bit access to spriteram2
+-------------------------------------------------*/
+
+READ8_HANDLER( spriteram_2_r )
+{
+ return spriteram_2[offset];
+}
+
+WRITE8_HANDLER( spriteram_2_w )
+{
+ spriteram_2[offset] = data;
+}
+
+
+
+/***************************************************************************
+ GENERIC SPRITE BUFFERING
+***************************************************************************/
+
+/* Mish: 171099
+
+ 'Buffered spriteram' is where the graphics hardware draws the sprites
+from private ram that the main CPU cannot access. The main CPU typically
+prepares sprites for the next frame in it's own sprite ram as the graphics
+hardware renders sprites for the current frame from private ram. Main CPU
+sprite ram is usually copied across to private ram by setting some flag
+in the VBL interrupt routine.
+
+ The reason for this is to avoid sprite flicker or lag - if a game
+is unable to prepare sprite ram within a frame (for example, lots of sprites
+on screen) then it doesn't trigger the buffering hardware - instead the
+graphics hardware will use the sprites from the last frame. An example is
+Dark Seal - the buffer flag is only written to if the CPU is idle at the time
+of the VBL interrupt. If the buffering is not emulated the sprites flicker
+at busy scenes.
+
+ Some games seem to use buffering because of hardware constraints -
+Capcom games (Cps1, Last Duel, etc) render spriteram _1 frame ahead_ and
+buffer this spriteram at the end of a frame, so the _next_ frame must be drawn
+from the buffer. Presumably the graphics hardware and the main cpu cannot
+share the same spriteram for whatever reason.
+
+ Sprite buffering & Mame:
+
+ To use sprite buffering in a driver use VIDEO_BUFFERS_SPRITERAM in the
+machine driver. This will automatically create an area for buffered spriteram
+equal to the size of normal spriteram.
+
+ Spriteram size _must_ be declared in the memory map:
+
+ { 0x120000, 0x1207ff, MWA8_BANK2, &spriteram, &spriteram_size },
+
+ Then the video driver must draw the sprites from the buffered_spriteram
+pointer. The function buffer_spriteram_w() is used to simulate hardware
+which buffers the spriteram from a memory location write. The function
+buffer_spriteram(UINT8 *ptr, int length) can be used where
+more control is needed over what is buffered.
+
+ For examples see darkseal.c, contra.c, lastduel.c, bionicc.c etc.
+
+*/
+
+
+/*-------------------------------------------------
+ buffer_spriteram_w - triggered writes to
+ buffer spriteram
+-------------------------------------------------*/
+
+WRITE8_HANDLER( buffer_spriteram_w )
+{
+ memcpy(buffered_spriteram, spriteram, spriteram_size);
+}
+
+WRITE16_HANDLER( buffer_spriteram16_w )
+{
+ memcpy(buffered_spriteram16, spriteram16, spriteram_size);
+}
+
+WRITE32_HANDLER( buffer_spriteram32_w )
+{
+ memcpy(buffered_spriteram32, spriteram32, spriteram_size);
+}
+
+
+/*-------------------------------------------------
+ buffer_spriteram_2_w - triggered writes to
+ buffer spriteram_2
+-------------------------------------------------*/
+
+WRITE8_HANDLER( buffer_spriteram_2_w )
+{
+ memcpy(buffered_spriteram_2, spriteram_2, spriteram_2_size);
+}
+
+WRITE16_HANDLER( buffer_spriteram16_2_w )
+{
+ memcpy(buffered_spriteram16_2, spriteram16_2, spriteram_2_size);
+}
+
+WRITE32_HANDLER( buffer_spriteram32_2_w )
+{
+ memcpy(buffered_spriteram32_2, spriteram32_2, spriteram_2_size);
+}
+
+
+/*-------------------------------------------------
+ buffer_spriteram - for manually buffering
+ spriteram
+-------------------------------------------------*/
+
+void buffer_spriteram(UINT8 *ptr, int length)
+{
+ memcpy(buffered_spriteram, ptr, length);
+}
+
+void buffer_spriteram_2(UINT8 *ptr, int length)
+{
+ memcpy(buffered_spriteram_2, ptr, length);
+}
+
+
+
+/***************************************************************************
+ GLOBAL VIDEO ATTRIBUTES
+***************************************************************************/
+
+/*-------------------------------------------------
+ updateflip - handle global flipping
+-------------------------------------------------*/
+
+static void updateflip(void)
+{
+ screen_state *state = &Machine->screen[0];
+ rectangle visarea = state->visarea;
+
+ tilemap_set_flip(ALL_TILEMAPS,(TILEMAP_FLIPX & flip_screen_x) | (TILEMAP_FLIPY & flip_screen_y));
+
+ if (flip_screen_x)
+ {
+ int temp;
+
+ temp = state->width - visarea.min_x - 1;
+ visarea.min_x = state->width - visarea.max_x - 1;
+ visarea.max_x = temp;
+ }
+ if (flip_screen_y)
+ {
+ int temp;
+
+ temp = state->height - visarea.min_y - 1;
+ visarea.min_y = state->height - visarea.max_y - 1;
+ visarea.max_y = temp;
+ }
+
+ video_screen_configure(0, state->width, state->height, &visarea, state->refresh);
+}
+
+
+/*-------------------------------------------------
+ flip_screen_set - set global flip
+-------------------------------------------------*/
+
+void flip_screen_set(int on)
+{
+ flip_screen_x_set(on);
+ flip_screen_y_set(on);
+}
+
+
+/*-------------------------------------------------
+ flip_screen_x_set - set global horizontal flip
+-------------------------------------------------*/
+
+void flip_screen_x_set(int on)
+{
+ if (on) on = ~0;
+ if (flip_screen_x != on)
+ {
+ flip_screen_x = on;
+ updateflip();
+ }
+}
+
+
+/*-------------------------------------------------
+ flip_screen_y_set - set global vertical flip
+-------------------------------------------------*/
+
+void flip_screen_y_set(int on)
+{
+ if (on) on = ~0;
+ if (flip_screen_y != on)
+ {
+ flip_screen_y = on;
+ updateflip();
+ }
+}
+
+
+/***************************************************************************
+ COMMON PALETTE INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ black_and_white - basic 2-color black & white
+-------------------------------------------------*/
+
+PALETTE_INIT( black_and_white )
+{
+ palette_set_color(machine,0,RGB_BLACK); /* black */
+ palette_set_color(machine,1,RGB_WHITE); /* white */
+}
+
+
+/*-------------------------------------------------
+ RRRR_GGGG_BBBB - standard 4-4-4 palette,
+ assuming the commonly used resistor values:
+
+ 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( RRRR_GGGG_BBBB )
+{
+ 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] >> 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));
+ }
+}
+
+
+
+/***************************************************************************
+ GENERIC PALETTE READ HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ 8-bit read handlers
+-------------------------------------------------*/
+
+READ8_HANDLER( paletteram_r )
+{
+ return paletteram[offset];
+}
+
+READ8_HANDLER( paletteram_2_r )
+{
+ return paletteram_2[offset];
+}
+
+
+/*-------------------------------------------------
+ 16-bit read handlers
+-------------------------------------------------*/
+
+READ16_HANDLER( paletteram16_word_r )
+{
+ return paletteram16[offset];
+}
+
+READ16_HANDLER( paletteram16_2_word_r )
+{
+ return paletteram16_2[offset];
+}
+
+
+/*-------------------------------------------------
+ 32-bit read handlers
+-------------------------------------------------*/
+
+READ32_HANDLER( paletteram32_r )
+{
+ return paletteram32[offset];
+}
+
+
+
+/***************************************************************************
+ 3-3-2 RGB PALETTE WRITE HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ RRR-GGG-BB writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_RRRGGGBB_w )
+{
+ paletteram[offset] = data;
+ palette_set_color_rgb(Machine, offset, pal3bit(data >> 5), pal3bit(data >> 2), pal2bit(data >> 0));
+}
+
+
+/*-------------------------------------------------
+ BB-GGG-RR writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_BBGGGRRR_w )
+{
+ paletteram[offset] = data;
+ palette_set_color_rgb(Machine, offset, pal3bit(data >> 0), pal3bit(data >> 3), pal2bit(data >> 6));
+}
+
+
+/*-------------------------------------------------
+ BB-GG-RR-II writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_BBGGRRII_w )
+{
+ int i = (data >> 0) & 3;
+
+ paletteram[offset] = data;
+ palette_set_color_rgb(Machine, offset, pal4bit(((data >> 0) & 0x0c) | i),
+ pal4bit(((data >> 2) & 0x0c) | i),
+ pal4bit(((data >> 4) & 0x0c) | i));
+}
+
+
+
+/***************************************************************************
+ 4-4-4 RGB PALETTE WRITE HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ xxxx-BBBB-GGGG-RRRR writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_xxxxBBBBGGGGRRRR_le_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset / 2, 0, 4, 8, paletteram16_le(offset));
+}
+
+WRITE8_HANDLER( paletteram_xxxxBBBBGGGGRRRR_be_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset / 2, 0, 4, 8, paletteram16_be(offset));
+}
+
+WRITE8_HANDLER( paletteram_xxxxBBBBGGGGRRRR_split1_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset, 0, 4, 8, paletteram16_split(offset));
+}
+
+WRITE8_HANDLER( paletteram_xxxxBBBBGGGGRRRR_split2_w )
+{
+ paletteram_2[offset] = data;
+ set_color_444(offset, 0, 4, 8, paletteram16_split(offset));
+}
+
+WRITE16_HANDLER( paletteram16_xxxxBBBBGGGGRRRR_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_444(offset, 0, 4, 8, paletteram16[offset]);
+}
+
+
+/*-------------------------------------------------
+ xxxx-BBBB-RRRR-GGGG writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_xxxxBBBBRRRRGGGG_le_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset / 2, 4, 0, 8, paletteram16_le(offset));
+}
+
+WRITE8_HANDLER( paletteram_xxxxBBBBRRRRGGGG_be_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset / 2, 4, 0, 8, paletteram16_be(offset));
+}
+
+WRITE8_HANDLER( paletteram_xxxxBBBBRRRRGGGG_split1_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset, 4, 0, 8, paletteram16_split(offset));
+}
+
+WRITE8_HANDLER( paletteram_xxxxBBBBRRRRGGGG_split2_w )
+{
+ paletteram_2[offset] = data;
+ set_color_444(offset, 4, 0, 8, paletteram16_split(offset));
+}
+
+WRITE16_HANDLER( paletteram16_xxxxBBBBRRRRGGGG_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_444(offset, 4, 0, 8, paletteram16[offset]);
+}
+
+
+/*-------------------------------------------------
+ xxxx-RRRR-BBBB-GGGG writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_xxxxRRRRBBBBGGGG_split1_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset, 8, 0, 4, paletteram16_split(offset));
+}
+
+WRITE8_HANDLER( paletteram_xxxxRRRRBBBBGGGG_split2_w )
+{
+ paletteram_2[offset] = data;
+ set_color_444(offset, 8, 0, 4, paletteram16_split(offset));
+}
+
+
+/*-------------------------------------------------
+ xxxx-RRRR-GGGG-BBBB writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_xxxxRRRRGGGGBBBB_le_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset / 2, 8, 4, 0, paletteram16_le(offset));
+}
+
+WRITE8_HANDLER( paletteram_xxxxRRRRGGGGBBBB_be_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset / 2, 8, 4, 0, paletteram16_be(offset));
+}
+
+WRITE16_HANDLER( paletteram16_xxxxRRRRGGGGBBBB_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_444(offset, 8, 4, 0, paletteram16[offset]);
+}
+
+
+/*-------------------------------------------------
+ RRRR-GGGG-BBBB-xxxx writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_RRRRGGGGBBBBxxxx_be_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset / 2, 12, 8, 4, paletteram16_be(offset));
+}
+
+WRITE8_HANDLER( paletteram_RRRRGGGGBBBBxxxx_split1_w )
+{
+ paletteram[offset] = data;
+ set_color_444(offset, 12, 8, 4, paletteram16_split(offset));
+}
+
+WRITE8_HANDLER( paletteram_RRRRGGGGBBBBxxxx_split2_w )
+{
+ paletteram_2[offset] = data;
+ set_color_444(offset, 12, 8, 4, paletteram16_split(offset));
+}
+
+WRITE16_HANDLER( paletteram16_RRRRGGGGBBBBxxxx_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_444(offset, 12, 8, 4, paletteram16[offset]);
+}
+
+
+
+/***************************************************************************
+ 5-5-5 RGB PALETTE WRITE HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ x-BBBBB-GGGGG-RRRRR writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_xBBBBBGGGGGRRRRR_le_w )
+{
+ paletteram[offset] = data;
+ set_color_555(offset / 2, 0, 5, 10, paletteram16_le(offset));
+}
+
+WRITE8_HANDLER( paletteram_xBBBBBGGGGGRRRRR_be_w )
+{
+ paletteram[offset] = data;
+ set_color_555(offset / 2, 0, 5, 10, paletteram16_be(offset));
+}
+
+WRITE8_HANDLER( paletteram_xBBBBBGGGGGRRRRR_split1_w )
+{
+ paletteram[offset] = data;
+ set_color_555(offset, 0, 5, 10, paletteram16_split(offset));
+}
+
+WRITE8_HANDLER( paletteram_xBBBBBGGGGGRRRRR_split2_w )
+{
+ paletteram_2[offset] = data;
+ set_color_555(offset, 0, 5, 10, paletteram16_split(offset));
+}
+
+WRITE16_HANDLER( paletteram16_xBBBBBGGGGGRRRRR_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_555(offset, 0, 5, 10, paletteram16[offset]);
+}
+
+
+/*-------------------------------------------------
+ x-BBBBB-RRRRR-GGGGG writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_xBBBBBRRRRRGGGGG_split1_w )
+{
+ paletteram[offset] = data;
+ set_color_555(offset, 5, 0, 10, paletteram16_split(offset));
+}
+
+WRITE8_HANDLER( paletteram_xBBBBBRRRRRGGGGG_split2_w )
+{
+ paletteram_2[offset] = data;
+ set_color_555(offset, 5, 0, 10, paletteram16_split(offset));
+}
+
+
+/*-------------------------------------------------
+ x-RRRRR-GGGGG-BBBBB writes
+-------------------------------------------------*/
+
+WRITE8_HANDLER( paletteram_xRRRRRGGGGGBBBBB_le_w )
+{
+ paletteram[offset] = data;
+ set_color_555(offset / 2, 10, 5, 0, paletteram16_le(offset));
+}
+
+WRITE16_HANDLER( paletteram16_xRRRRRGGGGGBBBBB_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_555(offset, 10, 5, 0, paletteram16[offset]);
+}
+
+
+/*-------------------------------------------------
+ x-GGGGG-RRRRR-BBBBB writes
+-------------------------------------------------*/
+
+WRITE16_HANDLER( paletteram16_xGGGGGRRRRRBBBBB_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_555(offset, 5, 10, 0, paletteram16[offset]);
+}
+
+
+/*-------------------------------------------------
+ x-GGGGG-BBBBB-RRRRR writes
+-------------------------------------------------*/
+
+WRITE16_HANDLER( paletteram16_xGGGGGBBBBBRRRRR_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_555(offset, 0, 10, 5, paletteram16[offset]);
+}
+
+
+/*-------------------------------------------------
+ RRRRR-GGGGG-BBBBB-x writes
+-------------------------------------------------*/
+
+WRITE16_HANDLER( paletteram16_RRRRRGGGGGBBBBBx_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_555(offset, 11, 6, 1, paletteram16[offset]);
+}
+
+
+/*-------------------------------------------------
+ RRRR-GGGG-BBBB-RGBx writes
+-------------------------------------------------*/
+
+WRITE16_HANDLER( paletteram16_RRRRGGGGBBBBRGBx_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ data = paletteram16[offset];
+ palette_set_color_rgb(Machine, offset, pal5bit(((data >> 11) & 0x1e) | ((data >> 3) & 0x01)),
+ pal5bit(((data >> 7) & 0x1e) | ((data >> 2) & 0x01)),
+ pal5bit(((data >> 3) & 0x1e) | ((data >> 1) & 0x01)));
+}
+
+
+
+/***************************************************************************
+ 4-4-4-4 RGBI PALETTE WRITE HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ IIII-RRRR-GGGG-BBBB writes
+-------------------------------------------------*/
+
+WRITE16_HANDLER( paletteram16_IIIIRRRRGGGGBBBB_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_4444(offset, 12, 8, 4, 0, paletteram16[offset]);
+}
+
+
+/*-------------------------------------------------
+ RRRR-GGGG-BBBB-IIII writes
+-------------------------------------------------*/
+
+WRITE16_HANDLER( paletteram16_RRRRGGGGBBBBIIII_word_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_4444(offset, 0, 12, 8, 4, paletteram16[offset]);
+}
+
+
+
+/***************************************************************************
+ 8-8-8 RGB PALETTE WRITE HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ xxxxxxxx-RRRRRRRR-GGGGGGGG-BBBBBBBB writes
+-------------------------------------------------*/
+
+WRITE16_HANDLER( paletteram16_xrgb_word_be_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_888(offset / 2, 16, 8, 0, paletteram32_be(offset));
+}
+
+
+/*-------------------------------------------------
+ xxxxxxxx-BBBBBBBB-GGGGGGGG-RRRRRRRR writes
+-------------------------------------------------*/
+
+WRITE16_HANDLER( paletteram16_xbgr_word_be_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ set_color_888(offset / 2, 0, 8, 16, paletteram32_be(offset));
+}
diff --git a/src/emu/video/generic.h b/src/emu/video/generic.h
new file mode 100644
index 00000000000..33f9f63875a
--- /dev/null
+++ b/src/emu/video/generic.h
@@ -0,0 +1,229 @@
+/*********************************************************************
+
+ generic.h
+
+ Generic simple video functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __VIDEO_GENERIC_H__
+#define __VIDEO_GENERIC_H__
+
+#include "mamecore.h"
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+extern UINT8 *videoram;
+extern UINT16 *videoram16;
+extern UINT32 *videoram32;
+extern size_t videoram_size;
+
+extern UINT8 *colorram;
+extern UINT16 *colorram16;
+extern UINT32 *colorram32;
+
+extern UINT8 *spriteram;
+extern UINT16 *spriteram16;
+extern UINT32 *spriteram32;
+
+extern UINT8 *spriteram_2;
+extern UINT16 *spriteram16_2;
+extern UINT32 *spriteram32_2;
+
+extern UINT8 *spriteram_3;
+extern UINT16 *spriteram16_3;
+extern UINT32 *spriteram32_3;
+
+extern UINT8 *buffered_spriteram;
+extern UINT16 *buffered_spriteram16;
+extern UINT32 *buffered_spriteram32;
+
+extern UINT8 *buffered_spriteram_2;
+extern UINT16 *buffered_spriteram16_2;
+extern UINT32 *buffered_spriteram32_2;
+
+extern size_t spriteram_size;
+extern size_t spriteram_2_size;
+extern size_t spriteram_3_size;
+
+extern UINT8 *dirtybuffer;
+extern UINT16 *dirtybuffer16;
+extern UINT32 *dirtybuffer32;
+
+extern UINT8 *paletteram;
+extern UINT16 *paletteram16;
+extern UINT32 *paletteram32;
+
+extern UINT8 *paletteram_2; /* use when palette RAM is split in two parts */
+extern UINT16 *paletteram16_2;
+
+extern mame_bitmap *tmpbitmap;
+extern int flip_screen_x, flip_screen_y;
+
+
+
+/***************************************************************************
+ COMMON GRAPHICS LAYOUTS
+***************************************************************************/
+
+extern const gfx_layout gfx_8x8x1;
+extern const gfx_layout gfx_8x8x2_planar;
+extern const gfx_layout gfx_8x8x3_planar;
+extern const gfx_layout gfx_8x8x4_planar;
+extern const gfx_layout gfx_8x8x5_planar;
+extern const gfx_layout gfx_8x8x6_planar;
+
+extern const gfx_layout gfx_16x16x4_planar;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* ----- initialization ----- */
+
+/* set up all the common systems */
+void generic_video_init(running_machine *machine);
+
+/* generic video start with dirty buffers */
+VIDEO_START( generic );
+
+/* generic video start with a temporary bitmap */
+VIDEO_START( generic_bitmapped );
+
+/* generic video update to blit a temporary bitmap */
+VIDEO_UPDATE( generic_bitmapped );
+
+
+
+/* ----- core video/color/spriteram access ----- */
+
+/* video RAM read/write handlers */
+READ8_HANDLER( videoram_r );
+WRITE8_HANDLER( videoram_w );
+
+/* color RAM read/write handlers */
+READ8_HANDLER( colorram_r );
+WRITE8_HANDLER( colorram_w );
+
+/* sprite RAM read/write handlers */
+READ8_HANDLER( spriteram_r );
+WRITE8_HANDLER( spriteram_w );
+READ16_HANDLER( spriteram16_r );
+WRITE16_HANDLER( spriteram16_w );
+READ8_HANDLER( spriteram_2_r );
+WRITE8_HANDLER( spriteram_2_w );
+
+
+
+/* ----- sprite buffering ----- */
+
+/* buffered sprite RAM write handlers */
+WRITE8_HANDLER( buffer_spriteram_w );
+WRITE16_HANDLER( buffer_spriteram16_w );
+WRITE32_HANDLER( buffer_spriteram32_w );
+WRITE8_HANDLER( buffer_spriteram_2_w );
+WRITE16_HANDLER( buffer_spriteram16_2_w );
+WRITE32_HANDLER( buffer_spriteram32_2_w );
+
+/* perform the actual buffering */
+void buffer_spriteram(UINT8 *ptr, int length);
+void buffer_spriteram_2(UINT8 *ptr, int length);
+
+
+
+/* ----- global attributes ----- */
+
+/* set global attributes */
+void flip_screen_set(int on);
+void flip_screen_x_set(int on);
+void flip_screen_y_set(int on);
+#define flip_screen flip_screen_x
+
+
+
+/* ----- generic palette init routines ----- */
+
+PALETTE_INIT( black_and_white );
+PALETTE_INIT( RRRR_GGGG_BBBB );
+
+
+
+/* ----- generic palette RAM read/write handlers ----- */
+
+/* read handlers */
+READ8_HANDLER( paletteram_r );
+READ8_HANDLER( paletteram_2_r );
+READ16_HANDLER( paletteram16_word_r );
+READ16_HANDLER( paletteram16_2_word_r );
+READ32_HANDLER( paletteram32_r );
+
+/* 3-3-2 RGB palette write handlers */
+WRITE8_HANDLER( paletteram_BBGGGRRR_w );
+WRITE8_HANDLER( paletteram_RRRGGGBB_w );
+WRITE8_HANDLER( paletteram_BBGGRRII_w );
+
+/* 4-4-4 RGB palette write handlers */
+WRITE8_HANDLER( paletteram_xxxxBBBBGGGGRRRR_le_w );
+WRITE8_HANDLER( paletteram_xxxxBBBBGGGGRRRR_be_w );
+WRITE8_HANDLER( paletteram_xxxxBBBBGGGGRRRR_split1_w ); /* uses paletteram[] */
+WRITE8_HANDLER( paletteram_xxxxBBBBGGGGRRRR_split2_w ); /* uses paletteram_2[] */
+WRITE16_HANDLER( paletteram16_xxxxBBBBGGGGRRRR_word_w );
+
+WRITE8_HANDLER( paletteram_xxxxBBBBRRRRGGGG_le_w );
+WRITE8_HANDLER( paletteram_xxxxBBBBRRRRGGGG_be_w );
+WRITE8_HANDLER( paletteram_xxxxBBBBRRRRGGGG_split1_w ); /* uses paletteram[] */
+WRITE8_HANDLER( paletteram_xxxxBBBBRRRRGGGG_split2_w ); /* uses paletteram_2[] */
+WRITE16_HANDLER( paletteram16_xxxxBBBBRRRRGGGG_word_w );
+
+WRITE8_HANDLER( paletteram_xxxxRRRRBBBBGGGG_split1_w ); /* uses paletteram[] */
+WRITE8_HANDLER( paletteram_xxxxRRRRBBBBGGGG_split2_w ); /* uses paletteram_2[] */
+
+WRITE8_HANDLER( paletteram_xxxxRRRRGGGGBBBB_le_w );
+WRITE8_HANDLER( paletteram_xxxxRRRRGGGGBBBB_be_w );
+WRITE16_HANDLER( paletteram16_xxxxRRRRGGGGBBBB_word_w );
+
+WRITE8_HANDLER( paletteram_RRRRGGGGBBBBxxxx_be_w );
+WRITE8_HANDLER( paletteram_RRRRGGGGBBBBxxxx_split1_w ); /* uses paletteram[] */
+WRITE8_HANDLER( paletteram_RRRRGGGGBBBBxxxx_split2_w ); /* uses paletteram_2[] */
+WRITE16_HANDLER( paletteram16_RRRRGGGGBBBBxxxx_word_w );
+
+/* 4-4-4-4 IRGB palette write handlers */
+WRITE16_HANDLER( paletteram16_IIIIRRRRGGGGBBBB_word_w );
+WRITE16_HANDLER( paletteram16_RRRRGGGGBBBBIIII_word_w );
+
+/* 5-5-5 RGB palette write handlers */
+WRITE8_HANDLER( paletteram_xBBBBBGGGGGRRRRR_le_w );
+WRITE8_HANDLER( paletteram_xBBBBBGGGGGRRRRR_be_w );
+WRITE8_HANDLER( paletteram_xBBBBBGGGGGRRRRR_split1_w ); /* uses paletteram[] */
+WRITE8_HANDLER( paletteram_xBBBBBGGGGGRRRRR_split2_w ); /* uses paletteram_2[] */
+WRITE16_HANDLER( paletteram16_xBBBBBGGGGGRRRRR_word_w );
+
+WRITE8_HANDLER( paletteram_xBBBBBRRRRRGGGGG_split1_w ); /* uses paletteram[] */
+WRITE8_HANDLER( paletteram_xBBBBBRRRRRGGGGG_split2_w ); /* uses paletteram_2[] */
+
+WRITE8_HANDLER( paletteram_xRRRRRGGGGGBBBBB_le_w );
+WRITE16_HANDLER( paletteram16_xRRRRRGGGGGBBBBB_word_w );
+
+WRITE16_HANDLER( paletteram16_xGGGGGRRRRRBBBBB_word_w );
+WRITE16_HANDLER( paletteram16_xGGGGGBBBBBRRRRR_word_w );
+
+WRITE16_HANDLER( paletteram16_RRRRRGGGGGBBBBBx_word_w );
+WRITE16_HANDLER( paletteram16_RRRRGGGGBBBBRGBx_word_w );
+
+/* 8-8-8 RGB palette write handlers */
+WRITE16_HANDLER( paletteram16_xrgb_word_be_w );
+WRITE16_HANDLER( paletteram16_xbgr_word_be_w );
+
+
+#endif /* __VIDEO_GENERIC_H__ */
diff --git a/src/emu/video/poly.c b/src/emu/video/poly.c
new file mode 100644
index 00000000000..adafbe6a47d
--- /dev/null
+++ b/src/emu/video/poly.c
@@ -0,0 +1,1410 @@
+/***************************************************************************
+
+ polynew.c
+
+ Helper routines for polygon rendering.
+
+***************************************************************************/
+
+#include "poly.h"
+#include "eminline.h"
+#include "mame.h"
+#include <math.h>
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+/* keep statistics */
+#define KEEP_STATISTICS 0
+
+/* turn this on to log the reasons for any long waits */
+#define LOG_WAITS 0
+
+/* number of profiling ticks before we consider a wait "long" */
+#define LOG_WAIT_THRESHOLD 1000
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define SCANLINES_PER_BUCKET 8
+#define CACHE_LINE_SIZE 64 /* this is a general guess */
+#define TOTAL_BUCKETS (512 / SCANLINES_PER_BUCKET)
+#define UNITS_PER_POLY (100 / SCANLINES_PER_BUCKET)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* forward definitions */
+typedef struct _polygon_info polygon_info;
+
+
+/* tri_extent describes start/end points for a scanline */
+typedef struct _tri_extent tri_extent;
+struct _tri_extent
+{
+ INT16 startx; /* starting X coordinate (inclusive) */
+ INT16 stopx; /* ending X coordinate (exclusive) */
+};
+
+
+/* single set of polygon per-parameter data */
+typedef struct _poly_param poly_param;
+struct _poly_param
+{
+ float start; /* parameter value at starting X,Y */
+ float dpdx; /* dp/dx relative to starting X */
+ float dpdy; /* dp/dy relative to starting Y */
+};
+
+
+/* poly edge is used internally for quad rendering */
+typedef struct _poly_edge poly_edge;
+struct _poly_edge
+{
+ poly_edge * next; /* next edge in sequence */
+ int index; /* index of this edge */
+ const poly_vertex * v1; /* pointer to first vertex */
+ const poly_vertex * v2; /* pointer to second vertex */
+ float dxdy; /* dx/dy along the edge */
+ float dpdy[MAX_VERTEX_PARAMS];/* per-parameter dp/dy values */
+};
+
+
+/* poly section is used internally for quad rendering */
+typedef struct _poly_section poly_section;
+struct _poly_section
+{
+ const poly_edge * ledge; /* pointer to left edge */
+ const poly_edge * redge; /* pointer to right edge */
+ float ybottom; /* bottom of this section */
+};
+
+
+/* work_unit_shared is a common set of data shared between tris and quads */
+typedef struct _work_unit_shared work_unit_shared;
+struct _work_unit_shared
+{
+ polygon_info * polygon; /* pointer to polygon */
+ volatile UINT32 count_next; /* number of scanlines and index of next item to process */
+ INT16 scanline; /* starting scanline and count */
+ UINT16 previtem; /* index of previous item in the same bucket */
+#ifndef PTR64
+ UINT32 dummy; /* pad to 16 bytes */
+#endif
+};
+
+
+/* tri_work_unit is a triangle-specific work-unit */
+typedef struct _tri_work_unit tri_work_unit;
+struct _tri_work_unit
+{
+ work_unit_shared shared; /* shared data */
+ tri_extent extent[SCANLINES_PER_BUCKET]; /* array of scanline extents */
+};
+
+
+/* quad_work_unit is a quad-specific work-unit */
+typedef struct _quad_work_unit quad_work_unit;
+struct _quad_work_unit
+{
+ work_unit_shared shared; /* shared data */
+ poly_extent extent[SCANLINES_PER_BUCKET]; /* array of scanline extents */
+};
+
+
+/* work_unit is a union of the two types */
+typedef union _work_unit work_unit;
+union _work_unit
+{
+ work_unit_shared shared; /* shared data */
+ tri_work_unit tri; /* triangle work unit */
+ quad_work_unit quad; /* quad work unit */
+};
+
+
+/* polygon_info describes a single polygon, which includes the poly_params */
+struct _polygon_info
+{
+ poly_manager * poly; /* pointer back to the poly manager */
+ void * dest; /* pointer to the destination we are rendering to */
+ void * extra; /* extra data pointer */
+ UINT8 numparams; /* number of parameters for this polygon */
+ UINT8 numverts; /* number of vertices in this polygon */
+ poly_draw_scanline callback; /* callback to handle a scanline's worth of work */
+ INT32 xorigin; /* X origin for all parameters */
+ INT32 yorigin; /* Y origin for all parameters */
+ poly_param param[MAX_VERTEX_PARAMS];/* array of parameter data */
+};
+
+
+/* full poly manager description */
+struct _poly_manager
+{
+ /* queue management */
+ osd_work_queue * queue; /* work queue */
+
+ /* triangle work units */
+ work_unit ** unit; /* array of work unit pointers */
+ UINT32 unit_next; /* index of next unit to allocate */
+ UINT32 unit_count; /* number of work units available */
+ size_t unit_size; /* size of each work unit, in bytes */
+
+ /* quad work units */
+ UINT32 quadunit_next; /* index of next unit to allocate */
+ UINT32 quadunit_count; /* number of work units available */
+ size_t quadunit_size; /* size of each work unit, in bytes */
+
+ /* poly data */
+ polygon_info ** polygon; /* array of polygon pointers */
+ UINT32 polygon_next; /* index of next polygon to allocate */
+ UINT32 polygon_count; /* number of polygon items available */
+ size_t polygon_size; /* size of each polygon, in bytes */
+
+ /* extra data */
+ void ** extra; /* array of extra data pointers */
+ UINT32 extra_next; /* index of next extra data to allocate */
+ UINT32 extra_count; /* number of extra data items available */
+ size_t extra_size; /* size of each extra data, in bytes */
+
+ /* misc data */
+ UINT8 flags; /* flags */
+
+ /* buckets */
+ UINT16 unit_bucket[TOTAL_BUCKETS]; /* buckets for tracking unit usage */
+
+ /* statistics */
+ UINT32 triangles; /* number of triangles queued */
+ UINT32 quads; /* number of quads queued */
+ UINT64 pixels; /* number of pixels rendered */
+#if KEEP_STATISTICS
+ UINT32 unit_waits; /* number of times we waited for a unit */
+ UINT32 unit_max; /* maximum units used */
+ UINT32 polygon_waits; /* number of times we waited for a polygon */
+ UINT32 polygon_max; /* maximum polygons used */
+ UINT32 extra_waits; /* number of times we waited for an extra data */
+ UINT32 extra_max; /* maximum extra data used */
+ UINT32 conflicts[WORK_MAX_THREADS]; /* number of conflicts found, per thread */
+ UINT32 resolved[WORK_MAX_THREADS]; /* number of conflicts resolved, per thread */
+#endif
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void **allocate_array(size_t *itemsize, UINT32 itemcount);
+static void free_array(void **array);
+static void *poly_item_callback(void *param, int threadid);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ round_coordinate - round a coordinate to
+ an integer, following rules that 0.5 rounds
+ down
+-------------------------------------------------*/
+
+INLINE INT32 round_coordinate(float value)
+{
+ INT32 result = floor(value);
+ return result + (value - (float)result > 0.5f);
+}
+
+
+/*-------------------------------------------------
+ convert_tri_extent_to_poly_extent - convert
+ a simple tri_extent to a full poly_extent
+-------------------------------------------------*/
+
+INLINE void convert_tri_extent_to_poly_extent(poly_extent *dstextent, const tri_extent *srcextent, const polygon_info *polygon, INT32 y)
+{
+ /* copy start/stop always */
+ dstextent->startx = srcextent->startx;
+ dstextent->stopx = srcextent->stopx;
+
+ /* if we have parameters, process them as well */
+ if (polygon->numparams > 0)
+ {
+ float dx = srcextent->startx - polygon->xorigin;
+ float dy = y - polygon->yorigin;
+ int paramnum;
+
+ /* iterate over parameters */
+ for (paramnum = 0; paramnum < polygon->numparams; paramnum++)
+ {
+ dstextent->param[paramnum].start = polygon->param[paramnum].start + dx * polygon->param[paramnum].dpdx + dy * polygon->param[paramnum].dpdy;
+ dstextent->param[paramnum].dpdx = polygon->param[paramnum].dpdx;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ interpolate_vertex - interpolate values in
+ a vertex based on p[0] crossing the clipval
+-------------------------------------------------*/
+
+INLINE void interpolate_vertex(poly_vertex *outv, const poly_vertex *v1, const poly_vertex *v2, int paramcount, float clipval)
+{
+ float frac = (clipval - v1->p[0]) / (v2->p[0] - v1->p[0]);
+ int paramnum;
+
+ /* create a new one at the intersection point */
+ outv->x = v1->x + frac * (v2->x - v1->x);
+ outv->y = v1->y + frac * (v2->y - v1->y);
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ outv->p[paramnum] = v1->p[paramnum] + frac * (v2->p[paramnum] - v1->p[paramnum]);
+}
+
+
+/*-------------------------------------------------
+ copy_vertex - copy vertex data from one to
+ another
+-------------------------------------------------*/
+
+INLINE void copy_vertex(poly_vertex *outv, const poly_vertex *v, int paramcount)
+{
+ int paramnum;
+
+ outv->x = v->x;
+ outv->y = v->y;
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ outv->p[paramnum] = v->p[paramnum];
+}
+
+
+/*-------------------------------------------------
+ allocate_polygon - allocate a new polygon
+ object, blocking if we run out
+-------------------------------------------------*/
+
+INLINE polygon_info *allocate_polygon(poly_manager *poly, int miny, int maxy)
+{
+ /* wait for a work item if we have to */
+ if (poly->polygon_next + 1 > poly->polygon_count)
+ {
+ poly_wait(poly, "Out of polygons");
+#if KEEP_STATISTICS
+ poly->polygon_waits++;
+#endif
+ }
+ else if (poly->unit_next + (maxy - miny) / SCANLINES_PER_BUCKET + 2 > poly->unit_count)
+ {
+ poly_wait(poly, "Out of work units");
+#if KEEP_STATISTICS
+ poly->unit_waits++;
+#endif
+ }
+#if KEEP_STATISTICS
+ poly->polygon_max = MAX(poly->polygon_max, poly->polygon_next + 1);
+#endif
+ return poly->polygon[poly->polygon_next++];
+}
+
+
+
+/***************************************************************************
+ INITIALIZATION/TEARDOWN
+***************************************************************************/
+
+/*-------------------------------------------------
+ poly_alloc - initialize a new polygon
+ manager
+-------------------------------------------------*/
+
+poly_manager *poly_alloc(int max_polys, size_t extra_data_size, UINT8 flags)
+{
+ poly_manager *poly;
+
+ /* allocate the manager itself */
+ poly = malloc_or_die(sizeof(*poly));
+ memset(poly, 0, sizeof(*poly));
+ poly->flags = flags;
+
+ /* allocate polygons */
+ poly->polygon_size = sizeof(polygon_info);
+ poly->polygon_count = MAX(max_polys, 1);
+ poly->polygon_next = 0;
+ poly->polygon = (polygon_info **)allocate_array(&poly->polygon_size, poly->polygon_count);
+
+ /* allocate extra data */
+ poly->extra_size = extra_data_size;
+ poly->extra_count = poly->polygon_count;
+ poly->extra_next = 1;
+ poly->extra = allocate_array(&poly->extra_size, poly->extra_count);
+
+ /* allocate triangle work units */
+ poly->unit_size = (flags & POLYFLAG_ALLOW_QUADS) ? sizeof(quad_work_unit) : sizeof(tri_work_unit);
+ poly->unit_count = MIN(poly->polygon_count * UNITS_PER_POLY, 65535);
+ poly->unit_next = 0;
+ poly->unit = (work_unit **)allocate_array(&poly->unit_size, poly->unit_count);
+
+ /* create the work queue */
+ if (!(flags & POLYFLAG_NO_WORK_QUEUE))
+ poly->queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ);
+ return poly;
+}
+
+
+/*-------------------------------------------------
+ poly_free - free a polygon manager
+-------------------------------------------------*/
+
+void poly_free(poly_manager *poly)
+{
+#if KEEP_STATISTICS
+{
+ int i, conflicts = 0, resolved = 0;
+ for (i = 0; i < ARRAY_LENGTH(poly->conflicts); i++)
+ {
+ conflicts += poly->conflicts[i];
+ resolved += poly->resolved[i];
+ }
+ printf("Total triangles = %d\n", poly->triangles);
+ printf("Total quads = %d\n", poly->quads);
+ if (poly->pixels > 1000000000)
+ printf("Total pixels = %d%09d\n", (UINT32)(poly->pixels / 1000000000), (UINT32)(poly->pixels % 1000000000));
+ else
+ printf("Total pixels = %d\n", (UINT32)poly->pixels);
+ printf("Conflicts: %d resolved, %d total\n", resolved, conflicts);
+ printf("Units: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->unit_max, poly->unit_count, poly->unit_waits, poly->unit_size, poly->unit_count * poly->unit_size);
+ printf("Polygons: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->polygon_max, poly->polygon_count, poly->polygon_waits, poly->polygon_size, poly->polygon_count * poly->polygon_size);
+ printf("Extra data: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->extra_max, poly->extra_count, poly->extra_waits, poly->extra_size, poly->extra_count * poly->extra_size);
+}
+#endif
+
+ /* free the work queue */
+ if (poly->queue != NULL)
+ osd_work_queue_free(poly->queue);
+
+ /* free the arrays */
+ free_array(poly->extra);
+ free_array((void **)poly->polygon);
+ free_array((void **)poly->unit);
+
+ /* free the manager itself */
+ free(poly);
+}
+
+
+
+/***************************************************************************
+ COMMON FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ poly_wait - wait for all pending rendering
+ to complete
+-------------------------------------------------*/
+
+void poly_wait(poly_manager *poly, const char *debug_reason)
+{
+ osd_ticks_t time;
+
+ /* remember the start time if we're logging */
+ if (LOG_WAITS)
+ time = osd_profiling_ticks();
+
+ /* wait for all pending work items to complete */
+ if (poly->queue != NULL)
+ osd_work_queue_wait(poly->queue, osd_ticks_per_second() * 100);
+
+ /* if we don't have a queue, just run the whole list now */
+ else
+ {
+ int unitnum;
+ for (unitnum = 0; unitnum < poly->unit_next; unitnum++)
+ poly_item_callback(poly->unit[unitnum], 0);
+ }
+
+ /* log any long waits */
+ if (LOG_WAITS)
+ {
+ time = osd_profiling_ticks() - time;
+ if (time > LOG_WAIT_THRESHOLD)
+ logerror("Poly:Waited %d cycles for %s\n", (int)time, debug_reason);
+ }
+
+ /* reset the state */
+ poly->polygon_next = poly->unit_next = 0;
+ memset(poly->unit_bucket, 0xff, sizeof(poly->unit_bucket));
+
+ /* we need to preserve the last extra data that was supplied */
+ if (poly->extra_next > 1)
+ memcpy(poly->extra[0], poly->extra[poly->extra_next - 1], poly->extra_size);
+ poly->extra_next = 1;
+}
+
+
+/*-------------------------------------------------
+ poly_get_extra_data - get a pointer to the
+ extra data for the next polygon
+-------------------------------------------------*/
+
+void *poly_get_extra_data(poly_manager *poly)
+{
+ /* wait for a work item if we have to */
+ if (poly->extra_next + 1 > poly->extra_count)
+ {
+ poly_wait(poly, "Out of extra data");
+#if KEEP_STATISTICS
+ poly->extra_waits++;
+#endif
+ }
+
+ /* return a pointer to the extra data for the next item */
+#if KEEP_STATISTICS
+ poly->extra_max = MAX(poly->extra_max, poly->extra_next + 1);
+#endif
+ return poly->extra[poly->extra_next++];
+}
+
+
+
+/***************************************************************************
+ CORE TRIANGLE RENDERING
+***************************************************************************/
+
+/*-------------------------------------------------
+ poly_render_triangle - render a single
+ triangle given 3 vertexes
+-------------------------------------------------*/
+
+UINT32 poly_render_triangle(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3)
+{
+ float dxdy_v1v2, dxdy_v1v3, dxdy_v2v3;
+ const poly_vertex *tv;
+ INT32 curscan, scaninc;
+ polygon_info *polygon;
+ INT32 v1yclip, v3yclip;
+ INT32 v1y, v3y, v1x;
+ INT32 pixels = 0;
+ UINT32 startunit;
+
+ /* first sort by Y */
+ if (v2->y < v1->y)
+ {
+ tv = v1;
+ v1 = v2;
+ v2 = tv;
+ }
+ if (v3->y < v2->y)
+ {
+ tv = v2;
+ v2 = v3;
+ v3 = tv;
+ if (v2->y < v1->y)
+ {
+ tv = v1;
+ v1 = v2;
+ v2 = tv;
+ }
+ }
+
+ /* compute some integral X/Y vertex values */
+ v1x = round_coordinate(v1->x);
+ v1y = round_coordinate(v1->y);
+ v3y = round_coordinate(v3->y);
+
+ /* clip coordinates */
+ v1yclip = v1y;
+ v3yclip = v3y + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0);
+ if (cliprect != NULL)
+ {
+ v1yclip = MAX(v1yclip, cliprect->min_y);
+ v3yclip = MIN(v3yclip, cliprect->max_y + 1);
+ }
+ if (v3yclip - v1yclip <= 0)
+ return 0;
+
+ /* allocate a new polygon */
+ polygon = allocate_polygon(poly, v1yclip, v3yclip);
+
+ /* fill in the polygon information */
+ polygon->poly = poly;
+ polygon->dest = dest;
+ polygon->callback = callback;
+ polygon->extra = poly->extra[poly->extra_next - 1];
+ polygon->numparams = paramcount;
+ polygon->numverts = 3;
+
+ /* set the start X/Y coordinates */
+ polygon->xorigin = v1x;
+ polygon->yorigin = v1y;
+
+ /* compute the slopes for each portion of the triangle */
+ dxdy_v1v2 = (v2->y == v1->y) ? 0.0f : (v2->x - v1->x) / (v2->y - v1->y);
+ dxdy_v1v3 = (v3->y == v1->y) ? 0.0f : (v3->x - v1->x) / (v3->y - v1->y);
+ dxdy_v2v3 = (v3->y == v2->y) ? 0.0f : (v3->x - v2->x) / (v3->y - v2->y);
+
+ /* compute the X extents for each scanline */
+ startunit = poly->unit_next;
+ for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc)
+ {
+ UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS;
+ UINT32 unit_index = poly->unit_next++;
+ tri_work_unit *unit = &poly->unit[unit_index]->tri;
+ int extnum;
+
+ /* determine how much to advance to hit the next bucket */
+ scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET;
+
+ /* fill in the work unit basics */
+ unit->shared.polygon = polygon;
+ unit->shared.count_next = MIN(v3yclip - curscan, scaninc);
+ unit->shared.scanline = curscan;
+ unit->shared.previtem = poly->unit_bucket[bucketnum];
+ poly->unit_bucket[bucketnum] = unit_index;
+
+ /* iterate over extents */
+ for (extnum = 0; extnum < unit->shared.count_next; extnum++)
+ {
+ float fully = (float)(curscan + extnum) + 0.5f;
+ float startx = v1->x + (fully - v1->y) * dxdy_v1v3;
+ float stopx;
+ INT32 istartx, istopx;
+
+ /* compute the ending X based on which part of the triangle we're in */
+ if (fully < v2->y)
+ stopx = v1->x + (fully - v1->y) * dxdy_v1v2;
+ else
+ stopx = v2->x + (fully - v2->y) * dxdy_v2v3;
+
+ /* clamp to full pixels */
+ istartx = round_coordinate(startx);
+ istopx = round_coordinate(stopx);
+
+ /* force start < stop */
+ if (istartx > istopx)
+ {
+ INT32 temp = istartx;
+ istartx = istopx;
+ istopx = temp;
+ }
+
+ /* include the right edge if requested */
+ if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE)
+ istopx++;
+
+ /* apply left/right clipping */
+ if (cliprect != NULL)
+ {
+ if (istartx < cliprect->min_x)
+ istartx = cliprect->min_x;
+ if (istopx > cliprect->max_x)
+ istopx = cliprect->max_x + 1;
+ }
+
+ /* set the extent and update the total pixel count */
+ if (istartx >= istopx)
+ istartx = istopx = 0;
+ unit->extent[extnum].startx = istartx;
+ unit->extent[extnum].stopx = istopx;
+ pixels += istopx - istartx;
+ }
+ }
+#if KEEP_STATISTICS
+ poly->unit_max = MAX(poly->unit_max, poly->unit_next);
+#endif
+
+ /* compute parameter starting points and deltas */
+ if (paramcount > 0)
+ {
+ float divisor, dx1, dx2, dy1, dy2, xoffset, yoffset;
+ int paramnum;
+
+ /* compute the divisor */
+ divisor = 1.0f / ((v1->x - v2->x) * (v1->y - v3->y) - (v1->x - v3->x) * (v1->y - v2->y));
+
+ /* compute the dx/dy values */
+ dx1 = v1->y - v3->y;
+ dx2 = v1->y - v2->y;
+ dy1 = v1->x - v2->x;
+ dy2 = v1->x - v3->x;
+
+ /* determine x/y offset for subpixel correction so that the starting values are
+ relative to the integer coordinates */
+ xoffset = v1->x - ((float)polygon->xorigin + 0.5f);
+ yoffset = v1->y - ((float)polygon->yorigin + 0.5f);
+
+ /* iterate over parameters */
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ {
+ poly_param *params = &polygon->param[paramnum];
+ params->dpdx = ((v1->p[paramnum] - v2->p[paramnum]) * dx1 - (v1->p[paramnum] - v3->p[paramnum]) * dx2) * divisor;
+ params->dpdy = ((v1->p[paramnum] - v3->p[paramnum]) * dy1 - (v1->p[paramnum] - v2->p[paramnum]) * dy2) * divisor;
+ params->start = v1->p[paramnum] - xoffset * params->dpdx - yoffset * params->dpdy;
+ }
+ }
+
+ /* enqueue the work items */
+ if (poly->queue != NULL)
+ osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE);
+
+ /* return the total number of pixels in the triangle */
+ poly->triangles++;
+ poly->pixels += pixels;
+ return pixels;
+}
+
+
+/*-------------------------------------------------
+ poly_render_triangle_fan - render a set of
+ triangles in a fan
+-------------------------------------------------*/
+
+UINT32 poly_render_triangle_fan(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, int numverts, const poly_vertex *v)
+{
+ UINT32 pixels = 0;
+ int vertnum;
+
+ /* iterate over vertices */
+ for (vertnum = 2; vertnum < numverts; vertnum++)
+ pixels += poly_render_triangle(poly, dest, cliprect, callback, paramcount, &v[0], &v[vertnum - 1], &v[vertnum]);
+ return pixels;
+}
+
+
+/*-------------------------------------------------
+ poly_render_triangle_custom - perform a custom
+ render of an object, given specific extents
+-------------------------------------------------*/
+
+UINT32 poly_render_triangle_custom(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int startscanline, int numscanlines, const poly_extent *extents)
+{
+ INT32 curscan, scaninc;
+ polygon_info *polygon;
+ INT32 v1yclip, v3yclip;
+ INT32 pixels = 0;
+ UINT32 startunit;
+
+ /* clip coordinates */
+ if (cliprect != NULL)
+ {
+ v1yclip = MAX(startscanline, cliprect->min_y);
+ v3yclip = MIN(startscanline + numscanlines, cliprect->max_y + 1);
+ }
+ else
+ {
+ v1yclip = startscanline;
+ v3yclip = startscanline + numscanlines;
+ }
+ if (v3yclip - v1yclip <= 0)
+ return 0;
+
+ /* allocate a new polygon */
+ polygon = allocate_polygon(poly, v1yclip, v3yclip);
+
+ /* fill in the polygon information */
+ polygon->poly = poly;
+ polygon->dest = dest;
+ polygon->callback = callback;
+ polygon->extra = poly->extra[poly->extra_next - 1];
+ polygon->numparams = 0;
+ polygon->numverts = 3;
+
+ /* compute the X extents for each scanline */
+ startunit = poly->unit_next;
+ for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc)
+ {
+ UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS;
+ UINT32 unit_index = poly->unit_next++;
+ tri_work_unit *unit = &poly->unit[unit_index]->tri;
+ int extnum;
+
+ /* determine how much to advance to hit the next bucket */
+ scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET;
+
+ /* fill in the work unit basics */
+ unit->shared.polygon = polygon;
+ unit->shared.count_next = MIN(v3yclip - curscan, scaninc);
+ unit->shared.scanline = curscan;
+ unit->shared.previtem = poly->unit_bucket[bucketnum];
+ poly->unit_bucket[bucketnum] = unit_index;
+
+ /* iterate over extents */
+ for (extnum = 0; extnum < unit->shared.count_next; extnum++)
+ {
+ const poly_extent *extent = &extents[(curscan + extnum) - startscanline];
+ INT32 istartx = extent->startx, istopx = extent->stopx;
+
+ /* force start < stop */
+ if (istartx > istopx)
+ {
+ INT32 temp = istartx;
+ istartx = istopx;
+ istopx = temp;
+ }
+
+ /* apply left/right clipping */
+ if (cliprect != NULL)
+ {
+ if (istartx < cliprect->min_x)
+ istartx = cliprect->min_x;
+ if (istopx > cliprect->max_x)
+ istopx = cliprect->max_x + 1;
+ }
+
+ /* set the extent and update the total pixel count */
+ unit->extent[extnum].startx = istartx;
+ unit->extent[extnum].stopx = istopx;
+ if (istartx < istopx)
+ pixels += istopx - istartx;
+ }
+ }
+#if KEEP_STATISTICS
+ poly->unit_max = MAX(poly->unit_max, poly->unit_next);
+#endif
+
+ /* enqueue the work items */
+ if (poly->queue != NULL)
+ osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE);
+
+ /* return the total number of pixels in the object */
+ poly->triangles++;
+ poly->pixels += pixels;
+ return pixels;
+}
+
+
+
+/***************************************************************************
+ CORE QUAD RENDERING
+***************************************************************************/
+
+/*-------------------------------------------------
+ poly_render_quad - render a single quad
+ given 4 vertexes
+-------------------------------------------------*/
+
+UINT32 poly_render_quad(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3, const poly_vertex *v4)
+{
+ poly_edge fedgelist[3], bedgelist[3];
+ const poly_edge *ledge, *redge;
+ const poly_vertex *v[4];
+ poly_edge *edgeptr;
+ int minv, maxv, curv;
+ INT32 minyclip, maxyclip;
+ INT32 miny, maxy;
+ INT32 curscan, scaninc;
+ polygon_info *polygon;
+ INT32 pixels = 0;
+ UINT32 startunit;
+
+ assert(poly->flags & POLYFLAG_ALLOW_QUADS);
+
+ /* arrays make things easier */
+ v[0] = v1;
+ v[1] = v2;
+ v[2] = v3;
+ v[3] = v4;
+
+ /* determine min/max Y vertices */
+ if (v[1]->y < v[0]->y)
+ minv = 1, maxv = 0;
+ else
+ minv = 0, maxv = 1;
+ if (v[2]->y < v[minv]->y)
+ minv = 2;
+ else if (v[2]->y > v[maxv]->y)
+ maxv = 2;
+ if (v[3]->y < v[minv]->y)
+ minv = 3;
+ else if (v[3]->y > v[maxv]->y)
+ maxv = 3;
+
+ /* determine start/end scanlines */
+ miny = round_coordinate(v[minv]->y);
+ maxy = round_coordinate(v[maxv]->y);
+
+ /* clip coordinates */
+ minyclip = miny;
+ maxyclip = maxy + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0);
+ if (cliprect != NULL)
+ {
+ minyclip = MAX(minyclip, cliprect->min_y);
+ maxyclip = MIN(maxyclip, cliprect->max_y + 1);
+ }
+ if (maxyclip - minyclip <= 0)
+ return 0;
+
+ /* allocate a new polygon */
+ polygon = allocate_polygon(poly, minyclip, maxyclip);
+
+ /* fill in the polygon information */
+ polygon->poly = poly;
+ polygon->dest = dest;
+ polygon->callback = callback;
+ polygon->extra = poly->extra[poly->extra_next - 1];
+ polygon->numparams = paramcount;
+ polygon->numverts = 4;
+
+ /* walk forward to build up the forward edge list */
+ edgeptr = &fedgelist[0];
+ for (curv = minv; curv != maxv; curv = (curv + 1) & 3)
+ {
+ int paramnum;
+ float ooy;
+
+ /* set the two vertices */
+ edgeptr->v1 = v[curv];
+ edgeptr->v2 = v[(curv + 1) & 3];
+
+ /* if horizontal, skip altogether */
+ if (edgeptr->v1->y == edgeptr->v2->y)
+ continue;
+
+ /* need dx/dy always, and parameter deltas as necessary */
+ ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y);
+ edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy;
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy;
+ edgeptr++;
+ }
+
+ /* walk backward to build up the backward edge list */
+ edgeptr = &bedgelist[0];
+ for (curv = minv; curv != maxv; curv = (curv - 1) & 3)
+ {
+ int paramnum;
+ float ooy;
+
+ /* set the two vertices */
+ edgeptr->v1 = v[curv];
+ edgeptr->v2 = v[(curv - 1) & 3];
+
+ /* if horizontal, skip altogether */
+ if (edgeptr->v1->y == edgeptr->v2->y)
+ continue;
+
+ /* need dx/dy always, and parameter deltas as necessary */
+ ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y);
+ edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy;
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy;
+ edgeptr++;
+ }
+
+ /* determine which list is left/right: */
+ /* if the first vertex is shared, compare the slopes */
+ /* if the first vertex is not shared, compare the X coordinates */
+ if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) ||
+ (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x))
+ {
+ ledge = fedgelist;
+ redge = bedgelist;
+ }
+ else
+ {
+ ledge = bedgelist;
+ redge = fedgelist;
+ }
+
+ /* compute the X extents for each scanline */
+ startunit = poly->unit_next;
+ for (curscan = minyclip; curscan < maxyclip; curscan += scaninc)
+ {
+ UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS;
+ UINT32 unit_index = poly->unit_next++;
+ quad_work_unit *unit = &poly->unit[unit_index]->quad;
+ int extnum;
+
+ /* determine how much to advance to hit the next bucket */
+ scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET;
+
+ /* fill in the work unit basics */
+ unit->shared.polygon = polygon;
+ unit->shared.count_next = MIN(maxyclip - curscan, scaninc);
+ unit->shared.scanline = curscan;
+ unit->shared.previtem = poly->unit_bucket[bucketnum];
+ poly->unit_bucket[bucketnum] = unit_index;
+
+ /* iterate over extents */
+ for (extnum = 0; extnum < unit->shared.count_next; extnum++)
+ {
+ float fully = (float)(curscan + extnum) + 0.5f;
+ float startx, stopx;
+ INT32 istartx, istopx;
+ int paramnum;
+
+ /* compute the ending X based on which part of the triangle we're in */
+ while (fully > ledge->v2->y && fully < v[maxv]->y)
+ ledge++;
+ while (fully > redge->v2->y && fully < v[maxv]->y)
+ redge++;
+ startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy;
+ stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy;
+
+ /* clamp to full pixels */
+ istartx = round_coordinate(startx);
+ istopx = round_coordinate(stopx);
+
+ /* compute parameter starting points and deltas */
+ if (paramcount > 0)
+ {
+ float ldy = fully - ledge->v1->y;
+ float rdy = fully - redge->v1->y;
+ float oox = 1.0f / (stopx - startx);
+
+ /* iterate over parameters */
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ {
+ float lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum];
+ float rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum];
+ float dpdx = (rparam - lparam) * oox;
+
+ unit->extent[extnum].param[paramnum].start = lparam;// - ((float)istartx + 0.5f) * dpdx;
+ unit->extent[extnum].param[paramnum].dpdx = dpdx;
+ }
+ }
+
+ /* include the right edge if requested */
+ if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE)
+ istopx++;
+
+ /* apply left/right clipping */
+ if (cliprect != NULL)
+ {
+ if (istartx < cliprect->min_x)
+ {
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ unit->extent[extnum].param[paramnum].start += (cliprect->min_x - istartx) * unit->extent[extnum].param[paramnum].dpdx;
+ istartx = cliprect->min_x;
+ }
+ if (istopx > cliprect->max_x)
+ istopx = cliprect->max_x + 1;
+ }
+
+ /* set the extent and update the total pixel count */
+ if (istartx >= istopx)
+ istartx = istopx = 0;
+ unit->extent[extnum].startx = istartx;
+ unit->extent[extnum].stopx = istopx;
+ pixels += istopx - istartx;
+ }
+ }
+#if KEEP_STATISTICS
+ poly->unit_max = MAX(poly->unit_max, poly->unit_next);
+#endif
+
+ /* enqueue the work items */
+ if (poly->queue != NULL)
+ osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE);
+
+ /* return the total number of pixels in the triangle */
+ poly->quads++;
+ poly->pixels += pixels;
+ return pixels;
+}
+
+
+/*-------------------------------------------------
+ poly_render_quad_fan - render a set of
+ quads in a fan
+-------------------------------------------------*/
+
+UINT32 poly_render_quad_fan(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, int numverts, const poly_vertex *v)
+{
+ UINT32 pixels = 0;
+ int vertnum;
+
+ /* iterate over vertices */
+ for (vertnum = 2; vertnum < numverts; vertnum += 2)
+ pixels += poly_render_quad(poly, dest, cliprect, callback, paramcount, &v[0], &v[vertnum - 1], &v[vertnum], &v[MIN(vertnum + 1, numverts - 1)]);
+ return pixels;
+}
+
+
+
+/***************************************************************************
+ CORE POLYGON RENDERING
+***************************************************************************/
+
+/*-------------------------------------------------
+ poly_render_polygon - render a single polygon up
+ to 32 vertices
+-------------------------------------------------*/
+
+UINT32 poly_render_polygon(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, int numverts, const poly_vertex *v)
+{
+ poly_edge fedgelist[MAX_POLYGON_VERTS - 1], bedgelist[MAX_POLYGON_VERTS - 1];
+ const poly_edge *ledge, *redge;
+ poly_edge *edgeptr;
+ int minv, maxv, curv;
+ INT32 minyclip, maxyclip;
+ INT32 miny, maxy;
+ INT32 curscan, scaninc;
+ polygon_info *polygon;
+ INT32 pixels = 0;
+ UINT32 startunit;
+ int vertnum;
+
+ assert(poly->flags & POLYFLAG_ALLOW_QUADS);
+
+ /* determine min/max Y vertices */
+ minv = maxv = 0;
+ for (vertnum = 1; vertnum < numverts; vertnum++)
+ {
+ if (v[vertnum].y < v[minv].y)
+ minv = vertnum;
+ else if (v[vertnum].y > v[maxv].y)
+ maxv = vertnum;
+ }
+
+ /* determine start/end scanlines */
+ miny = round_coordinate(v[minv].y);
+ maxy = round_coordinate(v[maxv].y);
+
+ /* clip coordinates */
+ minyclip = miny;
+ maxyclip = maxy + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0);
+ if (cliprect != NULL)
+ {
+ minyclip = MAX(minyclip, cliprect->min_y);
+ maxyclip = MIN(maxyclip, cliprect->max_y + 1);
+ }
+ if (maxyclip - minyclip <= 0)
+ return 0;
+
+ /* allocate a new polygon */
+ polygon = allocate_polygon(poly, minyclip, maxyclip);
+
+ /* fill in the polygon information */
+ polygon->poly = poly;
+ polygon->dest = dest;
+ polygon->callback = callback;
+ polygon->extra = poly->extra[poly->extra_next - 1];
+ polygon->numparams = paramcount;
+ polygon->numverts = numverts;
+
+ /* walk forward to build up the forward edge list */
+ edgeptr = &fedgelist[0];
+ for (curv = minv; curv != maxv; curv = (curv == numverts - 1) ? 0 : (curv + 1))
+ {
+ int paramnum;
+ float ooy;
+
+ /* set the two vertices */
+ edgeptr->v1 = &v[curv];
+ edgeptr->v2 = &v[(curv == numverts - 1) ? 0 : (curv + 1)];
+
+ /* if horizontal, skip altogether */
+ if (edgeptr->v1->y == edgeptr->v2->y)
+ continue;
+
+ /* need dx/dy always, and parameter deltas as necessary */
+ ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y);
+ edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy;
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy;
+ edgeptr++;
+ }
+
+ /* walk backward to build up the backward edge list */
+ edgeptr = &bedgelist[0];
+ for (curv = minv; curv != maxv; curv = (curv == 0) ? (numverts - 1) : (curv - 1))
+ {
+ int paramnum;
+ float ooy;
+
+ /* set the two vertices */
+ edgeptr->v1 = &v[curv];
+ edgeptr->v2 = &v[(curv == 0) ? (numverts - 1) : (curv - 1)];
+
+ /* if horizontal, skip altogether */
+ if (edgeptr->v1->y == edgeptr->v2->y)
+ continue;
+
+ /* need dx/dy always, and parameter deltas as necessary */
+ ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y);
+ edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy;
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy;
+ edgeptr++;
+ }
+
+ /* determine which list is left/right: */
+ /* if the first vertex is shared, compare the slopes */
+ /* if the first vertex is not shared, compare the X coordinates */
+ if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) ||
+ (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x))
+ {
+ ledge = fedgelist;
+ redge = bedgelist;
+ }
+ else
+ {
+ ledge = bedgelist;
+ redge = fedgelist;
+ }
+
+ /* compute the X extents for each scanline */
+ startunit = poly->unit_next;
+ for (curscan = minyclip; curscan < maxyclip; curscan += scaninc)
+ {
+ UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS;
+ UINT32 unit_index = poly->unit_next++;
+ quad_work_unit *unit = &poly->unit[unit_index]->quad;
+ int extnum;
+
+ /* determine how much to advance to hit the next bucket */
+ scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET;
+
+ /* fill in the work unit basics */
+ unit->shared.polygon = polygon;
+ unit->shared.count_next = MIN(maxyclip - curscan, scaninc);
+ unit->shared.scanline = curscan;
+ unit->shared.previtem = poly->unit_bucket[bucketnum];
+ poly->unit_bucket[bucketnum] = unit_index;
+
+ /* iterate over extents */
+ for (extnum = 0; extnum < unit->shared.count_next; extnum++)
+ {
+ float fully = (float)(curscan + extnum) + 0.5f;
+ float startx, stopx;
+ INT32 istartx, istopx;
+ int paramnum;
+
+ /* compute the ending X based on which part of the triangle we're in */
+ while (fully > ledge->v2->y && fully < v[maxv].y)
+ ledge++;
+ while (fully > redge->v2->y && fully < v[maxv].y)
+ redge++;
+ startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy;
+ stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy;
+
+ /* clamp to full pixels */
+ istartx = round_coordinate(startx);
+ istopx = round_coordinate(stopx);
+
+ /* compute parameter starting points and deltas */
+ if (paramcount > 0)
+ {
+ float ldy = fully - ledge->v1->y;
+ float rdy = fully - redge->v1->y;
+ float oox = 1.0f / (stopx - startx);
+
+ /* iterate over parameters */
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ {
+ float lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum];
+ float rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum];
+ float dpdx = (rparam - lparam) * oox;
+
+ unit->extent[extnum].param[paramnum].start = lparam;// - ((float)istartx + 0.5f) * dpdx;
+ unit->extent[extnum].param[paramnum].dpdx = dpdx;
+ }
+ }
+
+ /* include the right edge if requested */
+ if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE)
+ istopx++;
+
+ /* apply left/right clipping */
+ if (cliprect != NULL)
+ {
+ if (istartx < cliprect->min_x)
+ {
+ for (paramnum = 0; paramnum < paramcount; paramnum++)
+ unit->extent[extnum].param[paramnum].start += (cliprect->min_x - istartx) * unit->extent[extnum].param[paramnum].dpdx;
+ istartx = cliprect->min_x;
+ }
+ if (istopx > cliprect->max_x)
+ istopx = cliprect->max_x + 1;
+ }
+
+ /* set the extent and update the total pixel count */
+ if (istartx >= istopx)
+ istartx = istopx = 0;
+ unit->extent[extnum].startx = istartx;
+ unit->extent[extnum].stopx = istopx;
+ pixels += istopx - istartx;
+ }
+ }
+#if KEEP_STATISTICS
+ poly->unit_max = MAX(poly->unit_max, poly->unit_next);
+#endif
+
+ /* enqueue the work items */
+ if (poly->queue != NULL)
+ osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE);
+
+ /* return the total number of pixels in the triangle */
+ poly->quads++;
+ poly->pixels += pixels;
+ return pixels;
+}
+
+
+
+/***************************************************************************
+ CLIPPING
+***************************************************************************/
+
+/*-------------------------------------------------
+ poly_zclip_if_less - z clip a polygon against
+ the given value, returning a set of clipped
+ vertices
+-------------------------------------------------*/
+
+int poly_zclip_if_less(int numverts, const poly_vertex *v, poly_vertex *outv, int paramcount, float clipval)
+{
+ int prevclipped = (v[numverts - 1].p[0] < clipval);
+ poly_vertex *nextout = outv;
+ int vertnum;
+
+ /* iterate over vertices */
+ for (vertnum = 0; vertnum < numverts; vertnum++)
+ {
+ int thisclipped = (v[vertnum].p[0] < clipval);
+
+ /* if we switched from clipped to non-clipped, interpolate a vertex */
+ if (thisclipped != prevclipped)
+ interpolate_vertex(nextout++, &v[(vertnum == 0) ? (numverts - 1) : (vertnum - 1)], &v[vertnum], paramcount, clipval);
+
+ /* if this vertex is not clipped, copy it in */
+ if (!thisclipped)
+ copy_vertex(nextout++, &v[vertnum], paramcount);
+
+ /* remember the last state */
+ prevclipped = thisclipped;
+ }
+ return nextout - outv;
+}
+
+
+
+/***************************************************************************
+ INTERNAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ allocate_array - allocate an array of pointers
+-------------------------------------------------*/
+
+static void **allocate_array(size_t *itemsize, UINT32 itemcount)
+{
+ void **ptrarray;
+ int itemnum;
+
+ /* fail if 0 */
+ if (itemcount == 0)
+ return NULL;
+
+ /* round to a cache line boundary */
+ *itemsize = ((*itemsize + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE;
+
+ /* allocate the array */
+ ptrarray = malloc_or_die(sizeof(*ptrarray) * itemcount);
+ memset(ptrarray, 0, sizeof(*ptrarray) * itemcount);
+
+ /* allocate the actual items */
+ ptrarray[0] = malloc_or_die(*itemsize * itemcount);
+ memset(ptrarray[0], 0, *itemsize * itemcount);
+
+ /* initialize the pointer array */
+ for (itemnum = 1; itemnum < itemcount; itemnum++)
+ ptrarray[itemnum] = (UINT8 *)ptrarray[0] + *itemsize * itemnum;
+ return ptrarray;
+}
+
+
+/*-------------------------------------------------
+ free_array - release an array of pointers
+-------------------------------------------------*/
+
+static void free_array(void **array)
+{
+ if (array != NULL)
+ {
+ if (array[0] != NULL)
+ free(array[0]);
+ free(array);
+ }
+}
+
+
+/*-------------------------------------------------
+ poly_item_callback - callback for each poly
+ item
+-------------------------------------------------*/
+
+static void *poly_item_callback(void *param, int threadid)
+{
+ while (1)
+ {
+ work_unit *unit = param;
+ polygon_info *polygon = unit->shared.polygon;
+ int count = unit->shared.count_next & 0xffff;
+ UINT32 orig_count_next;
+ int curscan;
+
+ /* if our previous item isn't done yet, enqueue this item to the end and proceed */
+ if (unit->shared.previtem != 0xffff)
+ {
+ work_unit *prevunit = polygon->poly->unit[unit->shared.previtem];
+ if (prevunit->shared.count_next != 0)
+ {
+ UINT32 unitnum = ((UINT8 *)unit - (UINT8 *)polygon->poly->unit[0]) / polygon->poly->unit_size;
+ UINT32 new_count_next;
+
+ /* attempt to atomically swap in this new value */
+ do
+ {
+ orig_count_next = prevunit->shared.count_next;
+ new_count_next = orig_count_next | (unitnum << 16);
+ } while (compare_exchange32((volatile INT32 *)&prevunit->shared.count_next, orig_count_next, new_count_next) != orig_count_next);
+
+#if KEEP_STATISTICS
+ /* track resolved conflicts */
+ polygon->poly->conflicts[threadid]++;
+ if (orig_count_next != 0)
+ polygon->poly->resolved[threadid]++;
+#endif
+ /* if we succeeded, skip out early so we can do other work */
+ if (orig_count_next != 0)
+ break;
+ }
+ }
+
+ /* iterate over extents */
+ for (curscan = 0; curscan < count; curscan++)
+ {
+ if (polygon->numverts == 3)
+ {
+ poly_extent tmpextent;
+ convert_tri_extent_to_poly_extent(&tmpextent, &unit->tri.extent[curscan], polygon, unit->shared.scanline + curscan);
+ (*polygon->callback)(polygon->dest, unit->shared.scanline + curscan, &tmpextent, polygon->extra, threadid);
+ }
+ else
+ (*polygon->callback)(polygon->dest, unit->shared.scanline + curscan, &unit->quad.extent[curscan], polygon->extra, threadid);
+ }
+
+ /* set our count to 0 and re-fetch the original count value */
+ do
+ {
+ orig_count_next = unit->shared.count_next;
+ } while (compare_exchange32((volatile INT32 *)&unit->shared.count_next, orig_count_next, 0) != orig_count_next);
+
+ /* if we have no more work to do, do nothing */
+ orig_count_next >>= 16;
+ if (orig_count_next == 0)
+ break;
+ param = polygon->poly->unit[orig_count_next];
+ }
+ return NULL;
+}
diff --git a/src/emu/video/poly.h b/src/emu/video/poly.h
new file mode 100644
index 00000000000..2cfee063900
--- /dev/null
+++ b/src/emu/video/poly.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+
+ poly.h
+
+ New polygon helper routines.
+
+****************************************************************************
+
+ Pixel model:
+
+ (0.0,0.0) (1.0,0.0) (2.0,0.0) (3.0,0.0)
+ +---------------+---------------+---------------+
+ | | | |
+ | | | |
+ | (0.5,0.5) | (1.5,0.5) | (2.5,0.5) |
+ | * | * | * |
+ | | | |
+ | | | |
+ (0.0,1.0) (1.0,1.0) (2.0,1.0) (3.0,1.0)
+ +---------------+---------------+---------------+
+ | | | |
+ | | | |
+ | (0.5,1.5) | (1.5,1.5) | (2.5,1.5) |
+ | * | * | * |
+ | | | |
+ | | | |
+ | | | |
+ +---------------+---------------+---------------+
+ (0.0,2.0) (1.0,2.0) (2.0,2.0) (3.0,2.0)
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __POLYNEW_H__
+#define __POLYNEW_H__
+
+#include "mamecore.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_VERTEX_PARAMS 6
+#define MAX_POLYGON_VERTS 32
+
+#define POLYFLAG_INCLUDE_BOTTOM_EDGE 0x01
+#define POLYFLAG_INCLUDE_RIGHT_EDGE 0x02
+#define POLYFLAG_NO_WORK_QUEUE 0x04
+#define POLYFLAG_ALLOW_QUADS 0x08
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* opaque reference to the poly manager */
+typedef struct _poly_manager poly_manager;
+
+
+/* input vertex data */
+typedef struct _poly_vertex poly_vertex;
+struct _poly_vertex
+{
+ float x; /* X coordinate */
+ float y; /* Y coordinate */
+ float p[MAX_VERTEX_PARAMS]; /* interpolated parameter values */
+};
+
+
+/* poly_param_extent describes information for a single parameter in an extent */
+typedef struct _poly_param_extent poly_param_extent;
+struct _poly_param_extent
+{
+ float start; /* parameter value at starting X,Y */
+ float dpdx; /* dp/dx relative to starting X */
+};
+
+
+/* poly_extent describes start/end points for a scanline, along with per-scanline parameters */
+typedef struct _poly_extent poly_extent;
+struct _poly_extent
+{
+ INT16 startx; /* starting X coordinate (inclusive) */
+ INT16 stopx; /* ending X coordinate (exclusive) */
+ poly_param_extent param[MAX_VERTEX_PARAMS]; /* starting and dx values for each parameter */
+};
+
+
+/* callback routine to process a batch of scanlines in a triangle */
+typedef void (*poly_draw_scanline)(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+
+/* ----- initialization/teardown ----- */
+
+/* allocate a new poly manager that can render triangles */
+poly_manager *poly_alloc(int max_polys, size_t extra_data_size, UINT8 flags);
+
+/* free a poly manager */
+void poly_free(poly_manager *poly);
+
+
+
+/* ----- common functions ----- */
+
+/* wait until all polygons in the queue have been rendered */
+void poly_wait(poly_manager *poly, const char *debug_reason);
+
+/* get a pointer to the extra data for the next polygon */
+void *poly_get_extra_data(poly_manager *poly);
+
+
+
+/* ----- core triangle rendering ----- */
+
+/* render a single triangle given 3 vertexes */
+UINT32 poly_render_triangle(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3);
+
+/* render a set of triangles in a fan */
+UINT32 poly_render_triangle_fan(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, int numverts, const poly_vertex *v);
+
+/* perform a custom render of an object, given specific extents */
+UINT32 poly_render_triangle_custom(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int startscanline, int numscanlines, const poly_extent *extents);
+
+
+
+/* ----- core quad rendering ----- */
+
+/* render a single quad given 4 vertexes */
+UINT32 poly_render_quad(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3, const poly_vertex *v4);
+
+/* render a set of quads in a fan */
+UINT32 poly_render_quad_fan(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, int numverts, const poly_vertex *v);
+
+
+
+/* ----- core polygon rendering ----- */
+
+/* render a single polygon up to 32 vertices */
+UINT32 poly_render_polygon(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline callback, int paramcount, int numverts, const poly_vertex *v);
+
+
+
+/* ----- clipping ----- */
+
+/* zclip (assumes p[0] == z) a polygon */
+int poly_zclip_if_less(int numverts, const poly_vertex *v, poly_vertex *outv, int paramcount, float clipval);
+
+
+#endif /* __POLY_H__ */
diff --git a/src/emu/video/resnet.c b/src/emu/video/resnet.c
new file mode 100644
index 00000000000..d27d0ce87cc
--- /dev/null
+++ b/src/emu/video/resnet.c
@@ -0,0 +1,738 @@
+/*****************************************************************************
+
+ resnet.c
+
+ Compute weights for resistors networks.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+******************************************************************************
+
+ Function can evaluate from one to three networks at a time.
+
+ The output weights can either be scaled with automatically calculated scaler
+ or scaled with a 'scaler' provided on entry.
+
+ On entry
+ --------
+
+ 'minval','maxval' specify the range of output signals (sum of weights).
+ 'scaler' if negative, function will calculate proper scaler,
+ otherwise it will use the one provided here.
+ 'count_x' is the number of resistors in this network
+ 'resistances_x' is the pointer to a table containing the resistances
+ 'weights_x' is the pointer to a table to be filled with the weights
+ (it can contain negative values if 'minval' is below zero).
+ 'pulldown_x' is the resistance of a pulldown resistor (0 means there's no pulldown resistor)
+ 'pullup_x' is the resistance of a pullup resistor (0 means there's no pullup resistor)
+
+
+ Return value
+ ------------
+
+ The value of the scaler that was used for fitting the output within the expected range.
+ Note that if you provide your own scaler on entry it will be returned here.
+
+
+ All resistances are expected in Ohms.
+
+
+ Hint
+ ----
+
+ If there is no need to calculate all three networks at a time, just specify '0'
+ for the 'count_x' for unused network(s).
+
+*****************************************************************************/
+
+
+#include "driver.h"
+#include "resnet.h"
+
+double compute_resistor_weights(
+ int minval, int maxval, double scaler,
+ int count_1, const int * resistances_1, double * weights_1, int pulldown_1, int pullup_1,
+ int count_2, const int * resistances_2, double * weights_2, int pulldown_2, int pullup_2,
+ int count_3, const int * resistances_3, double * weights_3, int pulldown_3, int pullup_3 )
+{
+
+ int networks_no;
+
+ int rescount[MAX_NETS]; /* number of resistors in each of the nets */
+ double r[MAX_NETS][MAX_RES_PER_NET]; /* resistances */
+ double w[MAX_NETS][MAX_RES_PER_NET]; /* calulated weights */
+ double ws[MAX_NETS][MAX_RES_PER_NET]; /* calulated, scaled weights */
+ int r_pd[MAX_NETS]; /* pulldown resistances */
+ int r_pu[MAX_NETS]; /* pullup resistances */
+
+ double max_out[MAX_NETS];
+ double * out[MAX_NETS];
+
+ int i,j,n;
+ double scale;
+ double max;
+
+ /* parse input parameters */
+
+ networks_no = 0;
+ for (n = 0; n < MAX_NETS; n++)
+ {
+ int count, pd, pu;
+ const int * resistances;
+ double * weights;
+
+ switch(n){
+ case 0:
+ count = count_1;
+ resistances = resistances_1;
+ weights = weights_1;
+ pd = pulldown_1;
+ pu = pullup_1;
+ break;
+ case 1:
+ count = count_2;
+ resistances = resistances_2;
+ weights = weights_2;
+ pd = pulldown_2;
+ pu = pullup_2;
+ break;
+ case 2:
+ default:
+ count = count_3;
+ resistances = resistances_3;
+ weights = weights_3;
+ pd = pulldown_3;
+ pu = pullup_3;
+ break;
+ }
+
+ /* parameters validity check */
+ if (count > MAX_RES_PER_NET)
+ {
+ logerror(" ERROR: res_net.h: compute_resistor_weights(): too many resistors in net #%i. The maximum allowed is %i, the number requested was: %i\n",n, MAX_RES_PER_NET, count);
+ /* quit */
+ return (0.0);
+ }
+
+
+ if (count > 0)
+ {
+ rescount[networks_no] = count;
+ for (i=0; i < count; i++)
+ {
+ r[networks_no][i] = 1.0 * resistances[i];
+ }
+ out[networks_no] = weights;
+ r_pd[networks_no] = pd;
+ r_pu[networks_no] = pu;
+ networks_no++;
+ }
+ }
+ if (networks_no < 1)
+ {
+ /* error - no networks to anaylse */
+ logerror(" ERROR: res_net.h: compute_resistor_weights(): no input data\n");
+ return (0.0);
+ }
+
+ /* calculate outputs for all given networks */
+ for( i = 0; i < networks_no; i++ )
+ {
+ double R0, R1, Vout, dst;
+
+ /* of n resistors */
+ for(n = 0; n < rescount[i]; n++)
+ {
+ R0 = ( r_pd[i] == 0 ) ? 1.0/1e12 : 1.0/r_pd[i];
+ R1 = ( r_pu[i] == 0 ) ? 1.0/1e12 : 1.0/r_pu[i];
+
+ for( j = 0; j < rescount[i]; j++ )
+ {
+ if( j==n ) /* only one resistance in the network connected to Vcc */
+ {
+ if (r[i][j] != 0.0)
+ R1 += 1.0/r[i][j];
+ }
+ else
+ if (r[i][j] != 0.0)
+ R0 += 1.0/r[i][j];
+ }
+
+ /* now determine the voltage */
+ R0 = 1.0/R0;
+ R1 = 1.0/R1;
+ Vout = (maxval - minval) * R0 / (R1 + R0) + minval;
+
+ /* and convert it to a destination value */
+ dst = (Vout < minval) ? minval : (Vout > maxval) ? maxval : Vout;
+
+ w[i][n] = dst;
+ }
+ }
+
+ /* calculate maximum outputs for all given networks */
+ j = 0;
+ max = 0.0;
+ for( i = 0; i < networks_no; i++ )
+ {
+ double sum = 0.0;
+
+ /* of n resistors */
+ for( n = 0; n < rescount[i]; n++ )
+ sum += w[i][n]; /* maximum output, ie when each resistance is connected to Vcc */
+
+ max_out[i] = sum;
+ if (max < sum)
+ {
+ max = sum;
+ j = i;
+ }
+ }
+
+
+ if (scaler < 0.0) /* use autoscale ? */
+ /* calculate the output scaler according to the network with the greatest output */
+ scale = ((double)maxval) / max_out[j];
+ else /* use scaler provided on entry */
+ scale = scaler;
+
+ /* calculate scaled output and fill the output table(s)*/
+ for(i = 0; i < networks_no;i++)
+ {
+ for (n = 0; n < rescount[i]; n++)
+ {
+ ws[i][n] = w[i][n]*scale; /* scale the result */
+ (out[i])[n] = ws[i][n]; /* fill the output table */
+ }
+ }
+
+/* debug code */
+#ifdef MAME_DEBUG
+ logerror("compute_resistor_weights(): scaler = %15.10f\n",scale);
+ logerror("min val :%i max val:%i Total number of networks :%i\n", minval, maxval, networks_no );
+
+ for(i = 0; i < networks_no;i++)
+ {
+ double sum = 0.0;
+
+ logerror(" Network no.%i=> resistances: %i", i, rescount[i] );
+ if (r_pu[i] != 0)
+ logerror(", pullup resistor: %i Ohms",r_pu[i]);
+ if (r_pd[i] != 0)
+ logerror(", pulldown resistor: %i Ohms",r_pd[i]);
+ logerror("\n maximum output of this network:%10.5f (scaled to %15.10f)\n", max_out[i], max_out[i]*scale );
+ for (n = 0; n < rescount[i]; n++)
+ {
+ logerror(" res %2i:%9.1f Ohms weight=%10.5f (scaled = %15.10f)\n", n, r[i][n], w[i][n], ws[i][n] );
+ sum += ws[i][n];
+ }
+ logerror(" sum of scaled weights = %15.10f\n", sum );
+ }
+#endif
+/* debug end */
+
+ return (scale);
+
+}
+
+
+double compute_resistor_net_outputs(
+ int minval, int maxval, double scaler,
+ int count_1, const int * resistances_1, double * outputs_1, int pulldown_1, int pullup_1,
+ int count_2, const int * resistances_2, double * outputs_2, int pulldown_2, int pullup_2,
+ int count_3, const int * resistances_3, double * outputs_3, int pulldown_3, int pullup_3 )
+{
+
+ int networks_no;
+
+ int rescount[MAX_NETS]; /* number of resistors in each of the nets */
+ double r[MAX_NETS][MAX_RES_PER_NET]; /* resistances */
+ double *o; /* calulated outputs */
+ double *os; /* calulated, scaled outputss */
+ int r_pd[MAX_NETS]; /* pulldown resistances */
+ int r_pu[MAX_NETS]; /* pullup resistances */
+
+ double max_out[MAX_NETS];
+ double min_out[MAX_NETS];
+ double * out[MAX_NETS];
+
+ int i,j,n;
+ double scale;
+ double min;
+ double max;
+
+ /* parse input parameters */
+
+ o = malloc_or_die( sizeof(double) * (1<<MAX_RES_PER_NET) * MAX_NETS);
+ os = malloc_or_die( sizeof(double) * (1<<MAX_RES_PER_NET) * MAX_NETS);
+
+ networks_no = 0;
+ for (n = 0; n < MAX_NETS; n++)
+ {
+ int count, pd, pu;
+ const int * resistances;
+ double * weights;
+
+ switch(n){
+ case 0:
+ count = count_1;
+ resistances = resistances_1;
+ weights = outputs_1;
+ pd = pulldown_1;
+ pu = pullup_1;
+ break;
+ case 1:
+ count = count_2;
+ resistances = resistances_2;
+ weights = outputs_2;
+ pd = pulldown_2;
+ pu = pullup_2;
+ break;
+ case 2:
+ default:
+ count = count_3;
+ resistances = resistances_3;
+ weights = outputs_3;
+ pd = pulldown_3;
+ pu = pullup_3;
+ break;
+ }
+
+ /* parameters validity check */
+ if (count > MAX_RES_PER_NET)
+ {
+ logerror(" ERROR: res_net.h: compute_resistor_net_outputs(): too many resistors in net #%i. The maximum allowed is %i, the number requested was: %i\n",n, MAX_RES_PER_NET, count);
+ /* quit */
+ free(o);
+ free(os);
+ return (0.0);
+ }
+
+ if (count > 0)
+ {
+ rescount[networks_no] = count;
+ for (i=0; i < count; i++)
+ {
+ r[networks_no][i] = 1.0 * resistances[i];
+ }
+ out[networks_no] = weights;
+ r_pd[networks_no] = pd;
+ r_pu[networks_no] = pu;
+ networks_no++;
+ }
+ }
+
+ if (networks_no<1)
+ {
+ /* error - no networks to anaylse */
+ logerror(" ERROR: res_net.h: compute_resistor_net_outputs(): no input data\n");
+ free(o);
+ free(os);
+ return (0.0);
+ }
+
+ /* calculate outputs for all given networks */
+ for( i = 0; i < networks_no; i++ )
+ {
+ double R0, R1, Vout, dst;
+
+ /* of n resistors, generating 1<<n possible outputs */
+ for(n = 0; n < (1<<rescount[i]); n++)
+ {
+ R0 = ( r_pd[i] == 0 ) ? 1.0/1e12 : 1.0/r_pd[i];
+ R1 = ( r_pu[i] == 0 ) ? 1.0/1e12 : 1.0/r_pu[i];
+
+ for( j = 0; j < rescount[i]; j++ )
+ {
+ if( (n & (1<<j)) == 0 )/* only when this resistance in the network connected to GND */
+ if (r[i][j] != 0.0)
+ R0 += 1.0/r[i][j];
+ }
+
+ /* now determine the voltage */
+ R0 = 1.0/R0;
+ R1 = 1.0/R1;
+ Vout = (maxval - minval) * R0 / (R1 + R0) + minval;
+
+ /* and convert it to a destination value */
+ dst = (Vout < minval) ? minval : (Vout > maxval) ? maxval : Vout;
+
+ o[i*(1<<MAX_RES_PER_NET)+n] = dst;
+ }
+ }
+
+ /* calculate minimum outputs for all given networks */
+ j = 0;
+ min = maxval;
+ max = minval;
+ for( i = 0; i < networks_no; i++ )
+ {
+ double val = 0.0;
+ double max_tmp = minval;
+ double min_tmp = maxval;
+
+ for (n = 0; n < (1<<rescount[i]); n++)
+ {
+ if (min_tmp > o[i*(1<<MAX_RES_PER_NET)+n])
+ min_tmp = o[i*(1<<MAX_RES_PER_NET)+n];
+ if (max_tmp < o[i*(1<<MAX_RES_PER_NET)+n])
+ max_tmp = o[i*(1<<MAX_RES_PER_NET)+n];
+ }
+
+ max_out[i] = max_tmp; /* maximum output */
+ min_out[i] = min_tmp; /* minimum output */
+
+ val = min_out[i]; /* minimum output of this network */
+ if (min > val)
+ {
+ min = val;
+ }
+ val = max_out[i]; /* maximum output of this network */
+ if (max < val)
+ {
+ max = val;
+ }
+ }
+
+
+ if (scaler < 0.0) /* use autoscale ? */
+ /* calculate the output scaler according to the network with the smallest output */
+ scale = ((double)maxval) / (max-min);
+ else /* use scaler provided on entry */
+ scale = scaler;
+
+ /* calculate scaled output and fill the output table(s) */
+ for(i = 0; i < networks_no; i++)
+ {
+ for (n = 0; n < (1<<rescount[i]); n++)
+ {
+ os[i*(1<<MAX_RES_PER_NET)+n] = (o[i*(1<<MAX_RES_PER_NET)+n] - min) * scale; /* scale the result */
+ (out[i])[n] = os[i*(1<<MAX_RES_PER_NET)+n]; /* fill the output table */
+ }
+ }
+
+/* debug code */
+#ifdef MAME_DEBUG
+ logerror("compute_resistor_net_outputs(): scaler = %15.10f\n",scale);
+ logerror("min val :%i max val:%i Total number of networks :%i\n", minval, maxval, networks_no );
+
+ for(i = 0; i < networks_no;i++)
+ {
+ logerror(" Network no.%i=> resistances: %i", i, rescount[i] );
+ if (r_pu[i] != 0)
+ logerror(", pullup resistor: %i Ohms",r_pu[i]);
+ if (r_pd[i] != 0)
+ logerror(", pulldown resistor: %i Ohms",r_pd[i]);
+ logerror("\n maximum output of this network:%10.5f", max_out[i] );
+ logerror("\n minimum output of this network:%10.5f\n", min_out[i] );
+ for (n = 0; n < rescount[i]; n++)
+ {
+ logerror(" res %2i:%9.1f Ohms\n", n, r[i][n]);
+ }
+ for (n = 0; n < (1<<rescount[i]); n++)
+ {
+ logerror(" combination %2i out=%10.5f (scaled = %15.10f)\n", n, o[i*(1<<MAX_RES_PER_NET)+n], os[i*(1<<MAX_RES_PER_NET)+n] );
+ }
+ }
+#endif
+/* debug end */
+
+ free(o);
+ free(os);
+ return (scale);
+
+}
+
+/*****************************************************************************
+
+ New Interface
+
+*****************************************************************************/
+
+
+/* Datasheets give a maximum of 0.4V to 0.5V
+ * However in the circuit simulated here this will only
+ * occur if (rBias + rOutn) = 50 Ohm, rBias exists.
+ * This is highly unlikely. With the resistor values used
+ * in such circuits VOL is likely to be around 50mV.
+ */
+
+#define TTL_VOL (0.05)
+
+
+/* Likely, datasheets give a typical value of 3.4V to 3.6V
+ * for VOH. Modelling the TTL circuit however backs a value
+ * of 4V for typical currents involved in resistor networks.
+ */
+
+#define TTL_VOH (4.0)
+
+int compute_res_net(int inputs, int channel, const res_net_info *di)
+{
+ double rTotal=0.0;
+ double v = 0;
+ int i;
+
+ double vBias = di->rgb[channel].vBias;
+ double vOH = di->vOH;
+ double vOL = di->vOL;
+ double minout = di->rgb[channel].minout;
+ double cut = di->rgb[channel].cut;
+ double vcc = di->vcc;
+ double ttlHRes = 0;
+ double rGnd = di->rgb[channel].rGnd;
+ UINT8 OpenCol = di->OpenCol;
+
+ /* Global options */
+
+ switch (di->options & RES_NET_AMP_MASK)
+ {
+ case RES_NET_AMP_USE_GLOBAL:
+ /* just ignore */
+ break;
+ case RES_NET_AMP_NONE:
+ minout = 0.0;
+ cut = 0.0;
+ break;
+ case RES_NET_AMP_DARLINGTON:
+ minout = 0.9;
+ cut = 0.0;
+ break;
+ case RES_NET_AMP_EMITTER:
+ minout = 0.0;
+ cut = 0.7;
+ break;
+ case RES_NET_AMP_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown amplifier type");
+ }
+
+ switch (di->options & RES_NET_VCC_MASK)
+ {
+ case RES_NET_VCC_5V:
+ vcc = 5.0;
+ break;
+ case RES_NET_VCC_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown vcc type");
+ }
+
+ switch (di->options & RES_NET_VBIAS_MASK)
+ {
+ case RES_NET_VBIAS_USE_GLOBAL:
+ /* just ignore */
+ break;
+ case RES_NET_VBIAS_5V:
+ vBias = 5.0;
+ break;
+ case RES_NET_VBIAS_TTL:
+ vBias = TTL_VOH;
+ break;
+ case RES_NET_VBIAS_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown vcc type");
+ }
+
+ switch (di->options & RES_NET_VIN_MASK)
+ {
+ case RES_NET_VIN_OPEN_COL:
+ OpenCol = 1;
+ vOL = TTL_VOL;
+ break;
+ case RES_NET_VIN_VCC:
+ vOL = 0.0;
+ vOH = vcc;
+ OpenCol = 0;
+ break;
+ case RES_NET_VIN_TTL_OUT:
+ vOL = TTL_VOL;
+ vOH = TTL_VOH;
+ /* rough estimation from 82s129 (7052) datasheet and from various sources
+ * 1.4k / 30
+ */
+ ttlHRes = 50;
+ OpenCol = 0;
+ break;
+ case RES_NET_VIN_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown vin type");
+ }
+
+ /* Per channel options */
+
+ switch (di->rgb[channel].options & RES_NET_AMP_MASK)
+ {
+ case RES_NET_AMP_USE_GLOBAL:
+ /* use global defaults */
+ break;
+ case RES_NET_AMP_NONE:
+ minout = 0.0;
+ cut = 0.0;
+ break;
+ case RES_NET_AMP_DARLINGTON:
+ minout = 0.9;
+ cut = 0.0;
+ break;
+ case RES_NET_AMP_EMITTER:
+ minout = 0.0;
+ cut = 0.7;
+ break;
+ case RES_NET_AMP_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown amplifier type");
+ }
+
+ switch (di->rgb[channel].options & RES_NET_VBIAS_MASK)
+ {
+ case RES_NET_VBIAS_USE_GLOBAL:
+ /* use global defaults */
+ break;
+ case RES_NET_VBIAS_5V:
+ vBias = 5.0;
+ break;
+ case RES_NET_VBIAS_TTL:
+ vBias = TTL_VOH;
+ break;
+ case RES_NET_VBIAS_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown vcc type");
+ }
+
+ /* Input impedances */
+
+ switch (di->options & RES_NET_MONITOR_MASK)
+ {
+ case RES_NET_MONITOR_INVERT:
+ case RES_NET_MONITOR_SANYO_EZV20:
+ /* Nothing */
+ break;
+ case RES_NET_MONITOR_ELECTROHOME_G07:
+ if (rGnd != 0.0)
+ rGnd = rGnd * 5600 / (rGnd + 5600);
+ else
+ rGnd = 5600;
+ break;
+ }
+
+ /* compute here - pass a / low inputs */
+
+ for (i=0; i<di->rgb[channel].num; i++)
+ {
+ int level = ((inputs >> i) & 1);
+ if (di->rgb[channel].R[i] != 0.0 && !level)
+ {
+ if (OpenCol)
+ {
+ rTotal += 1.0 / di->rgb[channel].R[i];
+ v += vOL / di->rgb[channel].R[i];
+ }
+ else
+ {
+ rTotal += 1.0 / di->rgb[channel].R[i];
+ v += vOL / di->rgb[channel].R[i];
+ }
+ }
+ }
+
+ /* Mix in rbias and rgnd */
+ if ( di->rgb[channel].rBias != 0.0 )
+ {
+ rTotal += 1.0 / di->rgb[channel].rBias;
+ v += vBias / di->rgb[channel].rBias;
+ }
+ if (rGnd != 0.0)
+ rTotal += 1.0 / rGnd;
+
+ /* if the resulting voltage after application of all low inputs is
+ * greater than vOH, treat high inputs as open collector/high impedance
+ * There will be now current into/from the TTL gate
+ */
+
+ if ( (di->options & RES_NET_VIN_MASK)==RES_NET_VIN_TTL_OUT)
+ {
+ if (v / rTotal > vOH)
+ OpenCol = 1;
+ }
+
+ /* Second pass - high inputs */
+
+ for (i=0; i<di->rgb[channel].num; i++)
+ {
+ int level = ((inputs >> i) & 1);
+ if (di->rgb[channel].R[i] != 0.0 && level)
+ {
+ if (OpenCol)
+ {
+ rTotal += 0;
+ v += 0;
+ }
+ else
+ {
+ rTotal += 1.0 / (di->rgb[channel].R[i] + ttlHRes);
+ v += vOH / (di->rgb[channel].R[i] + ttlHRes);
+ }
+ }
+ }
+
+ rTotal = 1.0 / rTotal;
+ v *= rTotal;
+ v = MAX(minout, v - cut);
+
+ switch (di->options & RES_NET_MONITOR_MASK)
+ {
+ case RES_NET_MONITOR_INVERT:
+ v = vcc - v;
+ break;
+ case RES_NET_MONITOR_SANYO_EZV20:
+ v = vcc - v;
+ v = MAX(0, v-0.7);
+ v = MIN(v, vcc - 2 * 0.7);
+ break;
+ case RES_NET_MONITOR_ELECTROHOME_G07:
+ /* Nothing */
+ break;
+ }
+
+ return (int) (v *255 / vcc + 0.4);
+}
+
+rgb_t *compute_res_net_all(const UINT8 *prom, const res_net_decode_info *rdi, const res_net_info *di)
+{
+ UINT8 r,g,b;
+ int i,j,k;
+ rgb_t *rgb;
+
+ rgb = malloc_or_die((rdi->end - rdi->start + 1)*sizeof(rgb_t));
+ for (i=rdi->start; i<=rdi->end; i++)
+ {
+ UINT8 t[3] = {0,0,0};
+ int s;
+ for (j=0;j<rdi->numcomp;j++)
+ for (k=0; k<3; k++)
+ {
+ s = rdi->shift[3*j+k];
+ if (s>0)
+ t[k] = t[k] | ( (prom[i+rdi->offset[3*j+k]]>>s) & rdi->mask[3*j+k]);
+ else
+ t[k] = t[k] | ( (prom[i+rdi->offset[3*j+k]]<<(0-s)) & rdi->mask[3*j+k]);
+ }
+ r = compute_res_net(t[0], RES_NET_CHAN_RED, di);
+ g = compute_res_net(t[1], RES_NET_CHAN_GREEN, di);
+ b = compute_res_net(t[2], RES_NET_CHAN_BLUE, di);
+ rgb[i-rdi->start] = MAKE_RGB(r,g,b);
+ }
+ return rgb;
+}
diff --git a/src/emu/video/resnet.h b/src/emu/video/resnet.h
new file mode 100644
index 00000000000..5d508fa1405
--- /dev/null
+++ b/src/emu/video/resnet.h
@@ -0,0 +1,201 @@
+/*****************************************************************************
+
+ resnet.h
+
+ Compute weights for resistors networks.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*****************************************************************************/
+
+#pragma once
+
+#ifndef _RESNET_H_
+#define _RESNET_H_
+
+/**********************************************************************
+ * Rbias
+ * Vbias >-ZZZ-. .-----------------------------------------> Out0
+ * | | Vcc
+ * R0 | | |
+ * In0 >-ZZZ-+----+ Vcc Z
+ * | | | Z
+ * R1 | | / Z
+ * In1 >-ZZZ-+ +----+----ZZZ--| NPN +------------> Out1
+ * : | > <
+ * : | +----+----| PNP
+ * R8 | | Z | \
+ * In8 >-ZZZ-+ | Z | |
+ * | | Z | Gnd
+ * Z | | '-------------------> Out2
+ * Z Rgnd | Gnd
+ * Z | |-----------------------|
+ * | `---| max(vmin,min(sig-vcut)|--------> Out3
+ * Gnd |-----------------------|
+ *
+ *********************************************************************/
+
+/* Amplifier stage per channel but may be specified globally as default */
+
+#define RES_NET_AMP_USE_GLOBAL 0x0000
+#define RES_NET_AMP_NONE 0x0001 //Out0
+#define RES_NET_AMP_DARLINGTON 0x0002 //Out1
+#define RES_NET_AMP_EMITTER 0x0003 //Out2
+#define RES_NET_AMP_CUSTOM 0x0004 //Out3
+#define RES_NET_AMP_MASK 0x0007
+
+/* VCC prebuilds - Global */
+
+#define RES_NET_VCC_5V 0x0000
+#define RES_NET_VCC_CUSTOM 0x0008
+#define RES_NET_VCC_MASK 0x0008
+
+/* VBias prebuils - per channel but may be specified globally as default */
+
+#define RES_NET_VBIAS_USE_GLOBAL 0x0000
+#define RES_NET_VBIAS_5V 0x0010
+#define RES_NET_VBIAS_TTL 0x0020
+#define RES_NET_VBIAS_CUSTOM 0x0030
+#define RES_NET_VBIAS_MASK 0x0030
+
+/* Input Voltage levels - Global */
+
+#define RES_NET_VIN_OPEN_COL 0x0000
+#define RES_NET_VIN_VCC 0x0100
+#define RES_NET_VIN_TTL_OUT 0x0200
+#define RES_NET_VIN_CUSTOM 0x0300
+#define RES_NET_VIN_MASK 0x0300
+
+/* Monitor options */
+
+// Just invert the signal
+#define RES_NET_MONITOR_INVERT 0x1000
+// SANYO_EZV20 / Nintendo with inverter circuit
+#define RES_NET_MONITOR_SANYO_EZV20 0x2000
+// Electrohome G07 Series
+// 5.6k input impedance
+#define RES_NET_MONITOR_ELECTROHOME_G07 0x3000
+
+#define RES_NET_MONITOR_MASK 0x3000
+
+/* General defines */
+
+#define RES_NET_CHAN_RED 0x00
+#define RES_NET_CHAN_GREEN 0x01
+#define RES_NET_CHAN_BLUE 0x02
+
+/* Some aliases */
+
+#define RES_NET_VIN_MB7052 RES_NET_VIN_TTL_OUT
+#define RES_NET_VIN_MB7053 RES_NET_VIN_TTL_OUT
+#define RES_NET_VIN_28S42 RES_NET_VIN_TTL_OUT
+
+/* Structures */
+
+typedef struct _res_net_channel_info res_net_channel_info;
+struct _res_net_channel_info {
+ // per channel options
+ UINT32 options;
+ // Pullup resistor value in Ohms
+ double rBias;
+ // Pulldown resistor value in Ohms
+ double rGnd;
+ // Number of inputs connected to resistors
+ int num;
+ // Resistor values
+ // - Least significant bit first
+ double R[8];
+ // Minimum output voltage
+ // - Applicable if output is routed through a complimentary
+ // - darlington circuit
+ // - typical value ~ 0.9V
+ double minout;
+ // Cutoff output voltage
+ // - Applicable if output is routed through 1:1 transistor amplifier
+ // - Typical value ~ 0.7V
+ double cut;
+ // Voltage at the pullup resistor
+ // - Typical voltage ~5V
+ double vBias;
+};
+
+typedef struct _res_net_info res_net_info;
+struct _res_net_info {
+ // global options
+ UINT32 options;
+ // The three color channels
+ res_net_channel_info rgb[3];
+ // Supply Voltage
+ // - Typical value 5V
+ double vcc;
+ // High Level output voltage
+ // - TTL : 3.40V
+ // - CMOS: 4.95V (@5v vcc)
+ double vOL;
+ // Low Level output voltage
+ // - TTL : 0.35V
+ // - CMOS: 0.05V (@5v vcc)
+ double vOH;
+ // Open Collector flag
+ UINT8 OpenCol;
+};
+
+#define RES_NET_MAX_COMP 3
+
+typedef struct _res_net_decode_info res_net_decode_info;
+struct _res_net_decode_info {
+ int numcomp;
+ int start;
+ int end;
+ UINT16 offset[3 * RES_NET_MAX_COMP];
+ INT16 shift[3 * RES_NET_MAX_COMP];
+ UINT16 mask[3 * RES_NET_MAX_COMP];
+};
+
+/* return a single value for one channel */
+
+int compute_res_net(int inputs, int channel, const res_net_info *di);
+
+/* compute all values */
+
+rgb_t *compute_res_net_all(const UINT8 *prom, const res_net_decode_info *rdi, const res_net_info *di);
+
+
+/* legacy interface */
+
+double compute_resistor_weights(
+ int minval, int maxval, double scaler,
+ int count_1, const int * resistances_1, double * weights_1, int pulldown_1, int pullup_1,
+ int count_2, const int * resistances_2, double * weights_2, int pulldown_2, int pullup_2,
+ int count_3, const int * resistances_3, double * weights_3, int pulldown_3, int pullup_3 );
+
+#define combine_8_weights(tab,w0,w1,w2,w3,w4,w5,w6,w7) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3) + (tab)[4]*(w4) + (tab)[5]*(w5) + (tab)[6]*(w6) + (tab)[7]*(w7)) + 0.5))
+#define combine_7_weights(tab,w0,w1,w2,w3,w4,w5,w6) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3) + (tab)[4]*(w4) + (tab)[5]*(w5) + (tab)[6]*(w6)) + 0.5))
+#define combine_6_weights(tab,w0,w1,w2,w3,w4,w5) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3) + (tab)[4]*(w4) + (tab)[5]*(w5)) + 0.5))
+#define combine_5_weights(tab,w0,w1,w2,w3,w4) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3) + (tab)[4]*(w4)) + 0.5))
+#define combine_4_weights(tab,w0,w1,w2,w3) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3)) + 0.5))
+#define combine_3_weights(tab,w0,w1,w2) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2)) + 0.5))
+#define combine_2_weights(tab,w0,w1) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1)) + 0.5))
+
+
+
+/* this should be moved to one of the core files */
+
+#define MAX_NETS 3
+#define MAX_RES_PER_NET 18
+
+
+
+
+/* for the open collector outputs PROMs */
+
+double compute_resistor_net_outputs(
+ int minval, int maxval, double scaler,
+ int count_1, const int * resistances_1, double * outputs_1, int pulldown_1, int pullup_1,
+ int count_2, const int * resistances_2, double * outputs_2, int pulldown_2, int pullup_2,
+ int count_3, const int * resistances_3, double * outputs_3, int pulldown_3, int pullup_3 );
+
+
+
+#endif /*_RESNET_H_*/
diff --git a/src/emu/video/rgbgen.h b/src/emu/video/rgbgen.h
new file mode 100644
index 00000000000..1a5469fef80
--- /dev/null
+++ b/src/emu/video/rgbgen.h
@@ -0,0 +1,396 @@
+/***************************************************************************
+
+ rgbgen.h
+
+ General RGB utilities.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __RGBGEN__
+#define __RGBGEN__
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* intermediate RGB values are stored in a struct */
+typedef struct { INT16 dummy, r, g, b; } rgbint;
+
+/* intermediate RGB values are stored in a struct */
+typedef struct { INT16 a, r, g, b; } rgbaint;
+
+
+
+/***************************************************************************
+ BASIC CONVERSIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgb_comp_to_rgbint - converts a trio of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgb_comp_to_rgbint(rgbint *rgb, INT16 r, INT16 g, INT16 b)
+{
+ rgb->r = r;
+ rgb->g = g;
+ rgb->b = b;
+}
+
+
+/*-------------------------------------------------
+ rgba_comp_to_rgbint - converts a quad of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgba_comp_to_rgbaint(rgbaint *rgb, INT16 a, INT16 r, INT16 g, INT16 b)
+{
+ rgb->a = a;
+ rgb->r = r;
+ rgb->g = g;
+ rgb->b = b;
+}
+
+
+/*-------------------------------------------------
+ rgb_to_rgbint - converts a packed trio of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgb_to_rgbint(rgbint *rgb, rgb_t color)
+{
+ rgb->r = RGB_RED(color);
+ rgb->g = RGB_GREEN(color);
+ rgb->b = RGB_BLUE(color);
+}
+
+
+/*-------------------------------------------------
+ rgba_to_rgbaint - converts a packed quad of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgba_to_rgbaint(rgbaint *rgb, rgb_t color)
+{
+ rgb->a = RGB_ALPHA(color);
+ rgb->r = RGB_RED(color);
+ rgb->g = RGB_GREEN(color);
+ rgb->b = RGB_BLUE(color);
+}
+
+
+/*-------------------------------------------------
+ rgbint_to_rgb - converts an rgbint back to
+ a packed trio of RGB values
+-------------------------------------------------*/
+
+INLINE rgb_t rgbint_to_rgb(const rgbint *color)
+{
+ return MAKE_RGB(color->r, color->g, color->b);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_to_rgba - converts an rgbint back to
+ a packed quad of RGB values
+-------------------------------------------------*/
+
+INLINE rgb_t rgbaint_to_rgba(const rgbaint *color)
+{
+ return MAKE_ARGB(color->a, color->r, color->g, color->b);
+}
+
+
+/*-------------------------------------------------
+ rgbint_to_rgb_clamp - converts an rgbint back
+ to a packed trio of RGB values, clamping them
+ to bytes first
+-------------------------------------------------*/
+
+INLINE rgb_t rgbint_to_rgb_clamp(const rgbint *color)
+{
+ UINT8 r = (color->r < 0) ? 0 : (color->r > 255) ? 255 : color->r;
+ UINT8 g = (color->g < 0) ? 0 : (color->g > 255) ? 255 : color->g;
+ UINT8 b = (color->b < 0) ? 0 : (color->b > 255) ? 255 : color->b;
+ return MAKE_RGB(r, g, b);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_to_rgba_clamp - converts an rgbint back
+ to a packed quad of RGB values, clamping them
+ to bytes first
+-------------------------------------------------*/
+
+INLINE rgb_t rgbaint_to_rgba_clamp(const rgbaint *color)
+{
+ UINT8 a = (color->a < 0) ? 0 : (color->a > 255) ? 255 : color->a;
+ UINT8 r = (color->r < 0) ? 0 : (color->r > 255) ? 255 : color->r;
+ UINT8 g = (color->g < 0) ? 0 : (color->g > 255) ? 255 : color->g;
+ UINT8 b = (color->b < 0) ? 0 : (color->b > 255) ? 255 : color->b;
+ return MAKE_ARGB(a, r, g, b);
+}
+
+
+
+/***************************************************************************
+ CORE MATH
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgbint_add - add two rgbint values
+-------------------------------------------------*/
+
+INLINE void rgbint_add(rgbint *color1, const rgbint *color2)
+{
+ color1->r += color2->r;
+ color1->g += color2->g;
+ color1->b += color2->b;
+}
+
+
+/*-------------------------------------------------
+ rgbaint_add - add two rgbaint values
+-------------------------------------------------*/
+
+INLINE void rgbaint_add(rgbaint *color1, const rgbaint *color2)
+{
+ color1->a += color2->a;
+ color1->r += color2->r;
+ color1->g += color2->g;
+ color1->b += color2->b;
+}
+
+
+/*-------------------------------------------------
+ rgbint_sub - subtract two rgbint values
+-------------------------------------------------*/
+
+INLINE void rgbint_sub(rgbint *color1, const rgbint *color2)
+{
+ color1->r -= color2->r;
+ color1->g -= color2->g;
+ color1->b -= color2->b;
+}
+
+
+/*-------------------------------------------------
+ rgbaint_sub - subtract two rgbaint values
+-------------------------------------------------*/
+
+INLINE void rgbaint_sub(rgbaint *color1, const rgbaint *color2)
+{
+ color1->a -= color2->a;
+ color1->r -= color2->r;
+ color1->g -= color2->g;
+ color1->b -= color2->b;
+}
+
+
+/*-------------------------------------------------
+ rgbint_subr - reverse subtract two rgbint
+ values
+-------------------------------------------------*/
+
+INLINE void rgbint_subr(rgbint *color1, const rgbint *color2)
+{
+ color1->r = color2->r - color1->r;
+ color1->g = color2->g - color1->g;
+ color1->b = color2->b - color1->b;
+}
+
+
+/*-------------------------------------------------
+ rgbaint_subr - reverse subtract two rgbaint
+ values
+-------------------------------------------------*/
+
+INLINE void rgbaint_subr(rgbaint *color1, const rgbaint *color2)
+{
+ color1->a = color2->a - color1->a;
+ color1->r = color2->r - color1->r;
+ color1->g = color2->g - color1->g;
+ color1->b = color2->b - color1->b;
+}
+
+
+
+/***************************************************************************
+ HIGHER LEVEL OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgbint_blend - blend two colors by the given
+ scale factor
+-------------------------------------------------*/
+
+INLINE void rgbint_blend(rgbint *color1, const rgbint *color2, UINT8 color1scale)
+{
+ int scale1 = (int)color1scale + 1;
+ int scale2 = 256 - scale1;
+
+ color1->r = (color1->r * scale1 + color2->r * scale2) >> 8;
+ color1->g = (color1->g * scale1 + color2->g * scale2) >> 8;
+ color1->b = (color1->b * scale1 + color2->b * scale2) >> 8;
+}
+
+
+/*-------------------------------------------------
+ rgbaint_blend - blend two colors by the given
+ scale factor
+-------------------------------------------------*/
+
+INLINE void rgbaint_blend(rgbaint *color1, const rgbaint *color2, UINT8 color1scale)
+{
+ int scale1 = (int)color1scale + 1;
+ int scale2 = 256 - scale1;
+
+ color1->a = (color1->a * scale1 + color2->a * scale2) >> 8;
+ color1->r = (color1->r * scale1 + color2->r * scale2) >> 8;
+ color1->g = (color1->g * scale1 + color2->g * scale2) >> 8;
+ color1->b = (color1->b * scale1 + color2->b * scale2) >> 8;
+}
+
+
+/*-------------------------------------------------
+ rgbint_scale_and_clamp - scale the given
+ color by an 8.8 scale factor and clamp to
+ byte values
+-------------------------------------------------*/
+
+INLINE void rgbint_scale_and_clamp(rgbint *color, INT16 colorscale)
+{
+ color->r = (color->r * colorscale) >> 8;
+ if ((UINT16)color->r > 255) { color->r = (color->r < 0) ? 0 : 255; }
+ color->g = (color->g * colorscale) >> 8;
+ if ((UINT16)color->g > 255) { color->g = (color->g < 0) ? 0 : 255; }
+ color->b = (color->b * colorscale) >> 8;
+ if ((UINT16)color->b > 255) { color->b = (color->b < 0) ? 0 : 255; }
+}
+
+
+/*-------------------------------------------------
+ rgbaint_scale_and_clamp - scale the given
+ color by an 8.8 scale factor and clamp to
+ byte values
+-------------------------------------------------*/
+
+INLINE void rgbaint_scale_and_clamp(rgbaint *color, INT16 colorscale)
+{
+ color->a = (color->a * colorscale) >> 8;
+ if ((UINT16)color->a > 255) { color->a = (color->a < 0) ? 0 : 255; }
+ color->r = (color->r * colorscale) >> 8;
+ if ((UINT16)color->r > 255) { color->r = (color->r < 0) ? 0 : 255; }
+ color->g = (color->g * colorscale) >> 8;
+ if ((UINT16)color->g > 255) { color->g = (color->g < 0) ? 0 : 255; }
+ color->b = (color->b * colorscale) >> 8;
+ if ((UINT16)color->b > 255) { color->b = (color->b < 0) ? 0 : 255; }
+}
+
+
+/*-------------------------------------------------
+ rgb_bilinear_filter - bilinear filter between
+ four pixel values; this code is derived from
+ code provided by Michael Herf
+-------------------------------------------------*/
+
+INLINE rgb_t rgb_bilinear_filter(rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ UINT32 ag0, ag1, rb0, rb1;
+
+ rb0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
+ rb1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
+ ag0 = (rgb00 & 0x0000ff00) + ((((rgb01 & 0x0000ff00) - (rgb00 & 0x0000ff00)) * u) >> 8);
+ ag1 = (rgb10 & 0x0000ff00) + ((((rgb11 & 0x0000ff00) - (rgb10 & 0x0000ff00)) * u) >> 8);
+
+ rb0 = (rb0 & 0x00ff00ff) + ((((rb1 & 0x00ff00ff) - (rb0 & 0x00ff00ff)) * v) >> 8);
+ ag0 = (ag0 & 0x0000ff00) + ((((ag1 & 0x0000ff00) - (ag0 & 0x0000ff00)) * v) >> 8);
+
+ return (ag0 & 0x0000ff00) | (rb0 & 0x00ff00ff);
+}
+
+
+/*-------------------------------------------------
+ rgba_bilinear_filter - bilinear filter between
+ four pixel values; this code is derived from
+ code provided by Michael Herf
+-------------------------------------------------*/
+
+INLINE rgb_t rgba_bilinear_filter(rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ UINT32 ag0, ag1, rb0, rb1;
+
+ rb0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
+ rb1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
+ rgb00 >>= 8;
+ rgb01 >>= 8;
+ rgb10 >>= 8;
+ rgb11 >>= 8;
+ ag0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
+ ag1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
+
+ rb0 = (rb0 & 0x00ff00ff) + ((((rb1 & 0x00ff00ff) - (rb0 & 0x00ff00ff)) * v) >> 8);
+ ag0 = (ag0 & 0x00ff00ff) + ((((ag1 & 0x00ff00ff) - (ag0 & 0x00ff00ff)) * v) >> 8);
+
+ return ((ag0 << 8) & 0xff00ff00) | (rb0 & 0x00ff00ff);
+}
+
+
+/*-------------------------------------------------
+ rgbint_bilinear_filter - bilinear filter between
+ four pixel values; this code is derived from
+ code provided by Michael Herf
+-------------------------------------------------*/
+
+INLINE void rgbint_bilinear_filter(rgbint *color, rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ UINT32 ag0, ag1, rb0, rb1;
+
+ rb0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
+ rb1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
+ ag0 = (rgb00 & 0x0000ff00) + ((((rgb01 & 0x0000ff00) - (rgb00 & 0x0000ff00)) * u) >> 8);
+ ag1 = (rgb10 & 0x0000ff00) + ((((rgb11 & 0x0000ff00) - (rgb10 & 0x0000ff00)) * u) >> 8);
+
+ rb0 = (rb0 & 0x00ff00ff) + ((((rb1 & 0x00ff00ff) - (rb0 & 0x00ff00ff)) * v) >> 8);
+ ag0 = (ag0 & 0x0000ff00) + ((((ag1 & 0x0000ff00) - (ag0 & 0x0000ff00)) * v) >> 8);
+
+ color->r = rb0 >> 16;
+ color->g = ag0 >> 8;
+ color->b = rb0;
+}
+
+
+/*-------------------------------------------------
+ rgbaint_bilinear_filter - bilinear filter between
+ four pixel values; this code is derived from
+ code provided by Michael Herf
+-------------------------------------------------*/
+
+INLINE void rgbaint_bilinear_filter(rgbaint *color, rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ UINT32 ag0, ag1, rb0, rb1;
+
+ rb0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
+ rb1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
+ rgb00 >>= 8;
+ rgb01 >>= 8;
+ rgb10 >>= 8;
+ rgb11 >>= 8;
+ ag0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
+ ag1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
+
+ rb0 = (rb0 & 0x00ff00ff) + ((((rb1 & 0x00ff00ff) - (rb0 & 0x00ff00ff)) * v) >> 8);
+ ag0 = (ag0 & 0x00ff00ff) + ((((ag1 & 0x00ff00ff) - (ag0 & 0x00ff00ff)) * v) >> 8);
+
+ color->a = ag0 >> 16;
+ color->r = rb0 >> 16;
+ color->g = ag0;
+ color->b = rb0;
+}
+
+
+#endif /* __RGBUTIL__ */
diff --git a/src/emu/video/rgbsse.h b/src/emu/video/rgbsse.h
new file mode 100644
index 00000000000..a4e55619ce1
--- /dev/null
+++ b/src/emu/video/rgbsse.h
@@ -0,0 +1,485 @@
+/***************************************************************************
+
+ rgbgen.h
+
+ SSE optimized RGB utilities.
+
+ WARNING: This code assumes SSE2 or greater capability.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __RGBSSE__
+#define __RGBSSE__
+
+#include <emmintrin.h>
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* intermediate RGB values are stored in an __m128i */
+typedef __m128i rgbint;
+
+/* intermediate RGB values are stored in an __m128i */
+typedef __m128i rgbaint;
+
+
+
+/***************************************************************************
+ BASIC CONVERSIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgb_comp_to_rgbint - converts a trio of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgb_comp_to_rgbint(rgbint *rgb, INT16 r, INT16 g, INT16 b)
+{
+ *rgb = _mm_set_epi16(0, 0, 0, 0, 0, r, g, b);
+}
+
+
+/*-------------------------------------------------
+ rgba_comp_to_rgbint - converts a quad of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgba_comp_to_rgbaint(rgbaint *rgb, INT16 a, INT16 r, INT16 g, INT16 b)
+{
+ *rgb = _mm_set_epi16(0, 0, 0, 0, a, r, g, b);
+}
+
+
+/*-------------------------------------------------
+ rgb_to_rgbint - converts a packed trio of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgb_to_rgbint(rgbint *rgb, rgb_t color)
+{
+ *rgb = _mm_unpacklo_epi8(_mm_cvtsi32_si128(color), _mm_setzero_si128());
+}
+
+
+/*-------------------------------------------------
+ rgba_to_rgbaint - converts a packed quad of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgba_to_rgbaint(rgbaint *rgb, rgb_t color)
+{
+ *rgb = _mm_unpacklo_epi8(_mm_cvtsi32_si128(color), _mm_setzero_si128());
+}
+
+
+/*-------------------------------------------------
+ rgbint_to_rgb - converts an rgbint back to
+ a packed trio of RGB values
+-------------------------------------------------*/
+
+INLINE rgb_t rgbint_to_rgb(const rgbint *color)
+{
+ return _mm_cvtsi128_si32(_mm_packus_epi16(*color, *color));
+}
+
+
+/*-------------------------------------------------
+ rgbaint_to_rgba - converts an rgbint back to
+ a packed quad of RGB values
+-------------------------------------------------*/
+
+INLINE rgb_t rgbaint_to_rgba(const rgbaint *color)
+{
+ return _mm_cvtsi128_si32(_mm_packus_epi16(*color, *color));
+}
+
+
+/*-------------------------------------------------
+ rgbint_to_rgb_clamp - converts an rgbint back
+ to a packed trio of RGB values, clamping them
+ to bytes first
+-------------------------------------------------*/
+
+INLINE rgb_t rgbint_to_rgb_clamp(const rgbint *color)
+{
+ return _mm_cvtsi128_si32(_mm_packus_epi16(*color, *color));
+}
+
+
+/*-------------------------------------------------
+ rgbaint_to_rgba_clamp - converts an rgbint back
+ to a packed quad of RGB values, clamping them
+ to bytes first
+-------------------------------------------------*/
+
+INLINE rgb_t rgbaint_to_rgba_clamp(const rgbaint *color)
+{
+ return _mm_cvtsi128_si32(_mm_packus_epi16(*color, *color));
+}
+
+
+
+/***************************************************************************
+ CORE MATH
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgbint_add - add two rgbint values
+-------------------------------------------------*/
+
+INLINE void rgbint_add(rgbint *color1, const rgbint *color2)
+{
+ *color1 = _mm_add_epi16(*color1, *color2);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_add - add two rgbaint values
+-------------------------------------------------*/
+
+INLINE void rgbaint_add(rgbaint *color1, const rgbaint *color2)
+{
+ *color1 = _mm_add_epi16(*color1, *color2);
+}
+
+
+/*-------------------------------------------------
+ rgbint_sub - subtract two rgbint values
+-------------------------------------------------*/
+
+INLINE void rgbint_sub(rgbint *color1, const rgbint *color2)
+{
+ *color1 = _mm_sub_epi16(*color1, *color2);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_sub - subtract two rgbaint values
+-------------------------------------------------*/
+
+INLINE void rgbaint_sub(rgbaint *color1, const rgbaint *color2)
+{
+ *color1 = _mm_sub_epi16(*color1, *color2);
+}
+
+
+/*-------------------------------------------------
+ rgbint_subr - reverse subtract two rgbint
+ values
+-------------------------------------------------*/
+
+INLINE void rgbint_subr(rgbint *color1, const rgbint *color2)
+{
+ __m128i temp = *color1;
+ *color1 = *color2;
+ *color1 = _mm_sub_epi16(*color1, temp);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_subr - reverse subtract two rgbaint
+ values
+-------------------------------------------------*/
+
+INLINE void rgbaint_subr(rgbaint *color1, const rgbaint *color2)
+{
+ __m128i temp = *color1;
+ *color1 = *color2;
+ *color1 = _mm_sub_epi16(*color1, temp);
+}
+
+
+
+/***************************************************************************
+ TABLES
+***************************************************************************/
+
+static const struct
+{
+ __m128 dummy_for_alignment;
+ INT16 zero[8];
+ INT16 maxbyte[8];
+ INT16 scale_table[256][8];
+} rgbsse_statics =
+{
+ { 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 255, 255, 255, 255, 255, 255, 255, 255 },
+ {
+ { 1, 256, 1, 256, 1, 256, 1, 256 }, { 2, 255, 2, 255, 2, 255, 2, 255 },
+ { 3, 254, 3, 254, 3, 254, 3, 254 }, { 4, 253, 4, 253, 4, 253, 4, 253 },
+ { 5, 252, 5, 252, 5, 252, 5, 252 }, { 6, 251, 6, 251, 6, 251, 6, 251 },
+ { 7, 250, 7, 250, 7, 250, 7, 250 }, { 8, 249, 8, 249, 8, 249, 8, 249 },
+ { 9, 248, 9, 248, 9, 248, 9, 248 }, { 10, 247, 10, 247, 10, 247, 10, 247 },
+ { 11, 246, 11, 246, 11, 246, 11, 246 }, { 12, 245, 12, 245, 12, 245, 12, 245 },
+ { 13, 244, 13, 244, 13, 244, 13, 244 }, { 14, 243, 14, 243, 14, 243, 14, 243 },
+ { 15, 242, 15, 242, 15, 242, 15, 242 }, { 16, 241, 16, 241, 16, 241, 16, 241 },
+ { 17, 240, 17, 240, 17, 240, 17, 240 }, { 18, 239, 18, 239, 18, 239, 18, 239 },
+ { 19, 238, 19, 238, 19, 238, 19, 238 }, { 20, 237, 20, 237, 20, 237, 20, 237 },
+ { 21, 236, 21, 236, 21, 236, 21, 236 }, { 22, 235, 22, 235, 22, 235, 22, 235 },
+ { 23, 234, 23, 234, 23, 234, 23, 234 }, { 24, 233, 24, 233, 24, 233, 24, 233 },
+ { 25, 232, 25, 232, 25, 232, 25, 232 }, { 26, 231, 26, 231, 26, 231, 26, 231 },
+ { 27, 230, 27, 230, 27, 230, 27, 230 }, { 28, 229, 28, 229, 28, 229, 28, 229 },
+ { 29, 228, 29, 228, 29, 228, 29, 228 }, { 30, 227, 30, 227, 30, 227, 30, 227 },
+ { 31, 226, 31, 226, 31, 226, 31, 226 }, { 32, 225, 32, 225, 32, 225, 32, 225 },
+ { 33, 224, 33, 224, 33, 224, 33, 224 }, { 34, 223, 34, 223, 34, 223, 34, 223 },
+ { 35, 222, 35, 222, 35, 222, 35, 222 }, { 36, 221, 36, 221, 36, 221, 36, 221 },
+ { 37, 220, 37, 220, 37, 220, 37, 220 }, { 38, 219, 38, 219, 38, 219, 38, 219 },
+ { 39, 218, 39, 218, 39, 218, 39, 218 }, { 40, 217, 40, 217, 40, 217, 40, 217 },
+ { 41, 216, 41, 216, 41, 216, 41, 216 }, { 42, 215, 42, 215, 42, 215, 42, 215 },
+ { 43, 214, 43, 214, 43, 214, 43, 214 }, { 44, 213, 44, 213, 44, 213, 44, 213 },
+ { 45, 212, 45, 212, 45, 212, 45, 212 }, { 46, 211, 46, 211, 46, 211, 46, 211 },
+ { 47, 210, 47, 210, 47, 210, 47, 210 }, { 48, 209, 48, 209, 48, 209, 48, 209 },
+ { 49, 208, 49, 208, 49, 208, 49, 208 }, { 50, 207, 50, 207, 50, 207, 50, 207 },
+ { 51, 206, 51, 206, 51, 206, 51, 206 }, { 52, 205, 52, 205, 52, 205, 52, 205 },
+ { 53, 204, 53, 204, 53, 204, 53, 204 }, { 54, 203, 54, 203, 54, 203, 54, 203 },
+ { 55, 202, 55, 202, 55, 202, 55, 202 }, { 56, 201, 56, 201, 56, 201, 56, 201 },
+ { 57, 200, 57, 200, 57, 200, 57, 200 }, { 58, 199, 58, 199, 58, 199, 58, 199 },
+ { 59, 198, 59, 198, 59, 198, 59, 198 }, { 60, 197, 60, 197, 60, 197, 60, 197 },
+ { 61, 196, 61, 196, 61, 196, 61, 196 }, { 62, 195, 62, 195, 62, 195, 62, 195 },
+ { 63, 194, 63, 194, 63, 194, 63, 194 }, { 64, 193, 64, 193, 64, 193, 64, 193 },
+ { 65, 192, 65, 192, 65, 192, 65, 192 }, { 66, 191, 66, 191, 66, 191, 66, 191 },
+ { 67, 190, 67, 190, 67, 190, 67, 190 }, { 68, 189, 68, 189, 68, 189, 68, 189 },
+ { 69, 188, 69, 188, 69, 188, 69, 188 }, { 70, 187, 70, 187, 70, 187, 70, 187 },
+ { 71, 186, 71, 186, 71, 186, 71, 186 }, { 72, 185, 72, 185, 72, 185, 72, 185 },
+ { 73, 184, 73, 184, 73, 184, 73, 184 }, { 74, 183, 74, 183, 74, 183, 74, 183 },
+ { 75, 182, 75, 182, 75, 182, 75, 182 }, { 76, 181, 76, 181, 76, 181, 76, 181 },
+ { 77, 180, 77, 180, 77, 180, 77, 180 }, { 78, 179, 78, 179, 78, 179, 78, 179 },
+ { 79, 178, 79, 178, 79, 178, 79, 178 }, { 80, 177, 80, 177, 80, 177, 80, 177 },
+ { 81, 176, 81, 176, 81, 176, 81, 176 }, { 82, 175, 82, 175, 82, 175, 82, 175 },
+ { 83, 174, 83, 174, 83, 174, 83, 174 }, { 84, 173, 84, 173, 84, 173, 84, 173 },
+ { 85, 172, 85, 172, 85, 172, 85, 172 }, { 86, 171, 86, 171, 86, 171, 86, 171 },
+ { 87, 170, 87, 170, 87, 170, 87, 170 }, { 88, 169, 88, 169, 88, 169, 88, 169 },
+ { 89, 168, 89, 168, 89, 168, 89, 168 }, { 90, 167, 90, 167, 90, 167, 90, 167 },
+ { 91, 166, 91, 166, 91, 166, 91, 166 }, { 92, 165, 92, 165, 92, 165, 92, 165 },
+ { 93, 164, 93, 164, 93, 164, 93, 164 }, { 94, 163, 94, 163, 94, 163, 94, 163 },
+ { 95, 162, 95, 162, 95, 162, 95, 162 }, { 96, 161, 96, 161, 96, 161, 96, 161 },
+ { 97, 160, 97, 160, 97, 160, 97, 160 }, { 98, 159, 98, 159, 98, 159, 98, 159 },
+ { 99, 158, 99, 158, 99, 158, 99, 158 }, { 100, 157, 100, 157, 100, 157, 100, 157 },
+ { 101, 156, 101, 156, 101, 156, 101, 156 }, { 102, 155, 102, 155, 102, 155, 102, 155 },
+ { 103, 154, 103, 154, 103, 154, 103, 154 }, { 104, 153, 104, 153, 104, 153, 104, 153 },
+ { 105, 152, 105, 152, 105, 152, 105, 152 }, { 106, 151, 106, 151, 106, 151, 106, 151 },
+ { 107, 150, 107, 150, 107, 150, 107, 150 }, { 108, 149, 108, 149, 108, 149, 108, 149 },
+ { 109, 148, 109, 148, 109, 148, 109, 148 }, { 110, 147, 110, 147, 110, 147, 110, 147 },
+ { 111, 146, 111, 146, 111, 146, 111, 146 }, { 112, 145, 112, 145, 112, 145, 112, 145 },
+ { 113, 144, 113, 144, 113, 144, 113, 144 }, { 114, 143, 114, 143, 114, 143, 114, 143 },
+ { 115, 142, 115, 142, 115, 142, 115, 142 }, { 116, 141, 116, 141, 116, 141, 116, 141 },
+ { 117, 140, 117, 140, 117, 140, 117, 140 }, { 118, 139, 118, 139, 118, 139, 118, 139 },
+ { 119, 138, 119, 138, 119, 138, 119, 138 }, { 120, 137, 120, 137, 120, 137, 120, 137 },
+ { 121, 136, 121, 136, 121, 136, 121, 136 }, { 122, 135, 122, 135, 122, 135, 122, 135 },
+ { 123, 134, 123, 134, 123, 134, 123, 134 }, { 124, 133, 124, 133, 124, 133, 124, 133 },
+ { 125, 132, 125, 132, 125, 132, 125, 132 }, { 126, 131, 126, 131, 126, 131, 126, 131 },
+ { 127, 130, 127, 130, 127, 130, 127, 130 }, { 128, 129, 128, 129, 128, 129, 128, 129 },
+ { 129, 128, 129, 128, 129, 128, 129, 128 }, { 130, 127, 130, 127, 130, 127, 130, 127 },
+ { 131, 126, 131, 126, 131, 126, 131, 126 }, { 132, 125, 132, 125, 132, 125, 132, 125 },
+ { 133, 124, 133, 124, 133, 124, 133, 124 }, { 134, 123, 134, 123, 134, 123, 134, 123 },
+ { 135, 122, 135, 122, 135, 122, 135, 122 }, { 136, 121, 136, 121, 136, 121, 136, 121 },
+ { 137, 120, 137, 120, 137, 120, 137, 120 }, { 138, 119, 138, 119, 138, 119, 138, 119 },
+ { 139, 118, 139, 118, 139, 118, 139, 118 }, { 140, 117, 140, 117, 140, 117, 140, 117 },
+ { 141, 116, 141, 116, 141, 116, 141, 116 }, { 142, 115, 142, 115, 142, 115, 142, 115 },
+ { 143, 114, 143, 114, 143, 114, 143, 114 }, { 144, 113, 144, 113, 144, 113, 144, 113 },
+ { 145, 112, 145, 112, 145, 112, 145, 112 }, { 146, 111, 146, 111, 146, 111, 146, 111 },
+ { 147, 110, 147, 110, 147, 110, 147, 110 }, { 148, 109, 148, 109, 148, 109, 148, 109 },
+ { 149, 108, 149, 108, 149, 108, 149, 108 }, { 150, 107, 150, 107, 150, 107, 150, 107 },
+ { 151, 106, 151, 106, 151, 106, 151, 106 }, { 152, 105, 152, 105, 152, 105, 152, 105 },
+ { 153, 104, 153, 104, 153, 104, 153, 104 }, { 154, 103, 154, 103, 154, 103, 154, 103 },
+ { 155, 102, 155, 102, 155, 102, 155, 102 }, { 156, 101, 156, 101, 156, 101, 156, 101 },
+ { 157, 100, 157, 100, 157, 100, 157, 100 }, { 158, 99, 158, 99, 158, 99, 158, 99 },
+ { 159, 98, 159, 98, 159, 98, 159, 98 }, { 160, 97, 160, 97, 160, 97, 160, 97 },
+ { 161, 96, 161, 96, 161, 96, 161, 96 }, { 162, 95, 162, 95, 162, 95, 162, 95 },
+ { 163, 94, 163, 94, 163, 94, 163, 94 }, { 164, 93, 164, 93, 164, 93, 164, 93 },
+ { 165, 92, 165, 92, 165, 92, 165, 92 }, { 166, 91, 166, 91, 166, 91, 166, 91 },
+ { 167, 90, 167, 90, 167, 90, 167, 90 }, { 168, 89, 168, 89, 168, 89, 168, 89 },
+ { 169, 88, 169, 88, 169, 88, 169, 88 }, { 170, 87, 170, 87, 170, 87, 170, 87 },
+ { 171, 86, 171, 86, 171, 86, 171, 86 }, { 172, 85, 172, 85, 172, 85, 172, 85 },
+ { 173, 84, 173, 84, 173, 84, 173, 84 }, { 174, 83, 174, 83, 174, 83, 174, 83 },
+ { 175, 82, 175, 82, 175, 82, 175, 82 }, { 176, 81, 176, 81, 176, 81, 176, 81 },
+ { 177, 80, 177, 80, 177, 80, 177, 80 }, { 178, 79, 178, 79, 178, 79, 178, 79 },
+ { 179, 78, 179, 78, 179, 78, 179, 78 }, { 180, 77, 180, 77, 180, 77, 180, 77 },
+ { 181, 76, 181, 76, 181, 76, 181, 76 }, { 182, 75, 182, 75, 182, 75, 182, 75 },
+ { 183, 74, 183, 74, 183, 74, 183, 74 }, { 184, 73, 184, 73, 184, 73, 184, 73 },
+ { 185, 72, 185, 72, 185, 72, 185, 72 }, { 186, 71, 186, 71, 186, 71, 186, 71 },
+ { 187, 70, 187, 70, 187, 70, 187, 70 }, { 188, 69, 188, 69, 188, 69, 188, 69 },
+ { 189, 68, 189, 68, 189, 68, 189, 68 }, { 190, 67, 190, 67, 190, 67, 190, 67 },
+ { 191, 66, 191, 66, 191, 66, 191, 66 }, { 192, 65, 192, 65, 192, 65, 192, 65 },
+ { 193, 64, 193, 64, 193, 64, 193, 64 }, { 194, 63, 194, 63, 194, 63, 194, 63 },
+ { 195, 62, 195, 62, 195, 62, 195, 62 }, { 196, 61, 196, 61, 196, 61, 196, 61 },
+ { 197, 60, 197, 60, 197, 60, 197, 60 }, { 198, 59, 198, 59, 198, 59, 198, 59 },
+ { 199, 58, 199, 58, 199, 58, 199, 58 }, { 200, 57, 200, 57, 200, 57, 200, 57 },
+ { 201, 56, 201, 56, 201, 56, 201, 56 }, { 202, 55, 202, 55, 202, 55, 202, 55 },
+ { 203, 54, 203, 54, 203, 54, 203, 54 }, { 204, 53, 204, 53, 204, 53, 204, 53 },
+ { 205, 52, 205, 52, 205, 52, 205, 52 }, { 206, 51, 206, 51, 206, 51, 206, 51 },
+ { 207, 50, 207, 50, 207, 50, 207, 50 }, { 208, 49, 208, 49, 208, 49, 208, 49 },
+ { 209, 48, 209, 48, 209, 48, 209, 48 }, { 210, 47, 210, 47, 210, 47, 210, 47 },
+ { 211, 46, 211, 46, 211, 46, 211, 46 }, { 212, 45, 212, 45, 212, 45, 212, 45 },
+ { 213, 44, 213, 44, 213, 44, 213, 44 }, { 214, 43, 214, 43, 214, 43, 214, 43 },
+ { 215, 42, 215, 42, 215, 42, 215, 42 }, { 216, 41, 216, 41, 216, 41, 216, 41 },
+ { 217, 40, 217, 40, 217, 40, 217, 40 }, { 218, 39, 218, 39, 218, 39, 218, 39 },
+ { 219, 38, 219, 38, 219, 38, 219, 38 }, { 220, 37, 220, 37, 220, 37, 220, 37 },
+ { 221, 36, 221, 36, 221, 36, 221, 36 }, { 222, 35, 222, 35, 222, 35, 222, 35 },
+ { 223, 34, 223, 34, 223, 34, 223, 34 }, { 224, 33, 224, 33, 224, 33, 224, 33 },
+ { 225, 32, 225, 32, 225, 32, 225, 32 }, { 226, 31, 226, 31, 226, 31, 226, 31 },
+ { 227, 30, 227, 30, 227, 30, 227, 30 }, { 228, 29, 228, 29, 228, 29, 228, 29 },
+ { 229, 28, 229, 28, 229, 28, 229, 28 }, { 230, 27, 230, 27, 230, 27, 230, 27 },
+ { 231, 26, 231, 26, 231, 26, 231, 26 }, { 232, 25, 232, 25, 232, 25, 232, 25 },
+ { 233, 24, 233, 24, 233, 24, 233, 24 }, { 234, 23, 234, 23, 234, 23, 234, 23 },
+ { 235, 22, 235, 22, 235, 22, 235, 22 }, { 236, 21, 236, 21, 236, 21, 236, 21 },
+ { 237, 20, 237, 20, 237, 20, 237, 20 }, { 238, 19, 238, 19, 238, 19, 238, 19 },
+ { 239, 18, 239, 18, 239, 18, 239, 18 }, { 240, 17, 240, 17, 240, 17, 240, 17 },
+ { 241, 16, 241, 16, 241, 16, 241, 16 }, { 242, 15, 242, 15, 242, 15, 242, 15 },
+ { 243, 14, 243, 14, 243, 14, 243, 14 }, { 244, 13, 244, 13, 244, 13, 244, 13 },
+ { 245, 12, 245, 12, 245, 12, 245, 12 }, { 246, 11, 246, 11, 246, 11, 246, 11 },
+ { 247, 10, 247, 10, 247, 10, 247, 10 }, { 248, 9, 248, 9, 248, 9, 248, 9 },
+ { 249, 8, 249, 8, 249, 8, 249, 8 }, { 250, 7, 250, 7, 250, 7, 250, 7 },
+ { 251, 6, 251, 6, 251, 6, 251, 6 }, { 252, 5, 252, 5, 252, 5, 252, 5 },
+ { 253, 4, 253, 4, 253, 4, 253, 4 }, { 254, 3, 254, 3, 254, 3, 254, 3 },
+ { 255, 2, 255, 2, 255, 2, 255, 2 }, { 256, 1, 256, 1, 256, 1, 256, 1 }
+ }
+};
+
+
+
+/***************************************************************************
+ HIGHER LEVEL OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgbint_blend - blend two colors by the given
+ scale factor
+-------------------------------------------------*/
+
+INLINE void rgbint_blend(rgbint *color1, const rgbint *color2, UINT8 color1scale)
+{
+ *color1 = _mm_unpacklo_epi16(*color1, *color2);
+ *color1 = _mm_madd_epi16(*color1, *(__m128i *)&rgbsse_statics.scale_table[color1scale][0]);
+ *color1 = _mm_srli_epi32(*color1, 8);
+ *color1 = _mm_packs_epi32(*color1, *color1);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_blend - blend two colors by the given
+ scale factor
+-------------------------------------------------*/
+
+INLINE void rgbaint_blend(rgbaint *color1, const rgbaint *color2, UINT8 color1scale)
+{
+ rgbint_blend(color1, color2, color1scale);
+}
+
+
+/*-------------------------------------------------
+ rgbint_scale_and_clamp - scale the given
+ color by an 8.8 scale factor and clamp to
+ byte values
+-------------------------------------------------*/
+
+INLINE void rgbint_scale_and_clamp(rgbint *color, INT16 colorscale)
+{
+ __m128i mscale = _mm_set1_epi16(colorscale);
+ *color = _mm_unpacklo_epi16(*color, _mm_setzero_si128());
+ *color = _mm_madd_epi16(*color, mscale);
+ *color = _mm_srli_epi32(*color, 8);
+ *color = _mm_packs_epi32(*color, *color);
+ *color = _mm_min_epi16(*color, *(__m128i *)&rgbsse_statics.maxbyte);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_scale_and_clamp - scale the given
+ color by an 8.8 scale factor and clamp to
+ byte values
+-------------------------------------------------*/
+
+INLINE void rgbaint_scale_and_clamp(rgbaint *color, INT16 colorscale)
+{
+ rgbint_scale_and_clamp(color, colorscale);
+}
+
+
+/*-------------------------------------------------
+ rgb_bilinear_filter - bilinear filter between
+ four pixel values
+-------------------------------------------------*/
+
+INLINE rgb_t rgb_bilinear_filter(rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ __m128i color00 = _mm_cvtsi32_si128(rgb00);
+ __m128i color01 = _mm_cvtsi32_si128(rgb01);
+ __m128i color10 = _mm_cvtsi32_si128(rgb10);
+ __m128i color11 = _mm_cvtsi32_si128(rgb11);
+
+ /* interleave color01 and color00 at the byte level */
+ color01 = _mm_unpacklo_epi8(color01, color00);
+ color11 = _mm_unpacklo_epi8(color11, color10);
+ color01 = _mm_unpacklo_epi8(color01, _mm_setzero_si128());
+ color11 = _mm_unpacklo_epi8(color11, _mm_setzero_si128());
+ color01 = _mm_madd_epi16(color01, *(__m128i *)&rgbsse_statics.scale_table[u][0]);
+ color11 = _mm_madd_epi16(color11, *(__m128i *)&rgbsse_statics.scale_table[u][0]);
+ color01 = _mm_slli_epi32(color01, 15);
+ color11 = _mm_srli_epi32(color11, 1);
+ color01 = _mm_max_epi16(color01, color11);
+ color01 = _mm_madd_epi16(color01, *(__m128i *)&rgbsse_statics.scale_table[v][0]);
+ color01 = _mm_srli_epi32(color01, 15);
+ color01 = _mm_packs_epi32(color01, color01);
+ color01 = _mm_packus_epi16(color01, color01);
+ return _mm_cvtsi128_si32(color01);
+}
+
+
+/*-------------------------------------------------
+ rgba_bilinear_filter - bilinear filter between
+ four pixel values
+-------------------------------------------------*/
+
+INLINE rgb_t rgba_bilinear_filter(rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ return rgb_bilinear_filter(rgb00, rgb01, rgb10, rgb11, u, v);
+}
+
+
+/*-------------------------------------------------
+ rgbint_bilinear_filter - bilinear filter between
+ four pixel values
+-------------------------------------------------*/
+
+INLINE void rgbint_bilinear_filter(rgbint *color, rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ __m128i color00 = _mm_cvtsi32_si128(rgb00);
+ __m128i color01 = _mm_cvtsi32_si128(rgb01);
+ __m128i color10 = _mm_cvtsi32_si128(rgb10);
+ __m128i color11 = _mm_cvtsi32_si128(rgb11);
+
+ /* interleave color01 and color00 at the byte level */
+ color01 = _mm_unpacklo_epi8(color01, color00);
+ color11 = _mm_unpacklo_epi8(color11, color10);
+ color01 = _mm_unpacklo_epi8(color01, _mm_setzero_si128());
+ color11 = _mm_unpacklo_epi8(color11, _mm_setzero_si128());
+ color01 = _mm_madd_epi16(color01, *(__m128i *)&rgbsse_statics.scale_table[u][0]);
+ color11 = _mm_madd_epi16(color11, *(__m128i *)&rgbsse_statics.scale_table[u][0]);
+ color01 = _mm_slli_epi32(color01, 15);
+ color11 = _mm_srli_epi32(color11, 1);
+ color01 = _mm_max_epi16(color01, color11);
+ color01 = _mm_madd_epi16(color01, *(__m128i *)&rgbsse_statics.scale_table[v][0]);
+ color01 = _mm_srli_epi32(color01, 15);
+ *color = _mm_packs_epi32(color01, color01);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_bilinear_filter - bilinear filter between
+ four pixel values
+-------------------------------------------------*/
+
+INLINE void rgbaint_bilinear_filter(rgbaint *color, rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ rgbint_bilinear_filter(color, rgb00, rgb01, rgb10, rgb11, u, v);
+}
+
+
+#endif /* __RGBSSE__ */
diff --git a/src/emu/video/rgbutil.h b/src/emu/video/rgbutil.h
new file mode 100644
index 00000000000..d3c94496976
--- /dev/null
+++ b/src/emu/video/rgbutil.h
@@ -0,0 +1,25 @@
+/***************************************************************************
+
+ rgbutil.h
+
+ Utility definitions for RGB manipulation. Allows RGB handling to be
+ performed in an abstracted fashion and optimized with SIMD.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __RGBUTIL__
+#define __RGBUTIL__
+
+/* use SSE on 64-bit implementations, where it can be assumed */
+#if defined(__SSE2__) || (defined(PTR64) && defined(_MSC_VER))
+#include "rgbsse.h"
+#elif defined(__ALTIVEC__)
+#include "rgbvmx.h"
+#else
+#include "rgbgen.h"
+#endif
+
+#endif /* __RGBUTIL__ */
diff --git a/src/emu/video/rgbvmx.h b/src/emu/video/rgbvmx.h
new file mode 100644
index 00000000000..bb215d1966a
--- /dev/null
+++ b/src/emu/video/rgbvmx.h
@@ -0,0 +1,545 @@
+/***************************************************************************
+
+ rgbvmx.h
+
+ VMX/Altivec optimised RGB utilities.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __RGBVMX__
+#define __RGBVMX__
+
+#include <altivec.h>
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* intermediate RGB values are stored in a vector */
+typedef vector signed short rgbint;
+
+/* intermediate RGB values are stored in a vector */
+typedef vector signed short rgbaint;
+
+
+
+/***************************************************************************
+ BASIC CONVERSIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgb_comp_to_rgbint - converts a trio of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgb_comp_to_rgbint(rgbint *rgb, INT16 r, INT16 g, INT16 b)
+{
+ rgbint result = { 0, r, g, b, 0, 0, 0, 0 };
+ *rgb = result;
+}
+
+
+/*-------------------------------------------------
+ rgba_comp_to_rgbint - converts a quad of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgba_comp_to_rgbaint(rgbaint *rgb, INT16 a, INT16 r, INT16 g, INT16 b)
+{
+ rgbaint result = { a, r, g, b, 0, 0, 0, 0 };
+ *rgb = result;
+}
+
+
+/*-------------------------------------------------
+ rgb_to_rgbint - converts a packed trio of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgb_to_rgbint(rgbint *rgb, rgb_t color)
+{
+ vector signed char temp = (vector signed char)vec_perm((vector signed int)vec_lde(0, &color), vec_splat_s32(0), vec_lvsl(0, &color));
+ *rgb = vec_mergeh((vector signed char)vec_splat_s32(0), temp);
+}
+
+
+/*-------------------------------------------------
+ rgba_to_rgbaint - converts a packed quad of RGB
+ components to an rgbint type
+-------------------------------------------------*/
+
+INLINE void rgba_to_rgbaint(rgbaint *rgb, rgb_t color)
+{
+ vector signed char temp = (vector signed char)vec_perm((vector signed int)vec_lde(0, &color), vec_splat_s32(0), vec_lvsl(0, &color));
+ *rgb = vec_mergeh((vector signed char)vec_splat_s32(0), temp);
+}
+
+
+/*-------------------------------------------------
+ rgbint_to_rgb - converts an rgbint back to
+ a packed trio of RGB values
+-------------------------------------------------*/
+
+INLINE rgb_t rgbint_to_rgb(const rgbint *color)
+{
+ vector unsigned int temp = vec_splat((vector unsigned int)vec_packsu(*color, *color), 0);
+ rgb_t result;
+ vec_ste(temp, 0, &result);
+ return result;
+}
+
+
+/*-------------------------------------------------
+ rgbaint_to_rgba - converts an rgbint back to
+ a packed quad of RGB values
+-------------------------------------------------*/
+
+INLINE rgb_t rgbaint_to_rgba(const rgbaint *color)
+{
+ vector unsigned int temp = vec_splat((vector unsigned int)vec_packsu(*color, *color), 0);
+ rgb_t result;
+ vec_ste(temp, 0, &result);
+ return result;
+}
+
+
+/*-------------------------------------------------
+ rgbint_to_rgb_clamp - converts an rgbint back
+ to a packed trio of RGB values, clamping them
+ to bytes first
+-------------------------------------------------*/
+
+INLINE rgb_t rgbint_to_rgb_clamp(const rgbint *color)
+{
+ vector unsigned int temp = vec_splat((vector unsigned int)vec_packsu(*color, *color), 0);
+ rgb_t result;
+ vec_ste(temp, 0, &result);
+ return result;
+}
+
+
+/*-------------------------------------------------
+ rgbaint_to_rgba_clamp - converts an rgbint back
+ to a packed quad of RGB values, clamping them
+ to bytes first
+-------------------------------------------------*/
+
+INLINE rgb_t rgbaint_to_rgba_clamp(const rgbaint *color)
+{
+ vector unsigned int temp = vec_splat((vector unsigned int)vec_packsu(*color, *color), 0);
+ rgb_t result;
+ vec_ste(temp, 0, &result);
+ return result;
+}
+
+
+
+/***************************************************************************
+ CORE MATH
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgbint_add - add two rgbint values
+-------------------------------------------------*/
+
+INLINE void rgbint_add(rgbint *color1, const rgbint *color2)
+{
+ *color1 = vec_add(*color1, *color2);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_add - add two rgbaint values
+-------------------------------------------------*/
+
+INLINE void rgbaint_add(rgbaint *color1, const rgbaint *color2)
+{
+ *color1 = vec_add(*color1, *color2);
+}
+
+
+/*-------------------------------------------------
+ rgbint_sub - subtract two rgbint values
+-------------------------------------------------*/
+
+INLINE void rgbint_sub(rgbint *color1, const rgbint *color2)
+{
+ *color1 = vec_sub(*color1, *color2);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_sub - subtract two rgbaint values
+-------------------------------------------------*/
+
+INLINE void rgbaint_sub(rgbaint *color1, const rgbaint *color2)
+{
+ *color1 = vec_sub(*color1, *color2);
+}
+
+
+/*-------------------------------------------------
+ rgbint_subr - reverse subtract two rgbint
+ values
+-------------------------------------------------*/
+
+INLINE void rgbint_subr(rgbint *color1, const rgbint *color2)
+{
+ *color1 = vec_sub(*color2, *color1);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_subr - reverse subtract two rgbaint
+ values
+-------------------------------------------------*/
+
+INLINE void rgbaint_subr(rgbaint *color1, const rgbaint *color2)
+{
+ *color1 = vec_sub(*color2, *color1);
+}
+
+
+
+/***************************************************************************
+ TABLES
+***************************************************************************/
+
+static const struct
+{
+ rgbaint maxbyte;
+ rgbaint scale_table[256];
+} rgbvmx_statics =
+{
+ { 255, 255, 255, 255, 255, 255, 255, 255 },
+ {
+ { 1, 256, 1, 256, 1, 256, 1, 256 }, { 2, 255, 2, 255, 2, 255, 2, 255 },
+ { 3, 254, 3, 254, 3, 254, 3, 254 }, { 4, 253, 4, 253, 4, 253, 4, 253 },
+ { 5, 252, 5, 252, 5, 252, 5, 252 }, { 6, 251, 6, 251, 6, 251, 6, 251 },
+ { 7, 250, 7, 250, 7, 250, 7, 250 }, { 8, 249, 8, 249, 8, 249, 8, 249 },
+ { 9, 248, 9, 248, 9, 248, 9, 248 }, { 10, 247, 10, 247, 10, 247, 10, 247 },
+ { 11, 246, 11, 246, 11, 246, 11, 246 }, { 12, 245, 12, 245, 12, 245, 12, 245 },
+ { 13, 244, 13, 244, 13, 244, 13, 244 }, { 14, 243, 14, 243, 14, 243, 14, 243 },
+ { 15, 242, 15, 242, 15, 242, 15, 242 }, { 16, 241, 16, 241, 16, 241, 16, 241 },
+ { 17, 240, 17, 240, 17, 240, 17, 240 }, { 18, 239, 18, 239, 18, 239, 18, 239 },
+ { 19, 238, 19, 238, 19, 238, 19, 238 }, { 20, 237, 20, 237, 20, 237, 20, 237 },
+ { 21, 236, 21, 236, 21, 236, 21, 236 }, { 22, 235, 22, 235, 22, 235, 22, 235 },
+ { 23, 234, 23, 234, 23, 234, 23, 234 }, { 24, 233, 24, 233, 24, 233, 24, 233 },
+ { 25, 232, 25, 232, 25, 232, 25, 232 }, { 26, 231, 26, 231, 26, 231, 26, 231 },
+ { 27, 230, 27, 230, 27, 230, 27, 230 }, { 28, 229, 28, 229, 28, 229, 28, 229 },
+ { 29, 228, 29, 228, 29, 228, 29, 228 }, { 30, 227, 30, 227, 30, 227, 30, 227 },
+ { 31, 226, 31, 226, 31, 226, 31, 226 }, { 32, 225, 32, 225, 32, 225, 32, 225 },
+ { 33, 224, 33, 224, 33, 224, 33, 224 }, { 34, 223, 34, 223, 34, 223, 34, 223 },
+ { 35, 222, 35, 222, 35, 222, 35, 222 }, { 36, 221, 36, 221, 36, 221, 36, 221 },
+ { 37, 220, 37, 220, 37, 220, 37, 220 }, { 38, 219, 38, 219, 38, 219, 38, 219 },
+ { 39, 218, 39, 218, 39, 218, 39, 218 }, { 40, 217, 40, 217, 40, 217, 40, 217 },
+ { 41, 216, 41, 216, 41, 216, 41, 216 }, { 42, 215, 42, 215, 42, 215, 42, 215 },
+ { 43, 214, 43, 214, 43, 214, 43, 214 }, { 44, 213, 44, 213, 44, 213, 44, 213 },
+ { 45, 212, 45, 212, 45, 212, 45, 212 }, { 46, 211, 46, 211, 46, 211, 46, 211 },
+ { 47, 210, 47, 210, 47, 210, 47, 210 }, { 48, 209, 48, 209, 48, 209, 48, 209 },
+ { 49, 208, 49, 208, 49, 208, 49, 208 }, { 50, 207, 50, 207, 50, 207, 50, 207 },
+ { 51, 206, 51, 206, 51, 206, 51, 206 }, { 52, 205, 52, 205, 52, 205, 52, 205 },
+ { 53, 204, 53, 204, 53, 204, 53, 204 }, { 54, 203, 54, 203, 54, 203, 54, 203 },
+ { 55, 202, 55, 202, 55, 202, 55, 202 }, { 56, 201, 56, 201, 56, 201, 56, 201 },
+ { 57, 200, 57, 200, 57, 200, 57, 200 }, { 58, 199, 58, 199, 58, 199, 58, 199 },
+ { 59, 198, 59, 198, 59, 198, 59, 198 }, { 60, 197, 60, 197, 60, 197, 60, 197 },
+ { 61, 196, 61, 196, 61, 196, 61, 196 }, { 62, 195, 62, 195, 62, 195, 62, 195 },
+ { 63, 194, 63, 194, 63, 194, 63, 194 }, { 64, 193, 64, 193, 64, 193, 64, 193 },
+ { 65, 192, 65, 192, 65, 192, 65, 192 }, { 66, 191, 66, 191, 66, 191, 66, 191 },
+ { 67, 190, 67, 190, 67, 190, 67, 190 }, { 68, 189, 68, 189, 68, 189, 68, 189 },
+ { 69, 188, 69, 188, 69, 188, 69, 188 }, { 70, 187, 70, 187, 70, 187, 70, 187 },
+ { 71, 186, 71, 186, 71, 186, 71, 186 }, { 72, 185, 72, 185, 72, 185, 72, 185 },
+ { 73, 184, 73, 184, 73, 184, 73, 184 }, { 74, 183, 74, 183, 74, 183, 74, 183 },
+ { 75, 182, 75, 182, 75, 182, 75, 182 }, { 76, 181, 76, 181, 76, 181, 76, 181 },
+ { 77, 180, 77, 180, 77, 180, 77, 180 }, { 78, 179, 78, 179, 78, 179, 78, 179 },
+ { 79, 178, 79, 178, 79, 178, 79, 178 }, { 80, 177, 80, 177, 80, 177, 80, 177 },
+ { 81, 176, 81, 176, 81, 176, 81, 176 }, { 82, 175, 82, 175, 82, 175, 82, 175 },
+ { 83, 174, 83, 174, 83, 174, 83, 174 }, { 84, 173, 84, 173, 84, 173, 84, 173 },
+ { 85, 172, 85, 172, 85, 172, 85, 172 }, { 86, 171, 86, 171, 86, 171, 86, 171 },
+ { 87, 170, 87, 170, 87, 170, 87, 170 }, { 88, 169, 88, 169, 88, 169, 88, 169 },
+ { 89, 168, 89, 168, 89, 168, 89, 168 }, { 90, 167, 90, 167, 90, 167, 90, 167 },
+ { 91, 166, 91, 166, 91, 166, 91, 166 }, { 92, 165, 92, 165, 92, 165, 92, 165 },
+ { 93, 164, 93, 164, 93, 164, 93, 164 }, { 94, 163, 94, 163, 94, 163, 94, 163 },
+ { 95, 162, 95, 162, 95, 162, 95, 162 }, { 96, 161, 96, 161, 96, 161, 96, 161 },
+ { 97, 160, 97, 160, 97, 160, 97, 160 }, { 98, 159, 98, 159, 98, 159, 98, 159 },
+ { 99, 158, 99, 158, 99, 158, 99, 158 }, { 100, 157, 100, 157, 100, 157, 100, 157 },
+ { 101, 156, 101, 156, 101, 156, 101, 156 }, { 102, 155, 102, 155, 102, 155, 102, 155 },
+ { 103, 154, 103, 154, 103, 154, 103, 154 }, { 104, 153, 104, 153, 104, 153, 104, 153 },
+ { 105, 152, 105, 152, 105, 152, 105, 152 }, { 106, 151, 106, 151, 106, 151, 106, 151 },
+ { 107, 150, 107, 150, 107, 150, 107, 150 }, { 108, 149, 108, 149, 108, 149, 108, 149 },
+ { 109, 148, 109, 148, 109, 148, 109, 148 }, { 110, 147, 110, 147, 110, 147, 110, 147 },
+ { 111, 146, 111, 146, 111, 146, 111, 146 }, { 112, 145, 112, 145, 112, 145, 112, 145 },
+ { 113, 144, 113, 144, 113, 144, 113, 144 }, { 114, 143, 114, 143, 114, 143, 114, 143 },
+ { 115, 142, 115, 142, 115, 142, 115, 142 }, { 116, 141, 116, 141, 116, 141, 116, 141 },
+ { 117, 140, 117, 140, 117, 140, 117, 140 }, { 118, 139, 118, 139, 118, 139, 118, 139 },
+ { 119, 138, 119, 138, 119, 138, 119, 138 }, { 120, 137, 120, 137, 120, 137, 120, 137 },
+ { 121, 136, 121, 136, 121, 136, 121, 136 }, { 122, 135, 122, 135, 122, 135, 122, 135 },
+ { 123, 134, 123, 134, 123, 134, 123, 134 }, { 124, 133, 124, 133, 124, 133, 124, 133 },
+ { 125, 132, 125, 132, 125, 132, 125, 132 }, { 126, 131, 126, 131, 126, 131, 126, 131 },
+ { 127, 130, 127, 130, 127, 130, 127, 130 }, { 128, 129, 128, 129, 128, 129, 128, 129 },
+ { 129, 128, 129, 128, 129, 128, 129, 128 }, { 130, 127, 130, 127, 130, 127, 130, 127 },
+ { 131, 126, 131, 126, 131, 126, 131, 126 }, { 132, 125, 132, 125, 132, 125, 132, 125 },
+ { 133, 124, 133, 124, 133, 124, 133, 124 }, { 134, 123, 134, 123, 134, 123, 134, 123 },
+ { 135, 122, 135, 122, 135, 122, 135, 122 }, { 136, 121, 136, 121, 136, 121, 136, 121 },
+ { 137, 120, 137, 120, 137, 120, 137, 120 }, { 138, 119, 138, 119, 138, 119, 138, 119 },
+ { 139, 118, 139, 118, 139, 118, 139, 118 }, { 140, 117, 140, 117, 140, 117, 140, 117 },
+ { 141, 116, 141, 116, 141, 116, 141, 116 }, { 142, 115, 142, 115, 142, 115, 142, 115 },
+ { 143, 114, 143, 114, 143, 114, 143, 114 }, { 144, 113, 144, 113, 144, 113, 144, 113 },
+ { 145, 112, 145, 112, 145, 112, 145, 112 }, { 146, 111, 146, 111, 146, 111, 146, 111 },
+ { 147, 110, 147, 110, 147, 110, 147, 110 }, { 148, 109, 148, 109, 148, 109, 148, 109 },
+ { 149, 108, 149, 108, 149, 108, 149, 108 }, { 150, 107, 150, 107, 150, 107, 150, 107 },
+ { 151, 106, 151, 106, 151, 106, 151, 106 }, { 152, 105, 152, 105, 152, 105, 152, 105 },
+ { 153, 104, 153, 104, 153, 104, 153, 104 }, { 154, 103, 154, 103, 154, 103, 154, 103 },
+ { 155, 102, 155, 102, 155, 102, 155, 102 }, { 156, 101, 156, 101, 156, 101, 156, 101 },
+ { 157, 100, 157, 100, 157, 100, 157, 100 }, { 158, 99, 158, 99, 158, 99, 158, 99 },
+ { 159, 98, 159, 98, 159, 98, 159, 98 }, { 160, 97, 160, 97, 160, 97, 160, 97 },
+ { 161, 96, 161, 96, 161, 96, 161, 96 }, { 162, 95, 162, 95, 162, 95, 162, 95 },
+ { 163, 94, 163, 94, 163, 94, 163, 94 }, { 164, 93, 164, 93, 164, 93, 164, 93 },
+ { 165, 92, 165, 92, 165, 92, 165, 92 }, { 166, 91, 166, 91, 166, 91, 166, 91 },
+ { 167, 90, 167, 90, 167, 90, 167, 90 }, { 168, 89, 168, 89, 168, 89, 168, 89 },
+ { 169, 88, 169, 88, 169, 88, 169, 88 }, { 170, 87, 170, 87, 170, 87, 170, 87 },
+ { 171, 86, 171, 86, 171, 86, 171, 86 }, { 172, 85, 172, 85, 172, 85, 172, 85 },
+ { 173, 84, 173, 84, 173, 84, 173, 84 }, { 174, 83, 174, 83, 174, 83, 174, 83 },
+ { 175, 82, 175, 82, 175, 82, 175, 82 }, { 176, 81, 176, 81, 176, 81, 176, 81 },
+ { 177, 80, 177, 80, 177, 80, 177, 80 }, { 178, 79, 178, 79, 178, 79, 178, 79 },
+ { 179, 78, 179, 78, 179, 78, 179, 78 }, { 180, 77, 180, 77, 180, 77, 180, 77 },
+ { 181, 76, 181, 76, 181, 76, 181, 76 }, { 182, 75, 182, 75, 182, 75, 182, 75 },
+ { 183, 74, 183, 74, 183, 74, 183, 74 }, { 184, 73, 184, 73, 184, 73, 184, 73 },
+ { 185, 72, 185, 72, 185, 72, 185, 72 }, { 186, 71, 186, 71, 186, 71, 186, 71 },
+ { 187, 70, 187, 70, 187, 70, 187, 70 }, { 188, 69, 188, 69, 188, 69, 188, 69 },
+ { 189, 68, 189, 68, 189, 68, 189, 68 }, { 190, 67, 190, 67, 190, 67, 190, 67 },
+ { 191, 66, 191, 66, 191, 66, 191, 66 }, { 192, 65, 192, 65, 192, 65, 192, 65 },
+ { 193, 64, 193, 64, 193, 64, 193, 64 }, { 194, 63, 194, 63, 194, 63, 194, 63 },
+ { 195, 62, 195, 62, 195, 62, 195, 62 }, { 196, 61, 196, 61, 196, 61, 196, 61 },
+ { 197, 60, 197, 60, 197, 60, 197, 60 }, { 198, 59, 198, 59, 198, 59, 198, 59 },
+ { 199, 58, 199, 58, 199, 58, 199, 58 }, { 200, 57, 200, 57, 200, 57, 200, 57 },
+ { 201, 56, 201, 56, 201, 56, 201, 56 }, { 202, 55, 202, 55, 202, 55, 202, 55 },
+ { 203, 54, 203, 54, 203, 54, 203, 54 }, { 204, 53, 204, 53, 204, 53, 204, 53 },
+ { 205, 52, 205, 52, 205, 52, 205, 52 }, { 206, 51, 206, 51, 206, 51, 206, 51 },
+ { 207, 50, 207, 50, 207, 50, 207, 50 }, { 208, 49, 208, 49, 208, 49, 208, 49 },
+ { 209, 48, 209, 48, 209, 48, 209, 48 }, { 210, 47, 210, 47, 210, 47, 210, 47 },
+ { 211, 46, 211, 46, 211, 46, 211, 46 }, { 212, 45, 212, 45, 212, 45, 212, 45 },
+ { 213, 44, 213, 44, 213, 44, 213, 44 }, { 214, 43, 214, 43, 214, 43, 214, 43 },
+ { 215, 42, 215, 42, 215, 42, 215, 42 }, { 216, 41, 216, 41, 216, 41, 216, 41 },
+ { 217, 40, 217, 40, 217, 40, 217, 40 }, { 218, 39, 218, 39, 218, 39, 218, 39 },
+ { 219, 38, 219, 38, 219, 38, 219, 38 }, { 220, 37, 220, 37, 220, 37, 220, 37 },
+ { 221, 36, 221, 36, 221, 36, 221, 36 }, { 222, 35, 222, 35, 222, 35, 222, 35 },
+ { 223, 34, 223, 34, 223, 34, 223, 34 }, { 224, 33, 224, 33, 224, 33, 224, 33 },
+ { 225, 32, 225, 32, 225, 32, 225, 32 }, { 226, 31, 226, 31, 226, 31, 226, 31 },
+ { 227, 30, 227, 30, 227, 30, 227, 30 }, { 228, 29, 228, 29, 228, 29, 228, 29 },
+ { 229, 28, 229, 28, 229, 28, 229, 28 }, { 230, 27, 230, 27, 230, 27, 230, 27 },
+ { 231, 26, 231, 26, 231, 26, 231, 26 }, { 232, 25, 232, 25, 232, 25, 232, 25 },
+ { 233, 24, 233, 24, 233, 24, 233, 24 }, { 234, 23, 234, 23, 234, 23, 234, 23 },
+ { 235, 22, 235, 22, 235, 22, 235, 22 }, { 236, 21, 236, 21, 236, 21, 236, 21 },
+ { 237, 20, 237, 20, 237, 20, 237, 20 }, { 238, 19, 238, 19, 238, 19, 238, 19 },
+ { 239, 18, 239, 18, 239, 18, 239, 18 }, { 240, 17, 240, 17, 240, 17, 240, 17 },
+ { 241, 16, 241, 16, 241, 16, 241, 16 }, { 242, 15, 242, 15, 242, 15, 242, 15 },
+ { 243, 14, 243, 14, 243, 14, 243, 14 }, { 244, 13, 244, 13, 244, 13, 244, 13 },
+ { 245, 12, 245, 12, 245, 12, 245, 12 }, { 246, 11, 246, 11, 246, 11, 246, 11 },
+ { 247, 10, 247, 10, 247, 10, 247, 10 }, { 248, 9, 248, 9, 248, 9, 248, 9 },
+ { 249, 8, 249, 8, 249, 8, 249, 8 }, { 250, 7, 250, 7, 250, 7, 250, 7 },
+ { 251, 6, 251, 6, 251, 6, 251, 6 }, { 252, 5, 252, 5, 252, 5, 252, 5 },
+ { 253, 4, 253, 4, 253, 4, 253, 4 }, { 254, 3, 254, 3, 254, 3, 254, 3 },
+ { 255, 2, 255, 2, 255, 2, 255, 2 }, { 256, 1, 256, 1, 256, 1, 256, 1 }
+ }
+};
+
+
+
+/***************************************************************************
+ HIGHER LEVEL OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgbint_blend - blend two colors by the given
+ scale factor
+-------------------------------------------------*/
+
+INLINE void rgbint_blend(rgbint *color1, const rgbint *color2, UINT8 color1scale)
+{
+ vector signed int temp;
+ *color1 = vec_mergeh(*color1, *color2);
+ temp = vec_msum(*color1, rgbvmx_statics.scale_table[color1scale], vec_splat_s32(0));
+ temp = (vector signed int)vec_sr(temp, vec_splat_u32(8));
+ *color1 = vec_packs(temp, temp);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_blend - blend two colors by the given
+ scale factor
+-------------------------------------------------*/
+
+INLINE void rgbaint_blend(rgbaint *color1, const rgbaint *color2, UINT8 color1scale)
+{
+ vector signed int temp;
+ *color1 = vec_mergeh(*color1, *color2);
+ temp = vec_msum(*color1, rgbvmx_statics.scale_table[color1scale], vec_splat_s32(0));
+ temp = (vector signed int)vec_sr(temp, vec_splat_u32(8));
+ *color1 = vec_packs(temp, temp);
+}
+
+
+/*-------------------------------------------------
+ rgbint_scale_and_clamp - scale the given
+ color by an 8.8 scale factor and clamp to
+ byte values
+-------------------------------------------------*/
+
+INLINE void rgbint_scale_and_clamp(rgbint *color, INT16 colorscale)
+{
+ rgbint splatmap = vec_splat((rgbint)vec_lvsl(0, &colorscale), 0);
+ rgbint vecscale = vec_lde(0, &colorscale);
+ vector signed int temp;
+ vecscale = (rgbint)vec_perm(vecscale, vecscale, (vector unsigned char)splatmap);
+ *color = (rgbint)vec_mergeh(*color, (rgbint)vec_splat_s32(0));
+ temp = vec_msum(*color, vecscale, vec_splat_s32(0));
+ temp = (vector signed int)vec_sr(temp, vec_splat_u32(8));
+ *color = vec_min(vec_packs(temp, temp), rgbvmx_statics.maxbyte);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_scale_and_clamp - scale the given
+ color by an 8.8 scale factor and clamp to
+ byte values
+-------------------------------------------------*/
+
+INLINE void rgbaint_scale_and_clamp(rgbaint *color, INT16 colorscale)
+{
+ rgbaint splatmap = vec_splat((rgbaint)vec_lvsl(0, &colorscale), 0);
+ rgbaint vecscale = vec_lde(0, &colorscale);
+ vector signed int temp;
+ vecscale = (rgbaint)vec_perm(vecscale, vecscale, (vector unsigned char)splatmap);
+ *color = (rgbaint)vec_mergeh(*color, (rgbaint)vec_splat_s32(0));
+ temp = vec_msum(*color, vecscale, vec_splat_s32(0));
+ temp = (vector signed int)vec_sr(temp, vec_splat_u32(8));
+ *color = vec_min(vec_packs(temp, temp), rgbvmx_statics.maxbyte);
+}
+
+
+/*-------------------------------------------------
+ rgb_bilinear_filter - bilinear filter between
+ four pixel values
+-------------------------------------------------*/
+
+INLINE rgb_t rgb_bilinear_filter(rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ rgb_t result;
+ rgbint color00 = (rgbint)vec_perm((vector signed int)vec_lde(0, &rgb00), vec_splat_s32(0), vec_lvsl(0, &rgb00));
+ rgbint color01 = (rgbint)vec_perm((vector signed int)vec_lde(0, &rgb01), vec_splat_s32(0), vec_lvsl(0, &rgb01));
+ rgbint color10 = (rgbint)vec_perm((vector signed int)vec_lde(0, &rgb10), vec_splat_s32(0), vec_lvsl(0, &rgb10));
+ rgbint color11 = (rgbint)vec_perm((vector signed int)vec_lde(0, &rgb11), vec_splat_s32(0), vec_lvsl(0, &rgb11));
+
+ /* interleave color01 and color00 at the byte level */
+ color01 = vec_mergeh((vector signed char)color01, (vector signed char)color00);
+ color11 = vec_mergeh((vector signed char)color11, (vector signed char)color10);
+ color01 = vec_mergeh((vector signed char)vec_splat_s32(0), (vector signed char)color01);
+ color11 = vec_mergeh((vector signed char)vec_splat_s32(0), (vector signed char)color11);
+ color01 = vec_msum(color01, rgbvmx_statics.scale_table[u], vec_splat_s32(0));
+ color11 = vec_msum(color11, rgbvmx_statics.scale_table[u], vec_splat_s32(0));
+ color01 = (rgbint)vec_sr((vector signed int)color01, vec_splat_u32(1));
+ color11 = (rgbint)vec_sl((vector signed int)color11, vec_splat_u32(15));
+ color01 = vec_max(color01, color11);
+ color01 = vec_msum(color01, rgbvmx_statics.scale_table[v], vec_splat_s32(0));
+ color01 = (rgbint)vec_sr((vector signed int)color01, vec_splat_u32(15));
+ color01 = vec_packs((vector signed int)color01, (vector signed int)color01);
+ color01 = vec_packsu(color01, color01);
+ vec_ste((vector unsigned int)color01, 0, &result);
+ return result;
+}
+
+
+/*-------------------------------------------------
+ rgba_bilinear_filter - bilinear filter between
+ four pixel values
+-------------------------------------------------*/
+
+INLINE rgb_t rgba_bilinear_filter(rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ rgb_t result;
+ rgbaint color00 = (rgbaint)vec_perm((vector signed int)vec_lde(0, &rgb00), vec_splat_s32(0), vec_lvsl(0, &rgb00));
+ rgbaint color01 = (rgbaint)vec_perm((vector signed int)vec_lde(0, &rgb01), vec_splat_s32(0), vec_lvsl(0, &rgb01));
+ rgbaint color10 = (rgbaint)vec_perm((vector signed int)vec_lde(0, &rgb10), vec_splat_s32(0), vec_lvsl(0, &rgb10));
+ rgbaint color11 = (rgbaint)vec_perm((vector signed int)vec_lde(0, &rgb11), vec_splat_s32(0), vec_lvsl(0, &rgb11));
+
+ /* interleave color01 and color00 at the byte level */
+ color01 = vec_mergeh((vector signed char)color01, (vector signed char)color00);
+ color11 = vec_mergeh((vector signed char)color11, (vector signed char)color10);
+ color01 = vec_mergeh((vector signed char)vec_splat_s32(0), (vector signed char)color01);
+ color11 = vec_mergeh((vector signed char)vec_splat_s32(0), (vector signed char)color11);
+ color01 = vec_msum(color01, rgbvmx_statics.scale_table[u], vec_splat_s32(0));
+ color11 = vec_msum(color11, rgbvmx_statics.scale_table[u], vec_splat_s32(0));
+ color01 = (rgbaint)vec_sr((vector signed int)color01, vec_splat_u32(1));
+ color11 = (rgbaint)vec_sl((vector signed int)color11, vec_splat_u32(15));
+ color01 = vec_max(color01, color11);
+ color01 = vec_msum(color01, rgbvmx_statics.scale_table[v], vec_splat_s32(0));
+ color01 = (rgbaint)vec_sr((vector signed int)color01, vec_splat_u32(15));
+ color01 = vec_packs((vector signed int)color01, (vector signed int)color01);
+ color01 = vec_packsu(color01, color01);
+ vec_ste((vector unsigned int)color01, 0, &result);
+ return result;
+}
+
+
+/*-------------------------------------------------
+ rgbint_bilinear_filter - bilinear filter between
+ four pixel values
+-------------------------------------------------*/
+
+INLINE void rgbint_bilinear_filter(rgbint *color, rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ rgbint color00 = (rgbint)vec_perm((vector signed int)vec_lde(0, &rgb00), vec_splat_s32(0), vec_lvsl(0, &rgb00));
+ rgbint color01 = (rgbint)vec_perm((vector signed int)vec_lde(0, &rgb01), vec_splat_s32(0), vec_lvsl(0, &rgb01));
+ rgbint color10 = (rgbint)vec_perm((vector signed int)vec_lde(0, &rgb10), vec_splat_s32(0), vec_lvsl(0, &rgb10));
+ rgbint color11 = (rgbint)vec_perm((vector signed int)vec_lde(0, &rgb11), vec_splat_s32(0), vec_lvsl(0, &rgb11));
+
+ /* interleave color01 and color00 at the byte level */
+ color01 = vec_mergeh((vector signed char)color01, (vector signed char)color00);
+ color11 = vec_mergeh((vector signed char)color11, (vector signed char)color10);
+ color01 = vec_mergeh((vector signed char)vec_splat_s32(0), (vector signed char)color01);
+ color11 = vec_mergeh((vector signed char)vec_splat_s32(0), (vector signed char)color11);
+ color01 = vec_msum(color01, rgbvmx_statics.scale_table[u], vec_splat_s32(0));
+ color11 = vec_msum(color11, rgbvmx_statics.scale_table[u], vec_splat_s32(0));
+ color01 = (rgbint)vec_sr((vector signed int)color01, vec_splat_u32(1));
+ color11 = (rgbint)vec_sl((vector signed int)color11, vec_splat_u32(15));
+ color01 = vec_max(color01, color11);
+ color01 = vec_msum(color01, rgbvmx_statics.scale_table[v], vec_splat_s32(0));
+ color01 = (rgbint)vec_sr((vector signed int)color01, vec_splat_u32(15));
+ *color = vec_packs((vector signed int)color01, (vector signed int)color01);
+}
+
+
+/*-------------------------------------------------
+ rgbaint_bilinear_filter - bilinear filter between
+ four pixel values
+-------------------------------------------------*/
+
+INLINE void rgbaint_bilinear_filter(rgbaint *color, rgb_t rgb00, rgb_t rgb01, rgb_t rgb10, rgb_t rgb11, UINT8 u, UINT8 v)
+{
+ rgbaint color00 = (rgbaint)vec_perm((vector signed int)vec_lde(0, &rgb00), vec_splat_s32(0), vec_lvsl(0, &rgb00));
+ rgbaint color01 = (rgbaint)vec_perm((vector signed int)vec_lde(0, &rgb01), vec_splat_s32(0), vec_lvsl(0, &rgb01));
+ rgbaint color10 = (rgbaint)vec_perm((vector signed int)vec_lde(0, &rgb10), vec_splat_s32(0), vec_lvsl(0, &rgb10));
+ rgbaint color11 = (rgbaint)vec_perm((vector signed int)vec_lde(0, &rgb11), vec_splat_s32(0), vec_lvsl(0, &rgb11));
+
+ /* interleave color01 and color00 at the byte level */
+ color01 = vec_mergeh((vector signed char)color01, (vector signed char)color00);
+ color11 = vec_mergeh((vector signed char)color11, (vector signed char)color10);
+ color01 = vec_mergeh((vector signed char)vec_splat_s32(0), (vector signed char)color01);
+ color11 = vec_mergeh((vector signed char)vec_splat_s32(0), (vector signed char)color11);
+ color01 = vec_msum(color01, rgbvmx_statics.scale_table[u], vec_splat_s32(0));
+ color11 = vec_msum(color11, rgbvmx_statics.scale_table[u], vec_splat_s32(0));
+ color01 = (rgbaint)vec_sr((vector signed int)color01, vec_splat_u32(1));
+ color11 = (rgbaint)vec_sl((vector signed int)color11, vec_splat_u32(15));
+ color01 = vec_max(color01, color11);
+ color01 = vec_msum(color01, rgbvmx_statics.scale_table[v], vec_splat_s32(0));
+ color01 = (rgbaint)vec_sr((vector signed int)color01, vec_splat_u32(15));
+ *color = vec_packs((vector signed int)color01, (vector signed int)color01);
+}
+
+
+#endif /* __RGBVMX__ */
diff --git a/src/emu/video/s2636.c b/src/emu/video/s2636.c
new file mode 100644
index 00000000000..664399e4834
--- /dev/null
+++ b/src/emu/video/s2636.c
@@ -0,0 +1,300 @@
+/*************************************************************
+ * *
+ * Signetics 2636 video chip *
+ * *
+ *************************************************************
+
+ PVI REGISTER DESCRIPTION
+ ------------------------
+
+ | bit |R/W| description
+ byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
+ | | |
+ FC0 | size 4| size 3| size 2| size 1| W | size of the 4 objects(=sprites)
+ | | |
+ FC1 | |C1 |C2 |C3 |C1 |C2 |C3 | W | colours of the 4 objects
+ | | colour 1 | colour 2 | |
+ FC2 | |C1 |C2 |C3 |C1 |C2 |C3 | W |
+ | | colour 3 | colour 4 | |
+ | | |
+ FC3 | |sh |pos| W | 1=shape 0=position
+ | | | display format and position
+ FC4 | (free) | |
+ FC5 | (free) | |
+ | | |
+ FC6 | |C1 |C2 |C3 |BG |scrn colr | W | background lock and colour
+ | |backg colr |enb|C1 |C2 |C3 | | 3="enable"
+ | | |
+ FC7 | sound | W | squarewave output
+ | | |
+ FC8 | N1 | N2 | W | range of the 4 display digits
+ FC9 | N3 | N4 | W |
+ | | |
+ |obj/backgrnd |complete object| R |
+ FCA | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 | |
+ | | |
+ FCB | |VR-| object collisions | R | Composition of object and back-
+ | |LE |1/2|1/3|1/3|1/4|2/4|3/4| | ground,collision detection and
+ | | | object display as a state display
+ | | | for the status register.Set VRLE.
+ | | | wait for VRST.Read out or transmit
+ | | | [copy?] all bits until reset by
+ | | | VRST.
+ | | |
+ FCC | PORT1 | R | PORT1 and PORT2 for the range of
+ FCD | PORT2 | | the A/D conversion.Cleared by VRST
+ FCE | (free) | |
+ FCF | (free) | |
+
+
+ Size control by byte FC0
+
+ bit matrix
+ |0|0| 8x10
+ |0|1| 16x20
+ |1|0| 32x40
+ |1|1| 64x80
+
+ CE1 and not-CE2 are outputs from the PVI.$E80..$EFF also controls the
+ analogue multiplexer.
+
+
+ SPRITES
+ -------
+
+ each object field: (=sprite data structure)
+
+ 0 \ 10 bytes of bitmap (Each object is 8 pixels wide.)
+ 9 /
+ A HC horizontal object coordinate
+ B HCB horizontal dublicate coordinate
+ C VC vertical object coordinate
+ D VCB vertical dublicate coordinate
+
+ *************************************************************/
+
+#include "driver.h"
+#include "s2636.h"
+
+static int SpriteOffset[4] = {0,0x10,0x20,0x40};
+
+/* To adjust sprites against bitmap */
+
+UINT8 *s2636_1_ram;
+UINT8 *s2636_2_ram;
+UINT8 *s2636_3_ram;
+
+mame_bitmap *s2636_1_bitmap;
+mame_bitmap *s2636_2_bitmap;
+mame_bitmap *s2636_3_bitmap;
+
+UINT8 s2636_1_dirty[4];
+UINT8 s2636_2_dirty[4];
+UINT8 s2636_3_dirty[4];
+
+int s2636_x_offset=0;
+int s2636_y_offset=0;
+
+void s2636_w(UINT8 *workram,int offset,int data,UINT8 *dirty)
+{
+ if (workram[offset] != data)
+ {
+ workram[offset] = data;
+
+ if(offset < 10)
+ dirty[0]=1;
+ else
+ {
+ if((offset > 15) && (offset < 26))
+ dirty[1]=1;
+ else
+ {
+ if((offset > 31) && (offset < 42))
+ dirty[2]=1;
+ else
+ {
+ if((offset > 63) && (offset < 74))
+ dirty[3]=1;
+ }
+ }
+ }
+ }
+}
+
+/*****************************************/
+/* Check for Collision between 2 sprites */
+/*****************************************/
+
+static int SpriteCheck(running_machine *machine, int first,int second,UINT8 *workram,int Graphics_Bank,mame_bitmap *collision_bitmap)
+{
+ int Checksum=0;
+ int x,y;
+
+ // Does not check shadow sprites yet
+
+ if((workram[SpriteOffset[first] + 10] != 0xff) && (workram[SpriteOffset[second] + 10] != 0xff))
+ {
+ int fx1 = workram[SpriteOffset[first] + 10] + s2636_x_offset;
+ int fy1 = workram[SpriteOffset[first] + 12] + s2636_y_offset;
+ int fx2 = workram[SpriteOffset[second] + 10] + s2636_x_offset;
+ int fy2 = workram[SpriteOffset[second] + 12] + s2636_y_offset;
+
+ if((fx1>=0) && (fy1>=0) && (fx2>=0) && (fy2>=0))
+ {
+ int expand1 = 1 << (16+((workram[0xC0]>>(first<<1)) & 3));
+ int expand2 = 1 << (16+((workram[0xC0]>>(second<<1)) & 3));
+
+ int char1 = SpriteOffset[first]>>4;
+ int char2 = SpriteOffset[second]>>4;
+
+ /* Draw first sprite */
+
+ drawgfxzoom(collision_bitmap,machine->gfx[Graphics_Bank],
+ char1,
+ 1,
+ 0,0,
+ fx1,fy1,
+ &machine->screen[0].visarea, TRANSPARENCY_PEN, 0,
+ expand1,expand1);
+
+ /* Get fingerprint */
+
+ for (x = fx1; x < fx1 + machine->gfx[Graphics_Bank]->width; x++)
+ {
+ for (y = fy1; y < fy1 + machine->gfx[Graphics_Bank]->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_ADDR8(collision_bitmap, y, x);
+ }
+ }
+
+ /* Blackout second sprite */
+
+ drawgfxzoom(collision_bitmap,machine->gfx[Graphics_Bank],
+ char2,
+ 0,
+ 0,0,
+ fx2,fy2,
+ &machine->screen[0].visarea, TRANSPARENCY_PEN, 0,
+ expand2,expand2);
+
+ /* Remove fingerprint */
+
+ for (x = fx1; x < fx1 + machine->gfx[Graphics_Bank]->width; x++)
+ {
+ for (y = fy1; y < fy1 + machine->gfx[Graphics_Bank]->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_ADDR8(collision_bitmap, y, x);
+ }
+ }
+
+ /* Zero bitmap */
+
+ drawgfxzoom(collision_bitmap,machine->gfx[Graphics_Bank],
+ char1,
+ 0,
+ 0,0,
+ fx1,fy1,
+ &machine->screen[0].visarea, TRANSPARENCY_PEN, 0,
+ expand1,expand1);
+ }
+ }
+
+ return Checksum;
+}
+
+void s2636_update_bitmap(running_machine *machine,mame_bitmap *bitmap,UINT8 *workram,UINT8 *dirty,int Graphics_Bank,mame_bitmap *collision_bitmap)
+{
+ int CollisionSprite = 0;
+ int spriteno;
+ int offs;
+
+ for(spriteno=0;spriteno<4;spriteno++)
+ {
+ offs = SpriteOffset[spriteno];
+
+ if(workram[offs+10]!=0xFF)
+ {
+ int charno = offs>>4;
+ int expand = 1 << (16+((workram[0xC0]>>(spriteno<<1)) & 3));
+ int bx = workram[offs+10] + s2636_x_offset;
+ int by = workram[offs+12] + s2636_y_offset;
+
+ if((bx >= 0) && (by >= 0))
+ {
+ /* Get colour and mask correct bits */
+
+ int colour = workram[0xC1 + (spriteno >> 1)];
+
+ if((spriteno & 1)==0) colour >>= 3;
+
+ colour = (colour & 7) + 7;
+
+ if(dirty[spriteno])
+ {
+ decodechar(machine->gfx[Graphics_Bank],charno,workram,machine->drv->gfxdecodeinfo[Graphics_Bank].gfxlayout);
+ dirty[spriteno] = 0;
+ }
+
+ drawgfxzoom(bitmap,machine->gfx[Graphics_Bank],
+ charno,
+ colour,
+ 0,0,
+ bx,by,
+ &machine->screen[0].visarea,
+ TRANSPARENCY_BLEND_RAW, 0,
+ expand,expand);
+
+ /* Shadow Sprites */
+
+ if((workram[offs+11]!=0xff) && (workram[offs+13]!=0xfe))
+ {
+ bx=workram[offs+11] + s2636_x_offset;
+
+ if(bx >= 0)
+ {
+ for(;by < 255;)
+ {
+ by=by+10+workram[offs+13];
+
+ drawgfxzoom(bitmap,machine->gfx[Graphics_Bank],
+ charno,
+ colour,
+ 0,0,
+ bx,by,
+ &machine->screen[0].visarea,
+ TRANSPARENCY_BLEND_RAW, 0,
+ expand,expand);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Sprite->Sprite collision detection */
+
+ if(SpriteCheck(machine,0,1,workram,Graphics_Bank,collision_bitmap)) CollisionSprite |= 0x20;
+ if(SpriteCheck(machine,0,2,workram,Graphics_Bank,collision_bitmap)) CollisionSprite |= 0x10;
+ if(SpriteCheck(machine,0,3,workram,Graphics_Bank,collision_bitmap)) CollisionSprite |= 0x08;
+ if(SpriteCheck(machine,1,2,workram,Graphics_Bank,collision_bitmap)) CollisionSprite |= 0x04;
+ if(SpriteCheck(machine,1,3,workram,Graphics_Bank,collision_bitmap)) CollisionSprite |= 0x02;
+ if(SpriteCheck(machine,2,3,workram,Graphics_Bank,collision_bitmap)) CollisionSprite |= 0x01;
+
+ workram[0xCB] = CollisionSprite;
+}
diff --git a/src/emu/video/s2636.h b/src/emu/video/s2636.h
new file mode 100644
index 00000000000..a8defec0370
--- /dev/null
+++ b/src/emu/video/s2636.h
@@ -0,0 +1,18 @@
+extern UINT8 *s2636_1_ram;
+extern UINT8 *s2636_2_ram;
+extern UINT8 *s2636_3_ram;
+
+extern mame_bitmap *s2636_1_bitmap;
+extern mame_bitmap *s2636_2_bitmap;
+extern mame_bitmap *s2636_3_bitmap;
+
+extern UINT8 s2636_1_dirty[4];
+extern UINT8 s2636_2_dirty[4];
+extern UINT8 s2636_3_dirty[4];
+
+extern int s2636_x_offset;
+extern int s2636_y_offset;
+
+void s2636_w(UINT8 *workram,int offset,int data,UINT8 *dirty);
+void s2636_update_bitmap(running_machine *machine,mame_bitmap *bitmap,UINT8 *workram,UINT8 *dirty,int Graphics_Bank,mame_bitmap *collision_bitmap);
+
diff --git a/src/emu/video/tlc34076.c b/src/emu/video/tlc34076.c
new file mode 100644
index 00000000000..a750dd334ad
--- /dev/null
+++ b/src/emu/video/tlc34076.c
@@ -0,0 +1,262 @@
+/***************************************************************************
+
+ tlc34076.c
+
+ Basic implementation of the TLC34076 palette chip and similar
+ compatible chips.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "tlc34076.h"
+
+static UINT8 local_paletteram[0x300];
+static UINT8 regs[0x10];
+static UINT8 palettedata[3];
+static UINT8 writeindex, readindex;
+static UINT8 dacbits;
+
+
+#define PALETTE_WRITE_ADDR 0x00
+#define PALETTE_DATA 0x01
+#define PIXEL_READ_MASK 0x02
+#define PALETTE_READ_ADDR 0x03
+#define GENERAL_CONTROL 0x08
+#define INPUT_CLOCK_SEL 0x09
+#define OUTPUT_CLOCK_SEL 0x0a
+#define MUX_CONTROL 0x0b
+#define PALETTE_PAGE 0x0c
+#define TEST_REGISTER 0x0e
+#define RESET_STATE 0x0f
+
+
+
+/*************************************
+ *
+ * Palette update
+ *
+ *************************************/
+
+static void update_palette(int which)
+{
+ int totalcolors = (Machine->drv->total_colors <= 256) ? Machine->drv->total_colors : 256;
+ int i, mask = regs[PIXEL_READ_MASK];
+
+ for (i = 0; i < totalcolors; i++)
+ if (which == -1 || (i & mask) == which)
+ {
+ int r = local_paletteram[3 * i + 0];
+ int g = local_paletteram[3 * i + 1];
+ int b = local_paletteram[3 * i + 2];
+ if (dacbits == 6)
+ {
+ r = pal6bit(r);
+ g = pal6bit(g);
+ b = pal6bit(b);
+ }
+ palette_set_color(Machine, i, MAKE_RGB(r, g, b));
+ }
+}
+
+
+
+/*************************************
+ *
+ * State reset
+ *
+ *************************************/
+
+void tlc34076_reset(int dacwidth)
+{
+ /* set the DAC width */
+ dacbits = dacwidth;
+ if (dacbits != 6 && dacbits != 8)
+ {
+ logerror("tlc34076_reset: dacwidth must be 6 or 8!\n");
+ dacbits = 6;
+ }
+
+ /* reset the registers */
+ regs[PIXEL_READ_MASK] = 0xff;
+ regs[GENERAL_CONTROL] = 0x03;
+ regs[INPUT_CLOCK_SEL] = 0x00;
+ regs[OUTPUT_CLOCK_SEL] = 0x3f;
+ regs[MUX_CONTROL] = 0x2d;
+ regs[PALETTE_PAGE] = 0x00;
+ regs[TEST_REGISTER] = 0x00;
+ regs[RESET_STATE] = 0x00;
+}
+
+
+
+/*************************************
+ *
+ * Read access
+ *
+ *************************************/
+
+READ8_HANDLER( tlc34076_r )
+{
+ UINT8 result;
+
+ /* keep in range */
+ offset &= 0x0f;
+ result = regs[offset];
+
+ /* switch off the offset */
+ switch (offset)
+ {
+ case PALETTE_DATA:
+ if (readindex == 0)
+ {
+ palettedata[0] = local_paletteram[3 * regs[PALETTE_READ_ADDR] + 0];
+ palettedata[1] = local_paletteram[3 * regs[PALETTE_READ_ADDR] + 1];
+ palettedata[2] = local_paletteram[3 * regs[PALETTE_READ_ADDR] + 2];
+ }
+ result = palettedata[readindex++];
+ if (readindex == 3)
+ {
+ readindex = 0;
+ regs[PALETTE_READ_ADDR]++;
+ }
+ break;
+ }
+
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Write access
+ *
+ *************************************/
+
+WRITE8_HANDLER( tlc34076_w )
+{
+ UINT8 oldval;
+
+ /* keep in range */
+ offset &= 0x0f;
+ oldval = regs[offset];
+ regs[offset] = data;
+
+ /* switch off the offset */
+ switch (offset)
+ {
+ case PALETTE_WRITE_ADDR:
+ writeindex = 0;
+ break;
+
+ case PALETTE_DATA:
+ palettedata[writeindex++] = data;
+ if (writeindex == 3)
+ {
+ local_paletteram[3 * regs[PALETTE_WRITE_ADDR] + 0] = palettedata[0];
+ local_paletteram[3 * regs[PALETTE_WRITE_ADDR] + 1] = palettedata[1];
+ local_paletteram[3 * regs[PALETTE_WRITE_ADDR] + 2] = palettedata[2];
+ update_palette(regs[PALETTE_WRITE_ADDR]);
+ writeindex = 0;
+ regs[PALETTE_WRITE_ADDR]++;
+ }
+ break;
+
+ case PALETTE_READ_ADDR:
+ readindex = 0;
+ break;
+
+ case GENERAL_CONTROL:
+ /*
+ 7 6 5 4 3 2 1 0
+ X X X X X X X 0 HSYNCOUT is active-low
+ X X X X X X X 1 HSYNCOUT is active-high (default)
+ X X X X X X 0 X VSYNCOUT is active-low
+ X X X X X X 1 X VSYNCOUT is active-high (default)
+ X X X X X 0 X X Disable split shift register transfer (default)
+ X X X X 0 1 X X Enable split shift register transfer
+ X X X X 0 X X X Disable special nibble mode (default)
+ X X X X 1 0 X X Enable special nibble mode
+ X X X 0 X X X X 0-IRE pedestal (default)
+ X X X 1 X X X X 7.5-IRE pedestal
+ X X 0 X X X X X Disable sync (default)
+ X X 1 X X X X X Enable sync
+ X 0 X X X X X X Little-endian mode (default)
+ X 1 X X X X X X Big-endian mode
+ 0 X X X X X X X MUXOUT is low (default)
+ 1 X X X X X X X MUXOUT is high
+ */
+ break;
+
+ case INPUT_CLOCK_SEL:
+ /*
+ 3 2 1 0
+ 0 0 0 0 Select CLK0 as clock source?
+ 0 0 0 1 Select CLK1 as clock source
+ 0 0 1 0 Select CLK2 as clock source
+ 0 0 1 1 Select CLK3 as TTL clock source
+ 0 1 0 0 Select CLK3 as TTL clock source
+ 1 0 0 0 Select CLK3 and CLK3 as ECL clock sources
+ */
+ break;
+
+ case OUTPUT_CLOCK_SEL:
+ /*
+ 0 0 0 X X X VCLK frequency = DOTCLK frequency
+ 0 0 1 X X X VCLK frequency = DOTCLK frequency/2
+ 0 1 0 X X X VCLK frequency = DOTCLK frequency/4
+ 0 1 1 X X X VCLK frequency = DOTCLK frequency/8
+ 1 0 0 X X X VCLK frequency = DOTCLK frequency/16
+ 1 0 1 X X X VCLK frequency = DOTCLK frequency/32
+ 1 1 X X X X VCLK output held at logic high level (default condition)
+ X X X 0 0 0 SCLK frequency = DOTCLK frequency
+ X X X 0 0 1 SCLK frequency = DOTCLK frequency/2
+ X X X 0 1 0 SCLK frequency = DOTCLK frequency/4
+ X X X 0 1 1 SCLK frequency = DOTCLK frequency/8
+ X X X 1 0 0 SCLK frequency = DOTCLK frequency/16
+ X X X 1 0 1 SCLK frequency = DOTCLK frequency/32
+ X X X 1 1 X SCLK output held at logic level low (default condition)
+ */
+ break;
+
+ case PIXEL_READ_MASK:
+ case PALETTE_PAGE:
+ update_palette(-1);
+ break;
+
+ case RESET_STATE:
+ tlc34076_reset(dacbits);
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * 16-bit accessors
+ *
+ *************************************/
+
+READ16_HANDLER( tlc34076_lsb_r )
+{
+ return tlc34076_r(offset);
+}
+
+WRITE16_HANDLER( tlc34076_lsb_w )
+{
+ if (ACCESSING_LSB)
+ tlc34076_w(offset, data);
+}
+
+READ16_HANDLER( tlc34076_msb_r )
+{
+ return tlc34076_r(offset) << 8;
+}
+
+WRITE16_HANDLER( tlc34076_msb_w )
+{
+ if (ACCESSING_MSB)
+ tlc34076_w(offset, data >> 8);
+}
+
diff --git a/src/emu/video/tlc34076.h b/src/emu/video/tlc34076.h
new file mode 100644
index 00000000000..306aa45db2c
--- /dev/null
+++ b/src/emu/video/tlc34076.h
@@ -0,0 +1,19 @@
+/***************************************************************************
+
+ tlc34076.h
+
+ Basic implementation of the TLC34076 palette chip and similar
+ compatible chips.
+
+***************************************************************************/
+
+void tlc34076_reset(int dacwidth);
+
+READ8_HANDLER( tlc34076_r );
+WRITE8_HANDLER( tlc34076_w );
+
+READ16_HANDLER( tlc34076_lsb_r );
+WRITE16_HANDLER( tlc34076_lsb_w );
+READ16_HANDLER( tlc34076_msb_r );
+WRITE16_HANDLER( tlc34076_msb_w );
+
diff --git a/src/emu/video/tms34061.c b/src/emu/video/tms34061.c
new file mode 100644
index 00000000000..49d20d31da2
--- /dev/null
+++ b/src/emu/video/tms34061.c
@@ -0,0 +1,541 @@
+/****************************************************************************
+ * *
+ * Functions to emulate the TMS34061 video controller *
+ * *
+ * Created by Zsolt Vasvari on 5/26/1998. *
+ * Updated by Aaron Giles on 11/21/2000. *
+ * *
+ * This is far from complete. See the TMS34061 User's Guide available on *
+ * www.spies.com/arcade *
+ * *
+ ****************************************************************************/
+
+#include "driver.h"
+#include "tms34061.h"
+
+
+#define VERBOSE (0)
+
+
+/*************************************
+ *
+ * Internal structure
+ *
+ *************************************/
+
+struct tms34061_data
+{
+ UINT16 regs[TMS34061_REGCOUNT];
+ UINT16 xmask;
+ UINT8 yshift;
+ UINT32 vrammask;
+ UINT8 * vram;
+ UINT8 * latchram;
+ UINT8 latchdata;
+ UINT8 * shiftreg;
+ emu_timer * timer;
+ struct tms34061_interface intf;
+};
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+static struct tms34061_data tms34061;
+
+static const char *regnames[] =
+{
+ "HORENDSYNC", "HORENDBLNK", "HORSTARTBLNK", "HORTOTAL",
+ "VERENDSYNC", "VERENDBLNK", "VERSTARTBLNK", "VERTOTAL",
+ "DISPUPDATE", "DISPSTART", "VERINT", "CONTROL1",
+ "CONTROL2", "STATUS", "XYOFFSET", "XYADDRESS",
+ "DISPADDRESS", "VERCOUNTER"
+};
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static TIMER_CALLBACK( tms34061_interrupt );
+
+
+
+/*************************************
+ *
+ * Hardware startup
+ *
+ *************************************/
+
+void tms34061_start(struct tms34061_interface *interface)
+{
+ /* reset the data */
+ memset(&tms34061, 0, sizeof(tms34061));
+ tms34061.intf = *interface;
+ tms34061.vrammask = tms34061.intf.vramsize - 1;
+
+ /* allocate memory for VRAM */
+ tms34061.vram = auto_malloc(tms34061.intf.vramsize + 256 * 2);
+ memset(tms34061.vram, 0, tms34061.intf.vramsize + 256 * 2);
+
+ /* allocate memory for latch RAM */
+ tms34061.latchram = auto_malloc(tms34061.intf.vramsize + 256 * 2);
+ memset(tms34061.latchram, 0, tms34061.intf.vramsize + 256 * 2);
+
+ /* add some buffer space for VRAM and latch RAM */
+ tms34061.vram += 256;
+ tms34061.latchram += 256;
+
+ /* point the shift register to the base of VRAM for now */
+ tms34061.shiftreg = tms34061.vram;
+
+ /* initialize registers to their default values from the manual */
+ tms34061.regs[TMS34061_HORENDSYNC] = 0x0010;
+ tms34061.regs[TMS34061_HORENDBLNK] = 0x0020;
+ tms34061.regs[TMS34061_HORSTARTBLNK] = 0x01f0;
+ tms34061.regs[TMS34061_HORTOTAL] = 0x0200;
+ tms34061.regs[TMS34061_VERENDSYNC] = 0x0004;
+ tms34061.regs[TMS34061_VERENDBLNK] = 0x0010;
+ tms34061.regs[TMS34061_VERSTARTBLNK] = 0x00f0;
+ tms34061.regs[TMS34061_VERTOTAL] = 0x0100;
+ tms34061.regs[TMS34061_DISPUPDATE] = 0x0000;
+ tms34061.regs[TMS34061_DISPSTART] = 0x0000;
+ tms34061.regs[TMS34061_VERINT] = 0x0000;
+ tms34061.regs[TMS34061_CONTROL1] = 0x7000;
+ tms34061.regs[TMS34061_CONTROL2] = 0x0600;
+ tms34061.regs[TMS34061_STATUS] = 0x0000;
+ tms34061.regs[TMS34061_XYOFFSET] = 0x0010;
+ tms34061.regs[TMS34061_XYADDRESS] = 0x0000;
+ tms34061.regs[TMS34061_DISPADDRESS] = 0x0000;
+ tms34061.regs[TMS34061_VERCOUNTER] = 0x0000;
+
+ /* start vertical interrupt timer */
+ tms34061.timer = timer_alloc(tms34061_interrupt);
+}
+
+
+
+/*************************************
+ *
+ * Interrupt handling
+ *
+ *************************************/
+
+INLINE void update_interrupts(void)
+{
+ /* if we have a callback, process it */
+ if (tms34061.intf.interrupt)
+ {
+ /* if the status bit is set, and ints are enabled, turn it on */
+ if ((tms34061.regs[TMS34061_STATUS] & 0x0001) && (tms34061.regs[TMS34061_CONTROL1] & 0x0400))
+ (*tms34061.intf.interrupt)(ASSERT_LINE);
+ else
+ (*tms34061.intf.interrupt)(CLEAR_LINE);
+ }
+}
+
+
+static TIMER_CALLBACK( tms34061_interrupt )
+{
+ /* set timer for next frame */
+ timer_adjust(tms34061.timer, video_screen_get_frame_period(tms34061.intf.scrnum), 0, attotime_zero);
+
+ /* set the interrupt bit in the status reg */
+ tms34061.regs[TMS34061_STATUS] |= 1;
+
+ /* update the interrupt state */
+ update_interrupts();
+}
+
+
+
+/*************************************
+ *
+ * Register writes
+ *
+ *************************************/
+
+static WRITE8_HANDLER( register_w )
+{
+ int scanline;
+ int regnum = offset >> 2;
+
+ /* certain registers affect the display directly */
+ if ((regnum >= TMS34061_HORENDSYNC && regnum <= TMS34061_DISPSTART) ||
+ (regnum == TMS34061_CONTROL2))
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* store the hi/lo half */
+ if (offset & 0x02)
+ tms34061.regs[regnum] = (tms34061.regs[regnum] & 0x00ff) | (data << 8);
+ else
+ tms34061.regs[regnum] = (tms34061.regs[regnum] & 0xff00) | data;
+
+ /* log it */
+ if (VERBOSE) logerror("%04X:tms34061 %s = %04x\n", activecpu_get_pc(), regnames[regnum], tms34061.regs[regnum]);
+
+ /* update the state of things */
+ switch (regnum)
+ {
+ /* vertical interrupt: adjust the timer */
+ case TMS34061_VERINT:
+ scanline = tms34061.regs[TMS34061_VERINT] - tms34061.regs[TMS34061_VERENDBLNK];
+
+ if (scanline < 0)
+ scanline += tms34061.regs[TMS34061_VERTOTAL];
+
+ timer_adjust(tms34061.timer, video_screen_get_time_until_pos(tms34061.intf.scrnum, scanline, tms34061.regs[TMS34061_HORSTARTBLNK]), 0, attotime_zero);
+ break;
+
+ /* XY offset: set the X and Y masks */
+ case TMS34061_XYOFFSET:
+ switch (tms34061.regs[TMS34061_XYOFFSET] & 0x00ff)
+ {
+ case 0x01: tms34061.yshift = 2; break;
+ case 0x02: tms34061.yshift = 3; break;
+ case 0x04: tms34061.yshift = 4; break;
+ case 0x08: tms34061.yshift = 5; break;
+ case 0x10: tms34061.yshift = 6; break;
+ case 0x20: tms34061.yshift = 7; break;
+ case 0x40: tms34061.yshift = 8; break;
+ case 0x80: tms34061.yshift = 9; break;
+ default: logerror("Invalid value for XYOFFSET = %04x\n", tms34061.regs[TMS34061_XYOFFSET]); break;
+ }
+ tms34061.xmask = (1 << tms34061.yshift) - 1;
+ break;
+
+ /* CONTROL1: they could have turned interrupts on */
+ case TMS34061_CONTROL1:
+ update_interrupts();
+ break;
+
+ /* other supported registers */
+ case TMS34061_XYADDRESS:
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Register reads
+ *
+ *************************************/
+
+static READ8_HANDLER( register_r )
+{
+ int regnum = offset >> 2;
+ UINT16 result;
+
+ /* extract the correct portion of the register */
+ result = tms34061.regs[regnum];
+
+ /* special cases: */
+ switch (regnum)
+ {
+ /* status register: a read here clears it */
+ case TMS34061_STATUS:
+ tms34061.regs[TMS34061_STATUS] = 0;
+ update_interrupts();
+ break;
+
+ /* vertical count register: return the current scanline */
+ case TMS34061_VERCOUNTER:
+ result = (video_screen_get_vpos(0)+ tms34061.regs[TMS34061_VERENDBLNK]) % tms34061.regs[TMS34061_VERTOTAL];
+ break;
+ }
+
+ /* log it */
+ if (VERBOSE) logerror("%04X:tms34061 %s read = %04X\n", activecpu_get_pc(), regnames[regnum], result);
+ return (offset & 0x02) ? (result >> 8) : result;
+}
+
+
+
+/*************************************
+ *
+ * XY addressing
+ *
+ *************************************/
+
+INLINE void adjust_xyaddress(int offset)
+{
+ /* note that carries are allowed if the Y coordinate isn't being modified */
+ switch (offset & 0x1e)
+ {
+ case 0x00: /* no change */
+ break;
+
+ case 0x02: /* X + 1 */
+ tms34061.regs[TMS34061_XYADDRESS]++;
+ break;
+
+ case 0x04: /* X - 1 */
+ tms34061.regs[TMS34061_XYADDRESS]--;
+ break;
+
+ case 0x06: /* X = 0 */
+ tms34061.regs[TMS34061_XYADDRESS] &= ~tms34061.xmask;
+ break;
+
+ case 0x08: /* Y + 1 */
+ tms34061.regs[TMS34061_XYADDRESS] += 1 << tms34061.yshift;
+ break;
+
+ case 0x0a: /* X + 1, Y + 1 */
+ tms34061.regs[TMS34061_XYADDRESS] = (tms34061.regs[TMS34061_XYADDRESS] & ~tms34061.xmask) |
+ ((tms34061.regs[TMS34061_XYADDRESS] + 1) & tms34061.xmask);
+ tms34061.regs[TMS34061_XYADDRESS] += 1 << tms34061.yshift;
+ break;
+
+ case 0x0c: /* X - 1, Y + 1 */
+ tms34061.regs[TMS34061_XYADDRESS] = (tms34061.regs[TMS34061_XYADDRESS] & ~tms34061.xmask) |
+ ((tms34061.regs[TMS34061_XYADDRESS] - 1) & tms34061.xmask);
+ tms34061.regs[TMS34061_XYADDRESS] += 1 << tms34061.yshift;
+ break;
+
+ case 0x0e: /* X = 0, Y + 1 */
+ tms34061.regs[TMS34061_XYADDRESS] &= ~tms34061.xmask;
+ tms34061.regs[TMS34061_XYADDRESS] += 1 << tms34061.yshift;
+ break;
+
+ case 0x10: /* Y - 1 */
+ tms34061.regs[TMS34061_XYADDRESS] -= 1 << tms34061.yshift;
+ break;
+
+ case 0x12: /* X + 1, Y - 1 */
+ tms34061.regs[TMS34061_XYADDRESS] = (tms34061.regs[TMS34061_XYADDRESS] & ~tms34061.xmask) |
+ ((tms34061.regs[TMS34061_XYADDRESS] + 1) & tms34061.xmask);
+ tms34061.regs[TMS34061_XYADDRESS] -= 1 << tms34061.yshift;
+ break;
+
+ case 0x14: /* X - 1, Y - 1 */
+ tms34061.regs[TMS34061_XYADDRESS] = (tms34061.regs[TMS34061_XYADDRESS] & ~tms34061.xmask) |
+ ((tms34061.regs[TMS34061_XYADDRESS] - 1) & tms34061.xmask);
+ tms34061.regs[TMS34061_XYADDRESS] -= 1 << tms34061.yshift;
+ break;
+
+ case 0x16: /* X = 0, Y - 1 */
+ tms34061.regs[TMS34061_XYADDRESS] &= ~tms34061.xmask;
+ tms34061.regs[TMS34061_XYADDRESS] -= 1 << tms34061.yshift;
+ break;
+
+ case 0x18: /* Y = 0 */
+ tms34061.regs[TMS34061_XYADDRESS] &= tms34061.xmask;
+ break;
+
+ case 0x1a: /* X + 1, Y = 0 */
+ tms34061.regs[TMS34061_XYADDRESS]++;
+ tms34061.regs[TMS34061_XYADDRESS] &= tms34061.xmask;
+ break;
+
+ case 0x1c: /* X - 1, Y = 0 */
+ tms34061.regs[TMS34061_XYADDRESS]--;
+ tms34061.regs[TMS34061_XYADDRESS] &= tms34061.xmask;
+ break;
+
+ case 0x1e: /* X = 0, Y = 0 */
+ tms34061.regs[TMS34061_XYADDRESS] = 0;
+ break;
+ }
+}
+
+
+static WRITE8_HANDLER( xypixel_w )
+{
+ /* determine the offset, then adjust it */
+ offs_t pixeloffs = tms34061.regs[TMS34061_XYADDRESS];
+ if (offset)
+ adjust_xyaddress(offset);
+
+ /* adjust for the upper bits */
+ pixeloffs |= (tms34061.regs[TMS34061_XYOFFSET] & 0x0f00) << 8;
+
+ /* mask to the VRAM size */
+ pixeloffs &= tms34061.vrammask;
+
+ /* set the pixel data */
+ tms34061.vram[pixeloffs] = data;
+ tms34061.latchram[pixeloffs] = tms34061.latchdata;
+}
+
+
+static READ8_HANDLER( xypixel_r )
+{
+ /* determine the offset, then adjust it */
+ offs_t pixeloffs = tms34061.regs[TMS34061_XYADDRESS];
+ if (offset)
+ adjust_xyaddress(offset);
+
+ /* adjust for the upper bits */
+ pixeloffs |= (tms34061.regs[TMS34061_XYOFFSET] & 0x0f00) << 8;
+
+ /* mask to the VRAM size */
+ pixeloffs &= tms34061.vrammask;
+
+ /* return the result */
+ return tms34061.vram[pixeloffs];
+}
+
+
+
+/*************************************
+ *
+ * Core writes
+ *
+ *************************************/
+
+void tms34061_w(int col, int row, int func, UINT8 data)
+{
+ offs_t offs;
+
+ /* the function code determines what to do */
+ switch (func)
+ {
+ /* both 0 and 2 map to register access */
+ case 0:
+ case 2:
+ register_w(col, data);
+ break;
+
+ /* function 1 maps to XY access; col is the address adjustment */
+ case 1:
+ xypixel_w(col, data);
+ break;
+
+ /* function 3 maps to direct access */
+ case 3:
+ offs = ((row << tms34061.intf.rowshift) | col) & tms34061.vrammask;
+ if (tms34061.regs[TMS34061_CONTROL2] & 0x0040)
+ offs |= (tms34061.regs[TMS34061_CONTROL2] & 3) << 16;
+ if (tms34061.vram[offs] != data || tms34061.latchram[offs] != tms34061.latchdata)
+ {
+ tms34061.vram[offs] = data;
+ tms34061.latchram[offs] = tms34061.latchdata;
+ }
+ break;
+
+ /* function 4 performs a shift reg transfer to VRAM */
+ case 4:
+ offs = col << tms34061.intf.rowshift;
+ if (tms34061.regs[TMS34061_CONTROL2] & 0x0040)
+ offs |= (tms34061.regs[TMS34061_CONTROL2] & 3) << 16;
+ offs &= tms34061.vrammask;
+
+ memcpy(&tms34061.vram[offs], tms34061.shiftreg, (size_t)1 << tms34061.intf.rowshift);
+ memset(&tms34061.latchram[offs], tms34061.latchdata, (size_t)1 << tms34061.intf.rowshift);
+ break;
+
+ /* function 5 performs a shift reg transfer from VRAM */
+ case 5:
+ offs = col << tms34061.intf.rowshift;
+ if (tms34061.regs[TMS34061_CONTROL2] & 0x0040)
+ offs |= (tms34061.regs[TMS34061_CONTROL2] & 3) << 16;
+ offs &= tms34061.vrammask;
+
+ tms34061.shiftreg = &tms34061.vram[offs];
+ break;
+
+ /* log anything else */
+ default:
+ logerror("Unsupported TMS34061 function %d - PC: %04X\n", func, activecpu_get_pc());
+ break;
+ }
+}
+
+
+UINT8 tms34061_r(int col, int row, int func)
+{
+ int result = 0;
+ offs_t offs;
+
+ /* the function code determines what to do */
+ switch (func)
+ {
+ /* both 0 and 2 map to register access */
+ case 0:
+ case 2:
+ result = register_r(col);
+ break;
+
+ /* function 1 maps to XY access; col is the address adjustment */
+ case 1:
+ result = xypixel_r(col);
+ break;
+
+ /* funtion 3 maps to direct access */
+ case 3:
+ offs = ((row << tms34061.intf.rowshift) | col) & tms34061.vrammask;
+ result = tms34061.vram[offs];
+ break;
+
+ /* function 4 performs a shift reg transfer to VRAM */
+ case 4:
+ offs = col << tms34061.intf.rowshift;
+ if (tms34061.regs[TMS34061_CONTROL2] & 0x0040)
+ offs |= (tms34061.regs[TMS34061_CONTROL2] & 3) << 16;
+ offs &= tms34061.vrammask;
+
+ memcpy(&tms34061.vram[offs], tms34061.shiftreg, (size_t)1 << tms34061.intf.rowshift);
+ memset(&tms34061.latchram[offs], tms34061.latchdata, (size_t)1 << tms34061.intf.rowshift);
+ break;
+
+ /* function 5 performs a shift reg transfer from VRAM */
+ case 5:
+ offs = col << tms34061.intf.rowshift;
+ if (tms34061.regs[TMS34061_CONTROL2] & 0x0040)
+ offs |= (tms34061.regs[TMS34061_CONTROL2] & 3) << 16;
+ offs &= tms34061.vrammask;
+
+ tms34061.shiftreg = &tms34061.vram[offs];
+ break;
+
+ /* log anything else */
+ default:
+ logerror("Unsupported TMS34061 function %d - PC: %04X\n",
+ func, activecpu_get_pc());
+ break;
+ }
+
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Misc functions
+ *
+ *************************************/
+
+READ8_HANDLER( tms34061_latch_r )
+{
+ return tms34061.latchdata;
+}
+
+
+WRITE8_HANDLER( tms34061_latch_w )
+{
+ if (VERBOSE) logerror("tms34061_latch = %02X\n", data);
+ tms34061.latchdata = data;
+}
+
+
+void tms34061_get_display_state(struct tms34061_display *state)
+{
+ state->blanked = (~tms34061.regs[TMS34061_CONTROL2] >> 13) & 1;
+ state->vram = tms34061.vram;
+ state->latchram = tms34061.latchram;
+ state->regs = tms34061.regs;
+
+ /* compute the display start */
+ state->dispstart = (tms34061.regs[TMS34061_DISPSTART] << (tms34061.intf.rowshift - 2)) & tms34061.vrammask;
+}
diff --git a/src/emu/video/tms34061.h b/src/emu/video/tms34061.h
new file mode 100644
index 00000000000..9ff83a8eb6a
--- /dev/null
+++ b/src/emu/video/tms34061.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+ * *
+ * Function prototypes and constants used by the TMS34061 emulator *
+ * *
+ * Created by Zsolt Vasvari on 5/26/1998. *
+ * Updated by Aaron Giles on 11/21/2000. *
+ * *
+ ****************************************************************************/
+
+
+/* register constants */
+enum
+{
+ TMS34061_HORENDSYNC = 0,
+ TMS34061_HORENDBLNK,
+ TMS34061_HORSTARTBLNK,
+ TMS34061_HORTOTAL,
+ TMS34061_VERENDSYNC,
+ TMS34061_VERENDBLNK,
+ TMS34061_VERSTARTBLNK,
+ TMS34061_VERTOTAL,
+ TMS34061_DISPUPDATE,
+ TMS34061_DISPSTART,
+ TMS34061_VERINT,
+ TMS34061_CONTROL1,
+ TMS34061_CONTROL2,
+ TMS34061_STATUS,
+ TMS34061_XYOFFSET,
+ TMS34061_XYADDRESS,
+ TMS34061_DISPADDRESS,
+ TMS34061_VERCOUNTER,
+ TMS34061_REGCOUNT
+};
+
+
+
+/* interface structure */
+struct tms34061_interface
+{
+ int scrnum; /* the screen we are acting on */
+ UINT8 rowshift; /* VRAM address is (row << rowshift) | col */
+ UINT32 vramsize; /* size of video RAM */
+ void (*interrupt)(int state); /* interrupt gen callback */
+};
+
+
+/* display state structure */
+struct tms34061_display
+{
+ UINT8 blanked; /* true if blanked */
+ UINT8 * vram; /* base of VRAM */
+ UINT8 * latchram; /* base of latch RAM */
+ UINT16 * regs; /* pointer to array of registers */
+ offs_t dispstart; /* display start */
+};
+
+
+/* starts/stops the emulator */
+void tms34061_start(struct tms34061_interface *interface);
+
+/* reads/writes to the 34061 */
+UINT8 tms34061_r(int col, int row, int func);
+void tms34061_w(int col, int row, int func, UINT8 data);
+
+/* latch settings */
+READ8_HANDLER( tms34061_latch_r );
+WRITE8_HANDLER( tms34061_latch_w );
+
+/* video update handling */
+void tms34061_get_display_state(struct tms34061_display *state);
diff --git a/src/emu/video/tms9928a.c b/src/emu/video/tms9928a.c
new file mode 100644
index 00000000000..cf20b9d60ee
--- /dev/null
+++ b/src/emu/video/tms9928a.c
@@ -0,0 +1,809 @@
+/*
+** File: tms9928a.c -- software implementation of the Texas Instruments
+** TMS9918(A), TMS9928(A) and TMS9929(A), used by the Coleco, MSX and
+** TI99/4(A).
+**
+** All undocumented features as described in the following file
+** should be emulated.
+**
+** http://www.msxnet.org/tech/tms9918a.txt
+**
+** By Sean Young 1999 (sean@msxnet.org).
+** Based on code by Mike Balfour. Features added:
+** - read-ahead
+** - single read/write address
+** - AND mask for mode 2
+** - multicolor mode
+** - undocumented screen modes
+** - illegal sprites (max 4 on one line)
+** - vertical coordinate corrected -- was one to high (255 => 0, 0 => 1)
+** - errors in interrupt emulation
+** - back drop correctly emulated.
+**
+** 19 feb 2000, Sean:
+** - now uses plot _pixel (..), so -ror works properly
+** - fixed bug in tms.patternmask
+**
+** 3 nov 2000, Raphael Nabet:
+** - fixed a nasty bug in draw_sprites. A transparent sprite caused
+** sprites at lower levels not to be displayed, which is wrong.
+**
+** 3 jan 2001, Sean Young:
+** - A few minor cleanups
+** - Changed TMS9928A_vram_[rw] and TMS9928A_register_[rw] to READ8_HANDLER
+** and WRITE8_HANDLER.
+** - Got rid of the color table, unused. Also got rid of the old colors,
+** which were commented out anyway.
+**
+**
+** Todo:
+** - The screen image is rendered in `one go'. Modifications during
+** screen build up are not shown.
+** - Correctly emulate 4,8,16 kb VRAM if needed.
+** - uses plot _pixel (...) in TMS_sprites (...), which is rended in
+** in a back buffer created with malloc (). Hmm..
+** - Colours are incorrect. [fixed by R Nabet ?]
+*/
+
+#include "driver.h"
+#include "tms9928a.h"
+
+
+/*
+ New palette (R. Nabet).
+
+ First 3 columns from TI datasheet (in volts).
+ Next 3 columns based on formula :
+ Y = .299*R + .587*G + .114*B (NTSC)
+ (the coefficients are likely to be slightly different with PAL, but who cares ?)
+ I assumed the "zero" for R-Y and B-Y was 0.47V.
+ Last 3 coeffs are the 8-bit values.
+
+ Color Y R-Y B-Y R G B R G B
+ 0 Transparent
+ 1 Black 0.00 0.47 0.47 0.00 0.00 0.00 0 0 0
+ 2 Medium green 0.53 0.07 0.20 0.13 0.79 0.26 33 200 66
+ 3 Light green 0.67 0.17 0.27 0.37 0.86 0.47 94 220 120
+ 4 Dark blue 0.40 0.40 1.00 0.33 0.33 0.93 84 85 237
+ 5 Light blue 0.53 0.43 0.93 0.49 0.46 0.99 125 118 252
+ 6 Dark red 0.47 0.83 0.30 0.83 0.32 0.30 212 82 77
+ 7 Cyan 0.73 0.00 0.70 0.26 0.92 0.96 66 235 245
+ 8 Medium red 0.53 0.93 0.27 0.99 0.33 0.33 252 85 84
+ 9 Light red 0.67 0.93 0.27 1.13(!) 0.47 0.47 255 121 120
+ A Dark yellow 0.73 0.57 0.07 0.83 0.76 0.33 212 193 84
+ B Light yellow 0.80 0.57 0.17 0.90 0.81 0.50 230 206 128
+ C Dark green 0.47 0.13 0.23 0.13 0.69 0.23 33 176 59
+ D Magenta 0.53 0.73 0.67 0.79 0.36 0.73 201 91 186
+ E Gray 0.80 0.47 0.47 0.80 0.80 0.80 204 204 204
+ F White 1.00 0.47 0.47 1.00 1.00 1.00 255 255 255
+*/
+static const rgb_t TMS9928A_palette[16] =
+{
+ RGB_BLACK,
+ RGB_BLACK,
+ MAKE_RGB(33, 200, 66),
+ MAKE_RGB(94, 220, 120),
+ MAKE_RGB(84, 85, 237),
+ MAKE_RGB(125, 118, 252),
+ MAKE_RGB(212, 82, 77),
+ MAKE_RGB(66, 235, 245),
+ MAKE_RGB(252, 85, 84),
+ MAKE_RGB(255, 121, 120),
+ MAKE_RGB(212, 193, 84),
+ MAKE_RGB(230, 206, 128),
+ MAKE_RGB(33, 176, 59),
+ MAKE_RGB(201, 91, 186),
+ MAKE_RGB(204, 204, 204),
+ RGB_WHITE
+};
+
+/*
+** Forward declarations of internal functions.
+*/
+static void draw_mode0 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+static void draw_mode1 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+static void draw_mode2 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+static void draw_mode12 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+static void draw_mode3 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+static void draw_mode23 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+static void draw_modebogus (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+static void draw_sprites (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+static void change_register (int reg, UINT8 data);
+
+static void (*ModeHandlers[])(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) = {
+ draw_mode0, draw_mode1, draw_mode2, draw_mode12,
+ draw_mode3, draw_modebogus, draw_mode23,
+ draw_modebogus };
+
+#define IMAGE_SIZE (256*192) /* size of rendered image */
+
+#define LEFT_BORDER 15 /* a bit less for 9918a??? */
+#define RIGHT_BORDER 15 /* 13 for 9929a */
+#define TOP_BORDER_60HZ 27
+#define BOTTOM_BORDER_60HZ 24
+#define TOP_BORDER_50HZ 51 /* unknown (102 for top+bottom?) */
+#define BOTTOM_BORDER_50HZ 51 /* unknown (102 for top+bottom?) */
+#define TOP_BORDER tms.top_border
+#define BOTTOM_BORDER tms.bottom_border
+
+#define TMS_SPRITES_ENABLED ((tms.Regs[1] & 0x50) == 0x40)
+#define TMS_50HZ ((tms.model == TMS9929) || (tms.model == TMS9929A))
+#define TMS_REVA ((tms.model == TMS99x8A) || (tms.model == TMS9929A))
+#define TMS_MODE ( (TMS_REVA ? (tms.Regs[0] & 2) : 0) | \
+ ((tms.Regs[1] & 0x10)>>4) | ((tms.Regs[1] & 8)>>1))
+
+typedef struct {
+ /* TMS9928A internal settings */
+ UINT8 ReadAhead,Regs[8],StatusReg,FirstByte,latch,INT;
+ INT32 Addr;
+ int colour,pattern,nametbl,spriteattribute,spritepattern;
+ int colourmask,patternmask;
+ void (*INTCallback)(int);
+ /* memory */
+ UINT8 *vMem, *dBackMem;
+ mame_bitmap *tmpbmp;
+ int vramsize, model;
+ /* emulation settings */
+ int LimitSprites; /* max 4 sprites on a row, like original TMS9918A */
+ int top_border, bottom_border;
+ rectangle visarea;
+} TMS9928A;
+
+static TMS9928A tms;
+
+/*
+** initialize the palette
+*/
+static PALETTE_INIT( tms9928a )
+{
+ palette_set_colors(machine, 0, TMS9928A_palette, TMS9928A_PALETTE_SIZE);
+}
+
+
+/*
+** The init, reset and shutdown functions
+*/
+void TMS9928A_reset () {
+ int i;
+
+ for (i=0;i<8;i++) tms.Regs[i] = 0;
+ tms.StatusReg = 0;
+ tms.nametbl = tms.pattern = tms.colour = 0;
+ tms.spritepattern = tms.spriteattribute = 0;
+ tms.colourmask = tms.patternmask = 0;
+ tms.Addr = tms.ReadAhead = tms.INT = 0;
+ tms.FirstByte = 0;
+ tms.latch = 0;
+}
+
+static void TMS9928A_start (running_machine *machine, const TMS9928a_interface *intf)
+{
+ assert_always(((intf->vram == 0x1000) || (intf->vram == 0x2000) || (intf->vram == 0x4000)), "4, 8 or 16 kB vram please");
+
+ tms.model = intf->model;
+
+ tms.top_border = TMS_50HZ ? TOP_BORDER_50HZ : TOP_BORDER_60HZ;
+ tms.bottom_border = TMS_50HZ ? BOTTOM_BORDER_50HZ : BOTTOM_BORDER_60HZ;
+
+ tms.INTCallback = intf->int_callback;
+
+ /* determine the visible area */
+ tms.visarea.min_x = LEFT_BORDER - MIN(intf->borderx, LEFT_BORDER);
+ tms.visarea.max_x = LEFT_BORDER + 32*8 - 1 + MIN(intf->borderx, RIGHT_BORDER);
+ tms.visarea.min_y = tms.top_border - MIN(intf->bordery, tms.top_border);
+ tms.visarea.max_y = tms.top_border + 24*8 - 1 + MIN(intf->bordery, tms.bottom_border);
+
+ /* configure the screen if we weren't overridden */
+ if (machine->screen[0].width == LEFT_BORDER+32*8+RIGHT_BORDER && machine->screen[0].height == TOP_BORDER_60HZ+24*8+BOTTOM_BORDER_60HZ)
+ video_screen_configure(0, LEFT_BORDER + 32*8 + RIGHT_BORDER, tms.top_border + 24*8 + tms.bottom_border, &tms.visarea, machine->screen[0].refresh);
+
+ /* Video RAM */
+ tms.vramsize = intf->vram;
+ tms.vMem = (UINT8*) auto_malloc (intf->vram);
+ memset (tms.vMem, 0, intf->vram);
+
+ /* Sprite back buffer */
+ tms.dBackMem = (UINT8*)auto_malloc (IMAGE_SIZE);
+
+ /* back bitmap */
+ tms.tmpbmp = auto_bitmap_alloc (256, 192, machine->screen[0].format);
+
+ TMS9928A_reset ();
+ tms.LimitSprites = 1;
+
+ state_save_register_item("tms9928a", 0, tms.Regs[0]);
+ state_save_register_item("tms9928a", 0, tms.Regs[1]);
+ state_save_register_item("tms9928a", 0, tms.Regs[2]);
+ state_save_register_item("tms9928a", 0, tms.Regs[3]);
+ state_save_register_item("tms9928a", 0, tms.Regs[4]);
+ state_save_register_item("tms9928a", 0, tms.Regs[5]);
+ state_save_register_item("tms9928a", 0, tms.Regs[6]);
+ state_save_register_item("tms9928a", 0, tms.Regs[7]);
+ state_save_register_item("tms9928a", 0, tms.StatusReg);
+ state_save_register_item("tms9928a", 0, tms.ReadAhead);
+ state_save_register_item("tms9928a", 0, tms.FirstByte);
+ state_save_register_item("tms9928a", 0, tms.latch);
+ state_save_register_item("tms9928a", 0, tms.Addr);
+ state_save_register_item("tms9928a", 0, tms.INT);
+ state_save_register_item_pointer("tms9928a", 0, tms.vMem, intf->vram);
+}
+
+const rectangle *TMS9928A_get_visarea (void)
+{
+ return &tms.visarea;
+}
+
+
+void TMS9928A_post_load (void) {
+ int i;
+
+ /* all registers need to be re-written, so tables are recalculated */
+ for (i=0;i<8;i++)
+ change_register (i, tms.Regs[i]);
+
+ /* make sure the interrupt request is set properly */
+ if (tms.INTCallback) tms.INTCallback (tms.INT);
+}
+
+
+/*
+** The I/O functions.
+*/
+READ8_HANDLER (TMS9928A_vram_r) {
+ UINT8 b;
+ b = tms.ReadAhead;
+ tms.ReadAhead = tms.vMem[tms.Addr];
+ tms.Addr = (tms.Addr + 1) & (tms.vramsize - 1);
+ tms.latch = 0;
+ return b;
+}
+
+WRITE8_HANDLER (TMS9928A_vram_w) {
+
+ tms.vMem[tms.Addr] = data;
+ tms.Addr = (tms.Addr + 1) & (tms.vramsize - 1);
+ tms.ReadAhead = data;
+ tms.latch = 0;
+}
+
+READ8_HANDLER (TMS9928A_register_r) {
+ UINT8 b;
+ b = tms.StatusReg;
+ tms.StatusReg = 0x1f;
+ if (tms.INT) {
+ tms.INT = 0;
+ if (tms.INTCallback) tms.INTCallback (tms.INT);
+ }
+ tms.latch = 0;
+ return b;
+}
+
+WRITE8_HANDLER (TMS9928A_register_w) {
+ int reg;
+
+ if (tms.latch) {
+ if (data & 0x80) {
+ /* register write */
+ reg = data & 7;
+ /*if (tms.FirstByte != tms.Regs[reg])*/ /* Removed to fix ColecoVision MESS Driver*/
+ change_register (reg, tms.FirstByte);
+ } else {
+ /* set read/write address */
+ tms.Addr = ((UINT16)data << 8 | tms.FirstByte) & (tms.vramsize - 1);
+ if ( !(data & 0x40) ) {
+ /* read ahead */
+ TMS9928A_vram_r (0);
+ }
+ }
+ tms.latch = 0;
+ } else {
+ tms.FirstByte = data;
+ tms.latch = 1;
+ }
+}
+
+static void change_register (int reg, UINT8 val) {
+ static const UINT8 Mask[8] =
+ { 0x03, 0xfb, 0x0f, 0xff, 0x07, 0x7f, 0x07, 0xff };
+ static const char *modes[] = {
+ "Mode 0 (GRAPHIC 1)", "Mode 1 (TEXT 1)", "Mode 2 (GRAPHIC 2)",
+ "Mode 1+2 (TEXT 1 variation)", "Mode 3 (MULTICOLOR)",
+ "Mode 1+3 (BOGUS)", "Mode 2+3 (MULTICOLOR variation)",
+ "Mode 1+2+3 (BOGUS)" };
+ UINT8 b;
+
+ val &= Mask[reg];
+ tms.Regs[reg] = val;
+
+ logerror("TMS9928A: Reg %d = %02xh\n", reg, (int)val);
+ switch (reg) {
+ case 0:
+ /* re-calculate masks and pattern generator & colour */
+ if (val & 2) {
+ tms.colour = ((tms.Regs[3] & 0x80) * 64) & (tms.vramsize - 1);
+ tms.colourmask = (tms.Regs[3] & 0x7f) * 8 | 7;
+ tms.pattern = ((tms.Regs[4] & 4) * 2048) & (tms.vramsize - 1);
+ tms.patternmask = (tms.Regs[4] & 3) * 256 |
+ (tms.colourmask & 255);
+ } else {
+ tms.colour = (tms.Regs[3] * 64) & (tms.vramsize - 1);
+ tms.pattern = (tms.Regs[4] * 2048) & (tms.vramsize - 1);
+ }
+ logerror("TMS9928A: %s\n", modes[TMS_MODE]);
+ break;
+ case 1:
+ /* check for changes in the INT line */
+ b = (val & 0x20) && (tms.StatusReg & 0x80) ;
+ if (b != tms.INT) {
+ tms.INT = b;
+ if (tms.INTCallback) tms.INTCallback (tms.INT);
+ }
+ logerror("TMS9928A: %s\n", modes[TMS_MODE]);
+ break;
+ case 2:
+ tms.nametbl = (val * 1024) & (tms.vramsize - 1);
+ break;
+ case 3:
+ if (tms.Regs[0] & 2) {
+ tms.colour = ((val & 0x80) * 64) & (tms.vramsize - 1);
+ tms.colourmask = (val & 0x7f) * 8 | 7;
+ } else {
+ tms.colour = (val * 64) & (tms.vramsize - 1);
+ }
+ tms.patternmask = (tms.Regs[4] & 3) * 256 | (tms.colourmask & 255);
+ break;
+ case 4:
+ if (tms.Regs[0] & 2) {
+ tms.pattern = ((val & 4) * 2048) & (tms.vramsize - 1);
+ tms.patternmask = (val & 3) * 256 | 255;
+ } else {
+ tms.pattern = (val * 2048) & (tms.vramsize - 1);
+ }
+ break;
+ case 5:
+ tms.spriteattribute = (val * 128) & (tms.vramsize - 1);
+ break;
+ case 6:
+ tms.spritepattern = (val * 2048) & (tms.vramsize - 1);
+ break;
+ case 7:
+ /* The backdrop is updated at TMS9928A_refresh() */
+ break;
+ }
+}
+
+/*
+** Interface functions
+*/
+
+/*void TMS9928A_int_callback (void (*callback)(int)) {
+ tms.INTCallback = callback;
+}*/
+
+void TMS9928A_set_spriteslimit (int limit) {
+ tms.LimitSprites = limit;
+}
+
+/*
+** Updates the screen (the dMem memory area).
+*/
+VIDEO_UPDATE( tms9928a )
+{
+ INT32 BackColour = tms.Regs[7] & 15; if (!BackColour) BackColour=1;
+ palette_set_color(machine, 0, TMS9928A_palette[BackColour]);
+
+ if (! (tms.Regs[1] & 0x40))
+ fillbitmap(bitmap, machine->pens[BackColour], cliprect);
+ else
+ {
+ (*ModeHandlers[TMS_MODE])(machine, tms.tmpbmp, cliprect);
+
+ copybitmap(bitmap, tms.tmpbmp, 0, 0, LEFT_BORDER, TOP_BORDER, cliprect, TRANSPARENCY_NONE, 0);
+ {
+ rectangle rt;
+
+ /* set borders */
+ rt.min_x = 0; rt.max_x = LEFT_BORDER+256+RIGHT_BORDER-1;
+ rt.min_y = 0; rt.max_y = TOP_BORDER-1;
+ fillbitmap (bitmap, BackColour, &rt);
+ rt.min_y = TOP_BORDER+192; rt.max_y = TOP_BORDER+192+BOTTOM_BORDER-1;
+ fillbitmap (bitmap, BackColour, &rt);
+
+ rt.min_y = TOP_BORDER; rt.max_y = TOP_BORDER+192-1;
+ rt.min_x = 0; rt.max_x = LEFT_BORDER-1;
+ fillbitmap (bitmap, BackColour, &rt);
+ rt.min_x = LEFT_BORDER+256; rt.max_x = LEFT_BORDER+256+RIGHT_BORDER-1;
+ fillbitmap (bitmap, BackColour, &rt);
+ }
+ if (TMS_SPRITES_ENABLED)
+ draw_sprites(machine, bitmap, cliprect);
+ }
+
+ return 0;
+}
+
+int TMS9928A_interrupt () {
+ int b;
+
+ /* when skipping frames, calculate sprite collision */
+ if (video_skip_this_frame() ) {
+ if (TMS_SPRITES_ENABLED) {
+ draw_sprites (NULL, NULL, NULL);
+ }
+ }
+
+ tms.StatusReg |= 0x80;
+ b = (tms.Regs[1] & 0x20) != 0;
+ if (b != tms.INT) {
+ tms.INT = b;
+ if (tms.INTCallback) tms.INTCallback (tms.INT);
+ }
+
+ return b;
+}
+
+static void draw_mode1 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) {
+ int pattern,x,y,yy,xx,name,charcode;
+ UINT8 fg,bg,*patternptr;
+ rectangle rt;
+
+ fg = machine->pens[tms.Regs[7] / 16];
+ bg = machine->pens[tms.Regs[7] & 15];
+
+ /* colours at sides must be reset */
+ rt.min_y = 0; rt.max_y = 191;
+ rt.min_x = 0; rt.max_x = 7;
+ fillbitmap (bitmap, bg, &rt);
+ rt.min_y = 0; rt.max_y = 191;
+ rt.min_x = 248; rt.max_x = 255;
+ fillbitmap (bitmap, bg, &rt);
+
+ name = 0;
+ for (y=0;y<24;y++) {
+ for (x=0;x<40;x++) {
+ charcode = tms.vMem[tms.nametbl+name];
+ name++;
+ patternptr = tms.vMem + tms.pattern + (charcode*8);
+ for (yy=0;yy<8;yy++) {
+ pattern = *patternptr++;
+ for (xx=0;xx<6;xx++) {
+ *BITMAP_ADDR16(bitmap, y*8+yy, 8+x*6+xx) = (pattern & 0x80) ? fg : bg;
+ pattern *= 2;
+ }
+ }
+ }
+ }
+}
+
+static void draw_mode12 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) {
+ int pattern,x,y,yy,xx,name,charcode;
+ UINT8 fg,bg,*patternptr;
+ rectangle rt;
+
+ fg = machine->pens[tms.Regs[7] / 16];
+ bg = machine->pens[tms.Regs[7] & 15];
+
+ /* colours at sides must be reset */
+ rt.min_y = 0; rt.max_y = 191;
+ rt.min_x = 0; rt.max_x = 7;
+ fillbitmap (bitmap, bg, &rt);
+ rt.min_y = 0; rt.max_y = 191;
+ rt.min_x = 248; rt.max_x = 255;
+ fillbitmap (bitmap, bg, &rt);
+
+ name = 0;
+ for (y=0;y<24;y++) {
+ for (x=0;x<40;x++) {
+ charcode = (tms.vMem[tms.nametbl+name]+(y/8)*256)&tms.patternmask;
+ name++;
+ patternptr = tms.vMem + tms.pattern + (charcode*8);
+ for (yy=0;yy<8;yy++) {
+ pattern = *patternptr++;
+ for (xx=0;xx<6;xx++) {
+ *BITMAP_ADDR16(bitmap, y*8+yy, 8+x*6+xx) = (pattern & 0x80) ? fg : bg;
+ pattern *= 2;
+ }
+ }
+ }
+ }
+}
+
+static void draw_mode0 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) {
+ int pattern,x,y,yy,xx,name,charcode,colour;
+ UINT8 fg,bg,*patternptr;
+
+ name = 0;
+ for (y=0;y<24;y++) {
+ for (x=0;x<32;x++) {
+ charcode = tms.vMem[tms.nametbl+name];
+ name++;
+ patternptr = tms.vMem + tms.pattern + charcode*8;
+ colour = tms.vMem[tms.colour+charcode/8];
+ fg = machine->pens[colour / 16];
+ bg = machine->pens[colour & 15];
+ for (yy=0;yy<8;yy++) {
+ pattern=*patternptr++;
+ for (xx=0;xx<8;xx++) {
+ *BITMAP_ADDR16(bitmap, y*8+yy, x*8+xx) = (pattern & 0x80) ? fg : bg;
+ pattern *= 2;
+ }
+ }
+ }
+ }
+}
+
+static void draw_mode2 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) {
+ int colour,name,x,y,yy,pattern,xx,charcode;
+ UINT8 fg,bg;
+ UINT8 *colourptr,*patternptr;
+
+ name = 0;
+ for (y=0;y<24;y++) {
+ for (x=0;x<32;x++) {
+ charcode = tms.vMem[tms.nametbl+name]+(y/8)*256;
+ name++;
+ colour = (charcode&tms.colourmask);
+ pattern = (charcode&tms.patternmask);
+ patternptr = tms.vMem+tms.pattern+colour*8;
+ colourptr = tms.vMem+tms.colour+pattern*8;
+ for (yy=0;yy<8;yy++) {
+ pattern = *patternptr++;
+ colour = *colourptr++;
+ fg = machine->pens[colour / 16];
+ bg = machine->pens[colour & 15];
+ for (xx=0;xx<8;xx++) {
+ *BITMAP_ADDR16(bitmap, y*8+yy, x*8+xx) = (pattern & 0x80) ? fg : bg;
+ pattern *= 2;
+ }
+ }
+ }
+ }
+}
+
+static void draw_mode3 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) {
+ int x,y,yy,yyy,name,charcode;
+ UINT8 fg,bg,*patternptr;
+
+ name = 0;
+ for (y=0;y<24;y++) {
+ for (x=0;x<32;x++) {
+ charcode = tms.vMem[tms.nametbl+name];
+ name++;
+ patternptr = tms.vMem+tms.pattern+charcode*8+(y&3)*2;
+ for (yy=0;yy<2;yy++) {
+ fg = machine->pens[(*patternptr / 16)];
+ bg = machine->pens[((*patternptr++) & 15)];
+ for (yyy=0;yyy<4;yyy++) {
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+0) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+1) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+2) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+3) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+4) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+5) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+6) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+7) = fg;
+ }
+ }
+ }
+ }
+}
+
+static void draw_mode23 (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) {
+ int x,y,yy,yyy,name,charcode;
+ UINT8 fg,bg,*patternptr;
+
+ name = 0;
+ for (y=0;y<24;y++) {
+ for (x=0;x<32;x++) {
+ charcode = tms.vMem[tms.nametbl+name];
+ name++;
+ patternptr = tms.vMem + tms.pattern +
+ ((charcode+(y&3)*2+(y/8)*256)&tms.patternmask)*8;
+ for (yy=0;yy<2;yy++) {
+ fg = machine->pens[(*patternptr / 16)];
+ bg = machine->pens[((*patternptr++) & 15)];
+ for (yyy=0;yyy<4;yyy++) {
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+0) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+1) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+2) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+3) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+4) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+5) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+6) = fg;
+ *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+7) = fg;
+ }
+ }
+ }
+ }
+}
+
+static void draw_modebogus (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) {
+ UINT8 fg,bg;
+ int x,y,n,xx;
+
+ fg = machine->pens[tms.Regs[7] / 16];
+ bg = machine->pens[tms.Regs[7] & 15];
+
+ for (y=0;y<192;y++) {
+ xx=0;
+ n=8; while (n--) *BITMAP_ADDR16(bitmap, y, xx++) = bg;
+ for (x=0;x<40;x++) {
+ n=4; while (n--) *BITMAP_ADDR16(bitmap, y, xx++) = fg;
+ n=2; while (n--) *BITMAP_ADDR16(bitmap, y, xx++) = bg;
+ }
+ n=8; while (n--) *BITMAP_ADDR16(bitmap, y, xx++) = bg;
+ }
+}
+
+/*
+** This function renders the sprites. Sprite collision is calculated in
+** in a back buffer (tms.dBackMem), because sprite collision detection
+** is rather complicated (transparent sprites also cause the sprite
+** collision bit to be set, and ``illegal'' sprites do not count
+** (they're not displayed)).
+**
+** This code should be optimized. One day.
+*/
+static void draw_sprites (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) {
+ UINT8 *attributeptr,*patternptr,c;
+ int p,x,y,size,i,j,large,yy,xx,limit[192],
+ illegalsprite,illegalspriteline;
+ UINT16 line,line2;
+
+ attributeptr = tms.vMem + tms.spriteattribute;
+ size = (tms.Regs[1] & 2) ? 16 : 8;
+ large = (int)(tms.Regs[1] & 1);
+
+ for (x=0;x<192;x++) limit[x] = 4;
+ tms.StatusReg = 0x80;
+ illegalspriteline = 255;
+ illegalsprite = 0;
+
+ memset (tms.dBackMem, 0, IMAGE_SIZE);
+ for (p=0;p<32;p++) {
+ y = *attributeptr++;
+ if (y == 208) break;
+ if (y > 208) {
+ y=-(~y&255);
+ } else {
+ y++;
+ }
+ x = *attributeptr++;
+ patternptr = tms.vMem + tms.spritepattern +
+ ((size == 16) ? *attributeptr & 0xfc : *attributeptr) * 8;
+ attributeptr++;
+ c = (*attributeptr & 0x0f);
+ if (*attributeptr & 0x80) x -= 32;
+ attributeptr++;
+
+ if (!large) {
+ /* draw sprite (not enlarged) */
+ for (yy=y;yy<(y+size);yy++) {
+ if ( (yy < 0) || (yy > 191) ) continue;
+ if (limit[yy] == 0) {
+ /* illegal sprite line */
+ if (yy < illegalspriteline) {
+ illegalspriteline = yy;
+ illegalsprite = p;
+ } else if (illegalspriteline == yy) {
+ if (illegalsprite > p) {
+ illegalsprite = p;
+ }
+ }
+ if (tms.LimitSprites) continue;
+ } else limit[yy]--;
+ line = 256*patternptr[yy-y] + patternptr[yy-y+16];
+ for (xx=x;xx<(x+size);xx++) {
+ if (line & 0x8000) {
+ if ((xx >= 0) && (xx < 256)) {
+ if (tms.dBackMem[yy*256+xx]) {
+ tms.StatusReg |= 0x20;
+ } else {
+ tms.dBackMem[yy*256+xx] = 0x01;
+ }
+ if (c && ! (tms.dBackMem[yy*256+xx] & 0x02))
+ {
+ tms.dBackMem[yy*256+xx] |= 0x02;
+ if (bitmap)
+ *BITMAP_ADDR16(bitmap, TOP_BORDER+yy, LEFT_BORDER+xx) = machine->pens[c];
+ }
+ }
+ }
+ line *= 2;
+ }
+ }
+ } else {
+ /* draw enlarged sprite */
+ for (i=0;i<size;i++) {
+ yy=y+i*2;
+ line2 = 256*patternptr[i] + patternptr[i+16];
+ for (j=0;j<2;j++) {
+ if ( (yy >= 0) && (yy <= 191) ) {
+ if (limit[yy] == 0) {
+ /* illegal sprite line */
+ if (yy < illegalspriteline) {
+ illegalspriteline = yy;
+ illegalsprite = p;
+ } else if (illegalspriteline == yy) {
+ if (illegalsprite > p) {
+ illegalsprite = p;
+ }
+ }
+ if (tms.LimitSprites) continue;
+ } else limit[yy]--;
+ line = line2;
+ for (xx=x;xx<(x+size*2);xx+=2) {
+ if (line & 0x8000) {
+ if ((xx >=0) && (xx < 256)) {
+ if (tms.dBackMem[yy*256+xx]) {
+ tms.StatusReg |= 0x20;
+ } else {
+ tms.dBackMem[yy*256+xx] = 0x01;
+ }
+ if (c && ! (tms.dBackMem[yy*256+xx] & 0x02))
+ {
+ tms.dBackMem[yy*256+xx] |= 0x02;
+ if (bitmap)
+ *BITMAP_ADDR16(bitmap, TOP_BORDER+yy, LEFT_BORDER+xx) = machine->pens[c];
+ }
+ }
+ if (((xx+1) >=0) && ((xx+1) < 256)) {
+ if (tms.dBackMem[yy*256+xx+1]) {
+ tms.StatusReg |= 0x20;
+ } else {
+ tms.dBackMem[yy*256+xx+1] = 0x01;
+ }
+ if (c && ! (tms.dBackMem[yy*256+xx+1] & 0x02))
+ {
+ tms.dBackMem[yy*256+xx+1] |= 0x02;
+ if (bitmap)
+ *BITMAP_ADDR16(bitmap, TOP_BORDER+yy, LEFT_BORDER+xx+1) = machine->pens[c];
+ }
+ }
+ }
+ line *= 2;
+ }
+ }
+ yy++;
+ }
+ }
+ }
+ }
+ if (illegalspriteline == 255) {
+ tms.StatusReg |= (p > 31) ? 31 : p;
+ } else {
+ tms.StatusReg |= 0x40 + illegalsprite;
+ }
+}
+
+static TMS9928a_interface sIntf;
+
+
+void TMS9928A_configure (const TMS9928a_interface *intf)
+{
+ sIntf = *intf;
+}
+
+
+VIDEO_START( tms9928a )
+{
+ assert(sIntf.model != TMS_INVALID_MODEL);
+ TMS9928A_start(machine, &sIntf);
+}
+
+
+MACHINE_DRIVER_START( tms9928a )
+
+ /* video hardware */
+ MDRV_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK | VIDEO_TYPE_RASTER)
+ MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
+ MDRV_SCREEN_SIZE(LEFT_BORDER+32*8+RIGHT_BORDER, TOP_BORDER_60HZ+24*8+BOTTOM_BORDER_60HZ)
+ MDRV_SCREEN_VISIBLE_AREA(LEFT_BORDER-12, LEFT_BORDER+32*8+12-1, TOP_BORDER_60HZ-9, TOP_BORDER_60HZ+24*8+9-1)
+
+ MDRV_PALETTE_LENGTH(TMS9928A_PALETTE_SIZE)
+ MDRV_PALETTE_INIT(tms9928a)
+
+ MDRV_VIDEO_START(tms9928a)
+ MDRV_VIDEO_UPDATE(tms9928a)
+MACHINE_DRIVER_END
+
diff --git a/src/emu/video/tms9928a.h b/src/emu/video/tms9928a.h
new file mode 100644
index 00000000000..9b9b0e407e4
--- /dev/null
+++ b/src/emu/video/tms9928a.h
@@ -0,0 +1,88 @@
+/*
+** File: tms9928a.h -- software implementation of the TMS9928A VDP.
+**
+** By Sean Young 1999 (sean@msxnet.org).
+*/
+
+
+#define TMS9928A_PALETTE_SIZE 16
+
+/*
+** The different models
+*/
+typedef enum
+{
+ TMS_INVALID_MODEL,
+ TMS99x8,
+ TMS9929,
+ TMS99x8A,
+ TMS9929A
+} tms9928a_model;
+
+/*
+** MachineDriver video declarations for the TMS9928A chip
+*/
+typedef struct TMS9928a_interface
+{
+ tms9928a_model model; /* model: tms9929(a) runs at 50Hz instead of 60Hz */
+ int vram; /* VRAM size in bytes (4k, 8k or 16k) */
+ int borderx, bordery; /* number of border pixels to show in each direction */
+ void (*int_callback)(int); /* callback which is called whenever the state
+ ** of the INT output of the TMS9918A changes (may be NULL)*/
+} TMS9928a_interface;
+
+/*
+** configuration function
+*/
+extern void TMS9928A_configure (const TMS9928a_interface *intf);
+
+/*
+** visible area query
+*/
+extern const rectangle *TMS9928A_get_visarea (void);
+
+/*
+** reset function
+*/
+extern void TMS9928A_reset (void);
+
+/*
+** The I/O functions
+*/
+extern READ8_HANDLER (TMS9928A_vram_r);
+extern WRITE8_HANDLER (TMS9928A_vram_w);
+extern READ8_HANDLER (TMS9928A_register_r);
+extern WRITE8_HANDLER (TMS9928A_register_w);
+
+/*
+** Call this function to render the screen.
+*/
+extern VIDEO_START( tms9928a );
+extern VIDEO_UPDATE( tms9928a );
+
+/*
+** This next function must be called 50 (tms9929a) or 60 (tms99x8a) times per second,
+** to generate the necessary interrupts
+*/
+int TMS9928A_interrupt (void);
+
+/*
+** The parameter is a function pointer. This function is called whenever
+** the state of the INT output of the TMS9918A changes.
+*/
+/*void TMS9928A_int_callback (void (*callback)(int));*/
+
+/*
+** Set display of illegal sprites on or off
+*/
+void TMS9928A_set_spriteslimit (int);
+
+/*
+** After loading a state, call this function
+*/
+void TMS9928A_post_load (void);
+
+/*
+** MachineDriver video declarations for the TMS9928A chip
+*/
+MACHINE_DRIVER_EXTERN( tms9928a );
diff --git a/src/emu/video/v9938.c b/src/emu/video/v9938.c
new file mode 100644
index 00000000000..1a239f982db
--- /dev/null
+++ b/src/emu/video/v9938.c
@@ -0,0 +1,2428 @@
+
+/***************************************************************************
+
+ v9938 / v9958 emulation
+
+***************************************************************************/
+
+/*
+ todo:
+
+ - sprite collision
+ - vdp engine -- make run at correct speed
+ - vr/hr/fh flags: double-check all of that
+ - make vdp engine work in exp. ram
+*/
+
+#include "driver.h"
+#include "v9938.h"
+
+typedef struct {
+ /* general */
+ int model;
+ int offset_x, offset_y, visible_y, mode;
+ /* palette */
+ int pal_write_first, cmd_write_first;
+ UINT8 pal_write, cmd_write;
+ UINT8 palReg[32], statReg[10], contReg[48], read_ahead;
+ /* memory */
+ UINT16 address_latch;
+ UINT8 *vram, *vram_exp;
+ int vram_size;
+ /* interrupt */
+ UINT8 INT;
+ void (*INTCallback)(int);
+ int scanline;
+ /* blinking */
+ int blink, blink_count;
+ /* sprites */
+ int sprite_limit;
+ /* size */
+ int size, size_old, size_auto, size_now;
+ /* mouse */
+ UINT8 mx_delta, my_delta;
+ /* mouse & lightpen */
+ UINT8 button_state;
+} V9938;
+
+static V9938 vdp;
+
+static UINT16 pal_ind16[16], pal_ind256[256], *pal_indYJK;
+
+#define V9938_MODE_TEXT1 (0)
+#define V9938_MODE_MULTI (1)
+#define V9938_MODE_GRAPHIC1 (2)
+#define V9938_MODE_GRAPHIC2 (3)
+#define V9938_MODE_GRAPHIC3 (4)
+#define V9938_MODE_GRAPHIC4 (5)
+#define V9938_MODE_GRAPHIC5 (6)
+#define V9938_MODE_GRAPHIC6 (7)
+#define V9938_MODE_GRAPHIC7 (8)
+#define V9938_MODE_TEXT2 (9)
+#define V9938_MODE_UNKNOWN (10)
+
+
+static const char *v9938_modes[] = {
+ "TEXT 1", "MULTICOLOR", "GRAPHIC 1", "GRAPHIC 2", "GRAPHIC 3",
+ "GRAPHIC 4", "GRAPHIC 5", "GRAPHIC 6", "GRAPHIC 7", "TEXT 2",
+ "UNKNOWN" };
+
+static void v9938_register_write (int reg, int data);
+static void v9938_update_command (void);
+static void v9938_cpu_to_vdp (UINT8 V);
+static UINT8 v9938_command_unit_w (UINT8 Op);
+static UINT8 v9938_vdp_to_cpu (void);
+static void v9938_set_mode (void);
+static void v9938_refresh_line (mame_bitmap *bmp, int line);
+
+/***************************************************************************
+
+ Palette functions
+
+***************************************************************************/
+
+/*
+About the colour burst registers:
+
+The color burst registers will only have effect on the composite video outputfrom
+the V9938. but the output is only NTSC (Never The Same Color ,so the
+effects are already present) . this system is not used in europe
+the european machines use a separate PAL (Phase Alternating Line) encoder
+or no encoder at all , only RGB output.
+
+Erik de Boer.
+
+--
+Right now they're not emulated. For completeness sake they should -- with
+a dip-switch to turn them off. I really don't know how they work though. :(
+*/
+
+/*
+ In screen 8, the colors are encoded as:
+
+ 7 6 5 4 3 2 1 0
++--+--+--+--+--+--+--+--+
+|g2|g1|g0|r2|r1|r0|b2|b1|
++--+--+--+--+--+--+--+--+
+
+b0 is set if b2 and b1 are set (remember, color bus is 3 bits)
+
+*/
+
+PALETTE_INIT( v9938 )
+{
+ int i;
+
+ /* create the full 512 colour palette */
+ for (i=0;i<512;i++)
+ palette_set_color_rgb(machine, i, pal3bit(i >> 6), pal3bit(i >> 3), pal3bit(i >> 0));
+}
+
+/*
+
+The v9958 can display up to 19286 colours. For this we need a larger palette.
+
+The colours are encoded in 17 bits; however there are just 19268 different colours.
+Here we calculate the palette and a 2^17 reference table to the palette,
+which is: pal_indYJK. It's 256K in size, but I can't think of a faster way
+to emulate this. Also it keeps the palette a reasonable size. :)
+
+*/
+
+PALETTE_INIT( v9958 )
+{
+ int r,g,b,y,j,k,i,k0,j0,n;
+ UINT8 pal[19268*3];
+
+ /* init v9938 512-color palette */
+ palette_init_v9938(machine, colortable, color_prom);
+
+ /* set up YJK table */
+ pal_indYJK = auto_malloc(0x20000 * sizeof(UINT16));
+
+ logerror ("Building YJK table for V9958 screens, may take a while ... \n");
+ i = 0;
+ for (y=0;y<32;y++) for (k=0;k<64;k++) for (j=0;j<64;j++)
+ {
+ /* calculate the color */
+ if (k >= 32) k0 = (k - 64); else k0 = k;
+ if (j >= 32) j0 = (j - 64); else j0 = j;
+ r = y + j0;
+ b = (y * 5 - 2 * j0 - k0) / 4;
+ g = y + k0;
+ if (r < 0) r = 0; else if (r > 31) r = 31;
+ if (g < 0) g = 0; else if (g > 31) g = 31;
+ if (b < 0) b = 0; else if (b > 31) b = 31;
+
+ r = (r << 3) | (r >> 2);
+ b = (b << 3) | (b >> 2);
+ g = (g << 3) | (g >> 2);
+ /* have we seen this one before? */
+ n = 0;
+ while (n < i)
+ {
+ if (pal[n*3+0] == r && pal[n*3+1] == g && pal[n*3+2] == b)
+ {
+ pal_indYJK[y | j << 5 | k << (5 + 6)] = n + 512;
+ break;
+ }
+ n++;
+ }
+
+ if (i == n)
+ {
+ /* so we haven't; add it */
+ pal[i*3+0] = r;
+ pal[i*3+1] = g;
+ pal[i*3+2] = b;
+ palette_set_color(machine, i+512, MAKE_RGB(r, g, b));
+ pal_indYJK[y | j << 5 | k << (5 + 6)] = i + 512;
+ i++;
+ }
+ }
+
+ if (i != 19268)
+ logerror ("Table creation failed - %d colours out of 19286 created\n", i);
+}
+
+/*
+
+ so lookups for screen 12 will look like:
+
+ int ind;
+
+ ind = (*data & 7) << 11 | (*(data + 1) & 7) << 14 |
+ (*(data + 2) & 7) << 5 | (*(data + 3) & 7) << 8;
+
+ pixel0 = pal_indYJK[ind | (*data >> 3) & 31];
+ pixel1 = pal_indYJK[ind | (*(data + 1) >> 3) & 31];
+ pixel2 = pal_indYJK[ind | (*(data + 2) >> 3) & 31];
+ pixel3 = pal_indYJK[ind | (*(data + 3) >> 3) & 31];
+
+and for screen 11:
+
+pixel0 = (*data) & 8 ? pal_ind16[(*data) >> 4] : pal_indYJK[ind | (*data >> 3) & 30];
+pixel1 = *(data+1) & 8 ? pal_ind16[*(data+1) >> 4] : pal_indYJK[ind | *(data+1) >> 3) & 30];
+pixel2 = *(data+2) & 8 ? pal_ind16[*(data+2) >> 4] : pal_indYJK[ind | *(data+2) >> 3) & 30];
+pixel3 = *(data+3) & 8 ? pal_ind16[*(data+3) >> 4] : pal_indYJK[ind | *(data+3) >> 3) & 30];
+
+*/
+
+WRITE8_HANDLER (v9938_palette_w)
+ {
+ int indexp;
+
+ if (vdp.pal_write_first)
+ {
+ /* store in register */
+ indexp = vdp.contReg[0x10] & 15;
+ vdp.palReg[indexp*2] = vdp.pal_write & 0x77;
+ vdp.palReg[indexp*2+1] = data & 0x07;
+ /* update palette */
+ pal_ind16[indexp] = (((int)vdp.pal_write << 2) & 0x01c0) |
+ (((int)data << 3) & 0x0038) |
+ ((int)vdp.pal_write & 0x0007);
+
+ vdp.contReg[0x10] = (vdp.contReg[0x10] + 1) & 15;
+ vdp.pal_write_first = 0;
+ }
+ else
+ {
+ vdp.pal_write = data;
+ vdp.pal_write_first = 1;
+ }
+ }
+
+static void v9938_reset_palette (void)
+ {
+ /* taken from V9938 Technical Data book, page 148. it's in G-R-B format */
+ static const UINT8 pal16[16*3] = {
+ 0, 0, 0, /* 0: black/transparent */
+ 0, 0, 0, /* 1: black */
+ 6, 1, 1, /* 2: medium green */
+ 7, 3, 3, /* 3: light green */
+ 1, 1, 7, /* 4: dark blue */
+ 3, 2, 7, /* 5: light blue */
+ 1, 5, 1, /* 6: dark red */
+ 6, 2, 7, /* 7: cyan */
+ 1, 7, 1, /* 8: medium red */
+ 3, 7, 3, /* 9: light red */
+ 6, 6, 1, /* 10: dark yellow */
+ 6, 6, 4, /* 11: light yellow */
+ 4, 1, 1, /* 12: dark green */
+ 2, 6, 5, /* 13: magenta */
+ 5, 5, 5, /* 14: gray */
+ 7, 7, 7 /* 15: white */
+ };
+ int i, red, ind;
+
+ for (i=0;i<16;i++)
+ {
+ /* set the palette registers */
+ vdp.palReg[i*2+0] = pal16[i*3+1] << 4 | pal16[i*3+2];
+ vdp.palReg[i*2+1] = pal16[i*3];
+ /* set the reference table */
+ pal_ind16[i] = pal16[i*3+1] << 6 | pal16[i*3] << 3 | pal16[i*3+2];
+ }
+
+ /* set internal palette GRAPHIC 7 */
+ for (i=0;i<256;i++)
+ {
+ ind = (i << 4) & 0x01c0;
+ ind |= (i >> 2) & 0x0038;
+ red = (i << 1) & 6; if (red == 6) red++;
+ ind |= red;
+
+ pal_ind256[i] = ind;
+ }
+ }
+
+/***************************************************************************
+
+ Memory functions
+
+***************************************************************************/
+
+static void v9938_vram_write (int offset, int data)
+ {
+ int newoffset;
+
+ if ( (vdp.mode == V9938_MODE_GRAPHIC6) || (vdp.mode == V9938_MODE_GRAPHIC7) )
+ {
+ newoffset = ((offset & 1) << 16) | (offset >> 1);
+ if (newoffset < vdp.vram_size)
+ vdp.vram[newoffset] = data;
+ }
+ else
+ {
+ if (offset < vdp.vram_size)
+ vdp.vram[offset] = data;
+ }
+ }
+
+static int v9938_vram_read (int offset)
+ {
+ if ( (vdp.mode == V9938_MODE_GRAPHIC6) || (vdp.mode == V9938_MODE_GRAPHIC7) )
+ return vdp.vram[((offset & 1) << 16) | (offset >> 1)];
+ else
+ return vdp.vram[offset];
+ }
+
+WRITE8_HANDLER (v9938_vram_w)
+ {
+ int address;
+
+ /*v9938_update_command ();*/
+
+ vdp.cmd_write_first = 0;
+
+ address = ((int)vdp.contReg[14] << 14) | vdp.address_latch;
+
+ if (vdp.contReg[45] & 0x40)
+ {
+ if ( (vdp.mode == V9938_MODE_GRAPHIC6) || (vdp.mode == V9938_MODE_GRAPHIC7) )
+ address >>= 1; /* correct? */
+ if (vdp.vram_exp && address < 0x10000)
+ vdp.vram_exp[address] = data;
+ }
+ else
+ {
+ v9938_vram_write (address, data);
+ }
+
+ vdp.address_latch = (vdp.address_latch + 1) & 0x3fff;
+ if ((!vdp.address_latch) && (vdp.contReg[0] & 0x0c) ) /* correct ??? */
+ {
+ vdp.contReg[14] = (vdp.contReg[14] + 1) & 7;
+ }
+ }
+
+ READ8_HANDLER (v9938_vram_r)
+ {
+ UINT8 ret;
+ int address;
+
+ address = ((int)vdp.contReg[14] << 14) | vdp.address_latch;
+
+ vdp.cmd_write_first = 0;
+
+ ret = vdp.read_ahead;
+
+ if (vdp.contReg[45] & 0x40)
+ {
+ if ( (vdp.mode == V9938_MODE_GRAPHIC6) || (vdp.mode == V9938_MODE_GRAPHIC7) )
+ address >>= 1; /* correct? */
+ /* correct? */
+ if (vdp.vram_exp && address < 0x10000)
+ vdp.read_ahead = vdp.vram_exp[address];
+ else
+ vdp.read_ahead = 0xff;
+ }
+ else
+ {
+ vdp.read_ahead = v9938_vram_read (address);
+ }
+
+ vdp.address_latch = (vdp.address_latch + 1) & 0x3fff;
+ if ((!vdp.address_latch) && (vdp.contReg[0] & 0x0c) ) /* correct ??? */
+ {
+ vdp.contReg[14] = (vdp.contReg[14] + 1) & 7;
+ }
+
+ return ret;
+ }
+
+WRITE8_HANDLER (v9938_command_w)
+ {
+ if (vdp.cmd_write_first)
+ {
+ if (data & 0x80)
+ {
+ if (!(data & 0x40))
+ v9938_register_write (data & 0x3f, vdp.cmd_write);
+ }
+ else
+ {
+ vdp.address_latch =
+ (((UINT16)data << 8) | vdp.cmd_write) & 0x3fff;
+ if ( !(data & 0x40) ) v9938_vram_r (0); /* read ahead! */
+ }
+
+ vdp.cmd_write_first = 0;
+ }
+ else
+ {
+ vdp.cmd_write = data;
+ vdp.cmd_write_first = 1;
+ }
+ }
+
+/***************************************************************************
+
+ Init/stop/reset/Interrupt functions
+
+***************************************************************************/
+
+void v9938_init (running_machine *machine, int model, int vram_size, void (*callback)(int) )
+{
+ memset (&vdp, 0, sizeof (vdp) );
+
+ vdp.model = model;
+ vdp.vram_size = vram_size;
+ vdp.INTCallback = callback;
+ vdp.size_old = -1;
+
+ /* allocate VRAM */
+ vdp.vram = auto_malloc (0x20000);
+ memset (vdp.vram, 0, 0x20000);
+ if (vdp.vram_size < 0x20000)
+ {
+ /* set unavailable RAM to 0xff */
+ memset (vdp.vram + vdp.vram_size, 0xff, (0x20000 - vdp.vram_size) );
+ }
+
+ /* do we have expanded memory? */
+ if (vdp.vram_size > 0x20000)
+ {
+ vdp.vram_exp = auto_malloc (0x10000);
+ memset (vdp.vram_exp, 0, 0x10000);
+ }
+ else
+ vdp.vram_exp = NULL;
+
+ video_start_generic_bitmapped(machine);
+}
+
+void v9938_reset (void)
+{
+ int i;
+
+ /* offset reset */
+ vdp.offset_x = 8;
+ vdp.offset_y = 8 + 16;
+ vdp.visible_y = 192;
+ /* register reset */
+ v9938_reset_palette (); /* palette registers */
+ for (i=0;i<10;i++) vdp.statReg[i] = 0;
+ vdp.statReg[2] = 0x0c;
+ if (vdp.model == MODEL_V9958) vdp.statReg[1] |= 4;
+ for (i=0;i<48;i++) vdp.contReg[i] = 0;
+ vdp.cmd_write_first = vdp.pal_write_first = 0;
+ vdp.INT = 0;
+ vdp.read_ahead = 0; vdp.address_latch = 0; /* ??? */
+ vdp.scanline = 0;
+}
+
+static void v9938_check_int (void)
+ {
+ UINT8 n;
+
+ n = ( (vdp.contReg[1] & 0x20) && (vdp.statReg[0] & 0x80) ) ||
+ ( (vdp.statReg[1] & 0x01) && (vdp.contReg[0] & 0x10) );
+
+ if (n != vdp.INT)
+ {
+ vdp.INT = n;
+ logerror ("V9938: IRQ line %s\n", n ? "up" : "down");
+ }
+
+ /*
+ ** Somehow the IRQ request is going down without cpu_irq_line () being
+ ** called; because of this Mr. Ghost, Xevious and SD Snatcher don't
+ ** run. As a patch it's called every scanline
+ */
+ vdp.INTCallback (n);
+ }
+
+void v9938_set_sprite_limit (int i)
+ {
+ vdp.sprite_limit = i;
+ }
+
+void v9938_set_resolution (int i)
+ {
+ if (i == RENDER_AUTO)
+ {
+ vdp.size_auto = 1;
+ }
+ else
+ {
+ vdp.size = i;
+ vdp.size_auto = 0;
+ }
+ }
+
+/***************************************************************************
+
+ Register functions
+
+***************************************************************************/
+
+WRITE8_HANDLER (v9938_register_w)
+{
+ int reg;
+
+ reg = vdp.contReg[17] & 0x3f;
+ if (reg != 17)
+ v9938_register_write (reg, data); /* true ? */
+
+ if (!(vdp.contReg[17] & 0x80))
+ vdp.contReg[17] = (vdp.contReg[17] + 1) & 0x3f;
+}
+
+static void v9938_register_write (int reg, int data)
+{
+ static UINT8 const reg_mask[] =
+ {
+ 0x7e, 0x7b, 0x7f, 0xff, 0x3f, 0xff, 0x3f, 0xff,
+ 0xfb, 0xbf, 0x07, 0x03, 0xff, 0xff, 0x07, 0x0f,
+ 0x0f, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x7f, 0x3f, 0x07
+ };
+
+ if (reg <= 27)
+ {
+ data &= reg_mask[reg];
+ if (vdp.contReg[reg] == data)
+ return;
+ }
+
+ if (reg > 46)
+ {
+ logerror ("V9938: Attempted to write to non-existant R#%d\n", reg);
+ return;
+ }
+
+ /*v9938_update_command (); */
+
+ switch (reg) {
+ /* registers that affect interrupt and display mode */
+ case 0:
+ case 1:
+ vdp.contReg[reg] = data;
+ v9938_set_mode ();
+ v9938_check_int ();
+ logerror ("V9938: mode = %s\n", v9938_modes[vdp.mode]);
+ break;
+
+ case 18:
+ case 9:
+ vdp.contReg[reg] = data;
+ /* recalc offset */
+ vdp.offset_x = (( (~vdp.contReg[18] - 8) & 0x0f) + 1);
+ vdp.offset_y = ((~(vdp.contReg[18]>>4) - 8) & 0x0f) + 7;
+ if (vdp.contReg[9] & 0x80)
+ {
+ vdp.visible_y = 212;
+ }
+ else
+ {
+ vdp.visible_y = 192;
+ vdp.offset_y += 10;
+ }
+ break;
+
+ case 15:
+ vdp.pal_write_first = 0;
+ break;
+
+ /* color burst registers aren't emulated */
+ case 20:
+ case 21:
+ case 22:
+ logerror ("V9938: Write %02xh to R#%d; color burst not emulated\n",
+ data, reg);
+ break;
+ case 25:
+ case 26:
+ case 27:
+ if (vdp.model != MODEL_V9958)
+ {
+ logerror ("V9938: Attempting to write %02xh to V9958 R#%d\n", data, reg);
+ data = 0;
+ }
+ break;
+
+ case 44:
+ v9938_cpu_to_vdp (data);
+ break;
+
+ case 46:
+ v9938_command_unit_w (data);
+ break;
+ }
+
+ if (reg != 15)
+ logerror("V9938: Write %02x to R#%d\n", data, reg);
+
+ vdp.contReg[reg] = data;
+}
+
+ READ8_HANDLER (v9938_status_r)
+ {
+ int reg, n;
+ UINT8 ret;
+
+ vdp.cmd_write_first = 0;
+
+ reg = vdp.contReg[15] & 0x0f;
+ if (reg > 9)
+ return 0xff;
+
+ switch (reg)
+ {
+ case 0:
+ ret = vdp.statReg[0];
+ vdp.statReg[0] &= 0x1f;
+ break;
+ case 1:
+ ret = vdp.statReg[1];
+ vdp.statReg[1] &= 0xfe;
+ if ((vdp.contReg[8] & 0xc0) == 0x80)
+ /* mouse mode: add button state */
+ ret |= vdp.button_state & 0xc0;
+ break;
+ case 2:
+ /*v9938_update_command ();*/
+ n = cycles_currently_ran ();
+ if ( (n < 28) || (n > 199) ) vdp.statReg[2] |= 0x20;
+ else vdp.statReg[2] &= ~0x20;
+ ret = vdp.statReg[2];
+ break;
+ case 3:
+ if ((vdp.contReg[8] & 0xc0) == 0x80)
+ { /* mouse mode: return x mouse delta */
+ ret = vdp.mx_delta;
+ vdp.mx_delta = 0;
+ }
+ else
+ ret = vdp.statReg[3];
+ break;
+ case 5:
+ if ((vdp.contReg[8] & 0xc0) == 0x80)
+ { /* mouse mode: return y mouse delta */
+ ret = vdp.my_delta;
+ vdp.my_delta = 0;
+ }
+ else
+ ret = vdp.statReg[5];
+ break;
+ case 7:
+ ret = vdp.statReg[7];
+ vdp.statReg[7] = vdp.contReg[44] = v9938_vdp_to_cpu () ;
+ break;
+ default:
+ ret = vdp.statReg[reg];
+ break;
+ }
+
+ logerror ("V9938: Read %02x from S#%d\n", ret, reg);
+ v9938_check_int ();
+
+ return ret;
+ }
+
+/***************************************************************************
+
+ Refresh / render function
+
+***************************************************************************/
+
+#define V9938_SECOND_FIELD ( !(((vdp.contReg[9] & 0x04) && !(vdp.statReg[2] & 2)) || vdp.blink))
+
+#define V9938_BPP (16)
+#define V9938_WIDTH (512 + 32)
+#include "v9938mod.c"
+#undef V9938_WIDTH
+#define V9938_WIDTH (256 + 16)
+#include "v9938mod.c"
+#undef V9938_WIDTH
+#undef V9938_BPP
+
+static void v9938_sprite_mode1 (int line, UINT8 *col)
+ {
+ UINT8 *attrtbl, *patterntbl, *patternptr;
+ int x, y, p, height, c, p2, i, n, pattern;
+
+ memset (col, 0, 256);
+
+ /* are sprites disabled? */
+ if (vdp.contReg[8] & 0x02) return;
+
+ attrtbl = vdp.vram + (vdp.contReg[5] << 7) + (vdp.contReg[11] << 15);
+ patterntbl = vdp.vram + (vdp.contReg[6] << 11);
+
+ /* 16x16 or 8x8 sprites */
+ height = (vdp.contReg[1] & 2) ? 16 : 8;
+ /* magnified sprites (zoomed) */
+ if (vdp.contReg[1] & 1) height *= 2;
+
+ p2 = p = 0;
+ while (1)
+ {
+ y = attrtbl[0];
+ if (y == 208) break;
+ y = (y - vdp.contReg[23]) & 255;
+ if (y > 208)
+ y = -(~y&255);
+ else
+ y++;
+
+ /* if sprite in range, has to be drawn */
+ if ( (line >= y) && (line < (y + height) ) )
+ {
+ if (p2 == 4)
+ {
+ /* max maximum sprites per line! */
+ if ( !(vdp.statReg[0] & 0x40) )
+ vdp.statReg[0] = (vdp.statReg[0] & 0xa0) | 0x40 | p;
+
+ if (vdp.sprite_limit) break;
+ }
+ /* get x */
+ x = attrtbl[1];
+ if (attrtbl[3] & 0x80) x -= 32;
+
+ /* get pattern */
+ pattern = attrtbl[2];
+ if (vdp.contReg[1] & 2)
+ pattern &= 0xfc;
+ n = line - y;
+ patternptr = patterntbl + pattern * 8 +
+ ((vdp.contReg[1] & 1) ? n/2 : n);
+ pattern = patternptr[0] << 8 | patternptr[16];
+
+ /* get colour */
+ c = attrtbl[3] & 0x0f;
+
+ /* draw left part */
+ n = 0;
+ while (1)
+ {
+ if (n == 0) pattern = patternptr[0];
+ else if ( (n == 1) && (vdp.contReg[1] & 2) ) pattern = patternptr[16];
+ else break;
+
+ n++;
+
+ for (i=0;i<8;i++)
+ {
+ if (pattern & 0x80)
+ {
+ if ( (x >= 0) && (x < 256) )
+ {
+ if (col[x] & 0x40)
+ {
+ /* we have a collision! */
+ if (p2 < 4)
+ vdp.statReg[0] |= 0x20;
+ }
+ if ( !(col[x] & 0x80) )
+ {
+ if (c || (vdp.contReg[8] & 0x20) )
+ col[x] |= 0xc0 | c;
+ else
+ col[x] |= 0x40;
+ }
+
+ /* if zoomed, draw another pixel */
+ if (vdp.contReg[1] & 1)
+ {
+ if (col[x+1] & 0x40)
+ {
+ /* we have a collision! */
+ if (p2 < 4)
+ vdp.statReg[0] |= 0x20;
+ }
+ if ( !(col[x+1] & 0x80) )
+ {
+ if (c || (vdp.contReg[8] & 0x20) )
+ col[x+1] |= 0xc0 | c;
+ else
+ col[x+1] |= 0x80;
+ }
+ }
+ }
+ }
+ if (vdp.contReg[1] & 1) x += 2; else x++;
+ pattern <<= 1;
+ }
+ }
+
+ p2++;
+ }
+
+ if (p >= 31) break;
+ p++;
+ attrtbl += 4;
+ }
+
+ if ( !(vdp.statReg[0] & 0x40) )
+ vdp.statReg[0] = (vdp.statReg[0] & 0xa0) | p;
+ }
+
+static void v9938_sprite_mode2 (int line, UINT8 *col)
+ {
+ int attrtbl, patterntbl, patternptr, colourtbl;
+ int x, i, y, p, height, c, p2, n, pattern, colourmask, first_cc_seen;
+
+ memset (col, 0, 256);
+
+ /* are sprites disabled? */
+ if (vdp.contReg[8] & 0x02) return;
+
+ attrtbl = ( (vdp.contReg[5] & 0xfc) << 7) + (vdp.contReg[11] << 15);
+ colourtbl = ( (vdp.contReg[5] & 0xf8) << 7) + (vdp.contReg[11] << 15);
+ patterntbl = (vdp.contReg[6] << 11);
+ colourmask = ( (vdp.contReg[5] & 3) << 3) | 0x7; /* check this! */
+
+ /* 16x16 or 8x8 sprites */
+ height = (vdp.contReg[1] & 2) ? 16 : 8;
+ /* magnified sprites (zoomed) */
+ if (vdp.contReg[1] & 1) height *= 2;
+
+ p2 = p = first_cc_seen = 0;
+ while (1)
+ {
+ y = v9938_vram_read (attrtbl);
+ if (y == 216) break;
+ y = (y - vdp.contReg[23]) & 255;
+ if (y > 216)
+ y = -(~y&255);
+ else
+ y++;
+
+ /* if sprite in range, has to be drawn */
+ if ( (line >= y) && (line < (y + height) ) )
+ {
+ if (p2 == 8)
+ {
+ /* max maximum sprites per line! */
+ if ( !(vdp.statReg[0] & 0x40) )
+ vdp.statReg[0] = (vdp.statReg[0] & 0xa0) | 0x40 | p;
+
+ if (vdp.sprite_limit) break;
+ }
+
+ n = line - y; if (vdp.contReg[1] & 1) n /= 2;
+ /* get colour */
+ c = v9938_vram_read (colourtbl + (((p&colourmask)*16) + n));
+
+ /* don't draw all sprite with CC set before any sprites
+ with CC = 0 are seen on this line */
+ if (c & 0x40)
+ {
+ if (!first_cc_seen)
+ goto skip_first_cc_set;
+ }
+ else
+ first_cc_seen = 1;
+
+ /* get pattern */
+ pattern = v9938_vram_read (attrtbl + 2);
+ if (vdp.contReg[1] & 2)
+ pattern &= 0xfc;
+ patternptr = patterntbl + pattern * 8 + n;
+ pattern = (v9938_vram_read (patternptr) << 8) |
+ v9938_vram_read (patternptr + 16);
+
+ /* get x */
+ x = v9938_vram_read (attrtbl + 1);
+ if (c & 0x80) x -= 32;
+
+ n = (vdp.contReg[1] & 2) ? 16 : 8;
+ while (n--)
+ {
+ for (i=0;i<=(vdp.contReg[1] & 1);i++)
+ {
+ if ( (x >= 0) && (x < 256) )
+ {
+ if ( (pattern & 0x8000) && !(col[x] & 0x10) )
+ {
+ if ( (c & 15) || (vdp.contReg[8] & 0x20) )
+ {
+ if ( !(c & 0x40) )
+ {
+ if (col[x] & 0x20) col[x] |= 0x10;
+ else
+ col[x] |= 0x20 | (c & 15);
+ }
+ else
+ col[x] |= c & 15;
+
+ col[x] |= 0x80;
+ }
+ }
+ else
+ {
+ if ( !(c & 0x40) && (col[x] & 0x20) )
+ col[x] |= 0x10;
+ }
+
+ if ( !(c & 0x60) && (pattern & 0x8000) )
+ {
+ if (col[x] & 0x40)
+ {
+ /* sprite collision! */
+ if (p2 < 8)
+ vdp.statReg[0] |= 0x20;
+ }
+ else
+ col[x] |= 0x40;
+ }
+
+ x++;
+ }
+ }
+
+ pattern <<= 1;
+ }
+
+skip_first_cc_set:
+ p2++;
+ }
+
+ if (p >= 31) break;
+ p++;
+ attrtbl += 4;
+ }
+
+ if ( !(vdp.statReg[0] & 0x40) )
+ vdp.statReg[0] = (vdp.statReg[0] & 0xa0) | p;
+ }
+
+typedef struct {
+ UINT8 m;
+ void (*visible_16)(UINT16*, int);
+ void (*visible_16s)(UINT16*, int);
+ void (*border_16)(UINT16*);
+ void (*border_16s)(UINT16*);
+ void (*sprites)(int, UINT8*);
+ void (*draw_sprite_16)(UINT16*, UINT8*);
+ void (*draw_sprite_16s)(UINT16*, UINT8*);
+} V9938_MODE;
+
+static const V9938_MODE modes[] = {
+ { 0x02,
+ v9938_mode_text1_16,
+ v9938_mode_text1_16s,
+ v9938_default_border_16,
+ v9938_default_border_16s,
+ NULL,
+ NULL,
+ NULL },
+ { 0x01,
+ v9938_mode_multi_16,
+ v9938_mode_multi_16s,
+ v9938_default_border_16,
+ v9938_default_border_16s,
+ v9938_sprite_mode1,
+ v9938_default_draw_sprite_16,
+ v9938_default_draw_sprite_16s },
+ { 0x00,
+ v9938_mode_graphic1_16,
+ v9938_mode_graphic1_16s,
+ v9938_default_border_16,
+ v9938_default_border_16s,
+ v9938_sprite_mode1,
+ v9938_default_draw_sprite_16,
+ v9938_default_draw_sprite_16s },
+ { 0x04,
+ v9938_mode_graphic23_16,
+ v9938_mode_graphic23_16s,
+ v9938_default_border_16,
+ v9938_default_border_16s,
+ v9938_sprite_mode1,
+ v9938_default_draw_sprite_16,
+ v9938_default_draw_sprite_16s },
+ { 0x08,
+ v9938_mode_graphic23_16,
+ v9938_mode_graphic23_16s,
+ v9938_default_border_16,
+ v9938_default_border_16s,
+ v9938_sprite_mode2,
+ v9938_default_draw_sprite_16,
+ v9938_default_draw_sprite_16s },
+ { 0x0c,
+ v9938_mode_graphic4_16,
+ v9938_mode_graphic4_16s,
+ v9938_default_border_16,
+ v9938_default_border_16s,
+ v9938_sprite_mode2,
+ v9938_default_draw_sprite_16,
+ v9938_default_draw_sprite_16s },
+ { 0x10,
+ v9938_mode_graphic5_16,
+ v9938_mode_graphic5_16s,
+ v9938_graphic5_border_16,
+ v9938_graphic5_border_16s,
+ v9938_sprite_mode2,
+ v9938_graphic5_draw_sprite_16,
+ v9938_graphic5_draw_sprite_16s },
+ { 0x14,
+ v9938_mode_graphic6_16,
+ v9938_mode_graphic6_16s,
+ v9938_default_border_16,
+ v9938_default_border_16s,
+ v9938_sprite_mode2,
+ v9938_default_draw_sprite_16,
+ v9938_default_draw_sprite_16s },
+ { 0x1c,
+ v9938_mode_graphic7_16,
+ v9938_mode_graphic7_16s,
+ v9938_graphic7_border_16,
+ v9938_graphic7_border_16s,
+ v9938_sprite_mode2,
+ v9938_graphic7_draw_sprite_16,
+ v9938_graphic7_draw_sprite_16s },
+ { 0x0a,
+ v9938_mode_text2_16,
+ v9938_mode_text2_16s,
+ v9938_default_border_16,
+ v9938_default_border_16s,
+ NULL,
+ NULL,
+ NULL },
+ { 0xff,
+ v9938_mode_unknown_16,
+ v9938_mode_unknown_16s,
+ v9938_default_border_16,
+ v9938_default_border_16s,
+ NULL,
+ NULL,
+ NULL },
+};
+
+static void v9938_set_mode (void)
+ {
+ int n,i;
+
+ n = (((vdp.contReg[0] & 0x0e) << 1) | ((vdp.contReg[1] & 0x18) >> 3));
+ for (i=0;;i++)
+ {
+ if ( (modes[i].m == n) || (modes[i].m == 0xff) ) break;
+ }
+ vdp.mode = i;
+ }
+
+static void v9938_refresh_16 (mame_bitmap *bmp, int line)
+ {
+ int i, double_lines;
+ UINT8 col[256];
+ UINT16 *ln, *ln2 = NULL;
+
+ double_lines = 0;
+
+ if (vdp.size == RENDER_HIGH)
+ {
+ if (vdp.contReg[9] & 0x08)
+ {
+ vdp.size_now = RENDER_HIGH;
+ ln = BITMAP_ADDR16(bmp, line*2+((vdp.statReg[2]>>1)&1), 0);
+ }
+ else
+ {
+ ln = BITMAP_ADDR16(bmp, line*2, 0);
+ ln2 = BITMAP_ADDR16(bmp, line*2+1, 0);
+ double_lines = 1;
+ }
+ }
+ else
+ ln = BITMAP_ADDR16(bmp, line, 0);
+
+ if ( !(vdp.contReg[1] & 0x40) || (vdp.statReg[2] & 0x40) )
+ {
+ if (vdp.size == RENDER_HIGH)
+ modes[vdp.mode].border_16 (ln);
+ else
+ modes[vdp.mode].border_16s (ln);
+ }
+ else
+ {
+ i = (line - vdp.offset_y) & 255;
+ if (vdp.size == RENDER_HIGH)
+ {
+ modes[vdp.mode].visible_16 (ln, i);
+ if (modes[vdp.mode].sprites)
+ {
+ modes[vdp.mode].sprites (i, col);
+ modes[vdp.mode].draw_sprite_16 (ln, col);
+ }
+ }
+ else
+ {
+ modes[vdp.mode].visible_16s (ln, i);
+ if (modes[vdp.mode].sprites)
+ {
+ modes[vdp.mode].sprites (i, col);
+ modes[vdp.mode].draw_sprite_16s (ln, col);
+ }
+ }
+ }
+
+ if (double_lines)
+ memcpy (ln2, ln, (512 + 32) * 2);
+ }
+
+static void v9938_refresh_line (mame_bitmap *bmp, int line)
+ {
+ int ind16, ind256;
+
+ ind16 = pal_ind16[0];
+ ind256 = pal_ind256[0];
+
+ if ( !(vdp.contReg[8] & 0x20) && (vdp.mode != V9938_MODE_GRAPHIC5) )
+ {
+ pal_ind16[0] = pal_ind16[(vdp.contReg[7] & 0x0f)];
+ pal_ind256[0] = pal_ind256[vdp.contReg[7]];
+ }
+
+ v9938_refresh_16 (bmp, line);
+
+ if ( !(vdp.contReg[8] & 0x20) && (vdp.mode != V9938_MODE_GRAPHIC5) )
+ {
+ pal_ind16[0] = ind16;
+ pal_ind256[0] = ind256;
+ }
+ }
+
+/*
+
+From: awulms@inter.nl.net (Alex Wulms)
+*** About the HR/VR topic: this is how it works according to me:
+
+*** HR:
+HR is very straightforward:
+-HR=1 during 'display time'
+-HR=0 during 'horizontal border, horizontal retrace'
+I have put 'display time' and 'horizontal border, horizontal retrace' between
+quotes because HR does not only flip between 0 and 1 during the display of
+the 192/212 display lines, but also during the vertical border and during the
+vertical retrace.
+
+*** VR:
+VR is a little bit tricky
+-VR always gets set to 0 when the VDP starts with display line 0
+-VR gets set to 1 when the VDP reaches display line (192 if LN=0) or (212 if
+LN=1)
+-The VDP displays contents of VRAM as long as VR=0
+
+As a consequence of this behaviour, it is possible to program the famous
+overscan trick, where VRAM contents is shown in the borders:
+Generate an interrupt at line 230 (or so) and on this interrupt: set LN=1
+Generate an interrupt at line 200 (or so) and on this interrupt: set LN=0
+Repeat the above two steps
+
+*** The top/bottom border contents during overscan:
+On screen 0:
+1) The VDP keeps increasing the name table address pointer during bottom
+border, vertical retrace and top border
+2) The VDP resets the name table address pointer when the first display line
+is reached
+
+On the other screens:
+1) The VDP keeps increasing the name table address pointer during the bottom
+border
+2) The VDP resets the name table address pointer such that the top border
+contents connects up with the first display line. E.g., when the top border
+is 26 lines high, the VDP will take:
+'logical' vram line
+TOPB000 256-26
+...
+TOPB025 256-01
+DISPL000 000
+...
+DISPL211 211
+BOTB000 212
+...
+BOTB024 236
+
+
+
+*** About the horizontal interrupt
+
+All relevant definitions on a row:
+-FH: Bit 0 of status register 1
+-IE1: Bit 4 of mode register 0
+-IL: Line number in mode register 19
+-DL: The line that the VDP is going to display (corrected for vertical scroll)
+-IRQ: Interrupt request line of VDP to Z80
+
+At the *start* of every new line (display, bottom border, part of vertical
+display), the VDP does:
+-FH = (FH && IE1) || (IL==DL)
+
+After reading of status register 1 by the CPU, the VDP does:
+-FH = 0
+
+Furthermore, the following is true all the time:
+-IRQ = FH && IE1
+
+The resulting behaviour:
+When IE1=0:
+-FH will be set as soon as display of line IL starts
+-FH will be reset as soon as status register 1 is read
+-FH will be reset as soon as the next display line is reached
+
+When IE=1:
+-FH and IRQ will be set as soon as display line IL is reached
+-FH and IRQ will be reset as soon as status register 1 is read
+
+Another subtile result:
+If, while FH and IRQ are set, IE1 gets reset, the next happens:
+-IRQ is reset immediately (since IRQ is always FH && IE1)
+-FH will be reset as soon as display of the next line starts (unless the next
+line is line IL)
+
+
+*** About the vertical interrupt:
+Another relevant definition:
+-FV: Bit 7 of status register 0
+-IE0: Bit 5 of mode register 1
+
+I only know for sure the behaviour when IE0=1:
+-FV and IRQ will be set as soon as VR changes from 0 to 1
+-FV and IRQ will be reset as soon as status register 0 is read
+
+A consequence is that NO vertical interrupts will be generated during the
+overscan trick, described in the VR section above.
+
+I do not know the behaviour of FV when IE0=0. That is the part that I still
+have to test.
+*/
+
+static void v9938_interrupt_start_vblank (void)
+ {
+#if 0
+ if (input_code_pressed (KEYCODE_D) )
+ {
+ FILE *fp;
+ int i;
+
+ fp = fopen ("vram.dmp", "wb");
+ if (fp)
+ {
+ fwrite (vdp.vram, 0x10000, 1, fp);
+ fclose (fp);
+ popmessage("saved");
+ }
+
+ for (i=0;i<24;i++) mame_printf_debug ("R#%d = %02x\n", i, vdp.contReg[i]);
+ }
+#endif
+
+ /* at every frame, vdp switches fields */
+ vdp.statReg[2] = (vdp.statReg[2] & 0xfd) | (~vdp.statReg[2] & 2);
+
+ /* color blinking */
+ if (!(vdp.contReg[13] & 0xf0))
+ vdp.blink = 0;
+ else if (!(vdp.contReg[13] & 0x0f))
+ vdp.blink = 1;
+ else
+ {
+ /* both on and off counter are non-zero: timed blinking */
+ if (vdp.blink_count)
+ vdp.blink_count--;
+ if (!vdp.blink_count)
+ {
+ vdp.blink = !vdp.blink;
+ if (vdp.blink)
+ vdp.blink_count = (vdp.contReg[13] >> 4) * 10;
+ else
+ vdp.blink_count = (vdp.contReg[13] & 0x0f) * 10;
+ }
+ }
+
+ /* check screen rendering size */
+ if (vdp.size_auto && (vdp.size_now >= 0) && (vdp.size != vdp.size_now) )
+ vdp.size = vdp.size_now;
+
+ if (vdp.size != vdp.size_old)
+ {
+ if (vdp.size == RENDER_HIGH)
+ video_screen_set_visarea (0, 0, 512 + 32 - 1, 0, 424 + 56 - 1);
+ else
+ video_screen_set_visarea (0, 0, 256 + 16 - 1, 0, 212 + 28 - 1);
+
+ vdp.size_old = vdp.size;
+ }
+
+ vdp.size_now = -1;
+ }
+
+int v9938_interrupt (void)
+{
+ int scanline, max, pal, scanline_start;
+
+ v9938_update_command ();
+
+ pal = vdp.contReg[9] & 2;
+ if (pal) scanline_start = 53; else scanline_start = 22;
+
+ /* set flags */
+ if (vdp.scanline == (vdp.offset_y + scanline_start) )
+ {
+ vdp.statReg[2] &= ~0x40;
+ }
+ else if (vdp.scanline == (vdp.offset_y + vdp.visible_y + scanline_start) )
+ {
+ vdp.statReg[2] |= 0x40;
+ vdp.statReg[0] |= 0x80;
+ }
+
+ max = (pal) ? 255 : (vdp.contReg[9] & 0x80) ? 234 : 244;
+ scanline = (vdp.scanline - scanline_start - vdp.offset_y);
+ if ( (scanline >= 0) && (scanline <= max) &&
+ ( ( (scanline + vdp.contReg[23]) & 255) == vdp.contReg[19]) )
+ {
+ vdp.statReg[1] |= 1;
+ logerror ("V9938: scanline interrupt (%d)\n", scanline);
+ }
+ else
+ if ( !(vdp.contReg[0] & 0x10) ) vdp.statReg[1] &= 0xfe;
+
+ v9938_check_int ();
+
+ /* check for start of vblank */
+ if ((pal && (vdp.scanline == 310)) ||
+ (!pal && (vdp.scanline == 259)))
+ v9938_interrupt_start_vblank ();
+
+ /* render the current line */
+ if ((vdp.scanline >= scanline_start) && (vdp.scanline < (212 + 28 + scanline_start)))
+ {
+ scanline = (vdp.scanline - scanline_start) & 255;
+
+ v9938_refresh_line (tmpbitmap, scanline);
+ }
+
+ max = (vdp.contReg[9] & 2) ? 313 : 262;
+ if (++vdp.scanline == max)
+ vdp.scanline = 0;
+
+ return vdp.INT;
+}
+
+/*
+ Driver-specific function: update the vdp mouse state
+*/
+void v9938_update_mouse_state(int mx_delta, int my_delta, int button_state)
+{
+ /* save button state */
+ vdp.button_state = (button_state << 6) & 0xc0;
+
+ if ((vdp.contReg[8] & 0xc0) == 0x80)
+ { /* vdp will process mouse deltas only if it is in mouse mode */
+ vdp.mx_delta += mx_delta;
+ vdp.my_delta += my_delta;
+ }
+}
+
+/***************************************************************************
+
+ Command unit
+
+***************************************************************************/
+
+#define VDP vdp.contReg
+#define VDPStatus vdp.statReg
+#define VRAM vdp.vram
+#define VRAM_EXP vdp.vram_exp
+#define ScrMode vdp.mode
+
+/*************************************************************/
+/** Completely rewritten by Alex Wulms: **/
+/** - VDP Command execution 'in parallel' with CPU **/
+/** - Corrected behaviour of VDP commands **/
+/** - Made it easier to implement correct S7/8 mapping **/
+/** by concentrating VRAM access in one single place **/
+/** - Made use of the 'in parallel' VDP command exec **/
+/** and correct timing. You must call the function **/
+/** LoopVDP() from LoopZ80 in MSX.c. You must call it **/
+/** exactly 256 times per screen refresh. **/
+/** Started on : 11-11-1999 **/
+/** Beta release 1 on: 9-12-1999 **/
+/** Beta release 2 on: 20-01-2000 **/
+/** - Corrected behaviour of VRM <-> Z80 transfer **/
+/** - Improved performance of the code **/
+/** Public release 1.0: 20-04-2000 **/
+/*************************************************************/
+
+#define VDP_VRMP5(MX, X, Y) ((!MX) ? (VRAM + ((Y&1023)<<7) + ((X&255)>>1)) : (VRAM_EXP + ((Y&511)<<7) + ((X&255)>>1)))
+#define VDP_VRMP6(MX, X, Y) ((!MX) ? (VRAM + ((Y&1023)<<7) + ((X&511)>>2)) : (VRAM_EXP + ((Y&511)<<7) + ((X&511)>>2)))
+//#define VDP_VRMP7(MX, X, Y) ((!MX) ? (VRAM + ((Y&511)<<8) + ((X&511)>>1)) : (VRAM_EXP + ((Y&255)<<8) + ((X&511)>>1)))
+#define VDP_VRMP7(MX, X, Y) ((!MX) ? (VRAM + ((X&2)<<15) + ((Y&511)<<7) + ((X&511)>>2)) : (VRAM_EXP + ((Y&511)<<7) + ((X&511)>>2))/*(VRAM_EXP + ((Y&255)<<8) + ((X&511)>>1))*/)
+//#define VDP_VRMP8(MX, X, Y) ((!MX) ? (VRAM + ((Y&511)<<8) + (X&255)) : (VRAM_EXP + ((Y&255)<<8) + (X&255)))
+#define VDP_VRMP8(MX, X, Y) ((!MX) ? (VRAM + ((X&1)<<16) + ((Y&511)<<7) + ((X>>1)&127)) : (VRAM_EXP + ((Y&511)<<7) + ((X>>1)&127))/*(VRAM_EXP + ((Y&255)<<8) + (X&255))*/)
+
+#define VDP_VRMP(M, MX, X, Y) VDPVRMP(M, MX, X, Y)
+#define VDP_POINT(M, MX, X, Y) VDPpoint(M, MX, X, Y)
+#define VDP_PSET(M, MX, X, Y, C, O) VDPpset(M, MX, X, Y, C, O)
+
+#define CM_ABRT 0x0
+#define CM_POINT 0x4
+#define CM_PSET 0x5
+#define CM_SRCH 0x6
+#define CM_LINE 0x7
+#define CM_LMMV 0x8
+#define CM_LMMM 0x9
+#define CM_LMCM 0xA
+#define CM_LMMC 0xB
+#define CM_HMMV 0xC
+#define CM_HMMM 0xD
+#define CM_YMMM 0xE
+#define CM_HMMC 0xF
+
+/*************************************************************/
+/* Many VDP commands are executed in some kind of loop but */
+/* essentially, there are only a few basic loop structures */
+/* that are re-used. We define the loop structures that are */
+/* re-used here so that they have to be entered only once */
+/*************************************************************/
+#define pre_loop \
+ while ((cnt-=delta) > 0) {
+
+
+/* Loop over DX, DY */
+#define post__x_y(MX) \
+ if (!--ANX || ((ADX+=TX)&MX)) { \
+ if (!(--NY&1023) || (DY+=TY)==-1) \
+ break; \
+ else { \
+ ADX=DX; \
+ ANX=NX; \
+ } \
+ } \
+ }
+
+/* Loop over DX, SY, DY */
+#define post__xyy(MX) \
+ if ((ADX+=TX)&MX) { \
+ if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \
+ break; \
+ else \
+ ADX=DX; \
+ } \
+ }
+
+/* Loop over SX, DX, SY, DY */
+#define post_xxyy(MX) \
+ if (!--ANX || ((ASX+=TX)&MX) || ((ADX+=TX)&MX)) { \
+ if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \
+ break; \
+ else { \
+ ASX=SX; \
+ ADX=DX; \
+ ANX=NX; \
+ } \
+ } \
+ }
+
+/*************************************************************/
+/** Structures and stuff **/
+/*************************************************************/
+static struct {
+ int SX,SY;
+ int DX,DY;
+ int TX,TY;
+ int NX,NY;
+ int MX;
+ int ASX,ADX,ANX;
+ UINT8 CL;
+ UINT8 LO;
+ UINT8 CM;
+ UINT8 MXS, MXD;
+} MMC;
+
+/*************************************************************/
+/** Function prototypes **/
+/*************************************************************/
+static UINT8 *VDPVRMP(register UINT8 M, register int MX, register int X, register int Y);
+
+static UINT8 VDPpoint5(register int MXS, register int SX, register int SY);
+static UINT8 VDPpoint6(register int MXS, register int SX, register int SY);
+static UINT8 VDPpoint7(register int MXS, register int SX, register int SY);
+static UINT8 VDPpoint8(register int MXS, register int SX, register int SY);
+
+static UINT8 VDPpoint(register UINT8 SM, register int MXS,
+ register int SX, register int SY);
+
+static void VDPpsetlowlevel(register UINT8 *P, register UINT8 CL,
+ register UINT8 M, register UINT8 OP);
+
+static void VDPpset5(register int MXD, register int DX, register int DY,
+ register UINT8 CL, register UINT8 OP);
+static void VDPpset6(register int MXD, register int DX, register int DY,
+ register UINT8 CL, register UINT8 OP);
+static void VDPpset7(register int MXD, register int DX, register int DY,
+ register UINT8 CL, register UINT8 OP);
+static void VDPpset8(register int MXD, register int DX, register int DY,
+ register UINT8 CL, register UINT8 OP);
+
+static void VDPpset(register UINT8 SM, register int MXD,
+ register int DX, register int DY,
+ register UINT8 CL, register UINT8 OP);
+
+static int GetVdpTimingValue(register int *);
+
+static void SrchEngine(void);
+static void LineEngine(void);
+static void LmmvEngine(void);
+static void LmmmEngine(void);
+static void LmcmEngine(void);
+static void LmmcEngine(void);
+static void HmmvEngine(void);
+static void HmmmEngine(void);
+static void YmmmEngine(void);
+static void HmmcEngine(void);
+
+static void ReportVdpCommand(register UINT8 Op);
+
+/*************************************************************/
+/** Variables visible only in this module **/
+/*************************************************************/
+static UINT8 Mask[4] = { 0x0F,0x03,0x0F,0xFF };
+static int PPB[4] = { 2,4,2,1 };
+static int PPL[4] = { 256,512,512,256 };
+static int VdpOpsCnt=1;
+static void (*VdpEngine)(void)=0;
+
+ /* SprOn SprOn SprOf SprOf */
+ /* ScrOf ScrOn ScrOf ScrOn */
+static int srch_timing[8]={ 818, 1025, 818, 830, /* ntsc */
+ 696, 854, 696, 684 }; /* pal */
+static int line_timing[8]={ 1063, 1259, 1063, 1161,
+ 904, 1026, 904, 953 };
+static int hmmv_timing[8]={ 439, 549, 439, 531,
+ 366, 439, 366, 427 };
+static int lmmv_timing[8]={ 873, 1135, 873, 1056,
+ 732, 909, 732, 854 };
+static int ymmm_timing[8]={ 586, 952, 586, 610,
+ 488, 720, 488, 500 };
+static int hmmm_timing[8]={ 818, 1111, 818, 854,
+ 684, 879, 684, 708 };
+static int lmmm_timing[8]={ 1160, 1599, 1160, 1172,
+ 964, 1257, 964, 977 };
+
+
+/** VDPVRMP() **********************************************/
+/** Calculate addr of a pixel in vram **/
+/*************************************************************/
+INLINE UINT8 *VDPVRMP(UINT8 M,int MX,int X,int Y)
+{
+ switch(M)
+ {
+ case 0: return VDP_VRMP5(MX,X,Y);
+ case 1: return VDP_VRMP6(MX,X,Y);
+ case 2: return VDP_VRMP7(MX,X,Y);
+ case 3: return VDP_VRMP8(MX,X,Y);
+ }
+
+ return(VRAM);
+}
+
+/** VDPpoint5() ***********************************************/
+/** Get a pixel on screen 5 **/
+/*************************************************************/
+INLINE UINT8 VDPpoint5(int MXS, int SX, int SY)
+{
+ return (*VDP_VRMP5(MXS, SX, SY) >>
+ (((~SX)&1)<<2)
+ )&15;
+}
+
+/** VDPpoint6() ***********************************************/
+/** Get a pixel on screen 6 **/
+/*************************************************************/
+INLINE UINT8 VDPpoint6(int MXS, int SX, int SY)
+{
+ return (*VDP_VRMP6(MXS, SX, SY) >>
+ (((~SX)&3)<<1)
+ )&3;
+}
+
+/** VDPpoint7() ***********************************************/
+/** Get a pixel on screen 7 **/
+/*************************************************************/
+INLINE UINT8 VDPpoint7(int MXS, int SX, int SY)
+{
+ return (*VDP_VRMP7(MXS, SX, SY) >>
+ (((~SX)&1)<<2)
+ )&15;
+}
+
+/** VDPpoint8() ***********************************************/
+/** Get a pixel on screen 8 **/
+/*************************************************************/
+INLINE UINT8 VDPpoint8(int MXS, int SX, int SY)
+{
+ return *VDP_VRMP8(MXS, SX, SY);
+}
+
+/** VDPpoint() ************************************************/
+/** Get a pixel on a screen **/
+/*************************************************************/
+INLINE UINT8 VDPpoint(UINT8 SM, int MXS, int SX, int SY)
+{
+ switch(SM)
+ {
+ case 0: return VDPpoint5(MXS,SX,SY);
+ case 1: return VDPpoint6(MXS,SX,SY);
+ case 2: return VDPpoint7(MXS,SX,SY);
+ case 3: return VDPpoint8(MXS,SX,SY);
+ }
+
+ return(0);
+}
+
+/** VDPpsetlowlevel() ****************************************/
+/** Low level function to set a pixel on a screen **/
+/** Make it inline to make it fast **/
+/*************************************************************/
+INLINE void VDPpsetlowlevel(UINT8 *P, UINT8 CL, UINT8 M, UINT8 OP)
+{
+ switch (OP)
+ {
+ case 0: *P = (*P & M) | CL; break;
+ case 1: *P = *P & (CL | M); break;
+ case 2: *P |= CL; break;
+ case 3: *P ^= CL; break;
+ case 4: *P = (*P & M) | ~(CL | M); break;
+ case 8: if (CL) *P = (*P & M) | CL; break;
+ case 9: if (CL) *P = *P & (CL | M); break;
+ case 10: if (CL) *P |= CL; break;
+ case 11: if (CL) *P ^= CL; break;
+ case 12: if (CL) *P = (*P & M) | ~(CL|M); break;
+ }
+}
+
+/** VDPpset5() ***********************************************/
+/** Set a pixel on screen 5 **/
+/*************************************************************/
+INLINE void VDPpset5(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
+{
+ register UINT8 SH = ((~DX)&1)<<2;
+
+ VDPpsetlowlevel(VDP_VRMP5(MXD, DX, DY),
+ CL << SH, ~(15<<SH), OP);
+}
+
+/** VDPpset6() ***********************************************/
+/** Set a pixel on screen 6 **/
+/*************************************************************/
+INLINE void VDPpset6(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
+{
+ register UINT8 SH = ((~DX)&3)<<1;
+
+ VDPpsetlowlevel(VDP_VRMP6(MXD, DX, DY),
+ CL << SH, ~(3<<SH), OP);
+}
+
+/** VDPpset7() ***********************************************/
+/** Set a pixel on screen 7 **/
+/*************************************************************/
+INLINE void VDPpset7(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
+{
+ register UINT8 SH = ((~DX)&1)<<2;
+
+ VDPpsetlowlevel(VDP_VRMP7(MXD, DX, DY),
+ CL << SH, ~(15<<SH), OP);
+}
+
+/** VDPpset8() ***********************************************/
+/** Set a pixel on screen 8 **/
+/*************************************************************/
+INLINE void VDPpset8(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
+{
+ VDPpsetlowlevel(VDP_VRMP8(MXD, DX, DY),
+ CL, 0, OP);
+}
+
+/** VDPpset() ************************************************/
+/** Set a pixel on a screen **/
+/*************************************************************/
+INLINE void VDPpset(UINT8 SM, int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
+{
+ switch (SM) {
+ case 0: VDPpset5(MXD, DX, DY, CL, OP); break;
+ case 1: VDPpset6(MXD, DX, DY, CL, OP); break;
+ case 2: VDPpset7(MXD, DX, DY, CL, OP); break;
+ case 3: VDPpset8(MXD, DX, DY, CL, OP); break;
+ }
+}
+
+/** GetVdpTimingValue() **************************************/
+/** Get timing value for a certain VDP command **/
+/*************************************************************/
+static int GetVdpTimingValue(register int *timing_values)
+{
+ return(timing_values[((VDP[1]>>6)&1)|(VDP[8]&2)|((VDP[9]<<1)&4)]);
+}
+
+/** SrchEgine()** ********************************************/
+/** Search a dot **/
+/*************************************************************/
+void SrchEngine(void)
+{
+ register int SX=MMC.SX;
+ register int SY=MMC.SY;
+ register int TX=MMC.TX;
+ register int ANX=MMC.ANX;
+ register UINT8 CL=MMC.CL;
+ register int MXD = MMC.MXD;
+ register int cnt;
+ register int delta;
+
+ delta = GetVdpTimingValue(srch_timing);
+ cnt = VdpOpsCnt;
+
+#define pre_srch \
+ pre_loop \
+ if ((
+#define post_srch(MX) \
+ ==CL) ^ANX) { \
+ VDPStatus[2]|=0x10; /* Border detected */ \
+ break; \
+ } \
+ if ((SX+=TX) & MX) { \
+ VDPStatus[2]&=0xEF; /* Border not detected */ \
+ break; \
+ } \
+ }
+
+ switch (ScrMode) {
+ default:
+ case 5: pre_srch VDPpoint5(MXD, SX, SY) post_srch(256)
+ break;
+ case 6: pre_srch VDPpoint6(MXD, SX, SY) post_srch(512)
+ break;
+ case 7: pre_srch VDPpoint7(MXD, SX, SY) post_srch(512)
+ break;
+ case 8: pre_srch VDPpoint8(MXD, SX, SY) post_srch(256)
+ break;
+ }
+
+ if ((VdpOpsCnt=cnt)>0) {
+ /* Command execution done */
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ /* Update SX in VDP registers */
+ VDPStatus[8]=SX&0xFF;
+ VDPStatus[9]=(SX>>8)|0xFE;
+ }
+ else {
+ MMC.SX=SX;
+ }
+}
+
+/** LineEgine()** ********************************************/
+/** Draw a line **/
+/*************************************************************/
+void LineEngine(void)
+{
+ register int DX=MMC.DX;
+ register int DY=MMC.DY;
+ register int TX=MMC.TX;
+ register int TY=MMC.TY;
+ register int NX=MMC.NX;
+ register int NY=MMC.NY;
+ register int ASX=MMC.ASX;
+ register int ADX=MMC.ADX;
+ register UINT8 CL=MMC.CL;
+ register UINT8 LO=MMC.LO;
+ register int MXD = MMC.MXD;
+ register int cnt;
+ register int delta;
+
+ delta = GetVdpTimingValue(line_timing);
+ cnt = VdpOpsCnt;
+
+#define post_linexmaj(MX) \
+ DX+=TX; \
+ if ((ASX-=NY)<0) { \
+ ASX+=NX; \
+ DY+=TY; \
+ } \
+ ASX&=1023; /* Mask to 10 bits range */ \
+ if (ADX++==NX || (DX&MX)) \
+ break; \
+ }
+#define post_lineymaj(MX) \
+ DY+=TY; \
+ if ((ASX-=NY)<0) { \
+ ASX+=NX; \
+ DX+=TX; \
+ } \
+ ASX&=1023; /* Mask to 10 bits range */ \
+ if (ADX++==NX || (DX&MX)) \
+ break; \
+ }
+
+ if ((VDP[45]&0x01)==0)
+ /* X-Axis is major direction */
+ switch (ScrMode) {
+ default:
+ case 5: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_linexmaj(256)
+ break;
+ case 6: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_linexmaj(512)
+ break;
+ case 7: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_linexmaj(512)
+ break;
+ case 8: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_linexmaj(256)
+ break;
+ }
+ else
+ /* Y-Axis is major direction */
+ switch (ScrMode) {
+ default:
+ case 5: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_lineymaj(256)
+ break;
+ case 6: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_lineymaj(512)
+ break;
+ case 7: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_lineymaj(512)
+ break;
+ case 8: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_lineymaj(256)
+ break;
+ }
+
+ if ((VdpOpsCnt=cnt)>0) {
+ /* Command execution done */
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ VDP[38]=DY & 0xFF;
+ VDP[39]=(DY>>8) & 0x03;
+ }
+ else {
+ MMC.DX=DX;
+ MMC.DY=DY;
+ MMC.ASX=ASX;
+ MMC.ADX=ADX;
+ }
+}
+
+/** LmmvEngine() *********************************************/
+/** VDP -> Vram **/
+/*************************************************************/
+void LmmvEngine(void)
+{
+ register int DX=MMC.DX;
+ register int DY=MMC.DY;
+ register int TX=MMC.TX;
+ register int TY=MMC.TY;
+ register int NX=MMC.NX;
+ register int NY=MMC.NY;
+ register int ADX=MMC.ADX;
+ register int ANX=MMC.ANX;
+ register UINT8 CL=MMC.CL;
+ register UINT8 LO=MMC.LO;
+ register int MXD = MMC.MXD;
+ register int cnt;
+ register int delta;
+
+ delta = GetVdpTimingValue(lmmv_timing);
+ cnt = VdpOpsCnt;
+
+ switch (ScrMode) {
+ default:
+ case 5: pre_loop VDPpset5(MXD, ADX, DY, CL, LO); post__x_y(256)
+ break;
+ case 6: pre_loop VDPpset6(MXD, ADX, DY, CL, LO); post__x_y(512)
+ break;
+ case 7: pre_loop VDPpset7(MXD, ADX, DY, CL, LO); post__x_y(512)
+ break;
+ case 8: pre_loop VDPpset8(MXD, ADX, DY, CL, LO); post__x_y(256)
+ break;
+ }
+
+ if ((VdpOpsCnt=cnt)>0) {
+ /* Command execution done */
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ if (!NY)
+ DY+=TY;
+ VDP[38]=DY & 0xFF;
+ VDP[39]=(DY>>8) & 0x03;
+ VDP[42]=NY & 0xFF;
+ VDP[43]=(NY>>8) & 0x03;
+ }
+ else {
+ MMC.DY=DY;
+ MMC.NY=NY;
+ MMC.ANX=ANX;
+ MMC.ADX=ADX;
+ }
+}
+
+/** LmmmEngine() *********************************************/
+/** Vram -> Vram **/
+/*************************************************************/
+void LmmmEngine(void)
+{
+ register int SX=MMC.SX;
+ register int SY=MMC.SY;
+ register int DX=MMC.DX;
+ register int DY=MMC.DY;
+ register int TX=MMC.TX;
+ register int TY=MMC.TY;
+ register int NX=MMC.NX;
+ register int NY=MMC.NY;
+ register int ASX=MMC.ASX;
+ register int ADX=MMC.ADX;
+ register int ANX=MMC.ANX;
+ register UINT8 LO=MMC.LO;
+ register int MXS = MMC.MXS;
+ register int MXD = MMC.MXD;
+ register int cnt;
+ register int delta;
+
+ delta = GetVdpTimingValue(lmmm_timing);
+ cnt = VdpOpsCnt;
+
+ switch (ScrMode) {
+ default:
+ case 5: pre_loop VDPpset5(MXD, ADX, DY, VDPpoint5(MXS, ASX, SY), LO); post_xxyy(256)
+ break;
+ case 6: pre_loop VDPpset6(MXD, ADX, DY, VDPpoint6(MXS, ASX, SY), LO); post_xxyy(512)
+ break;
+ case 7: pre_loop VDPpset7(MXD, ADX, DY, VDPpoint7(MXS, ASX, SY), LO); post_xxyy(512)
+ break;
+ case 8: pre_loop VDPpset8(MXD, ADX, DY, VDPpoint8(MXS, ASX, SY), LO); post_xxyy(256)
+ break;
+ }
+
+ if ((VdpOpsCnt=cnt)>0) {
+ /* Command execution done */
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ if (!NY) {
+ SY+=TY;
+ DY+=TY;
+ }
+ else
+ if (SY==-1)
+ DY+=TY;
+ VDP[42]=NY & 0xFF;
+ VDP[43]=(NY>>8) & 0x03;
+ VDP[34]=SY & 0xFF;
+ VDP[35]=(SY>>8) & 0x03;
+ VDP[38]=DY & 0xFF;
+ VDP[39]=(DY>>8) & 0x03;
+ }
+ else {
+ MMC.SY=SY;
+ MMC.DY=DY;
+ MMC.NY=NY;
+ MMC.ANX=ANX;
+ MMC.ASX=ASX;
+ MMC.ADX=ADX;
+ }
+}
+
+/** LmcmEngine() *********************************************/
+/** Vram -> CPU **/
+/*************************************************************/
+void LmcmEngine(void)
+{
+ if ((VDPStatus[2]&0x80)!=0x80) {
+
+ VDPStatus[7]=VDP[44]=VDP_POINT(((ScrMode >= 5) && (ScrMode <= 8)) ? (ScrMode-5) : 0, MMC.MXS, MMC.ASX, MMC.SY);
+ VdpOpsCnt-=GetVdpTimingValue(lmmv_timing);
+ VDPStatus[2]|=0x80;
+
+ if (!--MMC.ANX || ((MMC.ASX+=MMC.TX)&MMC.MX)) {
+ if (!(--MMC.NY & 1023) || (MMC.SY+=MMC.TY)==-1) {
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ if (!MMC.NY)
+ MMC.DY+=MMC.TY;
+ VDP[42]=MMC.NY & 0xFF;
+ VDP[43]=(MMC.NY>>8) & 0x03;
+ VDP[34]=MMC.SY & 0xFF;
+ VDP[35]=(MMC.SY>>8) & 0x03;
+ }
+ else {
+ MMC.ASX=MMC.SX;
+ MMC.ANX=MMC.NX;
+ }
+ }
+ }
+}
+
+/** LmmcEngine() *********************************************/
+/** CPU -> Vram **/
+/*************************************************************/
+void LmmcEngine(void)
+{
+ if ((VDPStatus[2]&0x80)!=0x80) {
+ register UINT8 SM=((ScrMode >= 5) && (ScrMode <= 8)) ? (ScrMode-5) : 0;
+
+ VDPStatus[7]=VDP[44]&=Mask[SM];
+ VDP_PSET(SM, MMC.MXD, MMC.ADX, MMC.DY, VDP[44], MMC.LO);
+ VdpOpsCnt-=GetVdpTimingValue(lmmv_timing);
+ VDPStatus[2]|=0x80;
+
+ if (!--MMC.ANX || ((MMC.ADX+=MMC.TX)&MMC.MX)) {
+ if (!(--MMC.NY&1023) || (MMC.DY+=MMC.TY)==-1) {
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ if (!MMC.NY)
+ MMC.DY+=MMC.TY;
+ VDP[42]=MMC.NY & 0xFF;
+ VDP[43]=(MMC.NY>>8) & 0x03;
+ VDP[38]=MMC.DY & 0xFF;
+ VDP[39]=(MMC.DY>>8) & 0x03;
+ }
+ else {
+ MMC.ADX=MMC.DX;
+ MMC.ANX=MMC.NX;
+ }
+ }
+ }
+}
+
+/** HmmvEngine() *********************************************/
+/** VDP --> Vram **/
+/*************************************************************/
+void HmmvEngine(void)
+{
+ register int DX=MMC.DX;
+ register int DY=MMC.DY;
+ register int TX=MMC.TX;
+ register int TY=MMC.TY;
+ register int NX=MMC.NX;
+ register int NY=MMC.NY;
+ register int ADX=MMC.ADX;
+ register int ANX=MMC.ANX;
+ register UINT8 CL=MMC.CL;
+ register int MXD = MMC.MXD;
+ register int cnt;
+ register int delta;
+
+ delta = GetVdpTimingValue(hmmv_timing);
+ cnt = VdpOpsCnt;
+
+ switch (ScrMode) {
+ default:
+ case 5: pre_loop *VDP_VRMP5(MXD, ADX, DY) = CL; post__x_y(256)
+ break;
+ case 6: pre_loop *VDP_VRMP6(MXD, ADX, DY) = CL; post__x_y(512)
+ break;
+ case 7: pre_loop *VDP_VRMP7(MXD, ADX, DY) = CL; post__x_y(512)
+ break;
+ case 8: pre_loop *VDP_VRMP8(MXD, ADX, DY) = CL; post__x_y(256)
+ break;
+ }
+
+ if ((VdpOpsCnt=cnt)>0) {
+ /* Command execution done */
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ if (!NY)
+ DY+=TY;
+ VDP[42]=NY & 0xFF;
+ VDP[43]=(NY>>8) & 0x03;
+ VDP[38]=DY & 0xFF;
+ VDP[39]=(DY>>8) & 0x03;
+ }
+ else {
+ MMC.DY=DY;
+ MMC.NY=NY;
+ MMC.ANX=ANX;
+ MMC.ADX=ADX;
+ }
+}
+
+/** HmmmEngine() *********************************************/
+/** Vram -> Vram **/
+/*************************************************************/
+void HmmmEngine(void)
+{
+ register int SX=MMC.SX;
+ register int SY=MMC.SY;
+ register int DX=MMC.DX;
+ register int DY=MMC.DY;
+ register int TX=MMC.TX;
+ register int TY=MMC.TY;
+ register int NX=MMC.NX;
+ register int NY=MMC.NY;
+ register int ASX=MMC.ASX;
+ register int ADX=MMC.ADX;
+ register int ANX=MMC.ANX;
+ register int MXS = MMC.MXS;
+ register int MXD = MMC.MXD;
+ register int cnt;
+ register int delta;
+
+ delta = GetVdpTimingValue(hmmm_timing);
+ cnt = VdpOpsCnt;
+
+ switch (ScrMode) {
+ default:
+ case 5: pre_loop *VDP_VRMP5(MXD, ADX, DY) = *VDP_VRMP5(MXS, ASX, SY); post_xxyy(256)
+ break;
+ case 6: pre_loop *VDP_VRMP6(MXD, ADX, DY) = *VDP_VRMP6(MXS, ASX, SY); post_xxyy(512)
+ break;
+ case 7: pre_loop *VDP_VRMP7(MXD, ADX, DY) = *VDP_VRMP7(MXS, ASX, SY); post_xxyy(512)
+ break;
+ case 8: pre_loop *VDP_VRMP8(MXD, ADX, DY) = *VDP_VRMP8(MXS, ASX, SY); post_xxyy(256)
+ break;
+ }
+
+ if ((VdpOpsCnt=cnt)>0) {
+ /* Command execution done */
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ if (!NY) {
+ SY+=TY;
+ DY+=TY;
+ }
+ else
+ if (SY==-1)
+ DY+=TY;
+ VDP[42]=NY & 0xFF;
+ VDP[43]=(NY>>8) & 0x03;
+ VDP[34]=SY & 0xFF;
+ VDP[35]=(SY>>8) & 0x03;
+ VDP[38]=DY & 0xFF;
+ VDP[39]=(DY>>8) & 0x03;
+ }
+ else {
+ MMC.SY=SY;
+ MMC.DY=DY;
+ MMC.NY=NY;
+ MMC.ANX=ANX;
+ MMC.ASX=ASX;
+ MMC.ADX=ADX;
+ }
+}
+
+/** YmmmEngine() *********************************************/
+/** Vram -> Vram **/
+/*************************************************************/
+void YmmmEngine(void)
+{
+ register int SY=MMC.SY;
+ register int DX=MMC.DX;
+ register int DY=MMC.DY;
+ register int TX=MMC.TX;
+ register int TY=MMC.TY;
+ register int NY=MMC.NY;
+ register int ADX=MMC.ADX;
+ register int MXD = MMC.MXD;
+ register int cnt;
+ register int delta;
+
+ delta = GetVdpTimingValue(ymmm_timing);
+ cnt = VdpOpsCnt;
+
+ switch (ScrMode) {
+ default:
+ case 5: pre_loop *VDP_VRMP5(MXD, ADX, DY) = *VDP_VRMP5(MXD, ADX, SY); post__xyy(256)
+ break;
+ case 6: pre_loop *VDP_VRMP6(MXD, ADX, DY) = *VDP_VRMP6(MXD, ADX, SY); post__xyy(512)
+ break;
+ case 7: pre_loop *VDP_VRMP7(MXD, ADX, DY) = *VDP_VRMP7(MXD, ADX, SY); post__xyy(512)
+ break;
+ case 8: pre_loop *VDP_VRMP8(MXD, ADX, DY) = *VDP_VRMP8(MXD, ADX, SY); post__xyy(256)
+ break;
+ }
+
+ if ((VdpOpsCnt=cnt)>0) {
+ /* Command execution done */
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ if (!NY) {
+ SY+=TY;
+ DY+=TY;
+ }
+ else
+ if (SY==-1)
+ DY+=TY;
+ VDP[42]=NY & 0xFF;
+ VDP[43]=(NY>>8) & 0x03;
+ VDP[34]=SY & 0xFF;
+ VDP[35]=(SY>>8) & 0x03;
+ VDP[38]=DY & 0xFF;
+ VDP[39]=(DY>>8) & 0x03;
+ }
+ else {
+ MMC.SY=SY;
+ MMC.DY=DY;
+ MMC.NY=NY;
+ MMC.ADX=ADX;
+ }
+}
+
+/** HmmcEngine() *********************************************/
+/** CPU -> Vram **/
+/*************************************************************/
+void HmmcEngine(void)
+{
+ if ((VDPStatus[2]&0x80)!=0x80) {
+
+ *VDP_VRMP(((ScrMode >= 5) && (ScrMode <= 8)) ? (ScrMode-5) : 0, MMC.MXD, MMC.ADX, MMC.DY)=VDP[44];
+ VdpOpsCnt-=GetVdpTimingValue(hmmv_timing);
+ VDPStatus[2]|=0x80;
+
+ if (!--MMC.ANX || ((MMC.ADX+=MMC.TX)&MMC.MX)) {
+ if (!(--MMC.NY&1023) || (MMC.DY+=MMC.TY)==-1) {
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ if (!MMC.NY)
+ MMC.DY+=MMC.TY;
+ VDP[42]=MMC.NY & 0xFF;
+ VDP[43]=(MMC.NY>>8) & 0x03;
+ VDP[38]=MMC.DY & 0xFF;
+ VDP[39]=(MMC.DY>>8) & 0x03;
+ }
+ else {
+ MMC.ADX=MMC.DX;
+ MMC.ANX=MMC.NX;
+ }
+ }
+ }
+}
+
+/** VDPWrite() ***********************************************/
+/** Use this function to transfer pixel(s) from CPU to VDP. **/
+/*************************************************************/
+static void v9938_cpu_to_vdp (UINT8 V)
+{
+ VDPStatus[2]&=0x7F;
+ VDPStatus[7]=VDP[44]=V;
+ if(VdpEngine&&(VdpOpsCnt>0)) VdpEngine();
+}
+
+/** VDPRead() ************************************************/
+/** Use this function to transfer pixel(s) from VDP to CPU. **/
+/*************************************************************/
+static UINT8 v9938_vdp_to_cpu (void)
+{
+ VDPStatus[2]&=0x7F;
+ if(VdpEngine&&(VdpOpsCnt>0)) VdpEngine();
+ return(VDP[44]);
+}
+
+/** ReportVdpCommand() ***************************************/
+/** Report VDP Command to be executed **/
+/*************************************************************/
+static void ReportVdpCommand(register UINT8 Op)
+{
+ static const char *Ops[16] =
+ {
+ "SET ","AND ","OR ","XOR ","NOT ","NOP ","NOP ","NOP ",
+ "TSET","TAND","TOR ","TXOR","TNOT","NOP ","NOP ","NOP "
+ };
+ static const char *Commands[16] =
+ {
+ " ABRT"," ????"," ????"," ????","POINT"," PSET"," SRCH"," LINE",
+ " LMMV"," LMMM"," LMCM"," LMMC"," HMMV"," HMMM"," YMMM"," HMMC"
+ };
+
+ register UINT8 CL, CM, LO;
+ register int SX,SY, DX,DY, NX,NY;
+
+ /* Fetch arguments */
+ CL = VDP[44];
+ SX = (VDP[32]+((int)VDP[33]<<8)) & 511;
+ SY = (VDP[34]+((int)VDP[35]<<8)) & 1023;
+ DX = (VDP[36]+((int)VDP[37]<<8)) & 511;
+ DY = (VDP[38]+((int)VDP[39]<<8)) & 1023;
+ NX = (VDP[40]+((int)VDP[41]<<8)) & 1023;
+ NY = (VDP[42]+((int)VDP[43]<<8)) & 1023;
+ CM = Op>>4;
+ LO = Op&0x0F;
+
+ logerror ("V9938: Opcode %02Xh %s-%s (%d,%d)->(%d,%d),%d [%d,%d]%s\n",
+ Op, Commands[CM], Ops[LO],
+ SX,SY, DX,DY, CL, VDP[45]&0x04? -NX:NX,
+ VDP[45]&0x08? -NY:NY,
+ VDP[45]&0x70? " on ExtVRAM":""
+ );
+}
+
+/** VDPDraw() ************************************************/
+/** Perform a given V9938 operation Op. **/
+/*************************************************************/
+static UINT8 v9938_command_unit_w (UINT8 Op)
+{
+ register int SM;
+
+ /* V9938 ops only work in SCREENs 5-8 */
+ if (ScrMode<5)
+ return(0);
+
+ SM = ScrMode-5; /* Screen mode index 0..3 */
+
+ MMC.CM = Op>>4;
+ if ((MMC.CM & 0x0C) != 0x0C && MMC.CM != 0)
+ /* Dot operation: use only relevant bits of color */
+ VDPStatus[7]=(VDP[44]&=Mask[SM]);
+
+/* if(Verbose&0x02) */
+ ReportVdpCommand(Op);
+
+ switch(Op>>4) {
+ case CM_ABRT:
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ return 1;
+ case CM_POINT:
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ VDPStatus[7]=VDP[44]=
+ VDP_POINT(SM, (VDP[45] & 0x10) != 0,
+ VDP[32]+((int)VDP[33]<<8),
+ VDP[34]+((int)VDP[35]<<8));
+ return 1;
+ case CM_PSET:
+ VDPStatus[2]&=0xFE;
+ VdpEngine=0;
+ VDP_PSET(SM, (VDP[45] & 0x20) != 0,
+ VDP[36]+((int)VDP[37]<<8),
+ VDP[38]+((int)VDP[39]<<8),
+ VDP[44],
+ Op&0x0F);
+ return 1;
+ case CM_SRCH:
+ VdpEngine=SrchEngine;
+ break;
+ case CM_LINE:
+ VdpEngine=LineEngine;
+ break;
+ case CM_LMMV:
+ VdpEngine=LmmvEngine;
+ break;
+ case CM_LMMM:
+ VdpEngine=LmmmEngine;
+ break;
+ case CM_LMCM:
+ VdpEngine=LmcmEngine;
+ break;
+ case CM_LMMC:
+ VdpEngine=LmmcEngine;
+ break;
+ case CM_HMMV:
+ VdpEngine=HmmvEngine;
+ break;
+ case CM_HMMM:
+ VdpEngine=HmmmEngine;
+ break;
+ case CM_YMMM:
+ VdpEngine=YmmmEngine;
+ break;
+ case CM_HMMC:
+ VdpEngine=HmmcEngine;
+ break;
+ default:
+ logerror("V9938: Unrecognized opcode %02Xh\n",Op);
+ return(0);
+ }
+
+ /* Fetch unconditional arguments */
+ MMC.SX = (VDP[32]+((int)VDP[33]<<8)) & 511;
+ MMC.SY = (VDP[34]+((int)VDP[35]<<8)) & 1023;
+ MMC.DX = (VDP[36]+((int)VDP[37]<<8)) & 511;
+ MMC.DY = (VDP[38]+((int)VDP[39]<<8)) & 1023;
+ MMC.NY = (VDP[42]+((int)VDP[43]<<8)) & 1023;
+ MMC.TY = VDP[45]&0x08? -1:1;
+ MMC.MX = PPL[SM];
+ MMC.CL = VDP[44];
+ MMC.LO = Op&0x0F;
+ MMC.MXS = (VDP[45] & 0x10) != 0;
+ MMC.MXD = (VDP[45] & 0x20) != 0;
+
+ /* Argument depends on UINT8 or dot operation */
+ if ((MMC.CM & 0x0C) == 0x0C) {
+ MMC.TX = VDP[45]&0x04? -PPB[SM]:PPB[SM];
+ MMC.NX = ((VDP[40]+((int)VDP[41]<<8)) & 1023)/PPB[SM];
+ }
+ else {
+ MMC.TX = VDP[45]&0x04? -1:1;
+ MMC.NX = (VDP[40]+((int)VDP[41]<<8)) & 1023;
+ }
+
+ /* X loop variables are treated specially for LINE command */
+ if (MMC.CM == CM_LINE) {
+ MMC.ASX=((MMC.NX-1)>>1);
+ MMC.ADX=0;
+ }
+ else {
+ MMC.ASX = MMC.SX;
+ MMC.ADX = MMC.DX;
+ }
+
+ /* NX loop variable is treated specially for SRCH command */
+ if (MMC.CM == CM_SRCH)
+ MMC.ANX=(VDP[45]&0x02)!=0; /* Do we look for "==" or "!="? */
+ else
+ MMC.ANX = MMC.NX;
+
+ /* Command execution started */
+ VDPStatus[2]|=0x01;
+
+ /* Start execution if we still have time slices */
+ if(VdpEngine&&(VdpOpsCnt>0)) VdpEngine();
+
+ /* Operation successfull initiated */
+ return(1);
+}
+
+/** LoopVDP() ************************************************/
+/** Run X steps of active VDP command **/
+/*************************************************************/
+static void v9938_update_command (void)
+{
+ if(VdpOpsCnt<=0)
+ {
+ VdpOpsCnt+=13662;
+ if(VdpEngine&&(VdpOpsCnt>0)) VdpEngine();
+ }
+ else
+ {
+ VdpOpsCnt=13662;
+ if(VdpEngine) VdpEngine();
+ }
+}
+
diff --git a/src/emu/video/v9938.h b/src/emu/video/v9938.h
new file mode 100644
index 00000000000..015fd2b8d91
--- /dev/null
+++ b/src/emu/video/v9938.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+
+ v9938 / v9958 emulation
+
+***************************************************************************/
+
+/* init functions */
+
+#define MODEL_V9938 (0)
+#define MODEL_V9958 (1)
+
+/* resolutions */
+#define RENDER_HIGH (0)
+#define RENDER_LOW (1)
+#define RENDER_AUTO (2)
+
+void v9938_init (running_machine *, int, int, void (*callback)(int));
+void v9938_reset (void);
+int v9938_interrupt (void);
+void v9938_set_sprite_limit (int);
+void v9938_set_resolution (int);
+
+extern PALETTE_INIT( v9938 );
+extern PALETTE_INIT( v9958 );
+extern WRITE8_HANDLER( v9938_palette_w );
+extern WRITE8_HANDLER( v9938_vram_w );
+extern READ8_HANDLER( v9938_vram_r );
+extern WRITE8_HANDLER( v9938_command_w );
+extern READ8_HANDLER( v9938_status_r );
+extern WRITE8_HANDLER( v9938_register_w );
+
+void v9938_update_mouse_state(int mx_delta, int my_delta, int button_state);
diff --git a/src/emu/video/v9938mod.c b/src/emu/video/v9938mod.c
new file mode 100644
index 00000000000..8190bfacb01
--- /dev/null
+++ b/src/emu/video/v9938mod.c
@@ -0,0 +1,736 @@
+/*
+ * This file is included for a number of different situations:
+ * V9938_WIDTH : can be 512 + 32 or 256 + 16
+ * V9938_BPP : can be 8 or 16
+ */
+
+#if (V9938_WIDTH < 512)
+ #if (V9938_BPP == 8)
+ #define PEN_TYPE UINT8
+ #define FNAME(name) v9938_##name##_8s
+ #else
+ #define PEN_TYPE UINT16
+ #define FNAME(name) v9938_##name##_16s
+ #endif
+#else
+ #if (V9938_BPP == 8)
+ #define PEN_TYPE UINT8
+ #define FNAME(name) v9938_##name##_8
+ #else
+ #define PEN_TYPE UINT16
+ #define FNAME(name) v9938_##name##_16
+ #endif
+#endif
+
+
+#define V9938_BORDER_FUNC(name) \
+ static void FNAME (name) (PEN_TYPE *ln)
+
+#define V9938_MODE_FUNC(name) \
+ static void FNAME (name) (PEN_TYPE *ln, int line)
+
+#define V9938_SPRITE_FUNC(name) \
+ static void FNAME (name) (PEN_TYPE *ln, UINT8 *col)
+
+V9938_BORDER_FUNC (default_border)
+ {
+ PEN_TYPE pen;
+ int i;
+
+ pen = Machine->pens[pal_ind16[(vdp.contReg[7]&0x0f)]];
+ i = V9938_WIDTH;
+ while (i--) *ln++ = pen;
+
+ if (vdp.size_now != RENDER_HIGH) vdp.size_now = RENDER_LOW;
+ }
+
+V9938_BORDER_FUNC (graphic7_border)
+ {
+ PEN_TYPE pen;
+ int i;
+
+ pen = Machine->pens[pal_ind256[vdp.contReg[7]]];
+ i = V9938_WIDTH;
+ while (i--) *ln++ = pen;
+
+ if (vdp.size_now != RENDER_HIGH) vdp.size_now = RENDER_LOW;
+ }
+
+V9938_BORDER_FUNC (graphic5_border)
+ {
+ int i;
+ PEN_TYPE pen0;
+#if (V9938_WIDTH > 512)
+ PEN_TYPE pen1;
+
+ pen1 = Machine->pens[pal_ind16[(vdp.contReg[7]&0x03)]];
+ pen0 = Machine->pens[pal_ind16[((vdp.contReg[7]>>2)&0x03)]];
+ i = (V9938_WIDTH) / 2;
+ while (i--) { *ln++ = pen0; *ln++ = pen1; }
+#else
+ pen0 = Machine->pens[pal_ind16[((vdp.contReg[7]>>2)&0x03)]];
+ i = V9938_WIDTH;
+ while (i--) *ln++ = pen0;
+#endif
+ vdp.size_now = RENDER_HIGH;
+ }
+
+V9938_MODE_FUNC (mode_text1)
+ {
+ int pattern, x, xx, name, xxx;
+ PEN_TYPE fg, bg, pen;
+ UINT8 *nametbl, *patterntbl;
+
+ patterntbl = vdp.vram + (vdp.contReg[4] << 11);
+ nametbl = vdp.vram + (vdp.contReg[2] << 10);
+
+ fg = Machine->pens[pal_ind16[vdp.contReg[7] >> 4]];
+ bg = Machine->pens[pal_ind16[vdp.contReg[7] & 15]];
+
+ name = (line/8)*40;
+
+ pen = Machine->pens[pal_ind16[(vdp.contReg[7]&0x0f)]];
+
+ xxx = vdp.offset_x + 8;
+#if (V9938_WIDTH > 512)
+ xxx *= 2;
+#endif
+ while (xxx--) *ln++ = pen;
+
+ for (x=0;x<40;x++)
+ {
+ pattern = patterntbl[(nametbl[name] * 8) +
+ ((line + vdp.contReg[23]) & 7)];
+ for (xx=0;xx<6;xx++)
+ {
+ *ln++ = (pattern & 0x80) ? fg : bg;
+#if (V9938_WIDTH > 512)
+ *ln++ = (pattern & 0x80) ? fg : bg;
+#endif
+ pattern <<= 1;
+ }
+ /* width height 212, characters start repeating at the bottom */
+ name = (name + 1) & 0x3ff;
+ }
+
+ xxx = (16 - vdp.offset_x) + 8;
+#if (V9938_WIDTH > 512)
+ xxx *= 2;
+#endif
+ while (xxx--) *ln++ = pen;
+ if (vdp.size_now != RENDER_HIGH) vdp.size_now = RENDER_LOW;
+ }
+
+V9938_MODE_FUNC (mode_text2)
+ {
+ int pattern, x, charcode, name, xxx, patternmask, colourmask;
+ PEN_TYPE fg, bg, fg0, bg0, pen;
+ UINT8 *nametbl, *patterntbl, *colourtbl;
+
+ patterntbl = vdp.vram + (vdp.contReg[4] << 11);
+ colourtbl = vdp.vram + ((vdp.contReg[3] & 0xf8) << 6) + (vdp.contReg[10] << 14);
+#if 0
+ colourmask = ((vdp.contReg[3] & 7) << 5) | 0x1f; /* cause a bug in Forth+ v1.0 on Geneve */
+#else
+ colourmask = ((vdp.contReg[3] & 7) << 6) | 0x3f; /* verify! */
+#endif
+ nametbl = vdp.vram + ((vdp.contReg[2] & 0xfc) << 10);
+ patternmask = ((vdp.contReg[2] & 3) << 10) | 0x3ff; /* seems correct */
+
+ fg = Machine->pens[pal_ind16[vdp.contReg[7] >> 4]];
+ bg = Machine->pens[pal_ind16[vdp.contReg[7] & 15]];
+ fg0 = Machine->pens[pal_ind16[vdp.contReg[12] >> 4]];
+ bg0 = Machine->pens[pal_ind16[vdp.contReg[12] & 15]];
+
+ name = (line/8)*80;
+
+ xxx = vdp.offset_x + 8;
+ pen = Machine->pens[pal_ind16[(vdp.contReg[7]&0x0f)]];
+#if (V9938_WIDTH > 512)
+ xxx *= 2;
+#endif
+ while (xxx--) *ln++ = pen;
+
+ for (x=0;x<80;x++)
+ {
+ charcode = nametbl[name&patternmask];
+ if (vdp.blink)
+ {
+ pattern = colourtbl[(name/8)&colourmask];
+ if (pattern & (0x80 >> (name & 7) ) )
+ {
+ pattern = patterntbl[(charcode * 8) +
+ ((line + vdp.contReg[23]) & 7)];
+
+#if (V9938_WIDTH > 512)
+ *ln++ = (pattern & 0x80) ? fg0 : bg0;
+ *ln++ = (pattern & 0x40) ? fg0 : bg0;
+ *ln++ = (pattern & 0x20) ? fg0 : bg0;
+ *ln++ = (pattern & 0x10) ? fg0 : bg0;
+ *ln++ = (pattern & 0x08) ? fg0 : bg0;
+ *ln++ = (pattern & 0x04) ? fg0 : bg0;
+#else
+ *ln++ = (pattern & 0x80) ? fg0 : bg0;
+ *ln++ = (pattern & 0x20) ? fg0 : bg0;
+ *ln++ = (pattern & 0x08) ? fg0 : bg0;
+#endif
+
+ name++;
+ continue;
+ }
+ }
+
+ pattern = patterntbl[(charcode * 8) +
+ ((line + vdp.contReg[23]) & 7)];
+
+#if (V9938_WIDTH > 512)
+ *ln++ = (pattern & 0x80) ? fg : bg;
+ *ln++ = (pattern & 0x40) ? fg : bg;
+ *ln++ = (pattern & 0x20) ? fg : bg;
+ *ln++ = (pattern & 0x10) ? fg : bg;
+ *ln++ = (pattern & 0x08) ? fg : bg;
+ *ln++ = (pattern & 0x04) ? fg : bg;
+#else
+ *ln++ = (pattern & 0x80) ? fg : bg;
+ *ln++ = (pattern & 0x20) ? fg : bg;
+ *ln++ = (pattern & 0x08) ? fg : bg;
+#endif
+
+ name++;
+ }
+
+ xxx = 16 - vdp.offset_x + 8;
+#if (V9938_WIDTH > 512)
+ xxx *= 2;
+#endif
+ while (xxx--) *ln++ = pen;
+ vdp.size_now = RENDER_HIGH;
+ }
+
+V9938_MODE_FUNC (mode_multi)
+ {
+ UINT8 *nametbl, *patterntbl, colour;
+ int name, line2, x, xx;
+ PEN_TYPE pen, pen_bg;
+
+ nametbl = vdp.vram + (vdp.contReg[2] << 10);
+ patterntbl = vdp.vram + (vdp.contReg[4] << 11);
+
+ line2 = (line - vdp.contReg[23]) & 255;
+ name = (line2/8)*32;
+
+ pen_bg = Machine->pens[pal_ind16[(vdp.contReg[7]&0x0f)]];
+#if (V9938_WIDTH < 512)
+ xx = vdp.offset_x;
+#else
+ xx = vdp.offset_x * 2;
+#endif
+ while (xx--) *ln++ = pen_bg;
+
+ for (x=0;x<32;x++)
+ {
+ colour = patterntbl[(nametbl[name] * 8) + ((line2/4)&7)];
+ pen = Machine->pens[pal_ind16[colour>>4]];
+ /* eight pixels */
+ *ln++ = pen;
+ *ln++ = pen;
+ *ln++ = pen;
+ *ln++ = pen;
+#if (V9938_WIDTH > 512)
+ *ln++ = pen;
+ *ln++ = pen;
+ *ln++ = pen;
+ *ln++ = pen;
+#endif
+ pen = Machine->pens[pal_ind16[colour&15]];
+ /* eight pixels */
+ *ln++ = pen;
+ *ln++ = pen;
+ *ln++ = pen;
+ *ln++ = pen;
+#if (V9938_WIDTH > 512)
+ *ln++ = pen;
+ *ln++ = pen;
+ *ln++ = pen;
+ *ln++ = pen;
+#endif
+ name++;
+ }
+
+ xx = 16 - vdp.offset_x;
+#if (V9938_WIDTH > 512)
+ xx *= 2;
+#endif
+ while (xx--) *ln++ = pen_bg;
+ if (vdp.size_now != RENDER_HIGH) vdp.size_now = RENDER_LOW;
+ }
+
+V9938_MODE_FUNC (mode_graphic1)
+ {
+ PEN_TYPE fg, bg, pen;
+ UINT8 *nametbl, *patterntbl, *colourtbl;
+ int pattern, x, xx, line2, name, charcode, colour, xxx;
+
+ nametbl = vdp.vram + (vdp.contReg[2] << 10);
+ colourtbl = vdp.vram + (vdp.contReg[3] << 6) + (vdp.contReg[10] << 14);
+ patterntbl = vdp.vram + (vdp.contReg[4] << 11);
+
+ line2 = (line - vdp.contReg[23]) & 255;
+
+ name = (line2/8)*32;
+
+ pen = Machine->pens[pal_ind16[(vdp.contReg[7]&0x0f)]];
+#if (V9938_WIDTH < 512)
+ xxx = vdp.offset_x;
+#else
+ xxx = vdp.offset_x * 2;
+#endif
+ while (xxx--) *ln++ = pen;
+
+ for (x=0;x<32;x++)
+ {
+ charcode = nametbl[name];
+ colour = colourtbl[charcode/8];
+ fg = Machine->pens[pal_ind16[colour>>4]];
+ bg = Machine->pens[pal_ind16[colour&15]];
+ pattern = patterntbl[charcode * 8 + (line2 & 7)];
+
+ for (xx=0;xx<8;xx++)
+ {
+ *ln++ = (pattern & 0x80) ? fg : bg;
+#if (V9938_WIDTH > 512)
+ *ln++ = (pattern & 0x80) ? fg : bg;
+#endif
+ pattern <<= 1;
+ }
+ name++;
+ }
+
+ xx = 16 - vdp.offset_x;
+#if (V9938_WIDTH > 512)
+ xx *= 2;
+#endif
+ while (xx--) *ln++ = pen;
+ if (vdp.size_now != RENDER_HIGH) vdp.size_now = RENDER_LOW;
+ }
+
+V9938_MODE_FUNC (mode_graphic23)
+ {
+ PEN_TYPE fg, bg, pen;
+ UINT8 *nametbl, *patterntbl, *colourtbl;
+ int pattern, x, xx, line2, name, charcode,
+ colour, colourmask, patternmask, xxx;
+
+ colourmask = (vdp.contReg[3] & 0x7f) * 8 | 7;
+ patternmask = (vdp.contReg[4] & 0x03) * 256 | (colourmask & 255);
+
+ nametbl = vdp.vram + (vdp.contReg[2] << 10);
+ colourtbl = vdp.vram + ((vdp.contReg[3] & 0x80) << 6) + (vdp.contReg[10] << 14);
+ patterntbl = vdp.vram + ((vdp.contReg[4] & 0x3c) << 11);
+
+ line2 = (line + vdp.contReg[23]) & 255;
+ name = (line2/8)*32;
+
+ pen = Machine->pens[pal_ind16[(vdp.contReg[7]&0x0f)]];
+#if (V9938_WIDTH < 512)
+ xxx = vdp.offset_x;
+#else
+ xxx = vdp.offset_x * 2;
+#endif
+ while (xxx--) *ln++ = pen;
+
+ for (x=0;x<32;x++)
+ {
+ charcode = nametbl[name] + (line2&0xc0)*4;
+ colour = colourtbl[(charcode&colourmask)*8+(line2&7)];
+ pattern = patterntbl[(charcode&patternmask)*8+(line2&7)];
+ fg = Machine->pens[pal_ind16[colour>>4]];
+ bg = Machine->pens[pal_ind16[colour&15]];
+ for (xx=0;xx<8;xx++)
+ {
+ *ln++ = (pattern & 0x80) ? fg : bg;
+#if (V9938_WIDTH > 512)
+ *ln++ = (pattern & 0x80) ? fg : bg;
+#endif
+ pattern <<= 1;
+ }
+ name++;
+ }
+
+ xx = 16 - vdp.offset_x;
+#if (V9938_WIDTH > 512)
+ xx *= 2;
+#endif
+ while (xx--) *ln++ = pen;
+ if (vdp.size_now != RENDER_HIGH) vdp.size_now = RENDER_LOW;
+ }
+
+V9938_MODE_FUNC (mode_graphic4)
+ {
+ UINT8 *nametbl, colour;
+ int line2, linemask, x, xx;
+ PEN_TYPE pen, pen_bg;
+
+ linemask = ((vdp.contReg[2] & 0x1f) << 3) | 7;
+
+ line2 = ((line + vdp.contReg[23]) & linemask) & 255;
+
+ nametbl = vdp.vram + ((vdp.contReg[2] & 0x40) << 10) + line2 * 128;
+ if ( (vdp.contReg[2] & 0x20) && (V9938_SECOND_FIELD) )
+ nametbl += 0x8000;
+
+ pen_bg = Machine->pens[pal_ind16[(vdp.contReg[7]&0x0f)]];
+#if (V9938_WIDTH < 512)
+ xx = vdp.offset_x;
+#else
+ xx = vdp.offset_x * 2;
+#endif
+ while (xx--) *ln++ = pen_bg;
+
+ for (x=0;x<128;x++)
+ {
+ colour = *nametbl++;
+ pen = Machine->pens[pal_ind16[colour>>4]];
+ *ln++ = pen;
+#if (V9938_WIDTH > 512)
+ *ln++ = pen;
+#endif
+ pen = Machine->pens[pal_ind16[colour&15]];
+ *ln++ = pen;
+#if (V9938_WIDTH > 512)
+ *ln++ = pen;
+#endif
+ }
+
+ xx = 16 - vdp.offset_x;
+#if (V9938_WIDTH > 512)
+ xx *= 2;
+#endif
+ while (xx--) *ln++ = pen_bg;
+ if (vdp.size_now != RENDER_HIGH) vdp.size_now = RENDER_LOW;
+ }
+
+V9938_MODE_FUNC (mode_graphic5)
+ {
+ UINT8 *nametbl, colour;
+ int line2, linemask, x, xx;
+ PEN_TYPE pen_bg0[4];
+#if (V9938_WIDTH > 512)
+ PEN_TYPE pen_bg1[4];
+#endif
+
+ linemask = ((vdp.contReg[2] & 0x1f) << 3) | 7;
+
+ line2 = ((line + vdp.contReg[23]) & linemask) & 255;
+
+ nametbl = vdp.vram + ((vdp.contReg[2] & 0x40) << 10) + line2 * 128;
+ if ( (vdp.contReg[2] & 0x20) && (V9938_SECOND_FIELD) )
+ nametbl += 0x8000;
+
+#if (V9938_WIDTH > 512)
+ pen_bg1[0] = Machine->pens[pal_ind16[(vdp.contReg[7]&0x03)]];
+ pen_bg0[0] = Machine->pens[pal_ind16[((vdp.contReg[7]>>2)&0x03)]];
+
+ xx = vdp.offset_x;
+ while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; }
+
+ x = (vdp.contReg[8] & 0x20) ? 0 : 1;
+
+ for (;x<4;x++)
+ {
+ pen_bg0[x] = Machine->pens[pal_ind16[x]];
+ pen_bg1[x] = Machine->pens[pal_ind16[x]];
+ }
+
+ for (x=0;x<128;x++)
+ {
+ colour = *nametbl++;
+
+ *ln++ = pen_bg0[colour>>6];
+ *ln++ = pen_bg1[(colour>>4)&3];
+ *ln++ = pen_bg0[(colour>>2)&3];
+ *ln++ = pen_bg1[(colour&3)];
+ }
+
+ pen_bg1[0] = Machine->pens[pal_ind16[(vdp.contReg[7]&0x03)]];
+ pen_bg0[0] = Machine->pens[pal_ind16[((vdp.contReg[7]>>2)&0x03)]];
+ xx = 16 - vdp.offset_x;
+ while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; }
+#else
+ pen_bg0[0] = Machine->pens[pal_ind16[((vdp.contReg[7]>>2)&0x03)]];
+
+ x = (vdp.contReg[8] & 0x20) ? 0 : 1;
+
+ for (;x<4;x++)
+ pen_bg0[x] = Machine->pens[pal_ind16[x]];
+
+ xx = vdp.offset_x;
+ while (xx--) *ln++ = pen_bg0[0];
+
+ for (x=0;x<128;x++)
+ {
+ colour = *nametbl++;
+ *ln++ = pen_bg0[colour>>6];
+ *ln++ = pen_bg0[(colour>>2)&3];
+ }
+
+ pen_bg0[0] = Machine->pens[pal_ind16[((vdp.contReg[7]>>2)&0x03)]];
+ xx = 16 - vdp.offset_x;
+ while (xx--) *ln++ = pen_bg0[0];
+#endif
+ vdp.size_now = RENDER_HIGH;
+ }
+
+V9938_MODE_FUNC (mode_graphic6)
+ {
+ UINT8 colour;
+ int line2, linemask, x, xx, nametbl;
+ PEN_TYPE pen_bg, fg0;
+#if (V9938_WIDTH > 512)
+ PEN_TYPE fg1;
+#endif
+
+ linemask = ((vdp.contReg[2] & 0x1f) << 3) | 7;
+
+ line2 = ((line + vdp.contReg[23]) & linemask) & 255;
+
+ nametbl = line2 << 8 ;
+ if ( (vdp.contReg[2] & 0x20) && (V9938_SECOND_FIELD) )
+ nametbl += 0x10000;
+
+ pen_bg = Machine->pens[pal_ind16[(vdp.contReg[7]&0x0f)]];
+#if (V9938_WIDTH < 512)
+ xx = vdp.offset_x;
+#else
+ xx = vdp.offset_x * 2;
+#endif
+ while (xx--) *ln++ = pen_bg;
+
+ if (vdp.contReg[2] & 0x40)
+ {
+ for (x=0;x<32;x++)
+ {
+ nametbl++;
+ colour = vdp.vram[((nametbl&1) << 16) | (nametbl>>1)];
+ fg0 = Machine->pens[pal_ind16[colour>>4]];
+#if (V9938_WIDTH < 512)
+ *ln++ = fg0; *ln++ = fg0;
+ *ln++ = fg0; *ln++ = fg0;
+ *ln++ = fg0; *ln++ = fg0;
+ *ln++ = fg0; *ln++ = fg0;
+#else
+ fg1 = Machine->pens[pal_ind16[colour&15]];
+ *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
+ *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
+ *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
+ *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
+#endif
+ nametbl += 7;
+ }
+ }
+ else
+ {
+ for (x=0;x<256;x++)
+ {
+ colour = vdp.vram[((nametbl&1) << 16) | (nametbl>>1)];
+ *ln++ = Machine->pens[pal_ind16[colour>>4]];
+#if (V9938_WIDTH > 512)
+ *ln++ = Machine->pens[pal_ind16[colour&15]];
+#endif
+ nametbl++;
+ }
+ }
+
+ xx = 16 - vdp.offset_x;
+#if (V9938_WIDTH > 512)
+ xx *= 2;
+#endif
+ while (xx--) *ln++ = pen_bg;
+ vdp.size_now = RENDER_HIGH;
+ }
+
+V9938_MODE_FUNC (mode_graphic7)
+ {
+ UINT8 colour;
+ int line2, linemask, x, xx, nametbl;
+ PEN_TYPE pen, pen_bg;
+
+ linemask = ((vdp.contReg[2] & 0x1f) << 3) | 7;
+
+ line2 = ((line + vdp.contReg[23]) & linemask) & 255;
+
+ nametbl = line2 << 8;
+ if ( (vdp.contReg[2] & 0x20) && (V9938_SECOND_FIELD) )
+ nametbl += 0x10000;
+
+ pen_bg = Machine->pens[pal_ind256[vdp.contReg[7]]];
+#if (V9938_WIDTH < 512)
+ xx = vdp.offset_x;
+#else
+ xx = vdp.offset_x * 2;
+#endif
+ while (xx--) *ln++ = pen_bg;
+
+ if (vdp.contReg[2] & 0x40)
+ {
+ for (x=0;x<32;x++)
+ {
+ nametbl++;
+ colour = vdp.vram[((nametbl&1) << 16) | (nametbl>>1)];
+ pen = Machine->pens[pal_ind256[colour]];
+ *ln++ = pen; *ln++ = pen;
+ *ln++ = pen; *ln++ = pen;
+ *ln++ = pen; *ln++ = pen;
+ *ln++ = pen; *ln++ = pen;
+#if (V9938_WIDTH > 512)
+ *ln++ = pen; *ln++ = pen;
+ *ln++ = pen; *ln++ = pen;
+ *ln++ = pen; *ln++ = pen;
+ *ln++ = pen; *ln++ = pen;
+#endif
+ nametbl++;
+ }
+ }
+ else
+ {
+ for (x=0;x<256;x++)
+ {
+ colour = vdp.vram[((nametbl&1) << 16) | (nametbl>>1)];
+ pen = Machine->pens[pal_ind256[colour]];
+ *ln++ = pen;
+#if (V9938_WIDTH > 512)
+ *ln++ = pen;
+#endif
+ nametbl++;
+ }
+ }
+
+ xx = 16 - vdp.offset_x;
+#if (V9938_WIDTH > 512)
+ xx *= 2;
+#endif
+ while (xx--) *ln++ = pen_bg;
+ if (vdp.size_now != RENDER_HIGH) vdp.size_now = RENDER_LOW;
+ }
+
+V9938_MODE_FUNC (mode_unknown)
+ {
+ PEN_TYPE fg, bg;
+ int x;
+
+ fg = Machine->pens[pal_ind16[vdp.contReg[7] >> 4]];
+ bg = Machine->pens[pal_ind16[vdp.contReg[7] & 15]];
+
+#if (V9938_WIDTH < 512)
+ x = vdp.offset_x;
+ while (x--) *ln++ = bg;
+
+ x = 256;
+ while (x--) *ln++ = fg;
+
+ x = 16 - vdp.offset_x;
+ while (x--) *ln++ = bg;
+#else
+ x = vdp.offset_x * 2;
+ while (x--) *ln++ = bg;
+
+ x = 512;
+ while (x--) *ln++ = fg;
+
+ x = (16 - vdp.offset_x) * 2;
+ while (x--) *ln++ = bg;
+#endif
+ if (vdp.size_now != RENDER_HIGH) vdp.size_now = RENDER_LOW;
+ }
+
+V9938_SPRITE_FUNC (default_draw_sprite)
+ {
+ int i;
+#if (V9938_WIDTH > 512)
+ ln += vdp.offset_x * 2;
+#else
+ ln += vdp.offset_x;
+#endif
+
+ for (i=0;i<256;i++)
+ {
+ if (col[i] & 0x80)
+ {
+ *ln++ = Machine->pens[pal_ind16[col[i]&0x0f]];
+#if (V9938_WIDTH > 512)
+ *ln++ = Machine->pens[pal_ind16[col[i]&0x0f]];
+#endif
+ }
+ else
+#if (V9938_WIDTH > 512)
+ ln += 2;
+#else
+ ln++;
+#endif
+ }
+ }
+V9938_SPRITE_FUNC (graphic5_draw_sprite)
+ {
+ int i;
+#if (V9938_WIDTH > 512)
+ ln += vdp.offset_x * 2;
+#else
+ ln += vdp.offset_x;
+#endif
+
+ for (i=0;i<256;i++)
+ {
+ if (col[i] & 0x80)
+ {
+ *ln++ = Machine->pens[pal_ind16[(col[i]>>2)&0x03]];
+#if (V9938_WIDTH > 512)
+ *ln++ = Machine->pens[pal_ind16[col[i]&0x03]];
+#endif
+ }
+ else
+#if (V9938_WIDTH > 512)
+ ln += 2;
+#else
+ ln++;
+#endif
+ }
+ }
+
+
+V9938_SPRITE_FUNC (graphic7_draw_sprite)
+ {
+ static const UINT16 g7_ind16[16] = {
+ 0, 2, 192, 194, 48, 50, 240, 242,
+ 482, 7, 448, 455, 56, 63, 504, 511 };
+ int i;
+
+#if (V9938_WIDTH > 512)
+ ln += vdp.offset_x * 2;
+#else
+ ln += vdp.offset_x;
+#endif
+
+ for (i=0;i<256;i++)
+ {
+ if (col[i] & 0x80)
+ {
+ *ln++ = Machine->pens[g7_ind16[col[i]&0x0f]];
+#if (V9938_WIDTH > 512)
+ *ln++ = Machine->pens[g7_ind16[col[i]&0x0f]];
+#endif
+ }
+ else
+#if (V9938_WIDTH > 512)
+ ln += 2;
+#else
+ ln++;
+#endif
+ }
+ }
+
+
+#undef PEN_TYPE
+#undef FNAME
+#undef V9938_BORDER_FUNC
+#undef V9938_MODE_FUNC
+#undef V9938_SPRITE_FUNC
diff --git a/src/emu/video/vector.c b/src/emu/video/vector.c
new file mode 100644
index 00000000000..631dce624e0
--- /dev/null
+++ b/src/emu/video/vector.c
@@ -0,0 +1,315 @@
+/******************************************************************************
+ *
+ * vector.c
+ *
+ *
+ * Copyright 1997,1998 by the M.A.M.E. Project
+ *
+ * anti-alias code by Andrew Caldwell
+ * (still more to add)
+ *
+ * 040227 Fixed miny clip scaling which was breaking in mhavoc. AREK
+ * 010903 added support for direct RGB modes MLR
+ * 980611 use translucent vectors. Thanks to Peter Hirschberg
+ * and Neil Bradley for the inspiration. BW
+ * 980307 added cleverer dirty handling. BW, ASG
+ * fixed antialias table .ac
+ * 980221 rewrote anti-alias line draw routine
+ * added inline assembly multiply fuction for 8086 based machines
+ * beam diameter added to draw routine
+ * beam diameter is accurate in anti-alias line draw (Tcosin)
+ * flicker added .ac
+ * 980203 moved LBO's routines for drawing into a buffer of vertices
+ * from avgdvg.c to this location. Scaling is now initialized
+ * by calling vector_init(...). BW
+ * 980202 moved out of msdos.c ASG
+ * 980124 added anti-alias line draw routine
+ * modified avgdvg.c and sega.c to support new line draw routine
+ * added two new tables Tinten and Tmerge (for 256 color support)
+ * added find_color routine to build above tables .ac
+ *
+ **************************************************************************** */
+
+#include <math.h>
+#include "rendutil.h"
+#include "vector.h"
+
+
+
+#define VECTOR_WIDTH_DENOM 512
+
+
+#define MAX_POINTS 10000
+
+#define VECTOR_TEAM \
+ "-* Vector Heads *-\n" \
+ "Brad Oliver\n" \
+ "Aaron Giles\n" \
+ "Bernd Wiebelt\n" \
+ "Allard van der Bas\n" \
+ "Al Kossow (VECSIM)\n" \
+ "Hedley Rainnie (VECSIM)\n" \
+ "Eric Smith (VECSIM)\n" \
+ "Neil Bradley (technical advice)\n" \
+ "Andrew Caldwell (anti-aliasing)\n" \
+ "- *** -\n"
+
+#if 0
+
+#define TEXTURE_LENGTH_BUCKETS 32
+#define TEXTURE_INTENSITY_BUCKETS 4
+#define TEXTURE_WIDTH 16
+
+#define MAX_INTENSITY 2
+#define VECTOR_BLEED (0.25f)
+#define VECTOR_INT_SCALE (255.0f * 1.5f)
+
+
+typedef struct _vector_texture vector_texture;
+struct _vector_texture
+{
+ render_texture * texture;
+ mame_bitmap * bitmap;
+};
+
+static vector_texture *vectortex[TEXTURE_INTENSITY_BUCKETS][TEXTURE_LENGTH_BUCKETS];
+
+
+static render_texture *get_vector_texture(float dx, float dy, float intensity)
+{
+ float length = sqrt(dx * dx + dy * dy);
+ int lbucket = length * (float)TEXTURE_LENGTH_BUCKETS;
+ int ibucket = (intensity / (float)MAX_INTENSITY) * (float)TEXTURE_INTENSITY_BUCKETS;
+ vector_texture *tex;
+ int height, x, y;
+ float totalint;
+
+ if (lbucket > TEXTURE_LENGTH_BUCKETS)
+ lbucket = TEXTURE_LENGTH_BUCKETS;
+ if (ibucket > TEXTURE_INTENSITY_BUCKETS)
+ ibucket = TEXTURE_INTENSITY_BUCKETS;
+
+ tex = &vectortex[ibucket][lbucket];
+ if (tex->texture != NULL)
+ return tex->texture;
+
+ height = lbucket * VECTOR_WIDTH_DENOM / TEXTURE_LENGTH_BUCKETS;
+ tex->bitmap = bitmap_alloc(TEXTURE_WIDTH, height, BITMAP_FORMAT_ARGB32);
+ fillbitmap(tex->bitmap, NULL, MAKE_ARGB(0xff,0xff,0xff,0xff));
+
+ totalint = 1.0f;
+ for (x = TEXTURE_WIDTH / 2 - 1; x >= 0; x--)
+ {
+ int intensity = (int)(totalint * (1.0f - VECTOR_BLEED) * VECTOR_INT_SCALE);
+ intensity = MIN(255, intensity);
+ totalint -= (float)intensity * (1.0f / VECTOR_INT_SCALE);
+
+ for (y = 0; y < height; y++)
+ {
+ UINT32 *pix;
+
+ pix = (UINT32 *)bitmap->base + y * bitmap->rowpixels + x;
+ *pix = MAKE_ARGB((RGB_ALPHA(*pix) * intensity) >> 8,0xff,0xff,0xff);
+
+ pix = (UINT32 *)bitmap->base + y * bitmap->rowpixels + (TEXTURE_WIDTH - 1 - x);
+ *pix = MAKE_ARGB((RGB_ALPHA(*pix) * intensity) >> 8,0xff,0xff,0xff);
+ }
+ }
+
+ tex->texture = render_texture_create();
+ return tex->texture;
+}
+
+#endif
+
+#define VCLEAN 0
+#define VDIRTY 1
+#define VCLIP 2
+
+/* The vertices are buffered here */
+typedef struct
+{
+ int x; int y;
+ rgb_t col;
+ int intensity;
+ int arg1; int arg2; /* start/end in pixel array or clipping info */
+ int status; /* for dirty and clipping handling */
+} point;
+
+
+
+UINT8 *vectorram;
+size_t vectorram_size;
+
+static int flicker; /* beam flicker value */
+static float flicker_correction = 0.0f;
+
+static float beam_width;
+
+static point *vector_list;
+static int vector_index;
+
+
+void vector_set_flicker(float _flicker)
+{
+ flicker_correction = _flicker;
+ flicker = (int)(flicker_correction * 2.55);
+}
+
+float vector_get_flicker(void)
+{
+ return flicker_correction;
+}
+
+void vector_set_beam(float _beam)
+{
+ beam_width = _beam;
+}
+
+float vector_get_beam(void)
+{
+ return beam_width;
+}
+
+/*
+ * Initializes vector game video emulation
+ */
+
+VIDEO_START( vector )
+{
+ beam_width = options_get_float(mame_options(), OPTION_BEAM);
+
+ /* Grab the settings for this session */
+ vector_set_flicker(options_get_float(mame_options(), OPTION_FLICKER));
+
+ vector_index = 0;
+
+ /* allocate memory for tables */
+ vector_list = auto_malloc (MAX_POINTS * sizeof (vector_list[0]));
+}
+
+
+/*
+ * Adds a line end point to the vertices list. The vector processor emulation
+ * needs to call this.
+ */
+void vector_add_point (int x, int y, rgb_t color, int intensity)
+{
+ point *newpoint;
+
+ if (intensity > 0xff)
+ intensity = 0xff;
+
+ if (flicker && (intensity > 0))
+ {
+ intensity += (intensity * (0x80-(mame_rand(Machine)&0xff)) * flicker)>>16;
+ if (intensity < 0)
+ intensity = 0;
+ if (intensity > 0xff)
+ intensity = 0xff;
+ }
+ newpoint = &vector_list[vector_index];
+ newpoint->x = x;
+ newpoint->y = y;
+ newpoint->col = color;
+ newpoint->intensity = intensity;
+ newpoint->status = VDIRTY; /* mark identical lines as clean later */
+
+ vector_index++;
+ if (vector_index >= MAX_POINTS)
+ {
+ vector_index--;
+ logerror("*** Warning! Vector list overflow!\n");
+ }
+}
+
+/*
+ * Add new clipping info to the list
+ */
+void vector_add_clip (int x1, int yy1, int x2, int y2)
+{
+ point *newpoint;
+
+ newpoint = &vector_list[vector_index];
+ newpoint->x = x1;
+ newpoint->y = yy1;
+ newpoint->arg1 = x2;
+ newpoint->arg2 = y2;
+ newpoint->status = VCLIP;
+
+ vector_index++;
+ if (vector_index >= MAX_POINTS)
+ {
+ vector_index--;
+ logerror("*** Warning! Vector list overflow!\n");
+ }
+}
+
+
+/*
+ * The vector CPU creates a new display list. We save the old display list,
+ * but only once per refresh.
+ */
+void vector_clear_list (void)
+{
+ vector_index = 0;
+}
+
+
+VIDEO_UPDATE( vector )
+{
+ UINT32 flags = PRIMFLAG_ANTIALIAS(options_get_bool(mame_options(), OPTION_ANTIALIAS) ? 1 : 0) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD);
+ float xscale = 1.0f / (65536 * (machine->screen[screen].visarea.max_x - machine->screen[screen].visarea.min_x));
+ float yscale = 1.0f / (65536 * (machine->screen[screen].visarea.max_y - machine->screen[screen].visarea.min_y));
+ float xoffs = (float)machine->screen[screen].visarea.min_x;
+ float yoffs = (float)machine->screen[screen].visarea.min_y;
+ point *curpoint;
+ render_bounds clip;
+ int lastx = 0, lasty = 0;
+ int i;
+
+ curpoint = vector_list;
+
+ render_container_empty(render_container_get_screen(screen));
+ render_screen_add_rect(screen, 0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ clip.x0 = clip.y0 = 0.0f;
+ clip.x1 = clip.y1 = 1.0f;
+
+ for (i = 0; i < vector_index; i++)
+ {
+ render_bounds coords;
+
+ if (curpoint->status == VCLIP)
+ {
+ coords.x0 = ((float)curpoint->x - xoffs) * xscale;
+ coords.y0 = ((float)curpoint->y - yoffs) * yscale;
+ coords.x1 = ((float)curpoint->arg1 - xoffs) * xscale;
+ coords.y1 = ((float)curpoint->arg2 - yoffs) * yscale;
+
+ clip.x0 = (coords.x0 > 0.0f) ? coords.x0 : 0.0f;
+ clip.y0 = (coords.y0 > 0.0f) ? coords.y0 : 0.0f;
+ clip.x1 = (coords.x1 < 1.0f) ? coords.x1 : 1.0f;
+ clip.y1 = (coords.y1 < 1.0f) ? coords.y1 : 1.0f;
+ }
+ else
+ {
+ coords.x0 = ((float)lastx - xoffs) * xscale;
+ coords.y0 = ((float)lasty - yoffs) * yscale;
+ coords.x1 = ((float)curpoint->x - xoffs) * xscale;
+ coords.y1 = ((float)curpoint->y - yoffs) * yscale;
+
+ if (curpoint->intensity != 0)
+ if (!render_clip_line(&coords, &clip))
+ render_screen_add_line(screen, coords.x0, coords.y0, coords.x1, coords.y1,
+ beam_width * (1.0f / (float)VECTOR_WIDTH_DENOM),
+ (curpoint->intensity << 24) | (curpoint->col & 0xffffff),
+ flags);
+
+ lastx = curpoint->x;
+ lasty = curpoint->y;
+ }
+ curpoint++;
+ }
+ return 0;
+}
diff --git a/src/emu/video/vector.h b/src/emu/video/vector.h
new file mode 100644
index 00000000000..a141dcb090c
--- /dev/null
+++ b/src/emu/video/vector.h
@@ -0,0 +1,30 @@
+#ifndef __VECTOR__
+#define __VECTOR__
+
+#define VECTOR_COLOR111(c) \
+ MAKE_RGB(pal1bit((c) >> 2), pal1bit((c) >> 1), pal1bit((c) >> 0))
+
+#define VECTOR_COLOR222(c) \
+ MAKE_RGB(pal2bit((c) >> 4), pal2bit((c) >> 2), pal2bit((c) >> 0))
+
+#define VECTOR_COLOR444(c) \
+ MAKE_RGB(pal4bit((c) >> 8), pal4bit((c) >> 4), pal4bit((c) >> 0))
+
+extern UINT8 *vectorram;
+extern size_t vectorram_size;
+
+VIDEO_START( vector );
+VIDEO_UPDATE( vector );
+
+void vector_clear_list(void);
+void vector_add_point(int x, int y, rgb_t color, int intensity);
+void vector_add_clip(int minx, int miny, int maxx, int maxy);
+
+void vector_set_flicker(float _flicker);
+float vector_get_flicker(void);
+
+void vector_set_beam(float _beam);
+float vector_get_beam(void);
+
+#endif
+
diff --git a/src/emu/video/vooddefs.h b/src/emu/video/vooddefs.h
new file mode 100644
index 00000000000..374df64e76b
--- /dev/null
+++ b/src/emu/video/vooddefs.h
@@ -0,0 +1,3632 @@
+/*************************************************************************
+
+ 3dfx Voodoo Graphics SST-1/2 emulator
+
+ emulator by Aaron Giles
+
+**************************************************************************/
+
+
+/*************************************
+ *
+ * Misc. constants
+ *
+ *************************************/
+
+/* enumeration describing reasons we might be stalled */
+enum
+{
+ NOT_STALLED = 0,
+ STALLED_UNTIL_FIFO_LWM,
+ STALLED_UNTIL_FIFO_EMPTY
+};
+
+/* maximum number of TMUs */
+#define MAX_TMU 2
+
+/* accumulate operations less than this number of clocks */
+#define ACCUMULATE_THRESHOLD 0
+
+/* number of clocks to set up a triangle (just a guess) */
+#define TRIANGLE_SETUP_CLOCKS 100
+
+/* maximum number of rasterizers */
+#define MAX_RASTERIZERS 1024
+
+/* size of the rasterizer hash table */
+#define RASTER_HASH_SIZE 97
+
+/* flags for LFB writes */
+#define LFB_RGB_PRESENT 1
+#define LFB_ALPHA_PRESENT 2
+#define LFB_DEPTH_PRESENT 4
+#define LFB_DEPTH_PRESENT_MSW 8
+
+/* flags for the register access array */
+#define REGISTER_READ 0x01 /* reads are allowed */
+#define REGISTER_WRITE 0x02 /* writes are allowed */
+#define REGISTER_PIPELINED 0x04 /* writes are pipelined */
+#define REGISTER_FIFO 0x08 /* writes go to FIFO */
+#define REGISTER_WRITETHRU 0x10 /* writes are valid even for CMDFIFO */
+
+/* shorter combinations to make the table smaller */
+#define REG_R (REGISTER_READ)
+#define REG_W (REGISTER_WRITE)
+#define REG_WT (REGISTER_WRITE | REGISTER_WRITETHRU)
+#define REG_RW (REGISTER_READ | REGISTER_WRITE)
+#define REG_RWT (REGISTER_READ | REGISTER_WRITE | REGISTER_WRITETHRU)
+#define REG_RP (REGISTER_READ | REGISTER_PIPELINED)
+#define REG_WP (REGISTER_WRITE | REGISTER_PIPELINED)
+#define REG_RWP (REGISTER_READ | REGISTER_WRITE | REGISTER_PIPELINED)
+#define REG_RWPT (REGISTER_READ | REGISTER_WRITE | REGISTER_PIPELINED | REGISTER_WRITETHRU)
+#define REG_RF (REGISTER_READ | REGISTER_FIFO)
+#define REG_WF (REGISTER_WRITE | REGISTER_FIFO)
+#define REG_RWF (REGISTER_READ | REGISTER_WRITE | REGISTER_FIFO)
+#define REG_RPF (REGISTER_READ | REGISTER_PIPELINED | REGISTER_FIFO)
+#define REG_WPF (REGISTER_WRITE | REGISTER_PIPELINED | REGISTER_FIFO)
+#define REG_RWPF (REGISTER_READ | REGISTER_WRITE | REGISTER_PIPELINED | REGISTER_FIFO)
+
+/* lookup bits is the log2 of the size of the reciprocal/log table */
+#define RECIPLOG_LOOKUP_BITS 9
+
+/* input precision is how many fraction bits the input value has; this is a 64-bit number */
+#define RECIPLOG_INPUT_PREC 32
+
+/* lookup precision is how many fraction bits each table entry contains */
+#define RECIPLOG_LOOKUP_PREC 22
+
+/* output precision is how many fraction bits the result should have */
+#define RECIP_OUTPUT_PREC 15
+#define LOG_OUTPUT_PREC 8
+
+
+
+/*************************************
+ *
+ * Register constants
+ *
+ *************************************/
+
+/* Codes to the right:
+ R = readable
+ W = writeable
+ P = pipelined
+ F = goes to FIFO
+*/
+
+/* 0x000 */
+#define status (0x000/4) /* R P */
+#define intrCtrl (0x004/4) /* RW P -- Voodoo2/Banshee only */
+#define vertexAx (0x008/4) /* W PF */
+#define vertexAy (0x00c/4) /* W PF */
+#define vertexBx (0x010/4) /* W PF */
+#define vertexBy (0x014/4) /* W PF */
+#define vertexCx (0x018/4) /* W PF */
+#define vertexCy (0x01c/4) /* W PF */
+#define startR (0x020/4) /* W PF */
+#define startG (0x024/4) /* W PF */
+#define startB (0x028/4) /* W PF */
+#define startZ (0x02c/4) /* W PF */
+#define startA (0x030/4) /* W PF */
+#define startS (0x034/4) /* W PF */
+#define startT (0x038/4) /* W PF */
+#define startW (0x03c/4) /* W PF */
+
+/* 0x040 */
+#define dRdX (0x040/4) /* W PF */
+#define dGdX (0x044/4) /* W PF */
+#define dBdX (0x048/4) /* W PF */
+#define dZdX (0x04c/4) /* W PF */
+#define dAdX (0x050/4) /* W PF */
+#define dSdX (0x054/4) /* W PF */
+#define dTdX (0x058/4) /* W PF */
+#define dWdX (0x05c/4) /* W PF */
+#define dRdY (0x060/4) /* W PF */
+#define dGdY (0x064/4) /* W PF */
+#define dBdY (0x068/4) /* W PF */
+#define dZdY (0x06c/4) /* W PF */
+#define dAdY (0x070/4) /* W PF */
+#define dSdY (0x074/4) /* W PF */
+#define dTdY (0x078/4) /* W PF */
+#define dWdY (0x07c/4) /* W PF */
+
+/* 0x080 */
+#define triangleCMD (0x080/4) /* W PF */
+#define fvertexAx (0x088/4) /* W PF */
+#define fvertexAy (0x08c/4) /* W PF */
+#define fvertexBx (0x090/4) /* W PF */
+#define fvertexBy (0x094/4) /* W PF */
+#define fvertexCx (0x098/4) /* W PF */
+#define fvertexCy (0x09c/4) /* W PF */
+#define fstartR (0x0a0/4) /* W PF */
+#define fstartG (0x0a4/4) /* W PF */
+#define fstartB (0x0a8/4) /* W PF */
+#define fstartZ (0x0ac/4) /* W PF */
+#define fstartA (0x0b0/4) /* W PF */
+#define fstartS (0x0b4/4) /* W PF */
+#define fstartT (0x0b8/4) /* W PF */
+#define fstartW (0x0bc/4) /* W PF */
+
+/* 0x0c0 */
+#define fdRdX (0x0c0/4) /* W PF */
+#define fdGdX (0x0c4/4) /* W PF */
+#define fdBdX (0x0c8/4) /* W PF */
+#define fdZdX (0x0cc/4) /* W PF */
+#define fdAdX (0x0d0/4) /* W PF */
+#define fdSdX (0x0d4/4) /* W PF */
+#define fdTdX (0x0d8/4) /* W PF */
+#define fdWdX (0x0dc/4) /* W PF */
+#define fdRdY (0x0e0/4) /* W PF */
+#define fdGdY (0x0e4/4) /* W PF */
+#define fdBdY (0x0e8/4) /* W PF */
+#define fdZdY (0x0ec/4) /* W PF */
+#define fdAdY (0x0f0/4) /* W PF */
+#define fdSdY (0x0f4/4) /* W PF */
+#define fdTdY (0x0f8/4) /* W PF */
+#define fdWdY (0x0fc/4) /* W PF */
+
+/* 0x100 */
+#define ftriangleCMD (0x100/4) /* W PF */
+#define fbzColorPath (0x104/4) /* RW PF */
+#define fogMode (0x108/4) /* RW PF */
+#define alphaMode (0x10c/4) /* RW PF */
+#define fbzMode (0x110/4) /* RW F */
+#define lfbMode (0x114/4) /* RW F */
+#define clipLeftRight (0x118/4) /* RW F */
+#define clipLowYHighY (0x11c/4) /* RW F */
+#define nopCMD (0x120/4) /* W F */
+#define fastfillCMD (0x124/4) /* W F */
+#define swapbufferCMD (0x128/4) /* W F */
+#define fogColor (0x12c/4) /* W F */
+#define zaColor (0x130/4) /* W F */
+#define chromaKey (0x134/4) /* W F */
+#define chromaRange (0x138/4) /* W F -- Voodoo2/Banshee only */
+#define userIntrCMD (0x13c/4) /* W F -- Voodoo2/Banshee only */
+
+/* 0x140 */
+#define stipple (0x140/4) /* RW F */
+#define color0 (0x144/4) /* RW F */
+#define color1 (0x148/4) /* RW F */
+#define fbiPixelsIn (0x14c/4) /* R */
+#define fbiChromaFail (0x150/4) /* R */
+#define fbiZfuncFail (0x154/4) /* R */
+#define fbiAfuncFail (0x158/4) /* R */
+#define fbiPixelsOut (0x15c/4) /* R */
+#define fogTable (0x160/4) /* W F */
+
+/* 0x1c0 */
+#define cmdFifoBaseAddr (0x1e0/4) /* RW -- Voodoo2 only */
+#define cmdFifoBump (0x1e4/4) /* RW -- Voodoo2 only */
+#define cmdFifoRdPtr (0x1e8/4) /* RW -- Voodoo2 only */
+#define cmdFifoAMin (0x1ec/4) /* RW -- Voodoo2 only */
+#define colBufferAddr (0x1ec/4) /* RW -- Banshee only */
+#define cmdFifoAMax (0x1f0/4) /* RW -- Voodoo2 only */
+#define colBufferStride (0x1f0/4) /* RW -- Banshee only */
+#define cmdFifoDepth (0x1f4/4) /* RW -- Voodoo2 only */
+#define auxBufferAddr (0x1f4/4) /* RW -- Banshee only */
+#define cmdFifoHoles (0x1f8/4) /* RW -- Voodoo2 only */
+#define auxBufferStride (0x1f8/4) /* RW -- Banshee only */
+
+/* 0x200 */
+#define fbiInit4 (0x200/4) /* RW -- Voodoo/Voodoo2 only */
+#define clipLeftRight1 (0x200/4) /* RW -- Banshee only */
+#define vRetrace (0x204/4) /* R -- Voodoo/Voodoo2 only */
+#define clipTopBottom1 (0x204/4) /* RW -- Banshee only */
+#define backPorch (0x208/4) /* RW -- Voodoo/Voodoo2 only */
+#define videoDimensions (0x20c/4) /* RW -- Voodoo/Voodoo2 only */
+#define fbiInit0 (0x210/4) /* RW -- Voodoo/Voodoo2 only */
+#define fbiInit1 (0x214/4) /* RW -- Voodoo/Voodoo2 only */
+#define fbiInit2 (0x218/4) /* RW -- Voodoo/Voodoo2 only */
+#define fbiInit3 (0x21c/4) /* RW -- Voodoo/Voodoo2 only */
+#define hSync (0x220/4) /* W -- Voodoo/Voodoo2 only */
+#define vSync (0x224/4) /* W -- Voodoo/Voodoo2 only */
+#define clutData (0x228/4) /* W F -- Voodoo/Voodoo2 only */
+#define dacData (0x22c/4) /* W -- Voodoo/Voodoo2 only */
+#define maxRgbDelta (0x230/4) /* W -- Voodoo/Voodoo2 only */
+#define hBorder (0x234/4) /* W -- Voodoo2 only */
+#define vBorder (0x238/4) /* W -- Voodoo2 only */
+#define borderColor (0x23c/4) /* W -- Voodoo2 only */
+
+/* 0x240 */
+#define hvRetrace (0x240/4) /* R -- Voodoo2 only */
+#define fbiInit5 (0x244/4) /* RW -- Voodoo2 only */
+#define fbiInit6 (0x248/4) /* RW -- Voodoo2 only */
+#define fbiInit7 (0x24c/4) /* RW -- Voodoo2 only */
+#define swapPending (0x24c/4) /* W -- Banshee only */
+#define leftOverlayBuf (0x250/4) /* W -- Banshee only */
+#define rightOverlayBuf (0x254/4) /* W -- Banshee only */
+#define fbiSwapHistory (0x258/4) /* R -- Voodoo2/Banshee only */
+#define fbiTrianglesOut (0x25c/4) /* R -- Voodoo2/Banshee only */
+#define sSetupMode (0x260/4) /* W PF -- Voodoo2/Banshee only */
+#define sVx (0x264/4) /* W PF -- Voodoo2/Banshee only */
+#define sVy (0x268/4) /* W PF -- Voodoo2/Banshee only */
+#define sARGB (0x26c/4) /* W PF -- Voodoo2/Banshee only */
+#define sRed (0x270/4) /* W PF -- Voodoo2/Banshee only */
+#define sGreen (0x274/4) /* W PF -- Voodoo2/Banshee only */
+#define sBlue (0x278/4) /* W PF -- Voodoo2/Banshee only */
+#define sAlpha (0x27c/4) /* W PF -- Voodoo2/Banshee only */
+
+/* 0x280 */
+#define sVz (0x280/4) /* W PF -- Voodoo2/Banshee only */
+#define sWb (0x284/4) /* W PF -- Voodoo2/Banshee only */
+#define sWtmu0 (0x288/4) /* W PF -- Voodoo2/Banshee only */
+#define sS_W0 (0x28c/4) /* W PF -- Voodoo2/Banshee only */
+#define sT_W0 (0x290/4) /* W PF -- Voodoo2/Banshee only */
+#define sWtmu1 (0x294/4) /* W PF -- Voodoo2/Banshee only */
+#define sS_Wtmu1 (0x298/4) /* W PF -- Voodoo2/Banshee only */
+#define sT_Wtmu1 (0x29c/4) /* W PF -- Voodoo2/Banshee only */
+#define sDrawTriCMD (0x2a0/4) /* W PF -- Voodoo2/Banshee only */
+#define sBeginTriCMD (0x2a4/4) /* W PF -- Voodoo2/Banshee only */
+
+/* 0x2c0 */
+#define bltSrcBaseAddr (0x2c0/4) /* RW PF -- Voodoo2 only */
+#define bltDstBaseAddr (0x2c4/4) /* RW PF -- Voodoo2 only */
+#define bltXYStrides (0x2c8/4) /* RW PF -- Voodoo2 only */
+#define bltSrcChromaRange (0x2cc/4) /* RW PF -- Voodoo2 only */
+#define bltDstChromaRange (0x2d0/4) /* RW PF -- Voodoo2 only */
+#define bltClipX (0x2d4/4) /* RW PF -- Voodoo2 only */
+#define bltClipY (0x2d8/4) /* RW PF -- Voodoo2 only */
+#define bltSrcXY (0x2e0/4) /* RW PF -- Voodoo2 only */
+#define bltDstXY (0x2e4/4) /* RW PF -- Voodoo2 only */
+#define bltSize (0x2e8/4) /* RW PF -- Voodoo2 only */
+#define bltRop (0x2ec/4) /* RW PF -- Voodoo2 only */
+#define bltColor (0x2f0/4) /* RW PF -- Voodoo2 only */
+#define bltCommand (0x2f8/4) /* RW PF -- Voodoo2 only */
+#define bltData (0x2fc/4) /* W PF -- Voodoo2 only */
+
+/* 0x300 */
+#define textureMode (0x300/4) /* W PF */
+#define tLOD (0x304/4) /* W PF */
+#define tDetail (0x308/4) /* W PF */
+#define texBaseAddr (0x30c/4) /* W PF */
+#define texBaseAddr_1 (0x310/4) /* W PF */
+#define texBaseAddr_2 (0x314/4) /* W PF */
+#define texBaseAddr_3_8 (0x318/4) /* W PF */
+#define trexInit0 (0x31c/4) /* W F -- Voodoo/Voodoo2 only */
+#define trexInit1 (0x320/4) /* W F */
+#define nccTable (0x324/4) /* W F */
+
+
+
+/*************************************
+ *
+ * Alias map of the first 64
+ * registers when remapped
+ *
+ *************************************/
+
+static const UINT8 register_alias_map[0x40] =
+{
+ status, 0x004/4, vertexAx, vertexAy,
+ vertexBx, vertexBy, vertexCx, vertexCy,
+ startR, dRdX, dRdY, startG,
+ dGdX, dGdY, startB, dBdX,
+ dBdY, startZ, dZdX, dZdY,
+ startA, dAdX, dAdY, startS,
+ dSdX, dSdY, startT, dTdX,
+ dTdY, startW, dWdX, dWdY,
+
+ triangleCMD,0x084/4, fvertexAx, fvertexAy,
+ fvertexBx, fvertexBy, fvertexCx, fvertexCy,
+ fstartR, fdRdX, fdRdY, fstartG,
+ fdGdX, fdGdY, fstartB, fdBdX,
+ fdBdY, fstartZ, fdZdX, fdZdY,
+ fstartA, fdAdX, fdAdY, fstartS,
+ fdSdX, fdSdY, fstartT, fdTdX,
+ fdTdY, fstartW, fdWdX, fdWdY
+};
+
+
+
+/*************************************
+ *
+ * Table of per-register access rights
+ *
+ *************************************/
+
+static const UINT8 voodoo_register_access[0x100] =
+{
+ /* 0x000 */
+ REG_RP, 0, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x040 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x080 */
+ REG_WPF, 0, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x0c0 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x100 */
+ REG_WPF, REG_RWPF, REG_RWPF, REG_RWPF,
+ REG_RWF, REG_RWF, REG_RWF, REG_RWF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, 0, 0,
+
+ /* 0x140 */
+ REG_RWF, REG_RWF, REG_RWF, REG_R,
+ REG_R, REG_R, REG_R, REG_R,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x180 */
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x1c0 */
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+
+ /* 0x200 */
+ REG_RW, REG_R, REG_RW, REG_RW,
+ REG_RW, REG_RW, REG_RW, REG_RW,
+ REG_W, REG_W, REG_W, REG_W,
+ REG_W, 0, 0, 0,
+
+ /* 0x240 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+
+ /* 0x280 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+
+ /* 0x2c0 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+
+ /* 0x300 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x340 */
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x380 */
+ REG_WF
+};
+
+
+static const UINT8 voodoo2_register_access[0x100] =
+{
+ /* 0x000 */
+ REG_RP, REG_RWPT, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x040 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x080 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x0c0 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x100 */
+ REG_WPF, REG_RWPF, REG_RWPF, REG_RWPF,
+ REG_RWF, REG_RWF, REG_RWF, REG_RWF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x140 */
+ REG_RWF, REG_RWF, REG_RWF, REG_R,
+ REG_R, REG_R, REG_R, REG_R,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x180 */
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x1c0 */
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_RWT, REG_RWT, REG_RWT, REG_RWT,
+ REG_RWT, REG_RWT, REG_RWT, REG_RW,
+
+ /* 0x200 */
+ REG_RWT, REG_R, REG_RWT, REG_RWT,
+ REG_RWT, REG_RWT, REG_RWT, REG_RWT,
+ REG_WT, REG_WT, REG_WF, REG_WT,
+ REG_WT, REG_WT, REG_WT, REG_WT,
+
+ /* 0x240 */
+ REG_R, REG_RWT, REG_RWT, REG_RWT,
+ 0, 0, REG_R, REG_R,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x280 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, 0, 0,
+ 0, 0, 0, 0,
+
+ /* 0x2c0 */
+ REG_RWPF, REG_RWPF, REG_RWPF, REG_RWPF,
+ REG_RWPF, REG_RWPF, REG_RWPF, REG_RWPF,
+ REG_RWPF, REG_RWPF, REG_RWPF, REG_RWPF,
+ REG_RWPF, REG_RWPF, REG_RWPF, REG_WPF,
+
+ /* 0x300 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x340 */
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x380 */
+ REG_WF
+};
+
+
+static const UINT8 banshee_register_access[0x100] =
+{
+ /* 0x000 */
+ REG_RP, REG_RWPT, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x040 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x080 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x0c0 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x100 */
+ REG_WPF, REG_RWPF, REG_RWPF, REG_RWPF,
+ REG_RWF, REG_RWF, REG_RWF, REG_RWF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x140 */
+ REG_RWF, REG_RWF, REG_RWF, REG_R,
+ REG_R, REG_R, REG_R, REG_R,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x180 */
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x1c0 */
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ 0, 0, 0, REG_RWF,
+ REG_RWF, REG_RWF, REG_RWF, 0,
+
+ /* 0x200 */
+ REG_RWF, REG_RWF, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+
+ /* 0x240 */
+ 0, 0, 0, REG_WT,
+ REG_RWF, REG_RWF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_R, REG_R,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+
+ /* 0x280 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, 0, 0,
+ 0, 0, 0, 0,
+
+ /* 0x2c0 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+
+ /* 0x300 */
+ REG_WPF, REG_WPF, REG_WPF, REG_WPF,
+ REG_WPF, REG_WPF, REG_WPF, 0,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x340 */
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+ REG_WF, REG_WF, REG_WF, REG_WF,
+
+ /* 0x380 */
+ REG_WF
+};
+
+
+
+/*************************************
+ *
+ * Register string table for debug
+ *
+ *************************************/
+
+static const char *voodoo_reg_name[] =
+{
+ /* 0x000 */
+ "status", "{intrCtrl}", "vertexAx", "vertexAy",
+ "vertexBx", "vertexBy", "vertexCx", "vertexCy",
+ "startR", "startG", "startB", "startZ",
+ "startA", "startS", "startT", "startW",
+ /* 0x040 */
+ "dRdX", "dGdX", "dBdX", "dZdX",
+ "dAdX", "dSdX", "dTdX", "dWdX",
+ "dRdY", "dGdY", "dBdY", "dZdY",
+ "dAdY", "dSdY", "dTdY", "dWdY",
+ /* 0x080 */
+ "triangleCMD", "reserved084", "fvertexAx", "fvertexAy",
+ "fvertexBx", "fvertexBy", "fvertexCx", "fvertexCy",
+ "fstartR", "fstartG", "fstartB", "fstartZ",
+ "fstartA", "fstartS", "fstartT", "fstartW",
+ /* 0x0c0 */
+ "fdRdX", "fdGdX", "fdBdX", "fdZdX",
+ "fdAdX", "fdSdX", "fdTdX", "fdWdX",
+ "fdRdY", "fdGdY", "fdBdY", "fdZdY",
+ "fdAdY", "fdSdY", "fdTdY", "fdWdY",
+ /* 0x100 */
+ "ftriangleCMD", "fbzColorPath", "fogMode", "alphaMode",
+ "fbzMode", "lfbMode", "clipLeftRight","clipLowYHighY",
+ "nopCMD", "fastfillCMD", "swapbufferCMD","fogColor",
+ "zaColor", "chromaKey", "{chromaRange}","{userIntrCMD}",
+ /* 0x140 */
+ "stipple", "color0", "color1", "fbiPixelsIn",
+ "fbiChromaFail","fbiZfuncFail", "fbiAfuncFail", "fbiPixelsOut",
+ "fogTable160", "fogTable164", "fogTable168", "fogTable16c",
+ "fogTable170", "fogTable174", "fogTable178", "fogTable17c",
+ /* 0x180 */
+ "fogTable180", "fogTable184", "fogTable188", "fogTable18c",
+ "fogTable190", "fogTable194", "fogTable198", "fogTable19c",
+ "fogTable1a0", "fogTable1a4", "fogTable1a8", "fogTable1ac",
+ "fogTable1b0", "fogTable1b4", "fogTable1b8", "fogTable1bc",
+ /* 0x1c0 */
+ "fogTable1c0", "fogTable1c4", "fogTable1c8", "fogTable1cc",
+ "fogTable1d0", "fogTable1d4", "fogTable1d8", "fogTable1dc",
+ "{cmdFifoBaseAddr}","{cmdFifoBump}","{cmdFifoRdPtr}","{cmdFifoAMin}",
+ "{cmdFifoAMax}","{cmdFifoDepth}","{cmdFifoHoles}","reserved1fc",
+ /* 0x200 */
+ "fbiInit4", "vRetrace", "backPorch", "videoDimensions",
+ "fbiInit0", "fbiInit1", "fbiInit2", "fbiInit3",
+ "hSync", "vSync", "clutData", "dacData",
+ "maxRgbDelta", "{hBorder}", "{vBorder}", "{borderColor}",
+ /* 0x240 */
+ "{hvRetrace}", "{fbiInit5}", "{fbiInit6}", "{fbiInit7}",
+ "reserved250", "reserved254", "{fbiSwapHistory}","{fbiTrianglesOut}",
+ "{sSetupMode}", "{sVx}", "{sVy}", "{sARGB}",
+ "{sRed}", "{sGreen}", "{sBlue}", "{sAlpha}",
+ /* 0x280 */
+ "{sVz}", "{sWb}", "{sWtmu0}", "{sS/Wtmu0}",
+ "{sT/Wtmu0}", "{sWtmu1}", "{sS/Wtmu1}", "{sT/Wtmu1}",
+ "{sDrawTriCMD}","{sBeginTriCMD}","reserved2a8", "reserved2ac",
+ "reserved2b0", "reserved2b4", "reserved2b8", "reserved2bc",
+ /* 0x2c0 */
+ "{bltSrcBaseAddr}","{bltDstBaseAddr}","{bltXYStrides}","{bltSrcChromaRange}",
+ "{bltDstChromaRange}","{bltClipX}","{bltClipY}","reserved2dc",
+ "{bltSrcXY}", "{bltDstXY}", "{bltSize}", "{bltRop}",
+ "{bltColor}", "reserved2f4", "{bltCommand}", "{bltData}",
+ /* 0x300 */
+ "textureMode", "tLOD", "tDetail", "texBaseAddr",
+ "texBaseAddr_1","texBaseAddr_2","texBaseAddr_3_8","trexInit0",
+ "trexInit1", "nccTable0.0", "nccTable0.1", "nccTable0.2",
+ "nccTable0.3", "nccTable0.4", "nccTable0.5", "nccTable0.6",
+ /* 0x340 */
+ "nccTable0.7", "nccTable0.8", "nccTable0.9", "nccTable0.A",
+ "nccTable0.B", "nccTable1.0", "nccTable1.1", "nccTable1.2",
+ "nccTable1.3", "nccTable1.4", "nccTable1.5", "nccTable1.6",
+ "nccTable1.7", "nccTable1.8", "nccTable1.9", "nccTable1.A",
+ /* 0x380 */
+ "nccTable1.B"
+};
+
+
+static const char *banshee_reg_name[] =
+{
+ /* 0x000 */
+ "status", "intrCtrl", "vertexAx", "vertexAy",
+ "vertexBx", "vertexBy", "vertexCx", "vertexCy",
+ "startR", "startG", "startB", "startZ",
+ "startA", "startS", "startT", "startW",
+ /* 0x040 */
+ "dRdX", "dGdX", "dBdX", "dZdX",
+ "dAdX", "dSdX", "dTdX", "dWdX",
+ "dRdY", "dGdY", "dBdY", "dZdY",
+ "dAdY", "dSdY", "dTdY", "dWdY",
+ /* 0x080 */
+ "triangleCMD", "reserved084", "fvertexAx", "fvertexAy",
+ "fvertexBx", "fvertexBy", "fvertexCx", "fvertexCy",
+ "fstartR", "fstartG", "fstartB", "fstartZ",
+ "fstartA", "fstartS", "fstartT", "fstartW",
+ /* 0x0c0 */
+ "fdRdX", "fdGdX", "fdBdX", "fdZdX",
+ "fdAdX", "fdSdX", "fdTdX", "fdWdX",
+ "fdRdY", "fdGdY", "fdBdY", "fdZdY",
+ "fdAdY", "fdSdY", "fdTdY", "fdWdY",
+ /* 0x100 */
+ "ftriangleCMD", "fbzColorPath", "fogMode", "alphaMode",
+ "fbzMode", "lfbMode", "clipLeftRight","clipLowYHighY",
+ "nopCMD", "fastfillCMD", "swapbufferCMD","fogColor",
+ "zaColor", "chromaKey", "chromaRange", "userIntrCMD",
+ /* 0x140 */
+ "stipple", "color0", "color1", "fbiPixelsIn",
+ "fbiChromaFail","fbiZfuncFail", "fbiAfuncFail", "fbiPixelsOut",
+ "fogTable160", "fogTable164", "fogTable168", "fogTable16c",
+ "fogTable170", "fogTable174", "fogTable178", "fogTable17c",
+ /* 0x180 */
+ "fogTable180", "fogTable184", "fogTable188", "fogTable18c",
+ "fogTable190", "fogTable194", "fogTable198", "fogTable19c",
+ "fogTable1a0", "fogTable1a4", "fogTable1a8", "fogTable1ac",
+ "fogTable1b0", "fogTable1b4", "fogTable1b8", "fogTable1bc",
+ /* 0x1c0 */
+ "fogTable1c0", "fogTable1c4", "fogTable1c8", "fogTable1cc",
+ "fogTable1d0", "fogTable1d4", "fogTable1d8", "fogTable1dc",
+ "reserved1e0", "reserved1e4", "reserved1e8", "colBufferAddr",
+ "colBufferStride","auxBufferAddr","auxBufferStride","reserved1fc",
+ /* 0x200 */
+ "clipLeftRight1","clipTopBottom1","reserved208","reserved20c",
+ "reserved210", "reserved214", "reserved218", "reserved21c",
+ "reserved220", "reserved224", "reserved228", "reserved22c",
+ "reserved230", "reserved234", "reserved238", "reserved23c",
+ /* 0x240 */
+ "reserved240", "reserved244", "reserved248", "swapPending",
+ "leftOverlayBuf","rightOverlayBuf","fbiSwapHistory","fbiTrianglesOut",
+ "sSetupMode", "sVx", "sVy", "sARGB",
+ "sRed", "sGreen", "sBlue", "sAlpha",
+ /* 0x280 */
+ "sVz", "sWb", "sWtmu0", "sS/Wtmu0",
+ "sT/Wtmu0", "sWtmu1", "sS/Wtmu1", "sT/Wtmu1",
+ "sDrawTriCMD", "sBeginTriCMD", "reserved2a8", "reserved2ac",
+ "reserved2b0", "reserved2b4", "reserved2b8", "reserved2bc",
+ /* 0x2c0 */
+ "reserved2c0", "reserved2c4", "reserved2c8", "reserved2cc",
+ "reserved2d0", "reserved2d4", "reserved2d8", "reserved2dc",
+ "reserved2e0", "reserved2e4", "reserved2e8", "reserved2ec",
+ "reserved2f0", "reserved2f4", "reserved2f8", "reserved2fc",
+ /* 0x300 */
+ "textureMode", "tLOD", "tDetail", "texBaseAddr",
+ "texBaseAddr_1","texBaseAddr_2","texBaseAddr_3_8","reserved31c",
+ "trexInit1", "nccTable0.0", "nccTable0.1", "nccTable0.2",
+ "nccTable0.3", "nccTable0.4", "nccTable0.5", "nccTable0.6",
+ /* 0x340 */
+ "nccTable0.7", "nccTable0.8", "nccTable0.9", "nccTable0.A",
+ "nccTable0.B", "nccTable1.0", "nccTable1.1", "nccTable1.2",
+ "nccTable1.3", "nccTable1.4", "nccTable1.5", "nccTable1.6",
+ "nccTable1.7", "nccTable1.8", "nccTable1.9", "nccTable1.A",
+ /* 0x380 */
+ "nccTable1.B"
+};
+
+
+
+/*************************************
+ *
+ * Voodoo Banshee I/O space registers
+ *
+ *************************************/
+
+/* 0x000 */
+#define io_status (0x000/4) /* */
+#define io_pciInit0 (0x004/4) /* */
+#define io_sipMonitor (0x008/4) /* */
+#define io_lfbMemoryConfig (0x00c/4) /* */
+#define io_miscInit0 (0x010/4) /* */
+#define io_miscInit1 (0x014/4) /* */
+#define io_dramInit0 (0x018/4) /* */
+#define io_dramInit1 (0x01c/4) /* */
+#define io_agpInit (0x020/4) /* */
+#define io_tmuGbeInit (0x024/4) /* */
+#define io_vgaInit0 (0x028/4) /* */
+#define io_vgaInit1 (0x02c/4) /* */
+#define io_dramCommand (0x030/4) /* */
+#define io_dramData (0x034/4) /* */
+
+/* 0x040 */
+#define io_pllCtrl0 (0x040/4) /* */
+#define io_pllCtrl1 (0x044/4) /* */
+#define io_pllCtrl2 (0x048/4) /* */
+#define io_dacMode (0x04c/4) /* */
+#define io_dacAddr (0x050/4) /* */
+#define io_dacData (0x054/4) /* */
+#define io_rgbMaxDelta (0x058/4) /* */
+#define io_vidProcCfg (0x05c/4) /* */
+#define io_hwCurPatAddr (0x060/4) /* */
+#define io_hwCurLoc (0x064/4) /* */
+#define io_hwCurC0 (0x068/4) /* */
+#define io_hwCurC1 (0x06c/4) /* */
+#define io_vidInFormat (0x070/4) /* */
+#define io_vidInStatus (0x074/4) /* */
+#define io_vidSerialParallelPort (0x078/4) /* */
+#define io_vidInXDecimDeltas (0x07c/4) /* */
+
+/* 0x080 */
+#define io_vidInDecimInitErrs (0x080/4) /* */
+#define io_vidInYDecimDeltas (0x084/4) /* */
+#define io_vidPixelBufThold (0x088/4) /* */
+#define io_vidChromaMin (0x08c/4) /* */
+#define io_vidChromaMax (0x090/4) /* */
+#define io_vidCurrentLine (0x094/4) /* */
+#define io_vidScreenSize (0x098/4) /* */
+#define io_vidOverlayStartCoords (0x09c/4) /* */
+#define io_vidOverlayEndScreenCoord (0x0a0/4) /* */
+#define io_vidOverlayDudx (0x0a4/4) /* */
+#define io_vidOverlayDudxOffsetSrcWidth (0x0a8/4) /* */
+#define io_vidOverlayDvdy (0x0ac/4) /* */
+#define io_vgab0 (0x0b0/4) /* */
+#define io_vgab4 (0x0b4/4) /* */
+#define io_vgab8 (0x0b8/4) /* */
+#define io_vgabc (0x0bc/4) /* */
+
+/* 0x0c0 */
+#define io_vgac0 (0x0c0/4) /* */
+#define io_vgac4 (0x0c4/4) /* */
+#define io_vgac8 (0x0c8/4) /* */
+#define io_vgacc (0x0cc/4) /* */
+#define io_vgad0 (0x0d0/4) /* */
+#define io_vgad4 (0x0d4/4) /* */
+#define io_vgad8 (0x0d8/4) /* */
+#define io_vgadc (0x0dc/4) /* */
+#define io_vidOverlayDvdyOffset (0x0e0/4) /* */
+#define io_vidDesktopStartAddr (0x0e4/4) /* */
+#define io_vidDesktopOverlayStride (0x0e8/4) /* */
+#define io_vidInAddr0 (0x0ec/4) /* */
+#define io_vidInAddr1 (0x0f0/4) /* */
+#define io_vidInAddr2 (0x0f4/4) /* */
+#define io_vidInStride (0x0f8/4) /* */
+#define io_vidCurrOverlayStartAddr (0x0fc/4) /* */
+
+
+
+/*************************************
+ *
+ * Register string table for debug
+ *
+ *************************************/
+
+static const char *banshee_io_reg_name[] =
+{
+ /* 0x000 */
+ "status", "pciInit0", "sipMonitor", "lfbMemoryConfig",
+ "miscInit0", "miscInit1", "dramInit0", "dramInit1",
+ "agpInit", "tmuGbeInit", "vgaInit0", "vgaInit1",
+ "dramCommand", "dramData", "reserved38", "reserved3c",
+
+ /* 0x040 */
+ "pllCtrl0", "pllCtrl1", "pllCtrl2", "dacMode",
+ "dacAddr", "dacData", "rgbMaxDelta", "vidProcCfg",
+ "hwCurPatAddr", "hwCurLoc", "hwCurC0", "hwCurC1",
+ "vidInFormat", "vidInStatus", "vidSerialParallelPort","vidInXDecimDeltas",
+
+ /* 0x080 */
+ "vidInDecimInitErrs","vidInYDecimDeltas","vidPixelBufThold","vidChromaMin",
+ "vidChromaMax", "vidCurrentLine","vidScreenSize","vidOverlayStartCoords",
+ "vidOverlayEndScreenCoord","vidOverlayDudx","vidOverlayDudxOffsetSrcWidth","vidOverlayDvdy",
+ "vga[b0]", "vga[b4]", "vga[b8]", "vga[bc]",
+
+ /* 0x0c0 */
+ "vga[c0]", "vga[c4]", "vga[c8]", "vga[cc]",
+ "vga[d0]", "vga[d4]", "vga[d8]", "vga[dc]",
+ "vidOverlayDvdyOffset","vidDesktopStartAddr","vidDesktopOverlayStride","vidInAddr0",
+ "vidInAddr1", "vidInAddr2", "vidInStride", "vidCurrOverlayStartAddr"
+};
+
+
+
+/*************************************
+ *
+ * Voodoo Banshee AGP space registers
+ *
+ *************************************/
+
+/* 0x000 */
+#define agpReqSize (0x000/4) /* */
+#define agpHostAddressLow (0x004/4) /* */
+#define agpHostAddressHigh (0x008/4) /* */
+#define agpGraphicsAddress (0x00c/4) /* */
+#define agpGraphicsStride (0x010/4) /* */
+#define agpMoveCMD (0x014/4) /* */
+#define cmdBaseAddr0 (0x020/4) /* */
+#define cmdBaseSize0 (0x024/4) /* */
+#define cmdBump0 (0x028/4) /* */
+#define cmdRdPtrL0 (0x02c/4) /* */
+#define cmdRdPtrH0 (0x030/4) /* */
+#define cmdAMin0 (0x034/4) /* */
+#define cmdAMax0 (0x03c/4) /* */
+
+/* 0x040 */
+#define cmdFifoDepth0 (0x044/4) /* */
+#define cmdHoleCnt0 (0x048/4) /* */
+#define cmdBaseAddr1 (0x050/4) /* */
+#define cmdBaseSize1 (0x054/4) /* */
+#define cmdBump1 (0x058/4) /* */
+#define cmdRdPtrL1 (0x05c/4) /* */
+#define cmdRdPtrH1 (0x060/4) /* */
+#define cmdAMin1 (0x064/4) /* */
+#define cmdAMax1 (0x06c/4) /* */
+#define cmdFifoDepth1 (0x074/4) /* */
+#define cmdHoleCnt1 (0x078/4) /* */
+
+/* 0x080 */
+#define cmdFifoThresh (0x080/4) /* */
+#define cmdHoleInt (0x084/4) /* */
+
+/* 0x100 */
+#define yuvBaseAddress (0x100/4) /* */
+#define yuvStride (0x104/4) /* */
+#define crc1 (0x120/4) /* */
+#define crc2 (0x130/4) /* */
+
+
+
+/*************************************
+ *
+ * Register string table for debug
+ *
+ *************************************/
+
+static const char *banshee_agp_reg_name[] =
+{
+ /* 0x000 */
+ "agpReqSize", "agpHostAddressLow","agpHostAddressHigh","agpGraphicsAddress",
+ "agpGraphicsStride","agpMoveCMD","reserved18", "reserved1c",
+ "cmdBaseAddr0", "cmdBaseSize0", "cmdBump0", "cmdRdPtrL0",
+ "cmdRdPtrH0", "cmdAMin0", "reserved38", "cmdAMax0",
+
+ /* 0x040 */
+ "reserved40", "cmdFifoDepth0","cmdHoleCnt0", "reserved4c",
+ "cmdBaseAddr1", "cmdBaseSize1", "cmdBump1", "cmdRdPtrL1",
+ "cmdRdPtrH1", "cmdAMin1", "reserved68", "cmdAMax1",
+ "reserved70", "cmdFifoDepth1","cmdHoleCnt1", "reserved7c",
+
+ /* 0x080 */
+ "cmdFifoThresh","cmdHoleInt", "reserved88", "reserved8c",
+ "reserved90", "reserved94", "reserved98", "reserved9c",
+ "reserveda0", "reserveda4", "reserveda8", "reservedac",
+ "reservedb0", "reservedb4", "reservedb8", "reservedbc",
+
+ /* 0x0c0 */
+ "reservedc0", "reservedc4", "reservedc8", "reservedcc",
+ "reservedd0", "reservedd4", "reservedd8", "reserveddc",
+ "reservede0", "reservede4", "reservede8", "reservedec",
+ "reservedf0", "reservedf4", "reservedf8", "reservedfc",
+
+ /* 0x100 */
+ "yuvBaseAddress","yuvStride", "reserved108", "reserved10c",
+ "reserved110", "reserved114", "reserved118", "reserved11c",
+ "crc1", "reserved124", "reserved128", "reserved12c",
+ "crc2", "reserved134", "reserved138", "reserved13c"
+};
+
+
+
+/*************************************
+ *
+ * Dithering tables
+ *
+ *************************************/
+
+static const UINT8 dither_matrix_4x4[16] =
+{
+ 0, 8, 2, 10,
+ 12, 4, 14, 6,
+ 3, 11, 1, 9,
+ 15, 7, 13, 5
+};
+
+static const UINT8 dither_matrix_2x2[16] =
+{
+ 2, 10, 2, 10,
+ 14, 6, 14, 6,
+ 2, 10, 2, 10,
+ 14, 6, 14, 6
+};
+
+
+
+/*************************************
+ *
+ * Macros for extracting pixels
+ *
+ *************************************/
+
+#define EXTRACT_565_TO_888(val, a, b, c) \
+ (a) = (((val) >> 8) & 0xf8) | (((val) >> 13) & 0x07); \
+ (b) = (((val) >> 3) & 0xfc) | (((val) >> 9) & 0x03); \
+ (c) = (((val) << 3) & 0xf8) | (((val) >> 2) & 0x07); \
+
+#define EXTRACT_x555_TO_888(val, a, b, c) \
+ (a) = (((val) >> 7) & 0xf8) | (((val) >> 12) & 0x07); \
+ (b) = (((val) >> 2) & 0xf8) | (((val) >> 7) & 0x07); \
+ (c) = (((val) << 3) & 0xf8) | (((val) >> 2) & 0x07); \
+
+#define EXTRACT_555x_TO_888(val, a, b, c) \
+ (a) = (((val) >> 8) & 0xf8) | (((val) >> 13) & 0x07); \
+ (b) = (((val) >> 3) & 0xf8) | (((val) >> 8) & 0x07); \
+ (c) = (((val) << 2) & 0xf8) | (((val) >> 3) & 0x07); \
+
+#define EXTRACT_1555_TO_8888(val, a, b, c, d) \
+ (a) = ((INT16)(val) >> 15) & 0xff; \
+ EXTRACT_x555_TO_888(val, b, c, d) \
+
+#define EXTRACT_5551_TO_8888(val, a, b, c, d) \
+ EXTRACT_555x_TO_888(val, a, b, c) \
+ (d) = ((val) & 0x0001) ? 0xff : 0x00; \
+
+#define EXTRACT_x888_TO_888(val, a, b, c) \
+ (a) = ((val) >> 16) & 0xff; \
+ (b) = ((val) >> 8) & 0xff; \
+ (c) = ((val) >> 0) & 0xff; \
+
+#define EXTRACT_888x_TO_888(val, a, b, c) \
+ (a) = ((val) >> 24) & 0xff; \
+ (b) = ((val) >> 16) & 0xff; \
+ (c) = ((val) >> 8) & 0xff; \
+
+#define EXTRACT_8888_TO_8888(val, a, b, c, d) \
+ (a) = ((val) >> 24) & 0xff; \
+ (b) = ((val) >> 16) & 0xff; \
+ (c) = ((val) >> 8) & 0xff; \
+ (d) = ((val) >> 0) & 0xff; \
+
+#define EXTRACT_4444_TO_8888(val, a, b, c, d) \
+ (a) = (((val) >> 8) & 0xf0) | (((val) >> 12) & 0x0f); \
+ (b) = (((val) >> 4) & 0xf0) | (((val) >> 8) & 0x0f); \
+ (c) = (((val) >> 0) & 0xf0) | (((val) >> 4) & 0x0f); \
+ (d) = (((val) << 4) & 0xf0) | (((val) >> 0) & 0x0f); \
+
+#define EXTRACT_332_TO_888(val, a, b, c) \
+ (a) = (((val) >> 0) & 0xe0) | (((val) >> 3) & 0x1c) | (((val) >> 6) & 0x03); \
+ (b) = (((val) << 3) & 0xe0) | (((val) >> 0) & 0x1c) | (((val) >> 3) & 0x03); \
+ (c) = (((val) << 6) & 0xc0) | (((val) << 4) & 0x30) | (((val) << 2) & 0xc0) | (((val) << 0) & 0x03); \
+
+
+
+/*************************************
+ *
+ * Misc. macros
+ *
+ *************************************/
+
+/* macro for clamping a value between minimum and maximum values */
+#define CLAMP(val,min,max) do { if ((val) < (min)) { (val) = (min); } else if ((val) > (max)) { (val) = (max); } } while (0)
+
+/* macro to compute the base 2 log for LOD calculations */
+#define LOGB2(x) (log((double)(x)) / log(2.0))
+
+
+
+/*************************************
+ *
+ * Macros for extracting bitfields
+ *
+ *************************************/
+
+#define INITEN_ENABLE_HW_INIT(val) (((val) >> 0) & 1)
+#define INITEN_ENABLE_PCI_FIFO(val) (((val) >> 1) & 1)
+#define INITEN_REMAP_INIT_TO_DAC(val) (((val) >> 2) & 1)
+#define INITEN_ENABLE_SNOOP0(val) (((val) >> 4) & 1)
+#define INITEN_SNOOP0_MEMORY_MATCH(val) (((val) >> 5) & 1)
+#define INITEN_SNOOP0_READWRITE_MATCH(val) (((val) >> 6) & 1)
+#define INITEN_ENABLE_SNOOP1(val) (((val) >> 7) & 1)
+#define INITEN_SNOOP1_MEMORY_MATCH(val) (((val) >> 8) & 1)
+#define INITEN_SNOOP1_READWRITE_MATCH(val) (((val) >> 9) & 1)
+#define INITEN_SLI_BUS_OWNER(val) (((val) >> 10) & 1)
+#define INITEN_SLI_ODD_EVEN(val) (((val) >> 11) & 1)
+#define INITEN_SECONDARY_REV_ID(val) (((val) >> 12) & 0xf) /* voodoo 2 only */
+#define INITEN_MFCTR_FAB_ID(val) (((val) >> 16) & 0xf) /* voodoo 2 only */
+#define INITEN_ENABLE_PCI_INTERRUPT(val) (((val) >> 20) & 1) /* voodoo 2 only */
+#define INITEN_PCI_INTERRUPT_TIMEOUT(val) (((val) >> 21) & 1) /* voodoo 2 only */
+#define INITEN_ENABLE_NAND_TREE_TEST(val) (((val) >> 22) & 1) /* voodoo 2 only */
+#define INITEN_ENABLE_SLI_ADDRESS_SNOOP(val) (((val) >> 23) & 1) /* voodoo 2 only */
+#define INITEN_SLI_SNOOP_ADDRESS(val) (((val) >> 24) & 0xff) /* voodoo 2 only */
+
+#define FBZCP_CC_RGBSELECT(val) (((val) >> 0) & 3)
+#define FBZCP_CC_ASELECT(val) (((val) >> 2) & 3)
+#define FBZCP_CC_LOCALSELECT(val) (((val) >> 4) & 1)
+#define FBZCP_CCA_LOCALSELECT(val) (((val) >> 5) & 3)
+#define FBZCP_CC_LOCALSELECT_OVERRIDE(val) (((val) >> 7) & 1)
+#define FBZCP_CC_ZERO_OTHER(val) (((val) >> 8) & 1)
+#define FBZCP_CC_SUB_CLOCAL(val) (((val) >> 9) & 1)
+#define FBZCP_CC_MSELECT(val) (((val) >> 10) & 7)
+#define FBZCP_CC_REVERSE_BLEND(val) (((val) >> 13) & 1)
+#define FBZCP_CC_ADD_ACLOCAL(val) (((val) >> 14) & 3)
+#define FBZCP_CC_INVERT_OUTPUT(val) (((val) >> 16) & 1)
+#define FBZCP_CCA_ZERO_OTHER(val) (((val) >> 17) & 1)
+#define FBZCP_CCA_SUB_CLOCAL(val) (((val) >> 18) & 1)
+#define FBZCP_CCA_MSELECT(val) (((val) >> 19) & 7)
+#define FBZCP_CCA_REVERSE_BLEND(val) (((val) >> 22) & 1)
+#define FBZCP_CCA_ADD_ACLOCAL(val) (((val) >> 23) & 3)
+#define FBZCP_CCA_INVERT_OUTPUT(val) (((val) >> 25) & 1)
+#define FBZCP_CCA_SUBPIXEL_ADJUST(val) (((val) >> 26) & 1)
+#define FBZCP_TEXTURE_ENABLE(val) (((val) >> 27) & 1)
+#define FBZCP_RGBZW_CLAMP(val) (((val) >> 28) & 1) /* voodoo 2 only */
+#define FBZCP_ANTI_ALIAS(val) (((val) >> 29) & 1) /* voodoo 2 only */
+
+#define ALPHAMODE_ALPHATEST(val) (((val) >> 0) & 1)
+#define ALPHAMODE_ALPHAFUNCTION(val) (((val) >> 1) & 7)
+#define ALPHAMODE_ALPHABLEND(val) (((val) >> 4) & 1)
+#define ALPHAMODE_ANTIALIAS(val) (((val) >> 5) & 1)
+#define ALPHAMODE_SRCRGBBLEND(val) (((val) >> 8) & 15)
+#define ALPHAMODE_DSTRGBBLEND(val) (((val) >> 12) & 15)
+#define ALPHAMODE_SRCALPHABLEND(val) (((val) >> 16) & 15)
+#define ALPHAMODE_DSTALPHABLEND(val) (((val) >> 20) & 15)
+#define ALPHAMODE_ALPHAREF(val) (((val) >> 24) & 0xff)
+
+#define FOGMODE_ENABLE_FOG(val) (((val) >> 0) & 1)
+#define FOGMODE_FOG_ADD(val) (((val) >> 1) & 1)
+#define FOGMODE_FOG_MULT(val) (((val) >> 2) & 1)
+#define FOGMODE_FOG_ZALPHA(val) (((val) >> 3) & 3)
+#define FOGMODE_FOG_CONSTANT(val) (((val) >> 5) & 1)
+#define FOGMODE_FOG_DITHER(val) (((val) >> 6) & 1) /* voodoo 2 only */
+#define FOGMODE_FOG_ZONES(val) (((val) >> 7) & 1) /* voodoo 2 only */
+
+#define FBZMODE_ENABLE_CLIPPING(val) (((val) >> 0) & 1)
+#define FBZMODE_ENABLE_CHROMAKEY(val) (((val) >> 1) & 1)
+#define FBZMODE_ENABLE_STIPPLE(val) (((val) >> 2) & 1)
+#define FBZMODE_WBUFFER_SELECT(val) (((val) >> 3) & 1)
+#define FBZMODE_ENABLE_DEPTHBUF(val) (((val) >> 4) & 1)
+#define FBZMODE_DEPTH_FUNCTION(val) (((val) >> 5) & 7)
+#define FBZMODE_ENABLE_DITHERING(val) (((val) >> 8) & 1)
+#define FBZMODE_RGB_BUFFER_MASK(val) (((val) >> 9) & 1)
+#define FBZMODE_AUX_BUFFER_MASK(val) (((val) >> 10) & 1)
+#define FBZMODE_DITHER_TYPE(val) (((val) >> 11) & 1)
+#define FBZMODE_STIPPLE_PATTERN(val) (((val) >> 12) & 1)
+#define FBZMODE_ENABLE_ALPHA_MASK(val) (((val) >> 13) & 1)
+#define FBZMODE_DRAW_BUFFER(val) (((val) >> 14) & 3)
+#define FBZMODE_ENABLE_DEPTH_BIAS(val) (((val) >> 16) & 1)
+#define FBZMODE_Y_ORIGIN(val) (((val) >> 17) & 1)
+#define FBZMODE_ENABLE_ALPHA_PLANES(val) (((val) >> 18) & 1)
+#define FBZMODE_ALPHA_DITHER_SUBTRACT(val) (((val) >> 19) & 1)
+#define FBZMODE_DEPTH_SOURCE_COMPARE(val) (((val) >> 20) & 1)
+#define FBZMODE_DEPTH_FLOAT_SELECT(val) (((val) >> 21) & 1) /* voodoo 2 only */
+
+#define LFBMODE_WRITE_FORMAT(val) (((val) >> 0) & 0xf)
+#define LFBMODE_WRITE_BUFFER_SELECT(val) (((val) >> 4) & 3)
+#define LFBMODE_READ_BUFFER_SELECT(val) (((val) >> 6) & 3)
+#define LFBMODE_ENABLE_PIXEL_PIPELINE(val) (((val) >> 8) & 1)
+#define LFBMODE_RGBA_LANES(val) (((val) >> 9) & 3)
+#define LFBMODE_WORD_SWAP_WRITES(val) (((val) >> 11) & 1)
+#define LFBMODE_BYTE_SWIZZLE_WRITES(val) (((val) >> 12) & 1)
+#define LFBMODE_Y_ORIGIN(val) (((val) >> 13) & 1)
+#define LFBMODE_WRITE_W_SELECT(val) (((val) >> 14) & 1)
+#define LFBMODE_WORD_SWAP_READS(val) (((val) >> 15) & 1)
+#define LFBMODE_BYTE_SWIZZLE_READS(val) (((val) >> 16) & 1)
+
+#define CHROMARANGE_BLUE_EXCLUSIVE(val) (((val) >> 24) & 1)
+#define CHROMARANGE_GREEN_EXCLUSIVE(val) (((val) >> 25) & 1)
+#define CHROMARANGE_RED_EXCLUSIVE(val) (((val) >> 26) & 1)
+#define CHROMARANGE_UNION_MODE(val) (((val) >> 27) & 1)
+#define CHROMARANGE_ENABLE(val) (((val) >> 28) & 1)
+
+#define FBIINIT0_VGA_PASSTHRU(val) (((val) >> 0) & 1)
+#define FBIINIT0_GRAPHICS_RESET(val) (((val) >> 1) & 1)
+#define FBIINIT0_FIFO_RESET(val) (((val) >> 2) & 1)
+#define FBIINIT0_SWIZZLE_REG_WRITES(val) (((val) >> 3) & 1)
+#define FBIINIT0_STALL_PCIE_FOR_HWM(val) (((val) >> 4) & 1)
+#define FBIINIT0_PCI_FIFO_LWM(val) (((val) >> 6) & 0x1f)
+#define FBIINIT0_LFB_TO_MEMORY_FIFO(val) (((val) >> 11) & 1)
+#define FBIINIT0_TEXMEM_TO_MEMORY_FIFO(val) (((val) >> 12) & 1)
+#define FBIINIT0_ENABLE_MEMORY_FIFO(val) (((val) >> 13) & 1)
+#define FBIINIT0_MEMORY_FIFO_HWM(val) (((val) >> 14) & 0x7ff)
+#define FBIINIT0_MEMORY_FIFO_BURST(val) (((val) >> 25) & 0x3f)
+
+#define FBIINIT1_PCI_DEV_FUNCTION(val) (((val) >> 0) & 1)
+#define FBIINIT1_PCI_WRITE_WAIT_STATES(val) (((val) >> 1) & 1)
+#define FBIINIT1_MULTI_SST1(val) (((val) >> 2) & 1) /* not on voodoo 2 */
+#define FBIINIT1_ENABLE_LFB(val) (((val) >> 3) & 1)
+#define FBIINIT1_X_VIDEO_TILES(val) (((val) >> 4) & 0xf)
+#define FBIINIT1_VIDEO_TIMING_RESET(val) (((val) >> 8) & 1)
+#define FBIINIT1_SOFTWARE_OVERRIDE(val) (((val) >> 9) & 1)
+#define FBIINIT1_SOFTWARE_HSYNC(val) (((val) >> 10) & 1)
+#define FBIINIT1_SOFTWARE_VSYNC(val) (((val) >> 11) & 1)
+#define FBIINIT1_SOFTWARE_BLANK(val) (((val) >> 12) & 1)
+#define FBIINIT1_DRIVE_VIDEO_TIMING(val) (((val) >> 13) & 1)
+#define FBIINIT1_DRIVE_VIDEO_BLANK(val) (((val) >> 14) & 1)
+#define FBIINIT1_DRIVE_VIDEO_SYNC(val) (((val) >> 15) & 1)
+#define FBIINIT1_DRIVE_VIDEO_DCLK(val) (((val) >> 16) & 1)
+#define FBIINIT1_VIDEO_TIMING_VCLK(val) (((val) >> 17) & 1)
+#define FBIINIT1_VIDEO_CLK_2X_DELAY(val) (((val) >> 18) & 3)
+#define FBIINIT1_VIDEO_TIMING_SOURCE(val) (((val) >> 20) & 3)
+#define FBIINIT1_ENABLE_24BPP_OUTPUT(val) (((val) >> 22) & 1)
+#define FBIINIT1_ENABLE_SLI(val) (((val) >> 23) & 1)
+#define FBIINIT1_X_VIDEO_TILES_BIT5(val) (((val) >> 24) & 1) /* voodoo 2 only */
+#define FBIINIT1_ENABLE_EDGE_FILTER(val) (((val) >> 25) & 1)
+#define FBIINIT1_INVERT_VID_CLK_2X(val) (((val) >> 26) & 1)
+#define FBIINIT1_VID_CLK_2X_SEL_DELAY(val) (((val) >> 27) & 3)
+#define FBIINIT1_VID_CLK_DELAY(val) (((val) >> 29) & 3)
+#define FBIINIT1_DISABLE_FAST_READAHEAD(val) (((val) >> 31) & 1)
+
+#define FBIINIT2_DISABLE_DITHER_SUB(val) (((val) >> 0) & 1)
+#define FBIINIT2_DRAM_BANKING(val) (((val) >> 1) & 1)
+#define FBIINIT2_ENABLE_TRIPLE_BUF(val) (((val) >> 4) & 1)
+#define FBIINIT2_ENABLE_FAST_RAS_READ(val) (((val) >> 5) & 1)
+#define FBIINIT2_ENABLE_GEN_DRAM_OE(val) (((val) >> 6) & 1)
+#define FBIINIT2_ENABLE_FAST_READWRITE(val) (((val) >> 7) & 1)
+#define FBIINIT2_ENABLE_PASSTHRU_DITHER(val) (((val) >> 8) & 1)
+#define FBIINIT2_SWAP_BUFFER_ALGORITHM(val) (((val) >> 9) & 3)
+#define FBIINIT2_VIDEO_BUFFER_OFFSET(val) (((val) >> 11) & 0x1ff)
+#define FBIINIT2_ENABLE_DRAM_BANKING(val) (((val) >> 20) & 1)
+#define FBIINIT2_ENABLE_DRAM_READ_FIFO(val) (((val) >> 21) & 1)
+#define FBIINIT2_ENABLE_DRAM_REFRESH(val) (((val) >> 22) & 1)
+#define FBIINIT2_REFRESH_LOAD_VALUE(val) (((val) >> 23) & 0x1ff)
+
+#define FBIINIT3_TRI_REGISTER_REMAP(val) (((val) >> 0) & 1)
+#define FBIINIT3_VIDEO_FIFO_THRESH(val) (((val) >> 1) & 0x1f)
+#define FBIINIT3_DISABLE_TMUS(val) (((val) >> 6) & 1)
+#define FBIINIT3_FBI_MEMORY_TYPE(val) (((val) >> 8) & 7)
+#define FBIINIT3_VGA_PASS_RESET_VAL(val) (((val) >> 11) & 1)
+#define FBIINIT3_HARDCODE_PCI_BASE(val) (((val) >> 12) & 1)
+#define FBIINIT3_FBI2TREX_DELAY(val) (((val) >> 13) & 0xf)
+#define FBIINIT3_TREX2FBI_DELAY(val) (((val) >> 17) & 0x1f)
+#define FBIINIT3_YORIGIN_SUBTRACT(val) (((val) >> 22) & 0x3ff)
+
+#define FBIINIT4_PCI_READ_WAITS(val) (((val) >> 0) & 1)
+#define FBIINIT4_ENABLE_LFB_READAHEAD(val) (((val) >> 1) & 1)
+#define FBIINIT4_MEMORY_FIFO_LWM(val) (((val) >> 2) & 0x3f)
+#define FBIINIT4_MEMORY_FIFO_START_ROW(val) (((val) >> 8) & 0x3ff)
+#define FBIINIT4_MEMORY_FIFO_STOP_ROW(val) (((val) >> 18) & 0x3ff)
+#define FBIINIT4_VIDEO_CLOCKING_DELAY(val) (((val) >> 29) & 7) /* voodoo 2 only */
+
+#define FBIINIT5_DISABLE_PCI_STOP(val) (((val) >> 0) & 1) /* voodoo 2 only */
+#define FBIINIT5_PCI_SLAVE_SPEED(val) (((val) >> 1) & 1) /* voodoo 2 only */
+#define FBIINIT5_DAC_DATA_OUTPUT_WIDTH(val) (((val) >> 2) & 1) /* voodoo 2 only */
+#define FBIINIT5_DAC_DATA_17_OUTPUT(val) (((val) >> 3) & 1) /* voodoo 2 only */
+#define FBIINIT5_DAC_DATA_18_OUTPUT(val) (((val) >> 4) & 1) /* voodoo 2 only */
+#define FBIINIT5_GENERIC_STRAPPING(val) (((val) >> 5) & 0xf) /* voodoo 2 only */
+#define FBIINIT5_BUFFER_ALLOCATION(val) (((val) >> 9) & 3) /* voodoo 2 only */
+#define FBIINIT5_DRIVE_VID_CLK_SLAVE(val) (((val) >> 11) & 1) /* voodoo 2 only */
+#define FBIINIT5_DRIVE_DAC_DATA_16(val) (((val) >> 12) & 1) /* voodoo 2 only */
+#define FBIINIT5_VCLK_INPUT_SELECT(val) (((val) >> 13) & 1) /* voodoo 2 only */
+#define FBIINIT5_MULTI_CVG_DETECT(val) (((val) >> 14) & 1) /* voodoo 2 only */
+#define FBIINIT5_SYNC_RETRACE_READS(val) (((val) >> 15) & 1) /* voodoo 2 only */
+#define FBIINIT5_ENABLE_RHBORDER_COLOR(val) (((val) >> 16) & 1) /* voodoo 2 only */
+#define FBIINIT5_ENABLE_LHBORDER_COLOR(val) (((val) >> 17) & 1) /* voodoo 2 only */
+#define FBIINIT5_ENABLE_BVBORDER_COLOR(val) (((val) >> 18) & 1) /* voodoo 2 only */
+#define FBIINIT5_ENABLE_TVBORDER_COLOR(val) (((val) >> 19) & 1) /* voodoo 2 only */
+#define FBIINIT5_DOUBLE_HORIZ(val) (((val) >> 20) & 1) /* voodoo 2 only */
+#define FBIINIT5_DOUBLE_VERT(val) (((val) >> 21) & 1) /* voodoo 2 only */
+#define FBIINIT5_ENABLE_16BIT_GAMMA(val) (((val) >> 22) & 1) /* voodoo 2 only */
+#define FBIINIT5_INVERT_DAC_HSYNC(val) (((val) >> 23) & 1) /* voodoo 2 only */
+#define FBIINIT5_INVERT_DAC_VSYNC(val) (((val) >> 24) & 1) /* voodoo 2 only */
+#define FBIINIT5_ENABLE_24BIT_DACDATA(val) (((val) >> 25) & 1) /* voodoo 2 only */
+#define FBIINIT5_ENABLE_INTERLACING(val) (((val) >> 26) & 1) /* voodoo 2 only */
+#define FBIINIT5_DAC_DATA_18_CONTROL(val) (((val) >> 27) & 1) /* voodoo 2 only */
+#define FBIINIT5_RASTERIZER_UNIT_MODE(val) (((val) >> 30) & 3) /* voodoo 2 only */
+
+#define FBIINIT6_WINDOW_ACTIVE_COUNTER(val) (((val) >> 0) & 7) /* voodoo 2 only */
+#define FBIINIT6_WINDOW_DRAG_COUNTER(val) (((val) >> 3) & 0x1f) /* voodoo 2 only */
+#define FBIINIT6_SLI_SYNC_MASTER(val) (((val) >> 8) & 1) /* voodoo 2 only */
+#define FBIINIT6_DAC_DATA_22_OUTPUT(val) (((val) >> 9) & 3) /* voodoo 2 only */
+#define FBIINIT6_DAC_DATA_23_OUTPUT(val) (((val) >> 11) & 3) /* voodoo 2 only */
+#define FBIINIT6_SLI_SYNCIN_OUTPUT(val) (((val) >> 13) & 3) /* voodoo 2 only */
+#define FBIINIT6_SLI_SYNCOUT_OUTPUT(val) (((val) >> 15) & 3) /* voodoo 2 only */
+#define FBIINIT6_DAC_RD_OUTPUT(val) (((val) >> 17) & 3) /* voodoo 2 only */
+#define FBIINIT6_DAC_WR_OUTPUT(val) (((val) >> 19) & 3) /* voodoo 2 only */
+#define FBIINIT6_PCI_FIFO_LWM_RDY(val) (((val) >> 21) & 0x7f) /* voodoo 2 only */
+#define FBIINIT6_VGA_PASS_N_OUTPUT(val) (((val) >> 28) & 3) /* voodoo 2 only */
+#define FBIINIT6_X_VIDEO_TILES_BIT0(val) (((val) >> 30) & 1) /* voodoo 2 only */
+
+#define FBIINIT7_GENERIC_STRAPPING(val) (((val) >> 0) & 0xff) /* voodoo 2 only */
+#define FBIINIT7_CMDFIFO_ENABLE(val) (((val) >> 8) & 1) /* voodoo 2 only */
+#define FBIINIT7_CMDFIFO_MEMORY_STORE(val) (((val) >> 9) & 1) /* voodoo 2 only */
+#define FBIINIT7_DISABLE_CMDFIFO_HOLES(val) (((val) >> 10) & 1) /* voodoo 2 only */
+#define FBIINIT7_CMDFIFO_READ_THRESH(val) (((val) >> 11) & 0x1f) /* voodoo 2 only */
+#define FBIINIT7_SYNC_CMDFIFO_WRITES(val) (((val) >> 16) & 1) /* voodoo 2 only */
+#define FBIINIT7_SYNC_CMDFIFO_READS(val) (((val) >> 17) & 1) /* voodoo 2 only */
+#define FBIINIT7_RESET_PCI_PACKER(val) (((val) >> 18) & 1) /* voodoo 2 only */
+#define FBIINIT7_ENABLE_CHROMA_STUFF(val) (((val) >> 19) & 1) /* voodoo 2 only */
+#define FBIINIT7_CMDFIFO_PCI_TIMEOUT(val) (((val) >> 20) & 0x7f) /* voodoo 2 only */
+#define FBIINIT7_ENABLE_TEXTURE_BURST(val) (((val) >> 27) & 1) /* voodoo 2 only */
+
+#define TEXMODE_ENABLE_PERSPECTIVE(val) (((val) >> 0) & 1)
+#define TEXMODE_MINIFICATION_FILTER(val) (((val) >> 1) & 1)
+#define TEXMODE_MAGNIFICATION_FILTER(val) (((val) >> 2) & 1)
+#define TEXMODE_CLAMP_NEG_W(val) (((val) >> 3) & 1)
+#define TEXMODE_ENABLE_LOD_DITHER(val) (((val) >> 4) & 1)
+#define TEXMODE_NCC_TABLE_SELECT(val) (((val) >> 5) & 1)
+#define TEXMODE_CLAMP_S(val) (((val) >> 6) & 1)
+#define TEXMODE_CLAMP_T(val) (((val) >> 7) & 1)
+#define TEXMODE_FORMAT(val) (((val) >> 8) & 0xf)
+#define TEXMODE_TC_ZERO_OTHER(val) (((val) >> 12) & 1)
+#define TEXMODE_TC_SUB_CLOCAL(val) (((val) >> 13) & 1)
+#define TEXMODE_TC_MSELECT(val) (((val) >> 14) & 7)
+#define TEXMODE_TC_REVERSE_BLEND(val) (((val) >> 17) & 1)
+#define TEXMODE_TC_ADD_ACLOCAL(val) (((val) >> 18) & 3)
+#define TEXMODE_TC_INVERT_OUTPUT(val) (((val) >> 20) & 1)
+#define TEXMODE_TCA_ZERO_OTHER(val) (((val) >> 21) & 1)
+#define TEXMODE_TCA_SUB_CLOCAL(val) (((val) >> 22) & 1)
+#define TEXMODE_TCA_MSELECT(val) (((val) >> 23) & 7)
+#define TEXMODE_TCA_REVERSE_BLEND(val) (((val) >> 26) & 1)
+#define TEXMODE_TCA_ADD_ACLOCAL(val) (((val) >> 27) & 3)
+#define TEXMODE_TCA_INVERT_OUTPUT(val) (((val) >> 29) & 1)
+#define TEXMODE_TRILINEAR(val) (((val) >> 30) & 1)
+#define TEXMODE_SEQ_8_DOWNLD(val) (((val) >> 31) & 1)
+
+#define TEXLOD_LODMIN(val) (((val) >> 0) & 0x3f)
+#define TEXLOD_LODMAX(val) (((val) >> 6) & 0x3f)
+#define TEXLOD_LODBIAS(val) (((val) >> 12) & 0x3f)
+#define TEXLOD_LOD_ODD(val) (((val) >> 18) & 1)
+#define TEXLOD_LOD_TSPLIT(val) (((val) >> 19) & 1)
+#define TEXLOD_LOD_S_IS_WIDER(val) (((val) >> 20) & 1)
+#define TEXLOD_LOD_ASPECT(val) (((val) >> 21) & 3)
+#define TEXLOD_LOD_ZEROFRAC(val) (((val) >> 23) & 1)
+#define TEXLOD_TMULTIBASEADDR(val) (((val) >> 24) & 1)
+#define TEXLOD_TDATA_SWIZZLE(val) (((val) >> 25) & 1)
+#define TEXLOD_TDATA_SWAP(val) (((val) >> 26) & 1)
+#define TEXLOD_TDIRECT_WRITE(val) (((val) >> 27) & 1) /* Voodoo 2 only */
+
+#define TEXDETAIL_DETAIL_MAX(val) (((val) >> 0) & 0xff)
+#define TEXDETAIL_DETAIL_BIAS(val) (((val) >> 8) & 0x3f)
+#define TEXDETAIL_DETAIL_SCALE(val) (((val) >> 14) & 7)
+#define TEXDETAIL_RGB_MIN_FILTER(val) (((val) >> 17) & 1) /* Voodoo 2 only */
+#define TEXDETAIL_RGB_MAG_FILTER(val) (((val) >> 18) & 1) /* Voodoo 2 only */
+#define TEXDETAIL_ALPHA_MIN_FILTER(val) (((val) >> 19) & 1) /* Voodoo 2 only */
+#define TEXDETAIL_ALPHA_MAG_FILTER(val) (((val) >> 20) & 1) /* Voodoo 2 only */
+#define TEXDETAIL_SEPARATE_RGBA_FILTER(val) (((val) >> 21) & 1) /* Voodoo 2 only */
+
+
+
+/*************************************
+ *
+ * Core types
+ *
+ *************************************/
+
+typedef struct _voodoo_state voodoo_state;
+typedef struct _poly_extra_data poly_extra_data;
+
+
+typedef struct _rgba rgba;
+struct _rgba
+{
+#ifdef LSB_FIRST
+ UINT8 b, g, r, a;
+#else
+ UINT8 a, r, g, b;
+#endif
+};
+
+
+typedef union _voodoo_reg voodoo_reg;
+union _voodoo_reg
+{
+ INT32 i;
+ UINT32 u;
+ float f;
+ rgba rgb;
+};
+
+
+typedef voodoo_reg rgb_union;
+
+
+typedef struct _voodoo_stats voodoo_stats;
+struct _voodoo_stats
+{
+ UINT8 lastkey; /* last key state */
+ UINT8 display; /* display stats? */
+ INT32 swaps; /* total swaps */
+ INT32 stalls; /* total stalls */
+ INT32 total_triangles; /* total triangles */
+ INT32 total_pixels_in; /* total pixels in */
+ INT32 total_pixels_out; /* total pixels out */
+ INT32 total_chroma_fail; /* total chroma fail */
+ INT32 total_zfunc_fail; /* total z func fail */
+ INT32 total_afunc_fail; /* total a func fail */
+ INT32 total_clipped; /* total clipped */
+ INT32 total_stippled; /* total stippled */
+ INT32 lfb_writes; /* LFB writes */
+ INT32 lfb_reads; /* LFB reads */
+ INT32 reg_writes; /* register writes */
+ INT32 reg_reads; /* register reads */
+ INT32 tex_writes; /* texture writes */
+ INT32 texture_mode[16]; /* 16 different texture modes */
+ UINT8 render_override; /* render override */
+ char buffer[1024]; /* string */
+};
+
+
+/* note that this structure is an even 64 bytes long */
+typedef struct _stats_block stats_block;
+struct _stats_block
+{
+ INT32 pixels_in; /* pixels in statistic */
+ INT32 pixels_out; /* pixels out statistic */
+ INT32 chroma_fail; /* chroma test fail statistic */
+ INT32 zfunc_fail; /* z function test fail statistic */
+ INT32 afunc_fail; /* alpha function test fail statistic */
+ INT32 clip_fail; /* clipping fail statistic */
+ INT32 stipple_count; /* stipple statistic */
+ INT32 filler[64/4 - 7]; /* pad this structure to 64 bytes */
+};
+
+
+typedef struct _fifo_state fifo_state;
+struct _fifo_state
+{
+ UINT32 * base; /* base of the FIFO */
+ INT32 size; /* size of the FIFO */
+ INT32 in; /* input pointer */
+ INT32 out; /* output pointer */
+};
+
+
+typedef struct _cmdfifo_info cmdfifo_info;
+struct _cmdfifo_info
+{
+ UINT8 enable; /* enabled? */
+ UINT8 count_holes; /* count holes? */
+ UINT32 base; /* base address in framebuffer RAM */
+ UINT32 end; /* end address in framebuffer RAM */
+ UINT32 rdptr; /* current read pointer */
+ UINT32 amin; /* minimum address */
+ UINT32 amax; /* maximum address */
+ UINT32 depth; /* current depth */
+ UINT32 holes; /* number of holes */
+};
+
+
+typedef struct _pci_state pci_state;
+struct _pci_state
+{
+ fifo_state fifo; /* PCI FIFO */
+ UINT32 init_enable; /* initEnable value */
+ UINT8 stall_state; /* state of the system if we're stalled */
+ void (*stall_callback)(int); /* callback for stalling/unstalling */
+ UINT8 op_pending; /* true if an operation is pending */
+ attotime op_end_time; /* time when the pending operation ends */
+ emu_timer *continue_timer; /* timer to use to continue processing */
+ UINT32 fifo_mem[64*2]; /* memory backing the PCI FIFO */
+};
+
+
+typedef struct _ncc_table ncc_table;
+struct _ncc_table
+{
+ UINT8 dirty; /* is the texel lookup dirty? */
+ voodoo_reg *reg; /* pointer to our registers */
+ INT32 ir[4], ig[4], ib[4]; /* I values for R,G,B */
+ INT32 qr[4], qg[4], qb[4]; /* Q values for R,G,B */
+ INT32 y[16]; /* Y values */
+ rgb_t * palette; /* pointer to associated RGB palette */
+ rgb_t * palettea; /* pointer to associated ARGB palette */
+ rgb_t texel[256]; /* texel lookup */
+};
+
+
+typedef struct _tmu_state tmu_state;
+struct _tmu_state
+{
+ UINT8 * ram; /* pointer to our RAM */
+ UINT32 mask; /* mask to apply to pointers */
+ voodoo_reg *reg; /* pointer to our register base */
+ UINT32 regdirty; /* true if the LOD/mode/base registers have changed */
+
+ UINT32 texaddr_mask; /* mask for texture address */
+ UINT8 texaddr_shift; /* shift for texture address */
+
+ INT64 starts, startt; /* starting S,T (14.18) */
+ INT64 startw; /* starting W (2.30) */
+ INT64 dsdx, dtdx; /* delta S,T per X */
+ INT64 dwdx; /* delta W per X */
+ INT64 dsdy, dtdy; /* delta S,T per Y */
+ INT64 dwdy; /* delta W per Y */
+
+ INT32 lodmin, lodmax; /* min, max LOD values */
+ INT32 lodbias; /* LOD bias */
+ UINT32 lodmask; /* mask of available LODs */
+ UINT32 lodoffset[9]; /* offset of texture base for each LOD */
+ INT32 detailmax; /* detail clamp */
+ INT32 detailbias; /* detail bias */
+ UINT8 detailscale; /* detail scale */
+
+ UINT32 wmask; /* mask for the current texture width */
+ UINT32 hmask; /* mask for the current texture height */
+
+ UINT32 bilinear_mask; /* mask for bilinear resolution (0xf0 for V1, 0xff for V2) */
+
+ ncc_table ncc[2]; /* two NCC tables */
+
+ rgb_t * lookup; /* currently selected lookup */
+ rgb_t * texel[16]; /* texel lookups for each format */
+
+ rgb_t palette[256]; /* palette lookup table */
+ rgb_t palettea[256]; /* palette+alpha lookup table */
+};
+
+
+typedef struct _tmu_shared_state tmu_shared_state;
+struct _tmu_shared_state
+{
+ rgb_t rgb332[256]; /* RGB 3-3-2 lookup table */
+ rgb_t alpha8[256]; /* alpha 8-bit lookup table */
+ rgb_t int8[256]; /* intensity 8-bit lookup table */
+ rgb_t ai44[256]; /* alpha, intensity 4-4 lookup table */
+
+ rgb_t rgb565[65536]; /* RGB 5-6-5 lookup table */
+ rgb_t argb1555[65536]; /* ARGB 1-5-5-5 lookup table */
+ rgb_t argb4444[65536]; /* ARGB 4-4-4-4 lookup table */
+};
+
+
+typedef struct _setup_vertex setup_vertex;
+struct _setup_vertex
+{
+ float x, y; /* X, Y coordinates */
+ float a, r, g, b; /* A, R, G, B values */
+ float z, wb; /* Z and broadcast W values */
+ float w0, s0, t0; /* W, S, T for TMU 0 */
+ float w1, s1, t1; /* W, S, T for TMU 1 */
+};
+
+
+typedef struct _fbi_state fbi_state;
+struct _fbi_state
+{
+ void * ram; /* pointer to frame buffer RAM */
+ UINT32 mask; /* mask to apply to pointers */
+ UINT16 * rgb[3]; /* pointer to 3 RGB buffers */
+ UINT16 * aux; /* pointer to 1 aux buffer */
+ UINT32 rgbmax[3]; /* maximum valid offset in each RGB buffer */
+ UINT32 auxmax; /* maximum valid offset in the aux buffer */
+
+ UINT8 frontbuf; /* front buffer index */
+ UINT8 backbuf; /* back buffer index */
+ UINT8 swaps_pending; /* number of pending swaps */
+ UINT8 video_changed; /* did the frontbuffer video change? */
+
+ UINT32 yorigin; /* Y origin subtract value */
+ UINT32 lfb_base; /* base of LFB in memory */
+ UINT8 lfb_stride; /* stride of LFB accesses in bits */
+
+ UINT32 width; /* width of current frame buffer */
+ UINT32 height; /* height of current frame buffer */
+ UINT32 xoffs; /* horizontal offset (back porch) */
+ UINT32 yoffs; /* vertical offset (back porch) */
+ UINT32 vsyncscan; /* vertical sync scanline */
+ UINT32 rowpixels; /* pixels per row */
+ UINT32 tile_width; /* width of video tiles */
+ UINT32 tile_height; /* height of video tiles */
+ UINT32 x_tiles; /* number of tiles in the X direction */
+
+ emu_timer * vblank_timer; /* VBLANK timer */
+ UINT8 vblank; /* VBLANK state */
+ UINT8 vblank_count; /* number of VBLANKs since last swap */
+ UINT8 vblank_swap_pending; /* a swap is pending, waiting for a vblank */
+ UINT8 vblank_swap; /* swap when we hit this count */
+ UINT8 vblank_dont_swap; /* don't actually swap when we hit this point */
+ void (*vblank_client)(int); /* client callback */
+
+ /* triangle setup info */
+ UINT8 cheating_allowed; /* allow cheating? */
+ INT32 sign; /* triangle sign */
+ INT16 ax, ay; /* vertex A x,y (12.4) */
+ INT16 bx, by; /* vertex B x,y (12.4) */
+ INT16 cx, cy; /* vertex C x,y (12.4) */
+ INT32 startr, startg, startb, starta; /* starting R,G,B,A (12.12) */
+ INT32 startz; /* starting Z (20.12) */
+ INT64 startw; /* starting W (16.32) */
+ INT32 drdx, dgdx, dbdx, dadx; /* delta R,G,B,A per X */
+ INT32 dzdx; /* delta Z per X */
+ INT64 dwdx; /* delta W per X */
+ INT32 drdy, dgdy, dbdy, dady; /* delta R,G,B,A per Y */
+ INT32 dzdy; /* delta Z per Y */
+ INT64 dwdy; /* delta W per Y */
+
+ stats_block lfb_stats; /* LFB-access statistics */
+
+ UINT8 sverts; /* number of vertices ready */
+ setup_vertex svert[3]; /* 3 setup vertices */
+
+ fifo_state fifo; /* framebuffer memory fifo */
+ cmdfifo_info cmdfifo[2]; /* command FIFOs */
+
+ UINT8 fogblend[64]; /* 64-entry fog table */
+ UINT8 fogdelta[64]; /* 64-entry fog table */
+ UINT8 fogdelta_mask; /* mask for for delta (0xff for V1, 0xfc for V2) */
+
+ rgb_t pen[65536]; /* mapping from pixels to pens */
+ rgb_t clut[512]; /* clut gamma data */
+ UINT8 clut_dirty; /* do we need to recompute? */
+};
+
+
+typedef struct _dac_state dac_state;
+struct _dac_state
+{
+ UINT8 reg[8]; /* 8 registers */
+ UINT8 read_result; /* pending read result */
+};
+
+
+typedef struct _raster_info raster_info;
+struct _raster_info
+{
+ struct _raster_info *next; /* pointer to next entry with the same hash */
+ poly_draw_scanline callback; /* callback pointer */
+ UINT8 is_generic; /* TRUE if this is one of the generic rasterizers */
+ UINT8 display; /* display index */
+ UINT32 hits; /* how many hits (pixels) we've used this for */
+ UINT32 polys; /* how many polys we've used this for */
+ UINT32 eff_color_path; /* effective fbzColorPath value */
+ UINT32 eff_alpha_mode; /* effective alphaMode value */
+ UINT32 eff_fog_mode; /* effective fogMode value */
+ UINT32 eff_fbz_mode; /* effective fbzMode value */
+ UINT32 eff_tex_mode_0; /* effective textureMode value for TMU #0 */
+ UINT32 eff_tex_mode_1; /* effective textureMode value for TMU #1 */
+};
+
+
+struct _poly_extra_data
+{
+ voodoo_state *state; /* pointer back to the voodoo state */
+ raster_info *info; /* pointer to rasterizer information */
+
+ INT16 ax, ay; /* vertex A x,y (12.4) */
+ INT32 startr, startg, startb, starta; /* starting R,G,B,A (12.12) */
+ INT32 startz; /* starting Z (20.12) */
+ INT64 startw; /* starting W (16.32) */
+ INT32 drdx, dgdx, dbdx, dadx; /* delta R,G,B,A per X */
+ INT32 dzdx; /* delta Z per X */
+ INT64 dwdx; /* delta W per X */
+ INT32 drdy, dgdy, dbdy, dady; /* delta R,G,B,A per Y */
+ INT32 dzdy; /* delta Z per Y */
+ INT64 dwdy; /* delta W per Y */
+
+ INT64 starts0, startt0; /* starting S,T (14.18) */
+ INT64 startw0; /* starting W (2.30) */
+ INT64 ds0dx, dt0dx; /* delta S,T per X */
+ INT64 dw0dx; /* delta W per X */
+ INT64 ds0dy, dt0dy; /* delta S,T per Y */
+ INT64 dw0dy; /* delta W per Y */
+ INT32 lodbase0; /* used during rasterization */
+
+ INT64 starts1, startt1; /* starting S,T (14.18) */
+ INT64 startw1; /* starting W (2.30) */
+ INT64 ds1dx, dt1dx; /* delta S,T per X */
+ INT64 dw1dx; /* delta W per X */
+ INT64 ds1dy, dt1dy; /* delta S,T per Y */
+ INT64 dw1dy; /* delta W per Y */
+ INT32 lodbase1; /* used during rasterization */
+
+ UINT16 dither[16]; /* dither matrix, for fastfill */
+};
+
+
+typedef struct _banshee_info banshee_info;
+struct _banshee_info
+{
+ UINT32 io[0x40]; /* I/O registers */
+ UINT32 agp[0x80]; /* AGP registers */
+ UINT8 vga[0x20]; /* VGA registers */
+ UINT8 crtc[0x27]; /* VGA CRTC registers */
+ UINT8 seq[0x05]; /* VGA sequencer registers */
+ UINT8 gc[0x05]; /* VGA graphics controller registers */
+ UINT8 att[0x15]; /* VGA attribute registers */
+ UINT8 attff; /* VGA attribute flip-flop */
+};
+
+
+/* typedef struct _voodoo_state voodoo_state; -- declared above */
+struct _voodoo_state
+{
+ UINT8 index; /* index of board */
+ UINT8 scrnum; /* the screen we are acting on */
+ UINT8 type; /* type of system */
+ UINT8 chipmask; /* mask for which chips are available */
+ UINT32 freq; /* operating frequency */
+ attoseconds_t attoseconds_per_cycle;/* attoseconds per cycle */
+ UINT32 extra_cycles; /* extra cycles not yet accounted for */
+ int trigger; /* trigger used for stalling */
+
+ voodoo_reg reg[0x400]; /* raw registers */
+ const UINT8 *regaccess; /* register access array */
+ const char **regnames; /* register names array */
+ UINT8 alt_regmap; /* enable alternate register map? */
+
+ pci_state pci; /* PCI state */
+ dac_state dac; /* DAC state */
+
+ fbi_state fbi; /* FBI states */
+ tmu_state tmu[MAX_TMU]; /* TMU states */
+ tmu_shared_state tmushare; /* TMU shared state */
+ banshee_info banshee; /* Banshee state */
+
+ poly_manager *poly; /* polygon manager */
+ stats_block *thread_stats; /* per-thread statistics */
+
+ voodoo_stats stats; /* internal statistics */
+
+ offs_t last_status_pc; /* PC of last status read (for logging) */
+ UINT32 last_status_value; /* value of last status read (for logging) */
+
+ int next_rasterizer; /* next rasterizer index */
+ raster_info rasterizer[MAX_RASTERIZERS]; /* array of rasterizers */
+ raster_info *raster_hash[RASTER_HASH_SIZE]; /* hash table of rasterizers */
+};
+
+
+
+/*************************************
+ *
+ * Inline FIFO management
+ *
+ *************************************/
+
+INLINE void fifo_reset(fifo_state *f)
+{
+ f->in = f->out = 0;
+}
+
+
+INLINE void fifo_add(fifo_state *f, UINT32 data)
+{
+ INT32 next_in;
+
+ /* compute the value of 'in' after we add this item */
+ next_in = f->in + 1;
+ if (next_in >= f->size)
+ next_in = 0;
+
+ /* as long as it's not equal to the output pointer, we can do it */
+ if (next_in != f->out)
+ {
+ f->base[f->in] = data;
+ f->in = next_in;
+ }
+}
+
+
+INLINE UINT32 fifo_remove(fifo_state *f)
+{
+ UINT32 data = 0xffffffff;
+
+ /* as long as we have data, we can do it */
+ if (f->out != f->in)
+ {
+ INT32 next_out;
+
+ /* fetch the data */
+ data = f->base[f->out];
+
+ /* advance the output pointer */
+ next_out = f->out + 1;
+ if (next_out >= f->size)
+ next_out = 0;
+ f->out = next_out;
+ }
+ return data;
+}
+
+
+INLINE UINT32 fifo_peek(fifo_state *f)
+{
+ return f->base[f->out];
+}
+
+
+INLINE int fifo_empty(fifo_state *f)
+{
+ return (f->in == f->out);
+}
+
+
+INLINE int fifo_full(fifo_state *f)
+{
+ return (f->in + 1 == f->out || (f->in == f->size - 1 && f->out == 0));
+}
+
+
+INLINE INT32 fifo_items(fifo_state *f)
+{
+ INT32 items = f->in - f->out;
+ if (items < 0)
+ items += f->size;
+ return items;
+}
+
+
+INLINE INT32 fifo_space(fifo_state *f)
+{
+ INT32 items = f->in - f->out;
+ if (items < 0)
+ items += f->size;
+ return f->size - 1 - items;
+}
+
+
+
+/*************************************
+ *
+ * Computes a fast 16.16 reciprocal
+ * of a 16.32 value; used for
+ * computing 1/w in the rasterizer.
+ *
+ * Since it is trivial to also
+ * compute log2(1/w) = -log2(w) at
+ * the same time, we do that as well
+ * to 16.8 precision for LOD
+ * calculations.
+ *
+ * On a Pentium M, this routine is
+ * 20% faster than a 64-bit integer
+ * divide and also produces the log
+ * for free.
+ *
+ *************************************/
+
+INLINE INT32 fast_reciplog(INT64 value, INT32 *log2)
+{
+ extern UINT32 reciplog[];
+ UINT32 temp, recip, rlog;
+ UINT32 interp;
+ UINT32 *table;
+ int neg = FALSE;
+ int lz, exp = 0;
+
+ /* always work with unsigned numbers */
+ if (value < 0)
+ {
+ value = -value;
+ neg = TRUE;
+ }
+
+ /* if we've spilled out of 32 bits, push it down under 32 */
+ if (value & U64(0xffff00000000))
+ {
+ temp = (UINT32)(value >> 16);
+ exp -= 16;
+ }
+ else
+ temp = (UINT32)value;
+
+ /* if the resulting value is 0, the reciprocal is infinite */
+ if (UNEXPECTED(temp == 0))
+ {
+ *log2 = 1000 << LOG_OUTPUT_PREC;
+ return neg ? 0x80000000 : 0x7fffffff;
+ }
+
+ /* determine how many leading zeros in the value and shift it up high */
+ lz = count_leading_zeros(temp);
+ temp <<= lz;
+ exp += lz;
+
+ /* compute a pointer to the table entries we want */
+ /* math is a bit funny here because we shift one less than we need to in order */
+ /* to account for the fact that there are two UINT32's per table entry */
+ table = &reciplog[(temp >> (31 - RECIPLOG_LOOKUP_BITS - 1)) & ((2 << RECIPLOG_LOOKUP_BITS) - 2)];
+
+ /* compute the interpolation value */
+ interp = (temp >> (31 - RECIPLOG_LOOKUP_BITS - 8)) & 0xff;
+
+ /* do a linear interpolatation between the two nearest table values */
+ /* for both the log and the reciprocal */
+ rlog = (table[1] * (0x100 - interp) + table[3] * interp) >> 8;
+ recip = (table[0] * (0x100 - interp) + table[2] * interp) >> 8;
+
+ /* the log result is the fractional part of the log; round it to the output precision */
+ rlog = (rlog + (1 << (RECIPLOG_LOOKUP_PREC - LOG_OUTPUT_PREC - 1))) >> (RECIPLOG_LOOKUP_PREC - LOG_OUTPUT_PREC);
+
+ /* the exponent is the non-fractional part of the log; normally, we would subtract it from rlog */
+ /* but since we want the log(1/value) = -log(value), we subtract rlog from the exponent */
+ *log2 = ((exp - (31 - RECIPLOG_INPUT_PREC)) << LOG_OUTPUT_PREC) - rlog;
+
+ /* adjust the exponent to account for all the reciprocal-related parameters to arrive at a final shift amount */
+ exp += (RECIP_OUTPUT_PREC - RECIPLOG_LOOKUP_PREC) - (31 - RECIPLOG_INPUT_PREC);
+
+ /* shift by the exponent */
+ if (exp < 0)
+ recip >>= -exp;
+ else
+ recip <<= exp;
+
+ /* on the way out, apply the original sign to the reciprocal */
+ return neg ? -recip : recip;
+}
+
+
+
+/*************************************
+ *
+ * Float-to-int conversions
+ *
+ *************************************/
+
+INLINE INT32 float_to_int32(UINT32 data, int fixedbits)
+{
+ int exponent = ((data >> 23) & 0xff) - 127 - 23 + fixedbits;
+ INT32 result = (data & 0x7fffff) | 0x800000;
+ if (exponent < 0)
+ {
+ if (exponent > -32)
+ result >>= -exponent;
+ else
+ result = 0;
+ }
+ else
+ {
+ if (exponent < 32)
+ result <<= exponent;
+ else
+ result = 0x7fffffff;
+ }
+ if (data & 0x80000000)
+ result = -result;
+ return result;
+}
+
+
+INLINE INT64 float_to_int64(UINT32 data, int fixedbits)
+{
+ int exponent = ((data >> 23) & 0xff) - 127 - 23 + fixedbits;
+ INT64 result = (data & 0x7fffff) | 0x800000;
+ if (exponent < 0)
+ {
+ if (exponent > -64)
+ result >>= -exponent;
+ else
+ result = 0;
+ }
+ else
+ {
+ if (exponent < 64)
+ result <<= exponent;
+ else
+ result = U64(0x7fffffffffffffff);
+ }
+ if (data & 0x80000000)
+ result = -result;
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Rasterizer inlines
+ *
+ *************************************/
+
+INLINE UINT32 normalize_color_path(UINT32 eff_color_path)
+{
+ /* ignore the subpixel adjust and texture enable flags */
+ eff_color_path &= ~((1 << 26) | (1 << 27));
+
+ return eff_color_path;
+}
+
+
+INLINE UINT32 normalize_alpha_mode(UINT32 eff_alpha_mode)
+{
+ /* always ignore alpha ref value */
+ eff_alpha_mode &= ~(0xff << 24);
+
+ /* if not doing alpha testing, ignore the alpha function and ref value */
+ if (!ALPHAMODE_ALPHATEST(eff_alpha_mode))
+ eff_alpha_mode &= ~(7 << 1);
+
+ /* if not doing alpha blending, ignore the source and dest blending factors */
+ if (!ALPHAMODE_ALPHABLEND(eff_alpha_mode))
+ eff_alpha_mode &= ~((15 << 8) | (15 << 12) | (15 << 16) | (15 << 20));
+
+ return eff_alpha_mode;
+}
+
+
+INLINE UINT32 normalize_fog_mode(UINT32 eff_fog_mode)
+{
+ /* if not doing fogging, ignore all the other fog bits */
+ if (!FOGMODE_ENABLE_FOG(eff_fog_mode))
+ eff_fog_mode = 0;
+
+ return eff_fog_mode;
+}
+
+
+INLINE UINT32 normalize_fbz_mode(UINT32 eff_fbz_mode)
+{
+ /* ignore the draw buffer */
+ eff_fbz_mode &= ~(3 << 14);
+
+ return eff_fbz_mode;
+}
+
+
+INLINE UINT32 normalize_tex_mode(UINT32 eff_tex_mode)
+{
+ /* ignore the NCC table and seq_8_downld flags */
+ eff_tex_mode &= ~((1 << 5) | (1 << 31));
+
+ /* classify texture formats into 3 format categories */
+ if (TEXMODE_FORMAT(eff_tex_mode) < 8)
+ eff_tex_mode = (eff_tex_mode & ~(0xf << 8)) | (0 << 8);
+ else if (TEXMODE_FORMAT(eff_tex_mode) >= 10 && TEXMODE_FORMAT(eff_tex_mode) <= 12)
+ eff_tex_mode = (eff_tex_mode & ~(0xf << 8)) | (10 << 8);
+ else
+ eff_tex_mode = (eff_tex_mode & ~(0xf << 8)) | (8 << 8);
+
+ return eff_tex_mode;
+}
+
+
+INLINE UINT32 compute_raster_hash(const raster_info *info)
+{
+ UINT32 hash;
+
+ /* make a hash */
+ hash = info->eff_color_path;
+ hash = (hash << 1) | (hash >> 31);
+ hash ^= info->eff_fbz_mode;
+ hash = (hash << 1) | (hash >> 31);
+ hash ^= info->eff_alpha_mode;
+ hash = (hash << 1) | (hash >> 31);
+ hash ^= info->eff_fog_mode;
+ hash = (hash << 1) | (hash >> 31);
+ hash ^= info->eff_tex_mode_0;
+ hash = (hash << 1) | (hash >> 31);
+ hash ^= info->eff_tex_mode_1;
+
+ return hash % RASTER_HASH_SIZE;
+}
+
+
+
+/*************************************
+ *
+ * Dithering macros
+ *
+ *************************************/
+
+/* note that these equations and the dither matrixes have
+ been confirmed to be exact matches to the real hardware */
+#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)
+
+#define DECLARE_DITHER_POINTERS \
+ const UINT8 *dither_lookup = NULL; \
+ const UINT8 *dither4 = NULL; \
+ const UINT8 *dither = NULL \
+
+#define COMPUTE_DITHER_POINTERS(FBZMODE, YY) \
+do \
+{ \
+ /* compute the dithering pointers */ \
+ if (FBZMODE_ENABLE_DITHERING(FBZMODE)) \
+ { \
+ dither4 = &dither_matrix_4x4[((YY) & 3) * 4]; \
+ if (FBZMODE_DITHER_TYPE(FBZMODE) == 0) \
+ { \
+ dither = dither4; \
+ dither_lookup = &dither4_lookup[(YY & 3) << 11]; \
+ } \
+ else \
+ { \
+ dither = &dither_matrix_2x2[((YY) & 3) * 4]; \
+ dither_lookup = &dither2_lookup[(YY & 3) << 11]; \
+ } \
+ } \
+} \
+while (0)
+
+#define APPLY_DITHER(FBZMODE, XX, DITHER_LOOKUP, RR, GG, BB) \
+do \
+{ \
+ /* apply dithering */ \
+ if (FBZMODE_ENABLE_DITHERING(FBZMODE)) \
+ { \
+ /* look up the dither value from the appropriate matrix */ \
+ const UINT8 *dith = &DITHER_LOOKUP[((XX) & 3) << 1]; \
+ \
+ /* apply dithering to R,G,B */ \
+ (RR) = dith[((RR) << 3) + 0]; \
+ (GG) = dith[((GG) << 3) + 1]; \
+ (BB) = dith[((BB) << 3) + 0]; \
+ } \
+ else \
+ { \
+ (RR) >>= 3; \
+ (GG) >>= 2; \
+ (BB) >>= 3; \
+ } \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Clamping macros
+ *
+ *************************************/
+
+#define CLAMPED_ARGB(ITERR, ITERG, ITERB, ITERA, FBZCP, RESULT) \
+do \
+{ \
+ INT32 r = (INT32)(ITERR) >> 12; \
+ INT32 g = (INT32)(ITERG) >> 12; \
+ INT32 b = (INT32)(ITERB) >> 12; \
+ INT32 a = (INT32)(ITERA) >> 12; \
+ \
+ if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) \
+ { \
+ r &= 0xfff; \
+ RESULT.rgb.r = r; \
+ if (r == 0xfff) \
+ RESULT.rgb.r = 0; \
+ else if (r == 0x100) \
+ RESULT.rgb.r = 0xff; \
+ \
+ g &= 0xfff; \
+ RESULT.rgb.g = g; \
+ if (g == 0xfff) \
+ RESULT.rgb.g = 0; \
+ else if (g == 0x100) \
+ RESULT.rgb.g = 0xff; \
+ \
+ b &= 0xfff; \
+ RESULT.rgb.b = b; \
+ if (b == 0xfff) \
+ RESULT.rgb.b = 0; \
+ else if (b == 0x100) \
+ RESULT.rgb.b = 0xff; \
+ \
+ a &= 0xfff; \
+ RESULT.rgb.a = a; \
+ if (a == 0xfff) \
+ RESULT.rgb.a = 0; \
+ else if (a == 0x100) \
+ RESULT.rgb.a = 0xff; \
+ } \
+ else \
+ { \
+ RESULT.rgb.r = (r < 0) ? 0 : (r > 0xff) ? 0xff : r; \
+ RESULT.rgb.g = (g < 0) ? 0 : (g > 0xff) ? 0xff : g; \
+ RESULT.rgb.b = (b < 0) ? 0 : (b > 0xff) ? 0xff : b; \
+ RESULT.rgb.a = (a < 0) ? 0 : (a > 0xff) ? 0xff : a; \
+ } \
+} \
+while (0)
+
+
+#define CLAMPED_Z(ITERZ, FBZCP, RESULT) \
+do \
+{ \
+ (RESULT) = (INT32)(ITERZ) >> 12; \
+ if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) \
+ { \
+ (RESULT) &= 0xfffff; \
+ if ((RESULT) == 0xfffff) \
+ (RESULT) = 0; \
+ else if ((RESULT) == 0x10000) \
+ (RESULT) = 0xffff; \
+ else \
+ (RESULT) &= 0xffff; \
+ } \
+ else \
+ { \
+ CLAMP((RESULT), 0, 0xffff); \
+ } \
+} \
+while (0)
+
+
+#define CLAMPED_W(ITERW, FBZCP, RESULT) \
+do \
+{ \
+ (RESULT) = (INT16)((ITERW) >> 32); \
+ if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) \
+ { \
+ (RESULT) &= 0xffff; \
+ if ((RESULT) == 0xffff) \
+ (RESULT) = 0; \
+ else if ((RESULT) == 0x100) \
+ (RESULT) = 0xff; \
+ (RESULT) &= 0xff; \
+ } \
+ else \
+ { \
+ CLAMP((RESULT), 0, 0xff); \
+ } \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Chroma keying macro
+ *
+ *************************************/
+
+#define APPLY_CHROMAKEY(VV, STATS, FBZMODE, COLOR) \
+do \
+{ \
+ if (FBZMODE_ENABLE_CHROMAKEY(FBZMODE)) \
+ { \
+ /* non-range version */ \
+ if (!CHROMARANGE_ENABLE((VV)->reg[chromaRange].u)) \
+ { \
+ if (((COLOR.u ^ (VV)->reg[chromaKey].u) & 0xffffff) == 0) \
+ { \
+ (STATS)->chroma_fail++; \
+ goto skipdrawdepth; \
+ } \
+ } \
+ \
+ /* tricky range version */ \
+ else \
+ { \
+ INT32 low, high, test; \
+ int results = 0; \
+ \
+ /* check blue */ \
+ low = (VV)->reg[chromaKey].rgb.b; \
+ high = (VV)->reg[chromaRange].rgb.b; \
+ test = COLOR.rgb.b; \
+ results = (test >= low && test <= high); \
+ results ^= CHROMARANGE_BLUE_EXCLUSIVE((VV)->reg[chromaRange].u); \
+ results <<= 1; \
+ \
+ /* check green */ \
+ low = (VV)->reg[chromaKey].rgb.g; \
+ high = (VV)->reg[chromaRange].rgb.g; \
+ test = COLOR.rgb.g; \
+ results |= (test >= low && test <= high); \
+ results ^= CHROMARANGE_GREEN_EXCLUSIVE((VV)->reg[chromaRange].u); \
+ results <<= 1; \
+ \
+ /* check red */ \
+ low = (VV)->reg[chromaKey].rgb.r; \
+ high = (VV)->reg[chromaRange].rgb.r; \
+ test = COLOR.rgb.r; \
+ results |= (test >= low && test <= high); \
+ results ^= CHROMARANGE_RED_EXCLUSIVE((VV)->reg[chromaRange].u); \
+ \
+ /* final result */ \
+ if (CHROMARANGE_UNION_MODE((VV)->reg[chromaRange].u)) \
+ { \
+ if (results != 0) \
+ { \
+ (STATS)->chroma_fail++; \
+ goto skipdrawdepth; \
+ } \
+ } \
+ else \
+ { \
+ if (results == 7) \
+ { \
+ (STATS)->chroma_fail++; \
+ goto skipdrawdepth; \
+ } \
+ } \
+ } \
+ } \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Alpha masking macro
+ *
+ *************************************/
+
+#define APPLY_ALPHAMASK(VV, STATS, FBZMODE, AA) \
+do \
+{ \
+ if (FBZMODE_ENABLE_ALPHA_MASK(FBZMODE)) \
+ { \
+ if (((AA) & 1) == 0) \
+ { \
+ (STATS)->afunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ } \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Alpha testing macro
+ *
+ *************************************/
+
+#define APPLY_ALPHATEST(VV, STATS, ALPHAMODE, AA) \
+do \
+{ \
+ if (ALPHAMODE_ALPHATEST(ALPHAMODE)) \
+ { \
+ UINT8 alpharef = (VV)->reg[alphaMode].rgb.a; \
+ switch (ALPHAMODE_ALPHAFUNCTION(ALPHAMODE)) \
+ { \
+ case 0: /* alphaOP = never */ \
+ (STATS)->afunc_fail++; \
+ goto skipdrawdepth; \
+ \
+ case 1: /* alphaOP = less than */ \
+ if ((AA) >= alpharef) \
+ { \
+ (STATS)->afunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 2: /* alphaOP = equal */ \
+ if ((AA) != alpharef) \
+ { \
+ (STATS)->afunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 3: /* alphaOP = less than or equal */ \
+ if ((AA) > alpharef) \
+ { \
+ (STATS)->afunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 4: /* alphaOP = greater than */ \
+ if ((AA) <= alpharef) \
+ { \
+ (STATS)->afunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 5: /* alphaOP = not equal */ \
+ if ((AA) == alpharef) \
+ { \
+ (STATS)->afunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 6: /* alphaOP = greater than or equal */ \
+ if ((AA) < alpharef) \
+ { \
+ (STATS)->afunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 7: /* alphaOP = always */ \
+ break; \
+ } \
+ } \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Alpha blending macro
+ *
+ *************************************/
+
+#define APPLY_ALPHA_BLEND(FBZMODE, ALPHAMODE, XX, DITHER, RR, GG, BB, AA) \
+do \
+{ \
+ if (ALPHAMODE_ALPHABLEND(ALPHAMODE)) \
+ { \
+ int dpix = dest[XX]; \
+ int dr = (dpix >> 8) & 0xf8; \
+ int dg = (dpix >> 3) & 0xfc; \
+ int db = (dpix << 3) & 0xf8; \
+ int da = FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) ? depth[XX] : 0xff; \
+ int sr = (RR); \
+ int sg = (GG); \
+ int sb = (BB); \
+ int sa = (AA); \
+ int ta; \
+ \
+ /* apply dither subtraction */ \
+ if (FBZMODE_ALPHA_DITHER_SUBTRACT(FBZMODE)) \
+ { \
+ /* look up the dither value from the appropriate matrix */ \
+ int dith = DITHER[(XX) & 3]; \
+ \
+ /* subtract the dither value */ \
+ dr = ((dr << 1) + 15 - dith) >> 1; \
+ dg = ((dg << 2) + 15 - dith) >> 2; \
+ db = ((db << 1) + 15 - dith) >> 1; \
+ } \
+ \
+ /* compute source portion */ \
+ switch (ALPHAMODE_SRCRGBBLEND(ALPHAMODE)) \
+ { \
+ default: /* reserved */ \
+ case 0: /* AZERO */ \
+ (RR) = (GG) = (BB) = 0; \
+ break; \
+ \
+ case 1: /* ASRC_ALPHA */ \
+ (RR) = (sr * (sa + 1)) >> 8; \
+ (GG) = (sg * (sa + 1)) >> 8; \
+ (BB) = (sb * (sa + 1)) >> 8; \
+ break; \
+ \
+ case 2: /* A_COLOR */ \
+ (RR) = (sr * (dr + 1)) >> 8; \
+ (GG) = (sg * (dg + 1)) >> 8; \
+ (BB) = (sb * (db + 1)) >> 8; \
+ break; \
+ \
+ case 3: /* ADST_ALPHA */ \
+ (RR) = (sr * (da + 1)) >> 8; \
+ (GG) = (sg * (da + 1)) >> 8; \
+ (BB) = (sb * (da + 1)) >> 8; \
+ break; \
+ \
+ case 4: /* AONE */ \
+ break; \
+ \
+ case 5: /* AOMSRC_ALPHA */ \
+ (RR) = (sr * (0x100 - sa)) >> 8; \
+ (GG) = (sg * (0x100 - sa)) >> 8; \
+ (BB) = (sb * (0x100 - sa)) >> 8; \
+ break; \
+ \
+ case 6: /* AOM_COLOR */ \
+ (RR) = (sr * (0x100 - dr)) >> 8; \
+ (GG) = (sg * (0x100 - dg)) >> 8; \
+ (BB) = (sb * (0x100 - db)) >> 8; \
+ break; \
+ \
+ case 7: /* AOMDST_ALPHA */ \
+ (RR) = (sr * (0x100 - da)) >> 8; \
+ (GG) = (sg * (0x100 - da)) >> 8; \
+ (BB) = (sb * (0x100 - da)) >> 8; \
+ break; \
+ \
+ case 15: /* ASATURATE */ \
+ ta = (sa < (0x100 - da)) ? sa : (0x100 - da); \
+ (RR) = (sr * (ta + 1)) >> 8; \
+ (GG) = (sg * (ta + 1)) >> 8; \
+ (BB) = (sb * (ta + 1)) >> 8; \
+ break; \
+ } \
+ \
+ /* add in dest portion */ \
+ switch (ALPHAMODE_DSTRGBBLEND(ALPHAMODE)) \
+ { \
+ default: /* reserved */ \
+ case 0: /* AZERO */ \
+ break; \
+ \
+ case 1: /* ASRC_ALPHA */ \
+ (RR) += (dr * (sa + 1)) >> 8; \
+ (GG) += (dg * (sa + 1)) >> 8; \
+ (BB) += (db * (sa + 1)) >> 8; \
+ break; \
+ \
+ case 2: /* A_COLOR */ \
+ (RR) += (dr * (sr + 1)) >> 8; \
+ (GG) += (dg * (sg + 1)) >> 8; \
+ (BB) += (db * (sb + 1)) >> 8; \
+ break; \
+ \
+ case 3: /* ADST_ALPHA */ \
+ (RR) += (dr * (da + 1)) >> 8; \
+ (GG) += (dg * (da + 1)) >> 8; \
+ (BB) += (db * (da + 1)) >> 8; \
+ break; \
+ \
+ case 4: /* AONE */ \
+ (RR) += dr; \
+ (GG) += dg; \
+ (BB) += db; \
+ break; \
+ \
+ case 5: /* AOMSRC_ALPHA */ \
+ (RR) += (dr * (0x100 - sa)) >> 8; \
+ (GG) += (dg * (0x100 - sa)) >> 8; \
+ (BB) += (db * (0x100 - sa)) >> 8; \
+ break; \
+ \
+ case 6: /* AOM_COLOR */ \
+ (RR) += (dr * (0x100 - sr)) >> 8; \
+ (GG) += (dg * (0x100 - sg)) >> 8; \
+ (BB) += (db * (0x100 - sb)) >> 8; \
+ break; \
+ \
+ case 7: /* AOMDST_ALPHA */ \
+ (RR) += (dr * (0x100 - da)) >> 8; \
+ (GG) += (dg * (0x100 - da)) >> 8; \
+ (BB) += (db * (0x100 - da)) >> 8; \
+ break; \
+ \
+ case 15: /* A_COLORBEFOREFOG */ \
+ (RR) += (dr * (prefogr + 1)) >> 8; \
+ (GG) += (dg * (prefogg + 1)) >> 8; \
+ (BB) += (db * (prefogb + 1)) >> 8; \
+ break; \
+ } \
+ \
+ /* blend the source alpha */ \
+ (AA) = 0; \
+ if (ALPHAMODE_SRCALPHABLEND(ALPHAMODE) == 4) \
+ (AA) = sa; \
+ \
+ /* blend the dest alpha */ \
+ if (ALPHAMODE_DSTALPHABLEND(ALPHAMODE) == 4) \
+ (AA) += da; \
+ \
+ /* clamp */ \
+ CLAMP((RR), 0x00, 0xff); \
+ CLAMP((GG), 0x00, 0xff); \
+ CLAMP((BB), 0x00, 0xff); \
+ CLAMP((AA), 0x00, 0xff); \
+ } \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Fogging macro
+ *
+ *************************************/
+
+#define APPLY_FOGGING(VV, FOGMODE, FBZCP, XX, DITHER4, RR, GG, BB, ITERZ, ITERW, ITERAXXX) \
+do \
+{ \
+ if (FOGMODE_ENABLE_FOG(FOGMODE)) \
+ { \
+ rgb_union fogcolor = (VV)->reg[fogColor]; \
+ INT32 fr, fg, fb; \
+ \
+ /* constant fog bypasses everything else */ \
+ if (FOGMODE_FOG_CONSTANT(FOGMODE)) \
+ { \
+ fr = fogcolor.rgb.r; \
+ fg = fogcolor.rgb.g; \
+ fb = fogcolor.rgb.b; \
+ } \
+ \
+ /* non-constant fog comes from several sources */ \
+ else \
+ { \
+ INT32 fogblend = 0; \
+ \
+ /* if fog_add is zero, we start with the fog color */ \
+ if (FOGMODE_FOG_ADD(FOGMODE) == 0) \
+ { \
+ fr = fogcolor.rgb.r; \
+ fg = fogcolor.rgb.g; \
+ fb = fogcolor.rgb.b; \
+ } \
+ else \
+ fr = fg = fb = 0; \
+ \
+ /* if fog_mult is zero, we subtract the incoming color */ \
+ if (FOGMODE_FOG_MULT(FOGMODE) == 0) \
+ { \
+ fr -= (RR); \
+ fg -= (GG); \
+ fb -= (BB); \
+ } \
+ \
+ /* fog blending mode */ \
+ switch (FOGMODE_FOG_ZALPHA(FOGMODE)) \
+ { \
+ case 0: /* fog table */ \
+ { \
+ INT32 delta = (VV)->fbi.fogdelta[wfloat >> 10]; \
+ INT32 deltaval; \
+ \
+ /* perform the multiply against lower 8 bits of wfloat */ \
+ deltaval = (delta & (VV)->fbi.fogdelta_mask) * \
+ ((wfloat >> 2) & 0xff); \
+ \
+ /* fog zones allow for negating this value */ \
+ if (FOGMODE_FOG_ZONES(FOGMODE) && (delta & 2)) \
+ deltaval = -deltaval; \
+ deltaval >>= 6; \
+ \
+ /* apply dither */ \
+ if (FOGMODE_FOG_DITHER(FOGMODE)) \
+ deltaval += DITHER4[(XX) & 3]; \
+ deltaval >>= 4; \
+ \
+ /* add to the blending factor */ \
+ fogblend = (VV)->fbi.fogblend[wfloat >> 10] + deltaval; \
+ break; \
+ } \
+ \
+ case 1: /* iterated A */ \
+ fogblend = ITERAXXX.rgb.a; \
+ break; \
+ \
+ case 2: /* iterated Z */ \
+ CLAMPED_Z((ITERZ), FBZCP, fogblend); \
+ fogblend >>= 8; \
+ break; \
+ \
+ case 3: /* iterated W - Voodoo 2 only */ \
+ CLAMPED_W((ITERW), FBZCP, fogblend); \
+ break; \
+ } \
+ \
+ /* perform the blend */ \
+ fogblend++; \
+ fr = (fr * fogblend) >> 8; \
+ fg = (fg * fogblend) >> 8; \
+ fb = (fb * fogblend) >> 8; \
+ } \
+ \
+ /* if fog_mult is 0, we add this to the original color */ \
+ if (FOGMODE_FOG_MULT(FOGMODE) == 0) \
+ { \
+ (RR) += fr; \
+ (GG) += fg; \
+ (BB) += fb; \
+ } \
+ \
+ /* otherwise this just becomes the new color */ \
+ else \
+ { \
+ (RR) = fr; \
+ (GG) = fg; \
+ (BB) = fb; \
+ } \
+ \
+ /* clamp */ \
+ CLAMP((RR), 0x00, 0xff); \
+ CLAMP((GG), 0x00, 0xff); \
+ CLAMP((BB), 0x00, 0xff); \
+ } \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Texture pipeline macro
+ *
+ *************************************/
+
+#define TEXTURE_PIPELINE(TT, XX, DITHER4, TEXMODE, COTHER, LOOKUP, LODBASE, ITERS, ITERT, ITERW, RESULT) \
+do \
+{ \
+ INT32 blendr, blendg, blendb, blenda; \
+ INT32 tr, tg, tb, ta; \
+ INT32 oow, s, t, lod, ilod; \
+ INT32 smax, tmax; \
+ UINT32 texbase; \
+ rgb_union c_local; \
+ \
+ /* determine the S/T/LOD values for this texture */ \
+ if (TEXMODE_ENABLE_PERSPECTIVE(TEXMODE)) \
+ { \
+ oow = fast_reciplog((ITERW), &lod); \
+ s = ((INT64)oow * (ITERS)) >> 29; \
+ t = ((INT64)oow * (ITERT)) >> 29; \
+ lod += (LODBASE); \
+ } \
+ else \
+ { \
+ s = (ITERS) >> 14; \
+ t = (ITERT) >> 14; \
+ lod = (LODBASE); \
+ } \
+ \
+ /* clamp W */ \
+ if (TEXMODE_CLAMP_NEG_W(TEXMODE) && (ITERW) < 0) \
+ s = t = 0; \
+ \
+ /* clamp the LOD */ \
+ lod += (TT)->lodbias; \
+ if (TEXMODE_ENABLE_LOD_DITHER(TEXMODE)) \
+ lod += DITHER4[(XX) & 3] << 4; \
+ if (lod < (TT)->lodmin) \
+ lod = (TT)->lodmin; \
+ if (lod > (TT)->lodmax) \
+ lod = (TT)->lodmax; \
+ \
+ /* now the LOD is in range; if we don't own this LOD, take the next one */ \
+ ilod = lod >> 8; \
+ if (!(((TT)->lodmask >> ilod) & 1)) \
+ ilod++; \
+ \
+ /* fetch the texture base */ \
+ texbase = (TT)->lodoffset[ilod]; \
+ \
+ /* compute the maximum s and t values at this LOD */ \
+ smax = (TT)->wmask >> ilod; \
+ tmax = (TT)->hmask >> ilod; \
+ \
+ /* determine whether we are point-sampled or bilinear */ \
+ if ((lod == (TT)->lodmin && !TEXMODE_MAGNIFICATION_FILTER(TEXMODE)) || \
+ (lod != (TT)->lodmin && !TEXMODE_MINIFICATION_FILTER(TEXMODE))) \
+ { \
+ /* point sampled */ \
+ \
+ UINT32 texel0; \
+ \
+ /* adjust S/T for the LOD and strip off the fractions */ \
+ s >>= ilod + 18; \
+ t >>= ilod + 18; \
+ \
+ /* clamp/wrap S/T if necessary */ \
+ if (TEXMODE_CLAMP_S(TEXMODE)) \
+ CLAMP(s, 0, smax); \
+ if (TEXMODE_CLAMP_T(TEXMODE)) \
+ CLAMP(t, 0, tmax); \
+ s &= smax; \
+ t &= tmax; \
+ t *= smax + 1; \
+ \
+ /* fetch texel data */ \
+ if (TEXMODE_FORMAT(TEXMODE) < 8) \
+ { \
+ texel0 = *(UINT8 *)&(TT)->ram[(texbase + t + s) & (TT)->mask]; \
+ c_local.u = (LOOKUP)[texel0]; \
+ } \
+ else \
+ { \
+ texel0 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t + s)) & (TT)->mask]; \
+ if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) \
+ c_local.u = (LOOKUP)[texel0]; \
+ else \
+ c_local.u = ((LOOKUP)[texel0 & 0xff] & 0xffffff) | \
+ ((texel0 & 0xff00) << 16); \
+ } \
+ } \
+ else \
+ { \
+ /* bilinear filtered */ \
+ \
+ UINT32 texel0, texel1, texel2, texel3; \
+ UINT32 sfrac, tfrac; \
+ INT32 s1, t1; \
+ \
+ /* adjust S/T for the LOD and strip off all but the low 8 bits of */ \
+ /* the fraction */ \
+ s >>= ilod + 10; \
+ t >>= ilod + 10; \
+ \
+ /* also subtract 1/2 texel so that (0.5,0.5) = a full (0,0) texel */ \
+ s -= 0x80; \
+ t -= 0x80; \
+ \
+ /* extract the fractions */ \
+ sfrac = s & (TT)->bilinear_mask; \
+ tfrac = t & (TT)->bilinear_mask; \
+ \
+ /* now toss the rest */ \
+ s >>= 8; \
+ t >>= 8; \
+ s1 = s + 1; \
+ t1 = t + 1; \
+ \
+ /* clamp/wrap S/T if necessary */ \
+ if (TEXMODE_CLAMP_S(TEXMODE)) \
+ { \
+ CLAMP(s, 0, smax); \
+ CLAMP(s1, 0, smax); \
+ } \
+ if (TEXMODE_CLAMP_T(TEXMODE)) \
+ { \
+ CLAMP(t, 0, tmax); \
+ CLAMP(t1, 0, tmax); \
+ } \
+ s &= smax; \
+ s1 &= smax; \
+ t &= tmax; \
+ t1 &= tmax; \
+ t *= smax + 1; \
+ t1 *= smax + 1; \
+ \
+ /* fetch texel data */ \
+ if (TEXMODE_FORMAT(TEXMODE) < 8) \
+ { \
+ texel0 = *(UINT8 *)&(TT)->ram[(texbase + t + s) & (TT)->mask]; \
+ texel1 = *(UINT8 *)&(TT)->ram[(texbase + t + s1) & (TT)->mask]; \
+ texel2 = *(UINT8 *)&(TT)->ram[(texbase + t1 + s) & (TT)->mask]; \
+ texel3 = *(UINT8 *)&(TT)->ram[(texbase + t1 + s1) & (TT)->mask]; \
+ texel0 = (LOOKUP)[texel0]; \
+ texel1 = (LOOKUP)[texel1]; \
+ texel2 = (LOOKUP)[texel2]; \
+ texel3 = (LOOKUP)[texel3]; \
+ } \
+ else \
+ { \
+ texel0 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t + s)) & (TT)->mask]; \
+ texel1 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t + s1)) & (TT)->mask];\
+ texel2 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t1 + s)) & (TT)->mask];\
+ texel3 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t1 + s1)) & (TT)->mask];\
+ if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) \
+ { \
+ texel0 = (LOOKUP)[texel0]; \
+ texel1 = (LOOKUP)[texel1]; \
+ texel2 = (LOOKUP)[texel2]; \
+ texel3 = (LOOKUP)[texel3]; \
+ } \
+ else \
+ { \
+ texel0 = ((LOOKUP)[texel0 & 0xff] & 0xffffff) | \
+ ((texel0 & 0xff00) << 16); \
+ texel1 = ((LOOKUP)[texel1 & 0xff] & 0xffffff) | \
+ ((texel1 & 0xff00) << 16); \
+ texel2 = ((LOOKUP)[texel2 & 0xff] & 0xffffff) | \
+ ((texel2 & 0xff00) << 16); \
+ texel3 = ((LOOKUP)[texel3 & 0xff] & 0xffffff) | \
+ ((texel3 & 0xff00) << 16); \
+ } \
+ } \
+ \
+ /* weigh in each texel */ \
+ c_local.u = rgba_bilinear_filter(texel0, texel1, texel2, texel3, sfrac, tfrac);\
+ } \
+ \
+ /* select zero/other for RGB */ \
+ if (!TEXMODE_TC_ZERO_OTHER(TEXMODE)) \
+ { \
+ tr = COTHER.rgb.r; \
+ tg = COTHER.rgb.g; \
+ tb = COTHER.rgb.b; \
+ } \
+ else \
+ tr = tg = tb = 0; \
+ \
+ /* select zero/other for alpha */ \
+ if (!TEXMODE_TCA_ZERO_OTHER(TEXMODE)) \
+ ta = COTHER.rgb.a; \
+ else \
+ ta = 0; \
+ \
+ /* potentially subtract c_local */ \
+ if (TEXMODE_TC_SUB_CLOCAL(TEXMODE)) \
+ { \
+ tr -= c_local.rgb.r; \
+ tg -= c_local.rgb.g; \
+ tb -= c_local.rgb.b; \
+ } \
+ if (TEXMODE_TCA_SUB_CLOCAL(TEXMODE)) \
+ ta -= c_local.rgb.a; \
+ \
+ /* blend RGB */ \
+ switch (TEXMODE_TC_MSELECT(TEXMODE)) \
+ { \
+ default: /* reserved */ \
+ case 0: /* zero */ \
+ blendr = blendg = blendb = 0; \
+ break; \
+ \
+ case 1: /* c_local */ \
+ blendr = c_local.rgb.r; \
+ blendg = c_local.rgb.g; \
+ blendb = c_local.rgb.b; \
+ break; \
+ \
+ case 2: /* a_other */ \
+ blendr = blendg = blendb = COTHER.rgb.a; \
+ break; \
+ \
+ case 3: /* a_local */ \
+ blendr = blendg = blendb = c_local.rgb.a; \
+ break; \
+ \
+ case 4: /* LOD (detail factor) */ \
+ if ((TT)->detailbias <= lod) \
+ blendr = blendg = blendb = 0; \
+ else \
+ { \
+ blendr = ((((TT)->detailbias - lod) << (TT)->detailscale) >> 8);\
+ if (blendr > (TT)->detailmax) \
+ blendr = (TT)->detailmax; \
+ blendg = blendb = blendr; \
+ } \
+ break; \
+ \
+ case 5: /* LOD fraction */ \
+ blendr = blendg = blendb = lod & 0xff; \
+ break; \
+ } \
+ \
+ /* blend alpha */ \
+ switch (TEXMODE_TCA_MSELECT(TEXMODE)) \
+ { \
+ default: /* reserved */ \
+ case 0: /* zero */ \
+ blenda = 0; \
+ break; \
+ \
+ case 1: /* c_local */ \
+ blenda = c_local.rgb.a; \
+ break; \
+ \
+ case 2: /* a_other */ \
+ blenda = COTHER.rgb.a; \
+ break; \
+ \
+ case 3: /* a_local */ \
+ blenda = c_local.rgb.a; \
+ break; \
+ \
+ case 4: /* LOD (detail factor) */ \
+ if ((TT)->detailbias <= lod) \
+ blenda = 0; \
+ else \
+ { \
+ blenda = ((((TT)->detailbias - lod) << (TT)->detailscale) >> 8);\
+ if (blenda > (TT)->detailmax) \
+ blenda = (TT)->detailmax; \
+ } \
+ break; \
+ \
+ case 5: /* LOD fraction */ \
+ blenda = lod & 0xff; \
+ break; \
+ } \
+ \
+ /* reverse the RGB blend */ \
+ if (!TEXMODE_TC_REVERSE_BLEND(TEXMODE)) \
+ { \
+ blendr ^= 0xff; \
+ blendg ^= 0xff; \
+ blendb ^= 0xff; \
+ } \
+ \
+ /* reverse the alpha blend */ \
+ if (!TEXMODE_TCA_REVERSE_BLEND(TEXMODE)) \
+ blenda ^= 0xff; \
+ \
+ /* do the blend */ \
+ tr = (tr * (blendr + 1)) >> 8; \
+ tg = (tg * (blendg + 1)) >> 8; \
+ tb = (tb * (blendb + 1)) >> 8; \
+ ta = (ta * (blenda + 1)) >> 8; \
+ \
+ /* add clocal or alocal to RGB */ \
+ switch (TEXMODE_TC_ADD_ACLOCAL(TEXMODE)) \
+ { \
+ case 3: /* reserved */ \
+ case 0: /* nothing */ \
+ break; \
+ \
+ case 1: /* add c_local */ \
+ tr += c_local.rgb.r; \
+ tg += c_local.rgb.g; \
+ tb += c_local.rgb.b; \
+ break; \
+ \
+ case 2: /* add_alocal */ \
+ tr += c_local.rgb.a; \
+ tg += c_local.rgb.a; \
+ tb += c_local.rgb.a; \
+ break; \
+ } \
+ \
+ /* add clocal or alocal to alpha */ \
+ if (TEXMODE_TCA_ADD_ACLOCAL(TEXMODE)) \
+ ta += c_local.rgb.a; \
+ \
+ /* clamp */ \
+ RESULT.rgb.r = (tr < 0) ? 0 : (tr > 0xff) ? 0xff : tr; \
+ RESULT.rgb.g = (tg < 0) ? 0 : (tg > 0xff) ? 0xff : tg; \
+ RESULT.rgb.b = (tb < 0) ? 0 : (tb > 0xff) ? 0xff : tb; \
+ RESULT.rgb.a = (ta < 0) ? 0 : (ta > 0xff) ? 0xff : ta; \
+ \
+ /* invert */ \
+ if (TEXMODE_TC_INVERT_OUTPUT(TEXMODE)) \
+ RESULT.u ^= 0x00ffffff; \
+ if (TEXMODE_TCA_INVERT_OUTPUT(TEXMODE)) \
+ RESULT.rgb.a ^= 0xff; \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Pixel pipeline macros
+ *
+ *************************************/
+
+#define PIXEL_PIPELINE_BEGIN(VV, STATS, XX, YY, FBZCOLORPATH, FBZMODE, ITERZ, ITERW) \
+do \
+{ \
+ INT32 depthval, wfloat; \
+ INT32 prefogr, prefogg, prefogb; \
+ INT32 r, g, b, a; \
+ \
+ (STATS)->pixels_in++; \
+ \
+ /* apply clipping */ \
+ /* note that for perf reasons, we assume the caller has done clipping */ \
+ \
+ /* handle stippling */ \
+ if (FBZMODE_ENABLE_STIPPLE(FBZMODE)) \
+ { \
+ /* rotate mode */ \
+ if (FBZMODE_STIPPLE_PATTERN(FBZMODE) == 0) \
+ { \
+ (VV)->reg[stipple].u = ((VV)->reg[stipple].u << 1) | ((VV)->reg[stipple].u >> 31);\
+ if (((VV)->reg[stipple].u & 0x80000000) == 0) \
+ { \
+ (VV)->stats.total_stippled++; \
+ goto skipdrawdepth; \
+ } \
+ } \
+ \
+ /* pattern mode */ \
+ else \
+ { \
+ int stipple_index = (((YY) & 3) << 3) | (~(XX) & 7); \
+ if ((((VV)->reg[stipple].u >> stipple_index) & 1) == 0) \
+ { \
+ (VV)->stats.total_stippled++; \
+ goto skipdrawdepth; \
+ } \
+ } \
+ } \
+ \
+ /* compute "floating point" W value (used for depth and fog) */ \
+ if ((ITERW) & U64(0xffff00000000)) \
+ wfloat = 0x0000; \
+ else \
+ { \
+ UINT32 temp = (UINT32)(ITERW); \
+ if ((temp & 0xffff0000) == 0) \
+ wfloat = 0xffff; \
+ else \
+ { \
+ int exp = count_leading_zeros(temp); \
+ wfloat = ((exp << 12) | ((~temp >> (19 - exp)) & 0xfff)) + 1; \
+ } \
+ } \
+ \
+ /* compute depth value (W or Z) for this pixel */ \
+ if (FBZMODE_WBUFFER_SELECT(FBZMODE) == 0) \
+ CLAMPED_Z(ITERZ, FBZCOLORPATH, depthval); \
+ else if (FBZMODE_DEPTH_FLOAT_SELECT(FBZMODE) == 0) \
+ depthval = wfloat; \
+ else \
+ { \
+ if ((ITERZ) & 0xf0000000) \
+ depthval = 0x0000; \
+ else \
+ { \
+ UINT32 temp = (ITERZ) << 4; \
+ if ((temp & 0xffff0000) == 0) \
+ depthval = 0xffff; \
+ else \
+ { \
+ int exp = count_leading_zeros(temp); \
+ depthval = ((exp << 12) | ((~temp >> (19 - exp)) & 0xfff)) + 1; \
+ } \
+ } \
+ } \
+ \
+ /* add the bias */ \
+ if (FBZMODE_ENABLE_DEPTH_BIAS(FBZMODE)) \
+ { \
+ depthval += (INT16)(VV)->reg[zaColor].u; \
+ CLAMP(depthval, 0, 0xffff); \
+ } \
+ \
+ /* handle depth buffer testing */ \
+ if (FBZMODE_ENABLE_DEPTHBUF(FBZMODE)) \
+ { \
+ INT32 depthsource; \
+ \
+ /* the source depth is either the iterated W/Z+bias or a */ \
+ /* constant value */ \
+ if (FBZMODE_DEPTH_SOURCE_COMPARE(FBZMODE) == 0) \
+ depthsource = depthval; \
+ else \
+ depthsource = (UINT16)(VV)->reg[zaColor].u; \
+ \
+ /* test against the depth buffer */ \
+ switch (FBZMODE_DEPTH_FUNCTION(FBZMODE)) \
+ { \
+ case 0: /* depthOP = never */ \
+ (STATS)->zfunc_fail++; \
+ goto skipdrawdepth; \
+ \
+ case 1: /* depthOP = less than */ \
+ if (depthsource >= depth[XX]) \
+ { \
+ (STATS)->zfunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 2: /* depthOP = equal */ \
+ if (depthsource != depth[XX]) \
+ { \
+ (STATS)->zfunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 3: /* depthOP = less than or equal */ \
+ if (depthsource > depth[XX]) \
+ { \
+ (STATS)->zfunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 4: /* depthOP = greater than */ \
+ if (depthsource <= depth[XX]) \
+ { \
+ (STATS)->zfunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 5: /* depthOP = not equal */ \
+ if (depthsource == depth[XX]) \
+ { \
+ (STATS)->zfunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 6: /* depthOP = greater than or equal */ \
+ if (depthsource < depth[XX]) \
+ { \
+ (STATS)->zfunc_fail++; \
+ goto skipdrawdepth; \
+ } \
+ break; \
+ \
+ case 7: /* depthOP = always */ \
+ break; \
+ } \
+ }
+
+
+#define PIXEL_PIPELINE_END(VV, STATS, DITHER, DITHER4, DITHER_LOOKUP, XX, dest, depth, FBZMODE, FBZCOLORPATH, ALPHAMODE, FOGMODE, ITERZ, ITERW, ITERAXXX) \
+ \
+ /* perform fogging */ \
+ prefogr = r; \
+ prefogg = g; \
+ prefogb = b; \
+ APPLY_FOGGING(VV, FOGMODE, FBZCOLORPATH, XX, DITHER4, r, g, b, \
+ ITERZ, ITERW, ITERAXXX); \
+ \
+ /* perform alpha blending */ \
+ APPLY_ALPHA_BLEND(FBZMODE, ALPHAMODE, XX, DITHER, r, g, b, a); \
+ \
+ /* modify the pixel for debugging purposes */ \
+ MODIFY_PIXEL(VV); \
+ \
+ /* write to framebuffer */ \
+ if (FBZMODE_RGB_BUFFER_MASK(FBZMODE)) \
+ { \
+ /* apply dithering */ \
+ APPLY_DITHER(FBZMODE, XX, DITHER_LOOKUP, r, g, b); \
+ dest[XX] = (r << 11) | (g << 5) | b; \
+ } \
+ \
+ /* write to aux buffer */ \
+ if (depth && FBZMODE_AUX_BUFFER_MASK(FBZMODE)) \
+ { \
+ if (FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) == 0) \
+ depth[XX] = depthval; \
+ else \
+ depth[XX] = a; \
+ } \
+ \
+ /* track pixel writes to the frame buffer regardless of mask */ \
+ (STATS)->pixels_out++; \
+ \
+skipdrawdepth: \
+ ; \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Colorpath pipeline macro
+ *
+ *************************************/
+
+/*
+
+ c_other_is_used:
+
+ if (FBZMODE_ENABLE_CHROMAKEY(FBZMODE) ||
+ FBZCP_CC_ZERO_OTHER(FBZCOLORPATH) == 0)
+
+ c_local_is_used:
+
+ if (FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH) ||
+ FBZCP_CC_MSELECT(FBZCOLORPATH) == 1 ||
+ FBZCP_CC_ADD_ACLOCAL(FBZCOLORPATH) == 1)
+
+ NEEDS_ITER_RGB:
+
+ if ((c_other_is_used && FBZCP_CC_RGBSELECT(FBZCOLORPATH) == 0) ||
+ (c_local_is_used && (FBZCP_CC_LOCALSELECT_OVERRIDE(FBZCOLORPATH) != 0 || FBZCP_CC_LOCALSELECT(FBZCOLORPATH) == 0))
+
+ NEEDS_ITER_A:
+
+ if ((a_other_is_used && FBZCP_CC_ASELECT(FBZCOLORPATH) == 0) ||
+ (a_local_is_used && FBZCP_CCA_LOCALSELECT(FBZCOLORPATH) == 0))
+
+ NEEDS_ITER_Z:
+
+ if (FBZMODE_WBUFFER_SELECT(FBZMODE) == 0 ||
+ FBZMODE_DEPTH_FLOAT_SELECT(FBZMODE) != 0 ||
+ FBZCP_CCA_LOCALSELECT(FBZCOLORPATH) == 2)
+
+
+*/
+
+/*
+ Expects the following declarations to be outside of this scope:
+
+ INT32 r, g, b, a;
+*/
+#define COLORPATH_PIPELINE(VV, STATS, FBZCOLORPATH, FBZMODE, ALPHAMODE, TEXELARGB, ITERZ, ITERW, ITERARGB) \
+do \
+{ \
+ INT32 blendr, blendg, blendb, blenda; \
+ rgb_union c_other; \
+ rgb_union c_local; \
+ \
+ /* compute c_other */ \
+ switch (FBZCP_CC_RGBSELECT(FBZCOLORPATH)) \
+ { \
+ case 0: /* iterated RGB */ \
+ c_other.u = ITERARGB.u; \
+ break; \
+ \
+ case 1: /* texture RGB */ \
+ c_other.u = TEXELARGB.u; \
+ break; \
+ \
+ case 2: /* color1 RGB */ \
+ c_other.u = (VV)->reg[color1].u; \
+ break; \
+ \
+ default: /* reserved */ \
+ c_other.u = 0; \
+ break; \
+ } \
+ \
+ /* handle chroma key */ \
+ APPLY_CHROMAKEY(VV, STATS, FBZMODE, c_other); \
+ \
+ /* compute a_other */ \
+ switch (FBZCP_CC_ASELECT(FBZCOLORPATH)) \
+ { \
+ case 0: /* iterated alpha */ \
+ c_other.rgb.a = ITERARGB.rgb.a; \
+ break; \
+ \
+ case 1: /* texture alpha */ \
+ c_other.rgb.a = TEXELARGB.rgb.a; \
+ break; \
+ \
+ case 2: /* color1 alpha */ \
+ c_other.rgb.a = (VV)->reg[color1].rgb.a; \
+ break; \
+ \
+ default: /* reserved */ \
+ c_other.rgb.a = 0; \
+ break; \
+ } \
+ \
+ /* handle alpha mask */ \
+ APPLY_ALPHAMASK(VV, STATS, FBZMODE, c_other.rgb.a); \
+ \
+ /* handle alpha test */ \
+ APPLY_ALPHATEST(VV, STATS, ALPHAMODE, c_other.rgb.a); \
+ \
+ /* compute c_local */ \
+ if (FBZCP_CC_LOCALSELECT_OVERRIDE(FBZCOLORPATH) == 0) \
+ { \
+ if (FBZCP_CC_LOCALSELECT(FBZCOLORPATH) == 0) /* iterated RGB */ \
+ c_local.u = ITERARGB.u; \
+ else /* color0 RGB */ \
+ c_local.u = (VV)->reg[color0].u; \
+ } \
+ else \
+ { \
+ if (!(TEXELARGB.rgb.a & 0x80)) /* iterated RGB */ \
+ c_local.u = ITERARGB.u; \
+ else /* color0 RGB */ \
+ c_local.u = (VV)->reg[color0].u; \
+ } \
+ \
+ /* compute a_local */ \
+ switch (FBZCP_CCA_LOCALSELECT(FBZCOLORPATH)) \
+ { \
+ default: \
+ case 0: /* iterated alpha */ \
+ c_local.rgb.a = ITERARGB.rgb.a; \
+ break; \
+ \
+ case 1: /* color0 alpha */ \
+ c_local.rgb.a = (VV)->reg[color0].rgb.a; \
+ break; \
+ \
+ case 2: /* clamped iterated Z[27:20] */ \
+ { \
+ int temp; \
+ CLAMPED_Z(ITERZ, FBZCOLORPATH, temp); \
+ c_local.rgb.a = (UINT8)temp; \
+ break; \
+ } \
+ \
+ case 3: /* clamped iterated W[39:32] */ \
+ { \
+ int temp; \
+ CLAMPED_W(ITERW, FBZCOLORPATH, temp); /* Voodoo 2 only */ \
+ c_local.rgb.a = (UINT8)temp; \
+ break; \
+ } \
+ } \
+ \
+ /* select zero or c_other */ \
+ if (FBZCP_CC_ZERO_OTHER(FBZCOLORPATH) == 0) \
+ { \
+ r = c_other.rgb.r; \
+ g = c_other.rgb.g; \
+ b = c_other.rgb.b; \
+ } \
+ else \
+ r = g = b = 0; \
+ \
+ /* select zero or a_other */ \
+ if (FBZCP_CCA_ZERO_OTHER(FBZCOLORPATH) == 0) \
+ a = c_other.rgb.a; \
+ else \
+ a = 0; \
+ \
+ /* subtract c_local */ \
+ if (FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH)) \
+ { \
+ r -= c_local.rgb.r; \
+ g -= c_local.rgb.g; \
+ b -= c_local.rgb.b; \
+ } \
+ \
+ /* subtract a_local */ \
+ if (FBZCP_CCA_SUB_CLOCAL(FBZCOLORPATH)) \
+ a -= c_local.rgb.a; \
+ \
+ /* blend RGB */ \
+ switch (FBZCP_CC_MSELECT(FBZCOLORPATH)) \
+ { \
+ default: /* reserved */ \
+ case 0: /* 0 */ \
+ blendr = blendg = blendb = 0; \
+ break; \
+ \
+ case 1: /* c_local */ \
+ blendr = c_local.rgb.r; \
+ blendg = c_local.rgb.g; \
+ blendb = c_local.rgb.b; \
+ break; \
+ \
+ case 2: /* a_other */ \
+ blendr = blendg = blendb = c_other.rgb.a; \
+ break; \
+ \
+ case 3: /* a_local */ \
+ blendr = blendg = blendb = c_local.rgb.a; \
+ break; \
+ \
+ case 4: /* texture alpha */ \
+ blendr = blendg = blendb = TEXELARGB.rgb.a; \
+ break; \
+ \
+ case 5: /* texture RGB (Voodoo 2 only) */ \
+ blendr = TEXELARGB.rgb.r; \
+ blendg = TEXELARGB.rgb.g; \
+ blendb = TEXELARGB.rgb.b; \
+ break; \
+ } \
+ \
+ /* blend alpha */ \
+ switch (FBZCP_CCA_MSELECT(FBZCOLORPATH)) \
+ { \
+ default: /* reserved */ \
+ case 0: /* 0 */ \
+ blenda = 0; \
+ break; \
+ \
+ case 1: /* a_local */ \
+ blenda = c_local.rgb.a; \
+ break; \
+ \
+ case 2: /* a_other */ \
+ blenda = c_other.rgb.a; \
+ break; \
+ \
+ case 3: /* a_local */ \
+ blenda = c_local.rgb.a; \
+ break; \
+ \
+ case 4: /* texture alpha */ \
+ blenda = TEXELARGB.rgb.a; \
+ break; \
+ } \
+ \
+ /* reverse the RGB blend */ \
+ if (!FBZCP_CC_REVERSE_BLEND(FBZCOLORPATH)) \
+ { \
+ blendr ^= 0xff; \
+ blendg ^= 0xff; \
+ blendb ^= 0xff; \
+ } \
+ \
+ /* reverse the alpha blend */ \
+ if (!FBZCP_CCA_REVERSE_BLEND(FBZCOLORPATH)) \
+ blenda ^= 0xff; \
+ \
+ /* do the blend */ \
+ r = (r * (blendr + 1)) >> 8; \
+ g = (g * (blendg + 1)) >> 8; \
+ b = (b * (blendb + 1)) >> 8; \
+ a = (a * (blenda + 1)) >> 8; \
+ \
+ /* add clocal or alocal to RGB */ \
+ switch (FBZCP_CC_ADD_ACLOCAL(FBZCOLORPATH)) \
+ { \
+ case 3: /* reserved */ \
+ case 0: /* nothing */ \
+ break; \
+ \
+ case 1: /* add c_local */ \
+ r += c_local.rgb.r; \
+ g += c_local.rgb.g; \
+ b += c_local.rgb.b; \
+ break; \
+ \
+ case 2: /* add_alocal */ \
+ r += c_local.rgb.a; \
+ g += c_local.rgb.a; \
+ b += c_local.rgb.a; \
+ break; \
+ } \
+ \
+ /* add clocal or alocal to alpha */ \
+ if (FBZCP_CCA_ADD_ACLOCAL(FBZCOLORPATH)) \
+ a += c_local.rgb.a; \
+ \
+ /* clamp */ \
+ CLAMP(r, 0x00, 0xff); \
+ CLAMP(g, 0x00, 0xff); \
+ CLAMP(b, 0x00, 0xff); \
+ CLAMP(a, 0x00, 0xff); \
+ \
+ /* invert */ \
+ if (FBZCP_CC_INVERT_OUTPUT(FBZCOLORPATH)) \
+ { \
+ r ^= 0xff; \
+ g ^= 0xff; \
+ b ^= 0xff; \
+ } \
+ if (FBZCP_CCA_INVERT_OUTPUT(FBZCOLORPATH)) \
+ a ^= 0xff; \
+} \
+while (0)
+
+
+
+/*************************************
+ *
+ * Rasterizer generator macro
+ *
+ *************************************/
+
+#define RASTERIZER(name, TMUS, FBZCOLORPATH, FBZMODE, ALPHAMODE, FOGMODE, TEXMODE0, TEXMODE1) \
+ \
+static void raster_##name(void *destbase, INT32 y, const poly_extent *extent, const void *extradata, int threadid) \
+{ \
+ const poly_extra_data *extra = extradata; \
+ voodoo_state *v = extra->state; \
+ stats_block *stats = &v->thread_stats[threadid]; \
+ DECLARE_DITHER_POINTERS; \
+ INT32 startx = extent->startx; \
+ INT32 stopx = extent->stopx; \
+ INT32 iterr, iterg, iterb, itera; \
+ INT32 iterz; \
+ INT64 iterw, iterw0 = 0, iterw1 = 0; \
+ INT64 iters0 = 0, iters1 = 0; \
+ INT64 itert0 = 0, itert1 = 0; \
+ UINT16 *depth; \
+ UINT16 *dest; \
+ INT32 dx, dy; \
+ INT32 scry; \
+ INT32 x; \
+ \
+ /* determine the screen Y */ \
+ scry = y; \
+ if (FBZMODE_Y_ORIGIN(FBZMODE)) \
+ scry = (v->fbi.yorigin - y) & 0x3ff; \
+ \
+ /* compute dithering */ \
+ COMPUTE_DITHER_POINTERS(FBZMODE, y); \
+ \
+ /* apply clipping */ \
+ if (FBZMODE_ENABLE_CLIPPING(FBZMODE)) \
+ { \
+ INT32 tempclip; \
+ \
+ /* Y clipping buys us the whole scanline */ \
+ if (scry < ((v->reg[clipLowYHighY].u >> 16) & 0x3ff) || \
+ scry >= (v->reg[clipLowYHighY].u & 0x3ff)) \
+ { \
+ stats->pixels_in += stopx - startx; \
+ stats->clip_fail += stopx - startx; \
+ return; \
+ } \
+ \
+ /* X clipping */ \
+ tempclip = (v->reg[clipLeftRight].u >> 16) & 0x3ff; \
+ if (startx < tempclip) \
+ { \
+ stats->pixels_in += tempclip - startx; \
+ v->stats.total_clipped += tempclip - startx; \
+ startx = tempclip; \
+ } \
+ tempclip = v->reg[clipLeftRight].u & 0x3ff; \
+ if (stopx >= tempclip) \
+ { \
+ stats->pixels_in += stopx - tempclip; \
+ v->stats.total_clipped += stopx - tempclip; \
+ stopx = tempclip - 1; \
+ } \
+ } \
+ \
+ /* get pointers to the target buffer and depth buffer */ \
+ dest = (UINT16 *)destbase + scry * v->fbi.rowpixels; \
+ depth = v->fbi.aux ? (v->fbi.aux + scry * v->fbi.rowpixels) : NULL; \
+ \
+ /* compute the starting parameters */ \
+ dx = startx - (extra->ax >> 4); \
+ dy = y - (extra->ay >> 4); \
+ iterr = extra->startr + dy * extra->drdy + dx * extra->drdx; \
+ iterg = extra->startg + dy * extra->dgdy + dx * extra->dgdx; \
+ iterb = extra->startb + dy * extra->dbdy + dx * extra->dbdx; \
+ itera = extra->starta + dy * extra->dady + dx * extra->dadx; \
+ iterz = extra->startz + dy * extra->dzdy + dx * extra->dzdx; \
+ iterw = extra->startw + dy * extra->dwdy + dx * extra->dwdx; \
+ if (TMUS >= 1) \
+ { \
+ iterw0 = extra->startw0 + dy * extra->dw0dy + dx * extra->dw0dx; \
+ iters0 = extra->starts0 + dy * extra->ds0dy + dx * extra->ds0dx; \
+ itert0 = extra->startt0 + dy * extra->dt0dy + dx * extra->dt0dx; \
+ } \
+ if (TMUS >= 2) \
+ { \
+ iterw1 = extra->startw1 + dy * extra->dw1dy + dx * extra->dw1dx; \
+ iters1 = extra->starts1 + dy * extra->ds1dy + dx * extra->ds1dx; \
+ itert1 = extra->startt1 + dy * extra->dt1dy + dx * extra->dt1dx; \
+ } \
+ \
+ /* loop in X */ \
+ for (x = startx; x < stopx; x++) \
+ { \
+ rgb_union iterargb = { 0 }; \
+ rgb_union texel = { 0 }; \
+ \
+ /* pixel pipeline part 1 handles depth testing and stippling */ \
+ PIXEL_PIPELINE_BEGIN(v, stats, x, y, FBZCOLORPATH, FBZMODE, \
+ iterz, iterw); \
+ \
+ /* run the texture pipeline on TMU1 to produce a value in texel */ \
+ /* note that they set LOD min to 8 to "disable" a TMU */ \
+ if (TMUS >= 2 && v->tmu[1].lodmin < (8 << 8)) \
+ TEXTURE_PIPELINE(&v->tmu[1], x, dither4, TEXMODE1, texel, \
+ v->tmu[1].lookup, extra->lodbase1, \
+ iters1, itert1, iterw1, texel); \
+ \
+ /* run the texture pipeline on TMU0 to produce a final */ \
+ /* result in texel */ \
+ /* note that they set LOD min to 8 to "disable" a TMU */ \
+ if (TMUS >= 1 && v->tmu[0].lodmin < (8 << 8)) \
+ TEXTURE_PIPELINE(&v->tmu[0], x, dither4, TEXMODE0, texel, \
+ v->tmu[0].lookup, extra->lodbase0, \
+ iters0, itert0, iterw0, texel); \
+ \
+ /* colorpath pipeline selects source colors and does blending */ \
+ CLAMPED_ARGB(iterr, iterg, iterb, itera, FBZCOLORPATH, iterargb); \
+ COLORPATH_PIPELINE(v, stats, FBZCOLORPATH, FBZMODE, ALPHAMODE, texel, \
+ iterz, iterw, iterargb); \
+ \
+ /* pixel pipeline part 2 handles fog, alpha, and final output */ \
+ PIXEL_PIPELINE_END(v, stats, dither, dither4, dither_lookup, x, dest, depth, \
+ FBZMODE, FBZCOLORPATH, ALPHAMODE, FOGMODE, \
+ iterz, iterw, iterargb); \
+ \
+ /* update the iterated parameters */ \
+ iterr += extra->drdx; \
+ iterg += extra->dgdx; \
+ iterb += extra->dbdx; \
+ itera += extra->dadx; \
+ iterz += extra->dzdx; \
+ iterw += extra->dwdx; \
+ if (TMUS >= 1) \
+ { \
+ iterw0 += extra->dw0dx; \
+ iters0 += extra->ds0dx; \
+ itert0 += extra->dt0dx; \
+ } \
+ if (TMUS >= 2) \
+ { \
+ iterw1 += extra->dw1dx; \
+ iters1 += extra->ds1dx; \
+ itert1 += extra->dt1dx; \
+ } \
+ } \
+}
diff --git a/src/emu/video/voodoo.c b/src/emu/video/voodoo.c
new file mode 100644
index 00000000000..4ff1e60257e
--- /dev/null
+++ b/src/emu/video/voodoo.c
@@ -0,0 +1,5742 @@
+//fix me -- blitz2k dies when starting a game with heavy fog (in DRC)
+
+/*************************************************************************
+
+ 3dfx Voodoo Graphics SST-1/2 emulator
+
+ emulator by Aaron Giles
+
+ --------------------------
+
+ Specs:
+
+ Voodoo 1 (SST1):
+ 2,4MB frame buffer RAM
+ 1,2,4MB texture RAM
+ 50MHz clock frequency
+ clears @ 2 pixels/clock (RGB and depth simultaneously)
+ renders @ 1 pixel/clock
+ 64 entry PCI FIFO
+ memory FIFO up to 65536 entries
+
+ Voodoo 2:
+ 2,4MB frame buffer RAM
+ 2,4,8,16MB texture RAM
+ 90MHz clock frquency
+ clears @ 2 pixels/clock (RGB and depth simultaneously)
+ renders @ 1 pixel/clock
+ ultrafast clears @ 16 pixels/clock
+ 128 entry PCI FIFO
+ memory FIFO up to 65536 entries
+
+ Voodoo Banshee (h3):
+ Integrated VGA support
+ 2,4,8MB frame buffer RAM
+ 90MHz clock frquency
+ clears @ 2 pixels/clock (RGB and depth simultaneously)
+ renders @ 1 pixel/clock
+ ultrafast clears @ 32 pixels/clock
+
+ Voodoo 3 ("Avenger"/h4):
+ Integrated VGA support
+ 4,8,16MB frame buffer RAM
+ 143MHz clock frquency
+ clears @ 2 pixels/clock (RGB and depth simultaneously)
+ renders @ 1 pixel/clock
+ ultrafast clears @ 32 pixels/clock
+
+ --------------------------
+
+ still to be implemented:
+ * trilinear textures
+
+ things to verify:
+ * floating Z buffer
+
+
+iterated RGBA = 12.12 [24 bits]
+iterated Z = 20.12 [32 bits]
+iterated W = 18.32 [48 bits]
+
+>mamepm blitz
+Stall PCI for HWM: 1
+PCI FIFO Empty Entries LWM: D
+LFB -> FIFO: 1
+Texture -> FIFO: 1
+Memory FIFO: 1
+Memory FIFO HWM: 2000
+Memory FIFO Write Burst HWM: 36
+Memory FIFO LWM for PCI: 5
+Memory FIFO row start: 120
+Memory FIFO row rollover: 3FF
+Video dither subtract: 0
+DRAM banking: 1
+Triple buffer: 0
+Video buffer offset: 60
+DRAM banking: 1
+
+>mamepm wg3dh
+Stall PCI for HWM: 1
+PCI FIFO Empty Entries LWM: D
+LFB -> FIFO: 1
+Texture -> FIFO: 1
+Memory FIFO: 1
+Memory FIFO HWM: 2000
+Memory FIFO Write Burst HWM: 36
+Memory FIFO LWM for PCI: 5
+Memory FIFO row start: C0
+Memory FIFO row rollover: 3FF
+Video dither subtract: 0
+DRAM banking: 1
+Triple buffer: 0
+Video buffer offset: 40
+DRAM banking: 1
+
+
+As a point of reference, the 3D engine uses the following algorithm to calculate the linear memory address as a
+function of the video buffer offset (fbiInit2 bits(19:11)), the number of 32x32 tiles in the X dimension (fbiInit1
+bits(7:4) and bit(24)), X, and Y:
+
+ tilesInX[4:0] = {fbiInit1[24], fbiInit1[7:4], fbiInit6[30]}
+ rowBase = fbiInit2[19:11]
+ rowStart = ((Y>>5) * tilesInX) >> 1
+
+ if (!(tilesInX & 1))
+ {
+ rowOffset = (X>>6);
+ row[9:0] = rowStart + rowOffset (for color buffer 0)
+ row[9:0] = rowBase + rowStart + rowOffset (for color buffer 1)
+ row[9:0] = (rowBase<<1) + rowStart + rowOffset (for depth/alpha buffer when double color buffering[fbiInit5[10:9]=0])
+ row[9:0] = (rowBase<<1) + rowStart + rowOffset (for color buffer 2 when triple color buffering[fbiInit5[10:9]=1 or 2])
+ row[9:0] = (rowBase<<1) + rowBase + rowStart + rowOffset (for depth/alpha buffer when triple color buffering[fbiInit5[10:9]=2])
+ column[8:0] = ((Y % 32) <<4) + ((X % 32)>>1)
+ ramSelect[1] = ((X&0x20) ? 1 : 0) (for color buffers)
+ ramSelect[1] = ((X&0x20) ? 0 : 1) (for depth/alpha buffers)
+ }
+ else
+ {
+ rowOffset = (!(Y&0x20)) ? (X>>6) : ((X>31) ? (((X-32)>>6)+1) : 0)
+ row[9:0] = rowStart + rowOffset (for color buffer 0)
+ row[9:0] = rowBase + rowStart + rowOffset (for color buffer 1)
+ row[9:0] = (rowBase<<1) + rowStart + rowOffset (for depth/alpha buffer when double color buffering[fbiInit5[10:9]=0])
+ row[9:0] = (rowBase<<1) + rowStart + rowOffset (for color buffer 2 when triple color buffering[fbiInit5[10:9]=1 or 2])
+ row[9:0] = (rowBase<<1) + rowBase + rowStart + rowOffset (for depth/alpha buffer when triple color buffering[fbiInit5[10:9]=2])
+ column[8:0] = ((Y % 32) <<4) + ((X % 32)>>1)
+ ramSelect[1] = (((X&0x20)^(Y&0x20)) ? 1 : 0) (for color buffers)
+ ramSelect[1] = (((X&0x20)^(Y&0x20)) ? 0 : 1) (for depth/alpha buffers)
+ }
+ ramSelect[0] = X % 2
+ pixelMemoryAddress[21:0] = (row[9:0]<<12) + (column[8:0]<<3) + (ramSelect[1:0]<<1)
+ bankSelect = pixelMemoryAddress[21]
+
+**************************************************************************/
+
+#ifndef EXPAND_RASTERIZERS
+#define EXPAND_RASTERIZERS
+
+#include "driver.h"
+#include "eminline.h"
+#include "profiler.h"
+#include "video/poly.h"
+#include "video/rgbutil.h"
+#include "voodoo.h"
+#include "vooddefs.h"
+#include "ui.h"
+#include <math.h>
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define DEBUG_DEPTH (0)
+#define DEBUG_LOD (0)
+
+#define LOG_VBLANK_SWAP (0)
+#define LOG_FIFO (0)
+#define LOG_FIFO_VERBOSE (0)
+#define LOG_REGISTERS (0)
+#define LOG_WAITS (0)
+#define LOG_LFB (0)
+#define LOG_TEXTURE_RAM (0)
+#define LOG_RASTERIZERS (0)
+#define LOG_CMDFIFO (0)
+#define LOG_CMDFIFO_VERBOSE (0)
+
+#define MODIFY_PIXEL(VV)
+
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static voodoo_state *voodoo[MAX_VOODOO];
+
+/* fast dither lookup */
+static UINT8 dither4_lookup[256*16*2];
+static UINT8 dither2_lookup[256*16*2];
+
+/* fast reciprocal+log2 lookup */
+UINT32 reciplog[(2 << RECIPLOG_LOOKUP_BITS) + 2];
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static void init_fbi(voodoo_state *v, fbi_state *f, void *memory, int fbmem);
+static void init_tmu_shared(tmu_shared_state *s);
+static void init_tmu(voodoo_state *v, tmu_state *t, int type, voodoo_reg *reg, void *memory, int tmem);
+static void soft_reset(voodoo_state *v);
+static void check_stalled_cpu(voodoo_state *v, attotime current_time);
+static void flush_fifos(voodoo_state *v, attotime current_time);
+static TIMER_CALLBACK_PTR( stall_cpu_callback );
+static void stall_cpu(voodoo_state *v, int state, attotime current_time);
+static TIMER_CALLBACK_PTR( vblank_callback );
+static INT32 register_w(voodoo_state *v, offs_t offset, UINT32 data);
+static INT32 lfb_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask, int forcefront);
+static INT32 texture_w(voodoo_state *v, offs_t offset, UINT32 data);
+static void voodoo_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask);
+static UINT32 voodoo_r(voodoo_state *v, offs_t offset);
+static void banshee_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask);
+static UINT32 banshee_r(voodoo_state *v, offs_t offset, UINT32 mem_mask);
+static void banshee_fb_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask);
+static UINT32 banshee_fb_r(voodoo_state *v, offs_t offset, UINT32 mem_mask);
+static void banshee_io_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask);
+static UINT32 banshee_io_r(voodoo_state *v, offs_t offset, UINT32 mem_mask);
+static UINT32 banshee_rom_r(voodoo_state *v, offs_t offset, UINT32 mem_mask);
+
+/* command handlers */
+static INT32 fastfill(voodoo_state *v);
+static INT32 swapbuffer(voodoo_state *v, UINT32 data);
+static INT32 triangle(voodoo_state *v);
+static INT32 begin_triangle(voodoo_state *v);
+static INT32 draw_triangle(voodoo_state *v);
+
+/* triangle helpers */
+static INT32 setup_and_draw_triangle(voodoo_state *v);
+static INT32 triangle_create_work_item(voodoo_state *v, UINT16 *drawbuf, int texcount);
+
+/* rasterizer management */
+static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo);
+static raster_info *find_rasterizer(voodoo_state *v, int texcount);
+static void dump_rasterizer_stats(voodoo_state *v);
+
+/* generic rasterizers */
+static void raster_fastfill(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
+static void raster_generic_0tmu(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
+static void raster_generic_1tmu(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
+static void raster_generic_2tmu(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
+
+
+
+/*************************************
+ *
+ * Specific rasterizers
+ *
+ *************************************/
+
+#define RASTERIZER_ENTRY(fbzcp, alpha, fog, fbz, tex0, tex1) \
+ RASTERIZER(fbzcp##_##alpha##_##fog##_##fbz##_##tex0##_##tex1, (((tex0) == 0xffffffff) ? 0 : ((tex1) == 0xffffffff) ? 1 : 2), fbzcp, fbz, alpha, fog, tex0, tex1)
+
+#include "voodoo.c"
+
+#undef RASTERIZER_ENTRY
+
+
+
+/*************************************
+ *
+ * Rasterizer table
+ *
+ *************************************/
+
+#define RASTERIZER_ENTRY(fbzcp, alpha, fog, fbz, tex0, tex1) \
+ { NULL, raster_##fbzcp##_##alpha##_##fog##_##fbz##_##tex0##_##tex1, FALSE, 0, 0, 0, fbzcp, alpha, fog, fbz, tex0, tex1 },
+
+static const raster_info predef_raster_table[] =
+{
+#include "voodoo.c"
+ { 0 }
+};
+
+#undef RASTERIZER_ENTRY
+
+
+
+/*************************************
+ *
+ * Main create routine
+ *
+ *************************************/
+
+void voodoo_start(int which, int scrnum, int type, int fbmem_in_mb, int tmem0_in_mb, int tmem1_in_mb)
+{
+ const raster_info *info;
+ void *fbmem, *tmumem[2];
+ voodoo_state *v;
+ int val;
+
+ /* allocate memory */
+ v = auto_malloc(sizeof(*v));
+ memset(v, 0, sizeof(*v));
+ voodoo[which] = v;
+
+ /* create a multiprocessor work queue */
+ v->poly = poly_alloc(64, sizeof(poly_extra_data), 0);
+ v->thread_stats = auto_malloc(sizeof(v->thread_stats[0]) * WORK_MAX_THREADS);
+
+ /* create a table of precomputed 1/n and log2(n) values */
+ /* n ranges from 1.0000 to 2.0000 */
+ for (val = 0; val <= (1 << RECIPLOG_LOOKUP_BITS); val++)
+ {
+ UINT32 value = (1 << RECIPLOG_LOOKUP_BITS) + val;
+ reciplog[val*2 + 0] = (1 << (RECIPLOG_LOOKUP_PREC + RECIPLOG_LOOKUP_BITS)) / value;
+ reciplog[val*2 + 1] = (UINT32)(LOGB2((double)value / (double)(1 << RECIPLOG_LOOKUP_BITS)) * (double)(1 << RECIPLOG_LOOKUP_PREC));
+ }
+
+ /* create dithering tables */
+ for (val = 0; val < 256*16*2; val++)
+ {
+ int g = (val >> 0) & 1;
+ int x = (val >> 1) & 3;
+ int color = (val >> 3) & 0xff;
+ int y = (val >> 11) & 3;
+
+ if (!g)
+ {
+ dither4_lookup[val] = DITHER_RB(color, dither_matrix_4x4[y * 4 + x]) >> 3;
+ dither2_lookup[val] = DITHER_RB(color, dither_matrix_2x2[y * 4 + x]) >> 3;
+ }
+ else
+ {
+ dither4_lookup[val] = DITHER_G(color, dither_matrix_4x4[y * 4 + x]) >> 2;
+ dither2_lookup[val] = DITHER_G(color, dither_matrix_2x2[y * 4 + x]) >> 2;
+ }
+ }
+
+ /* configure type-specific values */
+ switch (type)
+ {
+ case VOODOO_1:
+ v->freq = 50000000;
+ v->regaccess = voodoo_register_access;
+ v->regnames = voodoo_reg_name;
+ v->alt_regmap = 0;
+ v->fbi.lfb_stride = 10;
+ break;
+
+ case VOODOO_2:
+ v->freq = 90000000;
+ v->regaccess = voodoo2_register_access;
+ v->regnames = voodoo_reg_name;
+ v->alt_regmap = 0;
+ v->fbi.lfb_stride = 10;
+ break;
+
+ case VOODOO_BANSHEE:
+ v->freq = 90000000;
+ v->regaccess = banshee_register_access;
+ v->regnames = banshee_reg_name;
+ v->alt_regmap = 1;
+ v->fbi.lfb_stride = 11;
+ break;
+
+ case VOODOO_3:
+ v->freq = 132000000;
+ v->regaccess = banshee_register_access;
+ v->regnames = banshee_reg_name;
+ v->alt_regmap = 1;
+ v->fbi.lfb_stride = 11;
+ break;
+
+ default:
+ fatalerror("Unsupported voodoo card in voodoo_start!");
+ break;
+ }
+
+ /* set the type, and initialize the chip mask */
+ v->index = which;
+ v->type = type;
+ v->chipmask = 0x01;
+ v->attoseconds_per_cycle = ATTOSECONDS_PER_SECOND / v->freq;
+ v->trigger = 51324 + which;
+
+ /* build the rasterizer table */
+ for (info = predef_raster_table; info->callback; info++)
+ add_rasterizer(v, info);
+
+ /* set up the PCI FIFO */
+ v->pci.fifo.base = v->pci.fifo_mem;
+ v->pci.fifo.size = 64*2;
+ v->pci.fifo.in = v->pci.fifo.out = 0;
+ v->pci.stall_state = NOT_STALLED;
+ v->pci.continue_timer = timer_alloc_ptr(stall_cpu_callback, v);
+
+ /* allocate memory */
+ if (type <= VOODOO_2)
+ {
+ /* separate FB/TMU memory */
+ fbmem = auto_malloc(fbmem_in_mb << 20);
+ tmumem[0] = auto_malloc(tmem0_in_mb << 20);
+ tmumem[1] = tmem1_in_mb ? auto_malloc(tmem1_in_mb << 20) : NULL;
+ }
+ else
+ {
+ /* shared memory */
+ tmumem[0] = tmumem[1] = fbmem = auto_malloc(fbmem_in_mb << 20);
+ }
+
+ /* set up frame buffer */
+ init_fbi(v, &v->fbi, fbmem, fbmem_in_mb << 20);
+
+ /* build shared TMU tables */
+ init_tmu_shared(&v->tmushare);
+
+ /* set up the TMUs */
+ init_tmu(v, &v->tmu[0], type, &v->reg[0x100], tmumem[0], tmem0_in_mb << 20);
+ v->chipmask |= 0x02;
+ if (tmem1_in_mb)
+ {
+ init_tmu(v, &v->tmu[1], type, &v->reg[0x200], tmumem[1], tmem1_in_mb << 20);
+ v->chipmask |= 0x04;
+ }
+
+ /* initialize some registers */
+ memset(v->reg, 0, sizeof(v->reg));
+ v->pci.init_enable = 0;
+ v->reg[fbiInit0].u = (1 << 4) | (0x10 << 6);
+ v->reg[fbiInit1].u = (1 << 1) | (1 << 8) | (1 << 12) | (2 << 20);
+ v->reg[fbiInit2].u = (1 << 6) | (0x100 << 23);
+ v->reg[fbiInit3].u = (2 << 13) | (0xf << 17);
+ v->reg[fbiInit4].u = (1 << 0);
+
+ /* initialize banshee registers */
+ memset(v->banshee.io, 0, sizeof(v->banshee.io));
+ v->banshee.io[io_pciInit0] = 0x01800040;
+ v->banshee.io[io_sipMonitor] = 0x40000000;
+ v->banshee.io[io_lfbMemoryConfig] = 0x000a2200;
+ v->banshee.io[io_dramInit0] = 0x00579d29;
+ v->banshee.io[io_dramInit1] = 0x00f02200;
+ v->banshee.io[io_tmuGbeInit] = 0x00000bfb;
+
+ /* do a soft reset to reset everything else */
+ soft_reset(v);
+}
+
+
+
+/*************************************
+ *
+ * Video exit
+ *
+ *************************************/
+
+void voodoo_exit(int which)
+{
+ /* release the work queue, ensuring all work is finished */
+ if (voodoo[which] != NULL && voodoo[which]->poly != NULL)
+ poly_free(voodoo[which]->poly);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+int voodoo_update(int which, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ voodoo_state *v = voodoo[which];
+ int changed = v->fbi.video_changed;
+ int drawbuf = v->fbi.frontbuf;
+ int statskey;
+ int x, y;
+
+ /* reset the video changed flag */
+ v->fbi.video_changed = FALSE;
+
+ /* if we are blank, just fill with black */
+ if (v->type <= VOODOO_2 && FBIINIT1_SOFTWARE_BLANK(v->reg[fbiInit1].u))
+ {
+ fillbitmap(bitmap, 0, cliprect);
+ return changed;
+ }
+
+ /* if the CLUT is dirty, recompute the pens array */
+ if (v->fbi.clut_dirty)
+ {
+ UINT8 rtable[32], gtable[64], btable[32];
+
+ /* Voodoo/Voodoo-2 have an internal 33-entry CLUT */
+ if (v->type <= VOODOO_2)
+ {
+ /* kludge: some of the Midway games write 0 to the last entry when they obviously mean FF */
+ if ((v->fbi.clut[32] & 0xffffff) == 0 && (v->fbi.clut[31] & 0xffffff) != 0)
+ v->fbi.clut[32] = 0x20ffffff;
+
+ /* compute the R/G/B pens first */
+ for (x = 0; x < 32; x++)
+ {
+ /* treat X as a 5-bit value, scale up to 8 bits, and linear interpolate for red/blue */
+ y = (x << 3) | (x >> 2);
+ rtable[x] = (RGB_RED(v->fbi.clut[y >> 3]) * (8 - (y & 7)) + RGB_RED(v->fbi.clut[(y >> 3) + 1]) * (y & 7)) >> 3;
+ btable[x] = (RGB_BLUE(v->fbi.clut[y >> 3]) * (8 - (y & 7)) + RGB_BLUE(v->fbi.clut[(y >> 3) + 1]) * (y & 7)) >> 3;
+
+ /* treat X as a 6-bit value with LSB=0, scale up to 8 bits, and linear interpolate */
+ y = (x * 2) + 0;
+ y = (y << 2) | (y >> 4);
+ gtable[x*2+0] = (RGB_GREEN(v->fbi.clut[y >> 3]) * (8 - (y & 7)) + RGB_GREEN(v->fbi.clut[(y >> 3) + 1]) * (y & 7)) >> 3;
+
+ /* treat X as a 6-bit value with LSB=1, scale up to 8 bits, and linear interpolate */
+ y = (x * 2) + 1;
+ y = (y << 2) | (y >> 4);
+ gtable[x*2+1] = (RGB_GREEN(v->fbi.clut[y >> 3]) * (8 - (y & 7)) + RGB_GREEN(v->fbi.clut[(y >> 3) + 1]) * (y & 7)) >> 3;
+ }
+ }
+
+ /* Banshee and later have a 512-entry CLUT that can be bypassed */
+ else
+ {
+ int which = (v->banshee.io[io_vidProcCfg] >> 13) & 1;
+ int bypass = (v->banshee.io[io_vidProcCfg] >> 11) & 1;
+
+ /* compute R/G/B pens first */
+ for (x = 0; x < 32; x++)
+ {
+ /* treat X as a 5-bit value, scale up to 8 bits */
+ y = (x << 3) | (x >> 2);
+ rtable[x] = bypass ? y : RGB_RED(v->fbi.clut[which * 256 + y]);
+ btable[x] = bypass ? y : RGB_BLUE(v->fbi.clut[which * 256 + y]);
+
+ /* treat X as a 6-bit value with LSB=0, scale up to 8 bits */
+ y = (x * 2) + 0;
+ y = (y << 2) | (y >> 4);
+ gtable[x*2+0] = bypass ? y : RGB_GREEN(v->fbi.clut[which * 256 + y]);
+
+ /* treat X as a 6-bit value with LSB=1, scale up to 8 bits, and linear interpolate */
+ y = (x * 2) + 1;
+ y = (y << 2) | (y >> 4);
+ gtable[x*2+1] = bypass ? y : RGB_GREEN(v->fbi.clut[which * 256 + y]);
+ }
+ }
+
+ /* now compute the actual pens array */
+ for (x = 0; x < 65536; x++)
+ {
+ int r = rtable[(x >> 11) & 0x1f];
+ int g = gtable[(x >> 5) & 0x3f];
+ int b = btable[x & 0x1f];
+ v->fbi.pen[x] = MAKE_RGB(r, g, b);
+ }
+
+ /* no longer dirty */
+ v->fbi.clut_dirty = FALSE;
+ changed = TRUE;
+ }
+
+ /* debugging! */
+ if (input_code_pressed(KEYCODE_L))
+ drawbuf = v->fbi.backbuf;
+
+ /* copy from the current front buffer */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *src = v->fbi.rgb[drawbuf] + (y - v->fbi.yoffs) * v->fbi.rowpixels - v->fbi.xoffs;
+ UINT32 *dst = BITMAP_ADDR32(bitmap, y, 0);
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ dst[x] = v->fbi.pen[src[x]];
+ }
+
+ /* update stats display */
+ statskey = (input_code_pressed(KEYCODE_BACKSLASH) != 0);
+ if (statskey && statskey != v->stats.lastkey)
+ v->stats.display = !v->stats.display;
+ v->stats.lastkey = statskey;
+
+ /* display stats */
+ if (v->stats.display)
+ popmessage(v->stats.buffer, 0, 0);
+
+ /* update render override */
+ v->stats.render_override = input_code_pressed(KEYCODE_ENTER);
+ if (DEBUG_DEPTH && v->stats.render_override)
+ {
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *src = v->fbi.aux + (y - v->fbi.yoffs) * v->fbi.rowpixels - v->fbi.xoffs;
+ UINT32 *dst = BITMAP_ADDR32(bitmap, y, 0);
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ dst[x] = ((src[x] << 8) & 0xff0000) | ((src[x] >> 0) & 0xff00) | ((src[x] >> 8) & 0xff);
+ }
+ }
+ return changed;
+}
+
+
+
+/*************************************
+ *
+ * Chip reset
+ *
+ *************************************/
+
+void voodoo_reset(int which)
+{
+ soft_reset(voodoo[which]);
+}
+
+
+int voodoo_get_type(int which)
+{
+ return voodoo[which]->type;
+}
+
+
+int voodoo_is_stalled(int which)
+{
+ return (voodoo[which]->pci.stall_state != NOT_STALLED);
+}
+
+
+void voodoo_set_init_enable(int which, UINT32 newval)
+{
+ voodoo[which]->pci.init_enable = newval;
+ if (LOG_REGISTERS)
+ logerror("VOODOO.%d.REG:initEnable write = %08X\n", which, newval);
+}
+
+
+void voodoo_set_vblank_callback(int which, void (*vblank)(int))
+{
+ voodoo[which]->fbi.vblank_client = vblank;
+}
+
+
+void voodoo_set_stall_callback(int which, void (*stall)(int))
+{
+ voodoo[which]->pci.stall_callback = stall;
+}
+
+
+
+/*************************************
+ *
+ * Specific write handlers
+ *
+ *************************************/
+
+WRITE32_HANDLER( voodoo_0_w )
+{
+ voodoo_w(voodoo[0], offset, data, mem_mask);
+}
+
+
+WRITE32_HANDLER( voodoo_1_w )
+{
+ voodoo_w(voodoo[1], offset, data, mem_mask);
+}
+
+
+
+/*************************************
+ *
+ * Specific read handlers
+ *
+ *************************************/
+
+READ32_HANDLER( voodoo_0_r )
+{
+ return voodoo_r(voodoo[0], offset);
+}
+
+
+READ32_HANDLER( voodoo_1_r )
+{
+ return voodoo_r(voodoo[1], offset);
+}
+
+
+
+/*************************************
+ *
+ * Specific Banshee write handlers
+ *
+ *************************************/
+
+WRITE32_HANDLER( banshee_0_w )
+{
+ banshee_w(voodoo[0], offset, data, mem_mask);
+}
+
+
+WRITE32_HANDLER( banshee_fb_0_w )
+{
+ banshee_fb_w(voodoo[0], offset, data, mem_mask);
+}
+
+
+WRITE32_HANDLER( banshee_io_0_w )
+{
+ banshee_io_w(voodoo[0], offset, data, mem_mask);
+}
+
+
+WRITE32_HANDLER( banshee_1_w )
+{
+ banshee_w(voodoo[1], offset, data, mem_mask);
+}
+
+
+WRITE32_HANDLER( banshee_fb_1_w )
+{
+ banshee_fb_w(voodoo[1], offset, data, mem_mask);
+}
+
+
+WRITE32_HANDLER( banshee_io_1_w )
+{
+ banshee_io_w(voodoo[1], offset, data, mem_mask);
+}
+
+
+
+
+/*************************************
+ *
+ * Specific Banshee read handlers
+ *
+ *************************************/
+
+READ32_HANDLER( banshee_0_r )
+{
+ return banshee_r(voodoo[0], offset, mem_mask);
+}
+
+
+READ32_HANDLER( banshee_fb_0_r )
+{
+ return banshee_fb_r(voodoo[0], offset, mem_mask);
+}
+
+
+READ32_HANDLER( banshee_io_0_r )
+{
+ return banshee_io_r(voodoo[0], offset, mem_mask);
+}
+
+
+READ32_HANDLER( banshee_rom_0_r )
+{
+ return banshee_rom_r(voodoo[0], offset, mem_mask);
+}
+
+
+READ32_HANDLER( banshee_1_r )
+{
+ return banshee_r(voodoo[1], offset, mem_mask);
+}
+
+
+READ32_HANDLER( banshee_fb_1_r )
+{
+ return banshee_fb_r(voodoo[1], offset, mem_mask);
+}
+
+
+READ32_HANDLER( banshee_io_1_r )
+{
+ return banshee_io_r(voodoo[1], offset, mem_mask);
+}
+
+
+READ32_HANDLER( banshee_rom_1_r )
+{
+ return banshee_rom_r(voodoo[1], offset, mem_mask);
+}
+
+
+
+/*************************************
+ *
+ * Common initialization
+ *
+ *************************************/
+
+static void init_fbi(voodoo_state *v, fbi_state *f, void *memory, int fbmem)
+{
+ int pen;
+
+ /* allocate frame buffer RAM and set pointers */
+ f->ram = memory;
+ f->mask = fbmem - 1;
+ f->rgb[0] = f->rgb[1] = f->rgb[2] = f->ram;
+ f->aux = f->ram;
+
+ /* default to 0x0 */
+ f->frontbuf = 0;
+ f->backbuf = 1;
+ f->width = 512;
+ f->height = 384;
+
+ /* init the pens */
+ for (pen = 0; pen < 65536; pen++)
+ {
+ int r = (pen >> 11) & 0x1f;
+ int g = (pen >> 5) & 0x3f;
+ int b = pen & 0x1f;
+ r = (r << 3) | (r >> 2);
+ g = (g << 2) | (g >> 4);
+ b = (b << 3) | (b >> 2);
+ f->pen[pen] = MAKE_RGB(r, g, b);
+ }
+
+ /* allocate a VBLANK timer */
+ f->vblank_timer = timer_alloc_ptr(vblank_callback, v);
+ f->vblank = FALSE;
+
+ /* initialize the memory FIFO */
+ f->fifo.base = f->ram;
+ f->fifo.size = f->fifo.in = f->fifo.out = 0;
+
+ /* set the fog delta mask */
+ f->fogdelta_mask = (v->type < VOODOO_2) ? 0xff : 0xfc;
+}
+
+
+static void init_tmu_shared(tmu_shared_state *s)
+{
+ int val;
+
+ /* build static 8-bit texel tables */
+ for (val = 0; val < 256; val++)
+ {
+ int r, g, b, a;
+
+ /* 8-bit RGB (3-3-2) */
+ EXTRACT_332_TO_888(val, r, g, b);
+ s->rgb332[val] = MAKE_ARGB(0xff, r, g, b);
+
+ /* 8-bit alpha */
+ s->alpha8[val] = MAKE_ARGB(val, val, val, val);
+
+ /* 8-bit intensity */
+ s->int8[val] = MAKE_ARGB(0xff, val, val, val);
+
+ /* 8-bit alpha, intensity */
+ a = ((val >> 0) & 0xf0) | ((val >> 4) & 0x0f);
+ r = ((val << 4) & 0xf0) | ((val << 0) & 0x0f);
+ s->ai44[val] = MAKE_ARGB(a, r, r, r);
+ }
+
+ /* build static 16-bit texel tables */
+ for (val = 0; val < 65536; val++)
+ {
+ int r, g, b, a;
+
+ /* table 10 = 16-bit RGB (5-6-5) */
+ EXTRACT_565_TO_888(val, r, g, b);
+ s->rgb565[val] = MAKE_ARGB(0xff, r, g, b);
+
+ /* table 11 = 16 ARGB (1-5-5-5) */
+ EXTRACT_1555_TO_8888(val, a, r, g, b);
+ s->argb1555[val] = MAKE_ARGB(a, r, g, b);
+
+ /* table 12 = 16-bit ARGB (4-4-4-4) */
+ EXTRACT_4444_TO_8888(val, a, r, g, b);
+ s->argb4444[val] = MAKE_ARGB(a, r, g, b);
+ }
+}
+
+
+static void init_tmu(voodoo_state *v, tmu_state *t, int type, voodoo_reg *reg, void *memory, int tmem)
+{
+ /* allocate texture RAM */
+ t->ram = memory;
+ t->mask = tmem - 1;
+ t->reg = reg;
+ t->regdirty = TRUE;
+ t->bilinear_mask = (type >= VOODOO_2) ? 0xff : 0xf0;
+
+ /* mark the NCC tables dirty and configure their registers */
+ t->ncc[0].dirty = t->ncc[1].dirty = TRUE;
+ t->ncc[0].reg = &t->reg[nccTable+0];
+ t->ncc[1].reg = &t->reg[nccTable+12];
+
+ /* create pointers to all the tables */
+ t->texel[0] = v->tmushare.rgb332;
+ t->texel[1] = t->ncc[0].texel;
+ t->texel[2] = v->tmushare.alpha8;
+ t->texel[3] = v->tmushare.int8;
+ t->texel[4] = v->tmushare.ai44;
+ t->texel[5] = t->palette;
+ t->texel[6] = (type >= VOODOO_2) ? t->palettea : NULL;
+ t->texel[7] = NULL;
+ t->texel[8] = v->tmushare.rgb332;
+ t->texel[9] = t->ncc[0].texel;
+ t->texel[10] = v->tmushare.rgb565;
+ t->texel[11] = v->tmushare.argb1555;
+ t->texel[12] = v->tmushare.argb4444;
+ t->texel[13] = v->tmushare.int8;
+ t->texel[14] = t->palette;
+ t->texel[15] = NULL;
+ t->lookup = t->texel[0];
+
+ /* attach the palette to NCC table 0 */
+ t->ncc[0].palette = t->palette;
+ if (type >= VOODOO_2)
+ t->ncc[0].palettea = t->palettea;
+
+ /* set up texture address calculations */
+ if (type <= VOODOO_2)
+ {
+ t->texaddr_mask = 0x0fffff;
+ t->texaddr_shift = 3;
+ }
+ else
+ {
+ t->texaddr_mask = 0xfffff0;
+ t->texaddr_shift = 0;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Statistics management
+ *
+ *************************************/
+
+static void accumulate_statistics(voodoo_state *v, const stats_block *stats)
+{
+ /* apply internal voodoo statistics */
+ v->reg[fbiPixelsIn].u += stats->pixels_in;
+ v->reg[fbiPixelsOut].u += stats->pixels_out;
+ v->reg[fbiChromaFail].u += stats->chroma_fail;
+ v->reg[fbiZfuncFail].u += stats->zfunc_fail;
+ v->reg[fbiAfuncFail].u += stats->afunc_fail;
+
+ /* apply emulation statistics */
+ v->stats.total_pixels_in += stats->pixels_in;
+ v->stats.total_pixels_out += stats->pixels_out;
+ v->stats.total_chroma_fail += stats->chroma_fail;
+ v->stats.total_zfunc_fail += stats->zfunc_fail;
+ v->stats.total_afunc_fail += stats->afunc_fail;
+ v->stats.total_clipped += stats->clip_fail;
+ v->stats.total_stippled += stats->stipple_count;
+}
+
+
+static void update_statistics(voodoo_state *v, int accumulate)
+{
+ int threadnum;
+
+ /* accumulate/reset statistics from all units */
+ for (threadnum = 0; threadnum < WORK_MAX_THREADS; threadnum++)
+ {
+ if (accumulate)
+ accumulate_statistics(v, &v->thread_stats[threadnum]);
+ memset(&v->thread_stats[threadnum], 0, sizeof(v->thread_stats[threadnum]));
+ }
+
+ /* accumulate/reset statistics from the LFB */
+ if (accumulate)
+ accumulate_statistics(v, &v->fbi.lfb_stats);
+ memset(&v->fbi.lfb_stats, 0, sizeof(v->fbi.lfb_stats));
+}
+
+
+
+/*************************************
+ *
+ * VBLANK management
+ *
+ *************************************/
+
+static void swap_buffers(voodoo_state *v)
+{
+ int count;
+
+ if (LOG_VBLANK_SWAP) logerror("--- swap_buffers @ %d\n", video_screen_get_vpos(v->scrnum));
+
+ /* force a partial update */
+ video_screen_update_partial(v->scrnum, video_screen_get_vpos(v->scrnum));
+ v->fbi.video_changed = TRUE;
+
+ /* keep a history of swap intervals */
+ count = v->fbi.vblank_count;
+ if (count > 15)
+ count = 15;
+ v->reg[fbiSwapHistory].u = (v->reg[fbiSwapHistory].u << 4) | count;
+
+ /* rotate the buffers */
+ if (v->type <= VOODOO_2)
+ {
+ if (v->type < VOODOO_2 || !v->fbi.vblank_dont_swap)
+ {
+ if (v->fbi.rgb[2] == NULL)
+ {
+ v->fbi.frontbuf = 1 - v->fbi.frontbuf;
+ v->fbi.backbuf = 1 - v->fbi.frontbuf;
+ }
+ else
+ {
+ v->fbi.frontbuf = (v->fbi.frontbuf + 1) % 3;
+ v->fbi.backbuf = (v->fbi.frontbuf + 1) % 3;
+ }
+ }
+ }
+ else
+ {
+ v->fbi.rgb[0] = (UINT16 *)((UINT8 *)v->fbi.ram + (v->reg[leftOverlayBuf].u & v->fbi.mask & ~0x0f));
+ v->fbi.rgbmax[0] = (UINT16 *)((UINT8 *)v->fbi.ram + v->fbi.mask + 1) - v->fbi.rgb[0];
+ }
+
+ /* decrement the pending count and reset our state */
+ if (v->fbi.swaps_pending)
+ v->fbi.swaps_pending--;
+ v->fbi.vblank_count = 0;
+ v->fbi.vblank_swap_pending = FALSE;
+
+ /* reset the last_op_time to now and start processing the next command */
+ if (v->pci.op_pending)
+ {
+ v->pci.op_end_time = timer_get_time();
+ flush_fifos(v, v->pci.op_end_time);
+ }
+
+ /* we may be able to unstall now */
+ if (v->pci.stall_state != NOT_STALLED)
+ check_stalled_cpu(v, timer_get_time());
+
+ /* periodically log rasterizer info */
+ v->stats.swaps++;
+ if (LOG_RASTERIZERS && v->stats.swaps % 100 == 0)
+ dump_rasterizer_stats(v);
+
+ /* update the statistics (debug) */
+ if (v->stats.display)
+ {
+ int screen_area = (Machine->screen[v->scrnum].visarea.max_x - Machine->screen[v->scrnum].visarea.min_x + 1) * (Machine->screen[v->scrnum].visarea.max_y - Machine->screen[v->scrnum].visarea.min_y + 1);
+ char *statsptr = v->stats.buffer;
+ int pixelcount;
+ int i;
+
+ update_statistics(v, TRUE);
+ pixelcount = v->stats.total_pixels_out;
+
+ statsptr += sprintf(statsptr, "Swap:%6d\n", v->stats.swaps);
+ statsptr += sprintf(statsptr, "Hist:%08X\n", v->reg[fbiSwapHistory].u);
+ statsptr += sprintf(statsptr, "Stal:%6d\n", v->stats.stalls);
+ statsptr += sprintf(statsptr, "Rend:%6d%%\n", pixelcount * 100 / screen_area);
+ statsptr += sprintf(statsptr, "Poly:%6d\n", v->stats.total_triangles);
+ statsptr += sprintf(statsptr, "PxIn:%6d\n", v->stats.total_pixels_in);
+ statsptr += sprintf(statsptr, "POut:%6d\n", v->stats.total_pixels_out);
+ statsptr += sprintf(statsptr, "Clip:%6d\n", v->stats.total_clipped);
+ statsptr += sprintf(statsptr, "Stip:%6d\n", v->stats.total_stippled);
+ statsptr += sprintf(statsptr, "Chro:%6d\n", v->stats.total_chroma_fail);
+ statsptr += sprintf(statsptr, "ZFun:%6d\n", v->stats.total_zfunc_fail);
+ statsptr += sprintf(statsptr, "AFun:%6d\n", v->stats.total_afunc_fail);
+ statsptr += sprintf(statsptr, "RegW:%6d\n", v->stats.reg_writes);
+ statsptr += sprintf(statsptr, "RegR:%6d\n", v->stats.reg_reads);
+ statsptr += sprintf(statsptr, "LFBW:%6d\n", v->stats.lfb_writes);
+ statsptr += sprintf(statsptr, "LFBR:%6d\n", v->stats.lfb_reads);
+ statsptr += sprintf(statsptr, "TexW:%6d\n", v->stats.tex_writes);
+ statsptr += sprintf(statsptr, "TexM:");
+ for (i = 0; i < 16; i++)
+ if (v->stats.texture_mode[i])
+ *statsptr++ = "0123456789ABCDEF"[i];
+ *statsptr = 0;
+ }
+
+ /* update statistics */
+ v->stats.stalls = 0;
+ v->stats.total_triangles = 0;
+ v->stats.total_pixels_in = 0;
+ v->stats.total_pixels_out = 0;
+ v->stats.total_chroma_fail = 0;
+ v->stats.total_zfunc_fail = 0;
+ v->stats.total_afunc_fail = 0;
+ v->stats.total_clipped = 0;
+ v->stats.total_stippled = 0;
+ v->stats.reg_writes = 0;
+ v->stats.reg_reads = 0;
+ v->stats.lfb_writes = 0;
+ v->stats.lfb_reads = 0;
+ v->stats.tex_writes = 0;
+ memset(v->stats.texture_mode, 0, sizeof(v->stats.texture_mode));
+}
+
+
+static void adjust_vblank_timer(voodoo_state *v)
+{
+ attotime vblank_period = video_screen_get_time_until_pos(v->scrnum, v->fbi.vsyncscan, 0);
+
+ /* if zero, adjust to next frame, otherwise we may get stuck in an infinite loop */
+ if (attotime_compare(vblank_period, attotime_zero) == 0)
+ vblank_period = video_screen_get_frame_period(v->scrnum);
+ timer_adjust_ptr(v->fbi.vblank_timer, vblank_period, attotime_never);
+}
+
+
+static TIMER_CALLBACK_PTR( vblank_off_callback )
+{
+ voodoo_state *v = param;
+
+ if (LOG_VBLANK_SWAP) logerror("--- vblank end\n");
+
+ /* set internal state and call the client */
+ v->fbi.vblank = FALSE;
+ if (v->fbi.vblank_client)
+ (*v->fbi.vblank_client)(FALSE);
+
+ /* go to the end of the next frame */
+ adjust_vblank_timer(v);
+}
+
+
+static TIMER_CALLBACK_PTR( vblank_callback )
+{
+ voodoo_state *v = param;
+
+ if (LOG_VBLANK_SWAP) logerror("--- vblank start\n");
+
+ /* flush the pipes */
+ if (v->pci.op_pending)
+ {
+ if (LOG_VBLANK_SWAP) logerror("---- vblank flush begin\n");
+ flush_fifos(v, timer_get_time());
+ if (LOG_VBLANK_SWAP) logerror("---- vblank flush end\n");
+ }
+
+ /* increment the count */
+ v->fbi.vblank_count++;
+ if (v->fbi.vblank_count > 250)
+ v->fbi.vblank_count = 250;
+ if (LOG_VBLANK_SWAP) logerror("---- vblank count = %d", v->fbi.vblank_count);
+ if (v->fbi.vblank_swap_pending)
+ if (LOG_VBLANK_SWAP) logerror(" (target=%d)", v->fbi.vblank_swap);
+ if (LOG_VBLANK_SWAP) logerror("\n");
+
+ /* if we're past the swap count, do the swap */
+ if (v->fbi.vblank_swap_pending && v->fbi.vblank_count >= v->fbi.vblank_swap)
+ swap_buffers(v);
+
+ /* set a timer for the next off state */
+ timer_set_ptr(video_screen_get_time_until_pos(v->scrnum, 0, 0), v, vblank_off_callback);
+
+ /* set internal state and call the client */
+ v->fbi.vblank = TRUE;
+ if (v->fbi.vblank_client)
+ (*v->fbi.vblank_client)(TRUE);
+}
+
+
+
+/*************************************
+ *
+ * Chip reset
+ *
+ *************************************/
+
+static void reset_counters(voodoo_state *v)
+{
+ update_statistics(v, FALSE);
+ v->reg[fbiPixelsIn].u = 0;
+ v->reg[fbiChromaFail].u = 0;
+ v->reg[fbiZfuncFail].u = 0;
+ v->reg[fbiAfuncFail].u = 0;
+ v->reg[fbiPixelsOut].u = 0;
+}
+
+
+static void soft_reset(voodoo_state *v)
+{
+ reset_counters(v);
+ v->reg[fbiTrianglesOut].u = 0;
+ fifo_reset(&v->fbi.fifo);
+ fifo_reset(&v->pci.fifo);
+}
+
+
+
+/*************************************
+ *
+ * Recompute video memory layout
+ *
+ *************************************/
+
+static void recompute_video_memory(voodoo_state *v)
+{
+ UINT32 buffer_pages = FBIINIT2_VIDEO_BUFFER_OFFSET(v->reg[fbiInit2].u);
+ UINT32 fifo_start_page = FBIINIT4_MEMORY_FIFO_START_ROW(v->reg[fbiInit4].u);
+ UINT32 fifo_last_page = FBIINIT4_MEMORY_FIFO_STOP_ROW(v->reg[fbiInit4].u);
+ UINT32 memory_config;
+ int buf;
+
+ /* memory config is determined differently between V1 and V2 */
+ memory_config = FBIINIT2_ENABLE_TRIPLE_BUF(v->reg[fbiInit2].u);
+ if (v->type == VOODOO_2 && memory_config == 0)
+ memory_config = FBIINIT5_BUFFER_ALLOCATION(v->reg[fbiInit5].u);
+
+ /* tiles are 64x16/32; x_tiles specifies how many half-tiles */
+ v->fbi.tile_width = (v->type == VOODOO_1) ? 64 : 32;
+ v->fbi.tile_height = (v->type == VOODOO_1) ? 16 : 32;
+ v->fbi.x_tiles = FBIINIT1_X_VIDEO_TILES(v->reg[fbiInit1].u);
+ if (v->type == VOODOO_2)
+ {
+ v->fbi.x_tiles = (v->fbi.x_tiles << 1) |
+ (FBIINIT1_X_VIDEO_TILES_BIT5(v->reg[fbiInit1].u) << 5) |
+ (FBIINIT6_X_VIDEO_TILES_BIT0(v->reg[fbiInit6].u));
+ }
+ v->fbi.rowpixels = v->fbi.tile_width * v->fbi.x_tiles;
+
+// logerror("VOODOO.%d.VIDMEM: buffer_pages=%X fifo=%X-%X tiles=%X rowpix=%d\n", v->index, buffer_pages, fifo_start_page, fifo_last_page, v->fbi.x_tiles, v->fbi.rowpixels);
+
+ /* first RGB buffer always starts at 0 */
+ v->fbi.rgb[0] = v->fbi.ram;
+
+ /* second RGB buffer starts immediately afterwards */
+ v->fbi.rgb[1] = (UINT16 *)((UINT8 *)v->fbi.ram + buffer_pages * 0x1000);
+
+ /* remaining buffers are based on the config */
+ switch (memory_config)
+ {
+ case 3: /* reserved */
+ logerror("VOODOO.%d.ERROR:Unexpected memory configuration in recompute_video_memory!\n", v->index);
+
+ case 0: /* 2 color buffers, 1 aux buffer */
+ v->fbi.rgb[2] = NULL;
+ v->fbi.aux = (UINT16 *)((UINT8 *)v->fbi.ram + 2 * buffer_pages * 0x1000);
+ break;
+
+ case 1: /* 3 color buffers, 0 aux buffers */
+ v->fbi.rgb[2] = (UINT16 *)((UINT8 *)v->fbi.ram + 2 * buffer_pages * 0x1000);
+ v->fbi.aux = NULL;
+ break;
+
+ case 2: /* 3 color buffers, 1 aux buffers */
+ v->fbi.rgb[2] = (UINT16 *)((UINT8 *)v->fbi.ram + 2 * buffer_pages * 0x1000);
+ v->fbi.aux = (UINT16 *)((UINT8 *)v->fbi.ram + 3 * buffer_pages * 0x1000);
+ break;
+ }
+
+ /* clamp the RGB buffers to video memory */
+ for (buf = 0; buf < 3; buf++)
+ {
+ v->fbi.rgbmax[buf] = 0;
+ if (v->fbi.rgb[buf])
+ {
+ if ((UINT8 *)v->fbi.rgb[buf] > (UINT8 *)v->fbi.ram + v->fbi.mask)
+ v->fbi.rgb[buf] = (UINT16 *)((UINT8 *)v->fbi.ram + v->fbi.mask);
+ v->fbi.rgbmax[buf] = (UINT16 *)((UINT8 *)v->fbi.ram + v->fbi.mask + 1) - v->fbi.rgb[buf];
+ }
+ }
+
+ /* clamp the aux buffer to video memory */
+ v->fbi.auxmax = 0;
+ if (v->fbi.aux)
+ {
+ if ((UINT8 *)v->fbi.aux > (UINT8 *)v->fbi.ram + v->fbi.mask)
+ v->fbi.aux = (UINT16 *)((UINT8 *)v->fbi.ram + v->fbi.mask);
+ v->fbi.auxmax = (UINT16 *)((UINT8 *)v->fbi.ram + v->fbi.mask + 1) - v->fbi.aux;
+ }
+
+/* mame_printf_debug("rgb[0] = %08X rgb[1] = %08X rgb[2] = %08X aux = %08X\n",
+ (UINT8 *)v->fbi.rgb[0] - (UINT8 *)v->fbi.ram,
+ (UINT8 *)v->fbi.rgb[1] - (UINT8 *)v->fbi.ram,
+ v->fbi.rgb[2] ? ((UINT8 *)v->fbi.rgb[2] - (UINT8 *)v->fbi.ram) : 0,
+ (UINT8 *)v->fbi.aux - (UINT8 *)v->fbi.ram);*/
+// logerror("VOODOO.%d.VIDMEM: rgbmax=%X,%X,%X auxmax=%X\n", v->index, v->fbi.rgbmax[0], v->fbi.rgbmax[1], v->fbi.rgbmax[2], v->fbi.auxmax);
+
+ /* compute the memory FIFO location and size */
+ if (fifo_last_page > v->fbi.mask / 0x1000)
+ fifo_last_page = v->fbi.mask / 0x1000;
+
+ /* is it valid and enabled? */
+ if (fifo_start_page <= fifo_last_page && FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u))
+ {
+ v->fbi.fifo.base = (UINT32 *)((UINT8 *)v->fbi.ram + fifo_start_page * 0x1000);
+ v->fbi.fifo.size = (fifo_last_page + 1 - fifo_start_page) * 0x1000 / 4;
+ if (v->fbi.fifo.size > 65536*2)
+ v->fbi.fifo.size = 65536*2;
+ }
+
+ /* if not, disable the FIFO */
+ else
+ {
+ v->fbi.fifo.base = NULL;
+ v->fbi.fifo.size = 0;
+ }
+
+ /* reset the FIFO */
+ fifo_reset(&v->fbi.fifo);
+
+ /* reset our front/back buffers if they are out of range */
+ if (!v->fbi.rgb[2])
+ {
+ if (v->fbi.frontbuf == 2)
+ v->fbi.frontbuf = 0;
+ if (v->fbi.backbuf == 2)
+ v->fbi.backbuf = 0;
+ }
+}
+
+
+
+/*************************************
+ *
+ * NCC table management
+ *
+ *************************************/
+
+static void ncc_table_write(ncc_table *n, offs_t regnum, UINT32 data)
+{
+ /* I/Q entries reference the plaette if the high bit is set */
+ if (regnum >= 4 && (data & 0x80000000) && n->palette)
+ {
+ int index = ((data >> 23) & 0xfe) | (regnum & 1);
+
+ /* set the ARGB for this palette index */
+ n->palette[index] = 0xff000000 | data;
+
+ /* if we have an ARGB palette as well, compute its value */
+ if (n->palettea)
+ {
+ int a = ((data >> 16) & 0xfc) | ((data >> 22) & 0x03);
+ int r = ((data >> 10) & 0xfc) | ((data >> 16) & 0x03);
+ int g = ((data >> 4) & 0xfc) | ((data >> 10) & 0x03);
+ int b = ((data << 2) & 0xfc) | ((data >> 4) & 0x03);
+ n->palettea[index] = MAKE_ARGB(a, r, g, b);
+ }
+
+ /* this doesn't dirty the table or go to the registers, so bail */
+ return;
+ }
+
+ /* if the register matches, don't update */
+ if (data == n->reg[regnum].u)
+ return;
+ n->reg[regnum].u = data;
+
+ /* first four entries are packed Y values */
+ if (regnum < 4)
+ {
+ regnum *= 4;
+ n->y[regnum+0] = (data >> 0) & 0xff;
+ n->y[regnum+1] = (data >> 8) & 0xff;
+ n->y[regnum+2] = (data >> 16) & 0xff;
+ n->y[regnum+3] = (data >> 24) & 0xff;
+ }
+
+ /* the second four entries are the I RGB values */
+ else if (regnum < 8)
+ {
+ regnum &= 3;
+ n->ir[regnum] = (INT32)(data << 5) >> 23;
+ n->ig[regnum] = (INT32)(data << 14) >> 23;
+ n->ib[regnum] = (INT32)(data << 23) >> 23;
+ }
+
+ /* the final four entries are the Q RGB values */
+ else
+ {
+ regnum &= 3;
+ n->qr[regnum] = (INT32)(data << 5) >> 23;
+ n->qg[regnum] = (INT32)(data << 14) >> 23;
+ n->qb[regnum] = (INT32)(data << 23) >> 23;
+ }
+
+ /* mark the table dirty */
+ n->dirty = TRUE;
+}
+
+
+static void ncc_table_update(ncc_table *n)
+{
+ int r, g, b, i;
+
+ /* generte all 256 possibilities */
+ for (i = 0; i < 256; i++)
+ {
+ int vi = (i >> 2) & 0x03;
+ int vq = (i >> 0) & 0x03;
+
+ /* start with the intensity */
+ r = g = b = n->y[(i >> 4) & 0x0f];
+
+ /* add the coloring */
+ r += n->ir[vi] + n->qr[vq];
+ g += n->ig[vi] + n->qg[vq];
+ b += n->ib[vi] + n->qb[vq];
+
+ /* clamp */
+ CLAMP(r, 0, 255);
+ CLAMP(g, 0, 255);
+ CLAMP(b, 0, 255);
+
+ /* fill in the table */
+ n->texel[i] = MAKE_ARGB(0xff, r, g, b);
+ }
+
+ /* no longer dirty */
+ n->dirty = FALSE;
+}
+
+
+
+/*************************************
+ *
+ * Faux DAC implementation
+ *
+ *************************************/
+
+static void dacdata_w(dac_state *d, UINT8 regnum, UINT8 data)
+{
+ d->reg[regnum] = data;
+}
+
+
+static void dacdata_r(dac_state *d, UINT8 regnum)
+{
+ UINT8 result = 0xff;
+
+ /* switch off the DAC register requested */
+ switch (regnum)
+ {
+ case 5:
+ /* this is just to make startup happy */
+ switch (d->reg[7])
+ {
+ case 0x01: result = 0x55; break;
+ case 0x07: result = 0x71; break;
+ case 0x0b: result = 0x79; break;
+ }
+ break;
+
+ default:
+ result = d->reg[regnum];
+ break;
+ }
+
+ /* remember the read result; it is fetched elsewhere */
+ d->read_result = result;
+}
+
+
+
+/*************************************
+ *
+ * Texuture parameter computation
+ *
+ *************************************/
+
+static void recompute_texture_params(tmu_state *t)
+{
+ int bppscale;
+ UINT32 base;
+ int lod;
+
+ /* extract LOD parameters */
+ t->lodmin = TEXLOD_LODMIN(t->reg[tLOD].u) << 6;
+ t->lodmax = TEXLOD_LODMAX(t->reg[tLOD].u) << 6;
+ t->lodbias = (INT8)(TEXLOD_LODBIAS(t->reg[tLOD].u) << 2) << 4;
+
+ /* determine which LODs are present */
+ t->lodmask = 0x1ff;
+ if (TEXLOD_LOD_TSPLIT(t->reg[tLOD].u))
+ {
+ if (!TEXLOD_LOD_ODD(t->reg[tLOD].u))
+ t->lodmask = 0x155;
+ else
+ t->lodmask = 0x0aa;
+ }
+
+ /* determine base texture width/height */
+ t->wmask = t->hmask = 0xff;
+ if (TEXLOD_LOD_S_IS_WIDER(t->reg[tLOD].u))
+ t->hmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u);
+ else
+ t->wmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u);
+
+ /* determine the bpp of the texture */
+ bppscale = TEXMODE_FORMAT(t->reg[textureMode].u) >> 3;
+
+ /* start with the base of LOD 0 */
+ if (t->texaddr_shift == 0 && (t->reg[texBaseAddr].u & 1))
+ mame_printf_debug("Tiled texture\n");
+ base = (t->reg[texBaseAddr].u & t->texaddr_mask) << t->texaddr_shift;
+ t->lodoffset[0] = base & t->mask;
+
+ /* LODs 1-3 are different depending on whether we are in multitex mode */
+ /* Several Voodoo 2 games leave the upper bits of TLOD == 0xff, meaning we think */
+ /* they want multitex mode when they really don't -- disable for now */
+ if (0)//TEXLOD_TMULTIBASEADDR(t->reg[tLOD].u))
+ {
+ base = (t->reg[texBaseAddr_1].u & t->texaddr_mask) << t->texaddr_shift;
+ t->lodoffset[1] = base & t->mask;
+ base = (t->reg[texBaseAddr_2].u & t->texaddr_mask) << t->texaddr_shift;
+ t->lodoffset[2] = base & t->mask;
+ base = (t->reg[texBaseAddr_3_8].u & t->texaddr_mask) << t->texaddr_shift;
+ t->lodoffset[3] = base & t->mask;
+ }
+ else
+ {
+ if (t->lodmask & (1 << 0))
+ base += (((t->wmask >> 0) + 1) * ((t->hmask >> 0) + 1)) << bppscale;
+ t->lodoffset[1] = base & t->mask;
+ if (t->lodmask & (1 << 1))
+ base += (((t->wmask >> 1) + 1) * ((t->hmask >> 1) + 1)) << bppscale;
+ t->lodoffset[2] = base & t->mask;
+ if (t->lodmask & (1 << 2))
+ base += (((t->wmask >> 2) + 1) * ((t->hmask >> 2) + 1)) << bppscale;
+ t->lodoffset[3] = base & t->mask;
+ }
+
+ /* remaining LODs make sense */
+ for (lod = 4; lod <= 8; lod++)
+ {
+ if (t->lodmask & (1 << (lod - 1)))
+ {
+ UINT32 size = ((t->wmask >> (lod - 1)) + 1) * ((t->hmask >> (lod - 1)) + 1);
+ if (size < 4) size = 4;
+ base += size << bppscale;
+ }
+ t->lodoffset[lod] = base & t->mask;
+ }
+
+ /* set the NCC lookup appropriately */
+ t->texel[1] = t->texel[9] = t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)].texel;
+
+ /* pick the lookup table */
+ t->lookup = t->texel[TEXMODE_FORMAT(t->reg[textureMode].u)];
+
+ /* compute the detail parameters */
+ t->detailmax = TEXDETAIL_DETAIL_MAX(t->reg[tDetail].u);
+ t->detailbias = (INT8)(TEXDETAIL_DETAIL_BIAS(t->reg[tDetail].u) << 2) << 6;
+ t->detailscale = TEXDETAIL_DETAIL_SCALE(t->reg[tDetail].u);
+
+ /* no longer dirty */
+ t->regdirty = FALSE;
+
+ /* check for separate RGBA filtering */
+ if (TEXDETAIL_SEPARATE_RGBA_FILTER(t->reg[tDetail].u))
+ fatalerror("Separate RGBA filters!");
+}
+
+
+INLINE INT32 prepare_tmu(tmu_state *t)
+{
+ INT64 texdx, texdy;
+ INT32 lodbase;
+
+ /* if the texture parameters are dirty, update them */
+ if (t->regdirty)
+ {
+ recompute_texture_params(t);
+
+ /* ensure that the NCC tables are up to date */
+ if ((TEXMODE_FORMAT(t->reg[textureMode].u) & 7) == 1)
+ {
+ ncc_table *n = &t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)];
+ t->texel[1] = t->texel[9] = n->texel;
+ if (n->dirty)
+ ncc_table_update(n);
+ }
+ }
+
+ /* compute (ds^2 + dt^2) in both X and Y as 28.36 numbers */
+ texdx = (INT64)(t->dsdx >> 14) * (INT64)(t->dsdx >> 14) + (INT64)(t->dtdx >> 14) * (INT64)(t->dtdx >> 14);
+ texdy = (INT64)(t->dsdy >> 14) * (INT64)(t->dsdy >> 14) + (INT64)(t->dtdy >> 14) * (INT64)(t->dtdy >> 14);
+
+ /* pick whichever is larger and shift off some high bits -> 28.20 */
+ if (texdx < texdy)
+ texdx = texdy;
+ texdx >>= 16;
+
+ /* use our fast reciprocal/log on this value; it expects input as a */
+ /* 16.32 number, and returns the log of the reciprocal, so we have to */
+ /* adjust the result: negative to get the log of the original value */
+ /* plus 12 to account for the extra exponent, and divided by 2 to */
+ /* get the log of the square root of texdx */
+ (void)fast_reciplog(texdx, &lodbase);
+ return (-lodbase + (12 << 8)) / 2;
+}
+
+
+
+/*************************************
+ *
+ * Command FIFO depth computation
+ *
+ *************************************/
+
+static int cmdfifo_compute_expected_depth(voodoo_state *v, cmdfifo_info *f)
+{
+ UINT32 *fifobase = v->fbi.ram;
+ UINT32 readptr = f->rdptr;
+ UINT32 command = fifobase[readptr / 4];
+ int i, count = 0;
+
+ /* low 3 bits specify the packet type */
+ switch (command & 7)
+ {
+ /*
+ Packet type 0: 1 or 2 words
+
+ Word Bits
+ 0 31:29 = reserved
+ 0 28:6 = Address [24:2]
+ 0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP)
+ 0 2:0 = Packet type (0)
+ 1 31:11 = reserved (JMP AGP only)
+ 1 10:0 = Address [35:25]
+ */
+ case 0:
+ if (((command >> 3) & 7) == 4)
+ return 2;
+ return 1;
+
+ /*
+ Packet type 1: 1 + N words
+
+ Word Bits
+ 0 31:16 = Number of words
+ 0 15 = Increment?
+ 0 14:3 = Register base
+ 0 2:0 = Packet type (1)
+ 1 31:0 = Data word
+ */
+ case 1:
+ return 1 + (command >> 16);
+
+ /*
+ Packet type 2: 1 + N words
+
+ Word Bits
+ 0 31:3 = 2D Register mask
+ 0 2:0 = Packet type (2)
+ 1 31:0 = Data word
+ */
+ case 2:
+ for (i = 3; i <= 31; i++)
+ if (command & (1 << i)) count++;
+ return 1 + count;
+
+ /*
+ Packet type 3: 1 + N words
+
+ Word Bits
+ 0 31:29 = Number of dummy entries following the data
+ 0 28 = Packed color data?
+ 0 25 = Disable ping pong sign correction (0=normal, 1=disable)
+ 0 24 = Culling sign (0=positive, 1=negative)
+ 0 23 = Enable culling (0=disable, 1=enable)
+ 0 22 = Strip mode (0=strip, 1=fan)
+ 0 17 = Setup S1 and T1
+ 0 16 = Setup W1
+ 0 15 = Setup S0 and T0
+ 0 14 = Setup W0
+ 0 13 = Setup Wb
+ 0 12 = Setup Z
+ 0 11 = Setup Alpha
+ 0 10 = Setup RGB
+ 0 9:6 = Number of vertices
+ 0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip)
+ 0 2:0 = Packet type (3)
+ 1 31:0 = Data word
+ */
+ case 3:
+ count = 2; /* X/Y */
+ if (command & (1 << 28))
+ {
+ if (command & (3 << 10)) count++; /* ARGB */
+ }
+ else
+ {
+ if (command & (1 << 10)) count += 3; /* RGB */
+ if (command & (1 << 11)) count++; /* A */
+ }
+ if (command & (1 << 12)) count++; /* Z */
+ if (command & (1 << 13)) count++; /* Wb */
+ if (command & (1 << 14)) count++; /* W0 */
+ if (command & (1 << 15)) count += 2; /* S0/T0 */
+ if (command & (1 << 16)) count++; /* W1 */
+ if (command & (1 << 17)) count += 2; /* S1/T1 */
+ count *= (command >> 6) & 15; /* numverts */
+ return 1 + count + (command >> 29);
+
+ /*
+ Packet type 4: 1 + N words
+
+ Word Bits
+ 0 31:29 = Number of dummy entries following the data
+ 0 28:15 = General register mask
+ 0 14:3 = Register base
+ 0 2:0 = Packet type (4)
+ 1 31:0 = Data word
+ */
+ case 4:
+ for (i = 15; i <= 28; i++)
+ if (command & (1 << i)) count++;
+ return 1 + count + (command >> 29);
+
+ /*
+ Packet type 5: 2 + N words
+
+ Word Bits
+ 0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture)
+ 0 29:26 = Byte disable W2
+ 0 25:22 = Byte disable WN
+ 0 21:3 = Num words
+ 0 2:0 = Packet type (5)
+ 1 31:30 = Reserved
+ 1 29:0 = Base address [24:0]
+ 2 31:0 = Data word
+ */
+ case 5:
+ return 2 + ((command >> 3) & 0x7ffff);
+
+ default:
+ mame_printf_debug("UNKNOWN PACKET TYPE %d\n", command & 7);
+ return 1;
+ }
+ return 1;
+}
+
+
+
+/*************************************
+ *
+ * Command FIFO execution
+ *
+ *************************************/
+
+static UINT32 cmdfifo_execute(voodoo_state *v, cmdfifo_info *f)
+{
+ UINT32 *fifobase = v->fbi.ram;
+ UINT32 readptr = f->rdptr;
+ UINT32 *src = &fifobase[readptr / 4];
+ UINT32 command = *src++;
+ int count, inc, code, i;
+ setup_vertex svert = {0};
+ offs_t target;
+ int cycles = 0;
+
+ switch (command & 7)
+ {
+ /*
+ Packet type 0: 1 or 2 words
+
+ Word Bits
+ 0 31:29 = reserved
+ 0 28:6 = Address [24:2]
+ 0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP)
+ 0 2:0 = Packet type (0)
+ 1 31:11 = reserved (JMP AGP only)
+ 1 10:0 = Address [35:25]
+ */
+ case 0:
+
+ /* extract parameters */
+ target = (command >> 4) & 0x1fffffc;
+
+ /* switch off of the specific command */
+ switch ((command >> 3) & 7)
+ {
+ case 0: /* NOP */
+ if (LOG_CMDFIFO) logerror(" NOP\n");
+ break;
+
+ case 1: /* JSR */
+ if (LOG_CMDFIFO) logerror(" JSR $%06X\n", target);
+ mame_printf_debug("JSR in CMDFIFO!\n");
+ src = &fifobase[target / 4];
+ break;
+
+ case 2: /* RET */
+ if (LOG_CMDFIFO) logerror(" RET $%06X\n", target);
+ fatalerror("RET in CMDFIFO!");
+ break;
+
+ case 3: /* JMP LOCAL FRAME BUFFER */
+ if (LOG_CMDFIFO) logerror(" JMP LOCAL FRAMEBUF $%06X\n", target);
+ src = &fifobase[target / 4];
+ break;
+
+ case 4: /* JMP AGP */
+ if (LOG_CMDFIFO) logerror(" JMP AGP $%06X\n", target);
+ fatalerror("JMP AGP in CMDFIFO!");
+ src = &fifobase[target / 4];
+ break;
+
+ default:
+ mame_printf_debug("INVALID JUMP COMMAND!\n");
+ fatalerror(" INVALID JUMP COMMAND");
+ break;
+ }
+ break;
+
+ /*
+ Packet type 1: 1 + N words
+
+ Word Bits
+ 0 31:16 = Number of words
+ 0 15 = Increment?
+ 0 14:3 = Register base
+ 0 2:0 = Packet type (1)
+ 1 31:0 = Data word
+ */
+ case 1:
+
+ /* extract parameters */
+ count = command >> 16;
+ inc = (command >> 15) & 1;
+ target = (command >> 3) & 0xfff;
+
+ if (LOG_CMDFIFO) logerror(" PACKET TYPE 1: count=%d inc=%d reg=%04X\n", count, inc, target);
+
+ /* loop over all registers and write them one at a time */
+ for (i = 0; i < count; i++, target += inc)
+ cycles += register_w(v, target, *src++);
+ break;
+
+ /*
+ Packet type 2: 1 + N words
+
+ Word Bits
+ 0 31:3 = 2D Register mask
+ 0 2:0 = Packet type (2)
+ 1 31:0 = Data word
+ */
+ case 2:
+ if (LOG_CMDFIFO) logerror(" PACKET TYPE 2: mask=%X\n", (command >> 3) & 0x1ffffff);
+
+ /* loop over all registers and write them one at a time */
+ for (i = 3; i <= 31; i++)
+ if (command & (1 << i))
+ cycles += register_w(v, bltSrcBaseAddr + (i - 3), *src++);
+ break;
+
+ /*
+ Packet type 3: 1 + N words
+
+ Word Bits
+ 0 31:29 = Number of dummy entries following the data
+ 0 28 = Packed color data?
+ 0 25 = Disable ping pong sign correction (0=normal, 1=disable)
+ 0 24 = Culling sign (0=positive, 1=negative)
+ 0 23 = Enable culling (0=disable, 1=enable)
+ 0 22 = Strip mode (0=strip, 1=fan)
+ 0 17 = Setup S1 and T1
+ 0 16 = Setup W1
+ 0 15 = Setup S0 and T0
+ 0 14 = Setup W0
+ 0 13 = Setup Wb
+ 0 12 = Setup Z
+ 0 11 = Setup Alpha
+ 0 10 = Setup RGB
+ 0 9:6 = Number of vertices
+ 0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip)
+ 0 2:0 = Packet type (3)
+ 1 31:0 = Data word
+ */
+ case 3:
+
+ /* extract parameters */
+ count = (command >> 6) & 15;
+ code = (command >> 3) & 7;
+
+ if (LOG_CMDFIFO) logerror(" PACKET TYPE 3: count=%d code=%d mask=%03X smode=%02X pc=%d\n", count, code, (command >> 10) & 0xfff, (command >> 22) & 0x3f, (command >> 28) & 1);
+
+ /* copy relevant bits into the setup mode register */
+ v->reg[sSetupMode].u = ((command >> 10) & 0xff) | ((command >> 6) & 0xf0000);
+
+ /* loop over triangles */
+ for (i = 0; i < count; i++)
+ {
+ /* always extract X/Y */
+ svert.x = *(float *)src++;
+ svert.y = *(float *)src++;
+
+ /* load ARGB values if packed */
+ if (command & (1 << 28))
+ {
+ if (command & (3 << 10))
+ {
+ UINT32 argb = *src++;
+ if (command & (1 << 10))
+ {
+ svert.r = RGB_RED(argb);
+ svert.g = RGB_GREEN(argb);
+ svert.b = RGB_BLUE(argb);
+ }
+ if (command & (1 << 11))
+ svert.a = RGB_ALPHA(argb);
+ }
+ }
+
+ /* load ARGB values if not packed */
+ else
+ {
+ if (command & (1 << 10))
+ {
+ svert.r = *(float *)src++;
+ svert.g = *(float *)src++;
+ svert.b = *(float *)src++;
+ }
+ if (command & (1 << 11))
+ svert.a = *(float *)src++;
+ }
+
+ /* load Z and Wb values */
+ if (command & (1 << 12))
+ svert.z = *(float *)src++;
+ if (command & (1 << 13))
+ svert.wb = *(float *)src++;
+
+ /* load W0, S0, T0 values */
+ if (command & (1 << 14))
+ svert.w0 = *(float *)src++;
+ if (command & (1 << 15))
+ {
+ svert.s0 = *(float *)src++;
+ svert.t0 = *(float *)src++;
+ }
+
+ /* load W1, S1, T1 values */
+ if (command & (1 << 16))
+ svert.w1 = *(float *)src++;
+ if (command & (1 << 17))
+ {
+ svert.s1 = *(float *)src++;
+ svert.t1 = *(float *)src++;
+ }
+
+ /* if we're starting a new strip, or if this is the first of a set of verts */
+ /* for a series of individual triangles, initialize all the verts */
+ if ((code == 1 && i == 0) || (code == 0 && i % 3 == 0))
+ {
+ v->fbi.sverts = 1;
+ v->fbi.svert[0] = v->fbi.svert[1] = v->fbi.svert[2] = svert;
+ }
+
+ /* otherwise, add this to the list */
+ else
+ {
+ /* for strip mode, shuffle vertex 1 down to 0 */
+ if (!(command & (1 << 22)))
+ v->fbi.svert[0] = v->fbi.svert[1];
+
+ /* copy 2 down to 1 and add our new one regardless */
+ v->fbi.svert[1] = v->fbi.svert[2];
+ v->fbi.svert[2] = svert;
+
+ /* if we have enough, draw */
+ if (++v->fbi.sverts >= 3)
+ cycles += setup_and_draw_triangle(v);
+ }
+ }
+
+ /* account for the extra dummy words */
+ src += command >> 29;
+ break;
+
+ /*
+ Packet type 4: 1 + N words
+
+ Word Bits
+ 0 31:29 = Number of dummy entries following the data
+ 0 28:15 = General register mask
+ 0 14:3 = Register base
+ 0 2:0 = Packet type (4)
+ 1 31:0 = Data word
+ */
+ case 4:
+
+ /* extract parameters */
+ target = (command >> 3) & 0xfff;
+
+ if (LOG_CMDFIFO) logerror(" PACKET TYPE 4: mask=%X reg=%04X pad=%d\n", (command >> 15) & 0x3fff, target, command >> 29);
+
+ /* loop over all registers and write them one at a time */
+ for (i = 15; i <= 28; i++)
+ if (command & (1 << i))
+ cycles += register_w(v, target + (i - 15), *src++);
+
+ /* account for the extra dummy words */
+ src += command >> 29;
+ break;
+
+ /*
+ Packet type 5: 2 + N words
+
+ Word Bits
+ 0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture)
+ 0 29:26 = Byte disable W2
+ 0 25:22 = Byte disable WN
+ 0 21:3 = Num words
+ 0 2:0 = Packet type (5)
+ 1 31:30 = Reserved
+ 1 29:0 = Base address [24:0]
+ 2 31:0 = Data word
+ */
+ case 5:
+
+ /* extract parameters */
+ count = (command >> 3) & 0x7ffff;
+ target = *src++ / 4;
+
+ /* handle LFB writes */
+ if ((command >> 30) == 2)
+ {
+ if (LOG_CMDFIFO) logerror(" PACKET TYPE 5: LFB count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15);
+
+ /* loop over words */
+ for (i = 0; i < count; i++)
+ cycles += lfb_w(v, target++, *src++, 0, FALSE);
+ }
+ else if ((command >> 30) == 3)
+ {
+ if (LOG_CMDFIFO) logerror(" PACKET TYPE 5: textureRAM count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15);
+
+ /* loop over words */
+ for (i = 0; i < count; i++)
+ cycles += texture_w(v, target++, *src++);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "PACKET TYPE %d\n", command & 7);
+ break;
+ }
+
+ /* by default just update the read pointer past all the data we consumed */
+ f->rdptr = 4 * (src - fifobase);
+ return cycles;
+}
+
+
+
+/*************************************
+ *
+ * Handle execution if we're ready
+ *
+ *************************************/
+
+static INT32 cmdfifo_execute_if_ready(voodoo_state *v, cmdfifo_info *f)
+{
+ int needed_depth;
+ int cycles;
+
+ /* all CMDFIFO commands need at least one word */
+ if (f->depth == 0)
+ return -1;
+
+ /* see if we have enough for the current command */
+ needed_depth = cmdfifo_compute_expected_depth(v, f);
+ if (f->depth < needed_depth)
+ return -1;
+
+ /* execute */
+ cycles = cmdfifo_execute(v, f);
+ f->depth -= needed_depth;
+ return cycles;
+}
+
+
+
+/*************************************
+ *
+ * Handle writes to the CMD FIFO
+ *
+ *************************************/
+
+static void cmdfifo_w(voodoo_state *v, cmdfifo_info *f, offs_t offset, UINT32 data)
+{
+ UINT32 addr = f->base + offset * 4;
+ UINT32 *fifobase = v->fbi.ram;
+
+ if (LOG_CMDFIFO_VERBOSE) logerror("CMDFIFO_w(%04X) = %08X\n", offset, data);
+
+ /* write the data */
+ if (addr < f->end)
+ fifobase[addr / 4] = data;
+
+ /* count holes? */
+ if (f->count_holes)
+ {
+ /* in-order, no holes */
+ if (f->holes == 0 && addr == f->amin + 4)
+ {
+ f->amin = f->amax = addr;
+ f->depth++;
+ }
+
+ /* out-of-order, below the minimum */
+ else if (addr < f->amin)
+ {
+ if (f->holes != 0)
+ logerror("Unexpected CMDFIFO: AMin=%08X AMax=%08X Holes=%d WroteTo:%08X\n",
+ f->amin, f->amax, f->holes, addr);
+ f->amin = f->amax = addr;
+ f->depth++;
+ }
+
+ /* out-of-order, but within the min-max range */
+ else if (addr < f->amax)
+ {
+ f->holes--;
+ if (f->holes == 0)
+ {
+ f->depth += (f->amax - f->amin) / 4;
+ f->amin = f->amax;
+ }
+ }
+
+ /* out-of-order, bumping max */
+ else
+ {
+ f->holes += (addr - f->amax) / 4 - 1;
+ f->amax = addr;
+ }
+ }
+
+ /* execute if we can */
+ if (!v->pci.op_pending)
+ {
+ INT32 cycles = cmdfifo_execute_if_ready(v, f);
+ if (cycles > 0)
+ {
+ v->pci.op_pending = TRUE;
+ v->pci.op_end_time = attotime_add_attoseconds(timer_get_time(), (attoseconds_t)cycles * v->attoseconds_per_cycle);
+
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:direct write start at %d.%08X%08X end at %d.%08X%08X\n", v->index,
+ timer_get_time().seconds, (UINT32)(timer_get_time().attoseconds >> 32), (UINT32)timer_get_time().attoseconds,
+ v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds);
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Stall the activecpu until we are
+ * ready
+ *
+ *************************************/
+
+static TIMER_CALLBACK_PTR( stall_cpu_callback )
+{
+ check_stalled_cpu(param, timer_get_time());
+}
+
+
+static void check_stalled_cpu(voodoo_state *v, attotime current_time)
+{
+ int resume = FALSE;
+
+ /* flush anything we can */
+ if (v->pci.op_pending)
+ flush_fifos(v, current_time);
+
+ /* if we're just stalled until the LWM is passed, see if we're ok now */
+ if (v->pci.stall_state == STALLED_UNTIL_FIFO_LWM)
+ {
+ /* if there's room in the memory FIFO now, we can proceed */
+ if (FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u))
+ {
+ if (fifo_items(&v->fbi.fifo) < 2 * 32 * FBIINIT0_MEMORY_FIFO_HWM(v->reg[fbiInit0].u))
+ resume = TRUE;
+ }
+ else if (fifo_space(&v->pci.fifo) > 2 * FBIINIT0_PCI_FIFO_LWM(v->reg[fbiInit0].u))
+ resume = TRUE;
+ }
+
+ /* if we're stalled until the FIFOs are empty, check now */
+ else if (v->pci.stall_state == STALLED_UNTIL_FIFO_EMPTY)
+ {
+ if (FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u))
+ {
+ if (fifo_empty(&v->fbi.fifo) && fifo_empty(&v->pci.fifo))
+ resume = TRUE;
+ }
+ else if (fifo_empty(&v->pci.fifo))
+ resume = TRUE;
+ }
+
+ /* resume if necessary */
+ if (resume || !v->pci.op_pending)
+ {
+ if (LOG_FIFO) logerror("VOODOO.%d.FIFO:Stall condition cleared; resuming\n", v->index);
+ v->pci.stall_state = NOT_STALLED;
+
+ /* either call the callback, or trigger the trigger */
+ if (v->pci.stall_callback)
+ (*v->pci.stall_callback)(FALSE);
+ else
+ cpu_trigger(v->trigger);
+ }
+
+ /* if not, set a timer for the next one */
+ else
+ {
+ timer_adjust_ptr(v->pci.continue_timer, attotime_sub(v->pci.op_end_time, current_time), attotime_never);
+ }
+}
+
+
+static void stall_cpu(voodoo_state *v, int state, attotime current_time)
+{
+ /* sanity check */
+ if (!v->pci.op_pending) fatalerror("FIFOs not empty, no op pending!");
+
+ /* set the state and update statistics */
+ v->pci.stall_state = state;
+ v->stats.stalls++;
+
+ /* either call the callback, or spin the CPU */
+ if (v->pci.stall_callback)
+ (*v->pci.stall_callback)(TRUE);
+ else
+ cpu_spinuntil_trigger(v->trigger);
+
+ /* set a timer to clear the stall */
+ timer_adjust_ptr(v->pci.continue_timer, attotime_sub(v->pci.op_end_time, current_time), attotime_never);
+}
+
+
+
+/*************************************
+ *
+ * Voodoo register writes
+ *
+ *************************************/
+
+static INT32 register_w(voodoo_state *v, offs_t offset, UINT32 data)
+{
+ UINT32 origdata = data;
+ INT32 cycles = 0;
+ INT64 data64;
+ UINT8 regnum;
+ UINT8 chips;
+
+ /* statistics */
+ v->stats.reg_writes++;
+
+ /* determine which chips we are addressing */
+ chips = (offset >> 8) & 0xf;
+ if (chips == 0)
+ chips = 0xf;
+ chips &= v->chipmask;
+
+ /* the first 64 registers can be aliased differently */
+ if ((offset & 0x800c0) == 0x80000 && v->alt_regmap)
+ regnum = register_alias_map[offset & 0x3f];
+ else
+ regnum = offset & 0xff;
+
+ /* first make sure this register is readable */
+ if (!(v->regaccess[regnum] & REGISTER_WRITE))
+ {
+ logerror("VOODOO.%d.ERROR:Invalid attempt to write %s\n", v->index, v->regnames[regnum]);
+ return 0;
+ }
+
+ /* switch off the register */
+ switch (regnum)
+ {
+ /* Vertex data is 12.4 formatted fixed point */
+ case fvertexAx:
+ data = float_to_int32(data, 4);
+ case vertexAx:
+ if (chips & 1) v->fbi.ax = (INT16)data;
+ break;
+
+ case fvertexAy:
+ data = float_to_int32(data, 4);
+ case vertexAy:
+ if (chips & 1) v->fbi.ay = (INT16)data;
+ break;
+
+ case fvertexBx:
+ data = float_to_int32(data, 4);
+ case vertexBx:
+ if (chips & 1) v->fbi.bx = (INT16)data;
+ break;
+
+ case fvertexBy:
+ data = float_to_int32(data, 4);
+ case vertexBy:
+ if (chips & 1) v->fbi.by = (INT16)data;
+ break;
+
+ case fvertexCx:
+ data = float_to_int32(data, 4);
+ case vertexCx:
+ if (chips & 1) v->fbi.cx = (INT16)data;
+ break;
+
+ case fvertexCy:
+ data = float_to_int32(data, 4);
+ case vertexCy:
+ if (chips & 1) v->fbi.cy = (INT16)data;
+ break;
+
+ /* RGB data is 12.12 formatted fixed point */
+ case fstartR:
+ data = float_to_int32(data, 12);
+ case startR:
+ if (chips & 1) v->fbi.startr = (INT32)(data << 8) >> 8;
+ break;
+
+ case fstartG:
+ data = float_to_int32(data, 12);
+ case startG:
+ if (chips & 1) v->fbi.startg = (INT32)(data << 8) >> 8;
+ break;
+
+ case fstartB:
+ data = float_to_int32(data, 12);
+ case startB:
+ if (chips & 1) v->fbi.startb = (INT32)(data << 8) >> 8;
+ break;
+
+ case fstartA:
+ data = float_to_int32(data, 12);
+ case startA:
+ if (chips & 1) v->fbi.starta = (INT32)(data << 8) >> 8;
+ break;
+
+ case fdRdX:
+ data = float_to_int32(data, 12);
+ case dRdX:
+ if (chips & 1) v->fbi.drdx = (INT32)(data << 8) >> 8;
+ break;
+
+ case fdGdX:
+ data = float_to_int32(data, 12);
+ case dGdX:
+ if (chips & 1) v->fbi.dgdx = (INT32)(data << 8) >> 8;
+ break;
+
+ case fdBdX:
+ data = float_to_int32(data, 12);
+ case dBdX:
+ if (chips & 1) v->fbi.dbdx = (INT32)(data << 8) >> 8;
+ break;
+
+ case fdAdX:
+ data = float_to_int32(data, 12);
+ case dAdX:
+ if (chips & 1) v->fbi.dadx = (INT32)(data << 8) >> 8;
+ break;
+
+ case fdRdY:
+ data = float_to_int32(data, 12);
+ case dRdY:
+ if (chips & 1) v->fbi.drdy = (INT32)(data << 8) >> 8;
+ break;
+
+ case fdGdY:
+ data = float_to_int32(data, 12);
+ case dGdY:
+ if (chips & 1) v->fbi.dgdy = (INT32)(data << 8) >> 8;
+ break;
+
+ case fdBdY:
+ data = float_to_int32(data, 12);
+ case dBdY:
+ if (chips & 1) v->fbi.dbdy = (INT32)(data << 8) >> 8;
+ break;
+
+ case fdAdY:
+ data = float_to_int32(data, 12);
+ case dAdY:
+ if (chips & 1) v->fbi.dady = (INT32)(data << 8) >> 8;
+ break;
+
+ /* Z data is 20.12 formatted fixed point */
+ case fstartZ:
+ data = float_to_int32(data, 12);
+ case startZ:
+ if (chips & 1) v->fbi.startz = (INT32)data;
+ break;
+
+ case fdZdX:
+ data = float_to_int32(data, 12);
+ case dZdX:
+ if (chips & 1) v->fbi.dzdx = (INT32)data;
+ break;
+
+ case fdZdY:
+ data = float_to_int32(data, 12);
+ case dZdY:
+ if (chips & 1) v->fbi.dzdy = (INT32)data;
+ break;
+
+ /* S,T data is 14.18 formatted fixed point, converted to 16.32 internally */
+ case fstartS:
+ data64 = float_to_int64(data, 32);
+ if (chips & 2) v->tmu[0].starts = data64;
+ if (chips & 4) v->tmu[1].starts = data64;
+ break;
+ case startS:
+ if (chips & 2) v->tmu[0].starts = (INT64)(INT32)data << 14;
+ if (chips & 4) v->tmu[1].starts = (INT64)(INT32)data << 14;
+ break;
+
+ case fstartT:
+ data64 = float_to_int64(data, 32);
+ if (chips & 2) v->tmu[0].startt = data64;
+ if (chips & 4) v->tmu[1].startt = data64;
+ break;
+ case startT:
+ if (chips & 2) v->tmu[0].startt = (INT64)(INT32)data << 14;
+ if (chips & 4) v->tmu[1].startt = (INT64)(INT32)data << 14;
+ break;
+
+ case fdSdX:
+ data64 = float_to_int64(data, 32);
+ if (chips & 2) v->tmu[0].dsdx = data64;
+ if (chips & 4) v->tmu[1].dsdx = data64;
+ break;
+ case dSdX:
+ if (chips & 2) v->tmu[0].dsdx = (INT64)(INT32)data << 14;
+ if (chips & 4) v->tmu[1].dsdx = (INT64)(INT32)data << 14;
+ break;
+
+ case fdTdX:
+ data64 = float_to_int64(data, 32);
+ if (chips & 2) v->tmu[0].dtdx = data64;
+ if (chips & 4) v->tmu[1].dtdx = data64;
+ break;
+ case dTdX:
+ if (chips & 2) v->tmu[0].dtdx = (INT64)(INT32)data << 14;
+ if (chips & 4) v->tmu[1].dtdx = (INT64)(INT32)data << 14;
+ break;
+
+ case fdSdY:
+ data64 = float_to_int64(data, 32);
+ if (chips & 2) v->tmu[0].dsdy = data64;
+ if (chips & 4) v->tmu[1].dsdy = data64;
+ break;
+ case dSdY:
+ if (chips & 2) v->tmu[0].dsdy = (INT64)(INT32)data << 14;
+ if (chips & 4) v->tmu[1].dsdy = (INT64)(INT32)data << 14;
+ break;
+
+ case fdTdY:
+ data64 = float_to_int64(data, 32);
+ if (chips & 2) v->tmu[0].dtdy = data64;
+ if (chips & 4) v->tmu[1].dtdy = data64;
+ break;
+ case dTdY:
+ if (chips & 2) v->tmu[0].dtdy = (INT64)(INT32)data << 14;
+ if (chips & 4) v->tmu[1].dtdy = (INT64)(INT32)data << 14;
+ break;
+
+ /* W data is 2.30 formatted fixed point, converted to 16.32 internally */
+ case fstartW:
+ data64 = float_to_int64(data, 32);
+ if (chips & 1) v->fbi.startw = data64;
+ if (chips & 2) v->tmu[0].startw = data64;
+ if (chips & 4) v->tmu[1].startw = data64;
+ break;
+ case startW:
+ if (chips & 1) v->fbi.startw = (INT64)(INT32)data << 2;
+ if (chips & 2) v->tmu[0].startw = (INT64)(INT32)data << 2;
+ if (chips & 4) v->tmu[1].startw = (INT64)(INT32)data << 2;
+ break;
+
+ case fdWdX:
+ data64 = float_to_int64(data, 32);
+ if (chips & 1) v->fbi.dwdx = data64;
+ if (chips & 2) v->tmu[0].dwdx = data64;
+ if (chips & 4) v->tmu[1].dwdx = data64;
+ break;
+ case dWdX:
+ if (chips & 1) v->fbi.dwdx = (INT64)(INT32)data << 2;
+ if (chips & 2) v->tmu[0].dwdx = (INT64)(INT32)data << 2;
+ if (chips & 4) v->tmu[1].dwdx = (INT64)(INT32)data << 2;
+ break;
+
+ case fdWdY:
+ data64 = float_to_int64(data, 32);
+ if (chips & 1) v->fbi.dwdy = data64;
+ if (chips & 2) v->tmu[0].dwdy = data64;
+ if (chips & 4) v->tmu[1].dwdy = data64;
+ break;
+ case dWdY:
+ if (chips & 1) v->fbi.dwdy = (INT64)(INT32)data << 2;
+ if (chips & 2) v->tmu[0].dwdy = (INT64)(INT32)data << 2;
+ if (chips & 4) v->tmu[1].dwdy = (INT64)(INT32)data << 2;
+ break;
+
+ /* setup bits */
+ case sARGB:
+ if (chips & 1)
+ {
+ v->reg[sAlpha].f = RGB_ALPHA(data);
+ v->reg[sRed].f = RGB_RED(data);
+ v->reg[sGreen].f = RGB_GREEN(data);
+ v->reg[sBlue].f = RGB_BLUE(data);
+ }
+ break;
+
+ /* mask off invalid bits for different cards */
+ case fbzColorPath:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (v->type < VOODOO_2)
+ data &= 0x0fffffff;
+ if (chips & 1) v->reg[fbzColorPath].u = data;
+ break;
+
+ case fbzMode:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (v->type < VOODOO_2)
+ data &= 0x001fffff;
+ if (chips & 1) v->reg[fbzMode].u = data;
+ break;
+
+ case fogMode:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (v->type < VOODOO_2)
+ data &= 0x0000003f;
+ if (chips & 1) v->reg[fogMode].u = data;
+ break;
+
+ /* triangle drawing */
+ case triangleCMD:
+ v->fbi.cheating_allowed = (v->fbi.ax != 0 || v->fbi.ay != 0 || v->fbi.bx > 50 || v->fbi.by != 0 || v->fbi.cx != 0 || v->fbi.cy > 50);
+ v->fbi.sign = data;
+ cycles = triangle(v);
+ break;
+
+ case ftriangleCMD:
+ v->fbi.cheating_allowed = TRUE;
+ v->fbi.sign = data;
+ cycles = triangle(v);
+ break;
+
+ case sBeginTriCMD:
+ cycles = begin_triangle(v);
+ break;
+
+ case sDrawTriCMD:
+ cycles = draw_triangle(v);
+ break;
+
+ /* other commands */
+ case nopCMD:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (data & 1)
+ reset_counters(v);
+ if (data & 2)
+ v->reg[fbiTrianglesOut].u = 0;
+ break;
+
+ case fastfillCMD:
+ cycles = fastfill(v);
+ break;
+
+ case swapbufferCMD:
+ poly_wait(v->poly, v->regnames[regnum]);
+ cycles = swapbuffer(v, data);
+ break;
+
+ case userIntrCMD:
+ poly_wait(v->poly, v->regnames[regnum]);
+ fatalerror("userIntrCMD");
+ break;
+
+ /* gamma table access -- Voodoo/Voodoo2 only */
+ case clutData:
+ if (v->type <= VOODOO_2 && (chips & 1))
+ {
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (!FBIINIT1_VIDEO_TIMING_RESET(v->reg[fbiInit1].u))
+ {
+ int index = data >> 24;
+ if (index <= 32)
+ {
+ v->fbi.clut[index] = data;
+ v->fbi.clut_dirty = TRUE;
+ }
+ }
+ else
+ logerror("clutData ignored because video timing reset = 1\n");
+ }
+ break;
+
+ /* external DAC access -- Voodoo/Voodoo2 only */
+ case dacData:
+ if (v->type <= VOODOO_2 && (chips & 1))
+ {
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (!(data & 0x800))
+ dacdata_w(&v->dac, (data >> 8) & 7, data & 0xff);
+ else
+ dacdata_r(&v->dac, (data >> 8) & 7);
+ }
+ break;
+
+ /* vertical sync rate -- Voodoo/Voodoo2 only */
+ case hSync:
+ case vSync:
+ case backPorch:
+ case videoDimensions:
+ if (v->type <= VOODOO_2 && (chips & 1))
+ {
+ poly_wait(v->poly, v->regnames[regnum]);
+ v->reg[regnum].u = data;
+ if (v->reg[hSync].u != 0 && v->reg[vSync].u != 0 && v->reg[videoDimensions].u != 0)
+ {
+ int htotal = ((v->reg[hSync].u >> 16) & 0x3ff) + 1 + (v->reg[hSync].u & 0xff) + 1;
+ int vtotal = ((v->reg[vSync].u >> 16) & 0xfff) + (v->reg[vSync].u & 0xfff);
+ int hvis = v->reg[videoDimensions].u & 0x3ff;
+ int vvis = (v->reg[videoDimensions].u >> 16) & 0x3ff;
+ int hbp = (v->reg[backPorch].u & 0xff) + 2;
+ int vbp = (v->reg[backPorch].u >> 16) & 0xff;
+ screen_state *state = &Machine->screen[v->scrnum];
+ attoseconds_t stdperiod, medperiod, vgaperiod;
+ attoseconds_t stddiff, meddiff, vgadiff;
+ rectangle visarea;
+
+ /* create a new visarea */
+ visarea.min_x = hbp;
+ visarea.max_x = hbp + hvis - 1;
+ visarea.min_y = vbp;
+ visarea.max_y = vbp + vvis - 1;
+
+ /* keep within bounds */
+ visarea.max_x = MIN(visarea.max_x, htotal - 1);
+ visarea.max_y = MIN(visarea.max_y, vtotal - 1);
+
+ /* compute the new period for standard res, medium res, and VGA res */
+ stdperiod = HZ_TO_ATTOSECONDS(15750) * vtotal;
+ medperiod = HZ_TO_ATTOSECONDS(25000) * vtotal;
+ vgaperiod = HZ_TO_ATTOSECONDS(31500) * vtotal;
+
+ /* compute a diff against the current refresh period */
+ stddiff = stdperiod - state->refresh;
+ if (stddiff < 0) stddiff = -stddiff;
+ meddiff = medperiod - state->refresh;
+ if (meddiff < 0) meddiff = -meddiff;
+ vgadiff = vgaperiod - state->refresh;
+ if (vgadiff < 0) vgadiff = -vgadiff;
+
+ mame_printf_debug("hSync=%08X vSync=%08X backPorch=%08X videoDimensions=%08X\n",
+ v->reg[hSync].u, v->reg[vSync].u, v->reg[backPorch].u, v->reg[videoDimensions].u);
+ mame_printf_debug("Horiz: %d-%d (%d total) Vert: %d-%d (%d total) -- ", visarea.min_x, visarea.max_x, htotal, visarea.min_y, visarea.max_y, vtotal);
+
+ /* configure the screen based on which one matches the closest */
+ if (stddiff < meddiff && stddiff < vgadiff)
+ {
+ video_screen_configure(v->scrnum, htotal, vtotal, &visarea, stdperiod);
+ mame_printf_debug("Standard resolution, %f Hz\n", ATTOSECONDS_TO_HZ(stdperiod));
+ }
+ else if (meddiff < vgadiff)
+ {
+ video_screen_configure(v->scrnum, htotal, vtotal, &visarea, medperiod);
+ mame_printf_debug("Medium resolution, %f Hz\n", ATTOSECONDS_TO_HZ(medperiod));
+ }
+ else
+ {
+ video_screen_configure(v->scrnum, htotal, vtotal, &visarea, vgaperiod);
+ mame_printf_debug("VGA resolution, %f Hz\n", ATTOSECONDS_TO_HZ(vgaperiod));
+ }
+
+ /* configure the new framebuffer info */
+ v->fbi.width = hvis;
+ v->fbi.height = vvis;
+ v->fbi.xoffs = hbp;
+ v->fbi.yoffs = vbp;
+ v->fbi.vsyncscan = (v->reg[vSync].u >> 16) & 0xfff;
+
+ /* recompute the time of VBLANK */
+ adjust_vblank_timer(v);
+
+ /* if changing dimensions, update video memory layout */
+ if (regnum == videoDimensions)
+ recompute_video_memory(v);
+ }
+ }
+ break;
+
+ /* fbiInit0 can only be written if initEnable says we can -- Voodoo/Voodoo2 only */
+ case fbiInit0:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (v->type <= VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
+ {
+ v->reg[fbiInit0].u = data;
+ if (FBIINIT0_GRAPHICS_RESET(data))
+ soft_reset(v);
+ if (FBIINIT0_FIFO_RESET(data))
+ fifo_reset(&v->pci.fifo);
+ recompute_video_memory(v);
+ }
+ break;
+
+ /* fbiInit5-7 are Voodoo 2-only; ignore them on anything else */
+ case fbiInit5:
+ case fbiInit6:
+ if (v->type < VOODOO_2)
+ break;
+ /* else fall through... */
+
+ /* fbiInitX can only be written if initEnable says we can -- Voodoo/Voodoo2 only */
+ /* most of these affect memory layout, so always recompute that when done */
+ case fbiInit1:
+ case fbiInit2:
+ case fbiInit4:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (v->type <= VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
+ {
+ v->reg[regnum].u = data;
+ recompute_video_memory(v);
+ v->fbi.video_changed = TRUE;
+ }
+ break;
+
+ case fbiInit3:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (v->type <= VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
+ {
+ v->reg[regnum].u = data;
+ v->alt_regmap = FBIINIT3_TRI_REGISTER_REMAP(data);
+ v->fbi.yorigin = FBIINIT3_YORIGIN_SUBTRACT(v->reg[fbiInit3].u);
+ recompute_video_memory(v);
+ }
+ break;
+
+ case fbiInit7:
+/* case swapPending: -- Banshee */
+ if (v->type == VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
+ {
+ poly_wait(v->poly, v->regnames[regnum]);
+ v->reg[regnum].u = data;
+ v->fbi.cmdfifo[0].enable = FBIINIT7_CMDFIFO_ENABLE(data);
+ v->fbi.cmdfifo[0].count_holes = !FBIINIT7_DISABLE_CMDFIFO_HOLES(data);
+ }
+ else if (v->type >= VOODOO_BANSHEE)
+ v->fbi.swaps_pending++;
+ break;
+
+ /* cmdFifo -- Voodoo2 only */
+ case cmdFifoBaseAddr:
+ if (v->type == VOODOO_2 && (chips & 1))
+ {
+ poly_wait(v->poly, v->regnames[regnum]);
+ v->reg[regnum].u = data;
+ v->fbi.cmdfifo[0].base = (data & 0x3ff) << 12;
+ v->fbi.cmdfifo[0].end = (((data >> 16) & 0x3ff) + 1) << 12;
+ }
+ break;
+
+ case cmdFifoBump:
+ if (v->type == VOODOO_2 && (chips & 1))
+ fatalerror("cmdFifoBump");
+ break;
+
+ case cmdFifoRdPtr:
+ if (v->type == VOODOO_2 && (chips & 1))
+ v->fbi.cmdfifo[0].rdptr = data;
+ break;
+
+ case cmdFifoAMin:
+/* case colBufferAddr: -- Banshee */
+ if (v->type == VOODOO_2 && (chips & 1))
+ v->fbi.cmdfifo[0].amin = data;
+ else if (v->type >= VOODOO_BANSHEE && (chips & 1))
+ {
+ v->fbi.rgb[1] = (UINT16 *)((UINT8 *)v->fbi.ram + (data & v->fbi.mask & ~0x0f));
+ v->fbi.rgbmax[1] = (UINT16 *)((UINT8 *)v->fbi.ram + v->fbi.mask + 1) - v->fbi.rgb[1];
+ }
+ break;
+
+ case cmdFifoAMax:
+/* case colBufferStride: -- Banshee */
+ if (v->type == VOODOO_2 && (chips & 1))
+ v->fbi.cmdfifo[0].amax = data;
+ else if (v->type >= VOODOO_BANSHEE && (chips & 1))
+ {
+ if (data & 0x8000)
+ v->fbi.rowpixels = (data & 0x7f) << 6;
+ else
+ v->fbi.rowpixels = (data & 0x3fff) >> 1;
+ }
+ break;
+
+ case cmdFifoDepth:
+/* case auxBufferAddr: -- Banshee */
+ if (v->type == VOODOO_2 && (chips & 1))
+ v->fbi.cmdfifo[0].depth = data;
+ else if (v->type >= VOODOO_BANSHEE && (chips & 1))
+ {
+ v->fbi.aux = (UINT16 *)((UINT8 *)v->fbi.ram + (data & v->fbi.mask & ~0x0f));
+ v->fbi.auxmax = (UINT16 *)((UINT8 *)v->fbi.ram + v->fbi.mask + 1) - v->fbi.aux;
+ }
+ break;
+
+ case cmdFifoHoles:
+/* case auxBufferStride: -- Banshee */
+ if (v->type == VOODOO_2 && (chips & 1))
+ v->fbi.cmdfifo[0].holes = data;
+ else if (v->type >= VOODOO_BANSHEE && (chips & 1))
+ {
+ int rowpixels;
+
+ if (data & 0x8000)
+ rowpixels = (data & 0x7f) << 6;
+ else
+ rowpixels = (data & 0x3fff) >> 1;
+ if (v->fbi.rowpixels != rowpixels)
+ fatalerror("aux buffer stride differs from color buffer stride");
+ }
+ break;
+
+ /* nccTable entries are processed and expanded immediately */
+ case nccTable+0:
+ case nccTable+1:
+ case nccTable+2:
+ case nccTable+3:
+ case nccTable+4:
+ case nccTable+5:
+ case nccTable+6:
+ case nccTable+7:
+ case nccTable+8:
+ case nccTable+9:
+ case nccTable+10:
+ case nccTable+11:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (chips & 2) ncc_table_write(&v->tmu[0].ncc[0], regnum - nccTable, data);
+ if (chips & 4) ncc_table_write(&v->tmu[1].ncc[0], regnum - nccTable, data);
+ break;
+
+ case nccTable+12:
+ case nccTable+13:
+ case nccTable+14:
+ case nccTable+15:
+ case nccTable+16:
+ case nccTable+17:
+ case nccTable+18:
+ case nccTable+19:
+ case nccTable+20:
+ case nccTable+21:
+ case nccTable+22:
+ case nccTable+23:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (chips & 2) ncc_table_write(&v->tmu[0].ncc[1], regnum - (nccTable+12), data);
+ if (chips & 4) ncc_table_write(&v->tmu[1].ncc[1], regnum - (nccTable+12), data);
+ break;
+
+ /* fogTable entries are processed and expanded immediately */
+ case fogTable+0:
+ case fogTable+1:
+ case fogTable+2:
+ case fogTable+3:
+ case fogTable+4:
+ case fogTable+5:
+ case fogTable+6:
+ case fogTable+7:
+ case fogTable+8:
+ case fogTable+9:
+ case fogTable+10:
+ case fogTable+11:
+ case fogTable+12:
+ case fogTable+13:
+ case fogTable+14:
+ case fogTable+15:
+ case fogTable+16:
+ case fogTable+17:
+ case fogTable+18:
+ case fogTable+19:
+ case fogTable+20:
+ case fogTable+21:
+ case fogTable+22:
+ case fogTable+23:
+ case fogTable+24:
+ case fogTable+25:
+ case fogTable+26:
+ case fogTable+27:
+ case fogTable+28:
+ case fogTable+29:
+ case fogTable+30:
+ case fogTable+31:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (chips & 1)
+ {
+ int base = 2 * (regnum - fogTable);
+ v->fbi.fogdelta[base + 0] = (data >> 0) & 0xff;
+ v->fbi.fogblend[base + 0] = (data >> 8) & 0xff;
+ v->fbi.fogdelta[base + 1] = (data >> 16) & 0xff;
+ v->fbi.fogblend[base + 1] = (data >> 24) & 0xff;
+ }
+ break;
+
+ /* texture modifications cause us to recompute everything */
+ case textureMode:
+ case tLOD:
+ case tDetail:
+ case texBaseAddr:
+ case texBaseAddr_1:
+ case texBaseAddr_2:
+ case texBaseAddr_3_8:
+ poly_wait(v->poly, v->regnames[regnum]);
+ if (chips & 2)
+ {
+ v->tmu[0].reg[regnum].u = data;
+ v->tmu[0].regdirty = TRUE;
+ }
+ if (chips & 4)
+ {
+ v->tmu[1].reg[regnum].u = data;
+ v->tmu[1].regdirty = TRUE;
+ }
+ break;
+
+ /* these registers are referenced in the renderer; we must wait for pending work before changing */
+ case chromaRange:
+ case chromaKey:
+ case alphaMode:
+ case fogColor:
+ case stipple:
+ case zaColor:
+ case color1:
+ case color0:
+ case clipLowYHighY:
+ case clipLeftRight:
+ poly_wait(v->poly, v->regnames[regnum]);
+ /* fall through to default implementation */
+
+ /* by default, just feed the data to the chips */
+ default:
+ if (chips & 1) v->reg[0x000 + regnum].u = data;
+ if (chips & 2) v->reg[0x100 + regnum].u = data;
+ if (chips & 4) v->reg[0x200 + regnum].u = data;
+ if (chips & 8) v->reg[0x300 + regnum].u = data;
+ break;
+ }
+
+ if (LOG_REGISTERS)
+ {
+ if (regnum < fvertexAx || regnum > fdWdY)
+ logerror("VOODOO.%d.REG:%s(%d) write = %08X\n", v->index, (regnum < 0x384/4) ? v->regnames[regnum] : "oob", chips, origdata);
+ else
+ logerror("VOODOO.%d.REG:%s(%d) write = %f\n", v->index, (regnum < 0x384/4) ? v->regnames[regnum] : "oob", chips, u2f(origdata));
+ }
+
+ return cycles;
+}
+
+
+
+/*************************************
+ *
+ * Voodoo LFB writes
+ *
+ *************************************/
+
+static INT32 lfb_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask, int forcefront)
+{
+ UINT16 *dest, *depth;
+ UINT32 destmax, depthmax;
+ int sr[2], sg[2], sb[2], sa[2], sw[2];
+ int x, y, scry, mask;
+ int pix, destbuf;
+
+ /* statistics */
+ v->stats.lfb_writes++;
+
+ /* byte swizzling */
+ if (LFBMODE_BYTE_SWIZZLE_WRITES(v->reg[lfbMode].u))
+ {
+ data = FLIPENDIAN_INT32(data);
+ mem_mask = FLIPENDIAN_INT32(mem_mask);
+ }
+
+ /* word swapping */
+ if (LFBMODE_WORD_SWAP_WRITES(v->reg[lfbMode].u))
+ {
+ data = (data << 16) | (data >> 16);
+ mem_mask = (mem_mask << 16) | (mem_mask >> 16);
+ }
+
+ /* extract default depth and alpha values */
+ sw[0] = sw[1] = v->reg[zaColor].u & 0xffff;
+ sa[0] = sa[1] = v->reg[zaColor].u >> 24;
+
+ /* first extract A,R,G,B from the data */
+ switch (LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u) + 16 * LFBMODE_RGBA_LANES(v->reg[lfbMode].u))
+ {
+ case 16*0 + 0: /* ARGB, 16-bit RGB 5-6-5 */
+ case 16*2 + 0: /* RGBA, 16-bit RGB 5-6-5 */
+ EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]);
+ EXTRACT_565_TO_888(data >> 16, sr[1], sg[1], sb[1]);
+ mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
+ offset <<= 1;
+ break;
+ case 16*1 + 0: /* ABGR, 16-bit RGB 5-6-5 */
+ case 16*3 + 0: /* BGRA, 16-bit RGB 5-6-5 */
+ EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]);
+ EXTRACT_565_TO_888(data >> 16, sb[1], sg[1], sr[1]);
+ mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
+ offset <<= 1;
+ break;
+
+ case 16*0 + 1: /* ARGB, 16-bit RGB x-5-5-5 */
+ EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]);
+ EXTRACT_x555_TO_888(data >> 16, sr[1], sg[1], sb[1]);
+ mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
+ offset <<= 1;
+ break;
+ case 16*1 + 1: /* ABGR, 16-bit RGB x-5-5-5 */
+ EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]);
+ EXTRACT_x555_TO_888(data >> 16, sb[1], sg[1], sr[1]);
+ mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
+ offset <<= 1;
+ break;
+ case 16*2 + 1: /* RGBA, 16-bit RGB x-5-5-5 */
+ EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]);
+ EXTRACT_555x_TO_888(data >> 16, sr[1], sg[1], sb[1]);
+ mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
+ offset <<= 1;
+ break;
+ case 16*3 + 1: /* BGRA, 16-bit RGB x-5-5-5 */
+ EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]);
+ EXTRACT_555x_TO_888(data >> 16, sb[1], sg[1], sr[1]);
+ mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
+ offset <<= 1;
+ break;
+
+ case 16*0 + 2: /* ARGB, 16-bit ARGB 1-5-5-5 */
+ EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
+ EXTRACT_1555_TO_8888(data >> 16, sa[1], sr[1], sg[1], sb[1]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
+ offset <<= 1;
+ break;
+ case 16*1 + 2: /* ABGR, 16-bit ARGB 1-5-5-5 */
+ EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
+ EXTRACT_1555_TO_8888(data >> 16, sa[1], sb[1], sg[1], sr[1]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
+ offset <<= 1;
+ break;
+ case 16*2 + 2: /* RGBA, 16-bit ARGB 1-5-5-5 */
+ EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
+ EXTRACT_5551_TO_8888(data >> 16, sr[1], sg[1], sb[1], sa[1]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
+ offset <<= 1;
+ break;
+ case 16*3 + 2: /* BGRA, 16-bit ARGB 1-5-5-5 */
+ EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
+ EXTRACT_5551_TO_8888(data >> 16, sb[1], sg[1], sr[1], sa[1]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
+ offset <<= 1;
+ break;
+
+ case 16*0 + 4: /* ARGB, 32-bit RGB x-8-8-8 */
+ EXTRACT_x888_TO_888(data, sr[0], sg[0], sb[0]);
+ mask = LFB_RGB_PRESENT;
+ break;
+ case 16*1 + 4: /* ABGR, 32-bit RGB x-8-8-8 */
+ EXTRACT_x888_TO_888(data, sb[0], sg[0], sr[0]);
+ mask = LFB_RGB_PRESENT;
+ break;
+ case 16*2 + 4: /* RGBA, 32-bit RGB x-8-8-8 */
+ EXTRACT_888x_TO_888(data, sr[0], sg[0], sb[0]);
+ mask = LFB_RGB_PRESENT;
+ break;
+ case 16*3 + 4: /* BGRA, 32-bit RGB x-8-8-8 */
+ EXTRACT_888x_TO_888(data, sb[0], sg[0], sr[0]);
+ mask = LFB_RGB_PRESENT;
+ break;
+
+ case 16*0 + 5: /* ARGB, 32-bit ARGB 8-8-8-8 */
+ EXTRACT_8888_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
+ break;
+ case 16*1 + 5: /* ABGR, 32-bit ARGB 8-8-8-8 */
+ EXTRACT_8888_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
+ break;
+ case 16*2 + 5: /* RGBA, 32-bit ARGB 8-8-8-8 */
+ EXTRACT_8888_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
+ break;
+ case 16*3 + 5: /* BGRA, 32-bit ARGB 8-8-8-8 */
+ EXTRACT_8888_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
+ break;
+
+ case 16*0 + 12: /* ARGB, 32-bit depth+RGB 5-6-5 */
+ case 16*2 + 12: /* RGBA, 32-bit depth+RGB 5-6-5 */
+ sw[0] = data >> 16;
+ EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]);
+ mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+ case 16*1 + 12: /* ABGR, 32-bit depth+RGB 5-6-5 */
+ case 16*3 + 12: /* BGRA, 32-bit depth+RGB 5-6-5 */
+ sw[0] = data >> 16;
+ EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]);
+ mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+
+ case 16*0 + 13: /* ARGB, 32-bit depth+RGB x-5-5-5 */
+ sw[0] = data >> 16;
+ EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]);
+ mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+ case 16*1 + 13: /* ABGR, 32-bit depth+RGB x-5-5-5 */
+ sw[0] = data >> 16;
+ EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]);
+ mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+ case 16*2 + 13: /* RGBA, 32-bit depth+RGB x-5-5-5 */
+ sw[0] = data >> 16;
+ EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]);
+ mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+ case 16*3 + 13: /* BGRA, 32-bit depth+RGB x-5-5-5 */
+ sw[0] = data >> 16;
+ EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]);
+ mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+
+ case 16*0 + 14: /* ARGB, 32-bit depth+ARGB 1-5-5-5 */
+ sw[0] = data >> 16;
+ EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+ case 16*1 + 14: /* ABGR, 32-bit depth+ARGB 1-5-5-5 */
+ sw[0] = data >> 16;
+ EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+ case 16*2 + 14: /* RGBA, 32-bit depth+ARGB 1-5-5-5 */
+ sw[0] = data >> 16;
+ EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+ case 16*3 + 14: /* BGRA, 32-bit depth+ARGB 1-5-5-5 */
+ sw[0] = data >> 16;
+ EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
+ mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
+ break;
+
+ case 16*0 + 15: /* ARGB, 16-bit depth */
+ case 16*1 + 15: /* ARGB, 16-bit depth */
+ case 16*2 + 15: /* ARGB, 16-bit depth */
+ case 16*3 + 15: /* ARGB, 16-bit depth */
+ sw[0] = data & 0xffff;
+ sw[1] = data >> 16;
+ mask = LFB_DEPTH_PRESENT | (LFB_DEPTH_PRESENT << 4);
+ offset <<= 1;
+ break;
+
+ default: /* reserved */
+ return 0;
+ }
+
+ /* compute X,Y */
+ x = (offset << 0) & ((1 << v->fbi.lfb_stride) - 1);
+ y = (offset >> v->fbi.lfb_stride) & ((1 << v->fbi.lfb_stride) - 1);
+
+ /* adjust the mask based on which half of the data is written */
+ if ((mem_mask & 0x0000ffff) == 0x0000ffff)
+ mask &= ~(0x0f - LFB_DEPTH_PRESENT_MSW);
+ if ((mem_mask & 0xffff0000) == 0xffff0000)
+ mask &= ~(0xf0 + LFB_DEPTH_PRESENT_MSW);
+
+ /* select the target buffer */
+ destbuf = (v->type >= VOODOO_BANSHEE) ? (!forcefront) : LFBMODE_WRITE_BUFFER_SELECT(v->reg[lfbMode].u);
+ switch (destbuf)
+ {
+ case 0: /* front buffer */
+ dest = v->fbi.rgb[v->fbi.frontbuf];
+ destmax = v->fbi.rgbmax[v->fbi.frontbuf];
+ v->fbi.video_changed = TRUE;
+ break;
+
+ case 1: /* back buffer */
+ dest = v->fbi.rgb[v->fbi.backbuf];
+ destmax = v->fbi.rgbmax[v->fbi.backbuf];
+ break;
+
+ default: /* reserved */
+ return 0;
+ }
+ depth = v->fbi.aux;
+ depthmax = v->fbi.auxmax;
+
+ /* wait for any outstanding work to finish */
+ poly_wait(v->poly, "LFB Write");
+
+ /* simple case: no pipeline */
+ if (!LFBMODE_ENABLE_PIXEL_PIPELINE(v->reg[lfbMode].u))
+ {
+ DECLARE_DITHER_POINTERS;
+ UINT32 bufoffs;
+
+ if (LOG_LFB) logerror("VOODOO.%d.LFB:write raw mode %X (%d,%d) = %08X & %08X\n", v->index, LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u), x, y, data, mem_mask);
+
+ /* determine the screen Y */
+ scry = y;
+ if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u))
+ scry = (v->fbi.yorigin - y) & 0x3ff;
+
+ /* advance pointers to the proper row */
+ bufoffs = scry * v->fbi.rowpixels + x;
+
+ /* compute dithering */
+ COMPUTE_DITHER_POINTERS(v->reg[fbzMode].u, y);
+
+ /* loop over up to two pixels */
+ for (pix = 0; mask; pix++)
+ {
+ /* make sure we care about this pixel */
+ if (mask & 0x0f)
+ {
+ /* write to the RGB buffer */
+ if ((mask & LFB_RGB_PRESENT) && bufoffs < destmax)
+ {
+ /* apply dithering and write to the screen */
+ APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, sr[pix], sg[pix], sb[pix]);
+ dest[bufoffs] = (sr[pix] << 11) | (sg[pix] << 5) | sb[pix];
+ }
+
+ /* make sure we have an aux buffer to write to */
+ if (depth && bufoffs < depthmax)
+ {
+ /* write to the alpha buffer */
+ if ((mask & LFB_ALPHA_PRESENT) && FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u))
+ depth[bufoffs] = sa[pix];
+
+ /* write to the depth buffer */
+ if ((mask & (LFB_DEPTH_PRESENT | LFB_DEPTH_PRESENT_MSW)) && !FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u))
+ depth[bufoffs] = sw[pix];
+ }
+
+ /* track pixel writes to the frame buffer regardless of mask */
+ v->reg[fbiPixelsOut].u++;
+ }
+
+ /* advance our pointers */
+ bufoffs++;
+ x++;
+ mask >>= 4;
+ }
+ }
+
+ /* tricky case: run the full pixel pipeline on the pixel */
+ else
+ {
+ DECLARE_DITHER_POINTERS;
+
+ if (LOG_LFB) logerror("VOODOO.%d.LFB:write pipelined mode %X (%d,%d) = %08X & %08X\n", v->index, LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u), x, y, data, mem_mask);
+
+ /* determine the screen Y */
+ scry = y;
+ if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
+ scry = (v->fbi.yorigin - y) & 0x3ff;
+
+ /* advance pointers to the proper row */
+ dest += scry * v->fbi.rowpixels;
+ if (depth)
+ depth += scry * v->fbi.rowpixels;
+
+ /* compute dithering */
+ COMPUTE_DITHER_POINTERS(v->reg[fbzMode].u, y);
+
+ /* loop over up to two pixels */
+ for (pix = 0; mask; pix++)
+ {
+ /* make sure we care about this pixel */
+ if (mask & 0x0f)
+ {
+ stats_block *stats = &v->fbi.lfb_stats;
+ INT64 iterw = sw[pix] << (30-16);
+ INT32 iterz = sw[pix] << 12;
+ rgb_union color;
+
+ /* apply clipping */
+ if (FBZMODE_ENABLE_CLIPPING(v->reg[fbzMode].u))
+ {
+ if (x < ((v->reg[clipLeftRight].u >> 16) & 0x3ff) ||
+ x >= (v->reg[clipLeftRight].u & 0x3ff) ||
+ scry < ((v->reg[clipLowYHighY].u >> 16) & 0x3ff) ||
+ scry >= (v->reg[clipLowYHighY].u & 0x3ff))
+ {
+ stats->pixels_in++;
+ stats->clip_fail++;
+ continue;
+ }
+ }
+
+ /* pixel pipeline part 1 handles depth testing and stippling */
+ PIXEL_PIPELINE_BEGIN(v, stats, x, y, v->reg[fbzColorPath].u, v->reg[fbzMode].u, iterz, iterw);
+
+ /* use the RGBA we stashed above */
+ color.rgb.r = r = sr[pix];
+ color.rgb.g = g = sg[pix];
+ color.rgb.b = b = sb[pix];
+ color.rgb.a = a = sa[pix];
+
+ /* apply chroma key, alpha mask, and alpha testing */
+ APPLY_CHROMAKEY(v, stats, v->reg[fbzMode].u, color);
+ APPLY_ALPHAMASK(v, stats, v->reg[fbzMode].u, color.rgb.a);
+ APPLY_ALPHATEST(v, stats, v->reg[alphaMode].u, color.rgb.a);
+
+ /* pixel pipeline part 2 handles color combine, fog, alpha, and final output */
+ PIXEL_PIPELINE_END(v, stats, dither, dither4, dither_lookup, x, dest, depth, v->reg[fbzMode].u, v->reg[fbzColorPath].u, v->reg[alphaMode].u, v->reg[fogMode].u, iterz, iterw, v->reg[zaColor]);
+ }
+
+ /* advance our pointers */
+ x++;
+ mask >>= 4;
+ }
+ }
+
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Voodoo texture RAM writes
+ *
+ *************************************/
+
+static INT32 texture_w(voodoo_state *v, offs_t offset, UINT32 data)
+{
+ int tmunum = (offset >> 19) & 0x03;
+ tmu_state *t;
+
+ /* statistics */
+ v->stats.tex_writes++;
+
+ /* point to the right TMU */
+ if (!(v->chipmask & (2 << tmunum)))
+ return 0;
+ t = &v->tmu[tmunum];
+
+ if (TEXLOD_TDIRECT_WRITE(t->reg[tLOD].u))
+ fatalerror("Texture direct write!");
+
+ /* wait for any outstanding work to finish */
+ poly_wait(v->poly, "Texture write");
+
+ /* update texture info if dirty */
+ if (t->regdirty)
+ recompute_texture_params(t);
+
+ /* swizzle the data */
+ if (TEXLOD_TDATA_SWIZZLE(t->reg[tLOD].u))
+ data = FLIPENDIAN_INT32(data);
+ if (TEXLOD_TDATA_SWAP(t->reg[tLOD].u))
+ data = (data >> 16) | (data << 16);
+
+ /* 8-bit texture case */
+ if (TEXMODE_FORMAT(t->reg[textureMode].u) < 8)
+ {
+ int lod, tt, ts;
+ UINT32 tbaseaddr;
+ UINT8 *dest;
+
+ /* extract info */
+ if (v->type <= VOODOO_2)
+ {
+ lod = (offset >> 15) & 0x0f;
+ tt = (offset >> 7) & 0xff;
+
+ /* old code has a bit about how this is broken in gauntleg unless we always look at TMU0 */
+ if (TEXMODE_SEQ_8_DOWNLD(v->tmu[0].reg/*t->reg*/[textureMode].u))
+ ts = (offset << 2) & 0xfc;
+ else
+ ts = (offset << 1) & 0xfc;
+
+ /* validate parameters */
+ if (lod > 8)
+ return 0;
+
+ /* compute the base address */
+ tbaseaddr = t->lodoffset[lod];
+ tbaseaddr += tt * ((t->wmask >> lod) + 1) + ts;
+
+ if (LOG_TEXTURE_RAM) logerror("Texture 8-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data);
+ }
+ else
+ {
+ tbaseaddr = t->lodoffset[0] + offset*4;
+
+ if (LOG_TEXTURE_RAM) logerror("Texture 16-bit w: offset=%X data=%08X\n", offset*4, data);
+ }
+
+ /* write the four bytes in little-endian order */
+ dest = t->ram;
+ tbaseaddr &= t->mask;
+ dest[BYTE4_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xff;
+ dest[BYTE4_XOR_LE(tbaseaddr + 1)] = (data >> 8) & 0xff;
+ dest[BYTE4_XOR_LE(tbaseaddr + 2)] = (data >> 16) & 0xff;
+ dest[BYTE4_XOR_LE(tbaseaddr + 3)] = (data >> 24) & 0xff;
+ }
+
+ /* 16-bit texture case */
+ else
+ {
+ int lod, tt, ts;
+ UINT32 tbaseaddr;
+ UINT16 *dest;
+
+ /* extract info */
+ if (v->type <= VOODOO_2)
+ {
+ tmunum = (offset >> 19) & 0x03;
+ lod = (offset >> 15) & 0x0f;
+ tt = (offset >> 7) & 0xff;
+ ts = (offset << 1) & 0xfe;
+
+ /* validate parameters */
+ if (lod > 8)
+ return 0;
+
+ /* compute the base address */
+ tbaseaddr = t->lodoffset[lod];
+ tbaseaddr += 2 * (tt * ((t->wmask >> lod) + 1) + ts);
+
+ if (LOG_TEXTURE_RAM) logerror("Texture 16-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data);
+ }
+ else
+ {
+ tbaseaddr = t->lodoffset[0] + offset*4;
+
+ if (LOG_TEXTURE_RAM) logerror("Texture 16-bit w: offset=%X data=%08X\n", offset*4, data);
+ }
+
+ /* write the two words in little-endian order */
+ dest = (UINT16 *)t->ram;
+ tbaseaddr &= t->mask;
+ tbaseaddr >>= 1;
+ dest[BYTE_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xffff;
+ dest[BYTE_XOR_LE(tbaseaddr + 1)] = (data >> 16) & 0xffff;
+ }
+
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Flush data from the FIFOs
+ *
+ *************************************/
+
+static void flush_fifos(voodoo_state *v, attotime current_time)
+{
+ static UINT8 in_flush;
+
+ /* check for recursive calls */
+ if (in_flush)
+ return;
+ in_flush = TRUE;
+
+ if (!v->pci.op_pending) fatalerror("flush_fifos called with no pending operation");
+
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos start -- pending=%d.%08X%08X cur=%d.%08X%08X\n", v->index,
+ v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds,
+ current_time.seconds, (UINT32)(current_time.attoseconds >> 32), (UINT32)current_time.attoseconds);
+
+ /* loop while we still have cycles to burn */
+ while (attotime_compare(v->pci.op_end_time, current_time) <= 0)
+ {
+ INT32 extra_cycles = 0;
+ INT32 cycles;
+
+ /* loop over 0-cycle stuff; this constitutes the bulk of our writes */
+ do
+ {
+ fifo_state *fifo;
+ UINT32 address;
+ UINT32 data;
+
+ /* we might be in CMDFIFO mode */
+ if (v->fbi.cmdfifo[0].enable)
+ {
+ /* if we don't have anything to execute, we're done for now */
+ cycles = cmdfifo_execute_if_ready(v, &v->fbi.cmdfifo[0]);
+ if (cycles == -1)
+ {
+ v->pci.op_pending = FALSE;
+ in_flush = FALSE;
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- CMDFIFO empty\n", v->index);
+ return;
+ }
+ }
+ else if (v->fbi.cmdfifo[1].enable)
+ {
+ /* if we don't have anything to execute, we're done for now */
+ cycles = cmdfifo_execute_if_ready(v, &v->fbi.cmdfifo[1]);
+ if (cycles == -1)
+ {
+ v->pci.op_pending = FALSE;
+ in_flush = FALSE;
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- CMDFIFO empty\n", v->index);
+ return;
+ }
+ }
+
+ /* else we are in standard PCI/memory FIFO mode */
+ else
+ {
+ /* choose which FIFO to read from */
+ if (!fifo_empty(&v->fbi.fifo))
+ fifo = &v->fbi.fifo;
+ else if (!fifo_empty(&v->pci.fifo))
+ fifo = &v->pci.fifo;
+ else
+ {
+ v->pci.op_pending = FALSE;
+ in_flush = FALSE;
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- FIFOs empty\n", v->index);
+ return;
+ }
+
+ /* extract address and data */
+ address = fifo_remove(fifo);
+ data = fifo_remove(fifo);
+
+ /* target the appropriate location */
+ if ((address & (0xc00000/4)) == 0)
+ cycles = register_w(v, address, data);
+ else if (address & (0x800000/4))
+ cycles = texture_w(v, address, data);
+ else
+ {
+ UINT32 mem_mask = 0;
+
+ /* compute mem_mask */
+ if (address & 0x80000000)
+ mem_mask |= 0xffff0000;
+ if (address & 0x40000000)
+ mem_mask |= 0x0000ffff;
+ address &= 0xffffff;
+
+ cycles = lfb_w(v, address, data, mem_mask, FALSE);
+ }
+ }
+
+ /* accumulate smaller operations */
+ if (cycles < ACCUMULATE_THRESHOLD)
+ {
+ extra_cycles += cycles;
+ cycles = 0;
+ }
+ }
+ while (cycles == 0);
+
+ /* account for extra cycles */
+ cycles += extra_cycles;
+
+ /* account for those cycles */
+ v->pci.op_end_time = attotime_add_attoseconds(v->pci.op_end_time, (attoseconds_t)cycles * v->attoseconds_per_cycle);
+
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:update -- pending=%d.%08X%08X cur=%d.%08X%08X\n", v->index,
+ v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds,
+ current_time.seconds, (UINT32)(current_time.attoseconds >> 32), (UINT32)current_time.attoseconds);
+ }
+
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- pending command complete at %d.%08X%08X\n", v->index,
+ v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds);
+
+ in_flush = FALSE;
+}
+
+
+
+/*************************************
+ *
+ * Handle a write to the Voodoo
+ * memory space
+ *
+ *************************************/
+
+static void voodoo_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ int stall = FALSE;
+
+ profiler_mark(PROFILER_USER1);
+
+ /* should not be getting accesses while stalled */
+ if (v->pci.stall_state != NOT_STALLED)
+ logerror("voodoo_w while stalled!\n");
+
+ /* if we have something pending, flush the FIFOs up to the current time */
+ if (v->pci.op_pending)
+ flush_fifos(v, timer_get_time());
+
+ /* special handling for registers */
+ if ((offset & 0xc00000/4) == 0)
+ {
+ UINT8 access;
+
+ /* some special stuff for Voodoo 2 */
+ if (v->type >= VOODOO_2)
+ {
+ /* we might be in CMDFIFO mode */
+ if (FBIINIT7_CMDFIFO_ENABLE(v->reg[fbiInit7].u))
+ {
+ /* if bit 21 is set, we're writing to the FIFO */
+ if (offset & 0x200000/4)
+ {
+ /* check for byte swizzling (bit 18) */
+ if (offset & 0x40000/4)
+ data = FLIPENDIAN_INT32(data);
+ cmdfifo_w(v, &v->fbi.cmdfifo[0], offset & 0xffff, data);
+ profiler_mark(PROFILER_END);
+ return;
+ }
+
+ /* we're a register access; but only certain ones are allowed */
+ access = v->regaccess[offset & 0xff];
+ if (!(access & REGISTER_WRITETHRU))
+ {
+ /* track swap buffers regardless */
+ if ((offset & 0xff) == swapbufferCMD)
+ v->fbi.swaps_pending++;
+
+ logerror("Ignoring write to %s in CMDFIFO mode\n", v->regnames[offset & 0xff]);
+ profiler_mark(PROFILER_END);
+ return;
+ }
+ }
+
+ /* if not, we might be byte swizzled (bit 20) */
+ else if (offset & 0x100000/4)
+ data = FLIPENDIAN_INT32(data);
+ }
+
+ /* check the access behavior; note that the table works even if the */
+ /* alternate mapping is used */
+ access = v->regaccess[offset & 0xff];
+
+ /* ignore if writes aren't allowed */
+ if (!(access & REGISTER_WRITE))
+ {
+ profiler_mark(PROFILER_END);
+ return;
+ }
+
+ /* if this is a non-FIFO command, let it go to the FIFO, but stall until it completes */
+ if (!(access & REGISTER_FIFO))
+ stall = TRUE;
+
+ /* track swap buffers */
+ if ((offset & 0xff) == swapbufferCMD)
+ v->fbi.swaps_pending++;
+ }
+
+ /* if we don't have anything pending, or if FIFOs are disabled, just execute */
+ if (!v->pci.op_pending || !INITEN_ENABLE_PCI_FIFO(v->pci.init_enable))
+ {
+ int cycles;
+
+ /* target the appropriate location */
+ if ((offset & (0xc00000/4)) == 0)
+ cycles = register_w(v, offset, data);
+ else if (offset & (0x800000/4))
+ cycles = texture_w(v, offset, data);
+ else
+ cycles = lfb_w(v, offset, data, mem_mask, FALSE);
+
+ /* if we ended up with cycles, mark the operation pending */
+ if (cycles)
+ {
+ v->pci.op_pending = TRUE;
+ v->pci.op_end_time = attotime_add_attoseconds(timer_get_time(), (attoseconds_t)cycles * v->attoseconds_per_cycle);
+
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:direct write start at %d.%08X%08X end at %d.%08X%08X\n", v->index,
+ timer_get_time().seconds, (UINT32)(timer_get_time().attoseconds >> 32), (UINT32)timer_get_time().attoseconds,
+ v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds);
+ }
+ profiler_mark(PROFILER_END);
+ return;
+ }
+
+ /* modify the offset based on the mem_mask */
+ if (mem_mask)
+ {
+ if (mem_mask & 0xffff0000)
+ offset |= 0x80000000;
+ if (mem_mask & 0x0000ffff)
+ offset |= 0x40000000;
+ }
+
+ /* if there's room in the PCI FIFO, add there */
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w adding to PCI FIFO @ %08X=%08X\n", v->index, offset, data);
+ if (!fifo_full(&v->pci.fifo))
+ {
+ fifo_add(&v->pci.fifo, offset);
+ fifo_add(&v->pci.fifo, data);
+ }
+ else
+ fatalerror("PCI FIFO full");
+
+ /* handle flushing to the memory FIFO */
+ if (FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u) &&
+ fifo_space(&v->pci.fifo) <= 2 * FBIINIT4_MEMORY_FIFO_LWM(v->reg[fbiInit4].u))
+ {
+ UINT8 valid[4];
+
+ /* determine which types of data can go to the memory FIFO */
+ valid[0] = TRUE;
+ valid[1] = FBIINIT0_LFB_TO_MEMORY_FIFO(v->reg[fbiInit0].u);
+ valid[2] = valid[3] = FBIINIT0_TEXMEM_TO_MEMORY_FIFO(v->reg[fbiInit0].u);
+
+ /* flush everything we can */
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w moving PCI FIFO to memory FIFO\n", v->index);
+ while (!fifo_empty(&v->pci.fifo) && valid[(fifo_peek(&v->pci.fifo) >> 22) & 3])
+ {
+ fifo_add(&v->fbi.fifo, fifo_remove(&v->pci.fifo));
+ fifo_add(&v->fbi.fifo, fifo_remove(&v->pci.fifo));
+ }
+
+ /* if we're above the HWM as a result, stall */
+ if (FBIINIT0_STALL_PCIE_FOR_HWM(v->reg[fbiInit0].u) &&
+ fifo_items(&v->fbi.fifo) >= 2 * 32 * FBIINIT0_MEMORY_FIFO_HWM(v->reg[fbiInit0].u))
+ {
+ if (LOG_FIFO) logerror("VOODOO.%d.FIFO:voodoo_w hit memory FIFO HWM -- stalling\n", v->index);
+ stall_cpu(v, STALLED_UNTIL_FIFO_LWM, timer_get_time());
+ }
+ }
+
+ /* if we're at the LWM for the PCI FIFO, stall */
+ if (FBIINIT0_STALL_PCIE_FOR_HWM(v->reg[fbiInit0].u) &&
+ fifo_space(&v->pci.fifo) <= 2 * FBIINIT0_PCI_FIFO_LWM(v->reg[fbiInit0].u))
+ {
+ if (LOG_FIFO) logerror("VOODOO.%d.FIFO:voodoo_w hit PCI FIFO free LWM -- stalling\n", v->index);
+ stall_cpu(v, STALLED_UNTIL_FIFO_LWM, timer_get_time());
+ }
+
+ /* if we weren't ready, and this is a non-FIFO access, stall until the FIFOs are clear */
+ if (stall)
+ {
+ if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w wrote non-FIFO register -- stalling until clear\n", v->index);
+ stall_cpu(v, STALLED_UNTIL_FIFO_EMPTY, timer_get_time());
+ }
+
+ profiler_mark(PROFILER_END);
+}
+
+
+
+/*************************************
+ *
+ * Handle a register read
+ *
+ *************************************/
+
+static UINT32 register_r(voodoo_state *v, offs_t offset)
+{
+ int regnum = offset & 0xff;
+ UINT32 result;
+
+ /* statistics */
+ v->stats.reg_reads++;
+
+ /* first make sure this register is readable */
+ if (!(v->regaccess[regnum] & REGISTER_READ))
+ {
+ logerror("VOODOO.%d.ERROR:Invalid attempt to read %s\n", v->index, v->regnames[regnum]);
+ return 0xffffffff;
+ }
+
+ /* default result is the FBI register value */
+ result = v->reg[regnum].u;
+
+ /* some registers are dynamic; compute them */
+ switch (regnum)
+ {
+ case status:
+
+ /* start with a blank slate */
+ result = 0;
+
+ /* bits 5:0 are the PCI FIFO free space */
+ if (fifo_empty(&v->pci.fifo))
+ result |= 0x3f << 0;
+ else
+ {
+ int temp = fifo_space(&v->pci.fifo)/2;
+ if (temp > 0x3f)
+ temp = 0x3f;
+ result |= temp << 0;
+ }
+
+ /* bit 6 is the vertical retrace */
+ result |= v->fbi.vblank << 6;
+
+ /* bit 7 is FBI graphics engine busy */
+ if (v->pci.op_pending)
+ result |= 1 << 7;
+
+ /* bit 8 is TREX busy */
+ if (v->pci.op_pending)
+ result |= 1 << 8;
+
+ /* bit 9 is overall busy */
+ if (v->pci.op_pending)
+ result |= 1 << 9;
+
+ /* Banshee is different starting here */
+ if (v->type < VOODOO_BANSHEE)
+ {
+ /* bits 11:10 specifies which buffer is visible */
+ result |= v->fbi.frontbuf << 10;
+
+ /* bits 27:12 indicate memory FIFO freespace */
+ if (!FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u) || fifo_empty(&v->fbi.fifo))
+ result |= 0xffff << 12;
+ else
+ {
+ int temp = fifo_space(&v->fbi.fifo)/2;
+ if (temp > 0xffff)
+ temp = 0xffff;
+ result |= temp << 12;
+ }
+ }
+ else
+ {
+ /* bit 10 is 2D busy */
+
+ /* bit 11 is cmd FIFO 0 busy */
+ if (v->fbi.cmdfifo[0].enable && v->fbi.cmdfifo[0].depth > 0)
+ result |= 1 << 11;
+
+ /* bit 12 is cmd FIFO 1 busy */
+ if (v->fbi.cmdfifo[1].enable && v->fbi.cmdfifo[1].depth > 0)
+ result |= 1 << 12;
+ }
+
+ /* bits 30:28 are the number of pending swaps */
+ if (v->fbi.swaps_pending > 7)
+ result |= 7 << 28;
+ else
+ result |= v->fbi.swaps_pending << 28;
+
+ /* bit 31 is not used */
+
+ /* eat some cycles since people like polling here */
+ activecpu_eat_cycles(1000);
+ break;
+
+ /* bit 2 of the initEnable register maps this to dacRead */
+ case fbiInit2:
+ if (INITEN_REMAP_INIT_TO_DAC(v->pci.init_enable))
+ result = v->dac.read_result;
+ break;
+
+ /* return the current scanline for now */
+ case vRetrace:
+ result = video_screen_get_vpos(v->scrnum);
+ break;
+
+ /* reserved area in the TMU read by the Vegas startup sequence */
+ case hvRetrace:
+ result = 0x200 << 16; /* should be between 0x7b and 0x267 */
+ result |= 0x80; /* should be between 0x17 and 0x103 */
+ break;
+
+ /* cmdFifo -- Voodoo2 only */
+ case cmdFifoRdPtr:
+ result = v->fbi.cmdfifo[0].rdptr;
+
+ /* eat some cycles since people like polling here */
+ activecpu_eat_cycles(1000);
+ break;
+
+ case cmdFifoAMin:
+ result = v->fbi.cmdfifo[0].amin;
+ break;
+
+ case cmdFifoAMax:
+ result = v->fbi.cmdfifo[0].amax;
+ break;
+
+ case cmdFifoDepth:
+ result = v->fbi.cmdfifo[0].depth;
+ break;
+
+ case cmdFifoHoles:
+ result = v->fbi.cmdfifo[0].holes;
+ break;
+
+ /* all counters are 24-bit only */
+ case fbiPixelsIn:
+ case fbiChromaFail:
+ case fbiZfuncFail:
+ case fbiAfuncFail:
+ case fbiPixelsOut:
+ update_statistics(v, TRUE);
+ case fbiTrianglesOut:
+ result = v->reg[regnum].u & 0xffffff;
+ break;
+ }
+
+ if (LOG_REGISTERS)
+ {
+ int logit = TRUE;
+
+ /* don't log multiple identical status reads from the same address */
+ if (regnum == status)
+ {
+ offs_t pc = activecpu_get_pc();
+ if (pc == v->last_status_pc && result == v->last_status_value)
+ logit = FALSE;
+ v->last_status_pc = pc;
+ v->last_status_value = result;
+ }
+ if (regnum == cmdFifoRdPtr)
+ logit = FALSE;
+
+ if (logit)
+ logerror("VOODOO.%d.REG:%s read = %08X\n", v->index, v->regnames[regnum], result);
+ }
+
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Handle an LFB read
+ *
+ *************************************/
+
+static UINT32 lfb_r(voodoo_state *v, offs_t offset, int forcefront)
+{
+ UINT16 *buffer;
+ UINT32 bufmax;
+ UINT32 bufoffs;
+ UINT32 data;
+ int x, y, scry, destbuf;
+
+ /* statistics */
+ v->stats.lfb_reads++;
+
+ /* compute X,Y */
+ x = (offset << 1) & 0x3fe;
+ y = (offset >> 9) & 0x3ff;
+
+ /* select the target buffer */
+ destbuf = (v->type >= VOODOO_BANSHEE) ? (!forcefront) : LFBMODE_READ_BUFFER_SELECT(v->reg[lfbMode].u);
+ switch (destbuf)
+ {
+ case 0: /* front buffer */
+ buffer = v->fbi.rgb[v->fbi.frontbuf];
+ bufmax = v->fbi.rgbmax[v->fbi.frontbuf];
+ break;
+
+ case 1: /* back buffer */
+ buffer = v->fbi.rgb[v->fbi.backbuf];
+ bufmax = v->fbi.rgbmax[v->fbi.backbuf];
+ break;
+
+ case 2: /* aux buffer */
+ buffer = v->fbi.aux;
+ bufmax = v->fbi.auxmax;
+ if (!buffer)
+ return 0xffffffff;
+ break;
+
+ default: /* reserved */
+ return 0xffffffff;
+ }
+
+ /* determine the screen Y */
+ scry = y;
+ if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u))
+ scry = (v->fbi.yorigin - y) & 0x3ff;
+
+ /* advance pointers to the proper row */
+ bufoffs = scry * v->fbi.rowpixels + x;
+ if (bufoffs >= bufmax)
+ return 0xffffffff;
+
+ /* wait for any outstanding work to finish */
+ poly_wait(v->poly, "LFB read");
+
+ /* compute the data */
+ data = buffer[bufoffs + 0] | (buffer[bufoffs + 1] << 16);
+
+ /* word swapping */
+ if (LFBMODE_WORD_SWAP_READS(v->reg[lfbMode].u))
+ data = (data << 16) | (data >> 16);
+
+ /* byte swizzling */
+ if (LFBMODE_BYTE_SWIZZLE_READS(v->reg[lfbMode].u))
+ data = FLIPENDIAN_INT32(data);
+
+ if (LOG_LFB) logerror("VOODOO.%d.LFB:read (%d,%d) = %08X\n", v->index, x, y, data);
+ return data;
+}
+
+
+
+/*************************************
+ *
+ * Handle a read from the Voodoo
+ * memory space
+ *
+ *************************************/
+
+static UINT32 voodoo_r(voodoo_state *v, offs_t offset)
+{
+ /* if we have something pending, flush the FIFOs up to the current time */
+ if (v->pci.op_pending)
+ flush_fifos(v, timer_get_time());
+
+ /* target the appropriate location */
+ if (!(offset & (0xc00000/4)))
+ return register_r(v, offset);
+ else if (!(offset & (0x800000/4)))
+ return lfb_r(v, offset, FALSE);
+
+ return 0xffffffff;
+}
+
+
+
+/*************************************
+ *
+ * Handle a read from the Banshee
+ * I/O space
+ *
+ *************************************/
+
+static UINT32 banshee_agp_r(voodoo_state *v, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result;
+
+ offset &= 0x1ff/4;
+
+ /* switch off the offset */
+ switch (offset)
+ {
+ case cmdRdPtrL0:
+ result = v->fbi.cmdfifo[0].rdptr;
+ break;
+
+ case cmdAMin0:
+ result = v->fbi.cmdfifo[0].amin;
+ break;
+
+ case cmdAMax0:
+ result = v->fbi.cmdfifo[0].amax;
+ break;
+
+ case cmdFifoDepth0:
+ result = v->fbi.cmdfifo[0].depth;
+ break;
+
+ case cmdHoleCnt0:
+ result = v->fbi.cmdfifo[0].holes;
+ break;
+
+ case cmdRdPtrL1:
+ result = v->fbi.cmdfifo[1].rdptr;
+ break;
+
+ case cmdAMin1:
+ result = v->fbi.cmdfifo[1].amin;
+ break;
+
+ case cmdAMax1:
+ result = v->fbi.cmdfifo[1].amax;
+ break;
+
+ case cmdFifoDepth1:
+ result = v->fbi.cmdfifo[1].depth;
+ break;
+
+ case cmdHoleCnt1:
+ result = v->fbi.cmdfifo[1].holes;
+ break;
+
+ default:
+ result = v->banshee.agp[offset];
+ break;
+ }
+
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_r(AGP:%s)\n", activecpu_get_pc(), banshee_agp_reg_name[offset]);
+ return result;
+}
+
+
+static UINT32 banshee_r(voodoo_state *v, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result = 0xffffffff;
+
+ /* if we have something pending, flush the FIFOs up to the current time */
+ if (v->pci.op_pending)
+ flush_fifos(v, timer_get_time());
+
+ if (offset < 0x80000/4)
+ result = banshee_io_r(v, offset, mem_mask);
+ else if (offset < 0x100000/4)
+ result = banshee_agp_r(v, offset, mem_mask);
+ else if (offset < 0x200000/4)
+ logerror("%08X:banshee_r(2D:%X)\n", activecpu_get_pc(), (offset*4) & 0xfffff);
+ else if (offset < 0x600000/4)
+ result = register_r(v, offset & 0x1fffff/4);
+ else if (offset < 0x800000/4)
+ logerror("%08X:banshee_r(TEX:%X)\n", activecpu_get_pc(), (offset*4) & 0x1fffff);
+ else if (offset < 0xc00000/4)
+ logerror("%08X:banshee_r(RES:%X)\n", activecpu_get_pc(), (offset*4) & 0x3fffff);
+ else if (offset < 0x1000000/4)
+ logerror("%08X:banshee_r(YUV:%X)\n", activecpu_get_pc(), (offset*4) & 0x3fffff);
+ else if (offset < 0x2000000/4)
+ {
+ UINT8 temp = v->fbi.lfb_stride;
+ v->fbi.lfb_stride = 11;
+ result = lfb_r(v, offset & 0xffffff/4, FALSE);
+ v->fbi.lfb_stride = temp;
+ }
+ return result;
+}
+
+
+static UINT32 banshee_fb_r(voodoo_state *v, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result = 0xffffffff;
+
+ /* if we have something pending, flush the FIFOs up to the current time */
+ if (v->pci.op_pending)
+ flush_fifos(v, timer_get_time());
+
+ if (offset < v->fbi.lfb_base)
+ {
+ logerror("%08X:banshee_fb_r(%X)\n", activecpu_get_pc(), offset*4);
+ if (offset*4 <= v->fbi.mask)
+ result = ((UINT32 *)v->fbi.ram)[offset];
+ }
+ else
+ result = lfb_r(v, offset - v->fbi.lfb_base, FALSE);
+ return result;
+}
+
+
+static UINT8 banshee_vga_r(voodoo_state *v, offs_t offset)
+{
+ UINT8 result = 0xff;
+
+ offset &= 0x1f;
+
+ /* switch off the offset */
+ switch (offset + 0x3c0)
+ {
+ /* attribute access */
+ case 0x3c0:
+ if (v->banshee.vga[0x3c1 & 0x1f] < ARRAY_LENGTH(v->banshee.att))
+ result = v->banshee.att[v->banshee.vga[0x3c1 & 0x1f]];
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_att_r(%X)\n", activecpu_get_pc(), v->banshee.vga[0x3c1 & 0x1f]);
+ break;
+
+ /* Input status 0 */
+ case 0x3c2:
+ /*
+ bit 7 = Interrupt Status. When its value is ?1?, denotes that an interrupt is pending.
+ bit 6:5 = Feature Connector. These 2 bits are readable bits from the feature connector.
+ bit 4 = Sense. This bit reflects the state of the DAC monitor sense logic.
+ bit 3:0 = Reserved. Read back as 0.
+ */
+ result = 0x00;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_vga_r(%X)\n", activecpu_get_pc(), 0x300+offset);
+ break;
+
+ /* Sequencer access */
+ case 0x3c5:
+ if (v->banshee.vga[0x3c4 & 0x1f] < ARRAY_LENGTH(v->banshee.seq))
+ result = v->banshee.seq[v->banshee.vga[0x3c4 & 0x1f]];
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_seq_r(%X)\n", activecpu_get_pc(), v->banshee.vga[0x3c4 & 0x1f]);
+ break;
+
+ /* Feature control */
+ case 0x3ca:
+ result = v->banshee.vga[0x3da & 0x1f];
+ v->banshee.attff = 0;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_vga_r(%X)\n", activecpu_get_pc(), 0x300+offset);
+ break;
+
+ /* Miscellaneous output */
+ case 0x3cc:
+ result = v->banshee.vga[0x3c2 & 0x1f];
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_vga_r(%X)\n", activecpu_get_pc(), 0x300+offset);
+ break;
+
+ /* Graphics controller access */
+ case 0x3cf:
+ if (v->banshee.vga[0x3ce & 0x1f] < ARRAY_LENGTH(v->banshee.gc))
+ result = v->banshee.gc[v->banshee.vga[0x3ce & 0x1f]];
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_gc_r(%X)\n", activecpu_get_pc(), v->banshee.vga[0x3ce & 0x1f]);
+ break;
+
+ /* CRTC access */
+ case 0x3d5:
+ if (v->banshee.vga[0x3d4 & 0x1f] < ARRAY_LENGTH(v->banshee.crtc))
+ result = v->banshee.crtc[v->banshee.vga[0x3d4 & 0x1f]];
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_crtc_r(%X)\n", activecpu_get_pc(), v->banshee.vga[0x3d4 & 0x1f]);
+ break;
+
+ /* Input status 1 */
+ case 0x3da:
+ /*
+ bit 7:6 = Reserved. These bits read back 0.
+ bit 5:4 = Display Status. These 2 bits reflect 2 of the 8 pixel data outputs from the Attribute
+ controller, as determined by the Attribute controller index 0x12 bits 4 and 5.
+ bit 3 = Vertical sync Status. A ?1? indicates vertical retrace is in progress.
+ bit 2:1 = Reserved. These bits read back 0x2.
+ bit 0 = Display Disable. When this bit is 1, either horizontal or vertical display end has occurred,
+ otherwise video data is being displayed.
+ */
+ result = 0x04;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_vga_r(%X)\n", activecpu_get_pc(), 0x300+offset);
+ break;
+
+ default:
+ result = v->banshee.vga[offset];
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_vga_r(%X)\n", activecpu_get_pc(), 0x300+offset);
+ break;
+ }
+ return result;
+}
+
+
+static UINT32 banshee_io_r(voodoo_state *v, offs_t offset, UINT32 mem_mask)
+{
+ UINT32 result;
+
+ offset &= 0xff/4;
+
+ /* switch off the offset */
+ switch (offset)
+ {
+ case io_status:
+ result = register_r(v, 0);
+ break;
+
+ case io_dacData:
+ result = v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff] = v->banshee.io[offset];
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_dac_r(%X)\n", activecpu_get_pc(), v->banshee.io[io_dacAddr] & 0x1ff);
+ break;
+
+ case io_vgab0: case io_vgab4: case io_vgab8: case io_vgabc:
+ case io_vgac0: case io_vgac4: case io_vgac8: case io_vgacc:
+ case io_vgad0: case io_vgad4: case io_vgad8: case io_vgadc:
+ result = 0;
+ if (!(mem_mask & 0x000000ff))
+ result |= banshee_vga_r(v, offset*4+0) << 0;
+ if (!(mem_mask & 0x0000ff00))
+ result |= banshee_vga_r(v, offset*4+1) << 8;
+ if (!(mem_mask & 0x00ff0000))
+ result |= banshee_vga_r(v, offset*4+2) << 16;
+ if (!(mem_mask & 0xff000000))
+ result |= banshee_vga_r(v, offset*4+3) << 24;
+ break;
+
+ default:
+ result = v->banshee.io[offset];
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_io_r(%s)\n", activecpu_get_pc(), banshee_io_reg_name[offset]);
+ break;
+ }
+
+ return result;
+}
+
+
+static UINT32 banshee_rom_r(voodoo_state *v, offs_t offset, UINT32 mem_mask)
+{
+ logerror("%08X:banshee_rom_r(%X)\n", activecpu_get_pc(), offset*4);
+ return 0xffffffff;
+}
+
+
+
+static void banshee_agp_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ offset &= 0x1ff/4;
+
+ /* switch off the offset */
+ switch (offset)
+ {
+ case cmdBaseAddr0:
+ COMBINE_DATA(&v->banshee.agp[offset]);
+ v->fbi.cmdfifo[0].base = (data & 0xffffff) << 12;
+ v->fbi.cmdfifo[0].end = v->fbi.cmdfifo[0].base + (((v->banshee.agp[cmdBaseSize0] & 0xff) + 1) << 12);
+ break;
+
+ case cmdBaseSize0:
+ COMBINE_DATA(&v->banshee.agp[offset]);
+ v->fbi.cmdfifo[0].end = v->fbi.cmdfifo[0].base + (((v->banshee.agp[cmdBaseSize0] & 0xff) + 1) << 12);
+ v->fbi.cmdfifo[0].enable = (data >> 8) & 1;
+ v->fbi.cmdfifo[0].count_holes = (~data >> 10) & 1;
+ break;
+
+ case cmdBump0:
+ fatalerror("cmdBump0");
+ break;
+
+ case cmdRdPtrL0:
+ v->fbi.cmdfifo[0].rdptr = data;
+ break;
+
+ case cmdAMin0:
+ v->fbi.cmdfifo[0].amin = data;
+ break;
+
+ case cmdAMax0:
+ v->fbi.cmdfifo[0].amax = data;
+ break;
+
+ case cmdFifoDepth0:
+ v->fbi.cmdfifo[0].depth = data;
+ break;
+
+ case cmdHoleCnt0:
+ v->fbi.cmdfifo[0].holes = data;
+ break;
+
+ case cmdBaseAddr1:
+ COMBINE_DATA(&v->banshee.agp[offset]);
+ v->fbi.cmdfifo[1].base = (data & 0xffffff) << 12;
+ v->fbi.cmdfifo[1].end = v->fbi.cmdfifo[1].base + (((v->banshee.agp[cmdBaseSize1] & 0xff) + 1) << 12);
+ break;
+
+ case cmdBaseSize1:
+ COMBINE_DATA(&v->banshee.agp[offset]);
+ v->fbi.cmdfifo[1].end = v->fbi.cmdfifo[1].base + (((v->banshee.agp[cmdBaseSize1] & 0xff) + 1) << 12);
+ v->fbi.cmdfifo[1].enable = (data >> 8) & 1;
+ v->fbi.cmdfifo[1].count_holes = (~data >> 10) & 1;
+ break;
+
+ case cmdBump1:
+ fatalerror("cmdBump1");
+ break;
+
+ case cmdRdPtrL1:
+ v->fbi.cmdfifo[1].rdptr = data;
+ break;
+
+ case cmdAMin1:
+ v->fbi.cmdfifo[1].amin = data;
+ break;
+
+ case cmdAMax1:
+ v->fbi.cmdfifo[1].amax = data;
+ break;
+
+ case cmdFifoDepth1:
+ v->fbi.cmdfifo[1].depth = data;
+ break;
+
+ case cmdHoleCnt1:
+ v->fbi.cmdfifo[1].holes = data;
+ break;
+
+ default:
+ COMBINE_DATA(&v->banshee.agp[offset]);
+ break;
+ }
+
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_w(AGP:%s) = %08X & %08X\n", activecpu_get_pc(), banshee_agp_reg_name[offset], data, ~mem_mask);
+}
+
+
+static void banshee_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ /* if we have something pending, flush the FIFOs up to the current time */
+ if (v->pci.op_pending)
+ flush_fifos(v, timer_get_time());
+
+ if (offset < 0x80000/4)
+ banshee_io_w(v, offset, data, mem_mask);
+ else if (offset < 0x100000/4)
+ banshee_agp_w(v, offset, data, mem_mask);
+ else if (offset < 0x200000/4)
+ logerror("%08X:banshee_w(2D:%X) = %08X & %08X\n", activecpu_get_pc(), (offset*4) & 0xfffff, data, ~mem_mask);
+ else if (offset < 0x600000/4)
+ register_w(v, offset & 0x1fffff/4, data);
+ else if (offset < 0x800000/4)
+ logerror("%08X:banshee_w(TEX:%X) = %08X & %08X\n", activecpu_get_pc(), (offset*4) & 0x1fffff, data, ~mem_mask);
+ else if (offset < 0xc00000/4)
+ logerror("%08X:banshee_w(RES:%X) = %08X & %08X\n", activecpu_get_pc(), (offset*4) & 0x3fffff, data, ~mem_mask);
+ else if (offset < 0x1000000/4)
+ logerror("%08X:banshee_w(YUV:%X) = %08X & %08X\n", activecpu_get_pc(), (offset*4) & 0x3fffff, data, ~mem_mask);
+ else if (offset < 0x2000000/4)
+ {
+ UINT8 temp = v->fbi.lfb_stride;
+ v->fbi.lfb_stride = 11;
+ lfb_w(v, offset & 0xffffff/4, data, mem_mask, FALSE);
+ v->fbi.lfb_stride = temp;
+ }
+}
+
+
+static void banshee_fb_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ UINT32 addr = offset*4;
+
+ /* if we have something pending, flush the FIFOs up to the current time */
+ if (v->pci.op_pending)
+ flush_fifos(v, timer_get_time());
+
+ if (offset < v->fbi.lfb_base)
+ {
+ if (v->fbi.cmdfifo[0].enable && addr >= v->fbi.cmdfifo[0].base && addr < v->fbi.cmdfifo[0].end)
+ cmdfifo_w(v, &v->fbi.cmdfifo[0], (addr - v->fbi.cmdfifo[0].base) / 4, data);
+ else if (v->fbi.cmdfifo[1].enable && addr >= v->fbi.cmdfifo[1].base && addr < v->fbi.cmdfifo[1].end)
+ cmdfifo_w(v, &v->fbi.cmdfifo[1], (addr - v->fbi.cmdfifo[1].base) / 4, data);
+ else
+ {
+ if (offset*4 <= v->fbi.mask)
+ COMBINE_DATA(&((UINT32 *)v->fbi.ram)[offset]);
+ logerror("%08X:banshee_fb_w(%X) = %08X & %08X\n", activecpu_get_pc(), offset*4, data, ~mem_mask);
+ }
+ }
+ else
+ lfb_w(v, offset - v->fbi.lfb_base, data, mem_mask, FALSE);
+}
+
+
+static void banshee_vga_w(voodoo_state *v, offs_t offset, UINT8 data)
+{
+ offset &= 0x1f;
+
+ /* switch off the offset */
+ switch (offset + 0x3c0)
+ {
+ /* attribute access */
+ case 0x3c0:
+ case 0x3c1:
+ if (v->banshee.attff == 0)
+ {
+ v->banshee.vga[0x3c1 & 0x1f] = data;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_vga_w(%X) = %02X\n", activecpu_get_pc(), 0x3c0+offset, data);
+ }
+ else
+ {
+ if (v->banshee.vga[0x3c1 & 0x1f] < ARRAY_LENGTH(v->banshee.att))
+ v->banshee.att[v->banshee.vga[0x3c1 & 0x1f]] = data;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_att_w(%X) = %02X\n", activecpu_get_pc(), v->banshee.vga[0x3c1 & 0x1f], data);
+ }
+ v->banshee.attff ^= 1;
+ break;
+
+ /* Sequencer access */
+ case 0x3c5:
+ if (v->banshee.vga[0x3c4 & 0x1f] < ARRAY_LENGTH(v->banshee.seq))
+ v->banshee.seq[v->banshee.vga[0x3c4 & 0x1f]] = data;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_seq_w(%X) = %02X\n", activecpu_get_pc(), v->banshee.vga[0x3c4 & 0x1f], data);
+ break;
+
+ /* Graphics controller access */
+ case 0x3cf:
+ if (v->banshee.vga[0x3ce & 0x1f] < ARRAY_LENGTH(v->banshee.gc))
+ v->banshee.gc[v->banshee.vga[0x3ce & 0x1f]] = data;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_gc_w(%X) = %02X\n", activecpu_get_pc(), v->banshee.vga[0x3ce & 0x1f], data);
+ break;
+
+ /* CRTC access */
+ case 0x3d5:
+ if (v->banshee.vga[0x3d4 & 0x1f] < ARRAY_LENGTH(v->banshee.crtc))
+ v->banshee.crtc[v->banshee.vga[0x3d4 & 0x1f]] = data;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_crtc_w(%X) = %02X\n", activecpu_get_pc(), v->banshee.vga[0x3d4 & 0x1f], data);
+ break;
+
+ default:
+ v->banshee.vga[offset] = data;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_vga_w(%X) = %02X\n", activecpu_get_pc(), 0x3c0+offset, data);
+ break;
+ }
+}
+
+
+static void banshee_io_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask)
+{
+ UINT32 old;
+
+ offset &= 0xff/4;
+ old = v->banshee.io[offset];
+
+ /* switch off the offset */
+ switch (offset)
+ {
+ case io_vidProcCfg:
+ COMBINE_DATA(&v->banshee.io[offset]);
+ if ((v->banshee.io[offset] ^ old) & 0x2800)
+ v->fbi.clut_dirty = TRUE;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_io_w(%s) = %08X & %08X\n", activecpu_get_pc(), banshee_io_reg_name[offset], data, ~mem_mask);
+ break;
+
+ case io_dacData:
+ COMBINE_DATA(&v->banshee.io[offset]);
+ if (v->banshee.io[offset] != v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff])
+ {
+ v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff] = v->banshee.io[offset];
+ v->fbi.clut_dirty = TRUE;
+ }
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_dac_w(%X) = %08X & %08X\n", activecpu_get_pc(), v->banshee.io[io_dacAddr] & 0x1ff, data, ~mem_mask);
+ break;
+
+ case io_miscInit0:
+ COMBINE_DATA(&v->banshee.io[offset]);
+ v->fbi.yorigin = (data >> 18) & 0xfff;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_io_w(%s) = %08X & %08X\n", activecpu_get_pc(), banshee_io_reg_name[offset], data, ~mem_mask);
+ break;
+
+ case io_vidScreenSize:
+ /* warning: this is a hack for now! We should really compute the screen size */
+ /* from the CRTC registers */
+ COMBINE_DATA(&v->banshee.io[offset]);
+ if (data & 0xfff)
+ v->fbi.width = data & 0xfff;
+ if (data & 0xfff000)
+ v->fbi.height = (data >> 12) & 0xfff;
+ video_screen_set_visarea(v->scrnum, 0, v->fbi.width - 1, 0, v->fbi.height - 1);
+ adjust_vblank_timer(v);
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_io_w(%s) = %08X & %08X\n", activecpu_get_pc(), banshee_io_reg_name[offset], data, ~mem_mask);
+ break;
+
+ case io_lfbMemoryConfig:
+ v->fbi.lfb_base = (data & 0x1fff) << 10;
+ v->fbi.lfb_stride = ((data >> 13) & 7) + 9;
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_io_w(%s) = %08X & %08X\n", activecpu_get_pc(), banshee_io_reg_name[offset], data, ~mem_mask);
+ break;
+
+ case io_vgab0: case io_vgab4: case io_vgab8: case io_vgabc:
+ case io_vgac0: case io_vgac4: case io_vgac8: case io_vgacc:
+ case io_vgad0: case io_vgad4: case io_vgad8: case io_vgadc:
+ if (!(mem_mask & 0x000000ff))
+ banshee_vga_w(v, offset*4+0, data >> 0);
+ if (!(mem_mask & 0x0000ff00))
+ banshee_vga_w(v, offset*4+1, data >> 8);
+ if (!(mem_mask & 0x00ff0000))
+ banshee_vga_w(v, offset*4+2, data >> 16);
+ if (!(mem_mask & 0xff000000))
+ banshee_vga_w(v, offset*4+3, data >> 24);
+ break;
+
+ default:
+ COMBINE_DATA(&v->banshee.io[offset]);
+ if (LOG_REGISTERS)
+ logerror("%08X:banshee_io_w(%s) = %08X & %08X\n", activecpu_get_pc(), banshee_io_reg_name[offset], data, ~mem_mask);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ COMMAND HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ fastfill - execute the 'fastfill'
+ command
+-------------------------------------------------*/
+
+static INT32 fastfill(voodoo_state *v)
+{
+ int sx = (v->reg[clipLeftRight].u >> 16) & 0x3ff;
+ int ex = (v->reg[clipLeftRight].u >> 0) & 0x3ff;
+ int sy = (v->reg[clipLowYHighY].u >> 16) & 0x3ff;
+ int ey = (v->reg[clipLowYHighY].u >> 0) & 0x3ff;
+ poly_extent extents[64];
+ UINT16 dithermatrix[16];
+ UINT16 *drawbuf = NULL;
+ UINT32 pixels = 0;
+ int extnum, x, y;
+
+ /* if we're not clearing either, take no time */
+ if (!FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u) && !FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u))
+ return 0;
+
+ /* are we clearing the RGB buffer? */
+ if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u))
+ {
+ /* determine the draw buffer */
+ int destbuf = (v->type >= VOODOO_BANSHEE) ? 1 : FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u);
+ switch (destbuf)
+ {
+ case 0: /* front buffer */
+ drawbuf = v->fbi.rgb[v->fbi.frontbuf];
+ break;
+
+ case 1: /* back buffer */
+ drawbuf = v->fbi.rgb[v->fbi.backbuf];
+ break;
+
+ default: /* reserved */
+ break;
+ }
+
+ /* determine the dither pattern */
+ for (y = 0; y < 4; y++)
+ {
+ DECLARE_DITHER_POINTERS;
+ COMPUTE_DITHER_POINTERS(v->reg[fbzMode].u, y);
+ for (x = 0; x < 4; x++)
+ {
+ int r = v->reg[color1].rgb.r;
+ int g = v->reg[color1].rgb.g;
+ int b = v->reg[color1].rgb.b;
+
+ APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, r, g, b);
+ dithermatrix[y*4 + x] = (r << 11) | (g << 5) | b;
+ }
+ }
+ }
+
+ /* fill in a block of extents */
+ extents[0].startx = sx;
+ extents[0].stopx = ex;
+ for (extnum = 1; extnum < ARRAY_LENGTH(extents); extnum++)
+ extents[extnum] = extents[0];
+
+ /* iterate over blocks of extents */
+ for (y = sy; y < ey; y += ARRAY_LENGTH(extents))
+ {
+ poly_extra_data *extra = poly_get_extra_data(v->poly);
+ int count = MIN(ey - y, ARRAY_LENGTH(extents));
+
+ extra->state = v;
+ memcpy(extra->dither, dithermatrix, sizeof(extra->dither));
+
+ pixels += poly_render_triangle_custom(v->poly, drawbuf, NULL, raster_fastfill, y, count, extents);
+ }
+
+ /* 2 pixels per clock */
+ return pixels / 2;
+}
+
+
+/*-------------------------------------------------
+ swapbuffer - execute the 'swapbuffer'
+ command
+-------------------------------------------------*/
+
+static INT32 swapbuffer(voodoo_state *v, UINT32 data)
+{
+ /* set the don't swap value for Voodoo 2 */
+ v->fbi.vblank_swap_pending = TRUE;
+ v->fbi.vblank_swap = (data >> 1) & 0xff;
+ v->fbi.vblank_dont_swap = (data >> 9) & 1;
+
+ /* if we're not syncing to the retrace, process the command immediately */
+ if (!(data & 1))
+ {
+ swap_buffers(v);
+ return 0;
+ }
+
+ /* determine how many cycles to wait; we deliberately overshoot here because */
+ /* the final count gets updated on the VBLANK */
+ return (v->fbi.vblank_swap + 1) * v->freq / 30;
+}
+
+
+/*-------------------------------------------------
+ triangle - execute the 'triangle'
+ command
+-------------------------------------------------*/
+
+static INT32 triangle(voodoo_state *v)
+{
+ int texcount = 0;
+ UINT16 *drawbuf;
+ int destbuf;
+ int pixels;
+
+ profiler_mark(PROFILER_USER2);
+
+ /* determine the number of TMUs involved */
+ texcount = 0;
+ if (!FBIINIT3_DISABLE_TMUS(v->reg[fbiInit3].u) && FBZCP_TEXTURE_ENABLE(v->reg[fbzColorPath].u))
+ {
+ texcount = 1;
+ if (v->chipmask & 0x04)
+ texcount = 2;
+ }
+
+ /* perform subpixel adjustments */
+ if (FBZCP_CCA_SUBPIXEL_ADJUST(v->reg[fbzColorPath].u))
+ {
+ INT32 dx = 8 - (v->fbi.ax & 15);
+ INT32 dy = 8 - (v->fbi.ay & 15);
+
+ /* adjust iterated R,G,B,A and W/Z */
+ v->fbi.startr += (dy * v->fbi.drdy + dx * v->fbi.drdx) >> 4;
+ v->fbi.startg += (dy * v->fbi.dgdy + dx * v->fbi.dgdx) >> 4;
+ v->fbi.startb += (dy * v->fbi.dbdy + dx * v->fbi.dbdx) >> 4;
+ v->fbi.starta += (dy * v->fbi.dady + dx * v->fbi.dadx) >> 4;
+ v->fbi.startw += (dy * v->fbi.dwdy + dx * v->fbi.dwdx) >> 4;
+ v->fbi.startz += mul_32x32_shift(dy, v->fbi.dzdy, 4) + mul_32x32_shift(dx, v->fbi.dzdx, 4);
+
+ /* adjust iterated W/S/T for TMU 0 */
+ if (texcount >= 1)
+ {
+ v->tmu[0].startw += (dy * v->tmu[0].dwdy + dx * v->tmu[0].dwdx) >> 4;
+ v->tmu[0].starts += (dy * v->tmu[0].dsdy + dx * v->tmu[0].dsdx) >> 4;
+ v->tmu[0].startt += (dy * v->tmu[0].dtdy + dx * v->tmu[0].dtdx) >> 4;
+
+ /* adjust iterated W/S/T for TMU 1 */
+ if (texcount >= 2)
+ {
+ v->tmu[1].startw += (dy * v->tmu[1].dwdy + dx * v->tmu[1].dwdx) >> 4;
+ v->tmu[1].starts += (dy * v->tmu[1].dsdy + dx * v->tmu[1].dsdx) >> 4;
+ v->tmu[1].startt += (dy * v->tmu[1].dtdy + dx * v->tmu[1].dtdx) >> 4;
+ }
+ }
+ }
+
+ /* wait for any outstanding work to finish */
+// poly_wait(v->poly, "triangle");
+
+ /* determine the draw buffer */
+ destbuf = (v->type >= VOODOO_BANSHEE) ? 1 : FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u);
+ switch (destbuf)
+ {
+ case 0: /* front buffer */
+ drawbuf = v->fbi.rgb[v->fbi.frontbuf];
+ v->fbi.video_changed = TRUE;
+ break;
+
+ case 1: /* back buffer */
+ drawbuf = v->fbi.rgb[v->fbi.backbuf];
+ break;
+
+ default: /* reserved */
+ return TRIANGLE_SETUP_CLOCKS;
+ }
+
+ /* find a rasterizer that matches our current state */
+ pixels = triangle_create_work_item(v, drawbuf, texcount);
+
+ /* update stats */
+ v->reg[fbiTrianglesOut].u++;
+
+ /* update stats */
+ v->stats.total_triangles++;
+
+ profiler_mark(PROFILER_END);
+
+ /* 1 pixel per clock, plus some setup time */
+ if (LOG_REGISTERS) logerror("cycles = %d\n", TRIANGLE_SETUP_CLOCKS + pixels);
+ return TRIANGLE_SETUP_CLOCKS + pixels;
+}
+
+
+/*-------------------------------------------------
+ begin_triangle - execute the 'beginTri'
+ command
+-------------------------------------------------*/
+
+static INT32 begin_triangle(voodoo_state *v)
+{
+ setup_vertex *sv = &v->fbi.svert[2];
+
+ /* extract all the data from registers */
+ sv->x = v->reg[sVx].f;
+ sv->y = v->reg[sVy].f;
+ sv->wb = v->reg[sWb].f;
+ sv->w0 = v->reg[sWtmu0].f;
+ sv->s0 = v->reg[sS_W0].f;
+ sv->t0 = v->reg[sT_W0].f;
+ sv->w1 = v->reg[sWtmu1].f;
+ sv->s1 = v->reg[sS_Wtmu1].f;
+ sv->t1 = v->reg[sT_Wtmu1].f;
+ sv->a = v->reg[sAlpha].f;
+ sv->r = v->reg[sRed].f;
+ sv->g = v->reg[sGreen].f;
+ sv->b = v->reg[sBlue].f;
+
+ /* spread it across all three verts and reset the count */
+ v->fbi.svert[0] = v->fbi.svert[1] = v->fbi.svert[2];
+ v->fbi.sverts = 1;
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ draw_triangle - execute the 'DrawTri'
+ command
+-------------------------------------------------*/
+
+static INT32 draw_triangle(voodoo_state *v)
+{
+ setup_vertex *sv = &v->fbi.svert[2];
+ int cycles = 0;
+
+ /* for strip mode, shuffle vertex 1 down to 0 */
+ if (!(v->reg[sSetupMode].u & (1 << 16)))
+ v->fbi.svert[0] = v->fbi.svert[1];
+
+ /* copy 2 down to 1 regardless */
+ v->fbi.svert[1] = v->fbi.svert[2];
+
+ /* extract all the data from registers */
+ sv->x = v->reg[sVx].f;
+ sv->y = v->reg[sVy].f;
+ sv->wb = v->reg[sWb].f;
+ sv->w0 = v->reg[sWtmu0].f;
+ sv->s0 = v->reg[sS_W0].f;
+ sv->t0 = v->reg[sT_W0].f;
+ sv->w1 = v->reg[sWtmu1].f;
+ sv->s1 = v->reg[sS_Wtmu1].f;
+ sv->t1 = v->reg[sT_Wtmu1].f;
+ sv->a = v->reg[sAlpha].f;
+ sv->r = v->reg[sRed].f;
+ sv->g = v->reg[sGreen].f;
+ sv->b = v->reg[sBlue].f;
+
+ /* if we have enough verts, go ahead and draw */
+ if (++v->fbi.sverts >= 3)
+ cycles = setup_and_draw_triangle(v);
+
+ return cycles;
+}
+
+
+
+/***************************************************************************
+ TRIANGLE HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ setup_and_draw_triangle - process the setup
+ parameters and render the triangle
+-------------------------------------------------*/
+
+static INT32 setup_and_draw_triangle(voodoo_state *v)
+{
+ float dx1, dy1, dx2, dy2;
+ float divisor, tdiv;
+
+ /* grab the X/Ys at least */
+ v->fbi.ax = (INT16)(v->fbi.svert[0].x * 16.0);
+ v->fbi.ay = (INT16)(v->fbi.svert[0].y * 16.0);
+ v->fbi.bx = (INT16)(v->fbi.svert[1].x * 16.0);
+ v->fbi.by = (INT16)(v->fbi.svert[1].y * 16.0);
+ v->fbi.cx = (INT16)(v->fbi.svert[2].x * 16.0);
+ v->fbi.cy = (INT16)(v->fbi.svert[2].y * 16.0);
+
+ /* compute the divisor */
+ divisor = 1.0f / ((v->fbi.svert[0].x - v->fbi.svert[1].x) * (v->fbi.svert[0].y - v->fbi.svert[2].y) -
+ (v->fbi.svert[0].x - v->fbi.svert[2].x) * (v->fbi.svert[0].y - v->fbi.svert[1].y));
+
+ /* backface culling */
+ if (v->reg[sSetupMode].u & 0x20000)
+ {
+ int culling_sign = (v->reg[sSetupMode].u >> 18) & 1;
+ int divisor_sign = (divisor < 0);
+
+ /* if doing strips and ping pong is enabled, apply the ping pong */
+ if ((v->reg[sSetupMode].u & 0x90000) == 0x00000)
+ culling_sign ^= (v->fbi.sverts - 3) & 1;
+
+ /* if our sign matches the culling sign, we're done for */
+ if (divisor_sign == culling_sign)
+ return TRIANGLE_SETUP_CLOCKS;
+ }
+
+ /* compute the dx/dy values */
+ dx1 = v->fbi.svert[0].y - v->fbi.svert[2].y;
+ dx2 = v->fbi.svert[0].y - v->fbi.svert[1].y;
+ dy1 = v->fbi.svert[0].x - v->fbi.svert[1].x;
+ dy2 = v->fbi.svert[0].x - v->fbi.svert[2].x;
+
+ /* set up R,G,B */
+ tdiv = divisor * 4096.0f;
+ if (v->reg[sSetupMode].u & (1 << 0))
+ {
+ v->fbi.startr = (INT32)(v->fbi.svert[0].r * 4096.0f);
+ v->fbi.drdx = (INT32)(((v->fbi.svert[0].r - v->fbi.svert[1].r) * dx1 - (v->fbi.svert[0].r - v->fbi.svert[2].r) * dx2) * tdiv);
+ v->fbi.drdy = (INT32)(((v->fbi.svert[0].r - v->fbi.svert[2].r) * dy1 - (v->fbi.svert[0].r - v->fbi.svert[1].r) * dy2) * tdiv);
+ v->fbi.startg = (INT32)(v->fbi.svert[0].g * 4096.0f);
+ v->fbi.dgdx = (INT32)(((v->fbi.svert[0].g - v->fbi.svert[1].g) * dx1 - (v->fbi.svert[0].g - v->fbi.svert[2].g) * dx2) * tdiv);
+ v->fbi.dgdy = (INT32)(((v->fbi.svert[0].g - v->fbi.svert[2].g) * dy1 - (v->fbi.svert[0].g - v->fbi.svert[1].g) * dy2) * tdiv);
+ v->fbi.startb = (INT32)(v->fbi.svert[0].b * 4096.0f);
+ v->fbi.dbdx = (INT32)(((v->fbi.svert[0].b - v->fbi.svert[1].b) * dx1 - (v->fbi.svert[0].b - v->fbi.svert[2].b) * dx2) * tdiv);
+ v->fbi.dbdy = (INT32)(((v->fbi.svert[0].b - v->fbi.svert[2].b) * dy1 - (v->fbi.svert[0].b - v->fbi.svert[1].b) * dy2) * tdiv);
+ }
+
+ /* set up alpha */
+ if (v->reg[sSetupMode].u & (1 << 1))
+ {
+ v->fbi.starta = (INT32)(v->fbi.svert[0].a * 4096.0);
+ v->fbi.dadx = (INT32)(((v->fbi.svert[0].a - v->fbi.svert[1].a) * dx1 - (v->fbi.svert[0].a - v->fbi.svert[2].a) * dx2) * tdiv);
+ v->fbi.dady = (INT32)(((v->fbi.svert[0].a - v->fbi.svert[2].a) * dy1 - (v->fbi.svert[0].a - v->fbi.svert[1].a) * dy2) * tdiv);
+ }
+
+ /* set up Z */
+ if (v->reg[sSetupMode].u & (1 << 2))
+ {
+ v->fbi.startz = (INT32)(v->fbi.svert[0].z * 4096.0);
+ v->fbi.dzdx = (INT32)(((v->fbi.svert[0].z - v->fbi.svert[1].z) * dx1 - (v->fbi.svert[0].z - v->fbi.svert[2].z) * dx2) * tdiv);
+ v->fbi.dzdy = (INT32)(((v->fbi.svert[0].z - v->fbi.svert[2].z) * dy1 - (v->fbi.svert[0].z - v->fbi.svert[1].z) * dy2) * tdiv);
+ }
+
+ /* set up Wb */
+ tdiv = divisor * 65536.0f * 65536.0f;
+ if (v->reg[sSetupMode].u & (1 << 3))
+ {
+ v->fbi.startw = v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].wb * 65536.0f * 65536.0f);
+ v->fbi.dwdx = v->tmu[0].dwdx = v->tmu[1].dwdx = ((v->fbi.svert[0].wb - v->fbi.svert[1].wb) * dx1 - (v->fbi.svert[0].wb - v->fbi.svert[2].wb) * dx2) * tdiv;
+ v->fbi.dwdy = v->tmu[0].dwdy = v->tmu[1].dwdy = ((v->fbi.svert[0].wb - v->fbi.svert[2].wb) * dy1 - (v->fbi.svert[0].wb - v->fbi.svert[1].wb) * dy2) * tdiv;
+ }
+
+ /* set up W0 */
+ if (v->reg[sSetupMode].u & (1 << 4))
+ {
+ v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].w0 * 65536.0f * 65536.0f);
+ v->tmu[0].dwdx = v->tmu[1].dwdx = ((v->fbi.svert[0].w0 - v->fbi.svert[1].w0) * dx1 - (v->fbi.svert[0].w0 - v->fbi.svert[2].w0) * dx2) * tdiv;
+ v->tmu[0].dwdy = v->tmu[1].dwdy = ((v->fbi.svert[0].w0 - v->fbi.svert[2].w0) * dy1 - (v->fbi.svert[0].w0 - v->fbi.svert[1].w0) * dy2) * tdiv;
+ }
+
+ /* set up S0,T0 */
+ if (v->reg[sSetupMode].u & (1 << 5))
+ {
+ v->tmu[0].starts = v->tmu[1].starts = (INT64)(v->fbi.svert[0].s0 * 65536.0f * 65536.0f);
+ v->tmu[0].dsdx = v->tmu[1].dsdx = ((v->fbi.svert[0].s0 - v->fbi.svert[1].s0) * dx1 - (v->fbi.svert[0].s0 - v->fbi.svert[2].s0) * dx2) * tdiv;
+ v->tmu[0].dsdy = v->tmu[1].dsdy = ((v->fbi.svert[0].s0 - v->fbi.svert[2].s0) * dy1 - (v->fbi.svert[0].s0 - v->fbi.svert[1].s0) * dy2) * tdiv;
+ v->tmu[0].startt = v->tmu[1].startt = (INT64)(v->fbi.svert[0].t0 * 65536.0f * 65536.0f);
+ v->tmu[0].dtdx = v->tmu[1].dtdx = ((v->fbi.svert[0].t0 - v->fbi.svert[1].t0) * dx1 - (v->fbi.svert[0].t0 - v->fbi.svert[2].t0) * dx2) * tdiv;
+ v->tmu[0].dtdy = v->tmu[1].dtdy = ((v->fbi.svert[0].t0 - v->fbi.svert[2].t0) * dy1 - (v->fbi.svert[0].t0 - v->fbi.svert[1].t0) * dy2) * tdiv;
+ }
+
+ /* set up W1 */
+ if (v->reg[sSetupMode].u & (1 << 6))
+ {
+ v->tmu[1].startw = (INT64)(v->fbi.svert[0].w1 * 65536.0f * 65536.0f);
+ v->tmu[1].dwdx = ((v->fbi.svert[0].w1 - v->fbi.svert[1].w1) * dx1 - (v->fbi.svert[0].w1 - v->fbi.svert[2].w1) * dx2) * tdiv;
+ v->tmu[1].dwdy = ((v->fbi.svert[0].w1 - v->fbi.svert[2].w1) * dy1 - (v->fbi.svert[0].w1 - v->fbi.svert[1].w1) * dy2) * tdiv;
+ }
+
+ /* set up S1,T1 */
+ if (v->reg[sSetupMode].u & (1 << 7))
+ {
+ v->tmu[1].starts = (INT64)(v->fbi.svert[0].s1 * 65536.0f * 65536.0f);
+ v->tmu[1].dsdx = ((v->fbi.svert[0].s1 - v->fbi.svert[1].s1) * dx1 - (v->fbi.svert[0].s1 - v->fbi.svert[2].s1) * dx2) * tdiv;
+ v->tmu[1].dsdy = ((v->fbi.svert[0].s1 - v->fbi.svert[2].s1) * dy1 - (v->fbi.svert[0].s1 - v->fbi.svert[1].s1) * dy2) * tdiv;
+ v->tmu[1].startt = (INT64)(v->fbi.svert[0].t1 * 65536.0f * 65536.0f);
+ v->tmu[1].dtdx = ((v->fbi.svert[0].t1 - v->fbi.svert[1].t1) * dx1 - (v->fbi.svert[0].t1 - v->fbi.svert[2].t1) * dx2) * tdiv;
+ v->tmu[1].dtdy = ((v->fbi.svert[0].t1 - v->fbi.svert[2].t1) * dy1 - (v->fbi.svert[0].t1 - v->fbi.svert[1].t1) * dy2) * tdiv;
+ }
+
+ /* draw the triangle */
+ v->fbi.cheating_allowed = 1;
+ return triangle(v);
+}
+
+
+/*-------------------------------------------------
+ triangle_create_work_item - finish triangle
+ setup and create the work item
+-------------------------------------------------*/
+
+static INT32 triangle_create_work_item(voodoo_state *v, UINT16 *drawbuf, int texcount)
+{
+ poly_extra_data *extra = poly_get_extra_data(v->poly);
+ raster_info *info = find_rasterizer(v, texcount);
+ poly_vertex vert[3];
+
+ /* fill in the vertex data */
+ vert[0].x = (float)v->fbi.ax * (1.0f / 16.0f);
+ vert[0].y = (float)v->fbi.ay * (1.0f / 16.0f);
+ vert[1].x = (float)v->fbi.bx * (1.0f / 16.0f);
+ vert[1].y = (float)v->fbi.by * (1.0f / 16.0f);
+ vert[2].x = (float)v->fbi.cx * (1.0f / 16.0f);
+ vert[2].y = (float)v->fbi.cy * (1.0f / 16.0f);
+
+ /* fill in the extra data */
+ extra->state = v;
+ extra->info = info;
+
+ /* fill in triangle parameters */
+ extra->ax = v->fbi.ax;
+ extra->ay = v->fbi.ay;
+ extra->startr = v->fbi.startr;
+ extra->startg = v->fbi.startg;
+ extra->startb = v->fbi.startb;
+ extra->starta = v->fbi.starta;
+ extra->startz = v->fbi.startz;
+ extra->startw = v->fbi.startw;
+ extra->drdx = v->fbi.drdx;
+ extra->dgdx = v->fbi.dgdx;
+ extra->dbdx = v->fbi.dbdx;
+ extra->dadx = v->fbi.dadx;
+ extra->dzdx = v->fbi.dzdx;
+ extra->dwdx = v->fbi.dwdx;
+ extra->drdy = v->fbi.drdy;
+ extra->dgdy = v->fbi.dgdy;
+ extra->dbdy = v->fbi.dbdy;
+ extra->dady = v->fbi.dady;
+ extra->dzdy = v->fbi.dzdy;
+ extra->dwdy = v->fbi.dwdy;
+
+ /* fill in texture 0 parameters */
+ if (texcount > 0)
+ {
+ extra->starts0 = v->tmu[0].starts;
+ extra->startt0 = v->tmu[0].startt;
+ extra->startw0 = v->tmu[0].startw;
+ extra->ds0dx = v->tmu[0].dsdx;
+ extra->dt0dx = v->tmu[0].dtdx;
+ extra->dw0dx = v->tmu[0].dwdx;
+ extra->ds0dy = v->tmu[0].dsdy;
+ extra->dt0dy = v->tmu[0].dtdy;
+ extra->dw0dy = v->tmu[0].dwdy;
+ extra->lodbase0 = prepare_tmu(&v->tmu[0]);
+ v->stats.texture_mode[TEXMODE_FORMAT(v->tmu[0].reg[textureMode].u)]++;
+
+ /* fill in texture 1 parameters */
+ if (texcount > 1)
+ {
+ extra->starts1 = v->tmu[1].starts;
+ extra->startt1 = v->tmu[1].startt;
+ extra->startw1 = v->tmu[1].startw;
+ extra->ds1dx = v->tmu[1].dsdx;
+ extra->dt1dx = v->tmu[1].dtdx;
+ extra->dw1dx = v->tmu[1].dwdx;
+ extra->ds1dy = v->tmu[1].dsdy;
+ extra->dt1dy = v->tmu[1].dtdy;
+ extra->dw1dy = v->tmu[1].dwdy;
+ extra->lodbase1 = prepare_tmu(&v->tmu[1]);
+ v->stats.texture_mode[TEXMODE_FORMAT(v->tmu[1].reg[textureMode].u)]++;
+ }
+ }
+
+ /* farm the rasterization out to other threads */
+ info->polys++;
+ return poly_render_triangle(v->poly, drawbuf, NULL, info->callback, 0, &vert[0], &vert[1], &vert[2]);
+}
+
+
+
+/***************************************************************************
+ RASTERIZER MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ add_rasterizer - add a rasterizer to our
+ hash table
+-------------------------------------------------*/
+
+static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo)
+{
+ raster_info *info = &v->rasterizer[v->next_rasterizer++];
+ int hash = compute_raster_hash(cinfo);
+
+ assert_always(v->next_rasterizer <= MAX_RASTERIZERS, "Out of space for new rasterizers!");
+
+ /* make a copy of the info */
+ *info = *cinfo;
+
+ /* fill in the data */
+ info->hits = 0;
+ info->polys = 0;
+
+ /* hook us into the hash table */
+ info->next = v->raster_hash[hash];
+ v->raster_hash[hash] = info;
+
+ if (LOG_RASTERIZERS)
+ printf("Adding rasterizer @ %p : %08X %08X %08X %08X %08X %08X (hash=%d)\n",
+ info->callback,
+ info->eff_color_path, info->eff_alpha_mode, info->eff_fog_mode, info->eff_fbz_mode,
+ info->eff_tex_mode_0, info->eff_tex_mode_1, hash);
+
+ return info;
+}
+
+
+/*-------------------------------------------------
+ find_rasterizer - find a rasterizer that
+ matches our current parameters and return
+ it, creating a new one if necessary
+-------------------------------------------------*/
+
+static raster_info *find_rasterizer(voodoo_state *v, int texcount)
+{
+ raster_info *info, *prev = NULL;
+ raster_info curinfo;
+ int hash;
+
+ /* build an info struct with all the parameters */
+ curinfo.eff_color_path = normalize_color_path(v->reg[fbzColorPath].u);
+ curinfo.eff_alpha_mode = normalize_alpha_mode(v->reg[alphaMode].u);
+ curinfo.eff_fog_mode = normalize_fog_mode(v->reg[fogMode].u);
+ curinfo.eff_fbz_mode = normalize_fbz_mode(v->reg[fbzMode].u);
+ curinfo.eff_tex_mode_0 = (texcount >= 1) ? normalize_tex_mode(v->tmu[0].reg[textureMode].u) : 0xffffffff;
+ curinfo.eff_tex_mode_1 = (texcount >= 2) ? normalize_tex_mode(v->tmu[1].reg[textureMode].u) : 0xffffffff;
+
+ /* compute the hash */
+ hash = compute_raster_hash(&curinfo);
+
+ /* find the appropriate hash entry */
+ for (info = v->raster_hash[hash]; info; prev = info, info = info->next)
+ if (info->eff_color_path == curinfo.eff_color_path &&
+ info->eff_alpha_mode == curinfo.eff_alpha_mode &&
+ info->eff_fog_mode == curinfo.eff_fog_mode &&
+ info->eff_fbz_mode == curinfo.eff_fbz_mode &&
+ info->eff_tex_mode_0 == curinfo.eff_tex_mode_0 &&
+ info->eff_tex_mode_1 == curinfo.eff_tex_mode_1)
+ {
+ /* got it, move us to the head of the list */
+ if (prev)
+ {
+ prev->next = info->next;
+ info->next = v->raster_hash[hash];
+ v->raster_hash[hash] = info;
+ }
+
+ /* return the result */
+ return info;
+ }
+
+ /* generate a new one using the generic entry */
+ curinfo.callback = (texcount == 0) ? raster_generic_0tmu : (texcount == 1) ? raster_generic_1tmu : raster_generic_2tmu;
+ curinfo.is_generic = TRUE;
+ curinfo.display = 0;
+ curinfo.polys = 0;
+ curinfo.hits = 0;
+ curinfo.next = 0;
+
+ return add_rasterizer(v, &curinfo);
+}
+
+
+/*-------------------------------------------------
+ dump_rasterizer_stats - dump statistics on
+ the current rasterizer usage patterns
+-------------------------------------------------*/
+
+static void dump_rasterizer_stats(voodoo_state *v)
+{
+ static UINT8 display_index;
+ raster_info *cur, *best;
+ int hash;
+
+ printf("----\n");
+ display_index++;
+
+ /* loop until we've displayed everything */
+ while (1)
+ {
+ best = NULL;
+
+ /* find the highest entry */
+ for (hash = 0; hash < RASTER_HASH_SIZE; hash++)
+ for (cur = v->raster_hash[hash]; cur; cur = cur->next)
+ if (cur->display != display_index && (best == NULL || cur->hits > best->hits))
+ best = cur;
+
+ /* if we're done, we're done */
+ if (best == NULL || best->hits == 0)
+ break;
+
+ /* print it */
+ printf("RASTERIZER_ENTRY( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X ) /* %c %8d %10d */\n",
+ best->eff_color_path,
+ best->eff_alpha_mode,
+ best->eff_fog_mode,
+ best->eff_fbz_mode,
+ best->eff_tex_mode_0,
+ best->eff_tex_mode_1,
+ best->is_generic ? '*' : ' ',
+ best->polys,
+ best->hits);
+
+ /* reset */
+ best->display = display_index;
+ }
+}
+
+
+
+/***************************************************************************
+ GENERIC RASTERIZERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ raster_fastfill - per-scanline
+ implementation of the 'fastfill' command
+-------------------------------------------------*/
+
+static void raster_fastfill(void *destbase, INT32 y, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ voodoo_state *v = extra->state;
+ stats_block *stats = &v->thread_stats[threadid];
+ INT32 startx = extent->startx;
+ INT32 stopx = extent->stopx;
+ int scry, x;
+
+ /* determine the screen Y */
+ scry = y;
+ if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
+ scry = (v->fbi.yorigin - y) & 0x3ff;
+
+ /* fill this RGB row */
+ if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u))
+ {
+ const UINT16 *ditherow = &extra->dither[(y & 3) * 4];
+ UINT64 expanded = *(UINT64 *)ditherow;
+ UINT16 *dest = (UINT16 *)destbase + scry * v->fbi.rowpixels;
+
+ for (x = startx; x < stopx && (x & 3) != 0; x++)
+ dest[x] = ditherow[x & 3];
+ for ( ; x < (stopx & ~3); x += 4)
+ *(UINT64 *)&dest[x] = expanded;
+ for ( ; x < stopx; x++)
+ dest[x] = ditherow[x & 3];
+ stats->pixels_out += stopx - startx;
+ }
+
+ /* fill this dest buffer row */
+ if (FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u) && v->fbi.aux)
+ {
+ UINT16 color = v->reg[zaColor].u;
+ UINT64 expanded = ((UINT64)color << 48) | ((UINT64)color << 32) | (color << 16) | color;
+ UINT16 *dest = v->fbi.aux + scry * v->fbi.rowpixels;
+
+ for (x = startx; x < stopx && (x & 3) != 0; x++)
+ dest[x] = color;
+ for ( ; x < (stopx & ~3); x += 4)
+ *(UINT64 *)&dest[x] = expanded;
+ for ( ; x < stopx; x++)
+ dest[x] = color;
+ }
+}
+
+
+/*-------------------------------------------------
+ generic_0tmu - generic rasterizer for 0 TMUs
+-------------------------------------------------*/
+
+RASTERIZER(generic_0tmu, 0, v->reg[fbzColorPath].u, v->reg[fbzMode].u, v->reg[alphaMode].u,
+ v->reg[fogMode].u, 0, 0)
+
+
+/*-------------------------------------------------
+ generic_1tmu - generic rasterizer for 1 TMU
+-------------------------------------------------*/
+
+RASTERIZER(generic_1tmu, 1, v->reg[fbzColorPath].u, v->reg[fbzMode].u, v->reg[alphaMode].u,
+ v->reg[fogMode].u, v->tmu[0].reg[textureMode].u, 0)
+
+
+/*-------------------------------------------------
+ generic_2tmu - generic rasterizer for 2 TMUs
+-------------------------------------------------*/
+
+RASTERIZER(generic_2tmu, 2, v->reg[fbzColorPath].u, v->reg[fbzMode].u, v->reg[alphaMode].u,
+ v->reg[fogMode].u, v->tmu[0].reg[textureMode].u, v->tmu[1].reg[textureMode].u)
+
+
+#else
+
+
+
+/***************************************************************************
+ GAME-SPECIFIC RASTERIZERS
+***************************************************************************/
+
+/* blitz ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 284269 914846168 */
+RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 485421 440309121 */
+RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 31606 230753709 */
+RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 76742 211701679 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* 6188 152109056 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* 1100 108134400 */
+RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 6229525 106197740 */
+RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0799, 0x0C261A0F, 0xFFFFFFFF ) /* 905641 75886220 */
+RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 205236 53317253 */
+RASTERIZER_ENTRY( 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* 817356 48881349 */
+RASTERIZER_ENTRY( 0x00000035, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 37979 41687251 */
+RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 26014 41183295 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 2512 37911104 */
+RASTERIZER_ENTRY( 0x00006136, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 28834 15527654 */
+RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 9878 4979429 */
+RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 199952 4622064 */
+RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* 8672 3676949 */
+RASTERIZER_ENTRY( 0x00582C35, 0x00515010, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* 616 2743972 */
+RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 81380 2494832 */
+//RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000000, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* 7670 2235587 */
+//RASTERIZER_ENTRY( 0x00592136, 0x00515110, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* 210 1639140 */
+//RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* 108 1154736 */
+//RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* 2152 1150842 */
+//RASTERIZER_ENTRY( 0x00592136, 0x00515110, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* 152 880560 */
+//RASTERIZER_ENTRY( 0x00008035, 0x00515119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 90848 805730 */
+//RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261AC9, 0xFFFFFFFF ) /* 2024 571406 */
+//RASTERIZER_ENTRY( 0x00012136, 0x00515110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 1792 494592 */
+//RASTERIZER_ENTRY( 0x00000002, 0x00000000, 0x00000000, 0x00000300, 0xFFFFFFFF, 0xFFFFFFFF ) /* 256 161280 */
+
+/* blitz99 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 6297478 149465839 */
+RASTERIZER_ENTRY( 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 210693 6285480 */
+RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* * 20180 2718710 */
+RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* * 360 2425416 */
+RASTERIZER_ENTRY( 0x00002C35, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 67059 1480978 */
+RASTERIZER_ENTRY( 0x00008035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 24811 400666 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* * 10304 324468 */
+RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 1024 112665 */
+
+/* blitz2k ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 3880 95344128 */
+RASTERIZER_ENTRY( 0x00582C35, 0x00514110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 148 1785480 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610CF, 0xFFFFFFFF ) /* * 9976 314244 */
+
+/* carnevil ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 492 84128082 */
+RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 1988398 36166780 */
+RASTERIZER_ENTRY( 0x00486116, 0x00045119, 0x00000000, 0x00030279, 0x0C26180F, 0xFFFFFFFF ) /* * 34424 28788847 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 514 26316800 */
+RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000000, 0x000306F9, 0x0C261AC9, 0xFFFFFFFF ) /* * 7346 18805760 */
+RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000302F9, 0x0C26180F, 0xFFFFFFFF ) /* * 130764 18678972 */
+RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x000306F9, 0x0C2618C9, 0xFFFFFFFF ) /* * 7244 12179040 */
+RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x000306F9, 0x0C26180F, 0xFFFFFFFF ) /* * 84520 12059721 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000306F9, 0x0C261AC9, 0xFFFFFFFF ) /* * 21926 11226112 */
+RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030679, 0x0C2618C9, 0xFFFFFFFF ) /* * 92115 8926536 */
+RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 1730 7629334 */
+RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x0C26180F, 0xFFFFFFFF ) /* * 37408 5545956 */
+RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x00030679, 0x0C26180F, 0xFFFFFFFF ) /* * 26528 4225026 */
+RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000306F9, 0x0C26180F, 0xFFFFFFFF ) /* * 35764 3230884 */
+RASTERIZER_ENTRY( 0x01422409, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 96020 1226438 */
+RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030279, 0x0C2618C9, 0xFFFFFFFF ) /* * 1020 574649 */
+RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 360 370008 */
+RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000000, 0x000306F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 576 334404 */
+
+/* calspeed ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26100F, 0xFFFFFFFF ) /* * 99120 1731923836 */
+RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 9955804 1526119944 */
+RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C26180F, 0xFFFFFFFF ) /* * 1898207 1124776864 */
+RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 3487467 1101663125 */
+RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 1079277 609256033 */
+RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A0723, 0x0C261ACF, 0xFFFFFFFF ) /* * 11880 583925760 */
+RASTERIZER_ENTRY( 0x00602819, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 63644 582469888 */
+RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 22688 556797972 */
+RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 1360254 417068457 */
+RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 3427489 405421272 */
+RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0739, 0x0C26180F, 0xFFFFFFFF ) /* * 286809 238944049 */
+RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 28160 231084818 */
+RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 183564 201014424 */
+RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 15275 168207109 */
+RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C26100F, 0xFFFFFFFF ) /* * 2856 134400000 */
+RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 98551 110417974 */
+RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C2610CF, 0xFFFFFFFF ) /* * 47040 107360728 */
+RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 13128 86876789 */
+RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 257515 76329054 */
+RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 3934 64958208 */
+//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 77400 63786236 */
+//RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 12500 63151200 */
+//RASTERIZER_ENTRY( 0x0102001A, 0x00045119, 0x00000001, 0x000A0321, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 8764 57629312 */
+//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 3257 32708448 */
+//RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A07E3, 0x0C2610CF, 0xFFFFFFFF ) /* * 28364 31195605 */
+//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 409001 30699647 */
+//RASTERIZER_ENTRY( 0x00482C35, 0x00045119, 0x00000001, 0x000A0321, 0x0C26100F, 0xFFFFFFFF ) /* * 17669 11214172 */
+//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 5844 6064373 */
+//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 626 4651080 */
+//RASTERIZER_ENTRY( 0x00482C35, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 5887 2945500 */
+//RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 1090 2945093 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 228 1723908 */
+//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000A0321, 0x0C261A0F, 0xFFFFFFFF ) /* * 112 1433600 */
+//RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 3091 1165805 */
+//RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 620 791202 */
+
+/* hyprdriv ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 60860 498565120 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 28688 235012096 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* * 11844 156499968 */
+RASTERIZER_ENTRY( 0x00580035, 0x00045119, 0x00000001, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 175990 146518715 */
+RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 2336 114819072 */
+RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 363325 100404294 */
+RASTERIZER_ENTRY( 0x00582C35, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 40918 96318738 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 54815 94990269 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 123032 91652828 */
+RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 82767 86431997 */
+RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 9874 78101834 */
+RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 102146 72570879 */
+RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 657804 67229658 */
+RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B03F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 10428 63173865 */
+RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 230145 57902926 */
+RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 769654 53992486 */
+RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 85365 51865697 */
+RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000001, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* * 454674 46165536 */
+RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 101889 33337987 */
+RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 255952 29810993 */
+//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 106190 25430383 */
+//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 595001 23268601 */
+//RASTERIZER_ENTRY( 0x0142612A, 0x00000000, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 946410 22589110 */
+//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 330036 21323230 */
+//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 40089 13470498 */
+//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 90906 12850855 */
+//RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 9492 12115280 */
+//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 453515 12013961 */
+//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 33829 8384312 */
+//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 83986 7841206 */
+//RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 42515 7242660 */
+//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 706 6158684 */
+//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 62051 5819485 */
+//RASTERIZER_ENTRY( 0x0142612A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 135139 5063467 */
+//RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 10359 5135837 */
+//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 170159 4449246 */
+//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 19037 4371219 */
+//RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 8963 4352501 */
+//RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 47712 4159994 */
+//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* * 47525 4151435 */
+//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 34980 3794066 */
+//RASTERIZER_ENTRY( 0x0142613A, 0x00045110, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 6540 2358068 */
+//RASTERIZER_ENTRY( 0x0142611A, 0x00045110, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 703308 2096781 */
+//RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B0339, 0x0C261A1F, 0xFFFFFFFF ) /* * 3963 2079440 */
+//RASTERIZER_ENTRY( 0x01422439, 0x00000000, 0x00000001, 0x000B073B, 0x0C261AC9, 0xFFFFFFFF ) /* * 22866 2008397 */
+//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 69705 1673671 */
+//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 13366 1575120 */
+//RASTERIZER_ENTRY( 0x0142613A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 50625 1408211 */
+//RASTERIZER_ENTRY( 0x0142613A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 1244348 1244346 */
+//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 13791 1222735 */
+//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 33064 943590 */
+//RASTERIZER_ENTRY( 0x0142610A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 2041 926507 */
+//RASTERIZER_ENTRY( 0x00480019, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 2722 453924 */
+//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 68232 306869 */
+//RASTERIZER_ENTRY( 0x0142611A, 0x00045110, 0x00000001, 0x000B0379, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 7164 269002 */
+
+/* mace -------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824100F, 0xFFFFFFFF ) /* * 7204150 1340201579 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0xFFFFFFFF ) /* * 15332 1181663232 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 104456 652582379 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824180F, 0xFFFFFFFF ) /* * 488613 368880164 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082418CF, 0xFFFFFFFF ) /* * 352924 312417405 */
+RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 15024 291762384 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082410CF, 0xFFFFFFFF ) /* * 711824 279246170 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824100F, 0xFFFFFFFF ) /* * 735574 171881981 */
+RASTERIZER_ENTRY( 0x00602401, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 943006 154374023 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082410CF, 0xFFFFFFFF ) /* * 103877 101077498 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824108F, 0xFFFFFFFF ) /* * 710125 87547221 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x08241ACF, 0xFFFFFFFF ) /* * 9834 79774966 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 17644 70187036 */
+RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 11324 56633925 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 96743 40820171 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 166053 29100794 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 166053 29100697 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0379, 0x0824188F, 0xFFFFFFFF ) /* * 6723 29076516 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824188F, 0xFFFFFFFF ) /* * 53297 23928976 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824180F, 0xFFFFFFFF ) /* * 10309 19001776 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 22105 17473157 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824188F, 0xFFFFFFFF ) /* * 11304 17236698 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0xFFFFFFFF ) /* * 1664 17180883 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x08241A0F, 0xFFFFFFFF ) /* * 148606 12274278 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418CF, 0xFFFFFFFF ) /* * 80692 9248007 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 37819 8080994 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000001, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 37819 8080969 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 536 7930305 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 27601 7905364 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 27601 7905364 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 36314 7667917 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 36314 7667917 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 31109 6020110 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 31109 6020110 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 42689 5959231 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 42689 5959231 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824188F, 0xFFFFFFFF ) /* * 11965 5118044 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 11923 4662909 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x082410CF, 0xFFFFFFFF ) /* * 4422 4624260 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824100F, 0xFFFFFFFF ) /* * 3853 3596375 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 400 3555759 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 3755 3453084 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 4170 2425016 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824184F, 0xFFFFFFFF ) /* * 322 2220073 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x082418CF, 0xFFFFFFFF ) /* * 4008 1201335 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824108F, 0xFFFFFFFF ) /* * 13704 883585 */
+
+/* sfrush -----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0824101F ) /* * 590139 246714190 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x0824101F ) /* * 397774 153418144 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x082410DF ) /* * 22732 146975666 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0824101F ) /* * 306398 130393278 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0x0824101F ) /* * 437743 117403881 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0x0824101F ) /* * 66608 109289500 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x082410DF ) /* * 19101 92573085 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0824181F ) /* * 258287 78618228 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824181F, 0x0824101F ) /* * 61814 68788856 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x0824181F ) /* * 149792 61464124 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0x0824181F ) /* * 109988 55083276 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x00000000 ) /* * 478 46989312 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x0824181F ) /* * 468 46006272 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0824181F ) /* * 125204 39023396 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x082410DB ) /* * 394 38731776 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 12890 36333568 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0824101F, 0x0824101F ) /* * 147995 31086325 */
+RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B077B, 0x00000000, 0x082410DB ) /* * 3576 29294592 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824181F, 0x0824181F ) /* * 76059 29282981 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 12632 29173808 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x082418DF ) /* * 14040 24318118 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0824101F, 0x0824101F ) /* * 56586 17643207 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 9130 17277440 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 66302 17049921 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x0824101F ) /* * 64380 16463672 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x0824181F ) /* * 152 14942208 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 8748 13810176 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082708DF, 0x0824101F ) /* * 216634 10628656 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B077B, 0x00000000, 0x082410DB ) /* * 1282 10502144 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 74636 9758030 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 58652 9353671 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 5242 8038747 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x082410DB ) /* * 11048 7538060 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0x0824181F ) /* * 121630 6906591 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x082418DF ) /* * 19553 6864245 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x082418DF ) /* * 1287 6648834 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082708DF, 0x0824101F ) /* * 197766 6617876 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082700DF, 0x0824101F ) /* * 75470 6231739 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x08241ADF, 0x0824101F ) /* * 180 5898240 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 7692 5743360 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 20128 4980591 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 1144 4685824 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082700DF, 0x0824101F ) /* * 72299 4466336 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 3750 4018176 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DF ) /* * 7533 3692141 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 9484 3610674 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x0824181F ) /* * 128660 3216280 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 22214 3172813 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824181F ) /* * 5094 3099098 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 1954 2850924 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 1542 2434304 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x00000000 ) /* * 478 1957888 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 468 1916928 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 11664 1729188 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x082410DB ) /* * 1282 1640960 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 388 1589248 */
+//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 1282 1312768 */
+//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x0824181F ) /* * 3928 1046582 */
+
+/* vaportrx ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00482405, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 2226138 592165102 */
+RASTERIZER_ENTRY( 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 53533 281405105 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* * 314131 219103141 */
+RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 216329 95014510 */
+RASTERIZER_ENTRY( 0x00482405, 0x00000009, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 317128 92010096 */
+RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B07F9, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 13728 88595930 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261ACF, 0xFFFFFFFF ) /* * 649448 81449105 */
+RASTERIZER_ENTRY( 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 444231 60067944 */
+RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C26184F, 0xFFFFFFFF ) /* * 36057 58970468 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 53147 48856709 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x0C2610C9, 0xFFFFFFFF ) /* * 447654 47171792 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 207392 38933691 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 2015632 33364173 */
+RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 196361 30395218 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 110898 28973006 */
+RASTERIZER_ENTRY( 0x00482435, 0x00000009, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 135107 16301589 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A8F, 0xFFFFFFFF ) /* * 22375 15797748 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C26184F, 0xFFFFFFFF ) /* * 141539 7513140 */
+RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 621403 5369705 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 30443 4070277 */
+//RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 22121 3129894 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 9187 1864599 */
+//RASTERIZER_ENTRY( 0x00482405, 0x00044110, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 10390 1694950 */
+//RASTERIZER_ENTRY( 0x0142610A, 0x00000009, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 25366 1624563 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 69033 1607970 */
+//RASTERIZER_ENTRY( 0x0142610A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 36316 1084818 */
+//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 1813 816763 */
+//RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B0339, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 6602 767221 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 2547 646048 */
+//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A8F, 0xFFFFFFFF ) /* * 2394 501590 */
+//RASTERIZER_ENTRY( 0x0142613A, 0x00000009, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 14078 440086 */
+//RASTERIZER_ENTRY( 0x0142610A, 0x00045119, 0x00000000, 0x000B0339, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 9877 429160 */
+//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261ACF, 0xFFFFFFFF ) /* * 3222 366052 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00000009, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 5942 285657 */
+//RASTERIZER_ENTRY( 0x00482405, 0x00044119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 2328 239688 */
+//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 1129 208448 */
+
+/* wg3dh ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0xFFFFFFFF ) /* * 127676 116109477 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824189F, 0xFFFFFFFF ) /* * 96310 112016758 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824109F, 0xFFFFFFFF ) /* * 1412831 108682642 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0xFFFFFFFF ) /* * 1612798 45952714 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241AD9, 0xFFFFFFFF ) /* * 5960 6103040 */
+RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 56512 4856542 */
+RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x0824109F, 0xFFFFFFFF ) /* * 8480 2045940 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0379, 0x0824181F, 0xFFFFFFFF ) /* * 2779 1994317 */
+RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824105F, 0xFFFFFFFF ) /* * 154691 1922774 */
+RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0xFFFFFFFF ) /* * 18114 776139 */
+
+/* gauntleg ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24100F ) /* * 157050 668626339 */
+RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 1079126 580272490 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A4F, 0x0C24100F ) /* * 49686 232178144 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C24104F, 0x0C24100F ) /* * 1048560 206304396 */
+RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C2240CF, 0x0C241ACF ) /* * 59176 182444375 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A4F ) /* * 66342 179689728 */
+RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 72264 109413344 */
+RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 281243 75399210 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24104F ) /* * 126384 68412120 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A0F, 0x0C24100F ) /* * 26864 43754988 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241ACF ) /* * 30510 32759936 */
+RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 44783 31884168 */
+RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 34946 31359362 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241ACF ) /* * 8006 28367999 */
+RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 15430 27908213 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A0F ) /* * 29306 25166802 */
+RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 27737 24517949 */
+RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 6783 21292092 */
+RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 9591 17815763 */
+RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 343966 13864759 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 11842 12126208 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A8F, 0x0C24100F ) /* * 6648 9788508 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C2418CF ) /* * 8444 8646656 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 9677 8365606 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 844920 8289326 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24184F ) /* * 3108 8010176 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x00000000, 0x0C24180F ) /* * 1435 6209238 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 5754 5617499 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 1608 5557253 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 105127 5133321 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 3460 4689138 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 7025 4629550 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 7164 4407683 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24188F ) /* * 1922 3924179 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 4116 3733777 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A8F ) /* * 2626 3732809 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C24180F ) /* * 778 3202973 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C24184F, 0x0C24100F ) /* * 1525 2997446 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C241A0F ) /* * 645 2975266 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00044119, 0x00000000, 0x000B0379, 0x00000000, 0x0C241A0F ) /* * 5212 2491361 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 825 1996513 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C241A0F ) /* * 466 1967163 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0580000F, 0x0C24180F ) /* * 77400 1883434 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 472 1698177 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 2476 1678760 */
+//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 4054 1541748 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00044119, 0x00000000, 0x000B0379, 0x0C241A0F, 0x0C24180F ) /* * 3132 1509438 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0580080F, 0x0C24180F ) /* * 8582 1324196 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00044119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24100F ) /* * 1436 1239704 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C24100F ) /* * 253 1220316 */
+//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 2433 1014668 */
+
+/* gauntdl ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C241ACF ) /* * 30860 1128173568 */
+RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 2631692 1117011118 */
+RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 2429239 826969012 */
+RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 454056 468285142 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C2418CF ) /* * 257586 355634672 */
+RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 10898 134362122 */
+RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C241A0F ) /* * 32195 126327049 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2410CF, 0x0C24100F ) /* * 855240 123899880 */
+RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 1718 120629204 */
+RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22488F, 0x0C241ACF ) /* * 186839 120281357 */
+RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0379, 0x0C22480F, 0x0C241ACF ) /* * 14102 115428820 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C2410CF ) /* * 88530 98271949 */
+RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0379, 0x0C22480F, 0x0C241ACF ) /* * 12994 68053222 */
+RASTERIZER_ENTRY( 0x00602439, 0x00044110, 0x00000000, 0x000B0379, 0x00000009, 0x0C24100F ) /* * 68273 67454880 */
+RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 100026 62271618 */
+RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 153285 44411342 */
+RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 157545 40702131 */
+RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 7800 31948800 */
+RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22408F, 0x0C241ACF ) /* * 47623 20321183 */
+RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24188F ) /* * 21570 19324892 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x000000C1, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 3698 15147008 */
+//RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22408F, 0x0C241ACF ) /* * 19765 12383722 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 662274 10563855 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 27909 10462997 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 78671 10286957 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 52038 9928244 */
+//RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C224A0F, 0x0C241ACF ) /* * 27469 9239782 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 757116 8072783 */
+//RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22488F, 0x0C241ACF ) /* * 18018 7035833 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C241A0F ) /* * 50339 5976564 */
+//RASTERIZER_ENTRY( 0x00603430, 0x00040219, 0x00000000, 0x000B0379, 0x00000009, 0x0C2410CE ) /* * 29385 5466384 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 423347 5355017 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 162620 4709092 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 463705 4642480 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 280337 4425529 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 212646 3432265 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 5788 2963456 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 460800 2609198 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 251108 2392362 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 297219 2352862 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0584180F, 0x0C2410CF ) /* * 9913 2097069 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 142722 2091569 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 8820 2053325 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 10346 2033427 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24188F, 0x0C241ACF ) /* * 2136 2017241 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24100F ) /* * 1505 1928490 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 176734 1842440 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 262577 1799080 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 83179 1534171 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 3863 1527077 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 8021 1472661 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C241A0F, 0x0C241ACF ) /* * 85416 1342195 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 261360 1335048 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00000009, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 74811 1320900 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 239331 1268661 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 107769 1244175 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 3706 1216182 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24188F ) /* * 49608 1206129 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00000009, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C241ACF ) /* * 42440 1204109 */
+//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x000000C1, 0x000B0779, 0x0C2410CF, 0x0C24100F ) /* * 29584 1168568 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 17729 1152869 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 4052 1108726 */
+//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 7082 1079348 */
+//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 7761 1023855 */
+
+/* gradius4 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+//RASTERIZER_ENTRY( 0x02420002, 0x00000009, 0x00000000, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* intro */
+//RASTERIZER_ENTRY( 0x01420021, 0x00005119, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* intro */
+//RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x14261A87, 0xFFFFFFFF ) /* in-game */
+
+/* nbapbp ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
+//RASTERIZER_ENTRY( 0x00424219, 0x00000000, 0x00000001, 0x00030B7B, 0x08241AC7, 0xFFFFFFFF ) /* intro */
+//RASTERIZER_ENTRY( 0x00002809, 0x00004110, 0x00000001, 0x00030FFB, 0x08241AC7, 0xFFFFFFFF ) /* in-game */
+//RASTERIZER_ENTRY( 0x00424219, 0x00000000, 0x00000001, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* in-game */
+//RASTERIZER_ENTRY( 0x0200421A, 0x00001510, 0x00000001, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* in-game */
+
+#endif
diff --git a/src/emu/video/voodoo.h b/src/emu/video/voodoo.h
new file mode 100644
index 00000000000..f19daca0dfa
--- /dev/null
+++ b/src/emu/video/voodoo.h
@@ -0,0 +1,50 @@
+/*************************************************************************
+
+ 3dfx Voodoo Graphics SST-1 emulator
+
+ driver by Aaron Giles
+
+**************************************************************************/
+
+#define MAX_VOODOO 2
+
+/* enumeration specifying which model of Voodoo we are emulating */
+enum
+{
+ VOODOO_1,
+ VOODOO_2,
+ VOODOO_BANSHEE,
+ VOODOO_3
+};
+
+void voodoo_start(int which, int scrnum, int type, int fbmem_in_mb, int tmem0_in_mb, int tmem1_in_mb);
+int voodoo_update(int which, mame_bitmap *bitmap, const rectangle *cliprect);
+void voodoo_reset(int which);
+void voodoo_exit(int which);
+int voodoo_get_type(int which);
+int voodoo_is_stalled(int which);
+void voodoo_set_init_enable(int which, UINT32 newval);
+void voodoo_set_vblank_callback(int which, void (*vblank)(int));
+void voodoo_set_stall_callback(int which, void (*stall)(int));
+
+READ32_HANDLER( voodoo_0_r );
+WRITE32_HANDLER( voodoo_0_w );
+
+READ32_HANDLER( voodoo_1_r );
+WRITE32_HANDLER( voodoo_1_w );
+
+READ32_HANDLER( banshee_0_r );
+WRITE32_HANDLER( banshee_0_w );
+READ32_HANDLER( banshee_fb_0_r );
+WRITE32_HANDLER( banshee_fb_0_w );
+READ32_HANDLER( banshee_io_0_r );
+WRITE32_HANDLER( banshee_io_0_w );
+READ32_HANDLER( banshee_rom_0_r );
+
+READ32_HANDLER( banshee_1_r );
+WRITE32_HANDLER( banshee_1_w );
+READ32_HANDLER( banshee_fb_1_r );
+WRITE32_HANDLER( banshee_fb_1_w );
+READ32_HANDLER( banshee_io_1_r );
+WRITE32_HANDLER( banshee_io_1_w );
+READ32_HANDLER( banshee_rom_1_r );